lib/iscsi: Send R2T in SCSI Data-Out PDU Header handling

Recent patches refactored iSCSI target to separate PDU header
and payload handling. However for SCSI Data-Out PDU, the division
of roles done by refactoring was wrong. Before refactoring, LUN
hotplug was checked after sending R2T, but after refactoring LUN
hotplug is checked before sending R2T. This change stopped PDU
exchange between iSCSI initiator and target and caused timeout of
LUN removal.

This patch restores the original ordering of checking LUN hotplug
and sending R2T by changing the division of roles.

SCSI Write Command PDU handling don't have any issue related with
this.

Fixes #1004

Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Change-Id: I7b2866d8394b522fb5420d2936de2fbddc7d1daa
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/472308
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Shuhei Matsumoto 2019-10-25 09:11:53 +09:00 committed by Tomasz Zawadzki
parent a4925ba744
commit 84f59335c2

View File

@ -4385,8 +4385,11 @@ iscsi_pdu_hdr_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
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;
@ -4396,6 +4399,7 @@ iscsi_pdu_hdr_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
}
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);
@ -4440,13 +4444,26 @@ iscsi_pdu_hdr_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
return SPDK_ISCSI_CONNECTION_FATAL;
}
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,
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,
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");
@ -4456,6 +4473,20 @@ iscsi_pdu_hdr_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
subtask->scsi.length = pdu->data_segment_len;
spdk_iscsi_task_associate_pdu(subtask, pdu);
if (task->next_expected_r2t_offset == transfer_len) {
task->acked_r2tsn++;
} else if (F_bit && (task->next_r2t_offset < transfer_len)) {
task->acked_r2tsn++;
len = DMIN32(conn->sess->MaxBurstLength, (transfer_len -
task->next_r2t_offset));
rc = iscsi_send_r2t(conn, task, task->next_r2t_offset, len,
task->ttt, &task->R2TSN);
if (rc < 0) {
SPDK_ERRLOG("iscsi_send_r2t() failed\n");
}
task->next_r2t_offset += len;
}
if (lun_dev == NULL) {
SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "LUN %d is removed, complete the task immediately\n",
task->lun_id);
@ -4481,36 +4512,13 @@ reject_return:
static int
iscsi_pdu_payload_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;
struct spdk_iscsi_task *subtask;
if (pdu->task == NULL) {
return 0;
}
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);
@ -4518,23 +4526,9 @@ iscsi_pdu_payload_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *p
spdk_scsi_task_set_data(&subtask->scsi, pdu->data, pdu->data_buf_len);
}
if (task->next_expected_r2t_offset == transfer_len) {
task->acked_r2tsn++;
} else if (F_bit && (task->next_r2t_offset < transfer_len)) {
task->acked_r2tsn++;
len = DMIN32(conn->sess->MaxBurstLength, (transfer_len -
task->next_r2t_offset));
rc = iscsi_send_r2t(conn, task, task->next_r2t_offset, len,
task->ttt, &task->R2TSN);
if (rc < 0) {
SPDK_ERRLOG("iscsi_send_r2t() failed\n");
}
task->next_r2t_offset += len;
}
if (spdk_scsi_dev_get_lun(conn->dev, task->lun_id) == NULL) {
if (spdk_scsi_dev_get_lun(conn->dev, subtask->lun_id) == NULL) {
SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "LUN %d is removed, complete the task immediately\n",
task->lun_id);
subtask->lun_id);
subtask->scsi.transfer_len = subtask->scsi.length;
spdk_scsi_task_process_null_lun(&subtask->scsi);
spdk_iscsi_task_cpl(&subtask->scsi);