1 /* $OpenBSD: scsi.c,v 1.20 2005/11/13 19:16:09 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 <ctype.h> 54 #include <signal.h> 55 #include <err.h> 56 #include <paths.h> 57 58 #include "libscsi.h" 59 60 int fd; 61 int debuglevel; 62 int debugflag; 63 int commandflag; 64 int reprobe; 65 #ifdef SCIOCADDR 66 int probe_all; 67 #endif 68 int verbose = 0; 69 int bus = -1; /* all busses */ 70 int targ = -1; /* all targs */ 71 int lun = 0; /* just lun 0 */ 72 #ifdef SCIOCFREEZE 73 int freeze = 0; /* Freeze this many seconds */ 74 #endif 75 76 int modeflag; 77 int editflag; 78 int modepage = 0; /* Read this mode page */ 79 int pagectl = 0; /* Mode sense page control */ 80 int seconds = 2; 81 82 void procargs(int *argc_p, char ***argv_p); 83 int iget(void *hook, char *name); 84 char *cget(void *hook, char *name); 85 void arg_put(void *hook, int letter, void *arg, int count, char *name); 86 int arg_get (void *hook, char *field_name); 87 void mode_sense(int fd, u_char *data, int len, int pc, int page); 88 void mode_select(int fd, u_char *data, int len, int perm); 89 90 static void 91 usage(void) 92 { 93 fprintf(stderr, 94 "Usage:\n" 95 "\n" 96 " scsi -f device -d debug_level # To set debug level\n" 97 #ifdef SCIOCFREEZE 98 " scsi -f device [-v] -z seconds # To freeze bus\n" 99 #endif 100 " scsi -f device -m page [-P pc] # To read mode pages\n" 101 " scsi -f device -p [-b bus] [-l lun] # To probe all devices\n" 102 " scsi -f device -r [-b bus] [-t targ] [-l lun] # To reprobe a device\n" 103 " scsi -f device [-v] [-s seconds] -c cmd_fmt [arg0 ... argn] # A command...\n" 104 " -o count out_fmt [arg0 ... argn] # EITHER (data out)\n" 105 " -i count in_fmt # OR (data in)\n" 106 "\n" 107 "\"out_fmt\" can be \"-\" to read output data from stdin;\n" 108 "\"in_fmt\" can be \"-\" to write input data to stdout;\n" 109 "\n" 110 "If debugging is not compiled in the kernel, \"-d\" will have no effect\n" 111 112 ); 113 114 exit (1); 115 } 116 117 void 118 procargs(int *argc_p, char ***argv_p) 119 { 120 int argc = *argc_p; 121 char **argv = *argv_p; 122 int fflag, ch; 123 124 fflag = 0; 125 commandflag = 0; 126 debugflag = 0; 127 while ((ch = getopt(argc, argv, "ceprvf:d:b:t:l:z:m:P:s:")) != -1) { 128 switch (ch) { 129 #ifdef SCIOCADDR 130 case 'p': 131 probe_all = 1; 132 break; 133 #endif 134 case 'r': 135 reprobe = 1; 136 break; 137 case 'c': 138 commandflag = 1; 139 break; 140 case 'v': 141 verbose = 1; 142 break; 143 case 'e': 144 editflag = 1; 145 break; 146 case 'f': 147 if ((fd = scsi_open(optarg, O_RDWR)) < 0) 148 err(errno, "unable to open device %s", optarg); 149 fflag = 1; 150 break; 151 case 'd': 152 debuglevel = strtol(optarg, 0, 0); 153 debugflag = 1; 154 break; 155 case 'b': 156 bus = strtol(optarg, 0, 0); 157 break; 158 case 't': 159 targ = strtol(optarg, 0, 0); 160 break; 161 case 'l': 162 lun = strtol(optarg, 0, 0); 163 break; 164 #ifdef SCIOCFREEZE 165 case 'z': 166 freeze = strtol(optarg, 0, 0); 167 break; 168 #endif 169 case 'P': 170 pagectl = strtol(optarg, 0, 0); 171 break; 172 case 's': 173 seconds = strtol(optarg, 0, 0); 174 break; 175 case 'm': 176 modeflag = 1; 177 modepage = strtol(optarg, 0, 0); 178 break; 179 case '?': 180 default: 181 usage(); 182 } 183 } 184 *argc_p = argc - optind; 185 *argv_p = argv + optind; 186 187 if (!fflag) usage(); 188 } 189 190 /* get_hook: Structure for evaluating args in a callback. 191 */ 192 struct get_hook 193 { 194 int argc; 195 char **argv; 196 int got; 197 }; 198 199 /* iget: Integer argument callback 200 */ 201 int 202 iget(void *hook, char *name) 203 { 204 struct get_hook *h = (struct get_hook *)hook; 205 int arg; 206 207 if (h->got >= h->argc) 208 { 209 fprintf(stderr, "Expecting an integer argument.\n"); 210 usage(); 211 } 212 arg = strtol(h->argv[h->got], 0, 0); 213 h->got++; 214 215 if (verbose && name && *name) 216 printf("%s: %d\n", name, arg); 217 218 return arg; 219 } 220 221 /* cget: char * argument callback 222 */ 223 char * 224 cget(void *hook, char *name) 225 { 226 struct get_hook *h = (struct get_hook *)hook; 227 char *arg; 228 229 if (h->got >= h->argc) 230 { 231 fprintf(stderr, "Expecting a character pointer argument.\n"); 232 usage(); 233 } 234 arg = h->argv[h->got]; 235 h->got++; 236 237 if (verbose && name) 238 printf("cget: %s: %s", name, arg); 239 240 return arg; 241 } 242 243 /* arg_put: "put argument" callback 244 */ 245 void arg_put(void *hook, int letter, void *arg, int count, char *name) 246 { 247 if (verbose && name && *name) 248 printf("%s: ", name); 249 250 switch(letter) 251 { 252 case 'i': 253 case 'b': 254 printf("%ld ", (long)arg); 255 break; 256 257 case 'c': 258 case 'z': 259 { 260 char *p = malloc(count + 1); 261 p[count] = 0; 262 strncpy(p, (char *)arg, count); 263 if (letter == 'z') 264 { 265 int i; 266 for (i = count - 1; i >= 0; i--) 267 if (p[i] == ' ') 268 p[i] = 0; 269 else 270 break; 271 } 272 printf("%s ", p); 273 } 274 275 break; 276 277 default: 278 printf("Unknown format letter: '%c'\n", letter); 279 } 280 if (verbose) 281 putchar('\n'); 282 } 283 284 int arg_get (void *hook, char *field_name) 285 { 286 printf("get \"%s\".\n", field_name); 287 return 0; 288 } 289 290 /* data_phase: SCSI bus data phase: DATA IN, DATA OUT, or no data transfer. 291 */ 292 enum data_phase {none = 0, in, out}; 293 294 /* do_cmd: Send a command to a SCSI device 295 */ 296 static void 297 do_cmd(int fd, char *fmt, int argc, char **argv) 298 { 299 struct get_hook h; 300 scsireq_t *scsireq = scsireq_new(); 301 enum data_phase data_phase; 302 int count, amount; 303 char *data_fmt, *bp; 304 305 h.argc = argc; 306 h.argv = argv; 307 h.got = 0; 308 309 scsireq_reset(scsireq); 310 311 scsireq_build_visit(scsireq, 0, 0, 0, fmt, iget, (void *)&h); 312 313 /* Three choices here: 314 * 1. We've used up all the args and have no data phase. 315 * 2. We have input data ("-i") 316 * 3. We have output data ("-o") 317 */ 318 319 if (h.got >= h.argc) 320 { 321 data_phase = none; 322 count = scsireq->datalen = 0; 323 } 324 else 325 { 326 char *flag = cget(&h, 0); 327 328 if (strcmp(flag, "-o") == 0) 329 { 330 data_phase = out; 331 scsireq->flags = SCCMD_WRITE; 332 } 333 else if (strcmp(flag, "-i") == 0) 334 { 335 data_phase = in; 336 scsireq->flags = SCCMD_READ; 337 } 338 else 339 { 340 fprintf(stderr, 341 "Need either \"-i\" or \"-o\" for data phase; not \"%s\".\n", flag); 342 usage(); 343 } 344 345 count = scsireq->datalen = iget(&h, 0); 346 if (count) { 347 data_fmt = cget(&h, 0); 348 349 scsireq->databuf = malloc(count); 350 351 if (data_phase == out) { 352 if (strcmp(data_fmt, "-") == 0) { 353 bp = (char *)scsireq->databuf; 354 while (count > 0 && 355 (amount = read(STDIN_FILENO, 356 bp, count)) > 0) { 357 count -= amount; 358 bp += amount; 359 } 360 if (amount == -1) 361 err(errno, "read"); 362 else if (amount == 0) { 363 /* early EOF */ 364 fprintf(stderr, 365 "Warning: only read %lu bytes out of %lu.\n", 366 scsireq->datalen - (u_long)count, 367 scsireq->datalen); 368 scsireq->datalen -= (u_long)count; 369 } 370 } 371 else 372 { 373 bzero(scsireq->databuf, count); 374 scsireq_encode_visit(scsireq, data_fmt, iget, (void *)&h); 375 } 376 } 377 } 378 } 379 380 381 scsireq->timeout = seconds * 1000; 382 383 if (scsireq_enter(fd, scsireq) == -1) 384 { 385 scsi_debug(stderr, -1, scsireq); 386 exit(errno); 387 } 388 389 if (SCSIREQ_ERROR(scsireq)) 390 scsi_debug(stderr, 0, scsireq); 391 392 if (count && data_phase == in) 393 { 394 if (strcmp(data_fmt, "-") == 0) /* stdout */ 395 { 396 bp = (char *)scsireq->databuf; 397 while (count > 0 && (amount = write(STDOUT_FILENO, bp, count)) > 0) 398 { 399 count -= amount; 400 bp += amount; 401 } 402 if (amount < 0) 403 err(errno, "write"); 404 else if (amount == 0) 405 fprintf(stderr, "Warning: wrote only %lu bytes out of %lu.\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 exit(errno); 427 } else 428 err(errno, "SCIOCFREEZE"); 429 } 430 } 431 432 /* do_freeze: Freeze the bus for a given number of seconds. 433 */ 434 static void do_freeze(int seconds) 435 { 436 if (seconds == -1) { 437 printf("Hit return to thaw: "); 438 fflush(stdout); 439 sync(); 440 441 freeze_ioctl(fd, SCIOCFREEZE, 0); 442 443 (void)getchar(); 444 445 freeze_ioctl(fd, SCIOCTHAW, 0); 446 } 447 else { 448 sync(); 449 freeze_ioctl(fd, SCIOCFREEZETHAW, &seconds); 450 if (verbose) { 451 putchar('\007'); 452 fflush(stdout); 453 } 454 455 freeze_ioctl(fd, SCIOCWAITTHAW, 0); 456 if (verbose) { 457 putchar('\007'); 458 fflush(stdout); 459 } 460 } 461 } 462 #endif 463 464 void mode_sense(int fd, u_char *data, int len, int pc, int page) 465 { 466 scsireq_t *scsireq; 467 468 bzero(data, len); 469 470 scsireq = scsireq_new(); 471 472 if (scsireq_enter(fd, scsireq_build(scsireq, 473 len, data, SCCMD_READ, 474 "1A 0 v:2 {Page Control} v:6 {Page Code} 0 v:i1 {Allocation Length} 0", 475 pc, page, len)) == -1) /* Mode sense */ 476 { 477 scsi_debug(stderr, -1, scsireq); 478 exit(errno); 479 } 480 481 if (SCSIREQ_ERROR(scsireq)) 482 { 483 scsi_debug(stderr, 0, scsireq); 484 exit(1); 485 } 486 487 free(scsireq); 488 } 489 490 void mode_select(int fd, u_char *data, int len, int perm) 491 { 492 scsireq_t *scsireq; 493 494 scsireq = scsireq_new(); 495 496 if (scsireq_enter(fd, scsireq_build(scsireq, 497 len, data, SCCMD_WRITE, 498 "15 0:7 v:1 {SP} 0 0 v:i1 {Allocation Length} 0", perm, len)) == -1) /* Mode select */ 499 { 500 scsi_debug(stderr, -1, scsireq); 501 exit(errno); 502 } 503 504 if (SCSIREQ_ERROR(scsireq)) 505 { 506 scsi_debug(stderr, 0, scsireq); 507 exit(1); 508 } 509 510 free(scsireq); 511 } 512 513 514 #define START_ENTRY '{' 515 #define END_ENTRY '}' 516 517 static void 518 skipwhite(FILE *f) 519 { 520 int c; 521 522 skip_again: 523 524 while (isspace(c = getc(f))) 525 ; 526 527 if (c == '#') { 528 while ((c = getc(f)) != '\n' && c != EOF) 529 ; 530 goto skip_again; 531 } 532 533 ungetc(c, f); 534 } 535 536 /* mode_lookup: Lookup a format description for a given page. 537 */ 538 char *mode_db = "/usr/share/misc/scsi_modes"; 539 static char *mode_lookup(int page) 540 { 541 char *new_db; 542 FILE *modes; 543 int match, next, found, c; 544 static char fmt[1024]; /* XXX This should be with strealloc */ 545 int page_desc; 546 new_db = getenv("SCSI_MODES"); 547 548 if (new_db) 549 mode_db = new_db; 550 551 modes = fopen(mode_db, "r"); 552 if (modes == NULL) 553 return 0; 554 555 next = 0; 556 found = 0; 557 558 while (!found) { 559 560 skipwhite(modes); 561 562 if (fscanf(modes, "%i", &page_desc) != 1) 563 break; 564 565 if (page_desc == page) 566 found = 1; 567 568 skipwhite(modes); 569 if (getc(modes) != START_ENTRY) { 570 fprintf(stderr, "Expected %c.\n", START_ENTRY); 571 exit(1); 572 } 573 574 match = 1; 575 while (match != 0) { 576 c = getc(modes); 577 if (c == EOF) 578 fprintf(stderr, "Expected %c.\n", END_ENTRY); 579 580 if (c == START_ENTRY) { 581 match++; 582 } 583 if (c == END_ENTRY) { 584 match--; 585 if (match == 0) 586 break; 587 } 588 if (found && c != '\n') { 589 if (next >= sizeof(fmt)) { 590 fprintf(stderr, 591 "Stupid program: Buffer overflow.\n"); 592 exit(ENOMEM); 593 } 594 595 fmt[next++] = (u_char)c; 596 } 597 } 598 } 599 fclose(modes); 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 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 strlcpy(edit_name, "/var/tmp/scXXXXXXXX", sizeof edit_name); 655 if ((fd = mkstemp(edit_name)) == -1) 656 err(errno, "mkstemp failed"); 657 if ( (edit_file = fdopen(fd, "w+")) == 0) 658 err(errno, "fdopen failed"); 659 edit_opened = 1; 660 661 atexit(edit_done); 662 } 663 664 static void 665 edit_check(void *hook, int letter, void *arg, int count, char *name) 666 { 667 if (letter != 'i' && letter != 'b') { 668 fprintf(stderr, "Can't edit format %c.\n", letter); 669 exit(1); 670 } 671 672 if (editind >= sizeof(editinfo) / sizeof(editinfo[0])) { 673 fprintf(stderr, "edit table overflow\n"); 674 exit(ENOMEM); 675 } 676 editinfo[editind].can_edit = ((long)arg != 0); 677 editind++; 678 } 679 680 static void 681 edit_defaults(void *hook, int letter, void *arg, int count, char *name) 682 { 683 if (letter != 'i' && letter != 'b') { 684 fprintf(stderr, "Can't edit format %c.\n", letter); 685 exit(1); 686 } 687 688 editinfo[editind].default_value = ((long)arg); 689 editind++; 690 } 691 692 static void 693 edit_report(void *hook, int letter, void *arg, int count, char *name) 694 { 695 if (editinfo[editind].can_edit) { 696 if (letter != 'i' && letter != 'b') { 697 fprintf(stderr, "Can't report format %c.\n", letter); 698 exit(1); 699 } 700 701 fprintf(edit_file, "%s: %ld\n", name, (long)arg); 702 } 703 704 editind++; 705 } 706 707 static int 708 edit_get(void *hook, char *name) 709 { 710 int arg = editinfo[editind].default_value; 711 712 if (editinfo[editind].can_edit) { 713 char line[80]; 714 if (fgets(line, sizeof(line), edit_file) == 0) 715 err(errno, "fgets"); 716 717 line[strlen(line) - 1] = 0; 718 719 if (strncmp(name, line, strlen(name)) != 0) { 720 fprintf(stderr, "Expected \"%s\" and read \"%s\"\n", 721 name, line); 722 exit(1); 723 } 724 725 arg = strtoul(line + strlen(name) + 2, 0, 0); 726 } 727 728 editind++; 729 return arg; 730 } 731 732 static void 733 edit_edit(void) 734 { 735 char *system_line; 736 char *editor = getenv("EDITOR"); 737 if (!editor) 738 editor = _PATH_VI; 739 740 fclose(edit_file); 741 742 if (asprintf(&system_line, "%s %s", editor, edit_name) == -1) 743 err(1, NULL); 744 745 system(system_line); 746 free(system_line); 747 748 if ( (edit_file = fopen(edit_name, "r")) == 0) 749 err(errno, "open %s", edit_name); 750 } 751 752 static void 753 mode_edit(int fd, int page, int edit, int argc, char *argv[]) 754 { 755 int i; 756 u_char data[255]; 757 u_char *mode_pars; 758 struct mode_header 759 { 760 u_char mdl; /* Mode data length */ 761 u_char medium_type; 762 u_char dev_spec_par; 763 u_char bdl; /* Block descriptor length */ 764 }; 765 766 struct mode_page_header 767 { 768 u_char page_code; 769 u_char page_length; 770 }; 771 772 struct mode_header *mh; 773 struct mode_page_header *mph; 774 775 char *fmt = mode_lookup(page); 776 if (!fmt && verbose) { 777 fprintf(stderr, 778 "No mode data base entry in \"%s\" for page %d; binary %s only.\n", 779 mode_db, page, (edit ? "edit" : "display")); 780 } 781 782 if (edit) { 783 if (!fmt) { 784 fprintf(stderr, "Sorry: can't edit without a format.\n"); 785 exit(1); 786 } 787 788 if (pagectl != 0 && pagectl != 3) { 789 fprintf(stderr, 790 "It only makes sense to edit page 0 (current) or page 3 (saved values)\n"); 791 exit(1); 792 } 793 794 verbose = 1; 795 796 mode_sense(fd, data, sizeof(data), 1, page); 797 798 mh = (struct mode_header *)data; 799 mph = (struct mode_page_header *) 800 (((char *)mh) + sizeof(*mh) + mh->bdl); 801 802 mode_pars = (char *)mph + sizeof(*mph); 803 804 edit_init(); 805 scsireq_buff_decode_visit(mode_pars, mh->mdl, 806 fmt, edit_check, 0); 807 808 mode_sense(fd, data, sizeof(data), 0, page); 809 810 edit_rewind(); 811 scsireq_buff_decode_visit(mode_pars, mh->mdl, 812 fmt, edit_defaults, 0); 813 814 edit_rewind(); 815 scsireq_buff_decode_visit(mode_pars, mh->mdl, 816 fmt, edit_report, 0); 817 818 edit_edit(); 819 820 edit_rewind(); 821 scsireq_buff_encode_visit(mode_pars, mh->mdl, 822 fmt, edit_get, 0); 823 824 /* Eliminate block descriptors: 825 */ 826 bcopy((char *)mph, ((char *)mh) + sizeof(*mh), 827 sizeof(*mph) + mph->page_length); 828 829 mh->bdl = 0; 830 mph = (struct mode_page_header *) (((char *)mh) + sizeof(*mh)); 831 mode_pars = ((char *)mph) + 2; 832 833 #if 0 834 /* Turn this on to see what you're sending to the 835 * device: 836 */ 837 edit_rewind(); 838 scsireq_buff_decode_visit(mode_pars, 839 mh->mdl, fmt, arg_put, 0); 840 #endif 841 842 edit_done(); 843 844 /* Make it permanent if pageselect is three. 845 */ 846 847 mph->page_code &= ~0xC0; /* Clear PS and RESERVED */ 848 mh->mdl = 0; /* Reserved for mode select */ 849 850 mode_select(fd, (char *)mh, 851 sizeof(*mh) + mh->bdl + sizeof(*mph) + mph->page_length, 852 (pagectl == 3)); 853 854 exit(0); 855 } 856 857 mode_sense(fd, data, sizeof(data), pagectl, page); 858 859 /* Skip over the block descriptors. 860 */ 861 mh = (struct mode_header *)data; 862 mph = (struct mode_page_header *)(((char *)mh) + sizeof(*mh) + mh->bdl); 863 mode_pars = (char *)mph + sizeof(*mph); 864 865 if (!fmt) { 866 for (i = 0; i < mh->mdl; i++) { 867 printf("%02x%c",mode_pars[i], 868 (((i + 1) % 8) == 0) ? '\n' : ' '); 869 } 870 putc('\n', stdout); 871 } else { 872 verbose = 1; 873 scsireq_buff_decode_visit(mode_pars, 874 mh->mdl, fmt, arg_put, 0); 875 } 876 } 877 878 #ifdef SCIOCADDR 879 /* do_probe_all: Loop over all SCSI IDs and see if something is 880 * there. This only does BUS 0 LUN 0. 881 */ 882 void do_probe_all(void) 883 { 884 scsireq_t *scsireq; 885 886 char vendor_id[8 + 1], product_id[16 + 1], revision[4 + 1]; 887 int id; 888 u_char *inq_buf = malloc(96); 889 struct scsi_addr addr; 890 891 scsireq = scsireq_build(scsireq_new(), 892 96, inq_buf, SCCMD_READ, 893 "12 0 0 0 v 0", 96); 894 895 addr.scbus = (bus == -1) ? 0 : bus; 896 addr.lun = lun; 897 898 if (addr.scbus || addr.lun) 899 { 900 printf("For bus %d lun %d:\n", addr.scbus, addr.lun); 901 } 902 903 for (id = 0; id < 8; id++) 904 { 905 addr.target = id; 906 907 printf("%d: ", id); 908 if (ioctl(fd, SCIOCADDR, &addr) == -1) { 909 if (errno == ENXIO) 910 { 911 errno = 0; 912 printf("nothing.\n"); 913 } 914 else 915 printf("SCIOCADDR: %s\n", strerror(errno)); 916 917 continue; 918 } 919 920 if (scsireq_enter(fd, scsireq) == -1) { 921 printf("scsireq_enter: %s\n", strerror(errno)); 922 continue; 923 } 924 925 vendor_id[sizeof(vendor_id) - 1] = 0; 926 product_id[sizeof(product_id) - 1] = 0; 927 revision[sizeof(revision) - 1] = 0; 928 929 scsireq_decode(scsireq, "s8 c8 c16 c4", 930 vendor_id, product_id, revision); 931 932 printf("%s %s %s\n", vendor_id, product_id, revision); 933 } 934 } 935 #endif 936 937 int 938 main(int argc, char **argv) 939 { 940 struct scsi_addr scaddr; 941 942 procargs(&argc,&argv); 943 944 /* XXX This has grown to the point that it should be cleaned up. 945 */ 946 #ifdef SCIOCFREEZE 947 if (freeze) { 948 do_freeze(freeze); 949 } else 950 #endif 951 #ifdef SCIOCADDR 952 if (probe_all) 953 do_probe_all(); 954 else 955 #endif 956 if(reprobe) { 957 scaddr.scbus = bus; 958 scaddr.target = targ; 959 scaddr.lun = lun; 960 961 if (ioctl(fd,SCIOCREPROBE,&scaddr) == -1) 962 warn("SCIOCREPROBE"); 963 } else if(debugflag) { 964 if (ioctl(fd,SCIOCDEBUG,&debuglevel) == -1) 965 err(errno, "SCIODEBUG"); 966 } else if (commandflag) { 967 char *fmt; 968 969 if (argc < 1) { 970 fprintf(stderr, "Need the command format string.\n"); 971 usage(); 972 } 973 974 975 fmt = argv[0]; 976 977 argc -= 1; 978 argv += 1; 979 980 do_cmd(fd, fmt, argc, argv); 981 } else if (modeflag) 982 mode_edit(fd, modepage, editflag, argc, argv); 983 984 exit(0); 985 } 986