1 /* $NetBSD: scsictl.c,v 1.27 2005/02/21 00:29:08 thorpej 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.27 2005/02/21 00:29:08 thorpej 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/scsi_spc.h> 64 #include <dev/scsipi/scsipi_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 scsi_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 scsi_mode_parameter_header_6 header; 473 struct scsi_general_block_descriptor blk_desc; 474 struct page_disk_format format_page; 475 } mode_page; 476 struct { 477 struct scsi_mode_parameter_header_6 header; 478 struct scsi_general_block_descriptor 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 = SSD_SENSE_KEY(sense.flags)) == 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 = 545 sizeof(struct scsi_general_block_descriptor); 546 /* 547 * blklen in desc is 3 bytes with a leading reserved byte 548 */ 549 _lto4b(blksize, &data_select.blk_desc.reserved); 550 551 /* 552 * Issue Mode Select to modify the device blocksize to be 553 * used on the Format. The modified device geometry will 554 * be stored as Current and Saved Page 3 parameters when 555 * the Format completes. 556 */ 557 scsi_mode_select(fd, 0, &data_select, sizeof(data_select)); 558 559 /* 560 * Since user specified a specific block size make sure it 561 * gets stored in the device when the format completes. 562 * 563 * Also scrub the defect list back to the manufacturers 564 * original. 565 */ 566 cmd.flags = SFU_CMPLST | SFU_FMTDATA; 567 } 568 569 memset(&dfl, 0, sizeof(dfl)); 570 571 if (argc > 1 && strncmp(argv[1], "imm", 3) == 0) { 572 /* 573 * Signal target for an immediate return from Format. 574 * 575 * We'll poll for completion status. 576 */ 577 dfl.header.flags = DLH_IMMED; 578 immediate = 1; 579 } else { 580 immediate = 0; 581 } 582 583 scsi_command(fd, &cmd, sizeof(cmd), &dfl, sizeof(dfl), 584 8 * 60 * 60 * 1000, 0); 585 586 /* 587 * Poll device for completion of Format 588 */ 589 if (immediate) { 590 i = 0; 591 printf("formatting."); 592 fflush(stdout); 593 do { 594 scsireq_t req; 595 struct scsi_test_unit_ready tcmd; 596 597 memset(&tcmd, 0, sizeof(cmd)); 598 tcmd.opcode = SCSI_TEST_UNIT_READY; 599 600 memset(&req, 0, sizeof(req)); 601 memcpy(req.cmd, &tcmd, 6); 602 req.cmdlen = 6; 603 req.timeout = 10000; 604 req.senselen = SENSEBUFLEN; 605 606 if (ioctl(fd, SCIOCCOMMAND, &req) == -1) { 607 err(1, "SCIOCCOMMAND"); 608 } 609 610 if (req.retsts == SCCMD_OK) { 611 break; 612 } else if (req.retsts == SCCMD_TIMEOUT) { 613 fprintf(stderr, "%s: SCSI command timed out", 614 dvname); 615 break; 616 } else if (req.retsts == SCCMD_BUSY) { 617 fprintf(stderr, "%s: device is busy", 618 dvname); 619 break; 620 } else if (req.retsts != SCCMD_SENSE) { 621 fprintf(stderr, 622 "%s: device had unknown status %x", dvname, 623 req.retsts); 624 break; 625 } 626 memcpy(&sense, req.sense, SENSEBUFLEN); 627 if (sense.sks.sks_bytes[0] & SSD_SKSV) { 628 j = (sense.sks.sks_bytes[1] << 8) | 629 (sense.sks.sks_bytes[2]); 630 if (j >= complete[i]) { 631 printf(".%d0%%.", ++i); 632 fflush(stdout); 633 } 634 } 635 sleep(10); 636 } while (SSD_SENSE_KEY(sense.flags) == SKEY_NOT_READY); 637 printf(".100%%..done.\n"); 638 } 639 return; 640 } 641 642 /* 643 * device_identify: 644 * 645 * Display the identity of the device, including it's SCSI bus, 646 * target, lun, and it's vendor/product/revision information. 647 */ 648 void 649 device_identify(int argc, char *argv[]) 650 { 651 struct scsipi_inquiry_data inqbuf; 652 struct scsipi_inquiry cmd; 653 654 /* x4 in case every character is escaped, +1 for NUL. */ 655 char vendor[(sizeof(inqbuf.vendor) * 4) + 1], 656 product[(sizeof(inqbuf.product) * 4) + 1], 657 revision[(sizeof(inqbuf.revision) * 4) + 1]; 658 659 /* No arguments. */ 660 if (argc != 0) 661 usage(); 662 663 memset(&cmd, 0, sizeof(cmd)); 664 memset(&inqbuf, 0, sizeof(inqbuf)); 665 666 cmd.opcode = INQUIRY; 667 cmd.length = sizeof(inqbuf); 668 669 scsi_command(fd, &cmd, sizeof(cmd), &inqbuf, sizeof(inqbuf), 670 10000, SCCMD_READ); 671 672 scsi_strvis(vendor, sizeof(vendor), inqbuf.vendor, 673 sizeof(inqbuf.vendor)); 674 scsi_strvis(product, sizeof(product), inqbuf.product, 675 sizeof(inqbuf.product)); 676 scsi_strvis(revision, sizeof(revision), inqbuf.revision, 677 sizeof(inqbuf.revision)); 678 679 printf("%s: scsibus%d target %d lun %d <%s, %s, %s>\n", 680 dvname, dvaddr.addr.scsi.scbus, dvaddr.addr.scsi.target, 681 dvaddr.addr.scsi.lun, vendor, product, revision); 682 683 return; 684 } 685 686 /* 687 * device_reassign: 688 * 689 * Reassign bad blocks on a direct access device. 690 */ 691 void 692 device_reassign(int argc, char *argv[]) 693 { 694 struct scsi_reassign_blocks cmd; 695 struct scsi_reassign_blocks_data *data; 696 size_t dlen; 697 u_int32_t blkno; 698 int i; 699 char *cp; 700 701 /* We get a list of block numbers. */ 702 if (argc < 1) 703 usage(); 704 705 /* 706 * Allocate the reassign blocks descriptor. The 4 comes from the 707 * size of the block address in the defect descriptor. 708 */ 709 dlen = sizeof(struct scsi_reassign_blocks_data) + ((argc - 1) * 4); 710 data = malloc(dlen); 711 if (data == NULL) 712 errx(1, "unable to allocate defect descriptor"); 713 memset(data, 0, dlen); 714 715 cmd.opcode = SCSI_REASSIGN_BLOCKS; 716 cmd.byte2 = 0; 717 cmd.unused[0] = 0; 718 cmd.unused[1] = 0; 719 cmd.unused[2] = 0; 720 cmd.control = 0; 721 722 /* Defect descriptor length. */ 723 _lto2b(argc * 4, data->length); 724 725 /* Build the defect descriptor list. */ 726 for (i = 0; i < argc; i++) { 727 blkno = strtoul(argv[i], &cp, 10); 728 if (*cp != '\0') 729 errx(1, "invalid block number: %s", argv[i]); 730 _lto4b(blkno, data->defect_descriptor[i].dlbaddr); 731 } 732 733 scsi_command(fd, &cmd, sizeof(cmd), data, dlen, 30000, SCCMD_WRITE); 734 735 free(data); 736 return; 737 } 738 739 /* 740 * device_release: 741 * 742 * Issue a RELEASE command to a SCSI drevice 743 */ 744 #ifndef SCSI_RELEASE 745 #define SCSI_RELEASE 0x17 746 #endif 747 void 748 device_release(int argc, char *argv[]) 749 { 750 struct scsi_test_unit_ready cmd; /* close enough */ 751 752 /* No arguments. */ 753 if (argc != 0) 754 usage(); 755 756 memset(&cmd, 0, sizeof(cmd)); 757 758 cmd.opcode = SCSI_RELEASE; 759 760 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 761 762 return; 763 } 764 765 766 767 /* 768 * device_reserve: 769 * 770 * Issue a RESERVE command to a SCSI drevice 771 */ 772 #ifndef SCSI_RESERVE 773 #define SCSI_RESERVE 0x16 774 #endif 775 void 776 device_reserve(int argc, char *argv[]) 777 { 778 struct scsi_test_unit_ready cmd; /* close enough */ 779 780 /* No arguments. */ 781 if (argc != 0) 782 usage(); 783 784 memset(&cmd, 0, sizeof(cmd)); 785 786 cmd.opcode = SCSI_RESERVE; 787 788 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 789 790 return; 791 } 792 793 /* 794 * device_reset: 795 * 796 * Issue a reset to a SCSI device. 797 */ 798 void 799 device_reset(int argc, char *argv[]) 800 { 801 802 /* No arguments. */ 803 if (argc != 0) 804 usage(); 805 806 if (ioctl(fd, SCIOCRESET, NULL) != 0) 807 err(1, "SCIOCRESET"); 808 809 return; 810 } 811 812 /* 813 * device_debug: 814 * 815 * Set debug level to a SCSI device. 816 * scsipi will print anything iff SCSIPI_DEBUG set in config. 817 */ 818 void 819 device_debug(int argc, char *argv[]) 820 { 821 int lvl; 822 823 if (argc < 1) 824 usage(); 825 826 lvl = atoi(argv[0]); 827 828 if (ioctl(fd, SCIOCDEBUG, &lvl) != 0) 829 err(1, "SCIOCDEBUG"); 830 831 return; 832 } 833 834 /* 835 * device_getcache: 836 * 837 * Get the caching parameters for a SCSI disk. 838 */ 839 void 840 device_getcache(int argc, char *argv[]) 841 { 842 struct { 843 struct scsi_mode_parameter_header_6 header; 844 struct scsi_general_block_descriptor blk_desc; 845 struct page_caching caching_params; 846 } data; 847 848 /* No arguments. */ 849 if (argc != 0) 850 usage(); 851 852 scsi_mode_sense(fd, 0x08, 0x00, &data, sizeof(data)); 853 854 if ((data.caching_params.flags & (CACHING_RCD|CACHING_WCE)) == 855 CACHING_RCD) 856 printf("%s: no caches enabled\n", dvname); 857 else { 858 printf("%s: read cache %senabled\n", dvname, 859 (data.caching_params.flags & CACHING_RCD) ? "not " : ""); 860 printf("%s: write-back cache %senabled\n", dvname, 861 (data.caching_params.flags & CACHING_WCE) ? "" : "not "); 862 } 863 printf("%s: caching parameters are %ssavable\n", dvname, 864 (data.caching_params.pg_code & PGCODE_PS) ? "" : "not "); 865 } 866 867 /* 868 * device_setcache: 869 * 870 * Set cache enables for a SCSI disk. 871 */ 872 void 873 device_setcache(int argc, char *argv[]) 874 { 875 struct { 876 struct scsi_mode_parameter_header_6 header; 877 struct scsi_general_block_descriptor blk_desc; 878 struct page_caching caching_params; 879 } data; 880 int dlen; 881 u_int8_t flags, byte2; 882 883 if (argc > 2 || argc == 0) 884 usage(); 885 886 if (strcmp(argv[0], "none") == 0) 887 flags = CACHING_RCD; 888 else if (strcmp(argv[0], "r") == 0) 889 flags = 0; 890 else if (strcmp(argv[0], "w") == 0) 891 flags = CACHING_RCD|CACHING_WCE; 892 else if (strcmp(argv[0], "rw") == 0) 893 flags = CACHING_WCE; 894 else 895 usage(); 896 897 if (argc == 2) { 898 if (strcmp(argv[1], "save") == 0) 899 byte2 = SMS_SP; 900 else 901 usage(); 902 } 903 904 scsi_mode_sense(fd, 0x08, 0x00, &data, sizeof(data)); 905 906 data.caching_params.pg_code &= PGCODE_MASK; 907 data.caching_params.flags = 908 (data.caching_params.flags & ~(CACHING_RCD|CACHING_WCE)) | flags; 909 910 data.caching_params.cache_segment_size[0] = 0; 911 data.caching_params.cache_segment_size[1] = 0; 912 913 data.header.data_length = 0; 914 915 dlen = sizeof(data.header) + sizeof(data.blk_desc) + 2 + 916 data.caching_params.pg_length; 917 918 scsi_mode_select(fd, byte2, &data, dlen); 919 } 920 921 /* 922 * device_flushcache: 923 * 924 * Issue a FLUSH CACHE command to a SCSI drevice 925 */ 926 #ifndef SCSI_FLUSHCACHE 927 #define SCSI_FLUSHCACHE 0x35 928 #endif 929 void 930 device_flushcache(int argc, char *argv[]) 931 { 932 struct scsi_test_unit_ready cmd; /* close enough */ 933 934 /* No arguments. */ 935 if (argc != 0) 936 usage(); 937 938 memset(&cmd, 0, sizeof(cmd)); 939 940 cmd.opcode = SCSI_FLUSHCACHE; 941 942 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 943 944 return; 945 } 946 947 /* 948 * device_prevent: 949 * 950 * Issue a prevent to a SCSI device. 951 */ 952 void 953 device_prevent(int argc, char *argv[]) 954 { 955 struct scsi_prevent_allow_medium_removal cmd; 956 957 /* No arguments. */ 958 if (argc != 0) 959 usage(); 960 961 memset(&cmd, 0, sizeof(cmd)); 962 963 cmd.opcode = SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL; 964 cmd.how = SPAMR_PREVENT_DT; /* XXX SMAMR_PREVENT_ALL? */ 965 966 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 967 968 return; 969 } 970 971 /* 972 * device_allow: 973 * 974 * Issue a stop to a SCSI device. 975 */ 976 void 977 device_allow(int argc, char *argv[]) 978 { 979 struct scsi_prevent_allow_medium_removal cmd; 980 981 /* No arguments. */ 982 if (argc != 0) 983 usage(); 984 985 memset(&cmd, 0, sizeof(cmd)); 986 987 cmd.opcode = SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL; 988 cmd.how = SPAMR_ALLOW; 989 990 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 991 992 return; 993 } 994 995 /* 996 * device_start: 997 * 998 * Issue a start to a SCSI device. 999 */ 1000 void 1001 device_start(int argc, char *argv[]) 1002 { 1003 struct scsipi_start_stop cmd; 1004 1005 /* No arguments. */ 1006 if (argc != 0) 1007 usage(); 1008 1009 memset(&cmd, 0, sizeof(cmd)); 1010 1011 cmd.opcode = START_STOP; 1012 cmd.how = SSS_START; 1013 1014 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 30000, 0); 1015 1016 return; 1017 } 1018 1019 /* 1020 * device_stop: 1021 * 1022 * Issue a stop to a SCSI device. 1023 */ 1024 void 1025 device_stop(int argc, char *argv[]) 1026 { 1027 struct scsipi_start_stop cmd; 1028 1029 /* No arguments. */ 1030 if (argc != 0) 1031 usage(); 1032 1033 memset(&cmd, 0, sizeof(cmd)); 1034 1035 cmd.opcode = START_STOP; 1036 cmd.how = SSS_STOP; 1037 1038 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 30000, 0); 1039 1040 return; 1041 } 1042 1043 /* 1044 * device_tur: 1045 * 1046 * Issue a TEST UNIT READY to a SCSI drevice 1047 */ 1048 void 1049 device_tur(int argc, char *argv[]) 1050 { 1051 struct scsi_test_unit_ready cmd; 1052 1053 /* No arguments. */ 1054 if (argc != 0) 1055 usage(); 1056 1057 memset(&cmd, 0, sizeof(cmd)); 1058 1059 cmd.opcode = SCSI_TEST_UNIT_READY; 1060 1061 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 1062 1063 return; 1064 } 1065 1066 /* 1067 * BUS COMMANDS 1068 */ 1069 1070 /* 1071 * bus_reset: 1072 * 1073 * Issue a reset to a SCSI bus. 1074 */ 1075 void 1076 bus_reset(int argc, char *argv[]) 1077 { 1078 1079 /* No arguments. */ 1080 if (argc != 0) 1081 usage(); 1082 1083 if (ioctl(fd, SCBUSIORESET, NULL) != 0) 1084 err(1, "SCBUSIORESET"); 1085 1086 return; 1087 } 1088 1089 /* 1090 * bus_scan: 1091 * 1092 * Rescan a SCSI bus for new devices. 1093 */ 1094 void 1095 bus_scan(int argc, char *argv[]) 1096 { 1097 struct scbusioscan_args args; 1098 char *cp; 1099 1100 /* Must have two args: target lun */ 1101 if (argc != 2) 1102 usage(); 1103 1104 if (strcmp(argv[0], "any") == 0 || strcmp(argv[0], "all") == 0) 1105 args.sa_target = -1; 1106 else { 1107 args.sa_target = strtol(argv[0], &cp, 10); 1108 if (*cp != '\0' || args.sa_target < 0) 1109 errx(1, "invalid target: %s", argv[0]); 1110 } 1111 1112 if (strcmp(argv[1], "any") == 0 || strcmp(argv[1], "all") == 0) 1113 args.sa_lun = -1; 1114 else { 1115 args.sa_lun = strtol(argv[1], &cp, 10); 1116 if (*cp != '\0' || args.sa_lun < 0) 1117 errx(1, "invalid lun: %s", argv[1]); 1118 } 1119 1120 if (ioctl(fd, SCBUSIOSCAN, &args) != 0) 1121 err(1, "SCBUSIOSCAN"); 1122 1123 return; 1124 } 1125 1126 /* 1127 * bus_detach: 1128 * 1129 * detach SCSI devices from a bus. 1130 */ 1131 void 1132 bus_detach(int argc, char *argv[]) 1133 { 1134 struct scbusiodetach_args args; 1135 char *cp; 1136 1137 /* Must have two args: target lun */ 1138 if (argc != 2) 1139 usage(); 1140 1141 if (strcmp(argv[0], "any") == 0 || strcmp(argv[0], "all") == 0) 1142 args.sa_target = -1; 1143 else { 1144 args.sa_target = strtol(argv[0], &cp, 10); 1145 if (*cp != '\0' || args.sa_target < 0) 1146 errx(1, "invalid target: %s", argv[0]); 1147 } 1148 1149 if (strcmp(argv[1], "any") == 0 || strcmp(argv[1], "all") == 0) 1150 args.sa_lun = -1; 1151 else { 1152 args.sa_lun = strtol(argv[1], &cp, 10); 1153 if (*cp != '\0' || args.sa_lun < 0) 1154 errx(1, "invalid lun: %s", argv[1]); 1155 } 1156 1157 if (ioctl(fd, SCBUSIODETACH, &args) != 0) 1158 err(1, "SCBUSIODETACH"); 1159 1160 return; 1161 } 1162