1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2019, Joyent, Inc.
25 */
26
27 #include <sys/fm/protocol.h>
28 #include <strings.h>
29 #include <fm/topo_mod.h>
30 #include <fm/topo_method.h>
31 #include <sys/scsi/impl/inquiry.h>
32 #include <sys/scsi/impl/scsi_sas.h>
33 #include <sys/scsi/scsi_address.h>
34 #include <did_props.h>
35
36 static const topo_pgroup_info_t storage_pgroup =
37 { TOPO_PGROUP_STORAGE, TOPO_STABILITY_PRIVATE,
38 TOPO_STABILITY_PRIVATE, 1 };
39
40 static const topo_method_t recep_methods[] = {
41 { TOPO_METH_OCCUPIED, TOPO_METH_OCCUPIED_DESC,
42 TOPO_METH_OCCUPIED_VERSION, TOPO_STABILITY_INTERNAL,
43 topo_mod_hc_occupied },
44 { NULL }
45 };
46
47 void
pci_di_prop_set(tnode_t * tn,di_node_t din,char * dpnm,char * tpnm)48 pci_di_prop_set(tnode_t *tn, di_node_t din, char *dpnm, char *tpnm)
49 {
50 int err;
51 char *tmpbuf;
52
53 if (di_prop_lookup_strings(DDI_DEV_T_ANY, din, dpnm, &tmpbuf) == 1)
54 (void) topo_prop_set_string(tn, TOPO_PGROUP_STORAGE, tpnm,
55 TOPO_PROP_IMMUTABLE, tmpbuf, &err);
56 }
57
58 void
pci_pi_prop_set(tnode_t * tn,di_path_t din,char * dpnm,char * tpnm)59 pci_pi_prop_set(tnode_t *tn, di_path_t din, char *dpnm, char *tpnm)
60 {
61 int err;
62 char *tmpbuf;
63
64 if (di_path_prop_lookup_strings(din, dpnm, &tmpbuf) == 1)
65 (void) topo_prop_set_string(tn, TOPO_PGROUP_STORAGE, tpnm,
66 TOPO_PROP_IMMUTABLE, tmpbuf, &err);
67 }
68
69 static void
pci_scsi_device_create(topo_mod_t * mod,nvlist_t * auth,tnode_t * parent,di_node_t cn,int instance,di_path_t pi)70 pci_scsi_device_create(topo_mod_t *mod, nvlist_t *auth, tnode_t *parent,
71 di_node_t cn, int instance, di_path_t pi)
72 {
73 tnode_t *child;
74 nvlist_t *fmri;
75 int e, *val;
76 int64_t *val64;
77
78 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, SCSI_DEVICE,
79 instance, NULL, auth, NULL, NULL, NULL);
80 if (fmri == NULL)
81 return;
82 child = topo_node_bind(mod, parent, SCSI_DEVICE, instance, fmri);
83 nvlist_free(fmri);
84 if (child == NULL)
85 return;
86 if (topo_pgroup_create(child, &storage_pgroup, &e) < 0)
87 return;
88 if (pi != NULL) {
89 pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_TARGET_PORT,
90 TOPO_STORAGE_TARGET_PORT);
91 pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_ATTACHED_PORT,
92 TOPO_STORAGE_ATTACHED_PORT);
93 pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_TARGET_PORT_PM,
94 TOPO_STORAGE_TARGET_PORT_PM);
95 pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_ATTACHED_PORT_PM,
96 TOPO_STORAGE_ATTACHED_PORT_PM);
97 if (di_path_prop_lookup_int64s(pi,
98 SCSI_ADDR_PROP_LUN64, &val64) == 1)
99 (void) topo_prop_set_int64(child, TOPO_PGROUP_STORAGE,
100 TOPO_STORAGE_LUN64, TOPO_PROP_IMMUTABLE, *val64,
101 &e);
102 } else {
103 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT,
104 TOPO_STORAGE_TARGET_PORT);
105 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT,
106 TOPO_STORAGE_ATTACHED_PORT);
107 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT_PM,
108 TOPO_STORAGE_TARGET_PORT_PM);
109 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT_PM,
110 TOPO_STORAGE_ATTACHED_PORT_PM);
111 if (di_prop_lookup_int64(DDI_DEV_T_ANY, cn,
112 SCSI_ADDR_PROP_LUN64, &val64) == 1)
113 (void) topo_prop_set_int64(child, TOPO_PGROUP_STORAGE,
114 TOPO_STORAGE_LUN64, TOPO_PROP_IMMUTABLE, *val64,
115 &e);
116 }
117 pci_di_prop_set(child, cn, DEVID_PROP_NAME, TOPO_STORAGE_DEVID);
118 pci_di_prop_set(child, cn, INQUIRY_VENDOR_ID,
119 TOPO_STORAGE_MANUFACTURER);
120 pci_di_prop_set(child, cn, INQUIRY_PRODUCT_ID, TOPO_STORAGE_MODEL);
121 pci_di_prop_set(child, cn, INQUIRY_REVISION_ID,
122 TOPO_STORAGE_FIRMWARE_REV);
123 if (di_prop_lookup_ints(DDI_DEV_T_ANY, cn,
124 INQUIRY_DEVICE_TYPE, &val) == 1)
125 (void) topo_prop_set_int32(child, TOPO_PGROUP_STORAGE,
126 TOPO_STORAGE_DEVICE_TYPE, TOPO_PROP_IMMUTABLE, *val, &e);
127 }
128
129 static void
pci_smp_device_create(topo_mod_t * mod,nvlist_t * auth,tnode_t * parent,di_node_t cn,int instance)130 pci_smp_device_create(topo_mod_t *mod, nvlist_t *auth, tnode_t *parent,
131 di_node_t cn, int instance)
132 {
133 tnode_t *child;
134 nvlist_t *fmri;
135 int e;
136
137 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, SMP_DEVICE,
138 instance, NULL, auth, NULL, NULL, NULL);
139 if (fmri == NULL)
140 return;
141 child = topo_node_bind(mod, parent, SMP_DEVICE, instance, fmri);
142 nvlist_free(fmri);
143 if (child == NULL)
144 return;
145 if (topo_pgroup_create(child, &storage_pgroup, &e) < 0)
146 return;
147 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT,
148 TOPO_STORAGE_TARGET_PORT);
149 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT,
150 TOPO_STORAGE_ATTACHED_PORT);
151 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT_PM,
152 TOPO_STORAGE_TARGET_PORT_PM);
153 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT_PM,
154 TOPO_STORAGE_ATTACHED_PORT_PM);
155 pci_di_prop_set(child, cn, DEVID_PROP_NAME, TOPO_STORAGE_DEVID);
156 pci_di_prop_set(child, cn, INQUIRY_VENDOR_ID,
157 TOPO_STORAGE_MANUFACTURER);
158 pci_di_prop_set(child, cn, INQUIRY_PRODUCT_ID, TOPO_STORAGE_MODEL);
159 pci_di_prop_set(child, cn, INQUIRY_REVISION_ID,
160 TOPO_STORAGE_FIRMWARE_REV);
161 }
162
163 static tnode_t *
pci_iport_device_create(topo_mod_t * mod,nvlist_t * auth,tnode_t * parent,di_node_t cn,int instance)164 pci_iport_device_create(topo_mod_t *mod, nvlist_t *auth, tnode_t *parent,
165 di_node_t cn, int instance)
166 {
167 tnode_t *child;
168 nvlist_t *fmri;
169 int e;
170
171 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, IPORT,
172 instance, NULL, auth, NULL, NULL, NULL);
173 if (fmri == NULL)
174 return (NULL);
175 child = topo_node_bind(mod, parent, IPORT, instance, fmri);
176 nvlist_free(fmri);
177 if (child == NULL)
178 return (NULL);
179 if (topo_pgroup_create(child, &storage_pgroup, &e) < 0)
180 return (child);
181 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_INITIATOR_PORT,
182 TOPO_STORAGE_INITIATOR_PORT);
183 (void) topo_prop_set_string(child, TOPO_PGROUP_STORAGE,
184 TOPO_STORAGE_INITIATOR_PORT_PM, TOPO_PROP_IMMUTABLE,
185 di_bus_addr(cn), &e);
186 return (child);
187 }
188
189 void
pci_iports_instantiate(topo_mod_t * mod,tnode_t * parent,di_node_t pn,int niports)190 pci_iports_instantiate(topo_mod_t *mod, tnode_t *parent, di_node_t pn,
191 int niports)
192 {
193 di_node_t cn, smp, sd;
194 di_path_t pi;
195 tnode_t *iport;
196 int i, j;
197 nvlist_t *auth;
198
199 if (topo_node_range_create(mod, parent, IPORT, 0, niports) < 0)
200 return;
201 auth = topo_mod_auth(mod, parent);
202 for (i = 0, cn = di_child_node(pn); cn != DI_NODE_NIL;
203 cn = di_sibling_node(cn)) {
204 /*
205 * First create any iport nodes.
206 */
207 if (strcmp(di_node_name(cn), "iport") != 0)
208 continue;
209 iport = pci_iport_device_create(mod, auth, parent, cn, i++);
210 if (iport == NULL)
211 continue;
212
213 /*
214 * Now create any scsi-device nodes.
215 */
216 for (j = 0, sd = di_child_node(cn); sd != DI_NODE_NIL;
217 sd = di_sibling_node(sd))
218 if (strcmp(di_node_name(sd), "smp") != 0)
219 j++;
220 for (pi = di_path_phci_next_path(cn, DI_PATH_NIL);
221 pi != DI_PATH_NIL; pi = di_path_phci_next_path(cn, pi))
222 if (di_path_client_node(pi) != NULL &&
223 strcmp(di_node_name(di_path_client_node(pi)),
224 "smp") != 0)
225 j++;
226 if (topo_node_range_create(mod, iport, SCSI_DEVICE, 0, j) < 0)
227 continue;
228 for (j = 0, sd = di_child_node(cn); sd != DI_NODE_NIL;
229 sd = di_sibling_node(sd))
230 if (strcmp(di_node_name(sd), "smp") != 0)
231 pci_scsi_device_create(mod, auth, iport, sd,
232 j++, NULL);
233 for (pi = di_path_phci_next_path(cn, DI_PATH_NIL);
234 pi != DI_PATH_NIL; pi = di_path_phci_next_path(cn, pi))
235 if (di_path_client_node(pi) != NULL &&
236 strcmp(di_node_name(di_path_client_node(pi)),
237 "smp") != 0)
238 pci_scsi_device_create(mod, auth, iport,
239 di_path_client_node(pi), j++, pi);
240
241 /*
242 * Now create any smp-device nodes.
243 */
244 for (j = 0, smp = di_child_node(cn); smp != DI_NODE_NIL;
245 smp = di_sibling_node(smp))
246 if (strcmp(di_node_name(smp), "smp") == 0)
247 j++;
248 if (topo_node_range_create(mod, iport, SMP_DEVICE, 0, j) < 0)
249 continue;
250 for (j = 0, smp = di_child_node(cn); smp != DI_NODE_NIL;
251 smp = di_sibling_node(smp))
252 if (strcmp(di_node_name(smp), "smp") == 0)
253 pci_smp_device_create(mod, auth, iport, smp,
254 j++);
255 }
256 nvlist_free(auth);
257 }
258
259 void
pci_receptacle_instantiate(topo_mod_t * mod,tnode_t * parent,di_node_t pnode)260 pci_receptacle_instantiate(topo_mod_t *mod, tnode_t *parent, di_node_t pnode)
261 {
262 int err, i, rcnt, lcnt;
263 char *propstrpm, *propstrlabel, *pm, *label;
264 nvlist_t *fmri, *auth;
265 tnode_t *recep;
266
267 rcnt = di_prop_lookup_strings(DDI_DEV_T_ANY, pnode,
268 DI_RECEPTACLE_PHYMASK, &propstrpm);
269 if ((lcnt = di_prop_lookup_strings(DDI_DEV_T_ANY, pnode,
270 DI_RECEPTACLE_LABEL, &propstrlabel)) <= 0) {
271 topo_mod_dprintf(mod,
272 "pci_receptacle_instanciate: rececptacle label not "
273 "found for the pci function node.\n");
274 return;
275 }
276
277 if (rcnt != lcnt) {
278 topo_mod_dprintf(mod,
279 "pci_receptacle_instantiate: rececptacle label count %d "
280 "doesn match with phy mask count %d\n", lcnt, rcnt);
281 }
282
283 label = propstrlabel;
284 pm = propstrpm;
285 auth = topo_mod_auth(mod, parent);
286 for (i = 0; i < rcnt; i++) {
287 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION,
288 RECEPTACLE, i, NULL, auth, NULL, NULL, NULL);
289 if (fmri == NULL) {
290 topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s",
291 topo_mod_errmsg(mod));
292 continue;
293 }
294 recep = topo_node_bind(mod, parent, RECEPTACLE, i, fmri);
295 nvlist_free(fmri);
296 if (recep == NULL) {
297 topo_mod_dprintf(mod, "topo_node_bind() failed: %s",
298 topo_mod_errmsg(mod));
299 continue;
300 }
301
302 if (label) {
303 if (topo_node_label_set(recep, label, &err) < 0) {
304 topo_mod_dprintf(mod,
305 "topo_receptacle_instantiate: "
306 "topo_node_label_set error(%s)\n",
307 topo_strerror(err));
308 }
309 if (i < lcnt) {
310 label = label + strlen(label) + 1;
311 } else {
312 label = NULL;
313 }
314 }
315
316 if (topo_pgroup_create(recep, &storage_pgroup, &err) < 0) {
317 topo_mod_dprintf(mod, "ses_set_expander_props: "
318 "create storage error %s\n", topo_strerror(err));
319 continue;
320 }
321 (void) topo_prop_set_string(recep, TOPO_PGROUP_STORAGE,
322 TOPO_STORAGE_SAS_PHY_MASK,
323 TOPO_PROP_IMMUTABLE, pm, &err);
324
325 if (topo_method_register(mod, recep, recep_methods) != 0) {
326 topo_mod_dprintf(mod, "topo_method_register() failed "
327 "on %s=%d: %s", RECEPTACLE, i,
328 topo_mod_errmsg(mod));
329 /* errno set */
330 continue;
331 }
332
333 pm = pm + strlen(pm) + 1;
334 }
335
336 nvlist_free(auth);
337 }
338