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