Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5a0adaed authored by Krishna Gudipati's avatar Krishna Gudipati Committed by James Bottomley
Browse files

[SCSI] bfa: IOC bug fixes.



- 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: default avatarKrishna Gudipati <kgudipat@brocade.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 1a4d8e1b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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;
};

/*
+111 −5
Original line number Diff line number Diff line
@@ -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);
}

+0 −15
Original line number Diff line number Diff line
@@ -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;
}

+10 −13
Original line number Diff line number Diff line
@@ -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);
	}

+2 −1
Original line number Diff line number Diff line
@@ -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	   */