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 } 1959