154879Storek /*
2*63459Sbostic * Copyright (c) 1992, 1993
3*63459Sbostic * The Regents of the University of California. All rights reserved.
454879Storek *
554879Storek * This software was developed by the Computer Systems Engineering group
654879Storek * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
754879Storek * contributed to Berkeley.
854879Storek *
955559Storek * All advertising materials mentioning features or use of this software
1055559Storek * must display the following acknowledgement:
1155559Storek * This product includes software developed by the University of
1255559Storek * California, Lawrence Berkeley Laboratories.
1355559Storek *
1454879Storek * %sccs.include.redist.c%
1554879Storek *
16*63459Sbostic * @(#)scsi_subr.c 8.1 (Berkeley) 06/16/93
1754879Storek *
1857755Storek * from: $Header: scsi_subr.c,v 1.10 93/02/01 19:21:58 torek Exp $ (LBL)
1954879Storek */
2054879Storek
2154879Storek /*
2254879Storek * Generic SCSI host adapter driver.
2354879Storek * Does almost nothing (most work is relegated to per-hba drivers).
2454879Storek */
2554879Storek
2655559Storek #include <sys/param.h>
2755559Storek #include <sys/buf.h>
2855559Storek #include <sys/device.h>
2954879Storek
3056898Storek #include <dev/scsi/scsi.h>
3156898Storek #include <dev/scsi/scsivar.h>
3255559Storek
3354879Storek /*
3454879Storek * General subroutines, and scsi data.
3554879Storek */
3654879Storek
3754879Storek /* table of lengths of scsi commands */
3854879Storek const char scsicmdlen[8] = { 6, 10, 0, 0, 0, 12, 0, 0 };
3954879Storek
4054879Storek /* table of lengths of scsi messages */
4154879Storek const signed char scsimsglen[0x24] = {
4254879Storek SMLEN_DONE, /* MSG_CMD_COMPLETE */
4354879Storek SMLEN_EXTENDED, /* MSG_EXT_MESSAGE */
4454879Storek 1, /* MSG_SAVE_DATA_PTR */
4554879Storek 1, /* MSG_RESTORE_PTR */
4654879Storek 1, /* MSG_DISCONNECT */
4754879Storek 1, /* MSG_INIT_DETECT_ERROR */
4854879Storek 1, /* MSG_ABORT */
4954879Storek 1, /* MSG_REJECT */
5054879Storek 1, /* MSG_NOOP */
5154879Storek 1, /* MSG_PARITY_ERROR */
5254879Storek 1, /* MSG_LCC */
5354879Storek 1, /* MSG_LCCF */
5454879Storek 1, /* MSG_BUS_DEVICE_RESET */
5554879Storek 1, /* MSG_ABORT_TAG */
5654879Storek 1, /* MSG_CLEAR_QUEUE */
5754879Storek 1, /* MSG_INITIATE_RECOVERY */
5854879Storek 1, /* MSG_RELEASE_RECOVERY */
5954879Storek 1, /* MSG_TERMINATE_PROCESS */
6054879Storek SMLEN_UNDEF, /* 0x12 */
6154879Storek SMLEN_UNDEF, /* 0x13 */
6254879Storek SMLEN_UNDEF, /* 0x14 */
6354879Storek SMLEN_UNDEF, /* 0x15 */
6454879Storek SMLEN_UNDEF, /* 0x16 */
6554879Storek SMLEN_UNDEF, /* 0x17 */
6654879Storek SMLEN_UNDEF, /* 0x18 */
6754879Storek SMLEN_UNDEF, /* 0x19 */
6854879Storek SMLEN_UNDEF, /* 0x1a */
6954879Storek SMLEN_UNDEF, /* 0x1b */
7054879Storek SMLEN_UNDEF, /* 0x1c */
7154879Storek SMLEN_UNDEF, /* 0x1d */
7254879Storek SMLEN_UNDEF, /* 0x1e */
7354879Storek SMLEN_UNDEF, /* 0x1f */
7454879Storek 2, /* MSG_SIMPLE_QTAG */
7554879Storek 2, /* MSG_HEAD_QTAG */
7654879Storek 2, /* MSG_ORDERED_QTAG */
7754879Storek 2, /* MSG_IGNORE_WIDE_RESID */
7854879Storek };
7954879Storek
8054879Storek /* definition of `tg' target driver for autoconfig */
8154879Storek static int scsi_targmatch __P((struct device *, struct cfdata *, void *));
8254879Storek static void scsi_targattach __P((struct device *, struct device *, void *));
8354879Storek struct cfdriver tgcd =
8454879Storek { NULL, "tg", scsi_targmatch, scsi_targattach,
8554879Storek DV_DULL, sizeof(struct targ) };
8654879Storek
8754879Storek void scsi_targstart __P((struct device *, struct sq *, struct buf *,
8854879Storek scdgo_fn, struct device *));
8954879Storek int scsi_targgo __P((struct device *, int targ,
9054879Storek scintr_fn, struct device *, struct buf *, int));
9154879Storek void scsi_targintr __P((struct device *, int, int));
9254879Storek void scsi_targrel __P((struct device *));
9354879Storek
9454879Storek #define NOBUF ((caddr_t)0)
9554879Storek
9654879Storek /*
9754879Storek * Perform a TEST UNIT READY immediate (polled) command
9854879Storek * on the given <target,unit> pair. Return the status byte
9954879Storek * returned, or -1 for none.
10054879Storek */
10154879Storek int
scsi_test_unit_ready(hba,targ,unit)10254879Storek scsi_test_unit_ready(hba, targ, unit)
10354879Storek struct hba_softc *hba;
10454879Storek int targ, unit;
10554879Storek {
10654879Storek struct scsi_cdb cdb;
10754879Storek
10854879Storek CDB6(&cdb)->cdb_cmd = CMD_TEST_UNIT_READY;
10954879Storek CDB6(&cdb)->cdb_lun_lbah = unit << 5;
11054879Storek *(short *)&CDB6(&cdb)->cdb_lbam = 0;
11154879Storek *(short *)&CDB6(&cdb)->cdb_len = 0;
11254879Storek return (hba->hba_driver->hd_icmd(hba, targ, &cdb, NOBUF, 0, 0));
11354879Storek }
11454879Storek
11554879Storek /*
11654879Storek * Request sense. The sense is to be written into the given buffer.
11754879Storek * The given length must be < 256.
11854879Storek */
11954879Storek int
scsi_request_sense(hba,targ,unit,buf,len)12054879Storek scsi_request_sense(hba, targ, unit, buf, len)
12154879Storek struct hba_softc *hba;
12254879Storek int targ, unit;
12354879Storek caddr_t buf;
12454879Storek int len;
12554879Storek {
12654879Storek struct scsi_cdb cdb;
12754879Storek
12854879Storek CDB6(&cdb)->cdb_cmd = CMD_REQUEST_SENSE;
12954879Storek CDB6(&cdb)->cdb_lun_lbah = unit << 5;
13054879Storek *(short *)&CDB6(&cdb)->cdb_lbam = 0;
13154879Storek CDB6(&cdb)->cdb_len = len;
13254879Storek CDB6(&cdb)->cdb_ctrl = 0;
13354879Storek return (hba->hba_driver->hd_icmd(hba, targ, &cdb, buf, len, B_READ));
13454879Storek }
13554879Storek
13654879Storek /*
13754879Storek * Called (indirectly, via config_found) from scsi_hbaattach.
13854879Storek * Print target number, and if no device was configured there,
13954879Storek * the hba as well.
14054879Storek */
14154879Storek int
scsi_targprint(aux,hba)14254879Storek scsi_targprint(aux, hba)
14354879Storek void *aux;
14454879Storek char *hba;
14554879Storek {
14654879Storek
14754879Storek if (hba) {
14854879Storek printf("target %d on %s", *(int *)aux, hba);
14954879Storek return (UNCONF);
15054879Storek }
15154879Storek printf(" target %d", *(int *)aux);
15254879Storek return (QUIET);
15354879Storek }
15454879Storek
15554879Storek /*
15654879Storek * Print information about a unit found on some target.
15754879Storek * If the unit was not configured, `targ' is the name of the target
15854879Storek * on which the unit was found. If it was, targ is NULL and we
15954879Storek * let the unit's attach routine print the INQUIRE result if
16054879Storek * appropriate.
16154879Storek */
16254879Storek static int
scsi_unitprint(aux,targ)16354879Storek scsi_unitprint(aux, targ)
16454879Storek void *aux;
16554879Storek char *targ;
16654879Storek {
16754879Storek register struct scsi_attach_args *sa = aux;
16854879Storek
16954879Storek if (targ) {
17054879Storek printf("unit %d at %s", sa->sa_unit, targ);
17154879Storek if ((sa->sa_inq_status & STS_MASK) == STS_GOOD) {
17254879Storek printf(" (");
17354879Storek scsi_printinq(&sa->sa_si);
17454879Storek printf(")");
17554879Storek }
17654879Storek return (UNCONF);
17754879Storek }
17854879Storek printf(" unit %d", sa->sa_unit);
17954879Storek return (QUIET);
18054879Storek }
18154879Storek
18254879Storek /*
18354879Storek * Generic target-match.
18454879Storek */
18554879Storek static int
scsi_targmatch(parent,cf,aux)18654879Storek scsi_targmatch(parent, cf, aux)
18754879Storek struct device *parent;
18854879Storek register struct cfdata *cf;
18954879Storek void *aux;
19054879Storek {
19154879Storek int targ = *(int *)aux;
19254879Storek
19354879Storek return (cf->cf_loc[0] == targ || cf->cf_loc[0] == -1);
19454879Storek }
19554879Storek
19654879Storek /*
19754879Storek * And now, a generic `target attach' routine.
19854879Storek * We assume that INQUIRY works.
19954879Storek */
20054879Storek static void
scsi_targattach(parent,self,aux)20154879Storek scsi_targattach(parent, self, aux)
20254879Storek struct device *parent, *self;
20354879Storek void *aux;
20454879Storek {
20554879Storek register struct targ *t = (struct targ *)self;
20654879Storek register struct hba_softc *hba;
20754879Storek register struct hbadriver *hd;
20854879Storek register int targ, unit;
20954879Storek struct scsi_attach_args sa;
21054879Storek struct scsi_cdb si;
21154879Storek
21254879Storek printf("\n");
21354879Storek t->t_targ = targ = *(int *)aux;
21454879Storek hba = (struct hba_softc *)parent;
21554879Storek hba->hba_targets[targ] = t;
21654879Storek
21754879Storek /*
21854879Storek * Probe each of the 8 units using the sequence
21954879Storek * TEST UNIT READY
22054879Storek * REQUEST SENSE
22154879Storek * INQUIRY
22254879Storek * The first should not be necessary, but some SCSI devices
22354879Storek * refuse to speak until it is done. The second is only necessary
22454879Storek * if the first returns a CHECK CONDITION status, but we do it
22554879Storek * anyway.
22654879Storek */
22754879Storek hd = hba->hba_driver;
22854879Storek sa.sa_targ = targ;
22954879Storek CDB6(&si)->cdb_cmd = CMD_INQUIRY;
23054879Storek *(short *)&CDB6(&si)->cdb_lbam = 0;
23154879Storek CDB6(&si)->cdb_len = sizeof sa.sa_si;
23254879Storek CDB6(&si)->cdb_ctrl = 0;
23354879Storek for (unit = 0; unit < 8; unit++) {
23454879Storek if (scsi_test_unit_ready(hba, targ, unit) == -1)
23554879Storek continue;
23654879Storek sa.sa_unit = unit;
23754879Storek sa.sa_req_status = scsi_request_sense(hba, targ, unit,
23854879Storek (caddr_t)&sa.sa_sn, sizeof sa.sa_sn);
23954879Storek CDB6(&si)->cdb_lun_lbah = unit << 5;
24054879Storek sa.sa_inq_status = (*hd->hd_icmd)(hba, targ, &si,
24154879Storek (caddr_t)&sa.sa_si, sizeof sa.sa_si, B_READ);
24254879Storek if ((sa.sa_inq_status & STS_MASK) == STS_GOOD &&
24354879Storek #ifdef notdef /* XXX don't know if this is a reasonable test */
24454879Storek (sa.sa_si.si_type & TYPE_QUAL_MASK) == TYPE_QUAL_NOTCONN &&
24554879Storek #endif
24654879Storek (sa.sa_si.si_type & TYPE_TYPE_MASK) == TYPE_NP) {
24754879Storek continue;
24854879Storek }
24954879Storek config_found(&t->t_dev, (void *)&sa, scsi_unitprint);
25054879Storek }
25154879Storek }
25254879Storek
25354879Storek /*
25454879Storek * Each unit calls scsi_establish to tell the hba and target of
25554879Storek * its existence.
25654879Storek */
25754879Storek void
scsi_establish(u,dev,unit)25854879Storek scsi_establish(u, dev, unit)
25954879Storek register struct unit *u;
26054879Storek struct device *dev;
26154879Storek register int unit;
26254879Storek {
26354879Storek register struct targ *t;
26454879Storek register struct hba_softc *hba;
26554879Storek register struct hbadriver *hbd;
26654879Storek
26754879Storek u->u_dev = dev;
26854879Storek t = (struct targ *)dev->dv_parent;
26954879Storek hba = (struct hba_softc *)t->t_dev.dv_parent;
27054879Storek hbd = hba->hba_driver;
27154879Storek t->t_units[unit] = u;
27254879Storek if (t->t_nunits == 0) {
27354879Storek /*
27454879Storek * This is the first unit on the target. We can
27554879Storek * probably just call the hba start code, avoiding
27654879Storek * one level of calls and queueing. If we attach
27754879Storek * another target we will fix this in the code below.
27854879Storek */
27954879Storek u->u_start = hbd->hd_start;
28054879Storek u->u_go = hbd->hd_go;
28154879Storek u->u_rel = hbd->hd_rel;
28254879Storek u->u_updev = &hba->hba_dev;
28354879Storek t->t_firstunit = unit;
28454879Storek } else {
28554879Storek /*
28654879Storek * This is not the only unit on the target, so we
28754879Storek * must call the target start code rather than the
28854879Storek * hba start code. Fix the linkage on the first
28954879Storek * target too (possibly for the 2nd, 3rd, ..., time).
29054879Storek */
29154879Storek t->t_units[t->t_firstunit]->u_start = scsi_targstart;
29263458Smckusick t->t_units[t->t_firstunit]->u_go = scsi_targgo;
29363458Smckusick t->t_units[t->t_firstunit]->u_rel = scsi_targrel;
29454879Storek t->t_units[t->t_firstunit]->u_updev = &t->t_dev;
29554879Storek u->u_start = scsi_targstart;
29654879Storek u->u_go = scsi_targgo;
29754879Storek u->u_rel = scsi_targrel;
29854879Storek u->u_updev = &t->t_dev;
29954879Storek }
30054879Storek t->t_nunits++; /* another unit is alive */
30154879Storek u->u_unit = unit;
30254879Storek u->u_targ = t->t_targ; /* record target number, */
30354879Storek u->u_hba = hba; /* hba ... */
30454879Storek u->u_hbd = hbd; /* and driver */
30554879Storek }
30654879Storek
30754879Storek /* NO DOUBT SOME OF THE STUFF PRINTED HERE IS USELESS */
30854879Storek void
scsi_printinq(inq)30954879Storek scsi_printinq(inq)
31054879Storek register struct scsi_inquiry *inq;
31154879Storek {
31254879Storek register int iso, ecma, ansi, t;
31354879Storek static char *types[] = { "disk", "tape", "printer", "processor",
31454879Storek "WORM", "ROM disk", "scanner", "magneto-optical",
31554879Storek "jukebox", "lan" };
31654879Storek
31754879Storek if ((t = (inq->si_type & TYPE_QUAL_MASK)) != 0)
31854879Storek printf("type-qual=0x%x ", t);
31954879Storek t = inq->si_type & TYPE_TYPE_MASK;
32054879Storek if (t < sizeof types / sizeof *types)
32154879Storek printf("%s", types[t]);
32254879Storek else
32354879Storek printf("<type %d>", t);
32454879Storek if (inq->si_qual & QUAL_RMB)
32554879Storek printf(" (removable)");
32654879Storek printf(" qual=0x%x", inq->si_qual & QUAL_MASK);
32754879Storek iso = (inq->si_qual >> VER_ISO_SHIFT) & VER_ISO_MASK;
32854879Storek ecma = (inq->si_qual >> VER_ECMA_SHIFT) & VER_ECMA_MASK;
32954879Storek ansi = (inq->si_qual >> VER_ANSI_SHIFT) & VER_ANSI_MASK;
33054879Storek printf(" version=<iso %d, ecma %d, ansi %d>", iso, ecma, ansi);
33154879Storek if (ansi == 1 || ansi == 2) {
33254879Storek char v[9], p[17], r[5];
33354879Storek
33454879Storek scsi_inq_ansi((struct scsi_inq_ansi *)inq, v, p, r);
33554879Storek printf(" vendor %s, product %s, rev %s", v, p, r);
33654879Storek }
33754879Storek }
33854879Storek
33954879Storek /* copy a counted string but trim trailing blanks; make the dest a C string */
34054879Storek static void
scsi_str(src,dst,len)34154879Storek scsi_str(src, dst, len)
34254879Storek register char *src, *dst;
34354879Storek register int len;
34454879Storek {
34554879Storek
34654879Storek while (src[len - 1] == ' ') {
34754879Storek if (--len == 0) {
34854879Storek *dst = 0;
34954879Storek return;
35054879Storek }
35154879Storek }
35254879Storek bcopy(src, dst, len);
35354879Storek dst[len] = 0;
35454879Storek }
35554879Storek
35654879Storek void
scsi_inq_ansi(si,vendor,product,rev)35754879Storek scsi_inq_ansi(si, vendor, product, rev)
35854879Storek register struct scsi_inq_ansi *si;
35954879Storek char *vendor, *product, *rev;
36054879Storek {
36154879Storek register int i, len;
36254879Storek
36354879Storek /* if too short, extend with blanks */
36454879Storek len = si->si_len + 5; /* 5 fixed; len is `additional' */
36554879Storek if (len < sizeof(*si))
36654879Storek for (i = len; i < sizeof *si; i++)
36754879Storek ((char *)si)[i] = ' ';
36854879Storek scsi_str(si->si_vendor, vendor, sizeof si->si_vendor);
36954879Storek scsi_str(si->si_product, product, sizeof si->si_product);
37054879Storek scsi_str(si->si_rev, rev, sizeof si->si_rev);
37154879Storek }
37254879Storek
37354879Storek /*
37454879Storek * Tell all the devices on the given hba that it has been reset.
37554879Storek * SHOULD PROBABLY DO MORE HERE
37654879Storek */
37754879Storek void
scsi_reset_units(hba)37854879Storek scsi_reset_units(hba)
37954879Storek register struct hba_softc *hba;
38054879Storek {
38154879Storek register int targ, unit;
38254879Storek register struct targ *t;
38354879Storek register struct unit *u;
38454879Storek
38554879Storek for (targ = 0; targ < 8; targ++) {
38654879Storek if ((t = hba->hba_targets[targ]) == NULL)
38754879Storek continue;
38854879Storek for (unit = 0; unit < 8; unit++)
38954879Storek if ((u = t->t_units[unit]) != NULL)
39054879Storek (*u->u_driver->ud_reset)(u);
39154879Storek }
39254879Storek }
39354879Storek
39454879Storek /*
39554879Storek * Start a unit on a target.
39654879Storek * If the target is busy, just enqueue the unit;
39754879Storek * once the target becomes free, we will call the hba start routine.
39854879Storek * Otherwise, call the hba start routine now, and then when the hba
39954879Storek * becomes free it will call the unit's dgo routine.
40054879Storek */
40154879Storek void
scsi_targstart(self,sq,bp,dgo,dev)40254879Storek scsi_targstart(self, sq, bp, dgo, dev)
40354879Storek struct device *self;
40454879Storek register struct sq *sq;
40554879Storek struct buf *bp;
40654879Storek scdgo_fn dgo;
40754879Storek struct device *dev;
40854879Storek {
40954879Storek register struct targ *t = (struct targ *)self;
41054879Storek register struct hba_softc *hba;
41154879Storek
41254879Storek sq->sq_forw = NULL;
41354879Storek if (t->t_head == NULL)
41454879Storek t->t_head = sq;
41554879Storek else
41654879Storek t->t_tail->sq_forw = sq;
41754879Storek t->t_tail = sq;
41854879Storek if (t->t_busy == 0) {
41954879Storek t->t_busy = 1;
42054879Storek hba = (struct hba_softc *)t->t_dev.dv_parent;
42154879Storek (*hba->hba_driver->hd_start)(&hba->hba_dev, &t->t_forw, bp,
42254879Storek dgo, dev);
42354879Storek } else {
42454879Storek sq->sq_bp = bp;
42554879Storek sq->sq_dgo = dgo;
42654879Storek sq->sq_dev = dev;
42754879Storek }
42854879Storek }
42954879Storek
43054879Storek /*
43154879Storek * The unit got the bus, and wants the hba to go.
43254879Storek * Remember its interrupt handler; substitute ours instead.
43354879Storek */
43454879Storek int
scsi_targgo(self,targ,intr,dev,bp,pad)43554879Storek scsi_targgo(self, targ, intr, dev, bp, pad)
43654879Storek struct device *self;
43754879Storek int targ;
43854879Storek scintr_fn intr;
43954879Storek struct device *dev;
44054879Storek struct buf *bp;
44154879Storek int pad;
44254879Storek {
44354879Storek register struct targ *t = (struct targ *)self;
44454879Storek register struct hba_softc *hba;
44554879Storek
44654879Storek t->t_intr = intr;
44754879Storek t->t_intrdev = dev;
44854879Storek hba = (struct hba_softc *)t->t_dev.dv_parent;
44954879Storek return ((*hba->hba_driver->hd_go)(&hba->hba_dev, targ,
45054879Storek scsi_targintr, &t->t_dev, bp, pad));
45154879Storek }
45254879Storek
45354879Storek /*
45454879Storek * The hba got an interrupt. Dequeue the unit from the target
45554879Storek * (the target is already off the hba queue) and then call the
45654879Storek * underlying interrupt handler.
45754879Storek */
45854879Storek void
scsi_targintr(self,stat,resid)45954879Storek scsi_targintr(self, stat, resid)
46054879Storek struct device *self;
46154879Storek int stat, resid;
46254879Storek {
46354879Storek register struct targ *t = (struct targ *)self;
46454879Storek register struct hba_softc *hba;
46554879Storek register struct sq *sq;
46654879Storek
46754879Storek sq = t->t_head;
46854879Storek if (sq == NULL) panic("scsi_targintr");
46954879Storek t->t_head = sq = sq->sq_forw;
47054879Storek (*t->t_intr)(t->t_intrdev, stat, resid);
47154879Storek if (sq != NULL) {
47254879Storek hba = (struct hba_softc *)t->t_dev.dv_parent;
47354879Storek (*hba->hba_driver->hd_start)(&hba->hba_dev, &t->t_forw,
47454879Storek sq->sq_bp, sq->sq_dgo, sq->sq_dev);
47554879Storek } else
47654879Storek t->t_busy = 0;
47754879Storek }
47854879Storek
47954879Storek /*
48054879Storek * The unit decided that it needed to `give up' its hold on the bus early.
48154879Storek */
48254879Storek void
scsi_targrel(self)48354879Storek scsi_targrel(self)
48454879Storek struct device *self;
48554879Storek {
48654879Storek register struct targ *t = (struct targ *)self;
48754879Storek register struct hba_softc *hba;
48854879Storek register struct sq *sq;
48954879Storek
49054879Storek hba = (struct hba_softc *)t->t_dev.dv_parent;
49154879Storek sq = t->t_head;
49254879Storek if (sq == NULL) panic("scsi_targrel");
49354879Storek /*
49454879Storek * This target is at the head of the hba queue.
49554879Storek * Remove it by calling hba bus release. Then, if the
49654879Storek * target queue is not empty, put it back on the hba queue.
49754879Storek * (This produces round robin service.)
49854879Storek */
49954879Storek (*hba->hba_driver->hd_rel)(&hba->hba_dev);
50054879Storek sq = sq->sq_forw;
50154879Storek if ((t->t_head = sq) != NULL)
50254879Storek (*hba->hba_driver->hd_start)(&hba->hba_dev, &t->t_forw,
50354879Storek sq->sq_bp, sq->sq_dgo, sq->sq_dev);
50454879Storek else
50554879Storek t->t_busy = 0;
50654879Storek }
507