scsictl.c revision 1.40
1/* $NetBSD: scsictl.c,v 1.40 2022/08/21 12:44:16 mlelstv 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 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33/* 34 * scsictl(8) - a program to manipulate SCSI devices and busses. 35 */ 36#include <sys/cdefs.h> 37 38#ifndef lint 39__RCSID("$NetBSD: scsictl.c,v 1.40 2022/08/21 12:44:16 mlelstv Exp $"); 40#endif 41 42 43#include <sys/param.h> 44#include <sys/ioctl.h> 45#include <sys/scsiio.h> 46#include <err.h> 47#include <errno.h> 48#include <fcntl.h> 49#include <limits.h> 50#include <stdio.h> 51#include <stdlib.h> 52#include <string.h> 53#include <unistd.h> 54#include <util.h> 55 56#include <dev/scsipi/scsi_spc.h> 57#include <dev/scsipi/scsipi_all.h> 58#include <dev/scsipi/scsi_disk.h> 59#include <dev/scsipi/scsipiconf.h> 60 61#include "extern.h" 62 63struct command { 64 const char *cmd_name; 65 const char *arg_names; 66 void (*cmd_func)(int, char *[]); 67}; 68 69__dead static void usage(void); 70 71static int fd; /* file descriptor for device */ 72const char *dvname; /* device name */ 73static char dvname_store[MAXPATHLEN]; /* for opendisk(3) */ 74static const char *cmdname; /* command user issued */ 75static struct scsi_addr dvaddr; /* SCSI device's address */ 76 77static void device_defects(int, char *[]); 78static void device_format(int, char *[]); 79static void device_identify(int, char *[]); 80static void device_reassign(int, char *[]); 81static void device_release(int, char *[]); 82static void device_reserve(int, char *[]); 83static void device_reset(int, char *[]); 84static void device_debug(int, char *[]); 85static void device_prevent(int, char *[]); 86static void device_allow(int, char *[]); 87static void device_start(int, char *[]); 88static void device_stop(int, char *[]); 89static void device_tur(int, char *[]); 90static void device_getcache(int, char *[]); 91static void device_setcache(int, char *[]); 92static void device_flushcache(int, char *[]); 93static void device_setspeed(int, char *[]); 94static void device_getrealloc(int, char *[]); 95static void device_setrealloc(int, char *[]); 96static void device_reportluns(int, char *[]); 97 98static struct command device_commands[] = { 99 { "defects", "[primary] [grown] [block|byte|physical]", 100 device_defects }, 101 { "format", "[blocksize [immediate]]", device_format }, 102 { "identify", "", device_identify }, 103 { "reassign", "blkno [blkno [...]]", device_reassign }, 104 { "release", "", device_release }, 105 { "reserve", "", device_reserve }, 106 { "reset", "", device_reset }, 107 { "debug", "level", device_debug }, 108 { "prevent", "", device_prevent }, 109 { "allow", "", device_allow }, 110 { "start", "", device_start }, 111 { "stop", "", device_stop }, 112 { "tur", "", device_tur }, 113 { "getcache", "", device_getcache }, 114 { "setcache", "none|r|w|rw [save]", device_setcache }, 115 { "flushcache", "", device_flushcache }, 116 { "setspeed", "[speed]", device_setspeed }, 117 { "getrealloc", "", device_getrealloc }, 118 { "setrealloc", "none|r|w|rw [save]", device_setrealloc }, 119 { "reportluns", "normal|wellknown|all|#", device_reportluns }, 120 { NULL, NULL, NULL }, 121}; 122 123static void bus_reset(int, char *[]); 124static void bus_scan(int, char *[]); 125static void bus_detach(int, char *[]); 126 127static 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 134int 135main(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 (*commands[i].cmd_func)(argc, argv); 191 exit(0); 192} 193 194static void 195usage(void) 196{ 197 int i; 198 199 fprintf(stderr, "usage: %s device command [arg [...]]\n", 200 getprogname()); 201 202 fprintf(stderr, " Commands pertaining to scsi devices:\n"); 203 for (i=0; device_commands[i].cmd_name != NULL; i++) 204 fprintf(stderr, "\t%s %s\n", device_commands[i].cmd_name, 205 device_commands[i].arg_names); 206 fprintf(stderr, " Commands pertaining to scsi busses:\n"); 207 for (i=0; bus_commands[i].cmd_name != NULL; i++) 208 fprintf(stderr, "\t%s %s\n", bus_commands[i].cmd_name, 209 bus_commands[i].arg_names); 210 fprintf(stderr, " Use `any' or `all' to wildcard target or lun\n"); 211 212 exit(1); 213} 214 215/* 216 * DEVICE COMMANDS 217 */ 218 219/* 220 * device_read_defect: 221 * 222 * Read primary and/or growth defect list in physical or block 223 * format from a direct access device. 224 * 225 * XXX Does not handle very large defect lists. Needs SCSI3 12 226 * byte READ DEFECT DATA command. 227 */ 228 229static void print_bf_dd(union scsi_defect_descriptor *); 230static void print_bfif_dd(union scsi_defect_descriptor *); 231static void print_psf_dd(union scsi_defect_descriptor *); 232 233static void 234device_defects(int argc, char *argv[]) 235{ 236 struct scsi_read_defect_data cmd; 237 struct scsi_read_defect_data_data *data; 238 size_t dlen; 239 int i, dlfmt = -1; 240 int defects; 241 char msg[256]; 242 void (*pfunc)(union scsi_defect_descriptor *); 243#define RDD_P_G_MASK 0x18 244#define RDD_DLF_MASK 0x7 245 246 dlen = USHRT_MAX; /* XXX - this may not be enough room 247 * for all of the defects. 248 */ 249 data = malloc(dlen); 250 if (data == NULL) 251 errx(1, "unable to allocate defect list"); 252 memset(data, 0, dlen); 253 memset(&cmd, 0, sizeof(cmd)); 254 defects = 0; 255 pfunc = NULL; 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 */ 389static void 390print_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 */ 406static void 407print_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 */ 430static void 431print_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 */ 454static void 455device_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: %d\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, SCCMD_WRITE); 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(tcmd)); 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, sizeof(sense)); 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 its SCSI bus, 646 * target, lun, and its vendor/product/revision information. 647 */ 648static void 649device_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 */ 691static void 692device_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 device. 743 */ 744#ifndef SCSI_RELEASE 745#define SCSI_RELEASE 0x17 746#endif 747static void 748device_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 device. 771 */ 772#ifndef SCSI_RESERVE 773#define SCSI_RESERVE 0x16 774#endif 775static void 776device_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 */ 798static void 799device_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 */ 818static void 819device_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 */ 839static void 840device_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 */ 872static void 873device_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 flags = 0; 887 byte2 = 0; 888 if (strcmp(argv[0], "none") == 0) 889 flags = CACHING_RCD; 890 else if (strcmp(argv[0], "r") == 0) 891 flags = 0; 892 else if (strcmp(argv[0], "w") == 0) 893 flags = CACHING_RCD|CACHING_WCE; 894 else if (strcmp(argv[0], "rw") == 0) 895 flags = CACHING_WCE; 896 else 897 usage(); 898 899 if (argc == 2) { 900 if (strcmp(argv[1], "save") == 0) 901 byte2 = SMS_SP; 902 else 903 usage(); 904 } 905 906 scsi_mode_sense(fd, 0x08, 0x00, &data, sizeof(data)); 907 908 data.caching_params.pg_code &= PGCODE_MASK; 909 data.caching_params.flags = 910 (data.caching_params.flags & ~(CACHING_RCD|CACHING_WCE)) | flags; 911 912 data.caching_params.cache_segment_size[0] = 0; 913 data.caching_params.cache_segment_size[1] = 0; 914 915 data.header.data_length = 0; 916 917 dlen = sizeof(data.header) + sizeof(data.blk_desc) + 2 + 918 data.caching_params.pg_length; 919 920 scsi_mode_select(fd, byte2, &data, dlen); 921} 922 923/* 924 * device_flushcache: 925 * 926 * Issue a FLUSH CACHE command to a SCSI device. 927 */ 928#ifndef SCSI_FLUSHCACHE 929#define SCSI_FLUSHCACHE 0x35 930#endif 931static void 932device_flushcache(int argc, char *argv[]) 933{ 934 struct scsi_test_unit_ready cmd; /* close enough */ 935 936 /* No arguments. */ 937 if (argc != 0) 938 usage(); 939 940 memset(&cmd, 0, sizeof(cmd)); 941 942 cmd.opcode = SCSI_FLUSHCACHE; 943 944 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 945 946 return; 947} 948 949/* 950 * device_setspeed: 951 * 952 * Set rotation speed to a CD/DVD drive. 953 */ 954static void 955device_setspeed(int argc, char *argv[]) 956{ 957 u_char cmd[11]; 958 u_char pd[28]; 959 u_int32_t speed; 960 961 if (argc != 1) 962 usage(); 963 964 speed = atoi(argv[0]) * 177; 965 966 memset(&pd, 0, sizeof(pd)); 967 if (speed == 0) 968 pd[0] = 4; /* restore drive defaults */ 969 pd[8] = 0xff; 970 pd[9] = 0xff; 971 pd[10] = 0xff; 972 pd[11] = 0xff; 973 pd[12] = pd[20] = (speed >> 24) & 0xff; 974 pd[13] = pd[21] = (speed >> 16) & 0xff; 975 pd[14] = pd[22] = (speed >> 8) & 0xff; 976 pd[15] = pd[23] = speed & 0xff; 977 pd[18] = pd[26] = 1000 >> 8; 978 pd[19] = pd[27] = 1000 & 0xff; 979 980 memset(&cmd, 0, sizeof(cmd)); 981 cmd[0] = 0xb6; 982 cmd[10] = sizeof(pd); 983 984 scsi_command(fd, &cmd, sizeof(cmd), pd, sizeof(pd), 10000, SCCMD_WRITE); 985 986 return; 987} 988 989/* 990 * device_reportluns: 991 * 992 * Report the known LUNs to which the initiator can send commands 993 */ 994static void 995device_reportluns(int argc, char *argv[]) 996{ 997 struct scsi_report_luns cmd; 998 struct { 999 struct scsi_report_luns_header header; 1000 struct scsi_report_luns_lun desc[1]; 1001 } *data; 1002 u_int32_t dlen, len; 1003 u_int64_t lun; 1004 size_t count, idx; 1005 unsigned long sel; 1006 char *endp; 1007 int i; 1008 1009 dlen = USHRT_MAX; /* good for > 8000 LUNs */ 1010 data = malloc(dlen); 1011 if (data == NULL) 1012 errx(1, "unable to allocate lun report"); 1013 1014 memset(&cmd, 0, sizeof(cmd)); 1015 cmd.opcode = SCSI_REPORT_LUNS; 1016 cmd.selectreport = SELECTREPORT_NORMAL; 1017 1018 /* determine which report to read. */ 1019 for (i = 0; i < argc; i++) { 1020 if (strcmp("normal", argv[i]) == 0) { 1021 cmd.selectreport = SELECTREPORT_NORMAL; 1022 continue; 1023 } 1024 if (strcmp("wellknown", argv[i]) == 0) { 1025 cmd.selectreport = SELECTREPORT_WELLKNOWN; 1026 continue; 1027 } 1028 if (strcmp("all", argv[i]) == 0) { 1029 cmd.selectreport = SELECTREPORT_ALL; 1030 continue; 1031 } 1032 sel = strtoul(argv[i], &endp, 0); 1033 if (*endp != '\0' || sel > 255) 1034 errx(1, "Unknown select report '%s'", argv[i]); 1035 cmd.selectreport = sel; 1036 } 1037 1038 _lto4b(dlen, &cmd.alloclen[0]); 1039 cmd.control = 0x00; 1040 1041 scsi_command(fd, &cmd, sizeof(cmd), data, dlen, 30000, SCCMD_READ); 1042 1043 len = _4btol(data->header.length); 1044 if (len > dlen) { 1045 /* XXX reallocate and retry */ 1046 printf("%s: report truncated %" PRIu32 "to %" PRIu32 "\n", 1047 dvname, len, dlen); 1048 len = dlen; 1049 } 1050 1051 count = len / sizeof(data->desc[0]); 1052 1053 for (idx=0; idx<count; ++idx) { 1054 lun = _8btol(data->desc[idx].lun); 1055 1056 /* 1057 * swizzle bits so that LUNs 0..255 are 1058 * mapped to numbers 0..255 1059 */ 1060 lun = (lun & 0xffff000000000000ull) >> 48 1061 | (lun & 0x0000ffff00000000ull) >> 16 1062 | (lun & 0x00000000ffff0000ull) << 16 1063 | (lun & 0x000000000000ffffull) << 48; 1064 1065 printf("%s: lun %" PRIu64 "\n", dvname, lun); 1066 } 1067 1068 free(data); 1069} 1070 1071/* 1072 * device_getrealloc: 1073 * 1074 * Get the automatic reallocation parameters for a SCSI disk. 1075 */ 1076static void 1077device_getrealloc(int argc, char *argv[]) 1078{ 1079 struct { 1080 struct scsi_mode_parameter_header_6 header; 1081 struct scsi_general_block_descriptor blk_desc; 1082 struct page_err_recov err_recov_params; 1083 } data; 1084 u_int8_t flags; 1085 1086 /* No arguments. */ 1087 if (argc != 0) 1088 usage(); 1089 1090 scsi_mode_sense(fd, 0x01, 0x00, &data, sizeof(data)); 1091 1092 flags = data.err_recov_params.flags; 1093 if ((flags & (ERR_RECOV_ARRE | ERR_RECOV_AWRE)) == 0) 1094 printf("%s: no automatic reallocation enabled\n", dvname); 1095 else { 1096 printf("%s: automatic read reallocation %senabled\n", dvname, 1097 (flags & ERR_RECOV_ARRE) ? "" : "not "); 1098 printf("%s: automatic write reallocation %senabled\n", dvname, 1099 (flags & ERR_RECOV_AWRE) ? "" : "not "); 1100 } 1101 printf("%s: error recovery parameters are %ssavable\n", dvname, 1102 (data.err_recov_params.pg_code & PGCODE_PS) ? "" : "not "); 1103} 1104 1105/* 1106 * device_setrealloc: 1107 * 1108 * Set the automatic reallocation parameters for a SCSI disk. 1109 */ 1110static void 1111device_setrealloc(int argc, char *argv[]) 1112{ 1113 struct { 1114 struct scsi_mode_parameter_header_6 header; 1115 struct scsi_general_block_descriptor blk_desc; 1116 struct page_err_recov err_recov_params; 1117 } data; 1118 int dlen; 1119 u_int8_t flags, byte2; 1120 1121 if (argc > 2 || argc == 0) 1122 usage(); 1123 1124 flags = 0; 1125 byte2 = 0; 1126 if (strcmp(argv[0], "none") == 0) 1127 flags = 0; 1128 else if (strcmp(argv[0], "r") == 0) 1129 flags = ERR_RECOV_ARRE; 1130 else if (strcmp(argv[0], "w") == 0) 1131 flags = ERR_RECOV_AWRE; 1132 else if (strcmp(argv[0], "rw") == 0) 1133 flags = ERR_RECOV_ARRE | ERR_RECOV_AWRE; 1134 else 1135 usage(); 1136 1137 if (argc == 2) { 1138 if (strcmp(argv[1], "save") == 0) 1139 byte2 = SMS_SP; 1140 else 1141 usage(); 1142 } 1143 1144 scsi_mode_sense(fd, 0x01, 0x00, &data, sizeof(data)); 1145 1146 data.err_recov_params.pg_code &= PGCODE_MASK; 1147 data.err_recov_params.flags &= ~(ERR_RECOV_ARRE | ERR_RECOV_AWRE); 1148 data.err_recov_params.flags |= flags; 1149 1150 data.header.data_length = 0; 1151 1152 dlen = sizeof(data.header) + sizeof(data.blk_desc) + 2 + 1153 data.err_recov_params.pg_length; 1154 1155 scsi_mode_select(fd, byte2, &data, dlen); 1156} 1157 1158/* 1159 * device_prevent: 1160 * 1161 * Issue a prevent to a SCSI device. 1162 */ 1163static void 1164device_prevent(int argc, char *argv[]) 1165{ 1166 struct scsi_prevent_allow_medium_removal cmd; 1167 1168 /* No arguments. */ 1169 if (argc != 0) 1170 usage(); 1171 1172 memset(&cmd, 0, sizeof(cmd)); 1173 1174 cmd.opcode = SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL; 1175 cmd.how = SPAMR_PREVENT_DT; /* XXX SMAMR_PREVENT_ALL? */ 1176 1177 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 1178 1179 return; 1180} 1181 1182/* 1183 * device_allow: 1184 * 1185 * Issue a stop to a SCSI device. 1186 */ 1187static void 1188device_allow(int argc, char *argv[]) 1189{ 1190 struct scsi_prevent_allow_medium_removal cmd; 1191 1192 /* No arguments. */ 1193 if (argc != 0) 1194 usage(); 1195 1196 memset(&cmd, 0, sizeof(cmd)); 1197 1198 cmd.opcode = SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL; 1199 cmd.how = SPAMR_ALLOW; 1200 1201 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 1202 1203 return; 1204} 1205 1206/* 1207 * device_start: 1208 * 1209 * Issue a start to a SCSI device. 1210 */ 1211static void 1212device_start(int argc, char *argv[]) 1213{ 1214 struct scsipi_start_stop cmd; 1215 1216 /* No arguments. */ 1217 if (argc != 0) 1218 usage(); 1219 1220 memset(&cmd, 0, sizeof(cmd)); 1221 1222 cmd.opcode = START_STOP; 1223 cmd.how = SSS_START; 1224 1225 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 30000, 0); 1226 1227 return; 1228} 1229 1230/* 1231 * device_stop: 1232 * 1233 * Issue a stop to a SCSI device. 1234 */ 1235static void 1236device_stop(int argc, char *argv[]) 1237{ 1238 struct scsipi_start_stop cmd; 1239 1240 /* No arguments. */ 1241 if (argc != 0) 1242 usage(); 1243 1244 memset(&cmd, 0, sizeof(cmd)); 1245 1246 cmd.opcode = START_STOP; 1247 cmd.how = SSS_STOP; 1248 1249 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 30000, 0); 1250 1251 return; 1252} 1253 1254/* 1255 * device_tur: 1256 * 1257 * Issue a TEST UNIT READY to a SCSI device. 1258 */ 1259static void 1260device_tur(int argc, char *argv[]) 1261{ 1262 struct scsi_test_unit_ready cmd; 1263 1264 /* No arguments. */ 1265 if (argc != 0) 1266 usage(); 1267 1268 memset(&cmd, 0, sizeof(cmd)); 1269 1270 cmd.opcode = SCSI_TEST_UNIT_READY; 1271 1272 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0); 1273 1274 return; 1275} 1276 1277/* 1278 * BUS COMMANDS 1279 */ 1280 1281/* 1282 * bus_reset: 1283 * 1284 * Issue a reset to a SCSI bus. 1285 */ 1286static void 1287bus_reset(int argc, char *argv[]) 1288{ 1289 1290 /* No arguments. */ 1291 if (argc != 0) 1292 usage(); 1293 1294 if (ioctl(fd, SCBUSIORESET, NULL) != 0) 1295 err(1, "SCBUSIORESET"); 1296 1297 return; 1298} 1299 1300/* 1301 * bus_scan: 1302 * 1303 * Rescan a SCSI bus for new devices. 1304 */ 1305static void 1306bus_scan(int argc, char *argv[]) 1307{ 1308 struct scbusioscan_args args; 1309 char *cp; 1310 1311 /* Must have two args: target lun */ 1312 if (argc != 2) 1313 usage(); 1314 1315 if (strcmp(argv[0], "any") == 0 || strcmp(argv[0], "all") == 0) 1316 args.sa_target = -1; 1317 else { 1318 args.sa_target = strtol(argv[0], &cp, 10); 1319 if (*cp != '\0' || args.sa_target < 0) 1320 errx(1, "invalid target: %s", argv[0]); 1321 } 1322 1323 if (strcmp(argv[1], "any") == 0 || strcmp(argv[1], "all") == 0) 1324 args.sa_lun = -1; 1325 else { 1326 args.sa_lun = strtol(argv[1], &cp, 10); 1327 if (*cp != '\0' || args.sa_lun < 0) 1328 errx(1, "invalid lun: %s", argv[1]); 1329 } 1330 1331 if (ioctl(fd, SCBUSIOSCAN, &args) != 0) 1332 err(1, "SCBUSIOSCAN"); 1333 1334 return; 1335} 1336 1337/* 1338 * bus_detach: 1339 * 1340 * detach SCSI devices from a bus. 1341 */ 1342static void 1343bus_detach(int argc, char *argv[]) 1344{ 1345 struct scbusiodetach_args args; 1346 char *cp; 1347 1348 /* Must have two args: target lun */ 1349 if (argc != 2) 1350 usage(); 1351 1352 if (strcmp(argv[0], "any") == 0 || strcmp(argv[0], "all") == 0) 1353 args.sa_target = -1; 1354 else { 1355 args.sa_target = strtol(argv[0], &cp, 10); 1356 if (*cp != '\0' || args.sa_target < 0) 1357 errx(1, "invalid target: %s", argv[0]); 1358 } 1359 1360 if (strcmp(argv[1], "any") == 0 || strcmp(argv[1], "all") == 0) 1361 args.sa_lun = -1; 1362 else { 1363 args.sa_lun = strtol(argv[1], &cp, 10); 1364 if (*cp != '\0' || args.sa_lun < 0) 1365 errx(1, "invalid lun: %s", argv[1]); 1366 } 1367 1368 if (ioctl(fd, SCBUSIODETACH, &args) != 0) 1369 err(1, "SCBUSIODETACH"); 1370 1371 return; 1372} 1373