diff options
author | Krishna Gudipati <kgudipat@brocade.com> | 2010-12-13 19:17:11 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-12-21 13:37:15 -0500 |
commit | f1d584d70f31f54e0a559049906f42db89e2746d (patch) | |
tree | 7bfa223d53221c5930802b988a8bb6c0aed201d6 /drivers/scsi/bfa/bfa_ioc_cb.c | |
parent | f3a060ca57903daaf2f1a88c6c25832619b2a74f (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.c | 95 |
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); | |||
30 | static void bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc); | 30 | static void bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc); |
31 | static void bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc); | 31 | static void bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc); |
32 | static void bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix); | 32 | static void bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix); |
33 | static void bfa_ioc_cb_notify_hbfail(struct bfa_ioc_s *ioc); | 33 | static void bfa_ioc_cb_notify_fail(struct bfa_ioc_s *ioc); |
34 | static void bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc); | 34 | static void bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc); |
35 | static void bfa_ioc_cb_sync_join(struct bfa_ioc_s *ioc); | ||
36 | static void bfa_ioc_cb_sync_leave(struct bfa_ioc_s *ioc); | ||
37 | static void bfa_ioc_cb_sync_ack(struct bfa_ioc_s *ioc); | ||
38 | static bfa_boolean_t bfa_ioc_cb_sync_complete(struct bfa_ioc_s *ioc); | ||
35 | 39 | ||
36 | static struct bfa_ioc_hwif_s hwif_cb; | 40 | static 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 | */ |
59 | static bfa_boolean_t | 67 | static bfa_boolean_t |
60 | bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc) | 68 | bfa_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 | */ |
73 | static void | 97 | static void |
74 | bfa_ioc_cb_notify_hbfail(struct bfa_ioc_s *ioc) | 98 | bfa_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 | */ | ||
217 | static void | ||
218 | bfa_ioc_cb_sync_join(struct bfa_ioc_s *ioc) | ||
219 | { | ||
220 | } | ||
188 | 221 | ||
222 | static void | ||
223 | bfa_ioc_cb_sync_leave(struct bfa_ioc_s *ioc) | ||
224 | { | ||
225 | } | ||
226 | |||
227 | static void | ||
228 | bfa_ioc_cb_sync_ack(struct bfa_ioc_s *ioc) | ||
229 | { | ||
230 | writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate); | ||
231 | } | ||
232 | |||
233 | static bfa_boolean_t | ||
234 | bfa_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 | ||
190 | bfa_status_t | 277 | bfa_status_t |
191 | bfa_ioc_cb_pll_init(void __iomem *rb, bfa_boolean_t fcmode) | 278 | bfa_ioc_cb_pll_init(void __iomem *rb, bfa_boolean_t fcmode) |