svcrdma: Make RDMA_ERROR messages work
[deliverable/linux.git] / net / sunrpc / xprtrdma / svc_rdma_sendto.c
index ace9efa7aa6c2cee5b194d1762ae4bbc9368e107..a26ca569f257ac33ae4569f95186e3dcf313a047 100644 (file)
@@ -652,3 +652,65 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
        set_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags);
        return -ENOTCONN;
 }
+
+void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
+                        int status)
+{
+       struct ib_send_wr err_wr;
+       struct page *p;
+       struct svc_rdma_op_ctxt *ctxt;
+       enum rpcrdma_errcode err;
+       __be32 *va;
+       int length;
+       int ret;
+
+       ret = svc_rdma_repost_recv(xprt, GFP_KERNEL);
+       if (ret)
+               return;
+
+       p = alloc_page(GFP_KERNEL);
+       if (!p)
+               return;
+       va = page_address(p);
+
+       /* XDR encode an error reply */
+       err = ERR_CHUNK;
+       if (status == -EPROTONOSUPPORT)
+               err = ERR_VERS;
+       length = svc_rdma_xdr_encode_error(xprt, rmsgp, err, va);
+
+       ctxt = svc_rdma_get_context(xprt);
+       ctxt->direction = DMA_TO_DEVICE;
+       ctxt->count = 1;
+       ctxt->pages[0] = p;
+
+       /* Prepare SGE for local address */
+       ctxt->sge[0].lkey = xprt->sc_pd->local_dma_lkey;
+       ctxt->sge[0].length = length;
+       ctxt->sge[0].addr = ib_dma_map_page(xprt->sc_cm_id->device,
+                                           p, 0, length, DMA_TO_DEVICE);
+       if (ib_dma_mapping_error(xprt->sc_cm_id->device, ctxt->sge[0].addr)) {
+               dprintk("svcrdma: Error mapping buffer for protocol error\n");
+               svc_rdma_put_context(ctxt, 1);
+               return;
+       }
+       atomic_inc(&xprt->sc_dma_used);
+
+       /* Prepare SEND WR */
+       memset(&err_wr, 0, sizeof(err_wr));
+       ctxt->wr_op = IB_WR_SEND;
+       err_wr.wr_id = (unsigned long)ctxt;
+       err_wr.sg_list = ctxt->sge;
+       err_wr.num_sge = 1;
+       err_wr.opcode = IB_WR_SEND;
+       err_wr.send_flags = IB_SEND_SIGNALED;
+
+       /* Post It */
+       ret = svc_rdma_send(xprt, &err_wr);
+       if (ret) {
+               dprintk("svcrdma: Error %d posting send for protocol error\n",
+                       ret);
+               svc_rdma_unmap_dma(ctxt);
+               svc_rdma_put_context(ctxt, 1);
+       }
+}
This page took 0.024409 seconds and 5 git commands to generate.