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 64struct 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 */ 73static 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 */ 83static 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 */ 99static 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 */ 111static 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 */ 132static void 133persist_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 153static void 154persist_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 */ 175static void 176persist_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 */ 211static void 212persist_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 */ 237static void 238persist_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 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 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 } 739retry: 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 944bailout: 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