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