1 /* $NetBSD: scsictl.c,v 1.24 2004/06/01 02:40:00 fair Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * scsictl(8) - a program to manipulate SCSI devices and busses. 42 */ 43 #include <sys/cdefs.h> 44 45 #ifndef lint 46 __RCSID("$NetBSD: scsictl.c,v 1.24 2004/06/01 02:40:00 fair Exp $"); 47 #endif 48 49 50 #include <sys/param.h> 51 #include <sys/ioctl.h> 52 #include <sys/scsiio.h> 53 #include <err.h> 54 #include <errno.h> 55 #include <fcntl.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <unistd.h> 60 #include <util.h> 61 62 #include <dev/scsipi/scsipi_all.h> 63 #include <dev/scsipi/scsi_all.h> 64 #include <dev/scsipi/scsi_disk.h> 65 #include <dev/scsipi/scsipiconf.h> 66 67 #include "extern.h" 68 69 struct command { 70 const char *cmd_name; 71 const char *arg_names; 72 void (*cmd_func) __P((int, char *[])); 73 }; 74 75 int main __P((int, char *[])); 76 void usage __P((void)); 77 78 int fd; /* file descriptor for device */ 79 const char *dvname; /* device name */ 80 char dvname_store[MAXPATHLEN]; /* for opendisk(3) */ 81 const char *cmdname; /* command user issued */ 82 const char *argnames; /* helpstring: expected arguments */ 83 struct scsi_addr dvaddr; /* SCSI device's address */ 84 85 void device_format __P((int, char *[])); 86 void device_identify __P((int, char *[])); 87 void device_reassign __P((int, char *[])); 88 void device_release __P((int, char *[])); 89 void device_reserve __P((int, char *[])); 90 void device_reset __P((int, char *[])); 91 void device_debug __P((int, char *[])); 92 void device_prevent __P((int, char *[])); 93 void device_allow __P((int, char *[])); 94 void device_start __P((int, char *[])); 95 void device_stop __P((int, char *[])); 96 void device_tur __P((int, char *[])); 97 void device_getcache __P((int, char *[])); 98 void device_setcache __P((int, char *[])); 99 void device_flushcache __P((int, char *[])); 100 101 struct command device_commands[] = { 102 { "format", "[blocksize [immediate]]", device_format }, 103 { "identify", "", device_identify }, 104 { "reassign", "blkno [blkno [...]]", device_reassign }, 105 { "release", "", device_release }, 106 { "reserve", "", device_reserve }, 107 { "reset", "", device_reset }, 108 { "debug", "level", device_debug }, 109 { "prevent", "", device_prevent }, 110 { "allow", "", device_allow }, 111 { "start", "", device_start }, 112 { "stop", "", device_stop }, 113 { "tur", "", device_tur }, 114 { "getcache", "", device_getcache }, 115 { "setcache", "none|r|w|rw [save]", device_setcache }, 116 { "flushcache", "", device_flushcache }, 117 { NULL, NULL, NULL }, 118 }; 119 120 void bus_reset __P((int, char *[])); 121 void bus_scan __P((int, char *[])); 122 void bus_detach __P((int, char *[])); 123 124 struct command bus_commands[] = { 125 { "reset", "", bus_reset }, 126 { "scan", "target lun", bus_scan }, 127 { "detach", "target lun", bus_detach }, 128 { NULL, NULL, NULL }, 129 }; 130 131 int 132 main(argc, argv) 133 int argc; 134 char *argv[]; 135 { 136 struct command *commands; 137 int i; 138 139 /* Must have at least: device command */ 140 if (argc < 3) 141 usage(); 142 143 /* Skip program name, get and skip device name and command. */ 144 dvname = argv[1]; 145 cmdname = argv[2]; 146 argv += 3; 147 argc -= 3; 148 149 /* 150 * Open the device and determine if it's a scsibus or an actual 151 * device. Devices respond to the SCIOCIDENTIFY ioctl. 152 */ 153 fd = opendisk(dvname, O_RDWR, dvname_store, sizeof(dvname_store), 0); 154 if (fd == -1) { 155 if (errno == ENOENT) { 156 /* 157 * Device doesn't exist. Probably trying to open 158 * a device which doesn't use disk semantics for 159 * device name. Try again, specifying "cooked", 160 * which leaves off the "r" in front of the device's 161 * name. 162 */ 163 fd = opendisk(dvname, O_RDWR, dvname_store, 164 sizeof(dvname_store), 1); 165 if (fd == -1) 166 err(1, "%s", dvname); 167 } else 168 err(1, "%s", dvname); 169 } 170 171 /* 172 * Point the dvname at the actual device name that opendisk() opened. 173 */ 174 dvname = dvname_store; 175 176 if (ioctl(fd, SCIOCIDENTIFY, &dvaddr) < 0) 177 commands = bus_commands; 178 else 179 commands = device_commands; 180 181 /* Look up and call the command. */ 182 for (i = 0; commands[i].cmd_name != NULL; i++) 183 if (strcmp(cmdname, commands[i].cmd_name) == 0) 184 break; 185 if (commands[i].cmd_name == NULL) 186 errx(1, "unknown %s command: %s", 187 commands == bus_commands ? "bus" : "device", cmdname); 188 189 argnames = commands[i].arg_names; 190 191 (*commands[i].cmd_func)(argc, argv); 192 exit(0); 193 } 194 195 void 196 usage() 197 { 198 int i; 199 200 fprintf(stderr, "usage: %s device command [arg [...]]\n", 201 getprogname()); 202 203 fprintf(stderr, " Commands pertaining to scsi devices:\n"); 204 for (i=0; device_commands[i].cmd_name != NULL; i++) 205 fprintf(stderr, "\t%s %s\n", device_commands[i].cmd_name, 206 device_commands[i].arg_names); 207 fprintf(stderr, " Commands pertaining to scsi busses:\n"); 208 for (i=0; bus_commands[i].cmd_name != NULL; i++) 209 fprintf(stderr, "\t%s %s\n", bus_commands[i].cmd_name, 210 bus_commands[i].arg_names); 211 fprintf(stderr, " Use `any' or `all' to wildcard target or lun\n"); 212 213 exit(1); 214 } 215 216 /* 217 * DEVICE COMMANDS 218 */ 219 220 /* 221 * device_format: 222 * 223 * Format a direct access device. 224 */ 225 void 226 device_format(argc, argv) 227 int argc; 228 char *argv[]; 229 { 230 u_int32_t blksize; 231 int i, j, immediate; 232 #define PC (65536/10) 233 static int complete[] = { 234 PC*1, PC*2, PC*3, PC*4, PC*5, PC*6, PC*7, PC*8, PC*9, 65536 235 }; 236 char *cp, buffer[64]; 237 struct scsipi_sense_data sense; 238 struct scsi_format_unit cmd; 239 struct { 240 struct scsi_format_unit_defect_list_header header; 241 /* optional initialization pattern */ 242 /* optional defect list */ 243 } dfl; 244 struct { 245 struct scsipi_mode_header header; 246 struct scsi_blk_desc blk_desc; 247 struct page_disk_format format_page; 248 } mode_page; 249 struct { 250 struct scsipi_mode_header header; 251 struct scsi_blk_desc blk_desc; 252 } data_select; 253 254 255 /* Blocksize is an optional argument. */ 256 if (argc > 2) 257 usage(); 258 259 /* 260 * Loop doing Request Sense to clear any pending Unit Attention. 261 * 262 * Multiple conditions may exist on the drive which are returned 263 * in priority order. 264 */ 265 for (i = 0; i < 8; i++) { 266 scsi_request_sense(fd, &sense, sizeof (sense)); 267 if ((j = sense.flags & SSD_KEY) == SKEY_NO_SENSE) 268 break; 269 } 270 /* 271 * Make sure we cleared any pending Unit Attention 272 */ 273 if (j != SKEY_NO_SENSE) { 274 cp = scsi_decode_sense((const unsigned char *) &sense, 2, 275 buffer, sizeof (buffer)); 276 errx(1, "failed to clean Unit Attention: %s", cp); 277 } 278 279 /* 280 * Get the DISK FORMAT mode page. SCSI-2 recommends specifying the 281 * interleave read from this page in the FORMAT UNIT command. 282 */ 283 scsi_mode_sense(fd, 0x03, 0x00, &mode_page, sizeof(mode_page)); 284 285 j = (mode_page.format_page.bytes_s[0] << 8) | 286 (mode_page.format_page.bytes_s[1]); 287 288 if (j != DEV_BSIZE) 289 printf("current disk sector size: %hd\n", j); 290 291 memset(&cmd, 0, sizeof(cmd)); 292 293 cmd.opcode = SCSI_FORMAT_UNIT; 294 memcpy(cmd.interleave, mode_page.format_page.interleave, 295 sizeof(cmd.interleave)); 296 297 /* 298 * The blocksize on the device is only changed if the user 299 * specified a new blocksize. If not specified the blocksize 300 * used for the device will be the Default value in the device. 301 * We don't specify the number of blocks since the format 302 * command will always reformat the entire drive. Also by 303 * not specifying a block count the drive will reset the 304 * block count to the maximum available after the format 305 * completes if the blocksize was changed in the format. 306 * Finally, the new disk geometry will not but updated on 307 * the drive in permanent storage until _AFTER_ the format 308 * completes successfully. 309 */ 310 if (argc > 0) { 311 blksize = strtoul(argv[0], &cp, 10); 312 if (*cp != '\0') 313 errx(1, "invalid block size: %s", argv[0]); 314 315 memset(&data_select, 0, sizeof(data_select)); 316 317 data_select.header.blk_desc_len = sizeof(struct scsi_blk_desc); 318 /* 319 * blklen in desc is 3 bytes with a leading reserved byte 320 */ 321 _lto4b(blksize, &data_select.blk_desc.reserved); 322 323 /* 324 * Issue Mode Select to modify the device blocksize to be 325 * used on the Format. The modified device geometry will 326 * be stored as Current and Saved Page 3 parameters when 327 * the Format completes. 328 */ 329 scsi_mode_select(fd, 0, &data_select, sizeof(data_select)); 330 331 /* 332 * Since user specified a specific block size make sure it 333 * gets stored in the device when the format completes. 334 * 335 * Also scrub the defect list back to the manufacturers 336 * original. 337 */ 338 cmd.flags = SFU_CMPLST | SFU_FMTDATA; 339 } 340 341 memset(&dfl, 0, sizeof(dfl)); 342 343 if (argc > 1 && strncmp(argv[1], "imm", 3) == 0) { 344 /* 345 * Signal target for an immediate return from Format. 346 * 347 * We'll poll for completion status. 348 */ 349 dfl.header.flags = DLH_IMMED; 350 immediate = 1; 351 } else { 352 immediate = 0; 353 } 354 355 scsi_command(fd, &cmd, sizeof(cmd), &dfl, sizeof(dfl), 356 8 * 60 * 60 * 1000, 0); 357 358 /* 359 * Poll device for completion of Format 360 */ 361 if (immediate) { 362 i = 0; 363 printf("formatting."); 364 fflush(stdout); 365 do { 366 scsireq_t req; 367 struct scsipi_test_unit_ready tcmd; 368 369 memset(&tcmd, 0, sizeof(cmd)); 370 tcmd.opcode = TEST_UNIT_READY; 371 372 memset(&req, 0, sizeof(req)); 373 memcpy(req.cmd, &tcmd, 6); 374 req.cmdlen = 6; 375 req.timeout = 10000; 376 req.senselen = SENSEBUFLEN; 377 378 if (ioctl(fd, SCIOCCOMMAND, &req) == -1) { 379 err(1, "SCIOCCOMMAND"); 380 } 381 382 if (req.retsts == SCCMD_OK) { 383 break; 384 } else if (req.retsts == SCCMD_TIMEOUT) { 385 fprintf(stderr, "%s: SCSI command timed out", 386 dvname); 387 break; 388 } else if (req.retsts == SCCMD_BUSY) { 389 fprintf(stderr, "%s: device is busy", 390 dvname); 391 break; 392 } else if (req.retsts != SCCMD_SENSE) { 393 fprintf(stderr, 394 "%s: device had unknown status %x", dvname, 395 req.retsts); 396 break; 397 } 398 memcpy(&sense, req.sense, SENSEBUFLEN); 399 if (sense.sense_key_spec_1 == SSD_SCS_VALID) { 400 j = (sense.sense_key_spec_2 << 8) | 401 (sense.sense_key_spec_3); 402 if (j >= complete[i]) { 403 printf(".%d0%%.", ++i); 404 fflush(stdout); 405 } 406 } 407 sleep(10); 408 } while ((sense.flags & SSD_KEY) == SKEY_NOT_READY); 409 printf(".100%%..done.\n"); 410 } 411 return; 412 } 413 414 /* 415 * device_identify: 416 * 417 * Display the identity of the device, including it's SCSI bus, 418 * target, lun, and it's vendor/product/revision information. 419 */ 420 void 421 device_identify(argc, argv) 422 int argc; 423 char *argv[]; 424 { 425 struct scsipi_inquiry_data inqbuf; 426 struct scsipi_inquiry cmd; 427 428 /* x4 in case every character is escaped, +1 for NUL. */ 429 char vendor[(sizeof(inqbuf.vendor) * 4) + 1], 430 product[(sizeof(inqbuf.product) * 4) + 1], 431 revision[(sizeof(inqbuf.revision) * 4) + 1]; 432 433 /* No arguments. */ 434 if (argc != 0) 435 usage(); 436 437 memset(&cmd, 0, sizeof(cmd)); 438 memset(&inqbuf, 0, sizeof(inqbuf)); 439 440 cmd.opcode = INQUIRY; 441 cmd.length = sizeof(inqbuf); 442 443 scsi_command(fd, &cmd, sizeof(cmd), &inqbuf, sizeof(inqbuf), 444 10000, SCCMD_READ); 445 446 scsi_strvis(vendor, sizeof(vendor), inqbuf.vendor, 447 sizeof(inqbuf.vendor)); 448 scsi_strvis(product, sizeof(product), inqbuf.product, 449 sizeof(inqbuf.product)); 450 scsi_strvis(revision, sizeof(revision), inqbuf.revision, 451 sizeof(inqbuf.revision)); 452 453 printf("%s: scsibus%d target %d lun %d <%s, %s, %s>\n", 454 dvname, dvaddr.addr.scsi.scbus, dvaddr.addr.scsi.target, 455 dvaddr.addr.scsi.lun, vendor, product, revision); 456 457 return; 458 } 459 460 /* 461 * device_reassign: 462 * 463 * Reassign bad blocks on a direct access device. 464 */ 465 void 466 device_reassign(argc, argv) 467 int argc; 468 char *argv[]; 469 { 470 struct scsi_reassign_blocks cmd; 471 struct scsi_reassign_blocks_data *data; 472 size_t dlen; 473 u_int32_t blkno; 474 int i; 475 char *cp; 476 477 /* We get a list of block numbers. */ 478 if (argc < 1) 479 usage(); 480 481 /* 482 * Allocate the reassign blocks descriptor. The 4 comes from the 483 * size of the block address in the defect descriptor. 484 */ 485 dlen = sizeof(struct scsi_reassign_blocks_data) + ((argc - 1) * 4); 486 data = malloc(dlen); 487 if (data == NULL) 488 errx(1, "unable to allocate defect descriptor"); 489 memset(data, 0, dlen); 490 491 cmd.opcode = SCSI_REASSIGN_BLOCKS; 492 cmd.byte2 = 0; 493 cmd.unused[0] = 0; 494 cmd.unused[1] = 0; 495 cmd.unused[2] = 0; 496 cmd.control = 0; 497 498 /* Defect descriptor length. */ 499 _lto2b(argc * 4, data->length); 500 501 /* Build the defect descriptor list. */ 502 for (i = 0; i < argc; i++) { 503 blkno = strtoul(argv[i], &cp, 10); 504 if (*cp != '\0') 505 errx(1, "invalid block number: %s", argv[i]); 506 _lto4b(blkno, data->defect_descriptor[i].dlbaddr); 507 } 508 509 scsi_command(fd, &cmd, sizeof(cmd), data, dlen, 30000, SCCMD_WRITE); 510 511 free(data); 512 return; 513 } 514 515 /* 516 * device_release: 517 * 518 * Issue a RELEASE command to a SCSI drevice 519 */ 520 #ifndef SCSI_RELEASE 521 #define SCSI_RELEASE 0x17 522 #endif 523 void 524 device_release(argc, argv) 525 int argc; 526 char *argv[]; 527 { 528 struct scsipi_test_unit_ready cmd; /* close enough */ 529 530 /* No arguments. */ 531 if (argc != 0) 532 usage(); 533 534 memset(&cmd, 0, sizeof(cmd)); 535 536 cmd.opcode = SCSI_RELEASE; 537 538 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 539 540 return; 541 } 542 543 544 545 /* 546 * device_reserve: 547 * 548 * Issue a RESERVE command to a SCSI drevice 549 */ 550 #ifndef SCSI_RESERVE 551 #define SCSI_RESERVE 0x16 552 #endif 553 void 554 device_reserve(argc, argv) 555 int argc; 556 char *argv[]; 557 { 558 struct scsipi_test_unit_ready cmd; /* close enough */ 559 560 /* No arguments. */ 561 if (argc != 0) 562 usage(); 563 564 memset(&cmd, 0, sizeof(cmd)); 565 566 cmd.opcode = SCSI_RESERVE; 567 568 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 569 570 return; 571 } 572 573 /* 574 * device_reset: 575 * 576 * Issue a reset to a SCSI device. 577 */ 578 void 579 device_reset(argc, argv) 580 int argc; 581 char *argv[]; 582 { 583 584 /* No arguments. */ 585 if (argc != 0) 586 usage(); 587 588 if (ioctl(fd, SCIOCRESET, NULL) != 0) 589 err(1, "SCIOCRESET"); 590 591 return; 592 } 593 594 /* 595 * device_debug: 596 * 597 * Set debug level to a SCSI device. 598 * scsipi will print anything iff SCSIPI_DEBUG set in config. 599 */ 600 void 601 device_debug(argc, argv) 602 int argc; 603 char *argv[]; 604 { 605 int lvl; 606 607 if (argc < 1) 608 usage(); 609 610 lvl = atoi(argv[0]); 611 612 if (ioctl(fd, SCIOCDEBUG, &lvl) != 0) 613 err(1, "SCIOCDEBUG"); 614 615 return; 616 } 617 618 /* 619 * device_getcache: 620 * 621 * Get the caching parameters for a SCSI disk. 622 */ 623 void 624 device_getcache(argc, argv) 625 int argc; 626 char *argv[]; 627 { 628 struct { 629 struct scsipi_mode_header header; 630 struct scsi_blk_desc blk_desc; 631 struct page_caching caching_params; 632 } data; 633 634 /* No arguments. */ 635 if (argc != 0) 636 usage(); 637 638 scsi_mode_sense(fd, 0x08, 0x00, &data, sizeof(data)); 639 640 if ((data.caching_params.flags & (CACHING_RCD|CACHING_WCE)) == 641 CACHING_RCD) 642 printf("%s: no caches enabled\n", dvname); 643 else { 644 printf("%s: read cache %senabled\n", dvname, 645 (data.caching_params.flags & CACHING_RCD) ? "not " : ""); 646 printf("%s: write-back cache %senabled\n", dvname, 647 (data.caching_params.flags & CACHING_WCE) ? "" : "not "); 648 } 649 printf("%s: caching parameters are %ssavable\n", dvname, 650 (data.caching_params.pg_code & PGCODE_PS) ? "" : "not "); 651 } 652 653 /* 654 * device_setcache: 655 * 656 * Set cache enables for a SCSI disk. 657 */ 658 void 659 device_setcache(argc, argv) 660 int argc; 661 char *argv[]; 662 { 663 struct { 664 struct scsipi_mode_header header; 665 struct scsi_blk_desc blk_desc; 666 struct page_caching caching_params; 667 } data; 668 int dlen; 669 u_int8_t flags, byte2; 670 671 if (argc > 2 || argc == 0) 672 usage(); 673 674 if (strcmp(argv[0], "none") == 0) 675 flags = CACHING_RCD; 676 else if (strcmp(argv[0], "r") == 0) 677 flags = 0; 678 else if (strcmp(argv[0], "w") == 0) 679 flags = CACHING_RCD|CACHING_WCE; 680 else if (strcmp(argv[0], "rw") == 0) 681 flags = CACHING_WCE; 682 else 683 usage(); 684 685 if (argc == 2) { 686 if (strcmp(argv[1], "save") == 0) 687 byte2 = SMS_SP; 688 else 689 usage(); 690 } 691 692 scsi_mode_sense(fd, 0x08, 0x00, &data, sizeof(data)); 693 694 data.caching_params.pg_code &= PGCODE_MASK; 695 data.caching_params.flags = 696 (data.caching_params.flags & ~(CACHING_RCD|CACHING_WCE)) | flags; 697 698 data.caching_params.cache_segment_size[0] = 0; 699 data.caching_params.cache_segment_size[1] = 0; 700 701 data.header.data_length = 0; 702 703 dlen = sizeof(data.header) + sizeof(data.blk_desc) + 2 + 704 data.caching_params.pg_length; 705 706 scsi_mode_select(fd, byte2, &data, dlen); 707 } 708 709 /* 710 * device_flushcache: 711 * 712 * Issue a FLUSH CACHE command to a SCSI drevice 713 */ 714 #ifndef SCSI_FLUSHCACHE 715 #define SCSI_FLUSHCACHE 0x35 716 #endif 717 void 718 device_flushcache(argc, argv) 719 int argc; 720 char *argv[]; 721 { 722 struct scsipi_test_unit_ready cmd; /* close enough */ 723 724 /* No arguments. */ 725 if (argc != 0) 726 usage(); 727 728 memset(&cmd, 0, sizeof(cmd)); 729 730 cmd.opcode = SCSI_FLUSHCACHE; 731 732 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 733 734 return; 735 } 736 737 /* 738 * device_prevent: 739 * 740 * Issue a prevent to a SCSI device. 741 */ 742 void 743 device_prevent(argc, argv) 744 int argc; 745 char *argv[]; 746 { 747 struct scsipi_prevent cmd; 748 749 /* No arguments. */ 750 if (argc != 0) 751 usage(); 752 753 memset(&cmd, 0, sizeof(cmd)); 754 755 cmd.opcode = PREVENT_ALLOW; 756 cmd.how = PR_PREVENT; 757 758 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 759 760 return; 761 } 762 763 /* 764 * device_allow: 765 * 766 * Issue a stop to a SCSI device. 767 */ 768 void 769 device_allow(argc, argv) 770 int argc; 771 char *argv[]; 772 { 773 struct scsipi_prevent cmd; 774 775 /* No arguments. */ 776 if (argc != 0) 777 usage(); 778 779 memset(&cmd, 0, sizeof(cmd)); 780 781 cmd.opcode = PREVENT_ALLOW; 782 cmd.how = PR_ALLOW; 783 784 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 785 786 return; 787 } 788 789 /* 790 * device_start: 791 * 792 * Issue a start to a SCSI device. 793 */ 794 void 795 device_start(argc, argv) 796 int argc; 797 char *argv[]; 798 { 799 struct scsipi_start_stop cmd; 800 801 /* No arguments. */ 802 if (argc != 0) 803 usage(); 804 805 memset(&cmd, 0, sizeof(cmd)); 806 807 cmd.opcode = START_STOP; 808 cmd.how = SSS_START; 809 810 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 30000, 0); 811 812 return; 813 } 814 815 /* 816 * device_stop: 817 * 818 * Issue a stop to a SCSI device. 819 */ 820 void 821 device_stop(argc, argv) 822 int argc; 823 char *argv[]; 824 { 825 struct scsipi_start_stop cmd; 826 827 /* No arguments. */ 828 if (argc != 0) 829 usage(); 830 831 memset(&cmd, 0, sizeof(cmd)); 832 833 cmd.opcode = START_STOP; 834 cmd.how = SSS_STOP; 835 836 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 30000, 0); 837 838 return; 839 } 840 841 /* 842 * device_tur: 843 * 844 * Issue a TEST UNIT READY to a SCSI drevice 845 */ 846 void 847 device_tur(argc, argv) 848 int argc; 849 char *argv[]; 850 { 851 struct scsipi_test_unit_ready cmd; 852 853 /* No arguments. */ 854 if (argc != 0) 855 usage(); 856 857 memset(&cmd, 0, sizeof(cmd)); 858 859 cmd.opcode = TEST_UNIT_READY; 860 861 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 862 863 return; 864 } 865 866 /* 867 * BUS COMMANDS 868 */ 869 870 /* 871 * bus_reset: 872 * 873 * Issue a reset to a SCSI bus. 874 */ 875 void 876 bus_reset(argc, argv) 877 int argc; 878 char *argv[]; 879 { 880 881 /* No arguments. */ 882 if (argc != 0) 883 usage(); 884 885 if (ioctl(fd, SCBUSIORESET, NULL) != 0) 886 err(1, "SCBUSIORESET"); 887 888 return; 889 } 890 891 /* 892 * bus_scan: 893 * 894 * Rescan a SCSI bus for new devices. 895 */ 896 void 897 bus_scan(argc, argv) 898 int argc; 899 char *argv[]; 900 { 901 struct scbusioscan_args args; 902 char *cp; 903 904 /* Must have two args: target lun */ 905 if (argc != 2) 906 usage(); 907 908 if (strcmp(argv[0], "any") == 0 || strcmp(argv[0], "all") == 0) 909 args.sa_target = -1; 910 else { 911 args.sa_target = strtol(argv[0], &cp, 10); 912 if (*cp != '\0' || args.sa_target < 0) 913 errx(1, "invalid target: %s", argv[0]); 914 } 915 916 if (strcmp(argv[1], "any") == 0 || strcmp(argv[1], "all") == 0) 917 args.sa_lun = -1; 918 else { 919 args.sa_lun = strtol(argv[1], &cp, 10); 920 if (*cp != '\0' || args.sa_lun < 0) 921 errx(1, "invalid lun: %s", argv[1]); 922 } 923 924 if (ioctl(fd, SCBUSIOSCAN, &args) != 0) 925 err(1, "SCBUSIOSCAN"); 926 927 return; 928 } 929 930 /* 931 * bus_detach: 932 * 933 * detach SCSI devices from a bus. 934 */ 935 void 936 bus_detach(argc, argv) 937 int argc; 938 char *argv[]; 939 { 940 struct scbusiodetach_args args; 941 char *cp; 942 943 /* Must have two args: target lun */ 944 if (argc != 2) 945 usage(); 946 947 if (strcmp(argv[0], "any") == 0 || strcmp(argv[0], "all") == 0) 948 args.sa_target = -1; 949 else { 950 args.sa_target = strtol(argv[0], &cp, 10); 951 if (*cp != '\0' || args.sa_target < 0) 952 errx(1, "invalid target: %s", argv[0]); 953 } 954 955 if (strcmp(argv[1], "any") == 0 || strcmp(argv[1], "all") == 0) 956 args.sa_lun = -1; 957 else { 958 args.sa_lun = strtol(argv[1], &cp, 10); 959 if (*cp != '\0' || args.sa_lun < 0) 960 errx(1, "invalid lun: %s", argv[1]); 961 } 962 963 if (ioctl(fd, SCBUSIODETACH, &args) != 0) 964 err(1, "SCBUSIODETACH"); 965 966 return; 967 } 968