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 int bus; 10 Biobuf bin, bout; 11 static char rwbuf[MaxIOsize]; 12 static int verbose = 1; 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 return -1; 88 } 89 if(*pid == 0){ 90 switch(omode){ 91 92 case OREAD: 93 dup(fd[0], 1); 94 break; 95 96 case OWRITE: 97 dup(fd[0], 0); 98 break; 99 } 100 close(fd[0]); 101 close(fd[1]); 102 execl("/bin/rc", "rc", "-c", file, 0); 103 exits("exec"); 104 } 105 close(fd[0]); 106 return fd[1]; 107 } 108 109 int 110 waitfor(int pid) 111 { 112 int rpid; 113 Waitmsg w; 114 115 while((rpid = wait(&w)) != pid && rpid != -1) 116 ; 117 return w.msg[0]; 118 } 119 120 static long 121 cmdread(ScsiReq *rp, int argc, char *argv[]) 122 { 123 long n, nbytes, total, iosize; 124 int fd, pid; 125 char *p; 126 127 iosize = MaxIOsize; 128 nbytes = 0x7FFFFFFF & ~iosize; 129 switch(argc){ 130 131 default: 132 rp->status = Status_BADARG; 133 return -1; 134 135 case 2: 136 if((nbytes = strtol(argv[1], &p, 0)) == 0 && p == argv[1]){ 137 rp->status = Status_BADARG; 138 return -1; 139 } 140 /*FALLTHROUGH*/ 141 142 case 1: 143 if((fd = mkfile(argv[0], OWRITE, &pid)) == -1){ 144 rp->status = Status_BADARG; 145 return -1; 146 } 147 break; 148 } 149 print("bsize=%d\n", rp->lbsize); 150 total = 0; 151 while(nbytes){ 152 n = MIN(nbytes, iosize); 153 if((n = SRread(rp, rwbuf, n)) == -1){ 154 if(total == 0) 155 total = -1; 156 break; 157 } 158 if(write(fd, rwbuf, n) != n){ 159 if(total == 0) 160 total = -1; 161 if(rp->status == Status_OK) 162 rp->status = Status_SW; 163 break; 164 } 165 nbytes -= n; 166 total += n; 167 } 168 close(fd); 169 if(pid >= 0 && waitfor(pid)){ 170 rp->status = Status_SW; 171 return -1; 172 } 173 return total; 174 } 175 176 static long 177 cmdwrite(ScsiReq *rp, int argc, char *argv[]) 178 { 179 long n, nbytes, total; 180 int fd, pid; 181 char *p; 182 183 nbytes = 0x7FFFFFFF & ~MaxIOsize; 184 switch(argc){ 185 186 default: 187 rp->status = Status_BADARG; 188 return -1; 189 190 case 2: 191 if((nbytes = strtol(argv[1], &p, 0)) == 0 && p == argv[1]){ 192 rp->status = Status_BADARG; 193 return -1; 194 } 195 /*FALLTHROUGH*/ 196 197 case 1: 198 if((fd = mkfile(argv[0], OREAD, &pid)) == -1){ 199 rp->status = Status_BADARG; 200 return -1; 201 } 202 break; 203 } 204 total = 0; 205 while(nbytes){ 206 n = MIN(nbytes, MaxIOsize); 207 if((n = read(fd, rwbuf, n)) == -1){ 208 if(total == 0) 209 total = -1; 210 break; 211 } 212 if(SRwrite(rp, rwbuf, n) != n){ 213 if(total == 0) 214 total = -1; 215 if(rp->status == Status_OK) 216 rp->status = Status_SW; 217 break; 218 } 219 nbytes -= n; 220 total += n; 221 } 222 close(fd); 223 if(pid >= 0 && waitfor(pid)){ 224 rp->status = Status_SW; 225 return -1; 226 } 227 return total; 228 } 229 230 static long 231 cmdseek(ScsiReq *rp, int argc, char *argv[]) 232 { 233 char *p; 234 long offset; 235 int type; 236 237 type = 0; 238 switch(argc){ 239 240 default: 241 rp->status = Status_BADARG; 242 return -1; 243 244 case 2: 245 if((type = strtol(argv[1], &p, 0)) == 0 && p == argv[1]){ 246 rp->status = Status_BADARG; 247 return -1; 248 } 249 /*FALLTHROUGH*/ 250 251 case 1: 252 if((offset = strtol(argv[0], &p, 0)) == 0 && p == argv[0]){ 253 rp->status = Status_BADARG; 254 return -1; 255 } 256 break; 257 } 258 return SRseek(rp, offset, type); 259 } 260 261 static long 262 cmdfilemark(ScsiReq *rp, int argc, char *argv[]) 263 { 264 char *p; 265 ulong howmany; 266 267 howmany = 1; 268 if(argc && (howmany = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){ 269 rp->status = Status_BADARG; 270 return -1; 271 } 272 return SRfilemark(rp, howmany); 273 } 274 275 static long 276 cmdspace(ScsiReq *rp, int argc, char *argv[]) 277 { 278 uchar code; 279 long howmany; 280 char option, *p; 281 282 code = 0x00; 283 howmany = 1; 284 while(argc && (*argv)[0] == '-'){ 285 while(option = *++argv[0]){ 286 switch(option){ 287 288 case '-': 289 break; 290 291 case 'b': 292 code = 0x00; 293 break; 294 295 case 'f': 296 code = 0x01; 297 break; 298 299 default: 300 rp->status = Status_BADARG; 301 return -1; 302 } 303 break; 304 } 305 argc--; argv++; 306 if(option == '-') 307 break; 308 } 309 if(argc || ((howmany = strtol(argv[0], &p, 0)) == 0 && p == argv[0])){ 310 USED(howmany); 311 rp->status = Status_BADARG; 312 return -1; 313 } 314 return SRspace(rp, code, howmany); 315 } 316 317 static long 318 cmdinquiry(ScsiReq *rp, int argc, char *argv[]) 319 { 320 long status; 321 int i, n; 322 uchar *p; 323 324 USED(argc, argv); 325 if((status = SRinquiry(rp)) != -1){ 326 n = rp->inquiry[4]+4; 327 for(i = 0; i < MIN(8, n); i++) 328 Bprint(&bout, " %2.2ux", rp->inquiry[i]); 329 p = &rp->inquiry[8]; 330 n = MIN(n, sizeof(rp->inquiry)-8); 331 while(n && (*p == ' ' || *p == '\t' || *p == '\n')){ 332 n--; 333 p++; 334 } 335 Bprint(&bout, "\t%.*s\n", n, p); 336 } 337 return status; 338 } 339 340 static long 341 cmdmodeselect(ScsiReq *rp, int argc, char *argv[]) 342 { 343 uchar list[MaxDirData]; 344 long nbytes, ul; 345 char *p; 346 347 memset(list, 0, sizeof(list)); 348 for(nbytes = 0; argc; argc--, argv++, nbytes++){ 349 if((ul = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){ 350 rp->status = Status_BADARG; 351 return -1; 352 } 353 list[nbytes] = ul; 354 } 355 return SRmodeselect(rp, list, nbytes); 356 } 357 358 static long 359 cmdmodesense(ScsiReq *rp, int argc, char *argv[]) 360 { 361 uchar list[MaxDirData], *lp, page; 362 long i, nbytes, status; 363 char *p; 364 365 nbytes = sizeof(list); 366 switch(argc){ 367 368 default: 369 rp->status = Status_BADARG; 370 return -1; 371 372 case 2: 373 if((nbytes = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){ 374 rp->status = Status_BADARG; 375 return -1; 376 } 377 /*FALLTHROUGH*/ 378 379 case 1: 380 if((page = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){ 381 rp->status = Status_BADARG; 382 return -1; 383 } 384 break; 385 386 case 0: 387 page = 0x3F; 388 break; 389 } 390 if((status = SRmodesense(rp, page, list, nbytes)) == -1) 391 return -1; 392 lp = list; 393 nbytes = list[0]-1; 394 for(i = 0; i < 4; i++){ /* header */ 395 Bprint(&bout, " %2.2ux", *lp); 396 lp++; 397 } 398 nbytes -= 4; 399 Bputc(&bout, '\n'); 400 for(i = 0; i < 8; i++){ /* block descriptor */ 401 Bprint(&bout, " %2.2ux", *lp); 402 lp++; 403 } 404 nbytes -= 8; 405 Bputc(&bout, '\n'); 406 while(nbytes > 0){ 407 i = *(lp+1); 408 nbytes -= i+2; 409 Bprint(&bout, " %2.2ux %2.2ux", *lp, *(lp+1)); 410 lp += 2; 411 while(i--){ 412 Bprint(&bout, " %2.2ux", *lp); 413 lp++; 414 } 415 Bputc(&bout, '\n'); 416 } 417 return status; 418 } 419 420 static long 421 start(ScsiReq *rp, int argc, char *argv[], uchar code) 422 { 423 char *p; 424 425 if(argc && (code = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){ 426 rp->status = Status_BADARG; 427 return -1; 428 } 429 return SRstart(rp, code); 430 } 431 432 static long 433 cmdstart(ScsiReq *rp, int argc, char *argv[]) 434 { 435 return start(rp, argc, argv, 1); 436 } 437 438 static long 439 cmdstop(ScsiReq *rp, int argc, char *argv[]) 440 { 441 return start(rp, argc, argv, 0); 442 } 443 444 static long 445 cmdeject(ScsiReq *rp, int argc, char *argv[]) 446 { 447 return start(rp, argc, argv, 2); 448 } 449 450 static long 451 cmdcapacity(ScsiReq *rp, int argc, char *argv[]) 452 { 453 uchar d[6]; 454 long n; 455 456 USED(argc, argv); 457 if((n = SRrcapacity(rp, d)) == -1) 458 return -1; 459 Bprint(&bout, " %ld %ld\n", d[0]<<24|d[1]<<16|d[2]<<8|d[3], 460 d[4]<<24|d[5]<<16|d[6]<<8|d[7]); 461 return n; 462 } 463 464 static long 465 cmdflushcache(ScsiReq *rp, int argc, char *argv[]) 466 { 467 USED(argc, argv); 468 return SRflushcache(rp); 469 } 470 471 static long 472 cmdrdiscinfo(ScsiReq *rp, int argc, char *argv[]) 473 { 474 uchar d[MaxDirData], ses, track, *p; 475 char *sp; 476 long n, nbytes; 477 478 ses = track = 0; 479 switch(argc){ 480 481 default: 482 rp->status = Status_BADARG; 483 return -1; 484 485 case 2: 486 if((ses = strtoul(argv[1], &sp, 0)) == 0 && sp == argv[1]){ 487 rp->status = Status_BADARG; 488 return -1; 489 } 490 /*FALLTHROUGH*/ 491 492 case 1: 493 if((track = strtoul(argv[0], &sp, 0)) == 0 && sp == argv[0]){ 494 rp->status = Status_BADARG; 495 return -1; 496 } 497 /*FALLTHROUGH*/ 498 499 case 0: 500 break; 501 } 502 if((nbytes = SRrdiscinfo(rp, d, ses, track)) == -1) 503 return -1; 504 if(ses == 0){ 505 Bprint(&bout, "\ttoc/pma data length: 0x%ux\n", (d[0]<<8)|d[1]); 506 Bprint(&bout, "\tfirst track number: %d\n", d[2]); 507 Bprint(&bout, "\tlast track number: %d\n", d[3]); 508 for(p = &d[4], n = nbytes-4; n; n -= 8, p += 8){ 509 Bprint(&bout, "\ttrack number: 0x%2.2ux\n", p[2]); 510 Bprint(&bout, "\t\tcontrol: 0x%2.2ux\n", p[1] & 0x0F); 511 Bprint(&bout, "\t\tblock address: 0x%lux\n", 512 (p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7]); 513 } 514 } 515 else{ 516 Bprint(&bout, "\tsessions data length: 0x%ux\n", (d[0]<<8)|d[1]); 517 Bprint(&bout, "\tnumber of finished sessions: %d\n", d[2]); 518 Bprint(&bout, "\tunfinished session number: %d\n", d[3]); 519 for(p = &d[4], n = nbytes-4; n; n -= 8, p += 8){ 520 Bprint(&bout, "\tsession number: 0x%2.2ux\n", p[0]); 521 Bprint(&bout, "\t\tfirst track number in session: 0x%2.2ux\n", 522 p[2]); 523 Bprint(&bout, "\t\tlogical start address: 0x%lux\n", 524 (p[5]<<16)|(p[6]<<8)|p[7]); 525 } 526 } 527 for(n = 0; n < nbytes; n++) 528 Bprint(&bout, " %2.2ux", d[n]); 529 Bprint(&bout, "\n"); 530 return nbytes; 531 } 532 533 static long 534 cmdfwaddr(ScsiReq *rp, int argc, char *argv[]) 535 { 536 uchar d[MaxDirData], npa, track, mode; 537 long n; 538 char *p; 539 540 npa = mode = track = 0; 541 switch(argc){ 542 543 default: 544 rp->status = Status_BADARG; 545 return -1; 546 547 case 3: 548 if((npa = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){ 549 rp->status = Status_BADARG; 550 return -1; 551 } 552 /*FALLTHROUGH*/ 553 554 case 2: 555 if((mode = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){ 556 rp->status = Status_BADARG; 557 return -1; 558 } 559 /*FALLTHROUGH*/ 560 561 case 1: 562 if((track = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){ 563 rp->status = Status_BADARG; 564 return -1; 565 } 566 break; 567 568 case 0: 569 break; 570 } 571 if((n = SRfwaddr(rp, track, mode, npa, d)) == -1) 572 return -1; 573 Bprint(&bout, "%ud %ld\n", d[0], (d[1]<<24)|(d[2]<<16)|(d[3]<<8)|d[4]); 574 return n; 575 } 576 577 static long 578 cmdtreserve(ScsiReq *rp, int argc, char *argv[]) 579 { 580 long nbytes; 581 char *p; 582 583 if(argc != 1 || ((nbytes = strtoul(argv[0], &p, 0)) == 0 && p == argv[0])){ 584 rp->status = Status_BADARG; 585 return -1; 586 } 587 return SRtreserve(rp, nbytes); 588 } 589 590 static long 591 cmdtrackinfo(ScsiReq *rp, int argc, char *argv[]) 592 { 593 uchar d[MaxDirData], track; 594 long n; 595 ulong ul; 596 char *p; 597 598 track = 0; 599 if(argc && (track = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){ 600 rp->status = Status_BADARG; 601 return -1; 602 } 603 if((n = SRtinfo(rp, track, d)) == -1) 604 return -1; 605 Bprint(&bout, "buffer length: 0x%ux\n", d[0]); 606 Bprint(&bout, "number of tracks: 0x%ux\n", d[1]); 607 ul = (d[2]<<24)|(d[3]<<16)|(d[4]<<8)|d[5]; 608 Bprint(&bout, "start address: 0x%lux\n", ul); 609 ul = (d[6]<<24)|(d[7]<<16)|(d[8]<<8)|d[9]; 610 Bprint(&bout, "track length: 0x%lux\n", ul); 611 Bprint(&bout, "track mode: 0x%ux\n", d[0x0A] & 0x0F); 612 Bprint(&bout, "track status: 0x%ux\n", (d[0x0A]>>4) & 0x0F); 613 Bprint(&bout, "data mode: 0x%ux\n", d[0x0B] & 0x0F); 614 ul = (d[0x0C]<<24)|(d[0x0D]<<16)|(d[0x0E]<<8)|d[0x0F]; 615 Bprint(&bout, "free blocks: 0x%lux\n", ul); 616 return n; 617 } 618 619 static long 620 cmdwtrack(ScsiReq *rp, int argc, char *argv[]) 621 { 622 uchar mode, track; 623 long n, nbytes, total, x; 624 int fd, pid; 625 char *p; 626 627 mode = track = 0; 628 nbytes = 0; 629 switch(argc){ 630 631 default: 632 rp->status = Status_BADARG; 633 return -1; 634 635 case 4: 636 if((mode = strtoul(argv[3], &p, 0)) == 0 && p == argv[3]){ 637 rp->status = Status_BADARG; 638 return -1; 639 } 640 /*FALLTHROUGH*/ 641 642 case 3: 643 if((track = strtoul(argv[2], &p, 0)) == 0 && p == argv[2]){ 644 rp->status = Status_BADARG; 645 return -1; 646 } 647 /*FALLTHROUGH*/ 648 649 case 2: 650 if((nbytes = strtoul(argv[1], &p, 0)) == 0 && p == argv[1]){ 651 rp->status = Status_BADARG; 652 return -1; 653 } 654 /*FALLTHROUGH*/ 655 656 case 1: 657 if((fd = mkfile(argv[0], OREAD, &pid)) == -1){ 658 rp->status = Status_BADARG; 659 return -1; 660 } 661 break; 662 } 663 total = 0; 664 n = MIN(nbytes, MaxIOsize); 665 if((n = read(fd, rwbuf, n)) == -1){ 666 fprint(2, "file read failed %r\n"); 667 close(fd); 668 return -1; 669 } 670 if((x = SRwtrack(rp, rwbuf, n, track, mode)) != n){ 671 fprint(2, "wtrack: write incomplete: asked %d, did %d\n", n, x); 672 if(rp->status == Status_OK) 673 rp->status = Status_SW; 674 close(fd); 675 return -1; 676 } 677 nbytes -= n; 678 total += n; 679 while(nbytes){ 680 n = MIN(nbytes, MaxIOsize); 681 if((n = read(fd, rwbuf, n)) == -1){ 682 break; 683 } 684 if((x = SRwrite(rp, rwbuf, n)) != n){ 685 fprint(2, "write: write incomplete: asked %d, did %d\n", n, x); 686 if(rp->status == Status_OK) 687 rp->status = Status_SW; 688 break; 689 } 690 nbytes -= n; 691 total += n; 692 } 693 close(fd); 694 if(pid >= 0 && waitfor(pid)){ 695 rp->status = Status_SW; 696 return -1; 697 } 698 return total; 699 } 700 701 static long 702 cmdload(ScsiReq *rp, int argc, char *argv[]) 703 { 704 USED(argc, argv); 705 return SRmload(rp, 0); 706 } 707 708 static long 709 cmdunload(ScsiReq *rp, int argc, char *argv[]) 710 { 711 USED(argc, argv); 712 return SRmload(rp, 1); 713 } 714 715 static long 716 cmdfixation(ScsiReq *rp, int argc, char *argv[]) 717 { 718 uchar type; 719 char *p; 720 721 type = 0; 722 if(argc && (type = strtoul(argv[0], &p, 0)) == 0 && p == argv[0]){ 723 rp->status = Status_BADARG; 724 return -1; 725 } 726 return SRfixation(rp, type); 727 } 728 729 static long 730 cmdhelp(ScsiReq *rp, int argc, char *argv[]) 731 { 732 ScsiCmd *cp; 733 char *p; 734 735 USED(rp); 736 if(argc) 737 p = argv[0]; 738 else 739 p = 0; 740 for(cp = scsicmd; cp->name; cp++){ 741 if(p == 0 || strcmp(p, cp->name) == 0) 742 Bprint(&bout, "%s\n", cp->help); 743 } 744 return 0; 745 } 746 747 static long 748 cmdprobe(ScsiReq *rp, int argc, char *argv[]) 749 { 750 ScsiReq scsireq; 751 uchar id; 752 753 USED(argc, argv); 754 rp->status = Status_OK; 755 scsireq.flags = 0; 756 for(id = 0; id < CtlrID; id++){ 757 if(SRopenraw(&scsireq, id) == -1) 758 return -1; 759 SRreqsense(&scsireq); 760 switch(scsireq.status){ 761 762 default: 763 break; 764 765 case Status_OK: 766 case Status_SD: 767 Bprint(&bout, "%d: ", id); 768 cmdinquiry(&scsireq, 0, 0); 769 break; 770 } 771 SRclose(&scsireq); 772 } 773 return 0; 774 } 775 776 static long 777 cmdclose(ScsiReq *rp, int argc, char *argv[]) 778 { 779 USED(argc, argv); 780 return SRclose(rp); 781 } 782 783 static long 784 cmdopen(ScsiReq *rp, int argc, char *argv[]) 785 { 786 char *p; 787 int id, raw; 788 long status; 789 790 raw = 0; 791 if(argc && strcmp("-r", argv[0]) == 0){ 792 raw = 1; 793 argc--, argv++; 794 } 795 if(argc != 1 || ((id = strtoul(argv[0], &p, 0)) == 0 && p == argv[0])){ 796 rp->status = Status_BADARG; 797 return -1; 798 } 799 if(raw == 0){ 800 if((status = SRopen(rp, id)) != -1 && verbose) 801 Bprint(&bout, "block size: %ld\n", rp->lbsize); 802 } 803 else { 804 status = SRopenraw(rp, id); 805 rp->lbsize = 512; 806 } 807 return status; 808 } 809 810 static ScsiCmd scsicmd[] = { 811 { "ready", cmdready, 1, /*[0x00]*/ 812 "ready", 813 }, 814 { "rewind", cmdrewind, 1, /*[0x01]*/ 815 "rewind", 816 }, 817 { "rezero", cmdrewind, 1, /*[0x01]*/ 818 "rezero", 819 }, 820 { "reqsense", cmdreqsense, 1, /*[0x03]*/ 821 "reqsense", 822 }, 823 { "format", cmdformat, 0, /*[0x04]*/ 824 "format", 825 }, 826 { "rblimits", cmdrblimits, 1, /*[0x05]*/ 827 "rblimits", 828 }, 829 { "read", cmdread, 1, /*[0x08]*/ 830 "read [|]file [nbytes]", 831 }, 832 { "write", cmdwrite, 1, /*[0x0A]*/ 833 "write [|]file [nbytes]", 834 }, 835 { "seek", cmdseek, 1, /*[0x0B]*/ 836 "seek offset [whence]", 837 }, 838 { "filemark", cmdfilemark, 1, /*[0x10]*/ 839 "filemark [howmany]", 840 }, 841 { "space", cmdspace, 1, /*[0x11]*/ 842 "space [-f] [-b] [[--] howmany]", 843 }, 844 { "inquiry", cmdinquiry, 1, /*[0x12]*/ 845 "inquiry", 846 }, 847 { "modeselect", cmdmodeselect, 1, /*[0x15] */ 848 "modeselect bytes...", 849 }, 850 { "modesense", cmdmodesense, 1, /*[0x1A]*/ 851 "modesense [page [nbytes]]", 852 }, 853 { "start", cmdstart, 1, /*[0x1B]*/ 854 "start [code]", 855 }, 856 { "stop", cmdstop, 1, /*[0x1B]*/ 857 "stop [code]", 858 }, 859 { "eject", cmdeject, 1, /*[0x1B]*/ 860 "eject [code]", 861 }, 862 { "capacity", cmdcapacity, 1, /*[0x25]*/ 863 "capacity", 864 }, 865 866 { "flushcache", cmdflushcache, 1, /*[0x35]*/ 867 "flushcache", 868 }, 869 { "rdiscinfo", cmdrdiscinfo, 1, /*[0x43]*/ 870 "rdiscinfo [track/session-number [ses]]", 871 }, 872 { "fwaddr", cmdfwaddr, 1, /*[0xE2]*/ 873 "fwaddr [track [mode [npa]]]", 874 }, 875 { "treserve", cmdtreserve, 1, /*[0xE4]*/ 876 "treserve nbytes", 877 }, 878 { "trackinfo", cmdtrackinfo, 1, /*[0xE5]*/ 879 "trackinfo [track]", 880 }, 881 { "wtrack", cmdwtrack, 1, /*[0xE6]*/ 882 "wtrack [|]file [nbytes [track [mode]]]", 883 }, 884 { "load", cmdload, 1, /*[0xE7]*/ 885 "load", 886 }, 887 { "unload", cmdunload, 1, /*[0xE7]*/ 888 "unload", 889 }, 890 { "fixation", cmdfixation, 1, /*[0xE9]*/ 891 "fixation [toc-type]", 892 }, 893 894 { "help", cmdhelp, 0, 895 "help", 896 }, 897 { "probe", cmdprobe, 0, 898 "probe", 899 }, 900 { "close", cmdclose, 1, 901 "close", 902 }, 903 { "open", cmdopen, 0, 904 "open target-id", 905 }, 906 { 0, 0 }, 907 }; 908 909 #define SEP(c) (((c)==' ')||((c)=='\t')||((c)=='\n')) 910 911 static char * 912 tokenise(char *s, char **start, char **end) 913 { 914 char *to; 915 Rune r; 916 int n; 917 918 while(*s && SEP(*s)) /* skip leading white space */ 919 s++; 920 to = *start = s; 921 while(*s){ 922 n = chartorune(&r, s); 923 if(SEP(r)){ 924 if(to != *start) /* we have data */ 925 break; 926 s += n; /* null string - keep looking */ 927 while(*s && SEP(*s)) 928 s++; 929 to = *start = s; 930 } 931 else if(r == '\''){ 932 s += n; /* skip leading quote */ 933 while(*s){ 934 n = chartorune(&r, s); 935 if(r == '\''){ 936 if(s[1] != '\'') 937 break; 938 s++; /* embedded quote */ 939 } 940 while (n--) 941 *to++ = *s++; 942 } 943 if(!*s) /* no trailing quote */ 944 break; 945 s++; /* skip trailing quote */ 946 } 947 else { 948 while(n--) 949 *to++ = *s++; 950 } 951 } 952 *end = to; 953 return s; 954 } 955 956 static int 957 parse(char *s, char *fields[], int nfields) 958 { 959 int c, argc; 960 char *start, *end; 961 962 argc = 0; 963 c = *s; 964 while(c){ 965 s = tokenise(s, &start, &end); 966 c = *s++; 967 if(*start == 0) 968 break; 969 if(argc >= nfields-1) 970 return -1; 971 *end = 0; 972 fields[argc++] = start; 973 } 974 fields[argc] = 0; 975 return argc; 976 } 977 978 static void 979 usage(void) 980 { 981 fprint(2, "%s: usage: %s [-b bus] [-q] [scsi-id]\n", argv0, argv0); 982 exits("usage"); 983 } 984 985 void 986 main(int argc, char *argv[]) 987 { 988 ScsiReq target; 989 char *ap, *av[50]; 990 int ac; 991 ScsiCmd *cp; 992 long status; 993 994 ARGBEGIN { 995 case 'b': 996 bus = atoi(ARGF()); 997 break; 998 999 case 'q': 1000 verbose = 0; 1001 break; 1002 1003 default: 1004 usage(); 1005 } ARGEND 1006 1007 if(Binit(&bin, 0, OREAD) == Beof || Binit(&bout, 1, OWRITE) == Beof){ 1008 fprint(2, "%s: can't init bio: %r\n", argv0); 1009 exits("Binit"); 1010 } 1011 1012 memset(&target, 0, sizeof(target)); 1013 if(argc && cmdopen(&target, argc, argv) == -1) 1014 usage(); 1015 Bflush(&bout); 1016 1017 while(ap = Brdline(&bin, '\n')){ 1018 ap[BLINELEN(&bin)-1] = 0; 1019 switch(ac = parse(ap, av, nelem(av))){ 1020 1021 default: 1022 for(cp = scsicmd; cp->name; cp++){ 1023 if(strcmp(cp->name, av[0]) == 0) 1024 break; 1025 } 1026 if(cp->name == 0){ 1027 Bprint(&bout, "eh?\n"); 1028 break; 1029 } 1030 if((target.flags & Fopen) == 0 && cp->open){ 1031 Bprint(&bout, "no current target\n"); 1032 break; 1033 } 1034 if((status = (*cp->f)(&target, ac-1, &av[1])) != -1){ 1035 if(verbose) 1036 Bprint(&bout, "ok %ld\n", status); 1037 break; 1038 } 1039 switch(target.status){ 1040 1041 case Status_OK: 1042 if(verbose) 1043 Bprint(&bout, "ok %ld\n", status); 1044 break; 1045 1046 case Status_SD: 1047 makesense(&target); 1048 break; 1049 1050 case Status_NX: 1051 Bprint(&bout, "select timeout\n"); 1052 break; 1053 1054 case Status_HW: 1055 Bprint(&bout, "hardware error\n"); 1056 break; 1057 1058 case Status_SW: 1059 Bprint(&bout, "software error\n"); 1060 break; 1061 1062 case Status_BADARG: 1063 Bprint(&bout, "bad argument\n"); 1064 break; 1065 1066 case Status_RO: 1067 Bprint(&bout, "device is read-only\n"); 1068 break; 1069 1070 default: 1071 Bprint(&bout, "status %ld #%2.2ux\n", status, target.status); 1072 break; 1073 } 1074 break; 1075 1076 case -1: 1077 Bprint(&bout, "eh?\n"); 1078 break; 1079 1080 case 0: 1081 break; 1082 } 1083 Bflush(&bout); 1084 } 1085 exits(0); 1086 } 1087 1088