aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/bfa/bfa_ioc_ct.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_ct.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_ct.c')
-rw-r--r--drivers/scsi/bfa/bfa_ioc_ct.c101
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
23BFA_TRC_FILE(CNA, IOC_CT); 23BFA_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);
30static void bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc); 39static void bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc);
31static void bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc); 40static void bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc);
32static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix); 41static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix);
33static void bfa_ioc_ct_notify_hbfail(struct bfa_ioc_s *ioc); 42static void bfa_ioc_ct_notify_fail(struct bfa_ioc_s *ioc);
34static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc); 43static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc);
44static void bfa_ioc_ct_sync_join(struct bfa_ioc_s *ioc);
45static void bfa_ioc_ct_sync_leave(struct bfa_ioc_s *ioc);
46static void bfa_ioc_ct_sync_ack(struct bfa_ioc_s *ioc);
47static bfa_boolean_t bfa_ioc_ct_sync_complete(struct bfa_ioc_s *ioc);
35 48
36static struct bfa_ioc_hwif_s hwif_ct; 49static 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 */
155static void 173static void
156bfa_ioc_ct_notify_hbfail(struct bfa_ioc_s *ioc) 174bfa_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 */
357static void
358bfa_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
366static void
367bfa_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
376static void
377bfa_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
385static bfa_boolean_t
386bfa_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