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$"); 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 66 struct 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 */ 75 static 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 */ 85 static 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 */ 101 static 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 */ 113 static 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 */ 134 static void 135 persist_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 155 static void 156 persist_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 */ 177 static void 178 persist_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 */ 213 static void 214 persist_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 */ 239 static void 240 persist_print_cap(struct scsi_per_res_cap *cap, uint32_t valid_len) 241 { 242 uint32_t length; 243 int check_type_mask = 0; 244 uint32_t type_mask; 245 246 length = scsi_2btoul(cap->length); 247 length = MIN(length, valid_len); 248 type_mask = scsi_2btoul(cap->type_mask); 249 250 if (length < __offsetof(struct scsi_per_res_cap, type_mask)) { 251 fprintf(stdout, "Insufficient data (%u bytes) to report " 252 "full capabilities\n", length); 253 return; 254 } 255 if (length >= __offsetof(struct scsi_per_res_cap, reserved)) 256 check_type_mask = 1; 257 258 fprintf(stdout, "Replace Lost Reservation Capable (RLR_C): %d\n", 259 (cap->flags1 & SPRI_RLR_C) ? 1 : 0); 260 fprintf(stdout, "Compatible Reservation Handling (CRH): %d\n", 261 (cap->flags1 & SPRI_CRH) ? 1 : 0); 262 fprintf(stdout, "Specify Initiator Ports Capable (SIP_C): %d\n", 263 (cap->flags1 & SPRI_SIP_C) ? 1 : 0); 264 fprintf(stdout, "All Target Ports Capable (ATP_C): %d\n", 265 (cap->flags1 & SPRI_ATP_C) ? 1 : 0); 266 fprintf(stdout, "Persist Through Power Loss Capable (PTPL_C): %d\n", 267 (cap->flags1 & SPRI_PTPL_C) ? 1 : 0); 268 fprintf(stdout, "ALLOW COMMANDS field: (%#x)\n", 269 (cap->flags2 & SPRI_ALLOW_CMD_MASK) >> SPRI_ALLOW_CMD_SHIFT); 270 /* 271 * These cases are cut-and-pasted from SPC4r36l. There is no 272 * succinct way to describe these otherwise, and even with the 273 * verbose description, the user will probably have to refer to 274 * the spec to fully understand what is going on. 275 */ 276 switch (cap->flags2 & SPRI_ALLOW_CMD_MASK) { 277 case SPRI_ALLOW_1: 278 fprintf(stdout, 279 " The device server allows the TEST UNIT READY command through Write\n" 280 " Exclusive type reservations and Exclusive Access type reservations\n" 281 " and does not provide information about whether the following commands\n" 282 " are allowed through Write Exclusive type reservations:\n" 283 " a) the MODE SENSE command, READ ATTRIBUTE command, READ BUFFER\n" 284 " command, RECEIVE COPY RESULTS command, RECEIVE DIAGNOSTIC\n" 285 " RESULTS command, REPORT SUPPORTED OPERATION CODES command,\n" 286 " and REPORT SUPPORTED TASK MANAGEMENT FUNCTION command; and\n" 287 " b) the READ DEFECT DATA command (see SBC-3).\n"); 288 break; 289 case SPRI_ALLOW_2: 290 fprintf(stdout, 291 " The device server allows the TEST UNIT READY command through Write\n" 292 " Exclusive type reservations and Exclusive Access type reservations\n" 293 " and does not allow the following commands through Write Exclusive type\n" 294 " reservations:\n" 295 " a) the MODE SENSE command, READ ATTRIBUTE command, READ BUFFER\n" 296 " command, RECEIVE DIAGNOSTIC RESULTS command, REPORT SUPPORTED\n" 297 " OPERATION CODES command, and REPORT SUPPORTED TASK MANAGEMENT\n" 298 " FUNCTION command; and\n" 299 " b) the READ DEFECT DATA command.\n" 300 " The device server does not allow the RECEIVE COPY RESULTS command\n" 301 " through Write Exclusive type reservations or Exclusive Access type\n" 302 " reservations.\n"); 303 break; 304 case SPRI_ALLOW_3: 305 fprintf(stdout, 306 " The device server allows the TEST UNIT READY command through Write\n" 307 " Exclusive type reservations and Exclusive Access type reservations\n" 308 " and allows the following commands through Write Exclusive type\n" 309 " reservations:\n" 310 " a) the MODE SENSE command, READ ATTRIBUTE command, READ BUFFER\n" 311 " command, RECEIVE DIAGNOSTIC RESULTS command, REPORT SUPPORTED\n" 312 " OPERATION CODES command, and REPORT SUPPORTED TASK MANAGEMENT\n" 313 " FUNCTION command; and\n" 314 " b) the READ DEFECT DATA command.\n" 315 " The device server does not allow the RECEIVE COPY RESULTS command\n" 316 " through Write Exclusive type reservations or Exclusive Access type\n" 317 " reservations.\n"); 318 break; 319 case SPRI_ALLOW_4: 320 fprintf(stdout, 321 " The device server allows the TEST UNIT READY command and the RECEIVE\n" 322 " COPY RESULTS command through Write Exclusive type reservations and\n" 323 " Exclusive Access type reservations and allows the following commands\n" 324 " through Write Exclusive type reservations:\n" 325 " a) the MODE SENSE command, READ ATTRIBUTE command, READ BUFFER\n" 326 " command, RECEIVE DIAGNOSTIC RESULTS command, REPORT SUPPORTED\n" 327 " OPERATION CODES command, and REPORT SUPPORTED TASK MANAGEMENT\n" 328 " FUNCTION command; and\n" 329 " b) the READ DEFECT DATA command.\n"); 330 break; 331 case SPRI_ALLOW_NA: 332 fprintf(stdout, 333 " No information is provided about whether certain commands are allowed\n" 334 " through certain types of persistent reservations.\n"); 335 break; 336 default: 337 fprintf(stdout, 338 " Unknown ALLOW COMMANDS value %#x\n", 339 (cap->flags2 & SPRI_ALLOW_CMD_MASK) >> 340 SPRI_ALLOW_CMD_SHIFT); 341 break; 342 } 343 fprintf(stdout, "Persist Through Power Loss Activated (PTPL_A): %d\n", 344 (cap->flags2 & SPRI_PTPL_A) ? 1 : 0); 345 if ((check_type_mask != 0) 346 && (cap->flags2 & SPRI_TMV)) { 347 fprintf(stdout, "Supported Persistent Reservation Types:\n"); 348 fprintf(stdout, " Write Exclusive - All Registrants " 349 "(WR_EX_AR): %d\n", 350 (type_mask & SPRI_TM_WR_EX_AR)? 1 : 0); 351 fprintf(stdout, " Exclusive Access - Registrants Only " 352 "(EX_AC_RO): %d\n", 353 (type_mask & SPRI_TM_EX_AC_RO) ? 1 : 0); 354 fprintf(stdout, " Write Exclusive - Registrants Only " 355 "(WR_EX_RO): %d\n", 356 (type_mask & SPRI_TM_WR_EX_RO)? 1 : 0); 357 fprintf(stdout, " Exclusive Access (EX_AC): %d\n", 358 (type_mask & SPRI_TM_EX_AC) ? 1 : 0); 359 fprintf(stdout, " Write Exclusive (WR_EX): %d\n", 360 (type_mask & SPRI_TM_WR_EX) ? 1 : 0); 361 fprintf(stdout, " Exclusive Access - All Registrants " 362 "(EX_AC_AR): %d\n", 363 (type_mask & SPRI_TM_EX_AC_AR) ? 1 : 0); 364 } else { 365 fprintf(stdout, "Persistent Reservation Type Mask is NOT " 366 "valid\n"); 367 } 368 369 370 } 371 372 static void 373 persist_print_full(struct scsi_per_res_in_header *hdr, uint32_t valid_len) 374 { 375 uint32_t length, len_to_go = 0; 376 struct scsi_per_res_in_full_desc *desc; 377 uint8_t *cur_pos; 378 int i; 379 380 length = scsi_4btoul(hdr->length); 381 length = MIN(length, valid_len); 382 383 if (length < sizeof(*desc)) { 384 if (length == 0) 385 fprintf(stdout, "No reservations.\n"); 386 else 387 warnx("unable to print reservation, only got %u " 388 "valid bytes", length); 389 return; 390 } 391 392 fprintf(stdout, "PRgeneration: %#x\n", scsi_4btoul(hdr->generation)); 393 cur_pos = (uint8_t *)&hdr[1]; 394 for (len_to_go = length, i = 0, 395 desc = (struct scsi_per_res_in_full_desc *)cur_pos; 396 len_to_go >= sizeof(*desc); 397 desc = (struct scsi_per_res_in_full_desc *)cur_pos, i++) { 398 uint32_t additional_length, cur_length; 399 400 401 fprintf(stdout, "Reservation Key: %#jx\n", 402 (uintmax_t)scsi_8btou64(desc->res_key.key)); 403 fprintf(stdout, "All Target Ports (ALL_TG_PT): %d\n", 404 (desc->flags & SPRI_FULL_ALL_TG_PT) ? 1 : 0); 405 fprintf(stdout, "Reservation Holder (R_HOLDER): %d\n", 406 (desc->flags & SPRI_FULL_R_HOLDER) ? 1 : 0); 407 408 if (desc->flags & SPRI_FULL_R_HOLDER) 409 persist_print_scopetype(desc->scopetype); 410 411 if ((desc->flags & SPRI_FULL_ALL_TG_PT) == 0) 412 fprintf(stdout, "Relative Target Port ID: %#x\n", 413 scsi_2btoul(desc->rel_trgt_port_id)); 414 415 additional_length = scsi_4btoul(desc->additional_length); 416 417 persist_print_transportid(desc->transport_id, 418 additional_length); 419 420 cur_length = sizeof(*desc) + additional_length; 421 len_to_go -= cur_length; 422 cur_pos += cur_length; 423 } 424 } 425 426 int 427 scsipersist(struct cam_device *device, int argc, char **argv, char *combinedopt, 428 int retry_count, int timeout, int verbosemode, int err_recover) 429 { 430 union ccb *ccb = NULL; 431 int c, in = 0, out = 0; 432 int action = -1, num_ids = 0; 433 int error = 0; 434 uint32_t res_len = 0; 435 unsigned long rel_tgt_port = 0; 436 uint8_t *res_buf = NULL; 437 int scope = SPR_LU_SCOPE, res_type = 0; 438 struct persist_transport_id *id, *id2; 439 STAILQ_HEAD(, persist_transport_id) transport_id_list; 440 uint64_t key = 0, sa_key = 0; 441 struct scsi_nv *table = NULL; 442 size_t table_size = 0, id_len = 0; 443 uint32_t valid_len = 0; 444 int all_tg_pt = 0, aptpl = 0, spec_i_pt = 0, unreg = 0,rel_port_set = 0; 445 446 STAILQ_INIT(&transport_id_list); 447 448 ccb = cam_getccb(device); 449 if (ccb == NULL) { 450 warnx("%s: error allocating CCB", __func__); 451 error = 1; 452 goto bailout; 453 } 454 455 CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio); 456 457 while ((c = getopt(argc, argv, combinedopt)) != -1) { 458 switch (c) { 459 case 'a': 460 all_tg_pt = 1; 461 break; 462 case 'I': { 463 int error_str_len = 128; 464 char error_str[error_str_len]; 465 char *id_str; 466 467 id = malloc(sizeof(*id)); 468 if (id == NULL) { 469 warnx("%s: error allocating %zu bytes", 470 __func__, sizeof(*id)); 471 error = 1; 472 goto bailout; 473 } 474 bzero(id, sizeof(*id)); 475 476 id_str = strdup(optarg); 477 if (id_str == NULL) { 478 warnx("%s: error duplicating string %s", 479 __func__, optarg); 480 free(id); 481 error = 1; 482 goto bailout; 483 } 484 error = scsi_parse_transportid(id_str, &id->hdr, 485 &id->alloc_len, error_str, error_str_len); 486 if (error != 0) { 487 warnx("%s", error_str); 488 error = 1; 489 free(id); 490 free(id_str); 491 goto bailout; 492 } 493 free(id_str); 494 495 STAILQ_INSERT_TAIL(&transport_id_list, id, links); 496 num_ids++; 497 id_len += id->alloc_len; 498 break; 499 } 500 case 'k': 501 case 'K': { 502 char *endptr; 503 uint64_t tmpval; 504 505 tmpval = strtoumax(optarg, &endptr, 0); 506 if (*endptr != '\0') { 507 warnx("%s: invalid key argument %s", __func__, 508 optarg); 509 error = 1; 510 goto bailout; 511 } 512 if (c == 'k') { 513 key = tmpval; 514 } else { 515 sa_key = tmpval; 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 } 742 retry: 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 953 bailout: 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