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