1 /*
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.
10 *
11 * BUGS:
12 * no luns
13 * and incomplete in many other ways
14 */
15
16 #include <u.h>
17 #include <libc.h>
18 #include <fcall.h>
19 #include <disk.h>
20 #include "scsireq.h"
21
22 enum {
23 Debug = 0,
24 };
25
26 /*
27 * exabyte tape drives, at least old ones like the 8200 and 8505,
28 * are dumb: you have to read the exact block size on the tape,
29 * they don't take 10-byte SCSI commands, and various other fine points.
30 */
31 extern int exabyte, force6bytecmds;
32
33 static int debug = Debug;
34
35 static char *scmdnames[256] = {
36 [ScmdTur] "Tur",
37 [ScmdRewind] "Rewind",
38 [ScmdRsense] "Rsense",
39 [ScmdFormat] "Format",
40 [ScmdRblimits] "Rblimits",
41 [ScmdRead] "Read",
42 [ScmdWrite] "Write",
43 [ScmdSeek] "Seek",
44 [ScmdFmark] "Fmark",
45 [ScmdSpace] "Space",
46 [ScmdInq] "Inq",
47 [ScmdMselect6] "Mselect6",
48 [ScmdMselect10] "Mselect10",
49 [ScmdMsense6] "Msense6",
50 [ScmdMsense10] "Msense10",
51 [ScmdStart] "Start",
52 [ScmdRcapacity] "Rcapacity",
53 [ScmdRcapacity16] "Rcap16",
54 [ScmdExtread] "Extread",
55 [ScmdExtwrite] "Extwrite",
56 [ScmdExtseek] "Extseek",
57
58 [ScmdSynccache] "Synccache",
59 [ScmdRTOC] "RTOC",
60 [ScmdRdiscinfo] "Rdiscinfo",
61 [ScmdRtrackinfo] "Rtrackinfo",
62 [ScmdReserve] "Reserve",
63 [ScmdBlank] "Blank",
64
65 [ScmdCDpause] "CDpause",
66 [ScmdCDstop] "CDstop",
67 [ScmdCDplay] "CDplay",
68 [ScmdCDload] "CDload",
69 [ScmdCDscan] "CDscan",
70 [ScmdCDstatus] "CDstatus",
71 [Scmdgetconf] "getconf",
72 };
73
74 long
SRready(ScsiReq * rp)75 SRready(ScsiReq *rp)
76 {
77 uchar cmd[6];
78
79 memset(cmd, 0, sizeof cmd);
80 rp->cmd.p = cmd;
81 rp->cmd.count = sizeof cmd;
82 rp->data.p = cmd;
83 rp->data.count = 0;
84 rp->data.write = 1;
85 return SRrequest(rp);
86 }
87
88 long
SRrewind(ScsiReq * rp)89 SRrewind(ScsiReq *rp)
90 {
91 uchar cmd[6];
92
93 memset(cmd, 0, sizeof cmd);
94 cmd[0] = ScmdRewind;
95 rp->cmd.p = cmd;
96 rp->cmd.count = sizeof cmd;
97 rp->data.p = cmd;
98 rp->data.count = 0;
99 rp->data.write = 1;
100 if(SRrequest(rp) >= 0){
101 rp->offset = 0;
102 return 0;
103 }
104 return -1;
105 }
106
107 long
SRreqsense(ScsiReq * rp)108 SRreqsense(ScsiReq *rp)
109 {
110 uchar cmd[6];
111 ScsiReq req;
112 long status;
113
114 if(rp->status == Status_SD){
115 rp->status = STok;
116 return 0;
117 }
118 memset(cmd, 0, sizeof cmd);
119 cmd[0] = ScmdRsense;
120 cmd[4] = sizeof(req.sense);
121 memset(&req, 0, sizeof(req));
122 if(rp->flags&Fusb)
123 req.flags |= Fusb;
124 req.lun = rp->lun;
125 req.unit = rp->unit;
126 req.fd = rp->fd;
127 req.umsc = rp->umsc;
128 req.cmd.p = cmd;
129 req.cmd.count = sizeof cmd;
130 req.data.p = rp->sense;
131 req.data.count = sizeof(rp->sense);
132 req.data.write = 0;
133 status = SRrequest(&req);
134 rp->status = req.status;
135 if(status != -1)
136 rp->sense[0] |= Sd0valid;
137 return status;
138 }
139
140 long
SRformat(ScsiReq * rp)141 SRformat(ScsiReq *rp)
142 {
143 uchar cmd[6];
144
145 memset(cmd, 0, sizeof cmd);
146 cmd[0] = ScmdFormat;
147 rp->cmd.p = cmd;
148 rp->cmd.count = sizeof cmd;
149 rp->data.p = cmd;
150 rp->data.count = 6;
151 rp->data.write = 0;
152 return SRrequest(rp);
153 }
154
155 long
SRrblimits(ScsiReq * rp,uchar * list)156 SRrblimits(ScsiReq *rp, uchar *list)
157 {
158 uchar cmd[6];
159
160 memset(cmd, 0, sizeof cmd);
161 cmd[0] = ScmdRblimits;
162 rp->cmd.p = cmd;
163 rp->cmd.count = sizeof cmd;
164 rp->data.p = list;
165 rp->data.count = 6;
166 rp->data.write = 0;
167 return SRrequest(rp);
168 }
169
170 static int
dirdevrw(ScsiReq * rp,uchar * cmd,long nbytes)171 dirdevrw(ScsiReq *rp, uchar *cmd, long nbytes)
172 {
173 long n;
174
175 n = nbytes / rp->lbsize;
176 if(rp->offset <= Max24off && n <= 256 && (rp->flags & Frw10) == 0){
177 PUTBE24(cmd+1, rp->offset);
178 cmd[4] = n;
179 cmd[5] = 0;
180 return 6;
181 }
182 cmd[0] |= ScmdExtread;
183 cmd[1] = 0;
184 PUTBELONG(cmd+2, rp->offset);
185 cmd[6] = 0;
186 cmd[7] = n>>8;
187 cmd[8] = n;
188 cmd[9] = 0;
189 return 10;
190 }
191
192 static int
seqdevrw(ScsiReq * rp,uchar * cmd,long nbytes)193 seqdevrw(ScsiReq *rp, uchar *cmd, long nbytes)
194 {
195 long n;
196
197 /* don't set Cmd1sili; we want the ILI bit instead of a fatal error */
198 cmd[1] = rp->flags&Fbfixed? Cmd1fixed: 0;
199 n = nbytes / rp->lbsize;
200 PUTBE24(cmd+2, n);
201 cmd[5] = 0;
202 return 6;
203 }
204
205 extern int diskdebug;
206
207 long
SRread(ScsiReq * rp,void * buf,long nbytes)208 SRread(ScsiReq *rp, void *buf, long nbytes)
209 {
210 uchar cmd[10];
211 long n;
212
213 if(rp->lbsize == 0 || (nbytes % rp->lbsize) || nbytes > Maxiosize){
214 if(diskdebug)
215 if (nbytes % rp->lbsize)
216 fprint(2, "disk: i/o size %ld %% %ld != 0\n",
217 nbytes, rp->lbsize);
218 else
219 fprint(2, "disk: i/o size %ld > %d\n",
220 nbytes, Maxiosize);
221 rp->status = Status_BADARG;
222 return -1;
223 }
224
225 /* set up scsi read cmd */
226 cmd[0] = ScmdRead;
227 if(rp->flags & Fseqdev)
228 rp->cmd.count = seqdevrw(rp, cmd, nbytes);
229 else
230 rp->cmd.count = dirdevrw(rp, cmd, nbytes);
231 rp->cmd.p = cmd;
232 rp->data.p = buf;
233 rp->data.count = nbytes;
234 rp->data.write = 0;
235
236 /* issue it */
237 n = SRrequest(rp);
238 if(n != -1){ /* it worked? */
239 rp->offset += n / rp->lbsize;
240 return n;
241 }
242
243 /* request failed; maybe we just read a short record? */
244 if (exabyte) {
245 fprint(2, "read error\n");
246 rp->status = STcheck;
247 return n;
248 }
249 if(rp->status != Status_SD || !(rp->sense[0] & Sd0valid))
250 return -1;
251 /* compute # of bytes not read */
252 n = GETBELONG(rp->sense+3) * rp->lbsize;
253 if(!(rp->flags & Fseqdev))
254 return -1;
255
256 /* device is a tape or something similar */
257 if (rp->sense[2] == Sd2filemark || rp->sense[2] == 0x08 ||
258 rp->sense[2] & Sd2ili && n > 0)
259 rp->data.count = nbytes - n;
260 else
261 return -1;
262 n = rp->data.count;
263 if (!rp->readblock++ || debug)
264 fprint(2, "SRread: tape data count %ld%s\n", n,
265 (rp->sense[2] & Sd2ili? " with ILI": ""));
266 rp->status = STok;
267 rp->offset += n / rp->lbsize;
268 return n;
269 }
270
271 long
SRwrite(ScsiReq * rp,void * buf,long nbytes)272 SRwrite(ScsiReq *rp, void *buf, long nbytes)
273 {
274 uchar cmd[10];
275 long n;
276
277 if(rp->lbsize == 0 || (nbytes % rp->lbsize) || nbytes > Maxiosize){
278 if(diskdebug)
279 if (nbytes % rp->lbsize)
280 fprint(2, "disk: i/o size %ld %% %ld != 0\n",
281 nbytes, rp->lbsize);
282 else
283 fprint(2, "disk: i/o size %ld > %d\n",
284 nbytes, Maxiosize);
285 rp->status = Status_BADARG;
286 return -1;
287 }
288
289 /* set up scsi write cmd */
290 cmd[0] = ScmdWrite;
291 if(rp->flags & Fseqdev)
292 rp->cmd.count = seqdevrw(rp, cmd, nbytes);
293 else
294 rp->cmd.count = dirdevrw(rp, cmd, nbytes);
295 rp->cmd.p = cmd;
296 rp->data.p = buf;
297 rp->data.count = nbytes;
298 rp->data.write = 1;
299
300 /* issue it */
301 if((n = SRrequest(rp)) == -1){
302 if (exabyte) {
303 fprint(2, "write error\n");
304 rp->status = STcheck;
305 return n;
306 }
307 if(rp->status != Status_SD || rp->sense[2] != Sd2eom)
308 return -1;
309 if(rp->sense[0] & Sd0valid){
310 n -= GETBELONG(rp->sense+3) * rp->lbsize;
311 rp->data.count = nbytes - n;
312 }
313 else
314 rp->data.count = nbytes;
315 n = rp->data.count;
316 }
317 rp->offset += n / rp->lbsize;
318 return n;
319 }
320
321 long
SRseek(ScsiReq * rp,long offset,int type)322 SRseek(ScsiReq *rp, long offset, int type)
323 {
324 uchar cmd[10];
325
326 switch(type){
327
328 case 0:
329 break;
330
331 case 1:
332 offset += rp->offset;
333 if(offset >= 0)
334 break;
335 /*FALLTHROUGH*/
336
337 default:
338 if(diskdebug)
339 fprint(2, "disk: seek failed\n");
340 rp->status = Status_BADARG;
341 return -1;
342 }
343 memset(cmd, 0, sizeof cmd);
344 if(offset <= Max24off && (rp->flags & Frw10) == 0){
345 cmd[0] = ScmdSeek;
346 PUTBE24(cmd+1, offset & Max24off);
347 rp->cmd.count = 6;
348 }else{
349 cmd[0] = ScmdExtseek;
350 PUTBELONG(cmd+2, offset);
351 rp->cmd.count = 10;
352 }
353 rp->cmd.p = cmd;
354 rp->data.p = cmd;
355 rp->data.count = 0;
356 rp->data.write = 1;
357 SRrequest(rp);
358 if(rp->status == STok) {
359 rp->offset = offset;
360 return offset;
361 }
362 return -1;
363 }
364
365 long
SRfilemark(ScsiReq * rp,ulong howmany)366 SRfilemark(ScsiReq *rp, ulong howmany)
367 {
368 uchar cmd[6];
369
370 memset(cmd, 0, sizeof cmd);
371 cmd[0] = ScmdFmark;
372 PUTBE24(cmd+2, howmany);
373 rp->cmd.p = cmd;
374 rp->cmd.count = sizeof cmd;
375 rp->data.p = cmd;
376 rp->data.count = 0;
377 rp->data.write = 1;
378 return SRrequest(rp);
379 }
380
381 long
SRspace(ScsiReq * rp,uchar code,long howmany)382 SRspace(ScsiReq *rp, uchar code, long howmany)
383 {
384 uchar cmd[6];
385
386 memset(cmd, 0, sizeof cmd);
387 cmd[0] = ScmdSpace;
388 cmd[1] = code;
389 PUTBE24(cmd+2, howmany);
390 rp->cmd.p = cmd;
391 rp->cmd.count = sizeof cmd;
392 rp->data.p = cmd;
393 rp->data.count = 0;
394 rp->data.write = 1;
395 /*
396 * what about rp->offset?
397 */
398 return SRrequest(rp);
399 }
400
401 long
SRinquiry(ScsiReq * rp)402 SRinquiry(ScsiReq *rp)
403 {
404 uchar cmd[6];
405
406 memset(cmd, 0, sizeof cmd);
407 cmd[0] = ScmdInq;
408 cmd[4] = sizeof rp->inquiry;
409 rp->cmd.p = cmd;
410 rp->cmd.count = sizeof cmd;
411 memset(rp->inquiry, 0, sizeof rp->inquiry);
412 rp->data.p = rp->inquiry;
413 rp->data.count = sizeof rp->inquiry;
414 rp->data.write = 0;
415 if(SRrequest(rp) >= 0){
416 rp->flags |= Finqok;
417 return 0;
418 }
419 rp->flags &= ~Finqok;
420 return -1;
421 }
422
423 long
SRmodeselect6(ScsiReq * rp,uchar * list,long nbytes)424 SRmodeselect6(ScsiReq *rp, uchar *list, long nbytes)
425 {
426 uchar cmd[6];
427
428 memset(cmd, 0, sizeof cmd);
429 cmd[0] = ScmdMselect6;
430 if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)
431 cmd[1] = 0x10;
432 cmd[4] = nbytes;
433 rp->cmd.p = cmd;
434 rp->cmd.count = sizeof cmd;
435 rp->data.p = list;
436 rp->data.count = nbytes;
437 rp->data.write = 1;
438 return SRrequest(rp);
439 }
440
441 long
SRmodeselect10(ScsiReq * rp,uchar * list,long nbytes)442 SRmodeselect10(ScsiReq *rp, uchar *list, long nbytes)
443 {
444 uchar cmd[10];
445
446 memset(cmd, 0, sizeof cmd);
447 if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)
448 cmd[1] = 0x10;
449 cmd[0] = ScmdMselect10;
450 cmd[7] = nbytes>>8;
451 cmd[8] = nbytes;
452 rp->cmd.p = cmd;
453 rp->cmd.count = sizeof cmd;
454 rp->data.p = list;
455 rp->data.count = nbytes;
456 rp->data.write = 1;
457 return SRrequest(rp);
458 }
459
460 long
SRmodesense6(ScsiReq * rp,uchar page,uchar * list,long nbytes)461 SRmodesense6(ScsiReq *rp, uchar page, uchar *list, long nbytes)
462 {
463 uchar cmd[6];
464
465 memset(cmd, 0, sizeof cmd);
466 cmd[0] = ScmdMsense6;
467 cmd[2] = page;
468 cmd[4] = nbytes;
469 rp->cmd.p = cmd;
470 rp->cmd.count = sizeof cmd;
471 rp->data.p = list;
472 rp->data.count = nbytes;
473 rp->data.write = 0;
474 return SRrequest(rp);
475 }
476
477 long
SRmodesense10(ScsiReq * rp,uchar page,uchar * list,long nbytes)478 SRmodesense10(ScsiReq *rp, uchar page, uchar *list, long nbytes)
479 {
480 uchar cmd[10];
481
482 memset(cmd, 0, sizeof cmd);
483 cmd[0] = ScmdMsense10;
484 cmd[2] = page;
485 cmd[7] = nbytes>>8;
486 cmd[8] = nbytes;
487 rp->cmd.p = cmd;
488 rp->cmd.count = sizeof cmd;
489 rp->data.p = list;
490 rp->data.count = nbytes;
491 rp->data.write = 0;
492 return SRrequest(rp);
493 }
494
495 long
SRstart(ScsiReq * rp,uchar code)496 SRstart(ScsiReq *rp, uchar code)
497 {
498 uchar cmd[6];
499
500 memset(cmd, 0, sizeof cmd);
501 cmd[0] = ScmdStart;
502 cmd[4] = code;
503 rp->cmd.p = cmd;
504 rp->cmd.count = sizeof cmd;
505 rp->data.p = cmd;
506 rp->data.count = 0;
507 rp->data.write = 1;
508 return SRrequest(rp);
509 }
510
511 long
SRrcapacity(ScsiReq * rp,uchar * data)512 SRrcapacity(ScsiReq *rp, uchar *data)
513 {
514 uchar cmd[10];
515
516 memset(cmd, 0, sizeof cmd);
517 cmd[0] = ScmdRcapacity;
518 rp->cmd.p = cmd;
519 rp->cmd.count = sizeof cmd;
520 rp->data.p = data;
521 rp->data.count = 8;
522 rp->data.write = 0;
523 return SRrequest(rp);
524 }
525
526 long
SRrcapacity16(ScsiReq * rp,uchar * data)527 SRrcapacity16(ScsiReq *rp, uchar *data)
528 {
529 uchar cmd[16];
530 uint i;
531
532 i = 32;
533 memset(cmd, 0, sizeof cmd);
534 cmd[0] = ScmdRcapacity16;
535 cmd[1] = 0x10;
536 cmd[10] = i>>24;
537 cmd[11] = i>>16;
538 cmd[12] = i>>8;
539 cmd[13] = i;
540
541 rp->cmd.p = cmd;
542 rp->cmd.count = sizeof cmd;
543 rp->data.p = data;
544 rp->data.count = i;
545 rp->data.write = 0;
546 return SRrequest(rp);
547 }
548
549 void
scsidebug(int d)550 scsidebug(int d)
551 {
552 debug = d;
553 if(debug)
554 fprint(2, "scsidebug on\n");
555 }
556
557 static long
request(int fd,ScsiPtr * cmd,ScsiPtr * data,int * status)558 request(int fd, ScsiPtr *cmd, ScsiPtr *data, int *status)
559 {
560 long n, r;
561 char buf[16];
562
563 /* this was an experiment but it seems to be a good idea */
564 *status = STok;
565
566 /* send SCSI command */
567 if(write(fd, cmd->p, cmd->count) != cmd->count){
568 fprint(2, "scsireq: write cmd: %r\n");
569 *status = Status_SW;
570 return -1;
571 }
572
573 /* read or write actual data */
574 werrstr("");
575 // alarm(5*1000);
576 if(data->write)
577 n = write(fd, data->p, data->count);
578 else {
579 n = read(fd, data->p, data->count);
580 if (n < 0)
581 memset(data->p, 0, data->count);
582 else if (n < data->count)
583 memset(data->p + n, 0, data->count - n);
584 }
585 // alarm(0);
586 if (n != data->count && n <= 0) {
587 if (debug)
588 fprint(2,
589 "request: tried to %s %ld bytes of data for cmd 0x%x but got %r\n",
590 (data->write? "write": "read"),
591 data->count, cmd->p[0]);
592 } else if (n != data->count && (data->write || debug))
593 fprint(2, "request: %s %ld of %ld bytes of actual data\n",
594 (data->write? "wrote": "read"), n, data->count);
595
596 /* read status */
597 buf[0] = '\0';
598 r = read(fd, buf, sizeof buf-1);
599 if(exabyte && r <= 0 || !exabyte && r < 0){
600 fprint(2, "scsireq: read status: %r\n");
601 *status = Status_SW;
602 return -1;
603 }
604 if (r >= 0)
605 buf[r] = '\0';
606 *status = atoi(buf);
607 if(n < 0 && (exabyte || *status != STcheck))
608 fprint(2, "scsireq: status 0x%2.2uX: data transfer: %r\n",
609 *status);
610 return n;
611 }
612
613 static char*
seprintcmd(char * s,char * e,char * cmd,int count,int args)614 seprintcmd(char *s, char* e, char *cmd, int count, int args)
615 {
616 uint c;
617
618 if(count < 6)
619 return seprint(s, e, "<short cmd>");
620 c = cmd[0];
621 if(scmdnames[c] != nil)
622 s = seprint(s, e, "%s", scmdnames[c]);
623 else
624 s = seprint(s, e, "cmd:%#02uX", c);
625 if(args != 0)
626 switch(c){
627 case ScmdRsense:
628 case ScmdInq:
629 case ScmdMselect6:
630 case ScmdMsense6:
631 s = seprint(s, e, " sz %d", cmd[4]);
632 break;
633 case ScmdSpace:
634 s = seprint(s, e, " code %d", cmd[1]);
635 break;
636 case ScmdStart:
637 s = seprint(s, e, " code %d", cmd[4]);
638 break;
639
640 }
641 return s;
642 }
643
644 static char*
seprintdata(char * s,char * se,uchar * p,int count)645 seprintdata(char *s, char *se, uchar *p, int count)
646 {
647 int i;
648
649 if(count == 0)
650 return s;
651 for(i = 0; i < 20 && i < count; i++)
652 s = seprint(s, se, " %02x", p[i]);
653 return s;
654 }
655
656 static void
SRdumpReq(ScsiReq * rp)657 SRdumpReq(ScsiReq *rp)
658 {
659 char buf[128];
660 char *s;
661 char *se;
662
663 se = buf+sizeof(buf);
664 s = seprint(buf, se, "lun %d ", rp->lun);
665 s = seprintcmd(s, se, (char*)rp->cmd.p, rp->cmd.count, 1);
666 s = seprint(s, se, " [%ld]", rp->data.count);
667 if(rp->cmd.write)
668 seprintdata(s, se, rp->data.p, rp->data.count);
669 fprint(2, "scsi⇒ %s\n", buf);
670 }
671
672 static void
SRdumpRep(ScsiReq * rp)673 SRdumpRep(ScsiReq *rp)
674 {
675 char buf[128];
676 char *s;
677 char *se;
678
679 se = buf+sizeof(buf);
680 s = seprint(buf, se, "lun %d ", rp->lun);
681 s = seprintcmd(s, se, (char*)rp->cmd.p, rp->cmd.count, 0);
682 switch(rp->status){
683 case STok:
684 s = seprint(s, se, " good [%ld] ", rp->data.count);
685 if(rp->cmd.write == 0)
686 s = seprintdata(s, se, rp->data.p, rp->data.count);
687 break;
688 case STnomem:
689 s = seprint(s, se, " buffer allocation failed");
690 break;
691 case STharderr:
692 s = seprint(s, se, " controller error");
693 break;
694 case STtimeout:
695 s = seprint(s, se, " bus timeout");
696 break;
697 case STcheck:
698 s = seprint(s, se, " check condition");
699 break;
700 case STcondmet:
701 s = seprint(s, se, " condition met/good");
702 break;
703 case STbusy:
704 s = seprint(s, se, " busy");
705 break;
706 case STintok:
707 s = seprint(s, se, " intermediate/good");
708 break;
709 case STintcondmet:
710 s = seprint(s, se, " intermediate/condition met/good");
711 break;
712 case STresconf:
713 s = seprint(s, se, " reservation conflict");
714 break;
715 case STterminated:
716 s = seprint(s, se, " command terminated");
717 break;
718 case STqfull:
719 s = seprint(s, se, " queue full");
720 break;
721 default:
722 s = seprint(s, se, " sts=%#x", rp->status);
723 }
724 USED(s);
725 fprint(2, "scsi← %s\n", buf);
726 }
727
728 static char*
scsierr(ScsiReq * rp)729 scsierr(ScsiReq *rp)
730 {
731 int ec;
732
733 switch(rp->status){
734 case 0:
735 return "";
736 case Status_SD:
737 ec = (rp->sense[12] << 8) | rp->sense[13];
738 return scsierrmsg(ec);
739 case Status_SW:
740 return "software error";
741 case Status_BADARG:
742 return "bad argument";
743 case Status_RO:
744 return "device is read only";
745 default:
746 return "unknown";
747 }
748 }
749
750 static void
SRdumpErr(ScsiReq * rp)751 SRdumpErr(ScsiReq *rp)
752 {
753 char buf[128];
754 char *se;
755
756 se = buf+sizeof(buf);
757 seprintcmd(buf, se, (char*)rp->cmd.p, rp->cmd.count, 0);
758 fprint(2, "\t%s status: %s\n", buf, scsierr(rp));
759 }
760
761 long
SRrequest(ScsiReq * rp)762 SRrequest(ScsiReq *rp)
763 {
764 long n;
765 int status;
766
767 retry:
768 if(debug)
769 SRdumpReq(rp);
770 if(rp->flags&Fusb)
771 n = umsrequest(rp->umsc, &rp->cmd, &rp->data, &status);
772 else
773 n = request(rp->fd, &rp->cmd, &rp->data, &status);
774 rp->status = status;
775 if(status == STok)
776 rp->data.count = n;
777 if(debug)
778 SRdumpRep(rp);
779 switch(status){
780 case STok:
781 break;
782 case STcheck:
783 if(rp->cmd.p[0] != ScmdRsense && SRreqsense(rp) != -1)
784 rp->status = Status_SD;
785 if(debug || exabyte)
786 SRdumpErr(rp);
787 werrstr("%s", scsierr(rp));
788 return -1;
789 case STbusy:
790 sleep(1000); /* TODO: try a shorter sleep? */
791 goto retry;
792 default:
793 if(debug || exabyte)
794 SRdumpErr(rp);
795 werrstr("%s", scsierr(rp));
796 return -1;
797 }
798 return n;
799 }
800
801 int
SRclose(ScsiReq * rp)802 SRclose(ScsiReq *rp)
803 {
804 if((rp->flags & Fopen) == 0){
805 if(diskdebug)
806 fprint(2, "disk: closing closed file\n");
807 rp->status = Status_BADARG;
808 return -1;
809 }
810 close(rp->fd);
811 rp->flags = 0;
812 return 0;
813 }
814
815 static int
dirdevopen(ScsiReq * rp)816 dirdevopen(ScsiReq *rp)
817 {
818 uvlong blocks;
819 uchar data[8+4+20]; /* 16-byte result: lba, blksize, reserved */
820
821 memset(data, 0, sizeof data);
822 if(SRstart(rp, 1) == -1 || SRrcapacity(rp, data) == -1)
823 return -1;
824 rp->lbsize = GETBELONG(data+4);
825 blocks = GETBELONG(data);
826 if(debug)
827 fprint(2, "disk: dirdevopen: 10-byte logical block size %lud, "
828 "# blocks %llud\n", rp->lbsize, blocks);
829 if(blocks == 0xffffffff){
830 if(SRrcapacity16(rp, data) == -1)
831 return -1;
832 rp->lbsize = GETBELONG(data + 8);
833 blocks = (vlong)GETBELONG(data)<<32 | GETBELONG(data + 4);
834 if(debug)
835 fprint(2, "disk: dirdevopen: 16-byte logical block size"
836 " %lud, # blocks %llud\n", rp->lbsize, blocks);
837 }
838 /* some newer dev's don't support 6-byte commands */
839 if(blocks > Max24off && !force6bytecmds)
840 rp->flags |= Frw10;
841 return 0;
842 }
843
844 static int
seqdevopen(ScsiReq * rp)845 seqdevopen(ScsiReq *rp)
846 {
847 uchar mode[16], limits[6];
848
849 if(SRrblimits(rp, limits) == -1)
850 return -1;
851 if(limits[1] == 0 && limits[2] == limits[4] && limits[3] == limits[5]){
852 rp->flags |= Fbfixed;
853 rp->lbsize = limits[4]<<8 | limits[5];
854 if(debug)
855 fprint(2, "disk: seqdevopen: 10-byte logical block size %lud\n",
856 rp->lbsize);
857 return 0;
858 }
859 /*
860 * On some older hardware the optional 10-byte
861 * modeselect command isn't implemented.
862 */
863 if (force6bytecmds)
864 rp->flags |= Fmode6;
865 if(!(rp->flags & Fmode6)){
866 /* try 10-byte command first */
867 memset(mode, 0, sizeof mode);
868 mode[3] = 0x10; /* device-specific param. */
869 mode[7] = 8; /* block descriptor length */
870 /*
871 * exabytes can't handle this, and
872 * modeselect(10) is optional.
873 */
874 if(SRmodeselect10(rp, mode, sizeof mode) != -1){
875 rp->lbsize = 1;
876 return 0; /* success */
877 }
878 /* can't do 10-byte commands, back off to 6-byte ones */
879 rp->flags |= Fmode6;
880 }
881
882 /* 6-byte command */
883 memset(mode, 0, sizeof mode);
884 mode[2] = 0x10; /* device-specific param. */
885 mode[3] = 8; /* block descriptor length */
886 /*
887 * bsd sez exabytes need this bit (NBE: no busy enable) in
888 * vendor-specific page (0), but so far we haven't needed it.
889 mode[12] |= 8;
890 */
891 if(SRmodeselect6(rp, mode, 4+8) == -1)
892 return -1;
893 rp->lbsize = 1;
894 return 0;
895 }
896
897 static int
wormdevopen(ScsiReq * rp)898 wormdevopen(ScsiReq *rp)
899 {
900 long status;
901 uchar list[MaxDirData];
902
903 if (SRstart(rp, 1) == -1 ||
904 (status = SRmodesense10(rp, Allmodepages, list, sizeof list)) == -1)
905 return -1;
906 /* nbytes = list[0]<<8 | list[1]; */
907
908 /* # of bytes of block descriptors of 8 bytes each; not even 1? */
909 if((list[6]<<8 | list[7]) < 8)
910 rp->lbsize = 2048;
911 else
912 /* last 3 bytes of block 0 descriptor */
913 rp->lbsize = GETBE24(list+13);
914 if(debug)
915 fprint(2, "disk: wormdevopen: 10-byte logical block size %lud\n",
916 rp->lbsize);
917 return status;
918 }
919
920 int
SRopenraw(ScsiReq * rp,char * unit)921 SRopenraw(ScsiReq *rp, char *unit)
922 {
923 char name[128];
924
925 if(rp->flags & Fopen){
926 if(diskdebug)
927 fprint(2, "disk: opening open file\n");
928 rp->status = Status_BADARG;
929 return -1;
930 }
931 memset(rp, 0, sizeof *rp);
932 rp->unit = unit;
933
934 snprint(name, sizeof name, "%s/raw", unit);
935 if((rp->fd = open(name, ORDWR)) == -1){
936 rp->status = STtimeout;
937 return -1;
938 }
939 rp->flags = Fopen;
940 return 0;
941 }
942
943 int
SRopen(ScsiReq * rp,char * unit)944 SRopen(ScsiReq *rp, char *unit)
945 {
946 if(SRopenraw(rp, unit) == -1)
947 return -1;
948 SRready(rp);
949 if(SRinquiry(rp) >= 0){
950 switch(rp->inquiry[0]){
951
952 default:
953 fprint(2, "unknown device type 0x%.2x\n", rp->inquiry[0]);
954 rp->status = Status_SW;
955 break;
956
957 case Devdir:
958 case Devcd:
959 case Devmo:
960 if(dirdevopen(rp) == -1)
961 break;
962 return 0;
963
964 case Devseq:
965 rp->flags |= Fseqdev;
966 if(seqdevopen(rp) == -1)
967 break;
968 return 0;
969
970 case Devprint:
971 rp->flags |= Fprintdev;
972 return 0;
973
974 case Devworm:
975 rp->flags |= Fwormdev;
976 if(wormdevopen(rp) == -1)
977 break;
978 return 0;
979
980 case Devjuke:
981 rp->flags |= Fchanger;
982 return 0;
983 }
984 }
985 SRclose(rp);
986 return -1;
987 }
988