lib/iscsi: Separate PDU header and payload handing for SCSI Data-Out

To use zero copy bdev I/O APIs, we have to allocate iSCSI task
before allocating data buffer.

Hence we separate PDU header and payload handling for SCSI Data-Out,
and include iSCSI task allocation into PDU header handling.

Factor out PDU header handling in iscsi_op_data() into iscsi_pdu_hdr_op_data().
spdk_nvmf_tcp_h2c_data_hdr_handle() and spdk_nvmf_tcp_h2c_data_payload_handle()
in lib/nvmf/tcp.c are used as a reference implementation.

Use pdu->task to pass the task allocated by iscsi_pdu_hdr_op_data() into
iscsi_op_data().

In iscsi_op_data(), if it sees pdu->is_rejected is true or pdu->task
is NULL, do nothing. Besides, check LUN hot plug again to separate
PDU header handling and PDU payload handling.

Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Change-Id: I5074e945254081960744577e4ed8e0170793e5e0
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/470291
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Community-CI: Broadcom SPDK FC-NVMe CI <spdk-ci.pdl@broadcom.com>
This commit is contained in:
Shuhei Matsumoto 2019-10-03 16:06:09 +09:00 committed by Jim Harris
parent 6e7473f724
commit 50bd0364d6

View File

@ -4392,18 +4392,15 @@ iscsi_pdu_hdr_op_snack(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
}
static int
iscsi_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
iscsi_pdu_hdr_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
{
struct spdk_iscsi_task *task, *subtask;
struct iscsi_bhs_data_out *reqh;
struct spdk_scsi_lun *lun_dev;
uint32_t transfer_tag;
uint32_t task_tag;
uint32_t transfer_len;
uint32_t DataSN;
uint32_t buffer_offset;
uint32_t len;
int F_bit;
int rc;
int reject_reason = ISCSI_REASON_INVALID_PDU_FIELD;
@ -4412,18 +4409,17 @@ iscsi_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
return SPDK_ISCSI_CONNECTION_FATAL;
}
if (pdu->data_segment_len > SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH) {
reject_reason = ISCSI_REASON_PROTOCOL_ERROR;
goto reject_return;
}
reqh = (struct iscsi_bhs_data_out *)&pdu->bhs;
F_bit = !!(reqh->flags & ISCSI_FLAG_FINAL);
transfer_tag = from_be32(&reqh->ttt);
task_tag = from_be32(&reqh->itt);
DataSN = from_be32(&reqh->data_sn);
buffer_offset = from_be32(&reqh->buffer_offset);
if (pdu->data_segment_len > SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH) {
reject_reason = ISCSI_REASON_PROTOCOL_ERROR;
goto reject_return;
}
task = get_transfer_task(conn, transfer_tag);
if (task == NULL) {
SPDK_ERRLOG("Not found task for transfer_tag=%x\n", transfer_tag);
@ -4458,26 +4454,13 @@ iscsi_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
return SPDK_ISCSI_CONNECTION_FATAL;
}
transfer_len = task->scsi.transfer_len;
task->current_r2t_length += pdu->data_segment_len;
task->next_expected_r2t_offset += pdu->data_segment_len;
task->r2t_datasn++;
if (task->current_r2t_length > conn->sess->MaxBurstLength) {
SPDK_ERRLOG("R2T burst(%u) > MaxBurstLength(%u)\n",
task->current_r2t_length,
if (task->current_r2t_length + pdu->data_segment_len > conn->sess->MaxBurstLength) {
SPDK_ERRLOG("R2T burst(%zu) > MaxBurstLength(%u)\n",
task->current_r2t_length + pdu->data_segment_len,
conn->sess->MaxBurstLength);
return SPDK_ISCSI_CONNECTION_FATAL;
}
if (F_bit) {
/*
* This R2T burst is done. Clear the length before we
* receive a PDU for the next R2T burst.
*/
task->current_r2t_length = 0;
}
subtask = spdk_iscsi_task_get(conn, task, spdk_iscsi_task_cpl);
if (subtask == NULL) {
SPDK_ERRLOG("Unable to acquire subtask\n");
@ -4485,12 +4468,70 @@ iscsi_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
}
subtask->scsi.offset = buffer_offset;
subtask->scsi.length = pdu->data_segment_len;
spdk_iscsi_task_associate_pdu(subtask, pdu);
if (lun_dev == NULL) {
SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "LUN %d is removed, complete the task immediately\n",
task->lun_id);
subtask->scsi.transfer_len = subtask->scsi.length;
spdk_scsi_task_process_null_lun(&subtask->scsi);
spdk_iscsi_task_cpl(&subtask->scsi);
return 0;
}
pdu->task = subtask;
return 0;
send_r2t_recovery_return:
rc = iscsi_send_r2t_recovery(conn, task, task->acked_r2tsn, true);
if (rc == 0) {
return 0;
}
reject_return:
return iscsi_reject(conn, pdu, reject_reason);
}
static int
iscsi_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
{
struct spdk_iscsi_task *task, *subtask;
struct iscsi_bhs_data_out *reqh;
uint32_t transfer_len;
uint32_t len;
int F_bit;
int rc;
rc = iscsi_pdu_hdr_op_data(conn, pdu);
if (rc != 0 || pdu->is_rejected || pdu->task == NULL) {
return rc;
}
subtask = pdu->task;
task = spdk_iscsi_task_get_primary(subtask);
assert(task != subtask);
reqh = (struct iscsi_bhs_data_out *)&pdu->bhs;
F_bit = !!(reqh->flags & ISCSI_FLAG_FINAL);
transfer_len = task->scsi.transfer_len;
task->current_r2t_length += pdu->data_segment_len;
task->next_expected_r2t_offset += pdu->data_segment_len;
task->r2t_datasn++;
if (F_bit) {
/*
* This R2T burst is done. Clear the length before we
* receive a PDU for the next R2T burst.
*/
task->current_r2t_length = 0;
}
if (spdk_likely(!pdu->dif_insert_or_strip)) {
spdk_scsi_task_set_data(&subtask->scsi, pdu->data, pdu->data_segment_len);
} else {
spdk_scsi_task_set_data(&subtask->scsi, pdu->data, pdu->data_buf_len);
}
spdk_iscsi_task_associate_pdu(subtask, pdu);
if (task->next_expected_r2t_offset == transfer_len) {
task->acked_r2tsn++;
@ -4506,7 +4547,7 @@ iscsi_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
task->next_r2t_offset += len;
}
if (lun_dev == NULL) {
if (spdk_scsi_dev_get_lun(conn->dev, task->lun_id) == NULL) {
SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "LUN %d is removed, complete the task immediately\n",
task->lun_id);
subtask->scsi.transfer_len = subtask->scsi.length;
@ -4517,15 +4558,6 @@ iscsi_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
iscsi_queue_task(conn, subtask);
return 0;
send_r2t_recovery_return:
rc = iscsi_send_r2t_recovery(conn, task, task->acked_r2tsn, true);
if (rc == 0) {
return 0;
}
reject_return:
return iscsi_reject(conn, pdu, reject_reason);
}
static void