summaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-01-20 17:20:53 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2016-01-20 17:20:53 -0800
commit71e4634e00119b2fb8dd0da99b3f5ebbb49cc872 (patch)
treec42a37a98e99aa9ce8a2af79710e295704782a16 /drivers/scsi
parent19a3dd7621af01b7e44a70d16beab59326c38824 (diff)
parentfab683eb12e71ac6057dc42dc7d1e5e71e5cba5e (diff)
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
Pull SCSI target updates from Nicholas Bellinger: "The highlights this round include: - Introduce configfs support for unlocked configfs_depend_item() (krzysztof + andrezej) - Conversion of usb-gadget target driver to new function registration interface (andrzej + sebastian) - Enable qla2xxx FC target mode support for Extended Logins (himansu + giridhar) - Enable qla2xxx FC target mode support for Exchange Offload (himansu + giridhar) - Add qla2xxx FC target mode irq affinity notification + selective command queuing. (quinn + himanshu) - Fix iscsi-target deadlock in se_node_acl configfs deletion (sagi + nab) - Convert se_node_acl configfs deletion + se_node_acl->queue_depth to proper se_session->sess_kref + target_get_session() usage. (hch + sagi + nab) - Fix long-standing race between se_node_acl->acl_kref get and get_initiator_node_acl() lookup. (hch + nab) - Fix target/user block-size handling, and make sure netlink reaches all network namespaces (sheng + andy) Note there is an outstanding bug-fix series for remote I_T nexus port TMR LUN_RESET has been posted and still being tested, and will likely become post -rc1 material at this point" * 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (56 commits) scsi: qla2xxxx: avoid type mismatch in comparison target/user: Make sure netlink would reach all network namespaces target: Obtain se_node_acl->acl_kref during get_initiator_node_acl target: Convert ACL change queue_depth se_session reference usage iscsi-target: Fix potential dead-lock during node acl delete ib_srpt: Convert acl lookup to modern get_initiator_node_acl usage tcm_fc: Convert acl lookup to modern get_initiator_node_acl usage tcm_fc: Wait for command completion before freeing a session target: Fix a memory leak in target_dev_lba_map_store() target: Support aborting tasks with a 64-bit tag usb/gadget: Remove set-but-not-used variables target: Remove an unused variable target: Fix indentation in target_core_configfs.c target/user: Allow user to set block size before enabling device iser-target: Fix non negative ERR_PTR isert_device_get usage target/fcoe: Add tag support to tcm_fc qla2xxx: Check for online flag instead of active reset when transmitting responses qla2xxx: Set all queues to 4k qla2xxx: Disable ZIO at start time. qla2xxx: Move atioq to a different lock to reduce lock contention ...
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c36
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c19
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h83
-rw-r--r--drivers/scsi/qla2xxx/qla_dfs.c106
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h18
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c58
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c188
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c126
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c265
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c165
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c645
-rw-r--r--drivers/scsi/qla2xxx/qla_target.h34
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c38
14 files changed, 1547 insertions, 236 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 6b942d9e5b74..6992ebc50c87 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -824,6 +824,41 @@ static struct bin_attribute sysfs_reset_attr = {
};
static ssize_t
+qla2x00_issue_logo(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
+ struct device, kobj)));
+ int type;
+ int rval = 0;
+ port_id_t did;
+
+ type = simple_strtol(buf, NULL, 10);
+
+ did.b.domain = (type & 0x00ff0000) >> 16;
+ did.b.area = (type & 0x0000ff00) >> 8;
+ did.b.al_pa = (type & 0x000000ff);
+
+ ql_log(ql_log_info, vha, 0x70e3, "portid=%02x%02x%02x done\n",
+ did.b.domain, did.b.area, did.b.al_pa);
+
+ ql_log(ql_log_info, vha, 0x70e4, "%s: %d\n", __func__, type);
+
+ rval = qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, did);
+ return count;
+}
+
+static struct bin_attribute sysfs_issue_logo_attr = {
+ .attr = {
+ .name = "issue_logo",
+ .mode = S_IWUSR,
+ },
+ .size = 0,
+ .write = qla2x00_issue_logo,
+};
+
+static ssize_t
qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
@@ -937,6 +972,7 @@ static struct sysfs_entry {
{ "vpd", &sysfs_vpd_attr, 1 },
{ "sfp", &sysfs_sfp_attr, 1 },
{ "reset", &sysfs_reset_attr, },
+ { "issue_logo", &sysfs_issue_logo_attr, },
{ "xgmac_stats", &sysfs_xgmac_stats_attr, 3 },
{ "dcbx_tlv", &sysfs_dcbx_tlv_attr, 3 },
{ NULL },
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 34dc9a35670b..cd0d94ea7f74 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -14,25 +14,24 @@
* | Module Init and Probe | 0x017f | 0x0146 |
* | | | 0x015b-0x0160 |
* | | | 0x016e-0x0170 |
- * | Mailbox commands | 0x118d | 0x1115-0x1116 |
- * | | | 0x111a-0x111b |
+ * | Mailbox commands | 0x1192 | |
+ * | | | |
* | Device Discovery | 0x2016 | 0x2020-0x2022, |
* | | | 0x2011-0x2012, |
* | | | 0x2099-0x20a4 |
- * | Queue Command and IO tracing | 0x3075 | 0x300b |
+ * | Queue Command and IO tracing | 0x3074 | 0x300b |
* | | | 0x3027-0x3028 |
* | | | 0x303d-0x3041 |
* | | | 0x302d,0x3033 |
* | | | 0x3036,0x3038 |
* | | | 0x303a |
* | DPC Thread | 0x4023 | 0x4002,0x4013 |
- * | Async Events | 0x508a | 0x502b-0x502f |
- * | | | 0x5047 |
+ * | Async Events | 0x5089 | 0x502b-0x502f |
* | | | 0x5084,0x5075 |
* | | | 0x503d,0x5044 |
* | | | 0x507b,0x505f |
* | Timer Routines | 0x6012 | |
- * | User Space Interactions | 0x70e2 | 0x7018,0x702e |
+ * | User Space Interactions | 0x70e65 | 0x7018,0x702e |
* | | | 0x7020,0x7024 |
* | | | 0x7039,0x7045 |
* | | | 0x7073-0x7075 |
@@ -60,15 +59,11 @@
* | | | 0xb13c-0xb140 |
* | | | 0xb149 |
* | MultiQ | 0xc00c | |
- * | Misc | 0xd300 | 0xd016-0xd017 |
- * | | | 0xd021,0xd024 |
- * | | | 0xd025,0xd029 |
- * | | | 0xd02a,0xd02e |
- * | | | 0xd031-0xd0ff |
+ * | Misc | 0xd301 | 0xd031-0xd0ff |
* | | | 0xd101-0xd1fe |
* | | | 0xd214-0xd2fe |
* | Target Mode | 0xe080 | |
- * | Target Mode Management | 0xf096 | 0xf002 |
+ * | Target Mode Management | 0xf09b | 0xf002 |
* | | | 0xf046-0xf049 |
* | Target Mode Task Management | 0x1000d | |
* ----------------------------------------------------------------------
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 388d79088b59..9872f3429e53 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -259,7 +259,7 @@
#define LOOP_DOWN_TIME 255 /* 240 */
#define LOOP_DOWN_RESET (LOOP_DOWN_TIME - 30)
-#define DEFAULT_OUTSTANDING_COMMANDS 1024
+#define DEFAULT_OUTSTANDING_COMMANDS 4096
#define MIN_OUTSTANDING_COMMANDS 128
/* ISP request and response entry counts (37-65535) */
@@ -267,11 +267,13 @@
#define REQUEST_ENTRY_CNT_2200 2048 /* Number of request entries. */
#define REQUEST_ENTRY_CNT_24XX 2048 /* Number of request entries. */
#define REQUEST_ENTRY_CNT_83XX 8192 /* Number of request entries. */
+#define RESPONSE_ENTRY_CNT_83XX 4096 /* Number of response entries.*/
#define RESPONSE_ENTRY_CNT_2100 64 /* Number of response entries.*/
#define RESPONSE_ENTRY_CNT_2300 512 /* Number of response entries.*/
#define RESPONSE_ENTRY_CNT_MQ 128 /* Number of response entries.*/
#define ATIO_ENTRY_CNT_24XX 4096 /* Number of ATIO entries. */
#define RESPONSE_ENTRY_CNT_FX00 256 /* Number of response entries.*/
+#define EXTENDED_EXCH_ENTRY_CNT 32768 /* Entries for offload case */
struct req_que;
struct qla_tgt_sess;
@@ -309,6 +311,14 @@ struct srb_cmd {
/* To identify if a srb is of T10-CRC type. @sp => srb_t pointer */
#define IS_PROT_IO(sp) (sp->flags & SRB_CRC_CTX_DSD_VALID)
+struct els_logo_payload {
+ uint8_t opcode;
+ uint8_t rsvd[3];
+ uint8_t s_id[3];
+ uint8_t rsvd1[1];
+ uint8_t wwpn[WWN_SIZE];
+};
+
/*
* SRB extensions.
*/
@@ -322,6 +332,15 @@ struct srb_iocb {
uint16_t data[2];
} logio;
struct {
+#define ELS_DCMD_TIMEOUT 20
+#define ELS_DCMD_LOGO 0x5
+ uint32_t flags;
+ uint32_t els_cmd;
+ struct completion comp;
+ struct els_logo_payload *els_logo_pyld;
+ dma_addr_t els_logo_pyld_dma;
+ } els_logo;
+ struct {
/*
* Values for flags field below are as
* defined in tsk_mgmt_entry struct
@@ -382,7 +401,7 @@ struct srb_iocb {
#define SRB_FXIOCB_DCMD 10
#define SRB_FXIOCB_BCMD 11
#define SRB_ABT_CMD 12
-
+#define SRB_ELS_DCMD 13
typedef struct srb {
atomic_t ref_count;
@@ -891,6 +910,7 @@ struct mbx_cmd_32 {
#define MBC_DISABLE_VI 0x24 /* Disable VI operation. */
#define MBC_ENABLE_VI 0x25 /* Enable VI operation. */
#define MBC_GET_FIRMWARE_OPTION 0x28 /* Get Firmware Options. */
+#define MBC_GET_MEM_OFFLOAD_CNTRL_STAT 0x34 /* Memory Offload ctrl/Stat*/
#define MBC_SET_FIRMWARE_OPTION 0x38 /* Set Firmware Options. */
#define MBC_LOOP_PORT_BYPASS 0x40 /* Loop Port Bypass. */
#define MBC_LOOP_PORT_ENABLE 0x41 /* Loop Port Enable. */
@@ -2695,11 +2715,16 @@ struct isp_operations {
struct scsi_qla_host;
+
+#define QLA83XX_RSPQ_MSIX_ENTRY_NUMBER 1 /* refer to qla83xx_msix_entries */
+
struct qla_msix_entry {
int have_irq;
uint32_t vector;
uint16_t entry;
struct rsp_que *rsp;
+ struct irq_affinity_notify irq_notify;
+ int cpuid;
};
#define WATCH_INTERVAL 1 /* number of seconds */
@@ -2910,12 +2935,15 @@ struct qlt_hw_data {
uint32_t num_qfull_cmds_dropped;
spinlock_t q_full_lock;
uint32_t leak_exchg_thresh_hold;
+ spinlock_t sess_lock;
+ int rspq_vector_cpuid;
+ spinlock_t atio_lock ____cacheline_aligned;
};
#define MAX_QFULL_CMDS_ALLOC 8192
#define Q_FULL_THRESH_HOLD_PERCENT 90
#define Q_FULL_THRESH_HOLD(ha) \
- ((ha->fw_xcb_count/100) * Q_FULL_THRESH_HOLD_PERCENT)
+ ((ha->cur_fw_xcb_count/100) * Q_FULL_THRESH_HOLD_PERCENT)
#define LEAK_EXCHG_THRESH_HOLD_PERCENT 75 /* 75 percent */
@@ -2962,10 +2990,12 @@ struct qla_hw_data {
uint32_t isp82xx_no_md_cap:1;
uint32_t host_shutting_down:1;
uint32_t idc_compl_status:1;
-
uint32_t mr_reset_hdlr_active:1;
uint32_t mr_intr_valid:1;
+
uint32_t fawwpn_enabled:1;
+ uint32_t exlogins_enabled:1;
+ uint32_t exchoffld_enabled:1;
/* 35 bits */
} flags;
@@ -3237,6 +3267,21 @@ struct qla_hw_data {
void *async_pd;
dma_addr_t async_pd_dma;
+#define ENABLE_EXTENDED_LOGIN BIT_7
+
+ /* Extended Logins */
+ void *exlogin_buf;
+ dma_addr_t exlogin_buf_dma;
+ int exlogin_size;
+
+#define ENABLE_EXCHANGE_OFFLD BIT_2
+
+ /* Exchange Offload */
+ void *exchoffld_buf;
+ dma_addr_t exchoffld_buf_dma;
+ int exchoffld_size;
+ int exchoffld_count;
+
void *swl;
/* These are used by mailbox operations. */
@@ -3279,8 +3324,14 @@ struct qla_hw_data {
#define RISC_START_ADDRESS_2100 0x1000
#define RISC_START_ADDRESS_2300 0x800
#define RISC_START_ADDRESS_2400 0x100000
- uint16_t fw_xcb_count;
- uint16_t fw_iocb_count;
+
+ uint16_t orig_fw_tgt_xcb_count;
+ uint16_t cur_fw_tgt_xcb_count;
+ uint16_t orig_fw_xcb_count;
+ uint16_t cur_fw_xcb_count;
+ uint16_t orig_fw_iocb_count;
+ uint16_t cur_fw_iocb_count;
+ uint16_t fw_max_fcf_count;
uint32_t fw_shared_ram_start;
uint32_t fw_shared_ram_end;
@@ -3323,6 +3374,9 @@ struct qla_hw_data {
uint32_t chain_offset;
struct dentry *dfs_dir;
struct dentry *dfs_fce;
+ struct dentry *dfs_tgt_counters;
+ struct dentry *dfs_fw_resource_cnt;
+
dma_addr_t fce_dma;
void *fce;
uint32_t fce_bufs;
@@ -3480,6 +3534,18 @@ struct qla_hw_data {
int allow_cna_fw_dump;
};
+struct qla_tgt_counters {
+ uint64_t qla_core_sbt_cmd;
+ uint64_t core_qla_que_buf;
+ uint64_t qla_core_ret_ctio;
+ uint64_t core_qla_snd_status;
+ uint64_t qla_core_ret_sta_ctio;
+ uint64_t core_qla_free_cmd;
+ uint64_t num_q_full_sent;
+ uint64_t num_alloc_iocb_failed;
+ uint64_t num_term_xchg_sent;
+};
+
/*
* Qlogic scsi host structure
*/
@@ -3595,6 +3661,10 @@ typedef struct scsi_qla_host {
atomic_t generation_tick;
/* Time when global fcport update has been scheduled */
int total_fcport_update_gen;
+ /* List of pending LOGOs, protected by tgt_mutex */
+ struct list_head logo_list;
+ /* List of pending PLOGI acks, protected by hw lock */
+ struct list_head plogi_ack_list;
uint32_t vp_abort_cnt;
@@ -3632,6 +3702,7 @@ typedef struct scsi_qla_host {
atomic_t vref_count;
struct qla8044_reset_template reset_tmplt;
+ struct qla_tgt_counters tgt_counters;
} scsi_qla_host_t;
#define SET_VP_IDX 1
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 15cf074ffa3c..cd8b96a4b0dd 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -13,6 +13,85 @@ static struct dentry *qla2x00_dfs_root;
static atomic_t qla2x00_dfs_root_count;
static int
+qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
+{
+ struct scsi_qla_host *vha = s->private;
+ struct qla_hw_data *ha = vha->hw;
+
+ seq_puts(s, "FW Resource count\n\n");
+ seq_printf(s, "Original TGT exchg count[%d]\n",
+ ha->orig_fw_tgt_xcb_count);
+ seq_printf(s, "current TGT exchg count[%d]\n",
+ ha->cur_fw_tgt_xcb_count);
+ seq_printf(s, "original Initiator Exchange count[%d]\n",
+ ha->orig_fw_xcb_count);
+ seq_printf(s, "Current Initiator Exchange count[%d]\n",
+ ha->cur_fw_xcb_count);
+ seq_printf(s, "Original IOCB count[%d]\n", ha->orig_fw_iocb_count);
+ seq_printf(s, "Current IOCB count[%d]\n", ha->cur_fw_iocb_count);
+ seq_printf(s, "MAX VP count[%d]\n", ha->max_npiv_vports);
+ seq_printf(s, "MAX FCF count[%d]\n", ha->fw_max_fcf_count);
+
+ return 0;
+}
+
+static int
+qla_dfs_fw_resource_cnt_open(struct inode *inode, struct file *file)
+{
+ struct scsi_qla_host *vha = inode->i_private;
+ return single_open(file, qla_dfs_fw_resource_cnt_show, vha);
+}
+
+static const struct file_operations dfs_fw_resource_cnt_ops = {
+ .open = qla_dfs_fw_resource_cnt_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int
+qla_dfs_tgt_counters_show(struct seq_file *s, void *unused)
+{
+ struct scsi_qla_host *vha = s->private;
+
+ seq_puts(s, "Target Counters\n");
+ seq_printf(s, "qla_core_sbt_cmd = %lld\n",
+ vha->tgt_counters.qla_core_sbt_cmd);
+ seq_printf(s, "qla_core_ret_sta_ctio = %lld\n",
+ vha->tgt_counters.qla_core_ret_sta_ctio);
+ seq_printf(s, "qla_core_ret_ctio = %lld\n",
+ vha->tgt_counters.qla_core_ret_ctio);
+ seq_printf(s, "core_qla_que_buf = %lld\n",
+ vha->tgt_counters.core_qla_que_buf);
+ seq_printf(s, "core_qla_snd_status = %lld\n",
+ vha->tgt_counters.core_qla_snd_status);
+ seq_printf(s, "core_qla_free_cmd = %lld\n",
+ vha->tgt_counters.core_qla_free_cmd);
+ seq_printf(s, "num alloc iocb failed = %lld\n",
+ vha->tgt_counters.num_alloc_iocb_failed);
+ seq_printf(s, "num term exchange sent = %lld\n",
+ vha->tgt_counters.num_term_xchg_sent);
+ seq_printf(s, "num Q full sent = %lld\n",
+ vha->tgt_counters.num_q_full_sent);
+
+ return 0;
+}
+
+static int
+qla_dfs_tgt_counters_open(struct inode *inode, struct file *file)
+{
+ struct scsi_qla_host *vha = inode->i_private;
+ return single_open(file, qla_dfs_tgt_counters_show, vha);
+}
+
+static const struct file_operations dfs_tgt_counters_ops = {
+ .open = qla_dfs_tgt_counters_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int
qla2x00_dfs_fce_show(struct seq_file *s, void *unused)
{
scsi_qla_host_t *vha = s->private;
@@ -146,6 +225,22 @@ create_dir:
atomic_inc(&qla2x00_dfs_root_count);
create_nodes:
+ ha->dfs_fw_resource_cnt = debugfs_create_file("fw_resource_count",
+ S_IRUSR, ha->dfs_dir, vha, &dfs_fw_resource_cnt_ops);
+ if (!ha->dfs_fw_resource_cnt) {
+ ql_log(ql_log_warn, vha, 0x00fd,
+ "Unable to create debugFS fw_resource_count node.\n");
+ goto out;
+ }
+
+ ha->dfs_tgt_counters = debugfs_create_file("tgt_counters", S_IRUSR,
+ ha->dfs_dir, vha, &dfs_tgt_counters_ops);
+ if (!ha->dfs_tgt_counters) {
+ ql_log(ql_log_warn, vha, 0xd301,
+ "Unable to create debugFS tgt_counters node.\n");
+ goto out;
+ }
+
ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, vha,
&dfs_fce_ops);
if (!ha->dfs_fce) {
@@ -161,6 +256,17 @@ int
qla2x00_dfs_remove(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
+
+ if (ha->dfs_fw_resource_cnt) {
+ debugfs_remove(ha->dfs_fw_resource_cnt);
+ ha->dfs_fw_resource_cnt = NULL;
+ }
+
+ if (ha->dfs_tgt_counters) {
+ debugfs_remove(ha->dfs_tgt_counters);
+ ha->dfs_tgt_counters = NULL;
+ }
+
if (ha->dfs_fce) {
debugfs_remove(ha->dfs_fce);
ha->dfs_fce = NULL;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 7686bfe9a4a9..0103e468e357 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -44,6 +44,8 @@ extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *);
extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *);
extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *);
+extern int qla24xx_els_dcmd_iocb(scsi_qla_host_t *, int, port_id_t);
+
extern void qla2x00_update_fcports(scsi_qla_host_t *);
extern int qla2x00_abort_isp(scsi_qla_host_t *);
@@ -117,6 +119,8 @@ extern int ql2xdontresethba;
extern uint64_t ql2xmaxlun;
extern int ql2xmdcapmask;
extern int ql2xmdenable;
+extern int ql2xexlogins;
+extern int ql2xexchoffld;
extern int qla2x00_loop_reset(scsi_qla_host_t *);
extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -135,6 +139,10 @@ extern int qla2x00_post_async_adisc_work(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_post_async_adisc_done_work(struct scsi_qla_host *,
fc_port_t *, uint16_t *);
+extern int qla2x00_set_exlogins_buffer(struct scsi_qla_host *);
+extern void qla2x00_free_exlogin_buffer(struct qla_hw_data *);
+extern int qla2x00_set_exchoffld_buffer(struct scsi_qla_host *);
+extern void qla2x00_free_exchoffld_buffer(struct qla_hw_data *);
extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);
@@ -323,8 +331,7 @@ extern int
qla2x00_get_id_list(scsi_qla_host_t *, void *, dma_addr_t, uint16_t *);
extern int
-qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *,
- uint16_t *, uint16_t *, uint16_t *, uint16_t *);
+qla2x00_get_resource_cnts(scsi_qla_host_t *);
extern int
qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map);
@@ -766,4 +773,11 @@ extern int qla8044_abort_isp(scsi_qla_host_t *);
extern int qla8044_check_fw_alive(struct scsi_qla_host *);
extern void qlt_host_reset_handler(struct qla_hw_data *ha);
+extern int qla_get_exlogin_status(scsi_qla_host_t *, uint16_t *,
+ uint16_t *);
+extern int qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr);
+extern int qla_get_exchoffld_status(scsi_qla_host_t *, uint16_t *, uint16_t *);
+extern int qla_set_exchoffld_mem_cfg(scsi_qla_host_t *, dma_addr_t);
+extern void qlt_handle_abts_recv(struct scsi_qla_host *, response_t *);
+
#endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 16a1935cc9c1..52a87657c7dd 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -1766,10 +1766,10 @@ qla2x00_alloc_outstanding_cmds(struct qla_hw_data *ha, struct req_que *req)
(ql2xmultique_tag || ql2xmaxqueues > 1)))
req->num_outstanding_cmds = DEFAULT_OUTSTANDING_COMMANDS;
else {
- if (ha->fw_xcb_count <= ha->fw_iocb_count)
- req->num_outstanding_cmds = ha->fw_xcb_count;
+ if (ha->cur_fw_xcb_count <= ha->cur_fw_iocb_count)
+ req->num_outstanding_cmds = ha->cur_fw_xcb_count;
else
- req->num_outstanding_cmds = ha->fw_iocb_count;
+ req->num_outstanding_cmds = ha->cur_fw_iocb_count;
}
req->outstanding_cmds = kzalloc(sizeof(srb_t *) *
@@ -1843,9 +1843,23 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
ql_dbg(ql_dbg_init, vha, 0x00ca,
"Starting firmware.\n");
+ if (ql2xexlogins)
+ ha->flags.exlogins_enabled = 1;
+
+ if (ql2xexchoffld)
+ ha->flags.exchoffld_enabled = 1;
+
rval = qla2x00_execute_fw(vha, srisc_address);
/* Retrieve firmware information. */
if (rval == QLA_SUCCESS) {
+ rval = qla2x00_set_exlogins_buffer(vha);
+ if (rval != QLA_SUCCESS)
+ goto failed;
+
+ rval = qla2x00_set_exchoffld_buffer(vha);
+ if (rval != QLA_SUCCESS)
+ goto failed;
+
enable_82xx_npiv:
fw_major_version = ha->fw_major_version;
if (IS_P3P_TYPE(ha))
@@ -1864,9 +1878,7 @@ enable_82xx_npiv:
ha->max_npiv_vports =
MIN_MULTI_ID_FABRIC - 1;
}
- qla2x00_get_resource_cnts(vha, NULL,
- &ha->fw_xcb_count, NULL, &ha->fw_iocb_count,
- &ha->max_npiv_vports, NULL);
+ qla2x00_get_resource_cnts(vha);
/*
* Allocate the array of outstanding commands
@@ -2248,7 +2260,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
if (IS_FWI2_CAPABLE(ha)) {
mid_init_cb->options = cpu_to_le16(BIT_1);
mid_init_cb->init_cb.execution_throttle =
- cpu_to_le16(ha->fw_xcb_count);
+ cpu_to_le16(ha->cur_fw_xcb_count);
/* D-Port Status */
if (IS_DPORT_CAPABLE(ha))
mid_init_cb->init_cb.firmware_options_1 |=
@@ -3053,6 +3065,26 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
atomic_set(&vha->loop_state, LOOP_READY);
ql_dbg(ql_dbg_disc, vha, 0x2069,
"LOOP READY.\n");
+
+ /*
+ * Process any ATIO queue entries that came in
+ * while we weren't online.
+ */
+ if (qla_tgt_mode_enabled(vha)) {
+ if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) {
+ spin_lock_irqsave(&ha->tgt.atio_lock,
+ flags);
+ qlt_24xx_process_atio_queue(vha, 0);
+ spin_unlock_irqrestore(
+ &ha->tgt.atio_lock, flags);
+ } else {
+ spin_lock_irqsave(&ha->hardware_lock,
+ flags);
+ qlt_24xx_process_atio_queue(vha, 1);
+ spin_unlock_irqrestore(
+ &ha->hardware_lock, flags);
+ }
+ }
}
}
@@ -4907,7 +4939,6 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
struct rsp_que *rsp = ha->rsp_q_map[0];
- unsigned long flags;
/* If firmware needs to be loaded */
if (qla2x00_isp_firmware(vha)) {
@@ -4929,17 +4960,6 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
/* Issue a marker after FW becomes ready. */
qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
- vha->flags.online = 1;
-
- /*
- * Process any ATIO queue entries that came in
- * while we weren't online.
- */
- spin_lock_irqsave(&ha->hardware_lock, flags);
- if (qla_tgt_mode_enabled(vha))
- qlt_24xx_process_atio_queue(vha);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
}
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index fee9eb7c8a60..a6b7f1588aa4 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -258,6 +258,8 @@ qla2x00_init_timer(srb_t *sp, unsigned long tmo)
if ((IS_QLAFX00(sp->fcport->vha->hw)) &&
(sp->type == SRB_FXIOCB_DCMD))
init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp);
+ if (sp->type == SRB_ELS_DCMD)
+ init_completion(&sp->u.iocb_cmd.u.els_logo.comp);
}
static inline int
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index c49df34e9b35..b41265a75ed5 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -1868,6 +1868,7 @@ skip_cmd_array:
}
queuing_error:
+ vha->tgt_counters.num_alloc_iocb_failed++;
return pkt;
}
@@ -2010,6 +2011,190 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
}
static void
+qla2x00_els_dcmd_sp_free(void *ptr, void *data)
+{
+ struct scsi_qla_host *vha = (scsi_qla_host_t *)ptr;
+ struct qla_hw_data *ha = vha->hw;
+ srb_t *sp = (srb_t *)data;
+ struct srb_iocb *elsio = &sp->u.iocb_cmd;
+
+ kfree(sp->fcport);
+
+ if (elsio->u.els_logo.els_logo_pyld)
+ dma_free_coherent(&ha->pdev->dev, DMA_POOL_SIZE,
+ elsio->u.els_logo.els_logo_pyld,
+ elsio->u.els_logo.els_logo_pyld_dma);
+
+ del_timer(&elsio->timer);
+ qla2x00_rel_sp(vha, sp);
+}
+
+static void
+qla2x00_els_dcmd_iocb_timeout(void *data)
+{
+ srb_t *sp = (srb_t *)data;
+ struct srb_iocb *lio = &sp->u.iocb_cmd;
+ fc_port_t *fcport = sp->fcport;
+ struct scsi_qla_host *vha = fcport->vha;
+ struct qla_hw_data *ha = vha->hw;
+ unsigned long flags = 0;
+
+ ql_dbg(ql_dbg_io, vha, 0x3069,
+ "%s Timeout, hdl=%x, portid=%02x%02x%02x\n",
+ sp->name, sp->handle, fcport->d_id.b.domain, fcport->d_id.b.area,
+ fcport->d_id.b.al_pa);
+
+ /* Abort the exchange */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ if (ha->isp_ops->abort_command(sp)) {
+ ql_dbg(ql_dbg_io, vha, 0x3070,
+ "mbx abort_command failed.\n");
+ } else {
+ ql_dbg(ql_dbg_io, vha, 0x3071,
+ "mbx abort_command success.\n");
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ complete(&lio->u.els_logo.comp);
+}
+
+static void
+qla2x00_els_dcmd_sp_done(void *data, void *ptr, int res)
+{
+ srb_t *sp = (srb_t *)ptr;
+ fc_port_t *fcport = sp->fcport;
+ struct srb_iocb *lio = &sp->u.iocb_cmd;
+ struct scsi_qla_host *vha = fcport->vha;
+
+ ql_dbg(ql_dbg_io, vha, 0x3072,
+ "%s hdl=%x, portid=%02x%02x%02x done\n",
+ sp->name, sp->handle, fcport->d_id.b.domain,
+ fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+ complete(&lio->u.els_logo.comp);
+}
+
+int
+qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
+ port_id_t remote_did)
+{
+ srb_t *sp;
+ fc_port_t *fcport = NULL;
+ struct srb_iocb *elsio = NULL;
+ struct qla_hw_data *ha = vha->hw;
+ struct els_logo_payload logo_pyld;
+ int rval = QLA_SUCCESS;
+
+ fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
+ if (!fcport) {
+ ql_log(ql_log_info, vha, 0x70e5, "fcport allocation failed\n");
+ return -ENOMEM;
+ }
+
+ /* Alloc SRB structure */
+ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+ if (!sp) {
+ kfree(fcport);
+ ql_log(ql_log_info, vha, 0x70e6,
+ "SRB allocation failed\n");
+ return -ENOMEM;
+ }
+
+ elsio = &sp->u.iocb_cmd;
+ fcport->loop_id = 0xFFFF;
+ fcport->d_id.b.domain = remote_did.b.domain;
+ fcport->d_id.b.area = remote_did.b.area;
+ fcport->d_id.b.al_pa = remote_did.b.al_pa;
+
+ ql_dbg(ql_dbg_io, vha, 0x3073, "portid=%02x%02x%02x done\n",
+ fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+ sp->type = SRB_ELS_DCMD;
+ sp->name = "ELS_DCMD";
+ sp->fcport = fcport;
+ qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT);
+ elsio->timeout = qla2x00_els_dcmd_iocb_timeout;
+ sp->done = qla2x00_els_dcmd_sp_done;
+ sp->free = qla2x00_els_dcmd_sp_free;
+
+ elsio->u.els_logo.els_logo_pyld = dma_alloc_coherent(&ha->pdev->dev,
+ DMA_POOL_SIZE, &elsio->u.els_logo.els_logo_pyld_dma,
+ GFP_KERNEL);
+
+ if (!elsio->u.els_logo.els_logo_pyld) {
+ sp->free(vha, sp);
+ return QLA_FUNCTION_FAILED;
+ }
+
+ memset(&logo_pyld, 0, sizeof(struct els_logo_payload));
+
+ elsio->u.els_logo.els_cmd = els_opcode;
+ logo_pyld.opcode = els_opcode;
+ logo_pyld.s_id[0] = vha->d_id.b.al_pa;
+ logo_pyld.s_id[1] = vha->d_id.b.area;
+ logo_pyld.s_id[2] = vha->d_id.b.domain;
+ host_to_fcp_swap(logo_pyld.s_id, sizeof(uint32_t));
+ memcpy(&logo_pyld.wwpn, vha->port_name, WWN_SIZE);
+
+ memcpy(elsio->u.els_logo.els_logo_pyld, &logo_pyld,
+ sizeof(struct els_logo_payload));
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS) {
+ sp->free(vha, sp);
+ return QLA_FUNCTION_FAILED;
+ }
+
+ ql_dbg(ql_dbg_io, vha, 0x3074,
+ "%s LOGO sent, hdl=%x, loopid=%x, portid=%02x%02x%02x.\n",
+ sp->name, sp->handle, fcport->loop_id, fcport->d_id.b.domain,
+ fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+ wait_for_completion(&elsio->u.els_logo.comp);
+
+ sp->free(vha, sp);
+ return rval;
+}
+
+static void
+qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
+{
+ scsi_qla_host_t *vha = sp->fcport->vha;
+ struct srb_iocb *elsio = &sp->u.iocb_cmd;
+
+ els_iocb->entry_type = ELS_IOCB_TYPE;
+ els_iocb->entry_count = 1;
+ els_iocb->sys_define = 0;
+ els_iocb->entry_status = 0;
+ els_iocb->handle = sp->handle;
+ els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+ els_iocb->tx_dsd_count = 1;
+ els_iocb->vp_index = vha->vp_idx;
+ els_iocb->sof_type = EST_SOFI3;
+ els_iocb->rx_dsd_count = 0;
+ els_iocb->opcode = elsio->u.els_logo.els_cmd;
+
+ els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
+ els_iocb->port_id[1] = sp->fcport->d_id.b.area;
+ els_iocb->port_id[2] = sp->fcport->d_id.b.domain;
+ els_iocb->control_flags = 0;
+
+ els_iocb->tx_byte_count = sizeof(struct els_logo_payload);
+ els_iocb->tx_address[0] =
+ cpu_to_le32(LSD(elsio->u.els_logo.els_logo_pyld_dma));
+ els_iocb->tx_address[1] =
+ cpu_to_le32(MSD(elsio->u.els_logo.els_logo_pyld_dma));
+ els_iocb->tx_len = cpu_to_le32(sizeof(struct els_logo_payload));
+
+ els_iocb->rx_byte_count = 0;
+ els_iocb->rx_address[0] = 0;
+ els_iocb->rx_address[1] = 0;
+ els_iocb->rx_len = 0;
+
+ sp->fcport->vha->qla_stats.control_requests++;
+}
+
+static void
qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
{
struct fc_bsg_job *bsg_job = sp->u.bsg_job;
@@ -2623,6 +2808,9 @@ qla2x00_start_sp(srb_t *sp)
qlafx00_abort_iocb(sp, pkt) :
qla24xx_abort_iocb(sp, pkt);
break;
+ case SRB_ELS_DCMD:
+ qla24xx_els_logo_iocb(sp, pkt);
+ break;
default:
break;
}
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index ccf6a7f99024..d4d65eb0e9b4 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -18,6 +18,10 @@ static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
sts_entry_t *);
+static void qla_irq_affinity_notify(struct irq_affinity_notify *,
+ const cpumask_t *);
+static void qla_irq_affinity_release(struct kref *);
+
/**
* qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
@@ -1418,6 +1422,12 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
case SRB_CT_CMD:
type = "ct pass-through";
break;
+ case SRB_ELS_DCMD:
+ type = "Driver ELS logo";
+ ql_dbg(ql_dbg_user, vha, 0x5047,
+ "Completing %s: (%p) type=%d.\n", type, sp, sp->type);
+ sp->done(vha, sp, 0);
+ return;
default:
ql_dbg(ql_dbg_user, vha, 0x503e,
"Unrecognized SRB: (%p) type=%d.\n",