IB/core: Enhance ib_map_mr_sg()
[deliverable/linux.git] / net / sunrpc / xprtrdma / frwr_ops.c
index e16567389e28f5eba1359ddf91802d63c4612c26..94c3fa910b85e5e4a53109a2121dd9be51067c49 100644 (file)
@@ -109,20 +109,20 @@ static void
 __frwr_recovery_worker(struct work_struct *work)
 {
        struct rpcrdma_mw *r = container_of(work, struct rpcrdma_mw,
-                                           r.frmr.fr_work);
-       struct rpcrdma_xprt *r_xprt = r->r.frmr.fr_xprt;
+                                           frmr.fr_work);
+       struct rpcrdma_xprt *r_xprt = r->frmr.fr_xprt;
        unsigned int depth = r_xprt->rx_ia.ri_max_frmr_depth;
        struct ib_pd *pd = r_xprt->rx_ia.ri_pd;
 
-       if (ib_dereg_mr(r->r.frmr.fr_mr))
+       if (ib_dereg_mr(r->frmr.fr_mr))
                goto out_fail;
 
-       r->r.frmr.fr_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, depth);
-       if (IS_ERR(r->r.frmr.fr_mr))
+       r->frmr.fr_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, depth);
+       if (IS_ERR(r->frmr.fr_mr))
                goto out_fail;
 
        dprintk("RPC:       %s: recovered FRMR %p\n", __func__, r);
-       r->r.frmr.fr_state = FRMR_IS_INVALID;
+       r->frmr.fr_state = FRMR_IS_INVALID;
        rpcrdma_put_mw(r_xprt, r);
        return;
 
@@ -137,15 +137,15 @@ out_fail:
 static void
 __frwr_queue_recovery(struct rpcrdma_mw *r)
 {
-       INIT_WORK(&r->r.frmr.fr_work, __frwr_recovery_worker);
-       queue_work(frwr_recovery_wq, &r->r.frmr.fr_work);
+       INIT_WORK(&r->frmr.fr_work, __frwr_recovery_worker);
+       queue_work(frwr_recovery_wq, &r->frmr.fr_work);
 }
 
 static int
 __frwr_init(struct rpcrdma_mw *r, struct ib_pd *pd, struct ib_device *device,
            unsigned int depth)
 {
-       struct rpcrdma_frmr *f = &r->r.frmr;
+       struct rpcrdma_frmr *f = &r->frmr;
        int rc;
 
        f->fr_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, depth);
@@ -158,6 +158,8 @@ __frwr_init(struct rpcrdma_mw *r, struct ib_pd *pd, struct ib_device *device,
 
        sg_init_table(f->sg, depth);
 
+       init_completion(&f->fr_linv_done);
+
        return 0;
 
 out_mr_err:
@@ -179,11 +181,11 @@ __frwr_release(struct rpcrdma_mw *r)
 {
        int rc;
 
-       rc = ib_dereg_mr(r->r.frmr.fr_mr);
+       rc = ib_dereg_mr(r->frmr.fr_mr);
        if (rc)
                dprintk("RPC:       %s: ib_dereg_mr status %i\n",
                        __func__, rc);
-       kfree(r->r.frmr.sg);
+       kfree(r->frmr.sg);
 }
 
 static int
@@ -244,39 +246,76 @@ frwr_op_maxpages(struct rpcrdma_xprt *r_xprt)
                     rpcrdma_max_segments(r_xprt) * ia->ri_max_frmr_depth);
 }
 
-/* If FAST_REG or LOCAL_INV failed, indicate the frmr needs
- * to be reset.
+static void
+__frwr_sendcompletion_flush(struct ib_wc *wc, struct rpcrdma_frmr *frmr,
+                           const char *wr)
+{
+       frmr->fr_state = FRMR_IS_STALE;
+       if (wc->status != IB_WC_WR_FLUSH_ERR)
+               pr_err("rpcrdma: %s: %s (%u/0x%x)\n",
+                      wr, ib_wc_status_msg(wc->status),
+                      wc->status, wc->vendor_err);
+}
+
+/**
+ * frwr_wc_fastreg - Invoked by RDMA provider for each polled FastReg WC
+ * @cq:        completion queue (ignored)
+ * @wc:        completed WR
  *
- * WARNING: Only wr_id and status are reliable at this point
  */
 static void
-__frwr_sendcompletion_flush(struct ib_wc *wc, struct rpcrdma_mw *r)
+frwr_wc_fastreg(struct ib_cq *cq, struct ib_wc *wc)
 {
-       if (likely(wc->status == IB_WC_SUCCESS))
-               return;
-
-       /* WARNING: Only wr_id and status are reliable at this point */
-       r = (struct rpcrdma_mw *)(unsigned long)wc->wr_id;
-       if (wc->status == IB_WC_WR_FLUSH_ERR)
-               dprintk("RPC:       %s: frmr %p flushed\n", __func__, r);
-       else
-               pr_warn("RPC:       %s: frmr %p error, status %s (%d)\n",
-                       __func__, r, ib_wc_status_msg(wc->status), wc->status);
+       struct rpcrdma_frmr *frmr;
+       struct ib_cqe *cqe;
 
-       r->r.frmr.fr_state = FRMR_IS_STALE;
+       /* WARNING: Only wr_cqe and status are reliable at this point */
+       if (wc->status != IB_WC_SUCCESS) {
+               cqe = wc->wr_cqe;
+               frmr = container_of(cqe, struct rpcrdma_frmr, fr_cqe);
+               __frwr_sendcompletion_flush(wc, frmr, "fastreg");
+       }
 }
 
+/**
+ * frwr_wc_localinv - Invoked by RDMA provider for each polled LocalInv WC
+ * @cq:        completion queue (ignored)
+ * @wc:        completed WR
+ *
+ */
 static void
-frwr_sendcompletion(struct ib_wc *wc)
+frwr_wc_localinv(struct ib_cq *cq, struct ib_wc *wc)
 {
-       struct rpcrdma_mw *r = (struct rpcrdma_mw *)(unsigned long)wc->wr_id;
-       struct rpcrdma_frmr *f = &r->r.frmr;
+       struct rpcrdma_frmr *frmr;
+       struct ib_cqe *cqe;
 
-       if (unlikely(wc->status != IB_WC_SUCCESS))
-               __frwr_sendcompletion_flush(wc, r);
+       /* WARNING: Only wr_cqe and status are reliable at this point */
+       if (wc->status != IB_WC_SUCCESS) {
+               cqe = wc->wr_cqe;
+               frmr = container_of(cqe, struct rpcrdma_frmr, fr_cqe);
+               __frwr_sendcompletion_flush(wc, frmr, "localinv");
+       }
+}
 
-       if (f->fr_waiter)
-               complete(&f->fr_linv_done);
+/**
+ * frwr_wc_localinv - Invoked by RDMA provider for each polled LocalInv WC
+ * @cq:        completion queue (ignored)
+ * @wc:        completed WR
+ *
+ * Awaken anyone waiting for an MR to finish being fenced.
+ */
+static void
+frwr_wc_localinv_wake(struct ib_cq *cq, struct ib_wc *wc)
+{
+       struct rpcrdma_frmr *frmr;
+       struct ib_cqe *cqe;
+
+       /* WARNING: Only wr_cqe and status are reliable at this point */
+       cqe = wc->wr_cqe;
+       frmr = container_of(cqe, struct rpcrdma_frmr, fr_cqe);
+       if (wc->status != IB_WC_SUCCESS)
+               __frwr_sendcompletion_flush(wc, frmr, "localinv");
+       complete_all(&frmr->fr_linv_done);
 }
 
 static int
@@ -313,8 +352,7 @@ frwr_op_init(struct rpcrdma_xprt *r_xprt)
 
                list_add(&r->mw_list, &buf->rb_mws);
                list_add(&r->mw_all, &buf->rb_all);
-               r->mw_sendcompletion = frwr_sendcompletion;
-               r->r.frmr.fr_xprt = r_xprt;
+               r->frmr.fr_xprt = r_xprt;
        }
 
        return 0;
@@ -347,10 +385,9 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
                mw = rpcrdma_get_mw(r_xprt);
                if (!mw)
                        return -ENOMEM;
-       } while (mw->r.frmr.fr_state != FRMR_IS_INVALID);
-       frmr = &mw->r.frmr;
+       } while (mw->frmr.fr_state != FRMR_IS_INVALID);
+       frmr = &mw->frmr;
        frmr->fr_state = FRMR_IS_VALID;
-       frmr->fr_waiter = false;
        mr = frmr->fr_mr;
        reg_wr = &frmr->fr_regwr;
 
@@ -384,7 +421,7 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
                return -ENOMEM;
        }
 
-       n = ib_map_mr_sg(mr, frmr->sg, frmr->sg_nents, PAGE_SIZE);
+       n = ib_map_mr_sg(mr, frmr->sg, frmr->sg_nents, NULL, PAGE_SIZE);
        if (unlikely(n != frmr->sg_nents)) {
                pr_err("RPC:       %s: failed to map mr %p (%u/%u)\n",
                       __func__, frmr->fr_mr, n, frmr->sg_nents);
@@ -400,7 +437,8 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
 
        reg_wr->wr.next = NULL;
        reg_wr->wr.opcode = IB_WR_REG_MR;
-       reg_wr->wr.wr_id = (uintptr_t)mw;
+       frmr->fr_cqe.done = frwr_wc_fastreg;
+       reg_wr->wr.wr_cqe = &frmr->fr_cqe;
        reg_wr->wr.num_sge = 0;
        reg_wr->wr.send_flags = 0;
        reg_wr->mr = mr;
@@ -434,15 +472,15 @@ static struct ib_send_wr *
 __frwr_prepare_linv_wr(struct rpcrdma_mr_seg *seg)
 {
        struct rpcrdma_mw *mw = seg->rl_mw;
-       struct rpcrdma_frmr *f = &mw->r.frmr;
+       struct rpcrdma_frmr *f = &mw->frmr;
        struct ib_send_wr *invalidate_wr;
 
-       f->fr_waiter = false;
        f->fr_state = FRMR_IS_INVALID;
        invalidate_wr = &f->fr_invwr;
 
        memset(invalidate_wr, 0, sizeof(*invalidate_wr));
-       invalidate_wr->wr_id = (unsigned long)(void *)mw;
+       f->fr_cqe.done = frwr_wc_localinv;
+       invalidate_wr->wr_cqe = &f->fr_cqe;
        invalidate_wr->opcode = IB_WR_LOCAL_INV;
        invalidate_wr->ex.invalidate_rkey = f->fr_mr->rkey;
 
@@ -455,7 +493,7 @@ __frwr_dma_unmap(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg,
 {
        struct ib_device *device = r_xprt->rx_ia.ri_device;
        struct rpcrdma_mw *mw = seg->rl_mw;
-       struct rpcrdma_frmr *f = &mw->r.frmr;
+       struct rpcrdma_frmr *f = &mw->frmr;
 
        seg->rl_mw = NULL;
 
@@ -504,15 +542,15 @@ frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
 
                i += seg->mr_nsegs;
        }
-       f = &seg->rl_mw->r.frmr;
+       f = &seg->rl_mw->frmr;
 
        /* Strong send queue ordering guarantees that when the
         * last WR in the chain completes, all WRs in the chain
         * are complete.
         */
        f->fr_invwr.send_flags = IB_SEND_SIGNALED;
-       f->fr_waiter = true;
-       init_completion(&f->fr_linv_done);
+       f->fr_cqe.done = frwr_wc_localinv_wake;
+       reinit_completion(&f->fr_linv_done);
        INIT_CQCOUNT(&r_xprt->rx_ep);
 
        /* Transport disconnect drains the receive CQ before it
@@ -520,14 +558,18 @@ frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
         * unless ri_id->qp is a valid pointer.
         */
        rc = ib_post_send(ia->ri_id->qp, invalidate_wrs, &bad_wr);
-       if (rc)
+       if (rc) {
                pr_warn("%s: ib_post_send failed %i\n", __func__, rc);
+               rdma_disconnect(ia->ri_id);
+               goto unmap;
+       }
 
        wait_for_completion(&f->fr_linv_done);
 
        /* ORDER: Now DMA unmap all of the req's MRs, and return
         * them to the free MW list.
         */
+unmap:
        for (i = 0, nchunks = req->rl_nchunks; nchunks; nchunks--) {
                seg = &req->rl_segments[i];
 
@@ -549,7 +591,7 @@ frwr_op_unmap(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg)
        struct rpcrdma_mr_seg *seg1 = seg;
        struct rpcrdma_ia *ia = &r_xprt->rx_ia;
        struct rpcrdma_mw *mw = seg1->rl_mw;
-       struct rpcrdma_frmr *frmr = &mw->r.frmr;
+       struct rpcrdma_frmr *frmr = &mw->frmr;
        struct ib_send_wr *invalidate_wr, *bad_wr;
        int rc, nsegs = seg->mr_nsegs;
 
@@ -557,10 +599,11 @@ frwr_op_unmap(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg)
 
        seg1->rl_mw = NULL;
        frmr->fr_state = FRMR_IS_INVALID;
-       invalidate_wr = &mw->r.frmr.fr_invwr;
+       invalidate_wr = &mw->frmr.fr_invwr;
 
        memset(invalidate_wr, 0, sizeof(*invalidate_wr));
-       invalidate_wr->wr_id = (uintptr_t)mw;
+       frmr->fr_cqe.done = frwr_wc_localinv;
+       invalidate_wr->wr_cqe = &frmr->fr_cqe;
        invalidate_wr->opcode = IB_WR_LOCAL_INV;
        invalidate_wr->ex.invalidate_rkey = frmr->fr_mr->rkey;
        DECR_CQCOUNT(&r_xprt->rx_ep);
This page took 0.029902 seconds and 5 git commands to generate.