2 * interface to scsi devices via scsi(2) to sd(3),
3 * which does not implement LUNs.
23 Target target[NTarget];
25 static Ctlr scsictlr[MaxScsi];
27 extern int scsiverbose;
37 for(ctlrno = 0; ctlrno < MaxScsi; ctlrno++){
38 ctlr = &scsictlr[ctlrno];
39 memset(ctlr, 0, sizeof(Ctlr));
40 for(targetno = 0; targetno < NTarget; targetno++){
41 tp = &ctlr->target[targetno];
45 sprint(tp->id, "scsictlr#%d.%d", ctlrno, targetno);
48 tp->targetno = targetno;
49 tp->inquiry = ialloc(Ninquiry, 0);
50 tp->sense = ialloc(Nsense, 0);
55 static uchar lastcmd[16];
59 sense2stcode(uchar *sense)
61 switch(sense[2] & 0x0F){
62 case 6: /* unit attention */
64 * 0x28 - not ready to ready transition,
65 * medium may have changed.
66 * 0x29 - power on, RESET or BUS DEVICE RESET occurred.
68 if(sense[12] != 0x28 && sense[12] != 0x29)
71 case 0: /* no sense */
72 case 1: /* recovered error */
74 case 8: /* blank data */
76 case 2: /* not ready */
77 if(sense[12] == 0x3A) /* medium not present */
82 * If unit is becoming ready, rather than not ready,
83 * then wait a little then poke it again; should this
84 * be here or in the caller?
86 if((sense[12] == 0x04 && sense[13] == 0x01)) {
89 fprint(2, "sense2stcode: unit becoming ready\n");
90 return STcheck; /* not exactly right */
97 * issue the SCSI command via scsi(2). lun must already be in cmd[1].
100 doscsi(Target* tp, int rw, uchar* cmd, int cbytes, void* data, int* dbytes)
103 uchar reqcmd[6], reqdata[Nsense], dummy[1];
108 panic("doscsi: nil tp->sc");
109 lun = cmd[1] >> 5; /* save lun in case we need it for reqsense */
111 /* cope with zero arguments */
117 if (scsi(sc, cmd, cbytes, data, db, rw) >= 0)
120 /* cmd failed, get whatever sense data we can */
121 memset(reqcmd, 0, sizeof reqcmd);
122 reqcmd[0] = CMDreqsense;
125 memset(reqdata, 0, sizeof reqdata);
126 if (scsicmd(sc, reqcmd, sizeof reqcmd, reqdata, sizeof reqdata,
130 /* translate sense data to ST* codes */
131 return sense2stcode(reqdata);
135 scsiexec(Target* tp, int rw, uchar* cmd, int cbytes, void* data, int* dbytes)
140 * issue the SCSI command. lun must already be in cmd[1].
142 s = doscsi(tp, rw, cmd, cbytes, data, dbytes);
146 memmove(lastcmd, cmd, cbytes);
152 * It's more complicated than this. There are conditions which
153 * are 'ok' but for which the returned status code is not 'STok'.
154 * Also, not all conditions require a reqsense, there may be a
155 * need to do a reqsense here when necessary and making it
156 * available to the caller somehow.
167 scsitest(Target* tp, char lun)
171 memset(cmd, 0, sizeof cmd);
174 return scsiexec(tp, SCSIread, cmd, sizeof cmd, 0, 0);
179 scsistart(Target* tp, char lun, int start)
183 memset(cmd, 0, sizeof cmd);
188 return scsiexec(tp, SCSIread, cmd, sizeof cmd, 0, 0);
192 scsiinquiry(Target* tp, char lun, int* nbytes)
196 memset(cmd, 0, sizeof cmd);
201 return scsiexec(tp, SCSIread, cmd, sizeof cmd, tp->inquiry, nbytes);
225 scsireqsense(Target* tp, char lun, int* nbytes, int quiet)
229 uchar cmd[6], *sense;
232 for(try = 0; try < 20; try++) {
233 memset(cmd, 0, sizeof cmd);
234 cmd[0] = CMDreqsense;
237 memset(sense, 0, Ninquiry);
240 status = scsiexec(tp, SCSIread, cmd, sizeof cmd, sense, nbytes);
243 *nbytes = sense[0x07]+8;
245 switch(sense[2] & 0x0F){
246 case 6: /* unit attention */
248 * 0x28 - not ready to ready transition,
249 * medium may have changed.
250 * 0x29 - power on, RESET or BUS DEVICE RESET occurred.
252 if(sense[12] != 0x28 && sense[12] != 0x29)
255 case 0: /* no sense */
256 case 1: /* recovered error */
258 case 8: /* blank data */
260 case 2: /* not ready */
261 if(sense[12] == 0x3A) /* medium not present */
266 * If unit is becoming ready, rather than not ready,
267 * then wait a little then poke it again; should this
268 * be here or in the caller?
270 if((sense[12] == 0x04 && sense[13] == 0x01)){
281 s = key[sense[2]&0x0F];
282 fprint(2, "%s: reqsense: '%s' code #%2.2ux #%2.2ux\n",
283 tp->id, s, sense[12], sense[13]);
284 fprint(2, "%s: byte 2: #%2.2ux, bytes 15-17: #%2.2ux #%2.2ux #%2.2ux\n",
285 tp->id, sense[2], sense[15], sense[16], sense[17]);
286 fprint(2, "lastcmd (%d): ", lastcmdsz);
287 for(n = 0; n < lastcmdsz; n++)
288 fprint(2, " #%2.2ux", lastcmd[n]);
296 scsitarget(Device* d)
298 int ctlrno, targetno;
300 ctlrno = d->wren.ctrl;
301 if(ctlrno < 0 || ctlrno >= MaxScsi /* || scsictlr[ctlrno].io == nil */)
303 targetno = d->wren.targ;
304 if(targetno < 0 || targetno >= NTarget)
306 return &scsictlr[ctlrno].target[targetno];
317 if((tp = scsitarget(d)) == 0)
318 panic("scsiprobe: device = %Z", d);
322 s = scsitest(tp, d->wren.lun);
324 fprint(2, "%s: test, status %d\n", tp->id, s);
329 * Determine if the drive exists and is not ready or
330 * is simply not responding.
331 * If the status is OK but the drive came back with a 'power on' or
332 * 'reset' status, try the test again to make sure the drive is really
334 * If the drive is not ready and requires intervention, try to spin it
337 s = scsireqsense(tp, d->wren.lun, &nbytes, acount);
341 if ((sense[2] & 0x0F) == 0x06 &&
342 (sense[12] == 0x28 || sense[12] == 0x29))
349 if((sense[2] & 0x0F) == 0x02){
350 if(sense[12] == 0x3A)
352 if(sense[12] == 0x04 && sense[13] == 0x02){
353 fprint(2, "%s: starting...\n", tp->id);
354 if(scsistart(tp, d->wren.lun, 1) == STok)
356 s = scsireqsense(tp, d->wren.lun, &nbytes, 0);
361 fprint(2, "%s: unavailable, status %d\n", tp->id, s);
366 * Inquire to find out what the device is.
367 * Hardware drivers may need some of the info.
369 s = scsiinquiry(tp, d->wren.lun, &nbytes);
371 fprint(2, "%s: inquiry failed, status %d\n", tp->id, s);
374 fprint(2, "%s: %s\n", tp->id, (char*)tp->inquiry+8);
379 scsiio(Device* d, int rw, uchar* cmd, int cbytes, void* data, int dbytes)
384 if((tp = scsitarget(d)) == 0)
385 panic("scsiio: device = %Z", d);
393 for(e = 0; e < 10; e++){
396 s = scsiexec(tp, rw, cmd, cbytes, data, &nbytes);
399 s = scsireqsense(tp, d->wren.lun, &nbytes, 0);
400 if(s == STblank && rw == SCSIread) {
401 memset(data, 0, dbytes);
411 fprint(2, "%s: retry %d cmd #%x\n", tp->id, e, cmd[0]);
416 newscsi(Device *d, Scsi *sc)
420 if((tp = scsitarget(d)) == nil)
421 panic("newscsi: device = %Z", d);
422 tp->sc = sc; /* connect Target to Scsi */