/*
* 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
*/
/*
* Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
*/
#include "cpqary3.h"
/*
* Local Functions Definitions
*/
/*
* The Driver DMA Limit structure.
*/
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 */
512, /* device granularity */
0 /* DMA flags */
};
/*
* Driver device access attr struct
*/
/*
* 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]
*/
{
uint16_t i = 0;
/*
* Allocate memory for the Structure to hold details about the
* Command Memory Pool.
* Update per_controller pointer to this.
*/
MEM_ZALLOC(sizeof (cpqary3_cmdmemlist_t));
if (!cpqary3p->cmdmemlistp) {
"Low Kernel Memory");
return (CPQARY3_FAILURE);
}
/*
* 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
*/
"Low Kernel Memory");
return (CPQARY3_FAILURE);
}
for (i = 0; i < no_cmds; i++) {
ptr->cmdlist_phyaddr = 0;
ptr->cmdlist_erraddr = 0;
ptr->cmdpvt_flag = 0;
}
/*
* 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);
(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)
/*
* 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.
*/
/* Allocate Memory for handle to maintain the Cmd Lists */
MEM_ZALLOC(sizeof (cpqary3_phyctg_t));
if (!cpqary3_phyctgp) {
"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 */
MEM_ZALLOC(sizeof (cpqary3_phys_hdl_addr_t));
} else {
MEM_ZALLOC(sizeof (cpqary3_phys_hdl_addr_t));
}
phyaddr = 0;
if (!mempool_addr) {
if (!mempoolnum) { /* Failue in the first attempt */
sizeof (cpqary3_phys_hdl_addr_t));
"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.
*/
ptr--;
return (CPQARY3_SUCCESS);
}
/*
* 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
*/
if (phyaddr & 0x1F) {
}
/*
* 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
*/
/*
* Update Counter for no. of Command Blocks.
*/
maxmemcnt = 0;
/*
* 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 *)
ptr++;
}
}
#ifdef MEM_DEBUG
if (cntr == 0)
debug_enter("");
ptr++;
}
#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
*/
{
/*
* 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
*/
return ((cpqary3_cmdpvt_t *)NULL);
}
else /* No more items left in the Memory q */
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
{
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 =
if (CPQARY3_HOLD_SW_MUTEX == flag)
} else {
}
memp->cmdpvt_flag = 0;
if (CPQARY3_HOLD_SW_MUTEX == flag)
}
/*
* 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
{
/*
* 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
*/
if (level & CPQARY3_PHYCTGS_DONE) {
if (blk_ptr) {
sizeof (cpqary3_phys_hdl_addr_t));
}
}
}
if (level & CPQARY3_CMDMEM_DONE) {
NO_OF_CMDLIST_IN_A_BLK * sizeof (cpqary3_cmdpvt_t));
}
if (level & CPQARY3_MEMLIST_DONE) {
}
}
/*
* Function : cpqary3_alloc_phyctgs_mem
* Description : This routine allocates Physically Contiguous Memory
* 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)
*/
{
/*
* 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 !=
&phyctgp->cpqary3_dmahandle))) {
switch (retvalue) {
case DDI_DMA_NORESOURCES:
"to allocate the DMA Handle\n");
break;
case DDI_DMA_BADATTR:
"ddi_dma_attr cannot allocate the DMA Handle \n");
break;
default:
"call to allocate the DMA Handle \n", retvalue);
}
/* Calling MEM_SFREE to free the memory */
return (NULL);
}
if (DDI_SUCCESS != retvalue) {
"Increase System Memory");
return (NULL);
}
if (DDI_DMA_MAPPED == retvalue) {
return (mempool);
}
switch (retvalue) {
case DDI_DMA_PARTIAL_MAP:
"of the object\n");
break;
case DDI_DMA_INUSE:
"the DMA handle cannot bind to the DMA Handle\n");
break;
case DDI_DMA_NORESOURCES:
"bind to the DMA Handle\n");
break;
case DDI_DMA_NOMAPPING:
"device cannot bind to the DMA Handle\n");
break;
case DDI_DMA_TOOBIG:
"to the DMA Handle\n");
"Increase System Memory/lomempages");
break;
default:
"from call to bind the DMA Handle", retvalue);
}
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
{
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(
}
if (cleanstat & CPQARY3_DMA_ALLOC_MEM_DONE) {
}
if (cleanstat & CPQARY3_DMA_ALLOC_HANDLE_DONE) {
}
}