persist.c revision 314221
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 314221 2017-02-24 20:51:39Z ken $"); 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 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, key_set = 0, sa_key_set = 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 CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio); 455 456 while ((c = getopt(argc, argv, combinedopt)) != -1) { 457 switch (c) { 458 case 'a': 459 all_tg_pt = 1; 460 break; 461 case 'I': { 462 int error_str_len = 128; 463 char error_str[error_str_len]; 464 char *id_str; 465 466 id = malloc(sizeof(*id)); 467 if (id == NULL) { 468 warnx("%s: error allocating %zu bytes", 469 __func__, sizeof(*id)); 470 error = 1; 471 goto bailout; 472 } 473 bzero(id, sizeof(*id)); 474 475 id_str = strdup(optarg); 476 if (id_str == NULL) { 477 warnx("%s: error duplicating string %s", 478 __func__, optarg); 479 free(id); 480 error = 1; 481 goto bailout; 482 } 483 error = scsi_parse_transportid(id_str, &id->hdr, 484 &id->alloc_len, error_str, error_str_len); 485 if (error != 0) { 486 warnx("%s", error_str); 487 error = 1; 488 free(id); 489 free(id_str); 490 goto bailout; 491 } 492 free(id_str); 493 494 STAILQ_INSERT_TAIL(&transport_id_list, id, links); 495 num_ids++; 496 id_len += id->alloc_len; 497 break; 498 } 499 case 'k': 500 case 'K': { 501 char *endptr; 502 uint64_t tmpval; 503 504 tmpval = strtoumax(optarg, &endptr, 0); 505 if (*endptr != '\0') { 506 warnx("%s: invalid key argument %s", __func__, 507 optarg); 508 error = 1; 509 goto bailout; 510 } 511 if (c == 'k') { 512 key = tmpval; 513 key_set = 1; 514 } else { 515 sa_key = tmpval; 516 sa_key_set = 1; 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 862 if (verbosemode != 0) { 863 cam_error_print(device, ccb, CAM_ESF_ALL, 864 CAM_EPF_ALL, stderr); 865 } 866 867 error = 1; 868 goto bailout; 869 } 870 871 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 872 if (verbosemode != 0) { 873 cam_error_print(device, ccb, CAM_ESF_ALL, 874 CAM_EPF_ALL, stderr); 875 } 876 error = 1; 877 goto bailout; 878 } 879 880 if (in == 0) 881 goto bailout; 882 883 valid_len = res_len - ccb->csio.resid; 884 885 switch (action) { 886 case SPRI_RK: 887 case SPRI_RR: 888 case SPRI_RS: { 889 struct scsi_per_res_in_header *hdr; 890 uint32_t hdr_len; 891 892 if (valid_len < sizeof(*hdr)) { 893 warnx("%s: only got %d valid bytes, need %zd", 894 __func__, valid_len, sizeof(*hdr)); 895 error = 1; 896 goto bailout; 897 } 898 hdr = (struct scsi_per_res_in_header *)res_buf; 899 hdr_len = scsi_4btoul(hdr->length); 900 901 if (hdr_len > (res_len - sizeof(*hdr))) { 902 res_len = hdr_len + sizeof(*hdr); 903 goto retry; 904 } 905 906 if (action == SPRI_RK) { 907 persist_print_keys(hdr, valid_len); 908 } else if (action == SPRI_RR) { 909 persist_print_res(hdr, valid_len); 910 } else { 911 persist_print_full(hdr, valid_len); 912 } 913 break; 914 } 915 case SPRI_RC: { 916 struct scsi_per_res_cap *cap; 917 uint32_t cap_len; 918 919 if (valid_len < sizeof(*cap)) { 920 warnx("%s: only got %u valid bytes, need %zd", 921 __func__, valid_len, sizeof(*cap)); 922 error = 1; 923 goto bailout; 924 } 925 cap = (struct scsi_per_res_cap *)res_buf; 926 cap_len = scsi_2btoul(cap->length); 927 if (cap_len != sizeof(*cap)) { 928 /* 929 * We should be able to deal with this, 930 * it's just more trouble. 931 */ 932 warnx("%s: reported size %u is different " 933 "than expected size %zd", __func__, 934 cap_len, sizeof(*cap)); 935 } 936 937 /* 938 * If there is more data available, grab it all, 939 * even though we don't really know what to do with 940 * the extra data since it obviously wasn't in the 941 * spec when this code was written. 942 */ 943 if (cap_len > res_len) { 944 res_len = cap_len; 945 goto retry; 946 } 947 persist_print_cap(cap, valid_len); 948 break; 949 } 950 default: 951 break; 952 } 953 954bailout: 955 free(res_buf); 956 957 if (ccb != NULL) 958 cam_freeccb(ccb); 959 960 STAILQ_FOREACH_SAFE(id, &transport_id_list, links, id2) { 961 STAILQ_REMOVE(&transport_id_list, id, persist_transport_id, 962 links); 963 free(id); 964 } 965 return (error); 966} 967