7 enum { /* fundamental constants/defaults */
9 * default & maximum `maximum i/o size'; overridden by -m.
10 * limits kernel memory consumption.
11 * 240K is exabyte maximum block size.
16 #define MIN(a, b) ((a) < (b) ? (a): (b))
18 static char rwbuf[MaxIOsize];
19 static int verbose = 1;
22 long maxiosize = MaxIOsize;
24 int force6bytecmds = 0;
28 long (*f)(ScsiReq *, int, char *[]);
33 static ScsiCmd scsicmd[];
36 vlmin(vlong a, vlong b)
45 cmdready(ScsiReq *rp, int argc, char *argv[])
52 cmdrewind(ScsiReq *rp, int argc, char *argv[])
59 cmdreqsense(ScsiReq *rp, int argc, char *argv[])
64 if((nbytes = SRreqsense(rp)) != -1)
70 cmdformat(ScsiReq *rp, int argc, char *argv[])
77 cmdrblimits(ScsiReq *rp, int argc, char *argv[])
83 if((n = SRrblimits(rp, l)) == -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]);
91 mkfile(char *file, int omode, int *pid)
98 return create(file, OWRITE, 0666);
99 else if(omode == OREAD)
100 return open(file, OREAD);
105 if(*file == 0 || pipe(fd) == -1)
107 if((*pid = fork()) == -1){
125 execl("/bin/rc", "rc", "-c", file, nil);
138 while((w = wait()) != nil){
143 msg = (w->msg[0] != '\0');
151 cmdread(ScsiReq *rp, int argc, char *argv[])
153 long n, iosize, prevsize = 0;
163 rp->status = Status_BADARG;
167 nbytes = strtoll(argv[1], &p, 0);
168 if(nbytes == 0 && p == argv[1]){
169 rp->status = Status_BADARG;
175 if((fd = mkfile(argv[0], OWRITE, &pid)) == -1){
176 rp->status = Status_BADARG;
181 print("device native block size=%lud\n", rp->lbsize);
184 n = vlmin(nbytes, iosize);
185 if((n = SRread(rp, rwbuf, n)) == -1){
193 print("tape block size=%ld\n", n);
196 if(write(fd, rwbuf, n) != n){
199 if(rp->status == STok)
200 rp->status = Status_SW;
207 if(pid >= 0 && waitfor(pid)){
208 rp->status = Status_SW;
215 cmdwrite(ScsiReq *rp, int argc, char *argv[])
217 long n, prevsize = 0;
226 rp->status = Status_BADARG;
230 nbytes = strtoll(argv[1], &p, 0);
231 if(nbytes == 0 && p == argv[1]){
232 rp->status = Status_BADARG;
238 if((fd = mkfile(argv[0], OREAD, &pid)) == -1){
239 rp->status = Status_BADARG;
246 n = vlmin(nbytes, maxiosize);
247 if((n = read(fd, rwbuf, n)) == -1){
255 print("tape block size=%ld\n", n);
258 if(SRwrite(rp, rwbuf, n) != n){
261 if(rp->status == STok)
262 rp->status = Status_SW;
269 if(pid >= 0 && waitfor(pid)){
270 rp->status = Status_SW;
277 cmdseek(ScsiReq *rp, int argc, char *argv[])
287 rp->status = Status_BADARG;
291 if((type = strtol(argv[1], &p, 0)) == 0 && p == argv[1]){
292 rp->status = Status_BADARG;
298 if((offset = strtol(argv[0], &p, 0)) == 0 && p == argv[0]){
299 rp->status = Status_BADARG;
304 return SRseek(rp, offset, type);
308 cmdfilemark(ScsiReq *rp, int argc, char *argv[])
314 if(argc && (howmany = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
315 rp->status = Status_BADARG;
318 return SRfilemark(rp, howmany);
322 cmdspace(ScsiReq *rp, int argc, char *argv[])
330 while(argc && (*argv)[0] == '-'){
331 while(option = *++argv[0]){
346 rp->status = Status_BADARG;
355 if(argc && ((howmany = strtol(argv[0], &p, 0)) == 0 && p == argv[0])){
356 rp->status = Status_BADARG;
359 return SRspace(rp, code, howmany);
363 cmdinquiry(ScsiReq *rp, int argc, char *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]);
375 n = MIN(n, sizeof(rp->inquiry)-8);
376 while(n && (*p == ' ' || *p == '\t' || *p == '\n')){
380 Bprint(&bout, "\t%.*s\n", n, (char*)p);
386 cmdmodeselect6(ScsiReq *rp, int argc, char *argv[])
388 uchar list[MaxDirData];
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;
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);
407 cmdmodeselect10(ScsiReq *rp, int argc, char *argv[])
409 uchar list[MaxDirData];
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;
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);
428 cmdmodesense6(ScsiReq *rp, int argc, char *argv[])
430 uchar list[MaxDirData], *lp, page;
431 long i, n, nbytes, status;
434 nbytes = sizeof list;
438 rp->status = Status_BADARG;
442 if((nbytes = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
443 rp->status = Status_BADARG;
449 if((page = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
450 rp->status = Status_BADARG;
459 if((status = SRmodesense6(rp, page, list, nbytes)) == -1)
463 Bprint(&bout, " Header\n ");
464 for(i = 0; i < 4; i++){ /* header */
465 Bprint(&bout, " %2.2uX", *lp);
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]);
484 while(nbytes > 0){ /* pages */
487 Bprint(&bout, " Page %2.2uX %d\n ", *lp & 0x3F, *(lp+1));
489 for(n = 0; n < i; n++){
490 if(n && ((n & 0x0F) == 0))
491 Bprint(&bout, "\n ");
492 Bprint(&bout, " %2.2uX", *lp);
502 cmdmodesense10(ScsiReq *rp, int argc, char *argv[])
504 uchar *list, *lp, page;
505 long blen, i, n, nbytes, status;
511 rp->status = Status_BADARG;
515 if((nbytes = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
516 rp->status = Status_BADARG;
521 if((page = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
522 rp->status = Status_BADARG;
531 list = malloc(nbytes);
533 rp->status = STnomem;
536 if((status = SRmodesense10(rp, page, list, nbytes)) == -1)
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);
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]);
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.
567 for(n = 0; n < nbytes; n += 2){
568 if(n && ((n & 0x1F) == 0))
570 Bprint(&bout, " %4.4uX", (*(lp+1)<<8)|*lp);
576 while(nbytes > 0){ /* pages */
579 Bprint(&bout, " Page %2.2uX %d\n ", *lp & 0x3F, lp[1]);
581 for(n = 0; n < i; n++){
582 if(n && ((n & 0x0F) == 0))
583 Bprint(&bout, "\n ");
584 Bprint(&bout, " %2.2uX", *lp);
595 start(ScsiReq *rp, int argc, char *argv[], uchar code)
599 if(argc && (code = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
600 rp->status = Status_BADARG;
603 return SRstart(rp, code);
607 cmdstart(ScsiReq *rp, int argc, char *argv[])
609 return start(rp, argc, argv, 1);
613 cmdstop(ScsiReq *rp, int argc, char *argv[])
615 return start(rp, argc, argv, 0);
619 cmdeject(ScsiReq *rp, int argc, char *argv[])
621 return start(rp, argc, argv, 2);
625 cmdingest(ScsiReq *rp, int argc, char *argv[])
627 return start(rp, argc, argv, 3);
631 cmdcapacity(ScsiReq *rp, int argc, char *argv[])
637 if((n = SRrcapacity(rp, d)) == -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]);
646 cmdblank(ScsiReq *rp, int argc, char *argv[])
655 rp->status = Status_BADARG;
659 if((type = strtoul(argv[1], &sp, 0)) == 0 && sp == argv[1]){
660 rp->status = Status_BADARG;
664 rp->status = Status_BADARG;
670 if((track = strtoul(argv[0], &sp, 0)) == 0 && sp == argv[0]){
671 rp->status = Status_BADARG;
679 return SRblank(rp, type, track);
683 cmdsynccache(ScsiReq *rp, int argc, char *argv[])
686 return SRsynccache(rp);
690 cmdrtoc(ScsiReq *rp, int argc, char *argv[])
692 uchar d[100*8+4], format, track, *p;
701 rp->status = Status_BADARG;
705 if((format = strtoul(argv[1], &sp, 0)) == 0 && sp == argv[1]){
706 rp->status = Status_BADARG;
710 rp->status = Status_BADARG;
716 if((track = strtoul(argv[0], &sp, 0)) == 0 && sp == argv[0]){
717 rp->status = Status_BADARG;
725 if((nbytes = SRTOC(rp, d, sizeof d, format, track)) == -1){
726 if(rp->status == STok)
727 Bprint(&bout, "\t(probably empty)\n");
730 tdl = (d[0]<<8)|d[1];
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]);
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",
753 Bprint(&bout, "\t\tlogical start address: 0x%uX\n",
754 (p[5]<<16)|(p[6]<<8)|p[7]);
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]);
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]);
795 Bprint(&bout, "\tATIP data length: 0x%uX\n", tdl);
799 for(n = 0; n < nbytes; n++){
800 if(n && ((n & 0x0F) == 0))
802 Bprint(&bout, " %2.2uX", d[n]);
810 cmdrdiscinfo(ScsiReq *rp, int argc, char*[])
819 rp->status = Status_BADARG;
825 if((nbytes = SRrdiscinfo(rp, d, sizeof d)) == -1)
829 Bprint(&bout, "\tdata length: 0x%uX\n", dl);
830 Bprint(&bout, "\tinfo[2] 0x%2.2uX\n", d[2]);
834 Bprint(&bout, "\t\tEmpty\n");
838 Bprint(&bout, "\t\tIncomplete disc (Appendable)\n");
842 Bprint(&bout, "\t\tComplete (CD-ROM or last session is closed and has no next session pointer)\n");
846 Bprint(&bout, "\t\tReserved\n");
849 switch((d[2]>>2) & 0x03){
852 Bprint(&bout, "\t\tEmpty Session\n");
856 Bprint(&bout, "\t\tIncomplete Session\n");
860 Bprint(&bout, "\t\tReserved\n");
864 Bprint(&bout, "\t\tComplete Session (only possible when disc Status is Complete)\n");
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]);
875 Bprint(&bout, "\t\tUnrestricted Use Disc\n");
877 Bprint(&bout, "\t\tDisc Bar Code Valid\n");
879 Bprint(&bout, "\t\tDisc ID Valid\n");
880 Bprint(&bout, "\tinfo[8] 0x%2.2uX\n", d[8]);
884 Bprint(&bout, "\t\tCD-DA or CD-ROM Disc\n");
888 Bprint(&bout, "\t\tCD-I Disc\n");
892 Bprint(&bout, "\t\tCD-ROM XA Disc\n");
896 Bprint(&bout, "\t\tUndefined\n");
900 Bprint(&bout, "\t\tReserved\n");
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]);
908 for(n = 0; n < nbytes; n++){
909 if(n && ((n & 0x0F) == 0))
911 Bprint(&bout, " %2.2uX", d[n]);
920 cmdrtrackinfo(ScsiReq *rp, int argc, char *argv[])
922 uchar d[MaxDirData], track;
931 rp->status = Status_BADARG;
935 if((track = strtoul(argv[0], &sp, 0)) == 0 && sp == argv[0]){
936 rp->status = Status_BADARG;
944 if((nbytes = SRrtrackinfo(rp, d, sizeof d, track)) == -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);
956 Bprint(&bout, "2 audio channels without pre-emphasis\n");
960 Bprint(&bout, "2 audio channels with pre-emphasis of 50/15µs\n");
964 Bprint(&bout, "audio channels without pre-emphasis (reserved in CD-R/RW)\n");
968 Bprint(&bout, "audio channels with pre-emphasis of 50/15µs (reserved in CD-R/RW)\n");
972 Bprint(&bout, "Data track, recorded uninterrupted\n");
976 Bprint(&bout, "Data track, recorded incremental\n");
979 Bprint(&bout, "(mode unknown)\n");
983 Bprint(&bout, "\t\tCopy\n");
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);
990 Bprint(&bout, "Mode 1 (ISO/IEC 10149)\n");
993 Bprint(&bout, "Mode 2 (ISO/IEC 10149 or CD-ROM XA)\n");
996 Bprint(&bout, "Data Block Type unknown (no track descriptor block)\n");
999 Bprint(&bout, "(Reserved)\n");
1003 Bprint(&bout, "\t\tFP\n");
1005 Bprint(&bout, "\t\tPacket\n");
1007 Bprint(&bout, "\t\tBlank\n");
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]);
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]);
1023 for(n = 0; n < nbytes; n++){
1024 if(n && ((n & 0x0F) == 0))
1025 Bprint(&bout, "\n");
1026 Bprint(&bout, " %2.2uX", d[n]);
1035 cmdcdpause(ScsiReq *rp, int argc, char *argv[])
1038 return SRcdpause(rp, 0);
1042 cmdcdresume(ScsiReq *rp, int argc, char *argv[])
1045 return SRcdpause(rp, 1);
1049 cmdcdstop(ScsiReq *rp, int argc, char *argv[])
1052 return SRcdstop(rp);
1056 cmdcdplay(ScsiReq *rp, int argc, char *argv[])
1064 if(argc && strcmp("-r", argv[0]) == 0){
1069 length = 0xFFFFFFFF;
1073 rp->status = Status_BADARG;
1077 if(!raw || ((length = strtol(argv[1], &sp, 0)) == 0 && sp == argv[1])){
1078 rp->status = Status_BADARG;
1084 if((start = strtol(argv[0], &sp, 0)) == 0 && sp == argv[0]){
1085 rp->status = Status_BADARG;
1094 return SRcdplay(rp, raw, start, length);
1098 cmdcdload(ScsiReq *rp, int argc, char *argv[])
1104 if(argc && (slot = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
1105 rp->status = Status_BADARG;
1108 return SRcdload(rp, 1, slot);
1112 cmdcdunload(ScsiReq *rp, int argc, char *argv[])
1118 if(argc && (slot = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
1119 rp->status = Status_BADARG;
1122 return SRcdload(rp, 0, slot);
1126 cmdcdstatus(ScsiReq *rp, int argc, char *argv[])
1129 long nbytes, status;
1135 list = malloc(nbytes);
1137 rp->status = STnomem;
1140 status = SRcdstatus(rp, list, nbytes);
1147 Bprint(&bout, " Header\n ");
1148 for(i = 0; i < 8; i++){ /* header */
1149 Bprint(&bout, " %2.2uX", *lp);
1154 slots = ((list[6]<<8)|list[7])/4;
1155 Bprint(&bout, " Slots\n ");
1157 Bprint(&bout, " %2.2uX %2.2uX %2.2uX %2.2uX\n ",
1158 *lp, *(lp+1), *(lp+2), *(lp+3));
1167 cmdgetconf(ScsiReq *rp, int argc, char *argv[])
1170 long nbytes, status;
1175 list = malloc(nbytes);
1177 rp->status = STnomem;
1180 status = SRgetconf(rp, list, nbytes);
1191 cmdfwaddr(ScsiReq *rp, int argc, char *argv[])
1193 uchar d[MaxDirData], npa, track, mode;
1197 npa = mode = track = 0;
1201 rp->status = Status_BADARG;
1205 if((npa = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
1206 rp->status = Status_BADARG;
1212 if((mode = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
1213 rp->status = Status_BADARG;
1219 if((track = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
1220 rp->status = Status_BADARG;
1228 if((n = SRfwaddr(rp, track, mode, npa, d)) == -1)
1230 Bprint(&bout, "%ud %ud\n", d[0], (d[1]<<24)|(d[2]<<16)|(d[3]<<8)|d[4]);
1235 cmdtreserve(ScsiReq *rp, int argc, char *argv[])
1240 if(argc != 1 || ((nbytes = strtoul(argv[0], &p, 0)) == 0 && p == argv[0])){
1241 rp->status = Status_BADARG;
1244 return SRtreserve(rp, nbytes);
1248 cmdtrackinfo(ScsiReq *rp, int argc, char *argv[])
1250 uchar d[MaxDirData], track;
1256 if(argc && (track = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
1257 rp->status = Status_BADARG;
1260 if((n = SRtinfo(rp, track, d)) == -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);
1277 cmdwtrack(ScsiReq *rp, int argc, char *argv[])
1280 long n, nbytes, total, x;
1289 rp->status = Status_BADARG;
1293 if((mode = strtoul(argv[3], &p, 0)) == 0 && p == argv[3]){
1294 rp->status = Status_BADARG;
1300 if((track = strtoul(argv[2], &p, 0)) == 0 && p == argv[2]){
1301 rp->status = Status_BADARG;
1307 if((nbytes = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
1308 rp->status = Status_BADARG;
1314 if((fd = mkfile(argv[0], OREAD, &pid)) == -1){
1315 rp->status = Status_BADARG;
1321 n = MIN(nbytes, maxiosize);
1322 if((n = readn(fd, rwbuf, n)) == -1){
1323 fprint(2, "file read failed %r\n");
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;
1337 n = MIN(nbytes, maxiosize);
1338 if((n = read(fd, rwbuf, n)) == -1){
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;
1351 if(pid >= 0 && waitfor(pid)){
1352 rp->status = Status_SW;
1359 cmdload(ScsiReq *rp, int argc, char *argv[])
1362 return SRmload(rp, 0);
1366 cmdunload(ScsiReq *rp, int argc, char *argv[])
1369 return SRmload(rp, 1);
1373 cmdfixation(ScsiReq *rp, int argc, char *argv[])
1379 if(argc && (type = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
1380 rp->status = Status_BADARG;
1383 return SRfixation(rp, type);
1387 cmdeinit(ScsiReq *rp, int argc, char *argv[])
1390 return SReinitialise(rp);
1394 cmdmmove(ScsiReq *rp, int argc, char *argv[])
1396 int transport, source, destination, invert;
1404 rp->status = Status_BADARG;
1408 if((invert = strtoul(argv[3], &p, 0)) == 0 && p == argv[3]){
1409 rp->status = Status_BADARG;
1415 if((transport = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
1416 rp->status = Status_BADARG;
1419 if((source = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
1420 rp->status = Status_BADARG;
1423 if((destination = strtoul(argv[2], &p, 0)) == 0 && p == argv[2]){
1424 rp->status = Status_BADARG;
1430 return SRmmove(rp, transport, source, destination, invert);
1434 cmdestatus(ScsiReq *rp, int argc, char *argv[])
1436 uchar *list, *lp, type;
1437 long d, i, n, nbytes, status;
1446 rp->status = Status_BADARG;
1450 if((nbytes = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){
1451 rp->status = Status_BADARG;
1457 if((type = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){
1458 rp->status = Status_BADARG;
1467 list = malloc(nbytes);
1469 rp->status = STnomem;
1472 status = SRestatus(rp, type, list, nbytes);
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);
1487 while(nbytes > 0){ /* pages */
1488 i = ((lp[5]<<16)|(lp[6]<<8)|lp[7]);
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];
1496 for(n = 0; n < i; n++){
1497 if(n && (n % d) == 0)
1498 Bprint(&bout, "\n ");
1499 Bprint(&bout, " %2.2uX", *lp);
1511 cmdhelp(ScsiReq *rp, int argc, char *argv[])
1521 for(cp = scsicmd; cp->name; cp++){
1522 if(p == 0 || strcmp(p, cp->name) == 0)
1523 Bprint(&bout, "%s\n", cp->help);
1529 cmdprobe(ScsiReq *rp, int argc, char *argv[])
1539 for(ctlr="CDEFGHIJ0123456789abcdef"; *ctlr; ctlr++) {
1541 * I can guess how many units you have.
1542 * SATA controllers can have more than two drives each.
1544 if(*ctlr >= 'C' && *ctlr <= 'D')
1546 else if((*ctlr >= '0' && *ctlr <= '9')
1547 || (*ctlr >= 'a' && *ctlr <= 'f'))
1548 unit = "0123456789abcdef"; /* allow wide scsi */
1552 for(; *unit; unit++){
1553 sprint(buf, "/dev/sd%c%c", *ctlr, *unit);
1554 if(SRopenraw(&scsireq, buf) == -1)
1556 SRreqsense(&scsireq);
1557 switch(scsireq.status){
1560 Bprint(&bout, "%s: ", buf);
1561 cmdinquiry(&scsireq, 0, 0);
1571 cmdclose(ScsiReq *rp, int argc, char *argv[])
1578 cmdopen(ScsiReq *rp, int argc, char *argv[])
1584 if(argc && strcmp("-r", argv[0]) == 0){
1589 rp->status = Status_BADARG;
1593 if((status = SRopen(rp, argv[0])) != -1 && verbose)
1594 Bprint(&bout, "%sblock size: %ld\n",
1595 rp->flags&Fbfixed? "fixed ": "", rp->lbsize);
1598 status = SRopenraw(rp, argv[0]);
1604 static ScsiCmd scsicmd[] = {
1605 { "ready", cmdready, 1, /*[0x00]*/
1608 { "rewind", cmdrewind, 1, /*[0x01]*/
1611 { "rezero", cmdrewind, 1, /*[0x01]*/
1614 { "reqsense", cmdreqsense, 1, /*[0x03]*/
1617 { "format", cmdformat, 0, /*[0x04]*/
1620 { "rblimits", cmdrblimits, 1, /*[0x05]*/
1623 { "read", cmdread, 1, /*[0x08]*/
1624 "read [|]file [nbytes]",
1626 { "write", cmdwrite, 1, /*[0x0A]*/
1627 "write [|]file [nbytes]",
1629 { "seek", cmdseek, 1, /*[0x0B]*/
1630 "seek offset [whence]",
1632 { "filemark", cmdfilemark, 1, /*[0x10]*/
1633 "filemark [howmany]",
1635 { "space", cmdspace, 1, /*[0x11]*/
1636 "space [-f] [-b] [[--] howmany]",
1638 { "inquiry", cmdinquiry, 1, /*[0x12]*/
1641 { "modeselect6",cmdmodeselect6, 1, /*[0x15] */
1642 "modeselect6 bytes...",
1644 { "modeselect", cmdmodeselect10, 1, /*[0x55] */
1645 "modeselect bytes...",
1647 { "modesense6", cmdmodesense6, 1, /*[0x1A]*/
1648 "modesense6 [page [nbytes]]",
1650 { "modesense", cmdmodesense10, 1, /*[0x5A]*/
1651 "modesense [page [nbytes]]",
1653 { "start", cmdstart, 1, /*[0x1B]*/
1656 { "stop", cmdstop, 1, /*[0x1B]*/
1659 { "eject", cmdeject, 1, /*[0x1B]*/
1662 { "ingest", cmdingest, 1, /*[0x1B]*/
1665 { "capacity", cmdcapacity, 1, /*[0x25]*/
1669 { "blank", cmdblank, 1, /*[0xA1]*/
1670 "blank [track/LBA [type]]",
1672 { "synccache", cmdsynccache, 1, /*[0x35]*/
1675 { "rtoc", cmdrtoc, 1, /*[0x43]*/
1676 "rtoc [track/session-number [format]]",
1678 { "rdiscinfo", cmdrdiscinfo, 1, /*[0x51]*/
1681 { "rtrackinfo", cmdrtrackinfo, 1, /*[0x52]*/
1682 "rtrackinfo [track]",
1685 { "cdpause", cmdcdpause, 1, /*[0x4B]*/
1688 { "cdresume", cmdcdresume, 1, /*[0x4B]*/
1691 { "cdstop", cmdcdstop, 1, /*[0x4E]*/
1694 { "cdplay", cmdcdplay, 1, /*[0xA5]*/
1695 "cdplay [track-number] or [-r [LBA [length]]]",
1697 { "cdload", cmdcdload, 1, /*[0xA6*/
1700 { "cdunload", cmdcdunload, 1, /*[0xA6]*/
1703 { "cdstatus", cmdcdstatus, 1, /*[0xBD]*/
1706 // { "getconf", cmdgetconf, 1, /*[0x46]*/
1710 // { "fwaddr", cmdfwaddr, 1, /*[0xE2]*/
1711 // "fwaddr [track [mode [npa]]]",
1713 // { "treserve", cmdtreserve, 1, /*[0xE4]*/
1714 // "treserve nbytes",
1716 // { "trackinfo", cmdtrackinfo, 1, /*[0xE5]*/
1717 // "trackinfo [track]",
1719 // { "wtrack", cmdwtrack, 1, /*[0xE6]*/
1720 // "wtrack [|]file [nbytes [track [mode]]]",
1722 // { "load", cmdload, 1, /*[0xE7]*/
1725 // { "unload", cmdunload, 1, /*[0xE7]*/
1728 // { "fixation", cmdfixation, 1, /*[0xE9]*/
1729 // "fixation [toc-type]",
1731 { "einit", cmdeinit, 1, /*[0x07]*/
1734 { "estatus", cmdestatus, 1, /*[0xB8]*/
1737 { "mmove", cmdmmove, 1, /*[0xA5]*/
1738 "mmove transport source destination [invert]",
1741 { "help", cmdhelp, 0,
1744 { "probe", cmdprobe, 0,
1747 { "close", cmdclose, 1,
1750 { "open", cmdopen, 0,
1756 #define SEP(c) (((c)==' ')||((c)=='\t')||((c)=='\n'))
1759 tokenise(char *s, char **start, char **end)
1765 while(*s && SEP(*s)) /* skip leading white space */
1769 n = chartorune(&r, s);
1771 if(to != *start) /* we have data */
1773 s += n; /* null string - keep looking */
1774 while(*s && SEP(*s))
1779 s += n; /* skip leading quote */
1781 n = chartorune(&r, s);
1785 s++; /* embedded quote */
1790 if(!*s) /* no trailing quote */
1792 s++; /* skip trailing quote */
1804 parse(char *s, char *fields[], int nfields)
1812 s = tokenise(s, &start, &end);
1816 if(argc >= nfields-1)
1819 fields[argc++] = start;
1828 fprint(2, "usage: %s [-6eq] [-m maxiosize] [[-r] /dev/sdXX]\n", argv0);
1836 STnomem, "buffer allocation failed",
1837 STtimeout, "bus timeout",
1838 STharderr, "controller error of some kind",
1840 STcheck, "check condition",
1841 STcondmet, "condition met/good",
1843 STintok, "intermediate/good",
1844 STintcondmet, "intermediate/condition met/good",
1845 STresconf, "reservation conflict",
1846 STterminated, "command terminated",
1847 STqfull, "queue full",
1849 Status_SD, "sense-data available",
1850 Status_SW, "internal software error",
1851 Status_BADARG, "bad argument to request",
1857 main(int argc, char *argv[])
1876 maxiosize = atol(ap);
1877 if(maxiosize < 512 || maxiosize > MaxIOsize)
1878 sysfatal("max-xfer < 512 or > %d", MaxIOsize);
1880 case 'r': /* must be last option and not bundled */
1890 if(Binit(&bin, 0, OREAD) == Beof || Binit(&bout, 1, OWRITE) == Beof){
1891 fprint(2, "%s: can't init bio: %r\n", argv0);
1895 memset(&target, 0, sizeof target);
1896 if (raw) { /* hack for -r */
1900 if(argc && cmdopen(&target, argc, argv) == -1) {
1901 fprint(2, "open failed\n");
1906 while(ap = Brdline(&bin, '\n')){
1907 ap[Blinelen(&bin)-1] = 0;
1908 switch(ac = parse(ap, av, nelem(av))){
1911 for(cp = scsicmd; cp->name; cp++){
1912 if(strcmp(cp->name, av[0]) == 0)
1916 Bprint(&bout, "eh?\n");
1919 if((target.flags & Fopen) == 0 && cp->open){
1920 Bprint(&bout, "no current target\n");
1923 if((status = (*cp->f)(&target, ac-1, &av[1])) != -1){
1925 Bprint(&bout, "ok %ld\n", status);
1928 for(i = 0; description[i].description; i++){
1929 if(target.status != description[i].status)
1931 if(target.status == Status_SD)
1934 Bprint(&bout, "%s\n", description[i].description);
1940 Bprint(&bout, "eh?\n");
1951 /* USB mass storage fake */
1953 umsrequest(Umsc *umsc, ScsiPtr *cmd, ScsiPtr *data, int *status)
1955 USED(umsc, data, cmd);
1956 *status = STharderr;