xref: /original-bsd/sys/dev/scsi/scsi_subr.c (revision f713f486)
1578e4aefStorek /*
2*f713f486Sbostic  * Copyright (c) 1992, 1993
3*f713f486Sbostic  *	The Regents of the University of California.  All rights reserved.
4578e4aefStorek  *
5578e4aefStorek  * This software was developed by the Computer Systems Engineering group
6578e4aefStorek  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7578e4aefStorek  * contributed to Berkeley.
8578e4aefStorek  *
9aa64c26eStorek  * All advertising materials mentioning features or use of this software
10aa64c26eStorek  * must display the following acknowledgement:
11aa64c26eStorek  *	This product includes software developed by the University of
12aa64c26eStorek  *	California, Lawrence Berkeley Laboratories.
13aa64c26eStorek  *
14578e4aefStorek  * %sccs.include.redist.c%
15578e4aefStorek  *
16*f713f486Sbostic  *	@(#)scsi_subr.c	8.1 (Berkeley) 06/16/93
17578e4aefStorek  *
1872ccdcaeStorek  * from: $Header: scsi_subr.c,v 1.10 93/02/01 19:21:58 torek Exp $ (LBL)
19578e4aefStorek  */
20578e4aefStorek 
21578e4aefStorek /*
22578e4aefStorek  * Generic SCSI host adapter driver.
23578e4aefStorek  * Does almost nothing (most work is relegated to per-hba drivers).
24578e4aefStorek  */
25578e4aefStorek 
26aa64c26eStorek #include <sys/param.h>
27aa64c26eStorek #include <sys/buf.h>
28aa64c26eStorek #include <sys/device.h>
29aa64c26eStorek 
3017c4aa30Storek #include <dev/scsi/scsi.h>
3117c4aa30Storek #include <dev/scsi/scsivar.h>
32578e4aefStorek 
33578e4aefStorek /*
34578e4aefStorek  * General subroutines, and scsi data.
35578e4aefStorek  */
36578e4aefStorek 
37578e4aefStorek /* table of lengths of scsi commands */
38578e4aefStorek const char scsicmdlen[8] = { 6, 10, 0, 0, 0, 12, 0, 0 };
39578e4aefStorek 
40578e4aefStorek /* table of lengths of scsi messages */
41578e4aefStorek const signed char scsimsglen[0x24] = {
42578e4aefStorek 	SMLEN_DONE,		/* MSG_CMD_COMPLETE */
43578e4aefStorek 	SMLEN_EXTENDED,		/* MSG_EXT_MESSAGE */
44578e4aefStorek 	1,			/* MSG_SAVE_DATA_PTR */
45578e4aefStorek 	1,			/* MSG_RESTORE_PTR */
46578e4aefStorek 	1,			/* MSG_DISCONNECT */
47578e4aefStorek 	1,			/* MSG_INIT_DETECT_ERROR */
48578e4aefStorek 	1,			/* MSG_ABORT */
49578e4aefStorek 	1,			/* MSG_REJECT */
50578e4aefStorek 	1,			/* MSG_NOOP */
51578e4aefStorek 	1,			/* MSG_PARITY_ERROR */
52578e4aefStorek 	1,			/* MSG_LCC */
53578e4aefStorek 	1,			/* MSG_LCCF */
54578e4aefStorek 	1,			/* MSG_BUS_DEVICE_RESET */
55578e4aefStorek 	1,			/* MSG_ABORT_TAG */
56578e4aefStorek 	1,			/* MSG_CLEAR_QUEUE */
57578e4aefStorek 	1,			/* MSG_INITIATE_RECOVERY */
58578e4aefStorek 	1,			/* MSG_RELEASE_RECOVERY */
59578e4aefStorek 	1,			/* MSG_TERMINATE_PROCESS */
60578e4aefStorek 	SMLEN_UNDEF,		/* 0x12 */
61578e4aefStorek 	SMLEN_UNDEF,		/* 0x13 */
62578e4aefStorek 	SMLEN_UNDEF,		/* 0x14 */
63578e4aefStorek 	SMLEN_UNDEF,		/* 0x15 */
64578e4aefStorek 	SMLEN_UNDEF,		/* 0x16 */
65578e4aefStorek 	SMLEN_UNDEF,		/* 0x17 */
66578e4aefStorek 	SMLEN_UNDEF,		/* 0x18 */
67578e4aefStorek 	SMLEN_UNDEF,		/* 0x19 */
68578e4aefStorek 	SMLEN_UNDEF,		/* 0x1a */
69578e4aefStorek 	SMLEN_UNDEF,		/* 0x1b */
70578e4aefStorek 	SMLEN_UNDEF,		/* 0x1c */
71578e4aefStorek 	SMLEN_UNDEF,		/* 0x1d */
72578e4aefStorek 	SMLEN_UNDEF,		/* 0x1e */
73578e4aefStorek 	SMLEN_UNDEF,		/* 0x1f */
74578e4aefStorek 	2,			/* MSG_SIMPLE_QTAG */
75578e4aefStorek 	2,			/* MSG_HEAD_QTAG */
76578e4aefStorek 	2,			/* MSG_ORDERED_QTAG */
77578e4aefStorek 	2,			/* MSG_IGNORE_WIDE_RESID */
78578e4aefStorek };
79578e4aefStorek 
80578e4aefStorek /* definition of `tg' target driver for autoconfig */
81578e4aefStorek static int scsi_targmatch __P((struct device *, struct cfdata *, void *));
82578e4aefStorek static void scsi_targattach __P((struct device *, struct device *, void *));
83578e4aefStorek struct cfdriver tgcd =
84578e4aefStorek     { NULL, "tg", scsi_targmatch, scsi_targattach,
85578e4aefStorek       DV_DULL, sizeof(struct targ) };
86578e4aefStorek 
87578e4aefStorek void	scsi_targstart __P((struct device *, struct sq *, struct buf *,
88578e4aefStorek 			scdgo_fn, struct device *));
89578e4aefStorek int	scsi_targgo __P((struct device *, int targ,
90578e4aefStorek 			scintr_fn, struct device *, struct buf *, int));
91578e4aefStorek void	scsi_targintr __P((struct device *, int, int));
92578e4aefStorek void	scsi_targrel __P((struct device *));
93578e4aefStorek 
94578e4aefStorek #define	NOBUF	((caddr_t)0)
95578e4aefStorek 
96578e4aefStorek /*
97578e4aefStorek  * Perform a TEST UNIT READY immediate (polled) command
98578e4aefStorek  * on the given <target,unit> pair.  Return the status byte
99578e4aefStorek  * returned, or -1 for none.
100578e4aefStorek  */
101578e4aefStorek int
scsi_test_unit_ready(hba,targ,unit)102578e4aefStorek scsi_test_unit_ready(hba, targ, unit)
103578e4aefStorek 	struct hba_softc *hba;
104578e4aefStorek 	int targ, unit;
105578e4aefStorek {
106578e4aefStorek 	struct scsi_cdb cdb;
107578e4aefStorek 
108578e4aefStorek 	CDB6(&cdb)->cdb_cmd = CMD_TEST_UNIT_READY;
109578e4aefStorek 	CDB6(&cdb)->cdb_lun_lbah = unit << 5;
110578e4aefStorek 	*(short *)&CDB6(&cdb)->cdb_lbam = 0;
111578e4aefStorek 	*(short *)&CDB6(&cdb)->cdb_len = 0;
112578e4aefStorek 	return (hba->hba_driver->hd_icmd(hba, targ, &cdb, NOBUF, 0, 0));
113578e4aefStorek }
114578e4aefStorek 
115578e4aefStorek /*
116578e4aefStorek  * Request sense.  The sense is to be written into the given buffer.
117578e4aefStorek  * The given length must be < 256.
118578e4aefStorek  */
119578e4aefStorek int
scsi_request_sense(hba,targ,unit,buf,len)120578e4aefStorek scsi_request_sense(hba, targ, unit, buf, len)
121578e4aefStorek 	struct hba_softc *hba;
122578e4aefStorek 	int targ, unit;
123578e4aefStorek 	caddr_t buf;
124578e4aefStorek 	int len;
125578e4aefStorek {
126578e4aefStorek 	struct scsi_cdb cdb;
127578e4aefStorek 
128578e4aefStorek 	CDB6(&cdb)->cdb_cmd = CMD_REQUEST_SENSE;
129578e4aefStorek 	CDB6(&cdb)->cdb_lun_lbah = unit << 5;
130578e4aefStorek 	*(short *)&CDB6(&cdb)->cdb_lbam = 0;
131578e4aefStorek 	CDB6(&cdb)->cdb_len = len;
132578e4aefStorek 	CDB6(&cdb)->cdb_ctrl = 0;
133578e4aefStorek 	return (hba->hba_driver->hd_icmd(hba, targ, &cdb, buf, len, B_READ));
134578e4aefStorek }
135578e4aefStorek 
136578e4aefStorek /*
137578e4aefStorek  * Called (indirectly, via config_found) from scsi_hbaattach.
138578e4aefStorek  * Print target number, and if no device was configured there,
139578e4aefStorek  * the hba as well.
140578e4aefStorek  */
141578e4aefStorek int
scsi_targprint(aux,hba)142578e4aefStorek scsi_targprint(aux, hba)
143578e4aefStorek 	void *aux;
144578e4aefStorek 	char *hba;
145578e4aefStorek {
146578e4aefStorek 
147578e4aefStorek 	if (hba) {
148578e4aefStorek 		printf("target %d on %s", *(int *)aux, hba);
149578e4aefStorek 		return (UNCONF);
150578e4aefStorek 	}
151578e4aefStorek 	printf(" target %d", *(int *)aux);
152578e4aefStorek 	return (QUIET);
153578e4aefStorek }
154578e4aefStorek 
155578e4aefStorek /*
156578e4aefStorek  * Print information about a unit found on some target.
157578e4aefStorek  * If the unit was not configured, `targ' is the name of the target
158578e4aefStorek  * on which the unit was found.  If it was, targ is NULL and we
159578e4aefStorek  * let the unit's attach routine print the INQUIRE result if
160578e4aefStorek  * appropriate.
161578e4aefStorek  */
162578e4aefStorek static int
scsi_unitprint(aux,targ)163578e4aefStorek scsi_unitprint(aux, targ)
164578e4aefStorek 	void *aux;
165578e4aefStorek 	char *targ;
166578e4aefStorek {
167578e4aefStorek 	register struct scsi_attach_args *sa = aux;
168578e4aefStorek 
169578e4aefStorek 	if (targ) {
170578e4aefStorek 		printf("unit %d at %s", sa->sa_unit, targ);
171578e4aefStorek 		if ((sa->sa_inq_status & STS_MASK) == STS_GOOD) {
172578e4aefStorek 			printf(" (");
173578e4aefStorek 			scsi_printinq(&sa->sa_si);
174578e4aefStorek 			printf(")");
175578e4aefStorek 		}
176578e4aefStorek 		return (UNCONF);
177578e4aefStorek 	}
178578e4aefStorek 	printf(" unit %d", sa->sa_unit);
179578e4aefStorek 	return (QUIET);
180578e4aefStorek }
181578e4aefStorek 
182578e4aefStorek /*
183578e4aefStorek  * Generic target-match.
184578e4aefStorek  */
185578e4aefStorek static int
scsi_targmatch(parent,cf,aux)186578e4aefStorek scsi_targmatch(parent, cf, aux)
187578e4aefStorek 	struct device *parent;
188578e4aefStorek 	register struct cfdata *cf;
189578e4aefStorek 	void *aux;
190578e4aefStorek {
191578e4aefStorek 	int targ = *(int *)aux;
192578e4aefStorek 
193578e4aefStorek 	return (cf->cf_loc[0] == targ || cf->cf_loc[0] == -1);
194578e4aefStorek }
195578e4aefStorek 
196578e4aefStorek /*
197578e4aefStorek  * And now, a generic `target attach' routine.
198578e4aefStorek  * We assume that INQUIRY works.
199578e4aefStorek  */
200578e4aefStorek static void
scsi_targattach(parent,self,aux)201578e4aefStorek scsi_targattach(parent, self, aux)
202578e4aefStorek 	struct device *parent, *self;
203578e4aefStorek 	void *aux;
204578e4aefStorek {
205578e4aefStorek 	register struct targ *t = (struct targ *)self;
206578e4aefStorek 	register struct hba_softc *hba;
207578e4aefStorek 	register struct hbadriver *hd;
208578e4aefStorek 	register int targ, unit;
209578e4aefStorek 	struct scsi_attach_args sa;
210578e4aefStorek 	struct scsi_cdb si;
211578e4aefStorek 
212578e4aefStorek 	printf("\n");
213578e4aefStorek 	t->t_targ = targ = *(int *)aux;
214578e4aefStorek 	hba = (struct hba_softc *)parent;
215578e4aefStorek 	hba->hba_targets[targ] = t;
216578e4aefStorek 
217578e4aefStorek 	/*
218578e4aefStorek 	 * Probe each of the 8 units using the sequence
219578e4aefStorek 	 *	TEST UNIT READY
220578e4aefStorek 	 *	REQUEST SENSE
221578e4aefStorek 	 *	INQUIRY
222578e4aefStorek 	 * The first should not be necessary, but some SCSI devices
223578e4aefStorek 	 * refuse to speak until it is done.  The second is only necessary
224578e4aefStorek 	 * if the first returns a CHECK CONDITION status, but we do it
225578e4aefStorek 	 * anyway.
226578e4aefStorek 	 */
227578e4aefStorek 	hd = hba->hba_driver;
228578e4aefStorek 	sa.sa_targ = targ;
229578e4aefStorek 	CDB6(&si)->cdb_cmd = CMD_INQUIRY;
230578e4aefStorek 	*(short *)&CDB6(&si)->cdb_lbam = 0;
231578e4aefStorek 	CDB6(&si)->cdb_len = sizeof sa.sa_si;
232578e4aefStorek 	CDB6(&si)->cdb_ctrl = 0;
233578e4aefStorek 	for (unit = 0; unit < 8; unit++) {
234578e4aefStorek 		if (scsi_test_unit_ready(hba, targ, unit) == -1)
235578e4aefStorek 			continue;
236578e4aefStorek 		sa.sa_unit = unit;
237578e4aefStorek 		sa.sa_req_status = scsi_request_sense(hba, targ, unit,
238578e4aefStorek 		    (caddr_t)&sa.sa_sn, sizeof sa.sa_sn);
239578e4aefStorek 		CDB6(&si)->cdb_lun_lbah = unit << 5;
240578e4aefStorek 		sa.sa_inq_status = (*hd->hd_icmd)(hba, targ, &si,
241578e4aefStorek 		    (caddr_t)&sa.sa_si, sizeof sa.sa_si, B_READ);
242578e4aefStorek 		if ((sa.sa_inq_status & STS_MASK) == STS_GOOD &&
243578e4aefStorek #ifdef notdef /* XXX don't know if this is a reasonable test */
244578e4aefStorek 		    (sa.sa_si.si_type & TYPE_QUAL_MASK) == TYPE_QUAL_NOTCONN &&
245578e4aefStorek #endif
246578e4aefStorek 		    (sa.sa_si.si_type & TYPE_TYPE_MASK) == TYPE_NP) {
247578e4aefStorek 			continue;
248578e4aefStorek 		}
249578e4aefStorek 		config_found(&t->t_dev, (void *)&sa, scsi_unitprint);
250578e4aefStorek 	}
251578e4aefStorek }
252578e4aefStorek 
253578e4aefStorek /*
254578e4aefStorek  * Each unit calls scsi_establish to tell the hba and target of
255578e4aefStorek  * its existence.
256578e4aefStorek  */
257578e4aefStorek void
scsi_establish(u,dev,unit)258578e4aefStorek scsi_establish(u, dev, unit)
259578e4aefStorek 	register struct unit *u;
260578e4aefStorek 	struct device *dev;
261578e4aefStorek 	register int unit;
262578e4aefStorek {
263578e4aefStorek 	register struct targ *t;
264578e4aefStorek 	register struct hba_softc *hba;
265578e4aefStorek 	register struct hbadriver *hbd;
266578e4aefStorek 
267578e4aefStorek 	u->u_dev = dev;
268578e4aefStorek 	t = (struct targ *)dev->dv_parent;
269578e4aefStorek 	hba = (struct hba_softc *)t->t_dev.dv_parent;
270578e4aefStorek 	hbd = hba->hba_driver;
271578e4aefStorek 	t->t_units[unit] = u;
272578e4aefStorek 	if (t->t_nunits == 0) {
273578e4aefStorek 		/*
274578e4aefStorek 		 * This is the first unit on the target.  We can
275578e4aefStorek 		 * probably just call the hba start code, avoiding
276578e4aefStorek 		 * one level of calls and queueing.  If we attach
277578e4aefStorek 		 * another target we will fix this in the code below.
278578e4aefStorek 		 */
279578e4aefStorek 		u->u_start = hbd->hd_start;
280578e4aefStorek 		u->u_go = hbd->hd_go;
281578e4aefStorek 		u->u_rel = hbd->hd_rel;
282578e4aefStorek 		u->u_updev = &hba->hba_dev;
283578e4aefStorek 		t->t_firstunit = unit;
284578e4aefStorek 	} else {
285578e4aefStorek 		/*
286578e4aefStorek 		 * This is not the only unit on the target, so we
287578e4aefStorek 		 * must call the target start code rather than the
288578e4aefStorek 		 * hba start code.  Fix the linkage on the first
289578e4aefStorek 		 * target too (possibly for the 2nd, 3rd, ..., time).
290578e4aefStorek 		 */
291578e4aefStorek 		t->t_units[t->t_firstunit]->u_start = scsi_targstart;
292a555ad07Smckusick 		t->t_units[t->t_firstunit]->u_go = scsi_targgo;
293a555ad07Smckusick 		t->t_units[t->t_firstunit]->u_rel = scsi_targrel;
294578e4aefStorek 		t->t_units[t->t_firstunit]->u_updev = &t->t_dev;
295578e4aefStorek 		u->u_start = scsi_targstart;
296578e4aefStorek 		u->u_go = scsi_targgo;
297578e4aefStorek 		u->u_rel = scsi_targrel;
298578e4aefStorek 		u->u_updev = &t->t_dev;
299578e4aefStorek 	}
300578e4aefStorek 	t->t_nunits++;			/* another unit is alive */
301578e4aefStorek 	u->u_unit = unit;
302578e4aefStorek 	u->u_targ = t->t_targ;		/* record target number, */
303578e4aefStorek 	u->u_hba = hba;			/* hba ... */
304578e4aefStorek 	u->u_hbd = hbd;			/* and driver */
305578e4aefStorek }
306578e4aefStorek 
307578e4aefStorek /* NO DOUBT SOME OF THE STUFF PRINTED HERE IS USELESS */
308578e4aefStorek void
scsi_printinq(inq)309578e4aefStorek scsi_printinq(inq)
310578e4aefStorek 	register struct scsi_inquiry *inq;
311578e4aefStorek {
312578e4aefStorek 	register int iso, ecma, ansi, t;
313578e4aefStorek 	static char *types[] = { "disk", "tape", "printer", "processor",
314578e4aefStorek 	    "WORM", "ROM disk", "scanner", "magneto-optical",
315578e4aefStorek 	    "jukebox", "lan" };
316578e4aefStorek 
317578e4aefStorek 	if ((t = (inq->si_type & TYPE_QUAL_MASK)) != 0)
318578e4aefStorek 		printf("type-qual=0x%x ", t);
319578e4aefStorek 	t = inq->si_type & TYPE_TYPE_MASK;
320578e4aefStorek 	if (t < sizeof types / sizeof *types)
321578e4aefStorek 		printf("%s", types[t]);
322578e4aefStorek 	else
323578e4aefStorek 		printf("<type %d>", t);
324578e4aefStorek 	if (inq->si_qual & QUAL_RMB)
325578e4aefStorek 		printf(" (removable)");
326578e4aefStorek 	printf(" qual=0x%x", inq->si_qual & QUAL_MASK);
327578e4aefStorek 	iso = (inq->si_qual >> VER_ISO_SHIFT) & VER_ISO_MASK;
328578e4aefStorek 	ecma = (inq->si_qual >> VER_ECMA_SHIFT) & VER_ECMA_MASK;
329578e4aefStorek 	ansi = (inq->si_qual >> VER_ANSI_SHIFT) & VER_ANSI_MASK;
330578e4aefStorek 	printf(" version=<iso %d, ecma %d, ansi %d>", iso, ecma, ansi);
331578e4aefStorek 	if (ansi == 1 || ansi == 2) {
332578e4aefStorek 		char v[9], p[17], r[5];
333578e4aefStorek 
334578e4aefStorek 		scsi_inq_ansi((struct scsi_inq_ansi *)inq, v, p, r);
335578e4aefStorek 		printf(" vendor %s, product %s, rev %s", v, p, r);
336578e4aefStorek 	}
337578e4aefStorek }
338578e4aefStorek 
339578e4aefStorek /* copy a counted string but trim trailing blanks; make the dest a C string */
340578e4aefStorek static void
scsi_str(src,dst,len)341578e4aefStorek scsi_str(src, dst, len)
342578e4aefStorek 	register char *src, *dst;
343578e4aefStorek 	register int len;
344578e4aefStorek {
345578e4aefStorek 
346578e4aefStorek 	while (src[len - 1] == ' ') {
347578e4aefStorek 		if (--len == 0) {
348578e4aefStorek 			*dst = 0;
349578e4aefStorek 			return;
350578e4aefStorek 		}
351578e4aefStorek 	}
352578e4aefStorek 	bcopy(src, dst, len);
353578e4aefStorek 	dst[len] = 0;
354578e4aefStorek }
355578e4aefStorek 
356578e4aefStorek void
scsi_inq_ansi(si,vendor,product,rev)357578e4aefStorek scsi_inq_ansi(si, vendor, product, rev)
358578e4aefStorek 	register struct scsi_inq_ansi *si;
359578e4aefStorek 	char *vendor, *product, *rev;
360578e4aefStorek {
361578e4aefStorek 	register int i, len;
362578e4aefStorek 
363578e4aefStorek 	/* if too short, extend with blanks */
364578e4aefStorek 	len = si->si_len + 5;	/* 5 fixed; len is `additional' */
365578e4aefStorek 	if (len < sizeof(*si))
366578e4aefStorek 		for (i = len; i < sizeof *si; i++)
367578e4aefStorek 			((char *)si)[i] = ' ';
368578e4aefStorek 	scsi_str(si->si_vendor, vendor, sizeof si->si_vendor);
369578e4aefStorek 	scsi_str(si->si_product, product, sizeof si->si_product);
370578e4aefStorek 	scsi_str(si->si_rev, rev, sizeof si->si_rev);
371578e4aefStorek }
372578e4aefStorek 
373578e4aefStorek /*
374578e4aefStorek  * Tell all the devices on the given hba that it has been reset.
375578e4aefStorek  * SHOULD PROBABLY DO MORE HERE
376578e4aefStorek  */
377578e4aefStorek void
scsi_reset_units(hba)378578e4aefStorek scsi_reset_units(hba)
379578e4aefStorek 	register struct hba_softc *hba;
380578e4aefStorek {
381578e4aefStorek 	register int targ, unit;
382578e4aefStorek 	register struct targ *t;
383578e4aefStorek 	register struct unit *u;
384578e4aefStorek 
385578e4aefStorek 	for (targ = 0; targ < 8; targ++) {
386578e4aefStorek 		if ((t = hba->hba_targets[targ]) == NULL)
387578e4aefStorek 			continue;
388578e4aefStorek 		for (unit = 0; unit < 8; unit++)
389578e4aefStorek 			if ((u = t->t_units[unit]) != NULL)
390578e4aefStorek 				(*u->u_driver->ud_reset)(u);
391578e4aefStorek 	}
392578e4aefStorek }
393578e4aefStorek 
394578e4aefStorek /*
395578e4aefStorek  * Start a unit on a target.
396578e4aefStorek  * If the target is busy, just enqueue the unit;
397578e4aefStorek  * once the target becomes free, we will call the hba start routine.
398578e4aefStorek  * Otherwise, call the hba start routine now, and then when the hba
399578e4aefStorek  * becomes free it will call the unit's dgo routine.
400578e4aefStorek  */
401578e4aefStorek void
scsi_targstart(self,sq,bp,dgo,dev)402578e4aefStorek scsi_targstart(self, sq, bp, dgo, dev)
403578e4aefStorek 	struct device *self;
404578e4aefStorek 	register struct sq *sq;
405578e4aefStorek 	struct buf *bp;
406578e4aefStorek 	scdgo_fn dgo;
407578e4aefStorek 	struct device *dev;
408578e4aefStorek {
409578e4aefStorek 	register struct targ *t = (struct targ *)self;
410578e4aefStorek 	register struct hba_softc *hba;
411578e4aefStorek 
412578e4aefStorek 	sq->sq_forw = NULL;
413578e4aefStorek 	if (t->t_head == NULL)
414578e4aefStorek 		t->t_head = sq;
415578e4aefStorek 	else
416578e4aefStorek 		t->t_tail->sq_forw = sq;
417578e4aefStorek 	t->t_tail = sq;
418578e4aefStorek 	if (t->t_busy == 0) {
419578e4aefStorek 		t->t_busy = 1;
420578e4aefStorek 		hba = (struct hba_softc *)t->t_dev.dv_parent;
421578e4aefStorek 		(*hba->hba_driver->hd_start)(&hba->hba_dev, &t->t_forw, bp,
422578e4aefStorek 		    dgo, dev);
423578e4aefStorek 	} else {
424578e4aefStorek 		sq->sq_bp = bp;
425578e4aefStorek 		sq->sq_dgo = dgo;
426578e4aefStorek 		sq->sq_dev = dev;
427578e4aefStorek 	}
428578e4aefStorek }
429578e4aefStorek 
430578e4aefStorek /*
431578e4aefStorek  * The unit got the bus, and wants the hba to go.
432578e4aefStorek  * Remember its interrupt handler; substitute ours instead.
433578e4aefStorek  */
434578e4aefStorek int
scsi_targgo(self,targ,intr,dev,bp,pad)435578e4aefStorek scsi_targgo(self, targ, intr, dev, bp, pad)
436578e4aefStorek 	struct device *self;
437578e4aefStorek 	int targ;
438578e4aefStorek 	scintr_fn intr;
439578e4aefStorek 	struct device *dev;
440578e4aefStorek 	struct buf *bp;
441578e4aefStorek 	int pad;
442578e4aefStorek {
443578e4aefStorek 	register struct targ *t = (struct targ *)self;
444578e4aefStorek 	register struct hba_softc *hba;
445578e4aefStorek 
446578e4aefStorek 	t->t_intr = intr;
447578e4aefStorek 	t->t_intrdev = dev;
448578e4aefStorek 	hba = (struct hba_softc *)t->t_dev.dv_parent;
449578e4aefStorek 	return ((*hba->hba_driver->hd_go)(&hba->hba_dev, targ,
450578e4aefStorek 	    scsi_targintr, &t->t_dev, bp, pad));
451578e4aefStorek }
452578e4aefStorek 
453578e4aefStorek /*
454578e4aefStorek  * The hba got an interrupt.  Dequeue the unit from the target
455578e4aefStorek  * (the target is already off the hba queue) and then call the
456578e4aefStorek  * underlying interrupt handler.
457578e4aefStorek  */
458578e4aefStorek void
scsi_targintr(self,stat,resid)459578e4aefStorek scsi_targintr(self, stat, resid)
460578e4aefStorek 	struct device *self;
461578e4aefStorek 	int stat, resid;
462578e4aefStorek {
463578e4aefStorek 	register struct targ *t = (struct targ *)self;
464578e4aefStorek 	register struct hba_softc *hba;
465578e4aefStorek 	register struct sq *sq;
466578e4aefStorek 
467578e4aefStorek 	sq = t->t_head;
468578e4aefStorek if (sq == NULL) panic("scsi_targintr");
469578e4aefStorek 	t->t_head = sq = sq->sq_forw;
470578e4aefStorek 	(*t->t_intr)(t->t_intrdev, stat, resid);
471578e4aefStorek 	if (sq != NULL) {
472578e4aefStorek 		hba = (struct hba_softc *)t->t_dev.dv_parent;
473578e4aefStorek 		(*hba->hba_driver->hd_start)(&hba->hba_dev, &t->t_forw,
474578e4aefStorek 		    sq->sq_bp, sq->sq_dgo, sq->sq_dev);
475578e4aefStorek 	} else
476578e4aefStorek 		t->t_busy = 0;
477578e4aefStorek }
478578e4aefStorek 
479578e4aefStorek /*
480578e4aefStorek  * The unit decided that it needed to `give up' its hold on the bus early.
481578e4aefStorek  */
482578e4aefStorek void
scsi_targrel(self)483578e4aefStorek scsi_targrel(self)
484578e4aefStorek 	struct device *self;
485578e4aefStorek {
486578e4aefStorek 	register struct targ *t = (struct targ *)self;
487578e4aefStorek 	register struct hba_softc *hba;
488578e4aefStorek 	register struct sq *sq;
489578e4aefStorek 
490578e4aefStorek 	hba = (struct hba_softc *)t->t_dev.dv_parent;
491578e4aefStorek 	sq = t->t_head;
492578e4aefStorek if (sq == NULL) panic("scsi_targrel");
493578e4aefStorek 	/*
494578e4aefStorek 	 * This target is at the head of the hba queue.
495578e4aefStorek 	 * Remove it by calling hba bus release.  Then, if the
496578e4aefStorek 	 * target queue is not empty, put it back on the hba queue.
497578e4aefStorek 	 * (This produces round robin service.)
498578e4aefStorek 	 */
499578e4aefStorek 	(*hba->hba_driver->hd_rel)(&hba->hba_dev);
500578e4aefStorek 	sq = sq->sq_forw;
501578e4aefStorek 	if ((t->t_head = sq) != NULL)
502578e4aefStorek 		(*hba->hba_driver->hd_start)(&hba->hba_dev, &t->t_forw,
503578e4aefStorek 		    sq->sq_bp, sq->sq_dgo, sq->sq_dev);
504578e4aefStorek 	else
505578e4aefStorek 		t->t_busy = 0;
506578e4aefStorek }
507