📄 scsireq.c
字号:
#include <u.h>#include <libc.h>/* * BUGS: * no luns * and incomplete in many other ways */#include "scsireq.h"enum { Debug = 0,};extern long maxiosize;/* * exabyte tape drives, at least old ones like the 8200 and 8505, * are dumb: you have to read the exact block size on the tape, * they don't take 10-byte SCSI commands, and various other fine points. */extern int exabyte, force6bytecmds;static int debug = Debug;longSRready(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);}longSRrewind(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;}longSRreqsense(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;}longSRformat(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);}longSRrblimits(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 intdirdevrw(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 intseqdevrw(ScsiReq *rp, uchar *cmd, long nbytes){ long n; cmd[1] = rp->flags&Fbfixed? 0x01: 0x00; /* cmd[1]&2 is the SILI bit: don't report `incorrect' block lengths */ n = nbytes/rp->lbsize; cmd[2] = n>>16; cmd[3] = n>>8; cmd[4] = n; cmd[5] = 0; return 6;}longSRread(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){ /* maybe we just read a short record? */ if (exabyte) { fprint(2, "read error\n"); rp->status = STcheck; return n; } if(rp->status != Status_SD || (rp->sense[0] & 0x80) == 0) return -1; if (debug) fprint(2, "SRread: SRrequest failed with sense data; reading byte count from sense\n"); 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; if (debug) fprint(2, "SRread: computing byte count from sense\n"); n = rp->data.count; rp->status = STok; } rp->offset += n/rp->lbsize; return n;}longSRwrite(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 (exabyte) { fprint(2, "write error\n"); rp->status = STcheck; return n; } 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;}longSRseek(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;}longSRfilemark(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);}longSRspace(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);}longSRinquiry(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;}longSRmodeselect6(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);}longSRmodeselect10(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);}longSRmodesense6(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);}longSRmodesense10(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);}longSRstart(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);}longSRrcapacity(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 longrequest(int fd, ScsiPtr *cmd, ScsiPtr *data, int *status){ long n, r; char buf[16]; /* this was an experiment but it seems to be a good idea */ *status = STok; /* send SCSI command */ if(write(fd, cmd->p, cmd->count) != cmd->count){ fprint(2, "scsireq: write cmd: %r\n"); *status = Status_SW; return -1; } /* read or write actual data */ if(data->write) n = write(fd, data->p, data->count); else { n = read(fd, data->p, data->count); if (n < 0) memset(data->p, 0, data->count); else if (n < data->count) memset(data->p + n, 0, data->count - n); } if (n != data->count && n <= 0) fprint(2, "request: tried to %s %ld bytes of data for cmd 0x%x but got %r\n", (data->write? "write": "read"), data->count, cmd->p[0]); else if (n != data->count && (data->write || debug)) fprint(2, "request: %s %ld of %ld bytes of actual data\n", (data->write? "wrote": "read"), n, data->count); /* read status */ buf[0] = '\0'; r = read(fd, buf, sizeof buf-1); if(exabyte && r <= 0 || !exabyte && r < 0){ fprint(2, "scsireq: read status: %r\n"); *status = Status_SW; return -1; } if (r >= 0) buf[r] = '\0'; *status = atoi(buf); if(n < 0 && (exabyte || *status != STcheck)) fprint(2, "scsireq: status 0x%2.2uX: data transfer: %r\n", *status); return n;}longSRrequest(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; if (exabyte) fprint(2, "SRrequest: STcheck, returning -1\n"); return -1; case STbusy: sleep(1000); goto retry; default: fprint(2, "status 0x%2.2uX\n", status); return -1; } return n;}intSRclose(ScsiReq *rp){ if((rp->flags & Fopen) == 0){ rp->status = Status_BADARG; return -1; } close(rp->fd); rp->flags = 0; return 0;}static intdirdevopen(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]; /* some newer dev's don't support 6-byte commands */ if(blocks > 0x1fffff && !force6bytecmds) rp->flags |= Frw10; return 0;}static intseqdevopen(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 (force6bytecmds) rp->flags |= Fmode6; if(!(rp->flags & Fmode6)){ /* try 10-byte command first */ memset(mode, 0, sizeof(mode)); mode[3] = 0x10; /* device-specific param. */ mode[7] = 8; /* block descriptor length */ /* * exabytes can't handle this, and * modeselect(10) is optional. */ if(SRmodeselect10(rp, mode, sizeof(mode)) != -1){ rp->lbsize = 1; return 0; /* success */ } /* can't do 10-byte commands, back off to 6-byte ones */ rp->flags |= Fmode6; } /* 6-byte command */ memset(mode, 0, sizeof(mode)); mode[2] = 0x10; /* device-specific param. */ mode[3] = 8; /* block descriptor length */ /* * bsd sez exabytes need this bit (NBE) in vendor-specific * page (0), but so far we haven't needed it. */ if (0) mode[12] |= 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 intwormdevopen(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;}intSRopenraw(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;}intSRopen(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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -