|
|
1.1 ! root 1: #define _DDI_DKI 1 ! 2: #define _SYSV4 1 ! 3: ! 4: /* ! 5: * Error-reporting code.... ! 6: */ ! 7: ! 8: /* ! 9: *-IMPORTS: ! 10: * <common/ccompat.h> ! 11: * __PROTO () ! 12: * __USE_PROTO__ ! 13: * __ARGS () ! 14: * <common/xdebug.h> ! 15: * __LOCAL__ ! 16: * <sys/inline.h> ! 17: * splhi () ! 18: * splx () ! 19: * <sys/ksynch.h> ! 20: * lock_t ! 21: * LOCK () ! 22: * LOCK_ALLOC () ! 23: * UNLOCK () ! 24: * <common/_null.h> ! 25: * NULL ! 26: * <limits.h> ! 27: * CHAR_BIT ! 28: * <stdarg.h> ! 29: * va_list ! 30: * va_start () ! 31: * va_arg () ! 32: * va_end () ! 33: * ! 34: *-PRIVATE DEPENDENCIES: ! 35: * _put_console () ! 36: * _put_putbuf () ! 37: */ ! 38: ! 39: #include <common/ccompat.h> ! 40: #include <common/xdebug.h> ! 41: #include <sys/inline.h> ! 42: #include <sys/ksynch.h> ! 43: #include <common/_null.h> ! 44: #include <sys/ddi.h> ! 45: ! 46: #include <limits.h> ! 47: #include <stdarg.h> ! 48: ! 49: #include <sys/cmn_err.h> ! 50: ! 51: #ifdef __MSDOS__ ! 52: ! 53: #include <process.h> ! 54: ! 55: #endif ! 56: ! 57: ! 58: /* ! 59: *-GLOBAL VARIABLES: ! 60: * conlock lock to single-thread console output ! 61: * putlock lock to single-thread putbuf output ! 62: */ ! 63: ! 64: /* ! 65: * Note that these locks are always acquired in the order conlock -> putlock; ! 66: * this is required to ensure that the system remains deadlock-free. The ! 67: * hierarchy mechanism is used to enforce this constraint. ! 68: * ! 69: * We use the user namespace for these since if they are actually made public ! 70: * by definitions in <common/xdebug.h> then they will still not conflict with ! 71: * user symbols (ie, we assume that this module is an "implementation" ! 72: * module... ! 73: */ ! 74: ! 75: __LOCAL__ lock_t * _conlock; ! 76: __LOCAL__ lock_t * _putlock; ! 77: ! 78: ! 79: /* ! 80: * The following are not global variables, they're static constants. ! 81: */ ! 82: ! 83: static char * message_level [] = { ! 84: "", ! 85: "NOTICE : ", ! 86: "WARNING : ", ! 87: "PANIC : ", ! 88: "<INVALID ERROR LEVEL> : " ! 89: }; ! 90: ! 91: ! 92: /* ! 93: * The following external function declarations exist for internal layering ! 94: * purposes and do not appear in any headers. The names begin with a single ! 95: * underscore (reserved for the user with internal linkage, reserved for the ! 96: * system with external linkage) so as not to conflict with any user-defined ! 97: * symbol names. ! 98: * ! 99: * If you find this use of the implementation namespace distasteful, then ! 100: * you'll have to move the function definitions in here. ! 101: * ! 102: * Note also that these functions will have the default language linkage ! 103: * for the translator, ie we allow these functions to be mangled C++. This ! 104: * constrains them to be produced by the same translator used for this ! 105: * module. ! 106: */ ! 107: ! 108: #if __COHERENT__ ! 109: void putchar __PROTO ((int _c)); ! 110: #define _put_console(c) putchar (c) ! 111: #else ! 112: void _put_console __PROTO ((unsigned char _outch)); ! 113: #endif ! 114: ! 115: void _put_putbuf __PROTO ((unsigned char _outch)); ! 116: ! 117: ! 118: /* ! 119: *-STATUS: ! 120: * DDI/DKI ! 121: * ! 122: *-NAME: ! 123: * cmn_err () display an error message or panic the system ! 124: * ! 125: *-SYNOPSIS: ! 126: * #include <sys/cmn_err.h> ! 127: * ! 128: * void cmn_err (int level, char * format, ...); ! 129: * ! 130: *-ARGUMENTS: ! 131: * level "level" indicates the severity of the error condition. ! 132: * Valid levels are: ! 133: * CE_CONT used to continue a previous message or to ! 134: * display an informative message not connected ! 135: * with an error. ! 136: * CE_NOTE used to display a message preceded with ! 137: * NOTICE:. This message is used to report system ! 138: * events that do not necessarily require action, ! 139: * by may interest the system administrator. For ! 140: * example, a message saying that a sector on a ! 141: * disk needs to be accessed repeatedly before it ! 142: * can be accessed correctly might be noteworthy. ! 143: * CE_WARN use to display a message preceded with ! 144: * WARNING:. This message is used to report ! 145: * system events that require immediate ! 146: * attention, such as those where if an action is ! 147: * not taken, the system may panic. For example, ! 148: * where a peripheral device does not initialize ! 149: * correctly, this level should be used. ! 150: * CE_PANIC used to display a message preceded by PANIC:, ! 151: * and panic the system. Drivers should use this ! 152: * level only for debugging or in the case of ! 153: * severe errors that indicate that the system ! 154: * cannot continue to function. This level halts ! 155: * processing. ! 156: * ! 157: * format The message to be displayed. By default, the message ! 158: * is sent both to the system console and to the circular ! 159: * kernel buffer, "putbuf". If the first character in ! 160: * "format" is an exclamation point ("!"), the message ! 161: * goes only to "putbuf". If the first character in ! 162: * "format" is a circumflex ("^"), the message goes only ! 163: * to the console. The size of the circular buffer ! 164: * "putbuf" is defined by the kernel variable "putbufsz". ! 165: * Driver developers or administrators can read the ! 166: * "putbuf" buffer using appropriate debugging or ! 167: * administrative tools. ! 168: * ! 169: * cmn_err () appends '\n' to each "format" string, even ! 170: * when a message is sent to "putbuf", except when level ! 171: * is CE_CONT. ! 172: * ! 173: * Valid conversion specifications are %s, %u, %d, %o, ! 174: * and %x. The cmn_err () function is otherwise similar ! 175: * to the printf () library subroutine is its ! 176: * interpretation of the "format" string, except that ! 177: * cmn_err () does not accept length specifications in ! 178: * conversion specifications. For example, %3d is invalid ! 179: * and will be treated as a literal string, resulting in ! 180: * a mismatch of arguments. ! 181: * ! 182: * ... the set of arguments passed with the message being ! 183: * displayed. Any argument within the range of supported ! 184: * conversion specifications can be passed. ! 185: * ! 186: *-DESCRIPTION: ! 187: * cmn_err () displays a specified message on the console and/or stores ! 188: * it in the kernel buffer "putbuf". cmn_err () can also panic the ! 189: * system. ! 190: * ! 191: * At times a driver may encounter error conditions requiring the ! 192: * attention of a system console monitor. These conditions may mean ! 193: * halting the system; however, this must be done with caution. Except ! 194: * during the debugging stage, or in the case of a serious, unrecoverable ! 195: * error, a driver should never stop the system. ! 196: * ! 197: * The cmn_err () function with the CE_CONT argument can be used by ! 198: * driver developers as a driver code debugging tool. However, using ! 199: * cmn_err () in this capacity can change system timing characteristics. ! 200: * ! 201: *-NOTES: ! 202: * Does not sleep. ! 203: * ! 204: * If "level" is CE_PANIC, then driver defined basic locks, read/write ! 205: * locks, and sleep locks may not be held across calls to this function. ! 206: * For other levels, locks may be held. ! 207: */ ! 208: ! 209: enum { OUT_CONSOLE = 1, ! 210: OUT_PUTBUF = 2, ! 211: OUT_LONG = 4, ! 212: OUT_SHORT = 8, ! 213: OUT_SIGNED = 16 ! 214: }; ! 215: ! 216: typedef char * _string_t; /* for va_arg () */ ! 217: typedef unsigned short _ushort_t; ! 218: typedef unsigned int _uint_t; ! 219: typedef unsigned long _ulong_t; ! 220: ! 221: ! 222: #if __USE_PROTO__ ! 223: void (cmn_err) (int level, char * format, ...) ! 224: #else ! 225: void ! 226: cmn_err __ARGS ((level, format)) ! 227: int level; ! 228: char * format; ! 229: #endif ! 230: { ! 231: /* ! 232: * The following local data is used for converting numeric data to ! 233: * strings. Numbuf is defined such that it is large enough to hold ! 234: * the maximum number of digits that could be generated from any ! 235: * conversion specification (currently, the longest possible spec is ! 236: * %lo). ! 237: */ ! 238: ! 239: char numbuf [(sizeof (long) * CHAR_BIT + 2) / 3 + 1]; ! 240: char * numptr; ! 241: int radix; ! 242: long svalue; ! 243: unsigned long value; ! 244: ! 245: va_list args; ! 246: ! 247: unsigned output; /* who to output to */ ! 248: ! 249: pl_t con_pl; /* for locking */ ! 250: pl_t put_pl; ! 251: ! 252: ! 253: if (format == NULL) ! 254: format = "<cmn_err: no error message was supplied>"; ! 255: ! 256: if (* format == '!') { ! 257: format ++; ! 258: output = OUT_PUTBUF; ! 259: } else if (* format == '^') { ! 260: format ++; ! 261: output = OUT_CONSOLE; ! 262: } else ! 263: output = OUT_PUTBUF | OUT_CONSOLE; ! 264: ! 265: ! 266: /* ! 267: * Before we generate any output, we should lock the console/putbuf ! 268: * so that our messages won't get interspersed with diagnostic output ! 269: * from interrupt handlers or other CPUs. ! 270: * ! 271: * If we get called before the locks have been allocated, proceed ! 272: * at the highest interrupt priority as a fallback. ! 273: */ ! 274: ! 275: if (_conlock != NULL) { ! 276: if ((output & OUT_CONSOLE) != 0) ! 277: con_pl = LOCK (_conlock, plhi); ! 278: ! 279: if ((output & OUT_PUTBUF) != 0) ! 280: put_pl = LOCK (_putlock, plhi); ! 281: } else ! 282: con_pl = splhi (); ! 283: ! 284: ! 285: /* ! 286: * Check that the level argument is reasonable. ! 287: */ ! 288: ! 289: if (level < CE_CONT || level > CE_PANIC) ! 290: level = CE_INVALID; ! 291: ! 292: ! 293: /* ! 294: * We should think about generating the date and as accurate a time ! 295: * reading as possible along with the fixed-text header. ! 296: * ! 297: * For now, we'll just generate some fixed text. ! 298: */ ! 299: ! 300: numptr = message_level [level]; ! 301: ! 302: while (* numptr != 0) { ! 303: if ((output & OUT_CONSOLE) != 0) ! 304: _put_console (* numptr); ! 305: ! 306: if ((output & OUT_PUTBUF) != 0) ! 307: _put_putbuf (* numptr); ! 308: ! 309: numptr ++; ! 310: } ! 311: ! 312: ! 313: /* ! 314: * Now start generating formatted output. ! 315: * ! 316: * The manual page quoted in the function header doesn't say whether ! 317: * the 'l' and 'h' modifiers are available for conversion ! 318: * specifications. We'll implement them anyway. ! 319: */ ! 320: ! 321: va_start (args, format); ! 322: ! 323: while (* format != 0) { ! 324: if (format [0] == '%') { ! 325: /* ! 326: * Process the conversion-specifications. ! 327: * ! 328: * We temporarily borrow 'radix' as a temporary for ! 329: * working out how long the conversion specification ! 330: * is. ! 331: */ ! 332: ! 333: ! 334: output &= ~ (OUT_LONG | OUT_SHORT | OUT_SIGNED); ! 335: ! 336: radix = 2; ! 337: ! 338: if (format [radix - 1] == 'h') { ! 339: output |= OUT_SHORT; ! 340: radix ++; ! 341: } else if (format [radix - 1] == 'l') { ! 342: output |= OUT_LONG; ! 343: radix ++; ! 344: } ! 345: ! 346: switch ((format += radix) [-1]) { ! 347: ! 348: case 's': ! 349: numptr = va_arg (args, _string_t); ! 350: goto out_string; ! 351: ! 352: case 'd': ! 353: /* ! 354: * This is the only signed numeric conversion ! 355: * specification, so we process the sign here. ! 356: */ ! 357: ! 358: radix = 10; ! 359: ! 360: if ((output & OUT_SHORT) != 0) ! 361: svalue = (short) va_arg (args, int); ! 362: else if ((output & OUT_LONG) != 0) ! 363: svalue = va_arg (args, long); ! 364: else ! 365: svalue = va_arg (args, int); ! 366: ! 367: if (svalue < 0) { ! 368: if ((output & OUT_CONSOLE) != 0) ! 369: _put_console ('-'); ! 370: ! 371: if ((output & OUT_PUTBUF) != 0) ! 372: _put_putbuf ('-'); ! 373: ! 374: svalue = - svalue; ! 375: } ! 376: ! 377: output |= OUT_SIGNED; ! 378: break; ! 379: ! 380: case 'o': ! 381: radix = 8; ! 382: break; ! 383: ! 384: case 'u': ! 385: radix = 10; ! 386: break; ! 387: ! 388: case 'x': ! 389: radix = 16; ! 390: break; ! 391: ! 392: case '%': ! 393: /* ! 394: * Special case: %% -> % ! 395: */ ! 396: ! 397: format -= 1; ! 398: goto bad_format; ! 399: ! 400: default: ! 401: /* ! 402: * It's not a valid conversion, so we back ! 403: * up "format". ! 404: */ ! 405: format -= radix; ! 406: goto bad_format; ! 407: } ! 408: ! 409: ! 410: /* ! 411: * All numeric conversions come here. ! 412: */ ! 413: ! 414: if ((output & OUT_SIGNED) != 0) ! 415: value = svalue; ! 416: else if ((output & OUT_SHORT) != 0) ! 417: value = (_ushort_t) va_arg (args, _uint_t); ! 418: else if ((output & OUT_LONG) != 0) ! 419: value = va_arg (args, _ulong_t); ! 420: else ! 421: value = va_arg (args, _uint_t); ! 422: ! 423: ! 424: /* ! 425: * Now we generate the output digits one-at-a-time in ! 426: * reverse order. We step back from the end of the ! 427: * conversion buffer so that at the end of the ! 428: * conversion process we have a C string with the ! 429: * characters in a 'normal' order. ! 430: * ! 431: * (This allows the final output loop to be folded in ! 432: * with the string-output code). ! 433: */ ! 434: ! 435: numptr = & numbuf [sizeof (numbuf) - 1]; ! 436: ! 437: * numptr = 0; /* terminate the output string */ ! 438: ! 439: do { ! 440: int rem = (int) (value % radix); ! 441: value /= radix; ! 442: ! 443: * -- numptr = (rem < 10) ? rem + '0' : ! 444: rem + 'a' - 10; ! 445: } while (value > 0); ! 446: ! 447: ! 448: /* ! 449: * Copy temporary numeric-conversion string or ! 450: * user-supplied string argument to the output. ! 451: */ ! 452: ! 453: out_string: ! 454: while (* numptr != 0) { ! 455: if ((output & OUT_CONSOLE) != 0) ! 456: _put_console (* numptr); ! 457: ! 458: if ((output & OUT_PUTBUF) != 0) ! 459: _put_putbuf (* numptr); ! 460: ! 461: numptr ++; ! 462: } ! 463: continue; ! 464: } ! 465: bad_format: ! 466: if ((output & OUT_CONSOLE) != 0) ! 467: _put_console (* format); ! 468: ! 469: if ((output & OUT_PUTBUF) != 0) ! 470: _put_putbuf (* format); ! 471: ! 472: format ++; ! 473: } ! 474: ! 475: ! 476: /* ! 477: * Output a trailing '\n' unless the level is CE_CONT ! 478: */ ! 479: ! 480: if (level != CE_CONT) { ! 481: if ((output & OUT_CONSOLE) != 0) ! 482: _put_console ('\n'); ! 483: ! 484: if ((output & OUT_PUTBUF) != 0) ! 485: _put_putbuf ('\n'); ! 486: } ! 487: ! 488: ! 489: /* ! 490: * Now release the locks we acquired, and consider returning to the ! 491: * caller (unless this is a panic). ! 492: * ! 493: * A minor point: if we panic, we should release our locks but ! 494: * without causing interrupts to be enabled on this CPU; in order to ! 495: * do this we kludge "con_pl" and "put_pl" to be "plhi"; ! 496: */ ! 497: ! 498: if (level >= CE_PANIC) /* panic on an invalid level */ ! 499: con_pl = put_pl = plhi; ! 500: ! 501: ! 502: if (_conlock != NULL) { ! 503: if ((output & OUT_PUTBUF) != 0) ! 504: UNLOCK (_putlock, put_pl); ! 505: ! 506: if ((output & OUT_CONSOLE) != 0) ! 507: LOCK (_conlock, con_pl); ! 508: } else ! 509: (void) splx (con_pl); ! 510: ! 511: ! 512: if (level >= CE_PANIC) { ! 513: /* ! 514: * This CPU is shutting down. The actions to be taken here ! 515: * are so highly system-specific that we'll just throw them ! 516: * into another file. ! 517: */ ! 518: ! 519: #ifdef __MSDOS__ ! 520: splx (plbase); ! 521: ! 522: exit (3); /* call atexit () functions */ ! 523: #endif ! 524: } ! 525: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.