Commit 50bd0364 authored by Shuhei Matsumoto's avatar Shuhei Matsumoto Committed by Jim Harris
Browse files

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: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Change-Id: I5074e945254081960744577e4ed8e0170793e5e0
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/470291


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Community-CI: Broadcom SPDK FC-NVMe CI <spdk-ci.pdl@broadcom.com>
parent 6e7473f7
Loading
Loading
Loading
Loading
+67 −35
Original line number Diff line number Diff line
@@ -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,18 +4454,71 @@ iscsi_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,
			    conn->sess->MaxBurstLength);
		return SPDK_ISCSI_CONNECTION_FATAL;
	}

	subtask = spdk_iscsi_task_get(conn, task, spdk_iscsi_task_cpl);
	if (subtask == NULL) {
		SPDK_ERRLOG("Unable to acquire subtask\n");
		return SPDK_ISCSI_CONNECTION_FATAL;
	}
	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 (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
@@ -4478,19 +4527,11 @@ iscsi_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
		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");
		return SPDK_ISCSI_CONNECTION_FATAL;
	}
	subtask->scsi.offset = buffer_offset;
	subtask->scsi.length = pdu->data_segment_len;
	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