Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_posix/sys/src/cmd/usb/disk/scsireq.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
extern int diskdebug;
206
 
207
long
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
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
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
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
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
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
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
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
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
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
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
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
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
550
scsidebug(int d)
551
{
552
	debug = d;
553
	if(debug)
554
		fprint(2, "scsidebug on\n");
555
}
556
 
557
static long
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*
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*
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
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
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*
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
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
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
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
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
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
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
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
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
}