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