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 /*
  23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  * hermon_umap.c
  28  *    Hermon Userland Mapping Routines
  29  *
  30  *    Implements all the routines necessary for enabling direct userland
  31  *    access to the Hermon hardware.  This includes all routines necessary for
  32  *    maintaining the "userland resources database" and all the support routines
  33  *    for the devmap calls.
  34  */
  35 
  36 #include <sys/types.h>
  37 #include <sys/conf.h>
  38 #include <sys/ddi.h>
  39 #include <sys/sunddi.h>
  40 #include <sys/modctl.h>
  41 #include <sys/file.h>
  42 #include <sys/avl.h>
  43 #include <sys/sysmacros.h>
  44 
  45 #include <sys/ib/adapters/hermon/hermon.h>
  46 
  47 /* Hermon HCA state pointer (extern) */
  48 extern void *hermon_statep;
  49 
  50 /* Hermon HCA Userland Resource Database (extern) */
  51 extern hermon_umap_db_t hermon_userland_rsrc_db;
  52 
  53 static int hermon_umap_uarpg(hermon_state_t *state, devmap_cookie_t dhp,
  54     hermon_rsrc_t *rsrcp, uint64_t offset, size_t *maplen, int *err);
  55 static int hermon_umap_cqmem(hermon_state_t *state, devmap_cookie_t dhp,
  56     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
  57 static int hermon_umap_qpmem(hermon_state_t *state, devmap_cookie_t dhp,
  58     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
  59 static int hermon_umap_srqmem(hermon_state_t *state, devmap_cookie_t dhp,
  60     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
  61 static int hermon_umap_dbrecmem(hermon_state_t *state, devmap_cookie_t dhp,
  62     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
  63 static int hermon_devmap_umem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
  64     offset_t off, size_t len, void **pvtp);
  65 static int hermon_devmap_umem_dup(devmap_cookie_t dhp, void *pvtp,
  66     devmap_cookie_t new_dhp, void **new_pvtp);
  67 static void hermon_devmap_umem_unmap(devmap_cookie_t dhp, void *pvtp,
  68     offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
  69     devmap_cookie_t new_dhp2, void **pvtp2);
  70 static int hermon_devmap_dbrecmem_map(devmap_cookie_t dhp, dev_t dev,
  71     uint_t flags, offset_t off, size_t len, void **pvtp);
  72 static int hermon_devmap_dbrecmem_dup(devmap_cookie_t dhp, void *pvtp,
  73     devmap_cookie_t new_dhp, void **new_pvtp);
  74 static void hermon_devmap_dbrecmem_unmap(devmap_cookie_t dhp, void *pvtp,
  75     offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
  76     devmap_cookie_t new_dhp2, void **pvtp2);
  77 static int hermon_devmap_devmem_map(devmap_cookie_t dhp, dev_t dev,
  78     uint_t flags, offset_t off, size_t len, void **pvtp);
  79 static int hermon_devmap_devmem_dup(devmap_cookie_t dhp, void *pvtp,
  80     devmap_cookie_t new_dhp, void **new_pvtp);
  81 static void hermon_devmap_devmem_unmap(devmap_cookie_t dhp, void *pvtp,
  82     offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
  83     devmap_cookie_t new_dhp2, void **pvtp2);
  84 static ibt_status_t hermon_umap_mr_data_in(hermon_mrhdl_t mr,
  85     ibt_mr_data_in_t *data, size_t data_sz);
  86 static ibt_status_t hermon_umap_cq_data_out(hermon_cqhdl_t cq,
  87     mlnx_umap_cq_data_out_t *data, size_t data_sz);
  88 static ibt_status_t hermon_umap_qp_data_out(hermon_qphdl_t qp,
  89     mlnx_umap_qp_data_out_t *data, size_t data_sz);
  90 static ibt_status_t hermon_umap_srq_data_out(hermon_srqhdl_t srq,
  91     mlnx_umap_srq_data_out_t *data, size_t data_sz);
  92 static ibt_status_t hermon_umap_pd_data_out(hermon_pdhdl_t pd,
  93     mlnx_umap_pd_data_out_t *data, size_t data_sz);
  94 static int hermon_umap_db_compare(const void *query, const void *entry);
  95 
  96 
  97 /*
  98  * These callbacks are passed to devmap_umem_setup() and devmap_devmem_setup(),
  99  * respectively.  They are used to handle (among other things) partial
 100  * unmappings and to provide a method for invalidating mappings inherited
 101  * as a result of a fork(2) system call.
 102  */
 103 static struct devmap_callback_ctl hermon_devmap_umem_cbops = {
 104         DEVMAP_OPS_REV,
 105         hermon_devmap_umem_map,
 106         NULL,
 107         hermon_devmap_umem_dup,
 108         hermon_devmap_umem_unmap
 109 };
 110 static struct devmap_callback_ctl hermon_devmap_devmem_cbops = {
 111         DEVMAP_OPS_REV,
 112         hermon_devmap_devmem_map,
 113         NULL,
 114         hermon_devmap_devmem_dup,
 115         hermon_devmap_devmem_unmap
 116 };
 117 static struct devmap_callback_ctl hermon_devmap_dbrecmem_cbops = {
 118         DEVMAP_OPS_REV,
 119         hermon_devmap_dbrecmem_map,
 120         NULL,
 121         hermon_devmap_dbrecmem_dup,
 122         hermon_devmap_dbrecmem_unmap
 123 };
 124 
 125 /*
 126  * hermon_devmap()
 127  *    Context: Can be called from user context.
 128  */
 129 /* ARGSUSED */
 130 int
 131 hermon_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
 132     size_t *maplen, uint_t model)
 133 {
 134         hermon_state_t  *state;
 135         hermon_rsrc_t   *rsrcp;
 136         minor_t         instance;
 137         uint64_t        key, value;
 138         uint64_t        bf_offset = 0;
 139         uint_t          type;
 140         int             err, status;
 141 
 142         /* Get Hermon softstate structure from instance */
 143         instance = HERMON_DEV_INSTANCE(dev);
 144         state = ddi_get_soft_state(hermon_statep, instance);
 145         if (state == NULL) {
 146                 return (ENXIO);
 147         }
 148 
 149         /*
 150          * Access to Hermon devmap interface is not allowed in
 151          * "maintenance mode".
 152          */
 153         if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
 154                 return (EFAULT);
 155         }
 156 
 157         /*
 158          * The bottom bits of "offset" are undefined (number depends on
 159          * system PAGESIZE).  Shifting these off leaves us with a "key".
 160          * The "key" is actually a combination of both a real key value
 161          * (for the purpose of database lookup) and a "type" value.  We
 162          * extract this information before doing the database lookup.
 163          */
 164         key  = off >> PAGESHIFT;
 165         type = key & MLNX_UMAP_RSRC_TYPE_MASK;
 166         key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
 167         if (type == MLNX_UMAP_BLUEFLAMEPG_RSRC) {
 168                 if (state->hs_devlim.blu_flm == 0) {
 169                         return (EFAULT);
 170                 }
 171                 bf_offset = state->hs_bf_offset;
 172                 type = MLNX_UMAP_UARPG_RSRC;
 173         }
 174         status = hermon_umap_db_find(instance, key, type, &value, 0, NULL);
 175         if (status == DDI_SUCCESS) {
 176                 rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
 177 
 178                 switch (type) {
 179                 case MLNX_UMAP_UARPG_RSRC:
 180                         /*
 181                          * Double check that process who open()'d Hermon is
 182                          * same process attempting to mmap() UAR page.
 183                          */
 184                         if (key != ddi_get_pid()) {
 185                                 return (EINVAL);
 186                         }
 187 
 188                         /* Map the UAR page out for userland access */
 189                         status = hermon_umap_uarpg(state, dhp, rsrcp, bf_offset,
 190                             maplen, &err);
 191                         if (status != DDI_SUCCESS) {
 192                                 return (err);
 193                         }
 194                         break;
 195 
 196                 case MLNX_UMAP_CQMEM_RSRC:
 197                         /* Map the CQ memory out for userland access */
 198                         status = hermon_umap_cqmem(state, dhp, rsrcp, off,
 199                             maplen, &err);
 200                         if (status != DDI_SUCCESS) {
 201                                 return (err);
 202                         }
 203                         break;
 204 
 205                 case MLNX_UMAP_QPMEM_RSRC:
 206                         /* Map the QP memory out for userland access */
 207                         status = hermon_umap_qpmem(state, dhp, rsrcp, off,
 208                             maplen, &err);
 209                         if (status != DDI_SUCCESS) {
 210                                 return (err);
 211                         }
 212                         break;
 213 
 214                 case MLNX_UMAP_SRQMEM_RSRC:
 215                         /* Map the SRQ memory out for userland access */
 216                         status = hermon_umap_srqmem(state, dhp, rsrcp, off,
 217                             maplen, &err);
 218                         if (status != DDI_SUCCESS) {
 219                                 return (err);
 220                         }
 221                         break;
 222 
 223                 case MLNX_UMAP_DBRMEM_RSRC:
 224                         /*
 225                          * Map the doorbell record memory out for
 226                          * userland access
 227                          */
 228                         status = hermon_umap_dbrecmem(state, dhp, rsrcp, off,
 229                             maplen, &err);
 230                         if (status != DDI_SUCCESS) {
 231                                 return (err);
 232                         }
 233                         break;
 234 
 235                 default:
 236                         HERMON_WARNING(state, "unexpected rsrc type in devmap");
 237                         return (EINVAL);
 238                 }
 239         } else {
 240                 return (EINVAL);
 241         }
 242 
 243         return (0);
 244 }
 245 
 246 
 247 /*
 248  * hermon_umap_uarpg()
 249  *    Context: Can be called from user context.
 250  */
 251 static int
 252 hermon_umap_uarpg(hermon_state_t *state, devmap_cookie_t dhp,
 253     hermon_rsrc_t *rsrcp, uint64_t offset, size_t *maplen, int *err)
 254 {
 255         int                     status;
 256         uint_t                  maxprot;
 257         ddi_device_acc_attr_t   *accattrp = &state->hs_reg_accattr;
 258         ddi_device_acc_attr_t   accattr;
 259 
 260         if (offset != 0) {      /* Hermon Blueflame */
 261                 /* Try to use write coalescing data ordering */
 262                 accattr = *accattrp;
 263                 accattr.devacc_attr_dataorder = DDI_STORECACHING_OK_ACC;
 264                 accattrp = &accattr;
 265         }
 266 
 267         /* Map out the UAR page (doorbell page) */
 268         maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
 269         status = devmap_devmem_setup(dhp, state->hs_dip,
 270             &hermon_devmap_devmem_cbops, HERMON_UAR_BAR, (rsrcp->hr_indx <<
 271             PAGESHIFT) + offset, PAGESIZE, maxprot, DEVMAP_ALLOW_REMAP,
 272             accattrp);
 273         if (status < 0) {
 274                 *err = status;
 275                 return (DDI_FAILURE);
 276         }
 277 
 278         *maplen = PAGESIZE;
 279         return (DDI_SUCCESS);
 280 }
 281 
 282 
 283 /*
 284  * hermon_umap_cqmem()
 285  *    Context: Can be called from user context.
 286  */
 287 /* ARGSUSED */
 288 static int
 289 hermon_umap_cqmem(hermon_state_t *state, devmap_cookie_t dhp,
 290     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
 291 {
 292         hermon_cqhdl_t  cq;
 293         size_t          size;
 294         uint_t          maxprot;
 295         int             status;
 296 
 297         /* Extract the Hermon CQ handle pointer from the hermon_rsrc_t */
 298         cq = (hermon_cqhdl_t)rsrcp->hr_addr;
 299 
 300         /* Round-up the CQ size to system page size */
 301         size = ptob(btopr(cq->cq_resize_hdl ?
 302             cq->cq_resize_hdl->cq_cqinfo.qa_size : cq->cq_cqinfo.qa_size));
 303 
 304         /* Map out the CQ memory - use resize_hdl if non-NULL */
 305         maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
 306         status = devmap_umem_setup(dhp, state->hs_dip,
 307             &hermon_devmap_umem_cbops, cq->cq_resize_hdl ?
 308             cq->cq_resize_hdl->cq_cqinfo.qa_umemcookie :
 309             cq->cq_cqinfo.qa_umemcookie, 0, size,
 310             maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
 311         if (status < 0) {
 312                 *err = status;
 313                 return (DDI_FAILURE);
 314         }
 315         *maplen = size;
 316 
 317         return (DDI_SUCCESS);
 318 }
 319 
 320 
 321 /*
 322  * hermon_umap_qpmem()
 323  *    Context: Can be called from user context.
 324  */
 325 /* ARGSUSED */
 326 static int
 327 hermon_umap_qpmem(hermon_state_t *state, devmap_cookie_t dhp,
 328     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
 329 {
 330         hermon_qphdl_t  qp;
 331         offset_t        offset;
 332         size_t          size;
 333         uint_t          maxprot;
 334         int             status;
 335 
 336         /* Extract the Hermon QP handle pointer from the hermon_rsrc_t */
 337         qp = (hermon_qphdl_t)rsrcp->hr_addr;
 338 
 339         /*
 340          * Calculate the offset of the first work queue (send or recv) into
 341          * the memory (ddi_umem_alloc()) allocated previously for the QP.
 342          */
 343         offset = (offset_t)((uintptr_t)qp->qp_wqinfo.qa_buf_aligned -
 344             (uintptr_t)qp->qp_wqinfo.qa_buf_real);
 345 
 346         /* Round-up the QP work queue sizes to system page size */
 347         size = ptob(btopr(qp->qp_wqinfo.qa_size));
 348 
 349         /* Map out the QP memory */
 350         maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
 351         status = devmap_umem_setup(dhp, state->hs_dip,
 352             &hermon_devmap_umem_cbops, qp->qp_wqinfo.qa_umemcookie, offset,
 353             size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
 354         if (status < 0) {
 355                 *err = status;
 356                 return (DDI_FAILURE);
 357         }
 358         *maplen = size;
 359 
 360         return (DDI_SUCCESS);
 361 }
 362 
 363 
 364 /*
 365  * hermon_umap_srqmem()
 366  *    Context: Can be called from user context.
 367  */
 368 /* ARGSUSED */
 369 static int
 370 hermon_umap_srqmem(hermon_state_t *state, devmap_cookie_t dhp,
 371     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
 372 {
 373         hermon_srqhdl_t srq;
 374         offset_t        offset;
 375         size_t          size;
 376         uint_t          maxprot;
 377         int             status;
 378 
 379         /* Extract the Hermon SRQ handle pointer from the hermon_rsrc_t */
 380         srq = (hermon_srqhdl_t)rsrcp->hr_addr;
 381 
 382         /*
 383          * Calculate the offset of the first shared recv queue into the memory
 384          * (ddi_umem_alloc()) allocated previously for the SRQ.
 385          */
 386         offset = (offset_t)((uintptr_t)srq->srq_wqinfo.qa_buf_aligned -
 387             (uintptr_t)srq->srq_wqinfo.qa_buf_real);
 388 
 389         /* Round-up the SRQ work queue sizes to system page size */
 390         size = ptob(btopr(srq->srq_wqinfo.qa_size));
 391 
 392         /* Map out the SRQ memory */
 393         maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
 394         status = devmap_umem_setup(dhp, state->hs_dip,
 395             &hermon_devmap_umem_cbops, srq->srq_wqinfo.qa_umemcookie, offset,
 396             size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
 397         if (status < 0) {
 398                 *err = status;
 399                 return (DDI_FAILURE);
 400         }
 401         *maplen = size;
 402 
 403         return (DDI_SUCCESS);
 404 }
 405 
 406 
 407 /*
 408  * hermon_devmap_dbrecmem()
 409  *    Context: Can be called from user context.
 410  */
 411 /* ARGSUSED */
 412 static int
 413 hermon_umap_dbrecmem(hermon_state_t *state, devmap_cookie_t dhp,
 414     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
 415 {
 416         hermon_udbr_page_t *pagep;
 417         offset_t        offset;
 418         size_t          size;
 419         uint_t          maxprot;
 420         int             status;
 421 
 422         /* We stored the udbr_page pointer, and not a hermon_rsrc_t */
 423         pagep = (hermon_udbr_page_t *)rsrcp;
 424 
 425         /*
 426          * Calculate the offset of the doorbell records into the memory
 427          * (ddi_umem_alloc()) allocated previously for them.
 428          */
 429         offset = 0;
 430 
 431         /* Round-up the doorbell page to system page size */
 432         size = PAGESIZE;
 433 
 434         /* Map out the Doorbell Record memory */
 435         maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
 436         status = devmap_umem_setup(dhp, state->hs_dip,
 437             &hermon_devmap_dbrecmem_cbops, pagep->upg_umemcookie, offset,
 438             size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
 439         if (status < 0) {
 440                 *err = status;
 441                 return (DDI_FAILURE);
 442         }
 443         *maplen = size;
 444 
 445         return (DDI_SUCCESS);
 446 }
 447 
 448 
 449 /*
 450  * hermon_devmap_umem_map()
 451  *    Context: Can be called from kernel context.
 452  */
 453 /* ARGSUSED */
 454 static int
 455 hermon_devmap_umem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
 456     offset_t off, size_t len, void **pvtp)
 457 {
 458         hermon_state_t          *state;
 459         hermon_devmap_track_t   *dvm_track;
 460         hermon_cqhdl_t          cq;
 461         hermon_qphdl_t          qp;
 462         hermon_srqhdl_t         srq;
 463         minor_t                 instance;
 464         uint64_t                key;
 465         uint_t                  type;
 466 
 467         /* Get Hermon softstate structure from instance */
 468         instance = HERMON_DEV_INSTANCE(dev);
 469         state = ddi_get_soft_state(hermon_statep, instance);
 470         if (state == NULL) {
 471                 return (ENXIO);
 472         }
 473 
 474         /*
 475          * The bottom bits of "offset" are undefined (number depends on
 476          * system PAGESIZE).  Shifting these off leaves us with a "key".
 477          * The "key" is actually a combination of both a real key value
 478          * (for the purpose of database lookup) and a "type" value.  Although
 479          * we are not going to do any database lookup per se, we do want
 480          * to extract the "key" and the "type" (to enable faster lookup of
 481          * the appropriate CQ or QP handle).
 482          */
 483         key  = off >> PAGESHIFT;
 484         type = key & MLNX_UMAP_RSRC_TYPE_MASK;
 485         key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
 486 
 487         /*
 488          * Allocate an entry to track the mapping and unmapping (specifically,
 489          * partial unmapping) of this resource.
 490          */
 491         dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
 492             sizeof (hermon_devmap_track_t), KM_SLEEP);
 493         dvm_track->hdt_offset = off;
 494         dvm_track->hdt_state  = state;
 495         dvm_track->hdt_refcnt = 1;
 496         mutex_init(&dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
 497             DDI_INTR_PRI(state->hs_intrmsi_pri));
 498 
 499         /*
 500          * Depending of the type of resource that has been mapped out, we
 501          * need to update the QP or CQ handle to reflect that it has, in
 502          * fact, been mapped.  This allows the driver code which frees a QP
 503          * or a CQ to know whether it is appropriate to do a
 504          * devmap_devmem_remap() to invalidate the userland mapping for the
 505          * corresponding queue's memory.
 506          */
 507         if (type == MLNX_UMAP_CQMEM_RSRC) {
 508 
 509                 /* Use "key" (CQ number) to do fast lookup of CQ handle */
 510                 cq = hermon_cqhdl_from_cqnum(state, key);
 511 
 512                 /*
 513                  * Update the handle to the userland mapping.  Note:  If
 514                  * the CQ already has a valid userland mapping, then stop
 515                  * and return failure.
 516                  */
 517                 mutex_enter(&cq->cq_lock);
 518                 if (cq->cq_umap_dhp == NULL) {
 519                         cq->cq_umap_dhp = dhp;
 520                         dvm_track->hdt_size = cq->cq_cqinfo.qa_size;
 521                         mutex_exit(&cq->cq_lock);
 522                 } else if (cq->cq_resize_hdl &&
 523                     (cq->cq_resize_hdl->cq_umap_dhp == NULL)) {
 524                         cq->cq_resize_hdl->cq_umap_dhp = dhp;
 525                         dvm_track->hdt_size =
 526                             cq->cq_resize_hdl->cq_cqinfo.qa_size;
 527                         mutex_exit(&cq->cq_lock);
 528                 } else {
 529                         mutex_exit(&cq->cq_lock);
 530                         goto umem_map_fail;
 531                 }
 532 
 533         } else if (type == MLNX_UMAP_QPMEM_RSRC) {
 534 
 535                 /* Use "key" (QP number) to do fast lookup of QP handle */
 536                 qp = hermon_qphdl_from_qpnum(state, key);
 537 
 538                 /*
 539                  * Update the handle to the userland mapping.  Note:  If
 540                  * the CQ already has a valid userland mapping, then stop
 541                  * and return failure.
 542                  */
 543                 mutex_enter(&qp->qp_lock);
 544                 if (qp->qp_umap_dhp == NULL) {
 545                         qp->qp_umap_dhp = dhp;
 546                         dvm_track->hdt_size = qp->qp_wqinfo.qa_size;
 547                         mutex_exit(&qp->qp_lock);
 548                 } else {
 549                         mutex_exit(&qp->qp_lock);
 550                         goto umem_map_fail;
 551                 }
 552 
 553         } else if (type == MLNX_UMAP_SRQMEM_RSRC) {
 554 
 555                 /* Use "key" (SRQ number) to do fast lookup on SRQ handle */
 556                 srq = hermon_srqhdl_from_srqnum(state, key);
 557 
 558                 /*
 559                  * Update the handle to the userland mapping.  Note:  If the
 560                  * SRQ already has a valid userland mapping, then stop and
 561                  * return failure.
 562                  */
 563                 mutex_enter(&srq->srq_lock);
 564                 if (srq->srq_umap_dhp == NULL) {
 565                         srq->srq_umap_dhp = dhp;
 566                         dvm_track->hdt_size = srq->srq_wqinfo.qa_size;
 567                         mutex_exit(&srq->srq_lock);
 568                 } else {
 569                         mutex_exit(&srq->srq_lock);
 570                         goto umem_map_fail;
 571                 }
 572         }
 573 
 574         /*
 575          * Pass the private "Hermon devmap tracking structure" back.  This
 576          * pointer will be returned in subsequent "unmap" callbacks.
 577          */
 578         *pvtp = dvm_track;
 579 
 580         return (DDI_SUCCESS);
 581 
 582 umem_map_fail:
 583         mutex_destroy(&dvm_track->hdt_lock);
 584         kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
 585         return (DDI_FAILURE);
 586 }
 587 
 588 
 589 /*
 590  * hermon_devmap_umem_dup()
 591  *    Context: Can be called from kernel context.
 592  */
 593 /* ARGSUSED */
 594 static int
 595 hermon_devmap_umem_dup(devmap_cookie_t dhp, void *pvtp, devmap_cookie_t new_dhp,
 596     void **new_pvtp)
 597 {
 598         hermon_state_t          *state;
 599         hermon_devmap_track_t   *dvm_track, *new_dvm_track;
 600         uint_t                  maxprot;
 601         int                     status;
 602 
 603         /*
 604          * Extract the Hermon softstate pointer from "Hermon devmap tracking
 605          * structure" (in "pvtp").
 606          */
 607         dvm_track = (hermon_devmap_track_t *)pvtp;
 608         state = dvm_track->hdt_state;
 609 
 610         /*
 611          * Since this devmap_dup() entry point is generally called
 612          * when a process does fork(2), it is incumbent upon the driver
 613          * to insure that the child does not inherit a valid copy of
 614          * the parent's QP or CQ resource.  This is accomplished by using
 615          * devmap_devmem_remap() to invalidate the child's mapping to the
 616          * kernel memory.
 617          */
 618         maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
 619         status = devmap_devmem_remap(new_dhp, state->hs_dip, 0, 0,
 620             dvm_track->hdt_size, maxprot, DEVMAP_MAPPING_INVALID, NULL);
 621         if (status != DDI_SUCCESS) {
 622                 HERMON_WARNING(state, "failed in hermon_devmap_umem_dup()");
 623                 return (status);
 624         }
 625 
 626         /*
 627          * Allocate a new entry to track the subsequent unmapping
 628          * (specifically, all partial unmappings) of the child's newly
 629          * invalidated resource.  Note: Setting the "hdt_size" field to
 630          * zero here is an indication to the devmap_unmap() entry point
 631          * that this mapping is invalid, and that its subsequent unmapping
 632          * should not affect any of the parent's CQ or QP resources.
 633          */
 634         new_dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
 635             sizeof (hermon_devmap_track_t), KM_SLEEP);
 636         new_dvm_track->hdt_offset = 0;
 637         new_dvm_track->hdt_state  = state;
 638         new_dvm_track->hdt_refcnt = 1;
 639         new_dvm_track->hdt_size        = 0;
 640         mutex_init(&new_dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
 641             DDI_INTR_PRI(state->hs_intrmsi_pri));
 642         *new_pvtp = new_dvm_track;
 643 
 644         return (DDI_SUCCESS);
 645 }
 646 
 647 
 648 /*
 649  * hermon_devmap_umem_unmap()
 650  *    Context: Can be called from kernel context.
 651  */
 652 /* ARGSUSED */
 653 static void
 654 hermon_devmap_umem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off,
 655     size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
 656     devmap_cookie_t new_dhp2, void **pvtp2)
 657 {
 658         hermon_state_t          *state;
 659         hermon_rsrc_t           *rsrcp;
 660         hermon_devmap_track_t   *dvm_track;
 661         hermon_cqhdl_t          cq;
 662         hermon_qphdl_t          qp;
 663         hermon_srqhdl_t         srq;
 664         uint64_t                key, value;
 665         uint_t                  type;
 666         uint_t                  size;
 667         int                     status;
 668 
 669         /*
 670          * Extract the Hermon softstate pointer from "Hermon devmap tracking
 671          * structure" (in "pvtp").
 672          */
 673         dvm_track = (hermon_devmap_track_t *)pvtp;
 674         state     = dvm_track->hdt_state;
 675 
 676         /*
 677          * Extract the "offset" from the "Hermon devmap tracking structure".
 678          * Note: The input argument "off" is ignored here because the
 679          * Hermon mapping interfaces define a very specific meaning to
 680          * each "logical offset".  Also extract the "key" and "type" encoded
 681          * in the logical offset.
 682          */
 683         key  = dvm_track->hdt_offset >> PAGESHIFT;
 684         type = key & MLNX_UMAP_RSRC_TYPE_MASK;
 685         key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
 686 
 687         /*
 688          * Extract the "size" of the mapping.  If this size is determined
 689          * to be zero, then it is an indication of a previously invalidated
 690          * mapping, and no CQ or QP resources should be affected.
 691          */
 692         size = dvm_track->hdt_size;
 693 
 694         /*
 695          * If only the "middle portion of a given mapping is being unmapped,
 696          * then we are effectively creating one new piece of mapped memory.
 697          * (Original region is divided into three pieces of which the middle
 698          * piece is being removed.  This leaves two pieces.  Since we started
 699          * with one piece and now have two pieces, we need to increment the
 700          * counter in the "Hermon devmap tracking structure".
 701          *
 702          * If, however, the whole mapped region is being unmapped, then we
 703          * have started with one region which we are completely removing.
 704          * In this case, we need to decrement the counter in the "Hermon
 705          * devmap tracking structure".
 706          *
 707          * In each of the remaining cases, we will have started with one
 708          * mapped region and ended with one (different) region.  So no counter
 709          * modification is necessary.
 710          */
 711         mutex_enter(&dvm_track->hdt_lock);
 712         if ((new_dhp1 == NULL) && (new_dhp2 == NULL)) {
 713                 dvm_track->hdt_refcnt--;
 714         } else if ((new_dhp1 != NULL) && (new_dhp2 != NULL)) {
 715                 dvm_track->hdt_refcnt++;
 716         }
 717         mutex_exit(&dvm_track->hdt_lock);
 718 
 719         /*
 720          * For each of the cases where the region is being divided, then we
 721          * need to pass back the "Hermon devmap tracking structure".  This way
 722          * we get it back when each of the remaining pieces is subsequently
 723          * unmapped.
 724          */
 725         if (new_dhp1 != NULL) {
 726                 *pvtp1 = pvtp;
 727         }
 728         if (new_dhp2 != NULL) {
 729                 *pvtp2 = pvtp;
 730         }
 731 
 732         /*
 733          * If the "Hermon devmap tracking structure" is no longer being
 734          * referenced, then free it up.  Otherwise, return.
 735          */
 736         if (dvm_track->hdt_refcnt == 0) {
 737                 mutex_destroy(&dvm_track->hdt_lock);
 738                 kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
 739 
 740                 /*
 741                  * If the mapping was invalid (see explanation above), then
 742                  * no further processing is necessary.
 743                  */
 744                 if (size == 0) {
 745                         return;
 746                 }
 747         } else {
 748                 return;
 749         }
 750 
 751         /*
 752          * Now that we can guarantee that the user memory is fully unmapped,
 753          * we can use the "key" and "type" values to try to find the entry
 754          * in the "userland resources database".  If it's found, then it
 755          * indicates that the queue memory (CQ or QP) has not yet been freed.
 756          * In this case, we update the corresponding CQ or QP handle to
 757          * indicate that the "devmap_devmem_remap()" call will be unnecessary.
 758          * If it's _not_ found, then it indicates that the CQ or QP memory
 759          * was, in fact, freed before it was unmapped (thus requiring a
 760          * previous invalidation by remapping - which will already have
 761          * been done in the free routine).
 762          */
 763         status = hermon_umap_db_find(state->hs_instance, key, type, &value,
 764             0, NULL);
 765         if (status == DDI_SUCCESS) {
 766                 /*
 767                  * Depending on the type of the mapped resource (CQ or QP),
 768                  * update handle to indicate that no invalidation remapping
 769                  * will be necessary.
 770                  */
 771                 if (type == MLNX_UMAP_CQMEM_RSRC) {
 772 
 773                         /* Use "value" to convert to CQ handle */
 774                         rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
 775                         cq = (hermon_cqhdl_t)rsrcp->hr_addr;
 776 
 777                         /*
 778                          * Invalidate the handle to the userland mapping.
 779                          * Note: We must ensure that the mapping being
 780                          * unmapped here is the current one for the CQ.  It
 781                          * is possible that it might not be if this CQ has
 782                          * been resized and the previous CQ memory has not
 783                          * yet been unmapped.  But in that case, because of
 784                          * the devmap_devmem_remap(), there is no longer any
 785                          * association between the mapping and the real CQ
 786                          * kernel memory.
 787                          */
 788                         mutex_enter(&cq->cq_lock);
 789                         if (cq->cq_umap_dhp == dhp) {
 790                                 cq->cq_umap_dhp = NULL;
 791                                 if (cq->cq_resize_hdl) {
 792                                         /* resize is DONE, switch queues */
 793                                         hermon_cq_resize_helper(state, cq);
 794                                 }
 795                         } else {
 796                                 if (cq->cq_resize_hdl &&
 797                                     cq->cq_resize_hdl->cq_umap_dhp == dhp) {
 798                                         /*
 799                                          * Unexpected case.  munmap of the
 800                                          * cq_resize buf, and not the
 801                                          * original buf.
 802                                          */
 803                                         cq->cq_resize_hdl->cq_umap_dhp = NULL;
 804                                 }
 805                         }
 806                         mutex_exit(&cq->cq_lock);
 807 
 808                 } else if (type == MLNX_UMAP_QPMEM_RSRC) {
 809 
 810                         /* Use "value" to convert to QP handle */
 811                         rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
 812                         qp = (hermon_qphdl_t)rsrcp->hr_addr;
 813 
 814                         /*
 815                          * Invalidate the handle to the userland mapping.
 816                          * Note: we ensure that the mapping being unmapped
 817                          * here is the current one for the QP.  This is
 818                          * more of a sanity check here since, unlike CQs
 819                          * (above) we do not support resize of QPs.
 820                          */
 821                         mutex_enter(&qp->qp_lock);
 822                         if (qp->qp_umap_dhp == dhp) {
 823                                 qp->qp_umap_dhp = NULL;
 824                         }
 825                         mutex_exit(&qp->qp_lock);
 826 
 827                 } else if (type == MLNX_UMAP_SRQMEM_RSRC) {
 828 
 829                         /* Use "value" to convert to SRQ handle */
 830                         rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
 831                         srq = (hermon_srqhdl_t)rsrcp->hr_addr;
 832 
 833                         /*
 834                          * Invalidate the handle to the userland mapping.
 835                          * Note: we ensure that the mapping being unmapped
 836                          * here is the current one for the QP.  This is
 837                          * more of a sanity check here since, unlike CQs
 838                          * (above) we do not support resize of QPs.
 839                          */
 840                         mutex_enter(&srq->srq_lock);
 841                         if (srq->srq_umap_dhp == dhp) {
 842                                 srq->srq_umap_dhp = NULL;
 843                         }
 844                         mutex_exit(&srq->srq_lock);
 845                 }
 846         }
 847 }
 848 
 849 
 850 /*
 851  * hermon_devmap_devmem_map()
 852  *    Context: Can be called from kernel context.
 853  */
 854 /* ARGSUSED */
 855 static int
 856 hermon_devmap_dbrecmem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
 857     offset_t off, size_t len, void **pvtp)
 858 {
 859         hermon_state_t          *state;
 860         hermon_devmap_track_t   *dvm_track;
 861         hermon_cqhdl_t          cq;
 862         hermon_qphdl_t          qp;
 863         hermon_srqhdl_t         srq;
 864         minor_t                 instance;
 865         uint64_t                key;
 866         uint_t                  type;
 867 
 868         /* Get Hermon softstate structure from instance */
 869         instance = HERMON_DEV_INSTANCE(dev);
 870         state = ddi_get_soft_state(hermon_statep, instance);
 871         if (state == NULL) {
 872                 return (ENXIO);
 873         }
 874 
 875         /*
 876          * The bottom bits of "offset" are undefined (number depends on
 877          * system PAGESIZE).  Shifting these off leaves us with a "key".
 878          * The "key" is actually a combination of both a real key value
 879          * (for the purpose of database lookup) and a "type" value.  Although
 880          * we are not going to do any database lookup per se, we do want
 881          * to extract the "key" and the "type" (to enable faster lookup of
 882          * the appropriate CQ or QP handle).
 883          */
 884         key  = off >> PAGESHIFT;
 885         type = key & MLNX_UMAP_RSRC_TYPE_MASK;
 886         key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
 887 
 888         /*
 889          * Allocate an entry to track the mapping and unmapping (specifically,
 890          * partial unmapping) of this resource.
 891          */
 892         dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
 893             sizeof (hermon_devmap_track_t), KM_SLEEP);
 894         dvm_track->hdt_offset = off;
 895         dvm_track->hdt_state  = state;
 896         dvm_track->hdt_refcnt = 1;
 897         mutex_init(&dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
 898             DDI_INTR_PRI(state->hs_intrmsi_pri));
 899 
 900         /*
 901          * Depending of the type of resource that has been mapped out, we
 902          * need to update the QP or CQ handle to reflect that it has, in
 903          * fact, been mapped.  This allows the driver code which frees a QP
 904          * or a CQ to know whether it is appropriate to do a
 905          * devmap_devmem_remap() to invalidate the userland mapping for the
 906          * corresponding queue's memory.
 907          */
 908         if (type == MLNX_UMAP_CQMEM_RSRC) {
 909 
 910                 /* Use "key" (CQ number) to do fast lookup of CQ handle */
 911                 cq = hermon_cqhdl_from_cqnum(state, key);
 912 
 913                 /*
 914                  * Update the handle to the userland mapping.  Note:  If
 915                  * the CQ already has a valid userland mapping, then stop
 916                  * and return failure.
 917                  */
 918                 mutex_enter(&cq->cq_lock);
 919                 if (cq->cq_umap_dhp == NULL) {
 920                         cq->cq_umap_dhp = dhp;
 921                         dvm_track->hdt_size = cq->cq_cqinfo.qa_size;
 922                         mutex_exit(&cq->cq_lock);
 923                 } else {
 924                         mutex_exit(&cq->cq_lock);
 925                         goto umem_map_fail;
 926                 }
 927 
 928         } else if (type == MLNX_UMAP_QPMEM_RSRC) {
 929 
 930                 /* Use "key" (QP number) to do fast lookup of QP handle */
 931                 qp = hermon_qphdl_from_qpnum(state, key);
 932 
 933                 /*
 934                  * Update the handle to the userland mapping.  Note:  If
 935                  * the CQ already has a valid userland mapping, then stop
 936                  * and return failure.
 937                  */
 938                 mutex_enter(&qp->qp_lock);
 939                 if (qp->qp_umap_dhp == NULL) {
 940                         qp->qp_umap_dhp = dhp;
 941                         dvm_track->hdt_size = qp->qp_wqinfo.qa_size;
 942                         mutex_exit(&qp->qp_lock);
 943                 } else {
 944                         mutex_exit(&qp->qp_lock);
 945                         goto umem_map_fail;
 946                 }
 947 
 948         } else if (type == MLNX_UMAP_SRQMEM_RSRC) {
 949 
 950                 /* Use "key" (SRQ number) to do fast lookup on SRQ handle */
 951                 srq = hermon_srqhdl_from_srqnum(state, key);
 952 
 953                 /*
 954                  * Update the handle to the userland mapping.  Note:  If the
 955                  * SRQ already has a valid userland mapping, then stop and
 956                  * return failure.
 957                  */
 958                 mutex_enter(&srq->srq_lock);
 959                 if (srq->srq_umap_dhp == NULL) {
 960                         srq->srq_umap_dhp = dhp;
 961                         dvm_track->hdt_size = srq->srq_wqinfo.qa_size;
 962                         mutex_exit(&srq->srq_lock);
 963                 } else {
 964                         mutex_exit(&srq->srq_lock);
 965                         goto umem_map_fail;
 966                 }
 967         }
 968 
 969         /*
 970          * Pass the private "Hermon devmap tracking structure" back.  This
 971          * pointer will be returned in subsequent "unmap" callbacks.
 972          */
 973         *pvtp = dvm_track;
 974 
 975         return (DDI_SUCCESS);
 976 
 977 umem_map_fail:
 978         mutex_destroy(&dvm_track->hdt_lock);
 979         kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
 980         return (DDI_FAILURE);
 981 }
 982 
 983 
 984 /*
 985  * hermon_devmap_dbrecmem_dup()
 986  *    Context: Can be called from kernel context.
 987  */
 988 /* ARGSUSED */
 989 static int
 990 hermon_devmap_dbrecmem_dup(devmap_cookie_t dhp, void *pvtp,
 991     devmap_cookie_t new_dhp, void **new_pvtp)
 992 {
 993         hermon_state_t          *state;
 994         hermon_devmap_track_t   *dvm_track, *new_dvm_track;
 995         uint_t                  maxprot;
 996         int                     status;
 997 
 998         /*
 999          * Extract the Hermon softstate pointer from "Hermon devmap tracking
1000          * structure" (in "pvtp").
1001          */
1002         dvm_track = (hermon_devmap_track_t *)pvtp;
1003         state = dvm_track->hdt_state;
1004 
1005         /*
1006          * Since this devmap_dup() entry point is generally called
1007          * when a process does fork(2), it is incumbent upon the driver
1008          * to insure that the child does not inherit a valid copy of
1009          * the parent's QP or CQ resource.  This is accomplished by using
1010          * devmap_devmem_remap() to invalidate the child's mapping to the
1011          * kernel memory.
1012          */
1013         maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
1014         status = devmap_devmem_remap(new_dhp, state->hs_dip, 0, 0,
1015             dvm_track->hdt_size, maxprot, DEVMAP_MAPPING_INVALID, NULL);
1016         if (status != DDI_SUCCESS) {
1017                 HERMON_WARNING(state, "failed in hermon_devmap_dbrecmem_dup()");
1018                 return (status);
1019         }
1020 
1021         /*
1022          * Allocate a new entry to track the subsequent unmapping
1023          * (specifically, all partial unmappings) of the child's newly
1024          * invalidated resource.  Note: Setting the "hdt_size" field to
1025          * zero here is an indication to the devmap_unmap() entry point
1026          * that this mapping is invalid, and that its subsequent unmapping
1027          * should not affect any of the parent's CQ or QP resources.
1028          */
1029         new_dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
1030             sizeof (hermon_devmap_track_t), KM_SLEEP);
1031         new_dvm_track->hdt_offset = 0;
1032         new_dvm_track->hdt_state  = state;
1033         new_dvm_track->hdt_refcnt = 1;
1034         new_dvm_track->hdt_size        = 0;
1035         mutex_init(&new_dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
1036             DDI_INTR_PRI(state->hs_intrmsi_pri));
1037         *new_pvtp = new_dvm_track;
1038 
1039         return (DDI_SUCCESS);
1040 }
1041 
1042 
1043 /*
1044  * hermon_devmap_dbrecmem_unmap()
1045  *    Context: Can be called from kernel context.
1046  */
1047 /* ARGSUSED */
1048 static void
1049 hermon_devmap_dbrecmem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off,
1050     size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
1051     devmap_cookie_t new_dhp2, void **pvtp2)
1052 {
1053         hermon_state_t          *state;
1054         hermon_rsrc_t           *rsrcp;
1055         hermon_devmap_track_t   *dvm_track;
1056         hermon_cqhdl_t          cq;
1057         hermon_qphdl_t          qp;
1058         hermon_srqhdl_t         srq;
1059         uint64_t                key, value;
1060         uint_t                  type;
1061         uint_t                  size;
1062         int                     status;
1063 
1064         /*
1065          * Extract the Hermon softstate pointer from "Hermon devmap tracking
1066          * structure" (in "pvtp").
1067          */
1068         dvm_track = (hermon_devmap_track_t *)pvtp;
1069         state     = dvm_track->hdt_state;
1070 
1071         /*
1072          * Extract the "offset" from the "Hermon devmap tracking structure".
1073          * Note: The input argument "off" is ignored here because the
1074          * Hermon mapping interfaces define a very specific meaning to
1075          * each "logical offset".  Also extract the "key" and "type" encoded
1076          * in the logical offset.
1077          */
1078         key  = dvm_track->hdt_offset >> PAGESHIFT;
1079         type = key & MLNX_UMAP_RSRC_TYPE_MASK;
1080         key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
1081 
1082         /*
1083          * Extract the "size" of the mapping.  If this size is determined
1084          * to be zero, then it is an indication of a previously invalidated
1085          * mapping, and no CQ or QP resources should be affected.
1086          */
1087         size = dvm_track->hdt_size;
1088 
1089         /*
1090          * If only the "middle portion of a given mapping is being unmapped,
1091          * then we are effectively creating one new piece of mapped memory.
1092          * (Original region is divided into three pieces of which the middle
1093          * piece is being removed.  This leaves two pieces.  Since we started
1094          * with one piece and now have two pieces, we need to increment the
1095          * counter in the "Hermon devmap tracking structure".
1096          *
1097          * If, however, the whole mapped region is being unmapped, then we
1098          * have started with one region which we are completely removing.
1099          * In this case, we need to decrement the counter in the "Hermon
1100          * devmap tracking structure".
1101          *
1102          * In each of the remaining cases, we will have started with one
1103          * mapped region and ended with one (different) region.  So no counter
1104          * modification is necessary.
1105          */
1106         mutex_enter(&dvm_track->hdt_lock);
1107         if ((new_dhp1 == NULL) && (new_dhp2 == NULL)) {
1108                 dvm_track->hdt_refcnt--;
1109         } else if ((new_dhp1 != NULL) && (new_dhp2 != NULL)) {
1110                 dvm_track->hdt_refcnt++;
1111         }
1112         mutex_exit(&dvm_track->hdt_lock);
1113 
1114         /*
1115          * For each of the cases where the region is being divided, then we
1116          * need to pass back the "Hermon devmap tracking structure".  This way
1117          * we get it back when each of the remaining pieces is subsequently
1118          * unmapped.
1119          */
1120         if (new_dhp1 != NULL) {
1121                 *pvtp1 = pvtp;
1122         }
1123         if (new_dhp2 != NULL) {
1124                 *pvtp2 = pvtp;
1125         }
1126 
1127         /*
1128          * If the "Hermon devmap tracking structure" is no longer being
1129          * referenced, then free it up.  Otherwise, return.
1130          */
1131         if (dvm_track->hdt_refcnt == 0) {
1132                 mutex_destroy(&dvm_track->hdt_lock);
1133                 kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
1134 
1135                 /*
1136                  * If the mapping was invalid (see explanation above), then
1137                  * no further processing is necessary.
1138                  */
1139                 if (size == 0) {
1140                         return;
1141                 }
1142         } else {
1143                 return;
1144         }
1145 
1146         /*
1147          * Now that we can guarantee that the user memory is fully unmapped,
1148          * we can use the "key" and "type" values to try to find the entry
1149          * in the "userland resources database".  If it's found, then it
1150          * indicates that the queue memory (CQ or QP) has not yet been freed.
1151          * In this case, we update the corresponding CQ or QP handle to
1152          * indicate that the "devmap_devmem_remap()" call will be unnecessary.
1153          * If it's _not_ found, then it indicates that the CQ or QP memory
1154          * was, in fact, freed before it was unmapped (thus requiring a
1155          * previous invalidation by remapping - which will already have
1156          * been done in the free routine).
1157          */
1158         status = hermon_umap_db_find(state->hs_instance, key, type, &value,
1159             0, NULL);
1160         if (status == DDI_SUCCESS) {
1161                 /*
1162                  * Depending on the type of the mapped resource (CQ or QP),
1163                  * update handle to indicate that no invalidation remapping
1164                  * will be necessary.
1165                  */
1166                 if (type == MLNX_UMAP_CQMEM_RSRC) {
1167 
1168                         /* Use "value" to convert to CQ handle */
1169                         rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
1170                         cq = (hermon_cqhdl_t)rsrcp->hr_addr;
1171 
1172                         /*
1173                          * Invalidate the handle to the userland mapping.
1174                          * Note: We must ensure that the mapping being
1175                          * unmapped here is the current one for the CQ.  It
1176                          * is possible that it might not be if this CQ has
1177                          * been resized and the previous CQ memory has not
1178                          * yet been unmapped.  But in that case, because of
1179                          * the devmap_devmem_remap(), there is no longer any
1180                          * association between the mapping and the real CQ
1181                          * kernel memory.
1182                          */
1183                         mutex_enter(&cq->cq_lock);
1184                         if (cq->cq_umap_dhp == dhp) {
1185                                 cq->cq_umap_dhp = NULL;
1186                         }
1187                         mutex_exit(&cq->cq_lock);
1188 
1189                 } else if (type == MLNX_UMAP_QPMEM_RSRC) {
1190 
1191                         /* Use "value" to convert to QP handle */
1192                         rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
1193                         qp = (hermon_qphdl_t)rsrcp->hr_addr;
1194 
1195                         /*
1196                          * Invalidate the handle to the userland mapping.
1197                          * Note: we ensure that the mapping being unmapped
1198                          * here is the current one for the QP.  This is
1199                          * more of a sanity check here since, unlike CQs
1200                          * (above) we do not support resize of QPs.
1201                          */
1202                         mutex_enter(&qp->qp_lock);
1203                         if (qp->qp_umap_dhp == dhp) {
1204                                 qp->qp_umap_dhp = NULL;
1205                         }
1206                         mutex_exit(&qp->qp_lock);
1207 
1208                 } else if (type == MLNX_UMAP_SRQMEM_RSRC) {
1209 
1210                         /* Use "value" to convert to SRQ handle */
1211                         rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
1212                         srq = (hermon_srqhdl_t)rsrcp->hr_addr;
1213 
1214                         /*
1215                          * Invalidate the handle to the userland mapping.
1216                          * Note: we ensure that the mapping being unmapped
1217                          * here is the current one for the QP.  This is
1218                          * more of a sanity check here since, unlike CQs
1219                          * (above) we do not support resize of QPs.
1220                          */
1221                         mutex_enter(&srq->srq_lock);
1222                         if (srq->srq_umap_dhp == dhp) {
1223                                 srq->srq_umap_dhp = NULL;
1224                         }
1225                         mutex_exit(&srq->srq_lock);
1226                 }
1227         }
1228 }
1229 
1230 
1231 /*
1232  * hermon_devmap_devmem_map()
1233  *    Context: Can be called from kernel context.
1234  */
1235 /* ARGSUSED */
1236 static int
1237 hermon_devmap_devmem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
1238     offset_t off, size_t len, void **pvtp)
1239 {
1240         hermon_state_t          *state;
1241         hermon_devmap_track_t   *dvm_track;
1242         minor_t                 instance;
1243 
1244         /* Get Hermon softstate structure from instance */
1245         instance = HERMON_DEV_INSTANCE(dev);
1246         state = ddi_get_soft_state(hermon_statep, instance);
1247         if (state == NULL) {
1248                 return (ENXIO);
1249         }
1250 
1251         /*
1252          * Allocate an entry to track the mapping and unmapping of this
1253          * resource.  Note:  We don't need to initialize the "refcnt" or
1254          * "offset" fields here, nor do we need to initialize the mutex
1255          * used with the "refcnt".  Since UAR pages are single pages, they
1256          * are not subject to "partial" unmappings.  This makes these other
1257          * fields unnecessary.
1258          */
1259         dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
1260             sizeof (hermon_devmap_track_t), KM_SLEEP);
1261         dvm_track->hdt_state  = state;
1262         dvm_track->hdt_size   = (uint_t)PAGESIZE;
1263 
1264         /*
1265          * Pass the private "Hermon devmap tracking structure" back.  This
1266          * pointer will be returned in a subsequent "unmap" callback.
1267          */
1268         *pvtp = dvm_track;
1269 
1270         return (DDI_SUCCESS);
1271 }
1272 
1273 
1274 /*
1275  * hermon_devmap_devmem_dup()
1276  *    Context: Can be called from kernel context.
1277  */
1278 /* ARGSUSED */
1279 static int
1280 hermon_devmap_devmem_dup(devmap_cookie_t dhp, void *pvtp,
1281     devmap_cookie_t new_dhp, void **new_pvtp)
1282 {
1283         hermon_state_t          *state;
1284         hermon_devmap_track_t   *dvm_track;
1285         uint_t                  maxprot;
1286         int                     status;
1287 
1288         /*
1289          * Extract the Hermon softstate pointer from "Hermon devmap tracking
1290          * structure" (in "pvtp").  Note: If the tracking structure is NULL
1291          * here, it means that the mapping corresponds to an invalid mapping.
1292          * In this case, it can be safely ignored ("new_pvtp" set to NULL).
1293          */
1294         dvm_track = (hermon_devmap_track_t *)pvtp;
1295         if (dvm_track == NULL) {
1296                 *new_pvtp = NULL;
1297                 return (DDI_SUCCESS);
1298         }
1299 
1300         state = dvm_track->hdt_state;
1301 
1302         /*
1303          * Since this devmap_dup() entry point is generally called
1304          * when a process does fork(2), it is incumbent upon the driver
1305          * to insure that the child does not inherit a valid copy of
1306          * the parent's resource.  This is accomplished by using
1307          * devmap_devmem_remap() to invalidate the child's mapping to the
1308          * kernel memory.
1309          */
1310         maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
1311         status = devmap_devmem_remap(new_dhp, state->hs_dip, 0, 0,
1312             dvm_track->hdt_size, maxprot, DEVMAP_MAPPING_INVALID, NULL);
1313         if (status != DDI_SUCCESS) {
1314                 HERMON_WARNING(state, "failed in hermon_devmap_devmem_dup()");
1315                 return (status);
1316         }
1317 
1318         /*
1319          * Since the region is invalid, there is no need for us to
1320          * allocate and continue to track an additional "Hermon devmap
1321          * tracking structure".  Instead we return NULL here, which is an
1322          * indication to the devmap_unmap() entry point that this entry
1323          * can be safely ignored.
1324          */
1325         *new_pvtp = NULL;
1326 
1327         return (DDI_SUCCESS);
1328 }
1329 
1330 
1331 /*
1332  * hermon_devmap_devmem_unmap()
1333  *    Context: Can be called from kernel context.
1334  */
1335 /* ARGSUSED */
1336 static void
1337 hermon_devmap_devmem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off,
1338     size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
1339     devmap_cookie_t new_dhp2, void **pvtp2)
1340 {
1341         hermon_devmap_track_t   *dvm_track;
1342 
1343         /*
1344          * Free up the "Hermon devmap tracking structure" (in "pvtp").
1345          * There cannot be "partial" unmappings here because all UAR pages
1346          * are single pages.  Note: If the tracking structure is NULL here,
1347          * it means that the mapping corresponds to an invalid mapping.  In
1348          * this case, it can be safely ignored.
1349          */
1350         dvm_track = (hermon_devmap_track_t *)pvtp;
1351         if (dvm_track == NULL) {
1352                 return;
1353         }
1354 
1355         kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
1356 }
1357 
1358 
1359 /*
1360  * hermon_umap_ci_data_in()
1361  *    Context: Can be called from user or kernel context.
1362  */
1363 /* ARGSUSED */
1364 ibt_status_t
1365 hermon_umap_ci_data_in(hermon_state_t *state, ibt_ci_data_flags_t flags,
1366     ibt_object_type_t object, void *hdl, void *data_p, size_t data_sz)
1367 {
1368         int     status;
1369 
1370         /*
1371          * Depending on the type of object about which additional information
1372          * is being provided (currently only MR is supported), we call the
1373          * appropriate resource-specific function.
1374          */
1375         switch (object) {
1376         case IBT_HDL_MR:
1377                 status = hermon_umap_mr_data_in((hermon_mrhdl_t)hdl,
1378                     (ibt_mr_data_in_t *)data_p, data_sz);
1379                 if (status != DDI_SUCCESS) {
1380                         return (status);
1381                 }
1382                 break;
1383 
1384         /*
1385          * For other possible valid IBT types, we return IBT_NOT_SUPPORTED,
1386          * since the Hermon driver does not support these.
1387          */
1388         case IBT_HDL_HCA:
1389         case IBT_HDL_QP:
1390         case IBT_HDL_CQ:
1391         case IBT_HDL_PD:
1392         case IBT_HDL_MW:
1393         case IBT_HDL_AH:
1394         case IBT_HDL_SCHED:
1395         case IBT_HDL_EEC:
1396         case IBT_HDL_RDD:
1397         case IBT_HDL_SRQ:
1398                 return (IBT_NOT_SUPPORTED);
1399 
1400         /*
1401          * Any other types are invalid.
1402          */
1403         default:
1404                 return (IBT_INVALID_PARAM);
1405         }
1406 
1407         return (DDI_SUCCESS);
1408 }
1409 
1410 
1411 /*
1412  * hermon_umap_mr_data_in()
1413  *    Context: Can be called from user or kernel context.
1414  */
1415 static ibt_status_t
1416 hermon_umap_mr_data_in(hermon_mrhdl_t mr, ibt_mr_data_in_t *data,
1417     size_t data_sz)
1418 {
1419         if (data->mr_rev != IBT_MR_DATA_IN_IF_VERSION) {
1420                 return (IBT_NOT_SUPPORTED);
1421         }
1422 
1423         /* Check for valid MR handle pointer */
1424         if (mr == NULL) {
1425                 return (IBT_MR_HDL_INVALID);
1426         }
1427 
1428         /* Check for valid MR input structure size */
1429         if (data_sz < sizeof (ibt_mr_data_in_t)) {
1430                 return (IBT_INSUFF_RESOURCE);
1431         }
1432 
1433         /*
1434          * Ensure that the MR corresponds to userland memory and that it is
1435          * a currently valid memory region as well.
1436          */
1437         mutex_enter(&mr->mr_lock);
1438         if ((mr->mr_is_umem == 0) || (mr->mr_umemcookie == NULL)) {
1439                 mutex_exit(&mr->mr_lock);
1440                 return (IBT_MR_HDL_INVALID);
1441         }
1442 
1443         /*
1444          * If it has passed all the above checks, then extract the callback
1445          * function and argument from the input structure.  Copy them into
1446          * the MR handle.  This function will be called only if the memory
1447          * corresponding to the MR handle gets a umem_lockmemory() callback.
1448          */
1449         mr->mr_umem_cbfunc = data->mr_func;
1450         mr->mr_umem_cbarg1 = data->mr_arg1;
1451         mr->mr_umem_cbarg2 = data->mr_arg2;
1452         mutex_exit(&mr->mr_lock);
1453 
1454         return (DDI_SUCCESS);
1455 }
1456 
1457 
1458 /*
1459  * hermon_umap_ci_data_out()
1460  *    Context: Can be called from user or kernel context.
1461  */
1462 /* ARGSUSED */
1463 ibt_status_t
1464 hermon_umap_ci_data_out(hermon_state_t *state, ibt_ci_data_flags_t flags,
1465     ibt_object_type_t object, void *hdl, void *data_p, size_t data_sz)
1466 {
1467         int     status;
1468 
1469         /*
1470          * Depending on the type of object about which additional information
1471          * is being requested (CQ or QP), we call the appropriate resource-
1472          * specific mapping function.
1473          */
1474         switch (object) {
1475         case IBT_HDL_CQ:
1476                 status = hermon_umap_cq_data_out((hermon_cqhdl_t)hdl,
1477                     (mlnx_umap_cq_data_out_t *)data_p, data_sz);
1478                 if (status != DDI_SUCCESS) {
1479                         return (status);
1480                 }
1481                 break;
1482 
1483         case IBT_HDL_QP:
1484                 status = hermon_umap_qp_data_out((hermon_qphdl_t)hdl,
1485                     (mlnx_umap_qp_data_out_t *)data_p, data_sz);
1486                 if (status != DDI_SUCCESS) {
1487                         return (status);
1488                 }
1489                 break;
1490 
1491         case IBT_HDL_SRQ:
1492                 status = hermon_umap_srq_data_out((hermon_srqhdl_t)hdl,
1493                     (mlnx_umap_srq_data_out_t *)data_p, data_sz);
1494                 if (status != DDI_SUCCESS) {
1495                         return (status);
1496                 }
1497                 break;
1498 
1499         case IBT_HDL_PD:
1500                 status = hermon_umap_pd_data_out((hermon_pdhdl_t)hdl,
1501                     (mlnx_umap_pd_data_out_t *)data_p, data_sz);
1502                 if (status != DDI_SUCCESS) {
1503                         return (status);
1504                 }
1505                 break;
1506 
1507         /*
1508          * For other possible valid IBT types, we return IBT_NOT_SUPPORTED,
1509          * since the Hermon driver does not support these.
1510          */
1511         case IBT_HDL_HCA:
1512         case IBT_HDL_MR:
1513         case IBT_HDL_MW:
1514         case IBT_HDL_AH:
1515         case IBT_HDL_SCHED:
1516         case IBT_HDL_EEC:
1517         case IBT_HDL_RDD:
1518                 return (IBT_NOT_SUPPORTED);
1519 
1520         /*
1521          * Any other types are invalid.
1522          */
1523         default:
1524                 return (IBT_INVALID_PARAM);
1525         }
1526 
1527         return (DDI_SUCCESS);
1528 }
1529 
1530 
1531 /*
1532  * hermon_umap_cq_data_out()
1533  *    Context: Can be called from user or kernel context.
1534  */
1535 static ibt_status_t
1536 hermon_umap_cq_data_out(hermon_cqhdl_t cq, mlnx_umap_cq_data_out_t *data,
1537     size_t data_sz)
1538 {
1539         /* Check for valid CQ handle pointer */
1540         if (cq == NULL) {
1541                 return (IBT_CQ_HDL_INVALID);
1542         }
1543 
1544         /* Check for valid CQ mapping structure size */
1545         if (data_sz < sizeof (mlnx_umap_cq_data_out_t)) {
1546                 return (IBT_INSUFF_RESOURCE);
1547         }
1548 
1549         /* deal with cq_alloc() verses cq_resize() */
1550         if (cq->cq_resize_hdl) {
1551                 data->mcq_maplen = cq->cq_resize_hdl->cq_cqinfo.qa_size;
1552                 data->mcq_numcqe = cq->cq_resize_hdl->cq_bufsz;
1553         } else {
1554                 data->mcq_maplen = cq->cq_cqinfo.qa_size;
1555                 data->mcq_numcqe = cq->cq_bufsz;
1556         }
1557 
1558         /*
1559          * If it has passed all the above checks, then fill in all the useful
1560          * mapping information (including the mapping offset that will be
1561          * passed back to the devmap() interface during a subsequent mmap()
1562          * call.
1563          *
1564          * The "offset" for CQ mmap()'s looks like this:
1565          * +----------------------------------------+--------+--------------+
1566          * |               CQ Number                |  0x33  | Reserved (0) |
1567          * +----------------------------------------+--------+--------------+
1568          *         (64 - 8 - PAGESHIFT) bits        8 bits      PAGESHIFT bits
1569          *
1570          * This returns information about the mapping offset, the length of
1571          * the CQ memory, the CQ number (for use in later CQ doorbells), the
1572          * number of CQEs the CQ memory can hold, and the size of each CQE.
1573          */
1574         data->mcq_rev                        = MLNX_UMAP_IF_VERSION;
1575         data->mcq_mapoffset          = ((((uint64_t)cq->cq_cqnum <<
1576             MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_CQMEM_RSRC) << PAGESHIFT);
1577         data->mcq_cqnum                      = cq->cq_cqnum;
1578         data->mcq_cqesz                      = sizeof (hermon_hw_cqe_t);
1579 
1580         /* doorbell record fields */
1581         data->mcq_polldbr_mapoffset  = cq->cq_dbr_mapoffset;
1582         data->mcq_polldbr_maplen     = PAGESIZE;
1583         data->mcq_polldbr_offset     = (uintptr_t)cq->cq_arm_ci_vdbr &
1584             PAGEOFFSET;
1585         data->mcq_armdbr_mapoffset   = cq->cq_dbr_mapoffset;
1586         data->mcq_armdbr_maplen              = PAGESIZE;
1587         data->mcq_armdbr_offset              = data->mcq_polldbr_offset + 4;
1588 
1589         return (DDI_SUCCESS);
1590 }
1591 
1592 
1593 /*
1594  * hermon_umap_qp_data_out()
1595  *    Context: Can be called from user or kernel context.
1596  */
1597 static ibt_status_t
1598 hermon_umap_qp_data_out(hermon_qphdl_t qp, mlnx_umap_qp_data_out_t *data,
1599     size_t data_sz)
1600 {
1601         /* Check for valid QP handle pointer */
1602         if (qp == NULL) {
1603                 return (IBT_QP_HDL_INVALID);
1604         }
1605 
1606         /* Check for valid QP mapping structure size */
1607         if (data_sz < sizeof (mlnx_umap_qp_data_out_t)) {
1608                 return (IBT_INSUFF_RESOURCE);
1609         }
1610 
1611         /*
1612          * If it has passed all the checks, then fill in all the useful
1613          * mapping information (including the mapping offset that will be
1614          * passed back to the devmap() interface during a subsequent mmap()
1615          * call.
1616          *
1617          * The "offset" for QP mmap()'s looks like this:
1618          * +----------------------------------------+--------+--------------+
1619          * |               QP Number                |  0x44  | Reserved (0) |
1620          * +----------------------------------------+--------+--------------+
1621          *         (64 - 8 - PAGESHIFT) bits        8 bits      PAGESHIFT bits
1622          *
1623          * This returns information about the mapping offset, the length of
1624          * the QP memory, and the QP number (for use in later send and recv
1625          * doorbells).  It also returns the following information for both
1626          * the receive work queue and the send work queue, respectively:  the
1627          * offset (from the base mapped address) of the start of the given
1628          * work queue, the 64-bit IB virtual address that corresponds to
1629          * the base mapped address (needed for posting WQEs though the
1630          * QP doorbells), the number of WQEs the given work queue can hold,
1631          * and the size of each WQE for the given work queue.
1632          */
1633         data->mqp_rev                = MLNX_UMAP_IF_VERSION;
1634         data->mqp_mapoffset  = ((((uint64_t)qp->qp_qpnum <<
1635             MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_QPMEM_RSRC) << PAGESHIFT);
1636         data->mqp_maplen     = qp->qp_wqinfo.qa_size;
1637         data->mqp_qpnum              = qp->qp_qpnum;
1638 
1639         /*
1640          * If this QP is associated with a shared receive queue (SRQ),
1641          * then return invalid RecvQ parameters.  Otherwise, return
1642          * the proper parameter values.
1643          */
1644         if (qp->qp_alloc_flags & IBT_QP_USES_SRQ) {
1645                 data->mqp_rq_off     = (uint32_t)qp->qp_wqinfo.qa_size;
1646                 data->mqp_rq_desc_addr       = (uint32_t)qp->qp_wqinfo.qa_size;
1647                 data->mqp_rq_numwqe  = 0;
1648                 data->mqp_rq_wqesz   = 0;
1649                 data->mqp_rdbr_mapoffset = 0;
1650                 data->mqp_rdbr_maplen        = 0;
1651                 data->mqp_rdbr_offset        = 0;
1652         } else {
1653                 data->mqp_rq_off     = (uintptr_t)qp->qp_rq_buf -
1654                     (uintptr_t)qp->qp_wqinfo.qa_buf_aligned;
1655                 data->mqp_rq_desc_addr       = (uint32_t)((uintptr_t)qp->qp_rq_buf -
1656                     qp->qp_desc_off);
1657                 data->mqp_rq_numwqe  = qp->qp_rq_bufsz;
1658                 data->mqp_rq_wqesz   = (1 << qp->qp_rq_log_wqesz);
1659 
1660                 /* doorbell record fields */
1661                 data->mqp_rdbr_mapoffset = qp->qp_rdbr_mapoffset;
1662                 data->mqp_rdbr_maplen        = PAGESIZE;
1663                 data->mqp_rdbr_offset        = (uintptr_t)qp->qp_rq_vdbr &
1664                     PAGEOFFSET;
1665         }
1666         data->mqp_sq_off             = (uintptr_t)qp->qp_sq_buf -
1667             (uintptr_t)qp->qp_wqinfo.qa_buf_aligned;
1668         data->mqp_sq_desc_addr       = (uint32_t)((uintptr_t)qp->qp_sq_buf -
1669             qp->qp_desc_off);
1670         data->mqp_sq_numwqe  = qp->qp_sq_bufsz;
1671         data->mqp_sq_wqesz   = (1 << qp->qp_sq_log_wqesz);
1672         data->mqp_sq_headroomwqes = qp->qp_sq_hdrmwqes;
1673 
1674         /* doorbell record fields */
1675         data->mqp_sdbr_mapoffset = 0;
1676         data->mqp_sdbr_maplen        = 0;
1677         data->mqp_sdbr_offset        = 0;
1678 
1679         return (DDI_SUCCESS);
1680 }
1681 
1682 
1683 /*
1684  * hermon_umap_srq_data_out()
1685  *    Context: Can be called from user or kernel context.
1686  */
1687 static ibt_status_t
1688 hermon_umap_srq_data_out(hermon_srqhdl_t srq, mlnx_umap_srq_data_out_t *data,
1689     size_t data_sz)
1690 {
1691         /* Check for valid SRQ handle pointer */
1692         if (srq == NULL) {
1693                 return (IBT_SRQ_HDL_INVALID);
1694         }
1695 
1696         /* Check for valid SRQ mapping structure size */
1697         if (data_sz < sizeof (mlnx_umap_srq_data_out_t)) {
1698                 return (IBT_INSUFF_RESOURCE);
1699         }
1700 
1701         /*
1702          * If it has passed all the checks, then fill in all the useful
1703          * mapping information (including the mapping offset that will be
1704          * passed back to the devmap() interface during a subsequent mmap()
1705          * call.
1706          *
1707          * The "offset" for SRQ mmap()'s looks like this:
1708          * +----------------------------------------+--------+--------------+
1709          * |               SRQ Number               |  0x66  | Reserved (0) |
1710          * +----------------------------------------+--------+--------------+
1711          *         (64 - 8 - PAGESHIFT) bits        8 bits      PAGESHIFT bits
1712          *
1713          * This returns information about the mapping offset, the length of the
1714          * SRQ memory, and the SRQ number (for use in later send and recv
1715          * doorbells).  It also returns the following information for the
1716          * shared receive queue: the offset (from the base mapped address) of
1717          * the start of the given work queue, the 64-bit IB virtual address
1718          * that corresponds to the base mapped address (needed for posting WQEs
1719          * though the QP doorbells), the number of WQEs the given work queue
1720          * can hold, and the size of each WQE for the given work queue.
1721          */
1722         data->msrq_rev               = MLNX_UMAP_IF_VERSION;
1723         data->msrq_mapoffset = ((((uint64_t)srq->srq_srqnum <<
1724             MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_SRQMEM_RSRC) << PAGESHIFT);
1725         data->msrq_maplen    = srq->srq_wqinfo.qa_size;
1726         data->msrq_srqnum    = srq->srq_srqnum;
1727 
1728         data->msrq_desc_addr = (uint32_t)((uintptr_t)srq->srq_wq_buf -
1729             srq->srq_desc_off);
1730         data->msrq_numwqe    = srq->srq_wq_bufsz;
1731         data->msrq_wqesz     = (1 << srq->srq_wq_log_wqesz);
1732 
1733         /* doorbell record fields */
1734         data->msrq_rdbr_mapoffset = srq->srq_rdbr_mapoffset;
1735         data->msrq_rdbr_maplen       = PAGESIZE;
1736         data->msrq_rdbr_offset       = (uintptr_t)srq->srq_wq_vdbr &
1737             PAGEOFFSET;
1738 
1739         return (DDI_SUCCESS);
1740 }
1741 
1742 
1743 /*
1744  * hermon_umap_pd_data_out()
1745  *    Context: Can be called from user or kernel context.
1746  */
1747 static ibt_status_t
1748 hermon_umap_pd_data_out(hermon_pdhdl_t pd, mlnx_umap_pd_data_out_t *data,
1749     size_t data_sz)
1750 {
1751         /* Check for valid PD handle pointer */
1752         if (pd == NULL) {
1753                 return (IBT_PD_HDL_INVALID);
1754         }
1755 
1756         /* Check for valid PD mapping structure size */
1757         if (data_sz < sizeof (mlnx_umap_pd_data_out_t)) {
1758                 return (IBT_INSUFF_RESOURCE);
1759         }
1760 
1761         /*
1762          * If it has passed all the checks, then fill the PD table index
1763          * (the PD table allocated index for the PD pd_pdnum).
1764          */
1765         data->mpd_rev                = MLNX_UMAP_IF_VERSION;
1766         data->mpd_pdnum              = pd->pd_pdnum;
1767 
1768         return (DDI_SUCCESS);
1769 }
1770 
1771 
1772 /*
1773  * hermon_umap_db_init()
1774  *    Context: Only called from attach() path context
1775  */
1776 void
1777 hermon_umap_db_init(void)
1778 {
1779         /*
1780          * Initialize the lock used by the Hermon "userland resources database"
1781          * This is used to ensure atomic access to add, remove, and find
1782          * entries in the database.
1783          */
1784         mutex_init(&hermon_userland_rsrc_db.hdl_umapdb_lock, NULL,
1785             MUTEX_DRIVER, NULL);
1786 
1787         /*
1788          * Initialize the AVL tree used for the "userland resources
1789          * database".  Using an AVL tree here provides the ability to
1790          * scale the database size to large numbers of resources.  The
1791          * entries in the tree are "hermon_umap_db_entry_t" (see
1792          * hermon_umap.h).  The tree is searched with the help of the
1793          * hermon_umap_db_compare() routine.
1794          */
1795         avl_create(&hermon_userland_rsrc_db.hdl_umapdb_avl,
1796             hermon_umap_db_compare, sizeof (hermon_umap_db_entry_t),
1797             offsetof(hermon_umap_db_entry_t, hdbe_avlnode));
1798 }
1799 
1800 
1801 /*
1802  * hermon_umap_db_fini()
1803  *    Context: Only called from attach() and/or detach() path contexts
1804  */
1805 void
1806 hermon_umap_db_fini(void)
1807 {
1808         /* Destroy the AVL tree for the "userland resources database" */
1809         avl_destroy(&hermon_userland_rsrc_db.hdl_umapdb_avl);
1810 
1811         /* Destroy the lock for the "userland resources database" */
1812         mutex_destroy(&hermon_userland_rsrc_db.hdl_umapdb_lock);
1813 }
1814 
1815 
1816 /*
1817  * hermon_umap_db_alloc()
1818  *    Context: Can be called from user or kernel context.
1819  */
1820 hermon_umap_db_entry_t *
1821 hermon_umap_db_alloc(uint_t instance, uint64_t key, uint_t type, uint64_t value)
1822 {
1823         hermon_umap_db_entry_t  *umapdb;
1824 
1825         /* Allocate an entry to add to the "userland resources database" */
1826         umapdb = kmem_zalloc(sizeof (hermon_umap_db_entry_t), KM_NOSLEEP);
1827         if (umapdb == NULL) {
1828                 return (NULL);
1829         }
1830 
1831         /* Fill in the fields in the database entry */
1832         umapdb->hdbe_common.hdb_instance  = instance;
1833         umapdb->hdbe_common.hdb_type   = type;
1834         umapdb->hdbe_common.hdb_key    = key;
1835         umapdb->hdbe_common.hdb_value          = value;
1836 
1837         return (umapdb);
1838 }
1839 
1840 
1841 /*
1842  * hermon_umap_db_free()
1843  *    Context: Can be called from user or kernel context.
1844  */
1845 void
1846 hermon_umap_db_free(hermon_umap_db_entry_t *umapdb)
1847 {
1848         /* Free the database entry */
1849         kmem_free(umapdb, sizeof (hermon_umap_db_entry_t));
1850 }
1851 
1852 
1853 /*
1854  * hermon_umap_db_add()
1855  *    Context: Can be called from user or kernel context.
1856  */
1857 void
1858 hermon_umap_db_add(hermon_umap_db_entry_t *umapdb)
1859 {
1860         mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
1861         hermon_umap_db_add_nolock(umapdb);
1862         mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
1863 }
1864 
1865 
1866 /*
1867  * hermon_umap_db_add_nolock()
1868  *    Context: Can be called from user or kernel context.
1869  */
1870 void
1871 hermon_umap_db_add_nolock(hermon_umap_db_entry_t *umapdb)
1872 {
1873         hermon_umap_db_query_t  query;
1874         avl_index_t             where;
1875 
1876         ASSERT(MUTEX_HELD(&hermon_userland_rsrc_db.hdl_umapdb_lock));
1877 
1878         /*
1879          * Copy the common portion of the "to-be-added" database entry
1880          * into the "hermon_umap_db_query_t" structure.  We use this structure
1881          * (with no flags set) to find the appropriate location in the
1882          * "userland resources database" for the new entry to be added.
1883          *
1884          * Note: we expect that this entry should not be found in the
1885          * database (unless something bad has happened).
1886          */
1887         query.hqdb_common = umapdb->hdbe_common;
1888         query.hqdb_flags  = 0;
1889         (void) avl_find(&hermon_userland_rsrc_db.hdl_umapdb_avl, &query,
1890             &where);
1891 
1892         /*
1893          * Now, using the "where" field from the avl_find() operation
1894          * above, we will insert the new database entry ("umapdb").
1895          */
1896         avl_insert(&hermon_userland_rsrc_db.hdl_umapdb_avl, umapdb,
1897             where);
1898 }
1899 
1900 
1901 /*
1902  * hermon_umap_db_find()
1903  *    Context: Can be called from user or kernel context.
1904  */
1905 int
1906 hermon_umap_db_find(uint_t instance, uint64_t key, uint_t type,
1907     uint64_t *value, uint_t flag, hermon_umap_db_entry_t        **umapdb)
1908 {
1909         int     status;
1910 
1911         mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
1912         status = hermon_umap_db_find_nolock(instance, key, type, value, flag,
1913             umapdb);
1914         mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
1915 
1916         return (status);
1917 }
1918 
1919 
1920 /*
1921  * hermon_umap_db_find_nolock()
1922  *    Context: Can be called from user or kernel context.
1923  */
1924 int
1925 hermon_umap_db_find_nolock(uint_t instance, uint64_t key, uint_t type,
1926     uint64_t *value, uint_t flags, hermon_umap_db_entry_t **umapdb)
1927 {
1928         hermon_umap_db_query_t  query;
1929         hermon_umap_db_entry_t  *entry;
1930         avl_index_t             where;
1931 
1932         ASSERT(MUTEX_HELD(&hermon_userland_rsrc_db.hdl_umapdb_lock));
1933 
1934         /*
1935          * Fill in key, type, instance, and flags values of the
1936          * hermon_umap_db_query_t in preparation for the database
1937          * lookup.
1938          */
1939         query.hqdb_flags                = flags;
1940         query.hqdb_common.hdb_key       = key;
1941         query.hqdb_common.hdb_type      = type;
1942         query.hqdb_common.hdb_instance  = instance;
1943 
1944         /*
1945          * Perform the database query.  If no entry is found, then
1946          * return failure, else continue.
1947          */
1948         entry = (hermon_umap_db_entry_t *)avl_find(
1949             &hermon_userland_rsrc_db.hdl_umapdb_avl, &query, &where);
1950         if (entry == NULL) {
1951                 return (DDI_FAILURE);
1952         }
1953 
1954         /*
1955          * If the flags argument specifies that the entry should
1956          * be removed if found, then call avl_remove() to remove
1957          * the entry from the database.
1958          */
1959         if (flags & HERMON_UMAP_DB_REMOVE) {
1960 
1961                 avl_remove(&hermon_userland_rsrc_db.hdl_umapdb_avl, entry);
1962 
1963                 /*
1964                  * The database entry is returned with the expectation
1965                  * that the caller will use hermon_umap_db_free() to
1966                  * free the entry's memory.  ASSERT that this is non-NULL.
1967                  * NULL pointer should never be passed for the
1968                  * HERMON_UMAP_DB_REMOVE case.
1969                  */
1970                 ASSERT(umapdb != NULL);
1971         }
1972 
1973         /*
1974          * If the caller would like visibility to the database entry
1975          * (indicated through the use of a non-NULL "umapdb" argument),
1976          * then fill it in.
1977          */
1978         if (umapdb != NULL) {
1979                 *umapdb = entry;
1980         }
1981 
1982         /* Extract value field from database entry and return success */
1983         *value = entry->hdbe_common.hdb_value;
1984 
1985         return (DDI_SUCCESS);
1986 }
1987 
1988 
1989 /*
1990  * hermon_umap_umemlock_cb()
1991  *    Context: Can be called from callback context.
1992  */
1993 void
1994 hermon_umap_umemlock_cb(ddi_umem_cookie_t *umem_cookie)
1995 {
1996         hermon_umap_db_entry_t  *umapdb;
1997         hermon_state_t          *state;
1998         hermon_rsrc_t           *rsrcp;
1999         hermon_mrhdl_t          mr;
2000         uint64_t                value;
2001         uint_t                  instance;
2002         int                     status;
2003         void                    (*mr_callback)(void *, void *);
2004         void                    *mr_cbarg1, *mr_cbarg2;
2005 
2006         /*
2007          * If this was userland memory, then we need to remove its entry
2008          * from the "userland resources database".  Note:  We use the
2009          * HERMON_UMAP_DB_IGNORE_INSTANCE flag here because we don't know
2010          * which instance was used when the entry was added (but we want
2011          * to know after the entry is found using the other search criteria).
2012          */
2013         status = hermon_umap_db_find(0, (uint64_t)(uintptr_t)umem_cookie,
2014             MLNX_UMAP_MRMEM_RSRC, &value, (HERMON_UMAP_DB_REMOVE |
2015             HERMON_UMAP_DB_IGNORE_INSTANCE), &umapdb);
2016         if (status == DDI_SUCCESS) {
2017                 instance = umapdb->hdbe_common.hdb_instance;
2018                 state = ddi_get_soft_state(hermon_statep, instance);
2019                 if (state == NULL) {
2020                         cmn_err(CE_WARN, "Unable to match Hermon instance\n");
2021                         return;
2022                 }
2023 
2024                 /* Free the database entry */
2025                 hermon_umap_db_free(umapdb);
2026 
2027                 /* Use "value" to convert to an MR handle */
2028                 rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
2029                 mr = (hermon_mrhdl_t)rsrcp->hr_addr;
2030 
2031                 /*
2032                  * If a callback has been provided, call it first.  This
2033                  * callback is expected to do any cleanup necessary to
2034                  * guarantee that the subsequent MR deregister (below)
2035                  * will succeed.  Specifically, this means freeing up memory
2036                  * windows which might have been associated with the MR.
2037                  */
2038                 mutex_enter(&mr->mr_lock);
2039                 mr_callback = mr->mr_umem_cbfunc;
2040                 mr_cbarg1   = mr->mr_umem_cbarg1;
2041                 mr_cbarg2   = mr->mr_umem_cbarg2;
2042                 mutex_exit(&mr->mr_lock);
2043                 if (mr_callback != NULL) {
2044                         mr_callback(mr_cbarg1, mr_cbarg2);
2045                 }
2046 
2047                 /*
2048                  * Then call hermon_mr_deregister() to release the resources
2049                  * associated with the MR handle.  Note: Because this routine
2050                  * will also check for whether the ddi_umem_cookie_t is in the
2051                  * database, it will take responsibility for disabling the
2052                  * memory region and calling ddi_umem_unlock().
2053                  */
2054                 status = hermon_mr_deregister(state, &mr, HERMON_MR_DEREG_ALL,
2055                     HERMON_SLEEP);
2056                 if (status != DDI_SUCCESS) {
2057                         HERMON_WARNING(state, "Unexpected failure in "
2058                             "deregister from callback\n");
2059                 }
2060         }
2061 }
2062 
2063 
2064 /*
2065  * hermon_umap_db_compare()
2066  *    Context: Can be called from user or kernel context.
2067  */
2068 static int
2069 hermon_umap_db_compare(const void *q, const void *e)
2070 {
2071         hermon_umap_db_common_t *entry_common, *query_common;
2072         uint_t                  query_flags;
2073 
2074         entry_common = &((hermon_umap_db_entry_t *)e)->hdbe_common;
2075         query_common = &((hermon_umap_db_query_t *)q)->hqdb_common;
2076         query_flags  = ((hermon_umap_db_query_t *)q)->hqdb_flags;
2077 
2078         /*
2079          * The first comparison is done on the "key" value in "query"
2080          * and "entry".  If they are not equal, then the appropriate
2081          * search direction is returned.  Else, we continue by
2082          * comparing "type".
2083          */
2084         if (query_common->hdb_key < entry_common->hdb_key) {
2085                 return (-1);
2086         } else if (query_common->hdb_key > entry_common->hdb_key) {
2087                 return (+1);
2088         }
2089 
2090         /*
2091          * If the search reaches this point, then "query" and "entry"
2092          * have equal key values.  So we continue be comparing their
2093          * "type" values.  Again, if they are not equal, then the
2094          * appropriate search direction is returned.  Else, we continue
2095          * by comparing "instance".
2096          */
2097         if (query_common->hdb_type < entry_common->hdb_type) {
2098                 return (-1);
2099         } else if (query_common->hdb_type > entry_common->hdb_type) {
2100                 return (+1);
2101         }
2102 
2103         /*
2104          * If the search reaches this point, then "query" and "entry"
2105          * have exactly the same key and type values.  Now we consult
2106          * the "flags" field in the query to determine whether the
2107          * "instance" is relevant to the search.  If the
2108          * HERMON_UMAP_DB_IGNORE_INSTANCE flags is set, then return
2109          * success (0) here.  Otherwise, continue the search by comparing
2110          * instance values and returning the appropriate search direction.
2111          */
2112         if (query_flags & HERMON_UMAP_DB_IGNORE_INSTANCE) {
2113                 return (0);
2114         }
2115 
2116         /*
2117          * If the search has reached this point, then "query" and "entry"
2118          * can only be differentiated by their instance values.  If these
2119          * are not equal, then return the appropriate search direction.
2120          * Else, we return success (0).
2121          */
2122         if (query_common->hdb_instance < entry_common->hdb_instance) {
2123                 return (-1);
2124         } else if (query_common->hdb_instance > entry_common->hdb_instance) {
2125                 return (+1);
2126         }
2127 
2128         /* Everything matches... so return success */
2129         return (0);
2130 }
2131 
2132 
2133 /*
2134  * hermon_umap_db_set_onclose_cb()
2135  *    Context: Can be called from user or kernel context.
2136  */
2137 int
2138 hermon_umap_db_set_onclose_cb(dev_t dev, uint64_t flag,
2139     int (*callback)(void *), void *arg)
2140 {
2141         hermon_umap_db_priv_t   *priv;
2142         hermon_umap_db_entry_t  *umapdb;
2143         minor_t                 instance;
2144         uint64_t                value;
2145         int                     status;
2146 
2147         instance = HERMON_DEV_INSTANCE(dev);
2148         if (instance == (minor_t)-1) {
2149                 return (DDI_FAILURE);
2150         }
2151 
2152         if (flag != HERMON_ONCLOSE_FLASH_INPROGRESS) {
2153                 return (DDI_FAILURE);
2154         }
2155 
2156         /*
2157          * Grab the lock for the "userland resources database" and find
2158          * the entry corresponding to this minor number.  Once it's found,
2159          * allocate (if necessary) and add an entry (in the "hdb_priv"
2160          * field) to indicate that further processing may be needed during
2161          * Hermon's close() handling.
2162          */
2163         mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2164         status = hermon_umap_db_find_nolock(instance, dev,
2165             MLNX_UMAP_PID_RSRC, &value, 0, &umapdb);
2166         if (status != DDI_SUCCESS) {
2167                 mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2168                 return (DDI_FAILURE);
2169         }
2170 
2171         priv = (hermon_umap_db_priv_t *)umapdb->hdbe_common.hdb_priv;
2172         if (priv == NULL) {
2173                 priv = (hermon_umap_db_priv_t *)kmem_zalloc(
2174                     sizeof (hermon_umap_db_priv_t), KM_NOSLEEP);
2175                 if (priv == NULL) {
2176                         mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2177                         return (DDI_FAILURE);
2178                 }
2179         }
2180 
2181         /*
2182          * Save away the callback and argument to be used during Hermon's
2183          * close() processing.
2184          */
2185         priv->hdp_cb = callback;
2186         priv->hdp_arg        = arg;
2187 
2188         umapdb->hdbe_common.hdb_priv = (void *)priv;
2189         mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2190 
2191         return (DDI_SUCCESS);
2192 }
2193 
2194 
2195 /*
2196  * hermon_umap_db_clear_onclose_cb()
2197  *    Context: Can be called from user or kernel context.
2198  */
2199 int
2200 hermon_umap_db_clear_onclose_cb(dev_t dev, uint64_t flag)
2201 {
2202         hermon_umap_db_priv_t   *priv;
2203         hermon_umap_db_entry_t  *umapdb;
2204         minor_t                 instance;
2205         uint64_t                value;
2206         int                     status;
2207 
2208         instance = HERMON_DEV_INSTANCE(dev);
2209         if (instance == (minor_t)-1) {
2210                 return (DDI_FAILURE);
2211         }
2212 
2213         if (flag != HERMON_ONCLOSE_FLASH_INPROGRESS) {
2214                 return (DDI_FAILURE);
2215         }
2216 
2217         /*
2218          * Grab the lock for the "userland resources database" and find
2219          * the entry corresponding to this minor number.  Once it's found,
2220          * remove the entry (in the "hdb_priv" field) that indicated the
2221          * need for further processing during Hermon's close().  Free the
2222          * entry, if appropriate.
2223          */
2224         mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2225         status = hermon_umap_db_find_nolock(instance, dev,
2226             MLNX_UMAP_PID_RSRC, &value, 0, &umapdb);
2227         if (status != DDI_SUCCESS) {
2228                 mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2229                 return (DDI_FAILURE);
2230         }
2231 
2232         priv = (hermon_umap_db_priv_t *)umapdb->hdbe_common.hdb_priv;
2233         if (priv != NULL) {
2234                 kmem_free(priv, sizeof (hermon_umap_db_priv_t));
2235                 priv = NULL;
2236         }
2237 
2238         umapdb->hdbe_common.hdb_priv = (void *)priv;
2239         mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2240         return (DDI_SUCCESS);
2241 }
2242 
2243 
2244 /*
2245  * hermon_umap_db_clear_onclose_cb()
2246  *    Context: Can be called from user or kernel context.
2247  */
2248 int
2249 hermon_umap_db_handle_onclose_cb(hermon_umap_db_priv_t *priv)
2250 {
2251         int     (*callback)(void *);
2252 
2253         ASSERT(MUTEX_HELD(&hermon_userland_rsrc_db.hdl_umapdb_lock));
2254 
2255         /*
2256          * Call the callback.
2257          *    Note: Currently there is only one callback (in "hdp_cb"), but
2258          *    in the future there may be more, depending on what other types
2259          *    of interaction there are between userland processes and the
2260          *    driver.
2261          */
2262         callback = priv->hdp_cb;
2263         return (callback(priv->hdp_arg));
2264 }