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_wr.c
289517SBill.Taylor@Sun.COM * Hermon Work Request Processing Routines
299517SBill.Taylor@Sun.COM *
309517SBill.Taylor@Sun.COM * Implements all the routines necessary to provide the PostSend(),
319517SBill.Taylor@Sun.COM * PostRecv() and PostSRQ() verbs. Also contains all the code
329517SBill.Taylor@Sun.COM * necessary to implement the Hermon WRID tracking mechanism.
339517SBill.Taylor@Sun.COM */
349517SBill.Taylor@Sun.COM
359517SBill.Taylor@Sun.COM #include <sys/types.h>
369517SBill.Taylor@Sun.COM #include <sys/conf.h>
379517SBill.Taylor@Sun.COM #include <sys/ddi.h>
389517SBill.Taylor@Sun.COM #include <sys/sunddi.h>
399517SBill.Taylor@Sun.COM #include <sys/modctl.h>
409517SBill.Taylor@Sun.COM #include <sys/avl.h>
419517SBill.Taylor@Sun.COM
429517SBill.Taylor@Sun.COM #include <sys/ib/adapters/hermon/hermon.h>
439517SBill.Taylor@Sun.COM
449517SBill.Taylor@Sun.COM static uint32_t hermon_wr_get_immediate(ibt_send_wr_t *wr);
459517SBill.Taylor@Sun.COM static int hermon_wr_bind_check(hermon_state_t *state, ibt_send_wr_t *wr);
469517SBill.Taylor@Sun.COM static int hermon_wqe_send_build(hermon_state_t *state, hermon_qphdl_t qp,
479517SBill.Taylor@Sun.COM ibt_send_wr_t *wr, uint64_t *desc, uint_t *size);
489517SBill.Taylor@Sun.COM static int hermon_wqe_mlx_build(hermon_state_t *state, hermon_qphdl_t qp,
499517SBill.Taylor@Sun.COM ibt_send_wr_t *wr, uint64_t *desc, uint_t *size);
509517SBill.Taylor@Sun.COM static void hermon_wqe_headroom(uint_t from, hermon_qphdl_t qp);
519517SBill.Taylor@Sun.COM static int hermon_wqe_recv_build(hermon_state_t *state, hermon_qphdl_t qp,
529517SBill.Taylor@Sun.COM ibt_recv_wr_t *wr, uint64_t *desc);
539517SBill.Taylor@Sun.COM static int hermon_wqe_srq_build(hermon_state_t *state, hermon_srqhdl_t srq,
549517SBill.Taylor@Sun.COM ibt_recv_wr_t *wr, uint64_t *desc);
559517SBill.Taylor@Sun.COM static hermon_workq_avl_t *hermon_wrid_wqavl_find(hermon_cqhdl_t cq, uint_t qpn,
569517SBill.Taylor@Sun.COM uint_t send_or_recv);
579517SBill.Taylor@Sun.COM static void hermon_cq_workq_add(hermon_cqhdl_t cq, hermon_workq_avl_t *wqavl);
589517SBill.Taylor@Sun.COM static void hermon_cq_workq_remove(hermon_cqhdl_t cq,
599517SBill.Taylor@Sun.COM hermon_workq_avl_t *wqavl);
609517SBill.Taylor@Sun.COM
619517SBill.Taylor@Sun.COM static ibt_wr_ds_t null_sgl = { 0, 0x00000100, 0 };
629517SBill.Taylor@Sun.COM
6311972SBill.Taylor@Sun.COM /*
6411972SBill.Taylor@Sun.COM * Add ability to try to debug RDMA_READ/RDMA_WRITE failures.
6511972SBill.Taylor@Sun.COM *
6611972SBill.Taylor@Sun.COM * 0x1 - print rkey used during post_send
6711972SBill.Taylor@Sun.COM * 0x2 - print sgls used during post_send
6811972SBill.Taylor@Sun.COM * 0x4 - print FMR comings and goings
6911972SBill.Taylor@Sun.COM */
7011972SBill.Taylor@Sun.COM int hermon_rdma_debug = 0x0;
7111972SBill.Taylor@Sun.COM
729517SBill.Taylor@Sun.COM static int
hermon_post_send_ud(hermon_state_t * state,hermon_qphdl_t qp,ibt_send_wr_t * wr,uint_t num_wr,uint_t * num_posted)739517SBill.Taylor@Sun.COM hermon_post_send_ud(hermon_state_t *state, hermon_qphdl_t qp,
749517SBill.Taylor@Sun.COM ibt_send_wr_t *wr, uint_t num_wr, uint_t *num_posted)
759517SBill.Taylor@Sun.COM {
769517SBill.Taylor@Sun.COM hermon_hw_snd_wqe_ud_t *ud;
779517SBill.Taylor@Sun.COM hermon_workq_hdr_t *wq;
789517SBill.Taylor@Sun.COM hermon_ahhdl_t ah;
79*12965SWilliam.Taylor@Oracle.COM ibt_wr_rfci_send_t *rfci;
80*12965SWilliam.Taylor@Oracle.COM ibt_wr_init_send_t *is;
819517SBill.Taylor@Sun.COM ibt_ud_dest_t *dest;
829517SBill.Taylor@Sun.COM uint64_t *desc;
839517SBill.Taylor@Sun.COM uint32_t desc_sz;
849517SBill.Taylor@Sun.COM uint32_t signaled_dbd, solicited;
859517SBill.Taylor@Sun.COM uint32_t head, tail, next_tail, qsize_msk;
869517SBill.Taylor@Sun.COM uint32_t hdrmwqes;
879517SBill.Taylor@Sun.COM uint32_t nopcode, fence, immed_data = 0;
8810633SRajkumar.Sivaprakasam@Sun.COM hermon_hw_wqe_sgl_t *ds, *old_ds;
899517SBill.Taylor@Sun.COM ibt_wr_ds_t *sgl;
90*12965SWilliam.Taylor@Oracle.COM int nds;
919517SBill.Taylor@Sun.COM int i, j, last_ds, num_ds, status;
929517SBill.Taylor@Sun.COM uint32_t *wqe_start;
939517SBill.Taylor@Sun.COM int sectperwqe;
949517SBill.Taylor@Sun.COM uint_t posted_cnt = 0;
95*12965SWilliam.Taylor@Oracle.COM int total_len, strong_order, fc_bits, cksum;
96*12965SWilliam.Taylor@Oracle.COM
979517SBill.Taylor@Sun.COM
989517SBill.Taylor@Sun.COM /* initialize the FMA retry loop */
999517SBill.Taylor@Sun.COM hermon_pio_init(fm_loop_cnt, fm_status, fm_test_num);
1009517SBill.Taylor@Sun.COM
1019517SBill.Taylor@Sun.COM ASSERT(MUTEX_HELD(&qp->qp_sq_lock));
1029517SBill.Taylor@Sun.COM _NOTE(LOCK_RELEASED_AS_SIDE_EFFECT(&qp->qp_sq_lock))
1039517SBill.Taylor@Sun.COM
1049517SBill.Taylor@Sun.COM /* Grab the lock for the WRID list */
1059517SBill.Taylor@Sun.COM membar_consumer();
1069517SBill.Taylor@Sun.COM
1079517SBill.Taylor@Sun.COM /* Save away some initial QP state */
1089517SBill.Taylor@Sun.COM wq = qp->qp_sq_wqhdr;
1099517SBill.Taylor@Sun.COM qsize_msk = wq->wq_mask;
1109517SBill.Taylor@Sun.COM hdrmwqes = qp->qp_sq_hdrmwqes; /* in WQEs */
1119517SBill.Taylor@Sun.COM sectperwqe = 1 << (qp->qp_sq_log_wqesz - 2);
1129517SBill.Taylor@Sun.COM
1139517SBill.Taylor@Sun.COM tail = wq->wq_tail;
1149517SBill.Taylor@Sun.COM head = wq->wq_head;
1159517SBill.Taylor@Sun.COM status = DDI_SUCCESS;
1169517SBill.Taylor@Sun.COM
1179517SBill.Taylor@Sun.COM post_next:
1189517SBill.Taylor@Sun.COM /*
1199517SBill.Taylor@Sun.COM * Check for "queue full" condition. If the queue
1209517SBill.Taylor@Sun.COM * is already full, then no more WQEs can be posted.
1219517SBill.Taylor@Sun.COM * So break out, ring a doorbell (if necessary) and
1229517SBill.Taylor@Sun.COM * return an error
1239517SBill.Taylor@Sun.COM */
1249517SBill.Taylor@Sun.COM if (wq->wq_full != 0) {
1259517SBill.Taylor@Sun.COM status = IBT_QP_FULL;
1269517SBill.Taylor@Sun.COM goto done;
1279517SBill.Taylor@Sun.COM }
1289517SBill.Taylor@Sun.COM
1299517SBill.Taylor@Sun.COM next_tail = (tail + 1) & qsize_msk;
1309517SBill.Taylor@Sun.COM if (((tail + hdrmwqes) & qsize_msk) == head) {
1319517SBill.Taylor@Sun.COM wq->wq_full = 1;
1329517SBill.Taylor@Sun.COM }
1339517SBill.Taylor@Sun.COM
1349517SBill.Taylor@Sun.COM desc = HERMON_QP_SQ_ENTRY(qp, tail);
1359517SBill.Taylor@Sun.COM
1369517SBill.Taylor@Sun.COM nds = wr->wr_nds;
1379517SBill.Taylor@Sun.COM sgl = wr->wr_sgl;
1389517SBill.Taylor@Sun.COM num_ds = 0;
139*12965SWilliam.Taylor@Oracle.COM strong_order = 0;
140*12965SWilliam.Taylor@Oracle.COM fc_bits = 0;
141*12965SWilliam.Taylor@Oracle.COM cksum = 0;
1429517SBill.Taylor@Sun.COM
1439517SBill.Taylor@Sun.COM /*
1449517SBill.Taylor@Sun.COM * Build a Send or Send_LSO WQE
1459517SBill.Taylor@Sun.COM */
146*12965SWilliam.Taylor@Oracle.COM switch (wr->wr_opcode) {
147*12965SWilliam.Taylor@Oracle.COM case IBT_WRC_SEND_LSO:
148*12965SWilliam.Taylor@Oracle.COM if (wr->wr_trans != IBT_UD_SRV) {
149*12965SWilliam.Taylor@Oracle.COM status = IBT_QP_SRV_TYPE_INVALID;
150*12965SWilliam.Taylor@Oracle.COM goto done;
151*12965SWilliam.Taylor@Oracle.COM }
1529517SBill.Taylor@Sun.COM nopcode = HERMON_WQE_SEND_NOPCODE_LSO;
153*12965SWilliam.Taylor@Oracle.COM if (wr->wr_flags & IBT_WR_SEND_CKSUM)
154*12965SWilliam.Taylor@Oracle.COM cksum = 0x30;
15510633SRajkumar.Sivaprakasam@Sun.COM if (wr->wr.ud_lso.lso_hdr_sz > 60) {
15610633SRajkumar.Sivaprakasam@Sun.COM nopcode |= (1 << 6); /* ReRead bit must be set */
15710633SRajkumar.Sivaprakasam@Sun.COM }
1589517SBill.Taylor@Sun.COM dest = wr->wr.ud_lso.lso_ud_dest;
1599517SBill.Taylor@Sun.COM ah = (hermon_ahhdl_t)dest->ud_ah;
1609517SBill.Taylor@Sun.COM if (ah == NULL) {
1619517SBill.Taylor@Sun.COM status = IBT_AH_HDL_INVALID;
1629517SBill.Taylor@Sun.COM goto done;
1639517SBill.Taylor@Sun.COM }
164*12965SWilliam.Taylor@Oracle.COM ud = (hermon_hw_snd_wqe_ud_t *)((uintptr_t)desc +
165*12965SWilliam.Taylor@Oracle.COM sizeof (hermon_hw_snd_wqe_ctrl_t));
166*12965SWilliam.Taylor@Oracle.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)ud +
167*12965SWilliam.Taylor@Oracle.COM sizeof (hermon_hw_snd_wqe_ud_t));
1689517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_UD(qp, ud, ah, dest);
1699517SBill.Taylor@Sun.COM
1709517SBill.Taylor@Sun.COM total_len = (4 + 0xf + wr->wr.ud_lso.lso_hdr_sz) & ~0xf;
1719517SBill.Taylor@Sun.COM if ((uintptr_t)ds + total_len + (nds * 16) >
1729517SBill.Taylor@Sun.COM (uintptr_t)desc + (1 << qp->qp_sq_log_wqesz)) {
1739517SBill.Taylor@Sun.COM status = IBT_QP_SGL_LEN_INVALID;
1749517SBill.Taylor@Sun.COM goto done;
1759517SBill.Taylor@Sun.COM }
17610633SRajkumar.Sivaprakasam@Sun.COM old_ds = ds;
17710633SRajkumar.Sivaprakasam@Sun.COM bcopy(wr->wr.ud_lso.lso_hdr, (uint32_t *)old_ds + 1,
1789517SBill.Taylor@Sun.COM wr->wr.ud_lso.lso_hdr_sz);
1799517SBill.Taylor@Sun.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)ds + total_len);
18010633SRajkumar.Sivaprakasam@Sun.COM i = 0;
181*12965SWilliam.Taylor@Oracle.COM break;
182*12965SWilliam.Taylor@Oracle.COM
183*12965SWilliam.Taylor@Oracle.COM case IBT_WRC_SEND:
184*12965SWilliam.Taylor@Oracle.COM nopcode = HERMON_WQE_SEND_NOPCODE_SEND;
185*12965SWilliam.Taylor@Oracle.COM if (qp->qp_serv_type == HERMON_QP_UD) {
186*12965SWilliam.Taylor@Oracle.COM if (wr->wr_trans != IBT_UD_SRV) {
187*12965SWilliam.Taylor@Oracle.COM status = IBT_QP_SRV_TYPE_INVALID;
188*12965SWilliam.Taylor@Oracle.COM goto done;
189*12965SWilliam.Taylor@Oracle.COM }
190*12965SWilliam.Taylor@Oracle.COM if (wr->wr_flags & IBT_WR_SEND_CKSUM)
191*12965SWilliam.Taylor@Oracle.COM cksum = 0x30;
192*12965SWilliam.Taylor@Oracle.COM dest = wr->wr.ud.udwr_dest;
193*12965SWilliam.Taylor@Oracle.COM } else if (qp->qp_serv_type == HERMON_QP_RFCI) {
194*12965SWilliam.Taylor@Oracle.COM if (wr->wr_trans != IBT_RFCI_SRV) {
195*12965SWilliam.Taylor@Oracle.COM status = IBT_QP_SRV_TYPE_INVALID;
196*12965SWilliam.Taylor@Oracle.COM goto done;
197*12965SWilliam.Taylor@Oracle.COM }
198*12965SWilliam.Taylor@Oracle.COM rfci = &wr->wr.fc.rfci_send;
199*12965SWilliam.Taylor@Oracle.COM if ((wr->wr_flags & IBT_WR_SEND_FC_CRC) != 0) {
200*12965SWilliam.Taylor@Oracle.COM nopcode |= (rfci->rfci_eof << 16);
201*12965SWilliam.Taylor@Oracle.COM fc_bits = 0x40; /* set FCRC */
202*12965SWilliam.Taylor@Oracle.COM }
203*12965SWilliam.Taylor@Oracle.COM dest = rfci->rfci_dest;
204*12965SWilliam.Taylor@Oracle.COM } else {
205*12965SWilliam.Taylor@Oracle.COM status = IBT_QP_OP_TYPE_INVALID;
206*12965SWilliam.Taylor@Oracle.COM goto done;
207*12965SWilliam.Taylor@Oracle.COM }
2089517SBill.Taylor@Sun.COM if (wr->wr_flags & IBT_WR_SEND_IMMED) {
209*12965SWilliam.Taylor@Oracle.COM /* "|=" changes 0xa to 0xb without touching FCEOF */
210*12965SWilliam.Taylor@Oracle.COM nopcode |= HERMON_WQE_SEND_NOPCODE_SENDI;
2119517SBill.Taylor@Sun.COM immed_data = wr->wr.ud.udwr_immed;
2129517SBill.Taylor@Sun.COM }
2139517SBill.Taylor@Sun.COM ah = (hermon_ahhdl_t)dest->ud_ah;
2149517SBill.Taylor@Sun.COM if (ah == NULL) {
2159517SBill.Taylor@Sun.COM status = IBT_AH_HDL_INVALID;
2169517SBill.Taylor@Sun.COM goto done;
2179517SBill.Taylor@Sun.COM }
218*12965SWilliam.Taylor@Oracle.COM ud = (hermon_hw_snd_wqe_ud_t *)((uintptr_t)desc +
219*12965SWilliam.Taylor@Oracle.COM sizeof (hermon_hw_snd_wqe_ctrl_t));
220*12965SWilliam.Taylor@Oracle.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)ud +
221*12965SWilliam.Taylor@Oracle.COM sizeof (hermon_hw_snd_wqe_ud_t));
2229517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_UD(qp, ud, ah, dest);
2239517SBill.Taylor@Sun.COM i = 0;
224*12965SWilliam.Taylor@Oracle.COM break;
225*12965SWilliam.Taylor@Oracle.COM
226*12965SWilliam.Taylor@Oracle.COM case IBT_WRC_INIT_SEND_FCMD:
227*12965SWilliam.Taylor@Oracle.COM if (qp->qp_serv_type != HERMON_QP_FCMND) {
228*12965SWilliam.Taylor@Oracle.COM status = IBT_QP_OP_TYPE_INVALID;
229*12965SWilliam.Taylor@Oracle.COM goto done;
230*12965SWilliam.Taylor@Oracle.COM }
231*12965SWilliam.Taylor@Oracle.COM if (wr->wr_trans != IBT_FCMD_SRV) {
232*12965SWilliam.Taylor@Oracle.COM status = IBT_QP_SRV_TYPE_INVALID;
233*12965SWilliam.Taylor@Oracle.COM goto done;
234*12965SWilliam.Taylor@Oracle.COM }
235*12965SWilliam.Taylor@Oracle.COM nopcode = HERMON_WQE_FCP_OPCODE_INIT_AND_SEND;
236*12965SWilliam.Taylor@Oracle.COM is = wr->wr.fc.fc_is;
237*12965SWilliam.Taylor@Oracle.COM dest = is->is_ctl.fc_dest;
238*12965SWilliam.Taylor@Oracle.COM ah = (hermon_ahhdl_t)dest->ud_ah;
239*12965SWilliam.Taylor@Oracle.COM if (ah == NULL) {
240*12965SWilliam.Taylor@Oracle.COM status = IBT_AH_HDL_INVALID;
241*12965SWilliam.Taylor@Oracle.COM goto done;
242*12965SWilliam.Taylor@Oracle.COM }
243*12965SWilliam.Taylor@Oracle.COM ud = (hermon_hw_snd_wqe_ud_t *)((uintptr_t)desc +
244*12965SWilliam.Taylor@Oracle.COM sizeof (hermon_hw_snd_wqe_ctrl_t));
245*12965SWilliam.Taylor@Oracle.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)ud +
246*12965SWilliam.Taylor@Oracle.COM sizeof (hermon_hw_snd_wqe_ud_t));
247*12965SWilliam.Taylor@Oracle.COM HERMON_WQE_BUILD_UD(qp, ud, ah, dest);
248*12965SWilliam.Taylor@Oracle.COM old_ds = ds;
249*12965SWilliam.Taylor@Oracle.COM /* move ds beyond the FCP-3 Init Segment */
250*12965SWilliam.Taylor@Oracle.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)ds + 0x10);
251*12965SWilliam.Taylor@Oracle.COM i = 0;
252*12965SWilliam.Taylor@Oracle.COM break;
253*12965SWilliam.Taylor@Oracle.COM
254*12965SWilliam.Taylor@Oracle.COM case IBT_WRC_FAST_REG_PMR:
255*12965SWilliam.Taylor@Oracle.COM {
256*12965SWilliam.Taylor@Oracle.COM hermon_hw_snd_wqe_frwr_t *frwr;
257*12965SWilliam.Taylor@Oracle.COM
258*12965SWilliam.Taylor@Oracle.COM if (qp->qp_serv_type != HERMON_QP_FCMND) {
259*12965SWilliam.Taylor@Oracle.COM status = IBT_QP_OP_TYPE_INVALID;
260*12965SWilliam.Taylor@Oracle.COM goto done;
261*12965SWilliam.Taylor@Oracle.COM }
262*12965SWilliam.Taylor@Oracle.COM if (wr->wr_trans != IBT_FCMD_SRV) {
263*12965SWilliam.Taylor@Oracle.COM status = IBT_QP_SRV_TYPE_INVALID;
264*12965SWilliam.Taylor@Oracle.COM goto done;
265*12965SWilliam.Taylor@Oracle.COM }
266*12965SWilliam.Taylor@Oracle.COM nopcode = HERMON_WQE_SEND_NOPCODE_FRWR;
267*12965SWilliam.Taylor@Oracle.COM frwr = (hermon_hw_snd_wqe_frwr_t *)((uintptr_t)desc +
268*12965SWilliam.Taylor@Oracle.COM sizeof (hermon_hw_snd_wqe_ctrl_t));
269*12965SWilliam.Taylor@Oracle.COM HERMON_WQE_BUILD_FRWR(qp, frwr, wr->wr.fc.reg_pmr);
270*12965SWilliam.Taylor@Oracle.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)frwr +
271*12965SWilliam.Taylor@Oracle.COM sizeof (hermon_hw_snd_wqe_frwr_t));
272*12965SWilliam.Taylor@Oracle.COM nds = 0;
273*12965SWilliam.Taylor@Oracle.COM strong_order = 0x80;
274*12965SWilliam.Taylor@Oracle.COM break;
275*12965SWilliam.Taylor@Oracle.COM }
276*12965SWilliam.Taylor@Oracle.COM
277*12965SWilliam.Taylor@Oracle.COM #if 0
278*12965SWilliam.Taylor@Oracle.COM /* firmware does not support this */
279*12965SWilliam.Taylor@Oracle.COM case IBT_WRC_LOCAL_INVALIDATE:
280*12965SWilliam.Taylor@Oracle.COM {
281*12965SWilliam.Taylor@Oracle.COM hermon_hw_snd_wqe_local_inv_t *li;
282*12965SWilliam.Taylor@Oracle.COM
283*12965SWilliam.Taylor@Oracle.COM if (qp->qp_serv_type != HERMON_QP_FCMND) {
284*12965SWilliam.Taylor@Oracle.COM status = IBT_QP_OP_TYPE_INVALID;
285*12965SWilliam.Taylor@Oracle.COM goto done;
286*12965SWilliam.Taylor@Oracle.COM }
287*12965SWilliam.Taylor@Oracle.COM if (wr->wr_trans != IBT_FCMD_SRV) {
288*12965SWilliam.Taylor@Oracle.COM status = IBT_QP_SRV_TYPE_INVALID;
289*12965SWilliam.Taylor@Oracle.COM goto done;
290*12965SWilliam.Taylor@Oracle.COM }
291*12965SWilliam.Taylor@Oracle.COM nopcode = HERMON_WQE_SEND_NOPCODE_LCL_INV;
292*12965SWilliam.Taylor@Oracle.COM li = (hermon_hw_snd_wqe_local_inv_t *)((uintptr_t)desc +
293*12965SWilliam.Taylor@Oracle.COM sizeof (hermon_hw_snd_wqe_ctrl_t));
294*12965SWilliam.Taylor@Oracle.COM HERMON_WQE_BUILD_LI(qp, li, wr->wr.fc.li);
295*12965SWilliam.Taylor@Oracle.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)li +
296*12965SWilliam.Taylor@Oracle.COM sizeof (hermon_hw_snd_wqe_local_inv_t));
297*12965SWilliam.Taylor@Oracle.COM nds = 0;
298*12965SWilliam.Taylor@Oracle.COM strong_order = 0x80;
299*12965SWilliam.Taylor@Oracle.COM break;
300*12965SWilliam.Taylor@Oracle.COM }
301*12965SWilliam.Taylor@Oracle.COM #endif
302*12965SWilliam.Taylor@Oracle.COM default:
3039517SBill.Taylor@Sun.COM status = IBT_QP_OP_TYPE_INVALID;
3049517SBill.Taylor@Sun.COM goto done;
3059517SBill.Taylor@Sun.COM }
3069517SBill.Taylor@Sun.COM
3079517SBill.Taylor@Sun.COM if (nds > qp->qp_sq_sgl) {
3089517SBill.Taylor@Sun.COM status = IBT_QP_SGL_LEN_INVALID;
3099517SBill.Taylor@Sun.COM goto done;
3109517SBill.Taylor@Sun.COM }
3119517SBill.Taylor@Sun.COM for (last_ds = num_ds, j = i; j < nds; j++) {
3129517SBill.Taylor@Sun.COM if (sgl[j].ds_len != 0)
3139517SBill.Taylor@Sun.COM last_ds++; /* real last ds of wqe to fill */
3149517SBill.Taylor@Sun.COM }
3159517SBill.Taylor@Sun.COM desc_sz = ((uintptr_t)&ds[last_ds] - (uintptr_t)desc) >> 0x4;
3169517SBill.Taylor@Sun.COM for (j = nds; --j >= i; ) {
3179517SBill.Taylor@Sun.COM if (sgl[j].ds_len == 0) {
3189517SBill.Taylor@Sun.COM continue;
3199517SBill.Taylor@Sun.COM }
3209517SBill.Taylor@Sun.COM
3219517SBill.Taylor@Sun.COM /*
3229517SBill.Taylor@Sun.COM * Fill in the Data Segment(s) for the current WQE, using the
3239517SBill.Taylor@Sun.COM * information contained in the scatter-gather list of the
3249517SBill.Taylor@Sun.COM * work request.
3259517SBill.Taylor@Sun.COM */
3269517SBill.Taylor@Sun.COM last_ds--;
3279517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_DATA_SEG_SEND(&ds[last_ds], &sgl[j]);
3289517SBill.Taylor@Sun.COM }
3299517SBill.Taylor@Sun.COM
33010633SRajkumar.Sivaprakasam@Sun.COM membar_producer();
33110633SRajkumar.Sivaprakasam@Sun.COM
33210633SRajkumar.Sivaprakasam@Sun.COM if (wr->wr_opcode == IBT_WRC_SEND_LSO) {
33310633SRajkumar.Sivaprakasam@Sun.COM HERMON_WQE_BUILD_LSO(qp, old_ds, wr->wr.ud_lso.lso_mss,
33410633SRajkumar.Sivaprakasam@Sun.COM wr->wr.ud_lso.lso_hdr_sz);
335*12965SWilliam.Taylor@Oracle.COM } else if (wr->wr_opcode == IBT_WRC_INIT_SEND_FCMD) {
336*12965SWilliam.Taylor@Oracle.COM /* This sits in the STAMP, so must be set after setting SGL */
337*12965SWilliam.Taylor@Oracle.COM HERMON_WQE_BUILD_FCP3_INIT(old_ds, is->is_ctl.fc_frame_ctrl,
338*12965SWilliam.Taylor@Oracle.COM is->is_cs_priority, is->is_tx_seq_id, is->is_fc_mtu,
339*12965SWilliam.Taylor@Oracle.COM is->is_dest_id, is->is_op, is->is_rem_exch,
340*12965SWilliam.Taylor@Oracle.COM is->is_exch_qp_idx);
341*12965SWilliam.Taylor@Oracle.COM
342*12965SWilliam.Taylor@Oracle.COM /* The following will be used in HERMON_WQE_SET_CTRL_SEGMENT */
343*12965SWilliam.Taylor@Oracle.COM /* SIT bit in FCP-3 ctrl segment */
344*12965SWilliam.Taylor@Oracle.COM desc_sz |= (is->is_ctl.fc_frame_ctrl & IBT_FCTL_SIT) ? 0x80 : 0;
345*12965SWilliam.Taylor@Oracle.COM /* LS bit in FCP-3 ctrl segment */
346*12965SWilliam.Taylor@Oracle.COM fc_bits |= (is->is_ctl.fc_frame_ctrl & IBT_FCTL_LAST_SEQ) ?
347*12965SWilliam.Taylor@Oracle.COM 0x10000 : 0;
348*12965SWilliam.Taylor@Oracle.COM fc_bits |= ((is->is_ctl.fc_routing_ctrl & 0xF) << 20) |
349*12965SWilliam.Taylor@Oracle.COM (is->is_ctl.fc_seq_id << 24);
350*12965SWilliam.Taylor@Oracle.COM immed_data = is->is_ctl.fc_parameter;
35110633SRajkumar.Sivaprakasam@Sun.COM }
35210633SRajkumar.Sivaprakasam@Sun.COM
3539517SBill.Taylor@Sun.COM fence = (wr->wr_flags & IBT_WR_SEND_FENCE) ? 1 : 0;
3549517SBill.Taylor@Sun.COM
3559517SBill.Taylor@Sun.COM signaled_dbd = ((qp->qp_sq_sigtype == HERMON_QP_SQ_ALL_SIGNALED) ||
356*12965SWilliam.Taylor@Oracle.COM (wr->wr_flags & IBT_WR_SEND_SIGNAL)) ? 0xC : 0;
3579517SBill.Taylor@Sun.COM
358*12965SWilliam.Taylor@Oracle.COM solicited = (wr->wr_flags & IBT_WR_SEND_SOLICIT) ? 0x2 : 0;
3599517SBill.Taylor@Sun.COM
3609517SBill.Taylor@Sun.COM HERMON_WQE_SET_CTRL_SEGMENT(desc, desc_sz, fence, immed_data,
361*12965SWilliam.Taylor@Oracle.COM solicited, signaled_dbd, cksum, qp, strong_order, fc_bits);
3629517SBill.Taylor@Sun.COM
3639517SBill.Taylor@Sun.COM wq->wq_wrid[tail] = wr->wr_id;
3649517SBill.Taylor@Sun.COM
3659517SBill.Taylor@Sun.COM tail = next_tail;
3669517SBill.Taylor@Sun.COM
3679517SBill.Taylor@Sun.COM /* Update some of the state in the QP */
3689517SBill.Taylor@Sun.COM wq->wq_tail = tail;
3699517SBill.Taylor@Sun.COM
3709517SBill.Taylor@Sun.COM membar_producer();
3719517SBill.Taylor@Sun.COM
3729517SBill.Taylor@Sun.COM /* Now set the ownership bit and opcode (first dword). */
3739517SBill.Taylor@Sun.COM HERMON_SET_SEND_WQE_OWNER(qp, (uint32_t *)desc, nopcode);
3749517SBill.Taylor@Sun.COM
3759517SBill.Taylor@Sun.COM posted_cnt++;
3769517SBill.Taylor@Sun.COM if (--num_wr > 0) {
3779517SBill.Taylor@Sun.COM /* do the invalidate of the headroom */
3789517SBill.Taylor@Sun.COM wqe_start = (uint32_t *)HERMON_QP_SQ_ENTRY(qp,
3799517SBill.Taylor@Sun.COM (tail + hdrmwqes) & qsize_msk);
3809517SBill.Taylor@Sun.COM for (i = 16; i < sectperwqe; i += 16) {
3819517SBill.Taylor@Sun.COM wqe_start[i] = 0xFFFFFFFF;
3829517SBill.Taylor@Sun.COM }
3839517SBill.Taylor@Sun.COM
3849517SBill.Taylor@Sun.COM wr++;
3859517SBill.Taylor@Sun.COM goto post_next;
3869517SBill.Taylor@Sun.COM }
3879517SBill.Taylor@Sun.COM done:
3889517SBill.Taylor@Sun.COM if (posted_cnt != 0) {
3899517SBill.Taylor@Sun.COM ddi_acc_handle_t uarhdl = hermon_get_uarhdl(state);
3909517SBill.Taylor@Sun.COM
3919517SBill.Taylor@Sun.COM membar_producer();
3929517SBill.Taylor@Sun.COM
3939517SBill.Taylor@Sun.COM /* the FMA retry loop starts for Hermon doorbell register. */
3949517SBill.Taylor@Sun.COM hermon_pio_start(state, uarhdl, pio_error, fm_loop_cnt,
3959517SBill.Taylor@Sun.COM fm_status, fm_test_num);
3969517SBill.Taylor@Sun.COM
3979517SBill.Taylor@Sun.COM HERMON_UAR_DOORBELL(state, uarhdl,
3989517SBill.Taylor@Sun.COM (uint64_t *)(void *)&state->hs_uar->send,
3999517SBill.Taylor@Sun.COM (uint64_t)qp->qp_ring);
4009517SBill.Taylor@Sun.COM
4019517SBill.Taylor@Sun.COM /* the FMA retry loop ends. */
4029517SBill.Taylor@Sun.COM hermon_pio_end(state, uarhdl, pio_error, fm_loop_cnt,
4039517SBill.Taylor@Sun.COM fm_status, fm_test_num);
4049517SBill.Taylor@Sun.COM
4059517SBill.Taylor@Sun.COM /* do the invalidate of the headroom */
4069517SBill.Taylor@Sun.COM wqe_start = (uint32_t *)HERMON_QP_SQ_ENTRY(qp,
4079517SBill.Taylor@Sun.COM (tail + hdrmwqes) & qsize_msk);
4089517SBill.Taylor@Sun.COM for (i = 16; i < sectperwqe; i += 16) {
4099517SBill.Taylor@Sun.COM wqe_start[i] = 0xFFFFFFFF;
4109517SBill.Taylor@Sun.COM }
4119517SBill.Taylor@Sun.COM }
4129517SBill.Taylor@Sun.COM if (num_posted != NULL)
4139517SBill.Taylor@Sun.COM *num_posted = posted_cnt;
4149517SBill.Taylor@Sun.COM
4159517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_sq_lock);
4169517SBill.Taylor@Sun.COM
4179517SBill.Taylor@Sun.COM return (status);
4189517SBill.Taylor@Sun.COM
4199517SBill.Taylor@Sun.COM pio_error:
4209517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_sq_lock);
4219517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
4229517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
4239517SBill.Taylor@Sun.COM }
4249517SBill.Taylor@Sun.COM
4259517SBill.Taylor@Sun.COM static int
hermon_post_send_rc(hermon_state_t * state,hermon_qphdl_t qp,ibt_send_wr_t * wr,uint_t num_wr,uint_t * num_posted)4269517SBill.Taylor@Sun.COM hermon_post_send_rc(hermon_state_t *state, hermon_qphdl_t qp,
4279517SBill.Taylor@Sun.COM ibt_send_wr_t *wr, uint_t num_wr, uint_t *num_posted)
4289517SBill.Taylor@Sun.COM {
4299517SBill.Taylor@Sun.COM uint64_t *desc;
4309517SBill.Taylor@Sun.COM hermon_workq_hdr_t *wq;
4319517SBill.Taylor@Sun.COM uint32_t desc_sz;
4329517SBill.Taylor@Sun.COM uint32_t signaled_dbd, solicited;
4339517SBill.Taylor@Sun.COM uint32_t head, tail, next_tail, qsize_msk;
4349517SBill.Taylor@Sun.COM uint32_t hdrmwqes;
4359517SBill.Taylor@Sun.COM int status;
4369517SBill.Taylor@Sun.COM uint32_t nopcode, fence, immed_data = 0;
4379517SBill.Taylor@Sun.COM hermon_hw_snd_wqe_remaddr_t *rc;
4389517SBill.Taylor@Sun.COM hermon_hw_snd_wqe_atomic_t *at;
4399517SBill.Taylor@Sun.COM hermon_hw_snd_wqe_bind_t *bn;
440*12965SWilliam.Taylor@Oracle.COM hermon_hw_snd_wqe_frwr_t *frwr;
441*12965SWilliam.Taylor@Oracle.COM hermon_hw_snd_wqe_local_inv_t *li;
4429517SBill.Taylor@Sun.COM hermon_hw_wqe_sgl_t *ds;
4439517SBill.Taylor@Sun.COM ibt_wr_ds_t *sgl;
444*12965SWilliam.Taylor@Oracle.COM int nds;
4459517SBill.Taylor@Sun.COM int i, last_ds, num_ds;
4469517SBill.Taylor@Sun.COM uint32_t *wqe_start;
4479517SBill.Taylor@Sun.COM int sectperwqe;
4489517SBill.Taylor@Sun.COM uint_t posted_cnt = 0;
449*12965SWilliam.Taylor@Oracle.COM int strong_order;
45011972SBill.Taylor@Sun.COM int print_rdma;
45111972SBill.Taylor@Sun.COM int rlen;
45211972SBill.Taylor@Sun.COM uint32_t rkey;
45311972SBill.Taylor@Sun.COM uint64_t raddr;
4549517SBill.Taylor@Sun.COM
4559517SBill.Taylor@Sun.COM /* initialize the FMA retry loop */
4569517SBill.Taylor@Sun.COM hermon_pio_init(fm_loop_cnt, fm_status, fm_test_num);
4579517SBill.Taylor@Sun.COM
4589517SBill.Taylor@Sun.COM ASSERT(MUTEX_HELD(&qp->qp_sq_lock));
4599517SBill.Taylor@Sun.COM _NOTE(LOCK_RELEASED_AS_SIDE_EFFECT(&qp->qp_sq_lock))
4609517SBill.Taylor@Sun.COM
4619517SBill.Taylor@Sun.COM /* Save away some initial QP state */
4629517SBill.Taylor@Sun.COM wq = qp->qp_sq_wqhdr;
4639517SBill.Taylor@Sun.COM qsize_msk = wq->wq_mask;
4649517SBill.Taylor@Sun.COM hdrmwqes = qp->qp_sq_hdrmwqes; /* in WQEs */
4659517SBill.Taylor@Sun.COM sectperwqe = 1 << (qp->qp_sq_log_wqesz - 2);
4669517SBill.Taylor@Sun.COM
4679517SBill.Taylor@Sun.COM tail = wq->wq_tail;
4689517SBill.Taylor@Sun.COM head = wq->wq_head;
4699517SBill.Taylor@Sun.COM status = DDI_SUCCESS;
4709517SBill.Taylor@Sun.COM
4719517SBill.Taylor@Sun.COM post_next:
47211972SBill.Taylor@Sun.COM print_rdma = 0;
47311972SBill.Taylor@Sun.COM rlen = 0;
474*12965SWilliam.Taylor@Oracle.COM strong_order = 0;
47511972SBill.Taylor@Sun.COM
4769517SBill.Taylor@Sun.COM /*
4779517SBill.Taylor@Sun.COM * Check for "queue full" condition. If the queue
4789517SBill.Taylor@Sun.COM * is already full, then no more WQEs can be posted.
4799517SBill.Taylor@Sun.COM * So break out, ring a doorbell (if necessary) and
4809517SBill.Taylor@Sun.COM * return an error
4819517SBill.Taylor@Sun.COM */
4829517SBill.Taylor@Sun.COM if (wq->wq_full != 0) {
4839517SBill.Taylor@Sun.COM status = IBT_QP_FULL;
4849517SBill.Taylor@Sun.COM goto done;
4859517SBill.Taylor@Sun.COM }
4869517SBill.Taylor@Sun.COM next_tail = (tail + 1) & qsize_msk;
4879517SBill.Taylor@Sun.COM if (((tail + hdrmwqes) & qsize_msk) == head) {
4889517SBill.Taylor@Sun.COM wq->wq_full = 1;
4899517SBill.Taylor@Sun.COM }
4909517SBill.Taylor@Sun.COM
4919517SBill.Taylor@Sun.COM desc = HERMON_QP_SQ_ENTRY(qp, tail);
4929517SBill.Taylor@Sun.COM
4939517SBill.Taylor@Sun.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)desc +
4949517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_ctrl_t));
4959517SBill.Taylor@Sun.COM nds = wr->wr_nds;
4969517SBill.Taylor@Sun.COM sgl = wr->wr_sgl;
4979517SBill.Taylor@Sun.COM num_ds = 0;
498*12965SWilliam.Taylor@Oracle.COM if (wr->wr_trans != IBT_RC_SRV) {
499*12965SWilliam.Taylor@Oracle.COM status = IBT_QP_SRV_TYPE_INVALID;
500*12965SWilliam.Taylor@Oracle.COM goto done;
501*12965SWilliam.Taylor@Oracle.COM }
5029517SBill.Taylor@Sun.COM
5039517SBill.Taylor@Sun.COM /*
5049517SBill.Taylor@Sun.COM * Validate the operation type. For RC requests, we allow
5059517SBill.Taylor@Sun.COM * "Send", "RDMA Read", "RDMA Write", various "Atomic"
5069517SBill.Taylor@Sun.COM * operations, and memory window "Bind"
5079517SBill.Taylor@Sun.COM */
5089517SBill.Taylor@Sun.COM switch (wr->wr_opcode) {
5099517SBill.Taylor@Sun.COM default:
5109517SBill.Taylor@Sun.COM status = IBT_QP_OP_TYPE_INVALID;
5119517SBill.Taylor@Sun.COM goto done;
5129517SBill.Taylor@Sun.COM
5139517SBill.Taylor@Sun.COM case IBT_WRC_SEND:
514*12965SWilliam.Taylor@Oracle.COM if (wr->wr_flags & IBT_WR_SEND_REMOTE_INVAL) {
515*12965SWilliam.Taylor@Oracle.COM nopcode = HERMON_WQE_SEND_NOPCODE_SND_INV;
516*12965SWilliam.Taylor@Oracle.COM immed_data = wr->wr.rc.rcwr.send_inval;
517*12965SWilliam.Taylor@Oracle.COM } else if (wr->wr_flags & IBT_WR_SEND_IMMED) {
5189517SBill.Taylor@Sun.COM nopcode = HERMON_WQE_SEND_NOPCODE_SENDI;
5199517SBill.Taylor@Sun.COM immed_data = wr->wr.rc.rcwr.send_immed;
5209517SBill.Taylor@Sun.COM } else {
5219517SBill.Taylor@Sun.COM nopcode = HERMON_WQE_SEND_NOPCODE_SEND;
5229517SBill.Taylor@Sun.COM }
5239517SBill.Taylor@Sun.COM break;
5249517SBill.Taylor@Sun.COM
5259517SBill.Taylor@Sun.COM /*
5269517SBill.Taylor@Sun.COM * If this is an RDMA Read or RDMA Write request, then fill
5279517SBill.Taylor@Sun.COM * in the "Remote Address" header fields.
5289517SBill.Taylor@Sun.COM */
5299517SBill.Taylor@Sun.COM case IBT_WRC_RDMAW:
5309517SBill.Taylor@Sun.COM if (wr->wr_flags & IBT_WR_SEND_IMMED) {
5319517SBill.Taylor@Sun.COM nopcode = HERMON_WQE_SEND_NOPCODE_RDMAWI;
5329517SBill.Taylor@Sun.COM immed_data = wr->wr.rc.rcwr.rdma.rdma_immed;
5339517SBill.Taylor@Sun.COM } else {
5349517SBill.Taylor@Sun.COM nopcode = HERMON_WQE_SEND_NOPCODE_RDMAW;
5359517SBill.Taylor@Sun.COM }
5369517SBill.Taylor@Sun.COM /* FALLTHROUGH */
5379517SBill.Taylor@Sun.COM case IBT_WRC_RDMAR:
5389517SBill.Taylor@Sun.COM if (wr->wr_opcode == IBT_WRC_RDMAR)
5399517SBill.Taylor@Sun.COM nopcode = HERMON_WQE_SEND_NOPCODE_RDMAR;
5409517SBill.Taylor@Sun.COM rc = (hermon_hw_snd_wqe_remaddr_t *)((uintptr_t)desc +
5419517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_ctrl_t));
5429517SBill.Taylor@Sun.COM
5439517SBill.Taylor@Sun.COM /*
5449517SBill.Taylor@Sun.COM * Build the Remote Address Segment for the WQE, using
5459517SBill.Taylor@Sun.COM * the information from the RC work request.
5469517SBill.Taylor@Sun.COM */
5479517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_REMADDR(qp, rc, &wr->wr.rc.rcwr.rdma);
5489517SBill.Taylor@Sun.COM
54911972SBill.Taylor@Sun.COM if (hermon_rdma_debug) {
55011972SBill.Taylor@Sun.COM print_rdma = hermon_rdma_debug;
55111972SBill.Taylor@Sun.COM rkey = wr->wr.rc.rcwr.rdma.rdma_rkey;
55211972SBill.Taylor@Sun.COM raddr = wr->wr.rc.rcwr.rdma.rdma_raddr;
55311972SBill.Taylor@Sun.COM }
55411972SBill.Taylor@Sun.COM
5559517SBill.Taylor@Sun.COM /* Update "ds" for filling in Data Segments (below) */
5569517SBill.Taylor@Sun.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)rc +
5579517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_remaddr_t));
5589517SBill.Taylor@Sun.COM break;
5599517SBill.Taylor@Sun.COM
5609517SBill.Taylor@Sun.COM /*
5619517SBill.Taylor@Sun.COM * If this is one of the Atomic type operations (i.e
5629517SBill.Taylor@Sun.COM * Compare-Swap or Fetch-Add), then fill in both the "Remote
5639517SBill.Taylor@Sun.COM * Address" header fields and the "Atomic" header fields.
5649517SBill.Taylor@Sun.COM */
5659517SBill.Taylor@Sun.COM case IBT_WRC_CSWAP:
5669517SBill.Taylor@Sun.COM nopcode = HERMON_WQE_SEND_NOPCODE_ATMCS;
5679517SBill.Taylor@Sun.COM /* FALLTHROUGH */
5689517SBill.Taylor@Sun.COM case IBT_WRC_FADD:
5699517SBill.Taylor@Sun.COM if (wr->wr_opcode == IBT_WRC_FADD)
5709517SBill.Taylor@Sun.COM nopcode = HERMON_WQE_SEND_NOPCODE_ATMFA;
5719517SBill.Taylor@Sun.COM rc = (hermon_hw_snd_wqe_remaddr_t *)((uintptr_t)desc +
5729517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_ctrl_t));
5739517SBill.Taylor@Sun.COM at = (hermon_hw_snd_wqe_atomic_t *)((uintptr_t)rc +
5749517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_remaddr_t));
5759517SBill.Taylor@Sun.COM
5769517SBill.Taylor@Sun.COM /*
5779517SBill.Taylor@Sun.COM * Build the Remote Address and Atomic Segments for
5789517SBill.Taylor@Sun.COM * the WQE, using the information from the RC Atomic
5799517SBill.Taylor@Sun.COM * work request.
5809517SBill.Taylor@Sun.COM */
5819517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_RC_ATOMIC_REMADDR(qp, rc, wr);
5829517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_ATOMIC(qp, at, wr->wr.rc.rcwr.atomic);
5839517SBill.Taylor@Sun.COM
5849517SBill.Taylor@Sun.COM /* Update "ds" for filling in Data Segments (below) */
5859517SBill.Taylor@Sun.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)at +
5869517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_atomic_t));
5879517SBill.Taylor@Sun.COM
5889517SBill.Taylor@Sun.COM /*
5899517SBill.Taylor@Sun.COM * Update "nds" and "sgl" because Atomic requests have
5909517SBill.Taylor@Sun.COM * only a single Data Segment.
5919517SBill.Taylor@Sun.COM */
5929517SBill.Taylor@Sun.COM nds = 1;
5939517SBill.Taylor@Sun.COM sgl = wr->wr_sgl;
5949517SBill.Taylor@Sun.COM break;
5959517SBill.Taylor@Sun.COM
5969517SBill.Taylor@Sun.COM /*
5979517SBill.Taylor@Sun.COM * If this is memory window Bind operation, then we call the
5989517SBill.Taylor@Sun.COM * hermon_wr_bind_check() routine to validate the request and
5999517SBill.Taylor@Sun.COM * to generate the updated RKey. If this is successful, then
6009517SBill.Taylor@Sun.COM * we fill in the WQE's "Bind" header fields.
6019517SBill.Taylor@Sun.COM */
6029517SBill.Taylor@Sun.COM case IBT_WRC_BIND:
6039517SBill.Taylor@Sun.COM nopcode = HERMON_WQE_SEND_NOPCODE_BIND;
6049517SBill.Taylor@Sun.COM status = hermon_wr_bind_check(state, wr);
6059517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS)
6069517SBill.Taylor@Sun.COM goto done;
6079517SBill.Taylor@Sun.COM
6089517SBill.Taylor@Sun.COM bn = (hermon_hw_snd_wqe_bind_t *)((uintptr_t)desc +
6099517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_ctrl_t));
6109517SBill.Taylor@Sun.COM
6119517SBill.Taylor@Sun.COM /*
6129517SBill.Taylor@Sun.COM * Build the Bind Memory Window Segments for the WQE,
6139517SBill.Taylor@Sun.COM * using the information from the RC Bind memory
6149517SBill.Taylor@Sun.COM * window work request.
6159517SBill.Taylor@Sun.COM */
6169517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_BIND(qp, bn, wr->wr.rc.rcwr.bind);
6179517SBill.Taylor@Sun.COM
6189517SBill.Taylor@Sun.COM /*
6199517SBill.Taylor@Sun.COM * Update the "ds" pointer. Even though the "bind"
6209517SBill.Taylor@Sun.COM * operation requires no SGLs, this is necessary to
6219517SBill.Taylor@Sun.COM * facilitate the correct descriptor size calculations
6229517SBill.Taylor@Sun.COM * (below).
6239517SBill.Taylor@Sun.COM */
6249517SBill.Taylor@Sun.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)bn +
6259517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_bind_t));
6269517SBill.Taylor@Sun.COM nds = 0;
627*12965SWilliam.Taylor@Oracle.COM break;
628*12965SWilliam.Taylor@Oracle.COM
629*12965SWilliam.Taylor@Oracle.COM case IBT_WRC_FAST_REG_PMR:
630*12965SWilliam.Taylor@Oracle.COM nopcode = HERMON_WQE_SEND_NOPCODE_FRWR;
631*12965SWilliam.Taylor@Oracle.COM frwr = (hermon_hw_snd_wqe_frwr_t *)((uintptr_t)desc +
632*12965SWilliam.Taylor@Oracle.COM sizeof (hermon_hw_snd_wqe_ctrl_t));
633*12965SWilliam.Taylor@Oracle.COM HERMON_WQE_BUILD_FRWR(qp, frwr, wr->wr.rc.rcwr.reg_pmr);
634*12965SWilliam.Taylor@Oracle.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)frwr +
635*12965SWilliam.Taylor@Oracle.COM sizeof (hermon_hw_snd_wqe_frwr_t));
636*12965SWilliam.Taylor@Oracle.COM nds = 0;
637*12965SWilliam.Taylor@Oracle.COM strong_order = 0x80;
638*12965SWilliam.Taylor@Oracle.COM break;
639*12965SWilliam.Taylor@Oracle.COM
640*12965SWilliam.Taylor@Oracle.COM case IBT_WRC_LOCAL_INVALIDATE:
641*12965SWilliam.Taylor@Oracle.COM nopcode = HERMON_WQE_SEND_NOPCODE_LCL_INV;
642*12965SWilliam.Taylor@Oracle.COM li = (hermon_hw_snd_wqe_local_inv_t *)((uintptr_t)desc +
643*12965SWilliam.Taylor@Oracle.COM sizeof (hermon_hw_snd_wqe_ctrl_t));
644*12965SWilliam.Taylor@Oracle.COM HERMON_WQE_BUILD_LI(qp, li, wr->wr.rc.rcwr.li);
645*12965SWilliam.Taylor@Oracle.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)li +
646*12965SWilliam.Taylor@Oracle.COM sizeof (hermon_hw_snd_wqe_local_inv_t));
647*12965SWilliam.Taylor@Oracle.COM nds = 0;
648*12965SWilliam.Taylor@Oracle.COM strong_order = 0x80;
649*12965SWilliam.Taylor@Oracle.COM break;
6509517SBill.Taylor@Sun.COM }
6519517SBill.Taylor@Sun.COM
6529517SBill.Taylor@Sun.COM /*
6539517SBill.Taylor@Sun.COM * Now fill in the Data Segments (SGL) for the Send WQE based
6549517SBill.Taylor@Sun.COM * on the values setup above (i.e. "sgl", "nds", and the "ds"
6559517SBill.Taylor@Sun.COM * pointer. Start by checking for a valid number of SGL entries
6569517SBill.Taylor@Sun.COM */
6579517SBill.Taylor@Sun.COM if (nds > qp->qp_sq_sgl) {
6589517SBill.Taylor@Sun.COM status = IBT_QP_SGL_LEN_INVALID;
6599517SBill.Taylor@Sun.COM goto done;
6609517SBill.Taylor@Sun.COM }
6619517SBill.Taylor@Sun.COM
6629517SBill.Taylor@Sun.COM for (last_ds = num_ds, i = 0; i < nds; i++) {
6639517SBill.Taylor@Sun.COM if (sgl[i].ds_len != 0)
6649517SBill.Taylor@Sun.COM last_ds++; /* real last ds of wqe to fill */
6659517SBill.Taylor@Sun.COM }
6669517SBill.Taylor@Sun.COM desc_sz = ((uintptr_t)&ds[last_ds] - (uintptr_t)desc) >> 0x4;
6679517SBill.Taylor@Sun.COM for (i = nds; --i >= 0; ) {
6689517SBill.Taylor@Sun.COM if (sgl[i].ds_len == 0) {
6699517SBill.Taylor@Sun.COM continue;
6709517SBill.Taylor@Sun.COM }
67111972SBill.Taylor@Sun.COM rlen += sgl[i].ds_len;
67211972SBill.Taylor@Sun.COM if (print_rdma & 0x2)
67311972SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("rdma", "post: [%d]: laddr %llx "
67411972SBill.Taylor@Sun.COM "llen %x", i, sgl[i].ds_va, sgl[i].ds_len);
6759517SBill.Taylor@Sun.COM
6769517SBill.Taylor@Sun.COM /*
6779517SBill.Taylor@Sun.COM * Fill in the Data Segment(s) for the current WQE, using the
6789517SBill.Taylor@Sun.COM * information contained in the scatter-gather list of the
6799517SBill.Taylor@Sun.COM * work request.
6809517SBill.Taylor@Sun.COM */
6819517SBill.Taylor@Sun.COM last_ds--;
6829517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_DATA_SEG_SEND(&ds[last_ds], &sgl[i]);
6839517SBill.Taylor@Sun.COM }
684*12965SWilliam.Taylor@Oracle.COM /* ensure RDMA READ does not exceed HCA limit */
685*12965SWilliam.Taylor@Oracle.COM if ((wr->wr_opcode == IBT_WRC_RDMAR) && (desc_sz >
686*12965SWilliam.Taylor@Oracle.COM state->hs_ibtfinfo.hca_attr->hca_conn_rdma_read_sgl_sz + 2)) {
687*12965SWilliam.Taylor@Oracle.COM status = IBT_QP_SGL_LEN_INVALID;
688*12965SWilliam.Taylor@Oracle.COM goto done;
689*12965SWilliam.Taylor@Oracle.COM }
6909517SBill.Taylor@Sun.COM
69111972SBill.Taylor@Sun.COM if (print_rdma & 0x1) {
69211972SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("rdma", "post: indx %x rkey %x raddr %llx "
69311972SBill.Taylor@Sun.COM "total len %x", tail, rkey, raddr, rlen);
69411972SBill.Taylor@Sun.COM }
69511972SBill.Taylor@Sun.COM
6969517SBill.Taylor@Sun.COM fence = (wr->wr_flags & IBT_WR_SEND_FENCE) ? 1 : 0;
6979517SBill.Taylor@Sun.COM
6989517SBill.Taylor@Sun.COM signaled_dbd = ((qp->qp_sq_sigtype == HERMON_QP_SQ_ALL_SIGNALED) ||
699*12965SWilliam.Taylor@Oracle.COM (wr->wr_flags & IBT_WR_SEND_SIGNAL)) ? 0xC : 0;
7009517SBill.Taylor@Sun.COM
701*12965SWilliam.Taylor@Oracle.COM solicited = (wr->wr_flags & IBT_WR_SEND_SOLICIT) ? 0x2 : 0;
7029517SBill.Taylor@Sun.COM
7039517SBill.Taylor@Sun.COM HERMON_WQE_SET_CTRL_SEGMENT(desc, desc_sz, fence, immed_data, solicited,
704*12965SWilliam.Taylor@Oracle.COM signaled_dbd, 0, qp, strong_order, 0);
7059517SBill.Taylor@Sun.COM
7069517SBill.Taylor@Sun.COM wq->wq_wrid[tail] = wr->wr_id;
7079517SBill.Taylor@Sun.COM
7089517SBill.Taylor@Sun.COM tail = next_tail;
7099517SBill.Taylor@Sun.COM
7109517SBill.Taylor@Sun.COM /* Update some of the state in the QP */
7119517SBill.Taylor@Sun.COM wq->wq_tail = tail;
7129517SBill.Taylor@Sun.COM
7139517SBill.Taylor@Sun.COM membar_producer();
7149517SBill.Taylor@Sun.COM
7159517SBill.Taylor@Sun.COM /* Now set the ownership bit of the first one in the chain. */
7169517SBill.Taylor@Sun.COM HERMON_SET_SEND_WQE_OWNER(qp, (uint32_t *)desc, nopcode);
7179517SBill.Taylor@Sun.COM
7189517SBill.Taylor@Sun.COM posted_cnt++;
7199517SBill.Taylor@Sun.COM if (--num_wr > 0) {
7209517SBill.Taylor@Sun.COM /* do the invalidate of the headroom */
7219517SBill.Taylor@Sun.COM wqe_start = (uint32_t *)HERMON_QP_SQ_ENTRY(qp,
7229517SBill.Taylor@Sun.COM (tail + hdrmwqes) & qsize_msk);
7239517SBill.Taylor@Sun.COM for (i = 16; i < sectperwqe; i += 16) {
7249517SBill.Taylor@Sun.COM wqe_start[i] = 0xFFFFFFFF;
7259517SBill.Taylor@Sun.COM }
7269517SBill.Taylor@Sun.COM
7279517SBill.Taylor@Sun.COM wr++;
7289517SBill.Taylor@Sun.COM goto post_next;
7299517SBill.Taylor@Sun.COM }
7309517SBill.Taylor@Sun.COM done:
7319517SBill.Taylor@Sun.COM
7329517SBill.Taylor@Sun.COM if (posted_cnt != 0) {
7339517SBill.Taylor@Sun.COM ddi_acc_handle_t uarhdl = hermon_get_uarhdl(state);
7349517SBill.Taylor@Sun.COM
7359517SBill.Taylor@Sun.COM membar_producer();
7369517SBill.Taylor@Sun.COM
7379517SBill.Taylor@Sun.COM /* the FMA retry loop starts for Hermon doorbell register. */
7389517SBill.Taylor@Sun.COM hermon_pio_start(state, uarhdl, pio_error, fm_loop_cnt,
7399517SBill.Taylor@Sun.COM fm_status, fm_test_num);
7409517SBill.Taylor@Sun.COM
7419517SBill.Taylor@Sun.COM /* Ring the doorbell */
7429517SBill.Taylor@Sun.COM HERMON_UAR_DOORBELL(state, uarhdl,
7439517SBill.Taylor@Sun.COM (uint64_t *)(void *)&state->hs_uar->send,
7449517SBill.Taylor@Sun.COM (uint64_t)qp->qp_ring);
7459517SBill.Taylor@Sun.COM
7469517SBill.Taylor@Sun.COM /* the FMA retry loop ends. */
7479517SBill.Taylor@Sun.COM hermon_pio_end(state, uarhdl, pio_error, fm_loop_cnt,
7489517SBill.Taylor@Sun.COM fm_status, fm_test_num);
7499517SBill.Taylor@Sun.COM
7509517SBill.Taylor@Sun.COM /* do the invalidate of the headroom */
7519517SBill.Taylor@Sun.COM wqe_start = (uint32_t *)HERMON_QP_SQ_ENTRY(qp,
7529517SBill.Taylor@Sun.COM (tail + hdrmwqes) & qsize_msk);
7539517SBill.Taylor@Sun.COM for (i = 16; i < sectperwqe; i += 16) {
7549517SBill.Taylor@Sun.COM wqe_start[i] = 0xFFFFFFFF;
7559517SBill.Taylor@Sun.COM }
7569517SBill.Taylor@Sun.COM }
7579517SBill.Taylor@Sun.COM /*
7589517SBill.Taylor@Sun.COM * Update the "num_posted" return value (if necessary).
7599517SBill.Taylor@Sun.COM * Then drop the locks and return success.
7609517SBill.Taylor@Sun.COM */
7619517SBill.Taylor@Sun.COM if (num_posted != NULL) {
7629517SBill.Taylor@Sun.COM *num_posted = posted_cnt;
7639517SBill.Taylor@Sun.COM }
7649517SBill.Taylor@Sun.COM
7659517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_sq_lock);
7669517SBill.Taylor@Sun.COM return (status);
7679517SBill.Taylor@Sun.COM
7689517SBill.Taylor@Sun.COM pio_error:
7699517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_sq_lock);
7709517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
7719517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
7729517SBill.Taylor@Sun.COM }
7739517SBill.Taylor@Sun.COM
7749517SBill.Taylor@Sun.COM /*
7759517SBill.Taylor@Sun.COM * hermon_post_send()
7769517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
7779517SBill.Taylor@Sun.COM */
7789517SBill.Taylor@Sun.COM int
hermon_post_send(hermon_state_t * state,hermon_qphdl_t qp,ibt_send_wr_t * wr,uint_t num_wr,uint_t * num_posted)7799517SBill.Taylor@Sun.COM hermon_post_send(hermon_state_t *state, hermon_qphdl_t qp,
7809517SBill.Taylor@Sun.COM ibt_send_wr_t *wr, uint_t num_wr, uint_t *num_posted)
7819517SBill.Taylor@Sun.COM {
7829517SBill.Taylor@Sun.COM ibt_send_wr_t *curr_wr;
7839517SBill.Taylor@Sun.COM hermon_workq_hdr_t *wq;
7849517SBill.Taylor@Sun.COM hermon_ahhdl_t ah;
7859517SBill.Taylor@Sun.COM uint64_t *desc, *prev;
7869517SBill.Taylor@Sun.COM uint32_t desc_sz;
7879517SBill.Taylor@Sun.COM uint32_t signaled_dbd, solicited;
7889517SBill.Taylor@Sun.COM uint32_t head, tail, next_tail, qsize_msk;
7899517SBill.Taylor@Sun.COM uint32_t hdrmwqes;
7909517SBill.Taylor@Sun.COM uint_t currindx, wrindx, numremain;
7919517SBill.Taylor@Sun.COM uint_t chainlen;
7929517SBill.Taylor@Sun.COM uint_t posted_cnt, maxstat;
7939517SBill.Taylor@Sun.COM uint_t total_posted;
7949517SBill.Taylor@Sun.COM int status;
7959517SBill.Taylor@Sun.COM uint32_t nopcode, fence, immed_data = 0;
7969517SBill.Taylor@Sun.COM uint32_t prev_nopcode;
797*12965SWilliam.Taylor@Oracle.COM uint_t qp_state;
7989517SBill.Taylor@Sun.COM
7999517SBill.Taylor@Sun.COM /* initialize the FMA retry loop */
8009517SBill.Taylor@Sun.COM hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
8019517SBill.Taylor@Sun.COM
8029517SBill.Taylor@Sun.COM /*
8039517SBill.Taylor@Sun.COM * Check for user-mappable QP memory. Note: We do not allow kernel
8049517SBill.Taylor@Sun.COM * clients to post to QP memory that is accessible directly by the
8059517SBill.Taylor@Sun.COM * user. If the QP memory is user accessible, then return an error.
8069517SBill.Taylor@Sun.COM */
807*12965SWilliam.Taylor@Oracle.COM if (qp->qp_alloc_flags & IBT_QP_USER_MAP) {
8089517SBill.Taylor@Sun.COM return (IBT_QP_HDL_INVALID);
8099517SBill.Taylor@Sun.COM }
8109517SBill.Taylor@Sun.COM
811*12965SWilliam.Taylor@Oracle.COM mutex_enter(&qp->qp_sq_lock);
8129517SBill.Taylor@Sun.COM
8139517SBill.Taylor@Sun.COM /*
8149517SBill.Taylor@Sun.COM * Check QP state. Can not post Send requests from the "Reset",
8159517SBill.Taylor@Sun.COM * "Init", or "RTR" states
8169517SBill.Taylor@Sun.COM */
817*12965SWilliam.Taylor@Oracle.COM qp_state = qp->qp_state_for_post_send;
818*12965SWilliam.Taylor@Oracle.COM if ((qp_state == HERMON_QP_RESET) ||
819*12965SWilliam.Taylor@Oracle.COM (qp_state == HERMON_QP_INIT) ||
820*12965SWilliam.Taylor@Oracle.COM (qp_state == HERMON_QP_RTR)) {
821*12965SWilliam.Taylor@Oracle.COM mutex_exit(&qp->qp_sq_lock);
8229517SBill.Taylor@Sun.COM return (IBT_QP_STATE_INVALID);
8239517SBill.Taylor@Sun.COM }
8249517SBill.Taylor@Sun.COM
8259517SBill.Taylor@Sun.COM if (qp->qp_is_special)
8269517SBill.Taylor@Sun.COM goto post_many;
8279517SBill.Taylor@Sun.COM
8289517SBill.Taylor@Sun.COM /* Use these optimized functions most of the time */
829*12965SWilliam.Taylor@Oracle.COM if (qp->qp_type == IBT_UD_RQP) {
8309517SBill.Taylor@Sun.COM return (hermon_post_send_ud(state, qp, wr, num_wr, num_posted));
83111972SBill.Taylor@Sun.COM }
8329517SBill.Taylor@Sun.COM
83311972SBill.Taylor@Sun.COM if (qp->qp_serv_type == HERMON_QP_RC) {
8349517SBill.Taylor@Sun.COM return (hermon_post_send_rc(state, qp, wr, num_wr, num_posted));
83511972SBill.Taylor@Sun.COM }
8369517SBill.Taylor@Sun.COM
8379517SBill.Taylor@Sun.COM if (qp->qp_serv_type == HERMON_QP_UC)
8389517SBill.Taylor@Sun.COM goto post_many;
8399517SBill.Taylor@Sun.COM
8409517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_sq_lock);
8419517SBill.Taylor@Sun.COM return (IBT_QP_SRV_TYPE_INVALID);
8429517SBill.Taylor@Sun.COM
8439517SBill.Taylor@Sun.COM post_many:
8449517SBill.Taylor@Sun.COM /* general loop for non-optimized posting */
8459517SBill.Taylor@Sun.COM
8469517SBill.Taylor@Sun.COM /* Save away some initial QP state */
8479517SBill.Taylor@Sun.COM wq = qp->qp_sq_wqhdr;
8489517SBill.Taylor@Sun.COM qsize_msk = wq->wq_mask;
8499517SBill.Taylor@Sun.COM tail = wq->wq_tail;
8509517SBill.Taylor@Sun.COM head = wq->wq_head;
8519517SBill.Taylor@Sun.COM hdrmwqes = qp->qp_sq_hdrmwqes; /* in WQEs */
8529517SBill.Taylor@Sun.COM
8539517SBill.Taylor@Sun.COM /* Initialize posted_cnt */
8549517SBill.Taylor@Sun.COM posted_cnt = 0;
8559517SBill.Taylor@Sun.COM total_posted = 0;
8569517SBill.Taylor@Sun.COM
8579517SBill.Taylor@Sun.COM /*
8589517SBill.Taylor@Sun.COM * For each ibt_send_wr_t in the wr[] list passed in, parse the
8599517SBill.Taylor@Sun.COM * request and build a Send WQE. NOTE: Because we are potentially
8609517SBill.Taylor@Sun.COM * building a chain of WQEs to post, we want to build them all first,
8619517SBill.Taylor@Sun.COM * and set the valid (HW Ownership) bit on all but the first.
8629517SBill.Taylor@Sun.COM * However, we do not want to validate the first one until the
8639517SBill.Taylor@Sun.COM * entire chain of WQEs has been built. Then in the final
8649517SBill.Taylor@Sun.COM * we set the valid bit in the first, flush if needed, and as a last
8659517SBill.Taylor@Sun.COM * step ring the appropriate doorbell. NOTE: the doorbell ring may
8669517SBill.Taylor@Sun.COM * NOT be needed if the HCA is already processing, but the doorbell
8679517SBill.Taylor@Sun.COM * ring will be done regardless. NOTE ALSO: It is possible for
8689517SBill.Taylor@Sun.COM * more Work Requests to be posted than the HW will support at one
8699517SBill.Taylor@Sun.COM * shot. If this happens, we need to be able to post and ring
8709517SBill.Taylor@Sun.COM * several chains here until the the entire request is complete.
8719517SBill.Taylor@Sun.COM * NOTE ALSO: the term "chain" is used to differentiate it from
8729517SBill.Taylor@Sun.COM * Work Request List passed in; and because that's the terminology
8739517SBill.Taylor@Sun.COM * from the previous generations of HCA - but the WQEs are not, in fact
8749517SBill.Taylor@Sun.COM * chained together for Hermon
8759517SBill.Taylor@Sun.COM */
8769517SBill.Taylor@Sun.COM
8779517SBill.Taylor@Sun.COM wrindx = 0;
8789517SBill.Taylor@Sun.COM numremain = num_wr;
8799517SBill.Taylor@Sun.COM status = DDI_SUCCESS;
8809517SBill.Taylor@Sun.COM while ((wrindx < num_wr) && (status == DDI_SUCCESS)) {
8819517SBill.Taylor@Sun.COM /*
8829517SBill.Taylor@Sun.COM * For the first WQE on a new chain we need "prev" to point
8839517SBill.Taylor@Sun.COM * to the current descriptor.
8849517SBill.Taylor@Sun.COM */
8859517SBill.Taylor@Sun.COM prev = HERMON_QP_SQ_ENTRY(qp, tail);
8869517SBill.Taylor@Sun.COM
8879517SBill.Taylor@Sun.COM /*
8889517SBill.Taylor@Sun.COM * Break the request up into lists that are less than or
8899517SBill.Taylor@Sun.COM * equal to the maximum number of WQEs that can be posted
8909517SBill.Taylor@Sun.COM * per doorbell ring - 256 currently
8919517SBill.Taylor@Sun.COM */
8929517SBill.Taylor@Sun.COM chainlen = (numremain > HERMON_QP_MAXDESC_PER_DB) ?
8939517SBill.Taylor@Sun.COM HERMON_QP_MAXDESC_PER_DB : numremain;
8949517SBill.Taylor@Sun.COM numremain -= chainlen;
8959517SBill.Taylor@Sun.COM
8969517SBill.Taylor@Sun.COM for (currindx = 0; currindx < chainlen; currindx++, wrindx++) {
8979517SBill.Taylor@Sun.COM /*
8989517SBill.Taylor@Sun.COM * Check for "queue full" condition. If the queue
8999517SBill.Taylor@Sun.COM * is already full, then no more WQEs can be posted.
9009517SBill.Taylor@Sun.COM * So break out, ring a doorbell (if necessary) and
9019517SBill.Taylor@Sun.COM * return an error
9029517SBill.Taylor@Sun.COM */
9039517SBill.Taylor@Sun.COM if (wq->wq_full != 0) {
9049517SBill.Taylor@Sun.COM status = IBT_QP_FULL;
9059517SBill.Taylor@Sun.COM break;
9069517SBill.Taylor@Sun.COM }
9079517SBill.Taylor@Sun.COM
9089517SBill.Taylor@Sun.COM /*
9099517SBill.Taylor@Sun.COM * Increment the "tail index". Check for "queue
9109517SBill.Taylor@Sun.COM * full" condition incl. headroom. If we detect that
9119517SBill.Taylor@Sun.COM * the current work request is going to fill the work
9129517SBill.Taylor@Sun.COM * queue, then we mark this condition and continue.
9139517SBill.Taylor@Sun.COM * Don't need >=, because going one-by-one we have to
9149517SBill.Taylor@Sun.COM * hit it exactly sooner or later
9159517SBill.Taylor@Sun.COM */
9169517SBill.Taylor@Sun.COM
9179517SBill.Taylor@Sun.COM next_tail = (tail + 1) & qsize_msk;
9189517SBill.Taylor@Sun.COM if (((tail + hdrmwqes) & qsize_msk) == head) {
9199517SBill.Taylor@Sun.COM wq->wq_full = 1;
9209517SBill.Taylor@Sun.COM }
9219517SBill.Taylor@Sun.COM
9229517SBill.Taylor@Sun.COM /*
9239517SBill.Taylor@Sun.COM * Get the address of the location where the next
9249517SBill.Taylor@Sun.COM * Send WQE should be built
9259517SBill.Taylor@Sun.COM */
9269517SBill.Taylor@Sun.COM desc = HERMON_QP_SQ_ENTRY(qp, tail);
9279517SBill.Taylor@Sun.COM /*
9289517SBill.Taylor@Sun.COM * Call hermon_wqe_send_build() to build the WQE
9299517SBill.Taylor@Sun.COM * at the given address. This routine uses the
9309517SBill.Taylor@Sun.COM * information in the ibt_send_wr_t list (wr[]) and
9319517SBill.Taylor@Sun.COM * returns the size of the WQE when it returns.
9329517SBill.Taylor@Sun.COM */
9339517SBill.Taylor@Sun.COM status = hermon_wqe_send_build(state, qp,
9349517SBill.Taylor@Sun.COM &wr[wrindx], desc, &desc_sz);
9359517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
9369517SBill.Taylor@Sun.COM break;
9379517SBill.Taylor@Sun.COM }
9389517SBill.Taylor@Sun.COM
9399517SBill.Taylor@Sun.COM /*
9409517SBill.Taylor@Sun.COM * Now, build the Ctrl Segment based on
9419517SBill.Taylor@Sun.COM * what was just done
9429517SBill.Taylor@Sun.COM */
9439517SBill.Taylor@Sun.COM curr_wr = &wr[wrindx];
9449517SBill.Taylor@Sun.COM
9459517SBill.Taylor@Sun.COM switch (curr_wr->wr_opcode) {
9469517SBill.Taylor@Sun.COM case IBT_WRC_RDMAW:
9479517SBill.Taylor@Sun.COM if (curr_wr->wr_flags & IBT_WR_SEND_IMMED) {
9489517SBill.Taylor@Sun.COM nopcode =
9499517SBill.Taylor@Sun.COM HERMON_WQE_SEND_NOPCODE_RDMAWI;
9509517SBill.Taylor@Sun.COM immed_data =
9519517SBill.Taylor@Sun.COM hermon_wr_get_immediate(curr_wr);
9529517SBill.Taylor@Sun.COM } else {
9539517SBill.Taylor@Sun.COM nopcode = HERMON_WQE_SEND_NOPCODE_RDMAW;
9549517SBill.Taylor@Sun.COM }
9559517SBill.Taylor@Sun.COM break;
9569517SBill.Taylor@Sun.COM
9579517SBill.Taylor@Sun.COM case IBT_WRC_SEND:
9589517SBill.Taylor@Sun.COM if (curr_wr->wr_flags & IBT_WR_SEND_IMMED) {
9599517SBill.Taylor@Sun.COM nopcode = HERMON_WQE_SEND_NOPCODE_SENDI;
9609517SBill.Taylor@Sun.COM immed_data =
9619517SBill.Taylor@Sun.COM hermon_wr_get_immediate(curr_wr);
9629517SBill.Taylor@Sun.COM } else {
9639517SBill.Taylor@Sun.COM nopcode = HERMON_WQE_SEND_NOPCODE_SEND;
9649517SBill.Taylor@Sun.COM }
9659517SBill.Taylor@Sun.COM break;
9669517SBill.Taylor@Sun.COM
9679517SBill.Taylor@Sun.COM case IBT_WRC_SEND_LSO:
9689517SBill.Taylor@Sun.COM nopcode = HERMON_WQE_SEND_NOPCODE_LSO;
9699517SBill.Taylor@Sun.COM break;
9709517SBill.Taylor@Sun.COM
9719517SBill.Taylor@Sun.COM case IBT_WRC_RDMAR:
9729517SBill.Taylor@Sun.COM nopcode = HERMON_WQE_SEND_NOPCODE_RDMAR;
9739517SBill.Taylor@Sun.COM break;
9749517SBill.Taylor@Sun.COM
9759517SBill.Taylor@Sun.COM case IBT_WRC_CSWAP:
9769517SBill.Taylor@Sun.COM nopcode = HERMON_WQE_SEND_NOPCODE_ATMCS;
9779517SBill.Taylor@Sun.COM break;
9789517SBill.Taylor@Sun.COM
9799517SBill.Taylor@Sun.COM case IBT_WRC_FADD:
9809517SBill.Taylor@Sun.COM nopcode = HERMON_WQE_SEND_NOPCODE_ATMFA;
9819517SBill.Taylor@Sun.COM break;
9829517SBill.Taylor@Sun.COM
9839517SBill.Taylor@Sun.COM case IBT_WRC_BIND:
9849517SBill.Taylor@Sun.COM nopcode = HERMON_WQE_SEND_NOPCODE_BIND;
9859517SBill.Taylor@Sun.COM break;
9869517SBill.Taylor@Sun.COM }
9879517SBill.Taylor@Sun.COM
9889517SBill.Taylor@Sun.COM fence = (curr_wr->wr_flags & IBT_WR_SEND_FENCE) ? 1 : 0;
9899517SBill.Taylor@Sun.COM
9909517SBill.Taylor@Sun.COM /*
9919517SBill.Taylor@Sun.COM * now, build up the control segment, leaving the
9929517SBill.Taylor@Sun.COM * owner bit as it is
9939517SBill.Taylor@Sun.COM */
9949517SBill.Taylor@Sun.COM
9959517SBill.Taylor@Sun.COM if ((qp->qp_sq_sigtype == HERMON_QP_SQ_ALL_SIGNALED) ||
9969517SBill.Taylor@Sun.COM (curr_wr->wr_flags & IBT_WR_SEND_SIGNAL)) {
997*12965SWilliam.Taylor@Oracle.COM signaled_dbd = 0xC;
9989517SBill.Taylor@Sun.COM } else {
9999517SBill.Taylor@Sun.COM signaled_dbd = 0;
10009517SBill.Taylor@Sun.COM }
10019517SBill.Taylor@Sun.COM if (curr_wr->wr_flags & IBT_WR_SEND_SOLICIT)
1002*12965SWilliam.Taylor@Oracle.COM solicited = 0x2;
10039517SBill.Taylor@Sun.COM else
10049517SBill.Taylor@Sun.COM solicited = 0;
10059517SBill.Taylor@Sun.COM
10069517SBill.Taylor@Sun.COM if (qp->qp_is_special) {
100711643SBill.Taylor@Sun.COM /* Ensure correctness, set the ReRead bit */
100811643SBill.Taylor@Sun.COM nopcode |= (1 << 6);
10099517SBill.Taylor@Sun.COM ah = (hermon_ahhdl_t)
10109517SBill.Taylor@Sun.COM curr_wr->wr.ud.udwr_dest->ud_ah;
10119517SBill.Taylor@Sun.COM mutex_enter(&ah->ah_lock);
10129517SBill.Taylor@Sun.COM maxstat = ah->ah_udav->max_stat_rate;
10139517SBill.Taylor@Sun.COM HERMON_WQE_SET_MLX_CTRL_SEGMENT(desc, desc_sz,
10149517SBill.Taylor@Sun.COM signaled_dbd, maxstat, ah->ah_udav->rlid,
10159517SBill.Taylor@Sun.COM qp, ah->ah_udav->sl);
10169517SBill.Taylor@Sun.COM mutex_exit(&ah->ah_lock);
10179517SBill.Taylor@Sun.COM } else {
10189517SBill.Taylor@Sun.COM HERMON_WQE_SET_CTRL_SEGMENT(desc, desc_sz,
10199517SBill.Taylor@Sun.COM fence, immed_data, solicited,
1020*12965SWilliam.Taylor@Oracle.COM signaled_dbd, 0, qp, 0, 0);
10219517SBill.Taylor@Sun.COM }
10229517SBill.Taylor@Sun.COM wq->wq_wrid[tail] = curr_wr->wr_id;
10239517SBill.Taylor@Sun.COM
10249517SBill.Taylor@Sun.COM /*
10259517SBill.Taylor@Sun.COM * If this is not the first descriptor on the current
10269517SBill.Taylor@Sun.COM * chain, then set the ownership bit.
10279517SBill.Taylor@Sun.COM */
10289517SBill.Taylor@Sun.COM if (currindx != 0) { /* not the first */
10299517SBill.Taylor@Sun.COM membar_producer();
10309517SBill.Taylor@Sun.COM HERMON_SET_SEND_WQE_OWNER(qp,
10319517SBill.Taylor@Sun.COM (uint32_t *)desc, nopcode);
10329517SBill.Taylor@Sun.COM } else
10339517SBill.Taylor@Sun.COM prev_nopcode = nopcode;
10349517SBill.Taylor@Sun.COM
10359517SBill.Taylor@Sun.COM /*
10369517SBill.Taylor@Sun.COM * Update the current "tail index" and increment
10379517SBill.Taylor@Sun.COM * "posted_cnt"
10389517SBill.Taylor@Sun.COM */
10399517SBill.Taylor@Sun.COM tail = next_tail;
10409517SBill.Taylor@Sun.COM posted_cnt++;
10419517SBill.Taylor@Sun.COM }
10429517SBill.Taylor@Sun.COM
10439517SBill.Taylor@Sun.COM /*
10449517SBill.Taylor@Sun.COM * If we reach here and there are one or more WQEs which have
10459517SBill.Taylor@Sun.COM * been successfully built as a chain, we have to finish up
10469517SBill.Taylor@Sun.COM * and prepare them for writing to the HW
10479517SBill.Taylor@Sun.COM * The steps are:
10489517SBill.Taylor@Sun.COM * 1. do the headroom fixup
10499517SBill.Taylor@Sun.COM * 2. add in the size of the headroom for the sync
10509517SBill.Taylor@Sun.COM * 3. write the owner bit for the first WQE
10519517SBill.Taylor@Sun.COM * 4. sync them
10529517SBill.Taylor@Sun.COM * 5. fix up the structures
10539517SBill.Taylor@Sun.COM * 6. hit the doorbell in UAR
10549517SBill.Taylor@Sun.COM */
10559517SBill.Taylor@Sun.COM if (posted_cnt != 0) {
10569517SBill.Taylor@Sun.COM ddi_acc_handle_t uarhdl = hermon_get_uarhdl(state);
10579517SBill.Taylor@Sun.COM
10589517SBill.Taylor@Sun.COM /* do the invalidate of the headroom */
10599517SBill.Taylor@Sun.COM
10609517SBill.Taylor@Sun.COM hermon_wqe_headroom(tail, qp);
10619517SBill.Taylor@Sun.COM
10629517SBill.Taylor@Sun.COM /* Update some of the state in the QP */
10639517SBill.Taylor@Sun.COM wq->wq_tail = tail;
10649517SBill.Taylor@Sun.COM total_posted += posted_cnt;
10659517SBill.Taylor@Sun.COM posted_cnt = 0;
10669517SBill.Taylor@Sun.COM
10679517SBill.Taylor@Sun.COM membar_producer();
10689517SBill.Taylor@Sun.COM
10699517SBill.Taylor@Sun.COM /*
10709517SBill.Taylor@Sun.COM * Now set the ownership bit of the first
10719517SBill.Taylor@Sun.COM * one in the chain
10729517SBill.Taylor@Sun.COM */
10739517SBill.Taylor@Sun.COM HERMON_SET_SEND_WQE_OWNER(qp, (uint32_t *)prev,
10749517SBill.Taylor@Sun.COM prev_nopcode);
10759517SBill.Taylor@Sun.COM
10769517SBill.Taylor@Sun.COM /* the FMA retry loop starts for Hermon doorbell. */
10779517SBill.Taylor@Sun.COM hermon_pio_start(state, uarhdl, pio_error, fm_loop_cnt,
10789517SBill.Taylor@Sun.COM fm_status, fm_test);
10799517SBill.Taylor@Sun.COM
10809517SBill.Taylor@Sun.COM HERMON_UAR_DOORBELL(state, uarhdl,
10819517SBill.Taylor@Sun.COM (uint64_t *)(void *)&state->hs_uar->send,
10829517SBill.Taylor@Sun.COM (uint64_t)qp->qp_ring);
10839517SBill.Taylor@Sun.COM
10849517SBill.Taylor@Sun.COM /* the FMA retry loop ends. */
10859517SBill.Taylor@Sun.COM hermon_pio_end(state, uarhdl, pio_error, fm_loop_cnt,
10869517SBill.Taylor@Sun.COM fm_status, fm_test);
10879517SBill.Taylor@Sun.COM }
10889517SBill.Taylor@Sun.COM }
10899517SBill.Taylor@Sun.COM
10909517SBill.Taylor@Sun.COM /*
10919517SBill.Taylor@Sun.COM * Update the "num_posted" return value (if necessary).
10929517SBill.Taylor@Sun.COM * Then drop the locks and return success.
10939517SBill.Taylor@Sun.COM */
10949517SBill.Taylor@Sun.COM if (num_posted != NULL) {
10959517SBill.Taylor@Sun.COM *num_posted = total_posted;
10969517SBill.Taylor@Sun.COM }
10979517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_sq_lock);
10989517SBill.Taylor@Sun.COM return (status);
10999517SBill.Taylor@Sun.COM
11009517SBill.Taylor@Sun.COM pio_error:
11019517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_sq_lock);
11029517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
11039517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
11049517SBill.Taylor@Sun.COM }
11059517SBill.Taylor@Sun.COM
11069517SBill.Taylor@Sun.COM
11079517SBill.Taylor@Sun.COM /*
11089517SBill.Taylor@Sun.COM * hermon_post_recv()
11099517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
11109517SBill.Taylor@Sun.COM */
11119517SBill.Taylor@Sun.COM int
hermon_post_recv(hermon_state_t * state,hermon_qphdl_t qp,ibt_recv_wr_t * wr,uint_t num_wr,uint_t * num_posted)11129517SBill.Taylor@Sun.COM hermon_post_recv(hermon_state_t *state, hermon_qphdl_t qp,
11139517SBill.Taylor@Sun.COM ibt_recv_wr_t *wr, uint_t num_wr, uint_t *num_posted)
11149517SBill.Taylor@Sun.COM {
11159517SBill.Taylor@Sun.COM uint64_t *desc;
11169517SBill.Taylor@Sun.COM hermon_workq_hdr_t *wq;
11179517SBill.Taylor@Sun.COM uint32_t head, tail, next_tail, qsize_msk;
11189517SBill.Taylor@Sun.COM uint_t wrindx;
11199517SBill.Taylor@Sun.COM uint_t posted_cnt;
11209517SBill.Taylor@Sun.COM int status;
11219517SBill.Taylor@Sun.COM
11229517SBill.Taylor@Sun.COM /*
11239517SBill.Taylor@Sun.COM * Check for user-mappable QP memory. Note: We do not allow kernel
11249517SBill.Taylor@Sun.COM * clients to post to QP memory that is accessible directly by the
11259517SBill.Taylor@Sun.COM * user. If the QP memory is user accessible, then return an error.
11269517SBill.Taylor@Sun.COM */
1127*12965SWilliam.Taylor@Oracle.COM if (qp->qp_alloc_flags & IBT_QP_USER_MAP) {
11289517SBill.Taylor@Sun.COM return (IBT_QP_HDL_INVALID);
11299517SBill.Taylor@Sun.COM }
11309517SBill.Taylor@Sun.COM
11319517SBill.Taylor@Sun.COM /* Initialize posted_cnt */
11329517SBill.Taylor@Sun.COM posted_cnt = 0;
11339517SBill.Taylor@Sun.COM
11349517SBill.Taylor@Sun.COM mutex_enter(&qp->qp_lock);
11359517SBill.Taylor@Sun.COM
11369517SBill.Taylor@Sun.COM /*
11379517SBill.Taylor@Sun.COM * Check if QP is associated with an SRQ
11389517SBill.Taylor@Sun.COM */
1139*12965SWilliam.Taylor@Oracle.COM if (qp->qp_alloc_flags & IBT_QP_USES_SRQ) {
11409517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_lock);
11419517SBill.Taylor@Sun.COM return (IBT_SRQ_IN_USE);
11429517SBill.Taylor@Sun.COM }
11439517SBill.Taylor@Sun.COM
11449517SBill.Taylor@Sun.COM /*
11459517SBill.Taylor@Sun.COM * Check QP state. Can not post Recv requests from the "Reset" state
11469517SBill.Taylor@Sun.COM */
11479517SBill.Taylor@Sun.COM if (qp->qp_state == HERMON_QP_RESET) {
11489517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_lock);
11499517SBill.Taylor@Sun.COM return (IBT_QP_STATE_INVALID);
11509517SBill.Taylor@Sun.COM }
11519517SBill.Taylor@Sun.COM
11529517SBill.Taylor@Sun.COM /* Check that work request transport type is valid */
1153*12965SWilliam.Taylor@Oracle.COM if ((qp->qp_type != IBT_UD_RQP) &&
11549517SBill.Taylor@Sun.COM (qp->qp_serv_type != HERMON_QP_RC) &&
11559517SBill.Taylor@Sun.COM (qp->qp_serv_type != HERMON_QP_UC)) {
11569517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_lock);
11579517SBill.Taylor@Sun.COM return (IBT_QP_SRV_TYPE_INVALID);
11589517SBill.Taylor@Sun.COM }
11599517SBill.Taylor@Sun.COM
11609517SBill.Taylor@Sun.COM /*
11619517SBill.Taylor@Sun.COM * Grab the lock for the WRID list, i.e., membar_consumer().
11629517SBill.Taylor@Sun.COM * This is not needed because the mutex_enter() above has
11639517SBill.Taylor@Sun.COM * the same effect.
11649517SBill.Taylor@Sun.COM */
11659517SBill.Taylor@Sun.COM
11669517SBill.Taylor@Sun.COM /* Save away some initial QP state */
11679517SBill.Taylor@Sun.COM wq = qp->qp_rq_wqhdr;
11689517SBill.Taylor@Sun.COM qsize_msk = wq->wq_mask;
11699517SBill.Taylor@Sun.COM tail = wq->wq_tail;
11709517SBill.Taylor@Sun.COM head = wq->wq_head;
11719517SBill.Taylor@Sun.COM
11729517SBill.Taylor@Sun.COM wrindx = 0;
11739517SBill.Taylor@Sun.COM status = DDI_SUCCESS;
11749517SBill.Taylor@Sun.COM
11759517SBill.Taylor@Sun.COM for (wrindx = 0; wrindx < num_wr; wrindx++) {
11769517SBill.Taylor@Sun.COM if (wq->wq_full != 0) {
11779517SBill.Taylor@Sun.COM status = IBT_QP_FULL;
11789517SBill.Taylor@Sun.COM break;
11799517SBill.Taylor@Sun.COM }
11809517SBill.Taylor@Sun.COM next_tail = (tail + 1) & qsize_msk;
11819517SBill.Taylor@Sun.COM if (next_tail == head) {
11829517SBill.Taylor@Sun.COM wq->wq_full = 1;
11839517SBill.Taylor@Sun.COM }
11849517SBill.Taylor@Sun.COM desc = HERMON_QP_RQ_ENTRY(qp, tail);
11859517SBill.Taylor@Sun.COM status = hermon_wqe_recv_build(state, qp, &wr[wrindx], desc);
11869517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
11879517SBill.Taylor@Sun.COM break;
11889517SBill.Taylor@Sun.COM }
11899517SBill.Taylor@Sun.COM
11909517SBill.Taylor@Sun.COM wq->wq_wrid[tail] = wr[wrindx].wr_id;
11919517SBill.Taylor@Sun.COM qp->qp_rq_wqecntr++;
11929517SBill.Taylor@Sun.COM
11939517SBill.Taylor@Sun.COM tail = next_tail;
11949517SBill.Taylor@Sun.COM posted_cnt++;
11959517SBill.Taylor@Sun.COM }
11969517SBill.Taylor@Sun.COM
11979517SBill.Taylor@Sun.COM if (posted_cnt != 0) {
11989517SBill.Taylor@Sun.COM
11999517SBill.Taylor@Sun.COM wq->wq_tail = tail;
12009517SBill.Taylor@Sun.COM
12019517SBill.Taylor@Sun.COM membar_producer(); /* ensure wrids are visible */
12029517SBill.Taylor@Sun.COM
12039517SBill.Taylor@Sun.COM /* Update the doorbell record w/ wqecntr */
12049517SBill.Taylor@Sun.COM HERMON_UAR_DB_RECORD_WRITE(qp->qp_rq_vdbr,
12059517SBill.Taylor@Sun.COM qp->qp_rq_wqecntr & 0xFFFF);
12069517SBill.Taylor@Sun.COM }
12079517SBill.Taylor@Sun.COM
12089517SBill.Taylor@Sun.COM if (num_posted != NULL) {
12099517SBill.Taylor@Sun.COM *num_posted = posted_cnt;
12109517SBill.Taylor@Sun.COM }
12119517SBill.Taylor@Sun.COM
12129517SBill.Taylor@Sun.COM
1213*12965SWilliam.Taylor@Oracle.COM mutex_exit(&qp->qp_lock);
12149517SBill.Taylor@Sun.COM return (status);
12159517SBill.Taylor@Sun.COM }
12169517SBill.Taylor@Sun.COM
12179517SBill.Taylor@Sun.COM /*
12189517SBill.Taylor@Sun.COM * hermon_post_srq()
12199517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
12209517SBill.Taylor@Sun.COM */
12219517SBill.Taylor@Sun.COM int
hermon_post_srq(hermon_state_t * state,hermon_srqhdl_t srq,ibt_recv_wr_t * wr,uint_t num_wr,uint_t * num_posted)12229517SBill.Taylor@Sun.COM hermon_post_srq(hermon_state_t *state, hermon_srqhdl_t srq,
12239517SBill.Taylor@Sun.COM ibt_recv_wr_t *wr, uint_t num_wr, uint_t *num_posted)
12249517SBill.Taylor@Sun.COM {
12259517SBill.Taylor@Sun.COM uint64_t *desc;
12269517SBill.Taylor@Sun.COM hermon_workq_hdr_t *wq;
12279517SBill.Taylor@Sun.COM uint_t indx, wrindx;
12289517SBill.Taylor@Sun.COM uint_t posted_cnt;
12299517SBill.Taylor@Sun.COM int status;
12309517SBill.Taylor@Sun.COM
12319517SBill.Taylor@Sun.COM mutex_enter(&srq->srq_lock);
12329517SBill.Taylor@Sun.COM
12339517SBill.Taylor@Sun.COM /*
12349517SBill.Taylor@Sun.COM * Check for user-mappable QP memory. Note: We do not allow kernel
12359517SBill.Taylor@Sun.COM * clients to post to QP memory that is accessible directly by the
12369517SBill.Taylor@Sun.COM * user. If the QP memory is user accessible, then return an error.
12379517SBill.Taylor@Sun.COM */
12389517SBill.Taylor@Sun.COM if (srq->srq_is_umap) {
12399517SBill.Taylor@Sun.COM mutex_exit(&srq->srq_lock);
12409517SBill.Taylor@Sun.COM return (IBT_SRQ_HDL_INVALID);
12419517SBill.Taylor@Sun.COM }
12429517SBill.Taylor@Sun.COM
12439517SBill.Taylor@Sun.COM /*
12449517SBill.Taylor@Sun.COM * Check SRQ state. Can not post Recv requests when SRQ is in error
12459517SBill.Taylor@Sun.COM */
12469517SBill.Taylor@Sun.COM if (srq->srq_state == HERMON_SRQ_STATE_ERROR) {
12479517SBill.Taylor@Sun.COM mutex_exit(&srq->srq_lock);
12489517SBill.Taylor@Sun.COM return (IBT_QP_STATE_INVALID);
12499517SBill.Taylor@Sun.COM }
12509517SBill.Taylor@Sun.COM
12519517SBill.Taylor@Sun.COM status = DDI_SUCCESS;
12529517SBill.Taylor@Sun.COM posted_cnt = 0;
12539517SBill.Taylor@Sun.COM wq = srq->srq_wq_wqhdr;
12549517SBill.Taylor@Sun.COM indx = wq->wq_head;
12559517SBill.Taylor@Sun.COM
12569517SBill.Taylor@Sun.COM for (wrindx = 0; wrindx < num_wr; wrindx++) {
12579517SBill.Taylor@Sun.COM
12589517SBill.Taylor@Sun.COM if (indx == wq->wq_tail) {
12599517SBill.Taylor@Sun.COM status = IBT_QP_FULL;
12609517SBill.Taylor@Sun.COM break;
12619517SBill.Taylor@Sun.COM }
12629517SBill.Taylor@Sun.COM desc = HERMON_SRQ_WQE_ADDR(srq, indx);
12639517SBill.Taylor@Sun.COM
12649517SBill.Taylor@Sun.COM wq->wq_wrid[indx] = wr[wrindx].wr_id;
12659517SBill.Taylor@Sun.COM
12669517SBill.Taylor@Sun.COM status = hermon_wqe_srq_build(state, srq, &wr[wrindx], desc);
12679517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
12689517SBill.Taylor@Sun.COM break;
12699517SBill.Taylor@Sun.COM }
12709517SBill.Taylor@Sun.COM
12719517SBill.Taylor@Sun.COM posted_cnt++;
12729517SBill.Taylor@Sun.COM indx = htons(((uint16_t *)desc)[1]);
12739517SBill.Taylor@Sun.COM wq->wq_head = indx;
12749517SBill.Taylor@Sun.COM }
12759517SBill.Taylor@Sun.COM
12769517SBill.Taylor@Sun.COM if (posted_cnt != 0) {
12779517SBill.Taylor@Sun.COM
12789517SBill.Taylor@Sun.COM srq->srq_wq_wqecntr += posted_cnt;
12799517SBill.Taylor@Sun.COM
12809517SBill.Taylor@Sun.COM membar_producer(); /* ensure wrids are visible */
12819517SBill.Taylor@Sun.COM
12829517SBill.Taylor@Sun.COM /* Ring the doorbell w/ wqecntr */
12839517SBill.Taylor@Sun.COM HERMON_UAR_DB_RECORD_WRITE(srq->srq_wq_vdbr,
12849517SBill.Taylor@Sun.COM srq->srq_wq_wqecntr & 0xFFFF);
12859517SBill.Taylor@Sun.COM }
12869517SBill.Taylor@Sun.COM
12879517SBill.Taylor@Sun.COM if (num_posted != NULL) {
12889517SBill.Taylor@Sun.COM *num_posted = posted_cnt;
12899517SBill.Taylor@Sun.COM }
12909517SBill.Taylor@Sun.COM
12919517SBill.Taylor@Sun.COM mutex_exit(&srq->srq_lock);
12929517SBill.Taylor@Sun.COM return (status);
12939517SBill.Taylor@Sun.COM }
12949517SBill.Taylor@Sun.COM
12959517SBill.Taylor@Sun.COM
12969517SBill.Taylor@Sun.COM /*
12979517SBill.Taylor@Sun.COM * hermon_wqe_send_build()
12989517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
12999517SBill.Taylor@Sun.COM */
13009517SBill.Taylor@Sun.COM static int
hermon_wqe_send_build(hermon_state_t * state,hermon_qphdl_t qp,ibt_send_wr_t * wr,uint64_t * desc,uint_t * size)13019517SBill.Taylor@Sun.COM hermon_wqe_send_build(hermon_state_t *state, hermon_qphdl_t qp,
13029517SBill.Taylor@Sun.COM ibt_send_wr_t *wr, uint64_t *desc, uint_t *size)
13039517SBill.Taylor@Sun.COM {
13049517SBill.Taylor@Sun.COM hermon_hw_snd_wqe_ud_t *ud;
13059517SBill.Taylor@Sun.COM hermon_hw_snd_wqe_remaddr_t *rc;
13069517SBill.Taylor@Sun.COM hermon_hw_snd_wqe_atomic_t *at;
13079517SBill.Taylor@Sun.COM hermon_hw_snd_wqe_remaddr_t *uc;
13089517SBill.Taylor@Sun.COM hermon_hw_snd_wqe_bind_t *bn;
13099517SBill.Taylor@Sun.COM hermon_hw_wqe_sgl_t *ds, *old_ds;
13109517SBill.Taylor@Sun.COM ibt_ud_dest_t *dest;
13119517SBill.Taylor@Sun.COM ibt_wr_ds_t *sgl;
13129517SBill.Taylor@Sun.COM hermon_ahhdl_t ah;
13139517SBill.Taylor@Sun.COM uint32_t nds;
13149517SBill.Taylor@Sun.COM int i, j, last_ds, num_ds, status;
13159517SBill.Taylor@Sun.COM int tmpsize;
13169517SBill.Taylor@Sun.COM
13179517SBill.Taylor@Sun.COM ASSERT(MUTEX_HELD(&qp->qp_sq_lock));
13189517SBill.Taylor@Sun.COM
13199517SBill.Taylor@Sun.COM /* Initialize the information for the Data Segments */
13209517SBill.Taylor@Sun.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)desc +
13219517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_ctrl_t));
13229517SBill.Taylor@Sun.COM nds = wr->wr_nds;
13239517SBill.Taylor@Sun.COM sgl = wr->wr_sgl;
13249517SBill.Taylor@Sun.COM num_ds = 0;
13259517SBill.Taylor@Sun.COM i = 0;
13269517SBill.Taylor@Sun.COM
13279517SBill.Taylor@Sun.COM /*
13289517SBill.Taylor@Sun.COM * Build a Send WQE depends first and foremost on the transport
13299517SBill.Taylor@Sun.COM * type of Work Request (i.e. UD, RC, or UC)
13309517SBill.Taylor@Sun.COM */
13319517SBill.Taylor@Sun.COM switch (wr->wr_trans) {
13329517SBill.Taylor@Sun.COM case IBT_UD_SRV:
13339517SBill.Taylor@Sun.COM /* Ensure that work request transport type matches QP type */
13349517SBill.Taylor@Sun.COM if (qp->qp_serv_type != HERMON_QP_UD) {
13359517SBill.Taylor@Sun.COM return (IBT_QP_SRV_TYPE_INVALID);
13369517SBill.Taylor@Sun.COM }
13379517SBill.Taylor@Sun.COM
13389517SBill.Taylor@Sun.COM /*
13399517SBill.Taylor@Sun.COM * Validate the operation type. For UD requests, only the
13409517SBill.Taylor@Sun.COM * "Send" and "Send LSO" operations are valid.
13419517SBill.Taylor@Sun.COM */
13429517SBill.Taylor@Sun.COM if (wr->wr_opcode != IBT_WRC_SEND &&
13439517SBill.Taylor@Sun.COM wr->wr_opcode != IBT_WRC_SEND_LSO) {
13449517SBill.Taylor@Sun.COM return (IBT_QP_OP_TYPE_INVALID);
13459517SBill.Taylor@Sun.COM }
13469517SBill.Taylor@Sun.COM
13479517SBill.Taylor@Sun.COM /*
13489517SBill.Taylor@Sun.COM * If this is a Special QP (QP0 or QP1), then we need to
13499517SBill.Taylor@Sun.COM * build MLX WQEs instead. So jump to hermon_wqe_mlx_build()
13509517SBill.Taylor@Sun.COM * and return whatever status it returns
13519517SBill.Taylor@Sun.COM */
13529517SBill.Taylor@Sun.COM if (qp->qp_is_special) {
13539517SBill.Taylor@Sun.COM if (wr->wr_opcode == IBT_WRC_SEND_LSO) {
13549517SBill.Taylor@Sun.COM return (IBT_QP_OP_TYPE_INVALID);
13559517SBill.Taylor@Sun.COM }
13569517SBill.Taylor@Sun.COM status = hermon_wqe_mlx_build(state, qp,
13579517SBill.Taylor@Sun.COM wr, desc, size);
13589517SBill.Taylor@Sun.COM return (status);
13599517SBill.Taylor@Sun.COM }
13609517SBill.Taylor@Sun.COM
13619517SBill.Taylor@Sun.COM /*
13629517SBill.Taylor@Sun.COM * Otherwise, if this is a normal UD Send request, then fill
13639517SBill.Taylor@Sun.COM * all the fields in the Hermon UD header for the WQE. Note:
13649517SBill.Taylor@Sun.COM * to do this we'll need to extract some information from the
13659517SBill.Taylor@Sun.COM * Address Handle passed with the work request.
13669517SBill.Taylor@Sun.COM */
13679517SBill.Taylor@Sun.COM ud = (hermon_hw_snd_wqe_ud_t *)((uintptr_t)desc +
13689517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_ctrl_t));
13699517SBill.Taylor@Sun.COM if (wr->wr_opcode == IBT_WRC_SEND) {
13709517SBill.Taylor@Sun.COM dest = wr->wr.ud.udwr_dest;
13719517SBill.Taylor@Sun.COM } else {
13729517SBill.Taylor@Sun.COM dest = wr->wr.ud_lso.lso_ud_dest;
13739517SBill.Taylor@Sun.COM }
13749517SBill.Taylor@Sun.COM ah = (hermon_ahhdl_t)dest->ud_ah;
13759517SBill.Taylor@Sun.COM if (ah == NULL) {
13769517SBill.Taylor@Sun.COM return (IBT_AH_HDL_INVALID);
13779517SBill.Taylor@Sun.COM }
13789517SBill.Taylor@Sun.COM
13799517SBill.Taylor@Sun.COM /*
13809517SBill.Taylor@Sun.COM * Build the Unreliable Datagram Segment for the WQE, using
13819517SBill.Taylor@Sun.COM * the information from the address handle and the work
13829517SBill.Taylor@Sun.COM * request.
13839517SBill.Taylor@Sun.COM */
13849517SBill.Taylor@Sun.COM /* mutex_enter(&ah->ah_lock); */
13859517SBill.Taylor@Sun.COM if (wr->wr_opcode == IBT_WRC_SEND) {
13869517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_UD(qp, ud, ah, wr->wr.ud.udwr_dest);
13879517SBill.Taylor@Sun.COM } else { /* IBT_WRC_SEND_LSO */
13889517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_UD(qp, ud, ah,
13899517SBill.Taylor@Sun.COM wr->wr.ud_lso.lso_ud_dest);
13909517SBill.Taylor@Sun.COM }
13919517SBill.Taylor@Sun.COM /* mutex_exit(&ah->ah_lock); */
13929517SBill.Taylor@Sun.COM
13939517SBill.Taylor@Sun.COM /* Update "ds" for filling in Data Segments (below) */
13949517SBill.Taylor@Sun.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)ud +
13959517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_ud_t));
13969517SBill.Taylor@Sun.COM
13979517SBill.Taylor@Sun.COM if (wr->wr_opcode == IBT_WRC_SEND_LSO) {
13989517SBill.Taylor@Sun.COM int total_len;
13999517SBill.Taylor@Sun.COM
14009517SBill.Taylor@Sun.COM total_len = (4 + 0xf + wr->wr.ud_lso.lso_hdr_sz) & ~0xf;
14019517SBill.Taylor@Sun.COM if ((uintptr_t)ds + total_len + (nds * 16) >
14029517SBill.Taylor@Sun.COM (uintptr_t)desc + (1 << qp->qp_sq_log_wqesz))
14039517SBill.Taylor@Sun.COM return (IBT_QP_SGL_LEN_INVALID);
14049517SBill.Taylor@Sun.COM
14059517SBill.Taylor@Sun.COM bcopy(wr->wr.ud_lso.lso_hdr, (uint32_t *)ds + 1,
14069517SBill.Taylor@Sun.COM wr->wr.ud_lso.lso_hdr_sz);
14079517SBill.Taylor@Sun.COM old_ds = ds;
14089517SBill.Taylor@Sun.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)ds + total_len);
14099517SBill.Taylor@Sun.COM for (; i < nds; i++) {
14109517SBill.Taylor@Sun.COM if (sgl[i].ds_len == 0)
14119517SBill.Taylor@Sun.COM continue;
14129517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_DATA_SEG_SEND(&ds[num_ds],
14139517SBill.Taylor@Sun.COM &sgl[i]);
14149517SBill.Taylor@Sun.COM num_ds++;
14159517SBill.Taylor@Sun.COM i++;
14169517SBill.Taylor@Sun.COM break;
14179517SBill.Taylor@Sun.COM }
14189517SBill.Taylor@Sun.COM membar_producer();
14199517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_LSO(qp, old_ds, wr->wr.ud_lso.lso_mss,
14209517SBill.Taylor@Sun.COM wr->wr.ud_lso.lso_hdr_sz);
14219517SBill.Taylor@Sun.COM }
14229517SBill.Taylor@Sun.COM
14239517SBill.Taylor@Sun.COM break;
14249517SBill.Taylor@Sun.COM
14259517SBill.Taylor@Sun.COM case IBT_RC_SRV:
14269517SBill.Taylor@Sun.COM /* Ensure that work request transport type matches QP type */
14279517SBill.Taylor@Sun.COM if (qp->qp_serv_type != HERMON_QP_RC) {
14289517SBill.Taylor@Sun.COM return (IBT_QP_SRV_TYPE_INVALID);
14299517SBill.Taylor@Sun.COM }
14309517SBill.Taylor@Sun.COM
14319517SBill.Taylor@Sun.COM /*
14329517SBill.Taylor@Sun.COM * Validate the operation type. For RC requests, we allow
14339517SBill.Taylor@Sun.COM * "Send", "RDMA Read", "RDMA Write", various "Atomic"
14349517SBill.Taylor@Sun.COM * operations, and memory window "Bind"
14359517SBill.Taylor@Sun.COM */
14369517SBill.Taylor@Sun.COM if ((wr->wr_opcode != IBT_WRC_SEND) &&
14379517SBill.Taylor@Sun.COM (wr->wr_opcode != IBT_WRC_RDMAR) &&
14389517SBill.Taylor@Sun.COM (wr->wr_opcode != IBT_WRC_RDMAW) &&
14399517SBill.Taylor@Sun.COM (wr->wr_opcode != IBT_WRC_CSWAP) &&
14409517SBill.Taylor@Sun.COM (wr->wr_opcode != IBT_WRC_FADD) &&
14419517SBill.Taylor@Sun.COM (wr->wr_opcode != IBT_WRC_BIND)) {
14429517SBill.Taylor@Sun.COM return (IBT_QP_OP_TYPE_INVALID);
14439517SBill.Taylor@Sun.COM }
14449517SBill.Taylor@Sun.COM
14459517SBill.Taylor@Sun.COM /*
14469517SBill.Taylor@Sun.COM * If this is a Send request, then all we need to do is break
14479517SBill.Taylor@Sun.COM * out and here and begin the Data Segment processing below
14489517SBill.Taylor@Sun.COM */
14499517SBill.Taylor@Sun.COM if (wr->wr_opcode == IBT_WRC_SEND) {
14509517SBill.Taylor@Sun.COM break;
14519517SBill.Taylor@Sun.COM }
14529517SBill.Taylor@Sun.COM
14539517SBill.Taylor@Sun.COM /*
14549517SBill.Taylor@Sun.COM * If this is an RDMA Read or RDMA Write request, then fill
14559517SBill.Taylor@Sun.COM * in the "Remote Address" header fields.
14569517SBill.Taylor@Sun.COM */
14579517SBill.Taylor@Sun.COM if ((wr->wr_opcode == IBT_WRC_RDMAR) ||
14589517SBill.Taylor@Sun.COM (wr->wr_opcode == IBT_WRC_RDMAW)) {
14599517SBill.Taylor@Sun.COM rc = (hermon_hw_snd_wqe_remaddr_t *)((uintptr_t)desc +
14609517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_ctrl_t));
14619517SBill.Taylor@Sun.COM
14629517SBill.Taylor@Sun.COM /*
14639517SBill.Taylor@Sun.COM * Build the Remote Address Segment for the WQE, using
14649517SBill.Taylor@Sun.COM * the information from the RC work request.
14659517SBill.Taylor@Sun.COM */
14669517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_REMADDR(qp, rc, &wr->wr.rc.rcwr.rdma);
14679517SBill.Taylor@Sun.COM
14689517SBill.Taylor@Sun.COM /* Update "ds" for filling in Data Segments (below) */
14699517SBill.Taylor@Sun.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)rc +
14709517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_remaddr_t));
14719517SBill.Taylor@Sun.COM break;
14729517SBill.Taylor@Sun.COM }
14739517SBill.Taylor@Sun.COM
14749517SBill.Taylor@Sun.COM /*
14759517SBill.Taylor@Sun.COM * If this is one of the Atomic type operations (i.e
14769517SBill.Taylor@Sun.COM * Compare-Swap or Fetch-Add), then fill in both the "Remote
14779517SBill.Taylor@Sun.COM * Address" header fields and the "Atomic" header fields.
14789517SBill.Taylor@Sun.COM */
14799517SBill.Taylor@Sun.COM if ((wr->wr_opcode == IBT_WRC_CSWAP) ||
14809517SBill.Taylor@Sun.COM (wr->wr_opcode == IBT_WRC_FADD)) {
14819517SBill.Taylor@Sun.COM rc = (hermon_hw_snd_wqe_remaddr_t *)((uintptr_t)desc +
14829517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_ctrl_t));
14839517SBill.Taylor@Sun.COM at = (hermon_hw_snd_wqe_atomic_t *)((uintptr_t)rc +
14849517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_remaddr_t));
14859517SBill.Taylor@Sun.COM
14869517SBill.Taylor@Sun.COM /*
14879517SBill.Taylor@Sun.COM * Build the Remote Address and Atomic Segments for
14889517SBill.Taylor@Sun.COM * the WQE, using the information from the RC Atomic
14899517SBill.Taylor@Sun.COM * work request.
14909517SBill.Taylor@Sun.COM */
14919517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_RC_ATOMIC_REMADDR(qp, rc, wr);
14929517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_ATOMIC(qp, at, wr->wr.rc.rcwr.atomic);
14939517SBill.Taylor@Sun.COM
14949517SBill.Taylor@Sun.COM /* Update "ds" for filling in Data Segments (below) */
14959517SBill.Taylor@Sun.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)at +
14969517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_atomic_t));
14979517SBill.Taylor@Sun.COM
14989517SBill.Taylor@Sun.COM /*
14999517SBill.Taylor@Sun.COM * Update "nds" and "sgl" because Atomic requests have
15009517SBill.Taylor@Sun.COM * only a single Data Segment (and they are encoded
15019517SBill.Taylor@Sun.COM * somewhat differently in the work request.
15029517SBill.Taylor@Sun.COM */
15039517SBill.Taylor@Sun.COM nds = 1;
15049517SBill.Taylor@Sun.COM sgl = wr->wr_sgl;
15059517SBill.Taylor@Sun.COM break;
15069517SBill.Taylor@Sun.COM }
15079517SBill.Taylor@Sun.COM
15089517SBill.Taylor@Sun.COM /*
15099517SBill.Taylor@Sun.COM * If this is memory window Bind operation, then we call the
15109517SBill.Taylor@Sun.COM * hermon_wr_bind_check() routine to validate the request and
15119517SBill.Taylor@Sun.COM * to generate the updated RKey. If this is successful, then
15129517SBill.Taylor@Sun.COM * we fill in the WQE's "Bind" header fields.
15139517SBill.Taylor@Sun.COM */
15149517SBill.Taylor@Sun.COM if (wr->wr_opcode == IBT_WRC_BIND) {
15159517SBill.Taylor@Sun.COM status = hermon_wr_bind_check(state, wr);
15169517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
15179517SBill.Taylor@Sun.COM return (status);
15189517SBill.Taylor@Sun.COM }
15199517SBill.Taylor@Sun.COM
15209517SBill.Taylor@Sun.COM bn = (hermon_hw_snd_wqe_bind_t *)((uintptr_t)desc +
15219517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_ctrl_t));
15229517SBill.Taylor@Sun.COM
15239517SBill.Taylor@Sun.COM /*
15249517SBill.Taylor@Sun.COM * Build the Bind Memory Window Segments for the WQE,
15259517SBill.Taylor@Sun.COM * using the information from the RC Bind memory
15269517SBill.Taylor@Sun.COM * window work request.
15279517SBill.Taylor@Sun.COM */
15289517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_BIND(qp, bn, wr->wr.rc.rcwr.bind);
15299517SBill.Taylor@Sun.COM
15309517SBill.Taylor@Sun.COM /*
15319517SBill.Taylor@Sun.COM * Update the "ds" pointer. Even though the "bind"
15329517SBill.Taylor@Sun.COM * operation requires no SGLs, this is necessary to
15339517SBill.Taylor@Sun.COM * facilitate the correct descriptor size calculations
15349517SBill.Taylor@Sun.COM * (below).
15359517SBill.Taylor@Sun.COM */
15369517SBill.Taylor@Sun.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)bn +
15379517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_bind_t));
15389517SBill.Taylor@Sun.COM nds = 0;
15399517SBill.Taylor@Sun.COM }
15409517SBill.Taylor@Sun.COM break;
15419517SBill.Taylor@Sun.COM
15429517SBill.Taylor@Sun.COM case IBT_UC_SRV:
15439517SBill.Taylor@Sun.COM /* Ensure that work request transport type matches QP type */
15449517SBill.Taylor@Sun.COM if (qp->qp_serv_type != HERMON_QP_UC) {
15459517SBill.Taylor@Sun.COM return (IBT_QP_SRV_TYPE_INVALID);
15469517SBill.Taylor@Sun.COM }
15479517SBill.Taylor@Sun.COM
15489517SBill.Taylor@Sun.COM /*
15499517SBill.Taylor@Sun.COM * Validate the operation type. For UC requests, we only
15509517SBill.Taylor@Sun.COM * allow "Send", "RDMA Write", and memory window "Bind".
15519517SBill.Taylor@Sun.COM * Note: Unlike RC, UC does not allow "RDMA Read" or "Atomic"
15529517SBill.Taylor@Sun.COM * operations
15539517SBill.Taylor@Sun.COM */
15549517SBill.Taylor@Sun.COM if ((wr->wr_opcode != IBT_WRC_SEND) &&
15559517SBill.Taylor@Sun.COM (wr->wr_opcode != IBT_WRC_RDMAW) &&
15569517SBill.Taylor@Sun.COM (wr->wr_opcode != IBT_WRC_BIND)) {
15579517SBill.Taylor@Sun.COM return (IBT_QP_OP_TYPE_INVALID);
15589517SBill.Taylor@Sun.COM }
15599517SBill.Taylor@Sun.COM
15609517SBill.Taylor@Sun.COM /*
15619517SBill.Taylor@Sun.COM * If this is a Send request, then all we need to do is break
15629517SBill.Taylor@Sun.COM * out and here and begin the Data Segment processing below
15639517SBill.Taylor@Sun.COM */
15649517SBill.Taylor@Sun.COM if (wr->wr_opcode == IBT_WRC_SEND) {
15659517SBill.Taylor@Sun.COM break;
15669517SBill.Taylor@Sun.COM }
15679517SBill.Taylor@Sun.COM
15689517SBill.Taylor@Sun.COM /*
15699517SBill.Taylor@Sun.COM * If this is an RDMA Write request, then fill in the "Remote
15709517SBill.Taylor@Sun.COM * Address" header fields.
15719517SBill.Taylor@Sun.COM */
15729517SBill.Taylor@Sun.COM if (wr->wr_opcode == IBT_WRC_RDMAW) {
15739517SBill.Taylor@Sun.COM uc = (hermon_hw_snd_wqe_remaddr_t *)((uintptr_t)desc +
15749517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_ctrl_t));
15759517SBill.Taylor@Sun.COM
15769517SBill.Taylor@Sun.COM /*
15779517SBill.Taylor@Sun.COM * Build the Remote Address Segment for the WQE, using
15789517SBill.Taylor@Sun.COM * the information from the UC work request.
15799517SBill.Taylor@Sun.COM */
15809517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_REMADDR(qp, uc, &wr->wr.uc.ucwr.rdma);
15819517SBill.Taylor@Sun.COM
15829517SBill.Taylor@Sun.COM /* Update "ds" for filling in Data Segments (below) */
15839517SBill.Taylor@Sun.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)uc +
15849517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_remaddr_t));
15859517SBill.Taylor@Sun.COM break;
15869517SBill.Taylor@Sun.COM }
15879517SBill.Taylor@Sun.COM
15889517SBill.Taylor@Sun.COM /*
15899517SBill.Taylor@Sun.COM * If this is memory window Bind operation, then we call the
15909517SBill.Taylor@Sun.COM * hermon_wr_bind_check() routine to validate the request and
15919517SBill.Taylor@Sun.COM * to generate the updated RKey. If this is successful, then
15929517SBill.Taylor@Sun.COM * we fill in the WQE's "Bind" header fields.
15939517SBill.Taylor@Sun.COM */
15949517SBill.Taylor@Sun.COM if (wr->wr_opcode == IBT_WRC_BIND) {
15959517SBill.Taylor@Sun.COM status = hermon_wr_bind_check(state, wr);
15969517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
15979517SBill.Taylor@Sun.COM return (status);
15989517SBill.Taylor@Sun.COM }
15999517SBill.Taylor@Sun.COM
16009517SBill.Taylor@Sun.COM bn = (hermon_hw_snd_wqe_bind_t *)((uintptr_t)desc +
16019517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_ctrl_t));
16029517SBill.Taylor@Sun.COM
16039517SBill.Taylor@Sun.COM /*
16049517SBill.Taylor@Sun.COM * Build the Bind Memory Window Segments for the WQE,
16059517SBill.Taylor@Sun.COM * using the information from the UC Bind memory
16069517SBill.Taylor@Sun.COM * window work request.
16079517SBill.Taylor@Sun.COM */
16089517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_BIND(qp, bn, wr->wr.uc.ucwr.bind);
16099517SBill.Taylor@Sun.COM
16109517SBill.Taylor@Sun.COM /*
16119517SBill.Taylor@Sun.COM * Update the "ds" pointer. Even though the "bind"
16129517SBill.Taylor@Sun.COM * operation requires no SGLs, this is necessary to
16139517SBill.Taylor@Sun.COM * facilitate the correct descriptor size calculations
16149517SBill.Taylor@Sun.COM * (below).
16159517SBill.Taylor@Sun.COM */
16169517SBill.Taylor@Sun.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)bn +
16179517SBill.Taylor@Sun.COM sizeof (hermon_hw_snd_wqe_bind_t));
16189517SBill.Taylor@Sun.COM nds = 0;
16199517SBill.Taylor@Sun.COM }
16209517SBill.Taylor@Sun.COM break;
16219517SBill.Taylor@Sun.COM
16229517SBill.Taylor@Sun.COM default:
16239517SBill.Taylor@Sun.COM return (IBT_QP_SRV_TYPE_INVALID);
16249517SBill.Taylor@Sun.COM }
16259517SBill.Taylor@Sun.COM
16269517SBill.Taylor@Sun.COM /*
16279517SBill.Taylor@Sun.COM * Now fill in the Data Segments (SGL) for the Send WQE based on
16289517SBill.Taylor@Sun.COM * the values setup above (i.e. "sgl", "nds", and the "ds" pointer
16299517SBill.Taylor@Sun.COM * Start by checking for a valid number of SGL entries
16309517SBill.Taylor@Sun.COM */
16319517SBill.Taylor@Sun.COM if (nds > qp->qp_sq_sgl) {
16329517SBill.Taylor@Sun.COM return (IBT_QP_SGL_LEN_INVALID);
16339517SBill.Taylor@Sun.COM }
16349517SBill.Taylor@Sun.COM
16359517SBill.Taylor@Sun.COM /*
16369517SBill.Taylor@Sun.COM * For each SGL in the Send Work Request, fill in the Send WQE's data
16379517SBill.Taylor@Sun.COM * segments. Note: We skip any SGL with zero size because Hermon
16389517SBill.Taylor@Sun.COM * hardware cannot handle a zero for "byte_cnt" in the WQE. Actually
16399517SBill.Taylor@Sun.COM * the encoding for zero means a 2GB transfer.
16409517SBill.Taylor@Sun.COM */
16419517SBill.Taylor@Sun.COM for (last_ds = num_ds, j = i; j < nds; j++) {
16429517SBill.Taylor@Sun.COM if (sgl[j].ds_len != 0)
16439517SBill.Taylor@Sun.COM last_ds++; /* real last ds of wqe to fill */
16449517SBill.Taylor@Sun.COM }
16459517SBill.Taylor@Sun.COM
16469517SBill.Taylor@Sun.COM /*
16479517SBill.Taylor@Sun.COM * Return the size of descriptor (in 16-byte chunks)
16489517SBill.Taylor@Sun.COM * For Hermon, we want them (for now) to be on stride size
16499517SBill.Taylor@Sun.COM * boundaries, which was implicit in Tavor/Arbel
16509517SBill.Taylor@Sun.COM *
16519517SBill.Taylor@Sun.COM */
16529517SBill.Taylor@Sun.COM tmpsize = ((uintptr_t)&ds[last_ds] - (uintptr_t)desc);
16539517SBill.Taylor@Sun.COM
16549517SBill.Taylor@Sun.COM *size = tmpsize >> 0x4;
16559517SBill.Taylor@Sun.COM
16569517SBill.Taylor@Sun.COM for (j = nds; --j >= i; ) {
16579517SBill.Taylor@Sun.COM if (sgl[j].ds_len == 0) {
16589517SBill.Taylor@Sun.COM continue;
16599517SBill.Taylor@Sun.COM }
16609517SBill.Taylor@Sun.COM
16619517SBill.Taylor@Sun.COM /*
16629517SBill.Taylor@Sun.COM * Fill in the Data Segment(s) for the current WQE, using the
16639517SBill.Taylor@Sun.COM * information contained in the scatter-gather list of the
16649517SBill.Taylor@Sun.COM * work request.
16659517SBill.Taylor@Sun.COM */
16669517SBill.Taylor@Sun.COM last_ds--;
16679517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_DATA_SEG_SEND(&ds[last_ds], &sgl[j]);
16689517SBill.Taylor@Sun.COM }
16699517SBill.Taylor@Sun.COM
16709517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
16719517SBill.Taylor@Sun.COM }
16729517SBill.Taylor@Sun.COM
16739517SBill.Taylor@Sun.COM
16749517SBill.Taylor@Sun.COM
16759517SBill.Taylor@Sun.COM /*
16769517SBill.Taylor@Sun.COM * hermon_wqe_mlx_build()
16779517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
16789517SBill.Taylor@Sun.COM */
16799517SBill.Taylor@Sun.COM static int
hermon_wqe_mlx_build(hermon_state_t * state,hermon_qphdl_t qp,ibt_send_wr_t * wr,uint64_t * desc,uint_t * size)16809517SBill.Taylor@Sun.COM hermon_wqe_mlx_build(hermon_state_t *state, hermon_qphdl_t qp,
16819517SBill.Taylor@Sun.COM ibt_send_wr_t *wr, uint64_t *desc, uint_t *size)
16829517SBill.Taylor@Sun.COM {
16839517SBill.Taylor@Sun.COM hermon_ahhdl_t ah;
16849517SBill.Taylor@Sun.COM hermon_hw_udav_t *udav;
16859517SBill.Taylor@Sun.COM ib_lrh_hdr_t *lrh;
16869517SBill.Taylor@Sun.COM ib_grh_t *grh;
16879517SBill.Taylor@Sun.COM ib_bth_hdr_t *bth;
16889517SBill.Taylor@Sun.COM ib_deth_hdr_t *deth;
16899517SBill.Taylor@Sun.COM hermon_hw_wqe_sgl_t *ds;
16909517SBill.Taylor@Sun.COM ibt_wr_ds_t *sgl;
16919517SBill.Taylor@Sun.COM uint8_t *mgmtclass, *hpoint, *hcount;
16929517SBill.Taylor@Sun.COM uint32_t nds, offset, pktlen;
16939517SBill.Taylor@Sun.COM uint32_t desc_sz;
16949517SBill.Taylor@Sun.COM int i, num_ds;
16959517SBill.Taylor@Sun.COM int tmpsize;
16969517SBill.Taylor@Sun.COM
16979517SBill.Taylor@Sun.COM ASSERT(MUTEX_HELD(&qp->qp_sq_lock));
16989517SBill.Taylor@Sun.COM
16999517SBill.Taylor@Sun.COM /* Initialize the information for the Data Segments */
17009517SBill.Taylor@Sun.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)desc +
17019517SBill.Taylor@Sun.COM sizeof (hermon_hw_mlx_wqe_nextctrl_t));
17029517SBill.Taylor@Sun.COM
17039517SBill.Taylor@Sun.COM /*
17049517SBill.Taylor@Sun.COM * Pull the address handle from the work request. The UDAV will
17059517SBill.Taylor@Sun.COM * be used to answer some questions about the request.
17069517SBill.Taylor@Sun.COM */
17079517SBill.Taylor@Sun.COM ah = (hermon_ahhdl_t)wr->wr.ud.udwr_dest->ud_ah;
17089517SBill.Taylor@Sun.COM if (ah == NULL) {
17099517SBill.Taylor@Sun.COM return (IBT_AH_HDL_INVALID);
17109517SBill.Taylor@Sun.COM }
17119517SBill.Taylor@Sun.COM mutex_enter(&ah->ah_lock);
17129517SBill.Taylor@Sun.COM udav = ah->ah_udav;
17139517SBill.Taylor@Sun.COM
17149517SBill.Taylor@Sun.COM /*
17159517SBill.Taylor@Sun.COM * If the request is for QP1 and the destination LID is equal to
17169517SBill.Taylor@Sun.COM * the Permissive LID, then return an error. This combination is
17179517SBill.Taylor@Sun.COM * not allowed
17189517SBill.Taylor@Sun.COM */
17199517SBill.Taylor@Sun.COM if ((udav->rlid == IB_LID_PERMISSIVE) &&
17209517SBill.Taylor@Sun.COM (qp->qp_is_special == HERMON_QP_GSI)) {
17219517SBill.Taylor@Sun.COM mutex_exit(&ah->ah_lock);
17229517SBill.Taylor@Sun.COM return (IBT_AH_HDL_INVALID);
17239517SBill.Taylor@Sun.COM }
17249517SBill.Taylor@Sun.COM
17259517SBill.Taylor@Sun.COM /*
17269517SBill.Taylor@Sun.COM * Calculate the size of the packet headers, including the GRH
17279517SBill.Taylor@Sun.COM * (if necessary)
17289517SBill.Taylor@Sun.COM */
17299517SBill.Taylor@Sun.COM desc_sz = sizeof (ib_lrh_hdr_t) + sizeof (ib_bth_hdr_t) +
17309517SBill.Taylor@Sun.COM sizeof (ib_deth_hdr_t);
17319517SBill.Taylor@Sun.COM if (udav->grh) {
17329517SBill.Taylor@Sun.COM desc_sz += sizeof (ib_grh_t);
17339517SBill.Taylor@Sun.COM }
17349517SBill.Taylor@Sun.COM
17359517SBill.Taylor@Sun.COM /*
17369517SBill.Taylor@Sun.COM * Begin to build the first "inline" data segment for the packet
17379517SBill.Taylor@Sun.COM * headers. Note: By specifying "inline" we can build the contents
17389517SBill.Taylor@Sun.COM * of the MAD packet headers directly into the work queue (as part
17399517SBill.Taylor@Sun.COM * descriptor). This has the advantage of both speeding things up
17409517SBill.Taylor@Sun.COM * and of not requiring the driver to allocate/register any additional
17419517SBill.Taylor@Sun.COM * memory for the packet headers.
17429517SBill.Taylor@Sun.COM */
17439517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_INLINE(qp, &ds[0], desc_sz);
17449517SBill.Taylor@Sun.COM desc_sz += 4;
17459517SBill.Taylor@Sun.COM
17469517SBill.Taylor@Sun.COM /*
17479517SBill.Taylor@Sun.COM * Build Local Route Header (LRH)
17489517SBill.Taylor@Sun.COM * We start here by building the LRH into a temporary location.
17499517SBill.Taylor@Sun.COM * When we have finished we copy the LRH data into the descriptor.
17509517SBill.Taylor@Sun.COM *
17519517SBill.Taylor@Sun.COM * Notice that the VL values are hardcoded. This is not a problem
17529517SBill.Taylor@Sun.COM * because VL15 is decided later based on the value in the MLX
17539517SBill.Taylor@Sun.COM * transport "next/ctrl" header (see the "vl15" bit below), and it
17549517SBill.Taylor@Sun.COM * is otherwise (meaning for QP1) chosen from the SL-to-VL table
17559517SBill.Taylor@Sun.COM * values. This rule does not hold for loopback packets however
17569517SBill.Taylor@Sun.COM * (all of which bypass the SL-to-VL tables) and it is the reason
17579517SBill.Taylor@Sun.COM * that non-QP0 MADs are setup with VL hardcoded to zero below.
17589517SBill.Taylor@Sun.COM *
17599517SBill.Taylor@Sun.COM * Notice also that Source LID is hardcoded to the Permissive LID
17609517SBill.Taylor@Sun.COM * (0xFFFF). This is also not a problem because if the Destination
17619517SBill.Taylor@Sun.COM * LID is not the Permissive LID, then the "slr" value in the MLX
17629517SBill.Taylor@Sun.COM * transport "next/ctrl" header will be set to zero and the hardware
17639517SBill.Taylor@Sun.COM * will pull the LID from value in the port.
17649517SBill.Taylor@Sun.COM */
17659517SBill.Taylor@Sun.COM lrh = (ib_lrh_hdr_t *)((uintptr_t)&ds[0] + 4);
17669517SBill.Taylor@Sun.COM pktlen = (desc_sz + 0x100) >> 2;
17679517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_MLX_LRH(lrh, qp, udav, pktlen);
17689517SBill.Taylor@Sun.COM
17699517SBill.Taylor@Sun.COM /*
17709517SBill.Taylor@Sun.COM * Build Global Route Header (GRH)
17719517SBill.Taylor@Sun.COM * This is only built if necessary as defined by the "grh" bit in
17729517SBill.Taylor@Sun.COM * the address vector. Note: We also calculate the offset to the
17739517SBill.Taylor@Sun.COM * next header (BTH) based on whether or not the "grh" bit is set.
17749517SBill.Taylor@Sun.COM */
17759517SBill.Taylor@Sun.COM if (udav->grh) {
17769517SBill.Taylor@Sun.COM /*
17779517SBill.Taylor@Sun.COM * If the request is for QP0, then return an error. The
17789517SBill.Taylor@Sun.COM * combination of global routine (GRH) and QP0 is not allowed.
17799517SBill.Taylor@Sun.COM */
17809517SBill.Taylor@Sun.COM if (qp->qp_is_special == HERMON_QP_SMI) {
17819517SBill.Taylor@Sun.COM mutex_exit(&ah->ah_lock);
17829517SBill.Taylor@Sun.COM return (IBT_AH_HDL_INVALID);
17839517SBill.Taylor@Sun.COM }
17849517SBill.Taylor@Sun.COM grh = (ib_grh_t *)((uintptr_t)lrh + sizeof (ib_lrh_hdr_t));
17859517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_MLX_GRH(state, grh, qp, udav, pktlen);
17869517SBill.Taylor@Sun.COM
17879517SBill.Taylor@Sun.COM bth = (ib_bth_hdr_t *)((uintptr_t)grh + sizeof (ib_grh_t));
17889517SBill.Taylor@Sun.COM } else {
17899517SBill.Taylor@Sun.COM bth = (ib_bth_hdr_t *)((uintptr_t)lrh + sizeof (ib_lrh_hdr_t));
17909517SBill.Taylor@Sun.COM }
17919517SBill.Taylor@Sun.COM mutex_exit(&ah->ah_lock);
17929517SBill.Taylor@Sun.COM
17939517SBill.Taylor@Sun.COM
17949517SBill.Taylor@Sun.COM /*
17959517SBill.Taylor@Sun.COM * Build Base Transport Header (BTH)
17969517SBill.Taylor@Sun.COM * Notice that the M, PadCnt, and TVer fields are all set
17979517SBill.Taylor@Sun.COM * to zero implicitly. This is true for all Management Datagrams
17989517SBill.Taylor@Sun.COM * MADs whether GSI are SMI.
17999517SBill.Taylor@Sun.COM */
18009517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_MLX_BTH(state, bth, qp, wr);
18019517SBill.Taylor@Sun.COM
18029517SBill.Taylor@Sun.COM /*
18039517SBill.Taylor@Sun.COM * Build Datagram Extended Transport Header (DETH)
18049517SBill.Taylor@Sun.COM */
18059517SBill.Taylor@Sun.COM deth = (ib_deth_hdr_t *)((uintptr_t)bth + sizeof (ib_bth_hdr_t));
18069517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_MLX_DETH(deth, qp);
18079517SBill.Taylor@Sun.COM
18089517SBill.Taylor@Sun.COM /* Ensure that the Data Segment is aligned on a 16-byte boundary */
18099517SBill.Taylor@Sun.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)deth + sizeof (ib_deth_hdr_t));
18109517SBill.Taylor@Sun.COM ds = (hermon_hw_wqe_sgl_t *)(((uintptr_t)ds + 0xF) & ~0xF);
18119517SBill.Taylor@Sun.COM nds = wr->wr_nds;
18129517SBill.Taylor@Sun.COM sgl = wr->wr_sgl;
18139517SBill.Taylor@Sun.COM num_ds = 0;
18149517SBill.Taylor@Sun.COM
18159517SBill.Taylor@Sun.COM /*
18169517SBill.Taylor@Sun.COM * Now fill in the Data Segments (SGL) for the MLX WQE based on the
18179517SBill.Taylor@Sun.COM * values set up above (i.e. "sgl", "nds", and the "ds" pointer
18189517SBill.Taylor@Sun.COM * Start by checking for a valid number of SGL entries
18199517SBill.Taylor@Sun.COM */
18209517SBill.Taylor@Sun.COM if (nds > qp->qp_sq_sgl) {
18219517SBill.Taylor@Sun.COM return (IBT_QP_SGL_LEN_INVALID);
18229517SBill.Taylor@Sun.COM }
18239517SBill.Taylor@Sun.COM
18249517SBill.Taylor@Sun.COM /*
18259517SBill.Taylor@Sun.COM * For each SGL in the Send Work Request, fill in the MLX WQE's data
18269517SBill.Taylor@Sun.COM * segments. Note: We skip any SGL with zero size because Hermon
18279517SBill.Taylor@Sun.COM * hardware cannot handle a zero for "byte_cnt" in the WQE. Actually
18289517SBill.Taylor@Sun.COM * the encoding for zero means a 2GB transfer. Because of this special
18299517SBill.Taylor@Sun.COM * encoding in the hardware, we mask the requested length with
18309517SBill.Taylor@Sun.COM * HERMON_WQE_SGL_BYTE_CNT_MASK (so that 2GB will end up encoded as
18319517SBill.Taylor@Sun.COM * zero.)
18329517SBill.Taylor@Sun.COM */
18339517SBill.Taylor@Sun.COM mgmtclass = hpoint = hcount = NULL;
18349517SBill.Taylor@Sun.COM offset = 0;
18359517SBill.Taylor@Sun.COM for (i = 0; i < nds; i++) {
18369517SBill.Taylor@Sun.COM if (sgl[i].ds_len == 0) {
18379517SBill.Taylor@Sun.COM continue;
18389517SBill.Taylor@Sun.COM }
18399517SBill.Taylor@Sun.COM
18409517SBill.Taylor@Sun.COM /*
18419517SBill.Taylor@Sun.COM * Fill in the Data Segment(s) for the MLX send WQE, using
18429517SBill.Taylor@Sun.COM * the information contained in the scatter-gather list of
18439517SBill.Taylor@Sun.COM * the work request.
18449517SBill.Taylor@Sun.COM */
18459517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_DATA_SEG_SEND(&ds[num_ds], &sgl[i]);
18469517SBill.Taylor@Sun.COM
18479517SBill.Taylor@Sun.COM /*
18489517SBill.Taylor@Sun.COM * Search through the contents of all MADs posted to QP0 to
18499517SBill.Taylor@Sun.COM * initialize pointers to the places where Directed Route "hop
18509517SBill.Taylor@Sun.COM * pointer", "hop count", and "mgmtclass" would be. Hermon
18519517SBill.Taylor@Sun.COM * needs these updated (i.e. incremented or decremented, as
18529517SBill.Taylor@Sun.COM * necessary) by software.
18539517SBill.Taylor@Sun.COM */
18549517SBill.Taylor@Sun.COM if (qp->qp_is_special == HERMON_QP_SMI) {
18559517SBill.Taylor@Sun.COM
18569517SBill.Taylor@Sun.COM HERMON_SPECIAL_QP_DRMAD_GET_MGMTCLASS(mgmtclass,
18579517SBill.Taylor@Sun.COM offset, sgl[i].ds_va, sgl[i].ds_len);
18589517SBill.Taylor@Sun.COM
18599517SBill.Taylor@Sun.COM HERMON_SPECIAL_QP_DRMAD_GET_HOPPOINTER(hpoint,
18609517SBill.Taylor@Sun.COM offset, sgl[i].ds_va, sgl[i].ds_len);
18619517SBill.Taylor@Sun.COM
18629517SBill.Taylor@Sun.COM HERMON_SPECIAL_QP_DRMAD_GET_HOPCOUNT(hcount,
18639517SBill.Taylor@Sun.COM offset, sgl[i].ds_va, sgl[i].ds_len);
18649517SBill.Taylor@Sun.COM
18659517SBill.Taylor@Sun.COM offset += sgl[i].ds_len;
18669517SBill.Taylor@Sun.COM }
18679517SBill.Taylor@Sun.COM num_ds++;
18689517SBill.Taylor@Sun.COM }
18699517SBill.Taylor@Sun.COM
18709517SBill.Taylor@Sun.COM /*
18719517SBill.Taylor@Sun.COM * Hermon's Directed Route MADs need to have the "hop pointer"
18729517SBill.Taylor@Sun.COM * incremented/decremented (as necessary) depending on whether it is
18739517SBill.Taylor@Sun.COM * currently less than or greater than the "hop count" (i.e. whether
18749517SBill.Taylor@Sun.COM * the MAD is a request or a response.)
18759517SBill.Taylor@Sun.COM */
18769517SBill.Taylor@Sun.COM if (qp->qp_is_special == HERMON_QP_SMI) {
18779517SBill.Taylor@Sun.COM HERMON_SPECIAL_QP_DRMAD_DO_HOPPOINTER_MODIFY(*mgmtclass,
18789517SBill.Taylor@Sun.COM *hpoint, *hcount);
18799517SBill.Taylor@Sun.COM }
18809517SBill.Taylor@Sun.COM
18819517SBill.Taylor@Sun.COM /*
18829517SBill.Taylor@Sun.COM * Now fill in the ICRC Data Segment. This data segment is inlined
18839517SBill.Taylor@Sun.COM * just like the packets headers above, but it is only four bytes and
18849517SBill.Taylor@Sun.COM * set to zero (to indicate that we wish the hardware to generate ICRC.
18859517SBill.Taylor@Sun.COM */
18869517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_INLINE_ICRC(qp, &ds[num_ds], 4, 0);
18879517SBill.Taylor@Sun.COM num_ds++;
18889517SBill.Taylor@Sun.COM
18899517SBill.Taylor@Sun.COM /*
18909517SBill.Taylor@Sun.COM * Return the size of descriptor (in 16-byte chunks)
18919517SBill.Taylor@Sun.COM * For Hermon, we want them (for now) to be on stride size
18929517SBill.Taylor@Sun.COM * boundaries, which was implicit in Tavor/Arbel
18939517SBill.Taylor@Sun.COM */
18949517SBill.Taylor@Sun.COM tmpsize = ((uintptr_t)&ds[num_ds] - (uintptr_t)desc);
18959517SBill.Taylor@Sun.COM
18969517SBill.Taylor@Sun.COM *size = tmpsize >> 0x04;
18979517SBill.Taylor@Sun.COM
18989517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
18999517SBill.Taylor@Sun.COM }
19009517SBill.Taylor@Sun.COM
19019517SBill.Taylor@Sun.COM
19029517SBill.Taylor@Sun.COM
19039517SBill.Taylor@Sun.COM /*
19049517SBill.Taylor@Sun.COM * hermon_wqe_recv_build()
19059517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
19069517SBill.Taylor@Sun.COM */
19079517SBill.Taylor@Sun.COM /* ARGSUSED */
19089517SBill.Taylor@Sun.COM static int
hermon_wqe_recv_build(hermon_state_t * state,hermon_qphdl_t qp,ibt_recv_wr_t * wr,uint64_t * desc)19099517SBill.Taylor@Sun.COM hermon_wqe_recv_build(hermon_state_t *state, hermon_qphdl_t qp,
19109517SBill.Taylor@Sun.COM ibt_recv_wr_t *wr, uint64_t *desc)
19119517SBill.Taylor@Sun.COM {
19129517SBill.Taylor@Sun.COM hermon_hw_wqe_sgl_t *ds;
19139517SBill.Taylor@Sun.COM int i, num_ds;
19149517SBill.Taylor@Sun.COM
1915*12965SWilliam.Taylor@Oracle.COM ASSERT(MUTEX_HELD(&qp->qp_lock));
19169517SBill.Taylor@Sun.COM
19179517SBill.Taylor@Sun.COM /*
19189517SBill.Taylor@Sun.COM * Fill in the Data Segments (SGL) for the Recv WQE - don't
19199517SBill.Taylor@Sun.COM * need to have a reserved for the ctrl, there is none on the
19209517SBill.Taylor@Sun.COM * recv queue for hermon, but will need to put an invalid
19219517SBill.Taylor@Sun.COM * (null) scatter pointer per PRM
19229517SBill.Taylor@Sun.COM */
19239517SBill.Taylor@Sun.COM ds = (hermon_hw_wqe_sgl_t *)(uintptr_t)desc;
19249517SBill.Taylor@Sun.COM num_ds = 0;
19259517SBill.Taylor@Sun.COM
19269517SBill.Taylor@Sun.COM /* Check for valid number of SGL entries */
19279517SBill.Taylor@Sun.COM if (wr->wr_nds > qp->qp_rq_sgl) {
19289517SBill.Taylor@Sun.COM return (IBT_QP_SGL_LEN_INVALID);
19299517SBill.Taylor@Sun.COM }
19309517SBill.Taylor@Sun.COM
19319517SBill.Taylor@Sun.COM /*
19329517SBill.Taylor@Sun.COM * For each SGL in the Recv Work Request, fill in the Recv WQE's data
19339517SBill.Taylor@Sun.COM * segments. Note: We skip any SGL with zero size because Hermon
19349517SBill.Taylor@Sun.COM * hardware cannot handle a zero for "byte_cnt" in the WQE. Actually
19359517SBill.Taylor@Sun.COM * the encoding for zero means a 2GB transfer. Because of this special
19369517SBill.Taylor@Sun.COM * encoding in the hardware, we mask the requested length with
19379517SBill.Taylor@Sun.COM * HERMON_WQE_SGL_BYTE_CNT_MASK (so that 2GB will end up encoded as
19389517SBill.Taylor@Sun.COM * zero.)
19399517SBill.Taylor@Sun.COM */
19409517SBill.Taylor@Sun.COM for (i = 0; i < wr->wr_nds; i++) {
19419517SBill.Taylor@Sun.COM if (wr->wr_sgl[i].ds_len == 0) {
19429517SBill.Taylor@Sun.COM continue;
19439517SBill.Taylor@Sun.COM }
19449517SBill.Taylor@Sun.COM
19459517SBill.Taylor@Sun.COM /*
19469517SBill.Taylor@Sun.COM * Fill in the Data Segment(s) for the receive WQE, using the
19479517SBill.Taylor@Sun.COM * information contained in the scatter-gather list of the
19489517SBill.Taylor@Sun.COM * work request.
19499517SBill.Taylor@Sun.COM */
19509517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_DATA_SEG_RECV(&ds[num_ds], &wr->wr_sgl[i]);
19519517SBill.Taylor@Sun.COM num_ds++;
19529517SBill.Taylor@Sun.COM }
19539517SBill.Taylor@Sun.COM
19549517SBill.Taylor@Sun.COM /* put the null sgl pointer as well if needed */
19559517SBill.Taylor@Sun.COM if (num_ds < qp->qp_rq_sgl) {
19569517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_DATA_SEG_RECV(&ds[num_ds], &null_sgl);
19579517SBill.Taylor@Sun.COM }
19589517SBill.Taylor@Sun.COM
19599517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
19609517SBill.Taylor@Sun.COM }
19619517SBill.Taylor@Sun.COM
19629517SBill.Taylor@Sun.COM
19639517SBill.Taylor@Sun.COM
19649517SBill.Taylor@Sun.COM /*
19659517SBill.Taylor@Sun.COM * hermon_wqe_srq_build()
19669517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
19679517SBill.Taylor@Sun.COM */
19689517SBill.Taylor@Sun.COM /* ARGSUSED */
19699517SBill.Taylor@Sun.COM static int
hermon_wqe_srq_build(hermon_state_t * state,hermon_srqhdl_t srq,ibt_recv_wr_t * wr,uint64_t * desc)19709517SBill.Taylor@Sun.COM hermon_wqe_srq_build(hermon_state_t *state, hermon_srqhdl_t srq,
19719517SBill.Taylor@Sun.COM ibt_recv_wr_t *wr, uint64_t *desc)
19729517SBill.Taylor@Sun.COM {
19739517SBill.Taylor@Sun.COM hermon_hw_wqe_sgl_t *ds;
19749517SBill.Taylor@Sun.COM int i, num_ds;
19759517SBill.Taylor@Sun.COM
19769517SBill.Taylor@Sun.COM ASSERT(MUTEX_HELD(&srq->srq_lock));
19779517SBill.Taylor@Sun.COM
19789517SBill.Taylor@Sun.COM /* Fill in the Data Segments (SGL) for the Recv WQE */
19799517SBill.Taylor@Sun.COM ds = (hermon_hw_wqe_sgl_t *)((uintptr_t)desc +
19809517SBill.Taylor@Sun.COM sizeof (hermon_hw_srq_wqe_next_t));
19819517SBill.Taylor@Sun.COM num_ds = 0;
19829517SBill.Taylor@Sun.COM
19839517SBill.Taylor@Sun.COM /* Check for valid number of SGL entries */
19849517SBill.Taylor@Sun.COM if (wr->wr_nds > srq->srq_wq_sgl) {
19859517SBill.Taylor@Sun.COM return (IBT_QP_SGL_LEN_INVALID);
19869517SBill.Taylor@Sun.COM }
19879517SBill.Taylor@Sun.COM
19889517SBill.Taylor@Sun.COM /*
19899517SBill.Taylor@Sun.COM * For each SGL in the Recv Work Request, fill in the Recv WQE's data
19909517SBill.Taylor@Sun.COM * segments. Note: We skip any SGL with zero size because Hermon
19919517SBill.Taylor@Sun.COM * hardware cannot handle a zero for "byte_cnt" in the WQE. Actually
19929517SBill.Taylor@Sun.COM * the encoding for zero means a 2GB transfer. Because of this special
19939517SBill.Taylor@Sun.COM * encoding in the hardware, we mask the requested length with
19949517SBill.Taylor@Sun.COM * HERMON_WQE_SGL_BYTE_CNT_MASK (so that 2GB will end up encoded as
19959517SBill.Taylor@Sun.COM * zero.)
19969517SBill.Taylor@Sun.COM */
19979517SBill.Taylor@Sun.COM for (i = 0; i < wr->wr_nds; i++) {
19989517SBill.Taylor@Sun.COM if (wr->wr_sgl[i].ds_len == 0) {
19999517SBill.Taylor@Sun.COM continue;
20009517SBill.Taylor@Sun.COM }
20019517SBill.Taylor@Sun.COM
20029517SBill.Taylor@Sun.COM /*
20039517SBill.Taylor@Sun.COM * Fill in the Data Segment(s) for the receive WQE, using the
20049517SBill.Taylor@Sun.COM * information contained in the scatter-gather list of the
20059517SBill.Taylor@Sun.COM * work request.
20069517SBill.Taylor@Sun.COM */
20079517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_DATA_SEG_RECV(&ds[num_ds], &wr->wr_sgl[i]);
20089517SBill.Taylor@Sun.COM num_ds++;
20099517SBill.Taylor@Sun.COM }
20109517SBill.Taylor@Sun.COM
20119517SBill.Taylor@Sun.COM /*
20129517SBill.Taylor@Sun.COM * put in the null sgl pointer as well, if needed
20139517SBill.Taylor@Sun.COM */
20149517SBill.Taylor@Sun.COM if (num_ds < srq->srq_wq_sgl) {
20159517SBill.Taylor@Sun.COM HERMON_WQE_BUILD_DATA_SEG_RECV(&ds[num_ds], &null_sgl);
20169517SBill.Taylor@Sun.COM }
20179517SBill.Taylor@Sun.COM
20189517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
20199517SBill.Taylor@Sun.COM }
20209517SBill.Taylor@Sun.COM
20219517SBill.Taylor@Sun.COM
20229517SBill.Taylor@Sun.COM /*
20239517SBill.Taylor@Sun.COM * hermon_wr_get_immediate()
20249517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
20259517SBill.Taylor@Sun.COM */
20269517SBill.Taylor@Sun.COM static uint32_t
hermon_wr_get_immediate(ibt_send_wr_t * wr)20279517SBill.Taylor@Sun.COM hermon_wr_get_immediate(ibt_send_wr_t *wr)
20289517SBill.Taylor@Sun.COM {
20299517SBill.Taylor@Sun.COM /*
20309517SBill.Taylor@Sun.COM * This routine extracts the "immediate data" from the appropriate
20319517SBill.Taylor@Sun.COM * location in the IBTF work request. Because of the way the
20329517SBill.Taylor@Sun.COM * work request structure is defined, the location for this data
20339517SBill.Taylor@Sun.COM * depends on the actual work request operation type.
20349517SBill.Taylor@Sun.COM */
20359517SBill.Taylor@Sun.COM
20369517SBill.Taylor@Sun.COM /* For RDMA Write, test if RC or UC */
20379517SBill.Taylor@Sun.COM if (wr->wr_opcode == IBT_WRC_RDMAW) {
20389517SBill.Taylor@Sun.COM if (wr->wr_trans == IBT_RC_SRV) {
20399517SBill.Taylor@Sun.COM return (wr->wr.rc.rcwr.rdma.rdma_immed);
20409517SBill.Taylor@Sun.COM } else { /* IBT_UC_SRV */
20419517SBill.Taylor@Sun.COM return (wr->wr.uc.ucwr.rdma.rdma_immed);
20429517SBill.Taylor@Sun.COM }
20439517SBill.Taylor@Sun.COM }
20449517SBill.Taylor@Sun.COM
20459517SBill.Taylor@Sun.COM /* For Send, test if RC, UD, or UC */
20469517SBill.Taylor@Sun.COM if (wr->wr_opcode == IBT_WRC_SEND) {
20479517SBill.Taylor@Sun.COM if (wr->wr_trans == IBT_RC_SRV) {
20489517SBill.Taylor@Sun.COM return (wr->wr.rc.rcwr.send_immed);
20499517SBill.Taylor@Sun.COM } else if (wr->wr_trans == IBT_UD_SRV) {
20509517SBill.Taylor@Sun.COM return (wr->wr.ud.udwr_immed);
20519517SBill.Taylor@Sun.COM } else { /* IBT_UC_SRV */
20529517SBill.Taylor@Sun.COM return (wr->wr.uc.ucwr.send_immed);
20539517SBill.Taylor@Sun.COM }
20549517SBill.Taylor@Sun.COM }
20559517SBill.Taylor@Sun.COM
20569517SBill.Taylor@Sun.COM /*
20579517SBill.Taylor@Sun.COM * If any other type of request, then immediate is undefined
20589517SBill.Taylor@Sun.COM */
20599517SBill.Taylor@Sun.COM return (0);
20609517SBill.Taylor@Sun.COM }
20619517SBill.Taylor@Sun.COM
20629517SBill.Taylor@Sun.COM /*
20639517SBill.Taylor@Sun.COM * hermon_wqe_headroom()
20649517SBill.Taylor@Sun.COM * Context: can be called from interrupt or base, currently only from
20659517SBill.Taylor@Sun.COM * base context.
20669517SBill.Taylor@Sun.COM * Routine that fills in the headroom for the Send Queue
20679517SBill.Taylor@Sun.COM */
20689517SBill.Taylor@Sun.COM
20699517SBill.Taylor@Sun.COM static void
hermon_wqe_headroom(uint_t from,hermon_qphdl_t qp)20709517SBill.Taylor@Sun.COM hermon_wqe_headroom(uint_t from, hermon_qphdl_t qp)
20719517SBill.Taylor@Sun.COM {
20729517SBill.Taylor@Sun.COM uint32_t *wqe_start, *wqe_top, *wqe_base, qsize;
20739517SBill.Taylor@Sun.COM int hdrmwqes, wqesizebytes, sectperwqe;
20749517SBill.Taylor@Sun.COM uint32_t invalue;
20759517SBill.Taylor@Sun.COM int i, j;
20769517SBill.Taylor@Sun.COM
20779517SBill.Taylor@Sun.COM qsize = qp->qp_sq_bufsz;
20789517SBill.Taylor@Sun.COM wqesizebytes = 1 << qp->qp_sq_log_wqesz;
20799517SBill.Taylor@Sun.COM sectperwqe = wqesizebytes >> 6; /* 64 bytes/section */
20809517SBill.Taylor@Sun.COM hdrmwqes = qp->qp_sq_hdrmwqes;
20819517SBill.Taylor@Sun.COM wqe_base = (uint32_t *)HERMON_QP_SQ_ENTRY(qp, 0);
20829517SBill.Taylor@Sun.COM wqe_top = (uint32_t *)HERMON_QP_SQ_ENTRY(qp, qsize);
20839517SBill.Taylor@Sun.COM wqe_start = (uint32_t *)HERMON_QP_SQ_ENTRY(qp, from);
20849517SBill.Taylor@Sun.COM
20859517SBill.Taylor@Sun.COM for (i = 0; i < hdrmwqes; i++) {
20869517SBill.Taylor@Sun.COM for (j = 0; j < sectperwqe; j++) {
20879517SBill.Taylor@Sun.COM if (j == 0) { /* 1st section of wqe */
20889517SBill.Taylor@Sun.COM /* perserve ownership bit */
20899517SBill.Taylor@Sun.COM invalue = ddi_get32(qp->qp_wqinfo.qa_acchdl,
20909517SBill.Taylor@Sun.COM wqe_start) | 0x7FFFFFFF;
20919517SBill.Taylor@Sun.COM } else {
20929517SBill.Taylor@Sun.COM /* or just invalidate it */
20939517SBill.Taylor@Sun.COM invalue = 0xFFFFFFFF;
20949517SBill.Taylor@Sun.COM }
20959517SBill.Taylor@Sun.COM ddi_put32(qp->qp_wqinfo.qa_acchdl, wqe_start, invalue);
20969517SBill.Taylor@Sun.COM wqe_start += 16; /* move 64 bytes */
20979517SBill.Taylor@Sun.COM }
20989517SBill.Taylor@Sun.COM if (wqe_start == wqe_top) /* hit the end of the queue */
20999517SBill.Taylor@Sun.COM wqe_start = wqe_base; /* wrap to start */
21009517SBill.Taylor@Sun.COM }
21019517SBill.Taylor@Sun.COM }
21029517SBill.Taylor@Sun.COM
21039517SBill.Taylor@Sun.COM /*
21049517SBill.Taylor@Sun.COM * hermon_wr_bind_check()
21059517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
21069517SBill.Taylor@Sun.COM */
21079517SBill.Taylor@Sun.COM /* ARGSUSED */
21089517SBill.Taylor@Sun.COM static int
hermon_wr_bind_check(hermon_state_t * state,ibt_send_wr_t * wr)21099517SBill.Taylor@Sun.COM hermon_wr_bind_check(hermon_state_t *state, ibt_send_wr_t *wr)
21109517SBill.Taylor@Sun.COM {
21119517SBill.Taylor@Sun.COM ibt_bind_flags_t bind_flags;
21129517SBill.Taylor@Sun.COM uint64_t vaddr, len;
21139517SBill.Taylor@Sun.COM uint64_t reg_start_addr, reg_end_addr;
21149517SBill.Taylor@Sun.COM hermon_mwhdl_t mw;
21159517SBill.Taylor@Sun.COM hermon_mrhdl_t mr;
21169517SBill.Taylor@Sun.COM hermon_rsrc_t *mpt;
21179517SBill.Taylor@Sun.COM uint32_t new_rkey;
21189517SBill.Taylor@Sun.COM
21199517SBill.Taylor@Sun.COM /* Check for a valid Memory Window handle in the WR */
21209517SBill.Taylor@Sun.COM mw = (hermon_mwhdl_t)wr->wr.rc.rcwr.bind->bind_ibt_mw_hdl;
21219517SBill.Taylor@Sun.COM if (mw == NULL) {
21229517SBill.Taylor@Sun.COM return (IBT_MW_HDL_INVALID);
21239517SBill.Taylor@Sun.COM }
21249517SBill.Taylor@Sun.COM
21259517SBill.Taylor@Sun.COM /* Check for a valid Memory Region handle in the WR */
21269517SBill.Taylor@Sun.COM mr = (hermon_mrhdl_t)wr->wr.rc.rcwr.bind->bind_ibt_mr_hdl;
21279517SBill.Taylor@Sun.COM if (mr == NULL) {
21289517SBill.Taylor@Sun.COM return (IBT_MR_HDL_INVALID);
21299517SBill.Taylor@Sun.COM }
21309517SBill.Taylor@Sun.COM
21319517SBill.Taylor@Sun.COM mutex_enter(&mr->mr_lock);
21329517SBill.Taylor@Sun.COM mutex_enter(&mw->mr_lock);
21339517SBill.Taylor@Sun.COM
21349517SBill.Taylor@Sun.COM /*
21359517SBill.Taylor@Sun.COM * Check here to see if the memory region has already been partially
21369517SBill.Taylor@Sun.COM * deregistered as a result of a hermon_umap_umemlock_cb() callback.
21379517SBill.Taylor@Sun.COM * If so, this is an error, return failure.
21389517SBill.Taylor@Sun.COM */
21399517SBill.Taylor@Sun.COM if ((mr->mr_is_umem) && (mr->mr_umemcookie == NULL)) {
21409517SBill.Taylor@Sun.COM mutex_exit(&mr->mr_lock);
21419517SBill.Taylor@Sun.COM mutex_exit(&mw->mr_lock);
21429517SBill.Taylor@Sun.COM return (IBT_MR_HDL_INVALID);
21439517SBill.Taylor@Sun.COM }
21449517SBill.Taylor@Sun.COM
21459517SBill.Taylor@Sun.COM /* Check for a valid Memory Window RKey (i.e. a matching RKey) */
21469517SBill.Taylor@Sun.COM if (mw->mr_rkey != wr->wr.rc.rcwr.bind->bind_rkey) {
21479517SBill.Taylor@Sun.COM mutex_exit(&mr->mr_lock);
21489517SBill.Taylor@Sun.COM mutex_exit(&mw->mr_lock);
21499517SBill.Taylor@Sun.COM return (IBT_MR_RKEY_INVALID);
21509517SBill.Taylor@Sun.COM }
21519517SBill.Taylor@Sun.COM
21529517SBill.Taylor@Sun.COM /* Check for a valid Memory Region LKey (i.e. a matching LKey) */
21539517SBill.Taylor@Sun.COM if (mr->mr_lkey != wr->wr.rc.rcwr.bind->bind_lkey) {
21549517SBill.Taylor@Sun.COM mutex_exit(&mr->mr_lock);
21559517SBill.Taylor@Sun.COM mutex_exit(&mw->mr_lock);
21569517SBill.Taylor@Sun.COM return (IBT_MR_LKEY_INVALID);
21579517SBill.Taylor@Sun.COM }
21589517SBill.Taylor@Sun.COM
21599517SBill.Taylor@Sun.COM /*
21609517SBill.Taylor@Sun.COM * Now check for valid "vaddr" and "len". Note: We don't check the
21619517SBill.Taylor@Sun.COM * "vaddr" range when "len == 0" (i.e. on unbind operations)
21629517SBill.Taylor@Sun.COM */
21639517SBill.Taylor@Sun.COM len = wr->wr.rc.rcwr.bind->bind_len;
21649517SBill.Taylor@Sun.COM if (len != 0) {
21659517SBill.Taylor@Sun.COM vaddr = wr->wr.rc.rcwr.bind->bind_va;
21669517SBill.Taylor@Sun.COM reg_start_addr = mr->mr_bindinfo.bi_addr;
21679517SBill.Taylor@Sun.COM reg_end_addr = mr->mr_bindinfo.bi_addr +
21689517SBill.Taylor@Sun.COM (mr->mr_bindinfo.bi_len - 1);
21699517SBill.Taylor@Sun.COM if ((vaddr < reg_start_addr) || (vaddr > reg_end_addr)) {
21709517SBill.Taylor@Sun.COM mutex_exit(&mr->mr_lock);
21719517SBill.Taylor@Sun.COM mutex_exit(&mw->mr_lock);
21729517SBill.Taylor@Sun.COM return (IBT_MR_VA_INVALID);
21739517SBill.Taylor@Sun.COM }
21749517SBill.Taylor@Sun.COM vaddr = (vaddr + len) - 1;
21759517SBill.Taylor@Sun.COM if (vaddr > reg_end_addr) {
21769517SBill.Taylor@Sun.COM mutex_exit(&mr->mr_lock);
21779517SBill.Taylor@Sun.COM mutex_exit(&mw->mr_lock);
21789517SBill.Taylor@Sun.COM return (IBT_MR_LEN_INVALID);
21799517SBill.Taylor@Sun.COM }
21809517SBill.Taylor@Sun.COM }
21819517SBill.Taylor@Sun.COM
21829517SBill.Taylor@Sun.COM /*
21839517SBill.Taylor@Sun.COM * Validate the bind access flags. Remote Write and Atomic access for
21849517SBill.Taylor@Sun.COM * the Memory Window require that Local Write access be set in the
21859517SBill.Taylor@Sun.COM * corresponding Memory Region.
21869517SBill.Taylor@Sun.COM */
21879517SBill.Taylor@Sun.COM bind_flags = wr->wr.rc.rcwr.bind->bind_flags;
21889517SBill.Taylor@Sun.COM if (((bind_flags & IBT_WR_BIND_WRITE) ||
21899517SBill.Taylor@Sun.COM (bind_flags & IBT_WR_BIND_ATOMIC)) &&
21909517SBill.Taylor@Sun.COM !(mr->mr_accflag & IBT_MR_LOCAL_WRITE)) {
21919517SBill.Taylor@Sun.COM mutex_exit(&mr->mr_lock);
21929517SBill.Taylor@Sun.COM mutex_exit(&mw->mr_lock);
21939517SBill.Taylor@Sun.COM return (IBT_MR_ACCESS_REQ_INVALID);
21949517SBill.Taylor@Sun.COM }
21959517SBill.Taylor@Sun.COM
21969517SBill.Taylor@Sun.COM /* Calculate the new RKey for the Memory Window */
21979517SBill.Taylor@Sun.COM mpt = mw->mr_mptrsrcp;
21989517SBill.Taylor@Sun.COM new_rkey = hermon_mr_keycalc(mpt->hr_indx);
21999517SBill.Taylor@Sun.COM new_rkey = hermon_mr_key_swap(new_rkey);
22009517SBill.Taylor@Sun.COM
22019517SBill.Taylor@Sun.COM wr->wr.rc.rcwr.bind->bind_rkey_out = new_rkey;
22029517SBill.Taylor@Sun.COM mw->mr_rkey = new_rkey;
22039517SBill.Taylor@Sun.COM
22049517SBill.Taylor@Sun.COM mutex_exit(&mr->mr_lock);
22059517SBill.Taylor@Sun.COM mutex_exit(&mw->mr_lock);
22069517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
22079517SBill.Taylor@Sun.COM }
22089517SBill.Taylor@Sun.COM
22099517SBill.Taylor@Sun.COM
22109517SBill.Taylor@Sun.COM /*
22119517SBill.Taylor@Sun.COM * hermon_wrid_from_reset_handling()
22129517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
22139517SBill.Taylor@Sun.COM */
22149517SBill.Taylor@Sun.COM /* ARGSUSED */
22159517SBill.Taylor@Sun.COM int
hermon_wrid_from_reset_handling(hermon_state_t * state,hermon_qphdl_t qp)22169517SBill.Taylor@Sun.COM hermon_wrid_from_reset_handling(hermon_state_t *state, hermon_qphdl_t qp)
22179517SBill.Taylor@Sun.COM {
22189517SBill.Taylor@Sun.COM hermon_workq_hdr_t *swq, *rwq;
22199517SBill.Taylor@Sun.COM
2220*12965SWilliam.Taylor@Oracle.COM if (qp->qp_alloc_flags & IBT_QP_USER_MAP)
22219517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
22229517SBill.Taylor@Sun.COM
2223*12965SWilliam.Taylor@Oracle.COM #ifdef __lock_lint
22249517SBill.Taylor@Sun.COM mutex_enter(&qp->qp_rq_cqhdl->cq_lock);
22259517SBill.Taylor@Sun.COM mutex_enter(&qp->qp_sq_cqhdl->cq_lock);
22269517SBill.Taylor@Sun.COM #else
2227*12965SWilliam.Taylor@Oracle.COM /* grab the cq lock(s) to modify the wqavl tree */
2228*12965SWilliam.Taylor@Oracle.COM if (qp->qp_rq_cqhdl)
2229*12965SWilliam.Taylor@Oracle.COM mutex_enter(&qp->qp_rq_cqhdl->cq_lock);
2230*12965SWilliam.Taylor@Oracle.COM if (qp->qp_rq_cqhdl != qp->qp_sq_cqhdl &&
2231*12965SWilliam.Taylor@Oracle.COM qp->qp_sq_cqhdl != NULL)
22329517SBill.Taylor@Sun.COM mutex_enter(&qp->qp_sq_cqhdl->cq_lock);
22339517SBill.Taylor@Sun.COM #endif
22349517SBill.Taylor@Sun.COM
22359517SBill.Taylor@Sun.COM /* Chain the newly allocated work queue header to the CQ's list */
2236*12965SWilliam.Taylor@Oracle.COM if (qp->qp_sq_cqhdl)
2237*12965SWilliam.Taylor@Oracle.COM hermon_cq_workq_add(qp->qp_sq_cqhdl, &qp->qp_sq_wqavl);
22389517SBill.Taylor@Sun.COM
22399517SBill.Taylor@Sun.COM swq = qp->qp_sq_wqhdr;
22409517SBill.Taylor@Sun.COM swq->wq_head = 0;
22419517SBill.Taylor@Sun.COM swq->wq_tail = 0;
22429517SBill.Taylor@Sun.COM swq->wq_full = 0;
22439517SBill.Taylor@Sun.COM
22449517SBill.Taylor@Sun.COM /*
22459517SBill.Taylor@Sun.COM * Now we repeat all the above operations for the receive work queue,
22469517SBill.Taylor@Sun.COM * or shared receive work queue.
22479517SBill.Taylor@Sun.COM *
22489517SBill.Taylor@Sun.COM * Note: We still use the 'qp_rq_cqhdl' even in the SRQ case.
22499517SBill.Taylor@Sun.COM */
22509517SBill.Taylor@Sun.COM
22519517SBill.Taylor@Sun.COM #ifdef __lock_lint
22529517SBill.Taylor@Sun.COM mutex_enter(&qp->qp_srqhdl->srq_lock);
22539517SBill.Taylor@Sun.COM #else
2254*12965SWilliam.Taylor@Oracle.COM if (qp->qp_alloc_flags & IBT_QP_USES_SRQ) {
22559517SBill.Taylor@Sun.COM mutex_enter(&qp->qp_srqhdl->srq_lock);
22569517SBill.Taylor@Sun.COM } else {
22579517SBill.Taylor@Sun.COM rwq = qp->qp_rq_wqhdr;
22589517SBill.Taylor@Sun.COM rwq->wq_head = 0;
22599517SBill.Taylor@Sun.COM rwq->wq_tail = 0;
22609517SBill.Taylor@Sun.COM rwq->wq_full = 0;
22619517SBill.Taylor@Sun.COM qp->qp_rq_wqecntr = 0;
22629517SBill.Taylor@Sun.COM }
22639517SBill.Taylor@Sun.COM #endif
22649517SBill.Taylor@Sun.COM hermon_cq_workq_add(qp->qp_rq_cqhdl, &qp->qp_rq_wqavl);
22659517SBill.Taylor@Sun.COM
22669517SBill.Taylor@Sun.COM #ifdef __lock_lint
22679517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_srqhdl->srq_lock);
22689517SBill.Taylor@Sun.COM #else
2269*12965SWilliam.Taylor@Oracle.COM if (qp->qp_alloc_flags & IBT_QP_USES_SRQ) {
22709517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_srqhdl->srq_lock);
22719517SBill.Taylor@Sun.COM }
22729517SBill.Taylor@Sun.COM #endif
22739517SBill.Taylor@Sun.COM
22749517SBill.Taylor@Sun.COM #ifdef __lock_lint
22759517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_sq_cqhdl->cq_lock);
2276*12965SWilliam.Taylor@Oracle.COM mutex_exit(&qp->qp_rq_cqhdl->cq_lock);
22779517SBill.Taylor@Sun.COM #else
2278*12965SWilliam.Taylor@Oracle.COM if (qp->qp_rq_cqhdl != qp->qp_sq_cqhdl &&
2279*12965SWilliam.Taylor@Oracle.COM qp->qp_sq_cqhdl != NULL)
22809517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_sq_cqhdl->cq_lock);
2281*12965SWilliam.Taylor@Oracle.COM if (qp->qp_rq_cqhdl)
2282*12965SWilliam.Taylor@Oracle.COM mutex_exit(&qp->qp_rq_cqhdl->cq_lock);
22839517SBill.Taylor@Sun.COM #endif
22849517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
22859517SBill.Taylor@Sun.COM }
22869517SBill.Taylor@Sun.COM
22879517SBill.Taylor@Sun.COM
22889517SBill.Taylor@Sun.COM /*
22899517SBill.Taylor@Sun.COM * hermon_wrid_to_reset_handling()
22909517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
22919517SBill.Taylor@Sun.COM */
22929517SBill.Taylor@Sun.COM int
hermon_wrid_to_reset_handling(hermon_state_t * state,hermon_qphdl_t qp)22939517SBill.Taylor@Sun.COM hermon_wrid_to_reset_handling(hermon_state_t *state, hermon_qphdl_t qp)
22949517SBill.Taylor@Sun.COM {
2295*12965SWilliam.Taylor@Oracle.COM if (qp->qp_alloc_flags & IBT_QP_USER_MAP)
22969517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
22979517SBill.Taylor@Sun.COM
22989517SBill.Taylor@Sun.COM /*
22999517SBill.Taylor@Sun.COM * If there are unpolled entries in these CQs, they are
23009517SBill.Taylor@Sun.COM * polled/flushed.
23019517SBill.Taylor@Sun.COM * Grab the CQ lock(s) before manipulating the lists.
23029517SBill.Taylor@Sun.COM */
2303*12965SWilliam.Taylor@Oracle.COM #ifdef __lock_lint
23049517SBill.Taylor@Sun.COM mutex_enter(&qp->qp_rq_cqhdl->cq_lock);
23059517SBill.Taylor@Sun.COM mutex_enter(&qp->qp_sq_cqhdl->cq_lock);
23069517SBill.Taylor@Sun.COM #else
2307*12965SWilliam.Taylor@Oracle.COM /* grab the cq lock(s) to modify the wqavl tree */
2308*12965SWilliam.Taylor@Oracle.COM if (qp->qp_rq_cqhdl)
2309*12965SWilliam.Taylor@Oracle.COM mutex_enter(&qp->qp_rq_cqhdl->cq_lock);
2310*12965SWilliam.Taylor@Oracle.COM if (qp->qp_rq_cqhdl != qp->qp_sq_cqhdl &&
2311*12965SWilliam.Taylor@Oracle.COM qp->qp_sq_cqhdl != NULL)
23129517SBill.Taylor@Sun.COM mutex_enter(&qp->qp_sq_cqhdl->cq_lock);
23139517SBill.Taylor@Sun.COM #endif
23149517SBill.Taylor@Sun.COM
23159517SBill.Taylor@Sun.COM #ifdef __lock_lint
23169517SBill.Taylor@Sun.COM mutex_enter(&qp->qp_srqhdl->srq_lock);
23179517SBill.Taylor@Sun.COM #else
2318*12965SWilliam.Taylor@Oracle.COM if (qp->qp_alloc_flags & IBT_QP_USES_SRQ) {
23199517SBill.Taylor@Sun.COM mutex_enter(&qp->qp_srqhdl->srq_lock);
23209517SBill.Taylor@Sun.COM }
23219517SBill.Taylor@Sun.COM #endif
23229517SBill.Taylor@Sun.COM /*
23239517SBill.Taylor@Sun.COM * Flush the entries on the CQ for this QP's QPN.
23249517SBill.Taylor@Sun.COM */
23259517SBill.Taylor@Sun.COM hermon_cq_entries_flush(state, qp);
23269517SBill.Taylor@Sun.COM
23279517SBill.Taylor@Sun.COM #ifdef __lock_lint
23289517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_srqhdl->srq_lock);
23299517SBill.Taylor@Sun.COM #else
2330*12965SWilliam.Taylor@Oracle.COM if (qp->qp_alloc_flags & IBT_QP_USES_SRQ) {
23319517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_srqhdl->srq_lock);
23329517SBill.Taylor@Sun.COM }
23339517SBill.Taylor@Sun.COM #endif
23349517SBill.Taylor@Sun.COM
23359517SBill.Taylor@Sun.COM hermon_cq_workq_remove(qp->qp_rq_cqhdl, &qp->qp_rq_wqavl);
2336*12965SWilliam.Taylor@Oracle.COM if (qp->qp_sq_cqhdl != NULL)
2337*12965SWilliam.Taylor@Oracle.COM hermon_cq_workq_remove(qp->qp_sq_cqhdl, &qp->qp_sq_wqavl);
23389517SBill.Taylor@Sun.COM
23399517SBill.Taylor@Sun.COM #ifdef __lock_lint
23409517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_sq_cqhdl->cq_lock);
2341*12965SWilliam.Taylor@Oracle.COM mutex_exit(&qp->qp_rq_cqhdl->cq_lock);
23429517SBill.Taylor@Sun.COM #else
2343*12965SWilliam.Taylor@Oracle.COM if (qp->qp_rq_cqhdl != qp->qp_sq_cqhdl &&
2344*12965SWilliam.Taylor@Oracle.COM qp->qp_sq_cqhdl != NULL)
23459517SBill.Taylor@Sun.COM mutex_exit(&qp->qp_sq_cqhdl->cq_lock);
2346*12965SWilliam.Taylor@Oracle.COM if (qp->qp_rq_cqhdl)
2347*12965SWilliam.Taylor@Oracle.COM mutex_exit(&qp->qp_rq_cqhdl->cq_lock);
23489517SBill.Taylor@Sun.COM #endif
23499517SBill.Taylor@Sun.COM
23509517SBill.Taylor@Sun.COM return (IBT_SUCCESS);
23519517SBill.Taylor@Sun.COM }
23529517SBill.Taylor@Sun.COM
23539517SBill.Taylor@Sun.COM
23549517SBill.Taylor@Sun.COM /*
23559517SBill.Taylor@Sun.COM * hermon_wrid_get_entry()
23569517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
23579517SBill.Taylor@Sun.COM */
23589517SBill.Taylor@Sun.COM uint64_t
hermon_wrid_get_entry(hermon_cqhdl_t cq,hermon_hw_cqe_t * cqe)23599517SBill.Taylor@Sun.COM hermon_wrid_get_entry(hermon_cqhdl_t cq, hermon_hw_cqe_t *cqe)
23609517SBill.Taylor@Sun.COM {
23619517SBill.Taylor@Sun.COM hermon_workq_avl_t *wqa;
23629517SBill.Taylor@Sun.COM hermon_workq_hdr_t *wq;
23639517SBill.Taylor@Sun.COM uint64_t wrid;
23649517SBill.Taylor@Sun.COM uint_t send_or_recv, qpnum;
23659517SBill.Taylor@Sun.COM uint32_t indx;
23669517SBill.Taylor@Sun.COM
23679517SBill.Taylor@Sun.COM /*
23689517SBill.Taylor@Sun.COM * Determine whether this CQE is a send or receive completion.
23699517SBill.Taylor@Sun.COM */
23709517SBill.Taylor@Sun.COM send_or_recv = HERMON_CQE_SENDRECV_GET(cq, cqe);
23719517SBill.Taylor@Sun.COM
23729517SBill.Taylor@Sun.COM /* Find the work queue for this QP number (send or receive side) */
23739517SBill.Taylor@Sun.COM qpnum = HERMON_CQE_QPNUM_GET(cq, cqe);
23749517SBill.Taylor@Sun.COM wqa = hermon_wrid_wqavl_find(cq, qpnum, send_or_recv);
23759517SBill.Taylor@Sun.COM wq = wqa->wqa_wq;
23769517SBill.Taylor@Sun.COM
23779517SBill.Taylor@Sun.COM /*
23789517SBill.Taylor@Sun.COM * Regardless of whether the completion is the result of a "success"
23799517SBill.Taylor@Sun.COM * or a "failure", we lock the list of "containers" and attempt to
23809517SBill.Taylor@Sun.COM * search for the the first matching completion (i.e. the first WR
23819517SBill.Taylor@Sun.COM * with a matching WQE addr and size). Once we find it, we pull out
23829517SBill.Taylor@Sun.COM * the "wrid" field and return it (see below). XXX Note: One possible
23839517SBill.Taylor@Sun.COM * future enhancement would be to enable this routine to skip over
23849517SBill.Taylor@Sun.COM * any "unsignaled" completions to go directly to the next "signaled"
23859517SBill.Taylor@Sun.COM * entry on success.
23869517SBill.Taylor@Sun.COM */
23879517SBill.Taylor@Sun.COM indx = HERMON_CQE_WQEADDRSZ_GET(cq, cqe) & wq->wq_mask;
23889517SBill.Taylor@Sun.COM wrid = wq->wq_wrid[indx];
23899517SBill.Taylor@Sun.COM if (wqa->wqa_srq_en) {
23909517SBill.Taylor@Sun.COM struct hermon_sw_srq_s *srq;
23919517SBill.Taylor@Sun.COM uint64_t *desc;
23929517SBill.Taylor@Sun.COM
23939517SBill.Taylor@Sun.COM /* put wqe back on the srq free list */
23949517SBill.Taylor@Sun.COM srq = wqa->wqa_srq;
23959517SBill.Taylor@Sun.COM mutex_enter(&srq->srq_lock);
23969517SBill.Taylor@Sun.COM desc = HERMON_SRQ_WQE_ADDR(srq, wq->wq_tail);
23979517SBill.Taylor@Sun.COM ((uint16_t *)desc)[1] = htons(indx);
23989517SBill.Taylor@Sun.COM wq->wq_tail = indx;
23999517SBill.Taylor@Sun.COM mutex_exit(&srq->srq_lock);
24009517SBill.Taylor@Sun.COM } else {
24019517SBill.Taylor@Sun.COM wq->wq_head = (indx + 1) & wq->wq_mask;
24029517SBill.Taylor@Sun.COM wq->wq_full = 0;
24039517SBill.Taylor@Sun.COM }
24049517SBill.Taylor@Sun.COM
24059517SBill.Taylor@Sun.COM return (wrid);
24069517SBill.Taylor@Sun.COM }
24079517SBill.Taylor@Sun.COM
24089517SBill.Taylor@Sun.COM
24099517SBill.Taylor@Sun.COM int
hermon_wrid_workq_compare(const void * p1,const void * p2)24109517SBill.Taylor@Sun.COM hermon_wrid_workq_compare(const void *p1, const void *p2)
24119517SBill.Taylor@Sun.COM {
24129517SBill.Taylor@Sun.COM hermon_workq_compare_t *cmpp;
24139517SBill.Taylor@Sun.COM hermon_workq_avl_t *curr;
24149517SBill.Taylor@Sun.COM
24159517SBill.Taylor@Sun.COM cmpp = (hermon_workq_compare_t *)p1;
24169517SBill.Taylor@Sun.COM curr = (hermon_workq_avl_t *)p2;
24179517SBill.Taylor@Sun.COM
24189517SBill.Taylor@Sun.COM if (cmpp->cmp_qpn < curr->wqa_qpn)
24199517SBill.Taylor@Sun.COM return (-1);
24209517SBill.Taylor@Sun.COM else if (cmpp->cmp_qpn > curr->wqa_qpn)
24219517SBill.Taylor@Sun.COM return (+1);
24229517SBill.Taylor@Sun.COM else if (cmpp->cmp_type < curr->wqa_type)
24239517SBill.Taylor@Sun.COM return (-1);
24249517SBill.Taylor@Sun.COM else if (cmpp->cmp_type > curr->wqa_type)
24259517SBill.Taylor@Sun.COM return (+1);
24269517SBill.Taylor@Sun.COM else
24279517SBill.Taylor@Sun.COM return (0);
24289517SBill.Taylor@Sun.COM }
24299517SBill.Taylor@Sun.COM
24309517SBill.Taylor@Sun.COM
24319517SBill.Taylor@Sun.COM /*
24329517SBill.Taylor@Sun.COM * hermon_wrid_workq_find()
24339517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
24349517SBill.Taylor@Sun.COM */
24359517SBill.Taylor@Sun.COM static hermon_workq_avl_t *
hermon_wrid_wqavl_find(hermon_cqhdl_t cq,uint_t qpn,uint_t wq_type)24369517SBill.Taylor@Sun.COM hermon_wrid_wqavl_find(hermon_cqhdl_t cq, uint_t qpn, uint_t wq_type)
24379517SBill.Taylor@Sun.COM {
24389517SBill.Taylor@Sun.COM hermon_workq_avl_t *curr;
24399517SBill.Taylor@Sun.COM hermon_workq_compare_t cmp;
24409517SBill.Taylor@Sun.COM
24419517SBill.Taylor@Sun.COM /*
24429517SBill.Taylor@Sun.COM * Walk the CQ's work queue list, trying to find a send or recv queue
24439517SBill.Taylor@Sun.COM * with the same QP number. We do this even if we are going to later
24449517SBill.Taylor@Sun.COM * create a new entry because it helps us easily find the end of the
24459517SBill.Taylor@Sun.COM * list.
24469517SBill.Taylor@Sun.COM */
24479517SBill.Taylor@Sun.COM cmp.cmp_qpn = qpn;
24489517SBill.Taylor@Sun.COM cmp.cmp_type = wq_type;
24499517SBill.Taylor@Sun.COM #ifdef __lock_lint
24509517SBill.Taylor@Sun.COM hermon_wrid_workq_compare(NULL, NULL);
24519517SBill.Taylor@Sun.COM #endif
24529517SBill.Taylor@Sun.COM curr = avl_find(&cq->cq_wrid_wqhdr_avl_tree, &cmp, NULL);
24539517SBill.Taylor@Sun.COM
24549517SBill.Taylor@Sun.COM return (curr);
24559517SBill.Taylor@Sun.COM }
24569517SBill.Taylor@Sun.COM
24579517SBill.Taylor@Sun.COM
24589517SBill.Taylor@Sun.COM /*
24599517SBill.Taylor@Sun.COM * hermon_wrid_wqhdr_create()
24609517SBill.Taylor@Sun.COM * Context: Can be called from base context.
24619517SBill.Taylor@Sun.COM */
24629517SBill.Taylor@Sun.COM /* ARGSUSED */
24639517SBill.Taylor@Sun.COM hermon_workq_hdr_t *
hermon_wrid_wqhdr_create(int bufsz)24649517SBill.Taylor@Sun.COM hermon_wrid_wqhdr_create(int bufsz)
24659517SBill.Taylor@Sun.COM {
24669517SBill.Taylor@Sun.COM hermon_workq_hdr_t *wqhdr;
24679517SBill.Taylor@Sun.COM
24689517SBill.Taylor@Sun.COM /*
24699517SBill.Taylor@Sun.COM * Allocate space for the wqhdr, and an array to record all the wrids.
24709517SBill.Taylor@Sun.COM */
24719517SBill.Taylor@Sun.COM wqhdr = (hermon_workq_hdr_t *)kmem_zalloc(sizeof (*wqhdr), KM_NOSLEEP);
24729517SBill.Taylor@Sun.COM if (wqhdr == NULL) {
24739517SBill.Taylor@Sun.COM return (NULL);
24749517SBill.Taylor@Sun.COM }
24759517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wqhdr))
24769517SBill.Taylor@Sun.COM wqhdr->wq_wrid = kmem_zalloc(bufsz * sizeof (uint64_t), KM_NOSLEEP);
24779517SBill.Taylor@Sun.COM if (wqhdr->wq_wrid == NULL) {
24789517SBill.Taylor@Sun.COM kmem_free(wqhdr, sizeof (*wqhdr));
24799517SBill.Taylor@Sun.COM return (NULL);
24809517SBill.Taylor@Sun.COM }
24819517SBill.Taylor@Sun.COM wqhdr->wq_size = bufsz;
24829517SBill.Taylor@Sun.COM wqhdr->wq_mask = bufsz - 1;
24839517SBill.Taylor@Sun.COM
24849517SBill.Taylor@Sun.COM return (wqhdr);
24859517SBill.Taylor@Sun.COM }
24869517SBill.Taylor@Sun.COM
24879517SBill.Taylor@Sun.COM void
hermon_wrid_wqhdr_destroy(hermon_workq_hdr_t * wqhdr)24889517SBill.Taylor@Sun.COM hermon_wrid_wqhdr_destroy(hermon_workq_hdr_t *wqhdr)
24899517SBill.Taylor@Sun.COM {
24909517SBill.Taylor@Sun.COM kmem_free(wqhdr->wq_wrid, wqhdr->wq_size * sizeof (uint64_t));
24919517SBill.Taylor@Sun.COM kmem_free(wqhdr, sizeof (*wqhdr));
24929517SBill.Taylor@Sun.COM }
24939517SBill.Taylor@Sun.COM
24949517SBill.Taylor@Sun.COM
24959517SBill.Taylor@Sun.COM /*
24969517SBill.Taylor@Sun.COM * hermon_cq_workq_add()
24979517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
24989517SBill.Taylor@Sun.COM */
24999517SBill.Taylor@Sun.COM static void
hermon_cq_workq_add(hermon_cqhdl_t cq,hermon_workq_avl_t * wqavl)25009517SBill.Taylor@Sun.COM hermon_cq_workq_add(hermon_cqhdl_t cq, hermon_workq_avl_t *wqavl)
25019517SBill.Taylor@Sun.COM {
25029517SBill.Taylor@Sun.COM hermon_workq_compare_t cmp;
25039517SBill.Taylor@Sun.COM avl_index_t where;
25049517SBill.Taylor@Sun.COM
25059517SBill.Taylor@Sun.COM cmp.cmp_qpn = wqavl->wqa_qpn;
25069517SBill.Taylor@Sun.COM cmp.cmp_type = wqavl->wqa_type;
25079517SBill.Taylor@Sun.COM #ifdef __lock_lint
25089517SBill.Taylor@Sun.COM hermon_wrid_workq_compare(NULL, NULL);
25099517SBill.Taylor@Sun.COM #endif
25109517SBill.Taylor@Sun.COM (void) avl_find(&cq->cq_wrid_wqhdr_avl_tree, &cmp, &where);
25119517SBill.Taylor@Sun.COM avl_insert(&cq->cq_wrid_wqhdr_avl_tree, wqavl, where);
25129517SBill.Taylor@Sun.COM }
25139517SBill.Taylor@Sun.COM
25149517SBill.Taylor@Sun.COM
25159517SBill.Taylor@Sun.COM /*
25169517SBill.Taylor@Sun.COM * hermon_cq_workq_remove()
25179517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
25189517SBill.Taylor@Sun.COM */
25199517SBill.Taylor@Sun.COM static void
hermon_cq_workq_remove(hermon_cqhdl_t cq,hermon_workq_avl_t * wqavl)25209517SBill.Taylor@Sun.COM hermon_cq_workq_remove(hermon_cqhdl_t cq, hermon_workq_avl_t *wqavl)
25219517SBill.Taylor@Sun.COM {
25229517SBill.Taylor@Sun.COM #ifdef __lock_lint
25239517SBill.Taylor@Sun.COM hermon_wrid_workq_compare(NULL, NULL);
25249517SBill.Taylor@Sun.COM #endif
25259517SBill.Taylor@Sun.COM avl_remove(&cq->cq_wrid_wqhdr_avl_tree, wqavl);
25269517SBill.Taylor@Sun.COM }
2527