1 /* $NetBSD: scsictl.c,v 1.26 2005/02/05 13:37:39 xtraeme 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.26 2005/02/05 13:37:39 xtraeme 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 <limits.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <unistd.h> 61 #include <util.h> 62 63 #include <dev/scsipi/scsipi_all.h> 64 #include <dev/scsipi/scsi_all.h> 65 #include <dev/scsipi/scsi_disk.h> 66 #include <dev/scsipi/scsipiconf.h> 67 68 #include "extern.h" 69 70 struct command { 71 const char *cmd_name; 72 const char *arg_names; 73 void (*cmd_func)(int, char *[]); 74 }; 75 76 void usage(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_defects(int, char *[]); 86 void device_format(int, char *[]); 87 void device_identify(int, char *[]); 88 void device_reassign(int, char *[]); 89 void device_release(int, char *[]); 90 void device_reserve(int, char *[]); 91 void device_reset(int, char *[]); 92 void device_debug(int, char *[]); 93 void device_prevent(int, char *[]); 94 void device_allow(int, char *[]); 95 void device_start(int, char *[]); 96 void device_stop(int, char *[]); 97 void device_tur(int, char *[]); 98 void device_getcache(int, char *[]); 99 void device_setcache(int, char *[]); 100 void device_flushcache(int, char *[]); 101 102 struct command device_commands[] = { 103 { "defects", "[primary] [grown] [block|byte|physical]", 104 device_defects }, 105 { "format", "[blocksize [immediate]]", device_format }, 106 { "identify", "", device_identify }, 107 { "reassign", "blkno [blkno [...]]", device_reassign }, 108 { "release", "", device_release }, 109 { "reserve", "", device_reserve }, 110 { "reset", "", device_reset }, 111 { "debug", "level", device_debug }, 112 { "prevent", "", device_prevent }, 113 { "allow", "", device_allow }, 114 { "start", "", device_start }, 115 { "stop", "", device_stop }, 116 { "tur", "", device_tur }, 117 { "getcache", "", device_getcache }, 118 { "setcache", "none|r|w|rw [save]", device_setcache }, 119 { "flushcache", "", device_flushcache }, 120 { NULL, NULL, NULL }, 121 }; 122 123 void bus_reset(int, char *[]); 124 void bus_scan(int, char *[]); 125 void bus_detach(int, char *[]); 126 127 struct command bus_commands[] = { 128 { "reset", "", bus_reset }, 129 { "scan", "target lun", bus_scan }, 130 { "detach", "target lun", bus_detach }, 131 { NULL, NULL, NULL }, 132 }; 133 134 int 135 main(int argc, char *argv[]) 136 { 137 struct command *commands; 138 int i; 139 140 /* Must have at least: device command */ 141 if (argc < 3) 142 usage(); 143 144 /* Skip program name, get and skip device name and command. */ 145 dvname = argv[1]; 146 cmdname = argv[2]; 147 argv += 3; 148 argc -= 3; 149 150 /* 151 * Open the device and determine if it's a scsibus or an actual 152 * device. Devices respond to the SCIOCIDENTIFY ioctl. 153 */ 154 fd = opendisk(dvname, O_RDWR, dvname_store, sizeof(dvname_store), 0); 155 if (fd == -1) { 156 if (errno == ENOENT) { 157 /* 158 * Device doesn't exist. Probably trying to open 159 * a device which doesn't use disk semantics for 160 * device name. Try again, specifying "cooked", 161 * which leaves off the "r" in front of the device's 162 * name. 163 */ 164 fd = opendisk(dvname, O_RDWR, dvname_store, 165 sizeof(dvname_store), 1); 166 if (fd == -1) 167 err(1, "%s", dvname); 168 } else 169 err(1, "%s", dvname); 170 } 171 172 /* 173 * Point the dvname at the actual device name that opendisk() opened. 174 */ 175 dvname = dvname_store; 176 177 if (ioctl(fd, SCIOCIDENTIFY, &dvaddr) < 0) 178 commands = bus_commands; 179 else 180 commands = device_commands; 181 182 /* Look up and call the command. */ 183 for (i = 0; commands[i].cmd_name != NULL; i++) 184 if (strcmp(cmdname, commands[i].cmd_name) == 0) 185 break; 186 if (commands[i].cmd_name == NULL) 187 errx(1, "unknown %s command: %s", 188 commands == bus_commands ? "bus" : "device", cmdname); 189 190 argnames = commands[i].arg_names; 191 192 (*commands[i].cmd_func)(argc, argv); 193 exit(0); 194 } 195 196 void 197 usage(void) 198 { 199 int i; 200 201 fprintf(stderr, "usage: %s device command [arg [...]]\n", 202 getprogname()); 203 204 fprintf(stderr, " Commands pertaining to scsi devices:\n"); 205 for (i=0; device_commands[i].cmd_name != NULL; i++) 206 fprintf(stderr, "\t%s %s\n", device_commands[i].cmd_name, 207 device_commands[i].arg_names); 208 fprintf(stderr, " Commands pertaining to scsi busses:\n"); 209 for (i=0; bus_commands[i].cmd_name != NULL; i++) 210 fprintf(stderr, "\t%s %s\n", bus_commands[i].cmd_name, 211 bus_commands[i].arg_names); 212 fprintf(stderr, " Use `any' or `all' to wildcard target or lun\n"); 213 214 exit(1); 215 } 216 217 /* 218 * DEVICE COMMANDS 219 */ 220 221 /* 222 * device_read_defect: 223 * 224 * Read primary and/or growth defect list in physical or block 225 * format from a direct access device. 226 * 227 * XXX Does not handle very large defect lists. Needs SCSI3 12 228 * byte READ DEFECT DATA command. 229 */ 230 231 void print_bf_dd(union scsi_defect_descriptor *); 232 void print_bfif_dd(union scsi_defect_descriptor *); 233 void print_psf_dd(union scsi_defect_descriptor *); 234 235 void 236 device_defects(int argc, char *argv[]) 237 { 238 struct scsi_read_defect_data cmd; 239 struct scsi_read_defect_data_data *data; 240 size_t dlen; 241 int i, dlfmt = -1; 242 int defects; 243 char msg[256]; 244 void (*pfunc)(union scsi_defect_descriptor *); 245 #define RDD_P_G_MASK 0x18 246 #define RDD_DLF_MASK 0x7 247 248 dlen = USHRT_MAX; /* XXX - this may not be enough room 249 * for all of the defects. 250 */ 251 data = malloc(dlen); 252 if (data == NULL) 253 errx(1, "unable to allocate defect list"); 254 memset(data, 0, dlen); 255 memset(&cmd, 0, sizeof(cmd)); 256 257 /* determine which defect list(s) to read. */ 258 for (i = 0; i < argc; i++) { 259 if (strncmp("primary", argv[i], 7) == 0) { 260 cmd.flags |= RDD_PRIMARY; 261 continue; 262 } 263 if (strncmp("grown", argv[i], 5) == 0) { 264 cmd.flags |= RDD_GROWN; 265 continue; 266 } 267 break; 268 } 269 270 /* no defect list sepecified, assume both. */ 271 if ((cmd.flags & (RDD_PRIMARY|RDD_GROWN)) == 0) 272 cmd.flags |= (RDD_PRIMARY|RDD_GROWN); 273 274 /* list format option. */ 275 if (i < argc) { 276 if (strncmp("block", argv[i], 5) == 0) { 277 cmd.flags |= RDD_BF; 278 dlfmt = RDD_BF; 279 } 280 else if (strncmp("byte", argv[i], 4) == 0) { 281 cmd.flags |= RDD_BFIF; 282 dlfmt = RDD_BFIF; 283 } 284 else if (strncmp("physical", argv[i], 4) == 0) { 285 cmd.flags |= RDD_PSF; 286 dlfmt = RDD_PSF; 287 } 288 else { 289 usage(); 290 } 291 } 292 293 /* 294 * no list format specified; since block format not 295 * recommended use physical sector format as default. 296 */ 297 if (dlfmt < 0) { 298 cmd.flags |= RDD_PSF; 299 dlfmt = RDD_PSF; 300 } 301 302 cmd.opcode = SCSI_READ_DEFECT_DATA; 303 _lto2b(dlen, &cmd.length[0]); 304 305 scsi_command(fd, &cmd, sizeof(cmd), data, dlen, 30000, SCCMD_READ); 306 307 msg[0] = '\0'; 308 309 /* is the defect list in the format asked for? */ 310 if ((data->flags & RDD_DLF_MASK) != dlfmt) { 311 strcpy(msg, "\n\tnotice:" 312 "requested defect list format not supported by device\n\n"); 313 dlfmt = (data->flags & RDD_DLF_MASK); 314 } 315 316 if (data->flags & RDD_PRIMARY) 317 strcat(msg, "primary"); 318 319 if (data->flags & RDD_GROWN) { 320 if (data->flags & RDD_PRIMARY) 321 strcat(msg, " and "); 322 strcat(msg, "grown"); 323 } 324 325 strcat(msg, " defects"); 326 327 if ((data->flags & RDD_P_G_MASK) == 0) 328 strcat(msg, ": none reported\n"); 329 330 331 printf("%s: scsibus%d target %d lun %d %s", 332 dvname, dvaddr.addr.scsi.scbus, dvaddr.addr.scsi.target, 333 dvaddr.addr.scsi.lun, msg); 334 335 /* device did not return either defect list. */ 336 if ((data->flags & RDD_P_G_MASK) == 0) 337 return; 338 339 switch (dlfmt) { 340 case RDD_BF: 341 defects = _2btol(data->length) / 342 sizeof(struct scsi_defect_descriptor_bf); 343 pfunc = print_bf_dd; 344 strcpy(msg, "block address\n" 345 "-------------\n"); 346 break; 347 case RDD_BFIF: 348 defects = _2btol(data->length) / 349 sizeof(struct scsi_defect_descriptor_bfif); 350 pfunc = print_bfif_dd; 351 strcpy(msg, " bytes from\n" 352 "cylinder head index\n" 353 "-------- ---- ----------\n"); 354 break; 355 case RDD_PSF: 356 defects = _2btol(data->length) / 357 sizeof(struct scsi_defect_descriptor_psf); 358 pfunc = print_psf_dd; 359 strcpy(msg, "cylinder head sector\n" 360 "-------- ---- ----------\n"); 361 break; 362 } 363 364 /* device did not return any defects. */ 365 if (defects == 0) { 366 printf(": none\n"); 367 return; 368 } 369 370 printf(": %d\n", defects); 371 372 /* print heading. */ 373 printf("%s", msg); 374 375 /* print defect list. */ 376 for (i = 0 ; i < defects; i++) { 377 pfunc(&data->defect_descriptor[i]); 378 } 379 380 free(data); 381 return; 382 } 383 384 /* 385 * print_bf_dd: 386 * 387 * Print a block format defect descriptor. 388 */ 389 void 390 print_bf_dd(union scsi_defect_descriptor *dd) 391 { 392 u_int32_t block; 393 394 block = _4btol(dd->bf.block_address); 395 396 printf("%13u\n", block); 397 } 398 399 #define DEFECTIVE_TRACK 0xffffffff 400 401 /* 402 * print_bfif_dd: 403 * 404 * Print a bytes from index format defect descriptor. 405 */ 406 void 407 print_bfif_dd(union scsi_defect_descriptor *dd) 408 { 409 u_int32_t cylinder; 410 u_int32_t head; 411 u_int32_t bytes_from_index; 412 413 cylinder = _3btol(dd->bfif.cylinder); 414 head = dd->bfif.head; 415 bytes_from_index = _4btol(dd->bfif.bytes_from_index); 416 417 printf("%8u %4u ", cylinder, head); 418 419 if (bytes_from_index == DEFECTIVE_TRACK) 420 printf("entire track defective\n"); 421 else 422 printf("%10u\n", bytes_from_index); 423 } 424 425 /* 426 * print_psf_dd: 427 * 428 * Print a physical sector format defect descriptor. 429 */ 430 void 431 print_psf_dd(union scsi_defect_descriptor *dd) 432 { 433 u_int32_t cylinder; 434 u_int32_t head; 435 u_int32_t sector; 436 437 cylinder = _3btol(dd->psf.cylinder); 438 head = dd->psf.head; 439 sector = _4btol(dd->psf.sector); 440 441 printf("%8u %4u ", cylinder, head); 442 443 if (sector == DEFECTIVE_TRACK) 444 printf("entire track defective\n"); 445 else 446 printf("%10u\n", sector); 447 } 448 449 /* 450 * device_format: 451 * 452 * Format a direct access device. 453 */ 454 void 455 device_format(int argc, char *argv[]) 456 { 457 u_int32_t blksize; 458 int i, j, immediate; 459 #define PC (65536/10) 460 static int complete[] = { 461 PC*1, PC*2, PC*3, PC*4, PC*5, PC*6, PC*7, PC*8, PC*9, 65536 462 }; 463 char *cp, buffer[64]; 464 struct scsipi_sense_data sense; 465 struct scsi_format_unit cmd; 466 struct { 467 struct scsi_format_unit_defect_list_header header; 468 /* optional initialization pattern */ 469 /* optional defect list */ 470 } dfl; 471 struct { 472 struct scsipi_mode_header header; 473 struct scsi_blk_desc blk_desc; 474 struct page_disk_format format_page; 475 } mode_page; 476 struct { 477 struct scsipi_mode_header header; 478 struct scsi_blk_desc blk_desc; 479 } data_select; 480 481 482 /* Blocksize is an optional argument. */ 483 if (argc > 2) 484 usage(); 485 486 /* 487 * Loop doing Request Sense to clear any pending Unit Attention. 488 * 489 * Multiple conditions may exist on the drive which are returned 490 * in priority order. 491 */ 492 for (i = 0; i < 8; i++) { 493 scsi_request_sense(fd, &sense, sizeof (sense)); 494 if ((j = sense.flags & SSD_KEY) == SKEY_NO_SENSE) 495 break; 496 } 497 /* 498 * Make sure we cleared any pending Unit Attention 499 */ 500 if (j != SKEY_NO_SENSE) { 501 cp = scsi_decode_sense((const unsigned char *) &sense, 2, 502 buffer, sizeof (buffer)); 503 errx(1, "failed to clean Unit Attention: %s", cp); 504 } 505 506 /* 507 * Get the DISK FORMAT mode page. SCSI-2 recommends specifying the 508 * interleave read from this page in the FORMAT UNIT command. 509 */ 510 scsi_mode_sense(fd, 0x03, 0x00, &mode_page, sizeof(mode_page)); 511 512 j = (mode_page.format_page.bytes_s[0] << 8) | 513 (mode_page.format_page.bytes_s[1]); 514 515 if (j != DEV_BSIZE) 516 printf("current disk sector size: %hd\n", j); 517 518 memset(&cmd, 0, sizeof(cmd)); 519 520 cmd.opcode = SCSI_FORMAT_UNIT; 521 memcpy(cmd.interleave, mode_page.format_page.interleave, 522 sizeof(cmd.interleave)); 523 524 /* 525 * The blocksize on the device is only changed if the user 526 * specified a new blocksize. If not specified the blocksize 527 * used for the device will be the Default value in the device. 528 * We don't specify the number of blocks since the format 529 * command will always reformat the entire drive. Also by 530 * not specifying a block count the drive will reset the 531 * block count to the maximum available after the format 532 * completes if the blocksize was changed in the format. 533 * Finally, the new disk geometry will not but updated on 534 * the drive in permanent storage until _AFTER_ the format 535 * completes successfully. 536 */ 537 if (argc > 0) { 538 blksize = strtoul(argv[0], &cp, 10); 539 if (*cp != '\0') 540 errx(1, "invalid block size: %s", argv[0]); 541 542 memset(&data_select, 0, sizeof(data_select)); 543 544 data_select.header.blk_desc_len = sizeof(struct scsi_blk_desc); 545 /* 546 * blklen in desc is 3 bytes with a leading reserved byte 547 */ 548 _lto4b(blksize, &data_select.blk_desc.reserved); 549 550 /* 551 * Issue Mode Select to modify the device blocksize to be 552 * used on the Format. The modified device geometry will 553 * be stored as Current and Saved Page 3 parameters when 554 * the Format completes. 555 */ 556 scsi_mode_select(fd, 0, &data_select, sizeof(data_select)); 557 558 /* 559 * Since user specified a specific block size make sure it 560 * gets stored in the device when the format completes. 561 * 562 * Also scrub the defect list back to the manufacturers 563 * original. 564 */ 565 cmd.flags = SFU_CMPLST | SFU_FMTDATA; 566 } 567 568 memset(&dfl, 0, sizeof(dfl)); 569 570 if (argc > 1 && strncmp(argv[1], "imm", 3) == 0) { 571 /* 572 * Signal target for an immediate return from Format. 573 * 574 * We'll poll for completion status. 575 */ 576 dfl.header.flags = DLH_IMMED; 577 immediate = 1; 578 } else { 579 immediate = 0; 580 } 581 582 scsi_command(fd, &cmd, sizeof(cmd), &dfl, sizeof(dfl), 583 8 * 60 * 60 * 1000, 0); 584 585 /* 586 * Poll device for completion of Format 587 */ 588 if (immediate) { 589 i = 0; 590 printf("formatting."); 591 fflush(stdout); 592 do { 593 scsireq_t req; 594 struct scsipi_test_unit_ready tcmd; 595 596 memset(&tcmd, 0, sizeof(cmd)); 597 tcmd.opcode = TEST_UNIT_READY; 598 599 memset(&req, 0, sizeof(req)); 600 memcpy(req.cmd, &tcmd, 6); 601 req.cmdlen = 6; 602 req.timeout = 10000; 603 req.senselen = SENSEBUFLEN; 604 605 if (ioctl(fd, SCIOCCOMMAND, &req) == -1) { 606 err(1, "SCIOCCOMMAND"); 607 } 608 609 if (req.retsts == SCCMD_OK) { 610 break; 611 } else if (req.retsts == SCCMD_TIMEOUT) { 612 fprintf(stderr, "%s: SCSI command timed out", 613 dvname); 614 break; 615 } else if (req.retsts == SCCMD_BUSY) { 616 fprintf(stderr, "%s: device is busy", 617 dvname); 618 break; 619 } else if (req.retsts != SCCMD_SENSE) { 620 fprintf(stderr, 621 "%s: device had unknown status %x", dvname, 622 req.retsts); 623 break; 624 } 625 memcpy(&sense, req.sense, SENSEBUFLEN); 626 if (sense.sense_key_spec_1 == SSD_SCS_VALID) { 627 j = (sense.sense_key_spec_2 << 8) | 628 (sense.sense_key_spec_3); 629 if (j >= complete[i]) { 630 printf(".%d0%%.", ++i); 631 fflush(stdout); 632 } 633 } 634 sleep(10); 635 } while ((sense.flags & SSD_KEY) == SKEY_NOT_READY); 636 printf(".100%%..done.\n"); 637 } 638 return; 639 } 640 641 /* 642 * device_identify: 643 * 644 * Display the identity of the device, including it's SCSI bus, 645 * target, lun, and it's vendor/product/revision information. 646 */ 647 void 648 device_identify(int argc, char *argv[]) 649 { 650 struct scsipi_inquiry_data inqbuf; 651 struct scsipi_inquiry cmd; 652 653 /* x4 in case every character is escaped, +1 for NUL. */ 654 char vendor[(sizeof(inqbuf.vendor) * 4) + 1], 655 product[(sizeof(inqbuf.product) * 4) + 1], 656 revision[(sizeof(inqbuf.revision) * 4) + 1]; 657 658 /* No arguments. */ 659 if (argc != 0) 660 usage(); 661 662 memset(&cmd, 0, sizeof(cmd)); 663 memset(&inqbuf, 0, sizeof(inqbuf)); 664 665 cmd.opcode = INQUIRY; 666 cmd.length = sizeof(inqbuf); 667 668 scsi_command(fd, &cmd, sizeof(cmd), &inqbuf, sizeof(inqbuf), 669 10000, SCCMD_READ); 670 671 scsi_strvis(vendor, sizeof(vendor), inqbuf.vendor, 672 sizeof(inqbuf.vendor)); 673 scsi_strvis(product, sizeof(product), inqbuf.product, 674 sizeof(inqbuf.product)); 675 scsi_strvis(revision, sizeof(revision), inqbuf.revision, 676 sizeof(inqbuf.revision)); 677 678 printf("%s: scsibus%d target %d lun %d <%s, %s, %s>\n", 679 dvname, dvaddr.addr.scsi.scbus, dvaddr.addr.scsi.target, 680 dvaddr.addr.scsi.lun, vendor, product, revision); 681 682 return; 683 } 684 685 /* 686 * device_reassign: 687 * 688 * Reassign bad blocks on a direct access device. 689 */ 690 void 691 device_reassign(int argc, char *argv[]) 692 { 693 struct scsi_reassign_blocks cmd; 694 struct scsi_reassign_blocks_data *data; 695 size_t dlen; 696 u_int32_t blkno; 697 int i; 698 char *cp; 699 700 /* We get a list of block numbers. */ 701 if (argc < 1) 702 usage(); 703 704 /* 705 * Allocate the reassign blocks descriptor. The 4 comes from the 706 * size of the block address in the defect descriptor. 707 */ 708 dlen = sizeof(struct scsi_reassign_blocks_data) + ((argc - 1) * 4); 709 data = malloc(dlen); 710 if (data == NULL) 711 errx(1, "unable to allocate defect descriptor"); 712 memset(data, 0, dlen); 713 714 cmd.opcode = SCSI_REASSIGN_BLOCKS; 715 cmd.byte2 = 0; 716 cmd.unused[0] = 0; 717 cmd.unused[1] = 0; 718 cmd.unused[2] = 0; 719 cmd.control = 0; 720 721 /* Defect descriptor length. */ 722 _lto2b(argc * 4, data->length); 723 724 /* Build the defect descriptor list. */ 725 for (i = 0; i < argc; i++) { 726 blkno = strtoul(argv[i], &cp, 10); 727 if (*cp != '\0') 728 errx(1, "invalid block number: %s", argv[i]); 729 _lto4b(blkno, data->defect_descriptor[i].dlbaddr); 730 } 731 732 scsi_command(fd, &cmd, sizeof(cmd), data, dlen, 30000, SCCMD_WRITE); 733 734 free(data); 735 return; 736 } 737 738 /* 739 * device_release: 740 * 741 * Issue a RELEASE command to a SCSI drevice 742 */ 743 #ifndef SCSI_RELEASE 744 #define SCSI_RELEASE 0x17 745 #endif 746 void 747 device_release(int argc, char *argv[]) 748 { 749 struct scsipi_test_unit_ready cmd; /* close enough */ 750 751 /* No arguments. */ 752 if (argc != 0) 753 usage(); 754 755 memset(&cmd, 0, sizeof(cmd)); 756 757 cmd.opcode = SCSI_RELEASE; 758 759 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 760 761 return; 762 } 763 764 765 766 /* 767 * device_reserve: 768 * 769 * Issue a RESERVE command to a SCSI drevice 770 */ 771 #ifndef SCSI_RESERVE 772 #define SCSI_RESERVE 0x16 773 #endif 774 void 775 device_reserve(int argc, char *argv[]) 776 { 777 struct scsipi_test_unit_ready cmd; /* close enough */ 778 779 /* No arguments. */ 780 if (argc != 0) 781 usage(); 782 783 memset(&cmd, 0, sizeof(cmd)); 784 785 cmd.opcode = SCSI_RESERVE; 786 787 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 788 789 return; 790 } 791 792 /* 793 * device_reset: 794 * 795 * Issue a reset to a SCSI device. 796 */ 797 void 798 device_reset(int argc, char *argv[]) 799 { 800 801 /* No arguments. */ 802 if (argc != 0) 803 usage(); 804 805 if (ioctl(fd, SCIOCRESET, NULL) != 0) 806 err(1, "SCIOCRESET"); 807 808 return; 809 } 810 811 /* 812 * device_debug: 813 * 814 * Set debug level to a SCSI device. 815 * scsipi will print anything iff SCSIPI_DEBUG set in config. 816 */ 817 void 818 device_debug(int argc, char *argv[]) 819 { 820 int lvl; 821 822 if (argc < 1) 823 usage(); 824 825 lvl = atoi(argv[0]); 826 827 if (ioctl(fd, SCIOCDEBUG, &lvl) != 0) 828 err(1, "SCIOCDEBUG"); 829 830 return; 831 } 832 833 /* 834 * device_getcache: 835 * 836 * Get the caching parameters for a SCSI disk. 837 */ 838 void 839 device_getcache(int argc, char *argv[]) 840 { 841 struct { 842 struct scsipi_mode_header header; 843 struct scsi_blk_desc blk_desc; 844 struct page_caching caching_params; 845 } data; 846 847 /* No arguments. */ 848 if (argc != 0) 849 usage(); 850 851 scsi_mode_sense(fd, 0x08, 0x00, &data, sizeof(data)); 852 853 if ((data.caching_params.flags & (CACHING_RCD|CACHING_WCE)) == 854 CACHING_RCD) 855 printf("%s: no caches enabled\n", dvname); 856 else { 857 printf("%s: read cache %senabled\n", dvname, 858 (data.caching_params.flags & CACHING_RCD) ? "not " : ""); 859 printf("%s: write-back cache %senabled\n", dvname, 860 (data.caching_params.flags & CACHING_WCE) ? "" : "not "); 861 } 862 printf("%s: caching parameters are %ssavable\n", dvname, 863 (data.caching_params.pg_code & PGCODE_PS) ? "" : "not "); 864 } 865 866 /* 867 * device_setcache: 868 * 869 * Set cache enables for a SCSI disk. 870 */ 871 void 872 device_setcache(int argc, char *argv[]) 873 { 874 struct { 875 struct scsipi_mode_header header; 876 struct scsi_blk_desc blk_desc; 877 struct page_caching caching_params; 878 } data; 879 int dlen; 880 u_int8_t flags, byte2; 881 882 if (argc > 2 || argc == 0) 883 usage(); 884 885 if (strcmp(argv[0], "none") == 0) 886 flags = CACHING_RCD; 887 else if (strcmp(argv[0], "r") == 0) 888 flags = 0; 889 else if (strcmp(argv[0], "w") == 0) 890 flags = CACHING_RCD|CACHING_WCE; 891 else if (strcmp(argv[0], "rw") == 0) 892 flags = CACHING_WCE; 893 else 894 usage(); 895 896 if (argc == 2) { 897 if (strcmp(argv[1], "save") == 0) 898 byte2 = SMS_SP; 899 else 900 usage(); 901 } 902 903 scsi_mode_sense(fd, 0x08, 0x00, &data, sizeof(data)); 904 905 data.caching_params.pg_code &= PGCODE_MASK; 906 data.caching_params.flags = 907 (data.caching_params.flags & ~(CACHING_RCD|CACHING_WCE)) | flags; 908 909 data.caching_params.cache_segment_size[0] = 0; 910 data.caching_params.cache_segment_size[1] = 0; 911 912 data.header.data_length = 0; 913 914 dlen = sizeof(data.header) + sizeof(data.blk_desc) + 2 + 915 data.caching_params.pg_length; 916 917 scsi_mode_select(fd, byte2, &data, dlen); 918 } 919 920 /* 921 * device_flushcache: 922 * 923 * Issue a FLUSH CACHE command to a SCSI drevice 924 */ 925 #ifndef SCSI_FLUSHCACHE 926 #define SCSI_FLUSHCACHE 0x35 927 #endif 928 void 929 device_flushcache(int argc, char *argv[]) 930 { 931 struct scsipi_test_unit_ready cmd; /* close enough */ 932 933 /* No arguments. */ 934 if (argc != 0) 935 usage(); 936 937 memset(&cmd, 0, sizeof(cmd)); 938 939 cmd.opcode = SCSI_FLUSHCACHE; 940 941 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 942 943 return; 944 } 945 946 /* 947 * device_prevent: 948 * 949 * Issue a prevent to a SCSI device. 950 */ 951 void 952 device_prevent(int argc, char *argv[]) 953 { 954 struct scsipi_prevent cmd; 955 956 /* No arguments. */ 957 if (argc != 0) 958 usage(); 959 960 memset(&cmd, 0, sizeof(cmd)); 961 962 cmd.opcode = PREVENT_ALLOW; 963 cmd.how = PR_PREVENT; 964 965 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 966 967 return; 968 } 969 970 /* 971 * device_allow: 972 * 973 * Issue a stop to a SCSI device. 974 */ 975 void 976 device_allow(int argc, char *argv[]) 977 { 978 struct scsipi_prevent cmd; 979 980 /* No arguments. */ 981 if (argc != 0) 982 usage(); 983 984 memset(&cmd, 0, sizeof(cmd)); 985 986 cmd.opcode = PREVENT_ALLOW; 987 cmd.how = PR_ALLOW; 988 989 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 990 991 return; 992 } 993 994 /* 995 * device_start: 996 * 997 * Issue a start to a SCSI device. 998 */ 999 void 1000 device_start(int argc, char *argv[]) 1001 { 1002 struct scsipi_start_stop cmd; 1003 1004 /* No arguments. */ 1005 if (argc != 0) 1006 usage(); 1007 1008 memset(&cmd, 0, sizeof(cmd)); 1009 1010 cmd.opcode = START_STOP; 1011 cmd.how = SSS_START; 1012 1013 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 30000, 0); 1014 1015 return; 1016 } 1017 1018 /* 1019 * device_stop: 1020 * 1021 * Issue a stop to a SCSI device. 1022 */ 1023 void 1024 device_stop(int argc, char *argv[]) 1025 { 1026 struct scsipi_start_stop cmd; 1027 1028 /* No arguments. */ 1029 if (argc != 0) 1030 usage(); 1031 1032 memset(&cmd, 0, sizeof(cmd)); 1033 1034 cmd.opcode = START_STOP; 1035 cmd.how = SSS_STOP; 1036 1037 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 30000, 0); 1038 1039 return; 1040 } 1041 1042 /* 1043 * device_tur: 1044 * 1045 * Issue a TEST UNIT READY to a SCSI drevice 1046 */ 1047 void 1048 device_tur(int argc, char *argv[]) 1049 { 1050 struct scsipi_test_unit_ready cmd; 1051 1052 /* No arguments. */ 1053 if (argc != 0) 1054 usage(); 1055 1056 memset(&cmd, 0, sizeof(cmd)); 1057 1058 cmd.opcode = TEST_UNIT_READY; 1059 1060 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 1061 1062 return; 1063 } 1064 1065 /* 1066 * BUS COMMANDS 1067 */ 1068 1069 /* 1070 * bus_reset: 1071 * 1072 * Issue a reset to a SCSI bus. 1073 */ 1074 void 1075 bus_reset(int argc, char *argv[]) 1076 { 1077 1078 /* No arguments. */ 1079 if (argc != 0) 1080 usage(); 1081 1082 if (ioctl(fd, SCBUSIORESET, NULL) != 0) 1083 err(1, "SCBUSIORESET"); 1084 1085 return; 1086 } 1087 1088 /* 1089 * bus_scan: 1090 * 1091 * Rescan a SCSI bus for new devices. 1092 */ 1093 void 1094 bus_scan(int argc, char *argv[]) 1095 { 1096 struct scbusioscan_args args; 1097 char *cp; 1098 1099 /* Must have two args: target lun */ 1100 if (argc != 2) 1101 usage(); 1102 1103 if (strcmp(argv[0], "any") == 0 || strcmp(argv[0], "all") == 0) 1104 args.sa_target = -1; 1105 else { 1106 args.sa_target = strtol(argv[0], &cp, 10); 1107 if (*cp != '\0' || args.sa_target < 0) 1108 errx(1, "invalid target: %s", argv[0]); 1109 } 1110 1111 if (strcmp(argv[1], "any") == 0 || strcmp(argv[1], "all") == 0) 1112 args.sa_lun = -1; 1113 else { 1114 args.sa_lun = strtol(argv[1], &cp, 10); 1115 if (*cp != '\0' || args.sa_lun < 0) 1116 errx(1, "invalid lun: %s", argv[1]); 1117 } 1118 1119 if (ioctl(fd, SCBUSIOSCAN, &args) != 0) 1120 err(1, "SCBUSIOSCAN"); 1121 1122 return; 1123 } 1124 1125 /* 1126 * bus_detach: 1127 * 1128 * detach SCSI devices from a bus. 1129 */ 1130 void 1131 bus_detach(int argc, char *argv[]) 1132 { 1133 struct scbusiodetach_args args; 1134 char *cp; 1135 1136 /* Must have two args: target lun */ 1137 if (argc != 2) 1138 usage(); 1139 1140 if (strcmp(argv[0], "any") == 0 || strcmp(argv[0], "all") == 0) 1141 args.sa_target = -1; 1142 else { 1143 args.sa_target = strtol(argv[0], &cp, 10); 1144 if (*cp != '\0' || args.sa_target < 0) 1145 errx(1, "invalid target: %s", argv[0]); 1146 } 1147 1148 if (strcmp(argv[1], "any") == 0 || strcmp(argv[1], "all") == 0) 1149 args.sa_lun = -1; 1150 else { 1151 args.sa_lun = strtol(argv[1], &cp, 10); 1152 if (*cp != '\0' || args.sa_lun < 0) 1153 errx(1, "invalid lun: %s", argv[1]); 1154 } 1155 1156 if (ioctl(fd, SCBUSIODETACH, &args) != 0) 1157 err(1, "SCBUSIODETACH"); 1158 1159 return; 1160 } 1161