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