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 usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*
  26  * Copyright (c) 2005 SilverStorm Technologies, Inc. All rights reserved.
  27  *
  28  * This software is available to you under a choice of one of two
  29  * licenses.  You may choose to be licensed under the terms of the GNU
  30  * General Public License (GPL) Version 2, available from the file
  31  * COPYING in the main directory of this source tree, or the
  32  * OpenIB.org BSD license below:
  33  *
  34  *     Redistribution and use in source and binary forms, with or
  35  *     without modification, are permitted provided that the following
  36  *     conditions are met:
  37  *
  38  *      - Redistributions of source code must retain the above
  39  *        copyright notice, this list of conditions and the following
  40  *        disclaimer.
  41  *
  42  *      - Redistributions in binary form must reproduce the above
  43  *        copyright notice, this list of conditions and the following
  44  *        disclaimer in the documentation and/or other materials
  45  *        provided with the distribution.
  46  *
  47  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  48  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  49  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  50  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  51  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  52  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  53  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  54  * SOFTWARE.
  55  *
  56  */
  57 /*
  58  * Sun elects to include this software in Sun product
  59  * under the OpenIB BSD license.
  60  *
  61  *
  62  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  63  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  64  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  65  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  66  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  67  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  68  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  69  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  70  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  71  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  72  * POSSIBILITY OF SUCH DAMAGE.
  73  */
  74 
  75 #include <sys/ib/clients/rds/rdsib_cm.h>
  76 #include <sys/ib/clients/rds/rdsib_ib.h>
  77 #include <sys/ib/clients/rds/rdsib_buf.h>
  78 #include <sys/ib/clients/rds/rdsib_ep.h>
  79 #include <sys/ib/clients/rds/rds_kstat.h>
  80 
  81 /*
  82  * This File contains the buffer management code
  83  */
  84 
  85 #define DUMP_USER_PARAMS()      \
  86         RDS_DPRINTF3(LABEL, "MaxNodes = %d", MaxNodes); \
  87         RDS_DPRINTF3(LABEL, "UserBufferSize = %d", UserBufferSize); \
  88         RDS_DPRINTF3(LABEL, "RdsPktSize = %d", RdsPktSize); \
  89         RDS_DPRINTF3(LABEL, "MaxDataSendBuffers = %d", MaxDataSendBuffers); \
  90         RDS_DPRINTF3(LABEL, "MaxDataRecvBuffers = %d", MaxDataRecvBuffers); \
  91         RDS_DPRINTF3(LABEL, "MaxCtrlSendBuffers = %d", MaxCtrlSendBuffers); \
  92         RDS_DPRINTF3(LABEL, "MaxCtrlRecvBuffers = %d", MaxCtrlRecvBuffers); \
  93         RDS_DPRINTF3(LABEL, "DataRecvBufferLWM = %d", DataRecvBufferLWM); \
  94         RDS_DPRINTF3(LABEL, "PendingRxPktsHWM = %d", PendingRxPktsHWM); \
  95         RDS_DPRINTF3(LABEL, "MinRnrRetry = %d", MinRnrRetry)
  96 
  97 uint_t  rds_nbuffers_to_putback;
  98 
  99 static void
 100 rds_free_mblk(char *arg)
 101 {
 102         rds_buf_t *bp = (rds_buf_t *)(uintptr_t)arg;
 103 
 104         /* Free the recv buffer */
 105         RDS_DPRINTF4("rds_free_mblk", "Enter: BP(%p)", bp);
 106         ASSERT(bp->buf_state == RDS_RCVBUF_ONSOCKQ);
 107         rds_free_recv_buf(bp, 1);
 108         RDS_DECR_RXPKTS_PEND(1);
 109         RDS_DPRINTF4("rds_free_mblk", "Return: BP(%p)", bp);
 110 }
 111 
 112 void
 113 rds_free_recv_caches(rds_state_t *statep)
 114 {
 115         rds_hca_t       *hcap;
 116         int             ret;
 117 
 118         RDS_DPRINTF4("rds_free_recv_caches", "Enter");
 119 
 120         mutex_enter(&rds_dpool.pool_lock);
 121         if (rds_dpool.pool_memp == NULL) {
 122                 RDS_DPRINTF2("rds_free_recv_caches", "Caches are empty");
 123                 mutex_exit(&rds_dpool.pool_lock);
 124                 return;
 125         }
 126 
 127         /*
 128          * All buffers must have been freed as all sessions are closed
 129          * and destroyed
 130          */
 131         ASSERT(rds_dpool.pool_nbusy == 0);
 132         RDS_DPRINTF2("rds_free_recv_caches", "Data Pool has "
 133             "pending buffers: %d", rds_dpool.pool_nbusy);
 134         while (rds_dpool.pool_nbusy != 0) {
 135                 mutex_exit(&rds_dpool.pool_lock);
 136                 delay(drv_sectohz(1));
 137                 mutex_enter(&rds_dpool.pool_lock);
 138         }
 139 
 140         hcap = statep->rds_hcalistp;
 141         while (hcap != NULL) {
 142                 if (hcap->hca_mrhdl != NULL) {
 143                         ret = ibt_deregister_mr(hcap->hca_hdl,
 144                             hcap->hca_mrhdl);
 145                         if (ret == IBT_SUCCESS) {
 146                                 hcap->hca_mrhdl = NULL;
 147                                 hcap->hca_lkey = 0;
 148                                 hcap->hca_rkey = 0;
 149                         } else {
 150                                 RDS_DPRINTF2(LABEL, "ibt_deregister_mr "
 151                                     "failed: %d, mrhdl: 0x%p", ret,
 152                                     hcap->hca_mrhdl);
 153                         }
 154                 }
 155                 hcap = hcap->hca_nextp;
 156         }
 157 
 158         kmem_free(rds_dpool.pool_bufmemp, (rds_dpool.pool_nbuffers +
 159             rds_cpool.pool_nbuffers) * sizeof (rds_buf_t));
 160         rds_dpool.pool_bufmemp = NULL;
 161 
 162         kmem_free(rds_dpool.pool_memp, rds_dpool.pool_memsize);
 163         rds_dpool.pool_memp = NULL;
 164 
 165         mutex_exit(&rds_dpool.pool_lock);
 166 
 167         RDS_DPRINTF4("rds_free_recv_caches", "Return");
 168 }
 169 
 170 int
 171 rds_init_recv_caches(rds_state_t *statep)
 172 {
 173         uint8_t         *mp;
 174         rds_buf_t       *bp;
 175         rds_hca_t       *hcap;
 176         uint32_t        nsessions;
 177         uint_t          ix;
 178         uint_t          nctrlrx;
 179         uint8_t         *memp;
 180         uint_t          memsize, nbuf;
 181         rds_buf_t       *bufmemp;
 182         ibt_mr_attr_t   mem_attr;
 183         ibt_mr_desc_t   mem_desc;
 184         int             ret;
 185 
 186         RDS_DPRINTF4("rds_init_recv_caches", "Enter");
 187 
 188         DUMP_USER_PARAMS();
 189 
 190         mutex_enter(&rds_dpool.pool_lock);
 191         if (rds_dpool.pool_memp != NULL) {
 192                 RDS_DPRINTF2("rds_init_recv_caches", "Pools are already "
 193                     "initialized");
 194                 mutex_exit(&rds_dpool.pool_lock);
 195                 return (0);
 196         }
 197 
 198         /*
 199          * High water mark for the receive buffers in the system. If the
 200          * number of buffers used crosses this mark then all sockets in
 201          * would be stalled. The port quota for the sockets is set based
 202          * on this limit.
 203          */
 204         rds_rx_pkts_pending_hwm = (PendingRxPktsHWM * NDataRX)/100;
 205 
 206         rds_nbuffers_to_putback = min(MaxCtrlRecvBuffers, MaxDataRecvBuffers);
 207 
 208         /* nsessions can never be less than 1 */
 209         nsessions = MaxNodes - 1;
 210         nctrlrx = (nsessions + 1) * MaxCtrlRecvBuffers * 2;
 211 
 212         RDS_DPRINTF3(LABEL, "Number of Possible Sessions: %d", nsessions);
 213 
 214         /* Add the hdr */
 215         RdsPktSize = UserBufferSize + RDS_DATA_HDR_SZ;
 216 
 217         memsize = (NDataRX * RdsPktSize) + (nctrlrx * RDS_CTRLPKT_SIZE);
 218         nbuf = NDataRX + nctrlrx;
 219         RDS_DPRINTF3(LABEL, "RDS Buffer Pool Memory: %lld", memsize);
 220         RDS_DPRINTF3(LABEL, "Total Buffers: %d", nbuf);
 221 
 222         memp = (uint8_t *)kmem_zalloc(memsize, KM_NOSLEEP);
 223         if (memp == NULL) {
 224                 RDS_DPRINTF1(LABEL, "RDS Memory allocation failed");
 225                 mutex_exit(&rds_dpool.pool_lock);
 226                 return (-1);
 227         }
 228 
 229         RDS_DPRINTF3(LABEL, "RDS Buffer Entries Memory: %lld",
 230             nbuf * sizeof (rds_buf_t));
 231 
 232         /* allocate memory for buffer entries */
 233         bufmemp = (rds_buf_t *)kmem_zalloc(nbuf * sizeof (rds_buf_t),
 234             KM_SLEEP);
 235 
 236         /* register the memory with all HCAs */
 237         mem_attr.mr_vaddr = (ib_vaddr_t)(uintptr_t)memp;
 238         mem_attr.mr_len = memsize;
 239         mem_attr.mr_as = NULL;
 240         mem_attr.mr_flags = IBT_MR_ENABLE_LOCAL_WRITE;
 241 
 242         rw_enter(&statep->rds_hca_lock, RW_WRITER);
 243 
 244         hcap = statep->rds_hcalistp;
 245         while (hcap != NULL) {
 246                 if (hcap->hca_state != RDS_HCA_STATE_OPEN) {
 247                         hcap = hcap->hca_nextp;
 248                         continue;
 249                 }
 250 
 251                 ret = ibt_register_mr(hcap->hca_hdl, hcap->hca_pdhdl,
 252                     &mem_attr, &hcap->hca_mrhdl, &mem_desc);
 253                 if (ret != IBT_SUCCESS) {
 254                         RDS_DPRINTF2(LABEL, "ibt_register_mr failed: %d", ret);
 255                         hcap = statep->rds_hcalistp;
 256                         while ((hcap) && (hcap->hca_mrhdl != NULL)) {
 257                                 ret = ibt_deregister_mr(hcap->hca_hdl,
 258                                     hcap->hca_mrhdl);
 259                                 if (ret == IBT_SUCCESS) {
 260                                         hcap->hca_mrhdl = NULL;
 261                                         hcap->hca_lkey = 0;
 262                                         hcap->hca_rkey = 0;
 263                                 } else {
 264                                         RDS_DPRINTF2(LABEL, "ibt_deregister_mr "
 265                                             "failed: %d, mrhdl: 0x%p", ret,
 266                                             hcap->hca_mrhdl);
 267                                 }
 268                                 hcap = hcap->hca_nextp;
 269                         }
 270                         kmem_free(bufmemp, nbuf * sizeof (rds_buf_t));
 271                         kmem_free(memp, memsize);
 272                         rw_exit(&statep->rds_hca_lock);
 273                         mutex_exit(&rds_dpool.pool_lock);
 274                         return (-1);
 275                 }
 276 
 277                 hcap->hca_state = RDS_HCA_STATE_MEM_REGISTERED;
 278                 hcap->hca_lkey = mem_desc.md_lkey;
 279                 hcap->hca_rkey = mem_desc.md_rkey;
 280 
 281                 hcap = hcap->hca_nextp;
 282         }
 283         rw_exit(&statep->rds_hca_lock);
 284 
 285         /* Initialize data pool */
 286         rds_dpool.pool_memp = memp;
 287         rds_dpool.pool_memsize = memsize;
 288         rds_dpool.pool_bufmemp = bufmemp;
 289         rds_dpool.pool_nbuffers = NDataRX;
 290         rds_dpool.pool_nbusy = 0;
 291         rds_dpool.pool_nfree = NDataRX;
 292 
 293         /* chain the buffers */
 294         mp = memp;
 295         bp = bufmemp;
 296         for (ix = 0; ix < NDataRX; ix++) {
 297                 bp[ix].buf_nextp = &bp[ix + 1];
 298                 bp[ix].buf_ds.ds_va = (ib_vaddr_t)(uintptr_t)mp;
 299                 bp[ix].buf_state = RDS_RCVBUF_FREE;
 300                 bp[ix].buf_frtn.free_func = rds_free_mblk;
 301                 bp[ix].buf_frtn.free_arg = (char *)&bp[ix];
 302                 mp = mp + RdsPktSize;
 303         }
 304         bp[NDataRX - 1].buf_nextp = NULL;
 305         rds_dpool.pool_headp = &bp[0];
 306         rds_dpool.pool_tailp = &bp[NDataRX - 1];
 307 
 308         /* Initialize ctrl pool */
 309         rds_cpool.pool_nbuffers = nctrlrx;
 310         rds_cpool.pool_nbusy = 0;
 311         rds_cpool.pool_nfree = nctrlrx;
 312 
 313         /* chain the buffers */
 314         for (ix = NDataRX; ix < nbuf - 1; ix++) {
 315                 bp[ix].buf_nextp = &bp[ix + 1];
 316                 bp[ix].buf_ds.ds_va = (ib_vaddr_t)(uintptr_t)mp;
 317                 mp = mp + RDS_CTRLPKT_SIZE;
 318         }
 319         bp[nbuf - 1].buf_ds.ds_va = (ib_vaddr_t)(uintptr_t)mp;
 320         bp[nbuf - 1].buf_nextp = NULL;
 321         rds_cpool.pool_headp = &bp[NDataRX];
 322         rds_cpool.pool_tailp = &bp[nbuf - 1];
 323 
 324         mutex_exit(&rds_dpool.pool_lock);
 325 
 326         RDS_DPRINTF3(LABEL, "rdsmemp start: %p end: %p", memp, mp);
 327         RDS_DPRINTF4("rds_init_recv_caches", "Return");
 328         return (0);
 329 }
 330 
 331 rds_hca_t *rds_lkup_hca(ib_guid_t hca_guid);
 332 
 333 void
 334 rds_free_send_pool(rds_ep_t *ep)
 335 {
 336         rds_bufpool_t   *pool;
 337         rds_hca_t       *hcap;
 338         int             ret;
 339 
 340         pool = &ep->ep_sndpool;
 341 
 342         mutex_enter(&pool->pool_lock);
 343         if (pool->pool_memp == NULL) {
 344                 mutex_exit(&pool->pool_lock);
 345                 RDS_DPRINTF2("rds_free_send_pool",
 346                     "EP(%p) DOUBLE Free on Send Pool", ep);
 347                 return;
 348         }
 349 
 350         /* get the hcap for the HCA hosting this channel */
 351         hcap = rds_lkup_hca(ep->ep_hca_guid);
 352         if (hcap == NULL) {
 353                 RDS_DPRINTF2("rds_free_send_pool", "HCA (0x%llx) not found",
 354                     ep->ep_hca_guid);
 355         } else {
 356                 ret = ibt_deregister_mr(hcap->hca_hdl, ep->ep_snd_mrhdl);
 357                 if (ret != IBT_SUCCESS) {
 358                         RDS_DPRINTF2(LABEL,
 359                             "ibt_deregister_mr failed: %d, mrhdl: 0x%p",
 360                             ret, ep->ep_snd_mrhdl);
 361                 }
 362 
 363                 if (ep->ep_ack_addr) {
 364                         ret = ibt_deregister_mr(hcap->hca_hdl, ep->ep_ackhdl);
 365                         if (ret != IBT_SUCCESS) {
 366                                 RDS_DPRINTF2(LABEL,
 367                                     "ibt_deregister_mr ackhdl failed: %d, "
 368                                     "mrhdl: 0x%p", ret, ep->ep_ackhdl);
 369                         }
 370 
 371                         kmem_free((void *)ep->ep_ack_addr, sizeof (uintptr_t));
 372                         ep->ep_ack_addr = NULL;
 373                 }
 374         }
 375 
 376         kmem_free(pool->pool_memp, pool->pool_memsize);
 377         kmem_free(pool->pool_bufmemp,
 378             pool->pool_nbuffers * sizeof (rds_buf_t));
 379         pool->pool_memp = NULL;
 380         pool->pool_bufmemp = NULL;
 381         mutex_exit(&pool->pool_lock);
 382 }
 383 
 384 int
 385 rds_init_send_pool(rds_ep_t *ep, ib_guid_t hca_guid)
 386 {
 387         uint8_t         *mp;
 388         rds_buf_t       *bp;
 389         rds_hca_t       *hcap;
 390         uint_t          ix, rcv_len;
 391         ibt_mr_attr_t   mem_attr;
 392         ibt_mr_desc_t   mem_desc;
 393         uint8_t         *memp;
 394         rds_buf_t       *bufmemp;
 395         uintptr_t       ack_addr = NULL;
 396         uint_t          memsize;
 397         uint_t          nbuf;
 398         rds_bufpool_t   *spool;
 399         rds_data_hdr_t  *pktp;
 400         int             ret;
 401 
 402         RDS_DPRINTF2("rds_init_send_pool", "Enter");
 403 
 404         spool = &ep->ep_sndpool;
 405 
 406         ASSERT(spool->pool_memp == NULL);
 407         ASSERT(ep->ep_hca_guid == 0);
 408 
 409         /* get the hcap for the HCA hosting this channel */
 410         hcap = rds_get_hcap(rdsib_statep, hca_guid);
 411         if (hcap == NULL) {
 412                 RDS_DPRINTF2("rds_init_send_pool", "HCA (0x%llx) not found",
 413                     hca_guid);
 414                 return (-1);
 415         }
 416 
 417         if (ep->ep_type == RDS_EP_TYPE_DATA) {
 418                 spool->pool_nbuffers = MaxDataSendBuffers;
 419                 spool->pool_nbusy = 0;
 420                 spool->pool_nfree = MaxDataSendBuffers;
 421                 memsize = (MaxDataSendBuffers * RdsPktSize) +
 422                     sizeof (uintptr_t);
 423                 rcv_len = RdsPktSize;
 424         } else {
 425                 spool->pool_nbuffers = MaxCtrlSendBuffers;
 426                 spool->pool_nbusy = 0;
 427                 spool->pool_nfree = MaxCtrlSendBuffers;
 428                 memsize = MaxCtrlSendBuffers * RDS_CTRLPKT_SIZE;
 429                 rcv_len = RDS_CTRLPKT_SIZE;
 430         }
 431         nbuf = spool->pool_nbuffers;
 432 
 433         RDS_DPRINTF3(LABEL, "RDS Send Pool Memory: %lld", memsize);
 434 
 435         memp = (uint8_t *)kmem_zalloc(memsize, KM_NOSLEEP);
 436         if (memp == NULL) {
 437                 RDS_DPRINTF1(LABEL, "RDS Send Memory allocation failed");
 438                 return (-1);
 439         }
 440 
 441         RDS_DPRINTF3(LABEL, "RDS Buffer Entries Memory: %lld",
 442             nbuf * sizeof (rds_buf_t));
 443 
 444         /* allocate memory for buffer entries */
 445         bufmemp = (rds_buf_t *)kmem_zalloc(nbuf * sizeof (rds_buf_t),
 446             KM_SLEEP);
 447 
 448         if (ep->ep_type == RDS_EP_TYPE_DATA) {
 449                 ack_addr = (uintptr_t)kmem_zalloc(sizeof (uintptr_t), KM_SLEEP);
 450 
 451                 /* register the memory with the HCA for this channel */
 452                 mem_attr.mr_vaddr = (ib_vaddr_t)ack_addr;
 453                 mem_attr.mr_len = sizeof (uintptr_t);
 454                 mem_attr.mr_as = NULL;
 455                 mem_attr.mr_flags = IBT_MR_SLEEP | IBT_MR_ENABLE_LOCAL_WRITE |
 456                     IBT_MR_ENABLE_REMOTE_WRITE;
 457 
 458                 ret = ibt_register_mr(hcap->hca_hdl, hcap->hca_pdhdl,
 459                     &mem_attr, &ep->ep_ackhdl, &mem_desc);
 460                 if (ret != IBT_SUCCESS) {
 461                         RDS_DPRINTF2("rds_init_send_pool",
 462                             "EP(%p): ibt_register_mr for ack failed: %d",
 463                             ep, ret);
 464                         kmem_free(memp, memsize);
 465                         kmem_free(bufmemp, nbuf * sizeof (rds_buf_t));
 466                         kmem_free((void *)ack_addr, sizeof (uintptr_t));
 467                         return (-1);
 468                 }
 469                 ep->ep_ack_rkey = mem_desc.md_rkey;
 470                 ep->ep_ack_addr = ack_addr;
 471         }
 472 
 473         /* register the memory with the HCA for this channel */
 474         mem_attr.mr_vaddr = (ib_vaddr_t)(uintptr_t)memp;
 475         mem_attr.mr_len = memsize;
 476         mem_attr.mr_as = NULL;
 477         mem_attr.mr_flags = IBT_MR_SLEEP | IBT_MR_ENABLE_LOCAL_WRITE;
 478 
 479         ret = ibt_register_mr(hcap->hca_hdl, hcap->hca_pdhdl,
 480             &mem_attr, &ep->ep_snd_mrhdl, &mem_desc);
 481         if (ret != IBT_SUCCESS) {
 482                 RDS_DPRINTF2("rds_init_send_pool", "EP(%p): ibt_register_mr "
 483                     "failed: %d", ep, ret);
 484                 kmem_free(memp, memsize);
 485                 kmem_free(bufmemp, nbuf * sizeof (rds_buf_t));
 486                 if (ack_addr != NULL)
 487                         kmem_free((void *)ack_addr, sizeof (uintptr_t));
 488                 return (-1);
 489         }
 490         ep->ep_snd_lkey = mem_desc.md_lkey;
 491 
 492 
 493         /* Initialize the pool */
 494         spool->pool_memp = memp;
 495         spool->pool_memsize = memsize;
 496         spool->pool_bufmemp = bufmemp;
 497         spool->pool_sqpoll_pending = B_FALSE;
 498 
 499         /* chain the buffers and initialize them */
 500         mp = memp;
 501         bp = bufmemp;
 502 
 503         if (ep->ep_type == RDS_EP_TYPE_DATA) {
 504                 for (ix = 0; ix < nbuf - 1; ix++) {
 505                         bp[ix].buf_nextp = &bp[ix + 1];
 506                         bp[ix].buf_ep = ep;
 507                         bp[ix].buf_ds.ds_va = (ib_vaddr_t)(uintptr_t)mp;
 508                         bp[ix].buf_ds.ds_key = ep->ep_snd_lkey;
 509                         bp[ix].buf_state = RDS_SNDBUF_FREE;
 510                         pktp = (rds_data_hdr_t *)(uintptr_t)mp;
 511                         pktp->dh_bufid = (uintptr_t)&bp[ix];
 512                         mp = mp + rcv_len;
 513                 }
 514                 bp[nbuf - 1].buf_nextp = NULL;
 515                 bp[nbuf - 1].buf_ep = ep;
 516                 bp[nbuf - 1].buf_ds.ds_va = (ib_vaddr_t)(uintptr_t)mp;
 517                 bp[nbuf - 1].buf_ds.ds_key = ep->ep_snd_lkey;
 518                 bp[nbuf - 1].buf_state = RDS_SNDBUF_FREE;
 519                 pktp = (rds_data_hdr_t *)(uintptr_t)mp;
 520                 pktp->dh_bufid = (uintptr_t)&bp[nbuf - 1];
 521 
 522                 spool->pool_headp = &bp[0];
 523                 spool->pool_tailp = &bp[nbuf - 1];
 524 
 525                 mp = mp + rcv_len;
 526                 ep->ep_ackds.ds_va = (ib_vaddr_t)(uintptr_t)mp;
 527                 ep->ep_ackds.ds_key = ep->ep_snd_lkey;
 528                 ep->ep_ackds.ds_len = sizeof (uintptr_t);
 529 
 530                 *(uintptr_t *)ep->ep_ack_addr = (uintptr_t)spool->pool_tailp;
 531         } else {
 532                 /* control send pool */
 533                 for (ix = 0; ix < nbuf - 1; ix++) {
 534                         bp[ix].buf_nextp = &bp[ix + 1];
 535                         bp[ix].buf_ep = ep;
 536                         bp[ix].buf_ds.ds_va = (ib_vaddr_t)(uintptr_t)mp;
 537                         bp[ix].buf_ds.ds_key = ep->ep_snd_lkey;
 538                         bp[ix].buf_state = RDS_SNDBUF_FREE;
 539                         mp = mp + rcv_len;
 540                 }
 541                 bp[nbuf - 1].buf_nextp = NULL;
 542                 bp[nbuf - 1].buf_ep = ep;
 543                 bp[nbuf - 1].buf_ds.ds_va = (ib_vaddr_t)(uintptr_t)mp;
 544                 bp[nbuf - 1].buf_ds.ds_key = ep->ep_snd_lkey;
 545                 bp[nbuf - 1].buf_state = RDS_SNDBUF_FREE;
 546                 spool->pool_headp = &bp[0];
 547                 spool->pool_tailp = &bp[nbuf - 1];
 548         }
 549 
 550         RDS_DPRINTF3(LABEL, "rdsmemp start: %p end: %p", memp, mp);
 551         RDS_DPRINTF2("rds_init_send_pool", "Return");
 552 
 553         return (0);
 554 }
 555 
 556 int
 557 rds_reinit_send_pool(rds_ep_t *ep, ib_guid_t hca_guid)
 558 {
 559         rds_buf_t       *bp;
 560         rds_hca_t       *hcap;
 561         ibt_mr_attr_t   mem_attr;
 562         ibt_mr_desc_t   mem_desc;
 563         rds_bufpool_t   *spool;
 564         int             ret;
 565 
 566         RDS_DPRINTF2("rds_reinit_send_pool", "Enter: EP(%p)", ep);
 567 
 568         spool = &ep->ep_sndpool;
 569         ASSERT(spool->pool_memp != NULL);
 570 
 571         /* deregister the send pool memory from the previous HCA */
 572         hcap = rds_get_hcap(rdsib_statep, ep->ep_hca_guid);
 573         if (hcap == NULL) {
 574                 RDS_DPRINTF2("rds_reinit_send_pool", "HCA (0x%llx) not found",
 575                     ep->ep_hca_guid);
 576         } else {
 577                 if (ep->ep_snd_mrhdl != NULL) {
 578                         (void) ibt_deregister_mr(hcap->hca_hdl,
 579                             ep->ep_snd_mrhdl);
 580                         ep->ep_snd_mrhdl = NULL;
 581                         ep->ep_snd_lkey = 0;
 582                 }
 583 
 584                 if ((ep->ep_type == RDS_EP_TYPE_DATA) &&
 585                     (ep->ep_ackhdl != NULL)) {
 586                         (void) ibt_deregister_mr(hcap->hca_hdl, ep->ep_ackhdl);
 587                         ep->ep_ackhdl = NULL;
 588                         ep->ep_ack_rkey = 0;
 589                 }
 590 
 591                 ep->ep_hca_guid = NULL;
 592         }
 593 
 594         /* get the hcap for the new HCA */
 595         hcap = rds_get_hcap(rdsib_statep, hca_guid);
 596         if (hcap == NULL) {
 597                 RDS_DPRINTF2("rds_reinit_send_pool", "HCA (0x%llx) not found",
 598                     hca_guid);
 599                 return (-1);
 600         }
 601 
 602         /* register the send memory */
 603         mem_attr.mr_vaddr = (ib_vaddr_t)(uintptr_t)spool->pool_memp;
 604         mem_attr.mr_len = spool->pool_memsize;
 605         mem_attr.mr_as = NULL;
 606         mem_attr.mr_flags = IBT_MR_SLEEP | IBT_MR_ENABLE_LOCAL_WRITE;
 607 
 608         ret = ibt_register_mr(hcap->hca_hdl, hcap->hca_pdhdl,
 609             &mem_attr, &ep->ep_snd_mrhdl, &mem_desc);
 610         if (ret != IBT_SUCCESS) {
 611                 RDS_DPRINTF2("rds_reinit_send_pool",
 612                     "EP(%p): ibt_register_mr failed: %d", ep, ret);
 613                 return (-1);
 614         }
 615         ep->ep_snd_lkey = mem_desc.md_lkey;
 616 
 617         /* register the acknowledgement space */
 618         if (ep->ep_type == RDS_EP_TYPE_DATA) {
 619                 mem_attr.mr_vaddr = (ib_vaddr_t)ep->ep_ack_addr;
 620                 mem_attr.mr_len = sizeof (uintptr_t);
 621                 mem_attr.mr_as = NULL;
 622                 mem_attr.mr_flags = IBT_MR_SLEEP | IBT_MR_ENABLE_LOCAL_WRITE |
 623                     IBT_MR_ENABLE_REMOTE_WRITE;
 624 
 625                 ret = ibt_register_mr(hcap->hca_hdl, hcap->hca_pdhdl,
 626                     &mem_attr, &ep->ep_ackhdl, &mem_desc);
 627                 if (ret != IBT_SUCCESS) {
 628                         RDS_DPRINTF2("rds_reinit_send_pool",
 629                             "EP(%p): ibt_register_mr for ack failed: %d",
 630                             ep, ret);
 631                         (void) ibt_deregister_mr(hcap->hca_hdl,
 632                             ep->ep_snd_mrhdl);
 633                         ep->ep_snd_mrhdl = NULL;
 634                         ep->ep_snd_lkey = 0;
 635                         return (-1);
 636                 }
 637                 ep->ep_ack_rkey = mem_desc.md_rkey;
 638 
 639                 /* update the LKEY in the acknowledgement WR */
 640                 ep->ep_ackds.ds_key = ep->ep_snd_lkey;
 641         }
 642 
 643         /* update the LKEY in each buffer */
 644         bp = spool->pool_headp;
 645         while (bp) {
 646                 bp->buf_ds.ds_key = ep->ep_snd_lkey;
 647                 bp = bp->buf_nextp;
 648         }
 649 
 650         ep->ep_hca_guid = hca_guid;
 651 
 652         RDS_DPRINTF2("rds_reinit_send_pool", "Return: EP(%p)", ep);
 653 
 654         return (0);
 655 }
 656 
 657 void
 658 rds_free_recv_pool(rds_ep_t *ep)
 659 {
 660         rds_bufpool_t *pool;
 661 
 662         if (ep->ep_type == RDS_EP_TYPE_DATA) {
 663                 pool = &rds_dpool;
 664         } else {
 665                 pool = &rds_cpool;
 666         }
 667 
 668         mutex_enter(&ep->ep_rcvpool.pool_lock);
 669         if (ep->ep_rcvpool.pool_nfree != 0) {
 670                 rds_free_buf(pool, ep->ep_rcvpool.pool_headp,
 671                     ep->ep_rcvpool.pool_nfree);
 672                 ep->ep_rcvpool.pool_nfree = 0;
 673                 ep->ep_rcvpool.pool_headp = NULL;
 674                 ep->ep_rcvpool.pool_tailp = NULL;
 675         }
 676         mutex_exit(&ep->ep_rcvpool.pool_lock);
 677 }
 678 
 679 int
 680 rds_init_recv_pool(rds_ep_t *ep)
 681 {
 682         rds_bufpool_t   *rpool;
 683         rds_qp_t        *recvqp;
 684 
 685         recvqp = &ep->ep_recvqp;
 686         rpool = &ep->ep_rcvpool;
 687         if (ep->ep_type == RDS_EP_TYPE_DATA) {
 688                 recvqp->qp_depth = MaxDataRecvBuffers;
 689                 recvqp->qp_level = 0;
 690                 recvqp->qp_lwm = (DataRecvBufferLWM * MaxDataRecvBuffers)/100;
 691                 recvqp->qp_taskqpending = B_FALSE;
 692 
 693                 rpool->pool_nbuffers = MaxDataRecvBuffers;
 694                 rpool->pool_nbusy = 0;
 695                 rpool->pool_nfree = 0;
 696         } else {
 697                 recvqp->qp_depth = MaxCtrlRecvBuffers;
 698                 recvqp->qp_level = 0;
 699                 recvqp->qp_lwm = (CtrlRecvBufferLWM * MaxCtrlRecvBuffers)/100;
 700                 recvqp->qp_taskqpending = B_FALSE;
 701 
 702                 rpool->pool_nbuffers = MaxCtrlRecvBuffers;
 703                 rpool->pool_nbusy = 0;
 704                 rpool->pool_nfree = 0;
 705         }
 706 
 707         return (0);
 708 }
 709 
 710 /* Free buffers to the global pool, either cpool or dpool */
 711 void
 712 rds_free_buf(rds_bufpool_t *pool, rds_buf_t *bp, uint_t nbuf)
 713 {
 714         uint_t          ix;
 715 
 716         RDS_DPRINTF4("rds_free_buf", "Enter");
 717 
 718         ASSERT(nbuf != 0);
 719 
 720         mutex_enter(&pool->pool_lock);
 721 
 722         if (pool->pool_nfree != 0) {
 723                 pool->pool_tailp->buf_nextp = bp;
 724         } else {
 725                 pool->pool_headp = bp;
 726         }
 727 
 728         if (nbuf == 1) {
 729                 ASSERT(bp->buf_state == RDS_RCVBUF_FREE);
 730                 bp->buf_ep = NULL;
 731                 bp->buf_nextp = NULL;
 732                 pool->pool_tailp = bp;
 733         } else {
 734                 for (ix = 1; ix < nbuf; ix++) {
 735                         ASSERT(bp->buf_state == RDS_RCVBUF_FREE);
 736                         bp->buf_ep = NULL;
 737                         bp = bp->buf_nextp;
 738                 }
 739                 ASSERT(bp->buf_state == RDS_RCVBUF_FREE);
 740                 bp->buf_ep = NULL;
 741                 bp->buf_nextp = NULL;
 742                 pool->pool_tailp = bp;
 743         }
 744         /* tail is always the last buffer */
 745         pool->pool_tailp->buf_nextp = NULL;
 746 
 747         pool->pool_nfree += nbuf;
 748         pool->pool_nbusy -= nbuf;
 749 
 750         mutex_exit(&pool->pool_lock);
 751 
 752         RDS_DPRINTF4("rds_free_buf", "Return");
 753 }
 754 
 755 /* Get buffers from the global pools, either cpool or dpool */
 756 rds_buf_t *
 757 rds_get_buf(rds_bufpool_t *pool, uint_t nbuf, uint_t *nret)
 758 {
 759         rds_buf_t       *bp = NULL, *bp1;
 760         uint_t          ix;
 761 
 762         RDS_DPRINTF4("rds_get_buf", "Enter");
 763 
 764         mutex_enter(&pool->pool_lock);
 765 
 766         RDS_DPRINTF3("rds_get_buf", "Available: %d Needed: %d",
 767             pool->pool_nfree, nbuf);
 768 
 769         if (nbuf < pool->pool_nfree) {
 770                 *nret = nbuf;
 771 
 772                 bp1 = pool->pool_headp;
 773                 for (ix = 1; ix < nbuf; ix++) {
 774                         bp1 = bp1->buf_nextp;
 775                 }
 776 
 777                 bp = pool->pool_headp;
 778                 pool->pool_headp = bp1->buf_nextp;
 779                 bp1->buf_nextp = NULL;
 780 
 781                 pool->pool_nfree -= nbuf;
 782                 pool->pool_nbusy += nbuf;
 783         } else if (nbuf >= pool->pool_nfree) {
 784                 *nret = pool->pool_nfree;
 785 
 786                 bp = pool->pool_headp;
 787 
 788                 pool->pool_headp = NULL;
 789                 pool->pool_tailp = NULL;
 790 
 791                 pool->pool_nbusy += pool->pool_nfree;
 792                 pool->pool_nfree = 0;
 793         }
 794 
 795         mutex_exit(&pool->pool_lock);
 796 
 797         RDS_DPRINTF4("rds_get_buf", "Return");
 798 
 799         return (bp);
 800 }
 801 
 802 boolean_t
 803 rds_is_recvq_empty(rds_ep_t *ep, boolean_t wait)
 804 {
 805         rds_qp_t        *recvqp;
 806         rds_bufpool_t   *rpool;
 807         boolean_t ret = B_TRUE;
 808 
 809         recvqp = &ep->ep_recvqp;
 810         mutex_enter(&recvqp->qp_lock);
 811         RDS_DPRINTF2("rds_is_recvq_empty", "EP(%p): QP has %d WRs",
 812             ep, recvqp->qp_level);
 813         if (wait) {
 814                 /* wait until the RQ is empty */
 815                 while (recvqp->qp_level != 0) {
 816                         /* wait one second and try again */
 817                         mutex_exit(&recvqp->qp_lock);
 818                         delay(drv_sectohz(1));
 819                         mutex_enter(&recvqp->qp_lock);
 820                 }
 821         } else if (recvqp->qp_level != 0) {
 822                         ret = B_FALSE;
 823         }
 824         mutex_exit(&recvqp->qp_lock);
 825 
 826         rpool = &ep->ep_rcvpool;
 827         mutex_enter(&rpool->pool_lock);
 828 
 829         /*
 830          * During failovers/reconnects, the app may still have some buffers
 831          * on thier socket queues. Waiting here for those buffers may
 832          * cause a hang. It seems ok for those buffers to get freed later.
 833          */
 834         if (rpool->pool_nbusy != 0) {
 835                 RDS_DPRINTF2("rds_is_recvq_empty", "EP(%p): "
 836                     "There are %d pending buffers on sockqs", ep,
 837                     rpool->pool_nbusy);
 838                 ret = B_FALSE;
 839         }
 840         mutex_exit(&rpool->pool_lock);
 841 
 842         return (ret);
 843 }
 844 
 845 boolean_t
 846 rds_is_sendq_empty(rds_ep_t *ep, uint_t wait)
 847 {
 848         rds_bufpool_t   *spool;
 849         rds_buf_t       *bp;
 850         boolean_t       ret1 = B_TRUE;
 851 
 852         /* check if all the sends completed */
 853         spool = &ep->ep_sndpool;
 854         mutex_enter(&spool->pool_lock);
 855         RDS_DPRINTF2("rds_is_sendq_empty", "EP(%p): "
 856             "Send Pool contains: %d", ep, spool->pool_nbusy);
 857         if (wait) {
 858                 while (spool->pool_nbusy != 0) {
 859                         if (rds_no_interrupts) {
 860                                 /* wait one second and try again */
 861                                 delay(drv_sectohz(1));
 862                                 rds_poll_send_completions(ep->ep_sendcq, ep,
 863                                     B_TRUE);
 864                         } else {
 865                                 /* wait one second and try again */
 866                                 mutex_exit(&spool->pool_lock);
 867                                 delay(drv_sectohz(1));
 868                                 mutex_enter(&spool->pool_lock);
 869                         }
 870                 }
 871 
 872                 if ((wait == 2) && (ep->ep_type == RDS_EP_TYPE_DATA)) {
 873                         rds_buf_t       *ackbp;
 874                         rds_buf_t       *prev_ackbp;
 875 
 876                         /*
 877                          * If the last one is acknowledged then everything
 878                          * is acknowledged
 879                          */
 880                         bp = spool->pool_tailp;
 881                         ackbp = *(rds_buf_t **)ep->ep_ack_addr;
 882                         prev_ackbp = ackbp;
 883                         RDS_DPRINTF2("rds_is_sendq_empty", "EP(%p): "
 884                             "Checking for acknowledgements", ep);
 885                         while (bp != ackbp) {
 886                                 RDS_DPRINTF2("rds_is_sendq_empty",
 887                                     "EP(%p) BP(0x%p/0x%p) last "
 888                                     "sent/acknowledged", ep, bp, ackbp);
 889                                 mutex_exit(&spool->pool_lock);
 890                                 delay(drv_sectohz(1));
 891                                 mutex_enter(&spool->pool_lock);
 892 
 893                                 bp = spool->pool_tailp;
 894                                 ackbp = *(rds_buf_t **)ep->ep_ack_addr;
 895                                 if (ackbp == prev_ackbp) {
 896                                         RDS_DPRINTF2("rds_is_sendq_empty",
 897                                             "There has been no progress,"
 898                                             "give up and proceed");
 899                                         break;
 900                                 }
 901                                 prev_ackbp = ackbp;
 902                         }
 903                 }
 904         } else if (spool->pool_nbusy != 0) {
 905                         ret1 = B_FALSE;
 906         }
 907         mutex_exit(&spool->pool_lock);
 908 
 909         /* check if all the rdma acks completed */
 910         mutex_enter(&ep->ep_lock);
 911         RDS_DPRINTF2("rds_is_sendq_empty", "EP(%p): "
 912             "Outstanding RDMA Acks: %d", ep, ep->ep_rdmacnt);
 913         if (wait) {
 914                 while (ep->ep_rdmacnt != 0) {
 915                         if (rds_no_interrupts) {
 916                                 /* wait one second and try again */
 917                                 delay(drv_sectohz(1));
 918                                 rds_poll_send_completions(ep->ep_sendcq, ep,
 919                                     B_FALSE);
 920                         } else {
 921                                 /* wait one second and try again */
 922                                 mutex_exit(&ep->ep_lock);
 923                                 delay(drv_sectohz(1));
 924                                 mutex_enter(&ep->ep_lock);
 925                         }
 926                 }
 927         } else if (ep->ep_rdmacnt != 0) {
 928                         ret1 = B_FALSE;
 929         }
 930         mutex_exit(&ep->ep_lock);
 931 
 932         return (ret1);
 933 }
 934 
 935 /* Get buffers from the send pool */
 936 rds_buf_t *
 937 rds_get_send_buf(rds_ep_t *ep, uint_t nbuf)
 938 {
 939         rds_buf_t       *bp = NULL, *bp1;
 940         rds_bufpool_t   *spool;
 941         uint_t          waittime = rds_waittime_ms * 1000;
 942         uint_t          ix;
 943         int             ret;
 944 
 945         RDS_DPRINTF4("rds_get_send_buf", "Enter: EP(%p) Buffers requested: %d",
 946             ep, nbuf);
 947 
 948         spool = &ep->ep_sndpool;
 949         mutex_enter(&spool->pool_lock);
 950 
 951         if (rds_no_interrupts) {
 952                 if ((spool->pool_sqpoll_pending == B_FALSE) &&
 953                     (spool->pool_nbusy >
 954                     (spool->pool_nbuffers * rds_poll_percent_full)/100)) {
 955                         spool->pool_sqpoll_pending = B_TRUE;
 956                         mutex_exit(&spool->pool_lock);
 957                         rds_poll_send_completions(ep->ep_sendcq, ep, B_FALSE);
 958                         mutex_enter(&spool->pool_lock);
 959                         spool->pool_sqpoll_pending = B_FALSE;
 960                 }
 961         }
 962 
 963         if (spool->pool_nfree < nbuf) {
 964                 /* wait for buffers to become available */
 965                 spool->pool_cv_count += nbuf;
 966                 ret = cv_reltimedwait_sig(&spool->pool_cv, &spool->pool_lock,
 967                     drv_usectohz(waittime), TR_CLOCK_TICK);
 968                 /* ret = cv_wait_sig(&spool->pool_cv, &spool->pool_lock); */
 969                 if (ret == 0) {
 970                         /* signal pending */
 971                         spool->pool_cv_count -= nbuf;
 972                         mutex_exit(&spool->pool_lock);
 973                         return (NULL);
 974                 }
 975 
 976                 spool->pool_cv_count -= nbuf;
 977         }
 978 
 979         /* Have the number of buffers needed */
 980         if (spool->pool_nfree > nbuf) {
 981                 bp = spool->pool_headp;
 982 
 983                 if (ep->ep_type == RDS_EP_TYPE_DATA) {
 984                         rds_buf_t *ackbp;
 985                         ackbp = *(rds_buf_t **)ep->ep_ack_addr;
 986 
 987                         /* check if all the needed buffers are acknowledged */
 988                         bp1 = bp;
 989                         for (ix = 0; ix < nbuf; ix++) {
 990                                 if ((bp1 == ackbp) ||
 991                                     (bp1->buf_state != RDS_SNDBUF_FREE)) {
 992                                         /*
 993                                          * The buffer is not yet signalled or
 994                                          * is not yet acknowledged
 995                                          */
 996                                         RDS_DPRINTF5("rds_get_send_buf",
 997                                             "EP(%p) Buffer (%p) not yet "
 998                                             "acked/completed", ep, bp1);
 999                                         mutex_exit(&spool->pool_lock);
1000                                         return (NULL);
1001                                 }
1002 
1003                                 bp1 = bp1->buf_nextp;
1004                         }
1005                 }
1006 
1007                 /* mark the buffers as pending */
1008                 bp1 = bp;
1009                 for (ix = 1; ix < nbuf; ix++) {
1010                         ASSERT(bp1->buf_state == RDS_SNDBUF_FREE);
1011                         bp1->buf_state = RDS_SNDBUF_PENDING;
1012                         bp1 = bp1->buf_nextp;
1013                 }
1014                 ASSERT(bp1->buf_state == RDS_SNDBUF_FREE);
1015                 bp1->buf_state = RDS_SNDBUF_PENDING;
1016 
1017                 spool->pool_headp = bp1->buf_nextp;
1018                 bp1->buf_nextp = NULL;
1019                 if (spool->pool_headp == NULL)
1020                         spool->pool_tailp = NULL;
1021                 spool->pool_nfree -= nbuf;
1022                 spool->pool_nbusy += nbuf;
1023         }
1024         mutex_exit(&spool->pool_lock);
1025 
1026         RDS_DPRINTF4("rds_get_send_buf", "Return: EP(%p) Buffers requested: %d",
1027             ep, nbuf);
1028 
1029         return (bp);
1030 }
1031 
1032 #define RDS_MIN_BUF_TO_WAKE_THREADS     10
1033 
1034 void
1035 rds_free_send_buf(rds_ep_t *ep, rds_buf_t *headp, rds_buf_t *tailp, uint_t nbuf,
1036     boolean_t lock)
1037 {
1038         rds_bufpool_t   *spool;
1039         rds_buf_t       *tmp;
1040 
1041         RDS_DPRINTF4("rds_free_send_buf", "Enter");
1042 
1043         ASSERT(nbuf != 0);
1044 
1045         if (tailp == NULL) {
1046                 if (nbuf > 1) {
1047                         tmp = headp;
1048                         while (tmp->buf_nextp) {
1049                                 tmp = tmp->buf_nextp;
1050                         }
1051                         tailp = tmp;
1052                 } else {
1053                         tailp = headp;
1054                 }
1055         }
1056 
1057         spool = &ep->ep_sndpool;
1058 
1059         if (lock == B_FALSE) {
1060                 /* lock is not held outside */
1061                 mutex_enter(&spool->pool_lock);
1062         }
1063 
1064         if (spool->pool_nfree) {
1065                 spool->pool_tailp->buf_nextp = headp;
1066         } else {
1067                 spool->pool_headp = headp;
1068         }
1069         spool->pool_tailp = tailp;
1070 
1071         spool->pool_nfree += nbuf;
1072         spool->pool_nbusy -= nbuf;
1073 
1074         if ((spool->pool_cv_count > 0) &&
1075             (spool->pool_nfree > RDS_MIN_BUF_TO_WAKE_THREADS)) {
1076                 if (spool->pool_nfree >= spool->pool_cv_count)
1077                         cv_broadcast(&spool->pool_cv);
1078                 else
1079                         cv_signal(&spool->pool_cv);
1080         }
1081 
1082         if (lock == B_FALSE) {
1083                 mutex_exit(&spool->pool_lock);
1084         }
1085 
1086         RDS_DPRINTF4("rds_free_send_buf", "Return");
1087 }
1088 
1089 void
1090 rds_free_recv_buf(rds_buf_t *bp, uint_t nbuf)
1091 {
1092         rds_ep_t        *ep;
1093         rds_bufpool_t   *rpool;
1094         rds_buf_t       *bp1;
1095         uint_t          ix;
1096 
1097         RDS_DPRINTF4("rds_free_recv_buf", "Enter");
1098 
1099         ASSERT(nbuf != 0);
1100 
1101         ep = bp->buf_ep;
1102         rpool = &ep->ep_rcvpool;
1103 
1104         mutex_enter(&rpool->pool_lock);
1105 
1106         /* Add the buffers to the local pool */
1107         if (rpool->pool_tailp == NULL) {
1108                 ASSERT(rpool->pool_headp == NULL);
1109                 ASSERT(rpool->pool_nfree == 0);
1110                 rpool->pool_headp = bp;
1111                 bp1 = bp;
1112                 for (ix = 1; ix < nbuf; ix++) {
1113                         if (bp1->buf_state == RDS_RCVBUF_ONSOCKQ) {
1114                                 rpool->pool_nbusy--;
1115                         }
1116                         bp1->buf_state = RDS_RCVBUF_FREE;
1117                         bp1 = bp1->buf_nextp;
1118                 }
1119                 bp1->buf_nextp = NULL;
1120                 if (bp->buf_state == RDS_RCVBUF_ONSOCKQ) {
1121                         rpool->pool_nbusy--;
1122                 }
1123                 bp->buf_state = RDS_RCVBUF_FREE;
1124                 rpool->pool_tailp = bp1;
1125                 rpool->pool_nfree += nbuf;
1126         } else {
1127                 bp1 = bp;
1128                 for (ix = 1; ix < nbuf; ix++) {
1129                         if (bp1->buf_state == RDS_RCVBUF_ONSOCKQ) {
1130                                 rpool->pool_nbusy--;
1131                         }
1132                         bp1->buf_state = RDS_RCVBUF_FREE;
1133                         bp1 = bp1->buf_nextp;
1134                 }
1135                 bp1->buf_nextp = NULL;
1136                 if (bp->buf_state == RDS_RCVBUF_ONSOCKQ) {
1137                         rpool->pool_nbusy--;
1138                 }
1139                 bp->buf_state = RDS_RCVBUF_FREE;
1140                 rpool->pool_tailp->buf_nextp = bp;
1141                 rpool->pool_tailp = bp1;
1142                 rpool->pool_nfree += nbuf;
1143         }
1144 
1145         if (rpool->pool_nfree >= rds_nbuffers_to_putback) {
1146                 bp = rpool->pool_headp;
1147                 nbuf = rpool->pool_nfree;
1148                 rpool->pool_headp = NULL;
1149                 rpool->pool_tailp = NULL;
1150                 rpool->pool_nfree = 0;
1151                 mutex_exit(&rpool->pool_lock);
1152 
1153                 /* Free the buffers to the global pool */
1154                 if (ep->ep_type == RDS_EP_TYPE_DATA) {
1155                         rds_free_buf(&rds_dpool, bp, nbuf);
1156                 } else {
1157                         rds_free_buf(&rds_cpool, bp, nbuf);
1158                 }
1159 
1160                 return;
1161         }
1162         mutex_exit(&rpool->pool_lock);
1163 
1164         RDS_DPRINTF4("rds_free_recv_buf", "Return");
1165 }