diff options
| author | Jing Huang <huangj@brocade.com> | 2011-04-13 14:45:53 -0400 |
|---|---|---|
| committer | James Bottomley <jbottomley@parallels.com> | 2011-05-24 12:38:02 -0400 |
| commit | 45d7f0cc58183062adea0a1de3d8cba768134138 (patch) | |
| tree | 1977a1b1a1452a53f5e6504674168235f32ce23a | |
| parent | a5442ba4a428081ebac7090f46c62ffaa17ca951 (diff) | |
[SCSI] bfa: kdump fix
Root cause: When kernel crashes, 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 hang 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: Jing Huang <huangj@brocade.com>
Signed-off-by: James Bottomley <jbottomley@parallels.com>
| -rw-r--r-- | drivers/scsi/bfa/bfa_ioc.c | 4 | ||||
| -rw-r--r-- | drivers/scsi/bfa/bfa_ioc.h | 1 | ||||
| -rw-r--r-- | drivers/scsi/bfa/bfa_ioc_cb.c | 11 | ||||
| -rw-r--r-- | drivers/scsi/bfa/bfa_ioc_ct.c | 26 |
4 files changed, 41 insertions, 1 deletions
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index c1f72c49196f..6c7e0339dda4 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c | |||
| @@ -56,6 +56,8 @@ BFA_TRC_FILE(CNA, IOC); | |||
| 56 | #define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc)) | 56 | #define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc)) |
| 57 | #define bfa_ioc_notify_fail(__ioc) \ | 57 | #define bfa_ioc_notify_fail(__ioc) \ |
| 58 | ((__ioc)->ioc_hwif->ioc_notify_fail(__ioc)) | 58 | ((__ioc)->ioc_hwif->ioc_notify_fail(__ioc)) |
| 59 | #define bfa_ioc_sync_start(__ioc) \ | ||
| 60 | ((__ioc)->ioc_hwif->ioc_sync_start(__ioc)) | ||
| 59 | #define bfa_ioc_sync_join(__ioc) \ | 61 | #define bfa_ioc_sync_join(__ioc) \ |
| 60 | ((__ioc)->ioc_hwif->ioc_sync_join(__ioc)) | 62 | ((__ioc)->ioc_hwif->ioc_sync_join(__ioc)) |
| 61 | #define bfa_ioc_sync_leave(__ioc) \ | 63 | #define bfa_ioc_sync_leave(__ioc) \ |
| @@ -647,7 +649,7 @@ bfa_iocpf_sm_fwcheck(struct bfa_iocpf_s *iocpf, enum iocpf_event event) | |||
| 647 | switch (event) { | 649 | switch (event) { |
| 648 | case IOCPF_E_SEMLOCKED: | 650 | case IOCPF_E_SEMLOCKED: |
| 649 | if (bfa_ioc_firmware_lock(ioc)) { | 651 | if (bfa_ioc_firmware_lock(ioc)) { |
| 650 | if (bfa_ioc_sync_complete(ioc)) { | 652 | if (bfa_ioc_sync_start(ioc)) { |
| 651 | iocpf->retry_count = 0; | 653 | iocpf->retry_count = 0; |
| 652 | bfa_ioc_sync_join(ioc); | 654 | bfa_ioc_sync_join(ioc); |
| 653 | bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit); | 655 | bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit); |
diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h index ec9cf08b0e7f..c85182a704fb 100644 --- a/drivers/scsi/bfa/bfa_ioc.h +++ b/drivers/scsi/bfa/bfa_ioc.h | |||
| @@ -263,6 +263,7 @@ struct bfa_ioc_hwif_s { | |||
| 263 | bfa_boolean_t msix); | 263 | bfa_boolean_t msix); |
| 264 | void (*ioc_notify_fail) (struct bfa_ioc_s *ioc); | 264 | void (*ioc_notify_fail) (struct bfa_ioc_s *ioc); |
| 265 | void (*ioc_ownership_reset) (struct bfa_ioc_s *ioc); | 265 | void (*ioc_ownership_reset) (struct bfa_ioc_s *ioc); |
| 266 | bfa_boolean_t (*ioc_sync_start) (struct bfa_ioc_s *ioc); | ||
| 266 | void (*ioc_sync_join) (struct bfa_ioc_s *ioc); | 267 | void (*ioc_sync_join) (struct bfa_ioc_s *ioc); |
| 267 | void (*ioc_sync_leave) (struct bfa_ioc_s *ioc); | 268 | void (*ioc_sync_leave) (struct bfa_ioc_s *ioc); |
| 268 | void (*ioc_sync_ack) (struct bfa_ioc_s *ioc); | 269 | void (*ioc_sync_ack) (struct bfa_ioc_s *ioc); |
diff --git a/drivers/scsi/bfa/bfa_ioc_cb.c b/drivers/scsi/bfa/bfa_ioc_cb.c index e4a0713185b6..89ae4c8f95a2 100644 --- a/drivers/scsi/bfa/bfa_ioc_cb.c +++ b/drivers/scsi/bfa/bfa_ioc_cb.c | |||
| @@ -32,6 +32,7 @@ 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_fail(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 bfa_boolean_t bfa_ioc_cb_sync_start(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_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_leave(struct bfa_ioc_s *ioc); |
| 37 | static void bfa_ioc_cb_sync_ack(struct bfa_ioc_s *ioc); | 38 | static void bfa_ioc_cb_sync_ack(struct bfa_ioc_s *ioc); |
| @@ -53,6 +54,7 @@ bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc) | |||
| 53 | hwif_cb.ioc_isr_mode_set = bfa_ioc_cb_isr_mode_set; | 54 | hwif_cb.ioc_isr_mode_set = bfa_ioc_cb_isr_mode_set; |
| 54 | hwif_cb.ioc_notify_fail = bfa_ioc_cb_notify_fail; | 55 | hwif_cb.ioc_notify_fail = bfa_ioc_cb_notify_fail; |
| 55 | hwif_cb.ioc_ownership_reset = bfa_ioc_cb_ownership_reset; | 56 | hwif_cb.ioc_ownership_reset = bfa_ioc_cb_ownership_reset; |
| 57 | hwif_cb.ioc_sync_start = bfa_ioc_cb_sync_start; | ||
| 56 | hwif_cb.ioc_sync_join = bfa_ioc_cb_sync_join; | 58 | hwif_cb.ioc_sync_join = bfa_ioc_cb_sync_join; |
| 57 | hwif_cb.ioc_sync_leave = bfa_ioc_cb_sync_leave; | 59 | hwif_cb.ioc_sync_leave = bfa_ioc_cb_sync_leave; |
| 58 | hwif_cb.ioc_sync_ack = bfa_ioc_cb_sync_ack; | 60 | hwif_cb.ioc_sync_ack = bfa_ioc_cb_sync_ack; |
| @@ -195,6 +197,15 @@ bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix) | |||
| 195 | } | 197 | } |
| 196 | 198 | ||
| 197 | /* | 199 | /* |
| 200 | * Synchronized IOC failure processing routines | ||
| 201 | */ | ||
| 202 | static bfa_boolean_t | ||
| 203 | bfa_ioc_cb_sync_start(struct bfa_ioc_s *ioc) | ||
| 204 | { | ||
| 205 | return bfa_ioc_cb_sync_complete(ioc); | ||
| 206 | } | ||
| 207 | |||
| 208 | /* | ||
| 198 | * Cleanup hw semaphore and usecnt registers | 209 | * Cleanup hw semaphore and usecnt registers |
| 199 | */ | 210 | */ |
| 200 | static void | 211 | static void |
diff --git a/drivers/scsi/bfa/bfa_ioc_ct.c b/drivers/scsi/bfa/bfa_ioc_ct.c index 008d129ddfcd..93612520f0d2 100644 --- a/drivers/scsi/bfa/bfa_ioc_ct.c +++ b/drivers/scsi/bfa/bfa_ioc_ct.c | |||
| @@ -41,6 +41,7 @@ static void bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc); | |||
| 41 | 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); |
| 42 | static void bfa_ioc_ct_notify_fail(struct bfa_ioc_s *ioc); | 42 | static void bfa_ioc_ct_notify_fail(struct bfa_ioc_s *ioc); |
| 43 | 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 bfa_boolean_t bfa_ioc_ct_sync_start(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_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_leave(struct bfa_ioc_s *ioc); |
| 46 | static void bfa_ioc_ct_sync_ack(struct bfa_ioc_s *ioc); | 47 | static void bfa_ioc_ct_sync_ack(struct bfa_ioc_s *ioc); |
| @@ -62,6 +63,7 @@ bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc) | |||
| 62 | hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set; | 63 | hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set; |
| 63 | hwif_ct.ioc_notify_fail = bfa_ioc_ct_notify_fail; | 64 | hwif_ct.ioc_notify_fail = bfa_ioc_ct_notify_fail; |
| 64 | hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset; | 65 | hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset; |
| 66 | hwif_ct.ioc_sync_start = bfa_ioc_ct_sync_start; | ||
| 65 | hwif_ct.ioc_sync_join = bfa_ioc_ct_sync_join; | 67 | hwif_ct.ioc_sync_join = bfa_ioc_ct_sync_join; |
| 66 | hwif_ct.ioc_sync_leave = bfa_ioc_ct_sync_leave; | 68 | hwif_ct.ioc_sync_leave = bfa_ioc_ct_sync_leave; |
| 67 | hwif_ct.ioc_sync_ack = bfa_ioc_ct_sync_ack; | 69 | hwif_ct.ioc_sync_ack = bfa_ioc_ct_sync_ack; |
| @@ -351,6 +353,30 @@ bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc) | |||
| 351 | writel(1, ioc->ioc_regs.ioc_sem_reg); | 353 | writel(1, ioc->ioc_regs.ioc_sem_reg); |
| 352 | } | 354 | } |
| 353 | 355 | ||
| 356 | static bfa_boolean_t | ||
| 357 | bfa_ioc_ct_sync_start(struct bfa_ioc_s *ioc) | ||
| 358 | { | ||
| 359 | uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync); | ||
| 360 | uint32_t sync_reqd = bfa_ioc_ct_get_sync_reqd(r32); | ||
| 361 | |||
| 362 | /* | ||
| 363 | * Driver load time. If the sync required bit for this PCI fn | ||
| 364 | * is set, it is due to an unclean exit by the driver for this | ||
| 365 | * PCI fn in the previous incarnation. Whoever comes here first | ||
| 366 | * should clean it up, no matter which PCI fn. | ||
| 367 | */ | ||
| 368 | |||
| 369 | if (sync_reqd & bfa_ioc_ct_sync_pos(ioc)) { | ||
| 370 | writel(0, ioc->ioc_regs.ioc_fail_sync); | ||
| 371 | writel(1, ioc->ioc_regs.ioc_usage_reg); | ||
| 372 | writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate); | ||
| 373 | writel(BFI_IOC_UNINIT, ioc->ioc_regs.alt_ioc_fwstate); | ||
| 374 | return BFA_TRUE; | ||
| 375 | } | ||
| 376 | |||
| 377 | return bfa_ioc_ct_sync_complete(ioc); | ||
| 378 | } | ||
| 379 | |||
| 354 | /* | 380 | /* |
| 355 | * Synchronized IOC failure processing routines | 381 | * Synchronized IOC failure processing routines |
| 356 | */ | 382 | */ |
