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