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 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", 123a4ac8bb3Sdnielsen func_name, ep, errstr, ap_id); 124a4ac8bb3Sdnielsen } else { 125a4ac8bb3Sdnielsen syslog(LOG_DEBUG, "%s: %s , ap_id = %s\n", 126a4ac8bb3Sdnielsen func_name, ep, ap_id); 127a4ac8bb3Sdnielsen } 128a4ac8bb3Sdnielsen 129a4ac8bb3Sdnielsen } 130a4ac8bb3Sdnielsen 131a4ac8bb3Sdnielsen /* 132a4ac8bb3Sdnielsen * Get the slot status. 133a4ac8bb3Sdnielsen */ 134a4ac8bb3Sdnielsen void 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, 146a4ac8bb3Sdnielsen 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" 155a4ac8bb3Sdnielsen "ap_log_id = %.*s\n" 156a4ac8bb3Sdnielsen "ap_phys_id = %.*s\n" 157a4ac8bb3Sdnielsen "ap_r_state = %d\n" 158a4ac8bb3Sdnielsen "ap_o_state = %d\n" 159a4ac8bb3Sdnielsen "ap_cond = %d\n" 160a4ac8bb3Sdnielsen "ap_busy = %6d\n" 161a4ac8bb3Sdnielsen "ap_status_time = %s" 162a4ac8bb3Sdnielsen "ap_info = %.*s\n" 163a4ac8bb3Sdnielsen "ap_type = %.*s\n", 164a4ac8bb3Sdnielsen sizeof (stat->ap_log_id), stat->ap_log_id, 165a4ac8bb3Sdnielsen sizeof (stat->ap_phys_id), stat->ap_phys_id, 166a4ac8bb3Sdnielsen stat->ap_r_state, 167a4ac8bb3Sdnielsen stat->ap_o_state, 168a4ac8bb3Sdnielsen stat->ap_cond, 169a4ac8bb3Sdnielsen stat->ap_busy, 170a4ac8bb3Sdnielsen asctime(localtime(&stat->ap_status_time)), 171a4ac8bb3Sdnielsen sizeof (stat->ap_info), stat->ap_info, 172a4ac8bb3Sdnielsen 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 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 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, 267a4ac8bb3Sdnielsen "Could not get dev info snapshot. errno=%d\n", 268a4ac8bb3Sdnielsen 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, 293a4ac8bb3Sdnielsen "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) && 312a4ac8bb3Sdnielsen (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, 348a4ac8bb3Sdnielsen SCFDATA_DEV_INFO); 349a4ac8bb3Sdnielsen } 350a4ac8bb3Sdnielsen } 351a4ac8bb3Sdnielsen 352a4ac8bb3Sdnielsen syslog(LOG_DEBUG, "device: %s@%x,%x [model: %s]\n", 353a4ac8bb3Sdnielsen dev_name, devid, funcid, dev_model); 354a4ac8bb3Sdnielsen 355a4ac8bb3Sdnielsen out: 356a4ac8bb3Sdnielsen di_fini(pci_node); 357a4ac8bb3Sdnielsen return (0); /* added */ 358a4ac8bb3Sdnielsen } 359a4ac8bb3Sdnielsen 360a4ac8bb3Sdnielsen 361a4ac8bb3Sdnielsen void 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, 460a4ac8bb3Sdnielsen (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, 485a4ac8bb3Sdnielsen 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))) { 506a4ac8bb3Sdnielsen (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