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

Commit 37ea0558 authored by Krishna Gudipati's avatar Krishna Gudipati Committed by James Bottomley
Browse files

[SCSI] bfa: Added support to collect and reset fcport stats



- Added support to collect and reset fcport stats.
- Modified design to allow multiple requests for fcport stats.
  - fcport will remember the stats request in its stats_pending
    queue and service each of the queued requests after receiving
    a firmware response for the prior request.

Signed-off-by: default avatarKrishna Gudipati <kgudipat@brocade.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 42a8e6e2
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
struct bfa_s;

typedef void (*bfa_isr_func_t) (struct bfa_s *bfa, struct bfi_msg_s *m);
typedef void (*bfa_cb_cbfn_status_t) (void *cbarg, bfa_status_t status);

/*
 * Interrupt message handlers
@@ -121,6 +122,7 @@ bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg),
#define bfa_cb_queue(__bfa, __hcb_qe, __cbfn, __cbarg) do {	\
		(__hcb_qe)->cbfn  = (__cbfn);      \
		(__hcb_qe)->cbarg = (__cbarg);      \
		(__hcb_qe)->pre_rmv = BFA_FALSE;		\
		list_add_tail(&(__hcb_qe)->qe, &(__bfa)->comp_q);      \
	} while (0)

@@ -135,6 +137,11 @@ bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg),
		}							\
	} while (0)

#define bfa_cb_queue_status(__bfa, __hcb_qe, __status) do {		\
		(__hcb_qe)->fw_status = (__status);			\
		list_add_tail(&(__hcb_qe)->qe, &(__bfa)->comp_q);	\
} while (0)

#define bfa_cb_queue_done(__hcb_qe) do {	\
		(__hcb_qe)->once = BFA_FALSE;	\
	} while (0)
@@ -408,4 +415,18 @@ void bfa_iocfc_disable(struct bfa_s *bfa);
#define bfa_timer_start(_bfa, _timer, _timercb, _arg, _timeout)		\
	bfa_timer_begin(&(_bfa)->timer_mod, _timer, _timercb, _arg, _timeout)

struct bfa_cb_pending_q_s {
	struct bfa_cb_qe_s	hcb_qe;
	void			*data;  /* Driver buffer */
};

/* Common macros to operate on pending stats/attr apis */
#define bfa_pending_q_init(__qe, __cbfn, __cbarg, __data) do {	\
	bfa_q_qe_init(&((__qe)->hcb_qe.qe));			\
	(__qe)->hcb_qe.cbfn = (__cbfn);				\
	(__qe)->hcb_qe.cbarg = (__cbarg);			\
	(__qe)->hcb_qe.pre_rmv = BFA_TRUE;			\
	(__qe)->data = (__data);				\
} while (0)

#endif /* __BFA_H__ */
+9 −1
Original line number Diff line number Diff line
@@ -1533,9 +1533,16 @@ bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q)
	struct list_head		*qe;
	struct list_head		*qen;
	struct bfa_cb_qe_s	*hcb_qe;
	bfa_cb_cbfn_status_t	cbfn;

	list_for_each_safe(qe, qen, comp_q) {
		hcb_qe = (struct bfa_cb_qe_s *) qe;
		if (hcb_qe->pre_rmv) {
			/* qe is invalid after return, dequeue before cbfn() */
			list_del(qe);
			cbfn = (bfa_cb_cbfn_status_t)(hcb_qe->cbfn);
			cbfn(hcb_qe->cbarg, hcb_qe->fw_status);
		} else
			hcb_qe->cbfn(hcb_qe->cbarg, BFA_TRUE);
	}
}
@@ -1549,6 +1556,7 @@ bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q)
	while (!list_empty(comp_q)) {
		bfa_q_deq(comp_q, &qe);
		hcb_qe = (struct bfa_cb_qe_s *) qe;
		WARN_ON(hcb_qe->pre_rmv);
		hcb_qe->cbfn(hcb_qe->cbarg, BFA_FALSE);
	}
}
+2 −0
Original line number Diff line number Diff line
@@ -367,6 +367,8 @@ struct bfa_cb_qe_s {
	struct list_head	qe;
	bfa_cb_cbfn_t	cbfn;
	bfa_boolean_t	once;
	bfa_boolean_t	pre_rmv;	/* set for stack based qe(s) */
	bfa_status_t	fw_status;	/* to access fw status in comp proc */
	void		*cbarg;
};

+71 −59
Original line number Diff line number Diff line
@@ -2910,6 +2910,9 @@ bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,

	port_cfg->trl_def_speed = BFA_PORT_SPEED_1GBPS;

	INIT_LIST_HEAD(&fcport->stats_pending_q);
	INIT_LIST_HEAD(&fcport->statsclr_pending_q);

	bfa_reqq_winit(&fcport->reqq_wait, bfa_fcport_qresume, fcport);
}

@@ -3138,30 +3141,38 @@ bfa_fcport_fcoe_stats_swap(struct bfa_fcoe_stats_s *d,
static void
__bfa_cb_fcport_stats_get(void *cbarg, bfa_boolean_t complete)
{
	struct bfa_fcport_s *fcport = cbarg;
	struct bfa_fcport_s *fcport = (struct bfa_fcport_s *)cbarg;
	struct bfa_cb_pending_q_s *cb;
	struct list_head *qe, *qen;
	union bfa_fcport_stats_u *ret;

	if (complete) {
		if (fcport->stats_status == BFA_STATUS_OK) {
		struct timeval tv;
		if (fcport->stats_status == BFA_STATUS_OK)
			do_gettimeofday(&tv);

		list_for_each_safe(qe, qen, &fcport->stats_pending_q) {
			bfa_q_deq(&fcport->stats_pending_q, &qe);
			cb = (struct bfa_cb_pending_q_s *)qe;
			if (fcport->stats_status == BFA_STATUS_OK) {
				ret = (union bfa_fcport_stats_u *)cb->data;
				/* Swap FC QoS or FCoE stats */
			if (bfa_ioc_get_fcmode(&fcport->bfa->ioc)) {
				bfa_fcport_qos_stats_swap(
					&fcport->stats_ret->fcqos,
				if (bfa_ioc_get_fcmode(&fcport->bfa->ioc))
					bfa_fcport_qos_stats_swap(&ret->fcqos,
							&fcport->stats->fcqos);
			} else {
				bfa_fcport_fcoe_stats_swap(
					&fcport->stats_ret->fcoe,
				else {
					bfa_fcport_fcoe_stats_swap(&ret->fcoe,
							&fcport->stats->fcoe);

				do_gettimeofday(&tv);
				fcport->stats_ret->fcoe.secs_reset =
					ret->fcoe.secs_reset =
					tv.tv_sec - fcport->stats_reset_time;
				}
			}
		fcport->stats_cbfn(fcport->stats_cbarg, fcport->stats_status);
			bfa_cb_queue_status(fcport->bfa, &cb->hcb_qe,
					fcport->stats_status);
		}
		fcport->stats_status = BFA_STATUS_OK;
	} else {
		fcport->stats_busy = BFA_FALSE;
		INIT_LIST_HEAD(&fcport->stats_pending_q);
		fcport->stats_status = BFA_STATUS_OK;
	}
}
@@ -3179,8 +3190,7 @@ bfa_fcport_stats_get_timeout(void *cbarg)
	}

	fcport->stats_status = BFA_STATUS_ETIMER;
	bfa_cb_queue(fcport->bfa, &fcport->hcb_qe, __bfa_cb_fcport_stats_get,
		fcport);
	__bfa_cb_fcport_stats_get(fcport, BFA_TRUE);
}

static void
@@ -3210,7 +3220,9 @@ bfa_fcport_send_stats_get(void *cbarg)
static void
__bfa_cb_fcport_stats_clr(void *cbarg, bfa_boolean_t complete)
{
	struct bfa_fcport_s *fcport = cbarg;
	struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg;
	struct bfa_cb_pending_q_s *cb;
	struct list_head *qe, *qen;

	if (complete) {
		struct timeval tv;
@@ -3220,10 +3232,15 @@ __bfa_cb_fcport_stats_clr(void *cbarg, bfa_boolean_t complete)
		 */
		do_gettimeofday(&tv);
		fcport->stats_reset_time = tv.tv_sec;

		fcport->stats_cbfn(fcport->stats_cbarg, fcport->stats_status);
		list_for_each_safe(qe, qen, &fcport->statsclr_pending_q) {
			bfa_q_deq(&fcport->statsclr_pending_q, &qe);
			cb = (struct bfa_cb_pending_q_s *)qe;
			bfa_cb_queue_status(fcport->bfa, &cb->hcb_qe,
						fcport->stats_status);
		}
		fcport->stats_status = BFA_STATUS_OK;
	} else {
		fcport->stats_busy = BFA_FALSE;
		INIT_LIST_HEAD(&fcport->statsclr_pending_q);
		fcport->stats_status = BFA_STATUS_OK;
	}
}
@@ -3241,8 +3258,7 @@ bfa_fcport_stats_clr_timeout(void *cbarg)
	}

	fcport->stats_status = BFA_STATUS_ETIMER;
	bfa_cb_queue(fcport->bfa, &fcport->hcb_qe,
			__bfa_cb_fcport_stats_clr, fcport);
	__bfa_cb_fcport_stats_clr(fcport, BFA_TRUE);
}

static void
@@ -3462,28 +3478,26 @@ bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
		/*
		 * check for timer pop before processing the rsp
		 */
		if (fcport->stats_busy == BFA_FALSE ||
		    fcport->stats_status == BFA_STATUS_ETIMER)
		if (list_empty(&fcport->stats_pending_q) ||
		    (fcport->stats_status == BFA_STATUS_ETIMER))
			break;

		bfa_timer_stop(&fcport->timer);
		fcport->stats_status = i2hmsg.pstatsget_rsp->status;
		bfa_cb_queue(fcport->bfa, &fcport->hcb_qe,
				__bfa_cb_fcport_stats_get, fcport);
		__bfa_cb_fcport_stats_get(fcport, BFA_TRUE);
		break;

	case BFI_FCPORT_I2H_STATS_CLEAR_RSP:
		/*
		 * check for timer pop before processing the rsp
		 */
		if (fcport->stats_busy == BFA_FALSE ||
		    fcport->stats_status == BFA_STATUS_ETIMER)
		if (list_empty(&fcport->statsclr_pending_q) ||
		    (fcport->stats_status == BFA_STATUS_ETIMER))
			break;

		bfa_timer_stop(&fcport->timer);
		fcport->stats_status = BFA_STATUS_OK;
		bfa_cb_queue(fcport->bfa, &fcport->hcb_qe,
				__bfa_cb_fcport_stats_clr, fcport);
		__bfa_cb_fcport_stats_clr(fcport, BFA_TRUE);
		break;

	case BFI_FCPORT_I2H_ENABLE_AEN:
@@ -3815,25 +3829,25 @@ bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_port_attr_s *attr)
 * Fetch port statistics (FCQoS or FCoE).
 */
bfa_status_t
bfa_fcport_get_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats,
	bfa_cb_port_t cbfn, void *cbarg)
bfa_fcport_get_stats(struct bfa_s *bfa, struct bfa_cb_pending_q_s *cb)
{
	struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);

	if (fcport->stats_busy) {
		bfa_trc(bfa, fcport->stats_busy);
		return BFA_STATUS_DEVBUSY;
	}
	if (bfa_ioc_is_disabled(&bfa->ioc))
		return BFA_STATUS_IOC_DISABLED;

	fcport->stats_busy  = BFA_TRUE;
	fcport->stats_ret   = stats;
	fcport->stats_cbfn  = cbfn;
	fcport->stats_cbarg = cbarg;
	if (!list_empty(&fcport->statsclr_pending_q))
		return BFA_STATUS_DEVBUSY;

	if (list_empty(&fcport->stats_pending_q)) {
		list_add_tail(&cb->hcb_qe.qe, &fcport->stats_pending_q);
		bfa_fcport_send_stats_get(fcport);

	bfa_timer_start(bfa, &fcport->timer, bfa_fcport_stats_get_timeout,
		bfa_timer_start(bfa, &fcport->timer,
				bfa_fcport_stats_get_timeout,
				fcport, BFA_FCPORT_STATS_TOV);
	} else
		list_add_tail(&cb->hcb_qe.qe, &fcport->stats_pending_q);

	return BFA_STATUS_OK;
}

@@ -3841,27 +3855,25 @@ bfa_fcport_get_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats,
 * Reset port statistics (FCQoS or FCoE).
 */
bfa_status_t
bfa_fcport_clear_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn, void *cbarg)
bfa_fcport_clear_stats(struct bfa_s *bfa, struct bfa_cb_pending_q_s *cb)
{
	struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);

	if (fcport->stats_busy) {
		bfa_trc(bfa, fcport->stats_busy);
	if (!list_empty(&fcport->stats_pending_q))
		return BFA_STATUS_DEVBUSY;
	}

	fcport->stats_busy  = BFA_TRUE;
	fcport->stats_cbfn  = cbfn;
	fcport->stats_cbarg = cbarg;

	if (list_empty(&fcport->statsclr_pending_q)) {
		list_add_tail(&cb->hcb_qe.qe, &fcport->statsclr_pending_q);
		bfa_fcport_send_stats_clear(fcport);

	bfa_timer_start(bfa, &fcport->timer, bfa_fcport_stats_clr_timeout,
		bfa_timer_start(bfa, &fcport->timer,
				bfa_fcport_stats_clr_timeout,
				fcport, BFA_FCPORT_STATS_TOV);
	} else
		list_add_tail(&cb->hcb_qe.qe, &fcport->statsclr_pending_q);

	return BFA_STATUS_OK;
}


/*
 * Fetch port attributes.
 */
+5 −9
Original line number Diff line number Diff line
@@ -441,7 +441,6 @@ void bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
 */

#define BFA_FCPORT(_bfa)	(&((_bfa)->modules.port))
typedef void (*bfa_cb_port_t) (void *cbarg, enum bfa_status status);

/*
 * Link notification data structure
@@ -495,13 +494,11 @@ struct bfa_fcport_s {
	u8			*stats_kva;
	u64		stats_pa;
	union bfa_fcport_stats_u *stats;
	union bfa_fcport_stats_u *stats_ret; /*  driver stats location */
	bfa_status_t		stats_status; /*  stats/statsclr status */
	bfa_boolean_t		stats_busy; /*  outstanding stats/statsclr */
	struct list_head	stats_pending_q;
	struct list_head	statsclr_pending_q;
	bfa_boolean_t		stats_qfull;
	u32		stats_reset_time; /*  stats reset time stamp */
	bfa_cb_port_t		stats_cbfn; /*  driver callback function */
	void			*stats_cbarg; /* *!< user callback arg */
	bfa_boolean_t		diag_busy; /*  diag busy status */
	bfa_boolean_t		beacon; /*  port beacon status */
	bfa_boolean_t		link_e2e_beacon; /*  link beacon status */
@@ -552,10 +549,9 @@ void bfa_fcport_beacon(void *dev, bfa_boolean_t beacon,
			bfa_boolean_t link_e2e_beacon);
bfa_boolean_t	bfa_fcport_is_linkup(struct bfa_s *bfa);
bfa_status_t bfa_fcport_get_stats(struct bfa_s *bfa,
				  union bfa_fcport_stats_u *stats,
				  bfa_cb_port_t cbfn, void *cbarg);
bfa_status_t bfa_fcport_clear_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn,
				    void *cbarg);
			struct bfa_cb_pending_q_s *cb);
bfa_status_t bfa_fcport_clear_stats(struct bfa_s *bfa,
			struct bfa_cb_pending_q_s *cb);
bfa_boolean_t bfa_fcport_is_qos_enabled(struct bfa_s *bfa);
bfa_boolean_t bfa_fcport_is_trunk_enabled(struct bfa_s *bfa);
bfa_status_t bfa_fcport_is_pbcdisabled(struct bfa_s *bfa);
Loading