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:
parent
6e7473f724
commit
50bd0364d6
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user