aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi
diff options
context:
space:
mode:
authorVasu Dev <vasu.dev@intel.com>2009-07-29 17:05:00 -0700
committerJames Bottomley <James.Bottomley@suse.de>2009-08-22 17:52:07 -0500
commit96316099ac3cb259eac2d6891f3c75b38b29d26e (patch)
treef4ec7001462bd00340de19b3045063872652c5a6 /drivers/scsi
parent201e5795b7b9582accb6d83316e30f24d7d40fd3 (diff)
[SCSI] fcoe, libfc: adds exchange manager(EM) anchor list per lport and related APIs
Adds EM list using a anchor struct fc_exch_mgr_anchor, anchor is used to allow same EM instance sharing across more than one lport on a eth device, this implementation is per discussed design posted at http://www.open-fcoe.org/pipermail/devel/2009-June/002566.html. The shared EM is required for multiple lports on eth device when using multiple VLANs or NPIV. Adds fc_exch_mgr_add API to add a EM to the lport and fc_exch_mgr_del API to delete previously added EM. Also adds function fc_exch_mgr_destroy() to destroy allocated EM. The kref is added to the EM to keep track of EM usage count, the EM is destroyed when no longer in use upon kref reaching to zero. The caller can specify match function to fc_exch_mgr_add, this will be used in determining exchange allocation from its EM or not. Moved calling of fcoe_em_config below fcoe_libfc_config calling, so that list head lp->ema_list is initialized before configuring EM. Signed-off-by: Vasu Dev <vasu.dev@intel.com> Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/fcoe/fcoe.c14
-rw-r--r--drivers/scsi/libfc/fc_exch.c48
-rw-r--r--drivers/scsi/libfc/fc_lport.c1
3 files changed, 56 insertions, 7 deletions
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 14a4017a153..719a99d4a43 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -603,18 +603,18 @@ static int fcoe_if_create(struct net_device *netdev)
goto out_netdev_cleanup;
}
- /* lport exch manager allocation */
- rc = fcoe_em_config(lp);
+ /* Initialize the library */
+ rc = fcoe_libfc_config(lp, &fcoe_libfc_fcn_templ);
if (rc) {
- FCOE_NETDEV_DBG(netdev, "Could not configure the EM for the "
+ FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the "
"interface\n");
- goto out_netdev_cleanup;
+ goto out_lp_destroy;
}
- /* Initialize the library */
- rc = fcoe_libfc_config(lp, &fcoe_libfc_fcn_templ);
+ /* lport exch manager allocation */
+ rc = fcoe_em_config(lp);
if (rc) {
- FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the "
+ FCOE_NETDEV_DBG(netdev, "Could not configure the EM for the "
"interface\n");
goto out_lp_destroy;
}
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index cab54996375..f1fa2b196e9 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -55,6 +55,7 @@ static struct kmem_cache *fc_em_cachep; /* cache for exchanges */
*/
struct fc_exch_mgr {
enum fc_class class; /* default class for sequences */
+ struct kref kref; /* exchange mgr reference count */
spinlock_t em_lock; /* exchange manager lock,
must be taken before ex_lock */
u16 last_xid; /* last allocated exchange ID */
@@ -84,6 +85,12 @@ struct fc_exch_mgr {
};
#define fc_seq_exch(sp) container_of(sp, struct fc_exch, seq)
+struct fc_exch_mgr_anchor {
+ struct list_head ema_list;
+ struct fc_exch_mgr *mp;
+ bool (*match)(struct fc_frame *);
+};
+
static void fc_exch_rrq(struct fc_exch *);
static void fc_seq_ls_acc(struct fc_seq *);
static void fc_seq_ls_rjt(struct fc_seq *, enum fc_els_rjt_reason,
@@ -1729,6 +1736,47 @@ reject:
fc_frame_free(fp);
}
+struct fc_exch_mgr_anchor *fc_exch_mgr_add(struct fc_lport *lport,
+ struct fc_exch_mgr *mp,
+ bool (*match)(struct fc_frame *))
+{
+ struct fc_exch_mgr_anchor *ema;
+
+ ema = kmalloc(sizeof(*ema), GFP_ATOMIC);
+ if (!ema)
+ return ema;
+
+ ema->mp = mp;
+ ema->match = match;
+ /* add EM anchor to EM anchors list */
+ list_add_tail(&ema->ema_list, &lport->ema_list);
+ kref_get(&mp->kref);
+ return ema;
+}
+EXPORT_SYMBOL(fc_exch_mgr_add);
+
+static void fc_exch_mgr_destroy(struct kref *kref)
+{
+ struct fc_exch_mgr *mp = container_of(kref, struct fc_exch_mgr, kref);
+
+ /*
+ * The total exch count must be zero
+ * before freeing exchange manager.
+ */
+ WARN_ON(mp->total_exches != 0);
+ mempool_destroy(mp->ep_pool);
+ kfree(mp);
+}
+
+void fc_exch_mgr_del(struct fc_exch_mgr_anchor *ema)
+{
+ /* remove EM anchor from EM anchors list */
+ list_del(&ema->ema_list);
+ kref_put(&ema->mp->kref, fc_exch_mgr_destroy);
+ kfree(ema);
+}
+EXPORT_SYMBOL(fc_exch_mgr_del);
+
struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp,
enum fc_class class,
u16 min_xid, u16 max_xid)
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index a430335ebf5..ca8ea264b68 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -1618,6 +1618,7 @@ int fc_lport_init(struct fc_lport *lport)
if (lport->link_supported_speeds & FC_PORTSPEED_10GBIT)
fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_10GBIT;
+ INIT_LIST_HEAD(&lport->ema_list);
return 0;
}
EXPORT_SYMBOL(fc_lport_init);