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