2 * This is /sys/src/cmd/scuzz/scsireq.c
3 * changed to add more debug support, to keep
4 * disk compiling without a scuzz that includes these changes.
5 * Also, this includes minor tweaks for usb:
6 * we set req.lun/unit to rp->lun/unit in SRreqsense
7 * we set the rp->sense[0] bit Sd0valid in SRreqsense
8 * This does not use libdisk to retrieve the scsi error to make
9 * user see the diagnostics if we boot with debug enabled.
13 * and incomplete in many other ways
26 * exabyte tape drives, at least old ones like the 8200 and 8505,
27 * are dumb: you have to read the exact block size on the tape,
28 * they don't take 10-byte SCSI commands, and various other fine points.
30 extern int exabyte, force6bytecmds;
32 static int debug = Debug;
34 static char *scmdnames[256] = {
36 [ScmdRewind] "Rewind",
37 [ScmdRsense] "Rsense",
38 [ScmdFormat] "Format",
39 [ScmdRblimits] "Rblimits",
46 [ScmdMselect6] "Mselect6",
47 [ScmdMselect10] "Mselect10",
48 [ScmdMsense6] "Msense6",
49 [ScmdMsense10] "Msense10",
51 [ScmdRcapacity] "Rcapacity",
52 [ScmdRcapacity16] "Rcap16",
53 [ScmdExtread] "Extread",
54 [ScmdExtwrite] "Extwrite",
55 [ScmdExtseek] "Extseek",
57 [ScmdSynccache] "Synccache",
59 [ScmdRdiscinfo] "Rdiscinfo",
60 [ScmdRtrackinfo] "Rtrackinfo",
61 [ScmdReserve] "Reserve",
64 [ScmdCDpause] "CDpause",
65 [ScmdCDstop] "CDstop",
66 [ScmdCDplay] "CDplay",
67 [ScmdCDload] "CDload",
68 [ScmdCDscan] "CDscan",
69 [ScmdCDstatus] "CDstatus",
70 [Scmdgetconf] "getconf",
78 memset(cmd, 0, sizeof cmd);
80 rp->cmd.count = sizeof cmd;
92 memset(cmd, 0, sizeof cmd);
95 rp->cmd.count = sizeof cmd;
99 if(SRrequest(rp) >= 0){
107 SRreqsense(ScsiReq *rp)
113 if(rp->status == Status_SD){
117 memset(cmd, 0, sizeof cmd);
119 cmd[4] = sizeof(req.sense);
120 memset(&req, 0, sizeof(req));
128 req.cmd.count = sizeof cmd;
129 req.data.p = rp->sense;
130 req.data.count = sizeof(rp->sense);
132 status = SRrequest(&req);
133 rp->status = req.status;
135 rp->sense[0] |= Sd0valid;
140 SRformat(ScsiReq *rp)
144 memset(cmd, 0, sizeof cmd);
147 rp->cmd.count = sizeof cmd;
151 return SRrequest(rp);
155 SRrblimits(ScsiReq *rp, uchar *list)
159 memset(cmd, 0, sizeof cmd);
160 cmd[0] = ScmdRblimits;
162 rp->cmd.count = sizeof cmd;
166 return SRrequest(rp);
170 dirdevrw(ScsiReq *rp, uchar *cmd, long nbytes)
174 n = nbytes / rp->lbsize;
175 if(rp->offset <= Max24off && n <= 256 && (rp->flags & Frw10) == 0){
176 PUTBE24(cmd+1, rp->offset);
181 cmd[0] |= ScmdExtread;
183 PUTBELONG(cmd+2, rp->offset);
192 seqdevrw(ScsiReq *rp, uchar *cmd, long nbytes)
196 /* don't set Cmd1sili; we want the ILI bit instead of a fatal error */
197 cmd[1] = rp->flags&Fbfixed? Cmd1fixed: 0;
198 n = nbytes / rp->lbsize;
204 extern int diskdebug;
207 SRread(ScsiReq *rp, void *buf, long nbytes)
212 if(rp->lbsize == 0 || (nbytes % rp->lbsize) || nbytes > Maxiosize){
214 if (nbytes % rp->lbsize)
215 fprint(2, "disk: i/o size %ld %% %ld != 0\n",
218 fprint(2, "disk: i/o size %ld > %d\n",
220 rp->status = Status_BADARG;
224 /* set up scsi read cmd */
226 if(rp->flags & Fseqdev)
227 rp->cmd.count = seqdevrw(rp, cmd, nbytes);
229 rp->cmd.count = dirdevrw(rp, cmd, nbytes);
232 rp->data.count = nbytes;
237 if(n != -1){ /* it worked? */
238 rp->offset += n / rp->lbsize;
242 /* request failed; maybe we just read a short record? */
244 fprint(2, "read error\n");
245 rp->status = STcheck;
248 if(rp->status != Status_SD || !(rp->sense[0] & Sd0valid))
250 /* compute # of bytes not read */
251 n = GETBELONG(rp->sense+3) * rp->lbsize;
252 if(!(rp->flags & Fseqdev))
255 /* device is a tape or something similar */
256 if (rp->sense[2] == Sd2filemark || rp->sense[2] == 0x08 ||
257 rp->sense[2] & Sd2ili && n > 0)
258 rp->data.count = nbytes - n;
262 if (!rp->readblock++ || debug)
263 fprint(2, "SRread: tape data count %ld%s\n", n,
264 (rp->sense[2] & Sd2ili? " with ILI": ""));
266 rp->offset += n / rp->lbsize;
271 SRwrite(ScsiReq *rp, void *buf, long nbytes)
276 if(rp->lbsize == 0 || (nbytes % rp->lbsize) || nbytes > Maxiosize){
278 if (nbytes % rp->lbsize)
279 fprint(2, "disk: i/o size %ld %% %ld != 0\n",
282 fprint(2, "disk: i/o size %ld > %d\n",
284 rp->status = Status_BADARG;
288 /* set up scsi write cmd */
290 if(rp->flags & Fseqdev)
291 rp->cmd.count = seqdevrw(rp, cmd, nbytes);
293 rp->cmd.count = dirdevrw(rp, cmd, nbytes);
296 rp->data.count = nbytes;
300 if((n = SRrequest(rp)) == -1){
302 fprint(2, "write error\n");
303 rp->status = STcheck;
306 if(rp->status != Status_SD || rp->sense[2] != Sd2eom)
308 if(rp->sense[0] & Sd0valid){
309 n -= GETBELONG(rp->sense+3) * rp->lbsize;
310 rp->data.count = nbytes - n;
313 rp->data.count = nbytes;
316 rp->offset += n / rp->lbsize;
321 SRseek(ScsiReq *rp, long offset, int type)
331 offset += rp->offset;
338 fprint(2, "disk: seek failed\n");
339 rp->status = Status_BADARG;
342 memset(cmd, 0, sizeof cmd);
343 if(offset <= Max24off && (rp->flags & Frw10) == 0){
345 PUTBE24(cmd+1, offset & Max24off);
348 cmd[0] = ScmdExtseek;
349 PUTBELONG(cmd+2, offset);
357 if(rp->status == STok) {
365 SRfilemark(ScsiReq *rp, ulong howmany)
369 memset(cmd, 0, sizeof cmd);
371 PUTBE24(cmd+2, howmany);
373 rp->cmd.count = sizeof cmd;
377 return SRrequest(rp);
381 SRspace(ScsiReq *rp, uchar code, long howmany)
385 memset(cmd, 0, sizeof cmd);
388 PUTBE24(cmd+2, howmany);
390 rp->cmd.count = sizeof cmd;
395 * what about rp->offset?
397 return SRrequest(rp);
401 SRinquiry(ScsiReq *rp)
405 memset(cmd, 0, sizeof cmd);
409 rp->cmd.count = sizeof cmd;
410 memset(rp->inquiry, 0, sizeof rp->inquiry);
411 rp->data.p = rp->inquiry;
414 if(SRrequest(rp) >= 0){
418 rp->flags &= ~Finqok;
423 SRmodeselect6(ScsiReq *rp, uchar *list, long nbytes)
427 memset(cmd, 0, sizeof cmd);
428 cmd[0] = ScmdMselect6;
429 if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)
433 rp->cmd.count = sizeof cmd;
435 rp->data.count = nbytes;
437 return SRrequest(rp);
441 SRmodeselect10(ScsiReq *rp, uchar *list, long nbytes)
445 memset(cmd, 0, sizeof cmd);
446 if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)
448 cmd[0] = ScmdMselect10;
452 rp->cmd.count = sizeof cmd;
454 rp->data.count = nbytes;
456 return SRrequest(rp);
460 SRmodesense6(ScsiReq *rp, uchar page, uchar *list, long nbytes)
464 memset(cmd, 0, sizeof cmd);
465 cmd[0] = ScmdMsense6;
469 rp->cmd.count = sizeof cmd;
471 rp->data.count = nbytes;
473 return SRrequest(rp);
477 SRmodesense10(ScsiReq *rp, uchar page, uchar *list, long nbytes)
481 memset(cmd, 0, sizeof cmd);
482 cmd[0] = ScmdMsense10;
487 rp->cmd.count = sizeof cmd;
489 rp->data.count = nbytes;
491 return SRrequest(rp);
495 SRstart(ScsiReq *rp, uchar code)
499 memset(cmd, 0, sizeof cmd);
503 rp->cmd.count = sizeof cmd;
507 return SRrequest(rp);
511 SRrcapacity(ScsiReq *rp, uchar *data)
515 memset(cmd, 0, sizeof cmd);
516 cmd[0] = ScmdRcapacity;
518 rp->cmd.count = sizeof cmd;
522 return SRrequest(rp);
526 SRrcapacity16(ScsiReq *rp, uchar *data)
532 memset(cmd, 0, sizeof cmd);
533 cmd[0] = ScmdRcapacity16;
541 rp->cmd.count = sizeof cmd;
545 return SRrequest(rp);
553 fprint(2, "scsidebug on\n");
557 request(int fd, ScsiPtr *cmd, ScsiPtr *data, int *status)
562 /* this was an experiment but it seems to be a good idea */
565 /* send SCSI command */
566 if(write(fd, cmd->p, cmd->count) != cmd->count){
567 fprint(2, "scsireq: write cmd: %r\n");
572 /* read or write actual data */
576 n = write(fd, data->p, data->count);
578 n = read(fd, data->p, data->count);
580 memset(data->p, 0, data->count);
581 else if (n < data->count)
582 memset(data->p + n, 0, data->count - n);
585 if (n != data->count && n <= 0) {
588 "request: tried to %s %ld bytes of data for cmd 0x%x but got %r\n",
589 (data->write? "write": "read"),
590 data->count, cmd->p[0]);
591 } else if (n != data->count && (data->write || debug))
592 fprint(2, "request: %s %ld of %ld bytes of actual data\n",
593 (data->write? "wrote": "read"), n, data->count);
597 r = read(fd, buf, sizeof buf-1);
598 if(exabyte && r <= 0 || !exabyte && r < 0){
599 fprint(2, "scsireq: read status: %r\n");
606 if(n < 0 && (exabyte || *status != STcheck))
607 fprint(2, "scsireq: status 0x%2.2uX: data transfer: %r\n",
613 seprintcmd(char *s, char* e, char *cmd, int count, int args)
618 return seprint(s, e, "<short cmd>");
620 if(scmdnames[c] != nil)
621 s = seprint(s, e, "%s", scmdnames[c]);
623 s = seprint(s, e, "cmd:%#02uX", c);
630 s = seprint(s, e, " sz %d", cmd[4]);
633 s = seprint(s, e, " code %d", cmd[1]);
636 s = seprint(s, e, " code %d", cmd[4]);
644 seprintdata(char *s, char *se, uchar *p, int count)
650 for(i = 0; i < 20 && i < count; i++)
651 s = seprint(s, se, " %02x", p[i]);
656 SRdumpReq(ScsiReq *rp)
662 se = buf+sizeof(buf);
663 s = seprint(buf, se, "lun %d ", rp->lun);
664 s = seprintcmd(s, se, (char*)rp->cmd.p, rp->cmd.count, 1);
665 s = seprint(s, se, " [%ld]", rp->data.count);
667 seprintdata(s, se, rp->data.p, rp->data.count);
668 fprint(2, "scsi⇒ %s\n", buf);
672 SRdumpRep(ScsiReq *rp)
678 se = buf+sizeof(buf);
679 s = seprint(buf, se, "lun %d ", rp->lun);
680 s = seprintcmd(s, se, (char*)rp->cmd.p, rp->cmd.count, 0);
683 s = seprint(s, se, " good [%ld] ", rp->data.count);
684 if(rp->cmd.write == 0)
685 s = seprintdata(s, se, rp->data.p, rp->data.count);
688 s = seprint(s, se, " buffer allocation failed");
691 s = seprint(s, se, " controller error");
694 s = seprint(s, se, " bus timeout");
697 s = seprint(s, se, " check condition");
700 s = seprint(s, se, " condition met/good");
703 s = seprint(s, se, " busy");
706 s = seprint(s, se, " intermediate/good");
709 s = seprint(s, se, " intermediate/condition met/good");
712 s = seprint(s, se, " reservation conflict");
715 s = seprint(s, se, " command terminated");
718 s = seprint(s, se, " queue full");
721 s = seprint(s, se, " sts=%#x", rp->status);
724 fprint(2, "scsi← %s\n", buf);
736 ec = (rp->sense[12] << 8) | rp->sense[13];
737 return scsierrmsg(ec);
739 return "software error";
741 return "bad argument";
743 return "device is read only";
750 SRdumpErr(ScsiReq *rp)
755 se = buf+sizeof(buf);
756 seprintcmd(buf, se, (char*)rp->cmd.p, rp->cmd.count, 0);
757 print("\t%s status: %s\n", buf, scsierr(rp));
761 SRrequest(ScsiReq *rp)
770 n = umsrequest(rp->umsc, &rp->cmd, &rp->data, &status);
772 n = request(rp->fd, &rp->cmd, &rp->data, &status);
782 if(rp->cmd.p[0] != ScmdRsense && SRreqsense(rp) != -1)
783 rp->status = Status_SD;
786 werrstr("%s", scsierr(rp));
789 sleep(1000); /* TODO: try a shorter sleep? */
794 werrstr("%s", scsierr(rp));
803 if((rp->flags & Fopen) == 0){
805 fprint(2, "disk: closing closed file\n");
806 rp->status = Status_BADARG;
815 dirdevopen(ScsiReq *rp)
818 uchar data[8+4+20]; /* 16-byte result: lba, blksize, reserved */
820 memset(data, 0, sizeof data);
821 if(SRstart(rp, 1) == -1 || SRrcapacity(rp, data) == -1)
823 rp->lbsize = GETBELONG(data+4);
824 blocks = GETBELONG(data);
826 fprint(2, "disk: dirdevopen: 10-byte logical block size %lud, "
827 "# blocks %llud\n", rp->lbsize, blocks);
828 if(blocks == 0xffffffff){
829 if(SRrcapacity16(rp, data) == -1)
831 rp->lbsize = GETBELONG(data + 8);
832 blocks = (vlong)GETBELONG(data)<<32 | GETBELONG(data + 4);
834 fprint(2, "disk: dirdevopen: 16-byte logical block size"
835 " %lud, # blocks %llud\n", rp->lbsize, blocks);
837 /* some newer dev's don't support 6-byte commands */
838 if(blocks > Max24off && !force6bytecmds)
844 seqdevopen(ScsiReq *rp)
846 uchar mode[16], limits[6];
848 if(SRrblimits(rp, limits) == -1)
850 if(limits[1] == 0 && limits[2] == limits[4] && limits[3] == limits[5]){
851 rp->flags |= Fbfixed;
852 rp->lbsize = limits[4]<<8 | limits[5];
854 fprint(2, "disk: seqdevopen: 10-byte logical block size %lud\n",
859 * On some older hardware the optional 10-byte
860 * modeselect command isn't implemented.
864 if(!(rp->flags & Fmode6)){
865 /* try 10-byte command first */
866 memset(mode, 0, sizeof mode);
867 mode[3] = 0x10; /* device-specific param. */
868 mode[7] = 8; /* block descriptor length */
870 * exabytes can't handle this, and
871 * modeselect(10) is optional.
873 if(SRmodeselect10(rp, mode, sizeof mode) != -1){
875 return 0; /* success */
877 /* can't do 10-byte commands, back off to 6-byte ones */
882 memset(mode, 0, sizeof mode);
883 mode[2] = 0x10; /* device-specific param. */
884 mode[3] = 8; /* block descriptor length */
886 * bsd sez exabytes need this bit (NBE: no busy enable) in
887 * vendor-specific page (0), but so far we haven't needed it.
890 if(SRmodeselect6(rp, mode, 4+8) == -1)
897 wormdevopen(ScsiReq *rp)
900 uchar list[MaxDirData];
902 if (SRstart(rp, 1) == -1 ||
903 (status = SRmodesense10(rp, Allmodepages, list, sizeof list)) == -1)
905 /* nbytes = list[0]<<8 | list[1]; */
907 /* # of bytes of block descriptors of 8 bytes each; not even 1? */
908 if((list[6]<<8 | list[7]) < 8)
911 /* last 3 bytes of block 0 descriptor */
912 rp->lbsize = GETBE24(list+13);
914 fprint(2, "disk: wormdevopen: 10-byte logical block size %lud\n",
920 SRopenraw(ScsiReq *rp, char *unit)
924 if(rp->flags & Fopen){
926 fprint(2, "disk: opening open file\n");
927 rp->status = Status_BADARG;
930 memset(rp, 0, sizeof *rp);
933 snprint(name, sizeof name, "%s/raw", unit);
934 if((rp->fd = open(name, ORDWR)) == -1){
935 rp->status = STtimeout;
943 SRopen(ScsiReq *rp, char *unit)
945 if(SRopenraw(rp, unit) == -1)
948 if(SRinquiry(rp) >= 0){
949 switch(rp->inquiry[0]){
952 fprint(2, "unknown device type 0x%.2x\n", rp->inquiry[0]);
953 rp->status = Status_SW;
959 if(dirdevopen(rp) == -1)
964 rp->flags |= Fseqdev;
965 if(seqdevopen(rp) == -1)
970 rp->flags |= Fprintdev;
974 rp->flags |= Fwormdev;
975 if(wormdevopen(rp) == -1)
980 rp->flags |= Fchanger;