diff options
Diffstat (limited to 'drivers/scsi')
151 files changed, 6434 insertions, 4272 deletions
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 06ea3bcfdd2..16570aa84aa 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -830,16 +830,11 @@ config SCSI_ISCI tristate "Intel(R) C600 Series Chipset SAS Controller" depends on PCI && SCSI depends on X86 - # (temporary): known alpha quality driver - depends on EXPERIMENTAL select SCSI_SAS_LIBSAS - select SCSI_SAS_HOST_SMP ---help--- This driver supports the 6Gb/s SAS capabilities of the storage control unit found in the Intel(R) C600 series chipset. - The experimental tag will be removed after the driver exits alpha - config SCSI_GENERIC_NCR5380 tristate "Generic NCR5380/53c400 SCSI PIO support" depends on ISA && SCSI diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 8a0b3303317..0bd38da4ada 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -650,6 +650,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) AAC_OPT_NEW_COMM) ? (dev->scsi_host_ptr->max_sectors << 9) : 65536)) { + kfree(usg); rcode = -EINVAL; goto cleanup; } diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 195823a51aa..ed119cedaae 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -102,7 +102,7 @@ static int setup_dmaspeed[MAXBOARDS] __initdata = { -1, -1, -1, -1 }; */ #if defined(MODULE) -static int isapnp = 0; +static bool isapnp = 0; static int aha1542[] = {0x330, 11, 4, -1}; module_param_array(aha1542, int, NULL, 0); module_param(isapnp, bool, 0); diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm.c b/drivers/scsi/aic7xxx/aicasm/aicasm.c index e4a77872030..2e3117aa382 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm.c +++ b/drivers/scsi/aic7xxx/aicasm/aicasm.c @@ -1,5 +1,5 @@ /* - * Aic7xxx SCSI host adapter firmware asssembler + * Aic7xxx SCSI host adapter firmware assembler * * Copyright (c) 1997, 1998, 2000, 2001 Justin T. Gibbs. * Copyright (c) 2001, 2002 Adaptec Inc. diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 8b002f6db6c..33c8f09c7ac 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -733,7 +733,7 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep); } -mode_t be2iscsi_attr_is_visible(int param_type, int param) +umode_t be2iscsi_attr_is_visible(int param_type, int param) { switch (param_type) { case ISCSI_HOST_PARAM: diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h index 4a1f2e393f3..5c45be13450 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.h +++ b/drivers/scsi/be2iscsi/be_iscsi.h @@ -26,7 +26,7 @@ #define BE2_IPV4 0x1 #define BE2_IPV6 0x10 -mode_t be2iscsi_attr_is_visible(int param_type, int param); +umode_t be2iscsi_attr_is_visible(int param_type, int param); void beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, struct beiscsi_offload_params *params); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 379c696dac1..375756fa95c 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -325,9 +325,9 @@ static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf) } -static mode_t beiscsi_tgt_get_attr_visibility(void *data, int type) +static umode_t beiscsi_tgt_get_attr_visibility(void *data, int type) { - int rc; + umode_t rc; switch (type) { case ISCSI_BOOT_TGT_NAME: @@ -348,9 +348,9 @@ static mode_t beiscsi_tgt_get_attr_visibility(void *data, int type) return rc; } -static mode_t beiscsi_ini_get_attr_visibility(void *data, int type) +static umode_t beiscsi_ini_get_attr_visibility(void *data, int type) { - int rc; + umode_t rc; switch (type) { case ISCSI_BOOT_INI_INITIATOR_NAME: @@ -364,9 +364,9 @@ static mode_t beiscsi_ini_get_attr_visibility(void *data, int type) } -static mode_t beiscsi_eth_get_attr_visibility(void *data, int type) +static umode_t beiscsi_eth_get_attr_visibility(void *data, int type) { - int rc; + umode_t rc; switch (type) { case ISCSI_BOOT_ETH_FLAGS: @@ -1105,7 +1105,6 @@ be_complete_io(struct beiscsi_conn *beiscsi_conn, struct be_status_bhs *sts_bhs = (struct be_status_bhs *)io_task->cmd_bhs; struct iscsi_conn *conn = beiscsi_conn->conn; - unsigned int sense_len; unsigned char *sense; u32 resid = 0, exp_cmdsn, max_cmdsn; u8 rsp, status, flags; @@ -1153,9 +1152,11 @@ be_complete_io(struct beiscsi_conn *beiscsi_conn, } if (status == SAM_STAT_CHECK_CONDITION) { + u16 sense_len; unsigned short *slen = (unsigned short *)sts_bhs->sense_info; + sense = sts_bhs->sense_info + sizeof(unsigned short); - sense_len = cpu_to_be16(*slen); + sense_len = be16_to_cpu(*slen); memcpy(task->sc->sense_buffer, sense, min_t(u16, sense_len, SCSI_SENSE_BUFFERSIZE)); } diff --git a/drivers/scsi/bfa/bfa_defs.h b/drivers/scsi/bfa/bfa_defs.h index 7b3d235d20b..b5a1595cc0a 100644 --- a/drivers/scsi/bfa/bfa_defs.h +++ b/drivers/scsi/bfa/bfa_defs.h @@ -902,7 +902,7 @@ struct sfp_mem_s { union sfp_xcvr_e10g_code_u { u8 b; struct { -#ifdef __BIGENDIAN +#ifdef __BIG_ENDIAN u8 e10g_unall:1; /* 10G Ethernet compliance */ u8 e10g_lrm:1; u8 e10g_lr:1; @@ -982,7 +982,7 @@ union sfp_xcvr_fc2_code_u { union sfp_xcvr_fc3_code_u { u8 b; struct { -#ifdef __BIGENDIAN +#ifdef __BIG_ENDIAN u8 rsv4:1; u8 mb800:1; /* 800 Mbytes/sec */ u8 mb1600:1; /* 1600 Mbytes/sec */ diff --git a/drivers/scsi/bfa/bfa_defs_svc.h b/drivers/scsi/bfa/bfa_defs_svc.h index 863c6ba7d5e..cb07c628b2f 100644 --- a/drivers/scsi/bfa/bfa_defs_svc.h +++ b/drivers/scsi/bfa/bfa_defs_svc.h @@ -34,22 +34,22 @@ struct bfa_iocfc_intr_attr_s { u8 coalesce; /* enable/disable coalescing */ u8 rsvd[3]; - __be16 latency; /* latency in microseconds */ - __be16 delay; /* delay in microseconds */ + __be16 latency; /* latency in microseconds */ + __be16 delay; /* delay in microseconds */ }; /* * IOC firmware configuraton */ struct bfa_iocfc_fwcfg_s { - u16 num_fabrics; /* number of fabrics */ - u16 num_lports; /* number of local lports */ - u16 num_rports; /* number of remote ports */ - u16 num_ioim_reqs; /* number of IO reqs */ - u16 num_tskim_reqs; /* task management requests */ - u16 num_fwtio_reqs; /* number of TM IO reqs in FW */ - u16 num_fcxp_reqs; /* unassisted FC exchanges */ - u16 num_uf_bufs; /* unsolicited recv buffers */ + u16 num_fabrics; /* number of fabrics */ + u16 num_lports; /* number of local lports */ + u16 num_rports; /* number of remote ports */ + u16 num_ioim_reqs; /* number of IO reqs */ + u16 num_tskim_reqs; /* task management requests */ + u16 num_fwtio_reqs; /* number of TM IO reqs in FW */ + u16 num_fcxp_reqs; /* unassisted FC exchanges */ + u16 num_uf_bufs; /* unsolicited recv buffers */ u8 num_cqs; u8 fw_tick_res; /* FW clock resolution in ms */ u8 rsvd[2]; @@ -57,19 +57,19 @@ struct bfa_iocfc_fwcfg_s { #pragma pack() struct bfa_iocfc_drvcfg_s { - u16 num_reqq_elems; /* number of req queue elements */ - u16 num_rspq_elems; /* number of rsp queue elements */ - u16 num_sgpgs; /* number of total SG pages */ - u16 num_sboot_tgts; /* number of SAN boot targets */ - u16 num_sboot_luns; /* number of SAN boot luns */ - u16 ioc_recover; /* IOC recovery mode */ - u16 min_cfg; /* minimum configuration */ - u16 path_tov; /* device path timeout */ - u16 num_tio_reqs; /*!< number of TM IO reqs */ + u16 num_reqq_elems; /* number of req queue elements */ + u16 num_rspq_elems; /* number of rsp queue elements */ + u16 num_sgpgs; /* number of total SG pages */ + u16 num_sboot_tgts; /* number of SAN boot targets */ + u16 num_sboot_luns; /* number of SAN boot luns */ + u16 ioc_recover; /* IOC recovery mode */ + u16 min_cfg; /* minimum configuration */ + u16 path_tov; /* device path timeout */ + u16 num_tio_reqs; /* number of TM IO reqs */ u8 port_mode; u8 rsvd_a; - bfa_boolean_t delay_comp; /* delay completion of - failed inflight IOs */ + bfa_boolean_t delay_comp; /* delay completion of failed + * inflight IOs */ u16 num_ttsk_reqs; /* TM task management requests */ u32 rsvd; }; @@ -101,8 +101,8 @@ struct bfa_fw_ioim_stats_s { u32 fw_frm_drop; /* f/w drop the frame */ u32 rec_timeout; /* FW rec timed out */ - u32 error_rec; /* FW sending rec on - * an error condition*/ + u32 error_rec; /* FW sending rec on + * an error condition*/ u32 wait_for_si; /* FW wait for SI */ u32 rec_rsp_inval; /* REC rsp invalid */ u32 seqr_io_abort; /* target does not know cmd so abort */ @@ -124,9 +124,9 @@ struct bfa_fw_ioim_stats_s { u32 unexp_fcp_rsp; /* fcp response in wrong state */ u32 fcp_rsp_under_run; /* fcp rsp IO underrun */ - u32 fcp_rsp_under_run_wr; /* fcp rsp IO underrun for write */ + u32 fcp_rsp_under_run_wr; /* fcp rsp IO underrun for write */ u32 fcp_rsp_under_run_err; /* fcp rsp IO underrun error */ - u32 fcp_rsp_resid_inval; /* invalid residue */ + u32 fcp_rsp_resid_inval; /* invalid residue */ u32 fcp_rsp_over_run; /* fcp rsp IO overrun */ u32 fcp_rsp_over_run_err; /* fcp rsp IO overrun error */ u32 fcp_rsp_proto_err; /* protocol error in fcp rsp */ @@ -142,21 +142,20 @@ struct bfa_fw_ioim_stats_s { u32 ioh_hit_class2_event; /* IOH hit class2 */ u32 ioh_miss_other_event; /* IOH miss other */ u32 ioh_seq_cnt_err_event; /* IOH seq cnt error */ - u32 ioh_len_err_event; /* IOH len error - fcp_dl != - * bytes xfered */ + u32 ioh_len_err_event; /* IOH len error - fcp_dl != + * bytes xfered */ u32 ioh_seq_len_err_event; /* IOH seq len error */ u32 ioh_data_oor_event; /* Data out of range */ u32 ioh_ro_ooo_event; /* Relative offset out of range */ u32 ioh_cpu_owned_event; /* IOH hit -iost owned by f/w */ u32 ioh_unexp_frame_event; /* unexpected frame received - * count */ + * count */ u32 ioh_err_int; /* IOH error int during data-phase - * for scsi write - */ + * for scsi write */ }; struct bfa_fw_tio_stats_s { - u32 tio_conf_proc; /* TIO CONF processed */ + u32 tio_conf_proc; /* TIO CONF processed */ u32 tio_conf_drop; /* TIO CONF dropped */ u32 tio_cleanup_req; /* TIO cleanup requested */ u32 tio_cleanup_comp; /* TIO cleanup completed */ @@ -164,34 +163,36 @@ struct bfa_fw_tio_stats_s { u32 tio_abort_rsp_comp; /* TIO abort rsp completed */ u32 tio_abts_req; /* TIO ABTS requested */ u32 tio_abts_ack; /* TIO ABTS ack-ed */ - u32 tio_abts_ack_nocomp; /* TIO ABTS ack-ed but not completed */ + u32 tio_abts_ack_nocomp;/* TIO ABTS ack-ed but not completed */ u32 tio_abts_tmo; /* TIO ABTS timeout */ u32 tio_snsdata_dma; /* TIO sense data DMA */ - u32 tio_rxwchan_wait; /* TIO waiting for RX wait channel */ - u32 tio_rxwchan_avail; /* TIO RX wait channel available */ + u32 tio_rxwchan_wait; /* TIO waiting for RX wait channel */ + u32 tio_rxwchan_avail; /* TIO RX wait channel available */ u32 tio_hit_bls; /* TIO IOH BLS event */ u32 tio_uf_recv; /* TIO received UF */ - u32 tio_rd_invalid_sm; /* TIO read reqst in wrong state machine */ - u32 tio_wr_invalid_sm;/* TIO write reqst in wrong state machine */ + u32 tio_rd_invalid_sm; /* TIO read reqst in wrong state machine */ + u32 tio_wr_invalid_sm; /* TIO write reqst in wrong state machine */ - u32 ds_rxwchan_wait; /* DS waiting for RX wait channel */ - u32 ds_rxwchan_avail; /* DS RX wait channel available */ + u32 ds_rxwchan_wait; /* DS waiting for RX wait channel */ + u32 ds_rxwchan_avail; /* DS RX wait channel available */ u32 ds_unaligned_rd; /* DS unaligned read */ - u32 ds_rdcomp_invalid_sm; /* DS read completed in wrong state machine */ - u32 ds_wrcomp_invalid_sm; /* DS write completed in wrong state machine */ + u32 ds_rdcomp_invalid_sm; /* DS read completed in wrong state + * machine */ + u32 ds_wrcomp_invalid_sm; /* DS write completed in wrong state + * machine */ u32 ds_flush_req; /* DS flush requested */ u32 ds_flush_comp; /* DS flush completed */ u32 ds_xfrdy_exp; /* DS XFER_RDY expired */ u32 ds_seq_cnt_err; /* DS seq cnt error */ u32 ds_seq_len_err; /* DS seq len error */ u32 ds_data_oor; /* DS data out of order */ - u32 ds_hit_bls; /* DS hit BLS */ + u32 ds_hit_bls; /* DS hit BLS */ u32 ds_edtov_timer_exp; /* DS edtov expired */ u32 ds_cpu_owned; /* DS cpu owned */ u32 ds_hit_class2; /* DS hit class2 */ u32 ds_length_err; /* DS length error */ u32 ds_ro_ooo_err; /* DS relative offset out-of-order error */ - u32 ds_rectov_timer_exp; /* DS rectov expired */ + u32 ds_rectov_timer_exp;/* DS rectov expired */ u32 ds_unexp_fr_err; /* DS unexp frame error */ }; @@ -208,119 +209,119 @@ struct bfa_fw_io_stats_s { */ struct bfa_fw_port_fpg_stats_s { - u32 intr_evt; - u32 intr; - u32 intr_excess; - u32 intr_cause0; - u32 intr_other; - u32 intr_other_ign; - u32 sig_lost; - u32 sig_regained; - u32 sync_lost; - u32 sync_to; - u32 sync_regained; - u32 div2_overflow; - u32 div2_underflow; - u32 efifo_overflow; - u32 efifo_underflow; - u32 idle_rx; - u32 lrr_rx; - u32 lr_rx; - u32 ols_rx; - u32 nos_rx; - u32 lip_rx; - u32 arbf0_rx; - u32 arb_rx; - u32 mrk_rx; - u32 const_mrk_rx; - u32 prim_unknown; + u32 intr_evt; + u32 intr; + u32 intr_excess; + u32 intr_cause0; + u32 intr_other; + u32 intr_other_ign; + u32 sig_lost; + u32 sig_regained; + u32 sync_lost; + u32 sync_to; + u32 sync_regained; + u32 div2_overflow; + u32 div2_underflow; + u32 efifo_overflow; + u32 efifo_underflow; + u32 idle_rx; + u32 lrr_rx; + u32 lr_rx; + u32 ols_rx; + u32 nos_rx; + u32 lip_rx; + u32 arbf0_rx; + u32 arb_rx; + u32 mrk_rx; + u32 const_mrk_rx; + u32 prim_unknown; }; struct bfa_fw_port_lksm_stats_s { - u32 hwsm_success; /* hwsm state machine success */ - u32 hwsm_fails; /* hwsm fails */ - u32 hwsm_wdtov; /* hwsm timed out */ - u32 swsm_success; /* swsm success */ - u32 swsm_fails; /* swsm fails */ - u32 swsm_wdtov; /* swsm timed out */ - u32 busybufs; /* link init failed due to busybuf */ - u32 buf_waits; /* bufwait state entries */ - u32 link_fails; /* link failures */ - u32 psp_errors; /* primitive sequence protocol errors */ - u32 lr_unexp; /* No. of times LR rx-ed unexpectedly */ - u32 lrr_unexp; /* No. of times LRR rx-ed unexpectedly */ - u32 lr_tx; /* No. of times LR tx started */ - u32 lrr_tx; /* No. of times LRR tx started */ - u32 ols_tx; /* No. of times OLS tx started */ - u32 nos_tx; /* No. of times NOS tx started */ - u32 hwsm_lrr_rx; /* No. of times LRR rx-ed by HWSM */ - u32 hwsm_lr_rx; /* No. of times LR rx-ed by HWSM */ - u32 bbsc_lr; /* LKSM LR tx for credit recovery */ + u32 hwsm_success; /* hwsm state machine success */ + u32 hwsm_fails; /* hwsm fails */ + u32 hwsm_wdtov; /* hwsm timed out */ + u32 swsm_success; /* swsm success */ + u32 swsm_fails; /* swsm fails */ + u32 swsm_wdtov; /* swsm timed out */ + u32 busybufs; /* link init failed due to busybuf */ + u32 buf_waits; /* bufwait state entries */ + u32 link_fails; /* link failures */ + u32 psp_errors; /* primitive sequence protocol errors */ + u32 lr_unexp; /* No. of times LR rx-ed unexpectedly */ + u32 lrr_unexp; /* No. of times LRR rx-ed unexpectedly */ + u32 lr_tx; /* No. of times LR tx started */ + u32 lrr_tx; /* No. of times LRR tx started */ + u32 ols_tx; /* No. of times OLS tx started */ + u32 nos_tx; /* No. of times NOS tx started */ + u32 hwsm_lrr_rx; /* No. of times LRR rx-ed by HWSM */ + u32 hwsm_lr_rx; /* No. of times LR rx-ed by HWSM */ + u32 bbsc_lr; /* LKSM LR tx for credit recovery */ }; struct bfa_fw_port_snsm_stats_s { - u32 hwsm_success; /* Successful hwsm terminations */ - u32 hwsm_fails; /* hwsm fail count */ - u32 hwsm_wdtov; /* hwsm timed out */ - u32 swsm_success; /* swsm success */ - u32 swsm_wdtov; /* swsm timed out */ - u32 error_resets; /* error resets initiated by upsm */ - u32 sync_lost; /* Sync loss count */ - u32 sig_lost; /* Signal loss count */ - u32 asn8g_attempts; /* SNSM HWSM at 8Gbps attempts */ + u32 hwsm_success; /* Successful hwsm terminations */ + u32 hwsm_fails; /* hwsm fail count */ + u32 hwsm_wdtov; /* hwsm timed out */ + u32 swsm_success; /* swsm success */ + u32 swsm_wdtov; /* swsm timed out */ + u32 error_resets; /* error resets initiated by upsm */ + u32 sync_lost; /* Sync loss count */ + u32 sig_lost; /* Signal loss count */ + u32 asn8g_attempts; /* SNSM HWSM at 8Gbps attempts */ }; struct bfa_fw_port_physm_stats_s { - u32 module_inserts; /* Module insert count */ - u32 module_xtracts; /* Module extracts count */ - u32 module_invalids; /* Invalid module inserted count */ - u32 module_read_ign; /* Module validation status ignored */ - u32 laser_faults; /* Laser fault count */ - u32 rsvd; + u32 module_inserts; /* Module insert count */ + u32 module_xtracts; /* Module extracts count */ + u32 module_invalids; /* Invalid module inserted count */ + u32 module_read_ign; /* Module validation status ignored */ + u32 laser_faults; /* Laser fault count */ + u32 rsvd; }; struct bfa_fw_fip_stats_s { - u32 vlan_req; /* vlan discovery requests */ - u32 vlan_notify; /* vlan notifications */ - u32 vlan_err; /* vlan response error */ - u32 vlan_timeouts; /* vlan disvoery timeouts */ - u32 vlan_invalids; /* invalid vlan in discovery advert. */ - u32 disc_req; /* Discovery solicit requests */ - u32 disc_rsp; /* Discovery solicit response */ - u32 disc_err; /* Discovery advt. parse errors */ - u32 disc_unsol; /* Discovery unsolicited */ - u32 disc_timeouts; /* Discovery timeouts */ - u32 disc_fcf_unavail; /* Discovery FCF Not Avail. */ - u32 linksvc_unsupp; /* Unsupported link service req */ - u32 linksvc_err; /* Parse error in link service req */ - u32 logo_req; /* FIP logos received */ - u32 clrvlink_req; /* Clear virtual link req */ - u32 op_unsupp; /* Unsupported FIP operation */ - u32 untagged; /* Untagged frames (ignored) */ - u32 invalid_version; /* Invalid FIP version */ + u32 vlan_req; /* vlan discovery requests */ + u32 vlan_notify; /* vlan notifications */ + u32 vlan_err; /* vlan response error */ + u32 vlan_timeouts; /* vlan disvoery timeouts */ + u32 vlan_invalids; /* invalid vlan in discovery advert. */ + u32 disc_req; /* Discovery solicit requests */ + u32 disc_rsp; /* Discovery solicit response */ + u32 disc_err; /* Discovery advt. parse errors */ + u32 disc_unsol; /* Discovery unsolicited */ + u32 disc_timeouts; /* Discovery timeouts */ + u32 disc_fcf_unavail; /* Discovery FCF Not Avail. */ + u32 linksvc_unsupp; /* Unsupported link service req */ + u32 linksvc_err; /* Parse error in link service req */ + u32 logo_req; /* FIP logos received */ + u32 clrvlink_req; /* Clear virtual link req */ + u32 op_unsupp; /* Unsupported FIP operation */ + u32 untagged; /* Untagged frames (ignored) */ + u32 invalid_version; /* Invalid FIP version */ }; struct bfa_fw_lps_stats_s { - u32 mac_invalids; /* Invalid mac assigned */ - u32 rsvd; + u32 mac_invalids; /* Invalid mac assigned */ + u32 rsvd; }; struct bfa_fw_fcoe_stats_s { - u32 cee_linkups; /* CEE link up count */ - u32 cee_linkdns; /* CEE link down count */ - u32 fip_linkups; /* FIP link up count */ - u32 fip_linkdns; /* FIP link up count */ - u32 fip_fails; /* FIP fail count */ - u32 mac_invalids; /* Invalid mac assigned */ + u32 cee_linkups; /* CEE link up count */ + u32 cee_linkdns; /* CEE link down count */ + u32 fip_linkups; /* FIP link up count */ + u32 fip_linkdns; /* FIP link up count */ + u32 fip_fails; /* FIP fail count */ + u32 mac_invalids; /* Invalid mac assigned */ }; /* * IOC firmware FCoE port stats */ struct bfa_fw_fcoe_port_stats_s { - struct bfa_fw_fcoe_stats_s fcoe_stats; - struct bfa_fw_fip_stats_s fip_stats; + struct bfa_fw_fcoe_stats_s fcoe_stats; + struct bfa_fw_fip_stats_s fip_stats; }; /* @@ -335,8 +336,8 @@ struct bfa_fw_fc_uport_stats_s { * IOC firmware FC port stats */ union bfa_fw_fc_port_stats_s { - struct bfa_fw_fc_uport_stats_s fc_stats; - struct bfa_fw_fcoe_port_stats_s fcoe_stats; + struct bfa_fw_fc_uport_stats_s fc_stats; + struct bfa_fw_fcoe_port_stats_s fcoe_stats; }; /* @@ -366,25 +367,25 @@ struct bfa_fw_lpsm_stats_s { */ struct bfa_fw_trunk_stats_s { u32 emt_recvd; /* Trunk EMT received */ - u32 emt_accepted; /* Trunk EMT Accepted */ - u32 emt_rejected; /* Trunk EMT rejected */ + u32 emt_accepted; /* Trunk EMT Accepted */ + u32 emt_rejected; /* Trunk EMT rejected */ u32 etp_recvd; /* Trunk ETP received */ - u32 etp_accepted; /* Trunk ETP Accepted */ - u32 etp_rejected; /* Trunk ETP rejected */ + u32 etp_accepted; /* Trunk ETP Accepted */ + u32 etp_rejected; /* Trunk ETP rejected */ u32 lr_recvd; /* Trunk LR received */ - u32 rsvd; /* padding for 64 bit alignment */ + u32 rsvd; /* padding for 64 bit alignment */ }; struct bfa_fw_advsm_stats_s { u32 flogi_sent; /* Flogi sent */ u32 flogi_acc_recvd; /* Flogi Acc received */ u32 flogi_rjt_recvd; /* Flogi rejects received */ - u32 flogi_retries; /* Flogi retries */ + u32 flogi_retries; /* Flogi retries */ u32 elp_recvd; /* ELP received */ - u32 elp_accepted; /* ELP Accepted */ - u32 elp_rejected; /* ELP rejected */ - u32 elp_dropped; /* ELP dropped */ + u32 elp_accepted; /* ELP Accepted */ + u32 elp_rejected; /* ELP rejected */ + u32 elp_dropped; /* ELP dropped */ }; /* @@ -521,7 +522,7 @@ struct bfa_qos_vc_attr_s { u16 total_vc_count; /* Total VC Count */ u16 shared_credit; u32 elp_opmode_flags; - struct bfa_qos_vc_info_s vc_info[BFA_QOS_MAX_VC]; /* as many as + struct bfa_qos_vc_info_s vc_info[BFA_QOS_MAX_VC]; /* as many as * total_vc_count */ }; @@ -531,16 +532,16 @@ struct bfa_qos_vc_attr_s { struct bfa_qos_stats_s { u32 flogi_sent; /* QoS Flogi sent */ u32 flogi_acc_recvd; /* QoS Flogi Acc received */ - u32 flogi_rjt_recvd; /* QoS Flogi rejects received */ + u32 flogi_rjt_recvd; /* QoS Flogi rejects received */ u32 flogi_retries; /* QoS Flogi retries */ u32 elp_recvd; /* QoS ELP received */ u32 elp_accepted; /* QoS ELP Accepted */ - u32 elp_rejected; /* QoS ELP rejected */ - u32 elp_dropped; /* QoS ELP dropped */ + u32 elp_rejected; /* QoS ELP rejected */ + u32 elp_dropped; /* QoS ELP dropped */ - u32 qos_rscn_recvd; /* QoS RSCN received */ - u32 rsvd; /* padding for 64 bit alignment */ + u32 qos_rscn_recvd; /* QoS RSCN received */ + u32 rsvd; /* padding for 64 bit alignment */ }; /* @@ -548,9 +549,9 @@ struct bfa_qos_stats_s { */ struct bfa_fcoe_stats_s { u64 secs_reset; /* Seconds since stats reset */ - u64 cee_linkups; /* CEE link up */ + u64 cee_linkups; /* CEE link up */ u64 cee_linkdns; /* CEE link down */ - u64 fip_linkups; /* FIP link up */ + u64 fip_linkups; /* FIP link up */ u64 fip_linkdns; /* FIP link down */ u64 fip_fails; /* FIP failures */ u64 mac_invalids; /* Invalid mac assignments */ @@ -560,38 +561,38 @@ struct bfa_fcoe_stats_s { u64 vlan_timeouts; /* Vlan request timeouts */ u64 vlan_invalids; /* Vlan invalids */ u64 disc_req; /* Discovery requests */ - u64 disc_rsp; /* Discovery responses */ + u64 disc_rsp; /* Discovery responses */ u64 disc_err; /* Discovery error frames */ u64 disc_unsol; /* Discovery unsolicited */ u64 disc_timeouts; /* Discovery timeouts */ u64 disc_fcf_unavail; /* Discovery FCF not avail */ - u64 linksvc_unsupp; /* FIP link service req unsupp. */ - u64 linksvc_err; /* FIP link service req errors */ + u64 linksvc_unsupp; /* FIP link service req unsupp */ + u64 linksvc_err; /* FIP link service req errors */ u64 logo_req; /* FIP logos received */ - u64 clrvlink_req; /* Clear virtual link requests */ + u64 clrvlink_req; /* Clear virtual link requests */ u64 op_unsupp; /* FIP operation unsupp. */ - u64 untagged; /* FIP untagged frames */ + u64 untagged; /* FIP untagged frames */ u64 txf_ucast; /* Tx FCoE unicast frames */ - u64 txf_ucast_vlan; /* Tx FCoE unicast vlan frames */ + u64 txf_ucast_vlan; /* Tx FCoE unicast vlan frames */ u64 txf_ucast_octets; /* Tx FCoE unicast octets */ u64 txf_mcast; /* Tx FCoE multicast frames */ - u64 txf_mcast_vlan; /* Tx FCoE multicast vlan frames */ + u64 txf_mcast_vlan; /* Tx FCoE multicast vlan frames */ u64 txf_mcast_octets; /* Tx FCoE multicast octets */ u64 txf_bcast; /* Tx FCoE broadcast frames */ - u64 txf_bcast_vlan; /* Tx FCoE broadcast vlan frames */ + u64 txf_bcast_vlan; /* Tx FCoE broadcast vlan frames */ u64 txf_bcast_octets; /* Tx FCoE broadcast octets */ - u64 txf_timeout; /* Tx timeouts */ + u64 txf_timeout; /* Tx timeouts */ u64 txf_parity_errors; /* Transmit parity err */ - u64 txf_fid_parity_errors; /* Transmit FID parity err */ + u64 txf_fid_parity_errors; /* Transmit FID parity err */ u64 rxf_ucast_octets; /* Rx FCoE unicast octets */ u64 rxf_ucast; /* Rx FCoE unicast frames */ - u64 rxf_ucast_vlan; /* Rx FCoE unicast vlan frames */ + u64 rxf_ucast_vlan; /* Rx FCoE unicast vlan frames */ u64 rxf_mcast_octets; /* Rx FCoE multicast octets */ u64 rxf_mcast; /* Rx FCoE multicast frames */ - u64 rxf_mcast_vlan; /* Rx FCoE multicast vlan frames */ + u64 rxf_mcast_vlan; /* Rx FCoE multicast vlan frames */ u64 rxf_bcast_octets; /* Rx FCoE broadcast octets */ u64 rxf_bcast; /* Rx FCoE broadcast frames */ - u64 rxf_bcast_vlan; /* Rx FCoE broadcast vlan frames */ + u64 rxf_bcast_vlan; /* Rx FCoE broadcast vlan frames */ }; /* @@ -672,12 +673,7 @@ struct bfa_itnim_iostats_s { u32 tm_iocdowns; /* TM cleaned-up due to IOC down */ u32 tm_cleanups; /* TM cleanup requests */ u32 tm_cleanup_comps; /* TM cleanup completions */ - u32 lm_lun_across_sg; /* LM lun is across sg data buf */ - u32 lm_lun_not_sup; /* LM lun not supported */ - u32 lm_rpl_data_changed; /* LM report-lun data changed */ - u32 lm_wire_residue_changed; /* LM report-lun rsp residue changed */ - u32 lm_small_buf_addresidue; /* LM buf smaller than reported cnt */ - u32 lm_lun_not_rdy; /* LM lun not ready */ + u32 rsvd[6]; }; /* Modify char* port_stt[] in bfal_port.c if a new state was added */ @@ -852,12 +848,12 @@ struct bfa_port_cfg_s { u8 tx_bbcredit; /* transmit buffer credits */ u8 ratelimit; /* ratelimit enabled or not */ u8 trl_def_speed; /* ratelimit default speed */ - u8 bb_scn; /* BB_SCN value from FLOGI Exchg */ - u8 bb_scn_state; /* Config state of BB_SCN */ - u8 faa_state; /* FAA enabled/disabled */ - u8 rsvd[1]; - u16 path_tov; /* device path timeout */ - u16 q_depth; /* SCSI Queue depth */ + u8 bb_scn; /* BB_SCN value from FLOGI Exchg */ + u8 bb_scn_state; /* Config state of BB_SCN */ + u8 faa_state; /* FAA enabled/disabled */ + u8 rsvd[1]; + u16 path_tov; /* device path timeout */ + u16 q_depth; /* SCSI Queue depth */ }; #pragma pack() @@ -868,20 +864,21 @@ struct bfa_port_attr_s { /* * Static fields */ - wwn_t nwwn; /* node wwn */ - wwn_t pwwn; /* port wwn */ - wwn_t factorynwwn; /* factory node wwn */ - wwn_t factorypwwn; /* factory port wwn */ - enum fc_cos cos_supported; /* supported class of services */ - u32 rsvd; + wwn_t nwwn; /* node wwn */ + wwn_t pwwn; /* port wwn */ + wwn_t factorynwwn; /* factory node wwn */ + wwn_t factorypwwn; /* factory port wwn */ + enum fc_cos cos_supported; /* supported class of + * services */ + u32 rsvd; struct fc_symname_s port_symname; /* port symbolic name */ - enum bfa_port_speed speed_supported; /* supported speeds */ - bfa_boolean_t pbind_enabled; + enum bfa_port_speed speed_supported; /* supported speeds */ + bfa_boolean_t pbind_enabled; /* * Configured values */ - struct bfa_port_cfg_s pport_cfg; /* pport cfg */ + struct bfa_port_cfg_s pport_cfg; /* pport cfg */ /* * Dynamic field - info from BFA @@ -890,19 +887,20 @@ struct bfa_port_attr_s { enum bfa_port_speed speed; /* current speed */ enum bfa_port_topology topology; /* current topology */ bfa_boolean_t beacon; /* current beacon status */ - bfa_boolean_t link_e2e_beacon; /* link beacon is on */ - bfa_boolean_t bbsc_op_status; /* fc credit recovery oper state */ + bfa_boolean_t link_e2e_beacon; /* link beacon is on */ + bfa_boolean_t bbsc_op_status; /* fc credit recovery oper + * state */ /* * Dynamic field - info from FCS */ - u32 pid; /* port ID */ + u32 pid; /* port ID */ enum bfa_port_type port_type; /* current topology */ - u32 loopback; /* external loopback */ - u32 authfail; /* auth fail state */ + u32 loopback; /* external loopback */ + u32 authfail; /* auth fail state */ /* FCoE specific */ - u16 fcoe_vlan; + u16 fcoe_vlan; u8 rsvd1[2]; }; @@ -910,48 +908,48 @@ struct bfa_port_attr_s { * Port FCP mappings. */ struct bfa_port_fcpmap_s { - char osdevname[256]; + char osdevname[256]; u32 bus; u32 target; u32 oslun; u32 fcid; - wwn_t nwwn; - wwn_t pwwn; + wwn_t nwwn; + wwn_t pwwn; u64 fcplun; - char luid[256]; + char luid[256]; }; /* * Port RNID info. */ struct bfa_port_rnid_s { - wwn_t wwn; + wwn_t wwn; u32 unittype; u32 portid; u32 attached_nodes_num; u16 ip_version; u16 udp_port; - u8 ipaddr[16]; + u8 ipaddr[16]; u16 rsvd; u16 topologydiscoveryflags; }; #pragma pack(1) struct bfa_fcport_fcf_s { - wwn_t name; /* FCF name */ - wwn_t fabric_name; /* Fabric Name */ - u8 fipenabled; /* FIP enabled or not */ - u8 fipfailed; /* FIP failed or not */ - u8 resv[2]; - u8 pri; /* FCF priority */ - u8 version; /* FIP version used */ - u8 available; /* Available for login */ - u8 fka_disabled; /* FKA is disabled */ - u8 maxsz_verified; /* FCoE max size verified */ - u8 fc_map[3]; /* FC map */ - __be16 vlan; /* FCoE vlan tag/priority */ - u32 fka_adv_per; /* FIP ka advert. period */ - mac_t mac; /* FCF mac */ + wwn_t name; /* FCF name */ + wwn_t fabric_name; /* Fabric Name */ + u8 fipenabled; /* FIP enabled or not */ + u8 fipfailed; /* FIP failed or not */ + u8 resv[2]; + u8 pri; /* FCF priority */ + u8 version; /* FIP version used */ + u8 available; /* Available for login */ + u8 fka_disabled; /* FKA is disabled */ + u8 maxsz_verified; /* FCoE max size verified */ + u8 fc_map[3]; /* FC map */ + __be16 vlan; /* FCoE vlan tag/priority */ + u32 fka_adv_per; /* FIP ka advert. period */ + mac_t mac; /* FCF mac */ }; /* @@ -981,7 +979,7 @@ struct bfa_port_link_s { u8 linkstate_rsn; /* bfa_port_linkstate_rsn_t */ u8 topology; /* P2P/LOOP bfa_port_topology */ u8 speed; /* Link speed (1/2/4/8 G) */ - u32 linkstate_opt; /* Linkstate optional data (debug) */ + u32 linkstate_opt; /* Linkstate optional data (debug) */ u8 trunked; /* Trunked or not (1 or 0) */ u8 resvd[3]; struct bfa_qos_attr_s qos_attr; /* QoS Attributes */ @@ -1035,7 +1033,7 @@ struct bfa_rport_hal_stats_s { u32 sm_fwc_del; /* fw create: delete events */ u32 sm_fwc_off; /* fw create: offline events */ u32 sm_fwc_hwf; /* fw create: IOC down */ - u32 sm_fwc_unexp; /* fw create: exception events*/ + u32 sm_fwc_unexp; /* fw create: exception events*/ u32 sm_on_off; /* online: offline events */ u32 sm_on_del; /* online: delete events */ u32 sm_on_hwf; /* online: IOC down events */ @@ -1043,25 +1041,25 @@ struct bfa_rport_hal_stats_s { u32 sm_fwd_rsp; /* fw delete: fw responses */ u32 sm_fwd_del; /* fw delete: delete events */ u32 sm_fwd_hwf; /* fw delete: IOC down events */ - u32 sm_fwd_unexp; /* fw delete: exception events*/ + u32 sm_fwd_unexp; /* fw delete: exception events*/ u32 sm_off_del; /* offline: delete events */ u32 sm_off_on; /* offline: online events */ u32 sm_off_hwf; /* offline: IOC down events */ - u32 sm_off_unexp; /* offline: exception events */ - u32 sm_del_fwrsp; /* delete: fw responses */ + u32 sm_off_unexp; /* offline: exception events */ + u32 sm_del_fwrsp; /* delete: fw responses */ u32 sm_del_hwf; /* delete: IOC down events */ - u32 sm_del_unexp; /* delete: exception events */ - u32 sm_delp_fwrsp; /* delete pend: fw responses */ + u32 sm_del_unexp; /* delete: exception events */ + u32 sm_delp_fwrsp; /* delete pend: fw responses */ u32 sm_delp_hwf; /* delete pend: IOC downs */ - u32 sm_delp_unexp; /* delete pend: exceptions */ - u32 sm_offp_fwrsp; /* off-pending: fw responses */ + u32 sm_delp_unexp; /* delete pend: exceptions */ + u32 sm_offp_fwrsp; /* off-pending: fw responses */ u32 sm_offp_del; /* off-pending: deletes */ u32 sm_offp_hwf; /* off-pending: IOC downs */ - u32 sm_offp_unexp; /* off-pending: exceptions */ + u32 sm_offp_unexp; /* off-pending: exceptions */ u32 sm_iocd_off; /* IOC down: offline events */ u32 sm_iocd_del; /* IOC down: delete events */ u32 sm_iocd_on; /* IOC down: online events */ - u32 sm_iocd_unexp; /* IOC down: exceptions */ + u32 sm_iocd_unexp; /* IOC down: exceptions */ u32 rsvd; }; #pragma pack(1) @@ -1069,9 +1067,9 @@ struct bfa_rport_hal_stats_s { * Rport's QoS attributes */ struct bfa_rport_qos_attr_s { - u8 qos_priority; /* rport's QoS priority */ - u8 rsvd[3]; - u32 qos_flow_id; /* QoS flow Id */ + u8 qos_priority; /* rport's QoS priority */ + u8 rsvd[3]; + u32 qos_flow_id; /* QoS flow Id */ }; #pragma pack() diff --git a/drivers/scsi/bfa/bfa_fc.h b/drivers/scsi/bfa/bfa_fc.h index 50b6a1c8619..8d0b88f67a3 100644 --- a/drivers/scsi/bfa/bfa_fc.h +++ b/drivers/scsi/bfa/bfa_fc.h @@ -56,161 +56,6 @@ struct scsi_cdb_s { #define SCSI_MAX_ALLOC_LEN 0xFF /* maximum allocarion length */ -#define SCSI_SENSE_CUR_ERR 0x70 -#define SCSI_SENSE_DEF_ERR 0x71 - -/* - * SCSI additional sense codes - */ -#define SCSI_ASC_LUN_NOT_READY 0x04 -#define SCSI_ASC_LUN_NOT_SUPPORTED 0x25 -#define SCSI_ASC_TOCC 0x3F - -/* - * SCSI additional sense code qualifiers - */ -#define SCSI_ASCQ_MAN_INTR_REQ 0x03 /* manual intervention req */ -#define SCSI_ASCQ_RL_DATA_CHANGED 0x0E /* report luns data changed */ - -/* - * Methods of reporting informational exceptions - */ -#define SCSI_MP_IEC_UNIT_ATTN 0x2 /* generate unit attention */ - -struct scsi_report_luns_data_s { - u32 lun_list_length; /* length of LUN list length */ - u32 reserved; - struct scsi_lun lun[1]; /* first LUN in lun list */ -}; - -struct scsi_inquiry_vendor_s { - u8 vendor_id[8]; -}; - -struct scsi_inquiry_prodid_s { - u8 product_id[16]; -}; - -struct scsi_inquiry_prodrev_s { - u8 product_rev[4]; -}; - -struct scsi_inquiry_data_s { -#ifdef __BIG_ENDIAN - u8 peripheral_qual:3; /* peripheral qualifier */ - u8 device_type:5; /* peripheral device type */ - u8 rmb:1; /* removable medium bit */ - u8 device_type_mod:7; /* device type modifier */ - u8 version; - u8 aenc:1; /* async evt notification capability */ - u8 trm_iop:1; /* terminate I/O process */ - u8 norm_aca:1; /* normal ACA supported */ - u8 hi_support:1; /* SCSI-3: supports REPORT LUNS */ - u8 rsp_data_format:4; - u8 additional_len; - u8 sccs:1; - u8 reserved1:7; - u8 reserved2:1; - u8 enc_serv:1; /* enclosure service component */ - u8 reserved3:1; - u8 multi_port:1; /* multi-port device */ - u8 m_chngr:1; /* device in medium transport element */ - u8 ack_req_q:1; /* SIP specific bit */ - u8 addr32:1; /* SIP specific bit */ - u8 addr16:1; /* SIP specific bit */ - u8 rel_adr:1; /* relative address */ - u8 w_bus32:1; - u8 w_bus16:1; - u8 synchronous:1; - u8 linked_commands:1; - u8 trans_dis:1; - u8 cmd_queue:1; /* command queueing supported */ - u8 soft_reset:1; /* soft reset alternative (VS) */ -#else - u8 device_type:5; /* peripheral device type */ - u8 peripheral_qual:3; /* peripheral qualifier */ - u8 device_type_mod:7; /* device type modifier */ - u8 rmb:1; /* removable medium bit */ - u8 version; - u8 rsp_data_format:4; - u8 hi_support:1; /* SCSI-3: supports REPORT LUNS */ - u8 norm_aca:1; /* normal ACA supported */ - u8 terminate_iop:1;/* terminate I/O process */ - u8 aenc:1; /* async evt notification capability */ - u8 additional_len; - u8 reserved1:7; - u8 sccs:1; - u8 addr16:1; /* SIP specific bit */ - u8 addr32:1; /* SIP specific bit */ - u8 ack_req_q:1; /* SIP specific bit */ - u8 m_chngr:1; /* device in medium transport element */ - u8 multi_port:1; /* multi-port device */ - u8 reserved3:1; /* TBD - Vendor Specific */ - u8 enc_serv:1; /* enclosure service component */ - u8 reserved2:1; - u8 soft_seset:1; /* soft reset alternative (VS) */ - u8 cmd_queue:1; /* command queueing supported */ - u8 trans_dis:1; - u8 linked_commands:1; - u8 synchronous:1; - u8 w_bus16:1; - u8 w_bus32:1; - u8 rel_adr:1; /* relative address */ -#endif - struct scsi_inquiry_vendor_s vendor_id; - struct scsi_inquiry_prodid_s product_id; - struct scsi_inquiry_prodrev_s product_rev; - u8 vendor_specific[20]; - u8 reserved4[40]; -}; - -/* - * SCSI sense data format - */ -struct scsi_sense_s { -#ifdef __BIG_ENDIAN - u8 valid:1; - u8 rsp_code:7; -#else - u8 rsp_code:7; - u8 valid:1; -#endif - u8 seg_num; -#ifdef __BIG_ENDIAN - u8 file_mark:1; - u8 eom:1; /* end of media */ - u8 ili:1; /* incorrect length indicator */ - u8 reserved:1; - u8 sense_key:4; -#else - u8 sense_key:4; - u8 reserved:1; - u8 ili:1; /* incorrect length indicator */ - u8 eom:1; /* end of media */ - u8 file_mark:1; -#endif - u8 information[4]; /* device-type or cmd specific info */ - u8 add_sense_length; /* additional sense length */ - u8 command_info[4];/* command specific information */ - u8 asc; /* additional sense code */ - u8 ascq; /* additional sense code qualifier */ - u8 fru_code; /* field replaceable unit code */ -#ifdef __BIG_ENDIAN - u8 sksv:1; /* sense key specific valid */ - u8 c_d:1; /* command/data bit */ - u8 res1:2; - u8 bpv:1; /* bit pointer valid */ - u8 bpointer:3; /* bit pointer */ -#else - u8 bpointer:3; /* bit pointer */ - u8 bpv:1; /* bit pointer valid */ - u8 res1:2; - u8 c_d:1; /* command/data bit */ - u8 sksv:1; /* sense key specific valid */ -#endif - u8 fpointer[2]; /* field pointer */ -}; - /* * Fibre Channel Header Structure (FCHS) definition */ diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c index e07bd4745d8..f0f80e282e3 100644 --- a/drivers/scsi/bfa/bfa_fcpim.c +++ b/drivers/scsi/bfa/bfa_fcpim.c @@ -24,8 +24,6 @@ BFA_TRC_FILE(HAL, FCPIM); * BFA ITNIM Related definitions */ static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim); -static bfa_boolean_t bfa_ioim_lm_proc_rpl_data(struct bfa_ioim_s *ioim); -static bfa_boolean_t bfa_ioim_lm_proc_inq_data(struct bfa_ioim_s *ioim); static void bfa_ioim_lm_init(struct bfa_s *bfa); #define BFA_ITNIM_FROM_TAG(_fcpim, _tag) \ @@ -60,14 +58,6 @@ static void bfa_ioim_lm_init(struct bfa_s *bfa); } \ } while (0) -#define bfa_ioim_rp_wwn(__ioim) \ - (((struct bfa_fcs_rport_s *) \ - (__ioim)->itnim->rport->rport_drv)->pwwn) - -#define bfa_ioim_lp_wwn(__ioim) \ - ((BFA_LPS_FROM_TAG(BFA_LPS_MOD((__ioim)->bfa), \ - (__ioim)->itnim->rport->rport_info.lp_tag))->pwwn) \ - #define bfa_itnim_sler_cb(__itnim) do { \ if ((__itnim)->bfa->fcs) \ bfa_cb_itnim_sler((__itnim)->ditn); \ @@ -77,13 +67,6 @@ static void bfa_ioim_lm_init(struct bfa_s *bfa); } \ } while (0) -enum bfa_ioim_lm_status { - BFA_IOIM_LM_PRESENT = 1, - BFA_IOIM_LM_LUN_NOT_SUP = 2, - BFA_IOIM_LM_RPL_DATA_CHANGED = 3, - BFA_IOIM_LM_LUN_NOT_RDY = 4, -}; - enum bfa_ioim_lm_ua_status { BFA_IOIM_LM_UA_RESET = 0, BFA_IOIM_LM_UA_SET = 1, @@ -145,9 +128,6 @@ enum bfa_ioim_event { BFA_IOIM_SM_TMDONE = 16, /* IO cleanup from tskim */ BFA_IOIM_SM_HWFAIL = 17, /* IOC h/w failure event */ BFA_IOIM_SM_IOTOV = 18, /* ITN offline TOV */ - BFA_IOIM_SM_LM_LUN_NOT_SUP = 19,/* lunmask lun not supported */ - BFA_IOIM_SM_LM_RPL_DC = 20, /* lunmask report-lun data changed */ - BFA_IOIM_SM_LM_LUN_NOT_RDY = 21,/* lunmask lun not ready */ }; @@ -245,9 +225,6 @@ static void __bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete); static void __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete); static void __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete); static bfa_boolean_t bfa_ioim_is_abortable(struct bfa_ioim_s *ioim); -static void __bfa_cb_ioim_lm_lun_not_sup(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_ioim_lm_rpl_dc(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_ioim_lm_lun_not_rdy(void *cbarg, bfa_boolean_t complete); /* * forward declaration of BFA IO state machine @@ -445,12 +422,6 @@ bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *lstats, bfa_fcpim_add_iostats(lstats, rstats, output_reqs); bfa_fcpim_add_iostats(lstats, rstats, rd_throughput); bfa_fcpim_add_iostats(lstats, rstats, wr_throughput); - bfa_fcpim_add_iostats(lstats, rstats, lm_lun_across_sg); - bfa_fcpim_add_iostats(lstats, rstats, lm_lun_not_sup); - bfa_fcpim_add_iostats(lstats, rstats, lm_rpl_data_changed); - bfa_fcpim_add_iostats(lstats, rstats, lm_wire_residue_changed); - bfa_fcpim_add_iostats(lstats, rstats, lm_small_buf_addresidue); - bfa_fcpim_add_iostats(lstats, rstats, lm_lun_not_rdy); } bfa_status_t @@ -1580,27 +1551,6 @@ bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) __bfa_cb_ioim_abort, ioim); break; - case BFA_IOIM_SM_LM_LUN_NOT_SUP: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, - __bfa_cb_ioim_lm_lun_not_sup, ioim); - break; - - case BFA_IOIM_SM_LM_RPL_DC: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, - __bfa_cb_ioim_lm_rpl_dc, ioim); - break; - - case BFA_IOIM_SM_LM_LUN_NOT_RDY: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, - __bfa_cb_ioim_lm_lun_not_rdy, ioim); - break; - default: bfa_sm_fault(ioim->bfa, event); } @@ -2160,243 +2110,6 @@ bfa_ioim_lm_init(struct bfa_s *bfa) } } -/* - * Validate LUN for LUN masking - */ -static enum bfa_ioim_lm_status -bfa_ioim_lm_check(struct bfa_ioim_s *ioim, struct bfa_lps_s *lps, - struct bfa_rport_s *rp, struct scsi_lun lun) -{ - u8 i; - struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(ioim->bfa); - struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio; - struct scsi_cdb_s *cdb = (struct scsi_cdb_s *)cmnd->cmnd; - - if ((cdb->scsi_cdb[0] == REPORT_LUNS) && - (scsilun_to_int((struct scsi_lun *)&lun) == 0)) { - ioim->proc_rsp_data = bfa_ioim_lm_proc_rpl_data; - return BFA_IOIM_LM_PRESENT; - } - - for (i = 0; i < MAX_LUN_MASK_CFG; i++) { - - if (lun_list[i].state != BFA_IOIM_LUN_MASK_ACTIVE) - continue; - - if ((scsilun_to_int((struct scsi_lun *)&lun_list[i].lun) == - scsilun_to_int((struct scsi_lun *)&lun)) - && (rp->rport_tag == lun_list[i].rp_tag) - && ((u8)ioim->itnim->rport->rport_info.lp_tag == - lun_list[i].lp_tag)) { - bfa_trc(ioim->bfa, lun_list[i].rp_tag); - bfa_trc(ioim->bfa, lun_list[i].lp_tag); - bfa_trc(ioim->bfa, scsilun_to_int( - (struct scsi_lun *)&lun_list[i].lun)); - - if ((lun_list[i].ua == BFA_IOIM_LM_UA_SET) && - ((cdb->scsi_cdb[0] != INQUIRY) || - (cdb->scsi_cdb[0] != REPORT_LUNS))) { - lun_list[i].ua = BFA_IOIM_LM_UA_RESET; - return BFA_IOIM_LM_RPL_DATA_CHANGED; - } - - if (cdb->scsi_cdb[0] == REPORT_LUNS) - ioim->proc_rsp_data = bfa_ioim_lm_proc_rpl_data; - - return BFA_IOIM_LM_PRESENT; - } - } - - if ((cdb->scsi_cdb[0] == INQUIRY) && - (scsilun_to_int((struct scsi_lun *)&lun) == 0)) { - ioim->proc_rsp_data = bfa_ioim_lm_proc_inq_data; - return BFA_IOIM_LM_PRESENT; - } - - if (cdb->scsi_cdb[0] == TEST_UNIT_READY) - return BFA_IOIM_LM_LUN_NOT_RDY; - - return BFA_IOIM_LM_LUN_NOT_SUP; -} - -static bfa_boolean_t -bfa_ioim_lm_proc_rsp_data_dummy(struct bfa_ioim_s *ioim) -{ - return BFA_TRUE; -} - -static void -bfa_ioim_lm_fetch_lun(struct bfa_ioim_s *ioim, u8 *rl_data, int offset, - int buf_lun_cnt) -{ - struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(ioim->bfa); - struct scsi_lun *lun_data = (struct scsi_lun *)(rl_data + offset); - struct scsi_lun lun; - int i, j; - - bfa_trc(ioim->bfa, buf_lun_cnt); - for (j = 0; j < buf_lun_cnt; j++) { - lun = *((struct scsi_lun *)(lun_data + j)); - for (i = 0; i < MAX_LUN_MASK_CFG; i++) { - if (lun_list[i].state != BFA_IOIM_LUN_MASK_ACTIVE) - continue; - if ((lun_list[i].rp_wwn == bfa_ioim_rp_wwn(ioim)) && - (lun_list[i].lp_wwn == bfa_ioim_lp_wwn(ioim)) && - (scsilun_to_int((struct scsi_lun *)&lun_list[i].lun) - == scsilun_to_int((struct scsi_lun *)&lun))) { - lun_list[i].state = BFA_IOIM_LUN_MASK_FETCHED; - break; - } - } /* next lun in mask DB */ - } /* next lun in buf */ -} - -static int -bfa_ioim_lm_update_lun_sg(struct bfa_ioim_s *ioim, u32 *pgdlen, - struct scsi_report_luns_data_s *rl) -{ - struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio; - struct scatterlist *sg = scsi_sglist(cmnd); - struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(ioim->bfa); - struct scsi_lun *prev_rl_data = NULL, *base_rl_data; - int i, j, sgeid, lun_fetched_cnt = 0, prev_sg_len = 0, base_count; - int lun_across_sg_bytes, bytes_from_next_buf; - u64 last_lun, temp_last_lun; - - /* fetch luns from the first sg element */ - bfa_ioim_lm_fetch_lun(ioim, (u8 *)(rl->lun), 0, - (sg_dma_len(sg) / sizeof(struct scsi_lun)) - 1); - - /* fetch luns from multiple sg elements */ - scsi_for_each_sg(cmnd, sg, scsi_sg_count(cmnd), sgeid) { - if (sgeid == 0) { - prev_sg_len = sg_dma_len(sg); - prev_rl_data = (struct scsi_lun *) - phys_to_virt(sg_dma_address(sg)); - continue; - } - - /* if the buf is having more data */ - lun_across_sg_bytes = prev_sg_len % sizeof(struct scsi_lun); - if (lun_across_sg_bytes) { - bfa_trc(ioim->bfa, lun_across_sg_bytes); - bfa_stats(ioim->itnim, lm_lun_across_sg); - bytes_from_next_buf = sizeof(struct scsi_lun) - - lun_across_sg_bytes; - - /* from next buf take higher bytes */ - temp_last_lun = *((u64 *) - phys_to_virt(sg_dma_address(sg))); - last_lun |= temp_last_lun >> - (lun_across_sg_bytes * BITS_PER_BYTE); - - /* from prev buf take higher bytes */ - temp_last_lun = *((u64 *)(prev_rl_data + - (prev_sg_len - lun_across_sg_bytes))); - temp_last_lun >>= bytes_from_next_buf * BITS_PER_BYTE; - last_lun = last_lun | (temp_last_lun << - (bytes_from_next_buf * BITS_PER_BYTE)); - - bfa_ioim_lm_fetch_lun(ioim, (u8 *)&last_lun, 0, 1); - } else - bytes_from_next_buf = 0; - - *pgdlen += sg_dma_len(sg); - prev_sg_len = sg_dma_len(sg); - prev_rl_data = (struct scsi_lun *) - phys_to_virt(sg_dma_address(sg)); - bfa_ioim_lm_fetch_lun(ioim, (u8 *)prev_rl_data, - bytes_from_next_buf, - sg_dma_len(sg) / sizeof(struct scsi_lun)); - } - - /* update the report luns data - based on fetched luns */ - sg = scsi_sglist(cmnd); - base_rl_data = (struct scsi_lun *)rl->lun; - base_count = (sg_dma_len(sg) / sizeof(struct scsi_lun)) - 1; - for (i = 0, j = 0; i < MAX_LUN_MASK_CFG; i++) { - if (lun_list[i].state == BFA_IOIM_LUN_MASK_FETCHED) { - base_rl_data[j] = lun_list[i].lun; - lun_list[i].state = BFA_IOIM_LUN_MASK_ACTIVE; - j++; - lun_fetched_cnt++; - } - - if (j > base_count) { - j = 0; - sg = sg_next(sg); - base_rl_data = (struct scsi_lun *) - phys_to_virt(sg_dma_address(sg)); - base_count = sg_dma_len(sg) / sizeof(struct scsi_lun); - } - } - - bfa_trc(ioim->bfa, lun_fetched_cnt); - return lun_fetched_cnt; -} - -static bfa_boolean_t -bfa_ioim_lm_proc_inq_data(struct bfa_ioim_s *ioim) -{ - struct scsi_inquiry_data_s *inq; - struct scatterlist *sg = scsi_sglist((struct scsi_cmnd *)ioim->dio); - - ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy; - inq = (struct scsi_inquiry_data_s *)phys_to_virt(sg_dma_address(sg)); - - bfa_trc(ioim->bfa, inq->device_type); - inq->peripheral_qual = SCSI_INQ_PQ_NOT_CON; - return 0; -} - -static bfa_boolean_t -bfa_ioim_lm_proc_rpl_data(struct bfa_ioim_s *ioim) -{ - struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio; - struct scatterlist *sg = scsi_sglist(cmnd); - struct bfi_ioim_rsp_s *m; - struct scsi_report_luns_data_s *rl = NULL; - int lun_count = 0, lun_fetched_cnt = 0; - u32 residue, pgdlen = 0; - - ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy; - if (bfa_get_lun_mask_status(ioim->bfa) != BFA_LUNMASK_ENABLED) - return BFA_TRUE; - - m = (struct bfi_ioim_rsp_s *) &ioim->iosp->comp_rspmsg; - if (m->scsi_status == SCSI_STATUS_CHECK_CONDITION) - return BFA_TRUE; - - pgdlen = sg_dma_len(sg); - bfa_trc(ioim->bfa, pgdlen); - rl = (struct scsi_report_luns_data_s *)phys_to_virt(sg_dma_address(sg)); - lun_count = cpu_to_be32(rl->lun_list_length) / sizeof(struct scsi_lun); - lun_fetched_cnt = bfa_ioim_lm_update_lun_sg(ioim, &pgdlen, rl); - - if (lun_count == lun_fetched_cnt) - return BFA_TRUE; - - bfa_trc(ioim->bfa, lun_count); - bfa_trc(ioim->bfa, lun_fetched_cnt); - bfa_trc(ioim->bfa, be32_to_cpu(rl->lun_list_length)); - - if (be32_to_cpu(rl->lun_list_length) <= pgdlen) - rl->lun_list_length = be32_to_cpu(lun_fetched_cnt) * - sizeof(struct scsi_lun); - else - bfa_stats(ioim->itnim, lm_small_buf_addresidue); - - bfa_trc(ioim->bfa, be32_to_cpu(rl->lun_list_length)); - bfa_trc(ioim->bfa, be32_to_cpu(m->residue)); - - residue = be32_to_cpu(m->residue); - residue += (lun_count - lun_fetched_cnt) * sizeof(struct scsi_lun); - bfa_stats(ioim->itnim, lm_wire_residue_changed); - m->residue = be32_to_cpu(residue); - bfa_trc(ioim->bfa, ioim->nsges); - return BFA_FALSE; -} - static void __bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete) { @@ -2454,83 +2167,6 @@ __bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete) m->scsi_status, sns_len, snsinfo, residue); } -static void -__bfa_cb_ioim_lm_lun_not_sup(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_ioim_s *ioim = cbarg; - int sns_len = 0xD; - u32 residue = scsi_bufflen((struct scsi_cmnd *)ioim->dio); - struct scsi_sense_s *snsinfo; - - if (!complete) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); - return; - } - - snsinfo = (struct scsi_sense_s *)BFA_SNSINFO_FROM_TAG( - ioim->fcpim->fcp, ioim->iotag); - snsinfo->rsp_code = SCSI_SENSE_CUR_ERR; - snsinfo->add_sense_length = 0xa; - snsinfo->asc = SCSI_ASC_LUN_NOT_SUPPORTED; - snsinfo->sense_key = ILLEGAL_REQUEST; - bfa_trc(ioim->bfa, residue); - bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_OK, - SCSI_STATUS_CHECK_CONDITION, sns_len, - (u8 *)snsinfo, residue); -} - -static void -__bfa_cb_ioim_lm_rpl_dc(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_ioim_s *ioim = cbarg; - int sns_len = 0xD; - u32 residue = scsi_bufflen((struct scsi_cmnd *)ioim->dio); - struct scsi_sense_s *snsinfo; - - if (!complete) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); - return; - } - - snsinfo = (struct scsi_sense_s *)BFA_SNSINFO_FROM_TAG(ioim->fcpim->fcp, - ioim->iotag); - snsinfo->rsp_code = SCSI_SENSE_CUR_ERR; - snsinfo->sense_key = SCSI_MP_IEC_UNIT_ATTN; - snsinfo->asc = SCSI_ASC_TOCC; - snsinfo->add_sense_length = 0x6; - snsinfo->ascq = SCSI_ASCQ_RL_DATA_CHANGED; - bfa_trc(ioim->bfa, residue); - bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_OK, - SCSI_STATUS_CHECK_CONDITION, sns_len, - (u8 *)snsinfo, residue); -} - -static void -__bfa_cb_ioim_lm_lun_not_rdy(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_ioim_s *ioim = cbarg; - int sns_len = 0xD; - u32 residue = scsi_bufflen((struct scsi_cmnd *)ioim->dio); - struct scsi_sense_s *snsinfo; - - if (!complete) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); - return; - } - - snsinfo = (struct scsi_sense_s *)BFA_SNSINFO_FROM_TAG( - ioim->fcpim->fcp, ioim->iotag); - snsinfo->rsp_code = SCSI_SENSE_CUR_ERR; - snsinfo->add_sense_length = 0xa; - snsinfo->sense_key = NOT_READY; - snsinfo->asc = SCSI_ASC_LUN_NOT_READY; - snsinfo->ascq = SCSI_ASCQ_MAN_INTR_REQ; - bfa_trc(ioim->bfa, residue); - bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_OK, - SCSI_STATUS_CHECK_CONDITION, sns_len, - (u8 *)snsinfo, residue); -} - void bfa_fcpim_lunmask_rp_update(struct bfa_s *bfa, wwn_t lp_wwn, wwn_t rp_wwn, u16 rp_tag, u8 lp_tag) @@ -2647,7 +2283,8 @@ bfa_fcpim_lunmask_add(struct bfa_s *bfa, u16 vf_id, wwn_t *pwwn, if (port) { *pwwn = port->port_cfg.pwwn; rp_fcs = bfa_fcs_lport_get_rport_by_pwwn(port, rpwwn); - rp = rp_fcs->bfa_rport; + if (rp_fcs) + rp = rp_fcs->bfa_rport; } lunm_list = bfa_get_lun_mask_list(bfa); @@ -2715,7 +2352,8 @@ bfa_fcpim_lunmask_delete(struct bfa_s *bfa, u16 vf_id, wwn_t *pwwn, if (port) { *pwwn = port->port_cfg.pwwn; rp_fcs = bfa_fcs_lport_get_rport_by_pwwn(port, rpwwn); - rp = rp_fcs->bfa_rport; + if (rp_fcs) + rp = rp_fcs->bfa_rport; } } @@ -2757,7 +2395,6 @@ __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete) return; } - ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy; bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_ABORTED, 0, 0, NULL, 0); } @@ -2773,7 +2410,6 @@ __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete) return; } - ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy; bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_PATHTOV, 0, 0, NULL, 0); } @@ -2788,7 +2424,6 @@ __bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete) return; } - ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy; bfa_cb_ioim_abort(ioim->bfa->bfad, ioim->dio); } @@ -3132,7 +2767,6 @@ bfa_ioim_attach(struct bfa_fcpim_s *fcpim) ioim->bfa = fcpim->bfa; ioim->fcpim = fcpim; ioim->iosp = iosp; - ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy; INIT_LIST_HEAD(&ioim->sgpg_q); bfa_reqq_winit(&ioim->iosp->reqq_wait, bfa_ioim_qresume, ioim); @@ -3170,7 +2804,6 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) evt = BFA_IOIM_SM_DONE; else evt = BFA_IOIM_SM_COMP; - ioim->proc_rsp_data(ioim); break; case BFI_IOIM_STS_TIMEDOUT: @@ -3206,7 +2839,6 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) if (rsp->abort_tag != ioim->abort_tag) { bfa_trc(ioim->bfa, rsp->abort_tag); bfa_trc(ioim->bfa, ioim->abort_tag); - ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy; return; } @@ -3225,7 +2857,6 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) WARN_ON(1); } - ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy; bfa_sm_send_event(ioim, evt); } @@ -3244,15 +2875,7 @@ bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *m) bfa_ioim_cb_profile_comp(fcpim, ioim); - if (bfa_get_lun_mask_status(bfa) != BFA_LUNMASK_ENABLED) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD); - return; - } - - if (ioim->proc_rsp_data(ioim) == BFA_TRUE) - bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD); - else - bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP); + bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD); } /* @@ -3364,35 +2987,6 @@ bfa_ioim_free(struct bfa_ioim_s *ioim) void bfa_ioim_start(struct bfa_ioim_s *ioim) { - struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio; - struct bfa_lps_s *lps; - enum bfa_ioim_lm_status status; - struct scsi_lun scsilun; - - if (bfa_get_lun_mask_status(ioim->bfa) == BFA_LUNMASK_ENABLED) { - lps = BFA_IOIM_TO_LPS(ioim); - int_to_scsilun(cmnd->device->lun, &scsilun); - status = bfa_ioim_lm_check(ioim, lps, - ioim->itnim->rport, scsilun); - if (status == BFA_IOIM_LM_LUN_NOT_RDY) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_LM_LUN_NOT_RDY); - bfa_stats(ioim->itnim, lm_lun_not_rdy); - return; - } - - if (status == BFA_IOIM_LM_LUN_NOT_SUP) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_LM_LUN_NOT_SUP); - bfa_stats(ioim->itnim, lm_lun_not_sup); - return; - } - - if (status == BFA_IOIM_LM_RPL_DATA_CHANGED) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_LM_RPL_DC); - bfa_stats(ioim->itnim, lm_rpl_data_changed); - return; - } - } - bfa_ioim_cb_profile_start(ioim->fcpim, ioim); /* diff --git a/drivers/scsi/bfa/bfa_fcpim.h b/drivers/scsi/bfa/bfa_fcpim.h index 1080bcb81cb..36f26da80f7 100644 --- a/drivers/scsi/bfa/bfa_fcpim.h +++ b/drivers/scsi/bfa/bfa_fcpim.h @@ -110,7 +110,6 @@ struct bfad_ioim_s; struct bfad_tskim_s; typedef void (*bfa_fcpim_profile_t) (struct bfa_ioim_s *ioim); -typedef bfa_boolean_t (*bfa_ioim_lm_proc_rsp_data_t) (struct bfa_ioim_s *ioim); struct bfa_fcpim_s { struct bfa_s *bfa; @@ -124,7 +123,6 @@ struct bfa_fcpim_s { u32 path_tov; u16 q_depth; u8 reqq; /* Request queue to be used */ - u8 lun_masking_pending; struct list_head itnim_q; /* queue of active itnim */ struct list_head ioim_resfree_q; /* IOs waiting for f/w */ struct list_head ioim_comp_q; /* IO global comp Q */ @@ -181,7 +179,6 @@ struct bfa_ioim_s { u8 reqq; /* Request queue for I/O */ u8 mode; /* IO is passthrough or not */ u64 start_time; /* IO's Profile start val */ - bfa_ioim_lm_proc_rsp_data_t proc_rsp_data; /* RSP data adjust */ }; struct bfa_ioim_sp_s { @@ -261,10 +258,6 @@ struct bfa_itnim_s { (__ioim)->iotag |= k << BFA_IOIM_RETRY_TAG_OFFSET; \ } while (0) -#define BFA_IOIM_TO_LPS(__ioim) \ - BFA_LPS_FROM_TAG(BFA_LPS_MOD(__ioim->bfa), \ - __ioim->itnim->rport->rport_info.lp_tag) - static inline bfa_boolean_t bfa_ioim_maxretry_reached(struct bfa_ioim_s *ioim) { diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index 1ac5aecf25a..eca7ab78085 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c @@ -3727,11 +3727,11 @@ bfa_sfp_media_get(struct bfa_sfp_s *sfp) (xmtr_tech & SFP_XMTR_TECH_SA)) *media = BFA_SFP_MEDIA_SW; /* Check 10G Ethernet Compilance code */ - else if (e10g.b & 0x10) + else if (e10g.r.e10g_sr) *media = BFA_SFP_MEDIA_SW; - else if (e10g.b & 0x60) + else if (e10g.r.e10g_lrm && e10g.r.e10g_lr) *media = BFA_SFP_MEDIA_LW; - else if (e10g.r.e10g_unall & 0x80) + else if (e10g.r.e10g_unall) *media = BFA_SFP_MEDIA_UNKNOWN; else bfa_trc(sfp, 0); diff --git a/drivers/scsi/bfa/bfa_svc.h b/drivers/scsi/bfa/bfa_svc.h index 95adb86d376..b52cbb6bcd5 100644 --- a/drivers/scsi/bfa/bfa_svc.h +++ b/drivers/scsi/bfa/bfa_svc.h @@ -582,11 +582,6 @@ void bfa_cb_rport_qos_scn_prio(void *rport, #define BFA_LP_TAG_INVALID 0xff void bfa_rport_set_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp); void bfa_rport_unset_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp); -bfa_boolean_t bfa_rport_lunmask_active(struct bfa_rport_s *rp); -wwn_t bfa_rport_get_pwwn(struct bfa_s *bfa, struct bfa_rport_s *rp); -struct bfa_rport_s *bfa_rport_get_by_wwn(struct bfa_s *bfa, u16 vf_id, - wwn_t *lpwwn, wwn_t rpwwn); -void *bfa_cb_get_rp_by_wwn(void *arg, u16 vf_id, wwn_t *lpwwn, wwn_t rpwwn); /* * bfa fcxp API functions diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index 66fb72531b3..404fd10ddb2 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -674,6 +674,7 @@ bfad_vport_create(struct bfad_s *bfad, u16 vf_id, spin_lock_irqsave(&bfad->bfad_lock, flags); bfa_fcs_vport_start(&vport->fcs_vport); + list_add_tail(&vport->list_entry, &bfad->vport_list); spin_unlock_irqrestore(&bfad->bfad_lock, flags); return BFA_STATUS_OK; @@ -1404,6 +1405,7 @@ bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) bfad->ref_count = 0; bfad->pport.bfad = bfad; INIT_LIST_HEAD(&bfad->pbc_vport_list); + INIT_LIST_HEAD(&bfad->vport_list); /* Setup the debugfs node for this bfad */ if (bfa_debugfs_enable) diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c index 9d95844ab46..1938fe0473e 100644 --- a/drivers/scsi/bfa/bfad_attr.c +++ b/drivers/scsi/bfa/bfad_attr.c @@ -491,7 +491,7 @@ bfad_im_vport_delete(struct fc_vport *fc_vport) free_scsi_host: bfad_scsi_host_free(bfad, im_port); - + list_del(&vport->list_entry); kfree(vport); return 0; diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c index 06fc00caeb4..530de2b1200 100644 --- a/drivers/scsi/bfa/bfad_bsg.c +++ b/drivers/scsi/bfa/bfad_bsg.c @@ -2394,6 +2394,21 @@ out: return 0; } +/* Function to reset the LUN SCAN mode */ +static void +bfad_iocmd_lunmask_reset_lunscan_mode(struct bfad_s *bfad, int lunmask_cfg) +{ + struct bfad_im_port_s *pport_im = bfad->pport.im_port; + struct bfad_vport_s *vport = NULL; + + /* Set the scsi device LUN SCAN flags for base port */ + bfad_reset_sdev_bflags(pport_im, lunmask_cfg); + + /* Set the scsi device LUN SCAN flags for the vports */ + list_for_each_entry(vport, &bfad->vport_list, list_entry) + bfad_reset_sdev_bflags(vport->drv_port.im_port, lunmask_cfg); +} + int bfad_iocmd_lunmask(struct bfad_s *bfad, void *pcmd, unsigned int v_cmd) { @@ -2401,11 +2416,17 @@ bfad_iocmd_lunmask(struct bfad_s *bfad, void *pcmd, unsigned int v_cmd) unsigned long flags; spin_lock_irqsave(&bfad->bfad_lock, flags); - if (v_cmd == IOCMD_FCPIM_LUNMASK_ENABLE) + if (v_cmd == IOCMD_FCPIM_LUNMASK_ENABLE) { iocmd->status = bfa_fcpim_lunmask_update(&bfad->bfa, BFA_TRUE); - else if (v_cmd == IOCMD_FCPIM_LUNMASK_DISABLE) + /* Set the LUN Scanning mode to be Sequential scan */ + if (iocmd->status == BFA_STATUS_OK) + bfad_iocmd_lunmask_reset_lunscan_mode(bfad, BFA_TRUE); + } else if (v_cmd == IOCMD_FCPIM_LUNMASK_DISABLE) { iocmd->status = bfa_fcpim_lunmask_update(&bfad->bfa, BFA_FALSE); - else if (v_cmd == IOCMD_FCPIM_LUNMASK_CLEAR) + /* Set the LUN Scanning mode to default REPORT_LUNS scan */ + if (iocmd->status == BFA_STATUS_OK) + bfad_iocmd_lunmask_reset_lunscan_mode(bfad, BFA_FALSE); + } else if (v_cmd == IOCMD_FCPIM_LUNMASK_CLEAR) iocmd->status = bfa_fcpim_lunmask_clear(&bfad->bfa); spin_unlock_irqrestore(&bfad->bfad_lock, flags); return 0; diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c index dee1a094c2c..439c012be76 100644 --- a/drivers/scsi/bfa/bfad_debugfs.c +++ b/drivers/scsi/bfa/bfad_debugfs.c @@ -472,7 +472,7 @@ static const struct file_operations bfad_debugfs_op_regwr = { struct bfad_debugfs_entry { const char *name; - mode_t mode; + umode_t mode; const struct file_operations *fops; }; @@ -557,8 +557,7 @@ bfad_debugfs_exit(struct bfad_port_s *port) } } - /* - * Remove the pci_dev debugfs directory for the port */ + /* Remove the pci_dev debugfs directory for the port */ if (port->port_debugfs_root) { debugfs_remove(port->port_debugfs_root); port->port_debugfs_root = NULL; diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h index 5e19a5f820e..dc5b9d99c45 100644 --- a/drivers/scsi/bfa/bfad_drv.h +++ b/drivers/scsi/bfa/bfad_drv.h @@ -43,6 +43,7 @@ #include <scsi/scsi_transport_fc.h> #include <scsi/scsi_transport.h> #include <scsi/scsi_bsg_fc.h> +#include <scsi/scsi_devinfo.h> #include "bfa_modules.h" #include "bfa_fcs.h" @@ -227,6 +228,7 @@ struct bfad_s { struct list_head active_aen_q; struct bfa_aen_entry_s aen_list[BFA_AEN_MAX_ENTRY]; spinlock_t bfad_aen_spinlock; + struct list_head vport_list; }; /* BFAD state machine events */ diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index e5db649e8eb..3153923f5b6 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -918,16 +918,70 @@ bfad_get_itnim(struct bfad_im_port_s *im_port, int id) } /* + * Function is invoked from the SCSI Host Template slave_alloc() entry point. + * Has the logic to query the LUN Mask database to check if this LUN needs to + * be made visible to the SCSI mid-layer or not. + * + * Returns BFA_STATUS_OK if this LUN needs to be added to the OS stack. + * Returns -ENXIO to notify SCSI mid-layer to not add this LUN to the OS stack. + */ +static int +bfad_im_check_if_make_lun_visible(struct scsi_device *sdev, + struct fc_rport *rport) +{ + struct bfad_itnim_data_s *itnim_data = + (struct bfad_itnim_data_s *) rport->dd_data; + struct bfa_s *bfa = itnim_data->itnim->bfa_itnim->bfa; + struct bfa_rport_s *bfa_rport = itnim_data->itnim->bfa_itnim->rport; + struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(bfa); + int i = 0, ret = -ENXIO; + + for (i = 0; i < MAX_LUN_MASK_CFG; i++) { + if (lun_list[i].state == BFA_IOIM_LUN_MASK_ACTIVE && + scsilun_to_int(&lun_list[i].lun) == sdev->lun && + lun_list[i].rp_tag == bfa_rport->rport_tag && + lun_list[i].lp_tag == (u8)bfa_rport->rport_info.lp_tag) { + ret = BFA_STATUS_OK; + break; + } + } + return ret; +} + +/* * Scsi_Host template entry slave_alloc */ static int bfad_im_slave_alloc(struct scsi_device *sdev) { struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); + struct bfad_itnim_data_s *itnim_data = + (struct bfad_itnim_data_s *) rport->dd_data; + struct bfa_s *bfa = itnim_data->itnim->bfa_itnim->bfa; if (!rport || fc_remote_port_chkready(rport)) return -ENXIO; + if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_ENABLED) { + /* + * We should not mask LUN 0 - since this will translate + * to no LUN / TARGET for SCSI ml resulting no scan. + */ + if (sdev->lun == 0) { + sdev->sdev_bflags |= BLIST_NOREPORTLUN | + BLIST_SPARSELUN; + goto done; + } + + /* + * Query LUN Mask configuration - to expose this LUN + * to the SCSI mid-layer or to mask it. + */ + if (bfad_im_check_if_make_lun_visible(sdev, rport) != + BFA_STATUS_OK) + return -ENXIO; + } +done: sdev->hostdata = rport->dd_data; return 0; @@ -1037,6 +1091,8 @@ bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, struct bfad_itnim_s *itnim) && (fc_rport->scsi_target_id < MAX_FCP_TARGET)) itnim->scsi_tgt_id = fc_rport->scsi_target_id; + itnim->channel = fc_rport->channel; + return; } diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h index 004b6cf848d..0814367ef10 100644 --- a/drivers/scsi/bfa/bfad_im.h +++ b/drivers/scsi/bfa/bfad_im.h @@ -91,6 +91,7 @@ struct bfad_itnim_s { struct fc_rport *fc_rport; struct bfa_itnim_s *bfa_itnim; u16 scsi_tgt_id; + u16 channel; u16 queue_work; unsigned long last_ramp_up_time; unsigned long last_queue_full_time; @@ -166,4 +167,30 @@ irqreturn_t bfad_intx(int irq, void *dev_id); int bfad_im_bsg_request(struct fc_bsg_job *job); int bfad_im_bsg_timeout(struct fc_bsg_job *job); +/* + * Macro to set the SCSI device sdev_bflags - sdev_bflags are used by the + * SCSI mid-layer to choose LUN Scanning mode REPORT_LUNS vs. Sequential Scan + * + * Internally iterate's over all the ITNIM's part of the im_port & set's the + * sdev_bflags for the scsi_device associated with LUN #0. + */ +#define bfad_reset_sdev_bflags(__im_port, __lunmask_cfg) do { \ + struct scsi_device *__sdev = NULL; \ + struct bfad_itnim_s *__itnim = NULL; \ + u32 scan_flags = BLIST_NOREPORTLUN | BLIST_SPARSELUN; \ + list_for_each_entry(__itnim, &((__im_port)->itnim_mapped_list), \ + list_entry) { \ + __sdev = scsi_device_lookup((__im_port)->shost, \ + __itnim->channel, \ + __itnim->scsi_tgt_id, 0); \ + if (__sdev) { \ + if ((__lunmask_cfg) == BFA_TRUE) \ + __sdev->sdev_bflags |= scan_flags; \ + else \ + __sdev->sdev_bflags &= ~scan_flags; \ + scsi_device_put(__sdev); \ + } \ + } \ +} while (0) + #endif diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index dba72a4e6a1..1ad0b822556 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -1906,18 +1906,19 @@ static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session, spin_lock(&session->lock); task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data, cqe->itt & ISCSI_CMD_RESPONSE_INDEX); - if (!task) { + if (!task || !task->sc) { spin_unlock(&session->lock); return -EINVAL; } sc = task->sc; - spin_unlock(&session->lock); if (!blk_rq_cpu_valid(sc->request)) cpu = smp_processor_id(); else cpu = sc->request->cpu; + spin_unlock(&session->lock); + p = &per_cpu(bnx2i_percpu, cpu); spin_lock(&p->p_work_lock); if (unlikely(!p->iothread)) { diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index d1e69719097..1a44b45e7be 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -2177,7 +2177,7 @@ static int bnx2i_nl_set_path(struct Scsi_Host *shost, struct iscsi_path *params) return 0; } -static mode_t bnx2i_attr_is_visible(int param_type, int param) +static umode_t bnx2i_attr_is_visible(int param_type, int param) { switch (param_type) { case ISCSI_HOST_PARAM: diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c index 000294a9df8..36739da8bc1 100644 --- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c +++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c @@ -966,7 +966,7 @@ static int init_act_open(struct cxgbi_sock *csk) csk->saddr.sin_addr.s_addr = chba->ipv4addr; csk->rss_qid = 0; - csk->l2t = t3_l2t_get(t3dev, dst_get_neighbour(dst), ndev); + csk->l2t = t3_l2t_get(t3dev, dst, ndev); if (!csk->l2t) { pr_err("NO l2t available.\n"); return -EINVAL; diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index ac7a9b1e3e2..5a4a3bfc60c 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -1127,6 +1127,7 @@ static int init_act_open(struct cxgbi_sock *csk) struct net_device *ndev = cdev->ports[csk->port_id]; struct port_info *pi = netdev_priv(ndev); struct sk_buff *skb = NULL; + struct neighbour *n; unsigned int step; log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, @@ -1141,7 +1142,12 @@ static int init_act_open(struct cxgbi_sock *csk) cxgbi_sock_set_flag(csk, CTPF_HAS_ATID); cxgbi_sock_get(csk); - csk->l2t = cxgb4_l2t_get(lldi->l2t, dst_get_neighbour(csk->dst), ndev, 0); + n = dst_get_neighbour_noref(csk->dst); + if (!n) { + pr_err("%s, can't get neighbour of csk->dst.\n", ndev->name); + goto rel_resource; + } + csk->l2t = cxgb4_l2t_get(lldi->l2t, n, ndev, 0); if (!csk->l2t) { pr_err("%s, cannot alloc l2t.\n", ndev->name); goto rel_resource; diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index c10f74a566f..d3ff9cd4023 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -472,6 +472,7 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) struct net_device *ndev; struct cxgbi_device *cdev; struct rtable *rt = NULL; + struct neighbour *n; struct flowi4 fl4; struct cxgbi_sock *csk = NULL; unsigned int mtu = 0; @@ -493,7 +494,12 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) goto err_out; } dst = &rt->dst; - ndev = dst_get_neighbour(dst)->dev; + n = dst_get_neighbour_noref(dst); + if (!n) { + err = -ENODEV; + goto rel_rt; + } + ndev = n->dev; if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { pr_info("multi-cast route %pI4, port %u, dev %s.\n", @@ -507,7 +513,7 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) ndev = ip_dev_find(&init_net, daddr->sin_addr.s_addr); mtu = ndev->mtu; pr_info("rt dev %s, loopback -> %s, mtu %u.\n", - dst_get_neighbour(dst)->dev->name, ndev->name, mtu); + n->dev->name, ndev->name, mtu); } cdev = cxgbi_device_find_by_netdev(ndev, &port); @@ -1862,8 +1868,9 @@ int cxgbi_conn_alloc_pdu(struct iscsi_task *task, u8 opcode) tdata->skb = alloc_skb(cdev->skb_tx_rsvd + headroom, GFP_ATOMIC); if (!tdata->skb) { - pr_warn("alloc skb %u+%u, opcode 0x%x failed.\n", - cdev->skb_tx_rsvd, headroom, opcode); + struct cxgbi_sock *csk = cconn->cep->csk; + struct net_device *ndev = cdev->ports[csk->port_id]; + ndev->stats.tx_dropped++; return -ENOMEM; } @@ -2569,7 +2576,7 @@ void cxgbi_iscsi_cleanup(struct iscsi_transport *itp, } EXPORT_SYMBOL_GPL(cxgbi_iscsi_cleanup); -mode_t cxgbi_attr_is_visible(int param_type, int param) +umode_t cxgbi_attr_is_visible(int param_type, int param) { switch (param_type) { case ISCSI_HOST_PARAM: diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h index 20c88279c7a..80fa99b3d38 100644 --- a/drivers/scsi/cxgbi/libcxgbi.h +++ b/drivers/scsi/cxgbi/libcxgbi.h @@ -709,7 +709,7 @@ int cxgbi_conn_xmit_pdu(struct iscsi_task *); void cxgbi_cleanup_task(struct iscsi_task *task); -mode_t cxgbi_attr_is_visible(int param_type, int param); +umode_t cxgbi_attr_is_visible(int param_type, int param); void cxgbi_get_conn_stats(struct iscsi_cls_conn *, struct iscsi_stats *); int cxgbi_set_conn_param(struct iscsi_cls_conn *, enum iscsi_param, char *, int); diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index f5b718d3c31..13aeca3d51f 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -546,7 +546,7 @@ static struct ParameterData __devinitdata cfg_data[] = { * command line overrides will be used. If set to 1 then safe and * slow settings will be used. */ -static int use_safe_settings = 0; +static bool use_safe_settings = 0; module_param_named(safe, use_safe_settings, bool, 0); MODULE_PARM_DESC(safe, "Use safe and slow settings only. Default: false"); diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index 23149b9e297..48e46f5b77c 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c @@ -28,7 +28,6 @@ static DEFINE_SPINLOCK(list_lock); static LIST_HEAD(scsi_dh_list); -static int scsi_dh_list_idx = 1; static struct scsi_device_handler *get_device_handler(const char *name) { @@ -45,21 +44,6 @@ static struct scsi_device_handler *get_device_handler(const char *name) return found; } -static struct scsi_device_handler *get_device_handler_by_idx(int idx) -{ - struct scsi_device_handler *tmp, *found = NULL; - - spin_lock(&list_lock); - list_for_each_entry(tmp, &scsi_dh_list, list) { - if (tmp->idx == idx) { - found = tmp; - break; - } - } - spin_unlock(&list_lock); - return found; -} - /* * device_handler_match_function - Match a device handler to a device * @sdev - SCSI device to be tested @@ -84,23 +68,6 @@ device_handler_match_function(struct scsi_device *sdev) } /* - * device_handler_match_devlist - Match a device handler to a device - * @sdev - SCSI device to be tested - * - * Tests @sdev against all device_handler registered in the devlist. - * Returns the found device handler or NULL if not found. - */ -static struct scsi_device_handler * -device_handler_match_devlist(struct scsi_device *sdev) -{ - int idx; - - idx = scsi_get_device_flags_keyed(sdev, sdev->vendor, sdev->model, - SCSI_DEVINFO_DH); - return get_device_handler_by_idx(idx); -} - -/* * device_handler_match - Attach a device handler to a device * @scsi_dh - The device handler to match against or NULL * @sdev - SCSI device to be tested against @scsi_dh @@ -116,8 +83,6 @@ device_handler_match(struct scsi_device_handler *scsi_dh, struct scsi_device_handler *found_dh; found_dh = device_handler_match_function(sdev); - if (!found_dh) - found_dh = device_handler_match_devlist(sdev); if (scsi_dh && found_dh != scsi_dh) found_dh = NULL; @@ -361,25 +326,14 @@ static int scsi_dh_notifier_remove(struct device *dev, void *data) */ int scsi_register_device_handler(struct scsi_device_handler *scsi_dh) { - int i; if (get_device_handler(scsi_dh->name)) return -EBUSY; spin_lock(&list_lock); - scsi_dh->idx = scsi_dh_list_idx++; list_add(&scsi_dh->list, &scsi_dh_list); spin_unlock(&list_lock); - for (i = 0; scsi_dh->devlist && scsi_dh->devlist[i].vendor; i++) { - scsi_dev_info_list_add_keyed(0, - scsi_dh->devlist[i].vendor, - scsi_dh->devlist[i].model, - NULL, - scsi_dh->idx, - SCSI_DEVINFO_DH); - } - bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add); printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name); @@ -396,7 +350,6 @@ EXPORT_SYMBOL_GPL(scsi_register_device_handler); */ int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) { - int i; if (!get_device_handler(scsi_dh->name)) return -ENODEV; @@ -404,12 +357,6 @@ int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_remove); - for (i = 0; scsi_dh->devlist && scsi_dh->devlist[i].vendor; i++) { - scsi_dev_info_list_del_keyed(scsi_dh->devlist[i].vendor, - scsi_dh->devlist[i].model, - SCSI_DEVINFO_DH); - } - spin_lock(&list_lock); list_del(&scsi_dh->list); spin_unlock(&list_lock); @@ -588,10 +535,6 @@ static int __init scsi_dh_init(void) { int r; - r = scsi_dev_info_add_list(SCSI_DEVINFO_DH, "SCSI Device Handler"); - if (r) - return r; - r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb); if (!r) @@ -606,7 +549,6 @@ static void __exit scsi_dh_exit(void) bus_for_each_dev(&scsi_bus_type, NULL, NULL, scsi_dh_sysfs_attr_remove); bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb); - scsi_dev_info_remove_list(SCSI_DEVINFO_DH); } module_init(scsi_dh_init); diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 4ef021291a4..04c5cea47a2 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -466,6 +466,11 @@ static int alua_check_sense(struct scsi_device *sdev, * Power On, Reset, or Bus Device Reset, just retry. */ return ADD_TO_MLQUEUE; + if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x01) + /* + * Mode Parameters Changed + */ + return ADD_TO_MLQUEUE; if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) /* * ALUA state changed diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index 591186cf189..e1c8be06de9 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -629,6 +629,24 @@ static const struct scsi_dh_devlist clariion_dev_list[] = { {NULL, NULL}, }; +static bool clariion_match(struct scsi_device *sdev) +{ + int i; + + if (scsi_device_tpgs(sdev)) + return false; + + for (i = 0; clariion_dev_list[i].vendor; i++) { + if (!strncmp(sdev->vendor, clariion_dev_list[i].vendor, + strlen(clariion_dev_list[i].vendor)) && + !strncmp(sdev->model, clariion_dev_list[i].model, + strlen(clariion_dev_list[i].model))) { + return true; + } + } + return false; +} + static int clariion_bus_attach(struct scsi_device *sdev); static void clariion_bus_detach(struct scsi_device *sdev); @@ -642,6 +660,7 @@ static struct scsi_device_handler clariion_dh = { .activate = clariion_activate, .prep_fn = clariion_prep_fn, .set_params = clariion_set_params, + .match = clariion_match, }; static int clariion_bus_attach(struct scsi_device *sdev) diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c index 0f86a18b157..084062bb8ee 100644 --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c @@ -320,6 +320,24 @@ static const struct scsi_dh_devlist hp_sw_dh_data_list[] = { {NULL, NULL}, }; +static bool hp_sw_match(struct scsi_device *sdev) +{ + int i; + + if (scsi_device_tpgs(sdev)) + return false; + + for (i = 0; hp_sw_dh_data_list[i].vendor; i++) { + if (!strncmp(sdev->vendor, hp_sw_dh_data_list[i].vendor, + strlen(hp_sw_dh_data_list[i].vendor)) && + !strncmp(sdev->model, hp_sw_dh_data_list[i].model, + strlen(hp_sw_dh_data_list[i].model))) { + return true; + } + } + return false; +} + static int hp_sw_bus_attach(struct scsi_device *sdev); static void hp_sw_bus_detach(struct scsi_device *sdev); @@ -331,6 +349,7 @@ static struct scsi_device_handler hp_sw_dh = { .detach = hp_sw_bus_detach, .activate = hp_sw_activate, .prep_fn = hp_sw_prep_fn, + .match = hp_sw_match, }; static int hp_sw_bus_attach(struct scsi_device *sdev) diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 1d312792006..20c4557f5ab 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -364,10 +364,7 @@ static void release_controller(struct kref *kref) struct rdac_controller *ctlr; ctlr = container_of(kref, struct rdac_controller, kref); - flush_workqueue(kmpath_rdacd); - spin_lock(&list_lock); list_del(&ctlr->node); - spin_unlock(&list_lock); kfree(ctlr); } @@ -376,20 +373,17 @@ static struct rdac_controller *get_controller(int index, char *array_name, { struct rdac_controller *ctlr, *tmp; - spin_lock(&list_lock); - list_for_each_entry(tmp, &ctlr_list, node) { if ((memcmp(tmp->array_id, array_id, UNIQUE_ID_LEN) == 0) && (tmp->index == index) && (tmp->host == sdev->host)) { kref_get(&tmp->kref); - spin_unlock(&list_lock); return tmp; } } ctlr = kmalloc(sizeof(*ctlr), GFP_ATOMIC); if (!ctlr) - goto done; + return NULL; /* initialize fields of controller */ memcpy(ctlr->array_id, array_id, UNIQUE_ID_LEN); @@ -405,8 +399,7 @@ static struct rdac_controller *get_controller(int index, char *array_name, INIT_WORK(&ctlr->ms_work, send_mode_select); INIT_LIST_HEAD(&ctlr->ms_head); list_add(&ctlr->node, &ctlr_list); -done: - spin_unlock(&list_lock); + return ctlr; } @@ -517,9 +510,12 @@ static int initialize_controller(struct scsi_device *sdev, index = 0; else index = 1; + + spin_lock(&list_lock); h->ctlr = get_controller(index, array_name, array_id, sdev); if (!h->ctlr) err = SCSI_DH_RES_TEMP_UNAVAIL; + spin_unlock(&list_lock); } return err; } @@ -820,6 +816,24 @@ static const struct scsi_dh_devlist rdac_dev_list[] = { {NULL, NULL}, }; +static bool rdac_match(struct scsi_device *sdev) +{ + int i; + + if (scsi_device_tpgs(sdev)) + return false; + + for (i = 0; rdac_dev_list[i].vendor; i++) { + if (!strncmp(sdev->vendor, rdac_dev_list[i].vendor, + strlen(rdac_dev_list[i].vendor)) && + !strncmp(sdev->model, rdac_dev_list[i].model, + strlen(rdac_dev_list[i].model))) { + return true; + } + } + return false; +} + static int rdac_bus_attach(struct scsi_device *sdev); static void rdac_bus_detach(struct scsi_device *sdev); @@ -832,6 +846,7 @@ static struct scsi_device_handler rdac_dh = { .attach = rdac_bus_attach, .detach = rdac_bus_detach, .activate = rdac_activate, + .match = rdac_match, }; static int rdac_bus_attach(struct scsi_device *sdev) @@ -887,7 +902,9 @@ static int rdac_bus_attach(struct scsi_device *sdev) return 0; clean_ctlr: + spin_lock(&list_lock); kref_put(&h->ctlr->kref, release_controller); + spin_unlock(&list_lock); failed: kfree(scsi_dh_data); @@ -902,14 +919,19 @@ static void rdac_bus_detach( struct scsi_device *sdev ) struct rdac_dh_data *h; unsigned long flags; - spin_lock_irqsave(sdev->request_queue->queue_lock, flags); scsi_dh_data = sdev->scsi_dh_data; + h = (struct rdac_dh_data *) scsi_dh_data->buf; + if (h->ctlr && h->ctlr->ms_queued) + flush_workqueue(kmpath_rdacd); + + spin_lock_irqsave(sdev->request_queue->queue_lock, flags); sdev->scsi_dh_data = NULL; spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); - h = (struct rdac_dh_data *) scsi_dh_data->buf; + spin_lock(&list_lock); if (h->ctlr) kref_put(&h->ctlr->kref, release_controller); + spin_unlock(&list_lock); kfree(scsi_dh_data); module_put(THIS_MODULE); sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", RDAC_NAME); @@ -934,6 +956,8 @@ static int __init rdac_init(void) if (!kmpath_rdacd) { scsi_unregister_device_handler(&rdac_dh); printk(KERN_ERR "kmpath_rdacd creation failed.\n"); + + r = -EINVAL; } done: return r; diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index cefbe44bb84..e9599600aa2 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -31,6 +31,8 @@ #include <linux/sysfs.h> #include <linux/ctype.h> #include <linux/workqueue.h> +#include <net/dcbnl.h> +#include <net/dcbevent.h> #include <scsi/scsi_tcq.h> #include <scsi/scsicam.h> #include <scsi/scsi_transport.h> @@ -56,7 +58,11 @@ module_param_named(ddp_min, fcoe_ddp_min, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ddp_min, "Minimum I/O size in bytes for " \ "Direct Data Placement (DDP)."); -DEFINE_MUTEX(fcoe_config_mutex); +unsigned int fcoe_debug_logging; +module_param_named(debug_logging, fcoe_debug_logging, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels"); + +static DEFINE_MUTEX(fcoe_config_mutex); static struct workqueue_struct *fcoe_wq; @@ -65,8 +71,8 @@ static DECLARE_COMPLETION(fcoe_flush_completion); /* fcoe host list */ /* must only by accessed under the RTNL mutex */ -LIST_HEAD(fcoe_hostlist); -DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu); +static LIST_HEAD(fcoe_hostlist); +static DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu); /* Function Prototypes */ static int fcoe_reset(struct Scsi_Host *); @@ -101,6 +107,8 @@ static int fcoe_ddp_done(struct fc_lport *, u16); static int fcoe_ddp_target(struct fc_lport *, u16, struct scatterlist *, unsigned int); static int fcoe_cpu_callback(struct notifier_block *, unsigned long, void *); +static int fcoe_dcb_app_notification(struct notifier_block *notifier, + ulong event, void *ptr); static bool fcoe_match(struct net_device *netdev); static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode); @@ -129,6 +137,11 @@ static struct notifier_block fcoe_cpu_notifier = { .notifier_call = fcoe_cpu_callback, }; +/* notification function for DCB events */ +static struct notifier_block dcb_notifier = { + .notifier_call = fcoe_dcb_app_notification, +}; + static struct scsi_transport_template *fcoe_nport_scsi_transport; static struct scsi_transport_template *fcoe_vport_scsi_transport; @@ -148,7 +161,7 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = { .lport_set_port_id = fcoe_set_port_id, }; -struct fc_function_template fcoe_nport_fc_functions = { +static struct fc_function_template fcoe_nport_fc_functions = { .show_host_node_name = 1, .show_host_port_name = 1, .show_host_supported_classes = 1, @@ -188,7 +201,7 @@ struct fc_function_template fcoe_nport_fc_functions = { .bsg_request = fc_lport_bsg_request, }; -struct fc_function_template fcoe_vport_fc_functions = { +static struct fc_function_template fcoe_vport_fc_functions = { .show_host_node_name = 1, .show_host_port_name = 1, .show_host_supported_classes = 1, @@ -424,7 +437,7 @@ static inline void fcoe_interface_put(struct fcoe_interface *fcoe) * * Caller must be holding the RTNL mutex */ -void fcoe_interface_cleanup(struct fcoe_interface *fcoe) +static void fcoe_interface_cleanup(struct fcoe_interface *fcoe) { struct net_device *netdev = fcoe->netdev; struct fcoe_ctlr *fip = &fcoe->ctlr; @@ -739,7 +752,7 @@ static int fcoe_shost_config(struct fc_lport *lport, struct device *dev) * * Returns: True for read types I/O, otherwise returns false. */ -bool fcoe_oem_match(struct fc_frame *fp) +static bool fcoe_oem_match(struct fc_frame *fp) { struct fc_frame_header *fh = fc_frame_header_get(fp); struct fcp_cmnd *fcp; @@ -747,11 +760,12 @@ bool fcoe_oem_match(struct fc_frame *fp) if (fc_fcp_is_read(fr_fsp(fp)) && (fr_fsp(fp)->data_len > fcoe_ddp_min)) return true; - else if (!(ntoh24(fh->fh_f_ctl) & FC_FC_EX_CTX)) { + else if ((fr_fsp(fp) == NULL) && + (fh->fh_r_ctl == FC_RCTL_DD_UNSOL_CMD) && + (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN)) { fcp = fc_frame_payload_get(fp, sizeof(*fcp)); - if (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN && - fcp && (ntohl(fcp->fc_dl) > fcoe_ddp_min) && - (fcp->fc_flags & FCP_CFL_WRDATA)) + if ((fcp->fc_flags & FCP_CFL_WRDATA) && + (ntohl(fcp->fc_dl) > fcoe_ddp_min)) return true; } return false; @@ -1097,7 +1111,7 @@ static int __init fcoe_if_init(void) * * Returns: 0 on success */ -int __exit fcoe_if_exit(void) +static int __exit fcoe_if_exit(void) { fc_release_transport(fcoe_nport_scsi_transport); fc_release_transport(fcoe_vport_scsi_transport); @@ -1286,7 +1300,7 @@ static inline unsigned int fcoe_select_cpu(void) * * Returns: 0 for success */ -int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, +static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, struct packet_type *ptype, struct net_device *olddev) { struct fc_lport *lport; @@ -1442,7 +1456,7 @@ static int fcoe_alloc_paged_crc_eof(struct sk_buff *skb, int tlen) * * Return: 0 for success */ -int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) +static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) { int wlen; u32 crc; @@ -1522,6 +1536,8 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) skb_reset_network_header(skb); skb->mac_len = elen; skb->protocol = htons(ETH_P_FCOE); + skb->priority = port->priority; + if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN && fcoe->realdev->features & NETIF_F_HW_VLAN_TX) { skb->vlan_tci = VLAN_TAG_PRESENT | @@ -1624,6 +1640,7 @@ static inline int fcoe_filter_frames(struct fc_lport *lport, stats->InvalidCRCCount++; if (stats->InvalidCRCCount < 5) printk(KERN_WARNING "fcoe: dropping frame with CRC error\n"); + put_cpu(); return -EINVAL; } @@ -1659,8 +1676,7 @@ static void fcoe_recv_frame(struct sk_buff *skb) skb->dev ? skb->dev->name : "<NULL>"); port = lport_priv(lport); - if (skb_is_nonlinear(skb)) - skb_linearize(skb); /* not ideal */ + skb_linearize(skb); /* check for skb_is_nonlinear is within skb_linearize */ /* * Frame length checks and setting up the header pointers @@ -1716,7 +1732,7 @@ drop: * * Return: 0 for success */ -int fcoe_percpu_receive_thread(void *arg) +static int fcoe_percpu_receive_thread(void *arg) { struct fcoe_percpu_s *p = arg; struct sk_buff *skb; @@ -1746,6 +1762,7 @@ int fcoe_percpu_receive_thread(void *arg) */ static void fcoe_dev_setup(void) { + register_dcbevent_notifier(&dcb_notifier); register_netdevice_notifier(&fcoe_notifier); } @@ -1754,9 +1771,69 @@ static void fcoe_dev_setup(void) */ static void fcoe_dev_cleanup(void) { + unregister_dcbevent_notifier(&dcb_notifier); unregister_netdevice_notifier(&fcoe_notifier); } +static struct fcoe_interface * +fcoe_hostlist_lookup_realdev_port(struct net_device *netdev) +{ + struct fcoe_interface *fcoe; + struct net_device *real_dev; + + list_for_each_entry(fcoe, &fcoe_hostlist, list) { + if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN) + real_dev = vlan_dev_real_dev(fcoe->netdev); + else + real_dev = fcoe->netdev; + + if (netdev == real_dev) + return fcoe; + } + return NULL; +} + +static int fcoe_dcb_app_notification(struct notifier_block *notifier, + ulong event, void *ptr) +{ + struct dcb_app_type *entry = ptr; + struct fcoe_interface *fcoe; + struct net_device *netdev; + struct fcoe_port *port; + int prio; + + if (entry->app.selector != DCB_APP_IDTYPE_ETHTYPE) + return NOTIFY_OK; + + netdev = dev_get_by_index(&init_net, entry->ifindex); + if (!netdev) + return NOTIFY_OK; + + fcoe = fcoe_hostlist_lookup_realdev_port(netdev); + dev_put(netdev); + if (!fcoe) + return NOTIFY_OK; + + if (entry->dcbx & DCB_CAP_DCBX_VER_CEE) + prio = ffs(entry->app.priority) - 1; + else + prio = entry->app.priority; + + if (prio < 0) + return NOTIFY_OK; + + if (entry->app.protocol == ETH_P_FIP || + entry->app.protocol == ETH_P_FCOE) + fcoe->ctlr.priority = prio; + + if (entry->app.protocol == ETH_P_FCOE) { + port = lport_priv(fcoe->ctlr.lp); + port->priority = prio; + } + + return NOTIFY_OK; +} + /** * fcoe_device_notification() - Handler for net device events * @notifier: The context of the notification @@ -1965,6 +2042,46 @@ static bool fcoe_match(struct net_device *netdev) } /** + * fcoe_dcb_create() - Initialize DCB attributes and hooks + * @netdev: The net_device object of the L2 link that should be queried + * @port: The fcoe_port to bind FCoE APP priority with + * @ + */ +static void fcoe_dcb_create(struct fcoe_interface *fcoe) +{ +#ifdef CONFIG_DCB + int dcbx; + u8 fup, up; + struct net_device *netdev = fcoe->realdev; + struct fcoe_port *port = lport_priv(fcoe->ctlr.lp); + struct dcb_app app = { + .priority = 0, + .protocol = ETH_P_FCOE + }; + + /* setup DCB priority attributes. */ + if (netdev && netdev->dcbnl_ops && netdev->dcbnl_ops->getdcbx) { + dcbx = netdev->dcbnl_ops->getdcbx(netdev); + + if (dcbx & DCB_CAP_DCBX_VER_IEEE) { + app.selector = IEEE_8021QAZ_APP_SEL_ETHERTYPE; + up = dcb_ieee_getapp_mask(netdev, &app); + app.protocol = ETH_P_FIP; + fup = dcb_ieee_getapp_mask(netdev, &app); + } else { + app.selector = DCB_APP_IDTYPE_ETHTYPE; + up = dcb_getapp(netdev, &app); + app.protocol = ETH_P_FIP; + fup = dcb_getapp(netdev, &app); + } + + port->priority = ffs(up) ? ffs(up) - 1 : 0; + fcoe->ctlr.priority = ffs(fup) ? ffs(fup) - 1 : port->priority; + } +#endif +} + +/** * fcoe_create() - Create a fcoe interface * @netdev : The net_device object the Ethernet interface to create on * @fip_mode: The FIP mode for this creation @@ -2007,6 +2124,9 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) /* Make this the "master" N_Port */ fcoe->ctlr.lp = lport; + /* setup DCB priority attributes. */ + fcoe_dcb_create(fcoe); + /* add to lports list */ fcoe_hostlist_add(lport); @@ -2030,7 +2150,7 @@ out_nortnl: * Returns: 0 if the ethtool query was successful * -1 if the ethtool query failed */ -int fcoe_link_speed_update(struct fc_lport *lport) +static int fcoe_link_speed_update(struct fc_lport *lport) { struct net_device *netdev = fcoe_netdev(lport); struct ethtool_cmd ecmd; @@ -2064,7 +2184,7 @@ int fcoe_link_speed_update(struct fc_lport *lport) * Returns: 0 if link is UP and OK, -1 if not * */ -int fcoe_link_ok(struct fc_lport *lport) +static int fcoe_link_ok(struct fc_lport *lport) { struct net_device *netdev = fcoe_netdev(lport); @@ -2084,7 +2204,7 @@ int fcoe_link_ok(struct fc_lport *lport) * there no packets that will be handled by the lport, but also that any * threads already handling packet have returned. */ -void fcoe_percpu_clean(struct fc_lport *lport) +static void fcoe_percpu_clean(struct fc_lport *lport) { struct fcoe_percpu_s *pp; struct fcoe_rcv_info *fr; @@ -2135,7 +2255,7 @@ void fcoe_percpu_clean(struct fc_lport *lport) * * Returns: Always 0 (return value required by FC transport template) */ -int fcoe_reset(struct Scsi_Host *shost) +static int fcoe_reset(struct Scsi_Host *shost) { struct fc_lport *lport = shost_priv(shost); struct fcoe_port *port = lport_priv(lport); diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 6c6884bcf84..bcc89e63949 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -40,9 +40,7 @@ #define FCOE_MIN_XID 0x0000 /* the min xid supported by fcoe_sw */ #define FCOE_MAX_XID 0x0FFF /* the max xid supported by fcoe_sw */ -unsigned int fcoe_debug_logging; -module_param_named(debug_logging, fcoe_debug_logging, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels"); +extern unsigned int fcoe_debug_logging; #define FCOE_LOGGING 0x01 /* General logging, not categorized */ #define FCOE_NETDEV_LOGGING 0x02 /* Netdevice logging */ diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index c74c4b8e71e..e7522dcc296 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -320,6 +320,7 @@ static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf) skb_put(skb, sizeof(*sol)); skb->protocol = htons(ETH_P_FIP); + skb->priority = fip->priority; skb_reset_mac_header(skb); skb_reset_network_header(skb); fip->send(fip, skb); @@ -474,6 +475,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, } skb_put(skb, len); skb->protocol = htons(ETH_P_FIP); + skb->priority = fip->priority; skb_reset_mac_header(skb); skb_reset_network_header(skb); fip->send(fip, skb); @@ -566,6 +568,7 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport, cap->fip.fip_dl_len = htons(dlen / FIP_BPW); skb->protocol = htons(ETH_P_FIP); + skb->priority = fip->priority; skb_reset_mac_header(skb); skb_reset_network_header(skb); return 0; @@ -1911,6 +1914,7 @@ static void fcoe_ctlr_vn_send(struct fcoe_ctlr *fip, skb_put(skb, len); skb->protocol = htons(ETH_P_FIP); + skb->priority = fip->priority; skb_reset_mac_header(skb); skb_reset_network_header(skb); diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h index d969855ac64..d3e4d7c6f57 100644 --- a/drivers/scsi/gdth.h +++ b/drivers/scsi/gdth.h @@ -359,7 +359,7 @@ typedef struct { u32 cmd_buff_addr2; /* physical address of cmd buffer 1 */ u32 cmd_buff_u_addr2; /* reserved for 64 bit addressing */ u32 cmd_buff_indx2; /* cmd buf addr1 unique identifier */ - u32 cmd_buff_size; /* size of each cmd bufer in bytes */ + u32 cmd_buff_size; /* size of each cmd buffer in bytes */ u32 reserved1; u32 reserved2; } __attribute__((packed)) gdth_perf_modes; diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 865d452542b..b96962c3944 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -293,12 +293,14 @@ static u32 unresettable_controller[] = { 0x3215103C, /* Smart Array E200i */ 0x3237103C, /* Smart Array E500 */ 0x323D103C, /* Smart Array P700m */ + 0x40800E11, /* Smart Array 5i */ 0x409C0E11, /* Smart Array 6400 */ 0x409D0E11, /* Smart Array 6400 EM */ }; /* List of controllers which cannot even be soft reset */ static u32 soft_unresettable_controller[] = { + 0x40800E11, /* Smart Array 5i */ /* Exclude 640x boards. These are two pci devices in one slot * which share a battery backed cache module. One controls the * cache, the other accesses the cache through the one that controls @@ -4072,10 +4074,10 @@ static int hpsa_request_irq(struct ctlr_info *h, if (h->msix_vector || h->msi_vector) rc = request_irq(h->intr[h->intr_mode], msixhandler, - IRQF_DISABLED, h->devname, h); + 0, h->devname, h); else rc = request_irq(h->intr[h->intr_mode], intxhandler, - IRQF_DISABLED, h->devname, h); + IRQF_SHARED, h->devname, h); if (rc) { dev_err(&h->pdev->dev, "unable to get irq %d for %s\n", h->intr[h->intr_mode], h->devname); @@ -4269,7 +4271,9 @@ static void stop_controller_lockup_detector(struct ctlr_info *h) remove_ctlr_from_lockup_detector_list(h); /* If the list of ctlr's to monitor is empty, stop the thread */ if (list_empty(&hpsa_ctlr_list)) { + spin_unlock_irqrestore(&lockup_detector_lock, flags); kthread_stop(hpsa_lockup_detector); + spin_lock_irqsave(&lockup_detector_lock, flags); hpsa_lockup_detector = NULL; } spin_unlock_irqrestore(&lockup_detector_lock, flags); diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index fd860d952b2..b538f0883fd 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -4613,11 +4613,13 @@ static int __ipr_eh_host_reset(struct scsi_cmnd * scsi_cmd) ENTER; ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata; - dev_err(&ioa_cfg->pdev->dev, - "Adapter being reset as a result of error recovery.\n"); + if (!ioa_cfg->in_reset_reload) { + dev_err(&ioa_cfg->pdev->dev, + "Adapter being reset as a result of error recovery.\n"); - if (WAIT_FOR_DUMP == ioa_cfg->sdt_state) - ioa_cfg->sdt_state = GET_DUMP; + if (WAIT_FOR_DUMP == ioa_cfg->sdt_state) + ioa_cfg->sdt_state = GET_DUMP; + } rc = ipr_reset_reload(ioa_cfg, IPR_SHUTDOWN_ABBREV); @@ -4907,7 +4909,7 @@ static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd) struct ipr_ioa_cfg *ioa_cfg; struct ipr_resource_entry *res; struct ipr_cmd_pkt *cmd_pkt; - u32 ioasc; + u32 ioasc, int_reg; int op_found = 0; ENTER; @@ -4920,7 +4922,17 @@ static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd) */ if (ioa_cfg->in_reset_reload || ioa_cfg->ioa_is_dead) return FAILED; - if (!res || !ipr_is_gscsi(res)) + if (!res) + return FAILED; + + /* + * If we are aborting a timed out op, chances are that the timeout was caused + * by a still not detected EEH error. In such cases, reading a register will + * trigger the EEH recovery infrastructure. + */ + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg); + + if (!ipr_is_gscsi(res)) return FAILED; list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { @@ -7638,8 +7650,12 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) **/ static int ipr_reset_bist_done(struct ipr_cmnd *ipr_cmd) { + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + ENTER; - pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev); + if (ioa_cfg->cfg_locked) + pci_cfg_access_unlock(ioa_cfg->pdev); + ioa_cfg->cfg_locked = 0; ipr_cmd->job_step = ipr_reset_restore_cfg_space; LEAVE; return IPR_RC_JOB_CONTINUE; @@ -7660,8 +7676,6 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) int rc = PCIBIOS_SUCCESSFUL; ENTER; - pci_block_user_cfg_access(ioa_cfg->pdev); - if (ioa_cfg->ipr_chip->bist_method == IPR_MMIO) writel(IPR_UPROCI_SIS64_START_BIST, ioa_cfg->regs.set_uproc_interrupt_reg32); @@ -7673,7 +7687,9 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT); rc = IPR_RC_JOB_RETURN; } else { - pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev); + if (ioa_cfg->cfg_locked) + pci_cfg_access_unlock(ipr_cmd->ioa_cfg->pdev); + ioa_cfg->cfg_locked = 0; ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); rc = IPR_RC_JOB_CONTINUE; } @@ -7716,7 +7732,6 @@ static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd) struct pci_dev *pdev = ioa_cfg->pdev; ENTER; - pci_block_user_cfg_access(pdev); pci_set_pcie_reset_state(pdev, pcie_warm_reset); ipr_cmd->job_step = ipr_reset_slot_reset_done; ipr_reset_start_timer(ipr_cmd, IPR_PCI_RESET_TIMEOUT); @@ -7725,6 +7740,56 @@ static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd) } /** + * ipr_reset_block_config_access_wait - Wait for permission to block config access + * @ipr_cmd: ipr command struct + * + * Description: This attempts to block config access to the IOA. + * + * Return value: + * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN + **/ +static int ipr_reset_block_config_access_wait(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + int rc = IPR_RC_JOB_CONTINUE; + + if (pci_cfg_access_trylock(ioa_cfg->pdev)) { + ioa_cfg->cfg_locked = 1; + ipr_cmd->job_step = ioa_cfg->reset; + } else { + if (ipr_cmd->u.time_left) { + rc = IPR_RC_JOB_RETURN; + ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT; + ipr_reset_start_timer(ipr_cmd, + IPR_CHECK_FOR_RESET_TIMEOUT); + } else { + ipr_cmd->job_step = ioa_cfg->reset; + dev_err(&ioa_cfg->pdev->dev, + "Timed out waiting to lock config access. Resetting anyway.\n"); + } + } + + return rc; +} + +/** + * ipr_reset_block_config_access - Block config access to the IOA + * @ipr_cmd: ipr command struct + * + * Description: This attempts to block config access to the IOA + * + * Return value: + * IPR_RC_JOB_CONTINUE + **/ +static int ipr_reset_block_config_access(struct ipr_cmnd *ipr_cmd) +{ + ipr_cmd->ioa_cfg->cfg_locked = 0; + ipr_cmd->job_step = ipr_reset_block_config_access_wait; + ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT; + return IPR_RC_JOB_CONTINUE; +} + +/** * ipr_reset_allowed - Query whether or not IOA can be reset * @ioa_cfg: ioa config struct * @@ -7763,7 +7828,7 @@ static int ipr_reset_wait_to_start_bist(struct ipr_cmnd *ipr_cmd) ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT; ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT); } else { - ipr_cmd->job_step = ioa_cfg->reset; + ipr_cmd->job_step = ipr_reset_block_config_access; rc = IPR_RC_JOB_CONTINUE; } @@ -7796,7 +7861,7 @@ static int ipr_reset_alert(struct ipr_cmnd *ipr_cmd) writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg32); ipr_cmd->job_step = ipr_reset_wait_to_start_bist; } else { - ipr_cmd->job_step = ioa_cfg->reset; + ipr_cmd->job_step = ipr_reset_block_config_access; } ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT; diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index ac84736c1b9..b13f9cc1227 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -1387,6 +1387,7 @@ struct ipr_ioa_cfg { u8 msi_received:1; u8 sis64:1; u8 dump_timeout:1; + u8 cfg_locked:1; u8 revid; diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 218f71a8726..d77891e5683 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -4494,7 +4494,7 @@ ips_init_scb(ips_ha_t * ha, ips_scb_t * scb) /* */ /* Initialize a CCB to default values */ /* */ -/* ASSUMED to be callled from within a lock */ +/* ASSUMED to be called from within a lock */ /* */ /****************************************************************************/ static ips_scb_t * diff --git a/drivers/scsi/isci/firmware/Makefile b/drivers/scsi/isci/firmware/Makefile deleted file mode 100644 index 5f54461cabc..00000000000 --- a/drivers/scsi/isci/firmware/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# Makefile for create_fw -# -CC=gcc -CFLAGS=-c -Wall -O2 -g -LDFLAGS= -SOURCES=create_fw.c -OBJECTS=$(SOURCES:.cpp=.o) -EXECUTABLE=create_fw - -all: $(SOURCES) $(EXECUTABLE) - -$(EXECUTABLE): $(OBJECTS) - $(CC) $(LDFLAGS) $(OBJECTS) -o $@ - -.c.o: - $(CC) $(CFLAGS) $< -O $@ - -clean: - rm -f *.o $(EXECUTABLE) diff --git a/drivers/scsi/isci/firmware/README b/drivers/scsi/isci/firmware/README deleted file mode 100644 index 8056d2bd233..00000000000 --- a/drivers/scsi/isci/firmware/README +++ /dev/null @@ -1,36 +0,0 @@ -This defines the temporary binary blow we are to pass to the SCU -driver to emulate the binary firmware that we will eventually be -able to access via NVRAM on the SCU controller. - -The current size of the binary blob is expected to be 149 bytes or larger - -Header Types: -0x1: Phy Masks -0x2: Phy Gens -0x3: SAS Addrs -0xff: End of Data - -ID string - u8[12]: "#SCU MAGIC#\0" -Version - u8: 1 -SubVersion - u8: 0 - -Header Type - u8: 0x1 -Size - u8: 8 -Phy Mask - u32[8] - -Header Type - u8: 0x2 -Size - u8: 8 -Phy Gen - u32[8] - -Header Type - u8: 0x3 -Size - u8: 8 -Sas Addr - u64[8] - -Header Type - u8: 0xf - - -============================================================================== - -Place isci_firmware.bin in /lib/firmware -Be sure to recreate the initramfs image to include the firmware. - diff --git a/drivers/scsi/isci/firmware/create_fw.c b/drivers/scsi/isci/firmware/create_fw.c deleted file mode 100644 index c7a2887a7e9..00000000000 --- a/drivers/scsi/isci/firmware/create_fw.c +++ /dev/null @@ -1,99 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <string.h> -#include <errno.h> -#include <asm/types.h> -#include <strings.h> -#include <stdint.h> - -#include "create_fw.h" -#include "../probe_roms.h" - -int write_blob(struct isci_orom *isci_orom) -{ - FILE *fd; - int err; - size_t count; - - fd = fopen(blob_name, "w+"); - if (!fd) { - perror("Open file for write failed"); - fclose(fd); - return -EIO; - } - - count = fwrite(isci_orom, sizeof(struct isci_orom), 1, fd); - if (count != 1) { - perror("Write data failed"); - fclose(fd); - return -EIO; - } - - fclose(fd); - - return 0; -} - -void set_binary_values(struct isci_orom *isci_orom) -{ - int ctrl_idx, phy_idx, port_idx; - - /* setting OROM signature */ - strncpy(isci_orom->hdr.signature, sig, strlen(sig)); - isci_orom->hdr.version = version; - isci_orom->hdr.total_block_length = sizeof(struct isci_orom); - isci_orom->hdr.hdr_length = sizeof(struct sci_bios_oem_param_block_hdr); - isci_orom->hdr.num_elements = num_elements; - - for (ctrl_idx = 0; ctrl_idx < 2; ctrl_idx++) { - isci_orom->ctrl[ctrl_idx].controller.mode_type = mode_type; - isci_orom->ctrl[ctrl_idx].controller.max_concurrent_dev_spin_up = - max_num_concurrent_dev_spin_up; - isci_orom->ctrl[ctrl_idx].controller.do_enable_ssc = - enable_ssc; - - for (port_idx = 0; port_idx < 4; port_idx++) - isci_orom->ctrl[ctrl_idx].ports[port_idx].phy_mask = - phy_mask[ctrl_idx][port_idx]; - - for (phy_idx = 0; phy_idx < 4; phy_idx++) { - isci_orom->ctrl[ctrl_idx].phys[phy_idx].sas_address.high = - (__u32)(sas_addr[ctrl_idx][phy_idx] >> 32); - isci_orom->ctrl[ctrl_idx].phys[phy_idx].sas_address.low = - (__u32)(sas_addr[ctrl_idx][phy_idx]); - - isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control0 = - afe_tx_amp_control0; - isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control1 = - afe_tx_amp_control1; - isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control2 = - afe_tx_amp_control2; - isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control3 = - afe_tx_amp_control3; - } - } -} - -int main(void) -{ - int err; - struct isci_orom *isci_orom; - - isci_orom = malloc(sizeof(struct isci_orom)); - memset(isci_orom, 0, sizeof(struct isci_orom)); - - set_binary_values(isci_orom); - - err = write_blob(isci_orom); - if (err < 0) { - free(isci_orom); - return err; - } - - free(isci_orom); - return 0; -} diff --git a/drivers/scsi/isci/firmware/create_fw.h b/drivers/scsi/isci/firmware/create_fw.h deleted file mode 100644 index 5f298828d22..00000000000 --- a/drivers/scsi/isci/firmware/create_fw.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef _CREATE_FW_H_ -#define _CREATE_FW_H_ -#include "../probe_roms.h" - - -/* we are configuring for 2 SCUs */ -static const int num_elements = 2; - -/* - * For all defined arrays: - * elements 0-3 are for SCU0, ports 0-3 - * elements 4-7 are for SCU1, ports 0-3 - * - * valid configurations for one SCU are: - * P0 P1 P2 P3 - * ---------------- - * 0xF,0x0,0x0,0x0 # 1 x4 port - * 0x3,0x0,0x4,0x8 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are each x1 - * # ports - * 0x1,0x2,0xC,0x0 # Phys 0 and 1 are each x1 ports, phy 2 and phy 3 are a x2 - * # port - * 0x3,0x0,0xC,0x0 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are a x2 port - * 0x1,0x2,0x4,0x8 # Each phy is a x1 port (this is the default configuration) - * - * if there is a port/phy on which you do not wish to override the default - * values, use the value assigned to UNINIT_PARAM (255). - */ - -/* discovery mode type (port auto config mode by default ) */ - -/* - * if there is a port/phy on which you do not wish to override the default - * values, use the value "0000000000000000". SAS address of zero's is - * considered invalid and will not be used. - */ -#ifdef MPC -static const int mode_type = SCIC_PORT_MANUAL_CONFIGURATION_MODE; -static const __u8 phy_mask[2][4] = { {1, 2, 4, 8}, - {1, 2, 4, 8} }; -static const unsigned long long sas_addr[2][4] = { { 0x5FCFFFFFF0000001ULL, - 0x5FCFFFFFF0000002ULL, - 0x5FCFFFFFF0000003ULL, - 0x5FCFFFFFF0000004ULL }, - { 0x5FCFFFFFF0000005ULL, - 0x5FCFFFFFF0000006ULL, - 0x5FCFFFFFF0000007ULL, - 0x5FCFFFFFF0000008ULL } }; -#else /* APC (default) */ -static const int mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE; -static const __u8 phy_mask[2][4]; -static const unsigned long long sas_addr[2][4] = { { 0x5FCFFFFF00000001ULL, - 0x5FCFFFFF00000001ULL, - 0x5FCFFFFF00000001ULL, - 0x5FCFFFFF00000001ULL }, - { 0x5FCFFFFF00000002ULL, - 0x5FCFFFFF00000002ULL, - 0x5FCFFFFF00000002ULL, - 0x5FCFFFFF00000002ULL } }; -#endif - -/* Maximum number of concurrent device spin up */ -static const int max_num_concurrent_dev_spin_up = 1; - -/* enable of ssc operation */ -static const int enable_ssc; - -/* AFE_TX_AMP_CONTROL */ -static const unsigned int afe_tx_amp_control0 = 0x000bdd08; -static const unsigned int afe_tx_amp_control1 = 0x000ffc00; -static const unsigned int afe_tx_amp_control2 = 0x000b7c09; -static const unsigned int afe_tx_amp_control3 = 0x000afc6e; - -static const char blob_name[] = "isci_firmware.bin"; -static const char sig[] = "ISCUOEMB"; -static const unsigned char version = 0x10; - -#endif diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index e7fe9c4c85b..418391b1c36 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -899,7 +899,8 @@ static enum sci_status sci_controller_start_next_phy(struct isci_host *ihost) */ if ((iphy->is_in_link_training == false && state == SCI_PHY_INITIAL) || (iphy->is_in_link_training == false && state == SCI_PHY_STOPPED) || - (iphy->is_in_link_training == true && is_phy_starting(iphy))) { + (iphy->is_in_link_training == true && is_phy_starting(iphy)) || + (ihost->port_agent.phy_ready_mask != ihost->port_agent.phy_configured_mask)) { is_controller_start_complete = false; break; } @@ -1666,6 +1667,9 @@ static void sci_controller_set_default_config_parameters(struct isci_host *ihost /* Default to no SSC operation. */ ihost->oem_parameters.controller.do_enable_ssc = false; + /* Default to short cables on all phys. */ + ihost->oem_parameters.controller.cable_selection_mask = 0; + /* Initialize all of the port parameter information to narrow ports. */ for (index = 0; index < SCI_MAX_PORTS; index++) { ihost->oem_parameters.ports[index].phy_mask = 0; @@ -1673,8 +1677,9 @@ static void sci_controller_set_default_config_parameters(struct isci_host *ihost /* Initialize all of the phy parameter information. */ for (index = 0; index < SCI_MAX_PHYS; index++) { - /* Default to 6G (i.e. Gen 3) for now. */ - ihost->user_parameters.phys[index].max_speed_generation = 3; + /* Default to 3G (i.e. Gen 2). */ + ihost->user_parameters.phys[index].max_speed_generation = + SCIC_SDS_PARM_GEN2_SPEED; /* the frequencies cannot be 0 */ ihost->user_parameters.phys[index].align_insertion_frequency = 0x7f; @@ -1694,7 +1699,7 @@ static void sci_controller_set_default_config_parameters(struct isci_host *ihost ihost->user_parameters.ssp_inactivity_timeout = 5; ihost->user_parameters.stp_max_occupancy_timeout = 5; ihost->user_parameters.ssp_max_occupancy_timeout = 20; - ihost->user_parameters.no_outbound_task_timeout = 20; + ihost->user_parameters.no_outbound_task_timeout = 2; } static void controller_timeout(unsigned long data) @@ -1759,7 +1764,7 @@ static enum sci_status sci_controller_construct(struct isci_host *ihost, return sci_controller_reset(ihost); } -int sci_oem_parameters_validate(struct sci_oem_params *oem) +int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version) { int i; @@ -1791,18 +1796,63 @@ int sci_oem_parameters_validate(struct sci_oem_params *oem) oem->controller.max_concurr_spin_up < 1) return -EINVAL; + if (oem->controller.do_enable_ssc) { + if (version < ISCI_ROM_VER_1_1 && oem->controller.do_enable_ssc != 1) + return -EINVAL; + + if (version >= ISCI_ROM_VER_1_1) { + u8 test = oem->controller.ssc_sata_tx_spread_level; + + switch (test) { + case 0: + case 2: + case 3: + case 6: + case 7: + break; + default: + return -EINVAL; + } + + test = oem->controller.ssc_sas_tx_spread_level; + if (oem->controller.ssc_sas_tx_type == 0) { + switch (test) { + case 0: + case 2: + case 3: + break; + default: + return -EINVAL; + } + } else if (oem->controller.ssc_sas_tx_type == 1) { + switch (test) { + case 0: + case 3: + case 6: + break; + default: + return -EINVAL; + } + } + } + } + return 0; } static enum sci_status sci_oem_parameters_set(struct isci_host *ihost) { u32 state = ihost->sm.current_state_id; + struct isci_pci_info *pci_info = to_pci_info(ihost->pdev); if (state == SCIC_RESET || state == SCIC_INITIALIZING || state == SCIC_INITIALIZED) { + u8 oem_version = pci_info->orom ? pci_info->orom->hdr.version : + ISCI_ROM_VER_1_0; - if (sci_oem_parameters_validate(&ihost->oem_parameters)) + if (sci_oem_parameters_validate(&ihost->oem_parameters, + oem_version)) return SCI_FAILURE_INVALID_PARAMETER_VALUE; return SCI_SUCCESS; @@ -1857,6 +1907,31 @@ static void power_control_timeout(unsigned long data) ihost->power_control.phys_waiting--; ihost->power_control.phys_granted_power++; sci_phy_consume_power_handler(iphy); + + if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) { + u8 j; + + for (j = 0; j < SCI_MAX_PHYS; j++) { + struct isci_phy *requester = ihost->power_control.requesters[j]; + + /* + * Search the power_control queue to see if there are other phys + * attached to the same remote device. If found, take all of + * them out of await_sas_power state. + */ + if (requester != NULL && requester != iphy) { + u8 other = memcmp(requester->frame_rcvd.iaf.sas_addr, + iphy->frame_rcvd.iaf.sas_addr, + sizeof(requester->frame_rcvd.iaf.sas_addr)); + + if (other == 0) { + ihost->power_control.requesters[j] = NULL; + ihost->power_control.phys_waiting--; + sci_phy_consume_power_handler(requester); + } + } + } + } } /* @@ -1891,9 +1966,34 @@ void sci_controller_power_control_queue_insert(struct isci_host *ihost, ihost->power_control.timer_started = true; } else { - /* Add the phy in the waiting list */ - ihost->power_control.requesters[iphy->phy_index] = iphy; - ihost->power_control.phys_waiting++; + /* + * There are phys, attached to the same sas address as this phy, are + * already in READY state, this phy don't need wait. + */ + u8 i; + struct isci_phy *current_phy; + + for (i = 0; i < SCI_MAX_PHYS; i++) { + u8 other; + current_phy = &ihost->phys[i]; + + other = memcmp(current_phy->frame_rcvd.iaf.sas_addr, + iphy->frame_rcvd.iaf.sas_addr, + sizeof(current_phy->frame_rcvd.iaf.sas_addr)); + + if (current_phy->sm.current_state_id == SCI_PHY_READY && + current_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS && + other == 0) { + sci_phy_consume_power_handler(iphy); + break; + } + } + + if (i == SCI_MAX_PHYS) { + /* Add the phy in the waiting list */ + ihost->power_control.requesters[iphy->phy_index] = iphy; + ihost->power_control.phys_waiting++; + } } } @@ -1908,162 +2008,250 @@ void sci_controller_power_control_queue_remove(struct isci_host *ihost, ihost->power_control.requesters[iphy->phy_index] = NULL; } +static int is_long_cable(int phy, unsigned char selection_byte) +{ + return !!(selection_byte & (1 << phy)); +} + +static int is_medium_cable(int phy, unsigned char selection_byte) +{ + return !!(selection_byte & (1 << (phy + 4))); +} + +static enum cable_selections decode_selection_byte( + int phy, + unsigned char selection_byte) +{ + return ((selection_byte & (1 << phy)) ? 1 : 0) + + (selection_byte & (1 << (phy + 4)) ? 2 : 0); +} + +static unsigned char *to_cable_select(struct isci_host *ihost) +{ + if (is_cable_select_overridden()) + return ((unsigned char *)&cable_selection_override) + + ihost->id; + else + return &ihost->oem_parameters.controller.cable_selection_mask; +} + +enum cable_selections decode_cable_selection(struct isci_host *ihost, int phy) +{ + return decode_selection_byte(phy, *to_cable_select(ihost)); +} + +char *lookup_cable_names(enum cable_selections selection) +{ + static char *cable_names[] = { + [short_cable] = "short", + [long_cable] = "long", + [medium_cable] = "medium", + [undefined_cable] = "<undefined, assumed long>" /* bit 0==1 */ + }; + return (selection <= undefined_cable) ? cable_names[selection] + : cable_names[undefined_cable]; +} + #define AFE_REGISTER_WRITE_DELAY 10 -/* Initialize the AFE for this phy index. We need to read the AFE setup from - * the OEM parameters - */ static void sci_controller_afe_initialization(struct isci_host *ihost) { + struct scu_afe_registers __iomem *afe = &ihost->scu_registers->afe; const struct sci_oem_params *oem = &ihost->oem_parameters; struct pci_dev *pdev = ihost->pdev; u32 afe_status; u32 phy_id; + unsigned char cable_selection_mask = *to_cable_select(ihost); /* Clear DFX Status registers */ - writel(0x0081000f, &ihost->scu_registers->afe.afe_dfx_master_control0); + writel(0x0081000f, &afe->afe_dfx_master_control0); udelay(AFE_REGISTER_WRITE_DELAY); - if (is_b0(pdev)) { + if (is_b0(pdev) || is_c0(pdev) || is_c1(pdev)) { /* PM Rx Equalization Save, PM SPhy Rx Acknowledgement - * Timer, PM Stagger Timer */ - writel(0x0007BFFF, &ihost->scu_registers->afe.afe_pmsn_master_control2); + * Timer, PM Stagger Timer + */ + writel(0x0007FFFF, &afe->afe_pmsn_master_control2); udelay(AFE_REGISTER_WRITE_DELAY); } /* Configure bias currents to normal */ if (is_a2(pdev)) - writel(0x00005A00, &ihost->scu_registers->afe.afe_bias_control); + writel(0x00005A00, &afe->afe_bias_control); else if (is_b0(pdev) || is_c0(pdev)) - writel(0x00005F00, &ihost->scu_registers->afe.afe_bias_control); + writel(0x00005F00, &afe->afe_bias_control); + else if (is_c1(pdev)) + writel(0x00005500, &afe->afe_bias_control); udelay(AFE_REGISTER_WRITE_DELAY); /* Enable PLL */ - if (is_b0(pdev) || is_c0(pdev)) - writel(0x80040A08, &ihost->scu_registers->afe.afe_pll_control0); - else - writel(0x80040908, &ihost->scu_registers->afe.afe_pll_control0); + if (is_a2(pdev)) + writel(0x80040908, &afe->afe_pll_control0); + else if (is_b0(pdev) || is_c0(pdev)) + writel(0x80040A08, &afe->afe_pll_control0); + else if (is_c1(pdev)) { + writel(0x80000B08, &afe->afe_pll_control0); + udelay(AFE_REGISTER_WRITE_DELAY); + writel(0x00000B08, &afe->afe_pll_control0); + udelay(AFE_REGISTER_WRITE_DELAY); + writel(0x80000B08, &afe->afe_pll_control0); + } udelay(AFE_REGISTER_WRITE_DELAY); /* Wait for the PLL to lock */ do { - afe_status = readl(&ihost->scu_registers->afe.afe_common_block_status); + afe_status = readl(&afe->afe_common_block_status); udelay(AFE_REGISTER_WRITE_DELAY); } while ((afe_status & 0x00001000) == 0); if (is_a2(pdev)) { - /* Shorten SAS SNW lock time (RxLock timer value from 76 us to 50 us) */ - writel(0x7bcc96ad, &ihost->scu_registers->afe.afe_pmsn_master_control0); + /* Shorten SAS SNW lock time (RxLock timer value from 76 + * us to 50 us) + */ + writel(0x7bcc96ad, &afe->afe_pmsn_master_control0); udelay(AFE_REGISTER_WRITE_DELAY); } for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++) { + struct scu_afe_transceiver *xcvr = &afe->scu_afe_xcvr[phy_id]; const struct sci_phy_oem_params *oem_phy = &oem->phys[phy_id]; + int cable_length_long = + is_long_cable(phy_id, cable_selection_mask); + int cable_length_medium = + is_medium_cable(phy_id, cable_selection_mask); - if (is_b0(pdev)) { - /* Configure transmitter SSC parameters */ - writel(0x00030000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_ssc_control); + if (is_a2(pdev)) { + /* All defaults, except the Receive Word + * Alignament/Comma Detect Enable....(0xe800) + */ + writel(0x00004512, &xcvr->afe_xcvr_control0); + udelay(AFE_REGISTER_WRITE_DELAY); + + writel(0x0050100F, &xcvr->afe_xcvr_control1); + udelay(AFE_REGISTER_WRITE_DELAY); + } else if (is_b0(pdev)) { + /* Configure transmitter SSC parameters */ + writel(0x00030000, &xcvr->afe_tx_ssc_control); udelay(AFE_REGISTER_WRITE_DELAY); } else if (is_c0(pdev)) { - /* Configure transmitter SSC parameters */ - writel(0x0003000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_ssc_control); + /* Configure transmitter SSC parameters */ + writel(0x00010202, &xcvr->afe_tx_ssc_control); udelay(AFE_REGISTER_WRITE_DELAY); - /* - * All defaults, except the Receive Word Alignament/Comma Detect - * Enable....(0xe800) */ - writel(0x00004500, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_xcvr_control0); + /* All defaults, except the Receive Word + * Alignament/Comma Detect Enable....(0xe800) + */ + writel(0x00014500, &xcvr->afe_xcvr_control0); udelay(AFE_REGISTER_WRITE_DELAY); - } else { - /* - * All defaults, except the Receive Word Alignament/Comma Detect - * Enable....(0xe800) */ - writel(0x00004512, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_xcvr_control0); + } else if (is_c1(pdev)) { + /* Configure transmitter SSC parameters */ + writel(0x00010202, &xcvr->afe_tx_ssc_control); udelay(AFE_REGISTER_WRITE_DELAY); - writel(0x0050100F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_xcvr_control1); + /* All defaults, except the Receive Word + * Alignament/Comma Detect Enable....(0xe800) + */ + writel(0x0001C500, &xcvr->afe_xcvr_control0); udelay(AFE_REGISTER_WRITE_DELAY); } - /* - * Power up TX and RX out from power down (PWRDNTX and PWRDNRX) - * & increase TX int & ext bias 20%....(0xe85c) */ + /* Power up TX and RX out from power down (PWRDNTX and + * PWRDNRX) & increase TX int & ext bias 20%....(0xe85c) + */ if (is_a2(pdev)) - writel(0x000003F0, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control); + writel(0x000003F0, &xcvr->afe_channel_control); else if (is_b0(pdev)) { - /* Power down TX and RX (PWRDNTX and PWRDNRX) */ - writel(0x000003D7, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control); + writel(0x000003D7, &xcvr->afe_channel_control); udelay(AFE_REGISTER_WRITE_DELAY); - /* - * Power up TX and RX out from power down (PWRDNTX and PWRDNRX) - * & increase TX int & ext bias 20%....(0xe85c) */ - writel(0x000003D4, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control); - } else { - writel(0x000001E7, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control); + writel(0x000003D4, &xcvr->afe_channel_control); + } else if (is_c0(pdev)) { + writel(0x000001E7, &xcvr->afe_channel_control); udelay(AFE_REGISTER_WRITE_DELAY); - /* - * Power up TX and RX out from power down (PWRDNTX and PWRDNRX) - * & increase TX int & ext bias 20%....(0xe85c) */ - writel(0x000001E4, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control); + writel(0x000001E4, &xcvr->afe_channel_control); + } else if (is_c1(pdev)) { + writel(cable_length_long ? 0x000002F7 : 0x000001F7, + &xcvr->afe_channel_control); + udelay(AFE_REGISTER_WRITE_DELAY); + + writel(cable_length_long ? 0x000002F4 : 0x000001F4, + &xcvr->afe_channel_control); } udelay(AFE_REGISTER_WRITE_DELAY); if (is_a2(pdev)) { /* Enable TX equalization (0xe824) */ - writel(0x00040000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_control); + writel(0x00040000, &xcvr->afe_tx_control); udelay(AFE_REGISTER_WRITE_DELAY); } - /* - * RDPI=0x0(RX Power On), RXOOBDETPDNC=0x0, TPD=0x0(TX Power On), - * RDD=0x0(RX Detect Enabled) ....(0xe800) */ - writel(0x00004100, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_xcvr_control0); + if (is_a2(pdev) || is_b0(pdev)) + /* RDPI=0x0(RX Power On), RXOOBDETPDNC=0x0, + * TPD=0x0(TX Power On), RDD=0x0(RX Detect + * Enabled) ....(0xe800) + */ + writel(0x00004100, &xcvr->afe_xcvr_control0); + else if (is_c0(pdev)) + writel(0x00014100, &xcvr->afe_xcvr_control0); + else if (is_c1(pdev)) + writel(0x0001C100, &xcvr->afe_xcvr_control0); udelay(AFE_REGISTER_WRITE_DELAY); /* Leave DFE/FFE on */ if (is_a2(pdev)) - writel(0x3F11103F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_rx_ssc_control0); + writel(0x3F11103F, &xcvr->afe_rx_ssc_control0); else if (is_b0(pdev)) { - writel(0x3F11103F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_rx_ssc_control0); + writel(0x3F11103F, &xcvr->afe_rx_ssc_control0); udelay(AFE_REGISTER_WRITE_DELAY); /* Enable TX equalization (0xe824) */ - writel(0x00040000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_control); - } else { - writel(0x0140DF0F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_rx_ssc_control1); + writel(0x00040000, &xcvr->afe_tx_control); + } else if (is_c0(pdev)) { + writel(0x01400C0F, &xcvr->afe_rx_ssc_control1); + udelay(AFE_REGISTER_WRITE_DELAY); + + writel(0x3F6F103F, &xcvr->afe_rx_ssc_control0); + udelay(AFE_REGISTER_WRITE_DELAY); + + /* Enable TX equalization (0xe824) */ + writel(0x00040000, &xcvr->afe_tx_control); + } else if (is_c1(pdev)) { + writel(cable_length_long ? 0x01500C0C : + cable_length_medium ? 0x01400C0D : 0x02400C0D, + &xcvr->afe_xcvr_control1); + udelay(AFE_REGISTER_WRITE_DELAY); + + writel(0x000003E0, &xcvr->afe_dfx_rx_control1); udelay(AFE_REGISTER_WRITE_DELAY); - writel(0x3F6F103F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_rx_ssc_control0); + writel(cable_length_long ? 0x33091C1F : + cable_length_medium ? 0x3315181F : 0x2B17161F, + &xcvr->afe_rx_ssc_control0); udelay(AFE_REGISTER_WRITE_DELAY); /* Enable TX equalization (0xe824) */ - writel(0x00040000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_control); + writel(0x00040000, &xcvr->afe_tx_control); } udelay(AFE_REGISTER_WRITE_DELAY); - writel(oem_phy->afe_tx_amp_control0, - &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_amp_control0); + writel(oem_phy->afe_tx_amp_control0, &xcvr->afe_tx_amp_control0); udelay(AFE_REGISTER_WRITE_DELAY); - writel(oem_phy->afe_tx_amp_control1, - &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_amp_control1); + writel(oem_phy->afe_tx_amp_control1, &xcvr->afe_tx_amp_control1); udelay(AFE_REGISTER_WRITE_DELAY); - writel(oem_phy->afe_tx_amp_control2, - &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_amp_control2); + writel(oem_phy->afe_tx_amp_control2, &xcvr->afe_tx_amp_control2); udelay(AFE_REGISTER_WRITE_DELAY); - writel(oem_phy->afe_tx_amp_control3, - &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_amp_control3); + writel(oem_phy->afe_tx_amp_control3, &xcvr->afe_tx_amp_control3); udelay(AFE_REGISTER_WRITE_DELAY); } /* Transfer control to the PEs */ - writel(0x00010f00, &ihost->scu_registers->afe.afe_dfx_master_control0); + writel(0x00010f00, &afe->afe_dfx_master_control0); udelay(AFE_REGISTER_WRITE_DELAY); } diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h index 646051afd3c..5477f0fa823 100644 --- a/drivers/scsi/isci/host.h +++ b/drivers/scsi/isci/host.h @@ -435,11 +435,36 @@ static inline bool is_b0(struct pci_dev *pdev) static inline bool is_c0(struct pci_dev *pdev) { - if (pdev->revision >= 5) + if (pdev->revision == 5) return true; return false; } +static inline bool is_c1(struct pci_dev *pdev) +{ + if (pdev->revision >= 6) + return true; + return false; +} + +enum cable_selections { + short_cable = 0, + long_cable = 1, + medium_cable = 2, + undefined_cable = 3 +}; + +#define CABLE_OVERRIDE_DISABLED (0x10000) + +static inline int is_cable_select_overridden(void) +{ + return cable_selection_override < CABLE_OVERRIDE_DISABLED; +} + +enum cable_selections decode_cable_selection(struct isci_host *ihost, int phy); +void validate_cable_selections(struct isci_host *ihost); +char *lookup_cable_names(enum cable_selections); + /* set hw control for 'activity', even though active enclosures seem to drive * the activity led on their own. Skip setting FSENG control on 'status' due * to unexpected operation and 'error' due to not being a supported automatic diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index a97edabcb85..17c4c2c89c2 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -65,7 +65,7 @@ #include "probe_roms.h" #define MAJ 1 -#define MIN 0 +#define MIN 1 #define BUILD 0 #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \ __stringify(BUILD) @@ -94,7 +94,7 @@ MODULE_DEVICE_TABLE(pci, isci_id_table); /* linux isci specific settings */ -unsigned char no_outbound_task_to = 20; +unsigned char no_outbound_task_to = 2; module_param(no_outbound_task_to, byte, 0); MODULE_PARM_DESC(no_outbound_task_to, "No Outbound Task Timeout (1us incr)"); @@ -114,7 +114,7 @@ u16 stp_inactive_to = 5; module_param(stp_inactive_to, ushort, 0); MODULE_PARM_DESC(stp_inactive_to, "STP inactivity timeout (100us incr)"); -unsigned char phy_gen = 3; +unsigned char phy_gen = SCIC_SDS_PARM_GEN2_SPEED; module_param(phy_gen, byte, 0); MODULE_PARM_DESC(phy_gen, "PHY generation (1: 1.5Gbps 2: 3.0Gbps 3: 6.0Gbps)"); @@ -122,6 +122,14 @@ unsigned char max_concurr_spinup; module_param(max_concurr_spinup, byte, 0); MODULE_PARM_DESC(max_concurr_spinup, "Max concurrent device spinup"); +uint cable_selection_override = CABLE_OVERRIDE_DISABLED; +module_param(cable_selection_override, uint, 0); + +MODULE_PARM_DESC(cable_selection_override, + "This field indicates length of the SAS/SATA cable between " + "host and device. If any bits > 15 are set (default) " + "indicates \"use platform defaults\""); + static ssize_t isci_show_id(struct device *dev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = container_of(dev, typeof(*shost), shost_dev); @@ -412,6 +420,14 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id) return NULL; isci_host->shost = shost; + dev_info(&pdev->dev, "%sSCU controller %d: phy 3-0 cables: " + "{%s, %s, %s, %s}\n", + (is_cable_select_overridden() ? "* " : ""), isci_host->id, + lookup_cable_names(decode_cable_selection(isci_host, 3)), + lookup_cable_names(decode_cable_selection(isci_host, 2)), + lookup_cable_names(decode_cable_selection(isci_host, 1)), + lookup_cable_names(decode_cable_selection(isci_host, 0))); + err = isci_host_init(isci_host); if (err) goto err_shost; @@ -466,7 +482,8 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic orom = isci_request_oprom(pdev); for (i = 0; orom && i < ARRAY_SIZE(orom->ctrl); i++) { - if (sci_oem_parameters_validate(&orom->ctrl[i])) { + if (sci_oem_parameters_validate(&orom->ctrl[i], + orom->hdr.version)) { dev_warn(&pdev->dev, "[%d]: invalid oem parameters detected, falling back to firmware\n", i); devm_kfree(&pdev->dev, orom); diff --git a/drivers/scsi/isci/isci.h b/drivers/scsi/isci/isci.h index 8efeb6b0832..234ab46fce3 100644 --- a/drivers/scsi/isci/isci.h +++ b/drivers/scsi/isci/isci.h @@ -480,6 +480,7 @@ extern u16 ssp_inactive_to; extern u16 stp_inactive_to; extern unsigned char phy_gen; extern unsigned char max_concurr_spinup; +extern uint cable_selection_override; irqreturn_t isci_msix_isr(int vec, void *data); irqreturn_t isci_intx_isr(int vec, void *data); diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c index 35f50c2183e..fe18acfd6eb 100644 --- a/drivers/scsi/isci/phy.c +++ b/drivers/scsi/isci/phy.c @@ -91,22 +91,23 @@ sci_phy_transport_layer_initialization(struct isci_phy *iphy, static enum sci_status sci_phy_link_layer_initialization(struct isci_phy *iphy, - struct scu_link_layer_registers __iomem *reg) + struct scu_link_layer_registers __iomem *llr) { struct isci_host *ihost = iphy->owning_port->owning_controller; + struct sci_phy_user_params *phy_user; + struct sci_phy_oem_params *phy_oem; int phy_idx = iphy->phy_index; - struct sci_phy_user_params *phy_user = &ihost->user_parameters.phys[phy_idx]; - struct sci_phy_oem_params *phy_oem = - &ihost->oem_parameters.phys[phy_idx]; - u32 phy_configuration; struct sci_phy_cap phy_cap; + u32 phy_configuration; u32 parity_check = 0; u32 parity_count = 0; u32 llctl, link_rate; u32 clksm_value = 0; u32 sp_timeouts = 0; - iphy->link_layer_registers = reg; + phy_user = &ihost->user_parameters.phys[phy_idx]; + phy_oem = &ihost->oem_parameters.phys[phy_idx]; + iphy->link_layer_registers = llr; /* Set our IDENTIFY frame data */ #define SCI_END_DEVICE 0x01 @@ -116,32 +117,26 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, SCU_SAS_TIID_GEN_BIT(STP_INITIATOR) | SCU_SAS_TIID_GEN_BIT(DA_SATA_HOST) | SCU_SAS_TIID_GEN_VAL(DEVICE_TYPE, SCI_END_DEVICE), - &iphy->link_layer_registers->transmit_identification); + &llr->transmit_identification); /* Write the device SAS Address */ - writel(0xFEDCBA98, - &iphy->link_layer_registers->sas_device_name_high); - writel(phy_idx, &iphy->link_layer_registers->sas_device_name_low); + writel(0xFEDCBA98, &llr->sas_device_name_high); + writel(phy_idx, &llr->sas_device_name_low); /* Write the source SAS Address */ - writel(phy_oem->sas_address.high, - &iphy->link_layer_registers->source_sas_address_high); - writel(phy_oem->sas_address.low, - &iphy->link_layer_registers->source_sas_address_low); + writel(phy_oem->sas_address.high, &llr->source_sas_address_high); + writel(phy_oem->sas_address.low, &llr->source_sas_address_low); /* Clear and Set the PHY Identifier */ - writel(0, &iphy->link_layer_registers->identify_frame_phy_id); - writel(SCU_SAS_TIPID_GEN_VALUE(ID, phy_idx), - &iphy->link_layer_registers->identify_frame_phy_id); + writel(0, &llr->identify_frame_phy_id); + writel(SCU_SAS_TIPID_GEN_VALUE(ID, phy_idx), &llr->identify_frame_phy_id); /* Change the initial state of the phy configuration register */ - phy_configuration = - readl(&iphy->link_layer_registers->phy_configuration); + phy_configuration = readl(&llr->phy_configuration); /* Hold OOB state machine in reset */ phy_configuration |= SCU_SAS_PCFG_GEN_BIT(OOB_RESET); - writel(phy_configuration, - &iphy->link_layer_registers->phy_configuration); + writel(phy_configuration, &llr->phy_configuration); /* Configure the SNW capabilities */ phy_cap.all = 0; @@ -149,15 +144,64 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, phy_cap.gen3_no_ssc = 1; phy_cap.gen2_no_ssc = 1; phy_cap.gen1_no_ssc = 1; - if (ihost->oem_parameters.controller.do_enable_ssc == true) { + if (ihost->oem_parameters.controller.do_enable_ssc) { + struct scu_afe_registers __iomem *afe = &ihost->scu_registers->afe; + struct scu_afe_transceiver *xcvr = &afe->scu_afe_xcvr[phy_idx]; + struct isci_pci_info *pci_info = to_pci_info(ihost->pdev); + bool en_sas = false; + bool en_sata = false; + u32 sas_type = 0; + u32 sata_spread = 0x2; + u32 sas_spread = 0x2; + phy_cap.gen3_ssc = 1; phy_cap.gen2_ssc = 1; phy_cap.gen1_ssc = 1; + + if (pci_info->orom->hdr.version < ISCI_ROM_VER_1_1) + en_sas = en_sata = true; + else { + sata_spread = ihost->oem_parameters.controller.ssc_sata_tx_spread_level; + sas_spread = ihost->oem_parameters.controller.ssc_sas_tx_spread_level; + + if (sata_spread) + en_sata = true; + + if (sas_spread) { + en_sas = true; + sas_type = ihost->oem_parameters.controller.ssc_sas_tx_type; + } + + } + + if (en_sas) { + u32 reg; + + reg = readl(&xcvr->afe_xcvr_control0); + reg |= (0x00100000 | (sas_type << 19)); + writel(reg, &xcvr->afe_xcvr_control0); + + reg = readl(&xcvr->afe_tx_ssc_control); + reg |= sas_spread << 8; + writel(reg, &xcvr->afe_tx_ssc_control); + } + + if (en_sata) { + u32 reg; + + reg = readl(&xcvr->afe_tx_ssc_control); + reg |= sata_spread; + writel(reg, &xcvr->afe_tx_ssc_control); + + reg = readl(&llr->stp_control); + reg |= 1 << 12; + writel(reg, &llr->stp_control); + } } - /* - * The SAS specification indicates that the phy_capabilities that - * are transmitted shall have an even parity. Calculate the parity. */ + /* The SAS specification indicates that the phy_capabilities that + * are transmitted shall have an even parity. Calculate the parity. + */ parity_check = phy_cap.all; while (parity_check != 0) { if (parity_check & 0x1) @@ -165,20 +209,20 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, parity_check >>= 1; } - /* - * If parity indicates there are an odd number of bits set, then - * set the parity bit to 1 in the phy capabilities. */ + /* If parity indicates there are an odd number of bits set, then + * set the parity bit to 1 in the phy capabilities. + */ if ((parity_count % 2) != 0) phy_cap.parity = 1; - writel(phy_cap.all, &iphy->link_layer_registers->phy_capabilities); + writel(phy_cap.all, &llr->phy_capabilities); /* Set the enable spinup period but disable the ability to send * notify enable spinup */ writel(SCU_ENSPINUP_GEN_VAL(COUNT, phy_user->notify_enable_spin_up_insertion_frequency), - &iphy->link_layer_registers->notify_enable_spinup_control); + &llr->notify_enable_spinup_control); /* Write the ALIGN Insertion Ferequency for connected phy and * inpendent of connected state @@ -189,11 +233,13 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, clksm_value |= SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL(GENERAL, phy_user->align_insertion_frequency); - writel(clksm_value, &iphy->link_layer_registers->clock_skew_management); + writel(clksm_value, &llr->clock_skew_management); - /* @todo Provide a way to write this register correctly */ - writel(0x02108421, - &iphy->link_layer_registers->afe_lookup_table_control); + if (is_c0(ihost->pdev) || is_c1(ihost->pdev)) { + writel(0x04210400, &llr->afe_lookup_table_control); + writel(0x020A7C05, &llr->sas_primitive_timeout); + } else + writel(0x02108421, &llr->afe_lookup_table_control); llctl = SCU_SAS_LLCTL_GEN_VAL(NO_OUTBOUND_TASK_TIMEOUT, (u8)ihost->user_parameters.no_outbound_task_timeout); @@ -210,9 +256,9 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, break; } llctl |= SCU_SAS_LLCTL_GEN_VAL(MAX_LINK_RATE, link_rate); - writel(llctl, &iphy->link_layer_registers->link_layer_control); + writel(llctl, &llr->link_layer_control); - sp_timeouts = readl(&iphy->link_layer_registers->sas_phy_timeouts); + sp_timeouts = readl(&llr->sas_phy_timeouts); /* Clear the default 0x36 (54us) RATE_CHANGE timeout value. */ sp_timeouts &= ~SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0xFF); @@ -222,20 +268,23 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, */ sp_timeouts |= SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0x3B); - writel(sp_timeouts, &iphy->link_layer_registers->sas_phy_timeouts); + writel(sp_timeouts, &llr->sas_phy_timeouts); if (is_a2(ihost->pdev)) { - /* Program the max ARB time for the PHY to 700us so we inter-operate with - * the PMC expander which shuts down PHYs if the expander PHY generates too - * many breaks. This time value will guarantee that the initiator PHY will - * generate the break. + /* Program the max ARB time for the PHY to 700us so we + * inter-operate with the PMC expander which shuts down + * PHYs if the expander PHY generates too many breaks. + * This time value will guarantee that the initiator PHY + * will generate the break. */ writel(SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME, - &iphy->link_layer_registers->maximum_arbitration_wait_timer_timeout); + &llr->maximum_arbitration_wait_timer_timeout); } - /* Disable link layer hang detection, rely on the OS timeout for I/O timeouts. */ - writel(0, &iphy->link_layer_registers->link_layer_hang_detection_timeout); + /* Disable link layer hang detection, rely on the OS timeout for + * I/O timeouts. + */ + writel(0, &llr->link_layer_hang_detection_timeout); /* We can exit the initial state to the stopped state */ sci_change_state(&iphy->sm, SCI_PHY_STOPPED); @@ -1049,24 +1098,25 @@ static void scu_link_layer_stop_protocol_engine( writel(enable_spinup_value, &iphy->link_layer_registers->notify_enable_spinup_control); } -/** - * - * - * This method will start the OOB/SN state machine for this struct isci_phy object. - */ -static void scu_link_layer_start_oob( - struct isci_phy *iphy) +static void scu_link_layer_start_oob(struct isci_phy *iphy) { - u32 scu_sas_pcfg_value; - - scu_sas_pcfg_value = - readl(&iphy->link_layer_registers->phy_configuration); - scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE); - scu_sas_pcfg_value &= - ~(SCU_SAS_PCFG_GEN_BIT(OOB_RESET) | - SCU_SAS_PCFG_GEN_BIT(HARD_RESET)); - writel(scu_sas_pcfg_value, - &iphy->link_layer_registers->phy_configuration); + struct scu_link_layer_registers __iomem *ll = iphy->link_layer_registers; + u32 val; + + /** Reset OOB sequence - start */ + val = readl(&ll->phy_configuration); + val &= ~(SCU_SAS_PCFG_GEN_BIT(OOB_RESET) | + SCU_SAS_PCFG_GEN_BIT(HARD_RESET)); + writel(val, &ll->phy_configuration); + readl(&ll->phy_configuration); /* flush */ + /** Reset OOB sequence - end */ + + /** Start OOB sequence - start */ + val = readl(&ll->phy_configuration); + val |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE); + writel(val, &ll->phy_configuration); + readl(&ll->phy_configuration); /* flush */ + /** Start OOB sequence - end */ } /** diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c index ac7f27749f9..7c6ac58a5c4 100644 --- a/drivers/scsi/isci/port.c +++ b/drivers/scsi/isci/port.c @@ -114,7 +114,7 @@ static u32 sci_port_get_phys(struct isci_port *iport) * value is returned if the specified port is not valid. When this value is * returned, no data is copied to the properties output parameter. */ -static enum sci_status sci_port_get_properties(struct isci_port *iport, +enum sci_status sci_port_get_properties(struct isci_port *iport, struct sci_port_properties *prop) { if (!iport || iport->logical_port_index == SCIC_SDS_DUMMY_PORT) @@ -647,19 +647,26 @@ void sci_port_setup_transports(struct isci_port *iport, u32 device_id) } } -static void sci_port_activate_phy(struct isci_port *iport, struct isci_phy *iphy, - bool do_notify_user) +static void sci_port_resume_phy(struct isci_port *iport, struct isci_phy *iphy) +{ + sci_phy_resume(iphy); + iport->enabled_phy_mask |= 1 << iphy->phy_index; +} + +static void sci_port_activate_phy(struct isci_port *iport, + struct isci_phy *iphy, + u8 flags) { struct isci_host *ihost = iport->owning_controller; - if (iphy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA) + if (iphy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA && (flags & PF_RESUME)) sci_phy_resume(iphy); iport->active_phy_mask |= 1 << iphy->phy_index; sci_controller_clear_invalid_phy(ihost, iphy); - if (do_notify_user == true) + if (flags & PF_NOTIFY) isci_port_link_up(ihost, iport, iphy); } @@ -669,14 +676,19 @@ void sci_port_deactivate_phy(struct isci_port *iport, struct isci_phy *iphy, struct isci_host *ihost = iport->owning_controller; iport->active_phy_mask &= ~(1 << iphy->phy_index); + iport->enabled_phy_mask &= ~(1 << iphy->phy_index); if (!iport->active_phy_mask) iport->last_active_phy = iphy->phy_index; iphy->max_negotiated_speed = SAS_LINK_RATE_UNKNOWN; - /* Re-assign the phy back to the LP as if it were a narrow port */ - writel(iphy->phy_index, - &iport->port_pe_configuration_register[iphy->phy_index]); + /* Re-assign the phy back to the LP as if it were a narrow port for APC + * mode. For MPC mode, the phy will remain in the port. + */ + if (iport->owning_controller->oem_parameters.controller.mode_type == + SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE) + writel(iphy->phy_index, + &iport->port_pe_configuration_register[iphy->phy_index]); if (do_notify_user == true) isci_port_link_down(ihost, iphy, iport); @@ -701,18 +713,16 @@ static void sci_port_invalid_link_up(struct isci_port *iport, struct isci_phy *i * sci_port_general_link_up_handler - phy can be assigned to port? * @sci_port: sci_port object for which has a phy that has gone link up. * @sci_phy: This is the struct isci_phy object that has gone link up. - * @do_notify_user: This parameter specifies whether to inform the user (via - * sci_port_link_up()) as to the fact that a new phy as become ready. + * @flags: PF_RESUME, PF_NOTIFY to sci_port_activate_phy * - * Determine if this phy can be assigned to this - * port . If the phy is not a valid PHY for - * this port then the function will notify the user. A PHY can only be - * part of a port if it's attached SAS ADDRESS is the same as all other PHYs in - * the same port. none + * Determine if this phy can be assigned to this port . If the phy is + * not a valid PHY for this port then the function will notify the user. + * A PHY can only be part of a port if it's attached SAS ADDRESS is the + * same as all other PHYs in the same port. */ static void sci_port_general_link_up_handler(struct isci_port *iport, - struct isci_phy *iphy, - bool do_notify_user) + struct isci_phy *iphy, + u8 flags) { struct sci_sas_address port_sas_address; struct sci_sas_address phy_sas_address; @@ -730,7 +740,7 @@ static void sci_port_general_link_up_handler(struct isci_port *iport, iport->active_phy_mask == 0) { struct sci_base_state_machine *sm = &iport->sm; - sci_port_activate_phy(iport, iphy, do_notify_user); + sci_port_activate_phy(iport, iphy, flags); if (sm->current_state_id == SCI_PORT_RESETTING) port_state_machine_change(iport, SCI_PORT_READY); } else @@ -781,11 +791,16 @@ bool sci_port_link_detected( struct isci_phy *iphy) { if ((iport->logical_port_index != SCIC_SDS_DUMMY_PORT) && - (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA) && - sci_port_is_wide(iport)) { - sci_port_invalid_link_up(iport, iphy); - - return false; + (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA)) { + if (sci_port_is_wide(iport)) { + sci_port_invalid_link_up(iport, iphy); + return false; + } else { + struct isci_host *ihost = iport->owning_controller; + struct isci_port *dst_port = &(ihost->ports[iphy->phy_index]); + writel(iphy->phy_index, + &dst_port->port_pe_configuration_register[iphy->phy_index]); + } } return true; @@ -975,6 +990,13 @@ static void sci_port_ready_substate_waiting_enter(struct sci_base_state_machine } } +static void scic_sds_port_ready_substate_waiting_exit( + struct sci_base_state_machine *sm) +{ + struct isci_port *iport = container_of(sm, typeof(*iport), sm); + sci_port_resume_port_task_scheduler(iport); +} + static void sci_port_ready_substate_operational_enter(struct sci_base_state_machine *sm) { u32 index; @@ -988,13 +1010,13 @@ static void sci_port_ready_substate_operational_enter(struct sci_base_state_mach writel(iport->physical_port_index, &iport->port_pe_configuration_register[ iport->phy_table[index]->phy_index]); + if (((iport->active_phy_mask^iport->enabled_phy_mask) & (1 << index)) != 0) + sci_port_resume_phy(iport, iport->phy_table[index]); } } sci_port_update_viit_entry(iport); - sci_port_resume_port_task_scheduler(iport); - /* * Post the dummy task for the port so the hardware can schedule * io correctly @@ -1061,20 +1083,9 @@ static void sci_port_ready_substate_configuring_enter(struct sci_base_state_mach if (iport->active_phy_mask == 0) { isci_port_not_ready(ihost, iport); - port_state_machine_change(iport, - SCI_PORT_SUB_WAITING); - } else if (iport->started_request_count == 0) - port_state_machine_change(iport, - SCI_PORT_SUB_OPERATIONAL); -} - -static void sci_port_ready_substate_configuring_exit(struct sci_base_state_machine *sm) -{ - struct isci_port *iport = container_of(sm, typeof(*iport), sm); - - sci_port_suspend_port_task_scheduler(iport); - if (iport->ready_exit) - sci_port_invalidate_dummy_remote_node(iport); + port_state_machine_change(iport, SCI_PORT_SUB_WAITING); + } else + port_state_machine_change(iport, SCI_PORT_SUB_OPERATIONAL); } enum sci_status sci_port_start(struct isci_port *iport) @@ -1252,7 +1263,7 @@ enum sci_status sci_port_add_phy(struct isci_port *iport, if (status != SCI_SUCCESS) return status; - sci_port_general_link_up_handler(iport, iphy, true); + sci_port_general_link_up_handler(iport, iphy, PF_NOTIFY|PF_RESUME); iport->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING; port_state_machine_change(iport, SCI_PORT_SUB_CONFIGURING); @@ -1262,7 +1273,7 @@ enum sci_status sci_port_add_phy(struct isci_port *iport, if (status != SCI_SUCCESS) return status; - sci_port_general_link_up_handler(iport, iphy, true); + sci_port_general_link_up_handler(iport, iphy, PF_NOTIFY); /* Re-enter the configuring state since this may be the last phy in * the port. @@ -1338,13 +1349,13 @@ enum sci_status sci_port_link_up(struct isci_port *iport, /* Since this is the first phy going link up for the port we * can just enable it and continue */ - sci_port_activate_phy(iport, iphy, true); + sci_port_activate_phy(iport, iphy, PF_NOTIFY|PF_RESUME); port_state_machine_change(iport, SCI_PORT_SUB_OPERATIONAL); return SCI_SUCCESS; case SCI_PORT_SUB_OPERATIONAL: - sci_port_general_link_up_handler(iport, iphy, true); + sci_port_general_link_up_handler(iport, iphy, PF_NOTIFY|PF_RESUME); return SCI_SUCCESS; case SCI_PORT_RESETTING: /* TODO We should make sure that the phy that has gone @@ -1361,7 +1372,7 @@ enum sci_status sci_port_link_up(struct isci_port *iport, /* In the resetting state we don't notify the user regarding * link up and link down notifications. */ - sci_port_general_link_up_handler(iport, iphy, false); + sci_port_general_link_up_handler(iport, iphy, PF_RESUME); return SCI_SUCCESS; default: dev_warn(sciport_to_dev(iport), @@ -1584,14 +1595,14 @@ static const struct sci_base_state sci_port_state_table[] = { }, [SCI_PORT_SUB_WAITING] = { .enter_state = sci_port_ready_substate_waiting_enter, + .exit_state = scic_sds_port_ready_substate_waiting_exit, }, [SCI_PORT_SUB_OPERATIONAL] = { .enter_state = sci_port_ready_substate_operational_enter, .exit_state = sci_port_ready_substate_operational_exit }, [SCI_PORT_SUB_CONFIGURING] = { - .enter_state = sci_port_ready_substate_configuring_enter, - .exit_state = sci_port_ready_substate_configuring_exit + .enter_state = sci_port_ready_substate_configuring_enter }, [SCI_PORT_RESETTING] = { .exit_state = sci_port_resetting_state_exit @@ -1609,6 +1620,7 @@ void sci_port_construct(struct isci_port *iport, u8 index, iport->logical_port_index = SCIC_SDS_DUMMY_PORT; iport->physical_port_index = index; iport->active_phy_mask = 0; + iport->enabled_phy_mask = 0; iport->last_active_phy = 0; iport->ready_exit = false; diff --git a/drivers/scsi/isci/port.h b/drivers/scsi/isci/port.h index cb5ffbc3860..08116090eb7 100644 --- a/drivers/scsi/isci/port.h +++ b/drivers/scsi/isci/port.h @@ -63,6 +63,9 @@ #define SCIC_SDS_DUMMY_PORT 0xFF +#define PF_NOTIFY (1 << 0) +#define PF_RESUME (1 << 1) + struct isci_phy; struct isci_host; @@ -83,6 +86,8 @@ enum isci_status { * @logical_port_index: software port index * @physical_port_index: hardware port index * @active_phy_mask: identifies phy members + * @enabled_phy_mask: phy mask for the port + * that are already part of the port * @reserved_tag: * @reserved_rni: reserver for port task scheduler workaround * @started_request_count: reference count for outstanding commands @@ -104,6 +109,7 @@ struct isci_port { u8 logical_port_index; u8 physical_port_index; u8 active_phy_mask; + u8 enabled_phy_mask; u8 last_active_phy; u16 reserved_rni; u16 reserved_tag; @@ -250,6 +256,10 @@ bool sci_port_link_detected( struct isci_port *iport, struct isci_phy *iphy); +enum sci_status sci_port_get_properties( + struct isci_port *iport, + struct sci_port_properties *prop); + enum sci_status sci_port_link_up(struct isci_port *iport, struct isci_phy *iphy); enum sci_status sci_port_link_down(struct isci_port *iport, diff --git a/drivers/scsi/isci/port_config.c b/drivers/scsi/isci/port_config.c index 38a99d28114..6d1e9544cbe 100644 --- a/drivers/scsi/isci/port_config.c +++ b/drivers/scsi/isci/port_config.c @@ -57,7 +57,7 @@ #define SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT (10) #define SCIC_SDS_APC_RECONFIGURATION_TIMEOUT (10) -#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION (100) +#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION (250) enum SCIC_SDS_APC_ACTIVITY { SCIC_SDS_APC_SKIP_PHY, @@ -466,6 +466,23 @@ sci_apc_agent_validate_phy_configuration(struct isci_host *ihost, return sci_port_configuration_agent_validate_ports(ihost, port_agent); } +/* + * This routine will restart the automatic port configuration timeout + * timer for the next time period. This could be caused by either a link + * down event or a link up event where we can not yet tell to which a phy + * belongs. + */ +static void sci_apc_agent_start_timer( + struct sci_port_configuration_agent *port_agent, + u32 timeout) +{ + if (port_agent->timer_pending) + sci_del_timer(&port_agent->timer); + + port_agent->timer_pending = true; + sci_mod_timer(&port_agent->timer, timeout); +} + static void sci_apc_agent_configure_ports(struct isci_host *ihost, struct sci_port_configuration_agent *port_agent, struct isci_phy *iphy, @@ -565,17 +582,8 @@ static void sci_apc_agent_configure_ports(struct isci_host *ihost, break; case SCIC_SDS_APC_START_TIMER: - /* - * This can occur for either a link down event, or a link - * up event where we cannot yet tell the port to which a - * phy belongs. - */ - if (port_agent->timer_pending) - sci_del_timer(&port_agent->timer); - - port_agent->timer_pending = true; - sci_mod_timer(&port_agent->timer, - SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION); + sci_apc_agent_start_timer(port_agent, + SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION); break; case SCIC_SDS_APC_SKIP_PHY: @@ -607,7 +615,8 @@ static void sci_apc_agent_link_up(struct isci_host *ihost, if (!iport) { /* the phy is not the part of this port */ port_agent->phy_ready_mask |= 1 << phy_index; - sci_apc_agent_configure_ports(ihost, port_agent, iphy, true); + sci_apc_agent_start_timer(port_agent, + SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION); } else { /* the phy is already the part of the port */ u32 port_state = iport->sm.current_state_id; diff --git a/drivers/scsi/isci/probe_roms.c b/drivers/scsi/isci/probe_roms.c index b5f4341de24..9b8117b9d75 100644 --- a/drivers/scsi/isci/probe_roms.c +++ b/drivers/scsi/isci/probe_roms.c @@ -147,7 +147,7 @@ struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmw memcpy(orom, fw->data, fw->size); - if (is_c0(pdev)) + if (is_c0(pdev) || is_c1(pdev)) goto out; /* diff --git a/drivers/scsi/isci/probe_roms.h b/drivers/scsi/isci/probe_roms.h index 2c75248ca32..bb0e9d4d97c 100644 --- a/drivers/scsi/isci/probe_roms.h +++ b/drivers/scsi/isci/probe_roms.h @@ -152,7 +152,7 @@ struct sci_user_parameters { #define MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT 4 struct sci_oem_params; -int sci_oem_parameters_validate(struct sci_oem_params *oem); +int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version); struct isci_orom; struct isci_orom *isci_request_oprom(struct pci_dev *pdev); @@ -191,6 +191,11 @@ struct isci_oem_hdr { 0x1a, 0x04, 0xc6) #define ISCI_EFI_VAR_NAME "RstScuO" +#define ISCI_ROM_VER_1_0 0x10 +#define ISCI_ROM_VER_1_1 0x11 +#define ISCI_ROM_VER_1_3 0x13 +#define ISCI_ROM_VER_LATEST ISCI_ROM_VER_1_3 + /* Allowed PORT configuration modes APC Automatic PORT configuration mode is * defined by the OEM configuration parameters providing no PHY_MASK parameters * for any PORT. i.e. There are no phys assigned to any of the ports at start. @@ -220,8 +225,86 @@ struct sci_oem_params { struct { uint8_t mode_type; uint8_t max_concurr_spin_up; - uint8_t do_enable_ssc; - uint8_t reserved; + /* + * This bitfield indicates the OEM's desired default Tx + * Spread Spectrum Clocking (SSC) settings for SATA and SAS. + * NOTE: Default SSC Modulation Frequency is 31.5KHz. + */ + union { + struct { + /* + * NOTE: Max spread for SATA is +0 / -5000 PPM. + * Down-spreading SSC (only method allowed for SATA): + * SATA SSC Tx Disabled = 0x0 + * SATA SSC Tx at +0 / -1419 PPM Spread = 0x2 + * SATA SSC Tx at +0 / -2129 PPM Spread = 0x3 + * SATA SSC Tx at +0 / -4257 PPM Spread = 0x6 + * SATA SSC Tx at +0 / -4967 PPM Spread = 0x7 + */ + uint8_t ssc_sata_tx_spread_level:4; + /* + * SAS SSC Tx Disabled = 0x0 + * + * NOTE: Max spread for SAS down-spreading +0 / + * -2300 PPM + * Down-spreading SSC: + * SAS SSC Tx at +0 / -1419 PPM Spread = 0x2 + * SAS SSC Tx at +0 / -2129 PPM Spread = 0x3 + * + * NOTE: Max spread for SAS center-spreading +2300 / + * -2300 PPM + * Center-spreading SSC: + * SAS SSC Tx at +1064 / -1064 PPM Spread = 0x3 + * SAS SSC Tx at +2129 / -2129 PPM Spread = 0x6 + */ + uint8_t ssc_sas_tx_spread_level:3; + /* + * NOTE: Refer to the SSC section of the SAS 2.x + * Specification for proper setting of this field. + * For standard SAS Initiator SAS PHY operation it + * should be 0 for Down-spreading. + * SAS SSC Tx spread type: + * Down-spreading SSC = 0 + * Center-spreading SSC = 1 + */ + uint8_t ssc_sas_tx_type:1; + }; + uint8_t do_enable_ssc; + }; + /* + * This field indicates length of the SAS/SATA cable between + * host and device. + * This field is used make relationship between analog + * parameters of the phy in the silicon and length of the cable. + * Supported cable attenuation levels: + * "short"- up to 3m, "medium"-3m to 6m, and "long"- more than + * 6m. + * + * This is bit mask field: + * + * BIT: (MSB) 7 6 5 4 + * ASSIGNMENT: <phy3><phy2><phy1><phy0> - Medium cable + * length assignment + * BIT: 3 2 1 0 (LSB) + * ASSIGNMENT: <phy3><phy2><phy1><phy0> - Long cable length + * assignment + * + * BITS 7-4 are set when the cable length is assigned to medium + * BITS 3-0 are set when the cable length is assigned to long + * + * The BIT positions are clear when the cable length is + * assigned to short. + * + * Setting the bits for both long and medium cable length is + * undefined. + * + * A value of 0x84 would assign + * phy3 - medium + * phy2 - long + * phy1 - short + * phy0 - short + */ + uint8_t cable_selection_mask; } controller; struct { diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c index b207cd3b15a..dd74b6ceeb8 100644 --- a/drivers/scsi/isci/remote_device.c +++ b/drivers/scsi/isci/remote_device.c @@ -53,6 +53,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <scsi/sas.h> +#include <linux/bitops.h> #include "isci.h" #include "port.h" #include "remote_device.h" @@ -1101,6 +1102,7 @@ static enum sci_status sci_remote_device_da_construct(struct isci_port *iport, struct isci_remote_device *idev) { enum sci_status status; + struct sci_port_properties properties; struct domain_device *dev = idev->domain_dev; sci_remote_device_construct(iport, idev); @@ -1110,6 +1112,11 @@ static enum sci_status sci_remote_device_da_construct(struct isci_port *iport, * entries will be needed to store the remote node. */ idev->is_direct_attached = true; + + sci_port_get_properties(iport, &properties); + /* Get accurate port width from port's phy mask for a DA device. */ + idev->device_port_width = hweight32(properties.phy_mask); + status = sci_controller_allocate_remote_node_context(iport->owning_controller, idev, &idev->rnc.remote_node_index); @@ -1125,9 +1132,6 @@ static enum sci_status sci_remote_device_da_construct(struct isci_port *iport, idev->connection_rate = sci_port_get_max_allowed_speed(iport); - /* / @todo Should I assign the port width by reading all of the phys on the port? */ - idev->device_port_width = 1; - return SCI_SUCCESS; } diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 66ad3dc8949..f5a3f7d2bda 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -496,7 +496,7 @@ static int isci_task_execute_tmf(struct isci_host *ihost, } } - isci_print_tmf(tmf); + isci_print_tmf(ihost, tmf); if (tmf->status == SCI_SUCCESS) ret = TMF_RESP_FUNC_COMPLETE; diff --git a/drivers/scsi/isci/task.h b/drivers/scsi/isci/task.h index bc78c0a41d5..1b27b3797c6 100644 --- a/drivers/scsi/isci/task.h +++ b/drivers/scsi/isci/task.h @@ -106,7 +106,6 @@ struct isci_tmf { } resp; unsigned char lun[8]; u16 io_tag; - struct isci_remote_device *device; enum isci_tmf_function_codes tmf_code; int status; @@ -120,10 +119,10 @@ struct isci_tmf { }; -static inline void isci_print_tmf(struct isci_tmf *tmf) +static inline void isci_print_tmf(struct isci_host *ihost, struct isci_tmf *tmf) { if (SAS_PROTOCOL_SATA == tmf->proto) - dev_dbg(&tmf->device->isci_port->isci_host->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: status = %x\n" "tmf->resp.d2h_fis.status = %x\n" "tmf->resp.d2h_fis.error = %x\n", @@ -132,7 +131,7 @@ static inline void isci_print_tmf(struct isci_tmf *tmf) tmf->resp.d2h_fis.status, tmf->resp.d2h_fis.error); else - dev_dbg(&tmf->device->isci_port->isci_host->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: status = %x\n" "tmf->resp.resp_iu.data_present = %x\n" "tmf->resp.resp_iu.status = %x\n" diff --git a/drivers/scsi/iscsi_boot_sysfs.c b/drivers/scsi/iscsi_boot_sysfs.c index 89700cbca16..14c1c8f6a95 100644 --- a/drivers/scsi/iscsi_boot_sysfs.c +++ b/drivers/scsi/iscsi_boot_sysfs.c @@ -112,7 +112,7 @@ static struct attribute *target_attrs[] = { NULL }; -static mode_t iscsi_boot_tgt_attr_is_visible(struct kobject *kobj, +static umode_t iscsi_boot_tgt_attr_is_visible(struct kobject *kobj, struct attribute *attr, int i) { struct iscsi_boot_kobj *boot_kobj = @@ -193,7 +193,7 @@ static struct attribute *ethernet_attrs[] = { NULL }; -static mode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj, +static umode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj, struct attribute *attr, int i) { struct iscsi_boot_kobj *boot_kobj = @@ -265,7 +265,7 @@ static struct attribute *initiator_attrs[] = { NULL }; -static mode_t iscsi_boot_ini_attr_is_visible(struct kobject *kobj, +static umode_t iscsi_boot_ini_attr_is_visible(struct kobject *kobj, struct attribute *attr, int i) { struct iscsi_boot_kobj *boot_kobj = @@ -306,7 +306,7 @@ iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, struct attribute_group *attr_group, const char *name, int index, void *data, ssize_t (*show) (void *data, int type, char *buf), - mode_t (*is_visible) (void *data, int type), + umode_t (*is_visible) (void *data, int type), void (*release) (void *data)) { struct iscsi_boot_kobj *boot_kobj; @@ -369,7 +369,7 @@ struct iscsi_boot_kobj * iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show) (void *data, int type, char *buf), - mode_t (*is_visible) (void *data, int type), + umode_t (*is_visible) (void *data, int type), void (*release) (void *data)) { return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group, @@ -394,7 +394,7 @@ struct iscsi_boot_kobj * iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show) (void *data, int type, char *buf), - mode_t (*is_visible) (void *data, int type), + umode_t (*is_visible) (void *data, int type), void (*release) (void *data)) { return iscsi_boot_create_kobj(boot_kset, @@ -420,7 +420,7 @@ struct iscsi_boot_kobj * iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show) (void *data, int type, char *buf), - mode_t (*is_visible) (void *data, int type), + umode_t (*is_visible) (void *data, int type), void (*release) (void *data)) { return iscsi_boot_create_kobj(boot_kset, diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 7c34d8e7cc7..db47158e0dd 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -873,7 +873,7 @@ static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session) iscsi_host_free(shost); } -static mode_t iscsi_sw_tcp_attr_is_visible(int param_type, int param) +static umode_t iscsi_sw_tcp_attr_is_visible(int param_type, int param) { switch (param_type) { case ISCSI_HOST_PARAM: diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c index 08e26d4e373..27cfb0cb186 100644 --- a/drivers/scsi/jazz_esp.c +++ b/drivers/scsi/jazz_esp.c @@ -1,6 +1,6 @@ /* jazz_esp.c: ESP front-end for MIPS JAZZ systems. * - * Copyright (C) 2007 Thomas Bogendörfer (tsbogend@alpha.frankende) + * Copyright (C) 2007 Thomas Bogendörfer (tsbogend@alpha.frankende) */ #include <linux/kernel.h> diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 7269e928824..1d1b0c9da29 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -61,7 +61,7 @@ static void fc_disc_restart(struct fc_disc *); * Locking Note: This function expects that the lport mutex is locked before * calling it. */ -void fc_disc_stop_rports(struct fc_disc *disc) +static void fc_disc_stop_rports(struct fc_disc *disc) { struct fc_lport *lport; struct fc_rport_priv *rdata; @@ -682,7 +682,7 @@ static int fc_disc_single(struct fc_lport *lport, struct fc_disc_port *dp) * fc_disc_stop() - Stop discovery for a given lport * @lport: The local port that discovery should stop on */ -void fc_disc_stop(struct fc_lport *lport) +static void fc_disc_stop(struct fc_lport *lport) { struct fc_disc *disc = &lport->disc; @@ -698,7 +698,7 @@ void fc_disc_stop(struct fc_lport *lport) * This function will block until discovery has been * completely stopped and all rports have been deleted. */ -void fc_disc_stop_final(struct fc_lport *lport) +static void fc_disc_stop_final(struct fc_lport *lport) { fc_disc_stop(lport); lport->tt.rport_flush_queue(); diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c index fb9161dc4ca..e17a28d324d 100644 --- a/drivers/scsi/libfc/fc_elsct.c +++ b/drivers/scsi/libfc/fc_elsct.c @@ -28,6 +28,7 @@ #include <scsi/fc/fc_els.h> #include <scsi/libfc.h> #include <scsi/fc_encode.h> +#include "fc_libfc.h" /** * fc_elsct_send() - Send an ELS or CT frame diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 9de9db27e87..4d70d96fa5d 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -91,7 +91,7 @@ struct fc_exch_pool { * It manages the allocation of exchange IDs. */ struct fc_exch_mgr { - struct fc_exch_pool *pool; + struct fc_exch_pool __percpu *pool; mempool_t *ep_pool; enum fc_class class; struct kref kref; diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 221875ec3d7..f607314810a 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -155,6 +155,7 @@ static struct fc_fcp_pkt *fc_fcp_pkt_alloc(struct fc_lport *lport, gfp_t gfp) fsp->xfer_ddp = FC_XID_UNKNOWN; atomic_set(&fsp->ref_cnt, 1); init_timer(&fsp->timer); + fsp->timer.data = (unsigned long)fsp; INIT_LIST_HEAD(&fsp->list); spin_lock_init(&fsp->scsi_pkt_lock); } @@ -1850,9 +1851,6 @@ int fc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc_cmd) } put_cpu(); - init_timer(&fsp->timer); - fsp->timer.data = (unsigned long)fsp; - /* * send it to the lower layer * if we get -1 return then put the request in the pending diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index e77094a587e..83750ebb527 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -677,7 +677,8 @@ EXPORT_SYMBOL(fc_set_mfs); * @lport: The local port receiving the event * @event: The discovery event */ -void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event) +static void fc_lport_disc_callback(struct fc_lport *lport, + enum fc_disc_event event) { switch (event) { case DISC_EV_SUCCESS: @@ -1568,7 +1569,7 @@ EXPORT_SYMBOL(fc_lport_flogi_resp); * Locking Note: The lport lock is expected to be held before calling * this routine. */ -void fc_lport_enter_flogi(struct fc_lport *lport) +static void fc_lport_enter_flogi(struct fc_lport *lport) { struct fc_frame *fp; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index b9e434844a6..83aa1efec87 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -391,7 +391,7 @@ static void fc_rport_work(struct work_struct *work) * If it appears we are already logged in, ADISC is used to verify * the setup. */ -int fc_rport_login(struct fc_rport_priv *rdata) +static int fc_rport_login(struct fc_rport_priv *rdata) { mutex_lock(&rdata->rp_mutex); @@ -451,7 +451,7 @@ static void fc_rport_enter_delete(struct fc_rport_priv *rdata, * function will hold the rport lock, call an _enter_* * function and then unlock the rport. */ -int fc_rport_logoff(struct fc_rport_priv *rdata) +static int fc_rport_logoff(struct fc_rport_priv *rdata) { mutex_lock(&rdata->rp_mutex); @@ -653,8 +653,8 @@ static int fc_rport_login_complete(struct fc_rport_priv *rdata, * @fp: The FLOGI response frame * @rp_arg: The remote port that received the FLOGI response */ -void fc_rport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, - void *rp_arg) +static void fc_rport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, + void *rp_arg) { struct fc_rport_priv *rdata = rp_arg; struct fc_lport *lport = rdata->local_port; @@ -1520,7 +1520,7 @@ reject: * * Locking Note: Called with the lport lock held. */ -void fc_rport_recv_req(struct fc_lport *lport, struct fc_frame *fp) +static void fc_rport_recv_req(struct fc_lport *lport, struct fc_frame *fp) { struct fc_seq_els_data els_data; diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index bb4c8e0584e..825f9307417 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -247,18 +247,6 @@ struct lpfc_stats { uint32_t fcpLocalErr; }; -enum sysfs_mbox_state { - SMBOX_IDLE, - SMBOX_WRITING, - SMBOX_READING -}; - -struct lpfc_sysfs_mbox { - enum sysfs_mbox_state state; - size_t offset; - struct lpfcMboxq * mbox; -}; - struct lpfc_hba; @@ -783,8 +771,6 @@ struct lpfc_hba { uint64_t bg_apptag_err_cnt; uint64_t bg_reftag_err_cnt; - struct lpfc_sysfs_mbox sysfs_mbox; - /* fastpath list. */ spinlock_t scsi_buf_list_lock; struct list_head lpfc_scsi_buf_list; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index d0ebaeb7ef6..f6697cb0e21 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -351,10 +351,23 @@ lpfc_fwrev_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; + uint32_t if_type; + uint8_t sli_family; char fwrev[32]; + int len; lpfc_decode_firmware_rev(phba, fwrev, 1); - return snprintf(buf, PAGE_SIZE, "%s, sli-%d\n", fwrev, phba->sli_rev); + if_type = phba->sli4_hba.pc_sli4_params.if_type; + sli_family = phba->sli4_hba.pc_sli4_params.sli_family; + + if (phba->sli_rev < LPFC_SLI_REV4) + len = snprintf(buf, PAGE_SIZE, "%s, sli-%d\n", + fwrev, phba->sli_rev); + else + len = snprintf(buf, PAGE_SIZE, "%s, sli-%d:%d:%x\n", + fwrev, phba->sli_rev, if_type, sli_family); + + return len; } /** @@ -488,6 +501,34 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr, } /** + * lpfc_sli4_protocol_show - Return the fip mode of the HBA + * @dev: class unused variable. + * @attr: device attribute, not used. + * @buf: on return contains the module description text. + * + * Returns: size of formatted string. + **/ +static ssize_t +lpfc_sli4_protocol_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + + if (phba->sli_rev < LPFC_SLI_REV4) + return snprintf(buf, PAGE_SIZE, "fc\n"); + + if (phba->sli4_hba.lnk_info.lnk_dv == LPFC_LNK_DAT_VAL) { + if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_GE) + return snprintf(buf, PAGE_SIZE, "fcoe\n"); + if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) + return snprintf(buf, PAGE_SIZE, "fc\n"); + } + return snprintf(buf, PAGE_SIZE, "unknown\n"); +} + +/** * lpfc_link_state_store - Transition the link_state on an HBA port * @dev: class device that is converted into a Scsi_host. * @attr: device attribute, not used. @@ -773,7 +814,12 @@ lpfc_issue_reset(struct device *dev, struct device_attribute *attr, * the readyness after performing a firmware reset. * * Returns: - * zero for success + * zero for success, -EPERM when port does not have privilage to perform the + * reset, -EIO when port timeout from recovering from the reset. + * + * Note: + * As the caller will interpret the return code by value, be careful in making + * change or addition to return codes. **/ int lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba) @@ -826,9 +872,11 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode) { struct completion online_compl; struct pci_dev *pdev = phba->pcidev; + uint32_t before_fc_flag; + uint32_t sriov_nr_virtfn; uint32_t reg_val; - int status = 0; - int rc; + int status = 0, rc = 0; + int job_posted = 1, sriov_err; if (!phba->cfg_enable_hba_reset) return -EACCES; @@ -838,6 +886,10 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode) LPFC_SLI_INTF_IF_TYPE_2)) return -EPERM; + /* Keep state if we need to restore back */ + before_fc_flag = phba->pport->fc_flag; + sriov_nr_virtfn = phba->cfg_sriov_nr_virtfn; + /* Disable SR-IOV virtual functions if enabled */ if (phba->cfg_sriov_nr_virtfn) { pci_disable_sriov(pdev); @@ -869,21 +921,44 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode) /* delay driver action following IF_TYPE_2 reset */ rc = lpfc_sli4_pdev_status_reg_wait(phba); - if (rc) + if (rc == -EPERM) { + /* no privilage for reset, restore if needed */ + if (before_fc_flag & FC_OFFLINE_MODE) + goto out; + } else if (rc == -EIO) { + /* reset failed, there is nothing more we can do */ return rc; + } + + /* keep the original port state */ + if (before_fc_flag & FC_OFFLINE_MODE) + goto out; init_completion(&online_compl); - rc = lpfc_workq_post_event(phba, &status, &online_compl, - LPFC_EVT_ONLINE); - if (rc == 0) - return -ENOMEM; + job_posted = lpfc_workq_post_event(phba, &status, &online_compl, + LPFC_EVT_ONLINE); + if (!job_posted) + goto out; wait_for_completion(&online_compl); - if (status != 0) - return -EIO; +out: + /* in any case, restore the virtual functions enabled as before */ + if (sriov_nr_virtfn) { + sriov_err = + lpfc_sli_probe_sriov_nr_virtfn(phba, sriov_nr_virtfn); + if (!sriov_err) + phba->cfg_sriov_nr_virtfn = sriov_nr_virtfn; + } - return 0; + /* return proper error code */ + if (!rc) { + if (!job_posted) + rc = -ENOMEM; + else if (status) + rc = -EIO; + } + return rc; } /** @@ -955,33 +1030,38 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; struct completion online_compl; - int status=0; + char *board_mode_str = NULL; + int status = 0; int rc; - if (!phba->cfg_enable_hba_reset) - return -EACCES; + if (!phba->cfg_enable_hba_reset) { + status = -EACCES; + goto board_mode_out; + } lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "3050 lpfc_board_mode set to %s\n", buf); + "3050 lpfc_board_mode set to %s\n", buf); init_completion(&online_compl); if(strncmp(buf, "online", sizeof("online") - 1) == 0) { rc = lpfc_workq_post_event(phba, &status, &online_compl, LPFC_EVT_ONLINE); - if (rc == 0) - return -ENOMEM; + if (rc == 0) { + status = -ENOMEM; + goto board_mode_out; + } wait_for_completion(&online_compl); } else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0) status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0) if (phba->sli_rev == LPFC_SLI_REV4) - return -EINVAL; + status = -EINVAL; else status = lpfc_do_offline(phba, LPFC_EVT_WARM_START); else if (strncmp(buf, "error", sizeof("error") - 1) == 0) if (phba->sli_rev == LPFC_SLI_REV4) - return -EINVAL; + status = -EINVAL; else status = lpfc_do_offline(phba, LPFC_EVT_KILL); else if (strncmp(buf, "dump", sizeof("dump") - 1) == 0) @@ -991,12 +1071,21 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr, else if (strncmp(buf, "dv_reset", sizeof("dv_reset") - 1) == 0) status = lpfc_sli4_pdev_reg_request(phba, LPFC_DV_RESET); else - return -EINVAL; + status = -EINVAL; +board_mode_out: if (!status) return strlen(buf); - else + else { + board_mode_str = strchr(buf, '\n'); + if (board_mode_str) + *board_mode_str = '\0'; + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "3097 Failed \"%s\", status(%d), " + "fc_flag(x%x)\n", + buf, status, phba->pport->fc_flag); return status; + } } /** @@ -1942,6 +2031,7 @@ static DEVICE_ATTR(lpfc_fips_rev, S_IRUGO, lpfc_fips_rev_show, NULL); static DEVICE_ATTR(lpfc_dss, S_IRUGO, lpfc_dss_show, NULL); static DEVICE_ATTR(lpfc_sriov_hw_max_virtfn, S_IRUGO, lpfc_sriov_hw_max_virtfn_show, NULL); +static DEVICE_ATTR(protocol, S_IRUGO, lpfc_sli4_protocol_show, NULL); static char *lpfc_soft_wwn_key = "C99G71SL8032A"; @@ -2687,6 +2777,14 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr, if (val >= 0 && val <= 6) { prev_val = phba->cfg_topology; phba->cfg_topology = val; + if (phba->cfg_link_speed == LPFC_USER_LINK_SPEED_16G && + val == 4) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "3113 Loop mode not supported at speed %d\n", + phba->cfg_link_speed); + phba->cfg_topology = prev_val; + return -EINVAL; + } if (nolip) return strlen(buf); @@ -3132,6 +3230,14 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr, val); return -EINVAL; } + if (val == LPFC_USER_LINK_SPEED_16G && + phba->fc_topology == LPFC_TOPOLOGY_LOOP) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3112 lpfc_link_speed attribute cannot be set " + "to %d. Speed is not supported in loop mode.\n", + val); + return -EINVAL; + } if ((val >= 0) && (val <= LPFC_USER_LINK_SPEED_MAX) && (LPFC_USER_LINK_SPEED_BITMAP & (1 << val))) { prev_val = phba->cfg_link_speed; @@ -3176,6 +3282,13 @@ lpfc_param_show(link_speed) static int lpfc_link_speed_init(struct lpfc_hba *phba, int val) { + if (val == LPFC_USER_LINK_SPEED_16G && phba->cfg_topology == 4) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3111 lpfc_link_speed of %d cannot " + "support loop mode, setting topology to default.\n", + val); + phba->cfg_topology = 0; + } if ((val >= 0) && (val <= LPFC_USER_LINK_SPEED_MAX) && (LPFC_USER_LINK_SPEED_BITMAP & (1 << val))) { phba->cfg_link_speed = val; @@ -3830,6 +3943,7 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_fips_rev, &dev_attr_lpfc_dss, &dev_attr_lpfc_sriov_hw_max_virtfn, + &dev_attr_protocol, NULL, }; @@ -3988,23 +4102,6 @@ static struct bin_attribute sysfs_ctlreg_attr = { }; /** - * sysfs_mbox_idle - frees the sysfs mailbox - * @phba: lpfc_hba pointer - **/ -static void -sysfs_mbox_idle(struct lpfc_hba *phba) -{ - phba->sysfs_mbox.state = SMBOX_IDLE; - phba->sysfs_mbox.offset = 0; - - if (phba->sysfs_mbox.mbox) { - mempool_free(phba->sysfs_mbox.mbox, - phba->mbox_mem_pool); - phba->sysfs_mbox.mbox = NULL; - } -} - -/** * sysfs_mbox_write - Write method for writing information via mbox * @filp: open sysfs file * @kobj: kernel kobject that contains the kernel class device. @@ -4014,71 +4111,18 @@ sysfs_mbox_idle(struct lpfc_hba *phba) * @count: bytes to transfer. * * Description: - * Accessed via /sys/class/scsi_host/hostxxx/mbox. - * Uses the sysfs mbox to send buf contents to the adapter. + * Deprecated function. All mailbox access from user space is performed via the + * bsg interface. * * Returns: - * -ERANGE off and count combo out of range - * -EINVAL off, count or buff address invalid - * zero if count is zero - * -EPERM adapter is offline - * -ENOMEM failed to allocate memory for the mail box - * -EAGAIN offset, state or mbox is NULL - * count number of bytes transferred + * -EPERM operation not permitted **/ static ssize_t sysfs_mbox_write(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - struct device *dev = container_of(kobj, struct device, kobj); - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct lpfcMboxq *mbox = NULL; - - if ((count + off) > MAILBOX_CMD_SIZE) - return -ERANGE; - - if (off % 4 || count % 4 || (unsigned long)buf % 4) - return -EINVAL; - - if (count == 0) - return 0; - - if (off == 0) { - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - memset(mbox, 0, sizeof (LPFC_MBOXQ_t)); - } - - spin_lock_irq(&phba->hbalock); - - if (off == 0) { - if (phba->sysfs_mbox.mbox) - mempool_free(mbox, phba->mbox_mem_pool); - else - phba->sysfs_mbox.mbox = mbox; - phba->sysfs_mbox.state = SMBOX_WRITING; - } else { - if (phba->sysfs_mbox.state != SMBOX_WRITING || - phba->sysfs_mbox.offset != off || - phba->sysfs_mbox.mbox == NULL) { - sysfs_mbox_idle(phba); - spin_unlock_irq(&phba->hbalock); - return -EAGAIN; - } - } - - memcpy((uint8_t *) &phba->sysfs_mbox.mbox->u.mb + off, - buf, count); - - phba->sysfs_mbox.offset = off + count; - - spin_unlock_irq(&phba->hbalock); - - return count; + return -EPERM; } /** @@ -4091,201 +4135,18 @@ sysfs_mbox_write(struct file *filp, struct kobject *kobj, * @count: bytes to transfer. * * Description: - * Accessed via /sys/class/scsi_host/hostxxx/mbox. - * Uses the sysfs mbox to receive data from to the adapter. + * Deprecated function. All mailbox access from user space is performed via the + * bsg interface. * * Returns: - * -ERANGE off greater than mailbox command size - * -EINVAL off, count or buff address invalid - * zero if off and count are zero - * -EACCES adapter over temp - * -EPERM garbage can value to catch a multitude of errors - * -EAGAIN management IO not permitted, state or off error - * -ETIME mailbox timeout - * -ENODEV mailbox error - * count number of bytes transferred + * -EPERM operation not permitted **/ static ssize_t sysfs_mbox_read(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - struct device *dev = container_of(kobj, struct device, kobj); - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - LPFC_MBOXQ_t *mboxq; - MAILBOX_t *pmb; - uint32_t mbox_tmo; - int rc; - - if (off > MAILBOX_CMD_SIZE) - return -ERANGE; - - if ((count + off) > MAILBOX_CMD_SIZE) - count = MAILBOX_CMD_SIZE - off; - - if (off % 4 || count % 4 || (unsigned long)buf % 4) - return -EINVAL; - - if (off && count == 0) - return 0; - - spin_lock_irq(&phba->hbalock); - - if (phba->over_temp_state == HBA_OVER_TEMP) { - sysfs_mbox_idle(phba); - spin_unlock_irq(&phba->hbalock); - return -EACCES; - } - - if (off == 0 && - phba->sysfs_mbox.state == SMBOX_WRITING && - phba->sysfs_mbox.offset >= 2 * sizeof(uint32_t)) { - mboxq = (LPFC_MBOXQ_t *)&phba->sysfs_mbox.mbox; - pmb = &mboxq->u.mb; - switch (pmb->mbxCommand) { - /* Offline only */ - case MBX_INIT_LINK: - case MBX_DOWN_LINK: - case MBX_CONFIG_LINK: - case MBX_CONFIG_RING: - case MBX_RESET_RING: - case MBX_UNREG_LOGIN: - case MBX_CLEAR_LA: - case MBX_DUMP_CONTEXT: - case MBX_RUN_DIAGS: - case MBX_RESTART: - case MBX_SET_MASK: - case MBX_SET_DEBUG: - if (!(vport->fc_flag & FC_OFFLINE_MODE)) { - printk(KERN_WARNING "mbox_read:Command 0x%x " - "is illegal in on-line state\n", - pmb->mbxCommand); - sysfs_mbox_idle(phba); - spin_unlock_irq(&phba->hbalock); - return -EPERM; - } - case MBX_WRITE_NV: - case MBX_WRITE_VPARMS: - case MBX_LOAD_SM: - case MBX_READ_NV: - case MBX_READ_CONFIG: - case MBX_READ_RCONFIG: - case MBX_READ_STATUS: - case MBX_READ_XRI: - case MBX_READ_REV: - case MBX_READ_LNK_STAT: - case MBX_DUMP_MEMORY: - case MBX_DOWN_LOAD: - case MBX_UPDATE_CFG: - case MBX_KILL_BOARD: - case MBX_LOAD_AREA: - case MBX_LOAD_EXP_ROM: - case MBX_BEACON: - case MBX_DEL_LD_ENTRY: - case MBX_SET_VARIABLE: - case MBX_WRITE_WWN: - case MBX_PORT_CAPABILITIES: - case MBX_PORT_IOV_CONTROL: - break; - case MBX_SECURITY_MGMT: - case MBX_AUTH_PORT: - if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) { - printk(KERN_WARNING "mbox_read:Command 0x%x " - "is not permitted\n", pmb->mbxCommand); - sysfs_mbox_idle(phba); - spin_unlock_irq(&phba->hbalock); - return -EPERM; - } - break; - case MBX_READ_SPARM64: - case MBX_READ_TOPOLOGY: - case MBX_REG_LOGIN: - case MBX_REG_LOGIN64: - case MBX_CONFIG_PORT: - case MBX_RUN_BIU_DIAG: - printk(KERN_WARNING "mbox_read: Illegal Command 0x%x\n", - pmb->mbxCommand); - sysfs_mbox_idle(phba); - spin_unlock_irq(&phba->hbalock); - return -EPERM; - default: - printk(KERN_WARNING "mbox_read: Unknown Command 0x%x\n", - pmb->mbxCommand); - sysfs_mbox_idle(phba); - spin_unlock_irq(&phba->hbalock); - return -EPERM; - } - - /* If HBA encountered an error attention, allow only DUMP - * or RESTART mailbox commands until the HBA is restarted. - */ - if (phba->pport->stopped && - pmb->mbxCommand != MBX_DUMP_MEMORY && - pmb->mbxCommand != MBX_RESTART && - pmb->mbxCommand != MBX_WRITE_VPARMS && - pmb->mbxCommand != MBX_WRITE_WWN) - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, - "1259 mbox: Issued mailbox cmd " - "0x%x while in stopped state.\n", - pmb->mbxCommand); - - phba->sysfs_mbox.mbox->vport = vport; - - /* Don't allow mailbox commands to be sent when blocked - * or when in the middle of discovery - */ - if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { - sysfs_mbox_idle(phba); - spin_unlock_irq(&phba->hbalock); - return -EAGAIN; - } - - if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { - - spin_unlock_irq(&phba->hbalock); - rc = lpfc_sli_issue_mbox (phba, - phba->sysfs_mbox.mbox, - MBX_POLL); - spin_lock_irq(&phba->hbalock); - - } else { - spin_unlock_irq(&phba->hbalock); - mbox_tmo = lpfc_mbox_tmo_val(phba, mboxq); - rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo); - spin_lock_irq(&phba->hbalock); - } - - if (rc != MBX_SUCCESS) { - if (rc == MBX_TIMEOUT) { - phba->sysfs_mbox.mbox = NULL; - } - sysfs_mbox_idle(phba); - spin_unlock_irq(&phba->hbalock); - return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; - } - phba->sysfs_mbox.state = SMBOX_READING; - } - else if (phba->sysfs_mbox.offset != off || - phba->sysfs_mbox.state != SMBOX_READING) { - printk(KERN_WARNING "mbox_read: Bad State\n"); - sysfs_mbox_idle(phba); - spin_unlock_irq(&phba->hbalock); - return -EAGAIN; - } - - memcpy(buf, (uint8_t *) &pmb + off, count); - - phba->sysfs_mbox.offset = off + count; - - if (phba->sysfs_mbox.offset == MAILBOX_CMD_SIZE) - sysfs_mbox_idle(phba); - - spin_unlock_irq(&phba->hbalock); - - return count; + return -EPERM; } static struct bin_attribute sysfs_mbox_attr = { @@ -4429,8 +4290,13 @@ lpfc_get_host_port_state(struct Scsi_Host *shost) case LPFC_LINK_UP: case LPFC_CLEAR_LA: case LPFC_HBA_READY: - /* Links up, beyond this port_type reports state */ - fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; + /* Links up, reports port state accordingly */ + if (vport->port_state < LPFC_VPORT_READY) + fc_host_port_state(shost) = + FC_PORTSTATE_BYPASSED; + else + fc_host_port_state(shost) = + FC_PORTSTATE_ONLINE; break; case LPFC_HBA_ERROR: fc_host_port_state(shost) = FC_PORTSTATE_ERROR; diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 6760c69f525..56a86baece5 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -916,9 +916,11 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } else { switch (cmd) { case ELX_LOOPBACK_DATA: - diag_cmd_data_free(phba, - (struct lpfc_dmabufext *) - dmabuf); + if (phba->sli_rev < + LPFC_SLI_REV4) + diag_cmd_data_free(phba, + (struct lpfc_dmabufext + *)dmabuf); break; case ELX_LOOPBACK_XRI_SETUP: if ((phba->sli_rev == @@ -1000,7 +1002,8 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, error_ct_unsol_exit: if (!list_empty(&head)) list_del(&head); - if (evt_req_id == SLI_CT_ELX_LOOPBACK) + if ((phba->sli_rev < LPFC_SLI_REV4) && + (evt_req_id == SLI_CT_ELX_LOOPBACK)) return 0; return 1; } @@ -1566,7 +1569,7 @@ lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job) struct diag_mode_set *loopback_mode; uint32_t link_flags; uint32_t timeout; - LPFC_MBOXQ_t *pmboxq; + LPFC_MBOXQ_t *pmboxq = NULL; int mbxstatus = MBX_SUCCESS; int i = 0; int rc = 0; @@ -1615,7 +1618,6 @@ lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job) rc = -ETIMEDOUT; goto loopback_mode_exit; } - msleep(10); } @@ -1635,7 +1637,9 @@ lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job) if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) rc = -ENODEV; else { + spin_lock_irq(&phba->hbalock); phba->link_flag |= LS_LOOPBACK_MODE; + spin_unlock_irq(&phba->hbalock); /* wait for the link attention interrupt */ msleep(100); @@ -1659,7 +1663,7 @@ loopback_mode_exit: /* * Let SLI layer release mboxq if mbox command completed after timeout. */ - if (mbxstatus != MBX_TIMEOUT) + if (pmboxq && mbxstatus != MBX_TIMEOUT) mempool_free(pmboxq, phba->mbox_mem_pool); job_error: @@ -1700,11 +1704,16 @@ lpfc_sli4_bsg_set_link_diag_state(struct lpfc_hba *phba, uint32_t diag) rc = -ENOMEM; goto link_diag_state_set_out; } + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, + "3128 Set link to diagnostic state:x%x (x%x/x%x)\n", + diag, phba->sli4_hba.lnk_info.lnk_tp, + phba->sli4_hba.lnk_info.lnk_no); + link_diag_state = &pmboxq->u.mqe.un.link_diag_state; bf_set(lpfc_mbx_set_diag_state_link_num, &link_diag_state->u.req, - phba->sli4_hba.link_state.number); + phba->sli4_hba.lnk_info.lnk_no); bf_set(lpfc_mbx_set_diag_state_link_type, &link_diag_state->u.req, - phba->sli4_hba.link_state.type); + phba->sli4_hba.lnk_info.lnk_tp); if (diag) bf_set(lpfc_mbx_set_diag_state_diag, &link_diag_state->u.req, 1); @@ -1727,6 +1736,79 @@ link_diag_state_set_out: } /** + * lpfc_sli4_bsg_set_internal_loopback - set sli4 internal loopback diagnostic + * @phba: Pointer to HBA context object. + * + * This function is responsible for issuing a sli4 mailbox command for setting + * up internal loopback diagnostic. + */ +static int +lpfc_sli4_bsg_set_internal_loopback(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *pmboxq; + uint32_t req_len, alloc_len; + struct lpfc_mbx_set_link_diag_loopback *link_diag_loopback; + int mbxstatus = MBX_SUCCESS, rc = 0; + + pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!pmboxq) + return -ENOMEM; + req_len = (sizeof(struct lpfc_mbx_set_link_diag_loopback) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, + LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK, + req_len, LPFC_SLI4_MBX_EMBED); + if (alloc_len != req_len) { + mempool_free(pmboxq, phba->mbox_mem_pool); + return -ENOMEM; + } + link_diag_loopback = &pmboxq->u.mqe.un.link_diag_loopback; + bf_set(lpfc_mbx_set_diag_state_link_num, + &link_diag_loopback->u.req, phba->sli4_hba.lnk_info.lnk_no); + bf_set(lpfc_mbx_set_diag_state_link_type, + &link_diag_loopback->u.req, phba->sli4_hba.lnk_info.lnk_tp); + bf_set(lpfc_mbx_set_diag_lpbk_type, &link_diag_loopback->u.req, + LPFC_DIAG_LOOPBACK_TYPE_SERDES); + + mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); + if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "3127 Failed setup loopback mode mailbox " + "command, rc:x%x, status:x%x\n", mbxstatus, + pmboxq->u.mb.mbxStatus); + rc = -ENODEV; + } + if (pmboxq && (mbxstatus != MBX_TIMEOUT)) + mempool_free(pmboxq, phba->mbox_mem_pool); + return rc; +} + +/** + * lpfc_sli4_diag_fcport_reg_setup - setup port registrations for diagnostic + * @phba: Pointer to HBA context object. + * + * This function set up SLI4 FC port registrations for diagnostic run, which + * includes all the rpis, vfi, and also vpi. + */ +static int +lpfc_sli4_diag_fcport_reg_setup(struct lpfc_hba *phba) +{ + int rc; + + if (phba->pport->fc_flag & FC_VFI_REGISTERED) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "3136 Port still had vfi registered: " + "mydid:x%x, fcfi:%d, vfi:%d, vpi:%d\n", + phba->pport->fc_myDID, phba->fcf.fcfi, + phba->sli4_hba.vfi_ids[phba->pport->vfi], + phba->vpi_ids[phba->pport->vpi]); + return -EINVAL; + } + rc = lpfc_issue_reg_vfi(phba->pport); + return rc; +} + +/** * lpfc_sli4_bsg_diag_loopback_mode - process an sli4 bsg vendor command * @phba: Pointer to HBA context object. * @job: LPFC_BSG_VENDOR_DIAG_MODE @@ -1738,10 +1820,8 @@ static int lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job) { struct diag_mode_set *loopback_mode; - uint32_t link_flags, timeout, req_len, alloc_len; - struct lpfc_mbx_set_link_diag_loopback *link_diag_loopback; - LPFC_MBOXQ_t *pmboxq = NULL; - int mbxstatus = MBX_SUCCESS, i, rc = 0; + uint32_t link_flags, timeout; + int i, rc = 0; /* no data to return just the return code */ job->reply->reply_payload_rcv_len = 0; @@ -1762,65 +1842,100 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job) if (rc) goto job_error; + /* indicate we are in loobpack diagnostic mode */ + spin_lock_irq(&phba->hbalock); + phba->link_flag |= LS_LOOPBACK_MODE; + spin_unlock_irq(&phba->hbalock); + + /* reset port to start frome scratch */ + rc = lpfc_selective_reset(phba); + if (rc) + goto job_error; + /* bring the link to diagnostic mode */ + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, + "3129 Bring link to diagnostic state.\n"); loopback_mode = (struct diag_mode_set *) job->request->rqst_data.h_vendor.vendor_cmd; link_flags = loopback_mode->type; timeout = loopback_mode->timeout * 100; rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1); - if (rc) + if (rc) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "3130 Failed to bring link to diagnostic " + "state, rc:x%x\n", rc); goto loopback_mode_exit; + } /* wait for link down before proceeding */ i = 0; while (phba->link_state != LPFC_LINK_DOWN) { if (i++ > timeout) { rc = -ETIMEDOUT; + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, + "3131 Timeout waiting for link to " + "diagnostic mode, timeout:%d ms\n", + timeout * 10); goto loopback_mode_exit; } msleep(10); } + /* set up loopback mode */ - pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmboxq) { - rc = -ENOMEM; - goto loopback_mode_exit; - } - req_len = (sizeof(struct lpfc_mbx_set_link_diag_loopback) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK, - req_len, LPFC_SLI4_MBX_EMBED); - if (alloc_len != req_len) { - rc = -ENOMEM; + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, + "3132 Set up loopback mode:x%x\n", link_flags); + + if (link_flags == INTERNAL_LOOP_BACK) + rc = lpfc_sli4_bsg_set_internal_loopback(phba); + else if (link_flags == EXTERNAL_LOOP_BACK) + rc = lpfc_hba_init_link_fc_topology(phba, + FLAGS_TOPOLOGY_MODE_PT_PT, + MBX_NOWAIT); + else { + rc = -EINVAL; + lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "3141 Loopback mode:x%x not supported\n", + link_flags); goto loopback_mode_exit; } - link_diag_loopback = &pmboxq->u.mqe.un.link_diag_loopback; - bf_set(lpfc_mbx_set_diag_state_link_num, - &link_diag_loopback->u.req, phba->sli4_hba.link_state.number); - bf_set(lpfc_mbx_set_diag_state_link_type, - &link_diag_loopback->u.req, phba->sli4_hba.link_state.type); - if (link_flags == INTERNAL_LOOP_BACK) - bf_set(lpfc_mbx_set_diag_lpbk_type, - &link_diag_loopback->u.req, - LPFC_DIAG_LOOPBACK_TYPE_INTERNAL); - else - bf_set(lpfc_mbx_set_diag_lpbk_type, - &link_diag_loopback->u.req, - LPFC_DIAG_LOOPBACK_TYPE_EXTERNAL); - mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); - if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) - rc = -ENODEV; - else { - phba->link_flag |= LS_LOOPBACK_MODE; + if (!rc) { /* wait for the link attention interrupt */ msleep(100); i = 0; + while (phba->link_state < LPFC_LINK_UP) { + if (i++ > timeout) { + rc = -ETIMEDOUT; + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, + "3137 Timeout waiting for link up " + "in loopback mode, timeout:%d ms\n", + timeout * 10); + break; + } + msleep(10); + } + } + + /* port resource registration setup for loopback diagnostic */ + if (!rc) { + /* set up a none zero myDID for loopback test */ + phba->pport->fc_myDID = 1; + rc = lpfc_sli4_diag_fcport_reg_setup(phba); + } else + goto loopback_mode_exit; + + if (!rc) { + /* wait for the port ready */ + msleep(100); + i = 0; while (phba->link_state != LPFC_HBA_READY) { if (i++ > timeout) { rc = -ETIMEDOUT; + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, + "3133 Timeout waiting for port " + "loopback mode ready, timeout:%d ms\n", + timeout * 10); break; } msleep(10); @@ -1828,14 +1943,14 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job) } loopback_mode_exit: + /* clear loopback diagnostic mode */ + if (rc) { + spin_lock_irq(&phba->hbalock); + phba->link_flag &= ~LS_LOOPBACK_MODE; + spin_unlock_irq(&phba->hbalock); + } lpfc_bsg_diag_mode_exit(phba); - /* - * Let SLI layer release mboxq if mbox command completed after timeout. - */ - if (pmboxq && (mbxstatus != MBX_TIMEOUT)) - mempool_free(pmboxq, phba->mbox_mem_pool); - job_error: /* make error code available to userspace */ job->reply->result = rc; @@ -1879,7 +1994,6 @@ lpfc_bsg_diag_loopback_mode(struct fc_bsg_job *job) rc = -ENODEV; return rc; - } /** @@ -1895,7 +2009,9 @@ lpfc_sli4_bsg_diag_mode_end(struct fc_bsg_job *job) struct Scsi_Host *shost; struct lpfc_vport *vport; struct lpfc_hba *phba; - int rc; + struct diag_mode_set *loopback_mode_end_cmd; + uint32_t timeout; + int rc, i; shost = job->shost; if (!shost) @@ -1913,11 +2029,47 @@ lpfc_sli4_bsg_diag_mode_end(struct fc_bsg_job *job) LPFC_SLI_INTF_IF_TYPE_2) return -ENODEV; + /* clear loopback diagnostic mode */ + spin_lock_irq(&phba->hbalock); + phba->link_flag &= ~LS_LOOPBACK_MODE; + spin_unlock_irq(&phba->hbalock); + loopback_mode_end_cmd = (struct diag_mode_set *) + job->request->rqst_data.h_vendor.vendor_cmd; + timeout = loopback_mode_end_cmd->timeout * 100; + rc = lpfc_sli4_bsg_set_link_diag_state(phba, 0); + if (rc) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "3139 Failed to bring link to diagnostic " + "state, rc:x%x\n", rc); + goto loopback_mode_end_exit; + } - if (!rc) - rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT); + /* wait for link down before proceeding */ + i = 0; + while (phba->link_state != LPFC_LINK_DOWN) { + if (i++ > timeout) { + rc = -ETIMEDOUT; + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, + "3140 Timeout waiting for link to " + "diagnostic mode_end, timeout:%d ms\n", + timeout * 10); + /* there is nothing much we can do here */ + break; + } + msleep(10); + } + + /* reset port resource registrations */ + rc = lpfc_selective_reset(phba); + phba->pport->fc_myDID = 0; +loopback_mode_end_exit: + /* make return code available to userspace */ + job->reply->result = rc; + /* complete the job back to userspace if no error */ + if (rc == 0) + job->job_done(job); return rc; } @@ -2012,9 +2164,9 @@ lpfc_sli4_bsg_link_diag_test(struct fc_bsg_job *job) } run_link_diag_test = &pmboxq->u.mqe.un.link_diag_test; bf_set(lpfc_mbx_run_diag_test_link_num, &run_link_diag_test->u.req, - phba->sli4_hba.link_state.number); + phba->sli4_hba.lnk_info.lnk_no); bf_set(lpfc_mbx_run_diag_test_link_type, &run_link_diag_test->u.req, - phba->sli4_hba.link_state.type); + phba->sli4_hba.lnk_info.lnk_tp); bf_set(lpfc_mbx_run_diag_test_test_id, &run_link_diag_test->u.req, link_diag_test_cmd->test_id); bf_set(lpfc_mbx_run_diag_test_loops, &run_link_diag_test->u.req, @@ -2091,10 +2243,18 @@ static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t *rpi) if (!mbox) return -ENOMEM; - if (phba->sli_rev == LPFC_SLI_REV4) + if (phba->sli_rev < LPFC_SLI_REV4) + status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID, + (uint8_t *)&phba->pport->fc_sparam, + mbox, *rpi); + else { *rpi = lpfc_sli4_alloc_rpi(phba); - status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID, - (uint8_t *)&phba->pport->fc_sparam, mbox, *rpi); + status = lpfc_reg_rpi(phba, phba->pport->vpi, + phba->pport->fc_myDID, + (uint8_t *)&phba->pport->fc_sparam, + mbox, *rpi); + } + if (status) { mempool_free(mbox, phba->mbox_mem_pool); if (phba->sli_rev == LPFC_SLI_REV4) @@ -2117,7 +2277,8 @@ static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t *rpi) return -ENODEV; } - *rpi = mbox->u.mb.un.varWords[0]; + if (phba->sli_rev < LPFC_SLI_REV4) + *rpi = mbox->u.mb.un.varWords[0]; lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); kfree(dmabuff); @@ -2142,7 +2303,12 @@ static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi) if (mbox == NULL) return -ENOMEM; - lpfc_unreg_login(phba, 0, rpi, mbox); + if (phba->sli_rev < LPFC_SLI_REV4) + lpfc_unreg_login(phba, 0, rpi, mbox); + else + lpfc_unreg_login(phba, phba->pport->vpi, + phba->sli4_hba.rpi_ids[rpi], mbox); + status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { @@ -2630,15 +2796,15 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) uint32_t full_size; size_t segment_len = 0, segment_offset = 0, current_offset = 0; uint16_t rpi = 0; - struct lpfc_iocbq *cmdiocbq, *rspiocbq; - IOCB_t *cmd, *rsp; + struct lpfc_iocbq *cmdiocbq, *rspiocbq = NULL; + IOCB_t *cmd, *rsp = NULL; struct lpfc_sli_ct_request *ctreq; struct lpfc_dmabuf *txbmp; struct ulp_bde64 *txbpl = NULL; struct lpfc_dmabufext *txbuffer = NULL; struct list_head head; struct lpfc_dmabuf *curr; - uint16_t txxri, rxxri; + uint16_t txxri = 0, rxxri; uint32_t num_bde; uint8_t *ptr = NULL, *rx_databuf = NULL; int rc = 0; @@ -2665,7 +2831,6 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) rc = -EINVAL; goto loopback_test_exit; } - diag_mode = (struct diag_mode_test *) job->request->rqst_data.h_vendor.vendor_cmd; @@ -2720,18 +2885,19 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) if (rc) goto loopback_test_exit; - rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri); - if (rc) { - lpfcdiag_loop_self_unreg(phba, rpi); - goto loopback_test_exit; - } + if (phba->sli_rev < LPFC_SLI_REV4) { + rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri); + if (rc) { + lpfcdiag_loop_self_unreg(phba, rpi); + goto loopback_test_exit; + } - rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size); - if (rc) { - lpfcdiag_loop_self_unreg(phba, rpi); - goto loopback_test_exit; + rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size); + if (rc) { + lpfcdiag_loop_self_unreg(phba, rpi); + goto loopback_test_exit; + } } - evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, SLI_CT_ELX_LOOPBACK); if (!evt) { @@ -2746,7 +2912,8 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) spin_unlock_irqrestore(&phba->ct_ev_lock, flags); cmdiocbq = lpfc_sli_get_iocbq(phba); - rspiocbq = lpfc_sli_get_iocbq(phba); + if (phba->sli_rev < LPFC_SLI_REV4) + rspiocbq = lpfc_sli_get_iocbq(phba); txbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); if (txbmp) { @@ -2759,14 +2926,18 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) } } - if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer || - !txbmp->virt) { + if (!cmdiocbq || !txbmp || !txbpl || !txbuffer || !txbmp->virt) { + rc = -ENOMEM; + goto err_loopback_test_exit; + } + if ((phba->sli_rev < LPFC_SLI_REV4) && !rspiocbq) { rc = -ENOMEM; goto err_loopback_test_exit; } cmd = &cmdiocbq->iocb; - rsp = &rspiocbq->iocb; + if (phba->sli_rev < LPFC_SLI_REV4) + rsp = &rspiocbq->iocb; INIT_LIST_HEAD(&head); list_add_tail(&head, &txbuffer->dma.list); @@ -2796,7 +2967,6 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) list_del(&head); /* Build the XMIT_SEQUENCE iocb */ - num_bde = (uint32_t)txbuffer->flag; cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(txbmp->phys); @@ -2813,16 +2983,27 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) cmd->ulpBdeCount = 1; cmd->ulpLe = 1; cmd->ulpClass = CLASS3; - cmd->ulpContext = txxri; + if (phba->sli_rev < LPFC_SLI_REV4) { + cmd->ulpContext = txxri; + } else { + cmd->un.xseq64.bdl.ulpIoTag32 = 0; + cmd->un.ulpWord[3] = phba->sli4_hba.rpi_ids[rpi]; + cmdiocbq->context3 = txbmp; + cmdiocbq->sli4_xritag = NO_XRI; + cmd->unsli3.rcvsli3.ox_id = 0xffff; + } cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; cmdiocbq->vport = phba->pport; - iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, rspiocbq, (phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT); - if ((iocb_stat != IOCB_SUCCESS) || (rsp->ulpStatus != IOCB_SUCCESS)) { + if ((iocb_stat != IOCB_SUCCESS) || ((phba->sli_rev < LPFC_SLI_REV4) && + (rsp->ulpStatus != IOCB_SUCCESS))) { + lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "3126 Failed loopback test issue iocb: " + "iocb_stat:x%x\n", iocb_stat); rc = -EIO; goto err_loopback_test_exit; } @@ -2832,9 +3013,12 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) evt->wq, !list_empty(&evt->events_to_see), ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ); evt->waiting = 0; - if (list_empty(&evt->events_to_see)) + if (list_empty(&evt->events_to_see)) { rc = (time_left) ? -EINTR : -ETIMEDOUT; - else { + lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "3125 Not receiving unsolicited event, " + "rc:x%x\n", rc); + } else { spin_lock_irqsave(&phba->ct_ev_lock, flags); list_move(evt->events_to_see.prev, &evt->events_to_get); evdat = list_entry(evt->events_to_get.prev, @@ -2891,7 +3075,7 @@ loopback_test_exit: job->reply->result = rc; job->dd_data = NULL; /* complete the job back to userspace if no error */ - if (rc == 0) + if (rc == IOCB_SUCCESS) job->job_done(job); return rc; } @@ -3078,7 +3262,9 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, && (mb->un.varWords[1] == 1)) { phba->wait_4_mlo_maint_flg = 1; } else if (mb->un.varWords[0] == SETVAR_MLORST) { + spin_lock_irq(&phba->hbalock); phba->link_flag &= ~LS_LOOPBACK_MODE; + spin_unlock_irq(&phba->hbalock); phba->fc_topology = LPFC_TOPOLOGY_PT_PT; } break; @@ -3140,6 +3326,9 @@ lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) unsigned long flags; uint32_t size; int rc = 0; + struct lpfc_dmabuf *dmabuf; + struct lpfc_sli_config_mbox *sli_cfg_mbx; + uint8_t *pmbx; spin_lock_irqsave(&phba->ct_ev_lock, flags); dd_data = pmboxq->context1; @@ -3156,7 +3345,19 @@ lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) */ pmb = (uint8_t *)&pmboxq->u.mb; pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb; + /* Copy the byte swapped response mailbox back to the user */ memcpy(pmb_buf, pmb, sizeof(MAILBOX_t)); + /* if there is any non-embedded extended data copy that too */ + dmabuf = phba->mbox_ext_buf_ctx.mbx_dmabuf; + sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; + if (!bsg_bf_get(lpfc_mbox_hdr_emb, + &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) { + pmbx = (uint8_t *)dmabuf->virt; + /* byte swap the extended data following the mailbox command */ + lpfc_sli_pcimem_bcopy(&pmbx[sizeof(MAILBOX_t)], + &pmbx[sizeof(MAILBOX_t)], + sli_cfg_mbx->un.sli_config_emb0_subsys.mse[0].buf_len); + } job = dd_data->context_un.mbox.set_job; if (job) { @@ -3519,6 +3720,18 @@ lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job, /* state change */ phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT; + /* + * Non-embedded mailbox subcommand data gets byte swapped here because + * the lower level driver code only does the first 64 mailbox words. + */ + if ((!bsg_bf_get(lpfc_mbox_hdr_emb, + &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) && + (nemb_tp == nemb_mse)) + lpfc_sli_pcimem_bcopy(&pmbx[sizeof(MAILBOX_t)], + &pmbx[sizeof(MAILBOX_t)], + sli_cfg_mbx->un.sli_config_emb0_subsys. + mse[0].buf_len); + rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, @@ -3575,7 +3788,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job, &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr); if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_MSE) { lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "2953 Handled SLI_CONFIG(mse) wr, " + "2953 Failed SLI_CONFIG(mse) wr, " "ext_buf_cnt(%d) out of range(%d)\n", ext_buf_cnt, LPFC_MBX_SLI_CONFIG_MAX_MSE); @@ -3593,7 +3806,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job, ext_buf_cnt = sli_cfg_mbx->un.sli_config_emb1_subsys.hbd_count; if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_HBD) { lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "2954 Handled SLI_CONFIG(hbd) wr, " + "2954 Failed SLI_CONFIG(hbd) wr, " "ext_buf_cnt(%d) out of range(%d)\n", ext_buf_cnt, LPFC_MBX_SLI_CONFIG_MAX_HBD); @@ -3687,6 +3900,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job, "2956 Failed to issue SLI_CONFIG ext-buffer " "maibox command, rc:x%x\n", rc); rc = -EPIPE; + goto job_error; } /* wait for additoinal external buffers */ @@ -3721,7 +3935,7 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t opcode; int rc = SLI_CONFIG_NOT_HANDLED; - /* state change */ + /* state change on new multi-buffer pass-through mailbox command */ phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_HOST; sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; @@ -3752,18 +3966,36 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, break; default: lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2959 Not handled SLI_CONFIG " + "2959 Reject SLI_CONFIG " "subsys_fcoe, opcode:x%x\n", opcode); - rc = SLI_CONFIG_NOT_HANDLED; + rc = -EPERM; + break; + } + } else if (subsys == SLI_CONFIG_SUBSYS_COMN) { + switch (opcode) { + case COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES: + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, + "3106 Handled SLI_CONFIG " + "subsys_fcoe, opcode:x%x\n", + opcode); + rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job, + nemb_mse, dmabuf); + break; + default: + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, + "3107 Reject SLI_CONFIG " + "subsys_fcoe, opcode:x%x\n", + opcode); + rc = -EPERM; break; } } else { lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2977 Handled SLI_CONFIG " + "2977 Reject SLI_CONFIG " "subsys:x%d, opcode:x%x\n", subsys, opcode); - rc = SLI_CONFIG_NOT_HANDLED; + rc = -EPERM; } } else { subsys = bsg_bf_get(lpfc_emb1_subcmnd_subsys, @@ -3799,12 +4031,17 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, } } else { lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2978 Handled SLI_CONFIG " + "2978 Not handled SLI_CONFIG " "subsys:x%d, opcode:x%x\n", subsys, opcode); rc = SLI_CONFIG_NOT_HANDLED; } } + + /* state reset on not handled new multi-buffer mailbox command */ + if (rc != SLI_CONFIG_HANDLED) + phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_IDLE; + return rc; } @@ -4262,11 +4499,8 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, /* extended mailbox commands will need an extended buffer */ if (mbox_req->inExtWLen || mbox_req->outExtWLen) { - /* any data for the device? */ - if (mbox_req->inExtWLen) { - from = pmbx; - ext = from + sizeof(MAILBOX_t); - } + from = pmbx; + ext = from + sizeof(MAILBOX_t); pmboxq->context2 = ext; pmboxq->in_ext_byte_len = mbox_req->inExtWLen * sizeof(uint32_t); diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h index c8c2b47ea88..edfe61fc52b 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.h +++ b/drivers/scsi/lpfc/lpfc_bsg.h @@ -96,7 +96,7 @@ struct get_mgmt_rev { }; #define MANAGEMENT_MAJOR_REV 1 -#define MANAGEMENT_MINOR_REV 0 +#define MANAGEMENT_MINOR_REV 1 /* the MgmtRevInfo structure */ struct MgmtRevInfo { @@ -248,6 +248,7 @@ struct lpfc_sli_config_emb1_subsys { #define COMN_OPCODE_WRITE_OBJECT 0xAC #define COMN_OPCODE_READ_OBJECT_LIST 0xAD #define COMN_OPCODE_DELETE_OBJECT 0xAE +#define COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES 0x79 uint32_t timeout; uint32_t request_length; uint32_t word9; diff --git a/drivers/scsi/lpfc/lpfc_compat.h b/drivers/scsi/lpfc/lpfc_compat.h index 75e2e569ded..c88e556ea62 100644 --- a/drivers/scsi/lpfc/lpfc_compat.h +++ b/drivers/scsi/lpfc/lpfc_compat.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2005 Emulex. All rights reserved. * + * Copyright (C) 2004-2011 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -82,7 +82,8 @@ lpfc_memcpy_from_slim( void *dest, void __iomem *src, unsigned int bytes) static inline void lpfc_memcpy_to_slim( void __iomem *dest, void *src, unsigned int bytes) { - __iowrite32_copy(dest, src, bytes); + /* convert bytes in argument list to word count for copy function */ + __iowrite32_copy(dest, src, bytes / sizeof(uint32_t)); } static inline void diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 60f95347bab..26924b7a6cd 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -26,7 +26,7 @@ void lpfc_sli_read_link_ste(struct lpfc_hba *); void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t, uint16_t); void lpfc_dump_wakeup_param(struct lpfc_hba *, LPFC_MBOXQ_t *); int lpfc_dump_static_vport(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); -int lpfc_dump_fcoe_param(struct lpfc_hba *, struct lpfcMboxq *); +int lpfc_sli4_dump_cfg_rg23(struct lpfc_hba *, struct lpfcMboxq *); void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); @@ -78,6 +78,7 @@ void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *, LPFC_MBOXQ_t *); +void lpfc_unregister_vfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_enqueue_node(struct lpfc_vport *, struct lpfc_nodelist *); void lpfc_dequeue_node(struct lpfc_vport *, struct lpfc_nodelist *); struct lpfc_nodelist *lpfc_enable_node(struct lpfc_vport *, @@ -106,7 +107,7 @@ void lpfc_cleanup(struct lpfc_vport *); void lpfc_disc_timeout(unsigned long); struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); - +struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); void lpfc_worker_wake_up(struct lpfc_hba *); int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t); int lpfc_do_work(void *); @@ -453,3 +454,11 @@ int lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *, int); uint16_t lpfc_sli_sriov_nr_virtfn_get(struct lpfc_hba *); int lpfc_sli4_queue_create(struct lpfc_hba *); void lpfc_sli4_queue_destroy(struct lpfc_hba *); +void lpfc_sli4_abts_err_handler(struct lpfc_hba *, struct lpfc_nodelist *, + struct sli4_wcqe_xri_aborted *); +int lpfc_hba_init_link_fc_topology(struct lpfc_hba *, uint32_t, uint32_t); +int lpfc_issue_reg_vfi(struct lpfc_vport *); +int lpfc_issue_unreg_vfi(struct lpfc_vport *); +int lpfc_selective_reset(struct lpfc_hba *); +int lpfc_sli4_read_config(struct lpfc_hba *phba); +int lpfc_scsi_buf_update(struct lpfc_hba *phba); diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 28382596fb9..3587a3fe8fc 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1997,7 +1997,8 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, /* Get slow-path event queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Slow-path EQ information:\n"); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + if (phba->sli4_hba.sp_eq) { + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tEQID[%02d], " "QE-COUNT[%04d], QE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", @@ -2006,12 +2007,17 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.sp_eq->entry_size, phba->sli4_hba.sp_eq->host_index, phba->sli4_hba.sp_eq->hba_index); + } /* Get fast-path event queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Fast-path EQ information:\n"); - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) { - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + if (phba->sli4_hba.fp_eq) { + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; + fcp_qidx++) { + if (phba->sli4_hba.fp_eq[fcp_qidx]) { + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tEQID[%02d], " "QE-COUNT[%04d], QE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", @@ -2020,16 +2026,19 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.fp_eq[fcp_qidx]->entry_size, phba->sli4_hba.fp_eq[fcp_qidx]->host_index, phba->sli4_hba.fp_eq[fcp_qidx]->hba_index); + } + } } len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); /* Get mailbox complete queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Slow-path MBX CQ information:\n"); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + if (phba->sli4_hba.mbx_cq) { + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Associated EQID[%02d]:\n", phba->sli4_hba.mbx_cq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tCQID[%02d], " "QE-COUNT[%04d], QE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", @@ -2038,14 +2047,16 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.mbx_cq->entry_size, phba->sli4_hba.mbx_cq->host_index, phba->sli4_hba.mbx_cq->hba_index); + } /* Get slow-path complete queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Slow-path ELS CQ information:\n"); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + if (phba->sli4_hba.els_cq) { + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Associated EQID[%02d]:\n", phba->sli4_hba.els_cq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tCQID [%02d], " "QE-COUNT[%04d], QE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", @@ -2054,16 +2065,21 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.els_cq->entry_size, phba->sli4_hba.els_cq->host_index, phba->sli4_hba.els_cq->hba_index); + } /* Get fast-path complete queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Fast-path FCP CQ information:\n"); fcp_qidx = 0; - do { - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + if (phba->sli4_hba.fcp_cq) { + do { + if (phba->sli4_hba.fcp_cq[fcp_qidx]) { + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "Associated EQID[%02d]:\n", phba->sli4_hba.fcp_cq[fcp_qidx]->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tCQID[%02d], " "QE-COUNT[%04d], QE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", @@ -2072,16 +2088,20 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.fcp_cq[fcp_qidx]->entry_size, phba->sli4_hba.fcp_cq[fcp_qidx]->host_index, phba->sli4_hba.fcp_cq[fcp_qidx]->hba_index); - } while (++fcp_qidx < phba->cfg_fcp_eq_count); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); + } + } while (++fcp_qidx < phba->cfg_fcp_eq_count); + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); + } /* Get mailbox queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Slow-path MBX MQ information:\n"); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + if (phba->sli4_hba.mbx_wq) { + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Associated CQID[%02d]:\n", phba->sli4_hba.mbx_wq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tWQID[%02d], " "QE-COUNT[%04d], QE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", @@ -2090,14 +2110,16 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.mbx_wq->entry_size, phba->sli4_hba.mbx_wq->host_index, phba->sli4_hba.mbx_wq->hba_index); + } /* Get slow-path work queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Slow-path ELS WQ information:\n"); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + if (phba->sli4_hba.els_wq) { + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Associated CQID[%02d]:\n", phba->sli4_hba.els_wq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tWQID[%02d], " "QE-COUNT[%04d], QE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", @@ -2106,15 +2128,22 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.els_wq->entry_size, phba->sli4_hba.els_wq->host_index, phba->sli4_hba.els_wq->hba_index); + } /* Get fast-path work queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Fast-path FCP WQ information:\n"); - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; fcp_qidx++) { - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + if (phba->sli4_hba.fcp_wq) { + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; + fcp_qidx++) { + if (!phba->sli4_hba.fcp_wq[fcp_qidx]) + continue; + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "Associated CQID[%02d]:\n", phba->sli4_hba.fcp_wq[fcp_qidx]->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tWQID[%02d], " "QE-COUNT[%04d], WQE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", @@ -2123,16 +2152,19 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.fcp_wq[fcp_qidx]->entry_size, phba->sli4_hba.fcp_wq[fcp_qidx]->host_index, phba->sli4_hba.fcp_wq[fcp_qidx]->hba_index); + } + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); } - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); /* Get receive queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Slow-path RQ information:\n"); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + if (phba->sli4_hba.hdr_rq && phba->sli4_hba.dat_rq) { + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Associated CQID[%02d]:\n", phba->sli4_hba.hdr_rq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tHQID[%02d], " "QE-COUNT[%04d], QE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", @@ -2141,7 +2173,7 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.hdr_rq->entry_size, phba->sli4_hba.hdr_rq->host_index, phba->sli4_hba.hdr_rq->hba_index); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tDQID[%02d], " "QE-COUNT[%04d], QE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", @@ -2150,7 +2182,7 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.dat_rq->entry_size, phba->sli4_hba.dat_rq->host_index, phba->sli4_hba.dat_rq->hba_index); - + } return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); } @@ -2360,7 +2392,8 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, switch (quetp) { case LPFC_IDIAG_EQ: /* Slow-path event queue */ - if (phba->sli4_hba.sp_eq->queue_id == queid) { + if (phba->sli4_hba.sp_eq && + phba->sli4_hba.sp_eq->queue_id == queid) { /* Sanity check */ rc = lpfc_idiag_que_param_check( phba->sli4_hba.sp_eq, index, count); @@ -2370,23 +2403,29 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, goto pass_check; } /* Fast-path event queue */ - for (qidx = 0; qidx < phba->cfg_fcp_eq_count; qidx++) { - if (phba->sli4_hba.fp_eq[qidx]->queue_id == queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( + if (phba->sli4_hba.fp_eq) { + for (qidx = 0; qidx < phba->cfg_fcp_eq_count; qidx++) { + if (phba->sli4_hba.fp_eq[qidx] && + phba->sli4_hba.fp_eq[qidx]->queue_id == + queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( phba->sli4_hba.fp_eq[qidx], index, count); - if (rc) - goto error_out; - idiag.ptr_private = phba->sli4_hba.fp_eq[qidx]; - goto pass_check; + if (rc) + goto error_out; + idiag.ptr_private = + phba->sli4_hba.fp_eq[qidx]; + goto pass_check; + } } } goto error_out; break; case LPFC_IDIAG_CQ: /* MBX complete queue */ - if (phba->sli4_hba.mbx_cq->queue_id == queid) { + if (phba->sli4_hba.mbx_cq && + phba->sli4_hba.mbx_cq->queue_id == queid) { /* Sanity check */ rc = lpfc_idiag_que_param_check( phba->sli4_hba.mbx_cq, index, count); @@ -2396,7 +2435,8 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, goto pass_check; } /* ELS complete queue */ - if (phba->sli4_hba.els_cq->queue_id == queid) { + if (phba->sli4_hba.els_cq && + phba->sli4_hba.els_cq->queue_id == queid) { /* Sanity check */ rc = lpfc_idiag_que_param_check( phba->sli4_hba.els_cq, index, count); @@ -2406,25 +2446,30 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, goto pass_check; } /* FCP complete queue */ - qidx = 0; - do { - if (phba->sli4_hba.fcp_cq[qidx]->queue_id == queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( + if (phba->sli4_hba.fcp_cq) { + qidx = 0; + do { + if (phba->sli4_hba.fcp_cq[qidx] && + phba->sli4_hba.fcp_cq[qidx]->queue_id == + queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( phba->sli4_hba.fcp_cq[qidx], index, count); - if (rc) - goto error_out; - idiag.ptr_private = + if (rc) + goto error_out; + idiag.ptr_private = phba->sli4_hba.fcp_cq[qidx]; - goto pass_check; - } - } while (++qidx < phba->cfg_fcp_eq_count); + goto pass_check; + } + } while (++qidx < phba->cfg_fcp_eq_count); + } goto error_out; break; case LPFC_IDIAG_MQ: /* MBX work queue */ - if (phba->sli4_hba.mbx_wq->queue_id == queid) { + if (phba->sli4_hba.mbx_wq && + phba->sli4_hba.mbx_wq->queue_id == queid) { /* Sanity check */ rc = lpfc_idiag_que_param_check( phba->sli4_hba.mbx_wq, index, count); @@ -2433,10 +2478,12 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, idiag.ptr_private = phba->sli4_hba.mbx_wq; goto pass_check; } + goto error_out; break; case LPFC_IDIAG_WQ: /* ELS work queue */ - if (phba->sli4_hba.els_wq->queue_id == queid) { + if (phba->sli4_hba.els_wq && + phba->sli4_hba.els_wq->queue_id == queid) { /* Sanity check */ rc = lpfc_idiag_que_param_check( phba->sli4_hba.els_wq, index, count); @@ -2446,24 +2493,30 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, goto pass_check; } /* FCP work queue */ - for (qidx = 0; qidx < phba->cfg_fcp_wq_count; qidx++) { - if (phba->sli4_hba.fcp_wq[qidx]->queue_id == queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( + if (phba->sli4_hba.fcp_wq) { + for (qidx = 0; qidx < phba->cfg_fcp_wq_count; qidx++) { + if (!phba->sli4_hba.fcp_wq[qidx]) + continue; + if (phba->sli4_hba.fcp_wq[qidx]->queue_id == + queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( phba->sli4_hba.fcp_wq[qidx], index, count); - if (rc) - goto error_out; - idiag.ptr_private = - phba->sli4_hba.fcp_wq[qidx]; - goto pass_check; + if (rc) + goto error_out; + idiag.ptr_private = + phba->sli4_hba.fcp_wq[qidx]; + goto pass_check; + } } } goto error_out; break; case LPFC_IDIAG_RQ: /* HDR queue */ - if (phba->sli4_hba.hdr_rq->queue_id == queid) { + if (phba->sli4_hba.hdr_rq && + phba->sli4_hba.hdr_rq->queue_id == queid) { /* Sanity check */ rc = lpfc_idiag_que_param_check( phba->sli4_hba.hdr_rq, index, count); @@ -2473,7 +2526,8 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, goto pass_check; } /* DAT queue */ - if (phba->sli4_hba.dat_rq->queue_id == queid) { + if (phba->sli4_hba.dat_rq && + phba->sli4_hba.dat_rq->queue_id == queid) { /* Sanity check */ rc = lpfc_idiag_que_param_check( phba->sli4_hba.dat_rq, index, count); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 445826a4c98..7afc757338d 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -421,13 +421,13 @@ fail: * @vport: pointer to a host virtual N_Port data structure. * * This routine issues a REG_VFI mailbox for the vfi, vpi, fcfi triplet for - * the @vport. This mailbox command is necessary for FCoE only. + * the @vport. This mailbox command is necessary for SLI4 port only. * * Return code * 0 - successfully issued REG_VFI for @vport * A failure code otherwise. **/ -static int +int lpfc_issue_reg_vfi(struct lpfc_vport *vport) { struct lpfc_hba *phba = vport->phba; @@ -438,10 +438,14 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport) int rc = 0; sp = &phba->fc_fabparam; - ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - rc = -ENODEV; - goto fail; + /* move forward in case of SLI4 FC port loopback test */ + if ((phba->sli_rev == LPFC_SLI_REV4) && + !(phba->link_flag & LS_LOOPBACK_MODE)) { + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + rc = -ENODEV; + goto fail; + } } dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); @@ -487,6 +491,54 @@ fail: } /** + * lpfc_issue_unreg_vfi - Unregister VFI for this vport's fabric login + * @vport: pointer to a host virtual N_Port data structure. + * + * This routine issues a UNREG_VFI mailbox with the vfi, vpi, fcfi triplet for + * the @vport. This mailbox command is necessary for SLI4 port only. + * + * Return code + * 0 - successfully issued REG_VFI for @vport + * A failure code otherwise. + **/ +int +lpfc_issue_unreg_vfi(struct lpfc_vport *vport) +{ + struct lpfc_hba *phba = vport->phba; + struct Scsi_Host *shost; + LPFC_MBOXQ_t *mboxq; + int rc; + + mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) { + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + "2556 UNREG_VFI mbox allocation failed" + "HBA state x%x\n", phba->pport->port_state); + return -ENOMEM; + } + + lpfc_unreg_vfi(mboxq, vport); + mboxq->vport = vport; + mboxq->mbox_cmpl = lpfc_unregister_vfi_cmpl; + + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + "2557 UNREG_VFI issue mbox failed rc x%x " + "HBA state x%x\n", + rc, phba->pport->port_state); + mempool_free(mboxq, phba->mbox_mem_pool); + return -EIO; + } + + shost = lpfc_shost_from_vport(vport); + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_VFI_REGISTERED; + spin_unlock_irq(shost->host_lock); + return 0; +} + +/** * lpfc_check_clean_addr_bit - Check whether assigned FCID is clean. * @vport: pointer to a host virtual N_Port data structure. * @sp: pointer to service parameter data structure. @@ -615,7 +667,9 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, "1816 FLOGI NPIV supported, " "response data 0x%x\n", sp->cmn.response_multiple_NPort); + spin_lock_irq(&phba->hbalock); phba->link_flag |= LS_NPIV_FAB_SUPPORTED; + spin_unlock_irq(&phba->hbalock); } else { /* Because we asked f/w for NPIV it still expects us to call reg_vnpid atleast for the physcial host */ @@ -623,7 +677,9 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, LOG_ELS | LOG_VPORT, "1817 Fabric does not support NPIV " "- configuring single port mode.\n"); + spin_lock_irq(&phba->hbalock); phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED; + spin_unlock_irq(&phba->hbalock); } } @@ -686,11 +742,16 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_do_scr_ns_plogi(phba, vport); } else if (vport->fc_flag & FC_VFI_REGISTERED) lpfc_issue_init_vpi(vport); - else + else { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "3135 Need register VFI: (x%x/%x)\n", + vport->fc_prevDID, vport->fc_myDID); lpfc_issue_reg_vfi(vport); + } } return 0; } + /** * lpfc_cmpl_els_flogi_nport - Completion function for flogi to an N_Port * @vport: pointer to a host virtual N_Port data structure. @@ -907,17 +968,16 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no * alpa map would take too long otherwise. */ - if (phba->alpa_map[0] == 0) { + if (phba->alpa_map[0] == 0) vport->cfg_discovery_threads = LPFC_MAX_DISC_THREADS; - if ((phba->sli_rev == LPFC_SLI_REV4) && - (!(vport->fc_flag & FC_VFI_REGISTERED) || - (vport->fc_prevDID != vport->fc_myDID))) { - if (vport->fc_flag & FC_VFI_REGISTERED) - lpfc_sli4_unreg_all_rpis(vport); - lpfc_issue_reg_vfi(vport); - lpfc_nlp_put(ndlp); - goto out; - } + if ((phba->sli_rev == LPFC_SLI_REV4) && + (!(vport->fc_flag & FC_VFI_REGISTERED) || + (vport->fc_prevDID != vport->fc_myDID))) { + if (vport->fc_flag & FC_VFI_REGISTERED) + lpfc_sli4_unreg_all_rpis(vport); + lpfc_issue_reg_vfi(vport); + lpfc_nlp_put(ndlp); + goto out; } goto flogifail; } @@ -1075,6 +1135,7 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Setup CSPs accordingly for Fabric */ sp->cmn.e_d_tov = 0; sp->cmn.w2.r_a_tov = 0; + sp->cmn.virtual_fabric_support = 0; sp->cls1.classValid = 0; sp->cls2.seqDelivery = 1; sp->cls3.seqDelivery = 1; @@ -1163,8 +1224,7 @@ lpfc_els_abort_flogi(struct lpfc_hba *phba) spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { icmd = &iocb->iocb; - if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR && - icmd->un.elsreq64.bdl.ulpIoTag32) { + if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) { ndlp = (struct lpfc_nodelist *)(iocb->context1); if (ndlp && NLP_CHK_NODE_ACT(ndlp) && (ndlp->nlp_DID == Fabric_DID)) @@ -3066,17 +3126,22 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (did == FDMI_DID) retry = 1; - if (((cmd == ELS_CMD_FLOGI) || (cmd == ELS_CMD_FDISC)) && + if ((cmd == ELS_CMD_FLOGI) && (phba->fc_topology != LPFC_TOPOLOGY_LOOP) && !lpfc_error_lost_link(irsp)) { /* FLOGI retry policy */ retry = 1; - /* retry forever */ + /* retry FLOGI forever */ maxretry = 0; if (cmdiocb->retry >= 100) delay = 5000; else if (cmdiocb->retry >= 32) delay = 1000; + } else if ((cmd == ELS_CMD_FDISC) && !lpfc_error_lost_link(irsp)) { + /* retry FDISCs every second up to devloss */ + retry = 1; + maxretry = vport->cfg_devloss_tmo; + delay = 1000; } cmdiocb->retry++; @@ -3389,11 +3454,17 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* * The driver received a LOGO from the rport and has ACK'd it. - * At this point, the driver is done so release the IOCB and - * remove the ndlp reference. + * At this point, the driver is done so release the IOCB */ lpfc_els_free_iocb(phba, cmdiocb); - lpfc_nlp_put(ndlp); + + /* + * Remove the ndlp reference if it's a fabric node that has + * sent us an unsolicted LOGO. + */ + if (ndlp->nlp_type & NLP_FABRIC) + lpfc_nlp_put(ndlp); + return; } @@ -4867,23 +4938,31 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, sizeof(struct lpfc_name)); if (!rc) { - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) + if (phba->sli_rev < LPFC_SLI_REV4) { + mbox = mempool_alloc(phba->mbox_mem_pool, + GFP_KERNEL); + if (!mbox) + return 1; + lpfc_linkdown(phba); + lpfc_init_link(phba, mbox, + phba->cfg_topology, + phba->cfg_link_speed); + mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0; + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + mbox->vport = vport; + rc = lpfc_sli_issue_mbox(phba, mbox, + MBX_NOWAIT); + lpfc_set_loopback_flag(phba); + if (rc == MBX_NOT_FINISHED) + mempool_free(mbox, phba->mbox_mem_pool); return 1; - - lpfc_linkdown(phba); - lpfc_init_link(phba, mbox, - phba->cfg_topology, - phba->cfg_link_speed); - mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0; - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - mbox->vport = vport; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - lpfc_set_loopback_flag(phba); - if (rc == MBX_NOT_FINISHED) { - mempool_free(mbox, phba->mbox_mem_pool); + } else { + /* abort the flogi coming back to ourselves + * due to external loopback on the port. + */ + lpfc_els_abort_flogi(phba); + return 0; } - return 1; } else if (rc > 0) { /* greater than */ spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_PT2PT_PLOGI; @@ -5838,8 +5917,12 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, vport->fc_myDID = vport->fc_prevDID; if (phba->sli_rev < LPFC_SLI_REV4) lpfc_issue_fabric_reglogin(vport); - else + else { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "3138 Need register VFI: (x%x/%x)\n", + vport->fc_prevDID, vport->fc_myDID); lpfc_issue_reg_vfi(vport); + } } } return 0; @@ -6596,56 +6679,6 @@ dropit: } /** - * lpfc_find_vport_by_vpid - Find a vport on a HBA through vport identifier - * @phba: pointer to lpfc hba data structure. - * @vpi: host virtual N_Port identifier. - * - * This routine finds a vport on a HBA (referred by @phba) through a - * @vpi. The function walks the HBA's vport list and returns the address - * of the vport with the matching @vpi. - * - * Return code - * NULL - No vport with the matching @vpi found - * Otherwise - Address to the vport with the matching @vpi. - **/ -struct lpfc_vport * -lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi) -{ - struct lpfc_vport *vport; - unsigned long flags; - int i = 0; - - /* The physical ports are always vpi 0 - translate is unnecessary. */ - if (vpi > 0) { - /* - * Translate the physical vpi to the logical vpi. The - * vport stores the logical vpi. - */ - for (i = 0; i < phba->max_vpi; i++) { - if (vpi == phba->vpi_ids[i]) - break; - } - - if (i >= phba->max_vpi) { - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, - "2936 Could not find Vport mapped " - "to vpi %d\n", vpi); - return NULL; - } - } - - spin_lock_irqsave(&phba->hbalock, flags); - list_for_each_entry(vport, &phba->port_list, listentry) { - if (vport->vpi == i) { - spin_unlock_irqrestore(&phba->hbalock, flags); - return vport; - } - } - spin_unlock_irqrestore(&phba->hbalock, flags); - return NULL; -} - -/** * lpfc_els_unsol_event - Process an unsolicited event from an els sli ring * @phba: pointer to lpfc hba data structure. * @pring: pointer to a SLI ring. @@ -7281,6 +7314,7 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Setup CSPs accordingly for Fabric */ sp->cmn.e_d_tov = 0; sp->cmn.w2.r_a_tov = 0; + sp->cmn.virtual_fabric_support = 0; sp->cls1.classValid = 0; sp->cls2.seqDelivery = 1; sp->cls3.seqDelivery = 1; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 091f68e5cb7..678a4b11059 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1074,6 +1074,12 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) mempool_free(pmb, phba->mbox_mem_pool); + /* don't perform discovery for SLI4 loopback diagnostic test */ + if ((phba->sli_rev == LPFC_SLI_REV4) && + !(phba->hba_flag & HBA_FCOE_MODE) && + (phba->link_flag & LS_LOOPBACK_MODE)) + return; + if (phba->fc_topology == LPFC_TOPOLOGY_LOOP && vport->fc_flag & FC_PUBLIC_LOOP && !(vport->fc_flag & FC_LBIT)) { @@ -2646,9 +2652,14 @@ lpfc_init_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { struct lpfc_vport *vport = mboxq->vport; - /* VFI not supported on interface type 0, just do the flogi */ - if (mboxq->u.mb.mbxStatus && (bf_get(lpfc_sli_intf_if_type, - &phba->sli4_hba.sli_intf) != LPFC_SLI_INTF_IF_TYPE_0)) { + /* + * VFI not supported on interface type 0, just do the flogi + * Also continue if the VFI is in use - just use the same one. + */ + if (mboxq->u.mb.mbxStatus && + (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != + LPFC_SLI_INTF_IF_TYPE_0) && + mboxq->u.mb.mbxStatus != MBX_VFI_IN_USE) { lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, "2891 Init VFI mailbox failed 0x%x\n", @@ -2842,10 +2853,10 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) lpfc_disc_list_loopmap(vport); /* Start discovery */ lpfc_disc_start(vport); - goto fail_free_mem; + goto out_free_mem; } lpfc_vport_set_state(vport, FC_VPORT_FAILED); - goto fail_free_mem; + goto out_free_mem; } /* The VPI is implicitly registered when the VFI is registered */ spin_lock_irq(shost->host_lock); @@ -2855,10 +2866,16 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI; spin_unlock_irq(shost->host_lock); + /* In case SLI4 FC loopback test, we are ready */ + if ((phba->sli_rev == LPFC_SLI_REV4) && + (phba->link_flag & LS_LOOPBACK_MODE)) { + phba->link_state = LPFC_HBA_READY; + goto out_free_mem; + } + if (vport->port_state == LPFC_FABRIC_CFG_LINK) { /* For private loop just start discovery and we are done. */ if ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) && - (phba->alpa_map[0] == 0) && !(vport->fc_flag & FC_PUBLIC_LOOP)) { /* Use loop map to make discovery list */ lpfc_disc_list_loopmap(vport); @@ -2870,7 +2887,7 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) } } -fail_free_mem: +out_free_mem: mempool_free(mboxq, phba->mbox_mem_pool); lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); kfree(dmabuf); @@ -2923,6 +2940,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) { struct lpfc_vport *vport = phba->pport; LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox = NULL; + struct Scsi_Host *shost; int i; struct lpfc_dmabuf *mp; int rc; @@ -2946,6 +2964,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) phba->fc_topology = bf_get(lpfc_mbx_read_top_topology, la); phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED; + shost = lpfc_shost_from_vport(vport); if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; @@ -2957,8 +2976,11 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) "1309 Link Up Event npiv not supported in loop " "topology\n"); /* Get Loop Map information */ - if (bf_get(lpfc_mbx_read_top_il, la)) + if (bf_get(lpfc_mbx_read_top_il, la)) { + spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_LBIT; + spin_unlock_irq(shost->host_lock); + } vport->fc_myDID = bf_get(lpfc_mbx_read_top_alpa_granted, la); i = la->lilpBde64.tus.f.bdeSize; @@ -3003,11 +3025,13 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) } else { if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) { if (phba->max_vpi && phba->cfg_enable_npiv && - (phba->sli_rev == 3)) + (phba->sli_rev >= LPFC_SLI_REV3)) phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED; } vport->fc_myDID = phba->fc_pref_DID; + spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_LBIT; + spin_unlock_irq(shost->host_lock); } spin_unlock_irq(&phba->hbalock); @@ -3224,15 +3248,14 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } else if (bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_DOWN) { phba->fc_stat.LinkDown++; - if (phba->link_flag & LS_LOOPBACK_MODE) { + if (phba->link_flag & LS_LOOPBACK_MODE) lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "1308 Link Down Event in loop back mode " "x%x received " "Data: x%x x%x x%x\n", la->eventTag, phba->fc_eventTag, phba->pport->port_state, vport->fc_flag); - } - else { + else lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "1305 Link Down Event x%x received " "Data: x%x x%x x%x x%x x%x\n", @@ -3240,7 +3263,6 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) phba->pport->port_state, vport->fc_flag, bf_get(lpfc_mbx_read_top_mm, la), bf_get(lpfc_mbx_read_top_fa, la)); - } lpfc_mbx_issue_link_down(phba); } if ((bf_get(lpfc_mbx_read_top_mm, la)) && @@ -3594,6 +3616,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) MAILBOX_t *mb = &pmb->u.mb; struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); struct lpfc_nodelist *ndlp; + struct Scsi_Host *shost; ndlp = (struct lpfc_nodelist *) pmb->context2; pmb->context1 = NULL; @@ -3639,8 +3662,12 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * vport discovery */ if (!(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG)) lpfc_start_fdiscs(phba); - else + else { + shost = lpfc_shost_from_vport(vport); + spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_LOGO_RCVD_DID_CHNG ; + spin_unlock_irq(shost->host_lock); + } lpfc_do_scr_ns_plogi(phba, vport); } @@ -5353,6 +5380,73 @@ lpfc_findnode_wwpn(struct lpfc_vport *vport, struct lpfc_name *wwpn) return ndlp; } +/* + * This routine looks up the ndlp lists for the given RPI. If the rpi + * is found, the routine returns the node element list pointer else + * return NULL. + */ +struct lpfc_nodelist * +lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi) +{ + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_nodelist *ndlp; + + spin_lock_irq(shost->host_lock); + ndlp = __lpfc_findnode_rpi(vport, rpi); + spin_unlock_irq(shost->host_lock); + return ndlp; +} + +/** + * lpfc_find_vport_by_vpid - Find a vport on a HBA through vport identifier + * @phba: pointer to lpfc hba data structure. + * @vpi: the physical host virtual N_Port identifier. + * + * This routine finds a vport on a HBA (referred by @phba) through a + * @vpi. The function walks the HBA's vport list and returns the address + * of the vport with the matching @vpi. + * + * Return code + * NULL - No vport with the matching @vpi found + * Otherwise - Address to the vport with the matching @vpi. + **/ +struct lpfc_vport * +lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi) +{ + struct lpfc_vport *vport; + unsigned long flags; + int i = 0; + + /* The physical ports are always vpi 0 - translate is unnecessary. */ + if (vpi > 0) { + /* + * Translate the physical vpi to the logical vpi. The + * vport stores the logical vpi. + */ + for (i = 0; i < phba->max_vpi; i++) { + if (vpi == phba->vpi_ids[i]) + break; + } + + if (i >= phba->max_vpi) { + lpfc_printf_log(phba, KERN_ERR, LOG_ELS, + "2936 Could not find Vport mapped " + "to vpi %d\n", vpi); + return NULL; + } + } + + spin_lock_irqsave(&phba->hbalock, flags); + list_for_each_entry(vport, &phba->port_list, listentry) { + if (vport->vpi == i) { + spin_unlock_irqrestore(&phba->hbalock, flags); + return vport; + } + } + spin_unlock_irqrestore(&phba->hbalock, flags); + return NULL; +} + void lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint32_t did) @@ -5599,7 +5693,7 @@ out: * * This function frees memory associated with the mailbox command. */ -static void +void lpfc_unregister_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { struct lpfc_vport *vport = mboxq->vport; @@ -5651,7 +5745,6 @@ lpfc_unregister_fcfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) int lpfc_unregister_fcf_prep(struct lpfc_hba *phba) { - LPFC_MBOXQ_t *mbox; struct lpfc_vport **vports; struct lpfc_nodelist *ndlp; struct Scsi_Host *shost; @@ -5687,35 +5780,9 @@ lpfc_unregister_fcf_prep(struct lpfc_hba *phba) /* Cleanup any outstanding ELS commands */ lpfc_els_flush_all_cmd(phba); - /* Unregister VFI */ - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, - "2556 UNREG_VFI mbox allocation failed" - "HBA state x%x\n", phba->pport->port_state); - return -ENOMEM; - } - - lpfc_unreg_vfi(mbox, phba->pport); - mbox->vport = phba->pport; - mbox->mbox_cmpl = lpfc_unregister_vfi_cmpl; - - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, - "2557 UNREG_VFI issue mbox failed rc x%x " - "HBA state x%x\n", - rc, phba->pport->port_state); - mempool_free(mbox, phba->mbox_mem_pool); - return -EIO; - } - - shost = lpfc_shost_from_vport(phba->pport); - spin_lock_irq(shost->host_lock); - phba->pport->fc_flag &= ~FC_VFI_REGISTERED; - spin_unlock_irq(shost->host_lock); - - return 0; + /* Unregister the physical port VFI */ + rc = lpfc_issue_unreg_vfi(phba->pport); + return rc; } /** diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 046edc4ab35..7245bead375 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -349,6 +349,12 @@ struct csp { * Word 1 Bit 31 in FLOGI response is clean address bit */ #define clean_address_bit request_multiple_Nport /* Word 1, bit 31 */ +/* + * Word 1 Bit 30 in common service parameter is overloaded. + * Word 1 Bit 30 in FLOGI request is Virtual Fabrics + * Word 1 Bit 30 in PLOGI request is random offset + */ +#define virtual_fabric_support randomOffset /* Word 1, bit 30 */ #ifdef __BIG_ENDIAN_BITFIELD uint16_t request_multiple_Nport:1; /* FC Word 1, bit 31 */ uint16_t randomOffset:1; /* FC Word 1, bit 30 */ @@ -1852,8 +1858,8 @@ typedef struct { uint8_t fabric_AL_PA; /* If using a Fabric Assigned AL_PA */ #endif -#define FLAGS_LOCAL_LB 0x01 /* link_flags (=1) ENDEC loopback */ #define FLAGS_TOPOLOGY_MODE_LOOP_PT 0x00 /* Attempt loop then pt-pt */ +#define FLAGS_LOCAL_LB 0x01 /* link_flags (=1) ENDEC loopback */ #define FLAGS_TOPOLOGY_MODE_PT_PT 0x02 /* Attempt pt-pt only */ #define FLAGS_TOPOLOGY_MODE_LOOP 0x04 /* Attempt loop only */ #define FLAGS_TOPOLOGY_MODE_PT_LOOP 0x06 /* Attempt pt-pt then loop */ @@ -2819,7 +2825,8 @@ typedef struct { #ifdef __BIG_ENDIAN_BITFIELD uint32_t rsvd1 : 19; /* Reserved */ uint32_t cdss : 1; /* Configure Data Security SLI */ - uint32_t rsvd2 : 3; /* Reserved */ + uint32_t casabt : 1; /* Configure async abts status notice */ + uint32_t rsvd2 : 2; /* Reserved */ uint32_t cbg : 1; /* Configure BlockGuard */ uint32_t cmv : 1; /* Configure Max VPIs */ uint32_t ccrp : 1; /* Config Command Ring Polling */ @@ -2839,14 +2846,16 @@ typedef struct { uint32_t ccrp : 1; /* Config Command Ring Polling */ uint32_t cmv : 1; /* Configure Max VPIs */ uint32_t cbg : 1; /* Configure BlockGuard */ - uint32_t rsvd2 : 3; /* Reserved */ + uint32_t rsvd2 : 2; /* Reserved */ + uint32_t casabt : 1; /* Configure async abts status notice */ uint32_t cdss : 1; /* Configure Data Security SLI */ uint32_t rsvd1 : 19; /* Reserved */ #endif #ifdef __BIG_ENDIAN_BITFIELD uint32_t rsvd3 : 19; /* Reserved */ uint32_t gdss : 1; /* Configure Data Security SLI */ - uint32_t rsvd4 : 3; /* Reserved */ + uint32_t gasabt : 1; /* Grant async abts status notice */ + uint32_t rsvd4 : 2; /* Reserved */ uint32_t gbg : 1; /* Grant BlockGuard */ uint32_t gmv : 1; /* Grant Max VPIs */ uint32_t gcrp : 1; /* Grant Command Ring Polling */ @@ -2866,7 +2875,8 @@ typedef struct { uint32_t gcrp : 1; /* Grant Command Ring Polling */ uint32_t gmv : 1; /* Grant Max VPIs */ uint32_t gbg : 1; /* Grant BlockGuard */ - uint32_t rsvd4 : 3; /* Reserved */ + uint32_t rsvd4 : 2; /* Reserved */ + uint32_t gasabt : 1; /* Grant async abts status notice */ uint32_t gdss : 1; /* Configure Data Security SLI */ uint32_t rsvd3 : 19; /* Reserved */ #endif @@ -3465,6 +3475,7 @@ typedef struct { } ASYNCSTAT_FIELDS; #define ASYNC_TEMP_WARN 0x100 #define ASYNC_TEMP_SAFE 0x101 +#define ASYNC_STATUS_CN 0x102 /* IOCB Command template for CMD_IOCB_RCV_ELS64_CX (0xB7) or CMD_IOCB_RCV_SEQ64_CX (0xB5) */ diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 98d21521f53..e5bfa7f334e 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1351,11 +1351,11 @@ struct lpfc_mbx_set_link_diag_loopback { struct { uint32_t word0; #define lpfc_mbx_set_diag_lpbk_type_SHIFT 0 -#define lpfc_mbx_set_diag_lpbk_type_MASK 0x00000001 +#define lpfc_mbx_set_diag_lpbk_type_MASK 0x00000003 #define lpfc_mbx_set_diag_lpbk_type_WORD word0 #define LPFC_DIAG_LOOPBACK_TYPE_DISABLE 0x0 #define LPFC_DIAG_LOOPBACK_TYPE_INTERNAL 0x1 -#define LPFC_DIAG_LOOPBACK_TYPE_EXTERNAL 0x2 +#define LPFC_DIAG_LOOPBACK_TYPE_SERDES 0x2 #define lpfc_mbx_set_diag_lpbk_link_num_SHIFT 16 #define lpfc_mbx_set_diag_lpbk_link_num_MASK 0x0000003F #define lpfc_mbx_set_diag_lpbk_link_num_WORD word0 @@ -1830,6 +1830,8 @@ struct lpfc_mbx_init_vfi { #define lpfc_init_vfi_hop_count_MASK 0x000000FF #define lpfc_init_vfi_hop_count_WORD word4 }; +#define MBX_VFI_IN_USE 0x9F02 + struct lpfc_mbx_reg_vfi { uint32_t word1; @@ -2104,6 +2106,8 @@ struct lpfc_mbx_read_config { #define lpfc_mbx_rd_conf_lnk_type_SHIFT 6 #define lpfc_mbx_rd_conf_lnk_type_MASK 0x00000003 #define lpfc_mbx_rd_conf_lnk_type_WORD word2 +#define LPFC_LNK_TYPE_GE 0 +#define LPFC_LNK_TYPE_FC 1 #define lpfc_mbx_rd_conf_lnk_ldv_SHIFT 8 #define lpfc_mbx_rd_conf_lnk_ldv_MASK 0x00000001 #define lpfc_mbx_rd_conf_lnk_ldv_WORD word2 @@ -3320,6 +3324,9 @@ struct wqe_rctl_dfctl { #define wqe_la_SHIFT 3 #define wqe_la_MASK 0x000000001 #define wqe_la_WORD word5 +#define wqe_xo_SHIFT 6 +#define wqe_xo_MASK 0x000000001 +#define wqe_xo_WORD word5 #define wqe_ls_SHIFT 7 #define wqe_ls_MASK 0x000000001 #define wqe_ls_WORD word5 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 55bc4fc7376..dfea2dada02 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -62,7 +62,6 @@ static int lpfc_post_rcv_buf(struct lpfc_hba *); static int lpfc_sli4_queue_verify(struct lpfc_hba *); static int lpfc_create_bootstrap_mbox(struct lpfc_hba *); static int lpfc_setup_endian_order(struct lpfc_hba *); -static int lpfc_sli4_read_config(struct lpfc_hba *); static void lpfc_destroy_bootstrap_mbox(struct lpfc_hba *); static void lpfc_free_sgl_list(struct lpfc_hba *); static int lpfc_init_sgl_list(struct lpfc_hba *); @@ -475,27 +474,6 @@ lpfc_config_port_post(struct lpfc_hba *phba) /* Get the default values for Model Name and Description */ lpfc_get_hba_model_desc(phba, phba->ModelName, phba->ModelDesc); - if ((phba->cfg_link_speed > LPFC_USER_LINK_SPEED_16G) - || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_1G) - && !(phba->lmt & LMT_1Gb)) - || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_2G) - && !(phba->lmt & LMT_2Gb)) - || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_4G) - && !(phba->lmt & LMT_4Gb)) - || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_8G) - && !(phba->lmt & LMT_8Gb)) - || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_10G) - && !(phba->lmt & LMT_10Gb)) - || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_16G) - && !(phba->lmt & LMT_16Gb))) { - /* Reset link speed to auto */ - lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, - "1302 Invalid speed for this board: " - "Reset link speed to auto: x%x\n", - phba->cfg_link_speed); - phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO; - } - phba->link_state = LPFC_LINK_DOWN; /* Only process IOCBs on ELS ring till hba_state is READY */ @@ -585,28 +563,10 @@ lpfc_config_port_post(struct lpfc_hba *phba) return -EIO; } } else if (phba->cfg_suppress_link_up == LPFC_INITIALIZE_LINK) { - lpfc_init_link(phba, pmb, phba->cfg_topology, - phba->cfg_link_speed); - pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - lpfc_set_loopback_flag(phba); - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0454 Adapter failed to init, mbxCmd x%x " - "INIT_LINK, mbxStatus x%x\n", - mb->mbxCommand, mb->mbxStatus); - - /* Clear all interrupt enable conditions */ - writel(0, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - /* Clear all pending interrupts */ - writel(0xffffffff, phba->HAregaddr); - readl(phba->HAregaddr); /* flush */ - phba->link_state = LPFC_HBA_ERROR; - if (rc != MBX_BUSY) - mempool_free(pmb, phba->mbox_mem_pool); - return -EIO; - } + mempool_free(pmb, phba->mbox_mem_pool); + rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT); + if (rc) + return rc; } /* MBOX buffer will be freed in mbox compl */ pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -668,6 +628,28 @@ lpfc_config_port_post(struct lpfc_hba *phba) int lpfc_hba_init_link(struct lpfc_hba *phba, uint32_t flag) { + return lpfc_hba_init_link_fc_topology(phba, phba->cfg_topology, flag); +} + +/** + * lpfc_hba_init_link_fc_topology - Initialize FC link with desired topology + * @phba: pointer to lpfc hba data structure. + * @fc_topology: desired fc topology. + * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT + * + * This routine will issue the INIT_LINK mailbox command call. + * It is available to other drivers through the lpfc_hba data + * structure for use as a delayed link up mechanism with the + * module parameter lpfc_suppress_link_up. + * + * Return code + * 0 - success + * Any other value - error + **/ +int +lpfc_hba_init_link_fc_topology(struct lpfc_hba *phba, uint32_t fc_topology, + uint32_t flag) +{ struct lpfc_vport *vport = phba->pport; LPFC_MBOXQ_t *pmb; MAILBOX_t *mb; @@ -681,9 +663,30 @@ lpfc_hba_init_link(struct lpfc_hba *phba, uint32_t flag) mb = &pmb->u.mb; pmb->vport = vport; - lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed); + if ((phba->cfg_link_speed > LPFC_USER_LINK_SPEED_MAX) || + ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_1G) && + !(phba->lmt & LMT_1Gb)) || + ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_2G) && + !(phba->lmt & LMT_2Gb)) || + ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_4G) && + !(phba->lmt & LMT_4Gb)) || + ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_8G) && + !(phba->lmt & LMT_8Gb)) || + ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_10G) && + !(phba->lmt & LMT_10Gb)) || + ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_16G) && + !(phba->lmt & LMT_16Gb))) { + /* Reset link speed to auto */ + lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, + "1302 Invalid speed for this board:%d " + "Reset link speed to auto.\n", + phba->cfg_link_speed); + phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO; + } + lpfc_init_link(phba, pmb, fc_topology, phba->cfg_link_speed); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - lpfc_set_loopback_flag(phba); + if (phba->sli_rev < LPFC_SLI_REV4) + lpfc_set_loopback_flag(phba); rc = lpfc_sli_issue_mbox(phba, pmb, flag); if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -1437,7 +1440,10 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) uint32_t event_data; struct Scsi_Host *shost; uint32_t if_type; - struct lpfc_register portstat_reg; + struct lpfc_register portstat_reg = {0}; + uint32_t reg_err1, reg_err2; + uint32_t uerrlo_reg, uemasklo_reg; + uint32_t pci_rd_rc1, pci_rd_rc2; int rc; /* If the pci channel is offline, ignore possible errors, since @@ -1449,38 +1455,52 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) if (!phba->cfg_enable_hba_reset) return; - /* Send an internal error event to mgmt application */ - lpfc_board_errevt_to_mgmt(phba); - - /* For now, the actual action for SLI4 device handling is not - * specified yet, just treated it as adaptor hardware failure - */ - event_data = FC_REG_DUMP_EVENT; - shost = lpfc_shost_from_vport(vport); - fc_host_post_vendor_event(shost, fc_get_event_number(), - sizeof(event_data), (char *) &event_data, - SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); - if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); switch (if_type) { case LPFC_SLI_INTF_IF_TYPE_0: + pci_rd_rc1 = lpfc_readl( + phba->sli4_hba.u.if_type0.UERRLOregaddr, + &uerrlo_reg); + pci_rd_rc2 = lpfc_readl( + phba->sli4_hba.u.if_type0.UEMASKLOregaddr, + &uemasklo_reg); + /* consider PCI bus read error as pci_channel_offline */ + if (pci_rd_rc1 == -EIO && pci_rd_rc2 == -EIO) + return; lpfc_sli4_offline_eratt(phba); break; case LPFC_SLI_INTF_IF_TYPE_2: - portstat_reg.word0 = - readl(phba->sli4_hba.u.if_type2.STATUSregaddr); - + pci_rd_rc1 = lpfc_readl( + phba->sli4_hba.u.if_type2.STATUSregaddr, + &portstat_reg.word0); + /* consider PCI bus read error as pci_channel_offline */ + if (pci_rd_rc1 == -EIO) + return; + reg_err1 = readl(phba->sli4_hba.u.if_type2.ERR1regaddr); + reg_err2 = readl(phba->sli4_hba.u.if_type2.ERR2regaddr); if (bf_get(lpfc_sliport_status_oti, &portstat_reg)) { /* TODO: Register for Overtemp async events. */ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2889 Port Overtemperature event, " - "taking port\n"); + "taking port offline\n"); spin_lock_irq(&phba->hbalock); phba->over_temp_state = HBA_OVER_TEMP; spin_unlock_irq(&phba->hbalock); lpfc_sli4_offline_eratt(phba); - return; + break; } + if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && + reg_err2 == SLIPORT_ERR2_REG_FW_RESTART) + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3143 Port Down: Firmware Restarted\n"); + else if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && + reg_err2 == SLIPORT_ERR2_REG_FORCED_DUMP) + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3144 Port Down: Debug Dump\n"); + else if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && + reg_err2 == SLIPORT_ERR2_REG_FUNC_PROVISON) + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3145 Port Down: Provisioning\n"); /* * On error status condition, driver need to wait for port * ready before performing reset. @@ -1489,14 +1509,19 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) if (!rc) { /* need reset: attempt for port recovery */ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2887 Port Error: Attempting " - "Port Recovery\n"); + "2887 Reset Needed: Attempting Port " + "Recovery...\n"); lpfc_offline_prep(phba); lpfc_offline(phba); lpfc_sli_brdrestart(phba); if (lpfc_online(phba) == 0) { lpfc_unblock_mgmt_io(phba); - return; + /* don't report event on forced debug dump */ + if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && + reg_err2 == SLIPORT_ERR2_REG_FORCED_DUMP) + return; + else + break; } /* fall through for not able to recover */ } @@ -1506,6 +1531,16 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) default: break; } + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "3123 Report dump event to upper layer\n"); + /* Send an internal error event to mgmt application */ + lpfc_board_errevt_to_mgmt(phba); + + event_data = FC_REG_DUMP_EVENT; + shost = lpfc_shost_from_vport(vport); + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(event_data), (char *) &event_data, + SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); } /** @@ -2674,6 +2709,32 @@ lpfc_offline(struct lpfc_hba *phba) } /** + * lpfc_scsi_buf_update - Update the scsi_buffers that are already allocated. + * @phba: pointer to lpfc hba data structure. + * + * This routine goes through all the scsi buffers in the system and updates the + * Physical XRIs assigned to the SCSI buffer because these may change after any + * firmware reset + * + * Return codes + * 0 - successful (for now, it always returns 0) + **/ +int +lpfc_scsi_buf_update(struct lpfc_hba *phba) +{ + struct lpfc_scsi_buf *sb, *sb_next; + + spin_lock_irq(&phba->hbalock); + spin_lock(&phba->scsi_buf_list_lock); + list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) + sb->cur_iocbq.sli4_xritag = + phba->sli4_hba.xri_ids[sb->cur_iocbq.sli4_lxritag]; + spin_unlock(&phba->scsi_buf_list_lock); + spin_unlock_irq(&phba->hbalock); + return 0; +} + +/** * lpfc_scsi_free - Free all the SCSI buffers and IOCBs from driver lists * @phba: pointer to lpfc hba data structure. * @@ -5040,15 +5101,8 @@ lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *phba) struct lpfc_rpi_hdr *rpi_hdr; INIT_LIST_HEAD(&phba->sli4_hba.lpfc_rpi_hdr_list); - /* - * If the SLI4 port supports extents, posting the rpi header isn't - * required. Set the expected maximum count and let the actual value - * get set when extents are fully allocated. - */ - if (!phba->sli4_hba.rpi_hdrs_in_use) { - phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.max_rpi; + if (!phba->sli4_hba.rpi_hdrs_in_use) return rc; - } if (phba->sli4_hba.extents_in_use) return -EIO; @@ -5942,7 +5996,7 @@ lpfc_destroy_bootstrap_mbox(struct lpfc_hba *phba) * -ENOMEM - No available memory * -EIO - The mailbox failed to complete successfully. **/ -static int +int lpfc_sli4_read_config(struct lpfc_hba *phba) { LPFC_MBOXQ_t *pmb; @@ -5974,6 +6028,20 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) rc = -EIO; } else { rd_config = &pmb->u.mqe.un.rd_config; + if (bf_get(lpfc_mbx_rd_conf_lnk_ldv, rd_config)) { + phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_VAL; + phba->sli4_hba.lnk_info.lnk_tp = + bf_get(lpfc_mbx_rd_conf_lnk_type, rd_config); + phba->sli4_hba.lnk_info.lnk_no = + bf_get(lpfc_mbx_rd_conf_lnk_numb, rd_config); + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3081 lnk_type:%d, lnk_numb:%d\n", + phba->sli4_hba.lnk_info.lnk_tp, + phba->sli4_hba.lnk_info.lnk_no); + } else + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "3082 Mailbox (x%x) returned ldv:x0\n", + bf_get(lpfc_mqe_command, &pmb->u.mqe)); phba->sli4_hba.extents_in_use = bf_get(lpfc_mbx_rd_conf_extnts_inuse, rd_config); phba->sli4_hba.max_cfg_param.max_xri = @@ -6462,6 +6530,7 @@ out_free_fcp_wq: phba->sli4_hba.fcp_wq[fcp_wqidx] = NULL; } kfree(phba->sli4_hba.fcp_wq); + phba->sli4_hba.fcp_wq = NULL; out_free_els_wq: lpfc_sli4_queue_free(phba->sli4_hba.els_wq); phba->sli4_hba.els_wq = NULL; @@ -6474,6 +6543,7 @@ out_free_fcp_cq: phba->sli4_hba.fcp_cq[fcp_cqidx] = NULL; } kfree(phba->sli4_hba.fcp_cq); + phba->sli4_hba.fcp_cq = NULL; out_free_els_cq: lpfc_sli4_queue_free(phba->sli4_hba.els_cq); phba->sli4_hba.els_cq = NULL; @@ -6486,6 +6556,7 @@ out_free_fp_eq: phba->sli4_hba.fp_eq[fcp_eqidx] = NULL; } kfree(phba->sli4_hba.fp_eq); + phba->sli4_hba.fp_eq = NULL; out_free_sp_eq: lpfc_sli4_queue_free(phba->sli4_hba.sp_eq); phba->sli4_hba.sp_eq = NULL; @@ -6519,8 +6590,10 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba) phba->sli4_hba.els_wq = NULL; /* Release FCP work queue */ - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; fcp_qidx++) - lpfc_sli4_queue_free(phba->sli4_hba.fcp_wq[fcp_qidx]); + if (phba->sli4_hba.fcp_wq != NULL) + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; + fcp_qidx++) + lpfc_sli4_queue_free(phba->sli4_hba.fcp_wq[fcp_qidx]); kfree(phba->sli4_hba.fcp_wq); phba->sli4_hba.fcp_wq = NULL; @@ -6540,15 +6613,18 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba) /* Release FCP response complete queue */ fcp_qidx = 0; - do - lpfc_sli4_queue_free(phba->sli4_hba.fcp_cq[fcp_qidx]); - while (++fcp_qidx < phba->cfg_fcp_eq_count); + if (phba->sli4_hba.fcp_cq != NULL) + do + lpfc_sli4_queue_free(phba->sli4_hba.fcp_cq[fcp_qidx]); + while (++fcp_qidx < phba->cfg_fcp_eq_count); kfree(phba->sli4_hba.fcp_cq); phba->sli4_hba.fcp_cq = NULL; /* Release fast-path event queue */ - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) - lpfc_sli4_queue_free(phba->sli4_hba.fp_eq[fcp_qidx]); + if (phba->sli4_hba.fp_eq != NULL) + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; + fcp_qidx++) + lpfc_sli4_queue_free(phba->sli4_hba.fp_eq[fcp_qidx]); kfree(phba->sli4_hba.fp_eq); phba->sli4_hba.fp_eq = NULL; @@ -6601,11 +6677,18 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.sp_eq->queue_id); /* Set up fast-path event queue */ + if (phba->cfg_fcp_eq_count && !phba->sli4_hba.fp_eq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3147 Fast-path EQs not allocated\n"); + rc = -ENOMEM; + goto out_destroy_sp_eq; + } for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) { if (!phba->sli4_hba.fp_eq[fcp_eqidx]) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0522 Fast-path EQ (%d) not " "allocated\n", fcp_eqidx); + rc = -ENOMEM; goto out_destroy_fp_eq; } rc = lpfc_eq_create(phba, phba->sli4_hba.fp_eq[fcp_eqidx], @@ -6630,6 +6713,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) if (!phba->sli4_hba.mbx_cq) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0528 Mailbox CQ not allocated\n"); + rc = -ENOMEM; goto out_destroy_fp_eq; } rc = lpfc_cq_create(phba, phba->sli4_hba.mbx_cq, phba->sli4_hba.sp_eq, @@ -6649,6 +6733,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) if (!phba->sli4_hba.els_cq) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0530 ELS CQ not allocated\n"); + rc = -ENOMEM; goto out_destroy_mbx_cq; } rc = lpfc_cq_create(phba, phba->sli4_hba.els_cq, phba->sli4_hba.sp_eq, @@ -6665,12 +6750,20 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.sp_eq->queue_id); /* Set up fast-path FCP Response Complete Queue */ + if (!phba->sli4_hba.fcp_cq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3148 Fast-path FCP CQ array not " + "allocated\n"); + rc = -ENOMEM; + goto out_destroy_els_cq; + } fcp_cqidx = 0; do { if (!phba->sli4_hba.fcp_cq[fcp_cqidx]) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0526 Fast-path FCP CQ (%d) not " "allocated\n", fcp_cqidx); + rc = -ENOMEM; goto out_destroy_fcp_cq; } if (phba->cfg_fcp_eq_count) @@ -6709,6 +6802,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) if (!phba->sli4_hba.mbx_wq) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0538 Slow-path MQ not allocated\n"); + rc = -ENOMEM; goto out_destroy_fcp_cq; } rc = lpfc_mq_create(phba, phba->sli4_hba.mbx_wq, @@ -6728,6 +6822,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) if (!phba->sli4_hba.els_wq) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0536 Slow-path ELS WQ not allocated\n"); + rc = -ENOMEM; goto out_destroy_mbx_wq; } rc = lpfc_wq_create(phba, phba->sli4_hba.els_wq, @@ -6744,11 +6839,19 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.els_cq->queue_id); /* Set up fast-path FCP Work Queue */ + if (!phba->sli4_hba.fcp_wq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3149 Fast-path FCP WQ array not " + "allocated\n"); + rc = -ENOMEM; + goto out_destroy_els_wq; + } for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) { if (!phba->sli4_hba.fcp_wq[fcp_wqidx]) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0534 Fast-path FCP WQ (%d) not " "allocated\n", fcp_wqidx); + rc = -ENOMEM; goto out_destroy_fcp_wq; } rc = lpfc_wq_create(phba, phba->sli4_hba.fcp_wq[fcp_wqidx], @@ -6779,6 +6882,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) if (!phba->sli4_hba.hdr_rq || !phba->sli4_hba.dat_rq) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0540 Receive Queue not allocated\n"); + rc = -ENOMEM; goto out_destroy_fcp_wq; } @@ -6805,18 +6909,21 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) out_destroy_fcp_wq: for (--fcp_wqidx; fcp_wqidx >= 0; fcp_wqidx--) lpfc_wq_destroy(phba, phba->sli4_hba.fcp_wq[fcp_wqidx]); +out_destroy_els_wq: lpfc_wq_destroy(phba, phba->sli4_hba.els_wq); out_destroy_mbx_wq: lpfc_mq_destroy(phba, phba->sli4_hba.mbx_wq); out_destroy_fcp_cq: for (--fcp_cqidx; fcp_cqidx >= 0; fcp_cqidx--) lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_cqidx]); +out_destroy_els_cq: lpfc_cq_destroy(phba, phba->sli4_hba.els_cq); out_destroy_mbx_cq: lpfc_cq_destroy(phba, phba->sli4_hba.mbx_cq); out_destroy_fp_eq: for (--fcp_eqidx; fcp_eqidx >= 0; fcp_eqidx--) lpfc_eq_destroy(phba, phba->sli4_hba.fp_eq[fcp_eqidx]); +out_destroy_sp_eq: lpfc_eq_destroy(phba, phba->sli4_hba.sp_eq); out_error: return rc; @@ -6853,13 +6960,18 @@ lpfc_sli4_queue_unset(struct lpfc_hba *phba) /* Unset ELS complete queue */ lpfc_cq_destroy(phba, phba->sli4_hba.els_cq); /* Unset FCP response complete queue */ - fcp_qidx = 0; - do { - lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_qidx]); - } while (++fcp_qidx < phba->cfg_fcp_eq_count); + if (phba->sli4_hba.fcp_cq) { + fcp_qidx = 0; + do { + lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_qidx]); + } while (++fcp_qidx < phba->cfg_fcp_eq_count); + } /* Unset fast-path event queue */ - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) - lpfc_eq_destroy(phba, phba->sli4_hba.fp_eq[fcp_qidx]); + if (phba->sli4_hba.fp_eq) { + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; + fcp_qidx++) + lpfc_eq_destroy(phba, phba->sli4_hba.fp_eq[fcp_qidx]); + } /* Unset slow-path event queue */ lpfc_eq_destroy(phba, phba->sli4_hba.sp_eq); } @@ -7398,22 +7510,25 @@ out: static void lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba) { - struct pci_dev *pdev; - - /* Obtain PCI device reference */ - if (!phba->pcidev) - return; - else - pdev = phba->pcidev; - - /* Free coherent DMA memory allocated */ - - /* Unmap I/O memory space */ - iounmap(phba->sli4_hba.drbl_regs_memmap_p); - iounmap(phba->sli4_hba.ctrl_regs_memmap_p); - iounmap(phba->sli4_hba.conf_regs_memmap_p); + uint32_t if_type; + if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); - return; + switch (if_type) { + case LPFC_SLI_INTF_IF_TYPE_0: + iounmap(phba->sli4_hba.drbl_regs_memmap_p); + iounmap(phba->sli4_hba.ctrl_regs_memmap_p); + iounmap(phba->sli4_hba.conf_regs_memmap_p); + break; + case LPFC_SLI_INTF_IF_TYPE_2: + iounmap(phba->sli4_hba.conf_regs_memmap_p); + break; + case LPFC_SLI_INTF_IF_TYPE_1: + default: + dev_printk(KERN_ERR, &phba->pcidev->dev, + "FATAL - unsupported SLI4 interface type - %d\n", + if_type); + break; + } } /** @@ -9198,12 +9313,15 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) /* Perform post initialization setup */ lpfc_post_init_setup(phba); - /* check for firmware upgrade or downgrade */ - snprintf(file_name, 16, "%s.grp", phba->ModelName); - error = request_firmware(&fw, file_name, &phba->pcidev->dev); - if (!error) { - lpfc_write_firmware(phba, fw); - release_firmware(fw); + /* check for firmware upgrade or downgrade (if_type 2 only) */ + if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == + LPFC_SLI_INTF_IF_TYPE_2) { + snprintf(file_name, 16, "%s.grp", phba->ModelName); + error = request_firmware(&fw, file_name, &phba->pcidev->dev); + if (!error) { + lpfc_write_firmware(phba, fw); + release_firmware(fw); + } } /* Check if there are static vports to be created. */ diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 2ebc7d2540c..20336f09fb3 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1293,6 +1293,10 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) phba->sli_rev = LPFC_SLI_REV2; mb->un.varCfgPort.sli_mode = phba->sli_rev; + /* If this is an SLI3 port, configure async status notification. */ + if (phba->sli_rev == LPFC_SLI_REV3) + mb->un.varCfgPort.casabt = 1; + /* Now setup pcb */ phba->pcb->type = TYPE_NATIVE_SLI2; phba->pcb->feature = FEATURE_INITIAL_SLI2; @@ -2129,6 +2133,14 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys) reg_vfi->bde.tus.f.bdeSize = sizeof(vport->fc_sparam); reg_vfi->bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64; bf_set(lpfc_reg_vfi_nport_id, reg_vfi, vport->fc_myDID); + lpfc_printf_vlog(vport, KERN_INFO, LOG_MBOX, + "3134 Register VFI, mydid:x%x, fcfi:%d, " + " vfi:%d, vpi:%d, fc_pname:%x%x\n", + vport->fc_myDID, + vport->phba->fcf.fcfi, + vport->phba->sli4_hba.vfi_ids[vport->vfi], + vport->phba->vpi_ids[vport->vpi], + reg_vfi->wwn[0], reg_vfi->wwn[1]); } /** @@ -2175,16 +2187,15 @@ lpfc_unreg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport) } /** - * lpfc_dump_fcoe_param - Dump config region 23 to get FCoe parameters. + * lpfc_sli4_dump_cfg_rg23 - Dump sli4 port config region 23 * @phba: pointer to the hba structure containing. * @mbox: pointer to lpfc mbox command to initialize. * - * This function create a SLI4 dump mailbox command to dump FCoE - * parameters stored in region 23. + * This function create a SLI4 dump mailbox command to dump configure + * region 23. **/ int -lpfc_dump_fcoe_param(struct lpfc_hba *phba, - struct lpfcMboxq *mbox) +lpfc_sli4_dump_cfg_rg23(struct lpfc_hba *phba, struct lpfcMboxq *mbox) { struct lpfc_dmabuf *mp = NULL; MAILBOX_t *mb; @@ -2198,9 +2209,9 @@ lpfc_dump_fcoe_param(struct lpfc_hba *phba, if (!mp || !mp->virt) { kfree(mp); - /* dump_fcoe_param failed to allocate memory */ + /* dump config region 23 failed to allocate memory */ lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, - "2569 lpfc_dump_fcoe_param: memory" + "2569 lpfc dump config region 23: memory" " allocation failed\n"); return 1; } diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 10d5b5e4149..ade763d3930 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -389,7 +389,7 @@ lpfc_els_hbq_alloc(struct lpfc_hba *phba) { struct hbq_dmabuf *hbqbp; - hbqbp = kmalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL); + hbqbp = kzalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL); if (!hbqbp) return NULL; @@ -441,7 +441,7 @@ lpfc_sli4_rb_alloc(struct lpfc_hba *phba) { struct hbq_dmabuf *dma_buf; - dma_buf = kmalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL); + dma_buf = kzalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL); if (!dma_buf) return NULL; diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 2ddd02f7c60..e8bb0055994 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -783,6 +783,14 @@ lpfc_device_rm_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, } static uint32_t +lpfc_device_recov_unused_node(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp, + void *arg, uint32_t evt) +{ + return ndlp->nlp_state; +} + +static uint32_t lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { @@ -2147,7 +2155,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT]) lpfc_disc_illegal, /* CMPL_ADISC */ lpfc_disc_illegal, /* CMPL_REG_LOGIN */ lpfc_device_rm_unused_node, /* DEVICE_RM */ - lpfc_disc_illegal, /* DEVICE_RECOVERY */ + lpfc_device_recov_unused_node, /* DEVICE_RECOVERY */ lpfc_rcv_plogi_plogi_issue, /* RCV_PLOGI PLOGI_ISSUE */ lpfc_rcv_prli_plogi_issue, /* RCV_PRLI */ diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 2e1e54e5c3a..c60f5d0b386 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -681,8 +681,10 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, rrq_empty = list_empty(&phba->active_rrq_list); spin_unlock_irqrestore(&phba->hbalock, iflag); - if (ndlp) + if (ndlp) { lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1); + lpfc_sli4_abts_err_handler(phba, ndlp, axri); + } lpfc_release_scsi_buf_s4(phba, psb); if (rrq_empty) lpfc_worker_wake_up(phba); @@ -2911,8 +2913,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, int_to_scsilun(lpfc_cmd->pCmd->device->lun, &lpfc_cmd->fcp_cmnd->fcp_lun); - memcpy(&fcp_cmnd->fcpCdb[0], scsi_cmnd->cmnd, 16); - + memset(&fcp_cmnd->fcpCdb[0], 0, LPFC_FCP_CDB_LEN); + memcpy(&fcp_cmnd->fcpCdb[0], scsi_cmnd->cmnd, scsi_cmnd->cmd_len); if (scsi_populate_tag_msg(scsi_cmnd, tag)) { switch (tag[0]) { case HEAD_OF_QUEUE_TAG: @@ -3236,6 +3238,15 @@ lpfc_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) cmnd->result = err; goto out_fail_command; } + /* + * Do not let the mid-layer retry I/O too fast. If an I/O is retried + * without waiting a bit then indicate that the device is busy. + */ + if (cmnd->retries && + time_before(jiffies, (cmnd->jiffies_at_alloc + + msecs_to_jiffies(LPFC_RETRY_PAUSE * + cmnd->retries)))) + return SCSI_MLQUEUE_DEVICE_BUSY; ndlp = rdata->pnode; if ((scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) && diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index ce645b20a6a..9075a08cf78 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -21,6 +21,7 @@ #include <asm/byteorder.h> struct lpfc_hba; +#define LPFC_FCP_CDB_LEN 16 #define list_remove_head(list, entry, type, member) \ do { \ @@ -102,7 +103,7 @@ struct fcp_cmnd { #define WRITE_DATA 0x01 /* Bit 0 */ #define READ_DATA 0x02 /* Bit 1 */ - uint8_t fcpCdb[16]; /* SRB cdb field is copied here */ + uint8_t fcpCdb[LPFC_FCP_CDB_LEN]; /* SRB cdb field is copied here */ uint32_t fcpDl; /* Total transfer length */ }; @@ -153,5 +154,5 @@ struct lpfc_scsi_buf { #define LPFC_SCSI_DMA_EXT_SIZE 264 #define LPFC_BPL_SIZE 1024 - +#define LPFC_RETRY_PAUSE 300 #define MDAC_DIRECT_CMD 0x22 diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 4d4104f38c9..23a27592388 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -89,15 +89,20 @@ lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) static uint32_t lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) { - union lpfc_wqe *temp_wqe = q->qe[q->host_index].wqe; + union lpfc_wqe *temp_wqe; struct lpfc_register doorbell; uint32_t host_index; + /* sanity check on queue memory */ + if (unlikely(!q)) + return -ENOMEM; + temp_wqe = q->qe[q->host_index].wqe; + /* If the host has not yet processed the next entry then we are done */ if (((q->host_index + 1) % q->entry_count) == q->hba_index) return -ENOMEM; /* set consumption flag every once in a while */ - if (!((q->host_index + 1) % LPFC_RELEASE_NOTIFICATION_INTERVAL)) + if (!((q->host_index + 1) % q->entry_repost)) bf_set(wqe_wqec, &wqe->generic.wqe_com, 1); if (q->phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED) bf_set(wqe_wqid, &wqe->generic.wqe_com, q->queue_id); @@ -134,6 +139,10 @@ lpfc_sli4_wq_release(struct lpfc_queue *q, uint32_t index) { uint32_t released = 0; + /* sanity check on queue memory */ + if (unlikely(!q)) + return 0; + if (q->hba_index == index) return 0; do { @@ -158,10 +167,15 @@ lpfc_sli4_wq_release(struct lpfc_queue *q, uint32_t index) static uint32_t lpfc_sli4_mq_put(struct lpfc_queue *q, struct lpfc_mqe *mqe) { - struct lpfc_mqe *temp_mqe = q->qe[q->host_index].mqe; + struct lpfc_mqe *temp_mqe; struct lpfc_register doorbell; uint32_t host_index; + /* sanity check on queue memory */ + if (unlikely(!q)) + return -ENOMEM; + temp_mqe = q->qe[q->host_index].mqe; + /* If the host has not yet processed the next entry then we are done */ if (((q->host_index + 1) % q->entry_count) == q->hba_index) return -ENOMEM; @@ -195,6 +209,10 @@ lpfc_sli4_mq_put(struct lpfc_queue *q, struct lpfc_mqe *mqe) static uint32_t lpfc_sli4_mq_release(struct lpfc_queue *q) { + /* sanity check on queue memory */ + if (unlikely(!q)) + return 0; + /* Clear the mailbox pointer for completion */ q->phba->mbox = NULL; q->hba_index = ((q->hba_index + 1) % q->entry_count); @@ -213,7 +231,12 @@ lpfc_sli4_mq_release(struct lpfc_queue *q) static struct lpfc_eqe * lpfc_sli4_eq_get(struct lpfc_queue *q) { - struct lpfc_eqe *eqe = q->qe[q->hba_index].eqe; + struct lpfc_eqe *eqe; + + /* sanity check on queue memory */ + if (unlikely(!q)) + return NULL; + eqe = q->qe[q->hba_index].eqe; /* If the next EQE is not valid then we are done */ if (!bf_get_le32(lpfc_eqe_valid, eqe)) @@ -248,6 +271,10 @@ lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm) struct lpfc_eqe *temp_eqe; struct lpfc_register doorbell; + /* sanity check on queue memory */ + if (unlikely(!q)) + return 0; + /* while there are valid entries */ while (q->hba_index != q->host_index) { temp_eqe = q->qe[q->host_index].eqe; @@ -288,6 +315,10 @@ lpfc_sli4_cq_get(struct lpfc_queue *q) { struct lpfc_cqe *cqe; + /* sanity check on queue memory */ + if (unlikely(!q)) + return NULL; + /* If the next CQE is not valid then we are done */ if (!bf_get_le32(lpfc_cqe_valid, q->qe[q->hba_index].cqe)) return NULL; @@ -322,6 +353,9 @@ lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm) struct lpfc_cqe *temp_qe; struct lpfc_register doorbell; + /* sanity check on queue memory */ + if (unlikely(!q)) + return 0; /* while there are valid entries */ while (q->hba_index != q->host_index) { temp_qe = q->qe[q->host_index].cqe; @@ -359,11 +393,17 @@ static int lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq, struct lpfc_rqe *hrqe, struct lpfc_rqe *drqe) { - struct lpfc_rqe *temp_hrqe = hq->qe[hq->host_index].rqe; - struct lpfc_rqe *temp_drqe = dq->qe[dq->host_index].rqe; + struct lpfc_rqe *temp_hrqe; + struct lpfc_rqe *temp_drqe; struct lpfc_register doorbell; int put_index = hq->host_index; + /* sanity check on queue memory */ + if (unlikely(!hq) || unlikely(!dq)) + return -ENOMEM; + temp_hrqe = hq->qe[hq->host_index].rqe; + temp_drqe = dq->qe[dq->host_index].rqe; + if (hq->type != LPFC_HRQ || dq->type != LPFC_DRQ) return -EINVAL; if (hq->host_index != dq->host_index) @@ -402,6 +442,10 @@ lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq, static uint32_t lpfc_sli4_rq_release(struct lpfc_queue *hq, struct lpfc_queue *dq) { + /* sanity check on queue memory */ + if (unlikely(!hq) || unlikely(!dq)) + return 0; + if ((hq->type != LPFC_HRQ) || (dq->type != LPFC_DRQ)) return 0; hq->hba_index = ((hq->hba_index + 1) % hq->entry_count); @@ -3575,8 +3619,8 @@ lpfc_sli_brdready(struct lpfc_hba *phba, uint32_t mask) * lpfc_reset_barrier - Make HBA ready for HBA reset * @phba: Pointer to HBA context object. * - * This function is called before resetting an HBA. This - * function requests HBA to quiesce DMAs before a reset. + * This function is called before resetting an HBA. This function is called + * with hbalock held and requests HBA to quiesce DMAs before a reset. **/ void lpfc_reset_barrier(struct lpfc_hba *phba) { @@ -3851,7 +3895,6 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; uint16_t cfg_value; - uint8_t qindx; /* Reset HBA */ lpfc_printf_log(phba, KERN_INFO, LOG_SLI, @@ -3867,19 +3910,6 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) spin_lock_irq(&phba->hbalock); psli->sli_flag &= ~(LPFC_PROCESS_LA); phba->fcf.fcf_flag = 0; - /* Clean up the child queue list for the CQs */ - list_del_init(&phba->sli4_hba.mbx_wq->list); - list_del_init(&phba->sli4_hba.els_wq->list); - list_del_init(&phba->sli4_hba.hdr_rq->list); - list_del_init(&phba->sli4_hba.dat_rq->list); - list_del_init(&phba->sli4_hba.mbx_cq->list); - list_del_init(&phba->sli4_hba.els_cq->list); - for (qindx = 0; qindx < phba->cfg_fcp_wq_count; qindx++) - list_del_init(&phba->sli4_hba.fcp_wq[qindx]->list); - qindx = 0; - do - list_del_init(&phba->sli4_hba.fcp_cq[qindx]->list); - while (++qindx < phba->cfg_fcp_eq_count); spin_unlock_irq(&phba->hbalock); /* Now physically reset the device */ @@ -3892,6 +3922,7 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR))); /* Perform FCoE PCI function reset */ + lpfc_sli4_queue_destroy(phba); lpfc_pci_function_reset(phba); /* Restore PCI cmd register */ @@ -4339,6 +4370,11 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) phba->sli.sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK; spin_unlock_irq(&phba->hbalock); done = 1; + + if ((pmb->u.mb.un.varCfgPort.casabt == 1) && + (pmb->u.mb.un.varCfgPort.gasabt == 0)) + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "3110 Port did not grant ASABT\n"); } } if (!done) { @@ -4551,9 +4587,9 @@ lpfc_sli_hba_setup_error: * data structure. **/ static int -lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba, - LPFC_MBOXQ_t *mboxq) +lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba) { + LPFC_MBOXQ_t *mboxq; struct lpfc_dmabuf *mp; struct lpfc_mqe *mqe; uint32_t data_length; @@ -4565,10 +4601,16 @@ lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba, phba->fc_map[1] = LPFC_FCOE_FCF_MAP1; phba->fc_map[2] = LPFC_FCOE_FCF_MAP2; - mqe = &mboxq->u.mqe; - if (lpfc_dump_fcoe_param(phba, mboxq)) + mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) return -ENOMEM; + mqe = &mboxq->u.mqe; + if (lpfc_sli4_dump_cfg_rg23(phba, mboxq)) { + rc = -ENOMEM; + goto out_free_mboxq; + } + mp = (struct lpfc_dmabuf *) mboxq->context1; rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); @@ -4596,19 +4638,25 @@ lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba, if (rc) { lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); - return -EIO; + rc = -EIO; + goto out_free_mboxq; } data_length = mqe->un.mb_words[5]; if (data_length > DMP_RGN23_SIZE) { lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); - return -EIO; + rc = -EIO; + goto out_free_mboxq; } lpfc_parse_fcoe_conf(phba, mp->virt, data_length); lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); - return 0; + rc = 0; + +out_free_mboxq: + mempool_free(mboxq, phba->mbox_mem_pool); + return rc; } /** @@ -4706,7 +4754,6 @@ static int lpfc_sli4_retrieve_pport_name(struct lpfc_hba *phba) { LPFC_MBOXQ_t *mboxq; - struct lpfc_mbx_read_config *rd_config; struct lpfc_mbx_get_cntl_attributes *mbx_cntl_attr; struct lpfc_controller_attribute *cntl_attr; struct lpfc_mbx_get_port_name *get_port_name; @@ -4724,33 +4771,11 @@ lpfc_sli4_retrieve_pport_name(struct lpfc_hba *phba) mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) return -ENOMEM; - /* obtain link type and link number via READ_CONFIG */ - lpfc_read_config(phba, mboxq); - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - if (rc == MBX_SUCCESS) { - rd_config = &mboxq->u.mqe.un.rd_config; - if (bf_get(lpfc_mbx_rd_conf_lnk_ldv, rd_config)) { - phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_VAL; - phba->sli4_hba.lnk_info.lnk_tp = - bf_get(lpfc_mbx_rd_conf_lnk_type, rd_config); - phba->sli4_hba.lnk_info.lnk_no = - bf_get(lpfc_mbx_rd_conf_lnk_numb, rd_config); - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "3081 lnk_type:%d, lnk_numb:%d\n", - phba->sli4_hba.lnk_info.lnk_tp, - phba->sli4_hba.lnk_info.lnk_no); - goto retrieve_ppname; - } else - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "3082 Mailbox (x%x) returned ldv:x0\n", - bf_get(lpfc_mqe_command, - &mboxq->u.mqe)); - } else - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "3083 Mailbox (x%x) failed, status:x%x\n", - bf_get(lpfc_mqe_command, &mboxq->u.mqe), - bf_get(lpfc_mqe_status, &mboxq->u.mqe)); + phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_INVAL; + lpfc_sli4_read_config(phba); + if (phba->sli4_hba.lnk_info.lnk_dv == LPFC_LNK_DAT_VAL) + goto retrieve_ppname; /* obtain link type and link number via COMMON_GET_CNTL_ATTRIBUTES */ reqlen = sizeof(struct lpfc_mbx_get_cntl_attributes); @@ -4875,14 +4900,19 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba) lpfc_sli4_cq_release(phba->sli4_hba.mbx_cq, LPFC_QUEUE_REARM); lpfc_sli4_cq_release(phba->sli4_hba.els_cq, LPFC_QUEUE_REARM); fcp_eqidx = 0; - do - lpfc_sli4_cq_release(phba->sli4_hba.fcp_cq[fcp_eqidx], - LPFC_QUEUE_REARM); - while (++fcp_eqidx < phba->cfg_fcp_eq_count); + if (phba->sli4_hba.fcp_cq) { + do + lpfc_sli4_cq_release(phba->sli4_hba.fcp_cq[fcp_eqidx], + LPFC_QUEUE_REARM); + while (++fcp_eqidx < phba->cfg_fcp_eq_count); + } lpfc_sli4_eq_release(phba->sli4_hba.sp_eq, LPFC_QUEUE_REARM); - for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) - lpfc_sli4_eq_release(phba->sli4_hba.fp_eq[fcp_eqidx], - LPFC_QUEUE_REARM); + if (phba->sli4_hba.fp_eq) { + for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; + fcp_eqidx++) + lpfc_sli4_eq_release(phba->sli4_hba.fp_eq[fcp_eqidx], + LPFC_QUEUE_REARM); + } } /** @@ -5457,6 +5487,8 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) uint16_t count, base; unsigned long longs; + if (!phba->sli4_hba.rpi_hdrs_in_use) + phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.max_rpi; if (phba->sli4_hba.extents_in_use) { /* * The port supports resource extents. The XRI, VPI, VFI, RPI @@ -5538,9 +5570,10 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) * need any action - just exit. */ if (bf_get(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags) == - LPFC_IDX_RSRC_RDY) - return 0; - + LPFC_IDX_RSRC_RDY) { + lpfc_sli4_dealloc_resource_identifiers(phba); + lpfc_sli4_remove_rpis(phba); + } /* RPIs. */ count = phba->sli4_hba.max_cfg_param.max_rpi; base = phba->sli4_hba.max_cfg_param.rpi_base; @@ -5880,14 +5913,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) if (!mboxq) return -ENOMEM; - /* - * Continue initialization with default values even if driver failed - * to read FCoE param config regions - */ - if (lpfc_sli4_read_fcoe_params(phba, mboxq)) - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_INIT, - "2570 Failed to read FCoE parameters\n"); - /* Issue READ_REV to collect vpd and FW information. */ vpd_size = SLI4_PAGE_SIZE; vpd = kzalloc(vpd_size, GFP_KERNEL); @@ -5925,6 +5950,16 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) } /* + * Continue initialization with default values even if driver failed + * to read FCoE param config regions, only read parameters if the + * board is FCoE + */ + if (phba->hba_flag & HBA_FCOE_MODE && + lpfc_sli4_read_fcoe_params(phba)) + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_INIT, + "2570 Failed to read FCoE parameters\n"); + + /* * Retrieve sli4 device physical port name, failure of doing it * is considered as non-fatal. */ @@ -6044,6 +6079,8 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) "rc = x%x\n", rc); goto out_free_mbox; } + /* update physical xri mappings in the scsi buffers */ + lpfc_scsi_buf_update(phba); /* Read the port's service parameters. */ rc = lpfc_read_sparam(phba, mboxq, vport->vpi); @@ -6205,7 +6242,11 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) rc = 0; phba->fcf.fcfi = bf_get(lpfc_reg_fcfi_fcfi, &mboxq->u.mqe.un.reg_fcfi); + + /* Check if the port is configured to be disabled */ + lpfc_sli_read_link_ste(phba); } + /* * The port is ready, set the host's link state to LINK_DOWN * in preparation for link interrupts. @@ -6213,10 +6254,25 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) spin_lock_irq(&phba->hbalock); phba->link_state = LPFC_LINK_DOWN; spin_unlock_irq(&phba->hbalock); - if (phba->cfg_suppress_link_up == LPFC_INITIALIZE_LINK) { - rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT); - if (rc) + if (!(phba->hba_flag & HBA_FCOE_MODE) && + (phba->hba_flag & LINK_DISABLED)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_SLI, + "3103 Adapter Link is disabled.\n"); + lpfc_down_link(phba, mboxq); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + if (rc != MBX_SUCCESS) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_SLI, + "3104 Adapter failed to issue " + "DOWN_LINK mbox cmd, rc:x%x\n", rc); goto out_unset_queue; + } + } else if (phba->cfg_suppress_link_up == LPFC_INITIALIZE_LINK) { + /* don't perform init_link on SLI4 FC port loopback test */ + if (!(phba->link_flag & LS_LOOPBACK_MODE)) { + rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT); + if (rc) + goto out_unset_queue; + } } mempool_free(mboxq, phba->mbox_mem_pool); return rc; @@ -7487,6 +7543,7 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, struct ulp_bde64 *bpl = NULL; struct ulp_bde64 bde; struct sli4_sge *sgl = NULL; + struct lpfc_dmabuf *dmabuf; IOCB_t *icmd; int numBdes = 0; int i = 0; @@ -7505,9 +7562,12 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, * have not been byteswapped yet so there is no * need to swap them back. */ - bpl = (struct ulp_bde64 *) - ((struct lpfc_dmabuf *)piocbq->context3)->virt; + if (piocbq->context3) + dmabuf = (struct lpfc_dmabuf *)piocbq->context3; + else + return xritag; + bpl = (struct ulp_bde64 *)dmabuf->virt; if (!bpl) return xritag; @@ -7616,6 +7676,8 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, int numBdes, i; struct ulp_bde64 bde; struct lpfc_nodelist *ndlp; + uint32_t *pcmd; + uint32_t if_type; fip = phba->hba_flag & HBA_FIP_SUPPORT; /* The fcp commands will set command type */ @@ -7669,6 +7731,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, iocbq->iocb.ulpCommand); return IOCB_ERROR; } + wqe->els_req.payload_len = xmit_len; /* Els_reguest64 has a TMO */ bf_set(wqe_tmo, &wqe->els_req.wqe_com, @@ -7683,9 +7746,28 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(wqe_ct, &wqe->els_req.wqe_com, ct); bf_set(wqe_pu, &wqe->els_req.wqe_com, 0); /* CCP CCPE PV PRI in word10 were set in the memcpy */ - if (command_type == ELS_COMMAND_FIP) { + if (command_type == ELS_COMMAND_FIP) els_id = ((iocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK) >> LPFC_FIP_ELS_ID_SHIFT); + pcmd = (uint32_t *) (((struct lpfc_dmabuf *) + iocbq->context2)->virt); + if_type = bf_get(lpfc_sli_intf_if_type, + &phba->sli4_hba.sli_intf); + if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { + if (pcmd && (*pcmd == ELS_CMD_FLOGI || + *pcmd == ELS_CMD_SCR || + *pcmd == ELS_CMD_PLOGI)) { + bf_set(els_req64_sp, &wqe->els_req, 1); + bf_set(els_req64_sid, &wqe->els_req, + iocbq->vport->fc_myDID); + bf_set(wqe_ct, &wqe->els_req.wqe_com, 1); + bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, + phba->vpi_ids[phba->pport->vpi]); + } else if (iocbq->context1) { + bf_set(wqe_ct, &wqe->els_req.wqe_com, 0); + bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, + phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); + } } bf_set(wqe_temp_rpi, &wqe->els_req.wqe_com, phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); @@ -7704,6 +7786,8 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, /* The entire sequence is transmitted for this IOCB */ xmit_len = total_len; cmnd = CMD_XMIT_SEQUENCE64_CR; + if (phba->link_flag & LS_LOOPBACK_MODE) + bf_set(wqe_xo, &wqe->xmit_sequence.wge_ctl, 1); case CMD_XMIT_SEQUENCE64_CR: /* word3 iocb=io_tag32 wqe=reserved */ wqe->xmit_sequence.rsvd3 = 0; @@ -7846,6 +7930,16 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(wqe_ebde_cnt, &wqe->xmit_els_rsp.wqe_com, 0); bf_set(wqe_rsp_temp_rpi, &wqe->xmit_els_rsp, phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); + pcmd = (uint32_t *) (((struct lpfc_dmabuf *) + iocbq->context2)->virt); + if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { + bf_set(els_req64_sp, &wqe->els_req, 1); + bf_set(els_req64_sid, &wqe->els_req, + iocbq->vport->fc_myDID); + bf_set(wqe_ct, &wqe->els_req.wqe_com, 1); + bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, + phba->vpi_ids[phba->pport->vpi]); + } command_type = OTHER_COMMAND; break; case CMD_CLOSE_XRI_CN: @@ -8037,6 +8131,8 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, */ if (piocb->iocb_flag & LPFC_IO_FCP) piocb->fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba); + if (unlikely(!phba->sli4_hba.fcp_wq)) + return IOCB_ERROR; if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[piocb->fcp_wqidx], &wqe)) return IOCB_ERROR; @@ -8173,6 +8269,137 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba) return 0; } +/* lpfc_sli_abts_recover_port - Recover a port that failed an ABTS. + * @vport: pointer to virtual port object. + * @ndlp: nodelist pointer for the impacted rport. + * + * The driver calls this routine in response to a XRI ABORT CQE + * event from the port. In this event, the driver is required to + * recover its login to the rport even though its login may be valid + * from the driver's perspective. The failed ABTS notice from the + * port indicates the rport is not responding. + */ +static void +lpfc_sli_abts_recover_port(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp) +{ + struct Scsi_Host *shost; + struct lpfc_hba *phba; + unsigned long flags = 0; + + shost = lpfc_shost_from_vport(vport); + phba = vport->phba; + if (ndlp->nlp_state != NLP_STE_MAPPED_NODE) { + lpfc_printf_log(phba, KERN_INFO, + LOG_SLI, "3093 No rport recovery needed. " + "rport in state 0x%x\n", + ndlp->nlp_state); + return; + } + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "3094 Start rport recovery on shost id 0x%x " + "fc_id 0x%06x vpi 0x%x rpi 0x%x state 0x%x " + "flags 0x%x\n", + shost->host_no, ndlp->nlp_DID, + vport->vpi, ndlp->nlp_rpi, ndlp->nlp_state, + ndlp->nlp_flag); + /* + * The rport is not responding. Don't attempt ADISC recovery. + * Remove the FCP-2 flag to force a PLOGI. + */ + spin_lock_irqsave(shost->host_lock, flags); + ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; + spin_unlock_irqrestore(shost->host_lock, flags); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RECOVERY); + lpfc_cancel_retry_delay_tmo(vport, ndlp); + spin_lock_irqsave(shost->host_lock, flags); + ndlp->nlp_flag |= NLP_NPR_2B_DISC; + spin_unlock_irqrestore(shost->host_lock, flags); + lpfc_disc_start(vport); +} + +/* lpfc_sli_abts_err_handler - handle a failed ABTS request from an SLI3 port. + * @phba: Pointer to HBA context object. + * @iocbq: Pointer to iocb object. + * + * The async_event handler calls this routine when it receives + * an ASYNC_STATUS_CN event from the port. The port generates + * this event when an Abort Sequence request to an rport fails + * twice in succession. The abort could be originated by the + * driver or by the port. The ABTS could have been for an ELS + * or FCP IO. The port only generates this event when an ABTS + * fails to complete after one retry. + */ +static void +lpfc_sli_abts_err_handler(struct lpfc_hba *phba, + struct lpfc_iocbq *iocbq) +{ + struct lpfc_nodelist *ndlp = NULL; + uint16_t rpi = 0, vpi = 0; + struct lpfc_vport *vport = NULL; + + /* The rpi in the ulpContext is vport-sensitive. */ + vpi = iocbq->iocb.un.asyncstat.sub_ctxt_tag; + rpi = iocbq->iocb.ulpContext; + + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "3092 Port generated ABTS async event " + "on vpi %d rpi %d status 0x%x\n", + vpi, rpi, iocbq->iocb.ulpStatus); + + vport = lpfc_find_vport_by_vpid(phba, vpi); + if (!vport) + goto err_exit; + ndlp = lpfc_findnode_rpi(vport, rpi); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + goto err_exit; + + if (iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT) + lpfc_sli_abts_recover_port(vport, ndlp); + return; + + err_exit: + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3095 Event Context not found, no " + "action on vpi %d rpi %d status 0x%x, reason 0x%x\n", + iocbq->iocb.ulpContext, iocbq->iocb.ulpStatus, + vpi, rpi); +} + +/* lpfc_sli4_abts_err_handler - handle a failed ABTS request from an SLI4 port. + * @phba: pointer to HBA context object. + * @ndlp: nodelist pointer for the impacted rport. + * @axri: pointer to the wcqe containing the failed exchange. + * + * The driver calls this routine when it receives an ABORT_XRI_FCP CQE from the + * port. The port generates this event when an abort exchange request to an + * rport fails twice in succession with no reply. The abort could be originated + * by the driver or by the port. The ABTS could have been for an ELS or FCP IO. + */ +void +lpfc_sli4_abts_err_handler(struct lpfc_hba *phba, + struct lpfc_nodelist *ndlp, + struct sli4_wcqe_xri_aborted *axri) +{ + struct lpfc_vport *vport; + + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3115 Node Context not found, driver " + "ignoring abts err event\n"); + vport = ndlp->vport; + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "3116 Port generated FCP XRI ABORT event on " + "vpi %d rpi %d xri x%x status 0x%x\n", + ndlp->vport->vpi, ndlp->nlp_rpi, + bf_get(lpfc_wcqe_xa_xri, axri), + bf_get(lpfc_wcqe_xa_status, axri)); + + if (bf_get(lpfc_wcqe_xa_status, axri) == IOSTAT_LOCAL_REJECT) + lpfc_sli_abts_recover_port(vport, ndlp); +} + /** * lpfc_sli_async_event_handler - ASYNC iocb handler function * @phba: Pointer to HBA context object. @@ -8192,63 +8419,58 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba, { IOCB_t *icmd; uint16_t evt_code; - uint16_t temp; struct temp_event temp_event_data; struct Scsi_Host *shost; uint32_t *iocb_w; icmd = &iocbq->iocb; evt_code = icmd->un.asyncstat.evt_code; - temp = icmd->ulpContext; - if ((evt_code != ASYNC_TEMP_WARN) && - (evt_code != ASYNC_TEMP_SAFE)) { + switch (evt_code) { + case ASYNC_TEMP_WARN: + case ASYNC_TEMP_SAFE: + temp_event_data.data = (uint32_t) icmd->ulpContext; + temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; + if (evt_code == ASYNC_TEMP_WARN) { + temp_event_data.event_code = LPFC_THRESHOLD_TEMP; + lpfc_printf_log(phba, KERN_ERR, LOG_TEMP, + "0347 Adapter is very hot, please take " + "corrective action. temperature : %d Celsius\n", + (uint32_t) icmd->ulpContext); + } else { + temp_event_data.event_code = LPFC_NORMAL_TEMP; + lpfc_printf_log(phba, KERN_ERR, LOG_TEMP, + "0340 Adapter temperature is OK now. " + "temperature : %d Celsius\n", + (uint32_t) icmd->ulpContext); + } + + /* Send temperature change event to applications */ + shost = lpfc_shost_from_vport(phba->pport); + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(temp_event_data), (char *) &temp_event_data, + LPFC_NL_VENDOR_ID); + break; + case ASYNC_STATUS_CN: + lpfc_sli_abts_err_handler(phba, iocbq); + break; + default: iocb_w = (uint32_t *) icmd; - lpfc_printf_log(phba, - KERN_ERR, - LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0346 Ring %d handler: unexpected ASYNC_STATUS" " evt_code 0x%x\n" "W0 0x%08x W1 0x%08x W2 0x%08x W3 0x%08x\n" "W4 0x%08x W5 0x%08x W6 0x%08x W7 0x%08x\n" "W8 0x%08x W9 0x%08x W10 0x%08x W11 0x%08x\n" "W12 0x%08x W13 0x%08x W14 0x%08x W15 0x%08x\n", - pring->ringno, - icmd->un.asyncstat.evt_code, + pring->ringno, icmd->un.asyncstat.evt_code, iocb_w[0], iocb_w[1], iocb_w[2], iocb_w[3], iocb_w[4], iocb_w[5], iocb_w[6], iocb_w[7], iocb_w[8], iocb_w[9], iocb_w[10], iocb_w[11], iocb_w[12], iocb_w[13], iocb_w[14], iocb_w[15]); - return; - } - temp_event_data.data = (uint32_t)temp; - temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; - if (evt_code == ASYNC_TEMP_WARN) { - temp_event_data.event_code = LPFC_THRESHOLD_TEMP; - lpfc_printf_log(phba, - KERN_ERR, - LOG_TEMP, - "0347 Adapter is very hot, please take " - "corrective action. temperature : %d Celsius\n", - temp); - } - if (evt_code == ASYNC_TEMP_SAFE) { - temp_event_data.event_code = LPFC_NORMAL_TEMP; - lpfc_printf_log(phba, - KERN_ERR, - LOG_TEMP, - "0340 Adapter temperature is OK now. " - "temperature : %d Celsius\n", - temp); + break; } - - /* Send temperature change event to applications */ - shost = lpfc_shost_from_vport(phba->pport); - fc_host_post_vendor_event(shost, fc_get_event_number(), - sizeof(temp_event_data), (char *) &temp_event_data, - LPFC_NL_VENDOR_ID); - } @@ -8823,12 +9045,14 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, { IOCB_t *irsp = &rspiocb->iocb; uint16_t abort_iotag, abort_context; - struct lpfc_iocbq *abort_iocb; - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; - - abort_iocb = NULL; + struct lpfc_iocbq *abort_iocb = NULL; if (irsp->ulpStatus) { + + /* + * Assume that the port already completed and returned, or + * will return the iocb. Just Log the message. + */ abort_context = cmdiocb->iocb.un.acxri.abortContextTag; abort_iotag = cmdiocb->iocb.un.acxri.abortIoTag; @@ -8846,68 +9070,15 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, */ abort_iocb = phba->sli.iocbq_lookup[abort_context]; - /* - * If the iocb is not found in Firmware queue the iocb - * might have completed already. Do not free it again. - */ - if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - if (irsp->un.ulpWord[4] != IOERR_NO_XRI) { - spin_unlock_irq(&phba->hbalock); - lpfc_sli_release_iocbq(phba, cmdiocb); - return; - } - /* For SLI4 the ulpContext field for abort IOCB - * holds the iotag of the IOCB being aborted so - * the local abort_context needs to be reset to - * match the aborted IOCBs ulpContext. - */ - if (abort_iocb && phba->sli_rev == LPFC_SLI_REV4) - abort_context = abort_iocb->iocb.ulpContext; - } - lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_SLI, "0327 Cannot abort els iocb %p " "with tag %x context %x, abort status %x, " "abort code %x\n", abort_iocb, abort_iotag, abort_context, irsp->ulpStatus, irsp->un.ulpWord[4]); - /* - * make sure we have the right iocbq before taking it - * off the txcmplq and try to call completion routine. - */ - if (!abort_iocb || - abort_iocb->iocb.ulpContext != abort_context || - (abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) == 0) - spin_unlock_irq(&phba->hbalock); - else if (phba->sli_rev < LPFC_SLI_REV4) { - /* - * leave the SLI4 aborted command on the txcmplq - * list and the command complete WCQE's XB bit - * will tell whether the SGL (XRI) can be released - * immediately or to the aborted SGL list for the - * following abort XRI from the HBA. - */ - list_del_init(&abort_iocb->list); - if (abort_iocb->iocb_flag & LPFC_IO_ON_Q) { - abort_iocb->iocb_flag &= ~LPFC_IO_ON_Q; - pring->txcmplq_cnt--; - } - /* Firmware could still be in progress of DMAing - * payload, so don't free data buffer till after - * a hbeat. - */ - abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE; - abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; - spin_unlock_irq(&phba->hbalock); - - abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT; - abort_iocb->iocb.un.ulpWord[4] = IOERR_ABORT_REQUESTED; - (abort_iocb->iocb_cmpl)(phba, abort_iocb, abort_iocb); - } else - spin_unlock_irq(&phba->hbalock); + spin_unlock_irq(&phba->hbalock); } - lpfc_sli_release_iocbq(phba, cmdiocb); return; } @@ -9258,6 +9429,14 @@ void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3096 ABORT_XRI_CN completing on xri x%x " + "original iotag x%x, abort cmd iotag x%x " + "status 0x%x, reason 0x%x\n", + cmdiocb->iocb.un.acxri.abortContextTag, + cmdiocb->iocb.un.acxri.abortIoTag, + cmdiocb->iotag, rspiocb->iocb.ulpStatus, + rspiocb->iocb.un.ulpWord[4]); lpfc_sli_release_iocbq(phba, cmdiocb); return; } @@ -9771,7 +9950,7 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba) phba->work_status[1] = readl(phba->sli4_hba.u.if_type2.ERR2regaddr); lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2885 Port Error Detected: " + "2885 Port Status Event: " "port status reg 0x%x, " "port smphr reg 0x%x, " "error 1=0x%x, error 2=0x%x\n", @@ -10777,6 +10956,9 @@ static void lpfc_sli4_sp_handle_rel_wcqe(struct lpfc_hba *phba, struct lpfc_wcqe_release *wcqe) { + /* sanity check on queue memory */ + if (unlikely(!phba->sli4_hba.els_wq)) + return; /* Check for the slow-path ELS work queue */ if (bf_get(lpfc_wcqe_r_wq_id, wcqe) == phba->sli4_hba.els_wq->queue_id) lpfc_sli4_wq_release(phba->sli4_hba.els_wq, @@ -10866,6 +11048,10 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) uint32_t status, rq_id; unsigned long iflags; + /* sanity check on queue memory */ + if (unlikely(!hrq) || unlikely(!drq)) + return workposted; + if (bf_get(lpfc_cqe_code, rcqe) == CQE_CODE_RECEIVE_V1) rq_id = bf_get(lpfc_rcqe_rq_id_v1, rcqe); else @@ -11000,6 +11186,9 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe) /* Search for completion queue pointer matching this cqid */ speq = phba->sli4_hba.sp_eq; + /* sanity check on queue memory */ + if (unlikely(!speq)) + return; list_for_each_entry(childq, &speq->child_list, list) { if (childq->queue_id == cqid) { cq = childq; @@ -11241,12 +11430,18 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, return; } + if (unlikely(!phba->sli4_hba.fcp_cq)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "3146 Fast-path completion queues " + "does not exist\n"); + return; + } cq = phba->sli4_hba.fcp_cq[fcp_cqidx]; if (unlikely(!cq)) { if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0367 Fast-path completion queue " - "does not exist\n"); + "(%d) does not exist\n", fcp_cqidx); return; } @@ -11417,6 +11612,8 @@ lpfc_sli4_fp_intr_handler(int irq, void *dev_id) /* Get to the EQ struct associated with this vector */ fpeq = phba->sli4_hba.fp_eq[fcp_eqidx]; + if (unlikely(!fpeq)) + return IRQ_NONE; /* Check device state for handling interrupt */ if (unlikely(lpfc_intr_state_check(phba))) { @@ -11635,6 +11832,9 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax) uint16_t dmult; uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; + /* sanity check on queue memory */ + if (!eq) + return -ENODEV; if (!phba->sli4_hba.pc_sli4_params.supported) hw_page_size = SLI4_PAGE_SIZE; @@ -11751,6 +11951,9 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, union lpfc_sli4_cfg_shdr *shdr; uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; + /* sanity check on queue memory */ + if (!cq || !eq) + return -ENODEV; if (!phba->sli4_hba.pc_sli4_params.supported) hw_page_size = SLI4_PAGE_SIZE; @@ -11933,6 +12136,9 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, union lpfc_sli4_cfg_shdr *shdr; uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; + /* sanity check on queue memory */ + if (!mq || !cq) + return -ENODEV; if (!phba->sli4_hba.pc_sli4_params.supported) hw_page_size = SLI4_PAGE_SIZE; @@ -12083,6 +12289,9 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; struct dma_address *page; + /* sanity check on queue memory */ + if (!wq || !cq) + return -ENODEV; if (!phba->sli4_hba.pc_sli4_params.supported) hw_page_size = SLI4_PAGE_SIZE; @@ -12151,6 +12360,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, wq->subtype = subtype; wq->host_index = 0; wq->hba_index = 0; + wq->entry_repost = LPFC_RELEASE_NOTIFICATION_INTERVAL; /* link the wq onto the parent cq child list */ list_add_tail(&wq->list, &cq->child_list); @@ -12174,6 +12384,9 @@ lpfc_rq_adjust_repost(struct lpfc_hba *phba, struct lpfc_queue *rq, int qno) { uint32_t cnt; + /* sanity check on queue memory */ + if (!rq) + return; cnt = lpfc_hbq_defs[qno]->entry_count; /* Recalc repost for RQs based on buffers initially posted */ @@ -12219,6 +12432,9 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, union lpfc_sli4_cfg_shdr *shdr; uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; + /* sanity check on queue memory */ + if (!hrq || !drq || !cq) + return -ENODEV; if (!phba->sli4_hba.pc_sli4_params.supported) hw_page_size = SLI4_PAGE_SIZE; @@ -12420,6 +12636,7 @@ lpfc_eq_destroy(struct lpfc_hba *phba, struct lpfc_queue *eq) uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; + /* sanity check on queue memory */ if (!eq) return -ENODEV; mbox = mempool_alloc(eq->phba->mbox_mem_pool, GFP_KERNEL); @@ -12475,6 +12692,7 @@ lpfc_cq_destroy(struct lpfc_hba *phba, struct lpfc_queue *cq) uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; + /* sanity check on queue memory */ if (!cq) return -ENODEV; mbox = mempool_alloc(cq->phba->mbox_mem_pool, GFP_KERNEL); @@ -12528,6 +12746,7 @@ lpfc_mq_destroy(struct lpfc_hba *phba, struct lpfc_queue *mq) uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; + /* sanity check on queue memory */ if (!mq) return -ENODEV; mbox = mempool_alloc(mq->phba->mbox_mem_pool, GFP_KERNEL); @@ -12581,6 +12800,7 @@ lpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq) uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; + /* sanity check on queue memory */ if (!wq) return -ENODEV; mbox = mempool_alloc(wq->phba->mbox_mem_pool, GFP_KERNEL); @@ -12634,6 +12854,7 @@ lpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq, uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; + /* sanity check on queue memory */ if (!hrq || !drq) return -ENODEV; mbox = mempool_alloc(hrq->phba->mbox_mem_pool, GFP_KERNEL); @@ -15252,45 +15473,42 @@ lpfc_sli4_fcf_dead_failthrough(struct lpfc_hba *phba) } /** - * lpfc_sli_read_link_ste - Read region 23 to decide if link is disabled. + * lpfc_sli_get_config_region23 - Get sli3 port region 23 data. * @phba: pointer to lpfc hba data structure. + * @rgn23_data: pointer to configure region 23 data. * - * This function read region 23 and parse TLV for port status to - * decide if the user disaled the port. If the TLV indicates the - * port is disabled, the hba_flag is set accordingly. + * This function gets SLI3 port configure region 23 data through memory dump + * mailbox command. When it successfully retrieves data, the size of the data + * will be returned, otherwise, 0 will be returned. **/ -void -lpfc_sli_read_link_ste(struct lpfc_hba *phba) +static uint32_t +lpfc_sli_get_config_region23(struct lpfc_hba *phba, char *rgn23_data) { LPFC_MBOXQ_t *pmb = NULL; MAILBOX_t *mb; - uint8_t *rgn23_data = NULL; - uint32_t offset = 0, data_size, sub_tlv_len, tlv_offset; + uint32_t offset = 0; int rc; + if (!rgn23_data) + return 0; + pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2600 lpfc_sli_read_serdes_param failed to" - " allocate mailbox memory\n"); - goto out; + "2600 failed to allocate mailbox memory\n"); + return 0; } mb = &pmb->u.mb; - /* Get adapter Region 23 data */ - rgn23_data = kzalloc(DMP_RGN23_SIZE, GFP_KERNEL); - if (!rgn23_data) - goto out; - do { lpfc_dump_mem(phba, pmb, offset, DMP_REGION_23); rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); if (rc != MBX_SUCCESS) { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2601 lpfc_sli_read_link_ste failed to" - " read config region 23 rc 0x%x Status 0x%x\n", - rc, mb->mbxStatus); + "2601 failed to read config " + "region 23, rc 0x%x Status 0x%x\n", + rc, mb->mbxStatus); mb->un.varDmp.word_cnt = 0; } /* @@ -15303,13 +15521,96 @@ lpfc_sli_read_link_ste(struct lpfc_hba *phba) mb->un.varDmp.word_cnt = DMP_RGN23_SIZE - offset; lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, - rgn23_data + offset, - mb->un.varDmp.word_cnt); + rgn23_data + offset, + mb->un.varDmp.word_cnt); offset += mb->un.varDmp.word_cnt; } while (mb->un.varDmp.word_cnt && offset < DMP_RGN23_SIZE); - data_size = offset; - offset = 0; + mempool_free(pmb, phba->mbox_mem_pool); + return offset; +} + +/** + * lpfc_sli4_get_config_region23 - Get sli4 port region 23 data. + * @phba: pointer to lpfc hba data structure. + * @rgn23_data: pointer to configure region 23 data. + * + * This function gets SLI4 port configure region 23 data through memory dump + * mailbox command. When it successfully retrieves data, the size of the data + * will be returned, otherwise, 0 will be returned. + **/ +static uint32_t +lpfc_sli4_get_config_region23(struct lpfc_hba *phba, char *rgn23_data) +{ + LPFC_MBOXQ_t *mboxq = NULL; + struct lpfc_dmabuf *mp = NULL; + struct lpfc_mqe *mqe; + uint32_t data_length = 0; + int rc; + + if (!rgn23_data) + return 0; + + mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3105 failed to allocate mailbox memory\n"); + return 0; + } + + if (lpfc_sli4_dump_cfg_rg23(phba, mboxq)) + goto out; + mqe = &mboxq->u.mqe; + mp = (struct lpfc_dmabuf *) mboxq->context1; + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + if (rc) + goto out; + data_length = mqe->un.mb_words[5]; + if (data_length == 0) + goto out; + if (data_length > DMP_RGN23_SIZE) { + data_length = 0; + goto out; + } + lpfc_sli_pcimem_bcopy((char *)mp->virt, rgn23_data, data_length); +out: + mempool_free(mboxq, phba->mbox_mem_pool); + if (mp) { + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } + return data_length; +} + +/** + * lpfc_sli_read_link_ste - Read region 23 to decide if link is disabled. + * @phba: pointer to lpfc hba data structure. + * + * This function read region 23 and parse TLV for port status to + * decide if the user disaled the port. If the TLV indicates the + * port is disabled, the hba_flag is set accordingly. + **/ +void +lpfc_sli_read_link_ste(struct lpfc_hba *phba) +{ + uint8_t *rgn23_data = NULL; + uint32_t if_type, data_size, sub_tlv_len, tlv_offset; + uint32_t offset = 0; + + /* Get adapter Region 23 data */ + rgn23_data = kzalloc(DMP_RGN23_SIZE, GFP_KERNEL); + if (!rgn23_data) + goto out; + + if (phba->sli_rev < LPFC_SLI_REV4) + data_size = lpfc_sli_get_config_region23(phba, rgn23_data); + else { + if_type = bf_get(lpfc_sli_intf_if_type, + &phba->sli4_hba.sli_intf); + if (if_type == LPFC_SLI_INTF_IF_TYPE_0) + goto out; + data_size = lpfc_sli4_get_config_region23(phba, rgn23_data); + } if (!data_size) goto out; @@ -15373,9 +15674,8 @@ lpfc_sli_read_link_ste(struct lpfc_hba *phba) goto out; } } + out: - if (pmb) - mempool_free(pmb, phba->mbox_mem_pool); kfree(rgn23_data); return; } diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index d5cffd8af34..3f266e2c54e 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -291,7 +291,7 @@ struct lpfc_bmbx { #define LPFC_RQE_SIZE 8 #define LPFC_EQE_DEF_COUNT 1024 -#define LPFC_CQE_DEF_COUNT 256 +#define LPFC_CQE_DEF_COUNT 1024 #define LPFC_WQE_DEF_COUNT 256 #define LPFC_MQE_DEF_COUNT 16 #define LPFC_RQE_DEF_COUNT 512 @@ -420,7 +420,16 @@ struct lpfc_sli4_hba { void __iomem *STATUSregaddr; void __iomem *CTRLregaddr; void __iomem *ERR1regaddr; +#define SLIPORT_ERR1_REG_ERR_CODE_1 0x1 +#define SLIPORT_ERR1_REG_ERR_CODE_2 0x2 void __iomem *ERR2regaddr; +#define SLIPORT_ERR2_REG_FW_RESTART 0x0 +#define SLIPORT_ERR2_REG_FUNC_PROVISON 0x1 +#define SLIPORT_ERR2_REG_FORCED_DUMP 0x2 +#define SLIPORT_ERR2_REG_FAILURE_EQ 0x3 +#define SLIPORT_ERR2_REG_FAILURE_CQ 0x4 +#define SLIPORT_ERR2_REG_FAILURE_BUS 0x5 +#define SLIPORT_ERR2_REG_FAILURE_RQ 0x6 } if_type2; } u; diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index b0630e37f1e..dd044d01a07 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.27" +#define LPFC_DRIVER_VERSION "8.3.28" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index cff6ca67415..0fe188e6600 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -774,10 +774,10 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba) return NULL; spin_lock_irq(&phba->hbalock); list_for_each_entry(port_iterator, &phba->port_list, listentry) { + if (port_iterator->load_flag & FC_UNLOADING) + continue; if (!scsi_host_get(lpfc_shost_from_vport(port_iterator))) { - if (!(port_iterator->load_flag & FC_UNLOADING)) - lpfc_printf_vlog(port_iterator, KERN_ERR, - LOG_VPORT, + lpfc_printf_vlog(port_iterator, KERN_ERR, LOG_VPORT, "1801 Create vport work array FAILED: " "cannot do scsi_host_get\n"); continue; diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index 590ce1ef201..70eb1f79b1b 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -25,6 +25,7 @@ #include <asm/dma.h> #include <asm/macints.h> #include <asm/macintosh.h> +#include <asm/mac_via.h> #include <scsi/scsi_host.h> @@ -149,7 +150,7 @@ static inline int mac_esp_wait_for_dreq(struct esp *esp) do { if (mep->pdma_regs == NULL) { - if (mac_irq_pending(IRQ_MAC_SCSIDRQ)) + if (via2_scsi_drq_pending()) return 0; } else { if (nubus_readl(mep->pdma_regs) & 0x200) @@ -564,8 +565,7 @@ static int __devinit esp_mac_probe(struct platform_device *dev) esp_chips[dev->id] = esp; mb(); if (esp_chips[!dev->id] == NULL) { - err = request_irq(host->irq, mac_scsi_esp_intr, 0, - "Mac ESP", NULL); + err = request_irq(host->irq, mac_scsi_esp_intr, 0, "ESP", NULL); if (err < 0) { esp_chips[dev->id] = NULL; goto fail_free_priv; diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index af3a6af97cc..2bccfbe5661 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -291,8 +291,7 @@ int __init macscsi_detect(struct scsi_host_template * tpnt) ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0; if (instance->irq != SCSI_IRQ_NONE) - if (request_irq(instance->irq, NCR5380_intr, IRQ_FLG_SLOW, - "ncr5380", instance)) { + if (request_irq(instance->irq, NCR5380_intr, 0, "ncr5380", instance)) { printk(KERN_WARNING "scsi%d: IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); instance->irq = SCSI_IRQ_NONE; @@ -340,9 +339,6 @@ static void mac_scsi_reset_boot(struct Scsi_Host *instance) printk(KERN_INFO "Macintosh SCSI: resetting the SCSI bus..." ); - /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */ - disable_irq(IRQ_MAC_SCSI); - /* get in phase */ NCR5380_write( TARGET_COMMAND_REG, PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) )); @@ -358,9 +354,6 @@ static void mac_scsi_reset_boot(struct Scsi_Host *instance) for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); ) barrier(); - /* switch on SCSI IRQ again */ - enable_irq(IRQ_MAC_SCSI); - printk(KERN_INFO " done\n" ); } #endif diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 5c1776406c9..15eefa1d61f 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -306,19 +306,22 @@ mega_query_adapter(adapter_t *adapter) adapter->host->sg_tablesize = adapter->sglen; - /* use HP firmware and bios version encoding */ + /* use HP firmware and bios version encoding + Note: fw_version[0|1] and bios_version[0|1] were originally shifted + right 8 bits making them zero. This 0 value was hardcoded to fix + sparse warnings. */ if (adapter->product_info.subsysvid == HP_SUBSYS_VID) { sprintf (adapter->fw_version, "%c%d%d.%d%d", adapter->product_info.fw_version[2], - adapter->product_info.fw_version[1] >> 8, + 0, adapter->product_info.fw_version[1] & 0x0f, - adapter->product_info.fw_version[0] >> 8, + 0, adapter->product_info.fw_version[0] & 0x0f); sprintf (adapter->bios_version, "%c%d%d.%d%d", adapter->product_info.bios_version[2], - adapter->product_info.bios_version[1] >> 8, + 0, adapter->product_info.bios_version[1] & 0x0f, - adapter->product_info.bios_version[0] >> 8, + 0, adapter->product_info.bios_version[0] & 0x0f); } else { memcpy(adapter->fw_version, diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index dd94c7d574f..e5f416f8042 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -33,9 +33,9 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "00.00.06.12-rc1" -#define MEGASAS_RELDATE "Oct. 5, 2011" -#define MEGASAS_EXT_VERSION "Wed. Oct. 5 17:00:00 PDT 2011" +#define MEGASAS_VERSION "00.00.06.14-rc1" +#define MEGASAS_RELDATE "Jan. 6, 2012" +#define MEGASAS_EXT_VERSION "Fri. Jan. 6 17:00:00 PDT 2012" /* * Device IDs @@ -773,7 +773,6 @@ struct megasas_ctrl_info { #define MFI_OB_INTR_STATUS_MASK 0x00000002 #define MFI_POLL_TIMEOUT_SECS 60 -#define MEGASAS_COMPLETION_TIMER_INTERVAL (HZ/10) #define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000 #define MFI_REPLY_GEN2_MESSAGE_INTERRUPT 0x00000001 @@ -1353,7 +1352,6 @@ struct megasas_instance { u32 mfiStatus; u32 last_seq_num; - struct timer_list io_completion_timer; struct list_head internal_reset_pending_q; /* Ptr to hba specific information */ diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 29a994f9c4f..8b300be4428 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * FILE: megaraid_sas_base.c - * Version : v00.00.06.12-rc1 + * Version : v00.00.06.14-rc1 * * Authors: LSI Corporation * Sreenivas Bagalkote @@ -59,14 +59,6 @@ #include "megaraid_sas.h" /* - * poll_mode_io:1- schedule complete completion from q cmd - */ -static unsigned int poll_mode_io; -module_param_named(poll_mode_io, poll_mode_io, int, 0); -MODULE_PARM_DESC(poll_mode_io, - "Complete cmds from IO path, (default=0)"); - -/* * Number of sectors per IO command * Will be set in megasas_init_mfi if user does not provide */ @@ -1439,11 +1431,6 @@ megasas_build_and_issue_cmd(struct megasas_instance *instance, instance->instancet->fire_cmd(instance, cmd->frame_phys_addr, cmd->frame_count-1, instance->reg_set); - /* - * Check if we have pend cmds to be completed - */ - if (poll_mode_io && atomic_read(&instance->fw_outstanding)) - tasklet_schedule(&instance->isr_tasklet); return 0; out_return_cmd: @@ -3370,47 +3357,6 @@ fail_fw_init: return -EINVAL; } -/** - * megasas_start_timer - Initializes a timer object - * @instance: Adapter soft state - * @timer: timer object to be initialized - * @fn: timer function - * @interval: time interval between timer function call - */ -static inline void -megasas_start_timer(struct megasas_instance *instance, - struct timer_list *timer, - void *fn, unsigned long interval) -{ - init_timer(timer); - timer->expires = jiffies + interval; - timer->data = (unsigned long)instance; - timer->function = fn; - add_timer(timer); -} - -/** - * megasas_io_completion_timer - Timer fn - * @instance_addr: Address of adapter soft state - * - * Schedules tasklet for cmd completion - * if poll_mode_io is set - */ -static void -megasas_io_completion_timer(unsigned long instance_addr) -{ - struct megasas_instance *instance = - (struct megasas_instance *)instance_addr; - - if (atomic_read(&instance->fw_outstanding)) - tasklet_schedule(&instance->isr_tasklet); - - /* Restart timer */ - if (poll_mode_io) - mod_timer(&instance->io_completion_timer, - jiffies + MEGASAS_COMPLETION_TIMER_INTERVAL); -} - static u32 megasas_init_adapter_mfi(struct megasas_instance *instance) { @@ -3638,11 +3584,6 @@ static int megasas_init_fw(struct megasas_instance *instance) tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, (unsigned long)instance); - /* Initialize the cmd completion timer */ - if (poll_mode_io) - megasas_start_timer(instance, &instance->io_completion_timer, - megasas_io_completion_timer, - MEGASAS_COMPLETION_TIMER_INTERVAL); return 0; fail_init_adapter: @@ -4369,9 +4310,6 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state) host = instance->host; instance->unload = 1; - if (poll_mode_io) - del_timer_sync(&instance->io_completion_timer); - megasas_flush_cache(instance); megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN); @@ -4511,12 +4449,6 @@ megasas_resume(struct pci_dev *pdev) } instance->instancet->enable_intr(instance->reg_set); - - /* Initialize the cmd completion timer */ - if (poll_mode_io) - megasas_start_timer(instance, &instance->io_completion_timer, - megasas_io_completion_timer, - MEGASAS_COMPLETION_TIMER_INTERVAL); instance->unload = 0; /* @@ -4570,9 +4502,6 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev) host = instance->host; fusion = instance->ctrl_context; - if (poll_mode_io) - del_timer_sync(&instance->io_completion_timer); - scsi_remove_host(instance->host); megasas_flush_cache(instance); megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN); @@ -4773,6 +4702,8 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, memcpy(cmd->frame, ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE); cmd->frame->hdr.context = cmd->index; cmd->frame->hdr.pad_0 = 0; + cmd->frame->hdr.flags &= ~(MFI_FRAME_IEEE | MFI_FRAME_SGL64 | + MFI_FRAME_SENSE64); /* * The management interface between applications and the fw uses @@ -5219,60 +5150,6 @@ megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t coun static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUSR, megasas_sysfs_show_dbg_lvl, megasas_sysfs_set_dbg_lvl); -static ssize_t -megasas_sysfs_show_poll_mode_io(struct device_driver *dd, char *buf) -{ - return sprintf(buf, "%u\n", poll_mode_io); -} - -static ssize_t -megasas_sysfs_set_poll_mode_io(struct device_driver *dd, - const char *buf, size_t count) -{ - int retval = count; - int tmp = poll_mode_io; - int i; - struct megasas_instance *instance; - - if (sscanf(buf, "%u", &poll_mode_io) < 1) { - printk(KERN_ERR "megasas: could not set poll_mode_io\n"); - retval = -EINVAL; - } - - /* - * Check if poll_mode_io is already set or is same as previous value - */ - if ((tmp && poll_mode_io) || (tmp == poll_mode_io)) - goto out; - - if (poll_mode_io) { - /* - * Start timers for all adapters - */ - for (i = 0; i < megasas_mgmt_info.max_index; i++) { - instance = megasas_mgmt_info.instance[i]; - if (instance) { - megasas_start_timer(instance, - &instance->io_completion_timer, - megasas_io_completion_timer, - MEGASAS_COMPLETION_TIMER_INTERVAL); - } - } - } else { - /* - * Delete timers for all adapters - */ - for (i = 0; i < megasas_mgmt_info.max_index; i++) { - instance = megasas_mgmt_info.instance[i]; - if (instance) - del_timer_sync(&instance->io_completion_timer); - } - } - -out: - return retval; -} - static void megasas_aen_polling(struct work_struct *work) { @@ -5502,11 +5379,6 @@ megasas_aen_polling(struct work_struct *work) kfree(ev); } - -static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUSR, - megasas_sysfs_show_poll_mode_io, - megasas_sysfs_set_poll_mode_io); - /** * megasas_init - Driver load entry point */ @@ -5566,11 +5438,6 @@ static int __init megasas_init(void) if (rval) goto err_dcf_dbg_lvl; rval = driver_create_file(&megasas_pci_driver.driver, - &driver_attr_poll_mode_io); - if (rval) - goto err_dcf_poll_mode_io; - - rval = driver_create_file(&megasas_pci_driver.driver, &driver_attr_support_device_change); if (rval) goto err_dcf_support_device_change; @@ -5579,10 +5446,6 @@ static int __init megasas_init(void) err_dcf_support_device_change: driver_remove_file(&megasas_pci_driver.driver, - &driver_attr_poll_mode_io); - -err_dcf_poll_mode_io: - driver_remove_file(&megasas_pci_driver.driver, &driver_attr_dbg_lvl); err_dcf_dbg_lvl: driver_remove_file(&megasas_pci_driver.driver, @@ -5607,8 +5470,6 @@ err_pcidrv: static void __exit megasas_exit(void) { driver_remove_file(&megasas_pci_driver.driver, - &driver_attr_poll_mode_io); - driver_remove_file(&megasas_pci_driver.driver, &driver_attr_dbg_lvl); driver_remove_file(&megasas_pci_driver.driver, &driver_attr_support_poll_for_event); diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index 5255dd688ac..294abb0defa 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -282,7 +282,9 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, else { *pDevHandle = MR_PD_INVALID; /* set dev handle as invalid. */ if ((raid->level >= 5) && - (instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER)) + ((instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER && + raid->regTypeReqOnRead != REGION_TYPE_UNUSED))) pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE; else if (raid->level == 1) { /* Get alternate Pd. */ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h index 8dc1b32918d..a01f0aa66f2 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2.h @@ -8,7 +8,7 @@ * scatter/gather formats. * Creation Date: June 21, 2006 * - * mpi2.h Version: 02.00.20 + * mpi2.h Version: 02.00.22 * * Version History * --------------- @@ -69,6 +69,8 @@ * 02-23-11 02.00.19 Bumped MPI2_HEADER_VERSION_UNIT. * Added MPI2_FUNCTION_SEND_HOST_MESSAGE. * 03-09-11 02.00.20 Bumped MPI2_HEADER_VERSION_UNIT. + * 05-25-11 02.00.21 Bumped MPI2_HEADER_VERSION_UNIT. + * 08-24-11 02.00.22 Bumped MPI2_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- */ @@ -94,7 +96,7 @@ #define MPI2_VERSION_02_00 (0x0200) /* versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x14) +#define MPI2_HEADER_VERSION_UNIT (0x16) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) @@ -1073,8 +1075,10 @@ typedef struct _MPI2_IEEE_SGE_UNION #define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02) #define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) /* IEEE Simple Element only */ -#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR (0x03) +#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR (0x03) /* IEEE Chain Element only */ +#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR \ + (MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR) /* typo in name */ /**************************************************************************** * IEEE SGE operation Macros diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h index cfd95b4e300..3a023dad77a 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h @@ -6,7 +6,7 @@ * Title: MPI Configuration messages and pages * Creation Date: November 10, 2006 * - * mpi2_cnfg.h Version: 02.00.19 + * mpi2_cnfg.h Version: 02.00.21 * * Version History * --------------- @@ -140,6 +140,13 @@ * Added SASNotifyPrimitiveMasks field to * MPI2_CONFIG_PAGE_IOC_7. * 03-09-11 02.00.19 Fixed IO Unit Page 10 (to match the spec). + * 05-25-11 02.00.20 Cleaned up a few comments. + * 08-24-11 02.00.21 Marked the IO Unit Page 7 PowerManagementCapabilities + * for PCIe link as obsolete. + * Added SpinupFlags field containing a Disable Spin-up + * bit to the MPI2_SAS_IOUNIT4_SPINUP_GROUP fields of + * SAS IO Unit Page 4. + * -------------------------------------------------------------------------- */ @@ -904,8 +911,8 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { #define MPI2_IOUNITPAGE7_PMCAP_12_5_PCT_IOCSPEED (0x00000400) #define MPI2_IOUNITPAGE7_PMCAP_25_0_PCT_IOCSPEED (0x00000200) #define MPI2_IOUNITPAGE7_PMCAP_50_0_PCT_IOCSPEED (0x00000100) -#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE (0x00000008) -#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004) +#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE (0x00000008) /* obsolete */ +#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004) /* obsolete */ /* defines for IO Unit Page 7 IOCTemperatureUnits field */ #define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00) @@ -1970,10 +1977,14 @@ typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP { U8 MaxTargetSpinup; /* 0x00 */ U8 SpinupDelay; /* 0x01 */ - U16 Reserved1; /* 0x02 */ + U8 SpinupFlags; /* 0x02 */ + U8 Reserved1; /* 0x03 */ } MPI2_SAS_IOUNIT4_SPINUP_GROUP, MPI2_POINTER PTR_MPI2_SAS_IOUNIT4_SPINUP_GROUP, Mpi2SasIOUnit4SpinupGroup_t, MPI2_POINTER pMpi2SasIOUnit4SpinupGroup_t; +/* defines for SAS IO Unit Page 4 SpinupFlags */ +#define MPI2_SASIOUNIT4_SPINUP_DISABLE_FLAG (0x01) + /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to * one and check the value returned for NumPhys at runtime. @@ -2321,13 +2332,12 @@ typedef struct _MPI2_CONFIG_PAGE_EXPANDER_1 /* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ -/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ - /* values for SAS Expander Page 1 DiscoveryInfo field */ #define MPI2_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED (0x04) #define MPI2_SAS_EXPANDER1_DISCINFO_LINK_STATUS_CHANGE (0x02) #define MPI2_SAS_EXPANDER1_DISCINFO_NO_ROUTING_ENTRIES (0x01) +/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ /**************************************************************************** * SAS Device Config Pages @@ -2447,6 +2457,8 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_0 #define MPI2_SASPHY0_PAGEVERSION (0x03) +/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ + /* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */ /* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */ @@ -2454,12 +2466,10 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_0 /* values for SAS PHY Page 0 Flags field */ #define MPI2_SAS_PHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC (0x01) -/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ +/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */ /* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ -/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */ - /* SAS PHY Page 1 */ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h index 93d9b6956d0..9a925c07a9e 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h @@ -6,7 +6,7 @@ * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: October 11, 2006 * - * mpi2_ioc.h Version: 02.00.17 + * mpi2_ioc.h Version: 02.00.19 * * Version History * --------------- @@ -110,6 +110,13 @@ * Added Temperature Threshold Event. * Added Host Message Event. * Added Send Host Message request and reply. + * 05-25-11 02.00.18 For Extended Image Header, added + * MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC and + * MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC defines. + * Deprecated MPI2_EXT_IMAGE_TYPE_MAX define. + * 08-24-11 02.00.19 Added PhysicalPort field to + * MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE structure. + * Marked MPI2_PM_CONTROL_FEATURE_PCIE_LINK as obsolete. * -------------------------------------------------------------------------- */ @@ -578,7 +585,7 @@ typedef struct _MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE { U16 TaskTag; /* 0x00 */ U8 ReasonCode; /* 0x02 */ - U8 Reserved1; /* 0x03 */ + U8 PhysicalPort; /* 0x03 */ U8 ASC; /* 0x04 */ U8 ASCQ; /* 0x05 */ U16 DevHandle; /* 0x06 */ @@ -1366,16 +1373,18 @@ typedef struct _MPI2_EXT_IMAGE_HEADER #define MPI2_EXT_IMAGE_HEADER_SIZE (0x40) /* defines for the ImageType field */ -#define MPI2_EXT_IMAGE_TYPE_UNSPECIFIED (0x00) -#define MPI2_EXT_IMAGE_TYPE_FW (0x01) -#define MPI2_EXT_IMAGE_TYPE_NVDATA (0x03) -#define MPI2_EXT_IMAGE_TYPE_BOOTLOADER (0x04) -#define MPI2_EXT_IMAGE_TYPE_INITIALIZATION (0x05) -#define MPI2_EXT_IMAGE_TYPE_FLASH_LAYOUT (0x06) -#define MPI2_EXT_IMAGE_TYPE_SUPPORTED_DEVICES (0x07) -#define MPI2_EXT_IMAGE_TYPE_MEGARAID (0x08) - -#define MPI2_EXT_IMAGE_TYPE_MAX (MPI2_EXT_IMAGE_TYPE_MEGARAID) +#define MPI2_EXT_IMAGE_TYPE_UNSPECIFIED (0x00) +#define MPI2_EXT_IMAGE_TYPE_FW (0x01) +#define MPI2_EXT_IMAGE_TYPE_NVDATA (0x03) +#define MPI2_EXT_IMAGE_TYPE_BOOTLOADER (0x04) +#define MPI2_EXT_IMAGE_TYPE_INITIALIZATION (0x05) +#define MPI2_EXT_IMAGE_TYPE_FLASH_LAYOUT (0x06) +#define MPI2_EXT_IMAGE_TYPE_SUPPORTED_DEVICES (0x07) +#define MPI2_EXT_IMAGE_TYPE_MEGARAID (0x08) +#define MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC (0x80) +#define MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC (0xFF) +#define MPI2_EXT_IMAGE_TYPE_MAX \ + (MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC) /* deprecated */ @@ -1568,7 +1577,7 @@ typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST { /* defines for the Feature field */ #define MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND (0x01) #define MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION (0x02) -#define MPI2_PM_CONTROL_FEATURE_PCIE_LINK (0x03) +#define MPI2_PM_CONTROL_FEATURE_PCIE_LINK (0x03) /* obsolete */ #define MPI2_PM_CONTROL_FEATURE_IOC_SPEED (0x04) #define MPI2_PM_CONTROL_FEATURE_MIN_PRODUCT_SPECIFIC (0x80) #define MPI2_PM_CONTROL_FEATURE_MAX_PRODUCT_SPECIFIC (0xFF) @@ -1597,14 +1606,14 @@ typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST { /* parameter usage for the MPI2_PM_CONTROL_FEATURE_PCIE_LINK Feature */ /* Parameter1 indicates desired PCIe link speed using these defines */ -#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS (0x00) -#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS (0x01) -#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS (0x02) +#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS (0x00) /* obsolete */ +#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS (0x01) /* obsolete */ +#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS (0x02) /* obsolete */ /* Parameter2 indicates desired PCIe link width using these defines */ -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1 (0x01) -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2 (0x02) -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4 (0x04) -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8 (0x08) +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1 (0x01) /* obsolete */ +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2 (0x02) /* obsolete */ +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4 (0x04) /* obsolete */ +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8 (0x08) /* obsolete */ /* Parameter3 and Parameter4 are reserved */ /* parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h index bd61a7b60a2..0601612b875 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h @@ -6,7 +6,7 @@ * Title: MPI Integrated RAID messages and structures * Creation Date: April 26, 2007 * - * mpi2_raid.h Version: 02.00.05 + * mpi2_raid.h Version: 02.00.06 * * Version History * --------------- @@ -23,6 +23,10 @@ * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of * VolumeCreationFlags and marked the old one as obsolete. * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define. + * 08-24-10 02.00.06 Added MPI2_RAID_ACTION_COMPATIBILITY_CHECK along with + * related structures and defines. + * Added product-specific range to RAID Action values. + * -------------------------------------------------------------------------- */ @@ -176,7 +180,9 @@ typedef struct _MPI2_RAID_ACTION_REQUEST #define MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED (0x20) #define MPI2_RAID_ACTION_START_RAID_FUNCTION (0x21) #define MPI2_RAID_ACTION_STOP_RAID_FUNCTION (0x22) - +#define MPI2_RAID_ACTION_COMPATIBILITY_CHECK (0x23) +#define MPI2_RAID_ACTION_MIN_PRODUCT_SPECIFIC (0x80) +#define MPI2_RAID_ACTION_MAX_PRODUCT_SPECIFIC (0xFF) /* RAID Volume Creation Structure */ @@ -244,6 +250,23 @@ typedef struct _MPI2_RAID_ONLINE_CAPACITY_EXPANSION Mpi2RaidOnlineCapacityExpansion_t, MPI2_POINTER pMpi2RaidOnlineCapacityExpansion_t; +/* RAID Compatibility Input Structure */ + +typedef struct _MPI2_RAID_COMPATIBILITY_INPUT_STRUCT { + U16 SourceDevHandle; /* 0x00 */ + U16 CandidateDevHandle; /* 0x02 */ + U32 Flags; /* 0x04 */ + U32 Reserved1; /* 0x08 */ + U32 Reserved2; /* 0x0C */ +} MPI2_RAID_COMPATIBILITY_INPUT_STRUCT, +MPI2_POINTER PTR_MPI2_RAID_COMPATIBILITY_INPUT_STRUCT, +Mpi2RaidCompatibilityInputStruct_t, +MPI2_POINTER pMpi2RaidCompatibilityInputStruct_t; + +/* defines for RAID Compatibility Structure Flags field */ +#define MPI2_RAID_COMPAT_SOURCE_IS_VOLUME_FLAG (0x00000002) +#define MPI2_RAID_COMPAT_REPORT_SOURCE_INFO_FLAG (0x00000001) + /* RAID Volume Indicator Structure */ @@ -263,15 +286,45 @@ typedef struct _MPI2_RAID_VOL_INDICATOR #define MPI2_RAID_VOL_FLAGS_OP_RESYNC (0x00000003) #define MPI2_RAID_VOL_FLAGS_OP_MDC (0x00000004) +/* RAID Compatibility Result Structure */ + +typedef struct _MPI2_RAID_COMPATIBILITY_RESULT_STRUCT { + U8 State; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 GenericAttributes; /* 0x04 */ + U32 OEMSpecificAttributes; /* 0x08 */ + U32 Reserved3; /* 0x0C */ + U32 Reserved4; /* 0x10 */ +} MPI2_RAID_COMPATIBILITY_RESULT_STRUCT, +MPI2_POINTER PTR_MPI2_RAID_COMPATIBILITY_RESULT_STRUCT, +Mpi2RaidCompatibilityResultStruct_t, +MPI2_POINTER pMpi2RaidCompatibilityResultStruct_t; + +/* defines for RAID Compatibility Result Structure State field */ +#define MPI2_RAID_COMPAT_STATE_COMPATIBLE (0x00) +#define MPI2_RAID_COMPAT_STATE_NOT_COMPATIBLE (0x01) + +/* defines for RAID Compatibility Result Structure GenericAttributes field */ +#define MPI2_RAID_COMPAT_GENATTRIB_4K_SECTOR (0x00000010) + +#define MPI2_RAID_COMPAT_GENATTRIB_MEDIA_MASK (0x0000000C) +#define MPI2_RAID_COMPAT_GENATTRIB_SOLID_STATE_DRIVE (0x00000008) +#define MPI2_RAID_COMPAT_GENATTRIB_HARD_DISK_DRIVE (0x00000004) + +#define MPI2_RAID_COMPAT_GENATTRIB_PROTOCOL_MASK (0x00000003) +#define MPI2_RAID_COMPAT_GENATTRIB_SAS_PROTOCOL (0x00000002) +#define MPI2_RAID_COMPAT_GENATTRIB_SATA_PROTOCOL (0x00000001) /* RAID Action Reply ActionData union */ typedef union _MPI2_RAID_ACTION_REPLY_DATA { - U32 Word[5]; - MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator; - U16 VolDevHandle; - U8 VolumeState; - U8 PhysDiskNum; + U32 Word[5]; + MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator; + U16 VolDevHandle; + U8 VolumeState; + U8 PhysDiskNum; + MPI2_RAID_COMPATIBILITY_RESULT_STRUCT RaidCompatibilityResult; } MPI2_RAID_ACTION_REPLY_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY_DATA, Mpi2RaidActionReplyData_t, MPI2_POINTER pMpi2RaidActionReplyData_t; diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h index 2a4bceda364..3cbe677c688 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h @@ -6,7 +6,7 @@ * Title: MPI diagnostic tool structures and definitions * Creation Date: March 26, 2007 * - * mpi2_tool.h Version: 02.00.06 + * mpi2_tool.h Version: 02.00.07 * * Version History * --------------- @@ -25,6 +25,8 @@ * 05-12-10 02.00.05 Added Diagnostic Data Upload tool. * 08-11-10 02.00.06 Added defines that were missing for Diagnostic Buffer * Post Request. + * 05-25-11 02.00.07 Added Flags field and related defines to + * MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST. * -------------------------------------------------------------------------- */ @@ -181,7 +183,7 @@ typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST { U8 DevIndex; /* 0x14 */ U8 Action; /* 0x15 */ U8 SGLFlags; /* 0x16 */ - U8 Reserved7; /* 0x17 */ + U8 Flags; /* 0x17 */ U16 TxDataLength; /* 0x18 */ U16 RxDataLength; /* 0x1A */ U32 Reserved8; /* 0x1C */ @@ -205,6 +207,9 @@ typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST { /* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ +/* values for the Flags field */ +#define MPI2_TOOL_ISTWI_FLAG_AUTO_RESERVE_RELEASE (0x80) +#define MPI2_TOOL_ISTWI_FLAG_PAGE_ADDR_MASK (0x07) /* Toolbox ISTWI Read Write Tool reply message */ typedef struct _MPI2_TOOLBOX_ISTWI_REPLY { diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index beda04a8404..a78036f5e1a 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -57,6 +57,7 @@ #include <linux/sort.h> #include <linux/io.h> #include <linux/time.h> +#include <linux/kthread.h> #include <linux/aer.h> #include "mpt2sas_base.h" @@ -65,6 +66,8 @@ static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS]; #define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */ +#define MAX_HBA_QUEUE_DEPTH 30000 +#define MAX_CHAIN_DEPTH 100000 static int max_queue_depth = -1; module_param(max_queue_depth, int, 0); MODULE_PARM_DESC(max_queue_depth, " max controller queue depth "); @@ -89,19 +92,6 @@ static int disable_discovery = -1; module_param(disable_discovery, int, 0); MODULE_PARM_DESC(disable_discovery, " disable discovery "); - -/* diag_buffer_enable is bitwise - * bit 0 set = TRACE - * bit 1 set = SNAPSHOT - * bit 2 set = EXTENDED - * - * Either bit can be set, or both - */ -static int diag_buffer_enable; -module_param(diag_buffer_enable, int, 0); -MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers " - "(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)"); - /** * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug. * @@ -120,10 +110,34 @@ _scsih_set_fwfault_debug(const char *val, struct kernel_param *kp) ioc->fwfault_debug = mpt2sas_fwfault_debug; return 0; } + module_param_call(mpt2sas_fwfault_debug, _scsih_set_fwfault_debug, param_get_int, &mpt2sas_fwfault_debug, 0644); /** + * mpt2sas_remove_dead_ioc_func - kthread context to remove dead ioc + * @arg: input argument, used to derive ioc + * + * Return 0 if controller is removed from pci subsystem. + * Return -1 for other case. + */ +static int mpt2sas_remove_dead_ioc_func(void *arg) +{ + struct MPT2SAS_ADAPTER *ioc = (struct MPT2SAS_ADAPTER *)arg; + struct pci_dev *pdev; + + if ((ioc == NULL)) + return -1; + + pdev = ioc->pdev; + if ((pdev == NULL)) + return -1; + pci_remove_bus_device(pdev); + return 0; +} + + +/** * _base_fault_reset_work - workq handling ioc fault conditions * @work: input argument, used to derive ioc * Context: sleep. @@ -138,6 +152,7 @@ _base_fault_reset_work(struct work_struct *work) unsigned long flags; u32 doorbell; int rc; + struct task_struct *p; spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); if (ioc->shost_recovery) @@ -145,6 +160,39 @@ _base_fault_reset_work(struct work_struct *work) spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); doorbell = mpt2sas_base_get_iocstate(ioc, 0); + if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_MASK) { + printk(MPT2SAS_INFO_FMT "%s : SAS host is non-operational !!!!\n", + ioc->name, __func__); + + /* + * Call _scsih_flush_pending_cmds callback so that we flush all + * pending commands back to OS. This call is required to aovid + * deadlock at block layer. Dead IOC will fail to do diag reset, + * and this call is safe since dead ioc will never return any + * command back from HW. + */ + ioc->schedule_dead_ioc_flush_running_cmds(ioc); + /* + * Set remove_host flag early since kernel thread will + * take some time to execute. + */ + ioc->remove_host = 1; + /*Remove the Dead Host */ + p = kthread_run(mpt2sas_remove_dead_ioc_func, ioc, + "mpt2sas_dead_ioc_%d", ioc->id); + if (IS_ERR(p)) { + printk(MPT2SAS_ERR_FMT + "%s: Running mpt2sas_dead_ioc thread failed !!!!\n", + ioc->name, __func__); + } else { + printk(MPT2SAS_ERR_FMT + "%s: Running mpt2sas_dead_ioc thread success !!!!\n", + ioc->name, __func__); + } + + return; /* don't rearm timer */ + } + if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); @@ -1346,7 +1394,7 @@ _base_enable_msix(struct MPT2SAS_ADAPTER *ioc) if (_base_check_enable_msix(ioc) != 0) goto try_ioapic; - ioc->reply_queue_count = min_t(u8, ioc->cpu_count, + ioc->reply_queue_count = min_t(int, ioc->cpu_count, ioc->msix_vector_count); entries = kcalloc(ioc->reply_queue_count, sizeof(struct msix_entry), @@ -1916,6 +1964,10 @@ _base_display_intel_branding(struct MPT2SAS_ADAPTER *ioc) printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, MPT2SAS_INTEL_RMS2LL040_BRANDING); break; + case MPT2SAS_INTEL_RAMSDALE_SSDID: + printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RAMSDALE_BRANDING); + break; default: break; } @@ -1925,6 +1977,22 @@ _base_display_intel_branding(struct MPT2SAS_ADAPTER *ioc) printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, MPT2SAS_INTEL_RS25GB008_BRANDING); break; + case MPT2SAS_INTEL_RMS25JB080_SSDID: + printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS25JB080_BRANDING); + break; + case MPT2SAS_INTEL_RMS25JB040_SSDID: + printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS25JB040_BRANDING); + break; + case MPT2SAS_INTEL_RMS25KB080_SSDID: + printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS25KB080_BRANDING); + break; + case MPT2SAS_INTEL_RMS25KB040_SSDID: + printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS25KB040_BRANDING); + break; default: break; } @@ -2311,8 +2379,6 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc) } if (ioc->chain_dma_pool) pci_pool_destroy(ioc->chain_dma_pool); - } - if (ioc->chain_lookup) { free_pages((ulong)ioc->chain_lookup, ioc->chain_pages); ioc->chain_lookup = NULL; } @@ -2330,9 +2396,7 @@ static int _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) { struct mpt2sas_facts *facts; - u32 queue_size, queue_diff; u16 max_sge_elements; - u16 num_of_reply_frames; u16 chains_needed_per_io; u32 sz, total_sz, reply_post_free_sz; u32 retry_sz; @@ -2359,7 +2423,8 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) max_request_credit = (max_queue_depth < facts->RequestCredit) ? max_queue_depth : facts->RequestCredit; else - max_request_credit = facts->RequestCredit; + max_request_credit = min_t(u16, facts->RequestCredit, + MAX_HBA_QUEUE_DEPTH); ioc->hba_queue_depth = max_request_credit; ioc->hi_priority_depth = facts->HighPriorityCredit; @@ -2400,50 +2465,25 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) } ioc->chains_needed_per_io = chains_needed_per_io; - /* reply free queue sizing - taking into account for events */ - num_of_reply_frames = ioc->hba_queue_depth + 32; - - /* number of replies frames can't be a multiple of 16 */ - /* decrease number of reply frames by 1 */ - if (!(num_of_reply_frames % 16)) - num_of_reply_frames--; - - /* calculate number of reply free queue entries - * (must be multiple of 16) - */ - - /* (we know reply_free_queue_depth is not a multiple of 16) */ - queue_size = num_of_reply_frames; - queue_size += 16 - (queue_size % 16); - ioc->reply_free_queue_depth = queue_size; - - /* reply descriptor post queue sizing */ - /* this size should be the number of request frames + number of reply - * frames - */ - - queue_size = ioc->hba_queue_depth + num_of_reply_frames + 1; - /* round up to 16 byte boundary */ - if (queue_size % 16) - queue_size += 16 - (queue_size % 16); - - /* check against IOC maximum reply post queue depth */ - if (queue_size > facts->MaxReplyDescriptorPostQueueDepth) { - queue_diff = queue_size - - facts->MaxReplyDescriptorPostQueueDepth; - - /* round queue_diff up to multiple of 16 */ - if (queue_diff % 16) - queue_diff += 16 - (queue_diff % 16); + /* reply free queue sizing - taking into account for 64 FW events */ + ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64; - /* adjust hba_queue_depth, reply_free_queue_depth, - * and queue_size - */ - ioc->hba_queue_depth -= (queue_diff / 2); - ioc->reply_free_queue_depth -= (queue_diff / 2); - queue_size = facts->MaxReplyDescriptorPostQueueDepth; + /* align the reply post queue on the next 16 count boundary */ + if (!ioc->reply_free_queue_depth % 16) + ioc->reply_post_queue_depth = ioc->reply_free_queue_depth + 16; + else + ioc->reply_post_queue_depth = ioc->reply_free_queue_depth + + 32 - (ioc->reply_free_queue_depth % 16); + if (ioc->reply_post_queue_depth > + facts->MaxReplyDescriptorPostQueueDepth) { + ioc->reply_post_queue_depth = min_t(u16, + (facts->MaxReplyDescriptorPostQueueDepth - + (facts->MaxReplyDescriptorPostQueueDepth % 16)), + (ioc->hba_queue_depth - (ioc->hba_queue_depth % 16))); + ioc->reply_free_queue_depth = ioc->reply_post_queue_depth - 16; + ioc->hba_queue_depth = ioc->reply_free_queue_depth - 64; } - ioc->reply_post_queue_depth = queue_size; + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scatter gather: " "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), " @@ -2529,15 +2569,12 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) "depth(%d)\n", ioc->name, ioc->request, ioc->scsiio_depth)); - /* loop till the allocation succeeds */ - do { - sz = ioc->chain_depth * sizeof(struct chain_tracker); - ioc->chain_pages = get_order(sz); - ioc->chain_lookup = (struct chain_tracker *)__get_free_pages( - GFP_KERNEL, ioc->chain_pages); - if (ioc->chain_lookup == NULL) - ioc->chain_depth -= 100; - } while (ioc->chain_lookup == NULL); + ioc->chain_depth = min_t(u32, ioc->chain_depth, MAX_CHAIN_DEPTH); + sz = ioc->chain_depth * sizeof(struct chain_tracker); + ioc->chain_pages = get_order(sz); + + ioc->chain_lookup = (struct chain_tracker *)__get_free_pages( + GFP_KERNEL, ioc->chain_pages); ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev, ioc->request_sz, 16, 0); if (!ioc->chain_dma_pool) { @@ -3136,8 +3173,8 @@ mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc, if (mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) ioc->ioc_link_reset_in_progress = 1; - mpt2sas_base_put_smid_default(ioc, smid); init_completion(&ioc->base_cmds.done); + mpt2sas_base_put_smid_default(ioc, smid); timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, msecs_to_jiffies(10000)); if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || @@ -3238,8 +3275,8 @@ mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc, request = mpt2sas_base_get_msg_frame(ioc, smid); ioc->base_cmds.smid = smid; memcpy(request, mpi_request, sizeof(Mpi2SepReply_t)); - mpt2sas_base_put_smid_default(ioc, smid); init_completion(&ioc->base_cmds.done); + mpt2sas_base_put_smid_default(ioc, smid); timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, msecs_to_jiffies(10000)); if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { @@ -3746,8 +3783,8 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) mpi_request->EventMasks[i] = cpu_to_le32(ioc->event_masks[i]); - mpt2sas_base_put_smid_default(ioc, smid); init_completion(&ioc->base_cmds.done); + mpt2sas_base_put_smid_default(ioc, smid); timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ); if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { printk(MPT2SAS_ERR_FMT "%s: timeout\n", @@ -4062,7 +4099,8 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) ioc->reply_free[i] = cpu_to_le32(reply_address); /* initialize reply queues */ - _base_assign_reply_queues(ioc); + if (ioc->is_driver_loading) + _base_assign_reply_queues(ioc); /* initialize Reply Post Free Queue */ reply_post_free = (long)ioc->reply_post_free; @@ -4110,24 +4148,17 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) if (ioc->is_driver_loading) { - - - - ioc->wait_for_discovery_to_complete = - _base_determine_wait_on_discovery(ioc); - return r; /* scan_start and scan_finished support */ - } - - - if (ioc->wait_for_discovery_to_complete && ioc->is_warpdrive) { - if (ioc->manu_pg10.OEMIdentifier == 0x80) { + if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier + == 0x80) { hide_flag = (u8) (ioc->manu_pg10.OEMSpecificFlags0 & MFG_PAGE10_HIDE_SSDS_MASK); if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK) ioc->mfg_pg10_hide_flag = hide_flag; } + ioc->wait_for_discovery_to_complete = + _base_determine_wait_on_discovery(ioc); + return r; /* scan_start and scan_finished support */ } - r = _base_send_port_enable(ioc, sleep_flag); if (r) return r; @@ -4206,7 +4237,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) r = mpt2sas_base_map_resources(ioc); if (r) - return r; + goto out_free_resources; if (ioc->is_warpdrive) { ioc->reply_post_host_index[0] = @@ -4517,7 +4548,7 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, printk(MPT2SAS_ERR_FMT "%s: pci error recovery reset\n", ioc->name, __func__); r = 0; - goto out; + goto out_unlocked; } if (mpt2sas_fwfault_debug) @@ -4573,6 +4604,7 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); mutex_unlock(&ioc->reset_in_progress_mutex); + out_unlocked: dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name, __func__)); return r; diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 3c3babc7d26..c7459fdc06c 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -69,8 +69,8 @@ #define MPT2SAS_DRIVER_NAME "mpt2sas" #define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>" #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION "10.100.00.00" -#define MPT2SAS_MAJOR_VERSION 10 +#define MPT2SAS_DRIVER_VERSION "12.100.00.00" +#define MPT2SAS_MAJOR_VERSION 12 #define MPT2SAS_MINOR_VERSION 100 #define MPT2SAS_BUILD_VERSION 00 #define MPT2SAS_RELEASE_VERSION 00 @@ -157,20 +157,33 @@ /* * Intel HBA branding */ +#define MPT2SAS_INTEL_RMS25JB080_BRANDING \ + "Intel(R) Integrated RAID Module RMS25JB080" +#define MPT2SAS_INTEL_RMS25JB040_BRANDING \ + "Intel(R) Integrated RAID Module RMS25JB040" +#define MPT2SAS_INTEL_RMS25KB080_BRANDING \ + "Intel(R) Integrated RAID Module RMS25KB080" +#define MPT2SAS_INTEL_RMS25KB040_BRANDING \ + "Intel(R) Integrated RAID Module RMS25KB040" #define MPT2SAS_INTEL_RMS2LL080_BRANDING \ "Intel Integrated RAID Module RMS2LL080" #define MPT2SAS_INTEL_RMS2LL040_BRANDING \ "Intel Integrated RAID Module RMS2LL040" #define MPT2SAS_INTEL_RS25GB008_BRANDING \ "Intel(R) RAID Controller RS25GB008" - +#define MPT2SAS_INTEL_RAMSDALE_BRANDING \ + "Intel 720 Series SSD" /* * Intel HBA SSDIDs */ +#define MPT2SAS_INTEL_RMS25JB080_SSDID 0x3516 +#define MPT2SAS_INTEL_RMS25JB040_SSDID 0x3517 +#define MPT2SAS_INTEL_RMS25KB080_SSDID 0x3518 +#define MPT2SAS_INTEL_RMS25KB040_SSDID 0x3519 #define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E #define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F #define MPT2SAS_INTEL_RS25GB008_SSDID 0x3000 - +#define MPT2SAS_INTEL_RAMSDALE_SSDID 0x3700 /* * HP HBA branding @@ -373,6 +386,7 @@ struct _sas_device { * @percent_complete: resync percent complete * @direct_io_enabled: Whether direct io to PDs are allowed or not * @stripe_exponent: X where 2powX is the stripe sz in blocks + * @block_exponent: X where 2powX is the block sz in bytes * @max_lba: Maximum number of LBA in the volume * @stripe_sz: Stripe Size of the volume * @device_info: Device info of the volume member disk @@ -394,6 +408,7 @@ struct _raid_device { u8 percent_complete; u8 direct_io_enabled; u8 stripe_exponent; + u8 block_exponent; u64 max_lba; u32 stripe_sz; u32 device_info; @@ -623,6 +638,7 @@ enum mutex_type { TM_MUTEX_ON = 1, }; +typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc); /** * struct MPT2SAS_ADAPTER - per adapter struct * @list: ioc_list @@ -665,6 +681,7 @@ enum mutex_type { * @msix_vector_count: number msix vectors * @cpu_msix_table: table for mapping cpus to msix index * @cpu_msix_table_sz: table size + * @schedule_dead_ioc_flush_running_cmds: callback to flush pending commands * @scsi_io_cb_idx: shost generated commands * @tm_cb_idx: task management commands * @scsih_cb_idx: scsih internal commands @@ -816,6 +833,7 @@ struct MPT2SAS_ADAPTER { resource_size_t **reply_post_host_index; u16 cpu_msix_table_sz; u32 ioc_reset_count; + MPT2SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds; /* internal commands, callback index */ u8 scsi_io_cb_idx; diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index aabcb911706..7fceb899029 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -818,6 +818,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, _ctl_display_some_debug(ioc, smid, "ctl_request", NULL); #endif + init_completion(&ioc->ctl_cmds.done); switch (mpi_request->Function) { case MPI2_FUNCTION_SCSI_IO_REQUEST: case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: @@ -903,7 +904,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, timeout = MPT2_IOCTL_DEFAULT_TIMEOUT; else timeout = karg.timeout; - init_completion(&ioc->ctl_cmds.done); timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, timeout*HZ); if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { @@ -1477,8 +1477,8 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc, mpi_request->ProductSpecific[i] = cpu_to_le32(ioc->product_specific[buffer_type][i]); - mpt2sas_base_put_smid_default(ioc, smid); init_completion(&ioc->ctl_cmds.done); + mpt2sas_base_put_smid_default(ioc, smid); timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -1821,8 +1821,8 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset) mpi_request->VF_ID = 0; /* TODO */ mpi_request->VP_ID = 0; - mpt2sas_base_put_smid_default(ioc, smid); init_completion(&ioc->ctl_cmds.done); + mpt2sas_base_put_smid_default(ioc, smid); timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -2095,8 +2095,8 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) mpi_request->VF_ID = 0; /* TODO */ mpi_request->VP_ID = 0; - mpt2sas_base_put_smid_default(ioc, smid); init_completion(&ioc->ctl_cmds.done); + mpt2sas_base_put_smid_default(ioc, smid); timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 4e041f6d808..193e33e28e4 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -99,7 +99,7 @@ MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info " static ushort max_sectors = 0xFFFF; module_param(max_sectors, ushort, 0); -MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 8192 default=8192"); +MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 32767 default=32767"); /* scsi-mid layer global parmeter is max_report_luns, which is 511 */ #define MPT2SAS_MAX_LUN (16895) @@ -612,13 +612,17 @@ _scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc, if (!mpt2sas_transport_port_add(ioc, sas_device->handle, sas_device->sas_address_parent)) { _scsih_sas_device_remove(ioc, sas_device); - } else if (!sas_device->starget) { - if (!ioc->is_driver_loading) - mpt2sas_transport_port_remove(ioc, - sas_device->sas_address, - sas_device->sas_address_parent); - _scsih_sas_device_remove(ioc, sas_device); - } + } else if (!sas_device->starget) { + /* When asyn scanning is enabled, its not possible to remove + * devices while scanning is turned on due to an oops in + * scsi_sysfs_add_sdev()->add_device()->sysfs_addrm_start() + */ + if (!ioc->is_driver_loading) + mpt2sas_transport_port_remove(ioc, + sas_device->sas_address, + sas_device->sas_address_parent); + _scsih_sas_device_remove(ioc, sas_device); + } } /** @@ -1007,8 +1011,8 @@ _scsih_get_chain_buffer_tracker(struct MPT2SAS_ADAPTER *ioc, u16 smid) spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); if (list_empty(&ioc->free_chain_list)) { spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - printk(MPT2SAS_WARN_FMT "chain buffers not available\n", - ioc->name); + dfailprintk(ioc, printk(MPT2SAS_WARN_FMT "chain buffers not " + "available\n", ioc->name)); return NULL; } chain_req = list_entry(ioc->free_chain_list.next, @@ -1449,7 +1453,7 @@ _scsih_slave_destroy(struct scsi_device *sdev) spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, sas_target_priv_data->sas_address); - if (sas_device) + if (sas_device && !sas_target_priv_data->num_luns) sas_device->starget = NULL; spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } @@ -1776,11 +1780,9 @@ _scsih_init_warpdrive_properties(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t mpi_reply; u16 sz; u8 num_pds, count; - u64 mb = 1024 * 1024; - u64 tb_2 = 2 * mb * mb; - u64 capacity; - u32 stripe_sz; - u8 i, stripe_exp; + unsigned long stripe_sz, block_sz; + u8 stripe_exp, block_exp; + u64 dev_max_lba; if (!ioc->is_warpdrive) return; @@ -1844,51 +1846,57 @@ _scsih_init_warpdrive_properties(struct MPT2SAS_ADAPTER *ioc, vol_pg0->PhysDisk[count].PhysDiskNum); goto out_error; } + /* Disable direct I/O if member drive lba exceeds 4 bytes */ + dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA); + if (dev_max_lba >> 32) { + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is " + "disabled for the drive with handle(0x%04x) member" + "handle (0x%04x) unsupported max lba 0x%016llx\n", + ioc->name, raid_device->handle, + le16_to_cpu(pd_pg0.DevHandle), + (unsigned long long)dev_max_lba); + goto out_error; + } + raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle); } /* * Assumption for WD: Direct I/O is not supported if the volume is - * not RAID0, if the stripe size is not 64KB, if the block size is - * not 512 and if the volume size is >2TB + * not RAID0 */ - if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0 || - le16_to_cpu(vol_pg0->BlockSize) != 512) { + if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) { printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " "for the drive with handle(0x%04x): type=%d, " "s_sz=%uK, blk_size=%u\n", ioc->name, raid_device->handle, raid_device->volume_type, - le32_to_cpu(vol_pg0->StripeSize)/2, + (le32_to_cpu(vol_pg0->StripeSize) * + le16_to_cpu(vol_pg0->BlockSize)) / 1024, le16_to_cpu(vol_pg0->BlockSize)); goto out_error; } - capacity = (u64) le16_to_cpu(vol_pg0->BlockSize) * - (le64_to_cpu(vol_pg0->MaxLBA) + 1); - - if (capacity > tb_2) { + stripe_sz = le32_to_cpu(vol_pg0->StripeSize); + stripe_exp = find_first_bit(&stripe_sz, 32); + if (stripe_exp == 32) { printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "for the drive with handle(0x%04x) since drive sz > 2TB\n", - ioc->name, raid_device->handle); + "for the drive with handle(0x%04x) invalid stripe sz %uK\n", + ioc->name, raid_device->handle, + (le32_to_cpu(vol_pg0->StripeSize) * + le16_to_cpu(vol_pg0->BlockSize)) / 1024); goto out_error; } - - stripe_sz = le32_to_cpu(vol_pg0->StripeSize); - stripe_exp = 0; - for (i = 0; i < 32; i++) { - if (stripe_sz & 1) - break; - stripe_exp++; - stripe_sz >>= 1; - } - if (i == 32) { + raid_device->stripe_exponent = stripe_exp; + block_sz = le16_to_cpu(vol_pg0->BlockSize); + block_exp = find_first_bit(&block_sz, 16); + if (block_exp == 16) { printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "for the drive with handle(0x%04x) invalid stripe sz %uK\n", + "for the drive with handle(0x%04x) invalid block sz %u\n", ioc->name, raid_device->handle, - le32_to_cpu(vol_pg0->StripeSize)/2); + le16_to_cpu(vol_pg0->BlockSize)); goto out_error; } - raid_device->stripe_exponent = stripe_exp; + raid_device->block_exponent = block_exp; raid_device->direct_io_enabled = 1; printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is Enabled for the drive" @@ -3804,8 +3812,9 @@ _scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, { u32 v_lba, p_lba, stripe_off, stripe_unit, column, io_size; u32 stripe_sz, stripe_exp; - u8 num_pds, *cdb_ptr, *tmp_ptr, *lba_ptr1, *lba_ptr2; + u8 num_pds, *cdb_ptr, i; u8 cdb0 = scmd->cmnd[0]; + u64 v_llba; /* * Try Direct I/O to RAID memeber disks @@ -3816,15 +3825,11 @@ _scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, if ((cdb0 < READ_16) || !(cdb_ptr[2] | cdb_ptr[3] | cdb_ptr[4] | cdb_ptr[5])) { - io_size = scsi_bufflen(scmd) >> 9; + io_size = scsi_bufflen(scmd) >> + raid_device->block_exponent; + i = (cdb0 < READ_16) ? 2 : 6; /* get virtual lba */ - lba_ptr1 = lba_ptr2 = (cdb0 < READ_16) ? &cdb_ptr[2] : - &cdb_ptr[6]; - tmp_ptr = (u8 *)&v_lba + 3; - *tmp_ptr-- = *lba_ptr1++; - *tmp_ptr-- = *lba_ptr1++; - *tmp_ptr-- = *lba_ptr1++; - *tmp_ptr = *lba_ptr1; + v_lba = be32_to_cpu(*(__be32 *)(&cdb_ptr[i])); if (((u64)v_lba + (u64)io_size - 1) <= (u32)raid_device->max_lba) { @@ -3843,11 +3848,39 @@ _scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, mpi_request->DevHandle = cpu_to_le16(raid_device-> pd_handle[column]); - tmp_ptr = (u8 *)&p_lba + 3; - *lba_ptr2++ = *tmp_ptr--; - *lba_ptr2++ = *tmp_ptr--; - *lba_ptr2++ = *tmp_ptr--; - *lba_ptr2 = *tmp_ptr; + (*(__be32 *)(&cdb_ptr[i])) = + cpu_to_be32(p_lba); + /* + * WD: To indicate this I/O is directI/O + */ + _scsih_scsi_direct_io_set(ioc, smid, 1); + } + } + } else { + io_size = scsi_bufflen(scmd) >> + raid_device->block_exponent; + /* get virtual lba */ + v_llba = be64_to_cpu(*(__be64 *)(&cdb_ptr[2])); + + if ((v_llba + (u64)io_size - 1) <= + raid_device->max_lba) { + stripe_sz = raid_device->stripe_sz; + stripe_exp = raid_device->stripe_exponent; + stripe_off = (u32) (v_llba & (stripe_sz - 1)); + + /* Check whether IO falls within a stripe */ + if ((stripe_off + io_size) <= stripe_sz) { + num_pds = raid_device->num_pds; + p_lba = (u32)(v_llba >> stripe_exp); + stripe_unit = p_lba / num_pds; + column = p_lba % num_pds; + p_lba = (stripe_unit << stripe_exp) + + stripe_off; + mpi_request->DevHandle = + cpu_to_le16(raid_device-> + pd_handle[column]); + (*(__be64 *)(&cdb_ptr[2])) = + cpu_to_be64((u64)p_lba); /* * WD: To indicate this I/O is directI/O */ @@ -4335,7 +4368,7 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle) /* insert into event log */ sz = offsetof(Mpi2EventNotificationReply_t, EventData) + sizeof(Mpi2EventDataSasDeviceStatusChange_t); - event_reply = kzalloc(sz, GFP_KERNEL); + event_reply = kzalloc(sz, GFP_ATOMIC); if (!event_reply) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); @@ -4403,11 +4436,14 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) scmd->result = DID_NO_CONNECT << 16; goto out; } + ioc_status = le16_to_cpu(mpi_reply->IOCStatus); /* * WARPDRIVE: If direct_io is set then it is directIO, * the failed direct I/O should be redirected to volume */ - if (_scsih_scsi_direct_io_get(ioc, smid)) { + if (_scsih_scsi_direct_io_get(ioc, smid) && + ((ioc_status & MPI2_IOCSTATUS_MASK) + != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) { spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); ioc->scsi_lookup[smid - 1].scmd = scmd; spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); @@ -4441,7 +4477,6 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) xfer_cnt = le32_to_cpu(mpi_reply->TransferCount); scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt); - ioc_status = le16_to_cpu(mpi_reply->IOCStatus); if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) log_info = le32_to_cpu(mpi_reply->IOCLogInfo); else @@ -4485,6 +4520,8 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) scmd->result = DID_TRANSPORT_DISRUPTED << 16; goto out; } + scmd->result = DID_SOFT_ERROR << 16; + break; case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: scmd->result = DID_RESET << 16; @@ -6714,6 +6751,7 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid, } else sas_target_priv_data = NULL; raid_device->responding = 1; + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); starget_printk(KERN_INFO, raid_device->starget, "handle(0x%04x), wwid(0x%016llx)\n", handle, (unsigned long long)raid_device->wwid); @@ -6724,16 +6762,16 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid, */ _scsih_init_warpdrive_properties(ioc, raid_device); if (raid_device->handle == handle) - goto out; + return; printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", raid_device->handle); raid_device->handle = handle; if (sas_target_priv_data) sas_target_priv_data->handle = handle; - goto out; + return; } } - out: + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); } @@ -7418,7 +7456,7 @@ static struct scsi_host_template scsih_driver_template = { .can_queue = 1, .this_id = -1, .sg_tablesize = MPT2SAS_SG_DEPTH, - .max_sectors = 8192, + .max_sectors = 32767, .cmd_per_lun = 7, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = mpt2sas_host_attrs, @@ -7928,6 +7966,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->tm_tr_volume_cb_idx = tm_tr_volume_cb_idx; ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx; ioc->logging_level = logging_level; + ioc->schedule_dead_ioc_flush_running_cmds = &_scsih_flush_running_cmds; /* misc semaphores and spin locks */ mutex_init(&ioc->reset_in_progress_mutex); spin_lock_init(&ioc->ioc_reset_in_progress_lock); @@ -7958,11 +7997,11 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) printk(MPT2SAS_WARN_FMT "Invalid value %d passed " "for max_sectors, range is 64 to 8192. Assigning " "value of 64.\n", ioc->name, max_sectors); - } else if (max_sectors > 8192) { - shost->max_sectors = 8192; + } else if (max_sectors > 32767) { + shost->max_sectors = 32767; printk(MPT2SAS_WARN_FMT "Invalid value %d passed " "for max_sectors, range is 64 to 8192. Assigning " - "default value of 8192.\n", ioc->name, + "default value of 32767.\n", ioc->name, max_sectors); } else { shost->max_sectors = max_sectors & 0xFFFE; @@ -8000,7 +8039,6 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_attach_fail; } - scsi_scan_host(shost); if (ioc->is_warpdrive) { if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) ioc->hide_drives = 0; @@ -8014,8 +8052,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) } } else ioc->hide_drives = 0; + scsi_scan_host(shost); - _scsih_probe_devices(ioc); return 0; out_attach_fail: diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index 230732241aa..831047466a5 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -398,8 +398,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - " "send to sas_addr(0x%016llx)\n", ioc->name, (unsigned long long)sas_address)); - mpt2sas_base_put_smid_default(ioc, smid); init_completion(&ioc->transport_cmds.done); + mpt2sas_base_put_smid_default(ioc, smid); timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); @@ -1184,8 +1184,8 @@ _transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc, dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - " "send to sas_addr(0x%016llx), phy(%d)\n", ioc->name, (unsigned long long)phy->identify.sas_address, phy->number)); - mpt2sas_base_put_smid_default(ioc, smid); init_completion(&ioc->transport_cmds.done); + mpt2sas_base_put_smid_default(ioc, smid); timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); @@ -1509,8 +1509,9 @@ _transport_expander_phy_control(struct MPT2SAS_ADAPTER *ioc, "send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n", ioc->name, (unsigned long long)phy->identify.sas_address, phy->number, phy_operation)); - mpt2sas_base_put_smid_default(ioc, smid); + init_completion(&ioc->transport_cmds.done); + mpt2sas_base_put_smid_default(ioc, smid); timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); @@ -1949,8 +1950,8 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - " "sending smp request\n", ioc->name, __func__)); - mpt2sas_base_put_smid_default(ioc, smid); init_completion(&ioc->transport_cmds.done); + mpt2sas_base_put_smid_default(ioc, smid); timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index f6a50c98c36..002924963cd 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -59,11 +59,11 @@ MODULE_PARM_DESC(trans_mode, "transfer mode (0: BIOS(default) 1: Async 2: Ultra2 #define ASYNC_MODE 1 #define ULTRA20M_MODE 2 -static int auto_param = 0; /* default: ON */ +static bool auto_param = 0; /* default: ON */ module_param (auto_param, bool, 0); MODULE_PARM_DESC(auto_param, "AutoParameter mode (0: ON(default) 1: OFF)"); -static int disc_priv = 1; /* default: OFF */ +static bool disc_priv = 1; /* default: OFF */ module_param (disc_priv, bool, 0); MODULE_PARM_DESC(disc_priv, "disconnection privilege mode (0: ON 1: OFF(default))"); diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c index b31a8e3841d..d4ed9eb5265 100644 --- a/drivers/scsi/osd/osd_uld.c +++ b/drivers/scsi/osd/osd_uld.c @@ -69,10 +69,10 @@ #ifndef SCSI_OSD_MAJOR # define SCSI_OSD_MAJOR 260 #endif -#define SCSI_OSD_MAX_MINOR 64 +#define SCSI_OSD_MAX_MINOR MINORMASK static const char osd_name[] = "osd"; -static const char *osd_version_string = "open-osd 0.2.0"; +static const char *osd_version_string = "open-osd 0.2.1"; MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>"); MODULE_DESCRIPTION("open-osd Upper-Layer-Driver osd.ko"); diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index ca86721a71b..b61a753eb89 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -70,7 +70,7 @@ module_param(nsp_burst_mode, int, 0); MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))"); /* Release IO ports after configuration? */ -static int free_ports = 0; +static bool free_ports = 0; module_param(free_ports, bool, 0); MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))"); diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 5163edb925c..ea8a0b47d66 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -4105,7 +4105,7 @@ static long pmcraid_chr_ioctl( hdr = kmalloc(sizeof(struct pmcraid_ioctl_header), GFP_KERNEL); if (!hdr) { - pmcraid_err("faile to allocate memory for ioctl header\n"); + pmcraid_err("failed to allocate memory for ioctl header\n"); return -ENOMEM; } diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index ac326c41e93..9f41b3b4358 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -107,7 +107,7 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj, set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); break; } - return -EINVAL; + return count; } static struct bin_attribute sysfs_fw_dump_attr = { @@ -387,7 +387,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, break; case 3: if (ha->optrom_state != QLA_SWRITING) - return -ENOMEM; + return -EINVAL; if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x7068, @@ -667,7 +667,7 @@ qla2x00_sysfs_write_edc(struct file *filp, struct kobject *kobj, dev, adr, len, opt); if (rval != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x7074, - "Unable to write EDC (%x) %02x:%04x:%02x:%02hhx\n", + "Unable to write EDC (%x) %02x:%04x:%02x:%02x:%02hhx\n", rval, dev, adr, opt, len, buf[8]); return -EIO; } @@ -724,7 +724,7 @@ qla2x00_sysfs_write_edc_status(struct file *filp, struct kobject *kobj, dev, adr, len, opt); if (rval != QLA_SUCCESS) { ql_log(ql_log_info, vha, 0x7075, - "Unable to write EDC status (%x) %02x:%04x:%02x.\n", + "Unable to write EDC status (%x) %02x:%04x:%02x:%02x.\n", rval, dev, adr, opt, len); return -EIO; } @@ -1036,8 +1036,7 @@ qla2x00_link_state_show(struct device *dev, struct device_attribute *attr, vha->device_flags & DFLG_NO_CABLE) len = snprintf(buf, PAGE_SIZE, "Link Down\n"); else if (atomic_read(&vha->loop_state) != LOOP_READY || - test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || - test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) + qla2x00_reset_active(vha)) len = snprintf(buf, PAGE_SIZE, "Unknown Link State\n"); else { len = snprintf(buf, PAGE_SIZE, "Link Up - "); @@ -1359,8 +1358,7 @@ qla2x00_thermal_temp_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "\n"); temp = frac = 0; - if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || - test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) + if (qla2x00_reset_active(vha)) ql_log(ql_log_warn, vha, 0x707b, "ISP reset active.\n"); else if (!vha->hw->flags.eeh_busy) @@ -1379,8 +1377,7 @@ qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr, int rval = QLA_FUNCTION_FAILED; uint16_t state[5]; - if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || - test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) + if (qla2x00_reset_active(vha)) ql_log(ql_log_warn, vha, 0x707c, "ISP reset active.\n"); else if (!vha->hw->flags.eeh_busy) @@ -1693,9 +1690,7 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost) if (IS_FWI2_CAPABLE(ha)) { rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma); } else if (atomic_read(&base_vha->loop_state) == LOOP_READY && - !test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) && - !test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags) && - !ha->dpc_active) { + !qla2x00_reset_active(vha) && !ha->dpc_active) { /* Must be in a 'READY' state for statistics retrieval. */ rval = qla2x00_get_link_status(base_vha, base_vha->loop_id, stats, stats_dma); @@ -1762,12 +1757,31 @@ qla2x00_get_host_port_state(struct Scsi_Host *shost) scsi_qla_host_t *vha = shost_priv(shost); struct scsi_qla_host *base_vha = pci_get_drvdata(vha->hw->pdev); - if (!base_vha->flags.online) + if (!base_vha->flags.online) { fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; - else if (atomic_read(&base_vha->loop_state) == LOOP_TIMEOUT) - fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; - else + return; + } + + switch (atomic_read(&base_vha->loop_state)) { + case LOOP_UPDATE: + fc_host_port_state(shost) = FC_PORTSTATE_DIAGNOSTICS; + break; + case LOOP_DOWN: + if (test_bit(LOOP_RESYNC_NEEDED, &base_vha->dpc_flags)) + fc_host_port_state(shost) = FC_PORTSTATE_DIAGNOSTICS; + else + fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; + break; + case LOOP_DEAD: + fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; + break; + case LOOP_READY: fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; + break; + default: + fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; + break; + } } static int @@ -1952,8 +1966,8 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) "Queue delete failed.\n"); } - scsi_host_put(vha->host); ql_log(ql_log_info, vha, 0x7088, "VP[%d] deleted.\n", id); + scsi_host_put(vha->host); return 0; } diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 8b641a8a0c7..1682e2e4201 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -31,6 +31,7 @@ qla2x00_get_ctx_bsg_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size) memset(sp, 0, sizeof(*sp)); sp->fcport = fcport; sp->ctx = ctx; + ctx->iocbs = 1; done: return sp; } @@ -102,18 +103,11 @@ qla24xx_proc_fcp_prio_cfg_cmd(struct fc_bsg_job *bsg_job) bsg_job->reply->reply_payload_rcv_len = 0; - if (!(IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha))) { + if (!(IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_QLA82XX(ha))) { ret = -EINVAL; goto exit_fcp_prio_cfg; } - if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || - test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || - test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { - ret = -EBUSY; - goto exit_fcp_prio_cfg; - } - /* Get the sub command */ oper = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; @@ -389,6 +383,20 @@ done: return rval; } +inline uint16_t +qla24xx_calc_ct_iocbs(uint16_t dsds) +{ + uint16_t iocbs; + + iocbs = 1; + if (dsds > 2) { + iocbs += (dsds - 2) / 5; + if ((dsds - 2) % 5) + iocbs++; + } + return iocbs; +} + static int qla2x00_process_ct(struct fc_bsg_job *bsg_job) { @@ -489,6 +497,7 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job) ct = sp->ctx; ct->type = SRB_CT_CMD; ct->name = "bsg_ct"; + ct->iocbs = qla24xx_calc_ct_iocbs(req_sg_cnt + rsp_sg_cnt); ct->u.bsg_job = bsg_job; ql_dbg(ql_dbg_user, vha, 0x7016, @@ -630,13 +639,6 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job) dma_addr_t rsp_data_dma; uint32_t rsp_data_len; - if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || - test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || - test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { - ql_log(ql_log_warn, vha, 0x7018, "Abort active or needed.\n"); - return -EBUSY; - } - if (!vha->flags.online) { ql_log(ql_log_warn, vha, 0x7019, "Host is not online.\n"); return -EIO; @@ -858,13 +860,6 @@ qla84xx_reset(struct fc_bsg_job *bsg_job) int rval = 0; uint32_t flag; - if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || - test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || - test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { - ql_log(ql_log_warn, vha, 0x702e, "Abort active or needed.\n"); - return -EBUSY; - } - if (!IS_QLA84XX(ha)) { ql_dbg(ql_dbg_user, vha, 0x702f, "Not 84xx, exiting.\n"); return -EINVAL; @@ -906,11 +901,6 @@ qla84xx_updatefw(struct fc_bsg_job *bsg_job) uint32_t flag; uint32_t fw_ver; - if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || - test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || - test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) - return -EBUSY; - if (!IS_QLA84XX(ha)) { ql_dbg(ql_dbg_user, vha, 0x7032, "Not 84xx, exiting.\n"); @@ -1020,14 +1010,6 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job) uint32_t data_len = 0; uint32_t dma_direction = DMA_NONE; - if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || - test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || - test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { - ql_log(ql_log_warn, vha, 0x7039, - "Abort active or needed.\n"); - return -EBUSY; - } - if (!IS_QLA84XX(ha)) { ql_log(ql_log_warn, vha, 0x703a, "Not 84xx, exiting.\n"); @@ -1230,13 +1212,6 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job) bsg_job->reply->reply_payload_rcv_len = 0; - if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || - test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || - test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { - ql_log(ql_log_warn, vha, 0x7045, "abort active or needed.\n"); - return -EBUSY; - } - if (!IS_IIDMA_CAPABLE(vha->hw)) { ql_log(ql_log_info, vha, 0x7046, "iiDMA not supported.\n"); return -EINVAL; @@ -1652,8 +1627,17 @@ qla24xx_bsg_request(struct fc_bsg_job *bsg_job) vha = shost_priv(host); } + if (qla2x00_reset_active(vha)) { + ql_dbg(ql_dbg_user, vha, 0x709f, + "BSG: ISP abort active/needed -- cmd=%d.\n", + bsg_job->request->msgcode); + bsg_job->reply->result = (DID_ERROR << 16); + bsg_job->job_done(bsg_job); + return -EBUSY; + } + ql_dbg(ql_dbg_user, vha, 0x7000, - "Entered %s msgcode=%d.\n", __func__, bsg_job->request->msgcode); + "Entered %s msgcode=0x%x.\n", __func__, bsg_job->request->msgcode); switch (bsg_job->request->msgcode) { case FC_BSG_RPT_ELS: diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 9df4787715c..45cbf0ba624 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -11,18 +11,21 @@ * ---------------------------------------------------------------------- * | Level | Last Value Used | Holes | * ---------------------------------------------------------------------- - * | Module Init and Probe | 0x0116 | | - * | Mailbox commands | 0x1129 | | - * | Device Discovery | 0x2083 | | - * | Queue Command and IO tracing | 0x302e | 0x3008 | + * | Module Init and Probe | 0x0116 | 0xfa | + * | Mailbox commands | 0x112b | | + * | Device Discovery | 0x2084 | | + * | Queue Command and IO tracing | 0x302f | 0x3008,0x302d, | + * | | | 0x302e | * | DPC Thread | 0x401c | | - * | Async Events | 0x5059 | | - * | Timer Routines | 0x600d | | - * | User Space Interactions | 0x709d | | - * | Task Management | 0x8041 | | + * | Async Events | 0x5057 | 0x5052 | + * | Timer Routines | 0x6011 | 0x600e,0x600f | + * | User Space Interactions | 0x709e | 0x7018,0x702e | + * | | | 0x7039,0x7045 | + * | Task Management | 0x803c | 0x8025-0x8026 | + * | | | 0x800b,0x8039 | * | AER/EEH | 0x900f | | * | Virtual Port | 0xa007 | | - * | ISP82XX Specific | 0xb051 | | + * | ISP82XX Specific | 0xb052 | | * | MultiQ | 0xc00b | | * | Misc | 0xd00b | | * ---------------------------------------------------------------------- @@ -368,7 +371,7 @@ qla25xx_copy_fce(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) memcpy(iter_reg, ha->fce, ntohl(fcec->size)); - return iter_reg; + return (char *)iter_reg + ntohl(fcec->size); } static inline void * @@ -1650,6 +1653,15 @@ qla81xx_fw_dump_failed: /****************************************************************************/ /* Driver Debug Functions. */ /****************************************************************************/ + +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; +} + /* * This function is for formatting and logging debug information. * It is to be used when vha is available. It formats the message @@ -1664,34 +1676,31 @@ qla81xx_fw_dump_failed: * msg: The message to be displayed. */ void -ql_dbg(uint32_t level, scsi_qla_host_t *vha, int32_t id, char *msg, ...) { - - char pbuf[QL_DBG_BUF_LEN]; - va_list ap; - uint32_t len; - struct pci_dev *pdev = NULL; - - memset(pbuf, 0, QL_DBG_BUF_LEN); - - va_start(ap, msg); - - if ((level & ql2xextended_error_logging) == level) { - if (vha != NULL) { - pdev = vha->hw->pdev; - /* <module-name> <pci-name> <msg-id>:<host> Message */ - sprintf(pbuf, "%s [%s]-%04x:%ld: ", QL_MSGHDR, - dev_name(&(pdev->dev)), id + ql_dbg_offset, - vha->host_no); - } else - sprintf(pbuf, "%s [%s]-%04x: : ", QL_MSGHDR, - "0000:00:00.0", id + ql_dbg_offset); - - len = strlen(pbuf); - vsprintf(pbuf+len, msg, ap); - pr_warning("%s", pbuf); +ql_dbg(uint32_t level, scsi_qla_host_t *vha, int32_t id, const char *fmt, ...) +{ + va_list va; + struct va_format vaf; + + if (!ql_mask_match(level)) + return; + + va_start(va, fmt); + + vaf.fmt = fmt; + vaf.va = &va; + + if (vha != NULL) { + const struct pci_dev *pdev = vha->hw->pdev; + /* <module-name> <pci-name> <msg-id>:<host> Message */ + pr_warn("%s [%s]-%04x:%ld: %pV", + QL_MSGHDR, dev_name(&(pdev->dev)), id + ql_dbg_offset, + vha->host_no, &vaf); + } else { + pr_warn("%s [%s]-%04x: : %pV", + QL_MSGHDR, "0000:00:00.0", id + ql_dbg_offset, &vaf); } - va_end(ap); + va_end(va); } @@ -1710,31 +1719,27 @@ ql_dbg(uint32_t level, scsi_qla_host_t *vha, int32_t id, char *msg, ...) { * msg: The message to be displayed. */ void -ql_dbg_pci(uint32_t level, struct pci_dev *pdev, int32_t id, char *msg, ...) { - - char pbuf[QL_DBG_BUF_LEN]; - va_list ap; - uint32_t len; +ql_dbg_pci(uint32_t level, struct pci_dev *pdev, int32_t id, + const char *fmt, ...) +{ + va_list va; + struct va_format vaf; if (pdev == NULL) return; + if (!ql_mask_match(level)) + return; - memset(pbuf, 0, QL_DBG_BUF_LEN); - - va_start(ap, msg); - - if ((level & ql2xextended_error_logging) == level) { - /* <module-name> <dev-name>:<msg-id> Message */ - sprintf(pbuf, "%s [%s]-%04x: : ", QL_MSGHDR, - dev_name(&(pdev->dev)), id + ql_dbg_offset); + va_start(va, fmt); - len = strlen(pbuf); - vsprintf(pbuf+len, msg, ap); - pr_warning("%s", pbuf); - } + vaf.fmt = fmt; + vaf.va = &va; - va_end(ap); + /* <module-name> <dev-name>:<msg-id> Message */ + pr_warn("%s [%s]-%04x: : %pV", + QL_MSGHDR, dev_name(&(pdev->dev)), id + ql_dbg_offset, &vaf); + va_end(va); } /* @@ -1751,47 +1756,47 @@ ql_dbg_pci(uint32_t level, struct pci_dev *pdev, int32_t id, char *msg, ...) { * msg: The message to be displayed. */ void -ql_log(uint32_t level, scsi_qla_host_t *vha, int32_t id, char *msg, ...) { - - char pbuf[QL_DBG_BUF_LEN]; - va_list ap; - uint32_t len; - struct pci_dev *pdev = NULL; - - memset(pbuf, 0, QL_DBG_BUF_LEN); - - va_start(ap, msg); - - if (level <= ql_errlev) { - if (vha != NULL) { - pdev = vha->hw->pdev; - /* <module-name> <msg-id>:<host> Message */ - sprintf(pbuf, "%s [%s]-%04x:%ld: ", QL_MSGHDR, - dev_name(&(pdev->dev)), id, vha->host_no); - } else - sprintf(pbuf, "%s [%s]-%04x: : ", QL_MSGHDR, - "0000:00:00.0", id); +ql_log(uint32_t level, scsi_qla_host_t *vha, int32_t id, const char *fmt, ...) +{ + va_list va; + struct va_format vaf; + char pbuf[128]; - len = strlen(pbuf); - vsprintf(pbuf+len, msg, ap); + if (level > ql_errlev) + return; - switch (level) { - case 0: /* FATAL LOG */ - pr_crit("%s", pbuf); - break; - case 1: - pr_err("%s", pbuf); - break; - case 2: - pr_warn("%s", pbuf); - break; - default: - pr_info("%s", pbuf); - break; - } + if (vha != NULL) { + const struct pci_dev *pdev = vha->hw->pdev; + /* <module-name> <msg-id>:<host> Message */ + snprintf(pbuf, sizeof(pbuf), "%s [%s]-%04x:%ld: ", + QL_MSGHDR, dev_name(&(pdev->dev)), id, vha->host_no); + } else { + snprintf(pbuf, sizeof(pbuf), "%s [%s]-%04x: : ", + QL_MSGHDR, "0000:00:00.0", id); + } + pbuf[sizeof(pbuf) - 1] = 0; + + va_start(va, fmt); + + vaf.fmt = fmt; + vaf.va = &va; + + switch (level) { + case 0: /* FATAL LOG */ + pr_crit("%s%pV", pbuf, &vaf); + break; + case 1: + pr_err("%s%pV", pbuf, &vaf); + break; + case 2: + pr_warn("%s%pV", pbuf, &vaf); + break; + default: + pr_info("%s%pV", pbuf, &vaf); + break; } - va_end(ap); + va_end(va); } /* @@ -1809,43 +1814,44 @@ ql_log(uint32_t level, scsi_qla_host_t *vha, int32_t id, char *msg, ...) { * msg: The message to be displayed. */ void -ql_log_pci(uint32_t level, struct pci_dev *pdev, int32_t id, char *msg, ...) { - - char pbuf[QL_DBG_BUF_LEN]; - va_list ap; - uint32_t len; +ql_log_pci(uint32_t level, struct pci_dev *pdev, int32_t id, + const char *fmt, ...) +{ + va_list va; + struct va_format vaf; + char pbuf[128]; if (pdev == NULL) return; + if (level > ql_errlev) + return; - memset(pbuf, 0, QL_DBG_BUF_LEN); - - va_start(ap, msg); - - if (level <= ql_errlev) { - /* <module-name> <dev-name>:<msg-id> Message */ - sprintf(pbuf, "%s [%s]-%04x: : ", QL_MSGHDR, - dev_name(&(pdev->dev)), id); - - len = strlen(pbuf); - vsprintf(pbuf+len, msg, ap); - switch (level) { - case 0: /* FATAL LOG */ - pr_crit("%s", pbuf); - break; - case 1: - pr_err("%s", pbuf); - break; - case 2: - pr_warn("%s", pbuf); - break; - default: - pr_info("%s", pbuf); - break; - } + /* <module-name> <dev-name>:<msg-id> Message */ + snprintf(pbuf, sizeof(pbuf), "%s [%s]-%04x: : ", + QL_MSGHDR, dev_name(&(pdev->dev)), id); + pbuf[sizeof(pbuf) - 1] = 0; + + va_start(va, fmt); + + vaf.fmt = fmt; + vaf.va = &va; + + switch (level) { + case 0: /* FATAL LOG */ + pr_crit("%s%pV", pbuf, &vaf); + break; + case 1: + pr_err("%s%pV", pbuf, &vaf); + break; + case 2: + pr_warn("%s%pV", pbuf, &vaf); + break; + default: + pr_info("%s%pV", pbuf, &vaf); + break; } - va_end(ap); + va_end(va); } void @@ -1858,20 +1864,20 @@ ql_dump_regs(uint32_t level, scsi_qla_host_t *vha, int32_t id) struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82; uint16_t __iomem *mbx_reg; - if ((level & ql2xextended_error_logging) == level) { - - if (IS_QLA82XX(ha)) - mbx_reg = ®82->mailbox_in[0]; - else if (IS_FWI2_CAPABLE(ha)) - mbx_reg = ®24->mailbox0; - else - mbx_reg = MAILBOX_REG(ha, reg, 0); + if (!ql_mask_match(level)) + return; - ql_dbg(level, vha, id, "Mailbox registers:\n"); - for (i = 0; i < 6; i++) - ql_dbg(level, vha, id, - "mbox[%d] 0x%04x\n", i, RD_REG_WORD(mbx_reg++)); - } + if (IS_QLA82XX(ha)) + mbx_reg = ®82->mailbox_in[0]; + else if (IS_FWI2_CAPABLE(ha)) + mbx_reg = ®24->mailbox0; + else + mbx_reg = MAILBOX_REG(ha, reg, 0); + + ql_dbg(level, vha, id, "Mailbox registers:\n"); + for (i = 0; i < 6; i++) + ql_dbg(level, vha, id, + "mbox[%d] 0x%04x\n", i, RD_REG_WORD(mbx_reg++)); } @@ -1881,24 +1887,25 @@ ql_dump_buffer(uint32_t level, scsi_qla_host_t *vha, int32_t id, { uint32_t cnt; uint8_t c; - if ((level & ql2xextended_error_logging) == level) { - - ql_dbg(level, vha, id, " 0 1 2 3 4 5 6 7 8 " - "9 Ah Bh Ch Dh Eh Fh\n"); - ql_dbg(level, vha, id, "----------------------------------" - "----------------------------\n"); - - ql_dbg(level, vha, id, ""); - for (cnt = 0; cnt < size;) { - c = *b++; - printk("%02x", (uint32_t) c); - cnt++; - if (!(cnt % 16)) - printk("\n"); - else - printk(" "); - } - if (cnt % 16) - ql_dbg(level, vha, id, "\n"); + + if (!ql_mask_match(level)) + return; + + ql_dbg(level, vha, id, " 0 1 2 3 4 5 6 7 8 " + "9 Ah Bh Ch Dh Eh Fh\n"); + ql_dbg(level, vha, id, "----------------------------------" + "----------------------------\n"); + + ql_dbg(level, vha, id, " "); + for (cnt = 0; cnt < size;) { + c = *b++; + printk("%02x", (uint32_t) c); + cnt++; + if (!(cnt % 16)) + printk("\n"); + else + printk(" "); } + if (cnt % 16) + ql_dbg(level, vha, id, "\n"); } diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index 98a377b9901..5f1b6d9c3dc 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -232,6 +232,7 @@ struct qla2xxx_fw_dump { }; #define QL_MSGHDR "qla2xxx" +#define QL_DBG_DEFAULT1_MASK 0x1e400000 #define ql_log_fatal 0 /* display fatal errors */ #define ql_log_warn 1 /* display critical errors */ @@ -244,15 +245,15 @@ struct qla2xxx_fw_dump { extern int ql_errlev; -void -ql_dbg(uint32_t, scsi_qla_host_t *vha, int32_t, char *, ...); -void -ql_dbg_pci(uint32_t, struct pci_dev *pdev, int32_t, char *, ...); +void __attribute__((format (printf, 4, 5))) +ql_dbg(uint32_t, scsi_qla_host_t *vha, int32_t, const char *fmt, ...); +void __attribute__((format (printf, 4, 5))) +ql_dbg_pci(uint32_t, struct pci_dev *pdev, int32_t, const char *fmt, ...); -void -ql_log(uint32_t, scsi_qla_host_t *vha, int32_t, char *, ...); -void -ql_log_pci(uint32_t, struct pci_dev *pdev, int32_t, char *, ...); +void __attribute__((format (printf, 4, 5))) +ql_log(uint32_t, scsi_qla_host_t *vha, int32_t, const char *fmt, ...); +void __attribute__((format (printf, 4, 5))) +ql_log_pci(uint32_t, struct pci_dev *pdev, int32_t, const char *fmt, ...); /* Debug Levels */ /* The 0x40000000 is the max value any debug level can have @@ -275,5 +276,3 @@ ql_log_pci(uint32_t, struct pci_dev *pdev, int32_t, char *, ...); #define ql_dbg_misc 0x00010000 /* For dumping everything that is not * not covered by upper categories */ - -#define QL_DBG_BUF_LEN 512 diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index fcf052c50bf..af1003f9de1 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -44,6 +44,7 @@ * ISP2100 HBAs. */ #define MAILBOX_REGISTER_COUNT_2100 8 +#define MAILBOX_REGISTER_COUNT_2200 24 #define MAILBOX_REGISTER_COUNT 32 #define QLA2200A_RISC_ROM_VER 4 @@ -271,6 +272,7 @@ struct srb_iocb { struct srb_ctx { uint16_t type; char *name; + int iocbs; union { struct srb_iocb *iocb_cmd; struct fc_bsg_job *bsg_job; @@ -2244,6 +2246,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 *); + int (*iospace_config)(struct qla_hw_data*); }; /* MSI-X Support *************************************************************/ @@ -2978,10 +2981,6 @@ typedef struct scsi_qla_host { atomic_dec(&__vha->vref_count); \ } while (0) - -#define qla_printk(level, ha, format, arg...) \ - dev_printk(level , &((ha)->pdev->dev) , format , ## arg) - /* * qla2x00 local function return status codes */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index ce32d8135c9..408679be8fd 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -572,12 +572,13 @@ 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 void qla82xx_start_iocbs(scsi_qla_host_t *); extern int qla82xx_fcoe_ctx_reset(scsi_qla_host_t *); extern int qla82xx_check_md_needed(scsi_qla_host_t *); extern void qla82xx_chip_reset_cleanup(scsi_qla_host_t *); extern int qla82xx_mbx_beacon_ctl(scsi_qla_host_t *, int); extern char *qdev_state(uint32_t); +extern void qla82xx_clear_pending_mbx(scsi_qla_host_t *); /* BSG related functions */ extern int qla24xx_bsg_request(struct fc_bsg_job *); diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 37937aa3c3b..4aea4ae2330 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -758,7 +758,7 @@ qla2x00_sns_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport) "GA_NXT Send SNS failed (%d).\n", rval); } else if (sns_cmd->p.gan_data[8] != 0x80 || sns_cmd->p.gan_data[9] != 0x02) { - ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x207d, + ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2084, "GA_NXT failed, rejected request ga_nxt_rsp:\n"); ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2074, sns_cmd->p.gan_data, 16); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index f03e915f187..1fa067e053d 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -111,6 +111,7 @@ qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size, memset(sp, 0, sizeof(*sp)); sp->fcport = fcport; sp->ctx = ctx; + ctx->iocbs = 1; ctx->u.iocb_cmd = iocb; iocb->free = qla2x00_ctx_sp_free; @@ -154,8 +155,8 @@ qla2x00_async_iocb_timeout(srb_t *sp) struct srb_ctx *ctx = sp->ctx; ql_dbg(ql_dbg_disc, fcport->vha, 0x2071, - "Async-%s timeout - portid=%02x%02x%02x.\n", - ctx->name, fcport->d_id.b.domain, fcport->d_id.b.area, + "Async-%s timeout - hdl=%x portid=%02x%02x%02x.\n", + ctx->name, sp->handle, fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa); fcport->flags &= ~FCF_ASYNC_SENT; @@ -211,9 +212,10 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, goto done_free_sp; ql_dbg(ql_dbg_disc, vha, 0x2072, - "Async-login - loopid=%x portid=%02x%02x%02x retries=%d.\n", - fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa, fcport->login_retry); + "Async-login - hdl=%x, loopid=%x portid=%02x%02x%02x " + "retries=%d.\n", sp->handle, fcport->loop_id, + fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, + fcport->login_retry); return rval; done_free_sp: @@ -258,9 +260,9 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport) goto done_free_sp; ql_dbg(ql_dbg_disc, vha, 0x2070, - "Async-logout - loop-id=%x portid=%02x%02x%02x.\n", - fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa); + "Async-logout - hdl=%x loop-id=%x portid=%02x%02x%02x.\n", + sp->handle, fcport->loop_id, fcport->d_id.b.domain, + fcport->d_id.b.area, fcport->d_id.b.al_pa); return rval; done_free_sp: @@ -308,9 +310,9 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport, goto done_free_sp; ql_dbg(ql_dbg_disc, vha, 0x206f, - "Async-adisc - loopid=%x portid=%02x%02x%02x.\n", - fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa); + "Async-adisc - hdl=%x loopid=%x portid=%02x%02x%02x.\n", + sp->handle, fcport->loop_id, fcport->d_id.b.domain, + fcport->d_id.b.area, fcport->d_id.b.al_pa); return rval; done_free_sp: @@ -360,9 +362,9 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun, goto done_free_sp; ql_dbg(ql_dbg_taskm, vha, 0x802f, - "Async-tmf loop-id=%x portid=%02x%02x%02x.\n", - fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa); + "Async-tmf hdl=%x loop-id=%x portid=%02x%02x%02x.\n", + sp->handle, fcport->loop_id, fcport->d_id.b.domain, + fcport->d_id.b.area, fcport->d_id.b.al_pa); return rval; done_free_sp: @@ -514,7 +516,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) set_bit(0, ha->req_qid_map); set_bit(0, ha->rsp_qid_map); - ql_log(ql_log_info, vha, 0x0040, + ql_dbg(ql_dbg_init, vha, 0x0040, "Configuring PCI space...\n"); rval = ha->isp_ops->pci_config(vha); if (rval) { @@ -533,7 +535,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) } ha->isp_ops->get_flash_version(vha, req->ring); - ql_log(ql_log_info, vha, 0x0061, + ql_dbg(ql_dbg_init, vha, 0x0061, "Configure NVRAM parameters...\n"); ha->isp_ops->nvram_config(vha); @@ -550,7 +552,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) return QLA_FUNCTION_FAILED; } - ql_log(ql_log_info, vha, 0x0078, + ql_dbg(ql_dbg_init, vha, 0x0078, "Verifying loaded RISC code...\n"); if (qla2x00_isp_firmware(vha) != QLA_SUCCESS) { @@ -1294,7 +1296,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) ha->flags.fce_enabled = 0; goto try_eft; } - ql_log(ql_log_info, vha, 0x00c0, + ql_dbg(ql_dbg_init, vha, 0x00c0, "Allocate (%d KB) for FCE...\n", FCE_SIZE / 1024); fce_size = sizeof(struct qla2xxx_fce_chain) + FCE_SIZE; @@ -1321,7 +1323,7 @@ try_eft: tc_dma); goto cont_alloc; } - ql_log(ql_log_info, vha, 0x00c3, + ql_dbg(ql_dbg_init, vha, 0x00c3, "Allocated (%d KB) EFT ...\n", EFT_SIZE / 1024); eft_size = EFT_SIZE; @@ -1358,7 +1360,7 @@ cont_alloc: } return; } - ql_log(ql_log_info, vha, 0x00c5, + ql_dbg(ql_dbg_init, vha, 0x00c5, "Allocated (%d KB) for firmware dump.\n", dump_size / 1024); ha->fw_dump_len = dump_size; @@ -1509,7 +1511,8 @@ enable_82xx_npiv: &ha->fw_xcb_count, NULL, NULL, &ha->max_npiv_vports, NULL); - if (!fw_major_version && ql2xallocfwdump) + if (!fw_major_version && ql2xallocfwdump + && !IS_QLA82XX(ha)) qla2x00_alloc_fw_dump(vha); } } else { @@ -1928,7 +1931,7 @@ qla2x00_fw_ready(scsi_qla_host_t *vha) rval = qla84xx_init_chip(vha); if (rval != QLA_SUCCESS) { ql_log(ql_log_warn, - vha, 0x8026, + vha, 0x8007, "Init chip failed.\n"); break; } @@ -1937,7 +1940,7 @@ qla2x00_fw_ready(scsi_qla_host_t *vha) cs84xx_time = jiffies - cs84xx_time; wtime += cs84xx_time; mtime += cs84xx_time; - ql_dbg(ql_dbg_taskm, vha, 0x8025, + ql_dbg(ql_dbg_taskm, vha, 0x8008, "Increasing wait time by %ld. " "New time %ld.\n", cs84xx_time, wtime); @@ -1980,16 +1983,13 @@ qla2x00_fw_ready(scsi_qla_host_t *vha) /* Delay for a while */ msleep(500); - - ql_dbg(ql_dbg_taskm, vha, 0x8039, - "fw_state=%x curr time=%lx.\n", state[0], jiffies); } while (1); ql_dbg(ql_dbg_taskm, vha, 0x803a, "fw_state=%x (%x, %x, %x, %x) " "curr time=%lx.\n", state[0], state[1], state[2], state[3], state[4], jiffies); - if (rval) { + if (rval && !(vha->device_flags & DFLG_NO_CABLE)) { ql_log(ql_log_warn, vha, 0x803b, "Firmware ready **** FAILED ****.\n"); } @@ -2385,7 +2385,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha) * internal driver logging. */ if (nv->host_p[0] & BIT_7) - ql2xextended_error_logging = 0x7fffffff; + ql2xextended_error_logging = QL_DBG_DEFAULT1_MASK; ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0); /* Always load RISC code on non ISP2[12]00 chips. */ if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) @@ -4187,7 +4187,8 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) spin_unlock_irqrestore(&ha->vport_slock, flags); } else { - ql_log(ql_log_warn, vha, 0x8023, "%s **** FAILED ****.\n"); + ql_log(ql_log_warn, vha, 0x8023, "%s **** FAILED ****.\n", + __func__); } return(status); @@ -4637,7 +4638,7 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr, struct req_que *req = ha->req_q_map[0]; ql_dbg(ql_dbg_init, vha, 0x008b, - "Loading firmware from flash (%x).\n", faddr); + "FW: Loading firmware from flash (%x).\n", faddr); rval = QLA_SUCCESS; @@ -4835,8 +4836,8 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr) return QLA_FUNCTION_FAILED; } - ql_log(ql_log_info, vha, 0x0092, - "Loading via request-firmware.\n"); + ql_dbg(ql_dbg_init, vha, 0x0092, + "FW: Loading via request-firmware.\n"); rval = QLA_SUCCESS; @@ -5424,7 +5425,7 @@ qla82xx_restart_isp(scsi_qla_host_t *vha) if ((vha->device_flags & DFLG_NO_CABLE)) status = 0; - ql_log(ql_log_info, vha, 0x803d, + ql_log(ql_log_info, vha, 0x8000, "Configure loop done, status = 0x%x.\n", status); } @@ -5457,7 +5458,7 @@ qla82xx_restart_isp(scsi_qla_host_t *vha) ha->fce_dma, ha->fce_bufs, ha->fce_mb, &ha->fce_bufs); if (rval) { - ql_log(ql_log_warn, vha, 0x803e, + ql_log(ql_log_warn, vha, 0x8001, "Unable to reinitialize FCE (%d).\n", rval); ha->flags.fce_enabled = 0; @@ -5469,7 +5470,7 @@ qla82xx_restart_isp(scsi_qla_host_t *vha) rval = qla2x00_enable_eft_trace(vha, ha->eft_dma, EFT_NUM_BUFFERS); if (rval) { - ql_log(ql_log_warn, vha, 0x803f, + ql_log(ql_log_warn, vha, 0x8010, "Unable to reinitialize EFT (%d).\n", rval); } @@ -5477,7 +5478,7 @@ qla82xx_restart_isp(scsi_qla_host_t *vha) } if (!status) { - ql_dbg(ql_dbg_taskm, vha, 0x8040, + ql_dbg(ql_dbg_taskm, vha, 0x8011, "qla82xx_restart_isp succeeded.\n"); spin_lock_irqsave(&ha->vport_slock, flags); @@ -5495,7 +5496,7 @@ qla82xx_restart_isp(scsi_qla_host_t *vha) spin_unlock_irqrestore(&ha->vport_slock, flags); } else { - ql_log(ql_log_warn, vha, 0x8041, + ql_log(ql_log_warn, vha, 0x8016, "qla82xx_restart_isp **** FAILED ****.\n"); } @@ -5642,13 +5643,26 @@ qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport) if (priority < 0) return QLA_FUNCTION_FAILED; + if (IS_QLA82XX(vha->hw)) { + fcport->fcp_prio = priority & 0xf; + return QLA_SUCCESS; + } + ret = qla24xx_set_fcp_prio(vha, fcport->loop_id, priority, mb); - if (ret == QLA_SUCCESS) - fcport->fcp_prio = priority; - else + if (ret == QLA_SUCCESS) { + if (fcport->fcp_prio != priority) + ql_dbg(ql_dbg_user, vha, 0x709e, + "Updated FCP_CMND priority - value=%d loop_id=%d " + "port_id=%02x%02x%02x.\n", priority, + fcport->loop_id, fcport->d_id.b.domain, + fcport->d_id.b.area, fcport->d_id.b.al_pa); + fcport->fcp_prio = priority & 0xf; + } else ql_dbg(ql_dbg_user, vha, 0x704f, - "Unable to activate fcp priority, ret=0x%x.\n", ret); - + "Unable to update FCP_CMND priority - ret=0x%x for " + "loop_id=%d port_id=%02x%02x%02x.\n", ret, fcport->loop_id, + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa); return ret; } diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 9902834e0b7..7cc4f36cd53 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -131,3 +131,16 @@ qla2x00_hba_err_chk_enabled(srb_t *sp) } return 0; } + +static inline int +qla2x00_reset_active(scsi_qla_host_t *vha) +{ + scsi_qla_host_t *base_vha = pci_get_drvdata(vha->hw->pdev); + + /* Test appropriate base-vha and vha flags. */ + return test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags) || + test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) || + test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) || + test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || + test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags); +} diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index dbec89622a0..55a96761b5a 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -11,8 +11,6 @@ #include <scsi/scsi_tcq.h> -static void qla2x00_isp_cmd(struct scsi_qla_host *, struct req_que *); - static void qla25xx_set_que(srb_t *, struct rsp_que **); /** * qla2x00_get_cmd_direction() - Determine control_flag data direction. @@ -120,11 +118,10 @@ qla2x00_prep_cont_type0_iocb(struct scsi_qla_host *vha) * Returns a pointer to the continuation type 1 IOCB packet. */ static inline cont_a64_entry_t * -qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha) +qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha, struct req_que *req) { cont_a64_entry_t *cont_pkt; - struct req_que *req = vha->req; /* Adjust ring index. */ req->ring_index++; if (req->ring_index == req->length) { @@ -292,7 +289,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, * Five DSDs are available in the Continuation * Type 1 IOCB. */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha); + cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req); cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; avail_dsds = 5; } @@ -469,6 +466,42 @@ queuing_error: } /** + * qla2x00_start_iocbs() - Execute the IOCB command + */ +static void +qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req) +{ + struct qla_hw_data *ha = vha->hw; + device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id); + struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp; + + if (IS_QLA82XX(ha)) { + qla82xx_start_iocbs(vha); + } else { + /* 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); + } else { + WRT_REG_WORD(ISP_REQ_Q_IN(ha, ®->isp), + req->ring_index); + RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, ®->isp)); + } + } +} + +/** * qla2x00_marker() - Send a marker IOCB to the firmware. * @ha: HA context * @loop_id: loop ID @@ -490,6 +523,7 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req, scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); mrk24 = NULL; + req = ha->req_q_map[0]; mrk = (mrk_entry_t *)qla2x00_alloc_iocbs(vha, 0); if (mrk == NULL) { ql_log(ql_log_warn, base_vha, 0x3026, @@ -516,7 +550,7 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req, } wmb(); - qla2x00_isp_cmd(vha, req); + qla2x00_start_iocbs(vha, req); return (QLA_SUCCESS); } @@ -537,89 +571,140 @@ qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req, } /** - * qla2x00_isp_cmd() - Modify the request ring pointer. - * @ha: HA context + * qla24xx_calc_iocbs() - Determine number of Command Type 3 and + * Continuation Type 1 IOCBs to allocate. + * + * @dsds: number of data segment decriptors needed * - * Note: The caller must hold the hardware lock before calling this routine. + * Returns the number of IOCB entries needed to store @dsds. */ -static void -qla2x00_isp_cmd(struct scsi_qla_host *vha, struct req_que *req) +inline uint16_t +qla24xx_calc_iocbs(scsi_qla_host_t *vha, uint16_t dsds) { - struct qla_hw_data *ha = vha->hw; - device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id); - struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp; + uint16_t iocbs; - ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x302d, - "IOCB data:\n"); - ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302e, - (uint8_t *)req->ring_ptr, REQUEST_ENTRY_SIZE); + iocbs = 1; + if (dsds > 1) { + iocbs += (dsds - 1) / 5; + if ((dsds - 1) % 5) + iocbs++; + } + return iocbs; +} - /* 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++; +static inline int +qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, + uint16_t tot_dsds) +{ + uint32_t *cur_dsd = NULL; + scsi_qla_host_t *vha; + struct qla_hw_data *ha; + struct scsi_cmnd *cmd; + struct scatterlist *cur_seg; + uint32_t *dsd_seg; + void *next_dsd; + uint8_t avail_dsds; + uint8_t first_iocb = 1; + uint32_t dsd_list_len; + struct dsd_dma *dsd_ptr; + struct ct6_dsd *ctx; - /* Set chip new ring index. */ - if (IS_QLA82XX(ha)) { - uint32_t dbval = 0x04 | (ha->portnum << 5); + cmd = sp->cmd; - /* 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 { - if (IS_FWI2_CAPABLE(ha)) { - WRT_REG_DWORD(®->isp24.req_q_in, req->ring_index); - RD_REG_DWORD_RELAXED(®->isp24.req_q_in); + /* Update entry type to indicate Command Type 3 IOCB */ + *((uint32_t *)(&cmd_pkt->entry_type)) = + __constant_cpu_to_le32(COMMAND_TYPE_6); + + /* No data transfer */ + if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { + cmd_pkt->byte_count = __constant_cpu_to_le32(0); + return 0; + } + + vha = sp->fcport->vha; + ha = vha->hw; + + /* Set transfer direction */ + if (cmd->sc_data_direction == DMA_TO_DEVICE) { + cmd_pkt->control_flags = + __constant_cpu_to_le16(CF_WRITE_DATA); + ha->qla_stats.output_bytes += scsi_bufflen(cmd); + } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { + cmd_pkt->control_flags = + __constant_cpu_to_le16(CF_READ_DATA); + ha->qla_stats.input_bytes += scsi_bufflen(cmd); + } + + cur_seg = scsi_sglist(cmd); + ctx = sp->ctx; + + while (tot_dsds) { + avail_dsds = (tot_dsds > QLA_DSDS_PER_IOCB) ? + QLA_DSDS_PER_IOCB : tot_dsds; + tot_dsds -= avail_dsds; + dsd_list_len = (avail_dsds + 1) * QLA_DSD_SIZE; + + dsd_ptr = list_first_entry(&ha->gbl_dsd_list, + struct dsd_dma, list); + next_dsd = dsd_ptr->dsd_addr; + list_del(&dsd_ptr->list); + ha->gbl_dsd_avail--; + list_add_tail(&dsd_ptr->list, &ctx->dsd_list); + ctx->dsd_use_cnt++; + ha->gbl_dsd_inuse++; + + if (first_iocb) { + first_iocb = 0; + dsd_seg = (uint32_t *)&cmd_pkt->fcp_data_dseg_address; + *dsd_seg++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); + *dsd_seg++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); + cmd_pkt->fcp_data_dseg_len = cpu_to_le32(dsd_list_len); } else { - WRT_REG_WORD(ISP_REQ_Q_IN(ha, ®->isp), - req->ring_index); - RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, ®->isp)); + *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); + *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); + *cur_dsd++ = cpu_to_le32(dsd_list_len); + } + cur_dsd = (uint32_t *)next_dsd; + while (avail_dsds) { + dma_addr_t sle_dma; + + sle_dma = sg_dma_address(cur_seg); + *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg)); + cur_seg = sg_next(cur_seg); + avail_dsds--; } } + /* Null termination */ + *cur_dsd++ = 0; + *cur_dsd++ = 0; + *cur_dsd++ = 0; + cmd_pkt->control_flags |= CF_DATA_SEG_DESCR_ENABLE; + return 0; } -/** - * qla24xx_calc_iocbs() - Determine number of Command Type 3 and - * Continuation Type 1 IOCBs to allocate. +/* + * qla24xx_calc_dsd_lists() - Determine number of DSD list required + * for Command Type 6. * * @dsds: number of data segment decriptors needed * - * Returns the number of IOCB entries needed to store @dsds. + * Returns the number of dsd list needed to store @dsds. */ inline uint16_t -qla24xx_calc_iocbs(scsi_qla_host_t *vha, uint16_t dsds) +qla24xx_calc_dsd_lists(uint16_t dsds) { - uint16_t iocbs; + uint16_t dsd_lists = 0; - iocbs = 1; - if (dsds > 1) { - iocbs += (dsds - 1) / 5; - if ((dsds - 1) % 5) - iocbs++; - } - return iocbs; + dsd_lists = (dsds/QLA_DSDS_PER_IOCB); + if (dsds % QLA_DSDS_PER_IOCB) + dsd_lists++; + return dsd_lists; } + /** * qla24xx_build_scsi_iocbs() - Build IOCB command utilizing Command Type 7 * IOCB types. @@ -684,7 +769,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, * Five DSDs are available in the Continuation * Type 1 IOCB. */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha); + cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req); cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; avail_dsds = 5; } @@ -946,6 +1031,7 @@ alloc_and_fill: *cur_dsd++ = 0; return 0; } + static int qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd, uint16_t tot_dsds) @@ -1005,7 +1091,7 @@ qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd, sle_dma = sg_dma_address(sg); ql_dbg(ql_dbg_io, vha, 0x300a, "sg entry %d - addr=0x%x 0x%x, " "len=%d for cmd=%p.\n", - cur_dsd, i, LSD(sle_dma), MSD(sle_dma), sg_dma_len(sg), + i, LSD(sle_dma), MSD(sle_dma), sg_dma_len(sg), sp->cmd); *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); @@ -1732,6 +1818,7 @@ qla2x00_alloc_iocbs(scsi_qla_host_t *vha, srb_t *sp) uint32_t index, handle; request_t *pkt; uint16_t cnt, req_cnt; + struct srb_ctx *ctx; pkt = NULL; req_cnt = 1; @@ -1760,6 +1847,12 @@ qla2x00_alloc_iocbs(scsi_qla_host_t *vha, srb_t *sp) req->outstanding_cmds[handle] = sp; sp->handle = handle; + /* Adjust entry-counts as needed. */ + if (sp->ctx) { + ctx = sp->ctx; + req_cnt = ctx->iocbs; + } + skip_cmd_array: /* Check for room on request queue. */ if (req->cnt < req_cnt) { @@ -1794,42 +1887,6 @@ queuing_error: } static void -qla2x00_start_iocbs(srb_t *sp) -{ - struct qla_hw_data *ha = sp->fcport->vha->hw; - struct req_que *req = ha->req_q_map[0]; - device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id); - struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp; - - if (IS_QLA82XX(ha)) { - qla82xx_start_iocbs(sp); - } else { - /* 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)); - } - } -} - -static void qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio) { struct srb_ctx *ctx = sp->ctx; @@ -2070,7 +2127,8 @@ qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb) * Five DSDs are available in the Cont. * Type 1 IOCB. */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha); + cont_pkt = qla2x00_prep_cont_type1_iocb(vha, + vha->hw->req_q_map[0]); cur_dsd = (uint32_t *) cont_pkt->dseg_0_address; avail_dsds = 5; cont_iocb_prsnt = 1; @@ -2096,6 +2154,7 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) int index; uint16_t tot_dsds; scsi_qla_host_t *vha = sp->fcport->vha; + struct qla_hw_data *ha = vha->hw; struct fc_bsg_job *bsg_job = ((struct srb_ctx *)sp->ctx)->u.bsg_job; int loop_iterartion = 0; int cont_iocb_prsnt = 0; @@ -2141,7 +2200,8 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) * Five DSDs are available in the Cont. * Type 1 IOCB. */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha); + 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; cont_iocb_prsnt = 1; @@ -2158,6 +2218,381 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) ct_iocb->entry_count = entry_count; } +/* + * qla82xx_start_scsi() - Send a SCSI command to the ISP + * @sp: command to send to the ISP + * + * Returns non-zero if a failure occurred, else zero. + */ +int +qla82xx_start_scsi(srb_t *sp) +{ + int ret, nseg; + unsigned long flags; + struct scsi_cmnd *cmd; + uint32_t *clr_ptr; + uint32_t index; + uint32_t handle; + uint16_t cnt; + uint16_t req_cnt; + uint16_t tot_dsds; + struct device_reg_82xx __iomem *reg; + uint32_t dbval; + uint32_t *fcp_dl; + uint8_t additional_cdb_len; + struct ct6_dsd *ctx; + struct scsi_qla_host *vha = sp->fcport->vha; + struct qla_hw_data *ha = vha->hw; + struct req_que *req = NULL; + struct rsp_que *rsp = NULL; + char tag[2]; + + /* Setup device pointers. */ + ret = 0; + reg = &ha->iobase->isp82; + cmd = sp->cmd; + req = vha->req; + rsp = ha->rsp_q_map[0]; + + /* So we know we haven't pci_map'ed anything yet */ + tot_dsds = 0; + + dbval = 0x04 | (ha->portnum << 5); + + /* Send marker if required */ + if (vha->marker_needed != 0) { + if (qla2x00_marker(vha, req, + rsp, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x300c, + "qla2x00_marker failed for cmd=%p.\n", cmd); + return QLA_FUNCTION_FAILED; + } + vha->marker_needed = 0; + } + + /* Acquire ring specific lock */ + spin_lock_irqsave(&ha->hardware_lock, flags); + + /* Check for room in outstanding command list. */ + handle = req->current_outstanding_cmd; + for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { + handle++; + if (handle == MAX_OUTSTANDING_COMMANDS) + handle = 1; + if (!req->outstanding_cmds[handle]) + break; + } + if (index == MAX_OUTSTANDING_COMMANDS) + goto queuing_error; + + /* Map the sg table so we have an accurate count of sg entries needed */ + if (scsi_sg_count(cmd)) { + nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), + scsi_sg_count(cmd), cmd->sc_data_direction); + if (unlikely(!nseg)) + goto queuing_error; + } else + nseg = 0; + + tot_dsds = nseg; + + if (tot_dsds > ql2xshiftctondsd) { + struct cmd_type_6 *cmd_pkt; + uint16_t more_dsd_lists = 0; + struct dsd_dma *dsd_ptr; + uint16_t i; + + more_dsd_lists = qla24xx_calc_dsd_lists(tot_dsds); + if ((more_dsd_lists + ha->gbl_dsd_inuse) >= NUM_DSD_CHAIN) { + ql_dbg(ql_dbg_io, vha, 0x300d, + "Num of DSD list %d is than %d for cmd=%p.\n", + more_dsd_lists + ha->gbl_dsd_inuse, NUM_DSD_CHAIN, + cmd); + goto queuing_error; + } + + if (more_dsd_lists <= ha->gbl_dsd_avail) + goto sufficient_dsds; + else + more_dsd_lists -= ha->gbl_dsd_avail; + + for (i = 0; i < more_dsd_lists; i++) { + dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); + if (!dsd_ptr) { + ql_log(ql_log_fatal, vha, 0x300e, + "Failed to allocate memory for dsd_dma " + "for cmd=%p.\n", cmd); + goto queuing_error; + } + + dsd_ptr->dsd_addr = dma_pool_alloc(ha->dl_dma_pool, + GFP_ATOMIC, &dsd_ptr->dsd_list_dma); + if (!dsd_ptr->dsd_addr) { + kfree(dsd_ptr); + ql_log(ql_log_fatal, vha, 0x300f, + "Failed to allocate memory for dsd_addr " + "for cmd=%p.\n", cmd); + goto queuing_error; + } + list_add_tail(&dsd_ptr->list, &ha->gbl_dsd_list); + ha->gbl_dsd_avail++; + } + +sufficient_dsds: + req_cnt = 1; + + if (req->cnt < (req_cnt + 2)) { + cnt = (uint16_t)RD_REG_DWORD_RELAXED( + ®->req_q_out[0]); + if (req->ring_index < cnt) + req->cnt = cnt - req->ring_index; + else + req->cnt = req->length - + (req->ring_index - cnt); + } + + if (req->cnt < (req_cnt + 2)) + goto queuing_error; + + ctx = sp->ctx = mempool_alloc(ha->ctx_mempool, GFP_ATOMIC); + if (!sp->ctx) { + ql_log(ql_log_fatal, vha, 0x3010, + "Failed to allocate ctx for cmd=%p.\n", cmd); + goto queuing_error; + } + memset(ctx, 0, sizeof(struct ct6_dsd)); + ctx->fcp_cmnd = dma_pool_alloc(ha->fcp_cmnd_dma_pool, + GFP_ATOMIC, &ctx->fcp_cmnd_dma); + if (!ctx->fcp_cmnd) { + ql_log(ql_log_fatal, vha, 0x3011, + "Failed to allocate fcp_cmnd for cmd=%p.\n", cmd); + goto queuing_error_fcp_cmnd; + } + + /* Initialize the DSD list and dma handle */ + INIT_LIST_HEAD(&ctx->dsd_list); + ctx->dsd_use_cnt = 0; + + if (cmd->cmd_len > 16) { + additional_cdb_len = cmd->cmd_len - 16; + if ((cmd->cmd_len % 4) != 0) { + /* SCSI command bigger than 16 bytes must be + * multiple of 4 + */ + ql_log(ql_log_warn, vha, 0x3012, + "scsi cmd len %d not multiple of 4 " + "for cmd=%p.\n", cmd->cmd_len, cmd); + goto queuing_error_fcp_cmnd; + } + ctx->fcp_cmnd_len = 12 + cmd->cmd_len + 4; + } else { + additional_cdb_len = 0; + ctx->fcp_cmnd_len = 12 + 16 + 4; + } + + cmd_pkt = (struct cmd_type_6 *)req->ring_ptr; + cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + + /* Zero out remaining portion of packet. */ + /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ + clr_ptr = (uint32_t *)cmd_pkt + 2; + memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); + cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); + + /* Set NPORT-ID and LUN number*/ + cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); + cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; + cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; + cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; + cmd_pkt->vp_index = sp->fcport->vp_idx; + + /* Build IOCB segments */ + if (qla24xx_build_scsi_type_6_iocbs(sp, cmd_pkt, tot_dsds)) + goto queuing_error_fcp_cmnd; + + int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun); + host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); + + /* build FCP_CMND IU */ + memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd)); + int_to_scsilun(sp->cmd->device->lun, &ctx->fcp_cmnd->lun); + ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len; + + if (cmd->sc_data_direction == DMA_TO_DEVICE) + ctx->fcp_cmnd->additional_cdb_len |= 1; + else if (cmd->sc_data_direction == DMA_FROM_DEVICE) + ctx->fcp_cmnd->additional_cdb_len |= 2; + + /* + * Update tagged queuing modifier -- default is TSK_SIMPLE (0). + */ + if (scsi_populate_tag_msg(cmd, tag)) { + switch (tag[0]) { + case HEAD_OF_QUEUE_TAG: + ctx->fcp_cmnd->task_attribute = + TSK_HEAD_OF_QUEUE; + break; + case ORDERED_QUEUE_TAG: + ctx->fcp_cmnd->task_attribute = + TSK_ORDERED; + break; + } + } + + /* Populate the FCP_PRIO. */ + if (ha->flags.fcp_prio_enabled) + ctx->fcp_cmnd->task_attribute |= + sp->fcport->fcp_prio << 3; + + memcpy(ctx->fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len); + + fcp_dl = (uint32_t *)(ctx->fcp_cmnd->cdb + 16 + + additional_cdb_len); + *fcp_dl = htonl((uint32_t)scsi_bufflen(cmd)); + + cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(ctx->fcp_cmnd_len); + cmd_pkt->fcp_cmnd_dseg_address[0] = + cpu_to_le32(LSD(ctx->fcp_cmnd_dma)); + cmd_pkt->fcp_cmnd_dseg_address[1] = + cpu_to_le32(MSD(ctx->fcp_cmnd_dma)); + + sp->flags |= SRB_FCP_CMND_DMA_VALID; + cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); + /* Set total data segment count. */ + cmd_pkt->entry_count = (uint8_t)req_cnt; + /* Specify response queue number where + * completion should happen + */ + cmd_pkt->entry_status = (uint8_t) rsp->id; + } else { + struct cmd_type_7 *cmd_pkt; + req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); + if (req->cnt < (req_cnt + 2)) { + cnt = (uint16_t)RD_REG_DWORD_RELAXED( + ®->req_q_out[0]); + if (req->ring_index < cnt) + req->cnt = cnt - req->ring_index; + else + req->cnt = req->length - + (req->ring_index - cnt); + } + if (req->cnt < (req_cnt + 2)) + goto queuing_error; + + cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; + cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + + /* Zero out remaining portion of packet. */ + /* tagged queuing modifier -- default is TSK_SIMPLE (0).*/ + clr_ptr = (uint32_t *)cmd_pkt + 2; + memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); + cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); + + /* Set NPORT-ID and LUN number*/ + cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); + cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; + cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; + cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; + cmd_pkt->vp_index = sp->fcport->vp_idx; + + int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun); + host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, + sizeof(cmd_pkt->lun)); + + /* + * Update tagged queuing modifier -- default is TSK_SIMPLE (0). + */ + if (scsi_populate_tag_msg(cmd, tag)) { + switch (tag[0]) { + case HEAD_OF_QUEUE_TAG: + cmd_pkt->task = TSK_HEAD_OF_QUEUE; + break; + case ORDERED_QUEUE_TAG: + cmd_pkt->task = TSK_ORDERED; + break; + } + } + + /* Populate the FCP_PRIO. */ + if (ha->flags.fcp_prio_enabled) + cmd_pkt->task |= sp->fcport->fcp_prio << 3; + + /* Load SCSI command packet. */ + memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len); + host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb)); + + cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); + + /* Build IOCB segments */ + qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds); + + /* Set total data segment count. */ + cmd_pkt->entry_count = (uint8_t)req_cnt; + /* Specify response queue number where + * completion should happen. + */ + cmd_pkt->entry_status = (uint8_t) rsp->id; + + } + /* Build command packet. */ + req->current_outstanding_cmd = handle; + req->outstanding_cmds[handle] = sp; + sp->handle = handle; + sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle; + req->cnt -= req_cnt; + wmb(); + + /* 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++; + + sp->flags |= SRB_DMA_VALID; + + /* Set chip new ring index. */ + /* 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(); + } + } + + /* 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); + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + return QLA_SUCCESS; + +queuing_error_fcp_cmnd: + dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd, ctx->fcp_cmnd_dma); +queuing_error: + if (tot_dsds) + scsi_dma_unmap(cmd); + + if (sp->ctx) { + mempool_free(sp->ctx, ha->ctx_mempool); + sp->ctx = NULL; + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return QLA_FUNCTION_FAILED; +} + int qla2x00_start_sp(srb_t *sp) { @@ -2194,8 +2629,8 @@ qla2x00_start_sp(srb_t *sp) break; case SRB_CT_CMD: IS_FWI2_CAPABLE(ha) ? - qla24xx_ct_iocb(sp, pkt) : - qla2x00_ct_iocb(sp, pkt); + qla24xx_ct_iocb(sp, pkt) : + qla2x00_ct_iocb(sp, pkt); break; case SRB_ADISC_CMD: IS_FWI2_CAPABLE(ha) ? @@ -2210,7 +2645,7 @@ qla2x00_start_sp(srb_t *sp) } wmb(); - qla2x00_start_iocbs(sp); + qla2x00_start_iocbs(sp->fcport->vha, ha->req_q_map[0]); done: spin_unlock_irqrestore(&ha->hardware_lock, flags); return rval; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 2516adf1aee..349843ea32f 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -242,32 +242,34 @@ static void qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) { uint16_t cnt; + uint32_t mboxes; uint16_t __iomem *wptr; struct qla_hw_data *ha = vha->hw; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; + /* Read all mbox registers? */ + mboxes = (1 << ha->mbx_count) - 1; + if (!ha->mcp) + ql_dbg(ql_dbg_async, vha, 0x5001, "MBX pointer ERRROR.\n"); + else + mboxes = ha->mcp->in_mb; + /* Load return mailbox registers. */ ha->flags.mbox_int = 1; ha->mailbox_out[0] = mb0; + mboxes >>= 1; wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 1); for (cnt = 1; cnt < ha->mbx_count; cnt++) { if (IS_QLA2200(ha) && cnt == 8) wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 8); - if (cnt == 4 || cnt == 5) + if ((cnt == 4 || cnt == 5) && (mboxes & BIT_0)) ha->mailbox_out[cnt] = qla2x00_debounce_register(wptr); - else + else if (mboxes & BIT_0) ha->mailbox_out[cnt] = RD_REG_WORD(wptr); wptr++; - } - - if (ha->mcp) { - ql_dbg(ql_dbg_async, vha, 0x5000, - "Got mbx completion. cmd=%x.\n", ha->mcp->mb[0]); - } else { - ql_dbg(ql_dbg_async, vha, 0x5001, - "MBX pointer ERROR.\n"); + mboxes >>= 1; } } @@ -298,7 +300,7 @@ qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr) return; ql_dbg(ql_dbg_async, vha, 0x5022, - "Inter-Driver Commucation %s -- ACK timeout=%d.\n", + "%lu Inter-Driver Communication %s -- ACK timeout=%d.\n", vha->host_no, event[aen & 0xff], timeout); rval = qla2x00_post_idc_ack_work(vha, mb); @@ -453,7 +455,7 @@ skip_rio: break; case MBA_LIP_OCCURRED: /* Loop Initialization Procedure */ - ql_log(ql_log_info, vha, 0x5009, + ql_dbg(ql_dbg_async, vha, 0x5009, "LIP occurred (%x).\n", mb[1]); if (atomic_read(&vha->loop_state) != LOOP_DOWN) { @@ -487,7 +489,7 @@ skip_rio: ha->link_data_rate = mb[1]; } - ql_log(ql_log_info, vha, 0x500a, + ql_dbg(ql_dbg_async, vha, 0x500a, "LOOP UP detected (%s Gbps).\n", link_speed); vha->flags.management_server_logged_in = 0; @@ -497,7 +499,7 @@ skip_rio: case MBA_LOOP_DOWN: /* Loop Down Event */ mbx = IS_QLA81XX(ha) ? RD_REG_WORD(®24->mailbox4) : 0; mbx = IS_QLA82XX(ha) ? RD_REG_WORD(®82->mailbox_out[4]) : mbx; - ql_log(ql_log_info, vha, 0x500b, + ql_dbg(ql_dbg_async, vha, 0x500b, "LOOP DOWN detected (%x %x %x %x).\n", mb[1], mb[2], mb[3], mbx); @@ -519,7 +521,7 @@ skip_rio: break; case MBA_LIP_RESET: /* LIP reset occurred */ - ql_log(ql_log_info, vha, 0x500c, + ql_dbg(ql_dbg_async, vha, 0x500c, "LIP reset occurred (%x).\n", mb[1]); if (atomic_read(&vha->loop_state) != LOOP_DOWN) { @@ -587,7 +589,7 @@ skip_rio: if (IS_QLA2100(ha)) break; - ql_log(ql_log_info, vha, 0x500f, + ql_dbg(ql_dbg_async, vha, 0x500f, "Configuration change detected: value=%x.\n", mb[1]); if (atomic_read(&vha->loop_state) != LOOP_DOWN) { @@ -920,15 +922,15 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, QLA_LOGIO_LOGIN_RETRIED : 0; if (mbx->entry_status) { ql_dbg(ql_dbg_async, vha, 0x5043, - "Async-%s error entry - portid=%02x%02x%02x " + "Async-%s error entry - hdl=%x portid=%02x%02x%02x " "entry-status=%x status=%x state-flag=%x " - "status-flags=%x.\n", - type, fcport->d_id.b.domain, fcport->d_id.b.area, + "status-flags=%x.\n", type, sp->handle, + fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, mbx->entry_status, le16_to_cpu(mbx->status), le16_to_cpu(mbx->state_flags), le16_to_cpu(mbx->status_flags)); - ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5057, + ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5029, (uint8_t *)mbx, sizeof(*mbx)); goto logio_done; @@ -940,9 +942,10 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, status = 0; if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) { ql_dbg(ql_dbg_async, vha, 0x5045, - "Async-%s complete - portid=%02x%02x%02x mbx1=%x.\n", - type, fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa, le16_to_cpu(mbx->mb1)); + "Async-%s complete - hdl=%x portid=%02x%02x%02x mbx1=%x.\n", + type, sp->handle, fcport->d_id.b.domain, + fcport->d_id.b.area, fcport->d_id.b.al_pa, + le16_to_cpu(mbx->mb1)); data[0] = MBS_COMMAND_COMPLETE; if (ctx->type == SRB_LOGIN_CMD) { @@ -968,11 +971,10 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, } ql_log(ql_log_warn, vha, 0x5046, - "Async-%s failed - portid=%02x%02x%02x status=%x " - "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n", - type, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa, status, - le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1), + "Async-%s failed - hdl=%x portid=%02x%02x%02x status=%x " + "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n", type, sp->handle, + fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, + status, le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1), le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6), le16_to_cpu(mbx->mb7)); @@ -1036,7 +1038,7 @@ qla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req, bsg_job->reply->result = DID_ERROR << 16; bsg_job->reply->reply_payload_rcv_len = 0; } - ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5058, + ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5035, (uint8_t *)pkt, sizeof(*pkt)); } else { bsg_job->reply->result = DID_OK << 16; @@ -1111,9 +1113,9 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count); ql_log(ql_log_info, vha, 0x503f, - "ELS-CT pass-through-%s error comp_status-status=0x%x " + "ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x " "error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n", - type, comp_status, fw_status[1], fw_status[2], + type, sp->handle, comp_status, fw_status[1], fw_status[2], le16_to_cpu(((struct els_sts_entry_24xx *) pkt)->total_byte_count)); fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); @@ -1121,9 +1123,9 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, } else { ql_log(ql_log_info, vha, 0x5040, - "ELS-CT pass-through-%s error comp_status-status=0x%x " + "ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x " "error subcode 1=0x%x error subcode 2=0x%x.\n", - type, comp_status, + type, sp->handle, comp_status, le16_to_cpu(((struct els_sts_entry_24xx *) pkt)->error_subcode_1), le16_to_cpu(((struct els_sts_entry_24xx *) @@ -1184,11 +1186,12 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, QLA_LOGIO_LOGIN_RETRIED : 0; if (logio->entry_status) { ql_log(ql_log_warn, vha, 0x5034, - "Async-%s error entry - " + "Async-%s error entry - hdl=%x" "portid=%02x%02x%02x entry-status=%x.\n", - type, fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa, logio->entry_status); - ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5059, + type, sp->handle, fcport->d_id.b.domain, + fcport->d_id.b.area, fcport->d_id.b.al_pa, + logio->entry_status); + ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x504d, (uint8_t *)logio, sizeof(*logio)); goto logio_done; @@ -1196,10 +1199,9 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) { ql_dbg(ql_dbg_async, vha, 0x5036, - "Async-%s complete - portid=%02x%02x%02x " - "iop0=%x.\n", - type, fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa, + "Async-%s complete - hdl=%x portid=%02x%02x%02x " + "iop0=%x.\n", type, sp->handle, fcport->d_id.b.domain, + fcport->d_id.b.area, fcport->d_id.b.al_pa, le32_to_cpu(logio->io_parameter[0])); data[0] = MBS_COMMAND_COMPLETE; @@ -1238,9 +1240,8 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, } ql_dbg(ql_dbg_async, vha, 0x5037, - "Async-%s failed - portid=%02x%02x%02x comp=%x " - "iop0=%x iop1=%x.\n", - type, fcport->d_id.b.domain, + "Async-%s failed - hdl=%x portid=%02x%02x%02x comp=%x " + "iop0=%x iop1=%x.\n", type, sp->handle, fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, le16_to_cpu(logio->comp_status), le32_to_cpu(logio->io_parameter[0]), @@ -1274,25 +1275,25 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, if (sts->entry_status) { ql_log(ql_log_warn, vha, 0x5038, - "Async-%s error - entry-status(%x).\n", - type, sts->entry_status); + "Async-%s error - hdl=%x entry-status(%x).\n", + type, sp->handle, sts->entry_status); } else if (sts->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) { ql_log(ql_log_warn, vha, 0x5039, - "Async-%s error - completion status(%x).\n", - type, sts->comp_status); + "Async-%s error - hdl=%x completion status(%x).\n", + type, sp->handle, sts->comp_status); } else if (!(le16_to_cpu(sts->scsi_status) & SS_RESPONSE_INFO_LEN_VALID)) { ql_log(ql_log_warn, vha, 0x503a, - "Async-%s error - no response info(%x).\n", - type, sts->scsi_status); + "Async-%s error - hdl=%x no response info(%x).\n", + type, sp->handle, sts->scsi_status); } else if (le32_to_cpu(sts->rsp_data_len) < 4) { ql_log(ql_log_warn, vha, 0x503b, - "Async-%s error - not enough response(%d).\n", - type, sts->rsp_data_len); + "Async-%s error - hdl=%x not enough response(%d).\n", + type, sp->handle, sts->rsp_data_len); } else if (sts->data[3]) { ql_log(ql_log_warn, vha, 0x503c, - "Async-%s error - response(%x).\n", - type, sts->data[3]); + "Async-%s error - hdl=%x response(%x).\n", + type, sp->handle, sts->data[3]); } else { error = 0; } @@ -1337,9 +1338,6 @@ qla2x00_process_response_queue(struct rsp_que *rsp) } if (pkt->entry_status != 0) { - ql_log(ql_log_warn, vha, 0x5035, - "Process error entry.\n"); - qla2x00_error_entry(vha, rsp, pkt); ((response_t *)pkt)->signature = RESPONSE_PROCESSED; wmb(); @@ -1391,7 +1389,6 @@ qla2x00_process_response_queue(struct rsp_que *rsp) } static inline void - qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len, uint32_t sense_len, struct rsp_que *rsp) { @@ -1413,13 +1410,14 @@ qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len, if (sp->request_sense_length != 0) rsp->status_srb = sp; - ql_dbg(ql_dbg_io, vha, 0x301c, - "Check condition Sense data, scsi(%ld:%d:%d:%d) cmd=%p.\n", - sp->fcport->vha->host_no, cp->device->channel, cp->device->id, - cp->device->lun, cp); - if (sense_len) + if (sense_len) { + ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x301c, + "Check condition Sense data, nexus%ld:%d:%d cmd=%p.\n", + sp->fcport->vha->host_no, cp->device->id, cp->device->lun, + cp); ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302b, cp->sense_buffer, sense_len); + } } struct scsi_dif_tuple { @@ -1506,7 +1504,7 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24) } if (k != blocks_done) { - qla_printk(KERN_WARNING, sp->fcport->vha->hw, + ql_log(ql_log_warn, vha, 0x302f, "unexpected tag values tag:lba=%x:%llx)\n", e_ref_tag, (unsigned long long)lba_s); return 1; @@ -1611,7 +1609,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) sp = NULL; if (sp == NULL) { - ql_log(ql_log_warn, vha, 0x3017, + ql_dbg(ql_dbg_io, vha, 0x3017, "Invalid status handle (0x%x).\n", sts->handle); if (IS_QLA82XX(ha)) @@ -1623,7 +1621,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) } cp = sp->cmd; if (cp == NULL) { - ql_log(ql_log_warn, vha, 0x3018, + ql_dbg(ql_dbg_io, vha, 0x3018, "Command already returned (0x%x/%p).\n", sts->handle, sp); @@ -1670,7 +1668,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) par_sense_len -= rsp_info_len; } if (rsp_info_len > 3 && rsp_info[3]) { - ql_log(ql_log_warn, vha, 0x3019, + ql_dbg(ql_dbg_io, vha, 0x3019, "FCP I/O protocol failure (0x%x/0x%x).\n", rsp_info_len, rsp_info[3]); @@ -1701,7 +1699,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) if (!lscsi_status && ((unsigned)(scsi_bufflen(cp) - resid) < cp->underflow)) { - ql_log(ql_log_warn, vha, 0x301a, + ql_dbg(ql_dbg_io, vha, 0x301a, "Mid-layer underflow " "detected (0x%x of 0x%x bytes).\n", resid, scsi_bufflen(cp)); @@ -1713,7 +1711,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) cp->result = DID_OK << 16 | lscsi_status; if (lscsi_status == SAM_STAT_TASK_SET_FULL) { - ql_log(ql_log_warn, vha, 0x301b, + ql_dbg(ql_dbg_io, vha, 0x301b, "QUEUE FULL detected.\n"); break; } @@ -1735,19 +1733,19 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) scsi_set_resid(cp, resid); if (scsi_status & SS_RESIDUAL_UNDER) { if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) { - ql_log(ql_log_warn, vha, 0x301d, + ql_dbg(ql_dbg_io, vha, 0x301d, "Dropped frame(s) detected " "(0x%x of 0x%x bytes).\n", resid, scsi_bufflen(cp)); cp->result = DID_ERROR << 16 | lscsi_status; - break; + goto check_scsi_status; } if (!lscsi_status && ((unsigned)(scsi_bufflen(cp) - resid) < cp->underflow)) { - ql_log(ql_log_warn, vha, 0x301e, + ql_dbg(ql_dbg_io, vha, 0x301e, "Mid-layer underflow " "detected (0x%x of 0x%x bytes).\n", resid, scsi_bufflen(cp)); @@ -1756,7 +1754,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) break; } } else { - ql_log(ql_log_warn, vha, 0x301f, + ql_dbg(ql_dbg_io, vha, 0x301f, "Dropped frame(s) detected (0x%x " "of 0x%x bytes).\n", resid, scsi_bufflen(cp)); @@ -1774,7 +1772,7 @@ check_scsi_status: */ if (lscsi_status != 0) { if (lscsi_status == SAM_STAT_TASK_SET_FULL) { - ql_log(ql_log_warn, vha, 0x3020, + ql_dbg(ql_dbg_io, vha, 0x3020, "QUEUE FULL detected.\n"); logit = 1; break; @@ -1838,10 +1836,15 @@ out: if (logit) ql_dbg(ql_dbg_io, vha, 0x3022, "FCP command status: 0x%x-0x%x (0x%x) " - "oxid=0x%x cdb=%02x%02x%02x len=0x%x " + "nexus=%ld:%d:%d portid=%02x%02x%02x oxid=0x%x " + "cdb=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x len=0x%x " "rsp_info=0x%x resid=0x%x fw_resid=0x%x.\n", - comp_status, scsi_status, cp->result, ox_id, cp->cmnd[0], - cp->cmnd[1], cp->cmnd[2], scsi_bufflen(cp), rsp_info_len, + comp_status, scsi_status, cp->result, vha->host_no, + cp->device->id, cp->device->lun, fcport->d_id.b.domain, + fcport->d_id.b.area, fcport->d_id.b.al_pa, ox_id, + cp->cmnd[0], cp->cmnd[1], cp->cmnd[2], cp->cmnd[3], + cp->cmnd[4], cp->cmnd[5], cp->cmnd[6], cp->cmnd[7], + cp->cmnd[8], cp->cmnd[9], scsi_bufflen(cp), rsp_info_len, resid_len, fw_resid_len); if (rsp->status_srb == NULL) @@ -1899,6 +1902,45 @@ qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt) } } +static int +qla2x00_free_sp_ctx(scsi_qla_host_t *vha, srb_t *sp) +{ + struct qla_hw_data *ha = vha->hw; + struct srb_ctx *ctx; + + if (!sp->ctx) + return 1; + + ctx = sp->ctx; + + if (ctx->type == SRB_LOGIN_CMD || + ctx->type == SRB_LOGOUT_CMD || + ctx->type == SRB_TM_CMD) { + ctx->u.iocb_cmd->done(sp); + return 0; + } else if (ctx->type == SRB_ADISC_CMD) { + ctx->u.iocb_cmd->free(sp); + return 0; + } else { + struct fc_bsg_job *bsg_job; + + bsg_job = ctx->u.bsg_job; + if (ctx->type == SRB_ELS_CMD_HST || + ctx->type == SRB_CT_CMD) + kfree(sp->fcport); + + bsg_job->reply->reply_data.ctels_reply.status = + FC_CTELS_STATUS_OK; + bsg_job->reply->result = DID_ERROR << 16; + bsg_job->reply->reply_payload_rcv_len = 0; + kfree(sp->ctx); + mempool_free(sp, ha->srb_mempool); + bsg_job->job_done(bsg_job); + return 0; + } + return 1; +} + /** * qla2x00_error_entry() - Process an error entry. * @ha: SCSI driver HA context @@ -1909,7 +1951,7 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) { srb_t *sp; struct qla_hw_data *ha = vha->hw; - uint32_t handle = LSW(pkt->handle); + const char func[] = "ERROR-IOCB"; uint16_t que = MSW(pkt->handle); struct req_que *req = ha->req_q_map[que]; @@ -1932,28 +1974,20 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) ql_dbg(ql_dbg_async, vha, 0x502f, "UNKNOWN flag error.\n"); - /* Validate handle. */ - if (handle < MAX_OUTSTANDING_COMMANDS) - sp = req->outstanding_cmds[handle]; - else - sp = NULL; - + sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); if (sp) { - /* Free outstanding command slot. */ - req->outstanding_cmds[handle] = NULL; - - /* Bad payload or header */ - if (pkt->entry_status & - (RF_INV_E_ORDER | RF_INV_E_COUNT | - RF_INV_E_PARAM | RF_INV_E_TYPE)) { - sp->cmd->result = DID_ERROR << 16; - } else if (pkt->entry_status & RF_BUSY) { - sp->cmd->result = DID_BUS_BUSY << 16; - } else { - sp->cmd->result = DID_ERROR << 16; + if (qla2x00_free_sp_ctx(vha, sp)) { + if (pkt->entry_status & + (RF_INV_E_ORDER | RF_INV_E_COUNT | + RF_INV_E_PARAM | RF_INV_E_TYPE)) { + sp->cmd->result = DID_ERROR << 16; + } else if (pkt->entry_status & RF_BUSY) { + sp->cmd->result = DID_BUS_BUSY << 16; + } else { + sp->cmd->result = DID_ERROR << 16; + } + qla2x00_sp_compl(ha, sp); } - qla2x00_sp_compl(ha, sp); - } else if (pkt->entry_type == COMMAND_A64_TYPE || pkt->entry_type == COMMAND_TYPE || pkt->entry_type == COMMAND_TYPE_7 || pkt->entry_type == COMMAND_TYPE_6) { @@ -1977,26 +2011,30 @@ static void qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) { uint16_t cnt; + uint32_t mboxes; uint16_t __iomem *wptr; struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + /* Read all mbox registers? */ + mboxes = (1 << ha->mbx_count) - 1; + if (!ha->mcp) + ql_dbg(ql_dbg_async, vha, 0x504e, "MBX pointer ERRROR.\n"); + else + mboxes = ha->mcp->in_mb; + /* Load return mailbox registers. */ ha->flags.mbox_int = 1; ha->mailbox_out[0] = mb0; + mboxes >>= 1; wptr = (uint16_t __iomem *)®->mailbox1; for (cnt = 1; cnt < ha->mbx_count; cnt++) { - ha->mailbox_out[cnt] = RD_REG_WORD(wptr); - wptr++; - } + if (mboxes & BIT_0) + ha->mailbox_out[cnt] = RD_REG_WORD(wptr); - if (ha->mcp) { - ql_dbg(ql_dbg_async, vha, 0x504d, - "Got mailbox completion. cmd=%x.\n", ha->mcp->mb[0]); - } else { - ql_dbg(ql_dbg_async, vha, 0x504e, - "MBX pointer ERROR.\n"); + mboxes >>= 1; + wptr++; } } @@ -2025,9 +2063,6 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, } if (pkt->entry_status != 0) { - ql_dbg(ql_dbg_async, vha, 0x5029, - "Process error entry.\n"); - qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt); ((response_t *)pkt)->signature = RESPONSE_PROCESSED; wmb(); @@ -2055,7 +2090,6 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, break; case CT_IOCB_TYPE: qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE); - clear_bit(MBX_INTERRUPT, &vha->hw->mbx_cmd_flags); break; case ELS_IOCB_TYPE: qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 3b3cec9f6ac..08f1d01bdc1 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -79,8 +79,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) mcp->mb[0] = MBS_LINK_DOWN_ERROR; ql_log(ql_log_warn, base_vha, 0x1004, "FW hung = %d.\n", ha->flags.isp82xx_fw_hung); - rval = QLA_FUNCTION_FAILED; - goto premature_exit; + return QLA_FUNCTION_TIMEOUT; } /* @@ -163,6 +162,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) HINT_MBX_INT_PENDING) { spin_unlock_irqrestore(&ha->hardware_lock, flags); + ha->flags.mbox_busy = 0; ql_dbg(ql_dbg_mbx, base_vha, 0x1010, "Pending mailbox timeout, exiting.\n"); rval = QLA_FUNCTION_TIMEOUT; @@ -188,6 +188,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) HINT_MBX_INT_PENDING) { spin_unlock_irqrestore(&ha->hardware_lock, flags); + ha->flags.mbox_busy = 0; ql_dbg(ql_dbg_mbx, base_vha, 0x1012, "Pending mailbox timeout, exiting.\n"); rval = QLA_FUNCTION_TIMEOUT; @@ -302,7 +303,15 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) && !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) && !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { - + if (IS_QLA82XX(ha)) { + ql_dbg(ql_dbg_mbx, vha, 0x112a, + "disabling pause transmit on port " + "0 & 1.\n"); + qla82xx_wr_32(ha, + QLA82XX_CRB_NIU + 0x98, + CRB_NIU_XG_PAUSE_CTL_P0| + CRB_NIU_XG_PAUSE_CTL_P1); + } ql_log(ql_log_info, base_vha, 0x101c, "Mailbox cmd timeout occured. " "Scheduling ISP abort eeh_busy=0x%x.\n", @@ -318,13 +327,23 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) && !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) && !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { - + if (IS_QLA82XX(ha)) { + ql_dbg(ql_dbg_mbx, vha, 0x112b, + "disabling pause transmit on port " + "0 & 1.\n"); + qla82xx_wr_32(ha, + QLA82XX_CRB_NIU + 0x98, + CRB_NIU_XG_PAUSE_CTL_P0| + CRB_NIU_XG_PAUSE_CTL_P1); + } ql_log(ql_log_info, base_vha, 0x101e, "Mailbox cmd timeout occured. " "Scheduling ISP abort.\n"); set_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags); clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + /* Allow next mbx cmd to come in. */ + complete(&ha->mbx_cmd_comp); if (ha->isp_ops->abort_isp(vha)) { /* Failed. retry later. */ set_bit(ISP_ABORT_NEEDED, @@ -333,6 +352,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) clear_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags); ql_dbg(ql_dbg_mbx, base_vha, 0x101f, "Finished abort_isp.\n"); + goto mbx_done; } } } @@ -341,6 +361,7 @@ premature_exit: /* Allow next mbx cmd to come in. */ complete(&ha->mbx_cmd_comp); +mbx_done: if (rval) { ql_dbg(ql_dbg_mbx, base_vha, 0x1020, "**** Failed mbx[0]=%x, mb[1]=%x, mb[2]=%x, cmd=%x ****.\n", @@ -2564,7 +2585,8 @@ qla2x00_stop_firmware(scsi_qla_host_t *vha) ql_dbg(ql_dbg_mbx, vha, 0x10a1, "Entered %s.\n", __func__); mcp->mb[0] = MBC_STOP_FIRMWARE; - mcp->out_mb = MBX_0; + mcp->mb[1] = 0; + mcp->out_mb = MBX_1|MBX_0; mcp->in_mb = MBX_0; mcp->tov = 5; mcp->flags = 0; @@ -2870,7 +2892,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, if (vp_idx == 0 && (MSB(stat) != 1)) goto reg_needed; - if (MSB(stat) == 1) { + if (MSB(stat) != 0) { ql_dbg(ql_dbg_mbx, vha, 0x10ba, "Could not acquire ID for VP[%d].\n", vp_idx); return; diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 94bded5ddce..270ba3130fd 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -369,7 +369,7 @@ qla82xx_pci_set_crbwindow_2M(struct qla_hw_data *ha, ulong *off) ql_dbg(ql_dbg_p3p, vha, 0xb000, "%s: Written crbwin (0x%x) " "!= Read crbwin (0x%x), off=0x%lx.\n", - ha->crb_win, win_read, *off); + __func__, ha->crb_win, win_read, *off); } *off = (*off & MASK(16)) + CRB_INDIRECT_2M + ha->nx_pcibase; } @@ -409,7 +409,7 @@ qla82xx_pci_set_crbwindow(struct qla_hw_data *ha, u64 off) } /* strange address given */ ql_dbg(ql_dbg_p3p, vha, 0xb001, - "%x: Warning: unm_nic_pci_set_crbwindow " + "%s: Warning: unm_nic_pci_set_crbwindow " "called with an unknown address(%llx).\n", QLA2XXX_DRIVER_NAME, off); return off; @@ -1055,7 +1055,7 @@ ql82xx_rom_lock_d(struct qla_hw_data *ha) "ROM lock failed.\n"); return -1; } - return 0;; + return 0; } static int @@ -1165,19 +1165,6 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha) qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xfeffffff); else qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xffffffff); - - /* reset ms */ - val = qla82xx_rd_32(ha, QLA82XX_CRB_QDR_NET + 0xe4); - val |= (1 << 1); - qla82xx_wr_32(ha, QLA82XX_CRB_QDR_NET + 0xe4, val); - msleep(20); - - /* unreset ms */ - val = qla82xx_rd_32(ha, QLA82XX_CRB_QDR_NET + 0xe4); - val &= ~(1 << 1); - qla82xx_wr_32(ha, QLA82XX_CRB_QDR_NET + 0xe4, val); - msleep(20); - qla82xx_rom_unlock(ha); /* Read the signature value from the flash. @@ -1711,12 +1698,12 @@ qla82xx_iospace_config(struct qla_hw_data *ha) ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc006, "nx_pci_base=%p iobase=%p " "max_req_queues=%d msix_count=%d.\n", - ha->nx_pcibase, ha->iobase, + (void *)ha->nx_pcibase, ha->iobase, ha->max_req_queues, ha->msix_count); ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0010, "nx_pci_base=%p iobase=%p " "max_req_queues=%d msix_count=%d.\n", - ha->nx_pcibase, ha->iobase, + (void *)ha->nx_pcibase, ha->iobase, ha->max_req_queues, ha->msix_count); return 0; @@ -1744,7 +1731,7 @@ qla82xx_pci_config(scsi_qla_host_t *vha) ret = pci_set_mwi(ha->pdev); ha->chip_revision = ha->pdev->revision; ql_dbg(ql_dbg_init, vha, 0x0043, - "Chip revision:%ld.\n", + "Chip revision:%d.\n", ha->chip_revision); return 0; } @@ -2023,13 +2010,9 @@ qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) wptr++; } - if (ha->mcp) { - ql_dbg(ql_dbg_async, vha, 0x5052, - "Got mailbox completion. cmd=%x.\n", ha->mcp->mb[0]); - } else { + if (!ha->mcp) ql_dbg(ql_dbg_async, vha, 0x5053, "MBX pointer ERROR.\n"); - } } /* @@ -2543,484 +2526,6 @@ qla82xx_start_firmware(scsi_qla_host_t *vha) return qla82xx_check_rcvpeg_state(ha); } -static inline int -qla2xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, - uint16_t tot_dsds) -{ - uint32_t *cur_dsd = NULL; - scsi_qla_host_t *vha; - struct qla_hw_data *ha; - struct scsi_cmnd *cmd; - struct scatterlist *cur_seg; - uint32_t *dsd_seg; - void *next_dsd; - uint8_t avail_dsds; - uint8_t first_iocb = 1; - uint32_t dsd_list_len; - struct dsd_dma *dsd_ptr; - struct ct6_dsd *ctx; - - cmd = sp->cmd; - - /* Update entry type to indicate Command Type 3 IOCB */ - *((uint32_t *)(&cmd_pkt->entry_type)) = - __constant_cpu_to_le32(COMMAND_TYPE_6); - - /* No data transfer */ - if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { - cmd_pkt->byte_count = __constant_cpu_to_le32(0); - return 0; - } - - vha = sp->fcport->vha; - ha = vha->hw; - - /* Set transfer direction */ - if (cmd->sc_data_direction == DMA_TO_DEVICE) { - cmd_pkt->control_flags = - __constant_cpu_to_le16(CF_WRITE_DATA); - ha->qla_stats.output_bytes += scsi_bufflen(cmd); - } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { - cmd_pkt->control_flags = - __constant_cpu_to_le16(CF_READ_DATA); - ha->qla_stats.input_bytes += scsi_bufflen(cmd); - } - - cur_seg = scsi_sglist(cmd); - ctx = sp->ctx; - - while (tot_dsds) { - avail_dsds = (tot_dsds > QLA_DSDS_PER_IOCB) ? - QLA_DSDS_PER_IOCB : tot_dsds; - tot_dsds -= avail_dsds; - dsd_list_len = (avail_dsds + 1) * QLA_DSD_SIZE; - - dsd_ptr = list_first_entry(&ha->gbl_dsd_list, - struct dsd_dma, list); - next_dsd = dsd_ptr->dsd_addr; - list_del(&dsd_ptr->list); - ha->gbl_dsd_avail--; - list_add_tail(&dsd_ptr->list, &ctx->dsd_list); - ctx->dsd_use_cnt++; - ha->gbl_dsd_inuse++; - - if (first_iocb) { - first_iocb = 0; - dsd_seg = (uint32_t *)&cmd_pkt->fcp_data_dseg_address; - *dsd_seg++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); - *dsd_seg++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - cmd_pkt->fcp_data_dseg_len = cpu_to_le32(dsd_list_len); - } else { - *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = cpu_to_le32(dsd_list_len); - } - cur_dsd = (uint32_t *)next_dsd; - while (avail_dsds) { - dma_addr_t sle_dma; - - sle_dma = sg_dma_address(cur_seg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg)); - cur_seg = sg_next(cur_seg); - avail_dsds--; - } - } - - /* Null termination */ - *cur_dsd++ = 0; - *cur_dsd++ = 0; - *cur_dsd++ = 0; - cmd_pkt->control_flags |= CF_DATA_SEG_DESCR_ENABLE; - return 0; -} - -/* - * qla82xx_calc_dsd_lists() - Determine number of DSD list required - * for Command Type 6. - * - * @dsds: number of data segment decriptors needed - * - * Returns the number of dsd list needed to store @dsds. - */ -inline uint16_t -qla82xx_calc_dsd_lists(uint16_t dsds) -{ - uint16_t dsd_lists = 0; - - dsd_lists = (dsds/QLA_DSDS_PER_IOCB); - if (dsds % QLA_DSDS_PER_IOCB) - dsd_lists++; - return dsd_lists; -} - -/* - * qla82xx_start_scsi() - Send a SCSI command to the ISP - * @sp: command to send to the ISP - * - * Returns non-zero if a failure occurred, else zero. - */ -int -qla82xx_start_scsi(srb_t *sp) -{ - int ret, nseg; - unsigned long flags; - struct scsi_cmnd *cmd; - uint32_t *clr_ptr; - uint32_t index; - uint32_t handle; - uint16_t cnt; - uint16_t req_cnt; - uint16_t tot_dsds; - struct device_reg_82xx __iomem *reg; - uint32_t dbval; - uint32_t *fcp_dl; - uint8_t additional_cdb_len; - struct ct6_dsd *ctx; - struct scsi_qla_host *vha = sp->fcport->vha; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = NULL; - struct rsp_que *rsp = NULL; - char tag[2]; - - /* Setup device pointers. */ - ret = 0; - reg = &ha->iobase->isp82; - cmd = sp->cmd; - req = vha->req; - rsp = ha->rsp_q_map[0]; - - /* So we know we haven't pci_map'ed anything yet */ - tot_dsds = 0; - - dbval = 0x04 | (ha->portnum << 5); - - /* Send marker if required */ - if (vha->marker_needed != 0) { - if (qla2x00_marker(vha, req, - rsp, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x300c, - "qla2x00_marker failed for cmd=%p.\n", cmd); - return QLA_FUNCTION_FAILED; - } - vha->marker_needed = 0; - } - - /* Acquire ring specific lock */ - spin_lock_irqsave(&ha->hardware_lock, flags); - - /* Check for room in outstanding command list. */ - handle = req->current_outstanding_cmd; - for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { - handle++; - if (handle == MAX_OUTSTANDING_COMMANDS) - handle = 1; - if (!req->outstanding_cmds[handle]) - break; - } - if (index == MAX_OUTSTANDING_COMMANDS) - goto queuing_error; - - /* Map the sg table so we have an accurate count of sg entries needed */ - if (scsi_sg_count(cmd)) { - nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), - scsi_sg_count(cmd), cmd->sc_data_direction); - if (unlikely(!nseg)) - goto queuing_error; - } else - nseg = 0; - - tot_dsds = nseg; - - if (tot_dsds > ql2xshiftctondsd) { - struct cmd_type_6 *cmd_pkt; - uint16_t more_dsd_lists = 0; - struct dsd_dma *dsd_ptr; - uint16_t i; - - more_dsd_lists = qla82xx_calc_dsd_lists(tot_dsds); - if ((more_dsd_lists + ha->gbl_dsd_inuse) >= NUM_DSD_CHAIN) { - ql_dbg(ql_dbg_io, vha, 0x300d, - "Num of DSD list %d is than %d for cmd=%p.\n", - more_dsd_lists + ha->gbl_dsd_inuse, NUM_DSD_CHAIN, - cmd); - goto queuing_error; - } - - if (more_dsd_lists <= ha->gbl_dsd_avail) - goto sufficient_dsds; - else - more_dsd_lists -= ha->gbl_dsd_avail; - - for (i = 0; i < more_dsd_lists; i++) { - dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); - if (!dsd_ptr) { - ql_log(ql_log_fatal, vha, 0x300e, - "Failed to allocate memory for dsd_dma " - "for cmd=%p.\n", cmd); - goto queuing_error; - } - - dsd_ptr->dsd_addr = dma_pool_alloc(ha->dl_dma_pool, - GFP_ATOMIC, &dsd_ptr->dsd_list_dma); - if (!dsd_ptr->dsd_addr) { - kfree(dsd_ptr); - ql_log(ql_log_fatal, vha, 0x300f, - "Failed to allocate memory for dsd_addr " - "for cmd=%p.\n", cmd); - goto queuing_error; - } - list_add_tail(&dsd_ptr->list, &ha->gbl_dsd_list); - ha->gbl_dsd_avail++; - } - -sufficient_dsds: - req_cnt = 1; - - if (req->cnt < (req_cnt + 2)) { - cnt = (uint16_t)RD_REG_DWORD_RELAXED( - ®->req_q_out[0]); - if (req->ring_index < cnt) - req->cnt = cnt - req->ring_index; - else - req->cnt = req->length - - (req->ring_index - cnt); - } - - if (req->cnt < (req_cnt + 2)) - goto queuing_error; - - ctx = sp->ctx = mempool_alloc(ha->ctx_mempool, GFP_ATOMIC); - if (!sp->ctx) { - ql_log(ql_log_fatal, vha, 0x3010, - "Failed to allocate ctx for cmd=%p.\n", cmd); - goto queuing_error; - } - memset(ctx, 0, sizeof(struct ct6_dsd)); - ctx->fcp_cmnd = dma_pool_alloc(ha->fcp_cmnd_dma_pool, - GFP_ATOMIC, &ctx->fcp_cmnd_dma); - if (!ctx->fcp_cmnd) { - ql_log(ql_log_fatal, vha, 0x3011, - "Failed to allocate fcp_cmnd for cmd=%p.\n", cmd); - goto queuing_error_fcp_cmnd; - } - - /* Initialize the DSD list and dma handle */ - INIT_LIST_HEAD(&ctx->dsd_list); - ctx->dsd_use_cnt = 0; - - if (cmd->cmd_len > 16) { - additional_cdb_len = cmd->cmd_len - 16; - if ((cmd->cmd_len % 4) != 0) { - /* SCSI command bigger than 16 bytes must be - * multiple of 4 - */ - ql_log(ql_log_warn, vha, 0x3012, - "scsi cmd len %d not multiple of 4 " - "for cmd=%p.\n", cmd->cmd_len, cmd); - goto queuing_error_fcp_cmnd; - } - ctx->fcp_cmnd_len = 12 + cmd->cmd_len + 4; - } else { - additional_cdb_len = 0; - ctx->fcp_cmnd_len = 12 + 16 + 4; - } - - cmd_pkt = (struct cmd_type_6 *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); - - /* Zero out remaining portion of packet. */ - /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ - clr_ptr = (uint32_t *)cmd_pkt + 2; - memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); - cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); - - /* Set NPORT-ID and LUN number*/ - cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); - cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; - cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; - cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; - cmd_pkt->vp_index = sp->fcport->vp_idx; - - /* Build IOCB segments */ - if (qla2xx_build_scsi_type_6_iocbs(sp, cmd_pkt, tot_dsds)) - goto queuing_error_fcp_cmnd; - - int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun); - host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); - - /* build FCP_CMND IU */ - memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd)); - int_to_scsilun(sp->cmd->device->lun, &ctx->fcp_cmnd->lun); - ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len; - - if (cmd->sc_data_direction == DMA_TO_DEVICE) - ctx->fcp_cmnd->additional_cdb_len |= 1; - else if (cmd->sc_data_direction == DMA_FROM_DEVICE) - ctx->fcp_cmnd->additional_cdb_len |= 2; - - /* - * Update tagged queuing modifier -- default is TSK_SIMPLE (0). - */ - if (scsi_populate_tag_msg(cmd, tag)) { - switch (tag[0]) { - case HEAD_OF_QUEUE_TAG: - ctx->fcp_cmnd->task_attribute = - TSK_HEAD_OF_QUEUE; - break; - case ORDERED_QUEUE_TAG: - ctx->fcp_cmnd->task_attribute = - TSK_ORDERED; - break; - } - } - - memcpy(ctx->fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len); - - fcp_dl = (uint32_t *)(ctx->fcp_cmnd->cdb + 16 + - additional_cdb_len); - *fcp_dl = htonl((uint32_t)scsi_bufflen(cmd)); - - cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(ctx->fcp_cmnd_len); - cmd_pkt->fcp_cmnd_dseg_address[0] = - cpu_to_le32(LSD(ctx->fcp_cmnd_dma)); - cmd_pkt->fcp_cmnd_dseg_address[1] = - cpu_to_le32(MSD(ctx->fcp_cmnd_dma)); - - sp->flags |= SRB_FCP_CMND_DMA_VALID; - cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); - /* Set total data segment count. */ - cmd_pkt->entry_count = (uint8_t)req_cnt; - /* Specify response queue number where - * completion should happen - */ - cmd_pkt->entry_status = (uint8_t) rsp->id; - } else { - struct cmd_type_7 *cmd_pkt; - req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); - if (req->cnt < (req_cnt + 2)) { - cnt = (uint16_t)RD_REG_DWORD_RELAXED( - ®->req_q_out[0]); - if (req->ring_index < cnt) - req->cnt = cnt - req->ring_index; - else - req->cnt = req->length - - (req->ring_index - cnt); - } - if (req->cnt < (req_cnt + 2)) - goto queuing_error; - - cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); - - /* Zero out remaining portion of packet. */ - /* tagged queuing modifier -- default is TSK_SIMPLE (0).*/ - clr_ptr = (uint32_t *)cmd_pkt + 2; - memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); - cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); - - /* Set NPORT-ID and LUN number*/ - cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); - cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; - cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; - cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; - cmd_pkt->vp_index = sp->fcport->vp_idx; - - int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun); - host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, - sizeof(cmd_pkt->lun)); - - /* - * Update tagged queuing modifier -- default is TSK_SIMPLE (0). - */ - if (scsi_populate_tag_msg(cmd, tag)) { - switch (tag[0]) { - case HEAD_OF_QUEUE_TAG: - cmd_pkt->task = TSK_HEAD_OF_QUEUE; - break; - case ORDERED_QUEUE_TAG: - cmd_pkt->task = TSK_ORDERED; - break; - } - } - - /* Load SCSI command packet. */ - memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len); - host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb)); - - cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); - - /* Build IOCB segments */ - qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds); - - /* Set total data segment count. */ - cmd_pkt->entry_count = (uint8_t)req_cnt; - /* Specify response queue number where - * completion should happen. - */ - cmd_pkt->entry_status = (uint8_t) rsp->id; - - } - /* Build command packet. */ - req->current_outstanding_cmd = handle; - req->outstanding_cmds[handle] = sp; - sp->handle = handle; - sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle; - req->cnt -= req_cnt; - wmb(); - - /* 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++; - - sp->flags |= SRB_DMA_VALID; - - /* Set chip new ring index. */ - /* 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(); - } - } - - /* 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); - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - return QLA_SUCCESS; - -queuing_error_fcp_cmnd: - dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd, ctx->fcp_cmnd_dma); -queuing_error: - if (tot_dsds) - scsi_dma_unmap(cmd); - - if (sp->ctx) { - mempool_free(sp->ctx, ha->ctx_mempool); - sp->ctx = NULL; - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return QLA_FUNCTION_FAILED; -} - static uint32_t * qla82xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, uint32_t length) @@ -3272,9 +2777,9 @@ qla82xx_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, } void -qla82xx_start_iocbs(srb_t *sp) +qla82xx_start_iocbs(scsi_qla_host_t *vha) { - struct qla_hw_data *ha = sp->fcport->vha->hw; + struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; struct device_reg_82xx __iomem *reg; uint32_t dbval; @@ -3659,11 +3164,10 @@ qla82xx_check_md_needed(scsi_qla_host_t *vha) qla82xx_md_free(vha); /* ALlocate MiniDump resources */ qla82xx_md_prep(vha); - } else - ql_log(ql_log_info, vha, 0xb02e, - "Firmware dump available to retrieve\n", - vha->host_no); - } + } + } else + ql_log(ql_log_info, vha, 0xb02e, + "Firmware dump available to retrieve\n"); } return rval; } @@ -3758,7 +3262,6 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha) switch (dev_state) { case QLA82XX_DEV_READY: - qla82xx_check_md_needed(vha); ha->flags.isp82xx_reset_owner = 0; goto exit; case QLA82XX_DEV_COLD: @@ -3817,6 +3320,20 @@ exit: return rval; } +void qla82xx_clear_pending_mbx(scsi_qla_host_t *vha) +{ + struct qla_hw_data *ha = vha->hw; + + if (ha->flags.mbox_busy) { + ha->flags.mbox_int = 1; + ha->flags.mbox_busy = 0; + ql_log(ql_log_warn, vha, 0x6010, + "Doing premature completion of mbx command.\n"); + if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags)) + complete(&ha->mbx_intr_comp); + } +} + void qla82xx_watchdog(scsi_qla_host_t *vha) { uint32_t dev_state, halt_status; @@ -3839,9 +3356,13 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) qla2xxx_wake_dpc(vha); } else { if (qla82xx_check_fw_alive(vha)) { + ql_dbg(ql_dbg_timer, vha, 0x6011, + "disabling pause transmit on port 0 & 1.\n"); + qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, + CRB_NIU_XG_PAUSE_CTL_P0|CRB_NIU_XG_PAUSE_CTL_P1); halt_status = qla82xx_rd_32(ha, QLA82XX_PEG_HALT_STATUS1); - ql_dbg(ql_dbg_timer, vha, 0x6005, + ql_log(ql_log_info, vha, 0x6005, "dumping hw/fw registers:.\n " " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,.\n " " PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,.\n " @@ -3858,6 +3379,11 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) QLA82XX_CRB_PEG_NET_3 + 0x3c), qla82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c)); + if (((halt_status & 0x1fffff00) >> 8) == 0x67) + ql_log(ql_log_warn, vha, 0xb052, + "Firmware aborted with " + "error code 0x00006700. Device is " + "being reset.\n"); if (halt_status & HALT_STATUS_UNRECOVERABLE) { set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags); @@ -3869,16 +3395,8 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) } qla2xxx_wake_dpc(vha); ha->flags.isp82xx_fw_hung = 1; - if (ha->flags.mbox_busy) { - ha->flags.mbox_int = 1; - ql_log(ql_log_warn, vha, 0x6007, - "Due to FW hung, doing " - "premature completion of mbx " - "command.\n"); - if (test_bit(MBX_INTR_WAIT, - &ha->mbx_cmd_flags)) - complete(&ha->mbx_intr_comp); - } + ql_log(ql_log_warn, vha, 0x6007, "Firmware hung.\n"); + qla82xx_clear_pending_mbx(vha); } } } @@ -4052,7 +3570,7 @@ int qla2x00_wait_for_fcoe_ctx_reset(scsi_qla_host_t *vha) } } ql_dbg(ql_dbg_p3p, vha, 0xb027, - "%s status=%d.\n", status); + "%s: status=%d.\n", __func__, status); return status; } @@ -4073,10 +3591,7 @@ qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha) msleep(1000); if (qla82xx_check_fw_alive(vha)) { ha->flags.isp82xx_fw_hung = 1; - if (ha->flags.mbox_busy) { - ha->flags.mbox_int = 1; - complete(&ha->mbx_intr_comp); - } + qla82xx_clear_pending_mbx(vha); break; } } diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h index 57820c199bc..57a226be339 100644 --- a/drivers/scsi/qla2xxx/qla_nx.h +++ b/drivers/scsi/qla2xxx/qla_nx.h @@ -1173,4 +1173,8 @@ struct qla82xx_md_entry_queue { static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC }; + +#define CRB_NIU_XG_PAUSE_CTL_P0 0x1 +#define CRB_NIU_XG_PAUSE_CTL_P1 0x8 + #endif diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index fd14c7bfc62..036030c9533 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -83,6 +83,9 @@ MODULE_PARM_DESC(ql2xextended_error_logging, "\t\t0x00080000 - P3P Specific. 0x00040000 - Virtual Port.\n" "\t\t0x00020000 - Buffer Dump. 0x00010000 - Misc.\n" "\t\t0x7fffffff - For enabling all logs, can be too many logs.\n" + "\t\t0x1e400000 - Preferred value for capturing essential " + "debug information (equivalent to old " + "ql2xextended_error_logging=1).\n" "\t\tDo LOGICAL OR of the value to enable more than one level"); int ql2xshiftctondsd = 6; @@ -199,14 +202,14 @@ int ql2xmdcapmask = 0x1F; module_param(ql2xmdcapmask, int, S_IRUGO); MODULE_PARM_DESC(ql2xmdcapmask, "Set the Minidump driver capture mask level. " - "Default is 0x7F - Can be set to 0x3, 0x7, 0xF, 0x1F, 0x7F."); + "Default is 0x1F - Can be set to 0x3, 0x7, 0xF, 0x1F, 0x7F."); -int ql2xmdenable; +int ql2xmdenable = 1; module_param(ql2xmdenable, int, S_IRUGO); MODULE_PARM_DESC(ql2xmdenable, "Enable/disable MiniDump. " - "0 (Default) - MiniDump disabled. " - "1 - MiniDump enabled."); + "0 - MiniDump disabled. " + "1 (Default) - MiniDump enabled."); /* * SCSI host template entry points @@ -423,6 +426,7 @@ fail2: qla25xx_delete_queues(vha); destroy_workqueue(ha->wq); ha->wq = NULL; + vha->req = ha->req_q_map[0]; fail: ha->mqenable = 0; kfree(ha->req_q_map); @@ -621,6 +625,12 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) cmd->result = DID_NO_CONNECT << 16; goto qc24_fail_command; } + + if (!fcport) { + cmd->result = DID_NO_CONNECT << 16; + goto qc24_fail_command; + } + if (atomic_read(&fcport->state) != FCS_ONLINE) { if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || atomic_read(&base_vha->loop_state) == LOOP_DEAD) { @@ -814,49 +824,6 @@ qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha) return return_status; } -/* - * qla2x00_wait_for_loop_ready - * Wait for MAX_LOOP_TIMEOUT(5 min) value for loop - * to be in LOOP_READY state. - * Input: - * ha - pointer to host adapter structure - * - * Note: - * Does context switching-Release SPIN_LOCK - * (if any) before calling this routine. - * - * - * Return: - * Success (LOOP_READY) : 0 - * Failed (LOOP_NOT_READY) : 1 - */ -static inline int -qla2x00_wait_for_loop_ready(scsi_qla_host_t *vha) -{ - int return_status = QLA_SUCCESS; - unsigned long loop_timeout ; - struct qla_hw_data *ha = vha->hw; - scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); - - /* wait for 5 min at the max for loop to be ready */ - loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ); - - while ((!atomic_read(&base_vha->loop_down_timer) && - atomic_read(&base_vha->loop_state) == LOOP_DOWN) || - atomic_read(&base_vha->loop_state) != LOOP_READY) { - if (atomic_read(&base_vha->loop_state) == LOOP_DEAD) { - return_status = QLA_FUNCTION_FAILED; - break; - } - msleep(1000); - if (time_after_eq(jiffies, loop_timeout)) { - return_status = QLA_FUNCTION_FAILED; - break; - } - } - return (return_status); -} - static void sp_get(struct srb *sp) { @@ -889,14 +856,10 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) int wait = 0; struct qla_hw_data *ha = vha->hw; - ql_dbg(ql_dbg_taskm, vha, 0x8000, - "Entered %s for cmd=%p.\n", __func__, cmd); if (!CMD_SP(cmd)) return SUCCESS; ret = fc_block_scsi_eh(cmd); - ql_dbg(ql_dbg_taskm, vha, 0x8001, - "Return value of fc_block_scsi_eh=%d.\n", ret); if (ret != 0) return ret; ret = SUCCESS; @@ -912,18 +875,20 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) } ql_dbg(ql_dbg_taskm, vha, 0x8002, - "Aborting sp=%p cmd=%p from RISC ", sp, cmd); + "Aborting from RISC nexus=%ld:%d:%d sp=%p cmd=%p\n", + vha->host_no, id, lun, sp, cmd); /* Get a reference to the sp and drop the lock.*/ sp_get(sp); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (ha->isp_ops->abort_command(sp)) { + ret = FAILED; ql_dbg(ql_dbg_taskm, vha, 0x8003, - "Abort command mbx failed for cmd=%p.\n", cmd); + "Abort command mbx failed cmd=%p.\n", cmd); } else { ql_dbg(ql_dbg_taskm, vha, 0x8004, - "Abort command mbx success.\n"); + "Abort command mbx success cmd=%p.\n", cmd); wait = 1; } @@ -939,13 +904,14 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) if (wait) { if (qla2x00_eh_wait_on_command(cmd) != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x8006, - "Abort handler timed out for cmd=%p.\n", cmd); + "Abort handler timed out cmd=%p.\n", cmd); ret = FAILED; } } ql_log(ql_log_info, vha, 0x801c, - "Abort command issued -- %d %x.\n", wait, ret); + "Abort command issued nexus=%ld:%d:%d -- %d %x.\n", + vha->host_no, id, lun, wait, ret); return ret; } @@ -1014,19 +980,15 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, int err; if (!fcport) { - ql_log(ql_log_warn, vha, 0x8007, - "fcport is NULL.\n"); return FAILED; } err = fc_block_scsi_eh(cmd); - ql_dbg(ql_dbg_taskm, vha, 0x8008, - "fc_block_scsi_eh ret=%d.\n", err); if (err != 0) return err; ql_log(ql_log_info, vha, 0x8009, - "%s RESET ISSUED for id %d lun %d cmd=%p.\n", name, + "%s RESET ISSUED nexus=%ld:%d:%d cmd=%p.\n", name, vha->host_no, cmd->device->id, cmd->device->lun, cmd); err = 0; @@ -1035,12 +997,6 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, "Wait for hba online failed for cmd=%p.\n", cmd); goto eh_reset_failed; } - err = 1; - if (qla2x00_wait_for_loop_ready(vha) != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x800b, - "Wait for loop ready failed for cmd=%p.\n", cmd); - goto eh_reset_failed; - } err = 2; if (do_reset(fcport, cmd->device->lun, cmd->request->cpu + 1) != QLA_SUCCESS) { @@ -1057,15 +1013,16 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, } ql_log(ql_log_info, vha, 0x800e, - "%s RESET SUCCEEDED for id %d lun %d cmd=%p.\n", name, - cmd->device->id, cmd->device->lun, cmd); + "%s RESET SUCCEEDED nexus:%ld:%d:%d cmd=%p.\n", name, + vha->host_no, cmd->device->id, cmd->device->lun, cmd); return SUCCESS; eh_reset_failed: ql_log(ql_log_info, vha, 0x800f, - "%s RESET FAILED: %s for id %d lun %d cmd=%p.\n", name, - reset_errors[err], cmd->device->id, cmd->device->lun); + "%s RESET FAILED: %s nexus=%ld:%d:%d cmd=%p.\n", name, + reset_errors[err], vha->host_no, cmd->device->id, cmd->device->lun, + cmd); return FAILED; } @@ -1116,20 +1073,16 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) lun = cmd->device->lun; if (!fcport) { - ql_log(ql_log_warn, vha, 0x8010, - "fcport is NULL.\n"); return ret; } ret = fc_block_scsi_eh(cmd); - ql_dbg(ql_dbg_taskm, vha, 0x8011, - "fc_block_scsi_eh ret=%d.\n", ret); if (ret != 0) return ret; ret = FAILED; ql_log(ql_log_info, vha, 0x8012, - "BUS RESET ISSUED for id %d lun %d.\n", id, lun); + "BUS RESET ISSUED nexus=%ld:%d%d.\n", vha->host_no, id, lun); if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { ql_log(ql_log_fatal, vha, 0x8013, @@ -1137,10 +1090,9 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) goto eh_bus_reset_done; } - if (qla2x00_wait_for_loop_ready(vha) == QLA_SUCCESS) { - if (qla2x00_loop_reset(vha) == QLA_SUCCESS) - ret = SUCCESS; - } + if (qla2x00_loop_reset(vha) == QLA_SUCCESS) + ret = SUCCESS; + if (ret == FAILED) goto eh_bus_reset_done; @@ -1154,7 +1106,8 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) eh_bus_reset_done: ql_log(ql_log_warn, vha, 0x802b, - "BUS RESET %s.\n", (ret == FAILED) ? "FAILED" : "SUCCEDED"); + "BUS RESET %s nexus=%ld:%d:%d.\n", + (ret == FAILED) ? "FAILED" : "SUCCEDED", vha->host_no, id, lun); return ret; } @@ -1178,7 +1131,6 @@ static int qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) { scsi_qla_host_t *vha = shost_priv(cmd->device->host); - fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; struct qla_hw_data *ha = vha->hw; int ret = FAILED; unsigned int id, lun; @@ -1187,34 +1139,12 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) id = cmd->device->id; lun = cmd->device->lun; - if (!fcport) { - ql_log(ql_log_warn, vha, 0x8016, - "fcport is NULL.\n"); - return ret; - } - - ret = fc_block_scsi_eh(cmd); - ql_dbg(ql_dbg_taskm, vha, 0x8017, - "fc_block_scsi_eh ret=%d.\n", ret); - if (ret != 0) - return ret; - ret = FAILED; - ql_log(ql_log_info, vha, 0x8018, - "ADAPTER RESET ISSUED for id %d lun %d.\n", id, lun); + "ADAPTER RESET ISSUED nexus=%ld:%d:%d.\n", vha->host_no, id, lun); if (qla2x00_wait_for_reset_ready(vha) != QLA_SUCCESS) goto eh_host_reset_lock; - /* - * Fixme-may be dpc thread is active and processing - * loop_resync,so wait a while for it to - * be completed and then issue big hammer.Otherwise - * it may cause I/O failure as big hammer marks the - * devices as lost kicking of the port_down_timer - * while dpc is stuck for the mailbox to complete. - */ - qla2x00_wait_for_loop_ready(vha); if (vha != base_vha) { if (qla2x00_vp_abort_isp(vha)) goto eh_host_reset_lock; @@ -1251,8 +1181,9 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) ret = SUCCESS; eh_host_reset_lock: - qla_printk(KERN_INFO, ha, "%s: reset %s.\n", __func__, - (ret == FAILED) ? "failed" : "succeeded"); + ql_log(ql_log_info, vha, 0x8017, + "ADAPTER RESET %s nexus=%ld:%d:%d.\n", + (ret == FAILED) ? "FAILED" : "SUCCEEDED", vha->host_no, id, lun); return ret; } @@ -1297,16 +1228,13 @@ qla2x00_loop_reset(scsi_qla_host_t *vha) atomic_set(&vha->loop_state, LOOP_DOWN); atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); qla2x00_mark_all_devices_lost(vha, 0); - qla2x00_wait_for_loop_ready(vha); } if (ha->flags.enable_lip_reset) { ret = qla2x00_lip_reset(vha); - if (ret != QLA_SUCCESS) { + if (ret != QLA_SUCCESS) ql_dbg(ql_dbg_taskm, vha, 0x802e, "lip_reset failed (%d).\n", ret); - } else - qla2x00_wait_for_loop_ready(vha); } /* Issue marker command only when we are going to start the I/O */ @@ -1405,10 +1333,8 @@ static void qla2x00_handle_queue_full(struct scsi_device *sdev, int qdepth) return; ql_dbg(ql_dbg_io, fcport->vha, 0x3029, - "Queue depth adjusted-down " - "to %d for scsi(%ld:%d:%d:%d).\n", - sdev->queue_depth, fcport->vha->host_no, - sdev->channel, sdev->id, sdev->lun); + "Queue depth adjusted-down to %d for nexus=%ld:%d:%d.\n", + sdev->queue_depth, fcport->vha->host_no, sdev->id, sdev->lun); } static void qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, int qdepth) @@ -1430,10 +1356,8 @@ static void qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, int qdepth) scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, qdepth); ql_dbg(ql_dbg_io, vha, 0x302a, - "Queue depth adjusted-up to %d for " - "scsi(%ld:%d:%d:%d).\n", - sdev->queue_depth, fcport->vha->host_no, - sdev->channel, sdev->id, sdev->lun); + "Queue depth adjusted-up to %d for nexus=%ld:%d:%d.\n", + sdev->queue_depth, fcport->vha->host_no, sdev->id, sdev->lun); } static int @@ -1557,6 +1481,118 @@ qla24xx_disable_intrs(struct qla_hw_data *ha) spin_unlock_irqrestore(&ha->hardware_lock, flags); } +static int +qla2x00_iospace_config(struct qla_hw_data *ha) +{ + resource_size_t pio; + uint16_t msix; + int cpus; + + if (IS_QLA82XX(ha)) + return qla82xx_iospace_config(ha); + + if (pci_request_selected_regions(ha->pdev, ha->bars, + QLA2XXX_DRIVER_NAME)) { + ql_log_pci(ql_log_fatal, ha->pdev, 0x0011, + "Failed to reserve PIO/MMIO regions (%s), aborting.\n", + pci_name(ha->pdev)); + goto iospace_error_exit; + } + if (!(ha->bars & 1)) + goto skip_pio; + + /* We only need PIO for Flash operations on ISP2312 v2 chips. */ + pio = pci_resource_start(ha->pdev, 0); + if (pci_resource_flags(ha->pdev, 0) & IORESOURCE_IO) { + if (pci_resource_len(ha->pdev, 0) < MIN_IOBASE_LEN) { + ql_log_pci(ql_log_warn, ha->pdev, 0x0012, + "Invalid pci I/O region size (%s).\n", + pci_name(ha->pdev)); + pio = 0; + } + } else { + ql_log_pci(ql_log_warn, ha->pdev, 0x0013, + "Region #0 no a PIO resource (%s).\n", + pci_name(ha->pdev)); + pio = 0; + } + ha->pio_address = pio; + ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0014, + "PIO address=%llu.\n", + (unsigned long long)ha->pio_address); + +skip_pio: + /* Use MMIO operations for all accesses. */ + if (!(pci_resource_flags(ha->pdev, 1) & IORESOURCE_MEM)) { + ql_log_pci(ql_log_fatal, ha->pdev, 0x0015, + "Region #1 not an MMIO resource (%s), aborting.\n", + pci_name(ha->pdev)); + goto iospace_error_exit; + } + if (pci_resource_len(ha->pdev, 1) < MIN_IOBASE_LEN) { + ql_log_pci(ql_log_fatal, ha->pdev, 0x0016, + "Invalid PCI mem region size (%s), aborting.\n", + pci_name(ha->pdev)); + goto iospace_error_exit; + } + + ha->iobase = ioremap(pci_resource_start(ha->pdev, 1), MIN_IOBASE_LEN); + if (!ha->iobase) { + ql_log_pci(ql_log_fatal, ha->pdev, 0x0017, + "Cannot remap MMIO (%s), aborting.\n", + pci_name(ha->pdev)); + goto iospace_error_exit; + } + + /* Determine queue resources */ + ha->max_req_queues = ha->max_rsp_queues = 1; + if ((ql2xmaxqueues <= 1 && !ql2xmultique_tag) || + (ql2xmaxqueues > 1 && ql2xmultique_tag) || + (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))) + goto mqiobase_exit; + + ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 3), + pci_resource_len(ha->pdev, 3)); + if (ha->mqiobase) { + ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0018, + "MQIO Base=%p.\n", ha->mqiobase); + /* Read MSIX vector size of the board */ + pci_read_config_word(ha->pdev, QLA_PCI_MSIX_CONTROL, &msix); + ha->msix_count = msix; + /* Max queues are bounded by available msix vectors */ + /* queue 0 uses two msix vectors */ + if (ql2xmultique_tag) { + cpus = num_online_cpus(); + ha->max_rsp_queues = (ha->msix_count - 1 > cpus) ? + (cpus + 1) : (ha->msix_count - 1); + ha->max_req_queues = 2; + } else if (ql2xmaxqueues > 1) { + ha->max_req_queues = ql2xmaxqueues > QLA_MQ_SIZE ? + QLA_MQ_SIZE : ql2xmaxqueues; + ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc008, + "QoS mode set, max no of request queues:%d.\n", + ha->max_req_queues); + ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0019, + "QoS mode set, max no of request queues:%d.\n", + ha->max_req_queues); + } + ql_log_pci(ql_log_info, ha->pdev, 0x001a, + "MSI-X vector count: %d.\n", msix); + } else + ql_log_pci(ql_log_info, ha->pdev, 0x001b, + "BAR 3 not enabled.\n"); + +mqiobase_exit: + ha->msix_count = ha->max_rsp_queues + 1; + ql_dbg_pci(ql_dbg_init, ha->pdev, 0x001c, + "MSIX Count:%d.\n", ha->msix_count); + return (0); + +iospace_error_exit: + return (-ENOMEM); +} + + static struct isp_operations qla2100_isp_ops = { .pci_config = qla2100_pci_config, .reset_chip = qla2x00_reset_chip, @@ -1591,6 +1627,7 @@ static struct isp_operations qla2100_isp_ops = { .get_flash_version = qla2x00_get_flash_version, .start_scsi = qla2x00_start_scsi, .abort_isp = qla2x00_abort_isp, + .iospace_config = qla2x00_iospace_config, }; static struct isp_operations qla2300_isp_ops = { @@ -1627,6 +1664,7 @@ static struct isp_operations qla2300_isp_ops = { .get_flash_version = qla2x00_get_flash_version, .start_scsi = qla2x00_start_scsi, .abort_isp = qla2x00_abort_isp, + .iospace_config = qla2x00_iospace_config, }; static struct isp_operations qla24xx_isp_ops = { @@ -1663,6 +1701,7 @@ static struct isp_operations qla24xx_isp_ops = { .get_flash_version = qla24xx_get_flash_version, .start_scsi = qla24xx_start_scsi, .abort_isp = qla2x00_abort_isp, + .iospace_config = qla2x00_iospace_config, }; static struct isp_operations qla25xx_isp_ops = { @@ -1699,6 +1738,7 @@ static struct isp_operations qla25xx_isp_ops = { .get_flash_version = qla24xx_get_flash_version, .start_scsi = qla24xx_dif_start_scsi, .abort_isp = qla2x00_abort_isp, + .iospace_config = qla2x00_iospace_config, }; static struct isp_operations qla81xx_isp_ops = { @@ -1735,6 +1775,7 @@ static struct isp_operations qla81xx_isp_ops = { .get_flash_version = qla24xx_get_flash_version, .start_scsi = qla24xx_dif_start_scsi, .abort_isp = qla2x00_abort_isp, + .iospace_config = qla2x00_iospace_config, }; static struct isp_operations qla82xx_isp_ops = { @@ -1771,6 +1812,7 @@ static struct isp_operations qla82xx_isp_ops = { .get_flash_version = qla24xx_get_flash_version, .start_scsi = qla82xx_start_scsi, .abort_isp = qla82xx_abort_isp, + .iospace_config = qla82xx_iospace_config, }; static inline void @@ -1880,121 +1922,10 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha) else ha->flags.port0 = 0; ql_dbg_pci(ql_dbg_init, ha->pdev, 0x000b, - "device_type=0x%x port=%d fw_srisc_address=%p.\n", + "device_type=0x%x port=%d fw_srisc_address=0x%x.\n", ha->device_type, ha->flags.port0, ha->fw_srisc_address); } -static int -qla2x00_iospace_config(struct qla_hw_data *ha) -{ - resource_size_t pio; - uint16_t msix; - int cpus; - - if (IS_QLA82XX(ha)) - return qla82xx_iospace_config(ha); - - if (pci_request_selected_regions(ha->pdev, ha->bars, - QLA2XXX_DRIVER_NAME)) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x0011, - "Failed to reserve PIO/MMIO regions (%s), aborting.\n", - pci_name(ha->pdev)); - goto iospace_error_exit; - } - if (!(ha->bars & 1)) - goto skip_pio; - - /* We only need PIO for Flash operations on ISP2312 v2 chips. */ - pio = pci_resource_start(ha->pdev, 0); - if (pci_resource_flags(ha->pdev, 0) & IORESOURCE_IO) { - if (pci_resource_len(ha->pdev, 0) < MIN_IOBASE_LEN) { - ql_log_pci(ql_log_warn, ha->pdev, 0x0012, - "Invalid pci I/O region size (%s).\n", - pci_name(ha->pdev)); - pio = 0; - } - } else { - ql_log_pci(ql_log_warn, ha->pdev, 0x0013, - "Region #0 no a PIO resource (%s).\n", - pci_name(ha->pdev)); - pio = 0; - } - ha->pio_address = pio; - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0014, - "PIO address=%p.\n", - ha->pio_address); - -skip_pio: - /* Use MMIO operations for all accesses. */ - if (!(pci_resource_flags(ha->pdev, 1) & IORESOURCE_MEM)) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x0015, - "Region #1 not an MMIO resource (%s), aborting.\n", - pci_name(ha->pdev)); - goto iospace_error_exit; - } - if (pci_resource_len(ha->pdev, 1) < MIN_IOBASE_LEN) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x0016, - "Invalid PCI mem region size (%s), aborting.\n", - pci_name(ha->pdev)); - goto iospace_error_exit; - } - - ha->iobase = ioremap(pci_resource_start(ha->pdev, 1), MIN_IOBASE_LEN); - if (!ha->iobase) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x0017, - "Cannot remap MMIO (%s), aborting.\n", - pci_name(ha->pdev)); - goto iospace_error_exit; - } - - /* Determine queue resources */ - ha->max_req_queues = ha->max_rsp_queues = 1; - if ((ql2xmaxqueues <= 1 && !ql2xmultique_tag) || - (ql2xmaxqueues > 1 && ql2xmultique_tag) || - (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))) - goto mqiobase_exit; - - ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 3), - pci_resource_len(ha->pdev, 3)); - if (ha->mqiobase) { - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0018, - "MQIO Base=%p.\n", ha->mqiobase); - /* Read MSIX vector size of the board */ - pci_read_config_word(ha->pdev, QLA_PCI_MSIX_CONTROL, &msix); - ha->msix_count = msix; - /* Max queues are bounded by available msix vectors */ - /* queue 0 uses two msix vectors */ - if (ql2xmultique_tag) { - cpus = num_online_cpus(); - ha->max_rsp_queues = (ha->msix_count - 1 > cpus) ? - (cpus + 1) : (ha->msix_count - 1); - ha->max_req_queues = 2; - } else if (ql2xmaxqueues > 1) { - ha->max_req_queues = ql2xmaxqueues > QLA_MQ_SIZE ? - QLA_MQ_SIZE : ql2xmaxqueues; - ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc008, - "QoS mode set, max no of request queues:%d.\n", - ha->max_req_queues); - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0019, - "QoS mode set, max no of request queues:%d.\n", - ha->max_req_queues); - } - ql_log_pci(ql_log_info, ha->pdev, 0x001a, - "MSI-X vector count: %d.\n", msix); - } else - ql_log_pci(ql_log_info, ha->pdev, 0x001b, - "BAR 3 not enabled.\n"); - -mqiobase_exit: - ha->msix_count = ha->max_rsp_queues + 1; - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x001c, - "MSIX Count:%d.\n", ha->msix_count); - return (0); - -iospace_error_exit: - return (-ENOMEM); -} - static void qla2xxx_scan_start(struct Scsi_Host *shost) { @@ -2093,14 +2024,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) pdev->needs_freset = 1; } - /* Configure PCI I/O space */ - ret = qla2x00_iospace_config(ha); - if (ret) - goto probe_hw_failed; - - ql_log_pci(ql_log_info, pdev, 0x001d, - "Found an ISP%04X irq %d iobase 0x%p.\n", - pdev->device, pdev->irq, ha->iobase); ha->prev_topology = 0; ha->init_cb_size = sizeof(init_cb_t); ha->link_data_rate = PORT_SPEED_UNKNOWN; @@ -2121,7 +2044,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->nvram_data_off = ~0; ha->isp_ops = &qla2100_isp_ops; } else if (IS_QLA2200(ha)) { - ha->mbx_count = MAILBOX_REGISTER_COUNT; + ha->mbx_count = MAILBOX_REGISTER_COUNT_2200; req_length = REQUEST_ENTRY_CNT_2200; rsp_length = RESPONSE_ENTRY_CNT_2100; ha->max_loop_id = SNS_LAST_LOOP_ID_2100; @@ -2213,6 +2136,15 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) "flash_data_off=%d, nvram_conf_off=%d, nvram_data_off=%d.\n", ha->isp_ops, ha->flash_conf_off, ha->flash_data_off, ha->nvram_conf_off, ha->nvram_data_off); + + /* Configure PCI I/O space */ + ret = ha->isp_ops->iospace_config(ha); + if (ret) + goto probe_hw_failed; + + ql_log_pci(ql_log_info, pdev, 0x001d, + "Found an ISP%04X irq %d iobase 0x%p.\n", + pdev->device, pdev->irq, ha->iobase); mutex_init(&ha->vport_lock); init_completion(&ha->mbx_cmd_comp); complete(&ha->mbx_cmd_comp); @@ -2288,7 +2220,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ql_dbg(ql_dbg_init, base_vha, 0x0033, "max_id=%d this_id=%d " "cmd_per_len=%d unique_id=%d max_cmd_len=%d max_channel=%d " - "max_lun=%d transportt=%p, vendor_id=%d.\n", host->max_id, + "max_lun=%d transportt=%p, vendor_id=%llu.\n", host->max_id, host->this_id, host->cmd_per_lun, host->unique_id, host->max_cmd_len, host->max_channel, host->max_lun, host->transportt, sht->vendor_id); @@ -2443,9 +2375,6 @@ skip_dpc: qla2x00_dfs_setup(base_vha); - ql_log(ql_log_info, base_vha, 0x00fa, - "QLogic Fibre Channed HBA Driver: %s.\n", - qla2x00_version_str); ql_log(ql_log_info, base_vha, 0x00fb, "QLogic %s - %s.\n", ha->model_number, ha->model_desc ? ha->model_desc : ""); @@ -2894,7 +2823,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, if (!ha->sns_cmd) goto fail_dma_pool; ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0026, - "sns_cmd.\n", ha->sns_cmd); + "sns_cmd: %p.\n", ha->sns_cmd); } else { /* Get consistent memory allocated for MS IOCB */ ha->ms_iocb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, @@ -3521,27 +3450,21 @@ qla2x00_do_dpc(void *data) schedule(); __set_current_state(TASK_RUNNING); - ql_dbg(ql_dbg_dpc, base_vha, 0x4001, - "DPC handler waking up.\n"); - ql_dbg(ql_dbg_dpc, base_vha, 0x4002, - "dpc_flags=0x%lx.\n", base_vha->dpc_flags); - - /* Initialization not yet finished. Don't do anything yet. */ - if (!base_vha->flags.init_done) - continue; + if (!base_vha->flags.init_done || ha->flags.mbox_busy) + goto end_loop; if (ha->flags.eeh_busy) { ql_dbg(ql_dbg_dpc, base_vha, 0x4003, "eeh_busy=%d.\n", ha->flags.eeh_busy); - continue; + goto end_loop; } ha->dpc_active = 1; - if (ha->flags.mbox_busy) { - ha->dpc_active = 0; - continue; - } + ql_dbg(ql_dbg_dpc, base_vha, 0x4001, + "DPC handler waking up.\n"); + ql_dbg(ql_dbg_dpc, base_vha, 0x4002, + "dpc_flags=0x%lx.\n", base_vha->dpc_flags); qla2x00_do_work(base_vha); @@ -3683,6 +3606,7 @@ qla2x00_do_dpc(void *data) qla2x00_do_dpc_all_vps(base_vha); ha->dpc_active = 0; +end_loop: set_current_state(TASK_INTERRUPTIBLE); } /* End of while(1) */ __set_current_state(TASK_RUNNING); @@ -3766,16 +3690,6 @@ qla2x00_sp_free_dma(srb_t *sp) sp->flags &= ~SRB_CRC_CTX_DMA_VALID; } - CMD_SP(cmd) = NULL; -} - -static void -qla2x00_sp_final_compl(struct qla_hw_data *ha, srb_t *sp) -{ - struct scsi_cmnd *cmd = sp->cmd; - - qla2x00_sp_free_dma(sp); - if (sp->flags & SRB_FCP_CMND_DMA_VALID) { struct ct6_dsd *ctx = sp->ctx; dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd, @@ -3787,6 +3701,15 @@ qla2x00_sp_final_compl(struct qla_hw_data *ha, srb_t *sp) sp->ctx = NULL; } + CMD_SP(cmd) = NULL; +} + +static void +qla2x00_sp_final_compl(struct qla_hw_data *ha, srb_t *sp) +{ + struct scsi_cmnd *cmd = sp->cmd; + + qla2x00_sp_free_dma(sp); mempool_free(sp, ha->srb_mempool); cmd->scsi_done(cmd); } @@ -4070,13 +3993,8 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) /* For ISP82XX complete any pending mailbox cmd */ if (IS_QLA82XX(ha)) { ha->flags.isp82xx_fw_hung = 1; - if (ha->flags.mbox_busy) { - ha->flags.mbox_int = 1; - ql_dbg(ql_dbg_aer, vha, 0x9001, - "Due to pci channel io frozen, doing premature " - "completion of mbx command.\n"); - complete(&ha->mbx_intr_comp); - } + ql_dbg(ql_dbg_aer, vha, 0x9001, "Pci channel io frozen\n"); + qla82xx_clear_pending_mbx(vha); } qla2x00_free_irqs(vha); pci_disable_device(pdev); diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index eff13563c82..16bc72844a9 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -904,8 +904,9 @@ no_flash_data: } done: ql_dbg(ql_dbg_init, vha, 0x004d, - "FDT[%x]: (0x%x/0x%x) erase=0x%x " - "pr=%x upro=%x wrtd=0x%x blk=0x%x.\n", loc, mid, fid, + "FDT[%s]: (0x%x/0x%x) erase=0x%x " + "pr=%x wrtd=0x%x blk=0x%x.\n", + loc, mid, fid, ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd, ha->fdt_wrt_disable, ha->fdt_block_size); diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 13b6357c1fa..29d780c3804 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.03.07.07-k" +#define QLA2XXX_VERSION "8.03.07.13-k" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 3 diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c index af62c3cf875..8d58ae27482 100644 --- a/drivers/scsi/qla4xxx/ql4_dbg.c +++ b/drivers/scsi/qla4xxx/ql4_dbg.c @@ -20,12 +20,12 @@ void qla4xxx_dump_buffer(void *b, uint32_t size) printk("------------------------------------------------------------" "--\n"); for (cnt = 0; cnt < size; c++) { - printk(KERN_INFO "%02x", *c); + printk("%02x", *c); if (!(++cnt % 16)) - printk(KERN_INFO "\n"); + printk("\n"); else - printk(KERN_INFO " "); + printk(" "); } printk(KERN_INFO "\n"); } diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index ace637bf254..bfe68545203 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -147,9 +147,11 @@ #define ISCSI_ALIAS_SIZE 32 /* ISCSI Alias name size */ #define ISCSI_NAME_SIZE 0xE0 /* ISCSI Name size */ -#define QL4_SESS_RECOVERY_TMO 30 /* iSCSI session */ +#define QL4_SESS_RECOVERY_TMO 120 /* iSCSI session */ /* recovery timeout */ +#define MSB(x) ((uint8_t)((uint16_t)(x) >> 8)) +#define LSW(x) ((uint16_t)(x)) #define LSDW(x) ((u32)((u64)(x))) #define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16)) @@ -173,8 +175,11 @@ #define ISNS_DEREG_TOV 5 #define HBA_ONLINE_TOV 30 #define DISABLE_ACB_TOV 30 +#define IP_CONFIG_TOV 30 +#define LOGIN_TOV 12 #define MAX_RESET_HA_RETRIES 2 +#define FW_ALIVE_WAIT_TOV 3 #define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr) @@ -240,6 +245,45 @@ struct ddb_entry { uint16_t fw_ddb_index; /* DDB firmware index */ uint32_t fw_ddb_device_state; /* F/W Device State -- see ql4_fw.h */ + uint16_t ddb_type; +#define FLASH_DDB 0x01 + + struct dev_db_entry fw_ddb_entry; + int (*unblock_sess)(struct iscsi_cls_session *cls_session); + int (*ddb_change)(struct scsi_qla_host *ha, uint32_t fw_ddb_index, + struct ddb_entry *ddb_entry, uint32_t state); + + /* Driver Re-login */ + unsigned long flags; /* DDB Flags */ + uint16_t default_relogin_timeout; /* Max time to wait for + * relogin to complete */ + atomic_t retry_relogin_timer; /* Min Time between relogins + * (4000 only) */ + atomic_t relogin_timer; /* Max Time to wait for + * relogin to complete */ + atomic_t relogin_retry_count; /* Num of times relogin has been + * retried */ + uint32_t default_time2wait; /* Default Min time between + * relogins (+aens) */ + +}; + +struct qla_ddb_index { + struct list_head list; + uint16_t fw_ddb_idx; + struct dev_db_entry fw_ddb; +}; + +#define DDB_IPADDR_LEN 64 + +struct ql4_tuple_ddb { + int port; + int tpgt; + char ip_addr[DDB_IPADDR_LEN]; + char iscsi_name[ISCSI_NAME_SIZE]; + uint16_t options; +#define DDB_OPT_IPV6 0x0e0e +#define DDB_OPT_IPV4 0x0f0f }; /* @@ -411,7 +455,7 @@ struct scsi_qla_host { #define AF_FW_RECOVERY 19 /* 0x00080000 */ #define AF_EEH_BUSY 20 /* 0x00100000 */ #define AF_PCI_CHANNEL_IO_PERM_FAILURE 21 /* 0x00200000 */ - +#define AF_BUILD_DDB_LIST 22 /* 0x00400000 */ unsigned long dpc_flags; #define DPC_RESET_HA 1 /* 0x00000002 */ @@ -604,6 +648,7 @@ struct scsi_qla_host { uint16_t bootload_minor; uint16_t bootload_patch; uint16_t bootload_build; + uint16_t def_timeout; /* Default login timeout */ uint32_t flash_state; #define QLFLASH_WAITING 0 @@ -623,6 +668,12 @@ struct scsi_qla_host { uint16_t iscsi_pci_func_cnt; uint8_t model_name[16]; struct completion disable_acb_comp; + struct dma_pool *fw_ddb_dma_pool; +#define DDB_DMA_BLOCK_SIZE 512 + uint16_t pri_ddb_idx; + uint16_t sec_ddb_idx; + int is_reset; + uint16_t temperature; }; struct ql4_task_data { @@ -835,6 +886,10 @@ static inline int ql4xxx_reset_active(struct scsi_qla_host *ha) /*---------------------------------------------------------------------------*/ /* Defines for qla4xxx_initialize_adapter() and qla4xxx_recover_adapter() */ + +#define INIT_ADAPTER 0 +#define RESET_ADAPTER 1 + #define PRESERVE_DDB_LIST 0 #define REBUILD_DDB_LIST 1 diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index cbd5a20dbbd..7825c141bc1 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h @@ -12,6 +12,7 @@ #define MAX_PRST_DEV_DB_ENTRIES 64 #define MIN_DISC_DEV_DB_ENTRY MAX_PRST_DEV_DB_ENTRIES #define MAX_DEV_DB_ENTRIES 512 +#define MAX_DEV_DB_ENTRIES_40XX 256 /************************************************************************* * @@ -604,6 +605,13 @@ struct addr_ctrl_blk { uint8_t res14[140]; /* 274-2FF */ }; +#define IP_ADDR_COUNT 4 /* Total 4 IP address supported in one interface + * One IPv4, one IPv6 link local and 2 IPv6 + */ + +#define IP_STATE_MASK 0x0F000000 +#define IP_STATE_SHIFT 24 + struct init_fw_ctrl_blk { struct addr_ctrl_blk pri; /* struct addr_ctrl_blk sec;*/ @@ -744,7 +752,7 @@ struct dev_db_entry { uint8_t res4[0x36]; /* 8A-BF */ uint8_t iscsi_name[0xE0]; /* C0-19F : xxzzy Make this a * pointer to a string so we - * don't have to reserve soooo + * don't have to reserve so * much RAM */ uint8_t link_local_ipv6_addr[0x10]; /* 1A0-1AF */ uint8_t res5[0x10]; /* 1B0-1BF */ diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 160db9d5ea2..d0dd4b33020 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -13,7 +13,7 @@ struct iscsi_cls_conn; int qla4xxx_hw_reset(struct scsi_qla_host *ha); int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a); int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb *srb); -int qla4xxx_initialize_adapter(struct scsi_qla_host *ha); +int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset); int qla4xxx_soft_reset(struct scsi_qla_host *ha); irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id); @@ -153,10 +153,13 @@ int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t fw_ddb_index, uint32_t *mbx_sts); int qla4xxx_clear_ddb_entry(struct scsi_qla_host *ha, uint32_t fw_ddb_index); int qla4xxx_send_passthru0(struct iscsi_task *task); +void qla4xxx_free_ddb_index(struct scsi_qla_host *ha); int qla4xxx_get_mgmt_data(struct scsi_qla_host *ha, uint16_t fw_ddb_index, uint16_t stats_size, dma_addr_t stats_dma); void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry); +void qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry); int qla4xxx_bootdb_by_index(struct scsi_qla_host *ha, struct dev_db_entry *fw_ddb_entry, dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index); @@ -169,11 +172,22 @@ int qla4xxx_set_nvram(struct scsi_qla_host *ha, dma_addr_t nvram_dma, int qla4xxx_restore_factory_defaults(struct scsi_qla_host *ha, uint32_t region, uint32_t field0, uint32_t field1); +int qla4xxx_get_ddb_index(struct scsi_qla_host *ha, uint16_t *ddb_index); +void qla4xxx_login_flash_ddb(struct iscsi_cls_session *cls_session); +int qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session); +int qla4xxx_unblock_flash_ddb(struct iscsi_cls_session *cls_session); +int qla4xxx_flash_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, + struct ddb_entry *ddb_entry, uint32_t state); +int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, + struct ddb_entry *ddb_entry, uint32_t state); +void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset); /* BSG Functions */ int qla4xxx_bsg_request(struct bsg_job *bsg_job); int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job); +void qla4xxx_arm_relogin_timer(struct ddb_entry *ddb_entry); + extern int ql4xextended_error_logging; extern int ql4xdontresethba; extern int ql4xenablemsix; diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 3075fbaef55..90614f38b55 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -697,6 +697,9 @@ int qla4xxx_start_firmware(struct scsi_qla_host *ha) writel(set_rmask(CSR_SCSI_PROCESSOR_INTR), &ha->reg->ctrl_status); readl(&ha->reg->ctrl_status); + writel(set_rmask(CSR_SCSI_COMPLETION_INTR), + &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS) { DEBUG2(printk("scsi%ld: %s: Get firmware " @@ -773,22 +776,24 @@ int qla4xxx_start_firmware(struct scsi_qla_host *ha) * be freed so that when login happens from user space there are free DDB * indices available. **/ -static void qla4xxx_free_ddb_index(struct scsi_qla_host *ha) +void qla4xxx_free_ddb_index(struct scsi_qla_host *ha) { int max_ddbs; int ret; uint32_t idx = 0, next_idx = 0; uint32_t state = 0, conn_err = 0; - max_ddbs = is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES : + max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : MAX_DEV_DB_ENTRIES; for (idx = 0; idx < max_ddbs; idx = next_idx) { ret = qla4xxx_get_fwddb_entry(ha, idx, NULL, 0, NULL, &next_idx, &state, &conn_err, NULL, NULL); - if (ret == QLA_ERROR) + if (ret == QLA_ERROR) { + next_idx++; continue; + } if (state == DDB_DS_NO_CONNECTION_ACTIVE || state == DDB_DS_SESSION_FAILED) { DEBUG2(ql4_printk(KERN_INFO, ha, @@ -804,7 +809,6 @@ static void qla4xxx_free_ddb_index(struct scsi_qla_host *ha) } } - /** * qla4xxx_initialize_adapter - initiailizes hba * @ha: Pointer to host adapter structure. @@ -812,7 +816,7 @@ static void qla4xxx_free_ddb_index(struct scsi_qla_host *ha) * This routine parforms all of the steps necessary to initialize the adapter. * **/ -int qla4xxx_initialize_adapter(struct scsi_qla_host *ha) +int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset) { int status = QLA_ERROR; @@ -840,7 +844,8 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha) if (status == QLA_ERROR) goto exit_init_hba; - qla4xxx_free_ddb_index(ha); + if (is_reset == RESET_ADAPTER) + qla4xxx_build_ddb_list(ha, is_reset); set_bit(AF_ONLINE, &ha->flags); exit_init_hba: @@ -855,38 +860,12 @@ exit_init_hba: return status; } -/** - * qla4xxx_process_ddb_changed - process ddb state change - * @ha - Pointer to host adapter structure. - * @fw_ddb_index - Firmware's device database index - * @state - Device state - * - * This routine processes a Decive Database Changed AEN Event. - **/ -int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, - uint32_t state, uint32_t conn_err) +int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, + struct ddb_entry *ddb_entry, uint32_t state) { - struct ddb_entry * ddb_entry; uint32_t old_fw_ddb_device_state; int status = QLA_ERROR; - /* check for out of range index */ - if (fw_ddb_index >= MAX_DDB_ENTRIES) - goto exit_ddb_event; - - /* Get the corresponging ddb entry */ - ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index); - /* Device does not currently exist in our database. */ - if (ddb_entry == NULL) { - ql4_printk(KERN_ERR, ha, "%s: No ddb_entry at FW index [%d]\n", - __func__, fw_ddb_index); - - if (state == DDB_DS_NO_CONNECTION_ACTIVE) - clear_bit(fw_ddb_index, ha->ddb_idx_map); - - goto exit_ddb_event; - } - old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; DEBUG2(ql4_printk(KERN_INFO, ha, "%s: DDB - old state = 0x%x, new state = 0x%x for " @@ -900,9 +879,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, switch (state) { case DDB_DS_SESSION_ACTIVE: case DDB_DS_DISCOVERY: - iscsi_conn_start(ddb_entry->conn); - iscsi_conn_login_event(ddb_entry->conn, - ISCSI_CONN_STATE_LOGGED_IN); + ddb_entry->unblock_sess(ddb_entry->sess); qla4xxx_update_session_conn_param(ha, ddb_entry); status = QLA_SUCCESS; break; @@ -936,9 +913,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, switch (state) { case DDB_DS_SESSION_ACTIVE: case DDB_DS_DISCOVERY: - iscsi_conn_start(ddb_entry->conn); - iscsi_conn_login_event(ddb_entry->conn, - ISCSI_CONN_STATE_LOGGED_IN); + ddb_entry->unblock_sess(ddb_entry->sess); qla4xxx_update_session_conn_param(ha, ddb_entry); status = QLA_SUCCESS; break; @@ -954,7 +929,198 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, __func__)); break; } + return status; +} + +void qla4xxx_arm_relogin_timer(struct ddb_entry *ddb_entry) +{ + /* + * This triggers a relogin. After the relogin_timer + * expires, the relogin gets scheduled. We must wait a + * minimum amount of time since receiving an 0x8014 AEN + * with failed device_state or a logout response before + * we can issue another relogin. + * + * Firmware pads this timeout: (time2wait +1). + * Driver retry to login should be longer than F/W. + * Otherwise F/W will fail + * set_ddb() mbx cmd with 0x4005 since it still + * counting down its time2wait. + */ + atomic_set(&ddb_entry->relogin_timer, 0); + atomic_set(&ddb_entry->retry_relogin_timer, + ddb_entry->default_time2wait + 4); + +} + +int qla4xxx_flash_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, + struct ddb_entry *ddb_entry, uint32_t state) +{ + uint32_t old_fw_ddb_device_state; + int status = QLA_ERROR; + + old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s: DDB - old state = 0x%x, new state = 0x%x for " + "index [%d]\n", __func__, + ddb_entry->fw_ddb_device_state, state, fw_ddb_index)); + + ddb_entry->fw_ddb_device_state = state; + + switch (old_fw_ddb_device_state) { + case DDB_DS_LOGIN_IN_PROCESS: + case DDB_DS_NO_CONNECTION_ACTIVE: + switch (state) { + case DDB_DS_SESSION_ACTIVE: + ddb_entry->unblock_sess(ddb_entry->sess); + qla4xxx_update_session_conn_fwddb_param(ha, ddb_entry); + status = QLA_SUCCESS; + break; + case DDB_DS_SESSION_FAILED: + iscsi_block_session(ddb_entry->sess); + if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) + qla4xxx_arm_relogin_timer(ddb_entry); + status = QLA_SUCCESS; + break; + } + break; + case DDB_DS_SESSION_ACTIVE: + switch (state) { + case DDB_DS_SESSION_FAILED: + iscsi_block_session(ddb_entry->sess); + if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) + qla4xxx_arm_relogin_timer(ddb_entry); + status = QLA_SUCCESS; + break; + } + break; + case DDB_DS_SESSION_FAILED: + switch (state) { + case DDB_DS_SESSION_ACTIVE: + ddb_entry->unblock_sess(ddb_entry->sess); + qla4xxx_update_session_conn_fwddb_param(ha, ddb_entry); + status = QLA_SUCCESS; + break; + case DDB_DS_SESSION_FAILED: + if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) + qla4xxx_arm_relogin_timer(ddb_entry); + status = QLA_SUCCESS; + break; + } + break; + default: + DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Unknown Event\n", + __func__)); + break; + } + return status; +} + +/** + * qla4xxx_process_ddb_changed - process ddb state change + * @ha - Pointer to host adapter structure. + * @fw_ddb_index - Firmware's device database index + * @state - Device state + * + * This routine processes a Decive Database Changed AEN Event. + **/ +int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, + uint32_t fw_ddb_index, + uint32_t state, uint32_t conn_err) +{ + struct ddb_entry *ddb_entry; + int status = QLA_ERROR; + + /* check for out of range index */ + if (fw_ddb_index >= MAX_DDB_ENTRIES) + goto exit_ddb_event; + + /* Get the corresponging ddb entry */ + ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index); + /* Device does not currently exist in our database. */ + if (ddb_entry == NULL) { + ql4_printk(KERN_ERR, ha, "%s: No ddb_entry at FW index [%d]\n", + __func__, fw_ddb_index); + + if (state == DDB_DS_NO_CONNECTION_ACTIVE) + clear_bit(fw_ddb_index, ha->ddb_idx_map); + + goto exit_ddb_event; + } + + ddb_entry->ddb_change(ha, fw_ddb_index, ddb_entry, state); exit_ddb_event: return status; } + +/** + * qla4xxx_login_flash_ddb - Login to target (DDB) + * @cls_session: Pointer to the session to login + * + * This routine logins to the target. + * Issues setddb and conn open mbx + **/ +void qla4xxx_login_flash_ddb(struct iscsi_cls_session *cls_session) +{ + struct iscsi_session *sess; + struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha; + struct dev_db_entry *fw_ddb_entry = NULL; + dma_addr_t fw_ddb_dma; + uint32_t mbx_sts = 0; + int ret; + + sess = cls_session->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + + if (!test_bit(AF_LINK_UP, &ha->flags)) + return; + + if (ddb_entry->ddb_type != FLASH_DDB) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "Skipping login to non FLASH DB")); + goto exit_login; + } + + fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, + &fw_ddb_dma); + if (fw_ddb_entry == NULL) { + DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); + goto exit_login; + } + + if (ddb_entry->fw_ddb_index == INVALID_ENTRY) { + ret = qla4xxx_get_ddb_index(ha, &ddb_entry->fw_ddb_index); + if (ret == QLA_ERROR) + goto exit_login; + + ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry; + ha->tot_ddbs++; + } + + memcpy(fw_ddb_entry, &ddb_entry->fw_ddb_entry, + sizeof(struct dev_db_entry)); + ddb_entry->sess->target_id = ddb_entry->fw_ddb_index; + + ret = qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index, + fw_ddb_dma, &mbx_sts); + if (ret == QLA_ERROR) { + DEBUG2(ql4_printk(KERN_ERR, ha, "Set DDB failed\n")); + goto exit_login; + } + + ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS; + ret = qla4xxx_conn_open(ha, ddb_entry->fw_ddb_index); + if (ret == QLA_ERROR) { + ql4_printk(KERN_ERR, ha, "%s: Login failed: %s\n", __func__, + sess->targetname); + goto exit_login; + } + +exit_login: + if (fw_ddb_entry) + dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); +} + diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index 827e93078b9..95828862eea 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -123,13 +123,13 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle)); if (!srb) { - DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Status Entry invalid " - "handle 0x%x, sp=%p. This cmd may have already " - "been completed.\n", ha->host_no, __func__, - le32_to_cpu(sts_entry->handle), srb)); - ql4_printk(KERN_WARNING, ha, "%s invalid status entry:" - " handle=0x%0x\n", __func__, sts_entry->handle); - set_bit(DPC_RESET_HA, &ha->dpc_flags); + ql4_printk(KERN_WARNING, ha, "%s invalid status entry: " + "handle=0x%0x, srb=%p\n", __func__, + sts_entry->handle, srb); + if (is_qla8022(ha)) + set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); + else + set_bit(DPC_RESET_HA, &ha->dpc_flags); return; } @@ -563,7 +563,11 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, case MBOX_ASTS_DHCP_LEASE_EXPIRED: DEBUG2(printk("scsi%ld: AEN %04x, ERROR Status, " "Reset HA\n", ha->host_no, mbox_status)); - set_bit(DPC_RESET_HA, &ha->dpc_flags); + if (is_qla8022(ha)) + set_bit(DPC_RESET_HA_FW_CONTEXT, + &ha->dpc_flags); + else + set_bit(DPC_RESET_HA, &ha->dpc_flags); break; case MBOX_ASTS_LINK_UP: @@ -617,9 +621,13 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, (mbox_sts[2] == ACB_STATE_ACQUIRING))) set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags); else if ((mbox_sts[3] == ACB_STATE_ACQUIRING) && - (mbox_sts[2] == ACB_STATE_VALID)) - set_bit(DPC_RESET_HA, &ha->dpc_flags); - else if ((mbox_sts[3] == ACB_STATE_UNCONFIGURED)) + (mbox_sts[2] == ACB_STATE_VALID)) { + if (is_qla8022(ha)) + set_bit(DPC_RESET_HA_FW_CONTEXT, + &ha->dpc_flags); + else + set_bit(DPC_RESET_HA, &ha->dpc_flags); + } else if ((mbox_sts[3] == ACB_STATE_UNCONFIGURED)) complete(&ha->disable_acb_comp); break; diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 4c2b8487039..e1e66a45e4d 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -41,6 +41,16 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, return status; } + if (is_qla40XX(ha)) { + if (test_bit(AF_HA_REMOVAL, &ha->flags)) { + DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: " + "prematurely completing mbx cmd as " + "adapter removal detected\n", + ha->host_no, __func__)); + return status; + } + } + if (is_qla8022(ha)) { if (test_bit(AF_FW_RECOVERY, &ha->flags)) { DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: " @@ -209,6 +219,13 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, ha->mailbox_timeout_count++; mbx_sts[0] = (-1); set_bit(DPC_RESET_HA, &ha->dpc_flags); + if (is_qla8022(ha)) { + ql4_printk(KERN_INFO, ha, + "disabling pause transmit on port 0 & 1.\n"); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, + CRB_NIU_XG_PAUSE_CTL_P0 | + CRB_NIU_XG_PAUSE_CTL_P1); + } goto mbox_exit; } @@ -413,6 +430,7 @@ qla4xxx_update_local_ifcb(struct scsi_qla_host *ha, memcpy(ha->name_string, init_fw_cb->iscsi_name, min(sizeof(ha->name_string), sizeof(init_fw_cb->iscsi_name))); + ha->def_timeout = le16_to_cpu(init_fw_cb->def_timeout); /*memcpy(ha->alias, init_fw_cb->Alias, min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/ diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index f484ff43819..65253dfbe96 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -10,6 +10,8 @@ #include "ql4_def.h" #include "ql4_glbl.h" +#include <asm-generic/io-64-nonatomic-lo-hi.h> + #define MASK(n) DMA_BIT_MASK(n) #define MN_WIN(addr) (((addr & 0x1fc0000) >> 1) | ((addr >> 25) & 0x3ff)) #define OCM_WIN(addr) (((addr & 0x1ff0000) >> 1) | ((addr >> 25) & 0x3ff)) @@ -655,27 +657,6 @@ static int qla4_8xxx_pci_is_same_window(struct scsi_qla_host *ha, return 0; } -#ifndef readq -static inline __u64 readq(const volatile void __iomem *addr) -{ - const volatile u32 __iomem *p = addr; - u32 low, high; - - low = readl(p); - high = readl(p + 1); - - return low + ((u64)high << 32); -} -#endif - -#ifndef writeq -static inline void writeq(__u64 val, volatile void __iomem *addr) -{ - writel(val, addr); - writel(val >> 32, addr+4); -} -#endif - static int qla4_8xxx_pci_mem_read_direct(struct scsi_qla_host *ha, u64 off, void *data, int size) { @@ -1792,8 +1773,11 @@ int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha) int rval = QLA_SUCCESS; unsigned long dev_init_timeout; - if (!test_bit(AF_INIT_DONE, &ha->flags)) + if (!test_bit(AF_INIT_DONE, &ha->flags)) { + qla4_8xxx_idc_lock(ha); qla4_8xxx_set_drv_active(ha); + qla4_8xxx_idc_unlock(ha); + } dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); ql4_printk(KERN_INFO, ha, "1:Device state is 0x%x = %s\n", dev_state, @@ -1802,8 +1786,8 @@ int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha) /* wait for 30 seconds for device to go ready */ dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ); + qla4_8xxx_idc_lock(ha); while (1) { - qla4_8xxx_idc_lock(ha); if (time_after_eq(jiffies, dev_init_timeout)) { ql4_printk(KERN_WARNING, ha, "Device init failed!\n"); @@ -1819,15 +1803,14 @@ int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha) /* NOTE: Make sure idc unlocked upon exit of switch statement */ switch (dev_state) { case QLA82XX_DEV_READY: - qla4_8xxx_idc_unlock(ha); goto exit; case QLA82XX_DEV_COLD: rval = qla4_8xxx_device_bootstrap(ha); - qla4_8xxx_idc_unlock(ha); goto exit; case QLA82XX_DEV_INITIALIZING: qla4_8xxx_idc_unlock(ha); msleep(1000); + qla4_8xxx_idc_lock(ha); break; case QLA82XX_DEV_NEED_RESET: if (!ql4xdontresethba) { @@ -1836,38 +1819,48 @@ int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha) * reset handler */ dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ); + } else { + qla4_8xxx_idc_unlock(ha); + msleep(1000); + qla4_8xxx_idc_lock(ha); } - qla4_8xxx_idc_unlock(ha); break; case QLA82XX_DEV_NEED_QUIESCENT: - qla4_8xxx_idc_unlock(ha); /* idc locked/unlocked in handler */ qla4_8xxx_need_qsnt_handler(ha); - qla4_8xxx_idc_lock(ha); - /* fall thru needs idc_locked */ + break; case QLA82XX_DEV_QUIESCENT: qla4_8xxx_idc_unlock(ha); msleep(1000); + qla4_8xxx_idc_lock(ha); break; case QLA82XX_DEV_FAILED: qla4_8xxx_idc_unlock(ha); qla4xxx_dead_adapter_cleanup(ha); rval = QLA_ERROR; + qla4_8xxx_idc_lock(ha); goto exit; default: qla4_8xxx_idc_unlock(ha); qla4xxx_dead_adapter_cleanup(ha); rval = QLA_ERROR; + qla4_8xxx_idc_lock(ha); goto exit; } } exit: + qla4_8xxx_idc_unlock(ha); return rval; } int qla4_8xxx_load_risc(struct scsi_qla_host *ha) { int retval; + + /* clear the interrupt */ + writel(0, &ha->qla4_8xxx_reg->host_int); + readl(&ha->qla4_8xxx_reg->host_int); + retval = qla4_8xxx_device_state_handler(ha); if (retval == QLA_SUCCESS && !test_bit(AF_INIT_DONE, &ha->flags)) diff --git a/drivers/scsi/qla4xxx/ql4_nx.h b/drivers/scsi/qla4xxx/ql4_nx.h index 35376a1c3f1..dc45ac92369 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.h +++ b/drivers/scsi/qla4xxx/ql4_nx.h @@ -19,12 +19,28 @@ #define PHAN_PEG_RCV_INITIALIZED 0xff01 /*CRB_RELATED*/ -#define QLA82XX_CRB_BASE QLA82XX_CAM_RAM(0x200) -#define QLA82XX_REG(X) (QLA82XX_CRB_BASE+(X)) - +#define QLA82XX_CRB_BASE (QLA82XX_CAM_RAM(0x200)) +#define QLA82XX_REG(X) (QLA82XX_CRB_BASE+(X)) #define CRB_CMDPEG_STATE QLA82XX_REG(0x50) #define CRB_RCVPEG_STATE QLA82XX_REG(0x13c) #define CRB_DMA_SHIFT QLA82XX_REG(0xcc) +#define CRB_TEMP_STATE QLA82XX_REG(0x1b4) + +#define qla82xx_get_temp_val(x) ((x) >> 16) +#define qla82xx_get_temp_state(x) ((x) & 0xffff) +#define qla82xx_encode_temp(val, state) (((val) << 16) | (state)) + +/* + * Temperature control. + */ +enum { + QLA82XX_TEMP_NORMAL = 0x1, /* Normal operating range */ + QLA82XX_TEMP_WARN, /* Sound alert, temperature getting high */ + QLA82XX_TEMP_PANIC /* Fatal error, hardware has shut down. */ +}; + +#define CRB_NIU_XG_PAUSE_CTL_P0 0x1 +#define CRB_NIU_XG_PAUSE_CTL_P1 0x8 #define QLA82XX_HW_H0_CH_HUB_ADR 0x05 #define QLA82XX_HW_H1_CH_HUB_ADR 0x0E diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 30f31b127f3..ce6d3b7f0c6 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -8,6 +8,7 @@ #include <linux/slab.h> #include <linux/blkdev.h> #include <linux/iscsi_boot_sysfs.h> +#include <linux/inet.h> #include <scsi/scsi_tcq.h> #include <scsi/scsicam.h> @@ -31,39 +32,47 @@ static struct kmem_cache *srb_cachep; /* * Module parameter information and variables */ +int ql4xdisablesysfsboot = 1; +module_param(ql4xdisablesysfsboot, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(ql4xdisablesysfsboot, + " Set to disable exporting boot targets to sysfs.\n" + "\t\t 0 - Export boot targets\n" + "\t\t 1 - Do not export boot targets (Default)"); + int ql4xdontresethba = 0; module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ql4xdontresethba, - "Don't reset the HBA for driver recovery \n" - " 0 - It will reset HBA (Default)\n" - " 1 - It will NOT reset HBA"); + " Don't reset the HBA for driver recovery.\n" + "\t\t 0 - It will reset HBA (Default)\n" + "\t\t 1 - It will NOT reset HBA"); -int ql4xextended_error_logging = 0; /* 0 = off, 1 = log errors */ +int ql4xextended_error_logging; module_param(ql4xextended_error_logging, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ql4xextended_error_logging, - "Option to enable extended error logging, " - "Default is 0 - no logging, 1 - debug logging"); + " Option to enable extended error logging.\n" + "\t\t 0 - no logging (Default)\n" + "\t\t 2 - debug logging"); int ql4xenablemsix = 1; module_param(ql4xenablemsix, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql4xenablemsix, - "Set to enable MSI or MSI-X interrupt mechanism.\n" - " 0 = enable INTx interrupt mechanism.\n" - " 1 = enable MSI-X interrupt mechanism (Default).\n" - " 2 = enable MSI interrupt mechanism."); + " Set to enable MSI or MSI-X interrupt mechanism.\n" + "\t\t 0 = enable INTx interrupt mechanism.\n" + "\t\t 1 = enable MSI-X interrupt mechanism (Default).\n" + "\t\t 2 = enable MSI interrupt mechanism."); #define QL4_DEF_QDEPTH 32 static int ql4xmaxqdepth = QL4_DEF_QDEPTH; module_param(ql4xmaxqdepth, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ql4xmaxqdepth, - "Maximum queue depth to report for target devices.\n" - " Default: 32."); + " Maximum queue depth to report for target devices.\n" + "\t\t Default: 32."); static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO; module_param(ql4xsess_recovery_tmo, int, S_IRUGO); MODULE_PARM_DESC(ql4xsess_recovery_tmo, "Target Session Recovery Timeout.\n" - " Default: 30 sec."); + "\t\t Default: 120 sec."); static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha); /* @@ -120,7 +129,7 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); static int qla4xxx_slave_alloc(struct scsi_device *device); static int qla4xxx_slave_configure(struct scsi_device *device); static void qla4xxx_slave_destroy(struct scsi_device *sdev); -static mode_t ql4_attr_is_visible(int param_type, int param); +static umode_t ql4_attr_is_visible(int param_type, int param); static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type); static struct qla4_8xxx_legacy_intr_set legacy_intr[] = @@ -189,7 +198,7 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { static struct scsi_transport_template *qla4xxx_scsi_transport; -static mode_t ql4_attr_is_visible(int param_type, int param) +static umode_t ql4_attr_is_visible(int param_type, int param) { switch (param_type) { case ISCSI_HOST_PARAM: @@ -415,7 +424,7 @@ static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) qla_ep = ep->dd_data; ha = to_qla_host(qla_ep->host); - if (adapter_up(ha)) + if (adapter_up(ha) && !test_bit(AF_BUILD_DDB_LIST, &ha->flags)) ret = 1; return ret; @@ -927,7 +936,16 @@ qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, uint32_t len) goto exit_init_fw_cb; } - qla4xxx_disable_acb(ha); + rval = qla4xxx_disable_acb(ha); + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_ERR, ha, "%s: disable acb mbx failed\n", + __func__); + rval = -EIO; + goto exit_init_fw_cb; + } + + wait_for_completion_timeout(&ha->disable_acb_comp, + DISABLE_ACB_TOV * HZ); qla4xxx_initcb_to_acb(init_fw_cb); @@ -975,6 +993,150 @@ static int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn, } +int qla4xxx_get_ddb_index(struct scsi_qla_host *ha, uint16_t *ddb_index) +{ + uint32_t mbx_sts = 0; + uint16_t tmp_ddb_index; + int ret; + +get_ddb_index: + tmp_ddb_index = find_first_zero_bit(ha->ddb_idx_map, MAX_DDB_ENTRIES); + + if (tmp_ddb_index >= MAX_DDB_ENTRIES) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "Free DDB index not available\n")); + ret = QLA_ERROR; + goto exit_get_ddb_index; + } + + if (test_and_set_bit(tmp_ddb_index, ha->ddb_idx_map)) + goto get_ddb_index; + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Found a free DDB index at %d\n", tmp_ddb_index)); + ret = qla4xxx_req_ddb_entry(ha, tmp_ddb_index, &mbx_sts); + if (ret == QLA_ERROR) { + if (mbx_sts == MBOX_STS_COMMAND_ERROR) { + ql4_printk(KERN_INFO, ha, + "DDB index = %d not available trying next\n", + tmp_ddb_index); + goto get_ddb_index; + } + DEBUG2(ql4_printk(KERN_INFO, ha, + "Free FW DDB not available\n")); + } + + *ddb_index = tmp_ddb_index; + +exit_get_ddb_index: + return ret; +} + +static int qla4xxx_match_ipaddress(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry, + char *existing_ipaddr, + char *user_ipaddr) +{ + uint8_t dst_ipaddr[IPv6_ADDR_LEN]; + char formatted_ipaddr[DDB_IPADDR_LEN]; + int status = QLA_SUCCESS, ret = 0; + + if (ddb_entry->fw_ddb_entry.options & DDB_OPT_IPV6_DEVICE) { + ret = in6_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr, + '\0', NULL); + if (ret == 0) { + status = QLA_ERROR; + goto out_match; + } + ret = sprintf(formatted_ipaddr, "%pI6", dst_ipaddr); + } else { + ret = in4_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr, + '\0', NULL); + if (ret == 0) { + status = QLA_ERROR; + goto out_match; + } + ret = sprintf(formatted_ipaddr, "%pI4", dst_ipaddr); + } + + if (strcmp(existing_ipaddr, formatted_ipaddr)) + status = QLA_ERROR; + +out_match: + return status; +} + +static int qla4xxx_match_fwdb_session(struct scsi_qla_host *ha, + struct iscsi_cls_conn *cls_conn) +{ + int idx = 0, max_ddbs, rval; + struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); + struct iscsi_session *sess, *existing_sess; + struct iscsi_conn *conn, *existing_conn; + struct ddb_entry *ddb_entry; + + sess = cls_sess->dd_data; + conn = cls_conn->dd_data; + + if (sess->targetname == NULL || + conn->persistent_address == NULL || + conn->persistent_port == 0) + return QLA_ERROR; + + max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : + MAX_DEV_DB_ENTRIES; + + for (idx = 0; idx < max_ddbs; idx++) { + ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); + if (ddb_entry == NULL) + continue; + + if (ddb_entry->ddb_type != FLASH_DDB) + continue; + + existing_sess = ddb_entry->sess->dd_data; + existing_conn = ddb_entry->conn->dd_data; + + if (existing_sess->targetname == NULL || + existing_conn->persistent_address == NULL || + existing_conn->persistent_port == 0) + continue; + + DEBUG2(ql4_printk(KERN_INFO, ha, + "IQN = %s User IQN = %s\n", + existing_sess->targetname, + sess->targetname)); + + DEBUG2(ql4_printk(KERN_INFO, ha, + "IP = %s User IP = %s\n", + existing_conn->persistent_address, + conn->persistent_address)); + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Port = %d User Port = %d\n", + existing_conn->persistent_port, + conn->persistent_port)); + + if (strcmp(existing_sess->targetname, sess->targetname)) + continue; + rval = qla4xxx_match_ipaddress(ha, ddb_entry, + existing_conn->persistent_address, + conn->persistent_address); + if (rval == QLA_ERROR) + continue; + if (existing_conn->persistent_port != conn->persistent_port) + continue; + break; + } + + if (idx == max_ddbs) + return QLA_ERROR; + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Match found in fwdb sessions\n")); + return QLA_SUCCESS; +} + static struct iscsi_cls_session * qla4xxx_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, uint16_t qdepth, @@ -984,8 +1146,7 @@ qla4xxx_session_create(struct iscsi_endpoint *ep, struct scsi_qla_host *ha; struct qla_endpoint *qla_ep; struct ddb_entry *ddb_entry; - uint32_t ddb_index; - uint32_t mbx_sts = 0; + uint16_t ddb_index; struct iscsi_session *sess; struct sockaddr *dst_addr; int ret; @@ -1000,32 +1161,9 @@ qla4xxx_session_create(struct iscsi_endpoint *ep, dst_addr = (struct sockaddr *)&qla_ep->dst_addr; ha = to_qla_host(qla_ep->host); -get_ddb_index: - ddb_index = find_first_zero_bit(ha->ddb_idx_map, MAX_DDB_ENTRIES); - - if (ddb_index >= MAX_DDB_ENTRIES) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "Free DDB index not available\n")); - return NULL; - } - - if (test_and_set_bit(ddb_index, ha->ddb_idx_map)) - goto get_ddb_index; - - DEBUG2(ql4_printk(KERN_INFO, ha, - "Found a free DDB index at %d\n", ddb_index)); - ret = qla4xxx_req_ddb_entry(ha, ddb_index, &mbx_sts); - if (ret == QLA_ERROR) { - if (mbx_sts == MBOX_STS_COMMAND_ERROR) { - ql4_printk(KERN_INFO, ha, - "DDB index = %d not available trying next\n", - ddb_index); - goto get_ddb_index; - } - DEBUG2(ql4_printk(KERN_INFO, ha, - "Free FW DDB not available\n")); + ret = qla4xxx_get_ddb_index(ha, &ddb_index); + if (ret == QLA_ERROR) return NULL; - } cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, qla_ep->host, cmds_max, sizeof(struct ddb_entry), @@ -1040,6 +1178,8 @@ get_ddb_index: ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE; ddb_entry->ha = ha; ddb_entry->sess = cls_sess; + ddb_entry->unblock_sess = qla4xxx_unblock_ddb; + ddb_entry->ddb_change = qla4xxx_ddb_change; cls_sess->recovery_tmo = ql4xsess_recovery_tmo; ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry; ha->tot_ddbs++; @@ -1077,6 +1217,9 @@ qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx) DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), conn_idx); + if (!cls_conn) + return NULL; + sess = cls_sess->dd_data; ddb_entry = sess->dd_data; ddb_entry->conn = cls_conn; @@ -1109,7 +1252,7 @@ static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn) struct iscsi_session *sess; struct ddb_entry *ddb_entry; struct scsi_qla_host *ha; - struct dev_db_entry *fw_ddb_entry; + struct dev_db_entry *fw_ddb_entry = NULL; dma_addr_t fw_ddb_entry_dma; uint32_t mbx_sts = 0; int ret = 0; @@ -1120,12 +1263,25 @@ static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn) ddb_entry = sess->dd_data; ha = ddb_entry->ha; + /* Check if we have matching FW DDB, if yes then do not + * login to this target. This could cause target to logout previous + * connection + */ + ret = qla4xxx_match_fwdb_session(ha, cls_conn); + if (ret == QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, + "Session already exist in FW.\n"); + ret = -EEXIST; + goto exit_conn_start; + } + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), &fw_ddb_entry_dma, GFP_KERNEL); if (!fw_ddb_entry) { ql4_printk(KERN_ERR, ha, "%s: Unable to allocate dma buffer\n", __func__); - return -ENOMEM; + ret = -ENOMEM; + goto exit_conn_start; } ret = qla4xxx_set_param_ddbentry(ha, ddb_entry, cls_conn, &mbx_sts); @@ -1138,9 +1294,7 @@ static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn) if (mbx_sts) if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { - iscsi_conn_start(ddb_entry->conn); - iscsi_conn_login_event(ddb_entry->conn, - ISCSI_CONN_STATE_LOGGED_IN); + ddb_entry->unblock_sess(ddb_entry->sess); goto exit_set_param; } @@ -1167,8 +1321,9 @@ exit_set_param: ret = 0; exit_conn_start: - dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), - fw_ddb_entry, fw_ddb_entry_dma); + if (fw_ddb_entry) + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); return ret; } @@ -1344,6 +1499,101 @@ static int qla4xxx_task_xmit(struct iscsi_task *task) return -ENOSYS; } +static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha, + struct dev_db_entry *fw_ddb_entry, + struct iscsi_cls_session *cls_sess, + struct iscsi_cls_conn *cls_conn) +{ + int buflen = 0; + struct iscsi_session *sess; + struct iscsi_conn *conn; + char ip_addr[DDB_IPADDR_LEN]; + uint16_t options = 0; + + sess = cls_sess->dd_data; + conn = cls_conn->dd_data; + + conn->max_recv_dlength = BYTE_UNITS * + le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); + + conn->max_xmit_dlength = BYTE_UNITS * + le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len); + + sess->initial_r2t_en = + (BIT_10 & le16_to_cpu(fw_ddb_entry->iscsi_options)); + + sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t); + + sess->imm_data_en = (BIT_11 & le16_to_cpu(fw_ddb_entry->iscsi_options)); + + sess->first_burst = BYTE_UNITS * + le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len); + + sess->max_burst = BYTE_UNITS * + le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len); + + sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); + + sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain); + + conn->persistent_port = le16_to_cpu(fw_ddb_entry->port); + + sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); + + options = le16_to_cpu(fw_ddb_entry->options); + if (options & DDB_OPT_IPV6_DEVICE) + sprintf(ip_addr, "%pI6", fw_ddb_entry->ip_addr); + else + sprintf(ip_addr, "%pI4", fw_ddb_entry->ip_addr); + + iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_NAME, + (char *)fw_ddb_entry->iscsi_name, buflen); + iscsi_set_param(cls_conn, ISCSI_PARAM_INITIATOR_NAME, + (char *)ha->name_string, buflen); + iscsi_set_param(cls_conn, ISCSI_PARAM_PERSISTENT_ADDRESS, + (char *)ip_addr, buflen); +} + +void qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry) +{ + struct iscsi_cls_session *cls_sess; + struct iscsi_cls_conn *cls_conn; + uint32_t ddb_state; + dma_addr_t fw_ddb_entry_dma; + struct dev_db_entry *fw_ddb_entry; + + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + &fw_ddb_entry_dma, GFP_KERNEL); + if (!fw_ddb_entry) { + ql4_printk(KERN_ERR, ha, + "%s: Unable to allocate dma buffer\n", __func__); + goto exit_session_conn_fwddb_param; + } + + if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry, + fw_ddb_entry_dma, NULL, NULL, &ddb_state, + NULL, NULL, NULL) == QLA_ERROR) { + DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed " + "get_ddb_entry for fw_ddb_index %d\n", + ha->host_no, __func__, + ddb_entry->fw_ddb_index)); + goto exit_session_conn_fwddb_param; + } + + cls_sess = ddb_entry->sess; + + cls_conn = ddb_entry->conn; + + /* Update params */ + qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn); + +exit_session_conn_fwddb_param: + if (fw_ddb_entry) + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); +} + void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry) { @@ -1360,7 +1610,7 @@ void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, if (!fw_ddb_entry) { ql4_printk(KERN_ERR, ha, "%s: Unable to allocate dma buffer\n", __func__); - return; + goto exit_session_conn_param; } if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry, @@ -1370,7 +1620,7 @@ void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, "get_ddb_entry for fw_ddb_index %d\n", ha->host_no, __func__, ddb_entry->fw_ddb_index)); - return; + goto exit_session_conn_param; } cls_sess = ddb_entry->sess; @@ -1379,6 +1629,14 @@ void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, cls_conn = ddb_entry->conn; conn = cls_conn->dd_data; + /* Update timers after login */ + ddb_entry->default_relogin_timeout = + (le16_to_cpu(fw_ddb_entry->def_timeout) > LOGIN_TOV) && + (le16_to_cpu(fw_ddb_entry->def_timeout) < LOGIN_TOV * 10) ? + le16_to_cpu(fw_ddb_entry->def_timeout) : LOGIN_TOV; + ddb_entry->default_time2wait = + le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); + /* Update params */ conn->max_recv_dlength = BYTE_UNITS * le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); @@ -1407,6 +1665,11 @@ void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, memcpy(sess->initiatorname, ha->name_string, min(sizeof(ha->name_string), sizeof(sess->initiatorname))); + +exit_session_conn_param: + if (fw_ddb_entry) + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); } /* @@ -1607,6 +1870,9 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha) vfree(ha->chap_list); ha->chap_list = NULL; + if (ha->fw_ddb_dma_pool) + dma_pool_destroy(ha->fw_ddb_dma_pool); + /* release io space registers */ if (is_qla8022(ha)) { if (ha->nx_pcibase) @@ -1689,6 +1955,16 @@ static int qla4xxx_mem_alloc(struct scsi_qla_host *ha) goto mem_alloc_error_exit; } + ha->fw_ddb_dma_pool = dma_pool_create("ql4_fw_ddb", &ha->pdev->dev, + DDB_DMA_BLOCK_SIZE, 8, 0); + + if (ha->fw_ddb_dma_pool == NULL) { + ql4_printk(KERN_WARNING, ha, + "%s: fw_ddb_dma_pool allocation failed..\n", + __func__); + goto mem_alloc_error_exit; + } + return QLA_SUCCESS; mem_alloc_error_exit: @@ -1697,14 +1973,51 @@ mem_alloc_error_exit: } /** + * qla4_8xxx_check_temp - Check the ISP82XX temperature. + * @ha: adapter block pointer. + * + * Note: The caller should not hold the idc lock. + **/ +static int qla4_8xxx_check_temp(struct scsi_qla_host *ha) +{ + uint32_t temp, temp_state, temp_val; + int status = QLA_SUCCESS; + + temp = qla4_8xxx_rd_32(ha, CRB_TEMP_STATE); + + temp_state = qla82xx_get_temp_state(temp); + temp_val = qla82xx_get_temp_val(temp); + + if (temp_state == QLA82XX_TEMP_PANIC) { + ql4_printk(KERN_WARNING, ha, "Device temperature %d degrees C" + " exceeds maximum allowed. Hardware has been shut" + " down.\n", temp_val); + status = QLA_ERROR; + } else if (temp_state == QLA82XX_TEMP_WARN) { + if (ha->temperature == QLA82XX_TEMP_NORMAL) + ql4_printk(KERN_WARNING, ha, "Device temperature %d" + " degrees C exceeds operating range." + " Immediate action needed.\n", temp_val); + } else { + if (ha->temperature == QLA82XX_TEMP_WARN) + ql4_printk(KERN_INFO, ha, "Device temperature is" + " now %d degrees C in normal range.\n", + temp_val); + } + ha->temperature = temp_state; + return status; +} + +/** * qla4_8xxx_check_fw_alive - Check firmware health * @ha: Pointer to host adapter structure. * * Context: Interrupt **/ -static void qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) +static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) { - uint32_t fw_heartbeat_counter, halt_status; + uint32_t fw_heartbeat_counter; + int status = QLA_SUCCESS; fw_heartbeat_counter = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); /* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */ @@ -1712,7 +2025,7 @@ static void qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Device in frozen " "state, QLA82XX_PEG_ALIVE_COUNTER is 0xffffffff\n", ha->host_no, __func__)); - return; + return status; } if (ha->fw_heartbeat_counter == fw_heartbeat_counter) { @@ -1720,8 +2033,6 @@ static void qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) /* FW not alive after 2 seconds */ if (ha->seconds_since_last_heartbeat == 2) { ha->seconds_since_last_heartbeat = 0; - halt_status = qla4_8xxx_rd_32(ha, - QLA82XX_PEG_HALT_STATUS1); ql4_printk(KERN_INFO, ha, "scsi(%ld): %s, Dumping hw/fw registers:\n " @@ -1729,7 +2040,9 @@ static void qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) " 0x%x,\n PEG_NET_0_PC: 0x%x, PEG_NET_1_PC:" " 0x%x,\n PEG_NET_2_PC: 0x%x, PEG_NET_3_PC:" " 0x%x,\n PEG_NET_4_PC: 0x%x\n", - ha->host_no, __func__, halt_status, + ha->host_no, __func__, + qla4_8xxx_rd_32(ha, + QLA82XX_PEG_HALT_STATUS1), qla4_8xxx_rd_32(ha, QLA82XX_PEG_HALT_STATUS2), qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_0 + @@ -1742,24 +2055,13 @@ static void qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) 0x3c), qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c)); - - /* Since we cannot change dev_state in interrupt - * context, set appropriate DPC flag then wakeup - * DPC */ - if (halt_status & HALT_STATUS_UNRECOVERABLE) - set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags); - else { - printk("scsi%ld: %s: detect abort needed!\n", - ha->host_no, __func__); - set_bit(DPC_RESET_HA, &ha->dpc_flags); - } - qla4xxx_wake_dpc(ha); - qla4xxx_mailbox_premature_completion(ha); + status = QLA_ERROR; } } else ha->seconds_since_last_heartbeat = 0; ha->fw_heartbeat_counter = fw_heartbeat_counter; + return status; } /** @@ -1770,22 +2072,29 @@ static void qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) **/ void qla4_8xxx_watchdog(struct scsi_qla_host *ha) { - uint32_t dev_state; - - dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); + uint32_t dev_state, halt_status; /* don't poll if reset is going on */ if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || test_bit(DPC_RESET_HA, &ha->dpc_flags) || test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags))) { - if (dev_state == QLA82XX_DEV_NEED_RESET && + dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); + + if (qla4_8xxx_check_temp(ha)) { + ql4_printk(KERN_INFO, ha, "disabling pause" + " transmit on port 0 & 1.\n"); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, + CRB_NIU_XG_PAUSE_CTL_P0 | + CRB_NIU_XG_PAUSE_CTL_P1); + set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags); + qla4xxx_wake_dpc(ha); + } else if (dev_state == QLA82XX_DEV_NEED_RESET && !test_bit(DPC_RESET_HA, &ha->dpc_flags)) { if (!ql4xdontresethba) { ql4_printk(KERN_INFO, ha, "%s: HW State: " "NEED RESET!\n", __func__); set_bit(DPC_RESET_HA, &ha->dpc_flags); qla4xxx_wake_dpc(ha); - qla4xxx_mailbox_premature_completion(ha); } } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT && !test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) { @@ -1795,7 +2104,90 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha) qla4xxx_wake_dpc(ha); } else { /* Check firmware health */ - qla4_8xxx_check_fw_alive(ha); + if (qla4_8xxx_check_fw_alive(ha)) { + ql4_printk(KERN_INFO, ha, "disabling pause" + " transmit on port 0 & 1.\n"); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, + CRB_NIU_XG_PAUSE_CTL_P0 | + CRB_NIU_XG_PAUSE_CTL_P1); + halt_status = qla4_8xxx_rd_32(ha, + QLA82XX_PEG_HALT_STATUS1); + + if (LSW(MSB(halt_status)) == 0x67) + ql4_printk(KERN_ERR, ha, "%s:" + " Firmware aborted with" + " error code 0x00006700." + " Device is being reset\n", + __func__); + + /* Since we cannot change dev_state in interrupt + * context, set appropriate DPC flag then wakeup + * DPC */ + if (halt_status & HALT_STATUS_UNRECOVERABLE) + set_bit(DPC_HA_UNRECOVERABLE, + &ha->dpc_flags); + else { + ql4_printk(KERN_INFO, ha, "%s: detect " + "abort needed!\n", __func__); + set_bit(DPC_RESET_HA, &ha->dpc_flags); + } + qla4xxx_mailbox_premature_completion(ha); + qla4xxx_wake_dpc(ha); + } + } + } +} + +static void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) +{ + struct iscsi_session *sess; + struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha; + + sess = cls_sess->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + + if (!(ddb_entry->ddb_type == FLASH_DDB)) + return; + + if (adapter_up(ha) && !test_bit(DF_RELOGIN, &ddb_entry->flags) && + !iscsi_is_session_online(cls_sess)) { + if (atomic_read(&ddb_entry->retry_relogin_timer) != + INVALID_ENTRY) { + if (atomic_read(&ddb_entry->retry_relogin_timer) == + 0) { + atomic_set(&ddb_entry->retry_relogin_timer, + INVALID_ENTRY); + set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); + set_bit(DF_RELOGIN, &ddb_entry->flags); + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s: index [%d] login device\n", + __func__, ddb_entry->fw_ddb_index)); + } else + atomic_dec(&ddb_entry->retry_relogin_timer); + } + } + + /* Wait for relogin to timeout */ + if (atomic_read(&ddb_entry->relogin_timer) && + (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) { + /* + * If the relogin times out and the device is + * still NOT ONLINE then try and relogin again. + */ + if (!iscsi_is_session_online(cls_sess)) { + /* Reset retry relogin timer */ + atomic_inc(&ddb_entry->relogin_retry_count); + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s: index[%d] relogin timed out-retrying" + " relogin (%d), retry (%d)\n", __func__, + ddb_entry->fw_ddb_index, + atomic_read(&ddb_entry->relogin_retry_count), + ddb_entry->default_time2wait + 4)); + set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); + atomic_set(&ddb_entry->retry_relogin_timer, + ddb_entry->default_time2wait + 4); } } } @@ -1809,6 +2201,8 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) int start_dpc = 0; uint16_t w; + iscsi_host_for_each_session(ha->host, qla4xxx_check_relogin_flash_ddb); + /* If we are in the middle of AER/EEH processing * skip any processing and reschedule the timer */ @@ -2078,7 +2472,12 @@ static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session) sess = cls_session->dd_data; ddb_entry = sess->dd_data; ddb_entry->fw_ddb_device_state = DDB_DS_SESSION_FAILED; - iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED); + + if (ddb_entry->ddb_type == FLASH_DDB) + iscsi_block_session(ddb_entry->sess); + else + iscsi_session_failure(cls_session->dd_data, + ISCSI_ERR_CONN_FAILED); } /** @@ -2089,6 +2488,8 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) { int status = QLA_ERROR; uint8_t reset_chip = 0; + uint32_t dev_state; + unsigned long wait; /* Stall incoming I/O until we are done */ scsi_block_requests(ha->host); @@ -2139,8 +2540,29 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) * or if stop_firmware fails for ISP-82xx. * This is the default case for ISP-4xxx */ if (!is_qla8022(ha) || reset_chip) { + if (!is_qla8022(ha)) + goto chip_reset; + + /* Check if 82XX firmware is alive or not + * We may have arrived here from NEED_RESET + * detection only */ + if (test_bit(AF_FW_RECOVERY, &ha->flags)) + goto chip_reset; + + wait = jiffies + (FW_ALIVE_WAIT_TOV * HZ); + while (time_before(jiffies, wait)) { + if (qla4_8xxx_check_fw_alive(ha)) { + qla4xxx_mailbox_premature_completion(ha); + break; + } + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + } + if (!test_bit(AF_FW_RECOVERY, &ha->flags)) qla4xxx_cmd_wait(ha); +chip_reset: qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); qla4xxx_abort_active_cmds(ha, DID_RESET << 16); DEBUG2(ql4_printk(KERN_INFO, ha, @@ -2163,7 +2585,7 @@ recover_ha_init_adapter: /* NOTE: AF_ONLINE flag set upon successful completion of * qla4xxx_initialize_adapter */ - status = qla4xxx_initialize_adapter(ha); + status = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); } /* Retry failed adapter initialization, if necessary @@ -2176,6 +2598,25 @@ recover_ha_init_adapter: * Since we don't want to block the DPC for too long * with multiple resets in the same thread, * utilize DPC to retry */ + if (is_qla8022(ha)) { + qla4_8xxx_idc_lock(ha); + dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); + qla4_8xxx_idc_unlock(ha); + if (dev_state == QLA82XX_DEV_FAILED) { + ql4_printk(KERN_INFO, ha, "%s: don't retry " + "recover adapter. H/W is in Failed " + "state\n", __func__); + qla4xxx_dead_adapter_cleanup(ha); + clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); + clear_bit(DPC_RESET_HA, &ha->dpc_flags); + clear_bit(DPC_RESET_HA_FW_CONTEXT, + &ha->dpc_flags); + status = QLA_ERROR; + + goto exit_recover; + } + } + if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) { ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES; DEBUG2(printk("scsi%ld: recover adapter - retrying " @@ -2214,6 +2655,7 @@ recover_ha_init_adapter: clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); } +exit_recover: ha->adapter_error_count++; if (test_bit(AF_ONLINE, &ha->flags)) @@ -2245,17 +2687,108 @@ static void qla4xxx_relogin_devices(struct iscsi_cls_session *cls_session) iscsi_unblock_session(ddb_entry->sess); } else { /* Trigger relogin */ - iscsi_session_failure(cls_session->dd_data, - ISCSI_ERR_CONN_FAILED); + if (ddb_entry->ddb_type == FLASH_DDB) { + if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) + qla4xxx_arm_relogin_timer(ddb_entry); + } else + iscsi_session_failure(cls_session->dd_data, + ISCSI_ERR_CONN_FAILED); } } } +int qla4xxx_unblock_flash_ddb(struct iscsi_cls_session *cls_session) +{ + struct iscsi_session *sess; + struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha; + + sess = cls_session->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" + " unblock session\n", ha->host_no, __func__, + ddb_entry->fw_ddb_index); + + iscsi_unblock_session(ddb_entry->sess); + + /* Start scan target */ + if (test_bit(AF_ONLINE, &ha->flags)) { + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" + " start scan\n", ha->host_no, __func__, + ddb_entry->fw_ddb_index); + scsi_queue_work(ha->host, &ddb_entry->sess->scan_work); + } + return QLA_SUCCESS; +} + +int qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session) +{ + struct iscsi_session *sess; + struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha; + + sess = cls_session->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" + " unblock user space session\n", ha->host_no, __func__, + ddb_entry->fw_ddb_index); + iscsi_conn_start(ddb_entry->conn); + iscsi_conn_login_event(ddb_entry->conn, + ISCSI_CONN_STATE_LOGGED_IN); + + return QLA_SUCCESS; +} + static void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha) { iscsi_host_for_each_session(ha->host, qla4xxx_relogin_devices); } +static void qla4xxx_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) +{ + uint16_t relogin_timer; + struct iscsi_session *sess; + struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha; + + sess = cls_sess->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + + relogin_timer = max(ddb_entry->default_relogin_timeout, + (uint16_t)RELOGIN_TOV); + atomic_set(&ddb_entry->relogin_timer, relogin_timer); + + DEBUG2(ql4_printk(KERN_INFO, ha, + "scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no, + ddb_entry->fw_ddb_index, relogin_timer)); + + qla4xxx_login_flash_ddb(cls_sess); +} + +static void qla4xxx_dpc_relogin(struct iscsi_cls_session *cls_sess) +{ + struct iscsi_session *sess; + struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha; + + sess = cls_sess->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + + if (!(ddb_entry->ddb_type == FLASH_DDB)) + return; + + if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) && + !iscsi_is_session_online(cls_sess)) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "relogin issued\n")); + qla4xxx_relogin_flash_ddb(cls_sess); + } +} + void qla4xxx_wake_dpc(struct scsi_qla_host *ha) { if (ha->dpc_thread) @@ -2356,6 +2889,12 @@ dpc_post_reset_ha: if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags)) qla4xxx_get_dhcp_ip_address(ha); + /* ---- relogin device? --- */ + if (adapter_up(ha) && + test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) { + iscsi_host_for_each_session(ha->host, qla4xxx_dpc_relogin); + } + /* ---- link change? --- */ if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) { if (!test_bit(AF_LINK_UP, &ha->flags)) { @@ -2368,8 +2907,12 @@ dpc_post_reset_ha: * fatal error recovery. Therefore, the driver must * manually relogin to devices when recovering from * connection failures, logouts, expired KATO, etc. */ - - qla4xxx_relogin_all_devices(ha); + if (test_and_clear_bit(AF_BUILD_DDB_LIST, &ha->flags)) { + qla4xxx_build_ddb_list(ha, ha->is_reset); + iscsi_host_for_each_session(ha->host, + qla4xxx_login_flash_ddb); + } else + qla4xxx_relogin_all_devices(ha); } } } @@ -2380,6 +2923,7 @@ dpc_post_reset_ha: **/ static void qla4xxx_free_adapter(struct scsi_qla_host *ha) { + qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); if (test_bit(AF_INTERRUPTS_ON, &ha->flags)) { /* Turn-off interrupts on the card. */ @@ -2613,7 +3157,7 @@ static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf) return rc; } -static mode_t qla4xxx_eth_get_attr_visibility(void *data, int type) +static umode_t qla4xxx_eth_get_attr_visibility(void *data, int type) { int rc; @@ -2647,7 +3191,7 @@ static ssize_t qla4xxx_show_boot_ini_info(void *data, int type, char *buf) return rc; } -static mode_t qla4xxx_ini_get_attr_visibility(void *data, int type) +static umode_t qla4xxx_ini_get_attr_visibility(void *data, int type) { int rc; @@ -2734,7 +3278,7 @@ static ssize_t qla4xxx_show_boot_tgt_sec_info(void *data, int type, char *buf) return qla4xxx_show_boot_tgt_info(boot_sess, type, buf); } -static mode_t qla4xxx_tgt_get_attr_visibility(void *data, int type) +static umode_t qla4xxx_tgt_get_attr_visibility(void *data, int type) { int rc; @@ -2867,6 +3411,9 @@ static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[]) " target ID %d\n", __func__, ddb_index[0], ddb_index[1])); + ha->pri_ddb_idx = ddb_index[0]; + ha->sec_ddb_idx = ddb_index[1]; + exit_boot_info_free: dma_free_coherent(&ha->pdev->dev, size, buf, buf_dma); exit_boot_info: @@ -3034,6 +3581,9 @@ static int qla4xxx_get_boot_info(struct scsi_qla_host *ha) return ret; } + if (ql4xdisablesysfsboot) + return QLA_SUCCESS; + if (ddb_index[0] == 0xffff) goto sec_target; @@ -3066,7 +3616,15 @@ static int qla4xxx_setup_boot_info(struct scsi_qla_host *ha) struct iscsi_boot_kobj *boot_kobj; if (qla4xxx_get_boot_info(ha) != QLA_SUCCESS) - return 0; + return QLA_ERROR; + + if (ql4xdisablesysfsboot) { + ql4_printk(KERN_INFO, ha, + "%s: syfsboot disabled - driver will trigger login" + "and publish session for discovery .\n", __func__); + return QLA_SUCCESS; + } + ha->boot_kset = iscsi_boot_create_host_kset(ha->host->host_no); if (!ha->boot_kset) @@ -3108,7 +3666,7 @@ static int qla4xxx_setup_boot_info(struct scsi_qla_host *ha) if (!boot_kobj) goto put_host; - return 0; + return QLA_SUCCESS; put_host: scsi_host_put(ha->host); @@ -3174,7 +3732,586 @@ static void qla4xxx_create_chap_list(struct scsi_qla_host *ha) exit_chap_list: dma_free_coherent(&ha->pdev->dev, chap_size, chap_flash_data, chap_dma); - return; +} + +static void qla4xxx_get_param_ddb(struct ddb_entry *ddb_entry, + struct ql4_tuple_ddb *tddb) +{ + struct scsi_qla_host *ha; + struct iscsi_cls_session *cls_sess; + struct iscsi_cls_conn *cls_conn; + struct iscsi_session *sess; + struct iscsi_conn *conn; + + DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); + ha = ddb_entry->ha; + cls_sess = ddb_entry->sess; + sess = cls_sess->dd_data; + cls_conn = ddb_entry->conn; + conn = cls_conn->dd_data; + + tddb->tpgt = sess->tpgt; + tddb->port = conn->persistent_port; + strncpy(tddb->iscsi_name, sess->targetname, ISCSI_NAME_SIZE); + strncpy(tddb->ip_addr, conn->persistent_address, DDB_IPADDR_LEN); +} + +static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry, + struct ql4_tuple_ddb *tddb) +{ + uint16_t options = 0; + + tddb->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); + memcpy(&tddb->iscsi_name[0], &fw_ddb_entry->iscsi_name[0], + min(sizeof(tddb->iscsi_name), sizeof(fw_ddb_entry->iscsi_name))); + + options = le16_to_cpu(fw_ddb_entry->options); + if (options & DDB_OPT_IPV6_DEVICE) + sprintf(tddb->ip_addr, "%pI6", fw_ddb_entry->ip_addr); + else + sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr); + + tddb->port = le16_to_cpu(fw_ddb_entry->port); +} + +static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha, + struct ql4_tuple_ddb *old_tddb, + struct ql4_tuple_ddb *new_tddb) +{ + if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name)) + return QLA_ERROR; + + if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr)) + return QLA_ERROR; + + if (old_tddb->port != new_tddb->port) + return QLA_ERROR; + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Match Found, fw[%d,%d,%s,%s], [%d,%d,%s,%s]", + old_tddb->port, old_tddb->tpgt, old_tddb->ip_addr, + old_tddb->iscsi_name, new_tddb->port, new_tddb->tpgt, + new_tddb->ip_addr, new_tddb->iscsi_name)); + + return QLA_SUCCESS; +} + +static int qla4xxx_is_session_exists(struct scsi_qla_host *ha, + struct dev_db_entry *fw_ddb_entry) +{ + struct ddb_entry *ddb_entry; + struct ql4_tuple_ddb *fw_tddb = NULL; + struct ql4_tuple_ddb *tmp_tddb = NULL; + int idx; + int ret = QLA_ERROR; + + fw_tddb = vzalloc(sizeof(*fw_tddb)); + if (!fw_tddb) { + DEBUG2(ql4_printk(KERN_WARNING, ha, + "Memory Allocation failed.\n")); + ret = QLA_SUCCESS; + goto exit_check; + } + + tmp_tddb = vzalloc(sizeof(*tmp_tddb)); + if (!tmp_tddb) { + DEBUG2(ql4_printk(KERN_WARNING, ha, + "Memory Allocation failed.\n")); + ret = QLA_SUCCESS; + goto exit_check; + } + + qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb); + + for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) { + ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); + if (ddb_entry == NULL) + continue; + + qla4xxx_get_param_ddb(ddb_entry, tmp_tddb); + if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb)) { + ret = QLA_SUCCESS; /* found */ + goto exit_check; + } + } + +exit_check: + if (fw_tddb) + vfree(fw_tddb); + if (tmp_tddb) + vfree(tmp_tddb); + return ret; +} + +static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha, + struct list_head *list_nt, + struct dev_db_entry *fw_ddb_entry) +{ + struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp; + struct ql4_tuple_ddb *fw_tddb = NULL; + struct ql4_tuple_ddb *tmp_tddb = NULL; + int ret = QLA_ERROR; + + fw_tddb = vzalloc(sizeof(*fw_tddb)); + if (!fw_tddb) { + DEBUG2(ql4_printk(KERN_WARNING, ha, + "Memory Allocation failed.\n")); + ret = QLA_SUCCESS; + goto exit_check; + } + + tmp_tddb = vzalloc(sizeof(*tmp_tddb)); + if (!tmp_tddb) { + DEBUG2(ql4_printk(KERN_WARNING, ha, + "Memory Allocation failed.\n")); + ret = QLA_SUCCESS; + goto exit_check; + } + + qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb); + + list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) { + qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb); + if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb)) { + ret = QLA_SUCCESS; /* found */ + goto exit_check; + } + } + +exit_check: + if (fw_tddb) + vfree(fw_tddb); + if (tmp_tddb) + vfree(tmp_tddb); + return ret; +} + +static void qla4xxx_free_ddb_list(struct list_head *list_ddb) +{ + struct qla_ddb_index *ddb_idx, *ddb_idx_tmp; + + list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) { + list_del_init(&ddb_idx->list); + vfree(ddb_idx); + } +} + +static struct iscsi_endpoint *qla4xxx_get_ep_fwdb(struct scsi_qla_host *ha, + struct dev_db_entry *fw_ddb_entry) +{ + struct iscsi_endpoint *ep; + struct sockaddr_in *addr; + struct sockaddr_in6 *addr6; + struct sockaddr *dst_addr; + char *ip; + + /* TODO: need to destroy on unload iscsi_endpoint*/ + dst_addr = vmalloc(sizeof(*dst_addr)); + if (!dst_addr) + return NULL; + + if (fw_ddb_entry->options & DDB_OPT_IPV6_DEVICE) { + dst_addr->sa_family = AF_INET6; + addr6 = (struct sockaddr_in6 *)dst_addr; + ip = (char *)&addr6->sin6_addr; + memcpy(ip, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN); + addr6->sin6_port = htons(le16_to_cpu(fw_ddb_entry->port)); + + } else { + dst_addr->sa_family = AF_INET; + addr = (struct sockaddr_in *)dst_addr; + ip = (char *)&addr->sin_addr; + memcpy(ip, fw_ddb_entry->ip_addr, IP_ADDR_LEN); + addr->sin_port = htons(le16_to_cpu(fw_ddb_entry->port)); + } + + ep = qla4xxx_ep_connect(ha->host, dst_addr, 0); + vfree(dst_addr); + return ep; +} + +static int qla4xxx_verify_boot_idx(struct scsi_qla_host *ha, uint16_t idx) +{ + if (ql4xdisablesysfsboot) + return QLA_SUCCESS; + if (idx == ha->pri_ddb_idx || idx == ha->sec_ddb_idx) + return QLA_ERROR; + return QLA_SUCCESS; +} + +static void qla4xxx_setup_flash_ddb_entry(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry) +{ + uint16_t def_timeout; + + ddb_entry->ddb_type = FLASH_DDB; + ddb_entry->fw_ddb_index = INVALID_ENTRY; + ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE; + ddb_entry->ha = ha; + ddb_entry->unblock_sess = qla4xxx_unblock_flash_ddb; + ddb_entry->ddb_change = qla4xxx_flash_ddb_change; + + atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY); + atomic_set(&ddb_entry->relogin_timer, 0); + atomic_set(&ddb_entry->relogin_retry_count, 0); + def_timeout = le16_to_cpu(ddb_entry->fw_ddb_entry.def_timeout); + ddb_entry->default_relogin_timeout = + (def_timeout > LOGIN_TOV) && (def_timeout < LOGIN_TOV * 10) ? + def_timeout : LOGIN_TOV; + ddb_entry->default_time2wait = + le16_to_cpu(ddb_entry->fw_ddb_entry.iscsi_def_time2wait); +} + +static void qla4xxx_wait_for_ip_configuration(struct scsi_qla_host *ha) +{ + uint32_t idx = 0; + uint32_t ip_idx[IP_ADDR_COUNT] = {0, 1, 2, 3}; /* 4 IP interfaces */ + uint32_t sts[MBOX_REG_COUNT]; + uint32_t ip_state; + unsigned long wtime; + int ret; + + wtime = jiffies + (HZ * IP_CONFIG_TOV); + do { + for (idx = 0; idx < IP_ADDR_COUNT; idx++) { + if (ip_idx[idx] == -1) + continue; + + ret = qla4xxx_get_ip_state(ha, 0, ip_idx[idx], sts); + + if (ret == QLA_ERROR) { + ip_idx[idx] = -1; + continue; + } + + ip_state = (sts[1] & IP_STATE_MASK) >> IP_STATE_SHIFT; + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Waiting for IP state for idx = %d, state = 0x%x\n", + ip_idx[idx], ip_state)); + if (ip_state == IP_ADDRSTATE_UNCONFIGURED || + ip_state == IP_ADDRSTATE_INVALID || + ip_state == IP_ADDRSTATE_PREFERRED || + ip_state == IP_ADDRSTATE_DEPRICATED || + ip_state == IP_ADDRSTATE_DISABLING) + ip_idx[idx] = -1; + } + + /* Break if all IP states checked */ + if ((ip_idx[0] == -1) && + (ip_idx[1] == -1) && + (ip_idx[2] == -1) && + (ip_idx[3] == -1)) + break; + schedule_timeout_uninterruptible(HZ); + } while (time_after(wtime, jiffies)); +} + +static void qla4xxx_build_st_list(struct scsi_qla_host *ha, + struct list_head *list_st) +{ + struct qla_ddb_index *st_ddb_idx; + int max_ddbs; + int fw_idx_size; + struct dev_db_entry *fw_ddb_entry; + dma_addr_t fw_ddb_dma; + int ret; + uint32_t idx = 0, next_idx = 0; + uint32_t state = 0, conn_err = 0; + uint16_t conn_id = 0; + + fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, + &fw_ddb_dma); + if (fw_ddb_entry == NULL) { + DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); + goto exit_st_list; + } + + max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : + MAX_DEV_DB_ENTRIES; + fw_idx_size = sizeof(struct qla_ddb_index); + + for (idx = 0; idx < max_ddbs; idx = next_idx) { + ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma, + NULL, &next_idx, &state, + &conn_err, NULL, &conn_id); + if (ret == QLA_ERROR) + break; + + /* Check if ST, add to the list_st */ + if (strlen((char *) fw_ddb_entry->iscsi_name) != 0) + goto continue_next_st; + + st_ddb_idx = vzalloc(fw_idx_size); + if (!st_ddb_idx) + break; + + st_ddb_idx->fw_ddb_idx = idx; + + list_add_tail(&st_ddb_idx->list, list_st); +continue_next_st: + if (next_idx == 0) + break; + } + +exit_st_list: + if (fw_ddb_entry) + dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); +} + +/** + * qla4xxx_remove_failed_ddb - Remove inactive or failed ddb from list + * @ha: pointer to adapter structure + * @list_ddb: List from which failed ddb to be removed + * + * Iterate over the list of DDBs and find and remove DDBs that are either in + * no connection active state or failed state + **/ +static void qla4xxx_remove_failed_ddb(struct scsi_qla_host *ha, + struct list_head *list_ddb) +{ + struct qla_ddb_index *ddb_idx, *ddb_idx_tmp; + uint32_t next_idx = 0; + uint32_t state = 0, conn_err = 0; + int ret; + + list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) { + ret = qla4xxx_get_fwddb_entry(ha, ddb_idx->fw_ddb_idx, + NULL, 0, NULL, &next_idx, &state, + &conn_err, NULL, NULL); + if (ret == QLA_ERROR) + continue; + + if (state == DDB_DS_NO_CONNECTION_ACTIVE || + state == DDB_DS_SESSION_FAILED) { + list_del_init(&ddb_idx->list); + vfree(ddb_idx); + } + } +} + +static int qla4xxx_sess_conn_setup(struct scsi_qla_host *ha, + struct dev_db_entry *fw_ddb_entry, + int is_reset) +{ + struct iscsi_cls_session *cls_sess; + struct iscsi_session *sess; + struct iscsi_cls_conn *cls_conn; + struct iscsi_endpoint *ep; + uint16_t cmds_max = 32; + uint16_t conn_id = 0; + uint32_t initial_cmdsn = 0; + int ret = QLA_SUCCESS; + + struct ddb_entry *ddb_entry = NULL; + + /* Create session object, with INVALID_ENTRY, + * the targer_id would get set when we issue the login + */ + cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, ha->host, + cmds_max, sizeof(struct ddb_entry), + sizeof(struct ql4_task_data), + initial_cmdsn, INVALID_ENTRY); + if (!cls_sess) { + ret = QLA_ERROR; + goto exit_setup; + } + + /* + * so calling module_put function to decrement the + * reference count. + **/ + module_put(qla4xxx_iscsi_transport.owner); + sess = cls_sess->dd_data; + ddb_entry = sess->dd_data; + ddb_entry->sess = cls_sess; + + cls_sess->recovery_tmo = ql4xsess_recovery_tmo; + memcpy(&ddb_entry->fw_ddb_entry, fw_ddb_entry, + sizeof(struct dev_db_entry)); + + qla4xxx_setup_flash_ddb_entry(ha, ddb_entry); + + cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), conn_id); + + if (!cls_conn) { + ret = QLA_ERROR; + goto exit_setup; + } + + ddb_entry->conn = cls_conn; + + /* Setup ep, for displaying attributes in sysfs */ + ep = qla4xxx_get_ep_fwdb(ha, fw_ddb_entry); + if (ep) { + ep->conn = cls_conn; + cls_conn->ep = ep; + } else { + DEBUG2(ql4_printk(KERN_ERR, ha, "Unable to get ep\n")); + ret = QLA_ERROR; + goto exit_setup; + } + + /* Update sess/conn params */ + qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn); + + if (is_reset == RESET_ADAPTER) { + iscsi_block_session(cls_sess); + /* Use the relogin path to discover new devices + * by short-circuting the logic of setting + * timer to relogin - instead set the flags + * to initiate login right away. + */ + set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); + set_bit(DF_RELOGIN, &ddb_entry->flags); + } + +exit_setup: + return ret; +} + +static void qla4xxx_build_nt_list(struct scsi_qla_host *ha, + struct list_head *list_nt, int is_reset) +{ + struct dev_db_entry *fw_ddb_entry; + dma_addr_t fw_ddb_dma; + int max_ddbs; + int fw_idx_size; + int ret; + uint32_t idx = 0, next_idx = 0; + uint32_t state = 0, conn_err = 0; + uint16_t conn_id = 0; + struct qla_ddb_index *nt_ddb_idx; + + fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, + &fw_ddb_dma); + if (fw_ddb_entry == NULL) { + DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); + goto exit_nt_list; + } + max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : + MAX_DEV_DB_ENTRIES; + fw_idx_size = sizeof(struct qla_ddb_index); + + for (idx = 0; idx < max_ddbs; idx = next_idx) { + ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma, + NULL, &next_idx, &state, + &conn_err, NULL, &conn_id); + if (ret == QLA_ERROR) + break; + + if (qla4xxx_verify_boot_idx(ha, idx) != QLA_SUCCESS) + goto continue_next_nt; + + /* Check if NT, then add to list it */ + if (strlen((char *) fw_ddb_entry->iscsi_name) == 0) + goto continue_next_nt; + + if (!(state == DDB_DS_NO_CONNECTION_ACTIVE || + state == DDB_DS_SESSION_FAILED)) + goto continue_next_nt; + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Adding DDB to session = 0x%x\n", idx)); + if (is_reset == INIT_ADAPTER) { + nt_ddb_idx = vmalloc(fw_idx_size); + if (!nt_ddb_idx) + break; + + nt_ddb_idx->fw_ddb_idx = idx; + + memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry, + sizeof(struct dev_db_entry)); + + if (qla4xxx_is_flash_ddb_exists(ha, list_nt, + fw_ddb_entry) == QLA_SUCCESS) { + vfree(nt_ddb_idx); + goto continue_next_nt; + } + list_add_tail(&nt_ddb_idx->list, list_nt); + } else if (is_reset == RESET_ADAPTER) { + if (qla4xxx_is_session_exists(ha, fw_ddb_entry) == + QLA_SUCCESS) + goto continue_next_nt; + } + + ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, is_reset); + if (ret == QLA_ERROR) + goto exit_nt_list; + +continue_next_nt: + if (next_idx == 0) + break; + } + +exit_nt_list: + if (fw_ddb_entry) + dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); +} + +/** + * qla4xxx_build_ddb_list - Build ddb list and setup sessions + * @ha: pointer to adapter structure + * @is_reset: Is this init path or reset path + * + * Create a list of sendtargets (st) from firmware DDBs, issue send targets + * using connection open, then create the list of normal targets (nt) + * from firmware DDBs. Based on the list of nt setup session and connection + * objects. + **/ +void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset) +{ + uint16_t tmo = 0; + struct list_head list_st, list_nt; + struct qla_ddb_index *st_ddb_idx, *st_ddb_idx_tmp; + unsigned long wtime; + + if (!test_bit(AF_LINK_UP, &ha->flags)) { + set_bit(AF_BUILD_DDB_LIST, &ha->flags); + ha->is_reset = is_reset; + return; + } + + INIT_LIST_HEAD(&list_st); + INIT_LIST_HEAD(&list_nt); + + qla4xxx_build_st_list(ha, &list_st); + + /* Before issuing conn open mbox, ensure all IPs states are configured + * Note, conn open fails if IPs are not configured + */ + qla4xxx_wait_for_ip_configuration(ha); + + /* Go thru the STs and fire the sendtargets by issuing conn open mbx */ + list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) { + qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx); + } + + /* Wait to ensure all sendtargets are done for min 12 sec wait */ + tmo = ((ha->def_timeout > LOGIN_TOV) && + (ha->def_timeout < LOGIN_TOV * 10) ? + ha->def_timeout : LOGIN_TOV); + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Default time to wait for build ddb %d\n", tmo)); + + wtime = jiffies + (HZ * tmo); + do { + if (list_empty(&list_st)) + break; + + qla4xxx_remove_failed_ddb(ha, &list_st); + schedule_timeout_uninterruptible(HZ / 10); + } while (time_after(wtime, jiffies)); + + /* Free up the sendtargets list */ + qla4xxx_free_ddb_list(&list_st); + + qla4xxx_build_nt_list(ha, &list_nt, is_reset); + + qla4xxx_free_ddb_list(&list_nt); + + qla4xxx_free_ddb_index(ha); } /** @@ -3298,7 +4435,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, * firmware * NOTE: interrupts enabled upon successful completion */ - status = qla4xxx_initialize_adapter(ha); + status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER); while ((!test_bit(AF_ONLINE, &ha->flags)) && init_retry_count++ < MAX_INIT_RETRIES) { @@ -3319,7 +4456,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, if (ha->isp_ops->reset_chip(ha) == QLA_ERROR) continue; - status = qla4xxx_initialize_adapter(ha); + status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER); } if (!test_bit(AF_ONLINE, &ha->flags)) { @@ -3386,12 +4523,16 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, ha->host_no, ha->firmware_version[0], ha->firmware_version[1], ha->patch_number, ha->build_number); - qla4xxx_create_chap_list(ha); - if (qla4xxx_setup_boot_info(ha)) ql4_printk(KERN_ERR, ha, "%s:ISCSI boot info setup failed\n", __func__); + /* Perform the build ddb list and login to each */ + qla4xxx_build_ddb_list(ha, INIT_ADAPTER); + iscsi_host_for_each_session(ha->host, qla4xxx_login_flash_ddb); + + qla4xxx_create_chap_list(ha); + qla4xxx_create_ifaces(ha); return 0; @@ -3449,6 +4590,38 @@ static void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha) } } +static void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha) +{ + struct ddb_entry *ddb_entry; + int options; + int idx; + + for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) { + + ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); + if ((ddb_entry != NULL) && + (ddb_entry->ddb_type == FLASH_DDB)) { + + options = LOGOUT_OPTION_CLOSE_SESSION; + if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) + == QLA_ERROR) + ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", + __func__); + + qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index); + /* + * we have decremented the reference count of the driver + * when we setup the session to have the driver unload + * to be seamless without actually destroying the + * session + **/ + try_module_get(qla4xxx_iscsi_transport.owner); + iscsi_destroy_endpoint(ddb_entry->conn->ep); + qla4xxx_free_ddb(ha, ddb_entry); + iscsi_session_teardown(ddb_entry->sess); + } + } +} /** * qla4xxx_remove_adapter - calback function to remove adapter. * @pci_dev: PCI device pointer @@ -3465,9 +4638,11 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) /* destroy iface from sysfs */ qla4xxx_destroy_ifaces(ha); - if (ha->boot_kset) + if ((!ql4xdisablesysfsboot) && ha->boot_kset) iscsi_boot_destroy_kset(ha->boot_kset); + qla4xxx_destroy_fw_ddb_session(ha); + scsi_remove_host(ha->host); qla4xxx_free_adapter(ha); @@ -3840,6 +5015,20 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) } /** + * qla4xxx_is_eh_active - check if error handler is running + * @shost: Pointer to SCSI Host struct + * + * This routine finds that if reset host is called in EH + * scenario or from some application like sg_reset + **/ +static int qla4xxx_is_eh_active(struct Scsi_Host *shost) +{ + if (shost->shost_state == SHOST_RECOVERY) + return 1; + return 0; +} + +/** * qla4xxx_eh_host_reset - kernel callback * @cmd: Pointer to Linux's SCSI command structure * @@ -3856,6 +5045,11 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) if (ql4xdontresethba) { DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", ha->host_no, __func__)); + + /* Clear outstanding srb in queues */ + if (qla4xxx_is_eh_active(cmd->device->host)) + qla4xxx_abort_active_cmds(ha, DID_ABORT << 16); + return FAILED; } @@ -4115,7 +5309,7 @@ static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) qla4_8xxx_idc_unlock(ha); clear_bit(AF_FW_RECOVERY, &ha->flags); - rval = qla4xxx_initialize_adapter(ha); + rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); qla4_8xxx_idc_lock(ha); if (rval != QLA_SUCCESS) { @@ -4151,7 +5345,7 @@ static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) if ((qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE) == QLA82XX_DEV_READY)) { clear_bit(AF_FW_RECOVERY, &ha->flags); - rval = qla4xxx_initialize_adapter(ha); + rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); if (rval == QLA_SUCCESS) { ret = qla4xxx_request_irqs(ha); if (ret) { diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index c15347d3f53..133989b3a9f 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h @@ -5,4 +5,4 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ -#define QLA4XXX_DRIVER_VERSION "5.02.00-k8" +#define QLA4XXX_DRIVER_VERSION "5.02.00-k12" diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index dc6131e6a1b..5f84a148eb1 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1812,7 +1812,7 @@ int scsi_error_handler(void *data) * what we need to do to get it up and online again (if we can). * If we fail, we end up taking the thing offline. */ - if (scsi_autopm_get_host(shost) != 0) { + if (!shost->eh_noresume && scsi_autopm_get_host(shost) != 0) { SCSI_LOG_ERROR_RECOVERY(1, printk(KERN_ERR "Error handler scsi_eh_%d " "unable to autoresume\n", @@ -1833,7 +1833,8 @@ int scsi_error_handler(void *data) * which are still online. */ scsi_restart_operations(shost); - scsi_autopm_put_host(shost); + if (!shost->eh_noresume) + scsi_autopm_put_host(shost); set_current_state(TASK_INTERRUPTIBLE); } __set_current_state(TASK_RUNNING); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index f85cfa6c47b..b2c95dbe9d6 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1316,15 +1316,10 @@ static inline int scsi_target_queue_ready(struct Scsi_Host *shost, } if (scsi_target_is_busy(starget)) { - if (list_empty(&sdev->starved_entry)) - list_add_tail(&sdev->starved_entry, - &shost->starved_list); + list_move_tail(&sdev->starved_entry, &shost->starved_list); return 0; } - /* We're OK to process the command, so we can't be starved */ - if (!list_empty(&sdev->starved_entry)) - list_del_init(&sdev->starved_entry); return 1; } diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c index 44f76e8b58a..c77628afbf9 100644 --- a/drivers/scsi/scsi_netlink.c +++ b/drivers/scsi/scsi_netlink.c @@ -112,7 +112,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb) goto next_msg; } - if (security_netlink_recv(skb, CAP_SYS_ADMIN)) { + if (!capable(CAP_SYS_ADMIN)) { err = -EPERM; goto next_msg; } diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index d329f8b12e2..c4670642d02 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c @@ -7,6 +7,7 @@ #include <linux/pm_runtime.h> #include <linux/export.h> +#include <linux/async.h> #include <scsi/scsi.h> #include <scsi/scsi_device.h> @@ -49,8 +50,22 @@ static int scsi_bus_suspend_common(struct device *dev, pm_message_t msg) { int err = 0; - if (scsi_is_sdev_device(dev)) + if (scsi_is_sdev_device(dev)) { + /* + * sd is the only high-level SCSI driver to implement runtime + * PM, and sd treats runtime suspend, system suspend, and + * system hibernate identically (but not system freeze). + */ + if (pm_runtime_suspended(dev)) { + if (msg.event == PM_EVENT_SUSPEND || + msg.event == PM_EVENT_HIBERNATE) + return 0; /* already suspended */ + + /* wake up device so that FREEZE will succeed */ + pm_runtime_resume(dev); + } err = scsi_dev_type_suspend(dev, msg); + } return err; } @@ -58,8 +73,17 @@ static int scsi_bus_resume_common(struct device *dev) { int err = 0; - if (scsi_is_sdev_device(dev)) + if (scsi_is_sdev_device(dev)) { + /* + * Parent device may have runtime suspended as soon as + * it is woken up during the system resume. + * + * Resume it on behalf of child. + */ + pm_runtime_get_sync(dev->parent); err = scsi_dev_type_resume(dev); + pm_runtime_put_sync(dev->parent); + } if (err == 0) { pm_runtime_disable(dev); @@ -69,6 +93,19 @@ static int scsi_bus_resume_common(struct device *dev) return err; } +static int scsi_bus_prepare(struct device *dev) +{ + if (scsi_is_sdev_device(dev)) { + /* sd probing uses async_schedule. Wait until it finishes. */ + async_synchronize_full(); + + } else if (scsi_is_host_device(dev)) { + /* Wait until async scanning is finished */ + scsi_complete_async_scans(); + } + return 0; +} + static int scsi_bus_suspend(struct device *dev) { return scsi_bus_suspend_common(dev, PMSG_SUSPEND); @@ -87,6 +124,7 @@ static int scsi_bus_poweroff(struct device *dev) #else /* CONFIG_PM_SLEEP */ #define scsi_bus_resume_common NULL +#define scsi_bus_prepare NULL #define scsi_bus_suspend NULL #define scsi_bus_freeze NULL #define scsi_bus_poweroff NULL @@ -195,6 +233,7 @@ void scsi_autopm_put_host(struct Scsi_Host *shost) #endif /* CONFIG_PM_RUNTIME */ const struct dev_pm_ops scsi_bus_pm_ops = { + .prepare = scsi_bus_prepare, .suspend = scsi_bus_suspend, .resume = scsi_bus_resume_common, .freeze = scsi_bus_freeze, diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 2a588955423..be4fa6d179b 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -45,7 +45,6 @@ static inline void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) enum { SCSI_DEVINFO_GLOBAL = 0, SCSI_DEVINFO_SPI, - SCSI_DEVINFO_DH, }; extern int scsi_get_device_flags(struct scsi_device *sdev, @@ -110,6 +109,7 @@ extern void scsi_exit_procfs(void); #endif /* CONFIG_PROC_FS */ /* scsi_scan.c */ +extern int scsi_complete_async_scans(void); extern int scsi_scan_host_selected(struct Scsi_Host *, unsigned int, unsigned int, unsigned int, int); extern void scsi_forget_host(struct Scsi_Host *); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index b3c6d957fbd..29c4c048097 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -297,7 +297,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, kfree(sdev); goto out; } - blk_get_queue(sdev->request_queue); + WARN_ON_ONCE(!blk_get_queue(sdev->request_queue)); sdev->request_queue->queuedata = sdev; scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); @@ -1815,6 +1815,7 @@ static void scsi_finish_async_scan(struct async_scan_data *data) } spin_unlock(&async_scan_lock); + scsi_autopm_put_host(shost); scsi_host_put(shost); kfree(data); } @@ -1841,7 +1842,6 @@ static int do_scan_async(void *_data) do_scsi_scan_host(shost); scsi_finish_async_scan(data); - scsi_autopm_put_host(shost); return 0; } @@ -1869,7 +1869,7 @@ void scsi_scan_host(struct Scsi_Host *shost) p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no); if (IS_ERR(p)) do_scan_async(data); - /* scsi_autopm_put_host(shost) is called in do_scan_async() */ + /* scsi_autopm_put_host(shost) is called in scsi_finish_async_scan() */ } EXPORT_SYMBOL(scsi_scan_host); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 1b214910b71..f59d4a05ecd 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -3048,7 +3048,8 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) spin_lock_irqsave(shost->host_lock, flags); rport->flags &= ~(FC_RPORT_FAST_FAIL_TIMEDOUT | - FC_RPORT_DEVLOSS_PENDING); + FC_RPORT_DEVLOSS_PENDING | + FC_RPORT_DEVLOSS_CALLBK_DONE); spin_unlock_irqrestore(shost->host_lock, flags); /* ensure any stgt delete functions are done */ diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 96029e6d027..cfd49143723 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -328,7 +328,7 @@ iscsi_iface_net_attr(iface, vlan_enabled, ISCSI_NET_PARAM_VLAN_ENABLED); iscsi_iface_net_attr(iface, mtu, ISCSI_NET_PARAM_MTU); iscsi_iface_net_attr(iface, port, ISCSI_NET_PARAM_PORT); -static mode_t iscsi_iface_attr_is_visible(struct kobject *kobj, +static umode_t iscsi_iface_attr_is_visible(struct kobject *kobj, struct attribute *attr, int i) { struct device *dev = container_of(kobj, struct device, kobj); @@ -1030,6 +1030,7 @@ iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport, return NULL; session->transport = transport; + session->creator = -1; session->recovery_tmo = 120; session->state = ISCSI_SESSION_FREE; INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); @@ -1634,8 +1635,9 @@ EXPORT_SYMBOL_GPL(iscsi_session_event); static int iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_endpoint *ep, - struct iscsi_uevent *ev, uint32_t initial_cmdsn, - uint16_t cmds_max, uint16_t queue_depth) + struct iscsi_uevent *ev, pid_t pid, + uint32_t initial_cmdsn, uint16_t cmds_max, + uint16_t queue_depth) { struct iscsi_transport *transport = priv->iscsi_transport; struct iscsi_cls_session *session; @@ -1646,6 +1648,7 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_endpoint *ep, if (!session) return -ENOMEM; + session->creator = pid; shost = iscsi_session_to_shost(session); ev->r.c_session_ret.host_no = shost->host_no; ev->r.c_session_ret.sid = session->sid; @@ -1938,6 +1941,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) switch (nlh->nlmsg_type) { case ISCSI_UEVENT_CREATE_SESSION: err = iscsi_if_create_session(priv, ep, ev, + NETLINK_CREDS(skb)->pid, ev->u.c_session.initial_cmdsn, ev->u.c_session.cmds_max, ev->u.c_session.queue_depth); @@ -1950,6 +1954,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) } err = iscsi_if_create_session(priv, ep, ev, + NETLINK_CREDS(skb)->pid, ev->u.c_bound_session.initial_cmdsn, ev->u.c_bound_session.cmds_max, ev->u.c_bound_session.queue_depth); @@ -2199,7 +2204,7 @@ static struct attribute *iscsi_conn_attrs[] = { NULL, }; -static mode_t iscsi_conn_attr_is_visible(struct kobject *kobj, +static umode_t iscsi_conn_attr_is_visible(struct kobject *kobj, struct attribute *attr, int i) { struct device *cdev = container_of(kobj, struct device, kobj); @@ -2298,6 +2303,15 @@ show_priv_session_state(struct device *dev, struct device_attribute *attr, } static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state, NULL); +static ssize_t +show_priv_session_creator(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent); + return sprintf(buf, "%d\n", session->creator); +} +static ISCSI_CLASS_ATTR(priv_sess, creator, S_IRUGO, show_priv_session_creator, + NULL); #define iscsi_priv_session_attr_show(field, format) \ static ssize_t \ @@ -2367,10 +2381,11 @@ static struct attribute *iscsi_session_attrs[] = { &dev_attr_sess_targetalias.attr, &dev_attr_priv_sess_recovery_tmo.attr, &dev_attr_priv_sess_state.attr, + &dev_attr_priv_sess_creator.attr, NULL, }; -static mode_t iscsi_session_attr_is_visible(struct kobject *kobj, +static umode_t iscsi_session_attr_is_visible(struct kobject *kobj, struct attribute *attr, int i) { struct device *cdev = container_of(kobj, struct device, kobj); @@ -2424,6 +2439,8 @@ static mode_t iscsi_session_attr_is_visible(struct kobject *kobj, return S_IRUGO | S_IWUSR; else if (attr == &dev_attr_priv_sess_state.attr) return S_IRUGO; + else if (attr == &dev_attr_priv_sess_creator.attr) + return S_IRUGO; else { WARN_ONCE(1, "Invalid session attr"); return 0; @@ -2468,7 +2485,7 @@ static struct attribute *iscsi_host_attrs[] = { NULL, }; -static mode_t iscsi_host_attr_is_visible(struct kobject *kobj, +static umode_t iscsi_host_attr_is_visible(struct kobject *kobj, struct attribute *attr, int i) { struct device *cdev = container_of(kobj, struct device, kobj); diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 5fbeadd9681..a2715c31e75 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -1434,7 +1434,7 @@ static int spi_host_configure(struct transport_container *tc, (si->f->show_##name ? S_IRUGO : 0) | \ (si->f->set_##name ? S_IWUSR : 0) -static mode_t target_attribute_is_visible(struct kobject *kobj, +static umode_t target_attribute_is_visible(struct kobject *kobj, struct attribute *attr, int i) { struct device *cdev = container_of(kobj, struct device, kobj); diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c index 6803b1e26ec..92d24d6dcb3 100644 --- a/drivers/scsi/scsicam.c +++ b/drivers/scsi/scsicam.c @@ -16,7 +16,6 @@ #include <linux/genhd.h> #include <linux/kernel.h> #include <linux/blkdev.h> -#include <linux/buffer_head.h> #include <asm/unaligned.h> #include <scsi/scsicam.h> diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index fa3a5918009..c691fb50e6c 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -50,6 +50,7 @@ #include <linux/string_helpers.h> #include <linux/async.h> #include <linux/slab.h> +#include <linux/pm_runtime.h> #include <asm/uaccess.h> #include <asm/unaligned.h> @@ -1074,6 +1075,10 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, " "cmd=0x%x\n", disk->disk_name, cmd)); + error = scsi_verify_blk_ioctl(bdev, cmd); + if (error < 0) + return error; + /* * If we are in the middle of error recovery, don't let anyone * else try and use this device. Also, if error recovery fails, it @@ -1096,7 +1101,7 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, error = scsi_ioctl(sdp, cmd, p); break; default: - error = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, p); + error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p); if (error != -ENOTTY) break; error = scsi_ioctl(sdp, cmd, p); @@ -1266,6 +1271,11 @@ static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device; + int ret; + + ret = scsi_verify_blk_ioctl(bdev, cmd); + if (ret < 0) + return ret; /* * If we are in the middle of error recovery, don't let anyone @@ -1277,8 +1287,6 @@ static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode, return -ENODEV; if (sdev->host->hostt->compat_ioctl) { - int ret; - ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg); return ret; @@ -2741,6 +2749,9 @@ static void sd_shutdown(struct device *dev) if (!sdkp) return; /* this can happen */ + if (pm_runtime_suspended(dev)) + goto exit; + if (sdkp->WCE) { sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); sd_sync_cache(sdkp); @@ -2751,6 +2762,7 @@ static void sd_shutdown(struct device *dev) sd_start_stop_device(sdkp, 0); } +exit: scsi_disk_put(sdkp); } diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 441a1c5b897..eacd46bb36b 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -2325,16 +2325,15 @@ static struct sg_proc_leaf sg_proc_leaf_arr[] = { static int sg_proc_init(void) { - int k, mask; int num_leaves = ARRAY_SIZE(sg_proc_leaf_arr); - struct sg_proc_leaf * leaf; + int k; sg_proc_sgp = proc_mkdir(sg_proc_sg_dirname, NULL); if (!sg_proc_sgp) return 1; for (k = 0; k < num_leaves; ++k) { - leaf = &sg_proc_leaf_arr[k]; - mask = leaf->fops->write ? S_IRUGO | S_IWUSR : S_IRUGO; + struct sg_proc_leaf *leaf = &sg_proc_leaf_arr[k]; + umode_t mask = leaf->fops->write ? S_IRUGO | S_IWUSR : S_IRUGO; proc_create(leaf->name, mask, sg_proc_sgp, leaf->fops); } return 0; @@ -2369,16 +2368,15 @@ static ssize_t sg_proc_write_adio(struct file *filp, const char __user *buffer, size_t count, loff_t *off) { - int num; - char buff[11]; + int err; + unsigned long num; if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; - num = (count < 10) ? count : 10; - if (copy_from_user(buff, buffer, num)) - return -EFAULT; - buff[num] = '\0'; - sg_allow_dio = simple_strtoul(buff, NULL, 10) ? 1 : 0; + err = kstrtoul_from_user(buffer, count, 0, &num); + if (err) + return err; + sg_allow_dio = num ? 1 : 0; return count; } @@ -2391,17 +2389,15 @@ static ssize_t sg_proc_write_dressz(struct file *filp, const char __user *buffer, size_t count, loff_t *off) { - int num; + int err; unsigned long k = ULONG_MAX; - char buff[11]; if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; - num = (count < 10) ? count : 10; - if (copy_from_user(buff, buffer, num)) - return -EFAULT; - buff[num] = '\0'; - k = simple_strtoul(buff, NULL, 10); + + err = kstrtoul_from_user(buffer, count, 0, &k); + if (err) + return err; if (k <= 1048576) { /* limit "big buff" to 1 MB */ sg_big_buff = k; return count; diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c index 9acc2b2a360..cf51432f8e7 100644 --- a/drivers/scsi/sni_53c710.c +++ b/drivers/scsi/sni_53c710.c @@ -51,7 +51,7 @@ #include "53c700.h" -MODULE_AUTHOR("Thomas Bogendörfer"); +MODULE_AUTHOR("Thomas Bogendörfer"); MODULE_DESCRIPTION("SNI RM 53c710 SCSI Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:snirm_53c710"); diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index b4543f575f4..36d1ed7817e 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -839,6 +839,10 @@ static void sym53c8xx_slave_destroy(struct scsi_device *sdev) struct sym_lcb *lp = sym_lp(tp, sdev->lun); unsigned long flags; + /* if slave_alloc returned before allocating a sym_lcb, return */ + if (!lp) + return; + spin_lock_irqsave(np->s.host->host_lock, flags); if (lp->busy_itlq || lp->busy_itl) { diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index a18996d2446..7264116185d 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -1144,7 +1144,7 @@ static void pvscsi_release_resources(struct pvscsi_adapter *adapter) * * These are statically allocated. Trying to be clever was not worth it. * - * Dynamic allocation can fail, and we can't go deeep into the memory + * Dynamic allocation can fail, and we can't go deep into the memory * allocator, since we're a SCSI driver, and trying too hard to allocate * memory might generate disk I/O. We also don't want to fail disk I/O * in that case because we can't get an allocation - the I/O could be |