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 #include <sys/ioctl.h>
38 #include <sys/stdint.h>
39 #include <sys/types.h>
40 #include <sys/endian.h>
41 #include <sys/sbuf.h>
42 #include <sys/queue.h>
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <inttypes.h>
47 #include <unistd.h>
48 #include <string.h>
49 #include <strings.h>
50 #include <fcntl.h>
51 #include <ctype.h>
52 #include <limits.h>
53 #include <err.h>
54
55 #include <cam/cam.h>
56 #include <cam/cam_debug.h>
57 #include <cam/cam_ccb.h>
58 #include <cam/scsi/scsi_all.h>
59 #include <cam/scsi/scsi_pass.h>
60 #include <cam/scsi/scsi_message.h>
61 #include <camlib.h>
62 #include "camcontrol.h"
63
64 struct persist_transport_id {
65 struct scsi_transportid_header *hdr;
66 unsigned int alloc_len;
67 STAILQ_ENTRY(persist_transport_id) links;
68 };
69
70 /*
71 * Service Actions for PERSISTENT RESERVE IN.
72 */
73 static struct scsi_nv persist_in_actions[] = {
74 { "read_keys", SPRI_RK },
75 { "read_reservation", SPRI_RR },
76 { "report_capabilities", SPRI_RC },
77 { "read_full_status", SPRI_RS }
78 };
79
80 /*
81 * Service Actions for PERSISTENT RESERVE OUT.
82 */
83 static struct scsi_nv persist_out_actions[] = {
84 { "register", SPRO_REGISTER },
85 { "reserve", SPRO_RESERVE },
86 { "release" , SPRO_RELEASE },
87 { "clear", SPRO_CLEAR },
88 { "preempt", SPRO_PREEMPT },
89 { "preempt_abort", SPRO_PRE_ABO },
90 { "register_ignore", SPRO_REG_IGNO },
91 { "register_move", SPRO_REG_MOVE },
92 { "replace_lost", SPRO_REPL_LOST_RES }
93 };
94
95 /*
96 * Known reservation scopes. As of SPC-4, only LU_SCOPE is used in the
97 * spec. The others are obsolete.
98 */
99 static struct scsi_nv persist_scope_table[] = {
100 { "lun", SPR_LU_SCOPE },
101 { "extent", SPR_EXTENT_SCOPE },
102 { "element", SPR_ELEMENT_SCOPE }
103 };
104
105 /*
106 * Reservation types. The longer name for a given reservation type is
107 * listed first, so that it makes more sense when we print out the
108 * reservation type. We step through the table linearly when looking for
109 * the text name for a particular numeric reservation type value.
110 */
111 static struct scsi_nv persist_type_table[] = {
112 { "read_shared", SPR_TYPE_RD_SHARED },
113 { "write_exclusive", SPR_TYPE_WR_EX },
114 { "wr_ex", SPR_TYPE_WR_EX },
115 { "read_exclusive", SPR_TYPE_RD_EX },
116 { "rd_ex", SPR_TYPE_RD_EX },
117 { "exclusive_access", SPR_TYPE_EX_AC },
118 { "ex_ac", SPR_TYPE_EX_AC },
119 { "write_exclusive_reg_only", SPR_TYPE_WR_EX_RO },
120 { "wr_ex_ro", SPR_TYPE_WR_EX_RO },
121 { "exclusive_access_reg_only", SPR_TYPE_EX_AC_RO },
122 { "ex_ac_ro", SPR_TYPE_EX_AC_RO },
123 { "write_exclusive_all_regs", SPR_TYPE_WR_EX_AR },
124 { "wr_ex_ar", SPR_TYPE_WR_EX_AR },
125 { "exclusive_access_all_regs", SPR_TYPE_EX_AC_AR },
126 { "ex_ac_ar", SPR_TYPE_EX_AC_AR }
127 };
128
129 /*
130 * Print out the standard scope/type field.
131 */
132 static void
persist_print_scopetype(uint8_t scopetype)133 persist_print_scopetype(uint8_t scopetype)
134 {
135 const char *tmpstr;
136 int num_entries;
137
138 num_entries = sizeof(persist_scope_table) /
139 sizeof(persist_scope_table[0]);
140 tmpstr = scsi_nv_to_str(persist_scope_table, num_entries,
141 scopetype & SPR_SCOPE_MASK);
142 fprintf(stdout, "Scope: %s (%#x)\n", (tmpstr != NULL) ? tmpstr :
143 "Unknown", (scopetype & SPR_SCOPE_MASK) >> SPR_SCOPE_SHIFT);
144
145 num_entries = sizeof(persist_type_table) /
146 sizeof(persist_type_table[0]);
147 tmpstr = scsi_nv_to_str(persist_type_table, num_entries,
148 scopetype & SPR_TYPE_MASK);
149 fprintf(stdout, "Type: %s (%#x)\n", (tmpstr != NULL) ? tmpstr :
150 "Unknown", scopetype & SPR_TYPE_MASK);
151 }
152
153 static void
persist_print_transportid(uint8_t * buf,uint32_t len)154 persist_print_transportid(uint8_t *buf, uint32_t len)
155 {
156 struct sbuf *sb;
157
158 sb = sbuf_new_auto();
159 if (sb == NULL)
160 fprintf(stderr, "Unable to allocate sbuf\n");
161
162 scsi_transportid_sbuf(sb, (struct scsi_transportid_header *)buf, len);
163
164 sbuf_finish(sb);
165
166 fprintf(stdout, "%s\n", sbuf_data(sb));
167
168 sbuf_delete(sb);
169 }
170
171 /*
172 * Print out a persistent reservation. This is used with the READ
173 * RESERVATION (0x01) service action of the PERSISTENT RESERVE IN command.
174 */
175 static void
persist_print_res(struct scsi_per_res_in_header * hdr,uint32_t valid_len)176 persist_print_res(struct scsi_per_res_in_header *hdr, uint32_t valid_len)
177 {
178 uint32_t length;
179 struct scsi_per_res_in_rsrv *res;
180
181 length = scsi_4btoul(hdr->length);
182 length = MIN(length, valid_len);
183
184 res = (struct scsi_per_res_in_rsrv *)hdr;
185
186 if (length < sizeof(res->data) - sizeof(res->data.extent_length)) {
187 if (length == 0)
188 fprintf(stdout, "No reservations.\n");
189 else
190 warnx("unable to print reservation, only got %u "
191 "valid bytes", length);
192 return;
193 }
194 fprintf(stdout, "PRgeneration: %#x\n",
195 scsi_4btoul(res->header.generation));
196 fprintf(stdout, "Reservation Key: %#jx\n",
197 (uintmax_t)scsi_8btou64(res->data.reservation));
198 fprintf(stdout, "Scope address: %#x\n",
199 scsi_4btoul(res->data.scope_addr));
200
201 persist_print_scopetype(res->data.scopetype);
202
203 fprintf(stdout, "Extent length: %u\n",
204 scsi_2btoul(res->data.extent_length));
205 }
206
207 /*
208 * Print out persistent reservation keys. This is used with the READ KEYS
209 * service action of the PERSISTENT RESERVE IN command.
210 */
211 static void
persist_print_keys(struct scsi_per_res_in_header * hdr,uint32_t valid_len)212 persist_print_keys(struct scsi_per_res_in_header *hdr, uint32_t valid_len)
213 {
214 uint32_t length, num_keys, i;
215 struct scsi_per_res_key *key;
216
217 length = scsi_4btoul(hdr->length);
218 length = MIN(length, valid_len);
219
220 num_keys = length / sizeof(*key);
221
222 fprintf(stdout, "PRgeneration: %#x\n", scsi_4btoul(hdr->generation));
223 fprintf(stdout, "%u key%s%s\n", num_keys, (num_keys == 1) ? "" : "s",
224 (num_keys == 0) ? "." : ":");
225
226 for (i = 0, key = (struct scsi_per_res_key *)&hdr[1]; i < num_keys;
227 i++, key++) {
228 fprintf(stdout, "%u: %#jx\n", i,
229 (uintmax_t)scsi_8btou64(key->key));
230 }
231 }
232
233 /*
234 * Print out persistent reservation capabilities. This is used with the
235 * REPORT CAPABILITIES service action of the PERSISTENT RESERVE IN command.
236 */
237 static void
persist_print_cap(struct scsi_per_res_cap * cap,uint32_t valid_len)238 persist_print_cap(struct scsi_per_res_cap *cap, uint32_t valid_len)
239 {
240 uint32_t length;
241 int check_type_mask = 0;
242 uint32_t type_mask;
243
244 length = scsi_2btoul(cap->length);
245 length = MIN(length, valid_len);
246 type_mask = scsi_2btoul(cap->type_mask);
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 (type_mask & SPRI_TM_WR_EX_AR)? 1 : 0);
349 fprintf(stdout, " Exclusive Access - Registrants Only "
350 "(EX_AC_RO): %d\n",
351 (type_mask & SPRI_TM_EX_AC_RO) ? 1 : 0);
352 fprintf(stdout, " Write Exclusive - Registrants Only "
353 "(WR_EX_RO): %d\n",
354 (type_mask & SPRI_TM_WR_EX_RO)? 1 : 0);
355 fprintf(stdout, " Exclusive Access (EX_AC): %d\n",
356 (type_mask & SPRI_TM_EX_AC) ? 1 : 0);
357 fprintf(stdout, " Write Exclusive (WR_EX): %d\n",
358 (type_mask & SPRI_TM_WR_EX) ? 1 : 0);
359 fprintf(stdout, " Exclusive Access - All Registrants "
360 "(EX_AC_AR): %d\n",
361 (type_mask & 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
persist_print_full(struct scsi_per_res_in_header * hdr,uint32_t valid_len)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
scsipersist(struct cam_device * device,int argc,char ** argv,char * combinedopt,int task_attr,int retry_count,int timeout,int verbosemode,int err_recover)425 scsipersist(struct cam_device *device, int argc, char **argv, char *combinedopt,
426 int task_attr, int retry_count, int timeout, int verbosemode,
427 int err_recover)
428 {
429 union ccb *ccb = NULL;
430 int c, in = 0, out = 0;
431 int action = -1, num_ids = 0;
432 int error = 0;
433 uint32_t res_len = 0;
434 unsigned long rel_tgt_port = 0;
435 uint8_t *res_buf = NULL;
436 int scope = SPR_LU_SCOPE, res_type = 0;
437 struct persist_transport_id *id, *id2;
438 STAILQ_HEAD(, persist_transport_id) transport_id_list;
439 uint64_t key = 0, sa_key = 0;
440 struct scsi_nv *table = NULL;
441 size_t table_size = 0, id_len = 0;
442 uint32_t valid_len = 0;
443 int all_tg_pt = 0, aptpl = 0, spec_i_pt = 0, unreg = 0,rel_port_set = 0;
444
445 STAILQ_INIT(&transport_id_list);
446
447 ccb = cam_getccb(device);
448 if (ccb == NULL) {
449 warnx("%s: error allocating CCB", __func__);
450 error = 1;
451 goto bailout;
452 }
453
454 while ((c = getopt(argc, argv, combinedopt)) != -1) {
455 switch (c) {
456 case 'a':
457 all_tg_pt = 1;
458 break;
459 case 'I': {
460 int error_str_len = 128;
461 char error_str[error_str_len];
462 char *id_str;
463
464 id = malloc(sizeof(*id));
465 if (id == NULL) {
466 warnx("%s: error allocating %zu bytes",
467 __func__, sizeof(*id));
468 error = 1;
469 goto bailout;
470 }
471 bzero(id, sizeof(*id));
472
473 id_str = strdup(optarg);
474 if (id_str == NULL) {
475 warnx("%s: error duplicating string %s",
476 __func__, optarg);
477 free(id);
478 error = 1;
479 goto bailout;
480 }
481 error = scsi_parse_transportid(id_str, &id->hdr,
482 &id->alloc_len, error_str, error_str_len);
483 if (error != 0) {
484 warnx("%s", error_str);
485 error = 1;
486 free(id);
487 free(id_str);
488 goto bailout;
489 }
490 free(id_str);
491
492 STAILQ_INSERT_TAIL(&transport_id_list, id, links);
493 num_ids++;
494 id_len += id->alloc_len;
495 break;
496 }
497 case 'k':
498 case 'K': {
499 char *endptr;
500 uint64_t tmpval;
501
502 tmpval = strtoumax(optarg, &endptr, 0);
503 if (*endptr != '\0') {
504 warnx("%s: invalid key argument %s", __func__,
505 optarg);
506 error = 1;
507 goto bailout;
508 }
509 if (c == 'k') {
510 key = tmpval;
511 } else {
512 sa_key = tmpval;
513 }
514 break;
515 }
516 case 'i':
517 case 'o': {
518 scsi_nv_status status;
519 int table_entry = 0;
520
521 if (c == 'i') {
522 in = 1;
523 table = persist_in_actions;
524 table_size = sizeof(persist_in_actions) /
525 sizeof(persist_in_actions[0]);
526 } else {
527 out = 1;
528 table = persist_out_actions;
529 table_size = sizeof(persist_out_actions) /
530 sizeof(persist_out_actions[0]);
531 }
532
533 if ((in + out) > 1) {
534 warnx("%s: only one in (-i) or out (-o) "
535 "action is allowed", __func__);
536 error = 1;
537 goto bailout;
538 }
539
540 status = scsi_get_nv(table, table_size, optarg,
541 &table_entry,SCSI_NV_FLAG_IG_CASE);
542 if (status == SCSI_NV_FOUND)
543 action = table[table_entry].value;
544 else {
545 warnx("%s: %s %s option %s", __func__,
546 (status == SCSI_NV_AMBIGUOUS) ?
547 "ambiguous" : "invalid", in ? "in" :
548 "out", optarg);
549 error = 1;
550 goto bailout;
551 }
552 break;
553 }
554 case 'p':
555 aptpl = 1;
556 break;
557 case 'R': {
558 char *endptr;
559
560 rel_tgt_port = strtoul(optarg, &endptr, 0);
561 if (*endptr != '\0') {
562 warnx("%s: invalid relative target port %s",
563 __func__, optarg);
564 error = 1;
565 goto bailout;
566 }
567 rel_port_set = 1;
568 break;
569 }
570 case 's': {
571 size_t scope_size;
572 struct scsi_nv *scope_table = NULL;
573 scsi_nv_status status;
574 int table_entry = 0;
575 char *endptr;
576
577 /*
578 * First check to see if the user gave us a numeric
579 * argument. If so, we'll try using it.
580 */
581 if (isdigit(optarg[0])) {
582 scope = strtol(optarg, &endptr, 0);
583 if (*endptr != '\0') {
584 warnx("%s: invalid scope %s",
585 __func__, optarg);
586 error = 1;
587 goto bailout;
588 }
589 scope = (scope << SPR_SCOPE_SHIFT) &
590 SPR_SCOPE_MASK;
591 break;
592 }
593
594 scope_size = sizeof(persist_scope_table) /
595 sizeof(persist_scope_table[0]);
596 scope_table = persist_scope_table;
597 status = scsi_get_nv(scope_table, scope_size, optarg,
598 &table_entry,SCSI_NV_FLAG_IG_CASE);
599 if (status == SCSI_NV_FOUND)
600 scope = scope_table[table_entry].value;
601 else {
602 warnx("%s: %s scope %s", __func__,
603 (status == SCSI_NV_AMBIGUOUS) ?
604 "ambiguous" : "invalid", optarg);
605 error = 1;
606 goto bailout;
607 }
608 break;
609 }
610 case 'S':
611 spec_i_pt = 1;
612 break;
613 case 'T': {
614 size_t res_type_size;
615 struct scsi_nv *rtype_table = NULL;
616 scsi_nv_status status;
617 char *endptr;
618 int table_entry = 0;
619
620 /*
621 * First check to see if the user gave us a numeric
622 * argument. If so, we'll try using it.
623 */
624 if (isdigit(optarg[0])) {
625 res_type = strtol(optarg, &endptr, 0);
626 if (*endptr != '\0') {
627 warnx("%s: invalid reservation type %s",
628 __func__, optarg);
629 error = 1;
630 goto bailout;
631 }
632 break;
633 }
634
635 res_type_size = sizeof(persist_type_table) /
636 sizeof(persist_type_table[0]);
637 rtype_table = persist_type_table;
638 status = scsi_get_nv(rtype_table, res_type_size,
639 optarg, &table_entry,
640 SCSI_NV_FLAG_IG_CASE);
641 if (status == SCSI_NV_FOUND)
642 res_type = rtype_table[table_entry].value;
643 else {
644 warnx("%s: %s reservation type %s", __func__,
645 (status == SCSI_NV_AMBIGUOUS) ?
646 "ambiguous" : "invalid", optarg);
647 error = 1;
648 goto bailout;
649 }
650 break;
651 }
652 case 'U':
653 unreg = 1;
654 break;
655 default:
656 break;
657 }
658 }
659
660 if ((in + out) != 1) {
661 warnx("%s: you must specify one of -i or -o", __func__);
662 error = 1;
663 goto bailout;
664 }
665
666 /*
667 * Note that we don't really try to figure out whether the user
668 * needs to specify one or both keys. There are a number of
669 * scenarios, and sometimes 0 is a valid and desired value.
670 */
671 if (in != 0) {
672 switch (action) {
673 case SPRI_RK:
674 case SPRI_RR:
675 case SPRI_RS:
676 /*
677 * Allocate the maximum length possible for these
678 * service actions. According to the spec, the
679 * target is supposed to return the available
680 * length in the header, regardless of the
681 * allocation length. In practice, though, with
682 * the READ FULL STATUS (SPRI_RS) service action,
683 * some Seagate drives (in particular a
684 * Constellation ES, <SEAGATE ST32000444SS 0006>)
685 * don't return the available length if you only
686 * allocate the length of the header. So just
687 * allocate the maximum here so we don't miss
688 * anything.
689 */
690 res_len = SPRI_MAX_LEN;
691 break;
692 case SPRI_RC:
693 res_len = sizeof(struct scsi_per_res_cap);
694 break;
695 default:
696 /* In theory we should catch this above */
697 warnx("%s: invalid action %d", __func__, action);
698 error = 1;
699 goto bailout;
700 break;
701 }
702 } else {
703
704 /*
705 * XXX KDM need to add length for transport IDs for the
706 * register and move service action and the register
707 * service action with the SPEC_I_PT bit set.
708 */
709 if (action == SPRO_REG_MOVE) {
710 if (num_ids != 1) {
711 warnx("%s: register and move requires a "
712 "single transport ID (-I)", __func__);
713 error = 1;
714 goto bailout;
715 }
716 if (rel_port_set == 0) {
717 warnx("%s: register and move requires a "
718 "relative target port (-R)", __func__);
719 error = 1;
720 goto bailout;
721 }
722 res_len = sizeof(struct scsi_per_res_reg_move) + id_len;
723 } else {
724 res_len = sizeof(struct scsi_per_res_out_parms);
725 if ((action == SPRO_REGISTER)
726 && (num_ids != 0)) {
727 /*
728 * If the user specifies any IDs with the
729 * register service action, turn on the
730 * spec_i_pt bit.
731 */
732 spec_i_pt = 1;
733 res_len += id_len;
734 res_len +=
735 sizeof(struct scsi_per_res_out_trans_ids);
736 }
737 }
738 }
739 retry:
740 if (res_buf != NULL) {
741 free(res_buf);
742 res_buf = NULL;
743 }
744 res_buf = malloc(res_len);
745 if (res_buf == NULL) {
746 warn("%s: error allocating %d bytes", __func__, res_len);
747 error = 1;
748 goto bailout;
749 }
750 bzero(res_buf, res_len);
751
752 if (in != 0) {
753 scsi_persistent_reserve_in(&ccb->csio,
754 /*retries*/ retry_count,
755 /*cbfcnp*/ NULL,
756 /*tag_action*/ task_attr,
757 /*service_action*/ action,
758 /*data_ptr*/ res_buf,
759 /*dxfer_len*/ res_len,
760 /*sense_len*/ SSD_FULL_SIZE,
761 /*timeout*/ timeout ? timeout :5000);
762
763 } else {
764 switch (action) {
765 case SPRO_REGISTER:
766 if (spec_i_pt != 0) {
767 struct scsi_per_res_out_trans_ids *id_hdr;
768 uint8_t *bufptr;
769
770 bufptr = res_buf +
771 sizeof(struct scsi_per_res_out_parms) +
772 sizeof(struct scsi_per_res_out_trans_ids);
773 STAILQ_FOREACH(id, &transport_id_list, links) {
774 bcopy(id->hdr, bufptr, id->alloc_len);
775 bufptr += id->alloc_len;
776 }
777 id_hdr = (struct scsi_per_res_out_trans_ids *)
778 (res_buf +
779 sizeof(struct scsi_per_res_out_parms));
780 scsi_ulto4b(id_len, id_hdr->additional_length);
781 }
782 case SPRO_REG_IGNO:
783 case SPRO_PREEMPT:
784 case SPRO_PRE_ABO:
785 case SPRO_RESERVE:
786 case SPRO_RELEASE:
787 case SPRO_CLEAR:
788 case SPRO_REPL_LOST_RES: {
789 struct scsi_per_res_out_parms *parms;
790
791 parms = (struct scsi_per_res_out_parms *)res_buf;
792
793 scsi_u64to8b(key, parms->res_key.key);
794 scsi_u64to8b(sa_key, parms->serv_act_res_key);
795 if (spec_i_pt != 0)
796 parms->flags |= SPR_SPEC_I_PT;
797 if (all_tg_pt != 0)
798 parms->flags |= SPR_ALL_TG_PT;
799 if (aptpl != 0)
800 parms->flags |= SPR_APTPL;
801 break;
802 }
803 case SPRO_REG_MOVE: {
804 struct scsi_per_res_reg_move *reg_move;
805 uint8_t *bufptr;
806
807 reg_move = (struct scsi_per_res_reg_move *)res_buf;
808
809 scsi_u64to8b(key, reg_move->res_key.key);
810 scsi_u64to8b(sa_key, reg_move->serv_act_res_key);
811 if (unreg != 0)
812 reg_move->flags |= SPR_REG_MOVE_UNREG;
813 if (aptpl != 0)
814 reg_move->flags |= SPR_REG_MOVE_APTPL;
815 scsi_ulto2b(rel_tgt_port, reg_move->rel_trgt_port_id);
816 id = STAILQ_FIRST(&transport_id_list);
817 /*
818 * This shouldn't happen, since we already checked
819 * the number of IDs above.
820 */
821 if (id == NULL) {
822 warnx("%s: No transport IDs found!", __func__);
823 error = 1;
824 goto bailout;
825 }
826 bufptr = (uint8_t *)®_move[1];
827 bcopy(id->hdr, bufptr, id->alloc_len);
828 scsi_ulto4b(id->alloc_len,
829 reg_move->transport_id_length);
830 break;
831 }
832 default:
833 break;
834 }
835 scsi_persistent_reserve_out(&ccb->csio,
836 /*retries*/ retry_count,
837 /*cbfcnp*/ NULL,
838 /*tag_action*/ task_attr,
839 /*service_action*/ action,
840 /*scope*/ scope,
841 /*res_type*/ res_type,
842 /*data_ptr*/ res_buf,
843 /*dxfer_len*/ res_len,
844 /*sense_len*/ SSD_FULL_SIZE,
845 /*timeout*/ timeout ?timeout :5000);
846 }
847
848 /* Disable freezing the device queue */
849 ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
850
851 if (err_recover != 0)
852 ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
853
854 if (cam_send_ccb(device, ccb) < 0) {
855 warn("error sending PERSISTENT RESERVE %s", (in != 0) ?
856 "IN" : "OUT");
857 error = 1;
858 goto bailout;
859 }
860
861 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
862 if (verbosemode != 0) {
863 cam_error_print(device, ccb, CAM_ESF_ALL,
864 CAM_EPF_ALL, stderr);
865 }
866 error = 1;
867 goto bailout;
868 }
869
870 if (in == 0)
871 goto bailout;
872
873 valid_len = res_len - ccb->csio.resid;
874
875 switch (action) {
876 case SPRI_RK:
877 case SPRI_RR:
878 case SPRI_RS: {
879 struct scsi_per_res_in_header *hdr;
880 uint32_t hdr_len;
881
882 if (valid_len < sizeof(*hdr)) {
883 warnx("%s: only got %d valid bytes, need %zd",
884 __func__, valid_len, sizeof(*hdr));
885 error = 1;
886 goto bailout;
887 }
888 hdr = (struct scsi_per_res_in_header *)res_buf;
889 hdr_len = scsi_4btoul(hdr->length);
890
891 if (hdr_len > (res_len - sizeof(*hdr))) {
892 res_len = hdr_len + sizeof(*hdr);
893 goto retry;
894 }
895
896 if (action == SPRI_RK) {
897 persist_print_keys(hdr, valid_len);
898 } else if (action == SPRI_RR) {
899 persist_print_res(hdr, valid_len);
900 } else {
901 persist_print_full(hdr, valid_len);
902 }
903 break;
904 }
905 case SPRI_RC: {
906 struct scsi_per_res_cap *cap;
907 uint32_t cap_len;
908
909 if (valid_len < sizeof(*cap)) {
910 warnx("%s: only got %u valid bytes, need %zd",
911 __func__, valid_len, sizeof(*cap));
912 error = 1;
913 goto bailout;
914 }
915 cap = (struct scsi_per_res_cap *)res_buf;
916 cap_len = scsi_2btoul(cap->length);
917 if (cap_len != sizeof(*cap)) {
918 /*
919 * We should be able to deal with this,
920 * it's just more trouble.
921 */
922 warnx("%s: reported size %u is different "
923 "than expected size %zd", __func__,
924 cap_len, sizeof(*cap));
925 }
926
927 /*
928 * If there is more data available, grab it all,
929 * even though we don't really know what to do with
930 * the extra data since it obviously wasn't in the
931 * spec when this code was written.
932 */
933 if (cap_len > res_len) {
934 res_len = cap_len;
935 goto retry;
936 }
937 persist_print_cap(cap, valid_len);
938 break;
939 }
940 default:
941 break;
942 }
943
944 bailout:
945 free(res_buf);
946
947 if (ccb != NULL)
948 cam_freeccb(ccb);
949
950 STAILQ_FOREACH_SAFE(id, &transport_id_list, links, id2) {
951 STAILQ_REMOVE(&transport_id_list, id, persist_transport_id,
952 links);
953 free(id);
954 }
955 return (error);
956 }
957