123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640 |
- #include <u.h>
- #include <libc.h>
- /*
- * BUGS:
- * no luns
- * and incomplete in many other ways
- */
- #include "scsireq.h"
- long
- SRready(ScsiReq *rp)
- {
- uchar cmd[6];
- memset(cmd, 0, sizeof(cmd));
- rp->cmd.p = cmd;
- rp->cmd.count = sizeof(cmd);
- rp->data.p = cmd;
- rp->data.count = 0;
- rp->data.write = 1;
- return SRrequest(rp);
- }
- long
- SRrewind(ScsiReq *rp)
- {
- uchar cmd[6];
- memset(cmd, 0, sizeof(cmd));
- cmd[0] = ScmdRewind;
- rp->cmd.p = cmd;
- rp->cmd.count = sizeof(cmd);
- rp->data.p = cmd;
- rp->data.count = 0;
- rp->data.write = 1;
- if(SRrequest(rp) >= 0){
- rp->offset = 0;
- return 0;
- }
- return -1;
- }
- long
- SRreqsense(ScsiReq *rp)
- {
- uchar cmd[6];
- ScsiReq req;
- long status;
- if(rp->status == Status_SD){
- rp->status = STok;
- return 0;
- }
- memset(cmd, 0, sizeof(cmd));
- cmd[0] = ScmdRsense;
- cmd[4] = sizeof(req.sense);
- memset(&req, 0, sizeof(req));
- req.fd = rp->fd;
- req.cmd.p = cmd;
- req.cmd.count = sizeof(cmd);
- req.data.p = rp->sense;
- req.data.count = sizeof(rp->sense);
- req.data.write = 0;
- status = SRrequest(&req);
- rp->status = req.status;
- return status;
- }
- long
- SRformat(ScsiReq *rp)
- {
- uchar cmd[6];
- memset(cmd, 0, sizeof(cmd));
- cmd[0] = ScmdFormat;
- rp->cmd.p = cmd;
- rp->cmd.count = sizeof(cmd);
- rp->data.p = cmd;
- rp->data.count = 6;
- rp->data.write = 0;
- return SRrequest(rp);
- }
- long
- SRrblimits(ScsiReq *rp, uchar *list)
- {
- uchar cmd[6];
- memset(cmd, 0, sizeof(cmd));
- cmd[0] = ScmdRblimits;
- rp->cmd.p = cmd;
- rp->cmd.count = sizeof(cmd);
- rp->data.p = list;
- rp->data.count = 6;
- rp->data.write = 0;
- return SRrequest(rp);
- }
- static int
- dirdevrw(ScsiReq *rp, uchar *cmd, long nbytes)
- {
- long n;
- n = nbytes/rp->lbsize;
- if(rp->offset <= 0x1fffff && n <= 256 && (rp->flags & Frw10) == 0){
- cmd[1] = rp->offset>>16;
- cmd[2] = rp->offset>>8;
- cmd[3] = rp->offset;
- cmd[4] = n;
- cmd[5] = 0;
- return 6;
- }
- cmd[0] |= ScmdExtread;
- cmd[1] = 0;
- cmd[2] = rp->offset>>24;
- cmd[3] = rp->offset>>16;
- cmd[4] = rp->offset>>8;
- cmd[5] = rp->offset;
- cmd[6] = 0;
- cmd[7] = n>>8;
- cmd[8] = n;
- cmd[9] = 0;
- return 10;
- }
- static int
- seqdevrw(ScsiReq *rp, uchar *cmd, long nbytes)
- {
- long n;
- cmd[1] = rp->flags&Fbfixed? 0x01: 0x00;
- n = nbytes/rp->lbsize;
- cmd[2] = n>>16;
- cmd[3] = n>>8;
- cmd[4] = n;
- cmd[5] = 0;
- return 6;
- }
- long
- SRread(ScsiReq *rp, void *buf, long nbytes)
- {
- uchar cmd[10];
- long n;
- if((nbytes % rp->lbsize) || nbytes > MaxIOsize){
- rp->status = Status_BADARG;
- return -1;
- }
- cmd[0] = ScmdRead;
- if(rp->flags & Fseqdev)
- rp->cmd.count = seqdevrw(rp, cmd, nbytes);
- else
- rp->cmd.count = dirdevrw(rp, cmd, nbytes);
- rp->cmd.p = cmd;
- rp->data.p = buf;
- rp->data.count = nbytes;
- rp->data.write = 0;
- if((n = SRrequest(rp)) == -1){
- if(rp->status != Status_SD || (rp->sense[0] & 0x80) == 0)
- return -1;
- n = ((rp->sense[3]<<24)
- | (rp->sense[4]<<16)
- | (rp->sense[5]<<8)
- | rp->sense[6])
- * rp->lbsize;
- if(!(rp->flags & Fseqdev))
- return -1;
- if(rp->sense[2] == 0x80 || rp->sense[2] == 0x08)
- rp->data.count = nbytes - n;
- else if(rp->sense[2] == 0x20 && n > 0)
- rp->data.count = nbytes - n;
- else
- return -1;
- n = rp->data.count;
- rp->status = STok;
- }
- rp->offset += n/rp->lbsize;
- return n;
- }
- long
- SRwrite(ScsiReq *rp, void *buf, long nbytes)
- {
- uchar cmd[10];
- long n;
- if((nbytes % rp->lbsize) || nbytes > MaxIOsize){
- rp->status = Status_BADARG;
- return -1;
- }
- cmd[0] = ScmdWrite;
- if(rp->flags & Fseqdev)
- rp->cmd.count = seqdevrw(rp, cmd, nbytes);
- else
- rp->cmd.count = dirdevrw(rp, cmd, nbytes);
- rp->cmd.p = cmd;
- rp->data.p = buf;
- rp->data.count = nbytes;
- rp->data.write = 1;
- if((n = SRrequest(rp)) == -1){
- if(rp->status != Status_SD || rp->sense[2] != 0x40)
- return -1;
- if(rp->sense[0] & 0x80){
- n -= ((rp->sense[3]<<24)
- | (rp->sense[4]<<16)
- | (rp->sense[5]<<8)
- | rp->sense[6])
- * rp->lbsize;
- rp->data.count = nbytes - n;
- }
- else
- rp->data.count = nbytes;
- n = rp->data.count;
- }
- rp->offset += n/rp->lbsize;
- return n;
- }
- long
- SRseek(ScsiReq *rp, long offset, int type)
- {
- uchar cmd[10];
- switch(type){
- case 0:
- break;
- case 1:
- offset += rp->offset;
- if(offset >= 0)
- break;
- /*FALLTHROUGH*/
- default:
- rp->status = Status_BADARG;
- return -1;
- }
- if(offset <= 0x1fffff && (rp->flags & Frw10) == 0){
- cmd[0] = ScmdSeek;
- cmd[1] = (offset>>16) & 0x1F;
- cmd[2] = offset>>8;
- cmd[3] = offset;
- cmd[4] = 0;
- cmd[5] = 0;
- rp->cmd.count = 6;
- }else{
- cmd[0] = ScmdExtseek;
- cmd[1] = 0;
- cmd[2] = offset>>24;
- cmd[3] = offset>>16;
- cmd[4] = offset>>8;
- cmd[5] = offset;
- cmd[6] = 0;
- cmd[7] = 0;
- cmd[8] = 0;
- cmd[9] = 0;
- rp->cmd.count = 10;
- }
- rp->cmd.p = cmd;
- rp->data.p = cmd;
- rp->data.count = 0;
- rp->data.write = 1;
- SRrequest(rp);
- if(rp->status == STok)
- return rp->offset = offset;
- return -1;
- }
- long
- SRfilemark(ScsiReq *rp, ulong howmany)
- {
- uchar cmd[6];
- cmd[0] = ScmdFmark;
- cmd[1] = 0;
- cmd[2] = howmany>>16;
- cmd[3] = howmany>>8;
- cmd[4] = howmany;
- cmd[5] = 0;
- rp->cmd.p = cmd;
- rp->cmd.count = sizeof(cmd);
- rp->data.p = cmd;
- rp->data.count = 0;
- rp->data.write = 1;
- return SRrequest(rp);
- }
- long
- SRspace(ScsiReq *rp, uchar code, long howmany)
- {
- uchar cmd[6];
- cmd[0] = ScmdSpace;
- cmd[1] = code;
- cmd[2] = howmany>>16;
- cmd[3] = howmany>>8;
- cmd[4] = howmany;
- cmd[5] = 0;
- rp->cmd.p = cmd;
- rp->cmd.count = sizeof(cmd);
- rp->data.p = cmd;
- rp->data.count = 0;
- rp->data.write = 1;
- /*
- * what about rp->offset?
- */
- return SRrequest(rp);
- }
- long
- SRinquiry(ScsiReq *rp)
- {
- uchar cmd[6];
- memset(cmd, 0, sizeof(cmd));
- cmd[0] = ScmdInq;
- cmd[4] = sizeof(rp->inquiry);
- rp->cmd.p = cmd;
- rp->cmd.count = sizeof(cmd);
- rp->data.p = rp->inquiry;
- rp->data.count = sizeof(rp->inquiry);
- rp->data.write = 0;
- if(SRrequest(rp) >= 0){
- rp->flags |= Finqok;
- return 0;
- }
- rp->flags &= ~Finqok;
- return -1;
- }
- long
- SRmodeselect6(ScsiReq *rp, uchar *list, long nbytes)
- {
- uchar cmd[6];
- memset(cmd, 0, sizeof(cmd));
- cmd[0] = ScmdMselect6;
- if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)
- cmd[1] = 0x10;
- cmd[4] = nbytes;
- rp->cmd.p = cmd;
- rp->cmd.count = sizeof(cmd);
- rp->data.p = list;
- rp->data.count = nbytes;
- rp->data.write = 1;
- return SRrequest(rp);
- }
- long
- SRmodeselect10(ScsiReq *rp, uchar *list, long nbytes)
- {
- uchar cmd[10];
- memset(cmd, 0, sizeof(cmd));
- if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)
- cmd[1] = 0x10;
- cmd[0] = ScmdMselect10;
- cmd[7] = nbytes>>8;
- cmd[8] = nbytes;
- rp->cmd.p = cmd;
- rp->cmd.count = sizeof(cmd);
- rp->data.p = list;
- rp->data.count = nbytes;
- rp->data.write = 1;
- return SRrequest(rp);
- }
- long
- SRmodesense6(ScsiReq *rp, uchar page, uchar *list, long nbytes)
- {
- uchar cmd[6];
- memset(cmd, 0, sizeof(cmd));
- cmd[0] = ScmdMsense6;
- cmd[2] = page;
- cmd[4] = nbytes;
- rp->cmd.p = cmd;
- rp->cmd.count = sizeof(cmd);
- rp->data.p = list;
- rp->data.count = nbytes;
- rp->data.write = 0;
- return SRrequest(rp);
- }
- long
- SRmodesense10(ScsiReq *rp, uchar page, uchar *list, long nbytes)
- {
- uchar cmd[10];
- memset(cmd, 0, sizeof(cmd));
- cmd[0] = ScmdMsense10;
- cmd[2] = page;
- cmd[7] = nbytes>>8;
- cmd[8] = nbytes;
- rp->cmd.p = cmd;
- rp->cmd.count = sizeof(cmd);
- rp->data.p = list;
- rp->data.count = nbytes;
- rp->data.write = 0;
- return SRrequest(rp);
- }
- long
- SRstart(ScsiReq *rp, uchar code)
- {
- uchar cmd[6];
- memset(cmd, 0, sizeof(cmd));
- cmd[0] = ScmdStart;
- cmd[4] = code;
- rp->cmd.p = cmd;
- rp->cmd.count = sizeof(cmd);
- rp->data.p = cmd;
- rp->data.count = 0;
- rp->data.write = 1;
- return SRrequest(rp);
- }
- long
- SRrcapacity(ScsiReq *rp, uchar *data)
- {
- uchar cmd[10];
- memset(cmd, 0, sizeof(cmd));
- cmd[0] = ScmdRcapacity;
- rp->cmd.p = cmd;
- rp->cmd.count = sizeof(cmd);
- rp->data.p = data;
- rp->data.count = 8;
- rp->data.write = 0;
- return SRrequest(rp);
- }
- static long
- request(int fd, ScsiPtr *cmd, ScsiPtr *data, int *status)
- {
- long n;
- char buf[16];
- if(write(fd, cmd->p, cmd->count) != cmd->count){
- fprint(2, "scsireq: write cmd: %r\n");
- *status = Status_SW;
- return -1;
- }
- if(data->write)
- n = write(fd, data->p, data->count);
- else
- n = read(fd, data->p, data->count);
- if(read(fd, buf, sizeof(buf)) < 0){
- fprint(2, "scsireq: read status: %r\n");
- *status = Status_SW;
- return -1;
- }
- buf[sizeof(buf)-1] = '\0';
- *status = atoi(buf);
- if(n < 0 && *status != STcheck)
- fprint(2, "scsireq: status 0x%2.2uX: data transfer: %r\n", *status);
- return n;
- }
- long
- SRrequest(ScsiReq *rp)
- {
- long n;
- int status;
- retry:
- n = request(rp->fd, &rp->cmd, &rp->data, &status);
- switch(rp->status = status){
- case STok:
- rp->data.count = n;
- break;
- case STcheck:
- if(rp->cmd.p[0] != ScmdRsense && SRreqsense(rp) != -1)
- rp->status = Status_SD;
- return -1;
- case STbusy:
- sleep(1000);
- goto retry;
- default:
- fprint(2, "status 0x%2.2uX\n", status);
- return -1;
- }
- return n;
- }
- int
- SRclose(ScsiReq *rp)
- {
- if((rp->flags & Fopen) == 0){
- rp->status = Status_BADARG;
- return -1;
- }
- close(rp->fd);
- rp->flags = 0;
- return 0;
- }
- static int
- dirdevopen(ScsiReq *rp)
- {
- ulong blocks;
- uchar data[8];
- if(SRstart(rp, 1) == -1 || SRrcapacity(rp, data) == -1)
- return -1;
- rp->lbsize = (data[4]<<28)|(data[5]<<16)|(data[6]<<8)|data[7];
- blocks = (data[0]<<24)|(data[1]<<16)|(data[2]<<8)|data[3];
- if(blocks > 0x1fffff)
- rp->flags |= Frw10; /* some newer devices don't support 6-byte commands */
- return 0;
- }
- static int
- seqdevopen(ScsiReq *rp)
- {
- uchar mode[16], limits[6];
- if(SRrblimits(rp, limits) == -1)
- return -1;
- if(limits[1] || limits[2] != limits[4] || limits[3] != limits[5]){
- /*
- * On some older hardware the optional 10-byte
- * modeselect command isn't implemented.
- */
- if(!(rp->flags & Fmode6)){
- memset(mode, 0, sizeof(mode));
- mode[3] = 0x10;
- mode[7] = 8;
- if(SRmodeselect10(rp, mode, sizeof(mode)) != -1){
- rp->lbsize = 1;
- return 0;
- }
- rp->flags |= Fmode6;
- }
- memset(mode, 0, sizeof(mode));
- mode[2] = 0x10;
- mode[3] = 8;
- if(SRmodeselect6(rp, mode, 4+8) == -1)
- return -1;
- rp->lbsize = 1;
- }
- else{
- rp->flags |= Fbfixed;
- rp->lbsize = (limits[4]<<8)|limits[5];
- }
- return 0;
- }
- static int
- wormdevopen(ScsiReq *rp)
- {
- uchar list[MaxDirData];
- long status;
- if(SRstart(rp, 1) == -1)
- return -1;
- if((status = SRmodesense10(rp, 0x3F, list, sizeof(list))) == -1)
- return -1;
- if(((list[6]<<8)|list[3]) < 8)
- rp->lbsize = 2048;
- else
- rp->lbsize = (list[13]<<8)|(list[14]<<8)|list[15];
- return status;
- }
- int
- SRopenraw(ScsiReq *rp, char *unit)
- {
- char name[128];
- if(rp->flags & Fopen){
- rp->status = Status_BADARG;
- return -1;
- }
- memset(rp, 0, sizeof(*rp));
- rp->unit = unit;
- sprint(name, "%s/raw", unit);
- if((rp->fd = open(name, ORDWR)) == -1){
- rp->status = STtimeout;
- return -1;
- }
- rp->flags = Fopen;
- return 0;
- }
- int
- SRopen(ScsiReq *rp, char *unit)
- {
- if(SRopenraw(rp, unit) == -1)
- return -1;
- SRready(rp);
- if(SRinquiry(rp) >= 0){
- switch(rp->inquiry[0]){
- default:
- fprint(2, "unknown device type 0x%.2x\n", rp->inquiry[0]);
- rp->status = Status_SW;
- break;
- case 0x00: /* Direct access (disk) */
- case 0x05: /* CD-ROM */
- case 0x07: /* rewriteable MO */
- if(dirdevopen(rp) == -1)
- break;
- return 0;
- case 0x01: /* Sequential eg: tape */
- rp->flags |= Fseqdev;
- if(seqdevopen(rp) == -1)
- break;
- return 0;
- case 0x02: /* Printer */
- rp->flags |= Fprintdev;
- return 0;
- case 0x04: /* Worm */
- rp->flags |= Fwormdev;
- if(wormdevopen(rp) == -1)
- break;
- return 0;
- case 0x08: /* medium-changer */
- rp->flags |= Fchanger;
- return 0;
- }
- }
- SRclose(rp);
- return -1;
- }
|