ref: 10cf5557ab4ab54278b6079da5539eb1cc59a597
parent: a069ed018555d165681cf3f02a2f00f565d9150f
author: joe9 <[email protected]>
date: Wed Jul 14 07:28:13 EDT 2021
using 9front sd drivers
--- a/os/pc/sdscsi.c
+++ /dev/null
@@ -1,393 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "ureg.h"
-#include "../port/error.h"
-
-#include "../port/sd.h"
-
-static int
-scsitest(SDreq* r)
-{
- r->write = 0;
- memset(r->cmd, 0, sizeof(r->cmd));
- r->cmd[1] = r->lun<<5;
- r->clen = 6;
- r->data = nil;
- r->dlen = 0;
- r->flags = 0;
-
- r->status = ~0;
-
- return r->unit->dev->ifc->rio(r);
-}
-
-int
-scsiverify(SDunit* unit)
-{
- SDreq *r;
- int i, status;
- uchar *inquiry;
-
- if((r = malloc(sizeof(SDreq))) == nil)
- return 0;
- if((inquiry = sdmalloc(sizeof(unit->inquiry))) == nil){
- free(r);
- return 0;
- }
- r->unit = unit;
- r->lun = 0; /* ??? */
-
- memset(unit->inquiry, 0, sizeof(unit->inquiry));
- r->write = 0;
- r->cmd[0] = 0x12;
- r->cmd[1] = r->lun<<5;
- r->cmd[4] = sizeof(unit->inquiry)-1;
- r->clen = 6;
- r->data = inquiry;
- r->dlen = sizeof(unit->inquiry)-1;
- r->flags = 0;
-
- r->status = ~0;
- if(unit->dev->ifc->rio(r) != SDok){
- free(r);
- return 0;
- }
- memmove(unit->inquiry, inquiry, r->dlen);
- free(inquiry);
-
- SET(status);
- for(i = 0; i < 3; i++){
- while((status = scsitest(r)) == SDbusy)
- ;
- if(status == SDok || status != SDcheck)
- break;
- if(!(r->flags & SDvalidsense))
- break;
- if((r->sense[2] & 0x0F) != 0x02)
- continue;
-
- /*
- * Unit is 'not ready'.
- * If it is in the process of becoming ready or needs
- * an initialising command, set status so it will be spun-up
- * below.
- * If there's no medium, that's OK too, but don't
- * try to spin it up.
- */
- if(r->sense[12] == 0x04){
- if(r->sense[13] == 0x02 || r->sense[13] == 0x01){
- status = SDok;
- break;
- }
- }
- if(r->sense[12] == 0x3A)
- break;
- }
-
- if(status == SDok){
- /*
- * Try to ensure a direct-access device is spinning.
- * Don't wait for completion, ignore the result.
- */
- if((unit->inquiry[0] & 0x1F) == 0){
- memset(r->cmd, 0, sizeof(r->cmd));
- r->write = 0;
- r->cmd[0] = 0x1B;
- r->cmd[1] = (r->lun<<5)|0x01;
- r->cmd[4] = 1;
- r->clen = 6;
- r->data = nil;
- r->dlen = 0;
- r->flags = 0;
-
- r->status = ~0;
- unit->dev->ifc->rio(r);
- }
- }
- free(r);
-
- if(status == SDok || status == SDcheck)
- return 1;
- return 0;
-}
-
-static int
-scsirio(SDreq* r)
-{
- /*
- * Perform an I/O request, returning
- * -1 failure
- * 0 ok
- * 1 no medium present
- * 2 retry
- * The contents of r may be altered so the
- * caller should re-initialise if necesary.
- */
- r->status = ~0;
- switch(r->unit->dev->ifc->rio(r)){
- default:
- return -1;
- case SDcheck:
- if(!(r->flags & SDvalidsense))
- return -1;
- switch(r->sense[2] & 0x0F){
- case 0x00: /* no sense */
- case 0x01: /* recovered error */
- return 2;
- case 0x06: /* check condition */
- /*
- * 0x28 - not ready to ready transition,
- * medium may have changed.
- * 0x29 - power on or some type of reset.
- */
- if(r->sense[12] == 0x28 && r->sense[13] == 0)
- return 2;
- if(r->sense[12] == 0x29)
- return 2;
- return -1;
- case 0x02: /* not ready */
- /*
- * If no medium present, bail out.
- * If unit is becoming ready, rather than not
- * not ready, wait a little then poke it again. */
- if(r->sense[12] == 0x3A)
- return 1;
- if(r->sense[12] != 0x04 || r->sense[13] != 0x01)
- return -1;
-
- while(waserror())
- ;
- tsleep(&up->sleep, return0, 0, 500);
- poperror();
- scsitest(r);
- return 2;
- default:
- return -1;
- }
- case SDok:
- return 0;
- }
- return -1;
-}
-
-int
-scsionline(SDunit* unit)
-{
- SDreq *r;
- uchar *p;
- int ok, retries;
-
- if((r = malloc(sizeof(SDreq))) == nil)
- return 0;
- if((p = sdmalloc(8)) == nil){
- free(r);
- return 0;
- }
-
- ok = 0;
-
- r->unit = unit;
- r->lun = 0; /* ??? */
- for(retries = 0; retries < 10; retries++){
- /*
- * Read-capacity is mandatory for DA, WORM, CD-ROM and
- * MO. It may return 'not ready' if type DA is not
- * spun up, type MO or type CD-ROM are not loaded or just
- * plain slow getting their act together after a reset.
- */
- r->write = 0;
- memset(r->cmd, 0, sizeof(r->cmd));
- r->cmd[0] = 0x25;
- r->cmd[1] = r->lun<<5;
- r->clen = 10;
- r->data = p;
- r->dlen = 8;
- r->flags = 0;
-
- r->status = ~0;
- switch(scsirio(r)){
- default:
- break;
- case 0:
- unit->sectors = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
- if(unit->sectors == 0)
- continue;
- /*
- * Read-capacity returns the LBA of the last sector,
- * therefore the number of sectors must be incremented.
- */
- unit->sectors++;
- unit->secsize = (p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7];
-
- /*
- * Some ATAPI CD readers lie about the block size.
- * Since we don't read audio via this interface
- * it's okay to always fudge this.
- */
- if(unit->secsize == 2352)
- unit->secsize = 2048;
- ok = 1;
- break;
- case 1:
- ok = 1;
- break;
- case 2:
- continue;
- }
- break;
- }
- free(p);
- free(r);
-
- if(ok)
- return ok+retries;
- else
- return 0;
-}
-
-int
-scsiexec(SDunit* unit, int write, uchar* cmd, int clen, void* data, int* dlen)
-{
- SDreq *r;
- int status;
-
- if((r = malloc(sizeof(SDreq))) == nil)
- return SDmalloc;
- r->unit = unit;
- r->lun = cmd[1]>>5; /* ??? */
- r->write = write;
- memmove(r->cmd, cmd, clen);
- r->clen = clen;
- r->data = data;
- if(dlen)
- r->dlen = *dlen;
- r->flags = 0;
-
- r->status = ~0;
-
- /*
- * Call the device-specific I/O routine.
- * There should be no calls to 'error()' below this
- * which percolate back up.
- */
- switch(status = unit->dev->ifc->rio(r)){
- case SDok:
- if(dlen)
- *dlen = r->rlen;
- /*FALLTHROUGH*/
- case SDcheck:
- /*FALLTHROUGH*/
- default:
- /*
- * It's more complicated than this. There are conditions
- * which are 'ok' but for which the returned status code
- * is not 'SDok'.
- * Also, not all conditions require a reqsense, might
- * need to do a reqsense here and make it available to the
- * caller somehow.
- *
- * Mañana.
- */
- break;
- }
- sdfree(r);
-
- return status;
-}
-
-long
-scsibio(SDunit* unit, int lun, int write, void* data, long nb, long bno)
-{
- SDreq *r;
- long rlen;
-
- if((r = malloc(sizeof(SDreq))) == nil)
- error(Enomem);
- r->unit = unit;
- r->lun = lun;
-again:
- r->write = write;
- if(write == 0)
- r->cmd[0] = 0x28;
- else
- r->cmd[0] = 0x2A;
- r->cmd[1] = (lun<<5);
- r->cmd[2] = bno>>24;
- r->cmd[3] = bno>>16;
- r->cmd[4] = bno>>8;
- r->cmd[5] = bno;
- r->cmd[6] = 0;
- r->cmd[7] = nb>>8;
- r->cmd[8] = nb;
- r->cmd[9] = 0;
- r->clen = 10;
- r->data = data;
- r->dlen = nb*unit->secsize;
- r->flags = 0;
-
- r->status = ~0;
- switch(scsirio(r)){
- default:
- rlen = -1;
- break;
- case 0:
- rlen = r->rlen;
- break;
- case 2:
- rlen = -1;
- if(!(r->flags & SDvalidsense))
- break;
- switch(r->sense[2] & 0x0F){
- default:
- break;
- case 0x06: /* check condition */
- /*
- * Check for a removeable media change.
- * If so, mark it by zapping the geometry info
- * to force an online request.
- */
- if(r->sense[12] != 0x28 || r->sense[13] != 0)
- break;
- if(unit->inquiry[1] & 0x80)
- unit->sectors = 0;
- break;
- case 0x02: /* not ready */
- /*
- * If unit is becoming ready,
- * rather than not not ready, try again.
- */
- if(r->sense[12] == 0x04 && r->sense[13] == 0x01)
- goto again;
- break;
- }
- break;
- }
- free(r);
-
- return rlen;
-}
-
-SDev*
-scsiid(SDev* sdev, SDifc* ifc)
-{
- char name[32];
- static char idno[16] = "0123456789abcdef";
- static char *p = idno;
-
- while(sdev){
- if(sdev->ifc == ifc){
- sdev->idno = *p++;
- snprint(name, sizeof(name), "sd%c", sdev->idno);
- kstrdup(&sdev->name, name);
- if(p >= &idno[sizeof(idno)])
- break;
- }
- sdev = sdev->next;
- }
-
- return nil;
-}
--- a/os/pc/sdvirtio.c
+++ b/os/pc/sdvirtio.c
@@ -67,7 +67,7 @@
struct Vdesc
{
u64int addr;
- u32 len;
+ u32int len;
u16int flags;
u16int next;
};
@@ -74,8 +74,8 @@
struct Vused
{
- u32 id;
- u32 len;
+ u32int id;
+ u32int len;
};
struct Vqueue
@@ -128,16 +128,16 @@
struct ScsiCfg
{
- u32 num_queues;
- u32 seg_max;
- u32 max_sectors;
- u32 cmd_per_lun;
- u32 event_info_size;
- u32 sense_size;
- u32 cdb_size;
+ u32int num_queues;
+ u32int seg_max;
+ u32int max_sectors;
+ u32int cmd_per_lun;
+ u32int event_info_size;
+ u32int sense_size;
+ u32int cdb_size;
u16int max_channel;
u16int max_target;
- u32 max_lun;
+ u32int max_lun;
};
static Vqueue*
@@ -336,8 +336,8 @@
u8int status;
struct Vioblkreqhdr {
- u32 typ;
- u32 prio;
+ u32int typ;
+ u32int prio;
u64int lba;
} req;
@@ -396,7 +396,7 @@
u8int resp[4+4+2+2+SENSESIZE];
u8int req[8+8+3+CDBSIZE];
int free, head;
- u32 len;
+ u32int len;
Vqueue *q;
Vdesc *d;
Vdev *vd;
@@ -469,7 +469,7 @@
r->status = SDcheck;
/* sense_len */
- len = *((u32*)&resp[0]);
+ len = *((u32int*)&resp[0]);
if(len > 0){
if(len > sizeof(r->sense))
len = sizeof(r->sense);
@@ -478,7 +478,7 @@
}
/* data residue */
- len = *((u32*)&resp[4]);
+ len = *((u32int*)&resp[4]);
if(len > r->dlen)
r->rlen = 0;
else
@@ -611,7 +611,7 @@
id = 'F';
for(vd = viopnpdevs(TypBlk); vd; vd = vd->next){
- if(vd->nqueue != 1)
+ if(vd->nqueue == 0)
continue;
if((s = malloc(sizeof(*s))) == nil)
@@ -680,7 +680,6 @@
viopnp, /* pnp */
nil, /* legacy */
- nil, /* id */
vioenable, /* enable */
viodisable, /* disable */
@@ -693,8 +692,6 @@
viobio, /* bio */
nil, /* probe */
nil, /* clear */
- nil, /* stat */
nil, /* rtopctl */
nil, /* wtopctl */
- nil, /* ataio */
};
--- a/os/port/devsd.c
+++ b/os/port/devsd.c
@@ -1284,13 +1284,13 @@
if(unit->sectors){
if(unit->dev->ifc->rctl == nil)
l += snprint(p+l, m-l,
- "geometry %ud %ud\n",
+ "geometry %llud %lud\n",
unit->sectors, unit->secsize);
pp = unit->part;
for(i = 0; i < unit->npart; i++){
if(pp->valid)
l += snprint(p+l, m-l,
- "part %s %lud %lud\n",
+ "part %s %llud %llud\n",
pp->name, pp->start, pp->end);
pp++;
}
--- a/os/port/sd.h
+++ b/os/port/sd.h
@@ -17,8 +17,8 @@
};
struct SDpart {
- ulong start;
- ulong end;
+ uvlong start;
+ uvlong end;
SDperm;
int valid;
ulong vers;
@@ -34,7 +34,7 @@
struct SDunit {
SDev* dev;
int subno;
- uchar inquiry[256]; /* format follows SCSI spec */
+ uchar inquiry[255]; /* format follows SCSI spec */
uchar sense[18]; /* format follows SCSI spec */
uchar rsense[18]; /* support seperate rq sense and inline return */
uchar haversense;
@@ -41,11 +41,11 @@
SDperm;
QLock ctl;
- u32 sectors;
- u32 secsize;
+ uvlong sectors;
+ ulong secsize;
SDpart* part; /* nil or array of size npart */
int npart;
- u32 vers;
+ ulong vers;
SDperm ctlperm;
QLock raw; /* raw read or write in progress */
@@ -57,17 +57,15 @@
int nefile;
};
-/*
+/*
* Each controller is represented by a SDev.
- * Each controller is responsible for allocating its unit structures.
- * Each controller has at least one unit.
- */
+ */
struct SDev {
Ref r; /* Number of callers using device */
SDifc* ifc; /* pnp/legacy */
void* ctlr;
int idno;
- char* name;
+ char name[8];
SDev* next;
QLock; /* enable/disable */
@@ -82,8 +80,7 @@
char* name;
SDev* (*pnp)(void);
- SDev* (*legacy)(int, int);
- SDev* (*id)(SDev*);
+ SDev* (*xxlegacy)(int, int); /* unused. remove me */
int (*enable)(SDev*);
int (*disable)(SDev*);
@@ -96,7 +93,6 @@
long (*bio)(SDunit*, int, int, void*, long, uvlong);
SDev* (*probe)(DevConf*);
void (*clear)(SDev*);
- char* (*stat)(SDev*, char*, char*);
char* (*rtopctl)(SDev*, char*, char*);
int (*wtopctl)(SDev*, Cmdbuf*);
int (*ataio)(SDreq*);
@@ -105,10 +101,10 @@
struct SDreq {
SDunit* unit;
int lun;
- int write;
+ char write;
char proto;
char ataproto;
- uchar cmd[16];
+ uchar cmd[0x20];
int clen;
void* data;
int dlen;
@@ -117,7 +113,7 @@
int status;
long rlen;
- uchar sense[256];
+ uchar sense[32];
};
enum {
@@ -162,7 +158,7 @@
int (*init)(void);
void (*enable)(void);
int (*inquiry)(char*, int);
- int (*cmd)(u32, u32, u32*);
+ int (*cmd)(u32int, u32int, u32int*);
void (*iosetup)(int, void*, int, int);
void (*io)(int, uchar*, int);
char highspeed;
@@ -180,5 +176,4 @@
/* sdscsi.c */
extern int scsiverify(SDunit*);
extern int scsionline(SDunit*);
-extern long scsibio(SDunit*, int, int, void*, long, long);
-extern SDev* scsiid(SDev*, SDifc*);
+extern long scsibio(SDunit*, int, int, void*, long, uvlong);
--- /dev/null
+++ b/os/port/sdscsi.c
@@ -1,0 +1,461 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+#include "../port/error.h"
+
+#include "../port/sd.h"
+
+static int
+scsitest(SDreq* r)
+{
+ r->write = 0;
+ memset(r->cmd, 0, sizeof(r->cmd));
+ r->cmd[1] = r->lun<<5;
+ r->clen = 6;
+ r->data = nil;
+ r->dlen = 0;
+ r->flags = 0;
+
+ r->status = ~0;
+
+ return r->unit->dev->ifc->rio(r);
+}
+
+int
+scsiverify(SDunit* unit)
+{
+ SDreq *r;
+ int i, status;
+ uchar *inquiry;
+
+ if((r = malloc(sizeof(SDreq))) == nil)
+ return 0;
+ if((inquiry = sdmalloc(sizeof(unit->inquiry))) == nil){
+ free(r);
+ return 0;
+ }
+ r->unit = unit;
+ r->lun = 0; /* ??? */
+
+ memset(unit->inquiry, 0, sizeof(unit->inquiry));
+ r->write = 0;
+ r->cmd[0] = 0x12;
+ r->cmd[1] = r->lun<<5;
+ r->cmd[4] = 36;
+ r->clen = 6;
+ r->data = inquiry;
+ r->dlen = 36;
+ r->flags = 0;
+
+ r->status = ~0;
+ if(unit->dev->ifc->rio(r) != SDok){
+ free(r);
+ return 0;
+ }
+ memmove(unit->inquiry, inquiry, r->dlen);
+ free(inquiry);
+
+ SET(status);
+ for(i = 0; i < 3; i++){
+ while((status = scsitest(r)) == SDbusy)
+ ;
+ if(status == SDok || status != SDcheck)
+ break;
+ if(!(r->flags & SDvalidsense))
+ break;
+ if((r->sense[2] & 0x0F) != 0x02)
+ continue;
+
+ /*
+ * Unit is 'not ready'.
+ * If it is in the process of becoming ready or needs
+ * an initialising command, set status so it will be spun-up
+ * below.
+ * If there's no medium, that's OK too, but don't
+ * try to spin it up.
+ */
+ if(r->sense[12] == 0x04){
+ if(r->sense[13] == 0x02 || r->sense[13] == 0x01){
+ status = SDok;
+ break;
+ }
+ }
+ if(r->sense[12] == 0x3A)
+ break;
+ }
+
+ if(status == SDok){
+ /*
+ * Try to ensure a direct-access device is spinning.
+ * Don't wait for completion, ignore the result.
+ */
+ if((unit->inquiry[0] & 0x1F) == 0){
+ memset(r->cmd, 0, sizeof(r->cmd));
+ r->write = 0;
+ r->cmd[0] = 0x1B;
+ r->cmd[1] = (r->lun<<5)|0x01;
+ r->cmd[4] = 1;
+ r->clen = 6;
+ r->data = nil;
+ r->dlen = 0;
+ r->flags = 0;
+
+ r->status = ~0;
+ unit->dev->ifc->rio(r);
+ }
+ }
+ free(r);
+
+ if(status == SDok || status == SDcheck)
+ return 1;
+ return 0;
+}
+
+static int
+scsirio(SDreq* r)
+{
+ /*
+ * Perform an I/O request, returning
+ * -1 failure
+ * 0 ok
+ * 1 no medium present
+ * 2 retry
+ * The contents of r may be altered so the
+ * caller should re-initialise if necesary.
+ */
+ r->status = ~0;
+ switch(r->unit->dev->ifc->rio(r)){
+ default:
+ break;
+ case SDcheck:
+ if(!(r->flags & SDvalidsense))
+ break;
+ switch(r->sense[2] & 0x0F){
+ case 0x00: /* no sense */
+ case 0x01: /* recovered error */
+ return 2;
+ case 0x06: /* check condition */
+ /*
+ * 0x28 - not ready to ready transition,
+ * medium may have changed.
+ * 0x29 - power on or some type of reset.
+ */
+ if(r->sense[12] == 0x28 && r->sense[13] == 0)
+ return 2;
+ if(r->sense[12] == 0x29)
+ return 2;
+ break;
+ case 0x02: /* not ready */
+ /*
+ * If no medium present, bail out.
+ * If unit is becoming ready, rather than not
+ * not ready, wait a little then poke it again.
+ */
+ if(r->sense[12] == 0x3A)
+ break;
+ if(r->sense[12] != 0x04 || r->sense[13] != 0x01)
+ break;
+
+ while(waserror())
+ ;
+ tsleep(&up->sleep, return0, 0, 500);
+ poperror();
+ scsitest(r);
+ return 2;
+ default:
+ break;
+ }
+ break;
+ case SDok:
+ return 0;
+ }
+ return -1;
+}
+
+static void
+cap10(SDreq *r)
+{
+ r->cmd[0] = 0x25;
+ r->cmd[1] = r->lun<<5;
+ r->clen = 10;
+ r->dlen = 8;
+}
+
+static void
+cap16(SDreq *r)
+{
+ uint i;
+
+ i = 32;
+ r->cmd[0] = 0x9e;
+ r->cmd[1] = 0x10;
+ r->cmd[10] = i>>24;
+ r->cmd[11] = i>>16;
+ r->cmd[12] = i>>8;
+ r->cmd[13] = i;
+ r->clen = 16;
+ r->dlen = i;
+}
+
+static uint
+belong(uchar *u)
+{
+ return u[0]<<24 | u[1]<<16 | u[2]<<8 | u[3];
+}
+
+static uvlong
+capreply(SDreq *r, ulong *secsize)
+{
+ uchar *u;
+ ulong ss;
+ uvlong s;
+
+ u = r->data;
+ if(r->clen == 16){
+ s = (uvlong)belong(u)<<32 | belong(u + 4);
+ ss = belong(u + 8);
+ }else{
+ s = belong(u);
+ ss = belong(u + 4);
+ }
+ if(secsize)
+ *secsize = ss;
+ return s;
+}
+
+int
+scsionline(SDunit* unit)
+{
+ SDreq *r;
+ uchar *p;
+ ulong ss;
+ uvlong s;
+ int ok, retries;
+ void (*cap)(SDreq*);
+
+ if((r = malloc(sizeof *r)) == nil)
+ return 0;
+ if((p = sdmalloc(32)) == nil){
+ free(r);
+ return 0;
+ }
+
+ ok = 0;
+ cap = cap10;
+ r->unit = unit;
+ r->lun = 0; /* ??? */
+ for(retries = 0; retries < 10; retries++){
+ /*
+ * Read-capacity is mandatory for DA, WORM, CD-ROM and
+ * MO. It may return 'not ready' if type DA is not
+ * spun up, type MO or type CD-ROM are not loaded or just
+ * plain slow getting their act together after a reset.
+ */
+ r->write = 0;
+ r->data = p;
+ r->flags = 0;
+ memset(r->cmd, 0, sizeof r->cmd);
+ cap(r);
+
+ switch(scsirio(r)){
+ default:
+ /*
+ * ATAPI returns error and no sense information
+ * on media change / no media present.
+ * count as retries.
+ */
+ if(retries < 4)
+ continue;
+ break;
+ case 0:
+ s = capreply(r, &ss);
+ if(s == 0xffffffff && cap == cap10){
+ cap = cap16;
+ continue;
+ }
+ if(s == 0xffffffffffffffffLL)
+ s = 0;
+
+ /*
+ * Some ATAPI CD readers lie about the block size.
+ * Since we don't read audio via this interface
+ * it's okay to always fudge this.
+ */
+ if(ss == 2352)
+ ss = 2048;
+
+ /*
+ * Devices with removable media may return 0 sectors
+ * when they have empty media (e.g. sata dvd writers);
+ * if so, keep the count zero.
+ *
+ * Read-capacity returns the LBA of the last sector,
+ * therefore the number of sectors must be incremented.
+ */
+ if(s != 0)
+ s++;
+
+ ok = (unit->sectors != s) ? 2 : 1;
+ unit->sectors = s;
+ unit->secsize = ss;
+ break;
+ case 1:
+ ok = (unit->sectors != 0) ? 2 : 1;
+ unit->sectors = 0;
+ break;
+ case 2:
+ continue;
+ }
+ break;
+ }
+ free(p);
+ free(r);
+
+ /*
+ print("scsionline: %s: ok=%d retries=%d sectors=%llud secsize=%lud\n",
+ unit->name, ok, retries, unit->sectors, unit->secsize);
+ */
+
+ if(ok)
+ return ok+retries;
+ else
+ return 0;
+}
+
+static void
+scsifmt10(SDreq *r, int write, int lun, ulong nb, uvlong bno)
+{
+ uchar *c;
+
+ c = r->cmd;
+ if(write == 0)
+ c[0] = 0x28;
+ else
+ c[0] = 0x2A;
+ c[1] = lun<<5;
+ c[2] = bno>>24;
+ c[3] = bno>>16;
+ c[4] = bno>>8;
+ c[5] = bno;
+ c[6] = 0;
+ c[7] = nb>>8;
+ c[8] = nb;
+ c[9] = 0;
+
+ r->clen = 10;
+}
+
+static void
+scsifmt16(SDreq *r, int write, int lun, ulong nb, uvlong bno)
+{
+ uchar *c;
+
+ c = r->cmd;
+ if(write == 0)
+ c[0] = 0x88;
+ else
+ c[0] = 0x8A;
+ c[1] = lun<<5; /* so wrong */
+ c[2] = bno>>56;
+ c[3] = bno>>48;
+ c[4] = bno>>40;
+ c[5] = bno>>32;
+ c[6] = bno>>24;
+ c[7] = bno>>16;
+ c[8] = bno>>8;
+ c[9] = bno;
+ c[10] = nb>>24;
+ c[11] = nb>>16;
+ c[12] = nb>>8;
+ c[13] = nb;
+ c[14] = 0;
+ c[15] = 0;
+
+ r->clen = 16;
+}
+
+long
+scsibio(SDunit* unit, int lun, int write, void* data, long nb, uvlong bno)
+{
+ SDreq *r;
+ long rlen;
+
+ r = smalloc(sizeof(SDreq));
+ r->unit = unit;
+ r->lun = lun;
+again:
+ r->write = write;
+ if(bno > 0xffffffff)
+ scsifmt16(r, write, lun, nb, bno);
+ else
+ scsifmt10(r, write, lun, nb, bno);
+ r->data = data;
+ r->dlen = nb*unit->secsize;
+ r->flags = 0;
+
+ r->status = ~0;
+ switch(scsirio(r)){
+ default:
+ rlen = -1;
+ break;
+ case 0:
+ /*
+ * scsi allows commands to return successfully
+ * but return sense data, indicating that the
+ * operation didn't proceed as expected.
+ * (confusing, no). this allows the raw commands
+ * to successfully return errors. but any sense
+ * data bio sees must be an error. bomb out.
+ */
+ if(r->status == SDok && r->rlen > 0
+ && ((r->flags & SDvalidsense) == 0 || r->sense[2] == 0)){
+ rlen = r->rlen;
+ break;
+ }
+ case 2:
+ rlen = -1;
+ if(!(r->flags & SDvalidsense))
+ break;
+ switch(r->sense[2] & 0x0F){
+ default:
+ break;
+ case 0x01: /* recovered error */
+ print("%s: recovered error at sector %llud\n",
+ unit->name, bno);
+ rlen = r->rlen;
+ break;
+ case 0x06: /* check condition */
+ /*
+ * Check for a removeable media change.
+ * If so, mark it by zapping the geometry info
+ * to force an online request.
+ */
+ if(r->sense[12] != 0x28 || r->sense[13] != 0)
+ break;
+ if(unit->inquiry[1] & 0x80)
+ unit->sectors = 0;
+ break;
+ case 0x02: /* not ready */
+ /*
+ * If unit is becoming ready,
+ * rather than not not ready, try again.
+ */
+ if(r->sense[12] == 0x04 && r->sense[13] == 0x01)
+ goto again;
+ break;
+ }
+ snprint(up->genbuf, sizeof up->genbuf, "%s %.2ux%.2ux%.2ux %lld",
+ Eio, r->sense[2], r->sense[12], r->sense[13], bno);
+ free(r);
+ error(up->genbuf);
+ break;
+ }
+ free(r);
+
+ return rlen;
+}
+