1 /*- 2 * Copyright (c) 2013 Spectra Logic Corporation 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions, and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * substantially similar to the "NO WARRANTY" disclaimer below 13 * ("Disclaimer") and any redistribution must be conditioned upon 14 * including a substantially similar Disclaimer requirement for further 15 * binary redistribution. 16 * 17 * NO WARRANTY 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGES. 29 * 30 * Authors: Ken Merry (Spectra Logic Corporation) 31 */ 32 /* 33 * SCSI Persistent Reservation support for camcontrol(8). 34 */ 35 36 #include <sys/cdefs.h> 37 #include <sys/ioctl.h> 38 #include <sys/stdint.h> 39 #include <sys/types.h> 40 #include <sys/endian.h> 41 #include <sys/sbuf.h> 42 #include <sys/queue.h> 43 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <inttypes.h> 47 #include <unistd.h> 48 #include <string.h> 49 #include <strings.h> 50 #include <fcntl.h> 51 #include <ctype.h> 52 #include <limits.h> 53 #include <err.h> 54 55 #include <cam/cam.h> 56 #include <cam/cam_debug.h> 57 #include <cam/cam_ccb.h> 58 #include <cam/scsi/scsi_all.h> 59 #include <cam/scsi/scsi_pass.h> 60 #include <cam/scsi/scsi_message.h> 61 #include <camlib.h> 62 #include "camcontrol.h" 63 64 struct persist_transport_id { 65 struct scsi_transportid_header *hdr; 66 unsigned int alloc_len; 67 STAILQ_ENTRY(persist_transport_id) links; 68 }; 69 70 /* 71 * Service Actions for PERSISTENT RESERVE IN. 72 */ 73 static struct scsi_nv persist_in_actions[] = { 74 { "read_keys", SPRI_RK }, 75 { "read_reservation", SPRI_RR }, 76 { "report_capabilities", SPRI_RC }, 77 { "read_full_status", SPRI_RS } 78 }; 79 80 /* 81 * Service Actions for PERSISTENT RESERVE OUT. 82 */ 83 static struct scsi_nv persist_out_actions[] = { 84 { "register", SPRO_REGISTER }, 85 { "reserve", SPRO_RESERVE }, 86 { "release" , SPRO_RELEASE }, 87 { "clear", SPRO_CLEAR }, 88 { "preempt", SPRO_PREEMPT }, 89 { "preempt_abort", SPRO_PRE_ABO }, 90 { "register_ignore", SPRO_REG_IGNO }, 91 { "register_move", SPRO_REG_MOVE }, 92 { "replace_lost", SPRO_REPL_LOST_RES } 93 }; 94 95 /* 96 * Known reservation scopes. As of SPC-4, only LU_SCOPE is used in the 97 * spec. The others are obsolete. 98 */ 99 static struct scsi_nv persist_scope_table[] = { 100 { "lun", SPR_LU_SCOPE }, 101 { "extent", SPR_EXTENT_SCOPE }, 102 { "element", SPR_ELEMENT_SCOPE } 103 }; 104 105 /* 106 * Reservation types. The longer name for a given reservation type is 107 * listed first, so that it makes more sense when we print out the 108 * reservation type. We step through the table linearly when looking for 109 * the text name for a particular numeric reservation type value. 110 */ 111 static struct scsi_nv persist_type_table[] = { 112 { "read_shared", SPR_TYPE_RD_SHARED }, 113 { "write_exclusive", SPR_TYPE_WR_EX }, 114 { "wr_ex", SPR_TYPE_WR_EX }, 115 { "read_exclusive", SPR_TYPE_RD_EX }, 116 { "rd_ex", SPR_TYPE_RD_EX }, 117 { "exclusive_access", SPR_TYPE_EX_AC }, 118 { "ex_ac", SPR_TYPE_EX_AC }, 119 { "write_exclusive_reg_only", SPR_TYPE_WR_EX_RO }, 120 { "wr_ex_ro", SPR_TYPE_WR_EX_RO }, 121 { "exclusive_access_reg_only", SPR_TYPE_EX_AC_RO }, 122 { "ex_ac_ro", SPR_TYPE_EX_AC_RO }, 123 { "write_exclusive_all_regs", SPR_TYPE_WR_EX_AR }, 124 { "wr_ex_ar", SPR_TYPE_WR_EX_AR }, 125 { "exclusive_access_all_regs", SPR_TYPE_EX_AC_AR }, 126 { "ex_ac_ar", SPR_TYPE_EX_AC_AR } 127 }; 128 129 /* 130 * Print out the standard scope/type field. 131 */ 132 static void 133 persist_print_scopetype(uint8_t scopetype) 134 { 135 const char *tmpstr; 136 int num_entries; 137 138 num_entries = sizeof(persist_scope_table) / 139 sizeof(persist_scope_table[0]); 140 tmpstr = scsi_nv_to_str(persist_scope_table, num_entries, 141 scopetype & SPR_SCOPE_MASK); 142 fprintf(stdout, "Scope: %s (%#x)\n", (tmpstr != NULL) ? tmpstr : 143 "Unknown", (scopetype & SPR_SCOPE_MASK) >> SPR_SCOPE_SHIFT); 144 145 num_entries = sizeof(persist_type_table) / 146 sizeof(persist_type_table[0]); 147 tmpstr = scsi_nv_to_str(persist_type_table, num_entries, 148 scopetype & SPR_TYPE_MASK); 149 fprintf(stdout, "Type: %s (%#x)\n", (tmpstr != NULL) ? tmpstr : 150 "Unknown", scopetype & SPR_TYPE_MASK); 151 } 152 153 static void 154 persist_print_transportid(uint8_t *buf, uint32_t len) 155 { 156 struct sbuf *sb; 157 158 sb = sbuf_new_auto(); 159 if (sb == NULL) 160 fprintf(stderr, "Unable to allocate sbuf\n"); 161 162 scsi_transportid_sbuf(sb, (struct scsi_transportid_header *)buf, len); 163 164 sbuf_finish(sb); 165 166 fprintf(stdout, "%s\n", sbuf_data(sb)); 167 168 sbuf_delete(sb); 169 } 170 171 /* 172 * Print out a persistent reservation. This is used with the READ 173 * RESERVATION (0x01) service action of the PERSISTENT RESERVE IN command. 174 */ 175 static void 176 persist_print_res(struct scsi_per_res_in_header *hdr, uint32_t valid_len) 177 { 178 uint32_t length; 179 struct scsi_per_res_in_rsrv *res; 180 181 length = scsi_4btoul(hdr->length); 182 length = MIN(length, valid_len); 183 184 res = (struct scsi_per_res_in_rsrv *)hdr; 185 186 if (length < sizeof(res->data) - sizeof(res->data.extent_length)) { 187 if (length == 0) 188 fprintf(stdout, "No reservations.\n"); 189 else 190 warnx("unable to print reservation, only got %u " 191 "valid bytes", length); 192 return; 193 } 194 fprintf(stdout, "PRgeneration: %#x\n", 195 scsi_4btoul(res->header.generation)); 196 fprintf(stdout, "Reservation Key: %#jx\n", 197 (uintmax_t)scsi_8btou64(res->data.reservation)); 198 fprintf(stdout, "Scope address: %#x\n", 199 scsi_4btoul(res->data.scope_addr)); 200 201 persist_print_scopetype(res->data.scopetype); 202 203 fprintf(stdout, "Extent length: %u\n", 204 scsi_2btoul(res->data.extent_length)); 205 } 206 207 /* 208 * Print out persistent reservation keys. This is used with the READ KEYS 209 * service action of the PERSISTENT RESERVE IN command. 210 */ 211 static void 212 persist_print_keys(struct scsi_per_res_in_header *hdr, uint32_t valid_len) 213 { 214 uint32_t length, num_keys, i; 215 struct scsi_per_res_key *key; 216 217 length = scsi_4btoul(hdr->length); 218 length = MIN(length, valid_len); 219 220 num_keys = length / sizeof(*key); 221 222 fprintf(stdout, "PRgeneration: %#x\n", scsi_4btoul(hdr->generation)); 223 fprintf(stdout, "%u key%s%s\n", num_keys, (num_keys == 1) ? "" : "s", 224 (num_keys == 0) ? "." : ":"); 225 226 for (i = 0, key = (struct scsi_per_res_key *)&hdr[1]; i < num_keys; 227 i++, key++) { 228 fprintf(stdout, "%u: %#jx\n", i, 229 (uintmax_t)scsi_8btou64(key->key)); 230 } 231 } 232 233 /* 234 * Print out persistent reservation capabilities. This is used with the 235 * REPORT CAPABILITIES service action of the PERSISTENT RESERVE IN command. 236 */ 237 static void 238 persist_print_cap(struct scsi_per_res_cap *cap, uint32_t valid_len) 239 { 240 uint32_t length; 241 int check_type_mask = 0; 242 uint32_t type_mask; 243 244 length = scsi_2btoul(cap->length); 245 length = MIN(length, valid_len); 246 type_mask = scsi_2btoul(cap->type_mask); 247 248 if (length < __offsetof(struct scsi_per_res_cap, type_mask)) { 249 fprintf(stdout, "Insufficient data (%u bytes) to report " 250 "full capabilities\n", length); 251 return; 252 } 253 if (length >= __offsetof(struct scsi_per_res_cap, reserved)) 254 check_type_mask = 1; 255 256 fprintf(stdout, "Replace Lost Reservation Capable (RLR_C): %d\n", 257 (cap->flags1 & SPRI_RLR_C) ? 1 : 0); 258 fprintf(stdout, "Compatible Reservation Handling (CRH): %d\n", 259 (cap->flags1 & SPRI_CRH) ? 1 : 0); 260 fprintf(stdout, "Specify Initiator Ports Capable (SIP_C): %d\n", 261 (cap->flags1 & SPRI_SIP_C) ? 1 : 0); 262 fprintf(stdout, "All Target Ports Capable (ATP_C): %d\n", 263 (cap->flags1 & SPRI_ATP_C) ? 1 : 0); 264 fprintf(stdout, "Persist Through Power Loss Capable (PTPL_C): %d\n", 265 (cap->flags1 & SPRI_PTPL_C) ? 1 : 0); 266 fprintf(stdout, "ALLOW COMMANDS field: (%#x)\n", 267 (cap->flags2 & SPRI_ALLOW_CMD_MASK) >> SPRI_ALLOW_CMD_SHIFT); 268 /* 269 * These cases are cut-and-pasted from SPC4r36l. There is no 270 * succinct way to describe these otherwise, and even with the 271 * verbose description, the user will probably have to refer to 272 * the spec to fully understand what is going on. 273 */ 274 switch (cap->flags2 & SPRI_ALLOW_CMD_MASK) { 275 case SPRI_ALLOW_1: 276 fprintf(stdout, 277 " The device server allows the TEST UNIT READY command through Write\n" 278 " Exclusive type reservations and Exclusive Access type reservations\n" 279 " and does not provide information about whether the following commands\n" 280 " are allowed through Write Exclusive type reservations:\n" 281 " a) the MODE SENSE command, READ ATTRIBUTE command, READ BUFFER\n" 282 " command, RECEIVE COPY RESULTS command, RECEIVE DIAGNOSTIC\n" 283 " RESULTS command, REPORT SUPPORTED OPERATION CODES command,\n" 284 " and REPORT SUPPORTED TASK MANAGEMENT FUNCTION command; and\n" 285 " b) the READ DEFECT DATA command (see SBC-3).\n"); 286 break; 287 case SPRI_ALLOW_2: 288 fprintf(stdout, 289 " The device server allows the TEST UNIT READY command through Write\n" 290 " Exclusive type reservations and Exclusive Access type reservations\n" 291 " and does not allow the following commands through Write Exclusive type\n" 292 " reservations:\n" 293 " a) the MODE SENSE command, READ ATTRIBUTE command, READ BUFFER\n" 294 " command, RECEIVE DIAGNOSTIC RESULTS command, REPORT SUPPORTED\n" 295 " OPERATION CODES command, and REPORT SUPPORTED TASK MANAGEMENT\n" 296 " FUNCTION command; and\n" 297 " b) the READ DEFECT DATA command.\n" 298 " The device server does not allow the RECEIVE COPY RESULTS command\n" 299 " through Write Exclusive type reservations or Exclusive Access type\n" 300 " reservations.\n"); 301 break; 302 case SPRI_ALLOW_3: 303 fprintf(stdout, 304 " The device server allows the TEST UNIT READY command through Write\n" 305 " Exclusive type reservations and Exclusive Access type reservations\n" 306 " and allows the following commands through Write Exclusive type\n" 307 " reservations:\n" 308 " a) the MODE SENSE command, READ ATTRIBUTE command, READ BUFFER\n" 309 " command, RECEIVE DIAGNOSTIC RESULTS command, REPORT SUPPORTED\n" 310 " OPERATION CODES command, and REPORT SUPPORTED TASK MANAGEMENT\n" 311 " FUNCTION command; and\n" 312 " b) the READ DEFECT DATA command.\n" 313 " The device server does not allow the RECEIVE COPY RESULTS command\n" 314 " through Write Exclusive type reservations or Exclusive Access type\n" 315 " reservations.\n"); 316 break; 317 case SPRI_ALLOW_4: 318 fprintf(stdout, 319 " The device server allows the TEST UNIT READY command and the RECEIVE\n" 320 " COPY RESULTS command through Write Exclusive type reservations and\n" 321 " Exclusive Access type reservations and allows the following commands\n" 322 " through Write Exclusive type reservations:\n" 323 " a) the MODE SENSE command, READ ATTRIBUTE command, READ BUFFER\n" 324 " command, RECEIVE DIAGNOSTIC RESULTS command, REPORT SUPPORTED\n" 325 " OPERATION CODES command, and REPORT SUPPORTED TASK MANAGEMENT\n" 326 " FUNCTION command; and\n" 327 " b) the READ DEFECT DATA command.\n"); 328 break; 329 case SPRI_ALLOW_NA: 330 fprintf(stdout, 331 " No information is provided about whether certain commands are allowed\n" 332 " through certain types of persistent reservations.\n"); 333 break; 334 default: 335 fprintf(stdout, 336 " Unknown ALLOW COMMANDS value %#x\n", 337 (cap->flags2 & SPRI_ALLOW_CMD_MASK) >> 338 SPRI_ALLOW_CMD_SHIFT); 339 break; 340 } 341 fprintf(stdout, "Persist Through Power Loss Activated (PTPL_A): %d\n", 342 (cap->flags2 & SPRI_PTPL_A) ? 1 : 0); 343 if ((check_type_mask != 0) 344 && (cap->flags2 & SPRI_TMV)) { 345 fprintf(stdout, "Supported Persistent Reservation Types:\n"); 346 fprintf(stdout, " Write Exclusive - All Registrants " 347 "(WR_EX_AR): %d\n", 348 (type_mask & SPRI_TM_WR_EX_AR)? 1 : 0); 349 fprintf(stdout, " Exclusive Access - Registrants Only " 350 "(EX_AC_RO): %d\n", 351 (type_mask & SPRI_TM_EX_AC_RO) ? 1 : 0); 352 fprintf(stdout, " Write Exclusive - Registrants Only " 353 "(WR_EX_RO): %d\n", 354 (type_mask & SPRI_TM_WR_EX_RO)? 1 : 0); 355 fprintf(stdout, " Exclusive Access (EX_AC): %d\n", 356 (type_mask & SPRI_TM_EX_AC) ? 1 : 0); 357 fprintf(stdout, " Write Exclusive (WR_EX): %d\n", 358 (type_mask & SPRI_TM_WR_EX) ? 1 : 0); 359 fprintf(stdout, " Exclusive Access - All Registrants " 360 "(EX_AC_AR): %d\n", 361 (type_mask & SPRI_TM_EX_AC_AR) ? 1 : 0); 362 } else { 363 fprintf(stdout, "Persistent Reservation Type Mask is NOT " 364 "valid\n"); 365 } 366 367 368 } 369 370 static void 371 persist_print_full(struct scsi_per_res_in_header *hdr, uint32_t valid_len) 372 { 373 uint32_t length, len_to_go = 0; 374 struct scsi_per_res_in_full_desc *desc; 375 uint8_t *cur_pos; 376 377 length = scsi_4btoul(hdr->length); 378 length = MIN(length, valid_len); 379 380 if (length < sizeof(*desc)) { 381 if (length == 0) 382 fprintf(stdout, "No reservations.\n"); 383 else 384 warnx("unable to print reservation, only got %u " 385 "valid bytes", length); 386 return; 387 } 388 389 fprintf(stdout, "PRgeneration: %#x\n", scsi_4btoul(hdr->generation)); 390 cur_pos = (uint8_t *)&hdr[1]; 391 for (len_to_go = length, 392 desc = (struct scsi_per_res_in_full_desc *)cur_pos; 393 len_to_go >= sizeof(*desc); 394 desc = (struct scsi_per_res_in_full_desc *)cur_pos) { 395 uint32_t additional_length, cur_length; 396 397 398 fprintf(stdout, "Reservation Key: %#jx\n", 399 (uintmax_t)scsi_8btou64(desc->res_key.key)); 400 fprintf(stdout, "All Target Ports (ALL_TG_PT): %d\n", 401 (desc->flags & SPRI_FULL_ALL_TG_PT) ? 1 : 0); 402 fprintf(stdout, "Reservation Holder (R_HOLDER): %d\n", 403 (desc->flags & SPRI_FULL_R_HOLDER) ? 1 : 0); 404 405 if (desc->flags & SPRI_FULL_R_HOLDER) 406 persist_print_scopetype(desc->scopetype); 407 408 if ((desc->flags & SPRI_FULL_ALL_TG_PT) == 0) 409 fprintf(stdout, "Relative Target Port ID: %#x\n", 410 scsi_2btoul(desc->rel_trgt_port_id)); 411 412 additional_length = scsi_4btoul(desc->additional_length); 413 414 persist_print_transportid(desc->transport_id, 415 additional_length); 416 417 cur_length = sizeof(*desc) + additional_length; 418 len_to_go -= cur_length; 419 cur_pos += cur_length; 420 } 421 } 422 423 int 424 scsipersist(struct cam_device *device, int argc, char **argv, char *combinedopt, 425 int task_attr, int retry_count, int timeout, int verbosemode, 426 int err_recover) 427 { 428 union ccb *ccb = NULL; 429 int c, in = 0, out = 0; 430 int action = -1, num_ids = 0; 431 int error = 0; 432 uint32_t res_len = 0; 433 unsigned long rel_tgt_port = 0; 434 uint8_t *res_buf = NULL; 435 int scope = SPR_LU_SCOPE, res_type = 0; 436 struct persist_transport_id *id, *id2; 437 STAILQ_HEAD(, persist_transport_id) transport_id_list; 438 uint64_t key = 0, sa_key = 0; 439 struct scsi_nv *table = NULL; 440 size_t table_size = 0, id_len = 0; 441 uint32_t valid_len = 0; 442 int all_tg_pt = 0, aptpl = 0, spec_i_pt = 0, unreg = 0,rel_port_set = 0; 443 444 STAILQ_INIT(&transport_id_list); 445 446 ccb = cam_getccb(device); 447 if (ccb == NULL) { 448 warnx("%s: error allocating CCB", __func__); 449 error = 1; 450 goto bailout; 451 } 452 453 while ((c = getopt(argc, argv, combinedopt)) != -1) { 454 switch (c) { 455 case 'a': 456 all_tg_pt = 1; 457 break; 458 case 'I': { 459 int error_str_len = 128; 460 char error_str[error_str_len]; 461 char *id_str; 462 463 id = malloc(sizeof(*id)); 464 if (id == NULL) { 465 warnx("%s: error allocating %zu bytes", 466 __func__, sizeof(*id)); 467 error = 1; 468 goto bailout; 469 } 470 bzero(id, sizeof(*id)); 471 472 id_str = strdup(optarg); 473 if (id_str == NULL) { 474 warnx("%s: error duplicating string %s", 475 __func__, optarg); 476 free(id); 477 error = 1; 478 goto bailout; 479 } 480 error = scsi_parse_transportid(id_str, &id->hdr, 481 &id->alloc_len, error_str, error_str_len); 482 if (error != 0) { 483 warnx("%s", error_str); 484 error = 1; 485 free(id); 486 free(id_str); 487 goto bailout; 488 } 489 free(id_str); 490 491 STAILQ_INSERT_TAIL(&transport_id_list, id, links); 492 num_ids++; 493 id_len += id->alloc_len; 494 break; 495 } 496 case 'k': 497 case 'K': { 498 char *endptr; 499 uint64_t tmpval; 500 501 tmpval = strtoumax(optarg, &endptr, 0); 502 if (*endptr != '\0') { 503 warnx("%s: invalid key argument %s", __func__, 504 optarg); 505 error = 1; 506 goto bailout; 507 } 508 if (c == 'k') { 509 key = tmpval; 510 } else { 511 sa_key = tmpval; 512 } 513 break; 514 } 515 case 'i': 516 case 'o': { 517 scsi_nv_status status; 518 int table_entry = 0; 519 520 if (c == 'i') { 521 in = 1; 522 table = persist_in_actions; 523 table_size = sizeof(persist_in_actions) / 524 sizeof(persist_in_actions[0]); 525 } else { 526 out = 1; 527 table = persist_out_actions; 528 table_size = sizeof(persist_out_actions) / 529 sizeof(persist_out_actions[0]); 530 } 531 532 if ((in + out) > 1) { 533 warnx("%s: only one in (-i) or out (-o) " 534 "action is allowed", __func__); 535 error = 1; 536 goto bailout; 537 } 538 539 status = scsi_get_nv(table, table_size, optarg, 540 &table_entry,SCSI_NV_FLAG_IG_CASE); 541 if (status == SCSI_NV_FOUND) 542 action = table[table_entry].value; 543 else { 544 warnx("%s: %s %s option %s", __func__, 545 (status == SCSI_NV_AMBIGUOUS) ? 546 "ambiguous" : "invalid", in ? "in" : 547 "out", optarg); 548 error = 1; 549 goto bailout; 550 } 551 break; 552 } 553 case 'p': 554 aptpl = 1; 555 break; 556 case 'R': { 557 char *endptr; 558 559 rel_tgt_port = strtoul(optarg, &endptr, 0); 560 if (*endptr != '\0') { 561 warnx("%s: invalid relative target port %s", 562 __func__, optarg); 563 error = 1; 564 goto bailout; 565 } 566 rel_port_set = 1; 567 break; 568 } 569 case 's': { 570 size_t scope_size; 571 struct scsi_nv *scope_table = NULL; 572 scsi_nv_status status; 573 int table_entry = 0; 574 char *endptr; 575 576 /* 577 * First check to see if the user gave us a numeric 578 * argument. If so, we'll try using it. 579 */ 580 if (isdigit(optarg[0])) { 581 scope = strtol(optarg, &endptr, 0); 582 if (*endptr != '\0') { 583 warnx("%s: invalid scope %s", 584 __func__, optarg); 585 error = 1; 586 goto bailout; 587 } 588 scope = (scope << SPR_SCOPE_SHIFT) & 589 SPR_SCOPE_MASK; 590 break; 591 } 592 593 scope_size = sizeof(persist_scope_table) / 594 sizeof(persist_scope_table[0]); 595 scope_table = persist_scope_table; 596 status = scsi_get_nv(scope_table, scope_size, optarg, 597 &table_entry,SCSI_NV_FLAG_IG_CASE); 598 if (status == SCSI_NV_FOUND) 599 scope = scope_table[table_entry].value; 600 else { 601 warnx("%s: %s scope %s", __func__, 602 (status == SCSI_NV_AMBIGUOUS) ? 603 "ambiguous" : "invalid", optarg); 604 error = 1; 605 goto bailout; 606 } 607 break; 608 } 609 case 'S': 610 spec_i_pt = 1; 611 break; 612 case 'T': { 613 size_t res_type_size; 614 struct scsi_nv *rtype_table = NULL; 615 scsi_nv_status status; 616 char *endptr; 617 int table_entry = 0; 618 619 /* 620 * First check to see if the user gave us a numeric 621 * argument. If so, we'll try using it. 622 */ 623 if (isdigit(optarg[0])) { 624 res_type = strtol(optarg, &endptr, 0); 625 if (*endptr != '\0') { 626 warnx("%s: invalid reservation type %s", 627 __func__, optarg); 628 error = 1; 629 goto bailout; 630 } 631 break; 632 } 633 634 res_type_size = sizeof(persist_type_table) / 635 sizeof(persist_type_table[0]); 636 rtype_table = persist_type_table; 637 status = scsi_get_nv(rtype_table, res_type_size, 638 optarg, &table_entry, 639 SCSI_NV_FLAG_IG_CASE); 640 if (status == SCSI_NV_FOUND) 641 res_type = rtype_table[table_entry].value; 642 else { 643 warnx("%s: %s reservation type %s", __func__, 644 (status == SCSI_NV_AMBIGUOUS) ? 645 "ambiguous" : "invalid", optarg); 646 error = 1; 647 goto bailout; 648 } 649 break; 650 } 651 case 'U': 652 unreg = 1; 653 break; 654 default: 655 break; 656 } 657 } 658 659 if ((in + out) != 1) { 660 warnx("%s: you must specify one of -i or -o", __func__); 661 error = 1; 662 goto bailout; 663 } 664 665 /* 666 * Note that we don't really try to figure out whether the user 667 * needs to specify one or both keys. There are a number of 668 * scenarios, and sometimes 0 is a valid and desired value. 669 */ 670 if (in != 0) { 671 switch (action) { 672 case SPRI_RK: 673 case SPRI_RR: 674 case SPRI_RS: 675 /* 676 * Allocate the maximum length possible for these 677 * service actions. According to the spec, the 678 * target is supposed to return the available 679 * length in the header, regardless of the 680 * allocation length. In practice, though, with 681 * the READ FULL STATUS (SPRI_RS) service action, 682 * some Seagate drives (in particular a 683 * Constellation ES, <SEAGATE ST32000444SS 0006>) 684 * don't return the available length if you only 685 * allocate the length of the header. So just 686 * allocate the maximum here so we don't miss 687 * anything. 688 */ 689 res_len = SPRI_MAX_LEN; 690 break; 691 case SPRI_RC: 692 res_len = sizeof(struct scsi_per_res_cap); 693 break; 694 default: 695 /* In theory we should catch this above */ 696 warnx("%s: invalid action %d", __func__, action); 697 error = 1; 698 goto bailout; 699 break; 700 } 701 } else { 702 703 /* 704 * XXX KDM need to add length for transport IDs for the 705 * register and move service action and the register 706 * service action with the SPEC_I_PT bit set. 707 */ 708 if (action == SPRO_REG_MOVE) { 709 if (num_ids != 1) { 710 warnx("%s: register and move requires a " 711 "single transport ID (-I)", __func__); 712 error = 1; 713 goto bailout; 714 } 715 if (rel_port_set == 0) { 716 warnx("%s: register and move requires a " 717 "relative target port (-R)", __func__); 718 error = 1; 719 goto bailout; 720 } 721 res_len = sizeof(struct scsi_per_res_reg_move) + id_len; 722 } else { 723 res_len = sizeof(struct scsi_per_res_out_parms); 724 if ((action == SPRO_REGISTER) 725 && (num_ids != 0)) { 726 /* 727 * If the user specifies any IDs with the 728 * register service action, turn on the 729 * spec_i_pt bit. 730 */ 731 spec_i_pt = 1; 732 res_len += id_len; 733 res_len += 734 sizeof(struct scsi_per_res_out_trans_ids); 735 } 736 } 737 } 738 retry: 739 if (res_buf != NULL) { 740 free(res_buf); 741 res_buf = NULL; 742 } 743 res_buf = malloc(res_len); 744 if (res_buf == NULL) { 745 warn("%s: error allocating %d bytes", __func__, res_len); 746 error = 1; 747 goto bailout; 748 } 749 bzero(res_buf, res_len); 750 751 if (in != 0) { 752 scsi_persistent_reserve_in(&ccb->csio, 753 /*retries*/ retry_count, 754 /*cbfcnp*/ NULL, 755 /*tag_action*/ task_attr, 756 /*service_action*/ action, 757 /*data_ptr*/ res_buf, 758 /*dxfer_len*/ res_len, 759 /*sense_len*/ SSD_FULL_SIZE, 760 /*timeout*/ timeout ? timeout :5000); 761 762 } else { 763 switch (action) { 764 case SPRO_REGISTER: 765 if (spec_i_pt != 0) { 766 struct scsi_per_res_out_trans_ids *id_hdr; 767 uint8_t *bufptr; 768 769 bufptr = res_buf + 770 sizeof(struct scsi_per_res_out_parms) + 771 sizeof(struct scsi_per_res_out_trans_ids); 772 STAILQ_FOREACH(id, &transport_id_list, links) { 773 bcopy(id->hdr, bufptr, id->alloc_len); 774 bufptr += id->alloc_len; 775 } 776 id_hdr = (struct scsi_per_res_out_trans_ids *) 777 (res_buf + 778 sizeof(struct scsi_per_res_out_parms)); 779 scsi_ulto4b(id_len, id_hdr->additional_length); 780 } 781 case SPRO_REG_IGNO: 782 case SPRO_PREEMPT: 783 case SPRO_PRE_ABO: 784 case SPRO_RESERVE: 785 case SPRO_RELEASE: 786 case SPRO_CLEAR: 787 case SPRO_REPL_LOST_RES: { 788 struct scsi_per_res_out_parms *parms; 789 790 parms = (struct scsi_per_res_out_parms *)res_buf; 791 792 scsi_u64to8b(key, parms->res_key.key); 793 scsi_u64to8b(sa_key, parms->serv_act_res_key); 794 if (spec_i_pt != 0) 795 parms->flags |= SPR_SPEC_I_PT; 796 if (all_tg_pt != 0) 797 parms->flags |= SPR_ALL_TG_PT; 798 if (aptpl != 0) 799 parms->flags |= SPR_APTPL; 800 break; 801 } 802 case SPRO_REG_MOVE: { 803 struct scsi_per_res_reg_move *reg_move; 804 uint8_t *bufptr; 805 806 reg_move = (struct scsi_per_res_reg_move *)res_buf; 807 808 scsi_u64to8b(key, reg_move->res_key.key); 809 scsi_u64to8b(sa_key, reg_move->serv_act_res_key); 810 if (unreg != 0) 811 reg_move->flags |= SPR_REG_MOVE_UNREG; 812 if (aptpl != 0) 813 reg_move->flags |= SPR_REG_MOVE_APTPL; 814 scsi_ulto2b(rel_tgt_port, reg_move->rel_trgt_port_id); 815 id = STAILQ_FIRST(&transport_id_list); 816 /* 817 * This shouldn't happen, since we already checked 818 * the number of IDs above. 819 */ 820 if (id == NULL) { 821 warnx("%s: No transport IDs found!", __func__); 822 error = 1; 823 goto bailout; 824 } 825 bufptr = (uint8_t *)®_move[1]; 826 bcopy(id->hdr, bufptr, id->alloc_len); 827 scsi_ulto4b(id->alloc_len, 828 reg_move->transport_id_length); 829 break; 830 } 831 default: 832 break; 833 } 834 scsi_persistent_reserve_out(&ccb->csio, 835 /*retries*/ retry_count, 836 /*cbfcnp*/ NULL, 837 /*tag_action*/ task_attr, 838 /*service_action*/ action, 839 /*scope*/ scope, 840 /*res_type*/ res_type, 841 /*data_ptr*/ res_buf, 842 /*dxfer_len*/ res_len, 843 /*sense_len*/ SSD_FULL_SIZE, 844 /*timeout*/ timeout ?timeout :5000); 845 } 846 847 /* Disable freezing the device queue */ 848 ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 849 850 if (err_recover != 0) 851 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 852 853 if (cam_send_ccb(device, ccb) < 0) { 854 warn("error sending PERSISTENT RESERVE %s", (in != 0) ? 855 "IN" : "OUT"); 856 error = 1; 857 goto bailout; 858 } 859 860 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 861 if (verbosemode != 0) { 862 cam_error_print(device, ccb, CAM_ESF_ALL, 863 CAM_EPF_ALL, stderr); 864 } 865 error = 1; 866 goto bailout; 867 } 868 869 if (in == 0) 870 goto bailout; 871 872 valid_len = res_len - ccb->csio.resid; 873 874 switch (action) { 875 case SPRI_RK: 876 case SPRI_RR: 877 case SPRI_RS: { 878 struct scsi_per_res_in_header *hdr; 879 uint32_t hdr_len; 880 881 if (valid_len < sizeof(*hdr)) { 882 warnx("%s: only got %d valid bytes, need %zd", 883 __func__, valid_len, sizeof(*hdr)); 884 error = 1; 885 goto bailout; 886 } 887 hdr = (struct scsi_per_res_in_header *)res_buf; 888 hdr_len = scsi_4btoul(hdr->length); 889 890 if (hdr_len > (res_len - sizeof(*hdr))) { 891 res_len = hdr_len + sizeof(*hdr); 892 goto retry; 893 } 894 895 if (action == SPRI_RK) { 896 persist_print_keys(hdr, valid_len); 897 } else if (action == SPRI_RR) { 898 persist_print_res(hdr, valid_len); 899 } else { 900 persist_print_full(hdr, valid_len); 901 } 902 break; 903 } 904 case SPRI_RC: { 905 struct scsi_per_res_cap *cap; 906 uint32_t cap_len; 907 908 if (valid_len < sizeof(*cap)) { 909 warnx("%s: only got %u valid bytes, need %zd", 910 __func__, valid_len, sizeof(*cap)); 911 error = 1; 912 goto bailout; 913 } 914 cap = (struct scsi_per_res_cap *)res_buf; 915 cap_len = scsi_2btoul(cap->length); 916 if (cap_len != sizeof(*cap)) { 917 /* 918 * We should be able to deal with this, 919 * it's just more trouble. 920 */ 921 warnx("%s: reported size %u is different " 922 "than expected size %zd", __func__, 923 cap_len, sizeof(*cap)); 924 } 925 926 /* 927 * If there is more data available, grab it all, 928 * even though we don't really know what to do with 929 * the extra data since it obviously wasn't in the 930 * spec when this code was written. 931 */ 932 if (cap_len > res_len) { 933 res_len = cap_len; 934 goto retry; 935 } 936 persist_print_cap(cap, valid_len); 937 break; 938 } 939 default: 940 break; 941 } 942 943 bailout: 944 free(res_buf); 945 946 if (ccb != NULL) 947 cam_freeccb(ccb); 948 949 STAILQ_FOREACH_SAFE(id, &transport_id_list, links, id2) { 950 STAILQ_REMOVE(&transport_id_list, id, persist_transport_id, 951 links); 952 free(id); 953 } 954 return (error); 955 } 956