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