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