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