xref: /titanic_44/usr/src/uts/common/io/cpqary3/cpqary3_mem.c (revision 80c94ecd7a524eb933a4bb221a9618b9dc490e76)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
14  */
15 
16 #include <sys/sdt.h>
17 #include "cpqary3.h"
18 
19 /*
20  * Local Functions Definitions
21  */
22 uint8_t	cleanstatus = 0;
23 
24 /*
25  * The Driver DMA Limit structure.
26  */
27 static ddi_dma_attr_t cpqary3_ctlr_dma_attr = {
28 	DMA_ATTR_V0,	/* ddi_dma_attr version */
29 	0,		/* low address */
30 	0xFFFFFFFF,	/* high address */
31 	0x00FFFFFF,	/* Max DMA Counter register */
32 	0x20,		/* Byte Alignment */
33 	0x20,		/* burst sizes */
34 	DMA_UNIT_8,	/* minimum DMA xfer Size */
35 	0xFFFFFFFF,	/* maximum DMA xfer Size */
36 	0x0000FFFF, 	/* segment boundary restrictions */
37 	1,		/* scatter/gather list length */
38 	512,		/* device granularity */
39 	0		/* DMA flags */
40 };
41 
42 /*
43  * Driver device access attr struct
44  */
45 extern ddi_device_acc_attr_t	cpqary3_dev_attributes;
46 
47 /*
48  * Function	:	cpqary3_meminit
49  * Description	:	This routine initialises memory for the command list.
50  *			Allocation of Physical contigous blocks and maintenance
51  * 			of lists to these.
52  * Called By	:	cpqary3_init_ctlr_resource()
53  * Parameters	:	per_controller
54  * Calls	:	cpqary3_alloc_phyctgs_mem, cpqary3_memfini
55  * Return Values:	SUCCESS / FAILURE
56  *			[If the required initialization and setup of memory
57  *			is successful, send back a success. Else, failure]
58  */
59 int16_t
cpqary3_meminit(cpqary3_t * cpqary3p)60 cpqary3_meminit(cpqary3_t *cpqary3p)
61 {
62 	size_t			mempool_size;
63 	caddr_t			mempool_addr;
64 	uint16_t		i = 0;
65 	uint32_t		mem_size = 0;
66 	uint32_t		no_cmds	= 0;
67 	uint32_t		cntr;
68 	uint32_t		maxmemcnt;
69 	uint32_t		phyaddr;
70 	uint32_t		temp_phyaddr;
71 	uint32_t		size_of_cmdlist	= 0;
72 	uint32_t		size_of_HRE = 0; /* Header + Request + Error */
73 	uint32_t		unused_mem = 0;
74 	uint32_t		mempoolnum;
75 	uint32_t		CmdsOutMax;
76 	CommandList_t		*cmdlist_memaddr;
77 	cpqary3_phyctg_t	*cpqary3_phyctgp;
78 	cpqary3_cmdpvt_t	*ptr;
79 	cpqary3_cmdpvt_t	*head_pvtp;
80 	cpqary3_cmdpvt_t	*tail_pvtp;
81 	cpqary3_cmdmemlist_t	*memlistp = NULL;
82 	cpqary3_phys_hdl_addr_t	*blk_ptr = NULL;
83 
84 	RETURN_FAILURE_IF_NULL(cpqary3p);
85 
86 	CmdsOutMax = cpqary3p->ctlr_maxcmds;
87 
88 
89 	/*
90 	 * Allocate memory for the Structure to hold details about the
91 	 * Command Memory Pool.
92 	 * Update per_controller pointer to this.
93 	 */
94 
95 	cpqary3p->cmdmemlistp = memlistp =
96 	    MEM_ZALLOC(sizeof (cpqary3_cmdmemlist_t));
97 
98 	if (!cpqary3p->cmdmemlistp) {
99 		cmn_err(CE_NOTE, "CPQary3: Memory Initialization: "
100 		    "Low Kernel Memory");
101 		return (CPQARY3_FAILURE);
102 	}
103 	cleanstatus |= CPQARY3_MEMLIST_DONE; /* For cleaning purpose. */
104 
105 	/*
106 	 * Allocate a Virtual Memory Pool of size
107 	 * NO_OF_CMDLIST_BLKS * NO_OF_CMDLIST_IN_A_BLK * sizeof (cmdmem_pvt_t)
108 	 * to store details of the above allocated Memory for
109 	 * NO_OF_CMDLIST_BLKS * NO_OF_CMDLIST_IN_A_BLK Commands
110 	 * Initialize this memory to act as a linked list to parse
111 	 * thru the entire list
112 	 * Initialize the Memory Mutex
113 	 */
114 	no_cmds  = (uint32_t)((CmdsOutMax / 3) * NO_OF_CMDLIST_IN_A_BLK);
115 	mem_size = (uint32_t)(no_cmds * sizeof (cpqary3_cmdpvt_t));
116 
117 	head_pvtp = ptr = (cpqary3_cmdpvt_t *)(MEM_ZALLOC(mem_size));
118 	if (NULL == head_pvtp) {
119 		MEM_SFREE(cpqary3p->cmdmemlistp, sizeof (cpqary3_cmdmemlist_t));
120 		cpqary3p->cmdmemlistp = NULL;
121 		cleanstatus &= ~CPQARY3_MEMLIST_DONE; /* For cleaning. */
122 		cmn_err(CE_NOTE, "CPQary3: Memory Initialization: "
123 		    "Low Kernel Memory");
124 		return (CPQARY3_FAILURE);
125 	}
126 
127 	tail_pvtp = &ptr[no_cmds - 1];
128 	cleanstatus |= CPQARY3_CMDMEM_DONE; /* For cleaning purpose. */
129 
130 	DTRACE_PROBE4(cmd_init_start, uint32_t, no_cmds, uint32_t, mem_size,
131 	    cpqary3_cmdpvt_t *, head_pvtp, cpqary3_cmdpvt_t *, tail_pvtp);
132 
133 	for (i = 0; i < no_cmds; i++) {
134 		ptr = &head_pvtp[i];
135 		ptr->occupied = CPQARY3_FREE;
136 		ptr->tag.tag_value = i;
137 		ptr->cmdlist_phyaddr = 0;
138 		ptr->cmdlist_erraddr = 0;
139 		ptr->cmdpvt_flag = 0;
140 		ptr->cmdlist_memaddr = (CommandList_t *)NULL;
141 		ptr->errorinfop = (ErrorInfo_t *)NULL;
142 		ptr->next = (cpqary3_cmdpvt_t *)((i == (no_cmds - 1)) ?
143 		    NULL : &head_pvtp[i+1]);
144 		ptr->prev = (cpqary3_cmdpvt_t *)((i == 0) ?
145 		    NULL : &head_pvtp[i-1]);
146 		ptr->ctlr = cpqary3p;
147 		ptr->pvt_pkt = (cpqary3_pkt_t *)NULL;
148 		ptr->sprev = (cpqary3_cmdpvt_t *)NULL;
149 		ptr->snext = (cpqary3_cmdpvt_t *)NULL;
150 	}
151 	cpqary3p->cmdmemlistp->head = head_pvtp; /* head Command Memory List */
152 	cpqary3p->cmdmemlistp->tail = tail_pvtp; /* tail Command Memory List */
153 	cpqary3p->cmdmemlistp->pool = head_pvtp; /* head Command Memory List */
154 	cpqary3p->cmdmemlistp->max_memcnt = 0; /* Maximum commands for ctlr */
155 
156 	ptr = head_pvtp;
157 
158 	DTRACE_PROBE(memlist_init_done);
159 
160 	/*
161 	 * We require the size of the commandlist and the combined
162 	 * size of the Command Header, Request Block and the Error Desriptor
163 	 * In CPQary3, it is 564 and 52 respectively.
164 	 */
165 	size_of_cmdlist = sizeof (CommandList_t);
166 	size_of_HRE = size_of_cmdlist -
167 	    (sizeof (SGDescriptor_t) * CISS_MAXSGENTRIES);
168 
169 	/*
170 	 * uint32_t alignment of cmdlist
171 	 * In CPQary3, after alignment, the size of each commandlist is 576
172 	 */
173 	if (size_of_cmdlist & 0x1F)
174 		size_of_cmdlist = ((size_of_cmdlist + 31) / 32) * 32;
175 
176 	/*
177 	 * The CmdsOutMax member in the Configuration Table states the maximum
178 	 * outstanding commands supported by this controller.
179 	 * The following code allocates memory in blocks; each block holds
180 	 * 3 commands.
181 	 */
182 
183 	for (mempoolnum = 0; mempoolnum < ((CmdsOutMax / 3)); mempoolnum++) {
184 		/* Allocate Memory for handle to maintain the Cmd Lists */
185 		cpqary3_phyctgp = (cpqary3_phyctg_t *)
186 		    MEM_ZALLOC(sizeof (cpqary3_phyctg_t));
187 		if (!cpqary3_phyctgp) {
188 			cpqary3_memfini(cpqary3p, cleanstatus);
189 			cmn_err(CE_NOTE, "CPQary3: Mem Initialization: "
190 			    "Low Kernel Memory");
191 			return (CPQARY3_FAILURE);
192 		}
193 
194 		/*
195 		 * Get the Physically Contiguous Memory
196 		 * Allocate 32 extra bytes of memory such as to get atleast
197 		 * 2 Command Blocks from every allocation even if we add any
198 		 * extra bytes after the initial allocation to make it 32 bit
199 		 * aligned.
200 		 */
201 		if (mempoolnum == 0) {	/* Head of Memory Blocks' Linked List */
202 			memlistp->cpqary3_phyctgp = blk_ptr =
203 			    (cpqary3_phys_hdl_addr_t *)
204 			    MEM_ZALLOC(sizeof (cpqary3_phys_hdl_addr_t));
205 			blk_ptr->blk_addr = cpqary3_phyctgp;
206 			blk_ptr->next = NULL;
207 		} else {
208 			blk_ptr->next = (cpqary3_phys_hdl_addr_t *)
209 			    MEM_ZALLOC(sizeof (cpqary3_phys_hdl_addr_t));
210 			blk_ptr = blk_ptr->next;
211 			blk_ptr->blk_addr = cpqary3_phyctgp;
212 			blk_ptr->next = NULL;
213 		}
214 
215 		phyaddr = 0;
216 		mempool_size = (size_of_cmdlist * NO_OF_CMDLIST_IN_A_BLK) + 32;
217 		mempool_addr = cpqary3_alloc_phyctgs_mem(cpqary3p,
218 		    mempool_size, &phyaddr, cpqary3_phyctgp);
219 
220 		if (!mempool_addr) {
221 			if (!mempoolnum) { /* Failue in the first attempt */
222 				MEM_SFREE(blk_ptr,
223 				    sizeof (cpqary3_phys_hdl_addr_t));
224 				memlistp->cpqary3_phyctgp = NULL;
225 				cmn_err(CE_WARN, "CPQary3 : Memory "
226 				    "Initialization : Low Kernel Memory");
227 				return (CPQARY3_FAILURE);
228 			}
229 
230 			/*
231 			 * Some memory allocation  has already been suucessful.
232 			 * The driver shall continue its initialization and
233 			 * working with whatever memory has been allocated.
234 			 *
235 			 * Free the latest virtual memory allocated.
236 			 * NULLify the last node created to maintain the memory
237 			 * block list.
238 			 * Terminate the Memory Q here by marking the Tail.
239 			 */
240 			blk_ptr->blk_addr = NULL;
241 			ptr--;
242 			ptr->next = NULL;
243 			memlistp->tail = ptr;
244 			return (CPQARY3_SUCCESS);
245 		}
246 		cleanstatus |= CPQARY3_PHYCTGS_DONE;
247 
248 		bzero(mempool_addr, cpqary3_phyctgp->real_size);
249 
250 		/*
251 		 * The 32 bit alignment is stated in the attribute structure.
252 		 * In case, it is not aligned as per requirement, we align it.
253 		 * uint32_t alignment of the first CMDLIST in the memory list
254 		 */
255 		temp_phyaddr = phyaddr;
256 		if (phyaddr & 0x1F) {
257 			phyaddr = (uint32_t)(((phyaddr + 31) / 32) * 32);
258 			unused_mem = (uint32_t)(phyaddr - temp_phyaddr);
259 		}
260 
261 		/*
262 		 * If the memory allocated is not 32 byte aligned then unused
263 		 * will give the total no of bytes that must remain unused to
264 		 * make it 32 byte aligned memory
265 		 */
266 		mempool_addr = (char *)((char *)mempool_addr + unused_mem);
267 
268 		/*
269 		 * Update Counter for no. of Command Blocks.
270 		 */
271 		maxmemcnt = 0;
272 		maxmemcnt = ((uint32_t)
273 		    (cpqary3_phyctgp->real_size - (uint32_t)unused_mem)) /
274 		    size_of_cmdlist;
275 		memlistp->max_memcnt = memlistp->max_memcnt + maxmemcnt;
276 
277 		/*
278 		 * Get the base of mempool which is 32 Byte aligned
279 		 * Initialize each Command Block with its corresponding
280 		 * Physical Address, Virtual address and the Physical Addres
281 		 * of the Error Info Descriptor
282 		 */
283 		cmdlist_memaddr = (CommandList_t *)mempool_addr;
284 
285 		for (cntr = 0; cntr < maxmemcnt; cntr++) {
286 			ptr->cmdlist_phyaddr = phyaddr;
287 			ptr->cmdlist_memaddr = cmdlist_memaddr;
288 			ptr->cmdlist_erraddr = phyaddr + size_of_HRE;
289 			ptr->errorinfop = (ErrorInfo_t *)
290 			    ((ulong_t)cmdlist_memaddr + size_of_HRE);
291 			phyaddr += size_of_cmdlist;
292 			cmdlist_memaddr = (CommandList_t *)
293 			    ((ulong_t)cmdlist_memaddr + size_of_cmdlist);
294 			ptr++;
295 		}
296 	}
297 
298 #ifdef MEM_DEBUG
299 	ptr = memlistp->head;
300 	cmn_err(CE_CONT, "CPQary3 : _meminit : max_memcnt = %d \n",
301 	    memlistp->max_memcnt);
302 	for (cntr = 0; cntr <= memlistp->max_memcnt; cntr++) {
303 		cmn_err(CE_CONT, "CPQary3: %d %x |",
304 		    cntr, ptr->cmdlist_phyaddr);
305 		if (cntr == 0)
306 			debug_enter("");
307 		ptr++;
308 	}
309 	cmn_err(CE_CONT, "\nCPQary3 : _meminit : "
310 	    "cpqary3_cmdpvt starts at %x \n", memlistp->head);
311 	cmn_err(CE_CONT, "CPQary3 : _meminit : cpqary3_cmdpvt ends at %x \n",
312 	    memlistp->tail);
313 	cmn_err(CE_CONT, "CPQary3 : _meminit : Leaving Successfully \n");
314 #endif
315 
316 	return (CPQARY3_SUCCESS);
317 }
318 
319 /*
320  * Function	: 	cpqary3_cmdlist_occupy
321  * Description	: 	This routine fetches a command block from the
322  *			initialised memory pool.
323  * Called By	: 	cpqary3_transport(), cpqary3_send_NOE_command(),
324  *			cpqary3_disable_NOE_command(), cpqary3_synccmd_alloc()
325  * Parameters	: 	per_controller
326  * Calls	: 	None
327  * Return Values: 	pointer to a valid Command Block /
328  *			NULL if none is available
329  */
330 cpqary3_cmdpvt_t *
cpqary3_cmdlist_occupy(cpqary3_t * ctlr)331 cpqary3_cmdlist_occupy(cpqary3_t *ctlr)
332 {
333 	cpqary3_cmdpvt_t	*memp = NULL;
334 	cpqary3_cmdmemlist_t	*memlistp;
335 
336 	RETURN_NULL_IF_NULL(ctlr);
337 	memlistp = ctlr->cmdmemlistp;
338 
339 	/*
340 	 * If pointer is NULL, we have no Command Memory Blocks available now.
341 	 * Else, occupy it and
342 	 * zero the commandlist so that old data is not existent.
343 	 * update tag, Error descriptor address & length in the CommandList
344 	 */
345 
346 	mutex_enter(&ctlr->sw_mutex);
347 	memp = memlistp->head;
348 	if (NULL == memp) {
349 		mutex_exit(&ctlr->sw_mutex);
350 		return ((cpqary3_cmdpvt_t *)NULL);
351 	}
352 
353 	memp->occupied = CPQARY3_OCCUPIED;
354 	bzero(memp->cmdlist_memaddr, sizeof (CommandList_t));
355 	memp->cmdlist_memaddr->Header.Tag.tag_value = memp->tag.tag_value;
356 	memp->cmdlist_memaddr->ErrDesc.Addr = memp->cmdlist_erraddr;
357 	memp->cmdlist_memaddr->ErrDesc.Len = sizeof (ErrorInfo_t);
358 	memlistp->head = memp->next;
359 
360 	DTRACE_PROBE1(cmdlist_occupy, cpqary3_cmdpvt_t *, memp);
361 
362 	if (memlistp->head) /* Atleast one more item is left in the Memory Q */
363 		memp->next->prev = NULL;
364 	else	/* No more items left in the Memory q */
365 		memlistp->tail	 = NULL;
366 
367 	mutex_exit(&ctlr->sw_mutex);
368 	return (memp);
369 }
370 
371 /*
372  * Function	:	cpqary3_cmdlist_release
373  * Description	: 	This routine releases a command block back to the
374  *			initialised memory pool.
375  * Called By	: 	cpqary3_transport(), cpqary3_process_pkt(),
376  *			cpqary3_send_NOE_command(), cpqary3_NOE_handler()
377  *			cpqary3_transport(), cpqary3_handle_flag_nointr()
378  *			cpqary3_synccmd_cleanup()
379  * Parameters	: 	pointer to Command Memory
380  *			flag to specify if mutex is to be held
381  * Calls	: 	None
382  * Return Values: 	None
383  */
384 void
cpqary3_cmdlist_release(cpqary3_cmdpvt_t * memp,uint8_t flag)385 cpqary3_cmdlist_release(cpqary3_cmdpvt_t *memp, uint8_t flag)
386 {
387 	cpqary3_cmdmemlist_t	*memlistp;
388 
389 	if (memp == NULL)
390 		return;
391 
392 	/*
393 	 * Hold The mutex ONLY if asked to (Else it means it is already held!)
394 	 * If both head & tail of the per-controller-memory-list are NULL,
395 	 * add this command list to the Available Q and Update head & tail.
396 	 * Else, append it to the Available Q.
397 	 */
398 
399 	memlistp =
400 	    (cpqary3_cmdmemlist_t *)((cpqary3_t *)memp->ctlr)->cmdmemlistp;
401 
402 	if (CPQARY3_HOLD_SW_MUTEX == flag)
403 		mutex_enter(&memp->ctlr->sw_mutex);
404 
405 	if (memlistp->head == NULL) {	/* obviously, tail is also NULL */
406 		memlistp->head = memp;
407 		memlistp->tail = memp;
408 		memp->next = NULL;
409 		memp->prev = NULL;
410 	} else {
411 		memlistp->tail->next = memp;
412 		memp->prev = memlistp->tail;
413 		memp->next = NULL;
414 		memlistp->tail = memp;
415 	}
416 
417 	memp->occupied = CPQARY3_FREE;
418 	memp->cmdpvt_flag = 0;
419 	memp->pvt_pkt = NULL;
420 
421 	if (CPQARY3_HOLD_SW_MUTEX == flag)
422 		mutex_exit(&memp->ctlr->sw_mutex);
423 }
424 
425 /*
426  * Function	: 	cpqary3_memfini
427  * Description	: 	This routine frees all command blocks that was
428  * 			initialised for the Command Memory Pool.
429  * 			It also fress any related memory that was occupied.
430  * Called By	: 	cpqary3_cleanup(), cpqary3_meminit(),
431  * 			cpqary3_init_ctlr_resource()
432  * Parameters	: 	per-controller, identifier(what all to clean up)
433  * Calls	:  	cpqary3_free_phyctgs_mem
434  * Return Values: 	None
435  */
436 void
cpqary3_memfini(cpqary3_t * ctlr,uint8_t level)437 cpqary3_memfini(cpqary3_t *ctlr, uint8_t level)
438 {
439 	uint32_t		mem_size;
440 	uint32_t		CmdsOutMax;
441 	cpqary3_cmdpvt_t	*memp;
442 	cpqary3_phys_hdl_addr_t	*blk_ptr;
443 	cpqary3_phys_hdl_addr_t	*tptr;
444 
445 	ASSERT(ctlr != NULL);
446 	blk_ptr = (cpqary3_phys_hdl_addr_t *)ctlr->cmdmemlistp->cpqary3_phyctgp;
447 
448 	CmdsOutMax = ctlr->ctlr_maxcmds;
449 
450 	DTRACE_PROBE1(memfini_start, uint32_t, CmdsOutMax);
451 
452 	/*
453 	 * Depending upon the identifier,
454 	 * Free Physical memory & Memory allocated to hold Block Details
455 	 * Virtual Memory used to maintain linked list of Command Memory Pool
456 	 * Memory which stores data relating to the Command Memory Pool
457 	 */
458 
459 	mutex_enter(&ctlr->sw_mutex);
460 	if (level & CPQARY3_PHYCTGS_DONE) {
461 		if (blk_ptr) {
462 			while (blk_ptr->next) {
463 				tptr = blk_ptr;
464 				blk_ptr = blk_ptr->next;
465 				cpqary3_free_phyctgs_mem(
466 				    tptr->blk_addr, CPQARY3_FREE_PHYCTG_MEM);
467 				MEM_SFREE(tptr,
468 				    sizeof (cpqary3_phys_hdl_addr_t));
469 			}
470 			cpqary3_free_phyctgs_mem(
471 			    blk_ptr->blk_addr, CPQARY3_FREE_PHYCTG_MEM);
472 			MEM_SFREE(blk_ptr, sizeof (cpqary3_phys_hdl_addr_t));
473 		}
474 	}
475 
476 	if (level & CPQARY3_CMDMEM_DONE) {
477 		mem_size = (uint32_t)((CmdsOutMax / 3) *
478 		    NO_OF_CMDLIST_IN_A_BLK * sizeof (cpqary3_cmdpvt_t));
479 		memp = ctlr->cmdmemlistp->pool;
480 
481 		DTRACE_PROBE2(memfini, uint32_t, mem_size, void *, memp);
482 		MEM_SFREE(memp, mem_size);
483 	}
484 	mutex_exit(&ctlr->sw_mutex);
485 
486 	if (level & CPQARY3_MEMLIST_DONE) {
487 		mutex_enter(&ctlr->hw_mutex);
488 		MEM_SFREE(ctlr->cmdmemlistp, sizeof (cpqary3_cmdmemlist_t));
489 		mutex_exit(&ctlr->hw_mutex);
490 	}
491 }
492 
493 /*
494  * Function	: 	cpqary3_alloc_phyctgs_mem
495  * Description	: 	This routine allocates Physically Contiguous Memory
496  *			for Commands or Scatter/Gather.
497  * Called By	:	cpqary3_meminit(), cpqary3_send_NOE_command()
498  *			cpqary3_synccmd_alloc()
499  * Parameters	: 	per-controller, size,
500  *			physical address that is sent back, per-physical
501  * Calls	:	cpqary3_free_phyctgs_mem(), ddi_dma_addr_bind_handle(),
502  *			ddi_dma_alloc_handle(), ddi_dma_mem_alloc()
503  * Return Values: 	Actually, this function sends back 2 values, one as an
504  *			explicit return and the other by updating a
505  * 			pointer-parameter:
506  * 			Virtual Memory Pointer to the allocated Memory(caddr_t),
507  * 			Physical Address of the allocated Memory(phyaddr)
508  */
509 caddr_t
cpqary3_alloc_phyctgs_mem(cpqary3_t * ctlr,size_t size_mempool,uint32_t * phyaddr,cpqary3_phyctg_t * phyctgp)510 cpqary3_alloc_phyctgs_mem(cpqary3_t *ctlr, size_t size_mempool,
511     uint32_t *phyaddr, cpqary3_phyctg_t *phyctgp)
512 {
513 	size_t real_len;
514 	int32_t retvalue;
515 	caddr_t mempool = NULL;
516 	uint8_t cleanstat = 0;
517 	uint32_t cookiecnt;
518 
519 	RETURN_NULL_IF_NULL(ctlr);
520 	RETURN_NULL_IF_NULL(phyctgp);
521 
522 	/*
523 	 * Allocation of Physical Contigous Memory follws:
524 	 * allocate a handle for this memory
525 	 * Use this handle in allocating memory
526 	 * bind the handle to this memory
527 	 * If any of the above fails, return a FAILURE.
528 	 * If all succeed, update phyaddr to the physical address of the
529 	 * allocated memory and return the pointer to the virtul allocated
530 	 * memory.
531 	 */
532 
533 	if (DDI_SUCCESS !=
534 	    (retvalue = ddi_dma_alloc_handle((dev_info_t *)ctlr->dip,
535 	    &cpqary3_ctlr_dma_attr, DDI_DMA_DONTWAIT, 0,
536 	    &phyctgp->cpqary3_dmahandle))) {
537 		switch (retvalue) {
538 		case DDI_DMA_NORESOURCES:
539 			cmn_err(CE_CONT, "CPQary3: No resources are available "
540 			    "to allocate the DMA Handle\n");
541 			break;
542 
543 		case DDI_DMA_BADATTR:
544 			cmn_err(CE_CONT, "CPQary3: Bad attributes in "
545 			    "ddi_dma_attr cannot allocate the DMA Handle \n");
546 			break;
547 
548 		default:
549 			cmn_err(CE_CONT, "CPQary3: Unexpected Value %x from "
550 			    "call to allocate the DMA Handle \n", retvalue);
551 		}
552 		/* Calling MEM_SFREE to free the memory */
553 		MEM_SFREE(phyctgp, sizeof (cpqary3_phyctg_t));
554 		return (NULL);
555 	}
556 
557 	cleanstat |= CPQARY3_DMA_ALLOC_HANDLE_DONE;
558 
559 	retvalue = ddi_dma_mem_alloc(phyctgp->cpqary3_dmahandle,
560 	    size_mempool, &cpqary3_dev_attributes,
561 	    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, 0, &mempool, &real_len,
562 	    &phyctgp->cpqary3_acchandle);
563 
564 	if (DDI_SUCCESS != retvalue) {
565 		cmn_err(CE_WARN, "CPQary3: Memory Allocation Failed: "
566 		    "Increase System Memory");
567 		cpqary3_free_phyctgs_mem(phyctgp, cleanstat);
568 		return (NULL);
569 	}
570 
571 	phyctgp->real_size = real_len;
572 
573 	cleanstat |= CPQARY3_DMA_ALLOC_MEM_DONE;
574 
575 	retvalue = ddi_dma_addr_bind_handle(phyctgp->cpqary3_dmahandle,
576 	    NULL, mempool, real_len,
577 	    DDI_DMA_CONSISTENT | DDI_DMA_RDWR, DDI_DMA_DONTWAIT, 0,
578 	    &phyctgp->cpqary3_dmacookie, &cookiecnt);
579 
580 	if (DDI_DMA_MAPPED == retvalue) {
581 		*phyaddr = phyctgp->cpqary3_dmacookie.dmac_address;
582 		return (mempool);
583 	}
584 
585 	switch (retvalue) {
586 	case DDI_DMA_PARTIAL_MAP:
587 		cmn_err(CE_CONT, "CPQary3: Allocated the resources for part "
588 		    "of the object\n");
589 		break;
590 
591 	case DDI_DMA_INUSE:
592 		cmn_err(CE_CONT, "CPQary3: Another I/O transaction is using "
593 		    "the DMA handle cannot bind to the DMA Handle\n");
594 		break;
595 
596 	case DDI_DMA_NORESOURCES:
597 		cmn_err(CE_CONT, "CPQary3: No resources are available cannot "
598 		    "bind to the DMA Handle\n");
599 		break;
600 
601 	case DDI_DMA_NOMAPPING:
602 		cmn_err(CE_CONT, "CPQary3: Object cannot be reached by the "
603 		    "device cannot bind to the DMA Handle\n");
604 		break;
605 
606 	case DDI_DMA_TOOBIG:
607 		cmn_err(CE_CONT, "CPQary3: The object is too big cannot bind "
608 		    "to the DMA Handle\n");
609 		cmn_err(CE_WARN, "CPQary3: Mem Scarce : "
610 		    "Increase System Memory/lomempages");
611 		break;
612 
613 	default:
614 		cmn_err(CE_WARN, "CPQary3 : Unexpected Return Value %x "
615 		    "from call to bind the DMA Handle", retvalue);
616 	}
617 
618 	cpqary3_free_phyctgs_mem(phyctgp, cleanstat);
619 
620 	mempool = NULL;
621 	return (mempool);
622 }
623 
624 /*
625  * Function	: 	cpqary3_free_phyctg_mem ()
626  * Description	: 	This routine frees the Physically contigous memory
627  *			that was allocated using ddi_dma operations.
628  *			It also fress any related memory that was occupied.
629  * Called By	: 	cpqary3_alloc_phyctgs_mem(), cpqary3_memfini(),
630  *			cpqary3_send_NOE_command(), cpqary3_NOE_handler(),
631  *			cpqary3_synccmd_alloc(), cpqary3_synccmd_cleanup()
632  * Parameters	: 	per-physical, identifier(what all to free)
633  * Calls	: 	None
634  */
635 void
cpqary3_free_phyctgs_mem(cpqary3_phyctg_t * cpqary3_phyctgp,uint8_t cleanstat)636 cpqary3_free_phyctgs_mem(cpqary3_phyctg_t *cpqary3_phyctgp, uint8_t cleanstat)
637 {
638 
639 	if (cpqary3_phyctgp == NULL)
640 		return;
641 
642 	/*
643 	 * Following the reverse prcess that was followed
644 	 * in allocating physical contigous memory
645 	 */
646 
647 	if (cleanstat & CPQARY3_DMA_BIND_ADDR_DONE) {
648 		(void) ddi_dma_unbind_handle(
649 		    cpqary3_phyctgp->cpqary3_dmahandle);
650 	}
651 
652 	if (cleanstat & CPQARY3_DMA_ALLOC_MEM_DONE) {
653 		ddi_dma_mem_free(&cpqary3_phyctgp->cpqary3_acchandle);
654 	}
655 
656 	if (cleanstat & CPQARY3_DMA_ALLOC_HANDLE_DONE) {
657 		ddi_dma_free_handle(&cpqary3_phyctgp->cpqary3_dmahandle);
658 	}
659 
660 	MEM_SFREE(cpqary3_phyctgp, sizeof (cpqary3_phyctg_t));
661 }
662