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

Commit 45c5dc1d authored by Krishna Gudipati's avatar Krishna Gudipati Committed by James Bottomley
Browse files

[SCSI] bfa: Add support to store driver configuration in flash.



- Added dconf (Driver Config) BFA sub-module.
- The dconf sub-module provides interfaces and manages flash writes
  to the flash DRV parition.
- dconf sub-module also ensures that the whole 64K DRV partition is updated
  on a flash write.

Signed-off-by: default avatarKrishna Gudipati <kgudipat@brocade.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent c0350bf5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -412,6 +412,7 @@ bfa_status_t bfa_iocfc_israttr_set(struct bfa_s *bfa,

void bfa_iocfc_enable(struct bfa_s *bfa);
void bfa_iocfc_disable(struct bfa_s *bfa);
void bfa_iocfc_cb_dconf_modinit(struct bfa_s *bfa, bfa_status_t status);
#define bfa_timer_start(_bfa, _timer, _timercb, _arg, _timeout)		\
	bfa_timer_begin(&(_bfa)->timer_mod, _timer, _timercb, _arg, _timeout)

+20 −5
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ static struct bfa_module_s *hal_mods[] = {
	&hal_mod_uf,
	&hal_mod_rport,
	&hal_mod_fcp,
	&hal_mod_dconf,
	NULL
};

@@ -702,7 +703,7 @@ bfa_iocfc_init_cb(void *bfa_arg, bfa_boolean_t complete)
	struct bfa_s	*bfa = bfa_arg;

	if (complete) {
		if (bfa->iocfc.cfgdone)
		if (bfa->iocfc.cfgdone && BFA_DCONF_MOD(bfa)->flashdone)
			bfa_cb_init(bfa->bfad, BFA_STATUS_OK);
		else
			bfa_cb_init(bfa->bfad, BFA_STATUS_FAILED);
@@ -815,9 +816,11 @@ bfa_iocfc_cfgrsp(struct bfa_s *bfa)
	 */
	bfa_fcport_init(bfa);

	if (iocfc->action == BFA_IOCFC_ACT_INIT)
		bfa_cb_queue(bfa, &iocfc->init_hcb_qe, bfa_iocfc_init_cb, bfa);
	else {
	if (iocfc->action == BFA_IOCFC_ACT_INIT) {
		if (BFA_DCONF_MOD(bfa)->flashdone == BFA_TRUE)
			bfa_cb_queue(bfa, &iocfc->init_hcb_qe,
				bfa_iocfc_init_cb, bfa);
	} else {
		if (bfa->iocfc.action == BFA_IOCFC_ACT_ENABLE)
			bfa_cb_queue(bfa, &bfa->iocfc.en_hcb_qe,
					bfa_iocfc_enable_cb, bfa);
@@ -1038,6 +1041,7 @@ bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status)
	}

	bfa_iocfc_send_cfg(bfa);
	bfa_dconf_modinit(bfa);
}

/*
@@ -1200,6 +1204,8 @@ bfa_iocfc_stop(struct bfa_s *bfa)
	bfa->iocfc.action = BFA_IOCFC_ACT_STOP;

	bfa->queue_process = BFA_FALSE;
	bfa_dconf_modexit(bfa);
	if (BFA_DCONF_MOD(bfa)->flashdone == BFA_TRUE)
		bfa_ioc_disable(&bfa->ioc);
}

@@ -1561,6 +1567,15 @@ bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q)
	}
}

void
bfa_iocfc_cb_dconf_modinit(struct bfa_s *bfa, bfa_status_t status)
{
	if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT) {
		if (bfa->iocfc.cfgdone == BFA_TRUE)
			bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe,
				bfa_iocfc_init_cb, bfa);
	}
}

/*
 * Return the list of PCI vendor/device id lists supported by this
+21 −0
Original line number Diff line number Diff line
@@ -788,6 +788,27 @@ enum bfa_port_linkstate_rsn {
	CEE_ISCSI_PRI_OVERLAP_FCOE_PRI		= 43
};
#pragma pack(1)
/*
 * LUN mask configuration
 */
struct bfa_lun_mask_s {
	wwn_t		lp_wwn;
	wwn_t		rp_wwn;
	lun_t		lun;
	u8		ua;
	u8		rsvd[3];
	u16		rp_tag;
	u8		lp_tag;
	u8		state;
};

#define MAX_LUN_MASK_CFG 16
struct bfa_lunmask_cfg_s {
	u32	status;
	u32	rsvd;
	struct bfa_lun_mask_s	lun_list[MAX_LUN_MASK_CFG];
};

/*
 *      Physical port configuration
 */
+1 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include "bfad_drv.h"

typedef u64 wwn_t;
typedef u64 lun_t;

#define WWN_NULL	(0)
#define FC_SYMNAME_MAX	256	/*  max name server symbolic name size */
+393 −0
Original line number Diff line number Diff line
@@ -5588,3 +5588,396 @@ bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg)
		WARN_ON(1);
	}
}

/*
 *	DCONF module specific
 */

BFA_MODULE(dconf);

/*
 * DCONF state machine events
 */
enum bfa_dconf_event {
	BFA_DCONF_SM_INIT		= 1,	/* dconf Init */
	BFA_DCONF_SM_FLASH_COMP		= 2,	/* read/write to flash */
	BFA_DCONF_SM_WR			= 3,	/* binding change, map */
	BFA_DCONF_SM_TIMEOUT		= 4,	/* Start timer */
	BFA_DCONF_SM_EXIT		= 5,	/* exit dconf module */
	BFA_DCONF_SM_IOCDISABLE		= 6,	/* IOC disable event */
};

/* forward declaration of DCONF state machine */
static void bfa_dconf_sm_uninit(struct bfa_dconf_mod_s *dconf,
				enum bfa_dconf_event event);
static void bfa_dconf_sm_flash_read(struct bfa_dconf_mod_s *dconf,
				enum bfa_dconf_event event);
static void bfa_dconf_sm_ready(struct bfa_dconf_mod_s *dconf,
				enum bfa_dconf_event event);
static void bfa_dconf_sm_dirty(struct bfa_dconf_mod_s *dconf,
				enum bfa_dconf_event event);
static void bfa_dconf_sm_sync(struct bfa_dconf_mod_s *dconf,
				enum bfa_dconf_event event);
static void bfa_dconf_sm_final_sync(struct bfa_dconf_mod_s *dconf,
				enum bfa_dconf_event event);
static void bfa_dconf_sm_iocdown_dirty(struct bfa_dconf_mod_s *dconf,
				enum bfa_dconf_event event);

static void bfa_dconf_cbfn(void *dconf, bfa_status_t status);
static void bfa_dconf_timer(void *cbarg);
static bfa_status_t bfa_dconf_flash_write(struct bfa_dconf_mod_s *dconf);
static void bfa_dconf_init_cb(void *arg, bfa_status_t status);

/*
 * Begining state of dconf module. Waiting for an event to start.
 */
static void
bfa_dconf_sm_uninit(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event)
{
	bfa_status_t bfa_status;
	bfa_trc(dconf->bfa, event);

	switch (event) {
	case BFA_DCONF_SM_INIT:
		if (dconf->min_cfg) {
			bfa_trc(dconf->bfa, dconf->min_cfg);
			return;
		}
		bfa_sm_set_state(dconf, bfa_dconf_sm_flash_read);
		dconf->flashdone = BFA_FALSE;
		bfa_trc(dconf->bfa, dconf->flashdone);
		bfa_status = bfa_flash_read_part(BFA_FLASH(dconf->bfa),
					BFA_FLASH_PART_DRV, dconf->instance,
					dconf->dconf,
					sizeof(struct bfa_dconf_s), 0,
					bfa_dconf_init_cb, dconf->bfa);
		if (bfa_status != BFA_STATUS_OK) {
			bfa_dconf_init_cb(dconf->bfa, BFA_STATUS_FAILED);
			bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
			return;
		}
		break;
	case BFA_DCONF_SM_EXIT:
		dconf->flashdone = BFA_TRUE;
	case BFA_DCONF_SM_IOCDISABLE:
	case BFA_DCONF_SM_WR:
	case BFA_DCONF_SM_FLASH_COMP:
		break;
	default:
		bfa_sm_fault(dconf->bfa, event);
	}
}

/*
 * Read flash for dconf entries and make a call back to the driver once done.
 */
static void
bfa_dconf_sm_flash_read(struct bfa_dconf_mod_s *dconf,
			enum bfa_dconf_event event)
{
	bfa_trc(dconf->bfa, event);

	switch (event) {
	case BFA_DCONF_SM_FLASH_COMP:
		bfa_sm_set_state(dconf, bfa_dconf_sm_ready);
		break;
	case BFA_DCONF_SM_TIMEOUT:
		bfa_sm_set_state(dconf, bfa_dconf_sm_ready);
		break;
	case BFA_DCONF_SM_EXIT:
		dconf->flashdone = BFA_TRUE;
		bfa_trc(dconf->bfa, dconf->flashdone);
	case BFA_DCONF_SM_IOCDISABLE:
		bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
		break;
	default:
		bfa_sm_fault(dconf->bfa, event);
	}
}

/*
 * DCONF Module is in ready state. Has completed the initialization.
 */
static void
bfa_dconf_sm_ready(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event)
{
	bfa_trc(dconf->bfa, event);

	switch (event) {
	case BFA_DCONF_SM_WR:
		bfa_timer_start(dconf->bfa, &dconf->timer,
			bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
		bfa_sm_set_state(dconf, bfa_dconf_sm_dirty);
		break;
	case BFA_DCONF_SM_EXIT:
		dconf->flashdone = BFA_TRUE;
		bfa_trc(dconf->bfa, dconf->flashdone);
		bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
		break;
	case BFA_DCONF_SM_INIT:
	case BFA_DCONF_SM_IOCDISABLE:
		break;
	default:
		bfa_sm_fault(dconf->bfa, event);
	}
}

/*
 * entries are dirty, write back to the flash.
 */

static void
bfa_dconf_sm_dirty(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event)
{
	bfa_trc(dconf->bfa, event);

	switch (event) {
	case BFA_DCONF_SM_TIMEOUT:
		bfa_sm_set_state(dconf, bfa_dconf_sm_sync);
		bfa_dconf_flash_write(dconf);
		break;
	case BFA_DCONF_SM_WR:
		bfa_timer_stop(&dconf->timer);
		bfa_timer_start(dconf->bfa, &dconf->timer,
			bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
		break;
	case BFA_DCONF_SM_EXIT:
		bfa_timer_stop(&dconf->timer);
		bfa_timer_start(dconf->bfa, &dconf->timer,
			bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
		bfa_sm_set_state(dconf, bfa_dconf_sm_final_sync);
		bfa_dconf_flash_write(dconf);
		break;
	case BFA_DCONF_SM_FLASH_COMP:
		break;
	case BFA_DCONF_SM_IOCDISABLE:
		bfa_timer_stop(&dconf->timer);
		bfa_sm_set_state(dconf, bfa_dconf_sm_iocdown_dirty);
		break;
	default:
		bfa_sm_fault(dconf->bfa, event);
	}
}

/*
 * Sync the dconf entries to the flash.
 */
static void
bfa_dconf_sm_final_sync(struct bfa_dconf_mod_s *dconf,
			enum bfa_dconf_event event)
{
	bfa_trc(dconf->bfa, event);

	switch (event) {
	case BFA_DCONF_SM_IOCDISABLE:
	case BFA_DCONF_SM_FLASH_COMP:
		bfa_timer_stop(&dconf->timer);
	case BFA_DCONF_SM_TIMEOUT:
		bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
		dconf->flashdone = BFA_TRUE;
		bfa_trc(dconf->bfa, dconf->flashdone);
		bfa_ioc_disable(&dconf->bfa->ioc);
		break;
	default:
		bfa_sm_fault(dconf->bfa, event);
	}
}

static void
bfa_dconf_sm_sync(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event)
{
	bfa_trc(dconf->bfa, event);

	switch (event) {
	case BFA_DCONF_SM_FLASH_COMP:
		bfa_sm_set_state(dconf, bfa_dconf_sm_ready);
		break;
	case BFA_DCONF_SM_WR:
		bfa_timer_start(dconf->bfa, &dconf->timer,
			bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
		bfa_sm_set_state(dconf, bfa_dconf_sm_dirty);
		break;
	case BFA_DCONF_SM_EXIT:
		bfa_timer_start(dconf->bfa, &dconf->timer,
			bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
		bfa_sm_set_state(dconf, bfa_dconf_sm_final_sync);
		break;
	case BFA_DCONF_SM_IOCDISABLE:
		bfa_sm_set_state(dconf, bfa_dconf_sm_iocdown_dirty);
		break;
	default:
		bfa_sm_fault(dconf->bfa, event);
	}
}

static void
bfa_dconf_sm_iocdown_dirty(struct bfa_dconf_mod_s *dconf,
			enum bfa_dconf_event event)
{
	bfa_trc(dconf->bfa, event);

	switch (event) {
	case BFA_DCONF_SM_INIT:
		bfa_timer_start(dconf->bfa, &dconf->timer,
			bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
		bfa_sm_set_state(dconf, bfa_dconf_sm_dirty);
		break;
	case BFA_DCONF_SM_EXIT:
		dconf->flashdone = BFA_TRUE;
		bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
		break;
	case BFA_DCONF_SM_IOCDISABLE:
		break;
	default:
		bfa_sm_fault(dconf->bfa, event);
	}
}

/*
 * Compute and return memory needed by DRV_CFG module.
 */
static void
bfa_dconf_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo,
		  struct bfa_s *bfa)
{
	struct bfa_mem_kva_s *dconf_kva = BFA_MEM_DCONF_KVA(bfa);

	if (cfg->drvcfg.min_cfg)
		bfa_mem_kva_setup(meminfo, dconf_kva,
				sizeof(struct bfa_dconf_hdr_s));
	else
		bfa_mem_kva_setup(meminfo, dconf_kva,
				sizeof(struct bfa_dconf_s));
}

static void
bfa_dconf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
		struct bfa_pcidev_s *pcidev)
{
	struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);

	dconf->bfad = bfad;
	dconf->bfa = bfa;
	dconf->instance = bfa->ioc.port_id;
	bfa_trc(bfa, dconf->instance);

	dconf->dconf = (struct bfa_dconf_s *) bfa_mem_kva_curp(dconf);
	if (cfg->drvcfg.min_cfg) {
		bfa_mem_kva_curp(dconf) += sizeof(struct bfa_dconf_hdr_s);
		dconf->min_cfg = BFA_TRUE;
		/*
		 * Set the flashdone flag to TRUE explicitly as no flash
		 * write will happen in min_cfg mode.
		 */
		dconf->flashdone = BFA_TRUE;
	} else {
		dconf->min_cfg = BFA_FALSE;
		bfa_mem_kva_curp(dconf) += sizeof(struct bfa_dconf_s);
	}

	bfa_dconf_read_data_valid(bfa) = BFA_FALSE;
	bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
}

static void
bfa_dconf_init_cb(void *arg, bfa_status_t status)
{
	struct bfa_s *bfa = arg;
	struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);

	dconf->flashdone = BFA_TRUE;
	bfa_trc(bfa, dconf->flashdone);
	bfa_iocfc_cb_dconf_modinit(bfa, status);
	if (status == BFA_STATUS_OK) {
		bfa_dconf_read_data_valid(bfa) = BFA_TRUE;
		if (dconf->dconf->hdr.signature != BFI_DCONF_SIGNATURE)
			dconf->dconf->hdr.signature = BFI_DCONF_SIGNATURE;
		if (dconf->dconf->hdr.version != BFI_DCONF_VERSION)
			dconf->dconf->hdr.version = BFI_DCONF_VERSION;
	}
	bfa_sm_send_event(dconf, BFA_DCONF_SM_FLASH_COMP);
}

void
bfa_dconf_modinit(struct bfa_s *bfa)
{
	struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);
	bfa_sm_send_event(dconf, BFA_DCONF_SM_INIT);
}
static void
bfa_dconf_start(struct bfa_s *bfa)
{
}

static void
bfa_dconf_stop(struct bfa_s *bfa)
{
}

static void bfa_dconf_timer(void *cbarg)
{
	struct bfa_dconf_mod_s *dconf = cbarg;
	bfa_sm_send_event(dconf, BFA_DCONF_SM_TIMEOUT);
}
static void
bfa_dconf_iocdisable(struct bfa_s *bfa)
{
	struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);
	bfa_sm_send_event(dconf, BFA_DCONF_SM_IOCDISABLE);
}

static void
bfa_dconf_detach(struct bfa_s *bfa)
{
}

static bfa_status_t
bfa_dconf_flash_write(struct bfa_dconf_mod_s *dconf)
{
	bfa_status_t bfa_status;
	bfa_trc(dconf->bfa, 0);

	bfa_status = bfa_flash_update_part(BFA_FLASH(dconf->bfa),
				BFA_FLASH_PART_DRV, dconf->instance,
				dconf->dconf,  sizeof(struct bfa_dconf_s), 0,
				bfa_dconf_cbfn, dconf);
	if (bfa_status != BFA_STATUS_OK)
		WARN_ON(bfa_status);
	bfa_trc(dconf->bfa, bfa_status);

	return bfa_status;
}

bfa_status_t
bfa_dconf_update(struct bfa_s *bfa)
{
	struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);
	bfa_trc(dconf->bfa, 0);
	if (bfa_sm_cmp_state(dconf, bfa_dconf_sm_iocdown_dirty))
		return BFA_STATUS_FAILED;

	if (dconf->min_cfg) {
		bfa_trc(dconf->bfa, dconf->min_cfg);
		return BFA_STATUS_FAILED;
	}

	bfa_sm_send_event(dconf, BFA_DCONF_SM_WR);
	return BFA_STATUS_OK;
}

static void
bfa_dconf_cbfn(void *arg, bfa_status_t status)
{
	struct bfa_dconf_mod_s *dconf = arg;
	WARN_ON(status);
	bfa_sm_send_event(dconf, BFA_DCONF_SM_FLASH_COMP);
}

void
bfa_dconf_modexit(struct bfa_s *bfa)
{
	struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);
	BFA_DCONF_MOD(bfa)->flashdone = BFA_FALSE;
	bfa_trc(bfa, BFA_DCONF_MOD(bfa)->flashdone);
	bfa_sm_send_event(dconf, BFA_DCONF_SM_EXIT);
}
Loading