Robert Love wrote:
> From: Vasu Dev <[email protected]>
>
> Previously when a netdev supported offloaded Rx it was
> indicating the range of XIDs for offload to the singular
> EM that was associated with the lport on the port.
>
> Previous patches have made it so an EM can be shared across
> multiple lports. This patch adds an offload EM to the fcoe_softc
> and allows the fcoe module to override the exch_get() function
> poiner in libfc's template so that requests for exchanges are
> handled by fcoe. fcoe can then choose from either the default
> EM associated with the lport the exchange is on or the offload
> EM associated with the lport's netdev.
>
> To accomplish this the patch does the following:
>
> - Adds oem (offload EM) pointer to the fcoe_softc
>
> - Reorganize EM freeing to consider the offload EM
>
> - Reorganize fcoe_em_alloc() (previously fcoe_em_config()) to
> assign the same EMs to any VN_Ports (lports) associated with
> the same netdev->phys_dev.
>
> - Implements fcoe_exch_recv() to handle incoming frames and
> determine with EM should handle the inbound exchange.
>
> - Overrides the exch_get() routine of the libfc template
> so that fcoe can use offload EM when offload criteria is met
> (i.e. exchange will be for a read request).
>
> Signed-off-by: Vasu Dev <[email protected]>
> Signed-off-by: Robert Love <[email protected]>
> ---
>
> drivers/scsi/fcoe/fcoe.c | 134
> +++++++++++++++++++++++++++++++++++++++---
> drivers/scsi/fcoe/fcoe.h | 1
> drivers/scsi/libfc/fc_exch.c | 92 +++++------------------------
> include/scsi/libfc.h | 5 --
> 4 files changed, 141 insertions(+), 91 deletions(-)
>
> diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
> index e4ba631..f589a47 100644
> --- a/drivers/scsi/fcoe/fcoe.c
> +++ b/drivers/scsi/fcoe/fcoe.c
> @@ -407,20 +407,78 @@ static int fcoe_shost_config(struct fc_lport *lp,
> struct Scsi_Host *shost,
> }
>
> /**
> - * fcoe_em_config() - allocates em for this lport
> + * fcoe_em_alloc() - allocates em for this lport
> * @lp: the port that em is to allocated for
> *
> * Returns : 0 on success
> */
> -static inline int fcoe_em_config(struct fc_lport *lp)
> +static inline int fcoe_em_alloc(struct fc_lport *lp)
> {
> + struct fcoe_softc *fc = lport_priv(lp);
> + struct fcoe_softc *oldfc = NULL;
> + int rc = 0;
> +
> BUG_ON(lp->emp);
>
> + /*
> + * Check if need to allocate an em instance for
> + * offload exchange ids to be shared across all VN_PORTs/lport.
> + */
> + if (!lp->lro_enabled || !lp->lro_xid || (lp->lro_xid >= FCOE_MAX_XID)) {
> + lp->lro_xid = 0;
> + goto skip_oem;
> + }
> +
> + /*
> + * Reuse exitsing offload em instance in case
typo: existing
> + * it is already allocated on phys_dev
> + */
> + write_lock(&fcoe_hostlist_lock);
> + list_for_each_entry(oldfc, &fcoe_hostlist, list) {
> + if (oldfc->phys_dev == fc->phys_dev) {
> + fc->oem = oldfc->oem;
Take a reference here?
What if the other other instance gets deleted, including the EM
before we start using it? Maybe do the exch_mgr_alloc inside the lock?
> + break;
> + }
> + }
> + write_unlock(&fcoe_hostlist_lock);
> +
> + fc->oem = fc_exch_mgr_alloc(lp, fc->oem, FC_CLASS_3,
> + FCOE_MIN_XID, lp->lro_xid);
> +
> + if (!fc->oem) {
> + printk(KERN_ERR "fcoe_em_alloc: failed to "
> + "allocate em for offload%s\n", fc->real_dev->name);
> + rc = -ENOMEM;
> + goto out;
> + }
> +
> +skip_oem:
> lp->emp = fc_exch_mgr_alloc(lp, NULL, FC_CLASS_3,
> - FCOE_MIN_XID, FCOE_MAX_XID);
> - if (!lp->emp)
> - return -ENOMEM;
> + FCOE_MIN_XID + lp->lro_xid,
> + FCOE_MAX_XID);
> +
> + if (!lp->emp) {
> + printk(KERN_ERR "Failed to allocate an Exchange "
> + "Manager for %s\n", fc->real_dev->name);
> + rc = -ENOMEM;
> + }
> +out:
> + return rc;
> +}
>
> +/**
> + * fcoe_em_free() - frees allocated em for a lport
> + * @lp: the port that em is to allocated for
> + *
> + * Returns : 0 on success
> + */
> +static inline int fcoe_em_free(struct fc_lport *lp)
> +{
> + struct fcoe_softc *fc = lport_priv(lp);
> +
> + if (fc->oem)
> + fc_exch_mgr_free(fc->oem);
> + fc_exch_mgr_free(lp->emp);
> return 0;
> }
>
> @@ -468,7 +526,7 @@ static int fcoe_if_destroy(struct net_device *netdev)
>
> /* There are no more rports or I/O, free the EM */
> if (lp->emp)
> - fc_exch_mgr_free(lp->emp);
> + fcoe_em_free(lp);
>
> /* Free the per-CPU revieve threads */
> fcoe_percpu_clean(lp);
> @@ -486,6 +544,59 @@ static int fcoe_if_destroy(struct net_device *netdev)
> return 0;
> }
>
> +/**
> + * fcoe_exch_recv() - receive a incoming frame
> + * @lp: the associated local port
> + * @fp: received fc_frame
> + *
> + * Locates exchange manager instance for received frame
> + * and pass it up to libfc using fc_exch_recv api.
> + */
> +static void fcoe_exch_recv(struct fc_lport *lp, struct fc_frame *fp)
> +{
> + struct fcoe_softc *fc = lport_priv(lp);
> + struct fc_frame_header *fh = fc_frame_header_get(fp);
> + u16 oxid = ntohs(fh->fh_ox_id);
> + u32 ctx;
> +
> + if (lp->lro_enabled && (oxid <= lp->lro_xid)) {
Should this be < instead of <= ?
If I'm correct, the first XID belonging to the non-offload EM is lro_xid.
BTW, parens are not needed around the comparison.
Since lro_xid is 0 when lro is disabled, we don't need to check lro_enabled.
Just:
if (oxid < lp->lro_xid) {
> + ctx = ntoh24(fh->fh_f_ctl) & (FC_FC_EX_CTX | FC_FC_SEQ_CTX);
> + if (ctx == FC_FC_EX_CTX) {
Maybe this should allow SEQ_CTX to be 1 or 0, not just 0.
That would permit class 2 action someday. Unless class 2 is supported,
it isn't necessary to check SEQ_CTX here. OK if you want to leave it as is.
> + fc_exch_recv(lp, fc->oem, fp);
> + return;
> + }
> + }
> + fc_exch_recv(lp, lp->emp, fp);
> +}
> +
> +/**
> + * fcoe_exch_get() - allocates an exchange
> + * @lp: the associated local port
> + * @fp: the fc_frame to be transmitted
> + *
> + * Allocates exchange from fc->oem for offload eligible frames
> + * otherwise allocates from exhcange from the default EM instance.
typo: exchange
> + */
> +static struct fc_exch *fcoe_exch_get(struct fc_lport *lp, struct fc_frame
> *fp)
> +{
> + struct fcoe_softc *fc = lport_priv(lp);
> + struct fc_exch *ep = NULL;
Don't initialize ep here. It won't be needed if we
rearrange to do ddp setup in the read case only.
> +
> + if (fc_fcp_is_read(fr_fsp(fp)))
{
> + ep = fc_exch_alloc(fc->oem);
> +
> + /*
> + * if valid ep allocated from fc->ofemp
> + * then set up ddp here, else allocate
> + * ep from other em.
> + */
> + if (ep)
This should be part of the above if-statement.
Test this only in the case of a read.
> + fc_fcp_ddp_setup(fr_fsp(fp), ep->xid);
> + else
> + ep = fc_exch_alloc(lp->emp);
> + return ep;
> +}
> +
> /*
> * fcoe_ddp_setup - calls LLD's ddp_setup through net_device
> * @lp: the corresponding fc_lport
> @@ -590,6 +701,9 @@ static int fcoe_if_create(struct net_device *netdev)
> goto out_netdev_cleanup;
> }
>
> + /* set exch_get if lro enabled */
> + if (lp->lro_enabled)
> + fcoe_libfc_fcn_templ.exch_get = fcoe_exch_get;
> /* Initialize the library */
> rc = fcoe_libfc_config(lp, &fcoe_libfc_fcn_templ);
> if (rc) {
> @@ -598,7 +712,7 @@ static int fcoe_if_create(struct net_device *netdev)
> }
>
> /* lport exch manager allocation */
> - rc = fcoe_em_config(lp);
> + rc = fcoe_em_alloc(lp);
> if (rc) {
> FCOE_NETDEV_DBG(netdev, "Could not configure the EM for the "
> "interface\n");
> @@ -620,7 +734,7 @@ static int fcoe_if_create(struct net_device *netdev)
> return rc;
>
> out_lp_destroy:
> - fc_exch_mgr_free(lp->emp); /* Free the EM */
> + fcoe_em_free(lp);
> out_netdev_cleanup:
> fcoe_netdev_cleanup(fc);
> out_host_put:
> @@ -1279,7 +1393,7 @@ int fcoe_percpu_receive_thread(void *arg)
> fh = fc_frame_header_get(fp);
> if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA &&
> fh->fh_type == FC_TYPE_FCP) {
> - fc_exch_recv(lp, lp->emp, fp);
> + fcoe_exch_recv(lp, fp);
> continue;
> }
> if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) {
> @@ -1300,7 +1414,7 @@ int fcoe_percpu_receive_thread(void *arg)
> fc_frame_free(fp);
> continue;
> }
> - fc_exch_recv(lp, lp->emp, fp);
> + fcoe_exch_recv(lp, fp);
> }
> return 0;
> }
> diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h
> index 917aae8..4db2330 100644
> --- a/drivers/scsi/fcoe/fcoe.h
> +++ b/drivers/scsi/fcoe/fcoe.h
> @@ -57,6 +57,7 @@ struct fcoe_softc {
> struct list_head list;
> struct net_device *real_dev;
> struct net_device *phys_dev; /* device with ethtool_ops */
> + struct fc_exch_mgr *oem; /* offload exchane manager */
typo: exchange
> struct packet_type fcoe_packet_type;
> struct packet_type fip_packet_type;
> struct sk_buff_head fcoe_pending_queue;
> diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
> index d429e8b..0664366 100644
> --- a/drivers/scsi/libfc/fc_exch.c
> +++ b/drivers/scsi/libfc/fc_exch.c
> @@ -72,9 +72,7 @@ struct fc_exch_mgr {
> u16 last_xid; /* last allocated exchange ID */
> u16 min_xid; /* min exchange ID */
> u16 max_xid; /* max exchange ID */
> - u16 max_read; /* max exchange ID for read */
> - u16 last_read; /* last xid allocated for read */
> - u32 total_exches; /* total allocated exchanges */
> + u32 total_exches; /* total allocated exchanges */
> struct list_head ex_list; /* allocated exchanges list */
> struct list_head em_list; /* fc_exch_mgr list */
> struct fc_lport *lp; /* fc device instance */
> @@ -474,64 +472,15 @@ static struct fc_seq *fc_seq_alloc(struct fc_exch *ep,
> u8 seq_id)
> }
>
> /*
> - * fc_em_alloc_xid - returns an xid based on request type
> - * @lp : ptr to associated lport
> - * @fp : ptr to the assocated frame
> - *
> - * check the associated fc_fsp_pkt to get scsi command type and
> - * command direction to decide from which range this exch id
> - * will be allocated from.
> - *
> - * Returns : 0 or an valid xid
> - */
> -static u16 fc_em_alloc_xid(struct fc_exch_mgr *mp, const struct fc_frame *fp)
> -{
> - u16 xid, min, max;
> - u16 *plast;
> - struct fc_exch *ep = NULL;
> -
> - if (mp->max_read) {
> - if (fc_fcp_is_read(fr_fsp(fp))) {
> - min = mp->min_xid;
> - max = mp->max_read;
> - plast = &mp->last_read;
> - } else {
> - min = mp->max_read + 1;
> - max = mp->max_xid;
> - plast = &mp->last_xid;
> - }
> - } else {
> - min = mp->min_xid;
> - max = mp->max_xid;
> - plast = &mp->last_xid;
> - }
> - xid = *plast;
> - do {
> - xid = (xid == max) ? min : xid + 1;
> - ep = mp->exches[xid - mp->min_xid];
> - } while ((ep != NULL) && (xid != *plast));
> -
> - if (unlikely(ep))
> - xid = 0;
> - else
> - *plast = xid;
> -
> - return xid;
> -}
> -
> -/*
> - * fc_exch_alloc - allocate an exchange.
> + * fc_exch_alloc - allocate an exchange and its exchange id.
> * @mp : ptr to the exchange manager
> - * @xid: input xid
> *
> - * if xid is supplied zero then assign next free exchange ID
> - * from exchange manager, otherwise use supplied xid.
> * Returns with exch lock held.
> */
> -struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp,
> - struct fc_frame *fp, u16 xid)
> +struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp)
> {
> struct fc_exch *ep;
> + u16 min, max, xid;
>
> /* allocate memory for exchange */
> ep = mempool_alloc(mp->ep_pool, GFP_ATOMIC);
> @@ -541,16 +490,18 @@ struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp,
> }
> memset(ep, 0, sizeof(*ep));
>
> + min = mp->min_xid;
> + max = mp->max_xid;
> +
> spin_lock_bh(&mp->em_lock);
> - /* alloc xid if input xid 0 */
> - if (!xid) {
> - /* alloc a new xid */
> - xid = fc_em_alloc_xid(mp, fp);
> - if (!xid) {
> - printk(KERN_ERR "fc_em_alloc_xid() failed\n");
> + xid = mp->last_xid;
> + /* alloc a new xid */
> + while (mp->exches[xid - min]) {
> + xid = (xid == max) ? min : xid + 1;
> + if (xid == mp->last_xid)
> goto err;
> - }
> }
> + mp->last_xid = xid;
>
> fc_exch_hold(ep); /* hold for exch in mp */
> spin_lock_init(&ep->ex_lock);
> @@ -1761,7 +1712,6 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport
> *lp,
> /*
> * Memory need for EM
> */
> -#define xid_ok(i, m1, m2) (((i) >= (m1)) && ((i) <= (m2)))
> len = (max_xid - min_xid + 1) * (sizeof(struct fc_exch *));
> len += sizeof(struct fc_exch_mgr);
>
> @@ -1775,17 +1725,7 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport
> *lp,
> /* adjust em exch xid range for offload */
> mp->min_xid = min_xid;
> mp->max_xid = max_xid;
> - mp->last_xid = min_xid - 1;
> - mp->max_read = 0;
> - mp->last_read = 0;
> - if (lp->lro_enabled && xid_ok(lp->lro_xid, min_xid, max_xid)) {
> - mp->max_read = lp->lro_xid;
> - mp->last_read = min_xid - 1;
> - mp->last_xid = mp->max_read;
> - } else {
> - /* disable lro if no xid control over read */
> - lp->lro_enabled = 0;
> - }
> + mp->last_xid = min_xid;
>
> INIT_LIST_HEAD(&mp->ex_list);
> spin_lock_init(&mp->em_lock);
> @@ -1830,7 +1770,7 @@ struct fc_exch *fc_exch_get(struct fc_lport *lp, struct
> fc_frame *fp)
> if (!lp || !lp->emp)
> return NULL;
>
> - return fc_exch_alloc(lp->emp, fp, 0);
> + return fc_exch_alloc(lp->emp);
> }
> EXPORT_SYMBOL(fc_exch_get);
>
> @@ -1867,8 +1807,6 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp,
> fc_exch_setup_hdr(ep, fp, ep->f_ctl);
> sp->cnt++;
>
> - fc_fcp_ddp_setup(fr_fsp(fp), ep->xid);
> -
> if (unlikely(lp->tt.frame_send(lp, fp)))
> goto err;
>
> diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
> index 68f7a61..99d687c 100644
> --- a/include/scsi/libfc.h
> +++ b/include/scsi/libfc.h
> @@ -992,11 +992,8 @@ struct fc_exch *fc_exch_get(struct fc_lport *lp, struct
> fc_frame *fp);
>
> /*
> * Allocate a new exchange and sequence pair.
> - * if ex_id is zero then next free exchange id
> - * from specified exchange manger mp will be assigned.
> */
> -struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp,
> - struct fc_frame *fp, u16 ex_id);
> +struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp);
> /*
> * Start a new sequence on the same exchange as the supplied sequence.
> */
>
> _______________________________________________
> devel mailing list
> [email protected]
> http://www.open-fcoe.org/mailman/listinfo/devel
_______________________________________________
devel mailing list
[email protected]
http://www.open-fcoe.org/mailman/listinfo/devel