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