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