M pc/scsi.c => pc/scsi.c +34 -27
@@ 136,7 136,9 @@ scsiprobe(Ctlr *ctlr)
* Determine if the drive exists and is not ready or
* is simply not responding
*/
- if((s = scsireqsense(t, 0, 0)) != STok){
+ nbytes = Nscratch;
+ s = scsireqsense(t, 0, t->scratch, &nbytes, 0);
+ if(s != STok){
print("scsi%d: unit %d unavailable, status %d\n", t->ctlrno, i, s);
continue;
}
@@ 152,7 154,7 @@ scsiprobe(Ctlr *ctlr)
print("scsi%d: unit %d inquire failed, status %d\n", t->ctlrno, i, s);
continue;
}
- print("scsi%d: unit %d:%2.2ux: %s\n", t->ctlrno, i, t->inq[0], t->inq+8);
+ print("scsi%d: unit %d: %s\n", t->ctlrno, i, t->inq+8);
t->ok = 1;
}
}
@@ 260,15 262,12 @@ scsicap(Target *t, char lun, ulong *size, ulong *bsize)
return -1;
nbytes = 8;
- s = scsiexec(t, SCSIread, cmd, sizeof(cmd), d, &nbytes);
- if(s < 0) {
- free(d);
- return s;
+ if((s = scsiexec(t, SCSIread, cmd, sizeof(cmd), d, &nbytes)) == STok){
+ *size = (d[0]<<24)|(d[1]<<16)|(d[2]<<8)|(d[3]<<0);
+ *bsize = (d[4]<<24)|(d[5]<<16)|(d[6]<<8)|(d[7]<<0);
}
- *size = (d[0]<<24)|(d[1]<<16)|(d[2]<<8)|(d[3]<<0);
- *bsize = (d[4]<<24)|(d[5]<<16)|(d[6]<<8)|(d[7]<<0);
free(d);
- return 0;
+ return s;
}
int
@@ 304,7 303,8 @@ scsibio(Target *t, char lun, int dir, void *b, long n, long bsize, long bno)
nbytes = n*bsize;
s = scsiexec(t, dir, cmd, cdbsiz, b, &nbytes);
if(s < 0) {
- scsireqsense(t, lun, 0);
+ nbytes = Nscratch;
+ scsireqsense(t, lun, t->scratch, &nbytes, 0);
return -1;
}
return nbytes;
@@ 331,37 331,44 @@ static char *key[] =
};
int
-scsireqsense(Target *t, char lun, int quiet)
+scsireqsense(Target *t, char lun, void *data, int *nbytes, int quiet)
{
char *s;
- int sr, try, nbytes;
+ int status, try;
uchar cmd[6], *sense;
- sense = t->scratch;
+ sense = malloc(*nbytes);
for(try = 0; try < 5; try++) {
memset(cmd, 0, sizeof(cmd));
cmd[0] = CMDreqsense;
cmd[1] = lun<<5;
- cmd[4] = Nscratch;
- memset(sense, 0, sizeof(sense));
+ cmd[4] = *nbytes;
+ memset(sense, 0, *nbytes);
- nbytes = Nscratch;
- sr = scsiexec(t, SCSIread, cmd, sizeof(cmd), sense, &nbytes);
- if(sr != STok)
- return sr;
+ status = scsiexec(t, SCSIread, cmd, sizeof(cmd), sense, nbytes);
+ if(status != STok){
+ free(sense);
+ return status;
+ }
+ *nbytes = sense[0x07]+8;
+ memmove(data, sense, *nbytes);
/*
* Unit attention. We can handle that.
*/
- if((sense[2] & 0x0F) == 0x00 || (sense[2] & 0x0F) == 0x06)
+ if((sense[2] & 0x0F) == 0x00 || (sense[2] & 0x0F) == 0x06){
+ free(sense);
return STok;
+ }
/*
* Recovered error. Why bother telling me.
*/
- if((sense[2] & 0x0F) == 0x01)
+ if((sense[2] & 0x0F) == 0x01){
+ free(sense);
return STok;
+ }
/*
* Unit is becoming ready
@@ 372,12 379,12 @@ scsireqsense(Target *t, char lun, int quiet)
delay(5000);
}
- if(quiet)
- return STcheck;
-
- s = key[sense[2]&0xf];
- print("scsi%d: unit %d reqsense: '%s' code #%2.2ux #%2.2ux\n",
- t->ctlrno, t->target, s, sense[12], sense[13]);
+ if(quiet == 0){
+ s = key[sense[2]&0x0F];
+ print("scsi%d: unit %d reqsense: '%s' code #%2.2ux #%2.2ux\n",
+ t->ctlrno, t->target, s, sense[12], sense[13]);
+ }
+ free(sense);
return STcheck;
}
M port/devsd.c => port/devsd.c +45 -29
@@ 100,8 100,7 @@ void
sdinit(void)
{
Disk *d;
- ulong s, b;
- uchar inq[255];
+ uchar scratch[0xFF], type;
int dev, i, nbytes;
dev = 0;
@@ 111,43 110,48 @@ sdinit(void)
if(dev < 0)
break;
- if(scsitest(d->t, 0) < 0)
- scsireqsense(d->t, 0, 0);
- if(scsistart(d->t, 0, 1) < 0)
- scsireqsense(d->t, 0, 0);
-print("sd1|");
-
- /* Search for other lun's */
+ /*
+ * Search for all the lun's.
+ */
for(i = 0; i < Nlun; i++) {
d->lun = i;
-print("sd2|");
/*
* A SCSI target does not support a lun if the
* the peripheral device type and qualifier fields
* in the response to an inquiry command are 0x7F.
*/
- memset(inq, 0, sizeof(inq));
- nbytes = sizeof(inq);
- if(scsiinquiry(d->t, d->lun, inq, &nbytes) != STok || inq[0] == 0x7F)
+ nbytes = sizeof(scratch);
+ memset(scratch, 0, nbytes);
+ if(scsiinquiry(d->t, d->lun, scratch, &nbytes) != STok)
continue;
-print("sd3|");
-
- s = 0;
- b = 0;
- if(scsicap(d->t, d->lun, &s, &b) != STok) {
- scsireqsense(d->t, 0, 0);
+ if(scratch[0] == 0x7F)
continue;
- }
-print("sd4/%d/%d|", s, b);
+ type = scratch[0] & 0x1F;
- if(s == 0 || b == 0)
- continue;
-print("sd5/0x%2.2ux|", d->inquire[0]);
+ /*
+ * Read-capacity is mandatory for TypeDA, TypeMO and TypeCD.
+ * It may return 'not ready' if TypeDA is not spun up,
+ * TypeMO or TypeCD are not loaded or just plain slow getting
+ * their act together after a reset.
+ * If 'not ready' comes back, try starting a TypeDA and punt
+ * the get capacity until the drive is attached.
+ * It might be possible to be smarter here, and look at the
+ * response from a test-unit-ready which would show if the
+ * target was in the process of becoming ready.
+ */
+ if(scsicap(d->t, d->lun, &d->size, &d->bsize) != STok) {
+ nbytes = sizeof(scratch);
+ memset(scratch, 0, nbytes);
+ scsireqsense(d->t, 0, scratch, &nbytes, 1);
+ if((scratch[2] & 0x0F) != 0x02)
+ continue;
+ if(type == TypeDA)
+ scsistart(d->t, d->lun, 0);
+ d->size = d->bsize = 0;
+ }
- d->size = s;
- d->bsize = b;
- switch(d->inquire[0] & 0x1F){
+ switch(type){
case TypeDA:
case TypeMO:
@@ 161,7 165,6 @@ print("sd5/0x%2.2ux|", d->inquire[0]);
default:
continue;
}
-print("sd6|");
if(++ndisk >= Ndisk)
break;
@@ 281,10 284,23 @@ sdrdpart(Disk *d)
char *b, *line[Npart+2], *field[3];
static char MAGIC[] = "plan9 partitions";
+ /*
+ * If the drive wasn't ready when we tried to do a
+ * read-capacity earlier (in sdinit()), try again.
+ * It might be possible to be smarter here, and look at the
+ * response from a test-unit-ready which would show if the
+ * target was in the process of becoming ready.
+ */
+ if(d->size == 0 || d->bsize == 0){
+ if(scsicap(d->t, d->lun, &d->size, &d->bsize) != STok){
+ d->size = d->bsize = 0;
+ error(Eio);
+ }
+ }
+
b = scsialloc(d->bsize);
if(b == 0)
error(Enomem);
-
qlock(d);
p = d->table;
M port/portfns.h => port/portfns.h +1 -1
@@ 241,7 241,7 @@ int scsiexec(Target*, int, uchar*, int, void*, int*);
#define scsifree(p) free(p)
int scsiinquiry(Target*, char, void*, int*);
int scsiinv(int, int*, Target**, uchar**, char*);
-int scsireqsense(Target*, char, int);
+int scsireqsense(Target*, char, void*, int*, int);
int scsistart(Target*, char, int);
int scsitest(Target*, char);
Target* scsiunit(int, int);