1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche * Copyright (c) 2004-2022 Douglas Gilbert.
3*44704f69SBart Van Assche * All rights reserved.
4*44704f69SBart Van Assche * Use of this source code is governed by a BSD-style
5*44704f69SBart Van Assche * license that can be found in the BSD_LICENSE file.
6*44704f69SBart Van Assche *
7*44704f69SBart Van Assche * SPDX-License-Identifier: BSD-2-Clause
8*44704f69SBart Van Assche */
9*44704f69SBart Van Assche
10*44704f69SBart Van Assche #include <unistd.h>
11*44704f69SBart Van Assche #include <fcntl.h>
12*44704f69SBart Van Assche #include <stdio.h>
13*44704f69SBart Van Assche #include <stdlib.h>
14*44704f69SBart Van Assche #include <stdarg.h>
15*44704f69SBart Van Assche #include <stdbool.h>
16*44704f69SBart Van Assche #include <string.h>
17*44704f69SBart Van Assche #include <ctype.h>
18*44704f69SBart Van Assche #include <errno.h>
19*44704f69SBart Van Assche #include <sys/types.h>
20*44704f69SBart Van Assche #include <sys/stat.h>
21*44704f69SBart Van Assche #include <getopt.h>
22*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
23*44704f69SBart Van Assche #include <inttypes.h>
24*44704f69SBart Van Assche
25*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
26*44704f69SBart Van Assche #include "config.h"
27*44704f69SBart Van Assche #endif
28*44704f69SBart Van Assche
29*44704f69SBart Van Assche #include "sg_lib.h"
30*44704f69SBart Van Assche #include "sg_cmds_basic.h"
31*44704f69SBart Van Assche #include "sg_cmds_extra.h"
32*44704f69SBart Van Assche #include "sg_unaligned.h"
33*44704f69SBart Van Assche #include "sg_pt.h"
34*44704f69SBart Van Assche #include "sg_pr2serr.h"
35*44704f69SBart Van Assche
36*44704f69SBart Van Assche /*
37*44704f69SBart Van Assche * This program issues SCSI SEND DIAGNOSTIC and RECEIVE DIAGNOSTIC RESULTS
38*44704f69SBart Van Assche * commands tailored for SES (enclosure) devices.
39*44704f69SBart Van Assche */
40*44704f69SBart Van Assche
41*44704f69SBart Van Assche static const char * version_str = "2.58 20220813"; /* ses4r04 */
42*44704f69SBart Van Assche
43*44704f69SBart Van Assche #define MX_ALLOC_LEN ((64 * 1024) - 4) /* max allowable for big enclosures */
44*44704f69SBart Van Assche #define MX_ELEM_HDR 1024
45*44704f69SBart Van Assche #define REQUEST_SENSE_RESP_SZ 252
46*44704f69SBart Van Assche #define DATA_IN_OFF 4
47*44704f69SBart Van Assche #define MIN_MAXLEN 16
48*44704f69SBart Van Assche #define MIN_DATA_IN_SZ 8192 /* use max(MIN_DATA_IN_SZ, op->maxlen) for
49*44704f69SBart Van Assche * the size of data_arr */
50*44704f69SBart Van Assche #define MX_DATA_IN_LINES (16 * 1024)
51*44704f69SBart Van Assche #define MX_JOIN_ROWS 520 /* element index fields in dpages are only 8
52*44704f69SBart Van Assche * bit, and index 0xff (255) is sometimes used
53*44704f69SBart Van Assche * for 'not applicable'. However this limit
54*44704f69SBart Van Assche * can bypassed with sub-enclosure numbers.
55*44704f69SBart Van Assche * So try higher figure. */
56*44704f69SBart Van Assche #define MX_DATA_IN_DESCS 32
57*44704f69SBart Van Assche #define NUM_ACTIVE_ET_AESP_ARR 32
58*44704f69SBart Van Assche
59*44704f69SBart Van Assche #define TEMPERAT_OFF 20 /* 8 bits represents -19 C to +235 C */
60*44704f69SBart Van Assche /* value of 0 (would imply -20 C) reserved */
61*44704f69SBart Van Assche
62*44704f69SBart Van Assche /* Send Diagnostic and Receive Diagnostic Results page codes */
63*44704f69SBart Van Assche /* Sometimes referred to as "dpage"s in code comments */
64*44704f69SBart Van Assche #define SUPPORTED_DPC 0x0
65*44704f69SBart Van Assche #define CONFIGURATION_DPC 0x1
66*44704f69SBart Van Assche #define ENC_CONTROL_DPC 0x2
67*44704f69SBart Van Assche #define ENC_STATUS_DPC 0x2
68*44704f69SBart Van Assche #define HELP_TEXT_DPC 0x3
69*44704f69SBart Van Assche #define STRING_DPC 0x4
70*44704f69SBart Van Assche #define THRESHOLD_DPC 0x5
71*44704f69SBart Van Assche #define ARRAY_CONTROL_DPC 0x6 /* obsolete, last seen ses-r08b.pdf */
72*44704f69SBart Van Assche #define ARRAY_STATUS_DPC 0x6 /* obsolete */
73*44704f69SBart Van Assche #define ELEM_DESC_DPC 0x7
74*44704f69SBart Van Assche #define SHORT_ENC_STATUS_DPC 0x8
75*44704f69SBart Van Assche #define ENC_BUSY_DPC 0x9
76*44704f69SBart Van Assche #define ADD_ELEM_STATUS_DPC 0xa /* Additional Element Status dpage code */
77*44704f69SBart Van Assche #define SUBENC_HELP_TEXT_DPC 0xb
78*44704f69SBart Van Assche #define SUBENC_STRING_DPC 0xc
79*44704f69SBart Van Assche #define SUPPORTED_SES_DPC 0xd /* should be 0x1 <= dpc <= 0x2f */
80*44704f69SBart Van Assche #define DOWNLOAD_MICROCODE_DPC 0xe
81*44704f69SBart Van Assche #define SUBENC_NICKNAME_DPC 0xf
82*44704f69SBart Van Assche #define ALL_DPC 0xff
83*44704f69SBart Van Assche
84*44704f69SBart Van Assche /* Element Type codes */
85*44704f69SBart Van Assche #define UNSPECIFIED_ETC 0x0
86*44704f69SBart Van Assche #define DEVICE_ETC 0x1
87*44704f69SBart Van Assche #define POWER_SUPPLY_ETC 0x2
88*44704f69SBart Van Assche #define COOLING_ETC 0x3
89*44704f69SBart Van Assche #define TEMPERATURE_ETC 0x4
90*44704f69SBart Van Assche #define DOOR_ETC 0x5 /* prior to ses3r05 was DOOR_LOCK_ETC */
91*44704f69SBart Van Assche #define AUD_ALARM_ETC 0x6
92*44704f69SBart Van Assche #define ENC_SCELECTR_ETC 0x7 /* Enclosure services controller electronics */
93*44704f69SBart Van Assche #define SCC_CELECTR_ETC 0x8 /* SCC: SCSI Controller Commands (e.g. RAID
94*44704f69SBart Van Assche * controller). SCC Controller Elecronics */
95*44704f69SBart Van Assche #define NV_CACHE_ETC 0x9
96*44704f69SBart Van Assche #define INV_OP_REASON_ETC 0xa
97*44704f69SBart Van Assche #define UI_POWER_SUPPLY_ETC 0xb
98*44704f69SBart Van Assche #define DISPLAY_ETC 0xc
99*44704f69SBart Van Assche #define KEY_PAD_ETC 0xd
100*44704f69SBart Van Assche #define ENCLOSURE_ETC 0xe
101*44704f69SBart Van Assche #define SCSI_PORT_TRAN_ETC 0xf
102*44704f69SBart Van Assche #define LANGUAGE_ETC 0x10
103*44704f69SBart Van Assche #define COMM_PORT_ETC 0x11
104*44704f69SBart Van Assche #define VOLT_SENSOR_ETC 0x12
105*44704f69SBart Van Assche #define CURR_SENSOR_ETC 0x13
106*44704f69SBart Van Assche #define SCSI_TPORT_ETC 0x14
107*44704f69SBart Van Assche #define SCSI_IPORT_ETC 0x15
108*44704f69SBart Van Assche #define SIMPLE_SUBENC_ETC 0x16
109*44704f69SBart Van Assche #define ARRAY_DEV_ETC 0x17
110*44704f69SBart Van Assche #define SAS_EXPANDER_ETC 0x18
111*44704f69SBart Van Assche #define SAS_CONNECTOR_ETC 0x19
112*44704f69SBart Van Assche #define LAST_ETC SAS_CONNECTOR_ETC /* adjust as necessary */
113*44704f69SBart Van Assche
114*44704f69SBart Van Assche #define TPROTO_PCIE_PS_NVME 1 /* NVMe regarded as subset of PCIe */
115*44704f69SBart Van Assche #define NUM_ETC (LAST_ETC + 1)
116*44704f69SBart Van Assche
117*44704f69SBart Van Assche #define DEF_CLEAR_VAL 0
118*44704f69SBart Van Assche #define DEF_SET_VAL 1
119*44704f69SBart Van Assche
120*44704f69SBart Van Assche
121*44704f69SBart Van Assche struct element_type_t {
122*44704f69SBart Van Assche int elem_type_code;
123*44704f69SBart Van Assche const char * abbrev;
124*44704f69SBart Van Assche const char * desc;
125*44704f69SBart Van Assche };
126*44704f69SBart Van Assche
127*44704f69SBart Van Assche #define CGS_CL_ARR_MAX_SZ 8
128*44704f69SBart Van Assche #define CGS_STR_MAX_SZ 80
129*44704f69SBart Van Assche
130*44704f69SBart Van Assche enum cgs_select_t {CLEAR_OPT, GET_OPT, SET_OPT};
131*44704f69SBart Van Assche
132*44704f69SBart Van Assche struct cgs_cl_t {
133*44704f69SBart Van Assche enum cgs_select_t cgs_sel;
134*44704f69SBart Van Assche bool last_cs; /* true only for last --clear= or --set= */
135*44704f69SBart Van Assche char cgs_str[CGS_STR_MAX_SZ];
136*44704f69SBart Van Assche };
137*44704f69SBart Van Assche
138*44704f69SBart Van Assche struct opts_t {
139*44704f69SBart Van Assche bool byte1_given; /* true if -b B1 or --byte1=B1 given */
140*44704f69SBart Van Assche bool do_control; /* want to write to DEVICE */
141*44704f69SBart Van Assche bool do_data; /* flag if --data= option has been used */
142*44704f69SBart Van Assche bool do_list;
143*44704f69SBart Van Assche bool do_status; /* want to read from DEVICE (or user data) */
144*44704f69SBart Van Assche bool eiioe_auto; /* Element Index Includes Overall (status) Element */
145*44704f69SBart Van Assche bool eiioe_force;
146*44704f69SBart Van Assche bool ind_given; /* '--index=...' or '-I ...' */
147*44704f69SBart Van Assche bool inner_hex;
148*44704f69SBart Van Assche bool many_dpages; /* user supplied data has more than one dpage */
149*44704f69SBart Van Assche bool mask_ign; /* element read-mask-modify-write actions */
150*44704f69SBart Van Assche bool o_readonly;
151*44704f69SBart Van Assche bool page_code_given; /* or suitable abbreviation */
152*44704f69SBart Van Assche bool quiet; /* exit status unaltered by --quiet */
153*44704f69SBart Van Assche bool seid_given;
154*44704f69SBart Van Assche bool verbose_given;
155*44704f69SBart Van Assche bool version_given;
156*44704f69SBart Van Assche bool warn;
157*44704f69SBart Van Assche int byte1; /* (origin 0 so second byte) in Control dpage */
158*44704f69SBart Van Assche int dev_slot_num;
159*44704f69SBart Van Assche int do_filter;
160*44704f69SBart Van Assche int do_help;
161*44704f69SBart Van Assche int do_hex;
162*44704f69SBart Van Assche int do_join; /* relational join of Enclosure status, Element
163*44704f69SBart Van Assche descriptor and Additional element status dpages.
164*44704f69SBart Van Assche Use twice to add Threshold in dpage to join. */
165*44704f69SBart Van Assche int do_raw;
166*44704f69SBart Van Assche int enumerate;
167*44704f69SBart Van Assche int ind_th; /* type header index, set by build_type_desc_hdr_arr() */
168*44704f69SBart Van Assche int ind_indiv; /* individual element index; -1 for overall */
169*44704f69SBart Van Assche int ind_indiv_last; /* if > ind_indiv then [ind_indiv..ind_indiv_last] */
170*44704f69SBart Van Assche int ind_et_inst; /* ETs can have multiple type header instances */
171*44704f69SBart Van Assche int maxlen;
172*44704f69SBart Van Assche int seid;
173*44704f69SBart Van Assche int page_code; /* recognised abbreviations converted to dpage num */
174*44704f69SBart Van Assche int verbose;
175*44704f69SBart Van Assche int num_cgs; /* number of --clear-, --get= and --set= options */
176*44704f69SBart Van Assche int mx_arr_len; /* allocated size of data_arr */
177*44704f69SBart Van Assche int arr_len; /* valid bytes in data_arr */
178*44704f69SBart Van Assche uint8_t * data_arr;
179*44704f69SBart Van Assche uint8_t * free_data_arr;
180*44704f69SBart Van Assche const char * desc_name;
181*44704f69SBart Van Assche const char * dev_name;
182*44704f69SBart Van Assche const struct element_type_t * ind_etp;
183*44704f69SBart Van Assche const char * index_str;
184*44704f69SBart Van Assche const char * nickname_str;
185*44704f69SBart Van Assche struct cgs_cl_t cgs_cl_arr[CGS_CL_ARR_MAX_SZ];
186*44704f69SBart Van Assche uint8_t sas_addr[8]; /* Big endian byte sequence */
187*44704f69SBart Van Assche };
188*44704f69SBart Van Assche
189*44704f69SBart Van Assche struct diag_page_code {
190*44704f69SBart Van Assche int page_code;
191*44704f69SBart Van Assche const char * desc;
192*44704f69SBart Van Assche };
193*44704f69SBart Van Assche
194*44704f69SBart Van Assche struct diag_page_abbrev {
195*44704f69SBart Van Assche const char * abbrev;
196*44704f69SBart Van Assche int page_code;
197*44704f69SBart Van Assche };
198*44704f69SBart Van Assche
199*44704f69SBart Van Assche /* The Configuration diagnostic page contains one or more of these. The
200*44704f69SBart Van Assche * elements of the Enclosure Control/Status and Threshold In/ Out page follow
201*44704f69SBart Van Assche * this format. The additional element status page is closely related to
202*44704f69SBart Van Assche * this format (with some element types and all overall elements excluded). */
203*44704f69SBart Van Assche struct type_desc_hdr_t {
204*44704f69SBart Van Assche uint8_t etype; /* element type code (0: unspecified) */
205*44704f69SBart Van Assche uint8_t num_elements; /* number of possible elements, excluding
206*44704f69SBart Van Assche * overall element */
207*44704f69SBart Van Assche uint8_t se_id; /* subenclosure id (0 for primary enclosure) */
208*44704f69SBart Van Assche uint8_t txt_len; /* type descriptor text length; (unused) */
209*44704f69SBart Van Assche };
210*44704f69SBart Van Assche
211*44704f69SBart Van Assche /* A SQL-like join of the Enclosure Status, Threshold In and Additional
212*44704f69SBart Van Assche * Element Status pages based of the format indicated in the Configuration
213*44704f69SBart Van Assche * page. Note that the array of these struct instances is built such that
214*44704f69SBart Van Assche * the array index is equal to the 'ei_ioe' (element index that includes
215*44704f69SBart Van Assche * overall elements). */
216*44704f69SBart Van Assche struct join_row_t { /* this struct is 72 bytes long on Intel "64" bit arch */
217*44704f69SBart Van Assche int th_i; /* type header index (origin 0) */
218*44704f69SBart Van Assche int indiv_i; /* individual (element) index, -1 for overall
219*44704f69SBart Van Assche * instance, otherwise origin 0 */
220*44704f69SBart Van Assche uint8_t etype; /* element type */
221*44704f69SBart Van Assche uint8_t se_id; /* subenclosure id (0 for primary enclosure) */
222*44704f69SBart Van Assche int ei_eoe; /* element index referring to Enclosure status dpage
223*44704f69SBart Van Assche * descriptors, origin 0 and excludes overall
224*44704f69SBart Van Assche * elements, -1 for not applicable. As defined by
225*44704f69SBart Van Assche * SES-2 standard for the AES descriptor, EIP=1 */
226*44704f69SBart Van Assche int ei_aess; /* subset of ei_eoe that only includes elements of
227*44704f69SBart Van Assche * these types: excludes DEVICE_ETC, ARRAY_DEV_ETC,
228*44704f69SBart Van Assche * SAS_EXPANDER_ETC, SCSI_IPORT_ETC, SCSI_TPORT_ETC
229*44704f69SBart Van Assche * and ENC_SCELECTR_ETC. -1 for not applicable */
230*44704f69SBart Van Assche /* following point into Element Descriptor, Enclosure Status, Threshold
231*44704f69SBart Van Assche * In and Additional element status diagnostic pages. enc_statp only
232*44704f69SBart Van Assche * NULL beyond last, other pointers can be NULL . */
233*44704f69SBart Van Assche const uint8_t * elem_descp;
234*44704f69SBart Van Assche uint8_t * enc_statp; /* NULL indicates past last */
235*44704f69SBart Van Assche uint8_t * thresh_inp;
236*44704f69SBart Van Assche const uint8_t * ae_statp;
237*44704f69SBart Van Assche int dev_slot_num; /* if not available, set to -1 */
238*44704f69SBart Van Assche uint8_t sas_addr[8]; /* big endian, if not available, set to 0 */
239*44704f69SBart Van Assche };
240*44704f69SBart Van Assche
241*44704f69SBart Van Assche enum fj_select_t {FJ_IOE, FJ_EOE, FJ_AESS, FJ_SAS_CON};
242*44704f69SBart Van Assche
243*44704f69SBart Van Assche /* Instance ('tes' in main() ) holds a type_desc_hdr_t array potentially with
244*44704f69SBart Van Assche the matching join array if present. */
245*44704f69SBart Van Assche struct th_es_t {
246*44704f69SBart Van Assche const struct type_desc_hdr_t * th_base;
247*44704f69SBart Van Assche int num_ths; /* items in array pointed to by th_base */
248*44704f69SBart Van Assche struct join_row_t * j_base;
249*44704f69SBart Van Assche int num_j_rows;
250*44704f69SBart Van Assche int num_j_eoe;
251*44704f69SBart Van Assche };
252*44704f69SBart Van Assche
253*44704f69SBart Van Assche /* Representation of <acronym>[=<value>] or
254*44704f69SBart Van Assche * <start_byte>:<start_bit>[:<num_bits>][=<value>]. Associated with
255*44704f69SBart Van Assche * --clear=, --get= or --set= option. */
256*44704f69SBart Van Assche struct tuple_acronym_val {
257*44704f69SBart Van Assche const char * acron;
258*44704f69SBart Van Assche const char * val_str;
259*44704f69SBart Van Assche enum cgs_select_t cgs_sel; /* indicates --clear=, --get= or --set= */
260*44704f69SBart Van Assche int start_byte; /* -1 indicates no start_byte */
261*44704f69SBart Van Assche int start_bit;
262*44704f69SBart Van Assche int num_bits;
263*44704f69SBart Van Assche int64_t val;
264*44704f69SBart Van Assche };
265*44704f69SBart Van Assche
266*44704f69SBart Van Assche /* Mapping from <acronym> to <start_byte>:<start_bit>:<num_bits> for a
267*44704f69SBart Van Assche * given element type. Table of known acronyms made from these elements. */
268*44704f69SBart Van Assche struct acronym2tuple {
269*44704f69SBart Van Assche const char * acron; /* element name or acronym, NULL for past end */
270*44704f69SBart Van Assche int etype; /* -1 for all element types */
271*44704f69SBart Van Assche int start_byte; /* origin 0, normally 0 to 3 */
272*44704f69SBart Van Assche int start_bit; /* 7 (MSbit or leftmost in SES drafts) to 0 (LSbit) */
273*44704f69SBart Van Assche int num_bits; /* usually 1, maximum is 64 */
274*44704f69SBart Van Assche const char * info; /* optional, set to NULL if not used */
275*44704f69SBart Van Assche };
276*44704f69SBart Van Assche
277*44704f69SBart Van Assche /* Structure for holding (sub-)enclosure information found in the
278*44704f69SBart Van Assche * Configuration diagnostic page. */
279*44704f69SBart Van Assche struct enclosure_info {
280*44704f69SBart Van Assche int have_info;
281*44704f69SBart Van Assche int rel_esp_id; /* relative enclosure services process id (origin 1) */
282*44704f69SBart Van Assche int num_esp; /* number of enclosure services processes */
283*44704f69SBart Van Assche uint8_t enc_log_id[8]; /* 8 byte NAA */
284*44704f69SBart Van Assche uint8_t enc_vendor_id[8]; /* may differ from INQUIRY response */
285*44704f69SBart Van Assche uint8_t product_id[16]; /* may differ from INQUIRY response */
286*44704f69SBart Van Assche uint8_t product_rev_level[4]; /* may differ from INQUIRY response */
287*44704f69SBart Van Assche };
288*44704f69SBart Van Assche
289*44704f69SBart Van Assche /* When --status is given with --data= the file contents may contain more
290*44704f69SBart Van Assche * than one dpage to be decoded. */
291*44704f69SBart Van Assche struct data_in_desc_t {
292*44704f69SBart Van Assche bool in_use;
293*44704f69SBart Van Assche int page_code;
294*44704f69SBart Van Assche int offset; /* byte offset from op->data_arr + DATA_IN_OFF */
295*44704f69SBart Van Assche int dp_len; /* byte length of this diagnostic page */
296*44704f69SBart Van Assche };
297*44704f69SBart Van Assche
298*44704f69SBart Van Assche
299*44704f69SBart Van Assche /* Join array has four "element index"ing strategies:
300*44704f69SBart Van Assche * [1] based on all descriptors in the Enclosure Status (ES) dpage
301*44704f69SBart Van Assche * [2] based on the non-overall descriptors in the ES dpage
302*44704f69SBart Van Assche * [3] based on the non-overall descriptors of these element types
303*44704f69SBart Van Assche * in the ES dpage: DEVICE_ETC, ARRAY_DEV_ETC, SAS_EXPANDER_ETC,
304*44704f69SBart Van Assche * SCSI_IPORT_ETC, SCSI_TPORT_ETC and ENC_SCELECTR_ETC.
305*44704f69SBart Van Assche * [4] based on the non-overall descriptors of the SAS_CONNECTOR_ETC
306*44704f69SBart Van Assche * element type
307*44704f69SBart Van Assche *
308*44704f69SBart Van Assche * The indexes are all origin 0 with the maximum index being one less then
309*44704f69SBart Van Assche * the number of status descriptors in the ES dpage. Table of supported
310*44704f69SBart Van Assche * permutations follows:
311*44704f69SBart Van Assche *
312*44704f69SBart Van Assche * ==========|===============================================================
313*44704f69SBart Van Assche * Algorithm | Indexes | Notes
314*44704f69SBart Van Assche * |Element|Connector element|Other element|
315*44704f69SBart Van Assche * ==========|=======|=================|=============|=======================
316*44704f69SBart Van Assche * [A] | [2] | [4] | [3] | SES-2, OR
317*44704f69SBart Van Assche * [A] | [2] | [4] | [3] | SES-3,EIIOE=0
318*44704f69SBart Van Assche * ----------|-------|-----------------|-------------|-----------------------
319*44704f69SBart Van Assche * [B] | [1] | [1] | [1] | SES-3, EIIOE=1
320*44704f69SBart Van Assche * ----------|-------|-----------------|-------------|-----------------------
321*44704f69SBart Van Assche * [C] | [2] | [2] | [2] | SES-3, EIIOE=2
322*44704f69SBart Van Assche * ----------|-------|-----------------|-------------|-----------------------
323*44704f69SBart Van Assche * [D] | [2] | [1] | [1] | SES-3, EIIOE=3
324*44704f69SBart Van Assche * ----------|-------|-----------------|-------------|-----------------------
325*44704f69SBart Van Assche * [E] | [1] | [4] | [3] | EIIOE=0 and
326*44704f69SBart Van Assche * | | | | --eiioe=force, OR
327*44704f69SBart Van Assche * [E] | [1] | [4] | [3] | {HP JBOD} EIIOE=0 and
328*44704f69SBart Van Assche * | | | | --eiioe=auto and
329*44704f69SBart Van Assche * | | | | AES[desc_0].ei==1 .
330*44704f69SBart Van Assche * ----------|-------|-----------------|-------------|-----------------------
331*44704f69SBart Van Assche * [F] | [2->3]| [4] | [3] | "broken_ei" when any
332*44704f69SBart Van Assche * | | | | of AES[*].ei invalid
333*44704f69SBart Van Assche * | | | | using strategy [2]
334*44704f69SBart Van Assche * ----------|-------|-----------------|-------------|-----------------------
335*44704f69SBart Van Assche * [Z] | - | [4] | [3] | EIP=0, implicit
336*44704f69SBart Van Assche * | | | | element index of [3]
337*44704f69SBart Van Assche * ==========================================================================
338*44704f69SBart Van Assche *
339*44704f69SBart Van Assche *
340*44704f69SBart Van Assche */
341*44704f69SBart Van Assche static struct join_row_t join_arr[MX_JOIN_ROWS];
342*44704f69SBart Van Assche static struct join_row_t * join_arr_lastp = join_arr + MX_JOIN_ROWS - 1;
343*44704f69SBart Van Assche static bool join_done = false;
344*44704f69SBart Van Assche
345*44704f69SBart Van Assche static struct type_desc_hdr_t type_desc_hdr_arr[MX_ELEM_HDR];
346*44704f69SBart Van Assche static int type_desc_hdr_count = 0;
347*44704f69SBart Van Assche static uint8_t * config_dp_resp = NULL;
348*44704f69SBart Van Assche static uint8_t * free_config_dp_resp = NULL;
349*44704f69SBart Van Assche static int config_dp_resp_len;
350*44704f69SBart Van Assche
351*44704f69SBart Van Assche static struct data_in_desc_t data_in_desc_arr[MX_DATA_IN_DESCS];
352*44704f69SBart Van Assche
353*44704f69SBart Van Assche /* Large buffers on heap, aligned to page size and zeroed */
354*44704f69SBart Van Assche static uint8_t * enc_stat_rsp;
355*44704f69SBart Van Assche static uint8_t * elem_desc_rsp;
356*44704f69SBart Van Assche static uint8_t * add_elem_rsp;
357*44704f69SBart Van Assche static uint8_t * threshold_rsp;
358*44704f69SBart Van Assche
359*44704f69SBart Van Assche static unsigned enc_stat_rsp_sz;
360*44704f69SBart Van Assche static unsigned elem_desc_rsp_sz;
361*44704f69SBart Van Assche static unsigned add_elem_rsp_sz;
362*44704f69SBart Van Assche static unsigned threshold_rsp_sz;
363*44704f69SBart Van Assche
364*44704f69SBart Van Assche static int enc_stat_rsp_len;
365*44704f69SBart Van Assche static int elem_desc_rsp_len;
366*44704f69SBart Van Assche static int add_elem_rsp_len;
367*44704f69SBart Van Assche static int threshold_rsp_len;
368*44704f69SBart Van Assche
369*44704f69SBart Van Assche
370*44704f69SBart Van Assche /* Diagnostic page names, control and/or status (in and/or out) */
371*44704f69SBart Van Assche static struct diag_page_code dpc_arr[] = {
372*44704f69SBart Van Assche {SUPPORTED_DPC, "Supported Diagnostic Pages"}, /* 0 */
373*44704f69SBart Van Assche {CONFIGURATION_DPC, "Configuration (SES)"},
374*44704f69SBart Van Assche {ENC_STATUS_DPC, "Enclosure Status/Control (SES)"},
375*44704f69SBart Van Assche {HELP_TEXT_DPC, "Help Text (SES)"},
376*44704f69SBart Van Assche {STRING_DPC, "String In/Out (SES)"},
377*44704f69SBart Van Assche {THRESHOLD_DPC, "Threshold In/Out (SES)"},
378*44704f69SBart Van Assche {ARRAY_STATUS_DPC, "Array Status/Control (SES, obsolete)"},
379*44704f69SBart Van Assche {ELEM_DESC_DPC, "Element Descriptor (SES)"},
380*44704f69SBart Van Assche {SHORT_ENC_STATUS_DPC, "Short Enclosure Status (SES)"}, /* 8 */
381*44704f69SBart Van Assche {ENC_BUSY_DPC, "Enclosure Busy (SES-2)"},
382*44704f69SBart Van Assche {ADD_ELEM_STATUS_DPC, "Additional Element Status (SES-2)"},
383*44704f69SBart Van Assche {SUBENC_HELP_TEXT_DPC, "Subenclosure Help Text (SES-2)"},
384*44704f69SBart Van Assche {SUBENC_STRING_DPC, "Subenclosure String In/Out (SES-2)"},
385*44704f69SBart Van Assche {SUPPORTED_SES_DPC, "Supported SES Diagnostic Pages (SES-2)"},
386*44704f69SBart Van Assche {DOWNLOAD_MICROCODE_DPC, "Download Microcode (SES-2)"},
387*44704f69SBart Van Assche {SUBENC_NICKNAME_DPC, "Subenclosure Nickname (SES-2)"},
388*44704f69SBart Van Assche {0x3f, "Protocol Specific (SAS transport)"},
389*44704f69SBart Van Assche {0x40, "Translate Address (SBC)"},
390*44704f69SBart Van Assche {0x41, "Device Status (SBC)"},
391*44704f69SBart Van Assche {0x42, "Rebuild Assist (SBC)"}, /* sbc3r31 */
392*44704f69SBart Van Assche {ALL_DPC, "All SES diagnostic pages output (sg_ses)"},
393*44704f69SBart Van Assche {-1, NULL},
394*44704f69SBart Van Assche };
395*44704f69SBart Van Assche
396*44704f69SBart Van Assche /* Diagnostic page names, for status (or in) pages */
397*44704f69SBart Van Assche static struct diag_page_code in_dpc_arr[] = {
398*44704f69SBart Van Assche {SUPPORTED_DPC, "Supported Diagnostic Pages"}, /* 0 */
399*44704f69SBart Van Assche {CONFIGURATION_DPC, "Configuration (SES)"},
400*44704f69SBart Van Assche {ENC_STATUS_DPC, "Enclosure Status (SES)"},
401*44704f69SBart Van Assche {HELP_TEXT_DPC, "Help Text (SES)"},
402*44704f69SBart Van Assche {STRING_DPC, "String In (SES)"},
403*44704f69SBart Van Assche {THRESHOLD_DPC, "Threshold In (SES)"},
404*44704f69SBart Van Assche {ARRAY_STATUS_DPC, "Array Status (SES, obsolete)"},
405*44704f69SBart Van Assche {ELEM_DESC_DPC, "Element Descriptor (SES)"},
406*44704f69SBart Van Assche {SHORT_ENC_STATUS_DPC, "Short Enclosure Status (SES)"}, /* 8 */
407*44704f69SBart Van Assche {ENC_BUSY_DPC, "Enclosure Busy (SES-2)"},
408*44704f69SBart Van Assche {ADD_ELEM_STATUS_DPC, "Additional Element Status (SES-2)"},
409*44704f69SBart Van Assche {SUBENC_HELP_TEXT_DPC, "Subenclosure Help Text (SES-2)"},
410*44704f69SBart Van Assche {SUBENC_STRING_DPC, "Subenclosure String In (SES-2)"},
411*44704f69SBart Van Assche {SUPPORTED_SES_DPC, "Supported SES Diagnostic Pages (SES-2)"},
412*44704f69SBart Van Assche {DOWNLOAD_MICROCODE_DPC, "Download Microcode (SES-2)"},
413*44704f69SBart Van Assche {SUBENC_NICKNAME_DPC, "Subenclosure Nickname (SES-2)"},
414*44704f69SBart Van Assche {0x3f, "Protocol Specific (SAS transport)"},
415*44704f69SBart Van Assche {0x40, "Translate Address (SBC)"},
416*44704f69SBart Van Assche {0x41, "Device Status (SBC)"},
417*44704f69SBart Van Assche {0x42, "Rebuild Assist Input (SBC)"},
418*44704f69SBart Van Assche {-1, NULL},
419*44704f69SBart Van Assche };
420*44704f69SBart Van Assche
421*44704f69SBart Van Assche /* Diagnostic page names, for control (or out) pages */
422*44704f69SBart Van Assche static struct diag_page_code out_dpc_arr[] = {
423*44704f69SBart Van Assche {SUPPORTED_DPC, "?? [Supported Diagnostic Pages]"}, /* 0 */
424*44704f69SBart Van Assche {CONFIGURATION_DPC, "?? [Configuration (SES)]"},
425*44704f69SBart Van Assche {ENC_CONTROL_DPC, "Enclosure Control (SES)"},
426*44704f69SBart Van Assche {HELP_TEXT_DPC, "Help Text (SES)"},
427*44704f69SBart Van Assche {STRING_DPC, "String Out (SES)"},
428*44704f69SBart Van Assche {THRESHOLD_DPC, "Threshold Out (SES)"},
429*44704f69SBart Van Assche {ARRAY_CONTROL_DPC, "Array Control (SES, obsolete)"},
430*44704f69SBart Van Assche {ELEM_DESC_DPC, "?? [Element Descriptor (SES)]"},
431*44704f69SBart Van Assche {SHORT_ENC_STATUS_DPC, "?? [Short Enclosure Status (SES)]"}, /* 8 */
432*44704f69SBart Van Assche {ENC_BUSY_DPC, "?? [Enclosure Busy (SES-2)]"},
433*44704f69SBart Van Assche {ADD_ELEM_STATUS_DPC, "?? [Additional Element Status (SES-2)]"},
434*44704f69SBart Van Assche {SUBENC_HELP_TEXT_DPC, "?? [Subenclosure Help Text (SES-2)]"},
435*44704f69SBart Van Assche {SUBENC_STRING_DPC, "Subenclosure String Out (SES-2)"},
436*44704f69SBart Van Assche {SUPPORTED_SES_DPC, "?? [Supported SES Diagnostic Pages (SES-2)]"},
437*44704f69SBart Van Assche {DOWNLOAD_MICROCODE_DPC, "Download Microcode (SES-2)"},
438*44704f69SBart Van Assche {SUBENC_NICKNAME_DPC, "Subenclosure Nickname (SES-2)"},
439*44704f69SBart Van Assche {0x3f, "Protocol Specific (SAS transport)"},
440*44704f69SBart Van Assche {0x40, "Translate Address (SBC)"},
441*44704f69SBart Van Assche {0x41, "Device Status (SBC)"},
442*44704f69SBart Van Assche {0x42, "Rebuild Assist Output (SBC)"},
443*44704f69SBart Van Assche {-1, NULL},
444*44704f69SBart Van Assche };
445*44704f69SBart Van Assche
446*44704f69SBart Van Assche static struct diag_page_abbrev dp_abbrev[] = {
447*44704f69SBart Van Assche {"ac", ARRAY_CONTROL_DPC},
448*44704f69SBart Van Assche {"aes", ADD_ELEM_STATUS_DPC},
449*44704f69SBart Van Assche {"all", ALL_DPC},
450*44704f69SBart Van Assche {"as", ARRAY_STATUS_DPC},
451*44704f69SBart Van Assche {"cf", CONFIGURATION_DPC},
452*44704f69SBart Van Assche {"dm", DOWNLOAD_MICROCODE_DPC},
453*44704f69SBart Van Assche {"eb", ENC_BUSY_DPC},
454*44704f69SBart Van Assche {"ec", ENC_CONTROL_DPC},
455*44704f69SBart Van Assche {"ed", ELEM_DESC_DPC},
456*44704f69SBart Van Assche {"es", ENC_STATUS_DPC},
457*44704f69SBart Van Assche {"ht", HELP_TEXT_DPC},
458*44704f69SBart Van Assche {"sdp", SUPPORTED_DPC},
459*44704f69SBart Van Assche {"ses", SHORT_ENC_STATUS_DPC},
460*44704f69SBart Van Assche {"sht", SUBENC_HELP_TEXT_DPC},
461*44704f69SBart Van Assche {"snic", SUBENC_NICKNAME_DPC},
462*44704f69SBart Van Assche {"ssp", SUPPORTED_SES_DPC},
463*44704f69SBart Van Assche {"sstr", SUBENC_STRING_DPC},
464*44704f69SBart Van Assche {"str", STRING_DPC},
465*44704f69SBart Van Assche {"th", THRESHOLD_DPC},
466*44704f69SBart Van Assche {NULL, -999},
467*44704f69SBart Van Assche };
468*44704f69SBart Van Assche
469*44704f69SBart Van Assche /* Names of element types used by the Enclosure Control/Status diagnostic
470*44704f69SBart Van Assche * page. */
471*44704f69SBart Van Assche static struct element_type_t element_type_arr[] = {
472*44704f69SBart Van Assche {UNSPECIFIED_ETC, "un", "Unspecified"},
473*44704f69SBart Van Assche {DEVICE_ETC, "dev", "Device slot"},
474*44704f69SBart Van Assche {POWER_SUPPLY_ETC, "ps", "Power supply"},
475*44704f69SBart Van Assche {COOLING_ETC, "coo", "Cooling"},
476*44704f69SBart Van Assche {TEMPERATURE_ETC, "ts", "Temperature sensor"},
477*44704f69SBart Van Assche {DOOR_ETC, "do", "Door"}, /* prior to ses3r05 was 'dl' (for Door Lock)
478*44704f69SBart Van Assche but the "Lock" has been dropped */
479*44704f69SBart Van Assche {AUD_ALARM_ETC, "aa", "Audible alarm"},
480*44704f69SBart Van Assche {ENC_SCELECTR_ETC, "esc", "Enclosure services controller electronics"},
481*44704f69SBart Van Assche {SCC_CELECTR_ETC, "sce", "SCC controller electronics"},
482*44704f69SBart Van Assche {NV_CACHE_ETC, "nc", "Nonvolatile cache"},
483*44704f69SBart Van Assche {INV_OP_REASON_ETC, "ior", "Invalid operation reason"},
484*44704f69SBart Van Assche {UI_POWER_SUPPLY_ETC, "ups", "Uninterruptible power supply"},
485*44704f69SBart Van Assche {DISPLAY_ETC, "dis", "Display"},
486*44704f69SBart Van Assche {KEY_PAD_ETC, "kpe", "Key pad entry"},
487*44704f69SBart Van Assche {ENCLOSURE_ETC, "enc", "Enclosure"},
488*44704f69SBart Van Assche {SCSI_PORT_TRAN_ETC, "sp", "SCSI port/transceiver"},
489*44704f69SBart Van Assche {LANGUAGE_ETC, "lan", "Language"},
490*44704f69SBart Van Assche {COMM_PORT_ETC, "cp", "Communication port"},
491*44704f69SBart Van Assche {VOLT_SENSOR_ETC, "vs", "Voltage sensor"},
492*44704f69SBart Van Assche {CURR_SENSOR_ETC, "cs", "Current sensor"},
493*44704f69SBart Van Assche {SCSI_TPORT_ETC, "stp", "SCSI target port"},
494*44704f69SBart Van Assche {SCSI_IPORT_ETC, "sip", "SCSI initiator port"},
495*44704f69SBart Van Assche {SIMPLE_SUBENC_ETC, "ss", "Simple subenclosure"},
496*44704f69SBart Van Assche {ARRAY_DEV_ETC, "arr", "Array device slot"},
497*44704f69SBart Van Assche {SAS_EXPANDER_ETC, "sse", "SAS expander"},
498*44704f69SBart Van Assche {SAS_CONNECTOR_ETC, "ssc", "SAS connector"},
499*44704f69SBart Van Assche {-1, NULL, NULL},
500*44704f69SBart Van Assche };
501*44704f69SBart Van Assche
502*44704f69SBart Van Assche static struct element_type_t element_type_by_code =
503*44704f69SBart Van Assche {0, NULL, "element type code form"};
504*44704f69SBart Van Assche
505*44704f69SBart Van Assche /* Many control element names below have "RQST" in front in drafts.
506*44704f69SBart Van Assche These are for the Enclosure Control/Status diagnostic page */
507*44704f69SBart Van Assche static struct acronym2tuple ecs_a2t_arr[] = {
508*44704f69SBart Van Assche /* acron element_type start_byte start_bit num_bits */
509*44704f69SBart Van Assche {"ac_fail", UI_POWER_SUPPLY_ETC, 2, 4, 1, NULL},
510*44704f69SBart Van Assche {"ac_hi", UI_POWER_SUPPLY_ETC, 2, 6, 1, NULL},
511*44704f69SBart Van Assche {"ac_lo", UI_POWER_SUPPLY_ETC, 2, 7, 1, NULL},
512*44704f69SBart Van Assche {"ac_qual", UI_POWER_SUPPLY_ETC, 2, 5, 1, NULL},
513*44704f69SBart Van Assche {"active", DEVICE_ETC, 2, 7, 1, NULL}, /* for control only */
514*44704f69SBart Van Assche {"active", ARRAY_DEV_ETC, 2, 7, 1, NULL}, /* for control only */
515*44704f69SBart Van Assche {"batt_fail", UI_POWER_SUPPLY_ETC, 3, 1, 1, NULL},
516*44704f69SBart Van Assche {"bpf", UI_POWER_SUPPLY_ETC, 3, 0, 1, NULL},
517*44704f69SBart Van Assche {"bypa", DEVICE_ETC, 3, 3, 1, "bypass port A"},
518*44704f69SBart Van Assche {"bypa", ARRAY_DEV_ETC, 3, 3, 1, "bypass port A"},
519*44704f69SBart Van Assche {"bypb", DEVICE_ETC, 3, 2, 1, "bypass port B"},
520*44704f69SBart Van Assche {"bypb", ARRAY_DEV_ETC, 3, 2, 1, "bypass port B"},
521*44704f69SBart Van Assche {"conscheck", ARRAY_DEV_ETC, 1, 4, 1, "consistency check"},
522*44704f69SBart Van Assche {"ctr_link", SAS_CONNECTOR_ETC, 2, 7, 8, "connector physical link"},
523*44704f69SBart Van Assche {"ctr_type", SAS_CONNECTOR_ETC, 1, 6, 7, "connector type"},
524*44704f69SBart Van Assche {"current", CURR_SENSOR_ETC, 2, 7, 16, "current in centiamps"},
525*44704f69SBart Van Assche {"dc_fail", UI_POWER_SUPPLY_ETC, 2, 3, 1, NULL},
526*44704f69SBart Van Assche {"disable", -1, 0, 5, 1, NULL}, /* -1 is for all element types */
527*44704f69SBart Van Assche {"disable_elm", SCSI_PORT_TRAN_ETC, 3, 4, 1, "disable port/transceiver"},
528*44704f69SBart Van Assche {"disable_elm", COMM_PORT_ETC, 3, 0, 1, "disable communication port"},
529*44704f69SBart Van Assche {"devoff", DEVICE_ETC, 3, 4, 1, NULL}, /* device off */
530*44704f69SBart Van Assche {"devoff", ARRAY_DEV_ETC, 3, 4, 1, NULL},
531*44704f69SBart Van Assche {"disp_mode", DISPLAY_ETC, 1, 1, 2, NULL},
532*44704f69SBart Van Assche {"disp_char", DISPLAY_ETC, 2, 7, 16, NULL},
533*44704f69SBart Van Assche {"dnr", ARRAY_DEV_ETC, 2, 6, 1, "do not remove"},
534*44704f69SBart Van Assche {"dnr", COOLING_ETC, 1, 6, 1, "do not remove"},
535*44704f69SBart Van Assche {"dnr", DEVICE_ETC, 2, 6, 1, "do not remove"},
536*44704f69SBart Van Assche {"dnr", ENC_SCELECTR_ETC, 1, 5, 1, "do not remove"},
537*44704f69SBart Van Assche {"dnr", POWER_SUPPLY_ETC, 1, 6, 1, "do not remove"},
538*44704f69SBart Van Assche {"dnr", UI_POWER_SUPPLY_ETC, 3, 3, 1, "do not remove"},
539*44704f69SBart Van Assche {"enable", SCSI_IPORT_ETC, 3, 0, 1, NULL},
540*44704f69SBart Van Assche {"enable", SCSI_TPORT_ETC, 3, 0, 1, NULL},
541*44704f69SBart Van Assche {"fail", AUD_ALARM_ETC, 1, 6, 1, NULL},
542*44704f69SBart Van Assche {"fail", COMM_PORT_ETC, 1, 7, 1, NULL},
543*44704f69SBart Van Assche {"fail", COOLING_ETC, 3, 6, 1, NULL},
544*44704f69SBart Van Assche {"fail", CURR_SENSOR_ETC, 3, 6, 1, NULL},
545*44704f69SBart Van Assche {"fail", DISPLAY_ETC, 1, 6, 1, NULL},
546*44704f69SBart Van Assche {"fail", DOOR_ETC, 1, 6, 1, NULL},
547*44704f69SBart Van Assche {"fail", ENC_SCELECTR_ETC, 1, 6, 1, NULL},
548*44704f69SBart Van Assche {"fail", KEY_PAD_ETC, 1, 6, 1, NULL},
549*44704f69SBart Van Assche {"fail", NV_CACHE_ETC, 3, 6, 1, NULL},
550*44704f69SBart Van Assche {"fail", POWER_SUPPLY_ETC, 3, 6, 1, NULL},
551*44704f69SBart Van Assche {"fail", SAS_CONNECTOR_ETC, 3, 6, 1, NULL},
552*44704f69SBart Van Assche {"fail", SAS_EXPANDER_ETC, 1, 6, 1, NULL},
553*44704f69SBart Van Assche {"fail", SCC_CELECTR_ETC, 3, 6, 1, NULL},
554*44704f69SBart Van Assche {"fail", SCSI_IPORT_ETC, 1, 6, 1, NULL},
555*44704f69SBart Van Assche {"fail", SCSI_PORT_TRAN_ETC, 1, 6, 1, NULL},
556*44704f69SBart Van Assche {"fail", SCSI_TPORT_ETC, 1, 6, 1, NULL},
557*44704f69SBart Van Assche {"fail", SIMPLE_SUBENC_ETC, 1, 6, 1, NULL},
558*44704f69SBart Van Assche {"fail", TEMPERATURE_ETC, 3, 6, 1, NULL},
559*44704f69SBart Van Assche {"fail", UI_POWER_SUPPLY_ETC, 3, 6, 1, NULL},
560*44704f69SBart Van Assche {"fail", VOLT_SENSOR_ETC, 1, 6, 1, NULL},
561*44704f69SBart Van Assche {"failure_ind", ENCLOSURE_ETC, 2, 1, 1, NULL},
562*44704f69SBart Van Assche {"failure", ENCLOSURE_ETC, 3, 1, 1, NULL},
563*44704f69SBart Van Assche {"fault", DEVICE_ETC, 3, 5, 1, NULL},
564*44704f69SBart Van Assche {"fault", ARRAY_DEV_ETC, 3, 5, 1, NULL},
565*44704f69SBart Van Assche {"hotspare", ARRAY_DEV_ETC, 1, 5, 1, NULL},
566*44704f69SBart Van Assche {"hotswap", COOLING_ETC, 3, 7, 1, NULL},
567*44704f69SBart Van Assche {"hotswap", ENC_SCELECTR_ETC, 3, 7, 1, NULL}, /* status only */
568*44704f69SBart Van Assche {"hw_reset", ENC_SCELECTR_ETC, 1, 2, 1, "hardware reset"}, /* 18-047r1 */
569*44704f69SBart Van Assche {"ident", DEVICE_ETC, 2, 1, 1, "flash LED"},
570*44704f69SBart Van Assche {"ident", ARRAY_DEV_ETC, 2, 1, 1, "flash LED"},
571*44704f69SBart Van Assche {"ident", POWER_SUPPLY_ETC, 1, 7, 1, "flash LED"},
572*44704f69SBart Van Assche {"ident", COMM_PORT_ETC, 1, 7, 1, "flash LED"},
573*44704f69SBart Van Assche {"ident", COOLING_ETC, 1, 7, 1, "flash LED"},
574*44704f69SBart Van Assche {"ident", CURR_SENSOR_ETC, 1, 7, 1, "flash LED"},
575*44704f69SBart Van Assche {"ident", DISPLAY_ETC, 1, 7, 1, "flash LED"},
576*44704f69SBart Van Assche {"ident", DOOR_ETC, 1, 7, 1, "flash LED"},
577*44704f69SBart Van Assche {"ident", ENC_SCELECTR_ETC, 1, 7, 1, "flash LED"},
578*44704f69SBart Van Assche {"ident", ENCLOSURE_ETC, 1, 7, 1, "flash LED"},
579*44704f69SBart Van Assche {"ident", KEY_PAD_ETC, 1, 7, 1, "flash LED"},
580*44704f69SBart Van Assche {"ident", LANGUAGE_ETC, 1, 7, 1, "flash LED"},
581*44704f69SBart Van Assche {"ident", AUD_ALARM_ETC, 1, 7, 1, NULL},
582*44704f69SBart Van Assche {"ident", NV_CACHE_ETC, 1, 7, 1, "flash LED"},
583*44704f69SBart Van Assche {"ident", SAS_CONNECTOR_ETC, 1, 7, 1, "flash LED"},
584*44704f69SBart Van Assche {"ident", SAS_EXPANDER_ETC, 1, 7, 1, "flash LED"},
585*44704f69SBart Van Assche {"ident", SCC_CELECTR_ETC, 1, 7, 1, "flash LED"},
586*44704f69SBart Van Assche {"ident", SCSI_IPORT_ETC, 1, 7, 1, "flash LED"},
587*44704f69SBart Van Assche {"ident", SCSI_PORT_TRAN_ETC, 1, 7, 1, "flash LED"},
588*44704f69SBart Van Assche {"ident", SCSI_TPORT_ETC, 1, 7, 1, "flash LED"},
589*44704f69SBart Van Assche {"ident", SIMPLE_SUBENC_ETC, 1, 7, 1, "flash LED"},
590*44704f69SBart Van Assche {"ident", TEMPERATURE_ETC, 1, 7, 1, "flash LED"},
591*44704f69SBart Van Assche {"ident", UI_POWER_SUPPLY_ETC, 3, 7, 1, "flash LED"},
592*44704f69SBart Van Assche {"ident", VOLT_SENSOR_ETC, 1, 7, 1, "flash LED"},
593*44704f69SBart Van Assche {"incritarray", ARRAY_DEV_ETC, 1, 3, 1, NULL},
594*44704f69SBart Van Assche {"infailedarray", ARRAY_DEV_ETC, 1, 2, 1, NULL},
595*44704f69SBart Van Assche {"info", AUD_ALARM_ETC, 3, 3, 1, "emits warning tone when set"},
596*44704f69SBart Van Assche {"insert", DEVICE_ETC, 2, 3, 1, NULL},
597*44704f69SBart Van Assche {"insert", ARRAY_DEV_ETC, 2, 3, 1, NULL},
598*44704f69SBart Van Assche {"intf_fail", UI_POWER_SUPPLY_ETC, 2, 0, 1, NULL},
599*44704f69SBart Van Assche {"language", LANGUAGE_ETC, 2, 7, 16, "language code"},
600*44704f69SBart Van Assche {"locate", DEVICE_ETC, 2, 1, 1, "flash LED"},
601*44704f69SBart Van Assche {"locate", ARRAY_DEV_ETC, 2, 1, 1, "flash LED"},
602*44704f69SBart Van Assche {"locate", POWER_SUPPLY_ETC, 1, 7, 1, "flash LED"},
603*44704f69SBart Van Assche {"locate", COMM_PORT_ETC, 1, 7, 1, "flash LED"},
604*44704f69SBart Van Assche {"locate", COOLING_ETC, 1, 7, 1, "flash LED"},
605*44704f69SBart Van Assche {"locate", CURR_SENSOR_ETC, 1, 7, 1, "flash LED"},
606*44704f69SBart Van Assche {"locate", DISPLAY_ETC, 1, 7, 1, "flash LED"},
607*44704f69SBart Van Assche {"locate", DOOR_ETC, 1, 7, 1, "flash LED"},
608*44704f69SBart Van Assche {"locate", ENC_SCELECTR_ETC, 1, 7, 1, "flash LED"},
609*44704f69SBart Van Assche {"locate", ENCLOSURE_ETC, 1, 7, 1, "flash LED"},
610*44704f69SBart Van Assche {"locate", KEY_PAD_ETC, 1, 7, 1, "flash LED"},
611*44704f69SBart Van Assche {"locate", LANGUAGE_ETC, 1, 7, 1, "flash LED"},
612*44704f69SBart Van Assche {"locate", AUD_ALARM_ETC, 1, 7, 1, NULL},
613*44704f69SBart Van Assche {"locate", NV_CACHE_ETC, 1, 7, 1, "flash LED"},
614*44704f69SBart Van Assche {"locate", SAS_CONNECTOR_ETC, 1, 7, 1, "flash LED"},
615*44704f69SBart Van Assche {"locate", SAS_EXPANDER_ETC, 1, 7, 1, "flash LED"},
616*44704f69SBart Van Assche {"locate", SCC_CELECTR_ETC, 1, 7, 1, "flash LED"},
617*44704f69SBart Van Assche {"locate", SCSI_IPORT_ETC, 1, 7, 1, "flash LED"},
618*44704f69SBart Van Assche {"locate", SCSI_PORT_TRAN_ETC, 1, 7, 1, "flash LED"},
619*44704f69SBart Van Assche {"locate", SCSI_TPORT_ETC, 1, 7, 1, "flash LED"},
620*44704f69SBart Van Assche {"locate", SIMPLE_SUBENC_ETC, 1, 7, 1, "flash LED"},
621*44704f69SBart Van Assche {"locate", TEMPERATURE_ETC, 1, 7, 1, "flash LED"},
622*44704f69SBart Van Assche {"locate", UI_POWER_SUPPLY_ETC, 3, 7, 1, "flash LED"},
623*44704f69SBart Van Assche {"locate", VOLT_SENSOR_ETC, 1, 7, 1, "flash LED"},
624*44704f69SBart Van Assche {"lol", SCSI_PORT_TRAN_ETC, 3, 1, 1, "Loss of Link"},
625*44704f69SBart Van Assche {"mated", SAS_CONNECTOR_ETC, 3, 7, 1, NULL},
626*44704f69SBart Van Assche {"missing", DEVICE_ETC, 2, 4, 1, NULL},
627*44704f69SBart Van Assche {"missing", ARRAY_DEV_ETC, 2, 4, 1, NULL},
628*44704f69SBart Van Assche {"mute", AUD_ALARM_ETC, 3, 6, 1, "control only: mute the alarm"},
629*44704f69SBart Van Assche {"muted", AUD_ALARM_ETC, 3, 6, 1, "status only: alarm is muted"},
630*44704f69SBart Van Assche {"off", POWER_SUPPLY_ETC, 3, 4, 1, "Not providing power"},
631*44704f69SBart Van Assche {"off", COOLING_ETC, 3, 4, 1, "Not providing cooling"},
632*44704f69SBart Van Assche {"offset_temp", TEMPERATURE_ETC, 1, 5, 6, "Offset for reference "
633*44704f69SBart Van Assche "temperature"},
634*44704f69SBart Van Assche {"ok", ARRAY_DEV_ETC, 1, 7, 1, NULL},
635*44704f69SBart Van Assche {"on", COOLING_ETC, 3, 5, 1, NULL},
636*44704f69SBart Van Assche {"on", POWER_SUPPLY_ETC, 3, 5, 1, "0: turn (remain) off; 1: turn on"},
637*44704f69SBart Van Assche {"open", DOOR_ETC, 3, 1, 1, NULL},
638*44704f69SBart Van Assche {"overcurrent", CURR_SENSOR_ETC, 1, 1, 1, "overcurrent"},
639*44704f69SBart Van Assche {"overcurrent", POWER_SUPPLY_ETC, 2, 1, 1, "DC overcurrent"},
640*44704f69SBart Van Assche {"overcurrent", SAS_CONNECTOR_ETC, 3, 5, 1, NULL}, /* added ses3r07 */
641*44704f69SBart Van Assche {"overcurrent_warn", CURR_SENSOR_ETC, 1, 3, 1, "overcurrent warning"},
642*44704f69SBart Van Assche {"overtemp_fail", TEMPERATURE_ETC, 3, 3, 1, "Overtemperature failure"},
643*44704f69SBart Van Assche {"overtemp_warn", TEMPERATURE_ETC, 3, 2, 1, "Overtemperature warning"},
644*44704f69SBart Van Assche {"overvoltage", POWER_SUPPLY_ETC, 2, 3, 1, "DC overvoltage"},
645*44704f69SBart Van Assche {"overvoltage", VOLT_SENSOR_ETC, 1, 1, 1, "overvoltage"},
646*44704f69SBart Van Assche {"overvoltage_warn", POWER_SUPPLY_ETC, 1, 3, 1, "DC overvoltage warning"},
647*44704f69SBart Van Assche {"pow_cycle", ENCLOSURE_ETC, 2, 7, 2,
648*44704f69SBart Van Assche "0: no; 1: start in pow_c_delay minutes; 2: cancel"},
649*44704f69SBart Van Assche {"pow_c_delay", ENCLOSURE_ETC, 2, 5, 6,
650*44704f69SBart Van Assche "delay in minutes before starting power cycle (max: 60)"},
651*44704f69SBart Van Assche {"pow_c_duration", ENCLOSURE_ETC, 3, 7, 6,
652*44704f69SBart Van Assche "0: power off, restore within 1 minute; <=60: restore within that many "
653*44704f69SBart Van Assche "minutes; 63: power off, wait for manual power on"},
654*44704f69SBart Van Assche /* slightly different in Enclosure status element */
655*44704f69SBart Van Assche {"pow_c_time", ENCLOSURE_ETC, 2, 7, 6,
656*44704f69SBart Van Assche "time in minutes remaining until starting power cycle; 0: not "
657*44704f69SBart Van Assche "scheduled; <=60: scheduled in that many minutes; 63: in zero minutes"},
658*44704f69SBart Van Assche {"prdfail", -1, 0, 6, 1, "predict failure"},
659*44704f69SBart Van Assche {"rebuildremap", ARRAY_DEV_ETC, 1, 1, 1, NULL},
660*44704f69SBart Van Assche {"remove", DEVICE_ETC, 2, 2, 1, NULL},
661*44704f69SBart Van Assche {"remove", ARRAY_DEV_ETC, 2, 2, 1, NULL},
662*44704f69SBart Van Assche {"remind", AUD_ALARM_ETC, 3, 4, 1, NULL},
663*44704f69SBart Van Assche {"report", ENC_SCELECTR_ETC, 2, 0, 1, NULL}, /* status only */
664*44704f69SBart Van Assche {"report", SCC_CELECTR_ETC, 2, 0, 1, NULL},
665*44704f69SBart Van Assche {"report", SCSI_IPORT_ETC, 2, 0, 1, NULL},
666*44704f69SBart Van Assche {"report", SCSI_TPORT_ETC, 2, 0, 1, NULL},
667*44704f69SBart Van Assche {"rqst_mute", AUD_ALARM_ETC, 3, 7, 1,
668*44704f69SBart Van Assche "status only: alarm was manually muted"},
669*44704f69SBart Van Assche {"rqst_override", TEMPERATURE_ETC, 3, 7, 1, "Request(ed) override"},
670*44704f69SBart Van Assche {"rrabort", ARRAY_DEV_ETC, 1, 0, 1, "rebuild/remap abort"},
671*44704f69SBart Van Assche {"rsvddevice", ARRAY_DEV_ETC, 1, 6, 1, "reserved device"},
672*44704f69SBart Van Assche {"select_element", ENC_SCELECTR_ETC, 2, 0, 1, NULL}, /* control */
673*44704f69SBart Van Assche {"short_stat", SIMPLE_SUBENC_ETC, 3, 7, 8, "short enclosure status"},
674*44704f69SBart Van Assche {"size", NV_CACHE_ETC, 2, 7, 16, NULL},
675*44704f69SBart Van Assche {"speed_act", COOLING_ETC, 1, 2, 11, "actual speed (rpm / 10)"},
676*44704f69SBart Van Assche {"speed_code", COOLING_ETC, 3, 2, 3,
677*44704f69SBart Van Assche "0: leave; 1: lowest... 7: highest"},
678*44704f69SBart Van Assche {"size_mult", NV_CACHE_ETC, 1, 1, 2, NULL},
679*44704f69SBart Van Assche {"swap", -1, 0, 4, 1, NULL}, /* Reset swap */
680*44704f69SBart Van Assche {"sw_reset", ENC_SCELECTR_ETC, 1, 3, 1, "software reset"},/* 18-047r1 */
681*44704f69SBart Van Assche {"temp", TEMPERATURE_ETC, 2, 7, 8, "(Requested) temperature"},
682*44704f69SBart Van Assche {"unlock", DOOR_ETC, 3, 0, 1, NULL},
683*44704f69SBart Van Assche {"undertemp_fail", TEMPERATURE_ETC, 3, 1, 1, "Undertemperature failure"},
684*44704f69SBart Van Assche {"undertemp_warn", TEMPERATURE_ETC, 3, 0, 1, "Undertemperature warning"},
685*44704f69SBart Van Assche {"undervoltage", POWER_SUPPLY_ETC, 2, 2, 1, "DC undervoltage"},
686*44704f69SBart Van Assche {"undervoltage", VOLT_SENSOR_ETC, 1, 0, 1, "undervoltage"},
687*44704f69SBart Van Assche {"undervoltage_warn", POWER_SUPPLY_ETC, 1, 2, 1,
688*44704f69SBart Van Assche "DC undervoltage warning"},
689*44704f69SBart Van Assche {"ups_fail", UI_POWER_SUPPLY_ETC, 2, 2, 1, NULL},
690*44704f69SBart Van Assche {"urgency", AUD_ALARM_ETC, 3, 3, 4, NULL}, /* Tone urgency control bits */
691*44704f69SBart Van Assche {"voltage", VOLT_SENSOR_ETC, 2, 7, 16, "voltage in centivolts"},
692*44704f69SBart Van Assche {"warning", UI_POWER_SUPPLY_ETC, 2, 1, 1, NULL},
693*44704f69SBart Van Assche {"warning", ENCLOSURE_ETC, 3, 0, 1, NULL},
694*44704f69SBart Van Assche {"warning_ind", ENCLOSURE_ETC, 2, 0, 1, NULL},
695*44704f69SBart Van Assche {"xmit_fail", SCSI_PORT_TRAN_ETC, 3, 0, 1, "Transmitter failure"},
696*44704f69SBart Van Assche {NULL, 0, 0, 0, 0, NULL},
697*44704f69SBart Van Assche };
698*44704f69SBart Van Assche
699*44704f69SBart Van Assche /* These are for the Threshold in/out diagnostic page */
700*44704f69SBart Van Assche static struct acronym2tuple th_a2t_arr[] = {
701*44704f69SBart Van Assche {"high_crit", -1, 0, 7, 8, NULL},
702*44704f69SBart Van Assche {"high_warn", -1, 1, 7, 8, NULL},
703*44704f69SBart Van Assche {"low_crit", -1, 2, 7, 8, NULL},
704*44704f69SBart Van Assche {"low_warn", -1, 3, 7, 8, NULL},
705*44704f69SBart Van Assche {NULL, 0, 0, 0, 0, NULL},
706*44704f69SBart Van Assche };
707*44704f69SBart Van Assche
708*44704f69SBart Van Assche /* These are for the Additional element status diagnostic page for SAS with
709*44704f69SBart Van Assche * the EIP bit set. First phy only. Index from start of AES descriptor */
710*44704f69SBart Van Assche static struct acronym2tuple ae_sas_a2t_arr[] = {
711*44704f69SBart Van Assche {"at_sas_addr", -1, 12, 7, 64, NULL}, /* best viewed with --hex --get= */
712*44704f69SBart Van Assche /* typically this is the expander's SAS address */
713*44704f69SBart Van Assche {"dev_type", -1, 8, 6, 3, "1: SAS/SATA dev, 2: expander"},
714*44704f69SBart Van Assche {"dsn", -1, 7, 7, 8, "device slot number (255: none)"},
715*44704f69SBart Van Assche {"num_phys", -1, 4, 7, 8, "number of phys"},
716*44704f69SBart Van Assche {"phy_id", -1, 28, 7, 8, NULL},
717*44704f69SBart Van Assche {"sas_addr", -1, 20, 7, 64, NULL}, /* should be disk or tape ... */
718*44704f69SBart Van Assche {"exp_sas_addr", -1, 8, 7, 64, NULL}, /* expander address */
719*44704f69SBart Van Assche {"sata_dev", -1, 11, 0, 1, NULL},
720*44704f69SBart Van Assche {"sata_port_sel", -1, 11, 7, 1, NULL},
721*44704f69SBart Van Assche {"smp_init", -1, 10, 1, 1, NULL},
722*44704f69SBart Van Assche {"smp_targ", -1, 11, 1, 1, NULL},
723*44704f69SBart Van Assche {"ssp_init", -1, 10, 3, 1, NULL},
724*44704f69SBart Van Assche {"ssp_targ", -1, 11, 3, 1, NULL},
725*44704f69SBart Van Assche {"stp_init", -1, 10, 2, 1, NULL},
726*44704f69SBart Van Assche {"stp_targ", -1, 11, 2, 1, NULL},
727*44704f69SBart Van Assche {NULL, 0, 0, 0, 0, NULL},
728*44704f69SBart Van Assche };
729*44704f69SBart Van Assche
730*44704f69SBart Van Assche /* Boolean array of element types of interest to the Additional Element
731*44704f69SBart Van Assche * Status page. Indexed by element type (0 <= et < 32). */
732*44704f69SBart Van Assche static bool active_et_aesp_arr[NUM_ACTIVE_ET_AESP_ARR] = {
733*44704f69SBart Van Assche false, true /* dev */, false, false,
734*44704f69SBart Van Assche false, false, false, true /* esce */,
735*44704f69SBart Van Assche false, false, false, false,
736*44704f69SBart Van Assche false, false, false, false,
737*44704f69SBart Van Assche false, false, false, false,
738*44704f69SBart Van Assche true /* starg */, true /* sinit */, false, true /* arr */,
739*44704f69SBart Van Assche true /* sas exp */, false, false, false,
740*44704f69SBart Van Assche false, false, false, false,
741*44704f69SBart Van Assche };
742*44704f69SBart Van Assche
743*44704f69SBart Van Assche /* Command line long option names with corresponding short letter. */
744*44704f69SBart Van Assche static struct option long_options[] = {
745*44704f69SBart Van Assche {"all", no_argument, 0, 'a'},
746*44704f69SBart Van Assche {"ALL", no_argument, 0, 'z'},
747*44704f69SBart Van Assche {"byte1", required_argument, 0, 'b'},
748*44704f69SBart Van Assche {"clear", required_argument, 0, 'C'},
749*44704f69SBart Van Assche {"control", no_argument, 0, 'c'},
750*44704f69SBart Van Assche {"data", required_argument, 0, 'd'},
751*44704f69SBart Van Assche {"descriptor", required_argument, 0, 'D'},
752*44704f69SBart Van Assche {"dev-slot-num", required_argument, 0, 'x'},
753*44704f69SBart Van Assche {"dev_slot_num", required_argument, 0, 'x'},
754*44704f69SBart Van Assche {"dsn", required_argument, 0, 'x'},
755*44704f69SBart Van Assche {"eiioe", required_argument, 0, 'E'},
756*44704f69SBart Van Assche {"enumerate", no_argument, 0, 'e'},
757*44704f69SBart Van Assche {"filter", no_argument, 0, 'f'},
758*44704f69SBart Van Assche {"get", required_argument, 0, 'G'},
759*44704f69SBart Van Assche {"help", no_argument, 0, 'h'},
760*44704f69SBart Van Assche {"hex", no_argument, 0, 'H'},
761*44704f69SBart Van Assche {"index", required_argument, 0, 'I'},
762*44704f69SBart Van Assche {"inhex", required_argument, 0, 'X'},
763*44704f69SBart Van Assche {"inner-hex", no_argument, 0, 'i'},
764*44704f69SBart Van Assche {"inner_hex", no_argument, 0, 'i'},
765*44704f69SBart Van Assche {"join", no_argument, 0, 'j'},
766*44704f69SBart Van Assche {"list", no_argument, 0, 'l'},
767*44704f69SBart Van Assche {"nickid", required_argument, 0, 'N'},
768*44704f69SBart Van Assche {"nickname", required_argument, 0, 'n'},
769*44704f69SBart Van Assche {"mask", required_argument, 0, 'M'},
770*44704f69SBart Van Assche {"maxlen", required_argument, 0, 'm'},
771*44704f69SBart Van Assche {"page", required_argument, 0, 'p'},
772*44704f69SBart Van Assche {"quiet", no_argument, 0, 'q'},
773*44704f69SBart Van Assche {"raw", no_argument, 0, 'r'},
774*44704f69SBart Van Assche {"readonly", no_argument, 0, 'R'},
775*44704f69SBart Van Assche {"sas-addr", required_argument, 0, 'A'},
776*44704f69SBart Van Assche {"sas_addr", required_argument, 0, 'A'},
777*44704f69SBart Van Assche {"set", required_argument, 0, 'S'},
778*44704f69SBart Van Assche {"status", no_argument, 0, 's'},
779*44704f69SBart Van Assche {"verbose", no_argument, 0, 'v'},
780*44704f69SBart Van Assche {"version", no_argument, 0, 'V'},
781*44704f69SBart Van Assche {"warn", no_argument, 0, 'w'},
782*44704f69SBart Van Assche {0, 0, 0, 0},
783*44704f69SBart Van Assche };
784*44704f69SBart Van Assche
785*44704f69SBart Van Assche /* For overzealous SES device servers that don't like some status elements
786*44704f69SBart Van Assche * sent back as control elements. This table is as per ses3r06. */
787*44704f69SBart Van Assche static uint8_t ses3_element_cmask_arr[NUM_ETC][4] = {
788*44704f69SBart Van Assche /* Element type code (ETC) names; comment */
789*44704f69SBart Van Assche {0x40, 0xff, 0xff, 0xff}, /* [0] unspecified */
790*44704f69SBart Van Assche {0x40, 0, 0x4e, 0x3c}, /* DEVICE */
791*44704f69SBart Van Assche {0x40, 0x80, 0, 0x60}, /* POWER_SUPPLY */
792*44704f69SBart Van Assche {0x40, 0x80, 0, 0x60}, /* COOLING; requested speed as is unless */
793*44704f69SBart Van Assche {0x40, 0xc0, 0, 0}, /* TEMPERATURE */
794*44704f69SBart Van Assche {0x40, 0xc0, 0, 0x1}, /* DOOR */
795*44704f69SBart Van Assche {0x40, 0xc0, 0, 0x5f}, /* AUD_ALARM */
796*44704f69SBart Van Assche {0x40, 0xc0, 0x1, 0}, /* ENC_SCELECTR_ETC */
797*44704f69SBart Van Assche {0x40, 0xc0, 0, 0}, /* SCC_CELECTR */
798*44704f69SBart Van Assche {0x40, 0xc0, 0, 0}, /* NV_CACHE */
799*44704f69SBart Van Assche {0x40, 0, 0, 0}, /* [10] INV_OP_REASON */
800*44704f69SBart Van Assche {0x40, 0, 0, 0xc0}, /* UI_POWER_SUPPLY */
801*44704f69SBart Van Assche {0x40, 0xc0, 0xff, 0xff}, /* DISPLAY */
802*44704f69SBart Van Assche {0x40, 0xc3, 0, 0}, /* KEY_PAD */
803*44704f69SBart Van Assche {0x40, 0x80, 0, 0xff}, /* ENCLOSURE */
804*44704f69SBart Van Assche {0x40, 0xc0, 0, 0x10}, /* SCSI_PORT_TRAN */
805*44704f69SBart Van Assche {0x40, 0x80, 0xff, 0xff}, /* LANGUAGE */
806*44704f69SBart Van Assche {0x40, 0xc0, 0, 0x1}, /* COMM_PORT */
807*44704f69SBart Van Assche {0x40, 0xc0, 0, 0}, /* VOLT_SENSOR */
808*44704f69SBart Van Assche {0x40, 0xc0, 0, 0}, /* CURR_SENSOR */
809*44704f69SBart Van Assche {0x40, 0xc0, 0, 0x1}, /* [20] SCSI_TPORT */
810*44704f69SBart Van Assche {0x40, 0xc0, 0, 0x1}, /* SCSI_IPORT */
811*44704f69SBart Van Assche {0x40, 0xc0, 0, 0}, /* SIMPLE_SUBENC */
812*44704f69SBart Van Assche {0x40, 0xff, 0x4e, 0x3c}, /* ARRAY */
813*44704f69SBart Van Assche {0x40, 0xc0, 0, 0}, /* SAS_EXPANDER */
814*44704f69SBart Van Assche {0x40, 0x80, 0, 0x40}, /* SAS_CONNECTOR */
815*44704f69SBart Van Assche };
816*44704f69SBart Van Assche
817*44704f69SBart Van Assche
818*44704f69SBart Van Assche static int read_hex(const char * inp, uint8_t * arr, int mx_arr_len,
819*44704f69SBart Van Assche int * arr_len, bool in_hex, bool may_gave_at, int verb);
820*44704f69SBart Van Assche static int strcase_eq(const char * s1p, const char * s2p);
821*44704f69SBart Van Assche static void enumerate_diag_pages(void);
822*44704f69SBart Van Assche static bool saddr_non_zero(const uint8_t * bp);
823*44704f69SBart Van Assche static const char * find_in_diag_page_desc(int page_num);
824*44704f69SBart Van Assche
825*44704f69SBart Van Assche
826*44704f69SBart Van Assche static void
usage(int help_num)827*44704f69SBart Van Assche usage(int help_num)
828*44704f69SBart Van Assche {
829*44704f69SBart Van Assche if (2 != help_num) {
830*44704f69SBart Van Assche pr2serr(
831*44704f69SBart Van Assche "Usage: sg_ses [--all] [--ALL] [--descriptor=DES] "
832*44704f69SBart Van Assche "[--dev-slot-num=SN]\n"
833*44704f69SBart Van Assche " [--eiioe=A_F] [--filter] [--get=STR] "
834*44704f69SBart Van Assche "[--hex]\n"
835*44704f69SBart Van Assche " [--index=IIA | =TIA,II] [--inner-hex] [--join] "
836*44704f69SBart Van Assche "[--maxlen=LEN]\n"
837*44704f69SBart Van Assche " [--page=PG] [--quiet] [--raw] [--readonly] "
838*44704f69SBart Van Assche "[--sas-addr=SA]\n"
839*44704f69SBart Van Assche " [--status] [--verbose] [--warn] DEVICE\n\n"
840*44704f69SBart Van Assche " sg_ses --control [--byte1=B1] [--clear=STR] "
841*44704f69SBart Van Assche "[--data=H,H...]\n"
842*44704f69SBart Van Assche " [--descriptor=DES] [--dev-slot-num=SN] "
843*44704f69SBart Van Assche "[--index=IIA | =TIA,II]\n"
844*44704f69SBart Van Assche " [--inhex=FN] [--mask] [--maxlen=LEN] "
845*44704f69SBart Van Assche "[--nickid=SEID]\n"
846*44704f69SBart Van Assche " [--nickname=SEN] [--page=PG] [--sas-addr=SA] "
847*44704f69SBart Van Assche "[--set=STR]\n"
848*44704f69SBart Van Assche " [--verbose] DEVICE\n\n"
849*44704f69SBart Van Assche " sg_ses --data=@FN --status [-rr] [<most options from "
850*44704f69SBart Van Assche "first form>]\n"
851*44704f69SBart Van Assche " sg_ses --inhex=FN --status [-rr] [<most options from "
852*44704f69SBart Van Assche "first form>]\n\n"
853*44704f69SBart Van Assche " sg_ses [--enumerate] [--help] [--index=IIA] [--list] "
854*44704f69SBart Van Assche "[--version]\n\n"
855*44704f69SBart Van Assche );
856*44704f69SBart Van Assche if ((help_num < 1) || (help_num > 2)) {
857*44704f69SBart Van Assche pr2serr("Or the corresponding short option usage: \n"
858*44704f69SBart Van Assche " sg_ses [-a] [-D DES] [-x SN] [-E A_F] [-f] [-G STR] "
859*44704f69SBart Van Assche "[-H] [-I IIA|TIA,II]\n"
860*44704f69SBart Van Assche " [-i] [-j] [-m LEN] [-p PG] [-q] [-r] [-R] "
861*44704f69SBart Van Assche "[-A SA] [-s] [-v] [-w]\n"
862*44704f69SBart Van Assche " DEVICE\n\n"
863*44704f69SBart Van Assche " sg_ses [-b B1] [-C STR] [-c] [-d H,H...] [-D DES] "
864*44704f69SBart Van Assche "[-x SN] [-I IIA|TIA,II]\n"
865*44704f69SBart Van Assche " [-M] [-m LEN] [-N SEID] [-n SEN] [-p PG] "
866*44704f69SBart Van Assche "[-A SA] [-S STR]\n"
867*44704f69SBart Van Assche " [-v] DEVICE\n\n"
868*44704f69SBart Van Assche " sg_ses -d @FN -s [-rr] [<most options from first "
869*44704f69SBart Van Assche "form>]\n"
870*44704f69SBart Van Assche " sg_ses -X FN -s [-rr] [<most options from first "
871*44704f69SBart Van Assche "form>]\n\n"
872*44704f69SBart Van Assche " sg_ses [-e] [-h] [-I IIA] [-l] [-V]\n"
873*44704f69SBart Van Assche );
874*44704f69SBart Van Assche pr2serr("\nFor help use '-h' one or more times.\n");
875*44704f69SBart Van Assche return;
876*44704f69SBart Van Assche }
877*44704f69SBart Van Assche pr2serr(
878*44704f69SBart Van Assche " where the main options are:\n"
879*44704f69SBart Van Assche " --all|-a show (almost) all status pages (same "
880*44704f69SBart Van Assche "as --join)\n"
881*44704f69SBart Van Assche " --clear=STR|-C STR clear field by acronym or position\n"
882*44704f69SBart Van Assche " --control|-c send control information (def: fetch "
883*44704f69SBart Van Assche "status)\n"
884*44704f69SBart Van Assche " --descriptor=DES|-D DES descriptor name (for indexing)\n"
885*44704f69SBart Van Assche " --dev-slot-num=SN|--dsn=SN|-x SN device slot number "
886*44704f69SBart Van Assche "(for indexing)\n"
887*44704f69SBart Van Assche " --filter|-f filter out enclosure status flags that "
888*44704f69SBart Van Assche "are clear\n"
889*44704f69SBart Van Assche " use twice for status=okay entries "
890*44704f69SBart Van Assche "only\n"
891*44704f69SBart Van Assche " --get=STR|-G STR get value of field by acronym or "
892*44704f69SBart Van Assche "position\n"
893*44704f69SBart Van Assche " --help|-h print out usage message, use twice for "
894*44704f69SBart Van Assche "additional\n"
895*44704f69SBart Van Assche " --index=IIA|-I IIA individual index ('-1' for overall) "
896*44704f69SBart Van Assche "or element\n"
897*44704f69SBart Van Assche " type abbreviation (e.g. 'arr'). A "
898*44704f69SBart Van Assche "range may be\n"
899*44704f69SBart Van Assche " given for the individual index "
900*44704f69SBart Van Assche "(e.g. '2-5')\n"
901*44704f69SBart Van Assche " --index=TIA,II|-I TIA,II comma separated pair: TIA is "
902*44704f69SBart Van Assche "type header\n"
903*44704f69SBart Van Assche " index or element type "
904*44704f69SBart Van Assche "abbreviation;\n"
905*44704f69SBart Van Assche " II is individual index ('-1' "
906*44704f69SBart Van Assche "for overall)\n"
907*44704f69SBart Van Assche );
908*44704f69SBart Van Assche pr2serr(
909*44704f69SBart Van Assche " --join|-j group Enclosure Status, Element "
910*44704f69SBart Van Assche "Descriptor\n"
911*44704f69SBart Van Assche " and Additional Element Status pages. "
912*44704f69SBart Van Assche "Use twice\n"
913*44704f69SBart Van Assche " to add Threshold In page\n"
914*44704f69SBart Van Assche " --page=PG|-p PG diagnostic page code (abbreviation "
915*44704f69SBart Van Assche "or number)\n"
916*44704f69SBart Van Assche " (def: 'ssp' [0x0] (supported diagnostic "
917*44704f69SBart Van Assche "pages))\n"
918*44704f69SBart Van Assche " --sas-addr=SA|-A SA SAS address in hex (for indexing)\n"
919*44704f69SBart Van Assche " --set=STR|-S STR set value of field by acronym or "
920*44704f69SBart Van Assche "position\n"
921*44704f69SBart Van Assche " --status|-s fetch status information (default "
922*44704f69SBart Van Assche "action)\n\n"
923*44704f69SBart Van Assche "First usage above is for fetching pages or fields from a SCSI "
924*44704f69SBart Van Assche "enclosure.\nThe second usage is for changing a page or field in "
925*44704f69SBart Van Assche "an enclosure. The\n'--clear=', '--get=' and '--set=' options "
926*44704f69SBart Van Assche "can appear multiple times.\nUse '-hh' for more help, including "
927*44704f69SBart Van Assche "the options not explained above.\n");
928*44704f69SBart Van Assche } else { /* for '-hh' or '--help --help' */
929*44704f69SBart Van Assche pr2serr(
930*44704f69SBart Van Assche " where the remaining sg_ses options are:\n"
931*44704f69SBart Van Assche " --ALL|-z same as --all twice (adds thresholds)\n"
932*44704f69SBart Van Assche " --byte1=B1|-b B1 byte 1 (2nd byte) of control page set "
933*44704f69SBart Van Assche "to B1\n"
934*44704f69SBart Van Assche " --data=H,H...|-d H,H... string of ASCII hex bytes to "
935*44704f69SBart Van Assche "send as a\n"
936*44704f69SBart Van Assche " control page or decode as a "
937*44704f69SBart Van Assche "status page\n"
938*44704f69SBart Van Assche " --data=- | -d - fetch string of ASCII hex bytes from "
939*44704f69SBart Van Assche "stdin\n"
940*44704f69SBart Van Assche " --data=@FN | -d @FN fetch string of ASCII hex bytes from "
941*44704f69SBart Van Assche "file: FN\n"
942*44704f69SBart Van Assche " --eiioe=A_F|-E A_F A_F is either 'auto' or 'force'. "
943*44704f69SBart Van Assche "'force' acts\n"
944*44704f69SBart Van Assche " as if EIIOE field is 1, 'auto' tries "
945*44704f69SBart Van Assche "to guess\n"
946*44704f69SBart Van Assche " --enumerate|-e enumerate page names + element types "
947*44704f69SBart Van Assche "(ignore\n"
948*44704f69SBart Van Assche " DEVICE). Use twice for clear,get,set "
949*44704f69SBart Van Assche "acronyms\n"
950*44704f69SBart Van Assche " --hex|-H print page response (or field) in hex\n"
951*44704f69SBart Van Assche " --inhex=FN|-X FN alternate form of --data=@FN\n"
952*44704f69SBart Van Assche " --inner-hex|-i print innermost level of a"
953*44704f69SBart Van Assche " status page in hex\n"
954*44704f69SBart Van Assche " --list|-l same as '--enumerate' option\n"
955*44704f69SBart Van Assche " --mask|-M ignore status element mask in modify "
956*44704f69SBart Van Assche "actions\n"
957*44704f69SBart Van Assche " (e.g.--set= and --clear=) (def: apply "
958*44704f69SBart Van Assche "mask)\n"
959*44704f69SBart Van Assche " --maxlen=LEN|-m LEN max response length (allocation "
960*44704f69SBart Van Assche "length in cdb)\n"
961*44704f69SBart Van Assche " --nickid=SEID|-N SEID SEID is subenclosure identifier "
962*44704f69SBart Van Assche "(def: 0)\n"
963*44704f69SBart Van Assche " used to specify which nickname to "
964*44704f69SBart Van Assche "change\n"
965*44704f69SBart Van Assche " --nickname=SEN|-n SEN SEN is new subenclosure nickname\n"
966*44704f69SBart Van Assche " --quiet|-q suppress some output messages\n"
967*44704f69SBart Van Assche " --raw|-r print status page in ASCII hex suitable "
968*44704f69SBart Van Assche "for '-d';\n"
969*44704f69SBart Van Assche " when used twice outputs page in binary "
970*44704f69SBart Van Assche "to stdout\n"
971*44704f69SBart Van Assche " --readonly|-R open DEVICE read-only (def: "
972*44704f69SBart Van Assche "read-write)\n"
973*44704f69SBart Van Assche " --verbose|-v increase verbosity\n"
974*44704f69SBart Van Assche " --version|-V print version string and exit\n"
975*44704f69SBart Van Assche " --warn|-w warn about join (and other) issues\n\n"
976*44704f69SBart Van Assche "If no options are given then DEVICE's supported diagnostic "
977*44704f69SBart Van Assche "pages are\nlisted. STR can be '<start_byte>:<start_bit>"
978*44704f69SBart Van Assche "[:<num_bits>][=<val>]'\nor '<acronym>[=val]'. Element type "
979*44704f69SBart Van Assche "abbreviations may be followed by a\nnumber (e.g. 'ps1' is "
980*44704f69SBart Van Assche "the second power supply element type). Use\n'sg_ses -e' and "
981*44704f69SBart Van Assche "'sg_ses -ee' for more information.\n\n"
982*44704f69SBart Van Assche );
983*44704f69SBart Van Assche pr2serr(
984*44704f69SBart Van Assche "Low level indexing can be done with one of the two '--index=' "
985*44704f69SBart Van Assche "options.\nAlternatively, medium level indexing can be done "
986*44704f69SBart Van Assche "with either the\n'--descriptor=', 'dev-slot-num=' or "
987*44704f69SBart Van Assche "'--sas-addr=' options. Support for\nthe medium level options "
988*44704f69SBart Van Assche "in the SES device is itself optional.\n"
989*44704f69SBart Van Assche );
990*44704f69SBart Van Assche }
991*44704f69SBart Van Assche }
992*44704f69SBart Van Assche
993*44704f69SBart Van Assche /* Return 0 for okay, else an error */
994*44704f69SBart Van Assche static int
parse_index(struct opts_t * op)995*44704f69SBart Van Assche parse_index(struct opts_t *op)
996*44704f69SBart Van Assche {
997*44704f69SBart Van Assche int n, n2;
998*44704f69SBart Van Assche const char * cp;
999*44704f69SBart Van Assche char * mallcp;
1000*44704f69SBart Van Assche char * c2p;
1001*44704f69SBart Van Assche const struct element_type_t * etp;
1002*44704f69SBart Van Assche char b[64];
1003*44704f69SBart Van Assche const int blen = sizeof(b);
1004*44704f69SBart Van Assche
1005*44704f69SBart Van Assche op->ind_given = true;
1006*44704f69SBart Van Assche n2 = 0;
1007*44704f69SBart Van Assche if ((cp = strchr(op->index_str, ','))) {
1008*44704f69SBart Van Assche /* decode number following comma */
1009*44704f69SBart Van Assche if (0 == strcmp("-1", cp + 1))
1010*44704f69SBart Van Assche n = -1;
1011*44704f69SBart Van Assche else {
1012*44704f69SBart Van Assche const char * cc3p;
1013*44704f69SBart Van Assche
1014*44704f69SBart Van Assche n = sg_get_num_nomult(cp + 1);
1015*44704f69SBart Van Assche if ((n < 0) || (n > 255)) {
1016*44704f69SBart Van Assche pr2serr("bad argument to '--index=', after comma expect "
1017*44704f69SBart Van Assche "number from -1 to 255\n");
1018*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1019*44704f69SBart Van Assche }
1020*44704f69SBart Van Assche if ((cc3p = strchr(cp + 1, '-'))) {
1021*44704f69SBart Van Assche n2 = sg_get_num_nomult(cc3p + 1);
1022*44704f69SBart Van Assche if ((n2 < n) || (n2 > 255)) {
1023*44704f69SBart Van Assche pr2serr("bad argument to '--index', after '-' expect "
1024*44704f69SBart Van Assche "number from -%d to 255\n", n);
1025*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1026*44704f69SBart Van Assche }
1027*44704f69SBart Van Assche }
1028*44704f69SBart Van Assche }
1029*44704f69SBart Van Assche op->ind_indiv = n;
1030*44704f69SBart Van Assche if (n2 > 0)
1031*44704f69SBart Van Assche op->ind_indiv_last = n2;
1032*44704f69SBart Van Assche n = cp - op->index_str;
1033*44704f69SBart Van Assche if (n >= (blen - 1)) {
1034*44704f69SBart Van Assche pr2serr("bad argument to '--index', string prior to comma too "
1035*44704f69SBart Van Assche "long\n");
1036*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1037*44704f69SBart Van Assche }
1038*44704f69SBart Van Assche } else { /* no comma found in index_str */
1039*44704f69SBart Van Assche n = strlen(op->index_str);
1040*44704f69SBart Van Assche if (n >= (blen - 1)) {
1041*44704f69SBart Van Assche pr2serr("bad argument to '--index', string too long\n");
1042*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1043*44704f69SBart Van Assche }
1044*44704f69SBart Van Assche }
1045*44704f69SBart Van Assche snprintf(b, blen, "%.*s", n, op->index_str);
1046*44704f69SBart Van Assche if (0 == strcmp("-1", b)) {
1047*44704f69SBart Van Assche if (cp) {
1048*44704f69SBart Van Assche pr2serr("bad argument to '--index', unexpected '-1' type header "
1049*44704f69SBart Van Assche "index\n");
1050*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1051*44704f69SBart Van Assche }
1052*44704f69SBart Van Assche op->ind_th = 0;
1053*44704f69SBart Van Assche op->ind_indiv = -1;
1054*44704f69SBart Van Assche } else if (isdigit((uint8_t)b[0])) {
1055*44704f69SBart Van Assche n = sg_get_num_nomult(b);
1056*44704f69SBart Van Assche if ((n < 0) || (n > 255)) {
1057*44704f69SBart Van Assche pr2serr("bad numeric argument to '--index', expect number from 0 "
1058*44704f69SBart Van Assche "to 255\n");
1059*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1060*44704f69SBart Van Assche }
1061*44704f69SBart Van Assche if (cp) /* argument to left of comma */
1062*44704f69SBart Van Assche op->ind_th = n;
1063*44704f69SBart Van Assche else { /* no comma found, so 'n' is ind_indiv */
1064*44704f69SBart Van Assche op->ind_th = 0;
1065*44704f69SBart Van Assche op->ind_indiv = n;
1066*44704f69SBart Van Assche if ((c2p = strchr(b, '-'))) {
1067*44704f69SBart Van Assche n2 = sg_get_num_nomult(c2p + 1);
1068*44704f69SBart Van Assche if ((n2 < n) || (n2 > 255)) {
1069*44704f69SBart Van Assche pr2serr("bad argument to '--index', after '-' expect "
1070*44704f69SBart Van Assche "number from -%d to 255\n", n);
1071*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1072*44704f69SBart Van Assche }
1073*44704f69SBart Van Assche }
1074*44704f69SBart Van Assche op->ind_indiv_last = n2;
1075*44704f69SBart Van Assche }
1076*44704f69SBart Van Assche } else if ('_' == b[0]) { /* leading "_" prefixes element type code */
1077*44704f69SBart Van Assche if ((c2p = strchr(b + 1, '_')))
1078*44704f69SBart Van Assche *c2p = '\0'; /* subsequent "_" prefixes e.t. index */
1079*44704f69SBart Van Assche n = sg_get_num_nomult(b + 1);
1080*44704f69SBart Van Assche if ((n < 0) || (n > 255)) {
1081*44704f69SBart Van Assche pr2serr("bad element type code for '--index', expect value from "
1082*44704f69SBart Van Assche "0 to 255\n");
1083*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1084*44704f69SBart Van Assche }
1085*44704f69SBart Van Assche element_type_by_code.elem_type_code = n;
1086*44704f69SBart Van Assche mallcp = (char *)malloc(8); /* willfully forget about freeing this */
1087*44704f69SBart Van Assche if (NULL == mallcp)
1088*44704f69SBart Van Assche return sg_convert_errno(ENOMEM);
1089*44704f69SBart Van Assche mallcp[0] = '_';
1090*44704f69SBart Van Assche snprintf(mallcp + 1, 6, "%d", n);
1091*44704f69SBart Van Assche element_type_by_code.abbrev = mallcp;
1092*44704f69SBart Van Assche if (c2p) {
1093*44704f69SBart Van Assche n = sg_get_num_nomult(c2p + 1);
1094*44704f69SBart Van Assche if ((n < 0) || (n > 255)) {
1095*44704f69SBart Van Assche pr2serr("bad element type code <num> for '--index', expect "
1096*44704f69SBart Van Assche "<num> from 0 to 255\n");
1097*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1098*44704f69SBart Van Assche }
1099*44704f69SBart Van Assche op->ind_et_inst = n;
1100*44704f69SBart Van Assche }
1101*44704f69SBart Van Assche op->ind_etp = &element_type_by_code;
1102*44704f69SBart Van Assche if (NULL == cp)
1103*44704f69SBart Van Assche op->ind_indiv = -1;
1104*44704f69SBart Van Assche } else { /* element type abbreviation perhaps followed by <num> */
1105*44704f69SBart Van Assche int b_len = strlen(b);
1106*44704f69SBart Van Assche
1107*44704f69SBart Van Assche for (etp = element_type_arr; etp->desc; ++etp) {
1108*44704f69SBart Van Assche n = strlen(etp->abbrev);
1109*44704f69SBart Van Assche if ((n == b_len) && (0 == strncmp(b, etp->abbrev, n)))
1110*44704f69SBart Van Assche break;
1111*44704f69SBart Van Assche }
1112*44704f69SBart Van Assche if (NULL == etp->desc) {
1113*44704f69SBart Van Assche pr2serr("bad element type abbreviation [%s] for '--index'\n"
1114*44704f69SBart Van Assche "use '--enumerate' to see possibles\n", b);
1115*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1116*44704f69SBart Van Assche }
1117*44704f69SBart Van Assche if (b_len > n) {
1118*44704f69SBart Van Assche n = sg_get_num_nomult(b + n);
1119*44704f69SBart Van Assche if ((n < 0) || (n > 255)) {
1120*44704f69SBart Van Assche pr2serr("bad element type abbreviation <num> for '--index', "
1121*44704f69SBart Van Assche "expect <num> from 0 to 255\n");
1122*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1123*44704f69SBart Van Assche }
1124*44704f69SBart Van Assche op->ind_et_inst = n;
1125*44704f69SBart Van Assche }
1126*44704f69SBart Van Assche op->ind_etp = etp;
1127*44704f69SBart Van Assche if (NULL == cp)
1128*44704f69SBart Van Assche op->ind_indiv = -1;
1129*44704f69SBart Van Assche }
1130*44704f69SBart Van Assche if (op->verbose > 1) {
1131*44704f69SBart Van Assche if (op->ind_etp)
1132*44704f69SBart Van Assche pr2serr(" element type abbreviation: %s, etp_num=%d, "
1133*44704f69SBart Van Assche "individual index=%d\n", op->ind_etp->abbrev,
1134*44704f69SBart Van Assche op->ind_et_inst, op->ind_indiv);
1135*44704f69SBart Van Assche else
1136*44704f69SBart Van Assche pr2serr(" type header index=%d, individual index=%d\n",
1137*44704f69SBart Van Assche op->ind_th, op->ind_indiv);
1138*44704f69SBart Van Assche }
1139*44704f69SBart Van Assche return 0;
1140*44704f69SBart Van Assche }
1141*44704f69SBart Van Assche
1142*44704f69SBart Van Assche
1143*44704f69SBart Van Assche /* command line process, options and arguments. Returns 0 if ok. */
1144*44704f69SBart Van Assche static int
parse_cmd_line(struct opts_t * op,int argc,char * argv[])1145*44704f69SBart Van Assche parse_cmd_line(struct opts_t *op, int argc, char *argv[])
1146*44704f69SBart Van Assche {
1147*44704f69SBart Van Assche int c, j, n, d_len, ret;
1148*44704f69SBart Van Assche const char * data_arg = NULL;
1149*44704f69SBart Van Assche const char * inhex_arg = NULL;
1150*44704f69SBart Van Assche uint64_t saddr;
1151*44704f69SBart Van Assche const char * cp;
1152*44704f69SBart Van Assche
1153*44704f69SBart Van Assche while (1) {
1154*44704f69SBart Van Assche int option_index = 0;
1155*44704f69SBart Van Assche
1156*44704f69SBart Van Assche c = getopt_long(argc, argv, "aA:b:cC:d:D:eE:fG:hHiI:jln:N:m:Mp:qrRs"
1157*44704f69SBart Van Assche "S:vVwx:z", long_options, &option_index);
1158*44704f69SBart Van Assche if (c == -1)
1159*44704f69SBart Van Assche break;
1160*44704f69SBart Van Assche
1161*44704f69SBart Van Assche switch (c) {
1162*44704f69SBart Van Assche case 'a': /* --all is synonym for --join */
1163*44704f69SBart Van Assche ++op->do_join;
1164*44704f69SBart Van Assche break;
1165*44704f69SBart Van Assche case 'A': /* SAS address, assumed to be hex */
1166*44704f69SBart Van Assche cp = optarg;
1167*44704f69SBart Van Assche if ((strlen(optarg) > 2) && ('X' == toupper((uint8_t)optarg[1])))
1168*44704f69SBart Van Assche cp = optarg + 2;
1169*44704f69SBart Van Assche if (1 != sscanf(cp, "%" SCNx64 "", &saddr)) {
1170*44704f69SBart Van Assche pr2serr("bad argument to '--sas-addr=SA'\n");
1171*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1172*44704f69SBart Van Assche }
1173*44704f69SBart Van Assche sg_put_unaligned_be64(saddr, op->sas_addr + 0);
1174*44704f69SBart Van Assche if (sg_all_ffs(op->sas_addr, 8)) {
1175*44704f69SBart Van Assche pr2serr("error decoding '--sas-addr=SA' argument\n");
1176*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1177*44704f69SBart Van Assche }
1178*44704f69SBart Van Assche break;
1179*44704f69SBart Van Assche case 'b':
1180*44704f69SBart Van Assche op->byte1 = sg_get_num_nomult(optarg);
1181*44704f69SBart Van Assche if ((op->byte1 < 0) || (op->byte1 > 255)) {
1182*44704f69SBart Van Assche pr2serr("bad argument to '--byte1=B1' (0 to 255 "
1183*44704f69SBart Van Assche "inclusive)\n");
1184*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1185*44704f69SBart Van Assche }
1186*44704f69SBart Van Assche op->byte1_given = true;
1187*44704f69SBart Van Assche break;
1188*44704f69SBart Van Assche case 'c':
1189*44704f69SBart Van Assche op->do_control = true;
1190*44704f69SBart Van Assche break;
1191*44704f69SBart Van Assche case 'C':
1192*44704f69SBart Van Assche if (strlen(optarg) >= CGS_STR_MAX_SZ) {
1193*44704f69SBart Van Assche pr2serr("--clear= option too long (max %d characters)\n",
1194*44704f69SBart Van Assche CGS_STR_MAX_SZ);
1195*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1196*44704f69SBart Van Assche }
1197*44704f69SBart Van Assche if (op->num_cgs < CGS_CL_ARR_MAX_SZ) {
1198*44704f69SBart Van Assche op->cgs_cl_arr[op->num_cgs].cgs_sel = CLEAR_OPT;
1199*44704f69SBart Van Assche strcpy(op->cgs_cl_arr[op->num_cgs].cgs_str, optarg);
1200*44704f69SBart Van Assche ++op->num_cgs;
1201*44704f69SBart Van Assche } else {
1202*44704f69SBart Van Assche pr2serr("Too many --clear=, --get= and --set= options "
1203*44704f69SBart Van Assche "(max: %d)\n", CGS_CL_ARR_MAX_SZ);
1204*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
1205*44704f69SBart Van Assche }
1206*44704f69SBart Van Assche break;
1207*44704f69SBart Van Assche case 'd':
1208*44704f69SBart Van Assche data_arg = optarg;
1209*44704f69SBart Van Assche op->do_data = true;
1210*44704f69SBart Van Assche break;
1211*44704f69SBart Van Assche case 'D':
1212*44704f69SBart Van Assche op->desc_name = optarg;
1213*44704f69SBart Van Assche break;
1214*44704f69SBart Van Assche case 'e':
1215*44704f69SBart Van Assche ++op->enumerate;
1216*44704f69SBart Van Assche break;
1217*44704f69SBart Van Assche case 'E':
1218*44704f69SBart Van Assche if (0 == strcmp("auto", optarg))
1219*44704f69SBart Van Assche op->eiioe_auto = true;
1220*44704f69SBart Van Assche else if (0 == strcmp("force", optarg))
1221*44704f69SBart Van Assche op->eiioe_force = true;
1222*44704f69SBart Van Assche else {
1223*44704f69SBart Van Assche pr2serr("--eiioe option expects 'auto' or 'force' as an "
1224*44704f69SBart Van Assche "argument\n");
1225*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
1226*44704f69SBart Van Assche }
1227*44704f69SBart Van Assche break;
1228*44704f69SBart Van Assche case 'f':
1229*44704f69SBart Van Assche ++op->do_filter;
1230*44704f69SBart Van Assche break;
1231*44704f69SBart Van Assche case 'G':
1232*44704f69SBart Van Assche if (strlen(optarg) >= CGS_STR_MAX_SZ) {
1233*44704f69SBart Van Assche pr2serr("--get= option too long (max %d characters)\n",
1234*44704f69SBart Van Assche CGS_STR_MAX_SZ);
1235*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1236*44704f69SBart Van Assche }
1237*44704f69SBart Van Assche if (op->num_cgs < CGS_CL_ARR_MAX_SZ) {
1238*44704f69SBart Van Assche op->cgs_cl_arr[op->num_cgs].cgs_sel = GET_OPT;
1239*44704f69SBart Van Assche strcpy(op->cgs_cl_arr[op->num_cgs].cgs_str, optarg);
1240*44704f69SBart Van Assche ++op->num_cgs;
1241*44704f69SBart Van Assche } else {
1242*44704f69SBart Van Assche pr2serr("Too many --clear=, --get= and --set= options "
1243*44704f69SBart Van Assche "(max: %d)\n", CGS_CL_ARR_MAX_SZ);
1244*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
1245*44704f69SBart Van Assche }
1246*44704f69SBart Van Assche break;
1247*44704f69SBart Van Assche case 'h':
1248*44704f69SBart Van Assche ++op->do_help;
1249*44704f69SBart Van Assche break;
1250*44704f69SBart Van Assche case '?':
1251*44704f69SBart Van Assche pr2serr("\n");
1252*44704f69SBart Van Assche usage(0);
1253*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1254*44704f69SBart Van Assche case 'H':
1255*44704f69SBart Van Assche ++op->do_hex;
1256*44704f69SBart Van Assche break;
1257*44704f69SBart Van Assche case 'i':
1258*44704f69SBart Van Assche op->inner_hex = true;
1259*44704f69SBart Van Assche break;
1260*44704f69SBart Van Assche case 'I':
1261*44704f69SBart Van Assche op->index_str = optarg;
1262*44704f69SBart Van Assche break;
1263*44704f69SBart Van Assche case 'j':
1264*44704f69SBart Van Assche ++op->do_join;
1265*44704f69SBart Van Assche break;
1266*44704f69SBart Van Assche case 'l':
1267*44704f69SBart Van Assche op->do_list = true;
1268*44704f69SBart Van Assche break;
1269*44704f69SBart Van Assche case 'n':
1270*44704f69SBart Van Assche op->nickname_str = optarg;
1271*44704f69SBart Van Assche break;
1272*44704f69SBart Van Assche case 'N':
1273*44704f69SBart Van Assche op->seid = sg_get_num_nomult(optarg);
1274*44704f69SBart Van Assche if ((op->seid < 0) || (op->seid > 255)) {
1275*44704f69SBart Van Assche pr2serr("bad argument to '--nickid=SEID' (0 to 255 "
1276*44704f69SBart Van Assche "inclusive)\n");
1277*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1278*44704f69SBart Van Assche }
1279*44704f69SBart Van Assche op->seid_given = true;
1280*44704f69SBart Van Assche break;
1281*44704f69SBart Van Assche case 'm':
1282*44704f69SBart Van Assche n = sg_get_num(optarg);
1283*44704f69SBart Van Assche if ((n < 0) || (n > 65535)) {
1284*44704f69SBart Van Assche pr2serr("bad argument to '--maxlen=LEN' (0 to 65535 "
1285*44704f69SBart Van Assche "inclusive expected)\n");
1286*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1287*44704f69SBart Van Assche }
1288*44704f69SBart Van Assche if (0 == n)
1289*44704f69SBart Van Assche op->maxlen = MX_ALLOC_LEN;
1290*44704f69SBart Van Assche else if (n < MIN_MAXLEN) {
1291*44704f69SBart Van Assche pr2serr("Warning: --maxlen=LEN less than %d ignored\n",
1292*44704f69SBart Van Assche MIN_MAXLEN);
1293*44704f69SBart Van Assche op->maxlen = MX_ALLOC_LEN;
1294*44704f69SBart Van Assche } else
1295*44704f69SBart Van Assche op->maxlen = n;
1296*44704f69SBart Van Assche break;
1297*44704f69SBart Van Assche case 'M':
1298*44704f69SBart Van Assche op->mask_ign = true;
1299*44704f69SBart Van Assche break;
1300*44704f69SBart Van Assche case 'p':
1301*44704f69SBart Van Assche if (isdigit((uint8_t)optarg[0])) {
1302*44704f69SBart Van Assche op->page_code = sg_get_num_nomult(optarg);
1303*44704f69SBart Van Assche if ((op->page_code < 0) || (op->page_code > 255)) {
1304*44704f69SBart Van Assche pr2serr("bad argument to '--page=PG' (0 to 255 "
1305*44704f69SBart Van Assche "inclusive)\n");
1306*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1307*44704f69SBart Van Assche }
1308*44704f69SBart Van Assche } else {
1309*44704f69SBart Van Assche const struct diag_page_abbrev * ap;
1310*44704f69SBart Van Assche
1311*44704f69SBart Van Assche for (ap = dp_abbrev; ap->abbrev; ++ap) {
1312*44704f69SBart Van Assche if (strcase_eq(ap->abbrev, optarg)) {
1313*44704f69SBart Van Assche op->page_code = ap->page_code;
1314*44704f69SBart Van Assche break;
1315*44704f69SBart Van Assche }
1316*44704f69SBart Van Assche }
1317*44704f69SBart Van Assche if (NULL == ap->abbrev) {
1318*44704f69SBart Van Assche pr2serr("'--page=PG' argument abbreviation \"%s\" not "
1319*44704f69SBart Van Assche "found\nHere are the choices:\n", optarg);
1320*44704f69SBart Van Assche enumerate_diag_pages();
1321*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1322*44704f69SBart Van Assche }
1323*44704f69SBart Van Assche }
1324*44704f69SBart Van Assche op->page_code_given = true;
1325*44704f69SBart Van Assche break;
1326*44704f69SBart Van Assche case 'q':
1327*44704f69SBart Van Assche op->quiet = true;
1328*44704f69SBart Van Assche break;
1329*44704f69SBart Van Assche case 'r':
1330*44704f69SBart Van Assche ++op->do_raw;
1331*44704f69SBart Van Assche break;
1332*44704f69SBart Van Assche case 'R':
1333*44704f69SBart Van Assche op->o_readonly = true;
1334*44704f69SBart Van Assche break;
1335*44704f69SBart Van Assche case 's':
1336*44704f69SBart Van Assche op->do_status = true;
1337*44704f69SBart Van Assche break;
1338*44704f69SBart Van Assche case 'S':
1339*44704f69SBart Van Assche if (strlen(optarg) >= CGS_STR_MAX_SZ) {
1340*44704f69SBart Van Assche pr2serr("--set= option too long (max %d characters)\n",
1341*44704f69SBart Van Assche CGS_STR_MAX_SZ);
1342*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1343*44704f69SBart Van Assche }
1344*44704f69SBart Van Assche if (op->num_cgs < CGS_CL_ARR_MAX_SZ) {
1345*44704f69SBart Van Assche op->cgs_cl_arr[op->num_cgs].cgs_sel = SET_OPT;
1346*44704f69SBart Van Assche strcpy(op->cgs_cl_arr[op->num_cgs].cgs_str, optarg);
1347*44704f69SBart Van Assche ++op->num_cgs;
1348*44704f69SBart Van Assche } else {
1349*44704f69SBart Van Assche pr2serr("Too many --clear=, --get= and --set= options "
1350*44704f69SBart Van Assche "(max: %d)\n", CGS_CL_ARR_MAX_SZ);
1351*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
1352*44704f69SBart Van Assche }
1353*44704f69SBart Van Assche break;
1354*44704f69SBart Van Assche case 'v':
1355*44704f69SBart Van Assche op->verbose_given = true;
1356*44704f69SBart Van Assche ++op->verbose;
1357*44704f69SBart Van Assche break;
1358*44704f69SBart Van Assche case 'V':
1359*44704f69SBart Van Assche op->version_given = true;
1360*44704f69SBart Van Assche return 0;
1361*44704f69SBart Van Assche case 'w':
1362*44704f69SBart Van Assche op->warn = true;
1363*44704f69SBart Van Assche break;
1364*44704f69SBart Van Assche case 'x':
1365*44704f69SBart Van Assche op->dev_slot_num = sg_get_num_nomult(optarg);
1366*44704f69SBart Van Assche if ((op->dev_slot_num < 0) || (op->dev_slot_num > 255)) {
1367*44704f69SBart Van Assche pr2serr("bad argument to '--dev-slot-num' (0 to 255 "
1368*44704f69SBart Van Assche "inclusive)\n");
1369*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1370*44704f69SBart Van Assche }
1371*44704f69SBart Van Assche break;
1372*44704f69SBart Van Assche case 'X': /* --inhex=FN for compatibility with other utils */
1373*44704f69SBart Van Assche inhex_arg = optarg;
1374*44704f69SBart Van Assche op->do_data = true;
1375*44704f69SBart Van Assche break;
1376*44704f69SBart Van Assche case 'z': /* --ALL and -z are synonyms for '--join --join' */
1377*44704f69SBart Van Assche /* -A already used for --sas-addr=SA shortened form */
1378*44704f69SBart Van Assche op->do_join += 2;
1379*44704f69SBart Van Assche break;
1380*44704f69SBart Van Assche default:
1381*44704f69SBart Van Assche pr2serr("unrecognised option code 0x%x ??\n", c);
1382*44704f69SBart Van Assche goto err_help;
1383*44704f69SBart Van Assche }
1384*44704f69SBart Van Assche }
1385*44704f69SBart Van Assche if (op->do_help)
1386*44704f69SBart Van Assche return 0;
1387*44704f69SBart Van Assche if (optind < argc) {
1388*44704f69SBart Van Assche if (NULL == op->dev_name) {
1389*44704f69SBart Van Assche op->dev_name = argv[optind];
1390*44704f69SBart Van Assche ++optind;
1391*44704f69SBart Van Assche }
1392*44704f69SBart Van Assche if (optind < argc) {
1393*44704f69SBart Van Assche for (; optind < argc; ++optind)
1394*44704f69SBart Van Assche pr2serr("Unexpected extra argument: %s\n", argv[optind]);
1395*44704f69SBart Van Assche goto err_help;
1396*44704f69SBart Van Assche }
1397*44704f69SBart Van Assche }
1398*44704f69SBart Van Assche op->mx_arr_len = (op->maxlen > MIN_DATA_IN_SZ) ? op->maxlen :
1399*44704f69SBart Van Assche MIN_DATA_IN_SZ;
1400*44704f69SBart Van Assche op->data_arr = sg_memalign(op->mx_arr_len, 0 /* page aligned */,
1401*44704f69SBart Van Assche &op->free_data_arr, false);
1402*44704f69SBart Van Assche if (NULL == op->data_arr) {
1403*44704f69SBart Van Assche pr2serr("unable to allocate %u bytes on heap\n", op->mx_arr_len);
1404*44704f69SBart Van Assche return sg_convert_errno(ENOMEM);
1405*44704f69SBart Van Assche }
1406*44704f69SBart Van Assche if (data_arg || inhex_arg) {
1407*44704f69SBart Van Assche if (inhex_arg) {
1408*44704f69SBart Van Assche data_arg = inhex_arg;
1409*44704f69SBart Van Assche if (read_hex(data_arg, op->data_arr + DATA_IN_OFF,
1410*44704f69SBart Van Assche op->mx_arr_len - DATA_IN_OFF, &op->arr_len,
1411*44704f69SBart Van Assche (op->do_raw < 2), false, op->verbose)) {
1412*44704f69SBart Van Assche pr2serr("bad argument, expect '--inhex=FN' or '--inhex=-'\n");
1413*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1414*44704f69SBart Van Assche }
1415*44704f69SBart Van Assche } else {
1416*44704f69SBart Van Assche if (read_hex(data_arg, op->data_arr + DATA_IN_OFF,
1417*44704f69SBart Van Assche op->mx_arr_len - DATA_IN_OFF, &op->arr_len,
1418*44704f69SBart Van Assche (op->do_raw < 2), true, op->verbose)) {
1419*44704f69SBart Van Assche pr2serr("bad argument, expect '--data=H,H...', '--data=-' or "
1420*44704f69SBart Van Assche "'--data=@FN'\n");
1421*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1422*44704f69SBart Van Assche }
1423*44704f69SBart Van Assche }
1424*44704f69SBart Van Assche op->do_raw = 0;
1425*44704f69SBart Van Assche /* struct data_in_desc_t stuff does not apply when --control */
1426*44704f69SBart Van Assche if (op->do_status && (op->arr_len > 3)) {
1427*44704f69SBart Van Assche int off;
1428*44704f69SBart Van Assche int pc = 0;
1429*44704f69SBart Van Assche const uint8_t * bp = op->data_arr + DATA_IN_OFF;
1430*44704f69SBart Van Assche struct data_in_desc_t * didp = data_in_desc_arr;
1431*44704f69SBart Van Assche
1432*44704f69SBart Van Assche d_len = sg_get_unaligned_be16(bp + 2) + 4;
1433*44704f69SBart Van Assche for (n = 0, off = 0; n < MX_DATA_IN_DESCS; ++n, ++didp) {
1434*44704f69SBart Van Assche didp->in_use = true;
1435*44704f69SBart Van Assche pc = bp[0];
1436*44704f69SBart Van Assche didp->page_code = pc;
1437*44704f69SBart Van Assche didp->offset = off;
1438*44704f69SBart Van Assche didp->dp_len = d_len;
1439*44704f69SBart Van Assche off += d_len;
1440*44704f69SBart Van Assche if ((off + 3) < op->arr_len) {
1441*44704f69SBart Van Assche bp += d_len;
1442*44704f69SBart Van Assche d_len = sg_get_unaligned_be16(bp + 2) + 4;
1443*44704f69SBart Van Assche } else {
1444*44704f69SBart Van Assche ++n;
1445*44704f69SBart Van Assche break;
1446*44704f69SBart Van Assche }
1447*44704f69SBart Van Assche }
1448*44704f69SBart Van Assche if (1 == n) {
1449*44704f69SBart Van Assche op->page_code_given = true;
1450*44704f69SBart Van Assche op->page_code = pc;
1451*44704f69SBart Van Assche } else /* n must be > 1 */
1452*44704f69SBart Van Assche op->many_dpages = true;
1453*44704f69SBart Van Assche
1454*44704f69SBart Van Assche if (op->verbose > 3) {
1455*44704f69SBart Van Assche int k;
1456*44704f69SBart Van Assche char b[128];
1457*44704f69SBart Van Assche
1458*44704f69SBart Van Assche for (didp = data_in_desc_arr, k = 0; k < n; ++k, ++didp) {
1459*44704f69SBart Van Assche if ((cp = find_in_diag_page_desc(didp->page_code)))
1460*44704f69SBart Van Assche snprintf(b, sizeof(b), "%s dpage", cp);
1461*44704f69SBart Van Assche else
1462*44704f69SBart Van Assche snprintf(b, sizeof(b), "dpage 0x%x", didp->page_code);
1463*44704f69SBart Van Assche pr2serr("%s found, offset %d, dp_len=%d\n", b,
1464*44704f69SBart Van Assche didp->offset, didp->dp_len);
1465*44704f69SBart Van Assche }
1466*44704f69SBart Van Assche }
1467*44704f69SBart Van Assche }
1468*44704f69SBart Van Assche }
1469*44704f69SBart Van Assche if (op->do_join && op->do_control) {
1470*44704f69SBart Van Assche pr2serr("cannot have '--join' and '--control'\n");
1471*44704f69SBart Van Assche goto err_help;
1472*44704f69SBart Van Assche }
1473*44704f69SBart Van Assche if (op->index_str) {
1474*44704f69SBart Van Assche ret = parse_index(op);
1475*44704f69SBart Van Assche if (ret) {
1476*44704f69SBart Van Assche pr2serr(" For more information use '--help'\n");
1477*44704f69SBart Van Assche return ret;
1478*44704f69SBart Van Assche }
1479*44704f69SBart Van Assche }
1480*44704f69SBart Van Assche if (op->desc_name || (op->dev_slot_num >= 0) ||
1481*44704f69SBart Van Assche saddr_non_zero(op->sas_addr)) {
1482*44704f69SBart Van Assche if (op->ind_given) {
1483*44704f69SBart Van Assche pr2serr("cannot have --index with either --descriptor, "
1484*44704f69SBart Van Assche "--dev-slot-num or --sas-addr\n");
1485*44704f69SBart Van Assche goto err_help;
1486*44704f69SBart Van Assche }
1487*44704f69SBart Van Assche if (((!! op->desc_name) + (op->dev_slot_num >= 0) +
1488*44704f69SBart Van Assche saddr_non_zero(op->sas_addr)) > 1) {
1489*44704f69SBart Van Assche pr2serr("can only have one of --descriptor, "
1490*44704f69SBart Van Assche "--dev-slot-num and --sas-addr\n");
1491*44704f69SBart Van Assche goto err_help;
1492*44704f69SBart Van Assche }
1493*44704f69SBart Van Assche if ((0 == op->do_join) && (! op->do_control) &&
1494*44704f69SBart Van Assche (0 == op->num_cgs) && (! op->page_code_given)) {
1495*44704f69SBart Van Assche ++op->do_join; /* implicit --join */
1496*44704f69SBart Van Assche if (op->verbose)
1497*44704f69SBart Van Assche pr2serr("process as if --join option is set\n");
1498*44704f69SBart Van Assche }
1499*44704f69SBart Van Assche }
1500*44704f69SBart Van Assche if (op->ind_given) {
1501*44704f69SBart Van Assche if ((0 == op->do_join) && (! op->do_control) &&
1502*44704f69SBart Van Assche (0 == op->num_cgs) && (! op->page_code_given)) {
1503*44704f69SBart Van Assche op->page_code_given = true;
1504*44704f69SBart Van Assche op->page_code = ENC_STATUS_DPC; /* implicit status page */
1505*44704f69SBart Van Assche if (op->verbose)
1506*44704f69SBart Van Assche pr2serr("assume --page=2 (es) option is set\n");
1507*44704f69SBart Van Assche }
1508*44704f69SBart Van Assche }
1509*44704f69SBart Van Assche if (op->do_list || op->enumerate)
1510*44704f69SBart Van Assche return 0;
1511*44704f69SBart Van Assche
1512*44704f69SBart Van Assche if (op->do_control && op->do_status) {
1513*44704f69SBart Van Assche pr2serr("cannot have both '--control' and '--status'\n");
1514*44704f69SBart Van Assche goto err_help;
1515*44704f69SBart Van Assche } else if (op->do_control) {
1516*44704f69SBart Van Assche if (op->nickname_str || op->seid_given)
1517*44704f69SBart Van Assche ;
1518*44704f69SBart Van Assche else if (! op->do_data) {
1519*44704f69SBart Van Assche pr2serr("need to give '--data' in control mode\n");
1520*44704f69SBart Van Assche goto err_help;
1521*44704f69SBart Van Assche }
1522*44704f69SBart Van Assche } else if (! op->do_status) {
1523*44704f69SBart Van Assche if (op->do_data) {
1524*44704f69SBart Van Assche pr2serr("when user data given, require '--control' or "
1525*44704f69SBart Van Assche "'--status' option\n");
1526*44704f69SBart Van Assche goto err_help;
1527*44704f69SBart Van Assche }
1528*44704f69SBart Van Assche op->do_status = true; /* default to receiving status pages */
1529*44704f69SBart Van Assche } else if (op->do_status && op->do_data && op->dev_name) {
1530*44704f69SBart Van Assche pr2serr(">>> Warning: device name (%s) will be ignored\n",
1531*44704f69SBart Van Assche op->dev_name);
1532*44704f69SBart Van Assche op->dev_name = NULL; /* quash device name */
1533*44704f69SBart Van Assche }
1534*44704f69SBart Van Assche
1535*44704f69SBart Van Assche if (op->nickname_str) {
1536*44704f69SBart Van Assche if (! op->do_control) {
1537*44704f69SBart Van Assche pr2serr("since '--nickname=' implies control mode, require "
1538*44704f69SBart Van Assche "'--control' as well\n");
1539*44704f69SBart Van Assche goto err_help;
1540*44704f69SBart Van Assche }
1541*44704f69SBart Van Assche if (op->page_code_given) {
1542*44704f69SBart Van Assche if (SUBENC_NICKNAME_DPC != op->page_code) {
1543*44704f69SBart Van Assche pr2serr("since '--nickname=' assume or expect "
1544*44704f69SBart Van Assche "'--page=snic'\n");
1545*44704f69SBart Van Assche goto err_help;
1546*44704f69SBart Van Assche }
1547*44704f69SBart Van Assche } else
1548*44704f69SBart Van Assche op->page_code = SUBENC_NICKNAME_DPC;
1549*44704f69SBart Van Assche } else if (op->seid_given) {
1550*44704f69SBart Van Assche pr2serr("'--nickid=' must be used together with '--nickname='\n");
1551*44704f69SBart Van Assche goto err_help;
1552*44704f69SBart Van Assche
1553*44704f69SBart Van Assche }
1554*44704f69SBart Van Assche if ((op->verbose > 4) && saddr_non_zero(op->sas_addr)) {
1555*44704f69SBart Van Assche pr2serr(" SAS address (in hex): ");
1556*44704f69SBart Van Assche for (j = 0; j < 8; ++j)
1557*44704f69SBart Van Assche pr2serr("%02x", op->sas_addr[j]);
1558*44704f69SBart Van Assche pr2serr("\n");
1559*44704f69SBart Van Assche }
1560*44704f69SBart Van Assche
1561*44704f69SBart Van Assche if ((! (op->do_data && op->do_status)) && (NULL == op->dev_name)) {
1562*44704f69SBart Van Assche pr2serr("missing DEVICE name!\n\n");
1563*44704f69SBart Van Assche goto err_help;
1564*44704f69SBart Van Assche }
1565*44704f69SBart Van Assche return 0;
1566*44704f69SBart Van Assche
1567*44704f69SBart Van Assche err_help:
1568*44704f69SBart Van Assche if (op->verbose) {
1569*44704f69SBart Van Assche pr2serr("\n");
1570*44704f69SBart Van Assche usage(0);
1571*44704f69SBart Van Assche }
1572*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
1573*44704f69SBart Van Assche }
1574*44704f69SBart Van Assche
1575*44704f69SBart Van Assche /* Parse clear/get/set string, writes output to '*tavp'. Uses 'buff' for
1576*44704f69SBart Van Assche * scratch area. Returns 0 on success, else -1. */
1577*44704f69SBart Van Assche static int
parse_cgs_str(char * buff,struct tuple_acronym_val * tavp)1578*44704f69SBart Van Assche parse_cgs_str(char * buff, struct tuple_acronym_val * tavp)
1579*44704f69SBart Van Assche {
1580*44704f69SBart Van Assche char * esp;
1581*44704f69SBart Van Assche char * colp;
1582*44704f69SBart Van Assche unsigned int ui;
1583*44704f69SBart Van Assche
1584*44704f69SBart Van Assche tavp->acron = NULL;
1585*44704f69SBart Van Assche tavp->val_str = NULL;
1586*44704f69SBart Van Assche tavp->start_byte = -1;
1587*44704f69SBart Van Assche tavp->num_bits = 1;
1588*44704f69SBart Van Assche if ((esp = strchr(buff, '='))) {
1589*44704f69SBart Van Assche tavp->val_str = esp + 1;
1590*44704f69SBart Van Assche *esp = '\0';
1591*44704f69SBart Van Assche if (0 == strcmp("-1", esp + 1))
1592*44704f69SBart Van Assche tavp->val = -1;
1593*44704f69SBart Van Assche else {
1594*44704f69SBart Van Assche tavp->val = sg_get_llnum_nomult(esp + 1);
1595*44704f69SBart Van Assche if (-1 == tavp->val) {
1596*44704f69SBart Van Assche pr2serr("unable to decode: %s value\n", esp + 1);
1597*44704f69SBart Van Assche pr2serr(" expected: <acronym>[=<val>]\n");
1598*44704f69SBart Van Assche return -1;
1599*44704f69SBart Van Assche }
1600*44704f69SBart Van Assche }
1601*44704f69SBart Van Assche }
1602*44704f69SBart Van Assche if (isalpha((uint8_t)buff[0]))
1603*44704f69SBart Van Assche tavp->acron = buff;
1604*44704f69SBart Van Assche else {
1605*44704f69SBart Van Assche char * cp;
1606*44704f69SBart Van Assche
1607*44704f69SBart Van Assche colp = strchr(buff, ':');
1608*44704f69SBart Van Assche if ((NULL == colp) || (buff == colp))
1609*44704f69SBart Van Assche return -1;
1610*44704f69SBart Van Assche *colp = '\0';
1611*44704f69SBart Van Assche if (('0' == buff[0]) && ('X' == toupper((uint8_t)buff[1]))) {
1612*44704f69SBart Van Assche if (1 != sscanf(buff + 2, "%x", &ui))
1613*44704f69SBart Van Assche return -1;
1614*44704f69SBart Van Assche tavp->start_byte = ui;
1615*44704f69SBart Van Assche } else if ('H' == toupper((uint8_t)*(colp - 1))) {
1616*44704f69SBart Van Assche if (1 != sscanf(buff, "%x", &ui))
1617*44704f69SBart Van Assche return -1;
1618*44704f69SBart Van Assche tavp->start_byte = ui;
1619*44704f69SBart Van Assche } else {
1620*44704f69SBart Van Assche if (1 != sscanf(buff, "%d", &tavp->start_byte))
1621*44704f69SBart Van Assche return -1;
1622*44704f69SBart Van Assche }
1623*44704f69SBart Van Assche if ((tavp->start_byte < 0) || (tavp->start_byte > 127)) {
1624*44704f69SBart Van Assche pr2serr("<start_byte> needs to be between 0 and 127\n");
1625*44704f69SBart Van Assche return -1;
1626*44704f69SBart Van Assche }
1627*44704f69SBart Van Assche cp = colp + 1;
1628*44704f69SBart Van Assche colp = strchr(cp, ':');
1629*44704f69SBart Van Assche if (cp == colp)
1630*44704f69SBart Van Assche return -1;
1631*44704f69SBart Van Assche if (colp)
1632*44704f69SBart Van Assche *colp = '\0';
1633*44704f69SBart Van Assche if (1 != sscanf(cp, "%d", &tavp->start_bit))
1634*44704f69SBart Van Assche return -1;
1635*44704f69SBart Van Assche if ((tavp->start_bit < 0) || (tavp->start_bit > 7)) {
1636*44704f69SBart Van Assche pr2serr("<start_bit> needs to be between 0 and 7\n");
1637*44704f69SBart Van Assche return -1;
1638*44704f69SBart Van Assche }
1639*44704f69SBart Van Assche if (colp) {
1640*44704f69SBart Van Assche if (1 != sscanf(colp + 1, "%d", &tavp->num_bits))
1641*44704f69SBart Van Assche return -1;
1642*44704f69SBart Van Assche }
1643*44704f69SBart Van Assche if ((tavp->num_bits < 1) || (tavp->num_bits > 64)) {
1644*44704f69SBart Van Assche pr2serr("<num_bits> needs to be between 1 and 64\n");
1645*44704f69SBart Van Assche return -1;
1646*44704f69SBart Van Assche }
1647*44704f69SBart Van Assche }
1648*44704f69SBart Van Assche return 0;
1649*44704f69SBart Van Assche }
1650*44704f69SBart Van Assche
1651*44704f69SBart Van Assche /* Fetch diagnostic page name (control or out). Returns NULL if not found. */
1652*44704f69SBart Van Assche static const char *
find_out_diag_page_desc(int page_num)1653*44704f69SBart Van Assche find_out_diag_page_desc(int page_num)
1654*44704f69SBart Van Assche {
1655*44704f69SBart Van Assche const struct diag_page_code * pcdp;
1656*44704f69SBart Van Assche
1657*44704f69SBart Van Assche for (pcdp = out_dpc_arr; pcdp->desc; ++pcdp) {
1658*44704f69SBart Van Assche if (page_num == pcdp->page_code)
1659*44704f69SBart Van Assche return pcdp->desc;
1660*44704f69SBart Van Assche else if (page_num < pcdp->page_code)
1661*44704f69SBart Van Assche return NULL;
1662*44704f69SBart Van Assche }
1663*44704f69SBart Van Assche return NULL;
1664*44704f69SBart Van Assche }
1665*44704f69SBart Van Assche
1666*44704f69SBart Van Assche static bool
match_ind_indiv(int index,const struct opts_t * op)1667*44704f69SBart Van Assche match_ind_indiv(int index, const struct opts_t * op)
1668*44704f69SBart Van Assche {
1669*44704f69SBart Van Assche if (index == op->ind_indiv)
1670*44704f69SBart Van Assche return true;
1671*44704f69SBart Van Assche if (op->ind_indiv_last > op->ind_indiv) {
1672*44704f69SBart Van Assche if ((index > op->ind_indiv) && (index <= op->ind_indiv_last))
1673*44704f69SBart Van Assche return true;
1674*44704f69SBart Van Assche }
1675*44704f69SBart Van Assche return false;
1676*44704f69SBart Van Assche }
1677*44704f69SBart Van Assche
1678*44704f69SBart Van Assche #if 0
1679*44704f69SBart Van Assche static bool
1680*44704f69SBart Van Assche match_last_ind_indiv(int index, const struct opts_t * op)
1681*44704f69SBart Van Assche {
1682*44704f69SBart Van Assche if (op->ind_indiv_last >= op->ind_indiv)
1683*44704f69SBart Van Assche return (index == op->ind_indiv_last);
1684*44704f69SBart Van Assche return (index == op->ind_indiv);
1685*44704f69SBart Van Assche }
1686*44704f69SBart Van Assche #endif
1687*44704f69SBart Van Assche
1688*44704f69SBart Van Assche /* Return of 0 -> success, SG_LIB_CAT_* positive values or -1 -> other
1689*44704f69SBart Van Assche * failures */
1690*44704f69SBart Van Assche static int
do_senddiag(struct sg_pt_base * ptvp,void * outgoing_pg,int outgoing_len,bool noisy,int verbose)1691*44704f69SBart Van Assche do_senddiag(struct sg_pt_base * ptvp, void * outgoing_pg, int outgoing_len,
1692*44704f69SBart Van Assche bool noisy, int verbose)
1693*44704f69SBart Van Assche {
1694*44704f69SBart Van Assche int ret;
1695*44704f69SBart Van Assche
1696*44704f69SBart Van Assche if (outgoing_pg && (verbose > 2)) {
1697*44704f69SBart Van Assche int page_num = ((const char *)outgoing_pg)[0];
1698*44704f69SBart Van Assche const char * cp = find_out_diag_page_desc(page_num);
1699*44704f69SBart Van Assche
1700*44704f69SBart Van Assche if (cp)
1701*44704f69SBart Van Assche pr2serr(" Send diagnostic command page name: %s\n", cp);
1702*44704f69SBart Van Assche else
1703*44704f69SBart Van Assche pr2serr(" Send diagnostic command page number: 0x%x\n",
1704*44704f69SBart Van Assche page_num);
1705*44704f69SBart Van Assche }
1706*44704f69SBart Van Assche ret = sg_ll_send_diag_pt(ptvp, 0 /* sf_code */, true /* pf_bit */,
1707*44704f69SBart Van Assche false /* sf_bit */, false /* devofl_bit */,
1708*44704f69SBart Van Assche false /* unitofl_bit */, 0 /* long_duration */,
1709*44704f69SBart Van Assche outgoing_pg, outgoing_len, noisy, verbose);
1710*44704f69SBart Van Assche clear_scsi_pt_obj(ptvp);
1711*44704f69SBart Van Assche return ret;
1712*44704f69SBart Van Assche }
1713*44704f69SBart Van Assche
1714*44704f69SBart Van Assche /* Fetch diagnostic page name (status and/or control). Returns NULL if not
1715*44704f69SBart Van Assche * found. */
1716*44704f69SBart Van Assche static const char *
find_diag_page_desc(int page_num)1717*44704f69SBart Van Assche find_diag_page_desc(int page_num)
1718*44704f69SBart Van Assche {
1719*44704f69SBart Van Assche const struct diag_page_code * pcdp;
1720*44704f69SBart Van Assche
1721*44704f69SBart Van Assche for (pcdp = dpc_arr; pcdp->desc; ++pcdp) {
1722*44704f69SBart Van Assche if (page_num == pcdp->page_code)
1723*44704f69SBart Van Assche return pcdp->desc;
1724*44704f69SBart Van Assche else if (page_num < pcdp->page_code)
1725*44704f69SBart Van Assche return NULL;
1726*44704f69SBart Van Assche }
1727*44704f69SBart Van Assche return NULL;
1728*44704f69SBart Van Assche }
1729*44704f69SBart Van Assche
1730*44704f69SBart Van Assche /* Fetch diagnostic page name (status or in). Returns NULL if not found. */
1731*44704f69SBart Van Assche static const char *
find_in_diag_page_desc(int page_num)1732*44704f69SBart Van Assche find_in_diag_page_desc(int page_num)
1733*44704f69SBart Van Assche {
1734*44704f69SBart Van Assche const struct diag_page_code * pcdp;
1735*44704f69SBart Van Assche
1736*44704f69SBart Van Assche for (pcdp = in_dpc_arr; pcdp->desc; ++pcdp) {
1737*44704f69SBart Van Assche if (page_num == pcdp->page_code)
1738*44704f69SBart Van Assche return pcdp->desc;
1739*44704f69SBart Van Assche else if (page_num < pcdp->page_code)
1740*44704f69SBart Van Assche return NULL;
1741*44704f69SBart Van Assche }
1742*44704f69SBart Van Assche return NULL;
1743*44704f69SBart Van Assche }
1744*44704f69SBart Van Assche
1745*44704f69SBart Van Assche /* Fetch element type name. Returns NULL if not found. */
1746*44704f69SBart Van Assche static char *
etype_str(int elem_type_code,char * b,int mlen_b)1747*44704f69SBart Van Assche etype_str(int elem_type_code, char * b, int mlen_b)
1748*44704f69SBart Van Assche {
1749*44704f69SBart Van Assche const struct element_type_t * etp;
1750*44704f69SBart Van Assche int len;
1751*44704f69SBart Van Assche
1752*44704f69SBart Van Assche if ((NULL == b) || (mlen_b < 1))
1753*44704f69SBart Van Assche return b;
1754*44704f69SBart Van Assche for (etp = element_type_arr; etp->desc; ++etp) {
1755*44704f69SBart Van Assche if (elem_type_code == etp->elem_type_code) {
1756*44704f69SBart Van Assche len = strlen(etp->desc);
1757*44704f69SBart Van Assche if (len < mlen_b)
1758*44704f69SBart Van Assche strcpy(b, etp->desc);
1759*44704f69SBart Van Assche else {
1760*44704f69SBart Van Assche strncpy(b, etp->desc, mlen_b - 1);
1761*44704f69SBart Van Assche b[mlen_b - 1] = '\0';
1762*44704f69SBart Van Assche }
1763*44704f69SBart Van Assche return b;
1764*44704f69SBart Van Assche } else if (elem_type_code < etp->elem_type_code)
1765*44704f69SBart Van Assche break;
1766*44704f69SBart Van Assche }
1767*44704f69SBart Van Assche if (elem_type_code < 0x80)
1768*44704f69SBart Van Assche snprintf(b, mlen_b - 1, "[0x%x]", elem_type_code);
1769*44704f69SBart Van Assche else
1770*44704f69SBart Van Assche snprintf(b, mlen_b - 1, "vendor specific [0x%x]", elem_type_code);
1771*44704f69SBart Van Assche b[mlen_b - 1] = '\0';
1772*44704f69SBart Van Assche return b;
1773*44704f69SBart Van Assche }
1774*44704f69SBart Van Assche
1775*44704f69SBart Van Assche /* Returns true if el_type (element type) is of interest to the Additional
1776*44704f69SBart Van Assche * Element Status page. Otherwise return false. */
1777*44704f69SBart Van Assche static bool
is_et_used_by_aes(int el_type)1778*44704f69SBart Van Assche is_et_used_by_aes(int el_type)
1779*44704f69SBart Van Assche {
1780*44704f69SBart Van Assche if ((el_type >= 0) && (el_type < NUM_ACTIVE_ET_AESP_ARR))
1781*44704f69SBart Van Assche return active_et_aesp_arr[el_type];
1782*44704f69SBart Van Assche else
1783*44704f69SBart Van Assche return false;
1784*44704f69SBart Van Assche }
1785*44704f69SBart Van Assche
1786*44704f69SBart Van Assche #if 0
1787*44704f69SBart Van Assche static struct join_row_t *
1788*44704f69SBart Van Assche find_join_row(struct th_es_t * tesp, int index, enum fj_select_t sel)
1789*44704f69SBart Van Assche {
1790*44704f69SBart Van Assche int k;
1791*44704f69SBart Van Assche struct join_row_t * jrp = tesp->j_base;
1792*44704f69SBart Van Assche
1793*44704f69SBart Van Assche if (index < 0)
1794*44704f69SBart Van Assche return NULL;
1795*44704f69SBart Van Assche switch (sel) {
1796*44704f69SBart Van Assche case FJ_IOE: /* index includes overall element */
1797*44704f69SBart Van Assche if (index >= tesp->num_j_rows)
1798*44704f69SBart Van Assche return NULL;
1799*44704f69SBart Van Assche return jrp + index;
1800*44704f69SBart Van Assche case FJ_EOE: /* index excludes overall element */
1801*44704f69SBart Van Assche if (index >= tesp->num_j_eoe)
1802*44704f69SBart Van Assche return NULL;
1803*44704f69SBart Van Assche for (k = 0; k < tesp->num_j_rows; ++k, ++jrp) {
1804*44704f69SBart Van Assche if (index == jrp->ei_eoe)
1805*44704f69SBart Van Assche return jrp;
1806*44704f69SBart Van Assche }
1807*44704f69SBart Van Assche return NULL;
1808*44704f69SBart Van Assche case FJ_AESS: /* index includes only AES listed element types */
1809*44704f69SBart Van Assche if (index >= tesp->num_j_eoe)
1810*44704f69SBart Van Assche return NULL;
1811*44704f69SBart Van Assche for (k = 0; k < tesp->num_j_rows; ++k, ++jrp) {
1812*44704f69SBart Van Assche if (index == jrp->ei_aess)
1813*44704f69SBart Van Assche return jrp;
1814*44704f69SBart Van Assche }
1815*44704f69SBart Van Assche return NULL;
1816*44704f69SBart Van Assche case FJ_SAS_CON: /* index on non-overall SAS connector etype */
1817*44704f69SBart Van Assche if (index >= tesp->num_j_rows)
1818*44704f69SBart Van Assche return NULL;
1819*44704f69SBart Van Assche for (k = 0; k < tesp->num_j_rows; ++k, ++jrp) {
1820*44704f69SBart Van Assche if (SAS_CONNECTOR_ETC == jrp->etype) {
1821*44704f69SBart Van Assche if (index == jrp->indiv_i)
1822*44704f69SBart Van Assche return jrp;
1823*44704f69SBart Van Assche }
1824*44704f69SBart Van Assche }
1825*44704f69SBart Van Assche return NULL;
1826*44704f69SBart Van Assche default:
1827*44704f69SBart Van Assche pr2serr("%s: bad selector: %d\n", __func__, (int)sel);
1828*44704f69SBart Van Assche return NULL;
1829*44704f69SBart Van Assche }
1830*44704f69SBart Van Assche }
1831*44704f69SBart Van Assche #endif
1832*44704f69SBart Van Assche
1833*44704f69SBart Van Assche static const struct join_row_t *
find_join_row_cnst(const struct th_es_t * tesp,int index,enum fj_select_t sel)1834*44704f69SBart Van Assche find_join_row_cnst(const struct th_es_t * tesp, int index,
1835*44704f69SBart Van Assche enum fj_select_t sel)
1836*44704f69SBart Van Assche {
1837*44704f69SBart Van Assche int k;
1838*44704f69SBart Van Assche const struct join_row_t * jrp = tesp->j_base;
1839*44704f69SBart Van Assche
1840*44704f69SBart Van Assche if (index < 0)
1841*44704f69SBart Van Assche return NULL;
1842*44704f69SBart Van Assche switch (sel) {
1843*44704f69SBart Van Assche case FJ_IOE: /* index includes overall element */
1844*44704f69SBart Van Assche if (index >= tesp->num_j_rows)
1845*44704f69SBart Van Assche return NULL;
1846*44704f69SBart Van Assche return jrp + index;
1847*44704f69SBart Van Assche case FJ_EOE: /* index excludes overall element */
1848*44704f69SBart Van Assche if (index >= tesp->num_j_eoe)
1849*44704f69SBart Van Assche return NULL;
1850*44704f69SBart Van Assche for (k = 0; k < tesp->num_j_rows; ++k, ++jrp) {
1851*44704f69SBart Van Assche if (index == jrp->ei_eoe)
1852*44704f69SBart Van Assche return jrp;
1853*44704f69SBart Van Assche }
1854*44704f69SBart Van Assche return NULL;
1855*44704f69SBart Van Assche case FJ_AESS: /* index includes only AES listed element types */
1856*44704f69SBart Van Assche if (index >= tesp->num_j_eoe)
1857*44704f69SBart Van Assche return NULL;
1858*44704f69SBart Van Assche for (k = 0; k < tesp->num_j_rows; ++k, ++jrp) {
1859*44704f69SBart Van Assche if (index == jrp->ei_aess)
1860*44704f69SBart Van Assche return jrp;
1861*44704f69SBart Van Assche }
1862*44704f69SBart Van Assche return NULL;
1863*44704f69SBart Van Assche case FJ_SAS_CON: /* index on non-overall SAS connector etype */
1864*44704f69SBart Van Assche if (index >= tesp->num_j_rows)
1865*44704f69SBart Van Assche return NULL;
1866*44704f69SBart Van Assche for (k = 0; k < tesp->num_j_rows; ++k, ++jrp) {
1867*44704f69SBart Van Assche if (SAS_CONNECTOR_ETC == jrp->etype) {
1868*44704f69SBart Van Assche if (index == jrp->indiv_i)
1869*44704f69SBart Van Assche return jrp;
1870*44704f69SBart Van Assche }
1871*44704f69SBart Van Assche }
1872*44704f69SBart Van Assche return NULL;
1873*44704f69SBart Van Assche default:
1874*44704f69SBart Van Assche pr2serr("%s: bad selector: %d\n", __func__, (int)sel);
1875*44704f69SBart Van Assche return NULL;
1876*44704f69SBart Van Assche }
1877*44704f69SBart Van Assche }
1878*44704f69SBart Van Assche
1879*44704f69SBart Van Assche /* Return of 0 -> success, SG_LIB_CAT_* positive values or -2 if response
1880*44704f69SBart Van Assche * had bad format, -1 -> other failures */
1881*44704f69SBart Van Assche static int
do_rec_diag(struct sg_pt_base * ptvp,int page_code,uint8_t * rsp_buff,int rsp_buff_size,struct opts_t * op,int * rsp_lenp)1882*44704f69SBart Van Assche do_rec_diag(struct sg_pt_base * ptvp, int page_code, uint8_t * rsp_buff,
1883*44704f69SBart Van Assche int rsp_buff_size, struct opts_t * op, int * rsp_lenp)
1884*44704f69SBart Van Assche {
1885*44704f69SBart Van Assche int k, d_len, rsp_len, res;
1886*44704f69SBart Van Assche int resid = 0;
1887*44704f69SBart Van Assche int vb = op->verbose;
1888*44704f69SBart Van Assche const char * cp;
1889*44704f69SBart Van Assche char b[80];
1890*44704f69SBart Van Assche char bb[120];
1891*44704f69SBart Van Assche static const char * rdr = "Receive diagnostic results";
1892*44704f69SBart Van Assche
1893*44704f69SBart Van Assche memset(rsp_buff, 0, rsp_buff_size);
1894*44704f69SBart Van Assche if (rsp_lenp)
1895*44704f69SBart Van Assche *rsp_lenp = 0;
1896*44704f69SBart Van Assche if ((cp = find_in_diag_page_desc(page_code)))
1897*44704f69SBart Van Assche snprintf(bb, sizeof(bb), "%s dpage", cp);
1898*44704f69SBart Van Assche else
1899*44704f69SBart Van Assche snprintf(bb, sizeof(bb), "dpage 0x%x", page_code);
1900*44704f69SBart Van Assche cp = bb;
1901*44704f69SBart Van Assche
1902*44704f69SBart Van Assche if (op->data_arr && op->do_data) { /* user provided data */
1903*44704f69SBart Van Assche /* N.B. First 4 bytes in data_arr are not used, user data was read in
1904*44704f69SBart Van Assche * starting at byte offset 4 */
1905*44704f69SBart Van Assche bool found = false;
1906*44704f69SBart Van Assche int off = 0;
1907*44704f69SBart Van Assche const uint8_t * bp = op->data_arr + DATA_IN_OFF;
1908*44704f69SBart Van Assche const struct data_in_desc_t * didp = data_in_desc_arr;
1909*44704f69SBart Van Assche
1910*44704f69SBart Van Assche for (k = 0, d_len = 0; k < MX_DATA_IN_DESCS; ++k, ++didp) {
1911*44704f69SBart Van Assche if (! didp->in_use)
1912*44704f69SBart Van Assche break;
1913*44704f69SBart Van Assche if (page_code == didp->page_code) {
1914*44704f69SBart Van Assche off = didp->offset;
1915*44704f69SBart Van Assche d_len = didp->dp_len;
1916*44704f69SBart Van Assche found = true;
1917*44704f69SBart Van Assche break;
1918*44704f69SBart Van Assche }
1919*44704f69SBart Van Assche }
1920*44704f69SBart Van Assche if (found)
1921*44704f69SBart Van Assche memcpy(rsp_buff, bp + off, d_len);
1922*44704f69SBart Van Assche else {
1923*44704f69SBart Van Assche if (vb)
1924*44704f69SBart Van Assche pr2serr("%s: %s not found in user data\n", __func__, cp);
1925*44704f69SBart Van Assche return SG_LIB_CAT_OTHER;
1926*44704f69SBart Van Assche }
1927*44704f69SBart Van Assche
1928*44704f69SBart Van Assche cp = find_in_diag_page_desc(page_code);
1929*44704f69SBart Van Assche if (vb > 2) {
1930*44704f69SBart Van Assche pr2serr(" %s: response data from user", rdr);
1931*44704f69SBart Van Assche if (3 == vb) {
1932*44704f69SBart Van Assche pr2serr("%s:\n", (d_len > 256 ? ", first 256 bytes" : ""));
1933*44704f69SBart Van Assche hex2stderr(rsp_buff, (d_len > 256 ? 256 : d_len), -1);
1934*44704f69SBart Van Assche } else {
1935*44704f69SBart Van Assche pr2serr(":\n");
1936*44704f69SBart Van Assche hex2stderr(rsp_buff, d_len, 0);
1937*44704f69SBart Van Assche }
1938*44704f69SBart Van Assche }
1939*44704f69SBart Van Assche res = 0;
1940*44704f69SBart Van Assche resid = rsp_buff_size - d_len;
1941*44704f69SBart Van Assche goto decode; /* step over the device access */
1942*44704f69SBart Van Assche }
1943*44704f69SBart Van Assche if (vb > 1)
1944*44704f69SBart Van Assche pr2serr(" %s command for %s\n", rdr, cp);
1945*44704f69SBart Van Assche res = sg_ll_receive_diag_pt(ptvp, true /* pcv */, page_code, rsp_buff,
1946*44704f69SBart Van Assche rsp_buff_size, 0 /* default timeout */,
1947*44704f69SBart Van Assche &resid, ! op->quiet, vb);
1948*44704f69SBart Van Assche clear_scsi_pt_obj(ptvp);
1949*44704f69SBart Van Assche decode:
1950*44704f69SBart Van Assche if (0 == res) {
1951*44704f69SBart Van Assche rsp_len = sg_get_unaligned_be16(rsp_buff + 2) + 4;
1952*44704f69SBart Van Assche if (rsp_len > rsp_buff_size) {
1953*44704f69SBart Van Assche if (rsp_buff_size > 8) /* tried to get more than header */
1954*44704f69SBart Van Assche pr2serr("<<< warning response buffer too small [was %d but "
1955*44704f69SBart Van Assche "need %d]>>>\n", rsp_buff_size, rsp_len);
1956*44704f69SBart Van Assche if (resid > 0)
1957*44704f69SBart Van Assche rsp_buff_size -= resid;
1958*44704f69SBart Van Assche } else if (resid > 0)
1959*44704f69SBart Van Assche rsp_buff_size -= resid;
1960*44704f69SBart Van Assche rsp_len = (rsp_len < rsp_buff_size) ? rsp_len : rsp_buff_size;
1961*44704f69SBart Van Assche if (rsp_len < 0) {
1962*44704f69SBart Van Assche pr2serr("<<< warning: resid=%d too large, implies negative "
1963*44704f69SBart Van Assche "reply length: %d\n", resid, rsp_len);
1964*44704f69SBart Van Assche rsp_len = 0;
1965*44704f69SBart Van Assche }
1966*44704f69SBart Van Assche if (rsp_lenp)
1967*44704f69SBart Van Assche *rsp_lenp = rsp_len;
1968*44704f69SBart Van Assche if ((rsp_len > 1) && (page_code != rsp_buff[0])) {
1969*44704f69SBart Van Assche if ((0x9 == rsp_buff[0]) && (1 & rsp_buff[1])) {
1970*44704f69SBart Van Assche pr2serr("Enclosure busy, try again later\n");
1971*44704f69SBart Van Assche if (op->do_hex)
1972*44704f69SBart Van Assche hex2stderr(rsp_buff, rsp_len, 0);
1973*44704f69SBart Van Assche } else if (0x8 == rsp_buff[0]) {
1974*44704f69SBart Van Assche pr2serr("Enclosure only supports Short Enclosure Status: "
1975*44704f69SBart Van Assche "0x%x\n", rsp_buff[1]);
1976*44704f69SBart Van Assche } else {
1977*44704f69SBart Van Assche pr2serr("Invalid response, wanted page code: 0x%x but got "
1978*44704f69SBart Van Assche "0x%x\n", page_code, rsp_buff[0]);
1979*44704f69SBart Van Assche hex2stderr(rsp_buff, rsp_len, 0);
1980*44704f69SBart Van Assche }
1981*44704f69SBart Van Assche return -2;
1982*44704f69SBart Van Assche }
1983*44704f69SBart Van Assche return 0;
1984*44704f69SBart Van Assche } else if (vb) {
1985*44704f69SBart Van Assche pr2serr("Attempt to fetch %s failed\n", cp);
1986*44704f69SBart Van Assche sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
1987*44704f69SBart Van Assche pr2serr(" %s\n", b);
1988*44704f69SBart Van Assche }
1989*44704f69SBart Van Assche return res;
1990*44704f69SBart Van Assche }
1991*44704f69SBart Van Assche
1992*44704f69SBart Van Assche #if 1
1993*44704f69SBart Van Assche
1994*44704f69SBart Van Assche static void
dStrRaw(const uint8_t * str,int len)1995*44704f69SBart Van Assche dStrRaw(const uint8_t * str, int len)
1996*44704f69SBart Van Assche {
1997*44704f69SBart Van Assche int k;
1998*44704f69SBart Van Assche
1999*44704f69SBart Van Assche for (k = 0; k < len; ++k)
2000*44704f69SBart Van Assche printf("%c", str[k]);
2001*44704f69SBart Van Assche }
2002*44704f69SBart Van Assche
2003*44704f69SBart Van Assche #else
2004*44704f69SBart Van Assche
2005*44704f69SBart Van Assche static void
dStrRaw(const uint8_t * str,int len)2006*44704f69SBart Van Assche dStrRaw(const uint8_t * str, int len)
2007*44704f69SBart Van Assche {
2008*44704f69SBart Van Assche int res, err;
2009*44704f69SBart Van Assche
2010*44704f69SBart Van Assche if (len > 0) {
2011*44704f69SBart Van Assche res = write(fileno(stdout), str, len);
2012*44704f69SBart Van Assche if (res < 0) {
2013*44704f69SBart Van Assche err = errno;
2014*44704f69SBart Van Assche pr2serr("%s: write to stdout failed: %s [%d]\n", __func__,
2015*44704f69SBart Van Assche strerror(err), err);
2016*44704f69SBart Van Assche }
2017*44704f69SBart Van Assche }
2018*44704f69SBart Van Assche }
2019*44704f69SBart Van Assche
2020*44704f69SBart Van Assche #endif
2021*44704f69SBart Van Assche
2022*44704f69SBart Van Assche /* CONFIGURATION_DPC [0x1]
2023*44704f69SBart Van Assche * Display Configuration diagnostic page. */
2024*44704f69SBart Van Assche static void
configuration_sdg(const uint8_t * resp,int resp_len)2025*44704f69SBart Van Assche configuration_sdg(const uint8_t * resp, int resp_len)
2026*44704f69SBart Van Assche {
2027*44704f69SBart Van Assche int j, k, el, num_subs, sum_elem_types;
2028*44704f69SBart Van Assche uint32_t gen_code;
2029*44704f69SBart Van Assche const uint8_t * bp;
2030*44704f69SBart Van Assche const uint8_t * last_bp;
2031*44704f69SBart Van Assche const uint8_t * text_bp;
2032*44704f69SBart Van Assche char b[64];
2033*44704f69SBart Van Assche
2034*44704f69SBart Van Assche printf("Configuration diagnostic page:\n");
2035*44704f69SBart Van Assche if (resp_len < 4)
2036*44704f69SBart Van Assche goto truncated;
2037*44704f69SBart Van Assche num_subs = resp[1] + 1; /* number of subenclosures (add 1 for primary) */
2038*44704f69SBart Van Assche sum_elem_types = 0;
2039*44704f69SBart Van Assche last_bp = resp + resp_len - 1;
2040*44704f69SBart Van Assche printf(" number of secondary subenclosures: %d\n",
2041*44704f69SBart Van Assche num_subs - 1);
2042*44704f69SBart Van Assche gen_code = sg_get_unaligned_be32(resp + 4);
2043*44704f69SBart Van Assche printf(" generation code: 0x%" PRIx32 "\n", gen_code);
2044*44704f69SBart Van Assche bp = resp + 8;
2045*44704f69SBart Van Assche printf(" enclosure descriptor list\n");
2046*44704f69SBart Van Assche for (k = 0; k < num_subs; ++k, bp += el) {
2047*44704f69SBart Van Assche if ((bp + 3) > last_bp)
2048*44704f69SBart Van Assche goto truncated;
2049*44704f69SBart Van Assche el = bp[3] + 4;
2050*44704f69SBart Van Assche sum_elem_types += bp[2];
2051*44704f69SBart Van Assche printf(" Subenclosure identifier: %d%s\n", bp[1],
2052*44704f69SBart Van Assche (bp[1] ? "" : " [primary]"));
2053*44704f69SBart Van Assche printf(" relative ES process id: %d, number of ES processes"
2054*44704f69SBart Van Assche ": %d\n", ((bp[0] & 0x70) >> 4), (bp[0] & 0x7));
2055*44704f69SBart Van Assche printf(" number of type descriptor headers: %d\n", bp[2]);
2056*44704f69SBart Van Assche if (el < 40) {
2057*44704f69SBart Van Assche pr2serr(" enc descriptor len=%d ??\n", el);
2058*44704f69SBart Van Assche continue;
2059*44704f69SBart Van Assche }
2060*44704f69SBart Van Assche printf(" enclosure logical identifier (hex): ");
2061*44704f69SBart Van Assche for (j = 0; j < 8; ++j)
2062*44704f69SBart Van Assche printf("%02x", bp[4 + j]);
2063*44704f69SBart Van Assche printf("\n enclosure vendor: %.8s product: %.16s rev: %.4s\n",
2064*44704f69SBart Van Assche bp + 12, bp + 20, bp + 36);
2065*44704f69SBart Van Assche if (el > 40) {
2066*44704f69SBart Van Assche char bb[1024];
2067*44704f69SBart Van Assche
2068*44704f69SBart Van Assche printf(" vendor-specific data:\n");
2069*44704f69SBart Van Assche hex2str(bp + 40, el - 40, " ", 0, sizeof(bb), bb);
2070*44704f69SBart Van Assche printf("%s\n", bb);
2071*44704f69SBart Van Assche }
2072*44704f69SBart Van Assche }
2073*44704f69SBart Van Assche /* printf("\n"); */
2074*44704f69SBart Van Assche printf(" type descriptor header and text list\n");
2075*44704f69SBart Van Assche text_bp = bp + (sum_elem_types * 4);
2076*44704f69SBart Van Assche for (k = 0; k < sum_elem_types; ++k, bp += 4) {
2077*44704f69SBart Van Assche if ((bp + 3) > last_bp)
2078*44704f69SBart Van Assche goto truncated;
2079*44704f69SBart Van Assche printf(" Element type: %s, subenclosure id: %d\n",
2080*44704f69SBart Van Assche etype_str(bp[0], b, sizeof(b)), bp[2]);
2081*44704f69SBart Van Assche printf(" number of possible elements: %d\n", bp[1]);
2082*44704f69SBart Van Assche if (bp[3] > 0) {
2083*44704f69SBart Van Assche if (text_bp > last_bp)
2084*44704f69SBart Van Assche goto truncated;
2085*44704f69SBart Van Assche printf(" text: %.*s\n", bp[3], text_bp);
2086*44704f69SBart Van Assche text_bp += bp[3];
2087*44704f69SBart Van Assche }
2088*44704f69SBart Van Assche }
2089*44704f69SBart Van Assche return;
2090*44704f69SBart Van Assche truncated:
2091*44704f69SBart Van Assche pr2serr(" <<<ses_configuration_sdg: response too short>>>\n");
2092*44704f69SBart Van Assche return;
2093*44704f69SBart Van Assche }
2094*44704f69SBart Van Assche
2095*44704f69SBart Van Assche /* CONFIGURATION_DPC [0x1] read and used to build array pointed to by
2096*44704f69SBart Van Assche * 'tdhp' with no more than 'max_elems' elements. If 'generationp' is non
2097*44704f69SBart Van Assche * NULL then writes generation code where it points. if 'primary_ip" is
2098*44704f69SBart Van Assche * non NULL the writes rimary enclosure info where it points.
2099*44704f69SBart Van Assche * Returns total number of type descriptor headers written to 'tdhp' or -1
2100*44704f69SBart Van Assche * if there is a problem */
2101*44704f69SBart Van Assche static int
build_type_desc_hdr_arr(struct sg_pt_base * ptvp,struct type_desc_hdr_t * tdhp,int max_elems,uint32_t * generationp,struct enclosure_info * primary_ip,struct opts_t * op)2102*44704f69SBart Van Assche build_type_desc_hdr_arr(struct sg_pt_base * ptvp,
2103*44704f69SBart Van Assche struct type_desc_hdr_t * tdhp, int max_elems,
2104*44704f69SBart Van Assche uint32_t * generationp,
2105*44704f69SBart Van Assche struct enclosure_info * primary_ip,
2106*44704f69SBart Van Assche struct opts_t * op)
2107*44704f69SBart Van Assche {
2108*44704f69SBart Van Assche int resp_len, k, el, num_subs, sum_type_dheaders, res, n;
2109*44704f69SBart Van Assche int ret = 0;
2110*44704f69SBart Van Assche uint32_t gen_code;
2111*44704f69SBart Van Assche const uint8_t * bp;
2112*44704f69SBart Van Assche const uint8_t * last_bp;
2113*44704f69SBart Van Assche
2114*44704f69SBart Van Assche if (NULL == config_dp_resp) {
2115*44704f69SBart Van Assche config_dp_resp = sg_memalign(op->maxlen, 0, &free_config_dp_resp,
2116*44704f69SBart Van Assche false);
2117*44704f69SBart Van Assche if (NULL == config_dp_resp) {
2118*44704f69SBart Van Assche pr2serr("%s: unable to allocate %d bytes on heap\n", __func__,
2119*44704f69SBart Van Assche op->maxlen);
2120*44704f69SBart Van Assche ret = -1;
2121*44704f69SBart Van Assche goto the_end;
2122*44704f69SBart Van Assche }
2123*44704f69SBart Van Assche res = do_rec_diag(ptvp, CONFIGURATION_DPC, config_dp_resp, op->maxlen,
2124*44704f69SBart Van Assche op, &resp_len);
2125*44704f69SBart Van Assche if (res) {
2126*44704f69SBart Van Assche pr2serr("%s: couldn't read config page, res=%d\n", __func__, res);
2127*44704f69SBart Van Assche ret = -1;
2128*44704f69SBart Van Assche free(free_config_dp_resp);
2129*44704f69SBart Van Assche free_config_dp_resp = NULL;
2130*44704f69SBart Van Assche goto the_end;
2131*44704f69SBart Van Assche }
2132*44704f69SBart Van Assche if (resp_len < 4) {
2133*44704f69SBart Van Assche ret = -1;
2134*44704f69SBart Van Assche free(free_config_dp_resp);
2135*44704f69SBart Van Assche free_config_dp_resp = NULL;
2136*44704f69SBart Van Assche goto the_end;
2137*44704f69SBart Van Assche }
2138*44704f69SBart Van Assche config_dp_resp_len = resp_len;
2139*44704f69SBart Van Assche } else
2140*44704f69SBart Van Assche resp_len = config_dp_resp_len;
2141*44704f69SBart Van Assche
2142*44704f69SBart Van Assche num_subs = config_dp_resp[1] + 1;
2143*44704f69SBart Van Assche sum_type_dheaders = 0;
2144*44704f69SBart Van Assche last_bp = config_dp_resp + resp_len - 1;
2145*44704f69SBart Van Assche gen_code = sg_get_unaligned_be32(config_dp_resp + 4);
2146*44704f69SBart Van Assche if (generationp)
2147*44704f69SBart Van Assche *generationp = gen_code;
2148*44704f69SBart Van Assche bp = config_dp_resp + 8;
2149*44704f69SBart Van Assche for (k = 0; k < num_subs; ++k, bp += el) {
2150*44704f69SBart Van Assche if ((bp + 3) > last_bp)
2151*44704f69SBart Van Assche goto p_truncated;
2152*44704f69SBart Van Assche el = bp[3] + 4;
2153*44704f69SBart Van Assche sum_type_dheaders += bp[2];
2154*44704f69SBart Van Assche if (el < 40) {
2155*44704f69SBart Van Assche pr2serr("%s: short enc descriptor len=%d ??\n", __func__, el);
2156*44704f69SBart Van Assche continue;
2157*44704f69SBart Van Assche }
2158*44704f69SBart Van Assche if ((0 == k) && primary_ip) {
2159*44704f69SBart Van Assche ++primary_ip->have_info;
2160*44704f69SBart Van Assche primary_ip->rel_esp_id = (bp[0] & 0x70) >> 4;
2161*44704f69SBart Van Assche primary_ip->num_esp = (bp[0] & 0x7);
2162*44704f69SBart Van Assche memcpy(primary_ip->enc_log_id, bp + 4, 8);
2163*44704f69SBart Van Assche memcpy(primary_ip->enc_vendor_id, bp + 12, 8);
2164*44704f69SBart Van Assche memcpy(primary_ip->product_id, bp + 20, 16);
2165*44704f69SBart Van Assche memcpy(primary_ip->product_rev_level, bp + 36, 4);
2166*44704f69SBart Van Assche }
2167*44704f69SBart Van Assche }
2168*44704f69SBart Van Assche for (k = 0; k < sum_type_dheaders; ++k, bp += 4) {
2169*44704f69SBart Van Assche if ((bp + 3) > last_bp)
2170*44704f69SBart Van Assche goto p_truncated;
2171*44704f69SBart Van Assche if (k >= max_elems) {
2172*44704f69SBart Van Assche pr2serr("%s: too many elements\n", __func__);
2173*44704f69SBart Van Assche ret = -1;
2174*44704f69SBart Van Assche goto the_end;
2175*44704f69SBart Van Assche }
2176*44704f69SBart Van Assche tdhp[k].etype = bp[0];
2177*44704f69SBart Van Assche tdhp[k].num_elements = bp[1];
2178*44704f69SBart Van Assche tdhp[k].se_id = bp[2];
2179*44704f69SBart Van Assche tdhp[k].txt_len = bp[3];
2180*44704f69SBart Van Assche }
2181*44704f69SBart Van Assche if (op->ind_given && op->ind_etp) {
2182*44704f69SBart Van Assche n = op->ind_et_inst;
2183*44704f69SBart Van Assche for (k = 0; k < sum_type_dheaders; ++k) {
2184*44704f69SBart Van Assche if (op->ind_etp->elem_type_code == tdhp[k].etype) {
2185*44704f69SBart Van Assche if (0 == n)
2186*44704f69SBart Van Assche break;
2187*44704f69SBart Van Assche else
2188*44704f69SBart Van Assche --n;
2189*44704f69SBart Van Assche }
2190*44704f69SBart Van Assche }
2191*44704f69SBart Van Assche if (k < sum_type_dheaders)
2192*44704f69SBart Van Assche op->ind_th = k;
2193*44704f69SBart Van Assche else {
2194*44704f69SBart Van Assche if (op->ind_et_inst)
2195*44704f69SBart Van Assche pr2serr("%s: unable to find element type '%s%d'\n", __func__,
2196*44704f69SBart Van Assche op->ind_etp->abbrev, op->ind_et_inst);
2197*44704f69SBart Van Assche else
2198*44704f69SBart Van Assche pr2serr("%s: unable to find element type '%s'\n", __func__,
2199*44704f69SBart Van Assche op->ind_etp->abbrev);
2200*44704f69SBart Van Assche ret = -1;
2201*44704f69SBart Van Assche goto the_end;
2202*44704f69SBart Van Assche }
2203*44704f69SBart Van Assche }
2204*44704f69SBart Van Assche ret = sum_type_dheaders;
2205*44704f69SBart Van Assche goto the_end;
2206*44704f69SBart Van Assche
2207*44704f69SBart Van Assche p_truncated:
2208*44704f69SBart Van Assche pr2serr("%s: config too short\n", __func__);
2209*44704f69SBart Van Assche ret = -1;
2210*44704f69SBart Van Assche
2211*44704f69SBart Van Assche the_end:
2212*44704f69SBart Van Assche if (0 == ret)
2213*44704f69SBart Van Assche ++type_desc_hdr_count;
2214*44704f69SBart Van Assche return ret;
2215*44704f69SBart Van Assche }
2216*44704f69SBart Van Assche
2217*44704f69SBart Van Assche static char *
find_sas_connector_type(int conn_type,bool abridged,char * buff,int buff_len)2218*44704f69SBart Van Assche find_sas_connector_type(int conn_type, bool abridged, char * buff,
2219*44704f69SBart Van Assche int buff_len)
2220*44704f69SBart Van Assche {
2221*44704f69SBart Van Assche switch (conn_type) {
2222*44704f69SBart Van Assche case 0x0:
2223*44704f69SBart Van Assche snprintf(buff, buff_len, "No information");
2224*44704f69SBart Van Assche break;
2225*44704f69SBart Van Assche case 0x1:
2226*44704f69SBart Van Assche if (abridged)
2227*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS 4x");
2228*44704f69SBart Van Assche else
2229*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS 4x receptacle (SFF-8470) "
2230*44704f69SBart Van Assche "[max 4 phys]");
2231*44704f69SBart Van Assche break;
2232*44704f69SBart Van Assche case 0x2:
2233*44704f69SBart Van Assche if (abridged)
2234*44704f69SBart Van Assche snprintf(buff, buff_len, "Mini SAS 4x");
2235*44704f69SBart Van Assche else
2236*44704f69SBart Van Assche snprintf(buff, buff_len, "Mini SAS 4x receptacle (SFF-8088) "
2237*44704f69SBart Van Assche "[max 4 phys]");
2238*44704f69SBart Van Assche break;
2239*44704f69SBart Van Assche case 0x3:
2240*44704f69SBart Van Assche if (abridged)
2241*44704f69SBart Van Assche snprintf(buff, buff_len, "QSFP+");
2242*44704f69SBart Van Assche else
2243*44704f69SBart Van Assche snprintf(buff, buff_len, "QSFP+ receptacle (SFF-8436) "
2244*44704f69SBart Van Assche "[max 4 phys]");
2245*44704f69SBart Van Assche break;
2246*44704f69SBart Van Assche case 0x4:
2247*44704f69SBart Van Assche if (abridged)
2248*44704f69SBart Van Assche snprintf(buff, buff_len, "Mini SAS 4x active");
2249*44704f69SBart Van Assche else
2250*44704f69SBart Van Assche snprintf(buff, buff_len, "Mini SAS 4x active receptacle "
2251*44704f69SBart Van Assche "(SFF-8088) [max 4 phys]");
2252*44704f69SBart Van Assche break;
2253*44704f69SBart Van Assche case 0x5:
2254*44704f69SBart Van Assche if (abridged)
2255*44704f69SBart Van Assche snprintf(buff, buff_len, "Mini SAS HD 4x");
2256*44704f69SBart Van Assche else
2257*44704f69SBart Van Assche snprintf(buff, buff_len, "Mini SAS HD 4x receptacle (SFF-8644) "
2258*44704f69SBart Van Assche "[max 4 phys]");
2259*44704f69SBart Van Assche break;
2260*44704f69SBart Van Assche case 0x6:
2261*44704f69SBart Van Assche if (abridged)
2262*44704f69SBart Van Assche snprintf(buff, buff_len, "Mini SAS HD 8x");
2263*44704f69SBart Van Assche else
2264*44704f69SBart Van Assche snprintf(buff, buff_len, "Mini SAS HD 8x receptacle (SFF-8644) "
2265*44704f69SBart Van Assche "[max 8 phys]");
2266*44704f69SBart Van Assche break;
2267*44704f69SBart Van Assche case 0x7:
2268*44704f69SBart Van Assche if (abridged)
2269*44704f69SBart Van Assche snprintf(buff, buff_len, "Mini SAS HD 16x");
2270*44704f69SBart Van Assche else
2271*44704f69SBart Van Assche snprintf(buff, buff_len, "Mini SAS HD 16x receptacle (SFF-8644) "
2272*44704f69SBart Van Assche "[max 16 phys]");
2273*44704f69SBart Van Assche break;
2274*44704f69SBart Van Assche case 0xf:
2275*44704f69SBart Van Assche snprintf(buff, buff_len, "Vendor specific");
2276*44704f69SBart Van Assche break;
2277*44704f69SBart Van Assche case 0x10:
2278*44704f69SBart Van Assche if (abridged)
2279*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS 4i");
2280*44704f69SBart Van Assche else
2281*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS 4i plug (SFF-8484) [max 4 phys]");
2282*44704f69SBart Van Assche break;
2283*44704f69SBart Van Assche case 0x11:
2284*44704f69SBart Van Assche if (abridged)
2285*44704f69SBart Van Assche snprintf(buff, buff_len, "Mini SAS 4i");
2286*44704f69SBart Van Assche else
2287*44704f69SBart Van Assche snprintf(buff, buff_len, "Mini SAS 4i receptacle (SFF-8087) "
2288*44704f69SBart Van Assche "[max 4 phys]");
2289*44704f69SBart Van Assche break;
2290*44704f69SBart Van Assche case 0x12:
2291*44704f69SBart Van Assche if (abridged)
2292*44704f69SBart Van Assche snprintf(buff, buff_len, "Mini SAS HD 4i");
2293*44704f69SBart Van Assche else
2294*44704f69SBart Van Assche snprintf(buff, buff_len, "Mini SAS HD 4i receptacle (SFF-8643) "
2295*44704f69SBart Van Assche "[max 4 phys]");
2296*44704f69SBart Van Assche break;
2297*44704f69SBart Van Assche case 0x13:
2298*44704f69SBart Van Assche if (abridged)
2299*44704f69SBart Van Assche snprintf(buff, buff_len, "Mini SAS HD 8i");
2300*44704f69SBart Van Assche else
2301*44704f69SBart Van Assche snprintf(buff, buff_len, "Mini SAS HD 8i receptacle (SFF-8643) "
2302*44704f69SBart Van Assche "[max 8 phys]");
2303*44704f69SBart Van Assche break;
2304*44704f69SBart Van Assche case 0x14:
2305*44704f69SBart Van Assche if (abridged)
2306*44704f69SBart Van Assche snprintf(buff, buff_len, "Mini SAS HD 16i");
2307*44704f69SBart Van Assche else
2308*44704f69SBart Van Assche snprintf(buff, buff_len, "Mini SAS HD 16i receptacle (SFF-8643) "
2309*44704f69SBart Van Assche "[max 16 phys]");
2310*44704f69SBart Van Assche break;
2311*44704f69SBart Van Assche case 0x15:
2312*44704f69SBart Van Assche if (abridged)
2313*44704f69SBart Van Assche snprintf(buff, buff_len, "SlimSAS 4i"); /* was "SAS SlimLine" */
2314*44704f69SBart Van Assche else
2315*44704f69SBart Van Assche snprintf(buff, buff_len, "SlimSAS 4i (SFF-8654) [max 4 phys]");
2316*44704f69SBart Van Assche break;
2317*44704f69SBart Van Assche case 0x16:
2318*44704f69SBart Van Assche if (abridged)
2319*44704f69SBart Van Assche snprintf(buff, buff_len, "SlimSAS 8i"); /* was "SAS SlimLine" */
2320*44704f69SBart Van Assche else
2321*44704f69SBart Van Assche snprintf(buff, buff_len, "SlimSAS 8i (SFF-8654) [max 8 phys]");
2322*44704f69SBart Van Assche break;
2323*44704f69SBart Van Assche case 0x17:
2324*44704f69SBart Van Assche if (abridged)
2325*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS MiniLink 4i");
2326*44704f69SBart Van Assche else
2327*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS MiniLink 4i (SFF-8612) "
2328*44704f69SBart Van Assche "[max 4 phys]");
2329*44704f69SBart Van Assche break;
2330*44704f69SBart Van Assche case 0x18:
2331*44704f69SBart Van Assche if (abridged)
2332*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS MiniLink 8i");
2333*44704f69SBart Van Assche else
2334*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS MiniLink 8i (SFF-8612) "
2335*44704f69SBart Van Assche "[max 8 phys]");
2336*44704f69SBart Van Assche break;
2337*44704f69SBart Van Assche case 0x20:
2338*44704f69SBart Van Assche if (abridged)
2339*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS Drive backplane");
2340*44704f69SBart Van Assche else
2341*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS Drive backplane receptacle "
2342*44704f69SBart Van Assche "(SFF-8482) [max 2 phys]");
2343*44704f69SBart Van Assche break;
2344*44704f69SBart Van Assche case 0x21:
2345*44704f69SBart Van Assche if (abridged)
2346*44704f69SBart Van Assche snprintf(buff, buff_len, "SATA host plug");
2347*44704f69SBart Van Assche else
2348*44704f69SBart Van Assche snprintf(buff, buff_len, "SATA host plug [max 1 phy]");
2349*44704f69SBart Van Assche break;
2350*44704f69SBart Van Assche case 0x22:
2351*44704f69SBart Van Assche if (abridged)
2352*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS Drive plug");
2353*44704f69SBart Van Assche else
2354*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS Drive plug (SFF-8482) "
2355*44704f69SBart Van Assche "[max 2 phys]");
2356*44704f69SBart Van Assche break;
2357*44704f69SBart Van Assche case 0x23:
2358*44704f69SBart Van Assche if (abridged)
2359*44704f69SBart Van Assche snprintf(buff, buff_len, "SATA device plug");
2360*44704f69SBart Van Assche else
2361*44704f69SBart Van Assche snprintf(buff, buff_len, "SATA device plug [max 1 phy]");
2362*44704f69SBart Van Assche break;
2363*44704f69SBart Van Assche case 0x24:
2364*44704f69SBart Van Assche if (abridged)
2365*44704f69SBart Van Assche snprintf(buff, buff_len, "Micro SAS receptacle");
2366*44704f69SBart Van Assche else
2367*44704f69SBart Van Assche snprintf(buff, buff_len, "Micro SAS receptacle [max 2 phys]");
2368*44704f69SBart Van Assche break;
2369*44704f69SBart Van Assche case 0x25:
2370*44704f69SBart Van Assche if (abridged)
2371*44704f69SBart Van Assche snprintf(buff, buff_len, "Micro SATA device plug");
2372*44704f69SBart Van Assche else
2373*44704f69SBart Van Assche snprintf(buff, buff_len, "Micro SATA device plug [max 1 phy]");
2374*44704f69SBart Van Assche break;
2375*44704f69SBart Van Assche case 0x26:
2376*44704f69SBart Van Assche if (abridged)
2377*44704f69SBart Van Assche snprintf(buff, buff_len, "Micro SAS plug");
2378*44704f69SBart Van Assche else
2379*44704f69SBart Van Assche snprintf(buff, buff_len, "Micro SAS plug (SFF-8486) [max 2 "
2380*44704f69SBart Van Assche "phys]");
2381*44704f69SBart Van Assche break;
2382*44704f69SBart Van Assche case 0x27:
2383*44704f69SBart Van Assche if (abridged)
2384*44704f69SBart Van Assche snprintf(buff, buff_len, "Micro SAS/SATA plug");
2385*44704f69SBart Van Assche else
2386*44704f69SBart Van Assche snprintf(buff, buff_len, "Micro SAS/SATA plug (SFF-8486) "
2387*44704f69SBart Van Assche "[max 2 phys]");
2388*44704f69SBart Van Assche break;
2389*44704f69SBart Van Assche case 0x28:
2390*44704f69SBart Van Assche if (abridged)
2391*44704f69SBart Van Assche snprintf(buff, buff_len, "12 Gb/s SAS drive backplane");
2392*44704f69SBart Van Assche else
2393*44704f69SBart Van Assche snprintf(buff, buff_len, "12 Gb/s SAS drive backplane receptacle "
2394*44704f69SBart Van Assche "(SFF-8680) [max 2 phys]");
2395*44704f69SBart Van Assche break;
2396*44704f69SBart Van Assche case 0x29:
2397*44704f69SBart Van Assche if (abridged)
2398*44704f69SBart Van Assche snprintf(buff, buff_len, "12 Gb/s SAS drive plug");
2399*44704f69SBart Van Assche else
2400*44704f69SBart Van Assche snprintf(buff, buff_len, "12 Gb/s SAS drive plug (SFF-8680) "
2401*44704f69SBart Van Assche "[max 2 phys]");
2402*44704f69SBart Van Assche break;
2403*44704f69SBart Van Assche case 0x2a:
2404*44704f69SBart Van Assche if (abridged)
2405*44704f69SBart Van Assche snprintf(buff, buff_len, "Multifunction 12 Gb/s 6x receptacle");
2406*44704f69SBart Van Assche else
2407*44704f69SBart Van Assche snprintf(buff, buff_len, "Multifunction 12 Gb/s 6x unshielded "
2408*44704f69SBart Van Assche "receptacle (SFF-8639)");
2409*44704f69SBart Van Assche break;
2410*44704f69SBart Van Assche case 0x2b:
2411*44704f69SBart Van Assche if (abridged)
2412*44704f69SBart Van Assche snprintf(buff, buff_len, "Multifunction 12 Gb/s 6x plug");
2413*44704f69SBart Van Assche else
2414*44704f69SBart Van Assche snprintf(buff, buff_len, "Multifunction 12 Gb/s 6x unshielded "
2415*44704f69SBart Van Assche "plug (SFF-8639)");
2416*44704f69SBart Van Assche break;
2417*44704f69SBart Van Assche case 0x2c:
2418*44704f69SBart Van Assche if (abridged)
2419*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS MultiLink Drive backplane "
2420*44704f69SBart Van Assche "receptacle");
2421*44704f69SBart Van Assche else
2422*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS MultiLink Drive backplane "
2423*44704f69SBart Van Assche "receptacle (SFF-8630)");
2424*44704f69SBart Van Assche break;
2425*44704f69SBart Van Assche case 0x2d:
2426*44704f69SBart Van Assche if (abridged)
2427*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS MultiLink Drive backplane plug");
2428*44704f69SBart Van Assche else
2429*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS MultiLink Drive backplane plug "
2430*44704f69SBart Van Assche "(SFF-8630)");
2431*44704f69SBart Van Assche break;
2432*44704f69SBart Van Assche case 0x2e:
2433*44704f69SBart Van Assche if (abridged)
2434*44704f69SBart Van Assche snprintf(buff, buff_len, "Reserved");
2435*44704f69SBart Van Assche else
2436*44704f69SBart Van Assche snprintf(buff, buff_len, "Reserved for internal connectors to "
2437*44704f69SBart Van Assche "end device");
2438*44704f69SBart Van Assche break;
2439*44704f69SBart Van Assche case 0x2f:
2440*44704f69SBart Van Assche if (abridged)
2441*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS virtual connector");
2442*44704f69SBart Van Assche else
2443*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS virtual connector [max 1 phy]");
2444*44704f69SBart Van Assche break;
2445*44704f69SBart Van Assche case 0x3f:
2446*44704f69SBart Van Assche if (abridged)
2447*44704f69SBart Van Assche snprintf(buff, buff_len, "VS internal connector");
2448*44704f69SBart Van Assche else
2449*44704f69SBart Van Assche snprintf(buff, buff_len, "Vendor specific internal connector");
2450*44704f69SBart Van Assche break;
2451*44704f69SBart Van Assche case 0x40:
2452*44704f69SBart Van Assche if (abridged)
2453*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS high density drive backplane "
2454*44704f69SBart Van Assche "receptacle");
2455*44704f69SBart Van Assche else
2456*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS high density drive backplane "
2457*44704f69SBart Van Assche "receptacle (SFF-8631) [max 8 phys]");
2458*44704f69SBart Van Assche break;
2459*44704f69SBart Van Assche case 0x41:
2460*44704f69SBart Van Assche if (abridged)
2461*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS high density drive backplane "
2462*44704f69SBart Van Assche "plug");
2463*44704f69SBart Van Assche else
2464*44704f69SBart Van Assche snprintf(buff, buff_len, "SAS high density drive backplane "
2465*44704f69SBart Van Assche "plug (SFF-8631) [max 8 phys]");
2466*44704f69SBart Van Assche break;
2467*44704f69SBart Van Assche default:
2468*44704f69SBart Van Assche if (conn_type < 0x10)
2469*44704f69SBart Van Assche snprintf(buff, buff_len, "unknown external connector type: 0x%x",
2470*44704f69SBart Van Assche conn_type);
2471*44704f69SBart Van Assche else if (conn_type < 0x20)
2472*44704f69SBart Van Assche snprintf(buff, buff_len, "unknown internal wide connector type: "
2473*44704f69SBart Van Assche "0x%x", conn_type);
2474*44704f69SBart Van Assche else if (conn_type < 0x3f)
2475*44704f69SBart Van Assche snprintf(buff, buff_len, "reserved for internal connector, "
2476*44704f69SBart Van Assche "type: 0x%x", conn_type);
2477*44704f69SBart Van Assche else if (conn_type < 0x70)
2478*44704f69SBart Van Assche snprintf(buff, buff_len, "reserved connector type: 0x%x",
2479*44704f69SBart Van Assche conn_type);
2480*44704f69SBart Van Assche else if (conn_type < 0x80)
2481*44704f69SBart Van Assche snprintf(buff, buff_len, "vendor specific connector type: 0x%x",
2482*44704f69SBart Van Assche conn_type);
2483*44704f69SBart Van Assche else /* conn_type is a 7 bit field, so this is impossible */
2484*44704f69SBart Van Assche snprintf(buff, buff_len, "unexpected connector type: 0x%x",
2485*44704f69SBart Van Assche conn_type);
2486*44704f69SBart Van Assche break;
2487*44704f69SBart Van Assche }
2488*44704f69SBart Van Assche return buff;
2489*44704f69SBart Van Assche }
2490*44704f69SBart Van Assche
2491*44704f69SBart Van Assche /* 'Fan speed factor' new in ses4r04 */
2492*44704f69SBart Van Assche static int
calc_fan_speed(int fan_speed_factor,int actual_fan_speed)2493*44704f69SBart Van Assche calc_fan_speed(int fan_speed_factor, int actual_fan_speed)
2494*44704f69SBart Van Assche {
2495*44704f69SBart Van Assche switch (fan_speed_factor) {
2496*44704f69SBart Van Assche case 0:
2497*44704f69SBart Van Assche return actual_fan_speed * 10;
2498*44704f69SBart Van Assche case 1:
2499*44704f69SBart Van Assche return (actual_fan_speed * 10) + 20480;
2500*44704f69SBart Van Assche case 2:
2501*44704f69SBart Van Assche return actual_fan_speed * 100;
2502*44704f69SBart Van Assche default:
2503*44704f69SBart Van Assche break;
2504*44704f69SBart Van Assche }
2505*44704f69SBart Van Assche return -1; /* something is wrong */
2506*44704f69SBart Van Assche }
2507*44704f69SBart Van Assche
2508*44704f69SBart Van Assche static const char * elem_status_code_desc[] = {
2509*44704f69SBart Van Assche "Unsupported", "OK", "Critical", "Noncritical",
2510*44704f69SBart Van Assche "Unrecoverable", "Not installed", "Unknown", "Not available",
2511*44704f69SBart Van Assche "No access allowed", "reserved [9]", "reserved [10]", "reserved [11]",
2512*44704f69SBart Van Assche "reserved [12]", "reserved [13]", "reserved [14]", "reserved [15]",
2513*44704f69SBart Van Assche };
2514*44704f69SBart Van Assche
2515*44704f69SBart Van Assche static const char * actual_speed_desc[] = {
2516*44704f69SBart Van Assche "stopped", "at lowest speed", "at second lowest speed",
2517*44704f69SBart Van Assche "at third lowest speed", "at intermediate speed",
2518*44704f69SBart Van Assche "at third highest speed", "at second highest speed", "at highest speed"
2519*44704f69SBart Van Assche };
2520*44704f69SBart Van Assche
2521*44704f69SBart Van Assche static const char * nv_cache_unit[] = {
2522*44704f69SBart Van Assche "Bytes", "KiB", "MiB", "GiB"
2523*44704f69SBart Van Assche };
2524*44704f69SBart Van Assche
2525*44704f69SBart Van Assche static const char * invop_type_desc[] = {
2526*44704f69SBart Van Assche "SEND DIAGNOSTIC page code error", "SEND DIAGNOSTIC page format error",
2527*44704f69SBart Van Assche "Reserved", "Vendor specific error"
2528*44704f69SBart Van Assche };
2529*44704f69SBart Van Assche
2530*44704f69SBart Van Assche static void
enc_status_helper(const char * pad,const uint8_t * statp,int etype,bool abridged,const struct opts_t * op)2531*44704f69SBart Van Assche enc_status_helper(const char * pad, const uint8_t * statp, int etype,
2532*44704f69SBart Van Assche bool abridged, const struct opts_t * op)
2533*44704f69SBart Van Assche {
2534*44704f69SBart Van Assche int res, a, b, ct, bblen;
2535*44704f69SBart Van Assche bool nofilter = ! op->do_filter;
2536*44704f69SBart Van Assche char bb[128];
2537*44704f69SBart Van Assche
2538*44704f69SBart Van Assche
2539*44704f69SBart Van Assche if (op->inner_hex) {
2540*44704f69SBart Van Assche printf("%s%02x %02x %02x %02x\n", pad, statp[0], statp[1], statp[2],
2541*44704f69SBart Van Assche statp[3]);
2542*44704f69SBart Van Assche return;
2543*44704f69SBart Van Assche }
2544*44704f69SBart Van Assche if (! abridged)
2545*44704f69SBart Van Assche printf("%sPredicted failure=%d, Disabled=%d, Swap=%d, status: %s\n",
2546*44704f69SBart Van Assche pad, !!(statp[0] & 0x40), !!(statp[0] & 0x20),
2547*44704f69SBart Van Assche !!(statp[0] & 0x10), elem_status_code_desc[statp[0] & 0xf]);
2548*44704f69SBart Van Assche switch (etype) { /* element types */
2549*44704f69SBart Van Assche case UNSPECIFIED_ETC:
2550*44704f69SBart Van Assche if (op->verbose)
2551*44704f69SBart Van Assche printf("%sstatus in hex: %02x %02x %02x %02x\n",
2552*44704f69SBart Van Assche pad, statp[0], statp[1], statp[2], statp[3]);
2553*44704f69SBart Van Assche break;
2554*44704f69SBart Van Assche case DEVICE_ETC:
2555*44704f69SBart Van Assche if (ARRAY_STATUS_DPC == op->page_code) { /* obsolete after SES-1 */
2556*44704f69SBart Van Assche if (nofilter || (0xf0 & statp[1]))
2557*44704f69SBart Van Assche printf("%sOK=%d, Reserved device=%d, Hot spare=%d, Cons "
2558*44704f69SBart Van Assche "check=%d\n", pad, !!(statp[1] & 0x80),
2559*44704f69SBart Van Assche !!(statp[1] & 0x40), !!(statp[1] & 0x20),
2560*44704f69SBart Van Assche !!(statp[1] & 0x10));
2561*44704f69SBart Van Assche if (nofilter || (0xf & statp[1]))
2562*44704f69SBart Van Assche printf("%sIn crit array=%d, In failed array=%d, Rebuild/"
2563*44704f69SBart Van Assche "remap=%d, R/R abort=%d\n", pad, !!(statp[1] & 0x8),
2564*44704f69SBart Van Assche !!(statp[1] & 0x4), !!(statp[1] & 0x2),
2565*44704f69SBart Van Assche !!(statp[1] & 0x1));
2566*44704f69SBart Van Assche if (nofilter || ((0x46 & statp[2]) || (0x8 & statp[3])))
2567*44704f69SBart Van Assche printf("%sDo not remove=%d, RMV=%d, Ident=%d, Enable bypass "
2568*44704f69SBart Van Assche "A=%d\n", pad, !!(statp[2] & 0x40), !!(statp[2] & 0x4),
2569*44704f69SBart Van Assche !!(statp[2] & 0x2), !!(statp[3] & 0x8));
2570*44704f69SBart Van Assche if (nofilter || (0x7 & statp[3]))
2571*44704f69SBart Van Assche printf("%sEnable bypass B=%d, Bypass A enabled=%d, Bypass B "
2572*44704f69SBart Van Assche "enabled=%d\n", pad, !!(statp[3] & 0x4),
2573*44704f69SBart Van Assche !!(statp[3] & 0x2), !!(statp[3] & 0x1));
2574*44704f69SBart Van Assche break;
2575*44704f69SBart Van Assche }
2576*44704f69SBart Van Assche printf("%sSlot address: %d\n", pad, statp[1]);
2577*44704f69SBart Van Assche if (nofilter || (0xe0 & statp[2]))
2578*44704f69SBart Van Assche printf("%sApp client bypassed A=%d, Do not remove=%d, Enc "
2579*44704f69SBart Van Assche "bypassed A=%d\n", pad, !!(statp[2] & 0x80),
2580*44704f69SBart Van Assche !!(statp[2] & 0x40), !!(statp[2] & 0x20));
2581*44704f69SBart Van Assche if (nofilter || (0x1c & statp[2]))
2582*44704f69SBart Van Assche printf("%sEnc bypassed B=%d, Ready to insert=%d, RMV=%d, Ident="
2583*44704f69SBart Van Assche "%d\n", pad, !!(statp[2] & 0x10), !!(statp[2] & 0x8),
2584*44704f69SBart Van Assche !!(statp[2] & 0x4), !!(statp[2] & 0x2));
2585*44704f69SBart Van Assche if (nofilter || ((1 & statp[2]) || (0xe0 & statp[3])))
2586*44704f69SBart Van Assche printf("%sReport=%d, App client bypassed B=%d, Fault sensed=%d, "
2587*44704f69SBart Van Assche "Fault requested=%d\n", pad, !!(statp[2] & 0x1),
2588*44704f69SBart Van Assche !!(statp[3] & 0x80), !!(statp[3] & 0x40),
2589*44704f69SBart Van Assche !!(statp[3] & 0x20));
2590*44704f69SBart Van Assche if (nofilter || (0x1e & statp[3]))
2591*44704f69SBart Van Assche printf("%sDevice off=%d, Bypassed A=%d, Bypassed B=%d, Device "
2592*44704f69SBart Van Assche "bypassed A=%d\n", pad, !!(statp[3] & 0x10),
2593*44704f69SBart Van Assche !!(statp[3] & 0x8), !!(statp[3] & 0x4), !!(statp[3] & 0x2));
2594*44704f69SBart Van Assche if (nofilter || (0x1 & statp[3]))
2595*44704f69SBart Van Assche printf("%sDevice bypassed B=%d\n", pad, !!(statp[3] & 0x1));
2596*44704f69SBart Van Assche break;
2597*44704f69SBart Van Assche case POWER_SUPPLY_ETC:
2598*44704f69SBart Van Assche if (nofilter || ((0xc0 & statp[1]) || (0xc & statp[2]))) {
2599*44704f69SBart Van Assche printf("%sIdent=%d, Do not remove=%d, DC overvoltage=%d, "
2600*44704f69SBart Van Assche "DC undervoltage=%d\n", pad, !!(statp[1] & 0x80),
2601*44704f69SBart Van Assche !!(statp[1] & 0x40), !!(statp[2] & 0x8),
2602*44704f69SBart Van Assche !!(statp[2] & 0x4));
2603*44704f69SBart Van Assche }
2604*44704f69SBart Van Assche if (nofilter || ((0x2 & statp[2]) || (0xf0 & statp[3])))
2605*44704f69SBart Van Assche printf("%sDC overcurrent=%d, Hot swap=%d, Fail=%d, Requested "
2606*44704f69SBart Van Assche "on=%d, Off=%d\n", pad, !!(statp[2] & 0x2),
2607*44704f69SBart Van Assche !!(statp[3] & 0x80), !!(statp[3] & 0x40),
2608*44704f69SBart Van Assche !!(statp[3] & 0x20), !!(statp[3] & 0x10));
2609*44704f69SBart Van Assche if (nofilter || (0xf & statp[3]))
2610*44704f69SBart Van Assche printf("%sOvertmp fail=%d, Temperature warn=%d, AC fail=%d, "
2611*44704f69SBart Van Assche "DC fail=%d\n", pad, !!(statp[3] & 0x8),
2612*44704f69SBart Van Assche !!(statp[3] & 0x4), !!(statp[3] & 0x2),
2613*44704f69SBart Van Assche !!(statp[3] & 0x1));
2614*44704f69SBart Van Assche break;
2615*44704f69SBart Van Assche case COOLING_ETC:
2616*44704f69SBart Van Assche if (nofilter || ((0xc0 & statp[1]) || (0xf0 & statp[3])))
2617*44704f69SBart Van Assche printf("%sIdent=%d, Do not remove=%d, Hot swap=%d, Fail=%d, "
2618*44704f69SBart Van Assche "Requested on=%d\n", pad, !!(statp[1] & 0x80),
2619*44704f69SBart Van Assche !!(statp[1] & 0x40), !!(statp[3] & 0x80),
2620*44704f69SBart Van Assche !!(statp[3] & 0x40), !!(statp[3] & 0x20));
2621*44704f69SBart Van Assche printf("%sOff=%d, Actual speed=%d rpm, Fan %s\n", pad,
2622*44704f69SBart Van Assche !!(statp[3] & 0x10),
2623*44704f69SBart Van Assche calc_fan_speed((statp[1] >> 3) & 0x3,
2624*44704f69SBart Van Assche ((0x7 & statp[1]) << 8) + statp[2]),
2625*44704f69SBart Van Assche actual_speed_desc[7 & statp[3]]);
2626*44704f69SBart Van Assche if (op->verbose > 1) /* show real field values */
2627*44704f69SBart Van Assche printf("%s [Fan_speed_factor=%d, Actual_fan_speed=%d]\n",
2628*44704f69SBart Van Assche pad, (statp[1] >> 3) & 0x3,
2629*44704f69SBart Van Assche ((0x7 & statp[1]) << 8) + statp[2]);
2630*44704f69SBart Van Assche break;
2631*44704f69SBart Van Assche case TEMPERATURE_ETC: /* temperature sensor */
2632*44704f69SBart Van Assche if (nofilter || ((0xc0 & statp[1]) || (0xf & statp[3]))) {
2633*44704f69SBart Van Assche printf("%sIdent=%d, Fail=%d, OT failure=%d, OT warning=%d, "
2634*44704f69SBart Van Assche "UT failure=%d\n", pad, !!(statp[1] & 0x80),
2635*44704f69SBart Van Assche !!(statp[1] & 0x40), !!(statp[3] & 0x8),
2636*44704f69SBart Van Assche !!(statp[3] & 0x4), !!(statp[3] & 0x2));
2637*44704f69SBart Van Assche printf("%sUT warning=%d\n", pad, !!(statp[3] & 0x1));
2638*44704f69SBart Van Assche }
2639*44704f69SBart Van Assche if (statp[2])
2640*44704f69SBart Van Assche printf("%sTemperature=%d C\n", pad,
2641*44704f69SBart Van Assche (int)statp[2] - TEMPERAT_OFF);
2642*44704f69SBart Van Assche else
2643*44704f69SBart Van Assche printf("%sTemperature: <reserved>\n", pad);
2644*44704f69SBart Van Assche break;
2645*44704f69SBart Van Assche case DOOR_ETC: /* OPEN field added in ses3r05 */
2646*44704f69SBart Van Assche if (nofilter || ((0xc0 & statp[1]) || (0x1 & statp[3])))
2647*44704f69SBart Van Assche printf("%sIdent=%d, Fail=%d, Open=%d, Unlock=%d\n", pad,
2648*44704f69SBart Van Assche !!(statp[1] & 0x80), !!(statp[1] & 0x40),
2649*44704f69SBart Van Assche !!(statp[3] & 0x2), !!(statp[3] & 0x1));
2650*44704f69SBart Van Assche break;
2651*44704f69SBart Van Assche case AUD_ALARM_ETC: /* audible alarm */
2652*44704f69SBart Van Assche if (nofilter || ((0xc0 & statp[1]) || (0xd0 & statp[3])))
2653*44704f69SBart Van Assche printf("%sIdent=%d, Fail=%d, Request mute=%d, Mute=%d, "
2654*44704f69SBart Van Assche "Remind=%d\n", pad, !!(statp[1] & 0x80),
2655*44704f69SBart Van Assche !!(statp[1] & 0x40), !!(statp[3] & 0x80),
2656*44704f69SBart Van Assche !!(statp[3] & 0x40), !!(statp[3] & 0x10));
2657*44704f69SBart Van Assche if (nofilter || (0xf & statp[3]))
2658*44704f69SBart Van Assche printf("%sTone indicator: Info=%d, Non-crit=%d, Crit=%d, "
2659*44704f69SBart Van Assche "Unrecov=%d\n", pad, !!(statp[3] & 0x8), !!(statp[3] & 0x4),
2660*44704f69SBart Van Assche !!(statp[3] & 0x2), !!(statp[3] & 0x1));
2661*44704f69SBart Van Assche break;
2662*44704f69SBart Van Assche case ENC_SCELECTR_ETC: /* enclosure services controller electronics */
2663*44704f69SBart Van Assche if (nofilter || (0xe0 & statp[1]) || (0x1 & statp[2]) ||
2664*44704f69SBart Van Assche (0x80 & statp[3]))
2665*44704f69SBart Van Assche printf("%sIdent=%d, Fail=%d, Do not remove=%d, Report=%d, "
2666*44704f69SBart Van Assche "Hot swap=%d\n", pad, !!(statp[1] & 0x80),
2667*44704f69SBart Van Assche !!(statp[1] & 0x40), !!(statp[1] & 0x20),
2668*44704f69SBart Van Assche !!(statp[2] & 0x1), !!(statp[3] & 0x80));
2669*44704f69SBart Van Assche break;
2670*44704f69SBart Van Assche case SCC_CELECTR_ETC: /* SCC controller electronics */
2671*44704f69SBart Van Assche if (nofilter || ((0xc0 & statp[1]) || (0x1 & statp[2])))
2672*44704f69SBart Van Assche printf("%sIdent=%d, Fail=%d, Report=%d\n", pad,
2673*44704f69SBart Van Assche !!(statp[1] & 0x80), !!(statp[1] & 0x40),
2674*44704f69SBart Van Assche !!(statp[2] & 0x1));
2675*44704f69SBart Van Assche break;
2676*44704f69SBart Van Assche case NV_CACHE_ETC: /* Non volatile cache */
2677*44704f69SBart Van Assche res = sg_get_unaligned_be16(statp + 2);
2678*44704f69SBart Van Assche printf("%sIdent=%d, Fail=%d, Size multiplier=%d, Non volatile cache "
2679*44704f69SBart Van Assche "size=0x%x\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40),
2680*44704f69SBart Van Assche (statp[1] & 0x3), res);
2681*44704f69SBart Van Assche printf("%sHence non volatile cache size: %d %s\n", pad, res,
2682*44704f69SBart Van Assche nv_cache_unit[statp[1] & 0x3]);
2683*44704f69SBart Van Assche break;
2684*44704f69SBart Van Assche case INV_OP_REASON_ETC: /* Invalid operation reason */
2685*44704f69SBart Van Assche res = ((statp[1] >> 6) & 3);
2686*44704f69SBart Van Assche printf("%sInvop type=%d %s\n", pad, res, invop_type_desc[res]);
2687*44704f69SBart Van Assche switch (res) {
2688*44704f69SBart Van Assche case 0:
2689*44704f69SBart Van Assche printf("%sPage not supported=%d\n", pad, (statp[1] & 1));
2690*44704f69SBart Van Assche break;
2691*44704f69SBart Van Assche case 1:
2692*44704f69SBart Van Assche printf("%sByte offset=%d, bit number=%d\n", pad,
2693*44704f69SBart Van Assche sg_get_unaligned_be16(statp + 2), (statp[1] & 7));
2694*44704f69SBart Van Assche break;
2695*44704f69SBart Van Assche case 2:
2696*44704f69SBart Van Assche case 3:
2697*44704f69SBart Van Assche printf("%slast 3 bytes (hex): %02x %02x %02x\n", pad, statp[1],
2698*44704f69SBart Van Assche statp[2], statp[3]);
2699*44704f69SBart Van Assche break;
2700*44704f69SBart Van Assche }
2701*44704f69SBart Van Assche break;
2702*44704f69SBart Van Assche case UI_POWER_SUPPLY_ETC: /* Uninterruptible power supply */
2703*44704f69SBart Van Assche if (0 == statp[1])
2704*44704f69SBart Van Assche printf("%sBattery status: discharged or unknown\n", pad);
2705*44704f69SBart Van Assche else if (255 == statp[1])
2706*44704f69SBart Van Assche printf("%sBattery status: 255 or more minutes remaining\n", pad);
2707*44704f69SBart Van Assche else
2708*44704f69SBart Van Assche printf("%sBattery status: %d minutes remaining\n", pad, statp[1]);
2709*44704f69SBart Van Assche if (nofilter || (0xf8 & statp[2]))
2710*44704f69SBart Van Assche printf("%sAC low=%d, AC high=%d, AC qual=%d, AC fail=%d, DC fail="
2711*44704f69SBart Van Assche "%d\n", pad, !!(statp[2] & 0x80), !!(statp[2] & 0x40),
2712*44704f69SBart Van Assche !!(statp[2] & 0x20), !!(statp[2] & 0x10),
2713*44704f69SBart Van Assche !!(statp[2] & 0x8));
2714*44704f69SBart Van Assche if (nofilter || ((0x7 & statp[2]) || (0xe3 & statp[3]))) {
2715*44704f69SBart Van Assche printf("%sUPS fail=%d, Warn=%d, Intf fail=%d, Ident=%d, Fail=%d, "
2716*44704f69SBart Van Assche "Do not remove=%d\n", pad, !!(statp[2] & 0x4),
2717*44704f69SBart Van Assche !!(statp[2] & 0x2), !!(statp[2] & 0x1),
2718*44704f69SBart Van Assche !!(statp[3] & 0x80), !!(statp[3] & 0x40),
2719*44704f69SBart Van Assche !!(statp[3] & 0x20));
2720*44704f69SBart Van Assche printf("%sBatt fail=%d, BPF=%d\n", pad, !!(statp[3] & 0x2),
2721*44704f69SBart Van Assche !!(statp[3] & 0x1));
2722*44704f69SBart Van Assche }
2723*44704f69SBart Van Assche break;
2724*44704f69SBart Van Assche case DISPLAY_ETC: /* Display (ses2r15) */
2725*44704f69SBart Van Assche if (nofilter || (0xc0 & statp[1])) {
2726*44704f69SBart Van Assche int dms = statp[1] & 0x3;
2727*44704f69SBart Van Assche
2728*44704f69SBart Van Assche printf("%sIdent=%d, Fail=%d, Display mode status=%d", pad,
2729*44704f69SBart Van Assche !!(statp[1] & 0x80), !!(statp[1] & 0x40), dms);
2730*44704f69SBart Van Assche if ((1 == dms) || (2 == dms)) {
2731*44704f69SBart Van Assche uint16_t dcs = sg_get_unaligned_be16(statp + 2);
2732*44704f69SBart Van Assche
2733*44704f69SBart Van Assche printf(", Display character status=0x%x", dcs);
2734*44704f69SBart Van Assche if (statp[2] && (0 == statp[3]))
2735*44704f69SBart Van Assche printf(" ['%c']", statp[2]);
2736*44704f69SBart Van Assche }
2737*44704f69SBart Van Assche printf("\n");
2738*44704f69SBart Van Assche }
2739*44704f69SBart Van Assche break;
2740*44704f69SBart Van Assche case KEY_PAD_ETC: /* Key pad entry */
2741*44704f69SBart Van Assche if (nofilter || (0xc0 & statp[1]))
2742*44704f69SBart Van Assche printf("%sIdent=%d, Fail=%d\n", pad, !!(statp[1] & 0x80),
2743*44704f69SBart Van Assche !!(statp[1] & 0x40));
2744*44704f69SBart Van Assche break;
2745*44704f69SBart Van Assche case ENCLOSURE_ETC:
2746*44704f69SBart Van Assche a = ((statp[2] >> 2) & 0x3f);
2747*44704f69SBart Van Assche if (nofilter || ((0x80 & statp[1]) || a || (0x2 & statp[2])))
2748*44704f69SBart Van Assche printf("%sIdent=%d, Time until power cycle=%d, "
2749*44704f69SBart Van Assche "Failure indication=%d\n", pad, !!(statp[1] & 0x80),
2750*44704f69SBart Van Assche a, !!(statp[2] & 0x2));
2751*44704f69SBart Van Assche b = ((statp[3] >> 2) & 0x3f);
2752*44704f69SBart Van Assche if (nofilter || (0x1 & statp[2]) || a || b)
2753*44704f69SBart Van Assche printf("%sWarning indication=%d, Requested power off "
2754*44704f69SBart Van Assche "duration=%d\n", pad, !!(statp[2] & 0x1), b);
2755*44704f69SBart Van Assche if (nofilter || (0x3 & statp[3]))
2756*44704f69SBart Van Assche printf("%sFailure requested=%d, Warning requested=%d\n",
2757*44704f69SBart Van Assche pad, !!(statp[3] & 0x2), !!(statp[3] & 0x1));
2758*44704f69SBart Van Assche break;
2759*44704f69SBart Van Assche case SCSI_PORT_TRAN_ETC: /* SCSI port/transceiver */
2760*44704f69SBart Van Assche if (nofilter || ((0xc0 & statp[1]) || (0x1 & statp[2]) ||
2761*44704f69SBart Van Assche (0x13 & statp[3])))
2762*44704f69SBart Van Assche printf("%sIdent=%d, Fail=%d, Report=%d, Disabled=%d, Loss of "
2763*44704f69SBart Van Assche "link=%d, Xmit fail=%d\n", pad, !!(statp[1] & 0x80),
2764*44704f69SBart Van Assche !!(statp[1] & 0x40), !!(statp[2] & 0x1),
2765*44704f69SBart Van Assche !!(statp[3] & 0x10), !!(statp[3] & 0x2),
2766*44704f69SBart Van Assche !!(statp[3] & 0x1));
2767*44704f69SBart Van Assche break;
2768*44704f69SBart Van Assche case LANGUAGE_ETC:
2769*44704f69SBart Van Assche printf("%sIdent=%d, Language code: %.2s\n", pad, !!(statp[1] & 0x80),
2770*44704f69SBart Van Assche statp + 2);
2771*44704f69SBart Van Assche break;
2772*44704f69SBart Van Assche case COMM_PORT_ETC: /* Communication port */
2773*44704f69SBart Van Assche if (nofilter || ((0xc0 & statp[1]) || (0x1 & statp[3])))
2774*44704f69SBart Van Assche printf("%sIdent=%d, Fail=%d, Disabled=%d\n", pad,
2775*44704f69SBart Van Assche !!(statp[1] & 0x80), !!(statp[1] & 0x40),
2776*44704f69SBart Van Assche !!(statp[3] & 0x1));
2777*44704f69SBart Van Assche break;
2778*44704f69SBart Van Assche case VOLT_SENSOR_ETC: /* Voltage sensor */
2779*44704f69SBart Van Assche if (nofilter || (0xcf & statp[1])) {
2780*44704f69SBart Van Assche printf("%sIdent=%d, Fail=%d, Warn Over=%d, Warn Under=%d, "
2781*44704f69SBart Van Assche "Crit Over=%d\n", pad, !!(statp[1] & 0x80),
2782*44704f69SBart Van Assche !!(statp[1] & 0x40), !!(statp[1] & 0x8),
2783*44704f69SBart Van Assche !!(statp[1] & 0x4), !!(statp[1] & 0x2));
2784*44704f69SBart Van Assche printf("%sCrit Under=%d\n", pad, !!(statp[1] & 0x1));
2785*44704f69SBart Van Assche }
2786*44704f69SBart Van Assche #ifdef SG_LIB_MINGW
2787*44704f69SBart Van Assche printf("%sVoltage: %g volts\n", pad,
2788*44704f69SBart Van Assche ((int)(short)sg_get_unaligned_be16(statp + 2) / 100.0));
2789*44704f69SBart Van Assche #else
2790*44704f69SBart Van Assche printf("%sVoltage: %.2f volts\n", pad,
2791*44704f69SBart Van Assche ((int)(short)sg_get_unaligned_be16(statp + 2) / 100.0));
2792*44704f69SBart Van Assche #endif
2793*44704f69SBart Van Assche break;
2794*44704f69SBart Van Assche case CURR_SENSOR_ETC: /* Current sensor */
2795*44704f69SBart Van Assche if (nofilter || (0xca & statp[1]))
2796*44704f69SBart Van Assche printf("%sIdent=%d, Fail=%d, Warn Over=%d, Crit Over=%d\n",
2797*44704f69SBart Van Assche pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40),
2798*44704f69SBart Van Assche !!(statp[1] & 0x8), !!(statp[1] & 0x2));
2799*44704f69SBart Van Assche #ifdef SG_LIB_MINGW
2800*44704f69SBart Van Assche printf("%sCurrent: %g amps\n", pad,
2801*44704f69SBart Van Assche ((int)(short)sg_get_unaligned_be16(statp + 2) / 100.0));
2802*44704f69SBart Van Assche #else
2803*44704f69SBart Van Assche printf("%sCurrent: %.2f amps\n", pad,
2804*44704f69SBart Van Assche ((int)(short)sg_get_unaligned_be16(statp + 2) / 100.0));
2805*44704f69SBart Van Assche #endif
2806*44704f69SBart Van Assche break;
2807*44704f69SBart Van Assche case SCSI_TPORT_ETC: /* SCSI target port */
2808*44704f69SBart Van Assche if (nofilter || ((0xc0 & statp[1]) || (0x1 & statp[2]) ||
2809*44704f69SBart Van Assche (0x1 & statp[3])))
2810*44704f69SBart Van Assche printf("%sIdent=%d, Fail=%d, Report=%d, Enabled=%d\n", pad,
2811*44704f69SBart Van Assche !!(statp[1] & 0x80), !!(statp[1] & 0x40),
2812*44704f69SBart Van Assche !!(statp[2] & 0x1), !!(statp[3] & 0x1));
2813*44704f69SBart Van Assche break;
2814*44704f69SBart Van Assche case SCSI_IPORT_ETC: /* SCSI initiator port */
2815*44704f69SBart Van Assche if (nofilter || ((0xc0 & statp[1]) || (0x1 & statp[2]) ||
2816*44704f69SBart Van Assche (0x1 & statp[3])))
2817*44704f69SBart Van Assche printf("%sIdent=%d, Fail=%d, Report=%d, Enabled=%d\n", pad,
2818*44704f69SBart Van Assche !!(statp[1] & 0x80), !!(statp[1] & 0x40),
2819*44704f69SBart Van Assche !!(statp[2] & 0x1), !!(statp[3] & 0x1));
2820*44704f69SBart Van Assche break;
2821*44704f69SBart Van Assche case SIMPLE_SUBENC_ETC: /* Simple subenclosure */
2822*44704f69SBart Van Assche printf("%sIdent=%d, Fail=%d, Short enclosure status: 0x%x\n", pad,
2823*44704f69SBart Van Assche !!(statp[1] & 0x80), !!(statp[1] & 0x40), statp[3]);
2824*44704f69SBart Van Assche break;
2825*44704f69SBart Van Assche case ARRAY_DEV_ETC: /* Array device */
2826*44704f69SBart Van Assche if (nofilter || (0xf0 & statp[1]))
2827*44704f69SBart Van Assche printf("%sOK=%d, Reserved device=%d, Hot spare=%d, Cons check="
2828*44704f69SBart Van Assche "%d\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40),
2829*44704f69SBart Van Assche !!(statp[1] & 0x20), !!(statp[1] & 0x10));
2830*44704f69SBart Van Assche if (nofilter || (0xf & statp[1]))
2831*44704f69SBart Van Assche printf("%sIn crit array=%d, In failed array=%d, Rebuild/remap=%d"
2832*44704f69SBart Van Assche ", R/R abort=%d\n", pad, !!(statp[1] & 0x8),
2833*44704f69SBart Van Assche !!(statp[1] & 0x4), !!(statp[1] & 0x2),
2834*44704f69SBart Van Assche !!(statp[1] & 0x1));
2835*44704f69SBart Van Assche if (nofilter || (0xf0 & statp[2]))
2836*44704f69SBart Van Assche printf("%sApp client bypass A=%d, Do not remove=%d, Enc bypass "
2837*44704f69SBart Van Assche "A=%d, Enc bypass B=%d\n", pad, !!(statp[2] & 0x80),
2838*44704f69SBart Van Assche !!(statp[2] & 0x40), !!(statp[2] & 0x20),
2839*44704f69SBart Van Assche !!(statp[2] & 0x10));
2840*44704f69SBart Van Assche if (nofilter || (0xf & statp[2]))
2841*44704f69SBart Van Assche printf("%sReady to insert=%d, RMV=%d, Ident=%d, Report=%d\n",
2842*44704f69SBart Van Assche pad, !!(statp[2] & 0x8), !!(statp[2] & 0x4),
2843*44704f69SBart Van Assche !!(statp[2] & 0x2), !!(statp[2] & 0x1));
2844*44704f69SBart Van Assche if (nofilter || (0xf0 & statp[3]))
2845*44704f69SBart Van Assche printf("%sApp client bypass B=%d, Fault sensed=%d, Fault reqstd="
2846*44704f69SBart Van Assche "%d, Device off=%d\n", pad, !!(statp[3] & 0x80),
2847*44704f69SBart Van Assche !!(statp[3] & 0x40), !!(statp[3] & 0x20),
2848*44704f69SBart Van Assche !!(statp[3] & 0x10));
2849*44704f69SBart Van Assche if (nofilter || (0xf & statp[3]))
2850*44704f69SBart Van Assche printf("%sBypassed A=%d, Bypassed B=%d, Dev bypassed A=%d, "
2851*44704f69SBart Van Assche "Dev bypassed B=%d\n",
2852*44704f69SBart Van Assche pad, !!(statp[3] & 0x8), !!(statp[3] & 0x4),
2853*44704f69SBart Van Assche !!(statp[3] & 0x2), !!(statp[3] & 0x1));
2854*44704f69SBart Van Assche break;
2855*44704f69SBart Van Assche case SAS_EXPANDER_ETC:
2856*44704f69SBart Van Assche printf("%sIdent=%d, Fail=%d\n", pad, !!(statp[1] & 0x80),
2857*44704f69SBart Van Assche !!(statp[1] & 0x40));
2858*44704f69SBart Van Assche break;
2859*44704f69SBart Van Assche case SAS_CONNECTOR_ETC: /* OC (overcurrent) added in ses3r07 */
2860*44704f69SBart Van Assche ct = (statp[1] & 0x7f);
2861*44704f69SBart Van Assche bblen = sizeof(bb);
2862*44704f69SBart Van Assche if (abridged)
2863*44704f69SBart Van Assche printf("%s%s, pl=%d", pad,
2864*44704f69SBart Van Assche find_sas_connector_type(ct, true, bb, bblen), statp[2]);
2865*44704f69SBart Van Assche else {
2866*44704f69SBart Van Assche printf("%sIdent=%d, %s\n", pad, !!(statp[1] & 0x80),
2867*44704f69SBart Van Assche find_sas_connector_type(ct, false, bb, bblen));
2868*44704f69SBart Van Assche /* Mated added in ses3r10 */
2869*44704f69SBart Van Assche printf("%sConnector physical link=0x%x, Mated=%d, Fail=%d, "
2870*44704f69SBart Van Assche "OC=%d\n", pad, statp[2], !!(statp[3] & 0x80),
2871*44704f69SBart Van Assche !!(statp[3] & 0x40), !!(statp[3] & 0x20));
2872*44704f69SBart Van Assche }
2873*44704f69SBart Van Assche break;
2874*44704f69SBart Van Assche default:
2875*44704f69SBart Van Assche if (etype < 0x80)
2876*44704f69SBart Van Assche printf("%sUnknown element type, status in hex: %02x %02x %02x "
2877*44704f69SBart Van Assche "%02x\n", pad, statp[0], statp[1], statp[2], statp[3]);
2878*44704f69SBart Van Assche else
2879*44704f69SBart Van Assche printf("%sVendor specific element type, status in hex: %02x "
2880*44704f69SBart Van Assche "%02x %02x %02x\n", pad, statp[0], statp[1], statp[2],
2881*44704f69SBart Van Assche statp[3]);
2882*44704f69SBart Van Assche break;
2883*44704f69SBart Van Assche }
2884*44704f69SBart Van Assche }
2885*44704f69SBart Van Assche
2886*44704f69SBart Van Assche /* ENC_STATUS_DPC [0x2]
2887*44704f69SBart Van Assche * Display enclosure status diagnostic page. */
2888*44704f69SBart Van Assche static void
enc_status_dp(const struct th_es_t * tesp,uint32_t ref_gen_code,const uint8_t * resp,int resp_len,const struct opts_t * op)2889*44704f69SBart Van Assche enc_status_dp(const struct th_es_t * tesp, uint32_t ref_gen_code,
2890*44704f69SBart Van Assche const uint8_t * resp, int resp_len,
2891*44704f69SBart Van Assche const struct opts_t * op)
2892*44704f69SBart Van Assche {
2893*44704f69SBart Van Assche int j, k;
2894*44704f69SBart Van Assche uint32_t gen_code;
2895*44704f69SBart Van Assche bool got1, match_ind_th;
2896*44704f69SBart Van Assche const uint8_t * bp;
2897*44704f69SBart Van Assche const uint8_t * last_bp;
2898*44704f69SBart Van Assche const struct type_desc_hdr_t * tdhp = tesp->th_base;
2899*44704f69SBart Van Assche char b[64];
2900*44704f69SBart Van Assche
2901*44704f69SBart Van Assche printf("Enclosure Status diagnostic page:\n");
2902*44704f69SBart Van Assche if (resp_len < 4)
2903*44704f69SBart Van Assche goto truncated;
2904*44704f69SBart Van Assche printf(" INVOP=%d, INFO=%d, NON-CRIT=%d, CRIT=%d, UNRECOV=%d\n",
2905*44704f69SBart Van Assche !!(resp[1] & 0x10), !!(resp[1] & 0x8), !!(resp[1] & 0x4),
2906*44704f69SBart Van Assche !!(resp[1] & 0x2), !!(resp[1] & 0x1));
2907*44704f69SBart Van Assche last_bp = resp + resp_len - 1;
2908*44704f69SBart Van Assche if (resp_len < 8)
2909*44704f69SBart Van Assche goto truncated;
2910*44704f69SBart Van Assche gen_code = sg_get_unaligned_be32(resp + 4);
2911*44704f69SBart Van Assche printf(" generation code: 0x%x\n", gen_code);
2912*44704f69SBart Van Assche if (ref_gen_code != gen_code) {
2913*44704f69SBart Van Assche pr2serr(" <<state of enclosure changed, please try again>>\n");
2914*44704f69SBart Van Assche return;
2915*44704f69SBart Van Assche }
2916*44704f69SBart Van Assche printf(" status descriptor list\n");
2917*44704f69SBart Van Assche bp = resp + 8;
2918*44704f69SBart Van Assche for (k = 0, got1 = false; k < tesp->num_ths; ++k, ++tdhp) {
2919*44704f69SBart Van Assche if ((bp + 3) > last_bp)
2920*44704f69SBart Van Assche goto truncated;
2921*44704f69SBart Van Assche match_ind_th = (op->ind_given && (k == op->ind_th));
2922*44704f69SBart Van Assche if ((! op->ind_given) || (match_ind_th && (-1 == op->ind_indiv))) {
2923*44704f69SBart Van Assche printf(" Element type: %s, subenclosure id: %d [ti=%d]\n",
2924*44704f69SBart Van Assche etype_str(tdhp->etype, b, sizeof(b)), tdhp->se_id, k);
2925*44704f69SBart Van Assche printf(" Overall descriptor:\n");
2926*44704f69SBart Van Assche enc_status_helper(" ", bp, tdhp->etype, false, op);
2927*44704f69SBart Van Assche got1 = true;
2928*44704f69SBart Van Assche }
2929*44704f69SBart Van Assche for (bp += 4, j = 0; j < tdhp->num_elements; ++j, bp += 4) {
2930*44704f69SBart Van Assche if (op->ind_given) {
2931*44704f69SBart Van Assche if ((! match_ind_th) || (-1 == op->ind_indiv) ||
2932*44704f69SBart Van Assche (! match_ind_indiv(j, op)))
2933*44704f69SBart Van Assche continue;
2934*44704f69SBart Van Assche }
2935*44704f69SBart Van Assche printf(" Element %d descriptor:\n", j);
2936*44704f69SBart Van Assche enc_status_helper(" ", bp, tdhp->etype, false, op);
2937*44704f69SBart Van Assche got1 = true;
2938*44704f69SBart Van Assche }
2939*44704f69SBart Van Assche }
2940*44704f69SBart Van Assche if (op->ind_given && (! got1)) {
2941*44704f69SBart Van Assche printf(" >>> no match on --index=%d,%d", op->ind_th,
2942*44704f69SBart Van Assche op->ind_indiv);
2943*44704f69SBart Van Assche if (op->ind_indiv_last > op->ind_indiv)
2944*44704f69SBart Van Assche printf("-%d\n", op->ind_indiv_last);
2945*44704f69SBart Van Assche else
2946*44704f69SBart Van Assche printf("\n");
2947*44704f69SBart Van Assche }
2948*44704f69SBart Van Assche return;
2949*44704f69SBart Van Assche truncated:
2950*44704f69SBart Van Assche pr2serr(" <<<enc: response too short>>>\n");
2951*44704f69SBart Van Assche return;
2952*44704f69SBart Van Assche }
2953*44704f69SBart Van Assche
2954*44704f69SBart Van Assche /* ARRAY_STATUS_DPC [0x6]
2955*44704f69SBart Van Assche * Display array status diagnostic page. */
2956*44704f69SBart Van Assche static void
array_status_dp(const struct th_es_t * tesp,uint32_t ref_gen_code,const uint8_t * resp,int resp_len,const struct opts_t * op)2957*44704f69SBart Van Assche array_status_dp(const struct th_es_t * tesp, uint32_t ref_gen_code,
2958*44704f69SBart Van Assche const uint8_t * resp, int resp_len,
2959*44704f69SBart Van Assche const struct opts_t * op)
2960*44704f69SBart Van Assche {
2961*44704f69SBart Van Assche int j, k;
2962*44704f69SBart Van Assche uint32_t gen_code;
2963*44704f69SBart Van Assche bool got1, match_ind_th;
2964*44704f69SBart Van Assche const uint8_t * bp;
2965*44704f69SBart Van Assche const uint8_t * last_bp;
2966*44704f69SBart Van Assche const struct type_desc_hdr_t * tdhp = tesp->th_base;
2967*44704f69SBart Van Assche char b[64];
2968*44704f69SBart Van Assche
2969*44704f69SBart Van Assche printf("Array Status diagnostic page:\n");
2970*44704f69SBart Van Assche if (resp_len < 4)
2971*44704f69SBart Van Assche goto truncated;
2972*44704f69SBart Van Assche printf(" INVOP=%d, INFO=%d, NON-CRIT=%d, CRIT=%d, UNRECOV=%d\n",
2973*44704f69SBart Van Assche !!(resp[1] & 0x10), !!(resp[1] & 0x8), !!(resp[1] & 0x4),
2974*44704f69SBart Van Assche !!(resp[1] & 0x2), !!(resp[1] & 0x1));
2975*44704f69SBart Van Assche last_bp = resp + resp_len - 1;
2976*44704f69SBart Van Assche if (resp_len < 8)
2977*44704f69SBart Van Assche goto truncated;
2978*44704f69SBart Van Assche gen_code = sg_get_unaligned_be32(resp + 4);
2979*44704f69SBart Van Assche printf(" generation code: 0x%x\n", gen_code);
2980*44704f69SBart Van Assche if (ref_gen_code != gen_code) {
2981*44704f69SBart Van Assche pr2serr(" <<state of enclosure changed, please try again>>\n");
2982*44704f69SBart Van Assche return;
2983*44704f69SBart Van Assche }
2984*44704f69SBart Van Assche printf(" status descriptor list\n");
2985*44704f69SBart Van Assche bp = resp + 8;
2986*44704f69SBart Van Assche for (k = 0, got1 = false; k < tesp->num_ths; ++k, ++tdhp) {
2987*44704f69SBart Van Assche if ((bp + 3) > last_bp)
2988*44704f69SBart Van Assche goto truncated;
2989*44704f69SBart Van Assche match_ind_th = (op->ind_given && (k == op->ind_th));
2990*44704f69SBart Van Assche if ((! op->ind_given) || (match_ind_th && (-1 == op->ind_indiv))) {
2991*44704f69SBart Van Assche printf(" Element type: %s, subenclosure id: %d [ti=%d]\n",
2992*44704f69SBart Van Assche etype_str(tdhp->etype, b, sizeof(b)), tdhp->se_id, k);
2993*44704f69SBart Van Assche printf(" Overall descriptor:\n");
2994*44704f69SBart Van Assche enc_status_helper(" ", bp, tdhp->etype, false, op);
2995*44704f69SBart Van Assche got1 = true;
2996*44704f69SBart Van Assche }
2997*44704f69SBart Van Assche for (bp += 4, j = 0; j < tdhp->num_elements; ++j, bp += 4) {
2998*44704f69SBart Van Assche if (op->ind_given) {
2999*44704f69SBart Van Assche if ((! match_ind_th) || (-1 == op->ind_indiv) ||
3000*44704f69SBart Van Assche (! match_ind_indiv(j, op)))
3001*44704f69SBart Van Assche continue;
3002*44704f69SBart Van Assche }
3003*44704f69SBart Van Assche printf(" Element %d descriptor:\n", j);
3004*44704f69SBart Van Assche enc_status_helper(" ", bp, tdhp->etype, false, op);
3005*44704f69SBart Van Assche got1 = true;
3006*44704f69SBart Van Assche }
3007*44704f69SBart Van Assche }
3008*44704f69SBart Van Assche if (op->ind_given && (! got1)) {
3009*44704f69SBart Van Assche printf(" >>> no match on --index=%d,%d", op->ind_th,
3010*44704f69SBart Van Assche op->ind_indiv);
3011*44704f69SBart Van Assche if (op->ind_indiv_last > op->ind_indiv)
3012*44704f69SBart Van Assche printf("-%d\n", op->ind_indiv_last);
3013*44704f69SBart Van Assche else
3014*44704f69SBart Van Assche printf("\n");
3015*44704f69SBart Van Assche }
3016*44704f69SBart Van Assche return;
3017*44704f69SBart Van Assche truncated:
3018*44704f69SBart Van Assche pr2serr(" <<<arr: response too short>>>\n");
3019*44704f69SBart Van Assche return;
3020*44704f69SBart Van Assche }
3021*44704f69SBart Van Assche
3022*44704f69SBart Van Assche static char *
reserved_or_num(char * buff,int buff_len,int num,int reserve_num)3023*44704f69SBart Van Assche reserved_or_num(char * buff, int buff_len, int num, int reserve_num)
3024*44704f69SBart Van Assche {
3025*44704f69SBart Van Assche if (num == reserve_num)
3026*44704f69SBart Van Assche strncpy(buff, "<res>", buff_len);
3027*44704f69SBart Van Assche else
3028*44704f69SBart Van Assche snprintf(buff, buff_len, "%d", num);
3029*44704f69SBart Van Assche if (buff_len > 0)
3030*44704f69SBart Van Assche buff[buff_len - 1] = '\0';
3031*44704f69SBart Van Assche return buff;
3032*44704f69SBart Van Assche }
3033*44704f69SBart Van Assche
3034*44704f69SBart Van Assche static void
threshold_helper(const char * header,const char * pad,const uint8_t * tp,int etype,const struct opts_t * op)3035*44704f69SBart Van Assche threshold_helper(const char * header, const char * pad,
3036*44704f69SBart Van Assche const uint8_t *tp, int etype,
3037*44704f69SBart Van Assche const struct opts_t * op)
3038*44704f69SBart Van Assche {
3039*44704f69SBart Van Assche char b[128];
3040*44704f69SBart Van Assche char b2[128];
3041*44704f69SBart Van Assche
3042*44704f69SBart Van Assche if (op->inner_hex) {
3043*44704f69SBart Van Assche if (header)
3044*44704f69SBart Van Assche printf("%s", header);
3045*44704f69SBart Van Assche printf("%s%02x %02x %02x %02x\n", pad, tp[0], tp[1], tp[2], tp[3]);
3046*44704f69SBart Van Assche return;
3047*44704f69SBart Van Assche }
3048*44704f69SBart Van Assche switch (etype) {
3049*44704f69SBart Van Assche case 0x4: /*temperature */
3050*44704f69SBart Van Assche if (header)
3051*44704f69SBart Van Assche printf("%s", header);
3052*44704f69SBart Van Assche printf("%shigh critical=%s, high warning=%s", pad,
3053*44704f69SBart Van Assche reserved_or_num(b, 128, tp[0] - TEMPERAT_OFF, -TEMPERAT_OFF),
3054*44704f69SBart Van Assche reserved_or_num(b2, 128, tp[1] - TEMPERAT_OFF, -TEMPERAT_OFF));
3055*44704f69SBart Van Assche if (op->do_filter && (0 == tp[2]) && (0 == tp[3])) {
3056*44704f69SBart Van Assche printf(" (in Celsius)\n");
3057*44704f69SBart Van Assche break;
3058*44704f69SBart Van Assche }
3059*44704f69SBart Van Assche printf("\n%slow warning=%s, low critical=%s (in Celsius)\n", pad,
3060*44704f69SBart Van Assche reserved_or_num(b, 128, tp[2] - TEMPERAT_OFF, -TEMPERAT_OFF),
3061*44704f69SBart Van Assche reserved_or_num(b2, 128, tp[3] - TEMPERAT_OFF, -TEMPERAT_OFF));
3062*44704f69SBart Van Assche break;
3063*44704f69SBart Van Assche case 0xb: /* UPS */
3064*44704f69SBart Van Assche if (header)
3065*44704f69SBart Van Assche printf("%s", header);
3066*44704f69SBart Van Assche if (0 == tp[2])
3067*44704f69SBart Van Assche strcpy(b, "<vendor>");
3068*44704f69SBart Van Assche else
3069*44704f69SBart Van Assche snprintf(b, sizeof(b), "%d", tp[2]);
3070*44704f69SBart Van Assche printf("%slow warning=%s, ", pad, b);
3071*44704f69SBart Van Assche if (0 == tp[3])
3072*44704f69SBart Van Assche strcpy(b, "<vendor>");
3073*44704f69SBart Van Assche else
3074*44704f69SBart Van Assche snprintf(b, sizeof(b), "%d", tp[3]);
3075*44704f69SBart Van Assche printf("low critical=%s (in minutes)\n", b);
3076*44704f69SBart Van Assche break;
3077*44704f69SBart Van Assche case 0x12: /* voltage */
3078*44704f69SBart Van Assche if (header)
3079*44704f69SBart Van Assche printf("%s", header);
3080*44704f69SBart Van Assche #ifdef SG_LIB_MINGW
3081*44704f69SBart Van Assche printf("%shigh critical=%g %%, high warning=%g %% (above nominal "
3082*44704f69SBart Van Assche "voltage)\n", pad, 0.5 * tp[0], 0.5 * tp[1]);
3083*44704f69SBart Van Assche printf("%slow warning=%g %%, low critical=%g %% (below nominal "
3084*44704f69SBart Van Assche "voltage)\n", pad, 0.5 * tp[2], 0.5 * tp[3]);
3085*44704f69SBart Van Assche #else
3086*44704f69SBart Van Assche printf("%shigh critical=%.1f %%, high warning=%.1f %% (above nominal "
3087*44704f69SBart Van Assche "voltage)\n", pad, 0.5 * tp[0], 0.5 * tp[1]);
3088*44704f69SBart Van Assche printf("%slow warning=%.1f %%, low critical=%.1f %% (below nominal "
3089*44704f69SBart Van Assche "voltage)\n", pad, 0.5 * tp[2], 0.5 * tp[3]);
3090*44704f69SBart Van Assche #endif
3091*44704f69SBart Van Assche break;
3092*44704f69SBart Van Assche case 0x13: /* current */
3093*44704f69SBart Van Assche if (header)
3094*44704f69SBart Van Assche printf("%s", header);
3095*44704f69SBart Van Assche #ifdef SG_LIB_MINGW
3096*44704f69SBart Van Assche printf("%shigh critical=%g %%, high warning=%g %%", pad,
3097*44704f69SBart Van Assche 0.5 * tp[0], 0.5 * tp[1]);
3098*44704f69SBart Van Assche #else
3099*44704f69SBart Van Assche printf("%shigh critical=%.1f %%, high warning=%.1f %%", pad,
3100*44704f69SBart Van Assche 0.5 * tp[0], 0.5 * tp[1]);
3101*44704f69SBart Van Assche #endif
3102*44704f69SBart Van Assche printf(" (above nominal current)\n");
3103*44704f69SBart Van Assche break;
3104*44704f69SBart Van Assche default:
3105*44704f69SBart Van Assche if (op->verbose) {
3106*44704f69SBart Van Assche if (header)
3107*44704f69SBart Van Assche printf("%s", header);
3108*44704f69SBart Van Assche printf("%s<< no thresholds for this element type >>\n", pad);
3109*44704f69SBart Van Assche }
3110*44704f69SBart Van Assche break;
3111*44704f69SBart Van Assche }
3112*44704f69SBart Van Assche }
3113*44704f69SBart Van Assche
3114*44704f69SBart Van Assche /* THRESHOLD_DPC [0x5] */
3115*44704f69SBart Van Assche static void
threshold_sdg(const struct th_es_t * tesp,uint32_t ref_gen_code,const uint8_t * resp,int resp_len,const struct opts_t * op)3116*44704f69SBart Van Assche threshold_sdg(const struct th_es_t * tesp, uint32_t ref_gen_code,
3117*44704f69SBart Van Assche const uint8_t * resp, int resp_len,
3118*44704f69SBart Van Assche const struct opts_t * op)
3119*44704f69SBart Van Assche {
3120*44704f69SBart Van Assche int j, k;
3121*44704f69SBart Van Assche uint32_t gen_code;
3122*44704f69SBart Van Assche bool got1, match_ind_th;
3123*44704f69SBart Van Assche const uint8_t * bp;
3124*44704f69SBart Van Assche const uint8_t * last_bp;
3125*44704f69SBart Van Assche const struct type_desc_hdr_t * tdhp = tesp->th_base;
3126*44704f69SBart Van Assche char b[64];
3127*44704f69SBart Van Assche
3128*44704f69SBart Van Assche printf("Threshold In diagnostic page:\n");
3129*44704f69SBart Van Assche if (resp_len < 4)
3130*44704f69SBart Van Assche goto truncated;
3131*44704f69SBart Van Assche printf(" INVOP=%d\n", !!(resp[1] & 0x10));
3132*44704f69SBart Van Assche last_bp = resp + resp_len - 1;
3133*44704f69SBart Van Assche if (resp_len < 8)
3134*44704f69SBart Van Assche goto truncated;
3135*44704f69SBart Van Assche gen_code = sg_get_unaligned_be32(resp + 4);
3136*44704f69SBart Van Assche printf(" generation code: 0x%" PRIx32 "\n", gen_code);
3137*44704f69SBart Van Assche if (ref_gen_code != gen_code) {
3138*44704f69SBart Van Assche pr2serr(" <<state of enclosure changed, please try again>>\n");
3139*44704f69SBart Van Assche return;
3140*44704f69SBart Van Assche }
3141*44704f69SBart Van Assche printf(" Threshold status descriptor list\n");
3142*44704f69SBart Van Assche bp = resp + 8;
3143*44704f69SBart Van Assche for (k = 0, got1 = false; k < tesp->num_ths; ++k, ++tdhp) {
3144*44704f69SBart Van Assche if ((bp + 3) > last_bp)
3145*44704f69SBart Van Assche goto truncated;
3146*44704f69SBart Van Assche match_ind_th = (op->ind_given && (k == op->ind_th));
3147*44704f69SBart Van Assche if ((! op->ind_given) || (match_ind_th && (-1 == op->ind_indiv))) {
3148*44704f69SBart Van Assche printf(" Element type: %s, subenclosure id: %d [ti=%d]\n",
3149*44704f69SBart Van Assche etype_str(tdhp->etype, b, sizeof(b)), tdhp->se_id, k);
3150*44704f69SBart Van Assche threshold_helper(" Overall descriptor:\n", " ", bp,
3151*44704f69SBart Van Assche tdhp->etype, op);
3152*44704f69SBart Van Assche got1 = true;
3153*44704f69SBart Van Assche }
3154*44704f69SBart Van Assche for (bp += 4, j = 0; j < tdhp->num_elements; ++j, bp += 4) {
3155*44704f69SBart Van Assche if (op->ind_given) {
3156*44704f69SBart Van Assche if ((! match_ind_th) || (-1 == op->ind_indiv) ||
3157*44704f69SBart Van Assche (! match_ind_indiv(j, op)))
3158*44704f69SBart Van Assche continue;
3159*44704f69SBart Van Assche }
3160*44704f69SBart Van Assche snprintf(b, sizeof(b), " Element %d descriptor:\n", j);
3161*44704f69SBart Van Assche threshold_helper(b, " ", bp, tdhp->etype, op);
3162*44704f69SBart Van Assche got1 = true;
3163*44704f69SBart Van Assche }
3164*44704f69SBart Van Assche }
3165*44704f69SBart Van Assche if (op->ind_given && (! got1)) {
3166*44704f69SBart Van Assche printf(" >>> no match on --index=%d,%d", op->ind_th,
3167*44704f69SBart Van Assche op->ind_indiv);
3168*44704f69SBart Van Assche if (op->ind_indiv_last > op->ind_indiv)
3169*44704f69SBart Van Assche printf("-%d\n", op->ind_indiv_last);
3170*44704f69SBart Van Assche else
3171*44704f69SBart Van Assche printf("\n");
3172*44704f69SBart Van Assche }
3173*44704f69SBart Van Assche return;
3174*44704f69SBart Van Assche truncated:
3175*44704f69SBart Van Assche pr2serr(" <<<thresh: response too short>>>\n");
3176*44704f69SBart Van Assche return;
3177*44704f69SBart Van Assche }
3178*44704f69SBart Van Assche
3179*44704f69SBart Van Assche /* ELEM_DESC_DPC [0x7]
3180*44704f69SBart Van Assche * This page essentially contains names of overall and individual
3181*44704f69SBart Van Assche * elements. */
3182*44704f69SBart Van Assche static void
element_desc_sdg(const struct th_es_t * tesp,uint32_t ref_gen_code,const uint8_t * resp,int resp_len,const struct opts_t * op)3183*44704f69SBart Van Assche element_desc_sdg(const struct th_es_t * tesp, uint32_t ref_gen_code,
3184*44704f69SBart Van Assche const uint8_t * resp, int resp_len,
3185*44704f69SBart Van Assche const struct opts_t * op)
3186*44704f69SBart Van Assche {
3187*44704f69SBart Van Assche int j, k, desc_len;
3188*44704f69SBart Van Assche uint32_t gen_code;
3189*44704f69SBart Van Assche bool got1, match_ind_th;
3190*44704f69SBart Van Assche const uint8_t * bp;
3191*44704f69SBart Van Assche const uint8_t * last_bp;
3192*44704f69SBart Van Assche const struct type_desc_hdr_t * tp;
3193*44704f69SBart Van Assche char b[64];
3194*44704f69SBart Van Assche
3195*44704f69SBart Van Assche printf("Element Descriptor In diagnostic page:\n");
3196*44704f69SBart Van Assche if (resp_len < 4)
3197*44704f69SBart Van Assche goto truncated;
3198*44704f69SBart Van Assche last_bp = resp + resp_len - 1;
3199*44704f69SBart Van Assche if (resp_len < 8)
3200*44704f69SBart Van Assche goto truncated;
3201*44704f69SBart Van Assche gen_code = sg_get_unaligned_be32(resp + 4);
3202*44704f69SBart Van Assche printf(" generation code: 0x%" PRIx32 "\n", gen_code);
3203*44704f69SBart Van Assche if (ref_gen_code != gen_code) {
3204*44704f69SBart Van Assche pr2serr(" <<state of enclosure changed, please try again>>\n");
3205*44704f69SBart Van Assche return;
3206*44704f69SBart Van Assche }
3207*44704f69SBart Van Assche printf(" element descriptor list (grouped by type):\n");
3208*44704f69SBart Van Assche bp = resp + 8;
3209*44704f69SBart Van Assche got1 = false;
3210*44704f69SBart Van Assche for (k = 0, tp = tesp->th_base; k < tesp->num_ths; ++k, ++tp) {
3211*44704f69SBart Van Assche if ((bp + 3) > last_bp)
3212*44704f69SBart Van Assche goto truncated;
3213*44704f69SBart Van Assche desc_len = sg_get_unaligned_be16(bp + 2) + 4;
3214*44704f69SBart Van Assche match_ind_th = (op->ind_given && (k == op->ind_th));
3215*44704f69SBart Van Assche if ((! op->ind_given) || (match_ind_th && (-1 == op->ind_indiv))) {
3216*44704f69SBart Van Assche printf(" Element type: %s, subenclosure id: %d [ti=%d]\n",
3217*44704f69SBart Van Assche etype_str(tp->etype, b, sizeof(b)), tp->se_id, k);
3218*44704f69SBart Van Assche if (desc_len > 4)
3219*44704f69SBart Van Assche printf(" Overall descriptor: %.*s\n", desc_len - 4,
3220*44704f69SBart Van Assche bp + 4);
3221*44704f69SBart Van Assche else
3222*44704f69SBart Van Assche printf(" Overall descriptor: <empty>\n");
3223*44704f69SBart Van Assche got1 = true;
3224*44704f69SBart Van Assche }
3225*44704f69SBart Van Assche for (bp += desc_len, j = 0; j < tp->num_elements;
3226*44704f69SBart Van Assche ++j, bp += desc_len) {
3227*44704f69SBart Van Assche desc_len = sg_get_unaligned_be16(bp + 2) + 4;
3228*44704f69SBart Van Assche if (op->ind_given) {
3229*44704f69SBart Van Assche if ((! match_ind_th) || (-1 == op->ind_indiv) ||
3230*44704f69SBart Van Assche (! match_ind_indiv(j, op)))
3231*44704f69SBart Van Assche continue;
3232*44704f69SBart Van Assche }
3233*44704f69SBart Van Assche if (desc_len > 4)
3234*44704f69SBart Van Assche printf(" Element %d descriptor: %.*s\n", j,
3235*44704f69SBart Van Assche desc_len - 4, bp + 4);
3236*44704f69SBart Van Assche else
3237*44704f69SBart Van Assche printf(" Element %d descriptor: <empty>\n", j);
3238*44704f69SBart Van Assche got1 = true;
3239*44704f69SBart Van Assche }
3240*44704f69SBart Van Assche }
3241*44704f69SBart Van Assche if (op->ind_given && (! got1)) {
3242*44704f69SBart Van Assche printf(" >>> no match on --index=%d,%d", op->ind_th,
3243*44704f69SBart Van Assche op->ind_indiv);
3244*44704f69SBart Van Assche if (op->ind_indiv_last > op->ind_indiv)
3245*44704f69SBart Van Assche printf("-%d\n", op->ind_indiv_last);
3246*44704f69SBart Van Assche else
3247*44704f69SBart Van Assche printf("\n");
3248*44704f69SBart Van Assche }
3249*44704f69SBart Van Assche return;
3250*44704f69SBart Van Assche truncated:
3251*44704f69SBart Van Assche pr2serr(" <<<element: response too short>>>\n");
3252*44704f69SBart Van Assche return;
3253*44704f69SBart Van Assche }
3254*44704f69SBart Van Assche
3255*44704f69SBart Van Assche static bool
saddr_non_zero(const uint8_t * bp)3256*44704f69SBart Van Assche saddr_non_zero(const uint8_t * bp)
3257*44704f69SBart Van Assche {
3258*44704f69SBart Van Assche return ! sg_all_zeros(bp, 8);
3259*44704f69SBart Van Assche }
3260*44704f69SBart Van Assche
3261*44704f69SBart Van Assche static const char * sas_device_type[] = {
3262*44704f69SBart Van Assche "no SAS device attached", /* but might be SATA device */
3263*44704f69SBart Van Assche "end device",
3264*44704f69SBart Van Assche "expander device", /* in SAS-1.1 this was a "edge expander device */
3265*44704f69SBart Van Assche "expander device (fanout, SAS-1.1)", /* marked obsolete in SAS-2 */
3266*44704f69SBart Van Assche "reserved [4]", "reserved [5]", "reserved [6]", "reserved [7]"
3267*44704f69SBart Van Assche };
3268*44704f69SBart Van Assche
3269*44704f69SBart Van Assche static void
additional_elem_sas(const char * pad,const uint8_t * ae_bp,int etype,const struct th_es_t * tesp,const struct opts_t * op)3270*44704f69SBart Van Assche additional_elem_sas(const char * pad, const uint8_t * ae_bp, int etype,
3271*44704f69SBart Van Assche const struct th_es_t * tesp, const struct opts_t * op)
3272*44704f69SBart Van Assche {
3273*44704f69SBart Van Assche int phys, j, m, n, desc_type, eiioe, eip_offset;
3274*44704f69SBart Van Assche bool nofilter = ! op->do_filter;
3275*44704f69SBart Van Assche bool eip;
3276*44704f69SBart Van Assche const struct join_row_t * jrp;
3277*44704f69SBart Van Assche const uint8_t * aep;
3278*44704f69SBart Van Assche const uint8_t * ed_bp;
3279*44704f69SBart Van Assche const char * cp;
3280*44704f69SBart Van Assche char b[64];
3281*44704f69SBart Van Assche
3282*44704f69SBart Van Assche eip = !!(0x10 & ae_bp[0]);
3283*44704f69SBart Van Assche eiioe = eip ? (0x3 & ae_bp[2]) : 0;
3284*44704f69SBart Van Assche eip_offset = eip ? 2 : 0;
3285*44704f69SBart Van Assche desc_type = (ae_bp[3 + eip_offset] >> 6) & 0x3;
3286*44704f69SBart Van Assche if (op->verbose > 1)
3287*44704f69SBart Van Assche printf("%sdescriptor_type: %d\n", pad, desc_type);
3288*44704f69SBart Van Assche if (0 == desc_type) {
3289*44704f69SBart Van Assche phys = ae_bp[2 + eip_offset];
3290*44704f69SBart Van Assche printf("%snumber of phys: %d, not all phys: %d", pad, phys,
3291*44704f69SBart Van Assche ae_bp[3 + eip_offset] & 1);
3292*44704f69SBart Van Assche if (eip_offset)
3293*44704f69SBart Van Assche printf(", device slot number: %d", ae_bp[5 + eip_offset]);
3294*44704f69SBart Van Assche printf("\n");
3295*44704f69SBart Van Assche aep = ae_bp + 4 + eip_offset + eip_offset;
3296*44704f69SBart Van Assche for (j = 0; j < phys; ++j, aep += 28) {
3297*44704f69SBart Van Assche bool print_sas_addr = false;
3298*44704f69SBart Van Assche bool saddr_nz;
3299*44704f69SBart Van Assche
3300*44704f69SBart Van Assche printf("%sphy index: %d\n", pad, j);
3301*44704f69SBart Van Assche printf("%s SAS device type: %s\n", pad,
3302*44704f69SBart Van Assche sas_device_type[(0x70 & aep[0]) >> 4]);
3303*44704f69SBart Van Assche if (nofilter || (0xe & aep[2]))
3304*44704f69SBart Van Assche printf("%s initiator port for:%s%s%s\n", pad,
3305*44704f69SBart Van Assche ((aep[2] & 8) ? " SSP" : ""),
3306*44704f69SBart Van Assche ((aep[2] & 4) ? " STP" : ""),
3307*44704f69SBart Van Assche ((aep[2] & 2) ? " SMP" : ""));
3308*44704f69SBart Van Assche if (nofilter || (0x8f & aep[3]))
3309*44704f69SBart Van Assche printf("%s target port for:%s%s%s%s%s\n", pad,
3310*44704f69SBart Van Assche ((aep[3] & 0x80) ? " SATA_port_selector" : ""),
3311*44704f69SBart Van Assche ((aep[3] & 8) ? " SSP" : ""),
3312*44704f69SBart Van Assche ((aep[3] & 4) ? " STP" : ""),
3313*44704f69SBart Van Assche ((aep[3] & 2) ? " SMP" : ""),
3314*44704f69SBart Van Assche ((aep[3] & 1) ? " SATA_device" : ""));
3315*44704f69SBart Van Assche saddr_nz = saddr_non_zero(aep + 4);
3316*44704f69SBart Van Assche if (nofilter || saddr_nz) {
3317*44704f69SBart Van Assche print_sas_addr = true;
3318*44704f69SBart Van Assche printf("%s attached SAS address: 0x", pad);
3319*44704f69SBart Van Assche if (saddr_nz) {
3320*44704f69SBart Van Assche for (m = 0; m < 8; ++m)
3321*44704f69SBart Van Assche printf("%02x", aep[4 + m]);
3322*44704f69SBart Van Assche } else
3323*44704f69SBart Van Assche printf("0");
3324*44704f69SBart Van Assche }
3325*44704f69SBart Van Assche saddr_nz = saddr_non_zero(aep + 12);
3326*44704f69SBart Van Assche if (nofilter || saddr_nz) {
3327*44704f69SBart Van Assche print_sas_addr = true;
3328*44704f69SBart Van Assche printf("\n%s SAS address: 0x", pad);
3329*44704f69SBart Van Assche if (saddr_nz) {
3330*44704f69SBart Van Assche for (m = 0; m < 8; ++m)
3331*44704f69SBart Van Assche printf("%02x", aep[12 + m]);
3332*44704f69SBart Van Assche } else
3333*44704f69SBart Van Assche printf("0");
3334*44704f69SBart Van Assche }
3335*44704f69SBart Van Assche if (print_sas_addr)
3336*44704f69SBart Van Assche printf("\n%s phy identifier: 0x%x\n", pad, aep[20]);
3337*44704f69SBart Van Assche }
3338*44704f69SBart Van Assche } else if (1 == desc_type) {
3339*44704f69SBart Van Assche phys = ae_bp[2 + eip_offset];
3340*44704f69SBart Van Assche if (SAS_EXPANDER_ETC == etype) {
3341*44704f69SBart Van Assche printf("%snumber of phys: %d\n", pad, phys);
3342*44704f69SBart Van Assche printf("%sSAS address: 0x", pad);
3343*44704f69SBart Van Assche for (m = 0; m < 8; ++m)
3344*44704f69SBart Van Assche printf("%02x", ae_bp[6 + eip_offset + m]);
3345*44704f69SBart Van Assche printf("\n%sAttached connector; other_element pairs:\n", pad);
3346*44704f69SBart Van Assche aep = ae_bp + 14 + eip_offset;
3347*44704f69SBart Van Assche for (j = 0; j < phys; ++j, aep += 2) {
3348*44704f69SBart Van Assche printf("%s [%d] ", pad, j);
3349*44704f69SBart Van Assche m = aep[0]; /* connector element index */
3350*44704f69SBart Van Assche if (0xff == m)
3351*44704f69SBart Van Assche printf("no connector");
3352*44704f69SBart Van Assche else {
3353*44704f69SBart Van Assche if (tesp->j_base) {
3354*44704f69SBart Van Assche if (0 == eiioe)
3355*44704f69SBart Van Assche jrp = find_join_row_cnst(tesp, m, FJ_SAS_CON);
3356*44704f69SBart Van Assche else if ((1 == eiioe) || (3 == eiioe))
3357*44704f69SBart Van Assche jrp = find_join_row_cnst(tesp, m, FJ_IOE);
3358*44704f69SBart Van Assche else
3359*44704f69SBart Van Assche jrp = find_join_row_cnst(tesp, m, FJ_EOE);
3360*44704f69SBart Van Assche if ((NULL == jrp) || (NULL == jrp->enc_statp) ||
3361*44704f69SBart Van Assche (SAS_CONNECTOR_ETC != jrp->etype))
3362*44704f69SBart Van Assche printf("broken [conn_idx=%d]", m);
3363*44704f69SBart Van Assche else {
3364*44704f69SBart Van Assche enc_status_helper("", jrp->enc_statp, jrp->etype,
3365*44704f69SBart Van Assche true, op);
3366*44704f69SBart Van Assche printf(" [%d]", jrp->indiv_i);
3367*44704f69SBart Van Assche }
3368*44704f69SBart Van Assche } else
3369*44704f69SBart Van Assche printf("connector ei: %d", m);
3370*44704f69SBart Van Assche }
3371*44704f69SBart Van Assche m = aep[1]; /* other element index */
3372*44704f69SBart Van Assche if (0xff != m) {
3373*44704f69SBart Van Assche printf("; ");
3374*44704f69SBart Van Assche if (tesp->j_base) {
3375*44704f69SBart Van Assche
3376*44704f69SBart Van Assche if (0 == eiioe)
3377*44704f69SBart Van Assche jrp = find_join_row_cnst(tesp, m, FJ_AESS);
3378*44704f69SBart Van Assche else if ((1 == eiioe) || (3 == eiioe))
3379*44704f69SBart Van Assche jrp = find_join_row_cnst(tesp, m, FJ_IOE);
3380*44704f69SBart Van Assche else
3381*44704f69SBart Van Assche jrp = find_join_row_cnst(tesp, m, FJ_EOE);
3382*44704f69SBart Van Assche if (NULL == jrp)
3383*44704f69SBart Van Assche printf("broken [oth_elem_idx=%d]", m);
3384*44704f69SBart Van Assche else if (jrp->elem_descp) {
3385*44704f69SBart Van Assche cp = etype_str(jrp->etype, b, sizeof(b));
3386*44704f69SBart Van Assche ed_bp = jrp->elem_descp;
3387*44704f69SBart Van Assche n = sg_get_unaligned_be16(ed_bp + 2);
3388*44704f69SBart Van Assche if (n > 0)
3389*44704f69SBart Van Assche printf("%.*s [%d,%d] etype: %s", n,
3390*44704f69SBart Van Assche (const char *)(ed_bp + 4),
3391*44704f69SBart Van Assche jrp->th_i, jrp->indiv_i, cp);
3392*44704f69SBart Van Assche else
3393*44704f69SBart Van Assche printf("[%d,%d] etype: %s", jrp->th_i,
3394*44704f69SBart Van Assche jrp->indiv_i, cp);
3395*44704f69SBart Van Assche } else {
3396*44704f69SBart Van Assche cp = etype_str(jrp->etype, b, sizeof(b));
3397*44704f69SBart Van Assche printf("[%d,%d] etype: %s", jrp->th_i,
3398*44704f69SBart Van Assche jrp->indiv_i, cp);
3399*44704f69SBart Van Assche }
3400*44704f69SBart Van Assche } else
3401*44704f69SBart Van Assche printf("other ei: %d", m);
3402*44704f69SBart Van Assche }
3403*44704f69SBart Van Assche printf("\n");
3404*44704f69SBart Van Assche }
3405*44704f69SBart Van Assche } else if ((SCSI_TPORT_ETC == etype) ||
3406*44704f69SBart Van Assche (SCSI_IPORT_ETC == etype) ||
3407*44704f69SBart Van Assche (ENC_SCELECTR_ETC == etype)) {
3408*44704f69SBart Van Assche printf("%snumber of phys: %d\n", pad, phys);
3409*44704f69SBart Van Assche aep = ae_bp + 6 + eip_offset;
3410*44704f69SBart Van Assche for (j = 0; j < phys; ++j, aep += 12) {
3411*44704f69SBart Van Assche printf("%sphy index: %d\n", pad, j);
3412*44704f69SBart Van Assche printf("%s phy_id: 0x%x\n", pad, aep[0]);
3413*44704f69SBart Van Assche printf("%s ", pad);
3414*44704f69SBart Van Assche m = aep[2]; /* connector element index */
3415*44704f69SBart Van Assche if (0xff == m)
3416*44704f69SBart Van Assche printf("no connector");
3417*44704f69SBart Van Assche else {
3418*44704f69SBart Van Assche if (tesp->j_base) {
3419*44704f69SBart Van Assche if (0 == eiioe)
3420*44704f69SBart Van Assche jrp = find_join_row_cnst(tesp, m, FJ_SAS_CON);
3421*44704f69SBart Van Assche else if ((1 == eiioe) || (3 == eiioe))
3422*44704f69SBart Van Assche jrp = find_join_row_cnst(tesp, m, FJ_IOE);
3423*44704f69SBart Van Assche else
3424*44704f69SBart Van Assche jrp = find_join_row_cnst(tesp, m, FJ_EOE);
3425*44704f69SBart Van Assche if ((NULL == jrp) || (NULL == jrp->enc_statp) ||
3426*44704f69SBart Van Assche (SAS_CONNECTOR_ETC != jrp->etype))
3427*44704f69SBart Van Assche printf("broken [conn_idx=%d]", m);
3428*44704f69SBart Van Assche else {
3429*44704f69SBart Van Assche enc_status_helper("", jrp->enc_statp, jrp->etype,
3430*44704f69SBart Van Assche true, op);
3431*44704f69SBart Van Assche printf(" [%d]", jrp->indiv_i);
3432*44704f69SBart Van Assche }
3433*44704f69SBart Van Assche } else
3434*44704f69SBart Van Assche printf("connector ei: %d", m);
3435*44704f69SBart Van Assche }
3436*44704f69SBart Van Assche m = aep[3]; /* other element index */
3437*44704f69SBart Van Assche if (0xff != m) {
3438*44704f69SBart Van Assche printf("; ");
3439*44704f69SBart Van Assche if (tesp->j_base) {
3440*44704f69SBart Van Assche if (0 == eiioe)
3441*44704f69SBart Van Assche jrp = find_join_row_cnst(tesp, m, FJ_AESS);
3442*44704f69SBart Van Assche else if ((1 == eiioe) || (3 == eiioe))
3443*44704f69SBart Van Assche jrp = find_join_row_cnst(tesp, m, FJ_IOE);
3444*44704f69SBart Van Assche else
3445*44704f69SBart Van Assche jrp = find_join_row_cnst(tesp, m, FJ_EOE);
3446*44704f69SBart Van Assche if (NULL == jrp)
3447*44704f69SBart Van Assche printf("broken [oth_elem_idx=%d]", m);
3448*44704f69SBart Van Assche else if (jrp->elem_descp) {
3449*44704f69SBart Van Assche cp = etype_str(jrp->etype, b, sizeof(b));
3450*44704f69SBart Van Assche ed_bp = jrp->elem_descp;
3451*44704f69SBart Van Assche n = sg_get_unaligned_be16(ed_bp + 2);
3452*44704f69SBart Van Assche if (n > 0)
3453*44704f69SBart Van Assche printf("%.*s [%d,%d] etype: %s", n,
3454*44704f69SBart Van Assche (const char *)(ed_bp + 4),
3455*44704f69SBart Van Assche jrp->th_i, jrp->indiv_i, cp);
3456*44704f69SBart Van Assche else
3457*44704f69SBart Van Assche printf("[%d,%d] etype: %s", jrp->th_i,
3458*44704f69SBart Van Assche jrp->indiv_i, cp);
3459*44704f69SBart Van Assche } else {
3460*44704f69SBart Van Assche cp = etype_str(jrp->etype, b, sizeof(b));
3461*44704f69SBart Van Assche printf("[%d,%d] etype: %s", jrp->th_i,
3462*44704f69SBart Van Assche jrp->indiv_i, cp);
3463*44704f69SBart Van Assche }
3464*44704f69SBart Van Assche } else
3465*44704f69SBart Van Assche printf("other ei: %d", m);
3466*44704f69SBart Van Assche }
3467*44704f69SBart Van Assche printf("\n");
3468*44704f69SBart Van Assche printf("%s SAS address: 0x", pad);
3469*44704f69SBart Van Assche for (m = 0; m < 8; ++m)
3470*44704f69SBart Van Assche printf("%02x", aep[4 + m]);
3471*44704f69SBart Van Assche printf("\n");
3472*44704f69SBart Van Assche } /* end_for: loop over phys in SCSI initiator, target */
3473*44704f69SBart Van Assche } else
3474*44704f69SBart Van Assche printf("%sunrecognised element type [%d] for desc_type "
3475*44704f69SBart Van Assche "1\n", pad, etype);
3476*44704f69SBart Van Assche } else
3477*44704f69SBart Van Assche printf("%sunrecognised descriptor type [%d]\n", pad, desc_type);
3478*44704f69SBart Van Assche }
3479*44704f69SBart Van Assche
3480*44704f69SBart Van Assche static void
additional_elem_helper(const char * pad,const uint8_t * ae_bp,int len,int etype,const struct th_es_t * tesp,const struct opts_t * op)3481*44704f69SBart Van Assche additional_elem_helper(const char * pad, const uint8_t * ae_bp,
3482*44704f69SBart Van Assche int len, int etype, const struct th_es_t * tesp,
3483*44704f69SBart Van Assche const struct opts_t * op)
3484*44704f69SBart Van Assche {
3485*44704f69SBart Van Assche int ports, phys, j, m, eip_offset, pcie_pt;
3486*44704f69SBart Van Assche bool eip;
3487*44704f69SBart Van Assche uint16_t pcie_vid;
3488*44704f69SBart Van Assche const uint8_t * aep;
3489*44704f69SBart Van Assche char b[64];
3490*44704f69SBart Van Assche
3491*44704f69SBart Van Assche if (op->inner_hex) {
3492*44704f69SBart Van Assche for (j = 0; j < len; ++j) {
3493*44704f69SBart Van Assche if (0 == (j % 16))
3494*44704f69SBart Van Assche printf("%s%s", ((0 == j) ? "" : "\n"), pad);
3495*44704f69SBart Van Assche printf("%02x ", ae_bp[j]);
3496*44704f69SBart Van Assche }
3497*44704f69SBart Van Assche printf("\n");
3498*44704f69SBart Van Assche return;
3499*44704f69SBart Van Assche }
3500*44704f69SBart Van Assche eip = !!(0x10 & ae_bp[0]);
3501*44704f69SBart Van Assche eip_offset = eip ? 2 : 0;
3502*44704f69SBart Van Assche switch (0xf & ae_bp[0]) { /* switch on protocol identifier */
3503*44704f69SBart Van Assche case TPROTO_FCP:
3504*44704f69SBart Van Assche printf("%sTransport protocol: FCP\n", pad);
3505*44704f69SBart Van Assche if (len < (12 + eip_offset))
3506*44704f69SBart Van Assche break;
3507*44704f69SBart Van Assche ports = ae_bp[2 + eip_offset];
3508*44704f69SBart Van Assche printf("%snumber of ports: %d\n", pad, ports);
3509*44704f69SBart Van Assche printf("%snode_name: ", pad);
3510*44704f69SBart Van Assche for (m = 0; m < 8; ++m)
3511*44704f69SBart Van Assche printf("%02x", ae_bp[6 + eip_offset + m]);
3512*44704f69SBart Van Assche if (eip_offset)
3513*44704f69SBart Van Assche printf(", device slot number: %d", ae_bp[5 + eip_offset]);
3514*44704f69SBart Van Assche printf("\n");
3515*44704f69SBart Van Assche aep = ae_bp + 14 + eip_offset;
3516*44704f69SBart Van Assche for (j = 0; j < ports; ++j, aep += 16) {
3517*44704f69SBart Van Assche printf("%s port index: %d, port loop position: %d, port "
3518*44704f69SBart Van Assche "bypass reason: 0x%x\n", pad, j, aep[0], aep[1]);
3519*44704f69SBart Van Assche printf("%srequested hard address: %d, n_port identifier: "
3520*44704f69SBart Van Assche "%02x%02x%02x\n", pad, aep[4], aep[5],
3521*44704f69SBart Van Assche aep[6], aep[7]);
3522*44704f69SBart Van Assche printf("%s n_port name: ", pad);
3523*44704f69SBart Van Assche for (m = 0; m < 8; ++m)
3524*44704f69SBart Van Assche printf("%02x", aep[8 + m]);
3525*44704f69SBart Van Assche printf("\n");
3526*44704f69SBart Van Assche }
3527*44704f69SBart Van Assche break;
3528*44704f69SBart Van Assche case TPROTO_SAS:
3529*44704f69SBart Van Assche printf("%sTransport protocol: SAS\n", pad);
3530*44704f69SBart Van Assche if (len < (4 + eip_offset))
3531*44704f69SBart Van Assche break;
3532*44704f69SBart Van Assche additional_elem_sas(pad, ae_bp, etype, tesp, op);
3533*44704f69SBart Van Assche break;
3534*44704f69SBart Van Assche case TPROTO_PCIE: /* added in ses3r08; contains little endian fields */
3535*44704f69SBart Van Assche printf("%sTransport protocol: PCIe\n", pad);
3536*44704f69SBart Van Assche if (0 == eip_offset) {
3537*44704f69SBart Van Assche printf("%sfor this protocol EIP must be set (it isn't)\n", pad);
3538*44704f69SBart Van Assche break;
3539*44704f69SBart Van Assche }
3540*44704f69SBart Van Assche if (len < 6)
3541*44704f69SBart Van Assche break;
3542*44704f69SBart Van Assche pcie_pt = (ae_bp[5] >> 5) & 0x7;
3543*44704f69SBart Van Assche if (TPROTO_PCIE_PS_NVME == pcie_pt)
3544*44704f69SBart Van Assche printf("%sPCIe protocol type: NVMe\n", pad);
3545*44704f69SBart Van Assche else { /* no others currently defined */
3546*44704f69SBart Van Assche printf("%sTransport protocol: PCIe subprotocol=0x%x not "
3547*44704f69SBart Van Assche "decoded\n", pad, pcie_pt);
3548*44704f69SBart Van Assche if (op->verbose)
3549*44704f69SBart Van Assche hex2stdout(ae_bp, len, 0);
3550*44704f69SBart Van Assche break;
3551*44704f69SBart Van Assche }
3552*44704f69SBart Van Assche phys = ae_bp[4];
3553*44704f69SBart Van Assche printf("%snumber of ports: %d, not all ports: %d", pad, phys,
3554*44704f69SBart Van Assche ae_bp[5] & 1);
3555*44704f69SBart Van Assche printf(", device slot number: %d\n", ae_bp[7]);
3556*44704f69SBart Van Assche
3557*44704f69SBart Van Assche pcie_vid = sg_get_unaligned_le16(ae_bp + 10); /* N.B. LE */
3558*44704f69SBart Van Assche printf("%sPCIe vendor id: 0x%" PRIx16 "%s\n", pad, pcie_vid,
3559*44704f69SBart Van Assche (0xffff == pcie_vid) ? " (not reported)" : "");
3560*44704f69SBart Van Assche printf("%sserial number: %.20s\n", pad, ae_bp + 12);
3561*44704f69SBart Van Assche printf("%smodel number: %.40s\n", pad, ae_bp + 32);
3562*44704f69SBart Van Assche aep = ae_bp + 72;
3563*44704f69SBart Van Assche for (j = 0; j < phys; ++j, aep += 8) {
3564*44704f69SBart Van Assche bool psn_valid = !!(0x4 & aep[0]);
3565*44704f69SBart Van Assche bool bdf_valid = !!(0x2 & aep[0]);
3566*44704f69SBart Van Assche bool cid_valid = !!(0x1 & aep[0]);
3567*44704f69SBart Van Assche
3568*44704f69SBart Van Assche printf("%sport index: %d\n", pad, j);
3569*44704f69SBart Van Assche printf("%s PSN_VALID=%d, BDF_VALID=%d, CID_VALID=%d\n", pad,
3570*44704f69SBart Van Assche (int)psn_valid, (int)bdf_valid, (int)cid_valid);
3571*44704f69SBart Van Assche if (cid_valid) /* N.B. little endian */
3572*44704f69SBart Van Assche printf("%s controller id: 0x%" PRIx16 "\n", pad,
3573*44704f69SBart Van Assche sg_get_unaligned_le16(aep + 1)); /* N.B. LEndian */
3574*44704f69SBart Van Assche if (bdf_valid)
3575*44704f69SBart Van Assche printf("%s bus number: 0x%x, device number: 0x%x, "
3576*44704f69SBart Van Assche "function number: 0x%x\n", pad, aep[4],
3577*44704f69SBart Van Assche (aep[5] >> 3) & 0x1f, 0x7 & aep[5]);
3578*44704f69SBart Van Assche if (psn_valid) /* little endian, top 3 bits assumed zero */
3579*44704f69SBart Van Assche printf("%s physical slot number: 0x%" PRIx16 "\n", pad,
3580*44704f69SBart Van Assche 0x1fff & sg_get_unaligned_le16(aep + 6)); /* N.B. LE */
3581*44704f69SBart Van Assche }
3582*44704f69SBart Van Assche break;
3583*44704f69SBart Van Assche default:
3584*44704f69SBart Van Assche printf("%sTransport protocol: %s not decoded\n", pad,
3585*44704f69SBart Van Assche sg_get_trans_proto_str((0xf & ae_bp[0]), sizeof(b), b));
3586*44704f69SBart Van Assche if (op->verbose)
3587*44704f69SBart Van Assche hex2stdout(ae_bp, len, 0);
3588*44704f69SBart Van Assche break;
3589*44704f69SBart Van Assche }
3590*44704f69SBart Van Assche }
3591*44704f69SBart Van Assche
3592*44704f69SBart Van Assche /* ADD_ELEM_STATUS_DPC [0xa] Additional Element Status dpage
3593*44704f69SBart Van Assche * Previously called "Device element status descriptor". Changed "device"
3594*44704f69SBart Van Assche * to "additional" to allow for SAS expander and SATA devices */
3595*44704f69SBart Van Assche static void
additional_elem_sdg(const struct th_es_t * tesp,uint32_t ref_gen_code,const uint8_t * resp,int resp_len,const struct opts_t * op)3596*44704f69SBart Van Assche additional_elem_sdg(const struct th_es_t * tesp, uint32_t ref_gen_code,
3597*44704f69SBart Van Assche const uint8_t * resp, int resp_len,
3598*44704f69SBart Van Assche const struct opts_t * op)
3599*44704f69SBart Van Assche {
3600*44704f69SBart Van Assche int j, k, desc_len, etype, el_num, ind, elem_count, ei, eiioe, num_elems;
3601*44704f69SBart Van Assche int fake_ei;
3602*44704f69SBart Van Assche uint32_t gen_code;
3603*44704f69SBart Van Assche bool eip, invalid, match_ind_th, my_eiioe_force, skip;
3604*44704f69SBart Van Assche const uint8_t * bp;
3605*44704f69SBart Van Assche const uint8_t * last_bp;
3606*44704f69SBart Van Assche const struct type_desc_hdr_t * tp = tesp->th_base;
3607*44704f69SBart Van Assche char b[64];
3608*44704f69SBart Van Assche
3609*44704f69SBart Van Assche printf("Additional element status diagnostic page:\n");
3610*44704f69SBart Van Assche if (resp_len < 4)
3611*44704f69SBart Van Assche goto truncated;
3612*44704f69SBart Van Assche last_bp = resp + resp_len - 1;
3613*44704f69SBart Van Assche gen_code = sg_get_unaligned_be32(resp + 4);
3614*44704f69SBart Van Assche printf(" generation code: 0x%" PRIx32 "\n", gen_code);
3615*44704f69SBart Van Assche if (ref_gen_code != gen_code) {
3616*44704f69SBart Van Assche pr2serr(" <<state of enclosure changed, please try again>>\n");
3617*44704f69SBart Van Assche return;
3618*44704f69SBart Van Assche }
3619*44704f69SBart Van Assche printf(" additional element status descriptor list\n");
3620*44704f69SBart Van Assche bp = resp + 8;
3621*44704f69SBart Van Assche my_eiioe_force = op->eiioe_force;
3622*44704f69SBart Van Assche for (k = 0, elem_count = 0; k < tesp->num_ths; ++k, ++tp) {
3623*44704f69SBart Van Assche fake_ei = -1;
3624*44704f69SBart Van Assche etype = tp->etype;
3625*44704f69SBart Van Assche num_elems = tp->num_elements;
3626*44704f69SBart Van Assche if (! is_et_used_by_aes(etype)) {
3627*44704f69SBart Van Assche elem_count += num_elems;
3628*44704f69SBart Van Assche continue; /* skip if not element type of interest */
3629*44704f69SBart Van Assche }
3630*44704f69SBart Van Assche if ((bp + 1) > last_bp)
3631*44704f69SBart Van Assche goto truncated;
3632*44704f69SBart Van Assche
3633*44704f69SBart Van Assche eip = !! (bp[0] & 0x10);
3634*44704f69SBart Van Assche if (eip) { /* do bounds check on the element index */
3635*44704f69SBart Van Assche ei = bp[3];
3636*44704f69SBart Van Assche skip = false;
3637*44704f69SBart Van Assche if ((0 == k) && op->eiioe_auto && (1 == ei)) {
3638*44704f69SBart Van Assche /* heuristic: if first AES descriptor has EIP set and its
3639*44704f69SBart Van Assche * element index equal to 1, then act as if the EIIOE field
3640*44704f69SBart Van Assche * is one. */
3641*44704f69SBart Van Assche my_eiioe_force = true;
3642*44704f69SBart Van Assche }
3643*44704f69SBart Van Assche eiioe = (0x3 & bp[2]);
3644*44704f69SBart Van Assche if (my_eiioe_force && (0 == eiioe))
3645*44704f69SBart Van Assche eiioe = 1;
3646*44704f69SBart Van Assche if (1 == eiioe) {
3647*44704f69SBart Van Assche if ((ei < (elem_count + k)) ||
3648*44704f69SBart Van Assche (ei > (elem_count + k + num_elems))) {
3649*44704f69SBart Van Assche elem_count += num_elems;
3650*44704f69SBart Van Assche skip = true;
3651*44704f69SBart Van Assche }
3652*44704f69SBart Van Assche } else {
3653*44704f69SBart Van Assche if ((ei < elem_count) || (ei > elem_count + num_elems)) {
3654*44704f69SBart Van Assche if ((0 == ei) && (TPROTO_SAS == (0xf & bp[0])) &&
3655*44704f69SBart Van Assche (1 == (bp[5] >> 6))) {
3656*44704f69SBart Van Assche /* heuristic (hack) for Areca 8028 */
3657*44704f69SBart Van Assche fake_ei = elem_count;
3658*44704f69SBart Van Assche if (op->verbose > 2)
3659*44704f69SBart Van Assche pr2serr("%s: hack, bad ei=%d, fake_ei=%d\n",
3660*44704f69SBart Van Assche __func__, ei, fake_ei);
3661*44704f69SBart Van Assche ei = fake_ei;
3662*44704f69SBart Van Assche } else {
3663*44704f69SBart Van Assche elem_count += num_elems;
3664*44704f69SBart Van Assche skip = true;
3665*44704f69SBart Van Assche }
3666*44704f69SBart Van Assche }
3667*44704f69SBart Van Assche }
3668*44704f69SBart Van Assche if (skip) {
3669*44704f69SBart Van Assche if (op->verbose > 2)
3670*44704f69SBart Van Assche pr2serr("skipping etype=0x%x, k=%d due to "
3671*44704f69SBart Van Assche "element_index=%d bounds\n effective eiioe=%d, "
3672*44704f69SBart Van Assche "elem_count=%d, num_elems=%d\n", etype, k,
3673*44704f69SBart Van Assche ei, eiioe, elem_count, num_elems);
3674*44704f69SBart Van Assche continue;
3675*44704f69SBart Van Assche }
3676*44704f69SBart Van Assche }
3677*44704f69SBart Van Assche match_ind_th = (op->ind_given && (k == op->ind_th));
3678*44704f69SBart Van Assche if ((! op->ind_given) || (match_ind_th && (-1 == op->ind_indiv))) {
3679*44704f69SBart Van Assche printf(" Element type: %s, subenclosure id: %d [ti=%d]\n",
3680*44704f69SBart Van Assche etype_str(etype, b, sizeof(b)), tp->se_id, k);
3681*44704f69SBart Van Assche }
3682*44704f69SBart Van Assche el_num = 0;
3683*44704f69SBart Van Assche for (j = 0; j < num_elems; ++j, bp += desc_len, ++el_num) {
3684*44704f69SBart Van Assche invalid = !!(bp[0] & 0x80);
3685*44704f69SBart Van Assche desc_len = bp[1] + 2;
3686*44704f69SBart Van Assche eip = !!(bp[0] & 0x10);
3687*44704f69SBart Van Assche eiioe = eip ? (0x3 & bp[2]) : 0;
3688*44704f69SBart Van Assche if (fake_ei >= 0)
3689*44704f69SBart Van Assche ind = fake_ei;
3690*44704f69SBart Van Assche else
3691*44704f69SBart Van Assche ind = eip ? bp[3] : el_num;
3692*44704f69SBart Van Assche if (op->ind_given) {
3693*44704f69SBart Van Assche if ((! match_ind_th) || (-1 == op->ind_indiv) ||
3694*44704f69SBart Van Assche (! match_ind_indiv(el_num, op)))
3695*44704f69SBart Van Assche continue;
3696*44704f69SBart Van Assche }
3697*44704f69SBart Van Assche if (eip)
3698*44704f69SBart Van Assche printf(" Element index: %d eiioe=%d%s\n", ind, eiioe,
3699*44704f69SBart Van Assche (((0 != eiioe) && my_eiioe_force) ?
3700*44704f69SBart Van Assche " but overridden" : ""));
3701*44704f69SBart Van Assche else
3702*44704f69SBart Van Assche printf(" Element %d descriptor\n", ind);
3703*44704f69SBart Van Assche if (invalid && (! op->inner_hex))
3704*44704f69SBart Van Assche printf(" flagged as invalid (no further "
3705*44704f69SBart Van Assche "information)\n");
3706*44704f69SBart Van Assche else
3707*44704f69SBart Van Assche additional_elem_helper(" ", bp, desc_len, etype,
3708*44704f69SBart Van Assche tesp, op);
3709*44704f69SBart Van Assche }
3710*44704f69SBart Van Assche elem_count += tp->num_elements;
3711*44704f69SBart Van Assche } /* end_for: loop over type descriptor headers */
3712*44704f69SBart Van Assche return;
3713*44704f69SBart Van Assche truncated:
3714*44704f69SBart Van Assche pr2serr(" <<<additional: response too short>>>\n");
3715*44704f69SBart Van Assche return;
3716*44704f69SBart Van Assche }
3717*44704f69SBart Van Assche
3718*44704f69SBart Van Assche /* SUBENC_HELP_TEXT_DPC [0xb] */
3719*44704f69SBart Van Assche static void
subenc_help_sdg(const uint8_t * resp,int resp_len)3720*44704f69SBart Van Assche subenc_help_sdg(const uint8_t * resp, int resp_len)
3721*44704f69SBart Van Assche {
3722*44704f69SBart Van Assche int k, el, num_subs;
3723*44704f69SBart Van Assche uint32_t gen_code;
3724*44704f69SBart Van Assche const uint8_t * bp;
3725*44704f69SBart Van Assche const uint8_t * last_bp;
3726*44704f69SBart Van Assche
3727*44704f69SBart Van Assche printf("Subenclosure help text diagnostic page:\n");
3728*44704f69SBart Van Assche if (resp_len < 4)
3729*44704f69SBart Van Assche goto truncated;
3730*44704f69SBart Van Assche num_subs = resp[1] + 1; /* number of subenclosures (add 1 for primary) */
3731*44704f69SBart Van Assche last_bp = resp + resp_len - 1;
3732*44704f69SBart Van Assche printf(" number of secondary subenclosures: %d\n", num_subs - 1);
3733*44704f69SBart Van Assche gen_code = sg_get_unaligned_be32(resp + 4);
3734*44704f69SBart Van Assche printf(" generation code: 0x%" PRIx32 "\n", gen_code);
3735*44704f69SBart Van Assche bp = resp + 8;
3736*44704f69SBart Van Assche for (k = 0; k < num_subs; ++k, bp += el) {
3737*44704f69SBart Van Assche if ((bp + 3) > last_bp)
3738*44704f69SBart Van Assche goto truncated;
3739*44704f69SBart Van Assche el = sg_get_unaligned_be16(bp + 2) + 4;
3740*44704f69SBart Van Assche printf(" subenclosure identifier: %d\n", bp[1]);
3741*44704f69SBart Van Assche if (el > 4)
3742*44704f69SBart Van Assche printf(" %.*s\n", el - 4, bp + 4);
3743*44704f69SBart Van Assche else
3744*44704f69SBart Van Assche printf(" <empty>\n");
3745*44704f69SBart Van Assche }
3746*44704f69SBart Van Assche return;
3747*44704f69SBart Van Assche truncated:
3748*44704f69SBart Van Assche pr2serr(" <<<subenc: response too short>>>\n");
3749*44704f69SBart Van Assche return;
3750*44704f69SBart Van Assche }
3751*44704f69SBart Van Assche
3752*44704f69SBart Van Assche /* SUBENC_STRING_DPC [0xc] */
3753*44704f69SBart Van Assche static void
subenc_string_sdg(const uint8_t * resp,int resp_len)3754*44704f69SBart Van Assche subenc_string_sdg(const uint8_t * resp, int resp_len)
3755*44704f69SBart Van Assche {
3756*44704f69SBart Van Assche int k, el, num_subs;
3757*44704f69SBart Van Assche uint32_t gen_code;
3758*44704f69SBart Van Assche const uint8_t * bp;
3759*44704f69SBart Van Assche const uint8_t * last_bp;
3760*44704f69SBart Van Assche
3761*44704f69SBart Van Assche printf("Subenclosure string in diagnostic page:\n");
3762*44704f69SBart Van Assche if (resp_len < 4)
3763*44704f69SBart Van Assche goto truncated;
3764*44704f69SBart Van Assche num_subs = resp[1] + 1; /* number of subenclosures (add 1 for primary) */
3765*44704f69SBart Van Assche last_bp = resp + resp_len - 1;
3766*44704f69SBart Van Assche printf(" number of secondary subenclosures: %d\n", num_subs - 1);
3767*44704f69SBart Van Assche gen_code = sg_get_unaligned_be32(resp + 4);
3768*44704f69SBart Van Assche printf(" generation code: 0x%" PRIx32 "\n", gen_code);
3769*44704f69SBart Van Assche bp = resp + 8;
3770*44704f69SBart Van Assche for (k = 0; k < num_subs; ++k, bp += el) {
3771*44704f69SBart Van Assche if ((bp + 3) > last_bp)
3772*44704f69SBart Van Assche goto truncated;
3773*44704f69SBart Van Assche el = sg_get_unaligned_be16(bp + 2) + 4;
3774*44704f69SBart Van Assche printf(" subenclosure identifier: %d\n", bp[1]);
3775*44704f69SBart Van Assche if (el > 4) {
3776*44704f69SBart Van Assche char bb[1024];
3777*44704f69SBart Van Assche
3778*44704f69SBart Van Assche hex2str(bp + 40, el - 40, " ", 0, sizeof(bb), bb);
3779*44704f69SBart Van Assche printf("%s\n", bb);
3780*44704f69SBart Van Assche } else
3781*44704f69SBart Van Assche printf(" <empty>\n");
3782*44704f69SBart Van Assche }
3783*44704f69SBart Van Assche return;
3784*44704f69SBart Van Assche truncated:
3785*44704f69SBart Van Assche pr2serr(" <<<subence str: response too short>>>\n");
3786*44704f69SBart Van Assche return;
3787*44704f69SBart Van Assche }
3788*44704f69SBart Van Assche
3789*44704f69SBart Van Assche /* SUBENC_NICKNAME_DPC [0xf] */
3790*44704f69SBart Van Assche static void
subenc_nickname_sdg(const uint8_t * resp,int resp_len)3791*44704f69SBart Van Assche subenc_nickname_sdg(const uint8_t * resp, int resp_len)
3792*44704f69SBart Van Assche {
3793*44704f69SBart Van Assche int k, el, num_subs;
3794*44704f69SBart Van Assche uint32_t gen_code;
3795*44704f69SBart Van Assche const uint8_t * bp;
3796*44704f69SBart Van Assche const uint8_t * last_bp;
3797*44704f69SBart Van Assche
3798*44704f69SBart Van Assche printf("Subenclosure nickname status diagnostic page:\n");
3799*44704f69SBart Van Assche if (resp_len < 4)
3800*44704f69SBart Van Assche goto truncated;
3801*44704f69SBart Van Assche num_subs = resp[1] + 1; /* number of subenclosures (add 1 for primary) */
3802*44704f69SBart Van Assche last_bp = resp + resp_len - 1;
3803*44704f69SBart Van Assche printf(" number of secondary subenclosures: %d\n", num_subs - 1);
3804*44704f69SBart Van Assche gen_code = sg_get_unaligned_be32(resp + 4);
3805*44704f69SBart Van Assche printf(" generation code: 0x%" PRIx32 "\n", gen_code);
3806*44704f69SBart Van Assche bp = resp + 8;
3807*44704f69SBart Van Assche el = 40;
3808*44704f69SBart Van Assche for (k = 0; k < num_subs; ++k, bp += el) {
3809*44704f69SBart Van Assche if ((bp + el - 1) > last_bp)
3810*44704f69SBart Van Assche goto truncated;
3811*44704f69SBart Van Assche printf(" subenclosure identifier: %d\n", bp[1]);
3812*44704f69SBart Van Assche printf(" nickname status: 0x%x\n", bp[2]);
3813*44704f69SBart Van Assche printf(" nickname additional status: 0x%x\n", bp[3]);
3814*44704f69SBart Van Assche printf(" nickname language code: %.2s\n", bp + 6);
3815*44704f69SBart Van Assche printf(" nickname: %.*s\n", 32, bp + 8);
3816*44704f69SBart Van Assche }
3817*44704f69SBart Van Assche return;
3818*44704f69SBart Van Assche truncated:
3819*44704f69SBart Van Assche pr2serr(" <<<subence str: response too short>>>\n");
3820*44704f69SBart Van Assche return;
3821*44704f69SBart Van Assche }
3822*44704f69SBart Van Assche
3823*44704f69SBart Van Assche /* SUPPORTED_SES_DPC [0xd] */
3824*44704f69SBart Van Assche static void
supported_pages_sdg(const char * leadin,const uint8_t * resp,int resp_len)3825*44704f69SBart Van Assche supported_pages_sdg(const char * leadin, const uint8_t * resp,
3826*44704f69SBart Van Assche int resp_len)
3827*44704f69SBart Van Assche {
3828*44704f69SBart Van Assche int k, code, prev;
3829*44704f69SBart Van Assche bool got1;
3830*44704f69SBart Van Assche const struct diag_page_abbrev * ap;
3831*44704f69SBart Van Assche
3832*44704f69SBart Van Assche printf("%s:\n", leadin);
3833*44704f69SBart Van Assche for (k = 0, prev = 0; k < (resp_len - 4); ++k, prev = code) {
3834*44704f69SBart Van Assche const char * cp;
3835*44704f69SBart Van Assche
3836*44704f69SBart Van Assche code = resp[k + 4];
3837*44704f69SBart Van Assche if (code < prev)
3838*44704f69SBart Van Assche break; /* assume to be padding at end */
3839*44704f69SBart Van Assche cp = find_diag_page_desc(code);
3840*44704f69SBart Van Assche if (cp) {
3841*44704f69SBart Van Assche printf(" %s [", cp);
3842*44704f69SBart Van Assche for (ap = dp_abbrev, got1 = false; ap->abbrev; ++ap) {
3843*44704f69SBart Van Assche if (ap->page_code == code) {
3844*44704f69SBart Van Assche printf("%s%s", (got1 ? "," : ""), ap->abbrev);
3845*44704f69SBart Van Assche got1 = true;
3846*44704f69SBart Van Assche }
3847*44704f69SBart Van Assche }
3848*44704f69SBart Van Assche printf("] [0x%x]\n", code);
3849*44704f69SBart Van Assche } else
3850*44704f69SBart Van Assche printf(" <unknown> [0x%x]\n", code);
3851*44704f69SBart Van Assche }
3852*44704f69SBart Van Assche }
3853*44704f69SBart Van Assche
3854*44704f69SBart Van Assche /* An array of Download microcode status field values and descriptions */
3855*44704f69SBart Van Assche static struct diag_page_code mc_status_arr[] = {
3856*44704f69SBart Van Assche {0x0, "No download microcode operation in progress"},
3857*44704f69SBart Van Assche {0x1, "Download in progress, awaiting more"},
3858*44704f69SBart Van Assche {0x2, "Download complete, updating non-volatile storage"},
3859*44704f69SBart Van Assche {0x3, "Updating non-volatile storage with deferred microcode"},
3860*44704f69SBart Van Assche {0x10, "Complete, no error, starting now"},
3861*44704f69SBart Van Assche {0x11, "Complete, no error, start after hard reset or power cycle"},
3862*44704f69SBart Van Assche {0x12, "Complete, no error, start after power cycle"},
3863*44704f69SBart Van Assche {0x13, "Complete, no error, start after activate_mc, hard reset or "
3864*44704f69SBart Van Assche "power cycle"},
3865*44704f69SBart Van Assche {0x80, "Error, discarded, see additional status"},
3866*44704f69SBart Van Assche {0x81, "Error, discarded, image error"},
3867*44704f69SBart Van Assche {0x82, "Timeout, discarded"},
3868*44704f69SBart Van Assche {0x83, "Internal error, need new microcode before reset"},
3869*44704f69SBart Van Assche {0x84, "Internal error, need new microcode, reset safe"},
3870*44704f69SBart Van Assche {0x85, "Unexpected activate_mc received"},
3871*44704f69SBart Van Assche {0x1000, NULL},
3872*44704f69SBart Van Assche };
3873*44704f69SBart Van Assche
3874*44704f69SBart Van Assche static const char *
get_mc_status(uint8_t status_val)3875*44704f69SBart Van Assche get_mc_status(uint8_t status_val)
3876*44704f69SBart Van Assche {
3877*44704f69SBart Van Assche const struct diag_page_code * mcsp;
3878*44704f69SBart Van Assche
3879*44704f69SBart Van Assche for (mcsp = mc_status_arr; mcsp->desc; ++mcsp) {
3880*44704f69SBart Van Assche if (status_val == mcsp->page_code)
3881*44704f69SBart Van Assche return mcsp->desc;
3882*44704f69SBart Van Assche }
3883*44704f69SBart Van Assche return "";
3884*44704f69SBart Van Assche }
3885*44704f69SBart Van Assche
3886*44704f69SBart Van Assche /* DOWNLOAD_MICROCODE_DPC [0xe] */
3887*44704f69SBart Van Assche static void
download_code_sdg(const uint8_t * resp,int resp_len)3888*44704f69SBart Van Assche download_code_sdg(const uint8_t * resp, int resp_len)
3889*44704f69SBart Van Assche {
3890*44704f69SBart Van Assche int k, num_subs;
3891*44704f69SBart Van Assche uint32_t gen_code;
3892*44704f69SBart Van Assche const uint8_t * bp;
3893*44704f69SBart Van Assche const uint8_t * last_bp;
3894*44704f69SBart Van Assche const char * cp;
3895*44704f69SBart Van Assche
3896*44704f69SBart Van Assche printf("Download microcode status diagnostic page:\n");
3897*44704f69SBart Van Assche if (resp_len < 4)
3898*44704f69SBart Van Assche goto truncated;
3899*44704f69SBart Van Assche num_subs = resp[1] + 1; /* number of subenclosures (add 1 for primary) */
3900*44704f69SBart Van Assche last_bp = resp + resp_len - 1;
3901*44704f69SBart Van Assche printf(" number of secondary subenclosures: %d\n", num_subs - 1);
3902*44704f69SBart Van Assche gen_code = sg_get_unaligned_be32(resp + 4);
3903*44704f69SBart Van Assche printf(" generation code: 0x%" PRIx32 "\n", gen_code);
3904*44704f69SBart Van Assche bp = resp + 8;
3905*44704f69SBart Van Assche for (k = 0; k < num_subs; ++k, bp += 16) {
3906*44704f69SBart Van Assche if ((bp + 3) > last_bp)
3907*44704f69SBart Van Assche goto truncated;
3908*44704f69SBart Van Assche cp = (0 == bp[1]) ? " [primary]" : "";
3909*44704f69SBart Van Assche printf(" subenclosure identifier: %d%s\n", bp[1], cp);
3910*44704f69SBart Van Assche cp = get_mc_status(bp[2]);
3911*44704f69SBart Van Assche if (strlen(cp) > 0) {
3912*44704f69SBart Van Assche printf(" download microcode status: %s [0x%x]\n", cp, bp[2]);
3913*44704f69SBart Van Assche printf(" download microcode additional status: 0x%x\n",
3914*44704f69SBart Van Assche bp[3]);
3915*44704f69SBart Van Assche } else
3916*44704f69SBart Van Assche printf(" download microcode status: 0x%x [additional "
3917*44704f69SBart Van Assche "status: 0x%x]\n", bp[2], bp[3]);
3918*44704f69SBart Van Assche printf(" download microcode maximum size: %d bytes\n",
3919*44704f69SBart Van Assche sg_get_unaligned_be32(bp + 4));
3920*44704f69SBart Van Assche printf(" download microcode expected buffer id: 0x%x\n", bp[11]);
3921*44704f69SBart Van Assche printf(" download microcode expected buffer id offset: %d\n",
3922*44704f69SBart Van Assche sg_get_unaligned_be32(bp + 12));
3923*44704f69SBart Van Assche }
3924*44704f69SBart Van Assche return;
3925*44704f69SBart Van Assche truncated:
3926*44704f69SBart Van Assche pr2serr(" <<<download: response too short>>>\n");
3927*44704f69SBart Van Assche return;
3928*44704f69SBart Van Assche }
3929*44704f69SBart Van Assche
3930*44704f69SBart Van Assche /* Reads hex data from command line, stdin or a file when in_hex is true.
3931*44704f69SBart Van Assche * Reads binary from stdin or file when in_hex is false. Returns 0 on
3932*44704f69SBart Van Assche * success, 1 otherwise. If inp is a file and may_have_at, then the
3933*44704f69SBart Van Assche * first character is skipped to get filename (since it should be '@'). */
3934*44704f69SBart Van Assche static int
read_hex(const char * inp,uint8_t * arr,int mx_arr_len,int * arr_len,bool in_hex,bool may_have_at,int vb)3935*44704f69SBart Van Assche read_hex(const char * inp, uint8_t * arr, int mx_arr_len, int * arr_len,
3936*44704f69SBart Van Assche bool in_hex, bool may_have_at, int vb)
3937*44704f69SBart Van Assche {
3938*44704f69SBart Van Assche bool has_stdin, split_line;
3939*44704f69SBart Van Assche int in_len, k, j, m, off, off_fn;
3940*44704f69SBart Van Assche unsigned int h;
3941*44704f69SBart Van Assche const char * lcp;
3942*44704f69SBart Van Assche char * cp;
3943*44704f69SBart Van Assche char * c2p;
3944*44704f69SBart Van Assche char line[512];
3945*44704f69SBart Van Assche char carry_over[4];
3946*44704f69SBart Van Assche FILE * fp = NULL;
3947*44704f69SBart Van Assche
3948*44704f69SBart Van Assche if ((NULL == inp) || (NULL == arr) || (NULL == arr_len))
3949*44704f69SBart Van Assche return 1;
3950*44704f69SBart Van Assche off_fn = may_have_at ? 1 : 0;
3951*44704f69SBart Van Assche lcp = inp;
3952*44704f69SBart Van Assche in_len = strlen(inp);
3953*44704f69SBart Van Assche if (0 == in_len) {
3954*44704f69SBart Van Assche *arr_len = 0;
3955*44704f69SBart Van Assche return 0;
3956*44704f69SBart Van Assche }
3957*44704f69SBart Van Assche has_stdin = ((1 == in_len) && ('-' == inp[0]));
3958*44704f69SBart Van Assche
3959*44704f69SBart Van Assche if (! in_hex) { /* binary, assume its not on the command line, */
3960*44704f69SBart Van Assche int fd; /* that leaves stdin or a file (pipe) */
3961*44704f69SBart Van Assche struct stat a_stat;
3962*44704f69SBart Van Assche
3963*44704f69SBart Van Assche if (has_stdin)
3964*44704f69SBart Van Assche fd = STDIN_FILENO;
3965*44704f69SBart Van Assche else {
3966*44704f69SBart Van Assche fd = open(inp + off_fn, O_RDONLY);
3967*44704f69SBart Van Assche if (fd < 0) {
3968*44704f69SBart Van Assche pr2serr("unable to open binary file %s: %s\n", inp + off_fn,
3969*44704f69SBart Van Assche safe_strerror(errno));
3970*44704f69SBart Van Assche return 1;
3971*44704f69SBart Van Assche }
3972*44704f69SBart Van Assche }
3973*44704f69SBart Van Assche k = read(fd, arr, mx_arr_len);
3974*44704f69SBart Van Assche if (k <= 0) {
3975*44704f69SBart Van Assche if (0 == k)
3976*44704f69SBart Van Assche pr2serr("read 0 bytes from binary file %s\n", inp + off_fn);
3977*44704f69SBart Van Assche else
3978*44704f69SBart Van Assche pr2serr("read from binary file %s: %s\n", inp + off_fn,
3979*44704f69SBart Van Assche safe_strerror(errno));
3980*44704f69SBart Van Assche if (! has_stdin)
3981*44704f69SBart Van Assche close(fd);
3982*44704f69SBart Van Assche return 1;
3983*44704f69SBart Van Assche }
3984*44704f69SBart Van Assche if ((0 == fstat(fd, &a_stat)) && S_ISFIFO(a_stat.st_mode)) {
3985*44704f69SBart Van Assche /* pipe; keep reading till error or 0 read */
3986*44704f69SBart Van Assche while (k < mx_arr_len) {
3987*44704f69SBart Van Assche m = read(fd, arr + k, mx_arr_len - k);
3988*44704f69SBart Van Assche if (0 == m)
3989*44704f69SBart Van Assche break;
3990*44704f69SBart Van Assche if (m < 0) {
3991*44704f69SBart Van Assche pr2serr("read from binary pipe %s: %s\n", inp + off_fn,
3992*44704f69SBart Van Assche safe_strerror(errno));
3993*44704f69SBart Van Assche if (! has_stdin)
3994*44704f69SBart Van Assche close(fd);
3995*44704f69SBart Van Assche return 1;
3996*44704f69SBart Van Assche }
3997*44704f69SBart Van Assche k += m;
3998*44704f69SBart Van Assche }
3999*44704f69SBart Van Assche }
4000*44704f69SBart Van Assche *arr_len = k;
4001*44704f69SBart Van Assche if (! has_stdin)
4002*44704f69SBart Van Assche close(fd);
4003*44704f69SBart Van Assche return 0;
4004*44704f69SBart Van Assche }
4005*44704f69SBart Van Assche if (has_stdin || (! may_have_at) || ('@' == inp[0])) {
4006*44704f69SBart Van Assche /* read hex from stdin or file */
4007*44704f69SBart Van Assche if (has_stdin)
4008*44704f69SBart Van Assche fp = stdin;
4009*44704f69SBart Van Assche else {
4010*44704f69SBart Van Assche fp = fopen(inp + off_fn, "r");
4011*44704f69SBart Van Assche if (NULL == fp) {
4012*44704f69SBart Van Assche pr2serr("%s: unable to open file: %s\n", __func__,
4013*44704f69SBart Van Assche inp + off_fn);
4014*44704f69SBart Van Assche return 1;
4015*44704f69SBart Van Assche }
4016*44704f69SBart Van Assche }
4017*44704f69SBart Van Assche carry_over[0] = 0;
4018*44704f69SBart Van Assche for (j = 0, off = 0; j < MX_DATA_IN_LINES; ++j) {
4019*44704f69SBart Van Assche if (NULL == fgets(line, sizeof(line), fp))
4020*44704f69SBart Van Assche break;
4021*44704f69SBart Van Assche in_len = strlen(line);
4022*44704f69SBart Van Assche if (in_len > 0) {
4023*44704f69SBart Van Assche if ('\n' == line[in_len - 1]) {
4024*44704f69SBart Van Assche --in_len;
4025*44704f69SBart Van Assche line[in_len] = '\0';
4026*44704f69SBart Van Assche split_line = false;
4027*44704f69SBart Van Assche } else
4028*44704f69SBart Van Assche split_line = true;
4029*44704f69SBart Van Assche }
4030*44704f69SBart Van Assche if (in_len < 1) {
4031*44704f69SBart Van Assche carry_over[0] = 0;
4032*44704f69SBart Van Assche continue;
4033*44704f69SBart Van Assche }
4034*44704f69SBart Van Assche if (carry_over[0]) {
4035*44704f69SBart Van Assche if (isxdigit((uint8_t)line[0])) {
4036*44704f69SBart Van Assche carry_over[1] = line[0];
4037*44704f69SBart Van Assche carry_over[2] = '\0';
4038*44704f69SBart Van Assche if (1 == sscanf(carry_over, "%x", &h))
4039*44704f69SBart Van Assche arr[off - 1] = h; /* back up and overwrite */
4040*44704f69SBart Van Assche else {
4041*44704f69SBart Van Assche pr2serr("%s: carry_over error ['%s'] around line "
4042*44704f69SBart Van Assche "%d\n", __func__, carry_over, j + 1);
4043*44704f69SBart Van Assche goto err_with_fp;
4044*44704f69SBart Van Assche }
4045*44704f69SBart Van Assche lcp = line + 1;
4046*44704f69SBart Van Assche --in_len;
4047*44704f69SBart Van Assche } else
4048*44704f69SBart Van Assche lcp = line;
4049*44704f69SBart Van Assche carry_over[0] = 0;
4050*44704f69SBart Van Assche } else
4051*44704f69SBart Van Assche lcp = line;
4052*44704f69SBart Van Assche m = strspn(lcp, " \t");
4053*44704f69SBart Van Assche if (m == in_len)
4054*44704f69SBart Van Assche continue;
4055*44704f69SBart Van Assche lcp += m;
4056*44704f69SBart Van Assche in_len -= m;
4057*44704f69SBart Van Assche if ('#' == *lcp)
4058*44704f69SBart Van Assche continue;
4059*44704f69SBart Van Assche k = strspn(lcp, "0123456789aAbBcCdDeEfF ,\t");
4060*44704f69SBart Van Assche if (in_len != k) {
4061*44704f69SBart Van Assche pr2serr("%s: syntax error at line %d, pos %d\n", __func__,
4062*44704f69SBart Van Assche j + 1, m + k + 1);
4063*44704f69SBart Van Assche if (vb > 2)
4064*44704f69SBart Van Assche pr2serr("first 40 characters of line: %.40s\n", line);
4065*44704f69SBart Van Assche goto err_with_fp;
4066*44704f69SBart Van Assche }
4067*44704f69SBart Van Assche for (k = 0; k < (mx_arr_len - off); ++k) {
4068*44704f69SBart Van Assche if (1 == sscanf(lcp, "%x", &h)) {
4069*44704f69SBart Van Assche if (h > 0xff) {
4070*44704f69SBart Van Assche pr2serr("%s: hex number larger than 0xff in line %d, "
4071*44704f69SBart Van Assche "pos %d\n", __func__, j + 1,
4072*44704f69SBart Van Assche (int)(lcp - line + 1));
4073*44704f69SBart Van Assche if (vb > 2)
4074*44704f69SBart Van Assche pr2serr("first 40 characters of line: %.40s\n",
4075*44704f69SBart Van Assche line);
4076*44704f69SBart Van Assche goto err_with_fp;
4077*44704f69SBart Van Assche }
4078*44704f69SBart Van Assche if (split_line && (1 == strlen(lcp))) {
4079*44704f69SBart Van Assche /* single trailing hex digit might be a split pair */
4080*44704f69SBart Van Assche carry_over[0] = *lcp;
4081*44704f69SBart Van Assche }
4082*44704f69SBart Van Assche arr[off + k] = h;
4083*44704f69SBart Van Assche lcp = strpbrk(lcp, " ,\t");
4084*44704f69SBart Van Assche if (NULL == lcp)
4085*44704f69SBart Van Assche break;
4086*44704f69SBart Van Assche lcp += strspn(lcp, " ,\t");
4087*44704f69SBart Van Assche if ('\0' == *lcp)
4088*44704f69SBart Van Assche break;
4089*44704f69SBart Van Assche } else {
4090*44704f69SBart Van Assche pr2serr("%s: error in line %d, at pos %d\n", __func__,
4091*44704f69SBart Van Assche j + 1, (int)(lcp - line + 1));
4092*44704f69SBart Van Assche if (vb > 2)
4093*44704f69SBart Van Assche pr2serr("first 40 characters of line: %.40s\n", line);
4094*44704f69SBart Van Assche goto err_with_fp;
4095*44704f69SBart Van Assche }
4096*44704f69SBart Van Assche }
4097*44704f69SBart Van Assche off += k + 1;
4098*44704f69SBart Van Assche if (off >= mx_arr_len)
4099*44704f69SBart Van Assche break;
4100*44704f69SBart Van Assche }
4101*44704f69SBart Van Assche *arr_len = off;
4102*44704f69SBart Van Assche } else { /* hex string on command line */
4103*44704f69SBart Van Assche k = strspn(inp, "0123456789aAbBcCdDeEfF, ");
4104*44704f69SBart Van Assche if (in_len != k) {
4105*44704f69SBart Van Assche pr2serr("%s: error at pos %d\n", __func__, k + 1);
4106*44704f69SBart Van Assche goto err_with_fp;
4107*44704f69SBart Van Assche }
4108*44704f69SBart Van Assche for (k = 0; k < mx_arr_len; ++k) {
4109*44704f69SBart Van Assche if (1 == sscanf(lcp, "%x", &h)) {
4110*44704f69SBart Van Assche if (h > 0xff) {
4111*44704f69SBart Van Assche pr2serr("%s: hex number larger than 0xff at pos %d\n",
4112*44704f69SBart Van Assche __func__, (int)(lcp - inp + 1));
4113*44704f69SBart Van Assche goto err_with_fp;
4114*44704f69SBart Van Assche }
4115*44704f69SBart Van Assche arr[k] = h;
4116*44704f69SBart Van Assche cp = (char *)strchr(lcp, ',');
4117*44704f69SBart Van Assche c2p = (char *)strchr(lcp, ' ');
4118*44704f69SBart Van Assche if (NULL == cp)
4119*44704f69SBart Van Assche cp = c2p;
4120*44704f69SBart Van Assche if (NULL == cp)
4121*44704f69SBart Van Assche break;
4122*44704f69SBart Van Assche if (c2p && (c2p < cp))
4123*44704f69SBart Van Assche cp = c2p;
4124*44704f69SBart Van Assche lcp = cp + 1;
4125*44704f69SBart Van Assche } else {
4126*44704f69SBart Van Assche pr2serr("%s: error at pos %d\n", __func__,
4127*44704f69SBart Van Assche (int)(lcp - inp + 1));
4128*44704f69SBart Van Assche goto err_with_fp;
4129*44704f69SBart Van Assche }
4130*44704f69SBart Van Assche }
4131*44704f69SBart Van Assche *arr_len = k + 1;
4132*44704f69SBart Van Assche }
4133*44704f69SBart Van Assche if (vb > 3) {
4134*44704f69SBart Van Assche pr2serr("%s: user provided data:\n", __func__);
4135*44704f69SBart Van Assche hex2stderr(arr, *arr_len, 0);
4136*44704f69SBart Van Assche }
4137*44704f69SBart Van Assche if (fp && (fp != stdin))
4138*44704f69SBart Van Assche fclose(fp);
4139*44704f69SBart Van Assche return 0;
4140*44704f69SBart Van Assche
4141*44704f69SBart Van Assche err_with_fp:
4142*44704f69SBart Van Assche if (fp && (fp != stdin))
4143*44704f69SBart Van Assche fclose(fp);
4144*44704f69SBart Van Assche return 1;
4145*44704f69SBart Van Assche }
4146*44704f69SBart Van Assche
4147*44704f69SBart Van Assche static int
process_status_dpage(struct sg_pt_base * ptvp,int page_code,uint8_t * resp,int resp_len,struct opts_t * op)4148*44704f69SBart Van Assche process_status_dpage(struct sg_pt_base * ptvp, int page_code, uint8_t * resp,
4149*44704f69SBart Van Assche int resp_len, struct opts_t * op)
4150*44704f69SBart Van Assche {
4151*44704f69SBart Van Assche int j, num_ths;
4152*44704f69SBart Van Assche int ret = 0;
4153*44704f69SBart Van Assche uint32_t ref_gen_code;
4154*44704f69SBart Van Assche const char * cp;
4155*44704f69SBart Van Assche struct enclosure_info primary_info;
4156*44704f69SBart Van Assche struct th_es_t tes;
4157*44704f69SBart Van Assche struct th_es_t * tesp;
4158*44704f69SBart Van Assche char bb[120];
4159*44704f69SBart Van Assche
4160*44704f69SBart Van Assche tesp = &tes;
4161*44704f69SBart Van Assche memset(tesp, 0, sizeof(tes));
4162*44704f69SBart Van Assche if ((cp = find_in_diag_page_desc(page_code)))
4163*44704f69SBart Van Assche snprintf(bb, sizeof(bb), "%s dpage", cp);
4164*44704f69SBart Van Assche else
4165*44704f69SBart Van Assche snprintf(bb, sizeof(bb), "dpage 0x%x", page_code);
4166*44704f69SBart Van Assche cp = bb;
4167*44704f69SBart Van Assche if (op->do_raw) {
4168*44704f69SBart Van Assche if (1 == op->do_raw)
4169*44704f69SBart Van Assche hex2stdout(resp + 4, resp_len - 4, -1);
4170*44704f69SBart Van Assche else {
4171*44704f69SBart Van Assche if (sg_set_binary_mode(STDOUT_FILENO) < 0)
4172*44704f69SBart Van Assche perror("sg_set_binary_mode");
4173*44704f69SBart Van Assche dStrRaw(resp, resp_len);
4174*44704f69SBart Van Assche }
4175*44704f69SBart Van Assche goto fini;
4176*44704f69SBart Van Assche } else if (op->do_hex) {
4177*44704f69SBart Van Assche if (op->do_hex > 2) {
4178*44704f69SBart Van Assche if (op->do_hex > 3) {
4179*44704f69SBart Van Assche if (4 == op->do_hex)
4180*44704f69SBart Van Assche printf("\n# %s:\n", cp);
4181*44704f69SBart Van Assche else
4182*44704f69SBart Van Assche printf("\n# %s [0x%x]:\n", cp, page_code);
4183*44704f69SBart Van Assche }
4184*44704f69SBart Van Assche hex2stdout(resp, resp_len, -1);
4185*44704f69SBart Van Assche } else {
4186*44704f69SBart Van Assche printf("# Response in hex for %s:\n", cp);
4187*44704f69SBart Van Assche hex2stdout(resp, resp_len, (2 == op->do_hex));
4188*44704f69SBart Van Assche }
4189*44704f69SBart Van Assche goto fini;
4190*44704f69SBart Van Assche }
4191*44704f69SBart Van Assche
4192*44704f69SBart Van Assche memset(&primary_info, 0, sizeof(primary_info));
4193*44704f69SBart Van Assche switch (page_code) {
4194*44704f69SBart Van Assche case SUPPORTED_DPC:
4195*44704f69SBart Van Assche supported_pages_sdg("Supported diagnostic pages", resp, resp_len);
4196*44704f69SBart Van Assche break;
4197*44704f69SBart Van Assche case CONFIGURATION_DPC:
4198*44704f69SBart Van Assche configuration_sdg(resp, resp_len);
4199*44704f69SBart Van Assche break;
4200*44704f69SBart Van Assche case ENC_STATUS_DPC:
4201*44704f69SBart Van Assche num_ths = build_type_desc_hdr_arr(ptvp, type_desc_hdr_arr,
4202*44704f69SBart Van Assche MX_ELEM_HDR, &ref_gen_code,
4203*44704f69SBart Van Assche &primary_info, op);
4204*44704f69SBart Van Assche if (num_ths < 0) {
4205*44704f69SBart Van Assche ret = num_ths;
4206*44704f69SBart Van Assche goto fini;
4207*44704f69SBart Van Assche }
4208*44704f69SBart Van Assche if ((1 == type_desc_hdr_count) && primary_info.have_info) {
4209*44704f69SBart Van Assche printf(" Primary enclosure logical identifier (hex): ");
4210*44704f69SBart Van Assche for (j = 0; j < 8; ++j)
4211*44704f69SBart Van Assche printf("%02x", primary_info.enc_log_id[j]);
4212*44704f69SBart Van Assche printf("\n");
4213*44704f69SBart Van Assche }
4214*44704f69SBart Van Assche tesp->th_base = type_desc_hdr_arr;
4215*44704f69SBart Van Assche tesp->num_ths = num_ths;
4216*44704f69SBart Van Assche enc_status_dp(tesp, ref_gen_code, resp, resp_len, op);
4217*44704f69SBart Van Assche break;
4218*44704f69SBart Van Assche case ARRAY_STATUS_DPC:
4219*44704f69SBart Van Assche num_ths = build_type_desc_hdr_arr(ptvp, type_desc_hdr_arr,
4220*44704f69SBart Van Assche MX_ELEM_HDR, &ref_gen_code,
4221*44704f69SBart Van Assche &primary_info, op);
4222*44704f69SBart Van Assche if (num_ths < 0) {
4223*44704f69SBart Van Assche ret = num_ths;
4224*44704f69SBart Van Assche goto fini;
4225*44704f69SBart Van Assche }
4226*44704f69SBart Van Assche if ((1 == type_desc_hdr_count) && primary_info.have_info) {
4227*44704f69SBart Van Assche printf(" Primary enclosure logical identifier (hex): ");
4228*44704f69SBart Van Assche for (j = 0; j < 8; ++j)
4229*44704f69SBart Van Assche printf("%02x", primary_info.enc_log_id[j]);
4230*44704f69SBart Van Assche printf("\n");
4231*44704f69SBart Van Assche }
4232*44704f69SBart Van Assche tesp->th_base = type_desc_hdr_arr;
4233*44704f69SBart Van Assche tesp->num_ths = num_ths;
4234*44704f69SBart Van Assche array_status_dp(tesp, ref_gen_code, resp, resp_len, op);
4235*44704f69SBart Van Assche break;
4236*44704f69SBart Van Assche case HELP_TEXT_DPC:
4237*44704f69SBart Van Assche printf("Help text diagnostic page (for primary "
4238*44704f69SBart Van Assche "subenclosure):\n");
4239*44704f69SBart Van Assche if (resp_len > 4)
4240*44704f69SBart Van Assche printf(" %.*s\n", resp_len - 4, resp + 4);
4241*44704f69SBart Van Assche else
4242*44704f69SBart Van Assche printf(" <empty>\n");
4243*44704f69SBart Van Assche break;
4244*44704f69SBart Van Assche case STRING_DPC:
4245*44704f69SBart Van Assche printf("String In diagnostic page (for primary "
4246*44704f69SBart Van Assche "subenclosure):\n");
4247*44704f69SBart Van Assche if (resp_len > 4)
4248*44704f69SBart Van Assche hex2stdout(resp + 4, resp_len - 4, 0);
4249*44704f69SBart Van Assche else
4250*44704f69SBart Van Assche printf(" <empty>\n");
4251*44704f69SBart Van Assche break;
4252*44704f69SBart Van Assche case THRESHOLD_DPC:
4253*44704f69SBart Van Assche num_ths = build_type_desc_hdr_arr(ptvp, type_desc_hdr_arr,
4254*44704f69SBart Van Assche MX_ELEM_HDR, &ref_gen_code,
4255*44704f69SBart Van Assche &primary_info, op);
4256*44704f69SBart Van Assche if (num_ths < 0) {
4257*44704f69SBart Van Assche ret = num_ths;
4258*44704f69SBart Van Assche goto fini;
4259*44704f69SBart Van Assche }
4260*44704f69SBart Van Assche if ((1 == type_desc_hdr_count) && primary_info.have_info) {
4261*44704f69SBart Van Assche printf(" Primary enclosure logical identifier (hex): ");
4262*44704f69SBart Van Assche for (j = 0; j < 8; ++j)
4263*44704f69SBart Van Assche printf("%02x", primary_info.enc_log_id[j]);
4264*44704f69SBart Van Assche printf("\n");
4265*44704f69SBart Van Assche }
4266*44704f69SBart Van Assche tesp->th_base = type_desc_hdr_arr;
4267*44704f69SBart Van Assche tesp->num_ths = num_ths;
4268*44704f69SBart Van Assche threshold_sdg(tesp, ref_gen_code, resp, resp_len, op);
4269*44704f69SBart Van Assche break;
4270*44704f69SBart Van Assche case ELEM_DESC_DPC:
4271*44704f69SBart Van Assche num_ths = build_type_desc_hdr_arr(ptvp, type_desc_hdr_arr,
4272*44704f69SBart Van Assche MX_ELEM_HDR, &ref_gen_code,
4273*44704f69SBart Van Assche &primary_info, op);
4274*44704f69SBart Van Assche if (num_ths < 0) {
4275*44704f69SBart Van Assche ret = num_ths;
4276*44704f69SBart Van Assche goto fini;
4277*44704f69SBart Van Assche }
4278*44704f69SBart Van Assche if ((1 == type_desc_hdr_count) && primary_info.have_info) {
4279*44704f69SBart Van Assche printf(" Primary enclosure logical identifier (hex): ");
4280*44704f69SBart Van Assche for (j = 0; j < 8; ++j)
4281*44704f69SBart Van Assche printf("%02x", primary_info.enc_log_id[j]);
4282*44704f69SBart Van Assche printf("\n");
4283*44704f69SBart Van Assche }
4284*44704f69SBart Van Assche tesp->th_base = type_desc_hdr_arr;
4285*44704f69SBart Van Assche tesp->num_ths = num_ths;
4286*44704f69SBart Van Assche element_desc_sdg(tesp, ref_gen_code, resp, resp_len, op);
4287*44704f69SBart Van Assche break;
4288*44704f69SBart Van Assche case SHORT_ENC_STATUS_DPC:
4289*44704f69SBart Van Assche printf("Short enclosure status diagnostic page, "
4290*44704f69SBart Van Assche "status=0x%x\n", resp[1]);
4291*44704f69SBart Van Assche break;
4292*44704f69SBart Van Assche case ENC_BUSY_DPC:
4293*44704f69SBart Van Assche printf("Enclosure Busy diagnostic page, "
4294*44704f69SBart Van Assche "busy=%d [vendor specific=0x%x]\n",
4295*44704f69SBart Van Assche resp[1] & 1, (resp[1] >> 1) & 0xff);
4296*44704f69SBart Van Assche break;
4297*44704f69SBart Van Assche case ADD_ELEM_STATUS_DPC:
4298*44704f69SBart Van Assche num_ths = build_type_desc_hdr_arr(ptvp, type_desc_hdr_arr,
4299*44704f69SBart Van Assche MX_ELEM_HDR, &ref_gen_code,
4300*44704f69SBart Van Assche &primary_info, op);
4301*44704f69SBart Van Assche if (num_ths < 0) {
4302*44704f69SBart Van Assche ret = num_ths;
4303*44704f69SBart Van Assche goto fini;
4304*44704f69SBart Van Assche }
4305*44704f69SBart Van Assche if (primary_info.have_info) {
4306*44704f69SBart Van Assche printf(" Primary enclosure logical identifier (hex): ");
4307*44704f69SBart Van Assche for (j = 0; j < 8; ++j)
4308*44704f69SBart Van Assche printf("%02x", primary_info.enc_log_id[j]);
4309*44704f69SBart Van Assche printf("\n");
4310*44704f69SBart Van Assche }
4311*44704f69SBart Van Assche tesp->th_base = type_desc_hdr_arr;
4312*44704f69SBart Van Assche tesp->num_ths = num_ths;
4313*44704f69SBart Van Assche additional_elem_sdg(tesp, ref_gen_code, resp, resp_len, op);
4314*44704f69SBart Van Assche break;
4315*44704f69SBart Van Assche case SUBENC_HELP_TEXT_DPC:
4316*44704f69SBart Van Assche subenc_help_sdg(resp, resp_len);
4317*44704f69SBart Van Assche break;
4318*44704f69SBart Van Assche case SUBENC_STRING_DPC:
4319*44704f69SBart Van Assche subenc_string_sdg(resp, resp_len);
4320*44704f69SBart Van Assche break;
4321*44704f69SBart Van Assche case SUPPORTED_SES_DPC:
4322*44704f69SBart Van Assche supported_pages_sdg("Supported SES diagnostic pages", resp,
4323*44704f69SBart Van Assche resp_len);
4324*44704f69SBart Van Assche break;
4325*44704f69SBart Van Assche case DOWNLOAD_MICROCODE_DPC:
4326*44704f69SBart Van Assche download_code_sdg(resp, resp_len);
4327*44704f69SBart Van Assche break;
4328*44704f69SBart Van Assche case SUBENC_NICKNAME_DPC:
4329*44704f69SBart Van Assche subenc_nickname_sdg(resp, resp_len);
4330*44704f69SBart Van Assche break;
4331*44704f69SBart Van Assche default:
4332*44704f69SBart Van Assche printf("Cannot decode response from diagnostic page: %s\n", cp);
4333*44704f69SBart Van Assche hex2stdout(resp, resp_len, 0);
4334*44704f69SBart Van Assche }
4335*44704f69SBart Van Assche
4336*44704f69SBart Van Assche fini:
4337*44704f69SBart Van Assche return ret;
4338*44704f69SBart Van Assche }
4339*44704f69SBart Van Assche
4340*44704f69SBart Van Assche /* Display "status" page or pages (if op->page_code==0xff) . data-in from
4341*44704f69SBart Van Assche * SES device or user provided (with --data= option). Return 0 for success */
4342*44704f69SBart Van Assche static int
process_status_page_s(struct sg_pt_base * ptvp,struct opts_t * op)4343*44704f69SBart Van Assche process_status_page_s(struct sg_pt_base * ptvp, struct opts_t * op)
4344*44704f69SBart Van Assche {
4345*44704f69SBart Van Assche int page_code, ret, resp_len;
4346*44704f69SBart Van Assche uint8_t * resp = NULL;
4347*44704f69SBart Van Assche uint8_t * free_resp = NULL;
4348*44704f69SBart Van Assche
4349*44704f69SBart Van Assche resp = sg_memalign(op->maxlen, 0, &free_resp, false);
4350*44704f69SBart Van Assche if (NULL == resp) {
4351*44704f69SBart Van Assche pr2serr("%s: unable to allocate %d bytes on heap\n", __func__,
4352*44704f69SBart Van Assche op->maxlen);
4353*44704f69SBart Van Assche ret = -1;
4354*44704f69SBart Van Assche goto fini;
4355*44704f69SBart Van Assche }
4356*44704f69SBart Van Assche page_code = op->page_code;
4357*44704f69SBart Van Assche if (ALL_DPC == page_code) {
4358*44704f69SBart Van Assche int k, n;
4359*44704f69SBart Van Assche uint8_t pc, prev;
4360*44704f69SBart Van Assche uint8_t supp_dpg_arr[256];
4361*44704f69SBart Van Assche const int s_arr_sz = sizeof(supp_dpg_arr);
4362*44704f69SBart Van Assche
4363*44704f69SBart Van Assche memset(supp_dpg_arr, 0, s_arr_sz);
4364*44704f69SBart Van Assche ret = do_rec_diag(ptvp, SUPPORTED_DPC, resp, op->maxlen, op,
4365*44704f69SBart Van Assche &resp_len);
4366*44704f69SBart Van Assche if (ret) /* SUPPORTED_DPC failed so try SUPPORTED_SES_DPC */
4367*44704f69SBart Van Assche ret = do_rec_diag(ptvp, SUPPORTED_SES_DPC, resp, op->maxlen, op,
4368*44704f69SBart Van Assche &resp_len);
4369*44704f69SBart Van Assche if (ret)
4370*44704f69SBart Van Assche goto fini;
4371*44704f69SBart Van Assche for (n = 0, pc = 0; (n < s_arr_sz) && (n < (resp_len - 4)); ++n) {
4372*44704f69SBart Van Assche prev = pc;
4373*44704f69SBart Van Assche pc = resp[4 + n];
4374*44704f69SBart Van Assche if (prev > pc) {
4375*44704f69SBart Van Assche if (pc) { /* could be zero pad at end which is ok */
4376*44704f69SBart Van Assche pr2serr("%s: Supported (SES) dpage seems corrupt, "
4377*44704f69SBart Van Assche "should ascend\n", __func__);
4378*44704f69SBart Van Assche ret = SG_LIB_CAT_OTHER;
4379*44704f69SBart Van Assche goto fini;
4380*44704f69SBart Van Assche }
4381*44704f69SBart Van Assche break;
4382*44704f69SBart Van Assche }
4383*44704f69SBart Van Assche if (pc > 0x2f)
4384*44704f69SBart Van Assche break;
4385*44704f69SBart Van Assche supp_dpg_arr[n] = pc;
4386*44704f69SBart Van Assche }
4387*44704f69SBart Van Assche for (k = 0; k < n; ++k) {
4388*44704f69SBart Van Assche page_code = supp_dpg_arr[k];
4389*44704f69SBart Van Assche ret = do_rec_diag(ptvp, page_code, resp, op->maxlen, op,
4390*44704f69SBart Van Assche &resp_len);
4391*44704f69SBart Van Assche if (ret)
4392*44704f69SBart Van Assche goto fini;
4393*44704f69SBart Van Assche ret = process_status_dpage(ptvp, page_code, resp, resp_len, op);
4394*44704f69SBart Van Assche }
4395*44704f69SBart Van Assche } else { /* asking for a specific page code */
4396*44704f69SBart Van Assche ret = do_rec_diag(ptvp, page_code, resp, op->maxlen, op, &resp_len);
4397*44704f69SBart Van Assche if (ret)
4398*44704f69SBart Van Assche goto fini;
4399*44704f69SBart Van Assche ret = process_status_dpage(ptvp, page_code, resp, resp_len, op);
4400*44704f69SBart Van Assche }
4401*44704f69SBart Van Assche
4402*44704f69SBart Van Assche fini:
4403*44704f69SBart Van Assche if (free_resp)
4404*44704f69SBart Van Assche free(free_resp);
4405*44704f69SBart Van Assche return ret;
4406*44704f69SBart Van Assche }
4407*44704f69SBart Van Assche
4408*44704f69SBart Van Assche static void
devslotnum_and_sasaddr(struct join_row_t * jrp,const uint8_t * ae_bp)4409*44704f69SBart Van Assche devslotnum_and_sasaddr(struct join_row_t * jrp, const uint8_t * ae_bp)
4410*44704f69SBart Van Assche {
4411*44704f69SBart Van Assche if ((NULL == jrp) || (NULL == ae_bp) || (0 == (0x10 & ae_bp[0])))
4412*44704f69SBart Van Assche return; /* sanity and expect EIP=1 */
4413*44704f69SBart Van Assche switch (0xf & ae_bp[0]) {
4414*44704f69SBart Van Assche case TPROTO_FCP:
4415*44704f69SBart Van Assche jrp->dev_slot_num = ae_bp[7];
4416*44704f69SBart Van Assche break;
4417*44704f69SBart Van Assche case TPROTO_SAS:
4418*44704f69SBart Van Assche if (0 == (0xc0 & ae_bp[5])) {
4419*44704f69SBart Van Assche /* only for device slot and array device slot elements */
4420*44704f69SBart Van Assche jrp->dev_slot_num = ae_bp[7];
4421*44704f69SBart Van Assche if (ae_bp[4] > 0) { /* number of phys */
4422*44704f69SBart Van Assche int m;
4423*44704f69SBart Van Assche
4424*44704f69SBart Van Assche /* Use the first phy's "SAS ADDRESS" field */
4425*44704f69SBart Van Assche for (m = 0; m < 8; ++m)
4426*44704f69SBart Van Assche jrp->sas_addr[m] = ae_bp[(4 + 4 + 12) + m];
4427*44704f69SBart Van Assche }
4428*44704f69SBart Van Assche }
4429*44704f69SBart Van Assche break;
4430*44704f69SBart Van Assche case TPROTO_PCIE:
4431*44704f69SBart Van Assche jrp->dev_slot_num = ae_bp[7];
4432*44704f69SBart Van Assche break;
4433*44704f69SBart Van Assche default:
4434*44704f69SBart Van Assche ;
4435*44704f69SBart Van Assche }
4436*44704f69SBart Van Assche }
4437*44704f69SBart Van Assche
4438*44704f69SBart Van Assche static const char *
offset_str(long offset,bool in_hex,char * b,int blen)4439*44704f69SBart Van Assche offset_str(long offset, bool in_hex, char * b, int blen)
4440*44704f69SBart Van Assche {
4441*44704f69SBart Van Assche if (in_hex && (offset >= 0))
4442*44704f69SBart Van Assche snprintf(b, blen, "0x%lx", offset);
4443*44704f69SBart Van Assche else
4444*44704f69SBart Van Assche snprintf(b, blen, "%ld", offset);
4445*44704f69SBart Van Assche return b;
4446*44704f69SBart Van Assche }
4447*44704f69SBart Van Assche
4448*44704f69SBart Van Assche /* Returns broken_ei which is only true when EIP=1 and EIIOE=0 is overridden
4449*44704f69SBart Van Assche * as outlined in join array description near the top of this file. */
4450*44704f69SBart Van Assche static bool
join_aes_helper(const uint8_t * ae_bp,const uint8_t * ae_last_bp,const struct th_es_t * tesp,const struct opts_t * op)4451*44704f69SBart Van Assche join_aes_helper(const uint8_t * ae_bp, const uint8_t * ae_last_bp,
4452*44704f69SBart Van Assche const struct th_es_t * tesp, const struct opts_t * op)
4453*44704f69SBart Van Assche {
4454*44704f69SBart Van Assche int k, j, ei, eiioe, aes_i, hex, blen;
4455*44704f69SBart Van Assche bool eip, broken_ei;
4456*44704f69SBart Van Assche struct join_row_t * jrp;
4457*44704f69SBart Van Assche struct join_row_t * jr2p;
4458*44704f69SBart Van Assche const struct type_desc_hdr_t * tdhp = tesp->th_base;
4459*44704f69SBart Van Assche char b[20];
4460*44704f69SBart Van Assche
4461*44704f69SBart Van Assche jrp = tesp->j_base;
4462*44704f69SBart Van Assche blen = sizeof(b);
4463*44704f69SBart Van Assche hex = op->do_hex;
4464*44704f69SBart Van Assche broken_ei = false;
4465*44704f69SBart Van Assche /* loop over all type descriptor headers in the Configuration dpge */
4466*44704f69SBart Van Assche for (k = 0, aes_i = 0; k < tesp->num_ths; ++k, ++tdhp) {
4467*44704f69SBart Van Assche if (is_et_used_by_aes(tdhp->etype)) {
4468*44704f69SBart Van Assche /* only consider element types that AES element are permiited
4469*44704f69SBart Van Assche * to refer to, then loop over those number of elements */
4470*44704f69SBart Van Assche for (j = 0; j < tdhp->num_elements;
4471*44704f69SBart Van Assche ++j, ++aes_i, ae_bp += ae_bp[1] + 2) {
4472*44704f69SBart Van Assche if ((ae_bp + 1) > ae_last_bp) {
4473*44704f69SBart Van Assche if (op->verbose || op->warn)
4474*44704f69SBart Van Assche pr2serr("warning: %s: off end of ae page\n",
4475*44704f69SBart Van Assche __func__);
4476*44704f69SBart Van Assche return broken_ei;
4477*44704f69SBart Van Assche }
4478*44704f69SBart Van Assche eip = !!(ae_bp[0] & 0x10); /* EIP == Element Index Present */
4479*44704f69SBart Van Assche if (eip) {
4480*44704f69SBart Van Assche eiioe = 0x3 & ae_bp[2];
4481*44704f69SBart Van Assche if ((0 == eiioe) && op->eiioe_force)
4482*44704f69SBart Van Assche eiioe = 1;
4483*44704f69SBart Van Assche } else
4484*44704f69SBart Van Assche eiioe = 0;
4485*44704f69SBart Van Assche if (eip && (1 == eiioe)) { /* EIP and EIIOE=1 */
4486*44704f69SBart Van Assche ei = ae_bp[3];
4487*44704f69SBart Van Assche jr2p = tesp->j_base + ei;
4488*44704f69SBart Van Assche if ((ei >= tesp->num_j_eoe) ||
4489*44704f69SBart Van Assche (NULL == jr2p->enc_statp)) {
4490*44704f69SBart Van Assche pr2serr("%s: oi=%d, ei=%d [num_eoe=%d], eiioe=1 "
4491*44704f69SBart Van Assche "not in join_arr\n", __func__, k, ei,
4492*44704f69SBart Van Assche tesp->num_j_eoe);
4493*44704f69SBart Van Assche return broken_ei;
4494*44704f69SBart Van Assche }
4495*44704f69SBart Van Assche devslotnum_and_sasaddr(jr2p, ae_bp);
4496*44704f69SBart Van Assche if (jr2p->ae_statp) {
4497*44704f69SBart Van Assche if (op->warn || op->verbose) {
4498*44704f69SBart Van Assche pr2serr("warning: aes slot already in use, "
4499*44704f69SBart Van Assche "keep existing AES+%s\n\t",
4500*44704f69SBart Van Assche offset_str(jr2p->ae_statp - add_elem_rsp,
4501*44704f69SBart Van Assche hex, b, blen));
4502*44704f69SBart Van Assche pr2serr("dropping AES+%s [length=%d, oi=%d, "
4503*44704f69SBart Van Assche "ei=%d, aes_i=%d]\n",
4504*44704f69SBart Van Assche offset_str(ae_bp - add_elem_rsp, hex, b,
4505*44704f69SBart Van Assche blen),
4506*44704f69SBart Van Assche ae_bp[1] + 2, k, ei, aes_i);
4507*44704f69SBart Van Assche }
4508*44704f69SBart Van Assche } else
4509*44704f69SBart Van Assche jr2p->ae_statp = ae_bp;
4510*44704f69SBart Van Assche } else if (eip && (0 == eiioe)) { /* SES-2 so be careful */
4511*44704f69SBart Van Assche ei = ae_bp[3];
4512*44704f69SBart Van Assche try_again:
4513*44704f69SBart Van Assche /* Check AES dpage descriptor ei is valid */
4514*44704f69SBart Van Assche for (jr2p = tesp->j_base; jr2p->enc_statp; ++jr2p) {
4515*44704f69SBart Van Assche if (broken_ei) {
4516*44704f69SBart Van Assche if (ei == jr2p->ei_aess)
4517*44704f69SBart Van Assche break;
4518*44704f69SBart Van Assche } else {
4519*44704f69SBart Van Assche if (ei == jr2p->ei_eoe)
4520*44704f69SBart Van Assche break;
4521*44704f69SBart Van Assche }
4522*44704f69SBart Van Assche }
4523*44704f69SBart Van Assche if (NULL == jr2p->enc_statp) {
4524*44704f69SBart Van Assche pr2serr("warning: %s: oi=%d, ei=%d (broken_ei=%d) "
4525*44704f69SBart Van Assche "not in join_arr\n", __func__, k, ei,
4526*44704f69SBart Van Assche (int)broken_ei);
4527*44704f69SBart Van Assche return broken_ei;
4528*44704f69SBart Van Assche }
4529*44704f69SBart Van Assche if (! is_et_used_by_aes(jr2p->etype)) {
4530*44704f69SBart Van Assche /* unexpected element type so ... */
4531*44704f69SBart Van Assche broken_ei = true;
4532*44704f69SBart Van Assche goto try_again;
4533*44704f69SBart Van Assche }
4534*44704f69SBart Van Assche devslotnum_and_sasaddr(jr2p, ae_bp);
4535*44704f69SBart Van Assche if (jr2p->ae_statp) {
4536*44704f69SBart Van Assche /* 1 to 1 AES to ES mapping assumption violated */
4537*44704f69SBart Van Assche if ((0 == ei) && (TPROTO_SAS == (0xf & ae_bp[0])) &&
4538*44704f69SBart Van Assche (1 == (ae_bp[5] >> 6))) {
4539*44704f69SBart Van Assche /* heuristic for (hack) Areca 8028 */
4540*44704f69SBart Van Assche for (jr2p = tesp->j_base; jr2p->enc_statp;
4541*44704f69SBart Van Assche ++jr2p) {
4542*44704f69SBart Van Assche if ((-1 == jr2p->indiv_i) ||
4543*44704f69SBart Van Assche (! is_et_used_by_aes(jr2p->etype)) ||
4544*44704f69SBart Van Assche jr2p->ae_statp)
4545*44704f69SBart Van Assche continue;
4546*44704f69SBart Van Assche jr2p->ae_statp = ae_bp;
4547*44704f69SBart Van Assche break;
4548*44704f69SBart Van Assche }
4549*44704f69SBart Van Assche if ((NULL == jr2p->enc_statp) &&
4550*44704f69SBart Van Assche (op->warn || op->verbose))
4551*44704f69SBart Van Assche pr2serr("warning2: dropping AES+%s [length="
4552*44704f69SBart Van Assche "%d, oi=%d, ei=%d, aes_i=%d]\n",
4553*44704f69SBart Van Assche offset_str(ae_bp - add_elem_rsp, hex,
4554*44704f69SBart Van Assche b, blen),
4555*44704f69SBart Van Assche ae_bp[1] + 2, k, ei, aes_i);
4556*44704f69SBart Van Assche } else if (op->warn || op->verbose) {
4557*44704f69SBart Van Assche pr2serr("warning3: aes slot already in use, "
4558*44704f69SBart Van Assche "keep existing AES+%s\n\t",
4559*44704f69SBart Van Assche offset_str(jr2p->ae_statp - add_elem_rsp,
4560*44704f69SBart Van Assche hex, b, blen));
4561*44704f69SBart Van Assche pr2serr("dropping AES+%s [length=%d, oi=%d, ei="
4562*44704f69SBart Van Assche "%d, aes_i=%d]\n",
4563*44704f69SBart Van Assche offset_str(ae_bp - add_elem_rsp, hex, b,
4564*44704f69SBart Van Assche blen),
4565*44704f69SBart Van Assche ae_bp[1] + 2, k, ei, aes_i);
4566*44704f69SBart Van Assche }
4567*44704f69SBart Van Assche } else
4568*44704f69SBart Van Assche jr2p->ae_statp = ae_bp;
4569*44704f69SBart Van Assche } else if (eip) { /* EIP and EIIOE=2,3 */
4570*44704f69SBart Van Assche ei = ae_bp[3];
4571*44704f69SBart Van Assche for (jr2p = tesp->j_base; jr2p->enc_statp; ++jr2p) {
4572*44704f69SBart Van Assche if (ei == jr2p->ei_eoe)
4573*44704f69SBart Van Assche break; /* good, found match on ei_eoe */
4574*44704f69SBart Van Assche }
4575*44704f69SBart Van Assche if (NULL == jr2p->enc_statp) {
4576*44704f69SBart Van Assche pr2serr("warning: %s: oi=%d, ei=%d, not in "
4577*44704f69SBart Van Assche "join_arr\n", __func__, k, ei);
4578*44704f69SBart Van Assche return broken_ei;
4579*44704f69SBart Van Assche }
4580*44704f69SBart Van Assche if (! is_et_used_by_aes(jr2p->etype)) {
4581*44704f69SBart Van Assche pr2serr("warning: %s: oi=%d, ei=%d, unexpected "
4582*44704f69SBart Van Assche "element_type=0x%x\n", __func__, k, ei,
4583*44704f69SBart Van Assche jr2p->etype);
4584*44704f69SBart Van Assche return broken_ei;
4585*44704f69SBart Van Assche }
4586*44704f69SBart Van Assche devslotnum_and_sasaddr(jr2p, ae_bp);
4587*44704f69SBart Van Assche if (jr2p->ae_statp) {
4588*44704f69SBart Van Assche if (op->warn || op->verbose) {
4589*44704f69SBart Van Assche pr2serr("warning3: aes slot already in use, "
4590*44704f69SBart Van Assche "keep existing AES+%s\n\t",
4591*44704f69SBart Van Assche offset_str(jr2p->ae_statp - add_elem_rsp,
4592*44704f69SBart Van Assche hex, b, blen));
4593*44704f69SBart Van Assche pr2serr("dropping AES+%s [length=%d, oi=%d, ei="
4594*44704f69SBart Van Assche "%d, aes_i=%d]\n",
4595*44704f69SBart Van Assche offset_str(ae_bp - add_elem_rsp, hex, b,
4596*44704f69SBart Van Assche blen),
4597*44704f69SBart Van Assche ae_bp[1] + 2, k, ei, aes_i);
4598*44704f69SBart Van Assche }
4599*44704f69SBart Van Assche } else
4600*44704f69SBart Van Assche jr2p->ae_statp = ae_bp;
4601*44704f69SBart Van Assche } else { /* EIP=0 */
4602*44704f69SBart Van Assche /* step jrp over overall elements or those with
4603*44704f69SBart Van Assche * jrp->ae_statp already used */
4604*44704f69SBart Van Assche while (jrp->enc_statp && ((-1 == jrp->indiv_i) ||
4605*44704f69SBart Van Assche jrp->ae_statp))
4606*44704f69SBart Van Assche ++jrp;
4607*44704f69SBart Van Assche if (NULL == jrp->enc_statp) {
4608*44704f69SBart Van Assche pr2serr("warning: %s: join_arr has no space for "
4609*44704f69SBart Van Assche "ae\n", __func__);
4610*44704f69SBart Van Assche return broken_ei;
4611*44704f69SBart Van Assche }
4612*44704f69SBart Van Assche jrp->ae_statp = ae_bp;
4613*44704f69SBart Van Assche ++jrp;
4614*44704f69SBart Van Assche }
4615*44704f69SBart Van Assche } /* end_for: loop over non-overall elements of the
4616*44704f69SBart Van Assche * current type descriptor header */
4617*44704f69SBart Van Assche } else { /* element type _not_ relevant to ae status */
4618*44704f69SBart Van Assche /* step jrp over overall and individual elements */
4619*44704f69SBart Van Assche for (j = 0; j <= tdhp->num_elements; ++j, ++jrp) {
4620*44704f69SBart Van Assche if (NULL == jrp->enc_statp) {
4621*44704f69SBart Van Assche pr2serr("warning: %s: join_arr has no space\n",
4622*44704f69SBart Van Assche __func__);
4623*44704f69SBart Van Assche return broken_ei;
4624*44704f69SBart Van Assche }
4625*44704f69SBart Van Assche }
4626*44704f69SBart Van Assche }
4627*44704f69SBart Van Assche } /* end_for: loop over type descriptor headers */
4628*44704f69SBart Van Assche return broken_ei;
4629*44704f69SBart Van Assche }
4630*44704f69SBart Van Assche
4631*44704f69SBart Van Assche
4632*44704f69SBart Van Assche /* User output of join array */
4633*44704f69SBart Van Assche static void
join_array_display(struct th_es_t * tesp,struct opts_t * op)4634*44704f69SBart Van Assche join_array_display(struct th_es_t * tesp, struct opts_t * op)
4635*44704f69SBart Van Assche {
4636*44704f69SBart Van Assche bool got1, need_aes;
4637*44704f69SBart Van Assche int k, j, blen, desc_len, dn_len;
4638*44704f69SBart Van Assche const uint8_t * ae_bp;
4639*44704f69SBart Van Assche const char * cp;
4640*44704f69SBart Van Assche const uint8_t * ed_bp;
4641*44704f69SBart Van Assche struct join_row_t * jrp;
4642*44704f69SBart Van Assche uint8_t * t_bp;
4643*44704f69SBart Van Assche char b[64];
4644*44704f69SBart Van Assche
4645*44704f69SBart Van Assche blen = sizeof(b);
4646*44704f69SBart Van Assche need_aes = (op->page_code_given &&
4647*44704f69SBart Van Assche (ADD_ELEM_STATUS_DPC == op->page_code));
4648*44704f69SBart Van Assche dn_len = op->desc_name ? (int)strlen(op->desc_name) : 0;
4649*44704f69SBart Van Assche for (k = 0, jrp = tesp->j_base, got1 = false;
4650*44704f69SBart Van Assche ((k < MX_JOIN_ROWS) && jrp->enc_statp); ++k, ++jrp) {
4651*44704f69SBart Van Assche if (op->ind_given) {
4652*44704f69SBart Van Assche if (op->ind_th != jrp->th_i)
4653*44704f69SBart Van Assche continue;
4654*44704f69SBart Van Assche if (! match_ind_indiv(jrp->indiv_i, op))
4655*44704f69SBart Van Assche continue;
4656*44704f69SBart Van Assche }
4657*44704f69SBart Van Assche if (need_aes && (NULL == jrp->ae_statp))
4658*44704f69SBart Van Assche continue;
4659*44704f69SBart Van Assche ed_bp = jrp->elem_descp;
4660*44704f69SBart Van Assche if (op->desc_name) {
4661*44704f69SBart Van Assche if (NULL == ed_bp)
4662*44704f69SBart Van Assche continue;
4663*44704f69SBart Van Assche desc_len = sg_get_unaligned_be16(ed_bp + 2);
4664*44704f69SBart Van Assche /* some element descriptor strings have trailing NULLs and
4665*44704f69SBart Van Assche * count them in their length; adjust */
4666*44704f69SBart Van Assche while (desc_len && ('\0' == ed_bp[4 + desc_len - 1]))
4667*44704f69SBart Van Assche --desc_len;
4668*44704f69SBart Van Assche if (desc_len != dn_len)
4669*44704f69SBart Van Assche continue;
4670*44704f69SBart Van Assche if (0 != strncmp(op->desc_name, (const char *)(ed_bp + 4),
4671*44704f69SBart Van Assche desc_len))
4672*44704f69SBart Van Assche continue;
4673*44704f69SBart Van Assche } else if (op->dev_slot_num >= 0) {
4674*44704f69SBart Van Assche if (op->dev_slot_num != jrp->dev_slot_num)
4675*44704f69SBart Van Assche continue;
4676*44704f69SBart Van Assche } else if (saddr_non_zero(op->sas_addr)) {
4677*44704f69SBart Van Assche for (j = 0; j < 8; ++j) {
4678*44704f69SBart Van Assche if (op->sas_addr[j] != jrp->sas_addr[j])
4679*44704f69SBart Van Assche break;
4680*44704f69SBart Van Assche }
4681*44704f69SBart Van Assche if (j < 8)
4682*44704f69SBart Van Assche continue;
4683*44704f69SBart Van Assche }
4684*44704f69SBart Van Assche got1 = true;
4685*44704f69SBart Van Assche if ((op->do_filter > 1) && (1 != (0xf & jrp->enc_statp[0])))
4686*44704f69SBart Van Assche continue; /* when '-ff' and status!=OK, skip */
4687*44704f69SBart Van Assche cp = etype_str(jrp->etype, b, blen);
4688*44704f69SBart Van Assche if (ed_bp) {
4689*44704f69SBart Van Assche desc_len = sg_get_unaligned_be16(ed_bp + 2) + 4;
4690*44704f69SBart Van Assche if (desc_len > 4)
4691*44704f69SBart Van Assche printf("%.*s [%d,%d] Element type: %s\n", desc_len - 4,
4692*44704f69SBart Van Assche (const char *)(ed_bp + 4), jrp->th_i,
4693*44704f69SBart Van Assche jrp->indiv_i, cp);
4694*44704f69SBart Van Assche else
4695*44704f69SBart Van Assche printf("[%d,%d] Element type: %s\n", jrp->th_i,
4696*44704f69SBart Van Assche jrp->indiv_i, cp);
4697*44704f69SBart Van Assche } else
4698*44704f69SBart Van Assche printf("[%d,%d] Element type: %s\n", jrp->th_i,
4699*44704f69SBart Van Assche jrp->indiv_i, cp);
4700*44704f69SBart Van Assche printf(" Enclosure Status:\n");
4701*44704f69SBart Van Assche enc_status_helper(" ", jrp->enc_statp, jrp->etype, false, op);
4702*44704f69SBart Van Assche if (jrp->ae_statp) {
4703*44704f69SBart Van Assche printf(" Additional Element Status:\n");
4704*44704f69SBart Van Assche ae_bp = jrp->ae_statp;
4705*44704f69SBart Van Assche desc_len = ae_bp[1] + 2;
4706*44704f69SBart Van Assche additional_elem_helper(" ", ae_bp, desc_len, jrp->etype,
4707*44704f69SBart Van Assche tesp, op);
4708*44704f69SBart Van Assche }
4709*44704f69SBart Van Assche if (jrp->thresh_inp) {
4710*44704f69SBart Van Assche t_bp = jrp->thresh_inp;
4711*44704f69SBart Van Assche threshold_helper(" Threshold In:\n", " ", t_bp, jrp->etype,
4712*44704f69SBart Van Assche op);
4713*44704f69SBart Van Assche }
4714*44704f69SBart Van Assche }
4715*44704f69SBart Van Assche if (! got1) {
4716*44704f69SBart Van Assche if (op->ind_given) {
4717*44704f69SBart Van Assche printf(" >>> no match on --index=%d,%d", op->ind_th,
4718*44704f69SBart Van Assche op->ind_indiv);
4719*44704f69SBart Van Assche if (op->ind_indiv_last > op->ind_indiv)
4720*44704f69SBart Van Assche printf("-%d\n", op->ind_indiv_last);
4721*44704f69SBart Van Assche else
4722*44704f69SBart Van Assche printf("\n");
4723*44704f69SBart Van Assche } else if (op->desc_name)
4724*44704f69SBart Van Assche printf(" >>> no match on --descriptor=%s\n", op->desc_name);
4725*44704f69SBart Van Assche else if (op->dev_slot_num >= 0)
4726*44704f69SBart Van Assche printf(" >>> no match on --dev-slot-name=%d\n",
4727*44704f69SBart Van Assche op->dev_slot_num);
4728*44704f69SBart Van Assche else if (saddr_non_zero(op->sas_addr)) {
4729*44704f69SBart Van Assche printf(" >>> no match on --sas-addr=0x");
4730*44704f69SBart Van Assche for (j = 0; j < 8; ++j)
4731*44704f69SBart Van Assche printf("%02x", op->sas_addr[j]);
4732*44704f69SBart Van Assche printf("\n");
4733*44704f69SBart Van Assche }
4734*44704f69SBart Van Assche }
4735*44704f69SBart Van Assche }
4736*44704f69SBart Van Assche
4737*44704f69SBart Van Assche /* This is for debugging, output to stderr */
4738*44704f69SBart Van Assche static void
join_array_dump(struct th_es_t * tesp,int broken_ei,struct opts_t * op)4739*44704f69SBart Van Assche join_array_dump(struct th_es_t * tesp, int broken_ei, struct opts_t * op)
4740*44704f69SBart Van Assche {
4741*44704f69SBart Van Assche int k, j, blen, hex;
4742*44704f69SBart Van Assche int eiioe_count = 0;
4743*44704f69SBart Van Assche int eip_count = 0;
4744*44704f69SBart Van Assche struct join_row_t * jrp;
4745*44704f69SBart Van Assche char b[64];
4746*44704f69SBart Van Assche
4747*44704f69SBart Van Assche blen = sizeof(b);
4748*44704f69SBart Van Assche hex = op->do_hex;
4749*44704f69SBart Van Assche pr2serr("Dump of join array, each line is a row. Lines start with\n");
4750*44704f69SBart Van Assche pr2serr("[<element_type>: <type_hdr_index>,<elem_ind_within>]\n");
4751*44704f69SBart Van Assche pr2serr("'-1' indicates overall element or not applicable.\n");
4752*44704f69SBart Van Assche jrp = tesp->j_base;
4753*44704f69SBart Van Assche for (k = 0; ((k < MX_JOIN_ROWS) && jrp->enc_statp); ++k, ++jrp) {
4754*44704f69SBart Van Assche pr2serr("[0x%x: %d,%d] ", jrp->etype, jrp->th_i, jrp->indiv_i);
4755*44704f69SBart Van Assche if (jrp->se_id > 0)
4756*44704f69SBart Van Assche pr2serr("se_id=%d ", jrp->se_id);
4757*44704f69SBart Van Assche pr2serr("ei_ioe,_eoe,_aess=%s", offset_str(k, hex, b, blen));
4758*44704f69SBart Van Assche pr2serr(",%s", offset_str(jrp->ei_eoe, hex, b, blen));
4759*44704f69SBart Van Assche pr2serr(",%s", offset_str(jrp->ei_aess, hex, b, blen));
4760*44704f69SBart Van Assche pr2serr(" dsn=%s", offset_str(jrp->dev_slot_num, hex, b, blen));
4761*44704f69SBart Van Assche if (op->do_join > 2) {
4762*44704f69SBart Van Assche pr2serr(" sa=0x");
4763*44704f69SBart Van Assche if (saddr_non_zero(jrp->sas_addr)) {
4764*44704f69SBart Van Assche for (j = 0; j < 8; ++j)
4765*44704f69SBart Van Assche pr2serr("%02x", jrp->sas_addr[j]);
4766*44704f69SBart Van Assche } else
4767*44704f69SBart Van Assche pr2serr("0");
4768*44704f69SBart Van Assche }
4769*44704f69SBart Van Assche if (jrp->enc_statp)
4770*44704f69SBart Van Assche pr2serr(" ES+%s", offset_str(jrp->enc_statp - enc_stat_rsp,
4771*44704f69SBart Van Assche hex, b, blen));
4772*44704f69SBart Van Assche if (jrp->elem_descp)
4773*44704f69SBart Van Assche pr2serr(" ED+%s", offset_str(jrp->elem_descp - elem_desc_rsp,
4774*44704f69SBart Van Assche hex, b, blen));
4775*44704f69SBart Van Assche if (jrp->ae_statp) {
4776*44704f69SBart Van Assche pr2serr(" AES+%s", offset_str(jrp->ae_statp - add_elem_rsp,
4777*44704f69SBart Van Assche hex, b, blen));
4778*44704f69SBart Van Assche if (jrp->ae_statp[0] & 0x10) {
4779*44704f69SBart Van Assche ++eip_count;
4780*44704f69SBart Van Assche if (jrp->ae_statp[2] & 0x3)
4781*44704f69SBart Van Assche ++eiioe_count;
4782*44704f69SBart Van Assche }
4783*44704f69SBart Van Assche }
4784*44704f69SBart Van Assche if (jrp->thresh_inp)
4785*44704f69SBart Van Assche pr2serr(" TI+%s", offset_str(jrp->thresh_inp - threshold_rsp,
4786*44704f69SBart Van Assche hex, b, blen));
4787*44704f69SBart Van Assche pr2serr("\n");
4788*44704f69SBart Van Assche }
4789*44704f69SBart Van Assche pr2serr(">> ES len=%s, ", offset_str(enc_stat_rsp_len, hex, b, blen));
4790*44704f69SBart Van Assche pr2serr("ED len=%s, ", offset_str(elem_desc_rsp_len, hex, b, blen));
4791*44704f69SBart Van Assche pr2serr("AES len=%s, ", offset_str(add_elem_rsp_len, hex, b, blen));
4792*44704f69SBart Van Assche pr2serr("TI len=%s\n", offset_str(threshold_rsp_len, hex, b, blen));
4793*44704f69SBart Van Assche pr2serr(">> join_arr elements=%s, ", offset_str(k, hex, b, blen));
4794*44704f69SBart Van Assche pr2serr("eip_count=%s, ", offset_str(eip_count, hex, b, blen));
4795*44704f69SBart Van Assche pr2serr("eiioe_count=%s ", offset_str(eiioe_count, hex, b, blen));
4796*44704f69SBart Van Assche pr2serr("broken_ei=%d\n", (int)broken_ei);
4797*44704f69SBart Van Assche }
4798*44704f69SBart Van Assche
4799*44704f69SBart Van Assche /* EIIOE juggling (standards + heuristics) for join with AES page */
4800*44704f69SBart Van Assche static void
join_juggle_aes(struct th_es_t * tesp,uint8_t * es_bp,const uint8_t * ed_bp,uint8_t * t_bp)4801*44704f69SBart Van Assche join_juggle_aes(struct th_es_t * tesp, uint8_t * es_bp, const uint8_t * ed_bp,
4802*44704f69SBart Van Assche uint8_t * t_bp)
4803*44704f69SBart Van Assche {
4804*44704f69SBart Van Assche int k, j, eoe, ei4aess;
4805*44704f69SBart Van Assche struct join_row_t * jrp;
4806*44704f69SBart Van Assche const struct type_desc_hdr_t * tdhp;
4807*44704f69SBart Van Assche
4808*44704f69SBart Van Assche jrp = tesp->j_base;
4809*44704f69SBart Van Assche tdhp = tesp->th_base;
4810*44704f69SBart Van Assche for (k = 0, eoe = 0, ei4aess = 0; k < tesp->num_ths; ++k, ++tdhp) {
4811*44704f69SBart Van Assche bool et_used_by_aes;
4812*44704f69SBart Van Assche
4813*44704f69SBart Van Assche jrp->th_i = k;
4814*44704f69SBart Van Assche jrp->indiv_i = -1;
4815*44704f69SBart Van Assche jrp->etype = tdhp->etype;
4816*44704f69SBart Van Assche jrp->ei_eoe = -1;
4817*44704f69SBart Van Assche et_used_by_aes = is_et_used_by_aes(tdhp->etype);
4818*44704f69SBart Van Assche jrp->ei_aess = -1;
4819*44704f69SBart Van Assche jrp->se_id = tdhp->se_id;
4820*44704f69SBart Van Assche /* check es_bp < es_last_bp still in range */
4821*44704f69SBart Van Assche jrp->enc_statp = es_bp;
4822*44704f69SBart Van Assche es_bp += 4;
4823*44704f69SBart Van Assche jrp->elem_descp = ed_bp;
4824*44704f69SBart Van Assche if (ed_bp)
4825*44704f69SBart Van Assche ed_bp += sg_get_unaligned_be16(ed_bp + 2) + 4;
4826*44704f69SBart Van Assche jrp->ae_statp = NULL;
4827*44704f69SBart Van Assche jrp->thresh_inp = t_bp;
4828*44704f69SBart Van Assche jrp->dev_slot_num = -1;
4829*44704f69SBart Van Assche /* assume sas_addr[8] zeroed since it's static file scope */
4830*44704f69SBart Van Assche if (t_bp)
4831*44704f69SBart Van Assche t_bp += 4;
4832*44704f69SBart Van Assche ++jrp;
4833*44704f69SBart Van Assche for (j = 0; j < tdhp->num_elements; ++j, ++jrp) {
4834*44704f69SBart Van Assche if (jrp >= join_arr_lastp)
4835*44704f69SBart Van Assche break;
4836*44704f69SBart Van Assche jrp->th_i = k;
4837*44704f69SBart Van Assche jrp->indiv_i = j;
4838*44704f69SBart Van Assche jrp->ei_eoe = eoe++;
4839*44704f69SBart Van Assche if (et_used_by_aes)
4840*44704f69SBart Van Assche jrp->ei_aess = ei4aess++;
4841*44704f69SBart Van Assche else
4842*44704f69SBart Van Assche jrp->ei_aess = -1;
4843*44704f69SBart Van Assche jrp->etype = tdhp->etype;
4844*44704f69SBart Van Assche jrp->se_id = tdhp->se_id;
4845*44704f69SBart Van Assche jrp->enc_statp = es_bp;
4846*44704f69SBart Van Assche es_bp += 4;
4847*44704f69SBart Van Assche jrp->elem_descp = ed_bp;
4848*44704f69SBart Van Assche if (ed_bp)
4849*44704f69SBart Van Assche ed_bp += sg_get_unaligned_be16(ed_bp + 2) + 4;
4850*44704f69SBart Van Assche jrp->thresh_inp = t_bp;
4851*44704f69SBart Van Assche jrp->dev_slot_num = -1;
4852*44704f69SBart Van Assche /* assume sas_addr[8] zeroed since it's static file scope */
4853*44704f69SBart Van Assche if (t_bp)
4854*44704f69SBart Van Assche t_bp += 4;
4855*44704f69SBart Van Assche jrp->ae_statp = NULL;
4856*44704f69SBart Van Assche ++tesp->num_j_eoe;
4857*44704f69SBart Van Assche }
4858*44704f69SBart Van Assche if (jrp >= join_arr_lastp) {
4859*44704f69SBart Van Assche /* ++k; */
4860*44704f69SBart Van Assche break; /* leave last row all zeros */
4861*44704f69SBart Van Assche }
4862*44704f69SBart Van Assche }
4863*44704f69SBart Van Assche tesp->num_j_rows = jrp - tesp->j_base;
4864*44704f69SBart Van Assche }
4865*44704f69SBart Van Assche
4866*44704f69SBart Van Assche /* Fetch Configuration, Enclosure Status, Element Descriptor, Additional
4867*44704f69SBart Van Assche * Element Status and optionally Threshold In pages, place in static arrays.
4868*44704f69SBart Van Assche * Collate (join) overall and individual elements into the static join_arr[].
4869*44704f69SBart Van Assche * When 'display' is true then the join_arr[] is output to stdout in a form
4870*44704f69SBart Van Assche * suitable for end users. For debug purposes the join_arr[] is output to
4871*44704f69SBart Van Assche * stderr when op->verbose > 3. Returns 0 for success, any other return value
4872*44704f69SBart Van Assche * is an error. */
4873*44704f69SBart Van Assche static int
join_work(struct sg_pt_base * ptvp,struct opts_t * op,bool display)4874*44704f69SBart Van Assche join_work(struct sg_pt_base * ptvp, struct opts_t * op, bool display)
4875*44704f69SBart Van Assche {
4876*44704f69SBart Van Assche bool broken_ei;
4877*44704f69SBart Van Assche int res, num_ths, mlen;
4878*44704f69SBart Van Assche uint32_t ref_gen_code, gen_code;
4879*44704f69SBart Van Assche const uint8_t * ae_bp;
4880*44704f69SBart Van Assche const uint8_t * ae_last_bp;
4881*44704f69SBart Van Assche const char * enc_state_changed = " <<state of enclosure changed, "
4882*44704f69SBart Van Assche "please try again>>\n";
4883*44704f69SBart Van Assche uint8_t * es_bp;
4884*44704f69SBart Van Assche const uint8_t * ed_bp;
4885*44704f69SBart Van Assche uint8_t * t_bp;
4886*44704f69SBart Van Assche struct th_es_t * tesp;
4887*44704f69SBart Van Assche struct enclosure_info primary_info;
4888*44704f69SBart Van Assche struct th_es_t tes;
4889*44704f69SBart Van Assche
4890*44704f69SBart Van Assche memset(&primary_info, 0, sizeof(primary_info));
4891*44704f69SBart Van Assche num_ths = build_type_desc_hdr_arr(ptvp, type_desc_hdr_arr, MX_ELEM_HDR,
4892*44704f69SBart Van Assche &ref_gen_code, &primary_info, op);
4893*44704f69SBart Van Assche if (num_ths < 0)
4894*44704f69SBart Van Assche return num_ths;
4895*44704f69SBart Van Assche tesp = &tes;
4896*44704f69SBart Van Assche memset(tesp, 0, sizeof(tes));
4897*44704f69SBart Van Assche tesp->th_base = type_desc_hdr_arr;
4898*44704f69SBart Van Assche tesp->num_ths = num_ths;
4899*44704f69SBart Van Assche if (display && primary_info.have_info) {
4900*44704f69SBart Van Assche int j;
4901*44704f69SBart Van Assche
4902*44704f69SBart Van Assche printf(" Primary enclosure logical identifier (hex): ");
4903*44704f69SBart Van Assche for (j = 0; j < 8; ++j)
4904*44704f69SBart Van Assche printf("%02x", primary_info.enc_log_id[j]);
4905*44704f69SBart Van Assche printf("\n");
4906*44704f69SBart Van Assche }
4907*44704f69SBart Van Assche mlen = enc_stat_rsp_sz;
4908*44704f69SBart Van Assche if (mlen > op->maxlen)
4909*44704f69SBart Van Assche mlen = op->maxlen;
4910*44704f69SBart Van Assche res = do_rec_diag(ptvp, ENC_STATUS_DPC, enc_stat_rsp, mlen, op,
4911*44704f69SBart Van Assche &enc_stat_rsp_len);
4912*44704f69SBart Van Assche if (res)
4913*44704f69SBart Van Assche return res;
4914*44704f69SBart Van Assche if (enc_stat_rsp_len < 8) {
4915*44704f69SBart Van Assche pr2serr("Enclosure Status response too short\n");
4916*44704f69SBart Van Assche return -1;
4917*44704f69SBart Van Assche }
4918*44704f69SBart Van Assche gen_code = sg_get_unaligned_be32(enc_stat_rsp + 4);
4919*44704f69SBart Van Assche if (ref_gen_code != gen_code) {
4920*44704f69SBart Van Assche pr2serr("%s", enc_state_changed);
4921*44704f69SBart Van Assche return -1;
4922*44704f69SBart Van Assche }
4923*44704f69SBart Van Assche es_bp = enc_stat_rsp + 8;
4924*44704f69SBart Van Assche /* es_last_bp = enc_stat_rsp + enc_stat_rsp_len - 1; */
4925*44704f69SBart Van Assche
4926*44704f69SBart Van Assche mlen = elem_desc_rsp_sz;
4927*44704f69SBart Van Assche if (mlen > op->maxlen)
4928*44704f69SBart Van Assche mlen = op->maxlen;
4929*44704f69SBart Van Assche res = do_rec_diag(ptvp, ELEM_DESC_DPC, elem_desc_rsp, mlen, op,
4930*44704f69SBart Van Assche &elem_desc_rsp_len);
4931*44704f69SBart Van Assche if (0 == res) {
4932*44704f69SBart Van Assche if (elem_desc_rsp_len < 8) {
4933*44704f69SBart Van Assche pr2serr("Element Descriptor response too short\n");
4934*44704f69SBart Van Assche return -1;
4935*44704f69SBart Van Assche }
4936*44704f69SBart Van Assche gen_code = sg_get_unaligned_be32(elem_desc_rsp + 4);
4937*44704f69SBart Van Assche if (ref_gen_code != gen_code) {
4938*44704f69SBart Van Assche pr2serr("%s", enc_state_changed);
4939*44704f69SBart Van Assche return -1;
4940*44704f69SBart Van Assche }
4941*44704f69SBart Van Assche ed_bp = elem_desc_rsp + 8;
4942*44704f69SBart Van Assche /* ed_last_bp = elem_desc_rsp + elem_desc_rsp_len - 1; */
4943*44704f69SBart Van Assche } else {
4944*44704f69SBart Van Assche elem_desc_rsp_len = 0;
4945*44704f69SBart Van Assche ed_bp = NULL;
4946*44704f69SBart Van Assche res = 0;
4947*44704f69SBart Van Assche if (op->verbose)
4948*44704f69SBart Van Assche pr2serr(" Element Descriptor page not available\n");
4949*44704f69SBart Van Assche }
4950*44704f69SBart Van Assche
4951*44704f69SBart Van Assche /* check if we want to add the AES page to the join */
4952*44704f69SBart Van Assche if (display || (ADD_ELEM_STATUS_DPC == op->page_code) ||
4953*44704f69SBart Van Assche (op->dev_slot_num >= 0) || saddr_non_zero(op->sas_addr)) {
4954*44704f69SBart Van Assche mlen = add_elem_rsp_sz;
4955*44704f69SBart Van Assche if (mlen > op->maxlen)
4956*44704f69SBart Van Assche mlen = op->maxlen;
4957*44704f69SBart Van Assche res = do_rec_diag(ptvp, ADD_ELEM_STATUS_DPC, add_elem_rsp, mlen, op,
4958*44704f69SBart Van Assche &add_elem_rsp_len);
4959*44704f69SBart Van Assche if (0 == res) {
4960*44704f69SBart Van Assche if (add_elem_rsp_len < 8) {
4961*44704f69SBart Van Assche pr2serr("Additional Element Status response too short\n");
4962*44704f69SBart Van Assche return -1;
4963*44704f69SBart Van Assche }
4964*44704f69SBart Van Assche gen_code = sg_get_unaligned_be32(add_elem_rsp + 4);
4965*44704f69SBart Van Assche if (ref_gen_code != gen_code) {
4966*44704f69SBart Van Assche pr2serr("%s", enc_state_changed);
4967*44704f69SBart Van Assche return -1;
4968*44704f69SBart Van Assche }
4969*44704f69SBart Van Assche ae_bp = add_elem_rsp + 8;
4970*44704f69SBart Van Assche ae_last_bp = add_elem_rsp + add_elem_rsp_len - 1;
4971*44704f69SBart Van Assche if (op->eiioe_auto && (add_elem_rsp_len > 11)) {
4972*44704f69SBart Van Assche /* heuristic: if first AES descriptor has EIP set and its
4973*44704f69SBart Van Assche * EI equal to 1, then act as if the EIIOE field is 1. */
4974*44704f69SBart Van Assche if ((ae_bp[0] & 0x10) && (1 == ae_bp[3]))
4975*44704f69SBart Van Assche op->eiioe_force = true;
4976*44704f69SBart Van Assche }
4977*44704f69SBart Van Assche } else { /* unable to read AES dpage */
4978*44704f69SBart Van Assche add_elem_rsp_len = 0;
4979*44704f69SBart Van Assche ae_bp = NULL;
4980*44704f69SBart Van Assche ae_last_bp = NULL;
4981*44704f69SBart Van Assche res = 0;
4982*44704f69SBart Van Assche if (op->verbose)
4983*44704f69SBart Van Assche pr2serr(" Additional Element Status page not available\n");
4984*44704f69SBart Van Assche }
4985*44704f69SBart Van Assche } else {
4986*44704f69SBart Van Assche ae_bp = NULL;
4987*44704f69SBart Van Assche ae_last_bp = NULL;
4988*44704f69SBart Van Assche }
4989*44704f69SBart Van Assche
4990*44704f69SBart Van Assche if ((op->do_join > 1) ||
4991*44704f69SBart Van Assche ((! display) && (THRESHOLD_DPC == op->page_code))) {
4992*44704f69SBart Van Assche mlen = threshold_rsp_sz;
4993*44704f69SBart Van Assche if (mlen > op->maxlen)
4994*44704f69SBart Van Assche mlen = op->maxlen;
4995*44704f69SBart Van Assche res = do_rec_diag(ptvp, THRESHOLD_DPC, threshold_rsp, mlen, op,
4996*44704f69SBart Van Assche &threshold_rsp_len);
4997*44704f69SBart Van Assche if (0 == res) {
4998*44704f69SBart Van Assche if (threshold_rsp_len < 8) {
4999*44704f69SBart Van Assche pr2serr("Threshold In response too short\n");
5000*44704f69SBart Van Assche return -1;
5001*44704f69SBart Van Assche }
5002*44704f69SBart Van Assche gen_code = sg_get_unaligned_be32(threshold_rsp + 4);
5003*44704f69SBart Van Assche if (ref_gen_code != gen_code) {
5004*44704f69SBart Van Assche pr2serr("%s", enc_state_changed);
5005*44704f69SBart Van Assche return -1;
5006*44704f69SBart Van Assche }
5007*44704f69SBart Van Assche t_bp = threshold_rsp + 8;
5008*44704f69SBart Van Assche /* t_last_bp = threshold_rsp + threshold_rsp_len - 1; */
5009*44704f69SBart Van Assche } else {
5010*44704f69SBart Van Assche threshold_rsp_len = 0;
5011*44704f69SBart Van Assche t_bp = NULL;
5012*44704f69SBart Van Assche res = 0;
5013*44704f69SBart Van Assche if (op->verbose)
5014*44704f69SBart Van Assche pr2serr(" Threshold In page not available\n");
5015*44704f69SBart Van Assche }
5016*44704f69SBart Van Assche } else {
5017*44704f69SBart Van Assche threshold_rsp_len = 0;
5018*44704f69SBart Van Assche t_bp = NULL;
5019*44704f69SBart Van Assche }
5020*44704f69SBart Van Assche
5021*44704f69SBart Van Assche
5022*44704f69SBart Van Assche tesp->j_base = join_arr;
5023*44704f69SBart Van Assche join_juggle_aes(tesp, es_bp, ed_bp, t_bp);
5024*44704f69SBart Van Assche
5025*44704f69SBart Van Assche broken_ei = false;
5026*44704f69SBart Van Assche if (ae_bp)
5027*44704f69SBart Van Assche broken_ei = join_aes_helper(ae_bp, ae_last_bp, tesp, op);
5028*44704f69SBart Van Assche
5029*44704f69SBart Van Assche if (op->verbose > 3)
5030*44704f69SBart Van Assche join_array_dump(tesp, broken_ei, op);
5031*44704f69SBart Van Assche
5032*44704f69SBart Van Assche join_done = true;
5033*44704f69SBart Van Assche if (display) /* probably wanted join_arr[] built only */
5034*44704f69SBart Van Assche join_array_display(tesp, op);
5035*44704f69SBart Van Assche
5036*44704f69SBart Van Assche return res;
5037*44704f69SBart Van Assche
5038*44704f69SBart Van Assche }
5039*44704f69SBart Van Assche
5040*44704f69SBart Van Assche /* Returns 1 if strings equal (same length, characters same or only differ
5041*44704f69SBart Van Assche * by case), else returns 0. Assumes 7 bit ASCII (English alphabet). */
5042*44704f69SBart Van Assche static int
strcase_eq(const char * s1p,const char * s2p)5043*44704f69SBart Van Assche strcase_eq(const char * s1p, const char * s2p)
5044*44704f69SBart Van Assche {
5045*44704f69SBart Van Assche int c1;
5046*44704f69SBart Van Assche
5047*44704f69SBart Van Assche do {
5048*44704f69SBart Van Assche int c2;
5049*44704f69SBart Van Assche
5050*44704f69SBart Van Assche c1 = *s1p++;
5051*44704f69SBart Van Assche c2 = *s2p++;
5052*44704f69SBart Van Assche if (c1 != c2) {
5053*44704f69SBart Van Assche if (c2 >= 'a')
5054*44704f69SBart Van Assche c2 = toupper(c2);
5055*44704f69SBart Van Assche else if (c1 >= 'a')
5056*44704f69SBart Van Assche c1 = toupper(c1);
5057*44704f69SBart Van Assche else
5058*44704f69SBart Van Assche return 0;
5059*44704f69SBart Van Assche if (c1 != c2)
5060*44704f69SBart Van Assche return 0;
5061*44704f69SBart Van Assche }
5062*44704f69SBart Van Assche } while (c1);
5063*44704f69SBart Van Assche return 1;
5064*44704f69SBart Van Assche }
5065*44704f69SBart Van Assche
5066*44704f69SBart Van Assche static bool
is_acronym_in_status_ctl(const struct tuple_acronym_val * tavp)5067*44704f69SBart Van Assche is_acronym_in_status_ctl(const struct tuple_acronym_val * tavp)
5068*44704f69SBart Van Assche {
5069*44704f69SBart Van Assche const struct acronym2tuple * ap;
5070*44704f69SBart Van Assche
5071*44704f69SBart Van Assche for (ap = ecs_a2t_arr; ap->acron; ++ ap) {
5072*44704f69SBart Van Assche if (strcase_eq(tavp->acron, ap->acron))
5073*44704f69SBart Van Assche break;
5074*44704f69SBart Van Assche }
5075*44704f69SBart Van Assche return ap->acron;
5076*44704f69SBart Van Assche }
5077*44704f69SBart Van Assche
5078*44704f69SBart Van Assche static bool
is_acronym_in_threshold(const struct tuple_acronym_val * tavp)5079*44704f69SBart Van Assche is_acronym_in_threshold(const struct tuple_acronym_val * tavp)
5080*44704f69SBart Van Assche {
5081*44704f69SBart Van Assche const struct acronym2tuple * ap;
5082*44704f69SBart Van Assche
5083*44704f69SBart Van Assche for (ap = th_a2t_arr; ap->acron; ++ ap) {
5084*44704f69SBart Van Assche if (strcase_eq(tavp->acron, ap->acron))
5085*44704f69SBart Van Assche break;
5086*44704f69SBart Van Assche }
5087*44704f69SBart Van Assche return ap->acron;
5088*44704f69SBart Van Assche }
5089*44704f69SBart Van Assche
5090*44704f69SBart Van Assche static bool
is_acronym_in_additional(const struct tuple_acronym_val * tavp)5091*44704f69SBart Van Assche is_acronym_in_additional(const struct tuple_acronym_val * tavp)
5092*44704f69SBart Van Assche {
5093*44704f69SBart Van Assche const struct acronym2tuple * ap;
5094*44704f69SBart Van Assche
5095*44704f69SBart Van Assche for (ap = ae_sas_a2t_arr; ap->acron; ++ ap) {
5096*44704f69SBart Van Assche if (strcase_eq(tavp->acron, ap->acron))
5097*44704f69SBart Van Assche break;
5098*44704f69SBart Van Assche }
5099*44704f69SBart Van Assche return ap->acron;
5100*44704f69SBart Van Assche }
5101*44704f69SBart Van Assche
5102*44704f69SBart Van Assche /* ENC_STATUS_DPC ENC_CONTROL_DPC
5103*44704f69SBart Van Assche * Do clear/get/set (cgs) on Enclosure Control/Status page. Return 0 for ok
5104*44704f69SBart Van Assche * -2 for acronym not found, else -1 . */
5105*44704f69SBart Van Assche static int
cgs_enc_ctl_stat(struct sg_pt_base * ptvp,struct join_row_t * jrp,const struct tuple_acronym_val * tavp,const struct opts_t * op,bool last)5106*44704f69SBart Van Assche cgs_enc_ctl_stat(struct sg_pt_base * ptvp, struct join_row_t * jrp,
5107*44704f69SBart Van Assche const struct tuple_acronym_val * tavp,
5108*44704f69SBart Van Assche const struct opts_t * op, bool last)
5109*44704f69SBart Van Assche {
5110*44704f69SBart Van Assche int s_byte, s_bit, n_bits;
5111*44704f69SBart Van Assche const struct acronym2tuple * ap;
5112*44704f69SBart Van Assche
5113*44704f69SBart Van Assche if (NULL == tavp->acron) {
5114*44704f69SBart Van Assche s_byte = tavp->start_byte;
5115*44704f69SBart Van Assche s_bit = tavp->start_bit;
5116*44704f69SBart Van Assche n_bits = tavp->num_bits;
5117*44704f69SBart Van Assche }
5118*44704f69SBart Van Assche if (tavp->acron) {
5119*44704f69SBart Van Assche for (ap = ecs_a2t_arr; ap->acron; ++ ap) {
5120*44704f69SBart Van Assche if (((jrp->etype == ap->etype) || (-1 == ap->etype)) &&
5121*44704f69SBart Van Assche strcase_eq(tavp->acron, ap->acron))
5122*44704f69SBart Van Assche break;
5123*44704f69SBart Van Assche }
5124*44704f69SBart Van Assche if (ap->acron) {
5125*44704f69SBart Van Assche s_byte = ap->start_byte;
5126*44704f69SBart Van Assche s_bit = ap->start_bit;
5127*44704f69SBart Van Assche n_bits = ap->num_bits;
5128*44704f69SBart Van Assche } else {
5129*44704f69SBart Van Assche if (-1 != ap->etype) {
5130*44704f69SBart Van Assche for (ap = ecs_a2t_arr; ap->acron; ++ap) {
5131*44704f69SBart Van Assche if (0 == strcase_eq(tavp->acron, ap->acron)) {
5132*44704f69SBart Van Assche pr2serr(">>> Found %s acronym but not for element "
5133*44704f69SBart Van Assche "type %d\n", tavp->acron, jrp->etype);
5134*44704f69SBart Van Assche break;
5135*44704f69SBart Van Assche }
5136*44704f69SBart Van Assche }
5137*44704f69SBart Van Assche }
5138*44704f69SBart Van Assche return -2;
5139*44704f69SBart Van Assche }
5140*44704f69SBart Van Assche }
5141*44704f69SBart Van Assche if (op->verbose > 1)
5142*44704f69SBart Van Assche pr2serr(" s_byte=%d, s_bit=%d, n_bits=%d\n", s_byte, s_bit, n_bits);
5143*44704f69SBart Van Assche if (GET_OPT == tavp->cgs_sel) {
5144*44704f69SBart Van Assche uint64_t ui = sg_get_big_endian(jrp->enc_statp + s_byte, s_bit,
5145*44704f69SBart Van Assche n_bits);
5146*44704f69SBart Van Assche
5147*44704f69SBart Van Assche if (op->do_hex)
5148*44704f69SBart Van Assche printf("0x%" PRIx64 "\n", ui);
5149*44704f69SBart Van Assche else
5150*44704f69SBart Van Assche printf("%" PRId64 "\n", (int64_t)ui);
5151*44704f69SBart Van Assche } else { /* --set or --clear */
5152*44704f69SBart Van Assche int len;
5153*44704f69SBart Van Assche
5154*44704f69SBart Van Assche if ((! op->mask_ign) && (jrp->etype < NUM_ETC)) {
5155*44704f69SBart Van Assche int k;
5156*44704f69SBart Van Assche
5157*44704f69SBart Van Assche if (op->verbose > 2)
5158*44704f69SBart Van Assche pr2serr("Applying mask to element status [etc=%d] prior to "
5159*44704f69SBart Van Assche "modify then write\n", jrp->etype);
5160*44704f69SBart Van Assche for (k = 0; k < 4; ++k)
5161*44704f69SBart Van Assche jrp->enc_statp[k] &= ses3_element_cmask_arr[jrp->etype][k];
5162*44704f69SBart Van Assche } else
5163*44704f69SBart Van Assche jrp->enc_statp[0] &= 0x40; /* keep PRDFAIL is set in byte 0 */
5164*44704f69SBart Van Assche /* next we modify requested bit(s) */
5165*44704f69SBart Van Assche sg_set_big_endian((uint64_t)tavp->val,
5166*44704f69SBart Van Assche jrp->enc_statp + s_byte, s_bit, n_bits);
5167*44704f69SBart Van Assche jrp->enc_statp[0] |= 0x80; /* set SELECT bit */
5168*44704f69SBart Van Assche if (op->byte1_given)
5169*44704f69SBart Van Assche enc_stat_rsp[1] = op->byte1;
5170*44704f69SBart Van Assche len = sg_get_unaligned_be16(enc_stat_rsp + 2) + 4;
5171*44704f69SBart Van Assche if (last) {
5172*44704f69SBart Van Assche int ret = do_senddiag(ptvp, enc_stat_rsp, len, ! op->quiet,
5173*44704f69SBart Van Assche op->verbose);
5174*44704f69SBart Van Assche
5175*44704f69SBart Van Assche if (ret) {
5176*44704f69SBart Van Assche pr2serr("couldn't send Enclosure Control page\n");
5177*44704f69SBart Van Assche return -1;
5178*44704f69SBart Van Assche }
5179*44704f69SBart Van Assche }
5180*44704f69SBart Van Assche }
5181*44704f69SBart Van Assche return 0;
5182*44704f69SBart Van Assche }
5183*44704f69SBart Van Assche
5184*44704f69SBart Van Assche /* THRESHOLD_DPC
5185*44704f69SBart Van Assche * Do clear/get/set (cgs) on Threshold In/Out page. Return 0 for ok,
5186*44704f69SBart Van Assche * -2 for acronym not found, else -1 . */
5187*44704f69SBart Van Assche static int
cgs_threshold(struct sg_pt_base * ptvp,const struct join_row_t * jrp,const struct tuple_acronym_val * tavp,const struct opts_t * op,bool last)5188*44704f69SBart Van Assche cgs_threshold(struct sg_pt_base * ptvp, const struct join_row_t * jrp,
5189*44704f69SBart Van Assche const struct tuple_acronym_val * tavp,
5190*44704f69SBart Van Assche const struct opts_t * op, bool last)
5191*44704f69SBart Van Assche {
5192*44704f69SBart Van Assche int s_byte, s_bit, n_bits;
5193*44704f69SBart Van Assche const struct acronym2tuple * ap;
5194*44704f69SBart Van Assche
5195*44704f69SBart Van Assche if (NULL == jrp->thresh_inp) {
5196*44704f69SBart Van Assche pr2serr("No Threshold In/Out element available\n");
5197*44704f69SBart Van Assche return -1;
5198*44704f69SBart Van Assche }
5199*44704f69SBart Van Assche if (NULL == tavp->acron) {
5200*44704f69SBart Van Assche s_byte = tavp->start_byte;
5201*44704f69SBart Van Assche s_bit = tavp->start_bit;
5202*44704f69SBart Van Assche n_bits = tavp->num_bits;
5203*44704f69SBart Van Assche }
5204*44704f69SBart Van Assche if (tavp->acron) {
5205*44704f69SBart Van Assche for (ap = th_a2t_arr; ap->acron; ++ap) {
5206*44704f69SBart Van Assche if (((jrp->etype == ap->etype) || (-1 == ap->etype)) &&
5207*44704f69SBart Van Assche strcase_eq(tavp->acron, ap->acron))
5208*44704f69SBart Van Assche break;
5209*44704f69SBart Van Assche }
5210*44704f69SBart Van Assche if (ap->acron) {
5211*44704f69SBart Van Assche s_byte = ap->start_byte;
5212*44704f69SBart Van Assche s_bit = ap->start_bit;
5213*44704f69SBart Van Assche n_bits = ap->num_bits;
5214*44704f69SBart Van Assche } else
5215*44704f69SBart Van Assche return -2;
5216*44704f69SBart Van Assche }
5217*44704f69SBart Van Assche if (GET_OPT == tavp->cgs_sel) {
5218*44704f69SBart Van Assche uint64_t ui = sg_get_big_endian(jrp->thresh_inp + s_byte, s_bit,
5219*44704f69SBart Van Assche n_bits);
5220*44704f69SBart Van Assche
5221*44704f69SBart Van Assche if (op->do_hex)
5222*44704f69SBart Van Assche printf("0x%" PRIx64 "\n", ui);
5223*44704f69SBart Van Assche else
5224*44704f69SBart Van Assche printf("%" PRId64 "\n", (int64_t)ui);
5225*44704f69SBart Van Assche } else {
5226*44704f69SBart Van Assche int len;
5227*44704f69SBart Van Assche
5228*44704f69SBart Van Assche sg_set_big_endian((uint64_t)tavp->val,
5229*44704f69SBart Van Assche jrp->thresh_inp + s_byte, s_bit, n_bits);
5230*44704f69SBart Van Assche if (op->byte1_given)
5231*44704f69SBart Van Assche threshold_rsp[1] = op->byte1;
5232*44704f69SBart Van Assche len = sg_get_unaligned_be16(threshold_rsp + 2) + 4;
5233*44704f69SBart Van Assche if (last) {
5234*44704f69SBart Van Assche int ret = do_senddiag(ptvp, threshold_rsp, len, ! op->quiet,
5235*44704f69SBart Van Assche op->verbose);
5236*44704f69SBart Van Assche
5237*44704f69SBart Van Assche if (ret) {
5238*44704f69SBart Van Assche pr2serr("couldn't send Threshold Out page\n");
5239*44704f69SBart Van Assche return -1;
5240*44704f69SBart Van Assche }
5241*44704f69SBart Van Assche }
5242*44704f69SBart Van Assche }
5243*44704f69SBart Van Assche return 0;
5244*44704f69SBart Van Assche }
5245*44704f69SBart Van Assche
5246*44704f69SBart Van Assche /* ADD_ELEM_STATUS_DPC
5247*44704f69SBart Van Assche * Do get (cgs) on Additional element status page. Return 0 for ok,
5248*44704f69SBart Van Assche * -2 for acronym not found, else -1 . */
5249*44704f69SBart Van Assche static int
cgs_additional_el(const struct join_row_t * jrp,const struct tuple_acronym_val * tavp,const struct opts_t * op)5250*44704f69SBart Van Assche cgs_additional_el(const struct join_row_t * jrp,
5251*44704f69SBart Van Assche const struct tuple_acronym_val * tavp,
5252*44704f69SBart Van Assche const struct opts_t * op)
5253*44704f69SBart Van Assche {
5254*44704f69SBart Van Assche int s_byte, s_bit, n_bits;
5255*44704f69SBart Van Assche const struct acronym2tuple * ap;
5256*44704f69SBart Van Assche
5257*44704f69SBart Van Assche if (NULL == jrp->ae_statp) {
5258*44704f69SBart Van Assche pr2serr("No additional element status element available\n");
5259*44704f69SBart Van Assche return -1;
5260*44704f69SBart Van Assche }
5261*44704f69SBart Van Assche if (NULL == tavp->acron) {
5262*44704f69SBart Van Assche s_byte = tavp->start_byte;
5263*44704f69SBart Van Assche s_bit = tavp->start_bit;
5264*44704f69SBart Van Assche n_bits = tavp->num_bits;
5265*44704f69SBart Van Assche }
5266*44704f69SBart Van Assche if (tavp->acron) {
5267*44704f69SBart Van Assche for (ap = ae_sas_a2t_arr; ap->acron; ++ap) {
5268*44704f69SBart Van Assche if (((jrp->etype == ap->etype) || (-1 == ap->etype)) &&
5269*44704f69SBart Van Assche strcase_eq(tavp->acron, ap->acron))
5270*44704f69SBart Van Assche break;
5271*44704f69SBart Van Assche }
5272*44704f69SBart Van Assche if (ap->acron) {
5273*44704f69SBart Van Assche s_byte = ap->start_byte;
5274*44704f69SBart Van Assche s_bit = ap->start_bit;
5275*44704f69SBart Van Assche n_bits = ap->num_bits;
5276*44704f69SBart Van Assche } else
5277*44704f69SBart Van Assche return -2;
5278*44704f69SBart Van Assche }
5279*44704f69SBart Van Assche if (GET_OPT == tavp->cgs_sel) {
5280*44704f69SBart Van Assche uint64_t ui = sg_get_big_endian(jrp->ae_statp + s_byte, s_bit,
5281*44704f69SBart Van Assche n_bits);
5282*44704f69SBart Van Assche
5283*44704f69SBart Van Assche if (op->do_hex)
5284*44704f69SBart Van Assche printf("0x%" PRIx64 "\n", ui);
5285*44704f69SBart Van Assche else
5286*44704f69SBart Van Assche printf("%" PRId64 "\n", (int64_t)ui);
5287*44704f69SBart Van Assche } else {
5288*44704f69SBart Van Assche pr2serr("--clear and --set not available for Additional Element "
5289*44704f69SBart Van Assche "Status page\n");
5290*44704f69SBart Van Assche return -1;
5291*44704f69SBart Van Assche }
5292*44704f69SBart Van Assche return 0;
5293*44704f69SBart Van Assche }
5294*44704f69SBart Van Assche
5295*44704f69SBart Van Assche /* Do --clear, --get or --set .
5296*44704f69SBart Van Assche * Returns 0 for success, any other return value is an error. */
5297*44704f69SBart Van Assche static int
ses_cgs(struct sg_pt_base * ptvp,const struct tuple_acronym_val * tavp,struct opts_t * op,bool last)5298*44704f69SBart Van Assche ses_cgs(struct sg_pt_base * ptvp, const struct tuple_acronym_val * tavp,
5299*44704f69SBart Van Assche struct opts_t * op, bool last)
5300*44704f69SBart Van Assche {
5301*44704f69SBart Van Assche int ret, k, j, desc_len, dn_len;
5302*44704f69SBart Van Assche bool found;
5303*44704f69SBart Van Assche struct join_row_t * jrp;
5304*44704f69SBart Van Assche const uint8_t * ed_bp;
5305*44704f69SBart Van Assche char b[64];
5306*44704f69SBart Van Assche
5307*44704f69SBart Van Assche if ((NULL == ptvp) && (GET_OPT != tavp->cgs_sel)) {
5308*44704f69SBart Van Assche pr2serr("%s: --clear= and --set= only supported when DEVICE is "
5309*44704f69SBart Van Assche "given\n", __func__);
5310*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
5311*44704f69SBart Van Assche }
5312*44704f69SBart Van Assche found = false;
5313*44704f69SBart Van Assche if (NULL == tavp->acron) {
5314*44704f69SBart Van Assche if (! op->page_code_given)
5315*44704f69SBart Van Assche op->page_code = ENC_CONTROL_DPC;
5316*44704f69SBart Van Assche found = true;
5317*44704f69SBart Van Assche } else if (is_acronym_in_status_ctl(tavp)) {
5318*44704f69SBart Van Assche if (op->page_code > 0) {
5319*44704f69SBart Van Assche if (ENC_CONTROL_DPC != op->page_code)
5320*44704f69SBart Van Assche goto inconsistent;
5321*44704f69SBart Van Assche } else
5322*44704f69SBart Van Assche op->page_code = ENC_CONTROL_DPC;
5323*44704f69SBart Van Assche found = true;
5324*44704f69SBart Van Assche } else if (is_acronym_in_threshold(tavp)) {
5325*44704f69SBart Van Assche if (op->page_code > 0) {
5326*44704f69SBart Van Assche if (THRESHOLD_DPC != op->page_code)
5327*44704f69SBart Van Assche goto inconsistent;
5328*44704f69SBart Van Assche } else
5329*44704f69SBart Van Assche op->page_code = THRESHOLD_DPC;
5330*44704f69SBart Van Assche found = true;
5331*44704f69SBart Van Assche } else if (is_acronym_in_additional(tavp)) {
5332*44704f69SBart Van Assche if (op->page_code > 0) {
5333*44704f69SBart Van Assche if (ADD_ELEM_STATUS_DPC != op->page_code)
5334*44704f69SBart Van Assche goto inconsistent;
5335*44704f69SBart Van Assche } else
5336*44704f69SBart Van Assche op->page_code = ADD_ELEM_STATUS_DPC;
5337*44704f69SBart Van Assche found = true;
5338*44704f69SBart Van Assche }
5339*44704f69SBart Van Assche if (! found) {
5340*44704f69SBart Van Assche pr2serr("acroynm %s not found (try '-ee' option)\n", tavp->acron);
5341*44704f69SBart Van Assche return -1;
5342*44704f69SBart Van Assche }
5343*44704f69SBart Van Assche if (false == join_done) {
5344*44704f69SBart Van Assche ret = join_work(ptvp, op, false);
5345*44704f69SBart Van Assche if (ret)
5346*44704f69SBart Van Assche return ret;
5347*44704f69SBart Van Assche }
5348*44704f69SBart Van Assche dn_len = op->desc_name ? (int)strlen(op->desc_name) : 0;
5349*44704f69SBart Van Assche for (k = 0, jrp = join_arr; ((k < MX_JOIN_ROWS) && jrp->enc_statp);
5350*44704f69SBart Van Assche ++k, ++jrp) {
5351*44704f69SBart Van Assche if (op->ind_given) {
5352*44704f69SBart Van Assche if (op->ind_th != jrp->th_i)
5353*44704f69SBart Van Assche continue;
5354*44704f69SBart Van Assche if (! match_ind_indiv(jrp->indiv_i, op))
5355*44704f69SBart Van Assche continue;
5356*44704f69SBart Van Assche } else if (op->desc_name) {
5357*44704f69SBart Van Assche ed_bp = jrp->elem_descp;
5358*44704f69SBart Van Assche if (NULL == ed_bp)
5359*44704f69SBart Van Assche continue;
5360*44704f69SBart Van Assche desc_len = sg_get_unaligned_be16(ed_bp + 2);
5361*44704f69SBart Van Assche /* some element descriptor strings have trailing NULLs and
5362*44704f69SBart Van Assche * count them; adjust */
5363*44704f69SBart Van Assche while (desc_len && ('\0' == ed_bp[4 + desc_len - 1]))
5364*44704f69SBart Van Assche --desc_len;
5365*44704f69SBart Van Assche if (desc_len != dn_len)
5366*44704f69SBart Van Assche continue;
5367*44704f69SBart Van Assche if (0 != strncmp(op->desc_name, (const char *)(ed_bp + 4),
5368*44704f69SBart Van Assche desc_len))
5369*44704f69SBart Van Assche continue;
5370*44704f69SBart Van Assche } else if (op->dev_slot_num >= 0) {
5371*44704f69SBart Van Assche if (op->dev_slot_num != jrp->dev_slot_num)
5372*44704f69SBart Van Assche continue;
5373*44704f69SBart Van Assche } else if (saddr_non_zero(op->sas_addr)) {
5374*44704f69SBart Van Assche for (j = 0; j < 8; ++j) {
5375*44704f69SBart Van Assche if (op->sas_addr[j] != jrp->sas_addr[j])
5376*44704f69SBart Van Assche break;
5377*44704f69SBart Van Assche }
5378*44704f69SBart Van Assche if (j < 8)
5379*44704f69SBart Van Assche continue;
5380*44704f69SBart Van Assche }
5381*44704f69SBart Van Assche if (ENC_CONTROL_DPC == op->page_code)
5382*44704f69SBart Van Assche ret = cgs_enc_ctl_stat(ptvp, jrp, tavp, op, last);
5383*44704f69SBart Van Assche else if (THRESHOLD_DPC == op->page_code)
5384*44704f69SBart Van Assche ret = cgs_threshold(ptvp, jrp, tavp, op, last);
5385*44704f69SBart Van Assche else if (ADD_ELEM_STATUS_DPC == op->page_code)
5386*44704f69SBart Van Assche ret = cgs_additional_el(jrp, tavp, op);
5387*44704f69SBart Van Assche else {
5388*44704f69SBart Van Assche pr2serr("page %s not supported for cgs\n",
5389*44704f69SBart Van Assche etype_str(op->page_code, b, sizeof(b)));
5390*44704f69SBart Van Assche ret = -1;
5391*44704f69SBart Van Assche }
5392*44704f69SBart Van Assche if (ret)
5393*44704f69SBart Van Assche return ret;
5394*44704f69SBart Van Assche if (op->ind_indiv_last <= op->ind_indiv)
5395*44704f69SBart Van Assche break;
5396*44704f69SBart Van Assche } /* end of loop over join array */
5397*44704f69SBart Van Assche if ((k >= MX_JOIN_ROWS || (NULL == jrp->enc_statp))) {
5398*44704f69SBart Van Assche if (op->desc_name)
5399*44704f69SBart Van Assche pr2serr("descriptor name: %s not found (check the 'ed' page "
5400*44704f69SBart Van Assche "[0x7])\n", op->desc_name);
5401*44704f69SBart Van Assche else if (op->dev_slot_num >= 0)
5402*44704f69SBart Van Assche pr2serr("device slot number: %d not found\n", op->dev_slot_num);
5403*44704f69SBart Van Assche else if (saddr_non_zero(op->sas_addr))
5404*44704f69SBart Van Assche pr2serr("SAS address not found\n");
5405*44704f69SBart Van Assche else {
5406*44704f69SBart Van Assche pr2serr("index: %d,%d", op->ind_th, op->ind_indiv);
5407*44704f69SBart Van Assche if (op->ind_indiv_last > op->ind_indiv)
5408*44704f69SBart Van Assche printf("-%d not found\n", op->ind_indiv_last);
5409*44704f69SBart Van Assche else
5410*44704f69SBart Van Assche printf(" not found\n");
5411*44704f69SBart Van Assche }
5412*44704f69SBart Van Assche return -1;
5413*44704f69SBart Van Assche }
5414*44704f69SBart Van Assche return 0;
5415*44704f69SBart Van Assche
5416*44704f69SBart Van Assche inconsistent:
5417*44704f69SBart Van Assche pr2serr("acroynm %s inconsistent with page_code=0x%x\n", tavp->acron,
5418*44704f69SBart Van Assche op->page_code);
5419*44704f69SBart Van Assche return -1;
5420*44704f69SBart Van Assche }
5421*44704f69SBart Van Assche
5422*44704f69SBart Van Assche /* Called when '--nickname=SEN' given. First calls status page to fetch
5423*44704f69SBart Van Assche * the generation code. Returns 0 for success, any other return value is
5424*44704f69SBart Van Assche * an error. */
5425*44704f69SBart Van Assche static int
ses_set_nickname(struct sg_pt_base * ptvp,struct opts_t * op)5426*44704f69SBart Van Assche ses_set_nickname(struct sg_pt_base * ptvp, struct opts_t * op)
5427*44704f69SBart Van Assche {
5428*44704f69SBart Van Assche int res, len;
5429*44704f69SBart Van Assche int resp_len = 0;
5430*44704f69SBart Van Assche uint8_t b[64];
5431*44704f69SBart Van Assche const int control_plen = 0x24;
5432*44704f69SBart Van Assche
5433*44704f69SBart Van Assche if (NULL == ptvp) {
5434*44704f69SBart Van Assche pr2serr("%s: ignored when no device name\n", __func__);
5435*44704f69SBart Van Assche return 0;
5436*44704f69SBart Van Assche }
5437*44704f69SBart Van Assche memset(b, 0, sizeof(b));
5438*44704f69SBart Van Assche /* Only after the generation code, offset 4 for 4 bytes */
5439*44704f69SBart Van Assche res = do_rec_diag(ptvp, SUBENC_NICKNAME_DPC, b, 8, op, &resp_len);
5440*44704f69SBart Van Assche if (res) {
5441*44704f69SBart Van Assche pr2serr("%s: Subenclosure nickname status page, res=%d\n", __func__,
5442*44704f69SBart Van Assche res);
5443*44704f69SBart Van Assche return -1;
5444*44704f69SBart Van Assche }
5445*44704f69SBart Van Assche if (resp_len < 8) {
5446*44704f69SBart Van Assche pr2serr("%s: Subenclosure nickname status page, response length too "
5447*44704f69SBart Van Assche "short: %d\n", __func__, resp_len);
5448*44704f69SBart Van Assche return -1;
5449*44704f69SBart Van Assche }
5450*44704f69SBart Van Assche if (op->verbose) {
5451*44704f69SBart Van Assche uint32_t gc;
5452*44704f69SBart Van Assche
5453*44704f69SBart Van Assche gc = sg_get_unaligned_be32(b + 4);
5454*44704f69SBart Van Assche pr2serr("%s: generation code from status page: %" PRIu32 "\n",
5455*44704f69SBart Van Assche __func__, gc);
5456*44704f69SBart Van Assche }
5457*44704f69SBart Van Assche b[0] = (uint8_t)SUBENC_NICKNAME_DPC; /* just in case */
5458*44704f69SBart Van Assche b[1] = (uint8_t)op->seid;
5459*44704f69SBart Van Assche sg_put_unaligned_be16((uint16_t)control_plen, b + 2);
5460*44704f69SBart Van Assche len = strlen(op->nickname_str);
5461*44704f69SBart Van Assche if (len > 32)
5462*44704f69SBart Van Assche len = 32;
5463*44704f69SBart Van Assche memcpy(b + 8, op->nickname_str, len);
5464*44704f69SBart Van Assche return do_senddiag(ptvp, b, control_plen + 4, ! op->quiet,
5465*44704f69SBart Van Assche op->verbose);
5466*44704f69SBart Van Assche }
5467*44704f69SBart Van Assche
5468*44704f69SBart Van Assche static void
enumerate_diag_pages(void)5469*44704f69SBart Van Assche enumerate_diag_pages(void)
5470*44704f69SBart Van Assche {
5471*44704f69SBart Van Assche bool got1;
5472*44704f69SBart Van Assche const struct diag_page_code * pcdp;
5473*44704f69SBart Van Assche const struct diag_page_abbrev * ap;
5474*44704f69SBart Van Assche
5475*44704f69SBart Van Assche printf("Diagnostic pages, followed by abbreviation(s) then page code:\n");
5476*44704f69SBart Van Assche for (pcdp = dpc_arr; pcdp->desc; ++pcdp) {
5477*44704f69SBart Van Assche printf(" %s [", pcdp->desc);
5478*44704f69SBart Van Assche for (ap = dp_abbrev, got1 = false; ap->abbrev; ++ap) {
5479*44704f69SBart Van Assche if (ap->page_code == pcdp->page_code) {
5480*44704f69SBart Van Assche printf("%s%s", (got1 ? "," : ""), ap->abbrev);
5481*44704f69SBart Van Assche got1 = true;
5482*44704f69SBart Van Assche }
5483*44704f69SBart Van Assche }
5484*44704f69SBart Van Assche printf("] [0x%x]\n", pcdp->page_code);
5485*44704f69SBart Van Assche }
5486*44704f69SBart Van Assche }
5487*44704f69SBart Van Assche
5488*44704f69SBart Van Assche /* Output from --enumerate or --list option. Note that the output is
5489*44704f69SBart Van Assche * different when the option is given twice. */
5490*44704f69SBart Van Assche static void
enumerate_work(const struct opts_t * op)5491*44704f69SBart Van Assche enumerate_work(const struct opts_t * op)
5492*44704f69SBart Van Assche {
5493*44704f69SBart Van Assche int num;
5494*44704f69SBart Van Assche
5495*44704f69SBart Van Assche if (op->dev_name)
5496*44704f69SBart Van Assche printf(">>> DEVICE %s ignored when --%s option given.\n",
5497*44704f69SBart Van Assche op->dev_name, (op->do_list ? "list" : "enumerate"));
5498*44704f69SBart Van Assche num = op->enumerate + (int)op->do_list;
5499*44704f69SBart Van Assche if (num < 2) {
5500*44704f69SBart Van Assche const struct element_type_t * etp;
5501*44704f69SBart Van Assche
5502*44704f69SBart Van Assche enumerate_diag_pages();
5503*44704f69SBart Van Assche printf("\nSES element type names, followed by abbreviation and "
5504*44704f69SBart Van Assche "element type code:\n");
5505*44704f69SBart Van Assche for (etp = element_type_arr; etp->desc; ++etp)
5506*44704f69SBart Van Assche printf(" %s [%s] [0x%x]\n", etp->desc, etp->abbrev,
5507*44704f69SBart Van Assche etp->elem_type_code);
5508*44704f69SBart Van Assche } else {
5509*44704f69SBart Van Assche bool given_et = false;
5510*44704f69SBart Van Assche const struct acronym2tuple * ap;
5511*44704f69SBart Van Assche const char * cp;
5512*44704f69SBart Van Assche char a[160];
5513*44704f69SBart Van Assche char b[64];
5514*44704f69SBart Van Assche char bb[64];
5515*44704f69SBart Van Assche
5516*44704f69SBart Van Assche /* command line has multiple --enumerate and/or --list options */
5517*44704f69SBart Van Assche printf("--clear, --get, --set acronyms for Enclosure Status/Control "
5518*44704f69SBart Van Assche "['es' or 'ec'] page");
5519*44704f69SBart Van Assche if (op->ind_given && op->ind_etp &&
5520*44704f69SBart Van Assche (cp = etype_str(op->ind_etp->elem_type_code, bb, sizeof(bb)))) {
5521*44704f69SBart Van Assche printf("\n(element type: %s)", cp);
5522*44704f69SBart Van Assche given_et = true;
5523*44704f69SBart Van Assche }
5524*44704f69SBart Van Assche printf(":\n");
5525*44704f69SBart Van Assche for (ap = ecs_a2t_arr; ap->acron; ++ap) {
5526*44704f69SBart Van Assche if (given_et && (op->ind_etp->elem_type_code != ap->etype))
5527*44704f69SBart Van Assche continue;
5528*44704f69SBart Van Assche cp = (ap->etype < 0) ? "*" : etype_str(ap->etype, b, sizeof(b));
5529*44704f69SBart Van Assche snprintf(a, sizeof(a), " %s [%s] [%d:%d:%d]", ap->acron,
5530*44704f69SBart Van Assche (cp ? cp : "??"), ap->start_byte, ap->start_bit,
5531*44704f69SBart Van Assche ap->num_bits);
5532*44704f69SBart Van Assche if (ap->info)
5533*44704f69SBart Van Assche printf("%-44s %s\n", a, ap->info);
5534*44704f69SBart Van Assche else
5535*44704f69SBart Van Assche printf("%s\n", a);
5536*44704f69SBart Van Assche }
5537*44704f69SBart Van Assche if (given_et)
5538*44704f69SBart Van Assche return;
5539*44704f69SBart Van Assche printf("\n--clear, --get, --set acronyms for Threshold In/Out "
5540*44704f69SBart Van Assche "['th'] page:\n");
5541*44704f69SBart Van Assche for (ap = th_a2t_arr; ap->acron; ++ap) {
5542*44704f69SBart Van Assche cp = (ap->etype < 0) ? "*" : etype_str(ap->etype, b, sizeof(b));
5543*44704f69SBart Van Assche snprintf(a, sizeof(a), " %s [%s] [%d:%d:%d]", ap->acron,
5544*44704f69SBart Van Assche (cp ? cp : "??"), ap->start_byte, ap->start_bit,
5545*44704f69SBart Van Assche ap->num_bits);
5546*44704f69SBart Van Assche if (ap->info)
5547*44704f69SBart Van Assche printf("%-34s %s\n", a, ap->info);
5548*44704f69SBart Van Assche else
5549*44704f69SBart Van Assche printf("%s\n", a);
5550*44704f69SBart Van Assche }
5551*44704f69SBart Van Assche printf("\n--get acronyms for Additional Element Status ['aes'] page "
5552*44704f69SBart Van Assche "(SAS EIP=1):\n");
5553*44704f69SBart Van Assche for (ap = ae_sas_a2t_arr; ap->acron; ++ap) {
5554*44704f69SBart Van Assche cp = (ap->etype < 0) ? "*" : etype_str(ap->etype, b, sizeof(b));
5555*44704f69SBart Van Assche snprintf(a, sizeof(a), " %s [%s] [%d:%d:%d]", ap->acron,
5556*44704f69SBart Van Assche (cp ? cp : "??"), ap->start_byte, ap->start_bit,
5557*44704f69SBart Van Assche ap->num_bits);
5558*44704f69SBart Van Assche if (ap->info)
5559*44704f69SBart Van Assche printf("%-34s %s\n", a, ap->info);
5560*44704f69SBart Van Assche else
5561*44704f69SBart Van Assche printf("%s\n", a);
5562*44704f69SBart Van Assche }
5563*44704f69SBart Van Assche }
5564*44704f69SBart Van Assche }
5565*44704f69SBart Van Assche
5566*44704f69SBart Van Assche
5567*44704f69SBart Van Assche int
main(int argc,char * argv[])5568*44704f69SBart Van Assche main(int argc, char * argv[])
5569*44704f69SBart Van Assche {
5570*44704f69SBart Van Assche bool have_cgs = false;
5571*44704f69SBart Van Assche int k, n, d_len, res, resid, vb;
5572*44704f69SBart Van Assche int sg_fd = -1;
5573*44704f69SBart Van Assche int pd_type = 0;
5574*44704f69SBart Van Assche int ret = 0;
5575*44704f69SBart Van Assche const char * cp;
5576*44704f69SBart Van Assche struct opts_t opts;
5577*44704f69SBart Van Assche struct opts_t * op;
5578*44704f69SBart Van Assche struct tuple_acronym_val * tavp;
5579*44704f69SBart Van Assche struct cgs_cl_t * cgs_clp;
5580*44704f69SBart Van Assche uint8_t * free_enc_stat_rsp = NULL;
5581*44704f69SBart Van Assche uint8_t * free_elem_desc_rsp = NULL;
5582*44704f69SBart Van Assche uint8_t * free_add_elem_rsp = NULL;
5583*44704f69SBart Van Assche uint8_t * free_threshold_rsp = NULL;
5584*44704f69SBart Van Assche struct sg_pt_base * ptvp = NULL;
5585*44704f69SBart Van Assche struct tuple_acronym_val tav_arr[CGS_CL_ARR_MAX_SZ];
5586*44704f69SBart Van Assche char buff[128];
5587*44704f69SBart Van Assche char b[128];
5588*44704f69SBart Van Assche
5589*44704f69SBart Van Assche op = &opts;
5590*44704f69SBart Van Assche memset(op, 0, sizeof(*op));
5591*44704f69SBart Van Assche op->dev_slot_num = -1;
5592*44704f69SBart Van Assche op->ind_indiv_last = -1;
5593*44704f69SBart Van Assche op->maxlen = MX_ALLOC_LEN;
5594*44704f69SBart Van Assche res = parse_cmd_line(op, argc, argv);
5595*44704f69SBart Van Assche vb = op->verbose;
5596*44704f69SBart Van Assche if (res) {
5597*44704f69SBart Van Assche ret = SG_LIB_SYNTAX_ERROR;
5598*44704f69SBart Van Assche goto early_out;
5599*44704f69SBart Van Assche }
5600*44704f69SBart Van Assche if (op->do_help) {
5601*44704f69SBart Van Assche usage(op->do_help);
5602*44704f69SBart Van Assche goto early_out;
5603*44704f69SBart Van Assche }
5604*44704f69SBart Van Assche #ifdef DEBUG
5605*44704f69SBart Van Assche pr2serr("In DEBUG mode, ");
5606*44704f69SBart Van Assche if (op->verbose_given && op->version_given) {
5607*44704f69SBart Van Assche pr2serr("but override: '-vV' given, zero verbose and continue\n");
5608*44704f69SBart Van Assche op->verbose_given = false;
5609*44704f69SBart Van Assche op->version_given = false;
5610*44704f69SBart Van Assche op->verbose = 0;
5611*44704f69SBart Van Assche } else if (! op->verbose_given) {
5612*44704f69SBart Van Assche pr2serr("set '-vv'\n");
5613*44704f69SBart Van Assche op->verbose = 2;
5614*44704f69SBart Van Assche } else
5615*44704f69SBart Van Assche pr2serr("keep verbose=%d\n", op->verbose);
5616*44704f69SBart Van Assche #else
5617*44704f69SBart Van Assche if (op->verbose_given && op->version_given)
5618*44704f69SBart Van Assche pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
5619*44704f69SBart Van Assche #endif
5620*44704f69SBart Van Assche if (op->version_given) {
5621*44704f69SBart Van Assche pr2serr("version: %s\n", version_str);
5622*44704f69SBart Van Assche goto early_out;
5623*44704f69SBart Van Assche }
5624*44704f69SBart Van Assche
5625*44704f69SBart Van Assche vb = op->verbose; /* may have changed */
5626*44704f69SBart Van Assche if (op->enumerate || op->do_list) {
5627*44704f69SBart Van Assche enumerate_work(op);
5628*44704f69SBart Van Assche goto early_out;
5629*44704f69SBart Van Assche }
5630*44704f69SBart Van Assche enc_stat_rsp = sg_memalign(op->maxlen, 0, &free_enc_stat_rsp, false);
5631*44704f69SBart Van Assche if (NULL == enc_stat_rsp) {
5632*44704f69SBart Van Assche pr2serr("Unable to get heap for enc_stat_rsp\n");
5633*44704f69SBart Van Assche goto err_out;
5634*44704f69SBart Van Assche }
5635*44704f69SBart Van Assche enc_stat_rsp_sz = op->maxlen;
5636*44704f69SBart Van Assche elem_desc_rsp = sg_memalign(op->maxlen, 0, &free_elem_desc_rsp, false);
5637*44704f69SBart Van Assche if (NULL == elem_desc_rsp) {
5638*44704f69SBart Van Assche pr2serr("Unable to get heap for elem_desc_rsp\n");
5639*44704f69SBart Van Assche goto err_out;
5640*44704f69SBart Van Assche }
5641*44704f69SBart Van Assche elem_desc_rsp_sz = op->maxlen;
5642*44704f69SBart Van Assche add_elem_rsp = sg_memalign(op->maxlen, 0, &free_add_elem_rsp, false);
5643*44704f69SBart Van Assche if (NULL == add_elem_rsp) {
5644*44704f69SBart Van Assche pr2serr("Unable to get heap for add_elem_rsp\n");
5645*44704f69SBart Van Assche goto err_out;
5646*44704f69SBart Van Assche }
5647*44704f69SBart Van Assche add_elem_rsp_sz = op->maxlen;
5648*44704f69SBart Van Assche threshold_rsp = sg_memalign(op->maxlen, 0, &free_threshold_rsp, false);
5649*44704f69SBart Van Assche if (NULL == threshold_rsp) {
5650*44704f69SBart Van Assche pr2serr("Unable to get heap for threshold_rsp\n");
5651*44704f69SBart Van Assche goto err_out;
5652*44704f69SBart Van Assche }
5653*44704f69SBart Van Assche threshold_rsp_sz = op->maxlen;
5654*44704f69SBart Van Assche
5655*44704f69SBart Van Assche if (op->num_cgs) {
5656*44704f69SBart Van Assche have_cgs = true;
5657*44704f69SBart Van Assche if (op->page_code_given &&
5658*44704f69SBart Van Assche ! ((ENC_STATUS_DPC == op->page_code) ||
5659*44704f69SBart Van Assche (THRESHOLD_DPC == op->page_code) ||
5660*44704f69SBart Van Assche (ADD_ELEM_STATUS_DPC == op->page_code))) {
5661*44704f69SBart Van Assche pr2serr("--clear, --get or --set options only supported for the "
5662*44704f69SBart Van Assche "Enclosure\nControl/Status, Threshold In/Out and "
5663*44704f69SBart Van Assche "Additional Element Status pages\n");
5664*44704f69SBart Van Assche ret = SG_LIB_SYNTAX_ERROR;
5665*44704f69SBart Van Assche goto err_out;
5666*44704f69SBart Van Assche }
5667*44704f69SBart Van Assche if (! (op->ind_given || op->desc_name || (op->dev_slot_num >= 0) ||
5668*44704f69SBart Van Assche saddr_non_zero(op->sas_addr))) {
5669*44704f69SBart Van Assche pr2serr("with --clear, --get or --set option need either\n "
5670*44704f69SBart Van Assche "--index, --descriptor, --dev-slot-num or --sas-addr\n");
5671*44704f69SBart Van Assche ret = SG_LIB_CONTRADICT;
5672*44704f69SBart Van Assche goto err_out;
5673*44704f69SBart Van Assche }
5674*44704f69SBart Van Assche for (k = 0, cgs_clp = op->cgs_cl_arr, tavp = tav_arr; k < op->num_cgs;
5675*44704f69SBart Van Assche ++k, ++cgs_clp, ++tavp) {
5676*44704f69SBart Van Assche if (parse_cgs_str(cgs_clp->cgs_str, tavp)) {
5677*44704f69SBart Van Assche pr2serr("unable to decode STR argument to: %s\n",
5678*44704f69SBart Van Assche cgs_clp->cgs_str);
5679*44704f69SBart Van Assche ret = SG_LIB_SYNTAX_ERROR;
5680*44704f69SBart Van Assche goto err_out;
5681*44704f69SBart Van Assche }
5682*44704f69SBart Van Assche if ((GET_OPT == cgs_clp->cgs_sel) && tavp->val_str)
5683*44704f69SBart Van Assche pr2serr("--get option ignoring =<val> at the end of STR "
5684*44704f69SBart Van Assche "argument\n");
5685*44704f69SBart Van Assche if (NULL == tavp->val_str) {
5686*44704f69SBart Van Assche if (CLEAR_OPT == cgs_clp->cgs_sel)
5687*44704f69SBart Van Assche tavp->val = DEF_CLEAR_VAL;
5688*44704f69SBart Van Assche if (SET_OPT == cgs_clp->cgs_sel)
5689*44704f69SBart Van Assche tavp->val = DEF_SET_VAL;
5690*44704f69SBart Van Assche }
5691*44704f69SBart Van Assche if (!strcmp(cgs_clp->cgs_str, "sas_addr") &&
5692*44704f69SBart Van Assche op->dev_slot_num < 0) {
5693*44704f69SBart Van Assche pr2serr("--get=sas_addr requires --dev-slot-num. For "
5694*44704f69SBart Van Assche "expander SAS address, use exp_sas_addr instead.\n");
5695*44704f69SBart Van Assche ret = SG_LIB_SYNTAX_ERROR;
5696*44704f69SBart Van Assche goto err_out;
5697*44704f69SBart Van Assche }
5698*44704f69SBart Van Assche tavp->cgs_sel = cgs_clp->cgs_sel;
5699*44704f69SBart Van Assche }
5700*44704f69SBart Van Assche /* keep this descending for loop directly after ascending for loop */
5701*44704f69SBart Van Assche for (--k, --cgs_clp; k >= 0; --k, --cgs_clp) {
5702*44704f69SBart Van Assche if ((CLEAR_OPT == cgs_clp->cgs_sel) ||
5703*44704f69SBart Van Assche (SET_OPT == cgs_clp->cgs_sel)) {
5704*44704f69SBart Van Assche cgs_clp->last_cs = true;
5705*44704f69SBart Van Assche break;
5706*44704f69SBart Van Assche }
5707*44704f69SBart Van Assche }
5708*44704f69SBart Van Assche }
5709*44704f69SBart Van Assche
5710*44704f69SBart Van Assche #ifdef SG_LIB_WIN32
5711*44704f69SBart Van Assche #ifdef SG_LIB_WIN32_DIRECT
5712*44704f69SBart Van Assche if (vb > 4)
5713*44704f69SBart Van Assche pr2serr("Initial win32 SPT interface state: %s\n",
5714*44704f69SBart Van Assche scsi_pt_win32_spt_state() ? "direct" : "indirect");
5715*44704f69SBart Van Assche if (op->maxlen >= 16384)
5716*44704f69SBart Van Assche scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */);
5717*44704f69SBart Van Assche #endif
5718*44704f69SBart Van Assche #endif
5719*44704f69SBart Van Assche
5720*44704f69SBart Van Assche #if 0
5721*44704f69SBart Van Assche pr2serr("Debug dump of input parameters:\n");
5722*44704f69SBart Van Assche pr2serr(" index option given: %d, ind_th=%d, ind_indiv=%d, "
5723*44704f69SBart Van Assche "ind_indiv_last=%d\n", op->ind_given, op->ind_th,
5724*44704f69SBart Van Assche op->ind_indiv, op->ind_indiv_last);
5725*44704f69SBart Van Assche pr2serr(" num_cgs=%d, contents:\n", op->num_cgs);
5726*44704f69SBart Van Assche for (k = 0, tavp = tav_arr, cgs_clp = op->cgs_cl_arr;
5727*44704f69SBart Van Assche k < op->num_cgs; ++k, ++tavp, ++cgs_clp) {
5728*44704f69SBart Van Assche pr2serr(" k=%d, cgs_sel=%d, last_cs=%d, tavp=%p str: %s\n",
5729*44704f69SBart Van Assche k, (int)cgs_clp->cgs_sel, (int)cgs_clp->last_cs, tavp,
5730*44704f69SBart Van Assche cgs_clp->cgs_str);
5731*44704f69SBart Van Assche }
5732*44704f69SBart Van Assche #endif
5733*44704f69SBart Van Assche
5734*44704f69SBart Van Assche if (op->dev_name) {
5735*44704f69SBart Van Assche sg_fd = sg_cmds_open_device(op->dev_name, op->o_readonly, vb);
5736*44704f69SBart Van Assche if (sg_fd < 0) {
5737*44704f69SBart Van Assche if (vb)
5738*44704f69SBart Van Assche pr2serr("open error: %s: %s\n", op->dev_name,
5739*44704f69SBart Van Assche safe_strerror(-sg_fd));
5740*44704f69SBart Van Assche ret = sg_convert_errno(-sg_fd);
5741*44704f69SBart Van Assche goto early_out;
5742*44704f69SBart Van Assche }
5743*44704f69SBart Van Assche ptvp = construct_scsi_pt_obj_with_fd(sg_fd, vb);
5744*44704f69SBart Van Assche if (NULL == ptvp) {
5745*44704f69SBart Van Assche pr2serr("construct pt_base failed, probably out of memory\n");
5746*44704f69SBart Van Assche ret = sg_convert_errno(ENOMEM);
5747*44704f69SBart Van Assche goto err_out;
5748*44704f69SBart Van Assche }
5749*44704f69SBart Van Assche if (! (op->do_raw || have_cgs || (op->do_hex > 2))) {
5750*44704f69SBart Van Assche uint8_t inq_rsp[36];
5751*44704f69SBart Van Assche
5752*44704f69SBart Van Assche memset(inq_rsp, 0, sizeof(inq_rsp));
5753*44704f69SBart Van Assche if ((ret = sg_ll_inquiry_pt(ptvp, false, 0, inq_rsp, 36,
5754*44704f69SBart Van Assche 0, &resid, ! op->quiet, vb))) {
5755*44704f69SBart Van Assche pr2serr("%s doesn't respond to a SCSI INQUIRY\n",
5756*44704f69SBart Van Assche op->dev_name);
5757*44704f69SBart Van Assche goto err_out;
5758*44704f69SBart Van Assche } else {
5759*44704f69SBart Van Assche if (resid > 0)
5760*44704f69SBart Van Assche pr2serr("Short INQUIRY response, not looking good\n");
5761*44704f69SBart Van Assche printf(" %.8s %.16s %.4s\n", inq_rsp + 8, inq_rsp + 16,
5762*44704f69SBart Van Assche inq_rsp + 32);
5763*44704f69SBart Van Assche pd_type = PDT_MASK & inq_rsp[0];
5764*44704f69SBart Van Assche cp = sg_get_pdt_str(pd_type, sizeof(buff), buff);
5765*44704f69SBart Van Assche if (0xd == pd_type) {
5766*44704f69SBart Van Assche if (vb)
5767*44704f69SBart Van Assche printf(" enclosure services device\n");
5768*44704f69SBart Van Assche } else if (0x40 & inq_rsp[6])
5769*44704f69SBart Van Assche printf(" %s device has EncServ bit set\n", cp);
5770*44704f69SBart Van Assche else {
5771*44704f69SBart Van Assche if (0 != memcmp("NVMe", inq_rsp + 8, 4))
5772*44704f69SBart Van Assche printf(" %s device (not an enclosure)\n", cp);
5773*44704f69SBart Van Assche }
5774*44704f69SBart Van Assche }
5775*44704f69SBart Van Assche clear_scsi_pt_obj(ptvp);
5776*44704f69SBart Van Assche }
5777*44704f69SBart Van Assche } else if (op->do_control) {
5778*44704f69SBart Van Assche pr2serr("Cannot do SCSI Send diagnostic command without a DEVICE\n");
5779*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
5780*44704f69SBart Van Assche }
5781*44704f69SBart Van Assche
5782*44704f69SBart Van Assche #if (HAVE_NVME && (! IGNORE_NVME))
5783*44704f69SBart Van Assche if (ptvp && pt_device_is_nvme(ptvp) && (enc_stat_rsp_sz > 4095)) {
5784*44704f69SBart Van Assche /* Fetch VPD 0xde (vendor specific: sg3_utils) for Identify ctl */
5785*44704f69SBart Van Assche ret = sg_ll_inquiry_pt(ptvp, true, 0xde, enc_stat_rsp, 4096, 0,
5786*44704f69SBart Van Assche &resid, ! op->quiet, vb);
5787*44704f69SBart Van Assche if (ret) {
5788*44704f69SBart Van Assche if (vb)
5789*44704f69SBart Van Assche pr2serr("Fetch VPD page 0xde (NVMe Identify ctl) failed, "
5790*44704f69SBart Van Assche "continue\n");
5791*44704f69SBart Van Assche } else if (resid > 0) {
5792*44704f69SBart Van Assche if (vb)
5793*44704f69SBart Van Assche pr2serr("VPD page 0xde (NVMe Identify ctl) less than 4096 "
5794*44704f69SBart Van Assche "bytes, continue\n");
5795*44704f69SBart Van Assche } else {
5796*44704f69SBart Van Assche uint8_t nvmsr;
5797*44704f69SBart Van Assche uint16_t oacs;
5798*44704f69SBart Van Assche
5799*44704f69SBart Van Assche nvmsr = enc_stat_rsp[253];
5800*44704f69SBart Van Assche oacs = sg_get_unaligned_le16(enc_stat_rsp + 256); /* N.B. LE */
5801*44704f69SBart Van Assche if (vb > 3)
5802*44704f69SBart Van Assche pr2serr("NVMe Identify ctl response: nvmsr=%u, oacs=0x%x\n",
5803*44704f69SBart Van Assche nvmsr, oacs);
5804*44704f69SBart Van Assche if (! ((0x2 & nvmsr) && (0x40 & oacs))) {
5805*44704f69SBart Van Assche pr2serr(">>> Warning: A NVMe enclosure needs both the "
5806*44704f69SBart Van Assche "enclosure bit and support for\n");
5807*44704f69SBart Van Assche pr2serr(">>> MI Send+Receive commands bit set; current "
5808*44704f69SBart Van Assche "state: %s, %s\n", (0x2 & nvmsr) ? "set" : "clear",
5809*44704f69SBart Van Assche (0x40 & oacs) ? "set" : "clear");
5810*44704f69SBart Van Assche }
5811*44704f69SBart Van Assche }
5812*44704f69SBart Van Assche clear_scsi_pt_obj(ptvp);
5813*44704f69SBart Van Assche memset(enc_stat_rsp, 0, enc_stat_rsp_sz);
5814*44704f69SBart Van Assche }
5815*44704f69SBart Van Assche #endif
5816*44704f69SBart Van Assche
5817*44704f69SBart Van Assche if (ptvp) {
5818*44704f69SBart Van Assche n = (enc_stat_rsp_sz < REQUEST_SENSE_RESP_SZ) ? enc_stat_rsp_sz :
5819*44704f69SBart Van Assche REQUEST_SENSE_RESP_SZ;
5820*44704f69SBart Van Assche ret = sg_ll_request_sense_pt(ptvp, false, enc_stat_rsp, n,
5821*44704f69SBart Van Assche ! op->quiet, vb);
5822*44704f69SBart Van Assche if (0 == ret) {
5823*44704f69SBart Van Assche int sense_len = n - get_scsi_pt_resid(ptvp);
5824*44704f69SBart Van Assche struct sg_scsi_sense_hdr ssh;
5825*44704f69SBart Van Assche
5826*44704f69SBart Van Assche if ((sense_len > 7) && sg_scsi_normalize_sense(enc_stat_rsp,
5827*44704f69SBart Van Assche sense_len, &ssh)) {
5828*44704f69SBart Van Assche const char * aa_str = sg_get_asc_ascq_str(ssh.asc, ssh.ascq,
5829*44704f69SBart Van Assche sizeof(b), b);
5830*44704f69SBart Van Assche
5831*44704f69SBart Van Assche /* Ignore the possibility that multiple UAs queued up */
5832*44704f69SBart Van Assche if (SPC_SK_UNIT_ATTENTION == ssh.sense_key)
5833*44704f69SBart Van Assche pr2serr("Unit attention detected: %s\n ... continue\n",
5834*44704f69SBart Van Assche aa_str);
5835*44704f69SBart Van Assche else {
5836*44704f69SBart Van Assche if (vb) {
5837*44704f69SBart Van Assche pr2serr("Request Sense near startup detected "
5838*44704f69SBart Van Assche "something:\n");
5839*44704f69SBart Van Assche pr2serr(" Sense key: %s, additional: %s\n ... "
5840*44704f69SBart Van Assche "continue\n",
5841*44704f69SBart Van Assche sg_get_sense_key_str(ssh.sense_key,
5842*44704f69SBart Van Assche sizeof(buff), buff), aa_str);
5843*44704f69SBart Van Assche }
5844*44704f69SBart Van Assche }
5845*44704f69SBart Van Assche }
5846*44704f69SBart Van Assche } else {
5847*44704f69SBart Van Assche if (vb)
5848*44704f69SBart Van Assche pr2serr("Request sense failed (res=%d), most likely "
5849*44704f69SBart Van Assche " problems ahead\n", ret);
5850*44704f69SBart Van Assche }
5851*44704f69SBart Van Assche clear_scsi_pt_obj(ptvp);
5852*44704f69SBart Van Assche memset(enc_stat_rsp, 0, enc_stat_rsp_sz);
5853*44704f69SBart Van Assche }
5854*44704f69SBart Van Assche
5855*44704f69SBart Van Assche if (op->nickname_str)
5856*44704f69SBart Van Assche ret = ses_set_nickname(ptvp, op);
5857*44704f69SBart Van Assche else if (have_cgs) {
5858*44704f69SBart Van Assche for (k = 0, tavp = tav_arr, cgs_clp = op->cgs_cl_arr;
5859*44704f69SBart Van Assche k < op->num_cgs; ++k, ++tavp, ++cgs_clp) {
5860*44704f69SBart Van Assche ret = ses_cgs(ptvp, tavp, op, cgs_clp->last_cs);
5861*44704f69SBart Van Assche if (ret)
5862*44704f69SBart Van Assche break;
5863*44704f69SBart Van Assche }
5864*44704f69SBart Van Assche } else if (op->do_join)
5865*44704f69SBart Van Assche ret = join_work(ptvp, op, true);
5866*44704f69SBart Van Assche else if (op->do_status)
5867*44704f69SBart Van Assche ret = process_status_page_s(ptvp, op);
5868*44704f69SBart Van Assche else { /* control page requested */
5869*44704f69SBart Van Assche op->data_arr[0] = op->page_code;
5870*44704f69SBart Van Assche op->data_arr[1] = op->byte1;
5871*44704f69SBart Van Assche d_len = op->arr_len + DATA_IN_OFF;
5872*44704f69SBart Van Assche sg_put_unaligned_be16((uint16_t)op->arr_len, op->data_arr + 2);
5873*44704f69SBart Van Assche switch (op->page_code) {
5874*44704f69SBart Van Assche case ENC_CONTROL_DPC: /* Enclosure Control diagnostic page [0x2] */
5875*44704f69SBart Van Assche printf("Sending Enclosure Control [0x%x] page, with page "
5876*44704f69SBart Van Assche "length=%d bytes\n", op->page_code, op->arr_len);
5877*44704f69SBart Van Assche ret = do_senddiag(ptvp, op->data_arr, d_len, ! op->quiet, vb);
5878*44704f69SBart Van Assche if (ret) {
5879*44704f69SBart Van Assche pr2serr("couldn't send Enclosure Control page\n");
5880*44704f69SBart Van Assche goto err_out;
5881*44704f69SBart Van Assche }
5882*44704f69SBart Van Assche break;
5883*44704f69SBart Van Assche case STRING_DPC: /* String Out diagnostic page [0x4] */
5884*44704f69SBart Van Assche printf("Sending String Out [0x%x] page, with page length=%d "
5885*44704f69SBart Van Assche "bytes\n", op->page_code, op->arr_len);
5886*44704f69SBart Van Assche ret = do_senddiag(ptvp, op->data_arr, d_len, ! op->quiet, vb);
5887*44704f69SBart Van Assche if (ret) {
5888*44704f69SBart Van Assche pr2serr("couldn't send String Out page\n");
5889*44704f69SBart Van Assche goto err_out;
5890*44704f69SBart Van Assche }
5891*44704f69SBart Van Assche break;
5892*44704f69SBart Van Assche case THRESHOLD_DPC: /* Threshold Out diagnostic page [0x5] */
5893*44704f69SBart Van Assche printf("Sending Threshold Out [0x%x] page, with page length=%d "
5894*44704f69SBart Van Assche "bytes\n", op->page_code, op->arr_len);
5895*44704f69SBart Van Assche ret = do_senddiag(ptvp, op->data_arr, d_len, ! op->quiet, vb);
5896*44704f69SBart Van Assche if (ret) {
5897*44704f69SBart Van Assche pr2serr("couldn't send Threshold Out page\n");
5898*44704f69SBart Van Assche goto err_out;
5899*44704f69SBart Van Assche }
5900*44704f69SBart Van Assche break;
5901*44704f69SBart Van Assche case ARRAY_CONTROL_DPC: /* Array control diagnostic page [0x6] */
5902*44704f69SBart Van Assche printf("Sending Array Control [0x%x] page, with page "
5903*44704f69SBart Van Assche "length=%d bytes\n", op->page_code, op->arr_len);
5904*44704f69SBart Van Assche ret = do_senddiag(ptvp, op->data_arr, d_len, ! op->quiet, vb);
5905*44704f69SBart Van Assche if (ret) {
5906*44704f69SBart Van Assche pr2serr("couldn't send Array Control page\n");
5907*44704f69SBart Van Assche goto err_out;
5908*44704f69SBart Van Assche }
5909*44704f69SBart Van Assche break;
5910*44704f69SBart Van Assche case SUBENC_STRING_DPC: /* Subenclosure String Out page [0xc] */
5911*44704f69SBart Van Assche printf("Sending Subenclosure String Out [0x%x] page, with page "
5912*44704f69SBart Van Assche "length=%d bytes\n", op->page_code, op->arr_len);
5913*44704f69SBart Van Assche ret = do_senddiag(ptvp, op->data_arr, d_len, ! op->quiet, vb);
5914*44704f69SBart Van Assche if (ret) {
5915*44704f69SBart Van Assche pr2serr("couldn't send Subenclosure String Out page\n");
5916*44704f69SBart Van Assche goto err_out;
5917*44704f69SBart Van Assche }
5918*44704f69SBart Van Assche break;
5919*44704f69SBart Van Assche case DOWNLOAD_MICROCODE_DPC: /* Download Microcode Control [0xe] */
5920*44704f69SBart Van Assche printf("Sending Download Microcode Control [0x%x] page, with "
5921*44704f69SBart Van Assche "page length=%d bytes\n", op->page_code, d_len);
5922*44704f69SBart Van Assche printf(" Perhaps it would be better to use the sg_ses_microcode "
5923*44704f69SBart Van Assche "utility\n");
5924*44704f69SBart Van Assche ret = do_senddiag(ptvp, op->data_arr, d_len, ! op->quiet, vb);
5925*44704f69SBart Van Assche if (ret) {
5926*44704f69SBart Van Assche pr2serr("couldn't send Download Microcode Control page\n");
5927*44704f69SBart Van Assche goto err_out;
5928*44704f69SBart Van Assche }
5929*44704f69SBart Van Assche break;
5930*44704f69SBart Van Assche case SUBENC_NICKNAME_DPC: /* Subenclosure Nickname Control [0xf] */
5931*44704f69SBart Van Assche printf("Sending Subenclosure Nickname Control [0x%x] page, with "
5932*44704f69SBart Van Assche "page length=%d bytes\n", op->page_code, d_len);
5933*44704f69SBart Van Assche ret = do_senddiag(ptvp, op->data_arr, d_len, ! op->quiet, vb);
5934*44704f69SBart Van Assche if (ret) {
5935*44704f69SBart Van Assche pr2serr("couldn't send Subenclosure Nickname Control page\n");
5936*44704f69SBart Van Assche goto err_out;
5937*44704f69SBart Van Assche }
5938*44704f69SBart Van Assche break;
5939*44704f69SBart Van Assche default:
5940*44704f69SBart Van Assche pr2serr("Setting SES control page 0x%x not supported by this "
5941*44704f69SBart Van Assche "utility\n", op->page_code);
5942*44704f69SBart Van Assche pr2serr("That can be done with the sg_senddiag utility with its "
5943*44704f69SBart Van Assche "'--raw=' option\n");
5944*44704f69SBart Van Assche ret = SG_LIB_SYNTAX_ERROR;
5945*44704f69SBart Van Assche break;
5946*44704f69SBart Van Assche }
5947*44704f69SBart Van Assche }
5948*44704f69SBart Van Assche
5949*44704f69SBart Van Assche err_out:
5950*44704f69SBart Van Assche if (! op->do_status) {
5951*44704f69SBart Van Assche sg_get_category_sense_str(ret, sizeof(b), b, vb);
5952*44704f69SBart Van Assche pr2serr(" %s\n", b);
5953*44704f69SBart Van Assche }
5954*44704f69SBart Van Assche if (free_enc_stat_rsp)
5955*44704f69SBart Van Assche free(free_enc_stat_rsp);
5956*44704f69SBart Van Assche if (free_elem_desc_rsp)
5957*44704f69SBart Van Assche free(free_elem_desc_rsp);
5958*44704f69SBart Van Assche if (free_add_elem_rsp)
5959*44704f69SBart Van Assche free(free_add_elem_rsp);
5960*44704f69SBart Van Assche if (free_threshold_rsp)
5961*44704f69SBart Van Assche free(free_threshold_rsp);
5962*44704f69SBart Van Assche
5963*44704f69SBart Van Assche early_out:
5964*44704f69SBart Van Assche if (sg_fd >= 0) {
5965*44704f69SBart Van Assche res = sg_cmds_close_device(sg_fd);
5966*44704f69SBart Van Assche if (res < 0) {
5967*44704f69SBart Van Assche pr2serr("close error: %s\n", safe_strerror(-res));
5968*44704f69SBart Van Assche if (0 == ret)
5969*44704f69SBart Van Assche ret = sg_convert_errno(-res);
5970*44704f69SBart Van Assche }
5971*44704f69SBart Van Assche }
5972*44704f69SBart Van Assche if (ptvp)
5973*44704f69SBart Van Assche destruct_scsi_pt_obj(ptvp);
5974*44704f69SBart Van Assche if ((0 == vb) && (! op->quiet)) {
5975*44704f69SBart Van Assche if (! sg_if_can2stderr("sg_ses failed: ", ret))
5976*44704f69SBart Van Assche pr2serr("Some error occurred, try again with '-v' or '-vv' for "
5977*44704f69SBart Van Assche "more information\n");
5978*44704f69SBart Van Assche else if ((SG_LIB_SYNTAX_ERROR == ret) && (0 == vb))
5979*44704f69SBart Van Assche pr2serr("Add '-h' to command line for usage information\n");
5980*44704f69SBart Van Assche }
5981*44704f69SBart Van Assche if (op->free_data_arr)
5982*44704f69SBart Van Assche free(op->free_data_arr);
5983*44704f69SBart Van Assche if (free_config_dp_resp)
5984*44704f69SBart Van Assche free(free_config_dp_resp);
5985*44704f69SBart Van Assche return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
5986*44704f69SBart Van Assche }
5987