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 LOG SENSE command
11 * and in some cases issues a LOG SELECT command.
12 *
13 */
14
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <stdarg.h>
20 #include <stdbool.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include <getopt.h>
24 #define __STDC_FORMAT_MACROS 1
25 #include <inttypes.h>
26 #include <errno.h>
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 #include "sg_lib.h"
32 #include "sg_lib_names.h"
33 #include "sg_cmds_basic.h"
34 #ifdef SG_LIB_WIN32
35 #include "sg_pt.h" /* needed for scsi_pt_win32_direct() */
36 #endif
37 #include "sg_unaligned.h"
38 #include "sg_pr2serr.h"
39
40 static const char * version_str = "2.08 20221112"; /* spc6r06 + sbc5r03 */
41
42 #define MY_NAME "sg_logs"
43
44 #define MX_ALLOC_LEN (0xfffc)
45 #define MX_INLEN_ALLOC_LEN (0x800000)
46 #define DEF_INLEN_ALLOC_LEN (0x40000)
47 #define SHORT_RESP_LEN 128
48
49 #define SUPP_PAGES_LPAGE 0x0
50 #define BUFF_OVER_UNDER_LPAGE 0x1
51 #define WRITE_ERR_LPAGE 0x2
52 #define READ_ERR_LPAGE 0x3
53 #define READ_REV_ERR_LPAGE 0x4
54 #define VERIFY_ERR_LPAGE 0x5
55 #define NON_MEDIUM_LPAGE 0x6
56 #define LAST_N_ERR_LPAGE 0x7
57 #define FORMAT_STATUS_LPAGE 0x8
58 #define LAST_N_DEFERRED_LPAGE 0xb
59 #define LB_PROV_LPAGE 0xc
60 #define TEMPERATURE_LPAGE 0xd
61 #define START_STOP_LPAGE 0xe
62 #define APP_CLIENT_LPAGE 0xf
63 #define SELF_TEST_LPAGE 0x10
64 #define SOLID_STATE_MEDIA_LPAGE 0x11
65 #define REQ_RECOVERY_LPAGE 0x13
66 #define DEVICE_STATS_LPAGE 0x14
67 #define BACKGROUND_SCAN_LPAGE 0x15
68 #define SAT_ATA_RESULTS_LPAGE 0x16
69 #define PROTO_SPECIFIC_LPAGE 0x18
70 #define STATS_LPAGE 0x19
71 #define PCT_LPAGE 0x1a
72 #define TAPE_ALERT_LPAGE 0x2e
73 #define IE_LPAGE 0x2f
74 #define NOT_SPG_SUBPG 0x0 /* any page: no subpages */
75 #define SUPP_SPGS_SUBPG 0xff /* all subpages of ... */
76 #define PENDING_DEFECTS_SUBPG 0x1 /* page 0x15 */
77 #define BACKGROUND_OP_SUBPG 0x2 /* page 0x15 */
78 #define CACHE_STATS_SUBPG 0x20 /* page 0x19 */
79 #define CMD_DUR_LIMITS_SUBPG 0x21 /* page 0x19 */
80 #define ENV_REPORTING_SUBPG 0x1 /* page 0xd */
81 #define UTILIZATION_SUBPG 0x1 /* page 0xe */
82 #define ENV_LIMITS_SUBPG 0x2 /* page 0xd */
83 #define LPS_MISALIGNMENT_SUBPG 0x3 /* page 0x15 */
84 #define ZONED_BLOCK_DEV_STATS_SUBPG 0x1 /* page 0x14 */
85 #define LAST_N_INQUIRY_DATA_CH_SUBPG 0x1 /* page 0xb */
86 #define LAST_N_MODE_PG_DATA_CH_SUBPG 0x2 /* page 0xb */
87
88 /* Vendor product numbers/identifiers */
89 #define VP_NONE (-1)
90 #define VP_SEAG 0
91 #define VP_HITA 1
92 #define VP_TOSH 2
93 #define VP_LTO5 3
94 #define VP_LTO6 4
95 #define VP_ALL 99
96
97 #define MVP_OFFSET 8
98
99 /* Vendor product masks
100 * MVP_STD OR-ed with MVP_<vendor> is a T10 defined lpage with vendor
101 * specific parameter codes (e.g. Information Exceptions lpage [0x2f]) */
102 #define MVP_STD (1 << (MVP_OFFSET - 1))
103 #define MVP_SEAG (1 << (VP_SEAG + MVP_OFFSET))
104 #define MVP_HITA (1 << (VP_HITA + MVP_OFFSET))
105 #define MVP_TOSH (1 << (VP_TOSH + MVP_OFFSET))
106 #define MVP_LTO5 (1 << (VP_LTO5 + MVP_OFFSET))
107 #define MVP_LTO6 (1 << (VP_LTO6 + MVP_OFFSET))
108
109 #define OVP_LTO (MVP_LTO5 | MVP_LTO6)
110 #define OVP_ALL (~0)
111
112
113 #define PCB_STR_LEN 128
114
115 #define LOG_SENSE_PROBE_ALLOC_LEN 4
116 #define LOG_SENSE_DEF_TIMEOUT 64 /* seconds */
117
118 static uint8_t * rsp_buff;
119 static uint8_t * free_rsp_buff;
120 static int rsp_buff_sz = MX_ALLOC_LEN + 4;
121 static const int parr_sz = 4096;
122
123 static const char * const unknown_s = "unknown";
124 static const char * const not_avail = "not available";
125 static const char * const param_c = "Parameter code";
126 static const char * const param_c_sn = "parameter_code";
127 static const char * const as_s_s = "as_string";
128 static const char * const rstrict_s = "restricted";
129 static const char * const rsv_s = "reserved";
130 static const char * const vend_spec = "vendor specific";
131 static const char * const not_rep = "not reported";
132 static const char * const in_hex = "in hex";
133 static const char * const s_key = "sense key";
134
135 static struct option long_options[] = {
136 {"All", no_argument, 0, 'A'}, /* equivalent to '-aa' */
137 {"ALL", no_argument, 0, 'A'}, /* equivalent to '-aa' */
138 {"all", no_argument, 0, 'a'},
139 {"brief", no_argument, 0, 'b'},
140 {"control", required_argument, 0, 'c'},
141 {"enumerate", no_argument, 0, 'e'},
142 {"exclude", no_argument, 0, 'E'},
143 {"filter", required_argument, 0, 'f'},
144 {"full", no_argument, 0, 'F'},
145 {"help", no_argument, 0, 'h'},
146 {"hex", no_argument, 0, 'H'},
147 {"in", required_argument, 0, 'i'},
148 {"inhex", required_argument, 0, 'i'},
149 {"json", optional_argument, 0, 'j'},
150 {"list", no_argument, 0, 'l'},
151 {"maxlen", required_argument, 0, 'm'},
152 {"name", no_argument, 0, 'n'},
153 {"new", no_argument, 0, 'N'},
154 {"no_inq", no_argument, 0, 'x'},
155 {"no-inq", no_argument, 0, 'x'},
156 {"old", no_argument, 0, 'O'},
157 {"page", required_argument, 0, 'p'},
158 {"paramp", required_argument, 0, 'P'},
159 {"pcb", no_argument, 0, 'q'},
160 {"ppc", no_argument, 0, 'Q'},
161 {"pdt", required_argument, 0, 'D'},
162 {"raw", no_argument, 0, 'r'},
163 {"readonly", no_argument, 0, 'X'},
164 {"reset", no_argument, 0, 'R'},
165 {"sp", no_argument, 0, 's'},
166 {"select", no_argument, 0, 'S'},
167 {"temperature", no_argument, 0, 't'},
168 {"transport", no_argument, 0, 'T'},
169 {"undefined", no_argument, 0, 'u'},
170 {"vendor", required_argument, 0, 'M'},
171 {"verbose", no_argument, 0, 'v'},
172 {"version", no_argument, 0, 'V'},
173 {0, 0, 0, 0},
174 };
175
176 struct opts_t {
177 bool do_full;
178 bool do_name;
179 bool do_pcb;
180 bool do_ppc;
181 bool do_raw;
182 bool do_pcreset;
183 bool do_select;
184 bool do_sp;
185 bool do_temperature;
186 bool do_transport;
187 bool exclude_vendor;
188 bool filter_given;
189 bool maxlen_given;
190 bool o_readonly;
191 bool opt_new;
192 bool verbose_given;
193 bool version_given;
194 int do_all;
195 int do_brief;
196 int do_enumerate;
197 int do_help;
198 int do_hex;
199 int do_list;
200 int dstrhex_no_ascii; /* value for dStrHex() no_ascii argument */
201 int hex2str_oformat; /* value for hex2str() oformat argument */
202 int vend_prod_num; /* one of the VP_* constants or -1 (def) */
203 int deduced_vpn; /* deduced vendor_prod_num; from INQUIRY, etc */
204 int verbose;
205 int filter;
206 int page_control;
207 int maxlen;
208 int pg_code;
209 int subpg_code;
210 int paramp;
211 int no_inq;
212 int dev_pdt; /* from device or --pdt=DT */
213 int decod_subpg_code;
214 int undefined_hex; /* hex format of undefined/unrecognized fields */
215 const char * device_name;
216 const char * in_fn;
217 const char * pg_arg;
218 const char * vend_prod;
219 const struct log_elem * lep;
220 sgj_state json_st;
221 };
222
223
224 struct log_elem {
225 int pg_code;
226 int subpg_code; /* only unless subpg_high>0 then this is only */
227 int subpg_high; /* when >0 this is high end of subpage range */
228 int pdt; /* -1 for all */
229 int flags; /* bit mask; or-ed with MVP_* constants */
230 const char * name;
231 const char * acron;
232 bool (*show_pagep)(const uint8_t * resp, int len,
233 struct opts_t * op, sgj_opaque_p jop);
234 /* Returns true if done */
235 };
236
237 struct vp_name_t {
238 int vend_prod_num; /* vendor/product identifier */
239 const char * acron;
240 const char * name;
241 const char * t10_vendorp;
242 const char * t10_productp;
243 };
244
245 static const char * ls_s = "log_sense: ";
246
247 static bool show_supported_pgs_page(const uint8_t * resp, int len,
248 struct opts_t * op, sgj_opaque_p jop);
249 static bool show_supported_pgs_sub_page(const uint8_t * resp, int len,
250 struct opts_t * op, sgj_opaque_p jop);
251 static bool show_buffer_over_under_run_page(const uint8_t * resp, int len,
252 struct opts_t * op,
253 sgj_opaque_p jop);
254 static bool show_error_counter_page(const uint8_t * resp, int len,
255 struct opts_t * op, sgj_opaque_p jop);
256 static bool show_non_medium_error_page(const uint8_t * resp, int len,
257 struct opts_t * op, sgj_opaque_p jop);
258 static bool show_last_n_error_page(const uint8_t * resp, int len,
259 struct opts_t * op, sgj_opaque_p jop);
260 static bool show_format_status_page(const uint8_t * resp, int len,
261 struct opts_t * op, sgj_opaque_p jop);
262 static bool show_last_n_deferred_error_page(const uint8_t * resp, int len,
263 struct opts_t * op,
264 sgj_opaque_p jop);
265 static bool show_last_n_inq_data_ch_page(const uint8_t * resp, int len,
266 struct opts_t * op,
267 sgj_opaque_p jop);
268 static bool show_last_n_mode_pg_data_ch_page(const uint8_t * resp, int len,
269 struct opts_t * op,
270 sgj_opaque_p jop);
271 static bool show_lb_provisioning_page(const uint8_t * resp, int len,
272 struct opts_t * op, sgj_opaque_p jop);
273 static bool show_sequential_access_page(const uint8_t * resp, int len,
274 struct opts_t * op, sgj_opaque_p jop);
275 static bool show_temperature_page(const uint8_t * resp, int len,
276 struct opts_t * op, sgj_opaque_p jop);
277 static bool show_start_stop_page(const uint8_t * resp, int len,
278 struct opts_t * op, sgj_opaque_p jop);
279 static bool show_utilization_page(const uint8_t * resp, int len,
280 struct opts_t * op, sgj_opaque_p jop);
281 static bool show_app_client_page(const uint8_t * resp, int len,
282 struct opts_t * op, sgj_opaque_p jop);
283 static bool show_self_test_page(const uint8_t * resp, int len,
284 struct opts_t * op, sgj_opaque_p jop);
285 static bool show_solid_state_media_page(const uint8_t * resp, int len,
286 struct opts_t * op, sgj_opaque_p jop);
287 static bool show_device_stats_page(const uint8_t * resp, int len,
288 struct opts_t * op, sgj_opaque_p jop);
289 static bool show_media_stats_page(const uint8_t * resp, int len,
290 struct opts_t * op, sgj_opaque_p jop);
291 static bool show_dt_device_status_page(const uint8_t * resp, int len,
292 struct opts_t * op, sgj_opaque_p jop);
293 static bool show_tapealert_response_page(const uint8_t * resp, int len,
294 struct opts_t * op,
295 sgj_opaque_p jop);
296 static bool show_requested_recovery_page(const uint8_t * resp, int len,
297 struct opts_t * op,
298 sgj_opaque_p jop);
299 static bool show_background_scan_results_page(const uint8_t * resp, int len,
300 struct opts_t * op,
301 sgj_opaque_p jop);
302 static bool show_zoned_block_dev_stats(const uint8_t * resp, int len,
303 struct opts_t * op, sgj_opaque_p jop);
304 static bool show_pending_defects_page(const uint8_t * resp, int len,
305 struct opts_t * op, sgj_opaque_p jop);
306 static bool show_background_op_page(const uint8_t * resp, int len,
307 struct opts_t * op, sgj_opaque_p jop);
308 static bool show_lps_misalignment_page(const uint8_t * resp, int len,
309 struct opts_t * op, sgj_opaque_p jop);
310 static bool show_element_stats_page(const uint8_t * resp, int len,
311 struct opts_t * op, sgj_opaque_p jop);
312 static bool show_service_buffer_info_page(const uint8_t * resp, int len,
313 struct opts_t * op,
314 sgj_opaque_p jop);
315 static bool show_ata_pt_results_page(const uint8_t * resp, int len,
316 struct opts_t * op, sgj_opaque_p jop);
317 static bool show_tape_diag_data_page(const uint8_t * resp, int len,
318 struct opts_t * op, sgj_opaque_p jop);
319 static bool show_mchanger_diag_data_page(const uint8_t * resp, int len,
320 struct opts_t * op,
321 sgj_opaque_p jop);
322 static bool show_non_volatile_cache_page(const uint8_t * resp, int len,
323 struct opts_t * op,
324 sgj_opaque_p jop);
325 static bool show_volume_stats_pages(const uint8_t * resp, int len,
326 struct opts_t * op, sgj_opaque_p jop);
327 static bool show_protocol_specific_port_page(const uint8_t * resp, int len,
328 struct opts_t * op,
329 sgj_opaque_p jop);
330 static bool show_stats_perform_pages(const uint8_t * resp, int len,
331 struct opts_t * op, sgj_opaque_p jop);
332 static bool show_cache_stats_page(const uint8_t * resp, int len,
333 struct opts_t * op, sgj_opaque_p jop);
334 static bool show_power_condition_transitions_page(const uint8_t * resp,
335 int len, struct opts_t * op,
336 sgj_opaque_p jop);
337 static bool show_environmental_reporting_page(const uint8_t * resp, int len,
338 struct opts_t * op,
339 sgj_opaque_p jop);
340 static bool show_environmental_limits_page(const uint8_t * resp, int len,
341 struct opts_t * op,
342 sgj_opaque_p jop);
343 static bool show_cmd_dur_limits_page(const uint8_t * resp, int len,
344 struct opts_t * op, sgj_opaque_p jop);
345 static bool show_data_compression_page(const uint8_t * resp, int len,
346 struct opts_t * op, sgj_opaque_p jop);
347 static bool show_tape_alert_ssc_page(const uint8_t * resp, int len,
348 struct opts_t * op, sgj_opaque_p jop);
349 static bool show_ie_page(const uint8_t * resp, int len,
350 struct opts_t * op, sgj_opaque_p jop);
351 static bool show_tape_usage_page(const uint8_t * resp, int len,
352 struct opts_t * op, sgj_opaque_p jop);
353 static bool show_tape_capacity_page(const uint8_t * resp, int len,
354 struct opts_t * op, sgj_opaque_p jop);
355 static bool show_seagate_cache_page(const uint8_t * resp, int len,
356 struct opts_t * op, sgj_opaque_p jop);
357 static bool show_seagate_factory_page(const uint8_t * resp, int len,
358 struct opts_t * op, sgj_opaque_p jop);
359 static bool show_hgst_perf_page(const uint8_t * resp, int len,
360 struct opts_t * op, sgj_opaque_p jop);
361 static bool show_hgst_misc_page(const uint8_t * resp, int len,
362 struct opts_t * op, sgj_opaque_p jop);
363
364 /* elements in page_number/subpage_number order */
365 static struct log_elem log_arr[] = {
366 {SUPP_PAGES_LPAGE, 0, 0, -1, MVP_STD, "Supported log pages", "sp",
367 show_supported_pgs_page}, /* 0, 0 */
368 {SUPP_PAGES_LPAGE, SUPP_SPGS_SUBPG, 0, -1, MVP_STD, "Supported log pages "
369 "and subpages", "ssp", show_supported_pgs_sub_page}, /* 0, 0xff */
370 {BUFF_OVER_UNDER_LPAGE, 0, 0, -1, MVP_STD, "Buffer over-run/under-run",
371 "bou", show_buffer_over_under_run_page}, /* 0x1, 0x0 */
372 {WRITE_ERR_LPAGE, 0, 0, -1, MVP_STD, "Write error counters", "we",
373 show_error_counter_page}, /* 0x2, 0x0 */
374 {READ_ERR_LPAGE, 0, 0, -1, MVP_STD, "Read error counters", "re",
375 show_error_counter_page}, /* 0x3, 0x0 */
376 {READ_REV_ERR_LPAGE, 0, 0, -1, MVP_STD, "Read reverse error counters",
377 "rre", show_error_counter_page}, /* 0x4, 0x0 */
378 {VERIFY_ERR_LPAGE, 0, 0, -1, MVP_STD, "Verify error counters", "ve",
379 show_error_counter_page}, /* 0x5, 0x0 */
380 {NON_MEDIUM_LPAGE, 0, 0, -1, MVP_STD, "Non medium", "nm",
381 show_non_medium_error_page}, /* 0x6, 0x0 */
382 {LAST_N_ERR_LPAGE, 0, 0, -1, MVP_STD, "Last n error", "lne",
383 show_last_n_error_page}, /* 0x7, 0x0 */
384 {FORMAT_STATUS_LPAGE, 0, 0, 0, MVP_STD, "Format status", "fs",
385 show_format_status_page}, /* 0x8, 0x0 SBC */
386 {LAST_N_DEFERRED_LPAGE, 0, 0, -1, MVP_STD, "Last n deferred error", "lnd",
387 show_last_n_deferred_error_page}, /* 0xb, 0x0 */
388 {LAST_N_DEFERRED_LPAGE, LAST_N_INQUIRY_DATA_CH_SUBPG, 0, -1, MVP_STD,
389 "Last n inquiry data changed", "lnic",
390 show_last_n_inq_data_ch_page}, /* 0xb, 0x1 */
391 {LAST_N_DEFERRED_LPAGE, LAST_N_MODE_PG_DATA_CH_SUBPG, 0, -1, MVP_STD,
392 "Last n mode page data changed", "lnmc",
393 show_last_n_mode_pg_data_ch_page}, /* 0xb, 0x2 */
394 {LB_PROV_LPAGE, 0, 0, 0, MVP_STD, "Logical block provisioning", "lbp",
395 show_lb_provisioning_page}, /* 0xc, 0x0 SBC */
396 {0xc, 0, 0, PDT_TAPE, MVP_STD, "Sequential access device", "sad",
397 show_sequential_access_page}, /* 0xc, 0x0 SSC */
398 {TEMPERATURE_LPAGE, 0, 0, -1, MVP_STD, "Temperature", "temp",
399 show_temperature_page}, /* 0xd, 0x0 */
400 {TEMPERATURE_LPAGE, ENV_REPORTING_SUBPG, 0, -1, MVP_STD, /* 0xd, 0x1 */
401 "Environmental reporting", "enr", show_environmental_reporting_page},
402 {TEMPERATURE_LPAGE, ENV_LIMITS_SUBPG, 0, -1, MVP_STD, /* 0xd, 0x2 */
403 "Environmental limits", "enl", show_environmental_limits_page},
404 {START_STOP_LPAGE, 0, 0, -1, MVP_STD, "Start-stop cycle counter", "sscc",
405 show_start_stop_page}, /* 0xe, 0x0 */
406 {START_STOP_LPAGE, UTILIZATION_SUBPG, 0, 0, MVP_STD, "Utilization",
407 "util", show_utilization_page}, /* 0xe, 0x1 SBC */ /* sbc4r04 */
408 {APP_CLIENT_LPAGE, 0, 0, -1, MVP_STD, "Application client", "ac",
409 show_app_client_page}, /* 0xf, 0x0 */
410 {SELF_TEST_LPAGE, 0, 0, -1, MVP_STD, "Self test results", "str",
411 show_self_test_page}, /* 0x10, 0x0 */
412 {SOLID_STATE_MEDIA_LPAGE, 0, 0, 0, MVP_STD, "Solid state media", "ssm",
413 show_solid_state_media_page}, /* 0x11, 0x0 SBC */
414 {0x11, 0, 0, PDT_TAPE, MVP_STD, "DT Device status", "dtds",
415 show_dt_device_status_page}, /* 0x11, 0x0 SSC,ADC */
416 {0x12, 0, 0, PDT_TAPE, MVP_STD, "Tape alert response", "tar",
417 show_tapealert_response_page}, /* 0x12, 0x0 SSC,ADC */
418 {REQ_RECOVERY_LPAGE, 0, 0, PDT_TAPE, MVP_STD, "Requested recovery", "rr",
419 show_requested_recovery_page}, /* 0x13, 0x0 SSC,ADC */
420 {DEVICE_STATS_LPAGE, 0, 0, PDT_TAPE, MVP_STD, "Device statistics", "ds",
421 show_device_stats_page}, /* 0x14, 0x0 SSC,ADC */
422 {DEVICE_STATS_LPAGE, 0, 0, PDT_MCHANGER, MVP_STD, /* 0x14, 0x0 SMC */
423 "Media changer statistics", "mcs", show_media_stats_page},
424 {DEVICE_STATS_LPAGE, ZONED_BLOCK_DEV_STATS_SUBPG, /* 0x14,0x1 zbc2r01 */
425 0, 0, MVP_STD, "Zoned block device statistics", "zbds",
426 show_zoned_block_dev_stats},
427 {BACKGROUND_SCAN_LPAGE, 0, 0, 0, MVP_STD, "Background scan results",
428 "bsr", show_background_scan_results_page}, /* 0x15, 0x0 SBC */
429 {BACKGROUND_SCAN_LPAGE, BACKGROUND_OP_SUBPG, 0, 0, MVP_STD,
430 "Background operation", "bop", show_background_op_page},
431 /* 0x15, 0x2 SBC */
432 {BACKGROUND_SCAN_LPAGE, LPS_MISALIGNMENT_SUBPG, 0, 0, MVP_STD,
433 "LPS misalignment", "lps", show_lps_misalignment_page},
434 /* 0x15, 0x3 SBC-4 */
435 {0x15, 0, 0, PDT_MCHANGER, MVP_STD, "Element statistics", "els",
436 show_element_stats_page}, /* 0x15, 0x0 SMC */
437 {0x15, 0, 0, PDT_ADC, MVP_STD, "Service buffers information", "sbi",
438 show_service_buffer_info_page}, /* 0x15, 0x0 ADC */
439 {BACKGROUND_SCAN_LPAGE, PENDING_DEFECTS_SUBPG, 0, 0, MVP_STD,
440 "Pending defects", "pd", show_pending_defects_page}, /* 0x15, 0x1 SBC */
441 {SAT_ATA_RESULTS_LPAGE, 0, 0, 0, MVP_STD, "ATA pass-through results",
442 "aptr", show_ata_pt_results_page}, /* 0x16, 0x0 SAT */
443 {0x16, 0, 0, PDT_TAPE, MVP_STD, "Tape diagnostic data", "tdd",
444 show_tape_diag_data_page}, /* 0x16, 0x0 SSC */
445 {0x16, 0, 0, PDT_MCHANGER, MVP_STD, "Media changer diagnostic data",
446 "mcdd", show_mchanger_diag_data_page}, /* 0x16, 0x0 SMC */
447 {0x17, 0, 0, 0, MVP_STD, "Non volatile cache", "nvc",
448 show_non_volatile_cache_page}, /* 0x17, 0x0 SBC */
449 {0x17, 0, 0xf, PDT_TAPE, MVP_STD, "Volume statistics", "vs",
450 show_volume_stats_pages}, /* 0x17, 0x0...0xf SSC */
451 {PROTO_SPECIFIC_LPAGE, 0, 0, -1, MVP_STD, "Protocol specific port",
452 "psp", show_protocol_specific_port_page}, /* 0x18, 0x0 */
453 {STATS_LPAGE, 0, 0, -1, MVP_STD, "General Statistics and Performance",
454 "gsp", show_stats_perform_pages}, /* 0x19, 0x0 */
455 {STATS_LPAGE, 0x1, 0x1f, -1, MVP_STD, "Group Statistics and Performance",
456 "grsp", show_stats_perform_pages}, /* 0x19, 0x1...0x1f */
457 {STATS_LPAGE, CACHE_STATS_SUBPG, 0, -1, MVP_STD, /* 0x19, 0x20 */
458 "Cache memory statistics", "cms", show_cache_stats_page},
459 {STATS_LPAGE, CMD_DUR_LIMITS_SUBPG, 0, -1, MVP_STD, /* 0x19, 0x21 */
460 "Command duration limits statistics", "cdl",
461 show_cmd_dur_limits_page /* spc6r01 */ },
462 {PCT_LPAGE, 0, 0, -1, MVP_STD, "Power condition transitions", "pct",
463 show_power_condition_transitions_page}, /* 0x1a, 0 */
464 {0x1b, 0, 0, PDT_TAPE, MVP_STD, "Data compression", "dc",
465 show_data_compression_page}, /* 0x1b, 0 SSC */
466 {0x2d, 0, 0, PDT_TAPE, MVP_STD, "Current service information", "csi",
467 NULL}, /* 0x2d, 0 SSC */
468 {TAPE_ALERT_LPAGE, 0, 0, PDT_TAPE, MVP_STD, "Tape alert", "ta",
469 show_tape_alert_ssc_page}, /* 0x2e, 0 SSC */
470 {IE_LPAGE, 0, 0, -1, (MVP_STD | MVP_HITA),
471 "Informational exceptions", "ie", show_ie_page}, /* 0x2f, 0 */
472 /* vendor specific */
473 {0x30, 0, 0, PDT_DISK, MVP_HITA, "Performance counters (Hitachi)",
474 "pc_hi", show_hgst_perf_page}, /* 0x30, 0 SBC */
475 {0x30, 0, 0, PDT_TAPE, OVP_LTO, "Tape usage (lto-5, 6)", "tu_",
476 show_tape_usage_page}, /* 0x30, 0 SSC */
477 {0x31, 0, 0, PDT_TAPE, OVP_LTO, "Tape capacity (lto-5, 6)",
478 "tc_", show_tape_capacity_page}, /* 0x31, 0 SSC */
479 {0x32, 0, 0, PDT_TAPE, MVP_LTO5, "Data compression (lto-5)",
480 "dc_", show_data_compression_page}, /* 0x32, 0 SSC; redirect to 0x1b */
481 {0x33, 0, 0, PDT_TAPE, MVP_LTO5, "Write errors (lto-5)", "we_",
482 NULL}, /* 0x33, 0 SSC */
483 {0x34, 0, 0, PDT_TAPE, MVP_LTO5, "Read forward errors (lto-5)",
484 "rfe_", NULL}, /* 0x34, 0 SSC */
485 {0x35, 0, 0, PDT_TAPE, OVP_LTO, "DT Device Error (lto-5, 6)",
486 "dtde_", NULL}, /* 0x35, 0 SSC */
487 {0x37, 0, 0, PDT_DISK, MVP_SEAG, "Cache (seagate)", "c_se",
488 show_seagate_cache_page}, /* 0x37, 0 SBC */
489 {0x37, 0, 0, PDT_DISK, MVP_HITA, "Miscellaneous (hitachi)", "mi_hi",
490 show_hgst_misc_page}, /* 0x37, 0 SBC */
491 {0x37, 0, 0, PDT_TAPE, MVP_LTO5, "Performance characteristics "
492 "(lto-5)", "pc_", NULL}, /* 0x37, 0 SSC */
493 {0x38, 0, 0, PDT_TAPE, MVP_LTO5, "Blocks/bytes transferred "
494 "(lto-5)", "bbt_", NULL}, /* 0x38, 0 SSC */
495 {0x39, 0, 0, PDT_TAPE, MVP_LTO5, "Host port 0 interface errors "
496 "(lto-5)", "hp0_", NULL}, /* 0x39, 0 SSC */
497 {0x3a, 0, 0, PDT_TAPE, MVP_LTO5, "Drive control verification "
498 "(lto-5)", "dcv_", NULL}, /* 0x3a, 0 SSC */
499 {0x3b, 0, 0, PDT_TAPE, MVP_LTO5, "Host port 1 interface errors "
500 "(lto-5)", "hp1_", NULL}, /* 0x3b, 0 SSC */
501 {0x3c, 0, 0, PDT_TAPE, MVP_LTO5, "Drive usage information "
502 "(lto-5)", "dui_", NULL}, /* 0x3c, 0 SSC */
503 {0x3d, 0, 0, PDT_TAPE, MVP_LTO5, "Subsystem statistics (lto-5)",
504 "ss_", NULL}, /* 0x3d, 0 SSC */
505 {0x3e, 0, 0, PDT_DISK, MVP_SEAG, "Factory (seagate)", "f_se",
506 show_seagate_factory_page}, /* 0x3e, 0 SBC */
507 {0x3e, 0, 0, PDT_DISK, MVP_HITA, "Factory (hitachi)", "f_hi",
508 NULL}, /* 0x3e, 0 SBC */
509 {0x3e, 0, 0, PDT_TAPE, OVP_LTO, "Device Status (lto-5, 6)",
510 "ds_", NULL}, /* 0x3e, 0 SSC */
511
512 {-1, -1, -1, -1, 0, NULL, "zzzzz", NULL}, /* end sentinel */
513 };
514
515 /* Supported vendor product codes */
516 /* Arrange in alphabetical order by acronym */
517 static struct vp_name_t vp_arr[] = {
518 {VP_SEAG, "sea", "Seagate", "SEAGATE", NULL},
519 {VP_HITA, "hit", "Hitachi", "HGST", NULL},
520 {VP_HITA, "wdc", "WDC/Hitachi", "WDC", NULL},
521 {VP_TOSH, "tos", "Toshiba", "TOSHIBA", NULL},
522 {VP_LTO5, "lto5", "LTO-5 (tape drive consortium)", NULL, NULL},
523 {VP_LTO6, "lto6", "LTO-6 (tape drive consortium)", NULL, NULL},
524 {VP_ALL, "all", "enumerate all vendor specific", NULL, NULL},
525 {0, NULL, NULL, NULL, NULL},
526 };
527
528 static char t10_vendor_str[10];
529 static char t10_product_str[18];
530
531 #ifdef SG_LIB_WIN32
532 static bool win32_spt_init_state = false;
533 static bool win32_spt_curr_state = false;
534 #endif
535
536
537 static void
usage(int hval)538 usage(int hval)
539 {
540 if (1 == hval) {
541 pr2serr(
542 "Usage: sg_logs [-ALL] [--all] [--brief] [--control=PC] "
543 "[--enumerate]\n"
544 " [--exclude] [--filter=FL] [--full] [--help] "
545 "[--hex]\n"
546 " [--in=FN] [--json[=JO]] [--list] [--maxlen=LEN] "
547 "[--name]\n"
548 " [--no_inq] [--page=PG] [--paramp=PP] [--pcb] "
549 "[--ppc]\n"
550 " [--pdt=DT] [--raw] [--readonly] [--reset] "
551 "[--select]\n"
552 " [--sp] [--temperature] [--transport] "
553 "[--undefined]\n"
554 " [--vendor=VP] [--verbose] [--version] DEVICE\n"
555 " where the main options are:\n"
556 " --ALL|-A fetch and decode all log pages and "
557 "subpages\n"
558 " --all|-a fetch and decode all log pages, but not "
559 "subpages; use\n"
560 " twice to fetch and decode all log pages "
561 "and subpages\n"
562 " --brief|-b shorten the output of some log pages\n"
563 " --enumerate|-e enumerate known pages, ignore DEVICE. "
564 "Sort order,\n"
565 " '-e': all by acronym; '-ee': non-vendor "
566 "by acronym;\n"
567 " '-eee': all numerically; '-eeee': "
568 "non-v numerically\n"
569 " --filter=FL|-f FL FL is parameter code to display (def: "
570 "all);\n"
571 " with '-e' then FL>=0 enumerate that "
572 "pdt + spc\n"
573 " FL=-1 all (default), FL=-2 spc only\n"
574 " --full|-F drill down in application client log page\n"
575 " --help|-h print usage message then exit. Use twice "
576 "for more help\n"
577 " --hex|-H output response in hex (default: decode if "
578 "known)\n"
579 " --in=FN|-i FN FN is a filename containing a log page "
580 "in ASCII hex\n"
581 " or binary if --raw also given. --inhex=FN "
582 "also accepted\n"
583 " --json[=JO]|-j[JO] output in JSON instead of human "
584 "readable\n"
585 " test. Use --json=? for JSON help\n"
586 " --list|-l list supported log pages; twice: list "
587 "supported log\n"
588 " pages and subpages page; thrice: merge of "
589 "both pages\n"
590 " --page=PG|-p PG PG is either log page acronym, PGN or "
591 "PGN,SPGN\n"
592 " where (S)PGN is a (sub) page number\n");
593 pr2serr(
594 " --raw|-r either output response in binary to stdout "
595 "or, if\n"
596 " '--in=FN' is given, FN is decoded as "
597 "binary\n"
598 " --temperature|-t decode temperature (log page 0xd or "
599 "0x2f)\n"
600 " --transport|-T decode transport (protocol specific port "
601 "0x18) page\n"
602 " --vendor=VP|-M VP vendor/product abbreviation [or "
603 "number]\n"
604 " --verbose|-v increase verbosity\n\n"
605 "Performs a SCSI LOG SENSE (or LOG SELECT) command and decodes "
606 "the response.\nIf only DEVICE is given then '-p sp' (supported "
607 "pages) is assumed. Use\n'-e' to see known pages and their "
608 "acronyms. For more help use '-hh'.\n");
609 } else if (hval > 1) {
610 pr2serr(
611 " where sg_logs' lesser used options are:\n"
612 " --control=PC|-c PC page control(PC) (default: 1)\n"
613 " 0: current threshold, 1: current "
614 "cumulative\n"
615 " 2: default threshold, 3: default "
616 "cumulative\n"
617 " --exclude|-E exclude vendor specific pages and "
618 "parameters\n"
619 " --list|-l list supported log page names (equivalent to "
620 "'-p sp')\n"
621 " use twice to list supported log page and "
622 "subpage names\n"
623 " --maxlen=LEN|-m LEN max response length (def: 0 "
624 "-> everything)\n"
625 " when > 1 will request LEN bytes\n"
626 " --name|-n decode some pages into multiple name=value "
627 "lines\n"
628 " --no_inq|-x no initial INQUIRY output (twice: and no "
629 "INQUIRY call)\n"
630 " --old|-O use old interface (use as first option)\n"
631 " --paramp=PP|-P PP place PP in parameter pointer field in "
632 "cdb (def: 0)\n"
633 " --pcb|-q show parameter control bytes in decoded "
634 "output\n"
635 " --ppc|-Q set the Parameter Pointer Control (PPC) bit "
636 "(def: 0)\n"
637 " --pdt=DT|-D DT DT is peripheral device type to use with "
638 "'--in=FN'\n"
639 " or when '--no_inq' is used\n"
640 " --readonly|-X open DEVICE read-only (def: first "
641 "read-write then if\n"
642 " fails try open again read-only)\n"
643 " --reset|-R reset log parameters (takes PC and SP into "
644 "account)\n"
645 " (uses PCR bit in LOG SELECT)\n"
646 " --select|-S perform LOG SELECT (def: LOG SENSE)\n"
647 " --sp|-s set the Saving Parameters (SP) bit (def: "
648 "0)\n"
649 " --undefined|-u hex format for undefined/unrecognized "
650 "fields,\n"
651 " use one or more times; format as per "
652 "--hex\n"
653 " --version|-V output version string then exit\n\n"
654 "If DEVICE and --select are given, a LOG SELECT command will be "
655 "issued.\nIf DEVICE is not given and '--in=FN' is given then FN "
656 "will decoded as if\nit were a log page. The contents of FN "
657 "generated by either a prior\n'sg_logs -HHH ...' invocation or "
658 "by a text editor.\nLog pages defined in SPC are common "
659 "to all device types.\n");
660 }
661 }
662
663 static void
usage_old()664 usage_old()
665 {
666 printf("Usage: sg_logs [-a] [-A] [-b] [-c=PC] [-D=DT] [-e] [-E] [-f=FL] "
667 "[-F]\n"
668 " [-h] [-H] [-i=FN] [-l] [-L] [-m=LEN] [-M=VP] "
669 "[-n] [-p=PG]\n"
670 " [-paramp=PP] [-pcb] [-ppc] [-r] [-select] [-sp] "
671 "[-t] [-T]\n"
672 " [-u] [-v] [-V] [-x] [-X] [-?] DEVICE\n"
673 " where:\n"
674 " -a fetch and decode all log pages\n"
675 " -A fetch and decode all log pages and subpages\n"
676 " -b shorten the output of some log pages\n"
677 " -c=PC page control(PC) (default: 1)\n"
678 " 0: current threshold, 1: current cumulative\n"
679 " 2: default threshold, 3: default cumulative\n"
680 " -e enumerate known log pages\n"
681 " -D=DT DT is peripheral device type to use with "
682 "'--in=FN'\n"
683 " -E exclude vendor specific pages and parameters\n"
684 " -f=FL filter match parameter code or pdt\n"
685 " -F drill down in application client log page\n"
686 " -h output in hex (default: decode if known)\n"
687 " -H output in hex (same as '-h')\n"
688 " -i=FN FN is a filename containing a log page "
689 "in ASCII hex.\n"
690 " -l list supported log page names (equivalent to "
691 "'-p=0')\n"
692 " -L list supported log page and subpages names "
693 "(equivalent to\n"
694 " '-p=0,ff')\n"
695 " -m=LEN max response length (decimal) (def: 0 "
696 "-> everything)\n"
697 " -M=VP vendor/product abbreviation [or number]\n"
698 " -n decode some pages into multiple name=value "
699 "lines\n"
700 " -N|--new use new interface\n"
701 " -p=PG PG is an acronym (def: 'sp')\n"
702 " -p=PGN page code in hex (def: 0)\n"
703 " -p=PGN,SPGN page and subpage codes in hex, (defs: 0,0)\n"
704 " -paramp=PP (in hex) (def: 0)\n"
705 " -pcb show parameter control bytes in decoded "
706 "output\n");
707 printf(" -ppc set the Parameter Pointer Control (PPC) bit "
708 "(def: 0)\n"
709 " -r reset log parameters (takes PC and SP into "
710 "account)\n"
711 " (uses PCR bit in LOG SELECT)\n"
712 " -select perform LOG SELECT (def: LOG SENSE)\n"
713 " -sp set the Saving Parameters (SP) bit (def: 0)\n"
714 " -t outputs temperature log page (0xd)\n"
715 " -T outputs transport (protocol specific port) log "
716 "page (0x18)\n"
717 " -u hex format for undefined/unrecognized fields\n"
718 " -v increase verbosity\n"
719 " -V output version string\n"
720 " -x no initial INQUIRY output (twice: no INQUIRY call)\n"
721 " -X open DEVICE read-only (def: first read-write then "
722 "if fails\n"
723 " try open again with read-only)\n"
724 " -? output this usage message\n\n"
725 "Performs a SCSI LOG SENSE (or LOG SELECT) command\n");
726 }
727
728 /* Return vendor product mask given vendor product number */
729 static int
get_vp_mask(int vpn)730 get_vp_mask(int vpn)
731 {
732 if (vpn < 0)
733 return 0;
734 else
735 return (vpn >= (32 - MVP_OFFSET)) ? OVP_ALL :
736 (1 << (vpn + MVP_OFFSET));
737 }
738
739 static int
asort_comp(const void * lp,const void * rp)740 asort_comp(const void * lp, const void * rp)
741 {
742 const struct log_elem * const * lepp =
743 (const struct log_elem * const *)lp;
744 const struct log_elem * const * repp =
745 (const struct log_elem * const *)rp;
746
747 return strcmp((*lepp)->acron, (*repp)->acron);
748 }
749
750 static void
enumerate_helper(const struct log_elem * lep,bool first,const struct opts_t * op)751 enumerate_helper(const struct log_elem * lep, bool first,
752 const struct opts_t * op)
753 {
754 char b[80];
755 char bb[80];
756 const char * cp;
757 bool vendor_lpage = ! (MVP_STD & lep->flags);
758
759 if (first) {
760 if (1 == op->verbose) {
761 printf("acronym pg[,spg] name\n");
762 printf("===============================================\n");
763 } else if (2 == op->verbose) {
764 printf("acronym pg[,spg] pdt name\n");
765 printf("===================================================\n");
766 }
767 }
768 if ((0 == (op->do_enumerate % 2)) && vendor_lpage)
769 return; /* if do_enumerate is even then skip vendor pages */
770 else if ((! op->filter_given) || (-1 == op->filter))
771 ; /* otherwise enumerate all lpages if no --filter= */
772 else if (-2 == op->filter) { /* skip non-SPC pages */
773 if (lep->pdt >= 0)
774 return;
775 } else if (-10 == op->filter) { /* skip non-disk like pages */
776 if (sg_lib_pdt_decay(lep->pdt) != 0)
777 return;
778 } else if (-11 == op->filter) { /* skip tape like device pages */
779 if (sg_lib_pdt_decay(lep->pdt) != 1)
780 return;
781 } else if ((op->filter >= 0) && (op->filter <= 0x1f)) {
782 if ((lep->pdt >= 0) && (lep->pdt != op->filter) &&
783 (lep->pdt != sg_lib_pdt_decay(op->filter)))
784 return;
785 }
786 if (op->vend_prod_num >= 0) {
787 if (! (lep->flags & get_vp_mask(op->vend_prod_num)))
788 return;
789 }
790 if (op->deduced_vpn >= 0) {
791 if (! (lep->flags & get_vp_mask(op->deduced_vpn)))
792 return;
793 }
794 if (lep->subpg_high > 0)
795 snprintf(b, sizeof(b), "0x%x,0x%x->0x%x", lep->pg_code,
796 lep->subpg_code, lep->subpg_high);
797 else if (lep->subpg_code > 0)
798 snprintf(b, sizeof(b), "0x%x,0x%x", lep->pg_code,
799 lep->subpg_code);
800 else
801 snprintf(b, sizeof(b), "0x%x", lep->pg_code);
802 snprintf(bb, sizeof(bb), "%-16s", b);
803 cp = (op->verbose && (! lep->show_pagep)) ? " [hex only]" : "";
804 if (op->verbose > 1) {
805 if (lep->pdt < 0)
806 printf(" %-8s%s- %s%s\n", lep->acron, bb, lep->name, cp);
807 else
808 printf(" %-8s%s0x%02x %s%s\n", lep->acron, bb, lep->pdt,
809 lep->name, cp);
810 } else
811 printf(" %-8s%s%s%s\n", lep->acron, bb, lep->name, cp);
812 }
813
814 static void
enumerate_pages(const struct opts_t * op)815 enumerate_pages(const struct opts_t * op)
816 {
817 int j;
818 struct log_elem * lep;
819 struct log_elem ** lep_arr;
820
821 if (op->do_enumerate < 3) { /* -e, -ee: sort by acronym */
822 int k;
823 struct log_elem ** lepp;
824
825 for (k = 0, lep = log_arr; lep->pg_code >=0; ++lep, ++k)
826 ;
827 ++k;
828 lep_arr = (struct log_elem **)calloc(k, sizeof(struct log_elem *));
829 if (NULL == lep_arr) {
830 pr2serr("%s: out of memory\n", __func__);
831 return;
832 }
833 for (k = 0, lep = log_arr; lep->pg_code >=0; ++lep, ++k)
834 lep_arr[k] = lep;
835 lep_arr[k++] = lep; /* put sentinel on end */
836 qsort(lep_arr, k, sizeof(struct log_elem *), asort_comp);
837 printf("Known log pages in acronym order:\n");
838 for (lepp = lep_arr, j = 0; (*lepp)->pg_code >=0; ++lepp, ++j)
839 enumerate_helper(*lepp, (0 == j), op);
840 free(lep_arr);
841 } else { /* -eee, -eeee numeric sort (as per table) */
842 printf("Known log pages in numerical order:\n");
843 for (lep = log_arr, j = 0; lep->pg_code >=0; ++lep, ++j)
844 enumerate_helper(lep, (0 == j), op);
845 }
846 }
847
848 static const struct log_elem *
acron_search(const char * acron)849 acron_search(const char * acron)
850 {
851 const struct log_elem * lep;
852
853 for (lep = log_arr; lep->pg_code >=0; ++lep) {
854 if (0 == strcmp(acron, lep->acron))
855 return lep;
856 }
857 return NULL;
858 }
859
860 static int
find_vpn_by_acron(const char * vp_ap)861 find_vpn_by_acron(const char * vp_ap)
862 {
863 const struct vp_name_t * vpp;
864
865 for (vpp = vp_arr; vpp->acron; ++vpp) {
866 size_t k;
867 size_t len = strlen(vpp->acron);
868
869 for (k = 0; k < len; ++k) {
870 if (tolower((uint8_t)vp_ap[k]) != (uint8_t)vpp->acron[k])
871 break;
872 }
873 if (k < len)
874 continue;
875 return vpp->vend_prod_num;
876 }
877 return VP_NONE;
878 }
879
880 /* Find vendor product number using T10 VENDOR and PRODUCT ID fields in a
881 INQUIRY response. */
882 static int
find_vpn_by_inquiry(void)883 find_vpn_by_inquiry(void)
884 {
885 size_t len;
886 size_t t10_v_len = strlen(t10_vendor_str);
887 size_t t10_p_len = strlen(t10_product_str);
888 const struct vp_name_t * vpp;
889
890 if ((0 == t10_v_len) && (0 == t10_p_len))
891 return VP_NONE;
892 for (vpp = vp_arr; vpp->acron; ++vpp) {
893 bool matched = false;
894
895 if (vpp->t10_vendorp && (t10_v_len > 0)) {
896 len = strlen(vpp->t10_vendorp);
897 len = (len > t10_v_len) ? t10_v_len : len;
898 if (strncmp(vpp->t10_vendorp, t10_vendor_str, len))
899 continue;
900 matched = true;
901 }
902 if (vpp->t10_productp && (t10_p_len > 0)) {
903 len = strlen(vpp->t10_productp);
904 len = (len > t10_p_len) ? t10_p_len : len;
905 if (strncmp(vpp->t10_productp, t10_product_str, len))
906 continue;
907 matched = true;
908 }
909 if (matched)
910 return vpp->vend_prod_num;
911 }
912 return VP_NONE;
913 }
914
915 static void
enumerate_vp(void)916 enumerate_vp(void)
917 {
918 const struct vp_name_t * vpp;
919 bool seen = false;
920
921 for (vpp = vp_arr; vpp->acron; ++vpp) {
922 if (vpp->name) {
923 if (! seen) {
924 printf("\nVendor/product identifiers:\n");
925 seen = true;
926 }
927 printf(" %-10s %d %s\n", vpp->acron,
928 vpp->vend_prod_num, vpp->name);
929 }
930 }
931 }
932
933 static const struct log_elem *
pg_subpg_pdt_search(int pg_code,int subpg_code,int pdt,int vpn)934 pg_subpg_pdt_search(int pg_code, int subpg_code, int pdt, int vpn)
935 {
936 const struct log_elem * lep;
937 int d_pdt;
938 int vp_mask = get_vp_mask(vpn);
939
940 d_pdt = sg_lib_pdt_decay(pdt);
941 for (lep = log_arr; lep->pg_code >=0; ++lep) {
942 if (pg_code == lep->pg_code) {
943 if (subpg_code == lep->subpg_code) {
944 if ((MVP_STD & lep->flags) || (0 == vp_mask) ||
945 (vp_mask & lep->flags))
946 ;
947 else
948 continue;
949 if ((lep->pdt < 0) || (pdt == lep->pdt) || (pdt < 0))
950 return lep;
951 else if (d_pdt == lep->pdt)
952 return lep;
953 else if (pdt == sg_lib_pdt_decay(lep->pdt))
954 return lep;
955 } else if ((lep->subpg_high > 0) &&
956 (subpg_code > lep->subpg_code) &&
957 (subpg_code <= lep->subpg_high))
958 return lep;
959 }
960 }
961 return NULL;
962 }
963
964 static void
js_snakenv_ihexstr_nex(sgj_state * jsp,sgj_opaque_p jop,const char * conv2sname,int64_t val_i,bool hex_as_well,const char * str_name,const char * val_s,const char * nex_s)965 js_snakenv_ihexstr_nex(sgj_state * jsp, sgj_opaque_p jop,
966 const char * conv2sname, int64_t val_i,
967 bool hex_as_well, const char * str_name,
968 const char * val_s, const char * nex_s)
969 {
970
971 if ((NULL == jsp) || (NULL == jop))
972 return;
973 if (sgj_is_snake_name(conv2sname))
974 sgj_js_nv_ihexstr_nex(jsp, jop, conv2sname, val_i, hex_as_well,
975 str_name, val_s, nex_s);
976 else {
977 char b[128];
978
979 sgj_convert_to_snake_name(conv2sname, b, sizeof(b));
980 sgj_js_nv_ihexstr_nex(jsp, jop, b, val_i, hex_as_well, str_name,
981 val_s, nex_s);
982 }
983 }
984
985 static void
usage_for(int hval,const struct opts_t * op)986 usage_for(int hval, const struct opts_t * op)
987 {
988 if (op->opt_new)
989 usage(hval);
990 else
991 usage_old();
992 }
993
994 /* Processes command line options according to new option format. Returns
995 * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */
996 static int
new_parse_cmd_line(struct opts_t * op,int argc,char * argv[])997 new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
998 {
999 while (1) {
1000 int c, n;
1001 int option_index = 0;
1002
1003 c = getopt_long(argc, argv, "aAbc:D:eEf:FhHi:j::lLm:M:nNOp:P:qQrRsStT"
1004 "uvVxX", long_options, &option_index);
1005 if (c == -1)
1006 break;
1007
1008 switch (c) {
1009 case 'a':
1010 ++op->do_all;
1011 break;
1012 case 'A':
1013 op->do_all += 2;
1014 break;
1015 case 'b':
1016 ++op->do_brief;
1017 break;
1018 case 'c':
1019 n = sg_get_num(optarg);
1020 if ((n < 0) || (n > 3)) {
1021 pr2serr("bad argument to '--control='\n");
1022 usage(2);
1023 return SG_LIB_SYNTAX_ERROR;
1024 }
1025 op->page_control = n;
1026 break;
1027 case 'D':
1028 if (0 == memcmp("-1", optarg, 3))
1029 op->dev_pdt = -1;
1030 else {
1031 n = sg_get_num(optarg);
1032 if ((n < 0) || (n > 31)) {
1033 pr2serr("bad argument to '--pdt='\n");
1034 return SG_LIB_SYNTAX_ERROR;
1035 }
1036 op->dev_pdt = n;
1037 }
1038 break;
1039 case 'e':
1040 ++op->do_enumerate;
1041 break;
1042 case 'E':
1043 op->exclude_vendor = true;
1044 break;
1045 case 'f':
1046 if ('-' == optarg[0]) {
1047 n = sg_get_num(optarg + 1);
1048 if ((n < 0) || (n > 0x30)) {
1049 pr2serr("bad negated argument to '--filter='\n");
1050 return SG_LIB_SYNTAX_ERROR;
1051 }
1052 op->filter = -n;
1053 } else {
1054 n = sg_get_num(optarg);
1055 if ((n < 0) || (n > 0xffff)) {
1056 pr2serr("bad argument to '--filter='\n");
1057 usage(1);
1058 return SG_LIB_SYNTAX_ERROR;
1059 }
1060 op->filter = n;
1061 }
1062 op->filter_given = true;
1063 break;
1064 case 'F':
1065 op->do_full = true;
1066 break;
1067 case 'h':
1068 case '?':
1069 ++op->do_help;
1070 break;
1071 case 'H':
1072 ++op->do_hex;
1073 break;
1074 case 'i':
1075 op->in_fn = optarg;
1076 break;
1077 case 'j':
1078 if (! sgj_init_state(&op->json_st, optarg)) {
1079 int bad_char = op->json_st.first_bad_char;
1080 char e[1500];
1081
1082 if (bad_char) {
1083 pr2serr("bad argument to --json= option, unrecognized "
1084 "character '%c'\n\n", bad_char);
1085 }
1086 sg_json_usage(0, e, sizeof(e));
1087 pr2serr("%s", e);
1088 return SG_LIB_SYNTAX_ERROR;
1089 }
1090 break;
1091 case 'l':
1092 ++op->do_list;
1093 break;
1094 case 'L':
1095 op->do_list += 2;
1096 break;
1097 case 'm':
1098 n = sg_get_num(optarg);
1099 if ((n < 0) || (1 == n)) {
1100 pr2serr("bad argument to '--maxlen=', from 2 and up "
1101 "expected\n");
1102 usage(2);
1103 return SG_LIB_SYNTAX_ERROR;
1104 } else if (n < 4) {
1105 pr2serr("Warning: setting '--maxlen' to 4\n");
1106 n = 4;
1107 }
1108 op->maxlen = n;
1109 op->maxlen_given = true;
1110 break;
1111 case 'M':
1112 if (op->vend_prod) {
1113 pr2serr("only one '--vendor=' option permitted\n");
1114 usage(2);
1115 return SG_LIB_SYNTAX_ERROR;
1116 } else
1117 op->vend_prod = optarg;
1118 break;
1119 case 'n':
1120 op->do_name = true;
1121 break;
1122 case 'N':
1123 break; /* ignore */
1124 case 'O':
1125 op->opt_new = false;
1126 return 0;
1127 case 'p':
1128 op->pg_arg = optarg;
1129 break;
1130 case 'P':
1131 n = sg_get_num(optarg);
1132 if (n < 0) {
1133 pr2serr("bad argument to '--paramp='\n");
1134 usage(2);
1135 return SG_LIB_SYNTAX_ERROR;
1136 }
1137 op->paramp = n;
1138 break;
1139 case 'q':
1140 op->do_pcb = true;
1141 break;
1142 case 'Q': /* N.B. PPC bit obsoleted in SPC-4 rev 18 */
1143 op->do_ppc = true;
1144 break;
1145 case 'r':
1146 op->do_raw = true;
1147 break;
1148 case 'R':
1149 op->do_pcreset = true;
1150 op->do_select = true;
1151 break;
1152 case 's':
1153 op->do_sp = true;
1154 break;
1155 case 'S':
1156 op->do_select = true;
1157 break;
1158 case 't':
1159 op->do_temperature = true;
1160 break;
1161 case 'T':
1162 op->do_transport = true;
1163 break;
1164 case 'u':
1165 ++op->undefined_hex;
1166 break;
1167 case 'v':
1168 op->verbose_given = true;
1169 ++op->verbose;
1170 break;
1171 case 'V':
1172 op->version_given = true;
1173 break;
1174 case 'x':
1175 ++op->no_inq;
1176 break;
1177 case 'X':
1178 op->o_readonly = true;
1179 break;
1180 default:
1181 pr2serr("unrecognised option code %c [0x%x]\n", c, c);
1182 if (op->do_help)
1183 break;
1184 usage(1);
1185 return SG_LIB_SYNTAX_ERROR;
1186 }
1187 }
1188 if (optind < argc) {
1189 if (NULL == op->device_name) {
1190 op->device_name = argv[optind];
1191 ++optind;
1192 }
1193 if (optind < argc) {
1194 for (; optind < argc; ++optind)
1195 pr2serr("Unexpected extra argument: %s\n", argv[optind]);
1196 usage(1);
1197 return SG_LIB_SYNTAX_ERROR;
1198 }
1199 }
1200 return 0;
1201 }
1202
1203 /* Processes command line options according to old option format. Returns
1204 * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */
1205 static int
old_parse_cmd_line(struct opts_t * op,int argc,char * argv[])1206 old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
1207 {
1208 bool jmp_out;
1209 int k, num, n;
1210 unsigned int u, uu;
1211 const char * cp;
1212
1213 for (k = 1; k < argc; ++k) {
1214 int plen;
1215
1216 cp = argv[k];
1217 plen = strlen(cp);
1218 if (plen <= 0)
1219 continue;
1220 if ('-' == *cp) {
1221 for (--plen, ++cp, jmp_out = false; plen > 0; --plen, ++cp) {
1222 switch (*cp) {
1223 case 'a':
1224 ++op->do_all;
1225 break;
1226 case 'A':
1227 op->do_all += 2;
1228 break;
1229 case 'b':
1230 ++op->do_brief;
1231 break;
1232 case 'e':
1233 ++op->do_enumerate;
1234 break;
1235 case 'E':
1236 op->exclude_vendor = true;
1237 break;
1238 case 'F':
1239 op->do_full = true;
1240 break;
1241 case 'h':
1242 case 'H':
1243 ++op->do_hex;
1244 break;
1245 case 'l':
1246 ++op->do_list;
1247 break;
1248 case 'L':
1249 op->do_list += 2;
1250 break;
1251 case 'n':
1252 op->do_name = true;
1253 break;
1254 case 'N':
1255 op->opt_new = true;
1256 return 0;
1257 case 'O':
1258 break;
1259 case 'r':
1260 op->do_pcreset = true;
1261 op->do_select = true;
1262 break;
1263 case 't':
1264 op->do_temperature = true;
1265 break;
1266 case 'T':
1267 op->do_transport = true;
1268 break;
1269 case 'u':
1270 ++op->undefined_hex;
1271 break;
1272 case 'v':
1273 op->verbose_given = true;
1274 ++op->verbose;
1275 break;
1276 case 'V':
1277 op->version_given = true;
1278 break;
1279 case 'x':
1280 ++op->no_inq;
1281 break;
1282 case 'X':
1283 op->o_readonly = true;
1284 break;
1285 case '?':
1286 ++op->do_help;
1287 break;
1288 case '-':
1289 ++cp;
1290 jmp_out = true;
1291 break;
1292 default:
1293 jmp_out = true;
1294 break;
1295 }
1296 if (jmp_out)
1297 break;
1298 }
1299 if (plen <= 0)
1300 continue;
1301 if (0 == strncmp("c=", cp, 2)) {
1302 num = sscanf(cp + 2, "%6x", &u);
1303 if ((1 != num) || (u > 3)) {
1304 pr2serr("Bad page control after '-c=' option [0..3]\n");
1305 usage_old();
1306 return SG_LIB_SYNTAX_ERROR;
1307 }
1308 op->page_control = u;
1309 } else if (0 == strncmp("D=", cp, 2)) {
1310 n = sg_get_num(cp + 2);
1311 if ((n < 0) || (n > 31)) {
1312 pr2serr("Bad argument after '-D=' option\n");
1313 usage_old();
1314 return SG_LIB_SYNTAX_ERROR;
1315 }
1316 op->dev_pdt = n;
1317 } else if (0 == strncmp("f=", cp, 2)) {
1318 n = sg_get_num(cp + 2);
1319 if ((n < 0) || (n > 0xffff)) {
1320 pr2serr("Bad argument after '-f=' option\n");
1321 usage_old();
1322 return SG_LIB_SYNTAX_ERROR;
1323 }
1324 op->filter = n;
1325 op->filter_given = true;
1326 } else if (0 == strncmp("i=", cp, 2))
1327 op->in_fn = cp + 2;
1328 else if (0 == strncmp("m=", cp, 2)) {
1329 num = sscanf(cp + 2, "%8d", &n);
1330 if ((1 != num) || (n < 0)) {
1331 pr2serr("Bad maximum response length after '-m=' "
1332 "option\n");
1333 usage_old();
1334 return SG_LIB_SYNTAX_ERROR;
1335 }
1336 op->maxlen_given = true;
1337 op->maxlen = n;
1338 } else if (0 == strncmp("M=", cp, 2)) {
1339 if (op->vend_prod) {
1340 pr2serr("only one '-M=' option permitted\n");
1341 usage(2);
1342 return SG_LIB_SYNTAX_ERROR;
1343 } else
1344 op->vend_prod = cp + 2;
1345 } else if (0 == strncmp("p=", cp, 2)) {
1346 const char * ccp = cp + 2;
1347 const struct log_elem * lep;
1348
1349 if (isalpha((uint8_t)ccp[0])) {
1350 char * xp;
1351 char b[80];
1352
1353 if (strlen(ccp) >= (sizeof(b) - 1)) {
1354 pr2serr("argument to '-p=' is too long\n");
1355 return SG_LIB_SYNTAX_ERROR;
1356 }
1357 strcpy(b, ccp);
1358 xp = (char *)strchr(b, ',');
1359 if (xp)
1360 *xp = '\0';
1361 lep = acron_search(b);
1362 if (NULL == lep) {
1363 pr2serr("bad argument to '--page=' no acronyn match "
1364 "to '%s'\n", b);
1365 pr2serr(" Try using '-e' or'-ee' to see available "
1366 "acronyns\n");
1367 return SG_LIB_SYNTAX_ERROR;
1368 }
1369 op->lep = lep;
1370 op->pg_code = lep->pg_code;
1371 if (xp) {
1372 n = sg_get_num_nomult(xp + 1);
1373 if ((n < 0) || (n > 255)) {
1374 pr2serr("Bad second value in argument to "
1375 "'--page='\n");
1376 return SG_LIB_SYNTAX_ERROR;
1377 }
1378 op->subpg_code = n;
1379 } else
1380 op->subpg_code = lep->subpg_code;
1381 } else {
1382 /* numeric arg: either 'pg_num' or 'pg_num,subpg_num' */
1383 if (NULL == strchr(cp + 2, ',')) {
1384 num = sscanf(cp + 2, "%6x", &u);
1385 if ((1 != num) || (u > 63)) {
1386 pr2serr("Bad page code value after '-p=' "
1387 "option\n");
1388 usage_old();
1389 return SG_LIB_SYNTAX_ERROR;
1390 }
1391 op->pg_code = u;
1392 } else if (2 == sscanf(cp + 2, "%4x,%4x", &u, &uu)) {
1393 if (uu > 255) {
1394 pr2serr("Bad sub page code value after '-p=' "
1395 "option\n");
1396 usage_old();
1397 return SG_LIB_SYNTAX_ERROR;
1398 }
1399 op->pg_code = u;
1400 op->subpg_code = uu;
1401 } else {
1402 pr2serr("Bad page code, subpage code sequence after "
1403 "'-p=' option\n");
1404 usage_old();
1405 return SG_LIB_SYNTAX_ERROR;
1406 }
1407 }
1408 } else if (0 == strncmp("paramp=", cp, 7)) {
1409 num = sscanf(cp + 7, "%8x", &u);
1410 if ((1 != num) || (u > 0xffff)) {
1411 pr2serr("Bad parameter pointer after '-paramp=' "
1412 "option\n");
1413 usage_old();
1414 return SG_LIB_SYNTAX_ERROR;
1415 }
1416 op->paramp = u;
1417 } else if (0 == strncmp("pcb", cp, 3))
1418 op->do_pcb = true;
1419 else if (0 == strncmp("ppc", cp, 3))
1420 op->do_ppc = true;
1421 else if (0 == strncmp("select", cp, 6))
1422 op->do_select = true;
1423 else if (0 == strncmp("sp", cp, 2))
1424 op->do_sp = true;
1425 else if (0 == strncmp("old", cp, 3))
1426 ;
1427 else if (jmp_out) {
1428 pr2serr("Unrecognized option: %s\n", cp);
1429 usage_old();
1430 return SG_LIB_SYNTAX_ERROR;
1431 }
1432 } else if (0 == op->device_name)
1433 op->device_name = cp;
1434 else {
1435 pr2serr("too many arguments, got: %s, not expecting: %s\n",
1436 op->device_name, cp);
1437 usage_old();
1438 return SG_LIB_SYNTAX_ERROR;
1439 }
1440 }
1441 return 0;
1442 }
1443
1444 /* Process command line options. First check using new option format unless
1445 * the SG3_UTILS_OLD_OPTS environment variable is defined which causes the
1446 * old option format to be checked first. Both new and old format can be
1447 * countermanded by a '-O' and '-N' options respectively. As soon as either
1448 * of these options is detected (when processing the other format), processing
1449 * stops and is restarted using the other format. Clear? */
1450 static int
parse_cmd_line(struct opts_t * op,int argc,char * argv[])1451 parse_cmd_line(struct opts_t * op, int argc, char * argv[])
1452 {
1453 int res;
1454 char * cp;
1455
1456 cp = getenv("SG3_UTILS_OLD_OPTS");
1457 if (cp) {
1458 op->opt_new = false;
1459 res = old_parse_cmd_line(op, argc, argv);
1460 if ((0 == res) && op->opt_new)
1461 res = new_parse_cmd_line(op, argc, argv);
1462 } else {
1463 op->opt_new = true;
1464 res = new_parse_cmd_line(op, argc, argv);
1465 if ((0 == res) && (0 == op->opt_new))
1466 res = old_parse_cmd_line(op, argc, argv);
1467 }
1468 return res;
1469 }
1470
1471 static void
dStrRaw(const uint8_t * str,int len)1472 dStrRaw(const uint8_t * str, int len)
1473 {
1474 int k;
1475
1476 for (k = 0; k < len; ++k)
1477 printf("%c", str[k]);
1478 }
1479
1480 /* Returns 'xp' with "unknown" if all bits set; otherwise decoded (big endian)
1481 * number in 'xp'. Number rendered in decimal if pr_in_hex=false otherwise in
1482 * hex with leading '0x' prepended. */
1483 static char *
num_or_unknown(const uint8_t * xp,int num_bytes,bool pr_in_hex,char * b,int blen)1484 num_or_unknown(const uint8_t * xp, int num_bytes /* max is 8 */,
1485 bool pr_in_hex, char * b, int blen)
1486 {
1487 if (sg_all_ffs(xp, num_bytes))
1488 snprintf(b, blen, "%s", unknown_s);
1489 else {
1490 uint64_t num = sg_get_unaligned_be(num_bytes, xp);
1491
1492 if (pr_in_hex)
1493 snprintf(b, blen, "0x%" PRIx64, num);
1494 else
1495 snprintf(b, blen, "%" PRIu64, num);
1496 }
1497 return b;
1498 }
1499
1500 /* Call LOG SENSE twice: the first time ask for 4 byte response to determine
1501 actual length of response; then a second time requesting the
1502 min(actual_len, mx_resp_len) bytes. If the calculated length for the
1503 second fetch is odd then it is incremented (perhaps should be made modulo
1504 4 in the future for SAS). Returns 0 if ok, SG_LIB_CAT_INVALID_OP for
1505 log_sense not supported, SG_LIB_CAT_ILLEGAL_REQ for bad field in log sense
1506 command, SG_LIB_CAT_NOT_READY, SG_LIB_CAT_UNIT_ATTENTION,
1507 SG_LIB_CAT_ABORTED_COMMAND and -1 for other errors. */
1508 static int
do_logs(int sg_fd,uint8_t * resp,int mx_resp_len,const struct opts_t * op)1509 do_logs(int sg_fd, uint8_t * resp, int mx_resp_len,
1510 const struct opts_t * op)
1511 {
1512 int calc_len, request_len, res, resid, vb;
1513
1514 #ifdef SG_LIB_WIN32
1515 #ifdef SG_LIB_WIN32_DIRECT
1516 if (! win32_spt_init_state) {
1517 if (win32_spt_curr_state) {
1518 if (mx_resp_len < 16384) {
1519 scsi_pt_win32_direct(0);
1520 win32_spt_curr_state = false;
1521 }
1522 } else {
1523 if (mx_resp_len >= 16384) {
1524 scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT direct */);
1525 win32_spt_curr_state = true;
1526 }
1527 }
1528 }
1529 #endif
1530 #endif
1531 memset(resp, 0, mx_resp_len);
1532 vb = op->verbose;
1533 if (op->maxlen > 1)
1534 request_len = mx_resp_len;
1535 else {
1536 request_len = LOG_SENSE_PROBE_ALLOC_LEN;
1537 if ((res = sg_ll_log_sense_v2(sg_fd, op->do_ppc, op->do_sp,
1538 op->page_control, op->pg_code,
1539 op->subpg_code, op->paramp,
1540 resp, request_len, LOG_SENSE_DEF_TIMEOUT,
1541 &resid, true /* noisy */, vb)))
1542 return res;
1543 if (resid > 0) {
1544 res = SG_LIB_WILD_RESID;
1545 goto resid_err;
1546 }
1547 calc_len = sg_get_unaligned_be16(resp + 2) + 4;
1548 if ((! op->do_raw) && (vb > 1)) {
1549 pr2serr(" Log sense (find length) response:\n");
1550 hex2stderr(resp, LOG_SENSE_PROBE_ALLOC_LEN, 1);
1551 pr2serr(" hence calculated response length=%d\n", calc_len);
1552 }
1553 if (op->pg_code != (0x3f & resp[0])) {
1554 if (vb)
1555 pr2serr("Page code does not appear in first byte of "
1556 "response so it's suspect\n");
1557 if (calc_len > 0x40) {
1558 calc_len = 0x40;
1559 if (vb)
1560 pr2serr("Trim response length to 64 bytes due to "
1561 "suspect response format\n");
1562 }
1563 }
1564 /* Some HBAs don't like odd transfer lengths */
1565 if (calc_len % 2)
1566 calc_len += 1;
1567 if (calc_len > mx_resp_len)
1568 calc_len = mx_resp_len;
1569 request_len = calc_len;
1570 }
1571 if ((res = sg_ll_log_sense_v2(sg_fd, op->do_ppc, op->do_sp,
1572 op->page_control, op->pg_code,
1573 op->subpg_code, op->paramp,
1574 resp, request_len,
1575 LOG_SENSE_DEF_TIMEOUT, &resid,
1576 true /* noisy */, vb)))
1577 return res;
1578 if (resid > 0) {
1579 request_len -= resid;
1580 if (request_len < 4) {
1581 request_len += resid;
1582 res = SG_LIB_WILD_RESID;
1583 goto resid_err;
1584 }
1585 }
1586 if ((! op->do_raw) && (vb > 1)) {
1587 pr2serr(" Log sense response:\n");
1588 hex2stderr(resp, request_len, 1);
1589 }
1590 return 0;
1591 resid_err:
1592 pr2serr("%s: request_len=%d, resid=%d, problems\n", __func__, request_len,
1593 resid);
1594 request_len -= resid;
1595 if ((request_len > 0) && (! op->do_raw) && (vb > 1)) {
1596 pr2serr(" Log sense (resid_err) response:\n");
1597 hex2stderr(resp, request_len, 1);
1598 }
1599 return res;
1600 }
1601
1602 sgj_opaque_p
sg_log_js_hdr(sgj_state * jsp,sgj_opaque_p jop,const char * name,const uint8_t * log_hdrp)1603 sg_log_js_hdr(sgj_state * jsp, sgj_opaque_p jop, const char * name,
1604 const uint8_t * log_hdrp)
1605 {
1606 bool ds = !! (log_hdrp[0] & 0x80);
1607 bool spf = !! (log_hdrp[0] & 0x40);
1608 int pg = log_hdrp[0] & 0x3f;
1609 int subpg = log_hdrp[1];
1610 size_t nlen = strlen(name);
1611 sgj_opaque_p jo2p;
1612 char b[80];
1613
1614 if ((nlen < 4) || (0 != strcmp("age", name + nlen - 3))) {
1615 memcpy(b, name, nlen);
1616 memcpy(b + nlen, " log page", 10);
1617 jo2p = sgj_snake_named_subobject_r(jsp, jop, b);
1618 } else
1619 jo2p = sgj_snake_named_subobject_r(jsp, jop, name);
1620
1621 sgj_js_nv_ihex_nex(jsp, jo2p, "ds", (int)ds, false, "Did not Save");
1622 sgj_js_nv_ihex_nex(jsp, jo2p, "spf", (int)spf, NULL, "SubPage Format");
1623 sgj_js_nv_ihex(jsp, jo2p, "page_code", pg);
1624 sgj_js_nv_ihex(jsp, jo2p, "subpage_code", subpg);
1625 return jo2p;
1626 }
1627
1628
1629
1630 /* DS made obsolete in spc4r03; TMC and ETC made obsolete in spc5r03. */
1631 static char *
get_pcb_str(int pcb,char * outp,int maxoutlen)1632 get_pcb_str(int pcb, char * outp, int maxoutlen)
1633 {
1634 char buff[PCB_STR_LEN];
1635 int n;
1636
1637 n = sprintf(buff, "du=%d [ds=%d] tsd=%d [etc=%d] ", ((pcb & 0x80) ? 1 : 0),
1638 ((pcb & 0x40) ? 1 : 0), ((pcb & 0x20) ? 1 : 0),
1639 ((pcb & 0x10) ? 1 : 0));
1640 if (pcb & 0x10)
1641 n += sprintf(buff + n, "[tmc=%d] ", ((pcb & 0xc) >> 2));
1642 #if 1
1643 n += sprintf(buff + n, "format+linking=%d [0x%.2x]", pcb & 3,
1644 pcb);
1645 #else
1646 if (pcb & 0x1)
1647 n += sprintf(buff + n, "lbin=%d ", ((pcb & 0x2) >> 1));
1648 n += sprintf(buff + n, "lp=%d [0x%.2x]", pcb & 0x1, pcb);
1649 #endif
1650 if (outp && (n < maxoutlen)) {
1651 memcpy(outp, buff, n);
1652 outp[n] = '\0';
1653 } else if (outp && (maxoutlen > 0))
1654 outp[0] = '\0';
1655 return outp;
1656 }
1657
1658 static void
js_pcb(sgj_state * jsp,sgj_opaque_p jop,int pcb)1659 js_pcb(sgj_state * jsp, sgj_opaque_p jop, int pcb)
1660 {
1661 sgj_opaque_p jo2p = sgj_snake_named_subobject_r(jsp, jop,
1662 "parameter_control_byte");
1663
1664 sgj_js_nv_ihex_nex(jsp, jo2p, "du", (pcb & 0x80) ? 1 : 0, false,
1665 "Disable Update");
1666 sgj_js_nv_ihex_nex(jsp, jo2p, "ds", (pcb & 0x40) ? 1 : 0, false,
1667 "Disable Save [obsolete]");
1668 sgj_js_nv_ihex_nex(jsp, jo2p, "tsd", (pcb & 0x20) ? 1 : 0, false,
1669 "Target Save Disable");
1670 sgj_js_nv_ihex_nex(jsp, jo2p, "etc", (pcb & 0x10) ? 1 : 0, false,
1671 "Enable Threshold Comparison [obsolete]");
1672 sgj_js_nv_ihex_nex(jsp, jo2p, "tmc", (pcb & 0xc) >> 2, false,
1673 "Threshold Met Criteria [obsolete]");
1674 sgj_js_nv_ihex_nex(jsp, jo2p, "format_and_linking", pcb & 0x3, false,
1675 NULL);
1676 }
1677
1678 /* SUPP_PAGES_LPAGE [0x0,0x0] <sp> */
1679 static bool
show_supported_pgs_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)1680 show_supported_pgs_page(const uint8_t * resp, int len,
1681 struct opts_t * op, sgj_opaque_p jop)
1682 {
1683 int num, k;
1684 const uint8_t * bp;
1685 sgj_state * jsp = &op->json_st;
1686 sgj_opaque_p jo2p, jo3p;
1687 sgj_opaque_p jap = NULL;
1688 char b[64];
1689 static const char * slpgs = "Supported log pages";
1690
1691 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
1692 sgj_pr_hr(jsp, "%s [0x0]:\n", slpgs); /* introduced in: SPC-2 */
1693 num = len - 4;
1694 bp = &resp[0] + 4;
1695 if ((op->do_hex > 0) || op->do_raw) {
1696 if (op->do_raw)
1697 dStrRaw(resp, len);
1698 else
1699 hex2stdout(resp, len, op->dstrhex_no_ascii);
1700 return true;
1701 }
1702 if (jsp->pr_as_json) {
1703 jo2p = sg_log_js_hdr(jsp, jop, slpgs, resp);
1704 jap = sgj_named_subarray_r(jsp, jo2p, "supported_pages_list");
1705 }
1706
1707 for (k = 0; k < num; ++k) {
1708 int pg_code = bp[k] & 0x3f;
1709 const struct log_elem * lep;
1710
1711 snprintf(b, sizeof(b) - 1, " 0x%02x ", pg_code);
1712 lep = pg_subpg_pdt_search(pg_code, 0, op->dev_pdt, -1);
1713 if (lep) {
1714 if (op->do_brief > 1)
1715 sgj_pr_hr(jsp, " %s\n", lep->name);
1716 else if (op->do_brief)
1717 sgj_pr_hr(jsp, "%s%s\n", b, lep->name);
1718 else
1719 sgj_pr_hr(jsp, "%s%s [%s]\n", b, lep->name, lep->acron);
1720 } else
1721 sgj_pr_hr(jsp, "%s\n", b);
1722 if (jsp->pr_as_json) {
1723 jo3p = sgj_new_unattached_object_r(jsp);
1724 sgj_js_nv_ihex(jsp, jo3p, "page_code", pg_code);
1725 sgj_js_nv_s(jsp, jo3p, "name", lep ? lep->name : unknown_s);
1726 sgj_js_nv_s(jsp, jo3p, "acronym", lep ? lep->acron : unknown_s);
1727 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
1728 }
1729 }
1730 return true;
1731 }
1732
1733 /* SUPP_PAGES_LPAGE,SUPP_SPGS_SUBPG [0x0,0xff] <ssp> or all subpages of a
1734 * given page code: [<pg_code>,0xff] where <pg_code> > 0 */
1735 static bool
show_supported_pgs_sub_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)1736 show_supported_pgs_sub_page(const uint8_t * resp, int len,
1737 struct opts_t * op, sgj_opaque_p jop)
1738 {
1739 int num, k;
1740 const uint8_t * bp;
1741 const struct log_elem * lep = NULL;
1742 sgj_state * jsp = &op->json_st;
1743 sgj_opaque_p jo2p, jo3p;
1744 sgj_opaque_p jap = NULL;
1745 char b[64];
1746 static const char * slpass = "Supported log pages and subpages";
1747 static const char * sss = "Supported subpages";
1748
1749 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex))) {
1750 if (op->pg_code > 0)
1751 sgj_pr_hr(jsp, "%s [0x%x, 0xff]:\n", sss, op->pg_code);
1752 else
1753 sgj_pr_hr(jsp, "%s [0x0, 0xff]:\n", sss);
1754 }
1755 num = len - 4;
1756 bp = &resp[0] + 4;
1757 if ((op->do_hex > 0) || op->do_raw) {
1758 if (op->do_raw)
1759 dStrRaw(resp, len);
1760 else
1761 hex2stdout(resp, len, op->dstrhex_no_ascii);
1762 return true;
1763 }
1764 if (jsp->pr_as_json) {
1765 if (op->pg_code > 0) {
1766 jo2p = sg_log_js_hdr(jsp, jop, sss, resp);
1767 jap = sgj_named_subarray_r(jsp, jo2p,
1768 "supported_subpage_descriptors");
1769 } else {
1770 jo2p = sg_log_js_hdr(jsp, jop, slpass, resp);
1771 jap = sgj_named_subarray_r(jsp, jo2p,
1772 "supported_page_subpage_descriptors");
1773 }
1774 }
1775
1776 for (k = 0; k < num; k += 2) {
1777 bool pr_name = true;
1778 int pg_code = bp[k];
1779 int subpg_code = bp[k + 1];
1780
1781 /* formerly ignored [pg, 0xff] when pg > 0, don't know why */
1782 if (NOT_SPG_SUBPG == subpg_code)
1783 snprintf(b, sizeof(b) - 1, " 0x%02x ", pg_code);
1784 else
1785 snprintf(b, sizeof(b) - 1, " 0x%02x,0x%02x ", pg_code,
1786 subpg_code);
1787 if ((pg_code > 0) && (subpg_code == 0xff)) {
1788 sgj_pr_hr(jsp, "%s\n", b);
1789 pr_name = false;
1790 } else {
1791 lep = pg_subpg_pdt_search(pg_code, subpg_code, op->dev_pdt, -1);
1792 if (lep) {
1793 if (op->do_brief > 1)
1794 sgj_pr_hr(jsp, " %s\n", lep->name);
1795 else if (op->do_brief)
1796 sgj_pr_hr(jsp, "%s%s\n", b, lep->name);
1797 else
1798 sgj_pr_hr(jsp, "%s%s [%s]\n", b, lep->name, lep->acron);
1799 } else
1800 sgj_pr_hr(jsp, "%s\n", b);
1801 }
1802 if (jsp->pr_as_json) {
1803 jo3p = sgj_new_unattached_object_r(jsp);
1804 sgj_js_nv_ihex(jsp, jo3p, "page_code", pg_code);
1805 sgj_js_nv_ihex(jsp, jo3p, "subpage_code", subpg_code);
1806 if (pr_name) {
1807 sgj_js_nv_s(jsp, jo3p, "name", lep ? lep->name : unknown_s);
1808 sgj_js_nv_s(jsp, jo3p, "acronym", lep ? lep->acron :
1809 unknown_s);
1810 }
1811 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
1812 }
1813 }
1814 return true;
1815 }
1816
1817 /* BUFF_OVER_UNDER_LPAGE [0x1] <bou> introduced: SPC-2 */
1818 static bool
show_buffer_over_under_run_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)1819 show_buffer_over_under_run_page(const uint8_t * resp, int len,
1820 struct opts_t * op, sgj_opaque_p jop)
1821 {
1822 int num, pl, pc;
1823 uint64_t count;
1824 const uint8_t * bp;
1825 const char * cp;
1826 sgj_state * jsp = &op->json_st;
1827 sgj_opaque_p jo2p;
1828 sgj_opaque_p jo3p = NULL;
1829 sgj_opaque_p jap = NULL;
1830 char str[PCB_STR_LEN];
1831 static const char * bourlp = "Buffer over-run/under-run log page";
1832 static const char * orurc = "over_run_under_run_counter";
1833
1834 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
1835 sgj_pr_hr(jsp, "%s [0x1]\n", bourlp);
1836 num = len - 4;
1837 bp = &resp[0] + 4;
1838 if (jsp->pr_as_json) {
1839 jo2p = sg_log_js_hdr(jsp, jop, bourlp, resp);
1840 jap = sgj_named_subarray_r(jsp, jo2p,
1841 "buffer_over_run_under_run_log_parameters");
1842 }
1843 while (num > 3) {
1844 cp = NULL;
1845 pl = bp[3] + 4;
1846 count = (pl > 4) ? sg_get_unaligned_be(pl - 4, bp + 4) : 0;
1847 pc = sg_get_unaligned_be16(bp + 0);
1848 if (op->filter_given) {
1849 if (pc != op->filter)
1850 goto skip;
1851 }
1852 if (op->do_raw) {
1853 dStrRaw(bp, pl);
1854 break;
1855 } else if (op->do_hex) {
1856 hex2stdout(bp, pl, op->dstrhex_no_ascii);
1857 break;
1858 }
1859 if (jsp->pr_as_json) {
1860 jo3p = sgj_new_unattached_object_r(jsp);
1861 if (op->do_pcb)
1862 js_pcb(jsp, jo3p, bp[2]);
1863 }
1864
1865 switch (pc) {
1866 case 0x0:
1867 cp = "under-run";
1868 break;
1869 case 0x1:
1870 cp = "over-run";
1871 break;
1872 case 0x2:
1873 cp = "service delivery subsystem busy, under-run";
1874 break;
1875 case 0x3:
1876 cp = "service delivery subsystem busy, over-run";
1877 break;
1878 case 0x4:
1879 cp = "transfer too slow, under-run";
1880 break;
1881 case 0x5:
1882 cp = "transfer too slow, over-run";
1883 break;
1884 case 0x20:
1885 cp = "command, under-run";
1886 break;
1887 case 0x21:
1888 cp = "command, over-run";
1889 break;
1890 case 0x22:
1891 cp = "command, service delivery subsystem busy, under-run";
1892 break;
1893 case 0x23:
1894 cp = "command, service delivery subsystem busy, over-run";
1895 break;
1896 case 0x24:
1897 cp = "command, transfer too slow, under-run";
1898 break;
1899 case 0x25:
1900 cp = "command, transfer too slow, over-run";
1901 break;
1902 case 0x40:
1903 cp = "I_T nexus, under-run";
1904 break;
1905 case 0x41:
1906 cp = "I_T nexus, over-run";
1907 break;
1908 case 0x42:
1909 cp = "I_T nexus, service delivery subsystem busy, under-run";
1910 break;
1911 case 0x43:
1912 cp = "I_T nexus, service delivery subsystem busy, over-run";
1913 break;
1914 case 0x44:
1915 cp = "I_T nexus, transfer too slow, under-run";
1916 break;
1917 case 0x45:
1918 cp = "I_T nexus, transfer too slow, over-run";
1919 break;
1920 case 0x80:
1921 cp = "time, under-run";
1922 break;
1923 case 0x81:
1924 cp = "time, over-run";
1925 break;
1926 case 0x82:
1927 cp = "time, service delivery subsystem busy, under-run";
1928 break;
1929 case 0x83:
1930 cp = "time, service delivery subsystem busy, over-run";
1931 break;
1932 case 0x84:
1933 cp = "time, transfer too slow, under-run";
1934 break;
1935 case 0x85:
1936 cp = "time, transfer too slow, over-run";
1937 break;
1938 default:
1939 pr2serr(" undefined %s [0x%x], count = %" PRIu64 "\n",
1940 param_c, pc, count);
1941 break;
1942 }
1943 sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc);
1944 sgj_pr_hr(jsp, " %s=0x%x\n", param_c, pc);
1945 if (cp) {
1946 sgj_pr_hr(jsp, " %s = %" PRIu64 "\n", cp, count);
1947 js_snakenv_ihexstr_nex(jsp, jo3p, param_c, pc, true,
1948 NULL, cp, NULL);
1949 sgj_js_nv_ihex(jsp, jo3p, orurc, count);
1950 } else
1951 sgj_pr_hr(jsp, " counter = %" PRIu64 "\n", count);
1952
1953 if (op->do_pcb)
1954 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2],
1955 str, sizeof(str)));
1956 if (jsp->pr_as_json)
1957 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
1958 if (op->filter_given)
1959 break;
1960 skip:
1961 num -= pl;
1962 bp += pl;
1963 }
1964 return true;
1965 }
1966
1967 /* WRITE_ERR_LPAGE; READ_ERR_LPAGE; READ_REV_ERR_LPAGE; VERIFY_ERR_LPAGE */
1968 /* [0x2, 0x3, 0x4, 0x5] <we, re, rre, ve> introduced: SPC-3 */
1969 static bool
show_error_counter_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)1970 show_error_counter_page(const uint8_t * resp, int len,
1971 struct opts_t * op, sgj_opaque_p jop)
1972 {
1973 bool skip_out = false;
1974 bool evsm_output = false;
1975 int n, num, pl, pc, pg_code;
1976 uint64_t val;
1977 const uint8_t * bp;
1978 const char * pg_cp = NULL;
1979 const char * par_cp = NULL;
1980 sgj_state * jsp = &op->json_st;
1981 sgj_opaque_p jo2p;
1982 sgj_opaque_p jo3p = NULL;
1983 sgj_opaque_p jap = NULL;
1984 char str[PCB_STR_LEN];
1985 char b[128] SG_C_CPP_ZERO_INIT;
1986 char d[128];
1987 char e[64];
1988 static const char * wec = "Write error counter";
1989 static const char * rec = "Read error counter";
1990 static const char * rrec = "Read reverse error counter";
1991 static const char * vec = "Verify error counter";
1992
1993 pg_code = resp[0] & 0x3f;
1994 switch(pg_code) {
1995 case WRITE_ERR_LPAGE:
1996 pg_cp = wec;
1997 break;
1998 case READ_ERR_LPAGE:
1999 pg_cp = rec;
2000 break;
2001 case READ_REV_ERR_LPAGE:
2002 pg_cp = rrec;
2003 break;
2004 case VERIFY_ERR_LPAGE:
2005 pg_cp = vec;
2006 break;
2007 default:
2008 pr2serr("expecting error counter page, got page = 0x%x\n",
2009 pg_code);
2010 return false;
2011 }
2012 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
2013 sgj_pr_hr(jsp, "%s log page [0x%x]\n", pg_cp, pg_code);
2014 if (jsp->pr_as_json) {
2015 n = strlen(pg_cp);
2016 memcpy(b, pg_cp, n);
2017 memcpy(b + n, " log", 4);
2018 n = strlen(b);
2019 memcpy(b + n, " page", 5);
2020 jo2p = sg_log_js_hdr(jsp, jop, b, resp);
2021 memcpy(b + n, " parameters", 11);
2022 sgj_convert_to_snake_name(b, d, sizeof(d) - 1);
2023 jap = sgj_named_subarray_r(jsp, jo2p, d);
2024 }
2025 num = len - 4;
2026 bp = &resp[0] + 4;
2027 while (num > 3) {
2028 pc = sg_get_unaligned_be16(bp + 0);
2029 pl = bp[3] + 4;
2030 if (op->filter_given) {
2031 if (pc != op->filter)
2032 goto skip;
2033 }
2034 if (op->do_raw) {
2035 dStrRaw(bp, pl);
2036 break;
2037 } else if (op->do_hex) {
2038 hex2stdout(bp, pl, op->dstrhex_no_ascii);
2039 break;
2040 }
2041 if (jsp->pr_as_json) {
2042 jo3p = sgj_new_unattached_object_r(jsp);
2043 if (op->do_pcb)
2044 js_pcb(jsp, jo3p, bp[2]);
2045 }
2046
2047 par_cp = NULL;
2048 switch (pc) {
2049 case 0:
2050 par_cp = "Errors corrected without substantial delay";
2051 break;
2052 case 1:
2053 par_cp = "Errors corrected with possible delays";
2054 break;
2055 case 2:
2056 par_cp = "Total rewrites or rereads";
2057 break;
2058 case 3:
2059 par_cp = "Total errors corrected";
2060 break;
2061 case 4:
2062 par_cp = "Total times correction algorithm processed";
2063 break;
2064 case 5:
2065 par_cp = "Total bytes processed";
2066 break;
2067 case 6:
2068 par_cp = "Total uncorrected errors";
2069 break;
2070 default:
2071 if (op->exclude_vendor) {
2072 skip_out = true;
2073 if ((op->verbose > 0) && (0 == op->do_brief) &&
2074 (! evsm_output)) {
2075 evsm_output = true;
2076 pr2serr(" %s parameter(s) being ignored\n", vend_spec);
2077 }
2078 } else {
2079 if (0x8009 == pc)
2080 par_cp = "Track following errors [Hitachi]";
2081 else if (0x8015 == pc)
2082 par_cp = "Positioning errors [Hitachi]";
2083 else {
2084 snprintf(e, sizeof(e), "Reserved or %s [0x%x]", vend_spec,
2085 pc);
2086 par_cp = e;
2087 }
2088 }
2089 break;
2090 }
2091
2092 if (skip_out)
2093 skip_out = false;
2094 else if (par_cp) {
2095 val = sg_get_unaligned_be(pl - 4, bp + 4);
2096 if (val > ((uint64_t)1 << 40))
2097 snprintf(d, sizeof(d), "%" PRIu64 " [%" PRIu64 " TB]",
2098 val, (val / (1000UL * 1000 * 1000 * 1000)));
2099 else if (val > ((uint64_t)1 << 30))
2100 snprintf(d, sizeof(d), "%" PRIu64 " [%" PRIu64 " GB]",
2101 val, (val / (1000UL * 1000 * 1000)));
2102 else
2103 snprintf(d, sizeof(d), "%" PRIu64, val);
2104 sgj_pr_hr(jsp, " %s = %s\n", par_cp, d);
2105 if (jsp->pr_as_json) {
2106 js_snakenv_ihexstr_nex(jsp, jo3p, param_c, pc, true,
2107 NULL, par_cp, NULL);
2108 sgj_convert_to_snake_name(pg_cp, e, sizeof(e) - 1);
2109 n = strlen(e);
2110 memcpy(e + n, "_counter", 9); /* take trailing null */
2111 sgj_js_nv_ihexstr(jsp, jo3p, e, val, as_s_s, d);
2112 }
2113 }
2114 if (op->do_pcb)
2115 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2],
2116 str, sizeof(str)));
2117 if (jsp->pr_as_json)
2118 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
2119 if (op->filter_given)
2120 break;
2121 skip:
2122 num -= pl;
2123 bp += pl;
2124 }
2125 return true;
2126 }
2127
2128 /* NON_MEDIUM_LPAGE [0x6] <nm> introduced: SPC-2 */
2129 static bool
show_non_medium_error_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)2130 show_non_medium_error_page(const uint8_t * resp, int len,
2131 struct opts_t * op, sgj_opaque_p jop)
2132 {
2133 bool skip_out = false;
2134 bool evsm_output = false;
2135 int num, pl, pc;
2136 uint64_t count;
2137 const uint8_t * bp;
2138 sgj_state * jsp = &op->json_st;
2139 sgj_opaque_p jo2p;
2140 sgj_opaque_p jo3p = NULL;
2141 sgj_opaque_p jap = NULL;
2142 char str[PCB_STR_LEN];
2143 char b[128] SG_C_CPP_ZERO_INIT;
2144 static const char * nmelp = "Non-medium error log page";
2145 static const char * nmec = "Non-medium error count";
2146
2147 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
2148 sgj_pr_hr(jsp, "%s [0x6]\n", nmelp);
2149 num = len - 4;
2150 bp = &resp[0] + 4;
2151 if (jsp->pr_as_json) {
2152 jo2p = sg_log_js_hdr(jsp, jop, nmelp, resp);
2153 jap = sgj_named_subarray_r(jsp, jo2p,
2154 "non_medium_error_log_parameters");
2155 }
2156 while (num > 3) {
2157 pc = sg_get_unaligned_be16(bp + 0);
2158 pl = bp[3] + 4;
2159 if (op->filter_given) {
2160 if (pc != op->filter)
2161 goto skip;
2162 }
2163 if (op->do_raw) {
2164 dStrRaw(bp, pl);
2165 break;
2166 } else if (op->do_hex) {
2167 hex2stdout(bp, pl, op->dstrhex_no_ascii);
2168 break;
2169 }
2170 if (jsp->pr_as_json) {
2171 jo3p = sgj_new_unattached_object_r(jsp);
2172 if (op->do_pcb)
2173 js_pcb(jsp, jo3p, bp[2]);
2174 }
2175
2176 switch (pc) {
2177 case 0:
2178 snprintf(b, sizeof(b), "%s", nmec);
2179 break;
2180 default:
2181 if (pc <= 0x7fff)
2182 snprintf(b, sizeof(b), " Reserved [0x%x]", pc);
2183 else {
2184 if (op->exclude_vendor) {
2185 skip_out = true;
2186 if ((op->verbose > 0) && (0 == op->do_brief) &&
2187 (! evsm_output)) {
2188 evsm_output = true;
2189 pr2serr(" %s parameter(s) being ignored\n",
2190 vend_spec);
2191 }
2192 } else
2193 snprintf(b, sizeof(b), "%s [0x%x]", vend_spec, pc);
2194 }
2195 break;
2196 }
2197 if (skip_out)
2198 skip_out = false;
2199 else {
2200 count = sg_get_unaligned_be(pl - 4, bp + 4);
2201 sgj_pr_hr(jsp, " %s = %" PRIu64 "\n", b, count);
2202 js_snakenv_ihexstr_nex(jsp, jo3p, param_c, pc, true,
2203 NULL, b, NULL);
2204 js_snakenv_ihexstr_nex(jsp, jo3p, nmec, count, true, NULL, NULL,
2205 NULL);
2206 }
2207 if (op->do_pcb)
2208 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2],
2209 str, sizeof(str)));
2210 if (jsp->pr_as_json)
2211 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
2212 if (op->filter_given)
2213 break;
2214 skip:
2215 num -= pl;
2216 bp += pl;
2217 }
2218 return true;
2219 }
2220
2221 /* PCT_LPAGE [0x1a] <pct> introduced: SPC-4 */
2222 static bool
show_power_condition_transitions_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)2223 show_power_condition_transitions_page(const uint8_t * resp, int len,
2224 struct opts_t * op, sgj_opaque_p jop)
2225 {
2226 bool partial;
2227 int num, pl, pc;
2228 uint64_t count;
2229 const uint8_t * bp;
2230 const char * cp;
2231 sgj_state * jsp = &op->json_st;
2232 sgj_opaque_p jo2p;
2233 sgj_opaque_p jo3p = NULL;
2234 sgj_opaque_p jap = NULL;
2235 char str[PCB_STR_LEN];
2236 char b[128];
2237 char bb[64];
2238 static const char * pctlp = "Power condition transitions log page";
2239 static const char * att = "Accumulated transitions to";
2240
2241 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
2242 sgj_pr_hr(jsp, "%s [0x1a]\n", pctlp);
2243 num = len - 4;
2244 bp = &resp[0] + 4;
2245 if (jsp->pr_as_json) {
2246 jo2p = sg_log_js_hdr(jsp, jop, pctlp, resp);
2247 jap = sgj_named_subarray_r(jsp, jo2p,
2248 "power_condition_transition_log_parameters");
2249 }
2250
2251 while (num > 3) {
2252 pc = sg_get_unaligned_be16(bp + 0);
2253 pl = bp[3] + 4;
2254 if (op->filter_given) {
2255 if (pc != op->filter)
2256 goto skip;
2257 }
2258 if (op->do_raw) {
2259 dStrRaw(bp, pl);
2260 break;
2261 } else if (op->do_hex) {
2262 hex2stdout(bp, pl, op->dstrhex_no_ascii);
2263 break;
2264 }
2265 if (jsp->pr_as_json) {
2266 jo3p = sgj_new_unattached_object_r(jsp);
2267 if (op->do_pcb)
2268 js_pcb(jsp, jo3p, bp[2]);
2269 }
2270
2271 cp = NULL;
2272 partial = true;
2273 switch (pc) {
2274 case 1:
2275 cp = "active";
2276 break;
2277 case 2:
2278 cp = "idle_a";
2279 break;
2280 case 3:
2281 cp = "idle_b";
2282 break;
2283 case 4:
2284 cp = "idle_c";
2285 break;
2286 case 8:
2287 cp = "standby_z";
2288 break;
2289 case 9:
2290 cp = "standby_y";
2291 break;
2292 default:
2293 snprintf(bb, sizeof(bb), "Reserved [0x%x]", pc);
2294 cp = bb;
2295 partial = false;
2296 break;
2297 }
2298 if (partial) {
2299 snprintf(b, sizeof(b), "%s %s", att, cp);
2300 cp = b;
2301 }
2302 count = sg_get_unaligned_be(pl - 4, bp + 4);
2303 sgj_pr_hr(jsp, " %s = %" PRIu64 "\n", cp, count);
2304 if (op->do_pcb)
2305 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2],
2306 str, sizeof(str)));
2307 if (jsp->pr_as_json) {
2308 js_snakenv_ihexstr_nex(jsp, jo3p, cp, count, true,
2309 NULL, NULL, "saturating counter");
2310 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
2311 }
2312 if (op->filter_given)
2313 break;
2314 skip:
2315 num -= pl;
2316 bp += pl;
2317 }
2318 return true;
2319 }
2320
2321 static char *
temperature_str(int8_t t,bool reporting,char * b,int blen)2322 temperature_str(int8_t t, bool reporting, char * b, int blen)
2323 {
2324 if (-128 == t) {
2325 if (reporting)
2326 snprintf(b, blen, "%s", not_avail);
2327 else
2328 snprintf(b, blen, "no limit");
2329 } else
2330 snprintf(b, blen, "%d C", t);
2331 return b;
2332 }
2333
2334 static char *
humidity_str(uint8_t h,bool reporting,char * b,int blen)2335 humidity_str(uint8_t h, bool reporting, char * b, int blen)
2336 {
2337 if (255 == h) {
2338 if (reporting)
2339 snprintf(b, blen, "%s", not_avail);
2340 else
2341 snprintf(b, blen, "no limit");
2342 } else if (h <= 100)
2343 snprintf(b, blen, "%u %%", h);
2344 else
2345 snprintf(b, blen, "%s value [%u]", rsv_s, h);
2346 return b;
2347 }
2348
2349 /* ENV_REPORTING_SUBPG [0xd,0x1] <env> introduced: SPC-5 (rev 02). "mounted"
2350 * changed to "other" in spc5r11 */
2351 static bool
show_environmental_reporting_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)2352 show_environmental_reporting_page(const uint8_t * resp, int len,
2353 struct opts_t * op, sgj_opaque_p jop)
2354 {
2355 int num, pl, pc, blen;
2356 bool other_valid;
2357 const uint8_t * bp;
2358 sgj_state * jsp = &op->json_st;
2359 sgj_opaque_p jo2p;
2360 sgj_opaque_p jo3p = NULL;
2361 sgj_opaque_p jap = NULL;
2362 char str[PCB_STR_LEN];
2363 char b[32];
2364 static const char * erlp = "Environmental reporting log page";
2365 static const char * temp = "Temperature";
2366 static const char * lmaxt = "Lifetime maximum temperature";
2367 static const char * lmint = "Lifetime minimum temperature";
2368 static const char * maxtspo = "Maximum temperature since power on";
2369 static const char * mintspo = "Minimum temperature since power on";
2370 static const char * maxot = "Maximum other temperature";
2371 static const char * minot = "Minimum other temperature";
2372 static const char * relhum = "Relative humidity";
2373 static const char * lmaxrh = "Lifetime maximum relative humidity";
2374 static const char * lminrh = "Lifetime minimum relative humidity";
2375 static const char * maxrhspo = "Maximum relative humidity since power on";
2376 static const char * minrhspo = "Minimum relative humidity since power on";
2377 static const char * maxorh = "Maximum other relative humidity";
2378 static const char * minorh = "Minimum other relative humidity";
2379
2380 blen = sizeof(b);
2381 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
2382 sgj_pr_hr(jsp, "%s [0xd,0x1]\n", erlp);
2383 if (jsp->pr_as_json) {
2384 jo2p = sg_log_js_hdr(jsp, jop, erlp, resp);
2385 jap = sgj_named_subarray_r(jsp, jo2p,
2386 "environmental_reporting_log_parameters");
2387 }
2388 num = len - 4;
2389 bp = &resp[0] + 4;
2390 while (num > 3) {
2391 pc = sg_get_unaligned_be16(bp + 0);
2392 pl = bp[3] + 4;
2393 if (op->filter_given) {
2394 if (pc != op->filter)
2395 goto skip;
2396 }
2397 if (op->do_raw) {
2398 dStrRaw(bp, pl);
2399 break;
2400 } else if (op->do_hex) {
2401 hex2stdout(bp, pl, op->dstrhex_no_ascii);
2402 break;
2403 }
2404 if (jsp->pr_as_json) {
2405 jo3p = sgj_new_unattached_object_r(jsp);
2406 if (op->do_pcb)
2407 js_pcb(jsp, jo3p, bp[2]);
2408 }
2409 other_valid = !!(bp[4] & 1);
2410 if (pc < 0x100) {
2411 if (pl < 12) {
2412 pr2serr(" <<expect parameter 0x%x to be at least 12 bytes "
2413 "long, got %d, skip>>\n", pc, pl);
2414 goto inner;
2415 }
2416 sgj_pr_hr(jsp, " %s=0x%x\n", param_c, pc);
2417 sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc);
2418 sgj_pr_hr(jsp, " OTV=%d\n", (int)other_valid);
2419 sgj_js_nv_ihex_nex(jsp, jo3p, "otv", (int)other_valid,
2420 false, "Other Temperature Valid");
2421
2422 temperature_str(bp[5], true, b, blen);
2423 sgj_pr_hr(jsp, " %s: %s\n", temp, b);
2424 js_snakenv_ihexstr_nex(jsp, jo3p, temp, bp[5], false,
2425 NULL, b, "current [Celsius]");
2426 temperature_str(bp[6], true, b, blen);
2427 sgj_pr_hr(jsp, " %s: %s\n", lmaxt, b);
2428 js_snakenv_ihexstr_nex(jsp, jo3p, lmaxt, bp[6], false,
2429 NULL, b, NULL);
2430 temperature_str(bp[7], true, b, blen);
2431 sgj_pr_hr(jsp, " %s: %s\n", lmint, b);
2432 js_snakenv_ihexstr_nex(jsp, jo3p, lmint, bp[7], false,
2433 NULL, b, NULL);
2434 temperature_str(bp[8], true, b, blen);
2435 sgj_pr_hr(jsp, " %s: %s\n", maxtspo, b);
2436 js_snakenv_ihexstr_nex(jsp, jo3p, maxtspo, bp[8], false,
2437 NULL, b, NULL);
2438 temperature_str(bp[9], true, b, blen);
2439 sgj_pr_hr(jsp, " %s: %s\n", mintspo, b);
2440 js_snakenv_ihexstr_nex(jsp, jo3p, mintspo, bp[9], false,
2441 NULL, b, NULL);
2442 if (other_valid) {
2443 temperature_str(bp[10], true, b, blen);
2444 sgj_pr_hr(jsp, " %s: %s\n", maxot, b);
2445 js_snakenv_ihexstr_nex(jsp, jo3p, maxot, bp[10], false,
2446 NULL, b, NULL);
2447 temperature_str(bp[11], true, b, blen);
2448 sgj_pr_hr(jsp, " %s: %s\n", minot, b);
2449 js_snakenv_ihexstr_nex(jsp, jo3p, minot, bp[11], false,
2450 NULL, b, NULL);
2451 }
2452 } else if (pc < 0x200) {
2453 if (pl < 12) {
2454 pr2serr(" <<expect parameter 0x%x to be at least 12 bytes "
2455 "long, got %d, skip>>\n", pc, pl);
2456 goto inner;
2457 }
2458 sgj_pr_hr(jsp, " %s=0x%x\n", param_c, pc);
2459 sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc);
2460 sgj_pr_hr(jsp, " ORHV=%d\n", (int)other_valid);
2461 sgj_js_nv_ihex_nex(jsp, jo3p, "orhv", (int)other_valid,
2462 false, "Other Relative Humidity Valid");
2463
2464 humidity_str(bp[5], true, b, blen);
2465 sgj_pr_hr(jsp, " %s: %s\n", relhum, b);
2466 js_snakenv_ihexstr_nex(jsp, jo3p, relhum, bp[5], false,
2467 NULL, b, NULL);
2468 humidity_str(bp[6], true, b, blen);
2469 sgj_pr_hr(jsp, " %s: %s\n", lmaxrh, b);
2470 js_snakenv_ihexstr_nex(jsp, jo3p, lmaxrh, bp[6], false,
2471 NULL, b, NULL);
2472 humidity_str(bp[7], true, b, blen);
2473 sgj_pr_hr(jsp, " %s: %s\n", lminrh, b);
2474 js_snakenv_ihexstr_nex(jsp, jo3p, lminrh, bp[7], false,
2475 NULL, b, NULL);
2476 humidity_str(bp[8], true, b, blen);
2477 sgj_pr_hr(jsp, " %s: %s\n", maxrhspo, b);
2478 js_snakenv_ihexstr_nex(jsp, jo3p, maxrhspo, bp[8], false,
2479 NULL, b, NULL);
2480 humidity_str(bp[9], true, b, blen);
2481 sgj_pr_hr(jsp, " %s: %s\n", minrhspo, b);
2482 js_snakenv_ihexstr_nex(jsp, jo3p, minrhspo, bp[9], false,
2483 NULL, b, NULL);
2484 if (other_valid) {
2485 humidity_str(bp[10], true, b, blen);
2486 sgj_pr_hr(jsp, " %s: %s\n", maxorh, b);
2487 js_snakenv_ihexstr_nex(jsp, jo3p, maxorh, bp[10], false,
2488 NULL, b, NULL);
2489 humidity_str(bp[11], true, b, blen);
2490 sgj_pr_hr(jsp, " %s: %s\n", minorh, b);
2491 js_snakenv_ihexstr_nex(jsp, jo3p, minorh, bp[11], false,
2492 NULL, b, NULL);
2493 }
2494 } else
2495 sgj_pr_hr(jsp, " <<unexpected %s 0x%x\n", param_c, pc);
2496 if (op->do_pcb)
2497 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], str,
2498 sizeof(str)));
2499 inner:
2500 if (jsp->pr_as_json)
2501 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
2502 if (op->filter_given)
2503 break;
2504 skip:
2505 num -= pl;
2506 bp += pl;
2507 }
2508 return true;
2509 }
2510
2511 /* ENV_LIMITS_SUBPG [0xd,0x2] <enl> introduced: SPC-5 (rev 02) */
2512 static bool
show_environmental_limits_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)2513 show_environmental_limits_page(const uint8_t * resp, int len,
2514 struct opts_t * op, sgj_opaque_p jop)
2515 {
2516 int num, pl, pc, blen;
2517 const uint8_t * bp;
2518 sgj_state * jsp = &op->json_st;
2519 sgj_opaque_p jo2p;
2520 sgj_opaque_p jo3p = NULL;
2521 sgj_opaque_p jap = NULL;
2522 char str[PCB_STR_LEN];
2523 char b[32];
2524 static const char * ellp = "Environmental limits log page";
2525 static const char * hctlt = "High critical temperature limit trigger";
2526 static const char * hctlr = "High critical temperature limit reset";
2527 static const char * lctlr = "High critical temperature limit reset";
2528 static const char * lctlt = "High critical temperature limit trigger";
2529 static const char * hotlt = "High operating temperature limit trigger";
2530 static const char * hotlr = "High operating temperature limit reset";
2531 static const char * lotlr = "High operating temperature limit reset";
2532 static const char * lotlt = "High operating temperature limit trigger";
2533 static const char * hcrhlt =
2534 "High critical relative humidity limit trigger";
2535 static const char * hcrhlr =
2536 "High critical relative humidity limit reset";
2537 static const char * lcrhlr =
2538 "High critical relative humidity limit reset";
2539 static const char * lcrhlt =
2540 "High critical relative humidity limit trigger";
2541 static const char * horhlt =
2542 "High operating relative humidity limit trigger";
2543 static const char * horhlr =
2544 "High operating relative humidity limit reset";
2545 static const char * lorhlr =
2546 "High operating relative humidity limit reset";
2547 static const char * lorhlt =
2548 "High operating relative humidity limit trigger";
2549
2550 blen = sizeof(b);
2551 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
2552 sgj_pr_hr(jsp, "%s [0xd,0x2]\n", ellp);
2553 if (jsp->pr_as_json) {
2554 jo2p = sg_log_js_hdr(jsp, jop, ellp, resp);
2555 jap = sgj_named_subarray_r(jsp, jo2p,
2556 "environmental_limits_log_parameters");
2557 }
2558 num = len - 4;
2559 bp = &resp[0] + 4;
2560 while (num > 3) {
2561 pc = sg_get_unaligned_be16(bp + 0);
2562 pl = bp[3] + 4;
2563 if (op->filter_given) {
2564 if (pc != op->filter)
2565 goto skip;
2566 }
2567 if (op->do_raw) {
2568 dStrRaw(bp, pl);
2569 break;
2570 } else if (op->do_hex) {
2571 hex2stdout(bp, pl, op->dstrhex_no_ascii);
2572 break;
2573 }
2574 if (jsp->pr_as_json) {
2575 jo3p = sgj_new_unattached_object_r(jsp);
2576 if (op->do_pcb)
2577 js_pcb(jsp, jo3p, bp[2]);
2578 }
2579 if (pc < 0x100) {
2580 if (pl < 12) {
2581 pr2serr(" <<expect parameter 0x%x to be at least 12 bytes "
2582 "long, got %d, skip>>\n", pc, pl);
2583 goto inner;
2584 }
2585 sgj_pr_hr(jsp, " %s=0x%x\n", param_c, pc);
2586 sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc);
2587
2588 temperature_str(bp[4], true, b, blen);
2589 sgj_pr_hr(jsp, " %s: %s\n", hctlt, b);
2590 js_snakenv_ihexstr_nex(jsp, jo3p, hctlt, bp[4], false,
2591 NULL, b, "[Celsius]");
2592 temperature_str(bp[5], true, b, blen);
2593 sgj_pr_hr(jsp, " %s: %s\n", hctlr, b);
2594 js_snakenv_ihexstr_nex(jsp, jo3p, hctlr, bp[5], false,
2595 NULL, b, NULL);
2596 temperature_str(bp[6], true, b, blen);
2597 sgj_pr_hr(jsp, " %s: %s\n", lctlr, b);
2598 js_snakenv_ihexstr_nex(jsp, jo3p, lctlr, bp[6], false,
2599 NULL, b, NULL);
2600 temperature_str(bp[7], true, b, blen);
2601 sgj_pr_hr(jsp, " %s: %s\n", lctlt, b);
2602 js_snakenv_ihexstr_nex(jsp, jo3p, lctlt, bp[7], false,
2603 NULL, b, NULL);
2604 temperature_str(bp[8], true, b, blen);
2605 sgj_pr_hr(jsp, " %s: %s\n", hotlt, b);
2606 js_snakenv_ihexstr_nex(jsp, jo3p, hotlt, bp[8], false,
2607 NULL, b, NULL);
2608 temperature_str(bp[9], true, b, blen);
2609 sgj_pr_hr(jsp, " %s: %s\n", hotlr, b);
2610 js_snakenv_ihexstr_nex(jsp, jo3p, hotlr, bp[9], false,
2611 NULL, b, NULL);
2612 temperature_str(bp[10], true, b, blen);
2613 sgj_pr_hr(jsp, " %s: %s\n", lotlr, b);
2614 js_snakenv_ihexstr_nex(jsp, jo3p, lotlr, bp[10], false,
2615 NULL, b, NULL);
2616 temperature_str(bp[11], true, b, blen);
2617 sgj_pr_hr(jsp, " %s: %s\n", lotlt, b);
2618 js_snakenv_ihexstr_nex(jsp, jo3p, lotlt, bp[11], false,
2619 NULL, b, NULL);
2620 } else if (pc < 0x200) {
2621 if (pl < 12) {
2622 pr2serr(" <<expect parameter 0x%x to be at least 12 bytes "
2623 "long, got %d, skip>>\n", pc, pl);
2624 goto inner;
2625 }
2626 sgj_pr_hr(jsp, " %s=0x%x\n", param_c, pc);
2627 sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc);
2628
2629 humidity_str(bp[4], true, b, blen);
2630 sgj_pr_hr(jsp, " %s: %s\n", hcrhlt, b);
2631 js_snakenv_ihexstr_nex(jsp, jo3p, hcrhlt, bp[4], false,
2632 NULL, b, "[percentage]");
2633 humidity_str(bp[5], true, b, blen);
2634 sgj_pr_hr(jsp, " %s: %s\n", hcrhlr, b);
2635 js_snakenv_ihexstr_nex(jsp, jo3p, hcrhlr, bp[5], false,
2636 NULL, b, NULL);
2637 humidity_str(bp[6], true, b, blen);
2638 sgj_pr_hr(jsp, " %s: %s\n", lcrhlr, b);
2639 js_snakenv_ihexstr_nex(jsp, jo3p, lcrhlr, bp[6], false,
2640 NULL, b, NULL);
2641 humidity_str(bp[7], true, b, blen);
2642 sgj_pr_hr(jsp, " %s: %s\n", lcrhlt, b);
2643 js_snakenv_ihexstr_nex(jsp, jo3p, lcrhlt, bp[7], false,
2644 NULL, b, NULL);
2645 humidity_str(bp[8], true, b, blen);
2646 sgj_pr_hr(jsp, " %s: %s\n", horhlt, b);
2647 js_snakenv_ihexstr_nex(jsp, jo3p, horhlt, bp[8], false,
2648 NULL, b, NULL);
2649 humidity_str(bp[9], true, b, blen);
2650 sgj_pr_hr(jsp, " %s: %s\n", horhlr, b);
2651 js_snakenv_ihexstr_nex(jsp, jo3p, horhlr, bp[9], false,
2652 NULL, b, NULL);
2653 humidity_str(bp[10], true, b, blen);
2654 sgj_pr_hr(jsp, " %s: %s\n", lorhlr, b);
2655 js_snakenv_ihexstr_nex(jsp, jo3p, lorhlr, bp[10], false,
2656 NULL, b, NULL);
2657 humidity_str(bp[11], true, b, blen);
2658 sgj_pr_hr(jsp, " %s: %s\n", lorhlt, b);
2659 js_snakenv_ihexstr_nex(jsp, jo3p, lorhlt, bp[11], false,
2660 NULL, b, NULL);
2661 } else
2662 sgj_pr_hr(jsp, " <<unexpected %s 0x%x\n", param_c, pc);
2663 if (op->do_pcb)
2664 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2],
2665 str, sizeof(str)));
2666 inner:
2667 if (jsp->pr_as_json)
2668 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
2669 if (op->filter_given)
2670 break;
2671 skip:
2672 num -= pl;
2673 bp += pl;
2674 }
2675 return true;
2676 }
2677
2678 /* CMD_DUR_LIMITS_SUBPG [0x19,0x21] <cdl>
2679 * introduced: SPC-6 rev 1, significantly changed rev 6 */
2680 static bool
show_cmd_dur_limits_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)2681 show_cmd_dur_limits_page(const uint8_t * resp, int len,
2682 struct opts_t * op, sgj_opaque_p jop)
2683 {
2684 int num, pl, pc;
2685 uint32_t count, noitmc_v, noatmc_v, noitatmc_v, noc_v;
2686 const uint8_t * bp;
2687 const char * cp;
2688 const char * thp;
2689 sgj_state * jsp = &op->json_st;
2690 sgj_opaque_p jo2p;
2691 sgj_opaque_p jo3p = NULL;
2692 sgj_opaque_p jap = NULL;
2693 char str[PCB_STR_LEN];
2694 char b[144];
2695 static const char * cdllp = "Command duration limits statistics log page";
2696 static const char * t2cdld = "T2 command duration limit descriptor";
2697 static const char * cdlt2amp = "CDL T2A mode page";
2698 static const char * cdlt2bmp = "CDL T2B mode page";
2699 static const char * first_7[] = {"First", "Second", "Third", "Fourth",
2700 "Fifth", "Sixth", "Seventh"};
2701 static const char * noitmc = "Number of inactive target miss commands";
2702 static const char * noatmc = "Number of active target miss commands";
2703 static const char * noitatmc =
2704 "Number of inactive target and active target miss commands";
2705 static const char * noc = "Number of commands";
2706
2707 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
2708 sgj_pr_hr(jsp, "%s [0x19,0x21]\n", cdllp);
2709 num = len - 4;
2710 bp = &resp[0] + 4;
2711 if (jsp->pr_as_json) {
2712 jo2p = sg_log_js_hdr(jsp, jop, cdllp, resp);
2713 jap = sgj_named_subarray_r(jsp, jo2p,
2714 "command_duration_limits_statistcs_log_parameters");
2715 }
2716
2717 while (num > 3) {
2718 pc = sg_get_unaligned_be16(bp + 0);
2719 pl = bp[3] + 4; /* parameter length */
2720 if (op->filter_given) {
2721 if (pc != op->filter)
2722 goto skip;
2723 }
2724 if (op->do_raw) {
2725 dStrRaw(bp, pl);
2726 break;
2727 } else if (op->do_hex) {
2728 hex2stdout(bp, pl, op->dstrhex_no_ascii);
2729 break;
2730 }
2731 if (jsp->pr_as_json) {
2732 jo3p = sgj_new_unattached_object_r(jsp);
2733 if (op->do_pcb)
2734 js_pcb(jsp, jo3p, bp[2]);
2735 }
2736
2737 switch (pc) {
2738 case 0x1:
2739 /* spc6r06: table 349 name "Number of READ commands" seems to
2740 * be wrong. Use what surrounding text and table 347 suggest */
2741 cp = "Achievable latency target";
2742 count = sg_get_unaligned_be32(bp + 4);
2743 sgj_pr_hr(jsp, " %s = %" PRIu32 "\n", cp, count);
2744 if (jsp->pr_as_json) {
2745 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, cp);
2746 js_snakenv_ihexstr_nex(jsp, jop, cp, count, true, NULL, NULL,
2747 "unit: microsecond");
2748 }
2749 break;
2750 case 0x11:
2751 case 0x12:
2752 case 0x13:
2753 case 0x14:
2754 case 0x15:
2755 case 0x16:
2756 case 0x17:
2757 sgj_pr_hr(jsp, " %s code 0x%x restricted\n", param_c, pc);
2758 if (jsp->pr_as_json)
2759 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, rstrict_s);
2760 break;
2761 case 0x21:
2762 case 0x22:
2763 case 0x23:
2764 case 0x24:
2765 case 0x25:
2766 case 0x26:
2767 case 0x27:
2768 thp = first_7[pc - 0x21];
2769 sgj_pr_hr(jsp, " %s %s for %s [pc=0x%x]:\n", thp, t2cdld,
2770 cdlt2amp, pc);
2771 noitmc_v = sg_get_unaligned_be32(bp + 4);
2772 sgj_pr_hr(jsp, " %s = %u\n", noitmc, noitmc_v);
2773 noatmc_v = sg_get_unaligned_be32(bp + 8);
2774 sgj_pr_hr(jsp, " %s = %u\n", noatmc, noatmc_v);
2775 noitatmc_v = sg_get_unaligned_be32(bp + 12);
2776 sgj_pr_hr(jsp, " %s = %u\n", noitatmc, noitatmc_v);
2777 noc_v = sg_get_unaligned_be32(bp + 16);
2778 sgj_pr_hr(jsp, " %s = %u\n", noc, noc_v);
2779 if (jsp->pr_as_json) {
2780 snprintf(b, sizeof(b), "%s %s for %s", thp, t2cdld, cdlt2amp);
2781 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, b);
2782
2783 js_snakenv_ihexstr_nex(jsp, jop, noitmc, noitmc_v, true, NULL,
2784 NULL, NULL);
2785 js_snakenv_ihexstr_nex(jsp, jop, noatmc, noatmc_v, true, NULL,
2786 NULL, NULL);
2787 js_snakenv_ihexstr_nex(jsp, jop, noitatmc, noitatmc_v, true,
2788 NULL, NULL, NULL);
2789 js_snakenv_ihexstr_nex(jsp, jop, noc, noc_v, true, NULL,
2790 NULL, NULL);
2791 }
2792 break;
2793 case 0x31:
2794 case 0x32:
2795 case 0x33:
2796 case 0x34:
2797 case 0x35:
2798 case 0x36:
2799 case 0x37:
2800 sgj_pr_hr(jsp, " %s 0x%x restricted\n", param_c, pc);
2801 if (jsp->pr_as_json)
2802 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, rstrict_s);
2803 break;
2804 case 0x41:
2805 case 0x42:
2806 case 0x43:
2807 case 0x44:
2808 case 0x45:
2809 case 0x46:
2810 case 0x47:
2811 /* This short form introduced in draft spc6r06 */
2812 thp = first_7[pc - 0x41];
2813 sgj_pr_hr(jsp, " %s %s for %s [pc=0x%x]:\n", thp, t2cdld,
2814 cdlt2bmp, pc);
2815 noitmc_v = sg_get_unaligned_be32(bp + 4);
2816 sgj_pr_hr(jsp, " %s = %u\n", noitmc, noitmc_v);
2817 noatmc_v = sg_get_unaligned_be32(bp + 8);
2818 sgj_pr_hr(jsp, " %s = %u\n", noatmc, noatmc_v);
2819 noitatmc_v = sg_get_unaligned_be32(bp + 12);
2820 sgj_pr_hr(jsp, " %s = %u\n", noitatmc, noitatmc_v);
2821 noc_v = sg_get_unaligned_be32(bp + 16);
2822 sgj_pr_hr(jsp, " %s = %u\n", noc, noc_v);
2823 if (jsp->pr_as_json) {
2824 snprintf(b, sizeof(b), "%s %s for %s", thp, t2cdld, cdlt2amp);
2825 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, b);
2826
2827 js_snakenv_ihexstr_nex(jsp, jop, noitmc, noitmc_v, true, NULL,
2828 NULL, NULL);
2829 js_snakenv_ihexstr_nex(jsp, jop, noatmc, noatmc_v, true, NULL,
2830 NULL, NULL);
2831 js_snakenv_ihexstr_nex(jsp, jop, noitatmc, noitatmc_v, true,
2832 NULL, NULL, NULL);
2833 js_snakenv_ihexstr_nex(jsp, jop, noc, noc_v, true, NULL,
2834 NULL, NULL);
2835 }
2836
2837 break;
2838 default:
2839 sgj_pr_hr(jsp, " <<unexpected %s 0x%x\n", param_c, pc);
2840 break;
2841 }
2842 if (op->do_pcb)
2843 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2],
2844 str, sizeof(str)));
2845 if (jsp->pr_as_json)
2846 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
2847 if (op->filter_given)
2848 break;
2849 skip:
2850 num -= pl;
2851 bp += pl;
2852 }
2853 return true;
2854 }
2855
2856 /* Tape usage: Vendor specific (LTO-5 and LTO-6): 0x30 */
2857 static bool
show_tape_usage_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)2858 show_tape_usage_page(const uint8_t * resp, int len, struct opts_t * op,
2859 sgj_opaque_p jop)
2860 {
2861 int k, num, extra;
2862 unsigned int n;
2863 uint64_t ull;
2864 const uint8_t * bp;
2865 char str[PCB_STR_LEN];
2866
2867 if (jop) { };
2868 num = len - 4;
2869 bp = &resp[0] + 4;
2870 if (num < 4) {
2871 pr2serr("badly formed tape usage page\n");
2872 return false;
2873 }
2874 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
2875 printf("Tape usage page (LTO-5 and LTO-6 specific) [0x30]\n");
2876 for (k = num; k > 0; k -= extra, bp += extra) {
2877 int pc = sg_get_unaligned_be16(bp + 0);
2878
2879 extra = bp[3] + 4;
2880 if (op->filter_given) {
2881 if (pc != op->filter)
2882 continue;
2883 }
2884 if (op->do_raw) {
2885 dStrRaw(bp, extra);
2886 break;
2887 } else if (op->do_hex) {
2888 hex2stdout(bp, extra, op->dstrhex_no_ascii);
2889 break;
2890 }
2891 ull = n = 0;
2892 switch (bp[3]) {
2893 case 2:
2894 n = sg_get_unaligned_be16(bp + 4);
2895 break;
2896 case 4:
2897 n = sg_get_unaligned_be32(bp + 4);
2898 break;
2899 case 8:
2900 ull = sg_get_unaligned_be64(bp + 4);
2901 break;
2902 }
2903 switch (pc) {
2904 case 0x01:
2905 if (extra == 8)
2906 printf(" Thread count: %u", n);
2907 break;
2908 case 0x02:
2909 if (extra == 12)
2910 printf(" Total data sets written: %" PRIu64, ull);
2911 break;
2912 case 0x03:
2913 if (extra == 8)
2914 printf(" Total write retries: %u", n);
2915 break;
2916 case 0x04:
2917 if (extra == 6)
2918 printf(" Total unrecovered write errors: %u", n);
2919 break;
2920 case 0x05:
2921 if (extra == 6)
2922 printf(" Total suspended writes: %u", n);
2923 break;
2924 case 0x06:
2925 if (extra == 6)
2926 printf(" Total fatal suspended writes: %u", n);
2927 break;
2928 case 0x07:
2929 if (extra == 12)
2930 printf(" Total data sets read: %" PRIu64, ull);
2931 break;
2932 case 0x08:
2933 if (extra == 8)
2934 printf(" Total read retries: %u", n);
2935 break;
2936 case 0x09:
2937 if (extra == 6)
2938 printf(" Total unrecovered read errors: %u", n);
2939 break;
2940 case 0x0a:
2941 if (extra == 6)
2942 printf(" Total suspended reads: %u", n);
2943 break;
2944 case 0x0b:
2945 if (extra == 6)
2946 printf(" Total fatal suspended reads: %u", n);
2947 break;
2948 default:
2949 printf(" unknown %s = 0x%x, contents in hex:\n", param_c, pc);
2950 hex2stdout(bp, extra, 1);
2951 break;
2952 }
2953 printf("\n");
2954 if (op->do_pcb)
2955 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
2956 if (op->filter_given)
2957 break;
2958 }
2959 return true;
2960 }
2961
2962 /* 0x30 */
2963 static bool
show_hgst_perf_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)2964 show_hgst_perf_page(const uint8_t * resp, int len, struct opts_t * op,
2965 sgj_opaque_p jop)
2966 {
2967 bool valid = false;
2968 int num, pl;
2969 const uint8_t * bp;
2970 char str[PCB_STR_LEN];
2971
2972 if (jop) { };
2973 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
2974 printf("HGST/WDC performance counters page [0x30]\n");
2975 num = len - 4;
2976 if (num < 0x30) {
2977 printf("HGST/WDC performance counters page too short (%d) < 48\n",
2978 num);
2979 return valid;
2980 }
2981 bp = &resp[0] + 4;
2982 while (num > 3) {
2983 int pc = sg_get_unaligned_be16(bp + 0);
2984
2985 pl = bp[3] + 4;
2986 if (op->filter_given) {
2987 if (pc != op->filter)
2988 goto skip;
2989 }
2990 if (op->do_raw) {
2991 dStrRaw(bp, pl);
2992 break;
2993 } else if (op->do_hex) {
2994 hex2stdout(bp, pl, op->dstrhex_no_ascii);
2995 break;
2996 }
2997 switch (pc) {
2998 case 0:
2999 valid = true;
3000 printf(" Zero Seeks = %u\n", sg_get_unaligned_be16(bp + 4));
3001 printf(" Seeks >= 2/3 = %u\n", sg_get_unaligned_be16(bp + 6));
3002 printf(" Seeks >= 1/3 and < 2/3 = %u\n",
3003 sg_get_unaligned_be16(bp + 8));
3004 printf(" Seeks >= 1/6 and < 1/3 = %u\n",
3005 sg_get_unaligned_be16(bp + 10));
3006 printf(" Seeks >= 1/12 and < 1/6 = %u\n",
3007 sg_get_unaligned_be16(bp + 12));
3008 printf(" Seeks > 0 and < 1/12 = %u\n",
3009 sg_get_unaligned_be16(bp + 14));
3010 printf(" Overrun Counter = %u\n",
3011 sg_get_unaligned_be16(bp + 20));
3012 printf(" Underrun Counter = %u\n",
3013 sg_get_unaligned_be16(bp + 22));
3014 printf(" Device Cache Full Read Hits = %u\n",
3015 sg_get_unaligned_be32(bp + 24));
3016 printf(" Device Cache Partial Read Hits = %u\n",
3017 sg_get_unaligned_be32(bp + 28));
3018 printf(" Device Cache Write Hits = %u\n",
3019 sg_get_unaligned_be32(bp + 32));
3020 printf(" Device Cache Fast Writes = %u\n",
3021 sg_get_unaligned_be32(bp + 36));
3022 printf(" Device Cache Read Misses = %u\n",
3023 sg_get_unaligned_be32(bp + 40));
3024 break;
3025 default:
3026 valid = false;
3027 printf(" Unknown HGST/WDC %s = 0x%x", param_c, pc);
3028 break;
3029 }
3030 if (op->do_pcb)
3031 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
3032 if (op->filter_given)
3033 break;
3034 skip:
3035 num -= pl;
3036 bp += pl;
3037 }
3038 return valid;
3039 }
3040
3041 /* Tape capacity: vendor specific (LTO-5 and LTO-6 ?): 0x31 */
3042 static bool
show_tape_capacity_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)3043 show_tape_capacity_page(const uint8_t * resp, int len,
3044 struct opts_t * op, sgj_opaque_p jop)
3045 {
3046 int k, num, extra;
3047 unsigned int n;
3048 const uint8_t * bp;
3049 char str[PCB_STR_LEN];
3050
3051 if (jop) { };
3052 num = len - 4;
3053 bp = &resp[0] + 4;
3054 if (num < 4) {
3055 pr2serr("badly formed tape capacity page\n");
3056 return false;
3057 }
3058 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
3059 printf("Tape capacity page (LTO-5 and LTO-6 specific) [0x31]\n");
3060 for (k = num; k > 0; k -= extra, bp += extra) {
3061 int pc = sg_get_unaligned_be16(bp + 0);
3062
3063 extra = bp[3] + 4;
3064 if (op->filter_given) {
3065 if (pc != op->filter)
3066 continue;
3067 }
3068 if (op->do_raw) {
3069 dStrRaw(bp, extra);
3070 break;
3071 } else if (op->do_hex) {
3072 hex2stdout(bp, extra, op->dstrhex_no_ascii);
3073 break;
3074 }
3075 if (extra != 8)
3076 continue;
3077 n = sg_get_unaligned_be32(bp + 4);
3078 switch (pc) {
3079 case 0x01:
3080 printf(" Main partition remaining capacity (in MiB): %u", n);
3081 break;
3082 case 0x02:
3083 printf(" Alternate partition remaining capacity (in MiB): %u", n);
3084 break;
3085 case 0x03:
3086 printf(" Main partition maximum capacity (in MiB): %u", n);
3087 break;
3088 case 0x04:
3089 printf(" Alternate partition maximum capacity (in MiB): %u", n);
3090 break;
3091 default:
3092 printf(" unknown %s = 0x%x, contents in hex:\n", param_c, pc);
3093 hex2stdout(bp, extra, 1);
3094 break;
3095 }
3096 printf("\n");
3097 if (op->do_pcb)
3098 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
3099 if (op->filter_given)
3100 break;
3101 }
3102 return true;
3103 }
3104
3105 /* Data compression: originally vendor specific 0x32 (LTO-5), then
3106 * ssc-4 standardizes it at 0x1b <dc> */
3107 static bool
show_data_compression_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)3108 show_data_compression_page(const uint8_t * resp, int len,
3109 struct opts_t * op, sgj_opaque_p jop)
3110 {
3111 int k, j, pl, num, extra, pc, pg_code;
3112 uint64_t n;
3113 const uint8_t * bp;
3114 char str[PCB_STR_LEN];
3115
3116 if (jop) { };
3117 pg_code = resp[0] & 0x3f;
3118 num = len - 4;
3119 bp = &resp[0] + 4;
3120 if (num < 4) {
3121 pr2serr("badly formed data compression page\n");
3122 return false;
3123 }
3124 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex))) {
3125 if (0x1b == pg_code)
3126 printf("Data compression page (ssc-4) [0x1b]\n");
3127 else
3128 printf("Data compression page (LTO-5 specific) [0x%x]\n",
3129 pg_code);
3130 }
3131 for (k = num; k > 0; k -= extra, bp += extra) {
3132 pc = sg_get_unaligned_be16(bp + 0);
3133 pl = bp[3];
3134 extra = pl + 4;
3135 if (op->filter_given) {
3136 if (pc != op->filter)
3137 continue;
3138 }
3139 if (op->do_raw) {
3140 dStrRaw(bp, extra);
3141 break;
3142 } else if (op->do_hex) {
3143 hex2stdout(bp, extra, op->dstrhex_no_ascii);
3144 break;
3145 }
3146 if ((0 == pl) || (pl > 8)) {
3147 printf("badly formed data compression log parameter\n");
3148 printf(" %s = 0x%x, contents in hex:\n", param_c, pc);
3149 hex2stdout(bp, extra, op->dstrhex_no_ascii);
3150 goto skip_para;
3151 }
3152 /* variable length integer, max length 8 bytes */
3153 for (j = 0, n = 0; j < pl; ++j) {
3154 if (j > 0)
3155 n <<= 8;
3156 n |= bp[4 + j];
3157 }
3158 switch (pc) {
3159 case 0x00:
3160 printf(" Read compression ratio x100: %" PRIu64 , n);
3161 break;
3162 case 0x01:
3163 printf(" Write compression ratio x100: %" PRIu64 , n);
3164 break;
3165 case 0x02:
3166 printf(" Megabytes transferred to server: %" PRIu64 , n);
3167 break;
3168 case 0x03:
3169 printf(" Bytes transferred to server: %" PRIu64 , n);
3170 break;
3171 case 0x04:
3172 printf(" Megabytes read from tape: %" PRIu64 , n);
3173 break;
3174 case 0x05:
3175 printf(" Bytes read from tape: %" PRIu64 , n);
3176 break;
3177 case 0x06:
3178 printf(" Megabytes transferred from server: %" PRIu64 , n);
3179 break;
3180 case 0x07:
3181 printf(" Bytes transferred from server: %" PRIu64 , n);
3182 break;
3183 case 0x08:
3184 printf(" Megabytes written to tape: %" PRIu64 , n);
3185 break;
3186 case 0x09:
3187 printf(" Bytes written to tape: %" PRIu64 , n);
3188 break;
3189 case 0x100:
3190 printf(" Data compression enabled: 0x%" PRIx64, n);
3191 break;
3192 default:
3193 printf(" unknown %s = 0x%x, contents in hex:\n", param_c, pc);
3194 hex2stdout(bp, extra, op->dstrhex_no_ascii);
3195 break;
3196 }
3197 skip_para:
3198 printf("\n");
3199 if (op->do_pcb)
3200 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
3201 if (op->filter_given)
3202 break;
3203 }
3204 return true;
3205 }
3206
3207 /* LAST_N_ERR_LPAGE [0x7] <lne> introduced: SPC-2 */
3208 static bool
show_last_n_error_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)3209 show_last_n_error_page(const uint8_t * resp, int len,
3210 struct opts_t * op, sgj_opaque_p jop)
3211 {
3212 int k, num, pl;
3213 const uint8_t * bp;
3214 sgj_state * jsp = &op->json_st;
3215 sgj_opaque_p jo2p;
3216 sgj_opaque_p jo3p = NULL;
3217 sgj_opaque_p jap = NULL;
3218 char str[PCB_STR_LEN];
3219 char b[256];
3220 static const char * lneelp = "Last n error events log page";
3221 static const char * eed = "error_event_data";
3222
3223 num = len - 4;
3224 bp = &resp[0] + 4;
3225 if (num < 4) {
3226 sgj_pr_hr(jsp, "No error events logged\n");
3227 return true;
3228 }
3229 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
3230 sgj_pr_hr(jsp, "%s [0x7]\n", lneelp);
3231 if (jsp->pr_as_json) {
3232 jo2p = sg_log_js_hdr(jsp, jop, lneelp, resp);
3233 jap = sgj_named_subarray_r(jsp, jo2p, "error_event_log_parameters");
3234 }
3235
3236 for (k = num; k > 0; k -= pl, bp += pl) {
3237 uint16_t pc;
3238
3239 if (k < 3) {
3240 pr2serr("short %s\n", lneelp);
3241 return false;
3242 }
3243 pl = bp[3] + 4;
3244 pc = sg_get_unaligned_be16(bp + 0);
3245 if (op->filter_given) {
3246 if (pc != op->filter)
3247 continue;
3248 }
3249 if (op->do_raw) {
3250 dStrRaw(bp, pl);
3251 break;
3252 } else if (op->do_hex) {
3253 hex2stdout(bp, pl, op->dstrhex_no_ascii);
3254 break;
3255 }
3256 if (jsp->pr_as_json) {
3257 jo3p = sgj_new_unattached_object_r(jsp);
3258 if (op->do_pcb)
3259 js_pcb(jsp, jo3p, bp[2]);
3260 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, NULL);
3261 }
3262
3263 sgj_pr_hr(jsp, " Error event %u [0x%x]:\n", pc, pc);
3264 if (pl > 4) {
3265 if ((bp[2] & 0x1) && (bp[2] & 0x2)) {
3266 sgj_pr_hr(jsp, " [binary]:\n");
3267 hex2str(bp + 4, pl - 4, " ", op->hex2str_oformat,
3268 sizeof(b), b);
3269 sgj_pr_hr(jsp, "%s\n", b);
3270 if (jsp->pr_as_json)
3271 sgj_js_nv_hex_bytes(jsp, jo3p, eed, bp + 4, pl - 4);
3272 } else if (0x01 == (bp[2] & 0x3)) { /* ASCII */
3273 sgj_pr_hr(jsp, " %.*s\n", pl - 4, (const char *)(bp + 4));
3274 if (jsp->pr_as_json)
3275 sgj_js_nv_s_len(jsp, jo3p, eed,
3276 (const char *)(bp + 4), pl - 4);
3277 } else {
3278 sgj_pr_hr(jsp, " [data counter?? (LP bit should be "
3279 "set)]:\n");
3280 hex2str(bp + 4, pl - 4, " ", op->hex2str_oformat,
3281 sizeof(b), b);
3282 sgj_pr_hr(jsp, "%s\n", b);
3283 if (jsp->pr_as_json)
3284 sgj_js_nv_hex_bytes(jsp, jo3p, eed, bp + 4, pl - 4);
3285 }
3286 }
3287 if (op->do_pcb)
3288 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2],
3289 str, sizeof(str)));
3290 if (jsp->pr_as_json)
3291 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
3292 if (op->filter_given)
3293 break;
3294 }
3295 return true;
3296 }
3297
3298 /* LAST_N_DEFERRED_LPAGE [0xb] <lnd> introduced: SPC-2 */
3299 static bool
show_last_n_deferred_error_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)3300 show_last_n_deferred_error_page(const uint8_t * resp, int len,
3301 struct opts_t * op, sgj_opaque_p jop)
3302 {
3303 int k, n, num, pl;
3304 const uint8_t * bp;
3305 sgj_state * jsp = &op->json_st;
3306 sgj_opaque_p jo2p, jo4p;
3307 sgj_opaque_p jo3p = NULL;
3308 sgj_opaque_p jap = NULL;
3309 char str[PCB_STR_LEN];
3310 char b[512];
3311 static const char * lndeoaelp =
3312 "Last n deferred errors or asynchronous events log page";
3313 static const char * deoae = "Deferred error or asynchronous event";
3314 static const char * sd = "sense_data";
3315
3316 num = len - 4;
3317 bp = &resp[0] + 4;
3318 if (num < 4) {
3319 pr2serr("No deferred errors logged\n");
3320 return true;
3321 }
3322 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
3323 sgj_pr_hr(jsp, "%s [0xb]\n", lndeoaelp);
3324 if (jsp->pr_as_json) {
3325 jo2p = sg_log_js_hdr(jsp, jop, lndeoaelp, resp);
3326 jap = sgj_named_subarray_r(jsp, jo2p,
3327 "deferred_error_or_asynchronous_event_log_parameters");
3328 }
3329
3330 for (k = num; k > 0; k -= pl, bp += pl) {
3331 int pc;
3332
3333 if (k < 3) {
3334 pr2serr("short %s\n", lndeoaelp);
3335 return false;
3336 }
3337 pl = bp[3] + 4;
3338 pc = sg_get_unaligned_be16(bp + 0);
3339 if (op->filter_given) {
3340 if (pc != op->filter)
3341 continue;
3342 }
3343 if (op->do_raw) {
3344 dStrRaw(bp, pl);
3345 break;
3346 } else if (op->do_hex) {
3347 hex2stdout(bp, pl, op->dstrhex_no_ascii);
3348 break;
3349 }
3350 if (jsp->pr_as_json) {
3351 jo3p = sgj_new_unattached_object_r(jsp);
3352 if (op->do_pcb)
3353 js_pcb(jsp, jo3p, bp[2]);
3354 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, deoae);
3355 }
3356 sgj_pr_hr(jsp, " %s [0x%x]:\n", deoae, pc);
3357 if (op->do_brief > 0) {
3358 hex2stdout(bp + 4, pl - 4, op->dstrhex_no_ascii);
3359 hex2str(bp + 4, pl - 4, " ", op->hex2str_oformat,
3360 sizeof(b), b);
3361 sgj_pr_hr(jsp, "%s\n", b);
3362 if (jsp->pr_as_json)
3363 sgj_js_nv_hex_bytes(jsp, jo3p, sd, bp + 4, pl - 4);
3364 } else {
3365
3366 n = sg_get_sense_str(" ", bp + 4, pl - 4, false, sizeof(b),
3367 b);
3368 sgj_pr_hr(jsp, "%.*s\n", n, b);
3369 if (jsp->pr_as_json) {
3370 jo4p = sgj_named_subobject_r(jsp, jo3p, sd);
3371 sgj_js_sense(jsp, jo4p, bp + 4, pl - 4);
3372 }
3373 }
3374 if (op->do_pcb)
3375 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2],
3376 str, sizeof(str)));
3377 if (jsp->pr_as_json)
3378 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
3379 if (op->filter_given)
3380 break;
3381 }
3382 return true;
3383 }
3384
3385 static const char * clgc = "Change list generation code";
3386 static const char * cgn = "Changed generation number";
3387
3388 /* LAST_N_INQUIRY_DATA_CH_SUBPG [0xb,0x1] <lnic> introduced: SPC-5 (rev 17) */
3389 static bool
show_last_n_inq_data_ch_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)3390 show_last_n_inq_data_ch_page(const uint8_t * resp, int len,
3391 struct opts_t * op, sgj_opaque_p jop)
3392 {
3393 bool vpd;
3394 int j, num, pl, vpd_pg;
3395 uint32_t k, n;
3396 const uint8_t * bp;
3397 const char * vpd_pg_name = NULL;
3398 sgj_state * jsp = &op->json_st;
3399 sgj_opaque_p jo2p, jo4p;
3400 sgj_opaque_p jo3p = NULL;
3401 sgj_opaque_p jap = NULL;
3402 sgj_opaque_p ja2p;
3403 char str[PCB_STR_LEN];
3404 char b[128];
3405 static const char * lnidclp = "Last n inquiry data changed log page";
3406 static const char * idci = "Inquiry data changed indicator";
3407
3408 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
3409 sgj_pr_hr(jsp, "%s [0xb,0x1]\n", lnidclp);
3410 num = len - 4;
3411 bp = &resp[0] + 4;
3412 if (jsp->pr_as_json) {
3413 jo2p = sg_log_js_hdr(jsp, jop, lnidclp, resp);
3414 jap = sgj_named_subarray_r(jsp, jo2p,
3415 "inquiry_data_changed_log_parameters");
3416 }
3417
3418 while (num > 3) {
3419 int pc = sg_get_unaligned_be16(bp + 0);
3420
3421 pl = bp[3] + 4;
3422 if (op->filter_given) {
3423 if (pc != op->filter)
3424 goto skip;
3425 }
3426 if (op->do_raw) {
3427 dStrRaw(bp, pl);
3428 break;
3429 } else if (op->do_hex) {
3430 hex2stdout(bp, pl, op->dstrhex_no_ascii);
3431 break;
3432 }
3433 if (jsp->pr_as_json) {
3434 jo3p = sgj_new_unattached_object_r(jsp);
3435 if (op->do_pcb)
3436 js_pcb(jsp, jo3p, bp[2]);
3437 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
3438 0 == pc ? clgc : idci);
3439 }
3440 if (0 == pc) {
3441 if (pl < 8) {
3442 pr2serr(" <<expect parameter 0x%x to be at least 8 bytes "
3443 "long, got %d, skip>>\n", pc, pl);
3444 goto skip;
3445 }
3446 sgj_pr_hr(jsp, " %s [pc=0x0]:\n", clgc);
3447 for (j = 4, k = 1; j < pl; j +=4, ++k) {
3448 n = sg_get_unaligned_be32(bp + j);
3449 sgj_pr_hr(jsp, " %s [0x%x]: %u\n", cgn, k, n);
3450 }
3451 if (jsp->pr_as_json) {
3452 ja2p = sgj_named_subarray_r(jsp, jo3p,
3453 "changed_generation_numbers");
3454 for (j = 4, k = 1; j < pl; j +=4, ++k) {
3455 jo4p = sgj_new_unattached_object_r(jsp);
3456 n = sg_get_unaligned_be32(bp + j);
3457 js_snakenv_ihexstr_nex(jsp, jo4p, cgn, n, true, NULL,
3458 NULL, NULL);
3459 sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo4p);
3460 }
3461 }
3462 } else { /* pc > 0x0 */
3463 int m;
3464 const int nn = sg_lib_names_mode_len;
3465 struct sg_lib_simple_value_name_t * nvp = sg_lib_names_vpd_arr;
3466
3467 snprintf(b, sizeof(b), " %s 0x%x, ", param_c, pc);
3468 vpd = !! (1 & *(bp + 4));
3469 vpd_pg = *(bp + 5);
3470 if (vpd) {
3471 for (m = 0; m < nn; ++m, ++nvp) {
3472 if (nvp->value == vpd_pg)
3473 break;
3474 }
3475 vpd_pg_name = (m < nn) ? nvp->name : NULL;
3476 } else
3477 vpd_pg_name = "Standard INQUIRY";
3478
3479 if (jsp->pr_as_json) {
3480 sgj_js_nv_i(jsp, jo3p, "vpd", (int)vpd);
3481 sgj_js_nv_ihex(jsp, jo3p, "changed_page_code", vpd_pg);
3482 if (vpd_pg_name)
3483 sgj_js_nv_s(jsp, jo3p, "changed_page_name", vpd_pg_name);
3484 }
3485 if (vpd) {
3486 sgj_pr_hr(jsp, "%sVPD page 0x%x changed\n", b, vpd_pg);
3487 if (0 == op->do_brief) {
3488 if (vpd_pg_name)
3489 sgj_pr_hr(jsp, " name: %s\n", vpd_pg_name);
3490 }
3491 } else
3492 sgj_pr_hr(jsp, "%sStandard INQUIRY data changed\n", b);
3493 }
3494 if (op->do_pcb)
3495 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2],
3496 str, sizeof(str)));
3497 skip:
3498 if (jsp->pr_as_json)
3499 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
3500 if (op->filter_given)
3501 break;
3502 num -= pl;
3503 bp += pl;
3504 }
3505 return true;
3506 }
3507
3508 /* LAST_N_MODE_PG_DATA_CH_SUBPG [0xb,0x2] <lnmc> introduced: SPC-5 (rev 17) */
3509 static bool
show_last_n_mode_pg_data_ch_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)3510 show_last_n_mode_pg_data_ch_page(const uint8_t * resp, int len,
3511 struct opts_t * op, sgj_opaque_p jop)
3512 {
3513 bool spf;
3514 int j, k, num, pl, pg_code, spg_code;
3515 uint32_t n;
3516 const uint8_t * bp;
3517 const char * mode_pg_name = NULL;
3518 sgj_state * jsp = &op->json_st;
3519 sgj_opaque_p jo2p, jo4p;
3520 sgj_opaque_p jo3p = NULL;
3521 sgj_opaque_p jap = NULL;
3522 sgj_opaque_p ja2p;
3523 char str[PCB_STR_LEN];
3524 char b[128];
3525 static const char * lnmpdclp = "Last n mode page data changed log page";
3526 static const char * mpdci = "Mode page data changed indicator";
3527
3528 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
3529 sgj_pr_hr(jsp, "%s [0xb,0x2]\n", lnmpdclp);
3530 num = len - 4;
3531 bp = &resp[0] + 4;
3532 if (jsp->pr_as_json) {
3533 jo2p = sg_log_js_hdr(jsp, jop, lnmpdclp, resp);
3534 jap = sgj_named_subarray_r(jsp, jo2p,
3535 "mode_page_data_changed_log_parameters");
3536 }
3537
3538 while (num > 3) {
3539 int pc = sg_get_unaligned_be16(bp + 0);
3540
3541 pl = bp[3] + 4;
3542 if (op->filter_given) {
3543 if (pc != op->filter)
3544 goto skip;
3545 }
3546 if (op->do_raw) {
3547 dStrRaw(bp, pl);
3548 break;
3549 } else if (op->do_hex) {
3550 hex2stdout(bp, pl, op->dstrhex_no_ascii);
3551 break;
3552 }
3553 if (jsp->pr_as_json) {
3554 jo3p = sgj_new_unattached_object_r(jsp);
3555 if (op->do_pcb)
3556 js_pcb(jsp, jo3p, bp[2]);
3557 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
3558 0 == pc ? clgc : mpdci);
3559 }
3560 if (0 == pc) { /* Same as LAST_N_INQUIRY_DATA_CH_SUBPG [0xb,0x1] */
3561 if (pl < 8) {
3562 pr2serr(" <<expect parameter 0x%x to be at least 8 bytes "
3563 "long, got %d, skip>>\n", pc, pl);
3564 goto skip;
3565 }
3566 sgj_pr_hr(jsp, " %s [pc=0x0]:\n", clgc);
3567 for (j = 4, k = 1; j < pl; j +=4, ++k) {
3568 n = sg_get_unaligned_be32(bp + j);
3569 sgj_pr_hr(jsp, " %s [0x%x]: %u\n", cgn, k, n);
3570 }
3571 if (jsp->pr_as_json) {
3572 ja2p = sgj_named_subarray_r(jsp, jo3p,
3573 "changed_generation_numbers");
3574 for (j = 4, k = 1; j < pl; j +=4, ++k) {
3575 jo4p = sgj_new_unattached_object_r(jsp);
3576 n = sg_get_unaligned_be32(bp + j);
3577 js_snakenv_ihexstr_nex(jsp, jo4p, cgn, n, true, NULL,
3578 NULL, NULL);
3579 sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo4p);
3580 }
3581 }
3582 } else { /* pc > 0x0 */
3583 int k, val;
3584 const int nn = sg_lib_names_mode_len;
3585 struct sg_lib_simple_value_name_t * nmp = sg_lib_names_mode_arr;
3586
3587 snprintf(b, sizeof(b), " %s 0x%x, ", param_c, pc);
3588 spf = !! (0x40 & *(bp + 4));
3589 pg_code = 0x3f & *(bp + 4);
3590 spg_code = *(bp + 5);
3591 if (spf) /* SPF bit set */
3592 sgj_pr_hr(jsp, "%smode page 0x%x,0%x changed\n", b, pg_code,
3593 spg_code);
3594 else
3595 sgj_pr_hr(jsp, "%smode page 0x%x changed\n", b, pg_code);
3596
3597 val = (pg_code << 8) | spg_code;
3598 for (k = 0; k < nn; ++k, ++nmp) {
3599 if (nmp->value == val)
3600 break;
3601 }
3602 mode_pg_name = (k < nn) ? nmp->name : NULL;
3603 if ((0 == op->do_brief) && mode_pg_name)
3604 sgj_pr_hr(jsp, " name: %s\n", nmp->name);
3605 if (jsp->pr_as_json) {
3606 sgj_js_nv_i(jsp, jo3p, "spf", (int)spf);
3607 sgj_js_nv_ihex(jsp, jo3p, "mode_page_code", pg_code);
3608 sgj_js_nv_ihex(jsp, jo3p, "subpage_code", spg_code);
3609 if (mode_pg_name)
3610 sgj_js_nv_s(jsp, jo3p, "mode_page_name", mode_pg_name);
3611 }
3612 }
3613 if (op->do_pcb)
3614 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2],
3615 str, sizeof(str)));
3616 skip:
3617 if (jsp->pr_as_json)
3618 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
3619 if (op->filter_given)
3620 break;
3621 num -= pl;
3622 bp += pl;
3623 }
3624 return true;
3625 }
3626
3627 static const char * self_test_code[] = {
3628 "default", "background short", "background extended", rsv_s,
3629 "aborted background", "foreground short", "foreground extended",
3630 rsv_s};
3631
3632 static const char * self_test_result[] = {
3633 "completed without error",
3634 "aborted by SEND DIAGNOSTIC",
3635 "aborted other than by SEND DIAGNOSTIC",
3636 "unknown error, unable to complete",
3637 "self test completed with failure in test segment (which one unknown)",
3638 "first segment in self test failed",
3639 "second segment in self test failed",
3640 "another segment in self test failed",
3641 rsv_s, rsv_s, rsv_s, rsv_s, rsv_s, rsv_s,
3642 rsv_s,
3643 "self test in progress"};
3644
3645 /* SELF_TEST_LPAGE [0x10] <str> introduced: SPC-3 */
3646 static bool
show_self_test_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)3647 show_self_test_page(const uint8_t * resp, int len, struct opts_t * op,
3648 sgj_opaque_p jop)
3649 {
3650 bool addr_all_ffs;
3651 int k, num, res, st_c;
3652 unsigned int v;
3653 uint32_t n;
3654 uint64_t ull;
3655 const uint8_t * bp;
3656 sgj_state * jsp = &op->json_st;
3657 sgj_opaque_p jo2p;
3658 sgj_opaque_p jo3p = NULL;
3659 sgj_opaque_p jap = NULL;
3660 char str[PCB_STR_LEN];
3661 char b[80];
3662 static const char * strlp = "Self-test results log page";
3663 static const char * stc_s = "Self-test code";
3664 static const char * str_s = "Self-test result";
3665 static const char * stn_s = "Self-test number";
3666 static const char * apoh = "Accumulated power on hours";
3667
3668 num = len - 4;
3669 if (num < 0x190) {
3670 pr2serr("short %s [length 0x%x rather than 0x190 bytes]\n", strlp,
3671 num);
3672 return false;
3673 }
3674 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
3675 sgj_pr_hr(jsp, "%s [0x10]\n", strlp);
3676 if (jsp->pr_as_json) {
3677 jo2p = sg_log_js_hdr(jsp, jop, strlp, resp);
3678 jap = sgj_named_subarray_r(jsp, jo2p,
3679 "self_test_results_log_parameters");
3680 }
3681
3682 for (k = 0, bp = resp + 4; k < 20; ++k, bp += 20 ) {
3683 int pc = sg_get_unaligned_be16(bp + 0);
3684 int pl = bp[3] + 4;
3685
3686 if (op->filter_given) {
3687 if (pc != op->filter)
3688 continue;
3689 }
3690 if (op->do_raw) {
3691 dStrRaw(bp, pl);
3692 break;
3693 } else if (op->do_hex) {
3694 hex2stdout(bp, pl, op->dstrhex_no_ascii);
3695 break;
3696 }
3697 if (jsp->pr_as_json) {
3698 jo3p = sgj_new_unattached_object_r(jsp);
3699 if (op->do_pcb)
3700 js_pcb(jsp, jo3p, bp[2]);
3701 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
3702 "Self-test results");
3703 }
3704 n = sg_get_unaligned_be16(bp + 6);
3705 if ((0 == n) && (0 == bp[4])) {
3706 if (jsp->pr_as_json)
3707 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
3708 break;
3709 }
3710 sgj_pr_hr(jsp, " %s = %d, accumulated power-on hours = %d\n",
3711 param_c, pc, n);
3712 st_c = (bp[4] >> 5) & 0x7;
3713 sgj_pr_hr(jsp, " %s: %s [%d]\n", stc_s, self_test_code[st_c],
3714 st_c);
3715 res = bp[4] & 0xf;
3716 sgj_pr_hr(jsp, " %s: %s [%d]\n", str_s, self_test_result[res],
3717 res);
3718 if (bp[5])
3719 sgj_pr_hr(jsp, " %s = %d\n", stn_s, (int)bp[5]);
3720 ull = sg_get_unaligned_be64(bp + 8);
3721
3722 addr_all_ffs = sg_all_ffs(bp + 8, 8);
3723 if (! addr_all_ffs) {
3724 addr_all_ffs = false;
3725 if ((res > 0) && ( res < 0xf))
3726 sgj_pr_hr(jsp, " address of first error = 0x%" PRIx64 "\n",
3727 ull);
3728 }
3729 addr_all_ffs = false;
3730 v = bp[16] & 0xf;
3731 if (v) {
3732 if (op->do_brief)
3733 sgj_pr_hr(jsp, " %s = 0x%x , asc = 0x%x, ascq = 0x%x\n",
3734 s_key, v, bp[17], bp[18]);
3735 else {
3736 sgj_pr_hr(jsp, " %s = 0x%x [%s]\n", s_key, v,
3737 sg_get_sense_key_str(v, sizeof(b), b));
3738
3739 sgj_pr_hr(jsp, " asc = 0x%x, ascq = 0x%x [%s]\n",
3740 bp[17], bp[18], sg_get_asc_ascq_str(bp[17], bp[18],
3741 sizeof(b), b));
3742 }
3743 }
3744 if (op->do_pcb)
3745 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2],
3746 str, sizeof(str)));
3747 if (jsp->pr_as_json) {
3748 js_snakenv_ihexstr_nex(jsp, jo3p, stc_s, st_c, true, NULL,
3749 self_test_code[st_c], NULL);
3750 js_snakenv_ihexstr_nex(jsp, jo3p, str_s, res, true, NULL,
3751 self_test_result[res], NULL);
3752 js_snakenv_ihexstr_nex(jsp, jo3p, stn_s, bp[5], false, NULL,
3753 NULL, "segment number that failed");
3754 js_snakenv_ihexstr_nex(jsp, jo3p, apoh, n, true, NULL,
3755 (0xffff == n ? "65535 hours or more" : NULL), NULL);
3756 sgj_js_nv_ihexstr(jsp, jo3p, "address_of_first_failure", pc, NULL,
3757 addr_all_ffs ? "no errors detected" : NULL);
3758 sgj_js_nv_ihexstr(jsp, jo3p, "sense_key", v, NULL,
3759 sg_get_sense_key_str(v, sizeof(b), b));
3760 sgj_js_nv_ihexstr(jsp, jo3p, "additional_sense_code", bp[17],
3761 NULL, NULL);
3762 sgj_js_nv_ihexstr(jsp, jo3p, "additional_sense_code_qualifier",
3763 bp[18], NULL, sg_get_asc_ascq_str(bp[17],
3764 bp[18], sizeof(b), b));
3765 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
3766 }
3767 if (op->filter_given)
3768 break;
3769 }
3770 return true;
3771 }
3772
3773 /* TEMPERATURE_LPAGE [0xd] <temp> introduced: SPC-3
3774 * N.B. The ENV_REPORTING_SUBPG [0xd,0x1] and the ENV_LIMITS_SUBPG [0xd,0x2]
3775 * (both added SPC-5) are a superset of this page. */
3776 static bool
show_temperature_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)3777 show_temperature_page(const uint8_t * resp, int len, struct opts_t * op,
3778 sgj_opaque_p jop)
3779 {
3780 int k, num, extra;
3781 const uint8_t * bp;
3782 sgj_state * jsp = &op->json_st;
3783 sgj_opaque_p jo2p;
3784 sgj_opaque_p jo3p = NULL;
3785 sgj_opaque_p jap = NULL;
3786 char str[PCB_STR_LEN];
3787 static const char * tlp = "Temperature log page";
3788 static const char * ctemp = "Current temperature";
3789 static const char * rtemp = "Reference temperature";
3790
3791 num = len - 4;
3792 bp = &resp[0] + 4;
3793 if (num < 4) {
3794 pr2serr("badly formed Temperature page\n");
3795 return false;
3796 }
3797 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex))) {
3798 if (! op->do_temperature)
3799 sgj_pr_hr(jsp, "%s [0xd]\n", tlp);
3800 }
3801 if (jsp->pr_as_json) {
3802 jo2p = sg_log_js_hdr(jsp, jop, tlp, resp);
3803 jap = sgj_named_subarray_r(jsp, jo2p, "temperature_log_parameters");
3804 }
3805
3806 for (k = num; k > 0; k -= extra, bp += extra) {
3807 int pc;
3808
3809 if (k < 3) {
3810 pr2serr("short Temperature page\n");
3811 return true;
3812 }
3813 extra = bp[3] + 4;
3814 pc = sg_get_unaligned_be16(bp + 0);
3815 if (op->filter_given) {
3816 if (pc != op->filter)
3817 continue;
3818 }
3819 if (op->do_raw) {
3820 dStrRaw(bp, extra);
3821 goto skip;
3822 } else if (op->do_hex) {
3823 hex2stdout(bp, extra, op->dstrhex_no_ascii);
3824 goto skip;
3825 }
3826 if (jsp->pr_as_json) {
3827 jo3p = sgj_new_unattached_object_r(jsp);
3828 if (op->do_pcb)
3829 js_pcb(jsp, jo3p, bp[2]);
3830 sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc);
3831 }
3832
3833 switch (pc) {
3834 case 0:
3835 if ((extra > 5) && (k > 5)) {
3836 if (0 == bp[5])
3837 sgj_pr_hr(jsp, " %s = 0 C (or less)\n", ctemp);
3838 else if (bp[5] < 0xff)
3839 sgj_pr_hr(jsp, " %s = %d C\n", ctemp, bp[5]);
3840 else
3841 sgj_pr_hr(jsp, " %s = <%s>\n", ctemp, not_avail);
3842 if (jsp->pr_as_json) {
3843 const char * cp = NULL;
3844
3845 if (0 == bp[5])
3846 cp = "0 or less Celsius";
3847 else if (0xff == bp[5])
3848 cp = "temperature not available";
3849 js_snakenv_ihexstr_nex(jsp, jo3p, "temperature", bp[5],
3850 false, NULL, cp,
3851 "current [unit: celsius]");
3852 }
3853 }
3854 break;
3855 case 1:
3856 if ((extra > 5) && (k > 5)) {
3857 if (bp[5] < 0xff)
3858 sgj_pr_hr(jsp, " %s = %d C\n", rtemp, bp[5]);
3859 else
3860 sgj_pr_hr(jsp, " %s = <%s>\n", rtemp, not_avail);
3861 if (jsp->pr_as_json) {
3862 const char * cp;
3863
3864 if (0 == bp[5])
3865 cp = "in C (or less)";
3866 else if (0xff == bp[5])
3867 cp = not_avail;
3868 else
3869 cp = "in C";
3870 sgj_js_nv_ihex_nex(jsp, jo3p, "reference_temperature",
3871 bp[5], true, cp);
3872 }
3873 }
3874 break;
3875 default:
3876 if (! op->do_temperature) {
3877 sgj_pr_hr(jsp, " unknown %s = 0x%x, contents in hex:\n",
3878 param_c, pc);
3879 hex2stdout(bp, extra, op->dstrhex_no_ascii);
3880 } else {
3881 if (jsp->pr_as_json)
3882 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
3883 continue;
3884 }
3885 break;
3886 }
3887 if (jsp->pr_as_json)
3888 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
3889 if (op->do_pcb)
3890 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], str,
3891 sizeof(str)));
3892 skip:
3893 if (op->filter_given)
3894 break;
3895 }
3896 return true;
3897 }
3898
3899 /* START_STOP_LPAGE [0xe] <sscc> introduced: SPC-3 */
3900 static bool
show_start_stop_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)3901 show_start_stop_page(const uint8_t * resp, int len, struct opts_t * op,
3902 sgj_opaque_p jop)
3903 {
3904 int k, num, extra;
3905 uint32_t val;
3906 const uint8_t * bp;
3907 sgj_state * jsp = &op->json_st;
3908 sgj_opaque_p jo2p;
3909 sgj_opaque_p jo3p = NULL;
3910 sgj_opaque_p jap = NULL;
3911 char str[PCB_STR_LEN];
3912 char b[256];
3913 static const char * sscclp = "Start-stop cycle counter log page";
3914 static const char * dom = "Date of manufacture";
3915 static const char * ad = "Accounting date";
3916 static const char * sccodl = "Specified cycle count over device lifetime";
3917 static const char * assc = "Accumulated start-stop cycles";
3918 static const char * slucodl =
3919 "Specified load-unload count over device lifetime";
3920 static const char * aluc = "Accumulated load-unload cycles";
3921
3922 num = len - 4;
3923 bp = &resp[0] + 4;
3924 if (num < 4) {
3925 pr2serr("badly formed Start-stop cycle counter page\n");
3926 return false;
3927 }
3928 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
3929 sgj_pr_hr(jsp, "%s [0xe]\n", sscclp);
3930 if (jsp->pr_as_json) {
3931 jo2p = sg_log_js_hdr(jsp, jop, sscclp, resp);
3932 jap = sgj_named_subarray_r(jsp, jo2p,
3933 "start_stop_cycle_log_parameters");
3934 }
3935
3936 for (k = num; k > 0; k -= extra, bp += extra) {
3937 int pc;
3938
3939 if (k < 3) {
3940 pr2serr("short %s\n", sscclp);
3941 return false;
3942 }
3943 extra = bp[3] + 4;
3944 pc = sg_get_unaligned_be16(bp + 0);
3945 if (op->filter_given) {
3946 if (pc != op->filter)
3947 continue;
3948 }
3949 if (op->do_raw) {
3950 dStrRaw(bp, extra);
3951 goto skip;
3952 } else if (op->do_hex) {
3953 hex2stdout(bp, extra, op->dstrhex_no_ascii);
3954 goto skip;
3955 }
3956 if (jsp->pr_as_json) {
3957 jo3p = sgj_new_unattached_object_r(jsp);
3958 if (op->do_pcb)
3959 js_pcb(jsp, jo3p, bp[2]);
3960 }
3961
3962 switch (pc) {
3963 case 1:
3964 if (10 == extra) {
3965 sgj_pr_hr(jsp, " %s, year: %.4s, week: %.2s\n", dom,
3966 bp + 4, bp + 8);
3967 if (jsp->pr_as_json) {
3968 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
3969 "Date of manufacture");
3970 sgj_js_nv_s_len(jsp, jo3p, "year_of_manufacture",
3971 (const char *)(bp + 4), 4);
3972 sgj_js_nv_s_len(jsp, jo3p, "week_of_manufacture",
3973 (const char *)(bp + 8), 2);
3974 }
3975 } else if (op->verbose) {
3976 pr2serr("%s parameter length strange: %d\n", dom, extra - 4);
3977 hex2stderr(bp, extra, 1);
3978 }
3979 break;
3980 case 2:
3981 if (10 == extra) {
3982 sgj_pr_hr(jsp, " %s, year: %.4s, week: %.2s\n", ad, bp + 4,
3983 bp + 8);
3984 if (jsp->pr_as_json) {
3985 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
3986 "Accounting date");
3987 sgj_js_nv_s_len(jsp, jo3p, "year_of_manufacture",
3988 (const char *)(bp + 4), 4);
3989 sgj_js_nv_s_len(jsp, jo3p, "week_of_manufacture",
3990 (const char *)(bp + 8), 2);
3991 }
3992 } else if (op->verbose) {
3993 pr2serr("%s parameter length strange: %d\n", ad, extra - 4);
3994 hex2stderr(bp, extra, 1);
3995 }
3996 break;
3997 case 3:
3998 if (extra > 7) {
3999 val = sg_get_unaligned_be32(bp + 4);
4000 sgj_pr_hr(jsp, " %s = %u\n", sccodl, val);
4001 if (jsp->pr_as_json) {
4002 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
4003 sccodl);
4004 js_snakenv_ihexstr_nex(jsp, jo3p, sccodl, val, false,
4005 NULL, NULL, NULL);
4006 }
4007 }
4008 break;
4009 case 4:
4010 if (extra > 7) {
4011 val = sg_get_unaligned_be32(bp + 4);
4012 sgj_pr_hr(jsp, " %s = %u\n", assc, val);
4013 if (jsp->pr_as_json) {
4014 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
4015 assc);
4016 js_snakenv_ihexstr_nex(jsp, jo3p, assc, val, false,
4017 NULL, NULL, NULL);
4018 }
4019 }
4020 break;
4021 case 5:
4022 if (extra > 7) {
4023 val = sg_get_unaligned_be32(bp + 4);
4024 sgj_pr_hr(jsp, " %s = %u\n", slucodl, val);
4025 if (jsp->pr_as_json) {
4026 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
4027 slucodl);
4028 js_snakenv_ihexstr_nex(jsp, jo3p, slucodl, val, false,
4029 NULL, NULL, NULL);
4030 }
4031 }
4032 break;
4033 case 6:
4034 if (extra > 7) {
4035 val = sg_get_unaligned_be32(bp + 4);
4036 sgj_pr_hr(jsp, " %s = %u\n", aluc, val);
4037 if (jsp->pr_as_json) {
4038 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, aluc);
4039 js_snakenv_ihexstr_nex(jsp, jo3p, aluc, val, false,
4040 NULL, NULL, NULL);
4041 }
4042 }
4043 break;
4044 default:
4045 sgj_pr_hr(jsp, " unknown %s = 0x%x, contents in hex:\n",
4046 param_c, pc);
4047 hex2str(bp, extra, " ", op->hex2str_oformat, sizeof(b), b);
4048 sgj_pr_hr(jsp, "%s\n", b);
4049 if (jsp->pr_as_json) {
4050 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, unknown_s);
4051 sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp, extra);
4052 }
4053 break;
4054 }
4055 if (jsp->pr_as_json)
4056 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
4057 if (op->do_pcb)
4058 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], str,
4059 sizeof(str)));
4060 skip:
4061 if (op->filter_given)
4062 break;
4063 }
4064 return true;
4065 }
4066
4067 /* APP_CLIENT_LPAGE [0xf] <ac> introduced: SPC-3 */
4068 static bool
show_app_client_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)4069 show_app_client_page(const uint8_t * resp, int len, struct opts_t * op,
4070 sgj_opaque_p jop)
4071 {
4072 int k, n, num, extra;
4073 char * mp;
4074 const uint8_t * bp;
4075 sgj_state * jsp = &op->json_st;
4076 sgj_opaque_p jo2p = NULL;
4077 sgj_opaque_p jo3p = NULL;
4078 sgj_opaque_p jap = NULL;
4079 char str[PCB_STR_LEN];
4080 static const char * aclp = "Application Client log page";
4081 static const char * guac = "General Usage Application Client";
4082
4083 num = len - 4;
4084 bp = &resp[0] + 4;
4085 if (num < 4) {
4086 pr2serr("badly formed %s\n", aclp);
4087 return false;
4088 }
4089 if (op->verbose || ((! op->do_raw) && (op->do_hex == 0)))
4090 sgj_pr_hr(jsp, "%s [0xf]\n", aclp);
4091 if (jsp->pr_as_json)
4092 jo2p = sg_log_js_hdr(jsp, jop, aclp, resp);
4093 if ((0 == op->filter_given) && (! op->do_full)) {
4094 if ((len > 128) && (0 == op->do_hex) && (0 == op->undefined_hex)) {
4095 char d[256];
4096
4097 hex2str(resp, 64, " ", op->hex2str_oformat, sizeof(d), d);
4098 sgj_pr_hr(jsp, "%s", d);
4099 sgj_pr_hr(jsp, " ..... [truncated after 64 of %d bytes (use "
4100 "'-H' to see the rest)]\n", len);
4101 if (jsp->pr_as_json) {
4102 sgj_js_nv_ihex(jsp, jo2p, "actual_length", len);
4103 sgj_js_nv_ihex(jsp, jo2p, "truncated_length", 64);
4104 sgj_js_nv_hex_bytes(jsp, jo2p, in_hex, resp, 64);
4105 }
4106 } else {
4107 n = len * 4 + 32;
4108 mp = malloc(n);
4109 if (mp) {
4110 hex2str(resp, len, " ", op->hex2str_oformat, n, mp);
4111 sgj_pr_hr(jsp, "%s", mp);
4112 if (jsp->pr_as_json) {
4113 sgj_js_nv_ihex(jsp, jo2p, "length", len);
4114 sgj_js_nv_hex_bytes(jsp, jo2p, in_hex, resp, len);
4115 }
4116 free(mp);
4117 }
4118 }
4119 return true;
4120 }
4121 if (jsp->pr_as_json)
4122 jap = sgj_named_subarray_r(jsp, jo2p,
4123 "application_client_log_parameters");
4124
4125 /* here if filter_given set or --full given */
4126 for (k = num; k > 0; k -= extra, bp += extra) {
4127 int pc;
4128 char d[1024];
4129
4130 if (k < 3) {
4131 pr2serr("short %s\n", aclp);
4132 return true;
4133 }
4134 extra = bp[3] + 4;
4135 pc = sg_get_unaligned_be16(bp + 0);
4136 if (op->filter_given) {
4137 if (pc != op->filter)
4138 continue;
4139 }
4140 if (op->do_raw) {
4141 dStrRaw(bp, extra);
4142 break;
4143 }
4144 if (jsp->pr_as_json) {
4145 jo3p = sgj_new_unattached_object_r(jsp);
4146 if (op->do_pcb)
4147 js_pcb(jsp, jo3p, bp[2]);
4148 }
4149 sgj_pr_hr(jsp, " %s = %d [0x%x] %s\n", param_c, pc, pc,
4150 (pc <= 0xfff) ? guac : "");
4151 hex2str(bp, extra, " ", op->hex2str_oformat, sizeof(d), d);
4152 sgj_pr_hr(jsp, "%s", d);
4153 if (jsp->pr_as_json) {
4154 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
4155 (pc <= 0xfff) ? guac : NULL);
4156 sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp, extra);
4157 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
4158 }
4159 if (op->do_pcb)
4160 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], str,
4161 sizeof(str)));
4162 if (op->filter_given)
4163 break;
4164 }
4165 return true;
4166 }
4167
4168 /* IE_LPAGE [0x2f] <ie> "Informational Exceptions" introduced: SPC-3
4169 * Previously known as "SMART Status and Temperature Reading" lpage. */
4170 static bool
show_ie_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)4171 show_ie_page(const uint8_t * resp, int len, struct opts_t * op,
4172 sgj_opaque_p jop)
4173 {
4174 bool skip = false;
4175 int k, num, param_len;
4176 const uint8_t * bp;
4177 const char * cp;
4178 sgj_state * jsp = &op->json_st;
4179 sgj_opaque_p jo2p;
4180 sgj_opaque_p jo3p = NULL;
4181 sgj_opaque_p jap = NULL;
4182 char str[PCB_STR_LEN];
4183 char b[512];
4184 char bb[64];
4185 bool full, decoded;
4186 static const char * ielp = "Informational exceptions log page";
4187 static const char * ieasc =
4188 "informational_exceptions_additional_sense_code";
4189 static const char * ct = "Current temperature";
4190 static const char * tt = "Threshold temperature";
4191 static const char * mt = "Maximum temperature";
4192 static const char * ce = "common extension";
4193
4194 full = ! op->do_temperature;
4195 num = len - 4;
4196 bp = &resp[0] + 4;
4197 if (num < 4) {
4198 pr2serr("badly formed %s\n", ielp);
4199 return false;
4200 }
4201 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex))) {
4202 if (full)
4203 sgj_pr_hr(jsp, "%s [0x2f]\n", ielp);
4204 }
4205 if (jsp->pr_as_json) {
4206 jo2p = sg_log_js_hdr(jsp, jop, ielp, resp);
4207 jap = sgj_named_subarray_r(jsp, jo2p,
4208 "informational_exceptions_log_parameters");
4209 }
4210
4211 for (k = num; k > 0; k -= param_len, bp += param_len) {
4212 int pc;
4213
4214 if (k < 3) {
4215 pr2serr("short %s\n", ielp);
4216 return false;
4217 }
4218 param_len = bp[3] + 4;
4219 pc = sg_get_unaligned_be16(bp + 0);
4220 if (op->filter_given) {
4221 if (pc != op->filter)
4222 continue;
4223 }
4224 if (op->do_raw) {
4225 dStrRaw(bp, param_len);
4226 goto skip;
4227 } else if (op->do_hex) {
4228 hex2stdout(bp, param_len, op->dstrhex_no_ascii);
4229 goto skip;
4230 }
4231 if (jsp->pr_as_json) {
4232 jo3p = sgj_new_unattached_object_r(jsp);
4233 if (op->do_pcb)
4234 js_pcb(jsp, jo3p, bp[2]);
4235 }
4236 decoded = true;
4237 cp = NULL;
4238
4239 switch (pc) {
4240 case 0x0:
4241 if (param_len > 5) {
4242 bool na;
4243 uint8_t t;
4244
4245 if (full) {
4246 sgj_pr_hr(jsp, " IE asc = 0x%x, ascq = 0x%x\n", bp[4],
4247 bp[5]);
4248 if (bp[4] || bp[5])
4249 if(sg_get_asc_ascq_str(bp[4], bp[5], sizeof(b), b))
4250 sgj_pr_hr(jsp, " [%s]\n", b);
4251 if (jsp->pr_as_json) {
4252 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
4253 "Informational exceptions general");
4254 sgj_js_nv_ihexstr(jsp, jo3p, ieasc, bp[4], NULL,
4255 NULL);
4256 snprintf(b, sizeof(b), "%s_qualifier", ieasc);
4257 sgj_js_nv_ihexstr(jsp, jo3p, b, bp[5], NULL,
4258 sg_get_asc_ascq_str(bp[4], bp[5],
4259 sizeof(bb), bb));
4260 }
4261 }
4262 if (param_len <= 6)
4263 break;
4264 t = bp[6];
4265 na = (0xff == t);
4266 if (na)
4267 snprintf(b, sizeof(b), "%u C", t);
4268 else
4269 snprintf(b, sizeof(b), "<%s>", unknown_s);
4270 sgj_pr_hr(jsp, " %s = %s\n", ct, b);
4271 if (jsp->pr_as_json)
4272 js_snakenv_ihexstr_nex(jsp, jo3p, ct, t, true,
4273 NULL, na ? unknown_s : NULL,
4274 "[unit: celsius]");
4275 if (param_len > 7) {
4276 t = bp[7];
4277 na = (0xff == t);
4278 if (na)
4279 snprintf(b, sizeof(b), "%u C", t);
4280 else
4281 snprintf(b, sizeof(b), "<%s>", unknown_s);
4282 sgj_pr_hr(jsp, " %s = %s [%s]\n", tt, b, ce);
4283 if (jsp->pr_as_json)
4284 js_snakenv_ihexstr_nex(jsp, jo3p, tt, t, true, NULL,
4285 na ? unknown_s : NULL, ce);
4286 t = bp[8];
4287 if ((param_len > 8) && (t >= bp[6])) {
4288 na = (0xff == t);
4289 if (na)
4290 snprintf(b, sizeof(b), "%u C", t);
4291 else
4292 snprintf(b, sizeof(b), "<%s>", unknown_s);
4293 sgj_pr_hr(jsp, " %s = %s [%s]\n", mt, b, ce);
4294 if (jsp->pr_as_json)
4295 js_snakenv_ihexstr_nex(jsp, jo3p, mt, t, true,
4296 NULL,
4297 na ? unknown_s : NULL, ce);
4298 }
4299 }
4300 }
4301 decoded = true;
4302 break;
4303 default:
4304 if (op->do_brief > 0) {
4305 cp = NULL;
4306 skip = true;
4307 break;
4308 }
4309 if (VP_HITA == op->vend_prod_num) {
4310 switch (pc) {
4311 case 0x1:
4312 cp = "Remaining reserve 1";
4313 break;
4314 case 0x2:
4315 cp = "Remaining reserve XOR";
4316 break;
4317 case 0x3:
4318 cp = "XOR depletion";
4319 break;
4320 case 0x4:
4321 cp = "Volatile memory backup failure";
4322 break;
4323 case 0x5:
4324 cp = "Wear indicator";
4325 break;
4326 case 0x6:
4327 cp = "System area wear indicator";
4328 break;
4329 case 0x7:
4330 cp = "Channel hangs";
4331 break;
4332 case 0x8:
4333 cp = "Flash scan failure";
4334 break;
4335 default:
4336 decoded = false;
4337 break;
4338 }
4339 if (cp) {
4340 sgj_pr_hr(jsp, " %s:\n", cp);
4341 sgj_pr_hr(jsp, " SMART sense_code=0x%x sense_qualifier"
4342 "=0x%x threshold=%d%% trip=%d\n", bp[4], bp[5],
4343 bp[6], bp[7]);
4344 if (jsp->pr_as_json) {
4345 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
4346 cp);
4347 sgj_js_nv_ihex(jsp, jo3p, "smart_sense_code", bp[4]);
4348 sgj_js_nv_ihex(jsp, jo3p, "smart_sense_qualifier",
4349 bp[5]);
4350 sgj_js_nv_ihex(jsp, jo3p, "smart_threshold", bp[6]);
4351 sgj_js_nv_ihex(jsp, jo3p, "smart_trip", bp[7]);
4352 }
4353 }
4354 } else {
4355 decoded = false;
4356 if (jsp->pr_as_json)
4357 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
4358 unknown_s);
4359 }
4360 break;
4361 } /* end of switch statement */
4362 if (skip)
4363 skip = false;
4364 else if ((! decoded) && full) {
4365 hex2str(bp, param_len, " ", op->hex2str_oformat, sizeof(b), b);
4366 sgj_pr_hr(jsp, " %s = 0x%x, contents in hex:\n%s", param_c, pc,
4367 b);
4368 }
4369
4370 if (jsp->pr_as_json)
4371 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
4372 if (op->do_pcb)
4373 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], str,
4374 sizeof(str)));
4375 skip:
4376 if (op->filter_given)
4377 break;
4378 } /* end of for loop */
4379 return true;
4380 }
4381
4382 /* called for SAS port of PROTO_SPECIFIC_LPAGE [0x18] */
4383 static const char *
show_sas_phy_event_info(int pes,unsigned int val,unsigned int thresh_val,char * b,int blen)4384 show_sas_phy_event_info(int pes, unsigned int val, unsigned int thresh_val,
4385 char * b, int blen)
4386 {
4387 int n = 0;
4388 unsigned int u;
4389 const char * cp = "";
4390 static const char * pvdt = "Peak value detector threshold";
4391
4392 switch (pes) {
4393 case 0:
4394 cp = "No event";
4395 snprintf(b, blen, "%s", cp);
4396 break;
4397 case 0x1:
4398 cp = "Invalid word count";
4399 snprintf(b, blen, "%s: %u", cp, val);
4400 break;
4401 case 0x2:
4402 cp = "Running disparity error count";
4403 snprintf(b, blen, "%s: %u", cp, val);
4404 break;
4405 case 0x3:
4406 cp = "Loss of dword synchronization count";
4407 snprintf(b, blen, "%s: %u", cp, val);
4408 break;
4409 case 0x4:
4410 cp = "Phy reset problem count";
4411 snprintf(b, blen, "%s: %u", cp, val);
4412 break;
4413 case 0x5:
4414 cp = "Elasticity buffer overflow count";
4415 snprintf(b, blen, "%s: %u", cp, val);
4416 break;
4417 case 0x6:
4418 cp = "Received ERROR count";
4419 snprintf(b, blen, "%s: %u", cp, val);
4420 break;
4421 case 0x7:
4422 cp = "Invalid SPL packet count";
4423 snprintf(b, blen, "%s: %u", cp, val);
4424 break;
4425 case 0x8:
4426 cp = "Loss of SPL packet synchronization count";
4427 snprintf(b, blen, "%s: %u", cp, val);
4428 break;
4429 case 0x20:
4430 cp = "Received address frame error count";
4431 snprintf(b, blen, "%s: %u", cp, val);
4432 break;
4433 case 0x21:
4434 cp = "Transmitted abandon-class OPEN_REJECT count";
4435 snprintf(b, blen, "%s: %u", cp, val);
4436 break;
4437 case 0x22:
4438 cp = "Received abandon-class OPEN_REJECT count";
4439 snprintf(b, blen, "%s: %u", cp, val);
4440 break;
4441 case 0x23:
4442 cp = "Transmitted retry-class OPEN_REJECT count";
4443 snprintf(b, blen, "%s: %u", cp, val);
4444 break;
4445 case 0x24:
4446 cp = "Received retry-class OPEN_REJECT count";
4447 snprintf(b, blen, "%s: %u", cp, val);
4448 break;
4449 case 0x25:
4450 cp = "Received AIP (WAITING ON PARTIAL) count";
4451 snprintf(b, blen, "%s: %u", cp, val);
4452 break;
4453 case 0x26:
4454 cp = "Received AIP (WAITING ON CONNECTION) count";
4455 snprintf(b, blen, "%s: %u", cp, val);
4456 break;
4457 case 0x27:
4458 cp = "Transmitted BREAK count";
4459 snprintf(b, blen, "%s: %u", cp, val);
4460 break;
4461 case 0x28:
4462 cp = "Received BREAK count";
4463 snprintf(b, blen, "%s: %u", cp, val);
4464 break;
4465 case 0x29:
4466 cp = "Break timeout count";
4467 snprintf(b, blen, "%s: %u", cp, val);
4468 break;
4469 case 0x2a:
4470 cp = "Connection count";
4471 snprintf(b, blen, "%s: %u", cp, val);
4472 break;
4473 case 0x2b:
4474 cp = "Peak transmitted pathway blocked count";
4475 n = sg_scnpr(b, blen, "%s: %u", cp, val & 0xff);
4476 sg_scnpr(b + n, blen - n, "\t%s: %u", pvdt, thresh_val & 0xff);
4477 break;
4478 case 0x2c:
4479 cp = "Peak transmitted arbitration wait time";
4480 u = val & 0xffff;
4481 if (u < 0x8000)
4482 n = sg_scnpr(b, blen, "%s (us): %u", cp, u);
4483 else
4484 n = sg_scnpr(b, blen, "%s (ms): %u", cp, 33 + (u - 0x8000));
4485 u = thresh_val & 0xffff;
4486 if (u < 0x8000)
4487 sg_scnpr(b + n, blen - n, "\t%s (us): %u", pvdt, u);
4488 else
4489 sg_scnpr(b + n, blen - n, "\t%s (ms): %u", pvdt,
4490 33 + (u - 0x8000));
4491 break;
4492 case 0x2d:
4493 cp = "Peak arbitration time";
4494 n = sg_scnpr(b, blen, "%s (us): %u", cp, val);
4495 sg_scnpr(b + n, blen - n, "\t%s: %u", pvdt, thresh_val);
4496 break;
4497 case 0x2e:
4498 cp = "Peak connection time";
4499 n = sg_scnpr(b, blen, "%s (us): %u", cp, val);
4500 sg_scnpr(b + n, blen - n, "\t%s: %u", pvdt, thresh_val);
4501 break;
4502 case 0x2f:
4503 cp = "Persistent connection count";
4504 snprintf(b, blen, "%s: %u", cp, val);
4505 break;
4506 case 0x40:
4507 cp = "Transmitted SSP frame count";
4508 snprintf(b, blen, "%s: %u", cp, val);
4509 break;
4510 case 0x41:
4511 cp = "Received SSP frame count";
4512 snprintf(b, blen, "%s: %u", cp, val);
4513 break;
4514 case 0x42:
4515 cp = "Transmitted SSP frame error count";
4516 snprintf(b, blen, "%s: %u", cp, val);
4517 break;
4518 case 0x43:
4519 cp = "Received SSP frame error count";
4520 snprintf(b, blen, "%s: %u", cp, val);
4521 break;
4522 case 0x44:
4523 cp = "Transmitted CREDIT_BLOCKED count";
4524 snprintf(b, blen, "%s: %u", cp, val);
4525 break;
4526 case 0x45:
4527 cp = "Received CREDIT_BLOCKED count";
4528 snprintf(b, blen, "%s: %u", cp, val);
4529 break;
4530 case 0x50:
4531 cp = "Transmitted SATA frame count";
4532 snprintf(b, blen, "%s: %u", cp, val);
4533 break;
4534 case 0x51:
4535 cp = "Received SATA frame count";
4536 snprintf(b, blen, "%s: %u", cp, val);
4537 break;
4538 case 0x52:
4539 cp = "SATA flow control buffer overflow count";
4540 snprintf(b, blen, "%s: %u", cp, val);
4541 break;
4542 case 0x60:
4543 cp = "Transmitted SMP frame count";
4544 snprintf(b, blen, "%s: %u", cp, val);
4545 break;
4546 case 0x61:
4547 cp = "Received SMP frame count";
4548 snprintf(b, blen, "%s: %u", cp, val);
4549 break;
4550 case 0x63:
4551 cp = "Received SMP frame error count";
4552 snprintf(b, blen, "%s: %u", cp, val);
4553 break;
4554 default:
4555 cp = "";
4556 snprintf(b, blen, "Unknown phy event source: %d, val=%u, "
4557 "thresh_val=%u", pes, val, thresh_val);
4558 break;
4559 }
4560 return cp;
4561 }
4562
4563 static const char * sas_link_rate_arr[16] = {
4564 "phy enabled; unknown rate",
4565 "phy disabled",
4566 "phy enabled; speed negotiation failed",
4567 "phy enabled; SATA spinup hold state",
4568 "phy enabled; port selector",
4569 "phy enabled; reset in progress",
4570 "phy enabled; unsupported phy attached",
4571 "reserved [0x7]",
4572 "1.5 Gbps", /* 0x8 */
4573 "3 Gbps",
4574 "6 Gbps",
4575 "12 Gbps",
4576 "22.5 Gbps",
4577 "reserved [0xd]",
4578 "reserved [0xe]",
4579 "reserved [0xf]",
4580 };
4581
4582 static char *
sas_negot_link_rate(int lrate,char * b,int blen)4583 sas_negot_link_rate(int lrate, char * b, int blen)
4584 {
4585 int mask = 0xf;
4586
4587 if (~mask & lrate)
4588 snprintf(b, blen, "bad link_rate value=0x%x\n", lrate);
4589 else
4590 snprintf(b, blen, "%s", sas_link_rate_arr[lrate]);
4591 return b;
4592 }
4593
4594 /* helper for SAS port of PROTO_SPECIFIC_LPAGE [0x18] */
4595 static void
show_sas_port_param(const uint8_t * bp,int param_len,struct opts_t * op,sgj_opaque_p jop)4596 show_sas_port_param(const uint8_t * bp, int param_len, struct opts_t * op,
4597 sgj_opaque_p jop)
4598 {
4599 int j, m, nphys, t, spld_len, pi;
4600 uint64_t ull;
4601 unsigned int ui, ui2, ui3, ui4;
4602 char * cp;
4603 const char * ccp;
4604 const char * cc2p;
4605 const char * cc3p;
4606 const char * cc4p;
4607 const uint8_t * vcp;
4608 sgj_state * jsp = &op->json_st;
4609 sgj_opaque_p jo2p = NULL;
4610 sgj_opaque_p jo3p = NULL;
4611 sgj_opaque_p jap = NULL;
4612 sgj_opaque_p ja2p = NULL;
4613 char b[160];
4614 char s[80];
4615 static char * rtpi = "Relative target port identifier";
4616 static char * psplpfstp =
4617 "Protocol Specific Port log parameter for SAS target port";
4618 static char * at = "attached";
4619 static char * ip = "initiator_port";
4620 static char * tp = "target_port";
4621 static char * pvdt = "peak_value_detector_threshold";
4622 static const int sz = sizeof(s);
4623 static const int blen = sizeof(b);
4624
4625 t = sg_get_unaligned_be16(bp + 0);
4626 if (op->do_name)
4627 sgj_pr_hr(jsp, " rel_target_port=%d\n", t);
4628 else
4629 sgj_pr_hr(jsp, " %s = %d\n", rtpi, t);
4630 if (op->do_name)
4631 sgj_pr_hr(jsp, " gen_code=%d\n", bp[6]);
4632 else
4633 sgj_pr_hr(jsp, " generation code = %d\n", bp[6]);
4634 nphys = bp[7];
4635 if (op->do_name)
4636 sgj_pr_hr(jsp, " num_phys=%d\n", nphys);
4637 else
4638 sgj_pr_hr(jsp, " number of phys = %d\n", nphys);
4639 if (jsp->pr_as_json) {
4640 js_snakenv_ihexstr_nex(jsp, jop, param_c , t, true,
4641 NULL, psplpfstp, rtpi);
4642 pi = 0xf & bp[4];
4643 sgj_js_nv_ihexstr(jsp, jop, "protocol_identifier", pi, NULL,
4644 sg_get_trans_proto_str(pi, blen, b));
4645 sgj_js_nv_ihex(jsp, jop, "generation_code", bp[6]);
4646 sgj_js_nv_ihex(jsp, jop, "number_of_phys", bp[7]);
4647 jap = sgj_named_subarray_r(jsp, jop, "sas_phy_log_descriptor_list");
4648 }
4649
4650 for (j = 0, vcp = bp + 8; j < (param_len - 8);
4651 vcp += spld_len, j += spld_len) {
4652 if (jsp->pr_as_json) {
4653 jo2p = sgj_new_unattached_object_r(jsp);
4654 if (op->do_pcb)
4655 js_pcb(jsp, jo2p, vcp[2]);
4656 }
4657 if (op->do_name)
4658 sgj_pr_hr(jsp, " phy_id=%d\n", vcp[1]);
4659 else
4660 sgj_haj_vi(jsp, jo2p, 2, "phy identifier", SGJ_SEP_EQUAL_1_SPACE,
4661 vcp[1], true);
4662 spld_len = vcp[3];
4663 if (spld_len < 44)
4664 spld_len = 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */
4665 else
4666 spld_len += 4;
4667 if (op->do_name) {
4668 t = ((0x70 & vcp[4]) >> 4);
4669 sgj_pr_hr(jsp, " att_dev_type=%d\n", t);
4670 sgj_pr_hr(jsp, " att_iport_mask=0x%x\n", vcp[6]);
4671 sgj_pr_hr(jsp, " att_phy_id=%d\n", vcp[24]);
4672 sgj_pr_hr(jsp, " att_reason=0x%x\n", (vcp[4] & 0xf));
4673 ull = sg_get_unaligned_be64(vcp + 16);
4674 sgj_pr_hr(jsp, " att_sas_addr=0x%" PRIx64 "\n", ull);
4675 sgj_pr_hr(jsp, " att_tport_mask=0x%x\n", vcp[7]);
4676 ui = sg_get_unaligned_be32(vcp + 32);
4677 sgj_pr_hr(jsp, " inv_dwords=%u\n", ui);
4678 ui = sg_get_unaligned_be32(vcp + 40);
4679 sgj_pr_hr(jsp, " loss_dword_sync=%u\n", ui);
4680 sgj_pr_hr(jsp, " neg_log_lrate=%d\n", 0xf & vcp[5]);
4681 ui = sg_get_unaligned_be32(vcp + 44);
4682 sgj_pr_hr(jsp, " phy_reset_probs=%u\n", ui);
4683 ui = sg_get_unaligned_be32(vcp + 36);
4684 sgj_pr_hr(jsp, " running_disparity=%u\n", ui);
4685 sgj_pr_hr(jsp, " reason=0x%x\n", (vcp[5] & 0xf0) >> 4);
4686 ull = sg_get_unaligned_be64(vcp + 8);
4687 sgj_pr_hr(jsp, " sas_addr=0x%" PRIx64 "\n", ull);
4688 } else {
4689 t = ((0x70 & vcp[4]) >> 4);
4690 /* attached SAS device type. In SAS-1.1 case 2 was an edge
4691 * expander; in SAS-2 case 3 is marked as obsolete. */
4692 switch (t) {
4693 case 0: snprintf(s, sz, "no device %s", at); break;
4694 case 1: snprintf(s, sz, "SAS or SATA device"); break;
4695 case 2: snprintf(s, sz, "expander device"); break;
4696 case 3: snprintf(s, sz, "expander device (fanout)"); break;
4697 default: snprintf(s, sz, "%s [%d]", rsv_s, t); break;
4698 }
4699 /* the word 'SAS' in following added in spl4r01 */
4700 sgj_pr_hr(jsp, " %s SAS device type: %s\n", at, s);
4701 if (jsp->pr_as_json)
4702 sgj_js_nv_ihexstr(jsp, jo2p, "attached_sas_device_type", t,
4703 NULL, s);
4704 t = 0xf & vcp[4];
4705 switch (t) {
4706 case 0: snprintf(s, sz, "%s", unknown_s); break;
4707 case 1: snprintf(s, sz, "power on"); break;
4708 case 2: snprintf(s, sz, "hard reset"); break;
4709 case 3: snprintf(s, sz, "SMP phy control function"); break;
4710 case 4: snprintf(s, sz, "loss of dword synchronization"); break;
4711 case 5: snprintf(s, sz, "mux mix up"); break;
4712 case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
4713 break;
4714 case 7: snprintf(s, sz, "break timeout timer expired"); break;
4715 case 8: snprintf(s, sz, "phy test function stopped"); break;
4716 case 9: snprintf(s, sz, "expander device reduced functionality");
4717 break;
4718 default: snprintf(s, sz, "%s [0x%x]", rsv_s, t); break;
4719 }
4720 sgj_pr_hr(jsp, " %s reason: %s\n", at, s);
4721 if (jsp->pr_as_json)
4722 sgj_js_nv_ihexstr(jsp, jo2p, "attached_reason", t, NULL, s);
4723 t = (vcp[5] & 0xf0) >> 4;
4724 switch (t) {
4725 case 0: snprintf(s, sz, "%s", unknown_s); break;
4726 case 1: snprintf(s, sz, "power on"); break;
4727 case 2: snprintf(s, sz, "hard reset"); break;
4728 case 3: snprintf(s, sz, "SMP phy control function"); break;
4729 case 4: snprintf(s, sz, "loss of dword synchronization"); break;
4730 case 5: snprintf(s, sz, "mux mix up"); break;
4731 case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
4732 break;
4733 case 7: snprintf(s, sz, "break timeout timer expired"); break;
4734 case 8: snprintf(s, sz, "phy test function stopped"); break;
4735 case 9: snprintf(s, sz, "expander device reduced functionality");
4736 break;
4737 default: snprintf(s, sz, "%s [0x%x]", rsv_s, t); break;
4738 }
4739 sgj_pr_hr(jsp, " reason: %s\n", s);
4740 if (jsp->pr_as_json)
4741 sgj_js_nv_ihexstr(jsp, jo2p, "reason", t, NULL, s);
4742 t = (0xf & vcp[5]);
4743 ccp = "negotiated logical link rate";
4744 cc2p = sas_negot_link_rate(t, s, sz);
4745 sgj_pr_hr(jsp, " %s: %s\n", ccp, cc2p);
4746 if (jsp->pr_as_json) {
4747 sgj_convert_to_snake_name(ccp, b, blen);
4748 sgj_js_nv_ihexstr(jsp, jo2p, b, t, NULL, cc2p);
4749 }
4750
4751 sgj_pr_hr(jsp, " %s initiator port: ssp=%d stp=%d smp=%d\n",
4752 at, !! (vcp[6] & 8), !! (vcp[6] & 4), !! (vcp[6] & 2));
4753 if (jsp->pr_as_json) {
4754 snprintf(b, blen, "%s_ssp_%s", at, ip);
4755 sgj_js_nv_i(jsp, jo2p, b, !! (vcp[6] & 8));
4756 snprintf(b, blen, "%s_stp_%s", at, ip);
4757 sgj_js_nv_i(jsp, jo2p, b, !! (vcp[6] & 4));
4758 snprintf(b, blen, "%s_smp_%s", at, ip);
4759 sgj_js_nv_i(jsp, jo2p, b, !! (vcp[6] & 2));
4760 }
4761 sgj_pr_hr(jsp, " %s target port: ssp=%d stp=%d smp=%d\n", at,
4762 !! (vcp[7] & 8), !! (vcp[7] & 4), !! (vcp[7] & 2));
4763 if (jsp->pr_as_json) {
4764 snprintf(b, blen, "%s_ssp_%s", at, tp);
4765 sgj_js_nv_i(jsp, jo2p, b, !! (vcp[7] & 8));
4766 snprintf(b, blen, "%s_stp_%s", at, tp);
4767 sgj_js_nv_i(jsp, jo2p, b, !! (vcp[7] & 4));
4768 snprintf(b, blen, "%s_smp_%s", at, tp);
4769 sgj_js_nv_i(jsp, jo2p, b, !! (vcp[7] & 2));
4770 }
4771 ull = sg_get_unaligned_be64(vcp + 8);
4772 sgj_pr_hr(jsp, " SAS address = 0x%" PRIx64 "\n", ull);
4773 if (jsp->pr_as_json)
4774 sgj_js_nv_ihex(jsp, jo2p, "sas_address", ull);
4775 ull = sg_get_unaligned_be64(vcp + 16);
4776 sgj_pr_hr(jsp, " %s SAS address = 0x%" PRIx64 "\n", at, ull);
4777 if (jsp->pr_as_json)
4778 sgj_js_nv_ihex(jsp, jo2p, "attached_sas_address", ull);
4779 ccp = "attached phy identifier";
4780 sgj_haj_vi(jsp, jo2p, 4, ccp, SGJ_SEP_EQUAL_1_SPACE, vcp[24],
4781 true);
4782 ccp = "Invalid DWORD count";
4783 ui = sg_get_unaligned_be32(vcp + 32);
4784 cc2p = "Running disparity error count";
4785 ui2 = sg_get_unaligned_be32(vcp + 36);
4786 cc3p = "Loss of DWORD synchronization count";
4787 ui3 = sg_get_unaligned_be32(vcp + 40);
4788 cc4p = "Phy reset problem count";
4789 ui4 = sg_get_unaligned_be32(vcp + 44);
4790 if (jsp->pr_as_json) {
4791 sgj_convert_to_snake_name(ccp, b, blen);
4792 sgj_js_nv_ihex(jsp, jo2p, b, ui);
4793 sgj_convert_to_snake_name(cc2p, b, blen);
4794 sgj_js_nv_ihex(jsp, jo2p, b, ui2);
4795 sgj_convert_to_snake_name(cc3p, b, blen);
4796 sgj_js_nv_ihex(jsp, jo2p, b, ui3);
4797 sgj_convert_to_snake_name(cc4p, b, blen);
4798 sgj_js_nv_ihex(jsp, jo2p, b, ui4);
4799 } else {
4800 if (0 == op->do_brief) {
4801 sgj_pr_hr(jsp, " %s = %u\n", ccp, ui);
4802 sgj_pr_hr(jsp, " %s = %u\n", cc2p, ui2);
4803 sgj_pr_hr(jsp, " %s = %u\n", cc3p, ui3);
4804 sgj_pr_hr(jsp, " %s = %u\n", cc4p, ui4);
4805 }
4806 }
4807 }
4808 if (op->do_brief > 0)
4809 goto skip;
4810 if (spld_len > 51) {
4811 int num_ped;
4812 const uint8_t * xcp;
4813
4814 num_ped = vcp[51];
4815 if (op->verbose > 1)
4816 sgj_pr_hr(jsp, " <<Phy event descriptors: %d, spld_len: "
4817 "%d, calc_ped: %d>>\n", num_ped, spld_len,
4818 (spld_len - 52) / 12);
4819 if (num_ped > 0) {
4820 if (op->do_name) {
4821 sgj_pr_hr(jsp, " phy_event_desc_num=%d\n", num_ped);
4822 return; /* don't decode at this stage */
4823 } else
4824 sgj_pr_hr(jsp, " Phy event descriptors:\n");
4825 }
4826 if (jsp->pr_as_json) {
4827 sgj_js_nv_i(jsp, jo2p, "number_of_phy_event_descriptors",
4828 num_ped);
4829 if (num_ped > 0)
4830 ja2p = sgj_named_subarray_r(jsp, jo2p,
4831 "phy_event_descriptor_list");
4832 }
4833 xcp = vcp + 52;
4834 for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) {
4835 int pes = xcp[3];
4836 unsigned int pvdt_v;
4837
4838 if (jsp->pr_as_json)
4839 jo3p = sgj_new_unattached_object_r(jsp);
4840 ui = sg_get_unaligned_be32(xcp + 4);
4841 pvdt_v = sg_get_unaligned_be32(xcp + 8);
4842 ccp = show_sas_phy_event_info(pes, ui, pvdt_v, b, blen);
4843 if (0 == strlen(ccp)) {
4844 sgj_pr_hr(jsp, " %s\n", b); /* unknown pvdt_v */
4845 if (jsp->pr_as_json) {
4846 int n;
4847
4848 snprintf(s, sz, "%s_pes_0x%x", unknown_s, pes);
4849 sgj_js_nv_ihex(jsp, jo3p, s, ui);
4850 n = strlen(s);
4851 sg_scnpr(s + n, sz - n, "_%s", "threshold");
4852 sgj_js_nv_ihex(jsp, jo3p, s, pvdt_v);
4853 }
4854 } else {
4855 if (jsp->pr_as_json) {
4856 sgj_convert_to_snake_name(ccp, s, sz);
4857 sgj_js_nv_ihex(jsp, jo3p, s, ui);
4858 if (0x2b == pes)
4859 sgj_js_nv_ihex(jsp, jo3p, pvdt, pvdt_v);
4860 else if (0x2c == pes)
4861 sgj_js_nv_ihex(jsp, jo3p, pvdt, pvdt_v);
4862 else if (0x2d == pes)
4863 sgj_js_nv_ihex(jsp, jo3p, pvdt, pvdt_v);
4864 else if (0x2e == pes)
4865 sgj_js_nv_ihex(jsp, jo3p, pvdt, pvdt_v);
4866 } else {
4867 cp = strchr(b, '\t');
4868 if (cp) {
4869 *cp = '\0';
4870 sgj_pr_hr(jsp, " %s\n", b);
4871 sgj_pr_hr(jsp, " %s\n", cp + 1);
4872 } else
4873 sgj_pr_hr(jsp, " %s\n", b);
4874 }
4875 }
4876 if (jsp->pr_as_json)
4877 sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo3p);
4878 }
4879 } else if (op->verbose)
4880 printf(" <<No phy event descriptors>>\n");
4881 skip:
4882 if (jsp->pr_as_json)
4883 sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
4884 } /* end of for loop over phys with this relative port */
4885 }
4886
4887 /* PROTO_SPECIFIC_LPAGE [0x18] <psp> */
4888 static bool
show_protocol_specific_port_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)4889 show_protocol_specific_port_page(const uint8_t * resp, int len,
4890 struct opts_t * op, sgj_opaque_p jop)
4891 {
4892 int k, num, pl, pid;
4893 const uint8_t * bp;
4894 sgj_state * jsp = &op->json_st;
4895 sgj_opaque_p jo2p;
4896 sgj_opaque_p jo3p = NULL;
4897 sgj_opaque_p jap = NULL;
4898 char b[128];
4899 static const char * psplp = "Protocol specific port log page";
4900 static const char * fss = "for SAS SSP";
4901
4902 num = len - 4;
4903 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex))) {
4904 if (op->do_name)
4905 sgj_pr_hr(jsp, "log_page=0x%x\n", PROTO_SPECIFIC_LPAGE);
4906 else
4907 sgj_pr_hr(jsp, "%s [0x18]\n", psplp);
4908 }
4909 if (jsp->pr_as_json) {
4910 jo2p = sg_log_js_hdr(jsp, jop, psplp, resp);
4911 jap = sgj_named_subarray_r(jsp, jo2p,
4912 "protocol_specific_port_log_parameter_list");
4913 }
4914
4915 for (k = 0, bp = resp + 4; k < num; ) {
4916 int pc = sg_get_unaligned_be16(bp + 0);
4917
4918 pl = bp[3] + 4;
4919 if (op->filter_given) {
4920 if (pc != op->filter)
4921 goto skip;
4922 }
4923 if (op->do_raw) {
4924 dStrRaw(bp, pl);
4925 goto skip;
4926 } else if (op->do_hex) {
4927 hex2stdout(bp, pl, op->dstrhex_no_ascii);
4928 goto skip;
4929 }
4930 pid = 0xf & bp[4];
4931 if (6 != pid) {
4932 pr2serr("Protocol identifier: %d, only support SAS (SPL) which "
4933 "is 6\n", pid);
4934 return false; /* only decode SAS log page */
4935 }
4936 if (jsp->pr_as_json) {
4937 jo3p = sgj_new_unattached_object_r(jsp);
4938 if (op->do_pcb)
4939 js_pcb(jsp, jo3p, bp[2]);
4940 }
4941 if ((0 == k) && (! op->do_name))
4942 sgj_pr_hr(jsp, "%s %s [0x18]\n", psplp, fss);
4943 /* call helper */
4944 show_sas_port_param(bp, pl, op, jo3p);
4945 if (jsp->pr_as_json)
4946 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
4947 if ((op->do_pcb) && (! op->do_name))
4948 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b,
4949 sizeof(b)));
4950 if (op->filter_given)
4951 break;
4952 skip:
4953 k += pl;
4954 bp += pl;
4955 }
4956 return true;
4957 }
4958
4959 /* Returns true if processed page, false otherwise */
4960 /* STATS_LPAGE [0x19], subpages: 0x0 to 0x1f <gsp,grsp> introduced: SPC-4 */
4961 static bool
show_stats_perform_pages(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)4962 show_stats_perform_pages(const uint8_t * resp, int len,
4963 struct opts_t * op, sgj_opaque_p jop)
4964 {
4965 bool nam, spf;
4966 int k, num, param_len, param_code, subpg_code, extra;
4967 uint64_t ull;
4968 const uint8_t * bp;
4969 const char * ccp;
4970 const char * pg_name;
4971 sgj_state * jsp = &op->json_st;
4972 sgj_opaque_p jo2p;
4973 sgj_opaque_p jo3p = NULL;
4974 sgj_opaque_p jap = NULL;
4975 char str[PCB_STR_LEN];
4976 static const char * gsaplp =
4977 "General statistics and performance log page";
4978 static const char * gr_saplp =
4979 "Group statistics and performance log page";
4980
4981 // yyyyyyyyyyyyyyyyyy
4982 nam = op->do_name;
4983 num = len - 4;
4984 bp = resp + 4;
4985 spf = !!(resp[0] & 0x40);
4986 subpg_code = spf ? resp[1] : NOT_SPG_SUBPG;
4987 if (0 == subpg_code)
4988 pg_name = gsaplp;
4989 else if (subpg_code < 0x20)
4990 pg_name = gr_saplp;
4991 else
4992 pg_name = "Unknown subpage";
4993 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex))) {
4994 if (nam) {
4995 sgj_pr_hr(jsp, "log_page=0x%x\n", STATS_LPAGE);
4996 if (subpg_code > 0)
4997 sgj_pr_hr(jsp, "log_subpage=0x%x\n", subpg_code);
4998 } else {
4999 if (0 == subpg_code)
5000 sgj_pr_hr(jsp, "%s [0x19]\n", gsaplp);
5001 else if (subpg_code < 0x20)
5002 sgj_pr_hr(jsp, "%s (%d) [0x19,0x%x]\n", gr_saplp, subpg_code,
5003 subpg_code);
5004 else
5005 sgj_pr_hr(jsp, "%s: %d [0x19,0x%x]\n", pg_name, subpg_code,
5006 subpg_code);
5007 }
5008 }
5009 if (jsp->pr_as_json)
5010 jo2p = sg_log_js_hdr(jsp, jop, pg_name, resp);
5011 if (subpg_code > 31)
5012 return false;
5013 if (jsp->pr_as_json)
5014 jap = sgj_named_subarray_r(jsp, jo2p, 0 == subpg_code ?
5015 "general_statistics_and_performance_log_parameters" :
5016 "group_statistics_and_performance_log_parameters");
5017 if (0 == subpg_code) { /* General statistics and performance log page */
5018 if (num < 0x5c)
5019 return false;
5020 for (k = num; k > 0; k -= extra, bp += extra) {
5021 unsigned int ui;
5022
5023 if (k < 3)
5024 return false;
5025 param_len = bp[3];
5026 extra = param_len + 4;
5027 param_code = sg_get_unaligned_be16(bp + 0);
5028 if (op->filter_given) {
5029 if (param_code != op->filter)
5030 continue;
5031 }
5032 if (op->do_raw) {
5033 dStrRaw(bp, extra);
5034 goto skip;
5035 } else if (op->do_hex) {
5036 hex2stdout(bp, extra, op->dstrhex_no_ascii);
5037 goto skip;
5038 }
5039 if (jsp->pr_as_json) {
5040 jo3p = sgj_new_unattached_object_r(jsp);
5041 if (op->do_pcb)
5042 js_pcb(jsp, jo3p, bp[2]);
5043 }
5044
5045 switch (param_code) {
5046 case 1: /* Statistics and performance log parameter */
5047 ccp = nam ? "parameter_code=1" : "Statistics and performance "
5048 "log parameter";
5049 sgj_pr_hr(jsp, "%s\n", ccp);
5050 ull = sg_get_unaligned_be64(bp + 4);
5051 ccp = nam ? "read_commands=" : "number of read commands = ";
5052 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5053 ull = sg_get_unaligned_be64(bp + 12);
5054 ccp = nam ? "write_commands=" : "number of write commands = ";
5055 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5056 ull = sg_get_unaligned_be64(bp + 20);
5057 ccp = nam ? "lb_received="
5058 : "number of logical blocks received = ";
5059 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5060 ull = sg_get_unaligned_be64(bp + 28);
5061 ccp = nam ? "lb_transmitted="
5062 : "number of logical blocks transmitted = ";
5063 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5064 ull = sg_get_unaligned_be64(bp + 36);
5065 ccp = nam ? "read_proc_intervals="
5066 : "read command processing intervals = ";
5067 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5068 ull = sg_get_unaligned_be64(bp + 44);
5069 ccp = nam ? "write_proc_intervals="
5070 : "write command processing intervals = ";
5071 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5072 ull = sg_get_unaligned_be64(bp + 52);
5073 ccp = nam ? "weight_rw_commands=" : "weighted number of "
5074 "read commands plus write commands = ";
5075 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5076 ull = sg_get_unaligned_be64(bp + 60);
5077 ccp = nam ? "weight_rw_processing=" : "weighted read command "
5078 "processing plus write command processing = ";
5079 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5080 break;
5081 case 2: /* Idle time log parameter */
5082 ccp = nam ? "parameter_code=2" : "Idle time log parameter";
5083 sgj_pr_hr(jsp, "%s\n", ccp);
5084 ull = sg_get_unaligned_be64(bp + 4);
5085 ccp = nam ? "idle_time_intervals=" : "idle time "
5086 "intervals = ";
5087 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5088 break;
5089 case 3: /* Time interval log parameter for general stats */
5090 ccp = nam ? "parameter_code=3" : "Time interval log "
5091 "parameter for general stats";
5092 sgj_pr_hr(jsp, "%s\n", ccp);
5093 ui = sg_get_unaligned_be32(bp + 4);
5094 ccp = nam ? "time_interval_neg_exp=" : "time interval "
5095 "negative exponent = ";
5096 sgj_pr_hr(jsp, " %s%u\n", ccp, ui);
5097 ui = sg_get_unaligned_be32(bp + 8);
5098 ccp = nam ? "time_interval_int=" : "time interval "
5099 "integer = ";
5100 sgj_pr_hr(jsp, " %s%u\n", ccp, ui);
5101 break;
5102 case 4: /* FUA statistics and performance log parameter */
5103 ccp = nam ? "parameter_code=4" : "Force unit access "
5104 "statistics and performance log parameter ";
5105 sgj_pr_hr(jsp, "%s\n", ccp);
5106 ull = sg_get_unaligned_be64(bp + 4);
5107 ccp = nam ? "read_fua_commands=" : "number of read FUA "
5108 "commands = ";
5109 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5110 ull = sg_get_unaligned_be64(bp + 12);
5111 ccp = nam ? "write_fua_commands=" : "number of write FUA "
5112 "commands = ";
5113 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5114 ull = sg_get_unaligned_be64(bp + 20);
5115 ccp = nam ? "read_fua_nv_commands="
5116 : "number of read FUA_NV commands = ";
5117 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5118 ull = sg_get_unaligned_be64(bp + 28);
5119 ccp = nam ? "write_fua_nv_commands="
5120 : "number of write FUA_NV commands = ";
5121 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5122 ull = sg_get_unaligned_be64(bp + 36);
5123 ccp = nam ? "read_fua_proc_intervals="
5124 : "read FUA command processing intervals = ";
5125 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5126 ull = sg_get_unaligned_be64(bp + 44);
5127 ccp = nam ? "write_fua_proc_intervals="
5128 : "write FUA command processing intervals = ";
5129 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5130 ull = sg_get_unaligned_be64(bp + 52);
5131 ccp = nam ? "read_fua_nv_proc_intervals="
5132 : "read FUA_NV command processing intervals = ";
5133 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5134 ull = sg_get_unaligned_be64(bp + 60);
5135 ccp = nam ? "write_fua_nv_proc_intervals="
5136 : "write FUA_NV command processing intervals = ";
5137 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5138 break;
5139 case 6: /* Time interval log parameter for cache stats */
5140 ccp = nam ? "parameter_code=6" : "Time interval log "
5141 "parameter for cache stats";
5142 sgj_pr_hr(jsp, "%s\n", ccp);
5143 ull = sg_get_unaligned_be64(bp + 4);
5144 ccp = nam ? "time_interval_neg_exp=" : "time interval "
5145 "negative exponent = ";
5146 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5147 ull = sg_get_unaligned_be64(bp + 8);
5148 ccp = nam ? "time_interval_int=" : "time interval "
5149 "integer = ";
5150 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5151 break;
5152 default:
5153 if (nam) {
5154 sgj_pr_hr(jsp, "parameter_code=%d\n", param_code);
5155 sgj_pr_hr(jsp, " unknown=1\n");
5156 } else
5157 pr2serr("show_performance... unknown %s %d\n", param_c,
5158 param_code);
5159 if (op->verbose)
5160 hex2stderr(bp, extra, 1);
5161 break;
5162 }
5163 if (jsp->pr_as_json)
5164 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
5165 if ((op->do_pcb) && (! op->do_name))
5166 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], str,
5167 sizeof(str)));
5168 skip:
5169 if (op->filter_given)
5170 break;
5171 }
5172 } else { /* Group statistics and performance (n) log page */
5173 if (num < 0x34)
5174 return false;
5175 for (k = num; k > 0; k -= extra, bp += extra) {
5176 if (k < 3)
5177 return false;
5178 param_len = bp[3];
5179 extra = param_len + 4;
5180 param_code = sg_get_unaligned_be16(bp + 0);
5181 if (op->filter_given) {
5182 if (param_code != op->filter)
5183 continue;
5184 }
5185 if (op->do_raw) {
5186 dStrRaw(bp, extra);
5187 goto skip2;
5188 } else if (op->do_hex) {
5189 hex2stdout(bp, extra, op->dstrhex_no_ascii);
5190 goto skip2;
5191 }
5192 if (jsp->pr_as_json) {
5193 jo3p = sgj_new_unattached_object_r(jsp);
5194 if (op->do_pcb)
5195 js_pcb(jsp, jo3p, bp[2]);
5196 }
5197
5198 switch (param_code) {
5199 case 1: /* Group n Statistics and performance log parameter */
5200 if (nam)
5201 sgj_pr_hr(jsp, "parameter_code=1\n");
5202 else
5203 sgj_pr_hr(jsp, "Group %d Statistics and performance log "
5204 "parameter\n", subpg_code);
5205 ull = sg_get_unaligned_be64(bp + 4);
5206 ccp = nam ? "gn_read_commands=" : "group n number of read "
5207 "commands = ";
5208 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5209 ull = sg_get_unaligned_be64(bp + 12);
5210 ccp = nam ? "gn_write_commands=" : "group n number of write "
5211 "commands = ";
5212 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5213 ull = sg_get_unaligned_be64(bp + 20);
5214 ccp = nam ? "gn_lb_received="
5215 : "group n number of logical blocks received = ";
5216 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5217 ull = sg_get_unaligned_be64(bp + 28);
5218 ccp = nam ? "gn_lb_transmitted="
5219 : "group n number of logical blocks transmitted = ";
5220 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5221 ull = sg_get_unaligned_be64(bp + 36);
5222 ccp = nam ? "gn_read_proc_intervals="
5223 : "group n read command processing intervals = ";
5224 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5225 ull = sg_get_unaligned_be64(bp + 44);
5226 ccp = nam ? "gn_write_proc_intervals="
5227 : "group n write command processing intervals = ";
5228 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5229 break;
5230 case 4: /* Group n FUA statistics and performance log parameter */
5231 ccp = nam ? "parameter_code=4" : "Group n force unit access "
5232 "statistics and performance log parameter";
5233 sgj_pr_hr(jsp, "%s\n", ccp);
5234 ull = sg_get_unaligned_be64(bp + 4);
5235 ccp = nam ? "gn_read_fua_commands="
5236 : "group n number of read FUA commands = ";
5237 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5238 ull = sg_get_unaligned_be64(bp + 12);
5239 ccp = nam ? "gn_write_fua_commands="
5240 : "group n number of write FUA commands = ";
5241 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5242 ull = sg_get_unaligned_be64(bp + 20);
5243 ccp = nam ? "gn_read_fua_nv_commands="
5244 : "group n number of read FUA_NV commands = ";
5245 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5246 ull = sg_get_unaligned_be64(bp + 28);
5247 ccp = nam ? "gn_write_fua_nv_commands="
5248 : "group n number of write FUA_NV commands = ";
5249 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5250 ull = sg_get_unaligned_be64(bp + 36);
5251 ccp = nam ? "gn_read_fua_proc_intervals="
5252 : "group n read FUA command processing intervals = ";
5253 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5254 ull = sg_get_unaligned_be64(bp + 44);
5255 ccp = nam ? "gn_write_fua_proc_intervals=" : "group n write "
5256 "FUA command processing intervals = ";
5257 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5258 ull = sg_get_unaligned_be64(bp + 52);
5259 ccp = nam ? "gn_read_fua_nv_proc_intervals=" : "group n "
5260 "read FUA_NV command processing intervals = ";
5261 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5262 ull = sg_get_unaligned_be64(bp + 60);
5263 ccp = nam ? "gn_write_fua_nv_proc_intervals=" : "group n "
5264 "write FUA_NV command processing intervals = ";
5265 sgj_pr_hr(jsp, " %s%" PRIu64 "\n", ccp, ull);
5266 break;
5267 default:
5268 if (nam) {
5269 sgj_pr_hr(jsp, "parameter_code=%d\n", param_code);
5270 sgj_pr_hr(jsp, " unknown=1\n");
5271 } else
5272 pr2serr("show_performance... unknown %s %d\n", param_c,
5273 param_code);
5274 if (op->verbose)
5275 hex2stderr(bp, extra, 1);
5276 break;
5277 }
5278 if (jsp->pr_as_json)
5279 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
5280 if ((op->do_pcb) && (! op->do_name))
5281 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], str,
5282 sizeof(str)));
5283 skip2:
5284 if (op->filter_given)
5285 break;
5286 }
5287 }
5288 return true;
5289 }
5290
5291 /* Returns true if processed page, false otherwise */
5292 /* STATS_LPAGE [0x19], CACHE_STATS_SUBPG [0x20] <cms> introduced: SPC-4 */
5293 static bool
show_cache_stats_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)5294 show_cache_stats_page(const uint8_t * resp, int len, struct opts_t * op,
5295 sgj_opaque_p jop)
5296 {
5297 int k, num, subpg_code, extra;
5298 bool nam, spf;
5299 unsigned int ui;
5300 const uint8_t * bp;
5301 const char * ccp;
5302 uint64_t ull;
5303 char str[PCB_STR_LEN];
5304
5305 if (jop) { };
5306 nam = op->do_name;
5307 num = len - 4;
5308 bp = resp + 4;
5309 if (num < 4) {
5310 pr2serr("badly formed Cache memory statistics page\n");
5311 return false;
5312 }
5313 spf = !!(resp[0] & 0x40);
5314 subpg_code = spf ? resp[1] : NOT_SPG_SUBPG;
5315 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex))) {
5316 if (nam) {
5317 printf("log_page=0x%x\n", STATS_LPAGE);
5318 if (subpg_code > 0)
5319 printf("log_subpage=0x%x\n", subpg_code);
5320 } else
5321 printf("Cache memory statistics page [0x19,0x20]\n");
5322 }
5323
5324 for (k = num; k > 0; k -= extra, bp += extra) {
5325 int pc;
5326
5327 if (k < 3) {
5328 pr2serr("short Cache memory statistics page\n");
5329 return false;
5330 }
5331 if (8 != bp[3]) {
5332 printf("Cache memory statistics page parameter length not "
5333 "8\n");
5334 return false;
5335 }
5336 extra = bp[3] + 4;
5337 pc = sg_get_unaligned_be16(bp + 0);
5338 if (op->filter_given) {
5339 if (pc != op->filter)
5340 continue;
5341 }
5342 if (op->do_raw) {
5343 dStrRaw(bp, extra);
5344 goto skip;
5345 } else if (op->do_hex) {
5346 hex2stdout(bp, extra, op->dstrhex_no_ascii);
5347 goto skip;
5348 }
5349 switch (pc) {
5350 case 1: /* Read cache memory hits log parameter */
5351 ccp = nam ? "parameter_code=1" :
5352 "Read cache memory hits log parameter";
5353 printf("%s\n", ccp);
5354 ull = sg_get_unaligned_be64(bp + 4);
5355 ccp = nam ? "read_cache_memory_hits=" :
5356 "read cache memory hits = ";
5357 printf(" %s%" PRIu64 "\n", ccp, ull);
5358 break;
5359 case 2: /* Reads to cache memory log parameter */
5360 ccp = nam ? "parameter_code=2" :
5361 "Reads to cache memory log parameter";
5362 printf("%s\n", ccp);
5363 ull = sg_get_unaligned_be64(bp + 4);
5364 ccp = nam ? "reads_to_cache_memory=" :
5365 "reads to cache memory = ";
5366 printf(" %s%" PRIu64 "\n", ccp, ull);
5367 break;
5368 case 3: /* Write cache memory hits log parameter */
5369 ccp = nam ? "parameter_code=3" :
5370 "Write cache memory hits log parameter";
5371 printf("%s\n", ccp);
5372 ull = sg_get_unaligned_be64(bp + 4);
5373 ccp = nam ? "write_cache_memory_hits=" :
5374 "write cache memory hits = ";
5375 printf(" %s%" PRIu64 "\n", ccp, ull);
5376 break;
5377 case 4: /* Writes from cache memory log parameter */
5378 ccp = nam ? "parameter_code=4" :
5379 "Writes from cache memory log parameter";
5380 printf("%s\n", ccp);
5381 ull = sg_get_unaligned_be64(bp + 4);
5382 ccp = nam ? "writes_from_cache_memory=" :
5383 "writes from cache memory = ";
5384 printf(" %s%" PRIu64 "\n", ccp, ull);
5385 break;
5386 case 5: /* Time from last hard reset log parameter */
5387 ccp = nam ? "parameter_code=5" :
5388 "Time from last hard reset log parameter";
5389 printf("%s\n", ccp);
5390 ull = sg_get_unaligned_be64(bp + 4);
5391 ccp = nam ? "time_from_last_hard_reset=" :
5392 "time from last hard reset = ";
5393 printf(" %s%" PRIu64 "\n", ccp, ull);
5394 break;
5395 case 6: /* Time interval log parameter for cache stats */
5396 ccp = nam ? "parameter_code=6" :
5397 "Time interval log parameter";
5398 printf("%s\n", ccp);
5399 ui = sg_get_unaligned_be32(bp + 4);
5400 ccp = nam ? "time_interval_neg_exp=" : "time interval "
5401 "negative exponent = ";
5402 printf(" %s%u\n", ccp, ui);
5403 ui = sg_get_unaligned_be32(bp + 8);
5404 ccp = nam ? "time_interval_int=" : "time interval "
5405 "integer = ";
5406 printf(" %s%u\n", ccp, ui);
5407 break;
5408 default:
5409 if (nam) {
5410 printf("parameter_code=%d\n", pc);
5411 printf(" unknown=1\n");
5412 } else
5413 pr2serr("show_performance... unknown %s %d\n", param_c,
5414 pc);
5415 if (op->verbose)
5416 hex2stderr(bp, extra, 1);
5417 break;
5418 }
5419 if ((op->do_pcb) && (! op->do_name))
5420 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
5421 skip:
5422 if (op->filter_given)
5423 break;
5424 }
5425 return true;
5426 }
5427
5428 /* FORMAT_STATUS_LPAGE [0x8] <fs> introduced: SBC-2 */
5429 static bool
show_format_status_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)5430 show_format_status_page(const uint8_t * resp, int len,
5431 struct opts_t * op, sgj_opaque_p jop)
5432 {
5433 bool is_count, is_not_avail;
5434 int k, num, pl, pc;
5435 uint64_t ull;
5436 const char * cp = "";
5437 const uint8_t * bp;
5438 const uint8_t * xp;
5439 sgj_state * jsp = &op->json_st;
5440 sgj_opaque_p jo2p;
5441 sgj_opaque_p jo3p = NULL;
5442 sgj_opaque_p jap = NULL;
5443 char str[PCB_STR_LEN];
5444 char b[512];
5445 static const char * fslp = "Format status log page";
5446 static const char * fso = "Format status out";
5447 static const char * fso_sn = "format_status_out";
5448
5449 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
5450 sgj_pr_hr(jsp, "%s [0x8]\n", fslp);
5451 num = len - 4;
5452 bp = &resp[0] + 4;
5453 if (jsp->pr_as_json) {
5454 jo2p = sg_log_js_hdr(jsp, jop, fslp, resp);
5455 jap = sgj_named_subarray_r(jsp, jo2p, "format_status_log_parameters");
5456 }
5457
5458
5459 while (num > 3) {
5460 pc = sg_get_unaligned_be16(bp + 0);
5461 pl = bp[3] + 4;
5462 if (op->filter_given) {
5463 if (pc != op->filter)
5464 goto skip;
5465 }
5466 if (op->do_raw) {
5467 dStrRaw(bp, pl);
5468 goto filter_chk;
5469 } else if (op->do_hex) {
5470 hex2stdout(bp, pl, op->dstrhex_no_ascii);
5471 goto filter_chk;
5472 }
5473 if (jsp->pr_as_json) {
5474 jo3p = sgj_new_unattached_object_r(jsp);
5475 if (op->do_pcb)
5476 js_pcb(jsp, jo3p, bp[2]);
5477 }
5478 is_count = true;
5479
5480 switch (pc) {
5481 case 0:
5482 is_not_avail = false;
5483 if (pl < 5)
5484 sgj_pr_hr(jsp, " %s: <empty>\n", fso);
5485 else {
5486 if (sg_all_ffs(bp + 4, pl - 4)) {
5487 sgj_pr_hr(jsp, " %s: <%s>\n", fso, not_avail);
5488 is_not_avail = true;
5489 } else {
5490 hex2str(bp + 4, pl - 4, " ", op->hex2str_oformat,
5491 sizeof(b), b);
5492 sgj_pr_hr(jsp, " %s:\n%s", fso, b);
5493
5494
5495 }
5496 }
5497 if (jsp->pr_as_json) {
5498 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, fso);
5499 if (is_not_avail)
5500 sgj_js_nv_ihexstr(jsp, jo3p, fso_sn, 0, NULL, not_avail);
5501 else
5502 sgj_js_nv_hex_bytes(jsp, jo3p, fso_sn, bp + 4, pl - 4);
5503 }
5504 is_count = false;
5505 break;
5506 case 1:
5507 cp = "Grown defects during certification";
5508 break;
5509 case 2:
5510 cp = "Total blocks reassigned during format";
5511 break;
5512 case 3:
5513 cp = "Total new blocks reassigned";
5514 break;
5515 case 4:
5516 cp = "Power on minutes since format";
5517 break;
5518 default:
5519 sgj_pr_hr(jsp, " Unknown Format %s = 0x%x\n", param_c, pc);
5520 is_count = false;
5521 hex2fp(bp, pl, " ", op->hex2str_oformat, stdout);
5522 if (jsp->pr_as_json) {
5523 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, unknown_s);
5524 sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp, pl);
5525 }
5526 break;
5527 }
5528 if (is_count) {
5529 k = pl - 4;
5530 xp = bp + 4;
5531 is_not_avail = false;
5532 ull = 0;
5533 if (sg_all_ffs(xp, k)) {
5534 sgj_pr_hr(jsp, " %s: <%s>\n", cp, not_avail);
5535 is_not_avail = true;
5536 } else {
5537 if (k > (int)sizeof(ull)) {
5538 xp += (k - sizeof(ull));
5539 k = sizeof(ull);
5540 }
5541 ull = sg_get_unaligned_be(k, xp);
5542 sgj_pr_hr(jsp, " %s = %" PRIu64 "\n", cp, ull);
5543 }
5544 if (jsp->pr_as_json) {
5545 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, cp);
5546 sgj_convert_to_snake_name(cp, b, sizeof(b));
5547 if (is_not_avail)
5548 sgj_js_nv_ihexstr(jsp, jo3p, b, 0, NULL, not_avail);
5549 else
5550 sgj_js_nv_ihex(jsp, jo3p, b, ull);
5551 }
5552 }
5553 if (jsp->pr_as_json)
5554 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
5555 if ((op->do_pcb) && (! op->do_name))
5556 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], str,
5557 sizeof(str)));
5558 filter_chk:
5559 if (op->filter_given)
5560 break;
5561 skip:
5562 num -= pl;
5563 bp += pl;
5564 }
5565 return true;
5566 }
5567
5568 /* Non-volatile cache page [0x17] <nvc> introduced: SBC-2
5569 * Standard vacillates between "non-volatile" and "nonvolatile" */
5570 static bool
show_non_volatile_cache_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)5571 show_non_volatile_cache_page(const uint8_t * resp, int len,
5572 struct opts_t * op, sgj_opaque_p jop)
5573 {
5574 int j, num, pl, pc;
5575 const char * cp;
5576 const char * c2p;
5577 const uint8_t * bp;
5578 sgj_state * jsp = &op->json_st;
5579 sgj_opaque_p jo2p;
5580 sgj_opaque_p jo3p = NULL;
5581 sgj_opaque_p jap = NULL;
5582 char str[PCB_STR_LEN];
5583 char b[96];
5584 static const char * nvclp = "Non-volatile cache log page";
5585 static const char * ziinv = "0 (i.e. it is now volatile)";
5586 static const char * indef = "indefinite";
5587
5588 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
5589 sgj_pr_hr(jsp, "%s [0x17]\n", nvclp);
5590 num = len - 4;
5591 bp = &resp[0] + 4;
5592 if (jsp->pr_as_json) {
5593 jo2p = sg_log_js_hdr(jsp, jop, nvclp, resp);
5594 jap = sgj_named_subarray_r(jsp, jo2p,
5595 "nonvolatile_cache_log_parameters");
5596 }
5597
5598 while (num > 3) {
5599 pc = sg_get_unaligned_be16(bp + 0);
5600 pl = bp[3] + 4;
5601 if (op->filter_given) {
5602 if (pc != op->filter)
5603 goto skip;
5604 }
5605 if (op->do_raw) {
5606 dStrRaw(bp, pl);
5607 goto filter_chk;
5608 } else if (op->do_hex) {
5609 hex2stdout(bp, pl, op->dstrhex_no_ascii);
5610 goto filter_chk;
5611 }
5612 if (jsp->pr_as_json) {
5613 jo3p = sgj_new_unattached_object_r(jsp);
5614 if (op->do_pcb)
5615 js_pcb(jsp, jo3p, bp[2]);
5616 }
5617
5618 cp = NULL;
5619 switch (pc) {
5620 case 0:
5621 cp = "Remaining nonvolatile time";
5622 c2p = NULL;
5623 j = sg_get_unaligned_be24(bp + 5);
5624 switch (j) {
5625 case 0:
5626 c2p = ziinv;
5627 sgj_pr_hr(jsp, " %s: %s\n", cp, c2p);
5628 break;
5629 case 1:
5630 c2p = unknown_s;
5631 sgj_pr_hr(jsp, " %s: <%s>\n", cp, c2p);
5632 break;
5633 case 0xffffff:
5634 c2p = indef;
5635 sgj_pr_hr(jsp, " %s: <%s>\n", cp, c2p);
5636 break;
5637 default:
5638 snprintf(b, sizeof(b), "%d minutes [%d:%d]", j, (j / 60),
5639 (j % 60));
5640 c2p = b;
5641 sgj_pr_hr(jsp, " %s: %s\n", cp, c2p);
5642 break;
5643 }
5644 break;
5645 case 1:
5646 cp = "Maximum non-volatile time";
5647 c2p = NULL;
5648 j = sg_get_unaligned_be24(bp + 5);
5649 switch (j) {
5650 case 0:
5651 c2p = ziinv;
5652 sgj_pr_hr(jsp, " %s: %s\n", cp, c2p);
5653 break;
5654 case 1:
5655 c2p = rsv_s;
5656 sgj_pr_hr(jsp, " %s: <%s>\n", cp, c2p);
5657 break;
5658 case 0xffffff:
5659 c2p = indef;
5660 sgj_pr_hr(jsp, " %s: <%s>\n", cp, c2p);
5661 break;
5662 default:
5663 snprintf(b, sizeof(b), "%d minutes [%d:%d]", j, (j / 60),
5664 (j % 60));
5665 c2p = b;
5666 sgj_pr_hr(jsp, " %s: %s\n", cp, c2p);
5667 break;
5668 }
5669 break;
5670 default:
5671 sgj_pr_hr(jsp, " Unknown %s = 0x%x\n", param_c, pc);
5672 hex2stdout(bp, pl, op->dstrhex_no_ascii);
5673 break;
5674 }
5675 if (jsp->pr_as_json) {
5676 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
5677 cp ? cp : unknown_s);
5678 if (cp)
5679 js_snakenv_ihexstr_nex(jsp, jo3p, cp , j, true,
5680 NULL, c2p, NULL);
5681 else if (pl > 4)
5682 sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp + 4, pl - 4);
5683
5684 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
5685 }
5686 if ((op->do_pcb) && (! op->do_name))
5687 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], str,
5688 sizeof(str)));
5689 filter_chk:
5690 if (op->filter_given)
5691 break;
5692 skip:
5693 num -= pl;
5694 bp += pl;
5695 }
5696 return true;
5697 }
5698
5699 /* LB_PROV_LPAGE [0xc] <lbp> introduced: SBC-3 */
5700 static bool
show_lb_provisioning_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)5701 show_lb_provisioning_page(const uint8_t * resp, int len,
5702 struct opts_t * op, sgj_opaque_p jop)
5703 {
5704 bool evsm_output = false;
5705 int num, pl, pc;
5706 const uint8_t * bp;
5707 const char * cp;
5708 char str[PCB_STR_LEN];
5709
5710 if (jop) { };
5711 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
5712 printf("Logical block provisioning page [0xc]\n");
5713 num = len - 4;
5714 bp = &resp[0] + 4;
5715 while (num > 3) {
5716 pc = sg_get_unaligned_be16(bp + 0);
5717 pl = bp[3] + 4;
5718 if (op->filter_given) {
5719 if (pc != op->filter)
5720 goto skip;
5721 }
5722 if (op->do_raw) {
5723 dStrRaw(bp, pl);
5724 goto filter_chk;
5725 } else if (op->do_hex) {
5726 hex2stdout(bp, pl, op->dstrhex_no_ascii);
5727 goto filter_chk;
5728 }
5729 switch (pc) {
5730 case 0x1:
5731 cp = " Available LBA mapping threshold";
5732 break;
5733 case 0x2:
5734 cp = " Used LBA mapping threshold";
5735 break;
5736 case 0x3:
5737 cp = " Available provisioning resource percentage";
5738 break;
5739 case 0x100:
5740 cp = " De-duplicated LBA";
5741 break;
5742 case 0x101:
5743 cp = " Compressed LBA";
5744 break;
5745 case 0x102:
5746 cp = " Total efficiency LBA";
5747 break;
5748 default:
5749 cp = NULL;
5750 break;
5751 }
5752 if (cp) {
5753 if ((pl < 8) || (num < 8)) {
5754 if (num < 8)
5755 pr2serr("\n truncated by response length, expected at "
5756 "least 8 bytes\n");
5757 else
5758 pr2serr("\n parameter length >= 8 expected, got %d\n",
5759 pl);
5760 break;
5761 }
5762 if (0x3 == pc) /* resource percentage log parameter */
5763 printf(" %s: %u %%\n", cp, sg_get_unaligned_be16(bp + 4));
5764 else /* resource count log parameters */
5765 printf(" %s resource count: %u\n", cp,
5766 sg_get_unaligned_be32(bp + 4));
5767 if (pl > 8) {
5768 switch (bp[8] & 0x3) { /* SCOPE field */
5769 case 0: cp = not_rep; break;
5770 case 1: cp = "dedicated to lu"; break;
5771 case 2: cp = "not dedicated to lu"; break;
5772 case 3: cp = rsv_s; break;
5773 }
5774 printf(" Scope: %s\n", cp);
5775 }
5776 } else if ((pc >= 0xfff0) && (pc <= 0xffff)) {
5777 if (op->exclude_vendor) {
5778 if ((op->verbose > 0) && (0 == op->do_brief) &&
5779 (! evsm_output)) {
5780 evsm_output = true;
5781 printf(" %s parameter(s) being ignored\n", vend_spec);
5782 }
5783 } else {
5784 printf(" %s [0x%x]:", vend_spec, pc);
5785 hex2stdout(bp, ((pl < num) ? pl : num), op->dstrhex_no_ascii);
5786 }
5787 } else {
5788 printf(" Reserved [%s=0x%x]:\n", param_c_sn, pc);
5789 hex2stdout(bp, ((pl < num) ? pl : num), op->dstrhex_no_ascii);
5790 }
5791 if (op->do_pcb)
5792 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
5793 filter_chk:
5794 if (op->filter_given)
5795 break;
5796 skip:
5797 num -= pl;
5798 bp += pl;
5799 }
5800 return true;
5801 }
5802
5803 /* UTILIZATION_SUBPG [0xe,0x1] <util> introduced: SBC-4 */
5804 static bool
show_utilization_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)5805 show_utilization_page(const uint8_t * resp, int len, struct opts_t * op,
5806 sgj_opaque_p jop)
5807 {
5808 int num, pl, pc, k;
5809 const uint8_t * bp;
5810 char str[PCB_STR_LEN];
5811
5812 if (jop) { };
5813 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
5814 printf("Utilization page [0xe,0x1]\n");
5815 num = len - 4;
5816 bp = &resp[0] + 4;
5817 while (num > 3) {
5818 pc = sg_get_unaligned_be16(bp + 0);
5819 pl = bp[3] + 4;
5820 if (op->filter_given) {
5821 if (pc != op->filter)
5822 goto skip;
5823 }
5824 if (op->do_raw) {
5825 dStrRaw(bp, pl);
5826 goto filter_chk;
5827 } else if (op->do_hex) {
5828 hex2stdout(bp, pl, op->dstrhex_no_ascii);
5829 goto filter_chk;
5830 }
5831 switch (pc) {
5832 case 0x0:
5833 printf(" Workload utilization:");
5834 if ((pl < 6) || (num < 6)) {
5835 if (num < 6)
5836 pr2serr("\n truncated by response length, expected "
5837 "at least 6 bytes\n");
5838 else
5839 pr2serr("\n parameter length >= 6 expected, got %d\n",
5840 pl);
5841 break;
5842 }
5843 k = sg_get_unaligned_be16(bp + 4);
5844 printf(" %d.%02d %%\n", k / 100, k % 100);
5845 break;
5846 case 0x1:
5847 printf(" Utilization usage rate based on date and time:");
5848 if ((pl < 6) || (num < 6)) {
5849 if (num < 6)
5850 pr2serr("\n truncated by response length, expected "
5851 "at least 6 bytes\n");
5852 else
5853 pr2serr("\n parameter length >= 6 expected, got %d\n",
5854 pl);
5855 break;
5856 }
5857 printf(" %d %%\n", bp[4]);
5858 break;
5859 default:
5860 printf(" Reserved [parameter_code=0x%x]:\n", pc);
5861 hex2stdout(bp, ((pl < num) ? pl : num), op->dstrhex_no_ascii);
5862 break;
5863 }
5864 if (op->do_pcb)
5865 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
5866 filter_chk:
5867 if (op->filter_given)
5868 break;
5869 skip:
5870 num -= pl;
5871 bp += pl;
5872 }
5873 return true;
5874 }
5875
5876 /* SOLID_STATE_MEDIA_LPAGE [0x11] <ssm> introduced: SBC-3 */
5877 static bool
show_solid_state_media_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)5878 show_solid_state_media_page(const uint8_t * resp, int len,
5879 struct opts_t * op, sgj_opaque_p jop)
5880 {
5881 int num, pl, pc;
5882 const uint8_t * bp;
5883 sgj_state * jsp = &op->json_st;
5884 sgj_opaque_p jo2p;
5885 sgj_opaque_p jo3p = NULL;
5886 sgj_opaque_p jap = NULL;
5887 char str[PCB_STR_LEN];
5888 static const char * ssmlp = "Solid state media log page";
5889 static const char * puei = "Percentage used endurance indicator";
5890
5891 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
5892 sgj_pr_hr(jsp, "%s [0x11]\n", ssmlp);
5893 if (jsp->pr_as_json) {
5894 jo2p = sg_log_js_hdr(jsp, jop, ssmlp, resp);
5895 jap = sgj_named_subarray_r(jsp, jo2p,
5896 "solid_state_media_log_parameters");
5897 }
5898 num = len - 4;
5899 bp = &resp[0] + 4;
5900 while (num > 3) {
5901 pc = sg_get_unaligned_be16(bp + 0);
5902 pl = bp[3] + 4;
5903 if (op->filter_given) {
5904 if (pc != op->filter)
5905 goto skip;
5906 }
5907 if (op->do_raw) {
5908 dStrRaw(bp, pl);
5909 goto filter_chk;
5910 } else if (op->do_hex) {
5911 hex2stdout(bp, pl, op->dstrhex_no_ascii);
5912 goto filter_chk;
5913 }
5914 if (jsp->pr_as_json) {
5915 jo3p = sgj_new_unattached_object_r(jsp);
5916 if (op->do_pcb)
5917 js_pcb(jsp, jo3p, bp[2]);
5918 }
5919
5920 switch (pc) {
5921 case 0x1:
5922 if ((pl < 8) || (num < 8)) {
5923 if (num < 8)
5924 pr2serr("\n truncated by response length, expected "
5925 "at least 8 bytes\n");
5926 else
5927 pr2serr("\n parameter length >= 8 expected, got %d\n",
5928 pl);
5929 break;
5930 }
5931 sgj_pr_hr(jsp, " %s: %u %%\n", puei, bp[7]);
5932 if (jsp->pr_as_json) {
5933 js_snakenv_ihexstr_nex(jsp, jo3p, param_c, pc, true,
5934 NULL, puei, NULL);
5935 js_snakenv_ihexstr_nex(jsp, jo3p, puei, bp[7], false,
5936 NULL, NULL, NULL);
5937 }
5938 break;
5939 default:
5940 printf(" Reserved [parameter_code=0x%x]:\n", pc);
5941 hex2stdout(bp, ((pl < num) ? pl : num), op->dstrhex_no_ascii);
5942 break;
5943 }
5944 if (jsp->pr_as_json)
5945 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
5946 if (op->do_pcb)
5947 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], str,
5948 sizeof(str)));
5949 filter_chk:
5950 if (op->filter_given)
5951 break;
5952 skip:
5953 num -= pl;
5954 bp += pl;
5955 }
5956 return true;
5957 }
5958
5959 static const char * dt_dev_activity[] = {
5960 "No DT device activity",
5961 "Cleaning operation in progress",
5962 "Volume is being loaded",
5963 "Volume is being unloaded",
5964 "Other medium activity",
5965 "Reading from medium",
5966 "Writing to medium",
5967 "Locating medium",
5968 "Rewinding medium", /* 8 */
5969 "Erasing volume",
5970 "Formatting volume",
5971 "Calibrating",
5972 "Other DT device activity",
5973 "Microcode update in progress",
5974 "Reading encrypted from medium",
5975 "Writing encrypted to medium",
5976 "Diagnostic operation in progress", /* 10 */
5977 };
5978
5979 /* DT device status [0x11] <dtds> (ssc, adc) */
5980 static bool
show_dt_device_status_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)5981 show_dt_device_status_page(const uint8_t * resp, int len,
5982 struct opts_t * op, sgj_opaque_p jop)
5983 {
5984 bool evsm_output = false;
5985 int num, pl, pc, j;
5986 const uint8_t * bp;
5987 char str[PCB_STR_LEN];
5988 char b[512];
5989
5990 if (jop) { };
5991 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
5992 printf("DT device status page (ssc-3, adc-3) [0x11]\n");
5993 num = len - 4;
5994 bp = &resp[0] + 4;
5995 while (num > 3) {
5996 pc = sg_get_unaligned_be16(bp + 0);
5997 pl = bp[3] + 4;
5998 if (op->filter_given) {
5999 if (pc != op->filter)
6000 goto skip;
6001 }
6002 if (op->do_raw) {
6003 dStrRaw(bp, pl);
6004 goto filter_chk;
6005 } else if (op->do_hex) {
6006 hex2stdout(bp, pl, op->dstrhex_no_ascii);
6007 goto filter_chk;
6008 }
6009 switch (pc) {
6010 case 0x0:
6011 printf(" Very high frequency data:\n");
6012 if ((pl < 8) || (num < 8)) {
6013 if (num < 8)
6014 pr2serr(" truncated by response length, expected at "
6015 "least 8 bytes\n");
6016 else
6017 pr2serr(" parameter length >= 8 expected, got %d\n",
6018 pl);
6019 break;
6020 }
6021 printf(" PAMR=%d HUI=%d MACC=%d CMPR=%d ", !!(0x80 & bp[4]),
6022 !!(0x40 & bp[4]), !!(0x20 & bp[4]), !!(0x10 & bp[4]));
6023 printf("WRTP=%d CRQST=%d CRQRD=%d DINIT=%d\n", !!(0x8 & bp[4]),
6024 !!(0x4 & bp[4]), !!(0x2 & bp[4]), !!(0x1 & bp[4]));
6025 printf(" INXTN=%d RAA=%d MPRSNT=%d ", !!(0x80 & bp[5]),
6026 !!(0x20 & bp[5]), !!(0x10 & bp[5]));
6027 printf("MSTD=%d MTHRD=%d MOUNTED=%d\n",
6028 !!(0x4 & bp[5]), !!(0x2 & bp[5]), !!(0x1 & bp[5]));
6029 printf(" DT device activity: ");
6030 j = bp[6];
6031 if (j < (int)SG_ARRAY_SIZE(dt_dev_activity))
6032 printf("%s\n", dt_dev_activity[j]);
6033 else if (j < 0x80)
6034 printf("Reserved [0x%x]\n", j);
6035 else
6036 printf("%s [0x%x]\n", vend_spec, j);
6037 printf(" VS=%d TDDEC=%d EPP=%d ", !!(0x80 & bp[7]),
6038 !!(0x20 & bp[7]), !!(0x10 & bp[7]));
6039 printf("ESR=%d RRQST=%d INTFC=%d TAFC=%d\n", !!(0x8 & bp[7]),
6040 !!(0x4 & bp[7]), !!(0x2 & bp[7]), !!(0x1 & bp[7]));
6041 break;
6042 case 0x1:
6043 printf(" Very high frequency polling delay: ");
6044 if ((pl < 6) || (num < 6)) {
6045 if (num < 6)
6046 pr2serr("\n truncated by response length, expected at "
6047 "least 6 bytes\n");
6048 else
6049 pr2serr("\n parameter length >= 6 expected, got %d\n",
6050 pl);
6051 break;
6052 }
6053 printf(" %d milliseconds\n", sg_get_unaligned_be16(bp + 4));
6054 break;
6055 case 0x2:
6056 printf(" DT device ADC data encryption control status (hex "
6057 "only now):\n");
6058 if ((pl < 12) || (num < 12)) {
6059 if (num < 12)
6060 pr2serr(" truncated by response length, expected at "
6061 "least 12 bytes\n");
6062 else
6063 pr2serr(" parameter length >= 12 expected, got %d\n",
6064 pl);
6065 break;
6066 }
6067 hex2fp(bp + 4, 8, " ", op->hex2str_oformat, stdout);
6068 break;
6069 case 0x3:
6070 printf(" Key management error data (hex only now):\n");
6071 if ((pl < 16) || (num < 16)) {
6072 if (num < 16)
6073 pr2serr(" truncated by response length, expected at "
6074 "least 16 bytes\n");
6075 else
6076 pr2serr(" parameter length >= 16 expected, got %d\n",
6077 pl);
6078 break;
6079 }
6080 hex2fp(bp + 4, 12, " ", op->hex2str_oformat, stdout);
6081 break;
6082 default:
6083 if ((pc >= 0x101) && (pc <= 0x1ff)) {
6084 printf(" Primary port %d status:\n", pc - 0x100);
6085 if (12 == bp[3]) { /* if length of desc is 12, assume SAS */
6086 printf(" SAS: negotiated physical link rate: %s\n",
6087 sas_negot_link_rate((0xf & (bp[4] >> 4)), b,
6088 sizeof(b)));
6089 printf(" signal=%d, pic=%d, ", !!(0x2 & bp[4]),
6090 !!(0x1 & bp[4]));
6091 printf("hashed SAS addr: 0x%u\n",
6092 sg_get_unaligned_be24(bp + 5));
6093 printf(" SAS addr: 0x%" PRIx64 "\n",
6094 sg_get_unaligned_be64(bp + 8));
6095 } else {
6096 printf(" non-SAS transport, in hex:\n");
6097 hex2fp(bp + 4, ((pl < num) ? pl : num) - 4, " ",
6098 op->hex2str_oformat, stdout);
6099 }
6100 } else if (pc >= 0x8000) {
6101 if (op->exclude_vendor) {
6102 if ((op->verbose > 0) && (0 == op->do_brief) &&
6103 (! evsm_output)) {
6104 evsm_output = true;
6105 printf(" %s parameter(s) being ignored\n",
6106 vend_spec);
6107 }
6108 } else {
6109 printf(" %s [%s=0x%x]:\n", vend_spec, param_c_sn, pc);
6110 hex2fp(bp, ((pl < num) ? pl : num), " ",
6111 op->hex2str_oformat, stdout);
6112 }
6113 } else {
6114 printf(" Reserved [%s=0x%x]:\n", param_c_sn, pc);
6115 hex2fp(bp, ((pl < num) ? pl : num), " ",
6116 op->hex2str_oformat, stdout);
6117 }
6118 break;
6119 }
6120 if (op->do_pcb)
6121 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
6122 filter_chk:
6123 if (op->filter_given)
6124 break;
6125 skip:
6126 num -= pl;
6127 bp += pl;
6128 }
6129 return true;
6130 }
6131
6132 /* TapeAlert response [0x12] <tar> (adc,ssc) */
6133 static bool
show_tapealert_response_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)6134 show_tapealert_response_page(const uint8_t * resp, int len,
6135 struct opts_t * op, sgj_opaque_p jop)
6136 {
6137 bool evsm_output = false;
6138 int num, pl, pc, k, mod, div;
6139 const uint8_t * bp;
6140 char str[PCB_STR_LEN];
6141
6142 if (jop) { };
6143 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
6144 printf("TapeAlert response page (ssc-3, adc-3) [0x12]\n");
6145 num = len - 4;
6146 bp = &resp[0] + 4;
6147 while (num > 3) {
6148 pc = sg_get_unaligned_be16(bp + 0);
6149 pl = bp[3] + 4;
6150 if (op->filter_given) {
6151 if (pc != op->filter)
6152 goto skip;
6153 }
6154 if (op->do_raw) {
6155 dStrRaw(bp, pl);
6156 goto filter_chk;
6157 } else if (op->do_hex) {
6158 hex2stdout(bp, pl, op->dstrhex_no_ascii);
6159 goto filter_chk;
6160 }
6161 switch (pc) {
6162 case 0x0:
6163 if (pl < 12) {
6164
6165 }
6166 for (k = 1; k < 0x41; ++k) {
6167 mod = ((k - 1) % 8);
6168 div = (k - 1) / 8;
6169 if (0 == mod) {
6170 if (div > 0)
6171 printf("\n");
6172 printf(" Flag%02Xh: %d", k, !! (bp[4 + div] & 0x80));
6173 } else
6174 printf(" %02Xh: %d", k,
6175 !! (bp[4 + div] & (1 << (7 - mod))));
6176 }
6177 printf("\n");
6178 break;
6179 default:
6180 if (pc <= 0x8000) {
6181 printf(" Reserved [parameter_code=0x%x]:\n", pc);
6182 hex2fp(bp, ((pl < num) ? pl : num), " ",
6183 op->hex2str_oformat, stdout);
6184 } else {
6185 if (op->exclude_vendor) {
6186 if ((op->verbose > 0) && (0 == op->do_brief) &&
6187 (! evsm_output)) {
6188 evsm_output = true;
6189 printf(" %s parameter(s) being ignored\n",
6190 vend_spec);
6191 }
6192 } else {
6193 printf(" %s [%s=0x%x]:\n", vend_spec, param_c_sn, pc);
6194 hex2fp(bp, ((pl < num) ? pl : num), " ",
6195 op->hex2str_oformat, stdout);
6196 }
6197 }
6198 break;
6199 }
6200 if (op->do_pcb)
6201 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
6202 filter_chk:
6203 if (op->filter_given)
6204 break;
6205 skip:
6206 num -= pl;
6207 bp += pl;
6208 }
6209 return true;
6210 }
6211
6212 #define NUM_REQ_REC_ARR_ELEMS 16
6213 static const char * req_rec_arr[NUM_REQ_REC_ARR_ELEMS] = {
6214 "Recovery not requested",
6215 "Recovery requested, no recovery procedure defined",
6216 "Instruct operator to push volume",
6217 "Instruct operator to remove and re-insert volume",
6218 "Issue UNLOAD command. Instruct operator to remove and re-insert volume",
6219 "Instruct operator to power cycle target device",
6220 "Issue LOAD command",
6221 "Issue UNLOAD command",
6222 "Issue LOGICAL UNIT RESET task management function", /* 0x8 */
6223 "No recovery procedure defined. Contact service organization",
6224 "Issue UNLOAD command. Instruct operator to remove and quarantine "
6225 "volume",
6226 "Instruct operator to not insert a volume. Contact service organization",
6227 "Issue UNLOAD command. Instruct operator to remove volume. Contact "
6228 "service organization",
6229 "Request creation of target device error log",
6230 "Retrieve a target device error log",
6231 "Modify configuration to all microcode update and instruct operator to "
6232 "re-insert volume", /* 0xf */
6233 };
6234
6235 /* REQ_RECOVERY_LPAGE Requested recovery [0x13] <rr> (ssc) */
6236 static bool
show_requested_recovery_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)6237 show_requested_recovery_page(const uint8_t * resp, int len,
6238 struct opts_t * op, sgj_opaque_p jop)
6239 {
6240 bool evsm_output = false;
6241 int num, pl, pc, j, k;
6242 const uint8_t * bp;
6243 char str[PCB_STR_LEN];
6244
6245 if (jop) { };
6246 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
6247 printf("Requested recovery page (ssc-3) [0x13]\n");
6248 num = len - 4;
6249 bp = &resp[0] + 4;
6250 while (num > 3) {
6251 pc = sg_get_unaligned_be16(bp + 0);
6252 pl = bp[3] + 4;
6253 if (op->filter_given) {
6254 if (pc != op->filter)
6255 goto skip;
6256 }
6257 if (op->do_raw) {
6258 dStrRaw(bp, pl);
6259 goto filter_chk;
6260 } else if (op->do_hex) {
6261 hex2stdout(bp, pl, op->dstrhex_no_ascii);
6262 goto filter_chk;
6263 }
6264 switch (pc) {
6265 case 0x0:
6266 printf(" Recovery procedures:\n");
6267 for (k = 4; k < pl; ++ k) {
6268 j = bp[k];
6269 if (j < NUM_REQ_REC_ARR_ELEMS)
6270 printf(" %s\n", req_rec_arr[j]);
6271 else if (j < 0x80)
6272 printf(" Reserved [0x%x]\n", j);
6273 else
6274 printf(" Vendor specific [0x%x]\n", j);
6275 }
6276 break;
6277 default:
6278 if (pc <= 0x8000) {
6279 printf(" Reserved [parameter_code=0x%x]:\n", pc);
6280 hex2fp(bp, ((pl < num) ? pl : num), " ",
6281 op->hex2str_oformat, stdout);
6282 } else {
6283 if (op->exclude_vendor) {
6284 if ((op->verbose > 0) && (0 == op->do_brief) &&
6285 (! evsm_output)) {
6286 evsm_output = true;
6287 printf(" Vendor specific parameter(s) being "
6288 "ignored\n");
6289 }
6290 } else {
6291 printf(" Vendor specific [parameter_code=0x%x]:\n", pc);
6292 hex2fp(bp, ((pl < num) ? pl : num), " ",
6293 op->hex2str_oformat, stdout);
6294 }
6295 }
6296 break;
6297 }
6298 if (op->do_pcb)
6299 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
6300 filter_chk:
6301 if (op->filter_given)
6302 break;
6303 skip:
6304 num -= pl;
6305 bp += pl;
6306 }
6307 return true;
6308 }
6309
6310 /* SAT_ATA_RESULTS_LPAGE (SAT-2) [0x16] <aptr> */
6311 static bool
show_ata_pt_results_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)6312 show_ata_pt_results_page(const uint8_t * resp, int len,
6313 struct opts_t * op, sgj_opaque_p jop)
6314 {
6315 int num, pl, pc;
6316 const uint8_t * bp;
6317 const uint8_t * dp;
6318 char str[PCB_STR_LEN];
6319
6320 if (jop) { };
6321 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
6322 printf("ATA pass-through results page (sat-2) [0x16]\n");
6323 num = len - 4;
6324 bp = &resp[0] + 4;
6325 while (num > 3) {
6326 pc = sg_get_unaligned_be16(bp + 0);
6327 pl = bp[3] + 4;
6328 if (op->filter_given) {
6329 if (pc != op->filter)
6330 goto skip;
6331 }
6332 if (op->do_raw) {
6333 dStrRaw(bp, pl);
6334 goto filter_chk;
6335 } else if (op->do_hex) {
6336 hex2stdout(bp, pl, op->dstrhex_no_ascii);
6337 goto filter_chk;
6338 }
6339 if ((pc < 0xf) && (pl > 17)) {
6340 int extend, count;
6341
6342 printf(" Log_index=0x%x (parameter_code=0x%x)\n", pc + 1, pc);
6343 dp = bp + 4; /* dp is start of ATA Return descriptor
6344 * which is 14 bytes long */
6345 extend = dp[2] & 1;
6346 count = dp[5] + (extend ? (dp[4] << 8) : 0);
6347 printf(" extend=%d error=0x%x count=0x%x\n", extend,
6348 dp[3], count);
6349 if (extend)
6350 printf(" lba=0x%02x%02x%02x%02x%02x%02x\n", dp[10], dp[8],
6351 dp[6], dp[11], dp[9], dp[7]);
6352 else
6353 printf(" lba=0x%02x%02x%02x\n", dp[11], dp[9], dp[7]);
6354 printf(" device=0x%x status=0x%x\n", dp[12], dp[13]);
6355 } else if (pl > 17) {
6356 printf(" Reserved [parameter_code=0x%x]:\n", pc);
6357 hex2fp(bp, ((pl < num) ? pl : num), " ",
6358 op->hex2str_oformat, stdout);
6359 } else {
6360 printf(" short parameter length: %d [parameter_code=0x%x]:\n",
6361 pl, pc);
6362 hex2fp(bp, ((pl < num) ? pl : num), " ",
6363 op->hex2str_oformat, stdout);
6364 }
6365 if (op->do_pcb)
6366 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
6367 filter_chk:
6368 if (op->filter_given)
6369 break;
6370 skip:
6371 num -= pl;
6372 bp += pl;
6373 }
6374 return true;
6375 }
6376
6377 static const char * bms_status[] = {
6378 "no background scans active",
6379 "background medium scan is active",
6380 "background pre-scan is active",
6381 "background scan halted due to fatal error",
6382 "background scan halted due to a vendor specific pattern of error",
6383 "background scan halted due to medium formatted without P-List",
6384 "background scan halted - vendor specific cause",
6385 "background scan halted due to temperature out of range",
6386 ("background scan enabled, none active (waiting for BMS interval timer "
6387 "to expire)"), /* clang warns about this, add parens to quieten */
6388 "background scan halted - scan results list full",
6389 "background scan halted - pre-scan time limit timer expired" /* 10 */,
6390 };
6391
6392 static const char * reassign_status[] = {
6393 "Reserved [0x0]",
6394 "Reassignment pending receipt of Reassign or Write command",
6395 "Logical block successfully reassigned by device server",
6396 "Reserved [0x3]",
6397 "Reassignment by device server failed",
6398 "Logical block recovered by device server via rewrite",
6399 "Logical block reassigned by application client, has valid data",
6400 "Logical block reassigned by application client, contains no valid data",
6401 "Logical block unsuccessfully reassigned by application client", /* 8 */
6402 };
6403
6404 /* Background scan results [0x15,0] <bsr> for disk introduced: SBC-3 */
6405 static bool
show_background_scan_results_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)6406 show_background_scan_results_page(const uint8_t * resp, int len,
6407 struct opts_t * op, sgj_opaque_p jop)
6408 {
6409 bool skip_out = false;
6410 bool evsm_output = false;
6411 bool ok;
6412 int j, m, n, num, pl, pc;
6413 const uint8_t * bp;
6414 double d;
6415 sgj_state * jsp = &op->json_st;
6416 sgj_opaque_p jo2p;
6417 sgj_opaque_p jo3p = NULL;
6418 sgj_opaque_p jap = NULL;
6419 char str[PCB_STR_LEN];
6420 char b[144];
6421 char e[80];
6422 static const int blen = sizeof(b);
6423 static const int elen = sizeof(e);
6424 static const char * bsrlp = "Background scan results log page";
6425 static const char * bss = "Background scan status";
6426 static const char * bms = "Background medium scan";
6427 static const char * bsr = "Background scan results";
6428 static const char * bs = "background scan";
6429 static const char * ms = "Medium scan";
6430 static const char * apom = "Accumulated power on minutes";
6431 static const char * rs = "Reassign status";
6432
6433 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
6434 sgj_pr_hr(jsp, "%s [0x15]\n", bsrlp);
6435 num = len - 4;
6436 bp = &resp[0] + 4;
6437 if (jsp->pr_as_json) {
6438 jo2p = sg_log_js_hdr(jsp, jop, bsrlp, resp);
6439 jap = sgj_named_subarray_r(jsp, jo2p, "background_scan_parameters");
6440 }
6441
6442 while (num > 3) {
6443 pc = sg_get_unaligned_be16(bp + 0);
6444 pl = bp[3] + 4;
6445 if (op->filter_given) {
6446 if (pc != op->filter)
6447 goto skip;
6448 }
6449 if (op->do_raw) {
6450 dStrRaw(bp, pl);
6451 goto filter_chk;
6452 } else if (op->do_hex) {
6453 hex2stdout(bp, pl, op->dstrhex_no_ascii);
6454 goto filter_chk;
6455 }
6456 if (jsp->pr_as_json) {
6457 jo3p = sgj_new_unattached_object_r(jsp);
6458 if (op->do_pcb)
6459 js_pcb(jsp, jo3p, bp[2]);
6460 }
6461
6462 switch (pc) {
6463 case 0:
6464 sgj_pr_hr(jsp, " Status parameters:\n");
6465 if (jsp->pr_as_json)
6466 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, bss);
6467 if ((pl < 16) || (num < 16)) {
6468 if (num < 16)
6469 pr2serr(" truncated by response length, expected at "
6470 "least 16 bytes\n");
6471 else
6472 pr2serr(" parameter length >= 16 expected, got %d\n",
6473 pl);
6474 break;
6475 }
6476 sg_scnpr(b, blen, " %s: ", apom);
6477 j = sg_get_unaligned_be32(bp + 4);
6478 sgj_pr_hr(jsp, "%s%d [h:m %d:%d]\n", b, j, (j / 60), (j % 60));
6479 if (jsp->pr_as_json)
6480 js_snakenv_ihexstr_nex(jsp, jo3p, apom, j, false, NULL, NULL,
6481 NULL);
6482 sg_scnpr(b, blen, " Status: ");
6483 j = bp[9];
6484 ok = (j < (int)SG_ARRAY_SIZE(bms_status));
6485 if (ok)
6486 sgj_pr_hr(jsp, "%s%s\n", b, bms_status[j]);
6487 else
6488 sgj_pr_hr(jsp, "%sunknown [0x%x] %s value\n", b, j, bss);
6489 if (jsp->pr_as_json)
6490 js_snakenv_ihexstr_nex(jsp, jo3p, bss, j, true, NULL,
6491 ok ? bms_status[j] : unknown_s, NULL);
6492 j = sg_get_unaligned_be16(bp + 10);
6493 snprintf(b, blen, "Number of %ss performed", bs);
6494 sgj_pr_hr(jsp, " %s: %d\n", b, j);
6495 if (jsp->pr_as_json)
6496 js_snakenv_ihexstr_nex(jsp, jo3p, b, j, true, NULL, NULL,
6497 NULL);
6498 j = sg_get_unaligned_be16(bp + 12);
6499 snprintf(b, blen, "%s progress", bms);
6500 d = (100.0 * j / 65536.0);
6501 #ifdef SG_LIB_MINGW
6502 snprintf(e, elen, "%g %%", d);
6503 #else
6504 snprintf(e, elen, "%.2f %%", d);
6505 #endif
6506 sgj_pr_hr(jsp, " %s: %s\n", b, e);
6507 if (jsp->pr_as_json)
6508 js_snakenv_ihexstr_nex(jsp, jo3p, b, j, true, NULL, e,
6509 NULL);
6510 j = sg_get_unaligned_be16(bp + 14);
6511 snprintf(b, blen, "Number of %ss performed", bms);
6512
6513 ok = (j > 0);
6514 if (ok)
6515 sgj_pr_hr(jsp, " %s: %d\n", b, j);
6516 else
6517 sgj_pr_hr(jsp, " %s: 0 [%s]\n", b, not_rep);
6518 if (jsp->pr_as_json)
6519 js_snakenv_ihexstr_nex(jsp, jo3p, b, j, true, NULL,
6520 ok ? NULL : not_rep, NULL);
6521 break;
6522 default:
6523 if (pc > 0x800) {
6524 if (jsp->pr_as_json)
6525 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL,
6526 (pc >= 0x8000) ? vend_spec : NULL);
6527 if ((pc >= 0x8000) && (pc <= 0xafff)) {
6528 if (op->exclude_vendor) {
6529 skip_out = true;
6530 if ((op->verbose > 0) && (0 == op->do_brief) &&
6531 (! evsm_output)) {
6532 evsm_output = true;
6533 sgj_pr_hr(jsp, " %s parameter(s) being "
6534 "ignored\n", vend_spec);
6535 }
6536 } else
6537 sgj_pr_hr(jsp, " %s parameter # %d [0x%x], %s\n",
6538 ms, pc, pc, vend_spec);
6539 } else
6540 sgj_pr_hr(jsp, " %s parameter # %d [0x%x], %s\n", ms, pc,
6541 pc, rsv_s);
6542 if (skip_out)
6543 skip_out = false;
6544 else
6545 hex2fp(bp, ((pl < num) ? pl : num), " ",
6546 op->hex2str_oformat, stdout);
6547 break;
6548 } else {
6549 sgj_pr_hr(jsp, " %s parameter # %d [0x%x]\n", ms, pc, pc);
6550 if (jsp->pr_as_json)
6551 sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, bsr);
6552 }
6553 if ((pl < 24) || (num < 24)) {
6554 if (num < 24)
6555 pr2serr(" truncated by response length, expected at "
6556 "least 24 bytes\n");
6557 else
6558 pr2serr(" parameter length >= 24 expected, got %d\n",
6559 pl);
6560 break;
6561 }
6562 j = sg_get_unaligned_be32(bp + 4);
6563 n = (j % 60);
6564 sgj_pr_hr(jsp, " %s when error detected: %d [%d:%d]\n", apom,
6565 j, (j / 60), n);
6566 if (jsp->pr_as_json) {
6567 snprintf(b, blen, "%d hours, %d minute%s", (j / 60), n,
6568 n != 1 ? "s" : "");
6569 js_snakenv_ihexstr_nex(jsp, jo3p, apom, j, true, NULL, b,
6570 "when error detected [unit: minute]");
6571 }
6572 j = (bp[8] >> 4) & 0xf;
6573 ok = (j < (int)SG_ARRAY_SIZE(reassign_status));
6574 if (ok)
6575 sgj_pr_hr(jsp, " %s: %s\n", rs, reassign_status[j]);
6576 else
6577 sgj_pr_hr(jsp, " %s: %s [0x%x]\n", rs, rsv_s, j);
6578 if (jsp->pr_as_json)
6579 js_snakenv_ihexstr_nex(jsp, jo3p, rs, j, true, NULL,
6580 ok ? reassign_status[j] : NULL, NULL);
6581 n = 0xf & b[8];
6582 sgj_pr_hr(jsp, " %s: %s [sk,asc,ascq: 0x%x,0x%x,0x%x]\n",
6583 s_key, sg_get_sense_key_str(n, blen, b), n, bp[9],
6584 bp[10]);
6585 if (bp[9] || bp[10])
6586 sgj_pr_hr(jsp, " %s\n",
6587 sg_get_asc_ascq_str(bp[9], bp[10], blen, b));
6588 if (jsp->pr_as_json) {
6589 sgj_js_nv_ihexstr(jsp, jo3p, "sense_key", n, NULL,
6590 sg_get_sense_key_str(n, blen, b));
6591 sgj_js_nv_ihexstr(jsp, jo3p, "additional_sense_code", bp[9],
6592 NULL, NULL);
6593 sgj_js_nv_ihexstr(jsp, jo3p, "additional_sense_code_qualifier",
6594 bp[10], NULL, sg_get_asc_ascq_str(bp[9],
6595 bp[10], blen, b));
6596 }
6597 if (op->verbose) {
6598 n = sg_scnpr(b, blen, " vendor bytes [11 -> 15]: ");
6599 for (m = 0; m < 5; ++m)
6600 n += sg_scnpr(b + n, blen - n, "0x%02x ", bp[11 + m]);
6601 sgj_pr_hr(jsp, "%s\n", b);
6602 }
6603 n = sg_scnpr(b, blen, " LBA (associated with medium error): "
6604 "0x");
6605 if (sg_all_zeros(bp + 16, 8))
6606 sgj_pr_hr(jsp, "%s0\n", b);
6607 else {
6608 for (m = 0; m < 8; ++m)
6609 n += sg_scnpr(b + n, blen - n, "%02x", bp[16 + m]);
6610 sgj_pr_hr(jsp, "%s\n", b);
6611 }
6612 if (jsp->pr_as_json)
6613 js_snakenv_ihexstr_nex(jsp, jo3p, "logical_block_address",
6614 sg_get_unaligned_be64(bp + 16), true,
6615 NULL, NULL, "of medium error");
6616 break;
6617 } /* end of switch statement block */
6618 if (jsp->pr_as_json)
6619 sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p);
6620 if (op->do_pcb)
6621 sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], str,
6622 sizeof(str)));
6623 filter_chk:
6624 if (op->filter_given)
6625 break;
6626 skip:
6627 num -= pl;
6628 bp += pl;
6629 }
6630 return true;
6631 }
6632
6633 /* ZONED_BLOCK_DEV_STATS_SUBPG [0x14,0x1] <zbds> introduced: zbc2r01 */
6634 static bool
show_zoned_block_dev_stats(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)6635 show_zoned_block_dev_stats(const uint8_t * resp, int len,
6636 struct opts_t * op, sgj_opaque_p jop)
6637 {
6638 bool trunc, bad_pl;
6639 int num, pl, pc;
6640 const uint8_t * bp;
6641 char str[PCB_STR_LEN];
6642
6643 if (jop) { };
6644 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
6645 printf("Zoned block device statistics page [0x14,0x1]\n");
6646 num = len - 4;
6647 bp = &resp[0] + 4;
6648 while (num > 3) {
6649 trunc = false;
6650 bad_pl = false;
6651 pc = sg_get_unaligned_be16(bp + 0);
6652 pl = bp[3] + 4;
6653 if (4 == pl) /* DC HC560 has empty descriptors */
6654 goto skip;
6655 if (op->filter_given) {
6656 if (pc != op->filter)
6657 goto skip;
6658 }
6659 if (op->do_raw) {
6660 dStrRaw(bp, pl);
6661 goto filter_chk;
6662 } else if (op->do_hex) {
6663 hex2stdout(bp, pl, op->dstrhex_no_ascii);
6664 goto filter_chk;
6665 }
6666 switch (pc) {
6667 case 0x0:
6668 if ((pl < 8) || (num < 8)) {
6669 if (num < 8)
6670 trunc = true;
6671 else
6672 bad_pl = true;
6673 } else
6674 printf(" Maximum open zones: %" PRIu32 "\n",
6675 sg_get_unaligned_be32(bp + 8));
6676 break;
6677 case 0x1:
6678 if ((pl < 8) || (num < 8)) {
6679 if (num < 8)
6680 trunc = true;
6681 else
6682 bad_pl = true;
6683 } else
6684 printf(" Maximum explicitly open zones: %" PRIu32 "\n",
6685 sg_get_unaligned_be32(bp + 8));
6686 break;
6687 case 0x2:
6688 if ((pl < 8) || (num < 8)) {
6689 if (num < 8)
6690 trunc = true;
6691 else
6692 bad_pl = true;
6693 } else
6694 printf(" Maximum implicitly open zones: %" PRIu32 "\n",
6695 sg_get_unaligned_be32(bp + 8));
6696 break;
6697 case 0x3:
6698 if ((pl < 8) || (num < 8)) {
6699 if (num < 8)
6700 trunc = true;
6701 else
6702 bad_pl = true;
6703 } else
6704 printf(" Minimum empty zones: %" PRIu32 "\n",
6705 sg_get_unaligned_be32(bp + 8));
6706 break;
6707 case 0x4:
6708 if ((pl < 8) || (num < 8)) {
6709 if (num < 8)
6710 trunc = true;
6711 else
6712 bad_pl = true;
6713 } else
6714 printf(" Maximum non-sequential zones: %" PRIu32 "\n",
6715 sg_get_unaligned_be32(bp + 8));
6716 break;
6717 case 0x5:
6718 if ((pl < 8) || (num < 8)) {
6719 if (num < 8)
6720 trunc = true;
6721 else
6722 bad_pl = true;
6723 } else
6724 printf(" Zones emptied: %" PRIu32 "\n",
6725 sg_get_unaligned_be32(bp + 8));
6726 break;
6727 case 0x6:
6728 if ((pl < 8) || (num < 8)) {
6729 if (num < 8)
6730 trunc = true;
6731 else
6732 bad_pl = true;
6733 } else
6734 printf(" Suboptimal write commands: %" PRIu32 "\n",
6735 sg_get_unaligned_be32(bp + 8));
6736 break;
6737 case 0x7:
6738 if ((pl < 8) || (num < 8)) {
6739 if (num < 8)
6740 trunc = true;
6741 else
6742 bad_pl = true;
6743 } else
6744 printf(" Commands exceeding optimal limit: %" PRIu32 "\n",
6745 sg_get_unaligned_be32(bp + 8));
6746 break;
6747 case 0x8:
6748 if ((pl < 8) || (num < 8)) {
6749 if (num < 8)
6750 trunc = true;
6751 else
6752 bad_pl = true;
6753 } else
6754 printf(" Failed explicit opens: %" PRIu32 "\n",
6755 sg_get_unaligned_be32(bp + 8));
6756 break;
6757 case 0x9:
6758 if ((pl < 8) || (num < 8)) {
6759 if (num < 8)
6760 trunc = true;
6761 else
6762 bad_pl = true;
6763 } else
6764 printf(" Read rule violations: %" PRIu32 "\n",
6765 sg_get_unaligned_be32(bp + 8));
6766 break;
6767 case 0xa:
6768 if ((pl < 8) || (num < 8)) {
6769 if (num < 8)
6770 trunc = true;
6771 else
6772 bad_pl = true;
6773 } else
6774 printf(" Write rule violations: %" PRIu32 "\n",
6775 sg_get_unaligned_be32(bp + 8));
6776 break;
6777 case 0xb: /* added zbc2r04 */
6778 if ((pl < 8) || (num < 8)) {
6779 if (num < 8)
6780 trunc = true;
6781 else
6782 bad_pl = true;
6783 } else
6784 printf(" Maximum implicitly open or before required zones: "
6785 "%" PRIu32 "\n", sg_get_unaligned_be32(bp + 8));
6786 break;
6787 default:
6788 printf(" Reserved [parameter_code=0x%x]:\n", pc);
6789 hex2fp(bp, ((pl < num) ? pl : num), " ",
6790 op->hex2str_oformat, stdout);
6791 break;
6792 }
6793 if (trunc)
6794 pr2serr(" truncated by response length, expected at least "
6795 "8 bytes\n");
6796 if (bad_pl)
6797 pr2serr(" parameter length >= 8 expected, got %d\n", pl);
6798 if (op->do_pcb)
6799 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
6800 filter_chk:
6801 if (op->filter_given)
6802 break;
6803 skip:
6804 num -= pl;
6805 bp += pl;
6806 }
6807 return true;
6808 }
6809
6810 /* PENDING_DEFECTS_SUBPG [0x15,0x1] <pd> introduced: SBC-4 */
6811 static bool
show_pending_defects_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)6812 show_pending_defects_page(const uint8_t * resp, int len,
6813 struct opts_t * op, sgj_opaque_p jop)
6814 {
6815 int num, pl, pc;
6816 uint32_t count;
6817 const uint8_t * bp;
6818 char str[PCB_STR_LEN];
6819
6820 if (jop) { };
6821 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
6822 printf("Pending defects page [0x15,0x1]\n");
6823 num = len - 4;
6824 bp = &resp[0] + 4;
6825 while (num > 3) {
6826 pc = sg_get_unaligned_be16(bp + 0);
6827 pl = bp[3] + 4;
6828 if (op->filter_given) {
6829 if (pc != op->filter)
6830 goto skip;
6831 }
6832 if (op->do_raw) {
6833 dStrRaw(bp, pl);
6834 goto filter_chk;
6835 } else if (op->do_hex) {
6836 hex2stdout(bp, pl, op->dstrhex_no_ascii);
6837 goto filter_chk;
6838 }
6839 switch (pc) {
6840 case 0x0:
6841 printf(" Pending defect count: ");
6842 if ((pl < 8) || (num < 8)) {
6843 if (num < 8)
6844 pr2serr("\n truncated by response length, expected "
6845 "at least 8 bytes\n");
6846 else
6847 pr2serr("\n parameter length >= 8 expected, got %d\n",
6848 pl);
6849 break;
6850 }
6851 count = sg_get_unaligned_be32(bp + 4);
6852 if (0 == count) {
6853 printf("0\n");
6854 break;
6855 }
6856 printf("%3u | LBA Accumulated power_on\n", count);
6857 printf("-----------------------------|---------------");
6858 printf("-----------hours---------\n");
6859 break;
6860 default:
6861 printf(" Pending defect %4d: ", pc);
6862 if ((pl < 16) || (num < 16)) {
6863 if (num < 16)
6864 pr2serr("\n truncated by response length, expected "
6865 "at least 16 bytes\n");
6866 else
6867 pr2serr("\n parameter length >= 16 expected, got %d\n",
6868 pl);
6869 break;
6870 }
6871 printf(" 0x%-16" PRIx64 " %5u\n",
6872 sg_get_unaligned_be64(bp + 8),
6873 sg_get_unaligned_be32(bp + 4));
6874 break;
6875 }
6876 if (op->do_pcb)
6877 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
6878 filter_chk:
6879 if (op->filter_given)
6880 break;
6881 skip:
6882 num -= pl;
6883 bp += pl;
6884 }
6885 return true;
6886 }
6887
6888 /* BACKGROUND_OP_SUBPG [0x15,0x2] <bop> introduced: SBC-4 rev 7 */
6889 static bool
show_background_op_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)6890 show_background_op_page(const uint8_t * resp, int len,
6891 struct opts_t * op, sgj_opaque_p jop)
6892 {
6893 int num, pl, pc;
6894 const uint8_t * bp;
6895 char str[PCB_STR_LEN];
6896
6897 if (jop) { };
6898 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
6899 printf("Background operation page [0x15,0x2]\n");
6900 num = len - 4;
6901 bp = &resp[0] + 4;
6902 while (num > 3) {
6903 pc = sg_get_unaligned_be16(bp + 0);
6904 pl = bp[3] + 4;
6905 if (op->filter_given) {
6906 if (pc != op->filter)
6907 goto skip;
6908 }
6909 if (op->do_raw) {
6910 dStrRaw(bp, pl);
6911 goto filter_chk;
6912 } else if (op->do_hex) {
6913 hex2stdout(bp, pl, op->dstrhex_no_ascii);
6914 goto filter_chk;
6915 }
6916 switch (pc) {
6917 case 0x0:
6918 printf(" Background operation:");
6919 if ((pl < 8) || (num < 8)) {
6920 if (num < 8)
6921 pr2serr("\n truncated by response length, expected "
6922 "at least 8 bytes\n");
6923 else
6924 pr2serr("\n parameter length >= 8 expected, got %d\n",
6925 pl);
6926 break;
6927 }
6928 printf(" BO_STATUS=%d\n", bp[4]);
6929 break;
6930 default:
6931 printf(" Reserved [parameter_code=0x%x]:\n", pc);
6932 hex2fp(bp, ((pl < num) ? pl : num), " ",
6933 op->hex2str_oformat, stdout);
6934 break;
6935 }
6936 if (op->do_pcb)
6937 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
6938 filter_chk:
6939 if (op->filter_given)
6940 break;
6941 skip:
6942 num -= pl;
6943 bp += pl;
6944 }
6945 return true;
6946 }
6947
6948 /* LPS misalignment page [0x15,0x3] <lps> introduced: SBC-4 rev 10
6949 LPS: "Long Physical Sector" a term from an ATA feature set */
6950 static bool
show_lps_misalignment_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)6951 show_lps_misalignment_page(const uint8_t * resp, int len,
6952 struct opts_t * op, sgj_opaque_p jop)
6953 {
6954 int num, pl, pc;
6955 const uint8_t * bp;
6956 char str[PCB_STR_LEN];
6957
6958 if (jop) { };
6959 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
6960 printf("LPS misalignment page [0x15,0x3]\n");
6961 num = len - 4;
6962 bp = &resp[0] + 4;
6963 while (num > 3) {
6964 pc = sg_get_unaligned_be16(bp + 0);
6965 pl = bp[3] + 4;
6966 if (op->filter_given) {
6967 if (pc != op->filter)
6968 goto skip;
6969 }
6970 if (op->do_raw) {
6971 dStrRaw(bp, pl);
6972 goto filter_chk;
6973 } else if (op->do_hex) {
6974 hex2stdout(bp, pl, op->dstrhex_no_ascii);
6975 goto filter_chk;
6976 }
6977 switch (pc) {
6978 case 0x0:
6979 printf(" LPS misalignment count: ");
6980 if (4 == bp[3])
6981 printf("max lpsm: %" PRIu16 ", count=%" PRIu16 "\n",
6982 sg_get_unaligned_be16(bp + 4),
6983 sg_get_unaligned_be16(bp + 6));
6984 else
6985 printf("<unexpected pc=0 parameter length=%d>\n", bp[4]);
6986 break;
6987 default:
6988 if (pc <= 0xf000) { /* parameter codes 0x1 to 0xf000 */
6989 if (8 == bp[3])
6990 printf(" LBA of misaligned block: 0x%" PRIx64 "\n",
6991 sg_get_unaligned_be64(bp + 4));
6992 else
6993 printf("<unexpected pc=0x%x parameter length=%d>\n",
6994 pc, bp[4]);
6995 } else {
6996 printf("<unexpected pc=0x%x>\n", pc);
6997 hex2fp(bp, ((pl < num) ? pl : num), " ",
6998 op->hex2str_oformat, stdout);
6999 }
7000 break;
7001 }
7002 if (op->do_pcb)
7003 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
7004 filter_chk:
7005 if (op->filter_given)
7006 break;
7007 skip:
7008 num -= pl;
7009 bp += pl;
7010 }
7011 return true;
7012 }
7013
7014 /* Service buffer information [0x15] <sbi> (adc) */
7015 static bool
show_service_buffer_info_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)7016 show_service_buffer_info_page(const uint8_t * resp, int len,
7017 struct opts_t * op, sgj_opaque_p jop)
7018 {
7019 bool evsm_output = false;
7020 int num, pl, pc;
7021 const uint8_t * bp;
7022 char str[PCB_STR_LEN];
7023
7024 if (jop) { };
7025 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
7026 printf("Service buffer information page (adc-3) [0x15]\n");
7027 num = len - 4;
7028 bp = &resp[0] + 4;
7029 while (num > 3) {
7030 pc = sg_get_unaligned_be16(bp + 0);
7031 pl = bp[3] + 4;
7032 if (op->filter_given) {
7033 if (pc != op->filter)
7034 goto skip;
7035 }
7036 if (op->do_raw) {
7037 dStrRaw(bp, pl);
7038 goto filter_chk;
7039 } else if (op->do_hex) {
7040 hex2stdout(bp, pl, op->dstrhex_no_ascii);
7041 goto filter_chk;
7042 }
7043 if (pc < 0x100) {
7044 printf(" Service buffer identifier: 0x%x\n", pc);
7045 printf(" Buffer id: 0x%x, tu=%d, nmp=%d, nmm=%d, "
7046 "offline=%d\n", bp[4], !!(0x10 & bp[5]),
7047 !!(0x8 & bp[5]), !!(0x4 & bp[5]), !!(0x2 & bp[5]));
7048 printf(" pd=%d, code_set: %s, Service buffer title:\n",
7049 !!(0x1 & bp[5]), sg_get_desig_code_set_str(0xf & bp[6]));
7050 printf(" %.*s\n", pl - 8, bp + 8);
7051 } else if (pc < 0x8000) {
7052 printf(" parameter_code=0x%x, Reserved, parameter in hex:\n",
7053 pc);
7054 hex2fp(bp + 4, pl - 4, " ", op->hex2str_oformat, stdout);
7055 } else {
7056 if (op->exclude_vendor) {
7057 if ((op->verbose > 0) && (0 == op->do_brief) &&
7058 (! evsm_output)) {
7059 evsm_output = true;
7060 printf(" Vendor specific parameter(s) being "
7061 "ignored\n");
7062 }
7063 } else {
7064 printf(" parameter_code=0x%x, Vendor-specific, parameter in "
7065 "hex:\n", pc);
7066 hex2fp(bp + 4, pl - 4, " ", op->hex2str_oformat, stdout);
7067 }
7068 }
7069 if (op->do_pcb)
7070 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
7071 filter_chk:
7072 if (op->filter_given)
7073 break;
7074 skip:
7075 num -= pl;
7076 bp += pl;
7077 }
7078 return true;
7079 }
7080
7081 /* Sequential access device page [0xc] <sad> for tape */
7082 static bool
show_sequential_access_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)7083 show_sequential_access_page(const uint8_t * resp, int len,
7084 struct opts_t * op, sgj_opaque_p jop)
7085 {
7086 bool evsm_output = false;
7087 int num, pl, pc;
7088 const uint8_t * bp;
7089 uint64_t ull, gbytes;
7090 bool all_set;
7091 char str[PCB_STR_LEN];
7092
7093 if (jop) { };
7094 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
7095 printf("Sequential access device page (ssc-3)\n");
7096 num = len - 4;
7097 bp = &resp[0] + 4;
7098 while (num > 3) {
7099 pc = sg_get_unaligned_be16(bp + 0);
7100 pl = bp[3] + 4;
7101 if (op->filter_given) {
7102 if (pc != op->filter)
7103 goto skip;
7104 }
7105 if (op->do_raw) {
7106 dStrRaw(bp, pl);
7107 goto filter_chk;
7108 } else if (op->do_hex) {
7109 hex2stdout(bp, pl, op->dstrhex_no_ascii);
7110 goto filter_chk;
7111 }
7112 ull = sg_get_unaligned_be(pl - 4, bp + 4);
7113 all_set = sg_all_ffs(bp + 4, pl - 4);
7114 gbytes = ull / 1000000000;
7115 switch (pc) {
7116 case 0:
7117 printf(" Data bytes received with WRITE commands: %" PRIu64
7118 " GB", gbytes);
7119 if (op->verbose)
7120 printf(" [%" PRIu64 " bytes]", ull);
7121 printf("\n");
7122 break;
7123 case 1:
7124 printf(" Data bytes written to media by WRITE commands: %" PRIu64
7125 " GB", gbytes);
7126 if (op->verbose)
7127 printf(" [%" PRIu64 " bytes]", ull);
7128 printf("\n");
7129 break;
7130 case 2:
7131 printf(" Data bytes read from media by READ commands: %" PRIu64
7132 " GB", gbytes);
7133 if (op->verbose)
7134 printf(" [%" PRIu64 " bytes]", ull);
7135 printf("\n");
7136 break;
7137 case 3:
7138 printf(" Data bytes transferred by READ commands: %" PRIu64
7139 " GB", gbytes);
7140 if (op->verbose)
7141 printf(" [%" PRIu64 " bytes]", ull);
7142 printf("\n");
7143 break;
7144 case 4:
7145 if (! all_set)
7146 printf(" Native capacity from BOP to EOD: %" PRIu64 " MB\n",
7147 ull);
7148 break;
7149 case 5:
7150 if (! all_set)
7151 printf(" Native capacity from BOP to EW of current "
7152 "partition: %" PRIu64 " MB\n", ull);
7153 break;
7154 case 6:
7155 if (! all_set)
7156 printf(" Minimum native capacity from EW to EOP of current "
7157 "partition: %" PRIu64 " MB\n", ull);
7158 break;
7159 case 7:
7160 if (! all_set)
7161 printf(" Native capacity from BOP to current position: %"
7162 PRIu64 " MB\n", ull);
7163 break;
7164 case 8:
7165 if (! all_set)
7166 printf(" Maximum native capacity in device object buffer: %"
7167 PRIu64 " MB\n", ull);
7168 break;
7169 case 0x100:
7170 if (ull > 0)
7171 printf(" Cleaning action required\n");
7172 else
7173 printf(" Cleaning action not required (or completed)\n");
7174 if (op->verbose)
7175 printf(" cleaning value: %" PRIu64 "\n", ull);
7176 break;
7177 default:
7178 if (pc >= 0x8000) {
7179 if (op->exclude_vendor) {
7180 if ((op->verbose > 0) && (0 == op->do_brief) &&
7181 (! evsm_output)) {
7182 evsm_output = true;
7183 printf(" Vendor specific parameter(s) being "
7184 "ignored\n");
7185 }
7186 } else
7187 printf(" Vendor specific parameter [0x%x] value: %"
7188 PRIu64 "\n", pc, ull);
7189 } else
7190 printf(" Reserved parameter [0x%x] value: %" PRIu64 "\n",
7191 pc, ull);
7192 break;
7193 }
7194 if (op->do_pcb)
7195 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
7196 filter_chk:
7197 if (op->filter_given)
7198 break;
7199 skip:
7200 num -= pl;
7201 bp += pl;
7202 }
7203 return true;
7204 }
7205
7206 /* Device statistics 0x14 <ds> for tape and ADC */
7207 static bool
show_device_stats_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)7208 show_device_stats_page(const uint8_t * resp, int len,
7209 struct opts_t * op, sgj_opaque_p jop)
7210 {
7211 bool evsm_output = false;
7212 int num, pl, pc;
7213 const uint8_t * bp;
7214 char str[PCB_STR_LEN];
7215
7216 if (jop) { };
7217 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
7218 printf("Device statistics page (ssc-3 and adc)\n");
7219 num = len - 4;
7220 bp = &resp[0] + 4;
7221 while (num > 3) {
7222 pc = sg_get_unaligned_be16(bp + 0);
7223 pl = bp[3] + 4;
7224 if (op->filter_given) {
7225 if (pc != op->filter)
7226 goto skip;
7227 }
7228 if (op->do_raw) {
7229 dStrRaw(bp, pl);
7230 goto filter_chk;
7231 } else if (op->do_hex) {
7232 hex2stdout(bp, pl, op->dstrhex_no_ascii);
7233 goto filter_chk;
7234 }
7235 if (pc < 0x1000) {
7236 bool vl_num = true;
7237
7238 switch (pc) {
7239 case 0:
7240 printf(" Lifetime media loads:");
7241 break;
7242 case 1:
7243 printf(" Lifetime cleaning operations:");
7244 break;
7245 case 2:
7246 printf(" Lifetime power on hours:");
7247 break;
7248 case 3:
7249 printf(" Lifetime media motion (head) hours:");
7250 break;
7251 case 4:
7252 printf(" Lifetime metres of tape processed:");
7253 break;
7254 case 5:
7255 printf(" Lifetime media motion (head) hours when "
7256 "incompatible media last loaded:");
7257 break;
7258 case 6:
7259 printf(" Lifetime power on hours when last temperature "
7260 "condition occurred:");
7261 break;
7262 case 7:
7263 printf(" Lifetime power on hours when last power "
7264 "consumption condition occurred:");
7265 break;
7266 case 8:
7267 printf(" Media motion (head) hours since last successful "
7268 "cleaning operation:");
7269 break;
7270 case 9:
7271 printf(" Media motion (head) hours since 2nd to last "
7272 "successful cleaning:");
7273 break;
7274 case 0xa:
7275 printf(" Media motion (head) hours since 3rd to last "
7276 "successful cleaning:");
7277 break;
7278 case 0xb:
7279 printf(" Lifetime power on hours when last operator "
7280 "initiated forced reset\n and/or emergency "
7281 "eject occurred:");
7282 break;
7283 case 0xc:
7284 printf(" Lifetime power cycles:");
7285 break;
7286 case 0xd:
7287 printf(" Volume loads since last parameter reset:");
7288 break;
7289 case 0xe:
7290 printf(" Hard write errors:");
7291 break;
7292 case 0xf:
7293 printf(" Hard read errors:");
7294 break;
7295 case 0x10:
7296 printf(" Duty cycle sample time (ms):");
7297 break;
7298 case 0x11:
7299 printf(" Read duty cycle:");
7300 break;
7301 case 0x12:
7302 printf(" Write duty cycle:");
7303 break;
7304 case 0x13:
7305 printf(" Activity duty cycle:");
7306 break;
7307 case 0x14:
7308 printf(" Volume not present duty cycle:");
7309 break;
7310 case 0x15:
7311 printf(" Ready duty cycle:");
7312 break;
7313 case 0x16:
7314 printf(" MBs transferred from app client in duty cycle "
7315 "sample time:");
7316 break;
7317 case 0x17:
7318 printf(" MBs transferred to app client in duty cycle "
7319 "sample time:");
7320 break;
7321 case 0x40:
7322 printf(" Drive manufacturer's serial number:");
7323 break;
7324 case 0x41:
7325 printf(" Drive serial number:");
7326 break;
7327 case 0x42: /* added ssc5r02b */
7328 vl_num = false;
7329 printf(" Manufacturing date (yyyymmdd): %.*s\n", pl - 4,
7330 bp + 4);
7331 break;
7332 case 0x43: /* added ssc5r02b */
7333 vl_num = false;
7334 printf(" Manufacturing date (yyyyww): %.*s\n", pl - 4,
7335 bp + 4);
7336 break;
7337 case 0x80:
7338 printf(" Medium removal prevented:");
7339 break;
7340 case 0x81:
7341 printf(" Maximum recommended mechanism temperature "
7342 "exceeded:");
7343 break;
7344 default:
7345 vl_num = false;
7346 printf(" Reserved %s [0x%x] data in hex:\n", param_c, pc);
7347 hex2fp(bp + 4, pl - 4, " ", op->hex2str_oformat, stdout);
7348 break;
7349 }
7350 if (vl_num)
7351 printf(" %" PRIu64 "\n", sg_get_unaligned_be(pl - 4, bp + 4));
7352 } else { /* parameter_code >= 0x1000 */
7353 int k;
7354 const uint8_t * p = bp + 4;
7355
7356 switch (pc) {
7357 case 0x1000:
7358 printf(" Media motion (head) hours for each medium type:\n");
7359 for (k = 0; ((pl - 4) - k) >= 8; k += 8, p += 8)
7360 printf(" [%d] Density code: %u, Medium type: 0x%x, "
7361 "hours: %u\n", ((k / 8) + 1), p[2], p[3],
7362 sg_get_unaligned_be32(p + 4));
7363 break;
7364 default:
7365 if (pc >= 0x8000) {
7366 if (op->exclude_vendor) {
7367 if ((op->verbose > 0) && (0 == op->do_brief) &&
7368 (! evsm_output)) {
7369 evsm_output = true;
7370 printf(" Vendor specific parameter(s) being "
7371 "ignored\n");
7372 }
7373 } else
7374 printf(" Vendor specific parameter [0x%x], dump in "
7375 "hex:\n", pc);
7376 } else {
7377 printf(" Reserved parameter [0x%x], dump in hex:\n", pc);
7378 hex2fp(bp + 4, pl - 4, " ", op->hex2str_oformat,
7379 stdout);
7380 }
7381 break;
7382 }
7383 }
7384 if (op->do_pcb)
7385 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
7386 filter_chk:
7387 if (op->filter_given)
7388 break;
7389 skip:
7390 num -= pl;
7391 bp += pl;
7392 }
7393 return true;
7394 }
7395
7396 /* Media changer statistics 0x14 <mcs> for media changer */
7397 static bool
show_media_stats_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)7398 show_media_stats_page(const uint8_t * resp, int len, struct opts_t * op,
7399 sgj_opaque_p jop)
7400 {
7401 int num, pl, pc;
7402 const uint8_t * bp;
7403 uint64_t ull;
7404 char str[PCB_STR_LEN];
7405
7406 if (jop) { };
7407 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
7408 printf("Media statistics page (smc-3)\n");
7409 num = len - 4;
7410 bp = &resp[0] + 4;
7411 while (num > 3) {
7412 pc = sg_get_unaligned_be16(bp + 0);
7413 pl = bp[3] + 4;
7414 if (op->filter_given) {
7415 if (pc != op->filter)
7416 goto skip;
7417 }
7418 if (op->do_raw) {
7419 dStrRaw(bp, pl);
7420 goto filter_chk;
7421 } else if (op->do_hex) {
7422 hex2stdout(bp, pl, op->dstrhex_no_ascii);
7423 goto filter_chk;
7424 }
7425 ull = sg_get_unaligned_be(pl - 4, bp + 4);
7426 switch (pc) {
7427 case 0:
7428 printf(" Number of moves: %" PRIu64 "\n", ull);
7429 break;
7430 case 1:
7431 printf(" Number of picks: %" PRIu64 "\n", ull);
7432 break;
7433 case 2:
7434 printf(" Number of pick retries: %" PRIu64 "\n", ull);
7435 break;
7436 case 3:
7437 printf(" Number of places: %" PRIu64 "\n", ull);
7438 break;
7439 case 4:
7440 printf(" Number of place retries: %" PRIu64 "\n", ull);
7441 break;
7442 case 5:
7443 printf(" Number of volume tags read by volume "
7444 "tag reader: %" PRIu64 "\n", ull);
7445 break;
7446 case 6:
7447 printf(" Number of invalid volume tags returned by "
7448 "volume tag reader: %" PRIu64 "\n", ull);
7449 break;
7450 case 7:
7451 printf(" Number of library door opens: %" PRIu64 "\n", ull);
7452 break;
7453 case 8:
7454 printf(" Number of import/export door opens: %" PRIu64 "\n",
7455 ull);
7456 break;
7457 case 9:
7458 printf(" Number of physical inventory scans: %" PRIu64 "\n",
7459 ull);
7460 break;
7461 case 0xa:
7462 printf(" Number of medium transport unrecovered errors: "
7463 "%" PRIu64 "\n", ull);
7464 break;
7465 case 0xb:
7466 printf(" Number of medium transport recovered errors: "
7467 "%" PRIu64 "\n", ull);
7468 break;
7469 case 0xc:
7470 printf(" Number of medium transport X axis translation "
7471 "unrecovered errors: %" PRIu64 "\n", ull);
7472 break;
7473 case 0xd:
7474 printf(" Number of medium transport X axis translation "
7475 "recovered errors: %" PRIu64 "\n", ull);
7476 break;
7477 case 0xe:
7478 printf(" Number of medium transport Y axis translation "
7479 "unrecovered errors: %" PRIu64 "\n", ull);
7480 break;
7481 case 0xf:
7482 printf(" Number of medium transport Y axis translation "
7483 "recovered errors: %" PRIu64 "\n", ull);
7484 break;
7485 case 0x10:
7486 printf(" Number of medium transport Z axis translation "
7487 "unrecovered errors: %" PRIu64 "\n", ull);
7488 break;
7489 case 0x11:
7490 printf(" Number of medium transport Z axis translation "
7491 "recovered errors: %" PRIu64 "\n", ull);
7492 break;
7493 case 0x12:
7494 printf(" Number of medium transport rotational translation "
7495 "unrecovered errors: %" PRIu64 "\n", ull);
7496 break;
7497 case 0x13:
7498 printf(" Number of medium transport rotational translation "
7499 "recovered errors: %" PRIu64 "\n", ull);
7500 break;
7501 case 0x14:
7502 printf(" Number of medium transport inversion translation "
7503 "unrecovered errors: %" PRIu64 "\n", ull);
7504 break;
7505 case 0x15:
7506 printf(" Number of medium transport inversion translation "
7507 "recovered errors: %" PRIu64 "\n", ull);
7508 break;
7509 case 0x16:
7510 printf(" Number of medium transport auxiliary translation "
7511 "unrecovered errors: %" PRIu64 "\n", ull);
7512 break;
7513 case 0x17:
7514 printf(" Number of medium transport auxiliary translation "
7515 "recovered errors: %" PRIu64 "\n", ull);
7516 break;
7517 default:
7518 printf(" Reserved parameter [0x%x] value: %" PRIu64 "\n",
7519 pc, ull);
7520 break;
7521 }
7522 if (op->do_pcb)
7523 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
7524 filter_chk:
7525 if (op->filter_given)
7526 break;
7527 skip:
7528 num -= pl;
7529 bp += pl;
7530 }
7531 return true;
7532 }
7533
7534 /* Element statistics page, 0x15 <els> for SMC */
7535 static bool
show_element_stats_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)7536 show_element_stats_page(const uint8_t * resp, int len,
7537 struct opts_t * op, sgj_opaque_p jop)
7538 {
7539 int num, pl, pc;
7540 unsigned int v;
7541 const uint8_t * bp;
7542 char str[PCB_STR_LEN];
7543
7544 if (jop) { };
7545 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
7546 printf("Element statistics page (smc-3) [0x15]\n");
7547 num = len - 4;
7548 bp = &resp[0] + 4;
7549 while (num > 3) {
7550 pc = sg_get_unaligned_be16(bp + 0);
7551 pl = bp[3] + 4;
7552 if (op->filter_given) {
7553 if (pc != op->filter)
7554 goto skip;
7555 }
7556 if (op->do_raw) {
7557 dStrRaw(bp, pl);
7558 goto filter_chk;
7559 } else if (op->do_hex) {
7560 hex2stdout(bp, pl, op->dstrhex_no_ascii);
7561 goto filter_chk;
7562 }
7563 printf(" Element address: %d\n", pc);
7564 v = sg_get_unaligned_be32(bp + 4);
7565 printf(" Number of places: %u\n", v);
7566 v = sg_get_unaligned_be32(bp + 8);
7567 printf(" Number of place retries: %u\n", v);
7568 v = sg_get_unaligned_be32(bp + 12);
7569 printf(" Number of picks: %u\n", v);
7570 v = sg_get_unaligned_be32(bp + 16);
7571 printf(" Number of pick retries: %u\n", v);
7572 v = sg_get_unaligned_be32(bp + 20);
7573 printf(" Number of determined volume identifiers: %u\n", v);
7574 v = sg_get_unaligned_be32(bp + 24);
7575 printf(" Number of unreadable volume identifiers: %u\n", v);
7576 if (op->do_pcb)
7577 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
7578 filter_chk:
7579 if (op->filter_given)
7580 break;
7581 skip:
7582 num -= pl;
7583 bp += pl;
7584 }
7585 return true;
7586 }
7587
7588 /* Tape diagnostic data [0x16] <tdd> for tape */
7589 static bool
show_tape_diag_data_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)7590 show_tape_diag_data_page(const uint8_t * resp, int len,
7591 struct opts_t * op, sgj_opaque_p jop)
7592 {
7593 int k, n, num, pl, pc;
7594 unsigned int v;
7595 const uint8_t * bp;
7596 char str[PCB_STR_LEN];
7597 char b[512];
7598
7599 if (jop) { };
7600 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
7601 printf("Tape diagnostics data page (ssc-3) [0x16]\n");
7602 num = len - 4;
7603 bp = &resp[0] + 4;
7604 while (num > 3) {
7605 pc = sg_get_unaligned_be16(bp + 0);
7606 pl = bp[3] + 4;
7607 if (op->filter_given) {
7608 if (pc != op->filter)
7609 goto skip;
7610 }
7611 if (op->do_raw) {
7612 dStrRaw(bp, pl);
7613 goto filter_chk;
7614 } else if (op->do_hex) {
7615 hex2stdout(bp, pl, op->dstrhex_no_ascii);
7616 goto filter_chk;
7617 }
7618 printf(" %s: %d\n", param_c, pc);
7619 printf(" Density code: 0x%x\n", bp[6]);
7620 printf(" Medium type: 0x%x\n", bp[7]);
7621 v = sg_get_unaligned_be32(bp + 8);
7622 printf(" Lifetime media motion hours: %u\n", v);
7623 printf(" Repeat: %d\n", !!(bp[13] & 0x80));
7624 v = bp[13] & 0xf;
7625 printf(" Sense key: 0x%x [%s]\n", v,
7626 sg_get_sense_key_str(v, sizeof(b), b));
7627 printf(" Additional sense code: 0x%x\n", bp[14]);
7628 printf(" Additional sense code qualifier: 0x%x\n", bp[15]);
7629 if (bp[14] || bp[15])
7630 printf(" [%s]\n", sg_get_asc_ascq_str(bp[14], bp[15],
7631 sizeof(b), b));
7632 v = sg_get_unaligned_be32(bp + 16);
7633 printf(" Vendor specific code qualifier: 0x%x\n", v);
7634 v = sg_get_unaligned_be32(bp + 20);
7635 printf(" Product revision level: %u\n", v);
7636 v = sg_get_unaligned_be32(bp + 24);
7637 printf(" Hours since last clean: %u\n", v);
7638 printf(" Operation code: 0x%x\n", bp[28]);
7639 printf(" Service action: 0x%x\n", bp[29] & 0xf);
7640 // Check Medium id number for all zeros
7641 // ssc4r03.pdf does not define this field, why? xxxxxx
7642 if (sg_all_zeros(bp + 32, 32))
7643 printf(" Medium id number is 32 bytes of zero\n");
7644 else {
7645 hex2str(bp + 32, 32, " ", 0 /* with ASCII */, sizeof(b), b);
7646 printf(" Medium id number (in hex):\n%s", b);
7647 }
7648 printf(" Timestamp origin: 0x%x\n", bp[64] & 0xf);
7649 // Check Timestamp for all zeros
7650 if (sg_all_zeros(bp + 66, 6))
7651 printf(" Timestamp is all zeros:\n");
7652 else {
7653 hex2str(bp + 66, 6, NULL, op->hex2str_oformat, sizeof(b), b);
7654 printf(" Timestamp: %s", b);
7655 }
7656 if (pl > 72) {
7657 n = pl - 72;
7658 k = hex2str(bp + 72, n, " ", op->hex2str_oformat,
7659 sizeof(b), b);
7660 printf(" Vendor specific:\n");
7661 printf("%s", b);
7662 if (k >= (int)sizeof(b) - 1)
7663 printf(" <truncated>\n");
7664 }
7665 if (op->do_pcb)
7666 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
7667 filter_chk:
7668 if (op->filter_given)
7669 break;
7670 skip:
7671 num -= pl;
7672 bp += pl;
7673 }
7674 return true;
7675 }
7676
7677 /* Media changer diagnostic data [0x16] <mcdd> for media changer */
7678 static bool
show_mchanger_diag_data_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)7679 show_mchanger_diag_data_page(const uint8_t * resp, int len,
7680 struct opts_t * op, sgj_opaque_p jop)
7681 {
7682 int num, pl, pc;
7683 unsigned int v;
7684 const uint8_t * bp;
7685 char str[PCB_STR_LEN];
7686 char b[512];
7687
7688 if (jop) { };
7689 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
7690 printf("Media changer diagnostics data page (smc-3) [0x16]\n");
7691 num = len - 4;
7692 bp = &resp[0] + 4;
7693 while (num > 3) {
7694 pc = sg_get_unaligned_be16(bp + 0);
7695 pl = bp[3] + 4;
7696 if (op->filter_given) {
7697 if (pc != op->filter)
7698 goto skip;
7699 }
7700 if (op->do_raw) {
7701 dStrRaw(bp, pl);
7702 goto filter_chk;
7703 } else if (op->do_hex) {
7704 hex2stdout(bp, pl, op->dstrhex_no_ascii);
7705 goto filter_chk;
7706 }
7707 printf(" %s: %d\n", param_c, pc);
7708 printf(" Repeat: %d\n", !!(bp[5] & 0x80));
7709 v = bp[5] & 0xf;
7710 printf(" Sense key: 0x%x [%s]\n", v,
7711 sg_get_sense_key_str(v, sizeof(b), b));
7712 printf(" Additional sense code: 0x%x\n", bp[6]);
7713 printf(" Additional sense code qualifier: 0x%x\n", bp[7]);
7714 if (bp[6] || bp[7])
7715 printf(" [%s]\n", sg_get_asc_ascq_str(bp[6], bp[7],
7716 sizeof(b), b));
7717 v = sg_get_unaligned_be32(bp + 8);
7718 printf(" Vendor specific code qualifier: 0x%x\n", v);
7719 v = sg_get_unaligned_be32(bp + 12);
7720 printf(" Product revision level: %u\n", v);
7721 v = sg_get_unaligned_be32(bp + 16);
7722 printf(" Number of moves: %u\n", v);
7723 v = sg_get_unaligned_be32(bp + 20);
7724 printf(" Number of pick: %u\n", v);
7725 v = sg_get_unaligned_be32(bp + 24);
7726 printf(" Number of pick retries: %u\n", v);
7727 v = sg_get_unaligned_be32(bp + 28);
7728 printf(" Number of places: %u\n", v);
7729 v = sg_get_unaligned_be32(bp + 32);
7730 printf(" Number of place retries: %u\n", v);
7731 v = sg_get_unaligned_be32(bp + 36);
7732 printf(" Number of determined volume identifiers: %u\n", v);
7733 v = sg_get_unaligned_be32(bp + 40);
7734 printf(" Number of unreadable volume identifiers: %u\n", v);
7735 printf(" Operation code: 0x%x\n", bp[44]);
7736 printf(" Service action: 0x%x\n", bp[45] & 0xf);
7737 printf(" Media changer error type: 0x%x\n", bp[46]);
7738 printf(" MTAV: %d\n", !!(bp[47] & 0x8));
7739 printf(" IAV: %d\n", !!(bp[47] & 0x4));
7740 printf(" LSAV: %d\n", !!(bp[47] & 0x2));
7741 printf(" DAV: %d\n", !!(bp[47] & 0x1));
7742 v = sg_get_unaligned_be16(bp + 48);
7743 printf(" Medium transport address: 0x%x\n", v);
7744 v = sg_get_unaligned_be16(bp + 50);
7745 printf(" Initial address: 0x%x\n", v);
7746 v = sg_get_unaligned_be16(bp + 52);
7747 printf(" Last successful address: 0x%x\n", v);
7748 v = sg_get_unaligned_be16(bp + 54);
7749 printf(" Destination address: 0x%x\n", v);
7750 if (pl > 91) {
7751 printf(" Volume tag information:\n");
7752 hex2fp(bp + 56, 36, " ", op->hex2str_oformat, stdout);
7753 }
7754 if (pl > 99) {
7755 printf(" Timestamp origin: 0x%x\n", bp[92] & 0xf);
7756 printf(" Timestamp:\n");
7757 hex2fp(bp + 94, 6, " ", op->hex2str_oformat, stdout);
7758 }
7759 if (op->do_pcb)
7760 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
7761 filter_chk:
7762 if (op->filter_given)
7763 break;
7764 skip:
7765 num -= pl;
7766 bp += pl;
7767 }
7768 return true;
7769 }
7770
7771 /* Helper for show_volume_stats_pages() */
7772 static void
volume_stats_partition(const uint8_t * xp,int len,bool pr_in_hex)7773 volume_stats_partition(const uint8_t * xp, int len, bool pr_in_hex)
7774 {
7775 uint64_t ull;
7776
7777 while (len > 3) {
7778 bool all_ffs, ffs_last_fe;
7779 int dl, pn;
7780
7781 dl = xp[0] + 1;
7782 if (dl < 3)
7783 return;
7784 pn = sg_get_unaligned_be16(xp + 2);
7785 ffs_last_fe = false;
7786 all_ffs = false;
7787 if (sg_all_ffs(xp + 4, dl - 3)) {
7788 switch (xp[4 + dl - 3]) {
7789 case 0xff:
7790 all_ffs = true;
7791 break;
7792 case 0xfe:
7793 ffs_last_fe = true;
7794 break;
7795 default:
7796 break;
7797 }
7798 }
7799 if (! (all_ffs || ffs_last_fe)) {
7800 ull = sg_get_unaligned_be(dl - 4, xp + 4);
7801 if (pr_in_hex)
7802 printf(" partition number: %d, partition record data "
7803 "counter: 0x%" PRIx64 "\n", pn, ull);
7804 else
7805 printf(" partition number: %d, partition record data "
7806 "counter: %" PRIu64 "\n", pn, ull);
7807 } else if (all_ffs)
7808 printf(" partition number: %d, partition record data "
7809 "counter is all 0xFFs\n", pn);
7810 else /* ffs_last_fe is true */
7811 printf(" partition number: %d, partition record data "
7812 "counter is all 0xFFs apart\n from a trailing "
7813 "0xFE\n", pn);
7814 xp += dl;
7815 len -= dl;
7816 }
7817 }
7818
7819 /* Helper for show_volume_stats_pages() */
7820 static void
volume_stats_history(const uint8_t * xp,int len)7821 volume_stats_history(const uint8_t * xp, int len)
7822 {
7823 while (len > 3) {
7824 int dl, mhi;
7825
7826 dl = xp[0] + 1;
7827 if (dl < 4)
7828 return;
7829 mhi = sg_get_unaligned_be16(xp + 2);
7830 if (dl < 12)
7831 printf(" index: %d\n", mhi);
7832 else if (12 == dl)
7833 printf(" index: %d, vendor: %.8s\n", mhi, xp + 4);
7834 else
7835 printf(" index: %d, vendor: %.8s, unit serial number: %.*s\n",
7836 mhi, xp + 4, dl - 12, xp + 12);
7837 xp += dl;
7838 len -= dl;
7839 }
7840 }
7841
7842 /* Volume Statistics log page and subpages (ssc-4) [0x17, 0x0-0xf] <vs> */
7843 static bool
show_volume_stats_pages(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)7844 show_volume_stats_pages(const uint8_t * resp, int len,
7845 struct opts_t * op, sgj_opaque_p jop)
7846 {
7847 bool skip_out = false;
7848 bool evsm_output = false;
7849 int num, pl, pc, subpg_code;
7850 bool spf;
7851 const uint8_t * bp;
7852 char str[PCB_STR_LEN];
7853 char b[512];
7854
7855 if (jop) { };
7856 spf = !!(resp[0] & 0x40);
7857 subpg_code = spf ? resp[1] : NOT_SPG_SUBPG;
7858 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex))) {
7859 if (subpg_code < 0x10)
7860 printf("Volume statistics page (ssc-4), subpage=%d\n",
7861 subpg_code);
7862 else {
7863 printf("Volume statistics page (ssc-4), subpage=%d; Reserved, "
7864 "skip\n", subpg_code);
7865 return false;
7866 }
7867 }
7868 num = len - 4;
7869 bp = &resp[0] + 4;
7870 while (num > 3) {
7871 pc = sg_get_unaligned_be16(bp + 0);
7872 pl = bp[3] + 4;
7873 if (op->filter_given) {
7874 if (pc != op->filter)
7875 goto skip;
7876 }
7877 if (op->do_raw) {
7878 dStrRaw(bp, pl);
7879 goto filter_chk;
7880 } else if (op->do_hex) {
7881 hex2stdout(bp, pl, op->dstrhex_no_ascii);
7882 goto filter_chk;
7883 }
7884
7885 switch (pc) {
7886 case 0:
7887 printf(" Page valid: %" PRIu64 "\n",
7888 sg_get_unaligned_be(pl - 4, bp + 4));
7889 break;
7890 case 1:
7891 printf(" Thread count: %" PRIu64 "\n",
7892 sg_get_unaligned_be(pl - 4, bp + 4));
7893 break;
7894 case 2:
7895 printf(" Total data sets written: %" PRIu64 "\n",
7896 sg_get_unaligned_be(pl - 4, bp + 4));
7897 break;
7898 case 3:
7899 printf(" Total write retries: %" PRIu64 "\n",
7900 sg_get_unaligned_be(pl - 4, bp + 4));
7901 break;
7902 case 4:
7903 printf(" Total unrecovered write errors: %" PRIu64 "\n",
7904 sg_get_unaligned_be(pl - 4, bp + 4));
7905 break;
7906 case 5:
7907 printf(" Total suspended writes: %" PRIu64 "\n",
7908 sg_get_unaligned_be(pl - 4, bp + 4));
7909 break;
7910 case 6:
7911 printf(" Total fatal suspended writes: %" PRIu64 "\n",
7912 sg_get_unaligned_be(pl - 4, bp + 4));
7913 break;
7914 case 7:
7915 printf(" Total data sets read: %" PRIu64 "\n",
7916 sg_get_unaligned_be(pl - 4, bp + 4));
7917 break;
7918 case 8:
7919 printf(" Total read retries: %" PRIu64 "\n",
7920 sg_get_unaligned_be(pl - 4, bp + 4));
7921 break;
7922 case 9:
7923 printf(" Total unrecovered read errors: %" PRIu64 "\n",
7924 sg_get_unaligned_be(pl - 4, bp + 4));
7925 break;
7926 case 0xa:
7927 printf(" Total suspended reads: %" PRIu64 "\n",
7928 sg_get_unaligned_be(pl - 4, bp + 4));
7929 break;
7930 case 0xb:
7931 printf(" Total fatal suspended reads: %" PRIu64 "\n",
7932 sg_get_unaligned_be(pl - 4, bp + 4));
7933 break;
7934 case 0xc:
7935 printf(" Last mount unrecovered write errors: %" PRIu64 "\n",
7936 sg_get_unaligned_be(pl - 4, bp + 4));
7937 break;
7938 case 0xd:
7939 printf(" Last mount unrecovered read errors: %" PRIu64 "\n",
7940 sg_get_unaligned_be(pl - 4, bp + 4));
7941 break;
7942 case 0xe:
7943 printf(" Last mount megabytes written: %" PRIu64 "\n",
7944 sg_get_unaligned_be(pl - 4, bp + 4));
7945 break;
7946 case 0xf:
7947 printf(" Last mount megabytes read: %" PRIu64 "\n",
7948 sg_get_unaligned_be(pl - 4, bp + 4));
7949 break;
7950 case 0x10:
7951 printf(" Lifetime megabytes written: %" PRIu64 "\n",
7952 sg_get_unaligned_be(pl - 4, bp + 4));
7953 break;
7954 case 0x11:
7955 printf(" Lifetime megabytes read: %" PRIu64 "\n",
7956 sg_get_unaligned_be(pl - 4, bp + 4));
7957 break;
7958 case 0x12:
7959 printf(" Last load write compression ratio: %" PRIu64 "\n",
7960 sg_get_unaligned_be(pl - 4, bp + 4));
7961 break;
7962 case 0x13:
7963 printf(" Last load read compression ratio: %" PRIu64 "\n",
7964 sg_get_unaligned_be(pl - 4, bp + 4));
7965 break;
7966 case 0x14:
7967 printf(" Medium mount time: %" PRIu64 "\n",
7968 sg_get_unaligned_be(pl - 4, bp + 4));
7969 break;
7970 case 0x15:
7971 printf(" Medium ready time: %" PRIu64 "\n",
7972 sg_get_unaligned_be(pl - 4, bp + 4));
7973 break;
7974 case 0x16:
7975 printf(" Total native capacity [MB]: %s\n",
7976 num_or_unknown(bp + 4, pl - 4, false, b, sizeof(b)));
7977 break;
7978 case 0x17:
7979 printf(" Total used native capacity [MB]: %s\n",
7980 num_or_unknown(bp + 4, pl - 4, false, b, sizeof(b)));
7981 break;
7982 case 0x1a:
7983 printf(" Volume stop writes of forward wraps: %" PRIu64 "\n",
7984 sg_get_unaligned_be(pl - 4, bp + 4));
7985 break;
7986 case 0x1b:
7987 printf(" Volume stop writes of backward wraps: %" PRIu64 "\n",
7988 sg_get_unaligned_be(pl - 4, bp + 4));
7989 break;
7990 case 0x40:
7991 printf(" Volume serial number: %.*s\n", pl - 4, bp + 4);
7992 break;
7993 case 0x41:
7994 printf(" Tape lot identifier: %.*s\n", pl - 4, bp + 4);
7995 break;
7996 case 0x42:
7997 printf(" Volume barcode: %.*s\n", pl - 4, bp + 4);
7998 break;
7999 case 0x43:
8000 printf(" Volume manufacturer: %.*s\n", pl - 4, bp + 4);
8001 break;
8002 case 0x44:
8003 printf(" Volume license code: %.*s\n", pl - 4, bp + 4);
8004 break;
8005 case 0x45:
8006 printf(" Volume personality: %.*s\n", pl - 4, bp + 4);
8007 break;
8008 case 0x80:
8009 printf(" Write protect: %s\n",
8010 num_or_unknown(bp + 4, pl - 4, false, b, sizeof(b)));
8011 break;
8012 case 0x81:
8013 printf(" WORM: %s\n",
8014 num_or_unknown(bp + 4, pl - 4, false, b, sizeof(b)));
8015 break;
8016 case 0x82:
8017 printf(" Maximum recommended tape path temperature exceeded: "
8018 "%s\n", num_or_unknown(bp + 4, pl - 4, false, b,
8019 sizeof(b)));
8020 break;
8021 case 0x100:
8022 printf(" Volume write mounts: %" PRIu64 "\n",
8023 sg_get_unaligned_be(pl - 4, bp + 4));
8024 break;
8025 case 0x101:
8026 printf(" Beginning of medium passes: %" PRIu64 "\n",
8027 sg_get_unaligned_be(pl - 4, bp + 4));
8028 break;
8029 case 0x102:
8030 printf(" Middle of medium passes: %" PRIu64 "\n",
8031 sg_get_unaligned_be(pl - 4, bp + 4));
8032 break;
8033 case 0x200:
8034 printf(" Logical position of first encrypted logical object:\n");
8035 volume_stats_partition(bp + 4, pl - 4, true);
8036 break;
8037 case 0x201:
8038 printf(" Logical position of first unencrypted logical object "
8039 "after first\n encrypted logical object:\n");
8040 volume_stats_partition(bp + 4, pl - 4, true);
8041 break;
8042 case 0x202:
8043 printf(" Native capacity partition(s) [MB]:\n");
8044 volume_stats_partition(bp + 4, pl - 4, false);
8045 break;
8046 case 0x203:
8047 printf(" Used native capacity partition(s) [MB]:\n");
8048 volume_stats_partition(bp + 4, pl - 4, false);
8049 break;
8050 case 0x204:
8051 printf(" Remaining native capacity partition(s) [MB]:\n");
8052 volume_stats_partition(bp + 4, pl - 4, false);
8053 break;
8054 case 0x300:
8055 printf(" Mount history:\n");
8056 volume_stats_history(bp + 4, pl - 4);
8057 break;
8058
8059 default:
8060 if (pc >= 0xf000) {
8061 if (op->exclude_vendor) {
8062 skip_out = true;
8063 if ((op->verbose > 0) && (0 == op->do_brief) &&
8064 (! evsm_output)) {
8065 evsm_output = true;
8066 printf(" Vendor specific parameter(s) being "
8067 "ignored\n");
8068 }
8069 } else
8070 printf(" Vendor specific %s (0x%x), payload in hex\n",
8071 param_c, pc);
8072 } else
8073 printf(" Reserved %s (0x%x), payload in hex\n", param_c, pc);
8074 if (skip_out)
8075 skip_out = false;
8076 else
8077 hex2fp(bp + 4, pl - 4, " ", op->hex2str_oformat, stdout);
8078 break;
8079 }
8080 if (op->do_pcb)
8081 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
8082 filter_chk:
8083 if (op->filter_given)
8084 break;
8085 skip:
8086 num -= pl;
8087 bp += pl;
8088 }
8089 return true;
8090 }
8091
8092 /* TAPE_ALERT_LPAGE [0x2e] <ta> */
8093 static bool
show_tape_alert_ssc_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)8094 show_tape_alert_ssc_page(const uint8_t * resp, int len,
8095 struct opts_t * op, sgj_opaque_p jop)
8096 {
8097 int num, pl, pc, flag;
8098 const uint8_t * bp;
8099 char str[PCB_STR_LEN];
8100
8101 if (jop) { };
8102 /* N.B. the Tape alert log page for smc-3 is different */
8103 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
8104 printf("Tape alert page (ssc-3) [0x2e]\n");
8105 num = len - 4;
8106 bp = &resp[0] + 4;
8107 while (num > 3) {
8108 pc = sg_get_unaligned_be16(bp + 0);
8109 pl = bp[3] + 4;
8110 if (op->filter_given) {
8111 if (pc != op->filter)
8112 goto skip;
8113 }
8114 if (op->do_raw) {
8115 dStrRaw(bp, pl);
8116 goto filter_chk;
8117 } else if (op->do_hex) {
8118 hex2stdout(bp, pl, op->dstrhex_no_ascii);
8119 goto filter_chk;
8120 }
8121 flag = bp[4] & 1;
8122 if (op->verbose && (0 == op->do_brief) && flag)
8123 printf(" >>>> ");
8124 if ((0 == op->do_brief) || op->verbose || flag) {
8125 if (NULL == sg_lib_tapealert_strs[0])
8126 printf(" No string available for code 0x%x, flag: %d\n",
8127 pc, flag);
8128 else if (pc <= 0x40)
8129 printf(" %s: %d\n", sg_lib_tapealert_strs[pc], flag);
8130 else
8131 printf(" Reserved %s 0x%x, flag: %d\n", param_c, pc, flag);
8132 }
8133 if (op->do_pcb)
8134 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
8135 filter_chk:
8136 if (op->filter_given)
8137 break;
8138 skip:
8139 num -= pl;
8140 bp += pl;
8141 }
8142 return true;
8143 }
8144
8145 /* 0x37 */
8146 static bool
show_seagate_cache_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)8147 show_seagate_cache_page(const uint8_t * resp, int len,
8148 struct opts_t * op, sgj_opaque_p jop)
8149 {
8150 bool skip = false;
8151 int num, pl, pc;
8152 int bsti = 0;
8153 const uint8_t * bp;
8154 char str[PCB_STR_LEN];
8155
8156 if (jop) { };
8157 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex))) {
8158 if (resp[1] > 0) {
8159 printf("Suspicious page 0x37, SPF=0 but subpage=0x%x\n", resp[1]);
8160 if (op->verbose)
8161 printf("... try vendor=wdc\n");
8162 if (op->do_brief > 0)
8163 return true;
8164 } else
8165 printf("Seagate cache page [0x37]\n");
8166 }
8167 num = len - 4;
8168 bp = &resp[0] + 4;
8169 while (num > 3) {
8170 pc = sg_get_unaligned_be16(bp + 0);
8171 pl = bp[3] + 4;
8172 if (op->filter_given) {
8173 if (pc != op->filter)
8174 goto skip;
8175 }
8176 if (op->do_raw) {
8177 dStrRaw(bp, pl);
8178 goto filter_chk;
8179 } else if (op->do_hex) {
8180 hex2stdout(bp, pl, op->dstrhex_no_ascii);
8181 goto filter_chk;
8182 }
8183 switch (pc) {
8184 case 0:
8185 ++bsti;
8186 if (bsti < 2)
8187 printf(" Blocks sent to initiator");
8188 else
8189 skip = true;
8190 break;
8191 case 1:
8192 printf(" Blocks received from initiator");
8193 break;
8194 case 2:
8195 printf(" Blocks read from cache and sent to initiator");
8196 break;
8197 case 3:
8198 printf(" Number of read and write commands whose size "
8199 "<= segment size");
8200 break;
8201 case 4:
8202 printf(" Number of read and write commands whose size "
8203 "> segment size");
8204 break;
8205 default:
8206 printf(" Unknown Seagate %s = 0x%x", param_c, pc);
8207 break;
8208 }
8209 if (skip)
8210 skip = false;
8211 else {
8212 printf(" = %" PRIu64 "", sg_get_unaligned_be(pl - 4, bp + 4));
8213 printf("\n");
8214 if (op->do_pcb)
8215 printf(" <%s>\n", get_pcb_str(bp[2], str,
8216 sizeof(str)));
8217 }
8218 filter_chk:
8219 if (op->filter_given)
8220 break;
8221 skip:
8222 num -= pl;
8223 bp += pl;
8224 }
8225 return true;
8226 }
8227
8228 /* 0x37 */
8229 static bool
show_hgst_misc_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)8230 show_hgst_misc_page(const uint8_t * resp, int len, struct opts_t * op,
8231 sgj_opaque_p jop)
8232 {
8233 bool valid = false;
8234 int num, pl, pc;
8235 const uint8_t * bp;
8236 char str[PCB_STR_LEN];
8237
8238 if (jop) { };
8239 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
8240 printf("HGST/WDC miscellaneous page [0x37, 0x%x]\n",
8241 op->decod_subpg_code);
8242 num = len - 4;
8243 if (num < 0x30) {
8244 printf("HGST/WDC miscellaneous page too short (%d) < 48\n", num);
8245 return valid;
8246 }
8247 bp = &resp[0] + 4;
8248 while (num > 3) {
8249 pc = sg_get_unaligned_be16(bp + 0);
8250 pl = bp[3] + 4;
8251 if (op->filter_given) {
8252 if (pc != op->filter)
8253 goto skip;
8254 }
8255 if (op->do_raw) {
8256 dStrRaw(bp, pl);
8257 goto filter_chk;
8258 } else if (op->do_hex) {
8259 hex2stdout(bp, pl, op->dstrhex_no_ascii);
8260 goto filter_chk;
8261 }
8262 switch (pc) {
8263 case 0:
8264 valid = true;
8265 printf(" Power on hours = %u\n", sg_get_unaligned_be32(bp + 4));
8266 printf(" Total Bytes Read = %" PRIu64 "\n",
8267 sg_get_unaligned_be64(bp + 8));
8268 printf(" Total Bytes Written = %" PRIu64 "\n",
8269 sg_get_unaligned_be64(bp + 16));
8270 printf(" Max Drive Temp (Celsius) = %u\n", bp[24]);
8271 printf(" GList Size = %u\n", sg_get_unaligned_be16(bp + 25));
8272 printf(" Number of Information Exceptions = %u\n", bp[27]);
8273 printf(" MED EXC = %u\n", !! (0x80 & bp[28]));
8274 printf(" HDW EXC = %u\n", !! (0x40 & bp[28]));
8275 printf(" Total Read Commands = %" PRIu64 "\n",
8276 sg_get_unaligned_be64(bp + 29));
8277 printf(" Total Write Commands = %" PRIu64 "\n",
8278 sg_get_unaligned_be64(bp + 37));
8279 printf(" Flash Correction Count = %u\n",
8280 sg_get_unaligned_be16(bp + 46));
8281 break;
8282 default:
8283 valid = false;
8284 printf(" Unknown HGST/WDC %s = 0x%x", param_c, pc);
8285 break;
8286 }
8287 if (op->do_pcb)
8288 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
8289 filter_chk:
8290 if (op->filter_given)
8291 break;
8292 skip:
8293 num -= pl;
8294 bp += pl;
8295 }
8296 return valid;
8297 }
8298
8299 /* 0x3e */
8300 static bool
show_seagate_factory_page(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)8301 show_seagate_factory_page(const uint8_t * resp, int len,
8302 struct opts_t * op, sgj_opaque_p jop)
8303 {
8304 bool valid = false;
8305 int num, pl, pc;
8306 const uint8_t * bp;
8307 uint64_t ull;
8308 char str[PCB_STR_LEN];
8309
8310 if (jop) { };
8311 if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
8312 printf("Seagate/Hitachi factory page [0x3e]\n");
8313 num = len - 4;
8314 bp = &resp[0] + 4;
8315 while (num > 3) {
8316 pc = sg_get_unaligned_be16(bp + 0);
8317 pl = bp[3] + 4;
8318 if (op->filter_given) {
8319 if (pc != op->filter)
8320 goto skip;
8321 }
8322 if (op->do_raw) {
8323 dStrRaw(bp, pl);
8324 goto filter_chk;
8325 } else if (op->do_hex) {
8326 hex2stdout(bp, pl, op->dstrhex_no_ascii);
8327 goto filter_chk;
8328 }
8329 valid = true;
8330 switch (pc) {
8331 case 0:
8332 printf(" number of hours powered up");
8333 break;
8334 case 8:
8335 printf(" number of minutes until next internal SMART test");
8336 break;
8337 default:
8338 valid = false;
8339 printf(" Unknown Seagate/Hitachi %s = 0x%x", param_c, pc);
8340 break;
8341 }
8342 if (valid) {
8343 ull = sg_get_unaligned_be(pl - 4, bp + 4);
8344 if (0 == pc)
8345 printf(" = %.2f", ((double)ull) / 60.0 );
8346 else
8347 printf(" = %" PRIu64 "", ull);
8348 }
8349 printf("\n");
8350 if (op->do_pcb)
8351 printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
8352 filter_chk:
8353 if (op->filter_given)
8354 break;
8355 skip:
8356 num -= pl;
8357 bp += pl;
8358 }
8359 return true;
8360 }
8361
8362 static void
decode_page_contents(const uint8_t * resp,int len,struct opts_t * op,sgj_opaque_p jop)8363 decode_page_contents(const uint8_t * resp, int len, struct opts_t * op,
8364 sgj_opaque_p jop)
8365 {
8366 int pg_code, subpg_code, vpn;
8367 bool spf;
8368 bool done = false;
8369 const struct log_elem * lep;
8370
8371 if (len < 3) {
8372 pr2serr("%s: response has bad length: %d\n", __func__, len);
8373 return;
8374 }
8375 spf = !!(resp[0] & 0x40);
8376 pg_code = resp[0] & 0x3f;
8377 if ((VP_HITA == op->vend_prod_num) && (pg_code >= 0x30))
8378 subpg_code = resp[1]; /* Hitachi don't set SPF on VS pages */
8379 else
8380 subpg_code = spf ? resp[1] : NOT_SPG_SUBPG;
8381 op->decod_subpg_code = subpg_code;
8382 if ((SUPP_SPGS_SUBPG == subpg_code) && (SUPP_PAGES_LPAGE != pg_code)) {
8383 done = show_supported_pgs_sub_page(resp, len, op, jop);
8384 if (done)
8385 return;
8386 }
8387 vpn = (op->vend_prod_num >= 0) ? op->vend_prod_num : op->deduced_vpn;
8388 lep = pg_subpg_pdt_search(pg_code, subpg_code, op->dev_pdt, vpn);
8389
8390 /* Below is the indirect function call to all the show_* functions */
8391 if (lep && lep->show_pagep)
8392 done = (*lep->show_pagep)(resp, len, op, jop);
8393
8394 if (! done) {
8395 if (0 == op->do_hex) {
8396 static const char * unable_s = "Unable to decode page = 0x";
8397
8398 if (subpg_code > 0)
8399 printf("%s%x, subpage = 0x%x, here is hex:\n", unable_s,
8400 pg_code, subpg_code);
8401 else
8402 printf("%s%x, here is hex:\n", unable_s, pg_code);
8403 }
8404 if ((len > 128) && (0 == op->do_hex)) {
8405 hex2fp(resp, 64, " ", op->hex2str_oformat, stdout);
8406 printf(" ..... [truncated after 64 of %d bytes (use '-H' to "
8407 "see the rest)]\n", len);
8408 } else {
8409 if (0 == op->do_hex)
8410 hex2fp(resp, len, " ", op->hex2str_oformat, stdout);
8411 else
8412 hex2stdout(resp, len, op->dstrhex_no_ascii);
8413 }
8414 }
8415 }
8416
8417 /* Tries to fetch the TEMPERATURE_LPAGE [0xd] page first. If that fails
8418 * tries to get the Informational Exceptions (IE_LPAGE) page. */
8419 static int
fetchTemperature(int sg_fd,uint8_t * resp,int max_len,struct opts_t * op,sgj_opaque_p jop)8420 fetchTemperature(int sg_fd, uint8_t * resp, int max_len, struct opts_t * op,
8421 sgj_opaque_p jop)
8422 {
8423 int len;
8424 int res = 0;
8425
8426 op->pg_code = TEMPERATURE_LPAGE;
8427 op->subpg_code = NOT_SPG_SUBPG;
8428 res = do_logs(sg_fd, resp, max_len, op);
8429 if (0 == res) {
8430 len = sg_get_unaligned_be16(resp + 2) + 4;
8431 if (op->do_raw)
8432 dStrRaw(resp, len);
8433 else if (op->do_hex)
8434 hex2stdout(resp, len, op->dstrhex_no_ascii);
8435 else
8436 show_temperature_page(resp, len, op, jop);
8437 } else if (SG_LIB_CAT_NOT_READY == res)
8438 pr2serr("Device not ready\n");
8439 else {
8440 op->pg_code = IE_LPAGE;
8441 res = do_logs(sg_fd, resp, max_len, op);
8442 if (0 == res) {
8443 len = sg_get_unaligned_be16(resp + 2) + 4;
8444 if (op->do_raw)
8445 dStrRaw(resp, len);
8446 else if (op->do_hex)
8447 hex2stdout(resp, len, op->dstrhex_no_ascii);
8448 else
8449 show_ie_page(resp, len, op, jop);
8450 } else
8451 pr2serr("Unable to find temperature in either Temperature or "
8452 "IE log page\n");
8453 }
8454 sg_cmds_close_device(sg_fd);
8455 return (res >= 0) ? res : SG_LIB_CAT_OTHER;
8456 }
8457
8458 /* Returns 0 if successful else SG_LIB_SYNTAX_ERROR. */
8459 static int
decode_pg_arg(struct opts_t * op)8460 decode_pg_arg(struct opts_t * op)
8461 {
8462 int nn;
8463 const struct log_elem * lep;
8464 char * cp;
8465
8466 if (isalpha((uint8_t)op->pg_arg[0])) {
8467 char b[80];
8468
8469 if (strlen(op->pg_arg) >= (sizeof(b) - 1)) {
8470 pr2serr("argument to '--page=' is too long\n");
8471 return SG_LIB_SYNTAX_ERROR;
8472 }
8473 strcpy(b, op->pg_arg);
8474 cp = (char *)strchr(b, ',');
8475 if (cp)
8476 *cp = '\0';
8477 lep = acron_search(b);
8478 if (NULL == lep) {
8479 pr2serr("bad argument to '--page=' no acronyn match to "
8480 "'%s'\n", b);
8481 pr2serr(" Try using '-e' or'-ee' to see available "
8482 "acronyns\n");
8483 return SG_LIB_SYNTAX_ERROR;
8484 }
8485 op->lep = lep;
8486 op->pg_code = lep->pg_code;
8487 if (cp) {
8488 nn = sg_get_num_nomult(cp + 1);
8489 if ((nn < 0) || (nn > 255)) {
8490 pr2serr("Bad second value in argument to "
8491 "'--page='\n");
8492 return SG_LIB_SYNTAX_ERROR;
8493 }
8494 op->subpg_code = nn;
8495 } else
8496 op->subpg_code = lep->subpg_code;
8497 } else { /* numeric arg: either 'pg_num' or 'pg_num,subpg_num' */
8498 int n;
8499
8500 cp = (char *)strchr(op->pg_arg, ',');
8501 n = sg_get_num_nomult(op->pg_arg);
8502 if ((n < 0) || (n > 63)) {
8503 pr2serr("Bad argument to '--page='\n");
8504 usage(1);
8505 return SG_LIB_SYNTAX_ERROR;
8506 }
8507 if (cp) {
8508 nn = sg_get_num_nomult(cp + 1);
8509 if ((nn < 0) || (nn > 255)) {
8510 pr2serr("Bad second value in argument to "
8511 "'--page='\n");
8512 usage(1);
8513 return SG_LIB_SYNTAX_ERROR;
8514 }
8515 } else
8516 nn = 0;
8517 op->pg_code = n;
8518 op->subpg_code = nn;
8519 }
8520 return 0;
8521 }
8522
8523 /* Since the Supported subpages page is sitting in the rsp_buff which is
8524 * MX_ALLOC_LEN bytes long (~ 64 KB) then move it (from rsp_buff+0 to
8525 * rsp_buff+pg_len-1) to the top end of that buffer. Then there is room
8526 * to merge supp_pgs_rsp with the supported subpages with the result back
8527 * at the bottom of rsp_buff. The new length of the merged subpages page
8528 * (excluding its 4 byte header) is returned.
8529 * Assumes both pages are in ascending order (as required by SPC-4). */
8530 static int
merge_both_supported(const uint8_t * supp_pgs_p,int su_p_pg_len,int pg_len)8531 merge_both_supported(const uint8_t * supp_pgs_p, int su_p_pg_len, int pg_len)
8532 {
8533 uint8_t pg;
8534 int k, kp, ks;
8535 int max_blen = (2 * su_p_pg_len) + pg_len;
8536 uint8_t * m_buff = rsp_buff + (rsp_buff_sz - pg_len);
8537 uint8_t * r_buff = rsp_buff + 4;
8538
8539 if (pg_len > 0)
8540 memmove(m_buff, rsp_buff + 4, pg_len);
8541 for (k = 0, kp = 0, ks = 0; k < max_blen; k += 2) {
8542 if (kp < su_p_pg_len)
8543 pg = supp_pgs_p[kp];
8544 else
8545 pg = 0xff;
8546 if (ks < pg_len) {
8547 if (m_buff[ks] < pg) {
8548 r_buff[k] = m_buff[ks];
8549 r_buff[k + 1] = m_buff[ks + 1];
8550 ks += 2;
8551 } else if ((m_buff[ks] == pg) && (m_buff[ks + 1] == 0)) {
8552 r_buff[k] = m_buff[ks];
8553 r_buff[k + 1] = m_buff[ks + 1];
8554 ks += 2;
8555 ++kp;
8556 } else {
8557 r_buff[k] = pg;
8558 r_buff[k + 1] = 0;
8559 ++kp;
8560 }
8561 } else {
8562 if (0xff == pg)
8563 break;
8564 r_buff[k] = pg;
8565 r_buff[k + 1] = 0;
8566 ++kp;
8567 }
8568 }
8569 sg_put_unaligned_be16(k, rsp_buff + 2);
8570 return k;
8571 }
8572
8573
8574 int
main(int argc,char * argv[])8575 main(int argc, char * argv[])
8576 {
8577 bool as_json;
8578 int k, nn, pg_len, res, vb;
8579 int resp_len = 0;
8580 int su_p_pg_len = 0;
8581 int in_len = -1;
8582 int sg_fd = -1;
8583 int ret = 0;
8584 uint8_t * parr;
8585 uint8_t * free_parr = NULL;
8586 struct opts_t * op;
8587 sgj_state * jsp;
8588 sgj_opaque_p jop = NULL;
8589 struct sg_simple_inquiry_resp inq_out;
8590 struct opts_t opts SG_C_CPP_ZERO_INIT;
8591 uint8_t supp_pgs_rsp[256];
8592 char b[128];
8593 static const int blen = sizeof(b);
8594
8595 op = &opts;
8596 /* N.B. some disks only give data for current cumulative */
8597 op->page_control = 1;
8598 op->dev_pdt = -1;
8599 op->vend_prod_num = VP_NONE;
8600 op->deduced_vpn = VP_NONE;
8601 res = parse_cmd_line(op, argc, argv);
8602 if (res)
8603 return SG_LIB_SYNTAX_ERROR;
8604 if (op->do_help) {
8605 usage_for(op->do_help, op);
8606 return 0;
8607 }
8608 jsp = &op->json_st;
8609 as_json = jsp->pr_as_json;
8610 if (as_json) {
8611 if (op->do_name) {
8612 pr2serr(">>> The --json option is superior to the --name "
8613 "option.\n");
8614 pr2serr(">>> Ignoring the --name option.\n");
8615 op->do_name = false;
8616 }
8617 jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp);
8618 }
8619 #ifdef DEBUG
8620 pr2serr("In DEBUG mode, ");
8621 if (op->verbose_given && op->version_given) {
8622 pr2serr("but override: '-vV' given, zero verbose and continue\n");
8623 op->verbose_given = false;
8624 op->version_given = false;
8625 op->verbose = 0;
8626 } else if (! op->verbose_given) {
8627 pr2serr("set '-vv'\n");
8628 op->verbose = 2;
8629 } else
8630 pr2serr("keep verbose=%d\n", op->verbose);
8631 #else
8632 if (op->verbose_given && op->version_given)
8633 pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
8634 #endif
8635 if (op->version_given) {
8636 pr2serr("Version string: %s\n", version_str);
8637 return 0;
8638 }
8639 if (op->do_hex > 0) {
8640 if (op->do_hex > 2) {
8641 op->dstrhex_no_ascii = -1;
8642 op->hex2str_oformat = 1;
8643 } else {
8644 op->dstrhex_no_ascii = (1 == op->do_hex);
8645 op->hex2str_oformat = (1 == op->do_hex);
8646 }
8647 } else {
8648 if (op->undefined_hex > 0) {
8649 if (op->undefined_hex > 2) {
8650 op->dstrhex_no_ascii = -1;
8651 op->hex2str_oformat = 1;
8652 } else {
8653 op->dstrhex_no_ascii = (1 == op->undefined_hex);
8654 op->hex2str_oformat = (1 == op->undefined_hex);
8655 }
8656 } else { /* default when no --hex nor --undefined */
8657 op->dstrhex_no_ascii = -1;
8658 op->hex2str_oformat = 1;
8659 }
8660 }
8661 vb = op->verbose;
8662 if (op->vend_prod) {
8663 if (0 == memcmp("-1", op->vend_prod,3))
8664 k = VP_NONE;
8665 else if (isdigit((uint8_t)op->vend_prod[0]))
8666 k = sg_get_num_nomult(op->vend_prod);
8667 else
8668 k = find_vpn_by_acron(op->vend_prod);
8669 op->vend_prod_num = k;
8670 if (VP_ALL == k)
8671 ;
8672 else if ((k < 0) || (k > (32 - MVP_OFFSET))) {
8673 pr2serr("Bad vendor/product acronym after '--vendor=' "
8674 " ('-M ') option\n");
8675 enumerate_vp();
8676 return SG_LIB_SYNTAX_ERROR;
8677 }
8678 }
8679 if (op->do_enumerate > 0) {
8680 if (op->device_name && vb)
8681 pr2serr("Warning: device: %s is being ignored\n",
8682 op->device_name);
8683 enumerate_pages(op);
8684 return 0;
8685 }
8686 if (op->in_fn) {
8687 if (op->maxlen_given) {
8688 if (op->maxlen > MX_INLEN_ALLOC_LEN) {
8689 pr2serr("bad argument to '--maxlen=' when --in= given, from "
8690 "2 to %d (inclusive) expected\n", MX_INLEN_ALLOC_LEN);
8691 return SG_LIB_SYNTAX_ERROR;
8692 }
8693 rsp_buff_sz = op->maxlen;
8694 } else
8695 rsp_buff_sz = DEF_INLEN_ALLOC_LEN;
8696 } else {
8697 if (op->maxlen_given) {
8698 if (op->maxlen > MX_ALLOC_LEN) {
8699 pr2serr("bad argument to '--maxlen=', from 2 to 65535 "
8700 "(inclusive) expected\n");
8701 return SG_LIB_SYNTAX_ERROR;
8702 }
8703 rsp_buff_sz = op->maxlen;
8704 }
8705 }
8706 rsp_buff = sg_memalign(rsp_buff_sz, 0 /* page aligned */, &free_rsp_buff,
8707 false);
8708 if (NULL == rsp_buff) {
8709 pr2serr("Unable to allocate %d bytes on the heap\n", rsp_buff_sz);
8710 ret = sg_convert_errno(ENOMEM);
8711 goto err_out;
8712 }
8713 if (NULL == op->device_name) {
8714 if (op->in_fn) {
8715 bool found = false;
8716 bool r_spf = false;
8717 uint16_t u;
8718 int pg_code, subpg_code, pdt, n;
8719 const struct log_elem * lep;
8720 const uint8_t * bp;
8721
8722 if ((ret = sg_f2hex_arr(op->in_fn, op->do_raw, false, rsp_buff,
8723 &in_len, rsp_buff_sz)))
8724 goto err_out;
8725 if (vb > 2)
8726 pr2serr("Read %d [0x%x] bytes of user supplied data\n",
8727 in_len, in_len);
8728 if (op->do_raw)
8729 op->do_raw = false; /* can interfere on decode */
8730 if (in_len < 4) {
8731 pr2serr("--in=%s only decoded %d bytes (needs 4 at least)\n",
8732 op->in_fn, in_len);
8733 ret = SG_LIB_SYNTAX_ERROR;
8734 goto err_out;
8735 }
8736 if (op->pg_arg) {
8737 char b[144];
8738 char * cp;
8739
8740 strcpy(b, op->pg_arg);
8741 cp = (char *)strchr(b, ',');
8742 if (cp)
8743 *cp = '\0';
8744 lep = acron_search(b);
8745 if (NULL == lep) {
8746 pr2serr("bad argument to '--page=' no acronyn match to "
8747 "'%s'\n", b);
8748 pr2serr(" Try using '-e' or'-ee' to see available "
8749 "acronyns\n");
8750 return SG_LIB_SYNTAX_ERROR;
8751 }
8752 op->lep = lep;
8753 op->pg_code = lep->pg_code;
8754 op->subpg_code = lep->subpg_code;
8755 if (op->subpg_code > 0)
8756 r_spf = true;
8757 }
8758
8759 for (bp = rsp_buff, k = 0; k < in_len; bp += n, k += n) {
8760 bool spf = !! (bp[0] & 0x40);
8761
8762 pg_code = bp[0] & 0x3f;
8763 subpg_code = spf ? bp[1] : NOT_SPG_SUBPG;
8764 u = sg_get_unaligned_be16(bp + 2);
8765 n = u + 4;
8766 if (n > (in_len - k)) {
8767 pr2serr("bytes decoded remaining (%d) less than lpage "
8768 "length (%d), try decoding anyway\n", in_len - k,
8769 n);
8770 n = in_len - k;
8771 }
8772 if (op->pg_arg) {
8773 if ((NOT_SPG_SUBPG == op->subpg_code) && spf) {
8774 continue;
8775 } else if ((! spf) && (! r_spf)) {
8776 if (pg_code != op->pg_code)
8777 continue;
8778 } else if ((SUPP_SPGS_SUBPG == op->subpg_code) &&
8779 (SUPP_PAGES_LPAGE != op->pg_code)) {
8780 if (pg_code != op->pg_code)
8781 continue;
8782 } else if ((SUPP_SPGS_SUBPG != op->subpg_code) &&
8783 (SUPP_PAGES_LPAGE == op->pg_code)) {
8784 if (subpg_code != op->subpg_code)
8785 continue;
8786 } else if ((SUPP_SPGS_SUBPG != op->subpg_code) &&
8787 (SUPP_PAGES_LPAGE != op->pg_code)) {
8788 if ((pg_code != op->pg_code) ||
8789 (subpg_code != op->subpg_code))
8790 continue;
8791 }
8792 }
8793 if (op->exclude_vendor && (pg_code >= 0x30))
8794 continue;
8795 found = true;
8796 if (op->do_hex > 2) {
8797 hex2fp(bp, n, NULL, op->hex2str_oformat, stdout);
8798 continue;
8799 }
8800 pdt = op->dev_pdt;
8801 lep = pg_subpg_pdt_search(pg_code, subpg_code, pdt,
8802 op->vend_prod_num);
8803 if (lep) {
8804 /* Below is the indirect function call to all the
8805 * show_* functions */
8806 if (lep->show_pagep)
8807 (*lep->show_pagep)(bp, n, op, jop);
8808 else
8809 sgj_pr_hr(jsp, "Unable to decode %s [%s]\n",
8810 lep->name, lep->acron);
8811 } else {
8812 nn = sg_scnpr(b, blen, "Unable to decode page=0x%x",
8813 pg_code);
8814 if (subpg_code > 0)
8815 sg_scnpr(b + nn, blen - nn, ", subpage=0x%x",
8816 subpg_code);
8817 if (pdt >= 0)
8818 sg_scnpr(b + nn, blen - nn, ", pdt=0x%x\n", pdt);
8819 sgj_pr_hr(jsp, "%s\n", b);
8820 }
8821 } /* end of page/subpage search loop */
8822 if (op->pg_arg && (! found)) {
8823 nn = sg_scnpr(b, blen, "Unable to find page=0x%x",
8824 op->pg_code);
8825 if (op->subpg_code > 0)
8826 sg_scnpr(b + nn, blen - nn, ", subpage=0x%x",
8827 op->subpg_code);
8828 sgj_pr_hr(jsp, "%s\n", b);
8829 if (jsp->pr_as_json)
8830 sgj_js_nv_i(jsp, jop, "page_not_found", 1);
8831 }
8832 ret = 0;
8833 goto err_out;
8834 }
8835 if (op->pg_arg) { /* do this for 'sg_logs -p xxx' */
8836 ret = decode_pg_arg(op);
8837 if (ret)
8838 goto err_out;
8839 }
8840 pr2serr("No DEVICE argument given\n\n");
8841 usage_for(1, op);
8842 ret = SG_LIB_FILE_ERROR;
8843 goto err_out;
8844 }
8845 if (op->do_select) {
8846 if (op->do_temperature) {
8847 pr2serr("--select cannot be used with --temperature\n");
8848 ret = SG_LIB_CONTRADICT;
8849 goto err_out;
8850 }
8851 if (op->do_transport) {
8852 pr2serr("--select cannot be used with --transport\n");
8853 ret = SG_LIB_CONTRADICT;
8854 goto err_out;
8855 }
8856 } else if (op->do_raw) {
8857 if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
8858 perror("sg_set_binary_mode");
8859 ret = SG_LIB_FILE_ERROR;
8860 goto err_out;
8861 }
8862 }
8863 if (op->do_all) {
8864 if (op->do_select) {
8865 pr2serr("--all conflicts with --select\n");
8866 ret = SG_LIB_CONTRADICT;
8867 goto err_out;
8868 }
8869 }
8870 if (op->in_fn) {
8871 if (! op->do_select) {
8872 pr2serr("--in=FN can only be used with --select when DEVICE "
8873 "given\n");
8874 ret = SG_LIB_CONTRADICT;
8875 goto err_out;
8876 }
8877 if ((ret = sg_f2hex_arr(op->in_fn, op->do_raw, false, rsp_buff,
8878 &in_len, rsp_buff_sz)))
8879 goto err_out;
8880 if (vb > 2)
8881 pr2serr("Read %d [0x%x] bytes of user supplied data\n", in_len,
8882 in_len);
8883 }
8884 if (op->pg_arg) {
8885 if (op->do_all) {
8886 if (0 == op->do_brief)
8887 pr2serr(">>> warning: --page=%s ignored when --all given\n",
8888 op->pg_arg);
8889 } else {
8890 ret = decode_pg_arg(op);
8891 if (ret)
8892 goto err_out;
8893 }
8894 }
8895
8896 #ifdef SG_LIB_WIN32
8897 #ifdef SG_LIB_WIN32_DIRECT
8898 win32_spt_init_state = !! scsi_pt_win32_spt_state();
8899 if (vb > 4)
8900 pr2serr("Initial win32 SPT interface state: %s\n",
8901 win32_spt_init_state ? "direct" : "indirect");
8902 #endif
8903 #endif
8904 sg_fd = sg_cmds_open_device(op->device_name, op->o_readonly, vb);
8905 if ((sg_fd < 0) && (! op->o_readonly))
8906 sg_fd = sg_cmds_open_device(op->device_name, true /* ro */, vb);
8907 if (sg_fd < 0) {
8908 pr2serr("error opening file: %s: %s \n", op->device_name,
8909 safe_strerror(-sg_fd));
8910 ret = sg_convert_errno(-sg_fd);
8911 goto err_out;
8912 }
8913 if (op->do_list || op->do_all) {
8914 op->pg_code = SUPP_PAGES_LPAGE;
8915 if ((op->do_list > 1) || (op->do_all > 1))
8916 op->subpg_code = SUPP_SPGS_SUBPG;
8917 }
8918 if (op->do_transport) {
8919 if ((op->pg_code > 0) || (op->subpg_code > 0) ||
8920 op->do_temperature) {
8921 pr2serr("'-T' should not be mixed with options implying other "
8922 "pages\n");
8923 ret = SG_LIB_FILE_ERROR;
8924 goto err_out;
8925 }
8926 op->pg_code = PROTO_SPECIFIC_LPAGE;
8927 }
8928
8929 memset(&inq_out, 0, sizeof(inq_out));
8930 if (op->no_inq < 2) {
8931 if (sg_simple_inquiry(sg_fd, &inq_out, true, vb)) {
8932 pr2serr("%s doesn't respond to a SCSI INQUIRY\n",
8933 op->device_name);
8934 ret = SG_LIB_CAT_OTHER;
8935 goto err_out;
8936 }
8937 op->dev_pdt = inq_out.peripheral_type;
8938 if ((! op->do_raw) && (0 == op->do_hex) && (! op->do_name) &&
8939 (0 == op->no_inq) && (0 == op->do_brief))
8940 sgj_pr_hr(jsp, " %.8s %.16s %.4s\n", inq_out.vendor,
8941 inq_out.product, inq_out.revision);
8942 memcpy(t10_vendor_str, inq_out.vendor, 8);
8943 memcpy(t10_product_str, inq_out.product, 16);
8944 if (VP_NONE == op->vend_prod_num)
8945 op->deduced_vpn = find_vpn_by_inquiry();
8946 }
8947
8948 if (op->do_temperature) {
8949 ret = fetchTemperature(sg_fd, rsp_buff, SHORT_RESP_LEN, op, jop);
8950 goto err_out;
8951 }
8952 if (op->do_select) {
8953 k = sg_ll_log_select(sg_fd, op->do_pcreset, op->do_sp,
8954 op->page_control, op->pg_code, op->subpg_code,
8955 rsp_buff, ((in_len > 0) ? in_len : 0), true, vb);
8956 if (k) {
8957 if (SG_LIB_CAT_NOT_READY == k)
8958 pr2serr("log_select: device not ready\n");
8959 else if (SG_LIB_CAT_ILLEGAL_REQ == k)
8960 pr2serr("log_select: field in cdb illegal\n");
8961 else if (SG_LIB_CAT_INVALID_OP == k)
8962 pr2serr("log_select: not supported\n");
8963 else if (SG_LIB_CAT_UNIT_ATTENTION == k)
8964 pr2serr("log_select: unit attention\n");
8965 else if (SG_LIB_CAT_ABORTED_COMMAND == k)
8966 pr2serr("log_select: aborted command\n");
8967 else
8968 pr2serr("log_select: failed (%d), try '-v' for more "
8969 "information\n", k);
8970 }
8971 ret = (k >= 0) ? k : SG_LIB_CAT_OTHER;
8972 goto err_out;
8973 }
8974 if (op->do_list > 2) {
8975 const int supp_pgs_blen = sizeof(supp_pgs_rsp);
8976
8977 op->subpg_code = NOT_SPG_SUBPG;
8978 res = do_logs(sg_fd, supp_pgs_rsp, supp_pgs_blen, op);
8979 if (res != 0)
8980 goto bad;
8981 su_p_pg_len = sg_get_unaligned_be16(supp_pgs_rsp + 2);
8982 if ((su_p_pg_len + 4) > supp_pgs_blen) {
8983 pr2serr("Supported log pages log page is too long [%d], exit\n",
8984 su_p_pg_len);
8985 res = SG_LIB_CAT_OTHER;
8986 goto bad;
8987 }
8988 op->subpg_code = SUPP_SPGS_SUBPG;
8989 }
8990 resp_len = (op->maxlen > 0) ? op->maxlen : MX_ALLOC_LEN;
8991 res = do_logs(sg_fd, rsp_buff, resp_len, op);
8992 if (0 == res) {
8993 pg_len = sg_get_unaligned_be16(rsp_buff + 2);
8994 if ((pg_len + 4) > resp_len) {
8995 pr2serr("Only fetched %d bytes of response (available: %d "
8996 "bytes)\n truncate output\n",
8997 resp_len, pg_len + 4);
8998 pg_len = resp_len - 4;
8999 }
9000 goto good;
9001 }
9002 bad:
9003 if (SG_LIB_CAT_INVALID_OP == res)
9004 pr2serr("%snot supported\n", ls_s);
9005 else if (SG_LIB_CAT_NOT_READY == res)
9006 pr2serr("%sdevice not ready\n", ls_s);
9007 else if (SG_LIB_CAT_ILLEGAL_REQ == res) {
9008 if ((op->do_list > 2) && (SUPP_SPGS_SUBPG == op->subpg_code)) {
9009 rsp_buff[0] = 0x40;
9010 rsp_buff[1] = SUPP_SPGS_SUBPG;
9011 pg_len = 0;
9012 res = 0;
9013 if (op->verbose)
9014 pr2serr("%sfield in cdb illegal in [0,0xff], "
9015 "continue with merge\n", ls_s);
9016 goto good;
9017 } else
9018 pr2serr("%sfield in cdb illegal\n", ls_s);
9019 } else if (SG_LIB_CAT_UNIT_ATTENTION == res)
9020 pr2serr("%sunit attention\n", ls_s);
9021 else if (SG_LIB_CAT_ABORTED_COMMAND == res)
9022 pr2serr("%saborted command\n", ls_s);
9023 else if (SG_LIB_TRANSPORT_ERROR == res)
9024 pr2serr("%stransport error\n", ls_s);
9025 else
9026 pr2serr("%sother error [%d]\n", ls_s, res);
9027 ret = res;
9028 goto err_out;
9029
9030 good:
9031 if (op->do_list > 2)
9032 pg_len = merge_both_supported(supp_pgs_rsp + 4, su_p_pg_len, pg_len);
9033
9034 if (0 == op->do_all) {
9035 if (op->filter_given) {
9036 if (op->do_hex > 2)
9037 hex2stdout(rsp_buff, pg_len + 4, op->dstrhex_no_ascii);
9038 else
9039 decode_page_contents(rsp_buff, pg_len + 4, op, jop);
9040 } else if (op->do_raw)
9041 dStrRaw(rsp_buff, pg_len + 4);
9042 else if (op->do_hex > 1)
9043 hex2stdout(rsp_buff, pg_len + 4, op->dstrhex_no_ascii);
9044 else if (pg_len > 1) {
9045 if (op->do_hex) {
9046 if (rsp_buff[0] & 0x40)
9047 printf("Log page code=0x%x,0x%x, DS=%d, SPF=1, "
9048 "page_len=0x%x\n", rsp_buff[0] & 0x3f, rsp_buff[1],
9049 !!(rsp_buff[0] & 0x80), pg_len);
9050 else
9051 printf("Log page code=0x%x, DS=%d, SPF=0, page_len=0x%x\n",
9052 rsp_buff[0] & 0x3f, !!(rsp_buff[0] & 0x80), pg_len);
9053 hex2stdout(rsp_buff, pg_len + 4, op->dstrhex_no_ascii);
9054 }
9055 else
9056 decode_page_contents(rsp_buff, pg_len + 4, op, jop);
9057 }
9058 }
9059 ret = res;
9060
9061 if (op->do_all && (pg_len > 1)) {
9062 int my_len = pg_len;
9063 bool spf;
9064
9065 parr = sg_memalign(parr_sz, 0, &free_parr, false);
9066 if (NULL == parr) {
9067 pr2serr("Unable to allocate heap for parr\n");
9068 ret = sg_convert_errno(ENOMEM);
9069 goto err_out;
9070 }
9071 spf = !!(rsp_buff[0] & 0x40);
9072 if (my_len > parr_sz) {
9073 pr2serr("Unexpectedly large page_len=%d, trim to %d\n", my_len,
9074 parr_sz);
9075 my_len = parr_sz;
9076 }
9077 memcpy(parr, rsp_buff + 4, my_len);
9078 for (k = 0; k < my_len; ++k) {
9079 op->pg_code = parr[k] & 0x3f;
9080 if (spf)
9081 op->subpg_code = parr[++k];
9082 else
9083 op->subpg_code = NOT_SPG_SUBPG;
9084
9085 /* Some devices include [pg_code, 0xff] for all pg_code > 0 */
9086 if ((op->pg_code > 0) && (SUPP_SPGS_SUBPG == op->subpg_code))
9087 continue; /* skip since no new information */
9088 if ((op->pg_code >= 0x30) && op->exclude_vendor)
9089 continue;
9090 if (! op->do_raw)
9091 sgj_pr_hr(jsp, "\n");
9092 res = do_logs(sg_fd, rsp_buff, resp_len, op);
9093 if (0 == res) {
9094 pg_len = sg_get_unaligned_be16(rsp_buff + 2);
9095 if ((pg_len + 4) > resp_len) {
9096 pr2serr("Only fetched %d bytes of response, truncate "
9097 "output\n", resp_len);
9098 pg_len = resp_len - 4;
9099 }
9100 if (op->do_raw && (! op->filter_given))
9101 dStrRaw(rsp_buff, pg_len + 4);
9102 else if (op->do_hex > 4)
9103 decode_page_contents(rsp_buff, pg_len + 4, op, jop);
9104 else if (op->do_hex > 1)
9105 hex2stdout(rsp_buff, pg_len + 4, op->dstrhex_no_ascii);
9106 else if (1 == op->do_hex) {
9107 if (0 == op->do_brief) {
9108 if (rsp_buff[0] & 0x40)
9109 printf("Log page code=0x%x,0x%x, DS=%d, SPF=1, "
9110 "page_len=0x%x\n", rsp_buff[0] & 0x3f,
9111 rsp_buff[1], !!(rsp_buff[0] & 0x80),
9112 pg_len);
9113 else
9114 printf("Log page code=0x%x, DS=%d, SPF=0, "
9115 "page_len=0x%x\n", rsp_buff[0] & 0x3f,
9116 !!(rsp_buff[0] & 0x80), pg_len);
9117 }
9118 hex2stdout(rsp_buff, pg_len + 4, op->dstrhex_no_ascii);
9119 }
9120 else
9121 decode_page_contents(rsp_buff, pg_len + 4, op, jop);
9122 } else if (SG_LIB_CAT_INVALID_OP == res)
9123 pr2serr("%spage=0x%x,0x%x not supported\n", ls_s,
9124 op->pg_code, op->subpg_code);
9125 else if (SG_LIB_CAT_NOT_READY == res)
9126 pr2serr("%sdevice not ready\n", ls_s);
9127 else if (SG_LIB_CAT_ILLEGAL_REQ == res)
9128 pr2serr("%sfield in cdb illegal [page=0x%x,0x%x]\n", ls_s,
9129 op->pg_code, op->subpg_code);
9130 else if (SG_LIB_CAT_UNIT_ATTENTION == res)
9131 pr2serr("%sunit attention\n", ls_s);
9132 else if (SG_LIB_CAT_ABORTED_COMMAND == res)
9133 pr2serr("%saborted command\n", ls_s);
9134 else
9135 pr2serr("%sfailed, try '-v' for more information\n", ls_s);
9136 }
9137 }
9138 err_out:
9139 if (free_rsp_buff)
9140 free(free_rsp_buff);
9141 if (free_parr)
9142 free(free_parr);
9143 if (sg_fd >= 0)
9144 sg_cmds_close_device(sg_fd);
9145 if (0 == vb) {
9146 if (! sg_if_can2stderr("sg_logs failed: ", ret))
9147 pr2serr("Some error occurred, try again with '-v' or '-vv' for "
9148 "more information\n");
9149 }
9150 if (as_json) {
9151 if (0 == op->do_hex)
9152 sgj_js2file(jsp, NULL, ret, stdout);
9153 sgj_finish(jsp);
9154 }
9155 return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
9156 }
9157