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