aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/bfa/bfa_ioc_cb.c
diff options
context:
space:
mode:
authorKrishna Gudipati <kgudipat@brocade.com>2010-12-13 19:17:11 -0500
committerJames Bottomley <James.Bottomley@suse.de>2010-12-21 13:37:15 -0500
commitf1d584d70f31f54e0a559049906f42db89e2746d (patch)
tree7bfa223d53221c5930802b988a8bb6c0aed201d6 /drivers/scsi/bfa/bfa_ioc_cb.c
parentf3a060ca57903daaf2f1a88c6c25832619b2a74f (diff)
[SCSI] bfa: IOC auto recovery fix.
- Made IOC auto_recovery synchronized and not timer based. - Only one PCI function will attempt to recover and reinitialize the ASIC on a failure, after all the active PCI fns acknowledge the IOC failure. Signed-off-by: Krishna Gudipati <kgudipat@brocade.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/bfa/bfa_ioc_cb.c')
-rw-r--r--drivers/scsi/bfa/bfa_ioc_cb.c95
1 files changed, 91 insertions, 4 deletions
diff --git a/drivers/scsi/bfa/bfa_ioc_cb.c b/drivers/scsi/bfa/bfa_ioc_cb.c
index a0e05da9df51..788ecca5aa01 100644
--- a/drivers/scsi/bfa/bfa_ioc_cb.c
+++ b/drivers/scsi/bfa/bfa_ioc_cb.c
@@ -30,8 +30,12 @@ static void bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc);
30static void bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc); 30static void bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc);
31static void bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc); 31static void bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc);
32static void bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix); 32static void bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix);
33static void bfa_ioc_cb_notify_hbfail(struct bfa_ioc_s *ioc); 33static void bfa_ioc_cb_notify_fail(struct bfa_ioc_s *ioc);
34static void bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc); 34static void bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc);
35static void bfa_ioc_cb_sync_join(struct bfa_ioc_s *ioc);
36static void bfa_ioc_cb_sync_leave(struct bfa_ioc_s *ioc);
37static void bfa_ioc_cb_sync_ack(struct bfa_ioc_s *ioc);
38static bfa_boolean_t bfa_ioc_cb_sync_complete(struct bfa_ioc_s *ioc);
35 39
36static struct bfa_ioc_hwif_s hwif_cb; 40static struct bfa_ioc_hwif_s hwif_cb;
37 41
@@ -47,18 +51,38 @@ bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc)
47 hwif_cb.ioc_reg_init = bfa_ioc_cb_reg_init; 51 hwif_cb.ioc_reg_init = bfa_ioc_cb_reg_init;
48 hwif_cb.ioc_map_port = bfa_ioc_cb_map_port; 52 hwif_cb.ioc_map_port = bfa_ioc_cb_map_port;
49 hwif_cb.ioc_isr_mode_set = bfa_ioc_cb_isr_mode_set; 53 hwif_cb.ioc_isr_mode_set = bfa_ioc_cb_isr_mode_set;
50 hwif_cb.ioc_notify_hbfail = bfa_ioc_cb_notify_hbfail; 54 hwif_cb.ioc_notify_fail = bfa_ioc_cb_notify_fail;
51 hwif_cb.ioc_ownership_reset = bfa_ioc_cb_ownership_reset; 55 hwif_cb.ioc_ownership_reset = bfa_ioc_cb_ownership_reset;
56 hwif_cb.ioc_sync_join = bfa_ioc_cb_sync_join;
57 hwif_cb.ioc_sync_leave = bfa_ioc_cb_sync_leave;
58 hwif_cb.ioc_sync_ack = bfa_ioc_cb_sync_ack;
59 hwif_cb.ioc_sync_complete = bfa_ioc_cb_sync_complete;
52 60
53 ioc->ioc_hwif = &hwif_cb; 61 ioc->ioc_hwif = &hwif_cb;
54} 62}
55 63
56/* 64/**
57 * Return true if firmware of current driver matches the running firmware. 65 * Return true if firmware of current driver matches the running firmware.
58 */ 66 */
59static bfa_boolean_t 67static bfa_boolean_t
60bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc) 68bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc)
61{ 69{
70 struct bfi_ioc_image_hdr_s fwhdr;
71 uint32_t fwstate = readl(ioc->ioc_regs.ioc_fwstate);
72
73 if ((fwstate == BFI_IOC_UNINIT) || bfa_ioc_is_uefi(ioc) ||
74 bfa_ioc_is_bios_optrom(ioc))
75 return BFA_TRUE;
76
77 bfa_ioc_fwver_get(ioc, &fwhdr);
78
79 if (swab32(fwhdr.exec) == BFI_BOOT_TYPE_NORMAL)
80 return BFA_TRUE;
81
82 bfa_trc(ioc, fwstate);
83 bfa_trc(ioc, fwhdr.exec);
84 writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate);
85
62 return BFA_TRUE; 86 return BFA_TRUE;
63} 87}
64 88
@@ -71,7 +95,7 @@ bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc)
71 * Notify other functions on HB failure. 95 * Notify other functions on HB failure.
72 */ 96 */
73static void 97static void
74bfa_ioc_cb_notify_hbfail(struct bfa_ioc_s *ioc) 98bfa_ioc_cb_notify_fail(struct bfa_ioc_s *ioc)
75{ 99{
76 writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set); 100 writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set);
77 readl(ioc->ioc_regs.err_set); 101 readl(ioc->ioc_regs.err_set);
@@ -109,9 +133,11 @@ bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc)
109 if (ioc->port_id == 0) { 133 if (ioc->port_id == 0) {
110 ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG; 134 ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG;
111 ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG; 135 ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG;
136 ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC1_STATE_REG;
112 } else { 137 } else {
113 ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG); 138 ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG);
114 ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG); 139 ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG);
140 ioc->ioc_regs.alt_ioc_fwstate = (rb + BFA_IOC0_STATE_REG);
115 } 141 }
116 142
117 /* 143 /*
@@ -185,7 +211,68 @@ bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc)
185 writel(1, ioc->ioc_regs.ioc_sem_reg); 211 writel(1, ioc->ioc_regs.ioc_sem_reg);
186} 212}
187 213
214/**
215 * Synchronized IOC failure processing routines
216 */
217static void
218bfa_ioc_cb_sync_join(struct bfa_ioc_s *ioc)
219{
220}
188 221
222static void
223bfa_ioc_cb_sync_leave(struct bfa_ioc_s *ioc)
224{
225}
226
227static void
228bfa_ioc_cb_sync_ack(struct bfa_ioc_s *ioc)
229{
230 writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
231}
232
233static bfa_boolean_t
234bfa_ioc_cb_sync_complete(struct bfa_ioc_s *ioc)
235{
236 uint32_t fwstate, alt_fwstate;
237 fwstate = readl(ioc->ioc_regs.ioc_fwstate);
238
239 /**
240 * At this point, this IOC is hoding the hw sem in the
241 * start path (fwcheck) OR in the disable/enable path
242 * OR to check if the other IOC has acknowledged failure.
243 *
244 * So, this IOC can be in UNINIT, INITING, DISABLED, FAIL
245 * or in MEMTEST states. In a normal scenario, this IOC
246 * can not be in OP state when this function is called.
247 *
248 * However, this IOC could still be in OP state when
249 * the OS driver is starting up, if the OptROM code has
250 * left it in that state.
251 *
252 * If we had marked this IOC's fwstate as BFI_IOC_FAIL
253 * in the failure case and now, if the fwstate is not
254 * BFI_IOC_FAIL it implies that the other PCI fn have
255 * reinitialized the ASIC or this IOC got disabled, so
256 * return TRUE.
257 */
258 if (fwstate == BFI_IOC_UNINIT ||
259 fwstate == BFI_IOC_INITING ||
260 fwstate == BFI_IOC_DISABLED ||
261 fwstate == BFI_IOC_MEMTEST ||
262 fwstate == BFI_IOC_OP)
263 return BFA_TRUE;
264 else {
265 alt_fwstate = readl(ioc->ioc_regs.alt_ioc_fwstate);
266 if (alt_fwstate == BFI_IOC_FAIL ||
267 alt_fwstate == BFI_IOC_DISABLED ||
268 alt_fwstate == BFI_IOC_UNINIT ||
269 alt_fwstate == BFI_IOC_INITING ||
270 alt_fwstate == BFI_IOC_MEMTEST)
271 return BFA_TRUE;
272 else
273 return BFA_FALSE;
274 }
275}
189 276
190bfa_status_t 277bfa_status_t
191bfa_ioc_cb_pll_init(void __iomem *rb, bfa_boolean_t fcmode) 278bfa_ioc_cb_pll_init(void __iomem *rb, bfa_boolean_t fcmode)