6 * and incomplete in many other ways
15 * exabyte tape drives, at least old ones like the 8200 and 8505,
16 * are dumb: you have to read the exact block size on the tape,
17 * they don't take 10-byte SCSI commands, and various other fine points.
19 extern int exabyte, force6bytecmds;
21 static int debug = Debug;
28 memset(cmd, 0, sizeof cmd);
30 rp->cmd.count = sizeof cmd;
42 memset(cmd, 0, sizeof cmd);
45 rp->cmd.count = sizeof cmd;
49 if(SRrequest(rp) >= 0){
57 SRreqsense(ScsiReq *rp)
63 if(rp->status == Status_SD){
67 memset(cmd, 0, sizeof cmd);
69 cmd[4] = sizeof(req.sense);
70 memset(&req, 0, sizeof(req));
76 req.cmd.count = sizeof cmd;
77 req.data.p = rp->sense;
78 req.data.count = sizeof(rp->sense);
80 status = SRrequest(&req);
81 rp->status = req.status;
90 memset(cmd, 0, sizeof cmd);
93 rp->cmd.count = sizeof cmd;
101 SRrblimits(ScsiReq *rp, uchar *list)
105 memset(cmd, 0, sizeof cmd);
106 cmd[0] = ScmdRblimits;
108 rp->cmd.count = sizeof cmd;
112 return SRrequest(rp);
116 dirdevrw(ScsiReq *rp, uchar *cmd, long nbytes)
120 n = nbytes / rp->lbsize;
121 if(rp->offset <= Max24off && n <= 256 && (rp->flags & Frw10) == 0){
122 PUTBE24(cmd+1, rp->offset);
127 cmd[0] |= ScmdExtread;
129 PUTBELONG(cmd+2, rp->offset);
138 seqdevrw(ScsiReq *rp, uchar *cmd, long nbytes)
142 /* don't set Cmd1sili; we want the ILI bit instead of a fatal error */
143 cmd[1] = rp->flags&Fbfixed? Cmd1fixed: 0;
144 n = nbytes / rp->lbsize;
151 SRread(ScsiReq *rp, void *buf, long nbytes)
156 if((nbytes % rp->lbsize) || nbytes > maxiosize){
158 if (nbytes % rp->lbsize)
159 fprint(2, "scuzz: i/o size %ld %% %ld != 0\n",
162 fprint(2, "scuzz: i/o size %ld > %ld\n",
164 rp->status = Status_BADARG;
168 /* set up scsi read cmd */
170 if(rp->flags & Fseqdev)
171 rp->cmd.count = seqdevrw(rp, cmd, nbytes);
173 rp->cmd.count = dirdevrw(rp, cmd, nbytes);
176 rp->data.count = nbytes;
181 if(n != -1){ /* it worked? */
182 rp->offset += n / rp->lbsize;
186 /* request failed; maybe we just read a short record? */
188 fprint(2, "read error\n");
189 rp->status = STcheck;
192 if(rp->status != Status_SD || !(rp->sense[0] & Sd0valid))
194 /* compute # of bytes not read */
195 n = GETBELONG(rp->sense+3) * rp->lbsize;
198 "SRread: request failed with sense data; sense byte count %ld\n",
200 if(!(rp->flags & Fseqdev))
203 /* device is a tape or something similar */
204 if (rp->sense[2] == Sd2filemark || rp->sense[2] == 0x08 ||
205 rp->sense[2] & Sd2ili && n > 0)
206 rp->data.count = nbytes - n;
210 if (!rp->readblock++ || debug)
211 fprint(2, "SRread: tape data count %ld%s\n", n,
212 (rp->sense[2] & Sd2ili? " with ILI": ""));
214 rp->offset += n / rp->lbsize;
219 SRwrite(ScsiReq *rp, void *buf, long nbytes)
224 if((nbytes % rp->lbsize) || nbytes > maxiosize){
226 if (nbytes % rp->lbsize)
227 fprint(2, "scuzz: i/o size %ld %% %ld != 0\n",
230 fprint(2, "scuzz: i/o size %ld > %ld\n",
232 rp->status = Status_BADARG;
236 /* set up scsi write cmd */
238 if(rp->flags & Fseqdev)
239 rp->cmd.count = seqdevrw(rp, cmd, nbytes);
241 rp->cmd.count = dirdevrw(rp, cmd, nbytes);
244 rp->data.count = nbytes;
248 if((n = SRrequest(rp)) == -1){
250 fprint(2, "write error\n");
251 rp->status = STcheck;
254 if(rp->status != Status_SD || rp->sense[2] != Sd2eom)
256 if(rp->sense[0] & Sd0valid){
257 n -= GETBELONG(rp->sense+3) * rp->lbsize;
258 rp->data.count = nbytes - n;
261 rp->data.count = nbytes;
264 rp->offset += n / rp->lbsize;
269 SRseek(ScsiReq *rp, long offset, int type)
279 offset += rp->offset;
286 fprint(2, "scuzz: seek failed\n");
287 rp->status = Status_BADARG;
290 memset(cmd, 0, sizeof cmd);
291 if(offset <= Max24off && (rp->flags & Frw10) == 0){
293 PUTBE24(cmd+1, offset & Max24off);
296 cmd[0] = ScmdExtseek;
297 PUTBELONG(cmd+2, offset);
305 if(rp->status == STok)
306 return rp->offset = offset;
311 SRfilemark(ScsiReq *rp, ulong howmany)
315 memset(cmd, 0, sizeof cmd);
317 PUTBE24(cmd+2, howmany);
319 rp->cmd.count = sizeof cmd;
323 return SRrequest(rp);
327 SRspace(ScsiReq *rp, uchar code, long howmany)
331 memset(cmd, 0, sizeof cmd);
334 PUTBE24(cmd+2, howmany);
336 rp->cmd.count = sizeof cmd;
341 * what about rp->offset?
343 return SRrequest(rp);
347 SRinquiry(ScsiReq *rp)
351 memset(cmd, 0, sizeof cmd);
353 cmd[4] = sizeof rp->inquiry;
355 rp->cmd.count = sizeof cmd;
356 memset(rp->inquiry, 0, sizeof rp->inquiry);
357 rp->data.p = rp->inquiry;
358 rp->data.count = sizeof rp->inquiry;
360 if(SRrequest(rp) >= 0){
364 rp->flags &= ~Finqok;
369 SRmodeselect6(ScsiReq *rp, uchar *list, long nbytes)
373 memset(cmd, 0, sizeof cmd);
374 cmd[0] = ScmdMselect6;
375 if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)
379 rp->cmd.count = sizeof cmd;
381 rp->data.count = nbytes;
383 return SRrequest(rp);
387 SRmodeselect10(ScsiReq *rp, uchar *list, long nbytes)
391 memset(cmd, 0, sizeof cmd);
392 if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)
394 cmd[0] = ScmdMselect10;
398 rp->cmd.count = sizeof cmd;
400 rp->data.count = nbytes;
402 return SRrequest(rp);
406 SRmodesense6(ScsiReq *rp, uchar page, uchar *list, long nbytes)
410 memset(cmd, 0, sizeof cmd);
411 cmd[0] = ScmdMsense6;
415 rp->cmd.count = sizeof cmd;
417 rp->data.count = nbytes;
419 return SRrequest(rp);
423 SRmodesense10(ScsiReq *rp, uchar page, uchar *list, long nbytes)
427 memset(cmd, 0, sizeof cmd);
428 cmd[0] = ScmdMsense10;
433 rp->cmd.count = sizeof cmd;
435 rp->data.count = nbytes;
437 return SRrequest(rp);
441 SRstart(ScsiReq *rp, uchar code)
445 memset(cmd, 0, sizeof cmd);
449 rp->cmd.count = sizeof cmd;
453 return SRrequest(rp);
457 SRrcapacity(ScsiReq *rp, uchar *data)
461 memset(cmd, 0, sizeof cmd);
462 cmd[0] = ScmdRcapacity;
464 rp->cmd.count = sizeof cmd;
468 return SRrequest(rp);
472 request(int fd, ScsiPtr *cmd, ScsiPtr *data, int *status)
477 /* this was an experiment but it seems to be a good idea */
480 /* send SCSI command */
481 if(write(fd, cmd->p, cmd->count) != cmd->count){
482 fprint(2, "scsireq: write cmd: %r\n");
487 /* read or write actual data */
490 n = write(fd, data->p, data->count);
492 n = read(fd, data->p, data->count);
494 memset(data->p, 0, data->count);
495 else if (n < data->count)
496 memset(data->p + n, 0, data->count - n);
498 if (n != data->count && n <= 0) {
501 "request: tried to %s %ld bytes of data for cmd 0x%x but got %r\n",
502 (data->write? "write": "read"),
503 data->count, cmd->p[0]);
504 } else if (n != data->count && (data->write || debug))
505 fprint(2, "request: %s %ld of %ld bytes of actual data\n",
506 (data->write? "wrote": "read"), n, data->count);
510 r = read(fd, buf, sizeof buf-1);
511 if(exabyte && r <= 0 || !exabyte && r < 0){
512 fprint(2, "scsireq: read status: %r\n");
519 if(n < 0 && (exabyte || *status != STcheck))
520 fprint(2, "scsireq: status 0x%2.2uX: data transfer: %r\n",
526 SRrequest(ScsiReq *rp)
533 n = umsrequest(rp->umsc, &rp->cmd, &rp->data, &status);
535 n = request(rp->fd, &rp->cmd, &rp->data, &status);
536 switch(rp->status = status){
543 if(rp->cmd.p[0] != ScmdRsense && SRreqsense(rp) != -1)
544 rp->status = Status_SD;
546 fprint(2, "SRrequest: STcheck, returning -1\n");
554 fprint(2, "status 0x%2.2uX\n", status);
563 if((rp->flags & Fopen) == 0){
565 fprint(2, "scuzz: closing closed file\n");
566 rp->status = Status_BADARG;
580 return u[2]<<16 | u[12]<<8 | u[13];
584 dirdevopen(ScsiReq *rp)
589 if(SRstart(rp, 1) == -1)
591 * it's okay for removable media to say
592 * "check condition: medium not present".
593 * 3a is "medium not present".
595 return rp->inquiry[1] & 0x80 && (mkascq(rp) >> 8) == 0x023a?
597 memset(data, 0, sizeof data);
598 if(SRrcapacity(rp, data) == -1)
600 rp->lbsize = GETBELONG(data+4);
601 blocks = GETBELONG(data);
603 fprint(2, "scuzz: dirdevopen: logical block size %lud, "
604 "# blocks %lud\n", rp->lbsize, blocks);
605 /* some newer dev's don't support 6-byte commands */
606 if(blocks > Max24off && !force6bytecmds)
612 seqdevopen(ScsiReq *rp)
614 uchar mode[16], limits[6];
616 if(SRrblimits(rp, limits) == -1)
618 if(limits[1] == 0 && limits[2] == limits[4] && limits[3] == limits[5]){
619 rp->flags |= Fbfixed;
620 rp->lbsize = limits[4]<<8 | limits[5];
622 fprint(2, "scuzz: seqdevopen: logical block size %lud\n",
627 * On some older hardware the optional 10-byte
628 * modeselect command isn't implemented.
632 if(!(rp->flags & Fmode6)){
633 /* try 10-byte command first */
634 memset(mode, 0, sizeof mode);
635 mode[3] = 0x10; /* device-specific param. */
636 mode[7] = 8; /* block descriptor length */
638 * exabytes can't handle this, and
639 * modeselect(10) is optional.
641 if(SRmodeselect10(rp, mode, sizeof mode) != -1){
643 return 0; /* success */
645 /* can't do 10-byte commands, back off to 6-byte ones */
650 memset(mode, 0, sizeof mode);
651 mode[2] = 0x10; /* device-specific param. */
652 mode[3] = 8; /* block descriptor length */
654 * bsd sez exabytes need this bit (NBE: no busy enable) in
655 * vendor-specific page (0), but so far we haven't needed it.
658 if(SRmodeselect6(rp, mode, 4+8) == -1)
665 wormdevopen(ScsiReq *rp)
668 uchar list[MaxDirData];
670 if (SRstart(rp, 1) == -1 ||
671 (status = SRmodesense10(rp, Allmodepages, list, sizeof list)) == -1)
673 /* nbytes = list[0]<<8 | list[1]; */
675 /* # of bytes of block descriptors of 8 bytes each; not even 1? */
676 if((list[6]<<8 | list[7]) < 8)
679 /* last 3 bytes of block 0 descriptor */
680 rp->lbsize = GETBE24(list+13);
682 fprint(2, "scuzz: wormdevopen: logical block size %lud\n",
688 SRopenraw(ScsiReq *rp, char *unit)
692 if(rp->flags & Fopen){
694 fprint(2, "scuzz: opening open file\n");
695 rp->status = Status_BADARG;
698 memset(rp, 0, sizeof *rp);
701 sprint(name, "%s/raw", unit);
703 if((rp->fd = open(name, ORDWR)) == -1){
704 rp->status = STtimeout;
712 SRopen(ScsiReq *rp, char *unit)
714 if(SRopenraw(rp, unit) == -1)
717 if(SRinquiry(rp) >= 0){
718 switch(rp->inquiry[0]){
721 fprint(2, "unknown device type 0x%.2x\n", rp->inquiry[0]);
722 rp->status = Status_SW;
725 case 0x00: /* Direct access (disk) */
726 case 0x05: /* CD-ROM */
727 case 0x07: /* rewriteable MO */
728 if(dirdevopen(rp) == -1)
732 case 0x01: /* Sequential eg: tape */
733 rp->flags |= Fseqdev;
734 if(seqdevopen(rp) == -1)
738 case 0x02: /* Printer */
739 rp->flags |= Fprintdev;
742 case 0x04: /* Worm */
743 rp->flags |= Fwormdev;
744 if(wormdevopen(rp) == -1)
748 case 0x08: /* medium-changer */
749 rp->flags |= Fchanger;