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