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
34static const topo_pgroup_info_t storage_pgroup =
35	{ TOPO_PGROUP_STORAGE, TOPO_STABILITY_PRIVATE,
36	    TOPO_STABILITY_PRIVATE, 1 };
37
38void
39pci_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
49void
50pci_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
60static void
61pci_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
120static void
121pci_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
154static tnode_t *
155pci_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
180void
181pci_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
250void
251pci_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