xref: /aosp_15_r20/external/sg3_utils/src/sg_persist.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1*44704f69SBart Van Assche /* A utility program originally written for the Linux OS SCSI subsystem.
2*44704f69SBart Van Assche  *  Copyright (C) 2004-2022 D. Gilbert
3*44704f69SBart Van Assche  *  This program is free software; you can redistribute it and/or modify
4*44704f69SBart Van Assche  *  it under the terms of the GNU General Public License as published by
5*44704f69SBart Van Assche  *  the Free Software Foundation; either version 2, or (at your option)
6*44704f69SBart Van Assche  *  any later version.
7*44704f69SBart Van Assche  *
8*44704f69SBart Van Assche  * SPDX-License-Identifier: GPL-2.0-or-later
9*44704f69SBart Van Assche  *
10*44704f69SBart Van Assche  *  This program issues the SCSI PERSISTENT IN and OUT commands.
11*44704f69SBart Van Assche  */
12*44704f69SBart Van Assche 
13*44704f69SBart Van Assche #include <unistd.h>
14*44704f69SBart Van Assche #include <fcntl.h>
15*44704f69SBart Van Assche #include <stdio.h>
16*44704f69SBart Van Assche #include <stdlib.h>
17*44704f69SBart Van Assche #include <stdint.h>
18*44704f69SBart Van Assche #include <stdarg.h>
19*44704f69SBart Van Assche #include <stdbool.h>
20*44704f69SBart Van Assche #include <string.h>
21*44704f69SBart Van Assche #include <ctype.h>
22*44704f69SBart Van Assche #include <errno.h>
23*44704f69SBart Van Assche #include <getopt.h>
24*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
25*44704f69SBart Van Assche 
26*44704f69SBart Van Assche #include <inttypes.h>
27*44704f69SBart Van Assche 
28*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
29*44704f69SBart Van Assche #include "config.h"
30*44704f69SBart Van Assche #endif
31*44704f69SBart Van Assche 
32*44704f69SBart Van Assche #include "sg_lib.h"
33*44704f69SBart Van Assche #include "sg_cmds_basic.h"
34*44704f69SBart Van Assche #include "sg_cmds_extra.h"
35*44704f69SBart Van Assche #include "sg_unaligned.h"
36*44704f69SBart Van Assche #include "sg_pr2serr.h"
37*44704f69SBart Van Assche 
38*44704f69SBart Van Assche static const char * version_str = "0.69 20220118";
39*44704f69SBart Van Assche 
40*44704f69SBart Van Assche 
41*44704f69SBart Van Assche #define PRIN_RKEY_SA     0x0
42*44704f69SBart Van Assche #define PRIN_RRES_SA     0x1
43*44704f69SBart Van Assche #define PRIN_RCAP_SA     0x2
44*44704f69SBart Van Assche #define PRIN_RFSTAT_SA   0x3
45*44704f69SBart Van Assche #define PROUT_REG_SA     0x0
46*44704f69SBart Van Assche #define PROUT_RES_SA     0x1
47*44704f69SBart Van Assche #define PROUT_REL_SA     0x2
48*44704f69SBart Van Assche #define PROUT_CLEAR_SA   0x3
49*44704f69SBart Van Assche #define PROUT_PREE_SA    0x4
50*44704f69SBart Van Assche #define PROUT_PREE_AB_SA 0x5
51*44704f69SBart Van Assche #define PROUT_REG_IGN_SA 0x6
52*44704f69SBart Van Assche #define PROUT_REG_MOVE_SA 0x7
53*44704f69SBart Van Assche #define PROUT_REPL_LOST_SA 0x8
54*44704f69SBart Van Assche #define MX_ALLOC_LEN 8192
55*44704f69SBart Van Assche #define MX_TIDS 32
56*44704f69SBart Van Assche #define MX_TID_LEN 256
57*44704f69SBart Van Assche 
58*44704f69SBart Van Assche #define ME "sg_persist"
59*44704f69SBart Van Assche 
60*44704f69SBart Van Assche #define SG_PERSIST_IN_RDONLY "SG_PERSIST_IN_RDONLY"
61*44704f69SBart Van Assche 
62*44704f69SBart Van Assche struct opts_t {
63*44704f69SBart Van Assche     bool inquiry;       /* set true by default (unlike most bools) */
64*44704f69SBart Van Assche     bool param_alltgpt;
65*44704f69SBart Van Assche     bool param_aptpl;
66*44704f69SBart Van Assche     bool param_unreg;
67*44704f69SBart Van Assche     bool pr_in;         /* true: PR_IN (def); false: PR_OUT */
68*44704f69SBart Van Assche     bool readonly;
69*44704f69SBart Van Assche     bool readwrite_force;/* set when '-yy' given. Ooverrides environment
70*44704f69SBart Van Assche                             variable SG_PERSIST_IN_RDONLY and opens RW */
71*44704f69SBart Van Assche     bool verbose_given;
72*44704f69SBart Van Assche     bool version_given;
73*44704f69SBart Van Assche     int hex;
74*44704f69SBart Van Assche     int num_transportids;
75*44704f69SBart Van Assche     int prin_sa;
76*44704f69SBart Van Assche     int prout_sa;
77*44704f69SBart Van Assche     int verbose;
78*44704f69SBart Van Assche     uint32_t alloc_len;
79*44704f69SBart Van Assche     uint32_t param_rtp;
80*44704f69SBart Van Assche     uint32_t prout_type;
81*44704f69SBart Van Assche     uint64_t param_rk;
82*44704f69SBart Van Assche     uint64_t param_sark;
83*44704f69SBart Van Assche     uint8_t transportid_arr[MX_TIDS * MX_TID_LEN];
84*44704f69SBart Van Assche };
85*44704f69SBart Van Assche 
86*44704f69SBart Van Assche 
87*44704f69SBart Van Assche static struct option long_options[] = {
88*44704f69SBart Van Assche     {"alloc-length", required_argument, 0, 'l'},
89*44704f69SBart Van Assche     {"alloc_length", required_argument, 0, 'l'},
90*44704f69SBart Van Assche     {"clear", no_argument, 0, 'C'},
91*44704f69SBart Van Assche     {"device", required_argument, 0, 'd'},
92*44704f69SBart Van Assche     {"help", no_argument, 0, 'h'},
93*44704f69SBart Van Assche     {"hex", no_argument, 0, 'H'},
94*44704f69SBart Van Assche     {"in", no_argument, 0, 'i'},
95*44704f69SBart Van Assche     {"maxlen", required_argument, 0, 'm'},
96*44704f69SBart Van Assche     {"no-inquiry", no_argument, 0, 'n'},
97*44704f69SBart Van Assche     {"no_inquiry", no_argument, 0, 'n'},
98*44704f69SBart Van Assche     {"out", no_argument, 0, 'o'},
99*44704f69SBart Van Assche     {"param-alltgpt", no_argument, 0, 'Y'},
100*44704f69SBart Van Assche     {"param_alltgpt", no_argument, 0, 'Y'},
101*44704f69SBart Van Assche     {"param-aptpl", no_argument, 0, 'Z'},
102*44704f69SBart Van Assche     {"param_aptpl", no_argument, 0, 'Z'},
103*44704f69SBart Van Assche     {"param-rk", required_argument, 0, 'K'},
104*44704f69SBart Van Assche     {"param_rk", required_argument, 0, 'K'},
105*44704f69SBart Van Assche     {"param-sark", required_argument, 0, 'S'},
106*44704f69SBart Van Assche     {"param_sark", required_argument, 0, 'S'},
107*44704f69SBart Van Assche     {"param-unreg", no_argument, 0, 'U'},
108*44704f69SBart Van Assche     {"param_unreg", no_argument, 0, 'U'},
109*44704f69SBart Van Assche     {"preempt", no_argument, 0, 'P'},
110*44704f69SBart Van Assche     {"preempt-abort", no_argument, 0, 'A'},
111*44704f69SBart Van Assche     {"preempt_abort", no_argument, 0, 'A'},
112*44704f69SBart Van Assche     {"prout-type", required_argument, 0, 'T'},
113*44704f69SBart Van Assche     {"prout_type", required_argument, 0, 'T'},
114*44704f69SBart Van Assche     {"read-full-status", no_argument, 0, 's'},
115*44704f69SBart Van Assche     {"read_full_status", no_argument, 0, 's'},
116*44704f69SBart Van Assche     {"read-keys", no_argument, 0, 'k'},
117*44704f69SBart Van Assche     {"read_keys", no_argument, 0, 'k'},
118*44704f69SBart Van Assche     {"readonly", no_argument, 0, 'y'},
119*44704f69SBart Van Assche     {"read-reservation", no_argument, 0, 'r'},
120*44704f69SBart Van Assche     {"read_reservation", no_argument, 0, 'r'},
121*44704f69SBart Van Assche     {"read-status", no_argument, 0, 's'},
122*44704f69SBart Van Assche     {"read_status", no_argument, 0, 's'},
123*44704f69SBart Van Assche     {"register", no_argument, 0, 'G'},
124*44704f69SBart Van Assche     {"register-ignore", no_argument, 0, 'I'},
125*44704f69SBart Van Assche     {"register_ignore", no_argument, 0, 'I'},
126*44704f69SBart Van Assche     {"register-move", no_argument, 0, 'M'},
127*44704f69SBart Van Assche     {"register_move", no_argument, 0, 'M'},
128*44704f69SBart Van Assche     {"release", no_argument, 0, 'L'},
129*44704f69SBart Van Assche     {"relative-target-port", required_argument, 0, 'Q'},
130*44704f69SBart Van Assche     {"relative_target_port", required_argument, 0, 'Q'},
131*44704f69SBart Van Assche     {"replace-lost", no_argument, 0, 'z'},
132*44704f69SBart Van Assche     {"replace_lost", no_argument, 0, 'z'},
133*44704f69SBart Van Assche     {"report-capabilities", no_argument, 0, 'c'},
134*44704f69SBart Van Assche     {"report_capabilities", no_argument, 0, 'c'},
135*44704f69SBart Van Assche     {"reserve", no_argument, 0, 'R'},
136*44704f69SBart Van Assche     {"transport-id", required_argument, 0, 'X'},
137*44704f69SBart Van Assche     {"transport_id", required_argument, 0, 'X'},
138*44704f69SBart Van Assche     {"unreg", no_argument, 0, 'U'},
139*44704f69SBart Van Assche     {"verbose", no_argument, 0, 'v'},
140*44704f69SBart Van Assche     {"version", no_argument, 0, 'V'},
141*44704f69SBart Van Assche     {0, 0, 0, 0}
142*44704f69SBart Van Assche };
143*44704f69SBart Van Assche 
144*44704f69SBart Van Assche static const char * prin_sa_strs[] = {
145*44704f69SBart Van Assche     "Read keys",
146*44704f69SBart Van Assche     "Read reservation",
147*44704f69SBart Van Assche     "Report capabilities",
148*44704f69SBart Van Assche     "Read full status",
149*44704f69SBart Van Assche     "[reserved 0x4]",
150*44704f69SBart Van Assche     "[reserved 0x5]",
151*44704f69SBart Van Assche     "[reserved 0x6]",
152*44704f69SBart Van Assche     "[reserved 0x7]",
153*44704f69SBart Van Assche };
154*44704f69SBart Van Assche static const int num_prin_sa_strs = SG_ARRAY_SIZE(prin_sa_strs);
155*44704f69SBart Van Assche 
156*44704f69SBart Van Assche static const char * prout_sa_strs[] = {
157*44704f69SBart Van Assche     "Register",
158*44704f69SBart Van Assche     "Reserve",
159*44704f69SBart Van Assche     "Release",
160*44704f69SBart Van Assche     "Clear",
161*44704f69SBart Van Assche     "Preempt",
162*44704f69SBart Van Assche     "Preempt and abort",
163*44704f69SBart Van Assche     "Register and ignore existing key",
164*44704f69SBart Van Assche     "Register and move",
165*44704f69SBart Van Assche     "Replace lost reservation",
166*44704f69SBart Van Assche     "[reserved 0x9]",
167*44704f69SBart Van Assche };
168*44704f69SBart Van Assche static const int num_prout_sa_strs = SG_ARRAY_SIZE(prout_sa_strs);
169*44704f69SBart Van Assche 
170*44704f69SBart Van Assche static const char * pr_type_strs[] = {
171*44704f69SBart Van Assche     "obsolete [0]",
172*44704f69SBart Van Assche     "Write Exclusive",
173*44704f69SBart Van Assche     "obsolete [2]",
174*44704f69SBart Van Assche     "Exclusive Access",
175*44704f69SBart Van Assche     "obsolete [4]",
176*44704f69SBart Van Assche     "Write Exclusive, registrants only",
177*44704f69SBart Van Assche     "Exclusive Access, registrants only",
178*44704f69SBart Van Assche     "Write Exclusive, all registrants",
179*44704f69SBart Van Assche     "Exclusive Access, all registrants",
180*44704f69SBart Van Assche     "obsolete [9]", "obsolete [0xa]", "obsolete [0xb]", "obsolete [0xc]",
181*44704f69SBart Van Assche     "obsolete [0xd]", "obsolete [0xe]", "obsolete [0xf]",
182*44704f69SBart Van Assche };
183*44704f69SBart Van Assche 
184*44704f69SBart Van Assche 
185*44704f69SBart Van Assche static void
usage(int help)186*44704f69SBart Van Assche usage(int help)
187*44704f69SBart Van Assche {
188*44704f69SBart Van Assche     if (help < 2) {
189*44704f69SBart Van Assche         pr2serr("Usage: sg_persist [OPTIONS] [DEVICE]\n"
190*44704f69SBart Van Assche                 "  where the main OPTIONS are:\n"
191*44704f69SBart Van Assche                 "    --clear|-C                 PR Out: Clear\n"
192*44704f69SBart Van Assche                 "    --help|-h                  print usage message, "
193*44704f69SBart Van Assche                 "twice for more\n"
194*44704f69SBart Van Assche                 "    --in|-i                    request PR In command "
195*44704f69SBart Van Assche                 "(default)\n"
196*44704f69SBart Van Assche                 "    --out|-o                   request PR Out command\n"
197*44704f69SBart Van Assche                 "    --param-rk=RK|-K RK        PR Out parameter reservation "
198*44704f69SBart Van Assche                 "key\n"
199*44704f69SBart Van Assche                 "                               (RK is in hex)\n"
200*44704f69SBart Van Assche                 "    --param-sark=SARK|-S SARK    PR Out parameter service "
201*44704f69SBart Van Assche                 "action\n"
202*44704f69SBart Van Assche                 "                                 reservation key (SARK is "
203*44704f69SBart Van Assche                 "in hex)\n"
204*44704f69SBart Van Assche                 "    --preempt|-P               PR Out: Preempt\n"
205*44704f69SBart Van Assche                 "    --preempt-abort|-A         PR Out: Preempt and Abort\n"
206*44704f69SBart Van Assche                 "    --prout-type=TYPE|-T TYPE    PR Out type field (see "
207*44704f69SBart Van Assche                 "'-hh')\n"
208*44704f69SBart Van Assche                 "    --read-full-status|-s      PR In: Read Full Status\n"
209*44704f69SBart Van Assche                 "    --read-keys|-k             PR In: Read Keys "
210*44704f69SBart Van Assche                 "(default)\n");
211*44704f69SBart Van Assche         pr2serr("    --read-reservation|-r      PR In: Read Reservation\n"
212*44704f69SBart Van Assche                 "    --read-status|-s           PR In: Read Full Status\n"
213*44704f69SBart Van Assche                 "    --register|-G              PR Out: Register\n"
214*44704f69SBart Van Assche                 "    --register-ignore|-I       PR Out: Register and Ignore\n"
215*44704f69SBart Van Assche                 "    --register-move|-M         PR Out: Register and Move\n"
216*44704f69SBart Van Assche                 "                               for '--register-move'\n"
217*44704f69SBart Van Assche                 "    --release|-L               PR Out: Release\n"
218*44704f69SBart Van Assche                 "    --replace-lost|-x          PR Out: Replace Lost "
219*44704f69SBart Van Assche                 "Reservation\n"
220*44704f69SBart Van Assche                 "    --report-capabilities|-c   PR In: Report Capabilities\n"
221*44704f69SBart Van Assche                 "    --reserve|-R               PR Out: Reserve\n"
222*44704f69SBart Van Assche                 "    --unreg|-U                 optional with PR Out "
223*44704f69SBart Van Assche                 "Register and Move\n\n"
224*44704f69SBart Van Assche                 "Performs a SCSI PERSISTENT RESERVE (IN or OUT) command. "
225*44704f69SBart Van Assche                 "Invoking\n'sg_persist DEVICE' will do a PR In Read Keys "
226*44704f69SBart Van Assche                 "command. Use '-hh'\nfor more options and TYPE meanings.\n");
227*44704f69SBart Van Assche     } else {
228*44704f69SBart Van Assche         pr2serr("Usage: sg_persist [OPTIONS] [DEVICE]\n"
229*44704f69SBart Van Assche                 "  where the other OPTIONS are:\n"
230*44704f69SBart Van Assche                 "    --alloc-length=LEN|-l LEN    allocation length hex "
231*44704f69SBart Van Assche                 "value (used with\n"
232*44704f69SBart Van Assche                 "                                 PR In only) (default: 8192 "
233*44704f69SBart Van Assche                 "(2000 in hex))\n"
234*44704f69SBart Van Assche                 "    --device=DEVICE|-d DEVICE    supply DEVICE as an option "
235*44704f69SBart Van Assche                 "rather than\n"
236*44704f69SBart Van Assche                 "                                 an argument\n"
237*44704f69SBart Van Assche                 "    --hex|-H                   output response in hex (for "
238*44704f69SBart Van Assche                 "PR In commands)\n"
239*44704f69SBart Van Assche                 "    --maxlen=LEN|-m LEN        allocation length in "
240*44704f69SBart Van Assche                 "decimal, by default.\n"
241*44704f69SBart Van Assche                 "                               like --alloc-len= "
242*44704f69SBart Van Assche                 "(def: 8192, 8k, 2000h)\n"
243*44704f69SBart Van Assche                 "    --no-inquiry|-n            skip INQUIRY (default: do "
244*44704f69SBart Van Assche                 "INQUIRY)\n"
245*44704f69SBart Van Assche                 "    --param-alltgpt|-Y         PR Out parameter "
246*44704f69SBart Van Assche                 "'ALL_TG_PT'\n"
247*44704f69SBart Van Assche                 "    --param-aptpl|-Z           PR Out parameter 'APTPL'\n"
248*44704f69SBart Van Assche                 "    --readonly|-y              open DEVICE read-only (def: "
249*44704f69SBart Van Assche                 "read-write)\n"
250*44704f69SBart Van Assche                 "    --relative-target-port=RTPI|-Q RTPI    relative target "
251*44704f69SBart Van Assche                 "port "
252*44704f69SBart Van Assche                 "identifier\n"
253*44704f69SBart Van Assche                 "    --transport-id=TIDS|-X TIDS    one or more "
254*44704f69SBart Van Assche                 "TransportIDs can\n"
255*44704f69SBart Van Assche                 "                                   be given in several "
256*44704f69SBart Van Assche                 "forms\n"
257*44704f69SBart Van Assche                 "    --verbose|-v               output additional debug "
258*44704f69SBart Van Assche                 "information\n"
259*44704f69SBart Van Assche                 "    --version|-V               output version string\n\n"
260*44704f69SBart Van Assche                 "For the main options use '--help' or '-h' once.\n\n\n");
261*44704f69SBart Van Assche         pr2serr("PR Out TYPE field value meanings:\n"
262*44704f69SBart Van Assche                 "  0:    obsolete (was 'read shared' in SPC)\n"
263*44704f69SBart Van Assche                 "  1:    write exclusive\n"
264*44704f69SBart Van Assche                 "  2:    obsolete (was 'read exclusive')\n"
265*44704f69SBart Van Assche                 "  3:    exclusive access\n"
266*44704f69SBart Van Assche                 "  4:    obsolete (was 'shared access')\n"
267*44704f69SBart Van Assche                 "  5:    write exclusive, registrants only\n"
268*44704f69SBart Van Assche                 "  6:    exclusive access, registrants only\n"
269*44704f69SBart Van Assche                 "  7:    write exclusive, all registrants\n"
270*44704f69SBart Van Assche                 "  8:    exclusive access, all registrants\n");
271*44704f69SBart Van Assche     }
272*44704f69SBart Van Assche }
273*44704f69SBart Van Assche 
274*44704f69SBart Van Assche static int
prin_work(int sg_fd,const struct opts_t * op)275*44704f69SBart Van Assche prin_work(int sg_fd, const struct opts_t * op)
276*44704f69SBart Van Assche {
277*44704f69SBart Van Assche     int k, j, num, add_len, add_desc_len;
278*44704f69SBart Van Assche     int res = 0;
279*44704f69SBart Van Assche     unsigned int pr_gen;
280*44704f69SBart Van Assche     uint8_t * bp;
281*44704f69SBart Van Assche     uint8_t * pr_buff = NULL;
282*44704f69SBart Van Assche     uint8_t * free_pr_buff = NULL;
283*44704f69SBart Van Assche 
284*44704f69SBart Van Assche     pr_buff = sg_memalign(op->alloc_len, 0 /* page aligned */, &free_pr_buff,
285*44704f69SBart Van Assche                           false);
286*44704f69SBart Van Assche     if (NULL == pr_buff) {
287*44704f69SBart Van Assche         pr2serr("%s: unable to allocate %d bytes on heap\n", __func__,
288*44704f69SBart Van Assche                 op->alloc_len);
289*44704f69SBart Van Assche         return sg_convert_errno(ENOMEM);
290*44704f69SBart Van Assche     }
291*44704f69SBart Van Assche     res = sg_ll_persistent_reserve_in(sg_fd, op->prin_sa, pr_buff,
292*44704f69SBart Van Assche                                       op->alloc_len, true, op->verbose);
293*44704f69SBart Van Assche     if (res) {
294*44704f69SBart Van Assche         char b[64];
295*44704f69SBart Van Assche         char bb[80];
296*44704f69SBart Van Assche 
297*44704f69SBart Van Assche         if (op->prin_sa < num_prin_sa_strs)
298*44704f69SBart Van Assche             snprintf(b, sizeof(b), "%s", prin_sa_strs[op->prin_sa]);
299*44704f69SBart Van Assche         else
300*44704f69SBart Van Assche             snprintf(b, sizeof(b), "service action=0x%x", op->prin_sa);
301*44704f69SBart Van Assche 
302*44704f69SBart Van Assche         if (SG_LIB_CAT_INVALID_OP == res)
303*44704f69SBart Van Assche             pr2serr("PR in (%s): command not supported\n", b);
304*44704f69SBart Van Assche         else if (SG_LIB_CAT_ILLEGAL_REQ == res)
305*44704f69SBart Van Assche             pr2serr("PR in (%s): bad field in cdb or parameter list (perhaps "
306*44704f69SBart Van Assche                     "unsupported service action)\n", b);
307*44704f69SBart Van Assche         else {
308*44704f69SBart Van Assche             sg_get_category_sense_str(res, sizeof(bb), bb, op->verbose);
309*44704f69SBart Van Assche             pr2serr("PR in (%s): %s\n", b, bb);
310*44704f69SBart Van Assche         }
311*44704f69SBart Van Assche         goto fini;
312*44704f69SBart Van Assche     }
313*44704f69SBart Van Assche     if (PRIN_RCAP_SA == op->prin_sa) {
314*44704f69SBart Van Assche         if (8 != pr_buff[1]) {
315*44704f69SBart Van Assche             pr2serr("Unexpected response for PRIN Report Capabilities\n");
316*44704f69SBart Van Assche             if (op->hex)
317*44704f69SBart Van Assche                 hex2stdout(pr_buff, pr_buff[1], 1);
318*44704f69SBart Van Assche             res = SG_LIB_CAT_MALFORMED;
319*44704f69SBart Van Assche             goto fini;
320*44704f69SBart Van Assche         }
321*44704f69SBart Van Assche         if (op->hex)
322*44704f69SBart Van Assche             hex2stdout(pr_buff, 8, 1);
323*44704f69SBart Van Assche         else {
324*44704f69SBart Van Assche             printf("Report capabilities response:\n");
325*44704f69SBart Van Assche             printf("  Replace Lost Reservation Capable(RLR_C): %d\n",
326*44704f69SBart Van Assche                    !!(pr_buff[2] & 0x80));      /* added spc4r26 */
327*44704f69SBart Van Assche             printf("  Compatible Reservation Handling(CRH): %d\n",
328*44704f69SBart Van Assche                    !!(pr_buff[2] & 0x10));
329*44704f69SBart Van Assche             printf("  Specify Initiator Ports Capable(SIP_C): %d\n",
330*44704f69SBart Van Assche                    !!(pr_buff[2] & 0x8));
331*44704f69SBart Van Assche             printf("  All Target Ports Capable(ATP_C): %d\n",
332*44704f69SBart Van Assche                    !!(pr_buff[2] & 0x4));
333*44704f69SBart Van Assche             printf("  Persist Through Power Loss Capable(PTPL_C): %d\n",
334*44704f69SBart Van Assche                    !!(pr_buff[2] & 0x1));
335*44704f69SBart Van Assche             printf("  Type Mask Valid(TMV): %d\n", !!(pr_buff[3] & 0x80));
336*44704f69SBart Van Assche             printf("  Allow Commands: %d\n", (pr_buff[3] >> 4) & 0x7);
337*44704f69SBart Van Assche             printf("  Persist Through Power Loss Active(PTPL_A): %d\n",
338*44704f69SBart Van Assche                    !!(pr_buff[3] & 0x1));
339*44704f69SBart Van Assche             if (pr_buff[3] & 0x80) {
340*44704f69SBart Van Assche                 printf("    Support indicated in Type mask:\n");
341*44704f69SBart Van Assche                 printf("      %s: %d\n", pr_type_strs[7],
342*44704f69SBart Van Assche                        !!(pr_buff[4] & 0x80));  /* WR_EX_AR */
343*44704f69SBart Van Assche                 printf("      %s: %d\n", pr_type_strs[6],
344*44704f69SBart Van Assche                        !!(pr_buff[4] & 0x40));  /* EX_AC_RO */
345*44704f69SBart Van Assche                 printf("      %s: %d\n", pr_type_strs[5],
346*44704f69SBart Van Assche                        !!(pr_buff[4] & 0x20));  /* WR_EX_RO */
347*44704f69SBart Van Assche                 printf("      %s: %d\n", pr_type_strs[3],
348*44704f69SBart Van Assche                        !!(pr_buff[4] & 0x8));   /* EX_AC */
349*44704f69SBart Van Assche                 printf("      %s: %d\n", pr_type_strs[1],
350*44704f69SBart Van Assche                        !!(pr_buff[4] & 0x2));   /* WR_EX */
351*44704f69SBart Van Assche                 printf("      %s: %d\n", pr_type_strs[8],
352*44704f69SBart Van Assche                        !!(pr_buff[5] & 0x1));   /* EX_AC_AR */
353*44704f69SBart Van Assche             }
354*44704f69SBart Van Assche         }
355*44704f69SBart Van Assche     } else {
356*44704f69SBart Van Assche         pr_gen =  sg_get_unaligned_be32(pr_buff + 0);
357*44704f69SBart Van Assche         add_len = sg_get_unaligned_be32(pr_buff + 4);
358*44704f69SBart Van Assche         if (op->hex) {
359*44704f69SBart Van Assche             if (op->hex > 1)
360*44704f69SBart Van Assche                 hex2stdout(pr_buff, add_len + 8, ((2 == op->hex) ? 1 : -1));
361*44704f69SBart Van Assche             else {
362*44704f69SBart Van Assche                 printf("  PR generation=0x%x, ", pr_gen);
363*44704f69SBart Van Assche                 if (add_len <= 0)
364*44704f69SBart Van Assche                     printf("Additional length=%d\n", add_len);
365*44704f69SBart Van Assche                 if ((uint32_t)add_len > (op->alloc_len - 8)) {
366*44704f69SBart Van Assche                     printf("Additional length too large=%d, truncate\n",
367*44704f69SBart Van Assche                            add_len);
368*44704f69SBart Van Assche                     hex2stdout((pr_buff + 8), op->alloc_len - 8, 1);
369*44704f69SBart Van Assche                 } else {
370*44704f69SBart Van Assche                     printf("Additional length=%d\n", add_len);
371*44704f69SBart Van Assche                     hex2stdout((pr_buff + 8), add_len, 1);
372*44704f69SBart Van Assche                 }
373*44704f69SBart Van Assche             }
374*44704f69SBart Van Assche         } else if (PRIN_RKEY_SA == op->prin_sa) {
375*44704f69SBart Van Assche             printf("  PR generation=0x%x, ", pr_gen);
376*44704f69SBart Van Assche             num = add_len / 8;
377*44704f69SBart Van Assche             if (num > 0) {
378*44704f69SBart Van Assche                 if (1 == num)
379*44704f69SBart Van Assche                     printf("1 registered reservation key follows:\n");
380*44704f69SBart Van Assche                 else
381*44704f69SBart Van Assche                     printf("%d registered reservation keys follow:\n", num);
382*44704f69SBart Van Assche                 bp = pr_buff + 8;
383*44704f69SBart Van Assche                 for (k = 0; k < num; ++k, bp += 8)
384*44704f69SBart Van Assche                     printf("    0x%" PRIx64 "\n",
385*44704f69SBart Van Assche                            sg_get_unaligned_be64(bp + 0));
386*44704f69SBart Van Assche             } else
387*44704f69SBart Van Assche                 printf("there are NO registered reservation keys\n");
388*44704f69SBart Van Assche         } else if (PRIN_RRES_SA == op->prin_sa) {
389*44704f69SBart Van Assche             printf("  PR generation=0x%x, ", pr_gen);
390*44704f69SBart Van Assche             num = add_len / 16;
391*44704f69SBart Van Assche             if (num > 0) {
392*44704f69SBart Van Assche                 printf("Reservation follows:\n");
393*44704f69SBart Van Assche                 bp = pr_buff + 8;
394*44704f69SBart Van Assche                 printf("    Key=0x%" PRIx64 "\n", sg_get_unaligned_be64(bp));
395*44704f69SBart Van Assche                 j = ((bp[13] >> 4) & 0xf);
396*44704f69SBart Van Assche                 if (0 == j)
397*44704f69SBart Van Assche                     printf("    scope: LU_SCOPE, ");
398*44704f69SBart Van Assche                 else
399*44704f69SBart Van Assche                     printf("    scope: %d ", j);
400*44704f69SBart Van Assche                 j = (bp[13] & 0xf);
401*44704f69SBart Van Assche                 printf(" type: %s\n", pr_type_strs[j]);
402*44704f69SBart Van Assche             } else
403*44704f69SBart Van Assche                 printf("there is NO reservation held\n");
404*44704f69SBart Van Assche         } else if (PRIN_RFSTAT_SA == op->prin_sa) {
405*44704f69SBart Van Assche             printf("  PR generation=0x%x\n", pr_gen);
406*44704f69SBart Van Assche             bp = pr_buff + 8;
407*44704f69SBart Van Assche             if (0 == add_len) {
408*44704f69SBart Van Assche                 printf("  No full status descriptors\n");
409*44704f69SBart Van Assche                 if (op->verbose)
410*44704f69SBart Van Assche                 printf("  So there are no registered IT nexuses\n");
411*44704f69SBart Van Assche             }
412*44704f69SBart Van Assche             for (k = 0; k < add_len; k += num, bp += num) {
413*44704f69SBart Van Assche                 add_desc_len = sg_get_unaligned_be32(bp + 20);
414*44704f69SBart Van Assche                 num = 24 + add_desc_len;
415*44704f69SBart Van Assche                 printf("    Key=0x%" PRIx64 "\n", sg_get_unaligned_be64(bp));
416*44704f69SBart Van Assche                 if (bp[12] & 0x2)
417*44704f69SBart Van Assche                     printf("      All target ports bit set\n");
418*44704f69SBart Van Assche                 else {
419*44704f69SBart Van Assche                     printf("      All target ports bit clear\n");
420*44704f69SBart Van Assche                     printf("      Relative port address: 0x%x\n",
421*44704f69SBart Van Assche                            sg_get_unaligned_be16(bp + 18));
422*44704f69SBart Van Assche                 }
423*44704f69SBart Van Assche                 if (bp[12] & 0x1) {
424*44704f69SBart Van Assche                     printf("      << Reservation holder >>\n");
425*44704f69SBart Van Assche                     j = ((bp[13] >> 4) & 0xf);
426*44704f69SBart Van Assche                     if (0 == j)
427*44704f69SBart Van Assche                         printf("      scope: LU_SCOPE, ");
428*44704f69SBart Van Assche                     else
429*44704f69SBart Van Assche                         printf("      scope: %d ", j);
430*44704f69SBart Van Assche                     j = (bp[13] & 0xf);
431*44704f69SBart Van Assche                     printf(" type: %s\n", pr_type_strs[j]);
432*44704f69SBart Van Assche                 } else
433*44704f69SBart Van Assche                     printf("      not reservation holder\n");
434*44704f69SBart Van Assche                 if (add_desc_len > 0) {
435*44704f69SBart Van Assche                     char b[1024];
436*44704f69SBart Van Assche 
437*44704f69SBart Van Assche                     printf("%s", sg_decode_transportid_str("      ", bp + 24,
438*44704f69SBart Van Assche                                         add_desc_len, true, sizeof(b), b));
439*44704f69SBart Van Assche                 }
440*44704f69SBart Van Assche             }
441*44704f69SBart Van Assche         }
442*44704f69SBart Van Assche     }
443*44704f69SBart Van Assche fini:
444*44704f69SBart Van Assche     if (free_pr_buff)
445*44704f69SBart Van Assche         free(free_pr_buff);
446*44704f69SBart Van Assche     return res;
447*44704f69SBart Van Assche }
448*44704f69SBart Van Assche 
449*44704f69SBart Van Assche /* Compact the 2 dimensional transportid_arr into a one dimensional
450*44704f69SBart Van Assche  * array in place returning the length. */
451*44704f69SBart Van Assche static int
compact_transportid_array(struct opts_t * op)452*44704f69SBart Van Assche compact_transportid_array(struct opts_t * op)
453*44704f69SBart Van Assche {
454*44704f69SBart Van Assche     int k, off, protocol_id, len;
455*44704f69SBart Van Assche     int compact_len = 0;
456*44704f69SBart Van Assche     uint8_t * bp = op->transportid_arr;
457*44704f69SBart Van Assche 
458*44704f69SBart Van Assche     for (k = 0, off = 0; ((k < op->num_transportids) && (k < MX_TIDS));
459*44704f69SBart Van Assche          ++k, off += MX_TID_LEN) {
460*44704f69SBart Van Assche         protocol_id = bp[off] & 0xf;
461*44704f69SBart Van Assche         if (TPROTO_ISCSI == protocol_id) {
462*44704f69SBart Van Assche             len = sg_get_unaligned_be16(bp + off + 2) + 4;
463*44704f69SBart Van Assche             if (len < 24)
464*44704f69SBart Van Assche                 len = 24;
465*44704f69SBart Van Assche             if (off > compact_len)
466*44704f69SBart Van Assche                 memmove(bp + compact_len, bp + off, len);
467*44704f69SBart Van Assche             compact_len += len;
468*44704f69SBart Van Assche 
469*44704f69SBart Van Assche         } else {
470*44704f69SBart Van Assche             if (off > compact_len)
471*44704f69SBart Van Assche                 memmove(bp + compact_len, bp + off, 24);
472*44704f69SBart Van Assche             compact_len += 24;
473*44704f69SBart Van Assche         }
474*44704f69SBart Van Assche     }
475*44704f69SBart Van Assche     return compact_len;
476*44704f69SBart Van Assche }
477*44704f69SBart Van Assche 
478*44704f69SBart Van Assche static int
prout_work(int sg_fd,struct opts_t * op)479*44704f69SBart Van Assche prout_work(int sg_fd, struct opts_t * op)
480*44704f69SBart Van Assche {
481*44704f69SBart Van Assche     int len, t_arr_len;
482*44704f69SBart Van Assche     int res = 0;
483*44704f69SBart Van Assche     uint8_t * pr_buff = NULL;
484*44704f69SBart Van Assche     uint8_t * free_pr_buff = NULL;
485*44704f69SBart Van Assche     char b[64];
486*44704f69SBart Van Assche     char bb[80];
487*44704f69SBart Van Assche 
488*44704f69SBart Van Assche     t_arr_len = compact_transportid_array(op);
489*44704f69SBart Van Assche     pr_buff = sg_memalign(op->alloc_len, 0 /* page aligned */, &free_pr_buff,
490*44704f69SBart Van Assche                           false);
491*44704f69SBart Van Assche     if (NULL == pr_buff) {
492*44704f69SBart Van Assche         pr2serr("%s: unable to allocate %d bytes on heap\n", __func__,
493*44704f69SBart Van Assche                 op->alloc_len);
494*44704f69SBart Van Assche         return sg_convert_errno(ENOMEM);
495*44704f69SBart Van Assche     }
496*44704f69SBart Van Assche     sg_put_unaligned_be64(op->param_rk, pr_buff + 0);
497*44704f69SBart Van Assche     sg_put_unaligned_be64(op->param_sark, pr_buff + 8);
498*44704f69SBart Van Assche     if (op->param_alltgpt)
499*44704f69SBart Van Assche         pr_buff[20] |= 0x4;
500*44704f69SBart Van Assche     if (op->param_aptpl)
501*44704f69SBart Van Assche         pr_buff[20] |= 0x1;
502*44704f69SBart Van Assche     len = 24;
503*44704f69SBart Van Assche     if (t_arr_len > 0) {
504*44704f69SBart Van Assche         pr_buff[20] |= 0x8;     /* set SPEC_I_PT bit */
505*44704f69SBart Van Assche         memcpy(&pr_buff[28], op->transportid_arr, t_arr_len);
506*44704f69SBart Van Assche         len += (t_arr_len + 4);
507*44704f69SBart Van Assche         sg_put_unaligned_be32((uint32_t)t_arr_len, pr_buff + 24);
508*44704f69SBart Van Assche     }
509*44704f69SBart Van Assche     res = sg_ll_persistent_reserve_out(sg_fd, op->prout_sa, 0 /* rq_scope */,
510*44704f69SBart Van Assche                                        op->prout_type, pr_buff, len, true,
511*44704f69SBart Van Assche                                        op->verbose);
512*44704f69SBart Van Assche     if (res || op->verbose) {
513*44704f69SBart Van Assche         if (op->prout_sa < num_prout_sa_strs)
514*44704f69SBart Van Assche             snprintf(b, sizeof(b), "%s", prout_sa_strs[op->prout_sa]);
515*44704f69SBart Van Assche         else
516*44704f69SBart Van Assche             snprintf(b, sizeof(b), "service action=0x%x", op->prout_sa);
517*44704f69SBart Van Assche         if (res) {
518*44704f69SBart Van Assche             if (SG_LIB_CAT_INVALID_OP == res)
519*44704f69SBart Van Assche                 pr2serr("PR out (%s): command not supported\n", b);
520*44704f69SBart Van Assche             else if (SG_LIB_CAT_ILLEGAL_REQ == res)
521*44704f69SBart Van Assche                 pr2serr("PR out (%s): bad field in cdb or parameter list "
522*44704f69SBart Van Assche                         "(perhaps unsupported service action)\n", b);
523*44704f69SBart Van Assche             else {
524*44704f69SBart Van Assche                 sg_get_category_sense_str(res, sizeof(bb), bb, op->verbose);
525*44704f69SBart Van Assche                 pr2serr("PR out (%s): %s\n", b, bb);
526*44704f69SBart Van Assche             }
527*44704f69SBart Van Assche             goto fini;
528*44704f69SBart Van Assche         } else if (op->verbose)
529*44704f69SBart Van Assche             pr2serr("PR out: command (%s) successful\n", b);
530*44704f69SBart Van Assche     }
531*44704f69SBart Van Assche fini:
532*44704f69SBart Van Assche     if (free_pr_buff)
533*44704f69SBart Van Assche         free(free_pr_buff);
534*44704f69SBart Van Assche     return res;
535*44704f69SBart Van Assche }
536*44704f69SBart Van Assche 
537*44704f69SBart Van Assche static int
prout_reg_move_work(int sg_fd,struct opts_t * op)538*44704f69SBart Van Assche prout_reg_move_work(int sg_fd, struct opts_t * op)
539*44704f69SBart Van Assche {
540*44704f69SBart Van Assche     int len, t_arr_len;
541*44704f69SBart Van Assche     int res = 0;
542*44704f69SBart Van Assche     uint8_t * pr_buff = NULL;
543*44704f69SBart Van Assche     uint8_t * free_pr_buff = NULL;
544*44704f69SBart Van Assche 
545*44704f69SBart Van Assche     t_arr_len = compact_transportid_array(op);
546*44704f69SBart Van Assche     pr_buff = sg_memalign(op->alloc_len, 0 /* page aligned */, &free_pr_buff,
547*44704f69SBart Van Assche                           false);
548*44704f69SBart Van Assche     if (NULL == pr_buff) {
549*44704f69SBart Van Assche         pr2serr("%s: unable to allocate %d bytes on heap\n", __func__,
550*44704f69SBart Van Assche                 op->alloc_len);
551*44704f69SBart Van Assche         return sg_convert_errno(ENOMEM);
552*44704f69SBart Van Assche     }
553*44704f69SBart Van Assche     sg_put_unaligned_be64(op->param_rk, pr_buff + 0);
554*44704f69SBart Van Assche     sg_put_unaligned_be64(op->param_sark, pr_buff + 8);
555*44704f69SBart Van Assche     if (op->param_unreg)
556*44704f69SBart Van Assche         pr_buff[17] |= 0x2;
557*44704f69SBart Van Assche     if (op->param_aptpl)
558*44704f69SBart Van Assche         pr_buff[17] |= 0x1;
559*44704f69SBart Van Assche     sg_put_unaligned_be16(op->param_rtp, pr_buff + 18);
560*44704f69SBart Van Assche     len = 24;
561*44704f69SBart Van Assche     if (t_arr_len > 0) {
562*44704f69SBart Van Assche         memcpy(&pr_buff[24], op->transportid_arr, t_arr_len);
563*44704f69SBart Van Assche         len += t_arr_len;
564*44704f69SBart Van Assche         sg_put_unaligned_be32((uint32_t)t_arr_len, pr_buff + 20);
565*44704f69SBart Van Assche     }
566*44704f69SBart Van Assche     res = sg_ll_persistent_reserve_out(sg_fd, PROUT_REG_MOVE_SA,
567*44704f69SBart Van Assche                                        0 /* rq_scope */, op->prout_type,
568*44704f69SBart Van Assche                                        pr_buff, len, true, op->verbose);
569*44704f69SBart Van Assche     if (res) {
570*44704f69SBart Van Assche        if (SG_LIB_CAT_INVALID_OP == res)
571*44704f69SBart Van Assche             pr2serr("PR out (register and move): command not supported\n");
572*44704f69SBart Van Assche         else if (SG_LIB_CAT_ILLEGAL_REQ == res)
573*44704f69SBart Van Assche             pr2serr("PR out (register and move): bad field in cdb or "
574*44704f69SBart Van Assche                     "parameter list (perhaps unsupported service action)\n");
575*44704f69SBart Van Assche         else {
576*44704f69SBart Van Assche             char bb[80];
577*44704f69SBart Van Assche 
578*44704f69SBart Van Assche             sg_get_category_sense_str(res, sizeof(bb), bb, op->verbose);
579*44704f69SBart Van Assche             pr2serr("PR out (register and move): %s\n", bb);
580*44704f69SBart Van Assche         }
581*44704f69SBart Van Assche         goto fini;
582*44704f69SBart Van Assche     } else if (op->verbose)
583*44704f69SBart Van Assche         pr2serr("PR out: 'register and move' command successful\n");
584*44704f69SBart Van Assche fini:
585*44704f69SBart Van Assche     if (free_pr_buff)
586*44704f69SBart Van Assche         free(free_pr_buff);
587*44704f69SBart Van Assche     return res;
588*44704f69SBart Van Assche }
589*44704f69SBart Van Assche 
590*44704f69SBart Van Assche /* Decode various symbolic forms of TransportIDs into SPC-4 format.
591*44704f69SBart Van Assche  * Returns 1 if one found, else returns 0. */
592*44704f69SBart Van Assche static int
decode_sym_transportid(const char * lcp,uint8_t * tidp)593*44704f69SBart Van Assche decode_sym_transportid(const char * lcp, uint8_t * tidp)
594*44704f69SBart Van Assche {
595*44704f69SBart Van Assche     int k, j, n, b, c, len, alen;
596*44704f69SBart Van Assche     unsigned int ui;
597*44704f69SBart Van Assche     const char * ecp;
598*44704f69SBart Van Assche     const char * isip;
599*44704f69SBart Van Assche 
600*44704f69SBart Van Assche     memset(tidp, 0, 24);
601*44704f69SBart Van Assche     if ((0 == memcmp("sas,", lcp, 4)) || (0 == memcmp("SAS,", lcp, 4))) {
602*44704f69SBart Van Assche         lcp += 4;
603*44704f69SBart Van Assche         k = strspn(lcp, "0123456789aAbBcCdDeEfF");
604*44704f69SBart Van Assche         if (16 != k) {
605*44704f69SBart Van Assche             pr2serr("badly formed symbolic SAS TransportID: %s\n", lcp);
606*44704f69SBart Van Assche             return 0;
607*44704f69SBart Van Assche         }
608*44704f69SBart Van Assche         tidp[0] = TPROTO_SAS;
609*44704f69SBart Van Assche         for (k = 0, j = 0, b = 0; k < 16; ++k) {
610*44704f69SBart Van Assche             c = lcp[k];
611*44704f69SBart Van Assche             if (isdigit(c))
612*44704f69SBart Van Assche                 n = c - 0x30;
613*44704f69SBart Van Assche             else if (isupper(c))
614*44704f69SBart Van Assche                 n = c - 0x37;
615*44704f69SBart Van Assche             else
616*44704f69SBart Van Assche                 n = c - 0x57;
617*44704f69SBart Van Assche             if (k & 1) {
618*44704f69SBart Van Assche                 tidp[4 + j] = b | n;
619*44704f69SBart Van Assche                 ++j;
620*44704f69SBart Van Assche             } else
621*44704f69SBart Van Assche                 b = n << 4;
622*44704f69SBart Van Assche         }
623*44704f69SBart Van Assche         return 1;
624*44704f69SBart Van Assche     } else if ((0 == memcmp("spi,", lcp, 4)) ||
625*44704f69SBart Van Assche                (0 == memcmp("SPI,", lcp, 4))) {
626*44704f69SBart Van Assche         lcp += 4;
627*44704f69SBart Van Assche         if (2 != sscanf(lcp, "%d,%d", &b, &c)) {
628*44704f69SBart Van Assche             pr2serr("badly formed symbolic SPI TransportID: %s\n", lcp);
629*44704f69SBart Van Assche             return 0;
630*44704f69SBart Van Assche         }
631*44704f69SBart Van Assche         tidp[0] = TPROTO_SPI;
632*44704f69SBart Van Assche         sg_put_unaligned_be16((uint16_t)b, tidp + 2);
633*44704f69SBart Van Assche         sg_put_unaligned_be16((uint16_t)c, tidp + 6);
634*44704f69SBart Van Assche         return 1;
635*44704f69SBart Van Assche     } else if ((0 == memcmp("fcp,", lcp, 4)) ||
636*44704f69SBart Van Assche                (0 == memcmp("FCP,", lcp, 4))) {
637*44704f69SBart Van Assche         lcp += 4;
638*44704f69SBart Van Assche         k = strspn(lcp, "0123456789aAbBcCdDeEfF");
639*44704f69SBart Van Assche         if (16 != k) {
640*44704f69SBart Van Assche             pr2serr("badly formed symbolic FCP TransportID: %s\n", lcp);
641*44704f69SBart Van Assche             return 0;
642*44704f69SBart Van Assche         }
643*44704f69SBart Van Assche         tidp[0] = TPROTO_FCP;
644*44704f69SBart Van Assche         for (k = 0, j = 0, b = 0; k < 16; ++k) {
645*44704f69SBart Van Assche             c = lcp[k];
646*44704f69SBart Van Assche             if (isdigit(c))
647*44704f69SBart Van Assche                 n = c - 0x30;
648*44704f69SBart Van Assche             else if (isupper(c))
649*44704f69SBart Van Assche                 n = c - 0x37;
650*44704f69SBart Van Assche             else
651*44704f69SBart Van Assche                 n = c - 0x57;
652*44704f69SBart Van Assche             if (k & 1) {
653*44704f69SBart Van Assche                 tidp[8 + j] = b | n;
654*44704f69SBart Van Assche                 ++j;
655*44704f69SBart Van Assche             } else
656*44704f69SBart Van Assche                 b = n << 4;
657*44704f69SBart Van Assche         }
658*44704f69SBart Van Assche         return 1;
659*44704f69SBart Van Assche     } else if ((0 == memcmp("sbp,", lcp, 4)) ||
660*44704f69SBart Van Assche                (0 == memcmp("SBP,", lcp, 4))) {
661*44704f69SBart Van Assche         lcp += 4;
662*44704f69SBart Van Assche         k = strspn(lcp, "0123456789aAbBcCdDeEfF");
663*44704f69SBart Van Assche         if (16 != k) {
664*44704f69SBart Van Assche             pr2serr("badly formed symbolic SBP TransportID: %s\n", lcp);
665*44704f69SBart Van Assche             return 0;
666*44704f69SBart Van Assche         }
667*44704f69SBart Van Assche         tidp[0] = TPROTO_1394;
668*44704f69SBart Van Assche         for (k = 0, j = 0, b = 0; k < 16; ++k) {
669*44704f69SBart Van Assche             c = lcp[k];
670*44704f69SBart Van Assche             if (isdigit(c))
671*44704f69SBart Van Assche                 n = c - 0x30;
672*44704f69SBart Van Assche             else if (isupper(c))
673*44704f69SBart Van Assche                 n = c - 0x37;
674*44704f69SBart Van Assche             else
675*44704f69SBart Van Assche                 n = c - 0x57;
676*44704f69SBart Van Assche             if (k & 1) {
677*44704f69SBart Van Assche                 tidp[8 + j] = b | n;
678*44704f69SBart Van Assche                 ++j;
679*44704f69SBart Van Assche             } else
680*44704f69SBart Van Assche                 b = n << 4;
681*44704f69SBart Van Assche         }
682*44704f69SBart Van Assche         return 1;
683*44704f69SBart Van Assche     } else if ((0 == memcmp("srp,", lcp, 4)) ||
684*44704f69SBart Van Assche                (0 == memcmp("SRP,", lcp, 4))) {
685*44704f69SBart Van Assche         lcp += 4;
686*44704f69SBart Van Assche         k = strspn(lcp, "0123456789aAbBcCdDeEfF");
687*44704f69SBart Van Assche         if (16 != k) {
688*44704f69SBart Van Assche             pr2serr("badly formed symbolic SRP TransportID: %s\n", lcp);
689*44704f69SBart Van Assche             return 0;
690*44704f69SBart Van Assche         }
691*44704f69SBart Van Assche         tidp[0] = TPROTO_SRP;
692*44704f69SBart Van Assche         for (k = 0, j = 0, b = 0; k < 32; ++k) {
693*44704f69SBart Van Assche             c = lcp[k];
694*44704f69SBart Van Assche             if (isdigit(c))
695*44704f69SBart Van Assche                 n = c - 0x30;
696*44704f69SBart Van Assche             else if (isupper(c))
697*44704f69SBart Van Assche                 n = c - 0x37;
698*44704f69SBart Van Assche             else
699*44704f69SBart Van Assche                 n = c - 0x57;
700*44704f69SBart Van Assche             if (k & 1) {
701*44704f69SBart Van Assche                 tidp[8 + j] = b | n;
702*44704f69SBart Van Assche                 ++j;
703*44704f69SBart Van Assche             } else
704*44704f69SBart Van Assche                 b = n << 4;
705*44704f69SBart Van Assche         }
706*44704f69SBart Van Assche         return 1;
707*44704f69SBart Van Assche     } else if (0 == memcmp("iqn.", lcp, 4)) {
708*44704f69SBart Van Assche         ecp = strpbrk(lcp, " \t");
709*44704f69SBart Van Assche         isip = strstr(lcp, ",i,0x");
710*44704f69SBart Van Assche         if (ecp && (isip > ecp))
711*44704f69SBart Van Assche             isip = NULL;
712*44704f69SBart Van Assche         len = ecp ? (ecp - lcp) : (int)strlen(lcp);
713*44704f69SBart Van Assche         tidp[0] = TPROTO_ISCSI | (isip ? 0x40 : 0x0);
714*44704f69SBart Van Assche         alen = len + 1; /* at least one trailing null */
715*44704f69SBart Van Assche         if (alen < 20)
716*44704f69SBart Van Assche             alen = 20;
717*44704f69SBart Van Assche         else if (0 != (alen % 4))
718*44704f69SBart Van Assche             alen = ((alen / 4) + 1) * 4;
719*44704f69SBart Van Assche         if (alen > 241) { /* sam5r02.pdf A.2 (Annex) */
720*44704f69SBart Van Assche             pr2serr("iSCSI name too long, alen=%d\n", alen);
721*44704f69SBart Van Assche             return 0;
722*44704f69SBart Van Assche         }
723*44704f69SBart Van Assche         tidp[3] = alen & 0xff;
724*44704f69SBart Van Assche         memcpy(tidp + 4, lcp, len);
725*44704f69SBart Van Assche         return 1;
726*44704f69SBart Van Assche     } else if ((0 == memcmp("sop,", lcp, 4)) ||
727*44704f69SBart Van Assche                (0 == memcmp("SOP,", lcp, 4))) {
728*44704f69SBart Van Assche         lcp += 4;
729*44704f69SBart Van Assche         if (2 != sscanf(lcp, "%x", &ui)) {
730*44704f69SBart Van Assche             pr2serr("badly formed symbolic SOP TransportID: %s\n", lcp);
731*44704f69SBart Van Assche             return 0;
732*44704f69SBart Van Assche         }
733*44704f69SBart Van Assche         tidp[0] = TPROTO_SOP;
734*44704f69SBart Van Assche         sg_put_unaligned_be16((uint16_t)ui, tidp + 2);
735*44704f69SBart Van Assche         return 1;
736*44704f69SBart Van Assche     }
737*44704f69SBart Van Assche     pr2serr("unable to parse symbolic TransportID: %s\n", lcp);
738*44704f69SBart Van Assche     return 0;
739*44704f69SBart Van Assche }
740*44704f69SBart Van Assche 
741*44704f69SBart Van Assche /* Read one or more TransportIDs from the given file or stdin. Reads from
742*44704f69SBart Van Assche  * stdin when 'fnp' is NULL. Returns 0 if successful, 1 otherwise. */
743*44704f69SBart Van Assche static int
decode_file_tids(const char * fnp,struct opts_t * op)744*44704f69SBart Van Assche decode_file_tids(const char * fnp, struct opts_t * op)
745*44704f69SBart Van Assche {
746*44704f69SBart Van Assche     bool split_line;
747*44704f69SBart Van Assche     int in_len, k, j, m;
748*44704f69SBart Van Assche     int off = 0;
749*44704f69SBart Van Assche     int num = 0;
750*44704f69SBart Van Assche     unsigned int h;
751*44704f69SBart Van Assche     FILE * fp = stdin;
752*44704f69SBart Van Assche     const char * lcp;
753*44704f69SBart Van Assche     uint8_t * tid_arr = op->transportid_arr;
754*44704f69SBart Van Assche     char line[1024];
755*44704f69SBart Van Assche     char carry_over[4];
756*44704f69SBart Van Assche 
757*44704f69SBart Van Assche     if (fnp) {
758*44704f69SBart Van Assche         fp = fopen(fnp, "r");
759*44704f69SBart Van Assche         if (NULL == fp) {
760*44704f69SBart Van Assche             pr2serr("%s: unable to open %s\n", __func__, fnp);
761*44704f69SBart Van Assche             return 1;
762*44704f69SBart Van Assche         }
763*44704f69SBart Van Assche     }
764*44704f69SBart Van Assche     carry_over[0] = 0;
765*44704f69SBart Van Assche     for (j = 0, off = 0; j < 512; ++j) {
766*44704f69SBart Van Assche         if (NULL == fgets(line, sizeof(line), fp))
767*44704f69SBart Van Assche             break;
768*44704f69SBart Van Assche         in_len = strlen(line);
769*44704f69SBart Van Assche         if (in_len > 0) {
770*44704f69SBart Van Assche             if ('\n' == line[in_len - 1]) {
771*44704f69SBart Van Assche                 --in_len;
772*44704f69SBart Van Assche                 line[in_len] = '\0';
773*44704f69SBart Van Assche                 split_line = false;
774*44704f69SBart Van Assche             } else
775*44704f69SBart Van Assche                 split_line = true;
776*44704f69SBart Van Assche         }
777*44704f69SBart Van Assche         if (in_len < 1) {
778*44704f69SBart Van Assche             carry_over[0] = 0;
779*44704f69SBart Van Assche             continue;
780*44704f69SBart Van Assche         }
781*44704f69SBart Van Assche         if (carry_over[0]) {
782*44704f69SBart Van Assche             if (isxdigit((uint8_t)line[0])) {
783*44704f69SBart Van Assche                 carry_over[1] = line[0];
784*44704f69SBart Van Assche                 carry_over[2] = '\0';
785*44704f69SBart Van Assche                 if (1 == sscanf(carry_over, "%x", &h))
786*44704f69SBart Van Assche                     tid_arr[off - 1] = h;       /* back up and overwrite */
787*44704f69SBart Van Assche                 else {
788*44704f69SBart Van Assche                     pr2serr("%s: carry_over error ['%s'] around line %d\n",
789*44704f69SBart Van Assche                             __func__, carry_over, j + 1);
790*44704f69SBart Van Assche                     goto bad;
791*44704f69SBart Van Assche                 }
792*44704f69SBart Van Assche                 lcp = line + 1;
793*44704f69SBart Van Assche                 --in_len;
794*44704f69SBart Van Assche             } else
795*44704f69SBart Van Assche                 lcp = line;
796*44704f69SBart Van Assche             carry_over[0] = 0;
797*44704f69SBart Van Assche         } else
798*44704f69SBart Van Assche             lcp = line;
799*44704f69SBart Van Assche         m = strspn(lcp, " \t");
800*44704f69SBart Van Assche         if (m == in_len)
801*44704f69SBart Van Assche             continue;
802*44704f69SBart Van Assche         lcp += m;
803*44704f69SBart Van Assche         in_len -= m;
804*44704f69SBart Van Assche         if ('#' == *lcp)
805*44704f69SBart Van Assche             continue;
806*44704f69SBart Van Assche         if (decode_sym_transportid(lcp, tid_arr + off))
807*44704f69SBart Van Assche             goto my_cont_a;
808*44704f69SBart Van Assche         k = strspn(lcp, "0123456789aAbBcCdDeEfF ,\t");
809*44704f69SBart Van Assche         if ((k < in_len) && ('#' != lcp[k])) {
810*44704f69SBart Van Assche             pr2serr("%s: syntax error at line %d, pos %d\n", __func__, j + 1,
811*44704f69SBart Van Assche                     m + k + 1);
812*44704f69SBart Van Assche             goto bad;
813*44704f69SBart Van Assche         }
814*44704f69SBart Van Assche         for (k = 0; k < 1024; ++k) {
815*44704f69SBart Van Assche             if (1 == sscanf(lcp, "%x", &h)) {
816*44704f69SBart Van Assche                 if (h > 0xff) {
817*44704f69SBart Van Assche                     pr2serr("%s: hex number larger than 0xff in line %d, pos "
818*44704f69SBart Van Assche                             "%d\n", __func__, j + 1, (int)(lcp - line + 1));
819*44704f69SBart Van Assche                     goto bad;
820*44704f69SBart Van Assche                 }
821*44704f69SBart Van Assche                 if (split_line && (1 == strlen(lcp))) {
822*44704f69SBart Van Assche                     /* single trailing hex digit might be a split pair */
823*44704f69SBart Van Assche                     carry_over[0] = *lcp;
824*44704f69SBart Van Assche                 }
825*44704f69SBart Van Assche                 if ((off + k) >= (int)sizeof(op->transportid_arr)) {
826*44704f69SBart Van Assche                     pr2serr("%s: array length exceeded\n", __func__);
827*44704f69SBart Van Assche                     goto bad;
828*44704f69SBart Van Assche                 }
829*44704f69SBart Van Assche                 op->transportid_arr[off + k] = h;/* keep code checker happy */
830*44704f69SBart Van Assche                 lcp = strpbrk(lcp, " ,\t");
831*44704f69SBart Van Assche                 if (NULL == lcp)
832*44704f69SBart Van Assche                     break;
833*44704f69SBart Van Assche                 lcp += strspn(lcp, " ,\t");
834*44704f69SBart Van Assche                 if ('\0' == *lcp)
835*44704f69SBart Van Assche                     break;
836*44704f69SBart Van Assche             } else {
837*44704f69SBart Van Assche                 if ('#' == *lcp) {
838*44704f69SBart Van Assche                     --k;
839*44704f69SBart Van Assche                     break;
840*44704f69SBart Van Assche                 }
841*44704f69SBart Van Assche                 pr2serr("%s: error in line %d, at pos %d\n", __func__, j + 1,
842*44704f69SBart Van Assche                         (int)(lcp - line + 1));
843*44704f69SBart Van Assche                 goto bad;
844*44704f69SBart Van Assche             }
845*44704f69SBart Van Assche         }
846*44704f69SBart Van Assche my_cont_a:
847*44704f69SBart Van Assche         off += MX_TID_LEN;
848*44704f69SBart Van Assche         if (off >= (MX_TIDS * MX_TID_LEN)) {
849*44704f69SBart Van Assche             pr2serr("%s: array length exceeded\n", __func__);
850*44704f69SBart Van Assche             goto bad;
851*44704f69SBart Van Assche         }
852*44704f69SBart Van Assche         ++num;
853*44704f69SBart Van Assche     }
854*44704f69SBart Van Assche     op->num_transportids = num;
855*44704f69SBart Van Assche    if (fnp)
856*44704f69SBart Van Assche         fclose(fp);
857*44704f69SBart Van Assche     return 0;
858*44704f69SBart Van Assche 
859*44704f69SBart Van Assche bad:
860*44704f69SBart Van Assche    if (fnp)
861*44704f69SBart Van Assche         fclose(fp);
862*44704f69SBart Van Assche    return 1;
863*44704f69SBart Van Assche }
864*44704f69SBart Van Assche 
865*44704f69SBart Van Assche /* Build transportid array which may contain one or more TransportIDs.
866*44704f69SBart Van Assche  * A single TransportID can appear on the command line either as a list of
867*44704f69SBart Van Assche  * comma (or single space) separated ASCII hex bytes, or in some transport
868*44704f69SBart Van Assche  * protocol specific form (e.g. "sas,5000c50005b32001"). One or more
869*44704f69SBart Van Assche  * TransportIDs may be given in a file (syntax: "file=<name>") or read from
870*44704f69SBart Van Assche  * stdin in (when "-" is given). Fuller description in manpage of
871*44704f69SBart Van Assche  * sg_persist(8). Returns 0 if successful, else 1 .
872*44704f69SBart Van Assche  */
873*44704f69SBart Van Assche static int
build_transportid(const char * inp,struct opts_t * op)874*44704f69SBart Van Assche build_transportid(const char * inp, struct opts_t * op)
875*44704f69SBart Van Assche {
876*44704f69SBart Van Assche     int in_len;
877*44704f69SBart Van Assche     int k = 0;
878*44704f69SBart Van Assche     unsigned int h;
879*44704f69SBart Van Assche     const char * lcp;
880*44704f69SBart Van Assche     uint8_t * tid_arr = op->transportid_arr;
881*44704f69SBart Van Assche     char * cp;
882*44704f69SBart Van Assche     char * c2p;
883*44704f69SBart Van Assche 
884*44704f69SBart Van Assche     lcp = inp;
885*44704f69SBart Van Assche     in_len = strlen(inp);
886*44704f69SBart Van Assche     if (0 == in_len) {
887*44704f69SBart Van Assche         op->num_transportids = 0;
888*44704f69SBart Van Assche     }
889*44704f69SBart Van Assche     if (('-' == inp[0]) ||
890*44704f69SBart Van Assche         (0 == memcmp("file=", inp, 5)) ||
891*44704f69SBart Van Assche         (0 == memcmp("FILE=", inp, 5))) {
892*44704f69SBart Van Assche         if ('-' == inp[0])
893*44704f69SBart Van Assche             lcp = NULL;         /* read from stdin */
894*44704f69SBart Van Assche         else
895*44704f69SBart Van Assche             lcp = inp + 5;      /* read from given file */
896*44704f69SBart Van Assche         return decode_file_tids(lcp, op);
897*44704f69SBart Van Assche     } else {        /* TransportID given directly on command line */
898*44704f69SBart Van Assche         if (decode_sym_transportid(lcp, tid_arr))
899*44704f69SBart Van Assche             goto my_cont_b;
900*44704f69SBart Van Assche         k = strspn(inp, "0123456789aAbBcCdDeEfF, ");
901*44704f69SBart Van Assche         if (in_len != k) {
902*44704f69SBart Van Assche             pr2serr("%s: error at pos %d\n", __func__, k + 1);
903*44704f69SBart Van Assche             return 1;
904*44704f69SBart Van Assche         }
905*44704f69SBart Van Assche         for (k = 0; k < (int)sizeof(op->transportid_arr); ++k) {
906*44704f69SBart Van Assche             if (1 == sscanf(lcp, "%x", &h)) {
907*44704f69SBart Van Assche                 if (h > 0xff) {
908*44704f69SBart Van Assche                     pr2serr("%s: hex number larger than 0xff at pos %d\n",
909*44704f69SBart Van Assche                             __func__, (int)(lcp - inp + 1));
910*44704f69SBart Van Assche                     return 1;
911*44704f69SBart Van Assche                 }
912*44704f69SBart Van Assche                 tid_arr[k] = h;
913*44704f69SBart Van Assche                 cp = (char *)strchr(lcp, ',');
914*44704f69SBart Van Assche                 c2p = (char *)strchr(lcp, ' ');
915*44704f69SBart Van Assche                 if (NULL == cp)
916*44704f69SBart Van Assche                     cp = c2p;
917*44704f69SBart Van Assche                 if (NULL == cp)
918*44704f69SBart Van Assche                     break;
919*44704f69SBart Van Assche                 if (c2p && (c2p < cp))
920*44704f69SBart Van Assche                     cp = c2p;
921*44704f69SBart Van Assche                 lcp = cp + 1;
922*44704f69SBart Van Assche             } else {
923*44704f69SBart Van Assche                 pr2serr("%s: error at pos %d\n", __func__,
924*44704f69SBart Van Assche                         (int)(lcp - inp + 1));
925*44704f69SBart Van Assche                 return 1;
926*44704f69SBart Van Assche             }
927*44704f69SBart Van Assche         }
928*44704f69SBart Van Assche my_cont_b:
929*44704f69SBart Van Assche         op->num_transportids = 1;
930*44704f69SBart Van Assche         if (k >= (int)sizeof(op->transportid_arr)) {
931*44704f69SBart Van Assche             pr2serr("%s: array length exceeded\n", __func__);
932*44704f69SBart Van Assche             return 1;
933*44704f69SBart Van Assche         }
934*44704f69SBart Van Assche     }
935*44704f69SBart Van Assche     return 0;
936*44704f69SBart Van Assche }
937*44704f69SBart Van Assche 
938*44704f69SBart Van Assche 
939*44704f69SBart Van Assche int
main(int argc,char * argv[])940*44704f69SBart Van Assche main(int argc, char * argv[])
941*44704f69SBart Van Assche {
942*44704f69SBart Van Assche     bool got_maxlen, ok;
943*44704f69SBart Van Assche     bool flagged = false;
944*44704f69SBart Van Assche     bool want_prin = false;
945*44704f69SBart Van Assche     bool want_prout = false;
946*44704f69SBart Van Assche     int c, k, res;
947*44704f69SBart Van Assche     int help = 0;
948*44704f69SBart Van Assche     int num_prin_sa = 0;
949*44704f69SBart Van Assche     int num_prout_sa = 0;
950*44704f69SBart Van Assche     int num_prout_param = 0;
951*44704f69SBart Van Assche     int peri_type = 0;
952*44704f69SBart Van Assche     int sg_fd = -1;
953*44704f69SBart Van Assche     int ret = 0;
954*44704f69SBart Van Assche     const char * cp;
955*44704f69SBart Van Assche     const char * device_name = NULL;
956*44704f69SBart Van Assche     struct opts_t * op;
957*44704f69SBart Van Assche     char buff[48];
958*44704f69SBart Van Assche     struct opts_t opts;
959*44704f69SBart Van Assche     struct sg_simple_inquiry_resp inq_resp;
960*44704f69SBart Van Assche 
961*44704f69SBart Van Assche     op = &opts;
962*44704f69SBart Van Assche     memset(op, 0, sizeof(opts));
963*44704f69SBart Van Assche     op->pr_in = true;
964*44704f69SBart Van Assche     op->prin_sa = -1;
965*44704f69SBart Van Assche     op->prout_sa = -1;
966*44704f69SBart Van Assche     op->inquiry = true;
967*44704f69SBart Van Assche     op->alloc_len = MX_ALLOC_LEN;
968*44704f69SBart Van Assche 
969*44704f69SBart Van Assche     while (1) {
970*44704f69SBart Van Assche         int option_index = 0;
971*44704f69SBart Van Assche 
972*44704f69SBart Van Assche         c = getopt_long(argc, argv,
973*44704f69SBart Van Assche                         "AcCd:GHhiIkK:l:Lm:MnoPQ:rRsS:T:UvVX:yYzZ",
974*44704f69SBart Van Assche                         long_options, &option_index);
975*44704f69SBart Van Assche         if (c == -1)
976*44704f69SBart Van Assche             break;
977*44704f69SBart Van Assche 
978*44704f69SBart Van Assche         switch (c) {
979*44704f69SBart Van Assche         case 'A':
980*44704f69SBart Van Assche             op->prout_sa = PROUT_PREE_AB_SA;
981*44704f69SBart Van Assche             ++num_prout_sa;
982*44704f69SBart Van Assche             break;
983*44704f69SBart Van Assche         case 'c':
984*44704f69SBart Van Assche             op->prin_sa = PRIN_RCAP_SA;
985*44704f69SBart Van Assche             ++num_prin_sa;
986*44704f69SBart Van Assche             break;
987*44704f69SBart Van Assche         case 'C':
988*44704f69SBart Van Assche             op->prout_sa = PROUT_CLEAR_SA;
989*44704f69SBart Van Assche             ++num_prout_sa;
990*44704f69SBart Van Assche             break;
991*44704f69SBart Van Assche         case 'd':
992*44704f69SBart Van Assche             device_name = optarg;
993*44704f69SBart Van Assche             break;
994*44704f69SBart Van Assche         case 'G':
995*44704f69SBart Van Assche             op->prout_sa = PROUT_REG_SA;
996*44704f69SBart Van Assche             ++num_prout_sa;
997*44704f69SBart Van Assche             break;
998*44704f69SBart Van Assche         case 'h':
999*44704f69SBart Van Assche             ++help;
1000*44704f69SBart Van Assche             break;
1001*44704f69SBart Van Assche         case 'H':
1002*44704f69SBart Van Assche             ++op->hex;
1003*44704f69SBart Van Assche             break;
1004*44704f69SBart Van Assche         case 'i':
1005*44704f69SBart Van Assche             want_prin = true;
1006*44704f69SBart Van Assche             break;
1007*44704f69SBart Van Assche         case 'I':
1008*44704f69SBart Van Assche             op->prout_sa = PROUT_REG_IGN_SA;
1009*44704f69SBart Van Assche             ++num_prout_sa;
1010*44704f69SBart Van Assche             break;
1011*44704f69SBart Van Assche         case 'k':
1012*44704f69SBart Van Assche             op->prin_sa = PRIN_RKEY_SA;
1013*44704f69SBart Van Assche             ++num_prin_sa;
1014*44704f69SBart Van Assche             break;
1015*44704f69SBart Van Assche         case 'K':
1016*44704f69SBart Van Assche             if (1 != sscanf(optarg, "%" SCNx64 "", &op->param_rk)) {
1017*44704f69SBart Van Assche                 pr2serr("bad argument to '--param-rk'\n");
1018*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1019*44704f69SBart Van Assche             }
1020*44704f69SBart Van Assche             ++num_prout_param;
1021*44704f69SBart Van Assche             break;
1022*44704f69SBart Van Assche         case 'm':       /* --maxlen= and --alloc_length= are similar */
1023*44704f69SBart Van Assche         case 'l':
1024*44704f69SBart Van Assche             got_maxlen = ('m' == c);
1025*44704f69SBart Van Assche             cp =  (got_maxlen ? "maxlen" : "alloc-length");
1026*44704f69SBart Van Assche             if (got_maxlen) {
1027*44704f69SBart Van Assche                 k = sg_get_num(optarg);
1028*44704f69SBart Van Assche                 ok = (-1 != k);
1029*44704f69SBart Van Assche                 op->alloc_len = (unsigned int)k;
1030*44704f69SBart Van Assche             } else
1031*44704f69SBart Van Assche                 ok = (1 == sscanf(optarg, "%x", &op->alloc_len));
1032*44704f69SBart Van Assche             if (! ok) {
1033*44704f69SBart Van Assche                 pr2serr("bad argument to '--%s'\n", cp);
1034*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1035*44704f69SBart Van Assche             } else if (MX_ALLOC_LEN < op->alloc_len) {
1036*44704f69SBart Van Assche                 pr2serr("'--%s' argument exceeds maximum value (%d)\n", cp,
1037*44704f69SBart Van Assche                         MX_ALLOC_LEN);
1038*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1039*44704f69SBart Van Assche             }
1040*44704f69SBart Van Assche             break;
1041*44704f69SBart Van Assche         case 'L':
1042*44704f69SBart Van Assche             op->prout_sa = PROUT_REL_SA;
1043*44704f69SBart Van Assche             ++num_prout_sa;
1044*44704f69SBart Van Assche             break;
1045*44704f69SBart Van Assche         case 'M':
1046*44704f69SBart Van Assche             op->prout_sa = PROUT_REG_MOVE_SA;
1047*44704f69SBart Van Assche             ++num_prout_sa;
1048*44704f69SBart Van Assche             break;
1049*44704f69SBart Van Assche         case 'n':
1050*44704f69SBart Van Assche             op->inquiry = false;
1051*44704f69SBart Van Assche             break;
1052*44704f69SBart Van Assche         case 'o':
1053*44704f69SBart Van Assche             want_prout = true;
1054*44704f69SBart Van Assche             break;
1055*44704f69SBart Van Assche         case 'P':
1056*44704f69SBart Van Assche             op->prout_sa = PROUT_PREE_SA;
1057*44704f69SBart Van Assche             ++num_prout_sa;
1058*44704f69SBart Van Assche             break;
1059*44704f69SBart Van Assche         case 'Q':
1060*44704f69SBart Van Assche             if (1 != sscanf(optarg, "%x", &op->param_rtp)) {
1061*44704f69SBart Van Assche                 pr2serr("bad argument to '--relative-target-port'\n");
1062*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1063*44704f69SBart Van Assche             }
1064*44704f69SBart Van Assche             if (op->param_rtp > 0xffff) {
1065*44704f69SBart Van Assche                 pr2serr("argument to '--relative-target-port' 0 to ffff "
1066*44704f69SBart Van Assche                         "inclusive\n");
1067*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1068*44704f69SBart Van Assche             }
1069*44704f69SBart Van Assche             ++num_prout_param;
1070*44704f69SBart Van Assche             break;
1071*44704f69SBart Van Assche         case 'r':
1072*44704f69SBart Van Assche             op->prin_sa = PRIN_RRES_SA;
1073*44704f69SBart Van Assche             ++num_prin_sa;
1074*44704f69SBart Van Assche             break;
1075*44704f69SBart Van Assche         case 'R':
1076*44704f69SBart Van Assche             op->prout_sa = PROUT_RES_SA;
1077*44704f69SBart Van Assche             ++num_prout_sa;
1078*44704f69SBart Van Assche             break;
1079*44704f69SBart Van Assche         case 's':
1080*44704f69SBart Van Assche             op->prin_sa = PRIN_RFSTAT_SA;
1081*44704f69SBart Van Assche             ++num_prin_sa;
1082*44704f69SBart Van Assche             break;
1083*44704f69SBart Van Assche         case 'S':
1084*44704f69SBart Van Assche             if (1 != sscanf(optarg, "%" SCNx64 "", &op->param_sark)) {
1085*44704f69SBart Van Assche                 pr2serr("bad argument to '--param-sark'\n");
1086*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1087*44704f69SBart Van Assche             }
1088*44704f69SBart Van Assche             ++num_prout_param;
1089*44704f69SBart Van Assche             break;
1090*44704f69SBart Van Assche         case 'T':
1091*44704f69SBart Van Assche             if (1 != sscanf(optarg, "%x", &op->prout_type)) {
1092*44704f69SBart Van Assche                 pr2serr("bad argument to '--prout-type'\n");
1093*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1094*44704f69SBart Van Assche             }
1095*44704f69SBart Van Assche             ++num_prout_param;
1096*44704f69SBart Van Assche             break;
1097*44704f69SBart Van Assche         case 'U':
1098*44704f69SBart Van Assche             op->param_unreg = true;
1099*44704f69SBart Van Assche             break;
1100*44704f69SBart Van Assche         case 'v':
1101*44704f69SBart Van Assche             op->verbose_given = true;
1102*44704f69SBart Van Assche             ++op->verbose;
1103*44704f69SBart Van Assche             break;
1104*44704f69SBart Van Assche         case 'V':
1105*44704f69SBart Van Assche             op->version_given = true;
1106*44704f69SBart Van Assche             break;
1107*44704f69SBart Van Assche         case 'X':
1108*44704f69SBart Van Assche             if (0 != build_transportid(optarg, op)) {
1109*44704f69SBart Van Assche                 pr2serr("bad argument to '--transport-id'\n");
1110*44704f69SBart Van Assche                 return SG_LIB_SYNTAX_ERROR;
1111*44704f69SBart Van Assche             }
1112*44704f69SBart Van Assche             ++num_prout_param;
1113*44704f69SBart Van Assche             break;
1114*44704f69SBart Van Assche         case 'y':       /* differentiates -y, -yy and -yyy */
1115*44704f69SBart Van Assche             if (! op->readwrite_force) {
1116*44704f69SBart Van Assche                 if (op->readonly) {
1117*44704f69SBart Van Assche                     op->readwrite_force = true;
1118*44704f69SBart Van Assche                     op->readonly = false;
1119*44704f69SBart Van Assche                 } else
1120*44704f69SBart Van Assche                     op->readonly = true;
1121*44704f69SBart Van Assche             }
1122*44704f69SBart Van Assche             break;
1123*44704f69SBart Van Assche         case 'Y':
1124*44704f69SBart Van Assche             op->param_alltgpt = true;
1125*44704f69SBart Van Assche             ++num_prout_param;
1126*44704f69SBart Van Assche             break;
1127*44704f69SBart Van Assche         case 'z':
1128*44704f69SBart Van Assche             op->prout_sa = PROUT_REPL_LOST_SA;
1129*44704f69SBart Van Assche             ++num_prout_sa;
1130*44704f69SBart Van Assche             break;
1131*44704f69SBart Van Assche         case 'Z':
1132*44704f69SBart Van Assche             op->param_aptpl = true;
1133*44704f69SBart Van Assche             ++num_prout_param;
1134*44704f69SBart Van Assche             break;
1135*44704f69SBart Van Assche         case '?':
1136*44704f69SBart Van Assche             usage(1);
1137*44704f69SBart Van Assche             return 0;
1138*44704f69SBart Van Assche         default:
1139*44704f69SBart Van Assche             pr2serr("unrecognised switch code 0x%x ??\n", c);
1140*44704f69SBart Van Assche             usage(1);
1141*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
1142*44704f69SBart Van Assche         }
1143*44704f69SBart Van Assche     }
1144*44704f69SBart Van Assche     if (optind < argc) {
1145*44704f69SBart Van Assche         if (NULL == device_name) {
1146*44704f69SBart Van Assche             device_name = argv[optind];
1147*44704f69SBart Van Assche             ++optind;
1148*44704f69SBart Van Assche         }
1149*44704f69SBart Van Assche         if (optind < argc) {
1150*44704f69SBart Van Assche             for (; optind < argc; ++optind)
1151*44704f69SBart Van Assche                 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
1152*44704f69SBart Van Assche             usage(1);
1153*44704f69SBart Van Assche             return SG_LIB_SYNTAX_ERROR;
1154*44704f69SBart Van Assche         }
1155*44704f69SBart Van Assche     }
1156*44704f69SBart Van Assche     if (help > 0) {
1157*44704f69SBart Van Assche         usage(help);
1158*44704f69SBart Van Assche         return 0;
1159*44704f69SBart Van Assche     }
1160*44704f69SBart Van Assche #ifdef DEBUG
1161*44704f69SBart Van Assche     pr2serr("In DEBUG mode, ");
1162*44704f69SBart Van Assche     if (op->verbose_given && op->version_given) {
1163*44704f69SBart Van Assche         pr2serr("but override: '-vV' given, zero verbose and "
1164*44704f69SBart Van Assche                 "continue\n");
1165*44704f69SBart Van Assche         op->verbose_given = false;
1166*44704f69SBart Van Assche         op->version_given = false;
1167*44704f69SBart Van Assche         op->verbose = 0;
1168*44704f69SBart Van Assche     } else if (! op->verbose_given) {
1169*44704f69SBart Van Assche         pr2serr("set '-vv'\n");
1170*44704f69SBart Van Assche         op->verbose = 2;
1171*44704f69SBart Van Assche     } else
1172*44704f69SBart Van Assche         pr2serr("keep verbose=%d\n", op->verbose);
1173*44704f69SBart Van Assche #else
1174*44704f69SBart Van Assche     if (op->verbose_given && op->version_given)
1175*44704f69SBart Van Assche         pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
1176*44704f69SBart Van Assche #endif
1177*44704f69SBart Van Assche     if (op->version_given) {
1178*44704f69SBart Van Assche         pr2serr("version: %s\n", version_str);
1179*44704f69SBart Van Assche         return 0;
1180*44704f69SBart Van Assche     }
1181*44704f69SBart Van Assche 
1182*44704f69SBart Van Assche     if (NULL == device_name) {
1183*44704f69SBart Van Assche         pr2serr("No device name given\n");
1184*44704f69SBart Van Assche         usage(1);
1185*44704f69SBart Van Assche         return SG_LIB_SYNTAX_ERROR;
1186*44704f69SBart Van Assche     }
1187*44704f69SBart Van Assche     if (want_prout && want_prin) {
1188*44704f69SBart Van Assche         pr2serr("choose '--in' _or_ '--out' (not both)\n");
1189*44704f69SBart Van Assche         usage(1);
1190*44704f69SBart Van Assche         return SG_LIB_CONTRADICT;
1191*44704f69SBart Van Assche     } else if (want_prout) { /* syntax check on PROUT arguments */
1192*44704f69SBart Van Assche         op->pr_in = false;
1193*44704f69SBart Van Assche         if ((1 != num_prout_sa) || (0 != num_prin_sa)) {
1194*44704f69SBart Van Assche             pr2serr(">> For Persistent Reserve Out one and only one "
1195*44704f69SBart Van Assche                     "appropriate\n>> service action must be chosen (e.g. "
1196*44704f69SBart Van Assche                     "'--register')\n");
1197*44704f69SBart Van Assche             return SG_LIB_CONTRADICT;
1198*44704f69SBart Van Assche         }
1199*44704f69SBart Van Assche     } else { /* syntax check on PRIN arguments */
1200*44704f69SBart Van Assche         if (num_prout_sa > 0) {
1201*44704f69SBart Van Assche             pr2serr(">> When a service action for Persistent Reserve Out "
1202*44704f69SBart Van Assche                     "is chosen the\n>> '--out' option must be given (as a "
1203*44704f69SBart Van Assche                     "safeguard)\n");
1204*44704f69SBart Van Assche             return SG_LIB_CONTRADICT;
1205*44704f69SBart Van Assche         }
1206*44704f69SBart Van Assche         if (0 == num_prin_sa) {
1207*44704f69SBart Van Assche             pr2serr(">> No service action given; assume Persistent Reserve "
1208*44704f69SBart Van Assche                     "In command\n>> with Read Keys service action\n");
1209*44704f69SBart Van Assche             op->prin_sa = 0;
1210*44704f69SBart Van Assche             ++num_prin_sa;
1211*44704f69SBart Van Assche         } else if (num_prin_sa > 1)  {
1212*44704f69SBart Van Assche             pr2serr("Too many service actions given; choose one only\n");
1213*44704f69SBart Van Assche             usage(1);
1214*44704f69SBart Van Assche             return SG_LIB_CONTRADICT;
1215*44704f69SBart Van Assche         }
1216*44704f69SBart Van Assche     }
1217*44704f69SBart Van Assche     if ((op->param_unreg || op->param_rtp) &&
1218*44704f69SBart Van Assche         (PROUT_REG_MOVE_SA != op->prout_sa)) {
1219*44704f69SBart Van Assche         pr2serr("--unreg or --relative-target-port only useful with "
1220*44704f69SBart Van Assche                 "--register-move\n");
1221*44704f69SBart Van Assche         usage(1);
1222*44704f69SBart Van Assche         return SG_LIB_CONTRADICT;
1223*44704f69SBart Van Assche     }
1224*44704f69SBart Van Assche     if ((PROUT_REG_MOVE_SA == op->prout_sa) &&
1225*44704f69SBart Van Assche         (1 != op->num_transportids)) {
1226*44704f69SBart Van Assche         pr2serr("with --register-move one (and only one) --transport-id "
1227*44704f69SBart Van Assche                 "should be given\n");
1228*44704f69SBart Van Assche         usage(1);
1229*44704f69SBart Van Assche         return SG_LIB_CONTRADICT;
1230*44704f69SBart Van Assche     }
1231*44704f69SBart Van Assche     if (((PROUT_RES_SA == op->prout_sa) ||
1232*44704f69SBart Van Assche          (PROUT_REL_SA == op->prout_sa) ||
1233*44704f69SBart Van Assche          (PROUT_PREE_SA == op->prout_sa) ||
1234*44704f69SBart Van Assche          (PROUT_PREE_AB_SA == op->prout_sa)) &&
1235*44704f69SBart Van Assche         (0 == op->prout_type)) {
1236*44704f69SBart Van Assche         pr2serr("warning>>> --prout-type probably needs to be given\n");
1237*44704f69SBart Van Assche     }
1238*44704f69SBart Van Assche     if ((op->verbose > 2) && op->num_transportids) {
1239*44704f69SBart Van Assche         char b[1024];
1240*44704f69SBart Van Assche         uint8_t * bp;
1241*44704f69SBart Van Assche 
1242*44704f69SBart Van Assche         pr2serr("number of tranport-ids decoded from command line (or "
1243*44704f69SBart Van Assche                 "stdin): %d\n", op->num_transportids);
1244*44704f69SBart Van Assche         pr2serr("  Decode given transport-ids:\n");
1245*44704f69SBart Van Assche         for (k = 0; k < op->num_transportids; ++k) {
1246*44704f69SBart Van Assche             bp = op->transportid_arr + (MX_TID_LEN * k);
1247*44704f69SBart Van Assche             printf("%s", sg_decode_transportid_str("      ", bp, MX_TID_LEN,
1248*44704f69SBart Van Assche                                                    true, sizeof(b), b));
1249*44704f69SBart Van Assche         }
1250*44704f69SBart Van Assche     }
1251*44704f69SBart Van Assche 
1252*44704f69SBart Van Assche     if (op->inquiry) {
1253*44704f69SBart Van Assche         if ((sg_fd = sg_cmds_open_device(device_name, true /* ro */,
1254*44704f69SBart Van Assche                                          op->verbose)) < 0) {
1255*44704f69SBart Van Assche             pr2serr("%s: error opening file (ro): %s: %s\n", ME,
1256*44704f69SBart Van Assche                     device_name, safe_strerror(-sg_fd));
1257*44704f69SBart Van Assche             ret = sg_convert_errno(-sg_fd);
1258*44704f69SBart Van Assche             flagged = true;
1259*44704f69SBart Van Assche             goto fini;
1260*44704f69SBart Van Assche         }
1261*44704f69SBart Van Assche         ret = sg_simple_inquiry(sg_fd, &inq_resp, true, op->verbose);
1262*44704f69SBart Van Assche         if (0 == ret) {
1263*44704f69SBart Van Assche             printf("  %.8s  %.16s  %.4s\n", inq_resp.vendor, inq_resp.product,
1264*44704f69SBart Van Assche                    inq_resp.revision);
1265*44704f69SBart Van Assche             peri_type = inq_resp.peripheral_type;
1266*44704f69SBart Van Assche             cp = sg_get_pdt_str(peri_type, sizeof(buff), buff);
1267*44704f69SBart Van Assche             if (strlen(cp) > 0)
1268*44704f69SBart Van Assche                 printf("  Peripheral device type: %s\n", cp);
1269*44704f69SBart Van Assche             else
1270*44704f69SBart Van Assche                 printf("  Peripheral device type: 0x%x\n", peri_type);
1271*44704f69SBart Van Assche         } else {
1272*44704f69SBart Van Assche             printf("%s: SCSI INQUIRY failed on %s", ME, device_name);
1273*44704f69SBart Van Assche             if (ret < 0) {
1274*44704f69SBart Van Assche                 ret = -ret;
1275*44704f69SBart Van Assche                 printf(": %s\n", safe_strerror(ret));
1276*44704f69SBart Van Assche                 ret = sg_convert_errno(ret);
1277*44704f69SBart Van Assche             } else
1278*44704f69SBart Van Assche                 printf("\n");
1279*44704f69SBart Van Assche             flagged = true;
1280*44704f69SBart Van Assche             goto fini;
1281*44704f69SBart Van Assche         }
1282*44704f69SBart Van Assche         res = sg_cmds_close_device(sg_fd);
1283*44704f69SBart Van Assche         if (res < 0)
1284*44704f69SBart Van Assche             pr2serr("%s: sg_cmds_close_device() failed res=%d\n", ME, res);
1285*44704f69SBart Van Assche     }
1286*44704f69SBart Van Assche 
1287*44704f69SBart Van Assche     if (! op->readwrite_force) {
1288*44704f69SBart Van Assche         cp = getenv(SG_PERSIST_IN_RDONLY);
1289*44704f69SBart Van Assche         if (cp && op->pr_in)
1290*44704f69SBart Van Assche             op->readonly = true;  /* SG_PERSIST_IN_RDONLY overrides default
1291*44704f69SBart Van Assche                                      which is open(RW) */
1292*44704f69SBart Van Assche     } else
1293*44704f69SBart Van Assche         op->readonly = false;      /* '-yy' force open(RW) */
1294*44704f69SBart Van Assche     sg_fd = sg_cmds_open_device(device_name, op->readonly, op->verbose);
1295*44704f69SBart Van Assche     if (sg_fd < 0) {
1296*44704f69SBart Van Assche         pr2serr("%s: error opening file %s (r%s): %s\n", ME, device_name,
1297*44704f69SBart Van Assche                 (op->readonly ? "o" : "w"), safe_strerror(-sg_fd));
1298*44704f69SBart Van Assche         ret = sg_convert_errno(-sg_fd);
1299*44704f69SBart Van Assche         flagged = true;
1300*44704f69SBart Van Assche         goto fini;
1301*44704f69SBart Van Assche     }
1302*44704f69SBart Van Assche 
1303*44704f69SBart Van Assche     if (op->pr_in)
1304*44704f69SBart Van Assche         ret = prin_work(sg_fd, op);
1305*44704f69SBart Van Assche     else if (PROUT_REG_MOVE_SA == op->prout_sa)
1306*44704f69SBart Van Assche         ret = prout_reg_move_work(sg_fd, op);
1307*44704f69SBart Van Assche     else /* PROUT commands other than 'register and move' */
1308*44704f69SBart Van Assche         ret = prout_work(sg_fd, op);
1309*44704f69SBart Van Assche 
1310*44704f69SBart Van Assche fini:
1311*44704f69SBart Van Assche     if (ret && (0 == op->verbose) && (! flagged)) {
1312*44704f69SBart Van Assche         if (! sg_if_can2stderr("sg_persist failed: ", ret))
1313*44704f69SBart Van Assche             pr2serr("Some error occurred [%d]\n", ret);
1314*44704f69SBart Van Assche     }
1315*44704f69SBart Van Assche     if (sg_fd >= 0) {
1316*44704f69SBart Van Assche         res = sg_cmds_close_device(sg_fd);
1317*44704f69SBart Van Assche         if (res < 0) {
1318*44704f69SBart Van Assche             pr2serr("close error: %s\n", safe_strerror(-res));
1319*44704f69SBart Van Assche             if (0 == ret)
1320*44704f69SBart Van Assche                 ret = sg_convert_errno(-res);
1321*44704f69SBart Van Assche         }
1322*44704f69SBart Van Assche     }
1323*44704f69SBart Van Assche     return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
1324*44704f69SBart Van Assche }
1325