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