camcontrol.c revision 41962
1/* 2 * Copyright (c) 1997, 1998 Kenneth D. Merry 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $Id: camcontrol.c,v 1.6 1998/11/12 17:47:24 ken Exp $ 29 */ 30 31#include <sys/ioctl.h> 32#include <sys/types.h> 33#include <stdio.h> 34#include <stdlib.h> 35#include <string.h> 36#include <unistd.h> 37#include <fcntl.h> 38#include <ctype.h> 39#include <err.h> 40 41#include <cam/cam.h> 42#include <cam/cam_debug.h> 43#include <cam/cam_ccb.h> 44#include <cam/scsi/scsi_all.h> 45#include <cam/scsi/scsi_da.h> 46#include <cam/scsi/scsi_pass.h> 47#include <cam/scsi/scsi_message.h> 48#include <camlib.h> 49#include "camcontrol.h" 50 51#define DEFAULT_DEVICE "da" 52#define DEFAULT_UNIT 0 53 54typedef enum { 55 CAM_ARG_NONE = 0x00000000, 56 CAM_ARG_DEVLIST = 0x00000001, 57 CAM_ARG_TUR = 0x00000002, 58 CAM_ARG_INQUIRY = 0x00000003, 59 CAM_ARG_STARTSTOP = 0x00000004, 60 CAM_ARG_RESCAN = 0x00000005, 61 CAM_ARG_READ_DEFECTS = 0x00000006, 62 CAM_ARG_MODE_PAGE = 0x00000007, 63 CAM_ARG_SCSI_CMD = 0x00000008, 64 CAM_ARG_DEVTREE = 0x00000009, 65 CAM_ARG_USAGE = 0x0000000a, 66 CAM_ARG_DEBUG = 0x0000000b, 67 CAM_ARG_RESET = 0x0000000c, 68 CAM_ARG_OPT_MASK = 0x0000000f, 69 CAM_ARG_VERBOSE = 0x00000010, 70 CAM_ARG_DEVICE = 0x00000020, 71 CAM_ARG_BUS = 0x00000040, 72 CAM_ARG_TARGET = 0x00000080, 73 CAM_ARG_LUN = 0x00000100, 74 CAM_ARG_EJECT = 0x00000200, 75 CAM_ARG_UNIT = 0x00000400, 76 CAM_ARG_FORMAT_BLOCK = 0x00000800, 77 CAM_ARG_FORMAT_BFI = 0x00001000, 78 CAM_ARG_FORMAT_PHYS = 0x00002000, 79 CAM_ARG_PLIST = 0x00004000, 80 CAM_ARG_GLIST = 0x00008000, 81 CAM_ARG_GET_SERIAL = 0x00010000, 82 CAM_ARG_GET_STDINQ = 0x00020000, 83 CAM_ARG_GET_XFERRATE = 0x00040000, 84 CAM_ARG_INQ_MASK = 0x00070000, 85 CAM_ARG_MODE_EDIT = 0x00080000, 86 CAM_ARG_PAGE_CNTL = 0x00100000, 87 CAM_ARG_TIMEOUT = 0x00200000, 88 CAM_ARG_CMD_IN = 0x00400000, 89 CAM_ARG_CMD_OUT = 0x00800000, 90 CAM_ARG_DBD = 0x01000000, 91 CAM_ARG_ERR_RECOVER = 0x02000000, 92 CAM_ARG_RETRIES = 0x04000000, 93 CAM_ARG_START_UNIT = 0x08000000, 94 CAM_ARG_DEBUG_INFO = 0x10000000, 95 CAM_ARG_DEBUG_TRACE = 0x20000000, 96 CAM_ARG_DEBUG_SUBTRACE = 0x40000000, 97 CAM_ARG_DEBUG_CDB = 0x80000000, 98 CAM_ARG_FLAG_MASK = 0xfffffff0 99} cam_argmask; 100 101struct camcontrol_opts { 102 char *optname; 103 cam_argmask argnum; 104 const char *subopt; 105}; 106 107extern int optreset; 108 109static const char scsicmd_opts[] = "c:i:o:"; 110static const char readdefect_opts[] = "f:GP"; 111 112struct camcontrol_opts option_table[] = { 113 {"tur", CAM_ARG_TUR, NULL}, 114 {"inquiry", CAM_ARG_INQUIRY, "DSR"}, 115 {"start", CAM_ARG_STARTSTOP | CAM_ARG_START_UNIT, NULL}, 116 {"stop", CAM_ARG_STARTSTOP, NULL}, 117 {"eject", CAM_ARG_STARTSTOP | CAM_ARG_EJECT, NULL}, 118 {"rescan", CAM_ARG_RESCAN, NULL}, 119 {"reset", CAM_ARG_RESET, NULL}, 120 {"cmd", CAM_ARG_SCSI_CMD, scsicmd_opts}, 121 {"command", CAM_ARG_SCSI_CMD, scsicmd_opts}, 122 {"defects", CAM_ARG_READ_DEFECTS, readdefect_opts}, 123 {"defectlist", CAM_ARG_READ_DEFECTS, readdefect_opts}, 124 {"devlist", CAM_ARG_DEVTREE, NULL}, 125 {"periphlist", CAM_ARG_DEVLIST, NULL}, 126 {"modepage", CAM_ARG_MODE_PAGE, "dem:P:"}, 127 {"debug", CAM_ARG_DEBUG, "ITSc"}, 128 {"help", CAM_ARG_USAGE, NULL}, 129 {"-?", CAM_ARG_USAGE, NULL}, 130 {"-h", CAM_ARG_USAGE, NULL}, 131 {NULL, 0, NULL} 132}; 133 134typedef enum { 135 CC_OR_NOT_FOUND, 136 CC_OR_AMBIGUOUS, 137 CC_OR_FOUND 138} camcontrol_optret; 139 140cam_argmask arglist; 141 142 143camcontrol_optret getoption(char *arg, cam_argmask *argnum, char **subopt); 144static int getdevlist(struct cam_device *device); 145static int getdevtree(void); 146static int testunitready(struct cam_device *device, int retry_count, 147 int timeout); 148static int scsistart(struct cam_device *device, int startstop, int loadeject, 149 int retry_count, int timeout); 150static int scsidoinquiry(struct cam_device *device, int argc, char **argv, 151 char *combinedopt, int retry_count, int timeout); 152static int scsiinquiry(struct cam_device *device, int retry_count, int timeout); 153static int scsiserial(struct cam_device *device, int retry_count, int timeout); 154static int scsixferrate(struct cam_device *device); 155static int dorescan_or_reset(int argc, char **argv, int rescan); 156static int rescan_or_reset_bus(int bus, int rescan); 157static int scanlun_or_reset_dev(int bus, int target, int lun, int scan); 158static int readdefects(struct cam_device *device, int argc, char **argv, 159 char *combinedopt, int retry_count, int timeout); 160static void modepage(struct cam_device *device, int argc, char **argv, 161 char *combinedopt, int retry_count, int timeout); 162static int scsicmd(struct cam_device *device, int argc, char **argv, 163 char *combinedopt, int retry_count, int timeout); 164 165camcontrol_optret 166getoption(char *arg, cam_argmask *argnum, char **subopt) 167{ 168 struct camcontrol_opts *opts; 169 int num_matches = 0; 170 171 for (opts = option_table; (opts != NULL) && (opts->optname != NULL); 172 opts++) { 173 if (strncmp(opts->optname, arg, strlen(arg)) == 0) { 174 *argnum = opts->argnum; 175 *subopt = (char *)opts->subopt; 176 if (++num_matches > 1) 177 return(CC_OR_AMBIGUOUS); 178 } 179 } 180 181 if (num_matches > 0) 182 return(CC_OR_FOUND); 183 else 184 return(CC_OR_NOT_FOUND); 185} 186 187static int 188getdevlist(struct cam_device *device) 189{ 190 union ccb *ccb; 191 char status[32]; 192 int error = 0; 193 194 ccb = cam_getccb(device); 195 196 ccb->ccb_h.func_code = XPT_GDEVLIST; 197 ccb->ccb_h.flags = CAM_DIR_NONE; 198 ccb->ccb_h.retry_count = 1; 199 ccb->cgdl.index = 0; 200 ccb->cgdl.status = CAM_GDEVLIST_MORE_DEVS; 201 while (ccb->cgdl.status == CAM_GDEVLIST_MORE_DEVS) { 202 if (cam_send_ccb(device, ccb) < 0) { 203 perror("error getting device list"); 204 cam_freeccb(ccb); 205 return(1); 206 } 207 208 status[0] = '\0'; 209 210 switch (ccb->cgdl.status) { 211 case CAM_GDEVLIST_MORE_DEVS: 212 strcpy(status, "MORE"); 213 break; 214 case CAM_GDEVLIST_LAST_DEVICE: 215 strcpy(status, "LAST"); 216 break; 217 case CAM_GDEVLIST_LIST_CHANGED: 218 strcpy(status, "CHANGED"); 219 break; 220 case CAM_GDEVLIST_ERROR: 221 strcpy(status, "ERROR"); 222 error = 1; 223 break; 224 } 225 226 fprintf(stdout, "%s%d: generation: %d index: %d status: %s\n", 227 ccb->cgdl.periph_name, 228 ccb->cgdl.unit_number, 229 ccb->cgdl.generation, 230 ccb->cgdl.index, 231 status); 232 233 /* 234 * If the list has changed, we need to start over from the 235 * beginning. 236 */ 237 if (ccb->cgdl.status == CAM_GDEVLIST_LIST_CHANGED) 238 ccb->cgdl.index = 0; 239 } 240 241 cam_freeccb(ccb); 242 243 return(error); 244} 245 246static int 247getdevtree(void) 248{ 249 union ccb ccb; 250 int bufsize, i, fd; 251 int need_close = 0; 252 int error = 0; 253 254 if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) { 255 warn("couldn't open %s", XPT_DEVICE); 256 return(1); 257 } 258 259 bzero(&(&ccb.ccb_h)[1], sizeof(struct ccb_dev_match)); 260 261 ccb.ccb_h.func_code = XPT_DEV_MATCH; 262 bufsize = sizeof(struct dev_match_result) * 100; 263 ccb.cdm.match_buf_len = bufsize; 264 ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize); 265 ccb.cdm.num_matches = 0; 266 267 /* 268 * We fetch all nodes, since we display most of them in the default 269 * case, and all in the verbose case. 270 */ 271 ccb.cdm.num_patterns = 0; 272 ccb.cdm.pattern_buf_len = 0; 273 274 /* 275 * We do the ioctl multiple times if necessary, in case there are 276 * more than 100 nodes in the EDT. 277 */ 278 do { 279 if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 280 warn("error sending CAMIOCOMMAND ioctl"); 281 error = 1; 282 break; 283 } 284 285 if ((ccb.ccb_h.status != CAM_REQ_CMP) 286 || ((ccb.cdm.status != CAM_DEV_MATCH_LAST) 287 && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) { 288 fprintf(stderr, "got CAM error %#x, CDM error %d\n", 289 ccb.ccb_h.status, ccb.cdm.status); 290 error = 1; 291 break; 292 } 293 294 for (i = 0; i < ccb.cdm.num_matches; i++) { 295 switch(ccb.cdm.matches[i].type) { 296 case DEV_MATCH_BUS: { 297 struct bus_match_result *bus_result; 298 299 /* 300 * Only print the bus information if the 301 * user turns on the verbose flag. 302 */ 303 if ((arglist & CAM_ARG_VERBOSE) == 0) 304 break; 305 306 bus_result = 307 &ccb.cdm.matches[i].result.bus_result; 308 309 if (need_close) { 310 fprintf(stdout, ")\n"); 311 need_close = 0; 312 } 313 314 fprintf(stdout, "scbus%d on %s%d bus %d:\n", 315 bus_result->path_id, 316 bus_result->dev_name, 317 bus_result->unit_number, 318 bus_result->bus_id); 319 break; 320 } 321 case DEV_MATCH_DEVICE: { 322 struct device_match_result *dev_result; 323 char vendor[16], product[48], revision[16]; 324 char tmpstr[256]; 325 326 dev_result = 327 &ccb.cdm.matches[i].result.device_result; 328 329 cam_strvis(vendor, dev_result->inq_data.vendor, 330 sizeof(dev_result->inq_data.vendor), 331 sizeof(vendor)); 332 cam_strvis(product, 333 dev_result->inq_data.product, 334 sizeof(dev_result->inq_data.product), 335 sizeof(product)); 336 cam_strvis(revision, 337 dev_result->inq_data.revision, 338 sizeof(dev_result->inq_data.revision), 339 sizeof(revision)); 340 sprintf(tmpstr, "<%s %s %s>", vendor, product, 341 revision); 342 if (need_close) { 343 fprintf(stdout, ")\n"); 344 need_close = 0; 345 } 346 347 fprintf(stdout, "%-33s at scbus%d " 348 "target %d lun %d (", 349 tmpstr, 350 dev_result->path_id, 351 dev_result->target_id, 352 dev_result->target_lun); 353 break; 354 } 355 case DEV_MATCH_PERIPH: { 356 struct periph_match_result *periph_result; 357 358 periph_result = 359 &ccb.cdm.matches[i].result.periph_result; 360 361 if (need_close) 362 fprintf(stdout, ","); 363 364 fprintf(stdout, "%s%d", 365 periph_result->periph_name, 366 periph_result->unit_number); 367 368 need_close = 1; 369 break; 370 } 371 default: 372 fprintf(stdout, "unknown match type\n"); 373 break; 374 } 375 } 376 377 } while ((ccb.ccb_h.status == CAM_REQ_CMP) 378 && (ccb.cdm.status == CAM_DEV_MATCH_MORE)); 379 380 if (need_close) 381 fprintf(stdout, ")\n"); 382 383 close(fd); 384 385 return(error); 386} 387 388static int 389testunitready(struct cam_device *device, int retry_count, int timeout) 390{ 391 int error = 0; 392 union ccb *ccb; 393 394 ccb = cam_getccb(device); 395 396 scsi_test_unit_ready(&ccb->csio, 397 /* retries */ retry_count, 398 /* cbfcnp */ NULL, 399 /* tag_action */ MSG_SIMPLE_Q_TAG, 400 /* sense_len */ SSD_FULL_SIZE, 401 /* timeout */ timeout ? timeout : 5000); 402 403 /* Disable freezing the device queue */ 404 ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 405 406 if (arglist & CAM_ARG_ERR_RECOVER) 407 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 408 409 if (cam_send_ccb(device, ccb) < 0) { 410 perror("error sending test unit ready"); 411 412 if (arglist & CAM_ARG_VERBOSE) { 413 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 414 CAM_SCSI_STATUS_ERROR) 415 scsi_sense_print(device, &ccb->csio, stderr); 416 else 417 fprintf(stderr, "CAM status is %#x\n", 418 ccb->ccb_h.status); 419 } 420 421 cam_freeccb(ccb); 422 return(1); 423 } 424 425 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 426 fprintf(stdout, "Unit is ready\n"); 427 else { 428 fprintf(stdout, "Unit is not ready\n"); 429 error = 1; 430 431 if (arglist & CAM_ARG_VERBOSE) { 432 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 433 CAM_SCSI_STATUS_ERROR) 434 scsi_sense_print(device, &ccb->csio, stderr); 435 else 436 fprintf(stderr, "CAM status is %#x\n", 437 ccb->ccb_h.status); 438 } 439 } 440 441 cam_freeccb(ccb); 442 443 return(error); 444} 445 446static int 447scsistart(struct cam_device *device, int startstop, int loadeject, 448 int retry_count, int timeout) 449{ 450 union ccb *ccb; 451 int error = 0; 452 453 ccb = cam_getccb(device); 454 455 /* 456 * If we're stopping, send an ordered tag so the drive in question 457 * will finish any previously queued writes before stopping. If 458 * the device isn't capable of tagged queueing, or if tagged 459 * queueing is turned off, the tag action is a no-op. 460 */ 461 scsi_start_stop(&ccb->csio, 462 /* retries */ retry_count, 463 /* cbfcnp */ NULL, 464 /* tag_action */ startstop ? MSG_SIMPLE_Q_TAG : 465 MSG_ORDERED_Q_TAG, 466 /* start/stop */ startstop, 467 /* load_eject */ loadeject, 468 /* immediate */ 0, 469 /* sense_len */ SSD_FULL_SIZE, 470 /* timeout */ timeout ? timeout : 120000); 471 472 /* Disable freezing the device queue */ 473 ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 474 475 if (arglist & CAM_ARG_ERR_RECOVER) 476 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 477 478 if (cam_send_ccb(device, ccb) < 0) { 479 perror("error sending start unit"); 480 481 if (arglist & CAM_ARG_VERBOSE) { 482 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 483 CAM_SCSI_STATUS_ERROR) 484 scsi_sense_print(device, &ccb->csio, stderr); 485 else 486 fprintf(stderr, "CAM status is %#x\n", 487 ccb->ccb_h.status); 488 } 489 490 cam_freeccb(ccb); 491 return(1); 492 } 493 494 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 495 if (startstop) { 496 fprintf(stdout, "Unit started successfully"); 497 if (loadeject) 498 fprintf(stdout,", Media loaded\n"); 499 else 500 fprintf(stdout,"\n"); 501 } else { 502 fprintf(stdout, "Unit stopped successfully"); 503 if (loadeject) 504 fprintf(stdout, ", Media ejected\n"); 505 else 506 fprintf(stdout, "\n"); 507 } 508 else { 509 error = 1; 510 if (startstop) 511 fprintf(stdout, 512 "Error received from start unit command\n"); 513 else 514 fprintf(stdout, 515 "Error received from stop unit command\n"); 516 517 if (arglist & CAM_ARG_VERBOSE) { 518 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 519 CAM_SCSI_STATUS_ERROR) 520 scsi_sense_print(device, &ccb->csio, stderr); 521 else 522 fprintf(stderr, "CAM status is %#x\n", 523 ccb->ccb_h.status); 524 } 525 } 526 527 cam_freeccb(ccb); 528 529 return(error); 530} 531 532static int 533scsidoinquiry(struct cam_device *device, int argc, char **argv, 534 char *combinedopt, int retry_count, int timeout) 535{ 536 int c; 537 int error = 0; 538 539 while ((c = getopt(argc, argv, combinedopt)) != -1) { 540 switch(c) { 541 case 'D': 542 arglist |= CAM_ARG_GET_STDINQ; 543 break; 544 case 'R': 545 arglist |= CAM_ARG_GET_XFERRATE; 546 break; 547 case 'S': 548 arglist |= CAM_ARG_GET_SERIAL; 549 break; 550 default: 551 break; 552 } 553 } 554 555 /* 556 * If the user didn't specify any inquiry options, he wants all of 557 * them. 558 */ 559 if ((arglist & CAM_ARG_INQ_MASK) == 0) 560 arglist |= CAM_ARG_INQ_MASK; 561 562 if (arglist & CAM_ARG_GET_STDINQ) 563 error = scsiinquiry(device, retry_count, timeout); 564 565 if (error != 0) 566 return(error); 567 568 if (arglist & CAM_ARG_GET_SERIAL) 569 scsiserial(device, retry_count, timeout); 570 571 if (error != 0) 572 return(error); 573 574 if (arglist & CAM_ARG_GET_XFERRATE) 575 error = scsixferrate(device); 576 577 return(error); 578} 579 580static int 581scsiinquiry(struct cam_device *device, int retry_count, int timeout) 582{ 583 union ccb *ccb; 584 struct scsi_inquiry_data *inq_buf; 585 int error = 0; 586 587 ccb = cam_getccb(device); 588 589 if (ccb == NULL) { 590 warnx("couldn't allocate CCB"); 591 return(1); 592 } 593 594 /* cam_getccb cleans up the header, caller has to zero the payload */ 595 bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_scsiio)); 596 597 inq_buf = (struct scsi_inquiry_data *)malloc( 598 sizeof(struct scsi_inquiry_data)); 599 600 if (inq_buf == NULL) { 601 cam_freeccb(ccb); 602 warnx("can't malloc memory for inquiry\n"); 603 return(1); 604 } 605 bzero(inq_buf, sizeof(*inq_buf)); 606 607 scsi_inquiry(&ccb->csio, 608 /* retries */ retry_count, 609 /* cbfcnp */ NULL, 610 /* tag_action */ MSG_SIMPLE_Q_TAG, 611 /* inq_buf */ (u_int8_t *)inq_buf, 612 /* inq_len */ sizeof(struct scsi_inquiry_data), 613 /* evpd */ 0, 614 /* page_code */ 0, 615 /* sense_len */ SSD_FULL_SIZE, 616 /* timeout */ timeout ? timeout : 5000); 617 618 /* Disable freezing the device queue */ 619 ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 620 621 if (arglist & CAM_ARG_ERR_RECOVER) 622 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 623 624 if (cam_send_ccb(device, ccb) < 0) { 625 perror("error sending SCSI inquiry"); 626 627 if (arglist & CAM_ARG_VERBOSE) { 628 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 629 CAM_SCSI_STATUS_ERROR) 630 scsi_sense_print(device, &ccb->csio, stderr); 631 else 632 fprintf(stderr, "CAM status is %#x\n", 633 ccb->ccb_h.status); 634 } 635 636 cam_freeccb(ccb); 637 return(1); 638 } 639 640 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 641 error = 1; 642 643 if (arglist & CAM_ARG_VERBOSE) { 644 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 645 CAM_SCSI_STATUS_ERROR) 646 scsi_sense_print(device, &ccb->csio, stderr); 647 else 648 fprintf(stderr, "CAM status is %#x\n", 649 ccb->ccb_h.status); 650 } 651 } 652 653 cam_freeccb(ccb); 654 655 if (error != 0) { 656 free(inq_buf); 657 return(error); 658 } 659 660 scsi_print_inquiry(inq_buf); 661 662 free(inq_buf); 663 664 if (arglist & CAM_ARG_GET_SERIAL) 665 fprintf(stdout, "Serial Number "); 666 667 return(0); 668} 669 670static int 671scsiserial(struct cam_device *device, int retry_count, int timeout) 672{ 673 union ccb *ccb; 674 struct scsi_vpd_unit_serial_number *serial_buf; 675 char serial_num[SVPD_SERIAL_NUM_SIZE + 1]; 676 int error = 0; 677 678 ccb = cam_getccb(device); 679 680 if (ccb == NULL) { 681 warnx("couldn't allocate CCB"); 682 return(1); 683 } 684 685 /* cam_getccb cleans up the header, caller has to zero the payload */ 686 bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_scsiio)); 687 688 serial_buf = (struct scsi_vpd_unit_serial_number *) 689 malloc(sizeof(*serial_buf)); 690 691 if (serial_buf == NULL) { 692 cam_freeccb(ccb); 693 warnx("can't malloc memory for serial number"); 694 return(1); 695 } 696 697 scsi_inquiry(&ccb->csio, 698 /*retries*/ retry_count, 699 /*cbfcnp*/ NULL, 700 /* tag_action */ MSG_SIMPLE_Q_TAG, 701 /* inq_buf */ (u_int8_t *)serial_buf, 702 /* inq_len */ sizeof(*serial_buf), 703 /* evpd */ 1, 704 /* page_code */ SVPD_UNIT_SERIAL_NUMBER, 705 /* sense_len */ SSD_FULL_SIZE, 706 /* timeout */ timeout ? timeout : 5000); 707 708 /* Disable freezing the device queue */ 709 ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 710 711 if (arglist & CAM_ARG_ERR_RECOVER) 712 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 713 714 if (cam_send_ccb(device, ccb) < 0) { 715 warn("error getting serial number"); 716 717 if (arglist & CAM_ARG_VERBOSE) { 718 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 719 CAM_SCSI_STATUS_ERROR) 720 scsi_sense_print(device, &ccb->csio, stderr); 721 else 722 fprintf(stderr, "CAM status is %#x\n", 723 ccb->ccb_h.status); 724 } 725 726 cam_freeccb(ccb); 727 free(serial_buf); 728 return(1); 729 } 730 731 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 732 error = 1; 733 734 if (arglist & CAM_ARG_VERBOSE) { 735 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 736 CAM_SCSI_STATUS_ERROR) 737 scsi_sense_print(device, &ccb->csio, stderr); 738 else 739 fprintf(stderr, "CAM status is %#x\n", 740 ccb->ccb_h.status); 741 } 742 } 743 744 cam_freeccb(ccb); 745 746 if (error != 0) { 747 free(serial_buf); 748 return(error); 749 } 750 751 bcopy(serial_buf->serial_num, serial_num, serial_buf->length); 752 serial_num[serial_buf->length] = '\0'; 753 754 if (((arglist & CAM_ARG_GET_STDINQ) == 0) 755 && (arglist & CAM_ARG_GET_XFERRATE)) 756 fprintf(stdout, "Serial Number "); 757 758 fprintf(stdout, "%.60s\n", serial_num); 759 760 free(serial_buf); 761 762 return(0); 763} 764 765static int 766scsixferrate(struct cam_device *device) 767{ 768 u_int32_t freq; 769 u_int32_t speed; 770 771 if (device->sync_period != 0) 772 freq = scsi_calc_syncsrate(device->sync_period); 773 else 774 freq = 0; 775 776 speed = freq; 777 speed *= (0x01 << device->bus_width); 778 fprintf(stdout, "%d.%dMB/s transfers ", speed / 1000, speed % 1000); 779 780 if (device->sync_period != 0) 781 fprintf(stdout, "(%d.%dMHz, offset %d", freq / 1000, 782 freq % 1000, device->sync_offset); 783 784 if (device->bus_width != 0) { 785 if (device->sync_period == 0) 786 fprintf(stdout, "("); 787 else 788 fprintf(stdout, ", "); 789 fprintf(stdout, "%dbit)", 8 * (0x01 << device->bus_width)); 790 } else if (device->sync_period != 0) 791 fprintf(stdout, ")"); 792 793 if (device->inq_data.flags & SID_CmdQue) 794 fprintf(stdout, ", Tagged Queueing Enabled"); 795 796 fprintf(stdout, "\n"); 797 798 return(0); 799} 800 801static int 802dorescan_or_reset(int argc, char **argv, int rescan) 803{ 804 static const char *must = 805 "you must specify a bus, or a bus:target:lun to %s"; 806 int error = 0; 807 int bus = -1, target = -1, lun = -1; 808 char *tstr, *tmpstr = NULL; 809 810 if (argc < 3) { 811 warnx(must, rescan? "rescan" : "reset"); 812 return(1); 813 } 814 /* 815 * Parse out a bus, or a bus, target and lun in the following 816 * format: 817 * bus 818 * bus:target:lun 819 * It is an error to specify a bus and target, but not a lun. 820 */ 821 tstr = argv[optind]; 822 823 while (isspace(*tstr) && (*tstr != '\0')) 824 tstr++; 825 826 tmpstr = (char *)strtok(tstr, ":"); 827 if ((tmpstr != NULL) && (*tmpstr != '\0')){ 828 bus = strtol(tmpstr, NULL, 0); 829 arglist |= CAM_ARG_BUS; 830 tmpstr = (char *)strtok(NULL, ":"); 831 if ((tmpstr != NULL) && (*tmpstr != '\0')){ 832 target = strtol(tmpstr, NULL, 0); 833 arglist |= CAM_ARG_TARGET; 834 tmpstr = (char *)strtok(NULL, ":"); 835 if ((tmpstr != NULL) && (*tmpstr != '\0')){ 836 lun = strtol(tmpstr, NULL, 0); 837 arglist |= CAM_ARG_LUN; 838 } else { 839 error = 1; 840 warnx(must, rescan? "rescan" : "reset"); 841 } 842 } 843 } else { 844 error = 1; 845 warnx(must, rescan? "rescan" : "reset"); 846 } 847 848 849 if (error == 0) { 850 if ((arglist & CAM_ARG_BUS) 851 && (arglist & CAM_ARG_TARGET) 852 && (arglist & CAM_ARG_LUN)) 853 error = scanlun_or_reset_dev(bus, target, lun, rescan); 854 else if (arglist & CAM_ARG_BUS) 855 error = rescan_or_reset_bus(bus, rescan); 856 else { 857 error = 1; 858 warnx(must, rescan? "rescan" : "reset"); 859 } 860 } 861 return(error); 862} 863 864static int 865rescan_or_reset_bus(int bus, int rescan) 866{ 867 union ccb ccb; 868 int fd; 869 870 if (bus < 0) { 871 warnx("invalid bus number %d", bus); 872 return(1); 873 } 874 875 if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) { 876 warnx("error opening tranport layer device %s", XPT_DEVICE); 877 warn("%s", XPT_DEVICE); 878 return(1); 879 } 880 881 ccb.ccb_h.func_code = rescan? XPT_SCAN_BUS : XPT_RESET_BUS; 882 ccb.ccb_h.path_id = bus; 883 ccb.ccb_h.target_id = CAM_TARGET_WILDCARD; 884 ccb.ccb_h.target_lun = CAM_LUN_WILDCARD; 885 ccb.crcn.flags = CAM_FLAG_NONE; 886 887 /* run this at a low priority */ 888 ccb.ccb_h.pinfo.priority = 5; 889 890 if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 891 warn("CAMIOCOMMAND ioctl failed"); 892 close(fd); 893 return(1); 894 } 895 896 close(fd); 897 898 if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 899 fprintf(stdout, "%s of bus %d was successful\n", bus, 900 rescan? "Re-scan" : "Reset"); 901 return(0); 902 } else { 903 fprintf(stdout, "%s of bus %d returned error %#x\n", 904 rescan? "Re-scan" : "Reset", bus, 905 ccb.ccb_h.status & CAM_STATUS_MASK); 906 return(1); 907 } 908} 909 910static int 911scanlun_or_reset_dev(int bus, int target, int lun, int scan) 912{ 913 union ccb ccb; 914 int fd; 915 916 if (bus < 0) { 917 warnx("invalid bus number %d", bus); 918 return(1); 919 } 920 921 if (target < 0) { 922 warnx("invalid target number %d", target); 923 return(1); 924 } 925 926 if (lun < 0) { 927 warnx("invalid lun number %d", lun); 928 return(1); 929 } 930 931 if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) { 932 warnx("error opening tranport layer device %s\n", 933 XPT_DEVICE); 934 warn("%s", XPT_DEVICE); 935 return(1); 936 } 937 938 ccb.ccb_h.func_code = (scan)? XPT_SCAN_LUN : XPT_RESET_DEV; 939 ccb.ccb_h.path_id = bus; 940 ccb.ccb_h.target_id = target; 941 ccb.ccb_h.target_lun = lun; 942 ccb.crcn.flags = CAM_FLAG_NONE; 943 944 /* run this at a low priority */ 945 ccb.ccb_h.pinfo.priority = 5; 946 947 if (ioctl(fd, CAMIOCOMMAND, &ccb) < 0) { 948 warn("CAMIOCOMMAND ioctl failed"); 949 close(fd); 950 return(1); 951 } 952 953 close(fd); 954 955 if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 956 fprintf(stdout, "%s of %d:%d:%d was successful\n", 957 scan? "Re-scan" : "Reset", bus, target, lun); 958 return(0); 959 } else { 960 fprintf(stdout, "%s of %d:%d:%d returned error %#x\n", 961 scan? "Re-scan" : "Reset", bus, target, lun, 962 ccb.ccb_h.status & CAM_STATUS_MASK); 963 return(1); 964 } 965} 966 967static int 968readdefects(struct cam_device *device, int argc, char **argv, 969 char *combinedopt, int retry_count, int timeout) 970{ 971 union ccb *ccb = NULL; 972 struct scsi_read_defect_data_10 *rdd_cdb; 973 u_int8_t *defect_list = NULL; 974 u_int32_t dlist_length = 65000; 975 u_int32_t returned_length = 0; 976 u_int32_t num_returned = 0; 977 u_int8_t returned_format; 978 register int i; 979 int c, error = 0; 980 int lists_specified = 0; 981 982 while ((c = getopt(argc, argv, combinedopt)) != -1) { 983 switch(c){ 984 case 'f': 985 { 986 char *tstr; 987 tstr = optarg; 988 while (isspace(*tstr) && (*tstr != '\0')) 989 tstr++; 990 if (strcmp(tstr, "block") == 0) 991 arglist |= CAM_ARG_FORMAT_BLOCK; 992 else if (strcmp(tstr, "bfi") == 0) 993 arglist |= CAM_ARG_FORMAT_BFI; 994 else if (strcmp(tstr, "phys") == 0) 995 arglist |= CAM_ARG_FORMAT_PHYS; 996 else { 997 error = 1; 998 warnx("invalid defect format %s", tstr); 999 goto defect_bailout; 1000 } 1001 break; 1002 } 1003 case 'G': 1004 arglist |= CAM_ARG_GLIST; 1005 break; 1006 case 'P': 1007 arglist |= CAM_ARG_PLIST; 1008 break; 1009 default: 1010 break; 1011 } 1012 } 1013 1014 ccb = cam_getccb(device); 1015 1016 /* 1017 * Hopefully 65000 bytes is enough to hold the defect list. If it 1018 * isn't, the disk is probably dead already. We'd have to go with 1019 * 12 byte command (i.e. alloc_length is 32 bits instead of 16) 1020 * to hold them all. 1021 */ 1022 defect_list = malloc(dlist_length); 1023 1024 rdd_cdb =(struct scsi_read_defect_data_10 *)&ccb->csio.cdb_io.cdb_bytes; 1025 1026 /* 1027 * cam_getccb() zeros the CCB header only. So we need to zero the 1028 * payload portion of the ccb. 1029 */ 1030 bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_scsiio)); 1031 1032 cam_fill_csio(&ccb->csio, 1033 /*retries*/ retry_count, 1034 /*cbfcnp*/ NULL, 1035 /*flags*/ CAM_DIR_IN | (arglist & CAM_ARG_ERR_RECOVER) ? 1036 CAM_PASS_ERR_RECOVER : 0, 1037 /*tag_action*/ MSG_SIMPLE_Q_TAG, 1038 /*data_ptr*/ defect_list, 1039 /*dxfer_len*/ dlist_length, 1040 /*sense_len*/ SSD_FULL_SIZE, 1041 /*cdb_len*/ sizeof(struct scsi_read_defect_data_10), 1042 /*timeout*/ timeout ? timeout : 5000); 1043 1044 rdd_cdb->opcode = READ_DEFECT_DATA_10; 1045 if (arglist & CAM_ARG_FORMAT_BLOCK) 1046 rdd_cdb->format = SRDD10_BLOCK_FORMAT; 1047 else if (arglist & CAM_ARG_FORMAT_BFI) 1048 rdd_cdb->format = SRDD10_BYTES_FROM_INDEX_FORMAT; 1049 else if (arglist & CAM_ARG_FORMAT_PHYS) 1050 rdd_cdb->format = SRDD10_PHYSICAL_SECTOR_FORMAT; 1051 else { 1052 error = 1; 1053 warnx("no defect list format specified"); 1054 goto defect_bailout; 1055 } 1056 if (arglist & CAM_ARG_PLIST) { 1057 rdd_cdb->format |= SRDD10_PLIST; 1058 lists_specified++; 1059 } 1060 1061 if (arglist & CAM_ARG_GLIST) { 1062 rdd_cdb->format |= SRDD10_GLIST; 1063 lists_specified++; 1064 } 1065 1066 scsi_ulto2b(dlist_length, rdd_cdb->alloc_length); 1067 1068 /* Disable freezing the device queue */ 1069 ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 1070 1071 if (cam_send_ccb(device, ccb) < 0) { 1072 perror("error reading defect list"); 1073 1074 if (arglist & CAM_ARG_VERBOSE) { 1075 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 1076 CAM_SCSI_STATUS_ERROR) 1077 scsi_sense_print(device, &ccb->csio, stderr); 1078 else 1079 fprintf(stderr, "CAM status is %#x\n", 1080 ccb->ccb_h.status); 1081 } 1082 1083 error = 1; 1084 goto defect_bailout; 1085 } 1086 1087 if (arglist & CAM_ARG_VERBOSE) 1088 scsi_sense_print(device, &ccb->csio, stderr); 1089 1090 returned_length = scsi_2btoul(((struct 1091 scsi_read_defect_data_hdr_10 *)defect_list)->length); 1092 1093 returned_format = ((struct scsi_read_defect_data_hdr_10 *) 1094 defect_list)->format; 1095 1096 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1097 struct scsi_sense_data *sense; 1098 int error_code, sense_key, asc, ascq; 1099 1100 sense = &ccb->csio.sense_data; 1101 scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq); 1102 1103 /* 1104 * According to the SCSI spec, if the disk doesn't support 1105 * the requested format, it will generally return a sense 1106 * key of RECOVERED ERROR, and an additional sense code 1107 * of "DEFECT LIST NOT FOUND". So, we check for that, and 1108 * also check to make sure that the returned length is 1109 * greater than 0, and then print out whatever format the 1110 * disk gave us. 1111 */ 1112 if ((sense_key == SSD_KEY_RECOVERED_ERROR) 1113 && (asc == 0x1c) && (ascq == 0x00) 1114 && (returned_length > 0)) { 1115 warnx("requested defect format not available"); 1116 switch(returned_format & SRDDH10_DLIST_FORMAT_MASK) { 1117 case SRDD10_BLOCK_FORMAT: 1118 warnx("Device returned block format"); 1119 break; 1120 case SRDD10_BYTES_FROM_INDEX_FORMAT: 1121 warnx("Device returned bytes from index" 1122 " format"); 1123 break; 1124 case SRDD10_PHYSICAL_SECTOR_FORMAT: 1125 warnx("Device returned physical sector format"); 1126 break; 1127 default: 1128 error = 1; 1129 warnx("Device returned unknown defect" 1130 " data format %#x", returned_format); 1131 goto defect_bailout; 1132 break; /* NOTREACHED */ 1133 } 1134 } else { 1135 error = 1; 1136 warnx("Error returned from read defect data command"); 1137 goto defect_bailout; 1138 } 1139 } 1140 1141 /* 1142 * XXX KDM I should probably clean up the printout format for the 1143 * disk defects. 1144 */ 1145 switch (returned_format & SRDDH10_DLIST_FORMAT_MASK){ 1146 case SRDDH10_PHYSICAL_SECTOR_FORMAT: 1147 { 1148 struct scsi_defect_desc_phys_sector *dlist; 1149 1150 dlist = (struct scsi_defect_desc_phys_sector *) 1151 (defect_list + 1152 sizeof(struct scsi_read_defect_data_hdr_10)); 1153 1154 num_returned = returned_length / 1155 sizeof(struct scsi_defect_desc_phys_sector); 1156 1157 fprintf(stderr, "Got %d defect", num_returned); 1158 1159 if ((lists_specified == 0) || (num_returned == 0)) { 1160 fprintf(stderr, "s.\n"); 1161 break; 1162 } else if (num_returned == 1) 1163 fprintf(stderr, ":\n"); 1164 else 1165 fprintf(stderr, "s:\n"); 1166 1167 for (i = 0; i < num_returned; i++) { 1168 fprintf(stdout, "%d:%d:%d\n", 1169 scsi_3btoul(dlist[i].cylinder), 1170 dlist[i].head, 1171 scsi_4btoul(dlist[i].sector)); 1172 } 1173 break; 1174 } 1175 case SRDDH10_BYTES_FROM_INDEX_FORMAT: 1176 { 1177 struct scsi_defect_desc_bytes_from_index *dlist; 1178 1179 dlist = (struct scsi_defect_desc_bytes_from_index *) 1180 (defect_list + 1181 sizeof(struct scsi_read_defect_data_hdr_10)); 1182 1183 num_returned = returned_length / 1184 sizeof(struct scsi_defect_desc_bytes_from_index); 1185 1186 fprintf(stderr, "Got %d defect", num_returned); 1187 1188 if ((lists_specified == 0) || (num_returned == 0)) { 1189 fprintf(stderr, "s.\n"); 1190 break; 1191 } else if (num_returned == 1) 1192 fprintf(stderr, ":\n"); 1193 else 1194 fprintf(stderr, "s:\n"); 1195 1196 for (i = 0; i < num_returned; i++) { 1197 fprintf(stdout, "%d:%d:%d\n", 1198 scsi_3btoul(dlist[i].cylinder), 1199 dlist[i].head, 1200 scsi_4btoul(dlist[i].bytes_from_index)); 1201 } 1202 break; 1203 } 1204 case SRDDH10_BLOCK_FORMAT: 1205 { 1206 struct scsi_defect_desc_block *dlist; 1207 1208 dlist = (struct scsi_defect_desc_block *)(defect_list + 1209 sizeof(struct scsi_read_defect_data_hdr_10)); 1210 1211 num_returned = returned_length / 1212 sizeof(struct scsi_defect_desc_block); 1213 1214 fprintf(stderr, "Got %d defect", num_returned); 1215 1216 if ((lists_specified == 0) || (num_returned == 0)) { 1217 fprintf(stderr, "s.\n"); 1218 break; 1219 } else if (num_returned == 1) 1220 fprintf(stderr, ":\n"); 1221 else 1222 fprintf(stderr, "s:\n"); 1223 1224 for (i = 0; i < num_returned; i++) 1225 fprintf(stdout, "%u\n", 1226 scsi_4btoul(dlist[i].address)); 1227 break; 1228 } 1229 default: 1230 fprintf(stderr, "Unknown defect format %d\n", 1231 returned_format & SRDDH10_DLIST_FORMAT_MASK); 1232 error = 1; 1233 break; 1234 } 1235defect_bailout: 1236 1237 if (defect_list != NULL) 1238 free(defect_list); 1239 1240 if (ccb != NULL) 1241 cam_freeccb(ccb); 1242 1243 return(error); 1244} 1245 1246#if 0 1247void 1248reassignblocks(struct cam_device *device, u_int32_t *blocks, int num_blocks) 1249{ 1250 union ccb *ccb; 1251 1252 ccb = cam_getccb(device); 1253 1254 cam_freeccb(ccb); 1255} 1256#endif 1257 1258void 1259mode_sense(struct cam_device *device, int mode_page, int page_control, 1260 int dbd, int retry_count, int timeout, u_int8_t *data, int datalen) 1261{ 1262 union ccb *ccb; 1263 int retval; 1264 1265 ccb = cam_getccb(device); 1266 1267 if (ccb == NULL) 1268 errx(1, "mode_sense: couldn't allocate CCB"); 1269 1270 bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_scsiio)); 1271 1272 scsi_mode_sense(&ccb->csio, 1273 /* retries */ retry_count, 1274 /* cbfcnp */ NULL, 1275 /* tag_action */ MSG_SIMPLE_Q_TAG, 1276 /* dbd */ dbd, 1277 /* page_code */ page_control << 6, 1278 /* page */ mode_page, 1279 /* param_buf */ data, 1280 /* param_len */ datalen, 1281 /* sense_len */ SSD_FULL_SIZE, 1282 /* timeout */ timeout ? timeout : 5000); 1283 1284 if (arglist & CAM_ARG_ERR_RECOVER) 1285 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 1286 1287 /* Disable freezing the device queue */ 1288 ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 1289 1290 if (((retval = cam_send_ccb(device, ccb)) < 0) 1291 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 1292 if (arglist & CAM_ARG_VERBOSE) { 1293 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 1294 CAM_SCSI_STATUS_ERROR) 1295 scsi_sense_print(device, &ccb->csio, stderr); 1296 else 1297 fprintf(stderr, "CAM status is %#x\n", 1298 ccb->ccb_h.status); 1299 } 1300 cam_freeccb(ccb); 1301 cam_close_device(device); 1302 if (retval < 0) 1303 err(1, "error sending mode sense command"); 1304 else 1305 errx(1, "error sending mode sense command"); 1306 } 1307 1308 cam_freeccb(ccb); 1309} 1310 1311void 1312mode_select(struct cam_device *device, int save_pages, int retry_count, 1313 int timeout, u_int8_t *data, int datalen) 1314{ 1315 union ccb *ccb; 1316 int retval; 1317 1318 ccb = cam_getccb(device); 1319 1320 if (ccb == NULL) 1321 errx(1, "mode_select: couldn't allocate CCB"); 1322 1323 bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_scsiio)); 1324 1325 scsi_mode_select(&ccb->csio, 1326 /* retries */ retry_count, 1327 /* cbfcnp */ NULL, 1328 /* tag_action */ MSG_SIMPLE_Q_TAG, 1329 /* scsi_page_fmt */ 1, 1330 /* save_pages */ save_pages, 1331 /* param_buf */ data, 1332 /* param_len */ datalen, 1333 /* sense_len */ SSD_FULL_SIZE, 1334 /* timeout */ timeout ? timeout : 5000); 1335 1336 if (arglist & CAM_ARG_ERR_RECOVER) 1337 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 1338 1339 /* Disable freezing the device queue */ 1340 ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 1341 1342 if (((retval = cam_send_ccb(device, ccb)) < 0) 1343 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 1344 if (arglist & CAM_ARG_VERBOSE) { 1345 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 1346 CAM_SCSI_STATUS_ERROR) 1347 scsi_sense_print(device, &ccb->csio, stderr); 1348 else 1349 fprintf(stderr, "CAM status is %#x\n", 1350 ccb->ccb_h.status); 1351 } 1352 cam_freeccb(ccb); 1353 cam_close_device(device); 1354 1355 if (retval < 0) 1356 err(1, "error sending mode select command"); 1357 else 1358 errx(1, "error sending mode select command"); 1359 1360 } 1361 1362 cam_freeccb(ccb); 1363} 1364 1365void 1366modepage(struct cam_device *device, int argc, char **argv, char *combinedopt, 1367 int retry_count, int timeout) 1368{ 1369 int c, mode_page = -1, page_control = 0; 1370 1371 while ((c = getopt(argc, argv, combinedopt)) != -1) { 1372 switch(c) { 1373 case 'd': 1374 arglist |= CAM_ARG_DBD; 1375 break; 1376 case 'e': 1377 arglist |= CAM_ARG_MODE_EDIT; 1378 break; 1379 case 'm': 1380 mode_page = strtol(optarg, NULL, 0); 1381 if (mode_page < 0) 1382 errx(1, "invalid mode page %d", mode_page); 1383 break; 1384 case 'P': 1385 page_control = strtol(optarg, NULL, 0); 1386 if ((page_control < 0) || (page_control > 3)) 1387 errx(1, "invalid page control field %d", 1388 page_control); 1389 arglist |= CAM_ARG_PAGE_CNTL; 1390 break; 1391 default: 1392 break; 1393 } 1394 } 1395 1396 if (mode_page == -1) 1397 errx(1, "you must specify a mode page!"); 1398 1399 mode_edit(device, mode_page, page_control, arglist & CAM_ARG_DBD, 1400 arglist & CAM_ARG_MODE_EDIT, retry_count, timeout); 1401} 1402 1403static int 1404scsicmd(struct cam_device *device, int argc, char **argv, char *combinedopt, 1405 int retry_count, int timeout) 1406{ 1407 union ccb *ccb; 1408 u_int32_t flags = CAM_DIR_NONE; 1409 u_int8_t *data_ptr = NULL; 1410 u_int8_t cdb[20]; 1411 struct get_hook hook; 1412 int c, data_bytes = 0; 1413 int cdb_len = 0; 1414 char *datastr = NULL, *tstr; 1415 int error = 0; 1416 int fd_data = 0; 1417 int retval; 1418 1419 ccb = cam_getccb(device); 1420 1421 if (ccb == NULL) { 1422 warnx("scsicmd: error allocating ccb"); 1423 return(1); 1424 } 1425 1426 bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_scsiio)); 1427 1428 while ((c = getopt(argc, argv, combinedopt)) != -1) { 1429 switch(c) { 1430 case 'c': 1431 tstr = optarg; 1432 while (isspace(*tstr) && (*tstr != '\0')) 1433 tstr++; 1434 hook.argc = argc - optind; 1435 hook.argv = argv + optind; 1436 hook.got = 0; 1437 buff_encode_visit(cdb, sizeof(cdb), tstr, 1438 iget, &hook); 1439 /* 1440 * Increment optind by the number of arguments the 1441 * encoding routine processed. After each call to 1442 * getopt(3), optind points to the argument that 1443 * getopt should process _next_. In this case, 1444 * that means it points to the first command string 1445 * argument, if there is one. Once we increment 1446 * this, it should point to either the next command 1447 * line argument, or it should be past the end of 1448 * the list. 1449 */ 1450 optind += hook.got; 1451 break; 1452 case 'i': 1453 if (arglist & CAM_ARG_CMD_OUT) { 1454 warnx("command must either be " 1455 "read or write, not both"); 1456 error = 1; 1457 goto scsicmd_bailout; 1458 } 1459 arglist |= CAM_ARG_CMD_IN; 1460 flags = CAM_DIR_IN; 1461 data_bytes = strtol(optarg, NULL, 0); 1462 if (data_bytes <= 0) { 1463 warnx("invalid number of input bytes %d", 1464 data_bytes); 1465 error = 1; 1466 goto scsicmd_bailout; 1467 } 1468 hook.argc = argc - optind; 1469 hook.argv = argv + optind; 1470 hook.got = 0; 1471 optind++; 1472 datastr = cget(&hook, NULL); 1473 /* 1474 * If the user supplied "-" instead of a format, he 1475 * wants the data to be written to stdout. 1476 */ 1477 if ((datastr != NULL) 1478 && (datastr[0] == '-')) 1479 fd_data = 1; 1480 1481 data_ptr = (u_int8_t *)malloc(data_bytes); 1482 break; 1483 case 'o': 1484 if (arglist & CAM_ARG_CMD_IN) { 1485 warnx("command must either be " 1486 "read or write, not both"); 1487 error = 1; 1488 goto scsicmd_bailout; 1489 } 1490 arglist |= CAM_ARG_CMD_OUT; 1491 flags = CAM_DIR_OUT; 1492 data_bytes = strtol(optarg, NULL, 0); 1493 if (data_bytes <= 0) { 1494 warnx("invalid number of output bytes %d", 1495 data_bytes); 1496 error = 1; 1497 goto scsicmd_bailout; 1498 } 1499 hook.argc = argc - optind; 1500 hook.argv = argv + optind; 1501 hook.got = 0; 1502 datastr = cget(&hook, NULL); 1503 data_ptr = (u_int8_t *)malloc(data_bytes); 1504 /* 1505 * If the user supplied "-" instead of a format, he 1506 * wants the data to be read from stdin. 1507 */ 1508 if ((datastr != NULL) 1509 && (datastr[0] == '-')) 1510 fd_data = 1; 1511 else 1512 buff_encode_visit(data_ptr, data_bytes, datastr, 1513 iget, &hook); 1514 optind += hook.got; 1515 break; 1516 default: 1517 break; 1518 } 1519 } 1520 1521 /* 1522 * If fd_data is set, and we're writing to the device, we need to 1523 * read the data the user wants written from stdin. 1524 */ 1525 if ((fd_data == 1) && (arglist & CAM_ARG_CMD_OUT)) { 1526 size_t amt_read; 1527 int amt_to_read = data_bytes; 1528 u_int8_t *buf_ptr = data_ptr; 1529 1530 for (amt_read = 0; amt_to_read > 0; 1531 amt_read = read(0, buf_ptr, amt_to_read)) { 1532 if (amt_read == -1) { 1533 warn("error reading data from stdin"); 1534 error = 1; 1535 goto scsicmd_bailout; 1536 } 1537 amt_to_read -= amt_read; 1538 buf_ptr += amt_read; 1539 } 1540 } 1541 1542 if (arglist & CAM_ARG_ERR_RECOVER) 1543 flags |= CAM_PASS_ERR_RECOVER; 1544 1545 /* Disable freezing the device queue */ 1546 flags |= CAM_DEV_QFRZDIS; 1547 1548 /* 1549 * This is taken from the SCSI-3 draft spec. 1550 * (T10/1157D revision 0.3) 1551 * The top 3 bits of an opcode are the group code. The next 5 bits 1552 * are the command code. 1553 * Group 0: six byte commands 1554 * Group 1: ten byte commands 1555 * Group 2: ten byte commands 1556 * Group 3: reserved 1557 * Group 4: sixteen byte commands 1558 * Group 5: twelve byte commands 1559 * Group 6: vendor specific 1560 * Group 7: vendor specific 1561 */ 1562 switch((cdb[0] >> 5) & 0x7) { 1563 case 0: 1564 cdb_len = 6; 1565 break; 1566 case 1: 1567 case 2: 1568 cdb_len = 10; 1569 break; 1570 case 3: 1571 case 6: 1572 case 7: 1573 cdb_len = 1; 1574 break; 1575 case 4: 1576 cdb_len = 16; 1577 break; 1578 case 5: 1579 cdb_len = 12; 1580 break; 1581 } 1582 1583 /* 1584 * We should probably use csio_build_visit or something like that 1585 * here, but it's easier to encode arguments as you go. The 1586 * alternative would be skipping the CDB argument and then encoding 1587 * it here, since we've got the data buffer argument by now. 1588 */ 1589 bcopy(cdb, &ccb->csio.cdb_io.cdb_bytes, cdb_len); 1590 1591 cam_fill_csio(&ccb->csio, 1592 /*retries*/ retry_count, 1593 /*cbfcnp*/ NULL, 1594 /*flags*/ flags, 1595 /*tag_action*/ MSG_SIMPLE_Q_TAG, 1596 /*data_ptr*/ data_ptr, 1597 /*dxfer_len*/ data_bytes, 1598 /*sense_len*/ SSD_FULL_SIZE, 1599 /*cdb_len*/ cdb_len, 1600 /*timeout*/ timeout ? timeout : 5000); 1601 1602 if (((retval = cam_send_ccb(device, ccb)) < 0) 1603 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 1604 if (retval < 0) 1605 warn("error sending command"); 1606 else 1607 warnx("error sending command"); 1608 1609 if (arglist & CAM_ARG_VERBOSE) { 1610 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 1611 CAM_SCSI_STATUS_ERROR) 1612 scsi_sense_print(device, &ccb->csio, stderr); 1613 else 1614 fprintf(stderr, "CAM status is %#x\n", 1615 ccb->ccb_h.status); 1616 } 1617 1618 error = 1; 1619 goto scsicmd_bailout; 1620 } 1621 1622 1623 if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 1624 && (arglist & CAM_ARG_CMD_IN) 1625 && (data_bytes > 0)) { 1626 if (fd_data == 0) { 1627 buff_decode_visit(data_ptr, data_bytes, datastr, 1628 arg_put, NULL); 1629 fprintf(stdout, "\n"); 1630 } else { 1631 size_t amt_written; 1632 int amt_to_write = data_bytes; 1633 u_int8_t *buf_ptr = data_ptr; 1634 1635 for (amt_written = 0; (amt_to_write > 0) && 1636 (amt_written =write(1, buf_ptr,amt_to_write))> 0;){ 1637 amt_to_write -= amt_written; 1638 buf_ptr += amt_written; 1639 } 1640 if (amt_written == -1) { 1641 warn("error writing data to stdout"); 1642 error = 1; 1643 goto scsicmd_bailout; 1644 } else if ((amt_written == 0) 1645 && (amt_to_write > 0)) { 1646 warnx("only wrote %u bytes out of %u", 1647 data_bytes - amt_to_write, data_bytes); 1648 } 1649 } 1650 } 1651 1652scsicmd_bailout: 1653 1654 if ((data_bytes > 0) && (data_ptr != NULL)) 1655 free(data_ptr); 1656 1657 cam_freeccb(ccb); 1658 1659 return(error); 1660} 1661 1662static int 1663camdebug(int argc, char **argv, char *combinedopt) 1664{ 1665 int c, fd; 1666 int bus = -1, target = -1, lun = -1; 1667 char *tstr, *tmpstr = NULL; 1668 union ccb ccb; 1669 int error = 0; 1670 1671 bzero(&ccb, sizeof(union ccb)); 1672 1673 while ((c = getopt(argc, argv, combinedopt)) != -1) { 1674 switch(c) { 1675 case 'I': 1676 arglist |= CAM_ARG_DEBUG_INFO; 1677 ccb.cdbg.flags |= CAM_DEBUG_INFO; 1678 break; 1679 case 'S': 1680 arglist |= CAM_ARG_DEBUG_TRACE; 1681 ccb.cdbg.flags |= CAM_DEBUG_TRACE; 1682 break; 1683 case 'T': 1684 arglist |= CAM_ARG_DEBUG_SUBTRACE; 1685 ccb.cdbg.flags |= CAM_DEBUG_SUBTRACE; 1686 break; 1687 case 'c': 1688 arglist |= CAM_ARG_DEBUG_CDB; 1689 ccb.cdbg.flags |= CAM_DEBUG_CDB; 1690 break; 1691 default: 1692 break; 1693 } 1694 } 1695 1696 if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) { 1697 warnx("error opening transport layer device %s", XPT_DEVICE); 1698 warn("%s", XPT_DEVICE); 1699 return(1); 1700 } 1701 argc -= optind; 1702 argv += optind; 1703 1704 if (argc <= 0) { 1705 warnx("you must specify \"off\", \"all\" or a bus,"); 1706 warnx("bus:target, or bus:target:lun"); 1707 close(fd); 1708 return(1); 1709 } 1710 1711 tstr = *argv; 1712 1713 while (isspace(*tstr) && (*tstr != '\0')) 1714 tstr++; 1715 1716 if (strncmp(tstr, "off", 3) == 0) { 1717 ccb.cdbg.flags = CAM_DEBUG_NONE; 1718 arglist &= ~(CAM_ARG_DEBUG_INFO|CAM_ARG_DEBUG_TRACE| 1719 CAM_ARG_DEBUG_SUBTRACE); 1720 } else if (strncmp(tstr, "all", 3) != 0) { 1721 tmpstr = (char *)strtok(tstr, ":"); 1722 if ((tmpstr != NULL) && (*tmpstr != '\0')){ 1723 bus = strtol(tmpstr, NULL, 0); 1724 arglist |= CAM_ARG_BUS; 1725 tmpstr = (char *)strtok(NULL, ":"); 1726 if ((tmpstr != NULL) && (*tmpstr != '\0')){ 1727 target = strtol(tmpstr, NULL, 0); 1728 arglist |= CAM_ARG_TARGET; 1729 tmpstr = (char *)strtok(NULL, ":"); 1730 if ((tmpstr != NULL) && (*tmpstr != '\0')){ 1731 lun = strtol(tmpstr, NULL, 0); 1732 arglist |= CAM_ARG_LUN; 1733 } 1734 } 1735 } else { 1736 error = 1; 1737 warnx("you must specify \"all\", \"off\", or a bus,"); 1738 warnx("bus:target, or bus:target:lun to debug"); 1739 } 1740 } 1741 1742 if (error == 0) { 1743 1744 ccb.ccb_h.func_code = XPT_DEBUG; 1745 ccb.ccb_h.path_id = bus; 1746 ccb.ccb_h.target_id = target; 1747 ccb.ccb_h.target_lun = lun; 1748 1749 if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 1750 warn("CAMIOCOMMAND ioctl failed"); 1751 error = 1; 1752 } 1753 1754 if (error == 0) { 1755 if ((ccb.ccb_h.status & CAM_STATUS_MASK) == 1756 CAM_FUNC_NOTAVAIL) { 1757 warnx("CAM debugging not available"); 1758 warnx("you need to put options CAMDEBUG in" 1759 " your kernel config file!"); 1760 error = 1; 1761 } else if ((ccb.ccb_h.status & CAM_STATUS_MASK) != 1762 CAM_REQ_CMP) { 1763 warnx("XPT_DEBUG CCB failed with status %#x", 1764 ccb.ccb_h.status); 1765 error = 1; 1766 } else { 1767 if (ccb.cdbg.flags == CAM_DEBUG_NONE) { 1768 fprintf(stderr, 1769 "Debugging turned off\n"); 1770 } else { 1771 fprintf(stderr, 1772 "Debugging enabled for " 1773 "%d:%d:%d\n", 1774 bus, target, lun); 1775 } 1776 } 1777 } 1778 close(fd); 1779 } 1780 1781 return(error); 1782} 1783 1784void 1785usage(void) 1786{ 1787 fprintf(stderr, 1788"usage: camcontrol <command> [ generic args ] [ command args ]\n" 1789" camcontrol devlist [-v]\n" 1790" camcontrol periphlist [-n dev_name] [-u unit]\n" 1791" camcontrol tur [generic args]\n" 1792" camcontrol inquiry [generic args] [-D] [-S] [-R]\n" 1793" camcontrol start [generic args]\n" 1794" camcontrol stop [generic args]\n" 1795" camcontrol eject [generic args]\n" 1796" camcontrol rescan <bus[:target:lun]>\n" 1797" camcontrol reset <bus[:target:lun]>\n" 1798" camcontrol defects [generic args] <-f format> [-P][-G]\n" 1799" camcontrol modepage [generic args] <-m page> [-P pagectl][-e][-d]\n" 1800" camcontrol cmd [generic args] <-c cmd [args]> \n" 1801" [-i len fmt|-o len fmt [args]]\n" 1802" camcontrol debug [-I][-T][-S][-c] <all|bus[:target[:lun]]|off>\n" 1803"Specify one of the following options:\n" 1804"devlist list all CAM devices\n" 1805"periphlist list all CAM peripheral drivers attached to a device\n" 1806"tur send a test unit ready to the named device\n" 1807"inquiry send a SCSI inquiry command to the named device\n" 1808"start send a Start Unit command to the device\n" 1809"stop send a Stop Unit command to the device\n" 1810"eject send a Stop Unit command to the device with the eject bit set\n" 1811"rescan rescan the given bus, or bus:target:lun\n" 1812"reset reset the given bus, or bus:target:lun\n" 1813"defects read the defect list of the specified device\n" 1814"modepage display or edit (-e) the given mode page\n" 1815"cmd send the given scsi command, may need -i or -o as well\n" 1816"debug turn debugging on/off for a bus, target, or lun, or all devices\n" 1817"Generic arguments:\n" 1818"-v be verbose, print out sense information\n" 1819"-t timeout command timeout in seconds, overrides default timeout\n" 1820"-n dev_name specify device name (default is %s)\n" 1821"-u unit specify unit number (default is %d)\n" 1822"-E have the kernel attempt to perform SCSI error recovery\n" 1823"-C count specify the SCSI command retry count (needs -E to work)\n" 1824"modepage arguments:\n" 1825"-e edit the specified mode page\n" 1826"-B disable block descriptors for mode sense\n" 1827"-P pgctl page control field 0-3\n" 1828"defects arguments:\n" 1829"-f format specify defect list format (block, bfi or phys)\n" 1830"-G get the grown defect list\n" 1831"-P get the permanant defect list\n" 1832"inquiry arguments:\n" 1833"-D get the standard inquiry data\n" 1834"-S get the serial number\n" 1835"-R get the transfer rate, etc.\n" 1836"cmd arguments:\n" 1837"-c cdb [args] specify the SCSI CDB\n" 1838"-i len fmt specify input data and input data format\n" 1839"-o len fmt [args] specify output data and output data fmt\n" 1840"debug arguments:\n" 1841"-I CAM_DEBUG_INFO -- scsi commands, errors, data\n" 1842"-T CAM_DEBUG_TRACE -- routine flow tracking\n" 1843"-S CAM_DEBUG_SUBTRACE -- internal routine command flow\n" 1844"-c CAM_DEBUG_CDB -- print out SCSI CDBs only\n", 1845DEFAULT_DEVICE, DEFAULT_UNIT); 1846} 1847 1848int 1849main(int argc, char **argv) 1850{ 1851 int c; 1852 char *device = NULL; 1853 int unit = 0; 1854 struct cam_device *cam_dev = NULL; 1855 int timeout = 0, retry_count = 1; 1856 camcontrol_optret optreturn; 1857 char *tstr; 1858 char *mainopt = "C:En:t:u:v"; 1859 char *subopt = NULL; 1860 char combinedopt[256]; 1861 int error = 0; 1862 1863 arglist = CAM_ARG_NONE; 1864 1865 if (argc < 2) { 1866 usage(); 1867 exit(1); 1868 } 1869 1870 /* 1871 * Get the base option. 1872 */ 1873 optreturn = getoption(argv[1], &arglist, &subopt); 1874 1875 if (optreturn == CC_OR_AMBIGUOUS) { 1876 warnx("ambiguous option %s", argv[1]); 1877 usage(); 1878 exit(1); 1879 } else if (optreturn == CC_OR_NOT_FOUND) { 1880 warnx("option %s not found", argv[1]); 1881 usage(); 1882 exit(1); 1883 } 1884 1885 /* 1886 * Ahh, getopt(3) is a pain. 1887 * 1888 * This is a gross hack. There really aren't many other good 1889 * options (excuse the pun) for parsing options in a situation like 1890 * this. getopt is kinda braindead, so you end up having to run 1891 * through the options twice, and give each invocation of getopt 1892 * the option string for the other invocation. 1893 * 1894 * You would think that you could just have two groups of options. 1895 * The first group would get parsed by the first invocation of 1896 * getopt, and the second group would get parsed by the second 1897 * invocation of getopt. It doesn't quite work out that way. When 1898 * the first invocation of getopt finishes, it leaves optind pointing 1899 * to the argument _after_ the first argument in the second group. 1900 * So when the second invocation of getopt comes around, it doesn't 1901 * recognize the first argument it gets and then bails out. 1902 * 1903 * A nice alternative would be to have a flag for getopt that says 1904 * "just keep parsing arguments even when you encounter an unknown 1905 * argument", but there isn't one. So there's no real clean way to 1906 * easily parse two sets of arguments without having one invocation 1907 * of getopt know about the other. 1908 * 1909 * Without this hack, the first invocation of getopt would work as 1910 * long as the generic arguments are first, but the second invocation 1911 * (in the subfunction) would fail in one of two ways. In the case 1912 * where you don't set optreset, it would fail because optind may be 1913 * pointing to the argument after the one it should be pointing at. 1914 * In the case where you do set optreset, and reset optind, it would 1915 * fail because getopt would run into the first set of options, which 1916 * it doesn't understand. 1917 * 1918 * All of this would "sort of" work if you could somehow figure out 1919 * whether optind had been incremented one option too far. The 1920 * mechanics of that, however, are more daunting than just giving 1921 * both invocations all of the expect options for either invocation. 1922 * 1923 * Needless to say, I wouldn't mind if someone invented a better 1924 * (non-GPL!) command line parsing interface than getopt. I 1925 * wouldn't mind if someone added more knobs to getopt to make it 1926 * work better. Who knows, I may talk myself into doing it someday, 1927 * if the standards weenies let me. As it is, it just leads to 1928 * hackery like this and causes people to avoid it in some cases. 1929 * 1930 * KDM, September 8th, 1998 1931 */ 1932 if (subopt != NULL) 1933 sprintf(combinedopt, "%s%s", mainopt, subopt); 1934 else 1935 sprintf(combinedopt, "%s", mainopt); 1936 1937 /* 1938 * Start getopt processing at argv[2], since we've already accepted 1939 * argv[1] as the command name. 1940 */ 1941 optind = 2; 1942 1943 /* 1944 * Now we run through the argument list looking for generic 1945 * options, and ignoring options that possibly belong to 1946 * subfunctions. 1947 */ 1948 while ((c = getopt(argc, argv, combinedopt))!= -1){ 1949 switch(c) { 1950 case 'C': 1951 retry_count = strtol(optarg, NULL, 0); 1952 if (retry_count < 0) 1953 errx(1, "retry count %d is < 0", 1954 retry_count); 1955 arglist |= CAM_ARG_RETRIES; 1956 break; 1957 case 'E': 1958 arglist |= CAM_ARG_ERR_RECOVER; 1959 break; 1960 case 'n': 1961 arglist |= CAM_ARG_DEVICE; 1962 tstr = optarg; 1963 while (isspace(*tstr) && (*tstr != '\0')) 1964 tstr++; 1965 device = (char *)strdup(tstr); 1966 break; 1967 case 't': 1968 timeout = strtol(optarg, NULL, 0); 1969 if (timeout < 0) 1970 errx(1, "invalid timeout %d", timeout); 1971 /* Convert the timeout from seconds to ms */ 1972 timeout *= 1000; 1973 arglist |= CAM_ARG_TIMEOUT; 1974 break; 1975 case 'u': 1976 arglist |= CAM_ARG_UNIT; 1977 unit = strtol(optarg, NULL, 0); 1978 break; 1979 case 'v': 1980 arglist |= CAM_ARG_VERBOSE; 1981 break; 1982 default: 1983 break; 1984 } 1985 } 1986 1987 if ((arglist & CAM_ARG_DEVICE) == 0) 1988 device = (char *)strdup(DEFAULT_DEVICE); 1989 1990 if ((arglist & CAM_ARG_UNIT) == 0) 1991 unit = DEFAULT_UNIT; 1992 1993 /* 1994 * For most commands we'll want to open the passthrough device 1995 * associated with the specified device. In the case of the rescan 1996 * commands, we don't use a passthrough device at all, just the 1997 * transport layer device. 1998 */ 1999 if (((arglist & CAM_ARG_OPT_MASK) != CAM_ARG_RESCAN) 2000 && ((arglist & CAM_ARG_OPT_MASK) != CAM_ARG_RESET) 2001 && ((arglist & CAM_ARG_OPT_MASK) != CAM_ARG_DEVTREE) 2002 && ((arglist & CAM_ARG_OPT_MASK) != CAM_ARG_USAGE) 2003 && ((arglist & CAM_ARG_OPT_MASK) != CAM_ARG_DEBUG)) { 2004 2005 if ((cam_dev = cam_open_spec_device(device,unit,O_RDWR, 2006 NULL))== NULL) 2007 errx(1,"%s", cam_errbuf); 2008 } 2009 2010 /* 2011 * Reset optind to 2, and reset getopt, so these routines can parse 2012 * the arguments again. 2013 */ 2014 optind = 2; 2015 optreset = 1; 2016 2017 switch(arglist & CAM_ARG_OPT_MASK) { 2018 case CAM_ARG_DEVLIST: 2019 error = getdevlist(cam_dev); 2020 break; 2021 case CAM_ARG_DEVTREE: 2022 error = getdevtree(); 2023 break; 2024 case CAM_ARG_TUR: 2025 error = testunitready(cam_dev, retry_count, timeout); 2026 break; 2027 case CAM_ARG_INQUIRY: 2028 error = scsidoinquiry(cam_dev, argc, argv, combinedopt, 2029 retry_count, timeout); 2030 break; 2031 case CAM_ARG_STARTSTOP: 2032 error = scsistart(cam_dev, arglist & CAM_ARG_START_UNIT, 2033 arglist & CAM_ARG_EJECT, retry_count, 2034 timeout); 2035 break; 2036 case CAM_ARG_RESCAN: 2037 error = dorescan_or_reset(argc, argv, 1); 2038 break; 2039 case CAM_ARG_RESET: 2040 error = dorescan_or_reset(argc, argv, 0); 2041 break; 2042 case CAM_ARG_READ_DEFECTS: 2043 error = readdefects(cam_dev, argc, argv, combinedopt, 2044 retry_count, timeout); 2045 break; 2046 case CAM_ARG_MODE_PAGE: 2047 modepage(cam_dev, argc, argv, combinedopt, 2048 retry_count, timeout); 2049 break; 2050 case CAM_ARG_SCSI_CMD: 2051 error = scsicmd(cam_dev, argc, argv, combinedopt, 2052 retry_count, timeout); 2053 break; 2054 case CAM_ARG_DEBUG: 2055 error = camdebug(argc, argv, combinedopt); 2056 break; 2057 default: 2058 usage(); 2059 error = 1; 2060 break; 2061 } 2062 2063 if (cam_dev != NULL) 2064 cam_close_device(cam_dev); 2065 2066 exit(error); 2067} 2068