diff options
-rw-r--r-- | drivers/scsi/bfa/bfa_core.c | 12 | ||||
-rw-r--r-- | drivers/scsi/bfa/bfa_fcs.c | 133 | ||||
-rw-r--r-- | drivers/scsi/bfa/bfa_fcs.h | 8 | ||||
-rw-r--r-- | drivers/scsi/bfa/bfa_fcs_lport.c | 28 | ||||
-rw-r--r-- | drivers/scsi/bfa/bfa_ioc.c | 24 | ||||
-rw-r--r-- | drivers/scsi/bfa/bfa_ioc.h | 2 | ||||
-rw-r--r-- | drivers/scsi/bfa/bfa_svc.c | 4 | ||||
-rw-r--r-- | drivers/scsi/bfa/bfa_svc.h | 1 | ||||
-rw-r--r-- | drivers/scsi/bfa/bfad.c | 232 | ||||
-rw-r--r-- | drivers/scsi/bfa/bfad_drv.h | 3 | ||||
-rw-r--r-- | drivers/scsi/bfa/bfad_im.c | 9 |
11 files changed, 434 insertions, 22 deletions
diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c index 456e5762977..a4129c929f2 100644 --- a/drivers/scsi/bfa/bfa_core.c +++ b/drivers/scsi/bfa/bfa_core.c | |||
@@ -1022,7 +1022,7 @@ bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg) | |||
1022 | { | 1022 | { |
1023 | u8 *dm_kva = NULL; | 1023 | u8 *dm_kva = NULL; |
1024 | u64 dm_pa = 0; | 1024 | u64 dm_pa = 0; |
1025 | int i, per_reqq_sz, per_rspq_sz, dbgsz; | 1025 | int i, per_reqq_sz, per_rspq_sz; |
1026 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; | 1026 | struct bfa_iocfc_s *iocfc = &bfa->iocfc; |
1027 | struct bfa_mem_dma_s *ioc_dma = BFA_MEM_IOC_DMA(bfa); | 1027 | struct bfa_mem_dma_s *ioc_dma = BFA_MEM_IOC_DMA(bfa); |
1028 | struct bfa_mem_dma_s *iocfc_dma = BFA_MEM_IOCFC_DMA(bfa); | 1028 | struct bfa_mem_dma_s *iocfc_dma = BFA_MEM_IOCFC_DMA(bfa); |
@@ -1083,11 +1083,8 @@ bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg) | |||
1083 | BFA_CACHELINE_SZ); | 1083 | BFA_CACHELINE_SZ); |
1084 | 1084 | ||
1085 | /* Claim IOCFC kva memory */ | 1085 | /* Claim IOCFC kva memory */ |
1086 | dbgsz = (bfa_auto_recover) ? BFA_DBG_FWTRC_LEN : 0; | 1086 | bfa_ioc_debug_memclaim(&bfa->ioc, bfa_mem_kva_curp(iocfc)); |
1087 | if (dbgsz > 0) { | 1087 | bfa_mem_kva_curp(iocfc) += BFA_DBG_FWTRC_LEN; |
1088 | bfa_ioc_debug_memclaim(&bfa->ioc, bfa_mem_kva_curp(iocfc)); | ||
1089 | bfa_mem_kva_curp(iocfc) += dbgsz; | ||
1090 | } | ||
1091 | } | 1088 | } |
1092 | 1089 | ||
1093 | /* | 1090 | /* |
@@ -1429,8 +1426,7 @@ bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, | |||
1429 | bfa_mem_dma_setup(meminfo, iocfc_dma, dm_len); | 1426 | bfa_mem_dma_setup(meminfo, iocfc_dma, dm_len); |
1430 | 1427 | ||
1431 | /* kva memory setup for IOCFC */ | 1428 | /* kva memory setup for IOCFC */ |
1432 | bfa_mem_kva_setup(meminfo, iocfc_kva, | 1429 | bfa_mem_kva_setup(meminfo, iocfc_kva, BFA_DBG_FWTRC_LEN); |
1433 | ((bfa_auto_recover) ? BFA_DBG_FWTRC_LEN : 0)); | ||
1434 | } | 1430 | } |
1435 | 1431 | ||
1436 | /* | 1432 | /* |
diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c index 3f71d504e39..671a1a227f9 100644 --- a/drivers/scsi/bfa/bfa_fcs.c +++ b/drivers/scsi/bfa/bfa_fcs.c | |||
@@ -119,6 +119,18 @@ bfa_fcs_update_cfg(struct bfa_fcs_s *fcs) | |||
119 | } | 119 | } |
120 | 120 | ||
121 | /* | 121 | /* |
122 | * Stop FCS operations. | ||
123 | */ | ||
124 | void | ||
125 | bfa_fcs_stop(struct bfa_fcs_s *fcs) | ||
126 | { | ||
127 | bfa_wc_init(&fcs->wc, bfa_fcs_exit_comp, fcs); | ||
128 | bfa_wc_up(&fcs->wc); | ||
129 | bfa_fcs_fabric_modstop(fcs); | ||
130 | bfa_wc_wait(&fcs->wc); | ||
131 | } | ||
132 | |||
133 | /* | ||
122 | * fcs pbc vport initialization | 134 | * fcs pbc vport initialization |
123 | */ | 135 | */ |
124 | void | 136 | void |
@@ -213,6 +225,8 @@ static void bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric); | |||
213 | static void bfa_fcs_fabric_delay(void *cbarg); | 225 | static void bfa_fcs_fabric_delay(void *cbarg); |
214 | static void bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric); | 226 | static void bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric); |
215 | static void bfa_fcs_fabric_delete_comp(void *cbarg); | 227 | static void bfa_fcs_fabric_delete_comp(void *cbarg); |
228 | static void bfa_fcs_fabric_stop(struct bfa_fcs_fabric_s *fabric); | ||
229 | static void bfa_fcs_fabric_stop_comp(void *cbarg); | ||
216 | static void bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric, | 230 | static void bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric, |
217 | struct fchs_s *fchs, u16 len); | 231 | struct fchs_s *fchs, u16 len); |
218 | static void bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric, | 232 | static void bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric, |
@@ -250,6 +264,10 @@ static void bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric, | |||
250 | enum bfa_fcs_fabric_event event); | 264 | enum bfa_fcs_fabric_event event); |
251 | static void bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric, | 265 | static void bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric, |
252 | enum bfa_fcs_fabric_event event); | 266 | enum bfa_fcs_fabric_event event); |
267 | static void bfa_fcs_fabric_sm_stopping(struct bfa_fcs_fabric_s *fabric, | ||
268 | enum bfa_fcs_fabric_event event); | ||
269 | static void bfa_fcs_fabric_sm_cleanup(struct bfa_fcs_fabric_s *fabric, | ||
270 | enum bfa_fcs_fabric_event event); | ||
253 | /* | 271 | /* |
254 | * Beginning state before fabric creation. | 272 | * Beginning state before fabric creation. |
255 | */ | 273 | */ |
@@ -334,6 +352,11 @@ bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric, | |||
334 | bfa_fcs_fabric_delete(fabric); | 352 | bfa_fcs_fabric_delete(fabric); |
335 | break; | 353 | break; |
336 | 354 | ||
355 | case BFA_FCS_FABRIC_SM_STOP: | ||
356 | bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_cleanup); | ||
357 | bfa_fcs_fabric_stop(fabric); | ||
358 | break; | ||
359 | |||
337 | default: | 360 | default: |
338 | bfa_sm_fault(fabric->fcs, event); | 361 | bfa_sm_fault(fabric->fcs, event); |
339 | } | 362 | } |
@@ -585,6 +608,11 @@ bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric, | |||
585 | bfa_fcs_fabric_delete(fabric); | 608 | bfa_fcs_fabric_delete(fabric); |
586 | break; | 609 | break; |
587 | 610 | ||
611 | case BFA_FCS_FABRIC_SM_STOP: | ||
612 | bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_stopping); | ||
613 | bfa_fcs_fabric_stop(fabric); | ||
614 | break; | ||
615 | |||
588 | case BFA_FCS_FABRIC_SM_AUTH_FAILED: | 616 | case BFA_FCS_FABRIC_SM_AUTH_FAILED: |
589 | bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed); | 617 | bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed); |
590 | bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE); | 618 | bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE); |
@@ -682,7 +710,62 @@ bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric, | |||
682 | } | 710 | } |
683 | } | 711 | } |
684 | 712 | ||
713 | /* | ||
714 | * Fabric is being stopped, awaiting vport stop completions. | ||
715 | */ | ||
716 | static void | ||
717 | bfa_fcs_fabric_sm_stopping(struct bfa_fcs_fabric_s *fabric, | ||
718 | enum bfa_fcs_fabric_event event) | ||
719 | { | ||
720 | bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); | ||
721 | bfa_trc(fabric->fcs, event); | ||
722 | |||
723 | switch (event) { | ||
724 | case BFA_FCS_FABRIC_SM_STOPCOMP: | ||
725 | bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_cleanup); | ||
726 | bfa_sm_send_event(fabric->lps, BFA_LPS_SM_LOGOUT); | ||
727 | break; | ||
728 | |||
729 | case BFA_FCS_FABRIC_SM_LINK_UP: | ||
730 | break; | ||
731 | |||
732 | case BFA_FCS_FABRIC_SM_LINK_DOWN: | ||
733 | bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_cleanup); | ||
734 | break; | ||
735 | |||
736 | default: | ||
737 | bfa_sm_fault(fabric->fcs, event); | ||
738 | } | ||
739 | } | ||
740 | |||
741 | /* | ||
742 | * Fabric is being stopped, cleanup without FLOGO | ||
743 | */ | ||
744 | static void | ||
745 | bfa_fcs_fabric_sm_cleanup(struct bfa_fcs_fabric_s *fabric, | ||
746 | enum bfa_fcs_fabric_event event) | ||
747 | { | ||
748 | bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); | ||
749 | bfa_trc(fabric->fcs, event); | ||
750 | |||
751 | switch (event) { | ||
752 | case BFA_FCS_FABRIC_SM_STOPCOMP: | ||
753 | case BFA_FCS_FABRIC_SM_LOGOCOMP: | ||
754 | bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_created); | ||
755 | bfa_wc_down(&(fabric->fcs)->wc); | ||
756 | break; | ||
757 | |||
758 | case BFA_FCS_FABRIC_SM_LINK_DOWN: | ||
759 | /* | ||
760 | * Ignore - can get this event if we get notified about IOC down | ||
761 | * before the fabric completion callbk is done. | ||
762 | */ | ||
763 | break; | ||
685 | 764 | ||
765 | default: | ||
766 | bfa_sm_fault(fabric->fcs, event); | ||
767 | } | ||
768 | } | ||
686 | 769 | ||
687 | /* | 770 | /* |
688 | * fcs_fabric_private fabric private functions | 771 | * fcs_fabric_private fabric private functions |
@@ -919,6 +1002,28 @@ bfa_fcs_fabric_delay(void *cbarg) | |||
919 | } | 1002 | } |
920 | 1003 | ||
921 | /* | 1004 | /* |
1005 | * Stop all vports and wait for vport stop completions. | ||
1006 | */ | ||
1007 | static void | ||
1008 | bfa_fcs_fabric_stop(struct bfa_fcs_fabric_s *fabric) | ||
1009 | { | ||
1010 | struct bfa_fcs_vport_s *vport; | ||
1011 | struct list_head *qe, *qen; | ||
1012 | |||
1013 | bfa_wc_init(&fabric->stop_wc, bfa_fcs_fabric_stop_comp, fabric); | ||
1014 | |||
1015 | list_for_each_safe(qe, qen, &fabric->vport_q) { | ||
1016 | vport = (struct bfa_fcs_vport_s *) qe; | ||
1017 | bfa_wc_up(&fabric->stop_wc); | ||
1018 | bfa_fcs_vport_fcs_stop(vport); | ||
1019 | } | ||
1020 | |||
1021 | bfa_wc_up(&fabric->stop_wc); | ||
1022 | bfa_fcs_lport_stop(&fabric->bport); | ||
1023 | bfa_wc_wait(&fabric->stop_wc); | ||
1024 | } | ||
1025 | |||
1026 | /* | ||
922 | * Computes operating BB_SCN value | 1027 | * Computes operating BB_SCN value |
923 | */ | 1028 | */ |
924 | static u8 | 1029 | static u8 |
@@ -978,6 +1083,14 @@ bfa_fcs_fabric_delete_comp(void *cbarg) | |||
978 | bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELCOMP); | 1083 | bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELCOMP); |
979 | } | 1084 | } |
980 | 1085 | ||
1086 | static void | ||
1087 | bfa_fcs_fabric_stop_comp(void *cbarg) | ||
1088 | { | ||
1089 | struct bfa_fcs_fabric_s *fabric = cbarg; | ||
1090 | |||
1091 | bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_STOPCOMP); | ||
1092 | } | ||
1093 | |||
981 | /* | 1094 | /* |
982 | * fcs_fabric_public fabric public functions | 1095 | * fcs_fabric_public fabric public functions |
983 | */ | 1096 | */ |
@@ -1039,6 +1152,19 @@ bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs) | |||
1039 | } | 1152 | } |
1040 | 1153 | ||
1041 | /* | 1154 | /* |
1155 | * Fabric module stop -- stop FCS actions | ||
1156 | */ | ||
1157 | void | ||
1158 | bfa_fcs_fabric_modstop(struct bfa_fcs_s *fcs) | ||
1159 | { | ||
1160 | struct bfa_fcs_fabric_s *fabric; | ||
1161 | |||
1162 | bfa_trc(fcs, 0); | ||
1163 | fabric = &fcs->fabric; | ||
1164 | bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_STOP); | ||
1165 | } | ||
1166 | |||
1167 | /* | ||
1042 | * Fabric module start -- kick starts FCS actions | 1168 | * Fabric module start -- kick starts FCS actions |
1043 | */ | 1169 | */ |
1044 | void | 1170 | void |
@@ -1387,6 +1513,13 @@ bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric, | |||
1387 | } | 1513 | } |
1388 | } | 1514 | } |
1389 | 1515 | ||
1516 | void | ||
1517 | bfa_cb_lps_flogo_comp(void *bfad, void *uarg) | ||
1518 | { | ||
1519 | struct bfa_fcs_fabric_s *fabric = uarg; | ||
1520 | bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LOGOCOMP); | ||
1521 | } | ||
1522 | |||
1390 | /* | 1523 | /* |
1391 | * Returns FCS vf structure for a given vf_id. | 1524 | * Returns FCS vf structure for a given vf_id. |
1392 | * | 1525 | * |
diff --git a/drivers/scsi/bfa/bfa_fcs.h b/drivers/scsi/bfa/bfa_fcs.h index 10c93bf0984..b64ca35bf6f 100644 --- a/drivers/scsi/bfa/bfa_fcs.h +++ b/drivers/scsi/bfa/bfa_fcs.h | |||
@@ -205,6 +205,7 @@ struct bfa_fcs_fabric_s { | |||
205 | struct bfa_lps_s *lps; /* lport login services */ | 205 | struct bfa_lps_s *lps; /* lport login services */ |
206 | u8 fabric_ip_addr[BFA_FCS_FABRIC_IPADDR_SZ]; | 206 | u8 fabric_ip_addr[BFA_FCS_FABRIC_IPADDR_SZ]; |
207 | /* attached fabric's ip addr */ | 207 | /* attached fabric's ip addr */ |
208 | struct bfa_wc_s stop_wc; /* wait counter for stop */ | ||
208 | }; | 209 | }; |
209 | 210 | ||
210 | #define bfa_fcs_fabric_npiv_capable(__f) ((__f)->is_npiv) | 211 | #define bfa_fcs_fabric_npiv_capable(__f) ((__f)->is_npiv) |
@@ -323,6 +324,7 @@ void bfa_fcs_lport_init(struct bfa_fcs_lport_s *lport, | |||
323 | void bfa_fcs_lport_online(struct bfa_fcs_lport_s *port); | 324 | void bfa_fcs_lport_online(struct bfa_fcs_lport_s *port); |
324 | void bfa_fcs_lport_offline(struct bfa_fcs_lport_s *port); | 325 | void bfa_fcs_lport_offline(struct bfa_fcs_lport_s *port); |
325 | void bfa_fcs_lport_delete(struct bfa_fcs_lport_s *port); | 326 | void bfa_fcs_lport_delete(struct bfa_fcs_lport_s *port); |
327 | void bfa_fcs_lport_stop(struct bfa_fcs_lport_s *port); | ||
326 | struct bfa_fcs_rport_s *bfa_fcs_lport_get_rport_by_pid( | 328 | struct bfa_fcs_rport_s *bfa_fcs_lport_get_rport_by_pid( |
327 | struct bfa_fcs_lport_s *port, u32 pid); | 329 | struct bfa_fcs_lport_s *port, u32 pid); |
328 | struct bfa_fcs_rport_s *bfa_fcs_lport_get_rport_by_old_pid( | 330 | struct bfa_fcs_rport_s *bfa_fcs_lport_get_rport_by_old_pid( |
@@ -387,6 +389,7 @@ void bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport); | |||
387 | void bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport); | 389 | void bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport); |
388 | void bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport); | 390 | void bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport); |
389 | void bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport); | 391 | void bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport); |
392 | void bfa_fcs_vport_fcs_stop(struct bfa_fcs_vport_s *vport); | ||
390 | void bfa_fcs_vport_stop_comp(struct bfa_fcs_vport_s *vport); | 393 | void bfa_fcs_vport_stop_comp(struct bfa_fcs_vport_s *vport); |
391 | 394 | ||
392 | #define BFA_FCS_RPORT_DEF_DEL_TIMEOUT 90 /* in secs */ | 395 | #define BFA_FCS_RPORT_DEF_DEL_TIMEOUT 90 /* in secs */ |
@@ -709,6 +712,9 @@ enum bfa_fcs_fabric_event { | |||
709 | BFA_FCS_FABRIC_SM_DELCOMP = 14, /* all vports deleted event */ | 712 | BFA_FCS_FABRIC_SM_DELCOMP = 14, /* all vports deleted event */ |
710 | BFA_FCS_FABRIC_SM_LOOPBACK = 15, /* Received our own FLOGI */ | 713 | BFA_FCS_FABRIC_SM_LOOPBACK = 15, /* Received our own FLOGI */ |
711 | BFA_FCS_FABRIC_SM_START = 16, /* from driver */ | 714 | BFA_FCS_FABRIC_SM_START = 16, /* from driver */ |
715 | BFA_FCS_FABRIC_SM_STOP = 17, /* Stop from driver */ | ||
716 | BFA_FCS_FABRIC_SM_STOPCOMP = 18, /* Stop completion */ | ||
717 | BFA_FCS_FABRIC_SM_LOGOCOMP = 19, /* FLOGO completion */ | ||
712 | }; | 718 | }; |
713 | 719 | ||
714 | /* | 720 | /* |
@@ -748,6 +754,7 @@ void bfa_fcs_update_cfg(struct bfa_fcs_s *fcs); | |||
748 | void bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs, | 754 | void bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs, |
749 | struct bfa_fcs_driver_info_s *driver_info); | 755 | struct bfa_fcs_driver_info_s *driver_info); |
750 | void bfa_fcs_exit(struct bfa_fcs_s *fcs); | 756 | void bfa_fcs_exit(struct bfa_fcs_s *fcs); |
757 | void bfa_fcs_stop(struct bfa_fcs_s *fcs); | ||
751 | 758 | ||
752 | /* | 759 | /* |
753 | * bfa fcs vf public functions | 760 | * bfa fcs vf public functions |
@@ -778,6 +785,7 @@ void bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric, | |||
778 | u16 bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric); | 785 | u16 bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric); |
779 | void bfa_fcs_uf_attach(struct bfa_fcs_s *fcs); | 786 | void bfa_fcs_uf_attach(struct bfa_fcs_s *fcs); |
780 | void bfa_fcs_port_attach(struct bfa_fcs_s *fcs); | 787 | void bfa_fcs_port_attach(struct bfa_fcs_s *fcs); |
788 | void bfa_fcs_fabric_modstop(struct bfa_fcs_s *fcs); | ||
781 | void bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric, | 789 | void bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric, |
782 | enum bfa_fcs_fabric_event event); | 790 | enum bfa_fcs_fabric_event event); |
783 | void bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric, | 791 | void bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric, |
diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c index e5661703d46..3c9bde9a808 100644 --- a/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/drivers/scsi/bfa/bfa_fcs_lport.c | |||
@@ -131,6 +131,8 @@ bfa_fcs_lport_sm_init(struct bfa_fcs_lport_s *port, | |||
131 | /* If vport - send completion call back */ | 131 | /* If vport - send completion call back */ |
132 | if (port->vport) | 132 | if (port->vport) |
133 | bfa_fcs_vport_stop_comp(port->vport); | 133 | bfa_fcs_vport_stop_comp(port->vport); |
134 | else | ||
135 | bfa_wc_down(&(port->fabric->stop_wc)); | ||
134 | break; | 136 | break; |
135 | 137 | ||
136 | case BFA_FCS_PORT_SM_OFFLINE: | 138 | case BFA_FCS_PORT_SM_OFFLINE: |
@@ -166,6 +168,8 @@ bfa_fcs_lport_sm_online( | |||
166 | /* If vport - send completion call back */ | 168 | /* If vport - send completion call back */ |
167 | if (port->vport) | 169 | if (port->vport) |
168 | bfa_fcs_vport_stop_comp(port->vport); | 170 | bfa_fcs_vport_stop_comp(port->vport); |
171 | else | ||
172 | bfa_wc_down(&(port->fabric->stop_wc)); | ||
169 | } else { | 173 | } else { |
170 | bfa_sm_set_state(port, bfa_fcs_lport_sm_stopping); | 174 | bfa_sm_set_state(port, bfa_fcs_lport_sm_stopping); |
171 | list_for_each_safe(qe, qen, &port->rport_q) { | 175 | list_for_each_safe(qe, qen, &port->rport_q) { |
@@ -222,6 +226,8 @@ bfa_fcs_lport_sm_offline( | |||
222 | /* If vport - send completion call back */ | 226 | /* If vport - send completion call back */ |
223 | if (port->vport) | 227 | if (port->vport) |
224 | bfa_fcs_vport_stop_comp(port->vport); | 228 | bfa_fcs_vport_stop_comp(port->vport); |
229 | else | ||
230 | bfa_wc_down(&(port->fabric->stop_wc)); | ||
225 | } else { | 231 | } else { |
226 | bfa_sm_set_state(port, bfa_fcs_lport_sm_stopping); | 232 | bfa_sm_set_state(port, bfa_fcs_lport_sm_stopping); |
227 | list_for_each_safe(qe, qen, &port->rport_q) { | 233 | list_for_each_safe(qe, qen, &port->rport_q) { |
@@ -267,6 +273,8 @@ bfa_fcs_lport_sm_stopping(struct bfa_fcs_lport_s *port, | |||
267 | /* If vport - send completion call back */ | 273 | /* If vport - send completion call back */ |
268 | if (port->vport) | 274 | if (port->vport) |
269 | bfa_fcs_vport_stop_comp(port->vport); | 275 | bfa_fcs_vport_stop_comp(port->vport); |
276 | else | ||
277 | bfa_wc_down(&(port->fabric->stop_wc)); | ||
270 | } | 278 | } |
271 | break; | 279 | break; |
272 | 280 | ||
@@ -978,6 +986,16 @@ bfa_fcs_lport_offline(struct bfa_fcs_lport_s *port) | |||
978 | } | 986 | } |
979 | 987 | ||
980 | /* | 988 | /* |
989 | * Called by fabric for base port and by vport for virtual ports | ||
990 | * when target mode driver is unloaded. | ||
991 | */ | ||
992 | void | ||
993 | bfa_fcs_lport_stop(struct bfa_fcs_lport_s *port) | ||
994 | { | ||
995 | bfa_sm_send_event(port, BFA_FCS_PORT_SM_STOP); | ||
996 | } | ||
997 | |||
998 | /* | ||
981 | * Called by fabric to delete base lport and associated resources. | 999 | * Called by fabric to delete base lport and associated resources. |
982 | * | 1000 | * |
983 | * Called by vport to delete lport and associated resources. Should call | 1001 | * Called by vport to delete lport and associated resources. Should call |
@@ -5884,6 +5902,16 @@ bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport) | |||
5884 | { | 5902 | { |
5885 | vport->vport_stats.fab_cleanup++; | 5903 | vport->vport_stats.fab_cleanup++; |
5886 | } | 5904 | } |
5905 | |||
5906 | /* | ||
5907 | * Stop notification from fabric SM. To be invoked from within FCS. | ||
5908 | */ | ||
5909 | void | ||
5910 | bfa_fcs_vport_fcs_stop(struct bfa_fcs_vport_s *vport) | ||
5911 | { | ||
5912 | bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_STOP); | ||
5913 | } | ||
5914 | |||
5887 | /* | 5915 | /* |
5888 | * delete notification from fabric SM. To be invoked from within FCS. | 5916 | * delete notification from fabric SM. To be invoked from within FCS. |
5889 | */ | 5917 | */ |
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index 8cdb79c2fcd..7689872349f 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c | |||
@@ -92,7 +92,6 @@ static void bfa_ioc_event_notify(struct bfa_ioc_s *ioc , | |||
92 | enum bfa_ioc_event_e event); | 92 | enum bfa_ioc_event_e event); |
93 | static void bfa_ioc_disable_comp(struct bfa_ioc_s *ioc); | 93 | static void bfa_ioc_disable_comp(struct bfa_ioc_s *ioc); |
94 | static void bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc); | 94 | static void bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc); |
95 | static void bfa_ioc_debug_save_ftrc(struct bfa_ioc_s *ioc); | ||
96 | static void bfa_ioc_fail_notify(struct bfa_ioc_s *ioc); | 95 | static void bfa_ioc_fail_notify(struct bfa_ioc_s *ioc); |
97 | static void bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc); | 96 | static void bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc); |
98 | 97 | ||
@@ -599,8 +598,9 @@ bfa_ioc_sm_fail(struct bfa_ioc_s *ioc, enum ioc_event event) | |||
599 | break; | 598 | break; |
600 | 599 | ||
601 | case IOC_E_HWERROR: | 600 | case IOC_E_HWERROR: |
601 | case IOC_E_HWFAILED: | ||
602 | /* | 602 | /* |
603 | * HB failure notification, ignore. | 603 | * HB failure / HW error notification, ignore. |
604 | */ | 604 | */ |
605 | break; | 605 | break; |
606 | default: | 606 | default: |
@@ -632,6 +632,10 @@ bfa_ioc_sm_hwfail(struct bfa_ioc_s *ioc, enum ioc_event event) | |||
632 | bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit); | 632 | bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit); |
633 | break; | 633 | break; |
634 | 634 | ||
635 | case IOC_E_HWERROR: | ||
636 | /* Ignore - already in hwfail state */ | ||
637 | break; | ||
638 | |||
635 | default: | 639 | default: |
636 | bfa_sm_fault(ioc, event); | 640 | bfa_sm_fault(ioc, event); |
637 | } | 641 | } |
@@ -1455,7 +1459,7 @@ bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr) | |||
1455 | bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0); | 1459 | bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0); |
1456 | 1460 | ||
1457 | for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) { | 1461 | for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) { |
1458 | if (fwhdr->md5sum[i] != drv_fwhdr->md5sum[i]) { | 1462 | if (fwhdr->md5sum[i] != cpu_to_le32(drv_fwhdr->md5sum[i])) { |
1459 | bfa_trc(ioc, i); | 1463 | bfa_trc(ioc, i); |
1460 | bfa_trc(ioc, fwhdr->md5sum[i]); | 1464 | bfa_trc(ioc, fwhdr->md5sum[i]); |
1461 | bfa_trc(ioc, drv_fwhdr->md5sum[i]); | 1465 | bfa_trc(ioc, drv_fwhdr->md5sum[i]); |
@@ -1480,7 +1484,7 @@ bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc, u32 boot_env) | |||
1480 | drv_fwhdr = (struct bfi_ioc_image_hdr_s *) | 1484 | drv_fwhdr = (struct bfi_ioc_image_hdr_s *) |
1481 | bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0); | 1485 | bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0); |
1482 | 1486 | ||
1483 | if (fwhdr.signature != drv_fwhdr->signature) { | 1487 | if (fwhdr.signature != cpu_to_le32(drv_fwhdr->signature)) { |
1484 | bfa_trc(ioc, fwhdr.signature); | 1488 | bfa_trc(ioc, fwhdr.signature); |
1485 | bfa_trc(ioc, drv_fwhdr->signature); | 1489 | bfa_trc(ioc, drv_fwhdr->signature); |
1486 | return BFA_FALSE; | 1490 | return BFA_FALSE; |
@@ -1704,7 +1708,7 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type, | |||
1704 | * write smem | 1708 | * write smem |
1705 | */ | 1709 | */ |
1706 | bfa_mem_write(ioc->ioc_regs.smem_page_start, loff, | 1710 | bfa_mem_write(ioc->ioc_regs.smem_page_start, loff, |
1707 | fwimg[BFA_IOC_FLASH_OFFSET_IN_CHUNK(i)]); | 1711 | cpu_to_le32(fwimg[BFA_IOC_FLASH_OFFSET_IN_CHUNK(i)])); |
1708 | 1712 | ||
1709 | loff += sizeof(u32); | 1713 | loff += sizeof(u32); |
1710 | 1714 | ||
@@ -2260,6 +2264,12 @@ bfa_ioc_disable(struct bfa_ioc_s *ioc) | |||
2260 | bfa_fsm_send_event(ioc, IOC_E_DISABLE); | 2264 | bfa_fsm_send_event(ioc, IOC_E_DISABLE); |
2261 | } | 2265 | } |
2262 | 2266 | ||
2267 | void | ||
2268 | bfa_ioc_suspend(struct bfa_ioc_s *ioc) | ||
2269 | { | ||
2270 | ioc->dbg_fwsave_once = BFA_TRUE; | ||
2271 | bfa_fsm_send_event(ioc, IOC_E_HWERROR); | ||
2272 | } | ||
2263 | 2273 | ||
2264 | /* | 2274 | /* |
2265 | * Initialize memory for saving firmware trace. Driver must initialize | 2275 | * Initialize memory for saving firmware trace. Driver must initialize |
@@ -2269,7 +2279,7 @@ void | |||
2269 | bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave) | 2279 | bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave) |
2270 | { | 2280 | { |
2271 | ioc->dbg_fwsave = dbg_fwsave; | 2281 | ioc->dbg_fwsave = dbg_fwsave; |
2272 | ioc->dbg_fwsave_len = (ioc->iocpf.auto_recover) ? BFA_DBG_FWTRC_LEN : 0; | 2282 | ioc->dbg_fwsave_len = BFA_DBG_FWTRC_LEN; |
2273 | } | 2283 | } |
2274 | 2284 | ||
2275 | /* | 2285 | /* |
@@ -2856,7 +2866,7 @@ bfa_ioc_fw_stats_clear(struct bfa_ioc_s *ioc) | |||
2856 | /* | 2866 | /* |
2857 | * Save firmware trace if configured. | 2867 | * Save firmware trace if configured. |
2858 | */ | 2868 | */ |
2859 | static void | 2869 | void |
2860 | bfa_ioc_debug_save_ftrc(struct bfa_ioc_s *ioc) | 2870 | bfa_ioc_debug_save_ftrc(struct bfa_ioc_s *ioc) |
2861 | { | 2871 | { |
2862 | int tlen; | 2872 | int tlen; |
diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h index 1a99d4b5b50..593ce6b2bad 100644 --- a/drivers/scsi/bfa/bfa_ioc.h +++ b/drivers/scsi/bfa/bfa_ioc.h | |||
@@ -820,6 +820,7 @@ void bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa, | |||
820 | struct bfa_ioc_cbfn_s *cbfn, struct bfa_timer_mod_s *timer_mod); | 820 | struct bfa_ioc_cbfn_s *cbfn, struct bfa_timer_mod_s *timer_mod); |
821 | void bfa_ioc_auto_recover(bfa_boolean_t auto_recover); | 821 | void bfa_ioc_auto_recover(bfa_boolean_t auto_recover); |
822 | void bfa_ioc_detach(struct bfa_ioc_s *ioc); | 822 | void bfa_ioc_detach(struct bfa_ioc_s *ioc); |
823 | void bfa_ioc_suspend(struct bfa_ioc_s *ioc); | ||
823 | void bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev, | 824 | void bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev, |
824 | enum bfi_pcifn_class clscode); | 825 | enum bfi_pcifn_class clscode); |
825 | void bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa); | 826 | void bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa); |
@@ -866,6 +867,7 @@ bfa_boolean_t bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, | |||
866 | void bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event); | 867 | void bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event); |
867 | bfa_status_t bfa_ioc_fw_stats_get(struct bfa_ioc_s *ioc, void *stats); | 868 | bfa_status_t bfa_ioc_fw_stats_get(struct bfa_ioc_s *ioc, void *stats); |
868 | bfa_status_t bfa_ioc_fw_stats_clear(struct bfa_ioc_s *ioc); | 869 | bfa_status_t bfa_ioc_fw_stats_clear(struct bfa_ioc_s *ioc); |
870 | void bfa_ioc_debug_save_ftrc(struct bfa_ioc_s *ioc); | ||
869 | 871 | ||
870 | /* | 872 | /* |
871 | * asic block configuration related APIs | 873 | * asic block configuration related APIs |
diff --git a/drivers/scsi/bfa/bfa_svc.c b/drivers/scsi/bfa/bfa_svc.c index 849eac95cae..e7669f8ef78 100644 --- a/drivers/scsi/bfa/bfa_svc.c +++ b/drivers/scsi/bfa/bfa_svc.c | |||
@@ -1440,11 +1440,11 @@ bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event) | |||
1440 | 1440 | ||
1441 | switch (event) { | 1441 | switch (event) { |
1442 | case BFA_LPS_SM_FWRSP: | 1442 | case BFA_LPS_SM_FWRSP: |
1443 | case BFA_LPS_SM_OFFLINE: | ||
1443 | bfa_sm_set_state(lps, bfa_lps_sm_init); | 1444 | bfa_sm_set_state(lps, bfa_lps_sm_init); |
1444 | bfa_lps_logout_comp(lps); | 1445 | bfa_lps_logout_comp(lps); |
1445 | break; | 1446 | break; |
1446 | 1447 | ||
1447 | case BFA_LPS_SM_OFFLINE: | ||
1448 | case BFA_LPS_SM_DELETE: | 1448 | case BFA_LPS_SM_DELETE: |
1449 | bfa_sm_set_state(lps, bfa_lps_sm_init); | 1449 | bfa_sm_set_state(lps, bfa_lps_sm_init); |
1450 | break; | 1450 | break; |
@@ -1822,6 +1822,8 @@ bfa_lps_logout_comp_cb(void *arg, bfa_boolean_t complete) | |||
1822 | 1822 | ||
1823 | if (lps->fdisc) | 1823 | if (lps->fdisc) |
1824 | bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg); | 1824 | bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg); |
1825 | else | ||
1826 | bfa_cb_lps_flogo_comp(lps->bfa->bfad, lps->uarg); | ||
1825 | } | 1827 | } |
1826 | 1828 | ||
1827 | /* | 1829 | /* |
diff --git a/drivers/scsi/bfa/bfa_svc.h b/drivers/scsi/bfa/bfa_svc.h index 4da2b58c8eb..1abcf7c5166 100644 --- a/drivers/scsi/bfa/bfa_svc.h +++ b/drivers/scsi/bfa/bfa_svc.h | |||
@@ -664,6 +664,7 @@ u8 bfa_lps_get_fwtag(struct bfa_s *bfa, u8 lp_tag); | |||
664 | u32 bfa_lps_get_base_pid(struct bfa_s *bfa); | 664 | u32 bfa_lps_get_base_pid(struct bfa_s *bfa); |
665 | u8 bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid); | 665 | u8 bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid); |
666 | void bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status); | 666 | void bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status); |
667 | void bfa_cb_lps_flogo_comp(void *bfad, void *uarg); | ||
667 | void bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status); | 668 | void bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status); |
668 | void bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg); | 669 | void bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg); |
669 | void bfa_cb_lps_cvl_event(void *bfad, void *uarg); | 670 | void bfa_cb_lps_cvl_event(void *bfad, void *uarg); |
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index 2c8f0c71307..ab11ef0f846 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c | |||
@@ -736,6 +736,9 @@ bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad) | |||
736 | } | 736 | } |
737 | } | 737 | } |
738 | 738 | ||
739 | /* Enable PCIE Advanced Error Recovery (AER) if kernel supports */ | ||
740 | pci_enable_pcie_error_reporting(pdev); | ||
741 | |||
739 | bfad->pci_bar0_kva = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); | 742 | bfad->pci_bar0_kva = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); |
740 | bfad->pci_bar2_kva = pci_iomap(pdev, 2, pci_resource_len(pdev, 2)); | 743 | bfad->pci_bar2_kva = pci_iomap(pdev, 2, pci_resource_len(pdev, 2)); |
741 | 744 | ||
@@ -806,6 +809,8 @@ bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad) | |||
806 | } | 809 | } |
807 | } | 810 | } |
808 | 811 | ||
812 | pci_save_state(pdev); | ||
813 | |||
809 | return 0; | 814 | return 0; |
810 | 815 | ||
811 | out_release_region: | 816 | out_release_region: |
@@ -822,6 +827,8 @@ bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad) | |||
822 | pci_iounmap(pdev, bfad->pci_bar0_kva); | 827 | pci_iounmap(pdev, bfad->pci_bar0_kva); |
823 | pci_iounmap(pdev, bfad->pci_bar2_kva); | 828 | pci_iounmap(pdev, bfad->pci_bar2_kva); |
824 | pci_release_regions(pdev); | 829 | pci_release_regions(pdev); |
830 | /* Disable PCIE Advanced Error Recovery (AER) */ | ||
831 | pci_disable_pcie_error_reporting(pdev); | ||
825 | pci_disable_device(pdev); | 832 | pci_disable_device(pdev); |
826 | pci_set_drvdata(pdev, NULL); | 833 | pci_set_drvdata(pdev, NULL); |
827 | } | 834 | } |
@@ -1258,6 +1265,16 @@ bfad_setup_intr(struct bfad_s *bfad) | |||
1258 | 1265 | ||
1259 | error = pci_enable_msix(bfad->pcidev, msix_entries, bfad->nvec); | 1266 | error = pci_enable_msix(bfad->pcidev, msix_entries, bfad->nvec); |
1260 | if (error) { | 1267 | if (error) { |
1268 | /* In CT1 & CT2, try to allocate just one vector */ | ||
1269 | if (bfa_asic_id_ctc(pdev->device)) { | ||
1270 | printk(KERN_WARNING "bfa %s: trying one msix " | ||
1271 | "vector failed to allocate %d[%d]\n", | ||
1272 | bfad->pci_name, bfad->nvec, error); | ||
1273 | bfad->nvec = 1; | ||
1274 | error = pci_enable_msix(bfad->pcidev, | ||
1275 | msix_entries, bfad->nvec); | ||
1276 | } | ||
1277 | |||
1261 | /* | 1278 | /* |
1262 | * Only error number of vector is available. | 1279 | * Only error number of vector is available. |
1263 | * We don't have a mechanism to map multiple | 1280 | * We don't have a mechanism to map multiple |
@@ -1267,12 +1284,13 @@ bfad_setup_intr(struct bfad_s *bfad) | |||
1267 | * vectors. Linux doesn't duplicate vectors | 1284 | * vectors. Linux doesn't duplicate vectors |
1268 | * in the MSIX table for this case. | 1285 | * in the MSIX table for this case. |
1269 | */ | 1286 | */ |
1270 | 1287 | if (error) { | |
1271 | printk(KERN_WARNING "bfad%d: " | 1288 | printk(KERN_WARNING "bfad%d: " |
1272 | "pci_enable_msix failed (%d)," | 1289 | "pci_enable_msix failed (%d), " |
1273 | " use line based.\n", bfad->inst_no, error); | 1290 | "use line based.\n", |
1274 | 1291 | bfad->inst_no, error); | |
1275 | goto line_based; | 1292 | goto line_based; |
1293 | } | ||
1276 | } | 1294 | } |
1277 | 1295 | ||
1278 | /* Disable INTX in MSI-X mode */ | 1296 | /* Disable INTX in MSI-X mode */ |
@@ -1470,6 +1488,197 @@ bfad_pci_remove(struct pci_dev *pdev) | |||
1470 | kfree(bfad); | 1488 | kfree(bfad); |
1471 | } | 1489 | } |
1472 | 1490 | ||
1491 | /* | ||
1492 | * PCI Error Recovery entry, error detected. | ||
1493 | */ | ||
1494 | static pci_ers_result_t | ||
1495 | bfad_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) | ||
1496 | { | ||
1497 | struct bfad_s *bfad = pci_get_drvdata(pdev); | ||
1498 | unsigned long flags; | ||
1499 | pci_ers_result_t ret = PCI_ERS_RESULT_NONE; | ||
1500 | |||
1501 | dev_printk(KERN_ERR, &pdev->dev, | ||
1502 | "error detected state: %d - flags: 0x%x\n", | ||
1503 | state, bfad->bfad_flags); | ||
1504 | |||
1505 | switch (state) { | ||
1506 | case pci_channel_io_normal: /* non-fatal error */ | ||
1507 | spin_lock_irqsave(&bfad->bfad_lock, flags); | ||
1508 | bfad->bfad_flags &= ~BFAD_EEH_BUSY; | ||
1509 | /* Suspend/fail all bfa operations */ | ||
1510 | bfa_ioc_suspend(&bfad->bfa.ioc); | ||
1511 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | ||
1512 | del_timer_sync(&bfad->hal_tmo); | ||
1513 | ret = PCI_ERS_RESULT_CAN_RECOVER; | ||
1514 | break; | ||
1515 | case pci_channel_io_frozen: /* fatal error */ | ||
1516 | init_completion(&bfad->comp); | ||
1517 | spin_lock_irqsave(&bfad->bfad_lock, flags); | ||
1518 | bfad->bfad_flags |= BFAD_EEH_BUSY; | ||
1519 | /* Suspend/fail all bfa operations */ | ||
1520 | bfa_ioc_suspend(&bfad->bfa.ioc); | ||
1521 | bfa_fcs_stop(&bfad->bfa_fcs); | ||
1522 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | ||
1523 | wait_for_completion(&bfad->comp); | ||
1524 | |||
1525 | bfad_remove_intr(bfad); | ||
1526 | del_timer_sync(&bfad->hal_tmo); | ||
1527 | pci_disable_device(pdev); | ||
1528 | ret = PCI_ERS_RESULT_NEED_RESET; | ||
1529 | break; | ||
1530 | case pci_channel_io_perm_failure: /* PCI Card is DEAD */ | ||
1531 | spin_lock_irqsave(&bfad->bfad_lock, flags); | ||
1532 | bfad->bfad_flags |= BFAD_EEH_BUSY | | ||
1533 | BFAD_EEH_PCI_CHANNEL_IO_PERM_FAILURE; | ||
1534 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | ||
1535 | |||
1536 | /* If the error_detected handler is called with the reason | ||
1537 | * pci_channel_io_perm_failure - it will subsequently call | ||
1538 | * pci_remove() entry point to remove the pci device from the | ||
1539 | * system - So defer the cleanup to pci_remove(); cleaning up | ||
1540 | * here causes inconsistent state during pci_remove(). | ||
1541 | */ | ||
1542 | ret = PCI_ERS_RESULT_DISCONNECT; | ||
1543 | break; | ||
1544 | default: | ||
1545 | WARN_ON(1); | ||
1546 | } | ||
1547 | |||
1548 | return ret; | ||
1549 | } | ||
1550 | |||
1551 | int | ||
1552 | restart_bfa(struct bfad_s *bfad) | ||
1553 | { | ||
1554 | unsigned long flags; | ||
1555 | struct pci_dev *pdev = bfad->pcidev; | ||
1556 | |||
1557 | bfa_attach(&bfad->bfa, bfad, &bfad->ioc_cfg, | ||
1558 | &bfad->meminfo, &bfad->hal_pcidev); | ||
1559 | |||
1560 | /* Enable Interrupt and wait bfa_init completion */ | ||
1561 | if (bfad_setup_intr(bfad)) { | ||
1562 | dev_printk(KERN_WARNING, &pdev->dev, | ||
1563 | "%s: bfad_setup_intr failed\n", bfad->pci_name); | ||
1564 | bfa_sm_send_event(bfad, BFAD_E_INTR_INIT_FAILED); | ||
1565 | return -1; | ||
1566 | } | ||
1567 | |||
1568 | init_completion(&bfad->comp); | ||
1569 | spin_lock_irqsave(&bfad->bfad_lock, flags); | ||
1570 | bfa_iocfc_init(&bfad->bfa); | ||
1571 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | ||
1572 | |||
1573 | /* Set up interrupt handler for each vectors */ | ||
1574 | if ((bfad->bfad_flags & BFAD_MSIX_ON) && | ||
1575 | bfad_install_msix_handler(bfad)) | ||
1576 | dev_printk(KERN_WARNING, &pdev->dev, | ||
1577 | "%s: install_msix failed.\n", bfad->pci_name); | ||
1578 | |||
1579 | bfad_init_timer(bfad); | ||
1580 | wait_for_completion(&bfad->comp); | ||
1581 | bfad_drv_start(bfad); | ||
1582 | |||
1583 | return 0; | ||
1584 | } | ||
1585 | |||
1586 | /* | ||
1587 | * PCI Error Recovery entry, re-initialize the chip. | ||
1588 | */ | ||
1589 | static pci_ers_result_t | ||
1590 | bfad_pci_slot_reset(struct pci_dev *pdev) | ||
1591 | { | ||
1592 | struct bfad_s *bfad = pci_get_drvdata(pdev); | ||
1593 | u8 byte; | ||
1594 | |||
1595 | dev_printk(KERN_ERR, &pdev->dev, | ||
1596 | "bfad_pci_slot_reset flags: 0x%x\n", bfad->bfad_flags); | ||
1597 | |||
1598 | if (pci_enable_device(pdev)) { | ||
1599 | dev_printk(KERN_ERR, &pdev->dev, "Cannot re-enable " | ||
1600 | "PCI device after reset.\n"); | ||
1601 | return PCI_ERS_RESULT_DISCONNECT; | ||
1602 | } | ||
1603 | |||
1604 | pci_restore_state(pdev); | ||
1605 | |||
1606 | /* | ||
1607 | * Read some byte (e.g. DMA max. payload size which can't | ||
1608 | * be 0xff any time) to make sure - we did not hit another PCI error | ||
1609 | * in the middle of recovery. If we did, then declare permanent failure. | ||
1610 | */ | ||
1611 | pci_read_config_byte(pdev, 0x68, &byte); | ||
1612 | if (byte == 0xff) { | ||
1613 | dev_printk(KERN_ERR, &pdev->dev, | ||
1614 | "slot_reset failed ... got another PCI error !\n"); | ||
1615 | goto out_disable_device; | ||
1616 | } | ||
1617 | |||
1618 | pci_save_state(pdev); | ||
1619 | pci_set_master(pdev); | ||
1620 | |||
1621 | if (pci_set_dma_mask(bfad->pcidev, DMA_BIT_MASK(64)) != 0) | ||
1622 | if (pci_set_dma_mask(bfad->pcidev, DMA_BIT_MASK(32)) != 0) | ||
1623 | goto out_disable_device; | ||
1624 | |||
1625 | pci_cleanup_aer_uncorrect_error_status(pdev); | ||
1626 | |||
1627 | if (restart_bfa(bfad) == -1) | ||
1628 | goto out_disable_device; | ||
1629 | |||
1630 | pci_enable_pcie_error_reporting(pdev); | ||
1631 | dev_printk(KERN_WARNING, &pdev->dev, | ||
1632 | "slot_reset completed flags: 0x%x!\n", bfad->bfad_flags); | ||
1633 | |||
1634 | return PCI_ERS_RESULT_RECOVERED; | ||
1635 | |||
1636 | out_disable_device: | ||
1637 | pci_disable_device(pdev); | ||
1638 | return PCI_ERS_RESULT_DISCONNECT; | ||
1639 | } | ||
1640 | |||
1641 | static pci_ers_result_t | ||
1642 | bfad_pci_mmio_enabled(struct pci_dev *pdev) | ||
1643 | { | ||
1644 | unsigned long flags; | ||
1645 | struct bfad_s *bfad = pci_get_drvdata(pdev); | ||
1646 | |||
1647 | dev_printk(KERN_INFO, &pdev->dev, "mmio_enabled\n"); | ||
1648 | |||
1649 | /* Fetch FW diagnostic information */ | ||
1650 | bfa_ioc_debug_save_ftrc(&bfad->bfa.ioc); | ||
1651 | |||
1652 | /* Cancel all pending IOs */ | ||
1653 | spin_lock_irqsave(&bfad->bfad_lock, flags); | ||
1654 | init_completion(&bfad->comp); | ||
1655 | bfa_fcs_stop(&bfad->bfa_fcs); | ||
1656 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | ||
1657 | wait_for_completion(&bfad->comp); | ||
1658 | |||
1659 | bfad_remove_intr(bfad); | ||
1660 | del_timer_sync(&bfad->hal_tmo); | ||
1661 | pci_disable_device(pdev); | ||
1662 | |||
1663 | return PCI_ERS_RESULT_NEED_RESET; | ||
1664 | } | ||
1665 | |||
1666 | static void | ||
1667 | bfad_pci_resume(struct pci_dev *pdev) | ||
1668 | { | ||
1669 | unsigned long flags; | ||
1670 | struct bfad_s *bfad = pci_get_drvdata(pdev); | ||
1671 | |||
1672 | dev_printk(KERN_WARNING, &pdev->dev, "resume\n"); | ||
1673 | |||
1674 | /* wait until the link is online */ | ||
1675 | bfad_rport_online_wait(bfad); | ||
1676 | |||
1677 | spin_lock_irqsave(&bfad->bfad_lock, flags); | ||
1678 | bfad->bfad_flags &= ~BFAD_EEH_BUSY; | ||
1679 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | ||
1680 | } | ||
1681 | |||
1473 | struct pci_device_id bfad_id_table[] = { | 1682 | struct pci_device_id bfad_id_table[] = { |
1474 | { | 1683 | { |
1475 | .vendor = BFA_PCI_VENDOR_ID_BROCADE, | 1684 | .vendor = BFA_PCI_VENDOR_ID_BROCADE, |
@@ -1513,11 +1722,22 @@ struct pci_device_id bfad_id_table[] = { | |||
1513 | 1722 | ||
1514 | MODULE_DEVICE_TABLE(pci, bfad_id_table); | 1723 | MODULE_DEVICE_TABLE(pci, bfad_id_table); |
1515 | 1724 | ||
1725 | /* | ||
1726 | * PCI error recovery handlers. | ||
1727 | */ | ||
1728 | static struct pci_error_handlers bfad_err_handler = { | ||
1729 | .error_detected = bfad_pci_error_detected, | ||
1730 | .slot_reset = bfad_pci_slot_reset, | ||
1731 | .mmio_enabled = bfad_pci_mmio_enabled, | ||
1732 | .resume = bfad_pci_resume, | ||
1733 | }; | ||
1734 | |||
1516 | static struct pci_driver bfad_pci_driver = { | 1735 | static struct pci_driver bfad_pci_driver = { |
1517 | .name = BFAD_DRIVER_NAME, | 1736 | .name = BFAD_DRIVER_NAME, |
1518 | .id_table = bfad_id_table, | 1737 | .id_table = bfad_id_table, |
1519 | .probe = bfad_pci_probe, | 1738 | .probe = bfad_pci_probe, |
1520 | .remove = __devexit_p(bfad_pci_remove), | 1739 | .remove = __devexit_p(bfad_pci_remove), |
1740 | .err_handler = &bfad_err_handler, | ||
1521 | }; | 1741 | }; |
1522 | 1742 | ||
1523 | /* | 1743 | /* |
diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h index 7f74f1d1912..d1511d8fece 100644 --- a/drivers/scsi/bfa/bfad_drv.h +++ b/drivers/scsi/bfa/bfad_drv.h | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/vmalloc.h> | 37 | #include <linux/vmalloc.h> |
38 | #include <linux/workqueue.h> | 38 | #include <linux/workqueue.h> |
39 | #include <linux/bitops.h> | 39 | #include <linux/bitops.h> |
40 | #include <linux/aer.h> | ||
40 | #include <scsi/scsi.h> | 41 | #include <scsi/scsi.h> |
41 | #include <scsi/scsi_host.h> | 42 | #include <scsi/scsi_host.h> |
42 | #include <scsi/scsi_tcq.h> | 43 | #include <scsi/scsi_tcq.h> |
@@ -81,6 +82,8 @@ | |||
81 | #define BFAD_FC4_PROBE_DONE 0x00000200 | 82 | #define BFAD_FC4_PROBE_DONE 0x00000200 |
82 | #define BFAD_PORT_DELETE 0x00000001 | 83 | #define BFAD_PORT_DELETE 0x00000001 |
83 | #define BFAD_INTX_ON 0x00000400 | 84 | #define BFAD_INTX_ON 0x00000400 |
85 | #define BFAD_EEH_BUSY 0x00000800 | ||
86 | #define BFAD_EEH_PCI_CHANNEL_IO_PERM_FAILURE 0x00001000 | ||
84 | /* | 87 | /* |
85 | * BFAD related definition | 88 | * BFAD related definition |
86 | */ | 89 | */ |
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index 2eebf8d4d58..8f92732655c 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c | |||
@@ -1216,6 +1216,15 @@ bfad_im_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd | |||
1216 | return 0; | 1216 | return 0; |
1217 | } | 1217 | } |
1218 | 1218 | ||
1219 | if (bfad->bfad_flags & BFAD_EEH_BUSY) { | ||
1220 | if (bfad->bfad_flags & BFAD_EEH_PCI_CHANNEL_IO_PERM_FAILURE) | ||
1221 | cmnd->result = DID_NO_CONNECT << 16; | ||
1222 | else | ||
1223 | cmnd->result = DID_REQUEUE << 16; | ||
1224 | done(cmnd); | ||
1225 | return 0; | ||
1226 | } | ||
1227 | |||
1219 | sg_cnt = scsi_dma_map(cmnd); | 1228 | sg_cnt = scsi_dma_map(cmnd); |
1220 | if (sg_cnt < 0) | 1229 | if (sg_cnt < 0) |
1221 | return SCSI_MLQUEUE_HOST_BUSY; | 1230 | return SCSI_MLQUEUE_HOST_BUSY; |