xref: /aosp_15_r20/external/sg3_utils/src/sg_read_attr.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
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