/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* http://www.illumos.org/license/CDDL.
*/
/*
* Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
*/
#include <sys/sdt.h>
#include "cpqary3.h"
/*
* Local Functions Definitions
*/
uint8_t cleanstatus = 0;
/*
* The Driver DMA Limit structure.
*/
static ddi_dma_attr_t cpqary3_ctlr_dma_attr = {
DMA_ATTR_V0, /* ddi_dma_attr version */
0, /* low address */
0xFFFFFFFF, /* high address */
0x00FFFFFF, /* Max DMA Counter register */
0x20, /* Byte Alignment */
0x20, /* burst sizes */
DMA_UNIT_8, /* minimum DMA xfer Size */
0xFFFFFFFF, /* maximum DMA xfer Size */
0x0000FFFF, /* segment boundary restrictions */
1, /* scatter/gather list length */
512, /* device granularity */
0 /* DMA flags */
};
/*
* Driver device access attr struct
*/
extern ddi_device_acc_attr_t cpqary3_dev_attributes;
/*
* Function : cpqary3_meminit
* Description : This routine initialises memory for the command list.
* Allocation of Physical contigous blocks and maintenance
* of lists to these.
* Called By : cpqary3_init_ctlr_resource()
* Parameters : per_controller
* Calls : cpqary3_alloc_phyctgs_mem, cpqary3_memfini
* Return Values: SUCCESS / FAILURE
* [If the required initialization and setup of memory
* is successful, send back a success. Else, failure]
*/
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; /* Header + Request + Error */
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;
/*
* Allocate memory for the Structure to hold details about the
* Command Memory Pool.
* Update per_controller pointer to this.
*/
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; /* For cleaning purpose. */
/*
* Allocate a Virtual Memory Pool of size
* NO_OF_CMDLIST_BLKS * NO_OF_CMDLIST_IN_A_BLK * sizeof (cmdmem_pvt_t)
* to store details of the above allocated Memory for
* NO_OF_CMDLIST_BLKS * NO_OF_CMDLIST_IN_A_BLK Commands
* Initialize this memory to act as a linked list to parse
* thru the entire list
* Initialize the Memory Mutex
*/
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; /* For cleaning. */
cmn_err(CE_NOTE, "CPQary3: Memory Initialization: "
"Low Kernel Memory");
return (CPQARY3_FAILURE);
}
tail_pvtp = &ptr[no_cmds - 1];
cleanstatus |= CPQARY3_CMDMEM_DONE; /* For cleaning purpose. */
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; /* head Command Memory List */
cpqary3p->cmdmemlistp->tail = tail_pvtp; /* tail Command Memory List */
cpqary3p->cmdmemlistp->pool = head_pvtp; /* head Command Memory List */
cpqary3p->cmdmemlistp->max_memcnt = 0; /* Maximum commands for ctlr */
ptr = head_pvtp;
DTRACE_PROBE(memlist_init_done);
/*
* We require the size of the commandlist and the combined
* size of the Command Header, Request Block and the Error Desriptor
* In CPQary3, it is 564 and 52 respectively.
*/
size_of_cmdlist = sizeof (CommandList_t);
size_of_HRE = size_of_cmdlist -
(sizeof (SGDescriptor_t) * CISS_MAXSGENTRIES);
/*
* uint32_t alignment of cmdlist
* In CPQary3, after alignment, the size of each commandlist is 576
*/
if (size_of_cmdlist & 0x1F)
size_of_cmdlist = ((size_of_cmdlist + 31) / 32) * 32;
/*
* The CmdsOutMax member in the Configuration Table states the maximum
* outstanding commands supported by this controller.
* The following code allocates memory in blocks; each block holds
* 3 commands.
*/
for (mempoolnum = 0; mempoolnum < ((CmdsOutMax / 3)); mempoolnum++) {
/* Allocate Memory for handle to maintain the Cmd Lists */
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);
}
/*
* Get the Physically Contiguous Memory
* Allocate 32 extra bytes of memory such as to get atleast
* 2 Command Blocks from every allocation even if we add any
* extra bytes after the initial allocation to make it 32 bit
* aligned.
*/
if (mempoolnum == 0) { /* Head of Memory Blocks' Linked List */
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) { /* Failue in the first attempt */
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);
}
/*
* Some memory allocation has already been suucessful.
* The driver shall continue its initialization and
* working with whatever memory has been allocated.
*
* Free the latest virtual memory allocated.
* NULLify the last node created to maintain the memory
* block list.
* Terminate the Memory Q here by marking the Tail.
*/
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);
/*
* The 32 bit alignment is stated in the attribute structure.
* In case, it is not aligned as per requirement, we align it.
* uint32_t alignment of the first CMDLIST in the memory list
*/
temp_phyaddr = phyaddr;
if (phyaddr & 0x1F) {
phyaddr = (uint32_t)(((phyaddr + 31) / 32) * 32);
unused_mem = (uint32_t)(phyaddr - temp_phyaddr);
}
/*
* If the memory allocated is not 32 byte aligned then unused
* will give the total no of bytes that must remain unused to
* make it 32 byte aligned memory
*/
mempool_addr = (char *)((char *)mempool_addr + unused_mem);
/*
* Update Counter for no. of Command Blocks.
*/
maxmemcnt = 0;
maxmemcnt = ((uint32_t)
(cpqary3_phyctgp->real_size - (uint32_t)unused_mem)) /
size_of_cmdlist;
memlistp->max_memcnt = memlistp->max_memcnt + maxmemcnt;
/*
* Get the base of mempool which is 32 Byte aligned
* Initialize each Command Block with its corresponding
* Physical Address, Virtual address and the Physical Addres
* of the Error Info Descriptor
*/
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);
}
/*
* Function : cpqary3_cmdlist_occupy
* Description : This routine fetches a command block from the
* initialised memory pool.
* Called By : cpqary3_transport(), cpqary3_send_NOE_command(),
* cpqary3_disable_NOE_command(), cpqary3_synccmd_alloc()
* Parameters : per_controller
* Calls : None
* Return Values: pointer to a valid Command Block /
* NULL if none is available
*/
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;
/*
* If pointer is NULL, we have no Command Memory Blocks available now.
* Else, occupy it and
* zero the commandlist so that old data is not existent.
* update tag, Error descriptor address & length in the CommandList
*/
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) /* Atleast one more item is left in the Memory Q */
memp->next->prev = NULL;
else /* No more items left in the Memory q */
memlistp->tail = NULL;
mutex_exit(&ctlr->sw_mutex);
return (memp);
}
/*
* Function : cpqary3_cmdlist_release
* Description : This routine releases a command block back to the
* initialised memory pool.
* Called By : cpqary3_transport(), cpqary3_process_pkt(),
* cpqary3_send_NOE_command(), cpqary3_NOE_handler()
* cpqary3_transport(), cpqary3_handle_flag_nointr()
* cpqary3_synccmd_cleanup()
* Parameters : pointer to Command Memory
* flag to specify if mutex is to be held
* Calls : None
* Return Values: None
*/
void
cpqary3_cmdlist_release(cpqary3_cmdpvt_t *memp, uint8_t flag)
{
cpqary3_cmdmemlist_t *memlistp;
if (memp == NULL)
return;
/*
* Hold The mutex ONLY if asked to (Else it means it is already held!)
* If both head & tail of the per-controller-memory-list are NULL,
* add this command list to the Available Q and Update head & tail.
* Else, append it to the Available Q.
*/
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) { /* obviously, tail is also 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);
}
/*
* Function : cpqary3_memfini
* Description : This routine frees all command blocks that was
* initialised for the Command Memory Pool.
* It also fress any related memory that was occupied.
* Called By : cpqary3_cleanup(), cpqary3_meminit(),
* cpqary3_init_ctlr_resource()
* Parameters : per-controller, identifier(what all to clean up)
* Calls : cpqary3_free_phyctgs_mem
* Return Values: None
*/
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);
/*
* Depending upon the identifier,
* Free Physical memory & Memory allocated to hold Block Details
* Virtual Memory used to maintain linked list of Command Memory Pool
* Memory which stores data relating to the Command Memory Pool
*/
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);
}
}
/*
* Function : cpqary3_alloc_phyctgs_mem
* Description : This routine allocates Physically Contiguous Memory
* for Commands or Scatter/Gather.
* Called By : cpqary3_meminit(), cpqary3_send_NOE_command()
* cpqary3_synccmd_alloc()
* Parameters : per-controller, size,
* physical address that is sent back, per-physical
* Calls : cpqary3_free_phyctgs_mem(), ddi_dma_addr_bind_handle(),
* ddi_dma_alloc_handle(), ddi_dma_mem_alloc()
* Return Values: Actually, this function sends back 2 values, one as an
* explicit return and the other by updating a
* pointer-parameter:
* Virtual Memory Pointer to the allocated Memory(caddr_t),
* Physical Address of the allocated Memory(phyaddr)
*/
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);
/*
* Allocation of Physical Contigous Memory follws:
* allocate a handle for this memory
* Use this handle in allocating memory
* bind the handle to this memory
* If any of the above fails, return a FAILURE.
* If all succeed, update phyaddr to the physical address of the
* allocated memory and return the pointer to the virtul allocated
* memory.
*/
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);
}
/* Calling MEM_SFREE to free the memory */
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);
}
/*
* Function : cpqary3_free_phyctg_mem ()
* Description : This routine frees the Physically contigous memory
* that was allocated using ddi_dma operations.
* It also fress any related memory that was occupied.
* Called By : cpqary3_alloc_phyctgs_mem(), cpqary3_memfini(),
* cpqary3_send_NOE_command(), cpqary3_NOE_handler(),
* cpqary3_synccmd_alloc(), cpqary3_synccmd_cleanup()
* Parameters : per-physical, identifier(what all to free)
* Calls : None
*/
void
cpqary3_free_phyctgs_mem(cpqary3_phyctg_t *cpqary3_phyctgp, uint8_t cleanstat)
{
if (cpqary3_phyctgp == NULL)
return;
/*
* Following the reverse prcess that was followed
* in allocating physical contigous memory
*/
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));
}