xref: /titanic_44/usr/src/cmd/oplhpd/scf_notify.c (revision 09300c80acaa63e6014b47c990368f7a81638c0d)
1a4ac8bb3Sdnielsen /*
2a4ac8bb3Sdnielsen  * CDDL HEADER START
3a4ac8bb3Sdnielsen  *
4a4ac8bb3Sdnielsen  * The contents of this file are subject to the terms of the
5a4ac8bb3Sdnielsen  * Common Development and Distribution License (the "License").
6a4ac8bb3Sdnielsen  * You may not use this file except in compliance with the License.
7a4ac8bb3Sdnielsen  *
8a4ac8bb3Sdnielsen  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a4ac8bb3Sdnielsen  * or http://www.opensolaris.org/os/licensing.
10a4ac8bb3Sdnielsen  * See the License for the specific language governing permissions
11a4ac8bb3Sdnielsen  * and limitations under the License.
12a4ac8bb3Sdnielsen  *
13a4ac8bb3Sdnielsen  * When distributing Covered Code, include this CDDL HEADER in each
14a4ac8bb3Sdnielsen  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a4ac8bb3Sdnielsen  * If applicable, add the following below this CDDL HEADER, with the
16a4ac8bb3Sdnielsen  * fields enclosed by brackets "[]" replaced with your own identifying
17a4ac8bb3Sdnielsen  * information: Portions Copyright [yyyy] [name of copyright owner]
18a4ac8bb3Sdnielsen  *
19a4ac8bb3Sdnielsen  * CDDL HEADER END
20a4ac8bb3Sdnielsen  */
21a4ac8bb3Sdnielsen /*
22a4ac8bb3Sdnielsen  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23a4ac8bb3Sdnielsen  * Use is subject to license terms.
24a4ac8bb3Sdnielsen  */
25a4ac8bb3Sdnielsen 
26a4ac8bb3Sdnielsen #pragma ident	"%Z%%M%	%I%	%E% SMI"
27a4ac8bb3Sdnielsen 
28a4ac8bb3Sdnielsen #include <stdio.h>
29a4ac8bb3Sdnielsen #include <stdlib.h>
30a4ac8bb3Sdnielsen #include <fcntl.h>
31a4ac8bb3Sdnielsen #include <config_admin.h>
32a4ac8bb3Sdnielsen #include <strings.h>
33a4ac8bb3Sdnielsen #include <syslog.h>
34a4ac8bb3Sdnielsen #include <libsysevent.h>
35a4ac8bb3Sdnielsen #include <libdevinfo.h>
36a4ac8bb3Sdnielsen #include <libnvpair.h>
37a4ac8bb3Sdnielsen #include <assert.h>
38a4ac8bb3Sdnielsen #include <errno.h>
39a4ac8bb3Sdnielsen #include <unistd.h>
40a4ac8bb3Sdnielsen #include <stropts.h>
41a4ac8bb3Sdnielsen #include <sys/types.h>
42a4ac8bb3Sdnielsen #include <sys/stat.h>
43a4ac8bb3Sdnielsen #include <sys/sysevent/dr.h>
44a4ac8bb3Sdnielsen #include <sys/scfd/opcio.h>
45a4ac8bb3Sdnielsen 
46a4ac8bb3Sdnielsen 
47a4ac8bb3Sdnielsen /* Macros */
48a4ac8bb3Sdnielsen #define	SCF_DEV_DIR  "/devices"	/* device base dir */
49a4ac8bb3Sdnielsen 
50a4ac8bb3Sdnielsen 
51a4ac8bb3Sdnielsen 
52a4ac8bb3Sdnielsen /*
53a4ac8bb3Sdnielsen  * Connection for SCF driver
54a4ac8bb3Sdnielsen  */
55a4ac8bb3Sdnielsen 
56a4ac8bb3Sdnielsen /* Check the availability of SCF driver */
57a4ac8bb3Sdnielsen static int	scfdrv_enable = 0;
58a4ac8bb3Sdnielsen 
59a4ac8bb3Sdnielsen 
60a4ac8bb3Sdnielsen /* Device for SCF Driver */
61a4ac8bb3Sdnielsen #define	SCFIOCDEV	"/devices/pseudo/scfd@200:rasctl"
62a4ac8bb3Sdnielsen #define	SCFRETRY	10
63a4ac8bb3Sdnielsen #define	SCFIOCWAIT	3
64a4ac8bb3Sdnielsen #define	SCFDATA_DEV_INFO	32
65a4ac8bb3Sdnielsen #define	SCFDATA_APID    1054
66a4ac8bb3Sdnielsen 
67a4ac8bb3Sdnielsen /*
68a4ac8bb3Sdnielsen  * Data for XSCF
69a4ac8bb3Sdnielsen  * Note the size of the ap_id must be SCFDATA_APID for proper data alignment
70a4ac8bb3Sdnielsen  * for the ioctl. The SCF has a corresponding data structure which is matched
71a4ac8bb3Sdnielsen  * here.
72a4ac8bb3Sdnielsen  */
73a4ac8bb3Sdnielsen typedef struct {
74a4ac8bb3Sdnielsen 	char		ap_id[SCFDATA_APID];
75a4ac8bb3Sdnielsen 	uint8_t		ioua;
76a4ac8bb3Sdnielsen 	uint8_t		vflag;
77a4ac8bb3Sdnielsen 	uint32_t	r_state;
78a4ac8bb3Sdnielsen 	uint32_t	o_state;
79a4ac8bb3Sdnielsen 	uint64_t	tstamp;
80a4ac8bb3Sdnielsen 	char		dev_name[SCFDATA_DEV_INFO];
81a4ac8bb3Sdnielsen 	char		dev_model[SCFDATA_DEV_INFO];
82a4ac8bb3Sdnielsen } scf_slotinfo_t;
83a4ac8bb3Sdnielsen 
84a4ac8bb3Sdnielsen /*
85a4ac8bb3Sdnielsen  * Data for scf notification of state changes.
86a4ac8bb3Sdnielsen  * pci_name is an ap_id phys path for the hot pluggable pci device.
87a4ac8bb3Sdnielsen  * r_state is the recepticle state.
88a4ac8bb3Sdnielsen  * o_state is the occupant state.
89a4ac8bb3Sdnielsen  * cache_fmri_str is a string representation of an fmri in the rsrc cache.
90a4ac8bb3Sdnielsen  * fmri_asru_str is the asru for an fmri which is found in the topology.
91a4ac8bb3Sdnielsen  * found is a boolean indicating whether the device was found in the topology.
92a4ac8bb3Sdnielsen  */
93a4ac8bb3Sdnielsen typedef struct {
94a4ac8bb3Sdnielsen 	char		pci_name[MAXPATHLEN];
95a4ac8bb3Sdnielsen 	uint32_t	r_state;
96a4ac8bb3Sdnielsen 	uint32_t	o_state;
97a4ac8bb3Sdnielsen } pci_notify_t;
98a4ac8bb3Sdnielsen 
99a4ac8bb3Sdnielsen /*
100a4ac8bb3Sdnielsen  * Function Prototypes
101a4ac8bb3Sdnielsen  */
102a4ac8bb3Sdnielsen void scf_get_slotinfo(char *ap_id, cfga_stat_t *o_state,
103a4ac8bb3Sdnielsen 		cfga_stat_t *r_state);
104a4ac8bb3Sdnielsen static int scf_get_pci_name(const char *ap_phys_id, char *pci_name);
105a4ac8bb3Sdnielsen static int scf_get_devinfo(char *dev_name, char *dev_model,
106a4ac8bb3Sdnielsen 		const char *pci_name);
107a4ac8bb3Sdnielsen void notify_scf_of_hotplug(sysevent_t *ev);
108a4ac8bb3Sdnielsen 
109a4ac8bb3Sdnielsen 
110a4ac8bb3Sdnielsen /*
111a4ac8bb3Sdnielsen  * Error report utility for libcfgadm functions
112a4ac8bb3Sdnielsen  */
113a4ac8bb3Sdnielsen void
114a4ac8bb3Sdnielsen config_error(cfga_err_t err, const char *func_name, const char *errstr,
115a4ac8bb3Sdnielsen     const char *ap_id)
116a4ac8bb3Sdnielsen {
117a4ac8bb3Sdnielsen 	const char *ep;
118a4ac8bb3Sdnielsen 
119a4ac8bb3Sdnielsen 	ep = config_strerror(err);
120a4ac8bb3Sdnielsen 	if (ep == NULL) {
121a4ac8bb3Sdnielsen 		ep = "configuration administration unknown error";
122a4ac8bb3Sdnielsen 	}
123a4ac8bb3Sdnielsen 
124a4ac8bb3Sdnielsen 	if (errstr != NULL && *errstr != '\0') {
125a4ac8bb3Sdnielsen 		syslog(LOG_DEBUG, "%s: %s (%s), ap_id = %s\n",
126a4ac8bb3Sdnielsen 				func_name, ep, errstr, ap_id);
127a4ac8bb3Sdnielsen 	} else {
128a4ac8bb3Sdnielsen 		syslog(LOG_DEBUG, "%s: %s , ap_id = %s\n",
129a4ac8bb3Sdnielsen 				func_name, ep, ap_id);
130a4ac8bb3Sdnielsen 	}
131a4ac8bb3Sdnielsen 
132a4ac8bb3Sdnielsen }
133a4ac8bb3Sdnielsen 
134a4ac8bb3Sdnielsen /*
135a4ac8bb3Sdnielsen  * Get the slot status.
136a4ac8bb3Sdnielsen  */
137a4ac8bb3Sdnielsen void
138a4ac8bb3Sdnielsen scf_get_slotinfo(char *ap_pid, cfga_stat_t *r_state, cfga_stat_t *o_state)
139a4ac8bb3Sdnielsen {
140a4ac8bb3Sdnielsen 	cfga_err_t		rv;		/* return value */
141a4ac8bb3Sdnielsen 	cfga_list_data_t	*stat = NULL;	/* slot info. */
142a4ac8bb3Sdnielsen 	int			nlist;		/* number of slot */
143a4ac8bb3Sdnielsen 	char			*errstr = NULL;	/* error code */
144a4ac8bb3Sdnielsen 
145a4ac8bb3Sdnielsen 	/*
146a4ac8bb3Sdnielsen 	 * Get the attachment point information.
147a4ac8bb3Sdnielsen 	 */
148a4ac8bb3Sdnielsen 	rv = config_list_ext(1, (char *const *)&ap_pid, &stat, &nlist, NULL,
149a4ac8bb3Sdnielsen 		NULL, &errstr, 0);
150a4ac8bb3Sdnielsen 
151a4ac8bb3Sdnielsen 	if (rv != CFGA_OK) {
152a4ac8bb3Sdnielsen 		config_error(rv, "config_list_ext", errstr, ap_pid);
153a4ac8bb3Sdnielsen 		goto out;
154a4ac8bb3Sdnielsen 	}
155a4ac8bb3Sdnielsen 	assert(nlist == 1);
156a4ac8bb3Sdnielsen 
157a4ac8bb3Sdnielsen 	syslog(LOG_DEBUG, "\n"
158a4ac8bb3Sdnielsen 			"ap_log_id       = %.*s\n"
159a4ac8bb3Sdnielsen 			"ap_phys_id      = %.*s\n"
160a4ac8bb3Sdnielsen 			"ap_r_state      = %d\n"
161a4ac8bb3Sdnielsen 			"ap_o_state      = %d\n"
162a4ac8bb3Sdnielsen 			"ap_cond         = %d\n"
163a4ac8bb3Sdnielsen 			"ap_busy         = %6d\n"
164a4ac8bb3Sdnielsen 			"ap_status_time  = %s"
165a4ac8bb3Sdnielsen 			"ap_info         = %.*s\n"
166a4ac8bb3Sdnielsen 			"ap_type         = %.*s\n",
167a4ac8bb3Sdnielsen 			sizeof (stat->ap_log_id), stat->ap_log_id,
168a4ac8bb3Sdnielsen 			sizeof (stat->ap_phys_id), stat->ap_phys_id,
169a4ac8bb3Sdnielsen 			stat->ap_r_state,
170a4ac8bb3Sdnielsen 			stat->ap_o_state,
171a4ac8bb3Sdnielsen 			stat->ap_cond,
172a4ac8bb3Sdnielsen 			stat->ap_busy,
173a4ac8bb3Sdnielsen 			asctime(localtime(&stat->ap_status_time)),
174a4ac8bb3Sdnielsen 			sizeof (stat->ap_info), stat->ap_info,
175a4ac8bb3Sdnielsen 			sizeof (stat->ap_type), stat->ap_type);
176a4ac8bb3Sdnielsen 
177a4ac8bb3Sdnielsen 	/* Copy the slot status. */
178a4ac8bb3Sdnielsen 	*r_state = stat->ap_r_state;
179a4ac8bb3Sdnielsen 	*o_state = stat->ap_o_state;
180a4ac8bb3Sdnielsen 
181a4ac8bb3Sdnielsen out:
182a4ac8bb3Sdnielsen 	if (stat) {
183a4ac8bb3Sdnielsen 		free(stat);
184a4ac8bb3Sdnielsen 	}
185a4ac8bb3Sdnielsen 
186a4ac8bb3Sdnielsen 	if (errstr) {
187a4ac8bb3Sdnielsen 		free(errstr);
188a4ac8bb3Sdnielsen 	}
189a4ac8bb3Sdnielsen }
190a4ac8bb3Sdnielsen 
191a4ac8bb3Sdnielsen 
192a4ac8bb3Sdnielsen /*
193a4ac8bb3Sdnielsen  * Get the pci_name
194a4ac8bb3Sdnielsen  */
195a4ac8bb3Sdnielsen static int
196a4ac8bb3Sdnielsen scf_get_pci_name(const char *ap_phys_id, char *pci_name)
197a4ac8bb3Sdnielsen {
198a4ac8bb3Sdnielsen 	char		*pci_name_ptr;  /* pci node name pointer */
199a4ac8bb3Sdnielsen 	char		*ap_lid_ptr;    /* logical ap_id pointer */
200a4ac8bb3Sdnielsen 
201a4ac8bb3Sdnielsen 	int		devices_len;	/* "/device" length */
202a4ac8bb3Sdnielsen 	int		pci_name_len;	/* pci node name length */
203a4ac8bb3Sdnielsen 	int		ap_lid_len;	/* logical ap_id pointer */
204a4ac8bb3Sdnielsen 
205a4ac8bb3Sdnielsen 
206a4ac8bb3Sdnielsen 	/*
207a4ac8bb3Sdnielsen 	 * Pick pci node name up from physical ap_id string.
208a4ac8bb3Sdnielsen 	 * "/devices/pci@XX,YYYYYY:PCI#ZZ"
209a4ac8bb3Sdnielsen 	 */
210a4ac8bb3Sdnielsen 
211a4ac8bb3Sdnielsen 	/* Check the length of physical ap_id string */
212a4ac8bb3Sdnielsen 	if (strlen(ap_phys_id) >= MAXPATHLEN) {
213a4ac8bb3Sdnielsen 		return (-1); /* changed */
214a4ac8bb3Sdnielsen 	}
215a4ac8bb3Sdnielsen 
216a4ac8bb3Sdnielsen 	/* Check the pci node name start, which is after "/devices". */
217a4ac8bb3Sdnielsen 	if (strncmp(SCF_DEV_DIR, ap_phys_id, strlen(SCF_DEV_DIR)) == 0) {
218a4ac8bb3Sdnielsen 		devices_len = strlen(SCF_DEV_DIR);
219a4ac8bb3Sdnielsen 	} else {
220a4ac8bb3Sdnielsen 		devices_len = 0;
221a4ac8bb3Sdnielsen 	}
222a4ac8bb3Sdnielsen 	/* Check the pci node name end, which is before ":". */
223a4ac8bb3Sdnielsen 	if ((ap_lid_ptr = strchr(ap_phys_id, ':')) == NULL) {
224a4ac8bb3Sdnielsen 		ap_lid_len = 0;
225a4ac8bb3Sdnielsen 	} else {
226a4ac8bb3Sdnielsen 		ap_lid_len = strlen(ap_lid_ptr);
227a4ac8bb3Sdnielsen 	}
228a4ac8bb3Sdnielsen 
229a4ac8bb3Sdnielsen 	/*
230a4ac8bb3Sdnielsen 	 * Get the head of pci node name string.
231a4ac8bb3Sdnielsen 	 * Get the length of pci node name string.
232a4ac8bb3Sdnielsen 	 */
233a4ac8bb3Sdnielsen 	pci_name_ptr = (char *)ap_phys_id + devices_len;
234a4ac8bb3Sdnielsen 	pci_name_len = strlen(ap_phys_id) - devices_len - ap_lid_len;
235a4ac8bb3Sdnielsen 
236a4ac8bb3Sdnielsen 	/* Copy the pci node name. */
237a4ac8bb3Sdnielsen 	(void) strncpy(pci_name, pci_name_ptr, pci_name_len);
238a4ac8bb3Sdnielsen 	pci_name[pci_name_len] = '\0';
239a4ac8bb3Sdnielsen 
240a4ac8bb3Sdnielsen 	syslog(LOG_DEBUG, "pci device path = %s\n", pci_name);
241a4ac8bb3Sdnielsen 
242a4ac8bb3Sdnielsen 	return (0);
243a4ac8bb3Sdnielsen 
244a4ac8bb3Sdnielsen }
245a4ac8bb3Sdnielsen 
246a4ac8bb3Sdnielsen 
247a4ac8bb3Sdnielsen /*
248a4ac8bb3Sdnielsen  * Get the property of name and model.
249a4ac8bb3Sdnielsen  */
250a4ac8bb3Sdnielsen static int
251a4ac8bb3Sdnielsen scf_get_devinfo(char *dev_name, char *dev_model, const char *pci_name)
252a4ac8bb3Sdnielsen {
253a4ac8bb3Sdnielsen 	char		*tmp;		/* tmp */
254a4ac8bb3Sdnielsen 	unsigned int    devid, funcid;  /* bus addr */
255a4ac8bb3Sdnielsen 	unsigned int    sdevid, sfuncid; /* sibling bus addr */
256a4ac8bb3Sdnielsen 
257a4ac8bb3Sdnielsen 	di_node_t	pci_node;	/* pci device node */
258a4ac8bb3Sdnielsen 	di_node_t	child_node;	/* child level node */
259a4ac8bb3Sdnielsen 	di_node_t	ap_node;	/* hotplugged node */
260a4ac8bb3Sdnielsen 
261a4ac8bb3Sdnielsen 	pci_node = ap_node = DI_NODE_NIL;
262a4ac8bb3Sdnielsen 
263a4ac8bb3Sdnielsen 
264a4ac8bb3Sdnielsen 	/*
265a4ac8bb3Sdnielsen 	 * Take the snap shot of device node configuration,
266a4ac8bb3Sdnielsen 	 * to get the names of node and model.
267a4ac8bb3Sdnielsen 	 */
268a4ac8bb3Sdnielsen 	if ((pci_node = di_init(pci_name, DINFOCPYALL)) == DI_NODE_NIL) {
269a4ac8bb3Sdnielsen 		syslog(LOG_NOTICE,
270a4ac8bb3Sdnielsen 			"Could not get dev info snapshot. errno=%d\n",
271a4ac8bb3Sdnielsen 			errno);
272a4ac8bb3Sdnielsen 		return (-1); /* changed */
273a4ac8bb3Sdnielsen 	}
274a4ac8bb3Sdnielsen 
275a4ac8bb3Sdnielsen 	/*
276a4ac8bb3Sdnielsen 	 * The new child under pci node should be added. Then the
277a4ac8bb3Sdnielsen 	 * device and model names should be passed, which is in the
278a4ac8bb3Sdnielsen 	 * node with the minimum bus address.
279a4ac8bb3Sdnielsen 	 *
280a4ac8bb3Sdnielsen 	 * - Move to the child node level.
281a4ac8bb3Sdnielsen 	 * - Search the node with the minimum bus addrress in the
282a4ac8bb3Sdnielsen 	 *   sibling list.
283a4ac8bb3Sdnielsen 	 */
284a4ac8bb3Sdnielsen 	if ((child_node = di_child_node(pci_node)) == DI_NODE_NIL) {
285a4ac8bb3Sdnielsen 		syslog(LOG_NOTICE, "No slot device in snapshot\n");
286a4ac8bb3Sdnielsen 		goto out;
287a4ac8bb3Sdnielsen 	}
288a4ac8bb3Sdnielsen 
289a4ac8bb3Sdnielsen 	ap_node = child_node;
290a4ac8bb3Sdnielsen 	if ((tmp = di_bus_addr(child_node)) != NULL) {
291a4ac8bb3Sdnielsen 		if (sscanf(tmp, "%x,%x", &devid, &funcid) != 2) {
292a4ac8bb3Sdnielsen 			funcid = 0;
293a4ac8bb3Sdnielsen 			if (sscanf(tmp, "%x", &devid) != 1) {
294a4ac8bb3Sdnielsen 				devid = 0;
295a4ac8bb3Sdnielsen 				syslog(LOG_DEBUG,
296a4ac8bb3Sdnielsen 					"no bus addrress on device\n");
297a4ac8bb3Sdnielsen 				goto one_child;
298a4ac8bb3Sdnielsen 			}
299a4ac8bb3Sdnielsen 		}
300a4ac8bb3Sdnielsen 	}
301a4ac8bb3Sdnielsen 
302a4ac8bb3Sdnielsen 	while ((child_node = di_sibling_node(child_node)) != NULL) {
303a4ac8bb3Sdnielsen 		if ((tmp = di_bus_addr(child_node)) == NULL) {
304a4ac8bb3Sdnielsen 			ap_node = child_node;
305a4ac8bb3Sdnielsen 			break;
306a4ac8bb3Sdnielsen 		}
307a4ac8bb3Sdnielsen 
308a4ac8bb3Sdnielsen 		if (sscanf(tmp, "%x,%x", &sdevid, &sfuncid) == 2) {
309a4ac8bb3Sdnielsen 			/*
310a4ac8bb3Sdnielsen 			 * We do need to update the child node
311a4ac8bb3Sdnielsen 			 *   Case 1. devid > sdevid
312a4ac8bb3Sdnielsen 			 *   Case 2. devid == sdevid && funcid > sfuncid
313a4ac8bb3Sdnielsen 			 */
314a4ac8bb3Sdnielsen 			if ((devid > sdevid) || ((devid == sdevid) &&
315a4ac8bb3Sdnielsen 					(funcid > sfuncid))) {
316a4ac8bb3Sdnielsen 				ap_node = child_node;
317a4ac8bb3Sdnielsen 				devid   = sdevid;
318a4ac8bb3Sdnielsen 				funcid  = sfuncid;
319a4ac8bb3Sdnielsen 			}
320a4ac8bb3Sdnielsen 
321a4ac8bb3Sdnielsen 		} else if (sscanf(tmp, "%x", &sdevid) == 1) {
322a4ac8bb3Sdnielsen 			/*
323a4ac8bb3Sdnielsen 			 * We do need to update the child node
324a4ac8bb3Sdnielsen 			 *   Case 1. devid >= sdevid
325a4ac8bb3Sdnielsen 			 */
326a4ac8bb3Sdnielsen 			if (devid >= sdevid) {
327a4ac8bb3Sdnielsen 				ap_node = child_node;
328a4ac8bb3Sdnielsen 				devid   = sdevid;
329a4ac8bb3Sdnielsen 				funcid  = 0;
330a4ac8bb3Sdnielsen 			}
331a4ac8bb3Sdnielsen 
332a4ac8bb3Sdnielsen 		} else {
333a4ac8bb3Sdnielsen 			ap_node = child_node;
334a4ac8bb3Sdnielsen 			break;
335a4ac8bb3Sdnielsen 		}
336a4ac8bb3Sdnielsen 	}
337a4ac8bb3Sdnielsen 
338a4ac8bb3Sdnielsen one_child:
339a4ac8bb3Sdnielsen 	/*
340a4ac8bb3Sdnielsen 	 * Get the name and model properties.
341a4ac8bb3Sdnielsen 	 */
342a4ac8bb3Sdnielsen 	tmp = di_node_name(ap_node);
343a4ac8bb3Sdnielsen 	if (tmp != NULL) {
344a4ac8bb3Sdnielsen 		(void) strlcpy((char *)dev_name, tmp, SCFDATA_DEV_INFO);
345a4ac8bb3Sdnielsen 	}
346a4ac8bb3Sdnielsen 
347a4ac8bb3Sdnielsen 	tmp = NULL;
348a4ac8bb3Sdnielsen 	if (di_prop_lookup_strings(DDI_DEV_T_ANY, ap_node, "model", &tmp) > 0) {
349a4ac8bb3Sdnielsen 		if (tmp != NULL) {
350a4ac8bb3Sdnielsen 			(void) strlcpy((char *)dev_model, tmp,
351a4ac8bb3Sdnielsen 						SCFDATA_DEV_INFO);
352a4ac8bb3Sdnielsen 		}
353a4ac8bb3Sdnielsen 	}
354a4ac8bb3Sdnielsen 
355a4ac8bb3Sdnielsen 	syslog(LOG_DEBUG, "device: %s@%x,%x [model: %s]\n",
356a4ac8bb3Sdnielsen 		dev_name, devid, funcid, dev_model);
357a4ac8bb3Sdnielsen 
358a4ac8bb3Sdnielsen out:
359a4ac8bb3Sdnielsen 	di_fini(pci_node);
360a4ac8bb3Sdnielsen 	return (0); /* added */
361a4ac8bb3Sdnielsen }
362a4ac8bb3Sdnielsen 
363a4ac8bb3Sdnielsen 
364a4ac8bb3Sdnielsen void
365a4ac8bb3Sdnielsen notify_scf_of_hotplug(sysevent_t *ev)
366a4ac8bb3Sdnielsen {
367a4ac8bb3Sdnielsen 	int		rc;			/* return code */
368a4ac8bb3Sdnielsen 
369a4ac8bb3Sdnielsen 	/* For libsysevent */
370a4ac8bb3Sdnielsen 	char		*vendor = NULL;		/* event vendor */
371a4ac8bb3Sdnielsen 	char		*publisher = NULL;	/* event publisher */
372a4ac8bb3Sdnielsen 	nvlist_t	*ev_attr_list = NULL;	/* attribute */
373a4ac8bb3Sdnielsen 
374a4ac8bb3Sdnielsen 	/* For libcfgadm */
375a4ac8bb3Sdnielsen 	char		*ap_id = NULL;		/* attachment point */
376a4ac8bb3Sdnielsen 	cfga_stat_t	r_state, o_state;	/* slot status */
377a4ac8bb3Sdnielsen 
378a4ac8bb3Sdnielsen 	/* For libdevinfo */
379a4ac8bb3Sdnielsen 	char		dev_name[SCFDATA_DEV_INFO];	/* name property */
380a4ac8bb3Sdnielsen 	char		dev_model[SCFDATA_DEV_INFO];	/* model property */
381a4ac8bb3Sdnielsen 
382a4ac8bb3Sdnielsen 	/* Data for SCF */
383a4ac8bb3Sdnielsen 	pci_notify_t pci_notify_dev_info;
384a4ac8bb3Sdnielsen 	scfsetphpinfo_t scfdata;
385a4ac8bb3Sdnielsen 	scf_slotinfo_t  sdata;
386a4ac8bb3Sdnielsen 	time_t sec;			/* hotplug event current time */
387a4ac8bb3Sdnielsen 	int		fd, retry = 0;
388a4ac8bb3Sdnielsen 
389a4ac8bb3Sdnielsen 
390a4ac8bb3Sdnielsen 	/*
391a4ac8bb3Sdnielsen 	 * Initialization
392a4ac8bb3Sdnielsen 	 */
393a4ac8bb3Sdnielsen 	r_state = o_state = 0;
394a4ac8bb3Sdnielsen 	dev_name[0] = dev_model[0] = '\0';
395a4ac8bb3Sdnielsen 	(void) memset((void *)&pci_notify_dev_info, 0, sizeof (pci_notify_t));
396a4ac8bb3Sdnielsen 
397a4ac8bb3Sdnielsen 	/* Get the current time when event picked up. */
398a4ac8bb3Sdnielsen 	sec = time(NULL);
399a4ac8bb3Sdnielsen 
400a4ac8bb3Sdnielsen 	/*
401a4ac8bb3Sdnielsen 	 * Check the vendor and publisher name of event.
402a4ac8bb3Sdnielsen 	 */
403a4ac8bb3Sdnielsen 	vendor = sysevent_get_vendor_name(ev);
404a4ac8bb3Sdnielsen 	publisher = sysevent_get_pub_name(ev);
405a4ac8bb3Sdnielsen 	/* Check the vendor is "SUNW" */
406a4ac8bb3Sdnielsen 	if (strncmp("SUNW", vendor, strlen("SUNW")) != 0) {
407a4ac8bb3Sdnielsen 		/* Just return when not from SUNW */
408a4ac8bb3Sdnielsen 		syslog(LOG_DEBUG, "Event is not a SUNW vendor event\n");
409a4ac8bb3Sdnielsen 		goto out;
410a4ac8bb3Sdnielsen 	}
411a4ac8bb3Sdnielsen 
412a4ac8bb3Sdnielsen 	/* Enough to check "px" at the beginning of string */
413a4ac8bb3Sdnielsen 	if (strncmp("px", publisher, strlen("px")) != 0) {
414a4ac8bb3Sdnielsen 		/* Just return when not px event */
415a4ac8bb3Sdnielsen 		syslog(LOG_DEBUG, "Event is not a px publisher event\n");
416a4ac8bb3Sdnielsen 		goto out;
417a4ac8bb3Sdnielsen 	}
418a4ac8bb3Sdnielsen 
419a4ac8bb3Sdnielsen 	/*
420a4ac8bb3Sdnielsen 	 * Get attribute values of attachment point.
421a4ac8bb3Sdnielsen 	 */
422a4ac8bb3Sdnielsen 	if (sysevent_get_attr_list(ev, &ev_attr_list) != 0) {
423a4ac8bb3Sdnielsen 		/* could not get attribute list */
424a4ac8bb3Sdnielsen 		syslog(LOG_DEBUG, "Could not get attribute list\n");
425a4ac8bb3Sdnielsen 		goto out;
426a4ac8bb3Sdnielsen 	}
427a4ac8bb3Sdnielsen 	if (nvlist_lookup_string(ev_attr_list, DR_AP_ID, &ap_id) != 0) {
428a4ac8bb3Sdnielsen 		/* could not find the attribute from the list */
429a4ac8bb3Sdnielsen 		syslog(LOG_DEBUG, "Could not get ap_id in attribute list\n");
430a4ac8bb3Sdnielsen 		goto out;
431a4ac8bb3Sdnielsen 	}
432a4ac8bb3Sdnielsen 
433a4ac8bb3Sdnielsen 	if (ap_id == NULL || strlen(ap_id) == 0) {
434a4ac8bb3Sdnielsen 		syslog(LOG_DEBUG, "ap_id is NULL\n");
435a4ac8bb3Sdnielsen 		goto out;
436a4ac8bb3Sdnielsen 	} else {
437a4ac8bb3Sdnielsen 		/*
438a4ac8bb3Sdnielsen 		 * Get the slot status.
439a4ac8bb3Sdnielsen 		 */
440a4ac8bb3Sdnielsen 		syslog(LOG_DEBUG, "ap_id = %s\n", ap_id);
441a4ac8bb3Sdnielsen 		scf_get_slotinfo(ap_id, &r_state, &o_state);
442a4ac8bb3Sdnielsen 	}
443a4ac8bb3Sdnielsen 
444a4ac8bb3Sdnielsen 	syslog(LOG_DEBUG, "r_state = %d\n", r_state);
445a4ac8bb3Sdnielsen 	syslog(LOG_DEBUG, "o_state = %d\n", o_state);
446a4ac8bb3Sdnielsen 
447a4ac8bb3Sdnielsen 	/*
448a4ac8bb3Sdnielsen 	 * Get the pci name which is needed for both the configure and
449a4ac8bb3Sdnielsen 	 * unconfigure.
450a4ac8bb3Sdnielsen 	 */
451a4ac8bb3Sdnielsen 	rc = scf_get_pci_name(ap_id, (char *)pci_notify_dev_info.pci_name);
452a4ac8bb3Sdnielsen 	if (rc != 0) {
453a4ac8bb3Sdnielsen 		goto out;
454a4ac8bb3Sdnielsen 	}
455a4ac8bb3Sdnielsen 
456a4ac8bb3Sdnielsen 	/*
457a4ac8bb3Sdnielsen 	 * Event for configure case only,
458a4ac8bb3Sdnielsen 	 * Get the name and model property
459a4ac8bb3Sdnielsen 	 */
460a4ac8bb3Sdnielsen 	if (o_state == CFGA_STAT_CONFIGURED) {
461a4ac8bb3Sdnielsen 		rc = scf_get_devinfo(dev_name, dev_model,
462a4ac8bb3Sdnielsen 			(char *)pci_notify_dev_info.pci_name);
463a4ac8bb3Sdnielsen 		if (rc != 0) {
464a4ac8bb3Sdnielsen 			goto out;
465a4ac8bb3Sdnielsen 		}
466a4ac8bb3Sdnielsen 	}
467a4ac8bb3Sdnielsen 	/*
468a4ac8bb3Sdnielsen 	 * Copy the data for SCF.
469a4ac8bb3Sdnielsen 	 * Initialize Data passed to SCF Driver.
470a4ac8bb3Sdnielsen 	 */
471a4ac8bb3Sdnielsen 	(void) memset(scfdata.buf, 0, sizeof (scfdata.buf));
472a4ac8bb3Sdnielsen 
473a4ac8bb3Sdnielsen 	/*
474a4ac8bb3Sdnielsen 	 * Set Data passed to SCF Driver.
475a4ac8bb3Sdnielsen 	 */
476a4ac8bb3Sdnielsen 	scfdata.size = sizeof (scf_slotinfo_t);
477a4ac8bb3Sdnielsen 	(void) strlcpy(sdata.ap_id, ap_id, sizeof (sdata.ap_id));
478a4ac8bb3Sdnielsen 
479a4ac8bb3Sdnielsen 	sdata.vflag = (uint8_t)0x80;
480a4ac8bb3Sdnielsen 	sdata.r_state  = (uint32_t)r_state;
481a4ac8bb3Sdnielsen 	sdata.o_state  = (uint32_t)o_state;
482a4ac8bb3Sdnielsen 	sdata.tstamp   = (uint64_t)sec;
483a4ac8bb3Sdnielsen 	(void) strlcpy(sdata.dev_name, dev_name, sizeof (dev_name));
484a4ac8bb3Sdnielsen 	(void) strlcpy(sdata.dev_model, dev_model, sizeof (sdata.dev_model));
485a4ac8bb3Sdnielsen 
486a4ac8bb3Sdnielsen 	(void) memcpy((void *)&(scfdata.buf), (void *)&sdata,
487a4ac8bb3Sdnielsen 			sizeof (scf_slotinfo_t));
488a4ac8bb3Sdnielsen 
489a4ac8bb3Sdnielsen 	pci_notify_dev_info.r_state	= (uint32_t)r_state;
490a4ac8bb3Sdnielsen 	pci_notify_dev_info.o_state	= (uint32_t)o_state;
491a4ac8bb3Sdnielsen 
492a4ac8bb3Sdnielsen 	if (!scfdrv_enable) {
493a4ac8bb3Sdnielsen 		scfdrv_enable = 1;
494a4ac8bb3Sdnielsen 
495a4ac8bb3Sdnielsen 		/*
496a4ac8bb3Sdnielsen 		 * Pass data to SCF driver by ioctl.
497a4ac8bb3Sdnielsen 		 */
498a4ac8bb3Sdnielsen 		if ((fd = open(SCFIOCDEV, O_WRONLY)) < 0) {
499a4ac8bb3Sdnielsen 			syslog(LOG_ERR, "open %s fail", SCFIOCDEV);
500a4ac8bb3Sdnielsen 			scfdrv_enable = 0;
501a4ac8bb3Sdnielsen 			goto out;
502a4ac8bb3Sdnielsen 		}
503a4ac8bb3Sdnielsen 
504a4ac8bb3Sdnielsen 		while (ioctl(fd, SCFIOCSETPHPINFO, scfdata) < 0) {
505*09300c80Sdnielsen 			/* retry a few times for EBUSY and EIO */
506*09300c80Sdnielsen 			if ((++retry <= SCFRETRY) &&
507*09300c80Sdnielsen 			    ((errno == EBUSY) || (errno == EIO))) {
508a4ac8bb3Sdnielsen 				(void) sleep(SCFIOCWAIT);
509*09300c80Sdnielsen 				continue;
510a4ac8bb3Sdnielsen 			}
511a4ac8bb3Sdnielsen 
512*09300c80Sdnielsen 			syslog(LOG_ERR, "SCFIOCSETPHPINFO failed: %s.",
513*09300c80Sdnielsen 			    strerror(errno));
514*09300c80Sdnielsen 			break;
515a4ac8bb3Sdnielsen 		}
516a4ac8bb3Sdnielsen 
517a4ac8bb3Sdnielsen 		(void) close(fd);
518a4ac8bb3Sdnielsen 		scfdrv_enable = 0;
519a4ac8bb3Sdnielsen 	}
520a4ac8bb3Sdnielsen 
521a4ac8bb3Sdnielsen out:
522a4ac8bb3Sdnielsen 	if (vendor != NULL) {
523a4ac8bb3Sdnielsen 		free(vendor);
524a4ac8bb3Sdnielsen 	}
525a4ac8bb3Sdnielsen 	if (publisher != NULL) {
526a4ac8bb3Sdnielsen 		free(publisher);
527a4ac8bb3Sdnielsen 	}
528a4ac8bb3Sdnielsen 
529a4ac8bb3Sdnielsen 	if (ev_attr_list != NULL) {
530a4ac8bb3Sdnielsen 		nvlist_free(ev_attr_list);
531a4ac8bb3Sdnielsen 	}
532a4ac8bb3Sdnielsen 
533a4ac8bb3Sdnielsen }
534