xref: /plan9/sys/src/cmd/usb/disk/scsireq.c (revision fd362a73ff89ae80075dd82c9aad2a3468f0f3c9)
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