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