aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;