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