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