aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libfc
diff options
context:
space:
mode:
authorVasu Dev <vasu.dev@intel.com>2009-07-29 20:05:10 -0400
committerJames Bottomley <James.Bottomley@suse.de>2009-08-22 18:52:08 -0400
commit52ff878c912215210f53c0a080552dd6ba3055a2 (patch)
treeefaf0c6a6585aedc02af5faa3b47f4f4685fc783 /drivers/scsi/libfc
parentd459b7ea1b4c7aa3dacfeee174d02b2f7a95850d (diff)
[SCSI] fcoe, fnic, libfc: modifies current code paths to use EM anchor list
Modifies current code to use EM anchor list in EM allocation, EM free, EM reset, exch allocation and exch lookup code paths. 1. Modifies fc_exch_mgr_alloc to accept EM match function and then have allocated EM added to the lport using fc_exch_mgr_add API while also updating EM kref for newly added EM. 2. Updates fc_exch_mgr_free API to accept only lport pointer instead EM and then have this API free all EMs of the lport from EM anchor list. 3. Removes single lport pointer link from the EM, which was used in associating lport pointer in newly allocated exchange. Instead have lport pointer passed along new exchange allocation call path and then store passed lport pointer in newly allocated exchange, this will allow a single EM instance to be used across more than one lport and used in EM reset to reset only lport specific exchanges. 4. Modifies fc_exch_mgr_reset to reset all EMs from the EM anchor list of the lport, adds additional exch lport pointer (ep->lp) check for shared EM case to reset exchange specific to a lport requested reset. 5. Updates exch allocation API fc_exch_alloc to use EM anchor list and its anchor match func pointer. The fc_exch_alloc will walk the list of EMs until it finds a match, a match will be either null match func pointer or call to match function returning true value. 6. Updates fc_exch_recv to accept incoming frame on local port using only lport pointer and frame pointer without specifying EM instance of incoming frame. Instead modified fc_exch_recv to locate EM for the incoming frame by matching xid of incoming frame against a EM xid range. This change was required to use EM list in libfc Rx path and after this change the lport fc_exch_mgr pointer emp is not needed anymore, so removed emp pointer. 7. Updates fnic for removed lport emp pointer and above modified libfc APIs fc_exch_recv, fc_exch_mgr_alloc and fc_exch_mgr_free. 8. Removes exch_get and exch_put from libfc_function_template as these are no longer needed with EM anchor list and its match function use. Also removes its default function fc_exch_get. A defect this patch introduced regarding the libfc initialization order in the fnic driver was fixed by Joe Eykholt <jeykholt@cisco.com>. 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.c191
1 files changed, 117 insertions, 74 deletions
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index 3ad7f88e7ae3..324589a5cc03 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -65,7 +65,6 @@ struct fc_exch_mgr {
65 u16 last_read; /* last xid allocated for read */ 65 u16 last_read; /* last xid allocated for read */
66 u32 total_exches; /* total allocated exchanges */ 66 u32 total_exches; /* total allocated exchanges */
67 struct list_head ex_list; /* allocated exchanges list */ 67 struct list_head ex_list; /* allocated exchanges list */
68 struct fc_lport *lp; /* fc device instance */
69 mempool_t *ep_pool; /* reserve ep's */ 68 mempool_t *ep_pool; /* reserve ep's */
70 69
71 /* 70 /*
@@ -275,8 +274,6 @@ static void fc_exch_release(struct fc_exch *ep)
275 mp = ep->em; 274 mp = ep->em;
276 if (ep->destructor) 275 if (ep->destructor)
277 ep->destructor(&ep->seq, ep->arg); 276 ep->destructor(&ep->seq, ep->arg);
278 if (ep->lp->tt.exch_put)
279 ep->lp->tt.exch_put(ep->lp, mp, ep->xid);
280 WARN_ON(!(ep->esb_stat & ESB_ST_COMPLETE)); 277 WARN_ON(!(ep->esb_stat & ESB_ST_COMPLETE));
281 mempool_free(ep, mp->ep_pool); 278 mempool_free(ep, mp->ep_pool);
282 } 279 }
@@ -513,17 +510,20 @@ static u16 fc_em_alloc_xid(struct fc_exch_mgr *mp, const struct fc_frame *fp)
513 return xid; 510 return xid;
514} 511}
515 512
516/* 513/**
517 * fc_exch_alloc - allocate an exchange. 514 * fc_exch_em_alloc() - allocate an exchange from a specified EM.
518 * @mp : ptr to the exchange manager 515 * @lport: ptr to the local port
519 * @xid: input xid 516 * @mp: ptr to the exchange manager
517 * @fp: ptr to the FC frame
518 * @xid: input xid
520 * 519 *
521 * if xid is supplied zero then assign next free exchange ID 520 * if xid is supplied zero then assign next free exchange ID
522 * from exchange manager, otherwise use supplied xid. 521 * from exchange manager, otherwise use supplied xid.
523 * Returns with exch lock held. 522 * Returns with exch lock held.
524 */ 523 */
525struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, 524static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport,
526 struct fc_frame *fp, u16 xid) 525 struct fc_exch_mgr *mp,
526 struct fc_frame *fp, u16 xid)
527{ 527{
528 struct fc_exch *ep; 528 struct fc_exch *ep;
529 529
@@ -566,7 +566,7 @@ struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp,
566 */ 566 */
567 ep->oxid = ep->xid = xid; 567 ep->oxid = ep->xid = xid;
568 ep->em = mp; 568 ep->em = mp;
569 ep->lp = mp->lp; 569 ep->lp = lport;
570 ep->f_ctl = FC_FC_FIRST_SEQ; /* next seq is first seq */ 570 ep->f_ctl = FC_FC_FIRST_SEQ; /* next seq is first seq */
571 ep->rxid = FC_XID_UNKNOWN; 571 ep->rxid = FC_XID_UNKNOWN;
572 ep->class = mp->class; 572 ep->class = mp->class;
@@ -579,6 +579,31 @@ err:
579 mempool_free(ep, mp->ep_pool); 579 mempool_free(ep, mp->ep_pool);
580 return NULL; 580 return NULL;
581} 581}
582
583/**
584 * fc_exch_alloc() - allocate an exchange.
585 * @lport: ptr to the local port
586 * @fp: ptr to the FC frame
587 *
588 * This function walks the list of the exchange manager(EM)
589 * anchors to select a EM for new exchange allocation. The
590 * EM is selected having either a NULL match function pointer
591 * or call to match function returning true.
592 */
593struct fc_exch *fc_exch_alloc(struct fc_lport *lport, struct fc_frame *fp)
594{
595 struct fc_exch_mgr_anchor *ema;
596 struct fc_exch *ep;
597
598 list_for_each_entry(ema, &lport->ema_list, ema_list) {
599 if (!ema->match || ema->match(fp)) {
600 ep = fc_exch_em_alloc(lport, ema->mp, fp, 0);
601 if (ep)
602 return ep;
603 }
604 }
605 return NULL;
606}
582EXPORT_SYMBOL(fc_exch_alloc); 607EXPORT_SYMBOL(fc_exch_alloc);
583 608
584/* 609/*
@@ -617,12 +642,14 @@ EXPORT_SYMBOL(fc_exch_done);
617 * Allocate a new exchange as responder. 642 * Allocate a new exchange as responder.
618 * Sets the responder ID in the frame header. 643 * Sets the responder ID in the frame header.
619 */ 644 */
620static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) 645static struct fc_exch *fc_exch_resp(struct fc_lport *lport,
646 struct fc_exch_mgr *mp,
647 struct fc_frame *fp)
621{ 648{
622 struct fc_exch *ep; 649 struct fc_exch *ep;
623 struct fc_frame_header *fh; 650 struct fc_frame_header *fh;
624 651
625 ep = mp->lp->tt.exch_get(mp->lp, fp); 652 ep = fc_exch_alloc(lport, fp);
626 if (ep) { 653 if (ep) {
627 ep->class = fc_frame_class(fp); 654 ep->class = fc_frame_class(fp);
628 655
@@ -648,7 +675,7 @@ static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
648 ep->esb_stat &= ~ESB_ST_SEQ_INIT; 675 ep->esb_stat &= ~ESB_ST_SEQ_INIT;
649 676
650 fc_exch_hold(ep); /* hold for caller */ 677 fc_exch_hold(ep); /* hold for caller */
651 spin_unlock_bh(&ep->ex_lock); /* lock from exch_get */ 678 spin_unlock_bh(&ep->ex_lock); /* lock from fc_exch_alloc */
652 } 679 }
653 return ep; 680 return ep;
654} 681}
@@ -658,7 +685,8 @@ static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
658 * If fc_pf_rjt_reason is FC_RJT_NONE then this function will have a hold 685 * If fc_pf_rjt_reason is FC_RJT_NONE then this function will have a hold
659 * on the ep that should be released by the caller. 686 * on the ep that should be released by the caller.
660 */ 687 */
661static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_exch_mgr *mp, 688static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport,
689 struct fc_exch_mgr *mp,
662 struct fc_frame *fp) 690 struct fc_frame *fp)
663{ 691{
664 struct fc_frame_header *fh = fc_frame_header_get(fp); 692 struct fc_frame_header *fh = fc_frame_header_get(fp);
@@ -712,7 +740,7 @@ static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_exch_mgr *mp,
712 reject = FC_RJT_RX_ID; 740 reject = FC_RJT_RX_ID;
713 goto rel; 741 goto rel;
714 } 742 }
715 ep = fc_exch_resp(mp, fp); 743 ep = fc_exch_resp(lport, mp, fp);
716 if (!ep) { 744 if (!ep) {
717 reject = FC_RJT_EXCH_EST; /* XXX */ 745 reject = FC_RJT_EXCH_EST; /* XXX */
718 goto out; 746 goto out;
@@ -1103,7 +1131,7 @@ static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp,
1103 enum fc_pf_rjt_reason reject; 1131 enum fc_pf_rjt_reason reject;
1104 1132
1105 fr_seq(fp) = NULL; 1133 fr_seq(fp) = NULL;
1106 reject = fc_seq_lookup_recip(mp, fp); 1134 reject = fc_seq_lookup_recip(lp, mp, fp);
1107 if (reject == FC_RJT_NONE) { 1135 if (reject == FC_RJT_NONE) {
1108 sp = fr_seq(fp); /* sequence will be held */ 1136 sp = fr_seq(fp); /* sequence will be held */
1109 ep = fc_seq_exch(sp); 1137 ep = fc_seq_exch(sp);
@@ -1467,29 +1495,34 @@ void fc_exch_mgr_reset(struct fc_lport *lp, u32 sid, u32 did)
1467{ 1495{
1468 struct fc_exch *ep; 1496 struct fc_exch *ep;
1469 struct fc_exch *next; 1497 struct fc_exch *next;
1470 struct fc_exch_mgr *mp = lp->emp; 1498 struct fc_exch_mgr *mp;
1499 struct fc_exch_mgr_anchor *ema;
1471 1500
1472 spin_lock_bh(&mp->em_lock); 1501 list_for_each_entry(ema, &lp->ema_list, ema_list) {
1502 mp = ema->mp;
1503 spin_lock_bh(&mp->em_lock);
1473restart: 1504restart:
1474 list_for_each_entry_safe(ep, next, &mp->ex_list, ex_list) { 1505 list_for_each_entry_safe(ep, next, &mp->ex_list, ex_list) {
1475 if ((sid == 0 || sid == ep->sid) && 1506 if ((lp == ep->lp) &&
1476 (did == 0 || did == ep->did)) { 1507 (sid == 0 || sid == ep->sid) &&
1477 fc_exch_hold(ep); 1508 (did == 0 || did == ep->did)) {
1478 spin_unlock_bh(&mp->em_lock); 1509 fc_exch_hold(ep);
1479 1510 spin_unlock_bh(&mp->em_lock);
1480 fc_exch_reset(ep); 1511
1481 1512 fc_exch_reset(ep);
1482 fc_exch_release(ep); 1513
1483 spin_lock_bh(&mp->em_lock); 1514 fc_exch_release(ep);
1484 1515 spin_lock_bh(&mp->em_lock);
1485 /* 1516
1486 * must restart loop incase while lock was down 1517 /*
1487 * multiple eps were released. 1518 * must restart loop incase while lock
1488 */ 1519 * was down multiple eps were released.
1489 goto restart; 1520 */
1521 goto restart;
1522 }
1490 } 1523 }
1524 spin_unlock_bh(&mp->em_lock);
1491 } 1525 }
1492 spin_unlock_bh(&mp->em_lock);
1493} 1526}
1494EXPORT_SYMBOL(fc_exch_mgr_reset); 1527EXPORT_SYMBOL(fc_exch_mgr_reset);
1495 1528
@@ -1778,7 +1811,8 @@ EXPORT_SYMBOL(fc_exch_mgr_del);
1778 1811
1779struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, 1812struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp,
1780 enum fc_class class, 1813 enum fc_class class,
1781 u16 min_xid, u16 max_xid) 1814 u16 min_xid, u16 max_xid,
1815 bool (*match)(struct fc_frame *))
1782{ 1816{
1783 struct fc_exch_mgr *mp; 1817 struct fc_exch_mgr *mp;
1784 size_t len; 1818 size_t len;
@@ -1803,7 +1837,6 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp,
1803 mp->class = class; 1837 mp->class = class;
1804 mp->total_exches = 0; 1838 mp->total_exches = 0;
1805 mp->exches = (struct fc_exch **)(mp + 1); 1839 mp->exches = (struct fc_exch **)(mp + 1);
1806 mp->lp = lp;
1807 /* adjust em exch xid range for offload */ 1840 /* adjust em exch xid range for offload */
1808 mp->min_xid = min_xid; 1841 mp->min_xid = min_xid;
1809 mp->max_xid = max_xid; 1842 mp->max_xid = max_xid;
@@ -1826,6 +1859,18 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp,
1826 if (!mp->ep_pool) 1859 if (!mp->ep_pool)
1827 goto free_mp; 1860 goto free_mp;
1828 1861
1862 kref_init(&mp->kref);
1863 if (!fc_exch_mgr_add(lp, mp, match)) {
1864 mempool_destroy(mp->ep_pool);
1865 goto free_mp;
1866 }
1867
1868 /*
1869 * Above kref_init() sets mp->kref to 1 and then
1870 * call to fc_exch_mgr_add incremented mp->kref again,
1871 * so adjust that extra increment.
1872 */
1873 kref_put(&mp->kref, fc_exch_mgr_destroy);
1829 return mp; 1874 return mp;
1830 1875
1831free_mp: 1876free_mp:
@@ -1834,27 +1879,15 @@ free_mp:
1834} 1879}
1835EXPORT_SYMBOL(fc_exch_mgr_alloc); 1880EXPORT_SYMBOL(fc_exch_mgr_alloc);
1836 1881
1837void fc_exch_mgr_free(struct fc_exch_mgr *mp) 1882void fc_exch_mgr_free(struct fc_lport *lport)
1838{ 1883{
1839 WARN_ON(!mp); 1884 struct fc_exch_mgr_anchor *ema, *next;
1840 /* 1885
1841 * The total exch count must be zero 1886 list_for_each_entry_safe(ema, next, &lport->ema_list, ema_list)
1842 * before freeing exchange manager. 1887 fc_exch_mgr_del(ema);
1843 */
1844 WARN_ON(mp->total_exches != 0);
1845 mempool_destroy(mp->ep_pool);
1846 kfree(mp);
1847} 1888}
1848EXPORT_SYMBOL(fc_exch_mgr_free); 1889EXPORT_SYMBOL(fc_exch_mgr_free);
1849 1890
1850struct fc_exch *fc_exch_get(struct fc_lport *lp, struct fc_frame *fp)
1851{
1852 if (!lp || !lp->emp)
1853 return NULL;
1854
1855 return fc_exch_alloc(lp->emp, fp, 0);
1856}
1857EXPORT_SYMBOL(fc_exch_get);
1858 1891
1859struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, 1892struct fc_seq *fc_exch_seq_send(struct fc_lport *lp,
1860 struct fc_frame *fp, 1893 struct fc_frame *fp,
@@ -1869,7 +1902,7 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp,
1869 struct fc_frame_header *fh; 1902 struct fc_frame_header *fh;
1870 int rc = 1; 1903 int rc = 1;
1871 1904
1872 ep = lp->tt.exch_get(lp, fp); 1905 ep = fc_exch_alloc(lp, fp);
1873 if (!ep) { 1906 if (!ep) {
1874 fc_frame_free(fp); 1907 fc_frame_free(fp);
1875 return NULL; 1908 return NULL;
@@ -1914,24 +1947,44 @@ EXPORT_SYMBOL(fc_exch_seq_send);
1914/* 1947/*
1915 * Receive a frame 1948 * Receive a frame
1916 */ 1949 */
1917void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, 1950void fc_exch_recv(struct fc_lport *lp, struct fc_frame *fp)
1918 struct fc_frame *fp)
1919{ 1951{
1920 struct fc_frame_header *fh = fc_frame_header_get(fp); 1952 struct fc_frame_header *fh = fc_frame_header_get(fp);
1921 u32 f_ctl; 1953 struct fc_exch_mgr_anchor *ema;
1954 u32 f_ctl, found = 0;
1955 u16 oxid;
1922 1956
1923 /* lport lock ? */ 1957 /* lport lock ? */
1924 if (!lp || !mp || lp->state == LPORT_ST_DISABLED) { 1958 if (!lp || lp->state == LPORT_ST_DISABLED) {
1925 FC_LPORT_DBG(lp, "Receiving frames for an lport that " 1959 FC_LPORT_DBG(lp, "Receiving frames for an lport that "
1926 "has not been initialized correctly\n"); 1960 "has not been initialized correctly\n");
1927 fc_frame_free(fp); 1961 fc_frame_free(fp);
1928 return; 1962 return;
1929 } 1963 }
1930 1964
1965 f_ctl = ntoh24(fh->fh_f_ctl);
1966 oxid = ntohs(fh->fh_ox_id);
1967 if (f_ctl & FC_FC_EX_CTX) {
1968 list_for_each_entry(ema, &lp->ema_list, ema_list) {
1969 if ((oxid >= ema->mp->min_xid) &&
1970 (oxid <= ema->mp->max_xid)) {
1971 found = 1;
1972 break;
1973 }
1974 }
1975
1976 if (!found) {
1977 FC_LPORT_DBG(lp, "Received response for out "
1978 "of range oxid:%hx\n", oxid);
1979 fc_frame_free(fp);
1980 return;
1981 }
1982 } else
1983 ema = list_entry(lp->ema_list.prev, typeof(*ema), ema_list);
1984
1931 /* 1985 /*
1932 * If frame is marked invalid, just drop it. 1986 * If frame is marked invalid, just drop it.
1933 */ 1987 */
1934 f_ctl = ntoh24(fh->fh_f_ctl);
1935 switch (fr_eof(fp)) { 1988 switch (fr_eof(fp)) {
1936 case FC_EOF_T: 1989 case FC_EOF_T:
1937 if (f_ctl & FC_FC_END_SEQ) 1990 if (f_ctl & FC_FC_END_SEQ)
@@ -1939,34 +1992,24 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp,
1939 /* fall through */ 1992 /* fall through */
1940 case FC_EOF_N: 1993 case FC_EOF_N:
1941 if (fh->fh_type == FC_TYPE_BLS) 1994 if (fh->fh_type == FC_TYPE_BLS)
1942 fc_exch_recv_bls(mp, fp); 1995 fc_exch_recv_bls(ema->mp, fp);
1943 else if ((f_ctl & (FC_FC_EX_CTX | FC_FC_SEQ_CTX)) == 1996 else if ((f_ctl & (FC_FC_EX_CTX | FC_FC_SEQ_CTX)) ==
1944 FC_FC_EX_CTX) 1997 FC_FC_EX_CTX)
1945 fc_exch_recv_seq_resp(mp, fp); 1998 fc_exch_recv_seq_resp(ema->mp, fp);
1946 else if (f_ctl & FC_FC_SEQ_CTX) 1999 else if (f_ctl & FC_FC_SEQ_CTX)
1947 fc_exch_recv_resp(mp, fp); 2000 fc_exch_recv_resp(ema->mp, fp);
1948 else 2001 else
1949 fc_exch_recv_req(lp, mp, fp); 2002 fc_exch_recv_req(lp, ema->mp, fp);
1950 break; 2003 break;
1951 default: 2004 default:
1952 FC_LPORT_DBG(lp, "dropping invalid frame (eof %x)", fr_eof(fp)); 2005 FC_LPORT_DBG(lp, "dropping invalid frame (eof %x)", fr_eof(fp));
1953 fc_frame_free(fp); 2006 fc_frame_free(fp);
1954 break;
1955 } 2007 }
1956} 2008}
1957EXPORT_SYMBOL(fc_exch_recv); 2009EXPORT_SYMBOL(fc_exch_recv);
1958 2010
1959int fc_exch_init(struct fc_lport *lp) 2011int fc_exch_init(struct fc_lport *lp)
1960{ 2012{
1961 if (!lp->tt.exch_get) {
1962 /*
1963 * exch_put() should be NULL if
1964 * exch_get() is NULL
1965 */
1966 WARN_ON(lp->tt.exch_put);
1967 lp->tt.exch_get = fc_exch_get;
1968 }
1969
1970 if (!lp->tt.seq_start_next) 2013 if (!lp->tt.seq_start_next)
1971 lp->tt.seq_start_next = fc_seq_start_next; 2014 lp->tt.seq_start_next = fc_seq_start_next;
1972 2015