#include <sys/conf.h>
#include <sys/kmem.h>
#include <sys/debug.h>
#include <sys/modctl.h>
#include <sys/autoconf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/sunndi.h>
#include <sys/ddi_impldefs.h>
#include <sys/ndi_impldefs.h>
#include <sys/ddipropdefs.h>
#include <sys/open.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/pci.h>
#include <sys/pci_impl.h>
#include <sys/devctl.h>
#include <sys/hotplug/hpcsvc.h>
#include <sys/hotplug/pci/pcicfg.h>
#include <sys/hotplug/pci/pcihp.h>
#include <sys/sysevent.h>
#include <sys/sysevent/eventdefs.h>
#include <sys/sysevent/dr.h>
#include <sys/fs/dv_node.h>
typedef enum { PCIHP_SOFT_STATE_CLOSED, PCIHP_SOFT_STATE_OPEN,
PCIHP_SOFT_STATE_OPEN_EXCL } pcihp_soft_state_t;
#define PCI_MAX_DEVS 32
#define PCIHP_DR_AP_STATE_CHANGE 0
#define PCIHP_DR_REQ 1
#define PCIHP_DR_NOOP 0
#define PCIHP_DR_BUS_CONFIGURE 1
#define PCIHP_DR_BUS_UNCONFIGURE 2
#define PCIHP_DR_SLOT_ENTER 4
#define PCIHP_DR_SLOT_EXIT 8
enum { PCIHP_BUS_INITIALIZING, PCIHP_BUS_UNCONFIGURED,
PCIHP_BUS_CONFIGURED };
typedef struct pcihp {
struct pcihp *nextp;
dev_info_t *dip;
pcihp_soft_state_t soft_state;
kmutex_t mutex;
struct pcihp_slotinfo {
hpc_slot_t slot_hdl;
ap_rstate_t rstate;
ap_ostate_t ostate;
ap_condition_t condition;
time32_t last_change;
uint32_t event_mask;
char *name;
uint_t slot_flags;
uint16_t slot_type;
uint16_t slot_capabilities;
int hs_csr_location;
kmutex_t slot_mutex;
} slotinfo[PCI_MAX_DEVS];
uint_t bus_flags;
uint_t bus_state;
uint_t slots_active;
} pcihp_t;
#define PCIHP_SLOT_AUTO_CFG_EN 0x1
#define PCIHP_SLOT_DISABLED 0x2
#define PCIHP_SLOT_NOT_HEALTHY 0x4
#define PCIHP_SLOT_DEV_NON_HOTPLUG 0x8
#define PCIHP_SLOT_ENUM_INS_PENDING 0x10
#define PCIHP_SLOT_ENUM_EXT_PENDING 0x20
#define PCIHP_BUS_66MHZ 0x1
#define PCIHP_BUS_ENUM_RADIAL 0x2
#define PCIHP_DEVICES_STR "/devices"
struct pcihp_config_ctrl {
int pci_dev;
uint_t flags;
int op;
int rv;
dev_info_t *dip;
hpc_occupant_info_t *occupant;
};
#define PCIHP_CFG_CONTINUE 0x1
#define PCIHP_ONLINE 1
#define PCIHP_OFFLINE 0
static int pcihp_open(dev_t *, int, int, cred_t *);
static int pcihp_close(dev_t, int, int, cred_t *);
static int pcihp_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
#ifdef DEBUG
static int pcihp_debug = 0;
#define PCIHP_DEBUG(args) if (pcihp_debug >= 1) cmn_err args
#define PCIHP_DEBUG2(args) if (pcihp_debug >= 2) cmn_err args
#else
#define PCIHP_DEBUG(args)
#define PCIHP_DEBUG2(args)
#endif
static int pcihp_enum_scan_all = 0;
static int pcihp_cpci_board_type = HPC_BOARD_CPCI_NON_HS;
static int pcihp_cpci_led_blink = 30;
static int pcihp_cpci_blue_led = 1;
static pcihp_t *pcihp_create_soft_state(dev_info_t *dip);
static void pcihp_destroy_soft_state(dev_info_t *dip);
static pcihp_t *pcihp_get_soft_state(dev_info_t *dip, int cmd, int *rv);
static int pcihp_configure_ap(pcihp_t *pcihp_p, int pci_dev);
static int pcihp_unconfigure_ap(pcihp_t *pcihp_p, int pci_dev);
static int pcihp_new_slot_state(dev_info_t *, hpc_slot_t,
hpc_slot_info_t *, int);
static int pcihp_configure(dev_info_t *, void *);
static bool_t pcihp_check_status(dev_info_t *);
static int pcihp_event_handler(caddr_t, uint_t);
static dev_info_t *pcihp_devi_find(dev_info_t *dip, uint_t dev, uint_t func);
static int pcihp_match_dev(dev_info_t *dip, void *hdl);
static int pcihp_get_hs_csr(struct pcihp_slotinfo *, ddi_acc_handle_t,
uint8_t *);
static void pcihp_set_hs_csr(struct pcihp_slotinfo *, ddi_acc_handle_t,
uint8_t *);
static int pcihp_get_hs_csr_location(ddi_acc_handle_t);
static int pcihp_handle_enum(pcihp_t *, int, int, int);
static void pcihp_hs_csr_op(pcihp_t *, int, int);
static int pcihp_enum_slot(pcihp_t *, struct pcihp_slotinfo *, int, int, int);
static int pcihp_handle_enum_extraction(pcihp_t *, int, int, int);
static int pcihp_handle_enum_insertion(pcihp_t *, int, int, int);
static int pcihp_add_dummy_reg_property(dev_info_t *, uint_t, uint_t, uint_t);
static int pcihp_config_setup(dev_info_t **, ddi_acc_handle_t *,
dev_info_t **, int, pcihp_t *);
static void pcihp_config_teardown(ddi_acc_handle_t *,
dev_info_t **, int, pcihp_t *);
static int pcihp_get_board_type(struct pcihp_slotinfo *);
static void pcihp_gen_sysevent(char *, int, int, dev_info_t *, int);
static int pcihp_list_occupants(dev_info_t *, void *);
static int pcihp_indirect_map(dev_info_t *dip);
#if 0
static void pcihp_probe_slot_state(dev_info_t *, int, hpc_slot_state_t *);
#endif
int pcihp_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
int flags, char *name, caddr_t valuep, int *lengthp);
struct cb_ops pcihp_cb_ops = {
pcihp_open,
pcihp_close,
nodev,
nodev,
nodev,
nodev,
nodev,
pcihp_ioctl,
nodev,
nodev,
nodev,
nochpoll,
pcihp_prop_op,
NULL,
D_NEW | D_MP | D_HOTPLUG,
CB_REV,
nodev,
nodev
};
int pcihp_autocfg_enabled = 1;
static kmutex_t pcihp_mutex;
static pcihp_t *pcihp_head = NULL;
static kmutex_t pcihp_open_mutex;
static int pci_devlink_flags = 0;
extern struct mod_ops mod_miscops;
static struct modlmisc modlmisc = {
&mod_miscops,
"PCI nexus hotplug support",
};
static struct modlinkage modlinkage = {
MODREV_1,
&modlmisc,
NULL
};
int
_init(void)
{
int error;
mutex_init(&pcihp_mutex, NULL, MUTEX_DRIVER, NULL);
mutex_init(&pcihp_open_mutex, NULL, MUTEX_DRIVER, NULL);
if ((error = mod_install(&modlinkage)) != 0) {
mutex_destroy(&pcihp_open_mutex);
mutex_destroy(&pcihp_mutex);
}
return (error);
}
int
_fini(void)
{
return (EBUSY);
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
static pcihp_t *
pcihp_create_soft_state(
dev_info_t *dip)
{
pcihp_t *pcihp_p;
pcihp_p = kmem_zalloc(sizeof (struct pcihp), KM_SLEEP);
pcihp_p->dip = dip;
mutex_init(&pcihp_p->mutex, NULL, MUTEX_DRIVER, NULL);
mutex_enter(&pcihp_mutex);
pcihp_p->nextp = pcihp_head;
pcihp_head = pcihp_p;
pcihp_p->bus_state = PCIHP_BUS_INITIALIZING;
pcihp_p->slots_active = 0;
mutex_exit(&pcihp_mutex);
return (pcihp_p);
}
static void
pcihp_destroy_soft_state(
dev_info_t *dip)
{
pcihp_t *p;
pcihp_t **pp;
mutex_enter(&pcihp_mutex);
pp = &pcihp_head;
while ((p = *pp) != NULL) {
if (p->dip == dip) {
*pp = p->nextp;
kmem_free(p, sizeof (struct pcihp));
break;
}
pp = &(p->nextp);
}
mutex_exit(&pcihp_mutex);
}
int
pcihp_info(
dev_info_t *dip,
ddi_info_cmd_t cmd,
void *arg,
void **result)
{
pcihp_t *pcihp_p;
major_t major;
minor_t minor;
int instance;
major = getmajor((dev_t)arg);
minor = getminor((dev_t)arg);
instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
switch (cmd) {
default:
return (DDI_FAILURE);
case DDI_INFO_DEVT2INSTANCE:
*result = (void *)(intptr_t)instance;
return (DDI_SUCCESS);
case DDI_INFO_DEVT2DEVINFO:
mutex_enter(&pcihp_mutex);
pcihp_p = pcihp_head;
while (pcihp_p != NULL) {
if (ddi_driver_major(pcihp_p->dip) ==
major && ddi_get_instance(pcihp_p->dip) ==
instance) {
*result = (void *)pcihp_p->dip;
mutex_exit(&pcihp_mutex);
return (DDI_SUCCESS);
}
pcihp_p = pcihp_p->nextp;
}
mutex_exit(&pcihp_mutex);
return (DDI_FAILURE);
}
}
static pcihp_t *
pcihp_get_soft_state(
dev_info_t *dip, int cmd, int *rv)
{
pcihp_t *pcihp_p;
*rv = PCIHP_SUCCESS;
mutex_enter(&pcihp_mutex);
pcihp_p = pcihp_head;
while (pcihp_p != NULL) {
if (pcihp_p->dip == dip) {
switch (cmd) {
case PCIHP_DR_BUS_UNCONFIGURE:
if (pcihp_p->slots_active == 0)
pcihp_p->bus_state =
PCIHP_BUS_UNCONFIGURED;
else
*rv = PCIHP_FAILURE;
break;
case PCIHP_DR_SLOT_ENTER:
if (pcihp_p->bus_state ==
PCIHP_BUS_UNCONFIGURED)
*rv = PCIHP_FAILURE;
else
pcihp_p->slots_active++;
break;
case PCIHP_DR_SLOT_EXIT:
ASSERT(pcihp_p->slots_active > 0);
if (pcihp_p->slots_active == 0)
cmn_err(CE_PANIC,
"pcihp (%s%d): mismatched slot"
" activity",
ddi_driver_name(dip),
ddi_get_instance(dip));
else
pcihp_p->slots_active--;
break;
case PCIHP_DR_NOOP:
break;
default:
*rv = PCIHP_FAILURE;
break;
}
mutex_exit(&pcihp_mutex);
return (pcihp_p);
}
pcihp_p = pcihp_p->nextp;
}
mutex_exit(&pcihp_mutex);
return (NULL);
}
static int
pcihp_open(dev_t *devp, int flags, int otyp, cred_t *credp)
{
dev_info_t *self;
pcihp_t *pcihp_p;
minor_t minor;
int pci_dev;
int rv;
if (otyp != OTYP_CHR)
return (EINVAL);
mutex_enter(&pcihp_open_mutex);
if (pcihp_info(NULL, DDI_INFO_DEVT2DEVINFO, (void *)*devp,
(void **)&self) != DDI_SUCCESS) {
mutex_exit(&pcihp_open_mutex);
return (ENXIO);
}
pcihp_p = pcihp_get_soft_state(self, PCIHP_DR_NOOP, &rv);
ASSERT(pcihp_p != NULL);
mutex_enter(&pcihp_p->mutex);
minor = getminor(*devp);
pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor);
if (pci_dev < PCI_MAX_DEVS) {
struct pcihp_slotinfo *slotinfop;
slotinfop = &pcihp_p->slotinfo[pci_dev];
if (slotinfop->slot_hdl == NULL) {
mutex_exit(&pcihp_p->mutex);
mutex_exit(&pcihp_open_mutex);
return (ENXIO);
}
}
if ((pcihp_p->soft_state == PCIHP_SOFT_STATE_OPEN_EXCL) ||
((flags & FEXCL) &&
(pcihp_p->soft_state != PCIHP_SOFT_STATE_CLOSED))) {
mutex_exit(&pcihp_p->mutex);
mutex_exit(&pcihp_open_mutex);
return (EBUSY);
}
if (flags & FEXCL)
pcihp_p->soft_state = PCIHP_SOFT_STATE_OPEN_EXCL;
else
pcihp_p->soft_state = PCIHP_SOFT_STATE_OPEN;
mutex_exit(&pcihp_p->mutex);
mutex_exit(&pcihp_open_mutex);
return (0);
}
static int
pcihp_close(dev_t dev, int flags, int otyp, cred_t *credp)
{
dev_info_t *self;
pcihp_t *pcihp_p;
int rv;
if (otyp != OTYP_CHR)
return (EINVAL);
mutex_enter(&pcihp_open_mutex);
if (pcihp_info(NULL, DDI_INFO_DEVT2DEVINFO, (void *)dev,
(void **)&self) != DDI_SUCCESS) {
mutex_exit(&pcihp_open_mutex);
return (ENXIO);
}
pcihp_p = pcihp_get_soft_state(self, PCIHP_DR_NOOP, &rv);
ASSERT(pcihp_p != NULL);
mutex_enter(&pcihp_p->mutex);
pcihp_p->soft_state = PCIHP_SOFT_STATE_CLOSED;
mutex_exit(&pcihp_p->mutex);
mutex_exit(&pcihp_open_mutex);
return (0);
}
static int
pcihp_list_occupants(dev_info_t *dip, void *hdl)
{
int pci_dev;
struct pcihp_config_ctrl *ctrl = (struct pcihp_config_ctrl *)hdl;
pci_regspec_t *pci_rp;
int length;
major_t major;
if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
(uint_t *)&length) != DDI_PROP_SUCCESS) {
ctrl->rv = DDI_FAILURE;
ctrl->dip = dip;
return (DDI_WALK_TERMINATE);
}
pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
ddi_prop_free(pci_rp);
if (pci_dev == ctrl->pci_dev) {
major = ddi_driver_major(dip);
if ((major == -1) || !i_ddi_devi_attached(dip))
return (DDI_WALK_PRUNECHILD);
if (ctrl->occupant->i >= HPC_MAX_OCCUPANTS) {
cmn_err(CE_WARN,
"pcihp (%s%d): unable to list all occupants",
ddi_driver_name(ddi_get_parent(dip)),
ddi_get_instance(ddi_get_parent(dip)));
return (DDI_WALK_TERMINATE);
}
ctrl->occupant->id[ctrl->occupant->i] =
kmem_alloc(sizeof (char[MAXPATHLEN]), KM_SLEEP);
(void) ddi_pathname(dip,
(char *)ctrl->occupant->id[ctrl->occupant->i]);
ctrl->occupant->i++;
}
return (DDI_WALK_PRUNECHILD);
}
static void
pcihp_create_occupant_props_nolock(dev_info_t *self, dev_t dev, int pci_dev)
{
struct pcihp_config_ctrl ctrl;
hpc_occupant_info_t *occupant;
int i;
occupant = kmem_alloc(sizeof (hpc_occupant_info_t), KM_SLEEP);
occupant->i = 0;
ctrl.flags = 0;
ctrl.dip = NULL;
ctrl.rv = NDI_SUCCESS;
ctrl.pci_dev = pci_dev;
ctrl.op = 55;
ctrl.occupant = occupant;
ddi_walk_devs(ddi_get_child(self), pcihp_list_occupants,
(void *)&ctrl);
if (occupant->i == 0) {
char *c[] = { "" };
(void) ddi_prop_update_string_array(dev, self, "pci-occupant",
c, 1);
} else {
(void) ddi_prop_update_string_array(dev, self, "pci-occupant",
occupant->id, occupant->i);
}
for (i = 0; i < occupant->i; i++) {
kmem_free(occupant->id[i], sizeof (char[MAXPATHLEN]));
}
kmem_free(occupant, sizeof (hpc_occupant_info_t));
}
static void
pcihp_create_occupant_props(dev_info_t *self, dev_t dev, int pci_dev)
{
ndi_devi_enter(self);
pcihp_create_occupant_props_nolock(self, dev, pci_dev);
ndi_devi_exit(self);
}
static void
pcihp_delete_occupant_props(dev_info_t *dip, dev_t dev)
{
if (ddi_prop_remove(dev, dip, "pci-occupant")
!= DDI_PROP_SUCCESS)
return;
}
static int
pcihp_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
int *rvalp)
{
pcihp_t *pcihp_p;
dev_info_t *self;
struct devctl_iocdata *dcp;
uint_t bus_state;
int rv = 0;
int pci_dev;
struct pcihp_slotinfo *slotinfop;
hpc_slot_state_t rstate;
devctl_ap_state_t ap_state;
struct hpc_control_data hpc_ctrldata;
struct hpc_led_info led_info;
time_t time;
int state_locking;
int state_unlocking;
int rval;
char *pathname = NULL;
if ((cmd != DEVCTL_AP_CONTROL) &&
ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
return (EFAULT);
if (pcihp_info(NULL, DDI_INFO_DEVT2DEVINFO, (void *)dev,
(void **)&self) != DDI_SUCCESS) {
if (cmd != DEVCTL_AP_CONTROL)
ndi_dc_freehdl(dcp);
return (ENXIO);
}
switch (cmd) {
case DEVCTL_AP_INSERT:
case DEVCTL_AP_REMOVE:
case DEVCTL_AP_CONNECT:
case DEVCTL_AP_DISCONNECT:
case DEVCTL_AP_CONFIGURE:
case DEVCTL_AP_UNCONFIGURE:
case DEVCTL_AP_GETSTATE:
case DEVCTL_AP_CONTROL:
state_locking = PCIHP_DR_SLOT_ENTER;
state_unlocking = PCIHP_DR_SLOT_EXIT;
break;
default:
state_locking = PCIHP_DR_NOOP;
state_unlocking = PCIHP_DR_NOOP;
break;
}
pcihp_p = pcihp_get_soft_state(self, state_locking, &rval);
ASSERT(pcihp_p != NULL);
if (rval == PCIHP_FAILURE) {
(void) ddi_pathname(pcihp_p->dip, pathname);
PCIHP_DEBUG((CE_WARN, "Hot Plug bus %s instance is unconfigured"
" while slot activity is requested\n", pathname));
if (cmd != DEVCTL_AP_CONTROL)
ndi_dc_freehdl(dcp);
return (EBUSY);
}
pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(getminor(dev));
switch (cmd) {
case DEVCTL_DEVICE_GETSTATE:
case DEVCTL_DEVICE_ONLINE:
case DEVCTL_DEVICE_OFFLINE:
case DEVCTL_BUS_GETSTATE:
rv = ndi_devctl_ioctl(self, cmd, arg, mode, 0);
ndi_dc_freehdl(dcp);
return (rv);
default:
break;
}
switch (cmd) {
case DEVCTL_DEVICE_RESET:
rv = ENOTSUP;
break;
case DEVCTL_BUS_QUIESCE:
if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
if (bus_state == BUS_QUIESCED)
break;
(void) ndi_set_bus_state(self, BUS_QUIESCED);
break;
case DEVCTL_BUS_UNQUIESCE:
if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
if (bus_state == BUS_ACTIVE)
break;
(void) ndi_set_bus_state(self, BUS_ACTIVE);
break;
case DEVCTL_BUS_RESET:
rv = ENOTSUP;
break;
case DEVCTL_BUS_RESETALL:
rv = ENOTSUP;
break;
case DEVCTL_AP_CONNECT:
case DEVCTL_AP_DISCONNECT:
case DEVCTL_AP_INSERT:
case DEVCTL_AP_REMOVE:
if (pci_dev >= PCI_MAX_DEVS) {
rv = ENXIO;
break;
}
slotinfop = &pcihp_p->slotinfo[pci_dev];
mutex_enter(&slotinfop->slot_mutex);
if ((slotinfop->slot_hdl == NULL) ||
(slotinfop->slot_flags & PCIHP_SLOT_DISABLED)) {
rv = ENXIO;
mutex_exit(&slotinfop->slot_mutex);
break;
}
if (slotinfop->ostate != AP_OSTATE_UNCONFIGURED) {
rv = EINVAL;
mutex_exit(&slotinfop->slot_mutex);
break;
}
switch (cmd) {
case DEVCTL_AP_INSERT:
rv = hpc_nexus_insert(slotinfop->slot_hdl, NULL, 0);
break;
case DEVCTL_AP_REMOVE:
rv = hpc_nexus_remove(slotinfop->slot_hdl, NULL, 0);
break;
case DEVCTL_AP_CONNECT:
rv = hpc_nexus_connect(slotinfop->slot_hdl, NULL, 0);
if (rv == HPC_SUCCESS) {
slotinfop->rstate = AP_RSTATE_CONNECTED;
if (drv_getparm(TIME, (void *)&time) !=
DDI_SUCCESS)
slotinfop->last_change = (time_t)-1;
else
slotinfop->last_change = (time32_t)time;
slotinfop = &pcihp_p->slotinfo[pci_dev];
pcihp_gen_sysevent(slotinfop->name,
PCIHP_DR_AP_STATE_CHANGE,
SE_NO_HINT, pcihp_p->dip,
KM_SLEEP);
}
break;
case DEVCTL_AP_DISCONNECT:
rv = hpc_nexus_disconnect(slotinfop->slot_hdl, NULL, 0);
if (rv == HPC_SUCCESS) {
slotinfop->rstate = AP_RSTATE_DISCONNECTED;
if (drv_getparm(TIME, (void *)&time) !=
DDI_SUCCESS)
slotinfop->last_change = (time_t)-1;
else
slotinfop->last_change = (time32_t)time;
slotinfop = &pcihp_p->slotinfo[pci_dev];
pcihp_gen_sysevent(slotinfop->name,
PCIHP_DR_AP_STATE_CHANGE,
SE_NO_HINT, pcihp_p->dip,
KM_SLEEP);
}
break;
}
mutex_exit(&slotinfop->slot_mutex);
switch (rv) {
case HPC_ERR_INVALID:
rv = ENXIO;
break;
case HPC_ERR_NOTSUPPORTED:
rv = ENOTSUP;
break;
case HPC_ERR_FAILED:
rv = EIO;
break;
}
break;
case DEVCTL_AP_CONFIGURE:
slotinfop = &pcihp_p->slotinfo[pci_dev];
mutex_enter(&slotinfop->slot_mutex);
rv = pcihp_configure_ap(pcihp_p, pci_dev);
if (rv == HPC_SUCCESS) {
pcihp_gen_sysevent(slotinfop->name,
PCIHP_DR_AP_STATE_CHANGE,
SE_NO_HINT, pcihp_p->dip, KM_SLEEP);
pcihp_create_occupant_props(self, dev, pci_dev);
}
mutex_exit(&slotinfop->slot_mutex);
break;
case DEVCTL_AP_UNCONFIGURE:
slotinfop = &pcihp_p->slotinfo[pci_dev];
mutex_enter(&slotinfop->slot_mutex);
rv = pcihp_unconfigure_ap(pcihp_p, pci_dev);
if (rv == HPC_SUCCESS) {
pcihp_gen_sysevent(slotinfop->name,
PCIHP_DR_AP_STATE_CHANGE,
SE_NO_HINT, pcihp_p->dip, KM_SLEEP);
pcihp_delete_occupant_props(pcihp_p->dip, dev);
}
mutex_exit(&slotinfop->slot_mutex);
break;
case DEVCTL_AP_GETSTATE:
{
int mutex_held;
slotinfop = &pcihp_p->slotinfo[pci_dev];
mutex_held = mutex_tryenter(&slotinfop->slot_mutex);
if (pci_dev >= PCI_MAX_DEVS || slotinfop->slot_hdl == NULL) {
rv = ENXIO;
if (mutex_held) {
mutex_exit(&slotinfop->slot_mutex);
}
break;
}
if (slotinfop->ostate == AP_OSTATE_UNCONFIGURED) {
if (hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_GET_SLOT_STATE, (caddr_t)&rstate) != 0) {
rv = EIO;
if (mutex_held)
mutex_exit(&slotinfop->slot_mutex);
break;
}
slotinfop->rstate = (ap_rstate_t)rstate;
}
ap_state.ap_rstate = slotinfop->rstate;
ap_state.ap_ostate = slotinfop->ostate;
ap_state.ap_condition = slotinfop->condition;
ap_state.ap_last_change = slotinfop->last_change;
ap_state.ap_error_code = 0;
if (mutex_held)
ap_state.ap_in_transition = 0;
else
ap_state.ap_in_transition = 1;
if (mutex_held)
mutex_exit(&slotinfop->slot_mutex);
if (ndi_dc_return_ap_state(&ap_state, dcp) != NDI_SUCCESS)
rv = EFAULT;
break;
}
case DEVCTL_AP_CONTROL:
switch (ddi_model_convert_from(mode & FMODELS)) {
case DDI_MODEL_ILP32: {
struct hpc_control32_data hpc_ctrldata32;
if (copyin((void *)arg, (void *)&hpc_ctrldata32,
sizeof (struct hpc_control32_data)) != 0) {
rv = EFAULT;
break;
}
hpc_ctrldata.cmd = hpc_ctrldata32.cmd;
hpc_ctrldata.data =
(void *)(intptr_t)hpc_ctrldata32.data;
break;
}
case DDI_MODEL_NONE:
if (copyin((void *)arg, (void *)&hpc_ctrldata,
sizeof (struct hpc_control_data)) != 0) {
rv = EFAULT;
}
break;
default:
rv = EFAULT;
break;
}
if (rv == EFAULT)
break;
slotinfop = &pcihp_p->slotinfo[pci_dev];
mutex_enter(&slotinfop->slot_mutex);
if (pci_dev >= PCI_MAX_DEVS || slotinfop->slot_hdl == NULL) {
rv = ENXIO;
mutex_exit(&slotinfop->slot_mutex);
break;
}
switch (hpc_ctrldata.cmd) {
case HPC_CTRL_GET_LED_STATE:
if (copyin(hpc_ctrldata.data, (void *)&led_info,
sizeof (hpc_led_info_t)) != 0) {
rv = EFAULT;
break;
}
if (hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_GET_LED_STATE, (caddr_t)&led_info) != 0) {
if (rv != ENOTSUP)
rv = EIO;
break;
}
if (copyout((void *)&led_info, hpc_ctrldata.data,
sizeof (hpc_led_info_t)) != 0) {
rv = EFAULT;
break;
}
break;
case HPC_CTRL_SET_LED_STATE:
if (copyin(hpc_ctrldata.data, (void *)&led_info,
sizeof (hpc_led_info_t)) != 0) {
rv = EFAULT;
break;
}
rv = hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_SET_LED_STATE, (caddr_t)&led_info);
if ((rv == HPC_ERR_NOTSUPPORTED) &&
(slotinfop->slot_type & HPC_SLOT_TYPE_CPCI)) {
if (led_info.led != HPC_ATTN_LED)
break;
switch (led_info.state) {
case HPC_LED_OFF:
pcihp_hs_csr_op(pcihp_p,
pci_dev,
HPC_EVENT_SLOT_BLUE_LED_OFF);
rv = 0;
break;
case HPC_LED_ON:
pcihp_hs_csr_op(pcihp_p,
pci_dev,
HPC_EVENT_SLOT_BLUE_LED_ON);
rv = 0;
break;
case HPC_LED_BLINK:
{
int bl;
for (bl = 0; bl < 2; bl++) {
pcihp_hs_csr_op(pcihp_p,
pci_dev,
HPC_EVENT_SLOT_BLUE_LED_ON);
delay(pcihp_cpci_led_blink);
pcihp_hs_csr_op(pcihp_p,
pci_dev,
HPC_EVENT_SLOT_BLUE_LED_OFF);
delay(pcihp_cpci_led_blink);
}
rv = 0;
break;
}
default:
break;
}
}
if (rv == HPC_ERR_FAILED)
rv = EIO;
break;
case HPC_CTRL_ENABLE_SLOT:
if ((slotinfop->slot_flags & PCIHP_SLOT_DISABLED) == 0)
break;
if (hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_ENABLE_SLOT, NULL) != HPC_SUCCESS) {
rv = EIO;
break;
}
slotinfop->slot_flags &= ~PCIHP_SLOT_DISABLED;
slotinfop->condition = AP_COND_UNKNOWN;
break;
case HPC_CTRL_DISABLE_SLOT:
if (slotinfop->ostate == AP_OSTATE_CONFIGURED) {
rv = EAGAIN;
break;
}
if (hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_DISABLE_SLOT, NULL) != HPC_SUCCESS) {
rv = EIO;
break;
}
slotinfop->slot_flags |= PCIHP_SLOT_DISABLED;
slotinfop->condition = AP_COND_UNUSABLE;
break;
case HPC_CTRL_ENABLE_AUTOCFG:
slotinfop->slot_flags |= PCIHP_SLOT_AUTO_CFG_EN;
(void) hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_ENABLE_AUTOCFG, NULL);
if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI)
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_ENABLE_ENUM);
break;
case HPC_CTRL_DISABLE_AUTOCFG:
slotinfop->slot_flags &= ~PCIHP_SLOT_AUTO_CFG_EN;
(void) hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_DISABLE_AUTOCFG, NULL);
if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI)
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_DISABLE_ENUM);
break;
case HPC_CTRL_GET_BOARD_TYPE:
{
hpc_board_type_t board_type;
board_type = pcihp_get_board_type(slotinfop);
if (board_type == -1) {
rv = ENXIO;
break;
}
if (copyout((void *)&board_type, hpc_ctrldata.data,
sizeof (hpc_board_type_t)) != 0) {
rv = ENXIO;
break;
}
break;
}
case HPC_CTRL_GET_SLOT_INFO:
{
hpc_slot_info_t slot_info;
slot_info.version = HPC_SLOT_INFO_VERSION;
slot_info.slot_type = slotinfop->slot_type;
slot_info.pci_slot_capabilities =
slotinfop->slot_capabilities;
slot_info.pci_dev_num = (uint16_t)pci_dev;
(void) strcpy(slot_info.pci_slot_name, slotinfop->name);
if (copyout((void *)&slot_info, hpc_ctrldata.data,
sizeof (hpc_slot_info_t)) != 0) {
rv = EFAULT;
break;
}
break;
}
case HPC_CTRL_GET_CARD_INFO:
{
hpc_card_info_t card_info;
ddi_acc_handle_t handle;
dev_info_t *cdip;
if ((slotinfop->ostate != AP_OSTATE_CONFIGURED) ||
((cdip = pcihp_devi_find(self,
pci_dev, 0)) == NULL)) {
rv = ENXIO;
break;
}
if (slotinfop->condition == AP_COND_FAILED) {
rv = EIO;
break;
}
if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) {
rv = EIO;
break;
}
card_info.prog_class = pci_config_get8(handle,
PCI_CONF_PROGCLASS);
card_info.base_class = pci_config_get8(handle,
PCI_CONF_BASCLASS);
card_info.sub_class = pci_config_get8(handle,
PCI_CONF_SUBCLASS);
card_info.header_type = pci_config_get8(handle,
PCI_CONF_HEADER);
pci_config_teardown(&handle);
if (copyout((void *)&card_info, hpc_ctrldata.data,
sizeof (hpc_card_info_t)) != 0) {
rv = EFAULT;
break;
}
break;
}
default:
rv = EINVAL;
break;
}
mutex_exit(&slotinfop->slot_mutex);
break;
default:
rv = ENOTTY;
}
if (cmd != DEVCTL_AP_CONTROL)
ndi_dc_freehdl(dcp);
(void) pcihp_get_soft_state(self, state_unlocking, &rval);
return (rv);
}
static int
pcihp_configure_ap(pcihp_t *pcihp_p, int pci_dev)
{
dev_info_t *self = pcihp_p->dip;
int rv = HPC_SUCCESS;
struct pcihp_slotinfo *slotinfop;
hpc_slot_state_t rstate;
struct pcihp_config_ctrl ctrl;
time_t time;
slotinfop = &pcihp_p->slotinfo[pci_dev];
if ((pci_dev >= PCI_MAX_DEVS) || (slotinfop->slot_hdl == NULL) ||
(slotinfop->slot_flags & PCIHP_SLOT_DISABLED)) {
return (ENXIO);
}
if (slotinfop->ostate == AP_OSTATE_CONFIGURED) {
ctrl.flags = PCIHP_CFG_CONTINUE;
ctrl.rv = NDI_SUCCESS;
ctrl.dip = NULL;
ctrl.pci_dev = pci_dev;
ctrl.op = PCIHP_ONLINE;
ndi_devi_enter(self);
ddi_walk_devs(ddi_get_child(self), pcihp_configure,
(void *)&ctrl);
ndi_devi_exit(self);
if (ctrl.rv != NDI_SUCCESS) {
cmn_err(CE_WARN,
"pcihp (%s%d): failed to attach one or"
" more drivers for the card in the slot %s",
ddi_driver_name(self), ddi_get_instance(self),
slotinfop->name);
}
(void) hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_DEV_CONFIGURED, NULL);
if (drv_getparm(TIME, (void *)&time) != DDI_SUCCESS)
slotinfop->last_change = (time_t)-1;
else
slotinfop->last_change = (time32_t)time;
return (rv);
}
if (hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_GET_SLOT_STATE, (caddr_t)&rstate) != 0) {
return (ENXIO);
}
if (rstate == HPC_SLOT_EMPTY) {
return (ENXIO);
}
if (rstate != HPC_SLOT_CONNECTED) {
return (ENXIO);
}
slotinfop->rstate = AP_RSTATE_CONNECTED;
if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_SLOT_CONFIGURE);
if (pcihp_cpci_blue_led)
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_SLOT_BLUE_LED_OFF);
slotinfop->slot_flags &= ~PCIHP_SLOT_ENUM_INS_PENDING;
}
(void) hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_DEV_CONFIG_START, NULL);
if (pcicfg_configure(self, pci_dev, PCICFG_ALL_FUNC, 0)
!= PCICFG_SUCCESS) {
if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
if (pcihp_cpci_blue_led)
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_SLOT_BLUE_LED_ON);
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_SLOT_UNCONFIGURE);
}
(void) hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_DEV_CONFIG_FAILURE, NULL);
return (EIO);
}
slotinfop->ostate = AP_OSTATE_CONFIGURED;
slotinfop->condition = AP_COND_OK;
ctrl.flags = PCIHP_CFG_CONTINUE;
ctrl.rv = NDI_SUCCESS;
ctrl.dip = NULL;
ctrl.pci_dev = pci_dev;
ctrl.op = PCIHP_ONLINE;
ndi_devi_enter(self);
ddi_walk_devs(ddi_get_child(self), pcihp_configure, (void *)&ctrl);
ndi_devi_exit(self);
if (ctrl.rv != NDI_SUCCESS) {
cmn_err(CE_WARN,
"pcihp (%s%d): failed to attach one or"
" more drivers for the card in the slot %s",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name);
}
if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI)
pcihp_hs_csr_op(pcihp_p, pci_dev, -1);
(void) hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_DEV_CONFIGURED, NULL);
return (rv);
}
static int
pcihp_unconfigure_ap(pcihp_t *pcihp_p, int pci_dev)
{
dev_info_t *self = pcihp_p->dip;
int rv = HPC_SUCCESS;
struct pcihp_slotinfo *slotinfop;
struct pcihp_config_ctrl ctrl;
time_t time;
slotinfop = &pcihp_p->slotinfo[pci_dev];
if ((pci_dev >= PCI_MAX_DEVS) || (slotinfop->slot_hdl == NULL) ||
(slotinfop->slot_flags & PCIHP_SLOT_DISABLED)) {
return (ENXIO);
}
if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
if (slotinfop->slot_flags & PCIHP_SLOT_DEV_NON_HOTPLUG) {
return (ENOTSUP);
}
}
if (slotinfop->ostate == AP_OSTATE_CONFIGURED) {
pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_DISABLE_ENUM);
ctrl.flags = 0;
ctrl.rv = NDI_SUCCESS;
ctrl.dip = NULL;
ctrl.pci_dev = pci_dev;
ctrl.op = PCIHP_OFFLINE;
(void) devfs_clean(self, NULL, DV_CLEAN_FORCE);
ndi_devi_enter(self);
ddi_walk_devs(ddi_get_child(self), pcihp_configure,
(void *)&ctrl);
ndi_devi_exit(self);
if (ctrl.rv != NDI_SUCCESS) {
ctrl.flags = 0;
ctrl.rv = NDI_SUCCESS;
ctrl.dip = NULL;
ctrl.pci_dev = pci_dev;
ctrl.op = PCIHP_ONLINE;
ndi_devi_enter(self);
ddi_walk_devs(ddi_get_child(self),
pcihp_configure, (void *)&ctrl);
ndi_devi_exit(self);
(void) hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_DEV_UNCONFIG_FAILURE, NULL);
rv = EBUSY;
} else {
(void) hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_DEV_UNCONFIG_START, NULL);
if (pcicfg_unconfigure(self, pci_dev,
PCICFG_ALL_FUNC, 0) == PCICFG_SUCCESS) {
if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_SLOT_UNCONFIGURE);
if (pcihp_cpci_blue_led)
pcihp_hs_csr_op(pcihp_p,
pci_dev,
HPC_EVENT_SLOT_BLUE_LED_ON);
slotinfop->hs_csr_location = 0;
slotinfop->slot_flags &=
~(PCIHP_SLOT_DEV_NON_HOTPLUG|
PCIHP_SLOT_ENUM_EXT_PENDING);
}
slotinfop->ostate = AP_OSTATE_UNCONFIGURED;
slotinfop->condition = AP_COND_UNKNOWN;
(void) hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_DEV_UNCONFIGURED,
NULL);
} else {
(void) hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_DEV_UNCONFIG_FAILURE, NULL);
rv = EIO;
}
}
}
if (drv_getparm(TIME, (void *)&time) != DDI_SUCCESS)
slotinfop->last_change = (time_t)-1;
else
slotinfop->last_change = (time32_t)time;
if ((slotinfop->slot_flags & PCIHP_SLOT_AUTO_CFG_EN) == 0) {
pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_ENABLE_ENUM);
}
return (rv);
}
struct cb_ops *
pcihp_get_cb_ops()
{
return (&pcihp_cb_ops);
}
int
pcihp_init(dev_info_t *dip)
{
pcihp_t *pcihp_p;
int i;
caddr_t enum_data;
int enum_size;
int rv;
mutex_enter(&pcihp_open_mutex);
if (pcihp_get_soft_state(dip, PCIHP_DR_NOOP, &rv) != NULL) {
cmn_err(CE_WARN, "%s%d: pcihp instance already initialized!",
ddi_driver_name(dip), ddi_get_instance(dip));
goto cleanup;
}
if ((pcihp_p = pcihp_create_soft_state(dip)) == NULL) {
cmn_err(CE_WARN, "%s%d: can't allocate pcihp structure",
ddi_driver_name(dip), ddi_get_instance(dip));
goto cleanup;
}
pcihp_p->soft_state = PCIHP_SOFT_STATE_CLOSED;
pcihp_p->bus_flags = 0;
if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, "enum-impl",
(caddr_t)&enum_data, &enum_size) == DDI_PROP_SUCCESS) {
if (strcmp(enum_data, "radial") == 0) {
pcihp_p->bus_flags |= PCIHP_BUS_ENUM_RADIAL;
}
kmem_free(enum_data, enum_size);
}
for (i = 0; i < PCI_MAX_DEVS; i++) {
mutex_init(&pcihp_p->slotinfo[i].slot_mutex, NULL,
MUTEX_DRIVER, NULL);
}
if (hpc_nexus_register_bus(dip, pcihp_new_slot_state, 0) != 0) {
cmn_err(CE_WARN, "%s%d: failed to register the bus with HPS",
ddi_driver_name(dip), ddi_get_instance(dip));
goto cleanup1;
}
if (ddi_create_minor_node(dip, "devctl", S_IFCHR,
PCIHP_AP_MINOR_NUM(ddi_get_instance(dip), PCIHP_DEVCTL_MINOR),
DDI_NT_NEXUS, 0) != DDI_SUCCESS)
goto cleanup2;
(void) pci_resource_setup(dip);
pcihp_p->bus_state = PCIHP_BUS_CONFIGURED;
mutex_exit(&pcihp_open_mutex);
return (DDI_SUCCESS);
cleanup2:
(void) hpc_nexus_unregister_bus(dip);
cleanup1:
for (i = 0; i < PCI_MAX_DEVS; i++)
mutex_destroy(&pcihp_p->slotinfo[i].slot_mutex);
pcihp_destroy_soft_state(dip);
cleanup:
mutex_exit(&pcihp_open_mutex);
return (DDI_FAILURE);
}
int
pcihp_uninit(dev_info_t *dip)
{
pcihp_t *pcihp_p;
int i, j;
int rv;
mutex_enter(&pcihp_open_mutex);
pcihp_p = pcihp_get_soft_state(dip, PCIHP_DR_BUS_UNCONFIGURE, &rv);
ASSERT(pcihp_p != NULL);
for (i = 0; i < PCI_MAX_DEVS; i++) {
if (!mutex_tryenter(&pcihp_p->slotinfo[i].slot_mutex)) {
for (j = 0; j < i; j++) {
mutex_exit(&pcihp_p->slotinfo[j].slot_mutex);
}
mutex_exit(&pcihp_open_mutex);
return (DDI_FAILURE);
}
}
if ((pcihp_p->soft_state != PCIHP_SOFT_STATE_CLOSED) ||
(rv == PCIHP_FAILURE)) {
cmn_err(CE_WARN, "%s%d: pcihp instance is busy",
ddi_driver_name(dip), ddi_get_instance(dip));
for (i = 0; i < PCI_MAX_DEVS; i++) {
mutex_exit(&pcihp_p->slotinfo[i].slot_mutex);
}
mutex_exit(&pcihp_open_mutex);
return (DDI_FAILURE);
}
(void) hpc_nexus_unregister_bus(dip);
for (i = 0; i < PCI_MAX_DEVS; i++) {
if (pcihp_p->slotinfo[i].name != NULL)
kmem_free(pcihp_p->slotinfo[i].name,
strlen(pcihp_p->slotinfo[i].name) + 1);
}
for (i = 0; i < PCI_MAX_DEVS; i++)
mutex_destroy(&pcihp_p->slotinfo[i].slot_mutex);
ddi_remove_minor_node(dip, NULL);
pcihp_destroy_soft_state(dip);
(void) pci_resource_destroy(dip);
mutex_exit(&pcihp_open_mutex);
return (DDI_SUCCESS);
}
static int
pcihp_new_slot_state(dev_info_t *dip, hpc_slot_t hdl,
hpc_slot_info_t *slot_info, int slot_state)
{
pcihp_t *pcihp_p;
struct pcihp_slotinfo *slotinfop;
int pci_dev;
minor_t ap_minor;
major_t ap_major;
int rv = 0;
time_t time;
int auto_enable = 1;
int rval;
pcihp_p = pcihp_get_soft_state(dip, PCIHP_DR_SLOT_ENTER, &rval);
ASSERT(pcihp_p != NULL);
if (rval == PCIHP_FAILURE) {
PCIHP_DEBUG((CE_WARN, "pcihp instance is unconfigured"
" while slot activity is requested\n"));
return (HPC_ERR_FAILED);
}
pci_dev = slot_info->pci_dev_num;
slotinfop = &pcihp_p->slotinfo[pci_dev];
mutex_enter(&slotinfop->slot_mutex);
switch (slot_state) {
case HPC_SLOT_ONLINE:
if (slotinfop->slot_hdl != NULL) {
PCIHP_DEBUG((CE_WARN,
"pcihp (%s%d): pci slot (dev %x) already ONLINE!!",
ddi_driver_name(dip), ddi_get_instance(dip),
pci_dev));
rv = HPC_ERR_FAILED;
break;
}
ap_minor = PCIHP_AP_MINOR_NUM(ddi_get_instance(dip), pci_dev);
if (ddi_create_minor_node(dip, slot_info->pci_slot_name,
S_IFCHR, ap_minor,
DDI_NT_PCI_ATTACHMENT_POINT, 0) == DDI_FAILURE) {
cmn_err(CE_WARN,
"pcihp (%s%d): ddi_create_minor_node failed"
" for pci dev %x", ddi_driver_name(dip),
ddi_get_instance(dip), pci_dev);
rv = HPC_ERR_FAILED;
break;
}
slotinfop->slot_hdl = hdl;
ap_major = ddi_driver_major(dip);
if (hpc_install_event_handler(hdl, -1, pcihp_event_handler,
(caddr_t)makedevice(ap_major, ap_minor)) != 0) {
cmn_err(CE_WARN,
"pcihp (%s%d): install event handler failed"
" for pci dev %x", ddi_driver_name(dip),
ddi_get_instance(dip), pci_dev);
rv = HPC_ERR_FAILED;
break;
}
slotinfop->event_mask = (uint32_t)0xFFFFFFFF;
pcihp_create_occupant_props(dip, makedevice(ap_major,
ap_minor), pci_dev);
slotinfop->slot_flags = pcihp_autocfg_enabled;
slotinfop->name =
kmem_alloc(strlen(slot_info->pci_slot_name) + 1, KM_SLEEP);
(void) strcpy(slotinfop->name, slot_info->pci_slot_name);
slotinfop->slot_type = slot_info->slot_type;
slotinfop->hs_csr_location = 0;
slotinfop->slot_capabilities = slot_info->pci_slot_capabilities;
if (slot_info->slot_flags & HPC_SLOT_NO_AUTO_ENABLE)
auto_enable = 0;
if (slot_info->slot_flags & HPC_SLOT_CREATE_DEVLINK) {
pci_devlink_flags |= (1 << pci_dev);
(void) ddi_prop_update_int(DDI_DEV_T_NONE,
dip, "ap-names", pci_devlink_flags);
}
PCIHP_DEBUG((CE_NOTE,
"pcihp (%s%d): pci slot (dev %x) ONLINE\n",
ddi_driver_name(dip), ddi_get_instance(dip), pci_dev));
if (pcihp_devi_find(dip, pci_dev, 0) != NULL) {
slotinfop->ostate = AP_OSTATE_CONFIGURED;
slotinfop->rstate = AP_RSTATE_CONNECTED;
slotinfop->condition = AP_COND_OK;
if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
(void) pcihp_get_board_type(slotinfop);
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_SLOT_CONFIGURE);
if (pcihp_cpci_blue_led)
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_SLOT_BLUE_LED_OFF);
slotinfop->slot_flags |= PCIHP_SLOT_AUTO_CFG_EN;
slotinfop->slot_flags &=
~PCIHP_SLOT_ENUM_INS_PENDING;
}
(void) hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_DEV_CONFIGURED, NULL);
pcihp_gen_sysevent(slotinfop->name,
PCIHP_DR_AP_STATE_CHANGE, SE_NO_HINT,
pcihp_p->dip, KM_SLEEP);
} else {
struct pcihp_config_ctrl ctrl;
slotinfop->ostate = AP_OSTATE_UNCONFIGURED;
slotinfop->rstate = AP_RSTATE_EMPTY;
slotinfop->condition = AP_COND_UNKNOWN;
if (!auto_enable) {
break;
}
if (hpc_nexus_connect(slotinfop->slot_hdl,
NULL, 0) != HPC_SUCCESS)
break;
if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_SLOT_CONFIGURE);
if (pcihp_cpci_blue_led)
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_SLOT_BLUE_LED_OFF);
slotinfop->slot_flags |= PCIHP_SLOT_AUTO_CFG_EN;
slotinfop->slot_flags &=
~PCIHP_SLOT_ENUM_INS_PENDING;
}
(void) hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_DEV_CONFIG_START, NULL);
if (pcicfg_configure(dip, pci_dev, PCICFG_ALL_FUNC, 0)
!= PCICFG_SUCCESS) {
if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
if (pcihp_cpci_blue_led)
pcihp_hs_csr_op(pcihp_p,
pci_dev,
HPC_EVENT_SLOT_BLUE_LED_ON);
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_SLOT_UNCONFIGURE);
}
(void) hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_DEV_CONFIG_FAILURE, NULL);
(void) hpc_nexus_disconnect(slotinfop->slot_hdl,
NULL, 0);
} else {
slotinfop->ostate = AP_OSTATE_CONFIGURED;
slotinfop->rstate = AP_RSTATE_CONNECTED;
slotinfop->condition = AP_COND_OK;
ctrl.flags = PCIHP_CFG_CONTINUE;
ctrl.rv = NDI_SUCCESS;
ctrl.dip = NULL;
ctrl.pci_dev = pci_dev;
ctrl.op = PCIHP_ONLINE;
(void) pcihp_get_board_type(slotinfop);
ndi_devi_enter(dip);
ddi_walk_devs(ddi_get_child(dip),
pcihp_configure, (void *)&ctrl);
ndi_devi_exit(dip);
if (ctrl.rv != NDI_SUCCESS) {
cmn_err(CE_WARN,
"pcihp (%s%d): failed to attach"
" one or more drivers for the"
" card in the slot %s",
ddi_driver_name(dip),
ddi_get_instance(dip),
slotinfop->name);
}
(void) hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_DEV_CONFIGURED, NULL);
pcihp_gen_sysevent(slotinfop->name,
PCIHP_DR_AP_STATE_CHANGE, SE_NO_HINT,
pcihp_p->dip, KM_SLEEP);
}
}
break;
case HPC_SLOT_OFFLINE:
if (slotinfop->ostate != AP_OSTATE_UNCONFIGURED) {
cmn_err(CE_WARN, "pcihp (%s%d): Card is still in "
"configured state for pci dev %x",
ddi_driver_name(dip), ddi_get_instance(dip),
pci_dev);
rv = HPC_ERR_FAILED;
break;
}
if (pcihp_p->soft_state != PCIHP_SOFT_STATE_CLOSED) {
rv = HPC_ERR_FAILED;
break;
}
if (slot_info->slot_flags & HPC_SLOT_CREATE_DEVLINK) {
pci_devlink_flags &= ~(1 << pci_dev);
(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip,
"ap-names", pci_devlink_flags);
}
ddi_remove_minor_node(dip, slotinfop->name);
kmem_free(slotinfop->name, strlen(slotinfop->name) + 1);
slotinfop->name = NULL;
slotinfop->slot_hdl = NULL;
PCIHP_DEBUG((CE_NOTE,
"pcihp (%s%d): pci slot (dev %x) OFFLINE\n",
ddi_driver_name(dip), ddi_get_instance(dip),
slot_info->pci_dev_num));
break;
default:
cmn_err(CE_WARN,
"pcihp_new_slot_state: unknown slot_state %d", slot_state);
rv = HPC_ERR_FAILED;
}
if (rv == 0) {
if (drv_getparm(TIME, (void *)&time) != DDI_SUCCESS)
slotinfop->last_change = (time_t)-1;
else
slotinfop->last_change = (time32_t)time;
}
mutex_exit(&slotinfop->slot_mutex);
(void) pcihp_get_soft_state(dip, PCIHP_DR_SLOT_EXIT, &rval);
return (rv);
}
static int
pcihp_event_handler(caddr_t slot_arg, uint_t event_mask)
{
dev_t ap_dev = (dev_t)slot_arg;
dev_info_t *self;
pcihp_t *pcihp_p;
int pci_dev;
int rv = HPC_EVENT_CLAIMED;
struct pcihp_slotinfo *slotinfop;
struct pcihp_config_ctrl ctrl;
int rval;
int hint;
hpc_slot_state_t rstate;
struct hpc_led_info led_info;
if (pcihp_info(NULL, DDI_INFO_DEVT2DEVINFO, (void *)ap_dev,
(void **)&self) != DDI_SUCCESS)
return (ENXIO);
pcihp_p = pcihp_get_soft_state(self, PCIHP_DR_SLOT_ENTER, &rval);
ASSERT(pcihp_p != NULL);
if (rval == PCIHP_FAILURE) {
PCIHP_DEBUG((CE_WARN, "pcihp instance is unconfigured"
" while slot activity is requested\n"));
return (-1);
}
pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(getminor(ap_dev));
slotinfop = &pcihp_p->slotinfo[pci_dev];
switch (event_mask) {
case HPC_EVENT_CLEAR_ENUM:
PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): ENUM# is generated"
" on the bus (for slot %s ?)",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip), slotinfop->name));
rv = pcihp_handle_enum(pcihp_p, pci_dev, PCIHP_CLEAR_ENUM,
KM_NOSLEEP);
(void) pcihp_get_soft_state(self, PCIHP_DR_SLOT_EXIT, &rval);
return (rv);
default:
break;
}
mutex_enter(&slotinfop->slot_mutex);
if (hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_GET_SLOT_STATE, (caddr_t)&rstate) != 0)
rv = HPC_ERR_FAILED;
slotinfop->rstate = (ap_rstate_t)rstate;
switch (event_mask) {
case HPC_EVENT_SLOT_INSERTION:
cmn_err(CE_NOTE, "pcihp (%s%d): card is inserted"
" in the slot %s (pci dev %x)",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name, pci_dev);
break;
case HPC_EVENT_SLOT_CONFIGURE:
if ((slotinfop->slot_flags & PCIHP_SLOT_AUTO_CFG_EN) == 0) {
cmn_err(CE_NOTE, "pcihp (%s%d): SLOT_CONFIGURE event"
" occurred for pci dev %x (slot %s),"
" Slot disabled for auto-configuration.",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip), pci_dev,
slotinfop->name);
break;
}
if (slotinfop->ostate == AP_OSTATE_CONFIGURED) {
cmn_err(CE_WARN, "pcihp (%s%d): SLOT_CONFIGURE event"
" re-occurred for pci dev %x (slot %s),",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip), pci_dev,
slotinfop->name);
mutex_exit(&slotinfop->slot_mutex);
(void) pcihp_get_soft_state(self, PCIHP_DR_SLOT_EXIT,
&rval);
return (EAGAIN);
}
if ((rv = hpc_nexus_connect(slotinfop->slot_hdl,
NULL, 0)) == HPC_SUCCESS) {
slotinfop->rstate = AP_RSTATE_CONNECTED;
}
if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_SLOT_CONFIGURE);
if (pcihp_cpci_blue_led)
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_SLOT_BLUE_LED_OFF);
}
(void) hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_DEV_CONFIG_START, NULL);
if (pcicfg_configure(pcihp_p->dip, pci_dev, PCICFG_ALL_FUNC, 0)
!= PCICFG_SUCCESS) {
if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
if (pcihp_cpci_blue_led)
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_SLOT_BLUE_LED_ON);
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_SLOT_UNCONFIGURE);
}
cmn_err(CE_WARN, "pcihp (%s%d): failed to configure"
" the card in the slot %s",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name);
if (hpc_nexus_disconnect(slotinfop->slot_hdl,
NULL, 0) == HPC_SUCCESS) {
slotinfop->rstate = AP_RSTATE_DISCONNECTED;
}
(void) hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_DEV_CONFIG_FAILURE, NULL);
} else {
slotinfop->ostate = AP_OSTATE_CONFIGURED;
slotinfop->condition = AP_COND_OK;
ctrl.flags = PCIHP_CFG_CONTINUE;
ctrl.rv = NDI_SUCCESS;
ctrl.dip = NULL;
ctrl.pci_dev = pci_dev;
ctrl.op = PCIHP_ONLINE;
(void) pcihp_get_board_type(slotinfop);
ndi_devi_enter(pcihp_p->dip);
ddi_walk_devs(ddi_get_child(pcihp_p->dip),
pcihp_configure, (void *)&ctrl);
ndi_devi_exit(pcihp_p->dip);
if (ctrl.rv != NDI_SUCCESS) {
cmn_err(CE_WARN,
"pcihp (%s%d): failed to attach one or"
" more drivers for the card in"
" the slot %s",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name);
}
(void) hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_DEV_CONFIGURED, NULL);
cmn_err(CE_NOTE, "pcihp (%s%d): card is CONFIGURED"
" in the slot %s (pci dev %x)",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name, pci_dev);
}
break;
case HPC_EVENT_SLOT_UNCONFIGURE:
if ((slotinfop->slot_flags & PCIHP_SLOT_AUTO_CFG_EN) == 0) {
cmn_err(CE_NOTE, "pcihp (%s%d): SLOT_UNCONFIGURE event"
" for pci dev %x (slot %s) ignored,"
" Slot disabled for auto-configuration.",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip), pci_dev,
slotinfop->name);
break;
}
if (slotinfop->ostate == AP_OSTATE_UNCONFIGURED) {
cmn_err(CE_WARN, "pcihp (%s%d): SLOT_UNCONFIGURE "
"event re-occurred for pci dev %x (slot %s),",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip), pci_dev,
slotinfop->name);
mutex_exit(&slotinfop->slot_mutex);
(void) pcihp_get_soft_state(self, PCIHP_DR_SLOT_EXIT,
&rval);
return (EAGAIN);
}
if (slotinfop->ostate == AP_OSTATE_CONFIGURED) {
ctrl.flags = 0;
ctrl.rv = NDI_SUCCESS;
ctrl.dip = NULL;
ctrl.pci_dev = pci_dev;
ctrl.op = PCIHP_OFFLINE;
(void) devfs_clean(pcihp_p->dip, NULL, DV_CLEAN_FORCE);
ndi_devi_enter(pcihp_p->dip);
ddi_walk_devs(ddi_get_child(pcihp_p->dip),
pcihp_configure, (void *)&ctrl);
ndi_devi_exit(pcihp_p->dip);
if (ctrl.rv != NDI_SUCCESS) {
ctrl.flags = PCIHP_CFG_CONTINUE;
ctrl.rv = NDI_SUCCESS;
ctrl.dip = NULL;
ctrl.pci_dev = pci_dev;
ctrl.op = PCIHP_ONLINE;
ndi_devi_enter(pcihp_p->dip);
ddi_walk_devs(ddi_get_child(pcihp_p->dip),
pcihp_configure, (void *)&ctrl);
ndi_devi_exit(pcihp_p->dip);
rv = HPC_ERR_FAILED;
} else {
(void) hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_DEV_UNCONFIG_START, NULL);
if (pcicfg_unconfigure(pcihp_p->dip, pci_dev,
PCICFG_ALL_FUNC, 0) == PCICFG_SUCCESS) {
if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
if (pcihp_cpci_blue_led)
pcihp_hs_csr_op(pcihp_p,
pci_dev,
HPC_EVENT_SLOT_BLUE_LED_ON);
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_SLOT_UNCONFIGURE);
slotinfop->hs_csr_location = 0;
slotinfop->slot_flags &=
~PCIHP_SLOT_DEV_NON_HOTPLUG;
}
slotinfop->ostate =
AP_OSTATE_UNCONFIGURED;
slotinfop->condition = AP_COND_UNKNOWN;
(void) hpc_nexus_control(
slotinfop->slot_hdl,
HPC_CTRL_DEV_UNCONFIGURED, NULL);
if (hpc_nexus_disconnect(
slotinfop->slot_hdl,
NULL, 0) == HPC_SUCCESS) {
slotinfop->rstate =
AP_RSTATE_DISCONNECTED;
}
cmn_err(CE_NOTE,
"pcihp (%s%d): card is UNCONFIGURED"
" in the slot %s (pci dev %x)",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name, pci_dev);
} else {
(void) hpc_nexus_control(
slotinfop->slot_hdl,
HPC_CTRL_DEV_UNCONFIG_FAILURE,
NULL);
rv = HPC_ERR_FAILED;
}
}
}
break;
case HPC_EVENT_SLOT_REMOVAL:
if (slotinfop->ostate != AP_OSTATE_UNCONFIGURED) {
slotinfop->condition = AP_COND_FAILED;
cmn_err(CE_WARN, "pcihp (%s%d): card is removed"
" from the slot %s",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name);
} else {
slotinfop->condition = AP_COND_UNKNOWN;
cmn_err(CE_NOTE, "pcihp (%s%d): card is removed"
" from the slot %s",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name);
}
slotinfop->rstate = AP_RSTATE_EMPTY;
break;
case HPC_EVENT_SLOT_POWER_ON:
PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): card is powered"
" on in the slot %s",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name));
slotinfop->rstate = AP_RSTATE_CONNECTED;
break;
case HPC_EVENT_SLOT_POWER_OFF:
PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): card is powered"
" off in the slot %s",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name));
slotinfop->rstate = AP_RSTATE_DISCONNECTED;
break;
case HPC_EVENT_SLOT_LATCH_SHUT:
cmn_err(CE_NOTE, "pcihp (%s%d): latch is shut for the slot %s",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name);
break;
case HPC_EVENT_SLOT_LATCH_OPEN:
cmn_err(CE_NOTE, "pcihp (%s%d): latch is open for the slot %s",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name);
break;
case HPC_EVENT_PROCESS_ENUM:
PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): processing ENUM#"
" for slot %s",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name));
mutex_exit(&slotinfop->slot_mutex);
rv = pcihp_enum_slot(pcihp_p, slotinfop, pci_dev,
PCIHP_HANDLE_ENUM, KM_SLEEP);
mutex_enter(&slotinfop->slot_mutex);
break;
case HPC_EVENT_BUS_ENUM:
PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): ENUM# is generated"
" on the bus (for slot %s ?)",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name));
mutex_exit(&slotinfop->slot_mutex);
rv = pcihp_handle_enum(pcihp_p, pci_dev, PCIHP_HANDLE_ENUM,
KM_SLEEP);
mutex_enter(&slotinfop->slot_mutex);
break;
case HPC_EVENT_SLOT_BLUE_LED_ON:
PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): Request To Turn On Blue "
"LED on the bus (for slot %s ?)",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name));
pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_SLOT_BLUE_LED_ON);
break;
case HPC_EVENT_DISABLE_ENUM:
if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_DISABLE_ENUM);
slotinfop->slot_flags &= ~PCIHP_SLOT_AUTO_CFG_EN;
}
break;
case HPC_EVENT_ENABLE_ENUM:
if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_ENABLE_ENUM);
slotinfop->slot_flags |= PCIHP_SLOT_AUTO_CFG_EN;
}
break;
case HPC_EVENT_SLOT_BLUE_LED_OFF:
PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): Request To Turn Off Blue "
"LED on the bus (for slot %s ?)",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name));
pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_SLOT_BLUE_LED_OFF);
break;
case HPC_EVENT_SLOT_NOT_HEALTHY:
PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): HEALTHY# signal is not OK"
" for this slot %s",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name));
slotinfop->slot_flags |= PCIHP_SLOT_NOT_HEALTHY;
slotinfop->condition = AP_COND_FAILED;
break;
case HPC_EVENT_SLOT_HEALTHY_OK:
PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): HEALTHY# signal is OK now"
" for this slot %s",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name));
slotinfop->slot_flags &= ~PCIHP_SLOT_NOT_HEALTHY;
slotinfop->condition = AP_COND_OK;
break;
case HPC_EVENT_SLOT_ATTN:
if (((slotinfop->slot_flags & PCIHP_SLOT_AUTO_CFG_EN) == 0) ||
(slotinfop->slot_flags & PCIHP_SLOT_DISABLED)) {
break;
}
if (slotinfop->ostate == AP_OSTATE_UNCONFIGURED)
hint = SE_INCOMING_RES;
else
hint = SE_OUTGOING_RES;
if (ddi_getprop(DDI_DEV_T_ANY, pcihp_p->dip, DDI_PROP_DONTPASS,
"inkernel-autoconfig", 0) == 0) {
pcihp_gen_sysevent(slotinfop->name, PCIHP_DR_REQ, hint,
pcihp_p->dip, KM_SLEEP);
break;
}
if ((slotinfop->ostate == AP_OSTATE_UNCONFIGURED) &&
(slotinfop->rstate != AP_RSTATE_EMPTY) &&
(slotinfop->condition != AP_COND_FAILED)) {
if (slotinfop->rstate == AP_RSTATE_DISCONNECTED) {
rv = hpc_nexus_connect(slotinfop->slot_hdl,
NULL, 0);
if (rv == HPC_SUCCESS)
slotinfop->rstate = AP_RSTATE_CONNECTED;
else
break;
}
rv = pcihp_configure_ap(pcihp_p, pci_dev);
} else if ((slotinfop->ostate == AP_OSTATE_CONFIGURED) &&
(slotinfop->rstate == AP_RSTATE_CONNECTED) &&
(slotinfop->condition != AP_COND_FAILED)) {
rv = pcihp_unconfigure_ap(pcihp_p, pci_dev);
if (rv != HPC_SUCCESS)
break;
rv = hpc_nexus_disconnect(slotinfop->slot_hdl,
NULL, 0);
if (rv == HPC_SUCCESS)
slotinfop->rstate = AP_RSTATE_DISCONNECTED;
}
break;
case HPC_EVENT_SLOT_POWER_FAULT:
cmn_err(CE_NOTE, "pcihp (%s%d): power-fault"
" for this slot %s",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name);
led_info.led = HPC_ATTN_LED;
led_info.state = HPC_LED_ON;
rv = hpc_nexus_control(slotinfop->slot_hdl,
HPC_CTRL_SET_LED_STATE, (caddr_t)&led_info);
if (slotinfop->rstate == AP_RSTATE_CONNECTED)
(void) hpc_nexus_disconnect(slotinfop->slot_hdl,
NULL, 0);
slotinfop->condition = AP_COND_FAILED;
pcihp_gen_sysevent(slotinfop->name, PCIHP_DR_AP_STATE_CHANGE,
SE_NO_HINT, pcihp_p->dip, KM_SLEEP);
break;
default:
cmn_err(CE_NOTE, "pcihp (%s%d): unknown event %x"
" for this slot %s",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip), event_mask,
slotinfop->name);
break;
}
mutex_exit(&slotinfop->slot_mutex);
(void) pcihp_get_soft_state(self, PCIHP_DR_SLOT_EXIT, &rval);
return (rv);
}
static int
pcihp_configure(dev_info_t *dip, void *hdl)
{
int pci_dev;
struct pcihp_config_ctrl *ctrl = (struct pcihp_config_ctrl *)hdl;
int rv;
pci_regspec_t *pci_rp;
int length;
if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
"reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
ctrl->rv = DDI_FAILURE;
ctrl->dip = dip;
return (DDI_WALK_TERMINATE);
}
pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
ddi_prop_free(pci_rp);
if (pci_dev == ctrl->pci_dev) {
if (ctrl->op == PCIHP_ONLINE) {
if (pcihp_check_status(dip) == B_FALSE) {
return (DDI_WALK_PRUNECHILD);
}
rv = ndi_devi_online(dip, NDI_ONLINE_ATTACH|NDI_CONFIG);
} else {
rv = ndi_devi_offline(dip, NDI_UNCONFIG);
}
if (rv != NDI_SUCCESS) {
ctrl->rv = rv;
ctrl->dip = dip;
if (!(ctrl->flags & PCIHP_CFG_CONTINUE))
return (DDI_WALK_TERMINATE);
}
}
return (DDI_WALK_PRUNECHILD);
}
static bool_t
pcihp_check_status(dev_info_t *dip)
{
char *status_prop;
bool_t rv = B_TRUE;
if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
"status", &status_prop) == DDI_PROP_SUCCESS) {
if (strcmp(status_prop, "disabled") == 0) {
rv = B_FALSE;
PCIHP_DEBUG((CE_NOTE,
"pcihp (%s%d): device is in disabled state",
ddi_driver_name(dip), ddi_get_instance(dip)));
} else if (strncmp(status_prop, "fail", 4) == 0) {
rv = B_FALSE;
cmn_err(CE_WARN,
"pcihp (%s%d): device is in fault state (%s)",
ddi_driver_name(dip), ddi_get_instance(dip),
status_prop);
}
ddi_prop_free(status_prop);
}
return (rv);
}
struct pcihp_find_ctrl {
uint_t device;
uint_t function;
dev_info_t *dip;
};
static dev_info_t *
pcihp_devi_find(dev_info_t *dip, uint_t device, uint_t function)
{
struct pcihp_find_ctrl ctrl;
ctrl.device = device;
ctrl.function = function;
ctrl.dip = NULL;
ndi_devi_enter(dip);
ddi_walk_devs(ddi_get_child(dip), pcihp_match_dev, (void *)&ctrl);
ndi_devi_exit(dip);
return (ctrl.dip);
}
static int
pcihp_match_dev(dev_info_t *dip, void *hdl)
{
struct pcihp_find_ctrl *ctrl = (struct pcihp_find_ctrl *)hdl;
pci_regspec_t *pci_rp;
int length;
int pci_dev;
int pci_func;
if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
"reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
ctrl->dip = NULL;
return (DDI_WALK_TERMINATE);
}
pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
ddi_prop_free(pci_rp);
if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
ctrl->dip = dip;
return (DDI_WALK_TERMINATE);
}
return (DDI_WALK_PRUNECHILD);
}
#if 0
static void
pcihp_probe_slot_state(dev_info_t *dip, int dev, hpc_slot_state_t *rstatep)
{
}
#endif
static int
pcihp_handle_enum(pcihp_t *pcihp_p, int favorite_pci_dev, int opcode,
int kmflag)
{
struct pcihp_slotinfo *slotinfop;
int pci_dev, rc, event_serviced = 0;
slotinfop = &pcihp_p->slotinfo[favorite_pci_dev];
if (slotinfop) {
rc = pcihp_enum_slot(pcihp_p, slotinfop, favorite_pci_dev,
opcode, kmflag);
if (rc != HPC_EVENT_UNCLAIMED) {
event_serviced = 1;
if (! pcihp_enum_scan_all) {
return (rc);
}
}
}
if (pcihp_p->bus_flags & PCIHP_BUS_ENUM_RADIAL)
goto enum_service_check;
for (pci_dev = 0; pci_dev < PCI_MAX_DEVS; pci_dev++) {
if (pci_dev != favorite_pci_dev) {
slotinfop = &pcihp_p->slotinfo[pci_dev];
if (slotinfop == NULL) {
continue;
}
if (!(slotinfop->slot_type & HPC_SLOT_TYPE_CPCI))
continue;
rc = pcihp_enum_slot(pcihp_p, slotinfop, pci_dev,
opcode, kmflag);
if (rc != HPC_EVENT_UNCLAIMED) {
event_serviced = 1;
if (! pcihp_enum_scan_all)
break;
}
}
}
enum_service_check:
if (event_serviced) {
return (rc);
}
return (HPC_EVENT_UNCLAIMED);
}
static int
pcihp_enum_slot(pcihp_t *pcihp_p, struct pcihp_slotinfo *slotinfop, int pci_dev,
int opcode, int kmflag)
{
ddi_acc_handle_t handle;
dev_info_t *dip, *new_child = NULL;
int result, rv = -1;
uint8_t hs_csr;
if (pcihp_config_setup(&dip, &handle, &new_child, pci_dev,
pcihp_p) != DDI_SUCCESS) {
return (HPC_EVENT_UNCLAIMED);
}
result = pcihp_get_hs_csr(slotinfop, handle, (uint8_t *)&hs_csr);
PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): hs_csr = %x, flags = %x",
ddi_driver_name(pcihp_p->dip), ddi_get_instance(pcihp_p->dip),
hs_csr, slotinfop->slot_flags));
pcihp_config_teardown(&handle, &new_child, pci_dev, pcihp_p);
if (result == PCIHP_SUCCESS) {
if ((hs_csr & HS_CSR_EIM) && (opcode == PCIHP_CLEAR_ENUM))
return (HPC_EVENT_UNCLAIMED);
if ((hs_csr & HS_CSR_INS) ||
(slotinfop->slot_flags & PCIHP_SLOT_ENUM_INS_PENDING)) {
PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): "
"Handle Insertion ENUM (INS) "
"on the bus (for slot %s ?)",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name));
if (opcode == PCIHP_CLEAR_ENUM)
pcihp_gen_sysevent(slotinfop->name,
PCIHP_DR_REQ,
SE_INCOMING_RES, pcihp_p->dip,
kmflag);
rv = pcihp_handle_enum_insertion(pcihp_p, pci_dev,
opcode, kmflag);
} else if ((hs_csr & HS_CSR_EXT) ||
(slotinfop->slot_flags & PCIHP_SLOT_ENUM_EXT_PENDING)) {
PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): "
"Handle Extraction ENUM (EXT) "
"on the bus (for slot %s ?)",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip),
slotinfop->name));
if (opcode == PCIHP_CLEAR_ENUM)
pcihp_gen_sysevent(slotinfop->name,
PCIHP_DR_REQ,
SE_OUTGOING_RES,
pcihp_p->dip,
kmflag);
rv = pcihp_handle_enum_extraction(pcihp_p, pci_dev,
opcode, kmflag);
}
if (opcode == PCIHP_CLEAR_ENUM) {
if (rv == PCIHP_SUCCESS)
rv = pci_dev;
else
rv = HPC_EVENT_UNCLAIMED;
}
}
return (rv);
}
static int
pcihp_handle_enum_extraction(pcihp_t *pcihp_p, int pci_dev, int opcode,
int kmflag)
{
struct pcihp_slotinfo *slotinfop;
int rv = PCIHP_FAILURE;
slotinfop = &pcihp_p->slotinfo[pci_dev];
pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_DISABLE_ENUM);
if (opcode == PCIHP_CLEAR_ENUM) {
slotinfop->slot_flags |= PCIHP_SLOT_ENUM_EXT_PENDING;
return (PCIHP_SUCCESS);
}
mutex_enter(&slotinfop->slot_mutex);
rv = pcihp_unconfigure_ap(pcihp_p, pci_dev);
mutex_exit(&slotinfop->slot_mutex);
if (rv != HPC_SUCCESS && rv != EBUSY) {
cmn_err(CE_NOTE, "%s%d: PCI device %x Failed on Unconfigure",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip), pci_dev);
}
if (rv == EBUSY)
cmn_err(CE_NOTE, "%s%d: PCI device %x Busy",
ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip), pci_dev);
if (rv) {
if (pcihp_cpci_blue_led)
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_SLOT_BLUE_LED_OFF);
}
pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_SLOT_UNCONFIGURE);
if (!rv) {
pcihp_gen_sysevent(slotinfop->name, PCIHP_DR_AP_STATE_CHANGE,
SE_HINT_REMOVE, pcihp_p->dip, kmflag);
}
pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_ENABLE_ENUM);
slotinfop->slot_flags &= ~PCIHP_SLOT_ENUM_EXT_PENDING;
return (rv);
}
static int
pcihp_handle_enum_insertion(pcihp_t *pcihp_p, int pci_dev, int opcode,
int kmflag)
{
struct pcihp_slotinfo *slotinfop;
int rv = PCIHP_FAILURE;
minor_t ap_minor;
major_t ap_major;
slotinfop = &pcihp_p->slotinfo[pci_dev];
slotinfop->hs_csr_location = 0;
pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_SLOT_CONFIGURE);
pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_DISABLE_ENUM);
if (opcode == PCIHP_CLEAR_ENUM) {
slotinfop->slot_flags |= PCIHP_SLOT_ENUM_INS_PENDING;
return (PCIHP_SUCCESS);
}
if ((slotinfop->slot_flags & PCIHP_SLOT_AUTO_CFG_EN) ==
PCIHP_SLOT_AUTO_CFG_EN) {
mutex_enter(&slotinfop->slot_mutex);
rv = pcihp_configure_ap(pcihp_p, pci_dev);
mutex_exit(&slotinfop->slot_mutex);
if (rv != HPC_SUCCESS) {
cmn_err(CE_NOTE, "%s%d: PCI device %x Failed on"
" Configure", ddi_driver_name(pcihp_p->dip),
ddi_get_instance(pcihp_p->dip), pci_dev);
if (pcihp_cpci_blue_led)
pcihp_hs_csr_op(pcihp_p, pci_dev,
HPC_EVENT_SLOT_BLUE_LED_ON);
}
pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_ENABLE_ENUM);
if (!rv) {
ap_major = ddi_driver_major(pcihp_p->dip);
ap_minor = PCIHP_AP_MINOR_NUM(
ddi_get_instance(pcihp_p->dip), pci_dev);
pcihp_create_occupant_props(pcihp_p->dip,
makedevice(ap_major, ap_minor), pci_dev);
pcihp_gen_sysevent(slotinfop->name,
PCIHP_DR_AP_STATE_CHANGE,
SE_HINT_INSERT, pcihp_p->dip, kmflag);
}
} else
rv = PCIHP_SUCCESS;
slotinfop->slot_flags &= ~PCIHP_SLOT_ENUM_INS_PENDING;
return (rv);
}
static int
pcihp_get_hs_csr(struct pcihp_slotinfo *slotinfop,
ddi_acc_handle_t config_handle, uint8_t *hs_csr)
{
if (slotinfop->hs_csr_location == -1)
return (PCIHP_FAILURE);
if (slotinfop->hs_csr_location == 0) {
slotinfop->hs_csr_location =
pcihp_get_hs_csr_location(config_handle);
if (slotinfop->hs_csr_location == -1)
return (PCIHP_FAILURE);
}
*hs_csr = pci_config_get8(config_handle, slotinfop->hs_csr_location);
return (PCIHP_SUCCESS);
}
static void
pcihp_set_hs_csr(struct pcihp_slotinfo *slotinfop,
ddi_acc_handle_t config_handle, uint8_t *hs_csr)
{
if (slotinfop->hs_csr_location == -1)
return;
if (slotinfop->hs_csr_location == 0) {
slotinfop->hs_csr_location =
pcihp_get_hs_csr_location(config_handle);
if (slotinfop->hs_csr_location == -1)
return;
}
pci_config_put8(config_handle, slotinfop->hs_csr_location, *hs_csr);
PCIHP_DEBUG((CE_NOTE, "hs_csr wrote %x, read %x", *hs_csr,
pci_config_get8(config_handle, slotinfop->hs_csr_location)));
}
static int
pcihp_get_hs_csr_location(ddi_acc_handle_t config_handle)
{
uint8_t cap_id;
uint_t cap_id_loc;
uint16_t status;
int location = -1;
#define PCI_STAT_ECP_SUPP 0x10
status = pci_config_get16(config_handle, PCI_CONF_STAT);
if (!(status & PCI_STAT_ECP_SUPP)) {
PCIHP_DEBUG((CE_NOTE, "No Ext Capabilities for device\n"));
return (-1);
}
cap_id_loc = pci_config_get8(config_handle, PCI_CONF_EXTCAP);
while ((cap_id_loc) && (cap_id_loc < PCI_CONF_HDR_SIZE)) {
cap_id = pci_config_get8(config_handle, cap_id_loc);
if (cap_id == CPCI_HOTSWAP_CAPID) {
location = cap_id_loc + PCI_ECP_HS_CSR;
break;
}
cap_id_loc = pci_config_get8(config_handle,
cap_id_loc + 1);
}
return (location);
}
static int
pcihp_add_dummy_reg_property(dev_info_t *dip,
uint_t bus, uint_t device, uint_t func)
{
pci_regspec_t dummy_reg;
bzero(&dummy_reg, sizeof (dummy_reg));
dummy_reg.pci_phys_hi = PCIHP_MAKE_REG_HIGH(bus, device, func, 0);
return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
"reg", (int *)&dummy_reg, sizeof (pci_regspec_t)/sizeof (int)));
}
static void
pcihp_hs_csr_op(pcihp_t *pcihp_p, int pci_dev, int event)
{
struct pcihp_slotinfo *slotinfop;
ddi_acc_handle_t config_handle;
dev_info_t *dip, *new_child = NULL;
uint8_t hs_csr;
int result;
slotinfop = &pcihp_p->slotinfo[pci_dev];
if (pcihp_config_setup(&dip, &config_handle, &new_child, pci_dev,
pcihp_p) != DDI_SUCCESS) {
return;
}
result = pcihp_get_hs_csr(slotinfop, config_handle, (uint8_t *)&hs_csr);
if ((result != PCIHP_SUCCESS) || (event == -1)) {
pcihp_config_teardown(&config_handle, &new_child, pci_dev,
pcihp_p);
return;
}
hs_csr &= 0xf;
switch (event) {
case HPC_EVENT_SLOT_BLUE_LED_ON:
hs_csr |= HS_CSR_LOO;
break;
case HPC_EVENT_SLOT_BLUE_LED_OFF:
hs_csr &= ~HS_CSR_LOO;
break;
case HPC_EVENT_SLOT_CONFIGURE:
hs_csr |= HS_CSR_INS;
break;
case HPC_EVENT_CLEAR_ENUM:
hs_csr |= (HS_CSR_INS | HS_CSR_EXT);
break;
case HPC_EVENT_SLOT_UNCONFIGURE:
hs_csr |= HS_CSR_EXT;
break;
case HPC_EVENT_ENABLE_ENUM:
hs_csr &= ~HS_CSR_EIM;
break;
case HPC_EVENT_DISABLE_ENUM:
hs_csr |= HS_CSR_EIM;
break;
case HPC_EVENT_SLOT_NOT_HEALTHY:
case HPC_EVENT_SLOT_HEALTHY_OK:
default:
break;
}
pcihp_set_hs_csr(slotinfop, config_handle, (uint8_t *)&hs_csr);
pcihp_config_teardown(&config_handle, &new_child, pci_dev, pcihp_p);
}
static int
pcihp_config_setup(dev_info_t **dip, ddi_acc_handle_t *handle,
dev_info_t **new_child, int pci_dev, pcihp_t *pcihp_p)
{
dev_info_t *pdip = pcihp_p->dip;
int bus, len, rc = DDI_SUCCESS;
struct pcihp_slotinfo *slotinfop;
hpc_slot_state_t rstate;
ddi_acc_hdl_t *hp;
pci_bus_range_t pci_bus_range;
slotinfop = &pcihp_p->slotinfo[pci_dev];
if (slotinfop->condition == AP_COND_FAILED) {
return (PCIHP_FAILURE);
}
if (hpc_nexus_control(slotinfop->slot_hdl, HPC_CTRL_GET_SLOT_STATE,
(caddr_t)&rstate) != 0) {
return (DDI_FAILURE);
}
if (rstate != HPC_SLOT_CONNECTED) {
return (DDI_FAILURE);
}
*new_child = NULL;
len = sizeof (pci_bus_range_t);
if (ddi_getlongprop_buf(DDI_DEV_T_ANY, pdip,
0, "bus-range",
(caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
return (PCIHP_FAILURE);
}
bus = pci_bus_range.lo;
if (ndi_devi_alloc(pdip, DEVI_PSEUDO_NEXNAME,
(pnode_t)DEVI_SID_NODEID, dip) != NDI_SUCCESS) {
PCIHP_DEBUG((CE_NOTE, "Failed to alloc probe node\n"));
return (PCIHP_FAILURE);
}
if (pcihp_add_dummy_reg_property(*dip, bus,
pci_dev, 0) != DDI_SUCCESS) {
(void) ndi_devi_free(*dip);
return (PCIHP_FAILURE);
}
if (pci_config_setup(*dip, handle) != DDI_SUCCESS) {
cmn_err(CE_WARN, "Cannot set config space map for"
" pci device number %d", pci_dev);
(void) ndi_devi_free(*dip);
return (PCIHP_FAILURE);
}
if (pcihp_indirect_map(*dip) == DDI_SUCCESS) {
if (pci_config_get16(*handle, 0) == 0xffff) {
pci_config_teardown(handle);
(void) ndi_devi_free(*dip);
return (PCIHP_FAILURE);
}
} else {
hp = impl_acc_hdl_get(*handle);
if (ddi_peek16(*dip, (int16_t *)(hp->ah_addr),
(int16_t *)0) != DDI_SUCCESS) {
#ifdef DEBUG
cmn_err(CE_WARN, "Cannot Map PCI config space for "
"device number %d", pci_dev);
#endif
pci_config_teardown(handle);
(void) ndi_devi_free(*dip);
return (PCIHP_FAILURE);
}
}
*new_child = *dip;
return (rc);
}
static void
pcihp_config_teardown(ddi_acc_handle_t *handle,
dev_info_t **new_child, int pci_dev, pcihp_t *pcihp_p)
{
struct pcihp_slotinfo *slotinfop = &pcihp_p->slotinfo[pci_dev];
pci_config_teardown(handle);
if (*new_child) {
(void) ndi_devi_free(*new_child);
if (slotinfop->ostate != AP_OSTATE_CONFIGURED)
slotinfop->hs_csr_location = 0;
}
}
static int
pcihp_get_board_type(struct pcihp_slotinfo *slotinfop)
{
hpc_board_type_t board_type;
if (hpc_nexus_control(slotinfop->slot_hdl, HPC_CTRL_GET_BOARD_TYPE,
(caddr_t)&board_type) != 0) {
cmn_err(CE_WARN, "Cannot Get Board Type..");
return (-1);
}
if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
if (slotinfop->hs_csr_location > 0)
board_type = HPC_BOARD_CPCI_FULL_HS;
else {
if (board_type == HPC_BOARD_CPCI_HS) {
if (slotinfop->hs_csr_location == -1)
board_type = HPC_BOARD_CPCI_BASIC_HS;
}
if (board_type == HPC_BOARD_UNKNOWN) {
if (slotinfop->hs_csr_location == -1) {
board_type = pcihp_cpci_board_type;
} else if (slotinfop->hs_csr_location != 0) {
board_type = HPC_BOARD_CPCI_FULL_HS;
}
}
}
if (board_type == HPC_BOARD_CPCI_NON_HS)
slotinfop->slot_flags |= PCIHP_SLOT_DEV_NON_HOTPLUG;
else
slotinfop->slot_flags &= ~PCIHP_SLOT_DEV_NON_HOTPLUG;
}
return (board_type);
}
static void
pcihp_gen_sysevent(char *slot_name, int event_sub_class, int hint,
dev_info_t *self, int kmflag)
{
int err;
char *ev_subclass = NULL;
sysevent_id_t eid;
nvlist_t *ev_attr_list = NULL;
char attach_pnt[MAXPATHLEN];
(void) strcpy(attach_pnt, PCIHP_DEVICES_STR);
(void) ddi_pathname(self, attach_pnt + strlen(PCIHP_DEVICES_STR));
(void) strcat(attach_pnt, ":");
(void) strcat(attach_pnt, slot_name);
err = nvlist_alloc(&ev_attr_list, NV_UNIQUE_NAME_TYPE, kmflag);
if (err != 0) {
cmn_err(CE_WARN,
"%s%d: Failed to allocate memory "
"for event attributes%s", ddi_driver_name(self),
ddi_get_instance(self), ESC_DR_AP_STATE_CHANGE);
return;
}
switch (event_sub_class) {
case PCIHP_DR_AP_STATE_CHANGE:
ev_subclass = ESC_DR_AP_STATE_CHANGE;
switch (hint) {
case SE_NO_HINT:
case SE_HINT_INSERT:
case SE_HINT_REMOVE:
err = nvlist_add_string(ev_attr_list, DR_HINT,
SE_HINT2STR(hint));
if (err != 0) {
cmn_err(CE_WARN, "%s%d: Failed to add attr [%s]"
" for %s event", ddi_driver_name(self),
ddi_get_instance(self),
DR_HINT, ESC_DR_AP_STATE_CHANGE);
nvlist_free(ev_attr_list);
return;
}
break;
default:
cmn_err(CE_WARN, "%s%d: Unknown hint on sysevent",
ddi_driver_name(self), ddi_get_instance(self));
nvlist_free(ev_attr_list);
return;
}
break;
case PCIHP_DR_REQ:
ev_subclass = ESC_DR_REQ;
switch (hint) {
case SE_INVESTIGATE_RES:
case SE_INCOMING_RES:
case SE_OUTGOING_RES:
err = nvlist_add_string(ev_attr_list, DR_REQ_TYPE,
SE_REQ2STR(hint));
if (err != 0) {
cmn_err(CE_WARN,
"%s%d: Failed to add attr [%s] "
"for %s event", ddi_driver_name(self),
ddi_get_instance(self),
DR_REQ_TYPE, ESC_DR_REQ);
nvlist_free(ev_attr_list);
return;
}
break;
default:
cmn_err(CE_WARN, "%s%d: Unknown hint on sysevent",
ddi_driver_name(self), ddi_get_instance(self));
nvlist_free(ev_attr_list);
return;
}
break;
default:
cmn_err(CE_WARN, "%s%d: Unknown Event subclass",
ddi_driver_name(self), ddi_get_instance(self));
nvlist_free(ev_attr_list);
return;
}
err = nvlist_add_string(ev_attr_list, DR_AP_ID, attach_pnt);
if (err != 0) {
cmn_err(CE_WARN, "%s%d: Failed to add attr [%s] for %s event",
ddi_driver_name(self), ddi_get_instance(self),
DR_AP_ID, EC_DR);
nvlist_free(ev_attr_list);
return;
}
err = ddi_log_sysevent(self, DDI_VENDOR_SUNW, EC_DR,
ev_subclass, ev_attr_list, &eid,
((kmflag == KM_SLEEP) ? DDI_SLEEP : DDI_NOSLEEP));
if (err != 0) {
cmn_err(CE_WARN, "%s%d: Failed to log %s event",
ddi_driver_name(self), ddi_get_instance(self), EC_DR);
}
nvlist_free(ev_attr_list);
}
int
pcihp_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
int flags, char *name, caddr_t valuep, int *lengthp)
{
int pci_dev;
if (dev == DDI_DEV_T_ANY)
goto skip;
if (strcmp(name, "pci-occupant") == 0) {
pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(getminor(dev));
pcihp_create_occupant_props(dip, dev, pci_dev);
}
skip:
return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
}
static int
pcihp_indirect_map(dev_info_t *dip)
{
#if defined(__sparc)
int rc = DDI_FAILURE;
if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip), 0,
PCI_DEV_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE)
rc = DDI_SUCCESS;
else
if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip),
0, PCI_BUS_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE)
rc = DDI_SUCCESS;
return (rc);
#else
return (DDI_SUCCESS);
#endif
}