#include <sys/types.h>
#include <sys/cmn_err.h>
#include <sys/kmem.h>
#include <sys/errno.h>
#include <sys/cpuvar.h>
#include <sys/open.h>
#include <sys/stat.h>
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/modctl.h>
#include <sys/ksynch.h>
#include <sys/pci.h>
#include <sys/serengeti.h>
#include <sys/sghsc.h>
#include <sys/promif.h>
int sghsc_configure_ack = 0;
int cpci_enable = 1;
#ifdef DEBUG
#define SGHSC_DEBUG
#endif
#ifdef SGHSC_DEBUG
int sghsc_debug = 0;
#define DEBUGF(level, args) \
{ if (sghsc_debug >= (level)) cmn_err args; }
#define DEBUGON sghsc_debug = 3
#define DEBUGOFF sghsc_debug = 0
#else
#define DEBUGF(level, args)
#define DEBUGON
#define DEBUGOFF
#endif
static void *sghsc_state;
static sghsc_rb_head_t sghsc_rb_header;
static kthread_t *sghsc_event_thread;
static kmutex_t sghsc_event_thread_mutex;
static kcondvar_t sghsc_event_thread_cv;
static boolean_t sghsc_event_thread_exit = B_FALSE;
static struct cb_ops sghsc_cb_ops = {
nodev,
nodev,
nodev,
nodev,
nodev,
nodev,
nodev,
nodev,
nodev,
nodev,
nodev,
nochpoll,
ddi_prop_op,
0,
D_NEW | D_MP,
CB_REV,
nodev,
nodev
};
static int sghsc_attach(dev_info_t *, ddi_attach_cmd_t);
static int sghsc_detach(dev_info_t *, ddi_detach_cmd_t);
static struct dev_ops sghsc_dev_ops = {
DEVO_REV,
0,
nulldev,
nulldev,
nulldev,
sghsc_attach,
sghsc_detach,
nodev,
&sghsc_cb_ops,
(struct bus_ops *)0,
NULL,
ddi_quiesce_not_needed,
};
static struct modldrv modldrv = {
&mod_driverops,
"Serengeti CompactPCI HSC",
&sghsc_dev_ops,
};
static struct modlinkage modlinkage = {
MODREV_1,
&modldrv,
NULL
};
static int sghsc_connect(caddr_t, hpc_slot_t slot, void *, uint_t);
static int sghsc_disconnect(caddr_t, hpc_slot_t, void *, uint_t);
static int sghsc_control(caddr_t, hpc_slot_t, int, caddr_t);
static int sghsc_register_slots(sghsc_t *, int);
static int sghsc_get_slotnum(sghsc_t *, hpc_slot_t);
static int sghsc_scctl(int, int, int, int, int *);
static void sghsc_freemem(sghsc_t *);
static hpc_slot_t sghsc_find_sloth(int, int, int);
static sghsc_t *sghsc_find_softstate(int, int, int);
static int sghsc_led_state(sghsc_t *, hpc_slot_t, int, hpc_led_info_t *);
static void sghsc_rb_setup(sghsc_rb_head_t *);
static void sghsc_rb_teardown(sghsc_rb_head_t *);
static int sghsc_rb_get(sghsc_rb_head_t *, sghsc_event_t *);
static int sghsc_rb_put(sghsc_rb_head_t *, sghsc_event_t *);
int sghsc_mbx_timeout = SGHSC_MBX_TIMEOUT;
static int sghsc_maxinst;
static sdesc_t four_slot_wib_bd[] = {
0, 6, 1, HPC_SLOT_TYPE_CPCI,
1, 0, 2, 0,
1, 0, 0, 0,
0, 7, 1, HPC_SLOT_TYPE_CPCI
};
static sdesc_t four_slot_bd[] = {
0, 6, 1, HPC_SLOT_TYPE_CPCI,
1, 6, 1, HPC_SLOT_TYPE_CPCI,
0, 7, 1, HPC_SLOT_TYPE_CPCI,
1, 7, 1, HPC_SLOT_TYPE_CPCI
};
static sdesc_t six_slot_wib_bd[] = {
0, 6, 1, HPC_SLOT_TYPE_CPCI,
1, 0, 2, 0,
1, 0, 0, 0,
0, 7, 1, HPC_SLOT_TYPE_CPCI,
0, 7, 2, HPC_SLOT_TYPE_CPCI,
0, 7, 3, HPC_SLOT_TYPE_CPCI
};
static sdesc_t six_slot_bd[] = {
0, 6, 1, HPC_SLOT_TYPE_CPCI,
1, 6, 1, HPC_SLOT_TYPE_CPCI,
0, 7, 1, HPC_SLOT_TYPE_CPCI,
0, 7, 2, HPC_SLOT_TYPE_CPCI,
1, 7, 1, HPC_SLOT_TYPE_CPCI,
1, 7, 2, HPC_SLOT_TYPE_CPCI
};
int sghsc_event_init = 0;
static uint_t sghsc_event_handler(char *);
static void sghsc_event_thread_code(void);
static sbbc_msg_t event_msg;
static sghsc_event_t payload;
static kmutex_t sghsc_event_lock;
int sghsc_event_state;
int
_init(void)
{
int error;
sghsc_maxinst = 0;
if ((error = ddi_soft_state_init(&sghsc_state,
sizeof (sghsc_t), 1)) != 0)
return (error);
if ((error = mod_install(&modlinkage)) != 0) {
ddi_soft_state_fini(&sghsc_state);
return (error);
}
sghsc_rb_header.buf = NULL;
mutex_init(&sghsc_event_thread_mutex, NULL, MUTEX_DRIVER, NULL);
cv_init(&sghsc_event_thread_cv, NULL, CV_DRIVER, NULL);
return (error);
}
int
_fini(void)
{
int error;
if ((error = mod_remove(&modlinkage)) != 0)
return (error);
(void) sbbc_mbox_unreg_intr(MBOX_EVENT_CPCI_ENUM, sghsc_event_handler);
mutex_destroy(&sghsc_event_lock);
if (sghsc_event_thread != NULL) {
mutex_enter(&sghsc_event_thread_mutex);
sghsc_event_thread_exit = B_TRUE;
cv_signal(&sghsc_event_thread_cv);
cv_wait(&sghsc_event_thread_cv, &sghsc_event_thread_mutex);
mutex_exit(&sghsc_event_thread_mutex);
sghsc_event_thread = NULL;
}
mutex_destroy(&sghsc_event_thread_mutex);
cv_destroy(&sghsc_event_thread_cv);
sghsc_rb_teardown(&sghsc_rb_header);
sghsc_maxinst = 0;
ddi_soft_state_fini(&sghsc_state);
return (0);
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
static int
sghsc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
sghsc_t *sghsc;
uint_t instance;
uint_t portid;
int rc;
int board_type = 0;
instance = ddi_get_instance(dip);
switch (cmd) {
case DDI_RESUME:
return (DDI_SUCCESS);
case DDI_ATTACH:
break;
default:
cmn_err(CE_WARN, "sghsc%d: unsupported cmd %d",
instance, cmd);
return (DDI_FAILURE);
}
DEBUGF(1, (CE_NOTE, "attach sghsc driver. "));
portid = (uint_t)ddi_getprop(DDI_DEV_T_ANY, dip,
DDI_PROP_DONTPASS, "portid", -1);
if (!SG_PORTID_IS_IO_TYPE(portid)) {
cmn_err(CE_WARN, "sghsc%d: property %s out of bounds %d\n",
instance, "portid", portid);
return (DDI_FAILURE);
}
if (ddi_soft_state_zalloc(sghsc_state, instance) != DDI_SUCCESS)
return (DDI_FAILURE);
sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance);
sghsc->sghsc_dip = dip;
sghsc->sghsc_instance = instance;
sghsc->sghsc_board = SG_PORTID_TO_BOARD_NUM(portid);
sghsc->sghsc_node_id = SG_PORTID_TO_NODEID(portid);
sghsc->sghsc_portid = portid;
ddi_set_driver_private(dip, sghsc);
mutex_init(SGHSC_MUTEX(sghsc), NULL, MUTEX_DRIVER, NULL);
rc = sghsc_scctl(SGHSC_GET_NUM_SLOTS, sghsc->sghsc_node_id,
sghsc->sghsc_board, 0, (int *)&sghsc->sghsc_num_slots);
if (rc) {
cmn_err(CE_WARN, "sghsc%d: unable to size node %d / board %d",
instance, sghsc->sghsc_node_id, sghsc->sghsc_board);
goto cleanup_stage2;
}
DEBUGF(1, (CE_NOTE, "sghsc%d: node %d / board %d has %d slots",
instance, sghsc->sghsc_node_id, sghsc->sghsc_board,
sghsc->sghsc_num_slots));
switch (sghsc->sghsc_num_slots) {
case 4:
case 6:
rc = 0;
break;
default:
rc = -1;
break;
}
if (rc) {
cmn_err(CE_WARN, "sghsc%d: wrong num of slots %d for node %d"
" / board %d", instance, sghsc->sghsc_num_slots,
sghsc->sghsc_node_id, sghsc->sghsc_board);
goto cleanup_stage2;
}
rc = sghsc_scctl(SGHSC_GET_CPCI_BOARD_TYPE, sghsc->sghsc_node_id,
sghsc->sghsc_board, 0, &board_type);
DEBUGF(1, (CE_NOTE, "sghsc%d: node %d / board %d is type %d",
instance, sghsc->sghsc_node_id, sghsc->sghsc_board, board_type));
sghsc->sghsc_slot_table = (sghsc_slot_t *)kmem_zalloc((size_t)
(sghsc->sghsc_num_slots * sizeof (sghsc_slot_t)), KM_SLEEP);
if (sghsc_register_slots(sghsc, board_type) != DDI_SUCCESS) {
DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_register_slots"
" failed for node %d / board %d",
instance, sghsc->sghsc_node_id, sghsc->sghsc_board));
goto cleanup;
}
if (sghsc_connect((caddr_t)sghsc, 0, 0, SGHSC_ALL_SLOTS_ENABLE)
!= HPC_SUCCESS) {
DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_connect failed for"
" node %d / board %d", instance, sghsc->sghsc_node_id,
sghsc->sghsc_board));
goto cleanup;
}
if (sghsc_event_init == 0) {
sghsc_rb_setup(&sghsc_rb_header);
mutex_init(&sghsc_event_lock, NULL, MUTEX_DRIVER, NULL);
event_msg.msg_buf = (caddr_t)&payload;
event_msg.msg_len = sizeof (payload);
rc = sbbc_mbox_reg_intr(MBOX_EVENT_CPCI_ENUM,
sghsc_event_handler, &event_msg,
(uint_t *)&sghsc_event_state, &sghsc_event_lock);
if (rc != 0)
cmn_err(CE_WARN, "sghsc%d: failed to register events"
" for node %d", instance, sghsc->sghsc_node_id);
sghsc_event_init = 1;
if (sghsc_event_thread == NULL) {
DEBUGF(1, (CE_NOTE, "sghsc: creating event thread"
"for node %d", sghsc->sghsc_node_id));
sghsc_event_thread = thread_create(NULL, 0,
sghsc_event_thread_code, NULL, 0, &p0,
TS_RUN, minclsyspri);
}
}
ddi_report_dev(dip);
sghsc_maxinst++;
sghsc->sghsc_valid = 1;
return (DDI_SUCCESS);
cleanup:
sghsc_freemem(sghsc);
cleanup_stage2:
DEBUGF(1, (CE_NOTE, "sghsc%d: attach failed for node %d",
instance, sghsc->sghsc_node_id));
mutex_destroy(SGHSC_MUTEX(sghsc));
ddi_set_driver_private(dip, NULL);
ddi_soft_state_free(sghsc_state, instance);
return (DDI_FAILURE);
}
static int
sghsc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
sghsc_t *sghsc;
int instance;
int i;
instance = ddi_get_instance(dip);
sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance);
if (sghsc == NULL)
return (DDI_FAILURE);
switch (cmd) {
case DDI_DETACH:
for (i = 0; i < sghsc->sghsc_num_slots; i++) {
if (sghsc->sghsc_slot_table[i].handle &&
hpc_bus_registered(
sghsc->sghsc_slot_table[i].handle)) {
cmn_err(CE_WARN,
"sghsc: must detach buses first");
return (DDI_FAILURE);
}
}
if (mutex_tryenter(&sghsc_event_thread_mutex) == 0)
return (EBUSY);
sghsc->sghsc_valid = 0;
sghsc_freemem(sghsc);
mutex_destroy(SGHSC_MUTEX(sghsc));
ddi_set_driver_private(dip, NULL);
ddi_soft_state_free(sghsc_state, instance);
if (instance == (sghsc_maxinst - 1))
sghsc_maxinst--;
mutex_exit(&sghsc_event_thread_mutex);
return (DDI_SUCCESS);
case DDI_SUSPEND:
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
}
static int
sghsc_register_slots(sghsc_t *sghsc, int board_type)
{
int i;
dev_info_t *dip = sghsc->sghsc_dip;
hpc_slot_ops_t *slot_ops = NULL;
sdesc_t *slot2bus;
DEBUGF(1, (CE_NOTE, "sghsc%d: slot table has %d entries for "
"node %d / board %d", sghsc->sghsc_instance, sghsc->sghsc_num_slots,
sghsc->sghsc_node_id, sghsc->sghsc_board));
if ((cpci_enable == 0) || (sg_prom_cpci_dr_check() != 0))
return (DDI_SUCCESS);
if (sghsc->sghsc_slot_table == NULL)
return (DDI_FAILURE);
switch (board_type) {
case NO_BOARD_TYPE:
case CPCI_BOARD:
case SP_CPCI_BOARD:
switch (sghsc->sghsc_num_slots) {
case 4:
slot2bus = four_slot_bd;
break;
case 6:
slot2bus = six_slot_bd;
break;
default:
cmn_err(CE_WARN, "sghsc%d: unknown size %d for"
" node %d / board %d",
sghsc->sghsc_instance,
sghsc->sghsc_num_slots,
sghsc->sghsc_node_id, sghsc->sghsc_board);
break;
}
break;
case WCI_CPCI_BOARD:
slot2bus = four_slot_wib_bd;
break;
case WCI_SP_CPCI_BOARD:
slot2bus = six_slot_wib_bd;
break;
default:
cmn_err(CE_WARN, "sghsc%d: unknown type %d for"
" node %d / board %d", sghsc->sghsc_instance,
board_type, sghsc->sghsc_node_id,
sghsc->sghsc_board);
return (DDI_FAILURE);
}
for (i = 0; i < sghsc->sghsc_num_slots; i++) {
char *nexuspath;
hpc_slot_info_t *slot_info;
uint32_t base_id;
base_id = sghsc->sghsc_portid & SGHSC_SAFARI_ID_EVEN;
nexuspath = sghsc->sghsc_slot_table[i].nexus_path;
(void) sprintf(nexuspath, SGHSC_PATH, sghsc->sghsc_node_id,
(base_id + slot2bus[i].agent_delta), slot2bus[i].off);
sghsc->sghsc_slot_table[i].pci_device_num =
slot2bus[i].pcidev;
slot_info = &sghsc->sghsc_slot_table[i].slot_info;
slot_info->version = HPC_SLOT_INFO_VERSION;
slot_info->slot_type = slot2bus[i].slot_type;
slot_info->pci_slot_capabilities = HPC_SLOT_64BITS;
slot_info->pci_dev_num = slot2bus[i].pcidev;
(void) sprintf(slot_info->pci_slot_name,
"sg%dslot%d", sghsc->sghsc_board, i);
DEBUGF(1, (CE_NOTE, "pci_slot_name is %s at pci_dev_num %d"
" on node %d / board %d", slot_info->pci_slot_name,
slot_info->pci_dev_num, sghsc->sghsc_node_id,
sghsc->sghsc_board));
slot_ops = hpc_alloc_slot_ops(KM_SLEEP);
sghsc->sghsc_slot_table[i].slot_ops = slot_ops;
slot_ops->hpc_version = HPC_SLOT_OPS_VERSION;
slot_ops->hpc_op_connect = sghsc_connect;
slot_ops->hpc_op_disconnect = sghsc_disconnect;
slot_ops->hpc_op_insert = nodev;
slot_ops->hpc_op_remove = nodev;
slot_ops->hpc_op_control = sghsc_control;
sghsc->sghsc_slot_table[i].flags = SGHSC_SLOT_AUTO_CFG_EN;
sghsc->sghsc_slot_table[i].board_type = HPC_BOARD_UNKNOWN;
if (slot_info->slot_type != HPC_SLOT_TYPE_CPCI) {
DEBUGF(1, (CE_NOTE, "sghsc_register_slots: "
"slot %d is non-cpci", i));
continue;
}
if ((hpc_slot_register(dip, nexuspath, slot_info,
&sghsc->sghsc_slot_table[i].handle,
slot_ops, (caddr_t)sghsc, 0)) != 0) {
cmn_err(CE_WARN, "sghsc%d: Slot <%s> failed during HPS"
" registration process for node %d / board %d",
sghsc->sghsc_instance, slot_info->pci_slot_name,
sghsc->sghsc_node_id, sghsc->sghsc_board);
return (DDI_FAILURE);
}
}
DEBUGF(1, (CE_NOTE, "sghsc registered successfully for"
" node %d / board %d", sghsc->sghsc_node_id, sghsc->sghsc_board));
return (DDI_SUCCESS);
}
static int
sghsc_connect(caddr_t op_arg, hpc_slot_t sloth, void *data,
uint_t flag)
{
int i = 0;
sghsc_t *sghsc = (sghsc_t *)op_arg;
int rc;
int result;
int slot_num = sghsc_get_slotnum(sghsc, sloth);
switch (flag) {
case SGHSC_ALL_SLOTS_ENABLE:
for (i = 0; i < sghsc->sghsc_num_slots; i++) {
sghsc->sghsc_slot_table[i].slot_status =
HPC_SLOT_EMPTY;
}
return (HPC_SUCCESS);
}
if (slot_num == -1)
return (HPC_ERR_INVALID);
SGHSC_MUTEX_ENTER(sghsc);
DEBUGF(1, (CE_NOTE, "sghsc%d: connecting logical slot%d for"
" node %d / board %d", sghsc->sghsc_instance, slot_num,
sghsc->sghsc_node_id, sghsc->sghsc_board));
rc = sghsc_scctl(SGHSC_GET_SLOT_STATUS, sghsc->sghsc_node_id,
sghsc->sghsc_board, slot_num, &result);
if (rc == ETIMEDOUT) {
SGHSC_MUTEX_EXIT(sghsc);
return (HPC_ERR_FAILED);
}
if (rc) {
cmn_err(CE_NOTE, "sghsc%d: unable to stat slot %d for"
" node %d / board %d", sghsc->sghsc_instance, slot_num,
sghsc->sghsc_node_id, sghsc->sghsc_board);
sghsc->sghsc_slot_table[i].slot_status = HPC_SLOT_UNKNOWN;
SGHSC_MUTEX_EXIT(sghsc);
return (HPC_ERR_FAILED);
}
if ((result >> CPCI_STAT_SLOT_EMPTY_SHIFT) & ONE_BIT) {
sghsc->sghsc_slot_table[i].slot_status = HPC_SLOT_EMPTY;
SGHSC_MUTEX_EXIT(sghsc);
return (HPC_ERR_FAILED);
}
rc = sghsc_scctl(SGHSC_SET_SLOT_POWER_ON, sghsc->sghsc_node_id,
sghsc->sghsc_board, slot_num, &result);
if (rc) {
cmn_err(CE_WARN, "sghsc%d: unable to poweron slot %d for"
" node %d / board %d", sghsc->sghsc_instance,
slot_num, sghsc->sghsc_node_id, sghsc->sghsc_board);
SGHSC_MUTEX_EXIT(sghsc);
return (HPC_ERR_FAILED);
} else {
sghsc->sghsc_slot_table[slot_num].slot_status =
HPC_SLOT_CONNECTED;
}
SGHSC_MUTEX_EXIT(sghsc);
return (HPC_SUCCESS);
}
static int
sghsc_disconnect(caddr_t op_arg, hpc_slot_t sloth, void *data,
uint_t flag)
{
sghsc_t *sghsc = (sghsc_t *)op_arg;
int rc;
int result;
int slot_num = sghsc_get_slotnum(sghsc, sloth);
switch (flag) {
case SGHSC_ALL_SLOTS_DISABLE:
return (HPC_SUCCESS);
}
if (slot_num == -1)
return (HPC_ERR_INVALID);
SGHSC_MUTEX_ENTER(sghsc);
if (sghsc->sghsc_slot_table[slot_num].slot_status !=
HPC_SLOT_CONNECTED) {
SGHSC_MUTEX_EXIT(sghsc);
return (HPC_SUCCESS);
}
rc = sghsc_scctl(SGHSC_SET_SLOT_POWER_OFF, sghsc->sghsc_node_id,
sghsc->sghsc_board, slot_num, &result);
if (rc) {
cmn_err(CE_WARN, "sghsc%d: unable to poweroff slot %d for"
" node %d / board %d", sghsc->sghsc_instance,
slot_num, sghsc->sghsc_node_id, sghsc->sghsc_board);
SGHSC_MUTEX_EXIT(sghsc);
return (HPC_ERR_FAILED);
} else {
sghsc->sghsc_slot_table[slot_num].slot_status =
HPC_SLOT_DISCONNECTED;
}
SGHSC_MUTEX_EXIT(sghsc);
return (HPC_SUCCESS);
}
static int
sghsc_control(caddr_t op_arg, hpc_slot_t sloth, int request,
caddr_t arg)
{
sghsc_t *sghsc = (sghsc_t *)op_arg;
int slot = sghsc_get_slotnum(sghsc, sloth);
int error = HPC_SUCCESS;
int rc;
int result;
if ((sghsc == NULL) || (slot < 0) ||
(slot >= sghsc->sghsc_num_slots)) {
cmn_err(CE_WARN, "sghsc%d: sghsc_control fails with slot = %d"
" max = %d, sloth = 0x%p for node %d / board %d",
sghsc->sghsc_instance, slot, sghsc->sghsc_num_slots,
sloth, sghsc->sghsc_node_id, sghsc->sghsc_board);
return (HPC_ERR_INVALID);
}
SGHSC_MUTEX_ENTER(sghsc);
switch (request) {
case HPC_CTRL_GET_LED_STATE: {
hpc_led_info_t *ledinfo;
ledinfo = (hpc_led_info_t *)arg;
DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
" HPC_CTRL_GET_LED_STATE for node %d / board %d slot %d",
sghsc->sghsc_instance, sghsc->sghsc_node_id,
sghsc->sghsc_board, slot));
switch (ledinfo->led) {
case HPC_POWER_LED:
case HPC_ATTN_LED:
case HPC_FAULT_LED:
case HPC_ACTIVE_LED:
error = sghsc_led_state(sghsc, sloth,
HPC_CTRL_GET_LED_STATE, ledinfo);
break;
default:
cmn_err(CE_WARN, "sghsc%d: sghsc_control"
" HPC_CTRL_GET_LED_STATE "
" unknown led state %d for node %d / board %d"
" slot handle 0x%p", sghsc->sghsc_instance,
ledinfo->led, sghsc->sghsc_node_id,
sghsc->sghsc_board, sloth);
error = HPC_ERR_NOTSUPPORTED;
break;
}
break;
}
case HPC_CTRL_SET_LED_STATE: {
hpc_led_info_t *ledinfo;
ledinfo = (hpc_led_info_t *)arg;
DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
" HPC_CTRL_SET_LED_STATE for node %d / board %d slot %d",
sghsc->sghsc_instance, sghsc->sghsc_node_id,
sghsc->sghsc_board, slot));
switch (ledinfo->led) {
case HPC_POWER_LED:
case HPC_ATTN_LED:
case HPC_FAULT_LED:
case HPC_ACTIVE_LED:
DEBUGF(1, (CE_NOTE, "sghsc:"
" LED writing not supported "));
break;
default:
DEBUGF(1, (CE_NOTE, "sghsc:"
" LED not supported "));
error = HPC_ERR_NOTSUPPORTED;
}
break;
}
case HPC_CTRL_GET_SLOT_STATE: {
DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
" HPC_CTRL_GET_SLOT_STATE for node %d / board %d slot %d",
sghsc->sghsc_instance, sghsc->sghsc_node_id,
sghsc->sghsc_board, slot));
rc = sghsc_scctl(SGHSC_GET_SLOT_STATUS, sghsc->sghsc_node_id,
sghsc->sghsc_board, slot, &result);
if (rc == ETIMEDOUT) {
error = HPC_ERR_FAILED;
break;
}
if (rc) {
cmn_err(CE_NOTE, "sghsc%d: unable to stat slot %d for "
"node %d / board %d", sghsc->sghsc_instance, slot,
sghsc->sghsc_node_id, sghsc->sghsc_board);
sghsc->sghsc_slot_table[slot].slot_status =
HPC_SLOT_UNKNOWN;
*(hpc_slot_state_t *)arg = HPC_SLOT_UNKNOWN;
break;
}
if ((result >> CPCI_STAT_SLOT_EMPTY_SHIFT) & ONE_BIT) {
sghsc->sghsc_slot_table[slot].slot_status =
HPC_SLOT_EMPTY;
} else if ((result >> CPCI_STAT_POWER_ON_SHIFT) & ONE_BIT) {
sghsc->sghsc_slot_table[slot].slot_status =
HPC_SLOT_CONNECTED;
} else if (sghsc->sghsc_slot_table[slot].slot_status ==
HPC_SLOT_EMPTY ||
sghsc->sghsc_slot_table[slot].slot_status ==
HPC_SLOT_UNKNOWN) {
sghsc->sghsc_slot_table[slot].slot_status =
HPC_SLOT_DISCONNECTED;
}
*(hpc_slot_state_t *)arg =
sghsc->sghsc_slot_table[slot].slot_status;
break;
}
case HPC_CTRL_DEV_CONFIGURED:
DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
" HPC_CTRL_DEV_CONFIGURED for node %d / board %d slot %d",
sghsc->sghsc_instance, sghsc->sghsc_node_id,
sghsc->sghsc_board, slot));
if (sghsc_configure_ack)
cmn_err(CE_NOTE, "sghsc%d:"
" node %d / board %d slot %d configured",
sghsc->sghsc_instance, sghsc->sghsc_node_id,
sghsc->sghsc_board, slot);
if (sghsc->sghsc_slot_table[slot].flags &
SGHSC_SLOT_AUTO_CFG_EN)
(void) sghsc_scctl(SGHSC_SET_ENUM_CLEARED,
sghsc->sghsc_node_id, sghsc->sghsc_board,
slot, &result);
break;
case HPC_CTRL_DEV_UNCONFIGURED:
DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control "
"HPC_CTRL_DEV_UNCONFIGURED for node %d / board %d slot %d",
sghsc->sghsc_instance, sghsc->sghsc_node_id,
sghsc->sghsc_board, slot));
SGHSC_MUTEX_EXIT(sghsc);
if (sghsc_disconnect(op_arg, sloth, 0,
0) != HPC_SUCCESS) {
DEBUGF(1, (CE_NOTE, "sghsc_control: "
"disconnect failed"));
error = HPC_ERR_FAILED;
}
cmn_err(CE_NOTE, "sghsc%d: node %d / board %d "
"slot %d unconfigured", sghsc->sghsc_instance,
sghsc->sghsc_node_id, sghsc->sghsc_board, slot);
return (error);
case HPC_CTRL_GET_BOARD_TYPE: {
DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
" HPC_CTRL_GET_BOARD_TYPE for node %d / board %d slot %d",
sghsc->sghsc_instance, sghsc->sghsc_node_id,
sghsc->sghsc_board, slot));
*(hpc_board_type_t *)arg =
sghsc->sghsc_slot_table[slot].board_type;
break;
}
case HPC_CTRL_ENABLE_AUTOCFG:
DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
" HPC_CTRL_ENABLE_AUTOCFG for node %d / board %d slot %d",
sghsc->sghsc_instance, sghsc->sghsc_node_id,
sghsc->sghsc_board, slot));
sghsc->sghsc_slot_table[slot].flags |= SGHSC_SLOT_AUTO_CFG_EN;
(void) hpc_slot_event_notify(sloth, HPC_EVENT_ENABLE_ENUM,
HPC_EVENT_NORMAL);
rc = sghsc_scctl(SGHSC_SET_ENUM_CLEARED, sghsc->sghsc_node_id,
sghsc->sghsc_board, slot, &result);
if (rc)
cmn_err(CE_WARN, "sghsc%d: unable to arm ENUM for"
" node %d / board %d, slot %d",
sghsc->sghsc_instance, sghsc->sghsc_node_id,
sghsc->sghsc_board, slot);
break;
case HPC_CTRL_DISABLE_AUTOCFG:
DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
" HPC_CTRL_DISABLE_AUTOCFG for node %d / board %d slot %d",
sghsc->sghsc_instance, sghsc->sghsc_node_id,
sghsc->sghsc_board, slot));
sghsc->sghsc_slot_table[slot].flags &= ~SGHSC_SLOT_AUTO_CFG_EN;
(void) hpc_slot_event_notify(sloth, HPC_EVENT_DISABLE_ENUM,
HPC_EVENT_NORMAL);
break;
case HPC_CTRL_DISABLE_SLOT:
case HPC_CTRL_ENABLE_SLOT:
break;
case HPC_CTRL_DISABLE_ENUM:
case HPC_CTRL_ENABLE_ENUM:
default:
DEBUGF(1, (CE_CONT, "sghsc%d: sghsc_control "
"request (0x%x) not supported", sghsc->sghsc_instance,
request));
error = HPC_ERR_NOTSUPPORTED;
}
SGHSC_MUTEX_EXIT(sghsc);
return (error);
}
static int
sghsc_led_state(sghsc_t *sghsc, hpc_slot_t sloth, int op,
hpc_led_info_t *ledinfo)
{
int rval;
int slot_num;
int result;
slot_num = sghsc_get_slotnum(sghsc, sloth);
rval = sghsc_scctl(SGHSC_GET_SLOT_STATUS, sghsc->sghsc_node_id,
sghsc->sghsc_board, slot_num, &result);
if (rval != HPC_SUCCESS)
return (rval);
switch (op) {
case HPC_CTRL_GET_LED_STATE:
switch (ledinfo->led) {
case HPC_POWER_LED:
if ((result >> CPCI_STAT_LED_POWER_SHIFT) & ONE_BIT)
ledinfo->state = HPC_LED_ON;
else
ledinfo->state = HPC_LED_OFF;
break;
case HPC_ATTN_LED:
case HPC_FAULT_LED:
if ((result >> CPCI_STAT_LED_FAULT_SHIFT) & ONE_BIT)
ledinfo->state = HPC_LED_ON;
else
ledinfo->state = HPC_LED_OFF;
break;
case HPC_ACTIVE_LED:
if ((result >> CPCI_STAT_LED_HP_SHIFT) & ONE_BIT)
ledinfo->state = HPC_LED_ON;
else
ledinfo->state = HPC_LED_OFF;
break;
}
break;
case HPC_CTRL_SET_LED_STATE:
return (HPC_ERR_NOTSUPPORTED);
}
return (HPC_SUCCESS);
}
static int
sghsc_get_slotnum(sghsc_t *sghsc, hpc_slot_t sloth)
{
int i;
if (sloth == NULL || sghsc == NULL)
return (-1);
for (i = 0; i < sghsc->sghsc_num_slots; i++) {
if (sghsc->sghsc_slot_table[i].handle == sloth)
return (i);
}
return (-1);
}
static int
sghsc_scctl(int cmd, int node_id, int board, int slot, int *resultp)
{
int ret = 0xbee;
bitcmd_info_t cmd_info, *cmd_infop = &cmd_info;
bitcmd_resp_t cmd_info_r, *cmd_info_r_p = &cmd_info_r;
sbbc_msg_t request, *reqp = &request;
sbbc_msg_t response, *resp = &response;
cmd_infop->cmd_id = 0x01234567;
cmd_infop->node_id = node_id;
cmd_infop->board = board;
cmd_infop->slot = slot;
reqp->msg_type.type = CPCI_MBOX;
reqp->msg_status = 0xeeeeffff;
reqp->msg_len = sizeof (cmd_info);
reqp->msg_bytes = 8;
reqp->msg_buf = (caddr_t)cmd_infop;
reqp->msg_data[0] = 0;
reqp->msg_data[1] = 0;
bzero(resp, sizeof (*resp));
bzero(cmd_info_r_p, sizeof (*cmd_info_r_p));
resp->msg_buf = (caddr_t)cmd_info_r_p;
resp->msg_len = sizeof (cmd_info_r);
resp->msg_type.type = CPCI_MBOX;
resp->msg_bytes = 8;
resp->msg_status = 0xddddffff;
switch (cmd) {
case SGHSC_GET_SLOT_STATUS:
reqp->msg_type.sub_type = CPCI_GET_SLOT_STATUS;
resp->msg_type.sub_type = CPCI_GET_SLOT_STATUS;
reqp->msg_len -= 4;
break;
case SGHSC_GET_NUM_SLOTS:
reqp->msg_type.sub_type = CPCI_GET_NUM_SLOTS;
resp->msg_type.sub_type = CPCI_GET_NUM_SLOTS;
reqp->msg_len -= 8;
break;
case SGHSC_SET_SLOT_STATUS_RESET:
reqp->msg_type.sub_type = CPCI_SET_SLOT_STATUS;
resp->msg_type.sub_type = CPCI_SET_SLOT_STATUS;
cmd_infop->info = CPCI_SET_STATUS_SLOT_RESET;
break;
case SGHSC_SET_SLOT_STATUS_READY:
reqp->msg_type.sub_type = CPCI_SET_SLOT_STATUS;
resp->msg_type.sub_type = CPCI_SET_SLOT_STATUS;
cmd_infop->info = CPCI_SET_STATUS_SLOT_READY;
break;
case SGHSC_SET_SLOT_FAULT_LED_ON:
reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
cmd_infop->info = CPCI_SET_FAULT_LED_ON;
break;
case SGHSC_SET_SLOT_FAULT_LED_OFF:
reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
cmd_infop->info = CPCI_SET_FAULT_LED_OFF;
break;
case SGHSC_SET_SLOT_FAULT_LED_KEEP:
reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
cmd_infop->info = CPCI_SET_FAULT_LED_KEEP;
break;
case SGHSC_SET_SLOT_FAULT_LED_TOGGLE:
reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
cmd_infop->info = CPCI_SET_FAULT_LED_TOGGLE;
break;
case SGHSC_SET_SLOT_POWER_OFF:
reqp->msg_type.sub_type = CPCI_SET_SLOT_POWER;
resp->msg_type.sub_type = CPCI_SET_SLOT_POWER;
cmd_infop->info = CPCI_POWER_OFF;
break;
case SGHSC_SET_SLOT_POWER_ON:
reqp->msg_type.sub_type = CPCI_SET_SLOT_POWER;
resp->msg_type.sub_type = CPCI_SET_SLOT_POWER;
cmd_infop->info = CPCI_POWER_ON;
break;
case SGHSC_GET_CPCI_BOARD_TYPE:
reqp->msg_type.sub_type = CPCI_BOARD_TYPE;
resp->msg_type.sub_type = CPCI_BOARD_TYPE;
reqp->msg_len -= 8;
break;
case SGHSC_SET_ENUM_CLEARED:
reqp->msg_type.sub_type = CPCI_SET_ENUM_CLEARED;
resp->msg_type.sub_type = CPCI_SET_ENUM_CLEARED;
break;
default:
cmn_err(CE_WARN, "sghsc: unrecognized action code 0x%x\n",
cmd);
}
DEBUGF(1, (CE_NOTE,
"sghsc: sending mbox command type=%d subtype=0x%x size=%d buf=%p",
reqp->msg_type.type, reqp->msg_type.sub_type,
reqp->msg_len, (void *)reqp->msg_buf));
DEBUGF(1, (CE_NOTE,
"sghsc: sending buf cmd_id=0x%x node_id=0x%x board=0x%x "
"slot=0x%x info=0x%x", cmd_infop->cmd_id, cmd_infop->node_id,
cmd_infop->board, cmd_infop->slot, cmd_infop->info));
ret = sbbc_mbox_request_response(reqp, resp, sghsc_mbx_timeout);
if ((ret != 0) || (resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
DEBUGF(1, (CE_NOTE, "sghsc: mailbox command error = 0x%x, "
"status = 0x%x", ret, resp->msg_status));
return (-1);
}
DEBUGF(1, (CE_NOTE, "sghsc: reply request status=0x%x",
reqp->msg_status));
DEBUGF(1, (CE_NOTE, "sghsc: reply resp status=0x%x",
resp->msg_status));
DEBUGF(1, (CE_NOTE, "sghsc: reply buf cmd_id=0x%x result=0x%x\n",
cmd_info_r_p->cmd_id, cmd_info_r_p->result));
#ifdef DEBUG_EXTENDED
if (cmd == SGHSC_GET_NUM_SLOTS) {
DEBUGF(1, (CE_NOTE, "sghsc: node %d / board %d has %d slots",
cmd_infop->node_id, cmd_infop->board,
cmd_info_r_p->result));
*resultp = cmd_info_r_p->result;
return (0);
}
if ((cmd_info_r_p->result >> CPCI_STAT_POWER_ON_SHIFT) & ONE_BIT)
DEBUGF(1, (CE_NOTE, "sghsc: cpower on"));
if ((cmd_info_r_p->result >> CPCI_STAT_LED_POWER_SHIFT) & ONE_BIT)
DEBUGF(1, (CE_NOTE, "sghsc: power led on"));
if ((cmd_info_r_p->result >> CPCI_STAT_LED_FAULT_SHIFT) & ONE_BIT)
DEBUGF(1, (CE_NOTE, "sghsc: fault led on"));
if ((cmd_info_r_p->result >> CPCI_STAT_LED_HP_SHIFT) & ONE_BIT)
DEBUGF(1, (CE_NOTE, "sghsc: remove(hp) led on"));
if ((cmd_info_r_p->result >> CPCI_STAT_SLOT_EMPTY_SHIFT) & ONE_BIT)
DEBUGF(1, (CE_NOTE, "sghsc: slot empty"));
tmp = ((cmd_info_r_p->result >> CPCI_STAT_HOT_SWAP_STATUS_SHIFT) &
THREE_BITS);
if (tmp)
DEBUGF(1, (CE_NOTE,
"sghsc: slot condition(hot swap status) is 0x%x", tmp));
if (cmd_info_r_p->result & CPCI_GET_STAT_SLOT_HZ_CAP)
DEBUGF(1, (CE_NOTE,
"sghsc: freq cap %x", cmd_info_r_p->result &
CPCI_GET_STAT_SLOT_HZ_CAP));
if (cmd_info_r_p->result & CPCI_GET_STAT_SLOT_HZ_SET)
DEBUGF(1, (CE_NOTE,
"sghsc: freq setting %x", cmd_info_r_p->result &
CPCI_GET_STAT_SLOT_HZ_SET));
if ((cmd_info_r_p->result >> CPCI_STAT_HEALTHY_SHIFT) & ONE_BIT)
DEBUGF(1, (CE_NOTE, "sghsc: healthy"));
if ((cmd_info_r_p->result >> CPCI_STAT_RESET_SHIFT) & ONE_BIT)
DEBUGF(1, (CE_NOTE, "sghsc: in reset"));
if (cmd_info_r_p->result & CPCI_GET_STAT_POWER_GOOD)
DEBUGF(1, (CE_NOTE, "sghsc: power good"));
if (cmd_info_r_p->result & CPCI_GET_STAT_POWER_FAULT)
DEBUGF(1, (CE_NOTE, "sghsc: power fault"));
if (cmd_info_r_p->result & CPCI_GET_STAT_PCI_PRESENT)
DEBUGF(1, (CE_NOTE, "sghsc: pci present"));
#endif
*resultp = cmd_info_r_p->result;
return (0);
}
static void
sghsc_freemem(sghsc_t *sghsc)
{
int i;
for (i = 0; i < sghsc->sghsc_num_slots; i++) {
if (sghsc->sghsc_slot_table[i].slot_ops)
hpc_free_slot_ops(sghsc->sghsc_slot_table[i].slot_ops);
if (sghsc->sghsc_slot_table[i].handle)
(void) hpc_slot_unregister(
&sghsc->sghsc_slot_table[i].handle);
}
kmem_free(sghsc->sghsc_slot_table,
(size_t)(sghsc->sghsc_num_slots * sizeof (sghsc_slot_t)));
}
static hpc_slot_t
sghsc_find_sloth(int node_id, int board, int slot)
{
int instance;
sghsc_t *sghsc;
for (instance = 0; instance < sghsc_maxinst; instance++) {
sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance);
if (sghsc == NULL || sghsc->sghsc_node_id != node_id ||
sghsc->sghsc_board != board)
continue;
DEBUGF(1, (CE_NOTE, "sghsc_find_sloth on board %d at node %d"
" slot %d", board, node_id, slot))
if (sghsc->sghsc_num_slots < (slot + 1)) {
cmn_err(CE_WARN, "sghsc%d: slot data corruption at"
"node %d / board %d", instance, node_id, board);
return (NULL);
}
if (sghsc->sghsc_valid == 0)
return (NULL);
return (sghsc->sghsc_slot_table[slot].handle);
}
DEBUGF(1, (CE_WARN, "sghsc_find_sloth: slot %d not found for node %d"
" / board %d", slot, node_id, board));
return (NULL);
}
uint_t
sghsc_event_handler(char *arg)
{
sghsc_event_t *rsp_data;
hpc_slot_t sloth;
sghsc_t *enum_state;
DEBUGF(1, (CE_NOTE, "sghsc: sghsc_event_handler called"))
rsp_data = (sghsc_event_t *)(((sbbc_msg_t *)arg)->msg_buf);
if (rsp_data == NULL) {
cmn_err(CE_WARN,
("sghsc: sghsc_event_handler argument is null\n"));
return (DDI_INTR_CLAIMED);
}
sloth = sghsc_find_sloth(rsp_data->node_id, rsp_data->board,
rsp_data->slot);
if (sloth == NULL) {
DEBUGF(1, (CE_WARN, "sghsc: slot info not available for"
" node %d / board %d slot %d. CPCI event rejected",
rsp_data->node_id, rsp_data->board, rsp_data->slot));
return (DDI_INTR_CLAIMED);
}
enum_state = sghsc_find_softstate(rsp_data->node_id, rsp_data->board,
rsp_data->slot);
if (enum_state == NULL) {
cmn_err(CE_WARN, "sghsc: soft state not available for"
" node %d / board %d slot %d", rsp_data->node_id,
rsp_data->board, rsp_data->slot);
return (DDI_INTR_UNCLAIMED);
}
DEBUGF(1, (CE_NOTE, "sghsc: node %d", rsp_data->node_id));
DEBUGF(1, (CE_NOTE, "sghsc: board %d", rsp_data->board));
DEBUGF(1, (CE_NOTE, "sghsc: slot %d", rsp_data->slot));
DEBUGF(1, (CE_NOTE, "sghsc: event info %d", rsp_data->info));
switch (rsp_data->info) {
case SGHSC_EVENT_CARD_INSERT:
DEBUGF(1, (CE_NOTE, "sghsc: card inserted node %d / board %d"
" slot %d", rsp_data->node_id, rsp_data->board,
rsp_data->slot));
enum_state->sghsc_slot_table[rsp_data->slot].board_type =
HPC_BOARD_CPCI_HS;
enum_state->sghsc_slot_table[rsp_data->slot].slot_status =
HPC_SLOT_DISCONNECTED;
break;
case SGHSC_EVENT_CARD_REMOVE:
DEBUGF(1, (CE_NOTE, "sghsc: card removed node %d / board %d"
" slot %d", rsp_data->node_id, rsp_data->board,
rsp_data->slot));
enum_state->sghsc_slot_table[rsp_data->slot].board_type =
HPC_BOARD_UNKNOWN;
enum_state->sghsc_slot_table[rsp_data->slot].slot_status =
HPC_SLOT_EMPTY;
return (DDI_INTR_CLAIMED);
case SGHSC_EVENT_POWER_ON:
DEBUGF(1, (CE_NOTE, "sghsc: power on node %d / board %d"
" slot %d", rsp_data->node_id, rsp_data->board,
rsp_data->slot));
return (DDI_INTR_CLAIMED);
case SGHSC_EVENT_POWER_OFF:
DEBUGF(1, (CE_NOTE, "sghsc: power off node %d / board %d"
" slot %d", rsp_data->node_id, rsp_data->board,
rsp_data->slot));
return (DDI_INTR_CLAIMED);
case SGHSC_EVENT_HEALTHY_LOST:
DEBUGF(1, (CE_NOTE, "sghsc: healthy lost node %d / board %d"
" slot %d", rsp_data->node_id, rsp_data->board,
rsp_data->slot));
return (DDI_INTR_CLAIMED);
case SGHSC_EVENT_LEVER_ACTION:
DEBUGF(1, (CE_NOTE, "sghsc: ENUM generated for node %d /"
"board %d slot %d", rsp_data->node_id, rsp_data->board,
rsp_data->slot));
break;
default:
DEBUGF(1, (CE_NOTE, "sghsc: unrecognized event info for"
" node %d / board %d slot %d", rsp_data->node_id,
rsp_data->board, rsp_data->slot));
return (DDI_INTR_CLAIMED);
}
if (sghsc_rb_put(&sghsc_rb_header, rsp_data) != DDI_SUCCESS) {
cmn_err(CE_WARN, "sghsc: no space to store #ENUM info");
return (DDI_INTR_UNCLAIMED);
}
cv_signal(&sghsc_event_thread_cv);
return (DDI_INTR_CLAIMED);
}
static void
sghsc_event_thread_code(void)
{
int rc;
int result;
hpc_slot_t sloth;
sghsc_t *sghsc;
sghsc_event_t rsp_data;
mutex_enter(&sghsc_event_thread_mutex);
for (;;) {
cv_wait(&sghsc_event_thread_cv, &sghsc_event_thread_mutex);
if (sghsc_event_thread_exit)
break;
while (sghsc_rb_get(&sghsc_rb_header, &rsp_data) ==
DDI_SUCCESS) {
sghsc = sghsc_find_softstate(rsp_data.node_id,
rsp_data.board, rsp_data.slot);
if (sghsc == NULL)
continue;
sloth = sghsc_find_sloth(rsp_data.node_id,
rsp_data.board, rsp_data.slot);
if (sloth == NULL)
continue;
if (!(sghsc->sghsc_slot_table[rsp_data.slot].flags &
SGHSC_SLOT_AUTO_CFG_EN))
continue;
if (rsp_data.info == SGHSC_EVENT_CARD_INSERT) {
rc = sghsc_connect((caddr_t)sghsc, sloth,
NULL, 0);
if (rc != HPC_SUCCESS)
cmn_err(CE_WARN, "sghsc:"
" could not connect inserted card,"
" node %d / board %d slot %d",
rsp_data.node_id, rsp_data.board,
rsp_data.slot);
continue;
}
rc = hpc_slot_event_notify(sloth, HPC_EVENT_CLEAR_ENUM,
HPC_EVENT_SYNCHRONOUS);
if (rc == HPC_EVENT_UNCLAIMED) {
DEBUGF(1, (CE_WARN,
"sghsc: unable to clear ENUM"));
continue;
}
rc = sghsc_scctl(SGHSC_SET_ENUM_CLEARED,
rsp_data.node_id, rsp_data.board,
rsp_data.slot, &result);
if (rc) {
DEBUGF(1, (CE_WARN,
"sghsc: unable to ACK cleared ENUM"));
continue;
}
rc = hpc_slot_event_notify(sloth,
HPC_EVENT_PROCESS_ENUM, HPC_EVENT_SYNCHRONOUS);
if (rc == HPC_EVENT_UNCLAIMED) {
DEBUGF(1, (CE_WARN,
"sghsc: could not process ENUM"));
}
}
}
DEBUGF(1, (CE_NOTE, "sghsc: thread_exit"));
cv_signal(&sghsc_event_thread_cv);
mutex_exit(&sghsc_event_thread_mutex);
thread_exit();
}
static sghsc_t *
sghsc_find_softstate(int node_id, int board, int slot)
{
int instance;
sghsc_t *sghsc;
for (instance = 0; instance < sghsc_maxinst; instance++) {
sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance);
if (sghsc == NULL || sghsc->sghsc_node_id != node_id ||
sghsc->sghsc_board != board)
continue;
if (sghsc->sghsc_num_slots < (slot + 1)) {
cmn_err(CE_WARN, "sghsc%d: "
"slot data corruption", instance);
return (NULL);
}
if (sghsc->sghsc_valid == 0)
return (NULL);
return (sghsc);
}
cmn_err(CE_WARN, "sghsc: soft state not found");
return (NULL);
}
static void
sghsc_rb_setup(sghsc_rb_head_t *rb_head)
{
if (rb_head->buf == NULL) {
rb_head->put_idx = 0;
rb_head->get_idx = 0;
rb_head->size = SGHSC_RING_BUFFER_SZ;
rb_head->state = SGHSC_RB_EMPTY;
rb_head->buf = (sghsc_event_t *)kmem_zalloc(
sizeof (sghsc_event_t) * rb_head->size, KM_SLEEP);
}
}
static void
sghsc_rb_teardown(sghsc_rb_head_t *rb_head)
{
if (rb_head->buf != NULL) {
kmem_free(rb_head->buf,
(size_t)(sizeof (sghsc_event_t) * rb_head->size));
rb_head->buf = NULL;
rb_head->put_idx = 0;
rb_head->get_idx = 0;
rb_head->size = 0;
rb_head->state = SGHSC_RB_EMPTY;
}
}
static int
sghsc_rb_put(sghsc_rb_head_t *rb_head, sghsc_event_t *event)
{
if (rb_head->state == SGHSC_RB_FULL)
return (DDI_FAILURE);
rb_head->buf[rb_head->put_idx] = *event;
rb_head->put_idx = (rb_head->put_idx + 1) & (rb_head->size - 1);
if (rb_head->put_idx == rb_head->get_idx)
rb_head->state = SGHSC_RB_FULL;
else
rb_head->state = SGHSC_RB_FLOAT;
return (DDI_SUCCESS);
}
static int
sghsc_rb_get(sghsc_rb_head_t *rb_head, sghsc_event_t *event)
{
if (rb_head->state == SGHSC_RB_EMPTY)
return (DDI_FAILURE);
*event = rb_head->buf[rb_head->get_idx];
rb_head->get_idx = (rb_head->get_idx + 1) & (rb_head->size - 1);
if (rb_head->get_idx == rb_head->put_idx)
rb_head->state = SGHSC_RB_EMPTY;
else
rb_head->state = SGHSC_RB_FLOAT;
return (DDI_SUCCESS);
}