aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/qla2xxx')
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c86
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c10
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h118
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h28
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h22
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c18
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c183
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c55
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c78
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c263
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c14
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.c7
-rw-r--r--drivers/scsi/qla2xxx/qla_nvme.c161
-rw-r--r--drivers/scsi/qla2xxx/qla_nvme.h17
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c155
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c29
-rw-r--r--drivers/scsi/qla2xxx/qla_target.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_tmpl.c19
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
19 files changed, 942 insertions, 325 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 08a1feb3a195..9ce28c4f9812 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -318,6 +318,8 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
return -EINVAL;
if (start > ha->optrom_size)
return -EINVAL;
+ if (size > ha->optrom_size - start)
+ size = ha->optrom_size - start;
mutex_lock(&ha->optrom_mutex);
switch (val) {
@@ -343,8 +345,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
}
ha->optrom_region_start = start;
- ha->optrom_region_size = start + size > ha->optrom_size ?
- ha->optrom_size - start : size;
+ ha->optrom_region_size = start + size;
ha->optrom_state = QLA_SREADING;
ha->optrom_buffer = vmalloc(ha->optrom_region_size);
@@ -417,8 +418,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
}
ha->optrom_region_start = start;
- ha->optrom_region_size = start + size > ha->optrom_size ?
- ha->optrom_size - start : size;
+ ha->optrom_region_size = start + size;
ha->optrom_state = QLA_SWRITING;
ha->optrom_buffer = vmalloc(ha->optrom_region_size);
@@ -565,47 +565,17 @@ qla2x00_sysfs_read_sfp(struct file *filp, struct kobject *kobj,
{
struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
- struct qla_hw_data *ha = vha->hw;
- uint16_t iter, addr, offset;
int rval;
- if (!capable(CAP_SYS_ADMIN) || off != 0 || count != SFP_DEV_SIZE * 2)
+ if (!capable(CAP_SYS_ADMIN) || off != 0 || count < SFP_DEV_SIZE)
return 0;
- if (ha->sfp_data)
- goto do_read;
-
- ha->sfp_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
- &ha->sfp_data_dma);
- if (!ha->sfp_data) {
- ql_log(ql_log_warn, vha, 0x706c,
- "Unable to allocate memory for SFP read-data.\n");
+ if (qla2x00_reset_active(vha))
return 0;
- }
-
-do_read:
- memset(ha->sfp_data, 0, SFP_BLOCK_SIZE);
- addr = 0xa0;
- for (iter = 0, offset = 0; iter < (SFP_DEV_SIZE * 2) / SFP_BLOCK_SIZE;
- iter++, offset += SFP_BLOCK_SIZE) {
- if (iter == 4) {
- /* Skip to next device address. */
- addr = 0xa2;
- offset = 0;
- }
-
- rval = qla2x00_read_sfp(vha, ha->sfp_data_dma, ha->sfp_data,
- addr, offset, SFP_BLOCK_SIZE, BIT_1);
- if (rval != QLA_SUCCESS) {
- ql_log(ql_log_warn, vha, 0x706d,
- "Unable to read SFP data (%x/%x/%x).\n", rval,
- addr, offset);
- return -EIO;
- }
- memcpy(buf, ha->sfp_data, SFP_BLOCK_SIZE);
- buf += SFP_BLOCK_SIZE;
- }
+ rval = qla2x00_read_sfp_dev(vha, buf, count);
+ if (rval)
+ return -EIO;
return count;
}
@@ -615,7 +585,7 @@ static struct bin_attribute sysfs_sfp_attr = {
.name = "sfp",
.mode = S_IRUSR | S_IWUSR,
},
- .size = SFP_DEV_SIZE * 2,
+ .size = SFP_DEV_SIZE,
.read = qla2x00_sysfs_read_sfp,
};
@@ -1511,6 +1481,38 @@ qla2x00_pep_version_show(struct device *dev, struct device_attribute *attr,
ha->pep_version[0], ha->pep_version[1], ha->pep_version[2]);
}
+static ssize_t
+qla2x00_min_link_speed_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!IS_QLA27XX(ha))
+ return scnprintf(buf, PAGE_SIZE, "\n");
+
+ return scnprintf(buf, PAGE_SIZE, "%s\n",
+ ha->min_link_speed == 5 ? "32Gps" :
+ ha->min_link_speed == 4 ? "16Gps" :
+ ha->min_link_speed == 3 ? "8Gps" :
+ ha->min_link_speed == 2 ? "4Gps" :
+ ha->min_link_speed != 0 ? "unknown" : "");
+}
+
+static ssize_t
+qla2x00_max_speed_sup_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!IS_QLA27XX(ha))
+ return scnprintf(buf, PAGE_SIZE, "\n");
+
+ return scnprintf(buf, PAGE_SIZE, "%s\n",
+ ha->max_speed_sup ? "32Gps" : "16Gps");
+}
+
static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL);
static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
@@ -1556,6 +1558,8 @@ static DEVICE_ATTR(allow_cna_fw_dump, S_IRUGO | S_IWUSR,
qla2x00_allow_cna_fw_dump_show,
qla2x00_allow_cna_fw_dump_store);
static DEVICE_ATTR(pep_version, S_IRUGO, qla2x00_pep_version_show, NULL);
+static DEVICE_ATTR(min_link_speed, S_IRUGO, qla2x00_min_link_speed_show, NULL);
+static DEVICE_ATTR(max_speed_sup, S_IRUGO, qla2x00_max_speed_sup_show, NULL);
struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_driver_version,
@@ -1590,6 +1594,8 @@ struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_fw_dump_size,
&dev_attr_allow_cna_fw_dump,
&dev_attr_pep_version,
+ &dev_attr_min_link_speed,
+ &dev_attr_max_speed_sup,
NULL,
};
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 26751d34bcf2..3e9dc54b89a3 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -14,7 +14,7 @@
* | Module Init and Probe | 0x0193 | 0x0146 |
* | | | 0x015b-0x0160 |
* | | | 0x016e |
- * | Mailbox commands | 0x1199 | 0x1193 |
+ * | Mailbox commands | 0x1205 | 0x11a2-0x11ff |
* | Device Discovery | 0x2134 | 0x210e-0x2116 |
* | | | 0x211a |
* | | | 0x211c-0x2128 |
@@ -41,7 +41,7 @@
* | | | 0x70ad-0x70ae |
* | | | 0x70d0-0x70d6 |
* | | | 0x70d7-0x70db |
- * | Task Management | 0x8042 | 0x8000,0x800b |
+ * | Task Management | 0x8042 | 0x8000 |
* | | | 0x8019 |
* | | | 0x8025,0x8026 |
* | | | 0x8031,0x8032 |
@@ -2520,8 +2520,6 @@ qla83xx_fw_dump_failed:
static inline int
ql_mask_match(uint32_t level)
{
- if (ql2xextended_error_logging == 1)
- ql2xextended_error_logging = QL_DBG_DEFAULT1_MASK;
return (level & ql2xextended_error_logging) == level;
}
@@ -2738,9 +2736,9 @@ ql_dump_regs(uint32_t level, scsi_qla_host_t *vha, int32_t id)
mbx_reg = MAILBOX_REG(ha, reg, 0);
ql_dbg(level, vha, id, "Mailbox registers:\n");
- for (i = 0; i < 6; i++)
+ for (i = 0; i < 6; i++, mbx_reg++)
ql_dbg(level, vha, id,
- "mbox[%d] 0x%04x\n", i, RD_REG_WORD(mbx_reg++));
+ "mbox[%d] 0x%04x\n", i, RD_REG_WORD(mbx_reg));
}
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 0730b10b4280..486c075998f6 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -427,6 +427,7 @@ struct srb_iocb {
enum nvmefc_fcp_datadir dir;
uint32_t dl;
uint32_t timeout_sec;
+ struct list_head entry;
} nvme;
} u;
@@ -470,7 +471,7 @@ typedef struct srb {
uint8_t cmd_type;
uint8_t pad[3];
atomic_t ref_count;
- wait_queue_head_t nvme_ls_waitQ;
+ wait_queue_head_t nvme_ls_waitq;
struct fc_port *fcport;
struct scsi_qla_host *vha;
uint32_t handle;
@@ -901,6 +902,7 @@ struct mbx_cmd_32 {
#define MBA_SHUTDOWN_REQUESTED 0x8062 /* Shutdown Requested */
#define MBA_TEMPERATURE_ALERT 0x8070 /* Temperature Alert */
#define MBA_DPORT_DIAGNOSTICS 0x8080 /* D-port Diagnostics */
+#define MBA_TRANS_INSERT 0x8130 /* Transceiver Insertion */
#define MBA_FW_INIT_FAILURE 0x8401 /* Firmware initialization failure */
#define MBA_MIRROR_LUN_CHANGE 0x8402 /* Mirror LUN State Change
Notification */
@@ -977,6 +979,7 @@ struct mbx_cmd_32 {
#define MBC_ABORT_TARGET 0x17 /* Abort target (ID). */
#define MBC_RESET 0x18 /* Reset. */
#define MBC_GET_ADAPTER_LOOP_ID 0x20 /* Get loop id of ISP2200. */
+#define MBC_GET_SET_ZIO_THRESHOLD 0x21 /* Get/SET ZIO THRESHOLD. */
#define MBC_GET_RETRY_COUNT 0x22 /* Get f/w retry cnt/delay. */
#define MBC_DISABLE_VI 0x24 /* Disable VI operation. */
#define MBC_ENABLE_VI 0x25 /* Enable VI operation. */
@@ -2301,8 +2304,7 @@ typedef struct fc_port {
unsigned int login_succ:1;
struct work_struct nvme_del_work;
- atomic_t nvme_ref_count;
- wait_queue_head_t nvme_waitQ;
+ struct completion nvme_del_done;
uint32_t nvme_prli_service_param;
#define NVME_PRLI_SP_CONF BIT_7
#define NVME_PRLI_SP_INITIATOR BIT_5
@@ -3338,6 +3340,7 @@ struct qla_qpair {
struct work_struct q_work;
struct list_head qp_list_elem; /* vha->qp_list */
struct list_head hints_list;
+ struct list_head nvme_done_list;
uint16_t cpuid;
struct qla_tgt_counters tgt_counters;
};
@@ -3463,8 +3466,15 @@ struct qla_hw_data {
uint32_t n2n_ae:1;
uint32_t fw_started:1;
uint32_t fw_init_done:1;
+
+ uint32_t detected_lr_sfp:1;
+ uint32_t using_lr_setting:1;
} flags;
+ uint16_t long_range_distance; /* 32G & above */
+#define LR_DISTANCE_5K 1
+#define LR_DISTANCE_10K 0
+
/* This spinlock is used to protect "io transactions", you must
* acquire it before doing any IO to the card, eg with RD_REG*() and
* WRT_REG*() for the duration of your entire commandtransaction.
@@ -3712,7 +3722,7 @@ struct qla_hw_data {
struct sns_cmd_pkt *sns_cmd;
dma_addr_t sns_cmd_dma;
-#define SFP_DEV_SIZE 256
+#define SFP_DEV_SIZE 512
#define SFP_BLOCK_SIZE 64
void *sfp_data;
dma_addr_t sfp_data_dma;
@@ -4017,8 +4027,20 @@ struct qla_hw_data {
struct qlt_hw_data tgt;
int allow_cna_fw_dump;
+ uint32_t fw_ability_mask;
+ uint16_t min_link_speed;
+ uint16_t max_speed_sup;
+
+ atomic_t nvme_active_aen_cnt;
+ uint16_t nvme_last_rptd_aen; /* Last recorded aen count */
};
+#define FW_ABILITY_MAX_SPEED_MASK 0xFUL
+#define FW_ABILITY_MAX_SPEED_16G 0x0
+#define FW_ABILITY_MAX_SPEED_32G 0x1
+#define FW_ABILITY_MAX_SPEED(ha) \
+ (ha->fw_ability_mask & FW_ABILITY_MAX_SPEED_MASK)
+
/*
* Qlogic scsi host structure
*/
@@ -4089,6 +4111,8 @@ typedef struct scsi_qla_host {
#define FX00_CRITEMP_RECOVERY 25
#define FX00_HOST_INFO_RESEND 26
#define QPAIR_ONLINE_CHECK_NEEDED 27
+#define SET_ZIO_THRESHOLD_NEEDED 28
+#define DETECT_SFP_CHANGE 29
unsigned long pci_flags;
#define PFLG_DISCONNECTED 0 /* PCI device removed */
@@ -4129,8 +4153,7 @@ typedef struct scsi_qla_host {
uint8_t fabric_node_name[WWN_SIZE];
struct nvme_fc_local_port *nvme_local_port;
- atomic_t nvme_ref_count;
- wait_queue_head_t nvme_waitQ;
+ struct completion nvme_del_done;
struct list_head nvme_rport_list;
atomic_t nvme_active_aen_cnt;
uint16_t nvme_last_rptd_aen;
@@ -4199,6 +4222,7 @@ typedef struct scsi_qla_host {
int fcport_count;
wait_queue_head_t fcport_waitQ;
wait_queue_head_t vref_waitq;
+ uint8_t min_link_speed_feat;
} scsi_qla_host_t;
struct qla27xx_image_status {
@@ -4373,6 +4397,88 @@ enum nexus_wait_type {
WAIT_LUN,
};
+/* Refer to SNIA SFF 8247 */
+struct sff_8247_a0 {
+ u8 txid; /* transceiver id */
+ u8 ext_txid;
+ u8 connector;
+ /* compliance code */
+ u8 eth_infi_cc3; /* ethernet, inifiband */
+ u8 sonet_cc4[2];
+ u8 eth_cc6;
+ /* link length */
+#define FC_LL_VL BIT_7 /* very long */
+#define FC_LL_S BIT_6 /* Short */
+#define FC_LL_I BIT_5 /* Intermidiate*/
+#define FC_LL_L BIT_4 /* Long */
+#define FC_LL_M BIT_3 /* Medium */
+#define FC_LL_SA BIT_2 /* ShortWave laser */
+#define FC_LL_LC BIT_1 /* LongWave laser */
+#define FC_LL_EL BIT_0 /* Electrical inter enclosure */
+ u8 fc_ll_cc7;
+ /* FC technology */
+#define FC_TEC_EL BIT_7 /* Electrical inter enclosure */
+#define FC_TEC_SN BIT_6 /* short wave w/o OFC */
+#define FC_TEC_SL BIT_5 /* short wave with OFC */
+#define FC_TEC_LL BIT_4 /* Longwave Laser */
+#define FC_TEC_ACT BIT_3 /* Active cable */
+#define FC_TEC_PAS BIT_2 /* Passive cable */
+ u8 fc_tec_cc8;
+ /* Transmission Media */
+#define FC_MED_TW BIT_7 /* Twin Ax */
+#define FC_MED_TP BIT_6 /* Twited Pair */
+#define FC_MED_MI BIT_5 /* Min Coax */
+#define FC_MED_TV BIT_4 /* Video Coax */
+#define FC_MED_M6 BIT_3 /* Multimode, 62.5um */
+#define FC_MED_M5 BIT_2 /* Multimode, 50um */
+#define FC_MED_SM BIT_0 /* Single Mode */
+ u8 fc_med_cc9;
+ /* speed FC_SP_12: 12*100M = 1200 MB/s */
+#define FC_SP_12 BIT_7
+#define FC_SP_8 BIT_6
+#define FC_SP_16 BIT_5
+#define FC_SP_4 BIT_4
+#define FC_SP_32 BIT_3
+#define FC_SP_2 BIT_2
+#define FC_SP_1 BIT_0
+ u8 fc_sp_cc10;
+ u8 encode;
+ u8 bitrate;
+ u8 rate_id;
+ u8 length_km; /* offset 14/eh */
+ u8 length_100m;
+ u8 length_50um_10m;
+ u8 length_62um_10m;
+ u8 length_om4_10m;
+ u8 length_om3_10m;
+#define SFF_VEN_NAME_LEN 16
+ u8 vendor_name[SFF_VEN_NAME_LEN]; /* offset 20/14h */
+ u8 tx_compat;
+ u8 vendor_oui[3];
+#define SFF_PART_NAME_LEN 16
+ u8 vendor_pn[SFF_PART_NAME_LEN]; /* part number */
+ u8 vendor_rev[4];
+ u8 wavelength[2];
+ u8 resv;
+ u8 cc_base;
+ u8 options[2]; /* offset 64 */
+ u8 br_max;
+ u8 br_min;
+ u8 vendor_sn[16];
+ u8 date_code[8];
+ u8 diag;
+ u8 enh_options;
+ u8 sff_revision;
+ u8 cc_ext;
+ u8 vendor_specific[32];
+ u8 resv2[128];
+};
+
+#define AUTO_DETECT_SFP_SUPPORT(_vha)\
+ (ql2xautodetectsfp && !_vha->vp_idx && \
+ (IS_QLA25XX(_vha->hw) || IS_QLA81XX(_vha->hw) ||\
+ IS_QLA83XX(_vha->hw) || IS_QLA27XX(_vha->hw)))
+
#define USER_CTRL_IRQ(_ha) (ql2xuctrlirq && QLA_TGT_MODE_ENABLED() && \
(IS_QLA27XX(_ha) || IS_QLA83XX(_ha)))
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index b9c9886e8b1d..bec641aae7b3 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -1699,6 +1699,15 @@ struct access_chip_rsp_84xx {
#define FAC_OPT_CMD_UNLOCK_SEMAPHORE 0x04
#define FAC_OPT_CMD_GET_SECTOR_SIZE 0x05
+/* enhanced features bit definitions */
+#define NEF_LR_DIST_ENABLE BIT_0
+
+/* LR Distance bit positions */
+#define LR_DIST_NV_POS 2
+#define LR_DIST_FW_POS 12
+#define LR_DIST_FW_SHIFT (LR_DIST_FW_POS - LR_DIST_NV_POS)
+#define LR_DIST_FW_FIELD(x) ((x) << LR_DIST_FW_SHIFT & 0xf000)
+
struct nvram_81xx {
/* NVRAM header. */
uint8_t id[4];
@@ -1745,7 +1754,9 @@ struct nvram_81xx {
uint16_t reserved_6_3[14];
/* Offset 192. */
- uint16_t reserved_7[32];
+ uint8_t min_link_speed;
+ uint8_t reserved_7_0;
+ uint16_t reserved_7[31];
/*
* BIT 0 = Enable spinup delay
@@ -1839,16 +1850,13 @@ struct nvram_81xx {
uint8_t reserved_21[16];
uint16_t reserved_22[3];
- /*
- * BIT 0 = Extended BB credits for LR
- * BIT 1 = Virtual Fabric Enable
- * BIT 2 = Enhanced Features Unused
- * BIT 3-7 = Enhanced Features Reserved
+ /* Offset 406 (0x196) Enhanced Features
+ * BIT 0 = Extended BB credits for LR
+ * BIT 1 = Virtual Fabric Enable
+ * BIT 2-5 = Distance Support if BIT 0 is on
+ * BIT 6-15 = Unused
*/
- /* Enhanced Features */
- uint8_t enhanced_features;
-
- uint8_t reserved_23;
+ uint16_t enhanced_features;
uint16_t reserved_24[4];
/* Offset 416. */
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index cadb6e3baacc..f852ca60c49f 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -10,17 +10,6 @@
#include <linux/interrupt.h>
/*
- * Global functions prototype in qla_nvme.c source file.
- */
-extern void qla_nvme_register_hba(scsi_qla_host_t *);
-extern int qla_nvme_register_remote(scsi_qla_host_t *, fc_port_t *);
-extern void qla_nvme_delete(scsi_qla_host_t *);
-extern void qla_nvme_abort(struct qla_hw_data *, srb_t *sp);
-extern void qla24xx_nvme_ls4_iocb(scsi_qla_host_t *, struct pt_ls4_request *,
- struct req_que *);
-extern void qla24xx_async_gffid_sp_done(void *, int);
-
-/*
* Global Function Prototypes in qla_init.c source file.
*/
extern int qla2x00_initialize_adapter(scsi_qla_host_t *);
@@ -116,13 +105,15 @@ int qla24xx_async_notify_ack(scsi_qla_host_t *, fc_port_t *,
int qla24xx_post_newsess_work(struct scsi_qla_host *, port_id_t *, u8 *,
void *);
int qla24xx_fcport_handle_login(struct scsi_qla_host *, fc_port_t *);
-
+int qla24xx_detect_sfp(scsi_qla_host_t *vha);
+int qla24xx_post_gpdb_work(struct scsi_qla_host *, fc_port_t *, u8);
/*
* Global Data in qla_os.c source file.
*/
extern char qla2x00_version_str[];
extern struct kmem_cache *srb_cachep;
+extern struct kmem_cache *qla_tgt_plogi_cachep;
extern int ql2xlogintimeout;
extern int qlport_down_retry;
@@ -153,6 +144,7 @@ extern int ql2xfwholdabts;
extern int ql2xmvasynctoatio;
extern int ql2xuctrlirq;
extern int ql2xnvmeenable;
+extern int ql2xautodetectsfp;
extern int qla2x00_loop_reset(scsi_qla_host_t *);
extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -495,6 +487,9 @@ int qla24xx_gidlist_wait(struct scsi_qla_host *, void *, dma_addr_t,
int __qla24xx_parse_gpdb(struct scsi_qla_host *, fc_port_t *,
struct port_database_24xx *);
+extern int qla27xx_get_zio_threshold(scsi_qla_host_t *, uint16_t *);
+extern int qla27xx_set_zio_threshold(scsi_qla_host_t *, uint16_t);
+
/*
* Global Function Prototypes in qla_isr.c source file.
*/
@@ -804,6 +799,7 @@ extern char *qdev_state(uint32_t);
extern void qla82xx_clear_pending_mbx(scsi_qla_host_t *);
extern int qla82xx_read_temperature(scsi_qla_host_t *);
extern int qla8044_read_temperature(scsi_qla_host_t *);
+extern int qla2x00_read_sfp_dev(struct scsi_qla_host *, char *, int);
/* BSG related functions */
extern int qla24xx_bsg_request(struct bsg_job *);
@@ -873,4 +869,6 @@ void qlt_update_host_map(struct scsi_qla_host *, port_id_t);
void qlt_remove_target_resources(struct qla_hw_data *);
void qlt_clr_qp_table(struct scsi_qla_host *vha);
+void qla_nvme_cmpl_io(struct srb_iocb *);
+
#endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index b323a7c71eda..bc3db6abc9a0 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -2816,13 +2816,19 @@ void qla24xx_handle_gidpn_event(scsi_qla_host_t *vha, struct event_arg *ea)
case MODE_INITIATOR:
case MODE_DUAL:
default:
+ ql_dbg(ql_dbg_disc, vha, 0x201f,
+ "%s %d %8phC post %s\n", __func__,
+ __LINE__, fcport->port_name,
+ (atomic_read(&fcport->state) ==
+ FCS_ONLINE) ? "gpdb" : "gnl");
+
if (atomic_read(&fcport->state) ==
FCS_ONLINE)
- break;
- ql_dbg(ql_dbg_disc, vha, 0x201f,
- "%s %d %8phC post gnl\n",
- __func__, __LINE__, fcport->port_name);
- qla24xx_post_gnl_work(vha, fcport);
+ qla24xx_post_gpdb_work(vha,
+ fcport, PDO_FORCE_ADISC);
+ else
+ qla24xx_post_gnl_work(vha,
+ fcport);
break;
}
} else { /* fcport->d_id.b24 != ea->id.b24 */
@@ -3080,7 +3086,7 @@ int qla24xx_async_gpsc(scsi_qla_host_t *vha, fc_port_t *fcport)
GPSC_RSP_SIZE);
/* GPSC req */
- memcpy(ct_req->req.gpsc.port_name, fcport->port_name,
+ memcpy(ct_req->req.gpsc.port_name, fcport->fabric_port_name,
WWN_SIZE);
sp->u.iocb_cmd.u.ctarg.req = fcport->ct_desc.ct_sns;
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 072ad1aa5505..b5b48ddca962 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -36,7 +36,6 @@ static int qla2x00_restart_isp(scsi_qla_host_t *);
static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *);
static int qla84xx_init_chip(scsi_qla_host_t *);
static int qla25xx_init_queues(struct qla_hw_data *);
-static int qla24xx_post_gpdb_work(struct scsi_qla_host *, fc_port_t *, u8);
static int qla24xx_post_prli_work(struct scsi_qla_host*, fc_port_t *);
static void qla24xx_handle_plogi_done_event(struct scsi_qla_host *,
struct event_arg *);
@@ -774,8 +773,7 @@ done_free_sp:
return rval;
}
-static int qla24xx_post_gpdb_work(struct scsi_qla_host *vha, fc_port_t *fcport,
- u8 opt)
+int qla24xx_post_gpdb_work(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt)
{
struct qla_work_evt *e;
@@ -808,6 +806,12 @@ int qla24xx_async_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt)
if (!sp)
goto done;
+ sp->type = SRB_MB_IOCB;
+ sp->name = "gpdb";
+ sp->gen1 = fcport->rscn_gen;
+ sp->gen2 = fcport->login_gen;
+ qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
+
pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pd_dma);
if (pd == NULL) {
ql_log(ql_log_warn, vha, 0xd043,
@@ -816,12 +820,6 @@ int qla24xx_async_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt)
}
memset(pd, 0, max(PORT_DATABASE_SIZE, PORT_DATABASE_24XX_SIZE));
- sp->type = SRB_MB_IOCB;
- sp->name = "gpdb";
- sp->gen1 = fcport->rscn_gen;
- sp->gen2 = fcport->login_gen;
- qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
-
mb = sp->u.iocb_cmd.u.mbx.out_mb;
mb[0] = MBC_GET_PORT_DATABASE;
mb[1] = fcport->loop_id;
@@ -1466,6 +1464,7 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
__func__, __LINE__, ea->fcport->port_name);
ea->fcport->chip_reset = vha->hw->base_qpair->chip_reset;
ea->fcport->logout_on_delete = 1;
+ ea->fcport->send_els_logo = 0;
qla24xx_post_gpdb_work(vha, ea->fcport, 0);
}
break;
@@ -2823,6 +2822,147 @@ qla2x00_alloc_outstanding_cmds(struct qla_hw_data *ha, struct req_que *req)
return QLA_SUCCESS;
}
+#define PRINT_FIELD(_field, _flag, _str) { \
+ if (a0->_field & _flag) {\
+ if (p) {\
+ strcat(ptr, "|");\
+ ptr++;\
+ leftover--;\
+ } \
+ len = snprintf(ptr, leftover, "%s", _str); \
+ p = 1;\
+ leftover -= len;\
+ ptr += len; \
+ } \
+}
+
+static void qla2xxx_print_sfp_info(struct scsi_qla_host *vha)
+{
+#define STR_LEN 64
+ struct sff_8247_a0 *a0 = (struct sff_8247_a0 *)vha->hw->sfp_data;
+ u8 str[STR_LEN], *ptr, p;
+ int leftover, len;
+
+ memset(str, 0, STR_LEN);
+ snprintf(str, SFF_VEN_NAME_LEN+1, a0->vendor_name);
+ ql_dbg(ql_dbg_init, vha, 0x015a,
+ "SFP MFG Name: %s\n", str);
+
+ memset(str, 0, STR_LEN);
+ snprintf(str, SFF_PART_NAME_LEN+1, a0->vendor_pn);
+ ql_dbg(ql_dbg_init, vha, 0x015c,
+ "SFP Part Name: %s\n", str);
+
+ /* media */
+ memset(str, 0, STR_LEN);
+ ptr = str;
+ leftover = STR_LEN;
+ p = len = 0;
+ PRINT_FIELD(fc_med_cc9, FC_MED_TW, "Twin AX");
+ PRINT_FIELD(fc_med_cc9, FC_MED_TP, "Twisted Pair");
+ PRINT_FIELD(fc_med_cc9, FC_MED_MI, "Min Coax");
+ PRINT_FIELD(fc_med_cc9, FC_MED_TV, "Video Coax");
+ PRINT_FIELD(fc_med_cc9, FC_MED_M6, "MultiMode 62.5um");
+ PRINT_FIELD(fc_med_cc9, FC_MED_M5, "MultiMode 50um");
+ PRINT_FIELD(fc_med_cc9, FC_MED_SM, "SingleMode");
+ ql_dbg(ql_dbg_init, vha, 0x0160,
+ "SFP Media: %s\n", str);
+
+ /* link length */
+ memset(str, 0, STR_LEN);
+ ptr = str;
+ leftover = STR_LEN;
+ p = len = 0;
+ PRINT_FIELD(fc_ll_cc7, FC_LL_VL, "Very Long");
+ PRINT_FIELD(fc_ll_cc7, FC_LL_S, "Short");
+ PRINT_FIELD(fc_ll_cc7, FC_LL_I, "Intermediate");
+ PRINT_FIELD(fc_ll_cc7, FC_LL_L, "Long");
+ PRINT_FIELD(fc_ll_cc7, FC_LL_M, "Medium");
+ ql_dbg(ql_dbg_init, vha, 0x0196,
+ "SFP Link Length: %s\n", str);
+
+ memset(str, 0, STR_LEN);
+ ptr = str;
+ leftover = STR_LEN;
+ p = len = 0;
+ PRINT_FIELD(fc_ll_cc7, FC_LL_SA, "Short Wave (SA)");
+ PRINT_FIELD(fc_ll_cc7, FC_LL_LC, "Long Wave(LC)");
+ PRINT_FIELD(fc_tec_cc8, FC_TEC_SN, "Short Wave (SN)");
+ PRINT_FIELD(fc_tec_cc8, FC_TEC_SL, "Short Wave (SL)");
+ PRINT_FIELD(fc_tec_cc8, FC_TEC_LL, "Long Wave (LL)");
+ ql_dbg(ql_dbg_init, vha, 0x016e,
+ "SFP FC Link Tech: %s\n", str);
+
+ if (a0->length_km)
+ ql_dbg(ql_dbg_init, vha, 0x016f,
+ "SFP Distant: %d km\n", a0->length_km);
+ if (a0->length_100m)
+ ql_dbg(ql_dbg_init, vha, 0x0170,
+ "SFP Distant: %d m\n", a0->length_100m*100);
+ if (a0->length_50um_10m)
+ ql_dbg(ql_dbg_init, vha, 0x0189,
+ "SFP Distant (WL=50um): %d m\n", a0->length_50um_10m * 10);
+ if (a0->length_62um_10m)
+ ql_dbg(ql_dbg_init, vha, 0x018a,
+ "SFP Distant (WL=62.5um): %d m\n", a0->length_62um_10m * 10);
+ if (a0->length_om4_10m)
+ ql_dbg(ql_dbg_init, vha, 0x0194,
+ "SFP Distant (OM4): %d m\n", a0->length_om4_10m * 10);
+ if (a0->length_om3_10m)
+ ql_dbg(ql_dbg_init, vha, 0x0195,
+ "SFP Distant (OM3): %d m\n", a0->length_om3_10m * 10);
+}
+
+
+/*
+ * Return Code:
+ * QLA_SUCCESS: no action
+ * QLA_INTERFACE_ERROR: SFP is not there.
+ * QLA_FUNCTION_FAILED: detected New SFP
+ */
+int
+qla24xx_detect_sfp(scsi_qla_host_t *vha)
+{
+ int rc = QLA_SUCCESS;
+ struct sff_8247_a0 *a;
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!AUTO_DETECT_SFP_SUPPORT(vha))
+ goto out;
+
+ rc = qla2x00_read_sfp_dev(vha, NULL, 0);
+ if (rc)
+ goto out;
+
+ a = (struct sff_8247_a0 *)vha->hw->sfp_data;
+ qla2xxx_print_sfp_info(vha);
+
+ if (a->fc_ll_cc7 & FC_LL_VL || a->fc_ll_cc7 & FC_LL_L) {
+ /* long range */
+ ha->flags.detected_lr_sfp = 1;
+
+ if (a->length_km > 5 || a->length_100m > 50)
+ ha->long_range_distance = LR_DISTANCE_10K;
+ else
+ ha->long_range_distance = LR_DISTANCE_5K;
+
+ if (ha->flags.detected_lr_sfp != ha->flags.using_lr_setting)
+ ql_dbg(ql_dbg_async, vha, 0x507b,
+ "Detected Long Range SFP.\n");
+ } else {
+ /* short range */
+ ha->flags.detected_lr_sfp = 0;
+ if (ha->flags.using_lr_setting)
+ ql_dbg(ql_dbg_async, vha, 0x5084,
+ "Detected Short Range SFP.\n");
+ }
+
+ if (!vha->flags.init_done)
+ rc = QLA_SUCCESS;
+out:
+ return rc;
+}
+
/**
* qla2x00_setup_chip() - Load and start RISC firmware.
* @ha: HA context
@@ -2879,6 +3019,8 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
rval = qla2x00_execute_fw(vha, srisc_address);
/* Retrieve firmware information. */
if (rval == QLA_SUCCESS) {
+ qla24xx_detect_sfp(vha);
+
rval = qla2x00_set_exlogins_buffer(vha);
if (rval != QLA_SUCCESS)
goto failed;
@@ -4609,24 +4751,16 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
qla2x00_fdmi_register(vha);
/* Ensure we are logged into the SNS. */
- if (IS_FWI2_CAPABLE(ha))
- loop_id = NPH_SNS;
- else
- loop_id = SIMPLE_NAME_SERVER;
+ loop_id = NPH_SNS_LID(ha);
rval = ha->isp_ops->fabric_login(vha, loop_id, 0xff, 0xff,
0xfc, mb, BIT_1|BIT_0);
- if (rval != QLA_SUCCESS) {
+ if (rval != QLA_SUCCESS || mb[0] != MBS_COMMAND_COMPLETE) {
+ ql_dbg(ql_dbg_disc, vha, 0x20a1,
+ "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x (%x).\n",
+ loop_id, mb[0], mb[1], mb[2], mb[6], mb[7], rval);
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
return rval;
}
- if (mb[0] != MBS_COMMAND_COMPLETE) {
- ql_dbg(ql_dbg_disc, vha, 0x20a1,
- "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x "
- "mb[6]=%x mb[7]=%x.\n", loop_id, mb[0], mb[1],
- mb[2], mb[6], mb[7]);
- return (QLA_SUCCESS);
- }
-
if (test_and_clear_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags)) {
if (qla2x00_rft_id(vha)) {
/* EMPTY */
@@ -4804,6 +4938,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha)
new_fcport->fc4_type = swl[swl_idx].fc4_type;
new_fcport->nvme_flag = 0;
+ new_fcport->fc4f_nvme = 0;
if (vha->flags.nvme_enabled &&
swl[swl_idx].fc4f_nvme) {
new_fcport->fc4f_nvme =
@@ -5913,7 +6048,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
if (!status) {
ql_dbg(ql_dbg_taskm, vha, 0x8022, "%s succeeded.\n", __func__);
-
+ qla2x00_configure_hba(vha);
spin_lock_irqsave(&ha->vport_slock, flags);
list_for_each_entry(vp, &ha->vp_list, list) {
if (vp->vp_idx) {
@@ -7804,7 +7939,9 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos,
ha->queue_pair_map[qpair_id] = qpair;
qpair->id = qpair_id;
qpair->vp_idx = vp_idx;
+ qpair->fw_started = ha->flags.fw_started;
INIT_LIST_HEAD(&qpair->hints_list);
+ INIT_LIST_HEAD(&qpair->nvme_done_list);
qpair->chip_reset = ha->base_qpair->chip_reset;
qpair->enable_class_2 = ha->base_qpair->enable_class_2;
qpair->enable_explicit_conf =
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index a36c485fae50..2f94159186d7 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -2682,12 +2682,12 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
uint32_t *cur_dsd;
struct scatterlist *sg;
int index;
- uint16_t tot_dsds;
+ uint16_t cmd_dsds, rsp_dsds;
scsi_qla_host_t *vha = sp->vha;
struct qla_hw_data *ha = vha->hw;
struct bsg_job *bsg_job = sp->u.bsg_job;
- int loop_iterartion = 0;
int entry_count = 1;
+ cont_a64_entry_t *cont_pkt = NULL;
ct_iocb->entry_type = CT_IOCB_TYPE;
ct_iocb->entry_status = 0;
@@ -2698,30 +2698,46 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
ct_iocb->vp_index = sp->vha->vp_idx;
ct_iocb->comp_status = cpu_to_le16(0);
- ct_iocb->cmd_dsd_count =
- cpu_to_le16(bsg_job->request_payload.sg_cnt);
+ cmd_dsds = bsg_job->request_payload.sg_cnt;
+ rsp_dsds = bsg_job->reply_payload.sg_cnt;
+
+ ct_iocb->cmd_dsd_count = cpu_to_le16(cmd_dsds);
ct_iocb->timeout = 0;
- ct_iocb->rsp_dsd_count =
- cpu_to_le16(bsg_job->reply_payload.sg_cnt);
- ct_iocb->rsp_byte_count =
- cpu_to_le32(bsg_job->reply_payload.payload_len);
+ ct_iocb->rsp_dsd_count = cpu_to_le16(rsp_dsds);
ct_iocb->cmd_byte_count =
cpu_to_le32(bsg_job->request_payload.payload_len);
- ct_iocb->dseg_0_address[0] = cpu_to_le32(LSD(sg_dma_address
- (bsg_job->request_payload.sg_list)));
- ct_iocb->dseg_0_address[1] = cpu_to_le32(MSD(sg_dma_address
- (bsg_job->request_payload.sg_list)));
- ct_iocb->dseg_0_len = cpu_to_le32(sg_dma_len
- (bsg_job->request_payload.sg_list));
- avail_dsds = 1;
- cur_dsd = (uint32_t *)ct_iocb->dseg_1_address;
+ avail_dsds = 2;
+ cur_dsd = (uint32_t *)ct_iocb->dseg_0_address;
index = 0;
- tot_dsds = bsg_job->reply_payload.sg_cnt;
- for_each_sg(bsg_job->reply_payload.sg_list, sg, tot_dsds, index) {
+ for_each_sg(bsg_job->request_payload.sg_list, sg, cmd_dsds, index) {
+ dma_addr_t sle_dma;
+
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ /*
+ * Five DSDs are available in the Cont.
+ * Type 1 IOCB.
+ */
+ cont_pkt = qla2x00_prep_cont_type1_iocb(
+ vha, ha->req_q_map[0]);
+ cur_dsd = (uint32_t *) cont_pkt->dseg_0_address;
+ avail_dsds = 5;
+ entry_count++;
+ }
+
+ sle_dma = sg_dma_address(sg);
+ *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ avail_dsds--;
+ }
+
+ index = 0;
+
+ for_each_sg(bsg_job->reply_payload.sg_list, sg, rsp_dsds, index) {
dma_addr_t sle_dma;
- cont_a64_entry_t *cont_pkt;
/* Allocate additional continuation packets? */
if (avail_dsds == 0) {
@@ -2740,7 +2756,6 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
*cur_dsd++ = cpu_to_le32(LSD(sle_dma));
*cur_dsd++ = cpu_to_le32(MSD(sle_dma));
*cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
- loop_iterartion++;
avail_dsds--;
}
ct_iocb->entry_count = entry_count;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 7b3b702ef622..9d9668aac6f6 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -14,6 +14,8 @@
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_bsg_fc.h>
#include <scsi/scsi_eh.h>
+#include <scsi/fc/fc_fs.h>
+#include <linux/nvme-fc-driver.h>
static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
@@ -452,7 +454,7 @@ qla83xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb)
uint16_t peg_fw_state, nw_interface_link_up;
uint16_t nw_interface_signal_detect, sfp_status;
uint16_t htbt_counter, htbt_monitor_enable;
- uint16_t sfp_additonal_info, sfp_multirate;
+ uint16_t sfp_additional_info, sfp_multirate;
uint16_t sfp_tx_fault, link_speed, dcbx_status;
/*
@@ -492,7 +494,7 @@ qla83xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb)
sfp_status = ((mb[2] & 0x0c00) >> 10);
htbt_counter = ((mb[2] & 0x7000) >> 12);
htbt_monitor_enable = ((mb[2] & 0x8000) >> 15);
- sfp_additonal_info = (mb[6] & 0x0003);
+ sfp_additional_info = (mb[6] & 0x0003);
sfp_multirate = ((mb[6] & 0x0004) >> 2);
sfp_tx_fault = ((mb[6] & 0x0008) >> 3);
link_speed = ((mb[6] & 0x0070) >> 4);
@@ -507,9 +509,9 @@ qla83xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb)
sfp_status);
ql_log(ql_log_warn, vha, 0x5067,
"htbt_counter=0x%x, htbt_monitor_enable=0x%x, "
- "sfp_additonal_info=0x%x, sfp_multirate=0x%x.\n ",
+ "sfp_additional_info=0x%x, sfp_multirate=0x%x.\n ",
htbt_counter, htbt_monitor_enable,
- sfp_additonal_info, sfp_multirate);
+ sfp_additional_info, sfp_multirate);
ql_log(ql_log_warn, vha, 0x5068,
"sfp_tx_fault=0x%x, link_state=0x%x, "
"dcbx_status=0x%x.\n", sfp_tx_fault, link_speed,
@@ -799,6 +801,11 @@ skip_rio:
vha->flags.management_server_logged_in = 0;
qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate);
+
+ if (AUTO_DETECT_SFP_SUPPORT(vha)) {
+ set_bit(DETECT_SFP_CHANGE, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ }
break;
case MBA_LOOP_DOWN: /* Loop Down Event */
@@ -1228,6 +1235,11 @@ global_port_update:
schedule_work(&ha->board_disable);
break;
+ case MBA_TRANS_INSERT:
+ ql_dbg(ql_dbg_async, vha, 0x5091,
+ "Transceiver Insertion: %04x\n", mb[1]);
+ break;
+
default:
ql_dbg(ql_dbg_async, vha, 0x5057,
"Unknown AEN:%04x %04x %04x %04x\n",
@@ -1537,8 +1549,6 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
if (!sp)
return;
- bsg_job = sp->u.bsg_job;
- bsg_reply = bsg_job->reply;
type = NULL;
switch (sp->type) {
@@ -1577,6 +1587,8 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
/* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT
* fc payload to the caller
*/
+ bsg_job = sp->u.bsg_job;
+ bsg_reply = bsg_job->reply;
bsg_reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(fw_status);
@@ -1823,7 +1835,7 @@ qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk)
nvme = &sp->u.iocb_cmd;
if (unlikely(nvme->u.nvme.aen_op))
- atomic_dec(&sp->vha->nvme_active_aen_cnt);
+ atomic_dec(&sp->vha->hw->nvme_active_aen_cnt);
/*
* State flags: Bit 6 and 0.
@@ -1856,17 +1868,42 @@ qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk)
fd->transferred_length = fd->payload_length -
le32_to_cpu(sts->residual_len);
+ /*
+ * If transport error then Failure (HBA rejects request)
+ * otherwise transport will handle.
+ */
if (sts->entry_status) {
ql_log(ql_log_warn, fcport->vha, 0x5038,
"NVME-%s error - hdl=%x entry-status(%x).\n",
sp->name, sp->handle, sts->entry_status);
ret = QLA_FUNCTION_FAILED;
- } else if (sts->comp_status != cpu_to_le16(CS_COMPLETE)) {
- ql_log(ql_log_warn, fcport->vha, 0x5039,
- "NVME-%s error - hdl=%x completion status(%x) resid=%x ox_id=%x\n",
- sp->name, sp->handle, sts->comp_status,
- le32_to_cpu(sts->residual_len), sts->ox_id);
- ret = QLA_FUNCTION_FAILED;
+ } else {
+ switch (le16_to_cpu(sts->comp_status)) {
+ case CS_COMPLETE:
+ ret = 0;
+ break;
+
+ case CS_ABORTED:
+ case CS_RESET:
+ case CS_PORT_UNAVAILABLE:
+ case CS_PORT_LOGGED_OUT:
+ case CS_PORT_BUSY:
+ ql_log(ql_log_warn, fcport->vha, 0x5060,
+ "NVME-%s ERR Handling - hdl=%x completion status(%x) resid=%x ox_id=%x\n",
+ sp->name, sp->handle, sts->comp_status,
+ le32_to_cpu(sts->residual_len), sts->ox_id);
+ fd->transferred_length = fd->payload_length;
+ ret = QLA_ABORTED;
+ break;
+
+ default:
+ ql_log(ql_log_warn, fcport->vha, 0x5060,
+ "NVME-%s error - hdl=%x completion status(%x) resid=%x ox_id=%x\n",
+ sp->name, sp->handle, sts->comp_status,
+ le32_to_cpu(sts->residual_len), sts->ox_id);
+ ret = QLA_FUNCTION_FAILED;
+ break;
+ }
}
sp->done(sp, ret);
}
@@ -2827,8 +2864,8 @@ qla24xx_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
sp->done(sp, 0);
}
-void qla24xx_nvme_ls4_iocb(scsi_qla_host_t *vha, struct pt_ls4_request *pkt,
- struct req_que *req)
+void qla24xx_nvme_ls4_iocb(struct scsi_qla_host *vha,
+ struct pt_ls4_request *pkt, struct req_que *req)
{
srb_t *sp;
const char func[] = "LS4_IOCB";
@@ -3132,7 +3169,6 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
struct device_reg_24xx __iomem *reg;
struct scsi_qla_host *vha;
unsigned long flags;
- uint32_t stat = 0;
rsp = (struct rsp_que *) dev_id;
if (!rsp) {
@@ -3146,19 +3182,11 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
spin_lock_irqsave(&ha->hardware_lock, flags);
vha = pci_get_drvdata(ha->pdev);
- /*
- * Use host_status register to check to PCI disconnection before we
- * we process the response queue.
- */
- stat = RD_REG_DWORD(&reg->host_status);
- if (qla2x00_check_reg32_for_disconnect(vha, stat))
- goto out;
qla24xx_process_response_queue(vha, rsp);
if (!ha->flags.disable_msix_handshake) {
WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
RD_REG_DWORD_RELAXED(&reg->hccr);
}
-out:
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return IRQ_HANDLED;
@@ -3429,7 +3457,7 @@ msix_register_fail:
}
/* Enable MSI-X vector for response queue update for queue 0 */
- if (IS_QLA25XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
if (ha->msixbase && ha->mqiobase &&
(ha->max_rsp_queues > 1 || ha->max_req_queues > 1 ||
ql2xmqsupport))
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 7c6d1a404011..99502fa90810 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -54,6 +54,10 @@ static struct rom_cmd {
{ MBC_GET_MEM_OFFLOAD_CNTRL_STAT },
{ MBC_GET_RETRY_COUNT },
{ MBC_TRACE_CONTROL },
+ { MBC_INITIALIZE_MULTIQ },
+ { MBC_IOCB_COMMAND_A64 },
+ { MBC_GET_ADAPTER_LOOP_ID },
+ { MBC_READ_SFP },
};
static int is_rom_cmd(uint16_t cmd)
@@ -102,7 +106,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
uint16_t __iomem *optr;
uint32_t cnt;
uint32_t mboxes;
- uint16_t __iomem *mbx_reg;
unsigned long wait_time;
struct qla_hw_data *ha = vha->hw;
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
@@ -486,21 +489,24 @@ premature_exit:
mbx_done:
if (rval) {
- ql_dbg(ql_dbg_disc, base_vha, 0x1020,
- "**** Failed mbx[0]=%x, mb[1]=%x, mb[2]=%x, mb[3]=%x, cmd=%x ****.\n",
- mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3], command);
-
+ if (ql2xextended_error_logging & (ql_dbg_disc|ql_dbg_mbx)) {
+ pr_warn("%s [%s]-%04x:%ld: **** Failed", QL_MSGHDR,
+ dev_name(&ha->pdev->dev), 0x1020+0x800,
+ vha->host_no);
+ mboxes = mcp->in_mb;
+ cnt = 4;
+ for (i = 0; i < ha->mbx_count && cnt; i++, mboxes >>= 1)
+ if (mboxes & BIT_0) {
+ printk(" mb[%u]=%x", i, mcp->mb[i]);
+ cnt--;
+ }
+ pr_warn(" cmd=%x ****\n", command);
+ }
ql_dbg(ql_dbg_mbx, vha, 0x1198,
- "host status: 0x%x, flags:0x%lx, intr ctrl reg:0x%x, intr status:0x%x\n",
+ "host_status=%#x intr_ctrl=%#x intr_status=%#x\n",
RD_REG_DWORD(&reg->isp24.host_status),
- ha->fw_dump_cap_flags,
RD_REG_DWORD(&reg->isp24.ictrl),
RD_REG_DWORD(&reg->isp24.istatus));
-
- mbx_reg = &reg->isp24.mailbox0;
- for (i = 0; i < 6; i++)
- ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1199,
- "mbox[%d] 0x%04x\n", i, RD_REG_WORD(mbx_reg++));
} else {
ql_dbg(ql_dbg_mbx, base_vha, 0x1021, "Done %s.\n", __func__);
}
@@ -561,6 +567,28 @@ qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr,
#define EXTENDED_BB_CREDITS BIT_0
#define NVME_ENABLE_FLAG BIT_3
+static inline uint16_t qla25xx_set_sfp_lr_dist(struct qla_hw_data *ha)
+{
+ uint16_t mb4 = BIT_0;
+
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
+ mb4 |= ha->long_range_distance << LR_DIST_FW_POS;
+
+ return mb4;
+}
+
+static inline uint16_t qla25xx_set_nvr_lr_dist(struct qla_hw_data *ha)
+{
+ uint16_t mb4 = BIT_0;
+
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ struct nvram_81xx *nv = ha->nvram;
+
+ mb4 |= LR_DIST_FW_FIELD(nv->enhanced_features);
+ }
+
+ return mb4;
+}
/*
* qla2x00_execute_fw
@@ -595,17 +623,44 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
mcp->mb[1] = MSW(risc_addr);
mcp->mb[2] = LSW(risc_addr);
mcp->mb[3] = 0;
+ mcp->mb[4] = 0;
+ ha->flags.using_lr_setting = 0;
if (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) ||
IS_QLA27XX(ha)) {
- struct nvram_81xx *nv = ha->nvram;
- mcp->mb[4] = (nv->enhanced_features &
- EXTENDED_BB_CREDITS);
- } else
- mcp->mb[4] = 0;
+ if (ql2xautodetectsfp) {
+ if (ha->flags.detected_lr_sfp) {
+ mcp->mb[4] |=
+ qla25xx_set_sfp_lr_dist(ha);
+ ha->flags.using_lr_setting = 1;
+ }
+ } else {
+ struct nvram_81xx *nv = ha->nvram;
+ /* set LR distance if specified in nvram */
+ if (nv->enhanced_features &
+ NEF_LR_DIST_ENABLE) {
+ mcp->mb[4] |=
+ qla25xx_set_nvr_lr_dist(ha);
+ ha->flags.using_lr_setting = 1;
+ }
+ }
+ }
if (ql2xnvmeenable && IS_QLA27XX(ha))
mcp->mb[4] |= NVME_ENABLE_FLAG;
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ struct nvram_81xx *nv = ha->nvram;
+ /* set minimum speed if specified in nvram */
+ if (nv->min_link_speed >= 2 &&
+ nv->min_link_speed <= 5) {
+ mcp->mb[4] |= BIT_4;
+ mcp->mb[11] = nv->min_link_speed;
+ mcp->out_mb |= MBX_11;
+ mcp->in_mb |= BIT_5;
+ vha->min_link_speed_feat = nv->min_link_speed;
+ }
+ }
+
if (ha->flags.exlogins_enabled)
mcp->mb[4] |= ENABLE_EXTENDED_LOGIN;
@@ -613,7 +668,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
mcp->mb[4] |= ENABLE_EXCHANGE_OFFLD;
mcp->out_mb |= MBX_4|MBX_3|MBX_2|MBX_1;
- mcp->in_mb |= MBX_1;
+ mcp->in_mb |= MBX_3 | MBX_2 | MBX_1;
} else {
mcp->mb[1] = LSW(risc_addr);
mcp->out_mb |= MBX_1;
@@ -632,12 +687,30 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
"Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
} else {
if (IS_FWI2_CAPABLE(ha)) {
- ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1027,
- "Done exchanges=%x.\n", mcp->mb[1]);
- } else {
- ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1028,
- "Done %s.\n", __func__);
+ ha->fw_ability_mask = mcp->mb[3] << 16 | mcp->mb[2];
+ ql_dbg(ql_dbg_mbx, vha, 0x119a,
+ "fw_ability_mask=%x.\n", ha->fw_ability_mask);
+ ql_dbg(ql_dbg_mbx, vha, 0x1027,
+ "exchanges=%x.\n", mcp->mb[1]);
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ ha->max_speed_sup = mcp->mb[2] & BIT_0;
+ ql_dbg(ql_dbg_mbx, vha, 0x119b,
+ "Maximum speed supported=%s.\n",
+ ha->max_speed_sup ? "32Gps" : "16Gps");
+ if (vha->min_link_speed_feat) {
+ ha->min_link_speed = mcp->mb[5];
+ ql_dbg(ql_dbg_mbx, vha, 0x119c,
+ "Minimum speed set=%s.\n",
+ mcp->mb[5] == 5 ? "32Gps" :
+ mcp->mb[5] == 4 ? "16Gps" :
+ mcp->mb[5] == 3 ? "8Gps" :
+ mcp->mb[5] == 2 ? "4Gps" :
+ "unknown");
+ }
+ }
}
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1028,
+ "Done.\n");
}
return rval;
@@ -947,20 +1020,12 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
"%s: Firmware supports Exchange Offload 0x%x\n",
__func__, ha->fw_attributes_h);
- /* bit 26 of fw_attributes */
- if ((ha->fw_attributes_h & 0x400) && ql2xnvmeenable) {
- struct init_cb_24xx *icb;
-
- icb = (struct init_cb_24xx *)ha->init_cb;
- /*
- * fw supports nvme and driver load
- * parameter requested nvme
- */
+ /*
+ * FW supports nvme and driver load parameter requested nvme.
+ * BIT 26 of fw_attributes indicates NVMe support.
+ */
+ if ((ha->fw_attributes_h & 0x400) && ql2xnvmeenable)
vha->flags.nvme_enabled = 1;
- icb->firmware_options_2 &= cpu_to_le32(~0xf);
- ha->zio_mode = 0;
- ha->zio_timer = 0;
- }
}
@@ -1673,7 +1738,11 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
"Failed=%x mb[0]=%x, mb[1]=%x, mb[2]=%x, mb[3]=%x,.\n",
rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3]);
} else {
- /*EMPTY*/
+ if (IS_QLA27XX(ha)) {
+ if (mcp->mb[2] == 6 || mcp->mb[3] == 2)
+ ql_dbg(ql_dbg_mbx, vha, 0x119d,
+ "Invalid SFP/Validation Failed\n");
+ }
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x104e,
"Done %s.\n", __func__);
}
@@ -1878,6 +1947,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
int rval;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
+ struct qla_hw_data *ha = vha->hw;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1054,
"Entered %s.\n", __func__);
@@ -1906,7 +1976,11 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
/*EMPTY*/
ql_dbg(ql_dbg_mbx, vha, 0x1055, "Failed=%x.\n", rval);
} else {
- /*EMPTY*/
+ if (IS_QLA27XX(ha)) {
+ if (mcp->mb[2] == 6 || mcp->mb[3] == 2)
+ ql_dbg(ql_dbg_mbx, vha, 0x119e,
+ "Invalid SFP/Validation Failed\n");
+ }
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1056,
"Done %s.\n", __func__);
}
@@ -3689,7 +3763,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
if (qla_ini_mode_enabled(vha) &&
ha->flags.fawwpn_enabled &&
(rptid_entry->u.f1.flags &
- VP_FLAGS_NAME_VALID)) {
+ BIT_6)) {
memcpy(vha->port_name,
rptid_entry->u.f1.port_name,
WWN_SIZE);
@@ -4590,6 +4664,10 @@ qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp,
if (rval != QLA_SUCCESS) {
ql_dbg(ql_dbg_mbx, vha, 0x10e9,
"Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+ if (mcp->mb[0] == MBS_COMMAND_ERROR &&
+ mcp->mb[1] == 0x22)
+ /* sfp is not there */
+ rval = QLA_INTERFACE_ERROR;
} else {
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ea,
"Done %s.\n", __func__);
@@ -5817,7 +5895,7 @@ qla26xx_dport_diagnostics(scsi_qla_host_t *vha,
dd_dma = dma_map_single(&vha->hw->pdev->dev,
dd_buf, size, DMA_FROM_DEVICE);
- if (!dd_dma) {
+ if (dma_mapping_error(&vha->hw->pdev->dev, dd_dma)) {
ql_log(ql_log_warn, vha, 0x1194, "Failed to map dma buffer.\n");
return QLA_MEMORY_ALLOC_FAILED;
}
@@ -6085,3 +6163,108 @@ int qla24xx_gidlist_wait(struct scsi_qla_host *vha,
done:
return rval;
}
+
+int qla27xx_set_zio_threshold(scsi_qla_host_t *vha, uint16_t value)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1200,
+ "Entered %s\n", __func__);
+
+ memset(mcp->mb, 0 , sizeof(mcp->mb));
+ mcp->mb[0] = MBC_GET_SET_ZIO_THRESHOLD;
+ mcp->mb[1] = cpu_to_le16(1);
+ mcp->mb[2] = cpu_to_le16(value);
+ mcp->out_mb = MBX_2 | MBX_1 | MBX_0;
+ mcp->in_mb = MBX_2 | MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+
+ rval = qla2x00_mailbox_command(vha, mcp);
+
+ ql_dbg(ql_dbg_mbx, vha, 0x1201, "%s %x\n",
+ (rval != QLA_SUCCESS) ? "Failed" : "Done", rval);
+
+ return rval;
+}
+
+int qla27xx_get_zio_threshold(scsi_qla_host_t *vha, uint16_t *value)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1203,
+ "Entered %s\n", __func__);
+
+ memset(mcp->mb, 0, sizeof(mcp->mb));
+ mcp->mb[0] = MBC_GET_SET_ZIO_THRESHOLD;
+ mcp->mb[1] = cpu_to_le16(0);
+ mcp->out_mb = MBX_1 | MBX_0;
+ mcp->in_mb = MBX_2 | MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+
+ rval = qla2x00_mailbox_command(vha, mcp);
+ if (rval == QLA_SUCCESS)
+ *value = mc.mb[2];
+
+ ql_dbg(ql_dbg_mbx, vha, 0x1205, "%s %x\n",
+ (rval != QLA_SUCCESS) ? "Failed" : "Done", rval);
+
+ return rval;
+}
+
+int
+qla2x00_read_sfp_dev(struct scsi_qla_host *vha, char *buf, int count)
+{
+ struct qla_hw_data *ha = vha->hw;
+ uint16_t iter, addr, offset;
+ dma_addr_t phys_addr;
+ int rval, c;
+ u8 *sfp_data;
+
+ memset(ha->sfp_data, 0, SFP_DEV_SIZE);
+ addr = 0xa0;
+ phys_addr = ha->sfp_data_dma;
+ sfp_data = ha->sfp_data;
+ offset = c = 0;
+
+ for (iter = 0; iter < SFP_DEV_SIZE / SFP_BLOCK_SIZE; iter++) {
+ if (iter == 4) {
+ /* Skip to next device address. */
+ addr = 0xa2;
+ offset = 0;
+ }
+
+ rval = qla2x00_read_sfp(vha, phys_addr, sfp_data,
+ addr, offset, SFP_BLOCK_SIZE, BIT_1);
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0x706d,
+ "Unable to read SFP data (%x/%x/%x).\n", rval,
+ addr, offset);
+
+ return rval;
+ }
+
+ if (buf && (c < count)) {
+ u16 sz;
+
+ if ((count - c) >= SFP_BLOCK_SIZE)
+ sz = SFP_BLOCK_SIZE;
+ else
+ sz = count - c;
+
+ memcpy(buf, sfp_data, sz);
+ buf += SFP_BLOCK_SIZE;
+ c += sz;
+ }
+ phys_addr += SFP_BLOCK_SIZE;
+ sfp_data += SFP_BLOCK_SIZE;
+ offset += SFP_BLOCK_SIZE;
+ }
+
+ return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index f0605cd196fb..c0f8f6c17b79 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -74,7 +74,7 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
* ensures no active vp_list traversal while the vport is removed
* from the queue)
*/
- wait_event_timeout(vha->vref_waitq, atomic_read(&vha->vref_count),
+ wait_event_timeout(vha->vref_waitq, !atomic_read(&vha->vref_count),
10*HZ);
spin_lock_irqsave(&ha->vport_slock, flags);
@@ -187,6 +187,11 @@ qla24xx_enable_vp(scsi_qla_host_t *vha)
!(ha->current_topology & ISP_CFG_F)) {
vha->vp_err_state = VP_ERR_PORTDWN;
fc_vport_set_state(vha->fc_vport, FC_VPORT_LINKDOWN);
+ ql_dbg(ql_dbg_taskm, vha, 0x800b,
+ "%s skip enable. loop_state %x topo %x\n",
+ __func__, base_vha->loop_state.counter,
+ ha->current_topology);
+
goto enable_failed;
}
@@ -759,11 +764,18 @@ static void qla_do_work(struct work_struct *work)
struct qla_qpair *qpair = container_of(work, struct qla_qpair, q_work);
struct scsi_qla_host *vha;
struct qla_hw_data *ha = qpair->hw;
+ struct srb_iocb *nvme, *nxt_nvme;
spin_lock_irqsave(&qpair->qp_lock, flags);
vha = pci_get_drvdata(ha->pdev);
qla24xx_process_response_queue(vha, qpair->rsp);
spin_unlock_irqrestore(&qpair->qp_lock, flags);
+
+ list_for_each_entry_safe(nvme, nxt_nvme, &qpair->nvme_done_list,
+ u.nvme.entry) {
+ list_del_init(&nvme->u.nvme.entry);
+ qla_nvme_cmpl_io(nvme);
+ }
}
/* create response queue */
diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
index 10b742d27e16..e23a3d4c36f3 100644
--- a/drivers/scsi/qla2xxx/qla_mr.c
+++ b/drivers/scsi/qla2xxx/qla_mr.c
@@ -1819,6 +1819,10 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
if (!sp)
goto done;
+ sp->type = SRB_FXIOCB_DCMD;
+ sp->name = "fxdisc";
+ qla2x00_init_timer(sp, FXDISC_TIMEOUT);
+
fdisc = &sp->u.iocb_cmd;
switch (fx_type) {
case FXDISC_GET_CONFIG_INFO:
@@ -1920,9 +1924,6 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
goto done_unmap_req;
}
- sp->type = SRB_FXIOCB_DCMD;
- sp->name = "fxdisc";
- qla2x00_init_timer(sp, FXDISC_TIMEOUT);
fdisc->timeout = qla2x00_fxdisc_iocb_timeout;
fdisc->u.fxiocb.req_func_type = cpu_to_le16(fx_type);
sp->done = qla2x00_fxdisc_sp_done;
diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
index f3710a75fe1f..1f59e7a74c7b 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.c
+++ b/drivers/scsi/qla2xxx/qla_nvme.c
@@ -5,7 +5,6 @@
* See LICENSE.qla2xxx for copyright and licensing details.
*/
#include "qla_nvme.h"
-#include "qla_def.h"
#include <linux/scatterlist.h>
#include <linux/delay.h>
#include <linux/nvme.h>
@@ -15,7 +14,7 @@ static struct nvme_fc_port_template qla_nvme_fc_transport;
static void qla_nvme_unregister_remote_port(struct work_struct *);
-int qla_nvme_register_remote(scsi_qla_host_t *vha, fc_port_t *fcport)
+int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport)
{
struct nvme_rport *rport;
int ret;
@@ -61,8 +60,8 @@ int qla_nvme_register_remote(scsi_qla_host_t *vha, fc_port_t *fcport)
rport->req.port_id = fcport->d_id.b24;
ql_log(ql_log_info, vha, 0x2102,
- "%s: traddr=pn-0x%016llx:nn-0x%016llx PortID:%06x\n",
- __func__, rport->req.port_name, rport->req.node_name,
+ "%s: traddr=nn-0x%016llx:pn-0x%016llx PortID:%06x\n",
+ __func__, rport->req.node_name, rport->req.port_name,
rport->req.port_id);
ret = nvme_fc_register_remoteport(vha->nvme_local_port, &rport->req,
@@ -76,16 +75,14 @@ int qla_nvme_register_remote(scsi_qla_host_t *vha, fc_port_t *fcport)
fcport->nvme_remote_port->private = fcport;
fcport->nvme_flag |= NVME_FLAG_REGISTERED;
- atomic_set(&fcport->nvme_ref_count, 1);
- init_waitqueue_head(&fcport->nvme_waitQ);
rport->fcport = fcport;
list_add_tail(&rport->list, &vha->nvme_rport_list);
return 0;
}
/* Allocate a queue for NVMe traffic */
-static int qla_nvme_alloc_queue(struct nvme_fc_local_port *lport, unsigned int qidx,
- u16 qsize, void **handle)
+static int qla_nvme_alloc_queue(struct nvme_fc_local_port *lport,
+ unsigned int qidx, u16 qsize, void **handle)
{
struct scsi_qla_host *vha;
struct qla_hw_data *ha;
@@ -157,6 +154,16 @@ static void qla_nvme_sp_ls_done(void *ptr, int res)
qla2x00_rel_sp(sp);
}
+void qla_nvme_cmpl_io(struct srb_iocb *nvme)
+{
+ srb_t *sp;
+ struct nvmefc_fcp_req *fd = nvme->u.nvme.desc;
+
+ sp = container_of(nvme, srb_t, u.iocb_cmd);
+ fd->done(fd);
+ qla2xxx_rel_qpair_sp(sp->qpair, sp);
+}
+
static void qla_nvme_sp_done(void *ptr, int res)
{
srb_t *sp = ptr;
@@ -172,13 +179,14 @@ static void qla_nvme_sp_done(void *ptr, int res)
if (!(sp->fcport->nvme_flag & NVME_FLAG_REGISTERED))
goto rel;
- if (unlikely(nvme->u.nvme.comp_status || res))
- fd->status = -EINVAL;
+ if (unlikely(res == QLA_FUNCTION_FAILED))
+ fd->status = NVME_SC_FC_TRANSPORT_ERROR;
else
fd->status = 0;
fd->rcv_rsplen = nvme->u.nvme.rsp_pyld_len;
- fd->done(fd);
+ list_add_tail(&nvme->u.nvme.entry, &sp->qpair->nvme_done_list);
+ return;
rel:
qla2xxx_rel_qpair_sp(sp->qpair, sp);
}
@@ -193,13 +201,11 @@ static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport,
struct qla_hw_data *ha = fcport->vha->hw;
rval = ha->isp_ops->abort_command(sp);
- if (rval != QLA_SUCCESS)
- ql_log(ql_log_warn, fcport->vha, 0x2125,
- "%s: failed to abort LS command for SP:%p rval=%x\n",
- __func__, sp, rval);
ql_dbg(ql_dbg_io, fcport->vha, 0x212b,
- "%s: aborted sp:%p on fcport:%p\n", __func__, sp, fcport);
+ "%s: %s LS command for sp=%p on fcport=%p rval=%x\n", __func__,
+ (rval != QLA_SUCCESS) ? "Failed to abort" : "Aborted",
+ sp, fcport, rval);
}
static void qla_nvme_ls_complete(struct work_struct *work)
@@ -214,7 +220,7 @@ static void qla_nvme_ls_complete(struct work_struct *work)
static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd)
{
- fc_port_t *fcport = (fc_port_t *)rport->private;
+ fc_port_t *fcport = rport->private;
struct srb_iocb *nvme;
struct nvme_private *priv = fd->private;
struct scsi_qla_host *vha;
@@ -236,7 +242,6 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
sp->name = "nvme_ls";
sp->done = qla_nvme_sp_ls_done;
atomic_set(&sp->ref_count, 1);
- init_waitqueue_head(&sp->nvme_ls_waitQ);
nvme = &sp->u.iocb_cmd;
priv->sp = sp;
priv->fd = fd;
@@ -258,7 +263,7 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
ql_log(ql_log_warn, vha, 0x700e,
"qla2x00_start_sp failed = %d\n", rval);
atomic_dec(&sp->ref_count);
- wake_up(&sp->nvme_ls_waitQ);
+ wake_up(&sp->nvme_ls_waitq);
return rval;
}
@@ -276,20 +281,18 @@ static void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport,
struct qla_hw_data *ha = fcport->vha->hw;
rval = ha->isp_ops->abort_command(sp);
- if (!rval)
- ql_log(ql_log_warn, fcport->vha, 0x2127,
- "%s: failed to abort command for SP:%p rval=%x\n",
- __func__, sp, rval);
- ql_dbg(ql_dbg_io, fcport->vha, 0x2126,
- "%s: aborted sp:%p on fcport:%p\n", __func__, sp, fcport);
+ ql_dbg(ql_dbg_io, fcport->vha, 0x2127,
+ "%s: %s command for sp=%p on fcport=%p rval=%x\n", __func__,
+ (rval != QLA_SUCCESS) ? "Failed to abort" : "Aborted",
+ sp, fcport, rval);
}
static void qla_nvme_poll(struct nvme_fc_local_port *lport, void *hw_queue_handle)
{
struct scsi_qla_host *vha = lport->private;
unsigned long flags;
- struct qla_qpair *qpair = (struct qla_qpair *)hw_queue_handle;
+ struct qla_qpair *qpair = hw_queue_handle;
/* Acquire ring specific lock */
spin_lock_irqsave(&qpair->qp_lock, flags);
@@ -310,6 +313,7 @@ static int qla2x00_start_nvme_mq(srb_t *sp)
uint16_t avail_dsds;
uint32_t *cur_dsd;
struct req_que *req = NULL;
+ struct rsp_que *rsp = NULL;
struct scsi_qla_host *vha = sp->fcport->vha;
struct qla_hw_data *ha = vha->hw;
struct qla_qpair *qpair = sp->qpair;
@@ -318,13 +322,15 @@ static int qla2x00_start_nvme_mq(srb_t *sp)
struct nvmefc_fcp_req *fd = nvme->u.nvme.desc;
uint32_t rval = QLA_SUCCESS;
- /* Setup qpair pointers */
- req = qpair->req;
tot_dsds = fd->sg_cnt;
/* Acquire qpair specific lock */
spin_lock_irqsave(&qpair->qp_lock, flags);
+ /* Setup qpair pointers */
+ req = qpair->req;
+ rsp = qpair->rsp;
+
/* Check for room in outstanding command list. */
handle = req->current_outstanding_cmd;
for (index = 1; index < req->num_outstanding_cmds; index++) {
@@ -359,7 +365,7 @@ static int qla2x00_start_nvme_mq(srb_t *sp)
struct nvme_fc_cmd_iu *cmd = fd->cmdaddr;
if (cmd->sqe.common.opcode == nvme_admin_async_event) {
nvme->u.nvme.aen_op = 1;
- atomic_inc(&vha->nvme_active_aen_cnt);
+ atomic_inc(&vha->hw->nvme_active_aen_cnt);
}
}
@@ -472,6 +478,11 @@ static int qla2x00_start_nvme_mq(srb_t *sp)
/* Set chip new ring index. */
WRT_REG_DWORD(req->req_q_in, req->ring_index);
+ /* Manage unprocessed RIO/ZIO commands in response queue. */
+ if (vha->flags.process_response_queue &&
+ rsp->ring_ptr->signature != RESPONSE_PROCESSED)
+ qla24xx_process_response_queue(vha, rsp);
+
queuing_error:
spin_unlock_irqrestore(&qpair->qp_lock, flags);
return rval;
@@ -487,7 +498,7 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
struct scsi_qla_host *vha;
int rval = QLA_FUNCTION_FAILED;
srb_t *sp;
- struct qla_qpair *qpair = (struct qla_qpair *)hw_queue_handle;
+ struct qla_qpair *qpair = hw_queue_handle;
struct nvme_private *priv;
if (!fd) {
@@ -496,7 +507,7 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
}
priv = fd->private;
- fcport = (fc_port_t *)rport->private;
+ fcport = rport->private;
if (!fcport) {
ql_log(ql_log_warn, NULL, 0x210e, "No fcport ptr\n");
return rval;
@@ -512,7 +523,7 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
return -EIO;
atomic_set(&sp->ref_count, 1);
- init_waitqueue_head(&sp->nvme_ls_waitQ);
+ init_waitqueue_head(&sp->nvme_ls_waitq);
priv->sp = sp;
sp->type = SRB_NVME_CMD;
sp->name = "nvme_cmd";
@@ -526,7 +537,7 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
ql_log(ql_log_warn, vha, 0x212d,
"qla2x00_start_nvme_mq failed = %d\n", rval);
atomic_dec(&sp->ref_count);
- wake_up(&sp->nvme_ls_waitQ);
+ wake_up(&sp->nvme_ls_waitq);
return -EIO;
}
@@ -537,12 +548,10 @@ static void qla_nvme_localport_delete(struct nvme_fc_local_port *lport)
{
struct scsi_qla_host *vha = lport->private;
- atomic_dec(&vha->nvme_ref_count);
- wake_up_all(&vha->nvme_waitQ);
-
ql_log(ql_log_info, vha, 0x210f,
"localport delete of %p completed.\n", vha->nvme_local_port);
vha->nvme_local_port = NULL;
+ complete(&vha->nvme_del_done);
}
static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport)
@@ -550,11 +559,9 @@ static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport)
fc_port_t *fcport;
struct nvme_rport *r_port, *trport;
- fcport = (fc_port_t *)rport->private;
+ fcport = rport->private;
fcport->nvme_remote_port = NULL;
fcport->nvme_flag &= ~NVME_FLAG_REGISTERED;
- atomic_dec(&fcport->nvme_ref_count);
- wake_up_all(&fcport->nvme_waitQ);
list_for_each_entry_safe(r_port, trport,
&fcport->vha->nvme_rport_list, list) {
@@ -564,6 +571,7 @@ static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport)
}
}
kfree(r_port);
+ complete(&fcport->nvme_del_done);
ql_log(ql_log_info, fcport->vha, 0x2110,
"remoteport_delete of %p completed.\n", fcport);
@@ -594,7 +602,7 @@ static int qla_nvme_wait_on_command(srb_t *sp)
{
int ret = QLA_SUCCESS;
- wait_event_timeout(sp->nvme_ls_waitQ, (atomic_read(&sp->ref_count) > 1),
+ wait_event_timeout(sp->nvme_ls_waitq, (atomic_read(&sp->ref_count) > 1),
NVME_ABORT_POLLING_PERIOD*HZ);
if (atomic_read(&sp->ref_count) > 1)
@@ -606,12 +614,11 @@ static int qla_nvme_wait_on_command(srb_t *sp)
static int qla_nvme_wait_on_rport_del(fc_port_t *fcport)
{
int ret = QLA_SUCCESS;
+ int timeout;
- wait_event_timeout(fcport->nvme_waitQ,
- atomic_read(&fcport->nvme_ref_count),
- NVME_ABORT_POLLING_PERIOD*HZ);
-
- if (atomic_read(&fcport->nvme_ref_count)) {
+ timeout = wait_for_completion_timeout(&fcport->nvme_del_done,
+ msecs_to_jiffies(2000));
+ if (!timeout) {
ret = QLA_FUNCTION_FAILED;
ql_log(ql_log_info, fcport->vha, 0x2111,
"timed out waiting for fcport=%p to delete\n", fcport);
@@ -620,50 +627,14 @@ static int qla_nvme_wait_on_rport_del(fc_port_t *fcport)
return ret;
}
-void qla_nvme_abort(struct qla_hw_data *ha, srb_t *sp)
+void qla_nvme_abort(struct qla_hw_data *ha, struct srb *sp)
{
int rval;
rval = ha->isp_ops->abort_command(sp);
- if (!rval) {
- if (!qla_nvme_wait_on_command(sp))
- ql_log(ql_log_warn, NULL, 0x2112,
- "nvme_wait_on_command timed out waiting on sp=%p\n",
- sp);
- }
-}
-
-static void qla_nvme_abort_all(fc_port_t *fcport)
-{
- int que, cnt;
- unsigned long flags;
- srb_t *sp;
- struct qla_hw_data *ha = fcport->vha->hw;
- struct req_que *req;
-
- spin_lock_irqsave(&ha->hardware_lock, flags);
- for (que = 0; que < ha->max_req_queues; que++) {
- req = ha->req_q_map[que];
- if (!req)
- continue;
- if (!req->outstanding_cmds)
- continue;
- for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) {
- sp = req->outstanding_cmds[cnt];
- if ((sp) && ((sp->type == SRB_NVME_CMD) ||
- (sp->type == SRB_NVME_LS)) &&
- (sp->fcport == fcport)) {
- atomic_inc(&sp->ref_count);
- spin_unlock_irqrestore(&ha->hardware_lock,
- flags);
- qla_nvme_abort(ha, sp);
- spin_lock_irqsave(&ha->hardware_lock, flags);
- req->outstanding_cmds[cnt] = NULL;
- sp->done(sp, 1);
- }
- }
- }
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ if (!rval && !qla_nvme_wait_on_command(sp))
+ ql_log(ql_log_warn, NULL, 0x2112,
+ "nvme_wait_on_comand timed out waiting on sp=%p\n", sp);
}
static void qla_nvme_unregister_remote_port(struct work_struct *work)
@@ -675,18 +646,23 @@ static void qla_nvme_unregister_remote_port(struct work_struct *work)
if (!IS_ENABLED(CONFIG_NVME_FC))
return;
+ ql_log(ql_log_warn, NULL, 0x2112,
+ "%s: unregister remoteport on %p\n",__func__, fcport);
+
list_for_each_entry_safe(rport, trport,
&fcport->vha->nvme_rport_list, list) {
if (rport->fcport == fcport) {
ql_log(ql_log_info, fcport->vha, 0x2113,
"%s: fcport=%p\n", __func__, fcport);
+ init_completion(&fcport->nvme_del_done);
nvme_fc_unregister_remoteport(
fcport->nvme_remote_port);
+ qla_nvme_wait_on_rport_del(fcport);
}
}
}
-void qla_nvme_delete(scsi_qla_host_t *vha)
+void qla_nvme_delete(struct scsi_qla_host *vha)
{
struct nvme_rport *rport, *trport;
fc_port_t *fcport;
@@ -701,12 +677,13 @@ void qla_nvme_delete(scsi_qla_host_t *vha)
ql_log(ql_log_info, fcport->vha, 0x2114, "%s: fcport=%p\n",
__func__, fcport);
+ init_completion(&fcport->nvme_del_done);
nvme_fc_unregister_remoteport(fcport->nvme_remote_port);
qla_nvme_wait_on_rport_del(fcport);
- qla_nvme_abort_all(fcport);
}
if (vha->nvme_local_port) {
+ init_completion(&vha->nvme_del_done);
nv_ret = nvme_fc_unregister_localport(vha->nvme_local_port);
if (nv_ret == 0)
ql_log(ql_log_info, vha, 0x2116,
@@ -715,10 +692,12 @@ void qla_nvme_delete(scsi_qla_host_t *vha)
else
ql_log(ql_log_info, vha, 0x2115,
"Unregister of localport failed\n");
+ wait_for_completion_timeout(&vha->nvme_del_done,
+ msecs_to_jiffies(5000));
}
}
-void qla_nvme_register_hba(scsi_qla_host_t *vha)
+void qla_nvme_register_hba(struct scsi_qla_host *vha)
{
struct nvme_fc_port_template *tmpl;
struct qla_hw_data *ha;
@@ -744,8 +723,8 @@ void qla_nvme_register_hba(scsi_qla_host_t *vha)
pinfo.port_id = vha->d_id.b24;
ql_log(ql_log_info, vha, 0xffff,
- "register_localport: host-traddr=pn-0x%llx:nn-0x%llx on portID:%x\n",
- pinfo.port_name, pinfo.node_name, pinfo.port_id);
+ "register_localport: host-traddr=nn-0x%llx:pn-0x%llx on portID:%x\n",
+ pinfo.node_name, pinfo.port_name, pinfo.port_id);
qla_nvme_fc_transport.dma_boundary = vha->host->dma_boundary;
ret = nvme_fc_register_localport(&pinfo, tmpl,
@@ -755,7 +734,5 @@ void qla_nvme_register_hba(scsi_qla_host_t *vha)
"register_localport failed: ret=%x\n", ret);
return;
}
- atomic_set(&vha->nvme_ref_count, 1);
vha->nvme_local_port->private = vha;
- init_waitqueue_head(&vha->nvme_waitQ);
}
diff --git a/drivers/scsi/qla2xxx/qla_nvme.h b/drivers/scsi/qla2xxx/qla_nvme.h
index dfe56f207b28..7f05fa1c77db 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.h
+++ b/drivers/scsi/qla2xxx/qla_nvme.h
@@ -12,12 +12,18 @@
#include <uapi/scsi/fc/fc_els.h>
#include <linux/nvme-fc-driver.h>
+#include "qla_def.h"
+
#define NVME_ATIO_CMD_OFF 32
#define NVME_FIRST_PACKET_CMDLEN (64 - NVME_ATIO_CMD_OFF)
#define Q2T_NVME_NUM_TAGS 2048
#define QLA_MAX_FC_SEGMENTS 64
+struct scsi_qla_host;
+struct qla_hw_data;
+struct req_que;
struct srb;
+
struct nvme_private {
struct srb *sp;
struct nvmefc_ls_req *fd;
@@ -129,4 +135,15 @@ struct pt_ls4_rx_unsol {
uint32_t desc_len;
uint32_t payload[3];
};
+
+/*
+ * Global functions prototype in qla_nvme.c source file.
+ */
+void qla_nvme_register_hba(struct scsi_qla_host *);
+int qla_nvme_register_remote(struct scsi_qla_host *, struct fc_port *);
+void qla_nvme_delete(struct scsi_qla_host *);
+void qla_nvme_abort(struct qla_hw_data *, struct srb *sp);
+void qla24xx_nvme_ls4_iocb(struct scsi_qla_host *, struct pt_ls4_request *,
+ struct req_que *);
+void qla24xx_async_gffid_sp_done(void *, int);
#endif
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index df57655779ed..5b2437a5ea44 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -113,12 +113,12 @@ MODULE_PARM_DESC(ql2xfdmienable,
"Enables FDMI registrations. "
"0 - no FDMI. Default is 1 - perform FDMI.");
-#define MAX_Q_DEPTH 32
+#define MAX_Q_DEPTH 64
static int ql2xmaxqdepth = MAX_Q_DEPTH;
module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xmaxqdepth,
"Maximum queue depth to set for each LUN. "
- "Default is 32.");
+ "Default is 64.");
#if (IS_ENABLED(CONFIG_NVME_FC))
int ql2xenabledif;
@@ -200,7 +200,7 @@ MODULE_PARM_DESC(ql2xgffidenable,
"Enables GFF_ID checks of port type. "
"Default is 0 - Do not use GFF_ID information.");
-int ql2xasynctmfenable;
+int ql2xasynctmfenable = 1;
module_param(ql2xasynctmfenable, int, S_IRUGO);
MODULE_PARM_DESC(ql2xasynctmfenable,
"Enables issue of TM IOCBs asynchronously via IOCB mechanism"
@@ -262,6 +262,12 @@ MODULE_PARM_DESC(ql2xmvasynctoatio,
"0 (Default). Do not move IOCBs"
"1 - Move IOCBs.");
+int ql2xautodetectsfp = 1;
+module_param(ql2xautodetectsfp, int, 0444);
+MODULE_PARM_DESC(ql2xautodetectsfp,
+ "Detect SFP range and set appropriate distance.\n"
+ "1 (Default): Enable\n");
+
/*
* SCSI host template entry points
*/
@@ -379,6 +385,7 @@ static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req,
ha->base_qpair->use_shadow_reg = IS_SHADOW_REG_CAPABLE(ha) ? 1 : 0;
ha->base_qpair->msix = &ha->msix_entries[QLA_MSIX_RSP_Q];
INIT_LIST_HEAD(&ha->base_qpair->hints_list);
+ INIT_LIST_HEAD(&ha->base_qpair->nvme_done_list);
ha->base_qpair->enable_class_2 = ql2xenableclass2;
/* init qpair to this cpu. Will adjust at run time. */
qla_cpu_update(rsp->qpair, smp_processor_id());
@@ -710,7 +717,7 @@ qla2x00_sp_free_dma(void *ptr)
}
end:
- if ((sp->type != SRB_NVME_CMD) && (sp->type != SRB_NVME_LS)) {
+ if (sp->type != SRB_NVME_CMD && sp->type != SRB_NVME_LS) {
CMD_SP(cmd) = NULL;
qla2x00_rel_sp(sp);
}
@@ -735,7 +742,7 @@ qla2x00_sp_compl(void *ptr, int res)
if (!atomic_dec_and_test(&sp->ref_count))
return;
- qla2x00_sp_free_dma(sp);
+ sp->free(sp);
cmd->scsi_done(cmd);
}
@@ -807,7 +814,7 @@ qla2xxx_qpair_sp_compl(void *ptr, int res)
if (!atomic_dec_and_test(&sp->ref_count))
return;
- qla2xxx_qpair_sp_free_dma(sp);
+ sp->free(sp);
cmd->scsi_done(cmd);
}
@@ -928,7 +935,7 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
return 0;
qc24_host_busy_free_sp:
- qla2x00_sp_free_dma(sp);
+ sp->free(sp);
qc24_host_busy:
return SCSI_MLQUEUE_HOST_BUSY;
@@ -1017,7 +1024,7 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd,
return 0;
qc24_host_busy_free_sp:
- qla2xxx_qpair_sp_free_dma(sp);
+ sp->free(sp);
qc24_host_busy:
return SCSI_MLQUEUE_HOST_BUSY;
@@ -1134,7 +1141,7 @@ qla2x00_wait_for_sess_deletion(scsi_qla_host_t *vha)
{
qla2x00_mark_all_devices_lost(vha, 0);
- wait_event(vha->fcport_waitQ, test_fcport_count(vha));
+ wait_event_timeout(vha->fcport_waitQ, test_fcport_count(vha), 10*HZ);
}
/*
@@ -1715,8 +1722,8 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
if (sp) {
req->outstanding_cmds[cnt] = NULL;
if (sp->cmd_type == TYPE_SRB) {
- if ((sp->type == SRB_NVME_CMD) ||
- (sp->type == SRB_NVME_LS)) {
+ if (sp->type == SRB_NVME_CMD ||
+ sp->type == SRB_NVME_LS) {
sp_get(sp);
spin_unlock_irqrestore(
&ha->hardware_lock, flags);
@@ -1725,6 +1732,8 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
&ha->hardware_lock, flags);
} else if (GET_CMD_SP(sp) &&
!ha->flags.eeh_busy &&
+ (!test_bit(ABORT_ISP_ACTIVE,
+ &vha->dpc_flags)) &&
(sp->type == SRB_SCSI_CMD)) {
/*
* Don't abort commands in
@@ -2751,6 +2760,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init(&ha->tgt.sess_lock);
spin_lock_init(&ha->tgt.atio_lock);
+ atomic_set(&ha->nvme_active_aen_cnt, 0);
/* Clear our data area */
ha->bars = bars;
@@ -3168,7 +3178,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (ha->mqenable) {
bool mq = false;
bool startit = false;
- ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 1);
+ ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 0);
if (QLA_TGT_MODE_ENABLED()) {
mq = true;
@@ -3328,6 +3338,13 @@ skip_dpc:
if (test_bit(UNLOADING, &base_vha->dpc_flags))
return -ENODEV;
+ if (ha->flags.detected_lr_sfp) {
+ ql_log(ql_log_info, base_vha, 0xffff,
+ "Reset chip to pick up LR SFP setting\n");
+ set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
+ qla2xxx_wake_dpc(base_vha);
+ }
+
return 0;
probe_init_failed:
@@ -3383,12 +3400,22 @@ qla2x00_shutdown(struct pci_dev *pdev)
scsi_qla_host_t *vha;
struct qla_hw_data *ha;
- if (!atomic_read(&pdev->enable_cnt))
- return;
-
vha = pci_get_drvdata(pdev);
ha = vha->hw;
+ ql_log(ql_log_info, vha, 0xfffa,
+ "Adapter shutdown\n");
+
+ /*
+ * Prevent future board_disable and wait
+ * until any pending board_disable has completed.
+ */
+ set_bit(PFLG_DRIVER_REMOVING, &vha->pci_flags);
+ cancel_work_sync(&ha->board_disable);
+
+ if (!atomic_read(&pdev->enable_cnt))
+ return;
+
/* Notify ISPFX00 firmware */
if (IS_QLAFX00(ha))
qlafx00_driver_shutdown(vha, 20);
@@ -3419,8 +3446,9 @@ qla2x00_shutdown(struct pci_dev *pdev)
qla2x00_free_fw_dump(ha);
- pci_disable_pcie_error_reporting(pdev);
pci_disable_device(pdev);
+ ql_log(ql_log_info, vha, 0xfffe,
+ "Adapter shutdown successfully.\n");
}
/* Deletes all the virtual ports for a given ha */
@@ -4006,8 +4034,18 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
"loop_id_map=%p.\n", ha->loop_id_map);
}
+ ha->sfp_data = dma_alloc_coherent(&ha->pdev->dev,
+ SFP_DEV_SIZE, &ha->sfp_data_dma, GFP_KERNEL);
+ if (!ha->sfp_data) {
+ ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011b,
+ "Unable to allocate memory for SFP read-data.\n");
+ goto fail_sfp_data;
+ }
+
return 0;
+fail_sfp_data:
+ kfree(ha->loop_id_map);
fail_loop_id_map:
dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma);
fail_async_pd:
@@ -4345,7 +4383,8 @@ qla2x00_mem_free(struct qla_hw_data *ha)
ha->ct_sns, ha->ct_sns_dma);
if (ha->sfp_data)
- dma_pool_free(ha->s_dma_pool, ha->sfp_data, ha->sfp_data_dma);
+ dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE, ha->sfp_data,
+ ha->sfp_data_dma);
if (ha->ms_iocb)
dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
@@ -4638,9 +4677,10 @@ static
void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
{
unsigned long flags;
- fc_port_t *fcport = NULL;
+ fc_port_t *fcport = NULL, *tfcp;
struct qlt_plogi_ack_t *pla =
(struct qlt_plogi_ack_t *)e->u.new_sess.pla;
+ uint8_t free_fcport = 0;
spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
fcport = qla2x00_find_fcport_by_wwpn(vha, e->u.new_sess.port_name, 1);
@@ -4655,6 +4695,7 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
pla->ref_count--;
}
} else {
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
if (fcport) {
fcport->d_id = e->u.new_sess.id;
@@ -4664,6 +4705,29 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
memcpy(fcport->port_name, e->u.new_sess.port_name,
WWN_SIZE);
+ } else {
+ ql_dbg(ql_dbg_disc, vha, 0xffff,
+ "%s %8phC mem alloc fail.\n",
+ __func__, e->u.new_sess.port_name);
+
+ if (pla)
+ kmem_cache_free(qla_tgt_plogi_cachep, pla);
+ return;
+ }
+
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
+ /* search again to make sure one else got ahead */
+ tfcp = qla2x00_find_fcport_by_wwpn(vha,
+ e->u.new_sess.port_name, 1);
+ if (tfcp) {
+ /* should rarily happen */
+ ql_dbg(ql_dbg_disc, vha, 0xffff,
+ "%s %8phC found existing fcport b4 add. DS %d LS %d\n",
+ __func__, tfcp->port_name, tfcp->disc_state,
+ tfcp->fw_login_state);
+
+ free_fcport = 1;
+ } else {
list_add_tail(&fcport->list, &vha->vp_fcports);
if (pla) {
@@ -4681,6 +4745,12 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
else
qla24xx_async_gnl(vha, fcport);
}
+
+ if (free_fcport) {
+ qla2x00_free_fcport(fcport);
+ if (pla)
+ kmem_cache_free(qla_tgt_plogi_cachep, pla);
+ }
}
void
@@ -5493,6 +5563,13 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work)
ql_log(ql_log_warn, base_vha, 0x015b,
"Disabling adapter.\n");
+ if (!atomic_read(&pdev->enable_cnt)) {
+ ql_log(ql_log_info, base_vha, 0xfffc,
+ "PCI device disabled, no action req for PCI error=%lx\n",
+ base_vha->pci_flags);
+ return;
+ }
+
qla2x00_wait_for_sess_deletion(base_vha);
set_bit(UNLOADING, &base_vha->dpc_flags);
@@ -5687,6 +5764,16 @@ qla2x00_do_dpc(void *data)
}
}
+ if (test_and_clear_bit(DETECT_SFP_CHANGE,
+ &base_vha->dpc_flags) &&
+ !test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) {
+ qla24xx_detect_sfp(base_vha);
+
+ if (ha->flags.detected_lr_sfp !=
+ ha->flags.using_lr_setting)
+ set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
+ }
+
if (test_and_clear_bit(ISP_ABORT_NEEDED,
&base_vha->dpc_flags)) {
@@ -5828,6 +5915,17 @@ intr_on_check:
mutex_unlock(&ha->mq_lock);
}
+ if (test_and_clear_bit(SET_ZIO_THRESHOLD_NEEDED, &base_vha->dpc_flags)) {
+ ql_log(ql_log_info, base_vha, 0xffffff,
+ "nvme: SET ZIO Activity exchange threshold to %d.\n",
+ ha->nvme_last_rptd_aen);
+ if (qla27xx_set_zio_threshold(base_vha, ha->nvme_last_rptd_aen)) {
+ ql_log(ql_log_info, base_vha, 0xffffff,
+ "nvme: Unable to SET ZIO Activity exchange threshold to %d.\n",
+ ha->nvme_last_rptd_aen);
+ }
+ }
+
if (!IS_QLAFX00(ha))
qla2x00_do_dpc_all_vps(base_vha);
@@ -6025,12 +6123,15 @@ qla2x00_timer(scsi_qla_host_t *vha)
* FC-NVME
* see if the active AEN count has changed from what was last reported.
*/
- if (atomic_read(&vha->nvme_active_aen_cnt) != vha->nvme_last_rptd_aen) {
- vha->nvme_last_rptd_aen =
- atomic_read(&vha->nvme_active_aen_cnt);
+ if (!vha->vp_idx &&
+ atomic_read(&ha->nvme_active_aen_cnt) != ha->nvme_last_rptd_aen &&
+ ha->zio_mode == QLA_ZIO_MODE_6) {
ql_log(ql_log_info, vha, 0x3002,
- "reporting new aen count of %d to the fw\n",
- vha->nvme_last_rptd_aen);
+ "nvme: Sched: Set ZIO exchange threshold to %d.\n",
+ ha->nvme_last_rptd_aen);
+ ha->nvme_last_rptd_aen = atomic_read(&ha->nvme_active_aen_cnt);
+ set_bit(SET_ZIO_THRESHOLD_NEEDED, &vha->dpc_flags);
+ start_dpc++;
}
/* Schedule the DPC routine if needed */
@@ -6181,6 +6282,12 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
ql_dbg(ql_dbg_aer, vha, 0x9000,
"PCI error detected, state %x.\n", state);
+ if (!atomic_read(&pdev->enable_cnt)) {
+ ql_log(ql_log_info, vha, 0xffff,
+ "PCI device is disabled,state %x\n", state);
+ return PCI_ERS_RESULT_NEED_RESET;
+ }
+
switch (state) {
case pci_channel_io_normal:
ha->flags.eeh_busy = 0;
@@ -6574,6 +6681,8 @@ qla2x00_module_init(void)
strcpy(qla2x00_version_str, QLA2XXX_VERSION);
if (ql2xextended_error_logging)
strcat(qla2x00_version_str, "-debug");
+ if (ql2xextended_error_logging == 1)
+ ql2xextended_error_logging = QL_DBG_DEFAULT1_MASK;
qla2xxx_transport_template =
fc_attach_transport(&qla2xxx_transport_functions);
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index e101cd3043b9..f05cfc83c9c8 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -145,7 +145,7 @@ static void qlt_send_busy(struct qla_qpair *, struct atio_from_isp *,
* Global Variables
*/
static struct kmem_cache *qla_tgt_mgmt_cmd_cachep;
-static struct kmem_cache *qla_tgt_plogi_cachep;
+struct kmem_cache *qla_tgt_plogi_cachep;
static mempool_t *qla_tgt_mgmt_cmd_mempool;
static struct workqueue_struct *qla_tgt_wq;
static DEFINE_MUTEX(qla_tgt_mutex);
@@ -585,11 +585,13 @@ void qla2x00_async_nack_sp_done(void *s, int res)
sp->fcport->fw_login_state = DSC_LS_PLOGI_COMP;
sp->fcport->logout_on_delete = 1;
sp->fcport->plogi_nack_done_deadline = jiffies + HZ;
+ sp->fcport->send_els_logo = 0;
break;
case SRB_NACK_PRLI:
sp->fcport->fw_login_state = DSC_LS_PRLI_COMP;
sp->fcport->deleted = 0;
+ sp->fcport->send_els_logo = 0;
if (!sp->fcport->login_succ &&
!IS_SW_RESV_ADDR(sp->fcport->d_id)) {
@@ -1479,7 +1481,7 @@ int qlt_stop_phase1(struct qla_tgt *tgt)
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00a,
"Waiting for tgt %p: sess_count=%d\n", tgt, tgt->sess_count);
- wait_event(tgt->waitQ, test_tgt_sess_count(tgt));
+ wait_event_timeout(tgt->waitQ, test_tgt_sess_count(tgt), 10*HZ);
/* Big hammer */
if (!ha->flags.host_shutting_down &&
@@ -1487,7 +1489,7 @@ int qlt_stop_phase1(struct qla_tgt *tgt)
qlt_disable_vha(vha);
/* Wait for sessions to clear out (just in case) */
- wait_event(tgt->waitQ, test_tgt_sess_count(tgt));
+ wait_event_timeout(tgt->waitQ, test_tgt_sess_count(tgt), 10*HZ);
return 0;
}
EXPORT_SYMBOL(qlt_stop_phase1);
@@ -1528,6 +1530,7 @@ static void qlt_release(struct qla_tgt *tgt)
u64 key = 0;
u16 i;
struct qla_qpair_hint *h;
+ struct qla_hw_data *ha = vha->hw;
if ((vha->vha_tgt.qla_tgt != NULL) && !tgt->tgt_stop &&
!tgt->tgt_stopped)
@@ -1548,12 +1551,18 @@ static void qlt_release(struct qla_tgt *tgt)
}
}
kfree(tgt->qphints);
+ mutex_lock(&qla_tgt_mutex);
+ list_del(&vha->vha_tgt.qla_tgt->tgt_list_entry);
+ mutex_unlock(&qla_tgt_mutex);
btree_for_each_safe64(&tgt->lun_qpair_map, key, node)
btree_remove64(&tgt->lun_qpair_map, key);
btree_destroy64(&tgt->lun_qpair_map);
+ if (ha->tgt.tgt_ops && ha->tgt.tgt_ops->remove_target)
+ ha->tgt.tgt_ops->remove_target(vha);
+
vha->vha_tgt.qla_tgt = NULL;
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00d,
@@ -1901,6 +1910,7 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha,
mcmd->reset_count = ha->base_qpair->chip_reset;
mcmd->tmr_func = QLA_TGT_ABTS;
mcmd->qpair = ha->base_qpair;
+ mcmd->vha = vha;
/*
* LUN is looked up by target-core internally based on the passed
@@ -2003,7 +2013,7 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha,
static void qlt_24xx_send_task_mgmt_ctio(struct qla_qpair *qpair,
struct qla_tgt_mgmt_cmd *mcmd, uint32_t resp_code)
{
- struct scsi_qla_host *ha = qpair->vha;
+ struct scsi_qla_host *ha = mcmd->vha;
struct atio_from_isp *atio = &mcmd->orig_iocb.atio;
struct ctio7_to_24xx *ctio;
uint16_t temp;
@@ -3464,6 +3474,9 @@ static int __qlt_send_term_exchange(struct qla_qpair *qpair,
ql_dbg(ql_dbg_tgt, vha, 0xe009, "Sending TERM EXCH CTIO (ha=%p)\n", ha);
+ if (cmd)
+ vha = cmd->vha;
+
pkt = (request_t *)qla2x00_alloc_iocbs_ready(qpair, NULL);
if (pkt == NULL) {
ql_dbg(ql_dbg_tgt, vha, 0xe050,
@@ -4379,6 +4392,7 @@ static int qlt_issue_task_mgmt(struct fc_port *sess, u64 lun,
mcmd->flags = flags;
mcmd->reset_count = ha->base_qpair->chip_reset;
mcmd->qpair = ha->base_qpair;
+ mcmd->vha = vha;
switch (fn) {
case QLA_TGT_LUN_RESET:
@@ -6170,10 +6184,6 @@ int qlt_remove_target(struct qla_hw_data *ha, struct scsi_qla_host *vha)
/* free left over qfull cmds */
qlt_init_term_exchange(vha);
- mutex_lock(&qla_tgt_mutex);
- list_del(&vha->vha_tgt.qla_tgt->tgt_list_entry);
- mutex_unlock(&qla_tgt_mutex);
-
ql_dbg(ql_dbg_tgt, vha, 0xe03c, "Unregistering target for host %ld(%p)",
vha->host_no, ha);
qlt_release(vha->vha_tgt.qla_tgt);
@@ -6530,7 +6540,6 @@ qlt_24xx_process_atio_queue(struct scsi_qla_host *vha, uint8_t ha_locked)
/* Adjust ring index */
WRT_REG_DWORD(ISP_ATIO_Q_OUT(vha), ha->tgt.atio_ring_index);
- RD_REG_DWORD_RELAXED(ISP_ATIO_Q_OUT(vha));
}
void
@@ -6796,7 +6805,7 @@ qlt_probe_one_stage1(struct scsi_qla_host *base_vha, struct qla_hw_data *ha)
if (!QLA_TGT_MODE_ENABLED())
return;
- if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
ISP_ATIO_Q_IN(base_vha) = &ha->mqiobase->isp25mq.atio_q_in;
ISP_ATIO_Q_OUT(base_vha) = &ha->mqiobase->isp25mq.atio_q_out;
} else {
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index 7fe02d036bdf..aba58d3848a6 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -705,6 +705,7 @@ struct qla_tgt_func_tmpl {
int (*get_dif_tags)(struct qla_tgt_cmd *cmd, uint16_t *pfw_prot_opts);
int (*chk_dif_tags)(uint32_t tag);
void (*add_target)(struct scsi_qla_host *);
+ void (*remove_target)(struct scsi_qla_host *);
};
int qla2x00_wait_for_hba_online(struct scsi_qla_host *);
@@ -959,6 +960,7 @@ struct qla_tgt_mgmt_cmd {
uint8_t fc_tm_rsp;
struct fc_port *sess;
struct qla_qpair *qpair;
+ struct scsi_qla_host *vha;
struct se_cmd se_cmd;
struct work_struct free_work;
unsigned int flags;
diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c
index b18646d6057f..733e8dcccf5c 100644
--- a/drivers/scsi/qla2xxx/qla_tmpl.c
+++ b/drivers/scsi/qla2xxx/qla_tmpl.c
@@ -443,8 +443,12 @@ qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha,
qla27xx_skip_entry(ent, buf);
}
- if (buf)
- ent->t263.num_queues = count;
+ if (buf) {
+ if (count)
+ ent->t263.num_queues = count;
+ else
+ qla27xx_skip_entry(ent, buf);
+ }
return false;
}
@@ -692,11 +696,12 @@ qla27xx_fwdt_entry_t274(struct scsi_qla_host *vha,
qla27xx_skip_entry(ent, buf);
}
- if (buf)
- ent->t274.num_queues = count;
-
- if (!count)
- qla27xx_skip_entry(ent, buf);
+ if (buf) {
+ if (count)
+ ent->t274.num_queues = count;
+ else
+ qla27xx_skip_entry(ent, buf);
+ }
return false;
}
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 005a378f7fab..8c4b505c9f66 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "10.00.00.00-k"
+#define QLA2XXX_VERSION "10.00.00.01-k"
#define QLA_DRIVER_MAJOR_VER 10
#define QLA_DRIVER_MINOR_VER 0