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