Commit c679b599afa5dd38d20e058aa68bc94c1c1416a1

Authored by Vijaya Mohan Guvva
Committed by James Bottomley
1 parent f2a0cc3ffd

[SCSI] bfa: kdump fix on 815 and 825 adapters

Root cause: When kernel crashes, On brocade 815/825 adapters,
 bfa IOC state machine and FW doesn't get a notification and
hence are not cleanly shutdown. So registers holding driver/IOC
state information are not reset back to valid disabled/parking
values. This causes subsequent driver initialization to fail
during kdump kernel boot.

Fix description: during the initialization of first PCI function, reset
corresponding register when unclean shutown is detect by reading chip
registers. This will make sure that ioc/fw gets clean re-initialization.

Signed-off-by: Vijaya Mohan Guvva <vmohan@brocade.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>

Showing 5 changed files with 150 additions and 24 deletions Side-by-side Diff

drivers/scsi/bfa/bfa_ioc.c
... ... @@ -67,6 +67,14 @@
67 67 ((__ioc)->ioc_hwif->ioc_sync_ack(__ioc))
68 68 #define bfa_ioc_sync_complete(__ioc) \
69 69 ((__ioc)->ioc_hwif->ioc_sync_complete(__ioc))
  70 +#define bfa_ioc_set_cur_ioc_fwstate(__ioc, __fwstate) \
  71 + ((__ioc)->ioc_hwif->ioc_set_fwstate(__ioc, __fwstate))
  72 +#define bfa_ioc_get_cur_ioc_fwstate(__ioc) \
  73 + ((__ioc)->ioc_hwif->ioc_get_fwstate(__ioc))
  74 +#define bfa_ioc_set_alt_ioc_fwstate(__ioc, __fwstate) \
  75 + ((__ioc)->ioc_hwif->ioc_set_alt_fwstate(__ioc, __fwstate))
  76 +#define bfa_ioc_get_alt_ioc_fwstate(__ioc) \
  77 + ((__ioc)->ioc_hwif->ioc_get_alt_fwstate(__ioc))
70 78  
71 79 #define bfa_ioc_mbox_cmd_pending(__ioc) \
72 80 (!list_empty(&((__ioc)->mbox_mod.cmd_q)) || \
... ... @@ -698,7 +706,7 @@
698 706 }
699 707  
700 708 /* h/w sem init */
701   - fwstate = readl(iocpf->ioc->ioc_regs.ioc_fwstate);
  709 + fwstate = bfa_ioc_get_cur_ioc_fwstate(iocpf->ioc);
702 710 if (fwstate == BFI_IOC_UNINIT) {
703 711 writel(1, iocpf->ioc->ioc_regs.ioc_init_sem_reg);
704 712 goto sem_get;
... ... @@ -725,8 +733,8 @@
725 733  
726 734 bfa_trc(iocpf->ioc, fwstate);
727 735 bfa_trc(iocpf->ioc, swab32(fwhdr.exec));
728   - writel(BFI_IOC_UNINIT, iocpf->ioc->ioc_regs.ioc_fwstate);
729   - writel(BFI_IOC_UNINIT, iocpf->ioc->ioc_regs.alt_ioc_fwstate);
  736 + bfa_ioc_set_cur_ioc_fwstate(iocpf->ioc, BFI_IOC_UNINIT);
  737 + bfa_ioc_set_alt_ioc_fwstate(iocpf->ioc, BFI_IOC_UNINIT);
730 738  
731 739 /*
732 740 * Unlock the hw semaphore. Should be here only once per boot.
... ... @@ -1037,7 +1045,7 @@
1037 1045 */
1038 1046  
1039 1047 case IOCPF_E_TIMEOUT:
1040   - writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
  1048 + bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL);
1041 1049 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
1042 1050 break;
1043 1051  
... ... @@ -1138,7 +1146,7 @@
1138 1146 case IOCPF_E_SEMLOCKED:
1139 1147 bfa_ioc_notify_fail(ioc);
1140 1148 bfa_ioc_sync_leave(ioc);
1141   - writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
  1149 + bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL);
1142 1150 writel(1, ioc->ioc_regs.ioc_sem_reg);
1143 1151 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);
1144 1152 break;
... ... @@ -1227,7 +1235,7 @@
1227 1235 bfa_ioc_notify_fail(ioc);
1228 1236 if (!iocpf->auto_recover) {
1229 1237 bfa_ioc_sync_leave(ioc);
1230   - writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
  1238 + bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL);
1231 1239 writel(1, ioc->ioc_regs.ioc_sem_reg);
1232 1240 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
1233 1241 } else {
... ... @@ -1519,7 +1527,7 @@
1519 1527 u32 boot_type;
1520 1528 u32 boot_env;
1521 1529  
1522   - ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate);
  1530 + ioc_fwstate = bfa_ioc_get_cur_ioc_fwstate(ioc);
1523 1531  
1524 1532 if (force)
1525 1533 ioc_fwstate = BFI_IOC_UNINIT;
1526 1534  
... ... @@ -2006,11 +2014,11 @@
2006 2014 * Initialize IOC state of all functions on a chip reset.
2007 2015 */
2008 2016 if (boot_type == BFI_FWBOOT_TYPE_MEMTEST) {
2009   - writel(BFI_IOC_MEMTEST, ioc->ioc_regs.ioc_fwstate);
2010   - writel(BFI_IOC_MEMTEST, ioc->ioc_regs.alt_ioc_fwstate);
  2017 + bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_MEMTEST);
  2018 + bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_MEMTEST);
2011 2019 } else {
2012   - writel(BFI_IOC_INITING, ioc->ioc_regs.ioc_fwstate);
2013   - writel(BFI_IOC_INITING, ioc->ioc_regs.alt_ioc_fwstate);
  2020 + bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_INITING);
  2021 + bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_INITING);
2014 2022 }
2015 2023  
2016 2024 bfa_ioc_msgflush(ioc);
... ... @@ -2038,7 +2046,7 @@
2038 2046 bfa_boolean_t
2039 2047 bfa_ioc_is_initialized(struct bfa_ioc_s *ioc)
2040 2048 {
2041   - u32 r32 = readl(ioc->ioc_regs.ioc_fwstate);
  2049 + u32 r32 = bfa_ioc_get_cur_ioc_fwstate(ioc);
2042 2050  
2043 2051 return ((r32 != BFI_IOC_UNINIT) &&
2044 2052 (r32 != BFI_IOC_INITING) &&
2045 2053  
... ... @@ -2430,12 +2438,12 @@
2430 2438 if (!bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled))
2431 2439 return BFA_FALSE;
2432 2440  
2433   - ioc_state = readl(ioc->ioc_regs.ioc_fwstate);
  2441 + ioc_state = bfa_ioc_get_cur_ioc_fwstate(ioc);
2434 2442 if (!bfa_ioc_state_disabled(ioc_state))
2435 2443 return BFA_FALSE;
2436 2444  
2437 2445 if (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_FC_8G1P) {
2438   - ioc_state = readl(ioc->ioc_regs.alt_ioc_fwstate);
  2446 + ioc_state = bfa_ioc_get_cur_ioc_fwstate(ioc);
2439 2447 if (!bfa_ioc_state_disabled(ioc_state))
2440 2448 return BFA_FALSE;
2441 2449 }
... ... @@ -2449,8 +2457,8 @@
2449 2457 void
2450 2458 bfa_ioc_reset_fwstate(struct bfa_ioc_s *ioc)
2451 2459 {
2452   - writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate);
2453   - writel(BFI_IOC_UNINIT, ioc->ioc_regs.alt_ioc_fwstate);
  2460 + bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_UNINIT);
  2461 + bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_UNINIT);
2454 2462 }
2455 2463  
2456 2464 #define BFA_MFG_NAME "Brocade"
... ... @@ -2917,7 +2925,7 @@
2917 2925 static void
2918 2926 bfa_ioc_poll_fwinit(struct bfa_ioc_s *ioc)
2919 2927 {
2920   - u32 fwstate = readl(ioc->ioc_regs.ioc_fwstate);
  2928 + u32 fwstate = bfa_ioc_get_cur_ioc_fwstate(ioc);
2921 2929  
2922 2930 bfa_trc(ioc, fwstate);
2923 2931  
drivers/scsi/bfa/bfa_ioc.h
... ... @@ -346,6 +346,12 @@
346 346 void (*ioc_sync_ack) (struct bfa_ioc_s *ioc);
347 347 bfa_boolean_t (*ioc_sync_complete) (struct bfa_ioc_s *ioc);
348 348 bfa_boolean_t (*ioc_lpu_read_stat) (struct bfa_ioc_s *ioc);
  349 + void (*ioc_set_fwstate) (struct bfa_ioc_s *ioc,
  350 + enum bfi_ioc_state fwstate);
  351 + enum bfi_ioc_state (*ioc_get_fwstate) (struct bfa_ioc_s *ioc);
  352 + void (*ioc_set_alt_fwstate) (struct bfa_ioc_s *ioc,
  353 + enum bfi_ioc_state fwstate);
  354 + enum bfi_ioc_state (*ioc_get_alt_fwstate) (struct bfa_ioc_s *ioc);
349 355 };
350 356  
351 357 /*
drivers/scsi/bfa/bfa_ioc_cb.c
... ... @@ -22,6 +22,8 @@
22 22  
23 23 BFA_TRC_FILE(CNA, IOC_CB);
24 24  
  25 +#define bfa_ioc_cb_join_pos(__ioc) ((u32) (1 << BFA_IOC_CB_JOIN_SH))
  26 +
25 27 /*
26 28 * forward declarations
27 29 */
... ... @@ -37,6 +39,12 @@
37 39 static void bfa_ioc_cb_sync_leave(struct bfa_ioc_s *ioc);
38 40 static void bfa_ioc_cb_sync_ack(struct bfa_ioc_s *ioc);
39 41 static bfa_boolean_t bfa_ioc_cb_sync_complete(struct bfa_ioc_s *ioc);
  42 +static void bfa_ioc_cb_set_cur_ioc_fwstate(
  43 + struct bfa_ioc_s *ioc, enum bfi_ioc_state fwstate);
  44 +static enum bfi_ioc_state bfa_ioc_cb_get_cur_ioc_fwstate(struct bfa_ioc_s *ioc);
  45 +static void bfa_ioc_cb_set_alt_ioc_fwstate(
  46 + struct bfa_ioc_s *ioc, enum bfi_ioc_state fwstate);
  47 +static enum bfi_ioc_state bfa_ioc_cb_get_alt_ioc_fwstate(struct bfa_ioc_s *ioc);
40 48  
41 49 static struct bfa_ioc_hwif_s hwif_cb;
42 50  
... ... @@ -59,6 +67,10 @@
59 67 hwif_cb.ioc_sync_leave = bfa_ioc_cb_sync_leave;
60 68 hwif_cb.ioc_sync_ack = bfa_ioc_cb_sync_ack;
61 69 hwif_cb.ioc_sync_complete = bfa_ioc_cb_sync_complete;
  70 + hwif_cb.ioc_set_fwstate = bfa_ioc_cb_set_cur_ioc_fwstate;
  71 + hwif_cb.ioc_get_fwstate = bfa_ioc_cb_get_cur_ioc_fwstate;
  72 + hwif_cb.ioc_set_alt_fwstate = bfa_ioc_cb_set_alt_ioc_fwstate;
  73 + hwif_cb.ioc_get_alt_fwstate = bfa_ioc_cb_get_alt_ioc_fwstate;
62 74  
63 75 ioc->ioc_hwif = &hwif_cb;
64 76 }
... ... @@ -187,6 +199,20 @@
187 199 static bfa_boolean_t
188 200 bfa_ioc_cb_sync_start(struct bfa_ioc_s *ioc)
189 201 {
  202 + u32 ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate);
  203 +
  204 + /**
  205 + * Driver load time. If the join bit is set,
  206 + * it is due to an unclean exit by the driver for this
  207 + * PCI fn in the previous incarnation. Whoever comes here first
  208 + * should clean it up, no matter which PCI fn.
  209 + */
  210 + if (ioc_fwstate & BFA_IOC_CB_JOIN_MASK) {
  211 + writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate);
  212 + writel(BFI_IOC_UNINIT, ioc->ioc_regs.alt_ioc_fwstate);
  213 + return BFA_TRUE;
  214 + }
  215 +
190 216 return bfa_ioc_cb_sync_complete(ioc);
191 217 }
192 218  
193 219  
194 220  
195 221  
196 222  
... ... @@ -212,24 +238,66 @@
212 238 static void
213 239 bfa_ioc_cb_sync_join(struct bfa_ioc_s *ioc)
214 240 {
  241 + u32 r32 = readl(ioc->ioc_regs.ioc_fwstate);
  242 + u32 join_pos = bfa_ioc_cb_join_pos(ioc);
  243 +
  244 + writel((r32 | join_pos), ioc->ioc_regs.ioc_fwstate);
215 245 }
216 246  
217 247 static void
218 248 bfa_ioc_cb_sync_leave(struct bfa_ioc_s *ioc)
219 249 {
  250 + u32 r32 = readl(ioc->ioc_regs.ioc_fwstate);
  251 + u32 join_pos = bfa_ioc_cb_join_pos(ioc);
  252 +
  253 + writel((r32 & ~join_pos), ioc->ioc_regs.ioc_fwstate);
220 254 }
221 255  
222 256 static void
  257 +bfa_ioc_cb_set_cur_ioc_fwstate(struct bfa_ioc_s *ioc,
  258 + enum bfi_ioc_state fwstate)
  259 +{
  260 + u32 r32 = readl(ioc->ioc_regs.ioc_fwstate);
  261 +
  262 + writel((fwstate | (r32 & BFA_IOC_CB_JOIN_MASK)),
  263 + ioc->ioc_regs.ioc_fwstate);
  264 +}
  265 +
  266 +static enum bfi_ioc_state
  267 +bfa_ioc_cb_get_cur_ioc_fwstate(struct bfa_ioc_s *ioc)
  268 +{
  269 + return (enum bfi_ioc_state)(readl(ioc->ioc_regs.ioc_fwstate) &
  270 + BFA_IOC_CB_FWSTATE_MASK);
  271 +}
  272 +
  273 +static void
  274 +bfa_ioc_cb_set_alt_ioc_fwstate(struct bfa_ioc_s *ioc,
  275 + enum bfi_ioc_state fwstate)
  276 +{
  277 + u32 r32 = readl(ioc->ioc_regs.alt_ioc_fwstate);
  278 +
  279 + writel((fwstate | (r32 & BFA_IOC_CB_JOIN_MASK)),
  280 + ioc->ioc_regs.alt_ioc_fwstate);
  281 +}
  282 +
  283 +static enum bfi_ioc_state
  284 +bfa_ioc_cb_get_alt_ioc_fwstate(struct bfa_ioc_s *ioc)
  285 +{
  286 + return (enum bfi_ioc_state)(readl(ioc->ioc_regs.alt_ioc_fwstate) &
  287 + BFA_IOC_CB_FWSTATE_MASK);
  288 +}
  289 +
  290 +static void
223 291 bfa_ioc_cb_sync_ack(struct bfa_ioc_s *ioc)
224 292 {
225   - writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
  293 + bfa_ioc_cb_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL);
226 294 }
227 295  
228 296 static bfa_boolean_t
229 297 bfa_ioc_cb_sync_complete(struct bfa_ioc_s *ioc)
230 298 {
231   - uint32_t fwstate, alt_fwstate;
232   - fwstate = readl(ioc->ioc_regs.ioc_fwstate);
  299 + u32 fwstate, alt_fwstate;
  300 + fwstate = bfa_ioc_cb_get_cur_ioc_fwstate(ioc);
233 301  
234 302 /*
235 303 * At this point, this IOC is hoding the hw sem in the
... ... @@ -257,7 +325,7 @@
257 325 fwstate == BFI_IOC_OP)
258 326 return BFA_TRUE;
259 327 else {
260   - alt_fwstate = readl(ioc->ioc_regs.alt_ioc_fwstate);
  328 + alt_fwstate = bfa_ioc_cb_get_alt_ioc_fwstate(ioc);
261 329 if (alt_fwstate == BFI_IOC_FAIL ||
262 330 alt_fwstate == BFI_IOC_DISABLED ||
263 331 alt_fwstate == BFI_IOC_UNINIT ||
... ... @@ -272,7 +340,7 @@
272 340 bfa_status_t
273 341 bfa_ioc_cb_pll_init(void __iomem *rb, enum bfi_asic_mode fcmode)
274 342 {
275   - u32 pll_sclk, pll_fclk;
  343 + u32 pll_sclk, pll_fclk, join_bits;
276 344  
277 345 pll_sclk = __APP_PLL_SCLK_ENABLE | __APP_PLL_SCLK_LRESETN |
278 346 __APP_PLL_SCLK_P0_1(3U) |
... ... @@ -282,8 +350,12 @@
282 350 __APP_PLL_LCLK_RSEL200500 | __APP_PLL_LCLK_P0_1(3U) |
283 351 __APP_PLL_LCLK_JITLMT0_1(3U) |
284 352 __APP_PLL_LCLK_CNTLMT0_1(3U);
285   - writel(BFI_IOC_UNINIT, (rb + BFA_IOC0_STATE_REG));
286   - writel(BFI_IOC_UNINIT, (rb + BFA_IOC1_STATE_REG));
  353 + join_bits = readl(rb + BFA_IOC0_STATE_REG) &
  354 + BFA_IOC_CB_JOIN_MASK;
  355 + writel((BFI_IOC_UNINIT | join_bits), (rb + BFA_IOC0_STATE_REG));
  356 + join_bits = readl(rb + BFA_IOC1_STATE_REG) &
  357 + BFA_IOC_CB_JOIN_MASK;
  358 + writel((BFI_IOC_UNINIT | join_bits), (rb + BFA_IOC1_STATE_REG));
287 359 writel(0xffffffffU, (rb + HOSTFN0_INT_MSK));
288 360 writel(0xffffffffU, (rb + HOSTFN1_INT_MSK));
289 361 writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS));
drivers/scsi/bfa/bfa_ioc_ct.c
... ... @@ -43,6 +43,12 @@
43 43 static void bfa_ioc_ct_sync_leave(struct bfa_ioc_s *ioc);
44 44 static void bfa_ioc_ct_sync_ack(struct bfa_ioc_s *ioc);
45 45 static bfa_boolean_t bfa_ioc_ct_sync_complete(struct bfa_ioc_s *ioc);
  46 +static void bfa_ioc_ct_set_cur_ioc_fwstate(
  47 + struct bfa_ioc_s *ioc, enum bfi_ioc_state fwstate);
  48 +static enum bfi_ioc_state bfa_ioc_ct_get_cur_ioc_fwstate(struct bfa_ioc_s *ioc);
  49 +static void bfa_ioc_ct_set_alt_ioc_fwstate(
  50 + struct bfa_ioc_s *ioc, enum bfi_ioc_state fwstate);
  51 +static enum bfi_ioc_state bfa_ioc_ct_get_alt_ioc_fwstate(struct bfa_ioc_s *ioc);
46 52  
47 53 static struct bfa_ioc_hwif_s hwif_ct;
48 54 static struct bfa_ioc_hwif_s hwif_ct2;
... ... @@ -512,6 +518,10 @@
512 518 hwif->ioc_sync_leave = bfa_ioc_ct_sync_leave;
513 519 hwif->ioc_sync_ack = bfa_ioc_ct_sync_ack;
514 520 hwif->ioc_sync_complete = bfa_ioc_ct_sync_complete;
  521 + hwif->ioc_set_fwstate = bfa_ioc_ct_set_cur_ioc_fwstate;
  522 + hwif->ioc_get_fwstate = bfa_ioc_ct_get_cur_ioc_fwstate;
  523 + hwif->ioc_set_alt_fwstate = bfa_ioc_ct_set_alt_ioc_fwstate;
  524 + hwif->ioc_get_alt_fwstate = bfa_ioc_ct_get_alt_ioc_fwstate;
515 525 }
516 526  
517 527 /**
... ... @@ -958,5 +968,31 @@
958 968 writel(BFI_IOC_UNINIT, (rb + CT2_BFA_IOC1_STATE_REG));
959 969  
960 970 return BFA_STATUS_OK;
  971 +}
  972 +
  973 +static void
  974 +bfa_ioc_ct_set_cur_ioc_fwstate(struct bfa_ioc_s *ioc,
  975 + enum bfi_ioc_state fwstate)
  976 +{
  977 + writel(fwstate, ioc->ioc_regs.ioc_fwstate);
  978 +}
  979 +
  980 +static enum bfi_ioc_state
  981 +bfa_ioc_ct_get_cur_ioc_fwstate(struct bfa_ioc_s *ioc)
  982 +{
  983 + return (enum bfi_ioc_state)readl(ioc->ioc_regs.ioc_fwstate);
  984 +}
  985 +
  986 +static void
  987 +bfa_ioc_ct_set_alt_ioc_fwstate(struct bfa_ioc_s *ioc,
  988 + enum bfi_ioc_state fwstate)
  989 +{
  990 + writel(fwstate, ioc->ioc_regs.alt_ioc_fwstate);
  991 +}
  992 +
  993 +static enum bfi_ioc_state
  994 +bfa_ioc_ct_get_alt_ioc_fwstate(struct bfa_ioc_s *ioc)
  995 +{
  996 + return (enum bfi_ioc_state) readl(ioc->ioc_regs.alt_ioc_fwstate);
961 997 }
drivers/scsi/bfa/bfi.h
... ... @@ -374,6 +374,10 @@
374 374 BFI_IOC_MEMTEST = 9, /* IOC is doing memtest */
375 375 };
376 376  
  377 +#define BFA_IOC_CB_JOIN_SH 16
  378 +#define BFA_IOC_CB_FWSTATE_MASK 0x0000ffff
  379 +#define BFA_IOC_CB_JOIN_MASK 0xffff0000
  380 +
377 381 #define BFI_IOC_ENDIAN_SIG 0x12345678
378 382  
379 383 enum {