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