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