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