Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 778de368 authored by Nicholas Bellinger's avatar Nicholas Bellinger
Browse files

iscsi/isert-target: Refactor ISCSI_OP_NOOP RX handling



This patch refactors ISCSI_OP_NOOP handling within iscsi-target in
order to handle iscsi_nopout payloads in a transport specific manner.

This includes splitting existing iscsit_handle_nop_out() into
iscsit_setup_nop_out() and iscsit_process_nop_out() calls, and
makes iscsit_handle_nop_out() be only used internally by traditional
iscsi socket calls.

Next update iser-target code to use new callers and add FIXME for
the handling iscsi_nopout payloads.  Also fix reject response handling
in iscsit_setup_nop_out() to use proper iscsit_add_reject_from_cmd().

v2: Fix uninitialized iscsit_handle_nop_out() payload_length usage (Fengguang)
v3: Remove left-over dead code in iscsit_setup_nop_out() (DanC)

Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent 08234e3a
Loading
Loading
Loading
Loading
+22 −1
Original line number Diff line number Diff line
@@ -1000,6 +1000,25 @@ isert_handle_iscsi_dataout(struct isert_conn *isert_conn,
	return 0;
}

static int
isert_handle_nop_out(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
		     struct iser_rx_desc *rx_desc, unsigned char *buf)
{
	struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
	struct iscsi_conn *conn = isert_conn->conn;
	struct iscsi_nopout *hdr = (struct iscsi_nopout *)buf;
	int rc;

	rc = iscsit_setup_nop_out(conn, cmd, hdr);
	if (rc < 0)
		return rc;
	/*
	 * FIXME: Add support for NOPOUT payload using unsolicited RDMA payload
	 */

	return iscsit_process_nop_out(conn, cmd, hdr);
}

static int
isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
		uint32_t read_stag, uint64_t read_va,
@@ -1032,7 +1051,9 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
		if (!cmd)
			break;

		ret = iscsit_handle_nop_out(conn, cmd, (unsigned char *)hdr);
		isert_cmd = container_of(cmd, struct isert_cmd, iscsi_cmd);
		ret = isert_handle_nop_out(isert_conn, isert_cmd,
					   rx_desc, (unsigned char *)hdr);
		break;
	case ISCSI_OP_SCSI_DATA_OUT:
		ret = isert_handle_iscsi_dataout(isert_conn, rx_desc,
+89 −85
Original line number Diff line number Diff line
@@ -1535,24 +1535,16 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
	return iscsit_check_dataout_payload(cmd, hdr, data_crc_failed);
}

int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
			unsigned char *buf)
int iscsit_setup_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
			 struct iscsi_nopout *hdr)
{
	unsigned char *ping_data = NULL;
	int cmdsn_ret, niov = 0, ret = 0, rx_got, rx_size;
	u32 checksum, data_crc, padding = 0, payload_length;
	struct iscsi_cmd *cmd_p = NULL;
	struct kvec *iov = NULL;
	struct iscsi_nopout *hdr;

	hdr			= (struct iscsi_nopout *) buf;
	payload_length		= ntoh24(hdr->dlength);
	u32 payload_length = ntoh24(hdr->dlength);

	if (hdr->itt == RESERVED_ITT && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
		pr_err("NOPOUT ITT is reserved, but Immediate Bit is"
			" not set, protocol error.\n");
		return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
					buf, conn);
		return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
					1, 0, (unsigned char *)hdr, cmd);
	}

	if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
@@ -1560,8 +1552,8 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
			" greater than MaxXmitDataSegmentLength: %u, protocol"
			" error.\n", payload_length,
			conn->conn_ops->MaxXmitDataSegmentLength);
		return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
					buf, conn);
		return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
					1, 0, (unsigned char *)hdr, cmd);
	}

	pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%08x,"
@@ -1577,11 +1569,6 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
	 * can contain ping data.
	 */
	if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
		if (!cmd)
			return iscsit_add_reject(
					ISCSI_REASON_BOOKMARK_NO_RESOURCES,
					1, buf, conn);

		cmd->iscsi_opcode	= ISCSI_OP_NOOP_OUT;
		cmd->i_state		= ISTATE_SEND_NOPIN;
		cmd->immediate_cmd	= ((hdr->opcode & ISCSI_OP_IMMEDIATE) ?
@@ -1593,8 +1580,87 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
		cmd->data_direction	= DMA_NONE;
	}

	return 0;
}
EXPORT_SYMBOL(iscsit_setup_nop_out);

int iscsit_process_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
			   struct iscsi_nopout *hdr)
{
	struct iscsi_cmd *cmd_p = NULL;
	int cmdsn_ret = 0;
	/*
	 * Initiator is expecting a NopIN ping reply..
	 */
	if (hdr->itt != RESERVED_ITT) {
		BUG_ON(!cmd);

		spin_lock_bh(&conn->cmd_lock);
		list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
		spin_unlock_bh(&conn->cmd_lock);

		iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));

		if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
			iscsit_add_cmd_to_response_queue(cmd, conn,
							 cmd->i_state);
			return 0;
		}

		cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
                if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
			return 0;

		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
			return iscsit_add_reject_from_cmd(
					ISCSI_REASON_PROTOCOL_ERROR,
					1, 0, (unsigned char *)hdr, cmd);

		return 0;
	}
	/*
	 * This was a response to a unsolicited NOPIN ping.
	 */
	if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
		cmd_p = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt));
		if (!cmd_p)
			return -EINVAL;

		iscsit_stop_nopin_response_timer(conn);

		cmd_p->i_state = ISTATE_REMOVE;
		iscsit_add_cmd_to_immediate_queue(cmd_p, conn, cmd_p->i_state);

		iscsit_start_nopin_timer(conn);
		return 0;
	}
	/*
	 * Otherwise, initiator is not expecting a NOPIN is response.
	 * Just ignore for now.
	 */
        return 0;
}
EXPORT_SYMBOL(iscsit_process_nop_out);

static int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
				 unsigned char *buf)
{
	unsigned char *ping_data = NULL;
	struct iscsi_nopout *hdr = (struct iscsi_nopout *)buf;
	struct kvec *iov = NULL;
	u32 payload_length = ntoh24(hdr->dlength);
	int ret;

	ret = iscsit_setup_nop_out(conn, cmd, hdr);
	if (ret < 0)
		return ret;
	/*
	 * Handle NOP-OUT payload for traditional iSCSI sockets
	 */
	if (payload_length && hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
		rx_size = payload_length;
		u32 checksum, data_crc, padding = 0;
		int niov = 0, rx_got, rx_size = payload_length;

		ping_data = kzalloc(payload_length + 1, GFP_KERNEL);
		if (!ping_data) {
			pr_err("Unable to allocate memory for"
@@ -1673,76 +1739,14 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
		pr_debug("Ping Data: \"%s\"\n", ping_data);
	}

	if (hdr->itt != RESERVED_ITT) {
		if (!cmd) {
			pr_err("Checking CmdSN for NOPOUT,"
				" but cmd is NULL!\n");
			return -1;
		}
		/*
		 * Initiator is expecting a NopIN ping reply,
		 */
		spin_lock_bh(&conn->cmd_lock);
		list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
		spin_unlock_bh(&conn->cmd_lock);

		iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));

		if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
			iscsit_add_cmd_to_response_queue(cmd, conn,
					cmd->i_state);
			return 0;
		}

		cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
		if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
			ret = 0;
			goto ping_out;
		}
		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
			return iscsit_add_reject_from_cmd(
					ISCSI_REASON_PROTOCOL_ERROR,
					1, 0, buf, cmd);

		return 0;
	}

	if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
		/*
		 * This was a response to a unsolicited NOPIN ping.
		 */
		cmd_p = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt));
		if (!cmd_p)
			return -1;

		iscsit_stop_nopin_response_timer(conn);

		cmd_p->i_state = ISTATE_REMOVE;
		iscsit_add_cmd_to_immediate_queue(cmd_p, conn, cmd_p->i_state);
		iscsit_start_nopin_timer(conn);
	} else {
		/*
		 * Initiator is not expecting a NOPIN is response.
		 * Just ignore for now.
		 *
		 * iSCSI v19-91 10.18
		 * "A NOP-OUT may also be used to confirm a changed
		 *  ExpStatSN if another PDU will not be available
		 *  for a long time."
		 */
		ret = 0;
		goto out;
	}

	return 0;
	return iscsit_process_nop_out(conn, cmd, hdr);
out:
	if (cmd)
		iscsit_free_cmd(cmd, false);
ping_out:

	kfree(ping_data);
	return ret;
}
EXPORT_SYMBOL(iscsit_handle_nop_out);

int
iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+4 −2
Original line number Diff line number Diff line
@@ -45,8 +45,10 @@ extern int iscsit_check_dataout_hdr(struct iscsi_conn *, unsigned char *,
				struct iscsi_cmd **);
extern int iscsit_check_dataout_payload(struct iscsi_cmd *, struct iscsi_data *,
				bool);
extern int iscsit_handle_nop_out(struct iscsi_conn *, struct iscsi_cmd *,
				unsigned char *);
extern int iscsit_setup_nop_out(struct iscsi_conn *, struct iscsi_cmd *,
				struct iscsi_nopout *);
extern int iscsit_process_nop_out(struct iscsi_conn *, struct iscsi_cmd *,
				struct iscsi_nopout *);
extern int iscsit_handle_logout_cmd(struct iscsi_conn *, struct iscsi_cmd *,
				unsigned char *);
extern int iscsit_handle_task_mgt_cmd(struct iscsi_conn *, struct iscsi_cmd *,