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_tlsv12/sys/src/cmd/scuzz/scuzz.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
#include <u.h>
2
#include <libc.h>
3
#include <bio.h>
4
#include <disk.h>
5
#include "scsireq.h"
6
 
7
enum {					/* fundamental constants/defaults */
8
	/*
9
	 * default & maximum `maximum i/o size'; overridden by -m.
10
	 * limits kernel memory consumption.
11
	 * 240K is exabyte maximum block size.
12
	 */
13
	MaxIOsize	= 240*1024,
14
};
15
 
16
#define MIN(a, b)	((a) < (b) ? (a): (b))
17
 
18
static char rwbuf[MaxIOsize];
19
static int verbose = 1;
20
 
21
Biobuf bin, bout;
22
long maxiosize = MaxIOsize;
23
int exabyte = 0;
24
int force6bytecmds = 0;
25
 
26
typedef struct {
27
	char *name;
28
	long (*f)(ScsiReq *, int, char *[]);
29
	int open;
30
	char *help;
31
} ScsiCmd;
32
 
33
static ScsiCmd scsicmds[];
34
 
35
static vlong
36
vlmin(vlong a, vlong b)
37
{
38
	if (a < b)
39
		return a;
40
	else
41
		return b;
42
}
43
 
44
static long
45
cmdready(ScsiReq *rp, int argc, char *argv[])
46
{
47
	USED(argc, argv);
48
	return SRready(rp);
49
}
50
 
51
static long
52
cmdrewind(ScsiReq *rp, int argc, char *argv[])
53
{
54
	USED(argc, argv);
55
	return SRrewind(rp);
56
}
57
 
58
static long
59
cmdreqsense(ScsiReq *rp, int argc, char *argv[])
60
{
61
	long nbytes;
62
 
63
	USED(argc, argv);
64
	if((nbytes = SRreqsense(rp)) != -1)
65
		makesense(rp);
66
	return nbytes;
67
}
68
 
69
static long
70
cmdformat(ScsiReq *rp, int argc, char *argv[])
71
{
72
	USED(argc, argv);
73
	return SRformat(rp);
74
}
75
 
76
static long
77
cmdrblimits(ScsiReq *rp, int argc, char *argv[])
78
{
79
	uchar l[6];
80
	long n;
81
 
82
	USED(argc, argv);
83
	if((n = SRrblimits(rp, l)) == -1)
84
		return -1;
85
	Bprint(&bout, " %2.2uX %2.2uX %2.2uX %2.2uX %2.2uX %2.2uX\n",
86
		l[0], l[1], l[2], l[3], l[4], l[5]);
87
	return n;
88
}
89
 
90
static int
91
mkfile(char *file, int omode, int *pid)
92
{
93
	int fd[2];
94
 
95
	if(*file != '|'){
96
		*pid = -1;
97
		if(omode == OWRITE)
98
			return create(file, OWRITE, 0666);
99
		else if(omode == OREAD)
100
			return open(file, OREAD);
101
		return -1;
102
	}
103
 
104
	file++;
105
	if(*file == 0 || pipe(fd) == -1)
106
		return -1;
107
	if((*pid = fork()) == -1){
108
		close(fd[0]);
109
		close(fd[1]);
110
		return -1;
111
	}
112
	if(*pid == 0){
113
		switch(omode){
114
 
115
		case OREAD:
116
			dup(fd[0], 1);
117
			break;
118
 
119
		case OWRITE:
120
			dup(fd[0], 0);
121
			break;
122
		}
123
		close(fd[0]);
124
		close(fd[1]);
125
		execl("/bin/rc", "rc", "-c", file, nil);
126
		exits("exec");
127
	}
128
	close(fd[0]);
129
	return fd[1];
130
}
131
 
132
int
133
waitfor(int pid)
134
{
135
	int msg;
136
	Waitmsg *w;
137
 
138
	while((w = wait()) != nil){
139
		if(w->pid != pid){
140
			free(w);
141
			continue;
142
		}
143
		msg = (w->msg[0] != '\0');
144
		free(w);
145
		return msg;
146
	}
147
	return -1;
148
}
149
 
150
static long
151
cmdread(ScsiReq *rp, int argc, char *argv[])
152
{
153
	long n, iosize, prevsize = 0;
154
	vlong nbytes, total;
155
	int fd, pid;
156
	char *p;
157
 
158
	iosize = maxiosize;
159
	nbytes = ~0ULL >> 1;
160
	switch(argc){
161
 
162
	default:
163
		rp->status = Status_BADARG;
164
		return -1;
165
 
166
	case 2:
167
		nbytes = strtoll(argv[1], &p, 0);
168
		if(nbytes == 0 && p == argv[1]){
169
			rp->status = Status_BADARG;
170
			return -1;
171
		}
172
		/*FALLTHROUGH*/
173
 
174
	case 1:
175
		if((fd = mkfile(argv[0], OWRITE, &pid)) == -1){
176
			rp->status = Status_BADARG;
177
			return -1;
178
		}
179
		break;
180
	}
181
	print("device native block size=%lud\n", rp->lbsize);
182
	total = 0;
183
	while(nbytes){
184
		n = vlmin(nbytes, iosize);
185
		if((n = SRread(rp, rwbuf, n)) == -1){
186
			if(total == 0)
187
				total = -1;
188
			break;
189
		}
190
		if (n == 0)
191
			break;
192
		if (prevsize != n) {
193
			print("tape block size=%ld\n", n);
194
			prevsize = n;
195
		}
196
		if(write(fd, rwbuf, n) != n){
197
			if(total == 0)
198
				total = -1;
199
			if(rp->status == STok)
200
				rp->status = Status_SW;
201
			break;
202
		}
203
		nbytes -= n;
204
		total += n;
205
	}
206
	close(fd);
207
	if(pid >= 0 && waitfor(pid)){
208
		rp->status = Status_SW;
209
		return -1;
210
	}
211
	return total;
212
}
213
 
214
static long
215
cmdwrite(ScsiReq *rp, int argc, char *argv[])
216
{
217
	long n, prevsize = 0;
218
	vlong nbytes, total;
219
	int fd, pid;
220
	char *p;
221
 
222
	nbytes = ~0ULL >> 1;
223
	switch(argc){
224
 
225
	default:
226
		rp->status = Status_BADARG;
227
		return -1;
228
 
229
	case 2:
230
		nbytes = strtoll(argv[1], &p, 0);
231
		if(nbytes == 0 && p == argv[1]){
232
			rp->status = Status_BADARG;
233
			return -1;
234
		}
235
		/*FALLTHROUGH*/
236
 
237
	case 1:
238
		if((fd = mkfile(argv[0], OREAD, &pid)) == -1){
239
			rp->status = Status_BADARG;
240
			return -1;
241
		}
242
		break;
243
	}
244
	total = 0;
245
	while(nbytes){
246
		n = vlmin(nbytes, maxiosize);
247
		if((n = read(fd, rwbuf, n)) == -1){
248
			if(total == 0)
249
				total = -1;
250
			break;
251
		}
252
		if (n == 0)
253
			break;
254
		if (prevsize != n) {
255
			print("tape block size=%ld\n", n);
256
			prevsize = n;
257
		}
258
		if(SRwrite(rp, rwbuf, n) != n){
259
			if(total == 0)
260
				total = -1;
261
			if(rp->status == STok)
262
				rp->status = Status_SW;
263
			break;
264
		}
265
		nbytes -= n;
266
		total += n;
267
	}
268
	close(fd);
269
	if(pid >= 0 && waitfor(pid)){
270
		rp->status = Status_SW;
271
		return -1;
272
	}
273
	return total;
274
}
275
 
276
static long
277
cmdseek(ScsiReq *rp, int argc, char *argv[])
278
{
279
	char *p;
280
	long offset;
281
	int type;
282
 
283
	type = 0;
284
	switch(argc){
285
 
286
	default:
287
		rp->status = Status_BADARG;
288
		return -1;
289
 
290
	case 2:
291
		if((type = strtol(argv[1], &p, 0)) == 0 && p == argv[1]){
292
			rp->status = Status_BADARG;
293
			return -1;
294
		}
295
		/*FALLTHROUGH*/
296
 
297
	case 1:
298
		if((offset = strtol(argv[0], &p, 0)) == 0 && p == argv[0]){
299
			rp->status = Status_BADARG;
300
			return -1;
301
		}
302
		break;
303
	}
304
	return SRseek(rp, offset, type);
305
}
306
 
307
static long
308
cmdfilemark(ScsiReq *rp, int argc, char *argv[])
309
{
310
	char *p;
311
	ulong howmany;
312
 
313
	howmany = 1;
314
	if(argc && (howmany = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
315
		rp->status = Status_BADARG;
316
		return -1;
317
	}
318
	return SRfilemark(rp, howmany);
319
}
320
 
321
static long
322
cmdspace(ScsiReq *rp, int argc, char *argv[])
323
{
324
	uchar code;
325
	long howmany;
326
	char option, *p;
327
 
328
	code = 0x00;
329
	howmany = 1;
330
	while(argc && (*argv)[0] == '-'){
331
		while(option = *++argv[0]){
332
			switch(option){
333
 
334
			case '-':
335
				break;
336
 
337
			case 'b':
338
				code = 0x00;
339
				break;
340
 
341
			case 'f':
342
				code = 0x01;
343
				break;
344
 
345
			default:
346
				rp->status = Status_BADARG;
347
				return -1;
348
			}
349
			break;
350
		}
351
		argc--; argv++;
352
		if(option == '-')
353
			break;
354
	}
355
	if(argc && ((howmany = strtol(argv[0], &p, 0)) == 0 && p == argv[0])){
356
		rp->status = Status_BADARG;
357
		return -1;
358
	}
359
	return SRspace(rp, code, howmany);
360
}
361
 
362
static long
363
cmdinquiry(ScsiReq *rp, int argc, char *argv[])
364
{
365
	long status;
366
	int i, n;
367
	uchar *p;
368
 
369
	USED(argc, argv);
370
	if((status = SRinquiry(rp)) != -1){
371
		n = rp->inquiry[4]+4;
372
		for(i = 0; i < MIN(8, n); i++)
373
			Bprint(&bout, " %2.2uX", rp->inquiry[i]);
374
		p = &rp->inquiry[8];
375
		n = MIN(n, sizeof(rp->inquiry)-8);
376
		while(n && (*p == ' ' || *p == '\t' || *p == '\n')){
377
			n--;
378
			p++;
379
		}
380
		Bprint(&bout, "\t%.*s\n", n, (char*)p);
381
	}
382
	return status;
383
}
384
 
385
static long
386
cmdmodeselect6(ScsiReq *rp, int argc, char *argv[])
387
{
388
	uchar list[MaxDirData];
389
	long nbytes, ul;
390
	char *p;
391
 
392
	memset(list, 0, sizeof list);
393
	for(nbytes = 0; argc; argc--, argv++, nbytes++){
394
		if((ul = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
395
			rp->status = Status_BADARG;
396
			return -1;
397
		}
398
		list[nbytes] = ul;
399
 
400
	}
401
	if(!(rp->flags & Finqok) && SRinquiry(rp) == -1)
402
		Bprint(&bout, "warning: couldn't determine whether SCSI-1/SCSI-2 mode");
403
	return SRmodeselect6(rp, list, nbytes);
404
}
405
 
406
static long
407
cmdmodeselect10(ScsiReq *rp, int argc, char *argv[])
408
{
409
	uchar list[MaxDirData];
410
	long nbytes, ul;
411
	char *p;
412
 
413
	memset(list, 0, sizeof list);
414
	for(nbytes = 0; argc; argc--, argv++, nbytes++){
415
		if((ul = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
416
			rp->status = Status_BADARG;
417
			return -1;
418
		}
419
		list[nbytes] = ul;
420
 
421
	}
422
	if(!(rp->flags & Finqok) && SRinquiry(rp) == -1)
423
		Bprint(&bout, "warning: couldn't determine whether SCSI-1/SCSI-2 mode");
424
	return SRmodeselect10(rp, list, nbytes);
425
}
426
 
427
static long
428
cmdmodesense6(ScsiReq *rp, int argc, char *argv[])
429
{
430
	uchar list[MaxDirData], *lp, page;
431
	long i, n, nbytes, status;
432
	char *p;
433
 
434
	nbytes = sizeof list;
435
	switch(argc){
436
 
437
	default:
438
		rp->status = Status_BADARG;
439
		return -1;
440
 
441
	case 2:
442
		if((nbytes = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
443
			rp->status = Status_BADARG;
444
			return -1;
445
		}
446
		/*FALLTHROUGH*/
447
 
448
	case 1:
449
		if((page = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
450
			rp->status = Status_BADARG;
451
			return -1;
452
		}
453
		break;
454
 
455
	case 0:
456
		page = Allmodepages;
457
		break;
458
	}
459
	if((status = SRmodesense6(rp, page, list, nbytes)) == -1)
460
		return -1;
461
	lp = list;
462
	nbytes = list[0];
463
	Bprint(&bout, " Header\n   ");
464
	for(i = 0; i < 4; i++){				/* header */
465
		Bprint(&bout, " %2.2uX", *lp);
466
		lp++;
467
	}
468
	Bputc(&bout, '\n');
469
 
470
	if(list[3]){					/* block descriptors */
471
		for(n = 0; n < list[3]/8; n++){
472
			Bprint(&bout, " Block %ld\n   ", n);
473
			for(i = 0; i < 8; i++)
474
				Bprint(&bout, " %2.2uX", lp[i]);
475
			Bprint(&bout, "    (density %2.2uX", lp[0]);
476
			Bprint(&bout, " blocks %d", (lp[1]<<16)|(lp[2]<<8)|lp[3]);
477
			Bprint(&bout, " length %d)", (lp[5]<<16)|(lp[6]<<8)|lp[7]);
478
			lp += 8;
479
			nbytes -= 8;
480
			Bputc(&bout, '\n');
481
		}
482
	}
483
 
484
	while(nbytes > 0){				/* pages */
485
		i = *(lp+1);
486
		nbytes -= i+2;
487
		Bprint(&bout, " Page %2.2uX %d\n   ", *lp & 0x3F, *(lp+1));
488
		lp += 2;
489
		for(n = 0; n < i; n++){
490
			if(n && ((n & 0x0F) == 0))
491
				Bprint(&bout, "\n   ");
492
			Bprint(&bout, " %2.2uX", *lp);
493
			lp++;
494
		}
495
		if(n && (n & 0x0F))
496
			Bputc(&bout, '\n');
497
	}
498
	return status;
499
}
500
 
501
static long
502
cmdmodesense10(ScsiReq *rp, int argc, char *argv[])
503
{
504
	uchar *list, *lp, page;
505
	long blen, i, n, nbytes, status;
506
	char *p;
507
 
508
	nbytes = MaxDirData;
509
	switch(argc){
510
	default:
511
		rp->status = Status_BADARG;
512
		return -1;
513
 
514
	case 2:
515
		if((nbytes = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
516
			rp->status = Status_BADARG;
517
			return -1;
518
		}
519
		/*FALLTHROUGH*/
520
	case 1:
521
		if((page = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
522
			rp->status = Status_BADARG;
523
			return -1;
524
		}
525
		break;
526
 
527
	case 0:
528
		page = Allmodepages;
529
		break;
530
	}
531
	list = malloc(nbytes);
532
	if(list == 0){
533
		rp->status = STnomem;
534
		return -1;
535
	}
536
	if((status = SRmodesense10(rp, page, list, nbytes)) == -1)
537
		return -1;
538
	lp = list;
539
	nbytes = ((list[0]<<8)|list[1]);
540
	Bprint(&bout, " Header\n   ");
541
	for(i = 0; i < 8; i++){				/* header */
542
		Bprint(&bout, " %2.2uX", *lp);
543
		lp++;
544
	}
545
	Bputc(&bout, '\n');
546
 
547
	blen = (list[6]<<8)|list[7];
548
	if(blen){					/* block descriptors */
549
		for(n = 0; n < blen/8; n++){
550
			Bprint(&bout, " Block %ld\n   ", n);
551
			for(i = 0; i < 8; i++)
552
				Bprint(&bout, " %2.2uX", lp[i]);
553
			Bprint(&bout, "    (density %2.2uX", lp[0]);
554
			Bprint(&bout, " blocks %d", (lp[1]<<16)|(lp[2]<<8)|lp[3]);
555
			Bprint(&bout, " length %d)", (lp[5]<<16)|(lp[6]<<8)|lp[7]);
556
			lp += 8;
557
			nbytes -= 8;
558
			Bputc(&bout, '\n');
559
		}
560
	}
561
 
562
	/*
563
	 * Special for ATA drives, page 0 is the drive info in 16-bit
564
	 * chunks, little-endian, 256 in total. No decoding for now.
565
	 */
566
	if(page == 0){
567
		for(n = 0; n < nbytes; n += 2){
568
			if(n && ((n & 0x1F) == 0))
569
				Bprint(&bout, "\n");
570
			Bprint(&bout, " %4.4uX", (*(lp+1)<<8)|*lp);
571
			lp += 2;
572
		}
573
		Bputc(&bout, '\n');
574
	}
575
	else
576
		while(nbytes > 0){				/* pages */
577
			i = *(lp+1);
578
			nbytes -= i+2;
579
			Bprint(&bout, " Page %2.2uX %d\n   ", *lp & 0x3F, lp[1]);
580
			lp += 2;
581
			for(n = 0; n < i; n++){
582
				if(n && ((n & 0x0F) == 0))
583
					Bprint(&bout, "\n   ");
584
				Bprint(&bout, " %2.2uX", *lp);
585
				lp++;
586
			}
587
			if(n && (n & 0x0F))
588
				Bputc(&bout, '\n');
589
		}
590
	free(list);
591
	return status;
592
}
593
 
594
static long
595
start(ScsiReq *rp, int argc, char *argv[], uchar code)
596
{
597
	char *p;
598
 
599
	if(argc && (code = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
600
		rp->status = Status_BADARG;
601
		return -1;
602
	}
603
	return SRstart(rp, code);
604
}
605
 
606
static long
607
cmdstart(ScsiReq *rp, int argc, char *argv[])
608
{
609
	return start(rp, argc, argv, 1);
610
}
611
 
612
static long
613
cmdstop(ScsiReq *rp, int argc, char *argv[])
614
{
615
	return start(rp, argc, argv, 0);
616
}
617
 
618
static long
619
cmdeject(ScsiReq *rp, int argc, char *argv[])
620
{
621
	return start(rp, argc, argv, 2);
622
}
623
 
624
static long
625
cmdingest(ScsiReq *rp, int argc, char *argv[])
626
{
627
	return start(rp, argc, argv, 3);
628
}
629
 
630
static long
631
cmdcapacity(ScsiReq *rp, int argc, char *argv[])
632
{
633
	uchar d[8];
634
	long n;
635
 
636
	USED(argc, argv);
637
	if((n = SRrcapacity(rp, d)) == -1)
638
		return -1;
639
	Bprint(&bout, " %ud %ud\n",
640
		d[0]<<24|d[1]<<16|d[2]<<8|d[3],
641
		d[4]<<24|d[5]<<16|d[6]<<8|d[7]);
642
	return n;
643
}
644
 
645
static long
646
cmdblank(ScsiReq *rp, int argc, char *argv[])
647
{
648
	uchar type, track;
649
	char *sp;
650
 
651
	type = track = 0;
652
	switch(argc){
653
 
654
	default:
655
		rp->status = Status_BADARG;
656
		return -1;
657
 
658
	case 2:
659
		if((type = strtoul(argv[1], &sp, 0)) == 0 && sp == argv[1]){
660
			rp->status = Status_BADARG;
661
			return -1;
662
		}
663
		if(type > 6){
664
			rp->status = Status_BADARG;
665
			return -1;
666
		}
667
		/*FALLTHROUGH*/
668
 
669
	case 1:
670
		if((track = strtoul(argv[0], &sp, 0)) == 0 && sp == argv[0]){
671
			rp->status = Status_BADARG;
672
			return -1;
673
		}
674
		/*FALLTHROUGH*/
675
 
676
	case 0:
677
		break;
678
	}
679
	return SRblank(rp, type, track);
680
}
681
 
682
static long
683
cmdsynccache(ScsiReq *rp, int argc, char *argv[])
684
{
685
	USED(argc, argv);
686
	return SRsynccache(rp);
687
}
688
 
689
static long
690
cmdrtoc(ScsiReq *rp, int argc, char *argv[])
691
{
692
	uchar d[100*8+4], format, track, *p;
693
	char *sp;
694
	long n, nbytes;
695
	int tdl;
696
 
697
	format = track = 0;
698
	switch(argc){
699
 
700
	default:
701
		rp->status = Status_BADARG;
702
		return -1;
703
 
704
	case 2:
705
		if((format = strtoul(argv[1], &sp, 0)) == 0 && sp == argv[1]){
706
			rp->status = Status_BADARG;
707
			return -1;
708
		}
709
		if(format > 4){
710
			rp->status = Status_BADARG;
711
			return -1;
712
		}
713
		/*FALLTHROUGH*/
714
 
715
	case 1:
716
		if((track = strtoul(argv[0], &sp, 0)) == 0 && sp == argv[0]){
717
			rp->status = Status_BADARG;
718
			return -1;
719
		}
720
		/*FALLTHROUGH*/
721
 
722
	case 0:
723
		break;
724
	}
725
	if((nbytes = SRTOC(rp, d, sizeof d, format, track)) == -1){
726
		if(rp->status == STok)
727
			Bprint(&bout, "\t(probably empty)\n");
728
		return -1;
729
	}
730
	tdl = (d[0]<<8)|d[1];
731
	switch(format){
732
 
733
	case 0:
734
		Bprint(&bout, "\ttoc/pma data length: 0x%uX\n", tdl);
735
		Bprint(&bout, "\tfirst track number: %d\n", d[2]);
736
		Bprint(&bout, "\tlast track number: %d\n", d[3]);
737
		for(p = &d[4], n = tdl-2; n; n -= 8, p += 8){
738
			Bprint(&bout, "\ttrack number: 0x%2.2uX\n", p[2]);
739
			Bprint(&bout, "\t\tcontrol: 0x%2.2uX\n", p[1] & 0x0F);
740
			Bprint(&bout, "\t\tblock address: 0x%uX\n",
741
				(p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7]);
742
		}
743
		break;
744
 
745
	case 1:
746
		Bprint(&bout, "\tsessions data length: 0x%uX\n", tdl);
747
		Bprint(&bout, "\tnumber of finished sessions: %d\n", d[2]);
748
		Bprint(&bout, "\tunfinished session number: %d\n", d[3]);
749
		for(p = &d[4], n = tdl-2; n; n -= 8, p += 8){
750
			Bprint(&bout, "\tsession number: 0x%2.2uX\n", p[0]);
751
			Bprint(&bout, "\t\tfirst track number in session: 0x%2.2uX\n",
752
				p[2]);
753
			Bprint(&bout, "\t\tlogical start address: 0x%uX\n",
754
				(p[5]<<16)|(p[6]<<8)|p[7]);
755
		}
756
		break;
757
 
758
	case 2:
759
		Bprint(&bout, "\tfull TOC data length: 0x%uX\n", tdl);
760
		Bprint(&bout, "\tnumber of finished sessions: %d\n", d[2]);
761
		Bprint(&bout, "\tunfinished session number: %d\n", d[3]);
762
		for(p = &d[4], n = tdl-2; n > 0; n -= 11, p += 11){
763
			Bprint(&bout, "\tsession number: 0x%2.2uX\n", p[0]);
764
			Bprint(&bout, "\t\tcontrol: 0x%2.2uX\n", p[1] & 0x0F);
765
			Bprint(&bout, "\t\tADR: 0x%2.2uX\n", (p[1]>>4) & 0x0F);
766
			Bprint(&bout, "\t\tTNO: 0x%2.2uX\n", p[2]);
767
			Bprint(&bout, "\t\tPOINT: 0x%2.2uX\n", p[3]);
768
			Bprint(&bout, "\t\tMin: 0x%2.2uX\n", p[4]);
769
			Bprint(&bout, "\t\tSec: 0x%2.2uX\n", p[5]);
770
			Bprint(&bout, "\t\tFrame: 0x%2.2uX\n", p[6]);
771
			Bprint(&bout, "\t\tZero: 0x%2.2uX\n", p[7]);
772
			Bprint(&bout, "\t\tPMIN: 0x%2.2uX\n", p[8]);
773
			Bprint(&bout, "\t\tPSEC: 0x%2.2uX\n", p[9]);
774
			Bprint(&bout, "\t\tPFRAME: 0x%2.2uX\n", p[10]);
775
		}
776
		break;
777
	case 3:
778
		Bprint(&bout, "\tPMA data length: 0x%uX\n", tdl);
779
		for(p = &d[4], n = tdl-2; n > 0; n -= 11, p += 11){
780
			Bprint(&bout, "\t\tcontrol: 0x%2.2uX\n", p[1] & 0x0F);
781
			Bprint(&bout, "\t\tADR: 0x%2.2uX\n", (p[1]>>4) & 0x0F);
782
			Bprint(&bout, "\t\tTNO: 0x%2.2uX\n", p[2]);
783
			Bprint(&bout, "\t\tPOINT: 0x%2.2uX\n", p[3]);
784
			Bprint(&bout, "\t\tMin: 0x%2.2uX\n", p[4]);
785
			Bprint(&bout, "\t\tSec: 0x%2.2uX\n", p[5]);
786
			Bprint(&bout, "\t\tFrame: 0x%2.2uX\n", p[6]);
787
			Bprint(&bout, "\t\tZero: 0x%2.2uX\n", p[7]);
788
			Bprint(&bout, "\t\tPMIN: 0x%2.2uX\n", p[8]);
789
			Bprint(&bout, "\t\tPSEC: 0x%2.2uX\n", p[9]);
790
			Bprint(&bout, "\t\tPFRAME: 0x%2.2uX\n", p[10]);
791
		}
792
		break;
793
 
794
	case 4:
795
		Bprint(&bout, "\tATIP data length: 0x%uX\n", tdl);
796
		break;
797
 
798
	}
799
	for(n = 0; n < nbytes; n++){
800
		if(n && ((n & 0x0F) == 0))
801
			Bprint(&bout, "\n");
802
		Bprint(&bout, " %2.2uX", d[n]);
803
	}
804
	if(n && (n & 0x0F))
805
		Bputc(&bout, '\n');
806
	return nbytes;
807
}
808
 
809
static long
810
cmdrdiscinfo(ScsiReq *rp, int argc, char*[])
811
{
812
	uchar d[MaxDirData];
813
	int dl;
814
	long n, nbytes;
815
 
816
	switch(argc){
817
 
818
	default:
819
		rp->status = Status_BADARG;
820
		return -1;
821
 
822
	case 0:
823
		break;
824
	}
825
	if((nbytes = SRrdiscinfo(rp, d, sizeof d)) == -1)
826
		return -1;
827
 
828
	dl = (d[0]<<8)|d[1];
829
	Bprint(&bout, "\tdata length: 0x%uX\n", dl);
830
	Bprint(&bout, "\tinfo[2] 0x%2.2uX\n", d[2]);
831
	switch(d[2] & 0x03){
832
 
833
	case 0:
834
		Bprint(&bout, "\t\tEmpty\n");
835
		break;
836
 
837
	case 1:
838
		Bprint(&bout, "\t\tIncomplete disc (Appendable)\n");
839
		break;
840
 
841
	case 2:
842
		Bprint(&bout, "\t\tComplete (CD-ROM or last session is closed and has no next session pointer)\n");
843
		break;
844
 
845
	case 3:
846
		Bprint(&bout, "\t\tReserved\n");
847
		break;
848
	}
849
	switch((d[2]>>2) & 0x03){
850
 
851
	case 0:
852
		Bprint(&bout, "\t\tEmpty Session\n");
853
		break;
854
 
855
	case 1:
856
		Bprint(&bout, "\t\tIncomplete Session\n");
857
		break;
858
 
859
	case 2:
860
		Bprint(&bout, "\t\tReserved\n");
861
		break;
862
 
863
	case 3:
864
		Bprint(&bout, "\t\tComplete Session (only possible when disc Status is Complete)\n");
865
		break;
866
	}
867
	if(d[2] & 0x10)
868
		Bprint(&bout, "\t\tErasable\n");
869
	Bprint(&bout, "\tNumber of First Track on Disc %ud\n", d[3]);
870
	Bprint(&bout, "\tNumber of Sessions %ud\n", d[4]);
871
	Bprint(&bout, "\tFirst Track Number in Last Session %ud\n", d[5]);
872
	Bprint(&bout, "\tLast Track Number in Last Session %ud\n", d[6]);
873
	Bprint(&bout, "\tinfo[7] 0x%2.2uX\n", d[7]);
874
	if(d[7] & 0x20)
875
		Bprint(&bout, "\t\tUnrestricted Use Disc\n");
876
	if(d[7] & 0x40)
877
		Bprint(&bout, "\t\tDisc Bar Code Valid\n");
878
	if(d[7] & 0x80)
879
		Bprint(&bout, "\t\tDisc ID Valid\n");
880
	Bprint(&bout, "\tinfo[8] 0x%2.2uX\n", d[8]);
881
	switch(d[8]){
882
 
883
	case 0x00:
884
		Bprint(&bout, "\t\tCD-DA or CD-ROM Disc\n");
885
		break;
886
 
887
	case 0x10:
888
		Bprint(&bout, "\t\tCD-I Disc\n");
889
		break;
890
 
891
	case 0x20:
892
		Bprint(&bout, "\t\tCD-ROM XA Disc\n");
893
		break;
894
 
895
	case 0xFF:
896
		Bprint(&bout, "\t\tUndefined\n");
897
		break;
898
 
899
	default:
900
		Bprint(&bout, "\t\tReserved\n");
901
		break;
902
	}
903
	Bprint(&bout, "\tLast Session lead-in Start Time M/S/F: 0x%2.2uX/0x%2.2uX/0x%2.2uX\n",
904
		d[17], d[18], d[19]);
905
	Bprint(&bout, "\tLast Possible Start Time for Start of lead-out M/S/F: 0x%2.2uX/0x%2.2uX/0x%2.2uX\n",
906
		d[21], d[22], d[23]);
907
 
908
	for(n = 0; n < nbytes; n++){
909
		if(n && ((n & 0x0F) == 0))
910
			Bprint(&bout, "\n");
911
		Bprint(&bout, " %2.2uX", d[n]);
912
	}
913
	if(n && (n & 0x0F))
914
		Bputc(&bout, '\n');
915
 
916
	return nbytes;
917
}
918
 
919
static long
920
cmdrtrackinfo(ScsiReq *rp, int argc, char *argv[])
921
{
922
	uchar d[MaxDirData], track;
923
	char *sp;
924
	long n, nbytes;
925
	int dl;
926
 
927
	track = 0;
928
	switch(argc){
929
 
930
	default:
931
		rp->status = Status_BADARG;
932
		return -1;
933
 
934
	case 1:
935
		if((track = strtoul(argv[0], &sp, 0)) == 0 && sp == argv[0]){
936
			rp->status = Status_BADARG;
937
			return -1;
938
		}
939
		/*FALLTHROUGH*/
940
 
941
	case 0:
942
		break;
943
	}
944
	if((nbytes = SRrtrackinfo(rp, d, sizeof d, track)) == -1)
945
		return -1;
946
 
947
	dl = (d[0]<<8)|d[1];
948
	Bprint(&bout, "\tdata length: 0x%uX\n", dl);
949
	Bprint(&bout, "\Track Number %d\n", d[2]);
950
	Bprint(&bout, "\Session Number %d\n", d[3]);
951
	Bprint(&bout, "\tinfo[4] 0x%2.2uX\n", d[5]);
952
	Bprint(&bout, "\t\tTrack Mode 0x%2.2uX: ", d[5] & 0x0F);
953
	switch(d[5] & 0x0F){
954
	case 0x00:
955
	case 0x02:
956
		Bprint(&bout, "2 audio channels without pre-emphasis\n");
957
		break;
958
	case 0x01:
959
	case 0x03:
960
		Bprint(&bout, "2 audio channels with pre-emphasis of 50/15µs\n");
961
		break;
962
	case 0x08:
963
	case 0x0A:
964
		Bprint(&bout, "audio channels without pre-emphasis (reserved in CD-R/RW)\n");
965
		break;
966
	case 0x09:
967
	case 0x0B:
968
		Bprint(&bout, "audio channels with pre-emphasis of 50/15µs (reserved in CD-R/RW)\n");
969
		break;
970
	case 0x04:
971
	case 0x06:
972
		Bprint(&bout, "Data track, recorded uninterrupted\n");
973
		break;
974
	case 0x05:
975
	case 0x07:
976
		Bprint(&bout, "Data track, recorded incremental\n");
977
		break;
978
	default:
979
		Bprint(&bout, "(mode unknown)\n");
980
		break;
981
	}
982
	if(d[5] & 0x10)
983
		Bprint(&bout, "\t\tCopy\n");
984
	if(d[5] & 0x20)
985
		Bprint(&bout, "\t\tDamage\n");
986
	Bprint(&bout, "\tinfo[6] 0x%2.2uX\n", d[6]);
987
	Bprint(&bout, "\t\tData Mode 0x%2.2uX: ", d[6] & 0x0F);
988
	switch(d[6] & 0x0F){
989
	case 0x01:
990
		Bprint(&bout, "Mode 1 (ISO/IEC 10149)\n");
991
		break;
992
	case 0x02:
993
		Bprint(&bout, "Mode 2 (ISO/IEC 10149 or CD-ROM XA)\n");
994
		break;
995
	case 0x0F:
996
		Bprint(&bout, "Data Block Type unknown (no track descriptor block)\n");
997
		break;
998
	default:
999
		Bprint(&bout, "(Reserved)\n");
1000
		break;
1001
	}
1002
	if(d[6] & 0x10)
1003
		Bprint(&bout, "\t\tFP\n");
1004
	if(d[6] & 0x20)
1005
		Bprint(&bout, "\t\tPacket\n");
1006
	if(d[6] & 0x40)
1007
		Bprint(&bout, "\t\tBlank\n");
1008
	if(d[6] & 0x80)
1009
		Bprint(&bout, "\t\tRT\n");
1010
	Bprint(&bout, "\tTrack Start Address 0x%8.8uX\n",
1011
		(d[8]<<24)|(d[9]<<16)|(d[10]<<8)|d[11]);
1012
	if(d[7] & 0x01)
1013
		Bprint(&bout, "\tNext Writeable Address 0x%8.8uX\n",
1014
			(d[12]<<24)|(d[13]<<16)|(d[14]<<8)|d[15]);
1015
	Bprint(&bout, "\tFree Blocks 0x%8.8uX\n",
1016
		(d[16]<<24)|(d[17]<<16)|(d[18]<<8)|d[19]);
1017
	if((d[6] & 0x30) == 0x30)
1018
		Bprint(&bout, "\tFixed Packet Size 0x%8.8uX\n",
1019
			(d[20]<<24)|(d[21]<<16)|(d[22]<<8)|d[23]);
1020
	Bprint(&bout, "\tTrack Size 0x%8.8uX\n",
1021
		(d[24]<<24)|(d[25]<<16)|(d[26]<<8)|d[27]);
1022
 
1023
	for(n = 0; n < nbytes; n++){
1024
		if(n && ((n & 0x0F) == 0))
1025
			Bprint(&bout, "\n");
1026
		Bprint(&bout, " %2.2uX", d[n]);
1027
	}
1028
	if(n && (n & 0x0F))
1029
		Bputc(&bout, '\n');
1030
 
1031
	return nbytes;
1032
}
1033
 
1034
static long
1035
cmdcdpause(ScsiReq *rp, int argc, char *argv[])
1036
{
1037
	USED(argc, argv);
1038
	return SRcdpause(rp, 0);
1039
}
1040
 
1041
static long
1042
cmdcdresume(ScsiReq *rp, int argc, char *argv[])
1043
{
1044
	USED(argc, argv);
1045
	return SRcdpause(rp, 1);
1046
}
1047
 
1048
static long
1049
cmdcdstop(ScsiReq *rp, int argc, char *argv[])
1050
{
1051
	USED(argc, argv);
1052
	return SRcdstop(rp);
1053
}
1054
 
1055
static long
1056
cmdcdplay(ScsiReq *rp, int argc, char *argv[])
1057
{
1058
	long length, start;
1059
	char *sp;
1060
	int raw;
1061
 
1062
	raw = 0;
1063
	start = 0;
1064
	if(argc && strcmp("-r", argv[0]) == 0){
1065
		raw = 1;
1066
		argc--, argv++;
1067
	}
1068
 
1069
	length = 0xFFFFFFFF;
1070
	switch(argc){
1071
 
1072
	default:
1073
		rp->status = Status_BADARG;
1074
		return -1;
1075
 
1076
	case 2:
1077
		if(!raw || ((length = strtol(argv[1], &sp, 0)) == 0 && sp == argv[1])){
1078
			rp->status = Status_BADARG;
1079
			return -1;
1080
		}
1081
		/*FALLTHROUGH*/
1082
 
1083
	case 1:
1084
		if((start = strtol(argv[0], &sp, 0)) == 0 && sp == argv[0]){
1085
			rp->status = Status_BADARG;
1086
			return -1;
1087
		}
1088
		/*FALLTHROUGH*/
1089
 
1090
	case 0:
1091
		break;
1092
	}
1093
 
1094
	return SRcdplay(rp, raw, start, length);
1095
}
1096
 
1097
static long
1098
cmdcdload(ScsiReq *rp, int argc, char *argv[])
1099
{
1100
	char *p;
1101
	ulong slot;
1102
 
1103
	slot = 0;
1104
	if(argc && (slot = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
1105
		rp->status = Status_BADARG;
1106
		return -1;
1107
	}
1108
	return SRcdload(rp, 1, slot);
1109
}
1110
 
1111
static long
1112
cmdcdunload(ScsiReq *rp, int argc, char *argv[])
1113
{
1114
	char *p;
1115
	ulong slot;
1116
 
1117
	slot = 0;
1118
	if(argc && (slot = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
1119
		rp->status = Status_BADARG;
1120
		return -1;
1121
	}
1122
	return SRcdload(rp, 0, slot);
1123
}
1124
 
1125
static long
1126
cmdcdstatus(ScsiReq *rp, int argc, char *argv[])
1127
{
1128
	uchar *list, *lp;
1129
	long nbytes, status;
1130
	int i, slots;
1131
 
1132
	USED(argc, argv);
1133
 
1134
	nbytes = 4096;
1135
	list = malloc(nbytes);
1136
	if(list == 0){
1137
		rp->status = STnomem;
1138
		return -1;
1139
	}
1140
	status = SRcdstatus(rp, list, nbytes);
1141
	if(status == -1){
1142
		free(list);
1143
		return -1;
1144
	}
1145
 
1146
	lp = list;
1147
	Bprint(&bout, " Header\n   ");
1148
	for(i = 0; i < 8; i++){				/* header */
1149
		Bprint(&bout, " %2.2uX", *lp);
1150
		lp++;
1151
	}
1152
	Bputc(&bout, '\n');
1153
 
1154
	slots = ((list[6]<<8)|list[7])/4;
1155
	Bprint(&bout, " Slots\n   ");
1156
	while(slots--){
1157
		Bprint(&bout, " %2.2uX %2.2uX %2.2uX %2.2uX\n   ",
1158
			*lp, *(lp+1), *(lp+2), *(lp+3));
1159
		lp += 4;
1160
	}
1161
 
1162
	free(list);
1163
	return status;
1164
}
1165
 
1166
static long
1167
cmdgetconf(ScsiReq *rp, int argc, char *argv[])
1168
{
1169
	uchar *list;
1170
	long nbytes, status;
1171
 
1172
	USED(argc, argv);
1173
 
1174
	nbytes = 4096;
1175
	list = malloc(nbytes);
1176
	if(list == 0){
1177
		rp->status = STnomem;
1178
		return -1;
1179
	}
1180
	status = SRgetconf(rp, list, nbytes);
1181
	if(status == -1){
1182
		free(list);
1183
		return -1;
1184
	}
1185
	/* to be done... */
1186
	free(list);
1187
	return status;
1188
}
1189
 
1190
static long
1191
cmdfwaddr(ScsiReq *rp, int argc, char *argv[])
1192
{
1193
	uchar d[MaxDirData], npa, track, mode;
1194
	long n;
1195
	char *p;
1196
 
1197
	npa = mode = track = 0;
1198
	switch(argc){
1199
 
1200
	default:
1201
		rp->status = Status_BADARG;
1202
		return -1;
1203
 
1204
	case 3:
1205
		if((npa = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
1206
			rp->status = Status_BADARG;
1207
			return -1;
1208
		}
1209
		/*FALLTHROUGH*/
1210
 
1211
	case 2:
1212
		if((mode = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
1213
			rp->status = Status_BADARG;
1214
			return -1;
1215
		}
1216
		/*FALLTHROUGH*/
1217
 
1218
	case 1:
1219
		if((track = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
1220
			rp->status = Status_BADARG;
1221
			return -1;
1222
		}
1223
		break;
1224
 
1225
	case 0:
1226
		break;
1227
	}
1228
	if((n = SRfwaddr(rp, track, mode, npa, d)) == -1)
1229
		return -1;
1230
	Bprint(&bout, "%ud %ud\n", d[0], (d[1]<<24)|(d[2]<<16)|(d[3]<<8)|d[4]);
1231
	return n;
1232
}
1233
 
1234
static long
1235
cmdtreserve(ScsiReq *rp, int argc, char *argv[])
1236
{
1237
	long nbytes;
1238
	char *p;
1239
 
1240
	if(argc != 1 || ((nbytes = strtoul(argv[0], &p, 0)) == 0 && p == argv[0])){
1241
		rp->status = Status_BADARG;
1242
		return -1;
1243
	}
1244
	return SRtreserve(rp, nbytes);
1245
}
1246
 
1247
static long
1248
cmdtrackinfo(ScsiReq *rp, int argc, char *argv[])
1249
{
1250
	uchar d[MaxDirData], track;
1251
	long n;
1252
	ulong ul;
1253
	char *p;
1254
 
1255
	track = 0;
1256
	if(argc && (track = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
1257
		rp->status = Status_BADARG;
1258
		return -1;
1259
	}
1260
	if((n = SRtinfo(rp, track, d)) == -1)
1261
		return -1;
1262
	Bprint(&bout, "buffer length: 0x%uX\n", d[0]);
1263
	Bprint(&bout, "number of tracks: 0x%uX\n", d[1]);
1264
	ul = (d[2]<<24)|(d[3]<<16)|(d[4]<<8)|d[5];
1265
	Bprint(&bout, "start address: 0x%luX\n", ul);
1266
	ul = (d[6]<<24)|(d[7]<<16)|(d[8]<<8)|d[9];
1267
	Bprint(&bout, "track length: 0x%luX\n", ul);
1268
	Bprint(&bout, "track mode: 0x%uX\n", d[0x0A] & 0x0F);
1269
	Bprint(&bout, "track status: 0x%uX\n", (d[0x0A]>>4) & 0x0F);
1270
	Bprint(&bout, "data mode: 0x%uX\n", d[0x0B] & 0x0F);
1271
	ul = (d[0x0C]<<24)|(d[0x0D]<<16)|(d[0x0E]<<8)|d[0x0F];
1272
	Bprint(&bout, "free blocks: 0x%luX\n", ul);
1273
	return n;
1274
}
1275
 
1276
static long
1277
cmdwtrack(ScsiReq *rp, int argc, char *argv[])
1278
{
1279
	uchar mode, track;
1280
	long n, nbytes, total, x;
1281
	int fd, pid;
1282
	char *p;
1283
 
1284
	mode = track = 0;
1285
	nbytes = 0;
1286
	switch(argc){
1287
 
1288
	default:
1289
		rp->status = Status_BADARG;
1290
		return -1;
1291
 
1292
	case 4:
1293
		if((mode = strtoul(argv[3], &p, 0)) == 0 && p == argv[3]){
1294
			rp->status = Status_BADARG;
1295
			return -1;
1296
		}
1297
		/*FALLTHROUGH*/
1298
 
1299
	case 3:
1300
		if((track = strtoul(argv[2], &p, 0)) == 0 && p == argv[2]){
1301
			rp->status = Status_BADARG;
1302
			return -1;
1303
		}
1304
		/*FALLTHROUGH*/
1305
 
1306
	case 2:
1307
		if((nbytes = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
1308
			rp->status = Status_BADARG;
1309
			return -1;
1310
		}
1311
		/*FALLTHROUGH*/
1312
 
1313
	case 1:
1314
		if((fd = mkfile(argv[0], OREAD, &pid)) == -1){
1315
			rp->status = Status_BADARG;
1316
			return -1;
1317
		}
1318
		break;
1319
	}
1320
	total = 0;
1321
	n = MIN(nbytes, maxiosize);
1322
	if((n = readn(fd, rwbuf, n)) == -1){
1323
		fprint(2, "file read failed %r\n");
1324
		close(fd);
1325
		return -1;
1326
	}
1327
	if((x = SRwtrack(rp, rwbuf, n, track, mode)) != n){
1328
		fprint(2, "wtrack: write incomplete: asked %ld, did %ld\n", n, x);
1329
		if(rp->status == STok)
1330
			rp->status = Status_SW;
1331
		close(fd);
1332
		return -1;
1333
	}
1334
	nbytes -= n;
1335
	total += n;
1336
	while(nbytes){
1337
		n = MIN(nbytes, maxiosize);
1338
		if((n = read(fd, rwbuf, n)) == -1){
1339
			break;
1340
		}
1341
		if((x = SRwrite(rp, rwbuf, n)) != n){
1342
			fprint(2, "write: write incomplete: asked %ld, did %ld\n", n, x);
1343
			if(rp->status == STok)
1344
				rp->status = Status_SW;
1345
			break;
1346
		}
1347
		nbytes -= n;
1348
		total += n;
1349
	}
1350
	close(fd);
1351
	if(pid >= 0 && waitfor(pid)){
1352
		rp->status = Status_SW;
1353
		return -1;
1354
	}
1355
	return total;
1356
}
1357
 
1358
static long
1359
cmdload(ScsiReq *rp, int argc, char *argv[])
1360
{
1361
	USED(argc, argv);
1362
	return SRmload(rp, 0);
1363
}
1364
 
1365
static long
1366
cmdunload(ScsiReq *rp, int argc, char *argv[])
1367
{
1368
	USED(argc, argv);
1369
	return SRmload(rp, 1);
1370
}
1371
 
1372
static long
1373
cmdfixation(ScsiReq *rp, int argc, char *argv[])
1374
{
1375
	uchar type;
1376
	char *p;
1377
 
1378
	type = 0;
1379
	if(argc && (type = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
1380
		rp->status = Status_BADARG;
1381
		return -1;
1382
	}
1383
	return SRfixation(rp, type);
1384
}
1385
 
1386
static long
1387
cmdeinit(ScsiReq *rp, int argc, char *argv[])
1388
{
1389
	USED(argc, argv);
1390
	return SReinitialise(rp);
1391
}
1392
 
1393
static long
1394
cmdmmove(ScsiReq *rp, int argc, char *argv[])
1395
{
1396
	int transport, source, destination, invert;
1397
	char *p;
1398
 
1399
	invert = 0;
1400
 
1401
	switch(argc){
1402
 
1403
	default:
1404
		rp->status = Status_BADARG;
1405
		return -1;
1406
 
1407
	case 4:
1408
		if((invert = strtoul(argv[3], &p, 0)) == 0 && p == argv[3]){
1409
			rp->status = Status_BADARG;
1410
			return -1;
1411
		}
1412
		/*FALLTHROUGH*/
1413
 
1414
	case 3:
1415
		if((transport = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
1416
			rp->status = Status_BADARG;
1417
			return -1;
1418
		}
1419
		if((source = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
1420
			rp->status = Status_BADARG;
1421
			return -1;
1422
		}
1423
		if((destination = strtoul(argv[2], &p, 0)) == 0 && p == argv[2]){
1424
			rp->status = Status_BADARG;
1425
			return -1;
1426
		}
1427
		break;
1428
	}
1429
 
1430
	return SRmmove(rp, transport, source, destination, invert);
1431
}
1432
 
1433
static long
1434
cmdestatus(ScsiReq *rp, int argc, char *argv[])
1435
{
1436
	uchar *list, *lp, type;
1437
	long d, i, n, nbytes, status;
1438
	char *p;
1439
 
1440
	type = 0;
1441
	nbytes = 4096;
1442
 
1443
	switch(argc){
1444
 
1445
	default:
1446
		rp->status = Status_BADARG;
1447
		return -1;
1448
 
1449
	case 2:
1450
		if((nbytes = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
1451
			rp->status = Status_BADARG;
1452
			return -1;
1453
		}
1454
		/*FALLTHROUGH*/
1455
 
1456
	case 1:
1457
		if((type = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
1458
			rp->status = Status_BADARG;
1459
			return -1;
1460
		}
1461
		break;
1462
 
1463
	case 0:
1464
		break;
1465
	}
1466
 
1467
	list = malloc(nbytes);
1468
	if(list == 0){
1469
		rp->status = STnomem;
1470
		return -1;
1471
	}
1472
	status = SRestatus(rp, type, list, nbytes);
1473
	if(status == -1){
1474
		free(list);
1475
		return -1;
1476
	}
1477
 
1478
	lp = list;
1479
	nbytes = ((lp[5]<<16)|(lp[6]<<8)|lp[7])-8;
1480
	Bprint(&bout, " Header\n   ");
1481
	for(i = 0; i < 8; i++){				/* header */
1482
		Bprint(&bout, " %2.2uX", *lp);
1483
		lp++;
1484
	}
1485
	Bputc(&bout, '\n');
1486
 
1487
	while(nbytes > 0){				/* pages */
1488
		i = ((lp[5]<<16)|(lp[6]<<8)|lp[7]);
1489
		nbytes -= i+8;
1490
		Bprint(&bout, " Type");
1491
		for(n = 0; n < 8; n++)			/* header */
1492
			Bprint(&bout, " %2.2uX", lp[n]);
1493
		Bprint(&bout, "\n   ");
1494
		d = (lp[2]<<8)|lp[3];
1495
		lp += 8;
1496
		for(n = 0; n < i; n++){
1497
			if(n && (n % d) == 0)
1498
				Bprint(&bout, "\n   ");
1499
			Bprint(&bout, " %2.2uX", *lp);
1500
			lp++;
1501
		}
1502
		if(n && (n % d))
1503
			Bputc(&bout, '\n');
1504
	}
1505
 
1506
	free(list);
1507
	return status;
1508
}
1509
 
1510
static long
1511
cmdhelp(ScsiReq *rp, int argc, char *argv[])
1512
{
1513
	ScsiCmd *cp;
1514
	char *p;
1515
 
1516
	USED(rp);
1517
	if(argc)
1518
		p = argv[0];
1519
	else
1520
		p = 0;
1521
	for(cp = scsicmds; cp->name; cp++){
1522
		if(p == 0 || strcmp(p, cp->name) == 0)
1523
			Bprint(&bout, "%s\n", cp->help);
1524
	}
1525
	return 0;
1526
}
1527
 
1528
static long
1529
cmdprobe(ScsiReq *rp, int argc, char *argv[])
1530
{
1531
	char buf[32];
1532
	ScsiReq scsireq;
1533
	char *ctlr, *unit;
1534
 
1535
	USED(argc, argv);
1536
	rp->status = STok;
1537
	scsireq.flags = 0;
1538
 
1539
	for(ctlr="CDEFGHIJ0123456789abcdef"; *ctlr; ctlr++) {
1540
		/*
1541
		 * I can guess how many units you have.
1542
		 * SATA controllers can have more than two drives each.
1543
		 */
1544
		if(*ctlr >= 'C' && *ctlr <= 'D')
1545
			unit = "01";
1546
		else if((*ctlr >= '0' && *ctlr <= '9')
1547
		     || (*ctlr >= 'a' && *ctlr <= 'f'))
1548
			unit = "0123456789abcdef";	/* allow wide scsi */
1549
		else
1550
			unit = "01234567";
1551
 
1552
		for(; *unit; unit++){
1553
			sprint(buf, "/dev/sd%c%c", *ctlr, *unit);
1554
			if(SRopenraw(&scsireq, buf) == -1)
1555
				continue;
1556
			SRreqsense(&scsireq);
1557
			switch(scsireq.status){
1558
			case STok:
1559
			case Status_SD:
1560
				Bprint(&bout, "%s: ", buf);
1561
				cmdinquiry(&scsireq, 0, 0);
1562
				break;
1563
			}
1564
			SRclose(&scsireq);
1565
		}
1566
	}
1567
	return 0;
1568
}
1569
 
1570
static long
1571
cmdclose(ScsiReq *rp, int argc, char *argv[])
1572
{
1573
	USED(argc, argv);
1574
	return SRclose(rp);
1575
}
1576
 
1577
static long
1578
cmdopen(ScsiReq *rp, int argc, char *argv[])
1579
{
1580
	int raw;
1581
	long status;
1582
 
1583
	raw = 0;
1584
	if(argc && strcmp("-r", argv[0]) == 0){
1585
		raw = 1;
1586
		argc--, argv++;
1587
	}
1588
	if(argc != 1){
1589
		rp->status = Status_BADARG;
1590
		return -1;
1591
	}
1592
	if(raw == 0){
1593
		if((status = SRopen(rp, argv[0])) != -1 && verbose)
1594
			Bprint(&bout, "%sblock size: %ld\n",
1595
				rp->flags&Fbfixed? "fixed ": "", rp->lbsize);
1596
	}
1597
	else {
1598
		status = SRopenraw(rp, argv[0]);
1599
		rp->lbsize = 512;
1600
	}
1601
	return status;
1602
}
1603
 
1604
static ScsiCmd scsicmds[] = {
1605
	{ "ready",	cmdready,	1,		/*[0x00]*/
1606
	  "ready",
1607
	},
1608
	{ "rewind",	cmdrewind,	1,		/*[0x01]*/
1609
	  "rewind",
1610
	},
1611
	{ "rezero",	cmdrewind,	1,		/*[0x01]*/
1612
	  "rezero",
1613
	},
1614
	{ "reqsense",	cmdreqsense,	1,		/*[0x03]*/
1615
	  "reqsense",
1616
	},
1617
	{ "format",	cmdformat,	0,		/*[0x04]*/
1618
	  "format",
1619
	},
1620
	{ "rblimits",	cmdrblimits,	1,		/*[0x05]*/
1621
	  "rblimits",
1622
	},
1623
	{ "read",	cmdread,	1,		/*[0x08]*/
1624
	  "read [|]file [nbytes]",
1625
	},
1626
	{ "write",	cmdwrite,	1,		/*[0x0A]*/
1627
	  "write [|]file [nbytes]",
1628
	},
1629
	{ "seek",	cmdseek,	1,		/*[0x0B]*/
1630
	  "seek offset [whence]",
1631
	},
1632
	{ "filemark",	cmdfilemark,	1,		/*[0x10]*/
1633
	  "filemark [howmany]",
1634
	},
1635
	{ "space",	cmdspace,	1,		/*[0x11]*/
1636
	  "space [-f] [-b] [[--] howmany]",
1637
	},
1638
	{ "inquiry",	cmdinquiry,	1,		/*[0x12]*/
1639
	  "inquiry",
1640
	},
1641
	{ "modeselect6",cmdmodeselect6,	1,		/*[0x15] */
1642
	  "modeselect6 bytes...",
1643
	},
1644
	{ "modeselect",	cmdmodeselect10, 1,		/*[0x55] */
1645
	  "modeselect bytes...",
1646
	},
1647
	{ "modesense6",	cmdmodesense6,	1,		/*[0x1A]*/
1648
	  "modesense6 [page [nbytes]]",
1649
	},
1650
	{ "modesense",	cmdmodesense10, 1,		/*[0x5A]*/
1651
	  "modesense [page [nbytes]]",
1652
	},
1653
	{ "start",	cmdstart,	1,		/*[0x1B]*/
1654
	  "start [code]",
1655
	},
1656
	{ "stop",	cmdstop,	1,		/*[0x1B]*/
1657
	  "stop",
1658
	},
1659
	{ "eject",	cmdeject,	1,		/*[0x1B]*/
1660
	  "eject",
1661
	},
1662
	{ "ingest",	cmdingest,	1,		/*[0x1B]*/
1663
	  "ingest",
1664
	},
1665
	{ "capacity",	cmdcapacity,	1,		/*[0x25]*/
1666
	  "capacity",
1667
	},
1668
 
1669
	{ "blank",	cmdblank,	1,		/*[0xA1]*/
1670
	  "blank [track/LBA [type]]",
1671
	},
1672
//	{ "synccache",	cmdsynccache,	1,		/*[0x35]*/
1673
//	  "synccache",
1674
//	},
1675
	{ "rtoc",	cmdrtoc,	1,		/*[0x43]*/
1676
	  "rtoc [track/session-number [format]]",
1677
	},
1678
	{ "rdiscinfo",	cmdrdiscinfo,	1,		/*[0x51]*/
1679
	  "rdiscinfo",
1680
	},
1681
	{ "rtrackinfo",	cmdrtrackinfo,	1,		/*[0x52]*/
1682
	  "rtrackinfo [track]",
1683
	},
1684
 
1685
	{ "cdpause",	cmdcdpause,	1,		/*[0x4B]*/
1686
	  "cdpause",
1687
	},
1688
	{ "cdresume",	cmdcdresume,	1,		/*[0x4B]*/
1689
	  "cdresume",
1690
	},
1691
	{ "cdstop",	cmdcdstop,	1,		/*[0x4E]*/
1692
	  "cdstop",
1693
	},
1694
	{ "cdplay",	cmdcdplay,	1,		/*[0xA5]*/
1695
	  "cdplay [track-number] or [-r [LBA [length]]]",
1696
	},
1697
	{ "cdload",	cmdcdload,	1,		/*[0xA6*/
1698
	  "cdload [slot]",
1699
	},
1700
	{ "cdunload",	cmdcdunload,	1,		/*[0xA6]*/
1701
	  "cdunload [slot]",
1702
	},
1703
	{ "cdstatus",	cmdcdstatus,	1,		/*[0xBD]*/
1704
	  "cdstatus",
1705
	},
1706
//	{ "getconf",	cmdgetconf,	1,		/*[0x46]*/
1707
//	  "getconf",
1708
//	},
1709
 
1710
//	{ "fwaddr",	cmdfwaddr,	1,		/*[0xE2]*/
1711
//	  "fwaddr [track [mode [npa]]]",
1712
//	},
1713
//	{ "treserve",	cmdtreserve,	1,		/*[0xE4]*/
1714
//	  "treserve nbytes",
1715
//	},
1716
//	{ "trackinfo",	cmdtrackinfo,	1,		/*[0xE5]*/
1717
//	  "trackinfo [track]",
1718
//	},
1719
//	{ "wtrack",	cmdwtrack,	1,		/*[0xE6]*/
1720
//	  "wtrack [|]file [nbytes [track [mode]]]",
1721
//	},
1722
//	{ "load",	cmdload,	1,		/*[0xE7]*/
1723
//	  "load",
1724
//	},
1725
//	{ "unload",	cmdunload,	1,		/*[0xE7]*/
1726
//	  "unload",
1727
//	},
1728
//	{ "fixation",	cmdfixation,	1,		/*[0xE9]*/
1729
//	  "fixation [toc-type]",
1730
//	},
1731
	{ "einit",	cmdeinit,	1,		/*[0x07]*/
1732
	  "einit",
1733
	},
1734
	{ "estatus",	cmdestatus,	1,		/*[0xB8]*/
1735
	  "estatus",
1736
	},
1737
	{ "mmove",	cmdmmove,	1,		/*[0xA5]*/
1738
	  "mmove transport source destination [invert]",
1739
	},
1740
 
1741
	{ "help",	cmdhelp,	0,
1742
	  "help",
1743
	},
1744
	{ "probe",	cmdprobe,	0,
1745
	  "probe",
1746
	},
1747
	{ "close",	cmdclose,	1,
1748
	  "close",
1749
	},
1750
	{ "open",	cmdopen,	0,
1751
	  "open [-r] sddev",
1752
	},
1753
	{ 0, 0 },
1754
};
1755
 
1756
#define	SEP(c)	(((c)==' ')||((c)=='\t')||((c)=='\n'))
1757
 
1758
static char *
1759
tokenise(char *s, char **start, char **end)
1760
{
1761
	char *to;
1762
	Rune r;
1763
	int n;
1764
 
1765
	while(*s && SEP(*s))				/* skip leading white space */
1766
		s++;
1767
	to = *start = s;
1768
	while(*s){
1769
		n = chartorune(&r, s);
1770
		if(SEP(r)){
1771
			if(to != *start)		/* we have data */
1772
				break;
1773
			s += n;				/* null string - keep looking */
1774
			while(*s && SEP(*s))
1775
				s++;
1776
			to = *start = s;
1777
		}
1778
		else if(r == '\''){
1779
			s += n;				/* skip leading quote */
1780
			while(*s){
1781
				n = chartorune(&r, s);
1782
				if(r == '\''){
1783
					if(s[1] != '\'')
1784
						break;
1785
					s++;		/* embedded quote */
1786
				}
1787
				while (n--)
1788
					*to++ = *s++;
1789
			}
1790
			if(!*s)				/* no trailing quote */
1791
				break;
1792
			s++;				/* skip trailing quote */
1793
		}
1794
		else  {
1795
			while(n--)
1796
				*to++ = *s++;
1797
		}
1798
	}
1799
	*end = to;
1800
	return s;
1801
}
1802
 
1803
static int
1804
parse(char *s, char *fields[], int nfields)
1805
{
1806
	int c, argc;
1807
	char *start, *end;
1808
 
1809
	argc = 0;
1810
	c = *s;
1811
	while(c){
1812
		s = tokenise(s, &start, &end);
1813
		c = *s++;
1814
		if(*start == 0)
1815
			break;
1816
		if(argc >= nfields-1)
1817
			return -1;
1818
		*end = 0;
1819
		fields[argc++] = start;
1820
	}
1821
	fields[argc] = 0;
1822
	return argc;
1823
}
1824
 
1825
static void
1826
usage(void)
1827
{
1828
	fprint(2, "usage: %s [-6eq] [-m maxiosize] [[-r] /dev/sdXX]\n", argv0);
1829
	exits("usage");
1830
}
1831
 
1832
static struct {
1833
	int	status;
1834
	char*	description;
1835
} description[] = {
1836
	STnomem,	"buffer allocation failed",
1837
	STtimeout,	"bus timeout",
1838
	STharderr,	"controller error of some kind",
1839
	STok,		"good",
1840
	STcheck,	"check condition",
1841
	STcondmet,	"condition met/good",
1842
	STbusy,		"busy ",
1843
	STintok,	"intermediate/good",
1844
	STintcondmet,	"intermediate/condition met/good",
1845
	STresconf,	"reservation conflict",
1846
	STterminated,	"command terminated",
1847
	STqfull,	"queue full",
1848
 
1849
	Status_SD,	"sense-data available",
1850
	Status_SW,	"internal software error",
1851
	Status_BADARG,	"bad argument to request",
1852
 
1853
	0, 0,
1854
};
1855
 
1856
void
1857
main(int argc, char *argv[])
1858
{
1859
	ScsiReq target;
1860
	char *ap, *av[256];
1861
	int ac, i, raw = 0;
1862
	ScsiCmd *cp;
1863
	long status;
1864
 
1865
	ARGBEGIN {
1866
	case 'e':
1867
		exabyte = 1;
1868
		/* fallthrough */
1869
	case '6':
1870
		force6bytecmds = 1;
1871
		break;
1872
	case 'm':
1873
		ap = ARGF();
1874
		if(ap == nil)
1875
			usage();
1876
		maxiosize = atol(ap);
1877
		if(maxiosize < 512 || maxiosize > MaxIOsize)
1878
			sysfatal("max-xfer < 512 or > %d", MaxIOsize);
1879
		break;
1880
	case 'r':			/* must be last option and not bundled */
1881
		raw++;
1882
		break;
1883
	case 'q':
1884
		verbose = 0;
1885
		break;
1886
	default:
1887
		usage();
1888
	} ARGEND
1889
 
1890
	if(Binit(&bin, 0, OREAD) == Beof || Binit(&bout, 1, OWRITE) == Beof){
1891
		fprint(2, "%s: can't init bio: %r\n", argv0);
1892
		exits("Binit");
1893
	}
1894
 
1895
	memset(&target, 0, sizeof target);
1896
	if (raw) {			/* hack for -r */
1897
		++argc;
1898
		--argv;
1899
	}
1900
	if(argc && cmdopen(&target, argc, argv) == -1) {
1901
		fprint(2, "open failed\n");
1902
		usage();
1903
	}
1904
	Bflush(&bout);
1905
 
1906
	while(ap = Brdline(&bin, '\n')){
1907
		ap[Blinelen(&bin)-1] = 0;
1908
		switch(ac = parse(ap, av, nelem(av))){
1909
 
1910
		default:
1911
			for(cp = scsicmds; cp->name; cp++){
1912
				if(strcmp(cp->name, av[0]) == 0)
1913
					break;
1914
			}
1915
			if(cp->name == 0){
1916
				Bprint(&bout, "eh?\n");
1917
				break;
1918
			}
1919
			if((target.flags & Fopen) == 0 && cp->open){
1920
				Bprint(&bout, "no current target\n");
1921
				break;
1922
			}
1923
			if((status = (*cp->f)(&target, ac-1, &av[1])) != -1){
1924
				if(verbose)
1925
					Bprint(&bout, "ok %ld\n", status);
1926
				break;
1927
			}
1928
			for(i = 0; description[i].description; i++){
1929
				if(target.status != description[i].status)
1930
					continue;
1931
				if(target.status == Status_SD)
1932
					makesense(&target);
1933
				else
1934
					Bprint(&bout, "%s\n", description[i].description);
1935
				break;
1936
			}
1937
			break;
1938
 
1939
		case -1:
1940
			Bprint(&bout, "eh?\n");
1941
			break;
1942
 
1943
		case 0:
1944
			break;
1945
		}
1946
		Bflush(&bout);
1947
	}
1948
	exits(0);
1949
}
1950
 
1951
/* USB mass storage fake */
1952
long
1953
umsrequest(Umsc *umsc, ScsiPtr *cmd, ScsiPtr *data, int *status)
1954
{
1955
	USED(umsc, data, cmd);
1956
	*status = STharderr;
1957
	return -1;
1958
}