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 */
25
26 #include <sys/fm/protocol.h>
27 #include <strings.h>
28 #include <fm/topo_mod.h>
29 #include <sys/scsi/impl/inquiry.h>
30 #include <sys/scsi/impl/scsi_sas.h>
31 #include <sys/scsi/scsi_address.h>
32 #include <did_props.h>
33
34 static const topo_pgroup_info_t storage_pgroup =
35 { TOPO_PGROUP_STORAGE, TOPO_STABILITY_PRIVATE,
36 TOPO_STABILITY_PRIVATE, 1 };
37
38 void
pci_di_prop_set(tnode_t * tn,di_node_t din,char * dpnm,char * tpnm)39 pci_di_prop_set(tnode_t *tn, di_node_t din, char *dpnm, char *tpnm)
40 {
41 int err;
42 char *tmpbuf;
43
44 if (di_prop_lookup_strings(DDI_DEV_T_ANY, din, dpnm, &tmpbuf) == 1)
45 (void) topo_prop_set_string(tn, TOPO_PGROUP_STORAGE, tpnm,
46 TOPO_PROP_IMMUTABLE, tmpbuf, &err);
47 }
48
49 void
pci_pi_prop_set(tnode_t * tn,di_path_t din,char * dpnm,char * tpnm)50 pci_pi_prop_set(tnode_t *tn, di_path_t din, char *dpnm, char *tpnm)
51 {
52 int err;
53 char *tmpbuf;
54
55 if (di_path_prop_lookup_strings(din, dpnm, &tmpbuf) == 1)
56 (void) topo_prop_set_string(tn, TOPO_PGROUP_STORAGE, tpnm,
57 TOPO_PROP_IMMUTABLE, tmpbuf, &err);
58 }
59
60 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)61 pci_scsi_device_create(topo_mod_t *mod, nvlist_t *auth, tnode_t *parent,
62 di_node_t cn, int instance, di_path_t pi)
63 {
64 tnode_t *child;
65 nvlist_t *fmri;
66 int e, *val;
67 int64_t *val64;
68
69 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, SCSI_DEVICE,
70 instance, NULL, auth, NULL, NULL, NULL);
71 if (fmri == NULL)
72 return;
73 child = topo_node_bind(mod, parent, SCSI_DEVICE, instance, fmri);
74 nvlist_free(fmri);
75 if (child == NULL)
76 return;
77 if (topo_pgroup_create(child, &storage_pgroup, &e) < 0)
78 return;
79 if (pi != NULL) {
80 pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_TARGET_PORT,
81 TOPO_STORAGE_TARGET_PORT);
82 pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_ATTACHED_PORT,
83 TOPO_STORAGE_ATTACHED_PORT);
84 pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_TARGET_PORT_PM,
85 TOPO_STORAGE_TARGET_PORT_PM);
86 pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_ATTACHED_PORT_PM,
87 TOPO_STORAGE_ATTACHED_PORT_PM);
88 if (di_path_prop_lookup_int64s(pi,
89 SCSI_ADDR_PROP_LUN64, &val64) == 1)
90 (void) topo_prop_set_int64(child, TOPO_PGROUP_STORAGE,
91 TOPO_STORAGE_LUN64, TOPO_PROP_IMMUTABLE, *val64,
92 &e);
93 } else {
94 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT,
95 TOPO_STORAGE_TARGET_PORT);
96 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT,
97 TOPO_STORAGE_ATTACHED_PORT);
98 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT_PM,
99 TOPO_STORAGE_TARGET_PORT_PM);
100 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT_PM,
101 TOPO_STORAGE_ATTACHED_PORT_PM);
102 if (di_prop_lookup_int64(DDI_DEV_T_ANY, cn,
103 SCSI_ADDR_PROP_LUN64, &val64) == 1)
104 (void) topo_prop_set_int64(child, TOPO_PGROUP_STORAGE,
105 TOPO_STORAGE_LUN64, TOPO_PROP_IMMUTABLE, *val64,
106 &e);
107 }
108 pci_di_prop_set(child, cn, DEVID_PROP_NAME, TOPO_STORAGE_DEVID);
109 pci_di_prop_set(child, cn, INQUIRY_VENDOR_ID,
110 TOPO_STORAGE_MANUFACTURER);
111 pci_di_prop_set(child, cn, INQUIRY_PRODUCT_ID, TOPO_STORAGE_MODEL);
112 pci_di_prop_set(child, cn, INQUIRY_REVISION_ID,
113 TOPO_STORAGE_FIRMWARE_REV);
114 if (di_prop_lookup_ints(DDI_DEV_T_ANY, cn,
115 INQUIRY_DEVICE_TYPE, &val) == 1)
116 (void) topo_prop_set_int32(child, TOPO_PGROUP_STORAGE,
117 TOPO_STORAGE_DEVICE_TYPE, TOPO_PROP_IMMUTABLE, *val, &e);
118 }
119
120 static void
pci_smp_device_create(topo_mod_t * mod,nvlist_t * auth,tnode_t * parent,di_node_t cn,int instance)121 pci_smp_device_create(topo_mod_t *mod, nvlist_t *auth, tnode_t *parent,
122 di_node_t cn, int instance)
123 {
124 tnode_t *child;
125 nvlist_t *fmri;
126 int e;
127
128 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, SMP_DEVICE,
129 instance, NULL, auth, NULL, NULL, NULL);
130 if (fmri == NULL)
131 return;
132 child = topo_node_bind(mod, parent, SMP_DEVICE, instance, fmri);
133 nvlist_free(fmri);
134 if (child == NULL)
135 return;
136 if (topo_pgroup_create(child, &storage_pgroup, &e) < 0)
137 return;
138 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT,
139 TOPO_STORAGE_TARGET_PORT);
140 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT,
141 TOPO_STORAGE_ATTACHED_PORT);
142 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT_PM,
143 TOPO_STORAGE_TARGET_PORT_PM);
144 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT_PM,
145 TOPO_STORAGE_ATTACHED_PORT_PM);
146 pci_di_prop_set(child, cn, DEVID_PROP_NAME, TOPO_STORAGE_DEVID);
147 pci_di_prop_set(child, cn, INQUIRY_VENDOR_ID,
148 TOPO_STORAGE_MANUFACTURER);
149 pci_di_prop_set(child, cn, INQUIRY_PRODUCT_ID, TOPO_STORAGE_MODEL);
150 pci_di_prop_set(child, cn, INQUIRY_REVISION_ID,
151 TOPO_STORAGE_FIRMWARE_REV);
152 }
153
154 static tnode_t *
pci_iport_device_create(topo_mod_t * mod,nvlist_t * auth,tnode_t * parent,di_node_t cn,int instance)155 pci_iport_device_create(topo_mod_t *mod, nvlist_t *auth, tnode_t *parent,
156 di_node_t cn, int instance)
157 {
158 tnode_t *child;
159 nvlist_t *fmri;
160 int e;
161
162 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, IPORT,
163 instance, NULL, auth, NULL, NULL, NULL);
164 if (fmri == NULL)
165 return (NULL);
166 child = topo_node_bind(mod, parent, IPORT, instance, fmri);
167 nvlist_free(fmri);
168 if (child == NULL)
169 return (NULL);
170 if (topo_pgroup_create(child, &storage_pgroup, &e) < 0)
171 return (child);
172 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_INITIATOR_PORT,
173 TOPO_STORAGE_INITIATOR_PORT);
174 (void) topo_prop_set_string(child, TOPO_PGROUP_STORAGE,
175 TOPO_STORAGE_INITIATOR_PORT_PM, TOPO_PROP_IMMUTABLE,
176 di_bus_addr(cn), &e);
177 return (child);
178 }
179
180 void
pci_iports_instantiate(topo_mod_t * mod,tnode_t * parent,di_node_t pn,int niports)181 pci_iports_instantiate(topo_mod_t *mod, tnode_t *parent, di_node_t pn,
182 int niports)
183 {
184 di_node_t cn, smp, sd;
185 di_path_t pi;
186 tnode_t *iport;
187 int i, j;
188 nvlist_t *auth;
189
190 if (topo_node_range_create(mod, parent, IPORT, 0, niports) < 0)
191 return;
192 auth = topo_mod_auth(mod, parent);
193 for (i = 0, cn = di_child_node(pn); cn != DI_NODE_NIL;
194 cn = di_sibling_node(cn)) {
195 /*
196 * First create any iport nodes.
197 */
198 if (strcmp(di_node_name(cn), "iport") != 0)
199 continue;
200 iport = pci_iport_device_create(mod, auth, parent, cn, i++);
201 if (iport == NULL)
202 continue;
203
204 /*
205 * Now create any scsi-device nodes.
206 */
207 for (j = 0, sd = di_child_node(cn); sd != DI_NODE_NIL;
208 sd = di_sibling_node(sd))
209 if (strcmp(di_node_name(sd), "smp") != 0)
210 j++;
211 for (pi = di_path_phci_next_path(cn, DI_PATH_NIL);
212 pi != DI_PATH_NIL; pi = di_path_phci_next_path(cn, pi))
213 if (di_path_client_node(pi) != NULL &&
214 strcmp(di_node_name(di_path_client_node(pi)),
215 "smp") != 0)
216 j++;
217 if (topo_node_range_create(mod, iport, SCSI_DEVICE, 0, j) < 0)
218 continue;
219 for (j = 0, sd = di_child_node(cn); sd != DI_NODE_NIL;
220 sd = di_sibling_node(sd))
221 if (strcmp(di_node_name(sd), "smp") != 0)
222 pci_scsi_device_create(mod, auth, iport, sd,
223 j++, NULL);
224 for (pi = di_path_phci_next_path(cn, DI_PATH_NIL);
225 pi != DI_PATH_NIL; pi = di_path_phci_next_path(cn, pi))
226 if (di_path_client_node(pi) != NULL &&
227 strcmp(di_node_name(di_path_client_node(pi)),
228 "smp") != 0)
229 pci_scsi_device_create(mod, auth, iport,
230 di_path_client_node(pi), j++, pi);
231
232 /*
233 * Now create any smp-device nodes.
234 */
235 for (j = 0, smp = di_child_node(cn); smp != DI_NODE_NIL;
236 smp = di_sibling_node(smp))
237 if (strcmp(di_node_name(smp), "smp") == 0)
238 j++;
239 if (topo_node_range_create(mod, iport, SMP_DEVICE, 0, j) < 0)
240 continue;
241 for (j = 0, smp = di_child_node(cn); smp != DI_NODE_NIL;
242 smp = di_sibling_node(smp))
243 if (strcmp(di_node_name(smp), "smp") == 0)
244 pci_smp_device_create(mod, auth, iport, smp,
245 j++);
246 }
247 nvlist_free(auth);
248 }
249
250 void
pci_receptacle_instantiate(topo_mod_t * mod,tnode_t * parent,di_node_t pnode)251 pci_receptacle_instantiate(topo_mod_t *mod, tnode_t *parent, di_node_t pnode)
252 {
253 int err, i, rcnt, lcnt;
254 char *propstrpm, *propstrlabel, *pm, *label;
255 nvlist_t *fmri, *auth;
256 tnode_t *recep;
257
258 rcnt = di_prop_lookup_strings(DDI_DEV_T_ANY, pnode,
259 DI_RECEPTACLE_PHYMASK, &propstrpm);
260 if ((lcnt = di_prop_lookup_strings(DDI_DEV_T_ANY, pnode,
261 DI_RECEPTACLE_LABEL, &propstrlabel)) <= 0) {
262 topo_mod_dprintf(mod,
263 "pci_receptacle_instanciate: rececptacle label not "
264 "found for the pci function node.\n");
265 return;
266 }
267
268 if (rcnt != lcnt) {
269 topo_mod_dprintf(mod,
270 "pci_receptacle_instantiate: rececptacle label count %d "
271 "doesn match with phy mask count %d\n", lcnt, rcnt);
272 }
273
274 label = propstrlabel;
275 pm = propstrpm;
276 auth = topo_mod_auth(mod, parent);
277 for (i = 0; i < rcnt; i++) {
278 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION,
279 RECEPTACLE, i, NULL, auth, NULL, NULL, NULL);
280 if (fmri == NULL) {
281 topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s",
282 topo_mod_errmsg(mod));
283 continue;
284 }
285 recep = topo_node_bind(mod, parent, RECEPTACLE, i, fmri);
286 nvlist_free(fmri);
287 if (recep == NULL) {
288 topo_mod_dprintf(mod, "topo_node_bind() failed: %s",
289 topo_mod_errmsg(mod));
290 continue;
291 }
292
293 if (label) {
294 if (topo_node_label_set(recep, label, &err) < 0) {
295 topo_mod_dprintf(mod,
296 "topo_receptacle_instantiate: "
297 "topo_node_label_set error(%s)\n",
298 topo_strerror(err));
299 }
300 if (i < lcnt) {
301 label = label + strlen(label) + 1;
302 } else {
303 label = NULL;
304 }
305 }
306
307 if (topo_pgroup_create(recep, &storage_pgroup, &err) < 0) {
308 topo_mod_dprintf(mod, "ses_set_expander_props: "
309 "create storage error %s\n", topo_strerror(err));
310 continue;
311 }
312 (void) topo_prop_set_string(recep, TOPO_PGROUP_STORAGE,
313 TOPO_STORAGE_SAS_PHY_MASK,
314 TOPO_PROP_IMMUTABLE, pm, &err);
315 pm = pm + strlen(pm) + 1;
316 }
317
318 nvlist_free(auth);
319 }
320