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