[PATCH RFC 1/3] IB/iser: Post header-only PDUs inline

From: Andrei-Alexandru Bleortu

Date: Thu Oct 15 2026 - 09:06:01 EST


iser_post_send() posts every PDU by reference, and the QP asks for no
inline data. Before the HCA can send a SCSI command it therefore has
to DMA-read the 76 bytes of iSER and iSCSI headers from host memory,
and that read is on the latency path of every command.

Ask for ISER_HEADERS_LEN bytes of inline data when creating the QP,
and create the QP without inline data if the device refuses. Post a
PDU without a data segment with IB_SEND_INLINE when it fits in the
inline size the device granted. PDUs with a data segment are posted
by reference as before.

Providers copy inline data from sg_list[].addr as a kernel virtual
address. The inline path therefore points tx_sg[0] at the headers'
virtual address, and the by-reference path now sets it to the DMA
address on every post. The mapping is still synced and unmapped through
tx_desc->dma_addr.

Assisted-by: LLM
Signed-off-by: Andrei-Alexandru Bleortu <me@xxxxxxxxxxxx>
---
drivers/infiniband/ulp/iser/iscsi_iser.h | 2 ++
drivers/infiniband/ulp/iser/iser_verbs.c | 29 ++++++++++++++++++++++--
2 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 1d7ac24c4c00..ebd994d425a3 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -362,6 +362,7 @@ struct iser_fr_pool {
* @device: reference to iser device
* @fr_pool: connection fast registration pool
* @pi_support: Indicate device T10-PI support
+ * @max_inline_data: inline data size granted to the QP
* @reg_cqe: completion handler
*/
struct ib_conn {
@@ -372,6 +373,7 @@ struct ib_conn {
struct iser_device *device;
struct iser_fr_pool fr_pool;
bool pi_support;
+ u32 max_inline_data;
struct ib_cqe reg_cqe;
};

diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index ab2a27d23478..6319d7fd17cf 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -230,7 +230,7 @@ static int iser_create_ib_conn_res(struct ib_conn *ib_conn)
struct iser_conn *iser_conn = to_iser_conn(ib_conn);
struct iser_device *device;
struct ib_device *ib_dev;
- struct ib_qp_init_attr init_attr;
+ struct ib_qp_init_attr init_attr, attr;
int ret = -ENOMEM;
unsigned int max_send_wr, cq_size;

@@ -271,11 +271,23 @@ static int iser_create_ib_conn_res(struct ib_conn *ib_conn)
init_attr.create_flags |= IB_QP_CREATE_INTEGRITY_EN;
iser_conn->max_cmds = ISER_GET_MAX_XMIT_CMDS(max_send_wr - 1);

- ret = rdma_create_qp(ib_conn->cma_id, device->pd, &init_attr);
+ /*
+ * Ask for enough inline data to post the iSER and iSCSI headers
+ * inline (see iser_post_send()). If the device cannot provide it,
+ * create the QP without inline data.
+ */
+ attr = init_attr;
+ attr.cap.max_inline_data = ISER_HEADERS_LEN;
+ ret = rdma_create_qp(ib_conn->cma_id, device->pd, &attr);
+ if (ret) {
+ attr = init_attr;
+ ret = rdma_create_qp(ib_conn->cma_id, device->pd, &attr);
+ }
if (ret)
goto out_err;

ib_conn->qp = ib_conn->cma_id->qp;
+ ib_conn->max_inline_data = attr.cap.max_inline_data;
iser_info("setting conn %p cma_id %p qp %p max_send_wr %d\n", ib_conn,
ib_conn->cma_id, ib_conn->cma_id->qp, max_send_wr);
return ret;
@@ -870,6 +882,19 @@ int iser_post_send(struct ib_conn *ib_conn, struct iser_tx_desc *tx_desc)
wr->opcode = IB_WR_SEND;
wr->send_flags = IB_SEND_SIGNALED;

+ /*
+ * Post a header-only PDU inline if it fits in the granted inline
+ * size, so the HCA does not have to DMA-read it from host memory.
+ * The CPU copies inline data from a kernel virtual address, so point
+ * the SGE at the headers.
+ */
+ tx_desc->tx_sg[0].addr = tx_desc->dma_addr;
+ if (tx_desc->num_sge == 1 &&
+ tx_desc->tx_sg[0].length <= ib_conn->max_inline_data) {
+ tx_desc->tx_sg[0].addr = (uintptr_t)&tx_desc->iser_header;
+ wr->send_flags |= IB_SEND_INLINE;
+ }
+
if (tx_desc->inv_wr.next)
first_wr = &tx_desc->inv_wr;
else if (tx_desc->reg_wr.wr.next)
--
2.56.0