1 /* A utility program originally written for the Linux OS SCSI subsystem.
2 * Copyright (C) 2000-2022 D. Gilbert
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 *
10 * This program outputs information provided by a SCSI INQUIRY command.
11 * It is mainly based on the SCSI SPC-6 document at https://www.t10.org .
12 *
13 * Acknowledgment:
14 * - Martin Schwenke <martin at meltin dot net> added the raw switch and
15 * other improvements [20020814]
16 * - Lars Marowsky-Bree <lmb at suse dot de> contributed Unit Path Report
17 * VPD page decoding for EMC CLARiiON devices [20041016]
18 */
19
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdbool.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <ctype.h>
28 #include <getopt.h>
29 #define __STDC_FORMAT_MACROS 1
30 #include <inttypes.h>
31 #include <errno.h>
32
33 #ifdef SG_LIB_LINUX
34 #include <sys/ioctl.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <linux/hdreg.h>
38 #endif
39
40 #ifdef HAVE_CONFIG_H
41 #include "config.h"
42 #endif
43
44 #include "sg_lib.h"
45 #include "sg_lib_data.h"
46 #include "sg_cmds_basic.h"
47 #include "sg_pt.h"
48 #include "sg_unaligned.h"
49 #include "sg_pr2serr.h"
50 #if (HAVE_NVME && (! IGNORE_NVME))
51 #include "sg_pt_nvme.h"
52 #endif
53
54 #include "sg_vpd_common.h" /* for shared VPD page processing with sg_vpd */
55
56 static const char * version_str = "2.31 20220915"; /* spc6r06, sbc5r03 */
57
58 #define MY_NAME "sg_inq"
59
60 /* INQUIRY notes:
61 * It is recommended that the initial allocation length given to a
62 * standard INQUIRY is 36 (bytes), especially if this is the first
63 * SCSI command sent to a logical unit. This is compliant with SCSI-2
64 * and another major operating system. There are devices out there
65 * that use one of the SCSI commands sets and lock up if they receive
66 * an allocation length other than 36. This technique is sometimes
67 * referred to as a "36 byte INQUIRY".
68 *
69 * A "standard" INQUIRY is one that has the EVPD and the CmdDt bits
70 * clear.
71 *
72 * When doing device discovery on a SCSI transport (e.g. bus scanning)
73 * the first SCSI command sent to a device should be a standard (36
74 * byte) INQUIRY.
75 *
76 * The allocation length field in the INQUIRY command was changed
77 * from 1 to 2 bytes in SPC-3, revision 9, 17 September 2002.
78 * Be careful using allocation lengths greater than 252 bytes, especially
79 * if the lower byte is 0x0 (e.g. a 512 byte allocation length may
80 * not be a good arbitrary choice (as 512 == 0x200) ).
81 *
82 * From SPC-3 revision 16 the CmdDt bit in an INQUIRY is obsolete. There
83 * is now a REPORT SUPPORTED OPERATION CODES command that yields similar
84 * information [MAINTENANCE IN, service action = 0xc]; see sg_opcodes.
85 */
86
87 // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TESTING
88 // #undef SG_SCSI_STRINGS
89 // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TESTING
90
91 #define VPD_NOPE_WANT_STD_INQ -2 /* request for standard inquiry */
92
93 /* Vendor specific VPD pages (typically >= 0xc0) */
94 #define VPD_UPR_EMC 0xc0
95 #define VPD_RDAC_VERS 0xc2
96 #define VPD_RDAC_VAC 0xc9
97
98 /* values for selection one or more associations (2**vpd_assoc),
99 except _AS_IS */
100 #define VPD_DI_SEL_LU 1
101 #define VPD_DI_SEL_TPORT 2
102 #define VPD_DI_SEL_TARGET 4
103 #define VPD_DI_SEL_AS_IS 32
104
105 #define DEF_ALLOC_LEN 252 /* highest 1 byte value that is modulo 4 */
106 #define SAFE_STD_INQ_RESP_LEN 36
107 #define MX_ALLOC_LEN (0xc000 + 0x80)
108 #define VPD_ATA_INFO_LEN 572
109
110 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
111 #define INQUIRY_CMD 0x12
112 #define INQUIRY_CMDLEN 6
113 #define DEF_PT_TIMEOUT 60 /* 60 seconds */
114
115
116 uint8_t * rsp_buff;
117
118 static uint8_t * free_rsp_buff;
119 static const int rsp_buff_sz = MX_ALLOC_LEN + 1;
120
121 static char xtra_buff[MX_ALLOC_LEN + 1];
122 static char usn_buff[MX_ALLOC_LEN + 1];
123
124 static const char * find_version_descriptor_str(int value);
125 static void decode_dev_ids(const char * leadin, uint8_t * buff, int len,
126 struct opts_t * op, sgj_opaque_p jop);
127 static int vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
128 int off);
129
130 // Test define that will only work for Linux
131 // #define HDIO_GET_IDENTITY 1
132
133 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
134 defined(HDIO_GET_IDENTITY)
135 #include <sys/ioctl.h>
136
137 static int try_ata_identify(int ata_fd, int do_hex, int do_raw,
138 int verbose);
139 static void prepare_ata_identify(const struct opts_t * op, int inhex_len);
140 #endif
141
142
143 /* Note that this table is sorted by acronym */
144 static struct svpd_values_name_t t10_vpd_pg[] = {
145 {VPD_AUTOMATION_DEV_SN, 0, 1, "adsn", "Automation device serial "
146 "number (SSC)"},
147 {VPD_ATA_INFO, 0, -1, "ai", "ATA information (SAT)"},
148 {VPD_BLOCK_DEV_CHARS, 0, 0, "bdc",
149 "Block device characteristics (SBC)"},
150 {VPD_BLOCK_DEV_C_EXTENS, 0, 0, "bdce", "Block device characteristics "
151 "extension (SBC)"},
152 {VPD_BLOCK_LIMITS, 0, 0, "bl", "Block limits (SBC)"},
153 {VPD_BLOCK_LIMITS_EXT, 0, 0, "ble", "Block limits extension (SBC)"},
154 {VPD_CFA_PROFILE_INFO, 0, 0, "cfa", "CFA profile information"},
155 {VPD_CON_POS_RANGE, 0, 0, "cpr", "Concurrent positioning ranges "
156 "(SBC)"},
157 {VPD_DEVICE_CONSTITUENTS, 0, -1, "dc", "Device constituents"},
158 {VPD_DEVICE_ID, 0, -1, "di", "Device identification"},
159 #if 0 /* following found in sg_vpd */
160 {VPD_DEVICE_ID, VPD_DI_SEL_AS_IS, -1, "di_asis", "Like 'di' "
161 "but designators ordered as found"},
162 {VPD_DEVICE_ID, VPD_DI_SEL_LU, -1, "di_lu", "Device identification, "
163 "lu only"},
164 {VPD_DEVICE_ID, VPD_DI_SEL_TPORT, -1, "di_port", "Device "
165 "identification, target port only"},
166 {VPD_DEVICE_ID, VPD_DI_SEL_TARGET, -1, "di_target", "Device "
167 "identification, target device only"},
168 #endif
169 {VPD_EXT_INQ, 0, -1, "ei", "Extended inquiry data"},
170 {VPD_FORMAT_PRESETS, 0, 0, "fp", "Format presets"},
171 {VPD_LB_PROTECTION, 0, 0, "lbpro", "Logical block protection (SSC)"},
172 {VPD_LB_PROVISIONING, 0, 0, "lbpv", "Logical block provisioning "
173 "(SBC)"},
174 {VPD_MAN_ASS_SN, 0, 1, "mas", "Manufacturer assigned serial number (SSC)"},
175 {VPD_MAN_ASS_SN, 0, 0x12, "masa",
176 "Manufacturer assigned serial number (ADC)"},
177 {VPD_MAN_NET_ADDR, 0, -1, "mna", "Management network addresses"},
178 {VPD_MODE_PG_POLICY, 0, -1, "mpp", "Mode page policy"},
179 {VPD_POWER_CONDITION, 0, -1, "po", "Power condition"},/* "pc" in sg_vpd */
180 {VPD_POWER_CONSUMPTION, 0, -1, "psm", "Power consumption"},
181 {VPD_PROTO_LU, 0, -1, "pslu", "Protocol-specific logical unit "
182 "information"},
183 {VPD_PROTO_PORT, 0, -1, "pspo", "Protocol-specific port information"},
184 {VPD_REFERRALS, 0, 0, "ref", "Referrals (SBC)"},
185 {VPD_SA_DEV_CAP, 0, 1, "sad",
186 "Sequential access device capabilities (SSC)"},
187 {VPD_SUP_BLOCK_LENS, 0, 0, "sbl", "Supported block lengths and "
188 "protection types (SBC)"},
189 {VPD_SCSI_FEATURE_SETS, 0, -1, "sfs", "SCSI Feature sets"},
190 {VPD_SOFTW_INF_ID, 0, -1, "sii", "Software interface identification"},
191 {VPD_NOPE_WANT_STD_INQ, 0, -1, "sinq", "Standard inquiry data format"},
192 {VPD_UNIT_SERIAL_NUM, 0, -1, "sn", "Unit serial number"},
193 {VPD_SCSI_PORTS, 0, -1, "sp", "SCSI ports"},
194 {VPD_SUPPORTED_VPDS, 0, -1, "sv", "Supported VPD pages"},
195 {VPD_TA_SUPPORTED, 0, 1, "tas", "TapeAlert supported flags (SSC)"},
196 {VPD_3PARTY_COPY, 0, -1, "tpc", "Third party copy"},
197 {VPD_ZBC_DEV_CHARS, 0, 0, "zbdch", "Zoned block device "
198 "characteristics"},
199 {0, 0, 0, NULL, NULL},
200 };
201
202 /* Some alternate acronyms for T10 VPD pages (compatibility with sg_vpd) */
203 static struct svpd_values_name_t alt_t10_vpd_pg[] = {
204 {VPD_NOPE_WANT_STD_INQ, 0, -1, "stdinq", "Standard inquiry data format"},
205 {VPD_POWER_CONDITION, 0, -1, "pc", "Power condition"},
206 {0, 0, 0, NULL, NULL},
207 };
208
209 static struct svpd_values_name_t vs_vpd_pg[] = {
210 /* Following are vendor specific */
211 {SG_NVME_VPD_NICR, 0, -1, "nicr",
212 "NVMe Identify Controller Response (sg3_utils)"},
213 {VPD_RDAC_VAC, 0, -1, "rdac_vac", "RDAC volume access control (RDAC)"},
214 {VPD_RDAC_VERS, 0, -1, "rdac_vers", "RDAC software version (RDAC)"},
215 {VPD_UPR_EMC, 0, -1, "upr", "Unit path report (EMC)"},
216 {0, 0, 0, NULL, NULL},
217 };
218
219 static struct option long_options[] = {
220 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
221 defined(HDIO_GET_IDENTITY)
222 {"ata", no_argument, 0, 'a'},
223 #endif
224 {"block", required_argument, 0, 'B'},
225 {"cmddt", no_argument, 0, 'c'},
226 {"descriptors", no_argument, 0, 'd'},
227 {"export", no_argument, 0, 'u'},
228 {"extended", no_argument, 0, 'x'},
229 {"force", no_argument, 0, 'f'},
230 {"help", no_argument, 0, 'h'},
231 {"hex", no_argument, 0, 'H'},
232 {"id", no_argument, 0, 'i'},
233 {"inhex", required_argument, 0, 'I'},
234 {"len", required_argument, 0, 'l'},
235 {"long", no_argument, 0, 'L'},
236 {"maxlen", required_argument, 0, 'm'},
237 #ifdef SG_SCSI_STRINGS
238 {"new", no_argument, 0, 'N'},
239 {"old", no_argument, 0, 'O'},
240 #endif
241 {"only", no_argument, 0, 'o'},
242 {"page", required_argument, 0, 'p'},
243 {"raw", no_argument, 0, 'r'},
244 {"sinq_inraw", required_argument, 0, 'Q'},
245 {"sinq-inraw", required_argument, 0, 'Q'},
246 {"vendor", no_argument, 0, 's'},
247 {"verbose", no_argument, 0, 'v'},
248 {"version", no_argument, 0, 'V'},
249 {"vpd", no_argument, 0, 'e'},
250 {0, 0, 0, 0},
251 };
252
253
254 static void
usage()255 usage()
256 {
257 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
258 defined(HDIO_GET_IDENTITY)
259
260 pr2serr("Usage: sg_inq [--ata] [--block=0|1] [--cmddt] [--descriptors] "
261 "[--export]\n"
262 " [--extended] [--help] [--hex] [--id] "
263 "[--inhex=FN]\n"
264 " [--json[=JO]] [--len=LEN] [--long] "
265 "[--maxlen=LEN]\n"
266 " [--only] [--page=PG] [--raw] [--sinq_inraw=RFN] "
267 "[--vendor]\n"
268 " [--verbose] [--version] [--vpd] DEVICE\n"
269 " where:\n"
270 " --ata|-a treat DEVICE as (directly attached) ATA "
271 "device\n");
272 #else
273 pr2serr("Usage: sg_inq [--block=0|1] [--cmddt] [--descriptors] "
274 "[--export]\n"
275 " [--extended] [--help] [--hex] [--id] "
276 "[--inhex=FN]\n"
277 " [--json[=JO]] [--len=LEN] [--long] "
278 "[--maxlen=LEN]\n"
279 " [--only] [--page=PG] [--raw] [--sinq_inraw=RFN] "
280 "[--verbose]\n"
281 " [--version] [--vpd] DEVICE\n"
282 " where:\n");
283 #endif
284 pr2serr(" --block=0|1 0-> open(non-blocking); 1-> "
285 "open(blocking)\n"
286 " -B 0|1 (def: depends on OS; Linux pt: 0)\n"
287 " --cmddt|-c command support data mode (set opcode "
288 "with '--page=PG')\n"
289 " use twice for list of supported "
290 "commands; obsolete\n"
291 " --descriptors|-d fetch and decode version descriptors\n"
292 " --export|-u SCSI_IDENT_<assoc>_<type>=<ident> output "
293 "format.\n"
294 " Defaults to device id page (0x83) if --page "
295 "not given,\n"
296 " only supported for VPD pages 0x80 and 0x83\n"
297 " --extended|-E|-x decode extended INQUIRY data VPD page "
298 "(0x86)\n"
299 " --force|-f skip VPD page 0 check; directly fetch "
300 "requested page\n"
301 " --help|-h print usage message then exit\n"
302 " --hex|-H output response in hex\n"
303 " --id|-i decode device identification VPD page "
304 "(0x83)\n"
305 " --inhex=FN|-I FN read ASCII hex from file FN instead of "
306 "DEVICE;\n"
307 " if used with --raw then read binary "
308 "from FN\n"
309 " --json[=JO]|-j[JO] output in JSON instead of human "
310 "readable text.\n"
311 " Use --json=? for JSON help\n"
312 " --len=LEN|-l LEN requested response length (def: 0 "
313 "-> fetch 36\n"
314 " bytes first, then fetch again as "
315 "indicated)\n"
316 " --long|-L supply extra information on NVMe devices\n"
317 " --maxlen=LEN|-m LEN same as '--len='\n"
318 " --old|-O use old interface (use as first option)\n"
319 " --only|-o for std inquiry do not fetch serial number "
320 "vpd page;\n"
321 " for NVMe device only do Identify "
322 "controller\n"
323 " --page=PG|-p PG Vital Product Data (VPD) page number "
324 "or\n"
325 " abbreviation (opcode number if "
326 "'--cmddt' given)\n"
327 " --raw|-r output response in binary (to stdout)\n"
328 " --sinq_inraw=RFN|-Q RFN read raw (binary) standard "
329 "INQUIRY\n"
330 " response from the RFN filename\n"
331 " --vendor|-s show vendor specific fields in std "
332 "inquiry\n"
333 " --verbose|-v increase verbosity\n"
334 " --version|-V print version string then exit\n"
335 " --vpd|-e vital product data (set page with "
336 "'--page=PG')\n\n"
337 "Sends a SCSI INQUIRY command to the DEVICE and decodes the "
338 "response.\nAlternatively it decodes the INQUIRY response held "
339 "in file FN. If no\noptions given then it sends a 'standard' "
340 "INQUIRY command to DEVICE. Can\nlist VPD pages with '--vpd' or "
341 "'--page=PG' option.\n");
342 }
343
344 #ifdef SG_SCSI_STRINGS
345 static void
usage_old()346 usage_old()
347 {
348 #ifdef SG_LIB_LINUX
349 pr2serr("Usage: sg_inq [-a] [-A] [-b] [-B=0|1] [-c] [-cl] [-d] [-e] "
350 "[-h]\n"
351 " [-H] [-i] [-I=FN] [-j[=JO]] [-l=LEN] [-L] [-m] "
352 "[-M]\n"
353 " [-o] [-p=VPD_PG] [-P] [-r] [-s] [-u] [-U] [-v] "
354 "[-V]\n"
355 " [-x] [-36] [-?] DEVICE\n"
356 " where:\n"
357 " -a decode ATA information VPD page (0x89)\n"
358 " -A treat <device> as (directly attached) ATA device\n");
359 #else
360 pr2serr("Usage: sg_inq [-a] [-b] [-B 0|1] [-c] [-cl] [-d] [-e] [-h] "
361 "[-H]\n"
362 " [-i] [-l=LEN] [-L] [-m] [-M] [-o] "
363 "[-p=VPD_PG]\n"
364 " [-P] [-r] [-s] [-u] [-v] [-V] [-x] [-36] "
365 "[-?]\n"
366 " DEVICE\n"
367 " where:\n"
368 " -a decode ATA information VPD page (0x89)\n");
369
370 #endif /* SG_LIB_LINUX */
371 pr2serr(" -b decode Block limits VPD page (0xb0) (SBC)\n"
372 " -B=0|1 0-> open(non-blocking); 1->open(blocking)\n"
373 " -c set CmdDt mode (use -o for opcode) [obsolete]\n"
374 " -cl list supported commands using CmdDt mode [obsolete]\n"
375 " -d decode: version descriptors or VPD page\n"
376 " -e set VPD mode (use -p for page code)\n"
377 " -h output in hex (ASCII to the right)\n"
378 " -H output in hex (ASCII to the right) [same as '-h']\n"
379 " -i decode device identification VPD page (0x83)\n"
380 " -I=FN use ASCII hex in file FN instead of DEVICE\n"
381 " -j[=JO] output in JSON instead of human readable "
382 "text.\n"
383 " -l=LEN requested response length (def: 0 "
384 "-> fetch 36\n"
385 " bytes first, then fetch again as "
386 "indicated)\n"
387 " -L supply extra information on NVMe devices\n"
388 " -m decode management network addresses VPD page "
389 "(0x85)\n"
390 " -M decode mode page policy VPD page (0x87)\n"
391 " -N|--new use new interface\n"
392 " -o for std inquiry only do that, not serial number vpd "
393 "page\n"
394 " -p=VPD_PG vpd page code in hex (def: 0)\n"
395 " -P decode Unit Path Report VPD page (0xc0) (EMC)\n"
396 " -r output response in binary ('-rr': output for hdparm)\n"
397 " -s decode SCSI Ports VPD page (0x88)\n"
398 " -u SCSI_IDENT_<assoc>_<type>=<ident> output format\n"
399 " -v verbose (output cdb and, if non-zero, resid)\n"
400 " -V output version string\n"
401 " -x decode extended INQUIRY data VPD page (0x86)\n"
402 " -36 perform standard INQUIRY with a 36 byte response\n"
403 " -? output this usage message\n\n"
404 "If no options given then sends a standard SCSI INQUIRY "
405 "command and\ndecodes the response.\n");
406 }
407
408 static void
usage_for(const struct opts_t * op)409 usage_for(const struct opts_t * op)
410 {
411 if (op->opt_new)
412 usage();
413 else
414 usage_old();
415 }
416
417 #else /* SG_SCSI_STRINGS */
418
419 static void
usage_for(const struct opts_t * op)420 usage_for(const struct opts_t * op)
421 {
422 if (op) { } /* suppress warning */
423 usage();
424 }
425
426 #endif /* SG_SCSI_STRINGS */
427
428 /* Processes command line options according to new option format. Returns
429 * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */
430 static int
new_parse_cmd_line(struct opts_t * op,int argc,char * argv[])431 new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
432 {
433 int c, n;
434
435 while (1) {
436 int option_index = 0;
437
438 #ifdef SG_LIB_LINUX
439 #ifdef SG_SCSI_STRINGS
440 c = getopt_long(argc, argv, "aB:cdeEfhHiI:j::l:Lm:M:NoOp:Q:rsuvVx",
441 long_options, &option_index);
442 #else
443 c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:M:op:Q:rsuvVx",
444 long_options, &option_index);
445 #endif /* SG_SCSI_STRINGS */
446 #else /* SG_LIB_LINUX */
447 #ifdef SG_SCSI_STRINGS
448 c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:M:NoOp:Q:rsuvVx",
449 long_options, &option_index);
450 #else
451 c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:M:op:Q:rsuvVx",
452 long_options, &option_index);
453 #endif /* SG_SCSI_STRINGS */
454 #endif /* SG_LIB_LINUX */
455 if (c == -1)
456 break;
457
458 switch (c) {
459 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
460 defined(HDIO_GET_IDENTITY)
461 case 'a':
462 op->do_ata = true;
463 break;
464 #endif
465 case 'B':
466 if ('-' == optarg[0])
467 n = -1;
468 else {
469 n = sg_get_num(optarg);
470 if ((n < 0) || (n > 1)) {
471 pr2serr("bad argument to '--block=' want 0 or 1\n");
472 usage_for(op);
473 return SG_LIB_SYNTAX_ERROR;
474 }
475 }
476 op->do_block = n;
477 break;
478 case 'c':
479 ++op->do_cmddt;
480 break;
481 case 'd':
482 op->do_descriptors = true;
483 break;
484 case 'e':
485 op->do_vpd = true;
486 break;
487 case 'E': /* --extended */
488 case 'x':
489 op->do_decode = true;
490 op->do_vpd = true;
491 op->vpd_pn = VPD_EXT_INQ;
492 op->page_given = true;
493 break;
494 case 'f':
495 op->do_force = true;
496 break;
497 case 'h':
498 ++op->do_help;
499 break;
500 case 'j':
501 if (! sgj_init_state(&op->json_st, optarg)) {
502 int bad_char = op->json_st.first_bad_char;
503 char e[1500];
504
505 if (bad_char) {
506 pr2serr("bad argument to --json= option, unrecognized "
507 "character '%c'\n\n", bad_char);
508 }
509 sg_json_usage(0, e, sizeof(e));
510 pr2serr("%s", e);
511 return SG_LIB_SYNTAX_ERROR;
512 }
513 break;
514 case 'o':
515 op->do_only = true;
516 break;
517 case '?':
518 if (! op->do_help)
519 ++op->do_help;
520 break;
521 case 'H':
522 ++op->do_hex;
523 break;
524 case 'i':
525 op->do_decode = true;
526 op->do_vpd = true;
527 op->vpd_pn = VPD_DEVICE_ID;
528 op->page_given = true;
529 break;
530 case 'I':
531 op->inhex_fn = optarg;
532 break;
533 case 'l':
534 case 'm':
535 n = sg_get_num(optarg);
536 if ((n < 0) || (n > 65532)) {
537 pr2serr("bad argument to '--len='\n");
538 usage_for(op);
539 return SG_LIB_SYNTAX_ERROR;
540 }
541 if ((n > 0) && (n < 4)) {
542 pr2serr("Changing that '--maxlen=' value to 4\n");
543 n = 4;
544 }
545 op->maxlen = n;
546 break;
547 case 'M':
548 if (op->vend_prod) {
549 pr2serr("only one '--vendor=' option permitted\n");
550 usage();
551 return SG_LIB_SYNTAX_ERROR;
552 } else
553 op->vend_prod = optarg;
554 break;
555 case 'L':
556 ++op->do_long;
557 break;
558 #ifdef SG_SCSI_STRINGS
559 case 'N':
560 break; /* ignore */
561 case 'O':
562 op->opt_new = false;
563 return 0;
564 #endif
565 case 'p':
566 op->page_str = optarg;
567 op->page_given = true;
568 break;
569 case 'Q':
570 op->sinq_inraw_fn = optarg;
571 break;
572 case 'r':
573 ++op->do_raw;
574 break;
575 case 's':
576 ++op->do_vendor;
577 break;
578 case 'u':
579 op->do_export = true;
580 break;
581 case 'v':
582 op->verbose_given = true;
583 ++op->verbose;
584 break;
585 case 'V':
586 op->version_given = true;
587 break;
588 default:
589 pr2serr("unrecognised option code %c [0x%x]\n", c, c);
590 if (op->do_help)
591 break;
592 usage_for(op);
593 return SG_LIB_SYNTAX_ERROR;
594 }
595 }
596 if (optind < argc) {
597 if (NULL == op->device_name) {
598 op->device_name = argv[optind];
599 ++optind;
600 }
601 if (optind < argc) {
602 for (; optind < argc; ++optind)
603 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
604 usage_for(op);
605 return SG_LIB_SYNTAX_ERROR;
606 }
607 }
608 return 0;
609 }
610
611 #ifdef SG_SCSI_STRINGS
612 /* Processes command line options according to old option format. Returns
613 * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */
614 static int
old_parse_cmd_line(struct opts_t * op,int argc,char * argv[])615 old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
616 {
617 bool jmp_out;
618 int k, plen, num, n;
619 const char * cp;
620
621 for (k = 1; k < argc; ++k) {
622 cp = argv[k];
623 plen = strlen(cp);
624 if (plen <= 0)
625 continue;
626 if ('-' == *cp) {
627 for (--plen, ++cp, jmp_out = false; plen > 0; --plen, ++cp) {
628 switch (*cp) {
629 case '3':
630 if ('6' == *(cp + 1)) {
631 op->maxlen = 36;
632 --plen;
633 ++cp;
634 } else
635 jmp_out = true;
636 break;
637 case 'a':
638 op->vpd_pn = VPD_ATA_INFO;
639 op->do_vpd = true;
640 op->page_given = true;
641 ++op->num_pages;
642 break;
643 #ifdef SG_LIB_LINUX
644 case 'A':
645 op->do_ata = true;
646 break;
647 #endif
648 case 'b':
649 op->vpd_pn = VPD_BLOCK_LIMITS;
650 op->do_vpd = true;
651 op->page_given = true;
652 ++op->num_pages;
653 break;
654 case 'c':
655 ++op->do_cmddt;
656 if ('l' == *(cp + 1)) {
657 ++op->do_cmddt;
658 --plen;
659 ++cp;
660 }
661 break;
662 case 'd':
663 op->do_descriptors = true;
664 op->do_decode = true;
665 break;
666 case 'e':
667 op->do_vpd = true;
668 break;
669 case 'f':
670 op->do_force = true;
671 break;
672 case 'h':
673 case 'H':
674 ++op->do_hex;
675 break;
676 case 'i':
677 op->vpd_pn = VPD_DEVICE_ID;
678 op->do_vpd = true;
679 op->page_given = true;
680 ++op->num_pages;
681 break;
682 case 'L':
683 ++op->do_long;
684 break;
685 case 'm':
686 op->vpd_pn = VPD_MAN_NET_ADDR;
687 op->do_vpd = true;
688 ++op->num_pages;
689 op->page_given = true;
690 break;
691 case 'M':
692 op->vpd_pn = VPD_MODE_PG_POLICY;
693 op->do_vpd = true;
694 op->page_given = true;
695 ++op->num_pages;
696 break;
697 case 'N':
698 op->opt_new = true;
699 return 0;
700 case 'o':
701 op->do_only = true;
702 break;
703 case 'O':
704 break;
705 case 'P':
706 op->vpd_pn = VPD_UPR_EMC;
707 op->do_vpd = true;
708 op->page_given = true;
709 ++op->num_pages;
710 break;
711 case 'r':
712 ++op->do_raw;
713 break;
714 case 's':
715 op->vpd_pn = VPD_SCSI_PORTS;
716 op->do_vpd = true;
717 op->page_given = true;
718 ++op->num_pages;
719 break;
720 case 'u':
721 op->do_export = true;
722 break;
723 case 'v':
724 op->verbose_given = true;
725 ++op->verbose;
726 break;
727 case 'V':
728 op->version_given = true;
729 break;
730 case 'x':
731 op->vpd_pn = VPD_EXT_INQ;
732 op->do_vpd = true;
733 op->page_given = true;
734 ++op->num_pages;
735 break;
736 case '?':
737 if (! op->do_help)
738 ++op->do_help;
739 break;
740 default:
741 jmp_out = true;
742 break;
743 }
744 if (jmp_out)
745 break;
746 }
747 if (plen <= 0)
748 continue;
749 else if (0 == strncmp("B=", cp, 2)) {
750 num = sscanf(cp + 2, "%d", &n);
751 if ((1 != num) || (n < 0) || (n > 1)) {
752 pr2serr("'B=' option expects 0 or 1\n");
753 usage_for(op);
754 return SG_LIB_SYNTAX_ERROR;
755 }
756 op->do_block = n;
757 } else if (0 == strncmp("I=", cp, 2))
758 op->inhex_fn = cp + 2;
759 else if ('j' == *cp) { /* handle either '-j' or '-j=<JO>' */
760 const char * c2p = (('=' == *(cp + 1)) ? cp + 2 : NULL);
761
762 if (! sgj_init_state(&op->json_st, c2p)) {
763 int bad_char = op->json_st.first_bad_char;
764 char e[1500];
765
766 if (bad_char) {
767 pr2serr("bad argument to --json= option, unrecognized "
768 "character '%c'\n\n", bad_char);
769 }
770 sg_json_usage(0, e, sizeof(e));
771 pr2serr("%s", e);
772 return SG_LIB_SYNTAX_ERROR;
773 }
774 } else if (0 == strncmp("l=", cp, 2)) {
775 num = sscanf(cp + 2, "%d", &n);
776 if ((1 != num) || (n < 1)) {
777 pr2serr("Inappropriate value after 'l=' option\n");
778 usage_for(op);
779 return SG_LIB_SYNTAX_ERROR;
780 } else if (n > MX_ALLOC_LEN) {
781 pr2serr("value after 'l=' option too large\n");
782 return SG_LIB_SYNTAX_ERROR;
783 }
784 if ((n > 0) && (n < 4)) {
785 pr2serr("Changing that '-l=' value to 4\n");
786 n = 4;
787 }
788 op->maxlen = n;
789 } else if (0 == strncmp("p=", cp, 2)) {
790 op->page_str = cp + 2;
791 op->page_given = true;
792 } else if (0 == strncmp("-old", cp, 4))
793 ;
794 else if (jmp_out) {
795 pr2serr("Unrecognized option: %s\n", cp);
796 usage_for(op);
797 return SG_LIB_SYNTAX_ERROR;
798 }
799 } else if (0 == op->device_name)
800 op->device_name = cp;
801 else {
802 pr2serr("too many arguments, got: %s, not expecting: %s\n",
803 op->device_name, cp);
804 usage_for(op);
805 return SG_LIB_SYNTAX_ERROR;
806 }
807 }
808 return 0;
809 }
810
811 /* Process command line options. First check using new option format unless
812 * the SG3_UTILS_OLD_OPTS environment variable is defined which causes the
813 * old option format to be checked first. Both new and old format can be
814 * countermanded by a '-O' and '-N' options respectively. As soon as either
815 * of these options is detected (when processing the other format), processing
816 * stops and is restarted using the other format. Clear? */
817 static int
parse_cmd_line(struct opts_t * op,int argc,char * argv[])818 parse_cmd_line(struct opts_t * op, int argc, char * argv[])
819 {
820 int res;
821 char * cp;
822
823 cp = getenv("SG3_UTILS_OLD_OPTS");
824 if (cp) {
825 op->opt_new = false;
826 res = old_parse_cmd_line(op, argc, argv);
827 if ((0 == res) && op->opt_new)
828 res = new_parse_cmd_line(op, argc, argv);
829 } else {
830 op->opt_new = true;
831 res = new_parse_cmd_line(op, argc, argv);
832 if ((0 == res) && (! op->opt_new))
833 res = old_parse_cmd_line(op, argc, argv);
834 }
835 return res;
836 }
837
838 #else /* SG_SCSI_STRINGS */
839
840 static int
parse_cmd_line(struct opts_t * op,int argc,char * argv[])841 parse_cmd_line(struct opts_t * op, int argc, char * argv[])
842 {
843 return new_parse_cmd_line(op, argc, argv);
844 }
845
846 #endif /* SG_SCSI_STRINGS */
847
848
849 static const struct svpd_values_name_t *
sdp_find_vpd_by_acron(const char * ap)850 sdp_find_vpd_by_acron(const char * ap)
851 {
852 const struct svpd_values_name_t * vnp;
853
854 for (vnp = t10_vpd_pg; vnp->acron; ++vnp) {
855 if (0 == strcmp(vnp->acron, ap))
856 return vnp;
857 }
858 for (vnp = alt_t10_vpd_pg; vnp->acron; ++vnp) {
859 if (0 == strcmp(vnp->acron, ap))
860 return vnp;
861 }
862 for (vnp = vs_vpd_pg; vnp->acron; ++vnp) {
863 if (0 == strcmp(vnp->acron, ap))
864 return vnp;
865 }
866 return NULL;
867 }
868
869 static void
enumerate_vpds()870 enumerate_vpds()
871 {
872 const struct svpd_values_name_t * vnp;
873
874 printf("T10 defined VPD pages:\n");
875 for (vnp = t10_vpd_pg; vnp->acron; ++vnp) {
876 if (vnp->name) {
877 if (vnp->value < 0)
878 printf(" %-10s -1 %s\n", vnp->acron, vnp->name);
879 else
880 printf(" %-10s 0x%02x %s\n", vnp->acron, vnp->value,
881 vnp->name);
882 }
883 }
884 printf("Vendor specific VPD pages:\n");
885 for (vnp = vs_vpd_pg; vnp->acron; ++vnp) {
886 if (vnp->name) {
887 if (vnp->value < 0)
888 printf(" %-10s -1 %s\n", vnp->acron, vnp->name);
889 else
890 printf(" %-10s 0x%02x %s\n", vnp->acron, vnp->value,
891 vnp->name);
892 }
893 }
894 }
895
896 static void
dStrRaw(const char * str,int len)897 dStrRaw(const char * str, int len)
898 {
899 int k;
900
901 for (k = 0; k < len; ++k)
902 printf("%c", str[k]);
903 }
904
905 /* Strip initial and trailing whitespaces; convert one or repeated
906 * whitespaces to a single "_"; convert non-printable characters to "."
907 * and if there are no valid (i.e. printable) characters return 0.
908 * Process 'str' in place (i.e. it's input and output) and return the
909 * length of the output, excluding the trailing '\0'. To cover any
910 * potential unicode string an intermediate zero is skipped; two
911 * consecutive zeroes indicate a string termination.
912 */
913 static int
encode_whitespaces(uint8_t * str,int inlen)914 encode_whitespaces(uint8_t *str, int inlen)
915 {
916 int k, res;
917 int j;
918 bool valid = false;
919 int outlen = inlen, zeroes = 0;
920
921 /* Skip initial whitespaces */
922 for (j = 0; (j < inlen) && isblank(str[j]); ++j)
923 ;
924 if (j < inlen) {
925 /* Skip possible unicode prefix characters */
926 for ( ; (j < inlen) && (str[j] < 0x20); ++j)
927 ;
928 }
929 k = j;
930 /* Strip trailing whitespaces */
931 while ((outlen > k) &&
932 (isblank(str[outlen - 1]) || ('\0' == str[outlen - 1]))) {
933 str[outlen - 1] = '\0';
934 outlen--;
935 }
936 for (res = 0; k < outlen; ++k) {
937 if (isblank(str[k])) {
938 if ((res > 0) && ('_' != str[res - 1])) {
939 str[res++] = '_';
940 valid = true;
941 }
942 zeroes = 0;
943 } else if (! isprint(str[k])) {
944 if (str[k] == 0x00) {
945 /* Stop on more than one consecutive zero */
946 if (zeroes)
947 break;
948 zeroes++;
949 continue;
950 }
951 str[res++] = '.';
952 zeroes = 0;
953 } else {
954 str[res++] = str[k];
955 valid = true;
956 zeroes = 0;
957 }
958 }
959 if (! valid)
960 res = 0;
961 if (res < inlen)
962 str[res] = '\0';
963 return res;
964 }
965
966 static int
encode_unicode(uint8_t * str,int inlen)967 encode_unicode(uint8_t *str, int inlen)
968 {
969 int k = 0, res;
970 int zeroes = 0;
971
972 for (res = 0; k < inlen; ++k) {
973 if (str[k] == 0x00) {
974 if (zeroes) {
975 str[res++] = '\0';
976 break;
977 }
978 zeroes++;
979 } else {
980 zeroes = 0;
981 if (isprint(str[k]))
982 str[res++] = str[k];
983 else
984 str[res++] = ' ';
985 }
986 }
987
988 return res;
989 }
990
991 static int
encode_string(char * out,const uint8_t * in,int inlen)992 encode_string(char *out, const uint8_t *in, int inlen)
993 {
994 int i, j = 0;
995
996 for (i = 0; (i < inlen); ++i) {
997 if (isblank(in[i]) || !isprint(in[i])) {
998 sprintf(&out[j], "\\x%02x", in[i]);
999 j += 4;
1000 } else {
1001 out[j] = in[i];
1002 j++;
1003 }
1004 }
1005 out[j] = '\0';
1006 return j;
1007 }
1008
1009 static const struct svpd_values_name_t *
get_vpd_page_info(int vpd_page_num,int dev_pdt)1010 get_vpd_page_info(int vpd_page_num, int dev_pdt)
1011 {
1012 int decay_pdt;
1013 const struct svpd_values_name_t * vnp;
1014 const struct svpd_values_name_t * prev_vnp;
1015
1016 if (vpd_page_num < 0xb0) { /* take T10 first match */
1017 for (vnp = t10_vpd_pg; vnp->acron; ++vnp) {
1018 if (vnp->value == vpd_page_num)
1019 return vnp;
1020 }
1021 return NULL;
1022 } else if (vpd_page_num < 0xc0) {
1023 for (vnp = t10_vpd_pg; vnp->acron; ++vnp) {
1024 if (vnp->value == vpd_page_num)
1025 break;
1026 }
1027 if (NULL == vnp->acron)
1028 return NULL;
1029 if (vnp->pdt == dev_pdt) /* exact match */
1030 return vnp;
1031 prev_vnp = vnp;
1032
1033 for (++vnp; vnp->acron; ++vnp) {
1034 if (vnp->value == vpd_page_num)
1035 break;
1036 }
1037 decay_pdt = sg_lib_pdt_decay(dev_pdt);
1038 if (NULL == vnp->acron) {
1039 if (decay_pdt == prev_vnp->pdt)
1040 return prev_vnp;
1041 return NULL;
1042 }
1043 if ((vnp->pdt == dev_pdt) || (vnp->pdt == decay_pdt))
1044 return vnp;
1045 if (decay_pdt == prev_vnp->pdt)
1046 return prev_vnp;
1047
1048 for (++vnp; vnp->acron; ++vnp) {
1049 if (vnp->value == vpd_page_num)
1050 break;
1051 }
1052 if (NULL == vnp->acron)
1053 return NULL;
1054 if ((vnp->pdt == dev_pdt) || (vnp->pdt == decay_pdt))
1055 return vnp;
1056 return NULL; /* give up */
1057 } else { /* vendor specific: vpd >= 0xc0 */
1058 for (vnp = vs_vpd_pg; vnp->acron; ++vnp) {
1059 if (vnp->pdt == dev_pdt)
1060 return vnp;
1061 }
1062 return NULL;
1063 }
1064 }
1065
1066 static int
svpd_inhex_decode_all(struct opts_t * op,sgj_opaque_p jop)1067 svpd_inhex_decode_all(struct opts_t * op, sgj_opaque_p jop)
1068 {
1069 int k, res, pn;
1070 int max_pn = 255;
1071 int bump, off;
1072 int in_len = op->maxlen;
1073 int prev_pn = -1;
1074 sgj_state * jsp = &op->json_st;
1075 uint8_t vpd0_buff[512];
1076 uint8_t * rp = vpd0_buff;
1077
1078 if (op->vpd_pn > 0)
1079 max_pn = op->vpd_pn;
1080
1081 res = 0;
1082 if (op->page_given && (VPD_NOPE_WANT_STD_INQ == op->vpd_pn))
1083 return vpd_decode(-1, op, jop, 0);
1084
1085 for (k = 0, off = 0; off < in_len; ++k, off += bump) {
1086 rp = rsp_buff + off;
1087 pn = rp[1];
1088 bump = sg_get_unaligned_be16(rp + 2) + 4;
1089 if ((off + bump) > in_len) {
1090 pr2serr("%s: page 0x%x size (%d) exceeds buffer\n", __func__,
1091 pn, bump);
1092 bump = in_len - off;
1093 }
1094 if (op->page_given && (pn != op->vpd_pn))
1095 continue;
1096 if (pn <= prev_pn) {
1097 pr2serr("%s: prev_pn=0x%x, this pn=0x%x, not ascending so "
1098 "exit\n", __func__, prev_pn, pn);
1099 break;
1100 }
1101 prev_pn = pn;
1102 op->vpd_pn = pn;
1103 if (pn > max_pn) {
1104 if (op->verbose > 2)
1105 pr2serr("%s: skipping as this pn=0x%x exceeds "
1106 "max_pn=0x%x\n", __func__, pn, max_pn);
1107 continue;
1108 }
1109 if (op->do_long) {
1110 if (jsp->pr_as_json)
1111 sgj_pr_hr(jsp, "[0x%x]:\n", pn);
1112 else
1113 sgj_pr_hr(jsp, "[0x%x] ", pn);
1114 }
1115
1116 res = vpd_decode(-1, op, jop, off);
1117 if (SG_LIB_CAT_OTHER == res) {
1118 if (op->verbose)
1119 pr2serr("Can't decode VPD page=0x%x\n", pn);
1120 }
1121 }
1122 return res;
1123 }
1124
1125 static void
decode_supported_vpd_4inq(uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jap)1126 decode_supported_vpd_4inq(uint8_t * buff, int len, struct opts_t * op,
1127 sgj_opaque_p jap)
1128 {
1129 int vpd, k, rlen, pdt;
1130 sgj_state * jsp = &op->json_st;
1131 sgj_opaque_p jo2p;
1132 const struct svpd_values_name_t * vnp;
1133 char b[64];
1134
1135 if (op->do_hex) {
1136 hex2stdout(buff, len, no_ascii_4hex(op));
1137 return;
1138 }
1139 if (len < 4) {
1140 pr2serr("Supported VPD pages VPD page length too short=%d\n", len);
1141 return;
1142 }
1143 pdt = PDT_MASK & buff[0];
1144 rlen = buff[3] + 4;
1145 if (rlen > len)
1146 pr2serr("Supported VPD pages VPD page truncated, indicates %d, got "
1147 "%d\n", rlen, len);
1148 else
1149 len = rlen;
1150 sgj_pr_hr(jsp, " Supported VPD pages:\n");
1151 for (k = 0; k < len - 4; ++k) {
1152 vpd = buff[4 + k];
1153 snprintf(b, sizeof(b), "0x%x", vpd);
1154 vnp = get_vpd_page_info(vpd, pdt);
1155 if (jsp->pr_as_json && jap) {
1156 jo2p = sgj_new_unattached_object_r(jsp);
1157 sgj_js_nv_i(jsp, jo2p, "i", vpd);
1158 sgj_js_nv_s(jsp, jo2p, "hex", b + 2);
1159 sgj_js_nv_s(jsp, jo2p, "name", vnp ? vnp->name : "unknown");
1160 sgj_js_nv_s(jsp, jo2p, "acronym", vnp ? vnp->acron : "unknown");
1161 sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
1162 }
1163 if (vnp)
1164 sgj_pr_hr(jsp, " %s\t%s\n", b, vnp->name);
1165 else
1166 sgj_pr_hr(jsp, " %s\n", b);
1167 }
1168 }
1169
1170 static bool
vpd_page_is_supported(uint8_t * vpd_pg0,int v0_len,int pg_num,int vb)1171 vpd_page_is_supported(uint8_t * vpd_pg0, int v0_len, int pg_num, int vb)
1172 {
1173 int k, rlen;
1174
1175 if (v0_len < 4)
1176 return false;
1177
1178 rlen = vpd_pg0[3] + 4;
1179 if (rlen > v0_len)
1180 pr2serr("Supported VPD pages VPD page truncated, indicates %d, got "
1181 "%d\n", rlen, v0_len);
1182 else
1183 v0_len = rlen;
1184 if (vb > 1) {
1185 pr2serr("Supported VPD pages, hex list: ");
1186 hex2stderr(vpd_pg0 + 4, v0_len - 4, -1);
1187 }
1188 for (k = 4; k < v0_len; ++k) {
1189 if(vpd_pg0[k] == pg_num)
1190 return true;
1191 }
1192 return false;
1193 }
1194
1195 /* ASCII Information VPD pages (page numbers: 0x1 to 0x7f) */
1196 static void
decode_ascii_inf(uint8_t * buff,int len,struct opts_t * op)1197 decode_ascii_inf(uint8_t * buff, int len, struct opts_t * op)
1198 {
1199 int al, k, bump;
1200 uint8_t * bp;
1201 uint8_t * p;
1202 sgj_state * jsp = &op->json_st;
1203
1204 if (op->do_hex) {
1205 hex2stdout(buff, len, no_ascii_4hex(op));
1206 return;
1207 }
1208 if (len < 4) {
1209 pr2serr("ASCII information VPD page length too short=%d\n", len);
1210 return;
1211 }
1212 if (4 == len)
1213 return;
1214 al = buff[4];
1215 if ((al + 5) > len)
1216 al = len - 5;
1217 for (k = 0, bp = buff + 5; k < al; k += bump, bp += bump) {
1218 p = (uint8_t *)memchr(bp, 0, al - k);
1219 if (! p) {
1220 sgj_pr_hr(jsp, " %.*s\n", al - k, (const char *)bp);
1221 break;
1222 }
1223 sgj_pr_hr(jsp, " %s\n", (const char *)bp);
1224 bump = (p - bp) + 1;
1225 }
1226 bp = buff + 5 + al;
1227 if (bp < (buff + len)) {
1228 sgj_pr_hr(jsp, "Vendor specific information in hex:\n");
1229 hex2stdout(bp, len - (al + 5), 0);
1230 }
1231 }
1232
1233 static void
decode_id_vpd(uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jap)1234 decode_id_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap)
1235 {
1236 if (len < 4) {
1237 pr2serr("Device identification VPD page length too "
1238 "short=%d\n", len);
1239 return;
1240 }
1241 decode_dev_ids("Device identification", buff + 4, len - 4, op, jap);
1242 }
1243
1244 /* VPD_SCSI_PORTS 0x88 ["sp"] */
1245 static void
decode_scsi_ports_vpd_4inq(uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jap)1246 decode_scsi_ports_vpd_4inq(uint8_t * buff, int len, struct opts_t * op,
1247 sgj_opaque_p jap)
1248 {
1249 int k, bump, rel_port, ip_tid_len, tpd_len;
1250 uint8_t * bp;
1251 sgj_state * jsp = &op->json_st;
1252 sgj_opaque_p jo2p;
1253
1254 if (len < 4) {
1255 pr2serr("SCSI Ports VPD page length too short=%d\n", len);
1256 return;
1257 }
1258 if (op->do_hex > 2) {
1259 hex2stdout(buff, len, -1);
1260 return;
1261 }
1262 len -= 4;
1263 bp = buff + 4;
1264 for (k = 0; k < len; k += bump, bp += bump) {
1265 jo2p = sgj_new_unattached_object_r(jsp);
1266 rel_port = sg_get_unaligned_be16(bp + 2);
1267 sgj_pr_hr(jsp, "Relative port=%d\n", rel_port);
1268 sgj_js_nv_i(jsp, jo2p, "relative_port", rel_port);
1269 ip_tid_len = sg_get_unaligned_be16(bp + 6);
1270 bump = 8 + ip_tid_len;
1271 if ((k + bump) > len) {
1272 pr2serr("SCSI Ports VPD page, short descriptor "
1273 "length=%d, left=%d\n", bump, (len - k));
1274 sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
1275 return;
1276 }
1277 if (ip_tid_len > 0) {
1278 if (op->do_hex) {
1279 printf(" Initiator port transport id:\n");
1280 hex2stdout((bp + 8), ip_tid_len, no_ascii_4hex(op));
1281 } else {
1282 char b[1024];
1283
1284 sg_decode_transportid_str(" ", bp + 8, ip_tid_len,
1285 true, sizeof(b), b);
1286 if (jsp->pr_as_json)
1287 sgj_js_nv_s(jsp, jo2p, "initiator_port_transport_id", b);
1288 sgj_pr_hr(jsp, "%s",
1289 sg_decode_transportid_str(" ", bp + 8,
1290 ip_tid_len, true, sizeof(b), b));
1291 }
1292 }
1293 tpd_len = sg_get_unaligned_be16(bp + bump + 2);
1294 if ((k + bump + tpd_len + 4) > len) {
1295 pr2serr("SCSI Ports VPD page, short descriptor(tgt) "
1296 "length=%d, left=%d\n", bump, (len - k));
1297 sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
1298 return;
1299 }
1300 if (tpd_len > 0) {
1301 sgj_pr_hr(jsp, " Target port descriptor(s):\n");
1302 if (op->do_hex)
1303 hex2stdout(bp + bump + 4, tpd_len, no_ascii_4hex(op));
1304 else {
1305 sgj_opaque_p ja2p = sgj_named_subarray_r(jsp, jo2p,
1306 "target_port_descriptor_list");
1307
1308 decode_dev_ids("SCSI Ports", bp + bump + 4, tpd_len,
1309 op, ja2p);
1310 }
1311 }
1312 bump += tpd_len + 4;
1313 sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
1314 }
1315 }
1316
1317 /* These are target port, device server (i.e. target) and LU identifiers */
1318 static void
decode_dev_ids(const char * leadin,uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jap)1319 decode_dev_ids(const char * leadin, uint8_t * buff, int len,
1320 struct opts_t * op, sgj_opaque_p jap)
1321 {
1322 int u, j, m, id_len, p_id, c_set, piv, assoc, desig_type, i_len;
1323 int off, ci_off, c_id, d_id, naa, vsi, k, n;
1324 uint64_t vsei, id_ext, ccc_id;
1325 const uint8_t * bp;
1326 const uint8_t * ip;
1327 const char * cp;
1328 sgj_state * jsp = &op->json_st;
1329 char b[256];
1330 char d[64];
1331 static const int blen = sizeof(b);
1332 static const int dlen = sizeof(d);
1333
1334 if (jsp->pr_as_json) {
1335 int ret = filter_json_dev_ids(buff, len, -1, op, jap);
1336
1337 if (ret || (! jsp->pr_out_hr))
1338 return;
1339 }
1340 if (buff[2] > 2) { /* SPC-3,4,5 buff[2] is upper byte of length */
1341 /*
1342 * Reference the 3rd byte of the first Identification descriptor
1343 * of a page 83 reply to determine whether the reply is compliant
1344 * with SCSI-2 or SPC-2/3 specifications. A zero value in the
1345 * 3rd byte indicates an SPC-2/3 conforming reply ( the field is
1346 * reserved ). This byte will be non-zero for a SCSI-2
1347 * conforming page 83 reply from these EMC Symmetrix models since
1348 * the 7th byte of the reply corresponds to the 4th and 5th
1349 * nibbles of the 6-byte OUI for EMC, that is, 0x006048.
1350 */
1351 i_len = len;
1352 ip = bp = buff;
1353 c_set = 1;
1354 assoc = 0;
1355 piv = 0;
1356 p_id = 0xf;
1357 desig_type = 3;
1358 j = 1;
1359 off = 16;
1360 sgj_pr_hr(jsp, " Pre-SPC descriptor, descriptor length: %d\n",
1361 i_len);
1362 goto decode;
1363 }
1364
1365 for (j = 1, off = -1;
1366 (u = sg_vpd_dev_id_iter(buff, len, &off, -1, -1, -1)) == 0;
1367 ++j) {
1368 bp = buff + off;
1369 i_len = bp[3];
1370 id_len = i_len + 4;
1371 sgj_pr_hr(jsp, " Designation descriptor number %d, "
1372 "descriptor length: %d\n", j, id_len);
1373 if ((off + id_len) > len) {
1374 pr2serr("%s VPD page error: designator length longer "
1375 "than\n remaining response length=%d\n", leadin,
1376 (len - off));
1377 return;
1378 }
1379 ip = bp + 4;
1380 p_id = ((bp[0] >> 4) & 0xf); /* protocol identifier */
1381 c_set = (bp[0] & 0xf); /* code set */
1382 piv = ((bp[1] & 0x80) ? 1 : 0); /* protocol identifier valid */
1383 assoc = ((bp[1] >> 4) & 0x3);
1384 desig_type = (bp[1] & 0xf);
1385 decode:
1386 if (piv && ((1 == assoc) || (2 == assoc)))
1387 sgj_pr_hr(jsp, " transport: %s\n",
1388 sg_get_trans_proto_str(p_id, dlen, d));
1389 n = 0;
1390 cp = sg_get_desig_type_str(desig_type);
1391 n += sg_scnpr(b + n, blen - n, " designator_type: %s, ",
1392 cp ? cp : "-");
1393 cp = sg_get_desig_code_set_str(c_set);
1394 sgj_pr_hr(jsp, "%scode_set: %s\n", b, cp ? cp : "-");
1395 cp = sg_get_desig_assoc_str(assoc);
1396 sgj_pr_hr(jsp, " associated with the %s\n", cp ? cp : "-");
1397 if (op->do_hex) {
1398 sgj_pr_hr(jsp, " designator header(hex): %.2x %.2x %.2x %.2x\n",
1399 bp[0], bp[1], bp[2], bp[3]);
1400 sgj_pr_hr(jsp, " designator:\n");
1401 hex2stdout(ip, i_len, 0);
1402 continue;
1403 }
1404 switch (desig_type) {
1405 case 0: /* vendor specific */
1406 k = 0;
1407 if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */
1408 for (k = 0; (k < i_len) && isprint(ip[k]); ++k)
1409 ;
1410 if (k >= i_len)
1411 k = 1;
1412 }
1413 if (k)
1414 sgj_pr_hr(jsp, " vendor specific: %.*s\n", i_len, ip);
1415 else {
1416 sgj_pr_hr(jsp, " vendor specific:\n");
1417 hex2stdout(ip, i_len, -1);
1418 }
1419 break;
1420 case 1: /* T10 vendor identification */
1421 sgj_pr_hr(jsp, " vendor id: %.8s\n", ip);
1422 if (i_len > 8) {
1423 if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */
1424 sgj_pr_hr(jsp, " vendor specific: %.*s\n", i_len - 8,
1425 ip + 8);
1426 } else {
1427 n = 0;
1428 n += sg_scnpr(b + n, blen - n,
1429 " vendor specific: 0x");
1430 for (m = 8; m < i_len; ++m)
1431 n += sg_scnpr(b + n, blen - n, "%02x", ip[m]);
1432 sgj_pr_hr(jsp, "%s\n", b);
1433 }
1434 }
1435 break;
1436 case 2: /* EUI-64 based */
1437 sgj_pr_hr(jsp, " EUI-64 based %d byte identifier\n", i_len);
1438 if (1 != c_set) {
1439 pr2serr(" << expected binary code_set (1)>>\n");
1440 hex2stderr(ip, i_len, -1);
1441 break;
1442 }
1443 ci_off = 0;
1444 n = 0;
1445 b[0] = '\0';
1446 if (16 == i_len) {
1447 ci_off = 8;
1448 id_ext = sg_get_unaligned_be64(ip);
1449 n += sg_scnpr(b + n, blen - n,
1450 " Identifier extension: 0x%" PRIx64 "\n",
1451 id_ext);
1452 } else if ((8 != i_len) && (12 != i_len)) {
1453 pr2serr(" << can only decode 8, 12 and 16 "
1454 "byte ids>>\n");
1455 hex2stderr(ip, i_len, -1);
1456 break;
1457 }
1458 ccc_id = sg_get_unaligned_be64(ip + ci_off);
1459 sgj_pr_hr(jsp, "%s IEEE identifier: 0x%" PRIx64 "\n", b,
1460 ccc_id);
1461 if (12 == i_len) {
1462 d_id = sg_get_unaligned_be32(ip + 8);
1463 sgj_pr_hr(jsp, " Directory ID: 0x%x\n", d_id);
1464 }
1465 n = 0;
1466 n += sg_scnpr(b + n, blen - n, " [0x");
1467 for (m = 0; m < i_len; ++m)
1468 n += sg_scnpr(b + n, blen - n, "%02x", ip[m]);
1469 sgj_pr_hr(jsp, "%s]\n", b);
1470 break;
1471 case 3: /* NAA <n> */
1472 naa = (ip[0] >> 4) & 0xff;
1473 if (1 != c_set) {
1474 pr2serr(" << expected binary code_set (1), got %d for "
1475 "NAA=%d>>\n", c_set, naa);
1476 hex2stderr(ip, i_len, -1);
1477 break;
1478 }
1479 switch (naa) {
1480 case 2: /* NAA 2: IEEE Extended */
1481 if (8 != i_len) {
1482 pr2serr(" << unexpected NAA 2 identifier "
1483 "length: 0x%x>>\n", i_len);
1484 hex2stderr(ip, i_len, -1);
1485 break;
1486 }
1487 d_id = (((ip[0] & 0xf) << 8) | ip[1]);
1488 c_id = sg_get_unaligned_be24(ip + 2);
1489 vsi = sg_get_unaligned_be24(ip + 5);
1490 sgj_pr_hr(jsp, " NAA 2, vendor specific identifier A: "
1491 "0x%x\n", d_id);
1492 sgj_pr_hr(jsp, " AOI: 0x%x\n", c_id);
1493 sgj_pr_hr(jsp, " vendor specific identifier B: 0x%x\n",
1494 vsi);
1495 n = 0;
1496 n += sg_scnpr(b + n, blen - n, " [0x");
1497 for (m = 0; m < 8; ++m)
1498 n += sg_scnpr(b + n, blen - n, "%02x", ip[m]);
1499 sgj_pr_hr(jsp, "%s]\n", b);
1500 break;
1501 case 3: /* NAA 3: Locally assigned */
1502 if (8 != i_len) {
1503 pr2serr(" << unexpected NAA 3 identifier "
1504 "length: 0x%x>>\n", i_len);
1505 hex2stderr(ip, i_len, -1);
1506 break;
1507 }
1508 sgj_pr_hr(jsp, " NAA 3, Locally assigned:\n");
1509 n = 0;
1510 n += sg_scnpr(b + n, blen - n, " [0x");
1511 for (m = 0; m < 8; ++m)
1512 n += sg_scnpr(b + n, blen - n, "%02x", ip[m]);
1513 sgj_pr_hr(jsp, "%s]\n", b);
1514 break;
1515 case 5: /* NAA 5: IEEE Registered */
1516 if (8 != i_len) {
1517 pr2serr(" << unexpected NAA 5 identifier "
1518 "length: 0x%x>>\n", i_len);
1519 hex2stderr(ip, i_len, -1);
1520 break;
1521 }
1522 c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) |
1523 (ip[2] << 4) | ((ip[3] & 0xf0) >> 4));
1524 vsei = ip[3] & 0xf;
1525 for (m = 1; m < 5; ++m) {
1526 vsei <<= 8;
1527 vsei |= ip[3 + m];
1528 }
1529 sgj_pr_hr(jsp, " NAA 5, AOI: 0x%x\n", c_id);
1530 n = 0;
1531 n += sg_scnpr(b + n, blen - n, " Vendor Specific "
1532 "Identifier: 0x%" PRIx64 "\n", vsei);
1533 n += sg_scnpr(b + n, blen - n, " [0x");
1534 for (m = 0; m < 8; ++m)
1535 n += sg_scnpr(b + n, blen - n, "%02x", ip[m]);
1536 sgj_pr_hr(jsp, "%s]\n", b);
1537 break;
1538 case 6: /* NAA 6: IEEE Registered extended */
1539 if (16 != i_len) {
1540 pr2serr(" << unexpected NAA 6 identifier "
1541 "length: 0x%x>>\n", i_len);
1542 hex2stderr(ip, i_len, 0);
1543 break;
1544 }
1545 c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) |
1546 (ip[2] << 4) | ((ip[3] & 0xf0) >> 4));
1547 vsei = ip[3] & 0xf;
1548 for (m = 1; m < 5; ++m) {
1549 vsei <<= 8;
1550 vsei |= ip[3 + m];
1551 }
1552 sgj_pr_hr(jsp, " NAA 6, AOI: 0x%x\n", c_id);
1553 sgj_pr_hr(jsp, " Vendor Specific Identifier: 0x%"
1554 PRIx64 "\n", vsei);
1555 vsei = sg_get_unaligned_be64(ip + 8);
1556 sgj_pr_hr(jsp, " Vendor Specific Identifier Extension: "
1557 "0x%" PRIx64 "\n", vsei);
1558 n = 0;
1559 n += sg_scnpr(b + n, blen - n, " [0x");
1560 for (m = 0; m < 16; ++m)
1561 n += sg_scnpr(b + n, blen - n, "%02x", ip[m]);
1562 sgj_pr_hr(jsp, "%s]\n", b);
1563 break;
1564 default:
1565 pr2serr(" << bad NAA nibble , expect 2, 3, 5 or 6, "
1566 "got %d>>\n", naa);
1567 hex2stderr(ip, i_len, -1);
1568 break;
1569 }
1570 break;
1571 case 4: /* Relative target port */
1572 if ((1 != c_set) || (1 != assoc) || (4 != i_len)) {
1573 pr2serr(" << expected binary code_set, target "
1574 "port association, length 4>>\n");
1575 hex2stderr(ip, i_len, -1);
1576 break;
1577 }
1578 d_id = sg_get_unaligned_be16(ip + 2);
1579 sgj_pr_hr(jsp, " Relative target port: 0x%x\n", d_id);
1580 break;
1581 case 5: /* (primary) Target port group */
1582 if ((1 != c_set) || (1 != assoc) || (4 != i_len)) {
1583 pr2serr(" << expected binary code_set, target "
1584 "port association, length 4>>\n");
1585 hex2stderr(ip, i_len, -1);
1586 break;
1587 }
1588 d_id = sg_get_unaligned_be16(ip + 2);
1589 sgj_pr_hr(jsp, " Target port group: 0x%x\n", d_id);
1590 break;
1591 case 6: /* Logical unit group */
1592 if ((1 != c_set) || (0 != assoc) || (4 != i_len)) {
1593 pr2serr(" << expected binary code_set, logical "
1594 "unit association, length 4>>\n");
1595 hex2stderr(ip, i_len, -1);
1596 break;
1597 }
1598 d_id = sg_get_unaligned_be16(ip + 2);
1599 sgj_pr_hr(jsp, " Logical unit group: 0x%x\n", d_id);
1600 break;
1601 case 7: /* MD5 logical unit identifier */
1602 if ((1 != c_set) || (0 != assoc)) {
1603 pr2serr(" << expected binary code_set, logical "
1604 "unit association>>\n");
1605 hex2stderr(ip, i_len, -1);
1606 break;
1607 }
1608 sgj_pr_hr(jsp, " MD5 logical unit identifier:\n");
1609 if (jsp->pr_out_hr)
1610 sgj_js_str_out(jsp, (const char *)ip, i_len);
1611 else
1612 hex2stdout(ip, i_len, -1);
1613 break;
1614 case 8: /* SCSI name string */
1615 if (3 != c_set) {
1616 if (2 == c_set) {
1617 if (op->verbose)
1618 pr2serr(" << expected UTF-8, use ASCII>>\n");
1619 } else {
1620 pr2serr(" << expected UTF-8 code_set>>\n");
1621 hex2stderr(ip, i_len, -1);
1622 break;
1623 }
1624 }
1625 sgj_pr_hr(jsp, " SCSI name string:\n");
1626 /* does %s print out UTF-8 ok??
1627 * Seems to depend on the locale. Looks ok here with my
1628 * locale setting: en_AU.UTF-8
1629 */
1630 sgj_pr_hr(jsp, " %.*s\n", i_len, (const char *)ip);
1631 break;
1632 case 9: /* Protocol specific port identifier */
1633 /* added in spc4r36, PIV must be set, proto_id indicates */
1634 /* whether UAS (USB) or SOP (PCIe) or ... */
1635 if (! piv)
1636 pr2serr(" >>>> Protocol specific port identifier "
1637 "expects protocol\n"
1638 " identifier to be valid and it is not\n");
1639 if (TPROTO_UAS == p_id) {
1640 sgj_pr_hr(jsp, " USB device address: 0x%x\n",
1641 0x7f & ip[0]);
1642 sgj_pr_hr(jsp, " USB interface number: 0x%x\n", ip[2]);
1643 } else if (TPROTO_SOP == p_id) {
1644 sgj_pr_hr(jsp, " PCIe routing ID, bus number: 0x%x\n",
1645 ip[0]);
1646 sgj_pr_hr(jsp, " function number: 0x%x\n", ip[1]);
1647 sgj_pr_hr(jsp, " [or device number: 0x%x, function "
1648 "number: 0x%x]\n", (0x1f & (ip[1] >> 3)),
1649 0x7 & ip[1]);
1650 } else
1651 sgj_pr_hr(jsp, " >>>> unexpected protocol identifier: "
1652 "%s\n with Protocol specific port "
1653 "identifier\n", sg_get_trans_proto_str(p_id, dlen,
1654 d));
1655 break;
1656 case 0xa: /* UUID identifier [spc5r08] RFC 4122 */
1657 if (1 != c_set) {
1658 pr2serr(" << expected binary code_set >>\n");
1659 hex2stderr(ip, i_len, 0);
1660 break;
1661 }
1662 if ((1 != ((ip[0] >> 4) & 0xf)) || (18 != i_len)) {
1663 pr2serr(" << expected locally assigned UUID, 16 bytes "
1664 "long >>\n");
1665 hex2stderr(ip, i_len, 0);
1666 break;
1667 }
1668 n = 0;
1669 n += sg_scnpr(b + n, blen - n, " Locally assigned UUID: ");
1670 for (m = 0; m < 16; ++m) {
1671 if ((4 == m) || (6 == m) || (8 == m) || (10 == m))
1672 n += sg_scnpr(b + n, blen - n, "-");
1673 n += sg_scnpr(b + n, blen - n, "%02x", ip[2 + m]);
1674 }
1675 sgj_pr_hr(jsp, "%s\n", b);
1676 break;
1677 default: /* reserved */
1678 pr2serr(" reserved designator=0x%x\n", desig_type);
1679 hex2stderr(ip, i_len, -1);
1680 break;
1681 }
1682 }
1683 if (-2 == u)
1684 pr2serr("%s VPD page error: around offset=%d\n", leadin, off);
1685 }
1686
1687 /* The --export and --json options are assumed to be mutually exclusive.
1688 * Here the former takes precedence. */
1689 static void
export_dev_ids(uint8_t * buff,int len,int verbose)1690 export_dev_ids(uint8_t * buff, int len, int verbose)
1691 {
1692 int u, j, m, id_len, c_set, assoc, desig_type, i_len;
1693 int off, d_id, naa, k, p_id;
1694 uint8_t * bp;
1695 uint8_t * ip;
1696 const char * assoc_str;
1697 const char * suffix;
1698
1699 if (buff[2] != 0) {
1700 /*
1701 * Cf decode_dev_ids() for details
1702 */
1703 i_len = len;
1704 ip = buff;
1705 c_set = 1;
1706 assoc = 0;
1707 p_id = 0xf;
1708 desig_type = 3;
1709 j = 1;
1710 off = 16;
1711 goto decode;
1712 }
1713
1714 for (j = 1, off = -1;
1715 (u = sg_vpd_dev_id_iter(buff, len, &off, -1, -1, -1)) == 0;
1716 ++j) {
1717 bp = buff + off;
1718 i_len = bp[3];
1719 id_len = i_len + 4;
1720 if ((off + id_len) > len) {
1721 if (verbose)
1722 pr2serr("Device Identification VPD page error: designator "
1723 "length longer than\n remaining response "
1724 "length=%d\n", (len - off));
1725 return;
1726 }
1727 ip = bp + 4;
1728 p_id = ((bp[0] >> 4) & 0xf); /* protocol identifier */
1729 c_set = (bp[0] & 0xf);
1730 assoc = ((bp[1] >> 4) & 0x3);
1731 desig_type = (bp[1] & 0xf);
1732 decode:
1733 switch (assoc) {
1734 case 0:
1735 assoc_str = "LUN";
1736 break;
1737 case 1:
1738 assoc_str = "PORT";
1739 break;
1740 case 2:
1741 assoc_str = "TARGET";
1742 break;
1743 default:
1744 if (verbose)
1745 pr2serr(" Invalid association %d\n", assoc);
1746 return;
1747 }
1748 switch (desig_type) {
1749 case 0: /* vendor specific */
1750 if (i_len == 0 || i_len > 128)
1751 break;
1752 if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */
1753 k = encode_whitespaces(ip, i_len);
1754 /* udev-conforming character encoding */
1755 if (k > 0) {
1756 printf("SCSI_IDENT_%s_VENDOR=", assoc_str);
1757 for (m = 0; m < k; ++m) {
1758 if ((ip[m] >= '0' && ip[m] <= '9') ||
1759 (ip[m] >= 'A' && ip[m] <= 'Z') ||
1760 (ip[m] >= 'a' && ip[m] <= 'z') ||
1761 strchr("#+-.:=@_", ip[m]) != NULL)
1762 printf("%c", ip[m]);
1763 else
1764 printf("\\x%02x", ip[m]);
1765 }
1766 printf("\n");
1767 }
1768 } else {
1769 printf("SCSI_IDENT_%s_VENDOR=", assoc_str);
1770 for (m = 0; m < i_len; ++m)
1771 printf("%02x", (unsigned int)ip[m]);
1772 printf("\n");
1773 }
1774 break;
1775 case 1: /* T10 vendor identification */
1776 printf("SCSI_IDENT_%s_T10=", assoc_str);
1777 if ((2 == c_set) || (3 == c_set)) {
1778 k = encode_whitespaces(ip, i_len);
1779 /* udev-conforming character encoding */
1780 for (m = 0; m < k; ++m) {
1781 if ((ip[m] >= '0' && ip[m] <= '9') ||
1782 (ip[m] >= 'A' && ip[m] <= 'Z') ||
1783 (ip[m] >= 'a' && ip[m] <= 'z') ||
1784 strchr("#+-.:=@_", ip[m]) != NULL)
1785 printf("%c", ip[m]);
1786 else
1787 printf("\\x%02x", ip[m]);
1788 }
1789 printf("\n");
1790 if (!memcmp(ip, "ATA_", 4)) {
1791 printf("SCSI_IDENT_%s_ATA=%.*s\n", assoc_str,
1792 k - 4, ip + 4);
1793 }
1794 } else {
1795 for (m = 0; m < i_len; ++m)
1796 printf("%02x", (unsigned int)ip[m]);
1797 printf("\n");
1798 }
1799 break;
1800 case 2: /* EUI-64 based */
1801 if (1 != c_set) {
1802 if (verbose) {
1803 pr2serr(" << expected binary code_set (1)>>\n");
1804 hex2stderr(ip, i_len, 0);
1805 }
1806 break;
1807 }
1808 printf("SCSI_IDENT_%s_EUI64=", assoc_str);
1809 for (m = 0; m < i_len; ++m)
1810 printf("%02x", (unsigned int)ip[m]);
1811 printf("\n");
1812 break;
1813 case 3: /* NAA */
1814 if (1 != c_set) {
1815 if (verbose) {
1816 pr2serr(" << expected binary code_set (1)>>\n");
1817 hex2stderr(ip, i_len, 0);
1818 }
1819 break;
1820 }
1821 /*
1822 * Unfortunately, there are some (broken) implementations
1823 * which return _several_ NAA descriptors.
1824 * So add a suffix to differentiate between them.
1825 */
1826 naa = (ip[0] >> 4) & 0xff;
1827 switch (naa) {
1828 case 6:
1829 suffix="REGEXT";
1830 break;
1831 case 5:
1832 suffix="REG";
1833 break;
1834 case 2:
1835 suffix="EXT";
1836 break;
1837 case 3:
1838 default:
1839 suffix="LOCAL";
1840 break;
1841 }
1842 printf("SCSI_IDENT_%s_NAA_%s=", assoc_str, suffix);
1843 for (m = 0; m < i_len; ++m)
1844 printf("%02x", (unsigned int)ip[m]);
1845 printf("\n");
1846 break;
1847 case 4: /* Relative target port */
1848 if ((1 != c_set) || (1 != assoc) || (4 != i_len)) {
1849 if (verbose) {
1850 pr2serr(" << expected binary code_set, target "
1851 "port association, length 4>>\n");
1852 hex2stderr(ip, i_len, 0);
1853 }
1854 break;
1855 }
1856 d_id = sg_get_unaligned_be16(ip + 2);
1857 printf("SCSI_IDENT_%s_RELATIVE=%d\n", assoc_str, d_id);
1858 break;
1859 case 5: /* (primary) Target port group */
1860 if ((1 != c_set) || (1 != assoc) || (4 != i_len)) {
1861 if (verbose) {
1862 pr2serr(" << expected binary code_set, target "
1863 "port association, length 4>>\n");
1864 hex2stderr(ip, i_len, 0);
1865 }
1866 break;
1867 }
1868 d_id = sg_get_unaligned_be16(ip + 2);
1869 printf("SCSI_IDENT_%s_TARGET_PORT_GROUP=0x%x\n", assoc_str, d_id);
1870 break;
1871 case 6: /* Logical unit group */
1872 if ((1 != c_set) || (0 != assoc) || (4 != i_len)) {
1873 if (verbose) {
1874 pr2serr(" << expected binary code_set, logical "
1875 "unit association, length 4>>\n");
1876 hex2stderr(ip, i_len, 0);
1877 }
1878 break;
1879 }
1880 d_id = sg_get_unaligned_be16(ip + 2);
1881 printf("SCSI_IDENT_%s_LOGICAL_UNIT_GROUP=0x%x\n", assoc_str, d_id);
1882 break;
1883 case 7: /* MD5 logical unit identifier */
1884 if ((1 != c_set) || (0 != assoc)) {
1885 if (verbose) {
1886 pr2serr(" << expected binary code_set, logical "
1887 "unit association>>\n");
1888 hex2stderr(ip, i_len, 0);
1889 }
1890 break;
1891 }
1892 printf("SCSI_IDENT_%s_MD5=", assoc_str);
1893 hex2stdout(ip, i_len, -1);
1894 break;
1895 case 8: /* SCSI name string */
1896 if (3 != c_set) {
1897 if (verbose) {
1898 pr2serr(" << expected UTF-8 code_set>>\n");
1899 hex2stderr(ip, i_len, -1);
1900 }
1901 break;
1902 }
1903 if (! (strncmp((const char *)ip, "eui.", 4) ||
1904 strncmp((const char *)ip, "EUI.", 4) ||
1905 strncmp((const char *)ip, "naa.", 4) ||
1906 strncmp((const char *)ip, "NAA.", 4) ||
1907 strncmp((const char *)ip, "iqn.", 4))) {
1908 if (verbose) {
1909 pr2serr(" << expected name string prefix>>\n");
1910 hex2stderr(ip, i_len, -1);
1911 }
1912 break;
1913 }
1914
1915 printf("SCSI_IDENT_%s_NAME=%.*s\n", assoc_str, i_len,
1916 (const char *)ip);
1917 break;
1918 case 9: /* Protocol specific port identifier */
1919 if (TPROTO_UAS == p_id) {
1920 if ((4 != i_len) || (1 != assoc)) {
1921 if (verbose) {
1922 pr2serr(" << UAS (USB) expected target "
1923 "port association>>\n");
1924 hex2stderr(ip, i_len, 0);
1925 }
1926 break;
1927 }
1928 printf("SCSI_IDENT_%s_UAS_DEVICE_ADDRESS=0x%x\n", assoc_str,
1929 ip[0] & 0x7f);
1930 printf("SCSI_IDENT_%s_UAS_INTERFACE_NUMBER=0x%x\n", assoc_str,
1931 ip[2]);
1932 } else if (TPROTO_SOP == p_id) {
1933 if ((4 != i_len) && (8 != i_len)) { /* spc4r36h confused */
1934 if (verbose) {
1935 pr2serr(" << SOP (PCIe) descriptor "
1936 "length=%d >>\n", i_len);
1937 hex2stderr(ip, i_len, 0);
1938 }
1939 break;
1940 }
1941 printf("SCSI_IDENT_%s_SOP_ROUTING_ID=0x%x\n", assoc_str,
1942 sg_get_unaligned_be16(ip + 0));
1943 } else {
1944 pr2serr(" << Protocol specific port identifier "
1945 "protocol_id=0x%x>>\n", p_id);
1946 }
1947 break;
1948 case 0xa: /* UUID based */
1949 if (1 != c_set) {
1950 if (verbose) {
1951 pr2serr(" << expected binary code_set (1)>>\n");
1952 hex2stderr(ip, i_len, 0);
1953 }
1954 break;
1955 }
1956 if (i_len < 18) {
1957 if (verbose) {
1958 pr2serr(" << short UUID field expected 18 or more, "
1959 "got %d >>\n", i_len);
1960 hex2stderr(ip, i_len, 0);
1961 }
1962 break;
1963 }
1964 printf("SCSI_IDENT_%s_UUID=", assoc_str);
1965 for (m = 2; m < i_len; ++m) {
1966 if ((6 == m) || (8 == m) || (10 == m) || (12 == m))
1967 printf("-%02x", (unsigned int)ip[m]);
1968 else
1969 printf("%02x", (unsigned int)ip[m]);
1970 }
1971 printf("\n");
1972 break;
1973 default: /* reserved */
1974 if (verbose) {
1975 pr2serr(" reserved designator=0x%x\n", desig_type);
1976 hex2stderr(ip, i_len, -1);
1977 }
1978 break;
1979 }
1980 }
1981 if (-2 == u && verbose)
1982 pr2serr("Device identification VPD page error: "
1983 "around offset=%d\n", off);
1984 }
1985
1986 /* VPD_BLOCK_LIMITS 0xb0 ["bl"] (SBC) */
1987 /* VPD_SA_DEV_CAP 0xb0 ["sad"] (SSC) */
1988 /* Sequential access device characteristics, ssc+smc */
1989 /* OSD information, osd */
1990 static void
decode_b0_vpd(uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jop)1991 decode_b0_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
1992 {
1993 int pdt = PDT_MASK & buff[0];
1994 sgj_state * jsp = &op->json_st;
1995
1996 if (op->do_hex) {
1997 hex2stdout(buff, len, no_ascii_4hex(op));
1998 return;
1999 }
2000 switch (pdt) {
2001 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
2002 /* done by decode_block_limits_vpd() */
2003 break;
2004 case PDT_TAPE: case PDT_MCHANGER:
2005 sgj_haj_vi_nex(jsp, jop, 2, "TSMC", SGJ_SEP_EQUAL_NO_SPACE,
2006 !!(buff[4] & 0x2), false, "Tape Stream Mirror "
2007 "Capable");
2008 sgj_haj_vi_nex(jsp, jop, 2, "WORM", SGJ_SEP_EQUAL_NO_SPACE,
2009 !!(buff[4] & 0x1), false, "Write Once Read Multiple "
2010 "supported");
2011
2012 break;
2013 case PDT_OSD:
2014 default:
2015 pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt);
2016 hex2stderr(buff, len, 0);
2017 break;
2018 }
2019 }
2020
2021 /* VPD_BLOCK_DEV_CHARS sbc 0xb1 ["bdc"] */
2022 /* VPD_MAN_ASS_SN ssc */
2023 static void
decode_b1_vpd(uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jop)2024 decode_b1_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
2025 {
2026 int pdt;
2027 sgj_state * jsp = &op->json_st;
2028
2029 if (op->do_hex) {
2030 hex2stdout(buff, len, no_ascii_4hex(op));
2031 return;
2032 }
2033 pdt = PDT_MASK & buff[0];
2034 switch (pdt) {
2035 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
2036 /* now done by decode_block_dev_ch_vpd() in sg_vpd_common.c */
2037 break;
2038 case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC:
2039 sgj_pr_hr(jsp, " Manufacturer-assigned serial number: %.*s\n",
2040 len - 4, buff + 4);
2041 sgj_js_nv_s_len(jsp, jop, "manufacturer_assigned_serial_number",
2042 (const char *)buff + 4, len - 4);
2043 break;
2044 default:
2045 pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt);
2046 hex2stderr(buff, len, 0);
2047 break;
2048 }
2049 }
2050
2051 /* VPD_REFERRALS sbc 0xb3 ["ref"] */
2052 /* VPD_AUTOMATION_DEV_SN ssc 0xb3 ["adsn"] */
2053 static void
decode_b3_vpd(uint8_t * buff,int len,struct opts_t * op,sgj_opaque_p jop)2054 decode_b3_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
2055 {
2056 int pdt;
2057 sgj_state * jsp = &op->json_st;
2058
2059 if (op->do_hex) {
2060 hex2stdout(buff, len, no_ascii_4hex(op));
2061 return;
2062 }
2063 pdt = buff[0] & PDT_MASK;
2064 switch (pdt) {
2065 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
2066 /* now done in decode_referrals_vpd() in sg_vpd_common.c */
2067 break;
2068 case PDT_TAPE: case PDT_MCHANGER:
2069 sgj_pr_hr(jsp, " Automation device serial number: %.*s\n",
2070 len - 4, buff + 4);
2071 sgj_js_nv_s_len(jsp, jop, "automation_device_serial_number",
2072 (const char *)buff + 4, len - 4);
2073 break;
2074 default:
2075 pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt);
2076 hex2stderr(buff, len, 0);
2077 break;
2078 }
2079 }
2080
2081 #if 0
2082 static void
2083 decode_rdac_vpd_c9_rtpg_data(uint8_t aas, uint8_t vendor)
2084 {
2085 printf(" Asymmetric Access State:");
2086 switch(aas & 0x0F) {
2087 case 0x0:
2088 printf(" Active/Optimized");
2089 break;
2090 case 0x1:
2091 printf(" Active/Non-Optimized");
2092 break;
2093 case 0x2:
2094 printf(" Standby");
2095 break;
2096 case 0x3:
2097 printf(" Unavailable");
2098 break;
2099 case 0xE:
2100 printf(" Offline");
2101 break;
2102 case 0xF:
2103 printf(" Transitioning");
2104 break;
2105 default:
2106 printf(" (unknown)");
2107 break;
2108 }
2109 printf("\n");
2110
2111 printf(" Vendor Specific Field:");
2112 switch(vendor) {
2113 case 0x01:
2114 printf(" Operating normally");
2115 break;
2116 case 0x02:
2117 printf(" Non-responsive to queries");
2118 break;
2119 case 0x03:
2120 printf(" Controller being held in reset");
2121 break;
2122 case 0x04:
2123 printf(" Performing controller firmware download (1st "
2124 "controller)");
2125 break;
2126 case 0x05:
2127 printf(" Performing controller firmware download (2nd "
2128 "controller)");
2129 break;
2130 case 0x06:
2131 printf(" Quiesced as a result of an administrative request");
2132 break;
2133 case 0x07:
2134 printf(" Service mode as a result of an administrative request");
2135 break;
2136 case 0xFF:
2137 printf(" Details are not available");
2138 break;
2139 default:
2140 printf(" (unknown)");
2141 break;
2142 }
2143 printf("\n");
2144 }
2145
2146 static void
2147 decode_rdac_vpd_c9(uint8_t * buff, int len, struct opts_t * op)
2148 {
2149 if (len < 3) {
2150 pr2serr("Volume Access Control VPD page length too short=%d\n", len);
2151 return;
2152 }
2153 if (op->do_hex) {
2154 hex2stdout(buff, len, no_ascii_4hex(op));
2155 return;
2156 }
2157 if (buff[4] != 'v' && buff[5] != 'a' && buff[6] != 'c') {
2158 pr2serr("Invalid page identifier %c%c%c%c, decoding "
2159 "not possible.\n" , buff[4], buff[5], buff[6], buff[7]);
2160 return;
2161 }
2162 if (buff[7] != '1') {
2163 pr2serr("Invalid page version '%c' (should be 1)\n", buff[7]);
2164 }
2165 if ( (buff[8] & 0xE0) == 0xE0 ) {
2166 printf(" IOShipping (ALUA): Enabled\n");
2167 } else {
2168 printf(" AVT:");
2169 if (buff[8] & 0x80) {
2170 printf(" Enabled");
2171 if (buff[8] & 0x40)
2172 printf(" (Allow reads on sector 0)");
2173 printf("\n");
2174 } else {
2175 printf(" Disabled\n");
2176 }
2177 }
2178 printf(" Volume Access via: ");
2179 if (buff[8] & 0x01)
2180 printf("primary controller\n");
2181 else
2182 printf("alternate controller\n");
2183
2184 if (buff[8] & 0x08) {
2185 printf(" Path priority: %d ", buff[15] & 0xf);
2186 switch(buff[15] & 0xf) {
2187 case 0x1:
2188 printf("(preferred path)\n");
2189 break;
2190 case 0x2:
2191 printf("(secondary path)\n");
2192 break;
2193 default:
2194 printf("(unknown)\n");
2195 break;
2196 }
2197
2198 printf(" Preferred Path Auto Changeable:");
2199 switch(buff[14] & 0x3C) {
2200 case 0x14:
2201 printf(" No (User Disabled and Host Type Restricted)\n");
2202 break;
2203 case 0x18:
2204 printf(" No (User Disabled)\n");
2205 break;
2206 case 0x24:
2207 printf(" No (Host Type Restricted)\n");
2208 break;
2209 case 0x28:
2210 printf(" Yes\n");
2211 break;
2212 default:
2213 printf(" (Unknown)\n");
2214 break;
2215 }
2216
2217 printf(" Implicit Failback:");
2218 switch(buff[14] & 0x03) {
2219 case 0x1:
2220 printf(" Disabled\n");
2221 break;
2222 case 0x2:
2223 printf(" Enabled\n");
2224 break;
2225 default:
2226 printf(" (Unknown)\n");
2227 break;
2228 }
2229 } else {
2230 printf(" Path priority: %d ", buff[9] & 0xf);
2231 switch(buff[9] & 0xf) {
2232 case 0x1:
2233 printf("(preferred path)\n");
2234 break;
2235 case 0x2:
2236 printf("(secondary path)\n");
2237 break;
2238 default:
2239 printf("(unknown)\n");
2240 break;
2241 }
2242 }
2243
2244 if (buff[8] & 0x80) {
2245 printf(" Target Port Group Data (This controller):\n");
2246 decode_rdac_vpd_c9_rtpg_data(buff[10], buff[11]);
2247
2248 printf(" Target Port Group Data (Alternate controller):\n");
2249 decode_rdac_vpd_c9_rtpg_data(buff[12], buff[13]);
2250 }
2251
2252 return;
2253 }
2254 #endif
2255
2256 extern const char * sg_ansi_version_arr[];
2257
2258 static const char *
get_ansi_version_str(int version,char * b,int blen)2259 get_ansi_version_str(int version, char * b, int blen)
2260 {
2261 version &= 0xf;
2262 b[blen - 1] = '\0';
2263 strncpy(b, sg_ansi_version_arr[version], blen - 1);
2264 return b;
2265 }
2266
2267 static void
std_inq_decode(struct opts_t * op,sgj_opaque_p jop,int off)2268 std_inq_decode(struct opts_t * op, sgj_opaque_p jop, int off)
2269 {
2270 int len, pqual, pdt, ansi_version, k, j;
2271 sgj_state * jsp = &op->json_st;
2272 bool as_json = jsp->pr_as_json;
2273 const char * cp;
2274 const uint8_t * rp;
2275 int vdesc_arr[8];
2276 char b[128];
2277 static const int blen = sizeof(b);
2278
2279 rp = rsp_buff + off;
2280 memset(vdesc_arr, 0, sizeof(vdesc_arr));
2281 if (op->do_raw) {
2282 dStrRaw((const char *)rp, op->maxlen);
2283 return;
2284 } else if (op->do_hex) {
2285 /* with -H, print with address, -HH without */
2286 hex2stdout(rp, op->maxlen, no_ascii_4hex(op));
2287 return;
2288 }
2289 pqual = (rp[0] & 0xe0) >> 5;
2290 if (! op->do_raw && ! op->do_export) {
2291 strcpy(b, "standard INQUIRY:");
2292 if (0 == pqual)
2293 sgj_pr_hr(jsp, "%s\n", b);
2294 else if (1 == pqual)
2295 sgj_pr_hr(jsp, "%s [PQ indicates LU temporarily unavailable]\n",
2296 b);
2297 else if (3 == pqual)
2298 sgj_pr_hr(jsp, "%s [PQ indicates LU not accessible via this "
2299 "port]\n", b);
2300 else
2301 sgj_pr_hr(jsp, "%s [reserved or vendor specific qualifier "
2302 "[%d]]\n", b, pqual);
2303 }
2304 len = rp[4] + 5;
2305 /* N.B. rp[2] full byte is 'version' in SPC-2,3,4 but in SPC
2306 * [spc-r11a (1997)] bits 6,7: ISO/IEC version; bits 3-5: ECMA
2307 * version; bits 0-2: SCSI version */
2308 ansi_version = rp[2] & 0x7; /* Only take SCSI version */
2309 pdt = rp[0] & PDT_MASK;
2310 if (op->do_export) {
2311 printf("SCSI_TPGS=%d\n", (rp[5] & 0x30) >> 4);
2312 cp = sg_get_pdt_str(pdt, blen, b);
2313 if (strlen(cp) > 0)
2314 printf("SCSI_TYPE=%s\n", cp);
2315 } else {
2316 sgj_pr_hr(jsp, " PQual=%d PDT=%d RMB=%d LU_CONG=%d "
2317 "hot_pluggable=%d version=0x%02x ", pqual, pdt,
2318 !!(rp[1] & 0x80), !!(rp[1] & 0x40), (rp[1] >> 4) & 0x3,
2319 (unsigned int)rp[2]);
2320 sgj_pr_hr(jsp, " [%s]\n", get_ansi_version_str(ansi_version, b,
2321 blen));
2322 sgj_pr_hr(jsp, " [AERC=%d] [TrmTsk=%d] NormACA=%d HiSUP=%d "
2323 " Resp_data_format=%d\n SCCS=%d ", !!(rp[3] & 0x80),
2324 !!(rp[3] & 0x40), !!(rp[3] & 0x20), !!(rp[3] & 0x10),
2325 rp[3] & 0x0f, !!(rp[5] & 0x80));
2326 sgj_pr_hr(jsp, "ACC=%d TPGS=%d 3PC=%d Protect=%d ",
2327 !!(rp[5] & 0x40), ((rp[5] & 0x30) >> 4), !!(rp[5] & 0x08),
2328 !!(rp[5] & 0x01));
2329 sgj_pr_hr(jsp, " [BQue=%d]\n EncServ=%d ", !!(rp[6] & 0x80),
2330 !!(rp[6] & 0x40));
2331 if (rp[6] & 0x10)
2332 sgj_pr_hr(jsp, "MultiP=1 (VS=%d) ", !!(rp[6] & 0x20));
2333 else
2334 sgj_pr_hr(jsp, "MultiP=0 ");
2335 sgj_pr_hr(jsp, "[MChngr=%d] [ACKREQQ=%d] Addr16=%d\n "
2336 "[RelAdr=%d] ", !!(rp[6] & 0x08), !!(rp[6] & 0x04),
2337 !!(rp[6] & 0x01), !!(rp[7] & 0x80));
2338 sgj_pr_hr(jsp, "WBus16=%d Sync=%d [Linked=%d] [TranDis=%d] ",
2339 !!(rp[7] & 0x20), !!(rp[7] & 0x10), !!(rp[7] & 0x08),
2340 !!(rp[7] & 0x04));
2341 sgj_pr_hr(jsp, "CmdQue=%d\n", !!(rp[7] & 0x02));
2342 if (op->maxlen > 56)
2343 sgj_pr_hr(jsp, " [SPI: Clocking=0x%x QAS=%d IUS=%d]\n",
2344 (rp[56] & 0x0c) >> 2, !!(rp[56] & 0x2),
2345 !!(rp[56] & 0x1));
2346 if (op->maxlen >= len)
2347 sgj_pr_hr(jsp, " length=%d (0x%x)", len, len);
2348 else
2349 sgj_pr_hr(jsp, " length=%d (0x%x), but only fetched %d bytes",
2350 len, len, op->maxlen);
2351 if ((ansi_version >= 2) && (len < SAFE_STD_INQ_RESP_LEN))
2352 sgj_pr_hr(jsp, "\n [for SCSI>=2, len>=36 is expected]");
2353 cp = sg_get_pdt_str(pdt, blen, b);
2354 if (strlen(cp) > 0)
2355 sgj_pr_hr(jsp, " Peripheral device type: %s\n", cp);
2356 }
2357 if (op->maxlen <= 8) {
2358 if (! op->do_export)
2359 sgj_pr_hr(jsp, " Inquiry response length=%d, no vendor, product "
2360 "or revision data\n", op->maxlen);
2361 } else {
2362 int i;
2363
2364 memcpy(xtra_buff, &rp[8], 8);
2365 xtra_buff[8] = '\0';
2366 /* Fixup any tab characters */
2367 for (i = 0; i < 8; ++i)
2368 if (xtra_buff[i] == 0x09)
2369 xtra_buff[i] = ' ';
2370 if (op->do_export) {
2371 len = encode_whitespaces((uint8_t *)xtra_buff, 8);
2372 if (len > 0) {
2373 printf("SCSI_VENDOR=%s\n", xtra_buff);
2374 encode_string(xtra_buff, &rp[8], 8);
2375 printf("SCSI_VENDOR_ENC=%s\n", xtra_buff);
2376 }
2377 } else
2378 sgj_pr_hr(jsp, " Vendor identification: %s\n", xtra_buff);
2379 if (op->maxlen <= 16) {
2380 if (! op->do_export)
2381 sgj_pr_hr(jsp, " Product identification: <none>\n");
2382 } else {
2383 memcpy(xtra_buff, &rp[16], 16);
2384 xtra_buff[16] = '\0';
2385 if (op->do_export) {
2386 len = encode_whitespaces((uint8_t *)xtra_buff, 16);
2387 if (len > 0) {
2388 printf("SCSI_MODEL=%s\n", xtra_buff);
2389 encode_string(xtra_buff, &rp[16], 16);
2390 printf("SCSI_MODEL_ENC=%s\n", xtra_buff);
2391 }
2392 } else
2393 sgj_pr_hr(jsp, " Product identification: %s\n", xtra_buff);
2394 }
2395 if (op->maxlen <= 32) {
2396 if (! op->do_export)
2397 sgj_pr_hr(jsp, " Product revision level: <none>\n");
2398 } else {
2399 memcpy(xtra_buff, &rp[32], 4);
2400 xtra_buff[4] = '\0';
2401 if (op->do_export) {
2402 len = encode_whitespaces((uint8_t *)xtra_buff, 4);
2403 if (len > 0)
2404 printf("SCSI_REVISION=%s\n", xtra_buff);
2405 } else
2406 sgj_pr_hr(jsp, " Product revision level: %s\n", xtra_buff);
2407 }
2408 if (op->do_vendor && (op->maxlen > 36) && ('\0' != rp[36]) &&
2409 (' ' != rp[36])) {
2410 memcpy(xtra_buff, &rp[36], op->maxlen < 56 ? op->maxlen - 36 :
2411 20);
2412 if (op->do_export) {
2413 len = encode_whitespaces((uint8_t *)xtra_buff, 20);
2414 if (len > 0)
2415 printf("VENDOR_SPECIFIC=%s\n", xtra_buff);
2416 } else
2417 sgj_pr_hr(jsp, " Vendor specific: %s\n", xtra_buff);
2418 }
2419 if (op->do_descriptors) {
2420 for (j = 0, k = 58; ((j < 8) && ((k + 1) < op->maxlen));
2421 k +=2, ++j)
2422 vdesc_arr[j] = sg_get_unaligned_be16(rp + k);
2423 }
2424 if ((op->do_vendor > 1) && (op->maxlen > 96)) {
2425 memcpy(xtra_buff, &rp[96], op->maxlen - 96);
2426 if (op->do_export) {
2427 len = encode_whitespaces((uint8_t *)xtra_buff,
2428 op->maxlen - 96);
2429 if (len > 0)
2430 printf("VENDOR_SPECIFIC=%s\n", xtra_buff);
2431 } else
2432 sgj_pr_hr(jsp, " Vendor specific: %s\n", xtra_buff);
2433 }
2434 if (op->do_vendor && (op->maxlen > 243) &&
2435 (0 == strncmp("OPEN-V", (const char *)&rp[16], 6))) {
2436 memcpy(xtra_buff, &rp[212], 32);
2437 if (op->do_export) {
2438 len = encode_whitespaces((uint8_t *)xtra_buff, 32);
2439 if (len > 0)
2440 printf("VENDOR_SPECIFIC_OPEN-V_LDEV_NAME=%s\n", xtra_buff);
2441 } else
2442 sgj_pr_hr(jsp, " Vendor specific OPEN-V LDEV Name: %s\n",
2443 xtra_buff);
2444 }
2445 }
2446 if (! op->do_export) {
2447 sgj_opaque_p jo2p = NULL;
2448
2449 if (as_json)
2450 jo2p = std_inq_decode_js(rp, op->maxlen, op, jop);
2451 if ((0 == op->maxlen) && usn_buff[0])
2452 sgj_pr_hr(jsp, " Unit serial number: %s\n", usn_buff);
2453 if (op->do_descriptors) {
2454 sgj_opaque_p jap = sgj_named_subarray_r(jsp, jo2p,
2455 "version_descriptor_list");
2456 if (0 == vdesc_arr[0]) {
2457 sgj_pr_hr(jsp, "\n");
2458 sgj_pr_hr(jsp, " No version descriptors available\n");
2459 } else {
2460 sgj_pr_hr(jsp, "\n");
2461 sgj_pr_hr(jsp, " Version descriptors:\n");
2462 for (k = 0; k < 8; ++k) {
2463 sgj_opaque_p jo3p = sgj_new_unattached_object_r(jsp);
2464 int vdv = vdesc_arr[k];
2465
2466 if (0 == vdv)
2467 break;
2468 cp = find_version_descriptor_str(vdv);
2469 if (cp)
2470 sgj_pr_hr(jsp, " %s\n", cp);
2471 else
2472 sgj_pr_hr(jsp, " [unrecognised version descriptor "
2473 "code: 0x%x]\n", vdv);
2474 sgj_js_nv_ihexstr(jsp, jo3p, "version_descriptor", vdv,
2475 NULL, cp ? cp : "unknown");
2476 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
2477 }
2478 }
2479 }
2480 }
2481 }
2482
2483 /* Returns 0 if Unit Serial Number VPD page contents found, else see
2484 * sg_ll_inquiry_v2() return values */
2485 static int
fetch_unit_serial_num(int sg_fd,char * obuff,int obuff_len,int verbose)2486 fetch_unit_serial_num(int sg_fd, char * obuff, int obuff_len, int verbose)
2487 {
2488 int len, k, res, c;
2489 uint8_t * b;
2490 uint8_t * free_b;
2491
2492 b = sg_memalign(DEF_ALLOC_LEN, 0, &free_b, false);
2493 if (NULL == b) {
2494 pr2serr("%s: unable to allocate on heap\n", __func__);
2495 return sg_convert_errno(ENOMEM);
2496 }
2497 res = vpd_fetch_page(sg_fd, b, VPD_SUPPORTED_VPDS,
2498 -1 /* 1 byte alloc_len */, false, verbose, &len);
2499 if (res) {
2500 if (verbose > 2)
2501 pr2serr("%s: no supported VPDs page\n", __func__);
2502 res = SG_LIB_CAT_MALFORMED;
2503 goto fini;
2504 }
2505 if (! vpd_page_is_supported(b, len, VPD_UNIT_SERIAL_NUM, verbose)) {
2506 res = sg_convert_errno(EDOM); /* was SG_LIB_CAT_ILLEGAL_REQ */
2507 goto fini;
2508 }
2509
2510 memset(b, 0xff, 4); /* guard against empty response */
2511 res = vpd_fetch_page(sg_fd, b, VPD_UNIT_SERIAL_NUM, -1, false, verbose,
2512 &len);
2513 if ((0 == res) && (len > 3)) {
2514 len -= 4;
2515 len = (len < (obuff_len - 1)) ? len : (obuff_len - 1);
2516 if (len > 0) {
2517 /* replace non-printable characters (except NULL) with space */
2518 for (k = 0; k < len; ++k) {
2519 c = b[4 + k];
2520 if (c)
2521 obuff[k] = isprint(c) ? c : ' ';
2522 else
2523 break;
2524 }
2525 obuff[k] = '\0';
2526 res = 0;
2527 goto fini;
2528 } else {
2529 if (verbose > 2)
2530 pr2serr("%s: bad sn VPD page\n", __func__);
2531 res = SG_LIB_CAT_MALFORMED;
2532 }
2533 } else {
2534 if (verbose > 2)
2535 pr2serr("%s: no supported VPDs page\n", __func__);
2536 res = SG_LIB_CAT_MALFORMED;
2537 }
2538 fini:
2539 if (free_b)
2540 free(free_b);
2541 return res;
2542 }
2543
2544
2545 /* Process a standard INQUIRY data format (response).
2546 * Returns 0 if successful */
2547 static int
std_inq_process(int sg_fd,struct opts_t * op,sgj_opaque_p jop,int off)2548 std_inq_process(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
2549 {
2550 int res, len, rlen, act_len;
2551 int vb, resid;
2552 char buff[48];
2553
2554 if (sg_fd < 0) { /* assume --inhex=FD usage */
2555 std_inq_decode(op, jop, off);
2556 return 0;
2557 }
2558 rlen = (op->maxlen > 0) ? op->maxlen : SAFE_STD_INQ_RESP_LEN;
2559 vb = op->verbose;
2560 res = sg_ll_inquiry_v2(sg_fd, false, 0, rsp_buff, rlen, DEF_PT_TIMEOUT,
2561 &resid, false, vb);
2562 if (0 == res) {
2563 if ((vb > 4) && ((rlen - resid) > 0)) {
2564 pr2serr("Safe (36 byte) Inquiry response:\n");
2565 hex2stderr(rsp_buff, rlen - resid, 0);
2566 }
2567 len = rsp_buff[4] + 5;
2568 if ((len > SAFE_STD_INQ_RESP_LEN) && (len < 256) &&
2569 (0 == op->maxlen)) {
2570 rlen = len;
2571 memset(rsp_buff, 0, rlen);
2572 if (sg_ll_inquiry_v2(sg_fd, false, 0, rsp_buff, rlen,
2573 DEF_PT_TIMEOUT, &resid, true, vb)) {
2574 pr2serr("second INQUIRY (%d byte) failed\n", len);
2575 return SG_LIB_CAT_OTHER;
2576 }
2577 if (len != (rsp_buff[4] + 5)) {
2578 pr2serr("strange, consecutive INQUIRYs yield different "
2579 "'additional lengths'\n");
2580 len = rsp_buff[4] + 5;
2581 }
2582 }
2583 if (op->maxlen > 0)
2584 act_len = rlen;
2585 else
2586 act_len = (rlen < len) ? rlen : len;
2587 /* don't use more than HBA's resid says was transferred from LU */
2588 if (act_len > (rlen - resid))
2589 act_len = rlen - resid;
2590 if (act_len < SAFE_STD_INQ_RESP_LEN)
2591 rsp_buff[act_len] = '\0';
2592 if ((! op->do_only) && (! op->do_export) && (0 == op->maxlen)) {
2593 if (fetch_unit_serial_num(sg_fd, usn_buff, sizeof(usn_buff), vb))
2594 usn_buff[0] = '\0';
2595 }
2596 op->maxlen = act_len;
2597 std_inq_decode(op, jop, 0);
2598 return 0;
2599 } else if (res < 0) { /* could be an ATA device */
2600 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
2601 defined(HDIO_GET_IDENTITY)
2602 /* Try an ATA Identify Device command */
2603 res = try_ata_identify(sg_fd, op->do_hex, op->do_raw, vb);
2604 if (0 != res) {
2605 pr2serr("SCSI INQUIRY, NVMe Identify and fetching ATA "
2606 "information failed on %s\n", op->device_name);
2607 return (res < 0) ? SG_LIB_CAT_OTHER : res;
2608 }
2609 #else
2610 pr2serr("SCSI INQUIRY failed on %s, res=%d\n",
2611 op->device_name, res);
2612 return res;
2613 #endif
2614 } else {
2615 char b[80];
2616
2617 if (vb > 0) {
2618 pr2serr(" inquiry: failed requesting %d byte response: ", rlen);
2619 if (resid && (vb > 1))
2620 snprintf(buff, sizeof(buff), " [resid=%d]", resid);
2621 else
2622 buff[0] = '\0';
2623 sg_get_category_sense_str(res, sizeof(b), b, vb);
2624 pr2serr("%s%s\n", b, buff);
2625 }
2626 return res;
2627 }
2628 return 0;
2629 }
2630
2631 #ifdef SG_SCSI_STRINGS
2632 /* Returns 0 if successful */
2633 static int
cmddt_process(int sg_fd,const struct opts_t * op)2634 cmddt_process(int sg_fd, const struct opts_t * op)
2635 {
2636 int k, j, num, len, pdt, reserved_cmddt, support_num, res;
2637 char op_name[128];
2638
2639 memset(rsp_buff, 0, rsp_buff_sz);
2640 if (op->do_cmddt > 1) {
2641 printf("Supported command list:\n");
2642 for (k = 0; k < 256; ++k) {
2643 res = sg_ll_inquiry(sg_fd, true /* cmddt */, false, k, rsp_buff,
2644 DEF_ALLOC_LEN, true, op->verbose);
2645 if (0 == res) {
2646 pdt = rsp_buff[0] & PDT_MASK;
2647 support_num = rsp_buff[1] & 7;
2648 reserved_cmddt = rsp_buff[4];
2649 if ((3 == support_num) || (5 == support_num)) {
2650 num = rsp_buff[5];
2651 for (j = 0; j < num; ++j)
2652 printf(" %.2x", (int)rsp_buff[6 + j]);
2653 if (5 == support_num)
2654 printf(" [vendor specific manner (5)]");
2655 sg_get_opcode_name((uint8_t)k, pdt,
2656 sizeof(op_name) - 1, op_name);
2657 op_name[sizeof(op_name) - 1] = '\0';
2658 printf(" %s\n", op_name);
2659 } else if ((4 == support_num) || (6 == support_num))
2660 printf(" opcode=0x%.2x vendor specific (%d)\n",
2661 k, support_num);
2662 else if ((0 == support_num) && (reserved_cmddt > 0)) {
2663 printf(" opcode=0x%.2x ignored cmddt bit, "
2664 "given standard INQUIRY response, stop\n", k);
2665 break;
2666 }
2667 } else if (SG_LIB_CAT_ILLEGAL_REQ == res)
2668 break;
2669 else {
2670 pr2serr("CmdDt INQUIRY on opcode=0x%.2x: failed\n", k);
2671 break;
2672 }
2673 }
2674 }
2675 else {
2676 res = sg_ll_inquiry(sg_fd, true /* cmddt */, false, op->vpd_pn,
2677 rsp_buff, DEF_ALLOC_LEN, true, op->verbose);
2678 if (0 == res) {
2679 pdt = rsp_buff[0] & PDT_MASK;
2680 if (! op->do_raw) {
2681 printf("CmdDt INQUIRY, opcode=0x%.2x: [", op->vpd_pn);
2682 sg_get_opcode_name((uint8_t)op->vpd_pn, pdt,
2683 sizeof(op_name) - 1, op_name);
2684 op_name[sizeof(op_name) - 1] = '\0';
2685 printf("%s]\n", op_name);
2686 }
2687 len = rsp_buff[5] + 6;
2688 reserved_cmddt = rsp_buff[4];
2689 if (op->do_hex)
2690 hex2stdout(rsp_buff, len, no_ascii_4hex(op));
2691 else if (op->do_raw)
2692 dStrRaw((const char *)rsp_buff, len);
2693 else {
2694 bool prnt_cmd = false;
2695 const char * desc_p;
2696
2697 support_num = rsp_buff[1] & 7;
2698 num = rsp_buff[5];
2699 switch (support_num) {
2700 case 0:
2701 if (0 == reserved_cmddt)
2702 desc_p = "no data available";
2703 else
2704 desc_p = "ignored cmddt bit, standard INQUIRY "
2705 "response";
2706 break;
2707 case 1: desc_p = "not supported"; break;
2708 case 2: desc_p = "reserved (2)"; break;
2709 case 3: desc_p = "supported as per standard";
2710 prnt_cmd = true;
2711 break;
2712 case 4: desc_p = "vendor specific (4)"; break;
2713 case 5: desc_p = "supported in vendor specific way";
2714 prnt_cmd = true;
2715 break;
2716 case 6: desc_p = "vendor specific (6)"; break;
2717 case 7: desc_p = "reserved (7)"; break;
2718 }
2719 if (prnt_cmd) {
2720 printf(" Support field: %s [", desc_p);
2721 for (j = 0; j < num; ++j)
2722 printf(" %.2x", (int)rsp_buff[6 + j]);
2723 printf(" ]\n");
2724 } else
2725 printf(" Support field: %s\n", desc_p);
2726 }
2727 } else if (SG_LIB_CAT_ILLEGAL_REQ != res) {
2728 if (! op->do_raw) {
2729 printf("CmdDt INQUIRY, opcode=0x%.2x: [", op->vpd_pn);
2730 sg_get_opcode_name((uint8_t)op->vpd_pn, 0,
2731 sizeof(op_name) - 1, op_name);
2732 op_name[sizeof(op_name) - 1] = '\0';
2733 printf("%s]\n", op_name);
2734 }
2735 pr2serr("CmdDt INQUIRY on opcode=0x%.2x: failed\n", op->vpd_pn);
2736 }
2737 }
2738 return res;
2739 }
2740
2741 #else /* SG_SCSI_STRINGS */
2742
2743 /* Returns 0. */
2744 static int
cmddt_process(int sg_fd,const struct opts_t * op)2745 cmddt_process(int sg_fd, const struct opts_t * op)
2746 {
2747 if (sg_fd) { } /* suppress warning */
2748 if (op) { } /* suppress warning */
2749 pr2serr("'--cmddt' not implemented, use sg_opcodes\n");
2750 return 0;
2751 }
2752
2753 #endif /* SG_SCSI_STRINGS */
2754
2755
2756 /* Returns 0 if successful */
2757 static int
vpd_mainly_hex(int sg_fd,struct opts_t * op,sgj_opaque_p jap,int off)2758 vpd_mainly_hex(int sg_fd, struct opts_t * op, sgj_opaque_p jap, int off)
2759 {
2760 bool as_json;
2761 bool json_o_hr;
2762 int res, len, n;
2763 char b[128];
2764 sgj_state * jsp = &op->json_st;
2765 const char * cp;
2766 uint8_t * rp;
2767
2768 as_json = jsp->pr_as_json;
2769 json_o_hr = as_json && jsp->pr_out_hr;
2770 rp = rsp_buff + off;
2771 if ((! op->do_raw) && (op->do_hex < 3)) {
2772 if (op->do_hex)
2773 printf("VPD INQUIRY, page code=0x%.2x:\n", op->vpd_pn);
2774 else
2775 sgj_pr_hr(jsp, "VPD INQUIRY, page code=0x%.2x:\n", op->vpd_pn);
2776 }
2777 if (sg_fd < 0) {
2778 len = sg_get_unaligned_be16(rp + 2) + 4;
2779 res = 0;
2780 } else {
2781 memset(rp, 0, DEF_ALLOC_LEN);
2782 res = vpd_fetch_page(sg_fd, rp, op->vpd_pn, op->maxlen,
2783 op->do_quiet, op->verbose, &len);
2784 }
2785 if (0 == res) {
2786 if (op->do_raw)
2787 dStrRaw((const char *)rp, len);
2788 else {
2789 int pdt = pdt = rp[0] & PDT_MASK;
2790
2791 if (0 == op->vpd_pn)
2792 decode_supported_vpd_4inq(rp, len, op, jap);
2793 else {
2794 if (op->verbose) {
2795 cp = sg_get_pdt_str(pdt, sizeof(b), b);
2796 if (op->do_hex)
2797 printf(" [PQual=%d Peripheral device type: %s]\n",
2798 (rp[0] & 0xe0) >> 5, cp);
2799 else
2800 sgj_pr_hr(jsp, " [PQual=%d Peripheral device "
2801 "type: %s]\n", (rp[0] & 0xe0) >> 5, cp);
2802 }
2803 if (json_o_hr && (0 == op->do_hex) && (len > 0) &&
2804 (len < UINT16_MAX)) {
2805 char * p;
2806
2807 n = len * 4;
2808 p = malloc(n);
2809 if (p) {
2810 n = hex2str(rp, len, NULL, 1, n - 1, p);
2811 sgj_js_str_out(jsp, p, n);
2812 }
2813 } else
2814 hex2stdout(rp, len, no_ascii_4hex(op));
2815 }
2816 }
2817 } else {
2818 if (SG_LIB_CAT_ILLEGAL_REQ == res)
2819 pr2serr(" inquiry: field in cdb illegal (page not "
2820 "supported)\n");
2821 else {
2822 sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
2823 pr2serr(" inquiry: %s\n", b);
2824 }
2825 }
2826 return res;
2827 }
2828
2829 static int
recurse_vpd_decode(struct opts_t * op,sgj_opaque_p jop,int off)2830 recurse_vpd_decode(struct opts_t * op, sgj_opaque_p jop, int off)
2831 {
2832 return vpd_decode(-1, op, jop, off);
2833 }
2834
2835 /* Returns 0 if successful */
2836 static int
vpd_decode(int sg_fd,struct opts_t * op,sgj_opaque_p jop,int off)2837 vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
2838 {
2839 bool bad = false;
2840 bool qt = op->do_quiet;
2841 int len, pdt, pn, vb /*, pqual */;
2842 int res = 0;
2843 sgj_state * jsp = &op->json_st;
2844 bool as_json = jsp->pr_as_json;
2845 sgj_opaque_p jo2p = NULL;
2846 sgj_opaque_p jap = NULL;
2847 const char * np;
2848 const char * ep = "";
2849 uint8_t * rp;
2850
2851 rp = rsp_buff + off;
2852 vb = op->verbose;
2853 if ((off > 0) && (VPD_NOPE_WANT_STD_INQ != op->vpd_pn))
2854 pn = rp[1];
2855 else
2856 pn = op->vpd_pn;
2857 if (sg_fd != -1 && !op->do_force && pn != VPD_SUPPORTED_VPDS) {
2858 res = vpd_fetch_page(sg_fd, rp, VPD_SUPPORTED_VPDS, op->maxlen,
2859 qt, vb, &len);
2860 if (res)
2861 goto out;
2862 if (! vpd_page_is_supported(rp, len, pn, vb)) {
2863 if (vb)
2864 pr2serr("Given VPD page not in supported list, use --force "
2865 "to override this check\n");
2866 res = sg_convert_errno(EDOM); /* was SG_LIB_CAT_ILLEGAL_REQ */
2867 goto out;
2868 }
2869 }
2870 switch (pn) {
2871 case VPD_SUPPORTED_VPDS: /* 0x0 ["sv"] */
2872 np = "Supported VPD pages VPD page";
2873 if (!op->do_raw && (op->do_hex < 3))
2874 sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
2875 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
2876 if (res)
2877 break;
2878 if (op->do_raw)
2879 dStrRaw((const char *)rp, len);
2880 else if (op->do_hex)
2881 hex2stdout(rp, len, no_ascii_4hex(op));
2882 else {
2883 if (as_json) {
2884 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
2885 jap = sgj_named_subarray_r(jsp, jo2p,
2886 "supported_vpd_page_list");
2887 }
2888 decode_supported_vpd_4inq(rp, len, op, jap);
2889 }
2890 break;
2891 case VPD_UNIT_SERIAL_NUM: /* 0x80 ["sn"] */
2892 np = "Unit serial number VPD page";
2893 if (! op->do_raw && ! op->do_export && (op->do_hex < 3))
2894 sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
2895 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
2896 if (res)
2897 break;
2898 if (op->do_raw)
2899 dStrRaw((const char *)rp, len);
2900 else if (op->do_hex)
2901 hex2stdout(rp, len, no_ascii_4hex(op));
2902 else {
2903 char obuff[DEF_ALLOC_LEN];
2904 int k, m;
2905
2906 memset(obuff, 0, sizeof(obuff));
2907 len -= 4;
2908 if (len >= (int)sizeof(obuff))
2909 len = sizeof(obuff) - 1;
2910 memcpy(obuff, rp + 4, len);
2911 if (op->do_export) {
2912 k = encode_whitespaces((uint8_t *)obuff, len);
2913 if (k > 0) {
2914 printf("SCSI_IDENT_SERIAL=");
2915 /* udev-conforming character encoding */
2916 for (m = 0; m < k; ++m) {
2917 if ((obuff[m] >= '0' && obuff[m] <= '9') ||
2918 (obuff[m] >= 'A' && obuff[m] <= 'Z') ||
2919 (obuff[m] >= 'a' && obuff[m] <= 'z') ||
2920 strchr("#+-.:=@_", obuff[m]) != NULL)
2921 printf("%c", obuff[m]);
2922 else
2923 printf("\\x%02x", obuff[m]);
2924 }
2925 printf("\n");
2926 }
2927 } else {
2928 if (as_json)
2929 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
2930 k = encode_unicode((uint8_t *)obuff, len);
2931 if (k > 0) {
2932 sgj_pr_hr(jsp, " Unit serial number: %s\n", obuff);
2933 sgj_js_nv_s(jsp, jo2p, "unit_serial_number", obuff);
2934 }
2935 }
2936 }
2937 break;
2938 case VPD_DEVICE_ID: /* 0x83 ["di"] */
2939 np = "Device Identification VPD page";
2940 if (! op->do_raw && ! op->do_export && (op->do_hex < 3))
2941 sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
2942 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
2943 if (res)
2944 break;
2945 if (op->do_raw)
2946 dStrRaw((const char *)rp, len);
2947 else if (op->do_hex > 2)
2948 hex2stdout(rp, len, -1);
2949 else if (op->do_export && (! as_json))
2950 export_dev_ids(rp + 4, len - 4, op->verbose);
2951 else {
2952 if (as_json) {
2953 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
2954 jap = sgj_named_subarray_r(jsp, jo2p,
2955 "designation_descriptor_list");
2956 }
2957 decode_id_vpd(rp, len, op, jap);
2958 }
2959 break;
2960 case VPD_SOFTW_INF_ID: /* 0x84 ["sii"] */
2961 np = "Software interface identification VPD page";
2962 if (! op->do_raw && (op->do_hex < 3))
2963 sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
2964 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
2965 if (res)
2966 break;
2967 if (op->do_raw)
2968 dStrRaw((const char *)rp, len);
2969 else {
2970 if (as_json) {
2971 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
2972 jap = sgj_named_subarray_r(jsp, jo2p,
2973 "software_interface_identifier_list");
2974 }
2975 decode_softw_inf_id(rp, len, op, jap);
2976 }
2977 break;
2978 case VPD_MAN_NET_ADDR: /* 0x85 ["mna"] */
2979 np = "Management network addresses page";
2980 if (!op->do_raw && (op->do_hex < 3))
2981 sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
2982 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
2983 if (res)
2984 break;
2985 if (op->do_raw)
2986 dStrRaw((const char *)rp, len);
2987 else {
2988 // pdt = rp[0] & PDT_MASK;
2989 // pdt_str = sg_get_pdt_str(pdt, sizeof(d), d);
2990 // pqual = (rp[0] & 0xe0) >> 5;
2991 if (as_json) {
2992 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
2993 jap = sgj_named_subarray_r(jsp, jo2p,
2994 "network_services_descriptor_list");
2995 }
2996 decode_net_man_vpd(rp, len, op, jap);
2997 }
2998 break;
2999 case VPD_EXT_INQ: /* 0x86 ["ei"] */
3000 np = "Extended INQUIRY data";
3001 if (!op->do_raw && (op->do_hex < 3))
3002 sgj_pr_hr(jsp, "VPD INQUIRY: %s page\n", np);
3003 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3004 if (res)
3005 break;
3006 if (op->do_raw)
3007 dStrRaw((const char *)rp, len);
3008 else {
3009 bool protect = false;
3010
3011 op->protect_not_sure = false;
3012 if ((sg_fd >= 0) && (! op->do_force)) {
3013 struct sg_simple_inquiry_resp sir;
3014
3015 res = sg_simple_inquiry(sg_fd, &sir, false, vb);
3016 if (res) {
3017 if (op->verbose)
3018 pr2serr("%s: sg_simple_inquiry() failed, res=%d\n",
3019 __func__, res);
3020 op->protect_not_sure = true;
3021 } else
3022 protect = !!(sir.byte_5 & 0x1); /* SPC-3 and later */
3023 } else
3024 op->protect_not_sure = true;
3025 if (as_json)
3026 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3027 decode_x_inq_vpd(rp, len, protect, op, jo2p);
3028 }
3029 break;
3030 case VPD_MODE_PG_POLICY: /* 0x87 ["mpp"] */
3031 np = "Mode page policy";
3032 if (!op->do_raw && (op->do_hex < 3))
3033 sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3034 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3035 if (res)
3036 break;
3037 if (op->do_raw)
3038 dStrRaw((const char *)rp, len);
3039 else {
3040 if (as_json) {
3041 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3042 jap = sgj_named_subarray_r(jsp, jo2p,
3043 "mode_page_policy_descriptor_list");
3044 }
3045 decode_mode_policy_vpd(rp, len, op, jap);
3046 }
3047 break;
3048 case VPD_SCSI_PORTS: /* 0x88 ["sp"] */
3049 np = "SCSI Ports VPD page";
3050 if (!op->do_raw && (op->do_hex < 3))
3051 sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3052 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3053 if (res)
3054 break;
3055 if (op->do_raw)
3056 dStrRaw((const char *)rp, len);
3057 else {
3058 if (as_json) {
3059 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3060 jap = sgj_named_subarray_r(jsp, jo2p,
3061 "scsi_ports_descriptor_list");
3062 }
3063 decode_scsi_ports_vpd_4inq(rp, len, op, jap);
3064 }
3065 break;
3066 case VPD_ATA_INFO: /* 0x89 ["ai"] */
3067 np = "ATA information VPD page";
3068 if (!op->do_raw && (op->do_hex < 3))
3069 sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3070 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3071 if (res)
3072 break;
3073 /* format output for 'hdparm --Istdin' with '-rr' or '-HHH' */
3074 if ((2 == op->do_raw) || (3 == op->do_hex))
3075 dWordHex((const unsigned short *)(rp + 60), 256, -2,
3076 sg_is_big_endian());
3077 else if (op->do_raw)
3078 dStrRaw((const char *)rp, len);
3079 else {
3080 if (as_json)
3081 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3082 else
3083 op->do_long = true;
3084 decode_ata_info_vpd(rp, len, op, jo2p);
3085 }
3086 break;
3087 case VPD_POWER_CONDITION: /* 0x8a ["pc"] */
3088 np = "Power condition VPD page";
3089 if (!op->do_raw && (op->do_hex < 3))
3090 sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3091 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3092 if (res)
3093 break;
3094 if (op->do_raw)
3095 dStrRaw((const char *)rp, len);
3096 else {
3097 if (as_json)
3098 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3099 decode_power_condition(rp, len, op, jo2p);
3100 }
3101 break;
3102 case VPD_DEVICE_CONSTITUENTS: /* 0x8b ["dc"] */
3103 np = "Device constituents page VPD page";
3104 if (!op->do_raw && (op->do_hex < 3))
3105 sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3106 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3107 if (res)
3108 break;
3109 if (op->do_raw)
3110 dStrRaw((const char *)rp, len);
3111 else {
3112 if (as_json) {
3113 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3114 jap = sgj_named_subarray_r(jsp, jo2p,
3115 "constituent_descriptor_list");
3116 }
3117 decode_dev_constit_vpd(rp, len, op, jap, recurse_vpd_decode);
3118 }
3119 break;
3120 case VPD_CFA_PROFILE_INFO: /* 0x8c ["cfa"] */
3121 np = "CFA profile information VPD page";
3122 if (!op->do_raw && (op->do_hex < 3))
3123 sgj_pr_hr(jsp, "%s:\n", np);
3124 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3125 if (0 == res) {
3126 if (op->do_raw)
3127 dStrRaw((const char *)rp, len);
3128 else {
3129 if (as_json) {
3130 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3131 jap = sgj_named_subarray_r(jsp, jo2p,
3132 "cfa_profile_descriptor_list");
3133 }
3134 decode_cga_profile_vpd(rp, len, op, jap);
3135 }
3136 }
3137 break;
3138 case VPD_POWER_CONSUMPTION: /* 0x8d ["psm"] */
3139 np = "Power consumption VPD page";
3140 if (!op->do_raw && (op->do_hex < 3))
3141 sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3142 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3143 if (res)
3144 break;
3145 if (op->do_raw)
3146 dStrRaw((const char *)rp, len);
3147 else {
3148 if (as_json) {
3149 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3150 jap = sgj_named_subarray_r(jsp, jo2p,
3151 "power_consumption_descriptor_list");
3152 }
3153 decode_power_consumption(rp, len, op, jap);
3154 }
3155 break;
3156 case VPD_3PARTY_COPY: /* 0x8f ["tpc"] */
3157 np = "Third party copy VPD page";
3158 if (!op->do_raw && (op->do_hex < 3))
3159 sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3160 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3161 if (res)
3162 break;
3163 if (op->do_raw)
3164 dStrRaw((const char *)rp, len);
3165 else {
3166 if (as_json) {
3167 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3168 jap = sgj_named_subarray_r(jsp, jo2p,
3169 "third_party_copy_descriptor_list");
3170 }
3171 decode_3party_copy_vpd(rp, len, op, jap);
3172 }
3173 break;
3174 case VPD_PROTO_LU: /* 0x90 ["pslu"] */
3175 np = "Protocol specific logical unit information VPD page";
3176 if (!op->do_raw && (op->do_hex < 3))
3177 sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3178 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3179 if (res)
3180 break;
3181 if (op->do_raw)
3182 dStrRaw((const char *)rp, len);
3183 else {
3184 if (as_json) {
3185 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3186 jap = sgj_named_subarray_r(jsp, jo2p,
3187 "logical_unit_information_descriptor_list");
3188 }
3189 decode_proto_lu_vpd(rp, len, op, jap);
3190 }
3191 break;
3192 case VPD_PROTO_PORT: /* 0x91 ["pspo"] */
3193 np = "Protocol specific port information VPD page";
3194 if (!op->do_raw && (op->do_hex < 3))
3195 sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3196 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3197 if (res)
3198 break;
3199 if (op->do_raw)
3200 dStrRaw((const char *)rp, len);
3201 else {
3202 if (as_json) {
3203 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3204 jap = sgj_named_subarray_r(jsp, jo2p,
3205 "port_information_descriptor_list");
3206 }
3207 decode_proto_port_vpd(rp, len, op, jap);
3208 }
3209 break;
3210 case VPD_SCSI_FEATURE_SETS: /* 0x92 ["sfs"] */
3211 np = "SCSI Feature sets VPD page";
3212 if (!op->do_raw && (op->do_hex < 3))
3213 sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
3214 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3215 if (res)
3216 break;
3217 if (op->do_raw)
3218 dStrRaw((const char *)rp, len);
3219 else {
3220 if (as_json) {
3221 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3222 jap = sgj_named_subarray_r(jsp, jo2p,
3223 "feature_set_code_list");
3224 }
3225 decode_feature_sets_vpd(rp, len, op, jap);
3226 }
3227 break;
3228 case 0xb0: /* VPD pages in B0h to BFh range depend on pdt */
3229 np = NULL;
3230 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3231 if (0 == res) {
3232 bool bl = false;
3233 bool sad = false;
3234 bool oi = false;
3235
3236 ep = "";
3237 if (op->do_raw) {
3238 dStrRaw((const char *)rp, len);
3239 break;
3240 }
3241 pdt = rp[0] & PDT_MASK;
3242 switch (pdt) {
3243 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3244 np = "Block limits VPD page";
3245 ep = "(SBC)";
3246 bl = true;
3247 break;
3248 case PDT_TAPE: case PDT_MCHANGER:
3249 np = "Sequential-access device capabilities VPD page";
3250 ep = "(SSC)";
3251 sad = true;
3252 break;
3253 case PDT_OSD:
3254 np = "OSD information VPD page";
3255 ep = "(OSD)";
3256 oi = true;
3257 break;
3258 default:
3259 np = NULL;
3260 break;
3261 }
3262 if (op->do_hex < 3) {
3263 if (NULL == np)
3264 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3265 else
3266 sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3267 }
3268 if (as_json)
3269 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3270 if (bl)
3271 decode_block_limits_vpd(rp, len, op, jo2p);
3272 else if (sad || oi)
3273 decode_b0_vpd(rp, len, op, jop);
3274 } else if (! op->do_raw)
3275 pr2serr("VPD INQUIRY: page=0xb0\n");
3276 break;
3277 case 0xb1: /* VPD pages in B0h to BFh range depend on pdt */
3278 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3279 if (0 == res) {
3280 bool bdc = false;
3281 static const char * masn =
3282 "Manufactured-assigned serial number VPD page";
3283
3284 if (op->do_raw) {
3285 dStrRaw((const char *)rp, len);
3286 break;
3287 }
3288 pdt = rp[0] & PDT_MASK;
3289 switch (pdt) {
3290 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3291 np = "Block device characteristics VPD page";
3292 ep = "(SBC)";
3293 bdc = true;
3294 break;
3295 case PDT_TAPE: case PDT_MCHANGER:
3296 np = masn;
3297 ep = "(SSC)";
3298 break;
3299 case PDT_OSD:
3300 np = "Security token VPD page";
3301 ep = "(OSD)";
3302 break;
3303 case PDT_ADC:
3304 np = masn;
3305 ep = "(ADC)";
3306 break;
3307 default:
3308 np = NULL;
3309 printf("VPD INQUIRY: page=0x%x, pdt=0x%x\n", 0xb1, pdt);
3310 break;
3311 }
3312 if (op->do_hex < 3) {
3313 if (NULL == np)
3314 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3315 else
3316 sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3317 }
3318 if (as_json)
3319 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3320 if (bdc)
3321 decode_block_dev_ch_vpd(rp, len, op, jo2p);
3322 else
3323 decode_b1_vpd(rp, len, op, jo2p);
3324 } else if (! op->do_raw)
3325 pr2serr("VPD INQUIRY: page=0xb1\n");
3326 break;
3327 case 0xb2: /* VPD pages in B0h to BFh range depend on pdt */
3328 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3329 if (0 == res) {
3330 bool lbpv = false;
3331 bool tas = false;
3332
3333 if (op->do_raw) {
3334 dStrRaw((const char *)rp, len);
3335 break;
3336 }
3337 pdt = rp[0] & PDT_MASK;
3338 switch (pdt) {
3339 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3340 np = "Logical block provisioning VPD page";
3341 ep = "(SBC)";
3342 lbpv = true;
3343 break;
3344 case PDT_TAPE: case PDT_MCHANGER:
3345 np = "TapeAlert supported flags VPD page";
3346 ep = "(SSC)";
3347 tas = true;
3348 break;
3349 default:
3350 np = NULL;
3351 break;
3352 }
3353 if (op->do_hex < 3) {
3354 if (NULL == np)
3355 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3356 else
3357 sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3358 }
3359 if (as_json)
3360 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3361 if (lbpv)
3362 return decode_block_lb_prov_vpd(rp, len, op, jo2p);
3363 else if (tas)
3364 decode_tapealert_supported_vpd(rp, len, op, jo2p);
3365 else
3366 return vpd_mainly_hex(sg_fd, op, NULL, off);
3367 } else if (! op->do_raw)
3368 pr2serr("VPD INQUIRY: page=0xb2\n");
3369 break;
3370 case 0xb3:
3371 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3372 if (0 == res) {
3373 bool ref = false;
3374
3375 if (op->do_raw) {
3376 dStrRaw((const char *)rp, len);
3377 break;
3378 }
3379 pdt = rp[0] & PDT_MASK;
3380 switch (pdt) {
3381 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3382 np = "Referrals VPD page";
3383 ep = "(SBC)";
3384 ref = true;
3385 break;
3386 default:
3387 np = NULL;
3388 break;
3389 }
3390 if (op->do_hex < 3) {
3391 if (NULL == np)
3392 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3393 else
3394 sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3395 }
3396 if (as_json)
3397 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3398 if (ref)
3399 decode_referrals_vpd(rp, len, op, jo2p);
3400 else
3401 decode_b3_vpd(rp, len, op, jo2p);
3402 return 0;
3403 } else if (! op->do_raw)
3404 pr2serr("VPD INQUIRY: page=0xb3\n");
3405 break;
3406 case 0xb4:
3407 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3408 if (0 == res) {
3409 bool sbl = false;
3410 bool dtde = false;
3411
3412 if (op->do_raw) {
3413 dStrRaw((const char *)rp, len);
3414 break;
3415 }
3416 pdt = rp[0] & PDT_MASK;
3417 switch (pdt) {
3418 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3419 np = "Supported block lengths and protection types VPD page";
3420 ep = "(SBC)";
3421 sbl = true;
3422 break;
3423 case PDT_TAPE: case PDT_MCHANGER:
3424 np = "Device transfer data element VPD page";
3425 ep = "(SSC)";
3426 dtde = true;
3427 break;
3428 default:
3429 np = NULL;
3430 break;
3431 }
3432 if (op->do_hex < 3) {
3433 if (NULL == np)
3434 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3435 else
3436 sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3437 }
3438 if (as_json)
3439 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3440 if (sbl) {
3441 if (as_json)
3442 jap = sgj_named_subarray_r(jsp, jo2p, "logical_block_"
3443 "length_and_protection_types_descriptor_list");
3444 decode_sup_block_lens_vpd(rp, len, op, jap);
3445 } else if (dtde) {
3446 if (! jsp->pr_as_json)
3447 hex2stdout(rp + 4, len - 4, 1);
3448 sgj_js_nv_hex_bytes(jsp, jop, "device_transfer_data_element",
3449 rp + 4, len - 4);
3450 } else
3451 return vpd_mainly_hex(sg_fd, op, NULL, off);
3452 return 0;
3453 } else if (! op->do_raw)
3454 pr2serr("VPD INQUIRY: page=0xb4\n");
3455 break;
3456 case 0xb5:
3457 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3458 if (0 == res) {
3459 bool bdce = false;
3460 bool lbp = false;
3461
3462 if (op->do_raw) {
3463 dStrRaw((const char *)rp, len);
3464 break;
3465 }
3466 pdt = rp[0] & PDT_MASK;
3467 switch (pdt) {
3468 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3469 np = "Block device characteristics VPD page";
3470 ep = "(SBC)";
3471 bdce = true;
3472 break;
3473 case PDT_TAPE: case PDT_MCHANGER:
3474 np = "Logical block protection VPD page";
3475 ep = "(SSC)";
3476 lbp = true;
3477 break;
3478 default:
3479 np = NULL;
3480 break;
3481 }
3482 if (op->do_hex < 3) {
3483 if (NULL == np)
3484 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3485 else
3486 sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3487 }
3488 if (as_json)
3489 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3490 if (bdce)
3491 decode_block_dev_char_ext_vpd(rp, len, op, jo2p);
3492 else if (lbp) { /* VPD_LB_PROTECTION 0xb5 ["lbpro"] (SSC) */
3493 if (as_json)
3494 jap = sgj_named_subarray_r(jsp, jo2p,
3495 "logical_block_protection_method_descriptor_list");
3496 decode_lb_protection_vpd(rp, len, op, jap);
3497 } else
3498 return vpd_mainly_hex(sg_fd, op, NULL, off);
3499 return 0;
3500 } else if (! op->do_raw)
3501 pr2serr("VPD INQUIRY: page=0xb5\n");
3502 break;
3503 case 0xb6:
3504 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3505 if (0 == res) {
3506 bool zbdch = false;
3507
3508 if (op->do_raw) {
3509 dStrRaw((const char *)rp, len);
3510 break;
3511 }
3512 pdt = rp[0] & PDT_MASK;
3513 switch (pdt) {
3514 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3515 np = "Zoned block device characteristics VPD page";
3516 ep = "(SBC, ZBC)";
3517 zbdch = true;
3518 break;
3519 default:
3520 np = NULL;
3521 break;
3522 }
3523 if (op->do_hex < 3) {
3524 if (NULL == np)
3525 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3526 else
3527 sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3528 }
3529 if (as_json)
3530 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3531 if (zbdch)
3532 decode_zbdch_vpd(rp, len, op, jo2p);
3533 else
3534 return vpd_mainly_hex(sg_fd, op, NULL, off);
3535 return 0;
3536 } else if (! op->do_raw)
3537 pr2serr("VPD INQUIRY: page=0xb6\n");
3538 break;
3539 case 0xb7:
3540 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3541 if (0 == res) {
3542 bool ble = false;
3543
3544 if (op->do_raw) {
3545 dStrRaw((const char *)rp, len);
3546 break;
3547 }
3548 pdt = rp[0] & PDT_MASK;
3549 switch (pdt) {
3550 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3551 np = "Block limits extension VPD page";
3552 ep = "(SBC)";
3553 ble = true;
3554 break;
3555 default:
3556 np = NULL;
3557 break;
3558 }
3559 if (op->do_hex < 3) {
3560 if (NULL == np)
3561 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3562 else
3563 sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3564 }
3565 if (as_json)
3566 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3567 if (ble)
3568 decode_block_limits_ext_vpd(rp, len, op, jo2p);
3569 else
3570 return vpd_mainly_hex(sg_fd, op, NULL, off);
3571 return 0;
3572 } else if (! op->do_raw)
3573 pr2serr("VPD INQUIRY: page=0xb7\n");
3574 break;
3575 case 0xb8:
3576 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3577 if (0 == res) {
3578 bool fp = false;
3579
3580 if (op->do_raw) {
3581 dStrRaw((const char *)rp, len);
3582 break;
3583 }
3584 pdt = rp[0] & PDT_MASK;
3585 switch (pdt) {
3586 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3587 np = "Format presets VPD page";
3588 ep = "(SBC)";
3589 fp = true;
3590 break;
3591 default:
3592 np = NULL;
3593 break;
3594 }
3595 if (op->do_hex < 3) {
3596 if (NULL == np)
3597 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3598 else
3599 sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3600 }
3601 if (as_json) {
3602 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3603 jap = sgj_named_subarray_r(jsp, jo2p, "format_preset_"
3604 "descriptor_list");
3605 }
3606 if (fp)
3607 decode_format_presets_vpd(rp, len, op, jap);
3608 else
3609 return vpd_mainly_hex(sg_fd, op, NULL, off);
3610 return 0;
3611 } else if (! op->do_raw)
3612 pr2serr("VPD INQUIRY: page=0xb8\n");
3613 break;
3614 case 0xb9:
3615 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3616 if (0 == res) {
3617 bool cpr = false;
3618
3619 if (op->do_raw) {
3620 dStrRaw((const char *)rp, len);
3621 break;
3622 }
3623 pdt = rp[0] & PDT_MASK;
3624 switch (pdt) {
3625 case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
3626 np = "Concurrent positioning LBAs VPD page";
3627 ep = "(SBC)";
3628 cpr = true;
3629 break;
3630 default:
3631 np = NULL;
3632 break;
3633 }
3634 if (op->do_hex < 3) {
3635 if (NULL == np)
3636 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3637 else
3638 sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3639 }
3640 if (as_json) {
3641 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3642 jap = sgj_named_subarray_r(jsp, jo2p, "lba_range_"
3643 "descriptor_list");
3644 }
3645 if (cpr)
3646 decode_con_pos_range_vpd(rp, len, op, jap);
3647 else
3648 return vpd_mainly_hex(sg_fd, op, NULL, off);
3649 return 0;
3650 } else if (! op->do_raw)
3651 pr2serr("VPD INQUIRY: page=0xb8\n");
3652 break;
3653 /* Vendor specific VPD pages (>= 0xc0) */
3654 case VPD_UPR_EMC: /* 0xc0 */
3655 np = "Unit path report VPD page";
3656 ep = "(EMC)";
3657 if (!op->do_raw && (op->do_hex < 3))
3658 sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3659 res = vpd_fetch_page(sg_fd, rp, pn, -1, qt, vb, &len);
3660 if (res)
3661 break;
3662 if (op->do_raw)
3663 dStrRaw((const char *)rp, len);
3664 else {
3665 if (as_json)
3666 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3667 decode_upr_vpd_c0_emc(rp, len, op, jo2p);
3668 }
3669 break;
3670 case VPD_RDAC_VERS: /* 0xc2 */
3671 np = "Software Version VPD page";
3672 ep = "(RDAC)";
3673 if (!op->do_raw && (op->do_hex < 3))
3674 sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3675 res = vpd_fetch_page(sg_fd, rp, pn, -1, qt, vb, &len);
3676 if (res)
3677 break;
3678 if (op->do_raw)
3679 dStrRaw((const char *)rp, len);
3680 else {
3681 if (as_json)
3682 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3683 decode_rdac_vpd_c2(rp, len, op, jo2p);
3684 }
3685 break;
3686 case VPD_RDAC_VAC: /* 0xc9 */
3687 np = "Volume access control VPD page";
3688 ep = "(RDAC)";
3689 if (!op->do_raw && (op->do_hex < 3))
3690 sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3691 res = vpd_fetch_page(sg_fd, rp, pn, -1, qt, vb, &len);
3692 if (res)
3693 break;
3694 if (op->do_raw)
3695 dStrRaw((const char *)rp, len);
3696 else {
3697 if (as_json)
3698 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3699 decode_rdac_vpd_c9(rp, len, op, jo2p);
3700 }
3701 break;
3702 case SG_NVME_VPD_NICR: /* 0xde */
3703 np = "NVMe Identify Controller Response VPD page";
3704 /* NVMe: Identify Controller data structure (CNS 01h) */
3705 ep = "(sg3_utils)";
3706 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3707 if (res) {
3708 sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3709 break;
3710 }
3711 if (op->do_raw) {
3712 dStrRaw((const char *)rp, len);
3713 break;
3714 }
3715 pdt = rp[0] & PDT_MASK;
3716 if (op->do_hex < 3) {
3717 if (NULL == np)
3718 sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
3719 else
3720 sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
3721 }
3722 if (len < 16) {
3723 pr2serr("%s expected to be > 15 bytes long (got: %d)\n", ep, len);
3724 break;
3725 } else {
3726 int n = len - 16;
3727
3728 if (n > 4096) {
3729 pr2serr("NVMe Identify response expected to be <= 4096 "
3730 "bytes (got: %d)\n", n);
3731 break;
3732 }
3733 if (op->do_hex)
3734 hex2stdout(rp, len, no_ascii_4hex(op));
3735 else if (as_json) {
3736 jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
3737 sgj_js_nv_hex_bytes(jsp, jo2p, "response_bytes", rp + 16, n);
3738 } else
3739 hex2stdout(rp + 16, n, 1);
3740 }
3741 break;
3742 default:
3743 bad = true;
3744 break;
3745 }
3746 if (bad) {
3747 if ((pn > 0) && (pn < 0x80)) {
3748 if (!op->do_raw && (op->do_hex < 3))
3749 printf("VPD INQUIRY: ASCII information page, FRU code=0x%x\n",
3750 pn);
3751 res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
3752 if (0 == res) {
3753 if (op->do_raw)
3754 dStrRaw((const char *)rp, len);
3755 else
3756 decode_ascii_inf(rp, len, op);
3757 }
3758 } else {
3759 if (op->do_hex < 3)
3760 pr2serr(" Only hex output supported.\n");
3761 return vpd_mainly_hex(sg_fd, op, NULL, off);
3762 }
3763 }
3764 out:
3765 if (res) {
3766 char b[80];
3767
3768 if (SG_LIB_CAT_ILLEGAL_REQ == res)
3769 pr2serr(" inquiry: field in cdb illegal (page not "
3770 "supported)\n");
3771 else {
3772 sg_get_category_sense_str(res, sizeof(b), b, vb);
3773 pr2serr(" inquiry: %s\n", b);
3774 }
3775 }
3776 return res;
3777 }
3778
3779 #if (HAVE_NVME && (! IGNORE_NVME))
3780
3781 static void
nvme_hex_raw(const uint8_t * b,int b_len,const struct opts_t * op)3782 nvme_hex_raw(const uint8_t * b, int b_len, const struct opts_t * op)
3783 {
3784 if (op->do_raw)
3785 dStrRaw((const char *)b, b_len);
3786 else if (op->do_hex) {
3787 if (op->do_hex < 3) {
3788 printf("data_in buffer:\n");
3789 hex2stdout(b, b_len, (2 == op->do_hex));
3790 } else
3791 hex2stdout(b, b_len, -1);
3792 }
3793 }
3794
3795 static const char * rperf[] = {"Best", "Better", "Good", "Degraded"};
3796
3797 static void
show_nvme_id_ns(const uint8_t * dinp,int do_long)3798 show_nvme_id_ns(const uint8_t * dinp, int do_long)
3799 {
3800 bool got_eui_128 = false;
3801 uint32_t u, k, off, num_lbaf, flbas, flba_info, md_size, lb_size;
3802 uint64_t ns_sz, eui_64;
3803
3804 num_lbaf = dinp[25] + 1; /* spec says this is "0's based value" */
3805 flbas = dinp[26] & 0xf; /* index of active LBA format (for this ns) */
3806 ns_sz = sg_get_unaligned_le64(dinp + 0);
3807 eui_64 = sg_get_unaligned_be64(dinp + 120); /* N.B. big endian */
3808 if (! sg_all_zeros(dinp + 104, 16))
3809 got_eui_128 = true;
3810 printf(" Namespace size/capacity: %" PRIu64 "/%" PRIu64
3811 " blocks\n", ns_sz, sg_get_unaligned_le64(dinp + 8));
3812 printf(" Namespace utilization: %" PRIu64 " blocks\n",
3813 sg_get_unaligned_le64(dinp + 16));
3814 if (got_eui_128) { /* N.B. big endian */
3815 printf(" NGUID: 0x%02x", dinp[104]);
3816 for (k = 1; k < 16; ++k)
3817 printf("%02x", dinp[104 + k]);
3818 printf("\n");
3819 } else if (do_long)
3820 printf(" NGUID: 0x0\n");
3821 if (eui_64)
3822 printf(" EUI-64: 0x%" PRIx64 "\n", eui_64); /* N.B. big endian */
3823 printf(" Number of LBA formats: %u\n", num_lbaf);
3824 printf(" Index LBA size: %u\n", flbas);
3825 for (k = 0, off = 128; k < num_lbaf; ++k, off += 4) {
3826 printf(" LBA format %u support:", k);
3827 if (k == flbas)
3828 printf(" <-- active\n");
3829 else
3830 printf("\n");
3831 flba_info = sg_get_unaligned_le32(dinp + off);
3832 md_size = flba_info & 0xffff;
3833 lb_size = flba_info >> 16 & 0xff;
3834 if (lb_size > 31) {
3835 pr2serr("%s: logical block size exponent of %u implies a LB "
3836 "size larger than 4 billion bytes, ignore\n", __func__,
3837 lb_size);
3838 continue;
3839 }
3840 lb_size = 1U << lb_size;
3841 ns_sz *= lb_size;
3842 ns_sz /= 500*1000*1000;
3843 if (ns_sz & 0x1)
3844 ns_sz = (ns_sz / 2) + 1;
3845 else
3846 ns_sz = ns_sz / 2;
3847 u = (flba_info >> 24) & 0x3;
3848 printf(" Logical block size: %u bytes\n", lb_size);
3849 printf(" Approximate namespace size: %" PRIu64 " GB\n", ns_sz);
3850 printf(" Metadata size: %u bytes\n", md_size);
3851 printf(" Relative performance: %s [0x%x]\n", rperf[u], u);
3852 }
3853 }
3854
3855 /* Send Identify(CNS=0, nsid) and decode the Identify namespace response */
3856 static int
nvme_id_namespace(struct sg_pt_base * ptvp,uint32_t nsid,struct sg_nvme_passthru_cmd * id_cmdp,uint8_t * id_dinp,int id_din_len,const struct opts_t * op)3857 nvme_id_namespace(struct sg_pt_base * ptvp, uint32_t nsid,
3858 struct sg_nvme_passthru_cmd * id_cmdp, uint8_t * id_dinp,
3859 int id_din_len, const struct opts_t * op)
3860 {
3861 int ret = 0;
3862 int vb = op->verbose;
3863 uint8_t resp[16];
3864
3865 clear_scsi_pt_obj(ptvp);
3866 id_cmdp->nsid = nsid;
3867 id_cmdp->cdw10 = 0x0; /* CNS=0x0 Identify NS (CNTID=0) */
3868 id_cmdp->cdw11 = 0x0; /* NVMSETID=0 (only valid when CNS=0x4) */
3869 id_cmdp->cdw14 = 0x0; /* UUID index (assume not supported) */
3870 set_scsi_pt_data_in(ptvp, id_dinp, id_din_len);
3871 set_scsi_pt_sense(ptvp, resp, sizeof(resp));
3872 set_scsi_pt_cdb(ptvp, (const uint8_t *)id_cmdp, sizeof(*id_cmdp));
3873 ret = do_scsi_pt(ptvp, -1, 0 /* timeout (def: 1 min) */, vb);
3874 if (vb > 2)
3875 pr2serr("%s: do_scsi_pt() result is %d\n", __func__, ret);
3876 if (ret) {
3877 if (SCSI_PT_DO_BAD_PARAMS == ret)
3878 ret = SG_LIB_SYNTAX_ERROR;
3879 else if (SCSI_PT_DO_TIMEOUT == ret)
3880 ret = SG_LIB_CAT_TIMEOUT;
3881 else if (ret < 0)
3882 ret = sg_convert_errno(-ret);
3883 return ret;
3884 }
3885 if (op->do_hex || op->do_raw) {
3886 nvme_hex_raw(id_dinp, id_din_len, op);
3887 return 0;
3888 }
3889 show_nvme_id_ns(id_dinp, op->do_long);
3890 return 0;
3891 }
3892
3893 static void
show_nvme_id_ctrl(const uint8_t * dinp,const char * dev_name,int do_long)3894 show_nvme_id_ctrl(const uint8_t *dinp, const char *dev_name, int do_long)
3895 {
3896 bool got_fguid;
3897 uint8_t ver_min, ver_ter, mtds;
3898 uint16_t ver_maj, oacs, oncs;
3899 uint32_t k, ver, max_nsid, npss, j, n, m;
3900 uint64_t sz1, sz2;
3901 const uint8_t * up;
3902
3903 max_nsid = sg_get_unaligned_le32(dinp + 516); /* NN */
3904 printf("Identify controller for %s:\n", dev_name);
3905 printf(" Model number: %.40s\n", (const char *)(dinp + 24));
3906 printf(" Serial number: %.20s\n", (const char *)(dinp + 4));
3907 printf(" Firmware revision: %.8s\n", (const char *)(dinp + 64));
3908 ver = sg_get_unaligned_le32(dinp + 80);
3909 ver_maj = (ver >> 16);
3910 ver_min = (ver >> 8) & 0xff;
3911 ver_ter = (ver & 0xff);
3912 printf(" Version: %u.%u", ver_maj, ver_min);
3913 if ((ver_maj > 1) || ((1 == ver_maj) && (ver_min > 2)) ||
3914 ((1 == ver_maj) && (2 == ver_min) && (ver_ter > 0)))
3915 printf(".%u\n", ver_ter);
3916 else
3917 printf("\n");
3918 oacs = sg_get_unaligned_le16(dinp + 256);
3919 if (0x1ff & oacs) {
3920 printf(" Optional admin command support:\n");
3921 if (0x200 & oacs)
3922 printf(" Get LBA status\n"); /* NVMe 1.4 */
3923 if (0x100 & oacs)
3924 printf(" Doorbell buffer config\n");
3925 if (0x80 & oacs)
3926 printf(" Virtualization management\n");
3927 if (0x40 & oacs)
3928 printf(" NVMe-MI send and NVMe-MI receive\n");
3929 if (0x20 & oacs)
3930 printf(" Directive send and directive receive\n");
3931 if (0x10 & oacs)
3932 printf(" Device self-test\n");
3933 if (0x8 & oacs)
3934 printf(" Namespace management and attachment\n");
3935 if (0x4 & oacs)
3936 printf(" Firmware download and commit\n");
3937 if (0x2 & oacs)
3938 printf(" Format NVM\n");
3939 if (0x1 & oacs)
3940 printf(" Security send and receive\n");
3941 } else
3942 printf(" No optional admin command support\n");
3943 oncs = sg_get_unaligned_le16(dinp + 256);
3944 if (0x7f & oncs) {
3945 printf(" Optional NVM command support:\n");
3946 if (0x80 & oncs)
3947 printf(" Verify\n"); /* NVMe 1.4 */
3948 if (0x40 & oncs)
3949 printf(" Timestamp feature\n");
3950 if (0x20 & oncs)
3951 printf(" Reservations\n");
3952 if (0x10 & oncs)
3953 printf(" Save and Select fields non-zero\n");
3954 if (0x8 & oncs)
3955 printf(" Write zeroes\n");
3956 if (0x4 & oncs)
3957 printf(" Dataset management\n");
3958 if (0x2 & oncs)
3959 printf(" Write uncorrectable\n");
3960 if (0x1 & oncs)
3961 printf(" Compare\n");
3962 } else
3963 printf(" No optional NVM command support\n");
3964 printf(" PCI vendor ID VID/SSVID: 0x%x/0x%x\n",
3965 sg_get_unaligned_le16(dinp + 0),
3966 sg_get_unaligned_le16(dinp + 2));
3967 printf(" IEEE OUI Identifier: 0x%x\n", /* this has been renamed AOI */
3968 sg_get_unaligned_le24(dinp + 73));
3969 got_fguid = ! sg_all_zeros(dinp + 112, 16);
3970 if (got_fguid) {
3971 printf(" FGUID: 0x%02x", dinp[112]);
3972 for (k = 1; k < 16; ++k)
3973 printf("%02x", dinp[112 + k]);
3974 printf("\n");
3975 } else if (do_long)
3976 printf(" FGUID: 0x0\n");
3977 printf(" Controller ID: 0x%x\n", sg_get_unaligned_le16(dinp + 78));
3978 if (do_long) { /* Bytes 240 to 255 are reserved for NVME-MI */
3979 printf(" NVMe Management Interface [MI] settings:\n");
3980 printf(" Enclosure: %d [NVMEE]\n", !! (0x2 & dinp[253]));
3981 printf(" NVMe Storage device: %d [NVMESD]\n",
3982 !! (0x1 & dinp[253]));
3983 printf(" Management endpoint capabilities, over a PCIe port: %d "
3984 "[PCIEME]\n",
3985 !! (0x2 & dinp[255]));
3986 printf(" Management endpoint capabilities, over a SMBus/I2C port: "
3987 "%d [SMBUSME]\n", !! (0x1 & dinp[255]));
3988 }
3989 printf(" Number of namespaces: %u\n", max_nsid);
3990 sz1 = sg_get_unaligned_le64(dinp + 280); /* lower 64 bits */
3991 sz2 = sg_get_unaligned_le64(dinp + 288); /* upper 64 bits */
3992 if (sz2)
3993 printf(" Total NVM capacity: huge ...\n");
3994 else if (sz1)
3995 printf(" Total NVM capacity: %" PRIu64 " bytes\n", sz1);
3996 mtds = dinp[77];
3997 printf(" Maximum data transfer size: ");
3998 if (mtds)
3999 printf("%u pages\n", 1U << mtds);
4000 else
4001 printf("<unlimited>\n");
4002
4003 if (do_long) {
4004 const char * const non_op = "does not process I/O";
4005 const char * const operat = "processes I/O";
4006 const char * cp;
4007
4008 printf(" Total NVM capacity: 0 bytes\n");
4009 npss = dinp[263] + 1;
4010 up = dinp + 2048;
4011 for (k = 0; k < npss; ++k, up += 32) {
4012 n = sg_get_unaligned_le16(up + 0);
4013 n *= (0x1 & up[3]) ? 1 : 100; /* unit: 100 microWatts */
4014 j = n / 10; /* unit: 1 milliWatts */
4015 m = j % 1000;
4016 j /= 1000;
4017 cp = (0x2 & up[3]) ? non_op : operat;
4018 printf(" Power state %u: Max power: ", k);
4019 if (0 == j) {
4020 m = n % 10;
4021 n /= 10;
4022 printf("%u.%u milliWatts, %s\n", n, m, cp);
4023 } else
4024 printf("%u.%03u Watts, %s\n", j, m, cp);
4025 n = sg_get_unaligned_le32(up + 4);
4026 if (0 == n)
4027 printf(" [ENLAT], ");
4028 else
4029 printf(" ENLAT=%u, ", n);
4030 n = sg_get_unaligned_le32(up + 8);
4031 if (0 == n)
4032 printf("[EXLAT], ");
4033 else
4034 printf("EXLAT=%u, ", n);
4035 n = 0x1f & up[12];
4036 printf("RRT=%u, ", n);
4037 n = 0x1f & up[13];
4038 printf("RRL=%u, ", n);
4039 n = 0x1f & up[14];
4040 printf("RWT=%u, ", n);
4041 n = 0x1f & up[15];
4042 printf("RWL=%u\n", n);
4043 }
4044 }
4045 }
4046
4047 /* Send a NVMe Identify(CNS=1) and decode Controller info. If the
4048 * device name includes a namespace indication (e.g. /dev/nvme0ns1) then
4049 * an Identify namespace command is sent to that namespace (e.g. 1). If the
4050 * device name does not contain a namespace indication (e.g. /dev/nvme0)
4051 * and --only is not given then nvme_id_namespace() is sent for each
4052 * namespace in the controller. Namespaces number sequentially starting at
4053 * 1 . The CNS (Controller or Namespace Structure) field is CDW10 7:0, was
4054 * only bit 0 in NVMe 1.0 and bits 1:0 in NVMe 1.1, thereafter 8 bits. */
4055 static int
do_nvme_identify_ctrl(int pt_fd,const struct opts_t * op)4056 do_nvme_identify_ctrl(int pt_fd, const struct opts_t * op)
4057 {
4058 int ret = 0;
4059 int vb = op->verbose;
4060 uint32_t k, nsid, max_nsid;
4061 struct sg_pt_base * ptvp;
4062 struct sg_nvme_passthru_cmd identify_cmd;
4063 struct sg_nvme_passthru_cmd * id_cmdp = &identify_cmd;
4064 uint8_t * id_dinp = NULL;
4065 uint8_t * free_id_dinp = NULL;
4066 const uint32_t pg_sz = sg_get_page_size();
4067 uint8_t resp[16];
4068
4069 if (op->do_raw) {
4070 if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
4071 perror("sg_set_binary_mode");
4072 return SG_LIB_FILE_ERROR;
4073 }
4074 }
4075 ptvp = construct_scsi_pt_obj_with_fd(pt_fd, vb);
4076 if (NULL == ptvp) {
4077 pr2serr("%s: memory problem\n", __func__);
4078 return sg_convert_errno(ENOMEM);
4079 }
4080 memset(id_cmdp, 0, sizeof(*id_cmdp));
4081 id_cmdp->opcode = 0x6;
4082 nsid = get_pt_nvme_nsid(ptvp);
4083 id_cmdp->cdw10 = 0x1; /* CNS=0x1 --> Identify controller */
4084 /* id_cmdp->nsid is a "don't care" when CNS=1, so leave as 0 */
4085 id_dinp = sg_memalign(pg_sz, pg_sz, &free_id_dinp, false);
4086 if (NULL == id_dinp) {
4087 pr2serr("%s: sg_memalign problem\n", __func__);
4088 return sg_convert_errno(ENOMEM);
4089 }
4090 set_scsi_pt_data_in(ptvp, id_dinp, pg_sz);
4091 set_scsi_pt_cdb(ptvp, (const uint8_t *)id_cmdp, sizeof(*id_cmdp));
4092 set_scsi_pt_sense(ptvp, resp, sizeof(resp));
4093 ret = do_scsi_pt(ptvp, -1, 0 /* timeout (def: 1 min) */, vb);
4094 if (vb > 2)
4095 pr2serr("%s: do_scsi_pt result is %d\n", __func__, ret);
4096 if (ret) {
4097 if (SCSI_PT_DO_BAD_PARAMS == ret)
4098 ret = SG_LIB_SYNTAX_ERROR;
4099 else if (SCSI_PT_DO_TIMEOUT == ret)
4100 ret = SG_LIB_CAT_TIMEOUT;
4101 else if (ret < 0)
4102 ret = sg_convert_errno(-ret);
4103 goto err_out;
4104 }
4105 max_nsid = sg_get_unaligned_le32(id_dinp + 516); /* NN */
4106 if (op->do_raw || op->do_hex) {
4107 if (op->do_only || (SG_NVME_CTL_NSID == nsid ) ||
4108 (SG_NVME_BROADCAST_NSID == nsid)) {
4109 nvme_hex_raw(id_dinp, pg_sz, op);
4110 goto fini;
4111 }
4112 goto skip1;
4113 }
4114 show_nvme_id_ctrl(id_dinp, op->device_name, op->do_long);
4115 skip1:
4116 if (op->do_only)
4117 goto fini;
4118 if (nsid > 0) {
4119 if (! (op->do_raw || (op->do_hex > 2))) {
4120 printf(" Namespace %u (deduced from device name):\n", nsid);
4121 if (nsid > max_nsid)
4122 pr2serr("NSID from device (%u) should not exceed number of "
4123 "namespaces (%u)\n", nsid, max_nsid);
4124 }
4125 ret = nvme_id_namespace(ptvp, nsid, id_cmdp, id_dinp, pg_sz, op);
4126 if (ret)
4127 goto err_out;
4128
4129 } else { /* nsid=0 so char device; loop over all namespaces */
4130 for (k = 1; k <= max_nsid; ++k) {
4131 if ((! op->do_raw) || (op->do_hex < 3))
4132 printf(" Namespace %u (of %u):\n", k, max_nsid);
4133 ret = nvme_id_namespace(ptvp, k, id_cmdp, id_dinp, pg_sz, op);
4134 if (ret)
4135 goto err_out;
4136 if (op->do_raw || op->do_hex)
4137 goto fini;
4138 }
4139 }
4140 fini:
4141 ret = 0;
4142 err_out:
4143 destruct_scsi_pt_obj(ptvp);
4144 free(free_id_dinp);
4145 return ret;
4146 }
4147 #endif /* (HAVE_NVME && (! IGNORE_NVME)) */
4148
4149
4150 int
main(int argc,char * argv[])4151 main(int argc, char * argv[])
4152 {
4153 bool as_json;
4154 int res, n, err;
4155 int sg_fd = -1;
4156 int ret = 0;
4157 int subvalue = 0;
4158 int inhex_len = 0;
4159 int inraw_len = 0;
4160 const char * cp;
4161 const struct svpd_values_name_t * vnp;
4162 sgj_state * jsp;
4163 sgj_opaque_p jop = NULL;
4164 struct opts_t opts SG_C_CPP_ZERO_INIT;
4165 struct opts_t * op;
4166
4167 op = &opts;
4168 op->invoker = SG_VPD_INV_SG_INQ;
4169 op->vpd_pn = -1;
4170 op->vend_prod_num = -1;
4171 op->page_pdt = -1;
4172 op->do_block = -1; /* use default for OS */
4173 res = parse_cmd_line(op, argc, argv);
4174 if (res)
4175 return SG_LIB_SYNTAX_ERROR;
4176 if (op->do_help) {
4177 usage_for(op);
4178 if (op->do_help > 1) {
4179 pr2serr("\n>>> Available VPD page abbreviations:\n");
4180 enumerate_vpds();
4181 }
4182 return 0;
4183 }
4184
4185 #ifdef DEBUG
4186 pr2serr("In DEBUG mode, ");
4187 if (op->verbose_given && op->version_given) {
4188 pr2serr("but override: '-vV' given, zero verbose and continue\n");
4189 op->verbose_given = false;
4190 op->version_given = false;
4191 op->verbose = 0;
4192 } else if (! op->verbose_given) {
4193 pr2serr("set '-vv'\n");
4194 op->verbose = 2;
4195 } else
4196 pr2serr("keep verbose=%d\n", op->verbose);
4197 #else
4198 if (op->verbose_given && op->version_given)
4199 pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
4200 #endif
4201 if (op->version_given) {
4202 pr2serr("Version string: %s\n", version_str);
4203 return 0;
4204 }
4205 jsp = &op->json_st;
4206 as_json = jsp->pr_as_json;
4207 if (op->page_str) {
4208 if (op->vpd_pn >= 0) {
4209 pr2serr("Given '-p' option and another option that "
4210 "implies a page\n");
4211 return SG_LIB_CONTRADICT;
4212 }
4213 if ('-' == op->page_str[0])
4214 op->vpd_pn = VPD_NOPE_WANT_STD_INQ;
4215 else if (isalpha((uint8_t)op->page_str[0])) {
4216 vnp = sdp_find_vpd_by_acron(op->page_str);
4217 if (NULL == vnp) {
4218 #ifdef SG_SCSI_STRINGS
4219 if (op->opt_new)
4220 pr2serr("abbreviation %s given to '--page=' "
4221 "not recognized\n", op->page_str);
4222 else
4223 pr2serr("abbreviation %s given to '-p=' "
4224 "not recognized\n", op->page_str);
4225 #else
4226 pr2serr("abbreviation %s given to '--page=' "
4227 "not recognized\n", op->page_str);
4228 #endif
4229 pr2serr(">>> Available abbreviations:\n");
4230 enumerate_vpds();
4231 return SG_LIB_SYNTAX_ERROR;
4232 }
4233 // if ((1 != op->do_hex) && (0 == op->do_raw))
4234 if (0 == op->do_raw)
4235 op->do_decode = true;
4236 op->vpd_pn = vnp->value;
4237 subvalue = vnp->subvalue;
4238 op->page_pdt = vnp->pdt;
4239 } else {
4240 cp = strchr(op->page_str, ',');
4241 if (cp && op->vend_prod) {
4242 pr2serr("the --page=pg,vp and the --vendor=vp forms overlap, "
4243 "choose one or the other\n");
4244 ret = SG_LIB_SYNTAX_ERROR;
4245 goto err_out;
4246 }
4247 op->vpd_pn = sg_get_num_nomult(op->page_str);
4248 if ((op->vpd_pn < 0) || (op->vpd_pn > 255)) {
4249 pr2serr("Bad page code value after '-p' option\n");
4250 printf("Available standard VPD pages:\n");
4251 enumerate_vpds(/* 1, 1 */);
4252 ret = SG_LIB_SYNTAX_ERROR;
4253 goto err_out;
4254 }
4255 if (cp) {
4256 if (isdigit((uint8_t)*(cp + 1)))
4257 op->vend_prod_num = sg_get_num_nomult(cp + 1);
4258 else
4259 op->vend_prod_num = svpd_find_vp_num_by_acron(cp + 1);
4260 if ((op->vend_prod_num < 0) || (op->vend_prod_num > 255)) {
4261 pr2serr("Bad vendor/product acronym after comma in '-p' "
4262 "option\n");
4263 if (op->vend_prod_num < 0)
4264 svpd_enumerate_vendor(-1);
4265 ret = SG_LIB_SYNTAX_ERROR;
4266 goto err_out;
4267 }
4268 subvalue = op->vend_prod_num;
4269 } else if (op->vend_prod) {
4270 if (isdigit((uint8_t)op->vend_prod[0]))
4271 op->vend_prod_num = sg_get_num_nomult(op->vend_prod);
4272 else
4273 op->vend_prod_num =
4274 svpd_find_vp_num_by_acron(op->vend_prod);
4275 if ((op->vend_prod_num < 0) || (op->vend_prod_num > 255)) {
4276 pr2serr("Bad vendor/product acronym after '--vendor=' "
4277 "option\n");
4278 svpd_enumerate_vendor(-1);
4279 ret = SG_LIB_SYNTAX_ERROR;
4280 goto err_out;
4281 }
4282 subvalue = op->vend_prod_num;
4283 }
4284 }
4285 if (op->verbose > 3)
4286 pr2serr("'--page=' matched pn=%d [0x%x], subvalue=%d\n",
4287 op->vpd_pn, op->vpd_pn, subvalue);
4288 #if 0
4289 else {
4290 #ifdef SG_SCSI_STRINGS
4291 if (op->opt_new) {
4292 n = sg_get_num(op->page_str);
4293 if ((n < 0) || (n > 255)) {
4294 pr2serr("Bad argument to '--page=', "
4295 "expecting 0 to 255 inclusive\n");
4296 usage_for(op);
4297 return SG_LIB_SYNTAX_ERROR;
4298 }
4299 if ((1 != op->do_hex) && (0 == op->do_raw))
4300 op->do_decode = true;
4301 } else {
4302 int num;
4303 unsigned int u;
4304
4305 num = sscanf(op->page_str, "%x", &u);
4306 if ((1 != num) || (u > 255)) {
4307 pr2serr("Inappropriate value after '-o=' "
4308 "or '-p=' option\n");
4309 usage_for(op);
4310 return SG_LIB_SYNTAX_ERROR;
4311 }
4312 n = u;
4313 }
4314 #else
4315 n = sg_get_num(op->page_str);
4316 if ((n < 0) || (n > 255)) {
4317 pr2serr("Bad argument to '--page=', "
4318 "expecting 0 to 255 inclusive\n");
4319 usage_for(op);
4320 return SG_LIB_SYNTAX_ERROR;
4321 }
4322 if ((1 != op->do_hex) && (0 == op->do_raw))
4323 op->do_decode = true;
4324 #endif /* SG_SCSI_STRINGS */
4325 op->vpd_pn = n;
4326 }
4327 #endif
4328 } else if (op->vend_prod) {
4329 if (isdigit((uint8_t)op->vend_prod[0]))
4330 op->vend_prod_num = sg_get_num_nomult(op->vend_prod);
4331 else
4332 op->vend_prod_num = svpd_find_vp_num_by_acron(op->vend_prod);
4333 if ((op->vend_prod_num < 0) || (op->vend_prod_num > 255)) {
4334 pr2serr("Bad vendor/product acronym after '--vendor=' "
4335 "option\n");
4336 svpd_enumerate_vendor(-1);
4337 ret = SG_LIB_SYNTAX_ERROR;
4338 goto err_out;
4339 }
4340 subvalue = op->vend_prod_num;
4341 }
4342 if (as_json)
4343 jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp);
4344
4345 rsp_buff = sg_memalign(rsp_buff_sz, 0 /* page align */, &free_rsp_buff,
4346 false);
4347 if (NULL == rsp_buff) {
4348 pr2serr("Unable to allocate %d bytes on heap\n", rsp_buff_sz);
4349 return sg_convert_errno(ENOMEM);
4350 }
4351 if (op->sinq_inraw_fn) {
4352 if (op->do_cmddt) {
4353 pr2serr("Don't support --cmddt with --sinq-inraw= option\n");
4354 ret = SG_LIB_CONTRADICT;
4355 goto err_out;
4356 }
4357 if ((ret = sg_f2hex_arr(op->sinq_inraw_fn, true, false, rsp_buff,
4358 &inraw_len, rsp_buff_sz))) {
4359 goto err_out;
4360 }
4361 if (inraw_len < 36) {
4362 pr2serr("Unable to read 36 or more bytes from %s\n",
4363 op->sinq_inraw_fn);
4364 ret = SG_LIB_FILE_ERROR;
4365 goto err_out;
4366 }
4367 memcpy(op->std_inq_a, rsp_buff, 36);
4368 op->std_inq_a_valid = true;
4369 }
4370 if (op->inhex_fn) {
4371 if (op->device_name) {
4372 pr2serr("Cannot have both a DEVICE and --inhex= option\n");
4373 ret = SG_LIB_CONTRADICT;
4374 goto err_out;
4375 }
4376 if (op->do_cmddt) {
4377 pr2serr("Don't support --cmddt with --inhex= option\n");
4378 ret = SG_LIB_CONTRADICT;
4379 goto err_out;
4380 }
4381 err = sg_f2hex_arr(op->inhex_fn, !!op->do_raw, false, rsp_buff,
4382 &inhex_len, rsp_buff_sz);
4383 if (err) {
4384 if (err < 0)
4385 err = sg_convert_errno(-err);
4386 ret = err;
4387 goto err_out;
4388 }
4389 op->do_raw = 0; /* don't want raw on output with --inhex= */
4390 if (-1 == op->vpd_pn) { /* may be able to deduce VPD page */
4391 if (op->page_pdt < 0)
4392 op->page_pdt = PDT_MASK & rsp_buff[0];
4393 if ((0x2 == (0xf & rsp_buff[3])) && (rsp_buff[2] > 2)) {
4394 if (op->verbose)
4395 pr2serr("Guessing from --inhex= this is a standard "
4396 "INQUIRY\n");
4397 } else if (rsp_buff[2] <= 2) {
4398 /*
4399 * Removable devices have the RMB bit set, which would
4400 * present itself as vpd page 0x80 output if we're not
4401 * careful
4402 *
4403 * Serial number must be right-aligned ASCII data in
4404 * bytes 5-7; standard INQUIRY will have flags here.
4405 */
4406 if (rsp_buff[1] == 0x80 &&
4407 (rsp_buff[5] < 0x20 || rsp_buff[5] > 0x80 ||
4408 rsp_buff[6] < 0x20 || rsp_buff[6] > 0x80 ||
4409 rsp_buff[7] < 0x20 || rsp_buff[7] > 0x80)) {
4410 if (op->verbose)
4411 pr2serr("Guessing from --inhex= this is a "
4412 "standard INQUIRY\n");
4413 } else {
4414 if (op->verbose)
4415 pr2serr("Guessing from --inhex= this is VPD "
4416 "page 0x%x\n", rsp_buff[1]);
4417 op->vpd_pn = rsp_buff[1];
4418 op->do_vpd = true;
4419 if ((1 != op->do_hex) && (0 == op->do_raw))
4420 op->do_decode = true;
4421 }
4422 } else {
4423 if (op->verbose)
4424 pr2serr("page number unclear from --inhex, hope it's a "
4425 "standard INQUIRY\n");
4426 }
4427 } else
4428 op->do_vpd = true;
4429 if (op->do_vpd) { /* Allow for multiple VPD pages from 'sg_vpd -a' */
4430 op->maxlen = inhex_len;
4431 ret = svpd_inhex_decode_all(op, jop);
4432 goto fini2;
4433 }
4434 } else if (0 == op->device_name) {
4435 pr2serr("No DEVICE argument given\n\n");
4436 usage_for(op);
4437 ret = SG_LIB_SYNTAX_ERROR;
4438 goto err_out;
4439 }
4440 if (VPD_NOPE_WANT_STD_INQ == op->vpd_pn)
4441 op->vpd_pn = -1; /* now past guessing, set to normal indication */
4442
4443 if (op->do_export) {
4444 if (op->vpd_pn != -1) {
4445 if (op->vpd_pn != VPD_DEVICE_ID &&
4446 op->vpd_pn != VPD_UNIT_SERIAL_NUM) {
4447 pr2serr("Option '--export' only supported for VPD pages 0x80 "
4448 "and 0x83\n");
4449 usage_for(op);
4450 ret = SG_LIB_CONTRADICT;
4451 goto err_out;
4452 }
4453 op->do_decode = true;
4454 op->do_vpd = true;
4455 }
4456 }
4457
4458 if ((0 == op->do_cmddt) && (op->vpd_pn >= 0) && op->page_given)
4459 op->do_vpd = true;
4460
4461 if (op->do_raw && op->do_hex) {
4462 pr2serr("Can't do hex and raw at the same time\n");
4463 usage_for(op);
4464 ret = SG_LIB_CONTRADICT;
4465 goto err_out;
4466 }
4467 if (op->do_vpd && op->do_cmddt) {
4468 #ifdef SG_SCSI_STRINGS
4469 if (op->opt_new)
4470 pr2serr("Can't use '--cmddt' with VPD pages\n");
4471 else
4472 pr2serr("Can't have both '-e' and '-c' (or '-cl')\n");
4473 #else
4474 pr2serr("Can't use '--cmddt' with VPD pages\n");
4475 #endif
4476 usage_for(op);
4477 ret = SG_LIB_CONTRADICT;
4478 goto err_out;
4479 }
4480 if (((op->do_vpd || op->do_cmddt)) && (op->vpd_pn < 0))
4481 op->vpd_pn = 0;
4482 if (op->num_pages > 1) {
4483 pr2serr("Can only fetch one page (VPD or Cmd) at a time\n");
4484 usage_for(op);
4485 ret = SG_LIB_SYNTAX_ERROR;
4486 goto err_out;
4487 }
4488 if (op->do_descriptors) {
4489 if ((op->maxlen > 0) && (op->maxlen < 60)) {
4490 pr2serr("version descriptors need INQUIRY response "
4491 "length >= 60 bytes\n");
4492 ret = SG_LIB_SYNTAX_ERROR;
4493 goto err_out;
4494 }
4495 if (op->do_vpd || op->do_cmddt) {
4496 pr2serr("version descriptors require standard INQUIRY\n");
4497 ret = SG_LIB_SYNTAX_ERROR;
4498 goto err_out;
4499 }
4500 }
4501 if (op->num_pages && op->do_ata) {
4502 pr2serr("Can't use '-A' with an explicit decode VPD page option\n");
4503 ret = SG_LIB_CONTRADICT;
4504 goto err_out;
4505 }
4506
4507 if (op->do_raw) {
4508 if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
4509 perror("sg_set_binary_mode");
4510 ret = SG_LIB_FILE_ERROR;
4511 goto err_out;
4512 }
4513 }
4514 if (op->inhex_fn) {
4515 if (op->do_vpd) {
4516 if (op->do_decode)
4517 ret = vpd_decode(-1, op, jop, 0);
4518 else
4519 ret = vpd_mainly_hex(-1, op, NULL, 0);
4520 goto err_out;
4521 }
4522 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
4523 defined(HDIO_GET_IDENTITY)
4524 else if (op->do_ata) {
4525 prepare_ata_identify(op, inhex_len);
4526 ret = 0;
4527 goto err_out;
4528 }
4529 #endif
4530 else {
4531 op->maxlen = inhex_len;
4532 ret = std_inq_process(-1, op, jop, 0);
4533 goto err_out;
4534 }
4535 }
4536
4537 #if defined(O_NONBLOCK) && defined(O_RDONLY)
4538 if (op->do_block >= 0) {
4539 n = O_RDONLY | (op->do_block ? 0 : O_NONBLOCK);
4540 if ((sg_fd = sg_cmds_open_flags(op->device_name, n,
4541 op->verbose)) < 0) {
4542 pr2serr("sg_inq: error opening file: %s: %s\n",
4543 op->device_name, safe_strerror(-sg_fd));
4544 ret = sg_convert_errno(-sg_fd);
4545 if (ret < 0)
4546 ret = SG_LIB_FILE_ERROR;
4547 goto err_out;
4548 }
4549
4550 } else {
4551 if ((sg_fd = sg_cmds_open_device(op->device_name, true /* ro */,
4552 op->verbose)) < 0) {
4553 pr2serr("sg_inq: error opening file: %s: %s\n",
4554 op->device_name, safe_strerror(-sg_fd));
4555 ret = sg_convert_errno(-sg_fd);
4556 if (ret < 0)
4557 ret = SG_LIB_FILE_ERROR;
4558 goto err_out;
4559 }
4560 }
4561 #else
4562 if ((sg_fd = sg_cmds_open_device(op->device_name, true /* ro */,
4563 op->verbose)) < 0) {
4564 pr2serr("sg_inq: error opening file: %s: %s\n",
4565 op->device_name, safe_strerror(-sg_fd));
4566 ret = sg_convert_errno(-sg_fd);
4567 if (ret < 0)
4568 ret = SG_LIB_FILE_ERROR;
4569 goto err_out;
4570 }
4571 #endif
4572 memset(rsp_buff, 0, rsp_buff_sz);
4573
4574 #if (HAVE_NVME && (! IGNORE_NVME))
4575 n = check_pt_file_handle(sg_fd, op->device_name, op->verbose);
4576 if (op->verbose > 1)
4577 pr2serr("check_pt_file_handle()-->%d, page_given: %s\n", n,
4578 (op->page_given ? "yes" : "no"));
4579 if (n > 2) { /* NVMe char or NVMe block */
4580 op->possible_nvme = true;
4581 if (! op->page_given) {
4582 ret = do_nvme_identify_ctrl(sg_fd, op);
4583 goto fini2;
4584 }
4585 }
4586 #endif
4587
4588 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
4589 defined(HDIO_GET_IDENTITY)
4590 if (op->do_ata) {
4591 res = try_ata_identify(sg_fd, op->do_hex, op->do_raw,
4592 op->verbose);
4593 if (0 != res) {
4594 pr2serr("fetching ATA information failed on %s\n",
4595 op->device_name);
4596 ret = SG_LIB_CAT_OTHER;
4597 } else
4598 ret = 0;
4599 goto fini3;
4600 }
4601 #endif
4602
4603 if ((! op->do_cmddt) && (! op->do_vpd)) {
4604 /* So it's a standard INQUIRY, try ATA IDENTIFY if that fails */
4605 ret = std_inq_process(sg_fd, op, jop, 0);
4606 if (ret)
4607 goto err_out;
4608 } else if (op->do_cmddt) {
4609 if (op->vpd_pn < 0)
4610 op->vpd_pn = 0;
4611 ret = cmddt_process(sg_fd, op);
4612 if (ret)
4613 goto err_out;
4614 } else if (op->do_vpd) {
4615 if (op->do_decode) {
4616 ret = vpd_decode(sg_fd, op, jop, 0);
4617 if (ret)
4618 goto err_out;
4619 } else {
4620 ret = vpd_mainly_hex(sg_fd, op, NULL, 0);
4621 if (ret)
4622 goto err_out;
4623 }
4624 }
4625
4626 #if (HAVE_NVME && (! IGNORE_NVME))
4627 fini2:
4628 #endif
4629 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
4630 defined(HDIO_GET_IDENTITY)
4631 fini3:
4632 #endif
4633
4634 err_out:
4635 if (free_rsp_buff)
4636 free(free_rsp_buff);
4637 if ((0 == op->verbose) && (! op->do_export)) {
4638 if (! sg_if_can2stderr("sg_inq failed: ", ret))
4639 pr2serr("Some error occurred, try again with '-v' or '-vv' for "
4640 "more information\n");
4641 }
4642 res = (sg_fd >= 0) ? sg_cmds_close_device(sg_fd) : 0;
4643 if (res < 0) {
4644 pr2serr("close error: %s\n", safe_strerror(-res));
4645 if (0 == ret)
4646 ret = sg_convert_errno(-res);
4647 }
4648 ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
4649 if (as_json) {
4650 if (0 == op->do_hex)
4651 sgj_js2file(jsp, NULL, ret, stdout);
4652 sgj_finish(jsp);
4653 }
4654 return ret;
4655 }
4656
4657
4658 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
4659 defined(HDIO_GET_IDENTITY)
4660 /* Following code permits ATA IDENTIFY commands to be performed on
4661 ATA non "Packet Interface" devices (e.g. ATA disks).
4662 GPL-ed code borrowed from smartmontools (smartmontools.sf.net).
4663 Copyright (C) 2002-4 Bruce Allen
4664 <[email protected]>
4665 */
4666 #ifndef ATA_IDENTIFY_DEVICE
4667 #define ATA_IDENTIFY_DEVICE 0xec
4668 #define ATA_IDENTIFY_PACKET_DEVICE 0xa1
4669 #endif
4670 #ifndef HDIO_DRIVE_CMD
4671 #define HDIO_DRIVE_CMD 0x031f
4672 #endif
4673
4674 /* Needed parts of the ATA DRIVE IDENTIFY Structure. Those labeled
4675 * word* are NOT used.
4676 */
4677 struct ata_identify_device {
4678 unsigned short words000_009[10];
4679 uint8_t serial_no[20];
4680 unsigned short words020_022[3];
4681 uint8_t fw_rev[8];
4682 uint8_t model[40];
4683 unsigned short words047_079[33];
4684 unsigned short major_rev_num;
4685 unsigned short minor_rev_num;
4686 unsigned short command_set_1;
4687 unsigned short command_set_2;
4688 unsigned short command_set_extension;
4689 unsigned short cfs_enable_1;
4690 unsigned short word086;
4691 unsigned short csf_default;
4692 unsigned short words088_255[168];
4693 };
4694
4695 #define ATA_IDENTIFY_BUFF_SZ sizeof(struct ata_identify_device)
4696 #define HDIO_DRIVE_CMD_OFFSET 4
4697
4698 static int
ata_command_interface(int device,char * data,bool * atapi_flag,int verbose)4699 ata_command_interface(int device, char *data, bool * atapi_flag, int verbose)
4700 {
4701 int err;
4702 uint8_t buff[ATA_IDENTIFY_BUFF_SZ + HDIO_DRIVE_CMD_OFFSET];
4703 unsigned short get_ident[256];
4704
4705 if (atapi_flag)
4706 *atapi_flag = false;
4707 memset(buff, 0, sizeof(buff));
4708 if (ioctl(device, HDIO_GET_IDENTITY, &get_ident) < 0) {
4709 err = errno;
4710 if (ENOTTY == err) {
4711 if (verbose > 1)
4712 pr2serr("HDIO_GET_IDENTITY failed with ENOTTY, "
4713 "try HDIO_DRIVE_CMD ioctl ...\n");
4714 buff[0] = ATA_IDENTIFY_DEVICE;
4715 buff[3] = 1;
4716 if (ioctl(device, HDIO_DRIVE_CMD, buff) < 0) {
4717 if (verbose)
4718 pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) "
4719 "ioctl failed:\n\t%s [%d]\n",
4720 safe_strerror(err), err);
4721 return sg_convert_errno(err);
4722 }
4723 memcpy(data, buff + HDIO_DRIVE_CMD_OFFSET, ATA_IDENTIFY_BUFF_SZ);
4724 return 0;
4725 } else {
4726 if (verbose)
4727 pr2serr("HDIO_GET_IDENTITY ioctl failed:\n"
4728 "\t%s [%d]\n", safe_strerror(err), err);
4729 return sg_convert_errno(err);
4730 }
4731 } else if (verbose > 1)
4732 pr2serr("HDIO_GET_IDENTITY succeeded\n");
4733 if (0x2 == ((get_ident[0] >> 14) &0x3)) { /* ATAPI device */
4734 if (verbose > 1)
4735 pr2serr("assume ATAPI device from HDIO_GET_IDENTITY response\n");
4736 memset(buff, 0, sizeof(buff));
4737 buff[0] = ATA_IDENTIFY_PACKET_DEVICE;
4738 buff[3] = 1;
4739 if (ioctl(device, HDIO_DRIVE_CMD, buff) < 0) {
4740 err = errno;
4741 if (verbose)
4742 pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_PACKET_DEVICE) ioctl "
4743 "failed:\n\t%s [%d]\n", safe_strerror(err), err);
4744 buff[0] = ATA_IDENTIFY_DEVICE;
4745 buff[3] = 1;
4746 if (ioctl(device, HDIO_DRIVE_CMD, buff) < 0) {
4747 err = errno;
4748 if (verbose)
4749 pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) ioctl "
4750 "failed:\n\t%s [%d]\n", safe_strerror(err), err);
4751 return sg_convert_errno(err);
4752 }
4753 } else if (atapi_flag) {
4754 *atapi_flag = true;
4755 if (verbose > 1)
4756 pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) succeeded\n");
4757 }
4758 } else { /* assume non-packet device */
4759 buff[0] = ATA_IDENTIFY_DEVICE;
4760 buff[3] = 1;
4761 if (ioctl(device, HDIO_DRIVE_CMD, buff) < 0) {
4762 err = errno;
4763 if (verbose)
4764 pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) ioctl failed:"
4765 "\n\t%s [%d]\n", safe_strerror(err), err);
4766 return sg_convert_errno(err);
4767 } else if (verbose > 1)
4768 pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) succeeded\n");
4769 }
4770 /* if the command returns data, copy it back */
4771 memcpy(data, buff + HDIO_DRIVE_CMD_OFFSET, ATA_IDENTIFY_BUFF_SZ);
4772 return 0;
4773 }
4774
4775 static void
show_ata_identify(const struct ata_identify_device * aidp,bool atapi,int vb)4776 show_ata_identify(const struct ata_identify_device * aidp, bool atapi,
4777 int vb)
4778 {
4779 int res;
4780 char model[64];
4781 char serial[64];
4782 char firm[64];
4783
4784 printf("%s device: model, serial number and firmware revision:\n",
4785 (atapi ? "ATAPI" : "ATA"));
4786 res = sg_ata_get_chars((const unsigned short *)aidp->model,
4787 0, 20, sg_is_big_endian(), model);
4788 model[res] = '\0';
4789 res = sg_ata_get_chars((const unsigned short *)aidp->serial_no,
4790 0, 10, sg_is_big_endian(), serial);
4791 serial[res] = '\0';
4792 res = sg_ata_get_chars((const unsigned short *)aidp->fw_rev,
4793 0, 4, sg_is_big_endian(), firm);
4794 firm[res] = '\0';
4795 printf(" %s %s %s\n", model, serial, firm);
4796 if (vb) {
4797 if (atapi)
4798 printf("ATA IDENTIFY PACKET DEVICE response "
4799 "(256 words):\n");
4800 else
4801 printf("ATA IDENTIFY DEVICE response (256 words):\n");
4802 dWordHex((const unsigned short *)aidp, 256, 0,
4803 sg_is_big_endian());
4804 }
4805 }
4806
4807 static void
prepare_ata_identify(const struct opts_t * op,int inhex_len)4808 prepare_ata_identify(const struct opts_t * op, int inhex_len)
4809 {
4810 int n = inhex_len;
4811 struct ata_identify_device ata_ident;
4812
4813 if (n < 16) {
4814 pr2serr("%s: got only %d bytes, give up\n", __func__, n);
4815 return;
4816 } else if (n < 512)
4817 pr2serr("%s: expect 512 bytes or more, got %d, continue\n", __func__,
4818 n);
4819 else if (n > 512)
4820 n = 512;
4821 memset(&ata_ident, 0, sizeof(ata_ident));
4822 memcpy(&ata_ident, rsp_buff, n);
4823 show_ata_identify(&ata_ident, false, op->verbose);
4824 }
4825
4826 /* Returns 0 if successful, else errno of error */
4827 static int
try_ata_identify(int ata_fd,int do_hex,int do_raw,int verbose)4828 try_ata_identify(int ata_fd, int do_hex, int do_raw, int verbose)
4829 {
4830 bool atapi;
4831 int res;
4832 struct ata_identify_device ata_ident;
4833
4834 memset(&ata_ident, 0, sizeof(ata_ident));
4835 res = ata_command_interface(ata_fd, (char *)&ata_ident, &atapi, verbose);
4836 if (res)
4837 return res;
4838 if ((2 == do_raw) || (3 == do_hex))
4839 dWordHex((const unsigned short *)&ata_ident, 256, -2,
4840 sg_is_big_endian());
4841 else if (do_raw)
4842 dStrRaw((const char *)&ata_ident, 512);
4843 else {
4844 if (do_hex) {
4845 if (atapi)
4846 printf("ATA IDENTIFY PACKET DEVICE response ");
4847 else
4848 printf("ATA IDENTIFY DEVICE response ");
4849 if (do_hex > 1) {
4850 printf("(512 bytes):\n");
4851 hex2stdout((const uint8_t *)&ata_ident, 512, 0);
4852 } else {
4853 printf("(256 words):\n");
4854 dWordHex((const unsigned short *)&ata_ident, 256, 0,
4855 sg_is_big_endian());
4856 }
4857 } else
4858 show_ata_identify(&ata_ident, atapi, verbose);
4859 }
4860 return 0;
4861 }
4862 #endif
4863
4864 /* structure defined in sg_lib_data.h */
4865 extern struct sg_lib_simple_value_name_t sg_version_descriptor_arr[];
4866
4867
4868 static const char *
find_version_descriptor_str(int value)4869 find_version_descriptor_str(int value)
4870 {
4871 int k;
4872 const struct sg_lib_simple_value_name_t * vdp;
4873
4874 for (k = 0; ((vdp = sg_version_descriptor_arr + k) && vdp->name); ++k) {
4875 if (value == vdp->value)
4876 return vdp->name;
4877 if (value < vdp->value)
4878 break;
4879 }
4880 return NULL;
4881 }
4882