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