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_ct.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_ct.c')
-rw-r--r-- | drivers/scsi/bfa/bfa_ioc_ct.c | 101 |
1 files changed, 98 insertions, 3 deletions
diff --git a/drivers/scsi/bfa/bfa_ioc_ct.c b/drivers/scsi/bfa/bfa_ioc_ct.c index 25a5d3c339c8..9da55a836bfb 100644 --- a/drivers/scsi/bfa/bfa_ioc_ct.c +++ b/drivers/scsi/bfa/bfa_ioc_ct.c | |||
@@ -22,6 +22,15 @@ | |||
22 | 22 | ||
23 | BFA_TRC_FILE(CNA, IOC_CT); | 23 | BFA_TRC_FILE(CNA, IOC_CT); |
24 | 24 | ||
25 | #define bfa_ioc_ct_sync_pos(__ioc) \ | ||
26 | ((uint32_t) (1 << bfa_ioc_pcifn(__ioc))) | ||
27 | #define BFA_IOC_SYNC_REQD_SH 16 | ||
28 | #define bfa_ioc_ct_get_sync_ackd(__val) (__val & 0x0000ffff) | ||
29 | #define bfa_ioc_ct_clear_sync_ackd(__val) (__val & 0xffff0000) | ||
30 | #define bfa_ioc_ct_get_sync_reqd(__val) (__val >> BFA_IOC_SYNC_REQD_SH) | ||
31 | #define bfa_ioc_ct_sync_reqd_pos(__ioc) \ | ||
32 | (bfa_ioc_ct_sync_pos(__ioc) << BFA_IOC_SYNC_REQD_SH) | ||
33 | |||
25 | /* | 34 | /* |
26 | * forward declarations | 35 | * forward declarations |
27 | */ | 36 | */ |
@@ -30,8 +39,12 @@ static void bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc); | |||
30 | static void bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc); | 39 | static void bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc); |
31 | static void bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc); | 40 | static void bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc); |
32 | static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix); | 41 | static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix); |
33 | static void bfa_ioc_ct_notify_hbfail(struct bfa_ioc_s *ioc); | 42 | static void bfa_ioc_ct_notify_fail(struct bfa_ioc_s *ioc); |
34 | static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc); | 43 | static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc); |
44 | static void bfa_ioc_ct_sync_join(struct bfa_ioc_s *ioc); | ||
45 | static void bfa_ioc_ct_sync_leave(struct bfa_ioc_s *ioc); | ||
46 | static void bfa_ioc_ct_sync_ack(struct bfa_ioc_s *ioc); | ||
47 | static bfa_boolean_t bfa_ioc_ct_sync_complete(struct bfa_ioc_s *ioc); | ||
35 | 48 | ||
36 | static struct bfa_ioc_hwif_s hwif_ct; | 49 | static struct bfa_ioc_hwif_s hwif_ct; |
37 | 50 | ||
@@ -47,8 +60,12 @@ bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc) | |||
47 | hwif_ct.ioc_reg_init = bfa_ioc_ct_reg_init; | 60 | hwif_ct.ioc_reg_init = bfa_ioc_ct_reg_init; |
48 | hwif_ct.ioc_map_port = bfa_ioc_ct_map_port; | 61 | hwif_ct.ioc_map_port = bfa_ioc_ct_map_port; |
49 | hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set; | 62 | hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set; |
50 | hwif_ct.ioc_notify_hbfail = bfa_ioc_ct_notify_hbfail; | 63 | hwif_ct.ioc_notify_fail = bfa_ioc_ct_notify_fail; |
51 | hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset; | 64 | hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset; |
65 | hwif_ct.ioc_sync_join = bfa_ioc_ct_sync_join; | ||
66 | hwif_ct.ioc_sync_leave = bfa_ioc_ct_sync_leave; | ||
67 | hwif_ct.ioc_sync_ack = bfa_ioc_ct_sync_ack; | ||
68 | hwif_ct.ioc_sync_complete = bfa_ioc_ct_sync_complete; | ||
52 | 69 | ||
53 | ioc->ioc_hwif = &hwif_ct; | 70 | ioc->ioc_hwif = &hwif_ct; |
54 | } | 71 | } |
@@ -85,6 +102,7 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc) | |||
85 | if (usecnt == 0) { | 102 | if (usecnt == 0) { |
86 | writel(1, ioc->ioc_regs.ioc_usage_reg); | 103 | writel(1, ioc->ioc_regs.ioc_usage_reg); |
87 | writel(1, ioc->ioc_regs.ioc_usage_sem_reg); | 104 | writel(1, ioc->ioc_regs.ioc_usage_sem_reg); |
105 | writel(0, ioc->ioc_regs.ioc_fail_sync); | ||
88 | bfa_trc(ioc, usecnt); | 106 | bfa_trc(ioc, usecnt); |
89 | return BFA_TRUE; | 107 | return BFA_TRUE; |
90 | } | 108 | } |
@@ -153,12 +171,14 @@ bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc) | |||
153 | * Notify other functions on HB failure. | 171 | * Notify other functions on HB failure. |
154 | */ | 172 | */ |
155 | static void | 173 | static void |
156 | bfa_ioc_ct_notify_hbfail(struct bfa_ioc_s *ioc) | 174 | bfa_ioc_ct_notify_fail(struct bfa_ioc_s *ioc) |
157 | { | 175 | { |
158 | if (ioc->cna) { | 176 | if (ioc->cna) { |
159 | writel(__FW_INIT_HALT_P, ioc->ioc_regs.ll_halt); | 177 | writel(__FW_INIT_HALT_P, ioc->ioc_regs.ll_halt); |
178 | writel(__FW_INIT_HALT_P, ioc->ioc_regs.alt_ll_halt); | ||
160 | /* Wait for halt to take effect */ | 179 | /* Wait for halt to take effect */ |
161 | readl(ioc->ioc_regs.ll_halt); | 180 | readl(ioc->ioc_regs.ll_halt); |
181 | readl(ioc->ioc_regs.alt_ll_halt); | ||
162 | } else { | 182 | } else { |
163 | writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set); | 183 | writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set); |
164 | readl(ioc->ioc_regs.err_set); | 184 | readl(ioc->ioc_regs.err_set); |
@@ -210,15 +230,19 @@ bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc) | |||
210 | if (ioc->port_id == 0) { | 230 | if (ioc->port_id == 0) { |
211 | ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG; | 231 | ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG; |
212 | ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG; | 232 | ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG; |
233 | ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC1_STATE_REG; | ||
213 | ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn; | 234 | ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn; |
214 | ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu; | 235 | ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu; |
215 | ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0; | 236 | ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0; |
237 | ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P1; | ||
216 | } else { | 238 | } else { |
217 | ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG); | 239 | ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG); |
218 | ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG); | 240 | ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG); |
241 | ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC0_STATE_REG; | ||
219 | ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn; | 242 | ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn; |
220 | ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu; | 243 | ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu; |
221 | ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1; | 244 | ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1; |
245 | ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P0; | ||
222 | } | 246 | } |
223 | 247 | ||
224 | /* | 248 | /* |
@@ -236,6 +260,7 @@ bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc) | |||
236 | ioc->ioc_regs.ioc_usage_sem_reg = (rb + HOST_SEM1_REG); | 260 | ioc->ioc_regs.ioc_usage_sem_reg = (rb + HOST_SEM1_REG); |
237 | ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG); | 261 | ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG); |
238 | ioc->ioc_regs.ioc_usage_reg = (rb + BFA_FW_USE_COUNT); | 262 | ioc->ioc_regs.ioc_usage_reg = (rb + BFA_FW_USE_COUNT); |
263 | ioc->ioc_regs.ioc_fail_sync = (rb + BFA_IOC_FAIL_SYNC); | ||
239 | 264 | ||
240 | /* | 265 | /* |
241 | * sram memory access | 266 | * sram memory access |
@@ -326,7 +351,77 @@ bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc) | |||
326 | writel(1, ioc->ioc_regs.ioc_sem_reg); | 351 | writel(1, ioc->ioc_regs.ioc_sem_reg); |
327 | } | 352 | } |
328 | 353 | ||
354 | /** | ||
355 | * Synchronized IOC failure processing routines | ||
356 | */ | ||
357 | static void | ||
358 | bfa_ioc_ct_sync_join(struct bfa_ioc_s *ioc) | ||
359 | { | ||
360 | uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync); | ||
361 | uint32_t sync_pos = bfa_ioc_ct_sync_reqd_pos(ioc); | ||
362 | |||
363 | writel((r32 | sync_pos), ioc->ioc_regs.ioc_fail_sync); | ||
364 | } | ||
329 | 365 | ||
366 | static void | ||
367 | bfa_ioc_ct_sync_leave(struct bfa_ioc_s *ioc) | ||
368 | { | ||
369 | uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync); | ||
370 | uint32_t sync_msk = bfa_ioc_ct_sync_reqd_pos(ioc) | | ||
371 | bfa_ioc_ct_sync_pos(ioc); | ||
372 | |||
373 | writel((r32 & ~sync_msk), ioc->ioc_regs.ioc_fail_sync); | ||
374 | } | ||
375 | |||
376 | static void | ||
377 | bfa_ioc_ct_sync_ack(struct bfa_ioc_s *ioc) | ||
378 | { | ||
379 | uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync); | ||
380 | |||
381 | writel((r32 | bfa_ioc_ct_sync_pos(ioc)), | ||
382 | ioc->ioc_regs.ioc_fail_sync); | ||
383 | } | ||
384 | |||
385 | static bfa_boolean_t | ||
386 | bfa_ioc_ct_sync_complete(struct bfa_ioc_s *ioc) | ||
387 | { | ||
388 | uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync); | ||
389 | uint32_t sync_reqd = bfa_ioc_ct_get_sync_reqd(r32); | ||
390 | uint32_t sync_ackd = bfa_ioc_ct_get_sync_ackd(r32); | ||
391 | uint32_t tmp_ackd; | ||
392 | |||
393 | if (sync_ackd == 0) | ||
394 | return BFA_TRUE; | ||
395 | |||
396 | /** | ||
397 | * The check below is to see whether any other PCI fn | ||
398 | * has reinitialized the ASIC (reset sync_ackd bits) | ||
399 | * and failed again while this IOC was waiting for hw | ||
400 | * semaphore (in bfa_iocpf_sm_semwait()). | ||
401 | */ | ||
402 | tmp_ackd = sync_ackd; | ||
403 | if ((sync_reqd & bfa_ioc_ct_sync_pos(ioc)) && | ||
404 | !(sync_ackd & bfa_ioc_ct_sync_pos(ioc))) | ||
405 | sync_ackd |= bfa_ioc_ct_sync_pos(ioc); | ||
406 | |||
407 | if (sync_reqd == sync_ackd) { | ||
408 | writel(bfa_ioc_ct_clear_sync_ackd(r32), | ||
409 | ioc->ioc_regs.ioc_fail_sync); | ||
410 | writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate); | ||
411 | writel(BFI_IOC_FAIL, ioc->ioc_regs.alt_ioc_fwstate); | ||
412 | return BFA_TRUE; | ||
413 | } | ||
414 | |||
415 | /** | ||
416 | * If another PCI fn reinitialized and failed again while | ||
417 | * this IOC was waiting for hw sem, the sync_ackd bit for | ||
418 | * this IOC need to be set again to allow reinitialization. | ||
419 | */ | ||
420 | if (tmp_ackd != sync_ackd) | ||
421 | writel((r32 | sync_ackd), ioc->ioc_regs.ioc_fail_sync); | ||
422 | |||
423 | return BFA_FALSE; | ||
424 | } | ||
330 | 425 | ||
331 | /* | 426 | /* |
332 | * Check the firmware state to know if pll_init has been completed already | 427 | * Check the firmware state to know if pll_init has been completed already |