|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1988 University of Utah. ! 3: * Copyright (c) 1990 The Regents of the University of California. ! 4: * All rights reserved. ! 5: * ! 6: * This code is derived from software contributed to Berkeley by ! 7: * Van Jacobson of Lawrence Berkeley Laboratory and the Systems ! 8: * Programming Group of the University of Utah Computer Science Department. ! 9: * ! 10: * Redistribution is only permitted until one year after the first shipment ! 11: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 12: * binary forms are permitted provided that: (1) source distributions retain ! 13: * this entire copyright notice and comment, and (2) distributions including ! 14: * binaries display the following acknowledgement: This product includes ! 15: * software developed by the University of California, Berkeley and its ! 16: * contributors'' in the documentation or other materials provided with the ! 17: * distribution and in all advertising materials mentioning features or use ! 18: * of this software. Neither the name of the University nor the names of ! 19: * its contributors may be used to endorse or promote products derived from ! 20: * this software without specific prior written permission. ! 21: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 22: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 23: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 24: * ! 25: * from: Utah $Hdr: scsi.c 1.3 90/01/27$ ! 26: * ! 27: * @(#)scsi.c 7.1 (Berkeley) 5/8/90 ! 28: */ ! 29: ! 30: /* ! 31: * SCSI bus driver for standalone programs. ! 32: */ ! 33: ! 34: #include "../sys/types.h" ! 35: #include "../sys/reboot.h" ! 36: #include "../hpdev/device.h" ! 37: #include "../hpdev/scsireg.h" ! 38: #include "scsivar.h" ! 39: ! 40: #include "saio.h" ! 41: #include "samachdep.h" ! 42: ! 43: struct scsi_softc scsi_softc[NSCSI]; ! 44: ! 45: #define scsiunit(x) ((x) >> 3) ! 46: #define scsislave(x) ((x) & 7) ! 47: ! 48: void scsireset(); ! 49: int scsi_cmd_wait = 500; ! 50: int scsi_data_wait = 300000; ! 51: ! 52: scsiinit() ! 53: { ! 54: extern struct hp_hw sc_table[]; ! 55: register struct hp_hw *hw; ! 56: register struct scsi_softc *hs; ! 57: register int i, addr; ! 58: static int first = 1; ! 59: ! 60: i = 0; ! 61: for (hw = sc_table; i < NSCSI && hw < &sc_table[MAX_CTLR]; hw++) { ! 62: if (hw->hw_type != SCSI) ! 63: continue; ! 64: hs = &scsi_softc[i]; ! 65: hs->sc_addr = hw->hw_addr; ! 66: scsireset(i); ! 67: if (howto & RB_ASKNAME) ! 68: printf("scsi%d at sc%d\n", i, hw->hw_sc); ! 69: /* ! 70: * Adjust devtype on first call. This routine assumes that ! 71: * adaptor is in the high byte of devtype. ! 72: */ ! 73: if (first && ((devtype >> 24) & 0xff) == hw->hw_sc) { ! 74: devtype = (devtype & 0x00ffffff) | (i << 24); ! 75: first = 0; ! 76: } ! 77: hs->sc_alive = 1; ! 78: i++; ! 79: } ! 80: } ! 81: ! 82: scsialive(unit) ! 83: register int unit; ! 84: { ! 85: unit = scsiunit(unit); ! 86: if (unit >= NSCSI || scsi_softc[unit].sc_alive == 0) ! 87: return (0); ! 88: return (1); ! 89: } ! 90: ! 91: void ! 92: scsireset(unit) ! 93: register int unit; ! 94: { ! 95: volatile register struct scsidevice *hd; ! 96: register struct scsi_softc *hs; ! 97: u_int i; ! 98: ! 99: unit = scsiunit(unit); ! 100: hs = &scsi_softc[unit]; ! 101: hd = (struct scsidevice *)hs->sc_addr; ! 102: hd->scsi_id = 0xFF; ! 103: DELAY(100); ! 104: /* ! 105: * Disable interrupts then reset the FUJI chip. ! 106: */ ! 107: hd->scsi_csr = 0; ! 108: hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST; ! 109: hd->scsi_scmd = 0; ! 110: hd->scsi_tmod = 0; ! 111: hd->scsi_pctl = 0; ! 112: hd->scsi_temp = 0; ! 113: hd->scsi_tch = 0; ! 114: hd->scsi_tcm = 0; ! 115: hd->scsi_tcl = 0; ! 116: hd->scsi_ints = 0; ! 117: ! 118: /* ! 119: * Configure the FUJI chip with its SCSI address, all ! 120: * interrupts enabled & appropriate parity. ! 121: */ ! 122: i = (~hd->scsi_hconf) & 0x7; ! 123: hs->sc_scsi_addr = 1 << i; ! 124: hd->scsi_bdid = i; ! 125: if (hd->scsi_hconf & HCONF_PARITY) ! 126: hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB | ! 127: SCTL_SEL_ENAB | SCTL_RESEL_ENAB | ! 128: SCTL_INTR_ENAB | SCTL_PARITY_ENAB; ! 129: else ! 130: hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB | ! 131: SCTL_SEL_ENAB | SCTL_RESEL_ENAB | ! 132: SCTL_INTR_ENAB; ! 133: hd->scsi_sctl &=~ SCTL_DISABLE; ! 134: } ! 135: ! 136: ! 137: int ! 138: scsiabort(hs, hd) ! 139: register struct scsi_softc *hs; ! 140: volatile register struct scsidevice *hd; ! 141: { ! 142: printf("scsi error: scsiabort\n"); ! 143: return (0); ! 144: } ! 145: ! 146: static int ! 147: issue_select(hd, target, our_addr) ! 148: volatile register struct scsidevice *hd; ! 149: u_char target, our_addr; ! 150: { ! 151: if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY)) ! 152: return (1); ! 153: ! 154: if (hd->scsi_ints & INTS_DISCON) ! 155: hd->scsi_ints = INTS_DISCON; ! 156: ! 157: hd->scsi_pctl = 0; ! 158: hd->scsi_temp = (1 << target) | our_addr; ! 159: /* select timeout is hardcoded to 2ms */ ! 160: hd->scsi_tch = 0; ! 161: hd->scsi_tcm = 32; ! 162: hd->scsi_tcl = 4; ! 163: ! 164: hd->scsi_scmd = SCMD_SELECT; ! 165: return (0); ! 166: } ! 167: ! 168: static int ! 169: wait_for_select(hd) ! 170: volatile register struct scsidevice *hd; ! 171: { ! 172: u_char ints; ! 173: ! 174: while ((ints = hd->scsi_ints) == 0) ! 175: DELAY(1); ! 176: hd->scsi_ints = ints; ! 177: return (!(hd->scsi_ssts & SSTS_INITIATOR)); ! 178: } ! 179: ! 180: static int ! 181: ixfer_start(hd, len, phase, wait) ! 182: volatile register struct scsidevice *hd; ! 183: int len; ! 184: u_char phase; ! 185: register int wait; ! 186: { ! 187: ! 188: hd->scsi_tch = len >> 16; ! 189: hd->scsi_tcm = len >> 8; ! 190: hd->scsi_tcl = len; ! 191: hd->scsi_pctl = phase; ! 192: hd->scsi_tmod = 0; /*XXX*/ ! 193: hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR; ! 194: ! 195: /* wait for xfer to start or svc_req interrupt */ ! 196: while ((hd->scsi_ssts & SSTS_BUSY) == 0) { ! 197: if (hd->scsi_ints || --wait < 0) ! 198: return (0); ! 199: DELAY(1); ! 200: } ! 201: return (1); ! 202: } ! 203: ! 204: static int ! 205: ixfer_out(hd, len, buf) ! 206: volatile register struct scsidevice *hd; ! 207: int len; ! 208: register u_char *buf; ! 209: { ! 210: register int wait = scsi_data_wait; ! 211: ! 212: for (; len > 0; --len) { ! 213: while (hd->scsi_ssts & SSTS_DREG_FULL) { ! 214: if (hd->scsi_ints || --wait < 0) ! 215: return (len); ! 216: DELAY(1); ! 217: } ! 218: hd->scsi_dreg = *buf++; ! 219: } ! 220: return (0); ! 221: } ! 222: ! 223: static int ! 224: ixfer_in(hd, len, buf) ! 225: volatile register struct scsidevice *hd; ! 226: int len; ! 227: register u_char *buf; ! 228: { ! 229: register int wait = scsi_data_wait; ! 230: ! 231: for (; len > 0; --len) { ! 232: while (hd->scsi_ssts & SSTS_DREG_EMPTY) { ! 233: if (hd->scsi_ints || --wait < 0) { ! 234: while (! (hd->scsi_ssts & SSTS_DREG_EMPTY)) { ! 235: *buf++ = hd->scsi_dreg; ! 236: --len; ! 237: } ! 238: return (len); ! 239: } ! 240: DELAY(1); ! 241: } ! 242: *buf++ = hd->scsi_dreg; ! 243: } ! 244: return (len); ! 245: } ! 246: ! 247: static int ! 248: scsiicmd(hs, target, cbuf, clen, buf, len, xferphase) ! 249: struct scsi_softc *hs; ! 250: int target; ! 251: u_char *cbuf; ! 252: int clen; ! 253: u_char *buf; ! 254: int len; ! 255: u_char xferphase; ! 256: { ! 257: volatile register struct scsidevice *hd = ! 258: (struct scsidevice *)hs->sc_addr; ! 259: int i; ! 260: u_char phase, ints; ! 261: register int wait; ! 262: ! 263: /* select the SCSI bus (it's an error if bus isn't free) */ ! 264: if (issue_select(hd, target, hs->sc_scsi_addr)) ! 265: return (0); ! 266: if (wait_for_select(hd)) ! 267: return (0); ! 268: /* ! 269: * Wait for a phase change (or error) then let the device ! 270: * sequence us through the various SCSI phases. ! 271: */ ! 272: phase = CMD_PHASE; ! 273: while (1) { ! 274: wait = scsi_cmd_wait; ! 275: switch (phase) { ! 276: ! 277: case CMD_PHASE: ! 278: if (ixfer_start(hd, clen, phase, wait)) ! 279: if (ixfer_out(hd, clen, cbuf)) ! 280: goto abort; ! 281: phase = xferphase; ! 282: break; ! 283: ! 284: case DATA_IN_PHASE: ! 285: if (len <= 0) ! 286: goto abort; ! 287: wait = scsi_data_wait; ! 288: if (ixfer_start(hd, len, phase, wait) || ! 289: !(hd->scsi_ssts & SSTS_DREG_EMPTY)) ! 290: ixfer_in(hd, len, buf); ! 291: phase = STATUS_PHASE; ! 292: break; ! 293: ! 294: case DATA_OUT_PHASE: ! 295: if (len <= 0) ! 296: goto abort; ! 297: wait = scsi_data_wait; ! 298: if (ixfer_start(hd, len, phase, wait)) ! 299: if (ixfer_out(hd, len, buf)) ! 300: goto abort; ! 301: phase = STATUS_PHASE; ! 302: break; ! 303: ! 304: case STATUS_PHASE: ! 305: wait = scsi_data_wait; ! 306: if (ixfer_start(hd, sizeof(hs->sc_stat), phase, wait) || ! 307: !(hd->scsi_ssts & SSTS_DREG_EMPTY)) ! 308: ixfer_in(hd, sizeof(hs->sc_stat), &hs->sc_stat); ! 309: phase = MESG_IN_PHASE; ! 310: break; ! 311: ! 312: case MESG_IN_PHASE: ! 313: if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait) || ! 314: !(hd->scsi_ssts & SSTS_DREG_EMPTY)) { ! 315: ixfer_in(hd, sizeof(hs->sc_msg), &hs->sc_msg); ! 316: hd->scsi_scmd = SCMD_RST_ACK; ! 317: } ! 318: phase = BUS_FREE_PHASE; ! 319: break; ! 320: ! 321: case BUS_FREE_PHASE: ! 322: return (1); ! 323: ! 324: default: ! 325: printf("unexpected scsi phase %d\n", phase); ! 326: goto abort; ! 327: } ! 328: /* wait for last command to complete */ ! 329: while ((ints = hd->scsi_ints) == 0) { ! 330: if (--wait < 0) ! 331: goto abort; ! 332: DELAY(1); ! 333: } ! 334: hd->scsi_ints = ints; ! 335: if (ints & INTS_SRV_REQ) ! 336: phase = hd->scsi_psns & PHASE; ! 337: else if (ints & INTS_DISCON) ! 338: return (1); ! 339: else if ((ints & INTS_CMD_DONE) == 0) { ! 340: goto abort; ! 341: } ! 342: } ! 343: abort: ! 344: scsiabort(hs, hd); ! 345: return (0); ! 346: } ! 347: ! 348: int ! 349: scsi_test_unit_rdy(unit) ! 350: { ! 351: int ctlr = scsiunit(unit); ! 352: int slave = scsislave(unit); ! 353: register struct scsi_softc *hs = &scsi_softc[ctlr]; ! 354: static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY }; ! 355: ! 356: if (scsiicmd(hs, slave, &cdb, sizeof(cdb), (u_char *)0, 0, ! 357: STATUS_PHASE) == 0) ! 358: return (0); ! 359: ! 360: return (hs->sc_stat == 0); ! 361: } ! 362: ! 363: int ! 364: scsi_request_sense(unit, buf, len) ! 365: int unit; ! 366: u_char *buf; ! 367: unsigned len; ! 368: { ! 369: int ctlr = scsiunit(unit); ! 370: int slave = scsislave(unit); ! 371: register struct scsi_softc *hs = &scsi_softc[ctlr]; ! 372: static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE }; ! 373: ! 374: cdb.len = len; ! 375: return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE)); ! 376: } ! 377: ! 378: int ! 379: scsi_read_capacity(unit, buf, len) ! 380: int unit; ! 381: u_char *buf; ! 382: unsigned len; ! 383: { ! 384: int ctlr = scsiunit(unit); ! 385: int slave = scsislave(unit); ! 386: register struct scsi_softc *hs = &scsi_softc[ctlr]; ! 387: static struct scsi_cdb10 cdb = { CMD_READ_CAPACITY }; ! 388: ! 389: return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE)); ! 390: } ! 391: ! 392: int ! 393: scsi_tt_read(unit, buf, len, blk, nblk) ! 394: int unit; ! 395: u_char *buf; ! 396: u_int len; ! 397: daddr_t blk; ! 398: u_int nblk; ! 399: { ! 400: int ctlr = scsiunit(unit); ! 401: int slave = scsislave(unit); ! 402: register struct scsi_softc *hs = &scsi_softc[ctlr]; ! 403: struct scsi_cdb10 cdb; ! 404: int stat; ! 405: ! 406: bzero(&cdb, sizeof(cdb)); ! 407: cdb.cmd = CMD_READ_EXT; ! 408: cdb.lbah = blk >> 24; ! 409: cdb.lbahm = blk >> 16; ! 410: cdb.lbalm = blk >> 8; ! 411: cdb.lbal = blk; ! 412: cdb.lenh = nblk >> (8 + DEV_BSHIFT); ! 413: cdb.lenl = nblk >> DEV_BSHIFT; ! 414: stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE); ! 415: if (stat == 0) ! 416: return (1); ! 417: return (hs->sc_stat); ! 418: } ! 419: ! 420: int ! 421: scsi_tt_write(unit, buf, len, blk, nblk) ! 422: int unit; ! 423: u_char *buf; ! 424: u_int len; ! 425: daddr_t blk; ! 426: u_int nblk; ! 427: { ! 428: int ctlr = scsiunit(unit); ! 429: int slave = scsislave(unit); ! 430: register struct scsi_softc *hs = &scsi_softc[ctlr]; ! 431: struct scsi_cdb10 cdb; ! 432: int stat; ! 433: ! 434: bzero(&cdb, sizeof(cdb)); ! 435: cdb.cmd = CMD_WRITE_EXT; ! 436: cdb.lbah = blk >> 24; ! 437: cdb.lbahm = blk >> 16; ! 438: cdb.lbalm = blk >> 8; ! 439: cdb.lbal = blk; ! 440: cdb.lenh = nblk >> (8 + DEV_BSHIFT); ! 441: cdb.lenl = nblk >> DEV_BSHIFT; ! 442: stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_OUT_PHASE); ! 443: if (stat == 0) ! 444: return (1); ! 445: return (hs->sc_stat); ! 446: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.