diff options
author | Vasu Dev <vasu.dev@intel.com> | 2009-07-29 20:05:21 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-08-22 18:52:09 -0400 |
commit | d7179680d04f1e196b7a5f70e7f93bb1850407c6 (patch) | |
tree | e31aaf450afcd7cba0d719178424ece5013964f8 /drivers/scsi/libfc | |
parent | e8af4d4380babc89d193c16163f070a6418f033b (diff) |
[SCSI] fcoe, libfc: adds offload EM per eth device with only single xid range per EM
Updates fcoe_em_config to allocate a single instance of sharable offload
EM for supported lp->lro_xid per eth device, and then share this EM
for subsequently more lports creation on same eth device (e.g when using
VLAN).
Adds tiny fcoe_oem_match function for offload EM to return true for read
types IO to have read IO exchanges allocated from offload shared EM.
Removes fc_em_alloc_xid function completely which was needed to manage
two xid ranges within a EM, this is not needed any more with allocation
of separate sharable offload EM per eth device. Instead this patch adds
simple xid allocation logic to manage single xid range.
Adds fc_exch_em_alloc with mp->next_xid as cursor to allocate new xid
from single xid range of EM, uses mp->next_xid instead removed mp->last_xid
which slightly increase probability of finding empty xid on exch allocation.
Removes restriction of not allowing use of xid zero along with changing
two xid range change to single xid range.
Makes fc_fcp_ddp_setup calling conditional to only xid allocated from
shared offload 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/libfc')
-rw-r--r-- | drivers/scsi/libfc/fc_exch.c | 94 |
1 files changed, 18 insertions, 76 deletions
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 324589a5cc03..11ddd115efb6 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c | |||
@@ -58,7 +58,7 @@ struct fc_exch_mgr { | |||
58 | struct kref kref; /* exchange mgr reference count */ | 58 | struct kref kref; /* exchange mgr reference count */ |
59 | spinlock_t em_lock; /* exchange manager lock, | 59 | spinlock_t em_lock; /* exchange manager lock, |
60 | must be taken before ex_lock */ | 60 | must be taken before ex_lock */ |
61 | u16 last_xid; /* last allocated exchange ID */ | 61 | u16 next_xid; /* next possible free exchange ID */ |
62 | u16 min_xid; /* min exchange ID */ | 62 | u16 min_xid; /* min exchange ID */ |
63 | u16 max_xid; /* max exchange ID */ | 63 | u16 max_xid; /* max exchange ID */ |
64 | u16 max_read; /* max exchange ID for read */ | 64 | u16 max_read; /* max exchange ID for read */ |
@@ -464,68 +464,21 @@ static struct fc_seq *fc_seq_alloc(struct fc_exch *ep, u8 seq_id) | |||
464 | return sp; | 464 | return sp; |
465 | } | 465 | } |
466 | 466 | ||
467 | /* | ||
468 | * fc_em_alloc_xid - returns an xid based on request type | ||
469 | * @lp : ptr to associated lport | ||
470 | * @fp : ptr to the assocated frame | ||
471 | * | ||
472 | * check the associated fc_fsp_pkt to get scsi command type and | ||
473 | * command direction to decide from which range this exch id | ||
474 | * will be allocated from. | ||
475 | * | ||
476 | * Returns : 0 or an valid xid | ||
477 | */ | ||
478 | static u16 fc_em_alloc_xid(struct fc_exch_mgr *mp, const struct fc_frame *fp) | ||
479 | { | ||
480 | u16 xid, min, max; | ||
481 | u16 *plast; | ||
482 | struct fc_exch *ep = NULL; | ||
483 | |||
484 | if (mp->max_read) { | ||
485 | if (fc_fcp_is_read(fr_fsp(fp))) { | ||
486 | min = mp->min_xid; | ||
487 | max = mp->max_read; | ||
488 | plast = &mp->last_read; | ||
489 | } else { | ||
490 | min = mp->max_read + 1; | ||
491 | max = mp->max_xid; | ||
492 | plast = &mp->last_xid; | ||
493 | } | ||
494 | } else { | ||
495 | min = mp->min_xid; | ||
496 | max = mp->max_xid; | ||
497 | plast = &mp->last_xid; | ||
498 | } | ||
499 | xid = *plast; | ||
500 | do { | ||
501 | xid = (xid == max) ? min : xid + 1; | ||
502 | ep = mp->exches[xid - mp->min_xid]; | ||
503 | } while ((ep != NULL) && (xid != *plast)); | ||
504 | |||
505 | if (unlikely(ep)) | ||
506 | xid = 0; | ||
507 | else | ||
508 | *plast = xid; | ||
509 | |||
510 | return xid; | ||
511 | } | ||
512 | |||
513 | /** | 467 | /** |
514 | * fc_exch_em_alloc() - allocate an exchange from a specified EM. | 468 | * fc_exch_em_alloc() - allocate an exchange from a specified EM. |
515 | * @lport: ptr to the local port | 469 | * @lport: ptr to the local port |
516 | * @mp: ptr to the exchange manager | 470 | * @mp: ptr to the exchange manager |
517 | * @fp: ptr to the FC frame | ||
518 | * @xid: input xid | ||
519 | * | 471 | * |
520 | * if xid is supplied zero then assign next free exchange ID | 472 | * Returns pointer to allocated fc_exch with exch lock held. |
521 | * from exchange manager, otherwise use supplied xid. | ||
522 | * Returns with exch lock held. | ||
523 | */ | 473 | */ |
524 | static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, | 474 | static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, |
525 | struct fc_exch_mgr *mp, | 475 | struct fc_exch_mgr *mp) |
526 | struct fc_frame *fp, u16 xid) | ||
527 | { | 476 | { |
528 | struct fc_exch *ep; | 477 | struct fc_exch *ep; |
478 | u16 min, max, xid; | ||
479 | |||
480 | min = mp->min_xid; | ||
481 | max = mp->max_xid; | ||
529 | 482 | ||
530 | /* allocate memory for exchange */ | 483 | /* allocate memory for exchange */ |
531 | ep = mempool_alloc(mp->ep_pool, GFP_ATOMIC); | 484 | ep = mempool_alloc(mp->ep_pool, GFP_ATOMIC); |
@@ -536,15 +489,14 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, | |||
536 | memset(ep, 0, sizeof(*ep)); | 489 | memset(ep, 0, sizeof(*ep)); |
537 | 490 | ||
538 | spin_lock_bh(&mp->em_lock); | 491 | spin_lock_bh(&mp->em_lock); |
539 | /* alloc xid if input xid 0 */ | 492 | xid = mp->next_xid; |
540 | if (!xid) { | 493 | /* alloc a new xid */ |
541 | /* alloc a new xid */ | 494 | while (mp->exches[xid - min]) { |
542 | xid = fc_em_alloc_xid(mp, fp); | 495 | xid = (xid == max) ? min : xid + 1; |
543 | if (!xid) { | 496 | if (xid == mp->next_xid) |
544 | printk(KERN_WARNING "libfc: Failed to allocate an exhange\n"); | ||
545 | goto err; | 497 | goto err; |
546 | } | ||
547 | } | 498 | } |
499 | mp->next_xid = (xid == max) ? min : xid + 1; | ||
548 | 500 | ||
549 | fc_exch_hold(ep); /* hold for exch in mp */ | 501 | fc_exch_hold(ep); /* hold for exch in mp */ |
550 | spin_lock_init(&ep->ex_lock); | 502 | spin_lock_init(&ep->ex_lock); |
@@ -597,7 +549,7 @@ struct fc_exch *fc_exch_alloc(struct fc_lport *lport, struct fc_frame *fp) | |||
597 | 549 | ||
598 | list_for_each_entry(ema, &lport->ema_list, ema_list) { | 550 | list_for_each_entry(ema, &lport->ema_list, ema_list) { |
599 | if (!ema->match || ema->match(fp)) { | 551 | if (!ema->match || ema->match(fp)) { |
600 | ep = fc_exch_em_alloc(lport, ema->mp, fp, 0); | 552 | ep = fc_exch_em_alloc(lport, ema->mp); |
601 | if (ep) | 553 | if (ep) |
602 | return ep; | 554 | return ep; |
603 | } | 555 | } |
@@ -1817,7 +1769,7 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, | |||
1817 | struct fc_exch_mgr *mp; | 1769 | struct fc_exch_mgr *mp; |
1818 | size_t len; | 1770 | size_t len; |
1819 | 1771 | ||
1820 | if (max_xid <= min_xid || min_xid == 0 || max_xid == FC_XID_UNKNOWN) { | 1772 | if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN) { |
1821 | FC_LPORT_DBG(lp, "Invalid min_xid 0x:%x and max_xid 0x:%x\n", | 1773 | FC_LPORT_DBG(lp, "Invalid min_xid 0x:%x and max_xid 0x:%x\n", |
1822 | min_xid, max_xid); | 1774 | min_xid, max_xid); |
1823 | return NULL; | 1775 | return NULL; |
@@ -1826,7 +1778,6 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, | |||
1826 | /* | 1778 | /* |
1827 | * Memory need for EM | 1779 | * Memory need for EM |
1828 | */ | 1780 | */ |
1829 | #define xid_ok(i, m1, m2) (((i) >= (m1)) && ((i) <= (m2))) | ||
1830 | len = (max_xid - min_xid + 1) * (sizeof(struct fc_exch *)); | 1781 | len = (max_xid - min_xid + 1) * (sizeof(struct fc_exch *)); |
1831 | len += sizeof(struct fc_exch_mgr); | 1782 | len += sizeof(struct fc_exch_mgr); |
1832 | 1783 | ||
@@ -1840,17 +1791,7 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, | |||
1840 | /* adjust em exch xid range for offload */ | 1791 | /* adjust em exch xid range for offload */ |
1841 | mp->min_xid = min_xid; | 1792 | mp->min_xid = min_xid; |
1842 | mp->max_xid = max_xid; | 1793 | mp->max_xid = max_xid; |
1843 | mp->last_xid = min_xid - 1; | 1794 | mp->next_xid = min_xid; |
1844 | mp->max_read = 0; | ||
1845 | mp->last_read = 0; | ||
1846 | if (lp->lro_enabled && xid_ok(lp->lro_xid, min_xid, max_xid)) { | ||
1847 | mp->max_read = lp->lro_xid; | ||
1848 | mp->last_read = min_xid - 1; | ||
1849 | mp->last_xid = mp->max_read; | ||
1850 | } else { | ||
1851 | /* disable lro if no xid control over read */ | ||
1852 | lp->lro_enabled = 0; | ||
1853 | } | ||
1854 | 1795 | ||
1855 | INIT_LIST_HEAD(&mp->ex_list); | 1796 | INIT_LIST_HEAD(&mp->ex_list); |
1856 | spin_lock_init(&mp->em_lock); | 1797 | spin_lock_init(&mp->em_lock); |
@@ -1922,7 +1863,8 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, | |||
1922 | fc_exch_setup_hdr(ep, fp, ep->f_ctl); | 1863 | fc_exch_setup_hdr(ep, fp, ep->f_ctl); |
1923 | sp->cnt++; | 1864 | sp->cnt++; |
1924 | 1865 | ||
1925 | fc_fcp_ddp_setup(fr_fsp(fp), ep->xid); | 1866 | if (ep->xid <= lp->lro_xid) |
1867 | fc_fcp_ddp_setup(fr_fsp(fp), ep->xid); | ||
1926 | 1868 | ||
1927 | if (unlikely(lp->tt.frame_send(lp, fp))) | 1869 | if (unlikely(lp->tt.frame_send(lp, fp))) |
1928 | goto err; | 1870 | goto err; |