xref: /plan9/sys/src/cmd/cwfs/scsi.c (revision 01a344a29f2ff35133953eaef092a50fc8c3163b)
1*01a344a2SDavid du Colombier /*
2*01a344a2SDavid du Colombier  * interface to scsi devices via scsi(2) to sd(3),
3*01a344a2SDavid du Colombier  * which does not implement LUNs.
4*01a344a2SDavid du Colombier  */
5*01a344a2SDavid du Colombier #include "all.h"
6*01a344a2SDavid du Colombier #include "io.h"
7*01a344a2SDavid du Colombier 
8*01a344a2SDavid du Colombier enum {
9*01a344a2SDavid du Colombier 	Ninquiry	= 255,
10*01a344a2SDavid du Colombier 	Nsense		= 255,
11*01a344a2SDavid du Colombier 
12*01a344a2SDavid du Colombier 	CMDtest		= 0x00,
13*01a344a2SDavid du Colombier 	CMDreqsense	= 0x03,
14*01a344a2SDavid du Colombier 	CMDread6	= 0x08,
15*01a344a2SDavid du Colombier 	CMDwrite6	= 0x0A,
16*01a344a2SDavid du Colombier 	CMDinquiry	= 0x12,
17*01a344a2SDavid du Colombier 	CMDstart	= 0x1B,
18*01a344a2SDavid du Colombier 	CMDread10	= 0x28,
19*01a344a2SDavid du Colombier 	CMDwrite10	= 0x2A,
20*01a344a2SDavid du Colombier };
21*01a344a2SDavid du Colombier 
22*01a344a2SDavid du Colombier typedef struct {
23*01a344a2SDavid du Colombier 	Target	target[NTarget];
24*01a344a2SDavid du Colombier } Ctlr;
25*01a344a2SDavid du Colombier static Ctlr scsictlr[MaxScsi];
26*01a344a2SDavid du Colombier 
27*01a344a2SDavid du Colombier extern int scsiverbose;
28*01a344a2SDavid du Colombier 
29*01a344a2SDavid du Colombier void
scsiinit(void)30*01a344a2SDavid du Colombier scsiinit(void)
31*01a344a2SDavid du Colombier {
32*01a344a2SDavid du Colombier 	Ctlr *ctlr;
33*01a344a2SDavid du Colombier 	int ctlrno, targetno;
34*01a344a2SDavid du Colombier 	Target *tp;
35*01a344a2SDavid du Colombier 
36*01a344a2SDavid du Colombier 	scsiverbose = 1;
37*01a344a2SDavid du Colombier 	for(ctlrno = 0; ctlrno < MaxScsi; ctlrno++){
38*01a344a2SDavid du Colombier 		ctlr = &scsictlr[ctlrno];
39*01a344a2SDavid du Colombier 		memset(ctlr, 0, sizeof(Ctlr));
40*01a344a2SDavid du Colombier 		for(targetno = 0; targetno < NTarget; targetno++){
41*01a344a2SDavid du Colombier 			tp = &ctlr->target[targetno];
42*01a344a2SDavid du Colombier 
43*01a344a2SDavid du Colombier 			qlock(tp);
44*01a344a2SDavid du Colombier 			qunlock(tp);
45*01a344a2SDavid du Colombier 			sprint(tp->id, "scsictlr#%d.%d", ctlrno, targetno);
46*01a344a2SDavid du Colombier 
47*01a344a2SDavid du Colombier 			tp->ctlrno = ctlrno;
48*01a344a2SDavid du Colombier 			tp->targetno = targetno;
49*01a344a2SDavid du Colombier 			tp->inquiry = malloc(Ninquiry);
50*01a344a2SDavid du Colombier 			tp->sense = malloc(Nsense);
51*01a344a2SDavid du Colombier 		}
52*01a344a2SDavid du Colombier 	}
53*01a344a2SDavid du Colombier }
54*01a344a2SDavid du Colombier 
55*01a344a2SDavid du Colombier static uchar lastcmd[16];
56*01a344a2SDavid du Colombier static int lastcmdsz;
57*01a344a2SDavid du Colombier 
58*01a344a2SDavid du Colombier static int
sense2stcode(uchar * sense)59*01a344a2SDavid du Colombier sense2stcode(uchar *sense)
60*01a344a2SDavid du Colombier {
61*01a344a2SDavid du Colombier 	switch(sense[2] & 0x0F){
62*01a344a2SDavid du Colombier 	case 6:						/* unit attention */
63*01a344a2SDavid du Colombier 		/*
64*01a344a2SDavid du Colombier 		 * 0x28 - not ready to ready transition,
65*01a344a2SDavid du Colombier 		 *	  medium may have changed.
66*01a344a2SDavid du Colombier 		 * 0x29 - power on, RESET or BUS DEVICE RESET occurred.
67*01a344a2SDavid du Colombier 		 */
68*01a344a2SDavid du Colombier 		if(sense[12] != 0x28 && sense[12] != 0x29)
69*01a344a2SDavid du Colombier 			return STcheck;
70*01a344a2SDavid du Colombier 		/*FALLTHROUGH*/
71*01a344a2SDavid du Colombier 	case 0:						/* no sense */
72*01a344a2SDavid du Colombier 	case 1:						/* recovered error */
73*01a344a2SDavid du Colombier 		return STok;
74*01a344a2SDavid du Colombier 	case 8:						/* blank data */
75*01a344a2SDavid du Colombier 		return STblank;
76*01a344a2SDavid du Colombier 	case 2:						/* not ready */
77*01a344a2SDavid du Colombier 		if(sense[12] == 0x3A)			/* medium not present */
78*01a344a2SDavid du Colombier 			return STcheck;
79*01a344a2SDavid du Colombier 		/*FALLTHROUGH*/
80*01a344a2SDavid du Colombier 	default:
81*01a344a2SDavid du Colombier 		/*
82*01a344a2SDavid du Colombier 		 * If unit is becoming ready, rather than not ready,
83*01a344a2SDavid du Colombier 		 * then wait a little then poke it again; should this
84*01a344a2SDavid du Colombier 		 * be here or in the caller?
85*01a344a2SDavid du Colombier 		 */
86*01a344a2SDavid du Colombier 		if((sense[12] == 0x04 && sense[13] == 0x01)) {
87*01a344a2SDavid du Colombier 			// delay(500);
88*01a344a2SDavid du Colombier 			// scsitest(tp, lun);
89*01a344a2SDavid du Colombier 			fprint(2, "sense2stcode: unit becoming ready\n");
90*01a344a2SDavid du Colombier 			return STcheck;			/* not exactly right */
91*01a344a2SDavid du Colombier 		}
92*01a344a2SDavid du Colombier 		return STcheck;
93*01a344a2SDavid du Colombier 	}
94*01a344a2SDavid du Colombier }
95*01a344a2SDavid du Colombier 
96*01a344a2SDavid du Colombier /*
97*01a344a2SDavid du Colombier  * issue the SCSI command via scsi(2).  lun must already be in cmd[1].
98*01a344a2SDavid du Colombier  */
99*01a344a2SDavid du Colombier static int
doscsi(Target * tp,int rw,uchar * cmd,int cbytes,void * data,int * dbytes)100*01a344a2SDavid du Colombier doscsi(Target* tp, int rw, uchar* cmd, int cbytes, void* data, int* dbytes)
101*01a344a2SDavid du Colombier {
102*01a344a2SDavid du Colombier 	int lun, db = 0;
103*01a344a2SDavid du Colombier 	uchar reqcmd[6], reqdata[Nsense], dummy[1];
104*01a344a2SDavid du Colombier 	Scsi *sc;
105*01a344a2SDavid du Colombier 
106*01a344a2SDavid du Colombier 	sc = tp->sc;
107*01a344a2SDavid du Colombier 	if (sc == nil)
108*01a344a2SDavid du Colombier 		panic("doscsi: nil tp->sc");
109*01a344a2SDavid du Colombier 	lun = cmd[1] >> 5;	/* save lun in case we need it for reqsense */
110*01a344a2SDavid du Colombier 
111*01a344a2SDavid du Colombier 	/* cope with zero arguments */
112*01a344a2SDavid du Colombier 	if (dbytes != nil)
113*01a344a2SDavid du Colombier 		db = *dbytes;
114*01a344a2SDavid du Colombier 	if (data == nil)
115*01a344a2SDavid du Colombier 		data = dummy;
116*01a344a2SDavid du Colombier 
117*01a344a2SDavid du Colombier 	if (scsi(sc, cmd, cbytes, data, db, rw) >= 0)
118*01a344a2SDavid du Colombier 		return STok;
119*01a344a2SDavid du Colombier 
120*01a344a2SDavid du Colombier 	/* cmd failed, get whatever sense data we can */
121*01a344a2SDavid du Colombier 	memset(reqcmd, 0, sizeof reqcmd);
122*01a344a2SDavid du Colombier 	reqcmd[0] = CMDreqsense;
123*01a344a2SDavid du Colombier 	reqcmd[1] = lun<<5;
124*01a344a2SDavid du Colombier 	reqcmd[4] = Nsense;
125*01a344a2SDavid du Colombier 	memset(reqdata, 0, sizeof reqdata);
126*01a344a2SDavid du Colombier 	if (scsicmd(sc, reqcmd, sizeof reqcmd, reqdata, sizeof reqdata,
127*01a344a2SDavid du Colombier 	    Sread) < 0)
128*01a344a2SDavid du Colombier 		return STharderr;
129*01a344a2SDavid du Colombier 
130*01a344a2SDavid du Colombier 	/* translate sense data to ST* codes */
131*01a344a2SDavid du Colombier 	return sense2stcode(reqdata);
132*01a344a2SDavid du Colombier }
133*01a344a2SDavid du Colombier 
134*01a344a2SDavid du Colombier static int
scsiexec(Target * tp,int rw,uchar * cmd,int cbytes,void * data,int * dbytes)135*01a344a2SDavid du Colombier scsiexec(Target* tp, int rw, uchar* cmd, int cbytes, void* data, int* dbytes)
136*01a344a2SDavid du Colombier {
137*01a344a2SDavid du Colombier 	int s;
138*01a344a2SDavid du Colombier 
139*01a344a2SDavid du Colombier 	/*
140*01a344a2SDavid du Colombier 	 * issue the SCSI command.  lun must already be in cmd[1].
141*01a344a2SDavid du Colombier 	 */
142*01a344a2SDavid du Colombier 	s = doscsi(tp, rw, cmd, cbytes, data, dbytes);
143*01a344a2SDavid du Colombier 	switch(s){
144*01a344a2SDavid du Colombier 
145*01a344a2SDavid du Colombier 	case STcheck:
146*01a344a2SDavid du Colombier 		memmove(lastcmd, cmd, cbytes);
147*01a344a2SDavid du Colombier 		lastcmdsz = cbytes;
148*01a344a2SDavid du Colombier 		/*FALLTHROUGH*/
149*01a344a2SDavid du Colombier 
150*01a344a2SDavid du Colombier 	default:
151*01a344a2SDavid du Colombier 		/*
152*01a344a2SDavid du Colombier 		 * It's more complicated than this.  There are conditions which
153*01a344a2SDavid du Colombier 		 * are 'ok' but for which the returned status code is not 'STok'.
154*01a344a2SDavid du Colombier 		 * Also, not all conditions require a reqsense, there may be a
155*01a344a2SDavid du Colombier 		 * need to do a reqsense here when necessary and making it
156*01a344a2SDavid du Colombier 		 * available to the caller somehow.
157*01a344a2SDavid du Colombier 		 *
158*01a344a2SDavid du Colombier 		 * Later.
159*01a344a2SDavid du Colombier 		 */
160*01a344a2SDavid du Colombier 		break;
161*01a344a2SDavid du Colombier 	}
162*01a344a2SDavid du Colombier 
163*01a344a2SDavid du Colombier 	return s;
164*01a344a2SDavid du Colombier }
165*01a344a2SDavid du Colombier 
166*01a344a2SDavid du Colombier static int
scsitest(Target * tp,char lun)167*01a344a2SDavid du Colombier scsitest(Target* tp, char lun)
168*01a344a2SDavid du Colombier {
169*01a344a2SDavid du Colombier 	uchar cmd[6];
170*01a344a2SDavid du Colombier 
171*01a344a2SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
172*01a344a2SDavid du Colombier 	cmd[0] = CMDtest;
173*01a344a2SDavid du Colombier 	cmd[1] = lun<<5;
174*01a344a2SDavid du Colombier 	return scsiexec(tp, SCSIread, cmd, sizeof cmd, 0, 0);
175*01a344a2SDavid du Colombier 
176*01a344a2SDavid du Colombier }
177*01a344a2SDavid du Colombier 
178*01a344a2SDavid du Colombier static int
scsistart(Target * tp,char lun,int start)179*01a344a2SDavid du Colombier scsistart(Target* tp, char lun, int start)
180*01a344a2SDavid du Colombier {
181*01a344a2SDavid du Colombier 	uchar cmd[6];
182*01a344a2SDavid du Colombier 
183*01a344a2SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
184*01a344a2SDavid du Colombier 	cmd[0] = CMDstart;
185*01a344a2SDavid du Colombier 	cmd[1] = lun<<5;
186*01a344a2SDavid du Colombier 	if(start)
187*01a344a2SDavid du Colombier 		cmd[4] = 1;
188*01a344a2SDavid du Colombier 	return scsiexec(tp, SCSIread, cmd, sizeof cmd, 0, 0);
189*01a344a2SDavid du Colombier }
190*01a344a2SDavid du Colombier 
191*01a344a2SDavid du Colombier static int
scsiinquiry(Target * tp,char lun,int * nbytes)192*01a344a2SDavid du Colombier scsiinquiry(Target* tp, char lun, int* nbytes)
193*01a344a2SDavid du Colombier {
194*01a344a2SDavid du Colombier 	uchar cmd[6];
195*01a344a2SDavid du Colombier 
196*01a344a2SDavid du Colombier 	memset(cmd, 0, sizeof cmd);
197*01a344a2SDavid du Colombier 	cmd[0] = CMDinquiry;
198*01a344a2SDavid du Colombier 	cmd[1] = lun<<5;
199*01a344a2SDavid du Colombier 	*nbytes = Ninquiry;
200*01a344a2SDavid du Colombier 	cmd[4] = *nbytes;
201*01a344a2SDavid du Colombier 	return scsiexec(tp, SCSIread, cmd, sizeof cmd, tp->inquiry, nbytes);
202*01a344a2SDavid du Colombier }
203*01a344a2SDavid du Colombier 
204*01a344a2SDavid du Colombier static char *key[] =
205*01a344a2SDavid du Colombier {
206*01a344a2SDavid du Colombier 	"no sense",
207*01a344a2SDavid du Colombier 	"recovered error",
208*01a344a2SDavid du Colombier 	"not ready",
209*01a344a2SDavid du Colombier 	"medium error",
210*01a344a2SDavid du Colombier 	"hardware error",
211*01a344a2SDavid du Colombier 	"illegal request",
212*01a344a2SDavid du Colombier 	"unit attention",
213*01a344a2SDavid du Colombier 	"data protect",
214*01a344a2SDavid du Colombier 	"blank check",
215*01a344a2SDavid du Colombier 	"vendor specific",
216*01a344a2SDavid du Colombier 	"copy aborted",
217*01a344a2SDavid du Colombier 	"aborted command",
218*01a344a2SDavid du Colombier 	"equal",
219*01a344a2SDavid du Colombier 	"volume overflow",
220*01a344a2SDavid du Colombier 	"miscompare",
221*01a344a2SDavid du Colombier 	"reserved"
222*01a344a2SDavid du Colombier };
223*01a344a2SDavid du Colombier 
224*01a344a2SDavid du Colombier static int
scsireqsense(Target * tp,char lun,int * nbytes,int quiet)225*01a344a2SDavid du Colombier scsireqsense(Target* tp, char lun, int* nbytes, int quiet)
226*01a344a2SDavid du Colombier {
227*01a344a2SDavid du Colombier 	char *s;
228*01a344a2SDavid du Colombier 	int n, status, try;
229*01a344a2SDavid du Colombier 	uchar cmd[6], *sense;
230*01a344a2SDavid du Colombier 
231*01a344a2SDavid du Colombier 	sense = tp->sense;
232*01a344a2SDavid du Colombier 	for(try = 0; try < 20; try++) {
233*01a344a2SDavid du Colombier 		memset(cmd, 0, sizeof cmd);
234*01a344a2SDavid du Colombier 		cmd[0] = CMDreqsense;
235*01a344a2SDavid du Colombier 		cmd[1] = lun<<5;
236*01a344a2SDavid du Colombier 		cmd[4] = Ninquiry;
237*01a344a2SDavid du Colombier 		memset(sense, 0, Ninquiry);
238*01a344a2SDavid du Colombier 
239*01a344a2SDavid du Colombier 		*nbytes = Ninquiry;
240*01a344a2SDavid du Colombier 		status = scsiexec(tp, SCSIread, cmd, sizeof cmd, sense, nbytes);
241*01a344a2SDavid du Colombier 		if(status != STok)
242*01a344a2SDavid du Colombier 			return status;
243*01a344a2SDavid du Colombier 		*nbytes = sense[0x07]+8;
244*01a344a2SDavid du Colombier 
245*01a344a2SDavid du Colombier 		switch(sense[2] & 0x0F){
246*01a344a2SDavid du Colombier 		case 6:					/* unit attention */
247*01a344a2SDavid du Colombier 			/*
248*01a344a2SDavid du Colombier 			 * 0x28 - not ready to ready transition,
249*01a344a2SDavid du Colombier 			 *	  medium may have changed.
250*01a344a2SDavid du Colombier 			 * 0x29 - power on, RESET or BUS DEVICE RESET occurred.
251*01a344a2SDavid du Colombier 			 */
252*01a344a2SDavid du Colombier 			if(sense[12] != 0x28 && sense[12] != 0x29)
253*01a344a2SDavid du Colombier 				goto buggery;
254*01a344a2SDavid du Colombier 			/*FALLTHROUGH*/
255*01a344a2SDavid du Colombier 		case 0:					/* no sense */
256*01a344a2SDavid du Colombier 		case 1:					/* recovered error */
257*01a344a2SDavid du Colombier 			return STok;
258*01a344a2SDavid du Colombier 		case 8:					/* blank data */
259*01a344a2SDavid du Colombier 			return STblank;
260*01a344a2SDavid du Colombier 		case 2:					/* not ready */
261*01a344a2SDavid du Colombier 			if(sense[12] == 0x3A)		/* medium not present */
262*01a344a2SDavid du Colombier 				goto buggery;
263*01a344a2SDavid du Colombier 			/*FALLTHROUGH*/
264*01a344a2SDavid du Colombier 		default:
265*01a344a2SDavid du Colombier 			/*
266*01a344a2SDavid du Colombier 			 * If unit is becoming ready, rather than not ready,
267*01a344a2SDavid du Colombier 			 * then wait a little then poke it again; should this
268*01a344a2SDavid du Colombier 			 * be here or in the caller?
269*01a344a2SDavid du Colombier 			 */
270*01a344a2SDavid du Colombier 			if((sense[12] == 0x04 && sense[13] == 0x01)){
271*01a344a2SDavid du Colombier 				delay(500);
272*01a344a2SDavid du Colombier 				scsitest(tp, lun);
273*01a344a2SDavid du Colombier 				break;
274*01a344a2SDavid du Colombier 			}
275*01a344a2SDavid du Colombier 			goto buggery;
276*01a344a2SDavid du Colombier 		}
277*01a344a2SDavid du Colombier 	}
278*01a344a2SDavid du Colombier 
279*01a344a2SDavid du Colombier buggery:
280*01a344a2SDavid du Colombier 	if(quiet == 0){
281*01a344a2SDavid du Colombier 		s = key[sense[2]&0x0F];
282*01a344a2SDavid du Colombier 		print("%s: reqsense: '%s' code #%2.2ux #%2.2ux\n",
283*01a344a2SDavid du Colombier 			tp->id, s, sense[12], sense[13]);
284*01a344a2SDavid du Colombier 		print("%s: byte 2: #%2.2ux, bytes 15-17: #%2.2ux #%2.2ux #%2.2ux\n",
285*01a344a2SDavid du Colombier 			tp->id, sense[2], sense[15], sense[16], sense[17]);
286*01a344a2SDavid du Colombier 		print("lastcmd (%d): ", lastcmdsz);
287*01a344a2SDavid du Colombier 		for(n = 0; n < lastcmdsz; n++)
288*01a344a2SDavid du Colombier 			print(" #%2.2ux", lastcmd[n]);
289*01a344a2SDavid du Colombier 		print("\n");
290*01a344a2SDavid du Colombier 	}
291*01a344a2SDavid du Colombier 
292*01a344a2SDavid du Colombier 	return STcheck;
293*01a344a2SDavid du Colombier }
294*01a344a2SDavid du Colombier 
295*01a344a2SDavid du Colombier static Target*
scsitarget(Device * d)296*01a344a2SDavid du Colombier scsitarget(Device* d)
297*01a344a2SDavid du Colombier {
298*01a344a2SDavid du Colombier 	int ctlrno, targetno;
299*01a344a2SDavid du Colombier 
300*01a344a2SDavid du Colombier 	ctlrno = d->wren.ctrl;
301*01a344a2SDavid du Colombier 	if(ctlrno < 0 || ctlrno >= MaxScsi /* || scsictlr[ctlrno].io == nil */)
302*01a344a2SDavid du Colombier 		return 0;
303*01a344a2SDavid du Colombier 	targetno = d->wren.targ;
304*01a344a2SDavid du Colombier 	if(targetno < 0 || targetno >= NTarget)
305*01a344a2SDavid du Colombier 		return 0;
306*01a344a2SDavid du Colombier 	return &scsictlr[ctlrno].target[targetno];
307*01a344a2SDavid du Colombier }
308*01a344a2SDavid du Colombier 
309*01a344a2SDavid du Colombier static void
scsiprobe(Device * d)310*01a344a2SDavid du Colombier scsiprobe(Device* d)
311*01a344a2SDavid du Colombier {
312*01a344a2SDavid du Colombier 	Target *tp;
313*01a344a2SDavid du Colombier 	int nbytes, s;
314*01a344a2SDavid du Colombier 	uchar *sense;
315*01a344a2SDavid du Colombier 	int acount;
316*01a344a2SDavid du Colombier 
317*01a344a2SDavid du Colombier 	if((tp = scsitarget(d)) == 0)
318*01a344a2SDavid du Colombier 		panic("scsiprobe: device = %Z", d);
319*01a344a2SDavid du Colombier 
320*01a344a2SDavid du Colombier 	acount = 0;
321*01a344a2SDavid du Colombier again:
322*01a344a2SDavid du Colombier 	s = scsitest(tp, d->wren.lun);
323*01a344a2SDavid du Colombier 	if(s < STok){
324*01a344a2SDavid du Colombier 		print("%s: test, status %d\n", tp->id, s);
325*01a344a2SDavid du Colombier 		return;
326*01a344a2SDavid du Colombier 	}
327*01a344a2SDavid du Colombier 
328*01a344a2SDavid du Colombier 	/*
329*01a344a2SDavid du Colombier 	 * Determine if the drive exists and is not ready or
330*01a344a2SDavid du Colombier 	 * is simply not responding.
331*01a344a2SDavid du Colombier 	 * If the status is OK but the drive came back with a 'power on' or
332*01a344a2SDavid du Colombier 	 * 'reset' status, try the test again to make sure the drive is really
333*01a344a2SDavid du Colombier 	 * ready.
334*01a344a2SDavid du Colombier 	 * If the drive is not ready and requires intervention, try to spin it
335*01a344a2SDavid du Colombier 	 * up.
336*01a344a2SDavid du Colombier 	 */
337*01a344a2SDavid du Colombier 	s = scsireqsense(tp, d->wren.lun, &nbytes, acount);
338*01a344a2SDavid du Colombier 	sense = tp->sense;
339*01a344a2SDavid du Colombier 	switch(s){
340*01a344a2SDavid du Colombier 	case STok:
341*01a344a2SDavid du Colombier 		if ((sense[2] & 0x0F) == 0x06 &&
342*01a344a2SDavid du Colombier 		    (sense[12] == 0x28 || sense[12] == 0x29))
343*01a344a2SDavid du Colombier 			if(acount == 0){
344*01a344a2SDavid du Colombier 				acount = 1;
345*01a344a2SDavid du Colombier 				goto again;
346*01a344a2SDavid du Colombier 			}
347*01a344a2SDavid du Colombier 		break;
348*01a344a2SDavid du Colombier 	case STcheck:
349*01a344a2SDavid du Colombier 		if((sense[2] & 0x0F) == 0x02){
350*01a344a2SDavid du Colombier 			if(sense[12] == 0x3A)
351*01a344a2SDavid du Colombier 				break;
352*01a344a2SDavid du Colombier 			if(sense[12] == 0x04 && sense[13] == 0x02){
353*01a344a2SDavid du Colombier 				print("%s: starting...\n", tp->id);
354*01a344a2SDavid du Colombier 				if(scsistart(tp, d->wren.lun, 1) == STok)
355*01a344a2SDavid du Colombier 					break;
356*01a344a2SDavid du Colombier 				s = scsireqsense(tp, d->wren.lun, &nbytes, 0);
357*01a344a2SDavid du Colombier 			}
358*01a344a2SDavid du Colombier 		}
359*01a344a2SDavid du Colombier 		/*FALLTHROUGH*/
360*01a344a2SDavid du Colombier 	default:
361*01a344a2SDavid du Colombier 		print("%s: unavailable, status %d\n", tp->id, s);
362*01a344a2SDavid du Colombier 		return;
363*01a344a2SDavid du Colombier 	}
364*01a344a2SDavid du Colombier 
365*01a344a2SDavid du Colombier 	/*
366*01a344a2SDavid du Colombier 	 * Inquire to find out what the device is.
367*01a344a2SDavid du Colombier 	 * Hardware drivers may need some of the info.
368*01a344a2SDavid du Colombier 	 */
369*01a344a2SDavid du Colombier 	s = scsiinquiry(tp, d->wren.lun, &nbytes);
370*01a344a2SDavid du Colombier 	if(s != STok) {
371*01a344a2SDavid du Colombier 		print("%s: inquiry failed, status %d\n", tp->id, s);
372*01a344a2SDavid du Colombier 		return;
373*01a344a2SDavid du Colombier 	}
374*01a344a2SDavid du Colombier 	print("%s: %s\n", tp->id, (char*)tp->inquiry+8);
375*01a344a2SDavid du Colombier 	tp->ok = 1;
376*01a344a2SDavid du Colombier }
377*01a344a2SDavid du Colombier 
378*01a344a2SDavid du Colombier int
scsiio(Device * d,int rw,uchar * cmd,int cbytes,void * data,int dbytes)379*01a344a2SDavid du Colombier scsiio(Device* d, int rw, uchar* cmd, int cbytes, void* data, int dbytes)
380*01a344a2SDavid du Colombier {
381*01a344a2SDavid du Colombier 	Target *tp;
382*01a344a2SDavid du Colombier 	int e, nbytes, s;
383*01a344a2SDavid du Colombier 
384*01a344a2SDavid du Colombier 	if((tp = scsitarget(d)) == 0)
385*01a344a2SDavid du Colombier 		panic("scsiio: device = %Z", d);
386*01a344a2SDavid du Colombier 
387*01a344a2SDavid du Colombier 	qlock(tp);
388*01a344a2SDavid du Colombier 	if(tp->ok == 0)
389*01a344a2SDavid du Colombier 		scsiprobe(d);
390*01a344a2SDavid du Colombier 	qunlock(tp);
391*01a344a2SDavid du Colombier 
392*01a344a2SDavid du Colombier 	s = STinit;
393*01a344a2SDavid du Colombier 	for(e = 0; e < 10; e++){
394*01a344a2SDavid du Colombier 		for(;;){
395*01a344a2SDavid du Colombier 			nbytes = dbytes;
396*01a344a2SDavid du Colombier 			s = scsiexec(tp, rw, cmd, cbytes, data, &nbytes);
397*01a344a2SDavid du Colombier 			if(s == STok)
398*01a344a2SDavid du Colombier 				break;
399*01a344a2SDavid du Colombier 			s = scsireqsense(tp, d->wren.lun, &nbytes, 0);
400*01a344a2SDavid du Colombier 			if(s == STblank && rw == SCSIread) {
401*01a344a2SDavid du Colombier 				memset(data, 0, dbytes);
402*01a344a2SDavid du Colombier 				return STok;
403*01a344a2SDavid du Colombier 			}
404*01a344a2SDavid du Colombier 			if(s != STok)
405*01a344a2SDavid du Colombier 				break;
406*01a344a2SDavid du Colombier 		}
407*01a344a2SDavid du Colombier 		if(s == STok)
408*01a344a2SDavid du Colombier 			break;
409*01a344a2SDavid du Colombier 	}
410*01a344a2SDavid du Colombier 	if(e)
411*01a344a2SDavid du Colombier 		print("%s: retry %d cmd #%x\n", tp->id, e, cmd[0]);
412*01a344a2SDavid du Colombier 	return s;
413*01a344a2SDavid du Colombier }
414*01a344a2SDavid du Colombier 
415*01a344a2SDavid du Colombier void
newscsi(Device * d,Scsi * sc)416*01a344a2SDavid du Colombier newscsi(Device *d, Scsi *sc)
417*01a344a2SDavid du Colombier {
418*01a344a2SDavid du Colombier 	Target *tp;
419*01a344a2SDavid du Colombier 
420*01a344a2SDavid du Colombier 	if((tp = scsitarget(d)) == nil)
421*01a344a2SDavid du Colombier 		panic("newscsi: device = %Z", d);
422*01a344a2SDavid du Colombier 	tp->sc = sc;		/* connect Target to Scsi */
423*01a344a2SDavid du Colombier }
424