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

Commit 5266e5b1 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull SCSI target updates from Nicholas Bellinger:
 "The highlights this round include:

   - Add target_alloc_session() w/ callback helper for doing se_session
     allocation + tag + se_node_acl lookup.  (HCH + nab)

   - Tree-wide fabric driver conversion to use target_alloc_session()

   - Convert sbp-target to use percpu_ida tag pre-allocation, and
     TARGET_SCF_ACK_KREF I/O krefs (Chris Boot + nab)

   - Convert usb-gadget to use percpu_ida tag pre-allocation, and
     TARGET_SCF_ACK_KREF I/O krefs (Andrzej Pietrasiewicz + nab)

   - Convert xen-scsiback to use percpu_ida tag pre-allocation, and
     TARGET_SCF_ACK_KREF I/O krefs (Juergen Gross + nab)

   - Convert tcm_fc to use TARGET_SCF_ACK_KREF I/O + TMR krefs

   - Convert ib_srpt to use percpu_ida tag pre-allocation

   - Add DebugFS node for qla2xxx target sess list (Quinn)

   - Rework iser-target connection termination (Jenny + Sagi)

   - Convert iser-target to new CQ API (HCH)

   - Add pass-through WRITE_SAME support for IBLOCK (Mike Christie)

   - Introduce data_bitmap for asynchronous access of data area (Sheng
     Yang + Andy)

   - Fix target_release_cmd_kref shutdown comp leak (Himanshu Madhani)

  Also, there is a separate PULL request coming for cxgb4 NIC driver
  prerequisites for supporting hw iscsi segmentation offload (ISO), that
  will be the base for a number of v4.7 developments involving
  iscsi-target hw offloads"

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (36 commits)
  target: Fix target_release_cmd_kref shutdown comp leak
  target: Avoid DataIN transfers for non-GOOD SAM status
  target/user: Report capability of handling out-of-order completions to userspace
  target/user: Fix size_t format-spec build warning
  target/user: Don't free expired command when time out
  target/user: Introduce data_bitmap, replace data_length/data_head/data_tail
  target/user: Free data ring in unified function
  target/user: Use iovec[] to describe continuous area
  target: Remove enum transport_lunflags_table
  target/iblock: pass WRITE_SAME to device if possible
  iser-target: Kill the ->isert_cmd back pointer in struct iser_tx_desc
  iser-target: Kill struct isert_rdma_wr
  iser-target: Convert to new CQ API
  iser-target: Split and properly type the login buffer
  iser-target: Remove ISER_RECV_DATA_SEG_LEN
  iser-target: Remove impossible condition from isert_wait_conn
  iser-target: Remove redundant wait in release_conn
  iser-target: Rework connection termination
  iser-target: Separate flows for np listeners and connections cma events
  iser-target: Add new state ISER_CONN_BOUND to isert_conn
  ...
parents fc739eba 5e47f198
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -117,7 +117,9 @@ userspace (respectively) to put commands on the ring, and indicate
when the commands are completed.

version - 1 (userspace should abort if otherwise)
flags - none yet defined.
flags:
- TCMU_MAILBOX_FLAG_CAP_OOOC: indicates out-of-order completion is
  supported.  See "The Command Ring" for details.
cmdr_off - The offset of the start of the command ring from the start
of the memory region, to account for the mailbox size.
cmdr_size - The size of the command ring. This does *not* need to be a
@@ -162,6 +164,13 @@ rsp.sense_buffer if necessary. Userspace then increments
mailbox.cmd_tail by entry.hdr.length (mod cmdr_size) and signals the
kernel via the UIO method, a 4-byte write to the file descriptor.

If TCMU_MAILBOX_FLAG_CAP_OOOC is set for mailbox->flags, kernel is
capable of handling out-of-order completions. In this case, userspace can
handle command in different order other than original. Since kernel would
still process the commands in the same order it appeared in the command
ring, userspace need to update the cmd->id when completing the
command(a.k.a steal the original command's entry).

When the opcode is PAD, userspace only updates cmd_tail as above --
it's a no-op. (The kernel inserts PAD entries to ensure each CMD entry
is contiguous within the command ring.)
+359 −451

File changed.

Preview size limit exceeded, changes collapsed.

+37 −35
Original line number Diff line number Diff line
@@ -36,9 +36,7 @@
/* Constant PDU lengths calculations */
#define ISER_HEADERS_LEN	(sizeof(struct iser_ctrl) + \
				 sizeof(struct iscsi_hdr))
#define ISER_RECV_DATA_SEG_LEN	8192
#define ISER_RX_PAYLOAD_SIZE	(ISER_HEADERS_LEN + ISER_RECV_DATA_SEG_LEN)
#define ISER_RX_LOGIN_SIZE	(ISER_HEADERS_LEN + ISCSI_DEF_MAX_RECV_SEG_LEN)
#define ISER_RX_PAYLOAD_SIZE	(ISER_HEADERS_LEN + ISCSI_DEF_MAX_RECV_SEG_LEN)

/* QP settings */
/* Maximal bounds on received asynchronous PDUs */
@@ -62,12 +60,11 @@
				ISERT_MAX_TX_MISC_PDUS	+ \
				ISERT_MAX_RX_MISC_PDUS)

#define ISER_RX_PAD_SIZE	(ISER_RECV_DATA_SEG_LEN + 4096 - \
		(ISER_RX_PAYLOAD_SIZE + sizeof(u64) + sizeof(struct ib_sge)))
#define ISER_RX_PAD_SIZE	(ISCSI_DEF_MAX_RECV_SEG_LEN + 4096 - \
		(ISER_RX_PAYLOAD_SIZE + sizeof(u64) + sizeof(struct ib_sge) + \
		 sizeof(struct ib_cqe)))

#define ISCSI_ISER_SG_TABLESIZE		256
#define ISER_FASTREG_LI_WRID		0xffffffffffffffffULL
#define ISER_BEACON_WRID               0xfffffffffffffffeULL

enum isert_desc_type {
	ISCSI_TX_CONTROL,
@@ -84,6 +81,7 @@ enum iser_ib_op_code {
enum iser_conn_state {
	ISER_CONN_INIT,
	ISER_CONN_UP,
	ISER_CONN_BOUND,
	ISER_CONN_FULL_FEATURE,
	ISER_CONN_TERMINATING,
	ISER_CONN_DOWN,
@@ -92,23 +90,35 @@ enum iser_conn_state {
struct iser_rx_desc {
	struct iser_ctrl iser_header;
	struct iscsi_hdr iscsi_header;
	char		data[ISER_RECV_DATA_SEG_LEN];
	char		data[ISCSI_DEF_MAX_RECV_SEG_LEN];
	u64		dma_addr;
	struct ib_sge	rx_sg;
	struct ib_cqe	rx_cqe;
	char		pad[ISER_RX_PAD_SIZE];
} __packed;

static inline struct iser_rx_desc *cqe_to_rx_desc(struct ib_cqe *cqe)
{
	return container_of(cqe, struct iser_rx_desc, rx_cqe);
}

struct iser_tx_desc {
	struct iser_ctrl iser_header;
	struct iscsi_hdr iscsi_header;
	enum isert_desc_type type;
	u64		dma_addr;
	struct ib_sge	tx_sg[2];
	struct ib_cqe	tx_cqe;
	int		num_sge;
	struct isert_cmd *isert_cmd;
	struct ib_send_wr send_wr;
} __packed;

static inline struct iser_tx_desc *cqe_to_tx_desc(struct ib_cqe *cqe)
{
	return container_of(cqe, struct iser_tx_desc, tx_cqe);
}


enum isert_indicator {
	ISERT_PROTECTED		= 1 << 0,
	ISERT_DATA_KEY_VALID	= 1 << 1,
@@ -144,20 +154,6 @@ enum {
	SIG = 2,
};

struct isert_rdma_wr {
	struct isert_cmd	*isert_cmd;
	enum iser_ib_op_code	iser_ib_op;
	struct ib_sge		*ib_sge;
	struct ib_sge		s_ib_sge;
	int			rdma_wr_num;
	struct ib_rdma_wr	*rdma_wr;
	struct ib_rdma_wr	s_rdma_wr;
	struct ib_sge		ib_sg[3];
	struct isert_data_buf	data;
	struct isert_data_buf	prot;
	struct fast_reg_descriptor *fr_desc;
};

struct isert_cmd {
	uint32_t		read_stag;
	uint32_t		write_stag;
@@ -170,22 +166,34 @@ struct isert_cmd {
	struct iscsi_cmd	*iscsi_cmd;
	struct iser_tx_desc	tx_desc;
	struct iser_rx_desc	*rx_desc;
	struct isert_rdma_wr	rdma_wr;
	enum iser_ib_op_code	iser_ib_op;
	struct ib_sge		*ib_sge;
	struct ib_sge		s_ib_sge;
	int			rdma_wr_num;
	struct ib_rdma_wr	*rdma_wr;
	struct ib_rdma_wr	s_rdma_wr;
	struct ib_sge		ib_sg[3];
	struct isert_data_buf	data;
	struct isert_data_buf	prot;
	struct fast_reg_descriptor *fr_desc;
	struct work_struct	comp_work;
	struct scatterlist	sg;
};

static inline struct isert_cmd *tx_desc_to_cmd(struct iser_tx_desc *desc)
{
	return container_of(desc, struct isert_cmd, tx_desc);
}

struct isert_device;

struct isert_conn {
	enum iser_conn_state	state;
	int			post_recv_buf_count;
	u32			responder_resources;
	u32			initiator_depth;
	bool			pi_support;
	u32			max_sge;
	char			*login_buf;
	char			*login_req_buf;
	struct iser_rx_desc	*login_req_buf;
	char			*login_rsp_buf;
	u64			login_req_dma;
	int			login_req_len;
@@ -201,7 +209,6 @@ struct isert_conn {
	struct ib_qp		*qp;
	struct isert_device	*device;
	struct mutex		mutex;
	struct completion	wait;
	struct completion	wait_comp_err;
	struct kref		kref;
	struct list_head	fr_pool;
@@ -221,17 +228,13 @@ struct isert_conn {
 *
 * @device:     pointer to device handle
 * @cq:         completion queue
 * @wcs:        work completion array
 * @active_qps: Number of active QPs attached
 *              to completion context
 * @work:       completion work handle
 */
struct isert_comp {
	struct isert_device     *device;
	struct ib_cq		*cq;
	struct ib_wc		 wcs[16];
	int                      active_qps;
	struct work_struct	 work;
};

struct isert_device {
@@ -243,9 +246,8 @@ struct isert_device {
	struct isert_comp	*comps;
	int                     comps_used;
	struct list_head	dev_node;
	int			(*reg_rdma_mem)(struct iscsi_conn *conn,
						    struct iscsi_cmd *cmd,
						    struct isert_rdma_wr *wr);
	int			(*reg_rdma_mem)(struct isert_cmd *isert_cmd,
						struct iscsi_conn *conn);
	void			(*unreg_rdma_mem)(struct isert_cmd *isert_cmd,
						  struct isert_conn *isert_conn);
};
+22 −54
Original line number Diff line number Diff line
@@ -1264,40 +1264,26 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
 */
static struct srpt_send_ioctx *srpt_get_send_ioctx(struct srpt_rdma_ch *ch)
{
	struct se_session *se_sess;
	struct srpt_send_ioctx *ioctx;
	unsigned long flags;
	int tag;

	BUG_ON(!ch);
	se_sess = ch->sess;

	ioctx = NULL;
	spin_lock_irqsave(&ch->spinlock, flags);
	if (!list_empty(&ch->free_list)) {
		ioctx = list_first_entry(&ch->free_list,
					 struct srpt_send_ioctx, free_list);
		list_del(&ioctx->free_list);
	tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING);
	if (tag < 0) {
		pr_err("Unable to obtain tag for srpt_send_ioctx\n");
		return NULL;
	}
	spin_unlock_irqrestore(&ch->spinlock, flags);

	if (!ioctx)
		return ioctx;

	BUG_ON(ioctx->ch != ch);
	ioctx = &((struct srpt_send_ioctx *)se_sess->sess_cmd_map)[tag];
	memset(ioctx, 0, sizeof(struct srpt_send_ioctx));
	ioctx->ch = ch;
	spin_lock_init(&ioctx->spinlock);
	ioctx->state = SRPT_STATE_NEW;
	ioctx->n_rbuf = 0;
	ioctx->rbufs = NULL;
	ioctx->n_rdma = 0;
	ioctx->n_rdma_wrs = 0;
	ioctx->rdma_wrs = NULL;
	ioctx->mapped_sg_count = 0;
	init_completion(&ioctx->tx_done);
	ioctx->queue_status_only = false;
	/*
	 * transport_init_se_cmd() does not initialize all fields, so do it
	 * here.
	 */
	memset(&ioctx->cmd, 0, sizeof(ioctx->cmd));
	memset(&ioctx->sense_data, 0, sizeof(ioctx->sense_data));

	ioctx->cmd.map_tag = tag;

	return ioctx;
}
@@ -2034,9 +2020,8 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
	struct srp_login_rej *rej;
	struct ib_cm_rep_param *rep_param;
	struct srpt_rdma_ch *ch, *tmp_ch;
	struct se_node_acl *se_acl;
	u32 it_iu_len;
	int i, ret = 0;
	int ret = 0;
	unsigned char *p;

	WARN_ON_ONCE(irqs_disabled());
@@ -2158,12 +2143,6 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
	if (!ch->ioctx_ring)
		goto free_ch;

	INIT_LIST_HEAD(&ch->free_list);
	for (i = 0; i < ch->rq_size; i++) {
		ch->ioctx_ring[i]->ch = ch;
		list_add_tail(&ch->ioctx_ring[i]->free_list, &ch->free_list);
	}

	ret = srpt_create_ch_ib(ch);
	if (ret) {
		rej->reason = cpu_to_be32(
@@ -2193,19 +2172,13 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
	pr_debug("registering session %s\n", ch->sess_name);
	p = &ch->sess_name[0];

	ch->sess = transport_init_session(TARGET_PROT_NORMAL);
	if (IS_ERR(ch->sess)) {
		rej->reason = cpu_to_be32(
				SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
		pr_debug("Failed to create session\n");
		goto destroy_ib;
	}

try_again:
	se_acl = core_tpg_get_initiator_node_acl(&sport->port_tpg_1, p);
	if (!se_acl) {
	ch->sess = target_alloc_session(&sport->port_tpg_1, ch->rq_size,
					sizeof(struct srpt_send_ioctx),
					TARGET_PROT_NORMAL, p, ch, NULL);
	if (IS_ERR(ch->sess)) {
		pr_info("Rejected login because no ACL has been"
			" configured yet for initiator %s.\n", ch->sess_name);
			" configured yet for initiator %s.\n", p);
		/*
		 * XXX: Hack to retry of ch->i_port_id without leading '0x'
		 */
@@ -2213,14 +2186,11 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
			p += 2;
			goto try_again;
		}
		rej->reason = cpu_to_be32(
		rej->reason = cpu_to_be32((PTR_ERR(ch->sess) == -ENOMEM) ?
				SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES :
				SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED);
		transport_free_session(ch->sess);
		goto destroy_ib;
	}
	ch->sess->se_node_acl = se_acl;

	transport_register_session(&sport->port_tpg_1, se_acl, ch->sess, ch);

	pr_debug("Establish connection sess=%p name=%s cm_id=%p\n", ch->sess,
		 ch->sess_name, ch->cm_id);
@@ -2911,7 +2881,7 @@ static void srpt_release_cmd(struct se_cmd *se_cmd)
	struct srpt_send_ioctx *ioctx = container_of(se_cmd,
				struct srpt_send_ioctx, cmd);
	struct srpt_rdma_ch *ch = ioctx->ch;
	unsigned long flags;
	struct se_session *se_sess = ch->sess;

	WARN_ON(ioctx->state != SRPT_STATE_DONE);
	WARN_ON(ioctx->mapped_sg_count != 0);
@@ -2922,9 +2892,7 @@ static void srpt_release_cmd(struct se_cmd *se_cmd)
		ioctx->n_rbuf = 0;
	}

	spin_lock_irqsave(&ch->spinlock, flags);
	list_add(&ioctx->free_list, &ch->free_list);
	spin_unlock_irqrestore(&ch->spinlock, flags);
	percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag);
}

/**
+0 −2
Original line number Diff line number Diff line
@@ -179,7 +179,6 @@ struct srpt_recv_ioctx {
 * struct srpt_send_ioctx - SRPT send I/O context.
 * @ioctx:       See above.
 * @ch:          Channel pointer.
 * @free_list:   Node in srpt_rdma_ch.free_list.
 * @n_rbuf:      Number of data buffers in the received SRP command.
 * @rbufs:       Pointer to SRP data buffer array.
 * @single_rbuf: SRP data buffer if the command has only a single buffer.
@@ -202,7 +201,6 @@ struct srpt_send_ioctx {
	struct srp_direct_buf	*rbufs;
	struct srp_direct_buf	single_rbuf;
	struct scatterlist	*sg;
	struct list_head	free_list;
	spinlock_t		spinlock;
	enum srpt_command_state	state;
	struct se_cmd		cmd;
Loading