diff --git a/include/iser-private.h b/include/iser-private.h index ff38793..b943d34 100644 --- a/include/iser-private.h +++ b/include/iser-private.h @@ -18,6 +18,7 @@ #define __iser_private_h__ #include +#include #include #include "iscsi-private.h" @@ -118,15 +119,14 @@ struct iser_hdr { struct iser_rx_desc { struct iser_hdr iser_header; - char pad1[4]; char iscsi_header[ISCSI_RAW_HEADER_SIZE]; - char data[ISER_RECV_DATA_SEG_LEN]; - struct ibv_sge rx_sg; + char data[ISER_RECV_DATA_SEG_LEN]; + char pad[4]; struct ibv_mr *hdr_mr; - char pad2[24]; + struct ibv_sge rx_sg; }; -static_assert(sizeof(struct iser_rx_desc) == 256, "iser_rx_desc size != 256"); +static_assert(offsetof(struct iser_rx_desc, hdr_mr) % 8 == 0, "iser_rx_desc is not aligned on 8-byte boundary"); /** * struct iser_tx_desc - iSER TX descriptor (for send wr_id) @@ -158,7 +158,7 @@ struct iser_tx_desc { struct iser_cm_hdr { uint8_t flags; uint8_t rsvd[3]; -} __packed; +}; struct iser_pdu { struct iscsi_pdu iscsi_pdu; diff --git a/lib/iser.c b/lib/iser.c index 22e9a19..66f51a7 100644 --- a/lib/iser.c +++ b/lib/iser.c @@ -56,6 +56,7 @@ union socket_address { }; static int cq_handle(struct iser_conn *iser_conn); +static int iscsi_iser_revive_queued_pdus(struct iscsi_context *iscsi); /* * iscsi_iser_get_fd() - Return completion queue @@ -111,7 +112,7 @@ iscsi_iser_service(struct iscsi_context *iscsi, int revents) return -1; } - return 0; + return iscsi_iser_revive_queued_pdus(iscsi); } /* @@ -570,7 +571,8 @@ iser_prepare_write_cmd(struct iser_conn *iser_conn, struct iser_pdu *iser_pdu) struct iser_hdr *hdr = &iser_pdu->desc->iser_header; struct iscsi_context *iscsi = iser_conn->cma_id->context; struct iser_tx_desc *tx_desc = iser_pdu->desc; - struct scsi_iovector *iovector = iscsi_get_scsi_task_iovector_out(iscsi, &iser_pdu->iscsi_pdu); + struct iscsi_pdu *iscsi_pdu = &iser_pdu->iscsi_pdu; + struct scsi_iovector *iovector = iscsi_get_scsi_task_iovector_out(iscsi, iscsi_pdu); int i, offset = 0; if (iovector == NULL) { @@ -587,7 +589,20 @@ iser_prepare_write_cmd(struct iser_conn *iser_conn, struct iser_pdu *iser_pdu) hdr->flags |= ISER_WSV; hdr->write_stag = htobe32((uint32_t)(tx_desc->data_mr->rkey)); - hdr->write_va = htobe64((intptr_t)(tx_desc->data_buff)); + + // ImmediateData + if (iscsi_pdu->payload_len > 0) { + struct ibv_sge *tx_dsg = &tx_desc->tx_sg[1]; + + tx_dsg->addr = (uintptr_t)tx_desc->data_buff; + tx_dsg->length = iscsi_pdu->payload_len; + tx_dsg->lkey = tx_desc->data_mr->lkey; + tx_desc->num_sge = 2; + + hdr->write_va = htobe64((intptr_t)(tx_desc->data_buff + iscsi_pdu->payload_len)); + } else { + hdr->write_va = htobe64((intptr_t)(tx_desc->data_buff)); + } return 0; } @@ -677,29 +692,12 @@ iser_send_command(struct iser_conn *iser_conn, struct iser_pdu *iser_pdu) return 0; } - -/* - * iser_queue_pdu() - sending iscsi pdu - * - * @iscsi_context: iscsi context - * @iscsi_pdu: iscsi pdu - * - * Notes: - * Need to be compatible to TCP which has real queue, - * in iSER every queue pdu already sends all pdu (post_send) - */ static int -iscsi_iser_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { - +iscsi_iser_send_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { struct iser_pdu *iser_pdu; struct iser_conn *iser_conn = iscsi->opaque; uint8_t opcode; - if (pdu == NULL) { - iscsi_set_error(iscsi, "trying to queue NULL pdu"); - return -1; - } - iser_pdu = container_of(pdu, struct iser_pdu, iscsi_pdu); opcode = pdu->outdata.data[0]; @@ -717,7 +715,7 @@ iscsi_iser_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { return -1; } } else { - if (iser_send_command(iser_conn, iser_pdu)) { + if (iser_send_command(iser_conn, iser_pdu)) { iscsi_set_error(iscsi, "iser_send_command Failed\n"); return -1; } @@ -726,6 +724,56 @@ iscsi_iser_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { return 0; } +static int +iscsi_iser_revive_queued_pdus(struct iscsi_context *iscsi) { + struct iscsi_pdu *pdu; + + while (iscsi->outqueue != NULL) { + if (iscsi_serial32_compare(iscsi->outqueue->cmdsn, iscsi->maxcmdsn) > 0) { + break; + } + + pdu = iscsi->outqueue; + ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu); + + if (iscsi_iser_send_pdu(iscsi, pdu) < 0) { + ISCSI_LIST_ADD(&iscsi->outqueue, pdu); + return -1; + } + } + + return 0; +} + + +/* + * iser_queue_pdu() - sending iscsi pdu + * + * @iscsi_context: iscsi context + * @iscsi_pdu: iscsi pdu + * + * Notes: + * Need to be compatible to TCP which has real queue, + * in iSER pdus with cmdsn not exceeds maxcmdsn are already sent. + */ +static int +iscsi_iser_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { + if (pdu == NULL) { + iscsi_set_error(iscsi, "trying to queue NULL pdu"); + return -1; + } + + if (iscsi->outqueue != NULL || + (iscsi_serial32_compare(pdu->cmdsn, iscsi->maxcmdsn) > 0 + && !(pdu->outdata.data[0] & ISCSI_PDU_IMMEDIATE))) { + iscsi_add_to_outqueue(iscsi, pdu); + return 0; + } + + return iscsi_iser_send_pdu(iscsi, pdu); +} + + /* * iser_create_iser_conn_res() - creating ib connections resources *