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