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 int i; 377 378 length = scsi_4btoul(hdr->length); 379 length = MIN(length, valid_len); 380 381 if (length < sizeof(*desc)) { 382 if (length == 0) 383 fprintf(stdout, "No reservations.\n"); 384 else 385 warnx("unable to print reservation, only got %u " 386 "valid bytes", length); 387 return; 388 } 389 390 fprintf(stdout, "PRgeneration: %#x\n", scsi_4btoul(hdr->generation)); 391 cur_pos = (uint8_t *)&hdr[1]; 392 for (len_to_go = length, i = 0, 393 desc = (struct scsi_per_res_in_full_desc *)cur_pos; 394 len_to_go >= sizeof(*desc); 395 desc = (struct scsi_per_res_in_full_desc *)cur_pos, i++) { 396 uint32_t additional_length, cur_length; 397 398 399 fprintf(stdout, "Reservation Key: %#jx\n", 400 (uintmax_t)scsi_8btou64(desc->res_key.key)); 401 fprintf(stdout, "All Target Ports (ALL_TG_PT): %d\n", 402 (desc->flags & SPRI_FULL_ALL_TG_PT) ? 1 : 0); 403 fprintf(stdout, "Reservation Holder (R_HOLDER): %d\n", 404 (desc->flags & SPRI_FULL_R_HOLDER) ? 1 : 0); 405 406 if (desc->flags & SPRI_FULL_R_HOLDER) 407 persist_print_scopetype(desc->scopetype); 408 409 if ((desc->flags & SPRI_FULL_ALL_TG_PT) == 0) 410 fprintf(stdout, "Relative Target Port ID: %#x\n", 411 scsi_2btoul(desc->rel_trgt_port_id)); 412 413 additional_length = scsi_4btoul(desc->additional_length); 414 415 persist_print_transportid(desc->transport_id, 416 additional_length); 417 418 cur_length = sizeof(*desc) + additional_length; 419 len_to_go -= cur_length; 420 cur_pos += cur_length; 421 } 422 } 423 424 int 425 scsipersist(struct cam_device *device, int argc, char **argv, char *combinedopt, 426 int task_attr, int retry_count, int timeout, int verbosemode, 427 int err_recover) 428 { 429 union ccb *ccb = NULL; 430 int c, in = 0, out = 0; 431 int action = -1, num_ids = 0; 432 int error = 0; 433 uint32_t res_len = 0; 434 unsigned long rel_tgt_port = 0; 435 uint8_t *res_buf = NULL; 436 int scope = SPR_LU_SCOPE, res_type = 0; 437 struct persist_transport_id *id, *id2; 438 STAILQ_HEAD(, persist_transport_id) transport_id_list; 439 uint64_t key = 0, sa_key = 0; 440 struct scsi_nv *table = NULL; 441 size_t table_size = 0, id_len = 0; 442 uint32_t valid_len = 0; 443 int all_tg_pt = 0, aptpl = 0, spec_i_pt = 0, unreg = 0,rel_port_set = 0; 444 445 STAILQ_INIT(&transport_id_list); 446 447 ccb = cam_getccb(device); 448 if (ccb == NULL) { 449 warnx("%s: error allocating CCB", __func__); 450 error = 1; 451 goto bailout; 452 } 453 454 while ((c = getopt(argc, argv, combinedopt)) != -1) { 455 switch (c) { 456 case 'a': 457 all_tg_pt = 1; 458 break; 459 case 'I': { 460 int error_str_len = 128; 461 char error_str[error_str_len]; 462 char *id_str; 463 464 id = malloc(sizeof(*id)); 465 if (id == NULL) { 466 warnx("%s: error allocating %zu bytes", 467 __func__, sizeof(*id)); 468 error = 1; 469 goto bailout; 470 } 471 bzero(id, sizeof(*id)); 472 473 id_str = strdup(optarg); 474 if (id_str == NULL) { 475 warnx("%s: error duplicating string %s", 476 __func__, optarg); 477 free(id); 478 error = 1; 479 goto bailout; 480 } 481 error = scsi_parse_transportid(id_str, &id->hdr, 482 &id->alloc_len, error_str, error_str_len); 483 if (error != 0) { 484 warnx("%s", error_str); 485 error = 1; 486 free(id); 487 free(id_str); 488 goto bailout; 489 } 490 free(id_str); 491 492 STAILQ_INSERT_TAIL(&transport_id_list, id, links); 493 num_ids++; 494 id_len += id->alloc_len; 495 break; 496 } 497 case 'k': 498 case 'K': { 499 char *endptr; 500 uint64_t tmpval; 501 502 tmpval = strtoumax(optarg, &endptr, 0); 503 if (*endptr != '\0') { 504 warnx("%s: invalid key argument %s", __func__, 505 optarg); 506 error = 1; 507 goto bailout; 508 } 509 if (c == 'k') { 510 key = tmpval; 511 } else { 512 sa_key = tmpval; 513 } 514 break; 515 } 516 case 'i': 517 case 'o': { 518 scsi_nv_status status; 519 int table_entry = 0; 520 521 if (c == 'i') { 522 in = 1; 523 table = persist_in_actions; 524 table_size = sizeof(persist_in_actions) / 525 sizeof(persist_in_actions[0]); 526 } else { 527 out = 1; 528 table = persist_out_actions; 529 table_size = sizeof(persist_out_actions) / 530 sizeof(persist_out_actions[0]); 531 } 532 533 if ((in + out) > 1) { 534 warnx("%s: only one in (-i) or out (-o) " 535 "action is allowed", __func__); 536 error = 1; 537 goto bailout; 538 } 539 540 status = scsi_get_nv(table, table_size, optarg, 541 &table_entry,SCSI_NV_FLAG_IG_CASE); 542 if (status == SCSI_NV_FOUND) 543 action = table[table_entry].value; 544 else { 545 warnx("%s: %s %s option %s", __func__, 546 (status == SCSI_NV_AMBIGUOUS) ? 547 "ambiguous" : "invalid", in ? "in" : 548 "out", optarg); 549 error = 1; 550 goto bailout; 551 } 552 break; 553 } 554 case 'p': 555 aptpl = 1; 556 break; 557 case 'R': { 558 char *endptr; 559 560 rel_tgt_port = strtoul(optarg, &endptr, 0); 561 if (*endptr != '\0') { 562 warnx("%s: invalid relative target port %s", 563 __func__, optarg); 564 error = 1; 565 goto bailout; 566 } 567 rel_port_set = 1; 568 break; 569 } 570 case 's': { 571 size_t scope_size; 572 struct scsi_nv *scope_table = NULL; 573 scsi_nv_status status; 574 int table_entry = 0; 575 char *endptr; 576 577 /* 578 * First check to see if the user gave us a numeric 579 * argument. If so, we'll try using it. 580 */ 581 if (isdigit(optarg[0])) { 582 scope = strtol(optarg, &endptr, 0); 583 if (*endptr != '\0') { 584 warnx("%s: invalid scope %s", 585 __func__, optarg); 586 error = 1; 587 goto bailout; 588 } 589 scope = (scope << SPR_SCOPE_SHIFT) & 590 SPR_SCOPE_MASK; 591 break; 592 } 593 594 scope_size = sizeof(persist_scope_table) / 595 sizeof(persist_scope_table[0]); 596 scope_table = persist_scope_table; 597 status = scsi_get_nv(scope_table, scope_size, optarg, 598 &table_entry,SCSI_NV_FLAG_IG_CASE); 599 if (status == SCSI_NV_FOUND) 600 scope = scope_table[table_entry].value; 601 else { 602 warnx("%s: %s scope %s", __func__, 603 (status == SCSI_NV_AMBIGUOUS) ? 604 "ambiguous" : "invalid", optarg); 605 error = 1; 606 goto bailout; 607 } 608 break; 609 } 610 case 'S': 611 spec_i_pt = 1; 612 break; 613 case 'T': { 614 size_t res_type_size; 615 struct scsi_nv *rtype_table = NULL; 616 scsi_nv_status status; 617 char *endptr; 618 int table_entry = 0; 619 620 /* 621 * First check to see if the user gave us a numeric 622 * argument. If so, we'll try using it. 623 */ 624 if (isdigit(optarg[0])) { 625 res_type = strtol(optarg, &endptr, 0); 626 if (*endptr != '\0') { 627 warnx("%s: invalid reservation type %s", 628 __func__, optarg); 629 error = 1; 630 goto bailout; 631 } 632 break; 633 } 634 635 res_type_size = sizeof(persist_type_table) / 636 sizeof(persist_type_table[0]); 637 rtype_table = persist_type_table; 638 status = scsi_get_nv(rtype_table, res_type_size, 639 optarg, &table_entry, 640 SCSI_NV_FLAG_IG_CASE); 641 if (status == SCSI_NV_FOUND) 642 res_type = rtype_table[table_entry].value; 643 else { 644 warnx("%s: %s reservation type %s", __func__, 645 (status == SCSI_NV_AMBIGUOUS) ? 646 "ambiguous" : "invalid", optarg); 647 error = 1; 648 goto bailout; 649 } 650 break; 651 } 652 case 'U': 653 unreg = 1; 654 break; 655 default: 656 break; 657 } 658 } 659 660 if ((in + out) != 1) { 661 warnx("%s: you must specify one of -i or -o", __func__); 662 error = 1; 663 goto bailout; 664 } 665 666 /* 667 * Note that we don't really try to figure out whether the user 668 * needs to specify one or both keys. There are a number of 669 * scenarios, and sometimes 0 is a valid and desired value. 670 */ 671 if (in != 0) { 672 switch (action) { 673 case SPRI_RK: 674 case SPRI_RR: 675 case SPRI_RS: 676 /* 677 * Allocate the maximum length possible for these 678 * service actions. According to the spec, the 679 * target is supposed to return the available 680 * length in the header, regardless of the 681 * allocation length. In practice, though, with 682 * the READ FULL STATUS (SPRI_RS) service action, 683 * some Seagate drives (in particular a 684 * Constellation ES, <SEAGATE ST32000444SS 0006>) 685 * don't return the available length if you only 686 * allocate the length of the header. So just 687 * allocate the maximum here so we don't miss 688 * anything. 689 */ 690 res_len = SPRI_MAX_LEN; 691 break; 692 case SPRI_RC: 693 res_len = sizeof(struct scsi_per_res_cap); 694 break; 695 default: 696 /* In theory we should catch this above */ 697 warnx("%s: invalid action %d", __func__, action); 698 error = 1; 699 goto bailout; 700 break; 701 } 702 } else { 703 704 /* 705 * XXX KDM need to add length for transport IDs for the 706 * register and move service action and the register 707 * service action with the SPEC_I_PT bit set. 708 */ 709 if (action == SPRO_REG_MOVE) { 710 if (num_ids != 1) { 711 warnx("%s: register and move requires a " 712 "single transport ID (-I)", __func__); 713 error = 1; 714 goto bailout; 715 } 716 if (rel_port_set == 0) { 717 warnx("%s: register and move requires a " 718 "relative target port (-R)", __func__); 719 error = 1; 720 goto bailout; 721 } 722 res_len = sizeof(struct scsi_per_res_reg_move) + id_len; 723 } else { 724 res_len = sizeof(struct scsi_per_res_out_parms); 725 if ((action == SPRO_REGISTER) 726 && (num_ids != 0)) { 727 /* 728 * If the user specifies any IDs with the 729 * register service action, turn on the 730 * spec_i_pt bit. 731 */ 732 spec_i_pt = 1; 733 res_len += id_len; 734 res_len += 735 sizeof(struct scsi_per_res_out_trans_ids); 736 } 737 } 738 } 739 retry: 740 if (res_buf != NULL) { 741 free(res_buf); 742 res_buf = NULL; 743 } 744 res_buf = malloc(res_len); 745 if (res_buf == NULL) { 746 warn("%s: error allocating %d bytes", __func__, res_len); 747 error = 1; 748 goto bailout; 749 } 750 bzero(res_buf, res_len); 751 752 if (in != 0) { 753 scsi_persistent_reserve_in(&ccb->csio, 754 /*retries*/ retry_count, 755 /*cbfcnp*/ NULL, 756 /*tag_action*/ task_attr, 757 /*service_action*/ action, 758 /*data_ptr*/ res_buf, 759 /*dxfer_len*/ res_len, 760 /*sense_len*/ SSD_FULL_SIZE, 761 /*timeout*/ timeout ? timeout :5000); 762 763 } else { 764 switch (action) { 765 case SPRO_REGISTER: 766 if (spec_i_pt != 0) { 767 struct scsi_per_res_out_trans_ids *id_hdr; 768 uint8_t *bufptr; 769 770 bufptr = res_buf + 771 sizeof(struct scsi_per_res_out_parms) + 772 sizeof(struct scsi_per_res_out_trans_ids); 773 STAILQ_FOREACH(id, &transport_id_list, links) { 774 bcopy(id->hdr, bufptr, id->alloc_len); 775 bufptr += id->alloc_len; 776 } 777 id_hdr = (struct scsi_per_res_out_trans_ids *) 778 (res_buf + 779 sizeof(struct scsi_per_res_out_parms)); 780 scsi_ulto4b(id_len, id_hdr->additional_length); 781 } 782 case SPRO_REG_IGNO: 783 case SPRO_PREEMPT: 784 case SPRO_PRE_ABO: 785 case SPRO_RESERVE: 786 case SPRO_RELEASE: 787 case SPRO_CLEAR: 788 case SPRO_REPL_LOST_RES: { 789 struct scsi_per_res_out_parms *parms; 790 791 parms = (struct scsi_per_res_out_parms *)res_buf; 792 793 scsi_u64to8b(key, parms->res_key.key); 794 scsi_u64to8b(sa_key, parms->serv_act_res_key); 795 if (spec_i_pt != 0) 796 parms->flags |= SPR_SPEC_I_PT; 797 if (all_tg_pt != 0) 798 parms->flags |= SPR_ALL_TG_PT; 799 if (aptpl != 0) 800 parms->flags |= SPR_APTPL; 801 break; 802 } 803 case SPRO_REG_MOVE: { 804 struct scsi_per_res_reg_move *reg_move; 805 uint8_t *bufptr; 806 807 reg_move = (struct scsi_per_res_reg_move *)res_buf; 808 809 scsi_u64to8b(key, reg_move->res_key.key); 810 scsi_u64to8b(sa_key, reg_move->serv_act_res_key); 811 if (unreg != 0) 812 reg_move->flags |= SPR_REG_MOVE_UNREG; 813 if (aptpl != 0) 814 reg_move->flags |= SPR_REG_MOVE_APTPL; 815 scsi_ulto2b(rel_tgt_port, reg_move->rel_trgt_port_id); 816 id = STAILQ_FIRST(&transport_id_list); 817 /* 818 * This shouldn't happen, since we already checked 819 * the number of IDs above. 820 */ 821 if (id == NULL) { 822 warnx("%s: No transport IDs found!", __func__); 823 error = 1; 824 goto bailout; 825 } 826 bufptr = (uint8_t *)®_move[1]; 827 bcopy(id->hdr, bufptr, id->alloc_len); 828 scsi_ulto4b(id->alloc_len, 829 reg_move->transport_id_length); 830 break; 831 } 832 default: 833 break; 834 } 835 scsi_persistent_reserve_out(&ccb->csio, 836 /*retries*/ retry_count, 837 /*cbfcnp*/ NULL, 838 /*tag_action*/ task_attr, 839 /*service_action*/ action, 840 /*scope*/ scope, 841 /*res_type*/ res_type, 842 /*data_ptr*/ res_buf, 843 /*dxfer_len*/ res_len, 844 /*sense_len*/ SSD_FULL_SIZE, 845 /*timeout*/ timeout ?timeout :5000); 846 } 847 848 /* Disable freezing the device queue */ 849 ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 850 851 if (err_recover != 0) 852 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; 853 854 if (cam_send_ccb(device, ccb) < 0) { 855 warn("error sending PERSISTENT RESERVE %s", (in != 0) ? 856 "IN" : "OUT"); 857 error = 1; 858 goto bailout; 859 } 860 861 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 862 if (verbosemode != 0) { 863 cam_error_print(device, ccb, CAM_ESF_ALL, 864 CAM_EPF_ALL, stderr); 865 } 866 error = 1; 867 goto bailout; 868 } 869 870 if (in == 0) 871 goto bailout; 872 873 valid_len = res_len - ccb->csio.resid; 874 875 switch (action) { 876 case SPRI_RK: 877 case SPRI_RR: 878 case SPRI_RS: { 879 struct scsi_per_res_in_header *hdr; 880 uint32_t hdr_len; 881 882 if (valid_len < sizeof(*hdr)) { 883 warnx("%s: only got %d valid bytes, need %zd", 884 __func__, valid_len, sizeof(*hdr)); 885 error = 1; 886 goto bailout; 887 } 888 hdr = (struct scsi_per_res_in_header *)res_buf; 889 hdr_len = scsi_4btoul(hdr->length); 890 891 if (hdr_len > (res_len - sizeof(*hdr))) { 892 res_len = hdr_len + sizeof(*hdr); 893 goto retry; 894 } 895 896 if (action == SPRI_RK) { 897 persist_print_keys(hdr, valid_len); 898 } else if (action == SPRI_RR) { 899 persist_print_res(hdr, valid_len); 900 } else { 901 persist_print_full(hdr, valid_len); 902 } 903 break; 904 } 905 case SPRI_RC: { 906 struct scsi_per_res_cap *cap; 907 uint32_t cap_len; 908 909 if (valid_len < sizeof(*cap)) { 910 warnx("%s: only got %u valid bytes, need %zd", 911 __func__, valid_len, sizeof(*cap)); 912 error = 1; 913 goto bailout; 914 } 915 cap = (struct scsi_per_res_cap *)res_buf; 916 cap_len = scsi_2btoul(cap->length); 917 if (cap_len != sizeof(*cap)) { 918 /* 919 * We should be able to deal with this, 920 * it's just more trouble. 921 */ 922 warnx("%s: reported size %u is different " 923 "than expected size %zd", __func__, 924 cap_len, sizeof(*cap)); 925 } 926 927 /* 928 * If there is more data available, grab it all, 929 * even though we don't really know what to do with 930 * the extra data since it obviously wasn't in the 931 * spec when this code was written. 932 */ 933 if (cap_len > res_len) { 934 res_len = cap_len; 935 goto retry; 936 } 937 persist_print_cap(cap, valid_len); 938 break; 939 } 940 default: 941 break; 942 } 943 944 bailout: 945 free(res_buf); 946 947 if (ccb != NULL) 948 cam_freeccb(ccb); 949 950 STAILQ_FOREACH_SAFE(id, &transport_id_list, links, id2) { 951 STAILQ_REMOVE(&transport_id_list, id, persist_transport_id, 952 links); 953 free(id); 954 } 955 return (error); 956 } 957