1 /* $OpenBSD: scsi.c,v 1.8 2001/07/07 18:26:21 deraadt Exp $ */ 2 /* $FreeBSD: scsi.c,v 1.11 1996/04/06 11:00:28 joerg Exp $ */ 3 4 /* 5 * Written By Julian ELischer 6 * Copyright julian Elischer 1993. 7 * Permission is granted to use or redistribute this file in any way as long 8 * as this notice remains. Julian Elischer does not guarantee that this file 9 * is totally correct for any given task and users of this file must 10 * accept responsibility for any damage that occurs from the application of this 11 * file. 12 * 13 * (julian@tfs.com julian@dialix.oz.au) 14 * 15 * User SCSI hooks added by Peter Dufault: 16 * 17 * Copyright (c) 1994 HD Associates 18 * (contact: dufault@hda.com) 19 * All rights reserved. 20 * 21 * Redistribution and use in source and binary forms, with or without 22 * modification, are permitted provided that the following conditions 23 * are met: 24 * 1. Redistributions of source code must retain the above copyright 25 * notice, this list of conditions and the following disclaimer. 26 * 2. Redistributions in binary form must reproduce the above copyright 27 * notice, this list of conditions and the following disclaimer in the 28 * documentation and/or other materials provided with the distribution. 29 * 3. The name of HD Associates 30 * may not be used to endorse or promote products derived from this software 31 * without specific prior written permission. 32 * 33 * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES ``AS IS'' AND 34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 36 * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES BE LIABLE 37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 43 * SUCH DAMAGE. 44 */ 45 46 #include <stdio.h> 47 #include <string.h> 48 #include <stdlib.h> 49 #include <unistd.h> 50 #include <errno.h> 51 #include <sys/scsiio.h> 52 #include <sys/file.h> 53 #include <scsi.h> 54 #include <ctype.h> 55 #include <signal.h> 56 57 int fd; 58 int debuglevel; 59 int debugflag; 60 int commandflag; 61 int reprobe; 62 #ifdef SCIOCADDR 63 int probe_all; 64 #endif 65 int verbose = 0; 66 int bus = -1; /* all busses */ 67 int targ = -1; /* all targs */ 68 int lun = 0; /* just lun 0 */ 69 #ifdef SCIOCFREEZE 70 int freeze = 0; /* Freeze this many seconds */ 71 #endif 72 73 int modeflag; 74 int editflag; 75 int modepage = 0; /* Read this mode page */ 76 int pagectl = 0; /* Mode sense page control */ 77 int seconds = 2; 78 79 void usage(void) 80 { 81 printf( 82 83 "Usage:\n" 84 "\n" 85 " scsi -f device -d debug_level # To set debug level\n" 86 #ifdef SCIOCFREEZE 87 " scsi -f device [-v] -z seconds # To freeze bus\n" 88 #endif 89 " scsi -f device -m page [-P pc] # To read mode pages\n" 90 " scsi -f device -p [-b bus] [-l lun] # To probe all devices\n" 91 " scsi -f device -r [-b bus] [-t targ] [-l lun] # To reprobe a device\n" 92 " scsi -f device [-v] [-s seconds] -c cmd_fmt [arg0 ... argn] # A command...\n" 93 " -o count out_fmt [arg0 ... argn] # EITHER (data out)\n" 94 " -i count in_fmt # OR (data in)\n" 95 "\n" 96 "\"out_fmt\" can be \"-\" to read output data from stdin;\n" 97 "\"in_fmt\" can be \"-\" to write input data to stdout;\n" 98 "\n" 99 "If debugging is not compiled in the kernel, \"-d\" will have no effect\n" 100 101 ); 102 103 exit (1); 104 } 105 106 void procargs(int *argc_p, char ***argv_p) 107 { 108 int argc = *argc_p; 109 char **argv = *argv_p; 110 int fflag, 111 ch; 112 113 fflag = 0; 114 commandflag = 0; 115 debugflag = 0; 116 while ((ch = getopt(argc, argv, "ceprvf:d:b:t:l:z:m:P:s:")) != -1) { 117 switch (ch) { 118 #ifdef SCIOCADDR 119 case 'p': 120 probe_all = 1; 121 break; 122 #endif 123 case 'r': 124 reprobe = 1; 125 break; 126 case 'c': 127 commandflag = 1; 128 break; 129 case 'v': 130 verbose = 1; 131 break; 132 case 'e': 133 editflag = 1; 134 break; 135 case 'f': 136 if ((fd = scsi_open(optarg, O_RDWR)) < 0) { 137 (void) fprintf(stderr, 138 "%s: unable to open device %s: %s\n", 139 argv[0], optarg, strerror(errno)); 140 exit(errno); 141 } 142 fflag = 1; 143 break; 144 case 'd': 145 debuglevel = strtol(optarg, 0, 0); 146 debugflag = 1; 147 break; 148 case 'b': 149 bus = strtol(optarg, 0, 0); 150 break; 151 case 't': 152 targ = strtol(optarg, 0, 0); 153 break; 154 case 'l': 155 lun = strtol(optarg, 0, 0); 156 break; 157 #ifdef SCIOCFREEZE 158 case 'z': 159 freeze = strtol(optarg, 0, 0); 160 break; 161 #endif 162 case 'P': 163 pagectl = strtol(optarg, 0, 0); 164 break; 165 case 's': 166 seconds = strtol(optarg, 0, 0); 167 break; 168 case 'm': 169 modeflag = 1; 170 modepage = strtol(optarg, 0, 0); 171 break; 172 case '?': 173 default: 174 usage(); 175 } 176 } 177 *argc_p = argc - optind; 178 *argv_p = argv + optind; 179 180 if (!fflag) usage(); 181 } 182 183 /* get_hook: Structure for evaluating args in a callback. 184 */ 185 struct get_hook 186 { 187 int argc; 188 char **argv; 189 int got; 190 }; 191 192 /* iget: Integer argument callback 193 */ 194 int iget(void *hook, char *name) 195 { 196 struct get_hook *h = (struct get_hook *)hook; 197 int arg; 198 199 if (h->got >= h->argc) 200 { 201 fprintf(stderr, "Expecting an integer argument.\n"); 202 usage(); 203 } 204 arg = strtol(h->argv[h->got], 0, 0); 205 h->got++; 206 207 if (verbose && name && *name) 208 printf("%s: %d\n", name, arg); 209 210 return arg; 211 } 212 213 /* cget: char * argument callback 214 */ 215 char *cget(void *hook, char *name) 216 { 217 struct get_hook *h = (struct get_hook *)hook; 218 char *arg; 219 220 if (h->got >= h->argc) 221 { 222 fprintf(stderr, "Expecting a character pointer argument.\n"); 223 usage(); 224 } 225 arg = h->argv[h->got]; 226 h->got++; 227 228 if (verbose && name) 229 printf("cget: %s: %s", name, arg); 230 231 return arg; 232 } 233 234 /* arg_put: "put argument" callback 235 */ 236 void arg_put(void *hook, int letter, void *arg, int count, char *name) 237 { 238 if (verbose && name && *name) 239 printf("%s: ", name); 240 241 switch(letter) 242 { 243 case 'i': 244 case 'b': 245 printf("%ld ", (long)arg); 246 break; 247 248 case 'c': 249 case 'z': 250 { 251 char *p = malloc(count + 1); 252 p[count] = 0; 253 strncpy(p, (char *)arg, count); 254 if (letter == 'z') 255 { 256 int i; 257 for (i = count - 1; i >= 0; i--) 258 if (p[i] == ' ') 259 p[i] = 0; 260 else 261 break; 262 } 263 printf("%s ", p); 264 } 265 266 break; 267 268 default: 269 printf("Unknown format letter: '%c'\n", letter); 270 } 271 if (verbose) 272 putchar('\n'); 273 } 274 275 int arg_get (void *hook, char *field_name) 276 { 277 printf("get \"%s\".\n", field_name); 278 return 0; 279 } 280 281 /* data_phase: SCSI bus data phase: DATA IN, DATA OUT, or no data transfer. 282 */ 283 enum data_phase {none = 0, in, out}; 284 285 /* do_cmd: Send a command to a SCSI device 286 */ 287 static void 288 do_cmd(int fd, char *fmt, int argc, char **argv) 289 { 290 struct get_hook h; 291 scsireq_t *scsireq = scsireq_new(); 292 enum data_phase data_phase; 293 int count, amount; 294 char *data_fmt, *bp; 295 296 h.argc = argc; 297 h.argv = argv; 298 h.got = 0; 299 300 scsireq_reset(scsireq); 301 302 scsireq_build_visit(scsireq, 0, 0, 0, fmt, iget, (void *)&h); 303 304 /* Three choices here: 305 * 1. We've used up all the args and have no data phase. 306 * 2. We have input data ("-i") 307 * 3. We have output data ("-o") 308 */ 309 310 if (h.got >= h.argc) 311 { 312 data_phase = none; 313 count = scsireq->datalen = 0; 314 } 315 else 316 { 317 char *flag = cget(&h, 0); 318 319 if (strcmp(flag, "-o") == 0) 320 { 321 data_phase = out; 322 scsireq->flags = SCCMD_WRITE; 323 } 324 else if (strcmp(flag, "-i") == 0) 325 { 326 data_phase = in; 327 scsireq->flags = SCCMD_READ; 328 } 329 else 330 { 331 fprintf(stderr, 332 "Need either \"-i\" or \"-o\" for data phase; not \"%s\".\n", flag); 333 usage(); 334 } 335 336 count = scsireq->datalen = iget(&h, 0); 337 if (count) 338 { 339 data_fmt = cget(&h, 0); 340 341 scsireq->databuf = malloc(count); 342 343 if (data_phase == out) 344 { 345 if (strcmp(data_fmt, "-") == 0) /* Read data from stdin */ 346 { 347 bp = (char *)scsireq->databuf; 348 while (count > 0 && (amount = read(0, bp, count)) > 0) 349 { 350 count -= amount; 351 bp += amount; 352 } 353 if (amount == -1) 354 { 355 perror("read"); 356 exit(errno); 357 } 358 else if (amount == 0) 359 { 360 /* early EOF */ 361 fprintf(stderr, 362 "Warning: only read %lu bytes out of %lu.\n", 363 scsireq->datalen - (u_long)count, 364 scsireq->datalen); 365 scsireq->datalen -= (u_long)count; 366 } 367 } 368 else 369 { 370 bzero(scsireq->databuf, count); 371 scsireq_encode_visit(scsireq, data_fmt, iget, (void *)&h); 372 } 373 } 374 } 375 } 376 377 378 scsireq->timeout = seconds * 1000; 379 380 if (scsireq_enter(fd, scsireq) == -1) 381 { 382 scsi_debug(stderr, -1, scsireq); 383 exit(errno); 384 } 385 386 if (SCSIREQ_ERROR(scsireq)) 387 scsi_debug(stderr, 0, scsireq); 388 389 if (count && data_phase == in) 390 { 391 if (strcmp(data_fmt, "-") == 0) /* stdout */ 392 { 393 bp = (char *)scsireq->databuf; 394 while (count > 0 && (amount = write(1, bp, count)) > 0) 395 { 396 count -= amount; 397 bp += amount; 398 } 399 if (amount < 0) 400 { 401 perror("write"); 402 exit(errno); 403 } 404 else if (amount == 0) 405 fprintf(stderr, "Warning: wrote only %u bytes out of %u.\n", 406 scsireq->datalen - count, 407 scsireq->datalen); 408 409 } 410 else 411 { 412 scsireq_decode_visit(scsireq, data_fmt, arg_put, 0); 413 putchar('\n'); 414 } 415 } 416 } 417 418 #ifdef SCIOCFREEZE 419 static void 420 freeze_ioctl(int fd, int op, void *data) 421 { 422 if (ioctl(fd, SCIOCFREEZE, 0) == -1) { 423 if (errno == ENODEV) { 424 fprintf(stderr, 425 "Your kernel must be configured with option SCSI_FREEZE.\n"); 426 } 427 else 428 perror("SCIOCFREEZE"); 429 exit(errno); 430 } 431 } 432 433 /* do_freeze: Freeze the bus for a given number of seconds. 434 */ 435 static void do_freeze(int seconds) 436 { 437 if (seconds == -1) { 438 printf("Hit return to thaw: "); 439 fflush(stdout); 440 sync(); 441 442 freeze_ioctl(fd, SCIOCFREEZE, 0); 443 444 (void)getchar(); 445 446 freeze_ioctl(fd, SCIOCTHAW, 0); 447 } 448 else { 449 sync(); 450 freeze_ioctl(fd, SCIOCFREEZETHAW, &seconds); 451 if (verbose) { 452 putchar('\007'); 453 fflush(stdout); 454 } 455 456 freeze_ioctl(fd, SCIOCWAITTHAW, 0); 457 if (verbose) { 458 putchar('\007'); 459 fflush(stdout); 460 } 461 } 462 } 463 #endif 464 465 void mode_sense(int fd, u_char *data, int len, int pc, int page) 466 { 467 scsireq_t *scsireq; 468 469 bzero(data, len); 470 471 scsireq = scsireq_new(); 472 473 if (scsireq_enter(fd, scsireq_build(scsireq, 474 len, data, SCCMD_READ, 475 "1A 0 v:2 {Page Control} v:6 {Page Code} 0 v:i1 {Allocation Length} 0", 476 pc, page, len)) == -1) /* Mode sense */ 477 { 478 scsi_debug(stderr, -1, scsireq); 479 exit(errno); 480 } 481 482 if (SCSIREQ_ERROR(scsireq)) 483 { 484 scsi_debug(stderr, 0, scsireq); 485 exit(1); 486 } 487 488 free(scsireq); 489 } 490 491 void mode_select(int fd, u_char *data, int len, int perm) 492 { 493 scsireq_t *scsireq; 494 495 scsireq = scsireq_new(); 496 497 if (scsireq_enter(fd, scsireq_build(scsireq, 498 len, data, SCCMD_WRITE, 499 "15 0:7 v:1 {SP} 0 0 v:i1 {Allocation Length} 0", perm, len)) == -1) /* Mode select */ 500 { 501 scsi_debug(stderr, -1, scsireq); 502 exit(errno); 503 } 504 505 if (SCSIREQ_ERROR(scsireq)) 506 { 507 scsi_debug(stderr, 0, scsireq); 508 exit(1); 509 } 510 511 free(scsireq); 512 } 513 514 515 #define START_ENTRY '{' 516 #define END_ENTRY '}' 517 518 static void 519 skipwhite(FILE *f) 520 { 521 int c; 522 523 skip_again: 524 525 while (isspace(c = getc(f))) 526 ; 527 528 if (c == '#') { 529 while ((c = getc(f)) != '\n' && c != EOF) 530 ; 531 goto skip_again; 532 } 533 534 ungetc(c, f); 535 } 536 537 /* mode_lookup: Lookup a format description for a given page. 538 */ 539 char *mode_db = "/usr/share/misc/scsi_modes"; 540 static char *mode_lookup(int page) 541 { 542 char *new_db; 543 FILE *modes; 544 int match, next, found, c; 545 static char fmt[1024]; /* XXX This should be with strealloc */ 546 int page_desc; 547 new_db = getenv("SCSI_MODES"); 548 549 if (new_db) 550 mode_db = new_db; 551 552 modes = fopen(mode_db, "r"); 553 if (modes == 0) 554 return 0; 555 556 next = 0; 557 found = 0; 558 559 while (!found) { 560 561 skipwhite(modes); 562 563 if (fscanf(modes, "%i", &page_desc) != 1) 564 break; 565 566 if (page_desc == page) 567 found = 1; 568 569 skipwhite(modes); 570 if (getc(modes) != START_ENTRY) { 571 fprintf(stderr, "Expected %c.\n", START_ENTRY); 572 exit(1); 573 } 574 575 match = 1; 576 while (match != 0) { 577 c = getc(modes); 578 if (c == EOF) { 579 fprintf(stderr, "Expected %c.\n", END_ENTRY); 580 } 581 582 if (c == START_ENTRY) { 583 match++; 584 } 585 if (c == END_ENTRY) { 586 match--; 587 if (match == 0) 588 break; 589 } 590 if (found && c != '\n') { 591 if (next >= sizeof(fmt)) { 592 fprintf(stderr, "Stupid program: Buffer overflow.\n"); 593 exit(ENOMEM); 594 } 595 596 fmt[next++] = (u_char)c; 597 } 598 } 599 } 600 fmt[next] = 0; 601 602 return (found) ? fmt : 0; 603 } 604 605 /* -------- edit: Mode Select Editor --------- 606 */ 607 struct editinfo 608 { 609 long can_edit; 610 long default_value; 611 } editinfo[64]; /* XXX Bogus fixed size */ 612 613 static int editind; 614 volatile int edit_opened; 615 static FILE *edit_file; 616 static char edit_name[L_tmpnam]; 617 618 static inline void 619 edit_rewind(void) 620 { 621 editind = 0; 622 } 623 624 static void 625 edit_done(void) 626 { 627 int opened; 628 629 sigset_t all, prev; 630 sigfillset(&all); 631 632 (void)sigprocmask(SIG_SETMASK, &all, &prev); 633 634 opened = (int)edit_opened; 635 edit_opened = 0; 636 637 (void)sigprocmask(SIG_SETMASK, &prev, 0); 638 639 if (opened) 640 { 641 if (fclose(edit_file)) 642 perror(edit_name); 643 if (unlink(edit_name)) 644 perror(edit_name); 645 } 646 } 647 648 static void 649 edit_init(void) 650 { 651 int fd; 652 653 edit_rewind(); 654 strcpy(edit_name, "/var/tmp/scXXXXXXXX"); 655 if ((fd = mkstemp(edit_name)) == -1) { 656 perror("mkstemp failed"); 657 exit(errno); 658 } 659 if ( (edit_file = fdopen(fd, "w+")) == 0) { 660 perror("fdopen failed"); 661 exit(errno); 662 } 663 edit_opened = 1; 664 665 atexit(edit_done); 666 } 667 668 static void 669 edit_check(void *hook, int letter, void *arg, int count, char *name) 670 { 671 if (letter != 'i' && letter != 'b') { 672 fprintf(stderr, "Can't edit format %c.\n", letter); 673 exit(1); 674 } 675 676 if (editind >= sizeof(editinfo) / sizeof(editinfo[0])) { 677 fprintf(stderr, "edit table overflow\n"); 678 exit(ENOMEM); 679 } 680 editinfo[editind].can_edit = ((long)arg != 0); 681 editind++; 682 } 683 684 static void 685 edit_defaults(void *hook, int letter, void *arg, int count, char *name) 686 { 687 if (letter != 'i' && letter != 'b') { 688 fprintf(stderr, "Can't edit format %c.\n", letter); 689 exit(1); 690 } 691 692 editinfo[editind].default_value = ((long)arg); 693 editind++; 694 } 695 696 static void 697 edit_report(void *hook, int letter, void *arg, int count, char *name) 698 { 699 if (editinfo[editind].can_edit) { 700 if (letter != 'i' && letter != 'b') { 701 fprintf(stderr, "Can't report format %c.\n", letter); 702 exit(1); 703 } 704 705 fprintf(edit_file, "%s: %ld\n", name, (long)arg); 706 } 707 708 editind++; 709 } 710 711 static int 712 edit_get(void *hook, char *name) 713 { 714 int arg = editinfo[editind].default_value; 715 716 if (editinfo[editind].can_edit) { 717 char line[80]; 718 if (fgets(line, sizeof(line), edit_file) == 0) { 719 perror("fgets"); 720 exit(errno); 721 } 722 723 line[strlen(line) - 1] = 0; 724 725 if (strncmp(name, line, strlen(name)) != 0) { 726 fprintf(stderr, "Expected \"%s\" and read \"%s\"\n", 727 name, line); 728 exit(1); 729 } 730 731 arg = strtoul(line + strlen(name) + 2, 0, 0); 732 } 733 734 editind++; 735 return arg; 736 } 737 738 static void 739 edit_edit(void) 740 { 741 char *system_line; 742 char *editor = getenv("EDITOR"); 743 if (!editor) 744 editor = "vi"; 745 746 fclose(edit_file); 747 748 system_line = malloc(strlen(editor) + strlen(edit_name) + 6); 749 sprintf(system_line, "%s %s", editor, edit_name); 750 system(system_line); 751 free(system_line); 752 753 if ( (edit_file = fopen(edit_name, "r")) == 0) { 754 perror(edit_name); 755 exit(errno); 756 } 757 } 758 759 static void 760 mode_edit(int fd, int page, int edit, int argc, char *argv[]) 761 { 762 int i; 763 u_char data[255]; 764 u_char *mode_pars; 765 struct mode_header 766 { 767 u_char mdl; /* Mode data length */ 768 u_char medium_type; 769 u_char dev_spec_par; 770 u_char bdl; /* Block descriptor length */ 771 }; 772 773 struct mode_page_header 774 { 775 u_char page_code; 776 u_char page_length; 777 }; 778 779 struct mode_header *mh; 780 struct mode_page_header *mph; 781 782 char *fmt = mode_lookup(page); 783 if (!fmt && verbose) { 784 fprintf(stderr, 785 "No mode data base entry in \"%s\" for page %d; binary %s only.\n", 786 mode_db, page, (edit ? "edit" : "display")); 787 } 788 789 if (edit) { 790 if (!fmt) { 791 fprintf(stderr, "Sorry: can't edit without a format.\n"); 792 exit(1); 793 } 794 795 if (pagectl != 0 && pagectl != 3) { 796 fprintf(stderr, 797 "It only makes sense to edit page 0 (current) or page 3 (saved values)\n"); 798 exit(1); 799 } 800 801 verbose = 1; 802 803 mode_sense(fd, data, sizeof(data), 1, page); 804 805 mh = (struct mode_header *)data; 806 mph = (struct mode_page_header *) 807 (((char *)mh) + sizeof(*mh) + mh->bdl); 808 809 mode_pars = (char *)mph + sizeof(*mph); 810 811 edit_init(); 812 scsireq_buff_decode_visit(mode_pars, mh->mdl, 813 fmt, edit_check, 0); 814 815 mode_sense(fd, data, sizeof(data), 0, page); 816 817 edit_rewind(); 818 scsireq_buff_decode_visit(mode_pars, mh->mdl, 819 fmt, edit_defaults, 0); 820 821 edit_rewind(); 822 scsireq_buff_decode_visit(mode_pars, mh->mdl, 823 fmt, edit_report, 0); 824 825 edit_edit(); 826 827 edit_rewind(); 828 scsireq_buff_encode_visit(mode_pars, mh->mdl, 829 fmt, edit_get, 0); 830 831 /* Eliminate block descriptors: 832 */ 833 bcopy((char *)mph, ((char *)mh) + sizeof(*mh), 834 sizeof(*mph) + mph->page_length); 835 836 mh->bdl = 0; 837 mph = (struct mode_page_header *) (((char *)mh) + sizeof(*mh)); 838 mode_pars = ((char *)mph) + 2; 839 840 #if 0 841 /* Turn this on to see what you're sending to the 842 * device: 843 */ 844 edit_rewind(); 845 scsireq_buff_decode_visit(mode_pars, 846 mh->mdl, fmt, arg_put, 0); 847 #endif 848 849 edit_done(); 850 851 /* Make it permanent if pageselect is three. 852 */ 853 854 mph->page_code &= ~0xC0; /* Clear PS and RESERVED */ 855 mh->mdl = 0; /* Reserved for mode select */ 856 857 mode_select(fd, (char *)mh, 858 sizeof(*mh) + mh->bdl + sizeof(*mph) + mph->page_length, 859 (pagectl == 3)); 860 861 exit(0); 862 } 863 864 mode_sense(fd, data, sizeof(data), pagectl, page); 865 866 /* Skip over the block descriptors. 867 */ 868 mh = (struct mode_header *)data; 869 mph = (struct mode_page_header *)(((char *)mh) + sizeof(*mh) + mh->bdl); 870 mode_pars = (char *)mph + sizeof(*mph); 871 872 if (!fmt) { 873 for (i = 0; i < mh->mdl; i++) { 874 printf("%02x%c",mode_pars[i], 875 (((i + 1) % 8) == 0) ? '\n' : ' '); 876 } 877 putc('\n', stdout); 878 } else { 879 verbose = 1; 880 scsireq_buff_decode_visit(mode_pars, 881 mh->mdl, fmt, arg_put, 0); 882 } 883 } 884 885 #ifdef SCIOCADDR 886 /* do_probe_all: Loop over all SCSI IDs and see if something is 887 * there. This only does BUS 0 LUN 0. 888 */ 889 void do_probe_all(void) 890 { 891 scsireq_t *scsireq; 892 893 char vendor_id[8 + 1], product_id[16 + 1], revision[4 + 1]; 894 int id; 895 u_char *inq_buf = malloc(96); 896 struct scsi_addr addr; 897 898 scsireq = scsireq_build(scsireq_new(), 899 96, inq_buf, SCCMD_READ, 900 "12 0 0 0 v 0", 96); 901 902 addr.scbus = (bus == -1) ? 0 : bus; 903 addr.lun = lun; 904 905 if (addr.scbus || addr.lun) 906 { 907 printf("For bus %d lun %d:\n", addr.scbus, addr.lun); 908 } 909 910 for (id = 0; id < 8; id++) 911 { 912 addr.target = id; 913 914 printf("%d: ", id); 915 if (ioctl(fd, SCIOCADDR, &addr) == -1) { 916 if (errno == ENXIO) 917 { 918 errno = 0; 919 printf("nothing.\n"); 920 } 921 else 922 printf("SCIOCADDR: %s\n", strerror(errno)); 923 924 continue; 925 } 926 927 if (scsireq_enter(fd, scsireq) == -1) { 928 printf("scsireq_enter: %s\n", strerror(errno)); 929 continue; 930 } 931 932 vendor_id[sizeof(vendor_id) - 1] = 0; 933 product_id[sizeof(product_id) - 1] = 0; 934 revision[sizeof(revision) - 1] = 0; 935 936 scsireq_decode(scsireq, "s8 c8 c16 c4", 937 vendor_id, product_id, revision); 938 939 printf("%s %s %s\n", vendor_id, product_id, revision); 940 } 941 } 942 #endif 943 944 int 945 main(int argc, char **argv) 946 { 947 struct scsi_addr scaddr; 948 949 procargs(&argc,&argv); 950 951 /* XXX This has grown to the point that it should be cleaned up. 952 */ 953 #ifdef SCIOCFREEZE 954 if (freeze) { 955 do_freeze(freeze); 956 } else 957 #endif 958 #ifdef SCIOCADDR 959 if (probe_all) { 960 do_probe_all(); 961 } else 962 #endif 963 if(reprobe) { 964 scaddr.scbus = bus; 965 scaddr.target = targ; 966 scaddr.lun = lun; 967 968 if (ioctl(fd,SCIOCREPROBE,&scaddr) == -1) 969 perror("ioctl"); 970 } else if(debugflag) { 971 if (ioctl(fd,SCIOCDEBUG,&debuglevel) == -1) 972 { 973 perror("ioctl [SCIODEBUG]"); 974 exit(1); 975 } 976 } else if (commandflag) { 977 char *fmt; 978 979 if (argc < 1) { 980 fprintf(stderr, "Need the command format string.\n"); 981 usage(); 982 } 983 984 985 fmt = argv[0]; 986 987 argc -= 1; 988 argv += 1; 989 990 do_cmd(fd, fmt, argc, argv); 991 } else if (modeflag) { 992 mode_edit(fd, modepage, editflag, argc, argv); 993 } 994 exit(0); 995 } 996