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 task_attr, int retry_count, int timeout, int verbosemode, 429 int err_recover) 430 { 431 union ccb *ccb = NULL; 432 int c, in = 0, out = 0; 433 int action = -1, num_ids = 0; 434 int error = 0; 435 uint32_t res_len = 0; 436 unsigned long rel_tgt_port = 0; 437 uint8_t *res_buf = NULL; 438 int scope = SPR_LU_SCOPE, res_type = 0; 439 struct persist_transport_id *id, *id2; 440 STAILQ_HEAD(, persist_transport_id) transport_id_list; 441 uint64_t key = 0, sa_key = 0; 442 struct scsi_nv *table = NULL; 443 size_t table_size = 0, id_len = 0; 444 uint32_t valid_len = 0; 445 int all_tg_pt = 0, aptpl = 0, spec_i_pt = 0, unreg = 0,rel_port_set = 0; 446 447 STAILQ_INIT(&transport_id_list); 448 449 ccb = cam_getccb(device); 450 if (ccb == NULL) { 451 warnx("%s: error allocating CCB", __func__); 452 error = 1; 453 goto bailout; 454 } 455 456 CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio); 457 458 while ((c = getopt(argc, argv, combinedopt)) != -1) { 459 switch (c) { 460 case 'a': 461 all_tg_pt = 1; 462 break; 463 case 'I': { 464 int error_str_len = 128; 465 char error_str[error_str_len]; 466 char *id_str; 467 468 id = malloc(sizeof(*id)); 469 if (id == NULL) { 470 warnx("%s: error allocating %zu bytes", 471 __func__, sizeof(*id)); 472 error = 1; 473 goto bailout; 474 } 475 bzero(id, sizeof(*id)); 476 477 id_str = strdup(optarg); 478 if (id_str == NULL) { 479 warnx("%s: error duplicating string %s", 480 __func__, optarg); 481 free(id); 482 error = 1; 483 goto bailout; 484 } 485 error = scsi_parse_transportid(id_str, &id->hdr, 486 &id->alloc_len, error_str, error_str_len); 487 if (error != 0) { 488 warnx("%s", error_str); 489 error = 1; 490 free(id); 491 free(id_str); 492 goto bailout; 493 } 494 free(id_str); 495 496 STAILQ_INSERT_TAIL(&transport_id_list, id, links); 497 num_ids++; 498 id_len += id->alloc_len; 499 break; 500 } 501 case 'k': 502 case 'K': { 503 char *endptr; 504 uint64_t tmpval; 505 506 tmpval = strtoumax(optarg, &endptr, 0); 507 if (*endptr != '\0') { 508 warnx("%s: invalid key argument %s", __func__, 509 optarg); 510 error = 1; 511 goto bailout; 512 } 513 if (c == 'k') { 514 key = tmpval; 515 } else { 516 sa_key = tmpval; 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 } 743 retry: 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 954 bailout: 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