|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1988 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * This code is derived from software contributed to Berkeley by ! 6: * Chris Torek. ! 7: * ! 8: * Redistribution and use in source and binary forms are permitted ! 9: * provided that the above copyright notice and this paragraph are ! 10: * duplicated in all such forms and that any documentation, ! 11: * advertising materials, and other materials related to such ! 12: * distribution and use acknowledge that the software was developed ! 13: * by the University of California, Berkeley. The name of the ! 14: * University may not be used to endorse or promote products derived ! 15: * from this software without specific prior written permission. ! 16: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 17: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 18: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 19: * ! 20: * @(#)mscp.c 7.3 (Berkeley) 7/9/88 ! 21: */ ! 22: ! 23: /* ! 24: * MSCP generic driver routines ! 25: */ ! 26: ! 27: #include "param.h" ! 28: #include "buf.h" ! 29: #include "errno.h" ! 30: #include "dkstat.h" ! 31: #include "ioctl.h" ! 32: #include "disklabel.h" ! 33: #include "syslog.h" ! 34: ! 35: #include "../vaxuba/ubavar.h" ! 36: ! 37: #include "mscp.h" ! 38: #include "mscpvar.h" ! 39: ! 40: #define PCMD PSWP /* priority for command packet waits */ ! 41: ! 42: /* ! 43: * During transfers, mapping info is saved in the buffer's b_resid. ! 44: */ ! 45: #define b_info b_resid ! 46: ! 47: /* ! 48: * Get a command packet. Second argument is true iff we are ! 49: * to wait if necessary. Return NULL if none are available and ! 50: * we cannot wait. ! 51: */ ! 52: struct mscp * ! 53: mscp_getcp(mi, canwait) ! 54: register struct mscp_info *mi; ! 55: int canwait; ! 56: { ! 57: #define mri (&mi->mi_cmd) ! 58: register struct mscp *mp; ! 59: register int i; ! 60: int s = spl5(); ! 61: ! 62: again: ! 63: /* ! 64: * Ensure that we have some command credits, and ! 65: * that the next command packet is free. ! 66: */ ! 67: if (mi->mi_credits <= MSCP_MINCREDITS) { ! 68: if (!canwait) { ! 69: splx(s); ! 70: return (NULL); ! 71: } ! 72: mi->mi_wantcredits = 1; ! 73: sleep((caddr_t) &mi->mi_wantcredits, PCMD); ! 74: goto again; ! 75: } ! 76: i = mri->mri_next; ! 77: if (mri->mri_desc[i] & MSCP_OWN) { ! 78: if (!canwait) { ! 79: splx(s); ! 80: return (NULL); ! 81: } ! 82: mi->mi_wantcmd = 1; ! 83: sleep((caddr_t) &mi->mi_wantcmd, PCMD); ! 84: goto again; ! 85: } ! 86: mi->mi_credits--; ! 87: mri->mri_desc[i] &= ~MSCP_INT; ! 88: mri->mri_next = (mri->mri_next + 1) % mri->mri_size; ! 89: splx(s); ! 90: mp = &mri->mri_ring[i]; ! 91: ! 92: /* ! 93: * Initialise some often-zero fields. ! 94: * ARE THE LAST TWO NECESSARY IN GENERAL? IT SURE WOULD BE ! 95: * NICE IF DEC SOLD DOCUMENTATION FOR THEIR OWN CONTROLLERS. ! 96: */ ! 97: mp->mscp_msglen = MSCP_MSGLEN; ! 98: mp->mscp_flags = 0; ! 99: mp->mscp_modifier = 0; ! 100: mp->mscp_seq.seq_bytecount = 0; ! 101: mp->mscp_seq.seq_buffer = 0; ! 102: mp->mscp_seq.seq_mapbase = 0; ! 103: /*???*/ mp->mscp_sccc.sccc_errlgfl = 0; ! 104: /*???*/ mp->mscp_sccc.sccc_copyspd = 0; ! 105: return (mp); ! 106: #undef mri ! 107: } ! 108: ! 109: #ifdef AVOID_EMULEX_BUG ! 110: int mscp_aeb_xor = 0x8000bb80; ! 111: #endif ! 112: ! 113: /* ! 114: * Do a device go. The driver calls this once it has allocated ! 115: * resources for the transfer. Save the resource information in ! 116: * bp->b_ubinfo, and finish the MSCP packet. ! 117: * ! 118: * N.B.: If we were blocked for some time, the drive could have gone ! 119: * off line and might still be that way. We should probably handle ! 120: * such a case by changing this command into an on line request and ! 121: * not dequeuing the transfer after all. ! 122: */ ! 123: mscp_go(mi, mp, info) ! 124: register struct mscp_info *mi; ! 125: register struct mscp *mp; ! 126: int info; ! 127: { ! 128: register struct buf *bp, *dp; ! 129: ! 130: /* ! 131: * Now is also the time to move the transfer off the ! 132: * controller and drive queues, and shuffle the drive ! 133: * queue on the controller queue. The idea is to try ! 134: * to keep as many drives busy as possible---to deal ! 135: * the controller's credits out to the drives in a `fair ! 136: * share' arrangement. (To do this fully would be more ! 137: * trouble than it is worth, though.) ! 138: */ ! 139: dp = mi->mi_tab->b_actf; ! 140: bp = dp->b_actf; ! 141: dp->b_actf = bp->av_forw; /* transfer off drive queue */ ! 142: mi->mi_tab->b_actf = dp->b_forw;/* drive off ctlr queue */ ! 143: APPEND(dp, mi->mi_tab, b_forw); /* then back again */ ! 144: ! 145: /* ! 146: * Move the buffer to the I/O wait queue. ! 147: */ ! 148: bp->av_back = mi->mi_wtab.av_back; ! 149: bp->av_forw = &mi->mi_wtab; ! 150: mi->mi_wtab.av_back->av_forw = bp; ! 151: mi->mi_wtab.av_back = bp; ! 152: ! 153: /* ! 154: * Save the mapping info, finish the command packet, and give ! 155: * it to the device. The device's dgo routine should then ! 156: * initiate polling. ! 157: */ ! 158: bp->b_info = info; ! 159: #ifdef AVOID_EMULEX_BUG ! 160: /* ! 161: * The Emulex SC41/MS will occasionally zero the lower half word ! 162: * of the command reference number. The upper half word remains ! 163: * intact. To keep running, we convert the buffer address into ! 164: * a small but nonzero integer that is unique over all pending ! 165: * transfers, and store that value in the upper half word. To ! 166: * catch occurrances of the bug (so that we can gripe to Emulex), ! 167: * we also put a nonzero value in the lower word. ! 168: */ ! 169: { ! 170: register u_int i = mi->mi_nextbp; ! 171: ! 172: do { /* find a free value */ ! 173: if (mi->mi_bp[i] == 0) ! 174: goto found; ! 175: i = (i + 1) % AEB_MAX_BP; ! 176: } while (i != mi->mi_nextbp); ! 177: panic("mscp_go: AEB_MAX_BP too small"); ! 178: found: ! 179: mi->mi_bp[i++] = bp; ! 180: mi->mi_nextbp = i % AEB_MAX_BP; ! 181: mp->mscp_cmdref = (i << 16) ^ mscp_aeb_xor; ! 182: } ! 183: #else ! 184: mp->mscp_cmdref = (long) bp; ! 185: #endif ! 186: *mp->mscp_addr |= MSCP_OWN | MSCP_INT; ! 187: } ! 188: ! 189: /* ! 190: * Handle a response ring transition. ! 191: */ ! 192: mscp_dorsp(mi) ! 193: register struct mscp_info *mi; ! 194: { ! 195: register struct uba_device *ui; ! 196: register struct buf *bp; ! 197: register struct mscp *mp; ! 198: register int nextrsp; ! 199: struct mscp_driver *md = mi->mi_md; ! 200: char *ctlrname, *drivename; ! 201: int st, error, info; ! 202: ! 203: ctlrname = md->md_mname; ! 204: drivename = md->md_dname; ! 205: nextrsp = mi->mi_rsp.mri_next; ! 206: loop: ! 207: if (mi->mi_rsp.mri_desc[nextrsp] & MSCP_OWN) { ! 208: /* ! 209: * No more responses. Remember the next expected ! 210: * response index. Check to see if we have some ! 211: * credits back, and wake up sleepers if so. ! 212: */ ! 213: mi->mi_rsp.mri_next = nextrsp; ! 214: if (mi->mi_wantcredits && mi->mi_credits > MSCP_MINCREDITS) { ! 215: mi->mi_wantcredits = 0; ! 216: wakeup((caddr_t) &mi->mi_wantcredits); ! 217: } ! 218: return; ! 219: } ! 220: ! 221: /* ! 222: * Found a response. Update credit information. If there is ! 223: * nothing else to do, jump to `done' to get the next response. ! 224: */ ! 225: mp = &mi->mi_rsp.mri_ring[nextrsp]; ! 226: mi->mi_credits += MSCP_CREDITS(mp->mscp_msgtc); ! 227: switch (MSCP_MSGTYPE(mp->mscp_msgtc)) { ! 228: ! 229: case MSCPT_SEQ: ! 230: break; ! 231: ! 232: case MSCPT_DATAGRAM: ! 233: (*md->md_dgram)(mi, mp); ! 234: goto done; ! 235: ! 236: case MSCPT_CREDITS: ! 237: goto done; ! 238: ! 239: case MSCPT_MAINTENANCE: ! 240: default: ! 241: printf("%s%d: unit %d: unknown message type 0x%x ignored\n", ! 242: ctlrname, mi->mi_ctlr, mp->mscp_unit, ! 243: MSCP_MSGTYPE(mp->mscp_msgtc)); ! 244: goto done; ! 245: } ! 246: ! 247: /* ! 248: * Controllers are allowed to interrupt as any drive, so we ! 249: * must check the command before checking for a drive. ! 250: */ ! 251: if (mp->mscp_opcode == (M_OP_SETCTLRC | M_OP_END)) { ! 252: (*md->md_ctlrdone)(mi, mp); ! 253: goto done; ! 254: } ! 255: ! 256: /* ! 257: * Find the drive info. If there is none, and this is an ! 258: * available attention response, try configuring a new drive. ! 259: */ ! 260: if (mp->mscp_unit > md->md_ndpc) { ! 261: printf("%s%d: unit %d out of range\n", ! 262: ctlrname, mi->mi_ctlr, mp->mscp_unit); ! 263: goto done; ! 264: } ! 265: if ((ui = mi->mi_ip[mp->mscp_unit]) == NULL) { ! 266: if ((*md->md_unconf)(mi, mp) != MSCP_DONE) { ! 267: printf("%s%d: unit %d not configured, ", ! 268: ctlrname, mi->mi_ctlr, mp->mscp_unit); ! 269: if (mp->mscp_opcode == M_OP_AVAILATTN) ! 270: printf("available attn"); ! 271: else ! 272: printf("stray response op 0x%x status 0x%x", ! 273: mp->mscp_opcode, mp->mscp_status); ! 274: printf(" ignored\n"); ! 275: } ! 276: goto done; ! 277: } ! 278: ! 279: /* ! 280: * Handle individual responses. ! 281: */ ! 282: st = mp->mscp_status & M_ST_MASK; ! 283: error = 0; ! 284: switch (mp->mscp_opcode) { ! 285: ! 286: case M_OP_END: ! 287: /* ! 288: * The controller presents a bogus END packet when ! 289: * a read/write command is given with an illegal ! 290: * block number. This is contrary to the MSCP ! 291: * specification (ENDs are to be given only for ! 292: * invalid commands), but that is the way of it. ! 293: */ ! 294: if (st == M_ST_INVALCMD && mp->mscp_cmdref != 0) { ! 295: printf("%s%d: bad lbn (%d)?\n", drivename, ! 296: ui->ui_unit, mp->mscp_seq.seq_lbn); ! 297: error = EIO; ! 298: goto rwend; ! 299: } ! 300: goto unknown; ! 301: ! 302: case M_OP_ONLINE | M_OP_END: ! 303: /* ! 304: * Finished an ON LINE request. Call the driver to ! 305: * find out whether it succeeded. If so, mark it on ! 306: * line. ! 307: */ ! 308: if (ui->ui_flags & UNIT_ONLINE) { ! 309: printf("%s%d: duplicate ONLINE ignored\n", ! 310: drivename, ui->ui_unit); ! 311: break; ! 312: } ! 313: if ((*md->md_online)(ui, mp) == MSCP_DONE) ! 314: ui->ui_flags |= UNIT_ONLINE; ! 315: break; ! 316: ! 317: case M_OP_GETUNITST | M_OP_END: ! 318: /* ! 319: * Got unit status. Call the driver to find out ! 320: * whether it succeeded, and if so, mark it. ! 321: */ ! 322: if ((*md->md_gotstatus)(ui, mp) == MSCP_DONE) ! 323: ui->ui_flags |= UNIT_HAVESTATUS; ! 324: break; ! 325: ! 326: case M_OP_AVAILATTN: ! 327: /* ! 328: * The drive went offline and we did not notice. ! 329: * Mark it off line now, to force an on line request ! 330: * next, so we can make sure it is still the same ! 331: * drive. ! 332: * ! 333: * IF THE UDA DRIVER HAS A COMMAND AWAITING UNIBUS ! 334: * RESOURCES, THAT COMMAND MAY GO OUT BEFORE THE ON ! 335: * LINE. IS IT WORTH FIXING?? ! 336: */ ! 337: ui->ui_flags &= ~(UNIT_ONLINE | UNIT_HAVESTATUS); ! 338: #ifdef notyet ! 339: (*md->md_offline)(ui, mp); ! 340: #endif ! 341: break; ! 342: ! 343: case M_OP_READ | M_OP_END: ! 344: case M_OP_WRITE | M_OP_END: ! 345: /* ! 346: * A transfer finished. Get the buffer, and release its ! 347: * map registers via ubadone(). If the command finished ! 348: * with an off line or available status, the drive went ! 349: * off line (the idiot controller does not tell us until ! 350: * it comes back *on* line, or until we try to use it). ! 351: */ ! 352: if (mp->mscp_cmdref == 0) { ! 353: /* ! 354: * No buffer means there is a bug somewhere! ! 355: */ ! 356: printf("%s%d: io done, but no buffer?\n", ! 357: drivename, ui->ui_unit); ! 358: mscp_hexdump(mp); ! 359: break; ! 360: } ! 361: ! 362: rwend: ! 363: #ifdef AVOID_EMULEX_BUG ! 364: { ! 365: register u_short *p = (u_short *) &mp->mscp_cmdref; ! 366: ! 367: /* ! 368: * Note any errors on the part of the controller. ! 369: * The lower word should be zero after exclusive ! 370: * or'ing with mscp_aeb_xor, and the upper should ! 371: * then be in the range [1..AEB_MAX_BP]. ! 372: */ ! 373: mp->mscp_cmdref ^= mscp_aeb_xor; ! 374: p[1]--; ! 375: if (p[1] >= AEB_MAX_BP) ! 376: panic("unrecoverable Emulex screwup"); ! 377: if (p[0] == 0) ! 378: mi->mi_ok++; ! 379: else { ! 380: /* ! 381: * Calculate the expected response, ! 382: * assuming p[1] is correct. The ! 383: * actual response is then the expected ! 384: * response xor p[0]. ! 385: */ ! 386: int sb = ((p[1] + 1) << 16) ^ mscp_aeb_xor; ! 387: ! 388: log(LOG_WARNING, "\ ! 389: Emulex SC41/MS screwup: %s%d, got %d correct, then changed 0x%x to 0x%x\n", ! 390: ctlrname, mi->mi_ctlr, ! 391: mi->mi_ok, sb, sb ^ p[0]); ! 392: mi->mi_ok = 0; ! 393: } ! 394: /* convert index back to buffer, and mark free */ ! 395: bp = mi->mi_bp[p[1]]; ! 396: mi->mi_bp[p[1]] = 0; ! 397: } ! 398: #else ! 399: bp = (struct buf *) mp->mscp_cmdref; ! 400: #ifdef MSCP_PARANOIA ! 401: { ! 402: register struct buf *q = mi->mi_wtab.av_forw; ! 403: ! 404: /* ! 405: * Ensure that this response corresponds to ! 406: * some outstanding request. If not, ignore ! 407: * it entirely. This will likely cause a ! 408: * Unibus reset soon, after which the controller ! 409: * just might behave. ! 410: */ ! 411: while (q != bp && q != &mi->mi_wtab) ! 412: q = q->av_forw; ! 413: if (q != bp) { ! 414: printf("%s%d: bad response packet ignored\n", ! 415: ctlrname, mi->mi_ctlr); ! 416: mscp_hexdump(mp); ! 417: goto out; ! 418: } ! 419: } ! 420: #endif MSCP_PARANOIA ! 421: #endif AVOID_EMULEX_BUG ! 422: ! 423: /* ! 424: * Mark any error-due-to-bad-LBN (via `goto rwend'). ! 425: * WHAT STATUS WILL THESE HAVE? IT SURE WOULD BE NICE ! 426: * IF DEC SOLD DOCUMENTATION FOR THEIR OWN CONTROLLERS. ! 427: */ ! 428: if (error) { ! 429: bp->b_flags |= B_ERROR; ! 430: bp->b_error = error; ! 431: } ! 432: if (st == M_ST_OFFLINE || st == M_ST_AVAILABLE) { ! 433: ui->ui_flags &= ~(UNIT_ONLINE | UNIT_HAVESTATUS); ! 434: #ifdef notyet ! 435: (*md->md_offline)(ui, mp); ! 436: #endif ! 437: } ! 438: ! 439: /* ! 440: * Unlink the transfer from the wait queue mi_wtab. ! 441: * If there are no more transfers on the drive queue ! 442: * for this drive, and it is a profiled disk, turn ! 443: * off its busy bit. ! 444: */ ! 445: bp->av_back->av_forw = bp->av_forw; ! 446: bp->av_forw->av_back = bp->av_back; ! 447: if (ui->ui_dk >= 0 && md->md_utab[ui->ui_unit].b_forw == NULL) ! 448: dk_busy &= ~(1 << ui->ui_dk); ! 449: ! 450: /* ! 451: * If the transfer has something to do with bad ! 452: * block forwarding, let the driver handle the ! 453: * rest. ! 454: */ ! 455: if ((bp->b_flags & B_BAD) != 0 && md->md_bb != NULL) { ! 456: (*md->md_bb)(ui, mp, bp); ! 457: goto out; ! 458: } ! 459: ! 460: /* ! 461: * If the transfer failed, give the driver a crack ! 462: * at fixing things up. ! 463: */ ! 464: if (st != M_ST_SUCCESS) { ! 465: switch ((*md->md_ioerr)(ui, mp, bp)) { ! 466: ! 467: case MSCP_DONE: /* fixed */ ! 468: break; ! 469: ! 470: case MSCP_RESTARTED: /* still working on it */ ! 471: goto out; ! 472: ! 473: case MSCP_FAILED: /* no luck */ ! 474: diskerr(bp, drivename, "hard error", ! 475: LOG_PRINTF, -1, md->md_lab ? ! 476: &md->md_lab[ui->ui_unit] : md->md_lab); ! 477: mscp_printevent(mp); ! 478: bp->b_flags |= B_ERROR; ! 479: bp->b_error = EIO; ! 480: break; ! 481: } ! 482: } ! 483: ! 484: /* ! 485: * Set the residual count and mark the transfer as ! 486: * done. If the I/O wait queue is now empty, release ! 487: * the shared BDP, if any. ! 488: */ ! 489: info = bp->b_info; /* we are about to clobber it */ ! 490: bp->b_resid = bp->b_bcount - mp->mscp_seq.seq_bytecount; ! 491: (*md->md_iodone)(mi, bp, info); ! 492: out: ! 493: break; ! 494: ! 495: case M_OP_REPLACE | M_OP_END: ! 496: /* ! 497: * A replace operation finished. Just let the driver ! 498: * handle it (if it does replaces). ! 499: */ ! 500: if (md->md_replace == NULL) ! 501: printf("%s%d: bogus REPLACE end\n", ! 502: drivename, ui->ui_unit); ! 503: else ! 504: (*md->md_replace)(ui, mp); ! 505: break; ! 506: ! 507: default: ! 508: /* ! 509: * If it is not one of the above, we cannot handle it. ! 510: * (And we should not have received it, for that matter.) ! 511: */ ! 512: unknown: ! 513: printf("%s%d: unknown opcode 0x%x status 0x%x ignored\n", ! 514: mi->mi_md->md_dname, ui->ui_unit, ! 515: mp->mscp_opcode, mp->mscp_status); ! 516: mscp_hexdump(mp); ! 517: break; ! 518: } ! 519: ! 520: /* ! 521: * If the drive needs to be put back in the controller queue, ! 522: * do that now. (`bp' below ought to be `dp', but they are all ! 523: * struct buf *.) Note that b_active was cleared in the driver; ! 524: * we presume that there is something to be done, hence reassert it. ! 525: */ ! 526: if (ui->ui_flags & UNIT_REQUEUE) { ! 527: bp = &md->md_utab[ui->ui_unit]; ! 528: if (bp->b_active) panic("mscp_dorsp requeue"); ! 529: APPEND(bp, mi->mi_tab, b_forw); ! 530: bp->b_active = 1; ! 531: ui->ui_flags &= ~UNIT_REQUEUE; ! 532: } ! 533: ! 534: done: ! 535: /* ! 536: * Give back the response packet, and take a look at the next. ! 537: */ ! 538: mp->mscp_msglen = MSCP_MSGLEN; ! 539: mi->mi_rsp.mri_desc[nextrsp] |= MSCP_OWN; ! 540: nextrsp = (nextrsp + 1) % mi->mi_rsp.mri_size; ! 541: goto loop; ! 542: } ! 543: ! 544: /* ! 545: * Dump the entire contents of an MSCP packet in hex. Mainly useful ! 546: * for debugging.... ! 547: */ ! 548: mscp_hexdump(mp) ! 549: register struct mscp *mp; ! 550: { ! 551: register long *p = (long *) mp; ! 552: register int i = mp->mscp_msglen; ! 553: ! 554: if (i > 256) /* sanity */ ! 555: i = 256; ! 556: i /= sizeof (*p); /* ASSUMES MULTIPLE OF sizeof(long) */ ! 557: while (--i >= 0) ! 558: printf("0x%x ", *p++); ! 559: printf("\n"); ! 560: } ! 561: ! 562: /* ! 563: * Requeue outstanding transfers, e.g., after bus reset. ! 564: * Also requeue any drives that have on line or unit status ! 565: * info pending. ! 566: */ ! 567: mscp_requeue(mi) ! 568: struct mscp_info *mi; ! 569: { ! 570: register struct uba_device *ui; ! 571: register struct mscp_driver *md = mi->mi_md; ! 572: register struct buf *bp, *dp; ! 573: register int unit; ! 574: struct buf *nextbp; ! 575: ! 576: /* ! 577: * Clear the controller chain. Mark everything un-busy; we ! 578: * will soon fix any that are in fact busy. ! 579: */ ! 580: mi->mi_tab->b_actf = NULL; ! 581: mi->mi_tab->b_active = 0; ! 582: for (unit = 0, dp = md->md_utab; unit < md->md_nunits; unit++, dp++) { ! 583: ui = md->md_dinfo[unit]; ! 584: if (ui == NULL || !ui->ui_alive || ui->ui_ctlr != mi->mi_ctlr) ! 585: continue; /* not ours */ ! 586: dp->b_forw = NULL; ! 587: dp->b_active = 0; ! 588: } ! 589: ! 590: /* ! 591: * Scan the wait queue, linking buffers onto drive queues. ! 592: * Note that these must be put at the front of the drive queue, ! 593: * lest we reorder I/O operations. ! 594: */ ! 595: for (bp = mi->mi_wtab.av_back; bp != &mi->mi_wtab; bp = nextbp) { ! 596: nextbp = bp->av_back; ! 597: dp = &md->md_utab[minor(bp->b_dev) >> md->md_unitshift]; ! 598: bp->av_forw = dp->b_actf; ! 599: if (dp->b_actf == NULL) ! 600: dp->b_actl = bp; ! 601: dp->b_actf = bp; ! 602: } ! 603: mi->mi_wtab.av_forw = mi->mi_wtab.av_back = &mi->mi_wtab; ! 604: ! 605: /* ! 606: * Scan for drives waiting for on line or status responses, ! 607: * and for drives with pending transfers. Put these on the ! 608: * controller queue, and mark the controller busy. ! 609: */ ! 610: for (unit = 0, dp = md->md_utab; unit < md->md_nunits; unit++, dp++) { ! 611: ui = md->md_dinfo[unit]; ! 612: if (ui == NULL || !ui->ui_alive || ui->ui_ctlr != mi->mi_ctlr) ! 613: continue; ! 614: ui->ui_flags &= ~(UNIT_HAVESTATUS | UNIT_ONLINE); ! 615: if ((ui->ui_flags & UNIT_REQUEUE) == 0 && dp->b_actf == NULL) ! 616: continue; ! 617: ui->ui_flags &= ~UNIT_REQUEUE; ! 618: APPEND(dp, mi->mi_tab, b_forw); ! 619: dp->b_active = 1; ! 620: mi->mi_tab->b_active = 1; ! 621: } ! 622: ! 623: #ifdef AVOID_EMULEX_BUG ! 624: /* ! 625: * ... and clear the index-to-buffer table. ! 626: */ ! 627: for (unit = 0; unit < AEB_MAX_BP; unit++) ! 628: mi->mi_bp[unit] = 0; ! 629: #endif ! 630: } ! 631: ! 632: ! 633: /* ! 634: * MSCP error reporting ! 635: */ ! 636: ! 637: /* ! 638: * Messages for the various subcodes. ! 639: */ ! 640: static char unknown_msg[] = "unknown subcode"; ! 641: ! 642: /* ! 643: * Subcodes for Success (0) ! 644: */ ! 645: static char *succ_msgs[] = { ! 646: "normal", /* 0 */ ! 647: "spin down ignored", /* 1 = Spin-Down Ignored */ ! 648: "still connected", /* 2 = Still Connected */ ! 649: unknown_msg, ! 650: "dup. unit #", /* 4 = Duplicate Unit Number */ ! 651: unknown_msg, ! 652: unknown_msg, ! 653: unknown_msg, ! 654: "already online", /* 8 = Already Online */ ! 655: unknown_msg, ! 656: unknown_msg, ! 657: unknown_msg, ! 658: unknown_msg, ! 659: unknown_msg, ! 660: unknown_msg, ! 661: unknown_msg, ! 662: "still online", /* 16 = Still Online */ ! 663: }; ! 664: ! 665: /* ! 666: * Subcodes for Invalid Command (1) ! 667: */ ! 668: static char *icmd_msgs[] = { ! 669: "invalid msg length", /* 0 = Invalid Message Length */ ! 670: }; ! 671: ! 672: /* ! 673: * Subcodes for Command Aborted (2) ! 674: */ ! 675: /* none known */ ! 676: ! 677: /* ! 678: * Subcodes for Unit Offline (3) ! 679: */ ! 680: static char *offl_msgs[] = { ! 681: "unknown drive", /* 0 = Unknown, or online to other ctlr */ ! 682: "not mounted", /* 1 = Unmounted, or RUN/STOP at STOP */ ! 683: "inoperative", /* 2 = Unit Inoperative */ ! 684: unknown_msg, ! 685: "duplicate", /* 4 = Duplicate Unit Number */ ! 686: unknown_msg, ! 687: unknown_msg, ! 688: unknown_msg, ! 689: "in diagnosis", /* 8 = Disabled by FS or diagnostic */ ! 690: }; ! 691: ! 692: /* ! 693: * Subcodes for Unit Available (4) ! 694: */ ! 695: /* none known */ ! 696: ! 697: /* ! 698: * Subcodes for Media Format Error (5) ! 699: */ ! 700: static char *media_fmt_msgs[] = { ! 701: "fct unread - edc", /* 0 = FCT unreadable */ ! 702: "invalid sector header",/* 1 = Invalid Sector Header */ ! 703: "not 512 sectors", /* 2 = Not 512 Byte Sectors */ ! 704: "not formatted", /* 3 = Not Formatted */ ! 705: "fct ecc", /* 4 = FCT ECC */ ! 706: }; ! 707: ! 708: /* ! 709: * Subcodes for Write Protected (6) ! 710: * N.B.: Code 6 subcodes are 7 bits higher than other subcodes ! 711: * (i.e., bits 12-15). ! 712: */ ! 713: static char *wrprot_msgs[] = { ! 714: unknown_msg, ! 715: "software", /* 1 = Software Write Protect */ ! 716: "hardware", /* 2 = Hardware Write Protect */ ! 717: }; ! 718: ! 719: /* ! 720: * Subcodes for Compare Error (7) ! 721: */ ! 722: /* none known */ ! 723: ! 724: /* ! 725: * Subcodes for Data Error (8) ! 726: */ ! 727: static char *data_msgs[] = { ! 728: "forced error", /* 0 = Forced Error (software) */ ! 729: unknown_msg, ! 730: "header compare", /* 2 = Header Compare Error */ ! 731: "sync timeout", /* 3 = Sync Timeout Error */ ! 732: unknown_msg, ! 733: unknown_msg, ! 734: unknown_msg, ! 735: "uncorrectable ecc", /* 7 = Uncorrectable ECC */ ! 736: "1 symbol ecc", /* 8 = 1 bit ECC */ ! 737: "2 symbol ecc", /* 9 = 2 bit ECC */ ! 738: "3 symbol ecc", /* 10 = 3 bit ECC */ ! 739: "4 symbol ecc", /* 11 = 4 bit ECC */ ! 740: "5 symbol ecc", /* 12 = 5 bit ECC */ ! 741: "6 symbol ecc", /* 13 = 6 bit ECC */ ! 742: "7 symbol ecc", /* 14 = 7 bit ECC */ ! 743: "8 symbol ecc", /* 15 = 8 bit ECC */ ! 744: }; ! 745: ! 746: /* ! 747: * Subcodes for Host Buffer Access Error (9) ! 748: */ ! 749: static char *host_buffer_msgs[] = { ! 750: unknown_msg, ! 751: "odd xfer addr", /* 1 = Odd Transfer Address */ ! 752: "odd xfer count", /* 2 = Odd Transfer Count */ ! 753: "non-exist. memory", /* 3 = Non-Existent Memory */ ! 754: "memory parity", /* 4 = Memory Parity Error */ ! 755: }; ! 756: ! 757: /* ! 758: * Subcodes for Controller Error (10) ! 759: */ ! 760: static char *cntlr_msgs[] = { ! 761: unknown_msg, ! 762: "serdes overrun", /* 1 = Serialiser/Deserialiser Overrun */ ! 763: "edc", /* 2 = Error Detection Code? */ ! 764: "inconsistant internal data struct",/* 3 = Internal Error */ ! 765: }; ! 766: ! 767: /* ! 768: * Subcodes for Drive Error (11) ! 769: */ ! 770: static char *drive_msgs[] = { ! 771: unknown_msg, ! 772: "sdi command timeout", /* 1 = SDI Command Timeout */ ! 773: "ctlr detected protocol",/* 2 = Controller Detected Protocol Error */ ! 774: "positioner", /* 3 = Positioner Error */ ! 775: "lost rd/wr ready", /* 4 = Lost R/W Ready Error */ ! 776: "drive clock dropout", /* 5 = Lost Drive Clock */ ! 777: "lost recvr ready", /* 6 = Lost Receiver Ready */ ! 778: "drive detected error", /* 7 = Drive Error */ ! 779: "ctlr detected pulse or parity",/* 8 = Pulse or Parity Error */ ! 780: }; ! 781: ! 782: /* ! 783: * The following table correlates message codes with the ! 784: * decoding strings. ! 785: */ ! 786: struct code_decode { ! 787: char *cdc_msg; ! 788: int cdc_nsubcodes; ! 789: char **cdc_submsgs; ! 790: } code_decode[] = { ! 791: #define SC(m) sizeof (m) / sizeof (m[0]), m ! 792: "success", SC(succ_msgs), ! 793: "invalid command", SC(icmd_msgs), ! 794: "command aborted", 0, 0, ! 795: "unit offline", SC(offl_msgs), ! 796: "unit available", 0, 0, ! 797: "media format error", SC(media_fmt_msgs), ! 798: "write protected", SC(wrprot_msgs), ! 799: "compare error", 0, 0, ! 800: "data error", SC(data_msgs), ! 801: "host buffer access error", SC(host_buffer_msgs), ! 802: "controller error", SC(cntlr_msgs), ! 803: "drive error", SC(drive_msgs), ! 804: #undef SC ! 805: }; ! 806: ! 807: /* ! 808: * Print the decoded error event from an MSCP error datagram. ! 809: */ ! 810: mscp_printevent(mp) ! 811: struct mscp *mp; ! 812: { ! 813: register int event = mp->mscp_event; ! 814: register struct code_decode *cdc; ! 815: int c, sc; ! 816: char *cm, *scm; ! 817: ! 818: /* ! 819: * The code is the lower six bits of the event number (aka ! 820: * status). If that is 6 (write protect), the subcode is in ! 821: * bits 12-15; otherwise, it is in bits 5-11. ! 822: * I WONDER WHAT THE OTHER BITS ARE FOR. IT SURE WOULD BE ! 823: * NICE IF DEC SOLD DOCUMENTATION FOR THEIR OWN CONTROLLERS. ! 824: */ ! 825: c = event & M_ST_MASK; ! 826: sc = (c != 6 ? event >> 5 : event >> 12) & 0x7ff; ! 827: if (c >= sizeof code_decode / sizeof code_decode[0]) ! 828: cm = "- unknown code", scm = "??"; ! 829: else { ! 830: cdc = &code_decode[c]; ! 831: cm = cdc->cdc_msg; ! 832: if (sc >= cdc->cdc_nsubcodes) ! 833: scm = unknown_msg; ! 834: else ! 835: scm = cdc->cdc_submsgs[sc]; ! 836: } ! 837: printf(" %s (%s) (code %d, subcode %d)\n", cm, scm, c, sc); ! 838: } ! 839: ! 840: /* ! 841: * Print the code and logical block number for an error packet. ! 842: * THIS IS PROBABLY PECULIAR TO DISK DRIVES. IT SURE WOULD BE ! 843: * NICE IF DEC SOLD DOCUMENTATION FOR THEIR OWN CONTROLLERS. ! 844: */ ! 845: mscp_decodeerror(name, ctlr, mp) ! 846: char *name; ! 847: int ctlr; ! 848: register struct mscp *mp; ! 849: { ! 850: /* ! 851: * For bad blocks, mp->mscp_erd.erd_hdr identifies a code and ! 852: * the logical block number. Code 0 is a regular block; code 6 ! 853: * is a replacement block. The remaining codes are currently ! 854: * undefined. The code is in the upper four bits of the header ! 855: * (bits 0-27 are the lbn). ! 856: */ ! 857: int issoft = mp->mscp_flags & (M_LF_SUCC | M_LF_CONT); ! 858: static char *codemsg[16] = { ! 859: "lbn", "code 1", "code 2", "code 3", ! 860: "code 4", "code 5", "rbn", "code 7", ! 861: "code 8", "code 9", "code 10", "code 11", ! 862: "code 12", "code 13", "code 14", "code 15" ! 863: }; ! 864: #define BADCODE(h) (codemsg[(unsigned)(h) >> 28]) ! 865: #define BADLBN(h) ((h) & 0xfffffff) ! 866: ! 867: printf("%s%d: %s error datagram%s:", name, ctlr, ! 868: issoft ? "soft" : "hard", ! 869: mp->mscp_flags & M_LF_CONT ? " (continuing)" : ""); ! 870: switch (mp->mscp_format & 0377) { ! 871: ! 872: case M_FM_CTLRERR: /* controller error */ ! 873: break; ! 874: ! 875: case M_FM_BUSADDR: /* host memory access error */ ! 876: printf(" memory addr 0x%x:", mp->mscp_erd.erd_busaddr); ! 877: break; ! 878: ! 879: case M_FM_DISKTRN: ! 880: printf(" unit %d: level %d retry %d, %s %d:", ! 881: mp->mscp_unit, ! 882: mp->mscp_erd.erd_level, mp->mscp_erd.erd_retry, ! 883: BADCODE(mp->mscp_erd.erd_hdr), ! 884: BADLBN(mp->mscp_erd.erd_hdr)); ! 885: break; ! 886: ! 887: case M_FM_SDI: ! 888: printf(" unit %d: %s %d:", mp->mscp_unit, ! 889: BADCODE(mp->mscp_erd.erd_hdr), ! 890: BADLBN(mp->mscp_erd.erd_hdr)); ! 891: break; ! 892: ! 893: case M_FM_SMLDSK: ! 894: printf(" unit %d: small disk error, cyl %d:", ! 895: mp->mscp_unit, mp->mscp_erd.erd_sdecyl); ! 896: break; ! 897: ! 898: default: ! 899: printf(" unit %d: unknown error, format 0x%x:", ! 900: mp->mscp_unit, mp->mscp_format); ! 901: } ! 902: mscp_printevent(mp); ! 903: #undef BADCODE ! 904: #undef BADLBN ! 905: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.