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