]> Pileus Git - ~andy/linux/commitdiff
[SCSI] bfa: IOC bug fixes.
authorKrishna Gudipati <kgudipat@brocade.com>
Sat, 25 Jun 2011 03:22:56 +0000 (20:22 -0700)
committerJames Bottomley <JBottomley@Parallels.com>
Wed, 29 Jun 2011 21:57:52 +0000 (16:57 -0500)
- Add logic to handle the case where PCI mapping goes away when
  IOCPF state machine is waiting for semaphore.
- Added logic to unlock hw semaphore if the previos FW boot was
  from flash based and the current FW initialization attempt is from OS.
- Added fix to update hbfails and hb_count stats during hwerror event.

Signed-off-by: Krishna Gudipati <kgudipat@brocade.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/bfa/bfa_defs.h
drivers/scsi/bfa/bfa_ioc.c
drivers/scsi/bfa/bfa_ioc_cb.c
drivers/scsi/bfa/bfa_ioc_ct.c
drivers/scsi/bfa/bfi.h

index cced5874cb55fadfbf38a4c9f4a056d2e96111db..c675e65c77a4b7a3a087b6f1fb1df3e9c48944cf 100644 (file)
@@ -274,6 +274,7 @@ enum bfa_ioc_state {
        BFA_IOC_DISABLED        = 10,   /*  IOC is disabled */
        BFA_IOC_FWMISMATCH      = 11,   /*  IOC f/w different from drivers */
        BFA_IOC_ENABLING        = 12,   /*  IOC is being enabled */
+       BFA_IOC_HWFAIL          = 13,   /*  PCI mapping doesn't exist */
 };
 
 /*
@@ -303,6 +304,7 @@ struct bfa_ioc_drv_stats_s {
        u32     enable_reqs;
        u32     disable_replies;
        u32     enable_replies;
+       u32     rsvd;
 };
 
 /*
index 2c575f5dea048cc95f04c4330d96e6da930a4cbb..931bf9769ff272ba7864c7090635735d5608ffd1 100644 (file)
@@ -112,6 +112,7 @@ enum ioc_event {
        IOC_E_HBFAIL            = 9,    /*  heartbeat failure           */
        IOC_E_HWERROR           = 10,   /*  hardware error interrupt    */
        IOC_E_TIMEOUT           = 11,   /*  timeout                     */
+       IOC_E_HWFAILED          = 12,   /*  PCI mapping failure notice  */
 };
 
 bfa_fsm_state_decl(bfa_ioc, uninit, struct bfa_ioc_s, enum ioc_event);
@@ -123,6 +124,7 @@ bfa_fsm_state_decl(bfa_ioc, fail_retry, struct bfa_ioc_s, enum ioc_event);
 bfa_fsm_state_decl(bfa_ioc, fail, struct bfa_ioc_s, enum ioc_event);
 bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc_s, enum ioc_event);
 bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, hwfail, struct bfa_ioc_s, enum ioc_event);
 
 static struct bfa_sm_table_s ioc_sm_table[] = {
        {BFA_SM(bfa_ioc_sm_uninit), BFA_IOC_UNINIT},
@@ -134,6 +136,7 @@ static struct bfa_sm_table_s ioc_sm_table[] = {
        {BFA_SM(bfa_ioc_sm_fail), BFA_IOC_FAIL},
        {BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING},
        {BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED},
+       {BFA_SM(bfa_ioc_sm_hwfail), BFA_IOC_HWFAIL},
 };
 
 /*
@@ -176,6 +179,7 @@ enum iocpf_event {
        IOCPF_E_GETATTRFAIL     = 9,    /*  init fail notice by ioc sm  */
        IOCPF_E_SEMLOCKED       = 10,   /*  h/w semaphore is locked     */
        IOCPF_E_TIMEOUT         = 11,   /*  f/w response timeout        */
+       IOCPF_E_SEM_ERROR       = 12,   /*  h/w sem mapping error       */
 };
 
 /*
@@ -322,6 +326,11 @@ bfa_ioc_sm_enabling(struct bfa_ioc_s *ioc, enum ioc_event event)
                        bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL);
                break;
 
+       case IOC_E_HWFAILED:
+               ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail);
+               break;
+
        case IOC_E_DISABLE:
                bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
                break;
@@ -465,6 +474,11 @@ bfa_ioc_sm_disabling(struct bfa_ioc_s *ioc, enum ioc_event event)
                bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL);
                break;
 
+       case IOC_E_HWFAILED:
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail);
+               bfa_ioc_disable_comp(ioc);
+               break;
+
        default:
                bfa_sm_fault(ioc, event);
        }
@@ -534,6 +548,11 @@ bfa_ioc_sm_fail_retry(struct bfa_ioc_s *ioc, enum ioc_event event)
                        bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL);
                break;
 
+       case IOC_E_HWFAILED:
+               ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail);
+               break;
+
        case IOC_E_ENABLE:
                break;
 
@@ -591,6 +610,35 @@ bfa_ioc_sm_fail(struct bfa_ioc_s *ioc, enum ioc_event event)
        }
 }
 
+static void
+bfa_ioc_sm_hwfail_entry(struct bfa_ioc_s *ioc)
+{
+       bfa_trc(ioc, 0);
+}
+
+static void
+bfa_ioc_sm_hwfail(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+       bfa_trc(ioc, event);
+
+       switch (event) {
+       case IOC_E_ENABLE:
+               ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+               break;
+
+       case IOC_E_DISABLE:
+               ioc->cbfn->disable_cbfn(ioc->bfa);
+               break;
+
+       case IOC_E_DETACH:
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
+               break;
+
+       default:
+               bfa_sm_fault(ioc, event);
+       }
+}
+
 /*
  * IOCPF State Machine
  */
@@ -634,6 +682,28 @@ bfa_iocpf_sm_reset(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
 static void
 bfa_iocpf_sm_fwcheck_entry(struct bfa_iocpf_s *iocpf)
 {
+       struct bfi_ioc_image_hdr_s      fwhdr;
+       u32     fwstate = readl(iocpf->ioc->ioc_regs.ioc_fwstate);
+
+       /* h/w sem init */
+       if (fwstate == BFI_IOC_UNINIT)
+               goto sem_get;
+
+       bfa_ioc_fwver_get(iocpf->ioc, &fwhdr);
+
+       if (swab32(fwhdr.exec) == BFI_FWBOOT_TYPE_NORMAL)
+               goto sem_get;
+
+       bfa_trc(iocpf->ioc, fwstate);
+       bfa_trc(iocpf->ioc, fwhdr.exec);
+       writel(BFI_IOC_UNINIT, iocpf->ioc->ioc_regs.ioc_fwstate);
+
+       /*
+        * Try to lock and then unlock the semaphore.
+        */
+       readl(iocpf->ioc->ioc_regs.ioc_sem_reg);
+       writel(1, iocpf->ioc->ioc_regs.ioc_sem_reg);
+sem_get:
        bfa_ioc_hw_sem_get(iocpf->ioc);
 }
 
@@ -664,6 +734,11 @@ bfa_iocpf_sm_fwcheck(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
                }
                break;
 
+       case IOCPF_E_SEM_ERROR:
+               bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
+               bfa_fsm_send_event(ioc, IOC_E_HWFAILED);
+               break;
+
        case IOCPF_E_DISABLE:
                bfa_sem_timer_stop(ioc);
                bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
@@ -757,6 +832,11 @@ bfa_iocpf_sm_semwait(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
                }
                break;
 
+       case IOCPF_E_SEM_ERROR:
+               bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
+               bfa_fsm_send_event(ioc, IOC_E_HWFAILED);
+               break;
+
        case IOCPF_E_DISABLE:
                bfa_sem_timer_stop(ioc);
                bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
@@ -957,6 +1037,11 @@ bfa_iocpf_sm_disabling_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
                bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
                break;
 
+       case IOCPF_E_SEM_ERROR:
+               bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
+               bfa_fsm_send_event(ioc, IOC_E_HWFAILED);
+               break;
+
        case IOCPF_E_FAIL:
                break;
 
@@ -1000,6 +1085,7 @@ bfa_iocpf_sm_disabled(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
 static void
 bfa_iocpf_sm_initfail_sync_entry(struct bfa_iocpf_s *iocpf)
 {
+       bfa_ioc_debug_save_ftrc(iocpf->ioc);
        bfa_ioc_hw_sem_get(iocpf->ioc);
 }
 
@@ -1022,6 +1108,11 @@ bfa_iocpf_sm_initfail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
                bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);
                break;
 
+       case IOCPF_E_SEM_ERROR:
+               bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
+               bfa_fsm_send_event(ioc, IOC_E_HWFAILED);
+               break;
+
        case IOCPF_E_DISABLE:
                bfa_sem_timer_stop(ioc);
                bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
@@ -1044,6 +1135,7 @@ bfa_iocpf_sm_initfail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
 static void
 bfa_iocpf_sm_initfail_entry(struct bfa_iocpf_s *iocpf)
 {
+       bfa_trc(iocpf->ioc, 0);
 }
 
 /*
@@ -1113,6 +1205,11 @@ bfa_iocpf_sm_fail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
                }
                break;
 
+       case IOCPF_E_SEM_ERROR:
+               bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
+               bfa_fsm_send_event(ioc, IOC_E_HWFAILED);
+               break;
+
        case IOCPF_E_DISABLE:
                bfa_sem_timer_stop(ioc);
                bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
@@ -1129,6 +1226,7 @@ bfa_iocpf_sm_fail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
 static void
 bfa_iocpf_sm_fail_entry(struct bfa_iocpf_s *iocpf)
 {
+       bfa_trc(iocpf->ioc, 0);
 }
 
 /*
@@ -1195,7 +1293,6 @@ bfa_ioc_sem_get(void __iomem *sem_reg)
        if (!(r32 & 1))
                return BFA_TRUE;
 
-       WARN_ON(cnt >= BFA_SEM_SPINCNT);
        return BFA_FALSE;
 }
 
@@ -1209,6 +1306,11 @@ bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc)
         * will return 1. Semaphore is released by writing 1 to the register
         */
        r32 = readl(ioc->ioc_regs.ioc_sem_reg);
+       if (r32 == ~0) {
+               WARN_ON(r32 == ~0);
+               bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEM_ERROR);
+               return;
+       }
        if (!(r32 & 1)) {
                bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEMLOCKED);
                return;
@@ -1617,6 +1719,7 @@ bfa_ioc_getattr_reply(struct bfa_ioc_s *ioc)
        attr->adapter_prop  = be32_to_cpu(attr->adapter_prop);
        attr->card_type     = be32_to_cpu(attr->card_type);
        attr->maxfrsize     = be16_to_cpu(attr->maxfrsize);
+       ioc->fcmode     = (attr->port_mode == BFI_PORT_MODE_FC);
 
        bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR);
 }
@@ -1733,6 +1836,7 @@ bfa_ioc_smem_read(struct bfa_ioc_s *ioc, void *tbuf, u32 soff, u32 sz)
        /*
         *  release semaphore.
         */
+       readl(ioc->ioc_regs.ioc_init_sem_reg);
        writel(1, ioc->ioc_regs.ioc_init_sem_reg);
 
        bfa_trc(ioc, pgnum);
@@ -1789,6 +1893,7 @@ bfa_ioc_smem_clr(struct bfa_ioc_s *ioc, u32 soff, u32 sz)
        /*
         *  release semaphore.
         */
+       readl(ioc->ioc_regs.ioc_init_sem_reg);
        writel(1, ioc->ioc_regs.ioc_init_sem_reg);
        bfa_trc(ioc, pgnum);
        return BFA_STATUS_OK;
@@ -1840,6 +1945,7 @@ bfa_ioc_pll_init(struct bfa_ioc_s *ioc)
        /*
         *  release semaphore.
         */
+       readl(ioc->ioc_regs.ioc_init_sem_reg);
        writel(1, ioc->ioc_regs.ioc_init_sem_reg);
 
        return BFA_STATUS_OK;
@@ -2232,6 +2338,8 @@ bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc)
 void
 bfa_ioc_error_isr(struct bfa_ioc_s *ioc)
 {
+       bfa_ioc_stats(ioc, ioc_hbfails);
+       ioc->stats.hb_count = ioc->hb_count;
        bfa_fsm_send_event(ioc, IOC_E_HWERROR);
 }
 
@@ -2354,15 +2462,12 @@ bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
 enum bfa_ioc_type_e
 bfa_ioc_get_type(struct bfa_ioc_s *ioc)
 {
-       enum bfi_port_mode mode;
-
        if (ioc->clscode == BFI_PCIFN_CLASS_ETH)
                return BFA_IOC_TYPE_LL;
 
        WARN_ON(ioc->clscode != BFI_PCIFN_CLASS_FC);
 
-       mode = (ioc->port_id == 0) ? ioc->port0_mode : ioc->port1_mode;
-       return (mode == BFI_PORT_MODE_FC)
+       return (ioc->attr->port_mode == BFI_PORT_MODE_FC)
                ? BFA_IOC_TYPE_FC : BFA_IOC_TYPE_FCoE;
 }
 
@@ -2739,6 +2844,7 @@ static void
 bfa_ioc_recover(struct bfa_ioc_s *ioc)
 {
        bfa_ioc_stats(ioc, ioc_hbfails);
+       ioc->stats.hb_count = ioc->hb_count;
        bfa_fsm_send_event(ioc, IOC_E_HBFAIL);
 }
 
index e858bc0c48d04739c2f763b03fca2bad9d8518d4..30df8a284715036945085f881db5461bffbc4957 100644 (file)
@@ -69,21 +69,6 @@ bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc)
 static bfa_boolean_t
 bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc)
 {
-       struct bfi_ioc_image_hdr_s fwhdr;
-       uint32_t fwstate = readl(ioc->ioc_regs.ioc_fwstate);
-
-       if (fwstate == BFI_IOC_UNINIT)
-               return BFA_TRUE;
-
-       bfa_ioc_fwver_get(ioc, &fwhdr);
-
-       if (swab32(fwhdr.exec) == BFI_FWBOOT_TYPE_NORMAL)
-               return BFA_TRUE;
-
-       bfa_trc(ioc, fwstate);
-       bfa_trc(ioc, fwhdr.exec);
-       writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate);
-
        return BFA_TRUE;
 }
 
index 5b5579401d43de52baf9421aab14347bed90534d..216016c50d118b8a2a2adb3aca6861c15b5c4170 100644 (file)
@@ -57,12 +57,6 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc)
        u32 usecnt;
        struct bfi_ioc_image_hdr_s fwhdr;
 
-       /*
-        * Firmware match check is relevant only for CNA.
-        */
-       if (!bfa_ioc_is_cna(ioc))
-               return BFA_TRUE;
-
        /*
         * If bios boot (flash based) -- do not increment usage count
         */
@@ -78,6 +72,7 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc)
         */
        if (usecnt == 0) {
                writel(1, ioc->ioc_regs.ioc_usage_reg);
+               readl(ioc->ioc_regs.ioc_usage_sem_reg);
                writel(1, ioc->ioc_regs.ioc_usage_sem_reg);
                writel(0, ioc->ioc_regs.ioc_fail_sync);
                bfa_trc(ioc, usecnt);
@@ -97,6 +92,7 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc)
         */
        bfa_ioc_fwver_get(ioc, &fwhdr);
        if (!bfa_ioc_fwver_cmp(ioc, &fwhdr)) {
+               readl(ioc->ioc_regs.ioc_usage_sem_reg);
                writel(1, ioc->ioc_regs.ioc_usage_sem_reg);
                bfa_trc(ioc, usecnt);
                return BFA_FALSE;
@@ -107,6 +103,7 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc)
         */
        usecnt++;
        writel(usecnt, ioc->ioc_regs.ioc_usage_reg);
+       readl(ioc->ioc_regs.ioc_usage_sem_reg);
        writel(1, ioc->ioc_regs.ioc_usage_sem_reg);
        bfa_trc(ioc, usecnt);
        return BFA_TRUE;
@@ -117,12 +114,6 @@ bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc)
 {
        u32 usecnt;
 
-       /*
-        * Firmware lock is relevant only for CNA.
-        */
-       if (!bfa_ioc_is_cna(ioc))
-               return;
-
        /*
         * If bios boot (flash based) -- do not decrement usage count
         */
@@ -141,6 +132,7 @@ bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc)
        writel(usecnt, ioc->ioc_regs.ioc_usage_reg);
        bfa_trc(ioc, usecnt);
 
+       readl(ioc->ioc_regs.ioc_usage_sem_reg);
        writel(1, ioc->ioc_regs.ioc_usage_sem_reg);
 }
 
@@ -344,7 +336,11 @@ bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc)
 static void
 bfa_ioc_ct2_map_port(struct bfa_ioc_s *ioc)
 {
-       ioc->port_id = bfa_ioc_pcifn(ioc) % 2;
+       void __iomem    *rb = ioc->pcidev.pci_bar_kva;
+       u32     r32;
+
+       r32 = readl(rb + CT2_HOSTFN_PERSONALITY0);
+       ioc->port_id = ((r32 & __FC_LL_PORT_MAP__MK) >> __FC_LL_PORT_MAP__SH);
 
        bfa_trc(ioc, bfa_ioc_pcifn(ioc));
        bfa_trc(ioc, ioc->port_id);
@@ -407,6 +403,7 @@ bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc)
        if (bfa_ioc_is_cna(ioc)) {
                bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
                writel(0, ioc->ioc_regs.ioc_usage_reg);
+               readl(ioc->ioc_regs.ioc_usage_sem_reg);
                writel(1, ioc->ioc_regs.ioc_usage_sem_reg);
        }
 
index d28c7c55a60cc574fb6375f7034a1fdc04914582..02e445612546c4ba693ce5703de14ec581c43bc4 100644 (file)
@@ -236,7 +236,8 @@ struct bfi_ioc_attr_s {
        wwn_t           mfg_pwwn;       /*  Mfg port wwn           */
        wwn_t           mfg_nwwn;       /*  Mfg node wwn           */
        mac_t           mfg_mac;        /*  Mfg mac                */
-       u16     rsvd_a;
+       u8              port_mode;      /* bfi_port_mode           */
+       u8              rsvd_a;
        wwn_t           pwwn;
        wwn_t           nwwn;
        mac_t           mac;            /*  PBC or Mfg mac         */