1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche * Copyright (c) 2016-2021 Douglas Gilbert.
3*44704f69SBart Van Assche * All rights reserved.
4*44704f69SBart Van Assche * Use of this source code is governed by a BSD-style
5*44704f69SBart Van Assche * license that can be found in the BSD_LICENSE file.
6*44704f69SBart Van Assche *
7*44704f69SBart Van Assche * SPDX-License-Identifier: BSD-2-Clause
8*44704f69SBart Van Assche */
9*44704f69SBart Van Assche
10*44704f69SBart Van Assche #include <unistd.h>
11*44704f69SBart Van Assche #include <fcntl.h>
12*44704f69SBart Van Assche #include <stdio.h>
13*44704f69SBart Van Assche #include <stdlib.h>
14*44704f69SBart Van Assche #include <stdarg.h>
15*44704f69SBart Van Assche #include <stdbool.h>
16*44704f69SBart Van Assche #include <string.h>
17*44704f69SBart Van Assche #include <errno.h>
18*44704f69SBart Van Assche #include <ctype.h>
19*44704f69SBart Van Assche #include <getopt.h>
20*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
21*44704f69SBart Van Assche #include <inttypes.h>
22*44704f69SBart Van Assche #include <errno.h>
23*44704f69SBart Van Assche
24*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
25*44704f69SBart Van Assche #include "config.h"
26*44704f69SBart Van Assche #endif
27*44704f69SBart Van Assche
28*44704f69SBart Van Assche #include "sg_lib.h"
29*44704f69SBart Van Assche #include "sg_lib_data.h"
30*44704f69SBart Van Assche #include "sg_pt.h"
31*44704f69SBart Van Assche #include "sg_cmds_basic.h"
32*44704f69SBart Van Assche #include "sg_unaligned.h"
33*44704f69SBart Van Assche #include "sg_pr2serr.h"
34*44704f69SBart Van Assche
35*44704f69SBart Van Assche /* A utility program originally written for the Linux OS SCSI subsystem.
36*44704f69SBart Van Assche *
37*44704f69SBart Van Assche *
38*44704f69SBart Van Assche * This program issues the SCSI READ ATTRIBUTE command to the given SCSI device
39*44704f69SBart Van Assche * and decodes the response. Based on spc5r08.pdf
40*44704f69SBart Van Assche */
41*44704f69SBart Van Assche
42*44704f69SBart Van Assche static const char * version_str = "1.16 20211114";
43*44704f69SBart Van Assche
44*44704f69SBart Van Assche #define MAX_RATTR_BUFF_LEN (1024 * 1024)
45*44704f69SBart Van Assche #define DEF_RATTR_BUFF_LEN (1024 * 8)
46*44704f69SBart Van Assche
47*44704f69SBart Van Assche #define SG_READ_ATTRIBUTE_CMD 0x8c
48*44704f69SBart Van Assche #define SG_READ_ATTRIBUTE_CMDLEN 16
49*44704f69SBart Van Assche
50*44704f69SBart Van Assche #define RA_ATTR_VAL_SA 0x0
51*44704f69SBart Van Assche #define RA_ATTR_LIST_SA 0x1
52*44704f69SBart Van Assche #define RA_LV_LIST_SA 0x2
53*44704f69SBart Van Assche #define RA_PART_LIST_SA 0x3
54*44704f69SBart Van Assche #define RA_SMC2_SA 0x4
55*44704f69SBart Van Assche #define RA_SUP_ATTR_SA 0x5
56*44704f69SBart Van Assche #define RA_HIGHEST_SA 0x5
57*44704f69SBart Van Assche
58*44704f69SBart Van Assche #define RA_FMT_BINARY 0x0
59*44704f69SBart Van Assche #define RA_FMT_ASCII 0x1
60*44704f69SBart Van Assche #define RA_FMT_TEXT 0x2 /* takes into account locale */
61*44704f69SBart Van Assche #define RA_FMT_RES 0x3 /* reserved */
62*44704f69SBart Van Assche
63*44704f69SBart Van Assche
64*44704f69SBart Van Assche #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
65*44704f69SBart Van Assche #define DEF_PT_TIMEOUT 60 /* 60 seconds */
66*44704f69SBart Van Assche
67*44704f69SBart Van Assche struct opts_t {
68*44704f69SBart Van Assche bool cache;
69*44704f69SBart Van Assche bool enumerate;
70*44704f69SBart Van Assche bool do_raw;
71*44704f69SBart Van Assche bool o_readonly;
72*44704f69SBart Van Assche bool verbose_given;
73*44704f69SBart Van Assche bool version_given;
74*44704f69SBart Van Assche int elem_addr;
75*44704f69SBart Van Assche int filter;
76*44704f69SBart Van Assche int fai;
77*44704f69SBart Van Assche int do_hex;
78*44704f69SBart Van Assche int lvn;
79*44704f69SBart Van Assche int maxlen;
80*44704f69SBart Van Assche int pn;
81*44704f69SBart Van Assche int quiet;
82*44704f69SBart Van Assche int sa;
83*44704f69SBart Van Assche int verbose;
84*44704f69SBart Van Assche };
85*44704f69SBart Van Assche
86*44704f69SBart Van Assche struct acron_nv_t {
87*44704f69SBart Van Assche const char * acron;
88*44704f69SBart Van Assche const char * name;
89*44704f69SBart Van Assche int val;
90*44704f69SBart Van Assche };
91*44704f69SBart Van Assche
92*44704f69SBart Van Assche struct attr_name_info_t {
93*44704f69SBart Van Assche int id;
94*44704f69SBart Van Assche const char * name; /* tab ('\t') suggest line break */
95*44704f69SBart Van Assche int format; /* RA_FMT_BINARY and friends, -1 --> unknown */
96*44704f69SBart Van Assche int len; /* -1 --> not fixed (variable) */
97*44704f69SBart Van Assche int process; /* 0 --> print decimal if binary, 1 --> print hex,
98*44704f69SBart Van Assche * 2 --> further processing */
99*44704f69SBart Van Assche };
100*44704f69SBart Van Assche
101*44704f69SBart Van Assche static struct option long_options[] = {
102*44704f69SBart Van Assche {"cache", no_argument, 0, 'c'},
103*44704f69SBart Van Assche {"enumerate", no_argument, 0, 'e'},
104*44704f69SBart Van Assche {"element", required_argument, 0, 'E'}, /* SMC-3 element address */
105*44704f69SBart Van Assche {"filter", required_argument, 0, 'f'},
106*44704f69SBart Van Assche {"first", required_argument, 0, 'F'},
107*44704f69SBart Van Assche {"help", no_argument, 0, 'h'},
108*44704f69SBart Van Assche {"hex", no_argument, 0, 'H'},
109*44704f69SBart Van Assche {"in", required_argument, 0, 'i'},
110*44704f69SBart Van Assche {"lvn", required_argument, 0, 'l'},
111*44704f69SBart Van Assche {"maxlen", required_argument, 0, 'm'},
112*44704f69SBart Van Assche {"partition", required_argument, 0, 'p'},
113*44704f69SBart Van Assche {"quiet", required_argument, 0, 'q'},
114*44704f69SBart Van Assche {"raw", no_argument, 0, 'r'},
115*44704f69SBart Van Assche {"readonly", no_argument, 0, 'R'},
116*44704f69SBart Van Assche {"sa", required_argument, 0, 's'},
117*44704f69SBart Van Assche {"verbose", no_argument, 0, 'v'},
118*44704f69SBart Van Assche {"version", no_argument, 0, 'V'},
119*44704f69SBart Van Assche {0, 0, 0, 0}, /* sentinel */
120*44704f69SBart Van Assche };
121*44704f69SBart Van Assche
122*44704f69SBart Van Assche static struct acron_nv_t sa_acron_arr[] = {
123*44704f69SBart Van Assche {"av", "attribute values", 0},
124*44704f69SBart Van Assche {"al", "attribute list", 1},
125*44704f69SBart Van Assche {"lvl", "logical volume list", 2},
126*44704f69SBart Van Assche {"pl", "partition list", 3},
127*44704f69SBart Van Assche {"smc", "SMC-2 should define this", 4},
128*44704f69SBart Van Assche {"sa", "supported attributes", 5},
129*44704f69SBart Van Assche {NULL, NULL, -1}, /* sentinel */
130*44704f69SBart Van Assche };
131*44704f69SBart Van Assche
132*44704f69SBart Van Assche static struct attr_name_info_t attr_name_arr[] = {
133*44704f69SBart Van Assche /* Device type attributes */
134*44704f69SBart Van Assche {0x0, "Remaining capacity in partition [MiB]", RA_FMT_BINARY, 8, 0},
135*44704f69SBart Van Assche {0x1, "Maximum capacity in partition [MiB]", RA_FMT_BINARY, 8, 0},
136*44704f69SBart Van Assche {0x2, "TapeAlert flags", RA_FMT_BINARY, 8, 0}, /* SSC-4 */
137*44704f69SBart Van Assche {0x3, "Load count", RA_FMT_BINARY, 8, 0},
138*44704f69SBart Van Assche {0x4, "MAM space remaining [B]", RA_FMT_BINARY, 8, 0},
139*44704f69SBart Van Assche {0x5, "Assigning organization", RA_FMT_ASCII, 8, 0}, /* SSC-4 */
140*44704f69SBart Van Assche {0x6, "Format density code", RA_FMT_BINARY, 1, 1}, /* SSC-4 */
141*44704f69SBart Van Assche {0x7, "Initialization count", RA_FMT_BINARY, 2, 0},
142*44704f69SBart Van Assche {0x8, "Volume identifier", RA_FMT_ASCII, 32, 0},
143*44704f69SBart Van Assche {0x9, "Volume change reference", RA_FMT_BINARY, -1, 1}, /* SSC-4 */
144*44704f69SBart Van Assche {0x20a, "Density vendor/serial number at last load", RA_FMT_ASCII, 40, 0},
145*44704f69SBart Van Assche {0x20b, "Density vendor/serial number at load-1", RA_FMT_ASCII, 40, 0},
146*44704f69SBart Van Assche {0x20c, "Density vendor/serial number at load-2", RA_FMT_ASCII, 40, 0},
147*44704f69SBart Van Assche {0x20d, "Density vendor/serial number at load-3", RA_FMT_ASCII, 40, 0},
148*44704f69SBart Van Assche {0x220, "Total MiB written in medium life", RA_FMT_BINARY, 8, 0},
149*44704f69SBart Van Assche {0x221, "Total MiB read in medium life", RA_FMT_BINARY, 8, 0},
150*44704f69SBart Van Assche {0x222, "Total MiB written in current/last load", RA_FMT_BINARY, 8, 0},
151*44704f69SBart Van Assche {0x223, "Total MiB read in current/last load", RA_FMT_BINARY, 8, 0},
152*44704f69SBart Van Assche {0x224, "Logical position of first encrypted block", RA_FMT_BINARY, 8, 2},
153*44704f69SBart Van Assche {0x225, "Logical position of first unencrypted block\tafter first "
154*44704f69SBart Van Assche "encrypted block", RA_FMT_BINARY, 8, 2},
155*44704f69SBart Van Assche {0x340, "Medium usage history", RA_FMT_BINARY, 90, 2},
156*44704f69SBart Van Assche {0x341, "Partition usage history", RA_FMT_BINARY, 60, 2},
157*44704f69SBart Van Assche
158*44704f69SBart Van Assche /* Medium type attributes */
159*44704f69SBart Van Assche {0x400, "Medium manufacturer", RA_FMT_ASCII, 8, 0},
160*44704f69SBart Van Assche {0x401, "Medium serial number", RA_FMT_ASCII, 32, 0},
161*44704f69SBart Van Assche {0x402, "Medium length [m]", RA_FMT_BINARY, 4, 0}, /* SSC-4 */
162*44704f69SBart Van Assche {0x403, "Medium width [0.1 mm]", RA_FMT_BINARY, 4, 0}, /* SSC-4 */
163*44704f69SBart Van Assche {0x404, "Assigning organization", RA_FMT_ASCII, 8, 0}, /* SSC-4 */
164*44704f69SBart Van Assche {0x405, "Medium density code", RA_FMT_BINARY, 1, 1}, /* SSC-4 */
165*44704f69SBart Van Assche {0x406, "Medium manufacture date", RA_FMT_ASCII, 8, 0},
166*44704f69SBart Van Assche {0x407, "MAM capacity [B]", RA_FMT_BINARY, 8, 0},
167*44704f69SBart Van Assche {0x408, "Medium type", RA_FMT_BINARY, 1, 1},
168*44704f69SBart Van Assche {0x409, "Medium type information", RA_FMT_BINARY, 2, 1},
169*44704f69SBart Van Assche {0x40a, "Numeric medium serial number", -1, -1, 1},
170*44704f69SBart Van Assche
171*44704f69SBart Van Assche /* Host type attributes */
172*44704f69SBart Van Assche {0x800, "Application vendor", RA_FMT_ASCII, 8, 0},
173*44704f69SBart Van Assche {0x801, "Application name", RA_FMT_ASCII, 32, 0},
174*44704f69SBart Van Assche {0x802, "Application version", RA_FMT_ASCII, 8, 0},
175*44704f69SBart Van Assche {0x803, "User medium text label", RA_FMT_TEXT, 160, 0},
176*44704f69SBart Van Assche {0x804, "Date and time last written", RA_FMT_ASCII, 12, 0},
177*44704f69SBart Van Assche {0x805, "Text localization identifier", RA_FMT_BINARY, 1, 0},
178*44704f69SBart Van Assche {0x806, "Barcode", RA_FMT_ASCII, 32, 0},
179*44704f69SBart Van Assche {0x807, "Owning host textual name", RA_FMT_TEXT, 80, 0},
180*44704f69SBart Van Assche {0x808, "Media pool", RA_FMT_TEXT, 160, 0},
181*44704f69SBart Van Assche {0x809, "Partition user text label", RA_FMT_ASCII, 16, 0},
182*44704f69SBart Van Assche {0x80a, "Load/unload at partition", RA_FMT_BINARY, 1, 0},
183*44704f69SBart Van Assche {0x80a, "Application format version", RA_FMT_ASCII, 16, 0},
184*44704f69SBart Van Assche {0x80c, "Volume coherency information", RA_FMT_BINARY, -1, 1},
185*44704f69SBart Van Assche /* SSC-5 */
186*44704f69SBart Van Assche {0x820, "Medium globally unique identifier", RA_FMT_BINARY, 36, 1},
187*44704f69SBart Van Assche {0x821, "Media pool globally unique identifier", RA_FMT_BINARY, 36, 1},
188*44704f69SBart Van Assche
189*44704f69SBart Van Assche {-1, NULL, -1, -1, 0},
190*44704f69SBart Van Assche };
191*44704f69SBart Van Assche
192*44704f69SBart Van Assche
193*44704f69SBart Van Assche static void
usage()194*44704f69SBart Van Assche usage()
195*44704f69SBart Van Assche {
196*44704f69SBart Van Assche pr2serr("Usage: sg_read_attr [--cache] [--element=EA] [--enumerate] "
197*44704f69SBart Van Assche "[--filter=FL]\n"
198*44704f69SBart Van Assche " [--first=FAI] [--help] [--hex] [--in=FN] "
199*44704f69SBart Van Assche "[--lvn=LVN]\n"
200*44704f69SBart Van Assche " [--maxlen=LEN] [--partition=PN] [--quiet] "
201*44704f69SBart Van Assche "[--raw]\n"
202*44704f69SBart Van Assche " [--readonly] [--sa=SA] [--verbose] "
203*44704f69SBart Van Assche "[--version]\n"
204*44704f69SBart Van Assche " DEVICE\n");
205*44704f69SBart Van Assche pr2serr(" where:\n"
206*44704f69SBart Van Assche " --cache|-c set CACHE bit in cdn (def: clear)\n"
207*44704f69SBart Van Assche " --enumerate|-e enumerate known attributes and service "
208*44704f69SBart Van Assche "actions\n"
209*44704f69SBart Van Assche " --element=EA|-E EA EA is placed in 'element address' "
210*44704f69SBart Van Assche "field in\n"
211*44704f69SBart Van Assche " cdb [SMC-3] (def: 0)\n"
212*44704f69SBart Van Assche " --filter=FL|-f FL FL is parameter code to match (def: "
213*44704f69SBart Van Assche "-1 -> all)\n"
214*44704f69SBart Van Assche " --first=FAI|-F FAI FAI is placed in 'first attribute "
215*44704f69SBart Van Assche "identifier'\n"
216*44704f69SBart Van Assche " field in cdb (def: 0)\n"
217*44704f69SBart Van Assche " --help|-h print out usage message\n"
218*44704f69SBart Van Assche " --hex|-H output response in hexadecimal; used "
219*44704f69SBart Van Assche "twice\n"
220*44704f69SBart Van Assche " shows decoded values in hex\n"
221*44704f69SBart Van Assche " --in=FN|-i FN FN is a filename containing attribute "
222*44704f69SBart Van Assche "values in\n"
223*44704f69SBart Van Assche " ASCII hex or binary if --raw also "
224*44704f69SBart Van Assche "given\n"
225*44704f69SBart Van Assche " --lvn=LVN|-l LVN logical volume number (LVN) (def:0)\n"
226*44704f69SBart Van Assche " --maxlen=LEN|-m LEN max response length (allocation "
227*44704f69SBart Van Assche "length in cdb)\n"
228*44704f69SBart Van Assche " (def: 0 -> 8192 bytes)\n"
229*44704f69SBart Van Assche " --partition=PN|-p PN partition number (PN) (def:0)\n"
230*44704f69SBart Van Assche " --quiet|-q reduce the amount of output, can use "
231*44704f69SBart Van Assche "more than once\n"
232*44704f69SBart Van Assche " --raw|-r output response in binary\n"
233*44704f69SBart Van Assche " --readonly|-R open DEVICE read-only (def: read-write)\n"
234*44704f69SBart Van Assche " --sa=SA|-s SA SA is service action (def: 0)\n"
235*44704f69SBart Van Assche " --verbose|-v increase verbosity\n"
236*44704f69SBart Van Assche " --version|-V print version string and exit\n\n"
237*44704f69SBart Van Assche "Performs a SCSI READ ATTRIBUTE command. Even though it is "
238*44704f69SBart Van Assche "defined in\nSPC-3 and later it is typically used on tape "
239*44704f69SBart Van Assche "systems.\n");
240*44704f69SBart Van Assche }
241*44704f69SBart Van Assche
242*44704f69SBart Van Assche /* Invokes a SCSI READ ATTRIBUTE command (SPC+SMC). Return of 0 -> success,
243*44704f69SBart Van Assche * various SG_LIB_CAT_* positive values or -1 -> other errors */
244*44704f69SBart Van Assche static int
sg_ll_read_attr(int sg_fd,void * resp,int * residp,bool noisy,const struct opts_t * op)245*44704f69SBart Van Assche sg_ll_read_attr(int sg_fd, void * resp, int * residp, bool noisy,
246*44704f69SBart Van Assche const struct opts_t * op)
247*44704f69SBart Van Assche {
248*44704f69SBart Van Assche int ret, res, sense_cat;
249*44704f69SBart Van Assche uint8_t ra_cdb[SG_READ_ATTRIBUTE_CMDLEN] =
250*44704f69SBart Van Assche {SG_READ_ATTRIBUTE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
251*44704f69SBart Van Assche 0, 0, 0, 0};
252*44704f69SBart Van Assche uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
253*44704f69SBart Van Assche struct sg_pt_base * ptvp;
254*44704f69SBart Van Assche
255*44704f69SBart Van Assche ra_cdb[1] = 0x1f & op->sa;
256*44704f69SBart Van Assche if (op->elem_addr)
257*44704f69SBart Van Assche sg_put_unaligned_be16(op->elem_addr, ra_cdb + 2);
258*44704f69SBart Van Assche if (op->lvn)
259*44704f69SBart Van Assche ra_cdb[5] = 0xff & op->lvn;
260*44704f69SBart Van Assche if (op->pn)
261*44704f69SBart Van Assche ra_cdb[7] = 0xff & op->pn;
262*44704f69SBart Van Assche if (op->fai)
263*44704f69SBart Van Assche sg_put_unaligned_be16(op->fai, ra_cdb + 8);
264*44704f69SBart Van Assche sg_put_unaligned_be32((uint32_t)op->maxlen, ra_cdb + 10);
265*44704f69SBart Van Assche if (op->cache)
266*44704f69SBart Van Assche ra_cdb[14] |= 0x1;
267*44704f69SBart Van Assche if (op->verbose) {
268*44704f69SBart Van Assche char b[128];
269*44704f69SBart Van Assche
270*44704f69SBart Van Assche pr2serr(" Read attribute cdb: %s\n",
271*44704f69SBart Van Assche sg_get_command_str(ra_cdb, SG_READ_ATTRIBUTE_CMDLEN, false,
272*44704f69SBart Van Assche sizeof(b), b));
273*44704f69SBart Van Assche }
274*44704f69SBart Van Assche
275*44704f69SBart Van Assche ptvp = construct_scsi_pt_obj();
276*44704f69SBart Van Assche if (NULL == ptvp) {
277*44704f69SBart Van Assche pr2serr("%s: out of memory\n", __func__);
278*44704f69SBart Van Assche return -1;
279*44704f69SBart Van Assche }
280*44704f69SBart Van Assche set_scsi_pt_cdb(ptvp, ra_cdb, sizeof(ra_cdb));
281*44704f69SBart Van Assche set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
282*44704f69SBart Van Assche set_scsi_pt_data_in(ptvp, (uint8_t *)resp, op->maxlen);
283*44704f69SBart Van Assche res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, op->verbose);
284*44704f69SBart Van Assche ret = sg_cmds_process_resp(ptvp, "read attribute", res, noisy,
285*44704f69SBart Van Assche op->verbose, &sense_cat);
286*44704f69SBart Van Assche if (-1 == ret) {
287*44704f69SBart Van Assche if (get_scsi_pt_transport_err(ptvp))
288*44704f69SBart Van Assche ret = SG_LIB_TRANSPORT_ERROR;
289*44704f69SBart Van Assche else
290*44704f69SBart Van Assche ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
291*44704f69SBart Van Assche } else if (-2 == ret) {
292*44704f69SBart Van Assche switch (sense_cat) {
293*44704f69SBart Van Assche case SG_LIB_CAT_RECOVERED:
294*44704f69SBart Van Assche case SG_LIB_CAT_NO_SENSE:
295*44704f69SBart Van Assche ret = 0;
296*44704f69SBart Van Assche break;
297*44704f69SBart Van Assche default:
298*44704f69SBart Van Assche ret = sense_cat;
299*44704f69SBart Van Assche break;
300*44704f69SBart Van Assche }
301*44704f69SBart Van Assche } else
302*44704f69SBart Van Assche ret = 0;
303*44704f69SBart Van Assche if (residp)
304*44704f69SBart Van Assche *residp = get_scsi_pt_resid(ptvp);
305*44704f69SBart Van Assche destruct_scsi_pt_obj(ptvp);
306*44704f69SBart Van Assche return ret;
307*44704f69SBart Van Assche }
308*44704f69SBart Van Assche
309*44704f69SBart Van Assche static void
dStrRaw(const char * str,int len)310*44704f69SBart Van Assche dStrRaw(const char * str, int len)
311*44704f69SBart Van Assche {
312*44704f69SBart Van Assche int k;
313*44704f69SBart Van Assche
314*44704f69SBart Van Assche for (k = 0; k < len; ++k)
315*44704f69SBart Van Assche printf("%c", str[k]);
316*44704f69SBart Van Assche }
317*44704f69SBart Van Assche
318*44704f69SBart Van Assche static int
find_sa_acron(const char * cp)319*44704f69SBart Van Assche find_sa_acron(const char * cp)
320*44704f69SBart Van Assche {
321*44704f69SBart Van Assche int k;
322*44704f69SBart Van Assche const struct acron_nv_t * anvp;
323*44704f69SBart Van Assche const char * mp;
324*44704f69SBart Van Assche
325*44704f69SBart Van Assche for (anvp = sa_acron_arr; anvp->acron ; ++anvp) {
326*44704f69SBart Van Assche for (mp = cp, k = 0; *mp; ++mp, ++k) {
327*44704f69SBart Van Assche if (0 == anvp->acron[k])
328*44704f69SBart Van Assche return anvp->val;
329*44704f69SBart Van Assche if (tolower((uint8_t)*mp) != (uint8_t)anvp->acron[k])
330*44704f69SBart Van Assche break;
331*44704f69SBart Van Assche }
332*44704f69SBart Van Assche if ((0 == *mp) && (0 == anvp->acron[k]))
333*44704f69SBart Van Assche return anvp->val;
334*44704f69SBart Van Assche }
335*44704f69SBart Van Assche return -1; /* not found */
336*44704f69SBart Van Assche }
337*44704f69SBart Van Assche
338*44704f69SBart Van Assche const char * a_format[] = {
339*44704f69SBart Van Assche "binary",
340*44704f69SBart Van Assche "ascii",
341*44704f69SBart Van Assche "text",
342*44704f69SBart Van Assche "format[0x3]",
343*44704f69SBart Van Assche };
344*44704f69SBart Van Assche
345*44704f69SBart Van Assche static void
enum_attributes(void)346*44704f69SBart Van Assche enum_attributes(void)
347*44704f69SBart Van Assche {
348*44704f69SBart Van Assche const struct attr_name_info_t * anip;
349*44704f69SBart Van Assche const char * cp;
350*44704f69SBart Van Assche char b[32];
351*44704f69SBart Van Assche
352*44704f69SBart Van Assche printf("Attribute ID\tLength\tFormat\tName\n");
353*44704f69SBart Van Assche printf("------------------------------------------\n");
354*44704f69SBart Van Assche for (anip = attr_name_arr; anip->name ; ++anip) {
355*44704f69SBart Van Assche if (anip->format < 0)
356*44704f69SBart Van Assche snprintf(b, sizeof(b), "unknown");
357*44704f69SBart Van Assche else
358*44704f69SBart Van Assche snprintf(b, sizeof(b), "%s", a_format[0x3 & anip->format]);
359*44704f69SBart Van Assche printf(" 0x%04x:\t%d\t%s\t", anip->id, anip->len, b);
360*44704f69SBart Van Assche cp = strchr(anip->name, '\t');
361*44704f69SBart Van Assche if (cp ) {
362*44704f69SBart Van Assche printf("%.*s\n", (int)(cp - anip->name), anip->name);
363*44704f69SBart Van Assche printf("\t\t\t\t%s\n", cp + 1);
364*44704f69SBart Van Assche } else
365*44704f69SBart Van Assche printf("%s\n", anip->name);
366*44704f69SBart Van Assche }
367*44704f69SBart Van Assche }
368*44704f69SBart Van Assche
369*44704f69SBart Van Assche static void
enum_sa_acrons(void)370*44704f69SBart Van Assche enum_sa_acrons(void)
371*44704f69SBart Van Assche {
372*44704f69SBart Van Assche const struct acron_nv_t * anvp;
373*44704f69SBart Van Assche
374*44704f69SBart Van Assche printf("SA_value\tAcronym\tDescription\n");
375*44704f69SBart Van Assche printf("------------------------------------------\n");
376*44704f69SBart Van Assche for (anvp = sa_acron_arr; anvp->acron ; ++anvp)
377*44704f69SBart Van Assche printf(" %d:\t\t%s\t%s\n", anvp->val, anvp->acron, anvp->name);
378*44704f69SBart Van Assche }
379*44704f69SBart Van Assche
380*44704f69SBart Van Assche /* Returns 1 if 'bp' all 0xff bytes, returns 2 is all 0xff bytes apart
381*44704f69SBart Van Assche * from last being 0xfe; otherwise returns 0. */
382*44704f69SBart Van Assche static int
all_ffs_or_last_fe(const uint8_t * bp,int len)383*44704f69SBart Van Assche all_ffs_or_last_fe(const uint8_t * bp, int len)
384*44704f69SBart Van Assche {
385*44704f69SBart Van Assche for ( ; len > 0; ++bp, --len) {
386*44704f69SBart Van Assche if (*bp < 0xfe)
387*44704f69SBart Van Assche return 0;
388*44704f69SBart Van Assche if (0xfe == *bp)
389*44704f69SBart Van Assche return (1 == len) ? 2 : 0;
390*44704f69SBart Van Assche
391*44704f69SBart Van Assche }
392*44704f69SBart Van Assche return 1;
393*44704f69SBart Van Assche }
394*44704f69SBart Van Assche
395*44704f69SBart Van Assche static char *
attr_id_lookup(unsigned int id,const struct attr_name_info_t ** anipp,int blen,char * b)396*44704f69SBart Van Assche attr_id_lookup(unsigned int id, const struct attr_name_info_t ** anipp,
397*44704f69SBart Van Assche int blen, char * b)
398*44704f69SBart Van Assche {
399*44704f69SBart Van Assche const struct attr_name_info_t * anip;
400*44704f69SBart Van Assche
401*44704f69SBart Van Assche for (anip = attr_name_arr; anip->name; ++anip) {
402*44704f69SBart Van Assche if (id == (unsigned int)anip->id)
403*44704f69SBart Van Assche break;
404*44704f69SBart Van Assche }
405*44704f69SBart Van Assche if (anip->name) {
406*44704f69SBart Van Assche snprintf(b, blen, "%s", anip->name);
407*44704f69SBart Van Assche if (anipp)
408*44704f69SBart Van Assche *anipp = anip;
409*44704f69SBart Van Assche return b;
410*44704f69SBart Van Assche }
411*44704f69SBart Van Assche if (anipp)
412*44704f69SBart Van Assche *anipp = NULL;
413*44704f69SBart Van Assche if (id < 0x400)
414*44704f69SBart Van Assche snprintf(b, blen, "Unknown device attribute 0x%x", id);
415*44704f69SBart Van Assche else if (id < 0x800)
416*44704f69SBart Van Assche snprintf(b, blen, "Unknown medium attribute 0x%x", id);
417*44704f69SBart Van Assche else if (id < 0xc00)
418*44704f69SBart Van Assche snprintf(b, blen, "Unknown host attribute 0x%x", id);
419*44704f69SBart Van Assche else if (id < 0x1000)
420*44704f69SBart Van Assche snprintf(b, blen, "Vendor specific device attribute 0x%x", id);
421*44704f69SBart Van Assche else if (id < 0x1400)
422*44704f69SBart Van Assche snprintf(b, blen, "Vendor specific medium attribute 0x%x", id);
423*44704f69SBart Van Assche else if (id < 0x1800)
424*44704f69SBart Van Assche snprintf(b, blen, "Vendor specific host attribute 0x%x", id);
425*44704f69SBart Van Assche else
426*44704f69SBart Van Assche snprintf(b, blen, "Reserved attribute 0x%x", id);
427*44704f69SBart Van Assche return b;
428*44704f69SBart Van Assche }
429*44704f69SBart Van Assche
430*44704f69SBart Van Assche static void
decode_attr_list(const uint8_t * alp,int len,bool supported,const struct opts_t * op)431*44704f69SBart Van Assche decode_attr_list(const uint8_t * alp, int len, bool supported,
432*44704f69SBart Van Assche const struct opts_t * op)
433*44704f69SBart Van Assche {
434*44704f69SBart Van Assche int id;
435*44704f69SBart Van Assche char b[160];
436*44704f69SBart Van Assche char * cp;
437*44704f69SBart Van Assche char * c2p;
438*44704f69SBart Van Assche const char * leadin = supported ? "Supported a" : "A";
439*44704f69SBart Van Assche
440*44704f69SBart Van Assche if (op->verbose)
441*44704f69SBart Van Assche printf("%sttribute list: [len=%d]\n", leadin, len);
442*44704f69SBart Van Assche else if (0 == op->quiet)
443*44704f69SBart Van Assche printf("%sttribute list:\n", leadin);
444*44704f69SBart Van Assche if (op->do_hex) {
445*44704f69SBart Van Assche hex2stdout(alp, len, 0);
446*44704f69SBart Van Assche return;
447*44704f69SBart Van Assche }
448*44704f69SBart Van Assche for ( ; len > 0; alp += 2, len -= 2) {
449*44704f69SBart Van Assche id = sg_get_unaligned_be16(alp + 0);
450*44704f69SBart Van Assche if ((op->filter >= 0) && (op->filter != id))
451*44704f69SBart Van Assche continue;
452*44704f69SBart Van Assche if (op->verbose)
453*44704f69SBart Van Assche printf(" 0x%.4x:\t", id);
454*44704f69SBart Van Assche cp = attr_id_lookup(id, NULL, sizeof(b), b);
455*44704f69SBart Van Assche c2p = strchr(cp, '\t');
456*44704f69SBart Van Assche if (c2p) {
457*44704f69SBart Van Assche printf(" %.*s -\n", (int)(c2p - cp), cp);
458*44704f69SBart Van Assche if (op->verbose)
459*44704f69SBart Van Assche printf("\t\t %s\n", c2p + 1);
460*44704f69SBart Van Assche else
461*44704f69SBart Van Assche printf(" %s\n", c2p + 1);
462*44704f69SBart Van Assche } else
463*44704f69SBart Van Assche printf(" %s\n", cp);
464*44704f69SBart Van Assche }
465*44704f69SBart Van Assche }
466*44704f69SBart Van Assche
467*44704f69SBart Van Assche static void
helper_full_attr(const uint8_t * alp,int len,int id,const struct attr_name_info_t * anip,const struct opts_t * op)468*44704f69SBart Van Assche helper_full_attr(const uint8_t * alp, int len, int id,
469*44704f69SBart Van Assche const struct attr_name_info_t * anip,
470*44704f69SBart Van Assche const struct opts_t * op)
471*44704f69SBart Van Assche {
472*44704f69SBart Van Assche int k;
473*44704f69SBart Van Assche const uint8_t * bp;
474*44704f69SBart Van Assche
475*44704f69SBart Van Assche if (op->verbose)
476*44704f69SBart Van Assche printf("[r%c] ", (0x80 & alp[2]) ? 'o' : 'w');
477*44704f69SBart Van Assche if (op->verbose > 3)
478*44704f69SBart Van Assche pr2serr("%s: id=0x%x, len=%d, anip->format=%d, anip->len=%d\n",
479*44704f69SBart Van Assche __func__, id, len, anip->format, anip->len);
480*44704f69SBart Van Assche switch (id) {
481*44704f69SBart Van Assche case 0x224: /* logical position of first encrypted block */
482*44704f69SBart Van Assche k = all_ffs_or_last_fe(alp + 5, len - 5);
483*44704f69SBart Van Assche if (1 == k)
484*44704f69SBart Van Assche printf("<unknown> [ff]\n");
485*44704f69SBart Van Assche else if (2 == k)
486*44704f69SBart Van Assche printf("<unknown [fe]>\n");
487*44704f69SBart Van Assche else {
488*44704f69SBart Van Assche if ((len - 5) <= 8)
489*44704f69SBart Van Assche printf("%" PRIx64, sg_get_unaligned_be(len - 5, alp + 5));
490*44704f69SBart Van Assche else {
491*44704f69SBart Van Assche printf("\n");
492*44704f69SBart Van Assche hex2stdout((alp + 5), len - 5, 0);
493*44704f69SBart Van Assche }
494*44704f69SBart Van Assche }
495*44704f69SBart Van Assche break;
496*44704f69SBart Van Assche case 0x225: /* logical position of first unencrypted block
497*44704f69SBart Van Assche * after first encrypted block */
498*44704f69SBart Van Assche k = all_ffs_or_last_fe(alp + 5, len - 5);
499*44704f69SBart Van Assche if (1 == k)
500*44704f69SBart Van Assche printf("<unknown> [ff]\n");
501*44704f69SBart Van Assche else if (2 == k)
502*44704f69SBart Van Assche printf("<unknown [fe]>\n");
503*44704f69SBart Van Assche else {
504*44704f69SBart Van Assche if ((len - 5) <= 8)
505*44704f69SBart Van Assche printf("%" PRIx64, sg_get_unaligned_be(len - 5, alp + 5));
506*44704f69SBart Van Assche else {
507*44704f69SBart Van Assche printf("\n");
508*44704f69SBart Van Assche hex2stdout(alp + 5, len - 5, 0);
509*44704f69SBart Van Assche }
510*44704f69SBart Van Assche }
511*44704f69SBart Van Assche break;
512*44704f69SBart Van Assche case 0x340: /* Medium Usage history */
513*44704f69SBart Van Assche bp = alp + 5;
514*44704f69SBart Van Assche printf("\n");
515*44704f69SBart Van Assche if ((len - 5) < 90) {
516*44704f69SBart Van Assche pr2serr("%s: expected 90 bytes, got %d\n", __func__, len - 5);
517*44704f69SBart Van Assche break;
518*44704f69SBart Van Assche }
519*44704f69SBart Van Assche printf(" Current amount of data written [MiB]: %" PRIu64 "\n",
520*44704f69SBart Van Assche sg_get_unaligned_be48(bp + 0));
521*44704f69SBart Van Assche printf(" Current write retry count: %" PRIu64 "\n",
522*44704f69SBart Van Assche sg_get_unaligned_be48(bp + 6));
523*44704f69SBart Van Assche printf(" Current amount of data read [MiB]: %" PRIu64 "\n",
524*44704f69SBart Van Assche sg_get_unaligned_be48(bp + 12));
525*44704f69SBart Van Assche printf(" Current read retry count: %" PRIu64 "\n",
526*44704f69SBart Van Assche sg_get_unaligned_be48(bp + 18));
527*44704f69SBart Van Assche printf(" Previous amount of data written [MiB]: %" PRIu64 "\n",
528*44704f69SBart Van Assche sg_get_unaligned_be48(bp + 24));
529*44704f69SBart Van Assche printf(" Previous write retry count: %" PRIu64 "\n",
530*44704f69SBart Van Assche sg_get_unaligned_be48(bp + 30));
531*44704f69SBart Van Assche printf(" Previous amount of data read [MiB]: %" PRIu64 "\n",
532*44704f69SBart Van Assche sg_get_unaligned_be48(bp + 36));
533*44704f69SBart Van Assche printf(" Previous read retry count: %" PRIu64 "\n",
534*44704f69SBart Van Assche sg_get_unaligned_be48(bp + 42));
535*44704f69SBart Van Assche printf(" Total amount of data written [MiB]: %" PRIu64 "\n",
536*44704f69SBart Van Assche sg_get_unaligned_be48(bp + 48));
537*44704f69SBart Van Assche printf(" Total write retry count: %" PRIu64 "\n",
538*44704f69SBart Van Assche sg_get_unaligned_be48(bp + 54));
539*44704f69SBart Van Assche printf(" Total amount of data read [MiB]: %" PRIu64 "\n",
540*44704f69SBart Van Assche sg_get_unaligned_be48(bp + 60));
541*44704f69SBart Van Assche printf(" Total read retry count: %" PRIu64 "\n",
542*44704f69SBart Van Assche sg_get_unaligned_be48(bp + 66));
543*44704f69SBart Van Assche printf(" Load count: %" PRIu64 "\n",
544*44704f69SBart Van Assche sg_get_unaligned_be48(bp + 72));
545*44704f69SBart Van Assche printf(" Total change partition count: %" PRIu64 "\n",
546*44704f69SBart Van Assche sg_get_unaligned_be48(bp + 78));
547*44704f69SBart Van Assche printf(" Total partition initialization count: %" PRIu64 "\n",
548*44704f69SBart Van Assche sg_get_unaligned_be48(bp + 84));
549*44704f69SBart Van Assche break;
550*44704f69SBart Van Assche case 0x341: /* Partition Usage history */
551*44704f69SBart Van Assche bp = alp + 5;
552*44704f69SBart Van Assche printf("\n");
553*44704f69SBart Van Assche if ((len - 5) < 60) {
554*44704f69SBart Van Assche pr2serr("%s: expected 60 bytes, got %d\n", __func__, len - 5);
555*44704f69SBart Van Assche break;
556*44704f69SBart Van Assche }
557*44704f69SBart Van Assche printf(" Current amount of data written [MiB]: %" PRIu32 "\n",
558*44704f69SBart Van Assche sg_get_unaligned_be32(bp + 0));
559*44704f69SBart Van Assche printf(" Current write retry count: %" PRIu32 "\n",
560*44704f69SBart Van Assche sg_get_unaligned_be32(bp + 4));
561*44704f69SBart Van Assche printf(" Current amount of data read [MiB]: %" PRIu32 "\n",
562*44704f69SBart Van Assche sg_get_unaligned_be32(bp + 8));
563*44704f69SBart Van Assche printf(" Current read retry count: %" PRIu32 "\n",
564*44704f69SBart Van Assche sg_get_unaligned_be32(bp + 12));
565*44704f69SBart Van Assche printf(" Previous amount of data written [MiB]: %" PRIu32 "\n",
566*44704f69SBart Van Assche sg_get_unaligned_be32(bp + 16));
567*44704f69SBart Van Assche printf(" Previous write retry count: %" PRIu32 "\n",
568*44704f69SBart Van Assche sg_get_unaligned_be32(bp + 20));
569*44704f69SBart Van Assche printf(" Previous amount of data read [MiB]: %" PRIu32 "\n",
570*44704f69SBart Van Assche sg_get_unaligned_be32(bp + 24));
571*44704f69SBart Van Assche printf(" Previous read retry count: %" PRIu32 "\n",
572*44704f69SBart Van Assche sg_get_unaligned_be32(bp + 28));
573*44704f69SBart Van Assche printf(" Total amount of data written [MiB]: %" PRIu32 "\n",
574*44704f69SBart Van Assche sg_get_unaligned_be32(bp + 32));
575*44704f69SBart Van Assche printf(" Total write retry count: %" PRIu32 "\n",
576*44704f69SBart Van Assche sg_get_unaligned_be32(bp + 36));
577*44704f69SBart Van Assche printf(" Total amount of data read [MiB]: %" PRIu32 "\n",
578*44704f69SBart Van Assche sg_get_unaligned_be32(bp + 40));
579*44704f69SBart Van Assche printf(" Total read retry count: %" PRIu32 "\n",
580*44704f69SBart Van Assche sg_get_unaligned_be32(bp + 44));
581*44704f69SBart Van Assche printf(" Load count: %" PRIu32 "\n",
582*44704f69SBart Van Assche sg_get_unaligned_be32(bp + 48));
583*44704f69SBart Van Assche printf(" change partition count: %" PRIu32 "\n",
584*44704f69SBart Van Assche sg_get_unaligned_be32(bp + 52));
585*44704f69SBart Van Assche printf(" partition initialization count: %" PRIu32 "\n",
586*44704f69SBart Van Assche sg_get_unaligned_be32(bp + 56));
587*44704f69SBart Van Assche break;
588*44704f69SBart Van Assche default:
589*44704f69SBart Van Assche pr2serr("%s: unknown attribute id: 0x%x\n", __func__, id);
590*44704f69SBart Van Assche printf(" In hex:\n");
591*44704f69SBart Van Assche hex2stdout(alp, len, 0);
592*44704f69SBart Van Assche break;
593*44704f69SBart Van Assche }
594*44704f69SBart Van Assche }
595*44704f69SBart Van Assche
596*44704f69SBart Van Assche static void
decode_attr_vals(const uint8_t * alp,int len,const struct opts_t * op)597*44704f69SBart Van Assche decode_attr_vals(const uint8_t * alp, int len, const struct opts_t * op)
598*44704f69SBart Van Assche {
599*44704f69SBart Van Assche int bump, id, alen;
600*44704f69SBart Van Assche uint64_t ull;
601*44704f69SBart Van Assche char * cp;
602*44704f69SBart Van Assche char * c2p;
603*44704f69SBart Van Assche const struct attr_name_info_t * anip;
604*44704f69SBart Van Assche char b[160];
605*44704f69SBart Van Assche
606*44704f69SBart Van Assche if (op->verbose)
607*44704f69SBart Van Assche printf("Attribute values: [len=%d]\n", len);
608*44704f69SBart Van Assche else if (op->filter < 0) {
609*44704f69SBart Van Assche if (0 == op->quiet)
610*44704f69SBart Van Assche printf("Attribute values:\n");
611*44704f69SBart Van Assche if (op->do_hex) { /* only expect -HH to get through here */
612*44704f69SBart Van Assche hex2stdout(alp, len, 0);
613*44704f69SBart Van Assche return;
614*44704f69SBart Van Assche }
615*44704f69SBart Van Assche }
616*44704f69SBart Van Assche for ( ; len > 4; alp += bump, len -= bump) {
617*44704f69SBart Van Assche id = sg_get_unaligned_be16(alp + 0);
618*44704f69SBart Van Assche bump = sg_get_unaligned_be16(alp + 3) + 5;
619*44704f69SBart Van Assche alen = bump - 5;
620*44704f69SBart Van Assche if ((op->filter >= 0) && (op->filter != id)) {
621*44704f69SBart Van Assche if (id < op->filter)
622*44704f69SBart Van Assche continue;
623*44704f69SBart Van Assche else
624*44704f69SBart Van Assche break; /* Assume array is ascending id order */
625*44704f69SBart Van Assche }
626*44704f69SBart Van Assche anip = NULL;
627*44704f69SBart Van Assche cp = attr_id_lookup(id, &anip, sizeof(b), b);
628*44704f69SBart Van Assche if (op->quiet < 2) {
629*44704f69SBart Van Assche c2p = strchr(cp, '\t');
630*44704f69SBart Van Assche if (c2p) {
631*44704f69SBart Van Assche printf(" %.*s -\n", (int)(c2p - cp), cp);
632*44704f69SBart Van Assche printf(" %s: ", c2p + 1);
633*44704f69SBart Van Assche } else
634*44704f69SBart Van Assche printf(" %s: ", cp);
635*44704f69SBart Van Assche }
636*44704f69SBart Van Assche if (op->verbose)
637*44704f69SBart Van Assche printf("[r%c] ", (0x80 & alp[2]) ? 'o' : 'w');
638*44704f69SBart Van Assche if (anip) {
639*44704f69SBart Van Assche if ((RA_FMT_BINARY == anip->format) && (bump <= 13)) {
640*44704f69SBart Van Assche ull = sg_get_unaligned_be(alen, alp + 5);
641*44704f69SBart Van Assche if (0 == anip->process)
642*44704f69SBart Van Assche printf("%" PRIu64 "\n", ull);
643*44704f69SBart Van Assche else if (1 == anip->process)
644*44704f69SBart Van Assche printf("0x%" PRIx64 "\n", ull);
645*44704f69SBart Van Assche else
646*44704f69SBart Van Assche helper_full_attr(alp, bump, id, anip, op);
647*44704f69SBart Van Assche if (op->verbose) {
648*44704f69SBart Van Assche if ((anip->len > 0) && (alen > 0) && (alen != anip->len))
649*44704f69SBart Van Assche printf(" <<< T10 length (%d) differs from length in "
650*44704f69SBart Van Assche "response (%d) >>>\n", anip->len, alen);
651*44704f69SBart Van Assche }
652*44704f69SBart Van Assche } else if (RA_FMT_BINARY == anip->format) {
653*44704f69SBart Van Assche if (2 == anip->process)
654*44704f69SBart Van Assche helper_full_attr(alp, bump, id, anip, op);
655*44704f69SBart Van Assche else {
656*44704f69SBart Van Assche printf("\n");
657*44704f69SBart Van Assche hex2stdout(alp + 5, alen, 0);
658*44704f69SBart Van Assche }
659*44704f69SBart Van Assche } else {
660*44704f69SBart Van Assche if (2 == anip->process)
661*44704f69SBart Van Assche helper_full_attr(alp, bump, id, anip, op);
662*44704f69SBart Van Assche else {
663*44704f69SBart Van Assche printf("%.*s\n", alen, alp + 5);
664*44704f69SBart Van Assche if (op->verbose) {
665*44704f69SBart Van Assche if ((anip->len > 0) && (alen > 0) &&
666*44704f69SBart Van Assche (alen != anip->len))
667*44704f69SBart Van Assche printf(" <<< T10 length (%d) differs from length "
668*44704f69SBart Van Assche "in response (%d) >>>\n", anip->len, alen);
669*44704f69SBart Van Assche }
670*44704f69SBart Van Assche }
671*44704f69SBart Van Assche }
672*44704f69SBart Van Assche } else {
673*44704f69SBart Van Assche if (op->verbose > 1)
674*44704f69SBart Van Assche printf("Attribute id lookup failed, in hex:\n");
675*44704f69SBart Van Assche else
676*44704f69SBart Van Assche printf("\n");
677*44704f69SBart Van Assche hex2stdout(alp + 5, alen, 0);
678*44704f69SBart Van Assche }
679*44704f69SBart Van Assche }
680*44704f69SBart Van Assche if (op->verbose && (len > 0) && (len <= 4))
681*44704f69SBart Van Assche pr2serr("warning: iterate of attributes should end a residual of "
682*44704f69SBart Van Assche "%d\n", len);
683*44704f69SBart Van Assche }
684*44704f69SBart Van Assche
685*44704f69SBart Van Assche static void
decode_all_sa_s(const uint8_t * rabp,int len,const struct opts_t * op)686*44704f69SBart Van Assche decode_all_sa_s(const uint8_t * rabp, int len, const struct opts_t * op)
687*44704f69SBart Van Assche {
688*44704f69SBart Van Assche if (op->do_hex && (2 != op->do_hex)) {
689*44704f69SBart Van Assche hex2stdout(rabp, len, ((1 == op->do_hex) ? 1 : -1));
690*44704f69SBart Van Assche return;
691*44704f69SBart Van Assche }
692*44704f69SBart Van Assche switch (op->sa) {
693*44704f69SBart Van Assche case RA_ATTR_VAL_SA:
694*44704f69SBart Van Assche decode_attr_vals(rabp + 4, len - 4, op);
695*44704f69SBart Van Assche break;
696*44704f69SBart Van Assche case RA_ATTR_LIST_SA:
697*44704f69SBart Van Assche decode_attr_list(rabp + 4, len - 4, false, op);
698*44704f69SBart Van Assche break;
699*44704f69SBart Van Assche case RA_LV_LIST_SA:
700*44704f69SBart Van Assche if ((0 == op->quiet) || op->verbose)
701*44704f69SBart Van Assche printf("Logical volume list:\n");
702*44704f69SBart Van Assche if (len < 4) {
703*44704f69SBart Van Assche pr2serr(">>> response length unexpectedly short: %d bytes\n",
704*44704f69SBart Van Assche len);
705*44704f69SBart Van Assche break;
706*44704f69SBart Van Assche }
707*44704f69SBart Van Assche printf(" First logical volume number: %u\n", rabp[2]);
708*44704f69SBart Van Assche printf(" Number of logical volumes available: %u\n", rabp[3]);
709*44704f69SBart Van Assche break;
710*44704f69SBart Van Assche case RA_PART_LIST_SA:
711*44704f69SBart Van Assche if ((0 == op->quiet) || op->verbose)
712*44704f69SBart Van Assche printf("Partition number list:\n");
713*44704f69SBart Van Assche if (len < 4) {
714*44704f69SBart Van Assche pr2serr(">>> response length unexpectedly short: %d bytes\n",
715*44704f69SBart Van Assche len);
716*44704f69SBart Van Assche break;
717*44704f69SBart Van Assche }
718*44704f69SBart Van Assche printf(" First partition number: %u\n", rabp[2]);
719*44704f69SBart Van Assche printf(" Number of partitions available: %u\n", rabp[3]);
720*44704f69SBart Van Assche break;
721*44704f69SBart Van Assche case RA_SMC2_SA:
722*44704f69SBart Van Assche printf("Used by SMC-2, not information, output in hex:\n");
723*44704f69SBart Van Assche hex2stdout(rabp, len, 0);
724*44704f69SBart Van Assche break;
725*44704f69SBart Van Assche case RA_SUP_ATTR_SA:
726*44704f69SBart Van Assche decode_attr_list(rabp + 4, len - 4, true, op);
727*44704f69SBart Van Assche break;
728*44704f69SBart Van Assche default:
729*44704f69SBart Van Assche printf("Unrecognized service action [0x%x], response in hex:\n",
730*44704f69SBart Van Assche op->sa);
731*44704f69SBart Van Assche hex2stdout(rabp, len, 0);
732*44704f69SBart Van Assche break;
733*44704f69SBart Van Assche }
734*44704f69SBart Van Assche }
735*44704f69SBart Van Assche
736*44704f69SBart Van Assche int
main(int argc,char * argv[])737*44704f69SBart Van Assche main(int argc, char * argv[])
738*44704f69SBart Van Assche {
739*44704f69SBart Van Assche int sg_fd, res, c, len, resid, rlen;
740*44704f69SBart Van Assche unsigned int ra_len;
741*44704f69SBart Van Assche int in_len = 0;
742*44704f69SBart Van Assche int ret = 0;
743*44704f69SBart Van Assche const char * device_name = NULL;
744*44704f69SBart Van Assche const char * fname = NULL;
745*44704f69SBart Van Assche uint8_t * rabp = NULL;
746*44704f69SBart Van Assche uint8_t * free_rabp = NULL;
747*44704f69SBart Van Assche struct opts_t opts;
748*44704f69SBart Van Assche struct opts_t * op;
749*44704f69SBart Van Assche char b[80];
750*44704f69SBart Van Assche
751*44704f69SBart Van Assche op = &opts;
752*44704f69SBart Van Assche memset(op, 0, sizeof(opts));
753*44704f69SBart Van Assche op->filter = -1;
754*44704f69SBart Van Assche while (1) {
755*44704f69SBart Van Assche int option_index = 0;
756*44704f69SBart Van Assche
757*44704f69SBart Van Assche c = getopt_long(argc, argv, "ceE:f:F:hHi:l:m:p:qrRs:vV",
758*44704f69SBart Van Assche long_options, &option_index);
759*44704f69SBart Van Assche if (c == -1)
760*44704f69SBart Van Assche break;
761*44704f69SBart Van Assche
762*44704f69SBart Van Assche switch (c) {
763*44704f69SBart Van Assche case 'c':
764*44704f69SBart Van Assche op->cache = true;
765*44704f69SBart Van Assche break;
766*44704f69SBart Van Assche case 'e':
767*44704f69SBart Van Assche op->enumerate = true;
768*44704f69SBart Van Assche break;
769*44704f69SBart Van Assche case 'E':
770*44704f69SBart Van Assche op->elem_addr = sg_get_num(optarg);
771*44704f69SBart Van Assche if ((op->elem_addr < 0) || (op->elem_addr > 65535)) {
772*44704f69SBart Van Assche pr2serr("bad argument to '--element=EA', expect 0 to 65535\n");
773*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
774*44704f69SBart Van Assche }
775*44704f69SBart Van Assche break;
776*44704f69SBart Van Assche case 'f':
777*44704f69SBart Van Assche op->filter = sg_get_num(optarg);
778*44704f69SBart Van Assche if ((op->filter < -3) || (op->filter > 65535)) {
779*44704f69SBart Van Assche pr2serr("bad argument to '--filter=FL', expect -3 to "
780*44704f69SBart Van Assche "65535\n");
781*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
782*44704f69SBart Van Assche }
783*44704f69SBart Van Assche break;
784*44704f69SBart Van Assche case 'F':
785*44704f69SBart Van Assche op->fai = sg_get_num(optarg);
786*44704f69SBart Van Assche if ((op->fai < 0) || (op->fai > 65535)) {
787*44704f69SBart Van Assche pr2serr("bad argument to '--first=FAI', expect 0 to 65535\n");
788*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
789*44704f69SBart Van Assche }
790*44704f69SBart Van Assche break;
791*44704f69SBart Van Assche case 'h':
792*44704f69SBart Van Assche case '?':
793*44704f69SBart Van Assche usage();
794*44704f69SBart Van Assche return 0;
795*44704f69SBart Van Assche case 'H':
796*44704f69SBart Van Assche ++op->do_hex;
797*44704f69SBart Van Assche break;
798*44704f69SBart Van Assche case 'i':
799*44704f69SBart Van Assche fname = optarg;
800*44704f69SBart Van Assche break;
801*44704f69SBart Van Assche case 'l':
802*44704f69SBart Van Assche op->lvn = sg_get_num(optarg);
803*44704f69SBart Van Assche if ((op->lvn < 0) || (op->lvn > 255)) {
804*44704f69SBart Van Assche pr2serr("bad argument to '--lvn=LVN', expect 0 to 255\n");
805*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
806*44704f69SBart Van Assche }
807*44704f69SBart Van Assche break;
808*44704f69SBart Van Assche case 'm':
809*44704f69SBart Van Assche op->maxlen = sg_get_num(optarg);
810*44704f69SBart Van Assche if ((op->maxlen < 0) || (op->maxlen > MAX_RATTR_BUFF_LEN)) {
811*44704f69SBart Van Assche pr2serr("argument to '--maxlen' should be %d or "
812*44704f69SBart Van Assche "less\n", MAX_RATTR_BUFF_LEN);
813*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
814*44704f69SBart Van Assche }
815*44704f69SBart Van Assche break;
816*44704f69SBart Van Assche case 'p':
817*44704f69SBart Van Assche op->pn = sg_get_num(optarg);
818*44704f69SBart Van Assche if ((op->pn < 0) || (op->pn > 255)) {
819*44704f69SBart Van Assche pr2serr("bad argument to '--pn=PN', expect 0 to 255\n");
820*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
821*44704f69SBart Van Assche }
822*44704f69SBart Van Assche break;
823*44704f69SBart Van Assche case 'q':
824*44704f69SBart Van Assche ++op->quiet;
825*44704f69SBart Van Assche break;
826*44704f69SBart Van Assche case 'r':
827*44704f69SBart Van Assche op->do_raw = true;
828*44704f69SBart Van Assche break;
829*44704f69SBart Van Assche case 'R':
830*44704f69SBart Van Assche op->o_readonly = true;
831*44704f69SBart Van Assche break;
832*44704f69SBart Van Assche case 's':
833*44704f69SBart Van Assche if (isdigit((uint8_t)*optarg)) {
834*44704f69SBart Van Assche op->sa = sg_get_num(optarg);
835*44704f69SBart Van Assche if ((op->sa < 0) || (op->sa > 63)) {
836*44704f69SBart Van Assche pr2serr("bad argument to '--sa=SA', expect 0 to 63\n");
837*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
838*44704f69SBart Van Assche }
839*44704f69SBart Van Assche } else {
840*44704f69SBart Van Assche res = find_sa_acron(optarg);
841*44704f69SBart Van Assche if (res < 0) {
842*44704f69SBart Van Assche enum_sa_acrons();
843*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
844*44704f69SBart Van Assche }
845*44704f69SBart Van Assche op->sa = res;
846*44704f69SBart Van Assche }
847*44704f69SBart Van Assche break;
848*44704f69SBart Van Assche case 'v':
849*44704f69SBart Van Assche op->verbose_given = true;
850*44704f69SBart Van Assche ++op->verbose;
851*44704f69SBart Van Assche break;
852*44704f69SBart Van Assche case 'V':
853*44704f69SBart Van Assche op->version_given = true;
854*44704f69SBart Van Assche break;
855*44704f69SBart Van Assche default:
856*44704f69SBart Van Assche pr2serr("unrecognised option code 0x%x ??\n", c);
857*44704f69SBart Van Assche usage();
858*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
859*44704f69SBart Van Assche }
860*44704f69SBart Van Assche }
861*44704f69SBart Van Assche if (optind < argc) {
862*44704f69SBart Van Assche if (NULL == device_name) {
863*44704f69SBart Van Assche device_name = argv[optind];
864*44704f69SBart Van Assche ++optind;
865*44704f69SBart Van Assche }
866*44704f69SBart Van Assche if (optind < argc) {
867*44704f69SBart Van Assche for (; optind < argc; ++optind)
868*44704f69SBart Van Assche pr2serr("Unexpected extra argument: %s\n", argv[optind]);
869*44704f69SBart Van Assche usage();
870*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
871*44704f69SBart Van Assche }
872*44704f69SBart Van Assche }
873*44704f69SBart Van Assche #ifdef DEBUG
874*44704f69SBart Van Assche pr2serr("In DEBUG mode, ");
875*44704f69SBart Van Assche if (op->verbose_given && op->version_given) {
876*44704f69SBart Van Assche pr2serr("but override: '-vV' given, zero verbose and continue\n");
877*44704f69SBart Van Assche op->verbose_given = false;
878*44704f69SBart Van Assche op->version_given = false;
879*44704f69SBart Van Assche op->verbose = 0;
880*44704f69SBart Van Assche } else if (! op->verbose_given) {
881*44704f69SBart Van Assche pr2serr("set '-vv'\n");
882*44704f69SBart Van Assche op->verbose = 2;
883*44704f69SBart Van Assche } else
884*44704f69SBart Van Assche pr2serr("keep verbose=%d\n", op->verbose);
885*44704f69SBart Van Assche #else
886*44704f69SBart Van Assche if (op->verbose_given && op->version_given)
887*44704f69SBart Van Assche pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
888*44704f69SBart Van Assche #endif
889*44704f69SBart Van Assche if (op->version_given) {
890*44704f69SBart Van Assche pr2serr("version: %s\n", version_str);
891*44704f69SBart Van Assche return 0;
892*44704f69SBart Van Assche }
893*44704f69SBart Van Assche
894*44704f69SBart Van Assche if (op->enumerate) {
895*44704f69SBart Van Assche enum_attributes();
896*44704f69SBart Van Assche printf("\n");
897*44704f69SBart Van Assche enum_sa_acrons();
898*44704f69SBart Van Assche return 0;
899*44704f69SBart Van Assche }
900*44704f69SBart Van Assche
901*44704f69SBart Van Assche if (fname && device_name) {
902*44704f69SBart Van Assche pr2serr("since '--in=FN' given, ignoring DEVICE\n");
903*44704f69SBart Van Assche device_name = NULL;
904*44704f69SBart Van Assche }
905*44704f69SBart Van Assche
906*44704f69SBart Van Assche if (0 == op->maxlen)
907*44704f69SBart Van Assche op->maxlen = DEF_RATTR_BUFF_LEN;
908*44704f69SBart Van Assche rabp = (uint8_t *)sg_memalign(op->maxlen, 0, &free_rabp, op->verbose > 3);
909*44704f69SBart Van Assche if (NULL == rabp) {
910*44704f69SBart Van Assche pr2serr("unable to sg_memalign %d bytes\n", op->maxlen);
911*44704f69SBart Van Assche return sg_convert_errno(ENOMEM);
912*44704f69SBart Van Assche }
913*44704f69SBart Van Assche
914*44704f69SBart Van Assche if (NULL == device_name) {
915*44704f69SBart Van Assche if (fname) {
916*44704f69SBart Van Assche if ((ret = sg_f2hex_arr(fname, op->do_raw, false /* no space */,
917*44704f69SBart Van Assche rabp, &in_len, op->maxlen)))
918*44704f69SBart Van Assche goto clean_up;
919*44704f69SBart Van Assche if (op->do_raw)
920*44704f69SBart Van Assche op->do_raw = false; /* can interfere on decode */
921*44704f69SBart Van Assche if (in_len < 4) {
922*44704f69SBart Van Assche pr2serr("--in=%s only decoded %d bytes (needs 4 at least)\n",
923*44704f69SBart Van Assche fname, in_len);
924*44704f69SBart Van Assche ret = SG_LIB_SYNTAX_ERROR;
925*44704f69SBart Van Assche goto clean_up;
926*44704f69SBart Van Assche }
927*44704f69SBart Van Assche decode_all_sa_s(rabp, in_len, op);
928*44704f69SBart Van Assche goto clean_up;
929*44704f69SBart Van Assche }
930*44704f69SBart Van Assche pr2serr("missing device name!\n");
931*44704f69SBart Van Assche usage();
932*44704f69SBart Van Assche ret = SG_LIB_SYNTAX_ERROR;
933*44704f69SBart Van Assche goto clean_up;
934*44704f69SBart Van Assche }
935*44704f69SBart Van Assche
936*44704f69SBart Van Assche if (op->do_raw) {
937*44704f69SBart Van Assche if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
938*44704f69SBart Van Assche perror("sg_set_binary_mode");
939*44704f69SBart Van Assche ret = SG_LIB_FILE_ERROR;
940*44704f69SBart Van Assche goto clean_up;
941*44704f69SBart Van Assche }
942*44704f69SBart Van Assche }
943*44704f69SBart Van Assche
944*44704f69SBart Van Assche sg_fd = sg_cmds_open_device(device_name, op->o_readonly, op->verbose);
945*44704f69SBart Van Assche if (sg_fd < 0) {
946*44704f69SBart Van Assche pr2serr("open error: %s: %s\n", device_name,
947*44704f69SBart Van Assche safe_strerror(-sg_fd));
948*44704f69SBart Van Assche ret = sg_convert_errno(-sg_fd);
949*44704f69SBart Van Assche goto clean_up;
950*44704f69SBart Van Assche }
951*44704f69SBart Van Assche
952*44704f69SBart Van Assche res = sg_ll_read_attr(sg_fd, rabp, &resid, op->verbose > 0, op);
953*44704f69SBart Van Assche ret = res;
954*44704f69SBart Van Assche if (0 == res) {
955*44704f69SBart Van Assche rlen = op->maxlen - resid;
956*44704f69SBart Van Assche if (rlen < 4) {
957*44704f69SBart Van Assche pr2serr("Response length (%d) too short\n", rlen);
958*44704f69SBart Van Assche ret = SG_LIB_CAT_MALFORMED;
959*44704f69SBart Van Assche goto close_then_end;
960*44704f69SBart Van Assche }
961*44704f69SBart Van Assche if ((op->sa <= RA_HIGHEST_SA) && (op->sa != RA_SMC2_SA)) {
962*44704f69SBart Van Assche ra_len = ((RA_LV_LIST_SA == op->sa) ||
963*44704f69SBart Van Assche (RA_PART_LIST_SA == op->sa)) ?
964*44704f69SBart Van Assche (unsigned int)sg_get_unaligned_be16(rabp + 0) :
965*44704f69SBart Van Assche sg_get_unaligned_be32(rabp + 0) + 2;
966*44704f69SBart Van Assche ra_len += 2;
967*44704f69SBart Van Assche } else
968*44704f69SBart Van Assche ra_len = rlen;
969*44704f69SBart Van Assche if ((int)ra_len > rlen) {
970*44704f69SBart Van Assche if (op->verbose)
971*44704f69SBart Van Assche pr2serr("ra_len available is %d, response length is %d\n",
972*44704f69SBart Van Assche ra_len, rlen);
973*44704f69SBart Van Assche len = rlen;
974*44704f69SBart Van Assche } else
975*44704f69SBart Van Assche len = (int)ra_len;
976*44704f69SBart Van Assche if (op->do_raw) {
977*44704f69SBart Van Assche dStrRaw((const char *)rabp, len);
978*44704f69SBart Van Assche goto close_then_end;
979*44704f69SBart Van Assche }
980*44704f69SBart Van Assche decode_all_sa_s(rabp, len, op);
981*44704f69SBart Van Assche } else if (SG_LIB_CAT_INVALID_OP == res)
982*44704f69SBart Van Assche pr2serr("Read attribute command not supported\n");
983*44704f69SBart Van Assche else {
984*44704f69SBart Van Assche sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
985*44704f69SBart Van Assche pr2serr("Read attribute command: %s\n", b);
986*44704f69SBart Van Assche }
987*44704f69SBart Van Assche
988*44704f69SBart Van Assche close_then_end:
989*44704f69SBart Van Assche res = sg_cmds_close_device(sg_fd);
990*44704f69SBart Van Assche if (res < 0) {
991*44704f69SBart Van Assche pr2serr("close error: %s\n", safe_strerror(-res));
992*44704f69SBart Van Assche if (0 == ret)
993*44704f69SBart Van Assche ret = sg_convert_errno(-res);
994*44704f69SBart Van Assche }
995*44704f69SBart Van Assche clean_up:
996*44704f69SBart Van Assche if (free_rabp)
997*44704f69SBart Van Assche free(free_rabp);
998*44704f69SBart Van Assche if (0 == op->verbose) {
999*44704f69SBart Van Assche if (! sg_if_can2stderr("sg_read_attr failed: ", ret))
1000*44704f69SBart Van Assche pr2serr("Some error occurred, try again with '-v' or '-vv' for "
1001*44704f69SBart Van Assche "more information\n");
1002*44704f69SBart Van Assche }
1003*44704f69SBart Van Assche return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
1004*44704f69SBart Van Assche }
1005