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