diff options
Diffstat (limited to 'drivers/scsi/qla2xxx')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 86 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_dbg.c | 10 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 118 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_fw.h | 28 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 22 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gs.c | 18 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_init.c | 183 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_iocb.c | 55 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 78 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mbx.c | 263 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mid.c | 14 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mr.c | 7 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_nvme.c | 161 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_nvme.h | 17 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 155 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_target.c | 29 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_target.h | 2 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_tmpl.c | 19 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_version.h | 2 |
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(®->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(®->hccr, HCCRX_CLR_RISC_INT); RD_REG_DWORD_RELAXED(®->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(®->isp24.host_status), - ha->fw_dump_cap_flags, RD_REG_DWORD(®->isp24.ictrl), RD_REG_DWORD(®->isp24.istatus)); - - mbx_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 |