aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/bfa
diff options
context:
space:
mode:
authorKrishna Gudipati <kgudipat@brocade.com>2012-08-22 22:52:02 -0400
committerJames Bottomley <JBottomley@Parallels.com>2012-09-24 04:10:56 -0400
commit881c1b3c486c7f181e0ca8c8df30f5f860c0d659 (patch)
tree6fda16f343c4a85ba19945d352d90d7134f109df /drivers/scsi/bfa
parent6dca60a387a6dd1317aa8c690cba74a5bdfde465 (diff)
[SCSI] bfa: Add PowerPC support and enable PCIE AER handling.
- Added few missing endian swap changes to support BFA on PowerPC. - Added PCIE AER support to BFA: a) Implemented the PCI error handler entry points. b) Made changes to FCS state machine to handle STOP event from the PCI error detected entry point. c) Made changes to the IO Controller state machine to handle SUSPEND event from the PCI error detected entry point. d) Made changes to restart the BFA operations on a slot_reset completion. Signed-off-by: Krishna Gudipati <kgudipat@brocade.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/bfa')
-rw-r--r--drivers/scsi/bfa/bfa_core.c12
-rw-r--r--drivers/scsi/bfa/bfa_fcs.c133
-rw-r--r--drivers/scsi/bfa/bfa_fcs.h8
-rw-r--r--drivers/scsi/bfa/bfa_fcs_lport.c28
-rw-r--r--drivers/scsi/bfa/bfa_ioc.c24
-rw-r--r--drivers/scsi/bfa/bfa_ioc.h2
-rw-r--r--drivers/scsi/bfa/bfa_svc.c4
-rw-r--r--drivers/scsi/bfa/bfa_svc.h1
-rw-r--r--drivers/scsi/bfa/bfad.c232
-rw-r--r--drivers/scsi/bfa/bfad_drv.h3
-rw-r--r--drivers/scsi/bfa/bfad_im.c9
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 */
124void
125bfa_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 */
124void 136void
@@ -213,6 +225,8 @@ static void bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric);
213static void bfa_fcs_fabric_delay(void *cbarg); 225static void bfa_fcs_fabric_delay(void *cbarg);
214static void bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric); 226static void bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric);
215static void bfa_fcs_fabric_delete_comp(void *cbarg); 227static void bfa_fcs_fabric_delete_comp(void *cbarg);
228static void bfa_fcs_fabric_stop(struct bfa_fcs_fabric_s *fabric);
229static void bfa_fcs_fabric_stop_comp(void *cbarg);
216static void bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric, 230static 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);
218static void bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric, 232static 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);
251static void bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric, 265static 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);
267static void bfa_fcs_fabric_sm_stopping(struct bfa_fcs_fabric_s *fabric,
268 enum bfa_fcs_fabric_event event);
269static 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 */
716static void
717bfa_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 */
744static void
745bfa_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 */
1007static void
1008bfa_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 */
924static u8 1029static 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
1086static void
1087bfa_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 */
1157void
1158bfa_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 */
1044void 1170void
@@ -1387,6 +1513,13 @@ bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric,
1387 } 1513 }
1388} 1514}
1389 1515
1516void
1517bfa_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,
323void bfa_fcs_lport_online(struct bfa_fcs_lport_s *port); 324void bfa_fcs_lport_online(struct bfa_fcs_lport_s *port);
324void bfa_fcs_lport_offline(struct bfa_fcs_lport_s *port); 325void bfa_fcs_lport_offline(struct bfa_fcs_lport_s *port);
325void bfa_fcs_lport_delete(struct bfa_fcs_lport_s *port); 326void bfa_fcs_lport_delete(struct bfa_fcs_lport_s *port);
327void bfa_fcs_lport_stop(struct bfa_fcs_lport_s *port);
326struct bfa_fcs_rport_s *bfa_fcs_lport_get_rport_by_pid( 328struct 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);
328struct bfa_fcs_rport_s *bfa_fcs_lport_get_rport_by_old_pid( 330struct 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);
387void bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport); 389void bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport);
388void bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport); 390void bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport);
389void bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport); 391void bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport);
392void bfa_fcs_vport_fcs_stop(struct bfa_fcs_vport_s *vport);
390void bfa_fcs_vport_stop_comp(struct bfa_fcs_vport_s *vport); 393void 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);
748void bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs, 754void 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);
750void bfa_fcs_exit(struct bfa_fcs_s *fcs); 756void bfa_fcs_exit(struct bfa_fcs_s *fcs);
757void 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,
778u16 bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric); 785u16 bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric);
779void bfa_fcs_uf_attach(struct bfa_fcs_s *fcs); 786void bfa_fcs_uf_attach(struct bfa_fcs_s *fcs);
780void bfa_fcs_port_attach(struct bfa_fcs_s *fcs); 787void bfa_fcs_port_attach(struct bfa_fcs_s *fcs);
788void bfa_fcs_fabric_modstop(struct bfa_fcs_s *fcs);
781void bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric, 789void 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);
783void bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric, 791void 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 */
992void
993bfa_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 */
5909void
5910bfa_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);
93static void bfa_ioc_disable_comp(struct bfa_ioc_s *ioc); 93static void bfa_ioc_disable_comp(struct bfa_ioc_s *ioc);
94static void bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc); 94static void bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc);
95static void bfa_ioc_debug_save_ftrc(struct bfa_ioc_s *ioc);
96static void bfa_ioc_fail_notify(struct bfa_ioc_s *ioc); 95static void bfa_ioc_fail_notify(struct bfa_ioc_s *ioc);
97static void bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc); 96static 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
2267void
2268bfa_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
2269bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave) 2279bfa_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 */
2859static void 2869void
2860bfa_ioc_debug_save_ftrc(struct bfa_ioc_s *ioc) 2870bfa_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);
821void bfa_ioc_auto_recover(bfa_boolean_t auto_recover); 821void bfa_ioc_auto_recover(bfa_boolean_t auto_recover);
822void bfa_ioc_detach(struct bfa_ioc_s *ioc); 822void bfa_ioc_detach(struct bfa_ioc_s *ioc);
823void bfa_ioc_suspend(struct bfa_ioc_s *ioc);
823void bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev, 824void 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);
825void bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa); 826void 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,
866void bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event); 867void bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event);
867bfa_status_t bfa_ioc_fw_stats_get(struct bfa_ioc_s *ioc, void *stats); 868bfa_status_t bfa_ioc_fw_stats_get(struct bfa_ioc_s *ioc, void *stats);
868bfa_status_t bfa_ioc_fw_stats_clear(struct bfa_ioc_s *ioc); 869bfa_status_t bfa_ioc_fw_stats_clear(struct bfa_ioc_s *ioc);
870void 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);
664u32 bfa_lps_get_base_pid(struct bfa_s *bfa); 664u32 bfa_lps_get_base_pid(struct bfa_s *bfa);
665u8 bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid); 665u8 bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid);
666void bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status); 666void bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status);
667void bfa_cb_lps_flogo_comp(void *bfad, void *uarg);
667void bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status); 668void bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status);
668void bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg); 669void bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg);
669void bfa_cb_lps_cvl_event(void *bfad, void *uarg); 670void 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
811out_release_region: 816out_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 */
1494static pci_ers_result_t
1495bfad_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
1551int
1552restart_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 */
1589static pci_ers_result_t
1590bfad_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
1636out_disable_device:
1637 pci_disable_device(pdev);
1638 return PCI_ERS_RESULT_DISCONNECT;
1639}
1640
1641static pci_ers_result_t
1642bfad_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
1666static void
1667bfad_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
1473struct pci_device_id bfad_id_table[] = { 1682struct 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
1514MODULE_DEVICE_TABLE(pci, bfad_id_table); 1723MODULE_DEVICE_TABLE(pci, bfad_id_table);
1515 1724
1725/*
1726 * PCI error recovery handlers.
1727 */
1728static 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
1516static struct pci_driver bfad_pci_driver = { 1735static 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;