xref: /illumos-gate/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_mem.c (revision b30d193948be5a7794d7ae3ba0ed9c2f72c88e0f)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at
9  * http://www.opensource.org/licenses/cddl1.txt.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2004-2011 Emulex. All rights reserved.
24  * Use is subject to license terms.
25  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
26  * Copyright 2020 RackTop Systems, Inc.
27  */
28 
29 #include <emlxs.h>
30 
31 /* #define EMLXS_POOL_DEBUG */
32 
33 EMLXS_MSG_DEF(EMLXS_MEM_C);
34 
35 
36 static uint32_t emlxs_mem_pool_alloc(emlxs_hba_t *hba, MEMSEG *seg,
37 			uint32_t count);
38 static void emlxs_mem_pool_free(emlxs_hba_t *hba, MEMSEG *seg, uint32_t count);
39 
40 
41 extern int32_t
42 emlxs_mem_alloc_buffer(emlxs_hba_t *hba)
43 {
44 	emlxs_port_t *port = &PPORT;
45 	emlxs_config_t *cfg;
46 	MBUF_INFO *buf_info;
47 	MEMSEG *seg;
48 	MBUF_INFO bufinfo;
49 	int32_t i;
50 	MATCHMAP *mp;
51 	MATCHMAP **bpl_table;
52 
53 	buf_info = &bufinfo;
54 	cfg = &CFG;
55 
56 	bzero(hba->memseg, sizeof (hba->memseg));
57 
58 	/* Allocate the fc_table */
59 	bzero(buf_info, sizeof (MBUF_INFO));
60 	buf_info->size = (hba->max_iotag * sizeof (emlxs_buf_t *));
61 
62 	(void) emlxs_mem_alloc(hba, buf_info);
63 	if (buf_info->virt == NULL) {
64 
65 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mem_alloc_failed_msg,
66 		    "fc_table buffer.");
67 
68 		goto failed;
69 	}
70 	hba->fc_table = buf_info->virt;
71 	bzero(hba->fc_table, buf_info->size);
72 
73 	/* Prepare the memory pools */
74 	for (i = 0; i < FC_MAX_SEG; i++) {
75 		seg = &hba->memseg[i];
76 
77 		switch (i) {
78 		case MEM_NLP:
79 			(void) strlcpy(seg->fc_label, "Node Pool",
80 			    sizeof (seg->fc_label));
81 			seg->fc_memtag	= MEM_NLP;
82 			seg->fc_memsize	= sizeof (NODELIST);
83 			seg->fc_hi_water = hba->max_nodes + 2;
84 			seg->fc_lo_water = 2;
85 			seg->fc_step = 1;
86 			break;
87 
88 		case MEM_IOCB:
89 			(void) strlcpy(seg->fc_label, "IOCB Pool",
90 			    sizeof (seg->fc_label));
91 			seg->fc_memtag	= MEM_IOCB;
92 			seg->fc_memsize	= sizeof (IOCBQ);
93 			seg->fc_hi_water = cfg[CFG_NUM_IOCBS].current;
94 			seg->fc_lo_water = cfg[CFG_NUM_IOCBS].low;
95 			seg->fc_step = cfg[CFG_NUM_IOCBS].low;
96 			break;
97 
98 		case MEM_MBOX:
99 			(void) strlcpy(seg->fc_label, "MBOX Pool",
100 			    sizeof (seg->fc_label));
101 			seg->fc_memtag	= MEM_MBOX;
102 			seg->fc_memsize	= sizeof (MAILBOXQ);
103 			seg->fc_hi_water = hba->max_nodes + 32;
104 			seg->fc_lo_water = 32;
105 			seg->fc_step = 1;
106 			break;
107 
108 		case MEM_BPL:
109 			if (hba->model_info.sli_mask & EMLXS_SLI4_MASK) {
110 				continue;
111 			}
112 			(void) strlcpy(seg->fc_label, "BPL Pool",
113 			    sizeof (seg->fc_label));
114 			seg->fc_memtag	= MEM_BPL;
115 			seg->fc_memsize	= hba->sli.sli3.mem_bpl_size;
116 			seg->fc_memflag	= FC_MBUF_DMA | FC_MBUF_SNGLSG;
117 			seg->fc_memalign = 32;
118 			seg->fc_hi_water = hba->max_iotag;
119 			seg->fc_lo_water = cfg[CFG_NUM_IOCBS].low;
120 			seg->fc_step = cfg[CFG_NUM_IOCBS].low;
121 			break;
122 
123 		case MEM_BUF:
124 			/* These are the unsolicited ELS buffers. */
125 			(void) strlcpy(seg->fc_label, "BUF Pool",
126 			    sizeof (seg->fc_label));
127 			seg->fc_memtag	= MEM_BUF;
128 			seg->fc_memsize	= MEM_BUF_SIZE;
129 			seg->fc_memflag	= FC_MBUF_DMA | FC_MBUF_SNGLSG;
130 			seg->fc_memalign = 32;
131 			seg->fc_hi_water = MEM_ELSBUF_COUNT + MEM_BUF_COUNT;
132 			seg->fc_lo_water = MEM_ELSBUF_COUNT;
133 			seg->fc_step = 1;
134 			break;
135 
136 		case MEM_IPBUF:
137 			/* These are the unsolicited IP buffers. */
138 			if (cfg[CFG_NETWORK_ON].current == 0) {
139 				continue;
140 			}
141 
142 			(void) strlcpy(seg->fc_label, "IPBUF Pool",
143 			    sizeof (seg->fc_label));
144 			seg->fc_memtag	= MEM_IPBUF;
145 			seg->fc_memsize	= MEM_IPBUF_SIZE;
146 			seg->fc_memflag	= FC_MBUF_DMA | FC_MBUF_SNGLSG;
147 			seg->fc_memalign = 32;
148 			seg->fc_hi_water = MEM_IPBUF_COUNT;
149 			seg->fc_lo_water = 0;
150 			seg->fc_step = 4;
151 			break;
152 
153 		case MEM_CTBUF:
154 			/* These are the unsolicited CT buffers. */
155 			(void) strlcpy(seg->fc_label, "CTBUF Pool",
156 			    sizeof (seg->fc_label));
157 			seg->fc_memtag	= MEM_CTBUF;
158 			seg->fc_memsize	= MEM_CTBUF_SIZE;
159 			seg->fc_memflag	= FC_MBUF_DMA | FC_MBUF_SNGLSG;
160 			seg->fc_memalign = 32;
161 			seg->fc_hi_water = MEM_CTBUF_COUNT;
162 			seg->fc_lo_water = MEM_CTBUF_COUNT;
163 			seg->fc_step = 1;
164 			break;
165 
166 		case MEM_SGL1K:
167 			(void) strlcpy(seg->fc_label, "1K SGL Pool",
168 			    sizeof (seg->fc_label));
169 			seg->fc_memtag	= MEM_SGL1K;
170 			seg->fc_memsize	= 0x400;
171 			seg->fc_memflag	= FC_MBUF_DMA | FC_MBUF_SNGLSG;
172 			seg->fc_memalign = 32;
173 			seg->fc_hi_water = 0x5000;
174 			seg->fc_lo_water = 0;
175 			seg->fc_step = 0x100;
176 			break;
177 
178 		case MEM_SGL2K:
179 			(void) strlcpy(seg->fc_label, "2K SGL Pool",
180 			    sizeof (seg->fc_label));
181 			seg->fc_memtag	= MEM_SGL2K;
182 			seg->fc_memsize	= 0x800;
183 			seg->fc_memflag	= FC_MBUF_DMA | FC_MBUF_SNGLSG;
184 			seg->fc_memalign = 32;
185 			seg->fc_hi_water = 0x5000;
186 			seg->fc_lo_water = 0;
187 			seg->fc_step = 0x100;
188 			break;
189 
190 		case MEM_SGL4K:
191 			(void) strlcpy(seg->fc_label, "4K SGL Pool",
192 			    sizeof (seg->fc_label));
193 			seg->fc_memtag	= MEM_SGL4K;
194 			seg->fc_memsize	= 0x1000;
195 			seg->fc_memflag	= FC_MBUF_DMA | FC_MBUF_SNGLSG;
196 			seg->fc_memalign = 32;
197 			seg->fc_hi_water = 0x5000;
198 			seg->fc_lo_water = 0;
199 			seg->fc_step = 0x100;
200 			break;
201 
202 #ifdef SFCT_SUPPORT
203 		case MEM_FCTBUF:
204 			/* These are the unsolicited FCT buffers. */
205 			if (!(port->flag & EMLXS_TGT_ENABLED)) {
206 				continue;
207 			}
208 
209 			(void) strlcpy(seg->fc_label, "FCTBUF Pool",
210 			    sizeof (seg->fc_label));
211 			seg->fc_memtag	= MEM_FCTBUF;
212 			seg->fc_memsize	= MEM_FCTBUF_SIZE;
213 			seg->fc_memflag	= FC_MBUF_DMA | FC_MBUF_SNGLSG;
214 			seg->fc_memalign = 32;
215 			seg->fc_hi_water = MEM_FCTBUF_COUNT;
216 			seg->fc_lo_water = 0;
217 			seg->fc_step = 8;
218 			break;
219 #endif /* SFCT_SUPPORT */
220 
221 		default:
222 			continue;
223 		}
224 
225 		if (seg->fc_memsize == 0) {
226 			continue;
227 		}
228 
229 		(void) emlxs_mem_pool_create(hba, seg);
230 
231 		if (seg->fc_numblks < seg->fc_lo_water) {
232 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mem_alloc_failed_msg,
233 			    "%s: count=%d size=%d flags=%x lo=%d hi=%d",
234 			    seg->fc_label, seg->fc_numblks,
235 			    seg->fc_memsize, seg->fc_memflag, seg->fc_lo_water,
236 			    seg->fc_hi_water);
237 
238 			goto failed;
239 		}
240 	}
241 
242 	hba->sli.sli3.bpl_table = NULL;
243 	seg = &hba->memseg[MEM_BPL];
244 
245 	/* If SLI3 and MEM_BPL pool is static */
246 	if (!(hba->model_info.sli_mask & EMLXS_SLI4_MASK) &&
247 	    !(seg->fc_memflag & FC_MEMSEG_DYNAMIC)) {
248 		/*
249 		 * Allocate and Initialize bpl_table
250 		 * This is for increased performance.
251 		 */
252 		bzero(buf_info, sizeof (MBUF_INFO));
253 		buf_info->size = hba->max_iotag * sizeof (MATCHMAP *);
254 
255 		(void) emlxs_mem_alloc(hba, buf_info);
256 		if (buf_info->virt == NULL) {
257 
258 			EMLXS_MSGF(EMLXS_CONTEXT,
259 			    &emlxs_mem_alloc_failed_msg,
260 			    "BPL table buffer.");
261 
262 			goto failed;
263 		}
264 		hba->sli.sli3.bpl_table = buf_info->virt;
265 
266 		bpl_table = (MATCHMAP**)hba->sli.sli3.bpl_table;
267 		for (i = 0; i < hba->max_iotag; i++) {
268 			mp = (MATCHMAP *) emlxs_mem_get(hba, MEM_BPL);
269 			mp->flag |= MAP_TABLE_ALLOCATED;
270 			bpl_table[i] = mp;
271 		}
272 	}
273 
274 	return (1);
275 
276 failed:
277 
278 	(void) emlxs_mem_free_buffer(hba);
279 	return (0);
280 
281 } /* emlxs_mem_alloc_buffer() */
282 
283 
284 /*
285  * emlxs_mem_free_buffer
286  *
287  * This routine will free iocb/data buffer space
288  * and TGTM resource.
289  */
290 extern int
291 emlxs_mem_free_buffer(emlxs_hba_t *hba)
292 {
293 	emlxs_port_t *port = &PPORT;
294 	emlxs_port_t *vport;
295 	int32_t j;
296 	MATCHMAP *mp;
297 	CHANNEL *cp;
298 	RING *rp;
299 	MBUF_INFO *buf_info;
300 	MBUF_INFO bufinfo;
301 	MATCHMAP **bpl_table;
302 
303 	buf_info = &bufinfo;
304 
305 	for (j = 0; j < hba->chan_count; j++) {
306 		cp = &hba->chan[j];
307 
308 		/* Flush the ring */
309 		(void) emlxs_tx_channel_flush(hba, cp, 0);
310 	}
311 
312 	if (!(hba->model_info.sli_mask & EMLXS_SLI4_MASK)) {
313 		/* free the mapped address match area for each ring */
314 		for (j = 0; j < MAX_RINGS; j++) {
315 			rp = &hba->sli.sli3.ring[j];
316 
317 			while (rp->fc_mpoff) {
318 				uint64_t addr;
319 
320 				addr = 0;
321 				mp = (MATCHMAP *)(rp->fc_mpoff);
322 
323 				if ((j == hba->channel_els) ||
324 				    (j == hba->channel_ct) ||
325 #ifdef SFCT_SUPPORT
326 				    (j == hba->CHANNEL_FCT) ||
327 #endif /* SFCT_SUPPORT */
328 				    (j == hba->channel_ip)) {
329 					addr = mp->phys;
330 				}
331 
332 				if ((mp = emlxs_mem_get_vaddr(hba, rp, addr))) {
333 					if (j == hba->channel_els) {
334 						emlxs_mem_put(hba,
335 						    MEM_ELSBUF, (void *)mp);
336 					} else if (j == hba->channel_ct) {
337 						emlxs_mem_put(hba,
338 						    MEM_CTBUF, (void *)mp);
339 					} else if (j == hba->channel_ip) {
340 						emlxs_mem_put(hba,
341 						    MEM_IPBUF, (void *)mp);
342 					}
343 #ifdef SFCT_SUPPORT
344 					else if (j == hba->CHANNEL_FCT) {
345 						emlxs_mem_put(hba,
346 						    MEM_FCTBUF, (void *)mp);
347 					}
348 #endif /* SFCT_SUPPORT */
349 
350 				}
351 			}
352 		}
353 	}
354 
355 	if (hba->flag & FC_HBQ_ENABLED) {
356 		emlxs_hbq_free_all(hba, EMLXS_ELS_HBQ_ID);
357 		emlxs_hbq_free_all(hba, EMLXS_IP_HBQ_ID);
358 		emlxs_hbq_free_all(hba, EMLXS_CT_HBQ_ID);
359 
360 		if (port->flag & EMLXS_TGT_ENABLED) {
361 			emlxs_hbq_free_all(hba, EMLXS_FCT_HBQ_ID);
362 		}
363 	}
364 
365 	/* Free the nodes */
366 	for (j = 0; j < MAX_VPORTS; j++) {
367 		vport = &VPORT(j);
368 		if (vport->node_count) {
369 			emlxs_node_destroy_all(vport);
370 		}
371 	}
372 
373 	/* Make sure the mailbox queue is empty */
374 	emlxs_mb_flush(hba);
375 
376 	if (hba->fc_table) {
377 		bzero(buf_info, sizeof (MBUF_INFO));
378 		buf_info->size = hba->max_iotag * sizeof (emlxs_buf_t *);
379 		buf_info->virt = hba->fc_table;
380 		emlxs_mem_free(hba, buf_info);
381 		hba->fc_table = NULL;
382 	}
383 
384 	if (hba->sli.sli3.bpl_table) {
385 		/* Return MEM_BPLs to their pool */
386 		bpl_table = (MATCHMAP**)hba->sli.sli3.bpl_table;
387 		for (j = 0; j < hba->max_iotag; j++) {
388 			mp = bpl_table[j];
389 			mp->flag &= ~MAP_TABLE_ALLOCATED;
390 			emlxs_mem_put(hba, MEM_BPL, (void*)mp);
391 		}
392 
393 		bzero(buf_info, sizeof (MBUF_INFO));
394 		buf_info->size = hba->max_iotag * sizeof (MATCHMAP *);
395 		buf_info->virt = hba->sli.sli3.bpl_table;
396 		emlxs_mem_free(hba, buf_info);
397 		hba->sli.sli3.bpl_table = NULL;
398 	}
399 
400 	/* Free the memory segments */
401 	for (j = 0; j < FC_MAX_SEG; j++) {
402 		emlxs_mem_pool_destroy(hba, &hba->memseg[j]);
403 	}
404 
405 	return (0);
406 
407 } /* emlxs_mem_free_buffer() */
408 
409 
410 /* Must hold EMLXS_MEMGET_LOCK when calling */
411 static uint32_t
412 emlxs_mem_pool_alloc(emlxs_hba_t *hba, MEMSEG *seg, uint32_t count)
413 {
414 	emlxs_port_t *port = &PPORT;
415 	uint8_t *bp = NULL;
416 	MATCHMAP *mp = NULL;
417 	MBUF_INFO *buf_info;
418 	MBUF_INFO local_buf_info;
419 	uint32_t i;
420 	uint32_t fc_numblks;
421 
422 	if (seg->fc_memsize == 0) {
423 		return (0);
424 	}
425 
426 	if (seg->fc_numblks >= seg->fc_hi_water) {
427 		return (0);
428 	}
429 
430 	if (count == 0) {
431 		return (0);
432 	}
433 
434 	if (count > (seg->fc_hi_water - seg->fc_numblks)) {
435 		count = (seg->fc_hi_water - seg->fc_numblks);
436 	}
437 
438 	buf_info = &local_buf_info;
439 	fc_numblks = seg->fc_numblks;
440 
441 	/* Check for initial allocation */
442 	if (!(seg->fc_memflag & FC_MEMSEG_PUT_ENABLED)) {
443 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pool_detail_msg,
444 		    "%s alloc:%d n=%d s=%d f=%x l=%d,%d,%d "
445 		    "f=%d:%d",
446 		    seg->fc_label, count, seg->fc_numblks,
447 		    seg->fc_memsize, seg->fc_memflag, seg->fc_lo_water,
448 		    seg->fc_hi_water, seg->fc_step, seg->fc_memget_cnt,
449 		    seg->fc_low);
450 	}
451 
452 	if (!(seg->fc_memflag & FC_MBUF_DMA)) {
453 		goto vmem_pool;
454 	}
455 
456 /* dma_pool */
457 
458 	for (i = 0; i < count; i++) {
459 		bzero(buf_info, sizeof (MBUF_INFO));
460 		buf_info->size = sizeof (MATCHMAP);
461 		buf_info->align = sizeof (void *);
462 
463 		(void) emlxs_mem_alloc(hba, buf_info);
464 		if (buf_info->virt == NULL) {
465 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mem_alloc_failed_msg,
466 			    "%s: count=%d size=%d",
467 			    seg->fc_label, seg->fc_numblks, seg->fc_memsize);
468 
469 			goto done;
470 		}
471 
472 		mp = (MATCHMAP *)buf_info->virt;
473 		bzero(mp, sizeof (MATCHMAP));
474 
475 		bzero(buf_info, sizeof (MBUF_INFO));
476 		buf_info->size  = seg->fc_memsize;
477 		buf_info->flags = seg->fc_memflag;
478 		buf_info->align = seg->fc_memalign;
479 
480 		(void) emlxs_mem_alloc(hba, buf_info);
481 		if (buf_info->virt == NULL) {
482 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mem_alloc_failed_msg,
483 			    "%s: count=%d size=%d",
484 			    seg->fc_label, seg->fc_numblks, seg->fc_memsize);
485 
486 			/* Free the mp object */
487 			bzero(buf_info, sizeof (MBUF_INFO));
488 			buf_info->size = sizeof (MATCHMAP);
489 			buf_info->virt = (void *)mp;
490 			emlxs_mem_free(hba, buf_info);
491 
492 			goto done;
493 		}
494 		bp = (uint8_t *)buf_info->virt;
495 		bzero(bp, seg->fc_memsize);
496 
497 		mp->virt = buf_info->virt;
498 		mp->phys = buf_info->phys;
499 		mp->size = buf_info->size;
500 		mp->dma_handle = buf_info->dma_handle;
501 		mp->data_handle = buf_info->data_handle;
502 		mp->tag = seg->fc_memtag;
503 		mp->segment = seg;
504 		mp->flag |= MAP_POOL_ALLOCATED;
505 
506 #ifdef SFCT_SUPPORT
507 		if (mp->tag >= MEM_FCTSEG) {
508 			if (emlxs_fct_stmf_alloc(hba, mp)) {
509 				/* Free the DMA memory itself */
510 				emlxs_mem_free(hba, buf_info);
511 
512 				/* Free the mp object */
513 				bzero(buf_info, sizeof (MBUF_INFO));
514 				buf_info->size = sizeof (MATCHMAP);
515 				buf_info->virt = (void *)mp;
516 				emlxs_mem_free(hba, buf_info);
517 
518 				goto done;
519 			}
520 		}
521 #endif /* SFCT_SUPPORT */
522 
523 		/* Add the buffer desc to the tail of the pool freelist */
524 		if (seg->fc_memget_end == NULL) {
525 			seg->fc_memget_ptr = (uint8_t *)mp;
526 			seg->fc_memget_cnt = 1;
527 		} else {
528 			*((uint8_t **)(seg->fc_memget_end)) = (uint8_t *)mp;
529 			seg->fc_memget_cnt++;
530 		}
531 		seg->fc_memget_end = (uint8_t *)mp;
532 
533 		seg->fc_numblks++;
534 		seg->fc_total_memsize += (seg->fc_memsize + sizeof (MATCHMAP));
535 	}
536 
537 	goto done;
538 
539 vmem_pool:
540 
541 	for (i = 0; i < count; i++) {
542 		bzero(buf_info, sizeof (MBUF_INFO));
543 		buf_info->size  = seg->fc_memsize;
544 
545 		(void) emlxs_mem_alloc(hba, buf_info);
546 		if (buf_info->virt == NULL) {
547 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mem_alloc_failed_msg,
548 			    "%s: count=%d size=%d",
549 			    seg->fc_label, seg->fc_numblks, seg->fc_memsize);
550 
551 			goto done;
552 		}
553 		bp = (uint8_t *)buf_info->virt;
554 
555 		/* Add the buffer to the tail of the pool freelist */
556 		if (seg->fc_memget_end == NULL) {
557 			seg->fc_memget_ptr = (uint8_t *)bp;
558 			seg->fc_memget_cnt = 1;
559 		} else {
560 			*((uint8_t **)(seg->fc_memget_end)) = (uint8_t *)bp;
561 			seg->fc_memget_cnt++;
562 		}
563 		seg->fc_memget_end = (uint8_t *)bp;
564 
565 		seg->fc_numblks++;
566 		seg->fc_total_memsize += seg->fc_memsize;
567 	}
568 
569 done:
570 
571 	return ((seg->fc_numblks - fc_numblks));
572 
573 } /* emlxs_mem_pool_alloc() */
574 
575 
576 /* Must hold EMLXS_MEMGET_LOCK & EMLXS_MEMPUT_LOCK when calling */
577 static void
578 emlxs_mem_pool_free(emlxs_hba_t *hba, MEMSEG *seg, uint32_t count)
579 {
580 	emlxs_port_t *port = &PPORT;
581 	uint8_t *bp = NULL;
582 	MATCHMAP *mp = NULL;
583 	MBUF_INFO *buf_info;
584 	MBUF_INFO local_buf_info;
585 
586 	if ((seg->fc_memsize == 0) ||
587 	    (seg->fc_numblks == 0) ||
588 	    (count == 0)) {
589 		return;
590 	}
591 
592 	/* Check max count */
593 	if (count > seg->fc_numblks) {
594 		count = seg->fc_numblks;
595 	}
596 
597 	/* Move memput list to memget list */
598 	if (seg->fc_memput_ptr) {
599 		if (seg->fc_memget_end == NULL) {
600 			seg->fc_memget_ptr = seg->fc_memput_ptr;
601 		} else {
602 			*((uint8_t **)(seg->fc_memget_end)) =\
603 			    seg->fc_memput_ptr;
604 		}
605 		seg->fc_memget_end = seg->fc_memput_end;
606 		seg->fc_memget_cnt += seg->fc_memput_cnt;
607 
608 		seg->fc_memput_ptr = NULL;
609 		seg->fc_memput_end = NULL;
610 		seg->fc_memput_cnt = 0;
611 	}
612 
613 	buf_info = &local_buf_info;
614 
615 	/* Check for final deallocation */
616 	if (!(seg->fc_memflag & FC_MEMSEG_GET_ENABLED)) {
617 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pool_detail_msg,
618 		    "%s free:%d n=%d s=%d f=%x l=%d,%d,%d "
619 		    "f=%d:%d",
620 		    seg->fc_label, count, seg->fc_numblks,
621 		    seg->fc_memsize, seg->fc_memflag, seg->fc_lo_water,
622 		    seg->fc_hi_water, seg->fc_step, seg->fc_memget_cnt,
623 		    seg->fc_low);
624 	}
625 
626 	if (!(seg->fc_memflag & FC_MBUF_DMA)) {
627 		goto vmem_pool;
628 	}
629 
630 dma_pool:
631 
632 	/* Free memory associated with all buffers on get buffer pool */
633 	while (count && ((bp = seg->fc_memget_ptr) != NULL)) {
634 		/* Remove buffer from list */
635 		if (seg->fc_memget_end == bp) {
636 			seg->fc_memget_ptr = NULL;
637 			seg->fc_memget_end = NULL;
638 			seg->fc_memget_cnt = 0;
639 
640 		} else {
641 			seg->fc_memget_ptr = *((uint8_t **)bp);
642 			seg->fc_memget_cnt--;
643 		}
644 		mp = (MATCHMAP *)bp;
645 
646 #ifdef SFCT_SUPPORT
647 		if (mp->tag >= MEM_FCTSEG) {
648 			emlxs_fct_stmf_free(hba, mp);
649 		}
650 #endif /* SFCT_SUPPORT */
651 
652 		/* Free the DMA memory itself */
653 		bzero(buf_info, sizeof (MBUF_INFO));
654 		buf_info->size = mp->size;
655 		buf_info->virt = mp->virt;
656 		buf_info->phys = mp->phys;
657 		buf_info->dma_handle = mp->dma_handle;
658 		buf_info->data_handle = mp->data_handle;
659 		buf_info->flags = seg->fc_memflag;
660 		emlxs_mem_free(hba, buf_info);
661 
662 		/* Free the handle */
663 		bzero(buf_info, sizeof (MBUF_INFO));
664 		buf_info->size = sizeof (MATCHMAP);
665 		buf_info->virt = (void *)mp;
666 		emlxs_mem_free(hba, buf_info);
667 
668 		seg->fc_numblks--;
669 		seg->fc_total_memsize -= (seg->fc_memsize + sizeof (MATCHMAP));
670 
671 		count--;
672 	}
673 
674 	return;
675 
676 vmem_pool:
677 
678 	/* Free memory associated with all buffers on get buffer pool */
679 	while (count && ((bp = seg->fc_memget_ptr) != NULL)) {
680 		/* Remove buffer from list */
681 		if (seg->fc_memget_end == bp) {
682 			seg->fc_memget_ptr = NULL;
683 			seg->fc_memget_end = NULL;
684 			seg->fc_memget_cnt = 0;
685 
686 		} else {
687 			seg->fc_memget_ptr = *((uint8_t **)bp);
688 			seg->fc_memget_cnt--;
689 		}
690 
691 		/* Free the Virtual memory itself */
692 		bzero(buf_info, sizeof (MBUF_INFO));
693 		buf_info->size = seg->fc_memsize;
694 		buf_info->virt = bp;
695 		emlxs_mem_free(hba, buf_info);
696 
697 		seg->fc_numblks--;
698 		seg->fc_total_memsize -= seg->fc_memsize;
699 
700 		count--;
701 	}
702 
703 	return;
704 
705 } /* emlxs_mem_pool_free() */
706 
707 
708 extern uint32_t
709 emlxs_mem_pool_create(emlxs_hba_t *hba, MEMSEG *seg)
710 {
711 	emlxs_config_t *cfg = &CFG;
712 
713 	mutex_enter(&EMLXS_MEMGET_LOCK);
714 	mutex_enter(&EMLXS_MEMPUT_LOCK);
715 
716 	if (seg->fc_memsize == 0) {
717 		mutex_exit(&EMLXS_MEMPUT_LOCK);
718 		mutex_exit(&EMLXS_MEMGET_LOCK);
719 
720 		return (0);
721 	}
722 
723 	/* Sanity check hi > lo */
724 	if (seg->fc_lo_water > seg->fc_hi_water) {
725 		seg->fc_hi_water = seg->fc_lo_water;
726 	}
727 
728 	/* If dynamic pools are disabled, then force pool to max level */
729 	if (cfg[CFG_MEM_DYNAMIC].current == 0) {
730 		seg->fc_lo_water = seg->fc_hi_water;
731 	}
732 
733 	/* If pool is dynamic, then fc_step must be >0 */
734 	/* Otherwise, fc_step must be 0 */
735 	if (seg->fc_lo_water != seg->fc_hi_water) {
736 		seg->fc_memflag |= FC_MEMSEG_DYNAMIC;
737 
738 		if (seg->fc_step == 0) {
739 			seg->fc_step = 1;
740 		}
741 	} else {
742 		seg->fc_step = 0;
743 	}
744 
745 	seg->fc_numblks = 0;
746 	seg->fc_total_memsize = 0;
747 	seg->fc_low = 0;
748 
749 	(void) emlxs_mem_pool_alloc(hba, seg, seg->fc_lo_water);
750 
751 	seg->fc_memflag |= (FC_MEMSEG_PUT_ENABLED|FC_MEMSEG_GET_ENABLED);
752 
753 	mutex_exit(&EMLXS_MEMPUT_LOCK);
754 	mutex_exit(&EMLXS_MEMGET_LOCK);
755 
756 	return (seg->fc_numblks);
757 
758 } /* emlxs_mem_pool_create() */
759 
760 
761 extern void
762 emlxs_mem_pool_destroy(emlxs_hba_t *hba, MEMSEG *seg)
763 {
764 	emlxs_port_t *port = &PPORT;
765 
766 	mutex_enter(&EMLXS_MEMGET_LOCK);
767 	mutex_enter(&EMLXS_MEMPUT_LOCK);
768 
769 	if (seg->fc_memsize == 0) {
770 		mutex_exit(&EMLXS_MEMPUT_LOCK);
771 		mutex_exit(&EMLXS_MEMGET_LOCK);
772 		return;
773 	}
774 
775 	/* Leave FC_MEMSEG_PUT_ENABLED set for now */
776 	seg->fc_memflag &= ~FC_MEMSEG_GET_ENABLED;
777 
778 	/* Try to free all objects */
779 	emlxs_mem_pool_free(hba, seg, seg->fc_numblks);
780 
781 	if (seg->fc_numblks) {
782 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pool_detail_msg,
783 		    "mem_pool_destroy: %s leak detected: "
784 		    "%d objects still allocated.",
785 		    seg->fc_label, seg->fc_numblks);
786 	} else {
787 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pool_detail_msg,
788 		    "mem_pool_destroy: %s destroyed.",
789 		    seg->fc_label);
790 
791 		/* Clear all */
792 		bzero(seg, sizeof (MEMSEG));
793 	}
794 
795 	mutex_exit(&EMLXS_MEMPUT_LOCK);
796 	mutex_exit(&EMLXS_MEMGET_LOCK);
797 
798 	return;
799 
800 } /* emlxs_mem_pool_destroy() */
801 
802 
803 extern void
804 emlxs_mem_pool_clean(emlxs_hba_t *hba, MEMSEG *seg)
805 {
806 	emlxs_port_t *port = &PPORT;
807 	uint32_t clean_count;
808 	uint32_t free_count;
809 	uint32_t free_pad;
810 
811 	mutex_enter(&EMLXS_MEMGET_LOCK);
812 	mutex_enter(&EMLXS_MEMPUT_LOCK);
813 
814 	if (!(seg->fc_memflag & FC_MEMSEG_DYNAMIC)) {
815 		mutex_exit(&EMLXS_MEMPUT_LOCK);
816 		mutex_exit(&EMLXS_MEMGET_LOCK);
817 		return;
818 	}
819 
820 	if (!(seg->fc_memflag & FC_MEMSEG_GET_ENABLED)) {
821 		goto done;
822 	}
823 
824 #ifdef EMLXS_POOL_DEBUG
825 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pool_detail_msg,
826 	    "%s clean: n=%d s=%d f=%x l=%d,%d,%d "
827 	    "f=%d:%d",
828 	    seg->fc_label, seg->fc_numblks,
829 	    seg->fc_memsize, seg->fc_memflag, seg->fc_lo_water,
830 	    seg->fc_hi_water, seg->fc_step, seg->fc_memget_cnt,
831 	    seg->fc_low);
832 #endif /* EMLXS_POOL_DEBUG */
833 
834 	/* Calculatge current free count */
835 	free_count = (seg->fc_memget_cnt + seg->fc_memput_cnt);
836 
837 	/* Reset fc_low value to current free count */
838 	clean_count = seg->fc_low;
839 	seg->fc_low = free_count;
840 
841 	/* Return if pool is already at lo water mark */
842 	if (seg->fc_numblks <= seg->fc_lo_water) {
843 		goto done;
844 	}
845 
846 	/* Return if there is nothing to clean */
847 	if ((free_count == 0) ||
848 	    (clean_count <= 1)) {
849 		goto done;
850 	}
851 
852 	/* Calculate a 3 percent free pad count (1 being minimum) */
853 	if (seg->fc_numblks > 66) {
854 		free_pad = ((seg->fc_numblks * 3)/100);
855 	} else {
856 		free_pad = 1;
857 	}
858 
859 	/* Return if fc_low is below pool free pad */
860 	if (clean_count <= free_pad) {
861 		goto done;
862 	}
863 
864 	clean_count -= free_pad;
865 
866 	/* clean_count can't exceed minimum pool levels */
867 	if (clean_count > (seg->fc_numblks - seg->fc_lo_water)) {
868 		clean_count = (seg->fc_numblks - seg->fc_lo_water);
869 	}
870 
871 	emlxs_mem_pool_free(hba, seg, clean_count);
872 
873 done:
874 	if (seg->fc_last != seg->fc_numblks) {
875 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pool_detail_msg,
876 		    "%s update: n=%d->%d s=%d f=%x l=%d,%d,%d "
877 		    "f=%d:%d",
878 		    seg->fc_label, seg->fc_last, seg->fc_numblks,
879 		    seg->fc_memsize, seg->fc_memflag, seg->fc_lo_water,
880 		    seg->fc_hi_water, seg->fc_step, seg->fc_memget_cnt,
881 		    seg->fc_low);
882 
883 		seg->fc_last = seg->fc_numblks;
884 	}
885 
886 	mutex_exit(&EMLXS_MEMPUT_LOCK);
887 	mutex_exit(&EMLXS_MEMGET_LOCK);
888 	return;
889 
890 } /* emlxs_mem_pool_clean() */
891 
892 
893 extern void *
894 emlxs_mem_pool_get(emlxs_hba_t *hba, MEMSEG *seg)
895 {
896 	emlxs_port_t	*port = &PPORT;
897 	void		*bp = NULL;
898 	MATCHMAP	*mp;
899 	uint32_t	free_count;
900 
901 	mutex_enter(&EMLXS_MEMGET_LOCK);
902 
903 	/* Check if memory pool is GET enabled */
904 	if (!(seg->fc_memflag & FC_MEMSEG_GET_ENABLED)) {
905 		mutex_exit(&EMLXS_MEMGET_LOCK);
906 		return (NULL);
907 	}
908 
909 	/* If no entries on memget list, then check memput list */
910 	if (!seg->fc_memget_ptr) {
911 		mutex_enter(&EMLXS_MEMPUT_LOCK);
912 		if (seg->fc_memput_ptr) {
913 			/*
914 			 * Move list from memput to memget
915 			 */
916 			seg->fc_memget_ptr = seg->fc_memput_ptr;
917 			seg->fc_memget_end = seg->fc_memput_end;
918 			seg->fc_memget_cnt = seg->fc_memput_cnt;
919 			seg->fc_memput_ptr = NULL;
920 			seg->fc_memput_end = NULL;
921 			seg->fc_memput_cnt = 0;
922 		}
923 		mutex_exit(&EMLXS_MEMPUT_LOCK);
924 	}
925 
926 	/* If no entries on memget list, then pool is empty */
927 	/* Try to allocate more if pool is dynamic */
928 	if (!seg->fc_memget_ptr &&
929 	    (seg->fc_memflag & FC_MEMSEG_DYNAMIC)) {
930 		(void) emlxs_mem_pool_alloc(hba, seg,  seg->fc_step);
931 		seg->fc_low = 0;
932 	}
933 
934 	/* If no entries on memget list, then pool is empty */
935 	if (!seg->fc_memget_ptr) {
936 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pool_alloc_failed_msg,
937 		    "%s empty.", seg->fc_label);
938 
939 		mutex_exit(&EMLXS_MEMGET_LOCK);
940 		return (NULL);
941 	}
942 
943 	/* Remove an entry from the get list */
944 	bp = seg->fc_memget_ptr;
945 
946 	if (seg->fc_memget_end == bp) {
947 		seg->fc_memget_ptr = NULL;
948 		seg->fc_memget_end = NULL;
949 		seg->fc_memget_cnt = 0;
950 
951 	} else {
952 		seg->fc_memget_ptr = *((uint8_t **)bp);
953 		seg->fc_memget_cnt--;
954 	}
955 
956 	/* Initialize buffer */
957 	if (!(seg->fc_memflag & FC_MBUF_DMA)) {
958 		bzero(bp, seg->fc_memsize);
959 	} else {
960 		mp = (MATCHMAP *)bp;
961 		mp->fc_mptr = NULL;
962 		mp->flag |= MAP_POOL_ALLOCATED;
963 	}
964 
965 	/* Set fc_low if pool is dynamic */
966 	if (seg->fc_memflag & FC_MEMSEG_DYNAMIC) {
967 		free_count = (seg->fc_memget_cnt + seg->fc_memput_cnt);
968 		if (free_count < seg->fc_low) {
969 			seg->fc_low = free_count;
970 		}
971 	}
972 
973 	mutex_exit(&EMLXS_MEMGET_LOCK);
974 
975 	return (bp);
976 
977 } /* emlxs_mem_pool_get() */
978 
979 
980 extern void
981 emlxs_mem_pool_put(emlxs_hba_t *hba, MEMSEG *seg, void *bp)
982 {
983 	emlxs_port_t	*port = &PPORT;
984 	MATCHMAP	*mp;
985 
986 	/* Free the pool object */
987 	mutex_enter(&EMLXS_MEMPUT_LOCK);
988 
989 	/* Check if memory pool is PUT enabled */
990 	if (!(seg->fc_memflag & FC_MEMSEG_PUT_ENABLED)) {
991 		mutex_exit(&EMLXS_MEMPUT_LOCK);
992 		return;
993 	}
994 
995 	/* Check if buffer was just freed */
996 	if ((seg->fc_memput_end == bp) || (seg->fc_memget_end == bp)) {
997 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pool_error_msg,
998 		    "%s: Freeing free object: bp=%p", seg->fc_label, bp);
999 
1000 		mutex_exit(&EMLXS_MEMPUT_LOCK);
1001 		return;
1002 	}
1003 
1004 	/* Validate DMA buffer */
1005 	if (seg->fc_memflag & FC_MBUF_DMA) {
1006 		mp = (MATCHMAP *)bp;
1007 
1008 		if (!(mp->flag & MAP_POOL_ALLOCATED) ||
1009 		    (mp->segment != seg)) {
1010 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pool_error_msg,
1011 			    "mem_pool_put: %s invalid: mp=%p " \
1012 			    "tag=0x%x flag=%x", seg->fc_label,
1013 			    mp, mp->tag, mp->flag);
1014 
1015 			EMLXS_STATE_CHANGE(hba, FC_ERROR);
1016 
1017 			mutex_exit(&EMLXS_MEMPUT_LOCK);
1018 
1019 			emlxs_thread_spawn(hba, emlxs_shutdown_thread,
1020 			    NULL, NULL);
1021 
1022 			return;
1023 		}
1024 	}
1025 
1026 	/* Release buffer to the end of the memput list */
1027 	if (seg->fc_memput_end == NULL) {
1028 		seg->fc_memput_ptr = bp;
1029 		seg->fc_memput_cnt = 1;
1030 	} else {
1031 		*((void **)(seg->fc_memput_end)) = bp;
1032 		seg->fc_memput_cnt++;
1033 	}
1034 	seg->fc_memput_end = bp;
1035 	*((void **)(bp)) = NULL;
1036 
1037 	mutex_exit(&EMLXS_MEMPUT_LOCK);
1038 
1039 	/* This is for late PUT's after an initial */
1040 	/* emlxs_mem_pool_destroy call */
1041 	if ((seg->fc_memflag & FC_MEMSEG_PUT_ENABLED) &&
1042 	    !(seg->fc_memflag & FC_MEMSEG_GET_ENABLED)) {
1043 		emlxs_mem_pool_destroy(hba, seg);
1044 	}
1045 
1046 	return;
1047 
1048 } /* emlxs_mem_pool_put() */
1049 
1050 
1051 extern MATCHMAP *
1052 emlxs_mem_buf_alloc(emlxs_hba_t *hba, uint32_t size)
1053 {
1054 	emlxs_port_t *port = &PPORT;
1055 	uint8_t *bp = NULL;
1056 	MATCHMAP *mp = NULL;
1057 	MBUF_INFO *buf_info;
1058 	MBUF_INFO bufinfo;
1059 
1060 	buf_info = &bufinfo;
1061 
1062 	bzero(buf_info, sizeof (MBUF_INFO));
1063 	buf_info->size = sizeof (MATCHMAP);
1064 	buf_info->align = sizeof (void *);
1065 
1066 	(void) emlxs_mem_alloc(hba, buf_info);
1067 	if (buf_info->virt == NULL) {
1068 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mem_alloc_failed_msg,
1069 		    "MEM_BUF_ALLOC buffer.");
1070 
1071 		return (NULL);
1072 	}
1073 
1074 	mp = (MATCHMAP *)buf_info->virt;
1075 	bzero(mp, sizeof (MATCHMAP));
1076 
1077 	bzero(buf_info, sizeof (MBUF_INFO));
1078 	buf_info->size = size;
1079 	buf_info->flags = FC_MBUF_DMA | FC_MBUF_SNGLSG;
1080 	buf_info->align = 32;
1081 
1082 	(void) emlxs_mem_alloc(hba, buf_info);
1083 	if (buf_info->virt == NULL) {
1084 
1085 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mem_alloc_failed_msg,
1086 		    "MEM_BUF_ALLOC DMA buffer.");
1087 
1088 		/* Free the mp object */
1089 		bzero(buf_info, sizeof (MBUF_INFO));
1090 		buf_info->size = sizeof (MATCHMAP);
1091 		buf_info->virt = (void *)mp;
1092 		emlxs_mem_free(hba, buf_info);
1093 
1094 		return (NULL);
1095 	}
1096 	bp = (uint8_t *)buf_info->virt;
1097 	bzero(bp, buf_info->size);
1098 
1099 	mp->virt = buf_info->virt;
1100 	mp->phys = buf_info->phys;
1101 	mp->size = buf_info->size;
1102 	mp->dma_handle = buf_info->dma_handle;
1103 	mp->data_handle = buf_info->data_handle;
1104 	mp->tag = MEM_BUF;
1105 	mp->flag |= MAP_BUF_ALLOCATED;
1106 
1107 	return (mp);
1108 
1109 } /* emlxs_mem_buf_alloc() */
1110 
1111 
1112 extern void
1113 emlxs_mem_buf_free(emlxs_hba_t *hba, MATCHMAP *mp)
1114 {
1115 	MBUF_INFO bufinfo;
1116 	MBUF_INFO *buf_info;
1117 
1118 	buf_info = &bufinfo;
1119 
1120 	if (!(mp->flag & MAP_BUF_ALLOCATED)) {
1121 		return;
1122 	}
1123 
1124 	bzero(buf_info, sizeof (MBUF_INFO));
1125 	buf_info->size = mp->size;
1126 	buf_info->virt = mp->virt;
1127 	buf_info->phys = mp->phys;
1128 	buf_info->dma_handle = mp->dma_handle;
1129 	buf_info->data_handle = mp->data_handle;
1130 	buf_info->flags = FC_MBUF_DMA;
1131 	emlxs_mem_free(hba, buf_info);
1132 
1133 	bzero(buf_info, sizeof (MBUF_INFO));
1134 	buf_info->size = sizeof (MATCHMAP);
1135 	buf_info->virt = (void *)mp;
1136 	emlxs_mem_free(hba, buf_info);
1137 
1138 	return;
1139 
1140 } /* emlxs_mem_buf_free() */
1141 
1142 
1143 extern void *
1144 emlxs_mem_get(emlxs_hba_t *hba, uint32_t seg_id)
1145 {
1146 	emlxs_port_t	*port = &PPORT;
1147 	void		*bp;
1148 	MAILBOXQ	*mbq;
1149 	IOCBQ		*iocbq;
1150 	NODELIST	*node;
1151 	MEMSEG		*seg;
1152 
1153 	if (seg_id >= FC_MAX_SEG) {
1154 
1155 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pool_error_msg,
1156 		    "mem_get: Invalid segment id = %d",
1157 		    seg_id);
1158 
1159 		return (NULL);
1160 	}
1161 	seg = &hba->memseg[seg_id];
1162 
1163 	/* Alloc a buffer from the pool */
1164 	bp = emlxs_mem_pool_get(hba, seg);
1165 
1166 	if (bp) {
1167 		switch (seg_id) {
1168 		case MEM_MBOX:
1169 			mbq = (MAILBOXQ *)bp;
1170 			mbq->flag |= MBQ_POOL_ALLOCATED;
1171 			break;
1172 
1173 		case MEM_IOCB:
1174 			iocbq = (IOCBQ *)bp;
1175 			iocbq->flag |= IOCB_POOL_ALLOCATED;
1176 			break;
1177 
1178 		case MEM_NLP:
1179 			node = (NODELIST *)bp;
1180 			node->flag |= NODE_POOL_ALLOCATED;
1181 			break;
1182 		}
1183 	}
1184 
1185 	return (bp);
1186 
1187 } /* emlxs_mem_get() */
1188 
1189 
1190 extern void
1191 emlxs_mem_put(emlxs_hba_t *hba, uint32_t seg_id, void *bp)
1192 {
1193 	emlxs_port_t	*port = &PPORT;
1194 	MAILBOXQ	*mbq;
1195 	IOCBQ		*iocbq;
1196 	NODELIST	*node;
1197 	MEMSEG		*seg;
1198 	MATCHMAP	*mp;
1199 
1200 	if (seg_id >= FC_MAX_SEG) {
1201 
1202 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pool_error_msg,
1203 		    "mem_put: Invalid segment id = %d: bp=%p",
1204 		    seg_id, bp);
1205 
1206 		return;
1207 	}
1208 	seg = &hba->memseg[seg_id];
1209 
1210 	/* Verify buffer */
1211 	switch (seg_id) {
1212 	case MEM_MBOX:
1213 		mbq = (MAILBOXQ *)bp;
1214 
1215 		if (!(mbq->flag & MBQ_POOL_ALLOCATED)) {
1216 			return;
1217 		}
1218 		break;
1219 
1220 	case MEM_IOCB:
1221 		iocbq = (IOCBQ *)bp;
1222 
1223 		if (!(iocbq->flag & IOCB_POOL_ALLOCATED)) {
1224 			return;
1225 		}
1226 
1227 		/* Any IOCBQ with a packet attached did not come */
1228 		/* from our pool */
1229 		if (iocbq->sbp) {
1230 			return;
1231 		}
1232 		break;
1233 
1234 	case MEM_NLP:
1235 		node = (NODELIST *)bp;
1236 
1237 		if (!(node->flag & NODE_POOL_ALLOCATED)) {
1238 			return;
1239 		}
1240 		break;
1241 
1242 	default:
1243 		mp = (MATCHMAP *)bp;
1244 
1245 		if (mp->flag & MAP_BUF_ALLOCATED) {
1246 			emlxs_mem_buf_free(hba, mp);
1247 			return;
1248 		}
1249 
1250 		if (mp->flag & MAP_TABLE_ALLOCATED) {
1251 			return;
1252 		}
1253 
1254 		if (!(mp->flag & MAP_POOL_ALLOCATED)) {
1255 			return;
1256 		}
1257 		break;
1258 	}
1259 
1260 	/* Free a buffer to the pool */
1261 	emlxs_mem_pool_put(hba, seg, bp);
1262 
1263 	return;
1264 
1265 } /* emlxs_mem_put() */
1266 
1267 
1268 /*
1269  * Look up the virtual address given a mapped address
1270  */
1271 /* SLI3 */
1272 extern MATCHMAP *
1273 emlxs_mem_get_vaddr(emlxs_hba_t *hba, RING *rp, uint64_t mapbp)
1274 {
1275 	emlxs_port_t *port = &PPORT;
1276 	MATCHMAP *prev;
1277 	MATCHMAP *mp;
1278 
1279 	if (rp->ringno == hba->channel_els) {
1280 		mp = (MATCHMAP *)rp->fc_mpoff;
1281 		prev = 0;
1282 
1283 		while (mp) {
1284 			if (mp->phys == mapbp) {
1285 				if (prev == 0) {
1286 					rp->fc_mpoff = mp->fc_mptr;
1287 				} else {
1288 					prev->fc_mptr = mp->fc_mptr;
1289 				}
1290 
1291 				if (rp->fc_mpon == mp) {
1292 					rp->fc_mpon = (void *)prev;
1293 				}
1294 
1295 				mp->fc_mptr = NULL;
1296 
1297 				EMLXS_MPDATA_SYNC(mp->dma_handle, 0, mp->size,
1298 				    DDI_DMA_SYNC_FORKERNEL);
1299 
1300 				HBASTATS.ElsUbPosted--;
1301 
1302 				return (mp);
1303 			}
1304 
1305 			prev = mp;
1306 			mp = (MATCHMAP *)mp->fc_mptr;
1307 		}
1308 
1309 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pool_error_msg,
1310 		    "ELS Buffer not mapped: bp=%lx ringno=%x mpoff=%p mpon=%p",
1311 		    mapbp, rp->ringno, rp->fc_mpoff, rp->fc_mpon);
1312 
1313 	} else if (rp->ringno == hba->channel_ct) {
1314 
1315 		mp = (MATCHMAP *)rp->fc_mpoff;
1316 		prev = 0;
1317 
1318 		while (mp) {
1319 			if (mp->phys == mapbp) {
1320 				if (prev == 0) {
1321 					rp->fc_mpoff = mp->fc_mptr;
1322 				} else {
1323 					prev->fc_mptr = mp->fc_mptr;
1324 				}
1325 
1326 				if (rp->fc_mpon == mp) {
1327 					rp->fc_mpon = (void *)prev;
1328 				}
1329 
1330 				mp->fc_mptr = NULL;
1331 
1332 				EMLXS_MPDATA_SYNC(mp->dma_handle, 0, mp->size,
1333 				    DDI_DMA_SYNC_FORKERNEL);
1334 
1335 				HBASTATS.CtUbPosted--;
1336 
1337 				return (mp);
1338 			}
1339 
1340 			prev = mp;
1341 			mp = (MATCHMAP *)mp->fc_mptr;
1342 		}
1343 
1344 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pool_error_msg,
1345 		    "CT Buffer not mapped: bp=%lx ringno=%x mpoff=%p mpon=%p",
1346 		    mapbp, rp->ringno, rp->fc_mpoff, rp->fc_mpon);
1347 
1348 	} else if (rp->ringno == hba->channel_ip) {
1349 
1350 		mp = (MATCHMAP *)rp->fc_mpoff;
1351 		prev = 0;
1352 
1353 		while (mp) {
1354 			if (mp->phys == mapbp) {
1355 				if (prev == 0) {
1356 					rp->fc_mpoff = mp->fc_mptr;
1357 				} else {
1358 					prev->fc_mptr = mp->fc_mptr;
1359 				}
1360 
1361 				if (rp->fc_mpon == mp) {
1362 					rp->fc_mpon = (void *)prev;
1363 				}
1364 
1365 				mp->fc_mptr = NULL;
1366 
1367 				EMLXS_MPDATA_SYNC(mp->dma_handle, 0, mp->size,
1368 				    DDI_DMA_SYNC_FORKERNEL);
1369 
1370 				HBASTATS.IpUbPosted--;
1371 
1372 				return (mp);
1373 			}
1374 
1375 			prev = mp;
1376 			mp = (MATCHMAP *)mp->fc_mptr;
1377 		}
1378 
1379 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pool_error_msg,
1380 		    "IP Buffer not mapped: bp=%lx ringno=%x mpoff=%p mpon=%p",
1381 		    mapbp, rp->ringno, rp->fc_mpoff, rp->fc_mpon);
1382 
1383 #ifdef SFCT_SUPPORT
1384 	} else if (rp->ringno == hba->CHANNEL_FCT) {
1385 		mp = (MATCHMAP *)rp->fc_mpoff;
1386 		prev = 0;
1387 
1388 		while (mp) {
1389 			if (mp->phys == mapbp) {
1390 				if (prev == 0) {
1391 					rp->fc_mpoff = mp->fc_mptr;
1392 				} else {
1393 					prev->fc_mptr = mp->fc_mptr;
1394 				}
1395 
1396 				if (rp->fc_mpon == mp) {
1397 					rp->fc_mpon = (void *)prev;
1398 				}
1399 
1400 				mp->fc_mptr = NULL;
1401 
1402 				EMLXS_MPDATA_SYNC(mp->dma_handle, 0, mp->size,
1403 				    DDI_DMA_SYNC_FORKERNEL);
1404 
1405 				HBASTATS.FctUbPosted--;
1406 
1407 				return (mp);
1408 			}
1409 
1410 			prev = mp;
1411 			mp = (MATCHMAP *)mp->fc_mptr;
1412 		}
1413 
1414 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pool_error_msg,
1415 		    "FCT Buffer not mapped: bp=%lx ringno=%x mpoff=%p mpon=%p",
1416 		    mapbp, rp->ringno, rp->fc_mpoff, rp->fc_mpon);
1417 
1418 #endif /* SFCT_SUPPORT */
1419 	}
1420 
1421 	return (0);
1422 
1423 } /* emlxs_mem_get_vaddr() */
1424 
1425 
1426 /*
1427  * Given a virtual address bp, generate the physical mapped address and
1428  * place it where addr points to. Save the address pair for lookup later.
1429  */
1430 /* SLI3 */
1431 extern void
1432 emlxs_mem_map_vaddr(emlxs_hba_t *hba, RING *rp, MATCHMAP *mp,
1433     uint32_t *haddr, uint32_t *laddr)
1434 {
1435 	if (rp->ringno == hba->channel_els) {
1436 		/*
1437 		 * Update slot fc_mpon points to then bump it
1438 		 * fc_mpoff is pointer head of the list.
1439 		 * fc_mpon is pointer tail of the list.
1440 		 */
1441 		mp->fc_mptr = NULL;
1442 		if (rp->fc_mpoff == 0) {
1443 			rp->fc_mpoff = (void *)mp;
1444 			rp->fc_mpon = (void *)mp;
1445 		} else {
1446 			((MATCHMAP *)(rp->fc_mpon))->fc_mptr =
1447 			    (void *)mp;
1448 			rp->fc_mpon = (void *)mp;
1449 		}
1450 
1451 		if (hba->flag & FC_SLIM2_MODE) {
1452 
1453 			/* return mapped address */
1454 			*haddr = PADDR_HI(mp->phys);
1455 			/* return mapped address */
1456 			*laddr = PADDR_LO(mp->phys);
1457 		} else {
1458 			/* return mapped address */
1459 			*laddr = PADDR_LO(mp->phys);
1460 		}
1461 
1462 		HBASTATS.ElsUbPosted++;
1463 
1464 	} else if (rp->ringno == hba->channel_ct) {
1465 		/*
1466 		 * Update slot fc_mpon points to then bump it
1467 		 * fc_mpoff is pointer head of the list.
1468 		 * fc_mpon is pointer tail of the list.
1469 		 */
1470 		mp->fc_mptr = NULL;
1471 		if (rp->fc_mpoff == 0) {
1472 			rp->fc_mpoff = (void *)mp;
1473 			rp->fc_mpon = (void *)mp;
1474 		} else {
1475 			((MATCHMAP *)(rp->fc_mpon))->fc_mptr =
1476 			    (void *)mp;
1477 			rp->fc_mpon = (void *)mp;
1478 		}
1479 
1480 		if (hba->flag & FC_SLIM2_MODE) {
1481 			/* return mapped address */
1482 			*haddr = PADDR_HI(mp->phys);
1483 			/* return mapped address */
1484 			*laddr = PADDR_LO(mp->phys);
1485 		} else {
1486 			/* return mapped address */
1487 			*laddr = PADDR_LO(mp->phys);
1488 		}
1489 
1490 		HBASTATS.CtUbPosted++;
1491 
1492 
1493 	} else if (rp->ringno == hba->channel_ip) {
1494 		/*
1495 		 * Update slot fc_mpon points to then bump it
1496 		 * fc_mpoff is pointer head of the list.
1497 		 * fc_mpon is pointer tail of the list.
1498 		 */
1499 		mp->fc_mptr = NULL;
1500 		if (rp->fc_mpoff == 0) {
1501 			rp->fc_mpoff = (void *)mp;
1502 			rp->fc_mpon = (void *)mp;
1503 		} else {
1504 			((MATCHMAP *)(rp->fc_mpon))->fc_mptr =
1505 			    (void *)mp;
1506 			rp->fc_mpon = (void *)mp;
1507 		}
1508 
1509 		if (hba->flag & FC_SLIM2_MODE) {
1510 			/* return mapped address */
1511 			*haddr = PADDR_HI(mp->phys);
1512 			*laddr = PADDR_LO(mp->phys);
1513 		} else {
1514 			*laddr = PADDR_LO(mp->phys);
1515 		}
1516 
1517 		HBASTATS.IpUbPosted++;
1518 
1519 
1520 #ifdef SFCT_SUPPORT
1521 	} else if (rp->ringno == hba->CHANNEL_FCT) {
1522 		/*
1523 		 * Update slot fc_mpon points to then bump it
1524 		 * fc_mpoff is pointer head of the list.
1525 		 * fc_mpon is pointer tail of the list.
1526 		 */
1527 		mp->fc_mptr = NULL;
1528 		if (rp->fc_mpoff == 0) {
1529 			rp->fc_mpoff = (void *)mp;
1530 			rp->fc_mpon = (void *)mp;
1531 		} else {
1532 			((MATCHMAP *)(rp->fc_mpon))->fc_mptr =
1533 			    (void *)mp;
1534 			rp->fc_mpon = (void *)mp;
1535 		}
1536 
1537 		if (hba->flag & FC_SLIM2_MODE) {
1538 			/* return mapped address */
1539 			*haddr = PADDR_HI(mp->phys);
1540 			/* return mapped address */
1541 			*laddr = PADDR_LO(mp->phys);
1542 		} else {
1543 			/* return mapped address */
1544 			*laddr = PADDR_LO(mp->phys);
1545 		}
1546 
1547 		HBASTATS.FctUbPosted++;
1548 
1549 #endif /* SFCT_SUPPORT */
1550 	}
1551 } /* emlxs_mem_map_vaddr() */
1552 
1553 
1554 /* SLI3 */
1555 uint32_t
1556 emlxs_hbq_alloc(emlxs_hba_t *hba, uint32_t hbq_id)
1557 {
1558 	emlxs_port_t *port = &PPORT;
1559 	HBQ_INIT_t *hbq;
1560 	MBUF_INFO *buf_info;
1561 	MBUF_INFO bufinfo;
1562 
1563 	hbq = &hba->sli.sli3.hbq_table[hbq_id];
1564 
1565 	if (hbq->HBQ_host_buf.virt == 0) {
1566 		buf_info = &bufinfo;
1567 
1568 		/* Get the system's page size in a DDI-compliant way. */
1569 		bzero(buf_info, sizeof (MBUF_INFO));
1570 		buf_info->size = hbq->HBQ_numEntries * sizeof (HBQE_t);
1571 		buf_info->flags = FC_MBUF_DMA;
1572 		buf_info->align = 4096;
1573 
1574 		(void) emlxs_mem_alloc(hba, buf_info);
1575 
1576 		if (buf_info->virt == NULL) {
1577 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mem_alloc_msg,
1578 			    "Unable to alloc HBQ.");
1579 			return (ENOMEM);
1580 		}
1581 
1582 		hbq->HBQ_host_buf.virt = buf_info->virt;
1583 		hbq->HBQ_host_buf.phys = buf_info->phys;
1584 		hbq->HBQ_host_buf.data_handle = buf_info->data_handle;
1585 		hbq->HBQ_host_buf.dma_handle = buf_info->dma_handle;
1586 		hbq->HBQ_host_buf.size = buf_info->size;
1587 		hbq->HBQ_host_buf.tag = hbq_id;
1588 
1589 		bzero((char *)hbq->HBQ_host_buf.virt, buf_info->size);
1590 	}
1591 
1592 	return (0);
1593 
1594 } /* emlxs_hbq_alloc() */
1595