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

Commit 8aa34172 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull SCSI target fixes from Nicholas Bellinger:
 "The bulk of the changes are in qla2xxx target driver code to address
  various issues found during Cavium/QLogic's internal testing (stable
  CC's included), along with a few other stability and smaller
  miscellaneous improvements.

  There are also a couple of different patch sets from Mike Christie,
  which have been a result of his work to use target-core ALUA logic
  together with tcm-user backend driver.

  Finally, a patch to address some long standing issues with
  pass-through SCSI export of TYPE_TAPE + TYPE_MEDIUM_CHANGER devices,
  which will make folks using physical (or virtual) magnetic tape happy"

* git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (28 commits)
  qla2xxx: Update driver version to 9.00.00.00-k
  qla2xxx: Fix delayed response to command for loop mode/direct connect.
  qla2xxx: Change scsi host lookup method.
  qla2xxx: Add DebugFS node to display Port Database
  qla2xxx: Use IOCB interface to submit non-critical MBX.
  qla2xxx: Add async new target notification
  qla2xxx: Export DIF stats via debugfs
  qla2xxx: Improve T10-DIF/PI handling in driver.
  qla2xxx: Allow relogin to proceed if remote login did not finish
  qla2xxx: Fix sess_lock & hardware_lock lock order problem.
  qla2xxx: Fix inadequate lock protection for ABTS.
  qla2xxx: Fix request queue corruption.
  qla2xxx: Fix memory leak for abts processing
  qla2xxx: Allow vref count to timeout on vport delete.
  tcmu: Convert cmd_time_out into backend device attribute
  tcmu: make cmd timeout configurable
  tcmu: add helper to check if dev was configured
  target: fix race during implicit transition work flushes
  target: allow userspace to set state to transitioning
  target: fix ALUA transition timeout handling
  ...
parents 1b8df619 6c611d18
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -3,6 +3,7 @@ config SCSI_QLA_FC
	depends on PCI && SCSI
	depends on PCI && SCSI
	depends on SCSI_FC_ATTRS
	depends on SCSI_FC_ATTRS
	select FW_LOADER
	select FW_LOADER
	select BTREE
	---help---
	---help---
	This qla2xxx driver supports all QLogic Fibre Channel
	This qla2xxx driver supports all QLogic Fibre Channel
	PCI and PCIe host adapters.
	PCI and PCIe host adapters.
+1 −3
Original line number Original line Diff line number Diff line
@@ -2154,8 +2154,6 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
		    "Timer for the VP[%d] has stopped\n", vha->vp_idx);
		    "Timer for the VP[%d] has stopped\n", vha->vp_idx);
	}
	}


	BUG_ON(atomic_read(&vha->vref_count));

	qla2x00_free_fcports(vha);
	qla2x00_free_fcports(vha);


	mutex_lock(&ha->vport_lock);
	mutex_lock(&ha->vport_lock);
@@ -2166,7 +2164,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
	dma_free_coherent(&ha->pdev->dev, vha->gnl.size, vha->gnl.l,
	dma_free_coherent(&ha->pdev->dev, vha->gnl.size, vha->gnl.l,
	    vha->gnl.ldma);
	    vha->gnl.ldma);


	if (vha->qpair->vp_idx == vha->vp_idx) {
	if (vha->qpair && vha->qpair->vp_idx == vha->vp_idx) {
		if (qla2xxx_delete_qpair(vha, vha->qpair) != QLA_SUCCESS)
		if (qla2xxx_delete_qpair(vha, vha->qpair) != QLA_SUCCESS)
			ql_log(ql_log_warn, vha, 0x7087,
			ql_log(ql_log_warn, vha, 0x7087,
			    "Queue Pair delete failed.\n");
			    "Queue Pair delete failed.\n");
+1 −0
Original line number Original line Diff line number Diff line
@@ -348,6 +348,7 @@ ql_log_pci(uint32_t, struct pci_dev *pdev, int32_t, const char *fmt, ...);
#define ql_dbg_tgt	0x00004000 /* Target mode */
#define ql_dbg_tgt	0x00004000 /* Target mode */
#define ql_dbg_tgt_mgt	0x00002000 /* Target mode management */
#define ql_dbg_tgt_mgt	0x00002000 /* Target mode management */
#define ql_dbg_tgt_tmr	0x00001000 /* Target mode task management */
#define ql_dbg_tgt_tmr	0x00001000 /* Target mode task management */
#define ql_dbg_tgt_dif  0x00000800 /* Target mode dif */


extern int qla27xx_dump_mpi_ram(struct qla_hw_data *, uint32_t, uint32_t *,
extern int qla27xx_dump_mpi_ram(struct qla_hw_data *, uint32_t, uint32_t *,
	uint32_t, void **);
	uint32_t, void **);
+50 −6
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@
#include <linux/firmware.h>
#include <linux/firmware.h>
#include <linux/aer.h>
#include <linux/aer.h>
#include <linux/mutex.h>
#include <linux/mutex.h>
#include <linux/btree.h>


#include <scsi/scsi.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_host.h>
@@ -395,11 +396,15 @@ struct srb_iocb {
			struct completion comp;
			struct completion comp;
		} abt;
		} abt;
		struct ct_arg ctarg;
		struct ct_arg ctarg;
#define MAX_IOCB_MB_REG 28
#define SIZEOF_IOCB_MB_REG (MAX_IOCB_MB_REG * sizeof(uint16_t))
		struct {
		struct {
			__le16 in_mb[28]; 	/* fr fw */
			__le16 in_mb[MAX_IOCB_MB_REG];	/* from FW */
			__le16 out_mb[28];	/* to fw */
			__le16 out_mb[MAX_IOCB_MB_REG];	/* to FW */
			void *out, *in;
			void *out, *in;
			dma_addr_t out_dma, in_dma;
			dma_addr_t out_dma, in_dma;
			struct completion comp;
			int rc;
		} mbx;
		} mbx;
		struct {
		struct {
			struct imm_ntfy_from_isp *ntfy;
			struct imm_ntfy_from_isp *ntfy;
@@ -437,7 +442,7 @@ typedef struct srb {
	uint32_t handle;
	uint32_t handle;
	uint16_t flags;
	uint16_t flags;
	uint16_t type;
	uint16_t type;
	char *name;
	const char *name;
	int iocbs;
	int iocbs;
	struct qla_qpair *qpair;
	struct qla_qpair *qpair;
	u32 gen1;	/* scratch */
	u32 gen1;	/* scratch */
@@ -2300,6 +2305,8 @@ typedef struct fc_port {
	struct ct_sns_desc ct_desc;
	struct ct_sns_desc ct_desc;
	enum discovery_state disc_state;
	enum discovery_state disc_state;
	enum login_state fw_login_state;
	enum login_state fw_login_state;
	unsigned long plogi_nack_done_deadline;

	u32 login_gen, last_login_gen;
	u32 login_gen, last_login_gen;
	u32 rscn_gen, last_rscn_gen;
	u32 rscn_gen, last_rscn_gen;
	u32 chip_reset;
	u32 chip_reset;
@@ -3106,6 +3113,16 @@ struct qla_chip_state_84xx {
	uint32_t gold_fw_version;
	uint32_t gold_fw_version;
};
};


struct qla_dif_statistics {
	uint64_t dif_input_bytes;
	uint64_t dif_output_bytes;
	uint64_t dif_input_requests;
	uint64_t dif_output_requests;
	uint32_t dif_guard_err;
	uint32_t dif_ref_tag_err;
	uint32_t dif_app_tag_err;
};

struct qla_statistics {
struct qla_statistics {
	uint32_t total_isp_aborts;
	uint32_t total_isp_aborts;
	uint64_t input_bytes;
	uint64_t input_bytes;
@@ -3118,6 +3135,8 @@ struct qla_statistics {
	uint32_t stat_max_pend_cmds;
	uint32_t stat_max_pend_cmds;
	uint32_t stat_max_qfull_cmds_alloc;
	uint32_t stat_max_qfull_cmds_alloc;
	uint32_t stat_max_qfull_cmds_dropped;
	uint32_t stat_max_qfull_cmds_dropped;

	struct qla_dif_statistics qla_dif_stats;
};
};


struct bidi_statistics {
struct bidi_statistics {
@@ -3125,6 +3144,16 @@ struct bidi_statistics {
	unsigned long long transfer_bytes;
	unsigned long long transfer_bytes;
};
};


struct qla_tc_param {
	struct scsi_qla_host *vha;
	uint32_t blk_sz;
	uint32_t bufflen;
	struct scatterlist *sg;
	struct scatterlist *prot_sg;
	struct crc_context *ctx;
	uint8_t *ctx_dsd_alloced;
};

/* Multi queue support */
/* Multi queue support */
#define MBC_INITIALIZE_MULTIQ 0x1f
#define MBC_INITIALIZE_MULTIQ 0x1f
#define QLA_QUE_PAGE 0X1000
#define QLA_QUE_PAGE 0X1000
@@ -3272,6 +3301,8 @@ struct qlt_hw_data {
	uint8_t tgt_node_name[WWN_SIZE];
	uint8_t tgt_node_name[WWN_SIZE];


	struct dentry *dfs_tgt_sess;
	struct dentry *dfs_tgt_sess;
	struct dentry *dfs_tgt_port_database;

	struct list_head q_full_list;
	struct list_head q_full_list;
	uint32_t num_pend_cmds;
	uint32_t num_pend_cmds;
	uint32_t num_qfull_cmds_alloc;
	uint32_t num_qfull_cmds_alloc;
@@ -3281,6 +3312,7 @@ struct qlt_hw_data {
	spinlock_t sess_lock;
	spinlock_t sess_lock;
	int rspq_vector_cpuid;
	int rspq_vector_cpuid;
	spinlock_t atio_lock ____cacheline_aligned;
	spinlock_t atio_lock ____cacheline_aligned;
	struct btree_head32 host_map;
};
};


#define MAX_QFULL_CMDS_ALLOC	8192
#define MAX_QFULL_CMDS_ALLOC	8192
@@ -3290,6 +3322,10 @@ struct qlt_hw_data {


#define LEAK_EXCHG_THRESH_HOLD_PERCENT 75	/* 75 percent */
#define LEAK_EXCHG_THRESH_HOLD_PERCENT 75	/* 75 percent */


#define QLA_EARLY_LINKUP(_ha) \
	((_ha->flags.n2n_ae || _ha->flags.lip_ae) && \
	 _ha->flags.fw_started && !_ha->flags.fw_init_done)

/*
/*
 * Qlogic host adapter specific data structure.
 * Qlogic host adapter specific data structure.
*/
*/
@@ -3339,7 +3375,11 @@ struct qla_hw_data {
		uint32_t	fawwpn_enabled:1;
		uint32_t	fawwpn_enabled:1;
		uint32_t	exlogins_enabled:1;
		uint32_t	exlogins_enabled:1;
		uint32_t	exchoffld_enabled:1;
		uint32_t	exchoffld_enabled:1;
		/* 35 bits */

		uint32_t	lip_ae:1;
		uint32_t	n2n_ae:1;
		uint32_t	fw_started:1;
		uint32_t	fw_init_done:1;
	} flags;
	} flags;


	/* This spinlock is used to protect "io transactions", you must
	/* This spinlock is used to protect "io transactions", you must
@@ -3432,7 +3472,6 @@ struct qla_hw_data {
#define P2P_LOOP  3
#define P2P_LOOP  3
	uint8_t		interrupts_on;
	uint8_t		interrupts_on;
	uint32_t	isp_abort_cnt;
	uint32_t	isp_abort_cnt;

#define PCI_DEVICE_ID_QLOGIC_ISP2532    0x2532
#define PCI_DEVICE_ID_QLOGIC_ISP2532    0x2532
#define PCI_DEVICE_ID_QLOGIC_ISP8432    0x8432
#define PCI_DEVICE_ID_QLOGIC_ISP8432    0x8432
#define PCI_DEVICE_ID_QLOGIC_ISP8001	0x8001
#define PCI_DEVICE_ID_QLOGIC_ISP8001	0x8001
@@ -3913,6 +3952,7 @@ typedef struct scsi_qla_host {
	struct list_head vp_fcports;	/* list of fcports */
	struct list_head vp_fcports;	/* list of fcports */
	struct list_head work_list;
	struct list_head work_list;
	spinlock_t work_lock;
	spinlock_t work_lock;
	struct work_struct iocb_work;


	/* Commonly used flags and state information. */
	/* Commonly used flags and state information. */
	struct Scsi_Host *host;
	struct Scsi_Host *host;
@@ -4076,6 +4116,7 @@ typedef struct scsi_qla_host {
	/* Count of active session/fcport */
	/* Count of active session/fcport */
	int fcport_count;
	int fcport_count;
	wait_queue_head_t fcport_waitQ;
	wait_queue_head_t fcport_waitQ;
	wait_queue_head_t vref_waitq;
} scsi_qla_host_t;
} scsi_qla_host_t;


struct qla27xx_image_status {
struct qla27xx_image_status {
@@ -4131,14 +4172,17 @@ struct qla2_sgx {
	mb();						\
	mb();						\
	if (__vha->flags.delete_progress) {		\
	if (__vha->flags.delete_progress) {		\
		atomic_dec(&__vha->vref_count);		\
		atomic_dec(&__vha->vref_count);		\
		wake_up(&__vha->vref_waitq);		\
		__bail = 1;				\
		__bail = 1;				\
	} else {					\
	} else {					\
		__bail = 0;				\
		__bail = 0;				\
	}						\
	}						\
} while (0)
} while (0)


#define QLA_VHA_MARK_NOT_BUSY(__vha)			\
#define QLA_VHA_MARK_NOT_BUSY(__vha) do {		\
	atomic_dec(&__vha->vref_count);			\
	atomic_dec(&__vha->vref_count);			\
	wake_up(&__vha->vref_waitq);			\
} while (0)						\


#define QLA_QPAIR_MARK_BUSY(__qpair, __bail) do {	\
#define QLA_QPAIR_MARK_BUSY(__qpair, __bail) do {	\
	atomic_inc(&__qpair->ref_count);		\
	atomic_inc(&__qpair->ref_count);		\
+103 −4
Original line number Original line Diff line number Diff line
@@ -23,7 +23,7 @@ qla2x00_dfs_tgt_sess_show(struct seq_file *s, void *unused)


	seq_printf(s, "%s\n", vha->host_str);
	seq_printf(s, "%s\n", vha->host_str);
	if (tgt) {
	if (tgt) {
		seq_printf(s, "Port ID   Port Name                Handle\n");
		seq_puts(s, "Port ID   Port Name                Handle\n");


		spin_lock_irqsave(&ha->tgt.sess_lock, flags);
		spin_lock_irqsave(&ha->tgt.sess_lock, flags);
		list_for_each_entry(sess, &vha->vp_fcports, list)
		list_for_each_entry(sess, &vha->vp_fcports, list)
@@ -44,7 +44,6 @@ qla2x00_dfs_tgt_sess_open(struct inode *inode, struct file *file)
	return single_open(file, qla2x00_dfs_tgt_sess_show, vha);
	return single_open(file, qla2x00_dfs_tgt_sess_show, vha);
}
}



static const struct file_operations dfs_tgt_sess_ops = {
static const struct file_operations dfs_tgt_sess_ops = {
	.open		= qla2x00_dfs_tgt_sess_open,
	.open		= qla2x00_dfs_tgt_sess_open,
	.read		= seq_read,
	.read		= seq_read,
@@ -52,6 +51,78 @@ static const struct file_operations dfs_tgt_sess_ops = {
	.release	= single_release,
	.release	= single_release,
};
};


static int
qla2x00_dfs_tgt_port_database_show(struct seq_file *s, void *unused)
{
	scsi_qla_host_t *vha = s->private;
	struct qla_hw_data *ha = vha->hw;
	struct gid_list_info *gid_list;
	dma_addr_t gid_list_dma;
	fc_port_t fc_port;
	char *id_iter;
	int rc, i;
	uint16_t entries, loop_id;
	struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;

	seq_printf(s, "%s\n", vha->host_str);
	if (tgt) {
		gid_list = dma_alloc_coherent(&ha->pdev->dev,
		    qla2x00_gid_list_size(ha),
		    &gid_list_dma, GFP_KERNEL);
		if (!gid_list) {
			ql_dbg(ql_dbg_user, vha, 0x705c,
			    "DMA allocation failed for %u\n",
			     qla2x00_gid_list_size(ha));
			return 0;
		}

		rc = qla24xx_gidlist_wait(vha, gid_list, gid_list_dma,
		    &entries);
		if (rc != QLA_SUCCESS)
			goto out_free_id_list;

		id_iter = (char *)gid_list;

		seq_puts(s, "Port Name	Port ID 	Loop ID\n");

		for (i = 0; i < entries; i++) {
			struct gid_list_info *gid =
			    (struct gid_list_info *)id_iter;
			loop_id = le16_to_cpu(gid->loop_id);
			memset(&fc_port, 0, sizeof(fc_port_t));

			fc_port.loop_id = loop_id;

			rc = qla24xx_gpdb_wait(vha, &fc_port, 0);
			seq_printf(s, "%8phC  %02x%02x%02x  %d\n",
				fc_port.port_name, fc_port.d_id.b.domain,
				fc_port.d_id.b.area, fc_port.d_id.b.al_pa,
				fc_port.loop_id);
			id_iter += ha->gid_list_info_size;
		}
out_free_id_list:
		dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha),
		    gid_list, gid_list_dma);
	}

	return 0;
}

static int
qla2x00_dfs_tgt_port_database_open(struct inode *inode, struct file *file)
{
	scsi_qla_host_t *vha = inode->i_private;

	return single_open(file, qla2x00_dfs_tgt_port_database_show, vha);
}

static const struct file_operations dfs_tgt_port_database_ops = {
	.open		= qla2x00_dfs_tgt_port_database_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};

static int
static int
qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
{
{
@@ -114,6 +185,21 @@ qla_dfs_tgt_counters_show(struct seq_file *s, void *unused)
	seq_printf(s, "num Q full sent = %lld\n",
	seq_printf(s, "num Q full sent = %lld\n",
		vha->tgt_counters.num_q_full_sent);
		vha->tgt_counters.num_q_full_sent);


	/* DIF stats */
	seq_printf(s, "DIF Inp Bytes = %lld\n",
		vha->qla_stats.qla_dif_stats.dif_input_bytes);
	seq_printf(s, "DIF Outp Bytes = %lld\n",
		vha->qla_stats.qla_dif_stats.dif_output_bytes);
	seq_printf(s, "DIF Inp Req = %lld\n",
		vha->qla_stats.qla_dif_stats.dif_input_requests);
	seq_printf(s, "DIF Outp Req = %lld\n",
		vha->qla_stats.qla_dif_stats.dif_output_requests);
	seq_printf(s, "DIF Guard err = %d\n",
		vha->qla_stats.qla_dif_stats.dif_guard_err);
	seq_printf(s, "DIF Ref tag err = %d\n",
		vha->qla_stats.qla_dif_stats.dif_ref_tag_err);
	seq_printf(s, "DIF App tag err = %d\n",
		vha->qla_stats.qla_dif_stats.dif_app_tag_err);
	return 0;
	return 0;
}
}


@@ -281,6 +367,14 @@ qla2x00_dfs_setup(scsi_qla_host_t *vha)
		goto out;
		goto out;
	}
	}


	ha->tgt.dfs_tgt_port_database = debugfs_create_file("tgt_port_database",
	    S_IRUSR,  ha->dfs_dir, vha, &dfs_tgt_port_database_ops);
	if (!ha->tgt.dfs_tgt_port_database) {
		ql_log(ql_log_warn, vha, 0xffff,
		    "Unable to create debugFS tgt_port_database node.\n");
		goto out;
	}

	ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, vha,
	ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, vha,
	    &dfs_fce_ops);
	    &dfs_fce_ops);
	if (!ha->dfs_fce) {
	if (!ha->dfs_fce) {
@@ -311,6 +405,11 @@ qla2x00_dfs_remove(scsi_qla_host_t *vha)
		ha->tgt.dfs_tgt_sess = NULL;
		ha->tgt.dfs_tgt_sess = NULL;
	}
	}


	if (ha->tgt.dfs_tgt_port_database) {
		debugfs_remove(ha->tgt.dfs_tgt_port_database);
		ha->tgt.dfs_tgt_port_database = NULL;
	}

	if (ha->dfs_fw_resource_cnt) {
	if (ha->dfs_fw_resource_cnt) {
		debugfs_remove(ha->dfs_fw_resource_cnt);
		debugfs_remove(ha->dfs_fw_resource_cnt);
		ha->dfs_fw_resource_cnt = NULL;
		ha->dfs_fw_resource_cnt = NULL;
Loading