xref: /plan9/sys/src/cmd/usb/disk/scsireq.c (revision 3468a4915d661daa200976acc4f80f51aae144b2)
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 we see the diagnostics if we boot with debug enabled.
10  *
11  */
12 
13 #include <u.h>
14 #include <libc.h>
15 /*
16  * BUGS:
17  *	no luns
18  *	and incomplete in many other ways
19  */
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
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
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
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
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
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
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
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 long
206 SRread(ScsiReq *rp, void *buf, long nbytes)
207 {
208 	uchar cmd[10];
209 	long n;
210 
211 	if((nbytes % rp->lbsize) || nbytes > maxiosize){
212 		rp->status = Status_BADARG;
213 		return -1;
214 	}
215 
216 	/* set up scsi read cmd */
217 	cmd[0] = ScmdRead;
218 	if(rp->flags & Fseqdev)
219 		rp->cmd.count = seqdevrw(rp, cmd, nbytes);
220 	else
221 		rp->cmd.count = dirdevrw(rp, cmd, nbytes);
222 	rp->cmd.p = cmd;
223 	rp->data.p = buf;
224 	rp->data.count = nbytes;
225 	rp->data.write = 0;
226 
227 	/* issue it */
228 	n = SRrequest(rp);
229 	if(n != -1){			/* it worked? */
230 		rp->offset += n / rp->lbsize;
231 		return n;
232 	}
233 
234 	/* request failed; maybe we just read a short record? */
235 	if (exabyte) {
236 		fprint(2, "read error\n");
237 		rp->status = STcheck;
238 		return n;
239 	}
240 	if(rp->status != Status_SD || !(rp->sense[0] & Sd0valid))
241 		return -1;
242 	/* compute # of bytes not read */
243 	n = GETBELONG(rp->sense+3) * rp->lbsize;
244 	if(!(rp->flags & Fseqdev))
245 		return -1;
246 
247 	/* device is a tape or something similar */
248 	if (rp->sense[2] == Sd2filemark || rp->sense[2] == 0x08 ||
249 	    rp->sense[2] & Sd2ili && n > 0)
250 		rp->data.count = nbytes - n;
251 	else
252 		return -1;
253 	n = rp->data.count;
254 	if (!rp->readblock++ || debug)
255 		fprint(2, "SRread: tape data count %ld%s\n", n,
256 			(rp->sense[2] & Sd2ili? " with ILI": ""));
257 	rp->status = STok;
258 	rp->offset += n / rp->lbsize;
259 	return n;
260 }
261 
262 long
263 SRwrite(ScsiReq *rp, void *buf, long nbytes)
264 {
265 	uchar cmd[10];
266 	long n;
267 
268 	if((nbytes % rp->lbsize) || nbytes > maxiosize){
269 		rp->status = Status_BADARG;
270 		return -1;
271 	}
272 
273 	/* set up scsi write cmd */
274 	cmd[0] = ScmdWrite;
275 	if(rp->flags & Fseqdev)
276 		rp->cmd.count = seqdevrw(rp, cmd, nbytes);
277 	else
278 		rp->cmd.count = dirdevrw(rp, cmd, nbytes);
279 	rp->cmd.p = cmd;
280 	rp->data.p = buf;
281 	rp->data.count = nbytes;
282 	rp->data.write = 1;
283 
284 	/* issue it */
285 	if((n = SRrequest(rp)) == -1){
286 		if (exabyte) {
287 			fprint(2, "write error\n");
288 			rp->status = STcheck;
289 			return n;
290 		}
291 		if(rp->status != Status_SD || rp->sense[2] != Sd2eom)
292 			return -1;
293 		if(rp->sense[0] & Sd0valid){
294 			n -= GETBELONG(rp->sense+3) * rp->lbsize;
295 			rp->data.count = nbytes - n;
296 		}
297 		else
298 			rp->data.count = nbytes;
299 		n = rp->data.count;
300 	}
301 	rp->offset += n / rp->lbsize;
302 	return n;
303 }
304 
305 long
306 SRseek(ScsiReq *rp, long offset, int type)
307 {
308 	uchar cmd[10];
309 
310 	switch(type){
311 
312 	case 0:
313 		break;
314 
315 	case 1:
316 		offset += rp->offset;
317 		if(offset >= 0)
318 			break;
319 		/*FALLTHROUGH*/
320 
321 	default:
322 		rp->status = Status_BADARG;
323 		return -1;
324 	}
325 	memset(cmd, 0, sizeof cmd);
326 	if(offset <= Max24off && (rp->flags & Frw10) == 0){
327 		cmd[0] = ScmdSeek;
328 		PUTBE24(cmd+1, offset & Max24off);
329 		rp->cmd.count = 6;
330 	}else{
331 		cmd[0] = ScmdExtseek;
332 		PUTBELONG(cmd+2, offset);
333 		rp->cmd.count = 10;
334 	}
335 	rp->cmd.p = cmd;
336 	rp->data.p = cmd;
337 	rp->data.count = 0;
338 	rp->data.write = 1;
339 	SRrequest(rp);
340 	if(rp->status == STok)
341 		return rp->offset = offset;
342 	return -1;
343 }
344 
345 long
346 SRfilemark(ScsiReq *rp, ulong howmany)
347 {
348 	uchar cmd[6];
349 
350 	memset(cmd, 0, sizeof cmd);
351 	cmd[0] = ScmdFmark;
352 	PUTBE24(cmd+2, howmany);
353 	rp->cmd.p = cmd;
354 	rp->cmd.count = sizeof cmd;
355 	rp->data.p = cmd;
356 	rp->data.count = 0;
357 	rp->data.write = 1;
358 	return SRrequest(rp);
359 }
360 
361 long
362 SRspace(ScsiReq *rp, uchar code, long howmany)
363 {
364 	uchar cmd[6];
365 
366 	memset(cmd, 0, sizeof cmd);
367 	cmd[0] = ScmdSpace;
368 	cmd[1] = code;
369 	PUTBE24(cmd+2, howmany);
370 	rp->cmd.p = cmd;
371 	rp->cmd.count = sizeof cmd;
372 	rp->data.p = cmd;
373 	rp->data.count = 0;
374 	rp->data.write = 1;
375 	/*
376 	 * what about rp->offset?
377 	 */
378 	return SRrequest(rp);
379 }
380 
381 long
382 SRinquiry(ScsiReq *rp)
383 {
384 	uchar cmd[6];
385 
386 	memset(cmd, 0, sizeof cmd);
387 	cmd[0] = ScmdInq;
388 	cmd[4] = sizeof rp->inquiry;
389 	rp->cmd.p = cmd;
390 	rp->cmd.count = sizeof cmd;
391 	memset(rp->inquiry, 0, sizeof rp->inquiry);
392 	rp->data.p = rp->inquiry;
393 	rp->data.count = sizeof rp->inquiry;
394 	rp->data.write = 0;
395 	if(SRrequest(rp) >= 0){
396 		rp->flags |= Finqok;
397 		return 0;
398 	}
399 	rp->flags &= ~Finqok;
400 	return -1;
401 }
402 
403 long
404 SRmodeselect6(ScsiReq *rp, uchar *list, long nbytes)
405 {
406 	uchar cmd[6];
407 
408 	memset(cmd, 0, sizeof cmd);
409 	cmd[0] = ScmdMselect6;
410 	if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)
411 		cmd[1] = 0x10;
412 	cmd[4] = nbytes;
413 	rp->cmd.p = cmd;
414 	rp->cmd.count = sizeof cmd;
415 	rp->data.p = list;
416 	rp->data.count = nbytes;
417 	rp->data.write = 1;
418 	return SRrequest(rp);
419 }
420 
421 long
422 SRmodeselect10(ScsiReq *rp, uchar *list, long nbytes)
423 {
424 	uchar cmd[10];
425 
426 	memset(cmd, 0, sizeof cmd);
427 	if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)
428 		cmd[1] = 0x10;
429 	cmd[0] = ScmdMselect10;
430 	cmd[7] = nbytes>>8;
431 	cmd[8] = nbytes;
432 	rp->cmd.p = cmd;
433 	rp->cmd.count = sizeof cmd;
434 	rp->data.p = list;
435 	rp->data.count = nbytes;
436 	rp->data.write = 1;
437 	return SRrequest(rp);
438 }
439 
440 long
441 SRmodesense6(ScsiReq *rp, uchar page, uchar *list, long nbytes)
442 {
443 	uchar cmd[6];
444 
445 	memset(cmd, 0, sizeof cmd);
446 	cmd[0] = ScmdMsense6;
447 	cmd[2] = page;
448 	cmd[4] = nbytes;
449 	rp->cmd.p = cmd;
450 	rp->cmd.count = sizeof cmd;
451 	rp->data.p = list;
452 	rp->data.count = nbytes;
453 	rp->data.write = 0;
454 	return SRrequest(rp);
455 }
456 
457 long
458 SRmodesense10(ScsiReq *rp, uchar page, uchar *list, long nbytes)
459 {
460 	uchar cmd[10];
461 
462 	memset(cmd, 0, sizeof cmd);
463 	cmd[0] = ScmdMsense10;
464 	cmd[2] = page;
465 	cmd[7] = nbytes>>8;
466 	cmd[8] = nbytes;
467 	rp->cmd.p = cmd;
468 	rp->cmd.count = sizeof cmd;
469 	rp->data.p = list;
470 	rp->data.count = nbytes;
471 	rp->data.write = 0;
472 	return SRrequest(rp);
473 }
474 
475 long
476 SRstart(ScsiReq *rp, uchar code)
477 {
478 	uchar cmd[6];
479 
480 	memset(cmd, 0, sizeof cmd);
481 	cmd[0] = ScmdStart;
482 	cmd[4] = code;
483 	rp->cmd.p = cmd;
484 	rp->cmd.count = sizeof cmd;
485 	rp->data.p = cmd;
486 	rp->data.count = 0;
487 	rp->data.write = 1;
488 	return SRrequest(rp);
489 }
490 
491 long
492 SRrcapacity(ScsiReq *rp, uchar *data)
493 {
494 	uchar cmd[10];
495 
496 	memset(cmd, 0, sizeof cmd);
497 	cmd[0] = ScmdRcapacity;
498 	rp->cmd.p = cmd;
499 	rp->cmd.count = sizeof cmd;
500 	rp->data.p = data;
501 	rp->data.count = 8;
502 	rp->data.write = 0;
503 	return SRrequest(rp);
504 }
505 
506 long
507 SRrcapacity16(ScsiReq *rp, uchar *data)
508 {
509 	uchar cmd[16];
510 	uint i;
511 
512 	i = 32;
513 	memset(cmd, 0, sizeof cmd);
514 	cmd[0] = ScmdRcapacity16;
515 	cmd[1] = 0x10;
516 	cmd[10] = i>>24;
517 	cmd[11] = i>>16;
518 	cmd[12] = i>>8;
519 	cmd[13] = i;
520 
521 	rp->cmd.p = cmd;
522 	rp->cmd.count = sizeof cmd;
523 	rp->data.p = data;
524 	rp->data.count = i;
525 	rp->data.write = 0;
526 	return SRrequest(rp);
527 }
528 
529 void
530 scsidebug(int d)
531 {
532 	debug = d;
533 	if(debug)
534 		fprint(2, "scsidebug on\n");
535 }
536 
537 static long
538 request(int fd, ScsiPtr *cmd, ScsiPtr *data, int *status)
539 {
540 	long n, r;
541 	char buf[16];
542 
543 	/* this was an experiment but it seems to be a good idea */
544 	*status = STok;
545 
546 	/* send SCSI command */
547 	if(write(fd, cmd->p, cmd->count) != cmd->count){
548 		fprint(2, "scsireq: write cmd: %r\n");
549 		*status = Status_SW;
550 		return -1;
551 	}
552 
553 	/* read or write actual data */
554 	werrstr("");
555 	if(data->write)
556 		n = write(fd, data->p, data->count);
557 	else {
558 		n = read(fd, data->p, data->count);
559 		if (n < 0)
560 			memset(data->p, 0, data->count);
561 		else if (n < data->count)
562 			memset(data->p + n, 0, data->count - n);
563 	}
564 	if (n != data->count && n <= 0) {
565 		if (debug)
566 			fprint(2,
567 	"request: tried to %s %ld bytes of data for cmd 0x%x but got %r\n",
568 				(data->write? "write": "read"),
569 				data->count, cmd->p[0]);
570 	} else if (n != data->count && (data->write || debug))
571 		fprint(2, "request: %s %ld of %ld bytes of actual data\n",
572 			(data->write? "wrote": "read"), n, data->count);
573 
574 	/* read status */
575 	buf[0] = '\0';
576 	r = read(fd, buf, sizeof buf-1);
577 	if(exabyte && r <= 0 || !exabyte && r < 0){
578 		fprint(2, "scsireq: read status: %r\n");
579 		*status = Status_SW;
580 		return -1;
581 	}
582 	if (r >= 0)
583 		buf[r] = '\0';
584 	*status = atoi(buf);
585 	if(n < 0 && (exabyte || *status != STcheck))
586 		fprint(2, "scsireq: status 0x%2.2uX: data transfer: %r\n",
587 			*status);
588 	return n;
589 }
590 
591 static char*
592 seprintcmd(char *s, char* e, char *cmd, int count, int args)
593 {
594 	uint c;
595 
596 	if(count < 6)
597 		return seprint(s, e, "<short cmd>");
598 	c = cmd[0];
599 	if(scmdnames[c] != nil)
600 		s = seprint(s, e, "%s", scmdnames[c]);
601 	else
602 		s = seprint(s, e, "cmd:%#02uX", c);
603 	if(args != 0)
604 		switch(c){
605 		case ScmdRsense:
606 		case ScmdInq:
607 		case ScmdMselect6:
608 		case ScmdMsense6:
609 			s = seprint(s, e, " sz %d", cmd[4]);
610 			break;
611 		case ScmdSpace:
612 			s = seprint(s, e, " code %d", cmd[1]);
613 			break;
614 		case ScmdStart:
615 			s = seprint(s, e, " code %d", cmd[4]);
616 			break;
617 
618 		}
619 	return s;
620 }
621 
622 static char*
623 seprintdata(char *s, char *se, uchar *p, int count)
624 {
625 	int i;
626 
627 	if(count == 0)
628 		return s;
629 	for(i = 0; i < 20 && i < count; i++)
630 		s = seprint(s, se, " %02x", p[i]);
631 	return s;
632 }
633 
634 static void
635 SRdumpReq(ScsiReq *rp)
636 {
637 	char buf[128];
638 	char *s;
639 	char *se;
640 
641 	se = buf+sizeof(buf);
642 	s = seprint(buf, se, "lun %d ", rp->lun);
643 	s = seprintcmd(s, se, (char*)rp->cmd.p, rp->cmd.count, 1);
644 	s = seprint(s, se, " [%ld]", rp->data.count);
645 	if(rp->cmd.write)
646 		seprintdata(s, se, rp->data.p, rp->data.count);
647 	fprint(2, "scsi⇒ %s\n", buf);
648 }
649 
650 static void
651 SRdumpRep(ScsiReq *rp)
652 {
653 	char buf[128];
654 	char *s;
655 	char *se;
656 
657 	se = buf+sizeof(buf);
658 	s = seprint(buf, se, "lun %d ", rp->lun);
659 	s = seprintcmd(s, se, (char*)rp->cmd.p, rp->cmd.count, 0);
660 	switch(rp->status){
661 	case STok:
662 		s = seprint(s, se, " good [%ld] ", rp->data.count);
663 		if(rp->cmd.write == 0)
664 			s = seprintdata(s, se, rp->data.p, rp->data.count);
665 		break;
666 	case STnomem:
667 		s = seprint(s, se, " buffer allocation failed");
668 		break;
669 	case STharderr:
670 		s = seprint(s, se, " controller error");
671 		break;
672 	case STtimeout:
673 		s = seprint(s, se, " bus timeout");
674 		break;
675 	case STcheck:
676 		s = seprint(s, se, " check condition");
677 		break;
678 	case STcondmet:
679 		s = seprint(s, se, " condition met/good");
680 		break;
681 	case STbusy:
682 		s = seprint(s, se, " busy");
683 		break;
684 	case STintok:
685 		s = seprint(s, se, " intermediate/good");
686 		break;
687 	case STintcondmet:
688 		s = seprint(s, se, " intermediate/condition met/good");
689 		break;
690 	case STresconf:
691 		s = seprint(s, se, " reservation conflict");
692 		break;
693 	case STterminated:
694 		s = seprint(s, se, " command terminated");
695 		break;
696 	case STqfull:
697 		s = seprint(s, se, " queue full");
698 		break;
699 	default:
700 		s = seprint(s, se, " sts=%#x", rp->status);
701 	}
702 	USED(s);
703 	fprint(2, "scsi← %s\n", buf);
704 }
705 
706 static char*
707 scsierr(ScsiReq *rp)
708 {
709 	int ec;
710 
711 	switch(rp->status){
712 	case 0:
713 		return "";
714 	case Status_SD:
715 		ec = (rp->sense[12] << 8) | rp->sense[13];
716 		return scsierrmsg(ec);
717 	case Status_SW:
718 		return "software error";
719 	case Status_BADARG:
720 		return "bad argument";
721 	case Status_RO:
722 		return "device is read only";
723 	default:
724 		return "unknown";
725 	}
726 }
727 
728 static void
729 SRdumpErr(ScsiReq *rp)
730 {
731 	char buf[128];
732 	char *se;
733 
734 	se = buf+sizeof(buf);
735 	seprintcmd(buf, se, (char*)rp->cmd.p, rp->cmd.count, 0);
736 	print("\t%s status: %s\n", buf, scsierr(rp));
737 }
738 
739 long
740 SRrequest(ScsiReq *rp)
741 {
742 	long n;
743 	int status;
744 
745 retry:
746 	if(debug)
747 		SRdumpReq(rp);
748 	if(rp->flags&Fusb)
749 		n = umsrequest(rp->umsc, &rp->cmd, &rp->data, &status);
750 	else
751 		n = request(rp->fd, &rp->cmd, &rp->data, &status);
752 	rp->status = status;
753 	if(status == STok)
754 		rp->data.count = n;
755 	if(debug)
756 		SRdumpRep(rp);
757 	switch(status){
758 	case STok:
759 		break;
760 	case STcheck:
761 		if(rp->cmd.p[0] != ScmdRsense && SRreqsense(rp) != -1)
762 			rp->status = Status_SD;
763 		if(debug || exabyte)
764 			SRdumpErr(rp);
765 		werrstr("%s", scsierr(rp));
766 		return -1;
767 	case STbusy:
768 		sleep(1000);
769 		goto retry;
770 	default:
771 		if(debug || exabyte)
772 			SRdumpErr(rp);
773 		werrstr("%s", scsierr(rp));
774 		return -1;
775 	}
776 	return n;
777 }
778 
779 int
780 SRclose(ScsiReq *rp)
781 {
782 	if((rp->flags & Fopen) == 0){
783 		rp->status = Status_BADARG;
784 		return -1;
785 	}
786 	close(rp->fd);
787 	rp->flags = 0;
788 	return 0;
789 }
790 
791 static int
792 dirdevopen(ScsiReq *rp)
793 {
794 	ulong blocks;
795 	uchar data[8];
796 
797 	if(SRstart(rp, 1) == -1 || SRrcapacity(rp, data) == -1)
798 		return -1;
799 	rp->lbsize = GETBELONG(data+4);
800 	blocks =     GETBELONG(data);
801 	if(blocks == 0xffffffff){
802 		if(SRrcapacity16(rp, data) == -1)
803 			return -1;
804 		rp->lbsize = GETBELONG(data + 8);
805 		blocks = (vlong)GETBELONG(data)<<32 | GETBELONG(data + 4);
806 	}
807 	/* some newer dev's don't support 6-byte commands */
808 	if(blocks > Max24off && !force6bytecmds)
809 		rp->flags |= Frw10;
810 	return 0;
811 }
812 
813 static int
814 seqdevopen(ScsiReq *rp)
815 {
816 	uchar mode[16], limits[6];
817 
818 	if(SRrblimits(rp, limits) == -1)
819 		return -1;
820 	if(limits[1] == 0 && limits[2] == limits[4] && limits[3] == limits[5]){
821 		rp->flags |= Fbfixed;
822 		rp->lbsize = limits[4]<<8 | limits[5];
823 		return 0;
824 	}
825 	/*
826 	 * On some older hardware the optional 10-byte
827 	 * modeselect command isn't implemented.
828 	 */
829 	if (force6bytecmds)
830 		rp->flags |= Fmode6;
831 	if(!(rp->flags & Fmode6)){
832 		/* try 10-byte command first */
833 		memset(mode, 0, sizeof mode);
834 		mode[3] = 0x10;		/* device-specific param. */
835 		mode[7] = 8;		/* block descriptor length */
836 		/*
837 		 * exabytes can't handle this, and
838 		 * modeselect(10) is optional.
839 		 */
840 		if(SRmodeselect10(rp, mode, sizeof mode) != -1){
841 			rp->lbsize = 1;
842 			return 0;	/* success */
843 		}
844 		/* can't do 10-byte commands, back off to 6-byte ones */
845 		rp->flags |= Fmode6;
846 	}
847 
848 	/* 6-byte command */
849 	memset(mode, 0, sizeof mode);
850 	mode[2] = 0x10;		/* device-specific param. */
851 	mode[3] = 8;		/* block descriptor length */
852 	/*
853 	 * bsd sez exabytes need this bit (NBE: no busy enable) in
854 	 * vendor-specific page (0), but so far we haven't needed it.
855 	mode[12] |= 8;
856 	 */
857 	if(SRmodeselect6(rp, mode, 4+8) == -1)
858 		return -1;
859 	rp->lbsize = 1;
860 	return 0;
861 }
862 
863 static int
864 wormdevopen(ScsiReq *rp)
865 {
866 	long status;
867 	uchar list[MaxDirData];
868 
869 	if (SRstart(rp, 1) == -1 ||
870 	    (status = SRmodesense10(rp, Allmodepages, list, sizeof list)) == -1)
871 		return -1;
872 	/* nbytes = list[0]<<8 | list[1]; */
873 
874 	/* # of bytes of block descriptors of 8 bytes each; not even 1? */
875 	if((list[6]<<8 | list[7]) < 8)
876 		rp->lbsize = 2048;
877 	else
878 		/* last 3 bytes of block 0 descriptor */
879 		rp->lbsize = GETBE24(list+13);
880 	return status;
881 }
882 
883 int
884 SRopenraw(ScsiReq *rp, char *unit)
885 {
886 	char name[128];
887 
888 	if(rp->flags & Fopen){
889 		rp->status = Status_BADARG;
890 		return -1;
891 	}
892 	memset(rp, 0, sizeof *rp);
893 	rp->unit = unit;
894 
895 	sprint(name, "%s/raw", unit);
896 
897 	if((rp->fd = open(name, ORDWR)) == -1){
898 		rp->status = STtimeout;
899 		return -1;
900 	}
901 	rp->flags = Fopen;
902 	return 0;
903 }
904 
905 int
906 SRopen(ScsiReq *rp, char *unit)
907 {
908 	if(SRopenraw(rp, unit) == -1)
909 		return -1;
910 	SRready(rp);
911 	if(SRinquiry(rp) >= 0){
912 		switch(rp->inquiry[0]){
913 
914 		default:
915 			fprint(2, "unknown device type 0x%.2x\n", rp->inquiry[0]);
916 			rp->status = Status_SW;
917 			break;
918 
919 		case Devdir:
920 		case Devcd:
921 		case Devmo:
922 			if(dirdevopen(rp) == -1)
923 				break;
924 			return 0;
925 
926 		case Devseq:
927 			rp->flags |= Fseqdev;
928 			if(seqdevopen(rp) == -1)
929 				break;
930 			return 0;
931 
932 		case Devprint:
933 			rp->flags |= Fprintdev;
934 			return 0;
935 
936 		case Devworm:
937 			rp->flags |= Fwormdev;
938 			if(wormdevopen(rp) == -1)
939 				break;
940 			return 0;
941 
942 		case Devjuke:
943 			rp->flags |= Fchanger;
944 			return 0;
945 		}
946 	}
947 	SRclose(rp);
948 	return -1;
949 }
950