|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1990 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * This code is derived from software contributed to Berkeley by ! 6: * Van Jacobson of Lawrence Berkeley Laboratory. ! 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: * @(#)scsi.c 7.1 (Berkeley) 5/8/90 ! 24: */ ! 25: ! 26: /* ! 27: * HP9000/3xx 98658 SCSI host adaptor driver. ! 28: */ ! 29: #include "scsi.h" ! 30: #if NSCSI > 0 ! 31: ! 32: #ifndef lint ! 33: static char rcsid[] = "$Header: scsi.c,v 1.3 90/01/06 04:56:50 van Exp $"; ! 34: #endif ! 35: ! 36: #include "param.h" ! 37: #include "systm.h" ! 38: #include "buf.h" ! 39: #include "device.h" ! 40: #include "scsivar.h" ! 41: #include "scsireg.h" ! 42: #include "dmavar.h" ! 43: ! 44: #include "machine/cpu.h" ! 45: #include "machine/isr.h" ! 46: ! 47: extern void isrlink(); ! 48: extern void printf(); ! 49: extern void _insque(); ! 50: extern void _remque(); ! 51: extern void bzero(); ! 52: ! 53: int scsiinit(), scsigo(), scsiintr(), scsixfer(); ! 54: void scsistart(), scsidone(), scsifree(), scsireset(); ! 55: struct driver scsidriver = { ! 56: scsiinit, "scsi", (int (*)())scsistart, scsigo, scsiintr, ! 57: (int (*)())scsidone, ! 58: }; ! 59: ! 60: struct scsi_softc scsi_softc[NSCSI]; ! 61: struct isr scsi_isr[NSCSI]; ! 62: ! 63: int scsi_cmd_wait = 512; /* microsec wait per step of 'immediate' cmds */ ! 64: int scsi_data_wait = 512; /* wait per data in/out step */ ! 65: int scsi_nosync = 1; /* inhibit sync xfers if 1 */ ! 66: ! 67: #ifdef DEBUG ! 68: int scsi_debug = 0; ! 69: #define WAITHIST ! 70: #endif ! 71: ! 72: #ifdef WAITHIST ! 73: #define MAXWAIT 2048 ! 74: u_int ixstart_wait[MAXWAIT+2]; ! 75: u_int ixin_wait[MAXWAIT+2]; ! 76: u_int ixout_wait[MAXWAIT+2]; ! 77: u_int mxin_wait[MAXWAIT+2]; ! 78: u_int cxin_wait[MAXWAIT+2]; ! 79: u_int fxfr_wait[MAXWAIT+2]; ! 80: u_int sgo_wait[MAXWAIT+2]; ! 81: #define HIST(h,w) (++h[((w)>MAXWAIT? MAXWAIT : ((w) < 0 ? -1 : (w))) + 1]); ! 82: #else ! 83: #define HIST(h,w) ! 84: #endif ! 85: ! 86: #define b_cylin b_resid ! 87: ! 88: static void ! 89: scsiabort(hs, hd, where) ! 90: register struct scsi_softc *hs; ! 91: volatile register struct scsidevice *hd; ! 92: char *where; ! 93: { ! 94: int len; ! 95: u_char junk; ! 96: ! 97: printf("scsi%d: abort from %s: phase=0x%x, ssts=0x%x, ints=0x%x\n", ! 98: hs->sc_hc->hp_unit, where, hd->scsi_psns, hd->scsi_ssts, ! 99: hd->scsi_ints); ! 100: ! 101: hd->scsi_ints = hd->scsi_ints; ! 102: hd->scsi_csr = 0; ! 103: if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0) ! 104: /* no longer connected to scsi target */ ! 105: return; ! 106: ! 107: /* get the number of bytes remaining in current xfer + fudge */ ! 108: len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl; ! 109: ! 110: /* for that many bus cycles, try to send an abort msg */ ! 111: for (len += 1024; (hd->scsi_ssts & SSTS_INITIATOR) && --len >= 0; ) { ! 112: hd->scsi_scmd = SCMD_SET_ATN; ! 113: while ((hd->scsi_psns & PSNS_REQ) == 0) { ! 114: if (! (hd->scsi_ssts & SSTS_INITIATOR)) ! 115: goto out; ! 116: DELAY(1); ! 117: } ! 118: if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE) ! 119: hd->scsi_scmd = SCMD_RST_ATN; ! 120: hd->scsi_pctl = hd->scsi_psns & PHASE; ! 121: if (hd->scsi_psns & PHASE_IO) { ! 122: /* one of the input phases - read & discard a byte */ ! 123: hd->scsi_scmd = SCMD_SET_ACK; ! 124: if (hd->scsi_tmod == 0) ! 125: while (hd->scsi_psns & PSNS_REQ) ! 126: DELAY(1); ! 127: junk = hd->scsi_temp; ! 128: } else { ! 129: /* one of the output phases - send an abort msg */ ! 130: hd->scsi_temp = MSG_ABORT; ! 131: hd->scsi_scmd = SCMD_SET_ACK; ! 132: if (hd->scsi_tmod == 0) ! 133: while (hd->scsi_psns & PSNS_REQ) ! 134: DELAY(1); ! 135: } ! 136: hd->scsi_scmd = SCMD_RST_ACK; ! 137: } ! 138: out: ! 139: /* ! 140: * Either the abort was successful & the bus is disconnected or ! 141: * the device didn't listen. If the latter, announce the problem. ! 142: * Either way, reset the card & the SPC. ! 143: */ ! 144: if (len < 0 && hs) ! 145: printf("scsi%d: abort failed. phase=0x%x, ssts=0x%x\n", ! 146: hs->sc_hc->hp_unit, hd->scsi_psns, hd->scsi_ssts); ! 147: ! 148: if (! ((junk = hd->scsi_ints) & INTS_RESEL)) { ! 149: hd->scsi_sctl |= SCTL_CTRLRST; ! 150: DELAY(1); ! 151: hd->scsi_sctl &=~ SCTL_CTRLRST; ! 152: hd->scsi_hconf = 0; ! 153: hd->scsi_ints = hd->scsi_ints; ! 154: } ! 155: } ! 156: ! 157: int ! 158: scsiinit(hc) ! 159: register struct hp_ctlr *hc; ! 160: { ! 161: register struct scsi_softc *hs = &scsi_softc[hc->hp_unit]; ! 162: register struct scsidevice *hd = (struct scsidevice *)hc->hp_addr; ! 163: ! 164: if ((hd->scsi_id & ID_MASK) != SCSI_ID) ! 165: return(0); ! 166: hc->hp_ipl = SCSI_IPL(hd->scsi_csr); ! 167: hs->sc_hc = hc; ! 168: hs->sc_dq.dq_unit = hc->hp_unit; ! 169: hs->sc_dq.dq_driver = &scsidriver; ! 170: hs->sc_sq.dq_forw = hs->sc_sq.dq_back = &hs->sc_sq; ! 171: scsi_isr[hc->hp_unit].isr_intr = scsiintr; ! 172: scsi_isr[hc->hp_unit].isr_ipl = hc->hp_ipl; ! 173: scsi_isr[hc->hp_unit].isr_arg = hc->hp_unit; ! 174: isrlink(&scsi_isr[hc->hp_unit]); ! 175: scsireset(hc->hp_unit); ! 176: return(1); ! 177: } ! 178: ! 179: void ! 180: scsireset(unit) ! 181: register int unit; ! 182: { ! 183: register struct scsi_softc *hs = &scsi_softc[unit]; ! 184: volatile register struct scsidevice *hd = ! 185: (struct scsidevice *)hs->sc_hc->hp_addr; ! 186: u_int i; ! 187: ! 188: if (hs->sc_flags & SCSI_ALIVE) ! 189: scsiabort(hs, hd, "reset"); ! 190: ! 191: printf("scsi%d: ", unit); ! 192: ! 193: hd->scsi_id = 0xFF; ! 194: DELAY(100); ! 195: /* ! 196: * Disable interrupts then reset the FUJI chip. ! 197: */ ! 198: hd->scsi_csr = 0; ! 199: hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST; ! 200: hd->scsi_scmd = 0; ! 201: hd->scsi_tmod = 0; ! 202: hd->scsi_pctl = 0; ! 203: hd->scsi_temp = 0; ! 204: hd->scsi_tch = 0; ! 205: hd->scsi_tcm = 0; ! 206: hd->scsi_tcl = 0; ! 207: hd->scsi_ints = 0; ! 208: ! 209: if ((hd->scsi_id & ID_WORD_DMA) == 0) { ! 210: hs->sc_flags |= SCSI_DMA32; ! 211: printf("32 bit dma, "); ! 212: } ! 213: ! 214: /* Determine Max Synchronous Transfer Rate */ ! 215: if (scsi_nosync) ! 216: i = 3; ! 217: else ! 218: i = SCSI_SYNC_XFER(hd->scsi_hconf); ! 219: switch (i) { ! 220: case 0: ! 221: hs->sc_sync = TMOD_SYNC | 0x3e; /* 250 nsecs */ ! 222: printf("250ns sync"); ! 223: break; ! 224: case 1: ! 225: hs->sc_sync = TMOD_SYNC | 0x5e; /* 375 nsecs */ ! 226: printf("375ns sync"); ! 227: break; ! 228: case 2: ! 229: hs->sc_sync = TMOD_SYNC | 0x7d; /* 500 nsecs */ ! 230: printf("500ns sync"); ! 231: break; ! 232: case 3: ! 233: hs->sc_sync = 0; ! 234: printf("async"); ! 235: break; ! 236: } ! 237: ! 238: /* ! 239: * Configure the FUJI chip with its SCSI address, all ! 240: * interrupts enabled & appropriate parity. ! 241: */ ! 242: i = (~hd->scsi_hconf) & 0x7; ! 243: hs->sc_scsi_addr = 1 << i; ! 244: hd->scsi_bdid = i; ! 245: if (hd->scsi_hconf & HCONF_PARITY) ! 246: hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB | ! 247: SCTL_SEL_ENAB | SCTL_RESEL_ENAB | ! 248: SCTL_INTR_ENAB | SCTL_PARITY_ENAB; ! 249: else { ! 250: hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB | ! 251: SCTL_SEL_ENAB | SCTL_RESEL_ENAB | ! 252: SCTL_INTR_ENAB; ! 253: printf(", no parity"); ! 254: } ! 255: hd->scsi_sctl &=~ SCTL_DISABLE; ! 256: ! 257: printf(", scsi id %d\n", i); ! 258: hs->sc_flags |= SCSI_ALIVE; ! 259: } ! 260: ! 261: static void ! 262: scsierror(hs, hd, ints) ! 263: register struct scsi_softc *hs; ! 264: volatile register struct scsidevice *hd; ! 265: u_char ints; ! 266: { ! 267: int unit = hs->sc_hc->hp_unit; ! 268: char *sep = ""; ! 269: ! 270: printf("scsi%d: ", unit); ! 271: if (ints & INTS_RST) { ! 272: DELAY(100); ! 273: if (hd->scsi_hconf & HCONF_SD) ! 274: printf("spurious RST interrupt"); ! 275: else ! 276: printf("hardware error - check fuse"); ! 277: sep = ", "; ! 278: } ! 279: if ((ints & INTS_HARD_ERR) || hd->scsi_serr) { ! 280: if (hd->scsi_serr & SERR_SCSI_PAR) { ! 281: printf("%sparity err", sep); ! 282: sep = ", "; ! 283: } ! 284: if (hd->scsi_serr & SERR_SPC_PAR) { ! 285: printf("%sSPC parity err", sep); ! 286: sep = ", "; ! 287: } ! 288: if (hd->scsi_serr & SERR_TC_PAR) { ! 289: printf("%sTC parity err", sep); ! 290: sep = ", "; ! 291: } ! 292: if (hd->scsi_serr & SERR_PHASE_ERR) { ! 293: printf("%sphase err", sep); ! 294: sep = ", "; ! 295: } ! 296: if (hd->scsi_serr & SERR_SHORT_XFR) { ! 297: printf("%ssync short transfer err", sep); ! 298: sep = ", "; ! 299: } ! 300: if (hd->scsi_serr & SERR_OFFSET) { ! 301: printf("%ssync offset error", sep); ! 302: sep = ", "; ! 303: } ! 304: } ! 305: if (ints & INTS_TIMEOUT) ! 306: printf("%sSPC select timeout error", sep); ! 307: if (ints & INTS_SRV_REQ) ! 308: printf("%sspurious SRV_REQ interrupt", sep); ! 309: if (ints & INTS_CMD_DONE) ! 310: printf("%sspurious CMD_DONE interrupt", sep); ! 311: if (ints & INTS_DISCON) ! 312: printf("%sspurious disconnect interrupt", sep); ! 313: if (ints & INTS_RESEL) ! 314: printf("%sspurious reselect interrupt", sep); ! 315: if (ints & INTS_SEL) ! 316: printf("%sspurious select interrupt", sep); ! 317: printf("\n"); ! 318: } ! 319: ! 320: static int ! 321: issue_select(hd, target, our_addr) ! 322: volatile register struct scsidevice *hd; ! 323: u_char target, our_addr; ! 324: { ! 325: if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY)) ! 326: return (1); ! 327: ! 328: if (hd->scsi_ints & INTS_DISCON) ! 329: hd->scsi_ints = INTS_DISCON; ! 330: ! 331: hd->scsi_pctl = 0; ! 332: hd->scsi_temp = (1 << target) | our_addr; ! 333: /* select timeout is hardcoded to 2ms */ ! 334: hd->scsi_tch = 0; ! 335: hd->scsi_tcm = 32; ! 336: hd->scsi_tcl = 4; ! 337: ! 338: hd->scsi_scmd = SCMD_SELECT; ! 339: return (0); ! 340: } ! 341: ! 342: static int ! 343: wait_for_select(hd) ! 344: volatile register struct scsidevice *hd; ! 345: { ! 346: u_char ints; ! 347: ! 348: while ((ints = hd->scsi_ints) == 0) ! 349: DELAY(1); ! 350: hd->scsi_ints = ints; ! 351: return (!(hd->scsi_ssts & SSTS_INITIATOR)); ! 352: } ! 353: ! 354: static int ! 355: ixfer_start(hd, len, phase, wait) ! 356: volatile register struct scsidevice *hd; ! 357: int len; ! 358: u_char phase; ! 359: register int wait; ! 360: { ! 361: ! 362: hd->scsi_tch = len >> 16; ! 363: hd->scsi_tcm = len >> 8; ! 364: hd->scsi_tcl = len; ! 365: hd->scsi_pctl = phase; ! 366: hd->scsi_tmod = 0; /*XXX*/ ! 367: hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR; ! 368: ! 369: /* wait for xfer to start or svc_req interrupt */ ! 370: while ((hd->scsi_ssts & SSTS_BUSY) == 0) { ! 371: if (hd->scsi_ints || --wait < 0) { ! 372: #ifdef DEBUG ! 373: if (scsi_debug) ! 374: printf("ixfer_start fail: i%x, w%d\n", ! 375: hd->scsi_ints, wait); ! 376: #endif ! 377: HIST(ixstart_wait, wait) ! 378: return (0); ! 379: } ! 380: DELAY(1); ! 381: } ! 382: HIST(ixstart_wait, wait) ! 383: return (1); ! 384: } ! 385: ! 386: static int ! 387: ixfer_out(hd, len, buf) ! 388: volatile register struct scsidevice *hd; ! 389: int len; ! 390: register u_char *buf; ! 391: { ! 392: register int wait = scsi_data_wait; ! 393: ! 394: for (; len > 0; --len) { ! 395: while (hd->scsi_ssts & SSTS_DREG_FULL) { ! 396: if (hd->scsi_ints || --wait < 0) { ! 397: #ifdef DEBUG ! 398: if (scsi_debug) ! 399: printf("ixfer_out fail: l%d i%x w%d\n", ! 400: len, hd->scsi_ints, wait); ! 401: #endif ! 402: HIST(ixout_wait, wait) ! 403: return (len); ! 404: } ! 405: DELAY(1); ! 406: } ! 407: hd->scsi_dreg = *buf++; ! 408: } ! 409: HIST(ixout_wait, wait) ! 410: return (0); ! 411: } ! 412: ! 413: static void ! 414: ixfer_in(hd, len, buf) ! 415: volatile register struct scsidevice *hd; ! 416: int len; ! 417: register u_char *buf; ! 418: { ! 419: register int wait = scsi_data_wait; ! 420: ! 421: for (; len > 0; --len) { ! 422: while (hd->scsi_ssts & SSTS_DREG_EMPTY) { ! 423: if (hd->scsi_ints || --wait < 0) { ! 424: while (! (hd->scsi_ssts & SSTS_DREG_EMPTY)) { ! 425: *buf++ = hd->scsi_dreg; ! 426: --len; ! 427: } ! 428: #ifdef DEBUG ! 429: if (scsi_debug) ! 430: printf("ixfer_in fail: l%d i%x w%d\n", ! 431: len, hd->scsi_ints, wait); ! 432: #endif ! 433: HIST(ixin_wait, wait) ! 434: return; ! 435: } ! 436: DELAY(1); ! 437: } ! 438: *buf++ = hd->scsi_dreg; ! 439: } ! 440: HIST(ixin_wait, wait) ! 441: } ! 442: ! 443: static int ! 444: mxfer_in(hd, len, buf, phase) ! 445: volatile register struct scsidevice *hd; ! 446: register int len; ! 447: register u_char *buf; ! 448: register u_char phase; ! 449: { ! 450: register int wait = scsi_cmd_wait; ! 451: register int i; ! 452: ! 453: hd->scsi_tmod = 0; ! 454: for (i = 0; i < len; ++i) { ! 455: /* ! 456: * wait for the request line (which says the target ! 457: * wants to give us data). If the phase changes while ! 458: * we're waiting, we're done. ! 459: */ ! 460: while ((hd->scsi_psns & PSNS_REQ) == 0) { ! 461: if (--wait < 0) { ! 462: HIST(mxin_wait, wait) ! 463: return (-1); ! 464: } ! 465: if ((hd->scsi_psns & PHASE) != phase || ! 466: (hd->scsi_ssts & SSTS_INITIATOR) == 0) ! 467: goto out; ! 468: ! 469: DELAY(1); ! 470: } ! 471: /* ! 472: * set ack (which says we're ready for the data, wait for ! 473: * req to go away (target says data is available), grab the ! 474: * data, then reset ack (say we've got the data). ! 475: */ ! 476: hd->scsi_pctl = phase; ! 477: hd->scsi_scmd = SCMD_SET_ACK; ! 478: while (hd->scsi_psns & PSNS_REQ) { ! 479: if (--wait < 0) { ! 480: HIST(mxin_wait, wait) ! 481: return (-2); ! 482: } ! 483: DELAY(1); ! 484: } ! 485: *buf++ = hd->scsi_temp; ! 486: hd->scsi_scmd = SCMD_RST_ACK; ! 487: if (hd->scsi_psns & PSNS_ATN) ! 488: hd->scsi_scmd = SCMD_RST_ATN; ! 489: } ! 490: out: ! 491: HIST(mxin_wait, wait) ! 492: return (i); ! 493: } ! 494: ! 495: /* ! 496: * SCSI 'immediate' command: issue a command to some SCSI device ! 497: * and get back an 'immediate' response (i.e., do programmed xfer ! 498: * to get the response data). 'cbuf' is a buffer containing a scsi ! 499: * command of length clen bytes. 'buf' is a buffer of length 'len' ! 500: * bytes for data. The transfer direction is determined by the device ! 501: * (i.e., by the scsi bus data xfer phase). If 'len' is zero, the ! 502: * command must supply no data. 'xferphase' is the bus phase the ! 503: * caller expects to happen after the command is issued. It should ! 504: * be one of DATA_IN_PHASE, DATA_OUT_PHASE or STATUS_PHASE. ! 505: */ ! 506: static int ! 507: scsiicmd(hs, target, cbuf, clen, buf, len, xferphase) ! 508: struct scsi_softc *hs; ! 509: int target; ! 510: u_char *cbuf; ! 511: int clen; ! 512: u_char *buf; ! 513: int len; ! 514: u_char xferphase; ! 515: { ! 516: volatile register struct scsidevice *hd = ! 517: (struct scsidevice *)hs->sc_hc->hp_addr; ! 518: u_char phase, ints; ! 519: register int wait; ! 520: ! 521: /* select the SCSI bus (it's an error if bus isn't free) */ ! 522: if (issue_select(hd, target, hs->sc_scsi_addr)) ! 523: return (-1); ! 524: if (wait_for_select(hd)) ! 525: return (-1); ! 526: /* ! 527: * Wait for a phase change (or error) then let the device ! 528: * sequence us through the various SCSI phases. ! 529: */ ! 530: hs->sc_stat[0] = 0xff; ! 531: hs->sc_msg[0] = 0xff; ! 532: phase = CMD_PHASE; ! 533: while (1) { ! 534: wait = scsi_cmd_wait; ! 535: switch (phase) { ! 536: ! 537: case CMD_PHASE: ! 538: if (ixfer_start(hd, clen, phase, wait)) ! 539: if (ixfer_out(hd, clen, cbuf)) ! 540: goto abort; ! 541: phase = xferphase; ! 542: break; ! 543: ! 544: case DATA_IN_PHASE: ! 545: if (len <= 0) ! 546: goto abort; ! 547: wait = scsi_data_wait; ! 548: if (ixfer_start(hd, len, phase, wait) || ! 549: !(hd->scsi_ssts & SSTS_DREG_EMPTY)) ! 550: ixfer_in(hd, len, buf); ! 551: phase = STATUS_PHASE; ! 552: break; ! 553: ! 554: case DATA_OUT_PHASE: ! 555: if (len <= 0) ! 556: goto abort; ! 557: wait = scsi_data_wait; ! 558: if (ixfer_start(hd, len, phase, wait)) { ! 559: if (ixfer_out(hd, len, buf)) ! 560: goto abort; ! 561: } ! 562: phase = STATUS_PHASE; ! 563: break; ! 564: ! 565: case STATUS_PHASE: ! 566: wait = scsi_data_wait; ! 567: if (ixfer_start(hd, sizeof(hs->sc_stat), phase, wait) || ! 568: !(hd->scsi_ssts & SSTS_DREG_EMPTY)) ! 569: ixfer_in(hd, sizeof(hs->sc_stat), hs->sc_stat); ! 570: phase = MESG_IN_PHASE; ! 571: break; ! 572: ! 573: case MESG_IN_PHASE: ! 574: if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait) || ! 575: !(hd->scsi_ssts & SSTS_DREG_EMPTY)) { ! 576: ixfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg); ! 577: hd->scsi_scmd = SCMD_RST_ACK; ! 578: } ! 579: phase = BUS_FREE_PHASE; ! 580: break; ! 581: ! 582: case BUS_FREE_PHASE: ! 583: goto out; ! 584: ! 585: default: ! 586: printf("scsi%d: unexpected phase %d in icmd from %d\n", ! 587: hs->sc_hc->hp_unit, phase, target); ! 588: goto abort; ! 589: } ! 590: /* wait for last command to complete */ ! 591: while ((ints = hd->scsi_ints) == 0) { ! 592: if (--wait < 0) { ! 593: HIST(cxin_wait, wait) ! 594: goto abort; ! 595: } ! 596: DELAY(1); ! 597: } ! 598: HIST(cxin_wait, wait) ! 599: hd->scsi_ints = ints; ! 600: if (ints & INTS_SRV_REQ) ! 601: phase = hd->scsi_psns & PHASE; ! 602: else if (ints & INTS_DISCON) ! 603: goto out; ! 604: else if ((ints & INTS_CMD_DONE) == 0) { ! 605: scsierror(hs, hd, ints); ! 606: goto abort; ! 607: } ! 608: } ! 609: abort: ! 610: scsiabort(hs, hd, "icmd"); ! 611: out: ! 612: return (hs->sc_stat[0]); ! 613: } ! 614: ! 615: /* ! 616: * Finish SCSI xfer command: After the completion interrupt from ! 617: * a read/write operation, sequence through the final phases in ! 618: * programmed i/o. This routine is a lot like scsiicmd except we ! 619: * skip (and don't allow) the select, cmd out and data in/out phases. ! 620: */ ! 621: static void ! 622: finishxfer(hs, hd, target) ! 623: struct scsi_softc *hs; ! 624: volatile register struct scsidevice *hd; ! 625: int target; ! 626: { ! 627: u_char phase, ints; ! 628: ! 629: /* ! 630: * We specified padding xfer so we ended with either a phase ! 631: * change interrupt (normal case) or an error interrupt (handled ! 632: * elsewhere). Reset the board dma logic then try to get the ! 633: * completion status & command done msg. The reset confuses ! 634: * the SPC REQ/ACK logic so we have to do any status/msg input ! 635: * operations via 'manual xfer'. ! 636: */ ! 637: if (hd->scsi_ssts & SSTS_BUSY) { ! 638: int wait = scsi_cmd_wait; ! 639: ! 640: /* wait for dma operation to finish */ ! 641: while (hd->scsi_ssts & SSTS_BUSY) { ! 642: if (--wait < 0) { ! 643: #ifdef DEBUG ! 644: if (scsi_debug) ! 645: printf("finishxfer fail: ssts %x\n", ! 646: hd->scsi_ssts); ! 647: #endif ! 648: HIST(fxfr_wait, wait) ! 649: goto abort; ! 650: } ! 651: } ! 652: HIST(fxfr_wait, wait) ! 653: } ! 654: hd->scsi_scmd |= SCMD_PROG_XFR; ! 655: hd->scsi_sctl |= SCTL_CTRLRST; ! 656: DELAY(1); ! 657: hd->scsi_sctl &=~ SCTL_CTRLRST; ! 658: hd->scsi_hconf = 0; ! 659: hs->sc_stat[0] = 0xff; ! 660: hs->sc_msg[0] = 0xff; ! 661: hd->scsi_csr = 0; ! 662: hd->scsi_ints = ints = hd->scsi_ints; ! 663: while (1) { ! 664: phase = hd->scsi_psns & PHASE; ! 665: switch (phase) { ! 666: ! 667: case STATUS_PHASE: ! 668: if (mxfer_in(hd, sizeof(hs->sc_stat), hs->sc_stat, ! 669: phase) <= 0) ! 670: goto abort; ! 671: break; ! 672: ! 673: case MESG_IN_PHASE: ! 674: if (mxfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg, ! 675: phase) < 0) ! 676: goto abort; ! 677: break; ! 678: ! 679: case BUS_FREE_PHASE: ! 680: return; ! 681: ! 682: default: ! 683: printf("scsi%d: unexpected phase %d in finishxfer from %d\n", ! 684: hs->sc_hc->hp_unit, phase, target); ! 685: goto abort; ! 686: } ! 687: if (ints = hd->scsi_ints) { ! 688: hd->scsi_ints = ints; ! 689: if (ints & INTS_DISCON) ! 690: return; ! 691: else if (ints & ~(INTS_SRV_REQ|INTS_CMD_DONE)) { ! 692: scsierror(hs, hd, ints); ! 693: break; ! 694: } ! 695: } ! 696: if ((hd->scsi_ssts & SSTS_INITIATOR) == 0) ! 697: return; ! 698: } ! 699: abort: ! 700: scsiabort(hs, hd, "finishxfer"); ! 701: hs->sc_stat[0] = 0xfe; ! 702: } ! 703: ! 704: int ! 705: scsi_test_unit_rdy(ctlr, slave, unit) ! 706: int ctlr, slave, unit; ! 707: { ! 708: register struct scsi_softc *hs = &scsi_softc[ctlr]; ! 709: static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY }; ! 710: ! 711: cdb.lun = unit; ! 712: return (scsiicmd(hs, slave, &cdb, sizeof(cdb), (u_char *)0, 0, ! 713: STATUS_PHASE)); ! 714: } ! 715: ! 716: int ! 717: scsi_request_sense(ctlr, slave, unit, buf, len) ! 718: int ctlr, slave, unit; ! 719: u_char *buf; ! 720: unsigned len; ! 721: { ! 722: register struct scsi_softc *hs = &scsi_softc[ctlr]; ! 723: static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE }; ! 724: ! 725: cdb.lun = unit; ! 726: cdb.len = len; ! 727: return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE)); ! 728: } ! 729: ! 730: int ! 731: scsi_immed_command(ctlr, slave, unit, cdb, buf, len, rd) ! 732: int ctlr, slave, unit; ! 733: struct scsi_fmt_cdb *cdb; ! 734: u_char *buf; ! 735: unsigned len; ! 736: { ! 737: register struct scsi_softc *hs = &scsi_softc[ctlr]; ! 738: ! 739: cdb->cdb[1] |= unit << 5; ! 740: return (scsiicmd(hs, slave, cdb->cdb, cdb->len, buf, len, ! 741: rd != 0? DATA_IN_PHASE : DATA_OUT_PHASE)); ! 742: } ! 743: ! 744: /* ! 745: * The following routines are test-and-transfer i/o versions of read/write ! 746: * for things like reading disk labels and writing core dumps. The ! 747: * routine scsigo should be used for normal data transfers, NOT these ! 748: * routines. ! 749: */ ! 750: int ! 751: scsi_tt_read(ctlr, slave, unit, buf, len, blk, bshift) ! 752: int ctlr, slave, unit; ! 753: u_char *buf; ! 754: u_int len; ! 755: daddr_t blk; ! 756: int bshift; ! 757: { ! 758: register struct scsi_softc *hs = &scsi_softc[ctlr]; ! 759: struct scsi_cdb10 cdb; ! 760: int stat; ! 761: int old_wait = scsi_data_wait; ! 762: ! 763: scsi_data_wait = 300000; ! 764: bzero(&cdb, sizeof(cdb)); ! 765: cdb.cmd = CMD_READ_EXT; ! 766: cdb.lun = unit; ! 767: blk >>= bshift; ! 768: cdb.lbah = blk >> 24; ! 769: cdb.lbahm = blk >> 16; ! 770: cdb.lbalm = blk >> 8; ! 771: cdb.lbal = blk; ! 772: cdb.lenh = len >> (8 + DEV_BSHIFT + bshift); ! 773: cdb.lenl = len >> (DEV_BSHIFT + bshift); ! 774: stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE); ! 775: scsi_data_wait = old_wait; ! 776: return (stat); ! 777: } ! 778: ! 779: int ! 780: scsi_tt_write(ctlr, slave, unit, buf, len, blk, bshift) ! 781: int ctlr, slave, unit; ! 782: u_char *buf; ! 783: u_int len; ! 784: daddr_t blk; ! 785: int bshift; ! 786: { ! 787: register struct scsi_softc *hs = &scsi_softc[ctlr]; ! 788: struct scsi_cdb10 cdb; ! 789: int stat; ! 790: int old_wait = scsi_data_wait; ! 791: ! 792: scsi_data_wait = 300000; ! 793: ! 794: bzero(&cdb, sizeof(cdb)); ! 795: cdb.cmd = CMD_WRITE_EXT; ! 796: cdb.lun = unit; ! 797: blk >>= bshift; ! 798: cdb.lbah = blk >> 24; ! 799: cdb.lbahm = blk >> 16; ! 800: cdb.lbalm = blk >> 8; ! 801: cdb.lbal = blk; ! 802: cdb.lenh = len >> (8 + DEV_BSHIFT + bshift); ! 803: cdb.lenl = len >> (DEV_BSHIFT + bshift); ! 804: stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_OUT_PHASE); ! 805: scsi_data_wait = old_wait; ! 806: return (stat); ! 807: } ! 808: ! 809: ! 810: int ! 811: scsireq(dq) ! 812: register struct devqueue *dq; ! 813: { ! 814: register struct devqueue *hq; ! 815: ! 816: hq = &scsi_softc[dq->dq_ctlr].sc_sq; ! 817: insque(dq, hq->dq_back); ! 818: if (dq->dq_back == hq) ! 819: return(1); ! 820: return(0); ! 821: } ! 822: ! 823: int ! 824: scsiustart(unit) ! 825: int unit; ! 826: { ! 827: register struct scsi_softc *hs = &scsi_softc[unit]; ! 828: ! 829: hs->sc_dq.dq_ctlr = DMA0 | DMA1; ! 830: if (dmareq(&hs->sc_dq)) ! 831: return(1); ! 832: return(0); ! 833: } ! 834: ! 835: void ! 836: scsistart(unit) ! 837: int unit; ! 838: { ! 839: register struct devqueue *dq; ! 840: ! 841: dq = scsi_softc[unit].sc_sq.dq_forw; ! 842: (dq->dq_driver->d_go)(dq->dq_unit); ! 843: } ! 844: ! 845: int ! 846: scsigo(ctlr, slave, unit, bp, cdb, pad) ! 847: int ctlr, slave, unit; ! 848: struct buf *bp; ! 849: struct scsi_fmt_cdb *cdb; ! 850: int pad; ! 851: { ! 852: register struct scsi_softc *hs = &scsi_softc[ctlr]; ! 853: volatile register struct scsidevice *hd = ! 854: (struct scsidevice *)hs->sc_hc->hp_addr; ! 855: int i, dmaflags; ! 856: u_char phase, ints, cmd; ! 857: ! 858: cdb->cdb[1] |= unit << 5; ! 859: ! 860: /* select the SCSI bus (it's an error if bus isn't free) */ ! 861: if (issue_select(hd, slave, hs->sc_scsi_addr) || wait_for_select(hd)) { ! 862: dmafree(&hs->sc_dq); ! 863: return (1); ! 864: } ! 865: /* ! 866: * Wait for a phase change (or error) then let the device ! 867: * sequence us through command phase (we may have to take ! 868: * a msg in/out before doing the command). If the disk has ! 869: * to do a seek, it may be a long time until we get a change ! 870: * to data phase so, in the absense of an explicit phase ! 871: * change, we assume data phase will be coming up and tell ! 872: * the SPC to start a transfer whenever it does. We'll get ! 873: * a service required interrupt later if this assumption is ! 874: * wrong. Otherwise we'll get a service required int when ! 875: * the transfer changes to status phase. ! 876: */ ! 877: phase = CMD_PHASE; ! 878: while (1) { ! 879: register int wait = scsi_cmd_wait; ! 880: ! 881: switch (phase) { ! 882: ! 883: case CMD_PHASE: ! 884: if (ixfer_start(hd, cdb->len, phase, wait)) ! 885: if (ixfer_out(hd, cdb->len, cdb->cdb)) ! 886: goto abort; ! 887: break; ! 888: ! 889: case MESG_IN_PHASE: ! 890: if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait)|| ! 891: !(hd->scsi_ssts & SSTS_DREG_EMPTY)) { ! 892: ixfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg); ! 893: hd->scsi_scmd = SCMD_RST_ACK; ! 894: } ! 895: phase = BUS_FREE_PHASE; ! 896: break; ! 897: ! 898: case DATA_IN_PHASE: ! 899: case DATA_OUT_PHASE: ! 900: goto out; ! 901: ! 902: default: ! 903: printf("scsi%d: unexpected phase %d in go from %d\n", ! 904: hs->sc_hc->hp_unit, phase, slave); ! 905: goto abort; ! 906: } ! 907: while ((ints = hd->scsi_ints) == 0) { ! 908: if (--wait < 0) { ! 909: HIST(sgo_wait, wait) ! 910: goto abort; ! 911: } ! 912: DELAY(1); ! 913: } ! 914: HIST(sgo_wait, wait) ! 915: hd->scsi_ints = ints; ! 916: if (ints & INTS_SRV_REQ) ! 917: phase = hd->scsi_psns & PHASE; ! 918: else if (ints & INTS_CMD_DONE) ! 919: goto out; ! 920: else { ! 921: scsierror(hs, hd, ints); ! 922: goto abort; ! 923: } ! 924: } ! 925: out: ! 926: /* ! 927: * Reset the card dma logic, setup the dma channel then ! 928: * get the dio part of the card set for a dma xfer. ! 929: */ ! 930: hd->scsi_hconf = 0; ! 931: cmd = CSR_IE | (CSR_DE0 << hs->sc_dq.dq_ctlr); ! 932: dmaflags = DMAGO_NOINT; ! 933: if (bp->b_flags & B_READ) ! 934: dmaflags |= DMAGO_READ; ! 935: if ((hs->sc_flags & SCSI_DMA32) && ! 936: ((int)bp->b_un.b_addr & 3) == 0 && (bp->b_bcount & 3) == 0) { ! 937: cmd |= CSR_DMA32; ! 938: dmaflags |= DMAGO_LWORD; ! 939: } else ! 940: dmaflags |= DMAGO_WORD; ! 941: dmago(hs->sc_dq.dq_ctlr, bp->b_un.b_addr, bp->b_bcount, dmaflags); ! 942: ! 943: if (bp->b_flags & B_READ) { ! 944: cmd |= CSR_DMAIN; ! 945: phase = DATA_IN_PHASE; ! 946: } else ! 947: phase = DATA_OUT_PHASE; ! 948: hd->scsi_csr = cmd; ! 949: /* ! 950: * Setup the SPC for the transfer. We don't want to take ! 951: * first a command complete then a service required interrupt ! 952: * at the end of the transfer so we try to disable the cmd ! 953: * complete by setting the transfer counter to more bytes ! 954: * than we expect. (XXX - This strategy may have to be ! 955: * modified to deal with devices that return variable length ! 956: * blocks, e.g., some tape drives.) ! 957: */ ! 958: cmd = SCMD_XFR; ! 959: i = (unsigned)bp->b_bcount; ! 960: if (pad) { ! 961: cmd |= SCMD_PAD; ! 962: /* ! 963: * XXX - If we don't do this, the last 2 or 4 bytes ! 964: * (depending on word/lword DMA) of a read get trashed. ! 965: * It looks like it is necessary for the DMA to complete ! 966: * before the SPC goes into "pad mode"??? Note: if we ! 967: * also do this on a write, the request never completes. ! 968: */ ! 969: if (bp->b_flags & B_READ) ! 970: i += 2; ! 971: #ifdef DEBUG ! 972: hs->sc_flags |= SCSI_PAD; ! 973: if (i & 1) ! 974: printf("scsi%d: odd byte count: %d bytes @ %d\n", ! 975: ctlr, i, bp->b_cylin); ! 976: #endif ! 977: } else ! 978: i += 4; ! 979: hd->scsi_tch = i >> 16; ! 980: hd->scsi_tcm = i >> 8; ! 981: hd->scsi_tcl = i; ! 982: hd->scsi_pctl = phase; ! 983: hd->scsi_tmod = 0; ! 984: hd->scsi_scmd = cmd; ! 985: hs->sc_flags |= SCSI_IO; ! 986: return (0); ! 987: abort: ! 988: scsiabort(hs, hd, "go"); ! 989: dmafree(&hs->sc_dq); ! 990: return (1); ! 991: } ! 992: ! 993: void ! 994: scsidone(unit) ! 995: register int unit; ! 996: { ! 997: volatile register struct scsidevice *hd = ! 998: (struct scsidevice *)scsi_softc[unit].sc_hc->hp_addr; ! 999: ! 1000: /* dma operation is done -- turn off card dma */ ! 1001: hd->scsi_csr &=~ (CSR_DE1|CSR_DE0); ! 1002: } ! 1003: ! 1004: int ! 1005: scsiintr(unit) ! 1006: register int unit; ! 1007: { ! 1008: register struct scsi_softc *hs = &scsi_softc[unit]; ! 1009: volatile register struct scsidevice *hd = ! 1010: (struct scsidevice *)hs->sc_hc->hp_addr; ! 1011: register u_char ints; ! 1012: register struct devqueue *dq; ! 1013: ! 1014: if ((hd->scsi_csr & (CSR_IE|CSR_IR)) != (CSR_IE|CSR_IR)) ! 1015: return (0); ! 1016: ! 1017: ints = hd->scsi_ints; ! 1018: if ((ints & INTS_SRV_REQ) && (hs->sc_flags & SCSI_IO)) { ! 1019: /* ! 1020: * this should be the normal i/o completion case. ! 1021: * get the status & cmd complete msg then let the ! 1022: * device driver look at what happened. ! 1023: */ ! 1024: #ifdef DEBUG ! 1025: int len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | ! 1026: hd->scsi_tcl; ! 1027: if (!(hs->sc_flags & SCSI_PAD)) ! 1028: len -= 4; ! 1029: if (len) ! 1030: printf("scsi%d: transfer length error %d\n", unit, len); ! 1031: hs->sc_flags &=~ SCSI_PAD; ! 1032: #endif ! 1033: dq = hs->sc_sq.dq_forw; ! 1034: finishxfer(hs, hd, dq->dq_unit); ! 1035: hs->sc_flags &=~ SCSI_IO; ! 1036: dmafree(&hs->sc_dq); ! 1037: (dq->dq_driver->d_intr)(dq->dq_unit, hs->sc_stat[0]); ! 1038: } else { ! 1039: /* Something unexpected happened -- deal with it. */ ! 1040: hd->scsi_ints = ints; ! 1041: hd->scsi_csr = 0; ! 1042: scsierror(hs, hd, ints); ! 1043: scsiabort(hs, hd, "intr"); ! 1044: if (hs->sc_flags & SCSI_IO) { ! 1045: hs->sc_flags &=~ SCSI_IO; ! 1046: dmafree(&hs->sc_dq); ! 1047: dq = hs->sc_sq.dq_forw; ! 1048: (dq->dq_driver->d_intr)(dq->dq_unit, -1); ! 1049: } ! 1050: } ! 1051: return(1); ! 1052: } ! 1053: ! 1054: void ! 1055: scsifree(dq) ! 1056: register struct devqueue *dq; ! 1057: { ! 1058: register struct devqueue *hq; ! 1059: ! 1060: hq = &scsi_softc[dq->dq_ctlr].sc_sq; ! 1061: remque(dq); ! 1062: if ((dq = hq->dq_forw) != hq) ! 1063: (dq->dq_driver->d_start)(dq->dq_unit); ! 1064: } ! 1065: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.