141488Smckusick /* 241488Smckusick * Copyright (c) 1988 University of Utah. 341488Smckusick * Copyright (c) 1990 The Regents of the University of California. 441488Smckusick * All rights reserved. 541488Smckusick * 641488Smckusick * This code is derived from software contributed to Berkeley by 741488Smckusick * Van Jacobson of Lawrence Berkeley Laboratory and the Systems 841488Smckusick * Programming Group of the University of Utah Computer Science Department. 941488Smckusick * 1041488Smckusick * %sccs.include.redist.c% 1141488Smckusick * 1241488Smckusick * from: Utah $Hdr: scsi.c 1.3 90/01/27$ 1341488Smckusick * 14*49334Shibler * @(#)scsi.c 7.4 (Berkeley) 05/07/91 1541488Smckusick */ 1641488Smckusick 1741488Smckusick /* 1841488Smckusick * SCSI bus driver for standalone programs. 1941488Smckusick */ 2041488Smckusick 2149153Sbostic #include <sys/param.h> 2249153Sbostic #include <sys/reboot.h> 2345790Sbostic #include "../dev/device.h" 2445790Sbostic #include "../dev/scsireg.h" 2541488Smckusick #include "scsivar.h" 2641488Smckusick 2741488Smckusick #include "saio.h" 2841488Smckusick #include "samachdep.h" 2941488Smckusick 3041488Smckusick struct scsi_softc scsi_softc[NSCSI]; 3141488Smckusick 3241488Smckusick #define scsiunit(x) ((x) >> 3) 3341488Smckusick #define scsislave(x) ((x) & 7) 3441488Smckusick 3541488Smckusick void scsireset(); 3641488Smckusick int scsi_cmd_wait = 500; 3741488Smckusick int scsi_data_wait = 300000; 3841488Smckusick 3941488Smckusick scsiinit() 4041488Smckusick { 4141488Smckusick extern struct hp_hw sc_table[]; 4241488Smckusick register struct hp_hw *hw; 4341488Smckusick register struct scsi_softc *hs; 4441488Smckusick register int i, addr; 4541488Smckusick static int first = 1; 4641488Smckusick 4741488Smckusick i = 0; 48*49334Shibler for (hw = sc_table; i < NSCSI && hw < &sc_table[MAXCTLRS]; hw++) { 49*49334Shibler if (!HW_ISSCSI(hw)) 5041488Smckusick continue; 5141488Smckusick hs = &scsi_softc[i]; 52*49334Shibler hs->sc_addr = hw->hw_kva; 5341488Smckusick scsireset(i); 5441488Smckusick if (howto & RB_ASKNAME) 5541488Smckusick printf("scsi%d at sc%d\n", i, hw->hw_sc); 5641488Smckusick /* 5741488Smckusick * Adjust devtype on first call. This routine assumes that 5841488Smckusick * adaptor is in the high byte of devtype. 5941488Smckusick */ 6041488Smckusick if (first && ((devtype >> 24) & 0xff) == hw->hw_sc) { 6141488Smckusick devtype = (devtype & 0x00ffffff) | (i << 24); 6241488Smckusick first = 0; 6341488Smckusick } 6441488Smckusick hs->sc_alive = 1; 6541488Smckusick i++; 6641488Smckusick } 6741488Smckusick } 6841488Smckusick 6941488Smckusick scsialive(unit) 7041488Smckusick register int unit; 7141488Smckusick { 7241488Smckusick unit = scsiunit(unit); 7341488Smckusick if (unit >= NSCSI || scsi_softc[unit].sc_alive == 0) 7441488Smckusick return (0); 7541488Smckusick return (1); 7641488Smckusick } 7741488Smckusick 7841488Smckusick void 7941488Smckusick scsireset(unit) 8041488Smckusick register int unit; 8141488Smckusick { 8241488Smckusick volatile register struct scsidevice *hd; 8341488Smckusick register struct scsi_softc *hs; 8441488Smckusick u_int i; 8541488Smckusick 8641488Smckusick unit = scsiunit(unit); 8741488Smckusick hs = &scsi_softc[unit]; 8841488Smckusick hd = (struct scsidevice *)hs->sc_addr; 8941488Smckusick hd->scsi_id = 0xFF; 9041488Smckusick DELAY(100); 9141488Smckusick /* 9241488Smckusick * Disable interrupts then reset the FUJI chip. 9341488Smckusick */ 9441488Smckusick hd->scsi_csr = 0; 9541488Smckusick hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST; 9641488Smckusick hd->scsi_scmd = 0; 9741488Smckusick hd->scsi_tmod = 0; 9841488Smckusick hd->scsi_pctl = 0; 9941488Smckusick hd->scsi_temp = 0; 10041488Smckusick hd->scsi_tch = 0; 10141488Smckusick hd->scsi_tcm = 0; 10241488Smckusick hd->scsi_tcl = 0; 10341488Smckusick hd->scsi_ints = 0; 10441488Smckusick 10541488Smckusick /* 10641488Smckusick * Configure the FUJI chip with its SCSI address, all 10741488Smckusick * interrupts enabled & appropriate parity. 10841488Smckusick */ 10941488Smckusick i = (~hd->scsi_hconf) & 0x7; 11041488Smckusick hs->sc_scsi_addr = 1 << i; 11141488Smckusick hd->scsi_bdid = i; 11241488Smckusick if (hd->scsi_hconf & HCONF_PARITY) 11341488Smckusick hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB | 11441488Smckusick SCTL_SEL_ENAB | SCTL_RESEL_ENAB | 11541488Smckusick SCTL_INTR_ENAB | SCTL_PARITY_ENAB; 11641488Smckusick else 11741488Smckusick hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB | 11841488Smckusick SCTL_SEL_ENAB | SCTL_RESEL_ENAB | 11941488Smckusick SCTL_INTR_ENAB; 12041488Smckusick hd->scsi_sctl &=~ SCTL_DISABLE; 12141488Smckusick } 12241488Smckusick 12341488Smckusick 12441488Smckusick int 12541488Smckusick scsiabort(hs, hd) 12641488Smckusick register struct scsi_softc *hs; 12741488Smckusick volatile register struct scsidevice *hd; 12841488Smckusick { 12941488Smckusick printf("scsi error: scsiabort\n"); 13041488Smckusick return (0); 13141488Smckusick } 13241488Smckusick 13341488Smckusick static int 13441488Smckusick issue_select(hd, target, our_addr) 13541488Smckusick volatile register struct scsidevice *hd; 13641488Smckusick u_char target, our_addr; 13741488Smckusick { 13841488Smckusick if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY)) 13941488Smckusick return (1); 14041488Smckusick 14141488Smckusick if (hd->scsi_ints & INTS_DISCON) 14241488Smckusick hd->scsi_ints = INTS_DISCON; 14341488Smckusick 14441488Smckusick hd->scsi_pctl = 0; 14541488Smckusick hd->scsi_temp = (1 << target) | our_addr; 14641488Smckusick /* select timeout is hardcoded to 2ms */ 14741488Smckusick hd->scsi_tch = 0; 14841488Smckusick hd->scsi_tcm = 32; 14941488Smckusick hd->scsi_tcl = 4; 15041488Smckusick 15141488Smckusick hd->scsi_scmd = SCMD_SELECT; 15241488Smckusick return (0); 15341488Smckusick } 15441488Smckusick 15541488Smckusick static int 15641488Smckusick wait_for_select(hd) 15741488Smckusick volatile register struct scsidevice *hd; 15841488Smckusick { 15941488Smckusick u_char ints; 16041488Smckusick 16141488Smckusick while ((ints = hd->scsi_ints) == 0) 16241488Smckusick DELAY(1); 16341488Smckusick hd->scsi_ints = ints; 16441488Smckusick return (!(hd->scsi_ssts & SSTS_INITIATOR)); 16541488Smckusick } 16641488Smckusick 16741488Smckusick static int 16841488Smckusick ixfer_start(hd, len, phase, wait) 16941488Smckusick volatile register struct scsidevice *hd; 17041488Smckusick int len; 17141488Smckusick u_char phase; 17241488Smckusick register int wait; 17341488Smckusick { 17441488Smckusick 17541488Smckusick hd->scsi_tch = len >> 16; 17641488Smckusick hd->scsi_tcm = len >> 8; 17741488Smckusick hd->scsi_tcl = len; 17841488Smckusick hd->scsi_pctl = phase; 17941488Smckusick hd->scsi_tmod = 0; /*XXX*/ 18041488Smckusick hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR; 18141488Smckusick 18241488Smckusick /* wait for xfer to start or svc_req interrupt */ 18341488Smckusick while ((hd->scsi_ssts & SSTS_BUSY) == 0) { 18441488Smckusick if (hd->scsi_ints || --wait < 0) 18541488Smckusick return (0); 18641488Smckusick DELAY(1); 18741488Smckusick } 18841488Smckusick return (1); 18941488Smckusick } 19041488Smckusick 19141488Smckusick static int 19241488Smckusick ixfer_out(hd, len, buf) 19341488Smckusick volatile register struct scsidevice *hd; 19441488Smckusick int len; 19541488Smckusick register u_char *buf; 19641488Smckusick { 19741488Smckusick register int wait = scsi_data_wait; 19841488Smckusick 19941488Smckusick for (; len > 0; --len) { 20041488Smckusick while (hd->scsi_ssts & SSTS_DREG_FULL) { 20141488Smckusick if (hd->scsi_ints || --wait < 0) 20241488Smckusick return (len); 20341488Smckusick DELAY(1); 20441488Smckusick } 20541488Smckusick hd->scsi_dreg = *buf++; 20641488Smckusick } 20741488Smckusick return (0); 20841488Smckusick } 20941488Smckusick 21041488Smckusick static int 21141488Smckusick ixfer_in(hd, len, buf) 21241488Smckusick volatile register struct scsidevice *hd; 21341488Smckusick int len; 21441488Smckusick register u_char *buf; 21541488Smckusick { 21641488Smckusick register int wait = scsi_data_wait; 21741488Smckusick 21841488Smckusick for (; len > 0; --len) { 21941488Smckusick while (hd->scsi_ssts & SSTS_DREG_EMPTY) { 22041488Smckusick if (hd->scsi_ints || --wait < 0) { 22141488Smckusick while (! (hd->scsi_ssts & SSTS_DREG_EMPTY)) { 22241488Smckusick *buf++ = hd->scsi_dreg; 22341488Smckusick --len; 22441488Smckusick } 22541488Smckusick return (len); 22641488Smckusick } 22741488Smckusick DELAY(1); 22841488Smckusick } 22941488Smckusick *buf++ = hd->scsi_dreg; 23041488Smckusick } 23141488Smckusick return (len); 23241488Smckusick } 23341488Smckusick 23441488Smckusick static int 23541488Smckusick scsiicmd(hs, target, cbuf, clen, buf, len, xferphase) 23641488Smckusick struct scsi_softc *hs; 23741488Smckusick int target; 23841488Smckusick u_char *cbuf; 23941488Smckusick int clen; 24041488Smckusick u_char *buf; 24141488Smckusick int len; 24241488Smckusick u_char xferphase; 24341488Smckusick { 24441488Smckusick volatile register struct scsidevice *hd = 24541488Smckusick (struct scsidevice *)hs->sc_addr; 24641488Smckusick int i; 24741488Smckusick u_char phase, ints; 24841488Smckusick register int wait; 24941488Smckusick 25041488Smckusick /* select the SCSI bus (it's an error if bus isn't free) */ 25141488Smckusick if (issue_select(hd, target, hs->sc_scsi_addr)) 25241488Smckusick return (0); 25341488Smckusick if (wait_for_select(hd)) 25441488Smckusick return (0); 25541488Smckusick /* 25641488Smckusick * Wait for a phase change (or error) then let the device 25741488Smckusick * sequence us through the various SCSI phases. 25841488Smckusick */ 25941488Smckusick phase = CMD_PHASE; 26041488Smckusick while (1) { 26141488Smckusick wait = scsi_cmd_wait; 26241488Smckusick switch (phase) { 26341488Smckusick 26441488Smckusick case CMD_PHASE: 26541488Smckusick if (ixfer_start(hd, clen, phase, wait)) 26641488Smckusick if (ixfer_out(hd, clen, cbuf)) 26741488Smckusick goto abort; 26841488Smckusick phase = xferphase; 26941488Smckusick break; 27041488Smckusick 27141488Smckusick case DATA_IN_PHASE: 27241488Smckusick if (len <= 0) 27341488Smckusick goto abort; 27441488Smckusick wait = scsi_data_wait; 27541488Smckusick if (ixfer_start(hd, len, phase, wait) || 27641488Smckusick !(hd->scsi_ssts & SSTS_DREG_EMPTY)) 27741488Smckusick ixfer_in(hd, len, buf); 27841488Smckusick phase = STATUS_PHASE; 27941488Smckusick break; 28041488Smckusick 28141488Smckusick case DATA_OUT_PHASE: 28241488Smckusick if (len <= 0) 28341488Smckusick goto abort; 28441488Smckusick wait = scsi_data_wait; 28541488Smckusick if (ixfer_start(hd, len, phase, wait)) 28641488Smckusick if (ixfer_out(hd, len, buf)) 28741488Smckusick goto abort; 28841488Smckusick phase = STATUS_PHASE; 28941488Smckusick break; 29041488Smckusick 29141488Smckusick case STATUS_PHASE: 29241488Smckusick wait = scsi_data_wait; 29341488Smckusick if (ixfer_start(hd, sizeof(hs->sc_stat), phase, wait) || 29441488Smckusick !(hd->scsi_ssts & SSTS_DREG_EMPTY)) 29541488Smckusick ixfer_in(hd, sizeof(hs->sc_stat), &hs->sc_stat); 29641488Smckusick phase = MESG_IN_PHASE; 29741488Smckusick break; 29841488Smckusick 29941488Smckusick case MESG_IN_PHASE: 30041488Smckusick if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait) || 30141488Smckusick !(hd->scsi_ssts & SSTS_DREG_EMPTY)) { 30241488Smckusick ixfer_in(hd, sizeof(hs->sc_msg), &hs->sc_msg); 30341488Smckusick hd->scsi_scmd = SCMD_RST_ACK; 30441488Smckusick } 30541488Smckusick phase = BUS_FREE_PHASE; 30641488Smckusick break; 30741488Smckusick 30841488Smckusick case BUS_FREE_PHASE: 30941488Smckusick return (1); 31041488Smckusick 31141488Smckusick default: 31241488Smckusick printf("unexpected scsi phase %d\n", phase); 31341488Smckusick goto abort; 31441488Smckusick } 31541488Smckusick /* wait for last command to complete */ 31641488Smckusick while ((ints = hd->scsi_ints) == 0) { 31741488Smckusick if (--wait < 0) 31841488Smckusick goto abort; 31941488Smckusick DELAY(1); 32041488Smckusick } 32141488Smckusick hd->scsi_ints = ints; 32241488Smckusick if (ints & INTS_SRV_REQ) 32341488Smckusick phase = hd->scsi_psns & PHASE; 32441488Smckusick else if (ints & INTS_DISCON) 32541488Smckusick return (1); 32641488Smckusick else if ((ints & INTS_CMD_DONE) == 0) { 32741488Smckusick goto abort; 32841488Smckusick } 32941488Smckusick } 33041488Smckusick abort: 33141488Smckusick scsiabort(hs, hd); 33241488Smckusick return (0); 33341488Smckusick } 33441488Smckusick 33541488Smckusick int 33641488Smckusick scsi_test_unit_rdy(unit) 33741488Smckusick { 33841488Smckusick int ctlr = scsiunit(unit); 33941488Smckusick int slave = scsislave(unit); 34041488Smckusick register struct scsi_softc *hs = &scsi_softc[ctlr]; 34141488Smckusick static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY }; 34241488Smckusick 34341488Smckusick if (scsiicmd(hs, slave, &cdb, sizeof(cdb), (u_char *)0, 0, 34441488Smckusick STATUS_PHASE) == 0) 34541488Smckusick return (0); 34641488Smckusick 34741488Smckusick return (hs->sc_stat == 0); 34841488Smckusick } 34941488Smckusick 35041488Smckusick int 35141488Smckusick scsi_request_sense(unit, buf, len) 35241488Smckusick int unit; 35341488Smckusick u_char *buf; 35441488Smckusick unsigned len; 35541488Smckusick { 35641488Smckusick int ctlr = scsiunit(unit); 35741488Smckusick int slave = scsislave(unit); 35841488Smckusick register struct scsi_softc *hs = &scsi_softc[ctlr]; 35941488Smckusick static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE }; 36041488Smckusick 36141488Smckusick cdb.len = len; 36241488Smckusick return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE)); 36341488Smckusick } 36441488Smckusick 36541488Smckusick int 36641488Smckusick scsi_read_capacity(unit, buf, len) 36741488Smckusick int unit; 36841488Smckusick u_char *buf; 36941488Smckusick unsigned len; 37041488Smckusick { 37141488Smckusick int ctlr = scsiunit(unit); 37241488Smckusick int slave = scsislave(unit); 37341488Smckusick register struct scsi_softc *hs = &scsi_softc[ctlr]; 37441488Smckusick static struct scsi_cdb10 cdb = { CMD_READ_CAPACITY }; 37541488Smckusick 37641488Smckusick return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE)); 37741488Smckusick } 37841488Smckusick 37941488Smckusick int 38041488Smckusick scsi_tt_read(unit, buf, len, blk, nblk) 38141488Smckusick int unit; 38241488Smckusick u_char *buf; 38341488Smckusick u_int len; 38441488Smckusick daddr_t blk; 38541488Smckusick u_int nblk; 38641488Smckusick { 38741488Smckusick int ctlr = scsiunit(unit); 38841488Smckusick int slave = scsislave(unit); 38941488Smckusick register struct scsi_softc *hs = &scsi_softc[ctlr]; 39041488Smckusick struct scsi_cdb10 cdb; 39141488Smckusick int stat; 39241488Smckusick 39341488Smckusick bzero(&cdb, sizeof(cdb)); 39441488Smckusick cdb.cmd = CMD_READ_EXT; 39541488Smckusick cdb.lbah = blk >> 24; 39641488Smckusick cdb.lbahm = blk >> 16; 39741488Smckusick cdb.lbalm = blk >> 8; 39841488Smckusick cdb.lbal = blk; 39941488Smckusick cdb.lenh = nblk >> (8 + DEV_BSHIFT); 40041488Smckusick cdb.lenl = nblk >> DEV_BSHIFT; 40141488Smckusick stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE); 40241488Smckusick if (stat == 0) 40341488Smckusick return (1); 40441488Smckusick return (hs->sc_stat); 40541488Smckusick } 40641488Smckusick 40741488Smckusick int 40841488Smckusick scsi_tt_write(unit, buf, len, blk, nblk) 40941488Smckusick int unit; 41041488Smckusick u_char *buf; 41141488Smckusick u_int len; 41241488Smckusick daddr_t blk; 41341488Smckusick u_int nblk; 41441488Smckusick { 41541488Smckusick int ctlr = scsiunit(unit); 41641488Smckusick int slave = scsislave(unit); 41741488Smckusick register struct scsi_softc *hs = &scsi_softc[ctlr]; 41841488Smckusick struct scsi_cdb10 cdb; 41941488Smckusick int stat; 42041488Smckusick 42141488Smckusick bzero(&cdb, sizeof(cdb)); 42241488Smckusick cdb.cmd = CMD_WRITE_EXT; 42341488Smckusick cdb.lbah = blk >> 24; 42441488Smckusick cdb.lbahm = blk >> 16; 42541488Smckusick cdb.lbalm = blk >> 8; 42641488Smckusick cdb.lbal = blk; 42741488Smckusick cdb.lenh = nblk >> (8 + DEV_BSHIFT); 42841488Smckusick cdb.lenl = nblk >> DEV_BSHIFT; 42941488Smckusick stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_OUT_PHASE); 43041488Smckusick if (stat == 0) 43141488Smckusick return (1); 43241488Smckusick return (hs->sc_stat); 43341488Smckusick } 434