1 /*- 2 * Copyright (c) 2003, 2004 Silicon Graphics International Corp. 3 * Copyright (c) 1997-2007 Kenneth D. Merry 4 * Copyright (c) 2012 The FreeBSD Foundation 5 * All rights reserved. 6 * 7 * Portions of this software were developed by Edward Tomasz Napierala 8 * under sponsorship from the FreeBSD Foundation. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions, and the following disclaimer, 15 * without modification. 16 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 17 * substantially similar to the "NO WARRANTY" disclaimer below 18 * ("Disclaimer") and any redistribution must be conditioned upon 19 * including a substantially similar Disclaimer requirement for further 20 * binary redistribution. 21 * 22 * NO WARRANTY 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 32 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGES. 34 * 35 * $Id: //depot/users/kenm/FreeBSD-test2/usr.sbin/ctladm/ctladm.c#4 $ 36 */ 37 /* 38 * CAM Target Layer exercise program. 39 * 40 * Author: Ken Merry <ken@FreeBSD.org> 41 */ 42 43 #include <sys/cdefs.h> 44 __FBSDID("$FreeBSD$"); 45 46 #include <sys/ioctl.h> 47 #include <sys/types.h> 48 #include <sys/stat.h> 49 #include <sys/param.h> 50 #include <sys/linker.h> 51 #include <sys/queue.h> 52 #include <sys/callout.h> 53 #include <sys/sbuf.h> 54 #include <stdint.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <unistd.h> 58 #include <fcntl.h> 59 #include <getopt.h> 60 #include <string.h> 61 #include <errno.h> 62 #include <err.h> 63 #include <ctype.h> 64 #include <bsdxml.h> 65 #include <cam/scsi/scsi_all.h> 66 #include <cam/scsi/scsi_message.h> 67 #include <cam/ctl/ctl.h> 68 #include <cam/ctl/ctl_io.h> 69 #include <cam/ctl/ctl_frontend_internal.h> 70 #include <cam/ctl/ctl_backend.h> 71 #include <cam/ctl/ctl_ioctl.h> 72 #include <cam/ctl/ctl_backend_block.h> 73 #include <cam/ctl/ctl_util.h> 74 #include <cam/ctl/ctl_scsi_all.h> 75 #include <camlib.h> 76 #include <libutil.h> 77 #include "ctladm.h" 78 79 #ifdef min 80 #undef min 81 #endif 82 #define min(x,y) (x < y) ? x : y 83 84 typedef enum { 85 CTLADM_CMD_TUR, 86 CTLADM_CMD_INQUIRY, 87 CTLADM_CMD_REQ_SENSE, 88 CTLADM_CMD_ARRAYLIST, 89 CTLADM_CMD_REPORT_LUNS, 90 CTLADM_CMD_HELP, 91 CTLADM_CMD_DEVLIST, 92 CTLADM_CMD_ADDDEV, 93 CTLADM_CMD_RM, 94 CTLADM_CMD_CREATE, 95 CTLADM_CMD_READ, 96 CTLADM_CMD_WRITE, 97 CTLADM_CMD_PORT, 98 CTLADM_CMD_READCAPACITY, 99 CTLADM_CMD_MODESENSE, 100 CTLADM_CMD_DUMPOOA, 101 CTLADM_CMD_DUMPSTRUCTS, 102 CTLADM_CMD_START, 103 CTLADM_CMD_STOP, 104 CTLADM_CMD_SYNC_CACHE, 105 CTLADM_CMD_SHUTDOWN, 106 CTLADM_CMD_STARTUP, 107 CTLADM_CMD_LUNLIST, 108 CTLADM_CMD_HARDSTOP, 109 CTLADM_CMD_HARDSTART, 110 CTLADM_CMD_DELAY, 111 CTLADM_CMD_REALSYNC, 112 CTLADM_CMD_SETSYNC, 113 CTLADM_CMD_GETSYNC, 114 CTLADM_CMD_ERR_INJECT, 115 CTLADM_CMD_BBRREAD, 116 CTLADM_CMD_PRES_IN, 117 CTLADM_CMD_PRES_OUT, 118 CTLADM_CMD_INQ_VPD_DEVID, 119 CTLADM_CMD_RTPG, 120 CTLADM_CMD_MODIFY 121 } ctladm_cmdfunction; 122 123 typedef enum { 124 CTLADM_ARG_NONE = 0x0000000, 125 CTLADM_ARG_AUTOSENSE = 0x0000001, 126 CTLADM_ARG_DEVICE = 0x0000002, 127 CTLADM_ARG_ARRAYSIZE = 0x0000004, 128 CTLADM_ARG_BACKEND = 0x0000008, 129 CTLADM_ARG_CDBSIZE = 0x0000010, 130 CTLADM_ARG_DATALEN = 0x0000020, 131 CTLADM_ARG_FILENAME = 0x0000040, 132 CTLADM_ARG_LBA = 0x0000080, 133 CTLADM_ARG_PC = 0x0000100, 134 CTLADM_ARG_PAGE_CODE = 0x0000200, 135 CTLADM_ARG_PAGE_LIST = 0x0000400, 136 CTLADM_ARG_SUBPAGE = 0x0000800, 137 CTLADM_ARG_PAGELIST = 0x0001000, 138 CTLADM_ARG_DBD = 0x0002000, 139 CTLADM_ARG_TARG_LUN = 0x0004000, 140 CTLADM_ARG_BLOCKSIZE = 0x0008000, 141 CTLADM_ARG_IMMED = 0x0010000, 142 CTLADM_ARG_RELADR = 0x0020000, 143 CTLADM_ARG_RETRIES = 0x0040000, 144 CTLADM_ARG_ONOFFLINE = 0x0080000, 145 CTLADM_ARG_ONESHOT = 0x0100000, 146 CTLADM_ARG_TIMEOUT = 0x0200000, 147 CTLADM_ARG_INITIATOR = 0x0400000, 148 CTLADM_ARG_NOCOPY = 0x0800000, 149 CTLADM_ARG_NEED_TL = 0x1000000 150 } ctladm_cmdargs; 151 152 struct ctladm_opts { 153 const char *optname; 154 uint32_t cmdnum; 155 ctladm_cmdargs argnum; 156 const char *subopt; 157 }; 158 159 typedef enum { 160 CC_OR_NOT_FOUND, 161 CC_OR_AMBIGUOUS, 162 CC_OR_FOUND 163 } ctladm_optret; 164 165 static const char rw_opts[] = "Nb:c:d:f:l:"; 166 static const char startstop_opts[] = "io"; 167 168 static struct ctladm_opts option_table[] = { 169 {"adddev", CTLADM_CMD_ADDDEV, CTLADM_ARG_NONE, NULL}, 170 {"bbrread", CTLADM_CMD_BBRREAD, CTLADM_ARG_NEED_TL, "d:l:"}, 171 {"create", CTLADM_CMD_CREATE, CTLADM_ARG_NONE, "b:B:d:l:o:s:S:t:"}, 172 {"delay", CTLADM_CMD_DELAY, CTLADM_ARG_NEED_TL, "T:l:t:"}, 173 {"devid", CTLADM_CMD_INQ_VPD_DEVID, CTLADM_ARG_NEED_TL, NULL}, 174 {"devlist", CTLADM_CMD_DEVLIST, CTLADM_ARG_NONE, "b:vx"}, 175 {"dumpooa", CTLADM_CMD_DUMPOOA, CTLADM_ARG_NONE, NULL}, 176 {"dumpstructs", CTLADM_CMD_DUMPSTRUCTS, CTLADM_ARG_NONE, NULL}, 177 {"getsync", CTLADM_CMD_GETSYNC, CTLADM_ARG_NEED_TL, NULL}, 178 {"hardstart", CTLADM_CMD_HARDSTART, CTLADM_ARG_NONE, NULL}, 179 {"hardstop", CTLADM_CMD_HARDSTOP, CTLADM_ARG_NONE, NULL}, 180 {"help", CTLADM_CMD_HELP, CTLADM_ARG_NONE, NULL}, 181 {"inject", CTLADM_CMD_ERR_INJECT, CTLADM_ARG_NEED_TL, "cd:i:p:r:s:"}, 182 {"inquiry", CTLADM_CMD_INQUIRY, CTLADM_ARG_NEED_TL, NULL}, 183 {"lunlist", CTLADM_CMD_LUNLIST, CTLADM_ARG_NONE, NULL}, 184 {"modesense", CTLADM_CMD_MODESENSE, CTLADM_ARG_NEED_TL, "P:S:dlm:c:"}, 185 {"modify", CTLADM_CMD_MODIFY, CTLADM_ARG_NONE, "b:l:s:"}, 186 {"port", CTLADM_CMD_PORT, CTLADM_ARG_NONE, "lo:p:qt:w:W:x"}, 187 {"prin", CTLADM_CMD_PRES_IN, CTLADM_ARG_NEED_TL, "a:"}, 188 {"prout", CTLADM_CMD_PRES_OUT, CTLADM_ARG_NEED_TL, "a:k:r:s:"}, 189 {"read", CTLADM_CMD_READ, CTLADM_ARG_NEED_TL, rw_opts}, 190 {"readcapacity", CTLADM_CMD_READCAPACITY, CTLADM_ARG_NEED_TL, "c:"}, 191 {"realsync", CTLADM_CMD_REALSYNC, CTLADM_ARG_NONE, NULL}, 192 {"remove", CTLADM_CMD_RM, CTLADM_ARG_NONE, "b:l:o:"}, 193 {"reportluns", CTLADM_CMD_REPORT_LUNS, CTLADM_ARG_NEED_TL, NULL}, 194 {"reqsense", CTLADM_CMD_REQ_SENSE, CTLADM_ARG_NEED_TL, NULL}, 195 {"rtpg", CTLADM_CMD_RTPG, CTLADM_ARG_NEED_TL, NULL}, 196 {"setsync", CTLADM_CMD_SETSYNC, CTLADM_ARG_NEED_TL, "i:"}, 197 {"shutdown", CTLADM_CMD_SHUTDOWN, CTLADM_ARG_NONE, NULL}, 198 {"start", CTLADM_CMD_START, CTLADM_ARG_NEED_TL, startstop_opts}, 199 {"startup", CTLADM_CMD_STARTUP, CTLADM_ARG_NONE, NULL}, 200 {"stop", CTLADM_CMD_STOP, CTLADM_ARG_NEED_TL, startstop_opts}, 201 {"synccache", CTLADM_CMD_SYNC_CACHE, CTLADM_ARG_NEED_TL, "b:c:il:r"}, 202 {"tur", CTLADM_CMD_TUR, CTLADM_ARG_NEED_TL, NULL}, 203 {"write", CTLADM_CMD_WRITE, CTLADM_ARG_NEED_TL, rw_opts}, 204 {"-?", CTLADM_CMD_HELP, CTLADM_ARG_NONE, NULL}, 205 {"-h", CTLADM_CMD_HELP, CTLADM_ARG_NONE, NULL}, 206 {NULL, 0, 0, NULL} 207 }; 208 209 210 ctladm_optret getoption(struct ctladm_opts *table, char *arg, uint32_t *cmdnum, 211 ctladm_cmdargs *argnum, const char **subopt); 212 static int cctl_parse_tl(char *str, int *target, int *lun); 213 static int cctl_dump_ooa(int fd, int argc, char **argv); 214 static int cctl_port_dump(int fd, int quiet, int xml, int32_t fe_num, 215 ctl_port_type port_type); 216 static int cctl_port(int fd, int argc, char **argv, char *combinedopt); 217 static int cctl_do_io(int fd, int retries, union ctl_io *io, const char *func); 218 static int cctl_delay(int fd, int target, int lun, int argc, char **argv, 219 char *combinedopt); 220 static int cctl_lunlist(int fd); 221 static void cctl_cfi_mt_statusstr(cfi_mt_status status, char *str, int str_len); 222 static void cctl_cfi_bbr_statusstr(cfi_bbrread_status, char *str, int str_len); 223 static int cctl_hardstopstart(int fd, ctladm_cmdfunction command); 224 static int cctl_bbrread(int fd, int target, int lun, int iid, int argc, 225 char **argv, char *combinedopt); 226 static int cctl_startup_shutdown(int fd, int target, int lun, int iid, 227 ctladm_cmdfunction command); 228 static int cctl_sync_cache(int fd, int target, int lun, int iid, int retries, 229 int argc, char **argv, char *combinedopt); 230 static int cctl_start_stop(int fd, int target, int lun, int iid, int retries, 231 int start, int argc, char **argv, char *combinedopt); 232 static int cctl_mode_sense(int fd, int target, int lun, int iid, int retries, 233 int argc, char **argv, char *combinedopt); 234 static int cctl_read_capacity(int fd, int target, int lun, int iid, 235 int retries, int argc, char **argv, 236 char *combinedopt); 237 static int cctl_read_write(int fd, int target, int lun, int iid, int retries, 238 int argc, char **argv, char *combinedopt, 239 ctladm_cmdfunction command); 240 static int cctl_get_luns(int fd, int target, int lun, int iid, int retries, 241 struct scsi_report_luns_data **lun_data, 242 uint32_t *num_luns); 243 static int cctl_report_luns(int fd, int target, int lun, int iid, int retries); 244 static int cctl_tur(int fd, int target, int lun, int iid, int retries); 245 static int cctl_get_inquiry(int fd, int target, int lun, int iid, int retries, 246 char *path_str, int path_len, 247 struct scsi_inquiry_data *inq_data); 248 static int cctl_inquiry(int fd, int target, int lun, int iid, int retries); 249 static int cctl_req_sense(int fd, int target, int lun, int iid, int retries); 250 static int cctl_persistent_reserve_in(int fd, int target, int lun, 251 int initiator, int argc, char **argv, 252 char *combinedopt, int retry_count); 253 static int cctl_persistent_reserve_out(int fd, int target, int lun, 254 int initiator, int argc, char **argv, 255 char *combinedopt, int retry_count); 256 static int cctl_create_lun(int fd, int argc, char **argv, char *combinedopt); 257 static int cctl_inquiry_vpd_devid(int fd, int target, int lun, int initiator); 258 static int cctl_report_target_port_group(int fd, int target, int lun, 259 int initiator); 260 static int cctl_modify_lun(int fd, int argc, char **argv, char *combinedopt); 261 262 ctladm_optret 263 getoption(struct ctladm_opts *table, char *arg, uint32_t *cmdnum, 264 ctladm_cmdargs *argnum, const char **subopt) 265 { 266 struct ctladm_opts *opts; 267 int num_matches = 0; 268 269 for (opts = table; (opts != NULL) && (opts->optname != NULL); 270 opts++) { 271 if (strncmp(opts->optname, arg, strlen(arg)) == 0) { 272 *cmdnum = opts->cmdnum; 273 *argnum = opts->argnum; 274 *subopt = opts->subopt; 275 276 if (strcmp(opts->optname, arg) == 0) 277 return (CC_OR_FOUND); 278 279 if (++num_matches > 1) 280 return(CC_OR_AMBIGUOUS); 281 } 282 } 283 284 if (num_matches > 0) 285 return(CC_OR_FOUND); 286 else 287 return(CC_OR_NOT_FOUND); 288 } 289 290 291 static int 292 cctl_parse_tl(char *str, int *target, int *lun) 293 { 294 char *tmpstr; 295 int retval; 296 297 retval = 0; 298 299 while (isspace(*str) && (*str != '\0')) 300 str++; 301 302 tmpstr = (char *)strtok(str, ":"); 303 if ((tmpstr != NULL) && (*tmpstr != '\0')) { 304 *target = strtol(tmpstr, NULL, 0); 305 tmpstr = (char *)strtok(NULL, ":"); 306 if ((tmpstr != NULL) && (*tmpstr != '\0')) { 307 *lun = strtol(tmpstr, NULL, 0); 308 } else 309 retval = -1; 310 } else 311 retval = -1; 312 313 return (retval); 314 } 315 316 static int 317 cctl_dump_ooa(int fd, int argc, char **argv) 318 { 319 struct ctl_ooa ooa; 320 long double cmd_latency; 321 int num_entries, len; 322 int target = -1, lun = -1; 323 int retval; 324 unsigned int i; 325 326 num_entries = 104; 327 328 if ((argc > 2) 329 && (isdigit(argv[2][0]))) { 330 retval = cctl_parse_tl(argv[2], &target, &lun); 331 if (retval != 0) 332 warnx("invalid target:lun argument %s", argv[2]); 333 } 334 retry: 335 336 len = num_entries * sizeof(struct ctl_ooa_entry); 337 338 bzero(&ooa, sizeof(ooa)); 339 340 ooa.entries = malloc(len); 341 342 if (ooa.entries == NULL) { 343 warn("%s: error mallocing %d bytes", __func__, len); 344 return (1); 345 } 346 347 if (argc > 2) { 348 ooa.lun_num = lun; 349 } else 350 ooa.flags |= CTL_OOA_FLAG_ALL_LUNS; 351 352 ooa.alloc_len = len; 353 ooa.alloc_num = num_entries; 354 if (ioctl(fd, CTL_GET_OOA, &ooa) == -1) { 355 warn("%s: CTL_GET_OOA ioctl failed", __func__); 356 retval = 1; 357 goto bailout; 358 } 359 360 if (ooa.status == CTL_OOA_NEED_MORE_SPACE) { 361 num_entries = num_entries * 2; 362 free(ooa.entries); 363 ooa.entries = NULL; 364 goto retry; 365 } 366 367 if (ooa.status != CTL_OOA_OK) { 368 warnx("%s: CTL_GET_OOA ioctl returned error %d", __func__, 369 ooa.status); 370 retval = 1; 371 goto bailout; 372 } 373 374 fprintf(stdout, "Dumping OOA queues\n"); 375 for (i = 0; i < ooa.fill_num; i++) { 376 struct ctl_ooa_entry *entry; 377 char cdb_str[(SCSI_MAX_CDBLEN * 3) +1]; 378 struct bintime delta_bt; 379 struct timespec ts; 380 381 entry = &ooa.entries[i]; 382 383 delta_bt = ooa.cur_bt; 384 bintime_sub(&delta_bt, &entry->start_bt); 385 bintime2timespec(&delta_bt, &ts); 386 cmd_latency = ts.tv_sec * 1000; 387 if (ts.tv_nsec > 0) 388 cmd_latency += ts.tv_nsec / 1000000; 389 390 fprintf(stdout, "LUN %jd tag 0x%04x%s%s%s%s%s: %s. CDB: %s " 391 "(%0.0Lf ms)\n", 392 (intmax_t)entry->lun_num, entry->tag_num, 393 (entry->cmd_flags & CTL_OOACMD_FLAG_BLOCKED) ? 394 " BLOCKED" : "", 395 (entry->cmd_flags & CTL_OOACMD_FLAG_DMA) ? " DMA" : "", 396 (entry->cmd_flags & CTL_OOACMD_FLAG_DMA_QUEUED) ? 397 " DMAQUEUED" : "", 398 (entry->cmd_flags & CTL_OOACMD_FLAG_ABORT) ? 399 " ABORT" : "", 400 (entry->cmd_flags & CTL_OOACMD_FLAG_RTR) ? " RTR" :"", 401 scsi_op_desc(entry->cdb[0], NULL), 402 scsi_cdb_string(entry->cdb, cdb_str, sizeof(cdb_str)), 403 cmd_latency); 404 } 405 fprintf(stdout, "OOA queues dump done\n"); 406 #if 0 407 if (ioctl(fd, CTL_DUMP_OOA) == -1) { 408 warn("%s: CTL_DUMP_OOA ioctl failed", __func__); 409 return (1); 410 } 411 #endif 412 413 bailout: 414 free(ooa.entries); 415 416 return (0); 417 } 418 419 static int 420 cctl_dump_structs(int fd, ctladm_cmdargs cmdargs __unused) 421 { 422 if (ioctl(fd, CTL_DUMP_STRUCTS) == -1) { 423 warn(__func__); 424 return (1); 425 } 426 return (0); 427 } 428 429 static int 430 cctl_port_dump(int fd, int quiet, int xml, int32_t targ_port, 431 ctl_port_type port_type) 432 { 433 struct ctl_port_list port_list; 434 struct ctl_port_entry *entries; 435 struct sbuf *sb = NULL; 436 int num_entries; 437 int did_print = 0; 438 unsigned int i; 439 440 num_entries = 16; 441 442 retry: 443 444 entries = malloc(sizeof(*entries) * num_entries); 445 bzero(&port_list, sizeof(port_list)); 446 port_list.entries = entries; 447 port_list.alloc_num = num_entries; 448 port_list.alloc_len = num_entries * sizeof(*entries); 449 if (ioctl(fd, CTL_GET_PORT_LIST, &port_list) != 0) { 450 warn("%s: CTL_GET_PORT_LIST ioctl failed", __func__); 451 return (1); 452 } 453 if (port_list.status == CTL_PORT_LIST_NEED_MORE_SPACE) { 454 printf("%s: allocated %d, need %d, retrying\n", __func__, 455 num_entries, port_list.fill_num + port_list.dropped_num); 456 free(entries); 457 num_entries = port_list.fill_num + port_list.dropped_num; 458 goto retry; 459 } 460 461 if ((quiet == 0) 462 && (xml == 0)) 463 printf("Port Online Type Name pp vp %-18s %-18s\n", 464 "WWNN", "WWPN"); 465 466 if (xml != 0) { 467 sb = sbuf_new_auto(); 468 sbuf_printf(sb, "<ctlfelist>\n"); 469 } 470 for (i = 0; i < port_list.fill_num; i++) { 471 struct ctl_port_entry *entry; 472 const char *type; 473 474 entry = &entries[i]; 475 476 switch (entry->port_type) { 477 case CTL_PORT_FC: 478 type = "FC"; 479 break; 480 case CTL_PORT_SCSI: 481 type = "SCSI"; 482 break; 483 case CTL_PORT_IOCTL: 484 type = "IOCTL"; 485 break; 486 case CTL_PORT_INTERNAL: 487 type = "INTERNAL"; 488 break; 489 case CTL_PORT_ISC: 490 type = "ISC"; 491 break; 492 default: 493 type = "UNKNOWN"; 494 break; 495 } 496 497 /* 498 * If the user specified a frontend number or a particular 499 * frontend type, only print out that particular frontend 500 * or frontend type. 501 */ 502 if ((targ_port != -1) 503 && (targ_port != entry->targ_port)) 504 continue; 505 else if ((port_type != CTL_PORT_NONE) 506 && ((port_type & entry->port_type) == 0)) 507 continue; 508 509 did_print = 1; 510 511 #if 0 512 printf("Num: %ju Type: %s (%#x) Name: %s Physical Port: %d " 513 "Virtual Port: %d\n", (uintmax_t)entry->fe_num, type, 514 entry->port_type, entry->fe_name, entry->physical_port, 515 entry->virtual_port); 516 printf("WWNN %#jx WWPN %#jx Online: %s\n", 517 (uintmax_t)entry->wwnn, (uintmax_t)entry->wwpn, 518 (entry->online) ? "YES" : "NO" ); 519 #endif 520 if (xml == 0) { 521 printf("%-4d %-6s %-8s %-12s %-2d %-2d %#-18jx " 522 "%#-18jx\n", 523 entry->targ_port, (entry->online) ? "YES" : "NO", 524 type, entry->port_name, entry->physical_port, 525 entry->virtual_port, (uintmax_t)entry->wwnn, 526 (uintmax_t)entry->wwpn); 527 } else { 528 sbuf_printf(sb, "<targ_port id=\"%d\">\n", 529 entry->targ_port); 530 sbuf_printf(sb, "<online>%s</online>\n", 531 (entry->online) ? "YES" : "NO"); 532 sbuf_printf(sb, "<port_type>%s</port_type>\n", type); 533 sbuf_printf(sb, "<port_name>%s</port_name>\n", 534 entry->port_name); 535 sbuf_printf(sb, "<physical_port>%d</physical_port>\n", 536 entry->physical_port); 537 sbuf_printf(sb, "<virtual_port>%d</virtual_port>\n", 538 entry->virtual_port); 539 sbuf_printf(sb, "<wwnn>%#jx</wwnn>\n", 540 (uintmax_t)entry->wwnn); 541 sbuf_printf(sb, "<wwpn>%#jx</wwpn>\n", 542 (uintmax_t)entry->wwpn); 543 sbuf_printf(sb, "</targ_port>\n"); 544 } 545 546 } 547 if (xml != 0) { 548 sbuf_printf(sb, "</ctlfelist>\n"); 549 if (sbuf_finish(sb) != 0) 550 err(1, "%s: sbuf_finish", __func__); 551 printf("%s", sbuf_data(sb)); 552 sbuf_delete(sb); 553 } 554 555 /* 556 * Give some indication that we didn't find the frontend or 557 * frontend type requested by the user. We could print something 558 * out, but it would probably be better to hide that behind a 559 * verbose flag. 560 */ 561 if ((did_print == 0) 562 && ((targ_port != -1) 563 || (port_type != CTL_PORT_NONE))) 564 return (1); 565 else 566 return (0); 567 } 568 569 typedef enum { 570 CCTL_PORT_MODE_NONE, 571 CCTL_PORT_MODE_LIST, 572 CCTL_PORT_MODE_SET, 573 CCTL_PORT_MODE_ON, 574 CCTL_PORT_MODE_OFF 575 } cctl_port_mode; 576 577 static struct ctladm_opts cctl_fe_table[] = { 578 {"fc", CTL_PORT_FC, CTLADM_ARG_NONE, NULL}, 579 {"scsi", CTL_PORT_SCSI, CTLADM_ARG_NONE, NULL}, 580 {"internal", CTL_PORT_INTERNAL, CTLADM_ARG_NONE, NULL}, 581 {"all", CTL_PORT_ALL, CTLADM_ARG_NONE, NULL}, 582 {NULL, 0, 0, NULL} 583 }; 584 585 static int 586 cctl_port(int fd, int argc, char **argv, char *combinedopt) 587 { 588 int c; 589 int32_t targ_port = -1; 590 int retval = 0; 591 int wwnn_set = 0, wwpn_set = 0; 592 uint64_t wwnn = 0, wwpn = 0; 593 cctl_port_mode port_mode = CCTL_PORT_MODE_NONE; 594 struct ctl_port_entry entry; 595 ctl_port_type port_type = CTL_PORT_NONE; 596 int quiet = 0, xml = 0; 597 598 while ((c = getopt(argc, argv, combinedopt)) != -1) { 599 switch (c) { 600 case 'l': 601 if (port_mode != CCTL_PORT_MODE_NONE) 602 goto bailout_badarg; 603 604 port_mode = CCTL_PORT_MODE_LIST; 605 break; 606 case 'o': 607 if (port_mode != CCTL_PORT_MODE_NONE) 608 goto bailout_badarg; 609 610 if (strcasecmp(optarg, "on") == 0) 611 port_mode = CCTL_PORT_MODE_ON; 612 else if (strcasecmp(optarg, "off") == 0) 613 port_mode = CCTL_PORT_MODE_OFF; 614 else { 615 warnx("Invalid -o argument %s, \"on\" or " 616 "\"off\" are the only valid args", 617 optarg); 618 retval = 1; 619 goto bailout; 620 } 621 break; 622 case 'p': 623 targ_port = strtol(optarg, NULL, 0); 624 break; 625 case 'q': 626 quiet = 1; 627 break; 628 case 't': { 629 ctladm_optret optret; 630 ctladm_cmdargs argnum; 631 const char *subopt; 632 ctl_port_type tmp_port_type; 633 634 optret = getoption(cctl_fe_table, optarg, &tmp_port_type, 635 &argnum, &subopt); 636 if (optret == CC_OR_AMBIGUOUS) { 637 warnx("%s: ambiguous frontend type %s", 638 __func__, optarg); 639 retval = 1; 640 goto bailout; 641 } else if (optret == CC_OR_NOT_FOUND) { 642 warnx("%s: invalid frontend type %s", 643 __func__, optarg); 644 retval = 1; 645 goto bailout; 646 } 647 648 port_type |= tmp_port_type; 649 break; 650 } 651 case 'w': 652 if ((port_mode != CCTL_PORT_MODE_NONE) 653 && (port_mode != CCTL_PORT_MODE_SET)) 654 goto bailout_badarg; 655 656 port_mode = CCTL_PORT_MODE_SET; 657 658 wwnn = strtoull(optarg, NULL, 0); 659 wwnn_set = 1; 660 break; 661 case 'W': 662 if ((port_mode != CCTL_PORT_MODE_NONE) 663 && (port_mode != CCTL_PORT_MODE_SET)) 664 goto bailout_badarg; 665 666 port_mode = CCTL_PORT_MODE_SET; 667 668 wwpn = strtoull(optarg, NULL, 0); 669 wwpn_set = 1; 670 break; 671 case 'x': 672 xml = 1; 673 break; 674 } 675 } 676 677 /* 678 * The user can specify either one or more frontend types (-t), or 679 * a specific frontend, but not both. 680 * 681 * If the user didn't specify a frontend type or number, set it to 682 * all. This is primarily needed for the enable/disable ioctls. 683 * This will be a no-op for the listing code. For the set ioctl, 684 * we'll throw an error, since that only works on one port at a time. 685 */ 686 if ((port_type != CTL_PORT_NONE) && (targ_port != -1)) { 687 warnx("%s: can only specify one of -t or -n", __func__); 688 retval = 1; 689 goto bailout; 690 } else if ((targ_port == -1) && (port_type == CTL_PORT_NONE)) 691 port_type = CTL_PORT_ALL; 692 693 bzero(&entry, sizeof(&entry)); 694 695 /* 696 * These are needed for all but list/dump mode. 697 */ 698 entry.port_type = port_type; 699 entry.targ_port = targ_port; 700 701 switch (port_mode) { 702 case CCTL_PORT_MODE_LIST: 703 cctl_port_dump(fd, quiet, xml, targ_port, port_type); 704 break; 705 case CCTL_PORT_MODE_SET: 706 if (targ_port == -1) { 707 warnx("%s: -w and -W require -n", __func__); 708 retval = 1; 709 goto bailout; 710 } 711 712 if (wwnn_set) { 713 entry.flags |= CTL_PORT_WWNN_VALID; 714 entry.wwnn = wwnn; 715 } 716 if (wwpn_set) { 717 entry.flags |= CTL_PORT_WWPN_VALID; 718 entry.wwpn = wwpn; 719 } 720 721 if (ioctl(fd, CTL_SET_PORT_WWNS, &entry) == -1) { 722 warn("%s: CTL_SET_PORT_WWNS ioctl failed", __func__); 723 retval = 1; 724 goto bailout; 725 } 726 break; 727 case CCTL_PORT_MODE_ON: 728 if (ioctl(fd, CTL_ENABLE_PORT, &entry) == -1) { 729 warn("%s: CTL_ENABLE_PORT ioctl failed", __func__); 730 retval = 1; 731 goto bailout; 732 } 733 fprintf(stdout, "Front End Ports enabled\n"); 734 break; 735 case CCTL_PORT_MODE_OFF: 736 if (ioctl(fd, CTL_DISABLE_PORT, &entry) == -1) { 737 warn("%s: CTL_DISABLE_PORT ioctl failed", __func__); 738 retval = 1; 739 goto bailout; 740 } 741 fprintf(stdout, "Front End Ports disabled\n"); 742 break; 743 default: 744 warnx("%s: one of -l, -o or -w/-W must be specified", __func__); 745 retval = 1; 746 goto bailout; 747 break; 748 } 749 750 bailout: 751 752 return (retval); 753 754 bailout_badarg: 755 warnx("%s: only one of -l, -o or -w/-W may be specified", __func__); 756 return (1); 757 } 758 759 static int 760 cctl_do_io(int fd, int retries, union ctl_io *io, const char *func) 761 { 762 do { 763 if (ioctl(fd, CTL_IO, io) == -1) { 764 warn("%s: error sending CTL_IO ioctl", func); 765 return (-1); 766 } 767 } while (((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS) 768 && (retries-- > 0)); 769 770 return (0); 771 } 772 773 static int 774 cctl_delay(int fd, int target, int lun, int argc, char **argv, 775 char *combinedopt) 776 { 777 struct ctl_io_delay_info delay_info; 778 char *delayloc = NULL; 779 char *delaytype = NULL; 780 int delaytime = -1; 781 int retval; 782 int c; 783 784 retval = 0; 785 786 memset(&delay_info, 0, sizeof(delay_info)); 787 788 while ((c = getopt(argc, argv, combinedopt)) != -1) { 789 switch (c) { 790 case 'T': 791 delaytype = strdup(optarg); 792 break; 793 case 'l': 794 delayloc = strdup(optarg); 795 break; 796 case 't': 797 delaytime = strtoul(optarg, NULL, 0); 798 break; 799 } 800 } 801 802 if (delaytime == -1) { 803 warnx("%s: you must specify the delaytime with -t", __func__); 804 retval = 1; 805 goto bailout; 806 } 807 808 if (strcasecmp(delayloc, "datamove") == 0) 809 delay_info.delay_loc = CTL_DELAY_LOC_DATAMOVE; 810 else if (strcasecmp(delayloc, "done") == 0) 811 delay_info.delay_loc = CTL_DELAY_LOC_DONE; 812 else { 813 warnx("%s: invalid delay location %s", __func__, delayloc); 814 retval = 1; 815 goto bailout; 816 } 817 818 if ((delaytype == NULL) 819 || (strcmp(delaytype, "oneshot") == 0)) 820 delay_info.delay_type = CTL_DELAY_TYPE_ONESHOT; 821 else if (strcmp(delaytype, "cont") == 0) 822 delay_info.delay_type = CTL_DELAY_TYPE_CONT; 823 else { 824 warnx("%s: invalid delay type %s", __func__, delaytype); 825 retval = 1; 826 goto bailout; 827 } 828 829 delay_info.target_id = target; 830 delay_info.lun_id = lun; 831 delay_info.delay_secs = delaytime; 832 833 if (ioctl(fd, CTL_DELAY_IO, &delay_info) == -1) { 834 warn("%s: CTL_DELAY_IO ioctl failed", __func__); 835 retval = 1; 836 goto bailout; 837 } 838 switch (delay_info.status) { 839 case CTL_DELAY_STATUS_NONE: 840 warnx("%s: no delay status??", __func__); 841 retval = 1; 842 break; 843 case CTL_DELAY_STATUS_OK: 844 break; 845 case CTL_DELAY_STATUS_INVALID_LUN: 846 warnx("%s: invalid lun %d", __func__, lun); 847 retval = 1; 848 break; 849 case CTL_DELAY_STATUS_INVALID_TYPE: 850 warnx("%s: invalid delay type %d", __func__, 851 delay_info.delay_type); 852 retval = 1; 853 break; 854 case CTL_DELAY_STATUS_INVALID_LOC: 855 warnx("%s: delay location %s not implemented?", __func__, 856 delayloc); 857 retval = 1; 858 break; 859 case CTL_DELAY_STATUS_NOT_IMPLEMENTED: 860 warnx("%s: delay not implemented in the kernel", __func__); 861 warnx("%s: recompile with the CTL_IO_DELAY flag set", __func__); 862 retval = 1; 863 break; 864 default: 865 warnx("%s: unknown delay return status %d", __func__, 866 delay_info.status); 867 retval = 1; 868 break; 869 } 870 bailout: 871 872 /* delayloc should never be NULL, but just in case...*/ 873 if (delayloc != NULL) 874 free(delayloc); 875 876 return (retval); 877 } 878 879 static int 880 cctl_realsync(int fd, int argc, char **argv) 881 { 882 int syncstate; 883 int retval; 884 char *syncarg; 885 886 retval = 0; 887 888 if (argc != 3) { 889 warnx("%s %s takes exactly one argument", argv[0], argv[1]); 890 retval = 1; 891 goto bailout; 892 } 893 894 syncarg = argv[2]; 895 896 if (strncasecmp(syncarg, "query", min(strlen(syncarg), 897 strlen("query"))) == 0) { 898 if (ioctl(fd, CTL_REALSYNC_GET, &syncstate) == -1) { 899 warn("%s: CTL_REALSYNC_GET ioctl failed", __func__); 900 retval = 1; 901 goto bailout; 902 } 903 fprintf(stdout, "SYNCHRONIZE CACHE support is: "); 904 switch (syncstate) { 905 case 0: 906 fprintf(stdout, "OFF\n"); 907 break; 908 case 1: 909 fprintf(stdout, "ON\n"); 910 break; 911 default: 912 fprintf(stdout, "unknown (%d)\n", syncstate); 913 break; 914 } 915 goto bailout; 916 } else if (strcasecmp(syncarg, "on") == 0) { 917 syncstate = 1; 918 } else if (strcasecmp(syncarg, "off") == 0) { 919 syncstate = 0; 920 } else { 921 warnx("%s: invalid realsync argument %s", __func__, syncarg); 922 retval = 1; 923 goto bailout; 924 } 925 926 if (ioctl(fd, CTL_REALSYNC_SET, &syncstate) == -1) { 927 warn("%s: CTL_REALSYNC_SET ioctl failed", __func__); 928 retval = 1; 929 goto bailout; 930 } 931 bailout: 932 return (retval); 933 } 934 935 static int 936 cctl_getsetsync(int fd, int target, int lun, ctladm_cmdfunction command, 937 int argc, char **argv, char *combinedopt) 938 { 939 struct ctl_sync_info sync_info; 940 uint32_t ioctl_cmd; 941 int sync_interval = -1; 942 int retval; 943 int c; 944 945 retval = 0; 946 947 memset(&sync_info, 0, sizeof(sync_info)); 948 sync_info.target_id = target; 949 sync_info.lun_id = lun; 950 951 while ((c = getopt(argc, argv, combinedopt)) != -1) { 952 switch (c) { 953 case 'i': 954 sync_interval = strtoul(optarg, NULL, 0); 955 break; 956 default: 957 break; 958 } 959 } 960 961 if (command == CTLADM_CMD_SETSYNC) { 962 if (sync_interval == -1) { 963 warnx("%s: you must specify the sync interval with -i", 964 __func__); 965 retval = 1; 966 goto bailout; 967 } 968 sync_info.sync_interval = sync_interval; 969 ioctl_cmd = CTL_SETSYNC; 970 } else { 971 ioctl_cmd = CTL_GETSYNC; 972 } 973 974 if (ioctl(fd, ioctl_cmd, &sync_info) == -1) { 975 warn("%s: CTL_%sSYNC ioctl failed", __func__, 976 (command == CTLADM_CMD_SETSYNC) ? "SET" : "GET"); 977 retval = 1; 978 goto bailout; 979 } 980 981 switch (sync_info.status) { 982 case CTL_GS_SYNC_OK: 983 if (command == CTLADM_CMD_GETSYNC) { 984 fprintf(stdout, "%d:%d: sync interval: %d\n", 985 target, lun, sync_info.sync_interval); 986 } 987 break; 988 case CTL_GS_SYNC_NO_LUN: 989 warnx("%s: unknown target:LUN %d:%d", __func__, target, lun); 990 retval = 1; 991 break; 992 case CTL_GS_SYNC_NONE: 993 default: 994 warnx("%s: unknown CTL_%sSYNC status %d", __func__, 995 (command == CTLADM_CMD_SETSYNC) ? "SET" : "GET", 996 sync_info.status); 997 retval = 1; 998 break; 999 } 1000 bailout: 1001 return (retval); 1002 } 1003 1004 static struct ctladm_opts cctl_err_types[] = { 1005 {"aborted", CTL_LUN_INJ_ABORTED, CTLADM_ARG_NONE, NULL}, 1006 {"mediumerr", CTL_LUN_INJ_MEDIUM_ERR, CTLADM_ARG_NONE, NULL}, 1007 {"ua", CTL_LUN_INJ_UA, CTLADM_ARG_NONE, NULL}, 1008 {"custom", CTL_LUN_INJ_CUSTOM, CTLADM_ARG_NONE, NULL}, 1009 {NULL, 0, 0, NULL} 1010 1011 }; 1012 1013 static struct ctladm_opts cctl_err_patterns[] = { 1014 {"read", CTL_LUN_PAT_READ, CTLADM_ARG_NONE, NULL}, 1015 {"write", CTL_LUN_PAT_WRITE, CTLADM_ARG_NONE, NULL}, 1016 {"rw", CTL_LUN_PAT_READWRITE, CTLADM_ARG_NONE, NULL}, 1017 {"readwrite", CTL_LUN_PAT_READWRITE, CTLADM_ARG_NONE, NULL}, 1018 {"readcap", CTL_LUN_PAT_READCAP, CTLADM_ARG_NONE, NULL}, 1019 {"tur", CTL_LUN_PAT_TUR, CTLADM_ARG_NONE, NULL}, 1020 {"any", CTL_LUN_PAT_ANY, CTLADM_ARG_NONE, NULL}, 1021 #if 0 1022 {"cmd", CTL_LUN_PAT_CMD, CTLADM_ARG_NONE, NULL}, 1023 #endif 1024 {NULL, 0, 0, NULL} 1025 }; 1026 1027 static int 1028 cctl_error_inject(int fd, uint32_t target, uint32_t lun, int argc, char **argv, 1029 char *combinedopt) 1030 { 1031 int retval = 0; 1032 struct ctl_error_desc err_desc; 1033 uint64_t lba = 0; 1034 uint32_t len = 0; 1035 uint64_t delete_id = 0; 1036 int delete_id_set = 0; 1037 int continuous = 0; 1038 int sense_len = 0; 1039 int fd_sense = 0; 1040 int c; 1041 1042 bzero(&err_desc, sizeof(err_desc)); 1043 err_desc.target_id = target; 1044 err_desc.lun_id = lun; 1045 1046 while ((c = getopt(argc, argv, combinedopt)) != -1) { 1047 switch (c) { 1048 case 'c': 1049 continuous = 1; 1050 break; 1051 case 'd': 1052 delete_id = strtoull(optarg, NULL, 0); 1053 delete_id_set = 1; 1054 break; 1055 case 'i': 1056 case 'p': { 1057 ctladm_optret optret; 1058 ctladm_cmdargs argnum; 1059 const char *subopt; 1060 1061 if (c == 'i') { 1062 ctl_lun_error err_type; 1063 1064 if (err_desc.lun_error != CTL_LUN_INJ_NONE) { 1065 warnx("%s: can't specify multiple -i " 1066 "arguments", __func__); 1067 retval = 1; 1068 goto bailout; 1069 } 1070 optret = getoption(cctl_err_types, optarg, 1071 &err_type, &argnum, &subopt); 1072 err_desc.lun_error = err_type; 1073 } else { 1074 ctl_lun_error_pattern pattern; 1075 1076 optret = getoption(cctl_err_patterns, optarg, 1077 &pattern, &argnum, &subopt); 1078 err_desc.error_pattern |= pattern; 1079 } 1080 1081 if (optret == CC_OR_AMBIGUOUS) { 1082 warnx("%s: ambiguous argument %s", __func__, 1083 optarg); 1084 retval = 1; 1085 goto bailout; 1086 } else if (optret == CC_OR_NOT_FOUND) { 1087 warnx("%s: argument %s not found", __func__, 1088 optarg); 1089 retval = 1; 1090 goto bailout; 1091 } 1092 break; 1093 } 1094 case 'r': { 1095 char *tmpstr, *tmpstr2; 1096 1097 tmpstr = strdup(optarg); 1098 if (tmpstr == NULL) { 1099 warn("%s: error duplicating string %s", 1100 __func__, optarg); 1101 retval = 1; 1102 goto bailout; 1103 } 1104 1105 tmpstr2 = strsep(&tmpstr, ","); 1106 if (tmpstr2 == NULL) { 1107 warnx("%s: invalid -r argument %s", __func__, 1108 optarg); 1109 retval = 1; 1110 free(tmpstr); 1111 goto bailout; 1112 } 1113 lba = strtoull(tmpstr2, NULL, 0); 1114 tmpstr2 = strsep(&tmpstr, ","); 1115 if (tmpstr2 == NULL) { 1116 warnx("%s: no len argument for -r lba,len, got" 1117 " %s", __func__, optarg); 1118 retval = 1; 1119 free(tmpstr); 1120 goto bailout; 1121 } 1122 len = strtoul(tmpstr2, NULL, 0); 1123 free(tmpstr); 1124 break; 1125 } 1126 case 's': { 1127 struct get_hook hook; 1128 char *sensestr; 1129 1130 sense_len = strtol(optarg, NULL, 0); 1131 if (sense_len <= 0) { 1132 warnx("invalid number of sense bytes %d", 1133 sense_len); 1134 retval = 1; 1135 goto bailout; 1136 } 1137 1138 sense_len = MIN(sense_len, SSD_FULL_SIZE); 1139 1140 hook.argc = argc - optind; 1141 hook.argv = argv + optind; 1142 hook.got = 0; 1143 1144 sensestr = cget(&hook, NULL); 1145 if ((sensestr != NULL) 1146 && (sensestr[0] == '-')) { 1147 fd_sense = 1; 1148 } else { 1149 buff_encode_visit( 1150 (uint8_t *)&err_desc.custom_sense, 1151 sense_len, sensestr, iget, &hook); 1152 } 1153 optind += hook.got; 1154 break; 1155 } 1156 default: 1157 break; 1158 } 1159 } 1160 1161 if (delete_id_set != 0) { 1162 err_desc.serial = delete_id; 1163 if (ioctl(fd, CTL_ERROR_INJECT_DELETE, &err_desc) == -1) { 1164 warn("%s: error issuing CTL_ERROR_INJECT_DELETE ioctl", 1165 __func__); 1166 retval = 1; 1167 } 1168 goto bailout; 1169 } 1170 1171 if (err_desc.lun_error == CTL_LUN_INJ_NONE) { 1172 warnx("%s: error injection command (-i) needed", 1173 __func__); 1174 retval = 1; 1175 goto bailout; 1176 } else if ((err_desc.lun_error == CTL_LUN_INJ_CUSTOM) 1177 && (sense_len == 0)) { 1178 warnx("%s: custom error requires -s", __func__); 1179 retval = 1; 1180 goto bailout; 1181 } 1182 1183 if (continuous != 0) 1184 err_desc.lun_error |= CTL_LUN_INJ_CONTINUOUS; 1185 1186 /* 1187 * If fd_sense is set, we need to read the sense data the user 1188 * wants returned from stdin. 1189 */ 1190 if (fd_sense == 1) { 1191 ssize_t amt_read; 1192 int amt_to_read = sense_len; 1193 u_int8_t *buf_ptr = (uint8_t *)&err_desc.custom_sense; 1194 1195 for (amt_read = 0; amt_to_read > 0; 1196 amt_read = read(STDIN_FILENO, buf_ptr, amt_to_read)) { 1197 if (amt_read == -1) { 1198 warn("error reading sense data from stdin"); 1199 retval = 1; 1200 goto bailout; 1201 } 1202 amt_to_read -= amt_read; 1203 buf_ptr += amt_read; 1204 } 1205 } 1206 1207 if (err_desc.error_pattern == CTL_LUN_PAT_NONE) { 1208 warnx("%s: command pattern (-p) needed", __func__); 1209 retval = 1; 1210 goto bailout; 1211 } 1212 1213 if (len != 0) { 1214 err_desc.error_pattern |= CTL_LUN_PAT_RANGE; 1215 /* 1216 * We could check here to see whether it's a read/write 1217 * command, but that will be pointless once we allow 1218 * custom patterns. At that point, the user could specify 1219 * a READ(6) CDB type, and we wouldn't have an easy way here 1220 * to verify whether range checking is possible there. The 1221 * user will just figure it out when his error never gets 1222 * executed. 1223 */ 1224 #if 0 1225 if ((err_desc.pattern & CTL_LUN_PAT_READWRITE) == 0) { 1226 warnx("%s: need read and/or write pattern if range " 1227 "is specified", __func__); 1228 retval = 1; 1229 goto bailout; 1230 } 1231 #endif 1232 err_desc.lba_range.lba = lba; 1233 err_desc.lba_range.len = len; 1234 } 1235 1236 if (ioctl(fd, CTL_ERROR_INJECT, &err_desc) == -1) { 1237 warn("%s: error issuing CTL_ERROR_INJECT ioctl", __func__); 1238 retval = 1; 1239 } else { 1240 printf("Error injection succeeded, serial number is %ju\n", 1241 (uintmax_t)err_desc.serial); 1242 } 1243 bailout: 1244 1245 return (retval); 1246 } 1247 1248 static int 1249 cctl_lunlist(int fd) 1250 { 1251 struct scsi_report_luns_data *lun_data; 1252 struct scsi_inquiry_data *inq_data; 1253 uint32_t num_luns; 1254 int target; 1255 int initid; 1256 unsigned int i; 1257 int retval; 1258 1259 retval = 0; 1260 inq_data = NULL; 1261 1262 target = 6; 1263 initid = 7; 1264 1265 /* 1266 * XXX KDM assuming LUN 0 is fine, but we may need to change this 1267 * if we ever acquire the ability to have multiple targets. 1268 */ 1269 if ((retval = cctl_get_luns(fd, target, /*lun*/ 0, initid, 1270 /*retries*/ 2, &lun_data, &num_luns)) != 0) 1271 goto bailout; 1272 1273 inq_data = malloc(sizeof(*inq_data)); 1274 if (inq_data == NULL) { 1275 warn("%s: couldn't allocate memory for inquiry data\n", 1276 __func__); 1277 retval = 1; 1278 goto bailout; 1279 } 1280 for (i = 0; i < num_luns; i++) { 1281 char scsi_path[40]; 1282 int lun_val; 1283 1284 switch (lun_data->luns[i].lundata[0] & RPL_LUNDATA_ATYP_MASK) { 1285 case RPL_LUNDATA_ATYP_PERIPH: 1286 lun_val = lun_data->luns[i].lundata[1]; 1287 break; 1288 case RPL_LUNDATA_ATYP_FLAT: 1289 lun_val = (lun_data->luns[i].lundata[0] & 1290 RPL_LUNDATA_FLAT_LUN_MASK) | 1291 (lun_data->luns[i].lundata[1] << 1292 RPL_LUNDATA_FLAT_LUN_BITS); 1293 break; 1294 case RPL_LUNDATA_ATYP_LUN: 1295 case RPL_LUNDATA_ATYP_EXTLUN: 1296 default: 1297 fprintf(stdout, "Unsupported LUN format %d\n", 1298 lun_data->luns[i].lundata[0] & 1299 RPL_LUNDATA_ATYP_MASK); 1300 lun_val = -1; 1301 break; 1302 } 1303 if (lun_val == -1) 1304 continue; 1305 1306 if ((retval = cctl_get_inquiry(fd, target, lun_val, initid, 1307 /*retries*/ 2, scsi_path, 1308 sizeof(scsi_path), 1309 inq_data)) != 0) { 1310 goto bailout; 1311 } 1312 printf("%s", scsi_path); 1313 scsi_print_inquiry(inq_data); 1314 } 1315 bailout: 1316 1317 if (lun_data != NULL) 1318 free(lun_data); 1319 1320 if (inq_data != NULL) 1321 free(inq_data); 1322 1323 return (retval); 1324 } 1325 1326 static void 1327 cctl_cfi_mt_statusstr(cfi_mt_status status, char *str, int str_len) 1328 { 1329 switch (status) { 1330 case CFI_MT_PORT_OFFLINE: 1331 snprintf(str, str_len, "Port Offline"); 1332 break; 1333 case CFI_MT_ERROR: 1334 snprintf(str, str_len, "Error"); 1335 break; 1336 case CFI_MT_SUCCESS: 1337 snprintf(str, str_len, "Success"); 1338 break; 1339 case CFI_MT_NONE: 1340 snprintf(str, str_len, "None??"); 1341 break; 1342 default: 1343 snprintf(str, str_len, "Unknown status: %d", status); 1344 break; 1345 } 1346 } 1347 1348 static void 1349 cctl_cfi_bbr_statusstr(cfi_bbrread_status status, char *str, int str_len) 1350 { 1351 switch (status) { 1352 case CFI_BBR_SUCCESS: 1353 snprintf(str, str_len, "Success"); 1354 break; 1355 case CFI_BBR_LUN_UNCONFIG: 1356 snprintf(str, str_len, "LUN not configured"); 1357 break; 1358 case CFI_BBR_NO_LUN: 1359 snprintf(str, str_len, "LUN does not exist"); 1360 break; 1361 case CFI_BBR_NO_MEM: 1362 snprintf(str, str_len, "Memory allocation error"); 1363 break; 1364 case CFI_BBR_BAD_LEN: 1365 snprintf(str, str_len, "Length is not a multiple of blocksize"); 1366 break; 1367 case CFI_BBR_RESERV_CONFLICT: 1368 snprintf(str, str_len, "Reservation conflict"); 1369 break; 1370 case CFI_BBR_LUN_STOPPED: 1371 snprintf(str, str_len, "LUN is powered off"); 1372 break; 1373 case CFI_BBR_LUN_OFFLINE_CTL: 1374 snprintf(str, str_len, "LUN is offline"); 1375 break; 1376 case CFI_BBR_LUN_OFFLINE_RC: 1377 snprintf(str, str_len, "RAIDCore array is offline (double " 1378 "failure?)"); 1379 break; 1380 case CFI_BBR_SCSI_ERROR: 1381 snprintf(str, str_len, "SCSI Error"); 1382 break; 1383 case CFI_BBR_ERROR: 1384 snprintf(str, str_len, "Error"); 1385 break; 1386 default: 1387 snprintf(str, str_len, "Unknown status: %d", status); 1388 break; 1389 } 1390 } 1391 1392 static int 1393 cctl_hardstopstart(int fd, ctladm_cmdfunction command) 1394 { 1395 struct ctl_hard_startstop_info hs_info; 1396 char error_str[256]; 1397 int do_start; 1398 int retval; 1399 1400 retval = 0; 1401 1402 if (command == CTLADM_CMD_HARDSTART) 1403 do_start = 1; 1404 else 1405 do_start = 0; 1406 1407 if (ioctl(fd, (do_start == 1) ? CTL_HARD_START : CTL_HARD_STOP, 1408 &hs_info) == -1) { 1409 warn("%s: CTL_HARD_%s ioctl failed", __func__, 1410 (do_start == 1) ? "START" : "STOP"); 1411 retval = 1; 1412 goto bailout; 1413 } 1414 1415 fprintf(stdout, "Hard %s Status: ", (command == CTLADM_CMD_HARDSTOP) ? 1416 "Stop" : "Start"); 1417 cctl_cfi_mt_statusstr(hs_info.status, error_str, sizeof(error_str)); 1418 fprintf(stdout, "%s\n", error_str); 1419 fprintf(stdout, "Total LUNs: %d\n", hs_info.total_luns); 1420 fprintf(stdout, "LUNs complete: %d\n", hs_info.luns_complete); 1421 fprintf(stdout, "LUNs failed: %d\n", hs_info.luns_failed); 1422 1423 bailout: 1424 return (retval); 1425 } 1426 1427 static int 1428 cctl_bbrread(int fd, int target __unused, int lun, int iid __unused, 1429 int argc, char **argv, char *combinedopt) 1430 { 1431 struct ctl_bbrread_info bbr_info; 1432 char error_str[256]; 1433 int datalen = -1; 1434 uint64_t lba = 0; 1435 int lba_set = 0; 1436 int retval; 1437 int c; 1438 1439 retval = 0; 1440 1441 while ((c = getopt(argc, argv, combinedopt)) != -1) { 1442 switch (c) { 1443 case 'd': 1444 datalen = strtoul(optarg, NULL, 0); 1445 break; 1446 case 'l': 1447 lba = strtoull(optarg, NULL, 0); 1448 lba_set = 1; 1449 break; 1450 default: 1451 break; 1452 } 1453 } 1454 1455 if (lba_set == 0) { 1456 warnx("%s: you must specify an LBA with -l", __func__); 1457 retval = 1; 1458 goto bailout; 1459 } 1460 1461 if (datalen == -1) { 1462 warnx("%s: you must specify a length with -d", __func__); 1463 retval = 1; 1464 goto bailout; 1465 } 1466 1467 bbr_info.lun_num = lun; 1468 bbr_info.lba = lba; 1469 /* 1470 * XXX KDM get the blocksize first?? 1471 */ 1472 if ((datalen % 512) != 0) { 1473 warnx("%s: data length %d is not a multiple of 512 bytes", 1474 __func__, datalen); 1475 retval = 1; 1476 goto bailout; 1477 } 1478 bbr_info.len = datalen; 1479 1480 if (ioctl(fd, CTL_BBRREAD, &bbr_info) == -1) { 1481 warn("%s: CTL_BBRREAD ioctl failed", __func__); 1482 retval = 1; 1483 goto bailout; 1484 } 1485 cctl_cfi_mt_statusstr(bbr_info.status, error_str, sizeof(error_str)); 1486 fprintf(stdout, "BBR Read Overall Status: %s\n", error_str); 1487 cctl_cfi_bbr_statusstr(bbr_info.bbr_status, error_str, 1488 sizeof(error_str)); 1489 fprintf(stdout, "BBR Read Status: %s\n", error_str); 1490 /* 1491 * XXX KDM should we bother printing out SCSI status if we get 1492 * CFI_BBR_SCSI_ERROR back? 1493 * 1494 * Return non-zero if this fails? 1495 */ 1496 bailout: 1497 return (retval); 1498 } 1499 1500 static int 1501 cctl_startup_shutdown(int fd, int target, int lun, int iid, 1502 ctladm_cmdfunction command) 1503 { 1504 union ctl_io *io; 1505 struct ctl_id id; 1506 struct scsi_report_luns_data *lun_data; 1507 struct scsi_inquiry_data *inq_data; 1508 uint32_t num_luns; 1509 unsigned int i; 1510 int retval; 1511 1512 retval = 0; 1513 inq_data = NULL; 1514 1515 /* 1516 * - report luns 1517 * - step through each lun, do an inquiry 1518 * - check OOA queue on direct access luns 1519 * - send stop with offline bit to each direct access device with a 1520 * clear OOA queue 1521 * - if we get a reservation conflict, reset the LUN to clear it 1522 * and reissue the stop with the offline bit set 1523 */ 1524 1525 id.id = iid; 1526 1527 io = ctl_scsi_alloc_io(id); 1528 if (io == NULL) { 1529 warnx("%s: can't allocate memory", __func__); 1530 return (1); 1531 } 1532 1533 if ((retval = cctl_get_luns(fd, target, lun, iid, /*retries*/ 2, 1534 &lun_data, &num_luns)) != 0) 1535 goto bailout; 1536 1537 inq_data = malloc(sizeof(*inq_data)); 1538 if (inq_data == NULL) { 1539 warn("%s: couldn't allocate memory for inquiry data\n", 1540 __func__); 1541 retval = 1; 1542 goto bailout; 1543 } 1544 for (i = 0; i < num_luns; i++) { 1545 char scsi_path[40]; 1546 int lun_val; 1547 1548 /* 1549 * XXX KDM figure out a way to share this code with 1550 * cctl_lunlist()? 1551 */ 1552 switch (lun_data->luns[i].lundata[0] & RPL_LUNDATA_ATYP_MASK) { 1553 case RPL_LUNDATA_ATYP_PERIPH: 1554 lun_val = lun_data->luns[i].lundata[1]; 1555 break; 1556 case RPL_LUNDATA_ATYP_FLAT: 1557 lun_val = (lun_data->luns[i].lundata[0] & 1558 RPL_LUNDATA_FLAT_LUN_MASK) | 1559 (lun_data->luns[i].lundata[1] << 1560 RPL_LUNDATA_FLAT_LUN_BITS); 1561 break; 1562 case RPL_LUNDATA_ATYP_LUN: 1563 case RPL_LUNDATA_ATYP_EXTLUN: 1564 default: 1565 fprintf(stdout, "Unsupported LUN format %d\n", 1566 lun_data->luns[i].lundata[0] & 1567 RPL_LUNDATA_ATYP_MASK); 1568 lun_val = -1; 1569 break; 1570 } 1571 if (lun_val == -1) 1572 continue; 1573 1574 if ((retval = cctl_get_inquiry(fd, target, lun_val, iid, 1575 /*retries*/ 2, scsi_path, 1576 sizeof(scsi_path), 1577 inq_data)) != 0) { 1578 goto bailout; 1579 } 1580 printf("%s", scsi_path); 1581 scsi_print_inquiry(inq_data); 1582 /* 1583 * We only want to shutdown direct access devices. 1584 */ 1585 if (SID_TYPE(inq_data) != T_DIRECT) { 1586 printf("%s LUN is not direct access, skipped\n", 1587 scsi_path); 1588 continue; 1589 } 1590 1591 if (command == CTLADM_CMD_SHUTDOWN) { 1592 struct ctl_ooa_info ooa_info; 1593 1594 ooa_info.target_id = target; 1595 ooa_info.lun_id = lun_val; 1596 1597 if (ioctl(fd, CTL_CHECK_OOA, &ooa_info) == -1) { 1598 printf("%s CTL_CHECK_OOA ioctl failed\n", 1599 scsi_path); 1600 continue; 1601 } 1602 1603 if (ooa_info.status != CTL_OOA_SUCCESS) { 1604 printf("%s CTL_CHECK_OOA returned status %d\n", 1605 scsi_path, ooa_info.status); 1606 continue; 1607 } 1608 if (ooa_info.num_entries != 0) { 1609 printf("%s %d entr%s in the OOA queue, " 1610 "skipping shutdown\n", scsi_path, 1611 ooa_info.num_entries, 1612 (ooa_info.num_entries > 1)?"ies" : "y" ); 1613 continue; 1614 } 1615 } 1616 1617 ctl_scsi_start_stop(/*io*/ io, 1618 /*start*/(command == CTLADM_CMD_STARTUP) ? 1619 1 : 0, 1620 /*load_eject*/ 0, 1621 /*immediate*/ 0, 1622 /*power_conditions*/ SSS_PC_START_VALID, 1623 /*onoffline*/ 1, 1624 /*ctl_tag_type*/ 1625 (command == CTLADM_CMD_STARTUP) ? 1626 CTL_TAG_SIMPLE :CTL_TAG_ORDERED, 1627 /*control*/ 0); 1628 1629 io->io_hdr.nexus.targ_target.id = target; 1630 io->io_hdr.nexus.targ_lun = lun_val; 1631 io->io_hdr.nexus.initid = id; 1632 1633 if (cctl_do_io(fd, /*retries*/ 3, io, __func__) != 0) { 1634 retval = 1; 1635 goto bailout; 1636 } 1637 1638 if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS) 1639 ctl_io_error_print(io, inq_data, stderr); 1640 else { 1641 printf("%s LUN is now %s\n", scsi_path, 1642 (command == CTLADM_CMD_STARTUP) ? "online" : 1643 "offline"); 1644 } 1645 } 1646 bailout: 1647 if (lun_data != NULL) 1648 free(lun_data); 1649 1650 if (inq_data != NULL) 1651 free(inq_data); 1652 1653 if (io != NULL) 1654 ctl_scsi_free_io(io); 1655 1656 return (retval); 1657 } 1658 1659 static int 1660 cctl_sync_cache(int fd, int target, int lun, int iid, int retries, 1661 int argc, char **argv, char *combinedopt) 1662 { 1663 union ctl_io *io; 1664 struct ctl_id id; 1665 int cdb_size = -1; 1666 int retval; 1667 uint64_t our_lba = 0; 1668 uint32_t our_block_count = 0; 1669 int reladr = 0, immed = 0; 1670 int c; 1671 1672 id.id = iid; 1673 retval = 0; 1674 1675 io = ctl_scsi_alloc_io(id); 1676 if (io == NULL) { 1677 warnx("%s: can't allocate memory", __func__); 1678 return (1); 1679 } 1680 1681 while ((c = getopt(argc, argv, combinedopt)) != -1) { 1682 switch (c) { 1683 case 'b': 1684 our_block_count = strtoul(optarg, NULL, 0); 1685 break; 1686 case 'c': 1687 cdb_size = strtol(optarg, NULL, 0); 1688 break; 1689 case 'i': 1690 immed = 1; 1691 break; 1692 case 'l': 1693 our_lba = strtoull(optarg, NULL, 0); 1694 break; 1695 case 'r': 1696 reladr = 1; 1697 break; 1698 default: 1699 break; 1700 } 1701 } 1702 1703 if (cdb_size != -1) { 1704 switch (cdb_size) { 1705 case 10: 1706 case 16: 1707 break; 1708 default: 1709 warnx("%s: invalid cdbsize %d, valid sizes are 10 " 1710 "and 16", __func__, cdb_size); 1711 retval = 1; 1712 goto bailout; 1713 break; /* NOTREACHED */ 1714 } 1715 } else 1716 cdb_size = 10; 1717 1718 ctl_scsi_sync_cache(/*io*/ io, 1719 /*immed*/ immed, 1720 /*reladr*/ reladr, 1721 /*minimum_cdb_size*/ cdb_size, 1722 /*starting_lba*/ our_lba, 1723 /*block_count*/ our_block_count, 1724 /*tag_type*/ CTL_TAG_SIMPLE, 1725 /*control*/ 0); 1726 1727 io->io_hdr.nexus.targ_target.id = target; 1728 io->io_hdr.nexus.targ_lun = lun; 1729 io->io_hdr.nexus.initid = id; 1730 1731 if (cctl_do_io(fd, retries, io, __func__) != 0) { 1732 retval = 1; 1733 goto bailout; 1734 } 1735 1736 if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) { 1737 fprintf(stdout, "Cache synchronized successfully\n"); 1738 } else 1739 ctl_io_error_print(io, NULL, stderr); 1740 bailout: 1741 ctl_scsi_free_io(io); 1742 1743 return (retval); 1744 } 1745 1746 static int 1747 cctl_start_stop(int fd, int target, int lun, int iid, int retries, int start, 1748 int argc, char **argv, char *combinedopt) 1749 { 1750 union ctl_io *io; 1751 struct ctl_id id; 1752 char scsi_path[40]; 1753 int immed = 0, onoffline = 0; 1754 int retval, c; 1755 1756 id.id = iid; 1757 retval = 0; 1758 1759 io = ctl_scsi_alloc_io(id); 1760 if (io == NULL) { 1761 warnx("%s: can't allocate memory", __func__); 1762 return (1); 1763 } 1764 1765 while ((c = getopt(argc, argv, combinedopt)) != -1) { 1766 switch (c) { 1767 case 'i': 1768 immed = 1; 1769 break; 1770 case 'o': 1771 onoffline = 1; 1772 break; 1773 default: 1774 break; 1775 } 1776 } 1777 /* 1778 * Use an ordered tag for the stop command, to guarantee that any 1779 * pending I/O will finish before the stop command executes. This 1780 * would normally be the case anyway, since CTL will basically 1781 * treat the start/stop command as an ordered command with respect 1782 * to any other command except an INQUIRY. (See ctl_ser_table.c.) 1783 */ 1784 ctl_scsi_start_stop(/*io*/ io, 1785 /*start*/ start, 1786 /*load_eject*/ 0, 1787 /*immediate*/ immed, 1788 /*power_conditions*/ SSS_PC_START_VALID, 1789 /*onoffline*/ onoffline, 1790 /*ctl_tag_type*/ start ? CTL_TAG_SIMPLE : 1791 CTL_TAG_ORDERED, 1792 /*control*/ 0); 1793 1794 io->io_hdr.nexus.targ_target.id = target; 1795 io->io_hdr.nexus.targ_lun = lun; 1796 io->io_hdr.nexus.initid = id; 1797 1798 if (cctl_do_io(fd, retries, io, __func__) != 0) { 1799 retval = 1; 1800 goto bailout; 1801 } 1802 1803 ctl_scsi_path_string(io, scsi_path, sizeof(scsi_path)); 1804 if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) { 1805 fprintf(stdout, "%s LUN %s successfully\n", scsi_path, 1806 (start) ? "started" : "stopped"); 1807 } else 1808 ctl_io_error_print(io, NULL, stderr); 1809 1810 bailout: 1811 ctl_scsi_free_io(io); 1812 1813 return (retval); 1814 } 1815 1816 static int 1817 cctl_mode_sense(int fd, int target, int lun, int iid, int retries, 1818 int argc, char **argv, char *combinedopt) 1819 { 1820 union ctl_io *io; 1821 struct ctl_id id; 1822 uint32_t datalen; 1823 uint8_t *dataptr; 1824 int pc = -1, cdbsize, retval, dbd = 0, subpage = -1; 1825 int list = 0; 1826 int page_code = -1; 1827 int c; 1828 1829 id.id = iid; 1830 cdbsize = 0; 1831 retval = 0; 1832 dataptr = NULL; 1833 1834 io = ctl_scsi_alloc_io(id); 1835 if (io == NULL) { 1836 warn("%s: can't allocate memory", __func__); 1837 return (1); 1838 } 1839 1840 while ((c = getopt(argc, argv, combinedopt)) != -1) { 1841 switch (c) { 1842 case 'P': 1843 pc = strtoul(optarg, NULL, 0); 1844 break; 1845 case 'S': 1846 subpage = strtoul(optarg, NULL, 0); 1847 break; 1848 case 'd': 1849 dbd = 1; 1850 break; 1851 case 'l': 1852 list = 1; 1853 break; 1854 case 'm': 1855 page_code = strtoul(optarg, NULL, 0); 1856 break; 1857 case 'c': 1858 cdbsize = strtol(optarg, NULL, 0); 1859 break; 1860 default: 1861 break; 1862 } 1863 } 1864 1865 if (((list == 0) && (page_code == -1)) 1866 || ((list != 0) && (page_code != -1))) { 1867 warnx("%s: you must specify either a page code (-m) or -l", 1868 __func__); 1869 retval = 1; 1870 goto bailout; 1871 } 1872 1873 if ((page_code != -1) 1874 && ((page_code > SMS_ALL_PAGES_PAGE) 1875 || (page_code < 0))) { 1876 warnx("%s: page code %d is out of range", __func__, 1877 page_code); 1878 retval = 1; 1879 goto bailout; 1880 } 1881 1882 if (list == 1) { 1883 page_code = SMS_ALL_PAGES_PAGE; 1884 if (pc != -1) { 1885 warnx("%s: arg -P makes no sense with -l", 1886 __func__); 1887 retval = 1; 1888 goto bailout; 1889 } 1890 if (subpage != -1) { 1891 warnx("%s: arg -S makes no sense with -l", __func__); 1892 retval = 1; 1893 goto bailout; 1894 } 1895 } 1896 1897 if (pc == -1) 1898 pc = SMS_PAGE_CTRL_CURRENT; 1899 else { 1900 if ((pc > 3) 1901 || (pc < 0)) { 1902 warnx("%s: page control value %d is out of range: 0-3", 1903 __func__, pc); 1904 retval = 1; 1905 goto bailout; 1906 } 1907 } 1908 1909 1910 if ((subpage != -1) 1911 && ((subpage > 255) 1912 || (subpage < 0))) { 1913 warnx("%s: subpage code %d is out of range: 0-255", __func__, 1914 subpage); 1915 retval = 1; 1916 goto bailout; 1917 } 1918 if (cdbsize != 0) { 1919 switch (cdbsize) { 1920 case 6: 1921 case 10: 1922 break; 1923 default: 1924 warnx("%s: invalid cdbsize %d, valid sizes are 6 " 1925 "and 10", __func__, cdbsize); 1926 retval = 1; 1927 goto bailout; 1928 break; 1929 } 1930 } else 1931 cdbsize = 6; 1932 1933 if (subpage == -1) 1934 subpage = 0; 1935 1936 if (cdbsize == 6) 1937 datalen = 255; 1938 else 1939 datalen = 65535; 1940 1941 dataptr = (uint8_t *)malloc(datalen); 1942 if (dataptr == NULL) { 1943 warn("%s: can't allocate %d bytes", __func__, datalen); 1944 retval = 1; 1945 goto bailout; 1946 } 1947 1948 memset(dataptr, 0, datalen); 1949 1950 ctl_scsi_mode_sense(io, 1951 /*data_ptr*/ dataptr, 1952 /*data_len*/ datalen, 1953 /*dbd*/ dbd, 1954 /*llbaa*/ 0, 1955 /*page_code*/ page_code, 1956 /*pc*/ pc << 6, 1957 /*subpage*/ subpage, 1958 /*minimum_cdb_size*/ cdbsize, 1959 /*tag_type*/ CTL_TAG_SIMPLE, 1960 /*control*/ 0); 1961 1962 io->io_hdr.nexus.targ_target.id = target; 1963 io->io_hdr.nexus.targ_lun = lun; 1964 io->io_hdr.nexus.initid = id; 1965 1966 if (cctl_do_io(fd, retries, io, __func__) != 0) { 1967 retval = 1; 1968 goto bailout; 1969 } 1970 1971 if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) { 1972 int pages_len, used_len; 1973 uint32_t returned_len; 1974 uint8_t *ndataptr; 1975 1976 if (io->scsiio.cdb[0] == MODE_SENSE_6) { 1977 struct scsi_mode_hdr_6 *hdr6; 1978 int bdlen; 1979 1980 hdr6 = (struct scsi_mode_hdr_6 *)dataptr; 1981 1982 returned_len = hdr6->datalen + 1; 1983 bdlen = hdr6->block_descr_len; 1984 1985 ndataptr = (uint8_t *)((uint8_t *)&hdr6[1] + bdlen); 1986 } else { 1987 struct scsi_mode_hdr_10 *hdr10; 1988 int bdlen; 1989 1990 hdr10 = (struct scsi_mode_hdr_10 *)dataptr; 1991 1992 returned_len = scsi_2btoul(hdr10->datalen) + 2; 1993 bdlen = scsi_2btoul(hdr10->block_descr_len); 1994 1995 ndataptr = (uint8_t *)((uint8_t *)&hdr10[1] + bdlen); 1996 } 1997 /* just in case they can give us more than we allocated for */ 1998 returned_len = min(returned_len, datalen); 1999 pages_len = returned_len - (ndataptr - dataptr); 2000 #if 0 2001 fprintf(stdout, "returned_len = %d, pages_len = %d\n", 2002 returned_len, pages_len); 2003 #endif 2004 if (list == 1) { 2005 fprintf(stdout, "Supported mode pages:\n"); 2006 for (used_len = 0; used_len < pages_len;) { 2007 struct scsi_mode_page_header *header; 2008 2009 header = (struct scsi_mode_page_header *) 2010 &ndataptr[used_len]; 2011 fprintf(stdout, "%d\n", header->page_code); 2012 used_len += header->page_length + 2; 2013 } 2014 } else { 2015 for (used_len = 0; used_len < pages_len; used_len++) { 2016 fprintf(stdout, "0x%x ", ndataptr[used_len]); 2017 if (((used_len+1) % 16) == 0) 2018 fprintf(stdout, "\n"); 2019 } 2020 fprintf(stdout, "\n"); 2021 } 2022 } else 2023 ctl_io_error_print(io, NULL, stderr); 2024 bailout: 2025 2026 ctl_scsi_free_io(io); 2027 2028 if (dataptr != NULL) 2029 free(dataptr); 2030 2031 return (retval); 2032 } 2033 2034 static int 2035 cctl_read_capacity(int fd, int target, int lun, int iid, int retries, 2036 int argc, char **argv, char *combinedopt) 2037 { 2038 union ctl_io *io; 2039 struct ctl_id id; 2040 struct scsi_read_capacity_data *data; 2041 struct scsi_read_capacity_data_long *longdata; 2042 int cdbsize = -1, retval; 2043 uint8_t *dataptr; 2044 int c; 2045 2046 cdbsize = 10; 2047 dataptr = NULL; 2048 retval = 0; 2049 id.id = iid; 2050 2051 io = ctl_scsi_alloc_io(id); 2052 if (io == NULL) { 2053 warn("%s: can't allocate memory\n", __func__); 2054 return (1); 2055 } 2056 2057 while ((c = getopt(argc, argv, combinedopt)) != -1) { 2058 switch (c) { 2059 case 'c': 2060 cdbsize = strtol(optarg, NULL, 0); 2061 break; 2062 default: 2063 break; 2064 } 2065 } 2066 if (cdbsize != -1) { 2067 switch (cdbsize) { 2068 case 10: 2069 case 16: 2070 break; 2071 default: 2072 warnx("%s: invalid cdbsize %d, valid sizes are 10 " 2073 "and 16", __func__, cdbsize); 2074 retval = 1; 2075 goto bailout; 2076 break; /* NOTREACHED */ 2077 } 2078 } else 2079 cdbsize = 10; 2080 2081 dataptr = (uint8_t *)malloc(sizeof(*longdata)); 2082 if (dataptr == NULL) { 2083 warn("%s: can't allocate %zd bytes\n", __func__, 2084 sizeof(*longdata)); 2085 retval = 1; 2086 goto bailout; 2087 } 2088 memset(dataptr, 0, sizeof(*longdata)); 2089 2090 retry: 2091 2092 switch (cdbsize) { 2093 case 10: 2094 ctl_scsi_read_capacity(io, 2095 /*data_ptr*/ dataptr, 2096 /*data_len*/ sizeof(*longdata), 2097 /*addr*/ 0, 2098 /*reladr*/ 0, 2099 /*pmi*/ 0, 2100 /*tag_type*/ CTL_TAG_SIMPLE, 2101 /*control*/ 0); 2102 break; 2103 case 16: 2104 ctl_scsi_read_capacity_16(io, 2105 /*data_ptr*/ dataptr, 2106 /*data_len*/ sizeof(*longdata), 2107 /*addr*/ 0, 2108 /*reladr*/ 0, 2109 /*pmi*/ 0, 2110 /*tag_type*/ CTL_TAG_SIMPLE, 2111 /*control*/ 0); 2112 break; 2113 } 2114 2115 io->io_hdr.nexus.initid = id; 2116 io->io_hdr.nexus.targ_target.id = target; 2117 io->io_hdr.nexus.targ_lun = lun; 2118 2119 if (cctl_do_io(fd, retries, io, __func__) != 0) { 2120 retval = 1; 2121 goto bailout; 2122 } 2123 2124 if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) { 2125 uint64_t maxlba; 2126 uint32_t blocksize; 2127 2128 if (cdbsize == 10) { 2129 2130 data = (struct scsi_read_capacity_data *)dataptr; 2131 2132 maxlba = scsi_4btoul(data->addr); 2133 blocksize = scsi_4btoul(data->length); 2134 2135 if (maxlba == 0xffffffff) { 2136 cdbsize = 16; 2137 goto retry; 2138 } 2139 } else { 2140 longdata=(struct scsi_read_capacity_data_long *)dataptr; 2141 2142 maxlba = scsi_8btou64(longdata->addr); 2143 blocksize = scsi_4btoul(longdata->length); 2144 } 2145 2146 fprintf(stdout, "Disk Capacity: %ju, Blocksize: %d\n", 2147 (uintmax_t)maxlba, blocksize); 2148 } else { 2149 ctl_io_error_print(io, NULL, stderr); 2150 } 2151 bailout: 2152 ctl_scsi_free_io(io); 2153 2154 if (dataptr != NULL) 2155 free(dataptr); 2156 2157 return (retval); 2158 } 2159 2160 static int 2161 cctl_read_write(int fd, int target, int lun, int iid, int retries, 2162 int argc, char **argv, char *combinedopt, 2163 ctladm_cmdfunction command) 2164 { 2165 union ctl_io *io; 2166 struct ctl_id id; 2167 int file_fd, do_stdio; 2168 int cdbsize = -1, databytes; 2169 uint8_t *dataptr; 2170 char *filename = NULL; 2171 int datalen = -1, blocksize = -1; 2172 uint64_t lba = 0; 2173 int lba_set = 0; 2174 int retval; 2175 int c; 2176 2177 retval = 0; 2178 do_stdio = 0; 2179 dataptr = NULL; 2180 file_fd = -1; 2181 id.id = iid; 2182 2183 io = ctl_scsi_alloc_io(id); 2184 if (io == NULL) { 2185 warn("%s: can't allocate memory\n", __func__); 2186 return (1); 2187 } 2188 2189 while ((c = getopt(argc, argv, combinedopt)) != -1) { 2190 switch (c) { 2191 case 'N': 2192 io->io_hdr.flags |= CTL_FLAG_NO_DATAMOVE; 2193 break; 2194 case 'b': 2195 blocksize = strtoul(optarg, NULL, 0); 2196 break; 2197 case 'c': 2198 cdbsize = strtoul(optarg, NULL, 0); 2199 break; 2200 case 'd': 2201 datalen = strtoul(optarg, NULL, 0); 2202 break; 2203 case 'f': 2204 filename = strdup(optarg); 2205 break; 2206 case 'l': 2207 lba = strtoull(optarg, NULL, 0); 2208 lba_set = 1; 2209 break; 2210 default: 2211 break; 2212 } 2213 } 2214 if (filename == NULL) { 2215 warnx("%s: you must supply a filename using -f", __func__); 2216 retval = 1; 2217 goto bailout; 2218 } 2219 2220 if (datalen == -1) { 2221 warnx("%s: you must specify the data length with -d", __func__); 2222 retval = 1; 2223 goto bailout; 2224 } 2225 2226 if (lba_set == 0) { 2227 warnx("%s: you must specify the LBA with -l", __func__); 2228 retval = 1; 2229 goto bailout; 2230 } 2231 2232 if (blocksize == -1) { 2233 warnx("%s: you must specify the blocksize with -b", __func__); 2234 retval = 1; 2235 goto bailout; 2236 } 2237 2238 if (cdbsize != -1) { 2239 switch (cdbsize) { 2240 case 6: 2241 case 10: 2242 case 12: 2243 case 16: 2244 break; 2245 default: 2246 warnx("%s: invalid cdbsize %d, valid sizes are 6, " 2247 "10, 12 or 16", __func__, cdbsize); 2248 retval = 1; 2249 goto bailout; 2250 break; /* NOTREACHED */ 2251 } 2252 } else 2253 cdbsize = 6; 2254 2255 databytes = datalen * blocksize; 2256 dataptr = (uint8_t *)malloc(databytes); 2257 2258 if (dataptr == NULL) { 2259 warn("%s: can't allocate %d bytes\n", __func__, databytes); 2260 retval = 1; 2261 goto bailout; 2262 } 2263 if (strcmp(filename, "-") == 0) { 2264 if (command == CTLADM_CMD_READ) 2265 file_fd = STDOUT_FILENO; 2266 else 2267 file_fd = STDIN_FILENO; 2268 do_stdio = 1; 2269 } else { 2270 file_fd = open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 2271 if (file_fd == -1) { 2272 warn("%s: can't open file %s", __func__, filename); 2273 retval = 1; 2274 goto bailout; 2275 } 2276 } 2277 2278 memset(dataptr, 0, databytes); 2279 2280 if (command == CTLADM_CMD_WRITE) { 2281 int bytes_read; 2282 2283 bytes_read = read(file_fd, dataptr, databytes); 2284 if (bytes_read == -1) { 2285 warn("%s: error reading file %s", __func__, filename); 2286 retval = 1; 2287 goto bailout; 2288 } 2289 if (bytes_read != databytes) { 2290 warnx("%s: only read %d bytes from file %s", 2291 __func__, bytes_read, filename); 2292 retval = 1; 2293 goto bailout; 2294 } 2295 } 2296 ctl_scsi_read_write(io, 2297 /*data_ptr*/ dataptr, 2298 /*data_len*/ databytes, 2299 /*read_op*/ (command == CTLADM_CMD_READ) ? 1 : 0, 2300 /*byte2*/ 0, 2301 /*minimum_cdb_size*/ cdbsize, 2302 /*lba*/ lba, 2303 /*num_blocks*/ datalen, 2304 /*tag_type*/ CTL_TAG_SIMPLE, 2305 /*control*/ 0); 2306 2307 io->io_hdr.nexus.targ_target.id = target; 2308 io->io_hdr.nexus.targ_lun = lun; 2309 io->io_hdr.nexus.initid = id; 2310 2311 if (cctl_do_io(fd, retries, io, __func__) != 0) { 2312 retval = 1; 2313 goto bailout; 2314 } 2315 2316 if (((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) 2317 && (command == CTLADM_CMD_READ)) { 2318 int bytes_written; 2319 2320 bytes_written = write(file_fd, dataptr, databytes); 2321 if (bytes_written == -1) { 2322 warn("%s: can't write to %s", __func__, filename); 2323 goto bailout; 2324 } 2325 } else if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS) 2326 ctl_io_error_print(io, NULL, stderr); 2327 2328 2329 bailout: 2330 2331 ctl_scsi_free_io(io); 2332 2333 if (dataptr != NULL) 2334 free(dataptr); 2335 2336 if ((do_stdio == 0) 2337 && (file_fd != -1)) 2338 close(file_fd); 2339 2340 return (retval); 2341 } 2342 2343 static int 2344 cctl_get_luns(int fd, int target, int lun, int iid, int retries, struct 2345 scsi_report_luns_data **lun_data, uint32_t *num_luns) 2346 { 2347 union ctl_io *io; 2348 struct ctl_id id; 2349 uint32_t nluns; 2350 int lun_datalen; 2351 int retval; 2352 2353 retval = 0; 2354 id.id = iid; 2355 2356 io = ctl_scsi_alloc_io(id); 2357 if (io == NULL) { 2358 warnx("%s: can't allocate memory", __func__); 2359 return (1); 2360 } 2361 2362 /* 2363 * lun_data includes space for 1 lun, allocate space for 4 initially. 2364 * If that isn't enough, we'll allocate more. 2365 */ 2366 nluns = 4; 2367 retry: 2368 lun_datalen = sizeof(*lun_data) + 2369 (nluns * sizeof(struct scsi_report_luns_lundata)); 2370 *lun_data = malloc(lun_datalen); 2371 2372 if (*lun_data == NULL) { 2373 warnx("%s: can't allocate memory", __func__); 2374 ctl_scsi_free_io(io); 2375 return (1); 2376 } 2377 2378 ctl_scsi_report_luns(io, 2379 /*data_ptr*/ (uint8_t *)*lun_data, 2380 /*data_len*/ lun_datalen, 2381 /*select_report*/ RPL_REPORT_ALL, 2382 /*tag_type*/ CTL_TAG_SIMPLE, 2383 /*control*/ 0); 2384 2385 io->io_hdr.nexus.initid = id; 2386 io->io_hdr.nexus.targ_target.id = target; 2387 io->io_hdr.nexus.targ_lun = lun; 2388 2389 if (cctl_do_io(fd, retries, io, __func__) != 0) { 2390 retval = 1; 2391 goto bailout; 2392 } 2393 2394 if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) { 2395 uint32_t returned_len, returned_luns; 2396 2397 returned_len = scsi_4btoul((*lun_data)->length); 2398 returned_luns = returned_len / 8; 2399 if (returned_luns > nluns) { 2400 nluns = returned_luns; 2401 free(*lun_data); 2402 goto retry; 2403 } 2404 /* These should be the same */ 2405 *num_luns = MIN(returned_luns, nluns); 2406 } else { 2407 ctl_io_error_print(io, NULL, stderr); 2408 retval = 1; 2409 } 2410 bailout: 2411 ctl_scsi_free_io(io); 2412 2413 return (retval); 2414 } 2415 2416 static int 2417 cctl_report_luns(int fd, int target, int lun, int iid, int retries) 2418 { 2419 struct scsi_report_luns_data *lun_data; 2420 uint32_t num_luns, i; 2421 int retval; 2422 2423 lun_data = NULL; 2424 2425 if ((retval = cctl_get_luns(fd, target, lun, iid, retries, &lun_data, 2426 &num_luns)) != 0) 2427 goto bailout; 2428 2429 fprintf(stdout, "%u LUNs returned\n", num_luns); 2430 for (i = 0; i < num_luns; i++) { 2431 int lun_val; 2432 2433 /* 2434 * XXX KDM figure out a way to share this code with 2435 * cctl_lunlist()? 2436 */ 2437 switch (lun_data->luns[i].lundata[0] & RPL_LUNDATA_ATYP_MASK) { 2438 case RPL_LUNDATA_ATYP_PERIPH: 2439 lun_val = lun_data->luns[i].lundata[1]; 2440 break; 2441 case RPL_LUNDATA_ATYP_FLAT: 2442 lun_val = (lun_data->luns[i].lundata[0] & 2443 RPL_LUNDATA_FLAT_LUN_MASK) | 2444 (lun_data->luns[i].lundata[1] << 2445 RPL_LUNDATA_FLAT_LUN_BITS); 2446 break; 2447 case RPL_LUNDATA_ATYP_LUN: 2448 case RPL_LUNDATA_ATYP_EXTLUN: 2449 default: 2450 fprintf(stdout, "Unsupported LUN format %d\n", 2451 lun_data->luns[i].lundata[0] & 2452 RPL_LUNDATA_ATYP_MASK); 2453 lun_val = -1; 2454 break; 2455 } 2456 if (lun_val == -1) 2457 continue; 2458 2459 fprintf(stdout, "%d\n", lun_val); 2460 } 2461 2462 bailout: 2463 if (lun_data != NULL) 2464 free(lun_data); 2465 2466 return (retval); 2467 } 2468 2469 static int 2470 cctl_tur(int fd, int target, int lun, int iid, int retries) 2471 { 2472 union ctl_io *io; 2473 struct ctl_id id; 2474 2475 id.id = iid; 2476 2477 io = ctl_scsi_alloc_io(id); 2478 if (io == NULL) { 2479 fprintf(stderr, "can't allocate memory\n"); 2480 return (1); 2481 } 2482 2483 ctl_scsi_tur(io, 2484 /* tag_type */ CTL_TAG_SIMPLE, 2485 /* control */ 0); 2486 2487 io->io_hdr.nexus.targ_target.id = target; 2488 io->io_hdr.nexus.targ_lun = lun; 2489 io->io_hdr.nexus.initid = id; 2490 2491 if (cctl_do_io(fd, retries, io, __func__) != 0) { 2492 ctl_scsi_free_io(io); 2493 return (1); 2494 } 2495 2496 if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) 2497 fprintf(stdout, "Unit is ready\n"); 2498 else 2499 ctl_io_error_print(io, NULL, stderr); 2500 2501 return (0); 2502 } 2503 2504 static int 2505 cctl_get_inquiry(int fd, int target, int lun, int iid, int retries, 2506 char *path_str, int path_len, 2507 struct scsi_inquiry_data *inq_data) 2508 { 2509 union ctl_io *io; 2510 struct ctl_id id; 2511 int retval; 2512 2513 retval = 0; 2514 2515 id.id = iid; 2516 2517 io = ctl_scsi_alloc_io(id); 2518 if (io == NULL) { 2519 warnx("cctl_inquiry: can't allocate memory\n"); 2520 return (1); 2521 } 2522 2523 ctl_scsi_inquiry(/*io*/ io, 2524 /*data_ptr*/ (uint8_t *)inq_data, 2525 /*data_len*/ sizeof(*inq_data), 2526 /*byte2*/ 0, 2527 /*page_code*/ 0, 2528 /*tag_type*/ CTL_TAG_SIMPLE, 2529 /*control*/ 0); 2530 2531 io->io_hdr.nexus.targ_target.id = target; 2532 io->io_hdr.nexus.targ_lun = lun; 2533 io->io_hdr.nexus.initid = id; 2534 2535 if (cctl_do_io(fd, retries, io, __func__) != 0) { 2536 retval = 1; 2537 goto bailout; 2538 } 2539 2540 if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS) { 2541 retval = 1; 2542 ctl_io_error_print(io, NULL, stderr); 2543 } else if (path_str != NULL) 2544 ctl_scsi_path_string(io, path_str, path_len); 2545 2546 bailout: 2547 ctl_scsi_free_io(io); 2548 2549 return (retval); 2550 } 2551 2552 static int 2553 cctl_inquiry(int fd, int target, int lun, int iid, int retries) 2554 { 2555 struct scsi_inquiry_data *inq_data; 2556 char scsi_path[40]; 2557 int retval; 2558 2559 retval = 0; 2560 2561 inq_data = malloc(sizeof(*inq_data)); 2562 if (inq_data == NULL) { 2563 warnx("%s: can't allocate inquiry data", __func__); 2564 retval = 1; 2565 goto bailout; 2566 } 2567 2568 if ((retval = cctl_get_inquiry(fd, target, lun, iid, retries, scsi_path, 2569 sizeof(scsi_path), inq_data)) != 0) 2570 goto bailout; 2571 2572 printf("%s", scsi_path); 2573 scsi_print_inquiry(inq_data); 2574 2575 bailout: 2576 if (inq_data != NULL) 2577 free(inq_data); 2578 2579 return (retval); 2580 } 2581 2582 static int 2583 cctl_req_sense(int fd, int target, int lun, int iid, int retries) 2584 { 2585 union ctl_io *io; 2586 struct scsi_sense_data *sense_data; 2587 struct ctl_id id; 2588 int retval; 2589 2590 retval = 0; 2591 2592 id.id = iid; 2593 2594 io = ctl_scsi_alloc_io(id); 2595 if (io == NULL) { 2596 warnx("cctl_req_sense: can't allocate memory\n"); 2597 return (1); 2598 } 2599 sense_data = malloc(sizeof(*sense_data)); 2600 memset(sense_data, 0, sizeof(*sense_data)); 2601 2602 ctl_scsi_request_sense(/*io*/ io, 2603 /*data_ptr*/ (uint8_t *)sense_data, 2604 /*data_len*/ sizeof(*sense_data), 2605 /*byte2*/ 0, 2606 /*tag_type*/ CTL_TAG_SIMPLE, 2607 /*control*/ 0); 2608 2609 io->io_hdr.nexus.targ_target.id = target; 2610 io->io_hdr.nexus.targ_lun = lun; 2611 io->io_hdr.nexus.initid = id; 2612 2613 if (cctl_do_io(fd, retries, io, __func__) != 0) { 2614 retval = 1; 2615 goto bailout; 2616 } 2617 2618 if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) { 2619 bcopy(sense_data, &io->scsiio.sense_data, sizeof(*sense_data)); 2620 io->scsiio.sense_len = sizeof(*sense_data); 2621 ctl_scsi_sense_print(&io->scsiio, NULL, stdout); 2622 } else 2623 ctl_io_error_print(io, NULL, stderr); 2624 2625 bailout: 2626 2627 ctl_scsi_free_io(io); 2628 free(sense_data); 2629 2630 return (retval); 2631 } 2632 2633 static int 2634 cctl_report_target_port_group(int fd, int target, int lun, int initiator) 2635 { 2636 union ctl_io *io; 2637 struct ctl_id id; 2638 uint32_t datalen; 2639 uint8_t *dataptr; 2640 int retval; 2641 2642 id.id = initiator; 2643 dataptr = NULL; 2644 retval = 0; 2645 2646 io = ctl_scsi_alloc_io(id); 2647 if (io == NULL) { 2648 warn("%s: can't allocate memory", __func__); 2649 return (1); 2650 } 2651 2652 datalen = 64; 2653 dataptr = (uint8_t *)malloc(datalen); 2654 if (dataptr == NULL) { 2655 warn("%s: can't allocate %d bytes", __func__, datalen); 2656 retval = 1; 2657 goto bailout; 2658 } 2659 2660 memset(dataptr, 0, datalen); 2661 2662 ctl_scsi_maintenance_in(/*io*/ io, 2663 /*data_ptr*/ dataptr, 2664 /*data_len*/ datalen, 2665 /*action*/ SA_RPRT_TRGT_GRP, 2666 /*tag_type*/ CTL_TAG_SIMPLE, 2667 /*control*/ 0); 2668 2669 io->io_hdr.nexus.targ_target.id = target; 2670 io->io_hdr.nexus.targ_lun = lun; 2671 io->io_hdr.nexus.initid = id; 2672 2673 if (cctl_do_io(fd, 0, io, __func__) != 0) { 2674 retval = 1; 2675 goto bailout; 2676 } 2677 2678 if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) { 2679 int returned_len, used_len; 2680 2681 returned_len = scsi_4btoul(&dataptr[0]) + 4; 2682 2683 for (used_len = 0; used_len < returned_len; used_len++) { 2684 fprintf(stdout, "0x%02x ", dataptr[used_len]); 2685 if (((used_len+1) % 8) == 0) 2686 fprintf(stdout, "\n"); 2687 } 2688 fprintf(stdout, "\n"); 2689 } else 2690 ctl_io_error_print(io, NULL, stderr); 2691 2692 bailout: 2693 ctl_scsi_free_io(io); 2694 2695 if (dataptr != NULL) 2696 free(dataptr); 2697 2698 return (retval); 2699 } 2700 2701 static int 2702 cctl_inquiry_vpd_devid(int fd, int target, int lun, int initiator) 2703 { 2704 union ctl_io *io; 2705 struct ctl_id id; 2706 uint32_t datalen; 2707 uint8_t *dataptr; 2708 int retval; 2709 2710 id.id = initiator; 2711 retval = 0; 2712 dataptr = NULL; 2713 2714 io = ctl_scsi_alloc_io(id); 2715 if (io == NULL) { 2716 warn("%s: can't allocate memory", __func__); 2717 return (1); 2718 } 2719 2720 datalen = 256; 2721 dataptr = (uint8_t *)malloc(datalen); 2722 if (dataptr == NULL) { 2723 warn("%s: can't allocate %d bytes", __func__, datalen); 2724 retval = 1; 2725 goto bailout; 2726 } 2727 2728 memset(dataptr, 0, datalen); 2729 2730 ctl_scsi_inquiry(/*io*/ io, 2731 /*data_ptr*/ dataptr, 2732 /*data_len*/ datalen, 2733 /*byte2*/ SI_EVPD, 2734 /*page_code*/ SVPD_DEVICE_ID, 2735 /*tag_type*/ CTL_TAG_SIMPLE, 2736 /*control*/ 0); 2737 2738 io->io_hdr.nexus.targ_target.id = target; 2739 io->io_hdr.nexus.targ_lun = lun; 2740 io->io_hdr.nexus.initid = id; 2741 2742 if (cctl_do_io(fd, 0, io, __func__) != 0) { 2743 retval = 1; 2744 goto bailout; 2745 } 2746 2747 if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) { 2748 int returned_len, used_len; 2749 2750 returned_len = scsi_2btoul(&dataptr[2]) + 4; 2751 2752 for (used_len = 0; used_len < returned_len; used_len++) { 2753 fprintf(stdout, "0x%02x ", dataptr[used_len]); 2754 if (((used_len+1) % 8) == 0) 2755 fprintf(stdout, "\n"); 2756 } 2757 fprintf(stdout, "\n"); 2758 } else 2759 ctl_io_error_print(io, NULL, stderr); 2760 2761 bailout: 2762 ctl_scsi_free_io(io); 2763 2764 if (dataptr != NULL) 2765 free(dataptr); 2766 2767 return (retval); 2768 } 2769 2770 static int 2771 cctl_persistent_reserve_in(int fd, int target, int lun, int initiator, 2772 int argc, char **argv, char *combinedopt, 2773 int retry_count) 2774 { 2775 union ctl_io *io; 2776 struct ctl_id id; 2777 uint32_t datalen; 2778 uint8_t *dataptr; 2779 int action = -1; 2780 int retval; 2781 int c; 2782 2783 id.id = initiator; 2784 retval = 0; 2785 dataptr = NULL; 2786 2787 io = ctl_scsi_alloc_io(id); 2788 if (io == NULL) { 2789 warn("%s: can't allocate memory", __func__); 2790 return (1); 2791 } 2792 2793 while ((c = getopt(argc, argv, combinedopt)) != -1) { 2794 switch (c) { 2795 case 'a': 2796 action = strtol(optarg, NULL, 0); 2797 break; 2798 default: 2799 break; 2800 } 2801 } 2802 2803 if (action < 0 || action > 2) { 2804 warn("action must be specified and in the range: 0-2"); 2805 retval = 1; 2806 goto bailout; 2807 } 2808 2809 2810 datalen = 256; 2811 dataptr = (uint8_t *)malloc(datalen); 2812 if (dataptr == NULL) { 2813 warn("%s: can't allocate %d bytes", __func__, datalen); 2814 retval = 1; 2815 goto bailout; 2816 } 2817 2818 memset(dataptr, 0, datalen); 2819 2820 ctl_scsi_persistent_res_in(io, 2821 /*data_ptr*/ dataptr, 2822 /*data_len*/ datalen, 2823 /*action*/ action, 2824 /*tag_type*/ CTL_TAG_SIMPLE, 2825 /*control*/ 0); 2826 2827 io->io_hdr.nexus.targ_target.id = target; 2828 io->io_hdr.nexus.targ_lun = lun; 2829 io->io_hdr.nexus.initid = id; 2830 2831 if (cctl_do_io(fd, retry_count, io, __func__) != 0) { 2832 retval = 1; 2833 goto bailout; 2834 } 2835 2836 if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) { 2837 int returned_len, used_len; 2838 2839 returned_len = 0; 2840 2841 switch (action) { 2842 case 0: 2843 returned_len = scsi_4btoul(&dataptr[4]) + 8; 2844 returned_len = min(returned_len, 256); 2845 break; 2846 case 1: 2847 returned_len = scsi_4btoul(&dataptr[4]) + 8; 2848 break; 2849 case 2: 2850 returned_len = 8; 2851 break; 2852 default: 2853 warnx("%s: invalid action %d", __func__, action); 2854 goto bailout; 2855 break; /* NOTREACHED */ 2856 } 2857 2858 for (used_len = 0; used_len < returned_len; used_len++) { 2859 fprintf(stdout, "0x%02x ", dataptr[used_len]); 2860 if (((used_len+1) % 8) == 0) 2861 fprintf(stdout, "\n"); 2862 } 2863 fprintf(stdout, "\n"); 2864 } else 2865 ctl_io_error_print(io, NULL, stderr); 2866 2867 bailout: 2868 ctl_scsi_free_io(io); 2869 2870 if (dataptr != NULL) 2871 free(dataptr); 2872 2873 return (retval); 2874 } 2875 2876 static int 2877 cctl_persistent_reserve_out(int fd, int target, int lun, int initiator, 2878 int argc, char **argv, char *combinedopt, 2879 int retry_count) 2880 { 2881 union ctl_io *io; 2882 struct ctl_id id; 2883 uint32_t datalen; 2884 uint64_t key = 0, sa_key = 0; 2885 int action = -1, restype = -1; 2886 uint8_t *dataptr; 2887 int retval; 2888 int c; 2889 2890 id.id = initiator; 2891 retval = 0; 2892 dataptr = NULL; 2893 2894 io = ctl_scsi_alloc_io(id); 2895 if (io == NULL) { 2896 warn("%s: can't allocate memory", __func__); 2897 return (1); 2898 } 2899 2900 while ((c = getopt(argc, argv, combinedopt)) != -1) { 2901 switch (c) { 2902 case 'a': 2903 action = strtol(optarg, NULL, 0); 2904 break; 2905 case 'k': 2906 key = strtoull(optarg, NULL, 0); 2907 break; 2908 case 'r': 2909 restype = strtol(optarg, NULL, 0); 2910 break; 2911 case 's': 2912 sa_key = strtoull(optarg, NULL, 0); 2913 break; 2914 default: 2915 break; 2916 } 2917 } 2918 if (action < 0 || action > 5) { 2919 warn("action must be specified and in the range: 0-5"); 2920 retval = 1; 2921 goto bailout; 2922 } 2923 2924 if (restype < 0 || restype > 5) { 2925 if (action != 0 && action != 5 && action != 3) { 2926 warn("'restype' must specified and in the range: 0-5"); 2927 retval = 1; 2928 goto bailout; 2929 } 2930 } 2931 2932 datalen = 24; 2933 dataptr = (uint8_t *)malloc(datalen); 2934 if (dataptr == NULL) { 2935 warn("%s: can't allocate %d bytes", __func__, datalen); 2936 retval = 1; 2937 goto bailout; 2938 } 2939 2940 memset(dataptr, 0, datalen); 2941 2942 ctl_scsi_persistent_res_out(io, 2943 /*data_ptr*/ dataptr, 2944 /*data_len*/ datalen, 2945 /*action*/ action, 2946 /*type*/ restype, 2947 /*key*/ key, 2948 /*sa key*/ sa_key, 2949 /*tag_type*/ CTL_TAG_SIMPLE, 2950 /*control*/ 0); 2951 2952 io->io_hdr.nexus.targ_target.id = target; 2953 io->io_hdr.nexus.targ_lun = lun; 2954 io->io_hdr.nexus.initid = id; 2955 2956 if (cctl_do_io(fd, retry_count, io, __func__) != 0) { 2957 retval = 1; 2958 goto bailout; 2959 } 2960 if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) { 2961 char scsi_path[40]; 2962 ctl_scsi_path_string(io, scsi_path, sizeof(scsi_path)); 2963 fprintf( stdout, "%sPERSISTENT RESERVE OUT executed " 2964 "successfully\n", scsi_path); 2965 } else 2966 ctl_io_error_print(io, NULL, stderr); 2967 2968 bailout: 2969 ctl_scsi_free_io(io); 2970 2971 if (dataptr != NULL) 2972 free(dataptr); 2973 2974 return (retval); 2975 } 2976 2977 struct cctl_req_option { 2978 char *name; 2979 int namelen; 2980 char *value; 2981 int vallen; 2982 STAILQ_ENTRY(cctl_req_option) links; 2983 }; 2984 2985 static int 2986 cctl_create_lun(int fd, int argc, char **argv, char *combinedopt) 2987 { 2988 struct ctl_lun_req req; 2989 int device_type = -1; 2990 uint64_t lun_size = 0; 2991 uint32_t blocksize = 0, req_lun_id = 0; 2992 char *serial_num = NULL; 2993 char *device_id = NULL; 2994 int lun_size_set = 0, blocksize_set = 0, lun_id_set = 0; 2995 char *backend_name = NULL; 2996 STAILQ_HEAD(, cctl_req_option) option_list; 2997 int num_options = 0; 2998 int retval = 0, c; 2999 3000 STAILQ_INIT(&option_list); 3001 3002 while ((c = getopt(argc, argv, combinedopt)) != -1) { 3003 switch (c) { 3004 case 'b': 3005 backend_name = strdup(optarg); 3006 break; 3007 case 'B': 3008 blocksize = strtoul(optarg, NULL, 0); 3009 blocksize_set = 1; 3010 break; 3011 case 'd': 3012 device_id = strdup(optarg); 3013 break; 3014 case 'l': 3015 req_lun_id = strtoul(optarg, NULL, 0); 3016 lun_id_set = 1; 3017 break; 3018 case 'o': { 3019 struct cctl_req_option *option; 3020 char *tmpstr; 3021 char *name, *value; 3022 3023 tmpstr = strdup(optarg); 3024 name = strsep(&tmpstr, "="); 3025 if (name == NULL) { 3026 warnx("%s: option -o takes \"name=value\"" 3027 "argument", __func__); 3028 retval = 1; 3029 goto bailout; 3030 } 3031 value = strsep(&tmpstr, "="); 3032 if (value == NULL) { 3033 warnx("%s: option -o takes \"name=value\"" 3034 "argument", __func__); 3035 retval = 1; 3036 goto bailout; 3037 } 3038 option = malloc(sizeof(*option)); 3039 if (option == NULL) { 3040 warn("%s: error allocating %zd bytes", 3041 __func__, sizeof(*option)); 3042 retval = 1; 3043 goto bailout; 3044 } 3045 option->name = strdup(name); 3046 option->namelen = strlen(name) + 1; 3047 option->value = strdup(value); 3048 option->vallen = strlen(value) + 1; 3049 free(tmpstr); 3050 3051 STAILQ_INSERT_TAIL(&option_list, option, links); 3052 num_options++; 3053 break; 3054 } 3055 case 's': 3056 if (strcasecmp(optarg, "auto") != 0) { 3057 retval = expand_number(optarg, &lun_size); 3058 if (retval != 0) { 3059 warn("%s: invalid -s argument", 3060 __func__); 3061 retval = 1; 3062 goto bailout; 3063 } 3064 } 3065 lun_size_set = 1; 3066 break; 3067 case 'S': 3068 serial_num = strdup(optarg); 3069 break; 3070 case 't': 3071 device_type = strtoul(optarg, NULL, 0); 3072 break; 3073 default: 3074 break; 3075 } 3076 } 3077 3078 if (backend_name == NULL) { 3079 warnx("%s: backend name (-b) must be specified", __func__); 3080 retval = 1; 3081 goto bailout; 3082 } 3083 3084 bzero(&req, sizeof(req)); 3085 3086 strlcpy(req.backend, backend_name, sizeof(req.backend)); 3087 req.reqtype = CTL_LUNREQ_CREATE; 3088 3089 if (blocksize_set != 0) 3090 req.reqdata.create.blocksize_bytes = blocksize; 3091 3092 if (lun_size_set != 0) 3093 req.reqdata.create.lun_size_bytes = lun_size; 3094 3095 if (lun_id_set != 0) { 3096 req.reqdata.create.flags |= CTL_LUN_FLAG_ID_REQ; 3097 req.reqdata.create.req_lun_id = req_lun_id; 3098 } 3099 3100 req.reqdata.create.flags |= CTL_LUN_FLAG_DEV_TYPE; 3101 3102 if (device_type != -1) 3103 req.reqdata.create.device_type = device_type; 3104 else 3105 req.reqdata.create.device_type = T_DIRECT; 3106 3107 if (serial_num != NULL) { 3108 strlcpy(req.reqdata.create.serial_num, serial_num, 3109 sizeof(req.reqdata.create.serial_num)); 3110 req.reqdata.create.flags |= CTL_LUN_FLAG_SERIAL_NUM; 3111 } 3112 3113 if (device_id != NULL) { 3114 strlcpy(req.reqdata.create.device_id, device_id, 3115 sizeof(req.reqdata.create.device_id)); 3116 req.reqdata.create.flags |= CTL_LUN_FLAG_DEVID; 3117 } 3118 3119 req.num_be_args = num_options; 3120 if (num_options > 0) { 3121 struct cctl_req_option *option, *next_option; 3122 int i; 3123 3124 req.be_args = malloc(num_options * sizeof(*req.be_args)); 3125 if (req.be_args == NULL) { 3126 warn("%s: error allocating %zd bytes", __func__, 3127 num_options * sizeof(*req.be_args)); 3128 retval = 1; 3129 goto bailout; 3130 } 3131 3132 for (i = 0, option = STAILQ_FIRST(&option_list); 3133 i < num_options; i++, option = next_option) { 3134 next_option = STAILQ_NEXT(option, links); 3135 3136 req.be_args[i].namelen = option->namelen; 3137 req.be_args[i].name = strdup(option->name); 3138 req.be_args[i].vallen = option->vallen; 3139 req.be_args[i].value = strdup(option->value); 3140 /* 3141 * XXX KDM do we want a way to specify a writeable 3142 * flag of some sort? Do we want a way to specify 3143 * binary data? 3144 */ 3145 req.be_args[i].flags = CTL_BEARG_ASCII | CTL_BEARG_RD; 3146 3147 STAILQ_REMOVE(&option_list, option, cctl_req_option, 3148 links); 3149 free(option->name); 3150 free(option->value); 3151 free(option); 3152 } 3153 } 3154 3155 if (ioctl(fd, CTL_LUN_REQ, &req) == -1) { 3156 warn("%s: error issuing CTL_LUN_REQ ioctl", __func__); 3157 retval = 1; 3158 goto bailout; 3159 } 3160 3161 if (req.status == CTL_LUN_ERROR) { 3162 warnx("%s: error returned from LUN creation request:\n%s", 3163 __func__, req.error_str); 3164 retval = 1; 3165 goto bailout; 3166 } else if (req.status != CTL_LUN_OK) { 3167 warnx("%s: unknown LUN creation request status %d", 3168 __func__, req.status); 3169 retval = 1; 3170 goto bailout; 3171 } 3172 3173 fprintf(stdout, "LUN created successfully\n"); 3174 fprintf(stdout, "backend: %s\n", req.backend); 3175 fprintf(stdout, "device type: %d\n",req.reqdata.create.device_type); 3176 fprintf(stdout, "LUN size: %ju bytes\n", 3177 (uintmax_t)req.reqdata.create.lun_size_bytes); 3178 fprintf(stdout, "blocksize %u bytes\n", 3179 req.reqdata.create.blocksize_bytes); 3180 fprintf(stdout, "LUN ID: %d\n", req.reqdata.create.req_lun_id); 3181 fprintf(stdout, "Serial Number: %s\n", req.reqdata.create.serial_num); 3182 fprintf(stdout, "Device ID; %s\n", req.reqdata.create.device_id); 3183 3184 bailout: 3185 return (retval); 3186 } 3187 3188 static int 3189 cctl_rm_lun(int fd, int argc, char **argv, char *combinedopt) 3190 { 3191 struct ctl_lun_req req; 3192 uint32_t lun_id = 0; 3193 int lun_id_set = 0; 3194 char *backend_name = NULL; 3195 STAILQ_HEAD(, cctl_req_option) option_list; 3196 int num_options = 0; 3197 int retval = 0, c; 3198 3199 STAILQ_INIT(&option_list); 3200 3201 while ((c = getopt(argc, argv, combinedopt)) != -1) { 3202 switch (c) { 3203 case 'b': 3204 backend_name = strdup(optarg); 3205 break; 3206 case 'l': 3207 lun_id = strtoul(optarg, NULL, 0); 3208 lun_id_set = 1; 3209 break; 3210 case 'o': { 3211 struct cctl_req_option *option; 3212 char *tmpstr; 3213 char *name, *value; 3214 3215 tmpstr = strdup(optarg); 3216 name = strsep(&tmpstr, "="); 3217 if (name == NULL) { 3218 warnx("%s: option -o takes \"name=value\"" 3219 "argument", __func__); 3220 retval = 1; 3221 goto bailout; 3222 } 3223 value = strsep(&tmpstr, "="); 3224 if (value == NULL) { 3225 warnx("%s: option -o takes \"name=value\"" 3226 "argument", __func__); 3227 retval = 1; 3228 goto bailout; 3229 } 3230 option = malloc(sizeof(*option)); 3231 if (option == NULL) { 3232 warn("%s: error allocating %zd bytes", 3233 __func__, sizeof(*option)); 3234 retval = 1; 3235 goto bailout; 3236 } 3237 option->name = strdup(name); 3238 option->namelen = strlen(name) + 1; 3239 option->value = strdup(value); 3240 option->vallen = strlen(value) + 1; 3241 free(tmpstr); 3242 3243 STAILQ_INSERT_TAIL(&option_list, option, links); 3244 num_options++; 3245 break; 3246 } 3247 default: 3248 break; 3249 } 3250 } 3251 3252 if (backend_name == NULL) 3253 errx(1, "%s: backend name (-b) must be specified", __func__); 3254 3255 if (lun_id_set == 0) 3256 errx(1, "%s: LUN id (-l) must be specified", __func__); 3257 3258 bzero(&req, sizeof(req)); 3259 3260 strlcpy(req.backend, backend_name, sizeof(req.backend)); 3261 req.reqtype = CTL_LUNREQ_RM; 3262 3263 req.reqdata.rm.lun_id = lun_id; 3264 3265 req.num_be_args = num_options; 3266 if (num_options > 0) { 3267 struct cctl_req_option *option, *next_option; 3268 int i; 3269 3270 req.be_args = malloc(num_options * sizeof(*req.be_args)); 3271 if (req.be_args == NULL) { 3272 warn("%s: error allocating %zd bytes", __func__, 3273 num_options * sizeof(*req.be_args)); 3274 retval = 1; 3275 goto bailout; 3276 } 3277 3278 for (i = 0, option = STAILQ_FIRST(&option_list); 3279 i < num_options; i++, option = next_option) { 3280 next_option = STAILQ_NEXT(option, links); 3281 3282 req.be_args[i].namelen = option->namelen; 3283 req.be_args[i].name = strdup(option->name); 3284 req.be_args[i].vallen = option->vallen; 3285 req.be_args[i].value = strdup(option->value); 3286 /* 3287 * XXX KDM do we want a way to specify a writeable 3288 * flag of some sort? Do we want a way to specify 3289 * binary data? 3290 */ 3291 req.be_args[i].flags = CTL_BEARG_ASCII | CTL_BEARG_RD; 3292 3293 STAILQ_REMOVE(&option_list, option, cctl_req_option, 3294 links); 3295 free(option->name); 3296 free(option->value); 3297 free(option); 3298 } 3299 } 3300 3301 if (ioctl(fd, CTL_LUN_REQ, &req) == -1) { 3302 warn("%s: error issuing CTL_LUN_REQ ioctl", __func__); 3303 retval = 1; 3304 goto bailout; 3305 } 3306 3307 if (req.status == CTL_LUN_ERROR) { 3308 warnx("%s: error returned from LUN removal request:\n%s", 3309 __func__, req.error_str); 3310 retval = 1; 3311 goto bailout; 3312 } else if (req.status != CTL_LUN_OK) { 3313 warnx("%s: unknown LUN removal request status %d", 3314 __func__, req.status); 3315 retval = 1; 3316 goto bailout; 3317 } 3318 3319 printf("LUN %d deleted successfully\n", lun_id); 3320 3321 bailout: 3322 return (retval); 3323 } 3324 3325 static int 3326 cctl_modify_lun(int fd, int argc, char **argv, char *combinedopt) 3327 { 3328 struct ctl_lun_req req; 3329 uint64_t lun_size = 0; 3330 uint32_t lun_id = 0; 3331 int lun_id_set = 0, lun_size_set = 0; 3332 char *backend_name = NULL; 3333 int retval = 0, c; 3334 3335 while ((c = getopt(argc, argv, combinedopt)) != -1) { 3336 switch (c) { 3337 case 'b': 3338 backend_name = strdup(optarg); 3339 break; 3340 case 'l': 3341 lun_id = strtoul(optarg, NULL, 0); 3342 lun_id_set = 1; 3343 break; 3344 case 's': 3345 if (strcasecmp(optarg, "auto") != 0) { 3346 retval = expand_number(optarg, &lun_size); 3347 if (retval != 0) { 3348 warn("%s: invalid -s argument", 3349 __func__); 3350 retval = 1; 3351 goto bailout; 3352 } 3353 } 3354 lun_size_set = 1; 3355 break; 3356 default: 3357 break; 3358 } 3359 } 3360 3361 if (backend_name == NULL) 3362 errx(1, "%s: backend name (-b) must be specified", __func__); 3363 3364 if (lun_id_set == 0) 3365 errx(1, "%s: LUN id (-l) must be specified", __func__); 3366 3367 if (lun_size_set == 0) 3368 errx(1, "%s: size (-s) must be specified", __func__); 3369 3370 bzero(&req, sizeof(req)); 3371 3372 strlcpy(req.backend, backend_name, sizeof(req.backend)); 3373 req.reqtype = CTL_LUNREQ_MODIFY; 3374 3375 req.reqdata.modify.lun_id = lun_id; 3376 req.reqdata.modify.lun_size_bytes = lun_size; 3377 3378 if (ioctl(fd, CTL_LUN_REQ, &req) == -1) { 3379 warn("%s: error issuing CTL_LUN_REQ ioctl", __func__); 3380 retval = 1; 3381 goto bailout; 3382 } 3383 3384 if (req.status == CTL_LUN_ERROR) { 3385 warnx("%s: error returned from LUN modification request:\n%s", 3386 __func__, req.error_str); 3387 retval = 1; 3388 goto bailout; 3389 } else if (req.status != CTL_LUN_OK) { 3390 warnx("%s: unknown LUN modification request status %d", 3391 __func__, req.status); 3392 retval = 1; 3393 goto bailout; 3394 } 3395 3396 printf("LUN %d modified successfully\n", lun_id); 3397 3398 bailout: 3399 return (retval); 3400 } 3401 3402 3403 /* 3404 * Name/value pair used for per-LUN attributes. 3405 */ 3406 struct cctl_lun_nv { 3407 char *name; 3408 char *value; 3409 STAILQ_ENTRY(cctl_lun_nv) links; 3410 }; 3411 3412 /* 3413 * Backend LUN information. 3414 */ 3415 struct cctl_lun { 3416 uint64_t lun_id; 3417 char *backend_type; 3418 uint64_t size_blocks; 3419 uint32_t blocksize; 3420 char *serial_number; 3421 char *device_id; 3422 STAILQ_HEAD(,cctl_lun_nv) attr_list; 3423 STAILQ_ENTRY(cctl_lun) links; 3424 }; 3425 3426 struct cctl_devlist_data { 3427 int num_luns; 3428 STAILQ_HEAD(,cctl_lun) lun_list; 3429 struct cctl_lun *cur_lun; 3430 int level; 3431 struct sbuf *cur_sb[32]; 3432 }; 3433 3434 static void 3435 cctl_start_element(void *user_data, const char *name, const char **attr) 3436 { 3437 int i; 3438 struct cctl_devlist_data *devlist; 3439 struct cctl_lun *cur_lun; 3440 3441 devlist = (struct cctl_devlist_data *)user_data; 3442 cur_lun = devlist->cur_lun; 3443 devlist->level++; 3444 if ((u_int)devlist->level > (sizeof(devlist->cur_sb) / 3445 sizeof(devlist->cur_sb[0]))) 3446 errx(1, "%s: too many nesting levels, %zd max", __func__, 3447 sizeof(devlist->cur_sb) / sizeof(devlist->cur_sb[0])); 3448 3449 devlist->cur_sb[devlist->level] = sbuf_new_auto(); 3450 if (devlist->cur_sb[devlist->level] == NULL) 3451 err(1, "%s: Unable to allocate sbuf", __func__); 3452 3453 if (strcmp(name, "lun") == 0) { 3454 if (cur_lun != NULL) 3455 errx(1, "%s: improper lun element nesting", __func__); 3456 3457 cur_lun = calloc(1, sizeof(*cur_lun)); 3458 if (cur_lun == NULL) 3459 err(1, "%s: cannot allocate %zd bytes", __func__, 3460 sizeof(*cur_lun)); 3461 3462 devlist->num_luns++; 3463 devlist->cur_lun = cur_lun; 3464 3465 STAILQ_INIT(&cur_lun->attr_list); 3466 STAILQ_INSERT_TAIL(&devlist->lun_list, cur_lun, links); 3467 3468 for (i = 0; attr[i] != NULL; i += 2) { 3469 if (strcmp(attr[i], "id") == 0) { 3470 cur_lun->lun_id = strtoull(attr[i+1], NULL, 0); 3471 } else { 3472 errx(1, "%s: invalid LUN attribute %s = %s", 3473 __func__, attr[i], attr[i+1]); 3474 } 3475 } 3476 } 3477 } 3478 3479 static void 3480 cctl_end_element(void *user_data, const char *name) 3481 { 3482 struct cctl_devlist_data *devlist; 3483 struct cctl_lun *cur_lun; 3484 char *str; 3485 3486 devlist = (struct cctl_devlist_data *)user_data; 3487 cur_lun = devlist->cur_lun; 3488 3489 if ((cur_lun == NULL) 3490 && (strcmp(name, "ctllunlist") != 0)) 3491 errx(1, "%s: cur_lun == NULL! (name = %s)", __func__, name); 3492 3493 if (devlist->cur_sb[devlist->level] == NULL) 3494 errx(1, "%s: no valid sbuf at level %d (name %s)", __func__, 3495 devlist->level, name); 3496 3497 if (sbuf_finish(devlist->cur_sb[devlist->level]) != 0) 3498 err(1, "%s: sbuf_finish", __func__); 3499 str = strdup(sbuf_data(devlist->cur_sb[devlist->level])); 3500 if (str == NULL) 3501 err(1, "%s can't allocate %zd bytes for string", __func__, 3502 sbuf_len(devlist->cur_sb[devlist->level])); 3503 3504 if (strlen(str) == 0) { 3505 free(str); 3506 str = NULL; 3507 } 3508 3509 sbuf_delete(devlist->cur_sb[devlist->level]); 3510 devlist->cur_sb[devlist->level] = NULL; 3511 devlist->level--; 3512 3513 if (strcmp(name, "backend_type") == 0) { 3514 cur_lun->backend_type = str; 3515 str = NULL; 3516 } else if (strcmp(name, "size") == 0) { 3517 cur_lun->size_blocks = strtoull(str, NULL, 0); 3518 } else if (strcmp(name, "blocksize") == 0) { 3519 cur_lun->blocksize = strtoul(str, NULL, 0); 3520 } else if (strcmp(name, "serial_number") == 0) { 3521 cur_lun->serial_number = str; 3522 str = NULL; 3523 } else if (strcmp(name, "device_id") == 0) { 3524 cur_lun->device_id = str; 3525 str = NULL; 3526 } else if (strcmp(name, "lun") == 0) { 3527 devlist->cur_lun = NULL; 3528 } else if (strcmp(name, "ctllunlist") == 0) { 3529 3530 } else { 3531 struct cctl_lun_nv *nv; 3532 3533 nv = calloc(1, sizeof(*nv)); 3534 if (nv == NULL) 3535 err(1, "%s: can't allocate %zd bytes for nv pair", 3536 __func__, sizeof(*nv)); 3537 3538 nv->name = strdup(name); 3539 if (nv->name == NULL) 3540 err(1, "%s: can't allocated %zd bytes for string", 3541 __func__, strlen(name)); 3542 3543 nv->value = str; 3544 str = NULL; 3545 STAILQ_INSERT_TAIL(&cur_lun->attr_list, nv, links); 3546 } 3547 3548 free(str); 3549 } 3550 3551 static void 3552 cctl_char_handler(void *user_data, const XML_Char *str, int len) 3553 { 3554 struct cctl_devlist_data *devlist; 3555 3556 devlist = (struct cctl_devlist_data *)user_data; 3557 3558 sbuf_bcat(devlist->cur_sb[devlist->level], str, len); 3559 } 3560 3561 static int 3562 cctl_devlist(int fd, int argc, char **argv, char *combinedopt) 3563 { 3564 struct ctl_lun_list list; 3565 struct cctl_devlist_data devlist; 3566 struct cctl_lun *lun; 3567 XML_Parser parser; 3568 char *lun_str; 3569 int lun_len; 3570 int dump_xml = 0; 3571 int retval, c; 3572 char *backend = NULL; 3573 int verbose = 0; 3574 3575 retval = 0; 3576 lun_len = 4096; 3577 3578 bzero(&devlist, sizeof(devlist)); 3579 STAILQ_INIT(&devlist.lun_list); 3580 3581 while ((c = getopt(argc, argv, combinedopt)) != -1) { 3582 switch (c) { 3583 case 'b': 3584 backend = strdup(optarg); 3585 break; 3586 case 'v': 3587 verbose++; 3588 break; 3589 case 'x': 3590 dump_xml = 1; 3591 break; 3592 default: 3593 break; 3594 } 3595 } 3596 3597 retry: 3598 lun_str = malloc(lun_len); 3599 3600 bzero(&list, sizeof(list)); 3601 list.alloc_len = lun_len; 3602 list.status = CTL_LUN_LIST_NONE; 3603 list.lun_xml = lun_str; 3604 3605 if (ioctl(fd, CTL_LUN_LIST, &list) == -1) { 3606 warn("%s: error issuing CTL_LUN_LIST ioctl", __func__); 3607 retval = 1; 3608 goto bailout; 3609 } 3610 3611 if (list.status == CTL_LUN_LIST_ERROR) { 3612 warnx("%s: error returned from CTL_LUN_LIST ioctl:\n%s", 3613 __func__, list.error_str); 3614 } else if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) { 3615 lun_len = lun_len << 1; 3616 goto retry; 3617 } 3618 3619 if (dump_xml != 0) { 3620 printf("%s", lun_str); 3621 goto bailout; 3622 } 3623 3624 parser = XML_ParserCreate(NULL); 3625 if (parser == NULL) { 3626 warn("%s: Unable to create XML parser", __func__); 3627 retval = 1; 3628 goto bailout; 3629 } 3630 3631 XML_SetUserData(parser, &devlist); 3632 XML_SetElementHandler(parser, cctl_start_element, cctl_end_element); 3633 XML_SetCharacterDataHandler(parser, cctl_char_handler); 3634 3635 retval = XML_Parse(parser, lun_str, strlen(lun_str), 1); 3636 XML_ParserFree(parser); 3637 if (retval != 1) { 3638 retval = 1; 3639 goto bailout; 3640 } 3641 3642 printf("LUN Backend %18s %4s %-16s %-16s\n", "Size (Blocks)", "BS", 3643 "Serial Number", "Device ID"); 3644 STAILQ_FOREACH(lun, &devlist.lun_list, links) { 3645 struct cctl_lun_nv *nv; 3646 3647 if ((backend != NULL) 3648 && (strcmp(lun->backend_type, backend) != 0)) 3649 continue; 3650 3651 printf("%3ju %-8s %18ju %4u %-16s %-16s\n", 3652 (uintmax_t)lun->lun_id, 3653 lun->backend_type, (uintmax_t)lun->size_blocks, 3654 lun->blocksize, lun->serial_number, lun->device_id); 3655 3656 if (verbose == 0) 3657 continue; 3658 3659 STAILQ_FOREACH(nv, &lun->attr_list, links) { 3660 printf(" %s=%s\n", nv->name, nv->value); 3661 } 3662 } 3663 bailout: 3664 free(lun_str); 3665 3666 return (retval); 3667 } 3668 3669 void 3670 usage(int error) 3671 { 3672 fprintf(error ? stderr : stdout, 3673 "Usage:\n" 3674 "Primary commands:\n" 3675 " ctladm tur [dev_id][general options]\n" 3676 " ctladm inquiry [dev_id][general options]\n" 3677 " ctladm devid [dev_id][general options]\n" 3678 " ctladm reqsense [dev_id][general options]\n" 3679 " ctladm reportluns [dev_id][general options]\n" 3680 " ctladm read [dev_id][general options] <-l lba> <-d len>\n" 3681 " <-f file|-> <-b blocksize> [-c cdbsize][-N]\n" 3682 " ctladm write [dev_id][general options] <-l lba> <-d len>\n" 3683 " <-f file|-> <-b blocksize> [-c cdbsize][-N]\n" 3684 " ctladm readcap [dev_id][general options] [-c cdbsize]\n" 3685 " ctladm modesense [dev_id][general options] <-m page|-l> [-P pc]\n" 3686 " [-d] [-S subpage] [-c cdbsize]\n" 3687 " ctladm prin [dev_id][general options] <-a action>\n" 3688 " ctladm prout [dev_id][general options] <-a action>\n" 3689 " <-r restype] [-k key] [-s sa_key]\n" 3690 " ctladm rtpg [dev_id][general options]\n" 3691 " ctladm start [dev_id][general options] [-i] [-o]\n" 3692 " ctladm stop [dev_id][general options] [-i] [-o]\n" 3693 " ctladm synccache [dev_id][general options] [-l lba]\n" 3694 " [-b blockcount] [-r] [-i] [-c cdbsize]\n" 3695 " ctladm create <-b backend> [-B blocksize] [-d device_id]\n" 3696 " [-l lun_id] [-o name=value] [-s size_bytes]\n" 3697 " [-S serial_num] [-t dev_type]\n" 3698 " ctladm remove <-b backend> <-l lun_id> [-o name=value]\n" 3699 " ctladm modify <-b backend> <-l lun_id> <-s size_bytes>\n" 3700 " ctladm devlist [-b][-v][-x]\n" 3701 " ctladm shutdown\n" 3702 " ctladm startup\n" 3703 " ctladm hardstop\n" 3704 " ctladm hardstart\n" 3705 " ctladm lunlist\n" 3706 " ctladm bbrread [dev_id] <-l lba> <-d datalen>\n" 3707 " ctladm delay [dev_id] <-l datamove|done> [-T oneshot|cont]\n" 3708 " [-t secs]\n" 3709 " ctladm realsync <on|off|query>\n" 3710 " ctladm setsync [dev_id] <-i interval>\n" 3711 " ctladm getsync [dev_id]\n" 3712 " ctladm inject [dev_id] <-i action> <-p pattern> [-r lba,len]\n" 3713 " [-s len fmt [args]] [-c] [-d delete_id]\n" 3714 " ctladm port <-l | -o <on|off> | [-w wwnn][-W wwpn]>\n" 3715 " [-p targ_port] [-t port_type] [-q] [-x]\n" 3716 " ctladm dumpooa\n" 3717 " ctladm dumpstructs\n" 3718 " ctladm help\n" 3719 "General Options:\n" 3720 "-I intiator_id : defaults to 7, used to change the initiator id\n" 3721 "-C retries : specify the number of times to retry this command\n" 3722 "-D devicename : specify the device to operate on\n" 3723 " : (default is %s)\n" 3724 "read/write options:\n" 3725 "-l lba : logical block address\n" 3726 "-d len : read/write length, in blocks\n" 3727 "-f file|- : write/read data to/from file or stdout/stdin\n" 3728 "-b blocksize : block size, in bytes\n" 3729 "-c cdbsize : specify minimum cdb size: 6, 10, 12 or 16\n" 3730 "-N : do not copy data to/from userland\n" 3731 "readcapacity options:\n" 3732 "-c cdbsize : specify minimum cdb size: 10 or 16\n" 3733 "modesense options:\n" 3734 "-m page : specify the mode page to view\n" 3735 "-l : request a list of supported pages\n" 3736 "-P pc : specify the page control value: 0-3 (current,\n" 3737 " changeable, default, saved, respectively)\n" 3738 "-d : disable block descriptors for mode sense\n" 3739 "-S subpage : specify a subpage\n" 3740 "-c cdbsize : specify minimum cdb size: 6 or 10\n" 3741 "persistent reserve in options:\n" 3742 "-a action : specify the action value: 0-2 (read key, read\n" 3743 " reservation, read capabilities, respectively)\n" 3744 "persistent reserve out options:\n" 3745 "-a action : specify the action value: 0-5 (register, reserve,\n" 3746 " release, clear, preempt, register and ignore)\n" 3747 "-k key : key value\n" 3748 "-s sa_key : service action value\n" 3749 "-r restype : specify the reservation type: 0-5(wr ex, ex ac,\n" 3750 " wr ex ro, ex ac ro, wr ex ar, ex ac ar)\n" 3751 "start/stop options:\n" 3752 "-i : set the immediate bit (CTL does not support this)\n" 3753 "-o : set the on/offline bit\n" 3754 "synccache options:\n" 3755 "-l lba : set the starting LBA\n" 3756 "-b blockcount : set the length to sync in blocks\n" 3757 "-r : set the relative addressing bit\n" 3758 "-i : set the immediate bit\n" 3759 "-c cdbsize : specify minimum cdb size: 10 or 16\n" 3760 "create options:\n" 3761 "-b backend : backend name (\"block\", \"ramdisk\", etc.)\n" 3762 "-B blocksize : LUN blocksize in bytes (some backends)\n" 3763 "-d device_id : SCSI VPD page 0x83 ID\n" 3764 "-l lun_id : requested LUN number\n" 3765 "-o name=value : backend-specific options, multiple allowed\n" 3766 "-s size_bytes : LUN size in bytes (some backends)\n" 3767 "-S serial_num : SCSI VPD page 0x80 serial number\n" 3768 "-t dev_type : SCSI device type (0=disk, 3=processor)\n" 3769 "remove options:\n" 3770 "-b backend : backend name (\"block\", \"ramdisk\", etc.)\n" 3771 "-l lun_id : LUN number to delete\n" 3772 "-o name=value : backend-specific options, multiple allowed\n" 3773 "devlist options:\n" 3774 "-b backend : list devices from specified backend only\n" 3775 "-v : be verbose, show backend attributes\n" 3776 "-x : dump raw XML\n" 3777 "delay options:\n" 3778 "-l datamove|done : delay command at datamove or done phase\n" 3779 "-T oneshot : delay one command, then resume normal completion\n" 3780 "-T cont : delay all commands\n" 3781 "-t secs : number of seconds to delay\n" 3782 "inject options:\n" 3783 "-i error_action : action to perform\n" 3784 "-p pattern : command pattern to look for\n" 3785 "-r lba,len : LBA range for pattern\n" 3786 "-s len fmt [args] : sense data for custom sense action\n" 3787 "-c : continuous operation\n" 3788 "-d delete_id : error id to delete\n" 3789 "port options:\n" 3790 "-l : list frontend ports\n" 3791 "-o on|off : turn frontend ports on or off\n" 3792 "-w wwnn : set WWNN for one frontend\n" 3793 "-W wwpn : set WWPN for one frontend\n" 3794 "-t port_type : specify fc, scsi, ioctl, internal frontend type\n" 3795 "-p targ_port : specify target port number\n" 3796 "-q : omit header in list output\n" 3797 "-x : output port list in XML format\n" 3798 "bbrread options:\n" 3799 "-l lba : starting LBA\n" 3800 "-d datalen : length, in bytes, to read\n", 3801 CTL_DEFAULT_DEV); 3802 } 3803 3804 int 3805 main(int argc, char **argv) 3806 { 3807 int c; 3808 ctladm_cmdfunction command; 3809 ctladm_cmdargs cmdargs; 3810 ctladm_optret optreturn; 3811 char *device; 3812 const char *mainopt = "C:D:I:"; 3813 const char *subopt = NULL; 3814 char combinedopt[256]; 3815 int target, lun; 3816 int optstart = 2; 3817 int retval, fd; 3818 int retries; 3819 int initid; 3820 int saved_errno; 3821 3822 retval = 0; 3823 cmdargs = CTLADM_ARG_NONE; 3824 command = CTLADM_CMD_HELP; 3825 device = NULL; 3826 fd = -1; 3827 retries = 0; 3828 target = 0; 3829 lun = 0; 3830 initid = 7; 3831 3832 if (argc < 2) { 3833 usage(1); 3834 retval = 1; 3835 goto bailout; 3836 } 3837 3838 /* 3839 * Get the base option. 3840 */ 3841 optreturn = getoption(option_table,argv[1], &command, &cmdargs,&subopt); 3842 3843 if (optreturn == CC_OR_AMBIGUOUS) { 3844 warnx("ambiguous option %s", argv[1]); 3845 usage(0); 3846 exit(1); 3847 } else if (optreturn == CC_OR_NOT_FOUND) { 3848 warnx("option %s not found", argv[1]); 3849 usage(0); 3850 exit(1); 3851 } 3852 3853 if (cmdargs & CTLADM_ARG_NEED_TL) { 3854 if ((argc < 3) 3855 || (!isdigit(argv[2][0]))) { 3856 warnx("option %s requires a target:lun argument", 3857 argv[1]); 3858 usage(0); 3859 exit(1); 3860 } 3861 retval = cctl_parse_tl(argv[2], &target, &lun); 3862 if (retval != 0) 3863 errx(1, "invalid target:lun argument %s", argv[2]); 3864 3865 cmdargs |= CTLADM_ARG_TARG_LUN; 3866 optstart++; 3867 } 3868 3869 /* 3870 * Ahh, getopt(3) is a pain. 3871 * 3872 * This is a gross hack. There really aren't many other good 3873 * options (excuse the pun) for parsing options in a situation like 3874 * this. getopt is kinda braindead, so you end up having to run 3875 * through the options twice, and give each invocation of getopt 3876 * the option string for the other invocation. 3877 * 3878 * You would think that you could just have two groups of options. 3879 * The first group would get parsed by the first invocation of 3880 * getopt, and the second group would get parsed by the second 3881 * invocation of getopt. It doesn't quite work out that way. When 3882 * the first invocation of getopt finishes, it leaves optind pointing 3883 * to the argument _after_ the first argument in the second group. 3884 * So when the second invocation of getopt comes around, it doesn't 3885 * recognize the first argument it gets and then bails out. 3886 * 3887 * A nice alternative would be to have a flag for getopt that says 3888 * "just keep parsing arguments even when you encounter an unknown 3889 * argument", but there isn't one. So there's no real clean way to 3890 * easily parse two sets of arguments without having one invocation 3891 * of getopt know about the other. 3892 * 3893 * Without this hack, the first invocation of getopt would work as 3894 * long as the generic arguments are first, but the second invocation 3895 * (in the subfunction) would fail in one of two ways. In the case 3896 * where you don't set optreset, it would fail because optind may be 3897 * pointing to the argument after the one it should be pointing at. 3898 * In the case where you do set optreset, and reset optind, it would 3899 * fail because getopt would run into the first set of options, which 3900 * it doesn't understand. 3901 * 3902 * All of this would "sort of" work if you could somehow figure out 3903 * whether optind had been incremented one option too far. The 3904 * mechanics of that, however, are more daunting than just giving 3905 * both invocations all of the expect options for either invocation. 3906 * 3907 * Needless to say, I wouldn't mind if someone invented a better 3908 * (non-GPL!) command line parsing interface than getopt. I 3909 * wouldn't mind if someone added more knobs to getopt to make it 3910 * work better. Who knows, I may talk myself into doing it someday, 3911 * if the standards weenies let me. As it is, it just leads to 3912 * hackery like this and causes people to avoid it in some cases. 3913 * 3914 * KDM, September 8th, 1998 3915 */ 3916 if (subopt != NULL) 3917 sprintf(combinedopt, "%s%s", mainopt, subopt); 3918 else 3919 sprintf(combinedopt, "%s", mainopt); 3920 3921 /* 3922 * Start getopt processing at argv[2/3], since we've already 3923 * accepted argv[1..2] as the command name, and as a possible 3924 * device name. 3925 */ 3926 optind = optstart; 3927 3928 /* 3929 * Now we run through the argument list looking for generic 3930 * options, and ignoring options that possibly belong to 3931 * subfunctions. 3932 */ 3933 while ((c = getopt(argc, argv, combinedopt))!= -1){ 3934 switch (c) { 3935 case 'C': 3936 cmdargs |= CTLADM_ARG_RETRIES; 3937 retries = strtol(optarg, NULL, 0); 3938 break; 3939 case 'D': 3940 device = strdup(optarg); 3941 cmdargs |= CTLADM_ARG_DEVICE; 3942 break; 3943 case 'I': 3944 cmdargs |= CTLADM_ARG_INITIATOR; 3945 initid = strtol(optarg, NULL, 0); 3946 break; 3947 default: 3948 break; 3949 } 3950 } 3951 3952 if ((cmdargs & CTLADM_ARG_INITIATOR) == 0) 3953 initid = 7; 3954 3955 optind = optstart; 3956 optreset = 1; 3957 3958 /* 3959 * Default to opening the CTL device for now. 3960 */ 3961 if (((cmdargs & CTLADM_ARG_DEVICE) == 0) 3962 && (command != CTLADM_CMD_HELP)) { 3963 device = strdup(CTL_DEFAULT_DEV); 3964 cmdargs |= CTLADM_ARG_DEVICE; 3965 } 3966 3967 if ((cmdargs & CTLADM_ARG_DEVICE) 3968 && (command != CTLADM_CMD_HELP)) { 3969 fd = open(device, O_RDWR); 3970 if (fd == -1 && errno == ENOENT) { 3971 saved_errno = errno; 3972 retval = kldload("ctl"); 3973 if (retval != -1) 3974 fd = open(device, O_RDWR); 3975 else 3976 errno = saved_errno; 3977 } 3978 if (fd == -1) { 3979 fprintf(stderr, "%s: error opening %s: %s\n", 3980 argv[0], device, strerror(errno)); 3981 retval = 1; 3982 goto bailout; 3983 } 3984 } else if ((command != CTLADM_CMD_HELP) 3985 && ((cmdargs & CTLADM_ARG_DEVICE) == 0)) { 3986 fprintf(stderr, "%s: you must specify a device with the " 3987 "--device argument for this command\n", argv[0]); 3988 command = CTLADM_CMD_HELP; 3989 retval = 1; 3990 } 3991 3992 switch (command) { 3993 case CTLADM_CMD_TUR: 3994 retval = cctl_tur(fd, target, lun, initid, retries); 3995 break; 3996 case CTLADM_CMD_INQUIRY: 3997 retval = cctl_inquiry(fd, target, lun, initid, retries); 3998 break; 3999 case CTLADM_CMD_REQ_SENSE: 4000 retval = cctl_req_sense(fd, target, lun, initid, retries); 4001 break; 4002 case CTLADM_CMD_REPORT_LUNS: 4003 retval = cctl_report_luns(fd, target, lun, initid, retries); 4004 break; 4005 case CTLADM_CMD_CREATE: 4006 retval = cctl_create_lun(fd, argc, argv, combinedopt); 4007 break; 4008 case CTLADM_CMD_RM: 4009 retval = cctl_rm_lun(fd, argc, argv, combinedopt); 4010 break; 4011 case CTLADM_CMD_DEVLIST: 4012 retval = cctl_devlist(fd, argc, argv, combinedopt); 4013 break; 4014 case CTLADM_CMD_READ: 4015 case CTLADM_CMD_WRITE: 4016 retval = cctl_read_write(fd, target, lun, initid, retries, 4017 argc, argv, combinedopt, command); 4018 break; 4019 case CTLADM_CMD_PORT: 4020 retval = cctl_port(fd, argc, argv, combinedopt); 4021 break; 4022 case CTLADM_CMD_READCAPACITY: 4023 retval = cctl_read_capacity(fd, target, lun, initid, retries, 4024 argc, argv, combinedopt); 4025 break; 4026 case CTLADM_CMD_MODESENSE: 4027 retval = cctl_mode_sense(fd, target, lun, initid, retries, 4028 argc, argv, combinedopt); 4029 break; 4030 case CTLADM_CMD_START: 4031 case CTLADM_CMD_STOP: 4032 retval = cctl_start_stop(fd, target, lun, initid, retries, 4033 (command == CTLADM_CMD_START) ? 1 : 0, 4034 argc, argv, combinedopt); 4035 break; 4036 case CTLADM_CMD_SYNC_CACHE: 4037 retval = cctl_sync_cache(fd, target, lun, initid, retries, 4038 argc, argv, combinedopt); 4039 break; 4040 case CTLADM_CMD_SHUTDOWN: 4041 case CTLADM_CMD_STARTUP: 4042 retval = cctl_startup_shutdown(fd, target, lun, initid, 4043 command); 4044 break; 4045 case CTLADM_CMD_HARDSTOP: 4046 case CTLADM_CMD_HARDSTART: 4047 retval = cctl_hardstopstart(fd, command); 4048 break; 4049 case CTLADM_CMD_BBRREAD: 4050 retval = cctl_bbrread(fd, target, lun, initid, argc, argv, 4051 combinedopt); 4052 break; 4053 case CTLADM_CMD_LUNLIST: 4054 retval = cctl_lunlist(fd); 4055 break; 4056 case CTLADM_CMD_DELAY: 4057 retval = cctl_delay(fd, target, lun, argc, argv, combinedopt); 4058 break; 4059 case CTLADM_CMD_REALSYNC: 4060 retval = cctl_realsync(fd, argc, argv); 4061 break; 4062 case CTLADM_CMD_SETSYNC: 4063 case CTLADM_CMD_GETSYNC: 4064 retval = cctl_getsetsync(fd, target, lun, command, 4065 argc, argv, combinedopt); 4066 break; 4067 case CTLADM_CMD_ERR_INJECT: 4068 retval = cctl_error_inject(fd, target, lun, argc, argv, 4069 combinedopt); 4070 break; 4071 case CTLADM_CMD_DUMPOOA: 4072 retval = cctl_dump_ooa(fd, argc, argv); 4073 break; 4074 case CTLADM_CMD_DUMPSTRUCTS: 4075 retval = cctl_dump_structs(fd, cmdargs); 4076 break; 4077 case CTLADM_CMD_PRES_IN: 4078 retval = cctl_persistent_reserve_in(fd, target, lun, initid, 4079 argc, argv, combinedopt, 4080 retries); 4081 break; 4082 case CTLADM_CMD_PRES_OUT: 4083 retval = cctl_persistent_reserve_out(fd, target, lun, initid, 4084 argc, argv, combinedopt, 4085 retries); 4086 break; 4087 case CTLADM_CMD_INQ_VPD_DEVID: 4088 retval = cctl_inquiry_vpd_devid(fd, target, lun, initid); 4089 break; 4090 case CTLADM_CMD_RTPG: 4091 retval = cctl_report_target_port_group(fd, target, lun, initid); 4092 break; 4093 case CTLADM_CMD_MODIFY: 4094 retval = cctl_modify_lun(fd, argc, argv, combinedopt); 4095 break; 4096 case CTLADM_CMD_HELP: 4097 default: 4098 usage(retval); 4099 break; 4100 } 4101 bailout: 4102 4103 if (fd != -1) 4104 close(fd); 4105 4106 exit (retval); 4107 } 4108 4109 /* 4110 * vim: ts=8 4111 */ 4112