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