141488Smckusick /*
241488Smckusick * Copyright (c) 1988 University of Utah.
3*63165Sbostic * Copyright (c) 1990, 1993
4*63165Sbostic * The Regents of the University of California. 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*63165Sbostic * @(#)scsi.c 8.1 (Berkeley) 06/10/93
1541488Smckusick */
1641488Smckusick
1741488Smckusick /*
1841488Smckusick * SCSI bus driver for standalone programs.
1941488Smckusick */
2041488Smckusick
2156510Sbostic #include <sys/param.h>
2256510Sbostic #include <sys/reboot.h>
2356510Sbostic #include <hp/dev/device.h>
2456510Sbostic #include <hp300/dev/scsireg.h>
2556510Sbostic #include <hp300/stand/scsivar.h>
2641488Smckusick
2760329Smckusick #include <stand.att/saio.h>
2856510Sbostic #include <hp300/stand/samachdep.h>
2941488Smckusick
3041488Smckusick struct scsi_softc scsi_softc[NSCSI];
3141488Smckusick
3241488Smckusick void scsireset();
3354073Shibler int scsi_cmd_wait = 50000; /* use the "real" driver init_wait value */
3454073Shibler int scsi_data_wait = 50000; /* use the "real" driver init_wait value */
3541488Smckusick
scsiinit()3641488Smckusick scsiinit()
3741488Smckusick {
3841488Smckusick extern struct hp_hw sc_table[];
3941488Smckusick register struct hp_hw *hw;
4041488Smckusick register struct scsi_softc *hs;
4141488Smckusick register int i, addr;
4254073Shibler static int waitset = 0;
4341488Smckusick
4441488Smckusick i = 0;
4549334Shibler for (hw = sc_table; i < NSCSI && hw < &sc_table[MAXCTLRS]; hw++) {
4649334Shibler if (!HW_ISSCSI(hw))
4741488Smckusick continue;
4841488Smckusick hs = &scsi_softc[i];
4949334Shibler hs->sc_addr = hw->hw_kva;
5041488Smckusick scsireset(i);
5141488Smckusick if (howto & RB_ASKNAME)
5241488Smckusick printf("scsi%d at sc%d\n", i, hw->hw_sc);
5354073Shibler hw->hw_pa = (caddr_t) i; /* XXX for autoconfig */
5441488Smckusick hs->sc_alive = 1;
5541488Smckusick i++;
5641488Smckusick }
5754073Shibler /*
5854073Shibler * Adjust the wait values
5954073Shibler */
6054073Shibler if (!waitset) {
6154073Shibler scsi_cmd_wait *= cpuspeed;
6254073Shibler scsi_data_wait *= cpuspeed;
6354073Shibler waitset = 1;
6454073Shibler }
6541488Smckusick }
6641488Smckusick
scsialive(unit)6741488Smckusick scsialive(unit)
6841488Smckusick register int unit;
6941488Smckusick {
7041488Smckusick if (unit >= NSCSI || scsi_softc[unit].sc_alive == 0)
7141488Smckusick return (0);
7241488Smckusick return (1);
7341488Smckusick }
7441488Smckusick
7541488Smckusick void
scsireset(unit)7641488Smckusick scsireset(unit)
7741488Smckusick register int unit;
7841488Smckusick {
7941488Smckusick volatile register struct scsidevice *hd;
8041488Smckusick register struct scsi_softc *hs;
8141488Smckusick u_int i;
8241488Smckusick
8341488Smckusick hs = &scsi_softc[unit];
8441488Smckusick hd = (struct scsidevice *)hs->sc_addr;
8541488Smckusick hd->scsi_id = 0xFF;
8641488Smckusick DELAY(100);
8741488Smckusick /*
8841488Smckusick * Disable interrupts then reset the FUJI chip.
8941488Smckusick */
9041488Smckusick hd->scsi_csr = 0;
9141488Smckusick hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST;
9241488Smckusick hd->scsi_scmd = 0;
9341488Smckusick hd->scsi_tmod = 0;
9441488Smckusick hd->scsi_pctl = 0;
9541488Smckusick hd->scsi_temp = 0;
9641488Smckusick hd->scsi_tch = 0;
9741488Smckusick hd->scsi_tcm = 0;
9841488Smckusick hd->scsi_tcl = 0;
9941488Smckusick hd->scsi_ints = 0;
10041488Smckusick
10141488Smckusick /*
10241488Smckusick * Configure the FUJI chip with its SCSI address, all
10341488Smckusick * interrupts enabled & appropriate parity.
10441488Smckusick */
10541488Smckusick i = (~hd->scsi_hconf) & 0x7;
10641488Smckusick hs->sc_scsi_addr = 1 << i;
10741488Smckusick hd->scsi_bdid = i;
10841488Smckusick if (hd->scsi_hconf & HCONF_PARITY)
10941488Smckusick hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
11041488Smckusick SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
11141488Smckusick SCTL_INTR_ENAB | SCTL_PARITY_ENAB;
11241488Smckusick else
11341488Smckusick hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
11441488Smckusick SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
11541488Smckusick SCTL_INTR_ENAB;
11641488Smckusick hd->scsi_sctl &=~ SCTL_DISABLE;
11741488Smckusick }
11841488Smckusick
11941488Smckusick
12041488Smckusick int
scsiabort(hs,hd)12141488Smckusick scsiabort(hs, hd)
12241488Smckusick register struct scsi_softc *hs;
12341488Smckusick volatile register struct scsidevice *hd;
12441488Smckusick {
12554073Shibler printf("scsi%d error: scsiabort\n", hs - scsi_softc);
12654073Shibler
12754073Shibler scsireset(hs - scsi_softc);
12857299Shibler DELAY(1000000);
12941488Smckusick }
13041488Smckusick
13141488Smckusick static int
issue_select(hd,target,our_addr)13241488Smckusick issue_select(hd, target, our_addr)
13341488Smckusick volatile register struct scsidevice *hd;
13441488Smckusick u_char target, our_addr;
13541488Smckusick {
13641488Smckusick if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))
13741488Smckusick return (1);
13841488Smckusick
13941488Smckusick if (hd->scsi_ints & INTS_DISCON)
14041488Smckusick hd->scsi_ints = INTS_DISCON;
14141488Smckusick
14241488Smckusick hd->scsi_pctl = 0;
14341488Smckusick hd->scsi_temp = (1 << target) | our_addr;
14441488Smckusick /* select timeout is hardcoded to 2ms */
14541488Smckusick hd->scsi_tch = 0;
14641488Smckusick hd->scsi_tcm = 32;
14741488Smckusick hd->scsi_tcl = 4;
14841488Smckusick
14941488Smckusick hd->scsi_scmd = SCMD_SELECT;
15041488Smckusick return (0);
15141488Smckusick }
15241488Smckusick
15341488Smckusick static int
wait_for_select(hd)15441488Smckusick wait_for_select(hd)
15541488Smckusick volatile register struct scsidevice *hd;
15641488Smckusick {
15754073Shibler register int wait;
15841488Smckusick u_char ints;
15941488Smckusick
16054073Shibler wait = scsi_data_wait;
16154073Shibler while ((ints = hd->scsi_ints) == 0) {
16254073Shibler if (--wait < 0)
16354073Shibler return (1);
16441488Smckusick DELAY(1);
16554073Shibler }
16641488Smckusick hd->scsi_ints = ints;
16741488Smckusick return (!(hd->scsi_ssts & SSTS_INITIATOR));
16841488Smckusick }
16941488Smckusick
17041488Smckusick static int
ixfer_start(hd,len,phase,wait)17141488Smckusick ixfer_start(hd, len, phase, wait)
17241488Smckusick volatile register struct scsidevice *hd;
17341488Smckusick int len;
17441488Smckusick u_char phase;
17541488Smckusick register int wait;
17641488Smckusick {
17741488Smckusick
17841488Smckusick hd->scsi_tch = len >> 16;
17941488Smckusick hd->scsi_tcm = len >> 8;
18041488Smckusick hd->scsi_tcl = len;
18141488Smckusick hd->scsi_pctl = phase;
18241488Smckusick hd->scsi_tmod = 0; /*XXX*/
18341488Smckusick hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
18441488Smckusick
18541488Smckusick /* wait for xfer to start or svc_req interrupt */
18641488Smckusick while ((hd->scsi_ssts & SSTS_BUSY) == 0) {
18741488Smckusick if (hd->scsi_ints || --wait < 0)
18841488Smckusick return (0);
18941488Smckusick DELAY(1);
19041488Smckusick }
19141488Smckusick return (1);
19241488Smckusick }
19341488Smckusick
19441488Smckusick static int
ixfer_out(hd,len,buf)19541488Smckusick ixfer_out(hd, len, buf)
19641488Smckusick volatile register struct scsidevice *hd;
19741488Smckusick int len;
19841488Smckusick register u_char *buf;
19941488Smckusick {
20041488Smckusick register int wait = scsi_data_wait;
20141488Smckusick
20241488Smckusick for (; len > 0; --len) {
20341488Smckusick while (hd->scsi_ssts & SSTS_DREG_FULL) {
20441488Smckusick if (hd->scsi_ints || --wait < 0)
20541488Smckusick return (len);
20641488Smckusick DELAY(1);
20741488Smckusick }
20841488Smckusick hd->scsi_dreg = *buf++;
20941488Smckusick }
21041488Smckusick return (0);
21141488Smckusick }
21241488Smckusick
21341488Smckusick static int
ixfer_in(hd,len,buf)21441488Smckusick ixfer_in(hd, len, buf)
21541488Smckusick volatile register struct scsidevice *hd;
21641488Smckusick int len;
21741488Smckusick register u_char *buf;
21841488Smckusick {
21941488Smckusick register int wait = scsi_data_wait;
22041488Smckusick
22141488Smckusick for (; len > 0; --len) {
22241488Smckusick while (hd->scsi_ssts & SSTS_DREG_EMPTY) {
22341488Smckusick if (hd->scsi_ints || --wait < 0) {
22441488Smckusick while (! (hd->scsi_ssts & SSTS_DREG_EMPTY)) {
22541488Smckusick *buf++ = hd->scsi_dreg;
22641488Smckusick --len;
22741488Smckusick }
22841488Smckusick return (len);
22941488Smckusick }
23041488Smckusick DELAY(1);
23141488Smckusick }
23241488Smckusick *buf++ = hd->scsi_dreg;
23341488Smckusick }
23441488Smckusick return (len);
23541488Smckusick }
23641488Smckusick
23741488Smckusick static int
scsiicmd(hs,target,cbuf,clen,buf,len,xferphase)23841488Smckusick scsiicmd(hs, target, cbuf, clen, buf, len, xferphase)
23941488Smckusick struct scsi_softc *hs;
24041488Smckusick int target;
24141488Smckusick u_char *cbuf;
24241488Smckusick int clen;
24341488Smckusick u_char *buf;
24441488Smckusick int len;
24541488Smckusick u_char xferphase;
24641488Smckusick {
24741488Smckusick volatile register struct scsidevice *hd =
24841488Smckusick (struct scsidevice *)hs->sc_addr;
24941488Smckusick u_char phase, ints;
25041488Smckusick register int wait;
25141488Smckusick
25241488Smckusick /* select the SCSI bus (it's an error if bus isn't free) */
25341488Smckusick if (issue_select(hd, target, hs->sc_scsi_addr))
25454073Shibler return (-2);
25541488Smckusick if (wait_for_select(hd))
25654073Shibler return (-2);
25741488Smckusick /*
25841488Smckusick * Wait for a phase change (or error) then let the device
25941488Smckusick * sequence us through the various SCSI phases.
26041488Smckusick */
26154073Shibler hs->sc_stat = -1;
26241488Smckusick phase = CMD_PHASE;
26341488Smckusick while (1) {
26441488Smckusick wait = scsi_cmd_wait;
26541488Smckusick switch (phase) {
26641488Smckusick
26741488Smckusick case CMD_PHASE:
26841488Smckusick if (ixfer_start(hd, clen, phase, wait))
26941488Smckusick if (ixfer_out(hd, clen, cbuf))
27041488Smckusick goto abort;
27141488Smckusick phase = xferphase;
27241488Smckusick break;
27341488Smckusick
27441488Smckusick case DATA_IN_PHASE:
27541488Smckusick if (len <= 0)
27641488Smckusick goto abort;
27741488Smckusick wait = scsi_data_wait;
27841488Smckusick if (ixfer_start(hd, len, phase, wait) ||
27941488Smckusick !(hd->scsi_ssts & SSTS_DREG_EMPTY))
28041488Smckusick ixfer_in(hd, len, buf);
28141488Smckusick phase = STATUS_PHASE;
28241488Smckusick break;
28341488Smckusick
28441488Smckusick case DATA_OUT_PHASE:
28541488Smckusick if (len <= 0)
28641488Smckusick goto abort;
28741488Smckusick wait = scsi_data_wait;
28841488Smckusick if (ixfer_start(hd, len, phase, wait))
28941488Smckusick if (ixfer_out(hd, len, buf))
29041488Smckusick goto abort;
29141488Smckusick phase = STATUS_PHASE;
29241488Smckusick break;
29341488Smckusick
29441488Smckusick case STATUS_PHASE:
29541488Smckusick wait = scsi_data_wait;
29641488Smckusick if (ixfer_start(hd, sizeof(hs->sc_stat), phase, wait) ||
29741488Smckusick !(hd->scsi_ssts & SSTS_DREG_EMPTY))
29841488Smckusick ixfer_in(hd, sizeof(hs->sc_stat), &hs->sc_stat);
29941488Smckusick phase = MESG_IN_PHASE;
30041488Smckusick break;
30141488Smckusick
30241488Smckusick case MESG_IN_PHASE:
30341488Smckusick if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait) ||
30441488Smckusick !(hd->scsi_ssts & SSTS_DREG_EMPTY)) {
30541488Smckusick ixfer_in(hd, sizeof(hs->sc_msg), &hs->sc_msg);
30641488Smckusick hd->scsi_scmd = SCMD_RST_ACK;
30741488Smckusick }
30841488Smckusick phase = BUS_FREE_PHASE;
30941488Smckusick break;
31041488Smckusick
31141488Smckusick case BUS_FREE_PHASE:
31254073Shibler goto out;
31341488Smckusick
31441488Smckusick default:
31554073Shibler printf("scsi%d: unexpected scsi phase %d\n",
31654073Shibler hs - scsi_softc, phase);
31741488Smckusick goto abort;
31841488Smckusick }
31954073Shibler #ifdef SLOWSCSI
32054073Shibler /*
32154073Shibler * XXX we have wierd transient problems with booting from
32254073Shibler * slow scsi disks on fast machines. I have never been
32354073Shibler * able to pin the problem down, but a large delay here
32454073Shibler * seems to always work.
32554073Shibler */
32654073Shibler DELAY(1000);
32754073Shibler #endif
32841488Smckusick /* wait for last command to complete */
32941488Smckusick while ((ints = hd->scsi_ints) == 0) {
33041488Smckusick if (--wait < 0)
33141488Smckusick goto abort;
33241488Smckusick DELAY(1);
33341488Smckusick }
33441488Smckusick hd->scsi_ints = ints;
33541488Smckusick if (ints & INTS_SRV_REQ)
33641488Smckusick phase = hd->scsi_psns & PHASE;
33741488Smckusick else if (ints & INTS_DISCON)
33854073Shibler goto out;
33954073Shibler else if ((ints & INTS_CMD_DONE) == 0)
34041488Smckusick goto abort;
34141488Smckusick }
34241488Smckusick abort:
34341488Smckusick scsiabort(hs, hd);
34454073Shibler out:
34554073Shibler return (hs->sc_stat);
34641488Smckusick }
34741488Smckusick
34841488Smckusick int
scsi_test_unit_rdy(ctlr,slave)34954073Shibler scsi_test_unit_rdy(ctlr, slave)
35054073Shibler int ctlr, slave;
35141488Smckusick {
35241488Smckusick register struct scsi_softc *hs = &scsi_softc[ctlr];
35341488Smckusick static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
35441488Smckusick
35554073Shibler return (scsiicmd(hs, slave, &cdb, sizeof(cdb), (u_char *)0, 0,
35654073Shibler STATUS_PHASE));
35741488Smckusick }
35841488Smckusick
35941488Smckusick int
scsi_request_sense(ctlr,slave,buf,len)36054073Shibler scsi_request_sense(ctlr, slave, buf, len)
36154073Shibler int ctlr, slave;
36241488Smckusick u_char *buf;
36341488Smckusick unsigned len;
36441488Smckusick {
36541488Smckusick register struct scsi_softc *hs = &scsi_softc[ctlr];
36641488Smckusick static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE };
36741488Smckusick
36841488Smckusick cdb.len = len;
36954073Shibler return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len,
37054073Shibler DATA_IN_PHASE));
37141488Smckusick }
37241488Smckusick
37341488Smckusick int
scsi_read_capacity(ctlr,slave,buf,len)37454073Shibler scsi_read_capacity(ctlr, slave, buf, len)
37554073Shibler int ctlr, slave;
37641488Smckusick u_char *buf;
37741488Smckusick unsigned len;
37841488Smckusick {
37941488Smckusick register struct scsi_softc *hs = &scsi_softc[ctlr];
38041488Smckusick static struct scsi_cdb10 cdb = { CMD_READ_CAPACITY };
38141488Smckusick
38254073Shibler return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len,
38354073Shibler DATA_IN_PHASE));
38441488Smckusick }
38541488Smckusick
38641488Smckusick int
scsi_tt_read(ctlr,slave,buf,len,blk,nblk)38754073Shibler scsi_tt_read(ctlr, slave, buf, len, blk, nblk)
38854073Shibler int ctlr, slave;
38941488Smckusick u_char *buf;
39041488Smckusick u_int len;
39141488Smckusick daddr_t blk;
39241488Smckusick u_int nblk;
39341488Smckusick {
39441488Smckusick register struct scsi_softc *hs = &scsi_softc[ctlr];
39541488Smckusick struct scsi_cdb10 cdb;
39641488Smckusick
39741488Smckusick bzero(&cdb, sizeof(cdb));
39841488Smckusick cdb.cmd = CMD_READ_EXT;
39941488Smckusick cdb.lbah = blk >> 24;
40041488Smckusick cdb.lbahm = blk >> 16;
40141488Smckusick cdb.lbalm = blk >> 8;
40241488Smckusick cdb.lbal = blk;
40341488Smckusick cdb.lenh = nblk >> (8 + DEV_BSHIFT);
40441488Smckusick cdb.lenl = nblk >> DEV_BSHIFT;
40554073Shibler return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len,
40654073Shibler DATA_IN_PHASE));
40741488Smckusick }
40841488Smckusick
40941488Smckusick int
scsi_tt_write(ctlr,slave,buf,len,blk,nblk)41054073Shibler scsi_tt_write(ctlr, slave, buf, len, blk, nblk)
41154073Shibler int ctlr, slave;
41241488Smckusick u_char *buf;
41341488Smckusick u_int len;
41441488Smckusick daddr_t blk;
41541488Smckusick u_int nblk;
41641488Smckusick {
41741488Smckusick register struct scsi_softc *hs = &scsi_softc[ctlr];
41841488Smckusick struct scsi_cdb10 cdb;
41941488Smckusick
42041488Smckusick bzero(&cdb, sizeof(cdb));
42141488Smckusick cdb.cmd = CMD_WRITE_EXT;
42241488Smckusick cdb.lbah = blk >> 24;
42341488Smckusick cdb.lbahm = blk >> 16;
42441488Smckusick cdb.lbalm = blk >> 8;
42541488Smckusick cdb.lbal = blk;
42641488Smckusick cdb.lenh = nblk >> (8 + DEV_BSHIFT);
42741488Smckusick cdb.lenl = nblk >> DEV_BSHIFT;
42854073Shibler return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len,
42954073Shibler DATA_OUT_PHASE));
43041488Smckusick }
431