1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
14 */
15
16 #include <stddef.h>
17 #include <libnvpair.h>
18 #include <scsi/libses.h>
19 #include <scsi/libses_plugin.h>
20 #include <scsi/plugins/ses/framework/ses2_impl.h>
21
22 /*
23 * FC protocol specific parsing for the given (fp) AES element descriptor.
24 * Copy-pasted elem_parse_aes_fc() from ses2_elements.c
25 */
26 static int
27 hp_elem_parse_aes_fc(const ses2_aes_descr_fc_eip_impl_t *fp,
28 nvlist_t *nvl, size_t len)
29 {
30 int nverr, i;
31 nvlist_t **nva;
32 int nports;
33
34 if (len < offsetof(ses2_aes_descr_fc_eip_impl_t,
35 sadfi_ports))
36 return (0);
37
38 SES_NV_ADD(uint64, nverr, nvl, SES_PROP_BAY_NUMBER,
39 fp->sadfi_bay_number);
40 SES_NV_ADD(uint64, nverr, nvl, SES_FC_PROP_NODE_NAME,
41 SCSI_READ64(&fp->sadfi_node_name));
42
43 nports = MIN(fp->sadfi_n_ports,
44 (len - offsetof(ses2_aes_descr_fc_eip_impl_t,
45 sadfi_ports)) / sizeof (ses2_aes_port_descr_impl_t));
46
47 if (nports == 0)
48 return (0);
49
50 nva = ses_zalloc(nports * sizeof (nvlist_t *));
51 if (nva == NULL)
52 return (-1);
53
54 for (i = 0; i < nports; i++) {
55 if ((nverr = nvlist_alloc(&nva[i], NV_UNIQUE_NAME, 0)) != 0)
56 goto fail;
57 if ((nverr = nvlist_add_uint64(nva[i], SES_FC_PROP_LOOP_POS,
58 fp->sadfi_ports[i].sapdi_port_loop_position)) != 0)
59 goto fail;
60 if ((nverr = nvlist_add_uint64(nva[i], SES_FC_PROP_REQ_HARDADDR,
61 fp->sadfi_ports[i].sapdi_port_requested_hard_address)) != 0)
62 goto fail;
63 nverr = nvlist_add_uint64(nva[i], SES_FC_PROP_N_PORT_ID,
64 SCSI_READ24(fp->sadfi_ports[i].sapdi_n_port_identifier));
65 if (nverr != 0)
66 goto fail;
67 if ((nverr = nvlist_add_uint64(nva[i], SES_FC_PROP_N_PORT_NAME,
68 SCSI_READ64(&fp->sadfi_ports[i].sapdi_n_port_name))) != 0)
69 goto fail;
70 }
71
72 if ((nverr = nvlist_add_nvlist_array(nvl, SES_FC_PROP_PORTS,
73 nva, nports)) != 0)
74 goto fail;
75
76 for (i = 0; i < nports && nva[i] != NULL; i++)
77 nvlist_free(nva[i]);
78 ses_free(nva);
79 return (0);
80
81 fail:
82 for (i = 0; i < nports && nva[i] != NULL; i++)
83 nvlist_free(nva[i]);
84 ses_free(nva);
85 return (ses_set_nverrno(nverr, NULL));
86 }
87
88 /*
89 * Parse AES descriptor for the given element (dep).
90 * Copy-pasted elem_parse_aes_device() from ses2_elements.c
91 */
92 static int
93 hp_elem_parse_aes_device(const ses2_aes_descr_eip_impl_t *dep, nvlist_t *nvl,
94 size_t len)
95 {
96 ses2_aes_descr_fc_eip_impl_t *fp;
97 ses2_aes_descr_sas0_eip_impl_t *s0ep;
98 ses2_aes_descr_sas0_impl_t *s0p;
99 ses2_aes_descr_impl_t *dip;
100 nvlist_t **nva;
101 int nverr, i;
102 size_t nphy;
103
104 if (dep->sadei_eip) {
105 s0ep = (ses2_aes_descr_sas0_eip_impl_t *)
106 dep->sadei_protocol_specific;
107 s0p = (ses2_aes_descr_sas0_impl_t *)
108 dep->sadei_protocol_specific;
109 } else {
110 dip = (ses2_aes_descr_impl_t *)dep;
111 s0ep = NULL;
112 s0p = (ses2_aes_descr_sas0_impl_t *)
113 dip->sadei_protocol_specific;
114 }
115
116 if (dep->sadei_invalid)
117 return (0);
118
119 if (dep->sadei_protocol_identifier == SPC4_PROTO_FIBRE_CHANNEL) {
120 fp = (ses2_aes_descr_fc_eip_impl_t *)
121 dep->sadei_protocol_specific;
122
123 if (!SES_WITHIN_PAGE_STRUCT(fp, dep, len))
124 return (0);
125
126 return (hp_elem_parse_aes_fc(fp, nvl, len -
127 offsetof(ses2_aes_descr_eip_impl_t,
128 sadei_protocol_specific)));
129 } else if (dep->sadei_protocol_identifier != SPC4_PROTO_SAS) {
130 return (0);
131 }
132
133 if (s0p->sadsi_descriptor_type != SES2_AESD_SAS_DEVICE)
134 return (0);
135
136 SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_SAS_NOT_ALL_PHYS,
137 s0p->sadsi_not_all_phys);
138 if (s0ep != NULL) {
139 SES_NV_ADD(uint64, nverr, nvl, SES_PROP_BAY_NUMBER,
140 s0ep->sadsi_bay_number);
141 nphy = MIN(s0ep->sadsi_n_phy_descriptors,
142 (len - offsetof(ses2_aes_descr_sas0_eip_impl_t,
143 sadsi_phys)) / sizeof (ses2_aes_phy0_descr_impl_t));
144 } else {
145 nphy = MIN(s0p->sadsi_n_phy_descriptors,
146 (len - offsetof(ses2_aes_descr_sas0_impl_t,
147 sadsi_phys)) / sizeof (ses2_aes_phy0_descr_impl_t));
148 }
149
150 if (nphy == 0)
151 return (0);
152
153 nva = ses_zalloc(nphy * sizeof (nvlist_t *));
154 if (nva == NULL)
155 return (-1);
156
157 for (i = 0; i < nphy; i++) {
158 ses2_aes_phy0_descr_impl_t *pp;
159 pp = s0ep != NULL ? &s0ep->sadsi_phys[i] : &s0p->sadsi_phys[i];
160 if ((nverr = nvlist_alloc(&nva[i], NV_UNIQUE_NAME, 0)) != 0)
161 goto fail;
162 if ((nverr = nvlist_add_uint64(nva[i], SES_SAS_PROP_DEVICE_TYPE,
163 pp->sapdi_device_type)) != 0)
164 goto fail;
165 if ((nverr = nvlist_add_boolean_value(nva[i],
166 SES_SAS_PROP_SMPI_PORT, pp->sapdi_smp_initiator_port)) != 0)
167 goto fail;
168 if ((nverr = nvlist_add_boolean_value(nva[i],
169 SES_SAS_PROP_STPI_PORT, pp->sapdi_stp_initiator_port)) != 0)
170 goto fail;
171 if ((nverr = nvlist_add_boolean_value(nva[i],
172 SES_SAS_PROP_SSPI_PORT, pp->sapdi_ssp_initiator_port)) != 0)
173 goto fail;
174 if ((nverr = nvlist_add_boolean_value(nva[i],
175 SES_SAS_PROP_SATA_DEVICE, pp->sapdi_sata_device)) != 0)
176 goto fail;
177 if ((nverr = nvlist_add_boolean_value(nva[i],
178 SES_SAS_PROP_SMPT_PORT, pp->sapdi_smp_target_port)) != 0)
179 goto fail;
180 if ((nverr = nvlist_add_boolean_value(nva[i],
181 SES_SAS_PROP_STPT_PORT, pp->sapdi_stp_target_port)) != 0)
182 goto fail;
183 if ((nverr = nvlist_add_boolean_value(nva[i],
184 SES_SAS_PROP_SSPT_PORT, pp->sapdi_ssp_target_port)) != 0)
185 goto fail;
186 nverr = nvlist_add_uint64(nva[i], SES_SAS_PROP_ATT_ADDR,
187 SCSI_READ64(&pp->sapdi_attached_sas_address));
188 if (nverr != 0)
189 goto fail;
190 nverr = nvlist_add_uint64(nva[i], SES_SAS_PROP_ADDR,
191 SCSI_READ64(&pp->sapdi_sas_address));
192 if (nverr != 0)
193 goto fail;
194 if ((nverr = nvlist_add_uint64(nva[i], SES_SAS_PROP_PHY_ID,
195 pp->sapdi_phy_identifier)) != 0)
196 goto fail;
197 }
198
199 if ((nverr = nvlist_add_nvlist_array(nvl, SES_SAS_PROP_PHYS,
200 nva, nphy)) != 0)
201 goto fail;
202
203 for (i = 0; i < nphy && nva[i] != NULL; i++)
204 nvlist_free(nva[i]);
205 ses_free(nva);
206 return (0);
207
208 fail:
209 for (i = 0; i < nphy && nva[i] != NULL; i++)
210 nvlist_free(nva[i]);
211 ses_free(nva);
212 return (ses_set_nverrno(nverr, NULL));
213 }
214
215 /*
216 * HP specific ses node parsing is needed to correct libses assumptions about
217 * index numbering.
218 */
219 static int
220 hp_parse_node(ses_plugin_t *sp, ses_node_t *np)
221 {
222 uint64_t i, type;
223 int nverr;
224 size_t len;
225 nvlist_t *props;
226 ses2_aes_descr_eip_impl_t *dep;
227
228 if (ses_node_type(np) != SES_NODE_ELEMENT)
229 return (0);
230
231 props = ses_node_props(np);
232 VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE, &type) == 0);
233 if (type != SES_ET_ARRAY_DEVICE && type != SES_ET_DEVICE)
234 return (0);
235
236 if (nvlist_lookup_uint64(props, SES_PROP_ELEMENT_ONLY_INDEX, &i) != 0)
237 return (0);
238
239 /*
240 * We populated the element-only-index in ses_build_snap_skel().
241 * This index starts at zero and is used internally by libses to match
242 * device element indexes to the indexes obtained from the AES page (see
243 * ses2_aes_index()).
244 * HP starts their element index at one so we have an off by one error
245 * that we are correcting here
246 */
247 SES_NV_ADD(uint64, nverr, props, SES_PROP_ELEMENT_ONLY_INDEX, i + 1);
248
249 /* now that we've fixed the index we need to redo the AES parsing */
250 if ((dep = ses_plugin_page_lookup(sp, ses_node_snapshot(np),
251 SES2_DIAGPAGE_ADDL_ELEM_STATUS, np, &len)) == NULL)
252 return (0);
253
254 return (hp_elem_parse_aes_device(dep, props, len));
255 }
256
257 int
258 _ses_init(ses_plugin_t *sp)
259 {
260 ses_plugin_config_t config = {
261 .spc_node_parse = hp_parse_node
262 };
263
264 return (ses_plugin_register(sp, LIBSES_PLUGIN_VERSION, &config) != 0);
265 }