xref: /csrg-svn/sys/hp300/stand/scsi.c (revision 63165)
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