1 /* $OpenBSD: scsi.c,v 1.18 2005/04/11 22:02:06 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 #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 { 348 data_fmt = cget(&h, 0); 349 350 scsireq->databuf = malloc(count); 351 352 if (data_phase == out) 353 { 354 if (strcmp(data_fmt, "-") == 0) /* Read data from stdin */ 355 { 356 bp = (char *)scsireq->databuf; 357 while (count > 0 && (amount = read(0, bp, count)) > 0) 358 { 359 count -= amount; 360 bp += amount; 361 } 362 if (amount == -1) 363 err(errno, "read"); 364 else if (amount == 0) 365 { 366 /* early EOF */ 367 fprintf(stderr, 368 "Warning: only read %lu bytes out of %lu.\n", 369 scsireq->datalen - (u_long)count, 370 scsireq->datalen); 371 scsireq->datalen -= (u_long)count; 372 } 373 } 374 else 375 { 376 bzero(scsireq->databuf, count); 377 scsireq_encode_visit(scsireq, data_fmt, iget, (void *)&h); 378 } 379 } 380 } 381 } 382 383 384 scsireq->timeout = seconds * 1000; 385 386 if (scsireq_enter(fd, scsireq) == -1) 387 { 388 scsi_debug(stderr, -1, scsireq); 389 exit(errno); 390 } 391 392 if (SCSIREQ_ERROR(scsireq)) 393 scsi_debug(stderr, 0, scsireq); 394 395 if (count && data_phase == in) 396 { 397 if (strcmp(data_fmt, "-") == 0) /* stdout */ 398 { 399 bp = (char *)scsireq->databuf; 400 while (count > 0 && (amount = write(STDOUT_FILENO, bp, count)) > 0) 401 { 402 count -= amount; 403 bp += amount; 404 } 405 if (amount < 0) 406 err(errno, "write"); 407 else if (amount == 0) 408 fprintf(stderr, "Warning: wrote only %lu bytes out of %lu.\n", 409 scsireq->datalen - count, 410 scsireq->datalen); 411 412 } 413 else 414 { 415 scsireq_decode_visit(scsireq, data_fmt, arg_put, 0); 416 putchar('\n'); 417 } 418 } 419 } 420 421 #ifdef SCIOCFREEZE 422 static void 423 freeze_ioctl(int fd, int op, void *data) 424 { 425 if (ioctl(fd, SCIOCFREEZE, 0) == -1) { 426 if (errno == ENODEV) { 427 fprintf(stderr, 428 "Your kernel must be configured with option SCSI_FREEZE.\n"); 429 exit(errno); 430 } else 431 err(errno, "SCIOCFREEZE"); 432 } 433 } 434 435 /* do_freeze: Freeze the bus for a given number of seconds. 436 */ 437 static void do_freeze(int seconds) 438 { 439 if (seconds == -1) { 440 printf("Hit return to thaw: "); 441 fflush(stdout); 442 sync(); 443 444 freeze_ioctl(fd, SCIOCFREEZE, 0); 445 446 (void)getchar(); 447 448 freeze_ioctl(fd, SCIOCTHAW, 0); 449 } 450 else { 451 sync(); 452 freeze_ioctl(fd, SCIOCFREEZETHAW, &seconds); 453 if (verbose) { 454 putchar('\007'); 455 fflush(stdout); 456 } 457 458 freeze_ioctl(fd, SCIOCWAITTHAW, 0); 459 if (verbose) { 460 putchar('\007'); 461 fflush(stdout); 462 } 463 } 464 } 465 #endif 466 467 void mode_sense(int fd, u_char *data, int len, int pc, int page) 468 { 469 scsireq_t *scsireq; 470 471 bzero(data, len); 472 473 scsireq = scsireq_new(); 474 475 if (scsireq_enter(fd, scsireq_build(scsireq, 476 len, data, SCCMD_READ, 477 "1A 0 v:2 {Page Control} v:6 {Page Code} 0 v:i1 {Allocation Length} 0", 478 pc, page, len)) == -1) /* Mode sense */ 479 { 480 scsi_debug(stderr, -1, scsireq); 481 exit(errno); 482 } 483 484 if (SCSIREQ_ERROR(scsireq)) 485 { 486 scsi_debug(stderr, 0, scsireq); 487 exit(1); 488 } 489 490 free(scsireq); 491 } 492 493 void mode_select(int fd, u_char *data, int len, int perm) 494 { 495 scsireq_t *scsireq; 496 497 scsireq = scsireq_new(); 498 499 if (scsireq_enter(fd, scsireq_build(scsireq, 500 len, data, SCCMD_WRITE, 501 "15 0:7 v:1 {SP} 0 0 v:i1 {Allocation Length} 0", perm, len)) == -1) /* Mode select */ 502 { 503 scsi_debug(stderr, -1, scsireq); 504 exit(errno); 505 } 506 507 if (SCSIREQ_ERROR(scsireq)) 508 { 509 scsi_debug(stderr, 0, scsireq); 510 exit(1); 511 } 512 513 free(scsireq); 514 } 515 516 517 #define START_ENTRY '{' 518 #define END_ENTRY '}' 519 520 static void 521 skipwhite(FILE *f) 522 { 523 int c; 524 525 skip_again: 526 527 while (isspace(c = getc(f))) 528 ; 529 530 if (c == '#') { 531 while ((c = getc(f)) != '\n' && c != EOF) 532 ; 533 goto skip_again; 534 } 535 536 ungetc(c, f); 537 } 538 539 /* mode_lookup: Lookup a format description for a given page. 540 */ 541 char *mode_db = "/usr/share/misc/scsi_modes"; 542 static char *mode_lookup(int page) 543 { 544 char *new_db; 545 FILE *modes; 546 int match, next, found, c; 547 static char fmt[1024]; /* XXX This should be with strealloc */ 548 int page_desc; 549 new_db = getenv("SCSI_MODES"); 550 551 if (new_db) 552 mode_db = new_db; 553 554 modes = fopen(mode_db, "r"); 555 if (modes == 0) 556 return 0; 557 558 next = 0; 559 found = 0; 560 561 while (!found) { 562 563 skipwhite(modes); 564 565 if (fscanf(modes, "%i", &page_desc) != 1) 566 break; 567 568 if (page_desc == page) 569 found = 1; 570 571 skipwhite(modes); 572 if (getc(modes) != START_ENTRY) { 573 fprintf(stderr, "Expected %c.\n", START_ENTRY); 574 exit(1); 575 } 576 577 match = 1; 578 while (match != 0) { 579 c = getc(modes); 580 if (c == EOF) 581 fprintf(stderr, "Expected %c.\n", END_ENTRY); 582 583 if (c == START_ENTRY) { 584 match++; 585 } 586 if (c == END_ENTRY) { 587 match--; 588 if (match == 0) 589 break; 590 } 591 if (found && c != '\n') { 592 if (next >= sizeof(fmt)) { 593 fprintf(stderr, "Stupid program: Buffer overflow.\n"); 594 exit(ENOMEM); 595 } 596 597 fmt[next++] = (u_char)c; 598 } 599 } 600 } 601 fmt[next] = 0; 602 603 return (found) ? fmt : 0; 604 } 605 606 /* -------- edit: Mode Select Editor --------- 607 */ 608 struct editinfo 609 { 610 long can_edit; 611 long default_value; 612 } editinfo[64]; /* XXX Bogus fixed size */ 613 614 static int editind; 615 volatile int edit_opened; 616 static FILE *edit_file; 617 static char edit_name[L_tmpnam]; 618 619 static void 620 edit_rewind(void) 621 { 622 editind = 0; 623 } 624 625 static void 626 edit_done(void) 627 { 628 int opened; 629 630 sigset_t all, prev; 631 sigfillset(&all); 632 633 (void)sigprocmask(SIG_SETMASK, &all, &prev); 634 635 opened = (int)edit_opened; 636 edit_opened = 0; 637 638 (void)sigprocmask(SIG_SETMASK, &prev, 0); 639 640 if (opened) 641 { 642 if (fclose(edit_file)) 643 perror(edit_name); 644 if (unlink(edit_name)) 645 perror(edit_name); 646 } 647 } 648 649 static void 650 edit_init(void) 651 { 652 int fd; 653 654 edit_rewind(); 655 strlcpy(edit_name, "/var/tmp/scXXXXXXXX", sizeof edit_name); 656 if ((fd = mkstemp(edit_name)) == -1) 657 err(errno, "mkstemp failed"); 658 if ( (edit_file = fdopen(fd, "w+")) == 0) 659 err(errno, "fdopen failed"); 660 edit_opened = 1; 661 662 atexit(edit_done); 663 } 664 665 static void 666 edit_check(void *hook, int letter, void *arg, int count, char *name) 667 { 668 if (letter != 'i' && letter != 'b') { 669 fprintf(stderr, "Can't edit format %c.\n", letter); 670 exit(1); 671 } 672 673 if (editind >= sizeof(editinfo) / sizeof(editinfo[0])) { 674 fprintf(stderr, "edit table overflow\n"); 675 exit(ENOMEM); 676 } 677 editinfo[editind].can_edit = ((long)arg != 0); 678 editind++; 679 } 680 681 static void 682 edit_defaults(void *hook, int letter, void *arg, int count, char *name) 683 { 684 if (letter != 'i' && letter != 'b') { 685 fprintf(stderr, "Can't edit format %c.\n", letter); 686 exit(1); 687 } 688 689 editinfo[editind].default_value = ((long)arg); 690 editind++; 691 } 692 693 static void 694 edit_report(void *hook, int letter, void *arg, int count, char *name) 695 { 696 if (editinfo[editind].can_edit) { 697 if (letter != 'i' && letter != 'b') { 698 fprintf(stderr, "Can't report format %c.\n", letter); 699 exit(1); 700 } 701 702 fprintf(edit_file, "%s: %ld\n", name, (long)arg); 703 } 704 705 editind++; 706 } 707 708 static int 709 edit_get(void *hook, char *name) 710 { 711 int arg = editinfo[editind].default_value; 712 713 if (editinfo[editind].can_edit) { 714 char line[80]; 715 if (fgets(line, sizeof(line), edit_file) == 0) 716 err(errno, "fgets"); 717 718 line[strlen(line) - 1] = 0; 719 720 if (strncmp(name, line, strlen(name)) != 0) { 721 fprintf(stderr, "Expected \"%s\" and read \"%s\"\n", 722 name, line); 723 exit(1); 724 } 725 726 arg = strtoul(line + strlen(name) + 2, 0, 0); 727 } 728 729 editind++; 730 return arg; 731 } 732 733 static void 734 edit_edit(void) 735 { 736 char *system_line; 737 char *editor = getenv("EDITOR"); 738 if (!editor) 739 editor = _PATH_VI; 740 741 fclose(edit_file); 742 743 if (asprintf(&system_line, "%s %s", editor, edit_name) == -1) 744 err(1, NULL); 745 746 system(system_line); 747 free(system_line); 748 749 if ( (edit_file = fopen(edit_name, "r")) == 0) 750 err(errno, "open %s", edit_name); 751 } 752 753 static void 754 mode_edit(int fd, int page, int edit, int argc, char *argv[]) 755 { 756 int i; 757 u_char data[255]; 758 u_char *mode_pars; 759 struct mode_header 760 { 761 u_char mdl; /* Mode data length */ 762 u_char medium_type; 763 u_char dev_spec_par; 764 u_char bdl; /* Block descriptor length */ 765 }; 766 767 struct mode_page_header 768 { 769 u_char page_code; 770 u_char page_length; 771 }; 772 773 struct mode_header *mh; 774 struct mode_page_header *mph; 775 776 char *fmt = mode_lookup(page); 777 if (!fmt && verbose) { 778 fprintf(stderr, 779 "No mode data base entry in \"%s\" for page %d; binary %s only.\n", 780 mode_db, page, (edit ? "edit" : "display")); 781 } 782 783 if (edit) { 784 if (!fmt) { 785 fprintf(stderr, "Sorry: can't edit without a format.\n"); 786 exit(1); 787 } 788 789 if (pagectl != 0 && pagectl != 3) { 790 fprintf(stderr, 791 "It only makes sense to edit page 0 (current) or page 3 (saved values)\n"); 792 exit(1); 793 } 794 795 verbose = 1; 796 797 mode_sense(fd, data, sizeof(data), 1, page); 798 799 mh = (struct mode_header *)data; 800 mph = (struct mode_page_header *) 801 (((char *)mh) + sizeof(*mh) + mh->bdl); 802 803 mode_pars = (char *)mph + sizeof(*mph); 804 805 edit_init(); 806 scsireq_buff_decode_visit(mode_pars, mh->mdl, 807 fmt, edit_check, 0); 808 809 mode_sense(fd, data, sizeof(data), 0, page); 810 811 edit_rewind(); 812 scsireq_buff_decode_visit(mode_pars, mh->mdl, 813 fmt, edit_defaults, 0); 814 815 edit_rewind(); 816 scsireq_buff_decode_visit(mode_pars, mh->mdl, 817 fmt, edit_report, 0); 818 819 edit_edit(); 820 821 edit_rewind(); 822 scsireq_buff_encode_visit(mode_pars, mh->mdl, 823 fmt, edit_get, 0); 824 825 /* Eliminate block descriptors: 826 */ 827 bcopy((char *)mph, ((char *)mh) + sizeof(*mh), 828 sizeof(*mph) + mph->page_length); 829 830 mh->bdl = 0; 831 mph = (struct mode_page_header *) (((char *)mh) + sizeof(*mh)); 832 mode_pars = ((char *)mph) + 2; 833 834 #if 0 835 /* Turn this on to see what you're sending to the 836 * device: 837 */ 838 edit_rewind(); 839 scsireq_buff_decode_visit(mode_pars, 840 mh->mdl, fmt, arg_put, 0); 841 #endif 842 843 edit_done(); 844 845 /* Make it permanent if pageselect is three. 846 */ 847 848 mph->page_code &= ~0xC0; /* Clear PS and RESERVED */ 849 mh->mdl = 0; /* Reserved for mode select */ 850 851 mode_select(fd, (char *)mh, 852 sizeof(*mh) + mh->bdl + sizeof(*mph) + mph->page_length, 853 (pagectl == 3)); 854 855 exit(0); 856 } 857 858 mode_sense(fd, data, sizeof(data), pagectl, page); 859 860 /* Skip over the block descriptors. 861 */ 862 mh = (struct mode_header *)data; 863 mph = (struct mode_page_header *)(((char *)mh) + sizeof(*mh) + mh->bdl); 864 mode_pars = (char *)mph + sizeof(*mph); 865 866 if (!fmt) { 867 for (i = 0; i < mh->mdl; i++) { 868 printf("%02x%c",mode_pars[i], 869 (((i + 1) % 8) == 0) ? '\n' : ' '); 870 } 871 putc('\n', stdout); 872 } else { 873 verbose = 1; 874 scsireq_buff_decode_visit(mode_pars, 875 mh->mdl, fmt, arg_put, 0); 876 } 877 } 878 879 #ifdef SCIOCADDR 880 /* do_probe_all: Loop over all SCSI IDs and see if something is 881 * there. This only does BUS 0 LUN 0. 882 */ 883 void do_probe_all(void) 884 { 885 scsireq_t *scsireq; 886 887 char vendor_id[8 + 1], product_id[16 + 1], revision[4 + 1]; 888 int id; 889 u_char *inq_buf = malloc(96); 890 struct scsi_addr addr; 891 892 scsireq = scsireq_build(scsireq_new(), 893 96, inq_buf, SCCMD_READ, 894 "12 0 0 0 v 0", 96); 895 896 addr.scbus = (bus == -1) ? 0 : bus; 897 addr.lun = lun; 898 899 if (addr.scbus || addr.lun) 900 { 901 printf("For bus %d lun %d:\n", addr.scbus, addr.lun); 902 } 903 904 for (id = 0; id < 8; id++) 905 { 906 addr.target = id; 907 908 printf("%d: ", id); 909 if (ioctl(fd, SCIOCADDR, &addr) == -1) { 910 if (errno == ENXIO) 911 { 912 errno = 0; 913 printf("nothing.\n"); 914 } 915 else 916 printf("SCIOCADDR: %s\n", strerror(errno)); 917 918 continue; 919 } 920 921 if (scsireq_enter(fd, scsireq) == -1) { 922 printf("scsireq_enter: %s\n", strerror(errno)); 923 continue; 924 } 925 926 vendor_id[sizeof(vendor_id) - 1] = 0; 927 product_id[sizeof(product_id) - 1] = 0; 928 revision[sizeof(revision) - 1] = 0; 929 930 scsireq_decode(scsireq, "s8 c8 c16 c4", 931 vendor_id, product_id, revision); 932 933 printf("%s %s %s\n", vendor_id, product_id, revision); 934 } 935 } 936 #endif 937 938 int 939 main(int argc, char **argv) 940 { 941 struct scsi_addr scaddr; 942 943 procargs(&argc,&argv); 944 945 /* XXX This has grown to the point that it should be cleaned up. 946 */ 947 #ifdef SCIOCFREEZE 948 if (freeze) { 949 do_freeze(freeze); 950 } else 951 #endif 952 #ifdef SCIOCADDR 953 if (probe_all) 954 do_probe_all(); 955 else 956 #endif 957 if(reprobe) { 958 scaddr.scbus = bus; 959 scaddr.target = targ; 960 scaddr.lun = lun; 961 962 if (ioctl(fd,SCIOCREPROBE,&scaddr) == -1) 963 warn("SCIOCREPROBE"); 964 } else if(debugflag) { 965 if (ioctl(fd,SCIOCDEBUG,&debuglevel) == -1) 966 err(errno, "SCIODEBUG"); 967 } else if (commandflag) { 968 char *fmt; 969 970 if (argc < 1) { 971 fprintf(stderr, "Need the command format string.\n"); 972 usage(); 973 } 974 975 976 fmt = argv[0]; 977 978 argc -= 1; 979 argv += 1; 980 981 do_cmd(fd, fmt, argc, argv); 982 } else if (modeflag) 983 mode_edit(fd, modepage, editflag, argc, argv); 984 985 exit(0); 986 } 987