19ef1f84bSDavid du Colombier #include "u.h"
29ef1f84bSDavid du Colombier #include "../port/lib.h"
39ef1f84bSDavid du Colombier #include "mem.h"
49ef1f84bSDavid du Colombier #include "dat.h"
59ef1f84bSDavid du Colombier #include "fns.h"
69ef1f84bSDavid du Colombier #include "../port/error.h"
79ef1f84bSDavid du Colombier
89ef1f84bSDavid du Colombier #include "io.h"
99ef1f84bSDavid du Colombier #include "ureg.h"
109ef1f84bSDavid du Colombier
119ef1f84bSDavid du Colombier #include "../port/sd.h"
129ef1f84bSDavid du Colombier
139ef1f84bSDavid du Colombier static int
scsitest(SDreq * r)149ef1f84bSDavid du Colombier scsitest(SDreq* r)
159ef1f84bSDavid du Colombier {
169ef1f84bSDavid du Colombier r->write = 0;
179ef1f84bSDavid du Colombier memset(r->cmd, 0, sizeof(r->cmd));
189ef1f84bSDavid du Colombier r->cmd[1] = r->lun<<5;
199ef1f84bSDavid du Colombier r->clen = 6;
209ef1f84bSDavid du Colombier r->data = nil;
219ef1f84bSDavid du Colombier r->dlen = 0;
229ef1f84bSDavid du Colombier r->flags = 0;
239ef1f84bSDavid du Colombier
249ef1f84bSDavid du Colombier r->status = ~0;
259ef1f84bSDavid du Colombier
269ef1f84bSDavid du Colombier return r->unit->dev->ifc->rio(r);
279ef1f84bSDavid du Colombier }
289ef1f84bSDavid du Colombier
299ef1f84bSDavid du Colombier int
scsiverify(SDunit * unit)309ef1f84bSDavid du Colombier scsiverify(SDunit* unit)
319ef1f84bSDavid du Colombier {
329ef1f84bSDavid du Colombier SDreq *r;
339ef1f84bSDavid du Colombier int i, status;
349ef1f84bSDavid du Colombier uchar *inquiry;
359ef1f84bSDavid du Colombier
369ef1f84bSDavid du Colombier if((r = malloc(sizeof(SDreq))) == nil)
379ef1f84bSDavid du Colombier return 0;
389ef1f84bSDavid du Colombier if((inquiry = sdmalloc(sizeof(unit->inquiry))) == nil){
399ef1f84bSDavid du Colombier free(r);
409ef1f84bSDavid du Colombier return 0;
419ef1f84bSDavid du Colombier }
429ef1f84bSDavid du Colombier r->unit = unit;
439ef1f84bSDavid du Colombier r->lun = 0; /* ??? */
449ef1f84bSDavid du Colombier
459ef1f84bSDavid du Colombier memset(unit->inquiry, 0, sizeof(unit->inquiry));
469ef1f84bSDavid du Colombier r->write = 0;
479ef1f84bSDavid du Colombier r->cmd[0] = 0x12;
489ef1f84bSDavid du Colombier r->cmd[1] = r->lun<<5;
499ef1f84bSDavid du Colombier r->cmd[4] = sizeof(unit->inquiry)-1;
509ef1f84bSDavid du Colombier r->clen = 6;
519ef1f84bSDavid du Colombier r->data = inquiry;
529ef1f84bSDavid du Colombier r->dlen = sizeof(unit->inquiry)-1;
539ef1f84bSDavid du Colombier r->flags = 0;
549ef1f84bSDavid du Colombier
559ef1f84bSDavid du Colombier r->status = ~0;
569ef1f84bSDavid du Colombier if(unit->dev->ifc->rio(r) != SDok){
579ef1f84bSDavid du Colombier free(r);
589ef1f84bSDavid du Colombier return 0;
599ef1f84bSDavid du Colombier }
609ef1f84bSDavid du Colombier memmove(unit->inquiry, inquiry, r->dlen);
619ef1f84bSDavid du Colombier free(inquiry);
629ef1f84bSDavid du Colombier
639ef1f84bSDavid du Colombier SET(status);
649ef1f84bSDavid du Colombier for(i = 0; i < 3; i++){
659ef1f84bSDavid du Colombier while((status = scsitest(r)) == SDbusy)
669ef1f84bSDavid du Colombier ;
679ef1f84bSDavid du Colombier if(status == SDok || status != SDcheck)
689ef1f84bSDavid du Colombier break;
699ef1f84bSDavid du Colombier if(!(r->flags & SDvalidsense))
709ef1f84bSDavid du Colombier break;
719ef1f84bSDavid du Colombier if((r->sense[2] & 0x0F) != 0x02)
729ef1f84bSDavid du Colombier continue;
739ef1f84bSDavid du Colombier
749ef1f84bSDavid du Colombier /*
759ef1f84bSDavid du Colombier * Unit is 'not ready'.
769ef1f84bSDavid du Colombier * If it is in the process of becoming ready or needs
779ef1f84bSDavid du Colombier * an initialising command, set status so it will be spun-up
789ef1f84bSDavid du Colombier * below.
799ef1f84bSDavid du Colombier * If there's no medium, that's OK too, but don't
809ef1f84bSDavid du Colombier * try to spin it up.
819ef1f84bSDavid du Colombier */
829ef1f84bSDavid du Colombier if(r->sense[12] == 0x04){
839ef1f84bSDavid du Colombier if(r->sense[13] == 0x02 || r->sense[13] == 0x01){
849ef1f84bSDavid du Colombier status = SDok;
859ef1f84bSDavid du Colombier break;
869ef1f84bSDavid du Colombier }
879ef1f84bSDavid du Colombier }
889ef1f84bSDavid du Colombier if(r->sense[12] == 0x3A)
899ef1f84bSDavid du Colombier break;
909ef1f84bSDavid du Colombier }
919ef1f84bSDavid du Colombier
929ef1f84bSDavid du Colombier if(status == SDok){
939ef1f84bSDavid du Colombier /*
949ef1f84bSDavid du Colombier * Try to ensure a direct-access device is spinning.
959ef1f84bSDavid du Colombier * Don't wait for completion, ignore the result.
969ef1f84bSDavid du Colombier */
979ef1f84bSDavid du Colombier if((unit->inquiry[0] & SDinq0periphtype) == SDperdisk){
989ef1f84bSDavid du Colombier memset(r->cmd, 0, sizeof(r->cmd));
999ef1f84bSDavid du Colombier r->write = 0;
1009ef1f84bSDavid du Colombier r->cmd[0] = 0x1B;
1019ef1f84bSDavid du Colombier r->cmd[1] = (r->lun<<5)|0x01;
1029ef1f84bSDavid du Colombier r->cmd[4] = 1;
1039ef1f84bSDavid du Colombier r->clen = 6;
1049ef1f84bSDavid du Colombier r->data = nil;
1059ef1f84bSDavid du Colombier r->dlen = 0;
1069ef1f84bSDavid du Colombier r->flags = 0;
1079ef1f84bSDavid du Colombier
1089ef1f84bSDavid du Colombier r->status = ~0;
1099ef1f84bSDavid du Colombier unit->dev->ifc->rio(r);
1109ef1f84bSDavid du Colombier }
1119ef1f84bSDavid du Colombier }
1129ef1f84bSDavid du Colombier free(r);
1139ef1f84bSDavid du Colombier
1149ef1f84bSDavid du Colombier if(status == SDok || status == SDcheck)
1159ef1f84bSDavid du Colombier return 1;
1169ef1f84bSDavid du Colombier return 0;
1179ef1f84bSDavid du Colombier }
1189ef1f84bSDavid du Colombier
1199ef1f84bSDavid du Colombier static int
scsirio(SDreq * r)1209ef1f84bSDavid du Colombier scsirio(SDreq* r)
1219ef1f84bSDavid du Colombier {
1229ef1f84bSDavid du Colombier /*
1239ef1f84bSDavid du Colombier * Perform an I/O request, returning
1249ef1f84bSDavid du Colombier * -1 failure
1259ef1f84bSDavid du Colombier * 0 ok
1269ef1f84bSDavid du Colombier * 1 no medium present
1279ef1f84bSDavid du Colombier * 2 retry
1289ef1f84bSDavid du Colombier * The contents of r may be altered so the
1299ef1f84bSDavid du Colombier * caller should re-initialise if necesary.
1309ef1f84bSDavid du Colombier */
1319ef1f84bSDavid du Colombier r->status = ~0;
1329ef1f84bSDavid du Colombier switch(r->unit->dev->ifc->rio(r)){
1339ef1f84bSDavid du Colombier default:
1349ef1f84bSDavid du Colombier break;
1359ef1f84bSDavid du Colombier case SDcheck:
1369ef1f84bSDavid du Colombier if(!(r->flags & SDvalidsense))
1379ef1f84bSDavid du Colombier break;
1389ef1f84bSDavid du Colombier switch(r->sense[2] & 0x0F){
1399ef1f84bSDavid du Colombier case 0x00: /* no sense */
1409ef1f84bSDavid du Colombier case 0x01: /* recovered error */
1419ef1f84bSDavid du Colombier return 2;
1429ef1f84bSDavid du Colombier case 0x06: /* check condition */
1439ef1f84bSDavid du Colombier /*
1449ef1f84bSDavid du Colombier * 0x28 - not ready to ready transition,
1459ef1f84bSDavid du Colombier * medium may have changed.
1469ef1f84bSDavid du Colombier * 0x29 - power on or some type of reset.
1479ef1f84bSDavid du Colombier */
1489ef1f84bSDavid du Colombier if(r->sense[12] == 0x28 && r->sense[13] == 0)
1499ef1f84bSDavid du Colombier return 2;
1509ef1f84bSDavid du Colombier if(r->sense[12] == 0x29)
1519ef1f84bSDavid du Colombier return 2;
1529ef1f84bSDavid du Colombier break;
1539ef1f84bSDavid du Colombier case 0x02: /* not ready */
1549ef1f84bSDavid du Colombier /*
1559ef1f84bSDavid du Colombier * If no medium present, bail out.
1569ef1f84bSDavid du Colombier * If unit is becoming ready, rather than not
1579ef1f84bSDavid du Colombier * not ready, wait a little then poke it again. */
1589ef1f84bSDavid du Colombier if(r->sense[12] == 0x3A)
1599ef1f84bSDavid du Colombier break;
1609ef1f84bSDavid du Colombier if(r->sense[12] != 0x04 || r->sense[13] != 0x01)
1619ef1f84bSDavid du Colombier break;
1629ef1f84bSDavid du Colombier
1639ef1f84bSDavid du Colombier while(waserror())
1649ef1f84bSDavid du Colombier ;
1659ef1f84bSDavid du Colombier tsleep(&up->sleep, return0, 0, 500);
1669ef1f84bSDavid du Colombier poperror();
1679ef1f84bSDavid du Colombier scsitest(r);
1689ef1f84bSDavid du Colombier return 2;
1699ef1f84bSDavid du Colombier default:
1709ef1f84bSDavid du Colombier break;
1719ef1f84bSDavid du Colombier }
1729ef1f84bSDavid du Colombier break;
1739ef1f84bSDavid du Colombier case SDok:
1749ef1f84bSDavid du Colombier return 0;
1759ef1f84bSDavid du Colombier }
1769ef1f84bSDavid du Colombier return -1;
1779ef1f84bSDavid du Colombier }
1789ef1f84bSDavid du Colombier
1799ef1f84bSDavid du Colombier int
scsionline(SDunit * unit)1809ef1f84bSDavid du Colombier scsionline(SDunit* unit)
1819ef1f84bSDavid du Colombier {
1829ef1f84bSDavid du Colombier SDreq *r;
1839ef1f84bSDavid du Colombier uchar *p;
1849ef1f84bSDavid du Colombier int ok, retries;
1859ef1f84bSDavid du Colombier
1869ef1f84bSDavid du Colombier if((r = malloc(sizeof(SDreq))) == nil)
1879ef1f84bSDavid du Colombier return 0;
1889ef1f84bSDavid du Colombier if((p = sdmalloc(8)) == nil){
1899ef1f84bSDavid du Colombier free(r);
1909ef1f84bSDavid du Colombier return 0;
1919ef1f84bSDavid du Colombier }
1929ef1f84bSDavid du Colombier
1939ef1f84bSDavid du Colombier ok = 0;
1949ef1f84bSDavid du Colombier
1959ef1f84bSDavid du Colombier r->unit = unit;
1969ef1f84bSDavid du Colombier r->lun = 0; /* ??? */
1979ef1f84bSDavid du Colombier for(retries = 0; retries < 10; retries++){
1989ef1f84bSDavid du Colombier /*
1999ef1f84bSDavid du Colombier * Read-capacity is mandatory for DA, WORM, CD-ROM and
2009ef1f84bSDavid du Colombier * MO. It may return 'not ready' if type DA is not
2019ef1f84bSDavid du Colombier * spun up, type MO or type CD-ROM are not loaded or just
2029ef1f84bSDavid du Colombier * plain slow getting their act together after a reset.
2039ef1f84bSDavid du Colombier */
2049ef1f84bSDavid du Colombier r->write = 0;
2059ef1f84bSDavid du Colombier memset(r->cmd, 0, sizeof(r->cmd));
206a72b0d60SDavid du Colombier r->cmd[0] = ScmdRcapacity;
2079ef1f84bSDavid du Colombier r->cmd[1] = r->lun<<5;
2089ef1f84bSDavid du Colombier r->clen = 10;
2099ef1f84bSDavid du Colombier r->data = p;
2109ef1f84bSDavid du Colombier r->dlen = 8;
2119ef1f84bSDavid du Colombier r->flags = 0;
2129ef1f84bSDavid du Colombier
2139ef1f84bSDavid du Colombier r->status = ~0;
2149ef1f84bSDavid du Colombier switch(scsirio(r)){
2159ef1f84bSDavid du Colombier default:
2169ef1f84bSDavid du Colombier break;
2179ef1f84bSDavid du Colombier case 0:
2189ef1f84bSDavid du Colombier unit->sectors = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
2199ef1f84bSDavid du Colombier unit->secsize = (p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7];
2209ef1f84bSDavid du Colombier
2219ef1f84bSDavid du Colombier /*
2229ef1f84bSDavid du Colombier * Some ATAPI CD readers lie about the block size.
2239ef1f84bSDavid du Colombier * Since we don't read audio via this interface
2249ef1f84bSDavid du Colombier * it's okay to always fudge this.
2259ef1f84bSDavid du Colombier */
2269ef1f84bSDavid du Colombier if(unit->secsize == 2352)
2279ef1f84bSDavid du Colombier unit->secsize = 2048;
2289ef1f84bSDavid du Colombier /*
2299ef1f84bSDavid du Colombier * Devices with removable media may return 0 sectors
2309ef1f84bSDavid du Colombier * when they have empty media (e.g. sata dvd writers);
2319ef1f84bSDavid du Colombier * if so, keep the count zero.
2329ef1f84bSDavid du Colombier *
2339ef1f84bSDavid du Colombier * Read-capacity returns the LBA of the last sector,
2349ef1f84bSDavid du Colombier * therefore the number of sectors must be incremented.
2359ef1f84bSDavid du Colombier */
2369ef1f84bSDavid du Colombier if(unit->sectors != 0)
2379ef1f84bSDavid du Colombier unit->sectors++;
2389ef1f84bSDavid du Colombier ok = 1;
2399ef1f84bSDavid du Colombier break;
2409ef1f84bSDavid du Colombier case 1:
2419ef1f84bSDavid du Colombier ok = 1;
2429ef1f84bSDavid du Colombier break;
2439ef1f84bSDavid du Colombier case 2:
2449ef1f84bSDavid du Colombier continue;
2459ef1f84bSDavid du Colombier }
2469ef1f84bSDavid du Colombier break;
2479ef1f84bSDavid du Colombier }
2489ef1f84bSDavid du Colombier free(p);
2499ef1f84bSDavid du Colombier free(r);
2509ef1f84bSDavid du Colombier
2519ef1f84bSDavid du Colombier if(ok)
2529ef1f84bSDavid du Colombier return ok+retries;
2539ef1f84bSDavid du Colombier else
2549ef1f84bSDavid du Colombier return 0;
2559ef1f84bSDavid du Colombier }
2569ef1f84bSDavid du Colombier
2579ef1f84bSDavid du Colombier int
scsiexec(SDunit * unit,int write,uchar * cmd,int clen,void * data,int * dlen)2589ef1f84bSDavid du Colombier scsiexec(SDunit* unit, int write, uchar* cmd, int clen, void* data, int* dlen)
2599ef1f84bSDavid du Colombier {
2609ef1f84bSDavid du Colombier SDreq *r;
2619ef1f84bSDavid du Colombier int status;
2629ef1f84bSDavid du Colombier
2639ef1f84bSDavid du Colombier if((r = malloc(sizeof(SDreq))) == nil)
2649ef1f84bSDavid du Colombier return SDmalloc;
2659ef1f84bSDavid du Colombier r->unit = unit;
2669ef1f84bSDavid du Colombier r->lun = cmd[1]>>5; /* ??? */
2679ef1f84bSDavid du Colombier r->write = write;
2689ef1f84bSDavid du Colombier memmove(r->cmd, cmd, clen);
2699ef1f84bSDavid du Colombier r->clen = clen;
2709ef1f84bSDavid du Colombier r->data = data;
2719ef1f84bSDavid du Colombier if(dlen)
2729ef1f84bSDavid du Colombier r->dlen = *dlen;
2739ef1f84bSDavid du Colombier r->flags = 0;
2749ef1f84bSDavid du Colombier
2759ef1f84bSDavid du Colombier r->status = ~0;
2769ef1f84bSDavid du Colombier
2779ef1f84bSDavid du Colombier /*
2789ef1f84bSDavid du Colombier * Call the device-specific I/O routine.
2799ef1f84bSDavid du Colombier * There should be no calls to 'error()' below this
2809ef1f84bSDavid du Colombier * which percolate back up.
2819ef1f84bSDavid du Colombier */
2829ef1f84bSDavid du Colombier switch(status = unit->dev->ifc->rio(r)){
2839ef1f84bSDavid du Colombier case SDok:
2849ef1f84bSDavid du Colombier if(dlen)
2859ef1f84bSDavid du Colombier *dlen = r->rlen;
2869ef1f84bSDavid du Colombier /*FALLTHROUGH*/
2879ef1f84bSDavid du Colombier case SDcheck:
2889ef1f84bSDavid du Colombier /*FALLTHROUGH*/
2899ef1f84bSDavid du Colombier default:
2909ef1f84bSDavid du Colombier /*
2919ef1f84bSDavid du Colombier * It's more complicated than this. There are conditions
2929ef1f84bSDavid du Colombier * which are 'ok' but for which the returned status code
2939ef1f84bSDavid du Colombier * is not 'SDok'.
2949ef1f84bSDavid du Colombier * Also, not all conditions require a reqsense, might
2959ef1f84bSDavid du Colombier * need to do a reqsense here and make it available to the
2969ef1f84bSDavid du Colombier * caller somehow.
2979ef1f84bSDavid du Colombier *
2989ef1f84bSDavid du Colombier * Mañana.
2999ef1f84bSDavid du Colombier */
3009ef1f84bSDavid du Colombier break;
3019ef1f84bSDavid du Colombier }
3029ef1f84bSDavid du Colombier sdfree(r);
3039ef1f84bSDavid du Colombier
3049ef1f84bSDavid du Colombier return status;
3059ef1f84bSDavid du Colombier }
3069ef1f84bSDavid du Colombier
307*a58eaef0SDavid du Colombier /* extract lba and count from scsi command block cmd of clen bytes */
308*a58eaef0SDavid du Colombier void
scsilbacount(uchar * cmd,int clen,uvlong * lbap,ulong * countp)309*a58eaef0SDavid du Colombier scsilbacount(uchar *cmd, int clen, uvlong *lbap, ulong *countp)
310*a58eaef0SDavid du Colombier {
311*a58eaef0SDavid du Colombier if (clen == 16) {
312*a58eaef0SDavid du Colombier *lbap = (uvlong)cmd[4]<<40 | (uvlong)cmd[5]<<32 |
313*a58eaef0SDavid du Colombier cmd[6]<<24 | cmd[7]<<16 | cmd[8]<<8 | cmd[9];
314*a58eaef0SDavid du Colombier *countp = cmd[10]<<24 | cmd[11]<<16 | cmd[12]<<8 | cmd[13];
315*a58eaef0SDavid du Colombier } else if (clen == 10) {
316*a58eaef0SDavid du Colombier *lbap = cmd[2]<<24 | cmd[3]<<16 | cmd[4]<<8 | cmd[5];
317*a58eaef0SDavid du Colombier *countp = cmd[7]<<8 | cmd[8];
318*a58eaef0SDavid du Colombier } else
319*a58eaef0SDavid du Colombier panic("scsilbacount: command len %d unexpected", clen);
320*a58eaef0SDavid du Colombier }
321*a58eaef0SDavid du Colombier
3229ef1f84bSDavid du Colombier static void
scsifmt10(SDreq * r,int write,int lun,ulong nb,uvlong bno)3239ef1f84bSDavid du Colombier scsifmt10(SDreq *r, int write, int lun, ulong nb, uvlong bno)
3249ef1f84bSDavid du Colombier {
3259ef1f84bSDavid du Colombier uchar *c;
3269ef1f84bSDavid du Colombier
3279ef1f84bSDavid du Colombier c = r->cmd;
3289ef1f84bSDavid du Colombier if(write == 0)
329a72b0d60SDavid du Colombier c[0] = ScmdExtread;
3309ef1f84bSDavid du Colombier else
331a72b0d60SDavid du Colombier c[0] = ScmdExtwrite;
3329ef1f84bSDavid du Colombier c[1] = lun<<5;
3339ef1f84bSDavid du Colombier c[2] = bno>>24;
3349ef1f84bSDavid du Colombier c[3] = bno>>16;
3359ef1f84bSDavid du Colombier c[4] = bno>>8;
3369ef1f84bSDavid du Colombier c[5] = bno;
3379ef1f84bSDavid du Colombier c[6] = 0;
3389ef1f84bSDavid du Colombier c[7] = nb>>8;
3399ef1f84bSDavid du Colombier c[8] = nb;
3409ef1f84bSDavid du Colombier c[9] = 0;
3419ef1f84bSDavid du Colombier
3429ef1f84bSDavid du Colombier r->clen = 10;
3439ef1f84bSDavid du Colombier }
3449ef1f84bSDavid du Colombier
3459ef1f84bSDavid du Colombier static void
scsifmt16(SDreq * r,int write,int lun,ulong nb,uvlong bno)3469ef1f84bSDavid du Colombier scsifmt16(SDreq *r, int write, int lun, ulong nb, uvlong bno)
3479ef1f84bSDavid du Colombier {
3489ef1f84bSDavid du Colombier uchar *c;
3499ef1f84bSDavid du Colombier
3509ef1f84bSDavid du Colombier c = r->cmd;
3519ef1f84bSDavid du Colombier if(write == 0)
352a72b0d60SDavid du Colombier c[0] = ScmdRead16;
3539ef1f84bSDavid du Colombier else
354a72b0d60SDavid du Colombier c[0] = ScmdWrite16;
3559ef1f84bSDavid du Colombier c[1] = lun<<5; /* so wrong */
3569ef1f84bSDavid du Colombier c[2] = bno>>56;
3579ef1f84bSDavid du Colombier c[3] = bno>>48;
3589ef1f84bSDavid du Colombier c[4] = bno>>40;
3599ef1f84bSDavid du Colombier c[5] = bno>>32;
3609ef1f84bSDavid du Colombier c[6] = bno>>24;
3619ef1f84bSDavid du Colombier c[7] = bno>>16;
3629ef1f84bSDavid du Colombier c[8] = bno>>8;
3639ef1f84bSDavid du Colombier c[9] = bno;
3649ef1f84bSDavid du Colombier c[10] = nb>>24;
3659ef1f84bSDavid du Colombier c[11] = nb>>16;
3669ef1f84bSDavid du Colombier c[12] = nb>>8;
3679ef1f84bSDavid du Colombier c[13] = nb;
3689ef1f84bSDavid du Colombier c[14] = 0;
3699ef1f84bSDavid du Colombier c[15] = 0;
3709ef1f84bSDavid du Colombier
3719ef1f84bSDavid du Colombier r->clen = 16;
3729ef1f84bSDavid du Colombier }
3739ef1f84bSDavid du Colombier
3749ef1f84bSDavid du Colombier long
scsibio(SDunit * unit,int lun,int write,void * data,long nb,uvlong bno)3759ef1f84bSDavid du Colombier scsibio(SDunit* unit, int lun, int write, void* data, long nb, uvlong bno)
3769ef1f84bSDavid du Colombier {
3779ef1f84bSDavid du Colombier SDreq *r;
3789ef1f84bSDavid du Colombier long rlen;
3799ef1f84bSDavid du Colombier
3809ef1f84bSDavid du Colombier if((r = malloc(sizeof(SDreq))) == nil)
3819ef1f84bSDavid du Colombier error(Enomem);
3829ef1f84bSDavid du Colombier r->unit = unit;
3839ef1f84bSDavid du Colombier r->lun = lun;
3849ef1f84bSDavid du Colombier again:
3859ef1f84bSDavid du Colombier r->write = write;
3869ef1f84bSDavid du Colombier if(bno >= (1ULL<<32))
3879ef1f84bSDavid du Colombier scsifmt16(r, write, lun, nb, bno);
3889ef1f84bSDavid du Colombier else
3899ef1f84bSDavid du Colombier scsifmt10(r, write, lun, nb, bno);
3909ef1f84bSDavid du Colombier r->data = data;
3919ef1f84bSDavid du Colombier r->dlen = nb*unit->secsize;
3929ef1f84bSDavid du Colombier r->flags = 0;
3939ef1f84bSDavid du Colombier
3949ef1f84bSDavid du Colombier r->status = ~0;
3959ef1f84bSDavid du Colombier switch(scsirio(r)){
3969ef1f84bSDavid du Colombier default:
3979ef1f84bSDavid du Colombier rlen = -1;
3989ef1f84bSDavid du Colombier break;
3999ef1f84bSDavid du Colombier case 0:
4009ef1f84bSDavid du Colombier rlen = r->rlen;
4019ef1f84bSDavid du Colombier break;
4029ef1f84bSDavid du Colombier case 2:
4039ef1f84bSDavid du Colombier rlen = -1;
4049ef1f84bSDavid du Colombier if(!(r->flags & SDvalidsense))
4059ef1f84bSDavid du Colombier break;
4069ef1f84bSDavid du Colombier switch(r->sense[2] & 0x0F){
4079ef1f84bSDavid du Colombier default:
4089ef1f84bSDavid du Colombier break;
4099ef1f84bSDavid du Colombier case 0x01: /* recovered error */
4109ef1f84bSDavid du Colombier print("%s: recovered error at sector %llud\n",
4119ef1f84bSDavid du Colombier unit->name, bno);
4129ef1f84bSDavid du Colombier rlen = r->rlen;
4139ef1f84bSDavid du Colombier break;
4149ef1f84bSDavid du Colombier case 0x06: /* check condition */
4159ef1f84bSDavid du Colombier /*
4169ef1f84bSDavid du Colombier * Check for a removeable media change.
4179ef1f84bSDavid du Colombier * If so, mark it by zapping the geometry info
4189ef1f84bSDavid du Colombier * to force an online request.
4199ef1f84bSDavid du Colombier */
4209ef1f84bSDavid du Colombier if(r->sense[12] != 0x28 || r->sense[13] != 0)
4219ef1f84bSDavid du Colombier break;
4229ef1f84bSDavid du Colombier if(unit->inquiry[1] & SDinq1removable)
4239ef1f84bSDavid du Colombier unit->sectors = 0;
4249ef1f84bSDavid du Colombier break;
4259ef1f84bSDavid du Colombier case 0x02: /* not ready */
4269ef1f84bSDavid du Colombier /*
4279ef1f84bSDavid du Colombier * If unit is becoming ready,
4289ef1f84bSDavid du Colombier * rather than not not ready, try again.
4299ef1f84bSDavid du Colombier */
4309ef1f84bSDavid du Colombier if(r->sense[12] == 0x04 && r->sense[13] == 0x01)
4319ef1f84bSDavid du Colombier goto again;
4329ef1f84bSDavid du Colombier break;
4339ef1f84bSDavid du Colombier }
4349ef1f84bSDavid du Colombier break;
4359ef1f84bSDavid du Colombier }
4369ef1f84bSDavid du Colombier free(r);
4379ef1f84bSDavid du Colombier
4389ef1f84bSDavid du Colombier return rlen;
4399ef1f84bSDavid du Colombier }
4409ef1f84bSDavid du Colombier
441