aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/bfa
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/bfa')
-rw-r--r--drivers/scsi/bfa/bfa_fcport.c232
-rw-r--r--drivers/scsi/bfa/bfa_port_priv.h13
2 files changed, 230 insertions, 15 deletions
diff --git a/drivers/scsi/bfa/bfa_fcport.c b/drivers/scsi/bfa/bfa_fcport.c
index aef648b55dfc..4ed048bf45cb 100644
--- a/drivers/scsi/bfa/bfa_fcport.c
+++ b/drivers/scsi/bfa/bfa_fcport.c
@@ -26,16 +26,6 @@
BFA_TRC_FILE(HAL, PPORT);
BFA_MODULE(pport);
-#define bfa_pport_callback(__pport, __event) do { \
- if ((__pport)->bfa->fcs) { \
- (__pport)->event_cbfn((__pport)->event_cbarg, (__event)); \
- } else { \
- (__pport)->hcb_event = (__event); \
- bfa_cb_queue((__pport)->bfa, &(__pport)->hcb_qe, \
- __bfa_cb_port_event, (__pport)); \
- } \
-} while (0)
-
/*
* The port is considered disabled if corresponding physical port or IOC are
* disabled explicitly
@@ -57,7 +47,10 @@ static void __bfa_cb_port_stats(void *cbarg, bfa_boolean_t complete);
static void __bfa_cb_port_stats_clr(void *cbarg, bfa_boolean_t complete);
static void bfa_port_stats_timeout(void *cbarg);
static void bfa_port_stats_clr_timeout(void *cbarg);
-
+static void bfa_pport_callback(struct bfa_pport_s *pport,
+ enum bfa_pport_linkstate event);
+static void bfa_pport_queue_cb(struct bfa_pport_ln_s *ln,
+ enum bfa_pport_linkstate event);
/**
* bfa_pport_private
*/
@@ -77,6 +70,16 @@ enum bfa_pport_sm_event {
BFA_PPORT_SM_HWFAIL = 9, /* IOC h/w failure */
};
+/**
+ * BFA port link notification state machine events
+ */
+
+enum bfa_pport_ln_sm_event {
+ BFA_PPORT_LN_SM_LINKUP = 1, /* linkup event */
+ BFA_PPORT_LN_SM_LINKDOWN = 2, /* linkdown event */
+ BFA_PPORT_LN_SM_NOTIFICATION = 3 /* done notification */
+};
+
static void bfa_pport_sm_uninit(struct bfa_pport_s *pport,
enum bfa_pport_sm_event event);
static void bfa_pport_sm_enabling_qwait(struct bfa_pport_s *pport,
@@ -100,6 +103,21 @@ static void bfa_pport_sm_iocdown(struct bfa_pport_s *pport,
static void bfa_pport_sm_iocfail(struct bfa_pport_s *pport,
enum bfa_pport_sm_event event);
+static void bfa_pport_ln_sm_dn(struct bfa_pport_ln_s *ln,
+ enum bfa_pport_ln_sm_event event);
+static void bfa_pport_ln_sm_dn_nf(struct bfa_pport_ln_s *ln,
+ enum bfa_pport_ln_sm_event event);
+static void bfa_pport_ln_sm_dn_up_nf(struct bfa_pport_ln_s *ln,
+ enum bfa_pport_ln_sm_event event);
+static void bfa_pport_ln_sm_up(struct bfa_pport_ln_s *ln,
+ enum bfa_pport_ln_sm_event event);
+static void bfa_pport_ln_sm_up_nf(struct bfa_pport_ln_s *ln,
+ enum bfa_pport_ln_sm_event event);
+static void bfa_pport_ln_sm_up_dn_nf(struct bfa_pport_ln_s *ln,
+ enum bfa_pport_ln_sm_event event);
+static void bfa_pport_ln_sm_up_dn_up_nf(struct bfa_pport_ln_s *ln,
+ enum bfa_pport_ln_sm_event event);
+
static struct bfa_sm_table_s hal_pport_sm_table[] = {
{BFA_SM(bfa_pport_sm_uninit), BFA_PPORT_ST_UNINIT},
{BFA_SM(bfa_pport_sm_enabling_qwait), BFA_PPORT_ST_ENABLING_QWAIT},
@@ -619,7 +637,163 @@ bfa_pport_sm_iocfail(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
}
}
+/**
+ * Link state is down
+ */
+static void
+bfa_pport_ln_sm_dn(struct bfa_pport_ln_s *ln,
+ enum bfa_pport_ln_sm_event event)
+{
+ bfa_trc(ln->pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_LN_SM_LINKUP:
+ bfa_sm_set_state(ln, bfa_pport_ln_sm_up_nf);
+ bfa_pport_queue_cb(ln, BFA_PPORT_LINKUP);
+ break;
+
+ default:
+ bfa_sm_fault(ln->pport->bfa, event);
+ }
+}
+
+/**
+ * Link state is waiting for down notification
+ */
+static void
+bfa_pport_ln_sm_dn_nf(struct bfa_pport_ln_s *ln,
+ enum bfa_pport_ln_sm_event event)
+{
+ bfa_trc(ln->pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_LN_SM_LINKUP:
+ bfa_sm_set_state(ln, bfa_pport_ln_sm_dn_up_nf);
+ break;
+
+ case BFA_PPORT_LN_SM_NOTIFICATION:
+ bfa_sm_set_state(ln, bfa_pport_ln_sm_dn);
+ break;
+
+ default:
+ bfa_sm_fault(ln->pport->bfa, event);
+ }
+}
+
+/**
+ * Link state is waiting for down notification and there is a pending up
+ */
+static void
+bfa_pport_ln_sm_dn_up_nf(struct bfa_pport_ln_s *ln,
+ enum bfa_pport_ln_sm_event event)
+{
+ bfa_trc(ln->pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_LN_SM_LINKDOWN:
+ bfa_sm_set_state(ln, bfa_pport_ln_sm_dn_nf);
+ break;
+
+ case BFA_PPORT_LN_SM_NOTIFICATION:
+ bfa_sm_set_state(ln, bfa_pport_ln_sm_up_nf);
+ bfa_pport_queue_cb(ln, BFA_PPORT_LINKUP);
+ break;
+
+ default:
+ bfa_sm_fault(ln->pport->bfa, event);
+ }
+}
+
+/**
+ * Link state is up
+ */
+static void
+bfa_pport_ln_sm_up(struct bfa_pport_ln_s *ln,
+ enum bfa_pport_ln_sm_event event)
+{
+ bfa_trc(ln->pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_LN_SM_LINKDOWN:
+ bfa_sm_set_state(ln, bfa_pport_ln_sm_dn_nf);
+ bfa_pport_queue_cb(ln, BFA_PPORT_LINKDOWN);
+ break;
+
+ default:
+ bfa_sm_fault(ln->pport->bfa, event);
+ }
+}
+
+/**
+ * Link state is waiting for up notification
+ */
+static void
+bfa_pport_ln_sm_up_nf(struct bfa_pport_ln_s *ln,
+ enum bfa_pport_ln_sm_event event)
+{
+ bfa_trc(ln->pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_LN_SM_LINKDOWN:
+ bfa_sm_set_state(ln, bfa_pport_ln_sm_up_dn_nf);
+ break;
+
+ case BFA_PPORT_LN_SM_NOTIFICATION:
+ bfa_sm_set_state(ln, bfa_pport_ln_sm_up);
+ break;
+
+ default:
+ bfa_sm_fault(ln->pport->bfa, event);
+ }
+}
+
+/**
+ * Link state is waiting for up notification and there is a pending down
+ */
+static void
+bfa_pport_ln_sm_up_dn_nf(struct bfa_pport_ln_s *ln,
+ enum bfa_pport_ln_sm_event event)
+{
+ bfa_trc(ln->pport->bfa, event);
+ switch (event) {
+ case BFA_PPORT_LN_SM_LINKUP:
+ bfa_sm_set_state(ln, bfa_pport_ln_sm_up_dn_up_nf);
+ break;
+
+ case BFA_PPORT_LN_SM_NOTIFICATION:
+ bfa_sm_set_state(ln, bfa_pport_ln_sm_dn_nf);
+ bfa_pport_queue_cb(ln, BFA_PPORT_LINKDOWN);
+ break;
+
+ default:
+ bfa_sm_fault(ln->pport->bfa, event);
+ }
+}
+
+/**
+ * Link state is waiting for up notification and there are pending down and up
+ */
+static void
+bfa_pport_ln_sm_up_dn_up_nf(struct bfa_pport_ln_s *ln,
+ enum bfa_pport_ln_sm_event event)
+{
+ bfa_trc(ln->pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_LN_SM_LINKDOWN:
+ bfa_sm_set_state(ln, bfa_pport_ln_sm_up_dn_nf);
+ break;
+
+ case BFA_PPORT_LN_SM_NOTIFICATION:
+ bfa_sm_set_state(ln, bfa_pport_ln_sm_dn_up_nf);
+ bfa_pport_queue_cb(ln, BFA_PPORT_LINKDOWN);
+ break;
+
+ default:
+ bfa_sm_fault(ln->pport->bfa, event);
+ }
+}
/**
* bfa_pport_private
@@ -628,10 +802,12 @@ bfa_pport_sm_iocfail(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
static void
__bfa_cb_port_event(void *cbarg, bfa_boolean_t complete)
{
- struct bfa_pport_s *pport = cbarg;
+ struct bfa_pport_ln_s *ln = cbarg;
if (complete)
- pport->event_cbfn(pport->event_cbarg, pport->hcb_event);
+ ln->pport->event_cbfn(ln->pport->event_cbarg, ln->ln_event);
+ else
+ bfa_sm_send_event(ln, BFA_PPORT_LN_SM_NOTIFICATION);
}
#define PPORT_STATS_DMA_SZ (BFA_ROUNDUP(sizeof(union bfa_pport_stats_u), \
@@ -681,13 +857,16 @@ bfa_pport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
{
struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
struct bfa_pport_cfg_s *port_cfg = &pport->cfg;
+ struct bfa_pport_ln_s *ln = &pport->ln;
bfa_os_memset(pport, 0, sizeof(struct bfa_pport_s));
pport->bfa = bfa;
+ ln->pport = pport;
bfa_pport_mem_claim(pport, meminfo);
bfa_sm_set_state(pport, bfa_pport_sm_uninit);
+ bfa_sm_set_state(ln, bfa_pport_ln_sm_dn);
/**
* initialize and set default configuration
@@ -1369,6 +1548,33 @@ bfa_port_stats_clr_timeout(void *cbarg)
}
static void
+bfa_pport_callback(struct bfa_pport_s *pport, enum bfa_pport_linkstate event)
+{
+ if (pport->bfa->fcs) {
+ pport->event_cbfn(pport->event_cbarg, event);
+ return;
+ }
+
+ switch (event) {
+ case BFA_PPORT_LINKUP:
+ bfa_sm_send_event(&pport->ln, BFA_PPORT_LN_SM_LINKUP);
+ break;
+ case BFA_PPORT_LINKDOWN:
+ bfa_sm_send_event(&pport->ln, BFA_PPORT_LN_SM_LINKDOWN);
+ break;
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_pport_queue_cb(struct bfa_pport_ln_s *ln, enum bfa_pport_linkstate event)
+{
+ ln->ln_event = event;
+ bfa_cb_queue(ln->pport->bfa, &ln->ln_qe, __bfa_cb_port_event, ln);
+}
+
+static void
__bfa_cb_port_stats(void *cbarg, bfa_boolean_t complete)
{
struct bfa_pport_s *port = cbarg;
diff --git a/drivers/scsi/bfa/bfa_port_priv.h b/drivers/scsi/bfa/bfa_port_priv.h
index 51f698a06b6d..f29701bd2369 100644
--- a/drivers/scsi/bfa/bfa_port_priv.h
+++ b/drivers/scsi/bfa/bfa_port_priv.h
@@ -23,6 +23,16 @@
#include "bfa_intr_priv.h"
/**
+ * Link notification data structure
+ */
+struct bfa_pport_ln_s {
+ struct bfa_pport_s *pport;
+ bfa_sm_t sm;
+ struct bfa_cb_qe_s ln_qe; /* BFA callback queue elem for ln */
+ enum bfa_pport_linkstate ln_event; /* ln event for callback */
+};
+
+/**
* BFA physical port data structure
*/
struct bfa_pport_s {
@@ -52,9 +62,8 @@ struct bfa_pport_s {
union bfi_pport_i2h_msg_u i2hmsg;
} event_arg;
void *bfad; /* BFA driver handle */
+ struct bfa_pport_ln_s ln; /* Link Notification */
struct bfa_cb_qe_s hcb_qe; /* BFA callback queue elem */
- enum bfa_pport_linkstate hcb_event;
- /* link event for callback */
u32 msgtag; /* fimrware msg tag for reply */
u8 *stats_kva;
u64 stats_pa;