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