int sdmodesense(SDreq *r, uchar *cmd, void *info, int ilen) { int len; uchar *data; /* * Fake a vendor-specific request with page code 0, * return the drive info. */ if((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F) return sdsetsense(r, SDcheck, 0x05, 0x24, 0); len = (cmd[7]<<8)|cmd[8]; if(len == 0) return SDok; if(len < 8+ilen) return sdsetsense(r, SDcheck, 0x05, 0x1A, 0); if(r->data == nil || r->dlen < len) return sdsetsense(r, SDcheck, 0x05, 0x20, 1); data = r->data; memset(data, 0, 8); data[0] = ilen>>8; data[1] = ilen; if(ilen) memmove(data+8, info, ilen); r->rlen = 8+ilen; return sdsetsense(r, SDok, 0, 0, 0); }
static int aoerio(SDreq *r) { int i, count, rw; uvlong lba; Ctlr *c; SDunit *u; u = r->unit; c = u->dev->ctlr; // if(c->feat & Datapi) // return aoeriopkt(r, d); if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91) { qlock(c); i = flushcache(c); qunlock(c); if(i == 0) return sdsetsense(r, SDok, 0, 0, 0); return sdsetsense(r, SDcheck, 3, 0xc, 2); } if((i = sdfakescsi(r)) != SDnostatus) { r->status = i; return i; } if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus) return i; r->rlen = aoebio(u, r->lun, rw == SDwrite, r->data, count, lba); return r->status = SDok; }
int sdfakescsirw(SDreq *r, uvlong *llba, int *nsec, int *rwp) { uchar *c; int rw, count; uvlong lba; c = r->cmd; rw = SDread; if((c[0] & 0xf) == 0xa) rw = SDwrite; switch(c[0]){ case 0x08: /* read6 */ case 0x0a: lba = (c[1] & 0xf)<<16 | c[2]<<8 | c[3]; count = c[4]; break; case 0x28: /* read10 */ case 0x2a: lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5]; count = c[7]<<8 | c[8]; break; case 0xa8: /* read12 */ case 0xaa: lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5]; count = c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9]; break; case 0x88: /* read16 */ case 0x8a: /* ata commands only go to 48-bit lba */ if(c[2] || c[3]) return sdsetsense(r, SDcheck, 3, 0xc, 2); lba = (uvlong)c[4]<<40 | (uvlong)c[5]<<32; lba |= c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9]; count = c[10]<<24 | c[11]<<16 | c[12]<<8 | c[13]; break; default: print("%s: bad cmd 0x%.2ux\n", r->unit->name, c[0]); r->status = sdsetsense(r, SDcheck, 0x05, 0x20, 0); return SDcheck; } if(r->data == nil) return SDok; if(r->dlen < count * r->unit->secsize) count = r->dlen/r->unit->secsize; if(rwp) *rwp = rw; *llba = lba; *nsec = count; return SDnostatus; }
static int viorio(SDreq *r) { int i, count, rw; uvlong lba; SDunit *u; u = r->unit; if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91){ if(vioreq(u->dev->ctlr, 4, nil, 0, 0, 0) != 0) return sdsetsense(r, SDcheck, 3, 0xc, 2); return sdsetsense(r, SDok, 0, 0, 0); } if((i = sdfakescsi(r)) != SDnostatus) return r->status = i; if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus) return i; r->rlen = viobio(u, r->lun, rw == SDwrite, r->data, count, lba); return r->status = SDok; }
static int looprio(SDreq *r) { int i, count, rw; uvlong lba; SDunit *u; u = r->unit; if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91) return sdsetsense(r, SDok, 0, 0, 0); if((i = sdfakescsi(r)) != SDnostatus) return r->status = i; if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus) return i; r->rlen = loopbio(u, r->lun, rw == SDwrite, r->data, count, lba); return r->status = SDok; }
static int aoerio(SDreq *r) { int i, count; uvlong lba; char *name; uchar *cmd; long (*rio)(Chan*, void*, long, vlong); Ctlr *c; SDunit *unit; unit = r->unit; c = unit->dev->ctlr; // if(c->feat & Datapi) // return aoeriopkt(r, d); cmd = r->cmd; name = unit->name; if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91){ // qlock(c); // i = flushcache(); // qunlock(c); // if(i == 0) // return sdsetsense(r, SDok, 0, 0, 0); return sdsetsense(r, SDcheck, 3, 0xc, 2); } if((i = sdfakescsi(r, c->ident, sizeof c->ident)) != SDnostatus){ r->status = i; return i; } switch(*cmd){ case 0x88: case 0x28: rio = devtab[c->c->type]->read; break; case 0x8a: case 0x2a: rio = devtab[c->c->type]->write; break; default: print("%s: bad cmd %#.2ux\n", name, cmd[0]); r->status = SDcheck; return SDcheck; } if(r->data == nil) return SDok; if(r->clen == 16){ if(cmd[2] || cmd[3]) return sdsetsense(r, SDcheck, 3, 0xc, 2); lba = (uvlong)cmd[4]<<40 | (uvlong)cmd[5]<<32; lba |= cmd[6]<<24 | cmd[7]<<16 | cmd[8]<<8 | cmd[9]; count = cmd[10]<<24 | cmd[11]<<16 | cmd[12]<<8 | cmd[13]; }else{ lba = cmd[2]<<24 | cmd[3]<<16 | cmd[4]<<8 | cmd[5]; count = cmd[7]<<8 | cmd[8]; } count *= Aoesectsz; if(r->dlen < count) count = r->dlen & ~0x1ff; if(waserror()){ if(strcmp(up->errstr, Echange) == 0 || strcmp(up->errstr, Eaoedown) == 0) unit->sectors = 0; nexterror(); } r->rlen = rio(c->c, r->data, count, Aoesectsz * lba); poperror(); r->status = SDok; return SDok; }
int sdfakescsi(SDreq *r, void *info, int ilen) { uchar *cmd, *p; uvlong len; SDunit *unit; cmd = r->cmd; r->rlen = 0; unit = r->unit; /* * Rewrite read(6)/write(6) into read(10)/write(10). */ switch(cmd[0]){ case 0x08: /* read */ case 0x0A: /* write */ cmd[9] = 0; cmd[8] = cmd[4]; cmd[7] = 0; cmd[6] = 0; cmd[5] = cmd[3]; cmd[4] = cmd[2]; cmd[3] = cmd[1] & 0x0F; cmd[2] = 0; cmd[1] &= 0xE0; cmd[0] |= 0x20; break; } /* * Map SCSI commands into ATA commands for discs. * Fail any command with a LUN except INQUIRY which * will return 'logical unit not supported'. */ if((cmd[1]>>5) && cmd[0] != 0x12) return sdsetsense(r, SDcheck, 0x05, 0x25, 0); switch(cmd[0]){ default: return sdsetsense(r, SDcheck, 0x05, 0x20, 0); case 0x00: /* test unit ready */ return sdsetsense(r, SDok, 0, 0, 0); case 0x03: /* request sense */ if(cmd[4] < sizeof unit->sense) len = cmd[4]; else len = sizeof unit->sense; if(r->data && r->dlen >= len){ memmove(r->data, unit->sense, len); r->rlen = len; } return sdsetsense(r, SDok, 0, 0, 0); case 0x12: /* inquiry */ if(cmd[4] < sizeof unit->inquiry) len = cmd[4]; else len = sizeof unit->inquiry; if(r->data && r->dlen >= len){ memmove(r->data, unit->inquiry, len); r->rlen = len; } return sdsetsense(r, SDok, 0, 0, 0); case 0x1B: /* start/stop unit */ /* * nop for now, can use power management later. */ return sdsetsense(r, SDok, 0, 0, 0); case 0x25: /* read capacity */ if((cmd[1] & 0x01) || cmd[2] || cmd[3]) return sdsetsense(r, SDcheck, 0x05, 0x24, 0); if(r->data == nil || r->dlen < 8) return sdsetsense(r, SDcheck, 0x05, 0x20, 1); /* * Read capacity returns the LBA of the last sector. */ len = unit->sectors - 1; p = r->data; *p++ = len>>24; *p++ = len>>16; *p++ = len>>8; *p++ = len; len = 512; *p++ = len>>24; *p++ = len>>16; *p++ = len>>8; *p++ = len; r->rlen = p - (uchar*)r->data; return sdsetsense(r, SDok, 0, 0, 0); case 0x9E: /* long read capacity */ if((cmd[1] & 0x01) || cmd[2] || cmd[3]) return sdsetsense(r, SDcheck, 0x05, 0x24, 0); if(r->data == nil || r->dlen < 8) return sdsetsense(r, SDcheck, 0x05, 0x20, 1); /* * Read capcity returns the LBA of the last sector. */ len = unit->sectors - 1; p = r->data; *p++ = len>>56; *p++ = len>>48; *p++ = len>>40; *p++ = len>>32; *p++ = len>>24; *p++ = len>>16; *p++ = len>>8; *p++ = len; len = 512; *p++ = len>>24; *p++ = len>>16; *p++ = len>>8; *p++ = len; r->rlen = p - (uchar*)r->data; return sdsetsense(r, SDok, 0, 0, 0); case 0x5A: /* mode sense */ return sdmodesense(r, cmd, info, ilen); case 0x28: /* read */ case 0x2A: /* write */ case 0x88: /* read16 */ case 0x8a: /* write16 */ return SDnostatus; } }
int sdfakescsi(SDreq *r) { uchar *cmd, *p; uvlong len; SDunit *unit; cmd = r->cmd; r->rlen = 0; unit = r->unit; /* * Map SCSI commands into ATA commands for discs. * Fail any command with a LUN except INQUIRY which * will return 'logical unit not supported'. */ if((cmd[1]>>5) && cmd[0] != 0x12) return sdsetsense(r, SDcheck, 0x05, 0x25, 0); switch(cmd[0]){ default: return sdsetsense(r, SDcheck, 0x05, 0x20, 0); case 0x00: /* test unit ready */ return sdsetsense(r, SDok, 0, 0, 0); case 0x03: /* request sense */ if(cmd[4] < sizeof unit->sense) len = cmd[4]; else len = sizeof unit->sense; if(r->data && r->dlen >= len){ memmove(r->data, unit->sense, len); r->rlen = len; } return sdsetsense(r, SDok, 0, 0, 0); case 0x12: /* inquiry */ if(cmd[4] < sizeof unit->inquiry) len = cmd[4]; else len = sizeof unit->inquiry; if(r->data && r->dlen >= len){ memmove(r->data, unit->inquiry, len); r->rlen = len; } return sdsetsense(r, SDok, 0, 0, 0); case 0x1B: /* start/stop unit */ /* * nop for now, can use power management later. */ return sdsetsense(r, SDok, 0, 0, 0); case 0x25: /* read capacity */ if((cmd[1] & 0x01) || cmd[2] || cmd[3]) return sdsetsense(r, SDcheck, 0x05, 0x24, 0); if(r->data == nil || r->dlen < 8) return sdsetsense(r, SDcheck, 0x05, 0x20, 1); /* * Read capacity returns the LBA of the last sector. */ len = unit->sectors; if(len >= 0xffffffff) len = 0xffffffff; else if(len > 0) len--; p = r->data; *p++ = len>>24; *p++ = len>>16; *p++ = len>>8; *p++ = len; len = unit->secsize; *p++ = len>>24; *p++ = len>>16; *p++ = len>>8; *p++ = len; r->rlen = p - (uchar*)r->data; return sdsetsense(r, SDok, 0, 0, 0); case 0x9E: /* long read capacity */ if((cmd[1] & 0x01) || cmd[2] || cmd[3]) return sdsetsense(r, SDcheck, 0x05, 0x24, 0); if(r->data == nil || r->dlen < 8) return sdsetsense(r, SDcheck, 0x05, 0x20, 1); /* * Read capcity returns the LBA of the last sector. */ len = unit->sectors; if(len > 0) len--; p = r->data; *p++ = len>>56; *p++ = len>>48; *p++ = len>>40; *p++ = len>>32; *p++ = len>>24; *p++ = len>>16; *p++ = len>>8; *p++ = len; len = unit->secsize; *p++ = len>>24; *p++ = len>>16; *p++ = len>>8; *p++ = len; r->rlen = p - (uchar*)r->data; return sdsetsense(r, SDok, 0, 0, 0); case 0x35: /* synchronize cache */ case 0x91: return sdsetsense(r, SDok, 0, 0, 0); case 0x08: /* read6 */ case 0x0a: /* write6 */ case 0x28: /* read10 */ case 0x2a: /* write10 */ case 0xa8: /* read12 */ case 0xaa: /* write12 */ case 0x88: /* read16 */ case 0x8a: /* write16 */ return SDnostatus; } }