#include <sys/sdt.h>
#include "cpqary3.h"
uint8_t cleanstatus = 0;
static ddi_dma_attr_t cpqary3_ctlr_dma_attr = {
DMA_ATTR_V0,
0,
0xFFFFFFFF,
0x00FFFFFF,
0x20,
0x20,
DMA_UNIT_8,
0xFFFFFFFF,
0x0000FFFF,
1,
512,
0
};
extern ddi_device_acc_attr_t cpqary3_dev_attributes;
int16_t
cpqary3_meminit(cpqary3_t *cpqary3p)
{
size_t mempool_size;
caddr_t mempool_addr;
uint16_t i = 0;
uint32_t mem_size = 0;
uint32_t no_cmds = 0;
uint32_t cntr;
uint32_t maxmemcnt;
uint32_t phyaddr;
uint32_t temp_phyaddr;
uint32_t size_of_cmdlist = 0;
uint32_t size_of_HRE = 0;
uint32_t unused_mem = 0;
uint32_t mempoolnum;
uint32_t CmdsOutMax;
CommandList_t *cmdlist_memaddr;
cpqary3_phyctg_t *cpqary3_phyctgp;
cpqary3_cmdpvt_t *ptr;
cpqary3_cmdpvt_t *head_pvtp;
cpqary3_cmdpvt_t *tail_pvtp;
cpqary3_cmdmemlist_t *memlistp = NULL;
cpqary3_phys_hdl_addr_t *blk_ptr = NULL;
RETURN_FAILURE_IF_NULL(cpqary3p);
CmdsOutMax = cpqary3p->ctlr_maxcmds;
cpqary3p->cmdmemlistp = memlistp =
MEM_ZALLOC(sizeof (cpqary3_cmdmemlist_t));
if (!cpqary3p->cmdmemlistp) {
cmn_err(CE_NOTE, "CPQary3: Memory Initialization: "
"Low Kernel Memory");
return (CPQARY3_FAILURE);
}
cleanstatus |= CPQARY3_MEMLIST_DONE;
no_cmds = (uint32_t)((CmdsOutMax / 3) * NO_OF_CMDLIST_IN_A_BLK);
mem_size = (uint32_t)(no_cmds * sizeof (cpqary3_cmdpvt_t));
head_pvtp = ptr = (cpqary3_cmdpvt_t *)(MEM_ZALLOC(mem_size));
if (NULL == head_pvtp) {
MEM_SFREE(cpqary3p->cmdmemlistp, sizeof (cpqary3_cmdmemlist_t));
cpqary3p->cmdmemlistp = NULL;
cleanstatus &= ~CPQARY3_MEMLIST_DONE;
cmn_err(CE_NOTE, "CPQary3: Memory Initialization: "
"Low Kernel Memory");
return (CPQARY3_FAILURE);
}
tail_pvtp = &ptr[no_cmds - 1];
cleanstatus |= CPQARY3_CMDMEM_DONE;
DTRACE_PROBE4(cmd_init_start, uint32_t, no_cmds, uint32_t, mem_size,
cpqary3_cmdpvt_t *, head_pvtp, cpqary3_cmdpvt_t *, tail_pvtp);
for (i = 0; i < no_cmds; i++) {
ptr = &head_pvtp[i];
ptr->occupied = CPQARY3_FREE;
ptr->tag.tag_value = i;
ptr->cmdlist_phyaddr = 0;
ptr->cmdlist_erraddr = 0;
ptr->cmdpvt_flag = 0;
ptr->cmdlist_memaddr = (CommandList_t *)NULL;
ptr->errorinfop = (ErrorInfo_t *)NULL;
ptr->next = (cpqary3_cmdpvt_t *)((i == (no_cmds - 1)) ?
NULL : &head_pvtp[i+1]);
ptr->prev = (cpqary3_cmdpvt_t *)((i == 0) ?
NULL : &head_pvtp[i-1]);
ptr->ctlr = cpqary3p;
ptr->pvt_pkt = (cpqary3_pkt_t *)NULL;
ptr->sprev = (cpqary3_cmdpvt_t *)NULL;
ptr->snext = (cpqary3_cmdpvt_t *)NULL;
}
cpqary3p->cmdmemlistp->head = head_pvtp;
cpqary3p->cmdmemlistp->tail = tail_pvtp;
cpqary3p->cmdmemlistp->pool = head_pvtp;
cpqary3p->cmdmemlistp->max_memcnt = 0;
ptr = head_pvtp;
DTRACE_PROBE(memlist_init_done);
size_of_cmdlist = sizeof (CommandList_t);
size_of_HRE = size_of_cmdlist -
(sizeof (SGDescriptor_t) * CISS_MAXSGENTRIES);
if (size_of_cmdlist & 0x1F)
size_of_cmdlist = ((size_of_cmdlist + 31) / 32) * 32;
for (mempoolnum = 0; mempoolnum < ((CmdsOutMax / 3)); mempoolnum++) {
cpqary3_phyctgp = (cpqary3_phyctg_t *)
MEM_ZALLOC(sizeof (cpqary3_phyctg_t));
if (!cpqary3_phyctgp) {
cpqary3_memfini(cpqary3p, cleanstatus);
cmn_err(CE_NOTE, "CPQary3: Mem Initialization: "
"Low Kernel Memory");
return (CPQARY3_FAILURE);
}
if (mempoolnum == 0) {
memlistp->cpqary3_phyctgp = blk_ptr =
(cpqary3_phys_hdl_addr_t *)
MEM_ZALLOC(sizeof (cpqary3_phys_hdl_addr_t));
blk_ptr->blk_addr = cpqary3_phyctgp;
blk_ptr->next = NULL;
} else {
blk_ptr->next = (cpqary3_phys_hdl_addr_t *)
MEM_ZALLOC(sizeof (cpqary3_phys_hdl_addr_t));
blk_ptr = blk_ptr->next;
blk_ptr->blk_addr = cpqary3_phyctgp;
blk_ptr->next = NULL;
}
phyaddr = 0;
mempool_size = (size_of_cmdlist * NO_OF_CMDLIST_IN_A_BLK) + 32;
mempool_addr = cpqary3_alloc_phyctgs_mem(cpqary3p,
mempool_size, &phyaddr, cpqary3_phyctgp);
if (!mempool_addr) {
if (!mempoolnum) {
MEM_SFREE(blk_ptr,
sizeof (cpqary3_phys_hdl_addr_t));
memlistp->cpqary3_phyctgp = NULL;
cmn_err(CE_WARN, "CPQary3 : Memory "
"Initialization : Low Kernel Memory");
return (CPQARY3_FAILURE);
}
blk_ptr->blk_addr = NULL;
ptr--;
ptr->next = NULL;
memlistp->tail = ptr;
return (CPQARY3_SUCCESS);
}
cleanstatus |= CPQARY3_PHYCTGS_DONE;
bzero(mempool_addr, cpqary3_phyctgp->real_size);
temp_phyaddr = phyaddr;
if (phyaddr & 0x1F) {
phyaddr = (uint32_t)(((phyaddr + 31) / 32) * 32);
unused_mem = (uint32_t)(phyaddr - temp_phyaddr);
}
mempool_addr = (char *)((char *)mempool_addr + unused_mem);
maxmemcnt = 0;
maxmemcnt = ((uint32_t)
(cpqary3_phyctgp->real_size - (uint32_t)unused_mem)) /
size_of_cmdlist;
memlistp->max_memcnt = memlistp->max_memcnt + maxmemcnt;
cmdlist_memaddr = (CommandList_t *)mempool_addr;
for (cntr = 0; cntr < maxmemcnt; cntr++) {
ptr->cmdlist_phyaddr = phyaddr;
ptr->cmdlist_memaddr = cmdlist_memaddr;
ptr->cmdlist_erraddr = phyaddr + size_of_HRE;
ptr->errorinfop = (ErrorInfo_t *)
((ulong_t)cmdlist_memaddr + size_of_HRE);
phyaddr += size_of_cmdlist;
cmdlist_memaddr = (CommandList_t *)
((ulong_t)cmdlist_memaddr + size_of_cmdlist);
ptr++;
}
}
#ifdef MEM_DEBUG
ptr = memlistp->head;
cmn_err(CE_CONT, "CPQary3 : _meminit : max_memcnt = %d \n",
memlistp->max_memcnt);
for (cntr = 0; cntr <= memlistp->max_memcnt; cntr++) {
cmn_err(CE_CONT, "CPQary3: %d %x |",
cntr, ptr->cmdlist_phyaddr);
if (cntr == 0)
debug_enter("");
ptr++;
}
cmn_err(CE_CONT, "\nCPQary3 : _meminit : "
"cpqary3_cmdpvt starts at %x \n", memlistp->head);
cmn_err(CE_CONT, "CPQary3 : _meminit : cpqary3_cmdpvt ends at %x \n",
memlistp->tail);
cmn_err(CE_CONT, "CPQary3 : _meminit : Leaving Successfully \n");
#endif
return (CPQARY3_SUCCESS);
}
cpqary3_cmdpvt_t *
cpqary3_cmdlist_occupy(cpqary3_t *ctlr)
{
cpqary3_cmdpvt_t *memp = NULL;
cpqary3_cmdmemlist_t *memlistp;
RETURN_NULL_IF_NULL(ctlr);
memlistp = ctlr->cmdmemlistp;
mutex_enter(&ctlr->sw_mutex);
memp = memlistp->head;
if (NULL == memp) {
mutex_exit(&ctlr->sw_mutex);
return ((cpqary3_cmdpvt_t *)NULL);
}
memp->occupied = CPQARY3_OCCUPIED;
bzero(memp->cmdlist_memaddr, sizeof (CommandList_t));
memp->cmdlist_memaddr->Header.Tag.tag_value = memp->tag.tag_value;
memp->cmdlist_memaddr->ErrDesc.Addr = memp->cmdlist_erraddr;
memp->cmdlist_memaddr->ErrDesc.Len = sizeof (ErrorInfo_t);
memlistp->head = memp->next;
DTRACE_PROBE1(cmdlist_occupy, cpqary3_cmdpvt_t *, memp);
if (memlistp->head)
memp->next->prev = NULL;
else
memlistp->tail = NULL;
mutex_exit(&ctlr->sw_mutex);
return (memp);
}
void
cpqary3_cmdlist_release(cpqary3_cmdpvt_t *memp, uint8_t flag)
{
cpqary3_cmdmemlist_t *memlistp;
if (memp == NULL)
return;
memlistp =
(cpqary3_cmdmemlist_t *)((cpqary3_t *)memp->ctlr)->cmdmemlistp;
if (CPQARY3_HOLD_SW_MUTEX == flag)
mutex_enter(&memp->ctlr->sw_mutex);
if (memlistp->head == NULL) {
memlistp->head = memp;
memlistp->tail = memp;
memp->next = NULL;
memp->prev = NULL;
} else {
memlistp->tail->next = memp;
memp->prev = memlistp->tail;
memp->next = NULL;
memlistp->tail = memp;
}
memp->occupied = CPQARY3_FREE;
memp->cmdpvt_flag = 0;
memp->pvt_pkt = NULL;
if (CPQARY3_HOLD_SW_MUTEX == flag)
mutex_exit(&memp->ctlr->sw_mutex);
}
void
cpqary3_memfini(cpqary3_t *ctlr, uint8_t level)
{
uint32_t mem_size;
uint32_t CmdsOutMax;
cpqary3_cmdpvt_t *memp;
cpqary3_phys_hdl_addr_t *blk_ptr;
cpqary3_phys_hdl_addr_t *tptr;
ASSERT(ctlr != NULL);
blk_ptr = (cpqary3_phys_hdl_addr_t *)ctlr->cmdmemlistp->cpqary3_phyctgp;
CmdsOutMax = ctlr->ctlr_maxcmds;
DTRACE_PROBE1(memfini_start, uint32_t, CmdsOutMax);
mutex_enter(&ctlr->sw_mutex);
if (level & CPQARY3_PHYCTGS_DONE) {
if (blk_ptr) {
while (blk_ptr->next) {
tptr = blk_ptr;
blk_ptr = blk_ptr->next;
cpqary3_free_phyctgs_mem(
tptr->blk_addr, CPQARY3_FREE_PHYCTG_MEM);
MEM_SFREE(tptr,
sizeof (cpqary3_phys_hdl_addr_t));
}
cpqary3_free_phyctgs_mem(
blk_ptr->blk_addr, CPQARY3_FREE_PHYCTG_MEM);
MEM_SFREE(blk_ptr, sizeof (cpqary3_phys_hdl_addr_t));
}
}
if (level & CPQARY3_CMDMEM_DONE) {
mem_size = (uint32_t)((CmdsOutMax / 3) *
NO_OF_CMDLIST_IN_A_BLK * sizeof (cpqary3_cmdpvt_t));
memp = ctlr->cmdmemlistp->pool;
DTRACE_PROBE2(memfini, uint32_t, mem_size, void *, memp);
MEM_SFREE(memp, mem_size);
}
mutex_exit(&ctlr->sw_mutex);
if (level & CPQARY3_MEMLIST_DONE) {
mutex_enter(&ctlr->hw_mutex);
MEM_SFREE(ctlr->cmdmemlistp, sizeof (cpqary3_cmdmemlist_t));
mutex_exit(&ctlr->hw_mutex);
}
}
caddr_t
cpqary3_alloc_phyctgs_mem(cpqary3_t *ctlr, size_t size_mempool,
uint32_t *phyaddr, cpqary3_phyctg_t *phyctgp)
{
size_t real_len;
int32_t retvalue;
caddr_t mempool = NULL;
uint8_t cleanstat = 0;
uint32_t cookiecnt;
RETURN_NULL_IF_NULL(ctlr);
RETURN_NULL_IF_NULL(phyctgp);
if (DDI_SUCCESS !=
(retvalue = ddi_dma_alloc_handle((dev_info_t *)ctlr->dip,
&cpqary3_ctlr_dma_attr, DDI_DMA_DONTWAIT, 0,
&phyctgp->cpqary3_dmahandle))) {
switch (retvalue) {
case DDI_DMA_NORESOURCES:
cmn_err(CE_CONT, "CPQary3: No resources are available "
"to allocate the DMA Handle\n");
break;
case DDI_DMA_BADATTR:
cmn_err(CE_CONT, "CPQary3: Bad attributes in "
"ddi_dma_attr cannot allocate the DMA Handle \n");
break;
default:
cmn_err(CE_CONT, "CPQary3: Unexpected Value %x from "
"call to allocate the DMA Handle \n", retvalue);
}
MEM_SFREE(phyctgp, sizeof (cpqary3_phyctg_t));
return (NULL);
}
cleanstat |= CPQARY3_DMA_ALLOC_HANDLE_DONE;
retvalue = ddi_dma_mem_alloc(phyctgp->cpqary3_dmahandle,
size_mempool, &cpqary3_dev_attributes,
DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, 0, &mempool, &real_len,
&phyctgp->cpqary3_acchandle);
if (DDI_SUCCESS != retvalue) {
cmn_err(CE_WARN, "CPQary3: Memory Allocation Failed: "
"Increase System Memory");
cpqary3_free_phyctgs_mem(phyctgp, cleanstat);
return (NULL);
}
phyctgp->real_size = real_len;
cleanstat |= CPQARY3_DMA_ALLOC_MEM_DONE;
retvalue = ddi_dma_addr_bind_handle(phyctgp->cpqary3_dmahandle,
NULL, mempool, real_len,
DDI_DMA_CONSISTENT | DDI_DMA_RDWR, DDI_DMA_DONTWAIT, 0,
&phyctgp->cpqary3_dmacookie, &cookiecnt);
if (DDI_DMA_MAPPED == retvalue) {
*phyaddr = phyctgp->cpqary3_dmacookie.dmac_address;
return (mempool);
}
switch (retvalue) {
case DDI_DMA_PARTIAL_MAP:
cmn_err(CE_CONT, "CPQary3: Allocated the resources for part "
"of the object\n");
break;
case DDI_DMA_INUSE:
cmn_err(CE_CONT, "CPQary3: Another I/O transaction is using "
"the DMA handle cannot bind to the DMA Handle\n");
break;
case DDI_DMA_NORESOURCES:
cmn_err(CE_CONT, "CPQary3: No resources are available cannot "
"bind to the DMA Handle\n");
break;
case DDI_DMA_NOMAPPING:
cmn_err(CE_CONT, "CPQary3: Object cannot be reached by the "
"device cannot bind to the DMA Handle\n");
break;
case DDI_DMA_TOOBIG:
cmn_err(CE_CONT, "CPQary3: The object is too big cannot bind "
"to the DMA Handle\n");
cmn_err(CE_WARN, "CPQary3: Mem Scarce : "
"Increase System Memory/lomempages");
break;
default:
cmn_err(CE_WARN, "CPQary3 : Unexpected Return Value %x "
"from call to bind the DMA Handle", retvalue);
}
cpqary3_free_phyctgs_mem(phyctgp, cleanstat);
mempool = NULL;
return (mempool);
}
void
cpqary3_free_phyctgs_mem(cpqary3_phyctg_t *cpqary3_phyctgp, uint8_t cleanstat)
{
if (cpqary3_phyctgp == NULL)
return;
if (cleanstat & CPQARY3_DMA_BIND_ADDR_DONE) {
(void) ddi_dma_unbind_handle(
cpqary3_phyctgp->cpqary3_dmahandle);
}
if (cleanstat & CPQARY3_DMA_ALLOC_MEM_DONE) {
ddi_dma_mem_free(&cpqary3_phyctgp->cpqary3_acchandle);
}
if (cleanstat & CPQARY3_DMA_ALLOC_HANDLE_DONE) {
ddi_dma_free_handle(&cpqary3_phyctgp->cpqary3_dmahandle);
}
MEM_SFREE(cpqary3_phyctgp, sizeof (cpqary3_phyctg_t));
}