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