xref: /illumos-gate/usr/src/lib/fm/topo/modules/common/pcibus/pcibus_hba.c (revision cd3e933325e68e23516a196a8fea7f49b1e497c3)
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
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
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
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
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 *
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
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 (strcmp(di_node_name(di_path_client_node(pi)),
214 			    "smp") != 0)
215 				j++;
216 		if (topo_node_range_create(mod, iport, SCSI_DEVICE, 0, j) < 0)
217 			continue;
218 		for (j = 0, sd = di_child_node(cn); sd != DI_NODE_NIL;
219 		    sd = di_sibling_node(sd))
220 			if (strcmp(di_node_name(sd), "smp") != 0)
221 				pci_scsi_device_create(mod, auth, iport, sd,
222 				    j++, NULL);
223 		for (pi = di_path_phci_next_path(cn, DI_PATH_NIL);
224 		    pi != DI_PATH_NIL; pi = di_path_phci_next_path(cn, pi))
225 			if (strcmp(di_node_name(di_path_client_node(pi)),
226 			    "smp") != 0)
227 				pci_scsi_device_create(mod, auth, iport,
228 				    di_path_client_node(pi),  j++, pi);
229 
230 		/*
231 		 * Now create any smp-device nodes.
232 		 */
233 		for (j = 0, smp = di_child_node(cn); smp != DI_NODE_NIL;
234 		    smp = di_sibling_node(smp))
235 			if (strcmp(di_node_name(smp), "smp") == 0)
236 				j++;
237 		if (topo_node_range_create(mod, iport, SMP_DEVICE, 0, j) < 0)
238 			continue;
239 		for (j = 0, smp = di_child_node(cn); smp != DI_NODE_NIL;
240 		    smp = di_sibling_node(smp))
241 			if (strcmp(di_node_name(smp), "smp") == 0)
242 				pci_smp_device_create(mod, auth, iport, smp,
243 				    j++);
244 	}
245 	nvlist_free(auth);
246 }
247 
248 void
249 pci_receptacle_instantiate(topo_mod_t *mod, tnode_t *parent, di_node_t pnode)
250 {
251 	int err, i, rcnt, lcnt;
252 	char *propstrpm, *propstrlabel, *pm, *label;
253 	nvlist_t *fmri, *auth;
254 	tnode_t	*recep;
255 
256 	rcnt = di_prop_lookup_strings(DDI_DEV_T_ANY, pnode,
257 	    DI_RECEPTACLE_PHYMASK, &propstrpm);
258 	if ((lcnt = di_prop_lookup_strings(DDI_DEV_T_ANY, pnode,
259 	    DI_RECEPTACLE_LABEL, &propstrlabel)) <= 0) {
260 		topo_mod_dprintf(mod,
261 		    "pci_receptacle_instanciate: rececptacle label not "
262 		    "found for the pci function node.\n");
263 		return;
264 	}
265 
266 	if (rcnt != lcnt) {
267 		topo_mod_dprintf(mod,
268 		    "pci_receptacle_instantiate: rececptacle label count %d "
269 		    "doesn match with phy mask count %d\n", lcnt, rcnt);
270 	}
271 
272 	label = propstrlabel;
273 	pm = propstrpm;
274 	auth = topo_mod_auth(mod, parent);
275 	for (i = 0; i < rcnt; i++) {
276 		fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION,
277 		    RECEPTACLE, i, NULL, auth, NULL, NULL, NULL);
278 		if (fmri == NULL) {
279 			topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s",
280 			    topo_mod_errmsg(mod));
281 			continue;
282 		}
283 		recep = topo_node_bind(mod, parent, RECEPTACLE, i, fmri);
284 		nvlist_free(fmri);
285 		if (recep == NULL) {
286 			topo_mod_dprintf(mod, "topo_node_bind() failed: %s",
287 			    topo_mod_errmsg(mod));
288 			continue;
289 		}
290 
291 		if (label) {
292 			if (topo_node_label_set(recep, label, &err) < 0) {
293 				topo_mod_dprintf(mod,
294 				    "topo_receptacle_instantiate: "
295 				    "topo_node_label_set error(%s)\n",
296 				    topo_strerror(err));
297 			}
298 			if (i < lcnt) {
299 				label = label + strlen(label) + 1;
300 			} else {
301 				label = NULL;
302 			}
303 		}
304 
305 		if (topo_pgroup_create(recep, &storage_pgroup, &err) < 0) {
306 			topo_mod_dprintf(mod, "ses_set_expander_props: "
307 			    "create storage error %s\n", topo_strerror(err));
308 			continue;
309 		}
310 		(void) topo_prop_set_string(recep, TOPO_PGROUP_STORAGE,
311 		    TOPO_STORAGE_SAS_PHY_MASK,
312 		    TOPO_PROP_IMMUTABLE, pm, &err);
313 		pm = pm + strlen(pm) + 1;
314 	}
315 
316 	nvlist_free(auth);
317 }
318