xprtrdma: Support RPC/RDMA v2 reverse-direction replies

Adjust the backchannel ->send_request method to encode a v2 Reply
when the transport has negotiated RPC/RDMA protocol version two.

The backchannel Call handler does not look at the transport header,
so it is already prepared for handling reverse-direction
rdma2_call_inline header types.

This commit gives us equivalent functionality as RPC/RDMA v1. The
_external/_middle header types are left unsupported for now.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
diff --git a/net/sunrpc/xprtrdma/backchannel.c b/net/sunrpc/xprtrdma/backchannel.c
index 224b88c..6377c53 100644
--- a/net/sunrpc/xprtrdma/backchannel.c
+++ b/net/sunrpc/xprtrdma/backchannel.c
@@ -57,10 +57,19 @@
 	return RPCRDMA_BACKWARD_WRS >> 1;
 }
 
-static int rpcrdma_bc_marshal_reply(struct rpc_rqst *rqst)
+/* For the moment, the send and receive grants are identical values */
+static __be32 rpcrdma2_encode_bc_credits(const struct rpcrdma_xprt *r_xprt)
 {
-	struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_xprt);
+	u32 grant = r_xprt->rx_buf.rb_bc_srv_max_requests & 0xffff;
+
+	return (__force __be32)((grant << 16) | grant);
+}
+
+static int rpcrdma_bc_marshal_reply(struct rpcrdma_xprt *r_xprt,
+				    struct rpc_rqst *rqst)
+{
 	struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
+	size_t msglen;
 	__be32 *p;
 
 	rpcrdma_set_xdrlen(&req->rl_hdrbuf, 0);
@@ -68,19 +77,36 @@
 			rdmab_data(req->rl_rdmabuf), rqst);
 	req->rl_rtype = rpcrdma_noch_pullup;
 
-	p = xdr_reserve_space(&req->rl_stream, 28);
-	if (unlikely(!p))
+	switch (r_xprt->rx_version) {
+	case RPCRDMA_VERSION_ONE:
+		msglen = RPCRDMA_HDRLEN_MIN;
+		p = xdr_reserve_space(&req->rl_stream, msglen);
+		if (!p)
+			return -EIO;
+		*p++ = rqst->rq_xid;
+		*p++ = rpcrdma_version_one;
+		*p++ = cpu_to_be32(r_xprt->rx_buf.rb_bc_srv_max_requests);
+		*p++ = rdma_msg;
+		*p++ = xdr_zero;
+		*p++ = xdr_zero;
+		*p = xdr_zero;
+		break;
+	case RPCRDMA_VERSION_TWO:
+		msglen = 5 * XDR_UNIT;
+		p = xdr_reserve_space(&req->rl_stream, msglen);
+		if (!p)
+			return -EIO;
+		*p++ = rqst->rq_xid;
+		*p++ = rpcrdma_version_two;
+		*p++ = rpcrdma2_encode_bc_credits(r_xprt);
+		*p++ = rdma2_reply_inline;
+		*p = xdr_zero;
+		break;
+	default:
 		return -EIO;
-	*p++ = rqst->rq_xid;
-	*p++ = rpcrdma_version_one;
-	*p++ = cpu_to_be32(r_xprt->rx_buf.rb_bc_srv_max_requests);
-	*p++ = rdma_msg;
-	*p++ = xdr_zero;
-	*p++ = xdr_zero;
-	*p = xdr_zero;
+	}
 
-	if (rpcrdma_prepare_send_sges(r_xprt, req, RPCRDMA_HDRLEN_MIN,
-				      &rqst->rq_snd_buf))
+	if (rpcrdma_prepare_send_sges(r_xprt, req, msglen, &rqst->rq_snd_buf))
 		return -EIO;
 
 	trace_xprtrdma_cb_reply(r_xprt, rqst);
@@ -112,7 +138,7 @@
 	if (!xprt_request_get_cong(xprt, rqst))
 		return -EBADSLT;
 
-	rc = rpcrdma_bc_marshal_reply(rqst);
+	rc = rpcrdma_bc_marshal_reply(r_xprt, rqst);
 	if (rc < 0)
 		goto failed_marshal;
 
@@ -216,6 +242,7 @@
  * @rep: receive buffer containing the call
  *
  * Operational assumptions:
+ *    o rep->rr_stream points to the XID field in the RPC Call header
  *    o Backchannel credits are ignored, just as the NFS server
  *      forechannel currently does
  *    o The ULP manages a replay cache (eg, NFSv4.1 sessions).