#include <sys/sdt.h>
#include "cpqary3.h"
int cpqary3_target_geometry(struct scsi_address *);
int8_t cpqary3_detect_target_geometry(cpqary3_t *);
void
cpqary3_read_conf_file(dev_info_t *dip, cpqary3_t *cpqary3p)
{
char *ptr;
cpqary3p->noe_support = 0;
if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
"cpqary3_tgtmap", &ptr) == DDI_PROP_SUCCESS) {
if (strcmp("off", ptr) == 0) {
cpqary3p->legacy_mapping = 1;
}
ddi_prop_free(ptr);
}
if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
"cpqary3_noesupport", &ptr) == DDI_PROP_SUCCESS) {
if (strcmp("on", ptr) == 0) {
cpqary3p->noe_support = 1;
}
if (strcmp("off", ptr) == 0) {
cpqary3p->noe_support = 0;
}
ddi_prop_free(ptr);
}
}
void
cpqary3_tick_hdlr(void *arg)
{
clock_t cpqary3_lbolt;
clock_t cpqary3_ticks;
cpqary3_t *ctlr;
cpqary3_pkt_t *pktp;
struct scsi_pkt *scsi_pktp;
cpqary3_cmdpvt_t *local;
volatile CfgTable_t *ctp;
uint32_t i;
uint32_t no_cmds = 0;
if (NULL == (ctlr = (cpqary3_t *)arg))
return;
ctp = (CfgTable_t *)ctlr->ct;
if (ctlr->heartbeat == DDI_GET32(ctlr, &ctp->HeartBeat)) {
if (ctlr->lockup_logged == CPQARY3_FALSE) {
cmn_err(CE_WARN, "CPQary3 : "
"%s HBA firmware Locked !!!", ctlr->hba_name);
cmn_err(CE_WARN, "CPQary3 : "
"Please reboot the system");
cpqary3_intr_onoff(ctlr, CPQARY3_INTR_DISABLE);
if (ctlr->host_support & 0x4)
cpqary3_lockup_intr_onoff(ctlr,
CPQARY3_LOCKUP_INTR_DISABLE);
ctlr->controller_lockup = CPQARY3_TRUE;
ctlr->lockup_logged = CPQARY3_TRUE;
}
}
no_cmds = (uint32_t)((ctlr->ctlr_maxcmds / 3) *
NO_OF_CMDLIST_IN_A_BLK);
mutex_enter(&ctlr->sw_mutex);
for (i = 0; i < no_cmds; i++) {
local = &ctlr->cmdmemlistp->pool[i];
ASSERT(local != NULL);
pktp = MEM2PVTPKT(local);
if (!pktp)
continue;
if ((local->cmdpvt_flag == CPQARY3_TIMEOUT) ||
(local->cmdpvt_flag == CPQARY3_RESET)) {
continue;
}
if (local->occupied == CPQARY3_OCCUPIED) {
scsi_pktp = pktp->scsi_cmd_pkt;
cpqary3_lbolt = ddi_get_lbolt();
if ((scsi_pktp) && (scsi_pktp->pkt_time)) {
cpqary3_ticks = cpqary3_lbolt -
pktp->cmd_start_time;
if ((drv_hztousec(cpqary3_ticks)/1000000) >
scsi_pktp->pkt_time) {
scsi_pktp->pkt_reason = CMD_TIMEOUT;
scsi_pktp->pkt_statistics =
STAT_TIMEOUT;
scsi_pktp->pkt_state = STATE_GOT_BUS |
STATE_GOT_TARGET | STATE_SENT_CMD;
local->cmdpvt_flag = CPQARY3_TIMEOUT;
if (scsi_pktp->pkt_comp) {
mutex_exit(&ctlr->sw_mutex);
(*scsi_pktp->pkt_comp)
(scsi_pktp);
mutex_enter(&ctlr->sw_mutex);
continue;
}
}
}
}
}
ctlr->heartbeat = DDI_GET32(ctlr, &ctp->HeartBeat);
mutex_exit(&ctlr->sw_mutex);
ctlr->tick_tmout_id = timeout(cpqary3_tick_hdlr,
(caddr_t)ctlr, drv_usectohz(CPQARY3_TICKTMOUT_VALUE));
}
uint16_t
cpqary3_init_ctlr_resource(cpqary3_t *ctlr)
{
#ifdef CPQARY3_DEBUG_MEM
int8_t i = 0;
#endif
RETURN_FAILURE_IF_NULL(ctlr);
if (CPQARY3_FAILURE == cpqary3_init_ctlr(ctlr))
return ((CPQARY3_FAILURE));
if (CPQARY3_FAILURE == cpqary3_meminit(ctlr))
return ((CPQARY3_FAILURE));
#ifdef CPQARY3_DEBUG_MEM
cmn_err(CE_CONT, "CPQary3 : _init_ctlr_resource : Testing memory \n");
for (i = 0; i < 15; i++) {
if (CPQARY3_SUCCESS != cpqary3_meminit(ctlr)) {
cmn_err(CE_CONT, "CPQary3 : meminit failed : "
"attempt %d \n", i);
return (CPQARY3_FAILURE);
}
cmn_err(CE_CONT,
"CPQary3 : INIT successful : attempt %d \n", i);
cpqary3_memfini(ctlr, CPQARY3_MEMLIST_DONE |
CPQARY3_PHYCTGS_DONE | CPQARY3_CMDMEM_DONE);
cmn_err(CE_CONT,
"CPQary3 : FINI successful : attempt %d \n", i);
}
return (CPQARY3_FAILURE);
#endif
ctlr->cpqary3_tgtp[CTLR_SCSI_ID] = MEM_ZALLOC(sizeof (cpqary3_tgt_t));
if (!(ctlr->cpqary3_tgtp[CTLR_SCSI_ID])) {
cmn_err(CE_WARN, "CPQary3: Target Initialization Failed");
cpqary3_memfini(ctlr, CPQARY3_MEMLIST_DONE |
CPQARY3_PHYCTGS_DONE | CPQARY3_CMDMEM_DONE);
return (CPQARY3_FAILURE);
}
ctlr->cpqary3_tgtp[CTLR_SCSI_ID]->type = CPQARY3_TARGET_CTLR;
cpqary3_intr_onoff(ctlr, CPQARY3_INTR_DISABLE);
cv_init(&ctlr->cv_immediate_wait, NULL, CV_DRIVER, NULL);
cv_init(&ctlr->cv_noe_wait, NULL, CV_DRIVER, NULL);
cv_init(&ctlr->cv_flushcache_wait, NULL, CV_DRIVER, NULL);
cv_init(&ctlr->cv_abort_wait, NULL, CV_DRIVER, NULL);
cv_init(&ctlr->cv_ioctl_wait, NULL, CV_DRIVER, NULL);
return (CPQARY3_SUCCESS);
}
int
cpqary3_target_geometry(struct scsi_address *sa)
{
cpqary3_t *ctlr = SA2CTLR(sa);
cpqary3_tgt_t *tgtp = ctlr->cpqary3_tgtp[SA2TGT(sa)];
return ((tgtp->properties.drive.heads << 16) |
tgtp->properties.drive.sectors);
}
cpqary3_cmdpvt_t *
cpqary3_synccmd_alloc(cpqary3_t *cpqary3p, size_t bufsz)
{
cpqary3_private_t *cmddmah = NULL;
uint32_t dmabufpa = 0;
cpqary3_cmdpvt_t *memp = NULL;
if (bufsz > 0) {
cpqary3_phyctg_t *dmah = NULL;
caddr_t dmabufva = NULL;
cmddmah = (cpqary3_private_t *)MEM_ZALLOC(sizeof (*cmddmah));
if (cmddmah == NULL) {
cmn_err(CE_WARN, "cpqary3_synccmd_alloc: "
"no memory for cmddmah");
return (NULL);
}
dmah = (cpqary3_phyctg_t *)MEM_ZALLOC(sizeof (*dmah));
if (dmah == NULL) {
MEM_SFREE(cmddmah, sizeof (*cmddmah));
cmn_err(CE_WARN, "cpqary3_synccmd_alloc: "
"no memory for dmah");
return (NULL);
}
dmabufva = cpqary3_alloc_phyctgs_mem(cpqary3p, bufsz,
&dmabufpa, dmah);
if (dmabufva == NULL) {
MEM_SFREE(cmddmah, sizeof (*cmddmah));
cmn_err(CE_WARN, "cpqary3_synccmd_alloc: "
"no memory for dma buf");
return (NULL);
}
bzero(dmabufva, bufsz);
cmddmah->sg = dmabufva;
cmddmah->phyctgp = dmah;
}
memp = cpqary3_cmdlist_occupy(cpqary3p);
if (memp == NULL) {
if (cmddmah != NULL) {
cpqary3_free_phyctgs_mem(cmddmah->phyctgp,
CPQARY3_FREE_PHYCTG_MEM);
MEM_SFREE(cmddmah, sizeof (*cmddmah));
}
cmn_err(CE_WARN, "cpqary3_synccmd_alloc: "
"cannot get free command");
return (NULL);
}
memp->cmdpvt_flag = 0;
memp->cmdlist_memaddr->Header.Tag.drvinfo_n_err =
CPQARY3_SYNCCMD_SUCCESS;
memp->driverdata = cmddmah;
memp->cmdlist_memaddr->SG[0].Addr = dmabufpa;
memp->cmdlist_memaddr->SG[0].Len = (uint32_t)bufsz;
return (memp);
}
void
cpqary3_synccmd_cleanup(cpqary3_cmdpvt_t *memp)
{
if (memp->driverdata != NULL) {
cpqary3_free_phyctgs_mem(memp->driverdata->phyctgp,
CPQARY3_FREE_PHYCTG_MEM);
MEM_SFREE(memp->driverdata, sizeof (cpqary3_private_t));
memp->driverdata = NULL;
}
memp->cmdpvt_flag = 0;
cpqary3_cmdlist_release(memp, CPQARY3_HOLD_SW_MUTEX);
}
void
cpqary3_synccmd_free(cpqary3_t *cpqary3p, cpqary3_cmdpvt_t *memp)
{
mutex_enter(&(cpqary3p->sw_mutex));
if (memp->cmdpvt_flag == CPQARY3_SYNC_SUBMITTED) {
memp->cmdpvt_flag = CPQARY3_SYNC_TIMEOUT;
mutex_exit(&(cpqary3p->sw_mutex));
return;
}
memp->cmdpvt_flag = 0;
mutex_exit(&(cpqary3p->sw_mutex));
cpqary3_synccmd_cleanup(memp);
return;
}
int
cpqary3_synccmd_send(cpqary3_t *cpqary3p, cpqary3_cmdpvt_t *memp,
clock_t timeoutms, int flags)
{
clock_t absto = 0;
int waitsig = 0;
int rc = 0;
kcondvar_t *cv = 0;
if (timeoutms > 0)
absto = ddi_get_lbolt() + drv_usectohz(timeoutms * 1000);
if (flags & CPQARY3_SYNCCMD_SEND_WAITSIG)
waitsig = 1;
mutex_enter(&(cpqary3p->sw_mutex));
mutex_enter(&(cpqary3p->hw_mutex));
memp->cmdpvt_flag = CPQARY3_SYNC_SUBMITTED;
memp->cmdlist_memaddr->Header.Tag.drvinfo_n_err =
CPQARY3_SYNCCMD_SUCCESS;
if (EIO == cpqary3_submit(cpqary3p, memp->cmdlist_phyaddr)) {
mutex_exit(&(cpqary3p->hw_mutex));
mutex_exit(&(cpqary3p->sw_mutex));
rc = -1;
return (rc);
}
mutex_exit(&(cpqary3p->hw_mutex));
while (memp->cmdpvt_flag == CPQARY3_SYNC_SUBMITTED) {
kmutex_t *mt = &(cpqary3p->sw_mutex);
cv = &(cpqary3p->cv_ioctl_wait);
if (absto) {
clock_t crc;
if (waitsig) {
crc = cv_timedwait_sig(cv, mt, absto);
} else {
crc = cv_timedwait(cv, mt, absto);
}
if (crc > 0)
rc = 0;
else
rc = (-1);
} else {
if (waitsig) {
rc = cv_wait_sig(cv, mt);
if (rc > 0)
rc = 0;
else
rc = (-1);
} else {
cv_wait(cv, mt);
rc = 0;
}
}
if (rc) {
break;
}
}
mutex_exit(&(cpqary3p->sw_mutex));
return (rc);
}
int8_t
cpqary3_detect_target_geometry(cpqary3_t *ctlr)
{
int i;
int8_t ld_count = 0;
int8_t loop_cnt = 0;
IdLogDrive *idlogdrive;
CommandList_t *cmdlistp;
cpqary3_cmdpvt_t *cpqary3_cmdpvtp;
RETURN_FAILURE_IF_NULL(ctlr);
cpqary3_cmdpvtp = cpqary3_synccmd_alloc(ctlr, sizeof (IdLogDrive));
if (cpqary3_cmdpvtp == NULL)
return (CPQARY3_FAILURE);
cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr;
idlogdrive = (IdLogDrive *)cpqary3_cmdpvtp->driverdata->sg;
cmdlistp->Header.SGList = 1;
cmdlistp->Header.SGTotal = 1;
cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_SYNCCMD_SUCCESS;
cmdlistp->Request.CDBLen = CPQARY3_CDBLEN_16;
cmdlistp->Request.CDB[0] = 0x26;
cmdlistp->Request.CDB[6] = BMIC_IDENTIFY_LOGICAL_DRIVE;
cmdlistp->Request.CDB[7] = (sizeof (IdLogDrive) >> 8) & 0xff;
cmdlistp->Request.CDB[8] = sizeof (IdLogDrive) & 0xff;
cmdlistp->Request.Type.Type = CISS_TYPE_CMD;
cmdlistp->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
cmdlistp->Request.Type.Direction = CISS_XFER_READ;
if (ctlr->legacy_mapping == 1) {
loop_cnt = ((ctlr->num_of_targets > CTLR_SCSI_ID) ?
(ctlr->num_of_targets + 1) : (ctlr->num_of_targets));
for (i = 0; i < loop_cnt; i++) {
if (i == CTLR_SCSI_ID)
i++;
bzero(idlogdrive, sizeof (IdLogDrive));
cmdlistp->Request.CDB[1] =
ctlr->cpqary3_tgtp[i]->logical_id;
cmdlistp->Header.LUN.PhysDev.TargetId = 0;
cmdlistp->Header.LUN.PhysDev.Bus =
(ctlr->cpqary3_tgtp[i]->logical_id) >> 16;
cmdlistp->Header.LUN.PhysDev.Mode =
(cmdlistp->Header.LUN.PhysDev.Bus > 0) ?
MASK_PERIPHERIAL_DEV_ADDR : PERIPHERIAL_DEV_ADDR;
cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete;
if (cpqary3_synccmd_send(ctlr, cpqary3_cmdpvtp, 90000,
CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp);
return (CPQARY3_FAILURE);
}
if ((cpqary3_cmdpvtp->
cmdlist_memaddr->Header.Tag.drvinfo_n_err ==
CPQARY3_SYNCCMD_FAILURE) &&
(cpqary3_cmdpvtp->errorinfop->CommandStatus != 2)) {
DTRACE_PROBE1(id_logdrv_fail,
ErrorInfo_t *, cpqary3_cmdpvtp->errorinfop);
cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp);
return (CPQARY3_FAILURE);
}
ctlr->cpqary3_tgtp[i]->properties.drive.heads =
idlogdrive->heads;
ctlr->cpqary3_tgtp[i]->properties.drive.sectors =
idlogdrive->sectors;
DTRACE_PROBE2(tgt_geometry_detect,
int, i, IdLogDrive *, idlogdrive);
}
} else {
for (i = 0; ld_count < ctlr->num_of_targets; i++) {
if (i == CTLR_SCSI_ID ||
ctlr->cpqary3_tgtp[i] == NULL)
continue;
bzero(idlogdrive, sizeof (IdLogDrive));
cmdlistp->Request.CDB[1] =
ctlr->cpqary3_tgtp[i]->logical_id;
cmdlistp->Header.LUN.PhysDev.TargetId = 0;
cmdlistp->Header.LUN.PhysDev.Bus =
(ctlr->cpqary3_tgtp[i]->logical_id) >> 16;
cmdlistp->Header.LUN.PhysDev.Mode =
(cmdlistp->Header.LUN.PhysDev.Bus > 0) ?
MASK_PERIPHERIAL_DEV_ADDR : PERIPHERIAL_DEV_ADDR;
cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete;
if (cpqary3_synccmd_send(ctlr, cpqary3_cmdpvtp, 90000,
CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp);
return (CPQARY3_FAILURE);
}
if ((cpqary3_cmdpvtp->
cmdlist_memaddr->Header.Tag.drvinfo_n_err ==
CPQARY3_SYNCCMD_FAILURE) &&
(cpqary3_cmdpvtp->errorinfop->CommandStatus != 2)) {
DTRACE_PROBE1(id_logdrv_fail,
ErrorInfo_t *, cpqary3_cmdpvtp->errorinfop);
cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp);
return (CPQARY3_FAILURE);
}
ctlr->cpqary3_tgtp[i]->properties.drive.heads =
idlogdrive->heads;
ctlr->cpqary3_tgtp[i]->properties.drive.sectors =
idlogdrive->sectors;
DTRACE_PROBE2(tgt_geometry_detect,
int, i, IdLogDrive *, idlogdrive);
ld_count++;
}
}
cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp);
return (CPQARY3_SUCCESS);
}