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