#include <sys/scsi/adapters/smrt/smrt.h>
uint_t
smrt_isr_hw_simple(caddr_t arg1, caddr_t arg2)
{
_NOTE(ARGUNUSED(arg2))
smrt_t *smrt = (smrt_t *)arg1;
uint32_t isr = smrt_get32(smrt, CISS_I2O_INTERRUPT_STATUS);
hrtime_t now = gethrtime();
mutex_enter(&smrt->smrt_mutex);
if (!(smrt->smrt_status & SMRT_CTLR_STATUS_RUNNING)) {
smrt->smrt_stats.smrts_unclaimed_interrupts++;
smrt->smrt_last_interrupt_unclaimed = now;
mutex_exit(&smrt->smrt_mutex);
return (DDI_INTR_UNCLAIMED);
}
if ((isr & CISS_ISR_BIT_SIMPLE_INTR) == 0) {
smrt->smrt_stats.smrts_unclaimed_interrupts++;
smrt->smrt_last_interrupt_unclaimed = now;
smrt_lockup_check(smrt);
mutex_exit(&smrt->smrt_mutex);
return (DDI_INTR_UNCLAIMED);
}
smrt->smrt_stats.smrts_claimed_interrupts++;
smrt->smrt_last_interrupt_claimed = now;
smrt_retrieve_simple(smrt);
smrt_process_finishq(smrt);
mutex_exit(&smrt->smrt_mutex);
return (DDI_INTR_CLAIMED);
}
void
smrt_retrieve_simple(smrt_t *smrt)
{
uint32_t opq;
uint32_t none = 0xffffffff;
VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
while ((opq = smrt_get32(smrt, CISS_I2O_OUTBOUND_POST_Q)) != none) {
uint32_t tag = CISS_OPQ_READ_TAG(opq);
smrt_command_t *smcm;
if ((smcm = smrt_lookup_inflight(smrt, tag)) == NULL) {
dev_err(smrt->smrt_dip, CE_WARN, "spurious tag %x",
tag);
continue;
}
avl_remove(&smrt->smrt_inflight, smcm);
smcm->smcm_status &= ~SMRT_CMD_STATUS_INFLIGHT;
if (CISS_OPQ_READ_ERROR(opq) != 0) {
smcm->smcm_status |= SMRT_CMD_STATUS_ERROR;
}
smcm->smcm_time_complete = gethrtime();
list_insert_tail(&smrt->smrt_finishq, smcm);
}
}
void
smrt_submit_simple(smrt_t *smrt, smrt_command_t *smcm)
{
smrt_put32(smrt, CISS_I2O_INBOUND_POST_Q, smcm->smcm_pa_cmd);
}
int
smrt_preinit_command_simple(smrt_t *smrt, smrt_command_t *smcm)
{
VERIFY(smrt->smrt_ctlr_mode == SMRT_CTLR_MODE_SIMPLE);
VERIFY(!(smrt->smrt_status & SMRT_CTLR_STATUS_RUNNING));
VERIFY(smcm->smcm_type == SMRT_CMDTYPE_PREINIT);
VERIFY(smcm->smcm_status & SMRT_CMD_STATUS_POLLED);
VERIFY3U(smcm->smcm_tag, ==, SMRT_PRE_TAG_NUMBER);
smcm->smcm_status |= SMRT_CMD_STATUS_INFLIGHT;
smrt_put32(smrt, CISS_I2O_INBOUND_POST_Q, smcm->smcm_pa_cmd);
for (;;) {
uint32_t none = 0xffffffff;
uint32_t opq = smrt_get32(smrt, CISS_I2O_OUTBOUND_POST_Q);
uint32_t tag;
if (smcm->smcm_expiry != 0) {
if (smcm->smcm_expiry < gethrtime()) {
return (ETIMEDOUT);
}
}
if (opq == none) {
delay(drv_usectohz(10 * 1000));
continue;
}
if ((tag = CISS_OPQ_READ_TAG(opq)) != SMRT_PRE_TAG_NUMBER) {
dev_err(smrt->smrt_dip, CE_WARN, "unexpected tag 0x%x"
" completed during driver init", tag);
delay(drv_usectohz(10 * 1000));
continue;
}
smcm->smcm_status &= ~SMRT_CMD_STATUS_INFLIGHT;
if (CISS_OPQ_READ_ERROR(opq) != 0) {
smcm->smcm_status |= SMRT_CMD_STATUS_ERROR;
}
smcm->smcm_time_complete = gethrtime();
smcm->smcm_status |= SMRT_CMD_STATUS_POLL_COMPLETE;
return (0);
}
}
int
smrt_ctlr_init_simple(smrt_t *smrt)
{
VERIFY(smrt->smrt_ctlr_mode == SMRT_CTLR_MODE_UNKNOWN);
if (smrt_cfgtbl_transport_has_support(smrt,
CISS_CFGTBL_XPORT_SIMPLE) != DDI_SUCCESS) {
return (DDI_FAILURE);
}
smrt->smrt_ctlr_mode = SMRT_CTLR_MODE_SIMPLE;
smrt_intr_set(smrt, B_FALSE);
if ((smrt->smrt_maxcmds = smrt_ctlr_get_cmdsoutmax(smrt)) == 0) {
dev_err(smrt->smrt_dip, CE_WARN, "maximum outstanding "
"commands set to zero");
return (DDI_FAILURE);
}
if ((smrt->smrt_sg_cnt = smrt_ctlr_get_maxsgelements(smrt)) == 0) {
smrt->smrt_sg_cnt = CISS_SGCNT_FALLBACK;
} else if (smrt->smrt_sg_cnt > CISS_MAXSGENTRIES) {
smrt->smrt_sg_cnt = CISS_MAXSGENTRIES;
}
ddi_put32(smrt->smrt_ct_handle, &smrt->smrt_ct->Upper32Addr, 0);
smrt_cfgtbl_transport_set(smrt, CISS_CFGTBL_XPORT_SIMPLE);
if (smrt_cfgtbl_flush(smrt) != DDI_SUCCESS) {
return (DDI_FAILURE);
}
if (smrt_cfgtbl_transport_confirm(smrt,
CISS_CFGTBL_XPORT_SIMPLE) != DDI_SUCCESS) {
return (DDI_FAILURE);
}
uint32_t check_again = smrt_ctlr_get_cmdsoutmax(smrt);
if (check_again != smrt->smrt_maxcmds) {
dev_err(smrt->smrt_dip, CE_WARN, "maximum outstanding commands "
"changed during initialisation (was %u, now %u)",
smrt->smrt_maxcmds, check_again);
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
void
smrt_ctlr_teardown_simple(smrt_t *smrt)
{
VERIFY(smrt->smrt_ctlr_mode == SMRT_CTLR_MODE_SIMPLE);
smrt->smrt_ctlr_mode = SMRT_CTLR_MODE_UNKNOWN;
}