19517SBill.Taylor@Sun.COM /*
29517SBill.Taylor@Sun.COM * CDDL HEADER START
39517SBill.Taylor@Sun.COM *
49517SBill.Taylor@Sun.COM * The contents of this file are subject to the terms of the
59517SBill.Taylor@Sun.COM * Common Development and Distribution License (the "License").
69517SBill.Taylor@Sun.COM * You may not use this file except in compliance with the License.
79517SBill.Taylor@Sun.COM *
89517SBill.Taylor@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99517SBill.Taylor@Sun.COM * or http://www.opensolaris.org/os/licensing.
109517SBill.Taylor@Sun.COM * See the License for the specific language governing permissions
119517SBill.Taylor@Sun.COM * and limitations under the License.
129517SBill.Taylor@Sun.COM *
139517SBill.Taylor@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
149517SBill.Taylor@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159517SBill.Taylor@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
169517SBill.Taylor@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
179517SBill.Taylor@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
189517SBill.Taylor@Sun.COM *
199517SBill.Taylor@Sun.COM * CDDL HEADER END
209517SBill.Taylor@Sun.COM */
219517SBill.Taylor@Sun.COM
229517SBill.Taylor@Sun.COM /*
23*12965SWilliam.Taylor@Oracle.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
249517SBill.Taylor@Sun.COM */
259517SBill.Taylor@Sun.COM
269517SBill.Taylor@Sun.COM /*
279517SBill.Taylor@Sun.COM * hermon_misc.c
289517SBill.Taylor@Sun.COM * Hermon Miscellaneous routines - Address Handle, Multicast, Protection
299517SBill.Taylor@Sun.COM * Domain, and port-related operations
309517SBill.Taylor@Sun.COM *
319517SBill.Taylor@Sun.COM * Implements all the routines necessary for allocating, freeing, querying
329517SBill.Taylor@Sun.COM * and modifying Address Handles and Protection Domains. Also implements
339517SBill.Taylor@Sun.COM * all the routines necessary for adding and removing Queue Pairs to/from
349517SBill.Taylor@Sun.COM * Multicast Groups. Lastly, it implements the routines necessary for
359517SBill.Taylor@Sun.COM * port-related query and modify operations.
369517SBill.Taylor@Sun.COM */
379517SBill.Taylor@Sun.COM
389517SBill.Taylor@Sun.COM #include <sys/types.h>
399517SBill.Taylor@Sun.COM #include <sys/conf.h>
409517SBill.Taylor@Sun.COM #include <sys/ddi.h>
419517SBill.Taylor@Sun.COM #include <sys/sunddi.h>
429517SBill.Taylor@Sun.COM #include <sys/modctl.h>
439517SBill.Taylor@Sun.COM #include <sys/bitmap.h>
449517SBill.Taylor@Sun.COM #include <sys/sysmacros.h>
459517SBill.Taylor@Sun.COM
469517SBill.Taylor@Sun.COM #include <sys/ib/adapters/hermon/hermon.h>
479517SBill.Taylor@Sun.COM
4811972SBill.Taylor@Sun.COM extern int hermon_rdma_debug;
49*12965SWilliam.Taylor@Oracle.COM int hermon_fmr_verbose = 0;
509517SBill.Taylor@Sun.COM
519517SBill.Taylor@Sun.COM static int hermon_mcg_qplist_add(hermon_state_t *state, hermon_mcghdl_t mcg,
529517SBill.Taylor@Sun.COM hermon_hw_mcg_qp_list_t *mcg_qplist, hermon_qphdl_t qp, uint_t *qp_found);
539517SBill.Taylor@Sun.COM static int hermon_mcg_qplist_remove(hermon_mcghdl_t mcg,
549517SBill.Taylor@Sun.COM hermon_hw_mcg_qp_list_t *mcg_qplist, hermon_qphdl_t qp);
559517SBill.Taylor@Sun.COM static void hermon_qp_mcg_refcnt_inc(hermon_qphdl_t qp);
569517SBill.Taylor@Sun.COM static void hermon_qp_mcg_refcnt_dec(hermon_qphdl_t qp);
579517SBill.Taylor@Sun.COM static uint_t hermon_mcg_walk_mgid_hash(hermon_state_t *state,
589517SBill.Taylor@Sun.COM uint64_t start_indx, ib_gid_t mgid, uint_t *prev_indx);
599517SBill.Taylor@Sun.COM static void hermon_mcg_setup_new_hdr(hermon_mcghdl_t mcg,
609517SBill.Taylor@Sun.COM hermon_hw_mcg_t *mcg_hdr, ib_gid_t mgid, hermon_rsrc_t *mcg_rsrc);
619517SBill.Taylor@Sun.COM static int hermon_mcg_hash_list_remove(hermon_state_t *state, uint_t curr_indx,
629517SBill.Taylor@Sun.COM uint_t prev_indx, hermon_hw_mcg_t *mcg_entry);
639517SBill.Taylor@Sun.COM static int hermon_mcg_entry_invalidate(hermon_state_t *state,
649517SBill.Taylor@Sun.COM hermon_hw_mcg_t *mcg_entry, uint_t indx);
659517SBill.Taylor@Sun.COM static int hermon_mgid_is_valid(ib_gid_t gid);
669517SBill.Taylor@Sun.COM static int hermon_mlid_is_valid(ib_lid_t lid);
67*12965SWilliam.Taylor@Oracle.COM static void hermon_fmr_cleanup(hermon_fmrhdl_t pool);
689517SBill.Taylor@Sun.COM
699517SBill.Taylor@Sun.COM
709517SBill.Taylor@Sun.COM #define HERMON_MAX_DBR_PAGES_PER_USER 64
719517SBill.Taylor@Sun.COM #define HERMON_DBR_KEY(index, page) \
729517SBill.Taylor@Sun.COM (((uint64_t)index) * HERMON_MAX_DBR_PAGES_PER_USER + (page))
739517SBill.Taylor@Sun.COM
749517SBill.Taylor@Sun.COM static hermon_udbr_page_t *
hermon_dbr_new_user_page(hermon_state_t * state,uint_t index,uint_t page)759517SBill.Taylor@Sun.COM hermon_dbr_new_user_page(hermon_state_t *state, uint_t index,
769517SBill.Taylor@Sun.COM uint_t page)
779517SBill.Taylor@Sun.COM {
789517SBill.Taylor@Sun.COM hermon_udbr_page_t *pagep;
799517SBill.Taylor@Sun.COM ddi_dma_attr_t dma_attr;
809517SBill.Taylor@Sun.COM uint_t cookiecnt;
8111586SBill.Taylor@Sun.COM int status;
829517SBill.Taylor@Sun.COM hermon_umap_db_entry_t *umapdb;
83*12965SWilliam.Taylor@Oracle.COM ulong_t pagesize = PAGESIZE;
849517SBill.Taylor@Sun.COM
859517SBill.Taylor@Sun.COM pagep = kmem_alloc(sizeof (*pagep), KM_SLEEP);
869517SBill.Taylor@Sun.COM pagep->upg_index = page;
87*12965SWilliam.Taylor@Oracle.COM pagep->upg_nfree = pagesize / sizeof (hermon_dbr_t);
8811586SBill.Taylor@Sun.COM
8911586SBill.Taylor@Sun.COM /* Allocate 1 bit per dbr for free/alloc management (0 => "free") */
90*12965SWilliam.Taylor@Oracle.COM pagep->upg_free = kmem_zalloc(pagesize / sizeof (hermon_dbr_t) / 8,
9111586SBill.Taylor@Sun.COM KM_SLEEP);
92*12965SWilliam.Taylor@Oracle.COM pagep->upg_kvaddr = ddi_umem_alloc(pagesize, DDI_UMEM_SLEEP,
939517SBill.Taylor@Sun.COM &pagep->upg_umemcookie); /* not HERMON_PAGESIZE here */
949517SBill.Taylor@Sun.COM
959517SBill.Taylor@Sun.COM pagep->upg_buf = ddi_umem_iosetup(pagep->upg_umemcookie, 0,
96*12965SWilliam.Taylor@Oracle.COM pagesize, B_WRITE, 0, 0, NULL, DDI_UMEM_SLEEP);
979517SBill.Taylor@Sun.COM
989517SBill.Taylor@Sun.COM hermon_dma_attr_init(state, &dma_attr);
9911972SBill.Taylor@Sun.COM #ifdef __sparc
10011972SBill.Taylor@Sun.COM if (state->hs_cfg_profile->cp_iommu_bypass == HERMON_BINDMEM_BYPASS)
10111972SBill.Taylor@Sun.COM dma_attr.dma_attr_flags = DDI_DMA_FORCE_PHYSICAL;
10211972SBill.Taylor@Sun.COM #endif
1039517SBill.Taylor@Sun.COM status = ddi_dma_alloc_handle(state->hs_dip, &dma_attr,
1049517SBill.Taylor@Sun.COM DDI_DMA_SLEEP, NULL, &pagep->upg_dmahdl);
1059517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
1069517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon", "hermon_new_user_page: "
1079517SBill.Taylor@Sun.COM "ddi_dma_buf_bind_handle failed: %d", status);
1089517SBill.Taylor@Sun.COM return (NULL);
1099517SBill.Taylor@Sun.COM }
1109517SBill.Taylor@Sun.COM status = ddi_dma_buf_bind_handle(pagep->upg_dmahdl,
1119517SBill.Taylor@Sun.COM pagep->upg_buf, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1129517SBill.Taylor@Sun.COM DDI_DMA_SLEEP, NULL, &pagep->upg_dmacookie, &cookiecnt);
1139517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
1149517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon", "hermon_dbr_new_user_page: "
1159517SBill.Taylor@Sun.COM "ddi_dma_buf_bind_handle failed: %d", status);
1169517SBill.Taylor@Sun.COM ddi_dma_free_handle(&pagep->upg_dmahdl);
1179517SBill.Taylor@Sun.COM return (NULL);
1189517SBill.Taylor@Sun.COM }
1199517SBill.Taylor@Sun.COM ASSERT(cookiecnt == 1);
1209517SBill.Taylor@Sun.COM
1219517SBill.Taylor@Sun.COM /* create db entry for mmap */
1229517SBill.Taylor@Sun.COM umapdb = hermon_umap_db_alloc(state->hs_instance,
1239517SBill.Taylor@Sun.COM HERMON_DBR_KEY(index, page), MLNX_UMAP_DBRMEM_RSRC,
1249517SBill.Taylor@Sun.COM (uint64_t)(uintptr_t)pagep);
1259517SBill.Taylor@Sun.COM hermon_umap_db_add(umapdb);
1269517SBill.Taylor@Sun.COM return (pagep);
1279517SBill.Taylor@Sun.COM }
1289517SBill.Taylor@Sun.COM
1299517SBill.Taylor@Sun.COM
1309517SBill.Taylor@Sun.COM /*ARGSUSED*/
1319517SBill.Taylor@Sun.COM static int
hermon_user_dbr_alloc(hermon_state_t * state,uint_t index,ddi_acc_handle_t * acchdl,hermon_dbr_t ** vdbr,uint64_t * pdbr,uint64_t * mapoffset)1329517SBill.Taylor@Sun.COM hermon_user_dbr_alloc(hermon_state_t *state, uint_t index,
1339517SBill.Taylor@Sun.COM ddi_acc_handle_t *acchdl, hermon_dbr_t **vdbr, uint64_t *pdbr,
1349517SBill.Taylor@Sun.COM uint64_t *mapoffset)
1359517SBill.Taylor@Sun.COM {
1369517SBill.Taylor@Sun.COM hermon_user_dbr_t *udbr;
1379517SBill.Taylor@Sun.COM hermon_udbr_page_t *pagep;
1389517SBill.Taylor@Sun.COM uint_t next_page;
13911586SBill.Taylor@Sun.COM int dbr_index;
14011586SBill.Taylor@Sun.COM int i1, i2, i3, last;
14111586SBill.Taylor@Sun.COM uint64_t u64, mask;
1429517SBill.Taylor@Sun.COM
1439517SBill.Taylor@Sun.COM mutex_enter(&state->hs_dbr_lock);
1449517SBill.Taylor@Sun.COM for (udbr = state->hs_user_dbr; udbr != NULL; udbr = udbr->udbr_link)
1459517SBill.Taylor@Sun.COM if (udbr->udbr_index == index)
1469517SBill.Taylor@Sun.COM break;
1479517SBill.Taylor@Sun.COM if (udbr == NULL) {
1489517SBill.Taylor@Sun.COM udbr = kmem_alloc(sizeof (*udbr), KM_SLEEP);
1499517SBill.Taylor@Sun.COM udbr->udbr_link = state->hs_user_dbr;
1509517SBill.Taylor@Sun.COM state->hs_user_dbr = udbr;
1519517SBill.Taylor@Sun.COM udbr->udbr_index = index;
1529517SBill.Taylor@Sun.COM udbr->udbr_pagep = NULL;
1539517SBill.Taylor@Sun.COM }
1549517SBill.Taylor@Sun.COM pagep = udbr->udbr_pagep;
1559517SBill.Taylor@Sun.COM next_page = (pagep == NULL) ? 0 : (pagep->upg_index + 1);
1569517SBill.Taylor@Sun.COM while (pagep != NULL)
1579517SBill.Taylor@Sun.COM if (pagep->upg_nfree > 0)
1589517SBill.Taylor@Sun.COM break;
1599517SBill.Taylor@Sun.COM else
1609517SBill.Taylor@Sun.COM pagep = pagep->upg_link;
1619517SBill.Taylor@Sun.COM if (pagep == NULL) {
1629517SBill.Taylor@Sun.COM pagep = hermon_dbr_new_user_page(state, index, next_page);
1639517SBill.Taylor@Sun.COM if (pagep == NULL) {
1649517SBill.Taylor@Sun.COM mutex_exit(&state->hs_dbr_lock);
1659517SBill.Taylor@Sun.COM return (DDI_FAILURE);
1669517SBill.Taylor@Sun.COM }
1679517SBill.Taylor@Sun.COM pagep->upg_link = udbr->udbr_pagep;
1689517SBill.Taylor@Sun.COM udbr->udbr_pagep = pagep;
1699517SBill.Taylor@Sun.COM }
17011586SBill.Taylor@Sun.COM
17111586SBill.Taylor@Sun.COM /* Since nfree > 0, we're assured the loops below will succeed */
17211586SBill.Taylor@Sun.COM
17311586SBill.Taylor@Sun.COM /* First, find a 64-bit (not ~0) that has a free dbr */
17411586SBill.Taylor@Sun.COM last = PAGESIZE / sizeof (uint64_t) / 64;
17511586SBill.Taylor@Sun.COM mask = ~0ull;
17611586SBill.Taylor@Sun.COM for (i1 = 0; i1 < last; i1++)
17711586SBill.Taylor@Sun.COM if ((pagep->upg_free[i1] & mask) != mask)
17811586SBill.Taylor@Sun.COM break;
17911586SBill.Taylor@Sun.COM u64 = pagep->upg_free[i1];
18011586SBill.Taylor@Sun.COM
18111586SBill.Taylor@Sun.COM /* Second, find a byte (not 0xff) that has a free dbr */
18211586SBill.Taylor@Sun.COM last = sizeof (uint64_t) / sizeof (uint8_t);
18311586SBill.Taylor@Sun.COM for (i2 = 0, mask = 0xff; i2 < last; i2++, mask <<= 8)
18411586SBill.Taylor@Sun.COM if ((u64 & mask) != mask)
18511586SBill.Taylor@Sun.COM break;
18611586SBill.Taylor@Sun.COM
18711586SBill.Taylor@Sun.COM /* Third, find a bit that is free (0) */
18811586SBill.Taylor@Sun.COM for (i3 = 0; i3 < sizeof (uint64_t) / sizeof (uint8_t); i3++)
18911586SBill.Taylor@Sun.COM if ((u64 & (1ul << (i3 + 8 * i2))) == 0)
19011586SBill.Taylor@Sun.COM break;
19111586SBill.Taylor@Sun.COM
19211586SBill.Taylor@Sun.COM /* Mark it as allocated */
19311586SBill.Taylor@Sun.COM pagep->upg_free[i1] |= (1ul << (i3 + 8 * i2));
19411586SBill.Taylor@Sun.COM
19511586SBill.Taylor@Sun.COM dbr_index = ((i1 * sizeof (uint64_t)) + i2) * sizeof (uint64_t) + i3;
1969517SBill.Taylor@Sun.COM pagep->upg_nfree--;
19711586SBill.Taylor@Sun.COM ((uint64_t *)(void *)pagep->upg_kvaddr)[dbr_index] = 0; /* clear dbr */
1989517SBill.Taylor@Sun.COM *mapoffset = ((HERMON_DBR_KEY(index, pagep->upg_index) <<
1999517SBill.Taylor@Sun.COM MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_DBRMEM_RSRC) << PAGESHIFT;
20011586SBill.Taylor@Sun.COM *vdbr = (hermon_dbr_t *)((uint64_t *)(void *)pagep->upg_kvaddr +
20111586SBill.Taylor@Sun.COM dbr_index);
20211586SBill.Taylor@Sun.COM *pdbr = pagep->upg_dmacookie.dmac_laddress + dbr_index *
20311586SBill.Taylor@Sun.COM sizeof (uint64_t);
2049517SBill.Taylor@Sun.COM
2059517SBill.Taylor@Sun.COM mutex_exit(&state->hs_dbr_lock);
2069517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
2079517SBill.Taylor@Sun.COM }
2089517SBill.Taylor@Sun.COM
2099517SBill.Taylor@Sun.COM static void
hermon_user_dbr_free(hermon_state_t * state,uint_t index,hermon_dbr_t * record)2109517SBill.Taylor@Sun.COM hermon_user_dbr_free(hermon_state_t *state, uint_t index, hermon_dbr_t *record)
2119517SBill.Taylor@Sun.COM {
2129517SBill.Taylor@Sun.COM hermon_user_dbr_t *udbr;
2139517SBill.Taylor@Sun.COM hermon_udbr_page_t *pagep;
2149517SBill.Taylor@Sun.COM caddr_t kvaddr;
2159517SBill.Taylor@Sun.COM uint_t dbr_index;
2169517SBill.Taylor@Sun.COM uint_t max_free = PAGESIZE / sizeof (hermon_dbr_t);
21711586SBill.Taylor@Sun.COM int i1, i2;
2189517SBill.Taylor@Sun.COM
2199517SBill.Taylor@Sun.COM dbr_index = (uintptr_t)record & PAGEOFFSET; /* offset (not yet index) */
2209517SBill.Taylor@Sun.COM kvaddr = (caddr_t)record - dbr_index;
2219517SBill.Taylor@Sun.COM dbr_index /= sizeof (hermon_dbr_t); /* now it's the index */
2229517SBill.Taylor@Sun.COM
2239517SBill.Taylor@Sun.COM mutex_enter(&state->hs_dbr_lock);
2249517SBill.Taylor@Sun.COM for (udbr = state->hs_user_dbr; udbr != NULL; udbr = udbr->udbr_link)
2259517SBill.Taylor@Sun.COM if (udbr->udbr_index == index)
2269517SBill.Taylor@Sun.COM break;
2279517SBill.Taylor@Sun.COM if (udbr == NULL) {
2289517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon", "free user dbr: udbr struct not "
2299517SBill.Taylor@Sun.COM "found for index %x", index);
2309517SBill.Taylor@Sun.COM mutex_exit(&state->hs_dbr_lock);
2319517SBill.Taylor@Sun.COM return;
2329517SBill.Taylor@Sun.COM }
2339517SBill.Taylor@Sun.COM for (pagep = udbr->udbr_pagep; pagep != NULL; pagep = pagep->upg_link)
2349517SBill.Taylor@Sun.COM if (pagep->upg_kvaddr == kvaddr)
2359517SBill.Taylor@Sun.COM break;
2369517SBill.Taylor@Sun.COM if (pagep == NULL) {
2379517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon", "free user dbr: pagep struct not"
2389517SBill.Taylor@Sun.COM " found for index %x, kvaddr %p, DBR index %x",
2399517SBill.Taylor@Sun.COM index, kvaddr, dbr_index);
2409517SBill.Taylor@Sun.COM mutex_exit(&state->hs_dbr_lock);
2419517SBill.Taylor@Sun.COM return;
2429517SBill.Taylor@Sun.COM }
2439517SBill.Taylor@Sun.COM if (pagep->upg_nfree >= max_free) {
2449517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon", "free user dbr: overflow: "
2459517SBill.Taylor@Sun.COM "UCE index %x, DBR index %x", index, dbr_index);
2469517SBill.Taylor@Sun.COM mutex_exit(&state->hs_dbr_lock);
2479517SBill.Taylor@Sun.COM return;
2489517SBill.Taylor@Sun.COM }
2499517SBill.Taylor@Sun.COM ASSERT(dbr_index < max_free);
25011586SBill.Taylor@Sun.COM i1 = dbr_index / 64;
25111586SBill.Taylor@Sun.COM i2 = dbr_index % 64;
25211586SBill.Taylor@Sun.COM ASSERT((pagep->upg_free[i1] & (1ul << i2)) == (1ul << i2));
25311586SBill.Taylor@Sun.COM pagep->upg_free[i1] &= ~(1ul << i2);
2549517SBill.Taylor@Sun.COM pagep->upg_nfree++;
2559517SBill.Taylor@Sun.COM mutex_exit(&state->hs_dbr_lock);
2569517SBill.Taylor@Sun.COM }
2579517SBill.Taylor@Sun.COM
2589517SBill.Taylor@Sun.COM /*
2599517SBill.Taylor@Sun.COM * hermon_dbr_page_alloc()
2609517SBill.Taylor@Sun.COM * first page allocation - called from attach or open
2619517SBill.Taylor@Sun.COM * in this case, we want exactly one page per call, and aligned on a
2629517SBill.Taylor@Sun.COM * page - and may need to be mapped to the user for access
2639517SBill.Taylor@Sun.COM */
2649517SBill.Taylor@Sun.COM int
hermon_dbr_page_alloc(hermon_state_t * state,hermon_dbr_info_t ** dinfo)2659517SBill.Taylor@Sun.COM hermon_dbr_page_alloc(hermon_state_t *state, hermon_dbr_info_t **dinfo)
2669517SBill.Taylor@Sun.COM {
2679517SBill.Taylor@Sun.COM int status;
2689517SBill.Taylor@Sun.COM ddi_dma_handle_t dma_hdl;
2699517SBill.Taylor@Sun.COM ddi_acc_handle_t acc_hdl;
2709517SBill.Taylor@Sun.COM ddi_dma_attr_t dma_attr;
2719517SBill.Taylor@Sun.COM ddi_dma_cookie_t cookie;
2729517SBill.Taylor@Sun.COM uint_t cookie_cnt;
2739517SBill.Taylor@Sun.COM int i;
2749517SBill.Taylor@Sun.COM hermon_dbr_info_t *info;
27510027SGiri.Adari@Sun.COM caddr_t dmaaddr;
2769517SBill.Taylor@Sun.COM uint64_t dmalen;
277*12965SWilliam.Taylor@Oracle.COM ulong_t pagesize = PAGESIZE;
2789517SBill.Taylor@Sun.COM
2799517SBill.Taylor@Sun.COM info = kmem_zalloc(sizeof (hermon_dbr_info_t), KM_SLEEP);
2809517SBill.Taylor@Sun.COM
2819517SBill.Taylor@Sun.COM /*
2829517SBill.Taylor@Sun.COM * Initialize many of the default DMA attributes. Then set additional
2839517SBill.Taylor@Sun.COM * alignment restrictions if necessary for the dbr memory, meaning
2849517SBill.Taylor@Sun.COM * page aligned. Also use the configured value for IOMMU bypass
2859517SBill.Taylor@Sun.COM */
2869517SBill.Taylor@Sun.COM hermon_dma_attr_init(state, &dma_attr);
287*12965SWilliam.Taylor@Oracle.COM dma_attr.dma_attr_align = pagesize;
2889517SBill.Taylor@Sun.COM dma_attr.dma_attr_sgllen = 1; /* make sure only one cookie */
28911972SBill.Taylor@Sun.COM #ifdef __sparc
29011972SBill.Taylor@Sun.COM if (state->hs_cfg_profile->cp_iommu_bypass == HERMON_BINDMEM_BYPASS)
29111972SBill.Taylor@Sun.COM dma_attr.dma_attr_flags = DDI_DMA_FORCE_PHYSICAL;
29211972SBill.Taylor@Sun.COM #endif
2939517SBill.Taylor@Sun.COM
2949517SBill.Taylor@Sun.COM status = ddi_dma_alloc_handle(state->hs_dip, &dma_attr,
2959517SBill.Taylor@Sun.COM DDI_DMA_SLEEP, NULL, &dma_hdl);
2969517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
2979517SBill.Taylor@Sun.COM kmem_free((void *)info, sizeof (hermon_dbr_info_t));
2989517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "dbr DMA handle alloc failed\n");
2999517SBill.Taylor@Sun.COM return (DDI_FAILURE);
3009517SBill.Taylor@Sun.COM }
3019517SBill.Taylor@Sun.COM
302*12965SWilliam.Taylor@Oracle.COM status = ddi_dma_mem_alloc(dma_hdl, pagesize,
3039517SBill.Taylor@Sun.COM &state->hs_reg_accattr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
30410027SGiri.Adari@Sun.COM NULL, &dmaaddr, (size_t *)&dmalen, &acc_hdl);
3059517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
3069517SBill.Taylor@Sun.COM ddi_dma_free_handle(&dma_hdl);
3079517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "dbr DMA mem alloc failed(status %d)", status);
3089517SBill.Taylor@Sun.COM kmem_free((void *)info, sizeof (hermon_dbr_info_t));
3099517SBill.Taylor@Sun.COM return (DDI_FAILURE);
3109517SBill.Taylor@Sun.COM }
3119517SBill.Taylor@Sun.COM
3129517SBill.Taylor@Sun.COM /* this memory won't be IB registered, so do the bind here */
3139517SBill.Taylor@Sun.COM status = ddi_dma_addr_bind_handle(dma_hdl, NULL,
31410027SGiri.Adari@Sun.COM dmaaddr, (size_t)dmalen, DDI_DMA_RDWR |
3159517SBill.Taylor@Sun.COM DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &cookie, &cookie_cnt);
3169517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
3179517SBill.Taylor@Sun.COM ddi_dma_mem_free(&acc_hdl);
3189517SBill.Taylor@Sun.COM ddi_dma_free_handle(&dma_hdl);
3199517SBill.Taylor@Sun.COM kmem_free((void *)info, sizeof (hermon_dbr_info_t));
3209517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "dbr DMA bind handle failed (status %d)",
3219517SBill.Taylor@Sun.COM status);
3229517SBill.Taylor@Sun.COM return (DDI_FAILURE);
3239517SBill.Taylor@Sun.COM }
3249517SBill.Taylor@Sun.COM *dinfo = info; /* Pass back the pointer */
3259517SBill.Taylor@Sun.COM
3269517SBill.Taylor@Sun.COM /* init the info structure with returned info */
3279517SBill.Taylor@Sun.COM info->dbr_dmahdl = dma_hdl;
3289517SBill.Taylor@Sun.COM info->dbr_acchdl = acc_hdl;
32910027SGiri.Adari@Sun.COM info->dbr_page = (hermon_dbr_t *)(void *)dmaaddr;
33010027SGiri.Adari@Sun.COM info->dbr_link = NULL;
3319517SBill.Taylor@Sun.COM /* extract the phys addr from the cookie */
3329517SBill.Taylor@Sun.COM info->dbr_paddr = cookie.dmac_laddress;
33310027SGiri.Adari@Sun.COM info->dbr_firstfree = 0;
33410027SGiri.Adari@Sun.COM info->dbr_nfree = HERMON_NUM_DBR_PER_PAGE;
3359517SBill.Taylor@Sun.COM /* link all DBrs onto the free list */
3369517SBill.Taylor@Sun.COM for (i = 0; i < HERMON_NUM_DBR_PER_PAGE; i++) {
33710027SGiri.Adari@Sun.COM info->dbr_page[i] = i + 1;
3389517SBill.Taylor@Sun.COM }
3399517SBill.Taylor@Sun.COM
3409517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
3419517SBill.Taylor@Sun.COM }
3429517SBill.Taylor@Sun.COM
3439517SBill.Taylor@Sun.COM
3449517SBill.Taylor@Sun.COM /*
3459517SBill.Taylor@Sun.COM * hermon_dbr_alloc()
3469517SBill.Taylor@Sun.COM * DBr record allocation - called from alloc cq/qp/srq
3479517SBill.Taylor@Sun.COM * will check for available dbrs in current
3489517SBill.Taylor@Sun.COM * page - if needed it will allocate another and link them
3499517SBill.Taylor@Sun.COM */
3509517SBill.Taylor@Sun.COM
3519517SBill.Taylor@Sun.COM int
hermon_dbr_alloc(hermon_state_t * state,uint_t index,ddi_acc_handle_t * acchdl,hermon_dbr_t ** vdbr,uint64_t * pdbr,uint64_t * mapoffset)3529517SBill.Taylor@Sun.COM hermon_dbr_alloc(hermon_state_t *state, uint_t index, ddi_acc_handle_t *acchdl,
3539517SBill.Taylor@Sun.COM hermon_dbr_t **vdbr, uint64_t *pdbr, uint64_t *mapoffset)
3549517SBill.Taylor@Sun.COM {
3559517SBill.Taylor@Sun.COM hermon_dbr_t *record = NULL;
35610027SGiri.Adari@Sun.COM hermon_dbr_info_t *info = NULL;
35710027SGiri.Adari@Sun.COM uint32_t idx;
3589517SBill.Taylor@Sun.COM int status;
3599517SBill.Taylor@Sun.COM
3609517SBill.Taylor@Sun.COM if (index != state->hs_kernel_uar_index)
3619517SBill.Taylor@Sun.COM return (hermon_user_dbr_alloc(state, index, acchdl, vdbr, pdbr,
3629517SBill.Taylor@Sun.COM mapoffset));
3639517SBill.Taylor@Sun.COM
3649517SBill.Taylor@Sun.COM mutex_enter(&state->hs_dbr_lock);
36510027SGiri.Adari@Sun.COM for (info = state->hs_kern_dbr; info != NULL; info = info->dbr_link)
36610027SGiri.Adari@Sun.COM if (info->dbr_nfree != 0)
36710027SGiri.Adari@Sun.COM break; /* found a page w/ one available */
36810027SGiri.Adari@Sun.COM
36910027SGiri.Adari@Sun.COM if (info == NULL) { /* did NOT find a page with one available */
37010027SGiri.Adari@Sun.COM status = hermon_dbr_page_alloc(state, &info);
3719517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
3729517SBill.Taylor@Sun.COM /* do error handling */
3739517SBill.Taylor@Sun.COM mutex_exit(&state->hs_dbr_lock);
3749517SBill.Taylor@Sun.COM return (DDI_FAILURE);
3759517SBill.Taylor@Sun.COM }
3769517SBill.Taylor@Sun.COM /* got a new page, so link it in. */
37710027SGiri.Adari@Sun.COM info->dbr_link = state->hs_kern_dbr;
37810027SGiri.Adari@Sun.COM state->hs_kern_dbr = info;
3799517SBill.Taylor@Sun.COM }
38010027SGiri.Adari@Sun.COM idx = info->dbr_firstfree;
38110027SGiri.Adari@Sun.COM record = info->dbr_page + idx;
38210027SGiri.Adari@Sun.COM info->dbr_firstfree = *record;
38310027SGiri.Adari@Sun.COM info->dbr_nfree--;
3849517SBill.Taylor@Sun.COM *record = 0;
3859517SBill.Taylor@Sun.COM
38610027SGiri.Adari@Sun.COM *acchdl = info->dbr_acchdl;
3879517SBill.Taylor@Sun.COM *vdbr = record;
38810027SGiri.Adari@Sun.COM *pdbr = info->dbr_paddr + idx * sizeof (hermon_dbr_t);
3899517SBill.Taylor@Sun.COM mutex_exit(&state->hs_dbr_lock);
3909517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
3919517SBill.Taylor@Sun.COM }
3929517SBill.Taylor@Sun.COM
3939517SBill.Taylor@Sun.COM /*
3949517SBill.Taylor@Sun.COM * hermon_dbr_free()
3959517SBill.Taylor@Sun.COM * DBr record deallocation - called from free cq/qp
3969517SBill.Taylor@Sun.COM * will update the counter in the header, and invalidate
3979517SBill.Taylor@Sun.COM * the dbr, but will NEVER free pages of dbrs - small
3989517SBill.Taylor@Sun.COM * price to pay, but userland access never will anyway
3999517SBill.Taylor@Sun.COM */
4009517SBill.Taylor@Sun.COM void
hermon_dbr_free(hermon_state_t * state,uint_t indx,hermon_dbr_t * record)4019517SBill.Taylor@Sun.COM hermon_dbr_free(hermon_state_t *state, uint_t indx, hermon_dbr_t *record)
4029517SBill.Taylor@Sun.COM {
40310027SGiri.Adari@Sun.COM hermon_dbr_t *page;
40410027SGiri.Adari@Sun.COM hermon_dbr_info_t *info;
4059517SBill.Taylor@Sun.COM
4069517SBill.Taylor@Sun.COM if (indx != state->hs_kernel_uar_index) {
4079517SBill.Taylor@Sun.COM hermon_user_dbr_free(state, indx, record);
4089517SBill.Taylor@Sun.COM return;
4099517SBill.Taylor@Sun.COM }
41010027SGiri.Adari@Sun.COM page = (hermon_dbr_t *)(uintptr_t)((uintptr_t)record & PAGEMASK);
4119517SBill.Taylor@Sun.COM mutex_enter(&state->hs_dbr_lock);
41210027SGiri.Adari@Sun.COM for (info = state->hs_kern_dbr; info != NULL; info = info->dbr_link)
41310027SGiri.Adari@Sun.COM if (info->dbr_page == page)
41410027SGiri.Adari@Sun.COM break;
41510027SGiri.Adari@Sun.COM ASSERT(info != NULL);
41610027SGiri.Adari@Sun.COM *record = info->dbr_firstfree;
41710027SGiri.Adari@Sun.COM info->dbr_firstfree = record - info->dbr_page;
41810027SGiri.Adari@Sun.COM info->dbr_nfree++;
4199517SBill.Taylor@Sun.COM mutex_exit(&state->hs_dbr_lock);
4209517SBill.Taylor@Sun.COM }
4219517SBill.Taylor@Sun.COM
4229517SBill.Taylor@Sun.COM /*
4239517SBill.Taylor@Sun.COM * hermon_dbr_kern_free()
4249517SBill.Taylor@Sun.COM * Context: Can be called only from detach context.
4259517SBill.Taylor@Sun.COM *
4269517SBill.Taylor@Sun.COM * Free all kernel dbr pages. This includes the freeing of all the dma
4279517SBill.Taylor@Sun.COM * resources acquired during the allocation of the pages.
4289517SBill.Taylor@Sun.COM *
4299517SBill.Taylor@Sun.COM * Also, free all the user dbr pages.
4309517SBill.Taylor@Sun.COM */
4319517SBill.Taylor@Sun.COM void
hermon_dbr_kern_free(hermon_state_t * state)4329517SBill.Taylor@Sun.COM hermon_dbr_kern_free(hermon_state_t *state)
4339517SBill.Taylor@Sun.COM {
43410027SGiri.Adari@Sun.COM hermon_dbr_info_t *info, *link;
4359517SBill.Taylor@Sun.COM hermon_user_dbr_t *udbr, *next;
4369517SBill.Taylor@Sun.COM hermon_udbr_page_t *pagep, *nextp;
4379517SBill.Taylor@Sun.COM hermon_umap_db_entry_t *umapdb;
4389517SBill.Taylor@Sun.COM int instance, status;
4399517SBill.Taylor@Sun.COM uint64_t value;
4409517SBill.Taylor@Sun.COM extern hermon_umap_db_t hermon_userland_rsrc_db;
4419517SBill.Taylor@Sun.COM
4429517SBill.Taylor@Sun.COM mutex_enter(&state->hs_dbr_lock);
44310027SGiri.Adari@Sun.COM for (info = state->hs_kern_dbr; info != NULL; info = link) {
44410027SGiri.Adari@Sun.COM (void) ddi_dma_unbind_handle(info->dbr_dmahdl);
44510027SGiri.Adari@Sun.COM ddi_dma_mem_free(&info->dbr_acchdl); /* free page */
44610027SGiri.Adari@Sun.COM ddi_dma_free_handle(&info->dbr_dmahdl);
44710027SGiri.Adari@Sun.COM link = info->dbr_link;
44810027SGiri.Adari@Sun.COM kmem_free(info, sizeof (hermon_dbr_info_t));
4499517SBill.Taylor@Sun.COM }
4509517SBill.Taylor@Sun.COM
4519517SBill.Taylor@Sun.COM udbr = state->hs_user_dbr;
4529517SBill.Taylor@Sun.COM instance = state->hs_instance;
4539517SBill.Taylor@Sun.COM mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
4549517SBill.Taylor@Sun.COM while (udbr != NULL) {
4559517SBill.Taylor@Sun.COM pagep = udbr->udbr_pagep;
4569517SBill.Taylor@Sun.COM while (pagep != NULL) {
4579517SBill.Taylor@Sun.COM /* probably need to remove "db" */
4589517SBill.Taylor@Sun.COM (void) ddi_dma_unbind_handle(pagep->upg_dmahdl);
4599517SBill.Taylor@Sun.COM ddi_dma_free_handle(&pagep->upg_dmahdl);
4609517SBill.Taylor@Sun.COM freerbuf(pagep->upg_buf);
4619517SBill.Taylor@Sun.COM ddi_umem_free(pagep->upg_umemcookie);
4629517SBill.Taylor@Sun.COM status = hermon_umap_db_find_nolock(instance,
4639517SBill.Taylor@Sun.COM HERMON_DBR_KEY(udbr->udbr_index,
4649517SBill.Taylor@Sun.COM pagep->upg_index), MLNX_UMAP_DBRMEM_RSRC,
4659517SBill.Taylor@Sun.COM &value, HERMON_UMAP_DB_REMOVE, &umapdb);
4669517SBill.Taylor@Sun.COM if (status == DDI_SUCCESS)
4679517SBill.Taylor@Sun.COM hermon_umap_db_free(umapdb);
46811586SBill.Taylor@Sun.COM kmem_free(pagep->upg_free,
46911586SBill.Taylor@Sun.COM PAGESIZE / sizeof (hermon_dbr_t) / 8);
4709517SBill.Taylor@Sun.COM nextp = pagep->upg_link;
4719517SBill.Taylor@Sun.COM kmem_free(pagep, sizeof (*pagep));
4729517SBill.Taylor@Sun.COM pagep = nextp;
4739517SBill.Taylor@Sun.COM }
4749517SBill.Taylor@Sun.COM next = udbr->udbr_link;
4759517SBill.Taylor@Sun.COM kmem_free(udbr, sizeof (*udbr));
4769517SBill.Taylor@Sun.COM udbr = next;
4779517SBill.Taylor@Sun.COM }
4789517SBill.Taylor@Sun.COM mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
4799517SBill.Taylor@Sun.COM mutex_exit(&state->hs_dbr_lock);
4809517SBill.Taylor@Sun.COM }
4819517SBill.Taylor@Sun.COM
4829517SBill.Taylor@Sun.COM /*
4839517SBill.Taylor@Sun.COM * hermon_ah_alloc()
4849517SBill.Taylor@Sun.COM * Context: Can be called only from user or kernel context.
4859517SBill.Taylor@Sun.COM */
4869517SBill.Taylor@Sun.COM int
hermon_ah_alloc(hermon_state_t * state,hermon_pdhdl_t pd,ibt_adds_vect_t * attr_p,hermon_ahhdl_t * ahhdl,uint_t sleepflag)4879517SBill.Taylor@Sun.COM hermon_ah_alloc(hermon_state_t *state, hermon_pdhdl_t pd,
4889517SBill.Taylor@Sun.COM ibt_adds_vect_t *attr_p, hermon_ahhdl_t *ahhdl, uint_t sleepflag)
4899517SBill.Taylor@Sun.COM {
4909517SBill.Taylor@Sun.COM hermon_rsrc_t *rsrc;
4919517SBill.Taylor@Sun.COM hermon_hw_udav_t *udav;
4929517SBill.Taylor@Sun.COM hermon_ahhdl_t ah;
4939517SBill.Taylor@Sun.COM int status;
4949517SBill.Taylor@Sun.COM
4959517SBill.Taylor@Sun.COM /*
4969517SBill.Taylor@Sun.COM * Someday maybe the "ibt_adds_vect_t *attr_p" will be NULL to
4979517SBill.Taylor@Sun.COM * indicate that we wish to allocate an "invalid" (i.e. empty)
4989517SBill.Taylor@Sun.COM * address handle XXX
4999517SBill.Taylor@Sun.COM */
5009517SBill.Taylor@Sun.COM
5019517SBill.Taylor@Sun.COM /* Validate that specified port number is legal */
5029517SBill.Taylor@Sun.COM if (!hermon_portnum_is_valid(state, attr_p->av_port_num)) {
5039517SBill.Taylor@Sun.COM return (IBT_HCA_PORT_INVALID);
5049517SBill.Taylor@Sun.COM }
5059517SBill.Taylor@Sun.COM
5069517SBill.Taylor@Sun.COM /*
5079517SBill.Taylor@Sun.COM * Allocate the software structure for tracking the address handle
5089517SBill.Taylor@Sun.COM * (i.e. the Hermon Address Handle struct).
5099517SBill.Taylor@Sun.COM */
5109517SBill.Taylor@Sun.COM status = hermon_rsrc_alloc(state, HERMON_AHHDL, 1, sleepflag, &rsrc);
5119517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
5129517SBill.Taylor@Sun.COM return (IBT_INSUFF_RESOURCE);
5139517SBill.Taylor@Sun.COM }
5149517SBill.Taylor@Sun.COM ah = (hermon_ahhdl_t)rsrc->hr_addr;
5159517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ah))
5169517SBill.Taylor@Sun.COM
5179517SBill.Taylor@Sun.COM /* Increment the reference count on the protection domain (PD) */
5189517SBill.Taylor@Sun.COM hermon_pd_refcnt_inc(pd);
5199517SBill.Taylor@Sun.COM
5209517SBill.Taylor@Sun.COM udav = (hermon_hw_udav_t *)kmem_zalloc(sizeof (hermon_hw_udav_t),
5219517SBill.Taylor@Sun.COM KM_SLEEP);
5229517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*udav))
5239517SBill.Taylor@Sun.COM
5249517SBill.Taylor@Sun.COM /*
5259517SBill.Taylor@Sun.COM * Fill in the UDAV data. We first zero out the UDAV, then populate
5269517SBill.Taylor@Sun.COM * it by then calling hermon_set_addr_path() to fill in the common
5279517SBill.Taylor@Sun.COM * portions that can be pulled from the "ibt_adds_vect_t" passed in
5289517SBill.Taylor@Sun.COM */
5299517SBill.Taylor@Sun.COM status = hermon_set_addr_path(state, attr_p,
5309517SBill.Taylor@Sun.COM (hermon_hw_addr_path_t *)udav, HERMON_ADDRPATH_UDAV);
5319517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
5329517SBill.Taylor@Sun.COM hermon_pd_refcnt_dec(pd);
5339517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &rsrc);
5349517SBill.Taylor@Sun.COM return (status);
5359517SBill.Taylor@Sun.COM }
5369517SBill.Taylor@Sun.COM udav->pd = pd->pd_pdnum;
5379517SBill.Taylor@Sun.COM udav->sl = attr_p->av_srvl;
5389517SBill.Taylor@Sun.COM
5399517SBill.Taylor@Sun.COM /*
5409517SBill.Taylor@Sun.COM * Fill in the rest of the Hermon Address Handle struct.
5419517SBill.Taylor@Sun.COM *
5429517SBill.Taylor@Sun.COM * NOTE: We are saving away a copy of the "av_dgid.gid_guid" field
5439517SBill.Taylor@Sun.COM * here because we may need to return it later to the IBTF (as a
5449517SBill.Taylor@Sun.COM * result of a subsequent query operation). Unlike the other UDAV
5459517SBill.Taylor@Sun.COM * parameters, the value of "av_dgid.gid_guid" is not always preserved.
5469517SBill.Taylor@Sun.COM * The reason for this is described in hermon_set_addr_path().
5479517SBill.Taylor@Sun.COM */
5489517SBill.Taylor@Sun.COM ah->ah_rsrcp = rsrc;
5499517SBill.Taylor@Sun.COM ah->ah_pdhdl = pd;
5509517SBill.Taylor@Sun.COM ah->ah_udav = udav;
5519517SBill.Taylor@Sun.COM ah->ah_save_guid = attr_p->av_dgid.gid_guid;
5529517SBill.Taylor@Sun.COM *ahhdl = ah;
5539517SBill.Taylor@Sun.COM
5549517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
5559517SBill.Taylor@Sun.COM }
5569517SBill.Taylor@Sun.COM
5579517SBill.Taylor@Sun.COM
5589517SBill.Taylor@Sun.COM /*
5599517SBill.Taylor@Sun.COM * hermon_ah_free()
5609517SBill.Taylor@Sun.COM * Context: Can be called only from user or kernel context.
5619517SBill.Taylor@Sun.COM */
5629517SBill.Taylor@Sun.COM /* ARGSUSED */
5639517SBill.Taylor@Sun.COM int
hermon_ah_free(hermon_state_t * state,hermon_ahhdl_t * ahhdl,uint_t sleepflag)5649517SBill.Taylor@Sun.COM hermon_ah_free(hermon_state_t *state, hermon_ahhdl_t *ahhdl, uint_t sleepflag)
5659517SBill.Taylor@Sun.COM {
5669517SBill.Taylor@Sun.COM hermon_rsrc_t *rsrc;
5679517SBill.Taylor@Sun.COM hermon_pdhdl_t pd;
5689517SBill.Taylor@Sun.COM hermon_ahhdl_t ah;
5699517SBill.Taylor@Sun.COM
5709517SBill.Taylor@Sun.COM /*
5719517SBill.Taylor@Sun.COM * Pull all the necessary information from the Hermon Address Handle
5729517SBill.Taylor@Sun.COM * struct. This is necessary here because the resource for the
5739517SBill.Taylor@Sun.COM * AH is going to be freed up as part of this operation.
5749517SBill.Taylor@Sun.COM */
5759517SBill.Taylor@Sun.COM ah = *ahhdl;
5769517SBill.Taylor@Sun.COM mutex_enter(&ah->ah_lock);
5779517SBill.Taylor@Sun.COM rsrc = ah->ah_rsrcp;
5789517SBill.Taylor@Sun.COM pd = ah->ah_pdhdl;
5799517SBill.Taylor@Sun.COM mutex_exit(&ah->ah_lock);
5809517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ah))
5819517SBill.Taylor@Sun.COM
5829517SBill.Taylor@Sun.COM /* Free the UDAV memory */
5839517SBill.Taylor@Sun.COM kmem_free(ah->ah_udav, sizeof (hermon_hw_udav_t));
5849517SBill.Taylor@Sun.COM
5859517SBill.Taylor@Sun.COM /* Decrement the reference count on the protection domain (PD) */
5869517SBill.Taylor@Sun.COM hermon_pd_refcnt_dec(pd);
5879517SBill.Taylor@Sun.COM
5889517SBill.Taylor@Sun.COM /* Free the Hermon Address Handle structure */
5899517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &rsrc);
5909517SBill.Taylor@Sun.COM
5919517SBill.Taylor@Sun.COM /* Set the ahhdl pointer to NULL and return success */
5929517SBill.Taylor@Sun.COM *ahhdl = NULL;
5939517SBill.Taylor@Sun.COM
5949517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
5959517SBill.Taylor@Sun.COM }
5969517SBill.Taylor@Sun.COM
5979517SBill.Taylor@Sun.COM
5989517SBill.Taylor@Sun.COM /*
5999517SBill.Taylor@Sun.COM * hermon_ah_query()
6009517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
6019517SBill.Taylor@Sun.COM */
6029517SBill.Taylor@Sun.COM /* ARGSUSED */
6039517SBill.Taylor@Sun.COM int
hermon_ah_query(hermon_state_t * state,hermon_ahhdl_t ah,hermon_pdhdl_t * pd,ibt_adds_vect_t * attr_p)6049517SBill.Taylor@Sun.COM hermon_ah_query(hermon_state_t *state, hermon_ahhdl_t ah, hermon_pdhdl_t *pd,
6059517SBill.Taylor@Sun.COM ibt_adds_vect_t *attr_p)
6069517SBill.Taylor@Sun.COM {
6079517SBill.Taylor@Sun.COM mutex_enter(&ah->ah_lock);
6089517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*attr_p))
6099517SBill.Taylor@Sun.COM
6109517SBill.Taylor@Sun.COM /*
6119517SBill.Taylor@Sun.COM * Pull the PD and UDAV from the Hermon Address Handle structure
6129517SBill.Taylor@Sun.COM */
6139517SBill.Taylor@Sun.COM *pd = ah->ah_pdhdl;
6149517SBill.Taylor@Sun.COM
6159517SBill.Taylor@Sun.COM /*
6169517SBill.Taylor@Sun.COM * Fill in "ibt_adds_vect_t". We call hermon_get_addr_path() to fill
6179517SBill.Taylor@Sun.COM * the common portions that can be pulled from the UDAV we pass in.
6189517SBill.Taylor@Sun.COM *
6199517SBill.Taylor@Sun.COM * NOTE: We will also fill the "av_dgid.gid_guid" field from the
6209517SBill.Taylor@Sun.COM * "ah_save_guid" field we have previously saved away. The reason
6219517SBill.Taylor@Sun.COM * for this is described in hermon_ah_alloc() and hermon_ah_modify().
6229517SBill.Taylor@Sun.COM */
6239517SBill.Taylor@Sun.COM hermon_get_addr_path(state, (hermon_hw_addr_path_t *)ah->ah_udav,
6249517SBill.Taylor@Sun.COM attr_p, HERMON_ADDRPATH_UDAV);
6259517SBill.Taylor@Sun.COM
6269517SBill.Taylor@Sun.COM attr_p->av_dgid.gid_guid = ah->ah_save_guid;
6279517SBill.Taylor@Sun.COM
6289517SBill.Taylor@Sun.COM mutex_exit(&ah->ah_lock);
6299517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
6309517SBill.Taylor@Sun.COM }
6319517SBill.Taylor@Sun.COM
6329517SBill.Taylor@Sun.COM
6339517SBill.Taylor@Sun.COM /*
6349517SBill.Taylor@Sun.COM * hermon_ah_modify()
6359517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
6369517SBill.Taylor@Sun.COM */
6379517SBill.Taylor@Sun.COM /* ARGSUSED */
6389517SBill.Taylor@Sun.COM int
hermon_ah_modify(hermon_state_t * state,hermon_ahhdl_t ah,ibt_adds_vect_t * attr_p)6399517SBill.Taylor@Sun.COM hermon_ah_modify(hermon_state_t *state, hermon_ahhdl_t ah,
6409517SBill.Taylor@Sun.COM ibt_adds_vect_t *attr_p)
6419517SBill.Taylor@Sun.COM {
6429517SBill.Taylor@Sun.COM hermon_hw_udav_t old_udav;
6439517SBill.Taylor@Sun.COM uint64_t data_old;
6449517SBill.Taylor@Sun.COM int status, size, i;
6459517SBill.Taylor@Sun.COM
6469517SBill.Taylor@Sun.COM /* Validate that specified port number is legal */
6479517SBill.Taylor@Sun.COM if (!hermon_portnum_is_valid(state, attr_p->av_port_num)) {
6489517SBill.Taylor@Sun.COM return (IBT_HCA_PORT_INVALID);
6499517SBill.Taylor@Sun.COM }
6509517SBill.Taylor@Sun.COM
6519517SBill.Taylor@Sun.COM mutex_enter(&ah->ah_lock);
6529517SBill.Taylor@Sun.COM
6539517SBill.Taylor@Sun.COM /* Save a copy of the current UDAV data in old_udav. */
6549517SBill.Taylor@Sun.COM bcopy(ah->ah_udav, &old_udav, sizeof (hermon_hw_udav_t));
6559517SBill.Taylor@Sun.COM
6569517SBill.Taylor@Sun.COM /*
6579517SBill.Taylor@Sun.COM * Fill in the new UDAV with the caller's data, passed in via the
6589517SBill.Taylor@Sun.COM * "ibt_adds_vect_t" structure.
6599517SBill.Taylor@Sun.COM *
6609517SBill.Taylor@Sun.COM * NOTE: We also need to save away a copy of the "av_dgid.gid_guid"
6619517SBill.Taylor@Sun.COM * field here (just as we did during hermon_ah_alloc()) because we
6629517SBill.Taylor@Sun.COM * may need to return it later to the IBTF (as a result of a
6639517SBill.Taylor@Sun.COM * subsequent query operation). As explained in hermon_ah_alloc(),
6649517SBill.Taylor@Sun.COM * unlike the other UDAV parameters, the value of "av_dgid.gid_guid"
6659517SBill.Taylor@Sun.COM * is not always preserved. The reason for this is described in
6669517SBill.Taylor@Sun.COM * hermon_set_addr_path().
6679517SBill.Taylor@Sun.COM */
6689517SBill.Taylor@Sun.COM status = hermon_set_addr_path(state, attr_p,
6699517SBill.Taylor@Sun.COM (hermon_hw_addr_path_t *)ah->ah_udav, HERMON_ADDRPATH_UDAV);
6709517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
6719517SBill.Taylor@Sun.COM mutex_exit(&ah->ah_lock);
6729517SBill.Taylor@Sun.COM return (status);
6739517SBill.Taylor@Sun.COM }
6749517SBill.Taylor@Sun.COM ah->ah_save_guid = attr_p->av_dgid.gid_guid;
6759517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*(ah->ah_udav)))
6769517SBill.Taylor@Sun.COM ah->ah_udav->sl = attr_p->av_srvl;
6779517SBill.Taylor@Sun.COM
6789517SBill.Taylor@Sun.COM /*
6799517SBill.Taylor@Sun.COM * Copy changes into the new UDAV.
6809517SBill.Taylor@Sun.COM * Note: We copy in 64-bit chunks. For the first two of these
6819517SBill.Taylor@Sun.COM * chunks it is necessary to read the current contents of the
6829517SBill.Taylor@Sun.COM * UDAV, mask off the modifiable portions (maintaining any
6839517SBill.Taylor@Sun.COM * of the "reserved" portions), and then mask on the new data.
6849517SBill.Taylor@Sun.COM */
6859517SBill.Taylor@Sun.COM size = sizeof (hermon_hw_udav_t) >> 3;
6869517SBill.Taylor@Sun.COM for (i = 0; i < size; i++) {
6879517SBill.Taylor@Sun.COM data_old = ((uint64_t *)&old_udav)[i];
6889517SBill.Taylor@Sun.COM
6899517SBill.Taylor@Sun.COM /*
6909517SBill.Taylor@Sun.COM * Apply mask to change only the relevant values.
6919517SBill.Taylor@Sun.COM */
6929517SBill.Taylor@Sun.COM if (i == 0) {
6939517SBill.Taylor@Sun.COM data_old = data_old & HERMON_UDAV_MODIFY_MASK0;
6949517SBill.Taylor@Sun.COM } else if (i == 1) {
6959517SBill.Taylor@Sun.COM data_old = data_old & HERMON_UDAV_MODIFY_MASK1;
6969517SBill.Taylor@Sun.COM } else {
6979517SBill.Taylor@Sun.COM data_old = 0;
6989517SBill.Taylor@Sun.COM }
6999517SBill.Taylor@Sun.COM
7009517SBill.Taylor@Sun.COM /* Store the updated values to the UDAV */
7019517SBill.Taylor@Sun.COM ((uint64_t *)ah->ah_udav)[i] |= data_old;
7029517SBill.Taylor@Sun.COM }
7039517SBill.Taylor@Sun.COM
7049517SBill.Taylor@Sun.COM /*
7059517SBill.Taylor@Sun.COM * Put the valid PD number back into the UDAV entry, as it
7069517SBill.Taylor@Sun.COM * might have been clobbered above.
7079517SBill.Taylor@Sun.COM */
7089517SBill.Taylor@Sun.COM ah->ah_udav->pd = old_udav.pd;
7099517SBill.Taylor@Sun.COM
7109517SBill.Taylor@Sun.COM
7119517SBill.Taylor@Sun.COM mutex_exit(&ah->ah_lock);
7129517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
7139517SBill.Taylor@Sun.COM }
7149517SBill.Taylor@Sun.COM
7159517SBill.Taylor@Sun.COM /*
7169517SBill.Taylor@Sun.COM * hermon_mcg_attach()
7179517SBill.Taylor@Sun.COM * Context: Can be called only from user or kernel context.
7189517SBill.Taylor@Sun.COM */
7199517SBill.Taylor@Sun.COM int
hermon_mcg_attach(hermon_state_t * state,hermon_qphdl_t qp,ib_gid_t gid,ib_lid_t lid)7209517SBill.Taylor@Sun.COM hermon_mcg_attach(hermon_state_t *state, hermon_qphdl_t qp, ib_gid_t gid,
7219517SBill.Taylor@Sun.COM ib_lid_t lid)
7229517SBill.Taylor@Sun.COM {
7239517SBill.Taylor@Sun.COM hermon_rsrc_t *rsrc;
7249517SBill.Taylor@Sun.COM hermon_hw_mcg_t *mcg_entry;
7259517SBill.Taylor@Sun.COM hermon_hw_mcg_qp_list_t *mcg_entry_qplist;
7269517SBill.Taylor@Sun.COM hermon_mcghdl_t mcg, newmcg;
7279517SBill.Taylor@Sun.COM uint64_t mgid_hash;
7289517SBill.Taylor@Sun.COM uint32_t end_indx;
7299517SBill.Taylor@Sun.COM int status;
7309517SBill.Taylor@Sun.COM uint_t qp_found;
7319517SBill.Taylor@Sun.COM
7329517SBill.Taylor@Sun.COM /*
7339517SBill.Taylor@Sun.COM * It is only allowed to attach MCG to UD queue pairs. Verify
7349517SBill.Taylor@Sun.COM * that the intended QP is of the appropriate transport type
7359517SBill.Taylor@Sun.COM */
7369517SBill.Taylor@Sun.COM if (qp->qp_serv_type != HERMON_QP_UD) {
7379517SBill.Taylor@Sun.COM return (IBT_QP_SRV_TYPE_INVALID);
7389517SBill.Taylor@Sun.COM }
7399517SBill.Taylor@Sun.COM
7409517SBill.Taylor@Sun.COM /*
7419517SBill.Taylor@Sun.COM * Check for invalid Multicast DLID. Specifically, all Multicast
7429517SBill.Taylor@Sun.COM * LIDs should be within a well defined range. If the specified LID
7439517SBill.Taylor@Sun.COM * is outside of that range, then return an error.
7449517SBill.Taylor@Sun.COM */
7459517SBill.Taylor@Sun.COM if (hermon_mlid_is_valid(lid) == 0) {
7469517SBill.Taylor@Sun.COM return (IBT_MC_MLID_INVALID);
7479517SBill.Taylor@Sun.COM }
7489517SBill.Taylor@Sun.COM /*
7499517SBill.Taylor@Sun.COM * Check for invalid Multicast GID. All Multicast GIDs should have
7509517SBill.Taylor@Sun.COM * a well-defined pattern of bits and flags that are allowable. If
7519517SBill.Taylor@Sun.COM * the specified GID does not meet the criteria, then return an error.
7529517SBill.Taylor@Sun.COM */
7539517SBill.Taylor@Sun.COM if (hermon_mgid_is_valid(gid) == 0) {
7549517SBill.Taylor@Sun.COM return (IBT_MC_MGID_INVALID);
7559517SBill.Taylor@Sun.COM }
7569517SBill.Taylor@Sun.COM
7579517SBill.Taylor@Sun.COM /*
7589517SBill.Taylor@Sun.COM * Compute the MGID hash value. Since the MCG table is arranged as
7599517SBill.Taylor@Sun.COM * a number of separate hash chains, this operation converts the
7609517SBill.Taylor@Sun.COM * specified MGID into the starting index of an entry in the hash
7619517SBill.Taylor@Sun.COM * table (i.e. the index for the start of the appropriate hash chain).
7629517SBill.Taylor@Sun.COM * Subsequent operations below will walk the chain searching for the
7639517SBill.Taylor@Sun.COM * right place to add this new QP.
7649517SBill.Taylor@Sun.COM */
7659517SBill.Taylor@Sun.COM status = hermon_mgid_hash_cmd_post(state, gid.gid_prefix, gid.gid_guid,
7669517SBill.Taylor@Sun.COM &mgid_hash, HERMON_SLEEPFLAG_FOR_CONTEXT());
7679517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
7689517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: MGID_HASH command failed: %08x\n",
7699517SBill.Taylor@Sun.COM status);
7709517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
7719517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
7729517SBill.Taylor@Sun.COM }
7739517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
7749517SBill.Taylor@Sun.COM }
7759517SBill.Taylor@Sun.COM
7769517SBill.Taylor@Sun.COM /*
7779517SBill.Taylor@Sun.COM * Grab the multicast group mutex. Then grab the pre-allocated
7789517SBill.Taylor@Sun.COM * temporary buffer used for holding and/or modifying MCG entries.
7799517SBill.Taylor@Sun.COM * Zero out the temporary MCG entry before we begin.
7809517SBill.Taylor@Sun.COM */
7819517SBill.Taylor@Sun.COM mutex_enter(&state->hs_mcglock);
7829517SBill.Taylor@Sun.COM mcg_entry = state->hs_mcgtmp;
7839517SBill.Taylor@Sun.COM mcg_entry_qplist = HERMON_MCG_GET_QPLIST_PTR(mcg_entry);
7849517SBill.Taylor@Sun.COM bzero(mcg_entry, HERMON_MCGMEM_SZ(state));
7859517SBill.Taylor@Sun.COM
7869517SBill.Taylor@Sun.COM /*
7879517SBill.Taylor@Sun.COM * Walk through the array of MCG entries starting at "mgid_hash".
7889517SBill.Taylor@Sun.COM * Try to find the appropriate place for this new QP to be added.
7899517SBill.Taylor@Sun.COM * This could happen when the first entry of the chain has MGID == 0
7909517SBill.Taylor@Sun.COM * (which means that the hash chain is empty), or because we find
7919517SBill.Taylor@Sun.COM * an entry with the same MGID (in which case we'll add the QP to
7929517SBill.Taylor@Sun.COM * that MCG), or because we come to the end of the chain (in which
7939517SBill.Taylor@Sun.COM * case this is the first QP being added to the multicast group that
7949517SBill.Taylor@Sun.COM * corresponds to the MGID. The hermon_mcg_walk_mgid_hash() routine
7959517SBill.Taylor@Sun.COM * walks the list and returns an index into the MCG table. The entry
7969517SBill.Taylor@Sun.COM * at this index is then checked to determine which case we have
7979517SBill.Taylor@Sun.COM * fallen into (see below). Note: We are using the "shadow" MCG
7989517SBill.Taylor@Sun.COM * list (of hermon_mcg_t structs) for this lookup because the real
7999517SBill.Taylor@Sun.COM * MCG entries are in hardware (and the lookup process would be much
8009517SBill.Taylor@Sun.COM * more time consuming).
8019517SBill.Taylor@Sun.COM */
8029517SBill.Taylor@Sun.COM end_indx = hermon_mcg_walk_mgid_hash(state, mgid_hash, gid, NULL);
8039517SBill.Taylor@Sun.COM mcg = &state->hs_mcghdl[end_indx];
8049517SBill.Taylor@Sun.COM
8059517SBill.Taylor@Sun.COM /*
8069517SBill.Taylor@Sun.COM * If MGID == 0, then the hash chain is empty. Just fill in the
8079517SBill.Taylor@Sun.COM * current entry. Note: No need to allocate an MCG table entry
8089517SBill.Taylor@Sun.COM * as all the hash chain "heads" are already preallocated.
8099517SBill.Taylor@Sun.COM */
8109517SBill.Taylor@Sun.COM if ((mcg->mcg_mgid_h == 0) && (mcg->mcg_mgid_l == 0)) {
8119517SBill.Taylor@Sun.COM
8129517SBill.Taylor@Sun.COM /* Fill in the current entry in the "shadow" MCG list */
8139517SBill.Taylor@Sun.COM hermon_mcg_setup_new_hdr(mcg, mcg_entry, gid, NULL);
8149517SBill.Taylor@Sun.COM
8159517SBill.Taylor@Sun.COM /*
8169517SBill.Taylor@Sun.COM * Try to add the new QP number to the list. This (and the
8179517SBill.Taylor@Sun.COM * above) routine fills in a temporary MCG. The "mcg_entry"
8189517SBill.Taylor@Sun.COM * and "mcg_entry_qplist" pointers simply point to different
8199517SBill.Taylor@Sun.COM * offsets within the same temporary copy of the MCG (for
8209517SBill.Taylor@Sun.COM * convenience). Note: If this fails, we need to invalidate
8219517SBill.Taylor@Sun.COM * the entries we've already put into the "shadow" list entry
8229517SBill.Taylor@Sun.COM * above.
8239517SBill.Taylor@Sun.COM */
8249517SBill.Taylor@Sun.COM status = hermon_mcg_qplist_add(state, mcg, mcg_entry_qplist, qp,
8259517SBill.Taylor@Sun.COM &qp_found);
8269517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
8279517SBill.Taylor@Sun.COM bzero(mcg, sizeof (struct hermon_sw_mcg_list_s));
8289517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
8299517SBill.Taylor@Sun.COM return (status);
8309517SBill.Taylor@Sun.COM }
8319517SBill.Taylor@Sun.COM if (!qp_found)
8329517SBill.Taylor@Sun.COM mcg_entry->member_cnt = (mcg->mcg_num_qps + 1);
8339517SBill.Taylor@Sun.COM /* set the member count */
8349517SBill.Taylor@Sun.COM
8359517SBill.Taylor@Sun.COM /*
8369517SBill.Taylor@Sun.COM * Once the temporary MCG has been filled in, write the entry
8379517SBill.Taylor@Sun.COM * into the appropriate location in the Hermon MCG entry table.
8389517SBill.Taylor@Sun.COM * If it's successful, then drop the lock and return success.
8399517SBill.Taylor@Sun.COM * Note: In general, this operation shouldn't fail. If it
8409517SBill.Taylor@Sun.COM * does, then it is an indication that something (probably in
8419517SBill.Taylor@Sun.COM * HW, but maybe in SW) has gone seriously wrong. We still
8429517SBill.Taylor@Sun.COM * want to zero out the entries that we've filled in above
8439517SBill.Taylor@Sun.COM * (in the hermon_mcg_setup_new_hdr() routine).
8449517SBill.Taylor@Sun.COM */
8459517SBill.Taylor@Sun.COM status = hermon_write_mgm_cmd_post(state, mcg_entry, end_indx,
8469517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
8479517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
8489517SBill.Taylor@Sun.COM bzero(mcg, sizeof (struct hermon_sw_mcg_list_s));
8499517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
8509517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to write MCG entry");
8519517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: WRITE_MGM command failed: "
8529517SBill.Taylor@Sun.COM "%08x\n", status);
8539517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
8549517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR,
8559517SBill.Taylor@Sun.COM HCA_ERR_SRV_LOST);
8569517SBill.Taylor@Sun.COM }
8579517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
8589517SBill.Taylor@Sun.COM }
8599517SBill.Taylor@Sun.COM
8609517SBill.Taylor@Sun.COM /*
8619517SBill.Taylor@Sun.COM * Now that we know all the Hermon firmware accesses have been
8629517SBill.Taylor@Sun.COM * successful, we update the "shadow" MCG entry by incrementing
8639517SBill.Taylor@Sun.COM * the "number of attached QPs" count.
8649517SBill.Taylor@Sun.COM *
8659517SBill.Taylor@Sun.COM * We increment only if the QP is not already part of the
8669517SBill.Taylor@Sun.COM * MCG by checking the 'qp_found' flag returned from the
8679517SBill.Taylor@Sun.COM * qplist_add above.
8689517SBill.Taylor@Sun.COM */
8699517SBill.Taylor@Sun.COM if (!qp_found) {
8709517SBill.Taylor@Sun.COM mcg->mcg_num_qps++;
8719517SBill.Taylor@Sun.COM
8729517SBill.Taylor@Sun.COM /*
8739517SBill.Taylor@Sun.COM * Increment the refcnt for this QP. Because the QP
8749517SBill.Taylor@Sun.COM * was added to this MCG, the refcnt must be
8759517SBill.Taylor@Sun.COM * incremented.
8769517SBill.Taylor@Sun.COM */
8779517SBill.Taylor@Sun.COM hermon_qp_mcg_refcnt_inc(qp);
8789517SBill.Taylor@Sun.COM }
8799517SBill.Taylor@Sun.COM
8809517SBill.Taylor@Sun.COM /*
8819517SBill.Taylor@Sun.COM * We drop the lock and return success.
8829517SBill.Taylor@Sun.COM */
8839517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
8849517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
8859517SBill.Taylor@Sun.COM }
8869517SBill.Taylor@Sun.COM
8879517SBill.Taylor@Sun.COM /*
8889517SBill.Taylor@Sun.COM * If the specified MGID matches the MGID in the current entry, then
8899517SBill.Taylor@Sun.COM * we need to try to add the QP to the current MCG entry. In this
8909517SBill.Taylor@Sun.COM * case, it means that we need to read the existing MCG entry (into
8919517SBill.Taylor@Sun.COM * the temporary MCG), add the new QP number to the temporary entry
8929517SBill.Taylor@Sun.COM * (using the same method we used above), and write the entry back
8939517SBill.Taylor@Sun.COM * to the hardware (same as above).
8949517SBill.Taylor@Sun.COM */
8959517SBill.Taylor@Sun.COM if ((mcg->mcg_mgid_h == gid.gid_prefix) &&
8969517SBill.Taylor@Sun.COM (mcg->mcg_mgid_l == gid.gid_guid)) {
8979517SBill.Taylor@Sun.COM
8989517SBill.Taylor@Sun.COM /*
8999517SBill.Taylor@Sun.COM * Read the current MCG entry into the temporary MCG. Note:
9009517SBill.Taylor@Sun.COM * In general, this operation shouldn't fail. If it does,
9019517SBill.Taylor@Sun.COM * then it is an indication that something (probably in HW,
9029517SBill.Taylor@Sun.COM * but maybe in SW) has gone seriously wrong.
9039517SBill.Taylor@Sun.COM */
9049517SBill.Taylor@Sun.COM status = hermon_read_mgm_cmd_post(state, mcg_entry, end_indx,
9059517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
9069517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
9079517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
9089517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to read MCG entry");
9099517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: READ_MGM command failed: "
9109517SBill.Taylor@Sun.COM "%08x\n", status);
9119517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
9129517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR,
9139517SBill.Taylor@Sun.COM HCA_ERR_SRV_LOST);
9149517SBill.Taylor@Sun.COM }
9159517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
9169517SBill.Taylor@Sun.COM }
9179517SBill.Taylor@Sun.COM
9189517SBill.Taylor@Sun.COM /*
9199517SBill.Taylor@Sun.COM * Try to add the new QP number to the list. This routine
9209517SBill.Taylor@Sun.COM * fills in the necessary pieces of the temporary MCG. The
9219517SBill.Taylor@Sun.COM * "mcg_entry_qplist" pointer is used to point to the portion
9229517SBill.Taylor@Sun.COM * of the temporary MCG that holds the QP numbers.
9239517SBill.Taylor@Sun.COM *
9249517SBill.Taylor@Sun.COM * Note: hermon_mcg_qplist_add() returns SUCCESS if it
9259517SBill.Taylor@Sun.COM * already found the QP in the list. In this case, the QP is
9269517SBill.Taylor@Sun.COM * not added on to the list again. Check the flag 'qp_found'
9279517SBill.Taylor@Sun.COM * if this value is needed to be known.
9289517SBill.Taylor@Sun.COM *
9299517SBill.Taylor@Sun.COM */
9309517SBill.Taylor@Sun.COM status = hermon_mcg_qplist_add(state, mcg, mcg_entry_qplist, qp,
9319517SBill.Taylor@Sun.COM &qp_found);
9329517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
9339517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
9349517SBill.Taylor@Sun.COM return (status);
9359517SBill.Taylor@Sun.COM }
9369517SBill.Taylor@Sun.COM if (!qp_found)
9379517SBill.Taylor@Sun.COM mcg_entry->member_cnt = (mcg->mcg_num_qps + 1);
9389517SBill.Taylor@Sun.COM /* set the member count */
9399517SBill.Taylor@Sun.COM
9409517SBill.Taylor@Sun.COM /*
9419517SBill.Taylor@Sun.COM * Once the temporary MCG has been updated, write the entry
9429517SBill.Taylor@Sun.COM * into the appropriate location in the Hermon MCG entry table.
9439517SBill.Taylor@Sun.COM * If it's successful, then drop the lock and return success.
9449517SBill.Taylor@Sun.COM * Note: In general, this operation shouldn't fail. If it
9459517SBill.Taylor@Sun.COM * does, then it is an indication that something (probably in
9469517SBill.Taylor@Sun.COM * HW, but maybe in SW) has gone seriously wrong.
9479517SBill.Taylor@Sun.COM */
9489517SBill.Taylor@Sun.COM status = hermon_write_mgm_cmd_post(state, mcg_entry, end_indx,
9499517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
9509517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
9519517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
9529517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to write MCG entry");
9539517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: WRITE_MGM command failed: "
9549517SBill.Taylor@Sun.COM "%08x\n", status);
9559517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
9569517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR,
9579517SBill.Taylor@Sun.COM HCA_ERR_SRV_LOST);
9589517SBill.Taylor@Sun.COM }
9599517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
9609517SBill.Taylor@Sun.COM }
9619517SBill.Taylor@Sun.COM
9629517SBill.Taylor@Sun.COM /*
9639517SBill.Taylor@Sun.COM * Now that we know all the Hermon firmware accesses have been
9649517SBill.Taylor@Sun.COM * successful, we update the current "shadow" MCG entry by
9659517SBill.Taylor@Sun.COM * incrementing the "number of attached QPs" count.
9669517SBill.Taylor@Sun.COM *
9679517SBill.Taylor@Sun.COM * We increment only if the QP is not already part of the
9689517SBill.Taylor@Sun.COM * MCG by checking the 'qp_found' flag returned
9699517SBill.Taylor@Sun.COM * hermon_mcg_walk_mgid_hashfrom the qplist_add above.
9709517SBill.Taylor@Sun.COM */
9719517SBill.Taylor@Sun.COM if (!qp_found) {
9729517SBill.Taylor@Sun.COM mcg->mcg_num_qps++;
9739517SBill.Taylor@Sun.COM
9749517SBill.Taylor@Sun.COM /*
9759517SBill.Taylor@Sun.COM * Increment the refcnt for this QP. Because the QP
9769517SBill.Taylor@Sun.COM * was added to this MCG, the refcnt must be
9779517SBill.Taylor@Sun.COM * incremented.
9789517SBill.Taylor@Sun.COM */
9799517SBill.Taylor@Sun.COM hermon_qp_mcg_refcnt_inc(qp);
9809517SBill.Taylor@Sun.COM }
9819517SBill.Taylor@Sun.COM
9829517SBill.Taylor@Sun.COM /*
9839517SBill.Taylor@Sun.COM * We drop the lock and return success.
9849517SBill.Taylor@Sun.COM */
9859517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
9869517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
9879517SBill.Taylor@Sun.COM }
9889517SBill.Taylor@Sun.COM
9899517SBill.Taylor@Sun.COM /*
9909517SBill.Taylor@Sun.COM * If we've reached here, then we're at the end of the hash chain.
9919517SBill.Taylor@Sun.COM * We need to allocate a new MCG entry, fill it in, write it to Hermon,
9929517SBill.Taylor@Sun.COM * and update the previous entry to link the new one to the end of the
9939517SBill.Taylor@Sun.COM * chain.
9949517SBill.Taylor@Sun.COM */
9959517SBill.Taylor@Sun.COM
9969517SBill.Taylor@Sun.COM /*
9979517SBill.Taylor@Sun.COM * Allocate an MCG table entry. This will be filled in with all
9989517SBill.Taylor@Sun.COM * the necessary parameters to define the multicast group. Then it
9999517SBill.Taylor@Sun.COM * will be written to the hardware in the next-to-last step below.
10009517SBill.Taylor@Sun.COM */
10019517SBill.Taylor@Sun.COM status = hermon_rsrc_alloc(state, HERMON_MCG, 1, HERMON_NOSLEEP, &rsrc);
10029517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
10039517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
10049517SBill.Taylor@Sun.COM return (IBT_INSUFF_RESOURCE);
10059517SBill.Taylor@Sun.COM }
10069517SBill.Taylor@Sun.COM
10079517SBill.Taylor@Sun.COM /*
10089517SBill.Taylor@Sun.COM * Fill in the new entry in the "shadow" MCG list. Note: Just as
10099517SBill.Taylor@Sun.COM * it does above, hermon_mcg_setup_new_hdr() also fills in a portion
10109517SBill.Taylor@Sun.COM * of the temporary MCG entry (the rest of which will be filled in by
10119517SBill.Taylor@Sun.COM * hermon_mcg_qplist_add() below)
10129517SBill.Taylor@Sun.COM */
10139517SBill.Taylor@Sun.COM newmcg = &state->hs_mcghdl[rsrc->hr_indx];
10149517SBill.Taylor@Sun.COM hermon_mcg_setup_new_hdr(newmcg, mcg_entry, gid, rsrc);
10159517SBill.Taylor@Sun.COM
10169517SBill.Taylor@Sun.COM /*
10179517SBill.Taylor@Sun.COM * Try to add the new QP number to the list. This routine fills in
10189517SBill.Taylor@Sun.COM * the final necessary pieces of the temporary MCG. The
10199517SBill.Taylor@Sun.COM * "mcg_entry_qplist" pointer is used to point to the portion of the
10209517SBill.Taylor@Sun.COM * temporary MCG that holds the QP numbers. If we fail here, we
10219517SBill.Taylor@Sun.COM * must undo the previous resource allocation.
10229517SBill.Taylor@Sun.COM *
10239517SBill.Taylor@Sun.COM * Note: hermon_mcg_qplist_add() can we return SUCCESS if it already
10249517SBill.Taylor@Sun.COM * found the QP in the list. In this case, the QP is not added on to
10259517SBill.Taylor@Sun.COM * the list again. Check the flag 'qp_found' if this value is needed
10269517SBill.Taylor@Sun.COM * to be known.
10279517SBill.Taylor@Sun.COM */
10289517SBill.Taylor@Sun.COM status = hermon_mcg_qplist_add(state, newmcg, mcg_entry_qplist, qp,
10299517SBill.Taylor@Sun.COM &qp_found);
10309517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
10319517SBill.Taylor@Sun.COM bzero(newmcg, sizeof (struct hermon_sw_mcg_list_s));
10329517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &rsrc);
10339517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
10349517SBill.Taylor@Sun.COM return (status);
10359517SBill.Taylor@Sun.COM }
10369517SBill.Taylor@Sun.COM mcg_entry->member_cnt = (newmcg->mcg_num_qps + 1);
10379517SBill.Taylor@Sun.COM /* set the member count */
10389517SBill.Taylor@Sun.COM
10399517SBill.Taylor@Sun.COM /*
10409517SBill.Taylor@Sun.COM * Once the temporary MCG has been updated, write the entry into the
10419517SBill.Taylor@Sun.COM * appropriate location in the Hermon MCG entry table. If this is
10429517SBill.Taylor@Sun.COM * successful, then we need to chain the previous entry to this one.
10439517SBill.Taylor@Sun.COM * Note: In general, this operation shouldn't fail. If it does, then
10449517SBill.Taylor@Sun.COM * it is an indication that something (probably in HW, but maybe in
10459517SBill.Taylor@Sun.COM * SW) has gone seriously wrong.
10469517SBill.Taylor@Sun.COM */
10479517SBill.Taylor@Sun.COM status = hermon_write_mgm_cmd_post(state, mcg_entry, rsrc->hr_indx,
10489517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
10499517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
10509517SBill.Taylor@Sun.COM bzero(newmcg, sizeof (struct hermon_sw_mcg_list_s));
10519517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &rsrc);
10529517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
10539517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to write MCG entry");
10549517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: WRITE_MGM command failed: %08x\n",
10559517SBill.Taylor@Sun.COM status);
10569517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
10579517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
10589517SBill.Taylor@Sun.COM }
10599517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
10609517SBill.Taylor@Sun.COM }
10619517SBill.Taylor@Sun.COM
10629517SBill.Taylor@Sun.COM /*
10639517SBill.Taylor@Sun.COM * Now read the current MCG entry (the one previously at the end of
10649517SBill.Taylor@Sun.COM * hash chain) into the temporary MCG. We are going to update its
10659517SBill.Taylor@Sun.COM * "next_gid_indx" now and write the entry back to the MCG table.
10669517SBill.Taylor@Sun.COM * Note: In general, this operation shouldn't fail. If it does, then
10679517SBill.Taylor@Sun.COM * it is an indication that something (probably in HW, but maybe in SW)
10689517SBill.Taylor@Sun.COM * has gone seriously wrong. We will free up the MCG entry resource,
10699517SBill.Taylor@Sun.COM * but we will not undo the previously written MCG entry in the HW.
10709517SBill.Taylor@Sun.COM * This is OK, though, because the MCG entry is not currently attached
10719517SBill.Taylor@Sun.COM * to any hash chain.
10729517SBill.Taylor@Sun.COM */
10739517SBill.Taylor@Sun.COM status = hermon_read_mgm_cmd_post(state, mcg_entry, end_indx,
10749517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
10759517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
10769517SBill.Taylor@Sun.COM bzero(newmcg, sizeof (struct hermon_sw_mcg_list_s));
10779517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &rsrc);
10789517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
10799517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to read MCG entry");
10809517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: READ_MGM command failed: %08x\n",
10819517SBill.Taylor@Sun.COM status);
10829517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
10839517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
10849517SBill.Taylor@Sun.COM }
10859517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
10869517SBill.Taylor@Sun.COM }
10879517SBill.Taylor@Sun.COM
10889517SBill.Taylor@Sun.COM /*
10899517SBill.Taylor@Sun.COM * Finally, we update the "next_gid_indx" field in the temporary MCG
10909517SBill.Taylor@Sun.COM * and attempt to write the entry back into the Hermon MCG table. If
10919517SBill.Taylor@Sun.COM * this succeeds, then we update the "shadow" list to reflect the
10929517SBill.Taylor@Sun.COM * change, drop the lock, and return success. Note: In general, this
10939517SBill.Taylor@Sun.COM * operation shouldn't fail. If it does, then it is an indication
10949517SBill.Taylor@Sun.COM * that something (probably in HW, but maybe in SW) has gone seriously
10959517SBill.Taylor@Sun.COM * wrong. Just as we do above, we will free up the MCG entry resource,
10969517SBill.Taylor@Sun.COM * but we will not try to undo the previously written MCG entry. This
10979517SBill.Taylor@Sun.COM * is OK, though, because (since we failed here to update the end of
10989517SBill.Taylor@Sun.COM * the chain) that other entry is not currently attached to any chain.
10999517SBill.Taylor@Sun.COM */
11009517SBill.Taylor@Sun.COM mcg_entry->next_gid_indx = rsrc->hr_indx;
11019517SBill.Taylor@Sun.COM status = hermon_write_mgm_cmd_post(state, mcg_entry, end_indx,
11029517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
11039517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
11049517SBill.Taylor@Sun.COM bzero(newmcg, sizeof (struct hermon_sw_mcg_list_s));
11059517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &rsrc);
11069517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
11079517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to write MCG entry");
11089517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: WRITE_MGM command failed: %08x\n",
11099517SBill.Taylor@Sun.COM status);
11109517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
11119517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
11129517SBill.Taylor@Sun.COM }
11139517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
11149517SBill.Taylor@Sun.COM }
11159517SBill.Taylor@Sun.COM mcg = &state->hs_mcghdl[end_indx];
11169517SBill.Taylor@Sun.COM mcg->mcg_next_indx = rsrc->hr_indx;
11179517SBill.Taylor@Sun.COM
11189517SBill.Taylor@Sun.COM /*
11199517SBill.Taylor@Sun.COM * Now that we know all the Hermon firmware accesses have been
11209517SBill.Taylor@Sun.COM * successful, we update the new "shadow" MCG entry by incrementing
11219517SBill.Taylor@Sun.COM * the "number of attached QPs" count. Then we drop the lock and
11229517SBill.Taylor@Sun.COM * return success.
11239517SBill.Taylor@Sun.COM */
11249517SBill.Taylor@Sun.COM newmcg->mcg_num_qps++;
11259517SBill.Taylor@Sun.COM
11269517SBill.Taylor@Sun.COM /*
11279517SBill.Taylor@Sun.COM * Increment the refcnt for this QP. Because the QP
11289517SBill.Taylor@Sun.COM * was added to this MCG, the refcnt must be
11299517SBill.Taylor@Sun.COM * incremented.
11309517SBill.Taylor@Sun.COM */
11319517SBill.Taylor@Sun.COM hermon_qp_mcg_refcnt_inc(qp);
11329517SBill.Taylor@Sun.COM
11339517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
11349517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
11359517SBill.Taylor@Sun.COM }
11369517SBill.Taylor@Sun.COM
11379517SBill.Taylor@Sun.COM
11389517SBill.Taylor@Sun.COM /*
11399517SBill.Taylor@Sun.COM * hermon_mcg_detach()
11409517SBill.Taylor@Sun.COM * Context: Can be called only from user or kernel context.
11419517SBill.Taylor@Sun.COM */
11429517SBill.Taylor@Sun.COM int
hermon_mcg_detach(hermon_state_t * state,hermon_qphdl_t qp,ib_gid_t gid,ib_lid_t lid)11439517SBill.Taylor@Sun.COM hermon_mcg_detach(hermon_state_t *state, hermon_qphdl_t qp, ib_gid_t gid,
11449517SBill.Taylor@Sun.COM ib_lid_t lid)
11459517SBill.Taylor@Sun.COM {
11469517SBill.Taylor@Sun.COM hermon_hw_mcg_t *mcg_entry;
11479517SBill.Taylor@Sun.COM hermon_hw_mcg_qp_list_t *mcg_entry_qplist;
11489517SBill.Taylor@Sun.COM hermon_mcghdl_t mcg;
11499517SBill.Taylor@Sun.COM uint64_t mgid_hash;
11509517SBill.Taylor@Sun.COM uint32_t end_indx, prev_indx;
11519517SBill.Taylor@Sun.COM int status;
11529517SBill.Taylor@Sun.COM
11539517SBill.Taylor@Sun.COM /*
11549517SBill.Taylor@Sun.COM * Check for invalid Multicast DLID. Specifically, all Multicast
11559517SBill.Taylor@Sun.COM * LIDs should be within a well defined range. If the specified LID
11569517SBill.Taylor@Sun.COM * is outside of that range, then return an error.
11579517SBill.Taylor@Sun.COM */
11589517SBill.Taylor@Sun.COM if (hermon_mlid_is_valid(lid) == 0) {
11599517SBill.Taylor@Sun.COM return (IBT_MC_MLID_INVALID);
11609517SBill.Taylor@Sun.COM }
11619517SBill.Taylor@Sun.COM
11629517SBill.Taylor@Sun.COM /*
11639517SBill.Taylor@Sun.COM * Compute the MGID hash value. As described above, the MCG table is
11649517SBill.Taylor@Sun.COM * arranged as a number of separate hash chains. This operation
11659517SBill.Taylor@Sun.COM * converts the specified MGID into the starting index of an entry in
11669517SBill.Taylor@Sun.COM * the hash table (i.e. the index for the start of the appropriate
11679517SBill.Taylor@Sun.COM * hash chain). Subsequent operations below will walk the chain
11689517SBill.Taylor@Sun.COM * searching for a matching entry from which to attempt to remove
11699517SBill.Taylor@Sun.COM * the specified QP.
11709517SBill.Taylor@Sun.COM */
11719517SBill.Taylor@Sun.COM status = hermon_mgid_hash_cmd_post(state, gid.gid_prefix, gid.gid_guid,
11729517SBill.Taylor@Sun.COM &mgid_hash, HERMON_SLEEPFLAG_FOR_CONTEXT());
11739517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
11749517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: MGID_HASH command failed: %08x\n",
11759517SBill.Taylor@Sun.COM status);
11769517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
11779517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
11789517SBill.Taylor@Sun.COM }
11799517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
11809517SBill.Taylor@Sun.COM }
11819517SBill.Taylor@Sun.COM
11829517SBill.Taylor@Sun.COM /*
11839517SBill.Taylor@Sun.COM * Grab the multicast group mutex. Then grab the pre-allocated
11849517SBill.Taylor@Sun.COM * temporary buffer used for holding and/or modifying MCG entries.
11859517SBill.Taylor@Sun.COM */
11869517SBill.Taylor@Sun.COM mutex_enter(&state->hs_mcglock);
11879517SBill.Taylor@Sun.COM mcg_entry = state->hs_mcgtmp;
11889517SBill.Taylor@Sun.COM mcg_entry_qplist = HERMON_MCG_GET_QPLIST_PTR(mcg_entry);
11899517SBill.Taylor@Sun.COM
11909517SBill.Taylor@Sun.COM /*
11919517SBill.Taylor@Sun.COM * Walk through the array of MCG entries starting at "mgid_hash".
11929517SBill.Taylor@Sun.COM * Try to find an MCG entry with a matching MGID. The
11939517SBill.Taylor@Sun.COM * hermon_mcg_walk_mgid_hash() routine walks the list and returns an
11949517SBill.Taylor@Sun.COM * index into the MCG table. The entry at this index is checked to
11959517SBill.Taylor@Sun.COM * determine whether it is a match or not. If it is a match, then
11969517SBill.Taylor@Sun.COM * we continue on to attempt to remove the QP from the MCG. If it
11979517SBill.Taylor@Sun.COM * is not a match (or not a valid MCG entry), then we return an error.
11989517SBill.Taylor@Sun.COM */
11999517SBill.Taylor@Sun.COM end_indx = hermon_mcg_walk_mgid_hash(state, mgid_hash, gid, &prev_indx);
12009517SBill.Taylor@Sun.COM mcg = &state->hs_mcghdl[end_indx];
12019517SBill.Taylor@Sun.COM
12029517SBill.Taylor@Sun.COM /*
12039517SBill.Taylor@Sun.COM * If MGID == 0 (the hash chain is empty) or if the specified MGID
12049517SBill.Taylor@Sun.COM * does not match the MGID in the current entry, then return
12059517SBill.Taylor@Sun.COM * IBT_MC_MGID_INVALID (to indicate that the specified MGID is not
12069517SBill.Taylor@Sun.COM * valid).
12079517SBill.Taylor@Sun.COM */
12089517SBill.Taylor@Sun.COM if (((mcg->mcg_mgid_h == 0) && (mcg->mcg_mgid_l == 0)) ||
12099517SBill.Taylor@Sun.COM ((mcg->mcg_mgid_h != gid.gid_prefix) ||
12109517SBill.Taylor@Sun.COM (mcg->mcg_mgid_l != gid.gid_guid))) {
12119517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
12129517SBill.Taylor@Sun.COM return (IBT_MC_MGID_INVALID);
12139517SBill.Taylor@Sun.COM }
12149517SBill.Taylor@Sun.COM
12159517SBill.Taylor@Sun.COM /*
12169517SBill.Taylor@Sun.COM * Read the current MCG entry into the temporary MCG. Note: In
12179517SBill.Taylor@Sun.COM * general, this operation shouldn't fail. If it does, then it is
12189517SBill.Taylor@Sun.COM * an indication that something (probably in HW, but maybe in SW)
12199517SBill.Taylor@Sun.COM * has gone seriously wrong.
12209517SBill.Taylor@Sun.COM */
12219517SBill.Taylor@Sun.COM status = hermon_read_mgm_cmd_post(state, mcg_entry, end_indx,
12229517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
12239517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
12249517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
12259517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to read MCG entry");
12269517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: READ_MGM command failed: %08x\n",
12279517SBill.Taylor@Sun.COM status);
12289517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
12299517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
12309517SBill.Taylor@Sun.COM }
12319517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
12329517SBill.Taylor@Sun.COM }
12339517SBill.Taylor@Sun.COM
12349517SBill.Taylor@Sun.COM /*
12359517SBill.Taylor@Sun.COM * Search the QP number list for a match. If a match is found, then
12369517SBill.Taylor@Sun.COM * remove the entry from the QP list. Otherwise, if no match is found,
12379517SBill.Taylor@Sun.COM * return an error.
12389517SBill.Taylor@Sun.COM */
12399517SBill.Taylor@Sun.COM status = hermon_mcg_qplist_remove(mcg, mcg_entry_qplist, qp);
12409517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
12419517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
12429517SBill.Taylor@Sun.COM return (status);
12439517SBill.Taylor@Sun.COM }
12449517SBill.Taylor@Sun.COM
12459517SBill.Taylor@Sun.COM /*
12469517SBill.Taylor@Sun.COM * Decrement the MCG count for this QP. When the 'qp_mcg'
12479517SBill.Taylor@Sun.COM * field becomes 0, then this QP is no longer a member of any
12489517SBill.Taylor@Sun.COM * MCG.
12499517SBill.Taylor@Sun.COM */
12509517SBill.Taylor@Sun.COM hermon_qp_mcg_refcnt_dec(qp);
12519517SBill.Taylor@Sun.COM
12529517SBill.Taylor@Sun.COM /*
12539517SBill.Taylor@Sun.COM * If the current MCG's QP number list is about to be made empty
12549517SBill.Taylor@Sun.COM * ("mcg_num_qps" == 1), then remove the entry itself from the hash
12559517SBill.Taylor@Sun.COM * chain. Otherwise, just write the updated MCG entry back to the
12569517SBill.Taylor@Sun.COM * hardware. In either case, once we successfully update the hardware
12579517SBill.Taylor@Sun.COM * chain, then we decrement the "shadow" list entry's "mcg_num_qps"
12589517SBill.Taylor@Sun.COM * count (or zero out the entire "shadow" list entry) before returning
12599517SBill.Taylor@Sun.COM * success. Note: Zeroing out the "shadow" list entry is done
12609517SBill.Taylor@Sun.COM * inside of hermon_mcg_hash_list_remove().
12619517SBill.Taylor@Sun.COM */
12629517SBill.Taylor@Sun.COM if (mcg->mcg_num_qps == 1) {
12639517SBill.Taylor@Sun.COM
12649517SBill.Taylor@Sun.COM /* Remove an MCG entry from the hash chain */
12659517SBill.Taylor@Sun.COM status = hermon_mcg_hash_list_remove(state, end_indx, prev_indx,
12669517SBill.Taylor@Sun.COM mcg_entry);
12679517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
12689517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
12699517SBill.Taylor@Sun.COM return (status);
12709517SBill.Taylor@Sun.COM }
12719517SBill.Taylor@Sun.COM
12729517SBill.Taylor@Sun.COM } else {
12739517SBill.Taylor@Sun.COM /*
12749517SBill.Taylor@Sun.COM * Write the updated MCG entry back to the Hermon MCG table.
12759517SBill.Taylor@Sun.COM * If this succeeds, then we update the "shadow" list to
12769517SBill.Taylor@Sun.COM * reflect the change (i.e. decrement the "mcg_num_qps"),
12779517SBill.Taylor@Sun.COM * drop the lock, and return success. Note: In general,
12789517SBill.Taylor@Sun.COM * this operation shouldn't fail. If it does, then it is an
12799517SBill.Taylor@Sun.COM * indication that something (probably in HW, but maybe in SW)
12809517SBill.Taylor@Sun.COM * has gone seriously wrong.
12819517SBill.Taylor@Sun.COM */
12829517SBill.Taylor@Sun.COM mcg_entry->member_cnt = (mcg->mcg_num_qps - 1);
12839517SBill.Taylor@Sun.COM status = hermon_write_mgm_cmd_post(state, mcg_entry, end_indx,
12849517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
12859517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
12869517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
12879517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to write MCG entry");
12889517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: WRITE_MGM command failed: "
12899517SBill.Taylor@Sun.COM "%08x\n", status);
12909517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
12919517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR,
12929517SBill.Taylor@Sun.COM HCA_ERR_SRV_LOST);
12939517SBill.Taylor@Sun.COM }
12949517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
12959517SBill.Taylor@Sun.COM }
12969517SBill.Taylor@Sun.COM mcg->mcg_num_qps--;
12979517SBill.Taylor@Sun.COM }
12989517SBill.Taylor@Sun.COM
12999517SBill.Taylor@Sun.COM mutex_exit(&state->hs_mcglock);
13009517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
13019517SBill.Taylor@Sun.COM }
13029517SBill.Taylor@Sun.COM
13039517SBill.Taylor@Sun.COM /*
13049517SBill.Taylor@Sun.COM * hermon_qp_mcg_refcnt_inc()
13059517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
13069517SBill.Taylor@Sun.COM */
13079517SBill.Taylor@Sun.COM static void
hermon_qp_mcg_refcnt_inc(hermon_qphdl_t qp)13089517SBill.Taylor@Sun.COM hermon_qp_mcg_refcnt_inc(hermon_qphdl_t qp)
13099517SBill.Taylor@Sun.COM {
13109517SBill.Taylor@Sun.COM /* Increment the QP's MCG reference count */
13119517SBill.Taylor@Sun.COM mutex_enter(&qp->qp_lock);
13129517SBill.Taylor@Sun.COM qp->qp_mcg_refcnt++;
13139517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_lock);
13149517SBill.Taylor@Sun.COM }
13159517SBill.Taylor@Sun.COM
13169517SBill.Taylor@Sun.COM
13179517SBill.Taylor@Sun.COM /*
13189517SBill.Taylor@Sun.COM * hermon_qp_mcg_refcnt_dec()
13199517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
13209517SBill.Taylor@Sun.COM */
13219517SBill.Taylor@Sun.COM static void
hermon_qp_mcg_refcnt_dec(hermon_qphdl_t qp)13229517SBill.Taylor@Sun.COM hermon_qp_mcg_refcnt_dec(hermon_qphdl_t qp)
13239517SBill.Taylor@Sun.COM {
13249517SBill.Taylor@Sun.COM /* Decrement the QP's MCG reference count */
13259517SBill.Taylor@Sun.COM mutex_enter(&qp->qp_lock);
13269517SBill.Taylor@Sun.COM qp->qp_mcg_refcnt--;
13279517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_lock);
13289517SBill.Taylor@Sun.COM }
13299517SBill.Taylor@Sun.COM
13309517SBill.Taylor@Sun.COM
13319517SBill.Taylor@Sun.COM /*
13329517SBill.Taylor@Sun.COM * hermon_mcg_qplist_add()
13339517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
13349517SBill.Taylor@Sun.COM */
13359517SBill.Taylor@Sun.COM static int
hermon_mcg_qplist_add(hermon_state_t * state,hermon_mcghdl_t mcg,hermon_hw_mcg_qp_list_t * mcg_qplist,hermon_qphdl_t qp,uint_t * qp_found)13369517SBill.Taylor@Sun.COM hermon_mcg_qplist_add(hermon_state_t *state, hermon_mcghdl_t mcg,
13379517SBill.Taylor@Sun.COM hermon_hw_mcg_qp_list_t *mcg_qplist, hermon_qphdl_t qp,
13389517SBill.Taylor@Sun.COM uint_t *qp_found)
13399517SBill.Taylor@Sun.COM {
13409517SBill.Taylor@Sun.COM uint_t qplist_indx;
13419517SBill.Taylor@Sun.COM
13429517SBill.Taylor@Sun.COM ASSERT(MUTEX_HELD(&state->hs_mcglock));
13439517SBill.Taylor@Sun.COM
13449517SBill.Taylor@Sun.COM qplist_indx = mcg->mcg_num_qps;
13459517SBill.Taylor@Sun.COM
13469517SBill.Taylor@Sun.COM /*
13479517SBill.Taylor@Sun.COM * Determine if we have exceeded the maximum number of QP per
13489517SBill.Taylor@Sun.COM * multicast group. If we have, then return an error
13499517SBill.Taylor@Sun.COM */
13509517SBill.Taylor@Sun.COM if (qplist_indx >= state->hs_cfg_profile->cp_num_qp_per_mcg) {
13519517SBill.Taylor@Sun.COM return (IBT_HCA_MCG_QP_EXCEEDED);
13529517SBill.Taylor@Sun.COM }
13539517SBill.Taylor@Sun.COM
13549517SBill.Taylor@Sun.COM /*
13559517SBill.Taylor@Sun.COM * Determine if the QP is already attached to this MCG table. If it
13569517SBill.Taylor@Sun.COM * is, then we break out and treat this operation as a NO-OP
13579517SBill.Taylor@Sun.COM */
13589517SBill.Taylor@Sun.COM for (qplist_indx = 0; qplist_indx < mcg->mcg_num_qps;
13599517SBill.Taylor@Sun.COM qplist_indx++) {
13609517SBill.Taylor@Sun.COM if (mcg_qplist[qplist_indx].qpn == qp->qp_qpnum) {
13619517SBill.Taylor@Sun.COM break;
13629517SBill.Taylor@Sun.COM }
13639517SBill.Taylor@Sun.COM }
13649517SBill.Taylor@Sun.COM
13659517SBill.Taylor@Sun.COM /*
13669517SBill.Taylor@Sun.COM * If the QP was already on the list, set 'qp_found' to TRUE. We still
13679517SBill.Taylor@Sun.COM * return SUCCESS in this case, but the qplist will not have been
13689517SBill.Taylor@Sun.COM * updated because the QP was already on the list.
13699517SBill.Taylor@Sun.COM */
13709517SBill.Taylor@Sun.COM if (qplist_indx < mcg->mcg_num_qps) {
13719517SBill.Taylor@Sun.COM *qp_found = 1;
13729517SBill.Taylor@Sun.COM } else {
13739517SBill.Taylor@Sun.COM /*
13749517SBill.Taylor@Sun.COM * Otherwise, append the new QP number to the end of the
13759517SBill.Taylor@Sun.COM * current QP list. Note: We will increment the "mcg_num_qps"
13769517SBill.Taylor@Sun.COM * field on the "shadow" MCG list entry later (after we know
13779517SBill.Taylor@Sun.COM * that all necessary Hermon firmware accesses have been
13789517SBill.Taylor@Sun.COM * successful).
13799517SBill.Taylor@Sun.COM *
13809517SBill.Taylor@Sun.COM * Set 'qp_found' to 0 so we know the QP was added on to the
13819517SBill.Taylor@Sun.COM * list for sure.
13829517SBill.Taylor@Sun.COM */
13839517SBill.Taylor@Sun.COM mcg_qplist[qplist_indx].qpn =
13849517SBill.Taylor@Sun.COM (qp->qp_qpnum | HERMON_MCG_QPN_BLOCK_LB);
13859517SBill.Taylor@Sun.COM *qp_found = 0;
13869517SBill.Taylor@Sun.COM }
13879517SBill.Taylor@Sun.COM
13889517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
13899517SBill.Taylor@Sun.COM }
13909517SBill.Taylor@Sun.COM
13919517SBill.Taylor@Sun.COM
13929517SBill.Taylor@Sun.COM
13939517SBill.Taylor@Sun.COM /*
13949517SBill.Taylor@Sun.COM * hermon_mcg_qplist_remove()
13959517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
13969517SBill.Taylor@Sun.COM */
13979517SBill.Taylor@Sun.COM static int
hermon_mcg_qplist_remove(hermon_mcghdl_t mcg,hermon_hw_mcg_qp_list_t * mcg_qplist,hermon_qphdl_t qp)13989517SBill.Taylor@Sun.COM hermon_mcg_qplist_remove(hermon_mcghdl_t mcg,
13999517SBill.Taylor@Sun.COM hermon_hw_mcg_qp_list_t *mcg_qplist, hermon_qphdl_t qp)
14009517SBill.Taylor@Sun.COM {
14019517SBill.Taylor@Sun.COM uint_t i, qplist_indx;
14029517SBill.Taylor@Sun.COM
14039517SBill.Taylor@Sun.COM /*
14049517SBill.Taylor@Sun.COM * Search the MCG QP list for a matching QPN. When
14059517SBill.Taylor@Sun.COM * it's found, we swap the last entry with the current
14069517SBill.Taylor@Sun.COM * one, set the last entry to zero, decrement the last
14079517SBill.Taylor@Sun.COM * entry, and return. If it's not found, then it's
14089517SBill.Taylor@Sun.COM * and error.
14099517SBill.Taylor@Sun.COM */
14109517SBill.Taylor@Sun.COM qplist_indx = mcg->mcg_num_qps;
14119517SBill.Taylor@Sun.COM for (i = 0; i < qplist_indx; i++) {
14129517SBill.Taylor@Sun.COM if (mcg_qplist[i].qpn == qp->qp_qpnum) {
14139517SBill.Taylor@Sun.COM mcg_qplist[i] = mcg_qplist[qplist_indx - 1];
14149517SBill.Taylor@Sun.COM mcg_qplist[qplist_indx - 1].qpn = 0;
14159517SBill.Taylor@Sun.COM
14169517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
14179517SBill.Taylor@Sun.COM }
14189517SBill.Taylor@Sun.COM }
14199517SBill.Taylor@Sun.COM
14209517SBill.Taylor@Sun.COM return (IBT_QP_HDL_INVALID);
14219517SBill.Taylor@Sun.COM }
14229517SBill.Taylor@Sun.COM
14239517SBill.Taylor@Sun.COM
14249517SBill.Taylor@Sun.COM /*
14259517SBill.Taylor@Sun.COM * hermon_mcg_walk_mgid_hash()
14269517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
14279517SBill.Taylor@Sun.COM */
14289517SBill.Taylor@Sun.COM static uint_t
hermon_mcg_walk_mgid_hash(hermon_state_t * state,uint64_t start_indx,ib_gid_t mgid,uint_t * p_indx)14299517SBill.Taylor@Sun.COM hermon_mcg_walk_mgid_hash(hermon_state_t *state, uint64_t start_indx,
14309517SBill.Taylor@Sun.COM ib_gid_t mgid, uint_t *p_indx)
14319517SBill.Taylor@Sun.COM {
14329517SBill.Taylor@Sun.COM hermon_mcghdl_t curr_mcghdl;
14339517SBill.Taylor@Sun.COM uint_t curr_indx, prev_indx;
14349517SBill.Taylor@Sun.COM
14359517SBill.Taylor@Sun.COM ASSERT(MUTEX_HELD(&state->hs_mcglock));
14369517SBill.Taylor@Sun.COM
14379517SBill.Taylor@Sun.COM /* Start at the head of the hash chain */
14389517SBill.Taylor@Sun.COM curr_indx = (uint_t)start_indx;
14399517SBill.Taylor@Sun.COM prev_indx = curr_indx;
14409517SBill.Taylor@Sun.COM curr_mcghdl = &state->hs_mcghdl[curr_indx];
14419517SBill.Taylor@Sun.COM
14429517SBill.Taylor@Sun.COM /* If the first entry in the chain has MGID == 0, then stop */
14439517SBill.Taylor@Sun.COM if ((curr_mcghdl->mcg_mgid_h == 0) &&
14449517SBill.Taylor@Sun.COM (curr_mcghdl->mcg_mgid_l == 0)) {
14459517SBill.Taylor@Sun.COM goto end_mgid_hash_walk;
14469517SBill.Taylor@Sun.COM }
14479517SBill.Taylor@Sun.COM
14489517SBill.Taylor@Sun.COM /* If the first entry in the chain matches the MGID, then stop */
14499517SBill.Taylor@Sun.COM if ((curr_mcghdl->mcg_mgid_h == mgid.gid_prefix) &&
14509517SBill.Taylor@Sun.COM (curr_mcghdl->mcg_mgid_l == mgid.gid_guid)) {
14519517SBill.Taylor@Sun.COM goto end_mgid_hash_walk;
14529517SBill.Taylor@Sun.COM }
14539517SBill.Taylor@Sun.COM
14549517SBill.Taylor@Sun.COM /* Otherwise, walk the hash chain looking for a match */
14559517SBill.Taylor@Sun.COM while (curr_mcghdl->mcg_next_indx != 0) {
14569517SBill.Taylor@Sun.COM prev_indx = curr_indx;
14579517SBill.Taylor@Sun.COM curr_indx = curr_mcghdl->mcg_next_indx;
14589517SBill.Taylor@Sun.COM curr_mcghdl = &state->hs_mcghdl[curr_indx];
14599517SBill.Taylor@Sun.COM
14609517SBill.Taylor@Sun.COM if ((curr_mcghdl->mcg_mgid_h == mgid.gid_prefix) &&
14619517SBill.Taylor@Sun.COM (curr_mcghdl->mcg_mgid_l == mgid.gid_guid)) {
14629517SBill.Taylor@Sun.COM break;
14639517SBill.Taylor@Sun.COM }
14649517SBill.Taylor@Sun.COM }
14659517SBill.Taylor@Sun.COM
14669517SBill.Taylor@Sun.COM end_mgid_hash_walk:
14679517SBill.Taylor@Sun.COM /*
14689517SBill.Taylor@Sun.COM * If necessary, return the index of the previous entry too. This
14699517SBill.Taylor@Sun.COM * is primarily used for detaching a QP from a multicast group. It
14709517SBill.Taylor@Sun.COM * may be necessary, in that case, to delete an MCG entry from the
14719517SBill.Taylor@Sun.COM * hash chain and having the index of the previous entry is helpful.
14729517SBill.Taylor@Sun.COM */
14739517SBill.Taylor@Sun.COM if (p_indx != NULL) {
14749517SBill.Taylor@Sun.COM *p_indx = prev_indx;
14759517SBill.Taylor@Sun.COM }
14769517SBill.Taylor@Sun.COM return (curr_indx);
14779517SBill.Taylor@Sun.COM }
14789517SBill.Taylor@Sun.COM
14799517SBill.Taylor@Sun.COM
14809517SBill.Taylor@Sun.COM /*
14819517SBill.Taylor@Sun.COM * hermon_mcg_setup_new_hdr()
14829517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
14839517SBill.Taylor@Sun.COM */
14849517SBill.Taylor@Sun.COM static void
hermon_mcg_setup_new_hdr(hermon_mcghdl_t mcg,hermon_hw_mcg_t * mcg_hdr,ib_gid_t mgid,hermon_rsrc_t * mcg_rsrc)14859517SBill.Taylor@Sun.COM hermon_mcg_setup_new_hdr(hermon_mcghdl_t mcg, hermon_hw_mcg_t *mcg_hdr,
14869517SBill.Taylor@Sun.COM ib_gid_t mgid, hermon_rsrc_t *mcg_rsrc)
14879517SBill.Taylor@Sun.COM {
14889517SBill.Taylor@Sun.COM /*
14899517SBill.Taylor@Sun.COM * Fill in the fields of the "shadow" entry used by software
14909517SBill.Taylor@Sun.COM * to track MCG hardware entry
14919517SBill.Taylor@Sun.COM */
14929517SBill.Taylor@Sun.COM mcg->mcg_mgid_h = mgid.gid_prefix;
14939517SBill.Taylor@Sun.COM mcg->mcg_mgid_l = mgid.gid_guid;
14949517SBill.Taylor@Sun.COM mcg->mcg_rsrcp = mcg_rsrc;
14959517SBill.Taylor@Sun.COM mcg->mcg_next_indx = 0;
14969517SBill.Taylor@Sun.COM mcg->mcg_num_qps = 0;
14979517SBill.Taylor@Sun.COM
14989517SBill.Taylor@Sun.COM /*
14999517SBill.Taylor@Sun.COM * Fill the header fields of the MCG entry (in the temporary copy)
15009517SBill.Taylor@Sun.COM */
15019517SBill.Taylor@Sun.COM mcg_hdr->mgid_h = mgid.gid_prefix;
15029517SBill.Taylor@Sun.COM mcg_hdr->mgid_l = mgid.gid_guid;
15039517SBill.Taylor@Sun.COM mcg_hdr->next_gid_indx = 0;
15049517SBill.Taylor@Sun.COM }
15059517SBill.Taylor@Sun.COM
15069517SBill.Taylor@Sun.COM
15079517SBill.Taylor@Sun.COM /*
15089517SBill.Taylor@Sun.COM * hermon_mcg_hash_list_remove()
15099517SBill.Taylor@Sun.COM * Context: Can be called only from user or kernel context.
15109517SBill.Taylor@Sun.COM */
15119517SBill.Taylor@Sun.COM static int
hermon_mcg_hash_list_remove(hermon_state_t * state,uint_t curr_indx,uint_t prev_indx,hermon_hw_mcg_t * mcg_entry)15129517SBill.Taylor@Sun.COM hermon_mcg_hash_list_remove(hermon_state_t *state, uint_t curr_indx,
15139517SBill.Taylor@Sun.COM uint_t prev_indx, hermon_hw_mcg_t *mcg_entry)
15149517SBill.Taylor@Sun.COM {
15159517SBill.Taylor@Sun.COM hermon_mcghdl_t curr_mcg, prev_mcg, next_mcg;
15169517SBill.Taylor@Sun.COM uint_t next_indx;
15179517SBill.Taylor@Sun.COM int status;
15189517SBill.Taylor@Sun.COM
15199517SBill.Taylor@Sun.COM /* Get the pointer to "shadow" list for current entry */
15209517SBill.Taylor@Sun.COM curr_mcg = &state->hs_mcghdl[curr_indx];
15219517SBill.Taylor@Sun.COM
15229517SBill.Taylor@Sun.COM /*
15239517SBill.Taylor@Sun.COM * If this is the first entry on a hash chain, then attempt to replace
15249517SBill.Taylor@Sun.COM * the entry with the next entry on the chain. If there are no
15259517SBill.Taylor@Sun.COM * subsequent entries on the chain, then this is the only entry and
15269517SBill.Taylor@Sun.COM * should be invalidated.
15279517SBill.Taylor@Sun.COM */
15289517SBill.Taylor@Sun.COM if (curr_indx == prev_indx) {
15299517SBill.Taylor@Sun.COM
15309517SBill.Taylor@Sun.COM /*
15319517SBill.Taylor@Sun.COM * If this is the only entry on the chain, then invalidate it.
15329517SBill.Taylor@Sun.COM * Note: Invalidating an MCG entry means writing all zeros
15339517SBill.Taylor@Sun.COM * to the entry. This is only necessary for those MCG
15349517SBill.Taylor@Sun.COM * entries that are the "head" entries of the individual hash
15359517SBill.Taylor@Sun.COM * chains. Regardless of whether this operation returns
15369517SBill.Taylor@Sun.COM * success or failure, return that result to the caller.
15379517SBill.Taylor@Sun.COM */
15389517SBill.Taylor@Sun.COM next_indx = curr_mcg->mcg_next_indx;
15399517SBill.Taylor@Sun.COM if (next_indx == 0) {
15409517SBill.Taylor@Sun.COM status = hermon_mcg_entry_invalidate(state, mcg_entry,
15419517SBill.Taylor@Sun.COM curr_indx);
15429517SBill.Taylor@Sun.COM bzero(curr_mcg, sizeof (struct hermon_sw_mcg_list_s));
15439517SBill.Taylor@Sun.COM return (status);
15449517SBill.Taylor@Sun.COM }
15459517SBill.Taylor@Sun.COM
15469517SBill.Taylor@Sun.COM /*
15479517SBill.Taylor@Sun.COM * Otherwise, this is just the first entry on the chain, so
15489517SBill.Taylor@Sun.COM * grab the next one
15499517SBill.Taylor@Sun.COM */
15509517SBill.Taylor@Sun.COM next_mcg = &state->hs_mcghdl[next_indx];
15519517SBill.Taylor@Sun.COM
15529517SBill.Taylor@Sun.COM /*
15539517SBill.Taylor@Sun.COM * Read the next MCG entry into the temporary MCG. Note:
15549517SBill.Taylor@Sun.COM * In general, this operation shouldn't fail. If it does,
15559517SBill.Taylor@Sun.COM * then it is an indication that something (probably in HW,
15569517SBill.Taylor@Sun.COM * but maybe in SW) has gone seriously wrong.
15579517SBill.Taylor@Sun.COM */
15589517SBill.Taylor@Sun.COM status = hermon_read_mgm_cmd_post(state, mcg_entry, next_indx,
15599517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
15609517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
15619517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to read MCG entry");
15629517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: READ_MGM command failed: "
15639517SBill.Taylor@Sun.COM "%08x\n", status);
15649517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
15659517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR,
15669517SBill.Taylor@Sun.COM HCA_ERR_SRV_LOST);
15679517SBill.Taylor@Sun.COM }
15689517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
15699517SBill.Taylor@Sun.COM }
15709517SBill.Taylor@Sun.COM
15719517SBill.Taylor@Sun.COM /*
15729517SBill.Taylor@Sun.COM * Copy/Write the temporary MCG back to the hardware MCG list
15739517SBill.Taylor@Sun.COM * using the current index. This essentially removes the
15749517SBill.Taylor@Sun.COM * current MCG entry from the list by writing over it with
15759517SBill.Taylor@Sun.COM * the next one. If this is successful, then we can do the
15769517SBill.Taylor@Sun.COM * same operation for the "shadow" list. And we can also
15779517SBill.Taylor@Sun.COM * free up the Hermon MCG entry resource that was associated
15789517SBill.Taylor@Sun.COM * with the (old) next entry. Note: In general, this
15799517SBill.Taylor@Sun.COM * operation shouldn't fail. If it does, then it is an
15809517SBill.Taylor@Sun.COM * indication that something (probably in HW, but maybe in SW)
15819517SBill.Taylor@Sun.COM * has gone seriously wrong.
15829517SBill.Taylor@Sun.COM */
15839517SBill.Taylor@Sun.COM status = hermon_write_mgm_cmd_post(state, mcg_entry, curr_indx,
15849517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
15859517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
15869517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to write MCG entry");
15879517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: WRITE_MGM command failed: "
15889517SBill.Taylor@Sun.COM "%08x\n", status);
15899517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
15909517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR,
15919517SBill.Taylor@Sun.COM HCA_ERR_SRV_LOST);
15929517SBill.Taylor@Sun.COM }
15939517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
15949517SBill.Taylor@Sun.COM }
15959517SBill.Taylor@Sun.COM
15969517SBill.Taylor@Sun.COM /*
15979517SBill.Taylor@Sun.COM * Copy all the software tracking information from the next
15989517SBill.Taylor@Sun.COM * entry on the "shadow" MCG list into the current entry on
15999517SBill.Taylor@Sun.COM * the list. Then invalidate (zero out) the other "shadow"
16009517SBill.Taylor@Sun.COM * list entry.
16019517SBill.Taylor@Sun.COM */
16029517SBill.Taylor@Sun.COM bcopy(next_mcg, curr_mcg, sizeof (struct hermon_sw_mcg_list_s));
16039517SBill.Taylor@Sun.COM bzero(next_mcg, sizeof (struct hermon_sw_mcg_list_s));
16049517SBill.Taylor@Sun.COM
16059517SBill.Taylor@Sun.COM /*
16069517SBill.Taylor@Sun.COM * Free up the Hermon MCG entry resource used by the "next"
16079517SBill.Taylor@Sun.COM * MCG entry. That resource is no longer needed by any
16089517SBill.Taylor@Sun.COM * MCG entry which is first on a hash chain (like the "next"
16099517SBill.Taylor@Sun.COM * entry has just become).
16109517SBill.Taylor@Sun.COM */
16119517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &curr_mcg->mcg_rsrcp);
16129517SBill.Taylor@Sun.COM
16139517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
16149517SBill.Taylor@Sun.COM }
16159517SBill.Taylor@Sun.COM
16169517SBill.Taylor@Sun.COM /*
16179517SBill.Taylor@Sun.COM * Else if this is the last entry on the hash chain (or a middle
16189517SBill.Taylor@Sun.COM * entry, then we update the previous entry's "next_gid_index" field
16199517SBill.Taylor@Sun.COM * to make it point instead to the next entry on the chain. By
16209517SBill.Taylor@Sun.COM * skipping over the removed entry in this way, we can then free up
16219517SBill.Taylor@Sun.COM * any resources associated with the current entry. Note: We don't
16229517SBill.Taylor@Sun.COM * need to invalidate the "skipped over" hardware entry because it
16239517SBill.Taylor@Sun.COM * will no be longer connected to any hash chains, and if/when it is
16249517SBill.Taylor@Sun.COM * finally re-used, it will be written with entirely new values.
16259517SBill.Taylor@Sun.COM */
16269517SBill.Taylor@Sun.COM
16279517SBill.Taylor@Sun.COM /*
16289517SBill.Taylor@Sun.COM * Read the next MCG entry into the temporary MCG. Note: In general,
16299517SBill.Taylor@Sun.COM * this operation shouldn't fail. If it does, then it is an
16309517SBill.Taylor@Sun.COM * indication that something (probably in HW, but maybe in SW) has
16319517SBill.Taylor@Sun.COM * gone seriously wrong.
16329517SBill.Taylor@Sun.COM */
16339517SBill.Taylor@Sun.COM status = hermon_read_mgm_cmd_post(state, mcg_entry, prev_indx,
16349517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
16359517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
16369517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to read MCG entry");
16379517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: READ_MGM command failed: %08x\n",
16389517SBill.Taylor@Sun.COM status);
16399517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
16409517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
16419517SBill.Taylor@Sun.COM }
16429517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
16439517SBill.Taylor@Sun.COM }
16449517SBill.Taylor@Sun.COM
16459517SBill.Taylor@Sun.COM /*
16469517SBill.Taylor@Sun.COM * Finally, we update the "next_gid_indx" field in the temporary MCG
16479517SBill.Taylor@Sun.COM * and attempt to write the entry back into the Hermon MCG table. If
16489517SBill.Taylor@Sun.COM * this succeeds, then we update the "shadow" list to reflect the
16499517SBill.Taylor@Sun.COM * change, free up the Hermon MCG entry resource that was associated
16509517SBill.Taylor@Sun.COM * with the current entry, and return success. Note: In general,
16519517SBill.Taylor@Sun.COM * this operation shouldn't fail. If it does, then it is an indication
16529517SBill.Taylor@Sun.COM * that something (probably in HW, but maybe in SW) has gone seriously
16539517SBill.Taylor@Sun.COM * wrong.
16549517SBill.Taylor@Sun.COM */
16559517SBill.Taylor@Sun.COM mcg_entry->next_gid_indx = curr_mcg->mcg_next_indx;
16569517SBill.Taylor@Sun.COM status = hermon_write_mgm_cmd_post(state, mcg_entry, prev_indx,
16579517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
16589517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
16599517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to write MCG entry");
16609517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: WRITE_MGM command failed: %08x\n",
16619517SBill.Taylor@Sun.COM status);
16629517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
16639517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR,
16649517SBill.Taylor@Sun.COM HCA_ERR_SRV_LOST);
16659517SBill.Taylor@Sun.COM }
16669517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
16679517SBill.Taylor@Sun.COM }
16689517SBill.Taylor@Sun.COM
16699517SBill.Taylor@Sun.COM /*
16709517SBill.Taylor@Sun.COM * Get the pointer to the "shadow" MCG list entry for the previous
16719517SBill.Taylor@Sun.COM * MCG. Update its "mcg_next_indx" to point to the next entry
16729517SBill.Taylor@Sun.COM * the one after the current entry. Note: This next index may be
16739517SBill.Taylor@Sun.COM * zero, indicating the end of the list.
16749517SBill.Taylor@Sun.COM */
16759517SBill.Taylor@Sun.COM prev_mcg = &state->hs_mcghdl[prev_indx];
16769517SBill.Taylor@Sun.COM prev_mcg->mcg_next_indx = curr_mcg->mcg_next_indx;
16779517SBill.Taylor@Sun.COM
16789517SBill.Taylor@Sun.COM /*
16799517SBill.Taylor@Sun.COM * Free up the Hermon MCG entry resource used by the current entry.
16809517SBill.Taylor@Sun.COM * This resource is no longer needed because the chain now skips over
16819517SBill.Taylor@Sun.COM * the current entry. Then invalidate (zero out) the current "shadow"
16829517SBill.Taylor@Sun.COM * list entry.
16839517SBill.Taylor@Sun.COM */
16849517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &curr_mcg->mcg_rsrcp);
16859517SBill.Taylor@Sun.COM bzero(curr_mcg, sizeof (struct hermon_sw_mcg_list_s));
16869517SBill.Taylor@Sun.COM
16879517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
16889517SBill.Taylor@Sun.COM }
16899517SBill.Taylor@Sun.COM
16909517SBill.Taylor@Sun.COM
16919517SBill.Taylor@Sun.COM /*
16929517SBill.Taylor@Sun.COM * hermon_mcg_entry_invalidate()
16939517SBill.Taylor@Sun.COM * Context: Can be called only from user or kernel context.
16949517SBill.Taylor@Sun.COM */
16959517SBill.Taylor@Sun.COM static int
hermon_mcg_entry_invalidate(hermon_state_t * state,hermon_hw_mcg_t * mcg_entry,uint_t indx)16969517SBill.Taylor@Sun.COM hermon_mcg_entry_invalidate(hermon_state_t *state, hermon_hw_mcg_t *mcg_entry,
16979517SBill.Taylor@Sun.COM uint_t indx)
16989517SBill.Taylor@Sun.COM {
16999517SBill.Taylor@Sun.COM int status;
17009517SBill.Taylor@Sun.COM
17019517SBill.Taylor@Sun.COM /*
17029517SBill.Taylor@Sun.COM * Invalidate the hardware MCG entry by zeroing out this temporary
17039517SBill.Taylor@Sun.COM * MCG and writing it the the hardware. Note: In general, this
17049517SBill.Taylor@Sun.COM * operation shouldn't fail. If it does, then it is an indication
17059517SBill.Taylor@Sun.COM * that something (probably in HW, but maybe in SW) has gone seriously
17069517SBill.Taylor@Sun.COM * wrong.
17079517SBill.Taylor@Sun.COM */
17089517SBill.Taylor@Sun.COM bzero(mcg_entry, HERMON_MCGMEM_SZ(state));
17099517SBill.Taylor@Sun.COM status = hermon_write_mgm_cmd_post(state, mcg_entry, indx,
17109517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
17119517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
17129517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to write MCG entry");
17139517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: WRITE_MGM command failed: %08x\n",
17149517SBill.Taylor@Sun.COM status);
17159517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
17169517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
17179517SBill.Taylor@Sun.COM }
17189517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
17199517SBill.Taylor@Sun.COM }
17209517SBill.Taylor@Sun.COM
17219517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
17229517SBill.Taylor@Sun.COM }
17239517SBill.Taylor@Sun.COM
17249517SBill.Taylor@Sun.COM
17259517SBill.Taylor@Sun.COM /*
17269517SBill.Taylor@Sun.COM * hermon_mgid_is_valid()
17279517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
17289517SBill.Taylor@Sun.COM */
17299517SBill.Taylor@Sun.COM static int
hermon_mgid_is_valid(ib_gid_t gid)17309517SBill.Taylor@Sun.COM hermon_mgid_is_valid(ib_gid_t gid)
17319517SBill.Taylor@Sun.COM {
17329517SBill.Taylor@Sun.COM uint_t topbits, flags, scope;
17339517SBill.Taylor@Sun.COM
17349517SBill.Taylor@Sun.COM /*
17359517SBill.Taylor@Sun.COM * According to IBA 1.1 specification (section 4.1.1) a valid
17369517SBill.Taylor@Sun.COM * "multicast GID" must have its top eight bits set to all ones
17379517SBill.Taylor@Sun.COM */
17389517SBill.Taylor@Sun.COM topbits = (gid.gid_prefix >> HERMON_MCG_TOPBITS_SHIFT) &
17399517SBill.Taylor@Sun.COM HERMON_MCG_TOPBITS_MASK;
17409517SBill.Taylor@Sun.COM if (topbits != HERMON_MCG_TOPBITS) {
17419517SBill.Taylor@Sun.COM return (0);
17429517SBill.Taylor@Sun.COM }
17439517SBill.Taylor@Sun.COM
17449517SBill.Taylor@Sun.COM /*
17459517SBill.Taylor@Sun.COM * The next 4 bits are the "flag" bits. These are valid only
17469517SBill.Taylor@Sun.COM * if they are "0" (which correspond to permanently assigned/
17479517SBill.Taylor@Sun.COM * "well-known" multicast GIDs) or "1" (for so-called "transient"
17489517SBill.Taylor@Sun.COM * multicast GIDs). All other values are reserved.
17499517SBill.Taylor@Sun.COM */
17509517SBill.Taylor@Sun.COM flags = (gid.gid_prefix >> HERMON_MCG_FLAGS_SHIFT) &
17519517SBill.Taylor@Sun.COM HERMON_MCG_FLAGS_MASK;
17529517SBill.Taylor@Sun.COM if (!((flags == HERMON_MCG_FLAGS_PERM) ||
17539517SBill.Taylor@Sun.COM (flags == HERMON_MCG_FLAGS_NONPERM))) {
17549517SBill.Taylor@Sun.COM return (0);
17559517SBill.Taylor@Sun.COM }
17569517SBill.Taylor@Sun.COM
17579517SBill.Taylor@Sun.COM /*
17589517SBill.Taylor@Sun.COM * The next 4 bits are the "scope" bits. These are valid only
17599517SBill.Taylor@Sun.COM * if they are "2" (Link-local), "5" (Site-local), "8"
17609517SBill.Taylor@Sun.COM * (Organization-local) or "E" (Global). All other values
17619517SBill.Taylor@Sun.COM * are reserved (or currently unassigned).
17629517SBill.Taylor@Sun.COM */
17639517SBill.Taylor@Sun.COM scope = (gid.gid_prefix >> HERMON_MCG_SCOPE_SHIFT) &
17649517SBill.Taylor@Sun.COM HERMON_MCG_SCOPE_MASK;
17659517SBill.Taylor@Sun.COM if (!((scope == HERMON_MCG_SCOPE_LINKLOC) ||
17669517SBill.Taylor@Sun.COM (scope == HERMON_MCG_SCOPE_SITELOC) ||
17679517SBill.Taylor@Sun.COM (scope == HERMON_MCG_SCOPE_ORGLOC) ||
17689517SBill.Taylor@Sun.COM (scope == HERMON_MCG_SCOPE_GLOBAL))) {
17699517SBill.Taylor@Sun.COM return (0);
17709517SBill.Taylor@Sun.COM }
17719517SBill.Taylor@Sun.COM
17729517SBill.Taylor@Sun.COM /*
17739517SBill.Taylor@Sun.COM * If it passes all of the above checks, then we will consider it
17749517SBill.Taylor@Sun.COM * a valid multicast GID.
17759517SBill.Taylor@Sun.COM */
17769517SBill.Taylor@Sun.COM return (1);
17779517SBill.Taylor@Sun.COM }
17789517SBill.Taylor@Sun.COM
17799517SBill.Taylor@Sun.COM
17809517SBill.Taylor@Sun.COM /*
17819517SBill.Taylor@Sun.COM * hermon_mlid_is_valid()
17829517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
17839517SBill.Taylor@Sun.COM */
17849517SBill.Taylor@Sun.COM static int
hermon_mlid_is_valid(ib_lid_t lid)17859517SBill.Taylor@Sun.COM hermon_mlid_is_valid(ib_lid_t lid)
17869517SBill.Taylor@Sun.COM {
17879517SBill.Taylor@Sun.COM /*
17889517SBill.Taylor@Sun.COM * According to IBA 1.1 specification (section 4.1.1) a valid
17899517SBill.Taylor@Sun.COM * "multicast DLID" must be between 0xC000 and 0xFFFE.
17909517SBill.Taylor@Sun.COM */
17919517SBill.Taylor@Sun.COM if ((lid < IB_LID_MC_FIRST) || (lid > IB_LID_MC_LAST)) {
17929517SBill.Taylor@Sun.COM return (0);
17939517SBill.Taylor@Sun.COM }
17949517SBill.Taylor@Sun.COM
17959517SBill.Taylor@Sun.COM return (1);
17969517SBill.Taylor@Sun.COM }
17979517SBill.Taylor@Sun.COM
17989517SBill.Taylor@Sun.COM
17999517SBill.Taylor@Sun.COM /*
18009517SBill.Taylor@Sun.COM * hermon_pd_alloc()
18019517SBill.Taylor@Sun.COM * Context: Can be called only from user or kernel context.
18029517SBill.Taylor@Sun.COM */
18039517SBill.Taylor@Sun.COM int
hermon_pd_alloc(hermon_state_t * state,hermon_pdhdl_t * pdhdl,uint_t sleepflag)18049517SBill.Taylor@Sun.COM hermon_pd_alloc(hermon_state_t *state, hermon_pdhdl_t *pdhdl, uint_t sleepflag)
18059517SBill.Taylor@Sun.COM {
18069517SBill.Taylor@Sun.COM hermon_rsrc_t *rsrc;
18079517SBill.Taylor@Sun.COM hermon_pdhdl_t pd;
18089517SBill.Taylor@Sun.COM int status;
18099517SBill.Taylor@Sun.COM
18109517SBill.Taylor@Sun.COM /*
18119517SBill.Taylor@Sun.COM * Allocate the software structure for tracking the protection domain
18129517SBill.Taylor@Sun.COM * (i.e. the Hermon Protection Domain handle). By default each PD
18139517SBill.Taylor@Sun.COM * structure will have a unique PD number assigned to it. All that
18149517SBill.Taylor@Sun.COM * is necessary is for software to initialize the PD reference count
18159517SBill.Taylor@Sun.COM * (to zero) and return success.
18169517SBill.Taylor@Sun.COM */
18179517SBill.Taylor@Sun.COM status = hermon_rsrc_alloc(state, HERMON_PDHDL, 1, sleepflag, &rsrc);
18189517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
18199517SBill.Taylor@Sun.COM return (IBT_INSUFF_RESOURCE);
18209517SBill.Taylor@Sun.COM }
18219517SBill.Taylor@Sun.COM pd = (hermon_pdhdl_t)rsrc->hr_addr;
18229517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*pd))
18239517SBill.Taylor@Sun.COM
18249517SBill.Taylor@Sun.COM pd->pd_refcnt = 0;
18259517SBill.Taylor@Sun.COM *pdhdl = pd;
18269517SBill.Taylor@Sun.COM
18279517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
18289517SBill.Taylor@Sun.COM }
18299517SBill.Taylor@Sun.COM
18309517SBill.Taylor@Sun.COM
18319517SBill.Taylor@Sun.COM /*
18329517SBill.Taylor@Sun.COM * hermon_pd_free()
18339517SBill.Taylor@Sun.COM * Context: Can be called only from user or kernel context.
18349517SBill.Taylor@Sun.COM */
18359517SBill.Taylor@Sun.COM int
hermon_pd_free(hermon_state_t * state,hermon_pdhdl_t * pdhdl)18369517SBill.Taylor@Sun.COM hermon_pd_free(hermon_state_t *state, hermon_pdhdl_t *pdhdl)
18379517SBill.Taylor@Sun.COM {
18389517SBill.Taylor@Sun.COM hermon_rsrc_t *rsrc;
18399517SBill.Taylor@Sun.COM hermon_pdhdl_t pd;
18409517SBill.Taylor@Sun.COM
18419517SBill.Taylor@Sun.COM /*
18429517SBill.Taylor@Sun.COM * Pull all the necessary information from the Hermon Protection Domain
18439517SBill.Taylor@Sun.COM * handle. This is necessary here because the resource for the
18449517SBill.Taylor@Sun.COM * PD is going to be freed up as part of this operation.
18459517SBill.Taylor@Sun.COM */
18469517SBill.Taylor@Sun.COM pd = *pdhdl;
18479517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*pd))
18489517SBill.Taylor@Sun.COM rsrc = pd->pd_rsrcp;
18499517SBill.Taylor@Sun.COM
18509517SBill.Taylor@Sun.COM /*
18519517SBill.Taylor@Sun.COM * Check the PD reference count. If the reference count is non-zero,
18529517SBill.Taylor@Sun.COM * then it means that this protection domain is still referenced by
18539517SBill.Taylor@Sun.COM * some memory region, queue pair, address handle, or other IB object
18549517SBill.Taylor@Sun.COM * If it is non-zero, then return an error. Otherwise, free the
18559517SBill.Taylor@Sun.COM * Hermon resource and return success.
18569517SBill.Taylor@Sun.COM */
18579517SBill.Taylor@Sun.COM if (pd->pd_refcnt != 0) {
18589517SBill.Taylor@Sun.COM return (IBT_PD_IN_USE);
18599517SBill.Taylor@Sun.COM }
18609517SBill.Taylor@Sun.COM
18619517SBill.Taylor@Sun.COM /* Free the Hermon Protection Domain handle */
18629517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &rsrc);
18639517SBill.Taylor@Sun.COM
18649517SBill.Taylor@Sun.COM /* Set the pdhdl pointer to NULL and return success */
18659517SBill.Taylor@Sun.COM *pdhdl = (hermon_pdhdl_t)NULL;
18669517SBill.Taylor@Sun.COM
18679517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
18689517SBill.Taylor@Sun.COM }
18699517SBill.Taylor@Sun.COM
18709517SBill.Taylor@Sun.COM
18719517SBill.Taylor@Sun.COM /*
18729517SBill.Taylor@Sun.COM * hermon_pd_refcnt_inc()
18739517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
18749517SBill.Taylor@Sun.COM */
18759517SBill.Taylor@Sun.COM void
hermon_pd_refcnt_inc(hermon_pdhdl_t pd)18769517SBill.Taylor@Sun.COM hermon_pd_refcnt_inc(hermon_pdhdl_t pd)
18779517SBill.Taylor@Sun.COM {
18789517SBill.Taylor@Sun.COM /* Increment the protection domain's reference count */
18799517SBill.Taylor@Sun.COM atomic_inc_32(&pd->pd_refcnt);
18809517SBill.Taylor@Sun.COM }
18819517SBill.Taylor@Sun.COM
18829517SBill.Taylor@Sun.COM
18839517SBill.Taylor@Sun.COM /*
18849517SBill.Taylor@Sun.COM * hermon_pd_refcnt_dec()
18859517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
18869517SBill.Taylor@Sun.COM */
18879517SBill.Taylor@Sun.COM void
hermon_pd_refcnt_dec(hermon_pdhdl_t pd)18889517SBill.Taylor@Sun.COM hermon_pd_refcnt_dec(hermon_pdhdl_t pd)
18899517SBill.Taylor@Sun.COM {
18909517SBill.Taylor@Sun.COM /* Decrement the protection domain's reference count */
18919517SBill.Taylor@Sun.COM atomic_dec_32(&pd->pd_refcnt);
18929517SBill.Taylor@Sun.COM }
18939517SBill.Taylor@Sun.COM
18949517SBill.Taylor@Sun.COM
18959517SBill.Taylor@Sun.COM /*
18969517SBill.Taylor@Sun.COM * hermon_port_query()
18979517SBill.Taylor@Sun.COM * Context: Can be called only from user or kernel context.
18989517SBill.Taylor@Sun.COM */
18999517SBill.Taylor@Sun.COM int
hermon_port_query(hermon_state_t * state,uint_t port,ibt_hca_portinfo_t * pi)19009517SBill.Taylor@Sun.COM hermon_port_query(hermon_state_t *state, uint_t port, ibt_hca_portinfo_t *pi)
19019517SBill.Taylor@Sun.COM {
19029517SBill.Taylor@Sun.COM sm_portinfo_t portinfo;
19039517SBill.Taylor@Sun.COM sm_guidinfo_t guidinfo;
19049517SBill.Taylor@Sun.COM sm_pkey_table_t pkeytable;
19059517SBill.Taylor@Sun.COM ib_gid_t *sgid;
19069517SBill.Taylor@Sun.COM uint_t sgid_max, pkey_max, tbl_size;
19079517SBill.Taylor@Sun.COM int i, j, indx, status;
19089517SBill.Taylor@Sun.COM ib_pkey_t *pkeyp;
19099517SBill.Taylor@Sun.COM ib_guid_t *guidp;
19109517SBill.Taylor@Sun.COM
19119517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*pi))
19129517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*state))
19139517SBill.Taylor@Sun.COM
19149517SBill.Taylor@Sun.COM /* Validate that specified port number is legal */
19159517SBill.Taylor@Sun.COM if (!hermon_portnum_is_valid(state, port)) {
19169517SBill.Taylor@Sun.COM return (IBT_HCA_PORT_INVALID);
19179517SBill.Taylor@Sun.COM }
19189517SBill.Taylor@Sun.COM pkeyp = state->hs_pkey[port - 1];
19199517SBill.Taylor@Sun.COM guidp = state->hs_guid[port - 1];
19209517SBill.Taylor@Sun.COM
19219517SBill.Taylor@Sun.COM /*
19229517SBill.Taylor@Sun.COM * We use the Hermon MAD_IFC command to post a GetPortInfo MAD
19239517SBill.Taylor@Sun.COM * to the firmware (for the specified port number). This returns
19249517SBill.Taylor@Sun.COM * a full PortInfo MAD (in "portinfo") which we subsequently
19259517SBill.Taylor@Sun.COM * parse to fill in the "ibt_hca_portinfo_t" structure returned
19269517SBill.Taylor@Sun.COM * to the IBTF.
19279517SBill.Taylor@Sun.COM */
19289517SBill.Taylor@Sun.COM status = hermon_getportinfo_cmd_post(state, port,
19299517SBill.Taylor@Sun.COM HERMON_SLEEPFLAG_FOR_CONTEXT(), &portinfo);
19309517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
19319517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: GetPortInfo (port %02d) command "
19329517SBill.Taylor@Sun.COM "failed: %08x\n", port, status);
19339517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
19349517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
19359517SBill.Taylor@Sun.COM }
19369517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
19379517SBill.Taylor@Sun.COM }
19389517SBill.Taylor@Sun.COM
19399517SBill.Taylor@Sun.COM /*
19409517SBill.Taylor@Sun.COM * Parse the PortInfo MAD and fill in the IBTF structure
19419517SBill.Taylor@Sun.COM */
19429517SBill.Taylor@Sun.COM pi->p_base_lid = portinfo.LID;
19439517SBill.Taylor@Sun.COM pi->p_qkey_violations = portinfo.Q_KeyViolations;
19449517SBill.Taylor@Sun.COM pi->p_pkey_violations = portinfo.P_KeyViolations;
19459517SBill.Taylor@Sun.COM pi->p_sm_sl = portinfo.MasterSMSL;
19469517SBill.Taylor@Sun.COM pi->p_sm_lid = portinfo.MasterSMLID;
19479517SBill.Taylor@Sun.COM pi->p_linkstate = portinfo.PortState;
19489517SBill.Taylor@Sun.COM pi->p_port_num = portinfo.LocalPortNum;
19499673SBill.Taylor@Sun.COM pi->p_phys_state = portinfo.PortPhysicalState;
19509673SBill.Taylor@Sun.COM pi->p_width_supported = portinfo.LinkWidthSupported;
19519673SBill.Taylor@Sun.COM pi->p_width_enabled = portinfo.LinkWidthEnabled;
19529673SBill.Taylor@Sun.COM pi->p_width_active = portinfo.LinkWidthActive;
19539673SBill.Taylor@Sun.COM pi->p_speed_supported = portinfo.LinkSpeedSupported;
19549673SBill.Taylor@Sun.COM pi->p_speed_enabled = portinfo.LinkSpeedEnabled;
19559673SBill.Taylor@Sun.COM pi->p_speed_active = portinfo.LinkSpeedActive;
19569517SBill.Taylor@Sun.COM pi->p_mtu = portinfo.MTUCap;
19579517SBill.Taylor@Sun.COM pi->p_lmc = portinfo.LMC;
19589517SBill.Taylor@Sun.COM pi->p_max_vl = portinfo.VLCap;
19599517SBill.Taylor@Sun.COM pi->p_subnet_timeout = portinfo.SubnetTimeOut;
19609517SBill.Taylor@Sun.COM pi->p_msg_sz = ((uint32_t)1 << HERMON_QP_LOG_MAX_MSGSZ);
19619517SBill.Taylor@Sun.COM tbl_size = state->hs_cfg_profile->cp_log_max_gidtbl;
19629517SBill.Taylor@Sun.COM pi->p_sgid_tbl_sz = (1 << tbl_size);
19639517SBill.Taylor@Sun.COM tbl_size = state->hs_cfg_profile->cp_log_max_pkeytbl;
19649517SBill.Taylor@Sun.COM pi->p_pkey_tbl_sz = (1 << tbl_size);
19659517SBill.Taylor@Sun.COM state->hs_sn_prefix[port - 1] = portinfo.GidPrefix;
19669517SBill.Taylor@Sun.COM
19679517SBill.Taylor@Sun.COM /*
19689517SBill.Taylor@Sun.COM * Convert InfiniBand-defined port capability flags to the format
19699517SBill.Taylor@Sun.COM * specified by the IBTF
19709517SBill.Taylor@Sun.COM */
19719517SBill.Taylor@Sun.COM if (portinfo.CapabilityMask & SM_CAP_MASK_IS_SM)
19729517SBill.Taylor@Sun.COM pi->p_capabilities |= IBT_PORT_CAP_SM;
19739517SBill.Taylor@Sun.COM if (portinfo.CapabilityMask & SM_CAP_MASK_IS_SM_DISABLED)
19749517SBill.Taylor@Sun.COM pi->p_capabilities |= IBT_PORT_CAP_SM_DISABLED;
19759517SBill.Taylor@Sun.COM if (portinfo.CapabilityMask & SM_CAP_MASK_IS_SNMP_SUPPD)
19769517SBill.Taylor@Sun.COM pi->p_capabilities |= IBT_PORT_CAP_SNMP_TUNNEL;
19779517SBill.Taylor@Sun.COM if (portinfo.CapabilityMask & SM_CAP_MASK_IS_DM_SUPPD)
19789517SBill.Taylor@Sun.COM pi->p_capabilities |= IBT_PORT_CAP_DM;
19799517SBill.Taylor@Sun.COM if (portinfo.CapabilityMask & SM_CAP_MASK_IS_VM_SUPPD)
19809517SBill.Taylor@Sun.COM pi->p_capabilities |= IBT_PORT_CAP_VENDOR;
19819891SRajkumar.Sivaprakasam@Sun.COM if (portinfo.CapabilityMask & SM_CAP_MASK_IS_CLNT_REREG_SUPPD)
19829891SRajkumar.Sivaprakasam@Sun.COM pi->p_capabilities |= IBT_PORT_CAP_CLNT_REREG;
19839517SBill.Taylor@Sun.COM
19849517SBill.Taylor@Sun.COM /*
19859517SBill.Taylor@Sun.COM * Fill in the SGID table. Since the only access to the Hermon
19869517SBill.Taylor@Sun.COM * GID tables is through the firmware's MAD_IFC interface, we
19879517SBill.Taylor@Sun.COM * post as many GetGUIDInfo MADs as necessary to read in the entire
19889517SBill.Taylor@Sun.COM * contents of the SGID table (for the specified port). Note: The
19899517SBill.Taylor@Sun.COM * GetGUIDInfo command only gets eight GUIDs per operation. These
19909517SBill.Taylor@Sun.COM * GUIDs are then appended to the GID prefix for the port (from the
19919517SBill.Taylor@Sun.COM * GetPortInfo above) to form the entire SGID table.
19929517SBill.Taylor@Sun.COM */
19939517SBill.Taylor@Sun.COM for (i = 0; i < pi->p_sgid_tbl_sz; i += 8) {
19949517SBill.Taylor@Sun.COM status = hermon_getguidinfo_cmd_post(state, port, i >> 3,
19959517SBill.Taylor@Sun.COM HERMON_SLEEPFLAG_FOR_CONTEXT(), &guidinfo);
19969517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
19979517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: GetGUIDInfo (port %02d) "
19989517SBill.Taylor@Sun.COM "command failed: %08x\n", port, status);
19999517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
20009517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR,
20019517SBill.Taylor@Sun.COM HCA_ERR_SRV_LOST);
20029517SBill.Taylor@Sun.COM }
20039517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
20049517SBill.Taylor@Sun.COM }
20059517SBill.Taylor@Sun.COM
20069517SBill.Taylor@Sun.COM /* Figure out how many of the entries are valid */
20079517SBill.Taylor@Sun.COM sgid_max = min((pi->p_sgid_tbl_sz - i), 8);
20089517SBill.Taylor@Sun.COM for (j = 0; j < sgid_max; j++) {
20099517SBill.Taylor@Sun.COM indx = (i + j);
20109517SBill.Taylor@Sun.COM sgid = &pi->p_sgid_tbl[indx];
20119517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sgid))
20129517SBill.Taylor@Sun.COM sgid->gid_prefix = portinfo.GidPrefix;
20139517SBill.Taylor@Sun.COM guidp[indx] = sgid->gid_guid =
20149517SBill.Taylor@Sun.COM guidinfo.GUIDBlocks[j];
20159517SBill.Taylor@Sun.COM }
20169517SBill.Taylor@Sun.COM }
20179517SBill.Taylor@Sun.COM
20189517SBill.Taylor@Sun.COM /*
20199517SBill.Taylor@Sun.COM * Fill in the PKey table. Just as for the GID tables above, the
20209517SBill.Taylor@Sun.COM * only access to the Hermon PKey tables is through the firmware's
20219517SBill.Taylor@Sun.COM * MAD_IFC interface. We post as many GetPKeyTable MADs as necessary
20229517SBill.Taylor@Sun.COM * to read in the entire contents of the PKey table (for the specified
20239517SBill.Taylor@Sun.COM * port). Note: The GetPKeyTable command only gets 32 PKeys per
20249517SBill.Taylor@Sun.COM * operation.
20259517SBill.Taylor@Sun.COM */
20269517SBill.Taylor@Sun.COM for (i = 0; i < pi->p_pkey_tbl_sz; i += 32) {
20279517SBill.Taylor@Sun.COM status = hermon_getpkeytable_cmd_post(state, port, i,
20289517SBill.Taylor@Sun.COM HERMON_SLEEPFLAG_FOR_CONTEXT(), &pkeytable);
20299517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
20309517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: GetPKeyTable (port %02d) "
20319517SBill.Taylor@Sun.COM "command failed: %08x\n", port, status);
20329517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
20339517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR,
20349517SBill.Taylor@Sun.COM HCA_ERR_SRV_LOST);
20359517SBill.Taylor@Sun.COM }
20369517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
20379517SBill.Taylor@Sun.COM }
20389517SBill.Taylor@Sun.COM
20399517SBill.Taylor@Sun.COM /* Figure out how many of the entries are valid */
20409517SBill.Taylor@Sun.COM pkey_max = min((pi->p_pkey_tbl_sz - i), 32);
20419517SBill.Taylor@Sun.COM for (j = 0; j < pkey_max; j++) {
20429517SBill.Taylor@Sun.COM indx = (i + j);
20439517SBill.Taylor@Sun.COM pkeyp[indx] = pi->p_pkey_tbl[indx] =
20449517SBill.Taylor@Sun.COM pkeytable.P_KeyTableBlocks[j];
20459517SBill.Taylor@Sun.COM }
20469517SBill.Taylor@Sun.COM }
20479517SBill.Taylor@Sun.COM
20489517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
20499517SBill.Taylor@Sun.COM }
20509517SBill.Taylor@Sun.COM
20519517SBill.Taylor@Sun.COM
20529517SBill.Taylor@Sun.COM /*
20539517SBill.Taylor@Sun.COM * hermon_port_modify()
20549517SBill.Taylor@Sun.COM * Context: Can be called only from user or kernel context.
20559517SBill.Taylor@Sun.COM */
20569517SBill.Taylor@Sun.COM /* ARGSUSED */
20579517SBill.Taylor@Sun.COM int
hermon_port_modify(hermon_state_t * state,uint8_t port,ibt_port_modify_flags_t flags,uint8_t init_type)20589517SBill.Taylor@Sun.COM hermon_port_modify(hermon_state_t *state, uint8_t port,
20599517SBill.Taylor@Sun.COM ibt_port_modify_flags_t flags, uint8_t init_type)
20609517SBill.Taylor@Sun.COM {
20619517SBill.Taylor@Sun.COM sm_portinfo_t portinfo;
20629517SBill.Taylor@Sun.COM uint32_t capmask;
20639517SBill.Taylor@Sun.COM int status;
20649517SBill.Taylor@Sun.COM hermon_hw_set_port_t set_port;
20659517SBill.Taylor@Sun.COM
20669517SBill.Taylor@Sun.COM /*
20679517SBill.Taylor@Sun.COM * Return an error if either of the unsupported flags are set
20689517SBill.Taylor@Sun.COM */
20699517SBill.Taylor@Sun.COM if ((flags & IBT_PORT_SHUTDOWN) ||
20709517SBill.Taylor@Sun.COM (flags & IBT_PORT_SET_INIT_TYPE)) {
20719517SBill.Taylor@Sun.COM return (IBT_NOT_SUPPORTED);
20729517SBill.Taylor@Sun.COM }
20739517SBill.Taylor@Sun.COM
20749517SBill.Taylor@Sun.COM bzero(&set_port, sizeof (set_port));
20759517SBill.Taylor@Sun.COM
20769517SBill.Taylor@Sun.COM /*
20779517SBill.Taylor@Sun.COM * Determine whether we are trying to reset the QKey counter
20789517SBill.Taylor@Sun.COM */
20799517SBill.Taylor@Sun.COM if (flags & IBT_PORT_RESET_QKEY)
20809517SBill.Taylor@Sun.COM set_port.rqk = 1;
20819517SBill.Taylor@Sun.COM
20829517SBill.Taylor@Sun.COM /* Validate that specified port number is legal */
20839517SBill.Taylor@Sun.COM if (!hermon_portnum_is_valid(state, port)) {
20849517SBill.Taylor@Sun.COM return (IBT_HCA_PORT_INVALID);
20859517SBill.Taylor@Sun.COM }
20869517SBill.Taylor@Sun.COM
20879517SBill.Taylor@Sun.COM /*
20889517SBill.Taylor@Sun.COM * Use the Hermon MAD_IFC command to post a GetPortInfo MAD to the
20899517SBill.Taylor@Sun.COM * firmware (for the specified port number). This returns a full
20909517SBill.Taylor@Sun.COM * PortInfo MAD (in "portinfo") from which we pull the current
20919517SBill.Taylor@Sun.COM * capability mask. We then modify the capability mask as directed
20929517SBill.Taylor@Sun.COM * by the "pmod_flags" field, and write the updated capability mask
20939517SBill.Taylor@Sun.COM * using the Hermon SET_IB command (below).
20949517SBill.Taylor@Sun.COM */
20959517SBill.Taylor@Sun.COM status = hermon_getportinfo_cmd_post(state, port,
20969517SBill.Taylor@Sun.COM HERMON_SLEEPFLAG_FOR_CONTEXT(), &portinfo);
20979517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
20989517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
20999517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
21009517SBill.Taylor@Sun.COM }
21019517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
21029517SBill.Taylor@Sun.COM }
21039517SBill.Taylor@Sun.COM
21049517SBill.Taylor@Sun.COM /*
21059517SBill.Taylor@Sun.COM * Convert InfiniBand-defined port capability flags to the format
21069517SBill.Taylor@Sun.COM * specified by the IBTF. Specifically, we modify the capability
21079517SBill.Taylor@Sun.COM * mask based on the specified values.
21089517SBill.Taylor@Sun.COM */
21099517SBill.Taylor@Sun.COM capmask = portinfo.CapabilityMask;
21109517SBill.Taylor@Sun.COM
21119517SBill.Taylor@Sun.COM if (flags & IBT_PORT_RESET_SM)
21129517SBill.Taylor@Sun.COM capmask &= ~SM_CAP_MASK_IS_SM;
21139517SBill.Taylor@Sun.COM else if (flags & IBT_PORT_SET_SM)
21149517SBill.Taylor@Sun.COM capmask |= SM_CAP_MASK_IS_SM;
21159517SBill.Taylor@Sun.COM
21169517SBill.Taylor@Sun.COM if (flags & IBT_PORT_RESET_SNMP)
21179517SBill.Taylor@Sun.COM capmask &= ~SM_CAP_MASK_IS_SNMP_SUPPD;
21189517SBill.Taylor@Sun.COM else if (flags & IBT_PORT_SET_SNMP)
21199517SBill.Taylor@Sun.COM capmask |= SM_CAP_MASK_IS_SNMP_SUPPD;
21209517SBill.Taylor@Sun.COM
21219517SBill.Taylor@Sun.COM if (flags & IBT_PORT_RESET_DEVMGT)
21229517SBill.Taylor@Sun.COM capmask &= ~SM_CAP_MASK_IS_DM_SUPPD;
21239517SBill.Taylor@Sun.COM else if (flags & IBT_PORT_SET_DEVMGT)
21249517SBill.Taylor@Sun.COM capmask |= SM_CAP_MASK_IS_DM_SUPPD;
21259517SBill.Taylor@Sun.COM
21269517SBill.Taylor@Sun.COM if (flags & IBT_PORT_RESET_VENDOR)
21279517SBill.Taylor@Sun.COM capmask &= ~SM_CAP_MASK_IS_VM_SUPPD;
21289517SBill.Taylor@Sun.COM else if (flags & IBT_PORT_SET_VENDOR)
21299517SBill.Taylor@Sun.COM capmask |= SM_CAP_MASK_IS_VM_SUPPD;
21309517SBill.Taylor@Sun.COM
21319517SBill.Taylor@Sun.COM set_port.cap_mask = capmask;
21329517SBill.Taylor@Sun.COM
21339517SBill.Taylor@Sun.COM /*
21349517SBill.Taylor@Sun.COM * Use the Hermon SET_PORT command to update the capability mask and
21359517SBill.Taylor@Sun.COM * (possibly) reset the QKey violation counter for the specified port.
21369517SBill.Taylor@Sun.COM * Note: In general, this operation shouldn't fail. If it does, then
21379517SBill.Taylor@Sun.COM * it is an indication that something (probably in HW, but maybe in
21389517SBill.Taylor@Sun.COM * SW) has gone seriously wrong.
21399517SBill.Taylor@Sun.COM */
21409517SBill.Taylor@Sun.COM status = hermon_set_port_cmd_post(state, &set_port, port,
21419517SBill.Taylor@Sun.COM HERMON_SLEEPFLAG_FOR_CONTEXT());
21429517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
21439517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to modify port capabilities");
21449517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: SET_IB (port %02d) command failed: "
21459517SBill.Taylor@Sun.COM "%08x\n", port, status);
21469517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
21479517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
21489517SBill.Taylor@Sun.COM }
21499517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
21509517SBill.Taylor@Sun.COM }
21519517SBill.Taylor@Sun.COM
21529517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
21539517SBill.Taylor@Sun.COM }
21549517SBill.Taylor@Sun.COM
21559517SBill.Taylor@Sun.COM
21569517SBill.Taylor@Sun.COM /*
21579517SBill.Taylor@Sun.COM * hermon_set_addr_path()
21589517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
21599517SBill.Taylor@Sun.COM *
21609517SBill.Taylor@Sun.COM * Note: This routine is used for two purposes. It is used to fill in the
21619517SBill.Taylor@Sun.COM * Hermon UDAV fields, and it is used to fill in the address path information
21629517SBill.Taylor@Sun.COM * for QPs. Because the two Hermon structures are similar, common fields can
21639517SBill.Taylor@Sun.COM * be filled in here. Because they are different, however, we pass
21649517SBill.Taylor@Sun.COM * an additional flag to indicate which type is being filled and do each one
21659517SBill.Taylor@Sun.COM * uniquely
21669517SBill.Taylor@Sun.COM */
21679517SBill.Taylor@Sun.COM
21689517SBill.Taylor@Sun.COM int hermon_srate_override = -1; /* allows ease of testing */
21699517SBill.Taylor@Sun.COM
21709517SBill.Taylor@Sun.COM int
hermon_set_addr_path(hermon_state_t * state,ibt_adds_vect_t * av,hermon_hw_addr_path_t * path,uint_t type)21719517SBill.Taylor@Sun.COM hermon_set_addr_path(hermon_state_t *state, ibt_adds_vect_t *av,
21729517SBill.Taylor@Sun.COM hermon_hw_addr_path_t *path, uint_t type)
21739517SBill.Taylor@Sun.COM {
21749517SBill.Taylor@Sun.COM uint_t gidtbl_sz;
21759517SBill.Taylor@Sun.COM hermon_hw_udav_t *udav;
21769517SBill.Taylor@Sun.COM
21779517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*av))
21789517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*path))
21799517SBill.Taylor@Sun.COM
21809517SBill.Taylor@Sun.COM udav = (hermon_hw_udav_t *)(void *)path;
21819517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*udav))
21829517SBill.Taylor@Sun.COM path->mlid = av->av_src_path;
21839517SBill.Taylor@Sun.COM path->rlid = av->av_dlid;
21849517SBill.Taylor@Sun.COM
21859580SBill.Taylor@Sun.COM switch (av->av_srate) {
21869580SBill.Taylor@Sun.COM case IBT_SRATE_2: /* 1xSDR-2.5Gb/s injection rate */
21879580SBill.Taylor@Sun.COM path->max_stat_rate = 7; break;
21889580SBill.Taylor@Sun.COM case IBT_SRATE_10: /* 4xSDR-10.0Gb/s injection rate */
21899580SBill.Taylor@Sun.COM path->max_stat_rate = 8; break;
21909580SBill.Taylor@Sun.COM case IBT_SRATE_30: /* 12xSDR-30Gb/s injection rate */
21919580SBill.Taylor@Sun.COM path->max_stat_rate = 9; break;
21929580SBill.Taylor@Sun.COM case IBT_SRATE_5: /* 1xDDR-5Gb/s injection rate */
21939580SBill.Taylor@Sun.COM path->max_stat_rate = 10; break;
21949580SBill.Taylor@Sun.COM case IBT_SRATE_20: /* 4xDDR-20Gb/s injection rate */
21959580SBill.Taylor@Sun.COM path->max_stat_rate = 11; break;
21969580SBill.Taylor@Sun.COM case IBT_SRATE_40: /* 4xQDR-40Gb/s injection rate */
21979580SBill.Taylor@Sun.COM path->max_stat_rate = 12; break;
21989580SBill.Taylor@Sun.COM case IBT_SRATE_60: /* 12xDDR-60Gb/s injection rate */
21999580SBill.Taylor@Sun.COM path->max_stat_rate = 13; break;
22009580SBill.Taylor@Sun.COM case IBT_SRATE_80: /* 8xQDR-80Gb/s injection rate */
22019580SBill.Taylor@Sun.COM path->max_stat_rate = 14; break;
22029580SBill.Taylor@Sun.COM case IBT_SRATE_120: /* 12xQDR-120Gb/s injection rate */
22039580SBill.Taylor@Sun.COM path->max_stat_rate = 15; break;
22049580SBill.Taylor@Sun.COM case IBT_SRATE_NOT_SPECIFIED: /* Max */
22059580SBill.Taylor@Sun.COM path->max_stat_rate = 0; break;
22069580SBill.Taylor@Sun.COM default:
22079517SBill.Taylor@Sun.COM return (IBT_STATIC_RATE_INVALID);
22089517SBill.Taylor@Sun.COM }
22099517SBill.Taylor@Sun.COM if (hermon_srate_override != -1) /* for evaluating HCA firmware */
22109517SBill.Taylor@Sun.COM path->max_stat_rate = hermon_srate_override;
22119517SBill.Taylor@Sun.COM
22129517SBill.Taylor@Sun.COM /* If "grh" flag is set, then check for valid SGID index too */
22139517SBill.Taylor@Sun.COM gidtbl_sz = (1 << state->hs_queryport.log_max_gid);
22149517SBill.Taylor@Sun.COM if ((av->av_send_grh) && (av->av_sgid_ix > gidtbl_sz)) {
22159517SBill.Taylor@Sun.COM return (IBT_SGID_INVALID);
22169517SBill.Taylor@Sun.COM }
22179517SBill.Taylor@Sun.COM
22189517SBill.Taylor@Sun.COM /*
22199517SBill.Taylor@Sun.COM * Fill in all "global" values regardless of the value in the GRH
22209517SBill.Taylor@Sun.COM * flag. Because "grh" is not set unless "av_send_grh" is set, the
22219517SBill.Taylor@Sun.COM * hardware will ignore the other "global" values as necessary. Note:
22229517SBill.Taylor@Sun.COM * SW does this here to enable later query operations to return
22239517SBill.Taylor@Sun.COM * exactly the same params that were passed when the addr path was
22249517SBill.Taylor@Sun.COM * last written.
22259517SBill.Taylor@Sun.COM */
22269517SBill.Taylor@Sun.COM path->grh = av->av_send_grh;
22279517SBill.Taylor@Sun.COM if (type == HERMON_ADDRPATH_QP) {
22289517SBill.Taylor@Sun.COM path->mgid_index = av->av_sgid_ix;
22299517SBill.Taylor@Sun.COM } else {
22309517SBill.Taylor@Sun.COM /*
22319517SBill.Taylor@Sun.COM * For Hermon UDAV, the "mgid_index" field is the index into
22329517SBill.Taylor@Sun.COM * a combined table (not a per-port table), but having sections
22339517SBill.Taylor@Sun.COM * for each port. So some extra calculations are necessary.
22349517SBill.Taylor@Sun.COM */
22359517SBill.Taylor@Sun.COM
22369517SBill.Taylor@Sun.COM path->mgid_index = ((av->av_port_num - 1) * gidtbl_sz) +
22379517SBill.Taylor@Sun.COM av->av_sgid_ix;
22389517SBill.Taylor@Sun.COM
22399517SBill.Taylor@Sun.COM udav->portnum = av->av_port_num;
22409517SBill.Taylor@Sun.COM }
22419517SBill.Taylor@Sun.COM
22429517SBill.Taylor@Sun.COM /*
22439517SBill.Taylor@Sun.COM * According to Hermon PRM, the (31:0) part of rgid_l must be set to
22449517SBill.Taylor@Sun.COM * "0x2" if the 'grh' or 'g' bit is cleared. It also says that we
22459517SBill.Taylor@Sun.COM * only need to do it for UDAV's. So we enforce that here.
22469517SBill.Taylor@Sun.COM *
22479517SBill.Taylor@Sun.COM * NOTE: The entire 64 bits worth of GUID info is actually being
22489517SBill.Taylor@Sun.COM * preserved (for UDAVs) by the callers of this function
22499517SBill.Taylor@Sun.COM * (hermon_ah_alloc() and hermon_ah_modify()) and as long as the
22509517SBill.Taylor@Sun.COM * 'grh' bit is not set, the upper 32 bits (63:32) of rgid_l are
22519517SBill.Taylor@Sun.COM * "don't care".
22529517SBill.Taylor@Sun.COM */
22539517SBill.Taylor@Sun.COM if ((path->grh) || (type == HERMON_ADDRPATH_QP)) {
22549517SBill.Taylor@Sun.COM path->flow_label = av->av_flow;
22559517SBill.Taylor@Sun.COM path->tclass = av->av_tclass;
22569517SBill.Taylor@Sun.COM path->hop_limit = av->av_hop;
22579517SBill.Taylor@Sun.COM bcopy(&(av->av_dgid.gid_prefix), &(path->rgid_h),
22589517SBill.Taylor@Sun.COM sizeof (uint64_t));
22599517SBill.Taylor@Sun.COM bcopy(&(av->av_dgid.gid_guid), &(path->rgid_l),
22609517SBill.Taylor@Sun.COM sizeof (uint64_t));
22619517SBill.Taylor@Sun.COM } else {
22629517SBill.Taylor@Sun.COM path->rgid_l = 0x2;
22639517SBill.Taylor@Sun.COM path->flow_label = 0;
22649517SBill.Taylor@Sun.COM path->tclass = 0;
22659517SBill.Taylor@Sun.COM path->hop_limit = 0;
22669517SBill.Taylor@Sun.COM path->rgid_h = 0;
22679517SBill.Taylor@Sun.COM }
22689517SBill.Taylor@Sun.COM /* extract the default service level */
22699517SBill.Taylor@Sun.COM udav->sl = (HERMON_DEF_SCHED_SELECTION & 0x3C) >> 2;
22709517SBill.Taylor@Sun.COM
22719517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
22729517SBill.Taylor@Sun.COM }
22739517SBill.Taylor@Sun.COM
22749517SBill.Taylor@Sun.COM
22759517SBill.Taylor@Sun.COM /*
22769517SBill.Taylor@Sun.COM * hermon_get_addr_path()
22779517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
22789517SBill.Taylor@Sun.COM *
22799517SBill.Taylor@Sun.COM * Note: Just like hermon_set_addr_path() above, this routine is used for two
22809517SBill.Taylor@Sun.COM * purposes. It is used to read in the Hermon UDAV fields, and it is used to
22819517SBill.Taylor@Sun.COM * read in the address path information for QPs. Because the two Hermon
22829517SBill.Taylor@Sun.COM * structures are similar, common fields can be read in here. But because
22839517SBill.Taylor@Sun.COM * they are slightly different, we pass an additional flag to indicate which
22849517SBill.Taylor@Sun.COM * type is being read.
22859517SBill.Taylor@Sun.COM */
22869517SBill.Taylor@Sun.COM void
hermon_get_addr_path(hermon_state_t * state,hermon_hw_addr_path_t * path,ibt_adds_vect_t * av,uint_t type)22879517SBill.Taylor@Sun.COM hermon_get_addr_path(hermon_state_t *state, hermon_hw_addr_path_t *path,
22889517SBill.Taylor@Sun.COM ibt_adds_vect_t *av, uint_t type)
22899517SBill.Taylor@Sun.COM {
22909517SBill.Taylor@Sun.COM uint_t gidtbl_sz;
22919517SBill.Taylor@Sun.COM
22929517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*path))
22939517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*av))
22949517SBill.Taylor@Sun.COM
22959517SBill.Taylor@Sun.COM av->av_src_path = path->mlid;
22969517SBill.Taylor@Sun.COM av->av_dlid = path->rlid;
22979517SBill.Taylor@Sun.COM
22989517SBill.Taylor@Sun.COM /* Set "av_ipd" value from max_stat_rate */
22999580SBill.Taylor@Sun.COM switch (path->max_stat_rate) {
23009580SBill.Taylor@Sun.COM case 7: /* 1xSDR-2.5Gb/s injection rate */
23019580SBill.Taylor@Sun.COM av->av_srate = IBT_SRATE_2; break;
23029580SBill.Taylor@Sun.COM case 8: /* 4xSDR-10.0Gb/s injection rate */
23039580SBill.Taylor@Sun.COM av->av_srate = IBT_SRATE_10; break;
23049580SBill.Taylor@Sun.COM case 9: /* 12xSDR-30Gb/s injection rate */
23059580SBill.Taylor@Sun.COM av->av_srate = IBT_SRATE_30; break;
23069580SBill.Taylor@Sun.COM case 10: /* 1xDDR-5Gb/s injection rate */
23079580SBill.Taylor@Sun.COM av->av_srate = IBT_SRATE_5; break;
23089580SBill.Taylor@Sun.COM case 11: /* 4xDDR-20Gb/s injection rate */
23099580SBill.Taylor@Sun.COM av->av_srate = IBT_SRATE_20; break;
23109580SBill.Taylor@Sun.COM case 12: /* xQDR-40Gb/s injection rate */
23119580SBill.Taylor@Sun.COM av->av_srate = IBT_SRATE_40; break;
23129580SBill.Taylor@Sun.COM case 13: /* 12xDDR-60Gb/s injection rate */
23139580SBill.Taylor@Sun.COM av->av_srate = IBT_SRATE_60; break;
23149580SBill.Taylor@Sun.COM case 14: /* 8xQDR-80Gb/s injection rate */
23159580SBill.Taylor@Sun.COM av->av_srate = IBT_SRATE_80; break;
23169580SBill.Taylor@Sun.COM case 15: /* 12xQDR-120Gb/s injection rate */
23179580SBill.Taylor@Sun.COM av->av_srate = IBT_SRATE_120; break;
23189580SBill.Taylor@Sun.COM case 0: /* max */
23199969SGiri.Adari@Sun.COM av->av_srate = IBT_SRATE_NOT_SPECIFIED; break;
23209580SBill.Taylor@Sun.COM default: /* 1x injection rate */
23219580SBill.Taylor@Sun.COM av->av_srate = IBT_SRATE_1X;
23229517SBill.Taylor@Sun.COM }
23239517SBill.Taylor@Sun.COM
23249517SBill.Taylor@Sun.COM /*
23259517SBill.Taylor@Sun.COM * Extract all "global" values regardless of the value in the GRH
23269517SBill.Taylor@Sun.COM * flag. Because "av_send_grh" is set only if "grh" is set, software
23279517SBill.Taylor@Sun.COM * knows to ignore the other "global" values as necessary. Note: SW
23289517SBill.Taylor@Sun.COM * does it this way to enable these query operations to return exactly
23299517SBill.Taylor@Sun.COM * the same params that were passed when the addr path was last written.
23309517SBill.Taylor@Sun.COM */
23319517SBill.Taylor@Sun.COM av->av_send_grh = path->grh;
23329517SBill.Taylor@Sun.COM if (type == HERMON_ADDRPATH_QP) {
23339517SBill.Taylor@Sun.COM av->av_sgid_ix = path->mgid_index;
23349517SBill.Taylor@Sun.COM } else {
23359517SBill.Taylor@Sun.COM /*
23369517SBill.Taylor@Sun.COM * For Hermon UDAV, the "mgid_index" field is the index into
23379517SBill.Taylor@Sun.COM * a combined table (not a per-port table).
23389517SBill.Taylor@Sun.COM */
23399517SBill.Taylor@Sun.COM gidtbl_sz = (1 << state->hs_queryport.log_max_gid);
23409517SBill.Taylor@Sun.COM av->av_sgid_ix = path->mgid_index - ((av->av_port_num - 1) *
23419517SBill.Taylor@Sun.COM gidtbl_sz);
23429517SBill.Taylor@Sun.COM
23439517SBill.Taylor@Sun.COM av->av_port_num = ((hermon_hw_udav_t *)(void *)path)->portnum;
23449517SBill.Taylor@Sun.COM }
23459517SBill.Taylor@Sun.COM av->av_flow = path->flow_label;
23469517SBill.Taylor@Sun.COM av->av_tclass = path->tclass;
23479517SBill.Taylor@Sun.COM av->av_hop = path->hop_limit;
23489517SBill.Taylor@Sun.COM /* this is for alignment issue w/ the addr path struct in Hermon */
23499517SBill.Taylor@Sun.COM bcopy(&(path->rgid_h), &(av->av_dgid.gid_prefix), sizeof (uint64_t));
23509517SBill.Taylor@Sun.COM bcopy(&(path->rgid_l), &(av->av_dgid.gid_guid), sizeof (uint64_t));
23519517SBill.Taylor@Sun.COM }
23529517SBill.Taylor@Sun.COM
23539517SBill.Taylor@Sun.COM
23549517SBill.Taylor@Sun.COM /*
23559517SBill.Taylor@Sun.COM * hermon_portnum_is_valid()
23569517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
23579517SBill.Taylor@Sun.COM */
23589517SBill.Taylor@Sun.COM int
hermon_portnum_is_valid(hermon_state_t * state,uint_t portnum)23599517SBill.Taylor@Sun.COM hermon_portnum_is_valid(hermon_state_t *state, uint_t portnum)
23609517SBill.Taylor@Sun.COM {
23619517SBill.Taylor@Sun.COM uint_t max_port;
23629517SBill.Taylor@Sun.COM
23639517SBill.Taylor@Sun.COM max_port = state->hs_cfg_profile->cp_num_ports;
23649517SBill.Taylor@Sun.COM if ((portnum <= max_port) && (portnum != 0)) {
23659517SBill.Taylor@Sun.COM return (1);
23669517SBill.Taylor@Sun.COM } else {
23679517SBill.Taylor@Sun.COM return (0);
23689517SBill.Taylor@Sun.COM }
23699517SBill.Taylor@Sun.COM }
23709517SBill.Taylor@Sun.COM
23719517SBill.Taylor@Sun.COM
23729517SBill.Taylor@Sun.COM /*
23739517SBill.Taylor@Sun.COM * hermon_pkeyindex_is_valid()
23749517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
23759517SBill.Taylor@Sun.COM */
23769517SBill.Taylor@Sun.COM int
hermon_pkeyindex_is_valid(hermon_state_t * state,uint_t pkeyindx)23779517SBill.Taylor@Sun.COM hermon_pkeyindex_is_valid(hermon_state_t *state, uint_t pkeyindx)
23789517SBill.Taylor@Sun.COM {
23799517SBill.Taylor@Sun.COM uint_t max_pkeyindx;
23809517SBill.Taylor@Sun.COM
23819517SBill.Taylor@Sun.COM max_pkeyindx = 1 << state->hs_cfg_profile->cp_log_max_pkeytbl;
23829517SBill.Taylor@Sun.COM if (pkeyindx < max_pkeyindx) {
23839517SBill.Taylor@Sun.COM return (1);
23849517SBill.Taylor@Sun.COM } else {
23859517SBill.Taylor@Sun.COM return (0);
23869517SBill.Taylor@Sun.COM }
23879517SBill.Taylor@Sun.COM }
23889517SBill.Taylor@Sun.COM
23899517SBill.Taylor@Sun.COM
23909517SBill.Taylor@Sun.COM /*
23919517SBill.Taylor@Sun.COM * hermon_queue_alloc()
23929517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
23939517SBill.Taylor@Sun.COM */
23949517SBill.Taylor@Sun.COM int
hermon_queue_alloc(hermon_state_t * state,hermon_qalloc_info_t * qa_info,uint_t sleepflag)23959517SBill.Taylor@Sun.COM hermon_queue_alloc(hermon_state_t *state, hermon_qalloc_info_t *qa_info,
23969517SBill.Taylor@Sun.COM uint_t sleepflag)
23979517SBill.Taylor@Sun.COM {
23989517SBill.Taylor@Sun.COM ddi_dma_attr_t dma_attr;
23999517SBill.Taylor@Sun.COM int (*callback)(caddr_t);
24009517SBill.Taylor@Sun.COM uint64_t realsize, alloc_mask;
24019517SBill.Taylor@Sun.COM int flag, status;
24029517SBill.Taylor@Sun.COM
24039517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*qa_info))
24049517SBill.Taylor@Sun.COM
24059517SBill.Taylor@Sun.COM /* Set the callback flag appropriately */
24069517SBill.Taylor@Sun.COM callback = (sleepflag == HERMON_SLEEP) ? DDI_DMA_SLEEP :
24079517SBill.Taylor@Sun.COM DDI_DMA_DONTWAIT;
24089517SBill.Taylor@Sun.COM
24099517SBill.Taylor@Sun.COM /*
24109517SBill.Taylor@Sun.COM * Initialize many of the default DMA attributes. Then set additional
24119517SBill.Taylor@Sun.COM * alignment restrictions as necessary for the queue memory. Also
24129517SBill.Taylor@Sun.COM * respect the configured value for IOMMU bypass
24139517SBill.Taylor@Sun.COM */
24149517SBill.Taylor@Sun.COM hermon_dma_attr_init(state, &dma_attr);
24159517SBill.Taylor@Sun.COM dma_attr.dma_attr_align = qa_info->qa_bind_align;
241611972SBill.Taylor@Sun.COM #ifdef __sparc
241711972SBill.Taylor@Sun.COM if (state->hs_cfg_profile->cp_iommu_bypass == HERMON_BINDMEM_BYPASS) {
24189517SBill.Taylor@Sun.COM dma_attr.dma_attr_flags = DDI_DMA_FORCE_PHYSICAL;
24199517SBill.Taylor@Sun.COM }
242011972SBill.Taylor@Sun.COM #endif
24219517SBill.Taylor@Sun.COM
24229517SBill.Taylor@Sun.COM /* Allocate a DMA handle */
24239517SBill.Taylor@Sun.COM status = ddi_dma_alloc_handle(state->hs_dip, &dma_attr, callback, NULL,
24249517SBill.Taylor@Sun.COM &qa_info->qa_dmahdl);
24259517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
24269517SBill.Taylor@Sun.COM return (DDI_FAILURE);
24279517SBill.Taylor@Sun.COM }
24289517SBill.Taylor@Sun.COM
24299517SBill.Taylor@Sun.COM /*
24309517SBill.Taylor@Sun.COM * Determine the amount of memory to allocate, depending on the values
24319517SBill.Taylor@Sun.COM * in "qa_bind_align" and "qa_alloc_align". The problem we are trying
24329517SBill.Taylor@Sun.COM * to solve here is that allocating a DMA handle with IOMMU bypass
24339517SBill.Taylor@Sun.COM * (DDI_DMA_FORCE_PHYSICAL) constrains us to only requesting alignments
24349517SBill.Taylor@Sun.COM * that are less restrictive than the page size. Since we may need
24359517SBill.Taylor@Sun.COM * stricter alignments on the memory allocated by ddi_dma_mem_alloc()
24369517SBill.Taylor@Sun.COM * (e.g. in Hermon QP work queue memory allocation), we use the
24379517SBill.Taylor@Sun.COM * following method to calculate how much additional memory to request,
24389517SBill.Taylor@Sun.COM * and we enforce our own alignment on the allocated result.
24399517SBill.Taylor@Sun.COM */
24409517SBill.Taylor@Sun.COM alloc_mask = qa_info->qa_alloc_align - 1;
24419517SBill.Taylor@Sun.COM if (qa_info->qa_bind_align == qa_info->qa_alloc_align) {
24429517SBill.Taylor@Sun.COM realsize = qa_info->qa_size;
24439517SBill.Taylor@Sun.COM } else {
24449517SBill.Taylor@Sun.COM realsize = qa_info->qa_size + alloc_mask;
24459517SBill.Taylor@Sun.COM }
24469517SBill.Taylor@Sun.COM
24479517SBill.Taylor@Sun.COM /*
24489517SBill.Taylor@Sun.COM * If we are to allocate the queue from system memory, then use
24499517SBill.Taylor@Sun.COM * ddi_dma_mem_alloc() to find the space. Otherwise, this is a
24509517SBill.Taylor@Sun.COM * host memory allocation, use ddi_umem_alloc(). In either case,
24519517SBill.Taylor@Sun.COM * return a pointer to the memory range allocated (including any
24529517SBill.Taylor@Sun.COM * necessary alignment adjustments), the "real" memory pointer,
24539517SBill.Taylor@Sun.COM * the "real" size, and a ddi_acc_handle_t to use when reading
24549517SBill.Taylor@Sun.COM * from/writing to the memory.
24559517SBill.Taylor@Sun.COM */
24569517SBill.Taylor@Sun.COM if (qa_info->qa_location == HERMON_QUEUE_LOCATION_NORMAL) {
24579517SBill.Taylor@Sun.COM /* Allocate system memory for the queue */
24589517SBill.Taylor@Sun.COM status = ddi_dma_mem_alloc(qa_info->qa_dmahdl, realsize,
24599517SBill.Taylor@Sun.COM &state->hs_reg_accattr, DDI_DMA_CONSISTENT, callback, NULL,
24609517SBill.Taylor@Sun.COM (caddr_t *)&qa_info->qa_buf_real,
24619517SBill.Taylor@Sun.COM (size_t *)&qa_info->qa_buf_realsz, &qa_info->qa_acchdl);
24629517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
24639517SBill.Taylor@Sun.COM ddi_dma_free_handle(&qa_info->qa_dmahdl);
24649517SBill.Taylor@Sun.COM return (DDI_FAILURE);
24659517SBill.Taylor@Sun.COM }
24669517SBill.Taylor@Sun.COM
24679517SBill.Taylor@Sun.COM /*
24689517SBill.Taylor@Sun.COM * Save temporary copy of the real pointer. (This may be
24699517SBill.Taylor@Sun.COM * modified in the last step below).
24709517SBill.Taylor@Sun.COM */
24719517SBill.Taylor@Sun.COM qa_info->qa_buf_aligned = qa_info->qa_buf_real;
24729517SBill.Taylor@Sun.COM
24739517SBill.Taylor@Sun.COM bzero(qa_info->qa_buf_real, qa_info->qa_buf_realsz);
24749517SBill.Taylor@Sun.COM
24759517SBill.Taylor@Sun.COM } else { /* HERMON_QUEUE_LOCATION_USERLAND */
24769517SBill.Taylor@Sun.COM
24779517SBill.Taylor@Sun.COM /* Allocate userland mappable memory for the queue */
24789517SBill.Taylor@Sun.COM flag = (sleepflag == HERMON_SLEEP) ? DDI_UMEM_SLEEP :
24799517SBill.Taylor@Sun.COM DDI_UMEM_NOSLEEP;
24809517SBill.Taylor@Sun.COM qa_info->qa_buf_real = ddi_umem_alloc(realsize, flag,
24819517SBill.Taylor@Sun.COM &qa_info->qa_umemcookie);
24829517SBill.Taylor@Sun.COM if (qa_info->qa_buf_real == NULL) {
24839517SBill.Taylor@Sun.COM ddi_dma_free_handle(&qa_info->qa_dmahdl);
24849517SBill.Taylor@Sun.COM return (DDI_FAILURE);
24859517SBill.Taylor@Sun.COM }
24869517SBill.Taylor@Sun.COM
24879517SBill.Taylor@Sun.COM /*
24889517SBill.Taylor@Sun.COM * Save temporary copy of the real pointer. (This may be
24899517SBill.Taylor@Sun.COM * modified in the last step below).
24909517SBill.Taylor@Sun.COM */
24919517SBill.Taylor@Sun.COM qa_info->qa_buf_aligned = qa_info->qa_buf_real;
24929517SBill.Taylor@Sun.COM
24939517SBill.Taylor@Sun.COM }
24949517SBill.Taylor@Sun.COM
24959517SBill.Taylor@Sun.COM /*
24969517SBill.Taylor@Sun.COM * The next to last step is to ensure that the final address
24979517SBill.Taylor@Sun.COM * ("qa_buf_aligned") has the appropriate "alloc" alignment
24989517SBill.Taylor@Sun.COM * restriction applied to it (if necessary).
24999517SBill.Taylor@Sun.COM */
25009517SBill.Taylor@Sun.COM if (qa_info->qa_bind_align != qa_info->qa_alloc_align) {
25019517SBill.Taylor@Sun.COM qa_info->qa_buf_aligned = (uint32_t *)(uintptr_t)(((uintptr_t)
25029517SBill.Taylor@Sun.COM qa_info->qa_buf_aligned + alloc_mask) & ~alloc_mask);
25039517SBill.Taylor@Sun.COM }
25049517SBill.Taylor@Sun.COM /*
25059517SBill.Taylor@Sun.COM * The last step is to figure out the offset of the start relative
25069517SBill.Taylor@Sun.COM * to the first page of the region - will be used in the eqc/cqc
25079517SBill.Taylor@Sun.COM * passed to the HW
25089517SBill.Taylor@Sun.COM */
25099517SBill.Taylor@Sun.COM qa_info->qa_pgoffs = (uint_t)((uintptr_t)
251011972SBill.Taylor@Sun.COM qa_info->qa_buf_aligned & HERMON_PAGEOFFSET);
25119517SBill.Taylor@Sun.COM
25129517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
25139517SBill.Taylor@Sun.COM }
25149517SBill.Taylor@Sun.COM
25159517SBill.Taylor@Sun.COM
25169517SBill.Taylor@Sun.COM /*
25179517SBill.Taylor@Sun.COM * hermon_queue_free()
25189517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
25199517SBill.Taylor@Sun.COM */
25209517SBill.Taylor@Sun.COM void
hermon_queue_free(hermon_qalloc_info_t * qa_info)25219517SBill.Taylor@Sun.COM hermon_queue_free(hermon_qalloc_info_t *qa_info)
25229517SBill.Taylor@Sun.COM {
25239517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*qa_info))
25249517SBill.Taylor@Sun.COM
25259517SBill.Taylor@Sun.COM /*
25269517SBill.Taylor@Sun.COM * Depending on how (i.e. from where) we allocated the memory for
25279517SBill.Taylor@Sun.COM * this queue, we choose the appropriate method for releasing the
25289517SBill.Taylor@Sun.COM * resources.
25299517SBill.Taylor@Sun.COM */
25309517SBill.Taylor@Sun.COM if (qa_info->qa_location == HERMON_QUEUE_LOCATION_NORMAL) {
25319517SBill.Taylor@Sun.COM
25329517SBill.Taylor@Sun.COM ddi_dma_mem_free(&qa_info->qa_acchdl);
25339517SBill.Taylor@Sun.COM
25349517SBill.Taylor@Sun.COM } else if (qa_info->qa_location == HERMON_QUEUE_LOCATION_USERLAND) {
25359517SBill.Taylor@Sun.COM
25369517SBill.Taylor@Sun.COM ddi_umem_free(qa_info->qa_umemcookie);
25379517SBill.Taylor@Sun.COM
25389517SBill.Taylor@Sun.COM }
25399517SBill.Taylor@Sun.COM
25409517SBill.Taylor@Sun.COM /* Always free the dma handle */
25419517SBill.Taylor@Sun.COM ddi_dma_free_handle(&qa_info->qa_dmahdl);
25429517SBill.Taylor@Sun.COM }
25439517SBill.Taylor@Sun.COM
25449517SBill.Taylor@Sun.COM /*
254511972SBill.Taylor@Sun.COM * hermon_create_fmr_pool()
25469517SBill.Taylor@Sun.COM * Create a pool of FMRs.
25479517SBill.Taylor@Sun.COM * Context: Can be called from kernel context only.
25489517SBill.Taylor@Sun.COM */
25499517SBill.Taylor@Sun.COM int
hermon_create_fmr_pool(hermon_state_t * state,hermon_pdhdl_t pd,ibt_fmr_pool_attr_t * fmr_attr,hermon_fmrhdl_t * fmrpoolp)25509517SBill.Taylor@Sun.COM hermon_create_fmr_pool(hermon_state_t *state, hermon_pdhdl_t pd,
25519517SBill.Taylor@Sun.COM ibt_fmr_pool_attr_t *fmr_attr, hermon_fmrhdl_t *fmrpoolp)
25529517SBill.Taylor@Sun.COM {
25539517SBill.Taylor@Sun.COM hermon_fmrhdl_t fmrpool;
25549517SBill.Taylor@Sun.COM hermon_fmr_list_t *fmr, *fmr_next;
25559517SBill.Taylor@Sun.COM hermon_mrhdl_t mr;
25569517SBill.Taylor@Sun.COM int status;
25579517SBill.Taylor@Sun.COM int sleep;
25589517SBill.Taylor@Sun.COM int i;
25599517SBill.Taylor@Sun.COM
25609517SBill.Taylor@Sun.COM sleep = (fmr_attr->fmr_flags & IBT_MR_SLEEP) ? HERMON_SLEEP :
25619517SBill.Taylor@Sun.COM HERMON_NOSLEEP;
25629517SBill.Taylor@Sun.COM if ((sleep == HERMON_SLEEP) &&
25639517SBill.Taylor@Sun.COM (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
25649517SBill.Taylor@Sun.COM return (IBT_INVALID_PARAM);
25659517SBill.Taylor@Sun.COM }
25669517SBill.Taylor@Sun.COM
25679517SBill.Taylor@Sun.COM fmrpool = (hermon_fmrhdl_t)kmem_zalloc(sizeof (*fmrpool), sleep);
25689517SBill.Taylor@Sun.COM if (fmrpool == NULL) {
25699517SBill.Taylor@Sun.COM status = IBT_INSUFF_RESOURCE;
25709517SBill.Taylor@Sun.COM goto fail;
25719517SBill.Taylor@Sun.COM }
25729517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*fmrpool))
25739517SBill.Taylor@Sun.COM
25749517SBill.Taylor@Sun.COM mutex_init(&fmrpool->fmr_lock, NULL, MUTEX_DRIVER,
25759517SBill.Taylor@Sun.COM DDI_INTR_PRI(state->hs_intrmsi_pri));
2576*12965SWilliam.Taylor@Oracle.COM mutex_init(&fmrpool->remap_lock, NULL, MUTEX_DRIVER,
2577*12965SWilliam.Taylor@Oracle.COM DDI_INTR_PRI(state->hs_intrmsi_pri));
2578*12965SWilliam.Taylor@Oracle.COM mutex_init(&fmrpool->dirty_lock, NULL, MUTEX_DRIVER,
2579*12965SWilliam.Taylor@Oracle.COM DDI_INTR_PRI(state->hs_intrmsi_pri));
25809517SBill.Taylor@Sun.COM
25819517SBill.Taylor@Sun.COM fmrpool->fmr_state = state;
25829517SBill.Taylor@Sun.COM fmrpool->fmr_flush_function = fmr_attr->fmr_func_hdlr;
25839517SBill.Taylor@Sun.COM fmrpool->fmr_flush_arg = fmr_attr->fmr_func_arg;
25849517SBill.Taylor@Sun.COM fmrpool->fmr_pool_size = 0;
25859517SBill.Taylor@Sun.COM fmrpool->fmr_max_pages = fmr_attr->fmr_max_pages_per_fmr;
25869517SBill.Taylor@Sun.COM fmrpool->fmr_page_sz = fmr_attr->fmr_page_sz;
2587*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_dirty_watermark = fmr_attr->fmr_pool_size / 4;
25889517SBill.Taylor@Sun.COM fmrpool->fmr_dirty_len = 0;
2589*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_watermark = fmr_attr->fmr_pool_size / 32;
2590*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_len = 0;
25919517SBill.Taylor@Sun.COM fmrpool->fmr_flags = fmr_attr->fmr_flags;
2592*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_stat_register = 0;
2593*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_max_remaps = state->hs_cfg_profile->cp_fmr_max_remaps;
2594*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_gen = 1;
25959517SBill.Taylor@Sun.COM
2596*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_free_list_tail = &fmrpool->fmr_free_list;
25979517SBill.Taylor@Sun.COM fmrpool->fmr_dirty_list = NULL;
2598*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_dirty_list_tail = &fmrpool->fmr_dirty_list;
2599*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_list = NULL;
2600*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_list_tail = &fmrpool->fmr_remap_list;
2601*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_pool_size = fmrpool->fmr_free_len =
2602*12965SWilliam.Taylor@Oracle.COM fmr_attr->fmr_pool_size;
26039517SBill.Taylor@Sun.COM
26049517SBill.Taylor@Sun.COM for (i = 0; i < fmr_attr->fmr_pool_size; i++) {
26059517SBill.Taylor@Sun.COM status = hermon_mr_alloc_fmr(state, pd, fmrpool, &mr);
26069517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
26079517SBill.Taylor@Sun.COM goto fail2;
26089517SBill.Taylor@Sun.COM }
26099517SBill.Taylor@Sun.COM
26109517SBill.Taylor@Sun.COM fmr = (hermon_fmr_list_t *)kmem_zalloc(
26119517SBill.Taylor@Sun.COM sizeof (hermon_fmr_list_t), sleep);
26129517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*fmr))
26139517SBill.Taylor@Sun.COM
26149517SBill.Taylor@Sun.COM fmr->fmr = mr;
26159517SBill.Taylor@Sun.COM fmr->fmr_remaps = 0;
2616*12965SWilliam.Taylor@Oracle.COM fmr->fmr_remap_gen = fmrpool->fmr_remap_gen;
26179517SBill.Taylor@Sun.COM fmr->fmr_pool = fmrpool;
26189517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mr))
26199517SBill.Taylor@Sun.COM mr->mr_fmr = fmr;
26209517SBill.Taylor@Sun.COM
2621*12965SWilliam.Taylor@Oracle.COM if (!i) /* address of last entry's link */
2622*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_free_list_tail = &fmr->fmr_next;
26239517SBill.Taylor@Sun.COM fmr->fmr_next = fmrpool->fmr_free_list;
26249517SBill.Taylor@Sun.COM fmrpool->fmr_free_list = fmr;
26259517SBill.Taylor@Sun.COM }
26269517SBill.Taylor@Sun.COM
26279517SBill.Taylor@Sun.COM /* Set to return pool */
26289517SBill.Taylor@Sun.COM *fmrpoolp = fmrpool;
26299517SBill.Taylor@Sun.COM
2630*12965SWilliam.Taylor@Oracle.COM IBTF_DPRINTF_L2("fmr", "create_fmr_pool SUCCESS");
26319517SBill.Taylor@Sun.COM return (IBT_SUCCESS);
26329517SBill.Taylor@Sun.COM fail2:
26339517SBill.Taylor@Sun.COM for (fmr = fmrpool->fmr_free_list; fmr != NULL; fmr = fmr_next) {
26349517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*fmr))
26359517SBill.Taylor@Sun.COM fmr_next = fmr->fmr_next;
26369517SBill.Taylor@Sun.COM (void) hermon_mr_dealloc_fmr(state, &fmr->fmr);
26379517SBill.Taylor@Sun.COM kmem_free(fmr, sizeof (hermon_fmr_list_t));
26389517SBill.Taylor@Sun.COM }
26399517SBill.Taylor@Sun.COM kmem_free(fmrpool, sizeof (*fmrpool));
26409517SBill.Taylor@Sun.COM fail:
2641*12965SWilliam.Taylor@Oracle.COM *fmrpoolp = NULL;
2642*12965SWilliam.Taylor@Oracle.COM IBTF_DPRINTF_L2("fmr", "create_fmr_pool FAILED");
26439517SBill.Taylor@Sun.COM if (status == DDI_FAILURE) {
26449517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
26459517SBill.Taylor@Sun.COM } else {
26469517SBill.Taylor@Sun.COM return (status);
26479517SBill.Taylor@Sun.COM }
26489517SBill.Taylor@Sun.COM }
26499517SBill.Taylor@Sun.COM
26509517SBill.Taylor@Sun.COM /*
26519517SBill.Taylor@Sun.COM * hermon_destroy_fmr_pool()
26529517SBill.Taylor@Sun.COM * Destroy an FMR pool and free all associated resources.
26539517SBill.Taylor@Sun.COM * Context: Can be called from kernel context only.
26549517SBill.Taylor@Sun.COM */
26559517SBill.Taylor@Sun.COM int
hermon_destroy_fmr_pool(hermon_state_t * state,hermon_fmrhdl_t fmrpool)26569517SBill.Taylor@Sun.COM hermon_destroy_fmr_pool(hermon_state_t *state, hermon_fmrhdl_t fmrpool)
26579517SBill.Taylor@Sun.COM {
26589517SBill.Taylor@Sun.COM hermon_fmr_list_t *fmr, *fmr_next;
26599517SBill.Taylor@Sun.COM
26609517SBill.Taylor@Sun.COM mutex_enter(&fmrpool->fmr_lock);
2661*12965SWilliam.Taylor@Oracle.COM hermon_fmr_cleanup(fmrpool);
26629517SBill.Taylor@Sun.COM
26639517SBill.Taylor@Sun.COM for (fmr = fmrpool->fmr_free_list; fmr != NULL; fmr = fmr_next) {
26649517SBill.Taylor@Sun.COM fmr_next = fmr->fmr_next;
26659517SBill.Taylor@Sun.COM
26669517SBill.Taylor@Sun.COM (void) hermon_mr_dealloc_fmr(state, &fmr->fmr);
26679517SBill.Taylor@Sun.COM kmem_free(fmr, sizeof (hermon_fmr_list_t));
2668*12965SWilliam.Taylor@Oracle.COM
2669*12965SWilliam.Taylor@Oracle.COM --fmrpool->fmr_pool_size;
26709517SBill.Taylor@Sun.COM }
2671*12965SWilliam.Taylor@Oracle.COM ASSERT(fmrpool->fmr_pool_size == 0);
26729517SBill.Taylor@Sun.COM mutex_exit(&fmrpool->fmr_lock);
26739517SBill.Taylor@Sun.COM
26749517SBill.Taylor@Sun.COM mutex_destroy(&fmrpool->fmr_lock);
2675*12965SWilliam.Taylor@Oracle.COM mutex_destroy(&fmrpool->dirty_lock);
2676*12965SWilliam.Taylor@Oracle.COM mutex_destroy(&fmrpool->remap_lock);
26779517SBill.Taylor@Sun.COM
26789517SBill.Taylor@Sun.COM kmem_free(fmrpool, sizeof (*fmrpool));
2679*12965SWilliam.Taylor@Oracle.COM IBTF_DPRINTF_L2("fmr", "destroy_fmr_pool SUCCESS");
26809517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
26819517SBill.Taylor@Sun.COM }
26829517SBill.Taylor@Sun.COM
26839517SBill.Taylor@Sun.COM /*
26849517SBill.Taylor@Sun.COM * hermon_flush_fmr_pool()
26859517SBill.Taylor@Sun.COM * Ensure that all unmapped FMRs are fully invalidated.
26869517SBill.Taylor@Sun.COM * Context: Can be called from kernel context only.
26879517SBill.Taylor@Sun.COM */
2688*12965SWilliam.Taylor@Oracle.COM /* ARGSUSED */
26899517SBill.Taylor@Sun.COM int
hermon_flush_fmr_pool(hermon_state_t * state,hermon_fmrhdl_t fmrpool)26909517SBill.Taylor@Sun.COM hermon_flush_fmr_pool(hermon_state_t *state, hermon_fmrhdl_t fmrpool)
26919517SBill.Taylor@Sun.COM {
26929517SBill.Taylor@Sun.COM /*
26939517SBill.Taylor@Sun.COM * Force the unmapping of all entries on the dirty list, regardless of
26949517SBill.Taylor@Sun.COM * whether the watermark has been hit yet.
26959517SBill.Taylor@Sun.COM */
26969517SBill.Taylor@Sun.COM /* grab the pool lock */
26979517SBill.Taylor@Sun.COM mutex_enter(&fmrpool->fmr_lock);
2698*12965SWilliam.Taylor@Oracle.COM hermon_fmr_cleanup(fmrpool);
26999517SBill.Taylor@Sun.COM mutex_exit(&fmrpool->fmr_lock);
2700*12965SWilliam.Taylor@Oracle.COM return (DDI_SUCCESS);
27019517SBill.Taylor@Sun.COM }
27029517SBill.Taylor@Sun.COM
27039517SBill.Taylor@Sun.COM /*
2704*12965SWilliam.Taylor@Oracle.COM * hermon_register_physical_fmr()
27059517SBill.Taylor@Sun.COM * Map memory into FMR
27069517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
27079517SBill.Taylor@Sun.COM */
27089517SBill.Taylor@Sun.COM int
hermon_register_physical_fmr(hermon_state_t * state,hermon_fmrhdl_t fmrpool,ibt_pmr_attr_t * mem_pattr,hermon_mrhdl_t * mr,ibt_pmr_desc_t * mem_desc_p)27099517SBill.Taylor@Sun.COM hermon_register_physical_fmr(hermon_state_t *state, hermon_fmrhdl_t fmrpool,
27109517SBill.Taylor@Sun.COM ibt_pmr_attr_t *mem_pattr, hermon_mrhdl_t *mr,
27119517SBill.Taylor@Sun.COM ibt_pmr_desc_t *mem_desc_p)
27129517SBill.Taylor@Sun.COM {
27139517SBill.Taylor@Sun.COM hermon_fmr_list_t *fmr;
27149517SBill.Taylor@Sun.COM int status;
27159517SBill.Taylor@Sun.COM
27169517SBill.Taylor@Sun.COM /* Check length */
27179517SBill.Taylor@Sun.COM if (mem_pattr->pmr_len < 1 || (mem_pattr->pmr_num_buf >
27189517SBill.Taylor@Sun.COM fmrpool->fmr_max_pages)) {
27199517SBill.Taylor@Sun.COM return (IBT_MR_LEN_INVALID);
27209517SBill.Taylor@Sun.COM }
27219517SBill.Taylor@Sun.COM
2722*12965SWilliam.Taylor@Oracle.COM mutex_enter(&fmrpool->fmr_lock);
2723*12965SWilliam.Taylor@Oracle.COM if (fmrpool->fmr_free_list == NULL) {
2724*12965SWilliam.Taylor@Oracle.COM if (hermon_fmr_verbose & 2)
2725*12965SWilliam.Taylor@Oracle.COM IBTF_DPRINTF_L2("fmr", "register needs remap");
2726*12965SWilliam.Taylor@Oracle.COM mutex_enter(&fmrpool->remap_lock);
2727*12965SWilliam.Taylor@Oracle.COM if (fmrpool->fmr_remap_list) {
2728*12965SWilliam.Taylor@Oracle.COM /* add to free list */
2729*12965SWilliam.Taylor@Oracle.COM *(fmrpool->fmr_free_list_tail) =
2730*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_list;
2731*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_list = NULL;
2732*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_free_list_tail =
2733*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_list_tail;
27349517SBill.Taylor@Sun.COM
2735*12965SWilliam.Taylor@Oracle.COM /* reset list */
2736*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_list_tail = &fmrpool->fmr_remap_list;
2737*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_free_len += fmrpool->fmr_remap_len;
2738*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_len = 0;
27399517SBill.Taylor@Sun.COM }
2740*12965SWilliam.Taylor@Oracle.COM mutex_exit(&fmrpool->remap_lock);
27419517SBill.Taylor@Sun.COM }
2742*12965SWilliam.Taylor@Oracle.COM if (fmrpool->fmr_free_list == NULL) {
2743*12965SWilliam.Taylor@Oracle.COM if (hermon_fmr_verbose & 2)
2744*12965SWilliam.Taylor@Oracle.COM IBTF_DPRINTF_L2("fmr", "register needs cleanup");
2745*12965SWilliam.Taylor@Oracle.COM hermon_fmr_cleanup(fmrpool);
2746*12965SWilliam.Taylor@Oracle.COM }
27479517SBill.Taylor@Sun.COM
27489517SBill.Taylor@Sun.COM /* grab next free entry */
27499517SBill.Taylor@Sun.COM fmr = fmrpool->fmr_free_list;
27509517SBill.Taylor@Sun.COM if (fmr == NULL) {
275111972SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("fmr", "WARNING: no free fmr resource");
2752*12965SWilliam.Taylor@Oracle.COM cmn_err(CE_CONT, "no free fmr resource\n");
27539517SBill.Taylor@Sun.COM mutex_exit(&fmrpool->fmr_lock);
27549517SBill.Taylor@Sun.COM return (IBT_INSUFF_RESOURCE);
27559517SBill.Taylor@Sun.COM }
27569517SBill.Taylor@Sun.COM
2757*12965SWilliam.Taylor@Oracle.COM if ((fmrpool->fmr_free_list = fmr->fmr_next) == NULL)
2758*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_free_list_tail = &fmrpool->fmr_free_list;
27599517SBill.Taylor@Sun.COM fmr->fmr_next = NULL;
2760*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_stat_register++;
2761*12965SWilliam.Taylor@Oracle.COM mutex_exit(&fmrpool->fmr_lock);
27629517SBill.Taylor@Sun.COM
2763*12965SWilliam.Taylor@Oracle.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*fmr))
27649517SBill.Taylor@Sun.COM status = hermon_mr_register_physical_fmr(state, mem_pattr, fmr->fmr,
27659517SBill.Taylor@Sun.COM mem_desc_p);
27669517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
27679517SBill.Taylor@Sun.COM return (status);
27689517SBill.Taylor@Sun.COM }
276911972SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*fmr->fmr))
277011972SBill.Taylor@Sun.COM if (hermon_rdma_debug & 0x4)
277111972SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("fmr", " reg: mr %p key %x",
277211972SBill.Taylor@Sun.COM fmr->fmr, fmr->fmr->mr_rkey);
277311972SBill.Taylor@Sun.COM _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*fmr->fmr))
2774*12965SWilliam.Taylor@Oracle.COM if (fmr->fmr_remap_gen != fmrpool->fmr_remap_gen) {
2775*12965SWilliam.Taylor@Oracle.COM fmr->fmr_remap_gen = fmrpool->fmr_remap_gen;
2776*12965SWilliam.Taylor@Oracle.COM fmr->fmr_remaps = 0;
2777*12965SWilliam.Taylor@Oracle.COM }
27789517SBill.Taylor@Sun.COM
27799517SBill.Taylor@Sun.COM fmr->fmr_remaps++;
27809517SBill.Taylor@Sun.COM
27819517SBill.Taylor@Sun.COM *mr = (hermon_mrhdl_t)fmr->fmr;
27829517SBill.Taylor@Sun.COM
27839517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
27849517SBill.Taylor@Sun.COM }
27859517SBill.Taylor@Sun.COM
27869517SBill.Taylor@Sun.COM /*
27879517SBill.Taylor@Sun.COM * hermon_deregister_fmr()
27889517SBill.Taylor@Sun.COM * Unmap FMR
27899517SBill.Taylor@Sun.COM * Context: Can be called from kernel context only.
27909517SBill.Taylor@Sun.COM */
27919517SBill.Taylor@Sun.COM int
hermon_deregister_fmr(hermon_state_t * state,hermon_mrhdl_t mr)27929517SBill.Taylor@Sun.COM hermon_deregister_fmr(hermon_state_t *state, hermon_mrhdl_t mr)
27939517SBill.Taylor@Sun.COM {
27949517SBill.Taylor@Sun.COM hermon_fmrhdl_t fmrpool;
2795*12965SWilliam.Taylor@Oracle.COM hermon_fmr_list_t *fmr, **fmrlast;
2796*12965SWilliam.Taylor@Oracle.COM int len;
27979517SBill.Taylor@Sun.COM
27989517SBill.Taylor@Sun.COM fmr = mr->mr_fmr;
2799*12965SWilliam.Taylor@Oracle.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*fmr))
28009517SBill.Taylor@Sun.COM fmrpool = fmr->fmr_pool;
28019517SBill.Taylor@Sun.COM
2802*12965SWilliam.Taylor@Oracle.COM /* mark as owned by software */
2803*12965SWilliam.Taylor@Oracle.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*(fmr->fmr)))
2804*12965SWilliam.Taylor@Oracle.COM *(uint8_t *)(fmr->fmr->mr_mptrsrcp->hr_addr) = 0xF0;
28059517SBill.Taylor@Sun.COM
2806*12965SWilliam.Taylor@Oracle.COM if (fmr->fmr_remaps <
2807*12965SWilliam.Taylor@Oracle.COM state->hs_cfg_profile->cp_fmr_max_remaps) {
2808*12965SWilliam.Taylor@Oracle.COM /* add to remap list */
2809*12965SWilliam.Taylor@Oracle.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*(fmr->fmr)))
2810*12965SWilliam.Taylor@Oracle.COM if (hermon_rdma_debug & 0x4)
2811*12965SWilliam.Taylor@Oracle.COM IBTF_DPRINTF_L2("fmr", "dereg: mr %p key %x",
2812*12965SWilliam.Taylor@Oracle.COM fmr->fmr, fmr->fmr->mr_rkey);
2813*12965SWilliam.Taylor@Oracle.COM _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*(fmr->fmr)))
2814*12965SWilliam.Taylor@Oracle.COM mutex_enter(&fmrpool->remap_lock);
2815*12965SWilliam.Taylor@Oracle.COM fmr->fmr_next = NULL;
2816*12965SWilliam.Taylor@Oracle.COM *(fmrpool->fmr_remap_list_tail) = fmr;
2817*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_list_tail = &fmr->fmr_next;
2818*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_len++;
28199517SBill.Taylor@Sun.COM
2820*12965SWilliam.Taylor@Oracle.COM /* conditionally add remap list back to free list */
2821*12965SWilliam.Taylor@Oracle.COM fmrlast = NULL;
2822*12965SWilliam.Taylor@Oracle.COM if (fmrpool->fmr_remap_len >=
2823*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_watermark) {
2824*12965SWilliam.Taylor@Oracle.COM fmr = fmrpool->fmr_remap_list;
2825*12965SWilliam.Taylor@Oracle.COM fmrlast = fmrpool->fmr_remap_list_tail;
2826*12965SWilliam.Taylor@Oracle.COM len = fmrpool->fmr_remap_len;
2827*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_len = 0;
2828*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_list = NULL;
2829*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_list_tail =
2830*12965SWilliam.Taylor@Oracle.COM &fmrpool->fmr_remap_list;
28319517SBill.Taylor@Sun.COM }
2832*12965SWilliam.Taylor@Oracle.COM mutex_exit(&fmrpool->remap_lock);
2833*12965SWilliam.Taylor@Oracle.COM if (fmrlast) {
2834*12965SWilliam.Taylor@Oracle.COM mutex_enter(&fmrpool->fmr_lock);
2835*12965SWilliam.Taylor@Oracle.COM *(fmrpool->fmr_free_list_tail) = fmr;
2836*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_free_list_tail = fmrlast;
2837*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_free_len += len;
2838*12965SWilliam.Taylor@Oracle.COM mutex_exit(&fmrpool->fmr_lock);
2839*12965SWilliam.Taylor@Oracle.COM }
2840*12965SWilliam.Taylor@Oracle.COM } else {
2841*12965SWilliam.Taylor@Oracle.COM /* add to dirty list */
2842*12965SWilliam.Taylor@Oracle.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*(fmr->fmr)))
2843*12965SWilliam.Taylor@Oracle.COM if (hermon_rdma_debug & 0x4)
2844*12965SWilliam.Taylor@Oracle.COM IBTF_DPRINTF_L2("fmr", "dirty: mr %p key %x",
2845*12965SWilliam.Taylor@Oracle.COM fmr->fmr, fmr->fmr->mr_rkey);
2846*12965SWilliam.Taylor@Oracle.COM _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*(fmr->fmr)))
28479517SBill.Taylor@Sun.COM
2848*12965SWilliam.Taylor@Oracle.COM mutex_enter(&fmrpool->dirty_lock);
2849*12965SWilliam.Taylor@Oracle.COM fmr->fmr_next = NULL;
2850*12965SWilliam.Taylor@Oracle.COM *(fmrpool->fmr_dirty_list_tail) = fmr;
2851*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_dirty_list_tail = &fmr->fmr_next;
2852*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_dirty_len++;
28539517SBill.Taylor@Sun.COM
2854*12965SWilliam.Taylor@Oracle.COM if (fmrpool->fmr_dirty_len >=
2855*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_dirty_watermark) {
2856*12965SWilliam.Taylor@Oracle.COM mutex_exit(&fmrpool->dirty_lock);
2857*12965SWilliam.Taylor@Oracle.COM mutex_enter(&fmrpool->fmr_lock);
2858*12965SWilliam.Taylor@Oracle.COM hermon_fmr_cleanup(fmrpool);
28599517SBill.Taylor@Sun.COM mutex_exit(&fmrpool->fmr_lock);
2860*12965SWilliam.Taylor@Oracle.COM } else
2861*12965SWilliam.Taylor@Oracle.COM mutex_exit(&fmrpool->dirty_lock);
28629517SBill.Taylor@Sun.COM }
2863*12965SWilliam.Taylor@Oracle.COM return (DDI_SUCCESS);
28649517SBill.Taylor@Sun.COM }
28659517SBill.Taylor@Sun.COM
28669517SBill.Taylor@Sun.COM /*
28679517SBill.Taylor@Sun.COM * hermon_fmr_cleanup()
2868*12965SWilliam.Taylor@Oracle.COM * Context: Called from any context.
28699517SBill.Taylor@Sun.COM */
2870*12965SWilliam.Taylor@Oracle.COM static void
hermon_fmr_cleanup(hermon_fmrhdl_t fmrpool)2871*12965SWilliam.Taylor@Oracle.COM hermon_fmr_cleanup(hermon_fmrhdl_t fmrpool)
28729517SBill.Taylor@Sun.COM {
28739517SBill.Taylor@Sun.COM int status;
28749517SBill.Taylor@Sun.COM
28759517SBill.Taylor@Sun.COM ASSERT(MUTEX_HELD(&fmrpool->fmr_lock));
28769517SBill.Taylor@Sun.COM
2877*12965SWilliam.Taylor@Oracle.COM if (fmrpool->fmr_stat_register == 0)
2878*12965SWilliam.Taylor@Oracle.COM return;
28799517SBill.Taylor@Sun.COM
2880*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_stat_register = 0;
2881*12965SWilliam.Taylor@Oracle.COM membar_producer();
28829517SBill.Taylor@Sun.COM
2883*12965SWilliam.Taylor@Oracle.COM if (hermon_fmr_verbose)
2884*12965SWilliam.Taylor@Oracle.COM IBTF_DPRINTF_L2("fmr", "TPT_SYNC");
2885*12965SWilliam.Taylor@Oracle.COM status = hermon_sync_tpt_cmd_post(fmrpool->fmr_state,
2886*12965SWilliam.Taylor@Oracle.COM HERMON_CMD_NOSLEEP_SPIN);
2887*12965SWilliam.Taylor@Oracle.COM if (status != HERMON_CMD_SUCCESS) {
2888*12965SWilliam.Taylor@Oracle.COM cmn_err(CE_WARN, "fmr SYNC_TPT failed(%x)\n", status);
2889*12965SWilliam.Taylor@Oracle.COM }
2890*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_gen++;
28919517SBill.Taylor@Sun.COM
2892*12965SWilliam.Taylor@Oracle.COM /* add everything back to the free list */
2893*12965SWilliam.Taylor@Oracle.COM mutex_enter(&fmrpool->dirty_lock);
2894*12965SWilliam.Taylor@Oracle.COM if (fmrpool->fmr_dirty_list) {
2895*12965SWilliam.Taylor@Oracle.COM /* add to free list */
2896*12965SWilliam.Taylor@Oracle.COM *(fmrpool->fmr_free_list_tail) = fmrpool->fmr_dirty_list;
2897*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_dirty_list = NULL;
2898*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_free_list_tail = fmrpool->fmr_dirty_list_tail;
28999517SBill.Taylor@Sun.COM
2900*12965SWilliam.Taylor@Oracle.COM /* reset list */
2901*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_dirty_list_tail = &fmrpool->fmr_dirty_list;
2902*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_free_len += fmrpool->fmr_dirty_len;
2903*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_dirty_len = 0;
29049517SBill.Taylor@Sun.COM }
2905*12965SWilliam.Taylor@Oracle.COM mutex_exit(&fmrpool->dirty_lock);
29069517SBill.Taylor@Sun.COM
2907*12965SWilliam.Taylor@Oracle.COM mutex_enter(&fmrpool->remap_lock);
2908*12965SWilliam.Taylor@Oracle.COM if (fmrpool->fmr_remap_list) {
2909*12965SWilliam.Taylor@Oracle.COM /* add to free list */
2910*12965SWilliam.Taylor@Oracle.COM *(fmrpool->fmr_free_list_tail) = fmrpool->fmr_remap_list;
2911*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_list = NULL;
2912*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_free_list_tail = fmrpool->fmr_remap_list_tail;
29139517SBill.Taylor@Sun.COM
2914*12965SWilliam.Taylor@Oracle.COM /* reset list */
2915*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_list_tail = &fmrpool->fmr_remap_list;
2916*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_free_len += fmrpool->fmr_remap_len;
2917*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_remap_len = 0;
2918*12965SWilliam.Taylor@Oracle.COM }
2919*12965SWilliam.Taylor@Oracle.COM mutex_exit(&fmrpool->remap_lock);
29209517SBill.Taylor@Sun.COM
2921*12965SWilliam.Taylor@Oracle.COM if (fmrpool->fmr_flush_function != NULL) {
2922*12965SWilliam.Taylor@Oracle.COM (void) fmrpool->fmr_flush_function(
2923*12965SWilliam.Taylor@Oracle.COM (ibc_fmr_pool_hdl_t)fmrpool,
2924*12965SWilliam.Taylor@Oracle.COM fmrpool->fmr_flush_arg);
29259517SBill.Taylor@Sun.COM }
29269517SBill.Taylor@Sun.COM }
2927