diff options
-rw-r--r-- | drivers/scsi/qla2xxx/Makefile | 3 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 35 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_dbg.c | 3 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 54 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 85 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gs.c | 2 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_init.c | 233 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_inline.h | 5 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_iocb.c | 74 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 42 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mbx.c | 158 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_nx.c | 3635 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_nx.h | 888 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 346 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_sup.c | 80 |
15 files changed, 5518 insertions, 125 deletions
diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile index 1014db6f992..5df782f4a09 100644 --- a/drivers/scsi/qla2xxx/Makefile +++ b/drivers/scsi/qla2xxx/Makefile @@ -1,4 +1,5 @@ qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \ - qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o qla_bsg.o + qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o qla_bsg.o \ + qla_nx.o obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 0710e3c8760..c272af4a76e 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -41,6 +41,12 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj, struct qla_hw_data *ha = vha->hw; int reading; + if (IS_QLA82XX(ha)) { + DEBUG2(qla_printk(KERN_INFO, ha, + "Firmware dump not supported for ISP82xx\n")); + return count; + } + if (off != 0) return (0); @@ -313,8 +319,8 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, else if (start == (ha->flt_region_boot * 4) || start == (ha->flt_region_fw * 4)) valid = 1; - else if (IS_QLA25XX(ha) || IS_QLA81XX(ha)) - valid = 1; + else if (IS_QLA25XX(ha) || IS_QLA8XXX_TYPE(ha)) + valid = 1; if (!valid) { qla_printk(KERN_WARNING, ha, "Invalid start region 0x%x/0x%x.\n", start, size); @@ -517,6 +523,7 @@ qla2x00_sysfs_write_reset(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; + struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); int type; if (off != 0) @@ -551,6 +558,20 @@ qla2x00_sysfs_write_reset(struct kobject *kobj, "MPI reset failed on (%ld).\n", vha->host_no); scsi_unblock_requests(vha->host); break; + case 0x2025e: + if (!IS_QLA82XX(ha) || vha != base_vha) { + qla_printk(KERN_INFO, ha, + "FCoE ctx reset not supported for host%ld.\n", + vha->host_no); + return count; + } + + qla_printk(KERN_INFO, ha, + "Issuing FCoE CTX reset on host%ld.\n", vha->host_no); + set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + qla2x00_wait_for_fcoe_ctx_reset(vha); + break; } return count; } @@ -836,7 +857,7 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha) continue; if (iter->is4GBp_only == 2 && !IS_QLA25XX(vha->hw)) continue; - if (iter->is4GBp_only == 3 && !IS_QLA81XX(vha->hw)) + if (iter->is4GBp_only == 3 && !(IS_QLA8XXX_TYPE(vha->hw))) continue; ret = sysfs_create_bin_file(&host->shost_gendev.kobj, @@ -860,7 +881,7 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha) continue; if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha)) continue; - if (iter->is4GBp_only == 3 && !IS_QLA81XX(ha)) + if (iter->is4GBp_only == 3 && !!(IS_QLA8XXX_TYPE(vha->hw))) continue; sysfs_remove_bin_file(&host->shost_gendev.kobj, @@ -1233,7 +1254,7 @@ qla2x00_vlan_id_show(struct device *dev, struct device_attribute *attr, { scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - if (!IS_QLA81XX(vha->hw)) + if (!IS_QLA8XXX_TYPE(vha->hw)) return snprintf(buf, PAGE_SIZE, "\n"); return snprintf(buf, PAGE_SIZE, "%d\n", vha->fcoe_vlan_id); @@ -1245,7 +1266,7 @@ qla2x00_vn_port_mac_address_show(struct device *dev, { scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - if (!IS_QLA81XX(vha->hw)) + if (!IS_QLA8XXX_TYPE(vha->hw)) return snprintf(buf, PAGE_SIZE, "\n"); return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n", @@ -1922,7 +1943,7 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha) fc_host_max_npiv_vports(vha->host) = ha->max_npiv_vports; fc_host_npiv_vports_inuse(vha->host) = ha->cur_vport_count; - if (IS_QLA81XX(ha)) + if (IS_QLA8XXX_TYPE(ha)) speed = FC_PORTSPEED_10GBIT; else if (IS_QLA25XX(ha)) speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT | diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index cb2eca4c26d..89bfc119010 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -769,6 +769,9 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) void *nxt; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); + if (IS_QLA82XX(ha)) + return; + risc_address = ext_mem_cnt = 0; flags = 0; diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index c51bd4e5fb4..edb7a704ed7 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -34,6 +34,7 @@ #include <scsi/scsi_bsg_fc.h> #include "qla_bsg.h" +#include "qla_nx.h" #define QLA2XXX_DRIVER_NAME "qla2xxx" /* @@ -207,6 +208,7 @@ typedef struct srb { * SRB flag definitions */ #define SRB_DMA_VALID BIT_0 /* Command sent to ISP */ +#define SRB_FCP_CMND_DMA_VALID BIT_12 /* FCP command in IOCB */ /* * SRB extensions. @@ -417,6 +419,7 @@ typedef union { struct device_reg_2xxx isp; struct device_reg_24xx isp24; struct device_reg_25xxmq isp25mq; + struct device_reg_82xx isp82; } device_reg_t; #define ISP_REQ_Q_IN(ha, reg) \ @@ -2112,6 +2115,7 @@ struct isp_operations { int (*get_flash_version) (struct scsi_qla_host *, void *); int (*start_scsi) (srb_t *); + int (*abort_isp) (struct scsi_qla_host *); }; /* MSI-X Support *************************************************************/ @@ -2386,7 +2390,8 @@ struct qla_hw_data { #define DT_ISP2532 BIT_11 #define DT_ISP8432 BIT_12 #define DT_ISP8001 BIT_13 -#define DT_ISP_LAST (DT_ISP8001 << 1) +#define DT_ISP8021 BIT_14 +#define DT_ISP_LAST (DT_ISP8021 << 1) #define DT_IIDMA BIT_26 #define DT_FWI2 BIT_27 @@ -2409,6 +2414,7 @@ struct qla_hw_data { #define IS_QLA2532(ha) (DT_MASK(ha) & DT_ISP2532) #define IS_QLA8432(ha) (DT_MASK(ha) & DT_ISP8432) #define IS_QLA8001(ha) (DT_MASK(ha) & DT_ISP8001) +#define IS_QLA82XX(ha) (DT_MASK(ha) & DT_ISP8021) #define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \ IS_QLA6312(ha) || IS_QLA6322(ha)) @@ -2419,8 +2425,10 @@ struct qla_hw_data { #define IS_QLA24XX_TYPE(ha) (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \ IS_QLA84XX(ha)) #define IS_QLA81XX(ha) (IS_QLA8001(ha)) +#define IS_QLA8XXX_TYPE(ha) (IS_QLA81XX(ha) || IS_QLA82XX(ha)) #define IS_QLA2XXX_MIDTYPE(ha) (IS_QLA24XX(ha) || IS_QLA84XX(ha) || \ - IS_QLA25XX(ha) || IS_QLA81XX(ha)) + IS_QLA25XX(ha) || IS_QLA81XX(ha) || \ + IS_QLA82XX(ha)) #define IS_MSIX_NACK_CAPABLE(ha) (IS_QLA81XX(ha)) #define IS_NOPOLLING_TYPE(ha) ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && \ (ha)->flags.msix_enabled) @@ -2603,6 +2611,7 @@ struct qla_hw_data { uint32_t flt_region_npiv_conf; uint32_t flt_region_gold_fw; uint32_t flt_region_fcp_prio; + uint32_t flt_region_bootload; /* Needed for BEACON */ uint16_t beacon_blink_led; @@ -2634,6 +2643,38 @@ struct qla_hw_data { /* FCP_CMND priority support */ struct qla_fcp_prio_cfg *fcp_prio_cfg; + + struct dma_pool *dl_dma_pool; +#define DSD_LIST_DMA_POOL_SIZE 512 + + struct dma_pool *fcp_cmnd_dma_pool; + mempool_t *ctx_mempool; +#define FCP_CMND_DMA_POOL_SIZE 512 + + unsigned long nx_pcibase; /* Base I/O address */ + uint8_t *nxdb_rd_ptr; /* Doorbell read pointer */ + unsigned long nxdb_wr_ptr; /* Door bell write pointer */ + unsigned long first_page_group_start; + unsigned long first_page_group_end; + + uint32_t crb_win; + uint32_t curr_window; + uint32_t ddr_mn_window; + unsigned long mn_win_crb; + unsigned long ms_win_crb; + int qdr_sn_window; + uint32_t nx_dev_init_timeout; + uint32_t nx_reset_timeout; + rwlock_t hw_lock; + uint16_t portnum; /* port number */ + int link_width; + struct fw_blob *hablob; + struct qla82xx_legacy_intr_set nx_legacy_intr; + + uint16_t gbl_dsd_inuse; + uint16_t gbl_dsd_avail; + struct list_head gbl_dsd_list; +#define NUM_DSD_CHAIN 4096 }; /* @@ -2686,10 +2727,13 @@ typedef struct scsi_qla_host { #define VP_DPC_NEEDED 14 /* wake up for VP dpc handling */ #define UNLOADING 15 #define NPIV_CONFIG_NEEDED 16 +#define ISP_UNRECOVERABLE 17 +#define FCOE_CTX_RESET_NEEDED 18 /* Initiate FCoE context reset */ uint32_t device_flags; #define SWITCH_FOUND BIT_0 #define DFLG_NO_CABLE BIT_1 +#define DFLG_DEV_FAILED BIT_5 /* ISP configuration data. */ uint16_t loop_id; /* Host adapter loop id */ @@ -2747,6 +2791,8 @@ typedef struct scsi_qla_host { #define VP_ERR_ADAP_NORESOURCES 5 struct qla_hw_data *hw; struct req_que *req; + int fw_heartbeat_counter; + int seconds_since_last_heartbeat; } scsi_qla_host_t; /* @@ -2799,6 +2845,10 @@ typedef struct scsi_qla_host { #define OPTROM_SIZE_24XX 0x100000 #define OPTROM_SIZE_25XX 0x200000 #define OPTROM_SIZE_81XX 0x400000 +#define OPTROM_SIZE_82XX 0x800000 + +#define OPTROM_BURST_SIZE 0x1000 +#define OPTROM_BURST_DWORDS (OPTROM_BURST_SIZE / 4) #include "qla_gbl.h" #include "qla_dbg.h" diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 5efd4c05c79..cff5a4ae762 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -44,6 +44,7 @@ extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *); extern void qla2x00_update_fcports(scsi_qla_host_t *); extern int qla2x00_abort_isp(scsi_qla_host_t *); +extern void qla2x00_abort_isp_cleanup(scsi_qla_host_t *); extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *); @@ -79,6 +80,9 @@ extern int ql2xmaxqueues; extern int ql2xmultique_tag; extern int ql2xfwloadbin; extern int ql2xetsenable; +extern int ql2xshiftctondsd; +extern int ql2xdbwr; +extern int ql2xdontresethba; extern int qla2x00_loop_reset(scsi_qla_host_t *); extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); @@ -135,6 +139,7 @@ extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *); extern int qla2x00_wait_for_hba_online(scsi_qla_host_t *); extern int qla2x00_wait_for_chip_reset(scsi_qla_host_t *); +extern int qla2x00_wait_for_fcoe_ctx_reset(scsi_qla_host_t *); extern void qla2xxx_wake_dpc(struct scsi_qla_host *); extern void qla2x00_alert_all_vps(struct rsp_que *, uint16_t *); @@ -157,6 +162,9 @@ int __qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *, uint16_t, uint16_t, uint8_t); extern int qla2x00_start_sp(srb_t *); extern void qla2x00_ctx_sp_free(srb_t *); +extern uint16_t qla24xx_calc_iocbs(uint16_t); +extern void qla24xx_build_scsi_iocbs(srb_t *, struct cmd_type_7 *, uint16_t); + /* * Global Function Prototypes in qla_mbx.c source file. @@ -343,6 +351,7 @@ qla24xx_process_response_queue(struct scsi_qla_host *, struct rsp_que *); extern int qla2x00_request_irqs(struct qla_hw_data *, struct rsp_que *); extern void qla2x00_free_irqs(scsi_qla_host_t *); +extern int qla2x00_get_data_rate(scsi_qla_host_t *); /* * Global Function Prototypes in qla_sup.c source file. */ @@ -466,6 +475,82 @@ extern void qla25xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t); extern void qla25xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t); extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t); +/* qla82xx related functions */ + +/* PCI related functions */ +extern int qla82xx_pci_config(struct scsi_qla_host *); +extern int qla82xx_pci_mem_read_2M(struct qla_hw_data *, u64, void *, int); +extern int qla82xx_pci_mem_write_2M(struct qla_hw_data *, u64, void *, int); +extern char *qla82xx_pci_info_str(struct scsi_qla_host *, char *); +extern int qla82xx_pci_region_offset(struct pci_dev *, int); +extern int qla82xx_pci_region_len(struct pci_dev *, int); +extern int qla82xx_iospace_config(struct qla_hw_data *); + +/* Initialization related functions */ +extern void qla82xx_reset_chip(struct scsi_qla_host *); +extern void qla82xx_config_rings(struct scsi_qla_host *); +extern int qla82xx_nvram_config(struct scsi_qla_host *); +extern int qla82xx_pinit_from_rom(scsi_qla_host_t *); +extern int qla82xx_load_firmware(scsi_qla_host_t *); +extern int qla82xx_reset_hw(scsi_qla_host_t *); +extern int qla82xx_load_risc_blob(scsi_qla_host_t *, uint32_t *); +extern void qla82xx_watchdog(scsi_qla_host_t *); + +/* Firmware and flash related functions */ +extern int qla82xx_load_risc(scsi_qla_host_t *, uint32_t *); +extern uint8_t *qla82xx_read_optrom_data(struct scsi_qla_host *, uint8_t *, + uint32_t, uint32_t); +extern int qla82xx_write_optrom_data(struct scsi_qla_host *, uint8_t *, + uint32_t, uint32_t); + +/* Mailbox related functions */ +extern int qla82xx_abort_isp(scsi_qla_host_t *); +extern int qla82xx_restart_isp(scsi_qla_host_t *); + +/* IOCB related functions */ +extern int qla82xx_start_scsi(srb_t *); + +/* Interrupt related */ +extern irqreturn_t qla82xx_intr_handler(int, void *); +extern irqreturn_t qla82xx_msi_handler(int, void *); +extern irqreturn_t qla82xx_msix_default(int, void *); +extern irqreturn_t qla82xx_msix_rsp_q(int, void *); +extern void qla82xx_enable_intrs(struct qla_hw_data *); +extern void qla82xx_disable_intrs(struct qla_hw_data *); +extern void qla82xx_mbx_completion(scsi_qla_host_t *, uint16_t); +extern void qla82xx_poll(int, void *); +extern void qla82xx_init_flags(struct qla_hw_data *); + +/* ISP 8021 hardware related */ +extern int qla82xx_crb_win_lock(struct qla_hw_data *); +extern void qla82xx_crb_win_unlock(struct qla_hw_data *); +extern int qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *, ulong *); +extern int qla82xx_wr_32(struct qla_hw_data *, ulong, u32); +extern int qla82xx_rd_32(struct qla_hw_data *, ulong); +extern int qla82xx_rdmem(struct qla_hw_data *, u64, void *, int); +extern int qla82xx_wrmem(struct qla_hw_data *, u64, void *, int); +extern int qla82xx_check_for_bad_spd(struct qla_hw_data *); +extern int qla82xx_load_fw(scsi_qla_host_t *); +extern int qla82xx_rom_lock(struct qla_hw_data *); +extern void qla82xx_rom_unlock(struct qla_hw_data *); +extern int qla82xx_rom_fast_read(struct qla_hw_data *, int , int *); +extern int qla82xx_do_rom_fast_read(struct qla_hw_data *, int, int *); +extern unsigned long qla82xx_decode_crb_addr(unsigned long); + +/* ISP 8021 IDC */ +extern void qla82xx_clear_drv_active(struct qla_hw_data *); +extern int qla82xx_idc_lock(struct qla_hw_data *); +extern void qla82xx_idc_unlock(struct qla_hw_data *); +extern int qla82xx_device_state_handler(scsi_qla_host_t *); + +extern void qla2x00_set_model_info(scsi_qla_host_t *, uint8_t *, + size_t, char *); +extern int qla82xx_mbx_intr_enable(scsi_qla_host_t *); +extern int qla82xx_mbx_intr_disable(scsi_qla_host_t *); +extern void qla82xx_start_iocbs(srb_t *); +extern int qla82xx_fcoe_ctx_reset(scsi_qla_host_t *); +extern void qla82xx_wait_for_pending_commands(scsi_qla_host_t *); + /* BSG related functions */ extern int qla24xx_bsg_request(struct fc_bsg_job *); extern int qla24xx_bsg_timeout(struct fc_bsg_job *); diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 4647015eba6..872c55f049a 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1535,7 +1535,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha) eiter = (struct ct_fdmi_port_attr *) (entries + size); eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED); eiter->len = __constant_cpu_to_be16(4 + 4); - if (IS_QLA81XX(ha)) + if (IS_QLA8XXX_TYPE(ha)) eiter->a.sup_speed = __constant_cpu_to_be32( FDMI_PORT_SPEED_10GB); else if (IS_QLA25XX(ha)) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 8517aa49744..55540d2d4e3 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -328,6 +328,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) if (rval) return (rval); } + if (IS_QLA84XX(ha)) { ha->cs84xx = qla84xx_get_chip(vha); if (!ha->cs84xx) { @@ -961,6 +962,9 @@ qla24xx_chip_diag(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; + if (IS_QLA82XX(ha)) + return QLA_SUCCESS; + ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length; rval = qla2x00_mbx_reg_test(vha); @@ -1183,6 +1187,12 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) unsigned long flags; uint16_t fw_major_version; + if (IS_QLA82XX(ha)) { + rval = ha->isp_ops->load_risc(vha, &srisc_address); + if (rval == QLA_SUCCESS) + goto enable_82xx_npiv; + } + if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) { /* Disable SRAM, Instruction RAM and GP RAM parity. */ spin_lock_irqsave(&ha->hardware_lock, flags); @@ -1208,6 +1218,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) rval = qla2x00_execute_fw(vha, srisc_address); /* Retrieve firmware information. */ if (rval == QLA_SUCCESS) { +enable_82xx_npiv: fw_major_version = ha->fw_major_version; rval = qla2x00_get_fw_version(vha, &ha->fw_major_version, @@ -1232,8 +1243,10 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) &ha->fw_xcb_count, NULL, NULL, &ha->max_npiv_vports, NULL); - if (!fw_major_version && ql2xallocfwdump) - qla2x00_alloc_fw_dump(vha); + if (!fw_major_version && ql2xallocfwdump) { + if (!IS_QLA82XX(ha)) + qla2x00_alloc_fw_dump(vha); + } } } else { DEBUG2(printk(KERN_INFO @@ -1390,6 +1403,9 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha) int rval; struct qla_hw_data *ha = vha->hw; + if (IS_QLA82XX(ha)) + return; + /* Update Serial Link options. */ if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0) return; @@ -1824,7 +1840,7 @@ qla2x00_configure_hba(scsi_qla_host_t *vha) return(rval); } -static inline void +inline void qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len, char *def) { @@ -1832,7 +1848,7 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len, uint16_t index; struct qla_hw_data *ha = vha->hw; int use_tbl = !IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && - !IS_QLA81XX(ha); + !IS_QLA8XXX_TYPE(ha); if (memcmp(model, BINZERO, len) != 0) { strncpy(ha->model_number, model, len); @@ -3552,6 +3568,45 @@ qla2x00_update_fcports(scsi_qla_host_t *base_vha) qla2x00_rport_del(fcport); } +void +qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) +{ + struct qla_hw_data *ha = vha->hw; + struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev); + struct scsi_qla_host *tvp; + + vha->flags.online = 0; + ha->flags.chip_reset_done = 0; + clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + ha->qla_stats.total_isp_aborts++; + + qla_printk(KERN_INFO, ha, + "Performing ISP error recovery - ha= %p.\n", ha); + + /* Chip reset does not apply to 82XX */ + if (!IS_QLA82XX(ha)) + ha->isp_ops->reset_chip(vha); + + atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); + if (atomic_read(&vha->loop_state) != LOOP_DOWN) { + atomic_set(&vha->loop_state, LOOP_DOWN); + qla2x00_mark_all_devices_lost(vha, 0); + list_for_each_entry_safe(vp, tvp, &base_vha->hw->vp_list, list) + qla2x00_mark_all_devices_lost(vp, 0); + } else { + if (!atomic_read(&vha->loop_down_timer)) + atomic_set(&vha->loop_down_timer, + LOOP_DOWN_TIME); + } + + /* Make sure for ISP 82XX IO DMA is complete */ + if (IS_QLA82XX(ha)) + qla82xx_wait_for_pending_commands(vha); + + /* Requeue all commands in outstanding command list. */ + qla2x00_abort_all_cmds(vha, DID_RESET << 16); +} + /* * qla2x00_abort_isp * Resets ISP and aborts all outstanding commands. @@ -3573,27 +3628,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) struct req_que *req = ha->req_q_map[0]; if (vha->flags.online) { - vha->flags.online = 0; - ha->flags.chip_reset_done = 0; - clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - ha->qla_stats.total_isp_aborts++; - - qla_printk(KERN_INFO, ha, - "Performing ISP error recovery - ha= %p.\n", ha); - ha->isp_ops->reset_chip(vha); - - atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); - if (atomic_read(&vha->loop_state) != LOOP_DOWN) { - atomic_set(&vha->loop_state, LOOP_DOWN); - qla2x00_mark_all_devices_lost(vha, 0); - } else { - if (!atomic_read(&vha->loop_down_timer)) - atomic_set(&vha->loop_down_timer, - LOOP_DOWN_TIME); - } - - /* Requeue all commands in outstanding command list. */ - qla2x00_abort_all_cmds(vha, DID_RESET << 16); + qla2x00_abort_isp_cleanup(vha); if (unlikely(pci_channel_offline(ha->pdev) && ha->flags.pci_channel_io_perm_failure)) { @@ -3849,6 +3884,9 @@ qla24xx_reset_adapter(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + if (IS_QLA82XX(ha)) + return; + vha->flags.online = 0; ha->isp_ops->disable_intrs(ha); @@ -3912,6 +3950,8 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) } ha->nvram_size = sizeof(struct nvram_24xx); ha->vpd_size = FA_NVRAM_VPD_SIZE; + if (IS_QLA82XX(ha)) + ha->vpd_size = FA_VPD_SIZE_82XX; /* Get VPD data into cache */ ha->vpd = ha->nvram + VPD_OFFSET; @@ -4775,7 +4815,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) * Setup driver NVRAM options. */ qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name), - "QLE81XX"); + "QLE8XXX"); /* Use alternate WWN? */ if (nv->host_p & __constant_cpu_to_le32(BIT_15)) { @@ -4898,6 +4938,147 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) return (rval); } +int +qla82xx_restart_isp(scsi_qla_host_t *vha) +{ + int status, rval; + uint32_t wait_time; + struct qla_hw_data *ha = vha->hw; + struct req_que *req = ha->req_q_map[0]; + struct rsp_que *rsp = ha->rsp_q_map[0]; + struct scsi_qla_host *vp; + struct scsi_qla_host *tvp; + + status = qla2x00_init_rings(vha); + if (!status) { + clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); + ha->flags.chip_reset_done = 1; + + status = qla2x00_fw_ready(vha); + if (!status) { + qla_printk(KERN_INFO, ha, + "%s(): Start configure loop, " + "status = %d\n", __func__, status); + + /* Issue a marker after FW becomes ready. */ + qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL); + + vha->flags.online = 1; + /* Wait at most MAX_TARGET RSCNs for a stable link. */ + wait_time = 256; + do { + clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); + qla2x00_configure_loop(vha); + wait_time--; + } while (!atomic_read(&vha->loop_down_timer) && + !(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) && + wait_time && + (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))); + } + + /* if no cable then assume it's good */ + if ((vha->device_flags & DFLG_NO_CABLE)) + status = 0; + + qla_printk(KERN_INFO, ha, + "%s(): Configure loop done, status = 0x%x\n", + __func__, status); + } + + if (!status) { + clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); + + if (!atomic_read(&vha->loop_down_timer)) { + /* + * Issue marker command only when we are going + * to start the I/O . + */ + vha->marker_needed = 1; + } + + vha->flags.online = 1; + + ha->isp_ops->enable_intrs(ha); + + ha->isp_abort_cnt = 0; + clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags); + + if (ha->fce) { + ha->flags.fce_enabled = 1; + memset(ha->fce, 0, + fce_calc_size(ha->fce_bufs)); + rval = qla2x00_enable_fce_trace(vha, + ha->fce_dma, ha->fce_bufs, ha->fce_mb, + &ha->fce_bufs); + if (rval) { + qla_printk(KERN_WARNING, ha, + "Unable to reinitialize FCE " + "(%d).\n", rval); + ha->flags.fce_enabled = 0; + } + } + + if (ha->eft) { + memset(ha->eft, 0, EFT_SIZE); + rval = qla2x00_enable_eft_trace(vha, + ha->eft_dma, EFT_NUM_BUFFERS); + if (rval) { + qla_printk(KERN_WARNING, ha, + "Unable to reinitialize EFT " + "(%d).\n", rval); + } + } + } else { /* failed the ISP abort */ + vha->flags.online = 1; + if (test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { + if (ha->isp_abort_cnt == 0) { + qla_printk(KERN_WARNING, ha, + "ISP error recovery failed - " + "board disabled\n"); + /* + * The next call disables the board + * completely. + */ + ha->isp_ops->reset_adapter(vha); + vha->flags.online = 0; + clear_bit(ISP_ABORT_RETRY, + &vha->dpc_flags); + status = 0; + } else { /* schedule another ISP abort */ + ha->isp_abort_cnt--; + qla_printk(KERN_INFO, ha, + "qla%ld: ISP abort - " + "retry remaining %d\n", + vha->host_no, ha->isp_abort_cnt); + status = 1; + } + } else { + ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT; + qla_printk(KERN_INFO, ha, + "(%ld): ISP error recovery " + "- retrying (%d) more times\n", + vha->host_no, ha->isp_abort_cnt); + set_bit(ISP_ABORT_RETRY, &vha->dpc_flags); + status = 1; + } + } + + if (!status) { + DEBUG(printk(KERN_INFO + "qla82xx_restart_isp(%ld): succeeded.\n", + vha->host_no)); + list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { + if (vp->vp_idx) + qla2x00_vp_abort_isp(vp); + } + } else { + qla_printk(KERN_INFO, ha, + "qla82xx_restart_isp: **** FAILED ****\n"); + } + + return status; +} + void qla81xx_update_fw_options(scsi_qla_host_t *vha) { diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 5e0a7095c9f..ad53c645555 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -37,7 +37,10 @@ qla2x00_poll(struct rsp_que *rsp) unsigned long flags; struct qla_hw_data *ha = rsp->hw; local_irq_save(flags); - ha->isp_ops->intr_handler(0, rsp); + if (IS_QLA82XX(ha)) + qla82xx_poll(0, rsp); + else + ha->isp_ops->intr_handler(0, rsp); local_irq_restore(flags); } diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 8299a9891bf..d792ae32ed6 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -506,7 +506,10 @@ qla2x00_req_pkt(struct scsi_qla_host *vha, struct req_que *req, cnt = (uint16_t) RD_REG_DWORD(®->isp25mq.req_q_out); else { - if (IS_FWI2_CAPABLE(ha)) + if (IS_QLA82XX(ha)) + cnt = (uint16_t)RD_REG_DWORD( + ®->isp82.req_q_out); + else if (IS_FWI2_CAPABLE(ha)) cnt = (uint16_t)RD_REG_DWORD( ®->isp24.req_q_out); else @@ -579,11 +582,29 @@ qla2x00_isp_cmd(struct scsi_qla_host *vha, struct req_que *req) req->ring_ptr++; /* Set chip new ring index. */ - if (ha->mqenable) { + if (IS_QLA82XX(ha)) { + uint32_t dbval = 0x04 | (ha->portnum << 5); + + /* write, read and verify logic */ + dbval = dbval | (req->id << 8) | (req->ring_index << 16); + if (ql2xdbwr) + qla82xx_wr_32(ha, ha->nxdb_wr_ptr, dbval); + else { + WRT_REG_DWORD( + (unsigned long __iomem *)ha->nxdb_wr_ptr, + dbval); + wmb(); + while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) { + WRT_REG_DWORD((unsigned long __iomem *) + ha->nxdb_wr_ptr, dbval); + wmb(); + } + } + } else if (ha->mqenable) { + /* Set chip new ring index. */ WRT_REG_DWORD(®->isp25mq.req_q_in, req->ring_index); RD_REG_DWORD(&ioreg->hccr); - } - else { + } else { if (IS_FWI2_CAPABLE(ha)) { WRT_REG_DWORD(®->isp24.req_q_in, req->ring_index); RD_REG_DWORD_RELAXED(®->isp24.req_q_in); @@ -604,7 +625,7 @@ qla2x00_isp_cmd(struct scsi_qla_host *vha, struct req_que *req) * * Returns the number of IOCB entries needed to store @dsds. */ -static inline uint16_t +inline uint16_t qla24xx_calc_iocbs(uint16_t dsds) { uint16_t iocbs; @@ -626,7 +647,7 @@ qla24xx_calc_iocbs(uint16_t dsds) * @cmd_pkt: Command type 3 IOCB * @tot_dsds: Total number of segments to transfer */ -static inline void +inline void qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, uint16_t tot_dsds) { @@ -931,24 +952,31 @@ qla2x00_start_iocbs(srb_t *sp) device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id); struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp; - /* Adjust ring index. */ - req->ring_index++; - if (req->ring_index == req->length) { - req->ring_index = 0; - req->ring_ptr = req->ring; - } else - req->ring_ptr++; - - /* Set chip new ring index. */ - if (ha->mqenable) { - WRT_REG_DWORD(®->isp25mq.req_q_in, req->ring_index); - RD_REG_DWORD(&ioreg->hccr); - } else if (IS_FWI2_CAPABLE(ha)) { - WRT_REG_DWORD(®->isp24.req_q_in, req->ring_index); - RD_REG_DWORD_RELAXED(®->isp24.req_q_in); + if (IS_QLA82XX(ha)) { + qla82xx_start_iocbs(sp); } else { - WRT_REG_WORD(ISP_REQ_Q_IN(ha, ®->isp), req->ring_index); - RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, ®->isp)); + /* Adjust ring index. */ + req->ring_index++; + if (req->ring_index == req->length) { + req->ring_index = 0; + req->ring_ptr = req->ring; + } else + req->ring_ptr++; + + /* Set chip new ring index. */ + if (ha->mqenable) { + WRT_REG_DWORD(®->isp25mq.req_q_in, req->ring_index); + RD_REG_DWORD(&ioreg->hccr); + } else if (IS_QLA82XX(ha)) { + qla82xx_start_iocbs(sp); + } else if (IS_FWI2_CAPABLE(ha)) { + WRT_REG_DWORD(®->isp24.req_q_in, req->ring_index); + RD_REG_DWORD_RELAXED(®->isp24.req_q_in); + } else { + WRT_REG_WORD(ISP_REQ_Q_IN(ha, ®->isp), + req->ring_index); + RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, ®->isp)); + } } } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index db539b0c3da..f1ac62d505d 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -326,7 +326,7 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) /* Setup to process RIO completion. */ handle_cnt = 0; - if (IS_QLA81XX(ha)) + if (IS_QLA8XXX_TYPE(ha)) goto skip_rio; switch (mb[0]) { case MBA_SCSI_COMPLETION: @@ -544,7 +544,7 @@ skip_rio: if (IS_QLA2100(ha)) break; - if (IS_QLA81XX(ha)) + if (IS_QLA8XXX_TYPE(ha)) DEBUG2(printk("scsi(%ld): DCBX Completed -- %04x %04x " "%04x\n", vha->host_no, mb[1], mb[2], mb[3])); else @@ -845,7 +845,7 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha, qla2x00_sp_compl(ha, sp); } else { DEBUG2(printk("scsi(%ld) Req:%d: Invalid ISP SCSI completion" - " handle(%d)\n", vha->host_no, req->id, index)); + " handle(0x%x)\n", vha->host_no, req->id, index)); qla_printk(KERN_WARNING, ha, "Invalid ISP SCSI completion handle\n"); @@ -1337,6 +1337,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) handle = (uint32_t) LSW(sts->handle); que = MSW(sts->handle); req = ha->req_q_map[que]; + /* Fast path completion. */ if (comp_status == CS_COMPLETE && scsi_status == 0) { qla2x00_process_completed_request(vha, req, handle); @@ -1806,6 +1807,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, struct rsp_que *rsp) { struct sts_entry_24xx *pkt; + struct qla_hw_data *ha = vha->hw; if (!vha->flags.online) return; @@ -1866,7 +1868,11 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, } /* Adjust ring index */ - WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index); + if (IS_QLA82XX(ha)) { + struct device_reg_82xx __iomem *reg = &ha->iobase->isp82; + WRT_REG_DWORD(®->rsp_q_out[0], rsp->ring_index); + } else + WR |