aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/scsi/fcoe/fcoe.c16
-rw-r--r--drivers/scsi/fcoe/libfcoe.c2
-rw-r--r--drivers/scsi/fnic/fnic_fcs.c2
-rw-r--r--drivers/scsi/fnic/fnic_main.c20
-rw-r--r--drivers/scsi/libfc/fc_exch.c191
-rw-r--r--include/scsi/libfc.h48
6 files changed, 142 insertions, 137 deletions
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 719a99d4a438..ebf2e20370d7 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -423,11 +423,8 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost,
423 */ 423 */
424static inline int fcoe_em_config(struct fc_lport *lp) 424static inline int fcoe_em_config(struct fc_lport *lp)
425{ 425{
426 BUG_ON(lp->emp); 426 if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCOE_MIN_XID,
427 427 FCOE_MAX_XID, NULL))
428 lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3,
429 FCOE_MIN_XID, FCOE_MAX_XID);
430 if (!lp->emp)
431 return -ENOMEM; 428 return -ENOMEM;
432 429
433 return 0; 430 return 0;
@@ -478,8 +475,7 @@ static int fcoe_if_destroy(struct net_device *netdev)
478 scsi_remove_host(lp->host); 475 scsi_remove_host(lp->host);
479 476
480 /* There are no more rports or I/O, free the EM */ 477 /* There are no more rports or I/O, free the EM */
481 if (lp->emp) 478 fc_exch_mgr_free(lp);
482 fc_exch_mgr_free(lp->emp);
483 479
484 /* Free existing skbs */ 480 /* Free existing skbs */
485 fcoe_clean_pending_queue(lp); 481 fcoe_clean_pending_queue(lp);
@@ -634,7 +630,7 @@ static int fcoe_if_create(struct net_device *netdev)
634 return rc; 630 return rc;
635 631
636out_lp_destroy: 632out_lp_destroy:
637 fc_exch_mgr_free(lp->emp); /* Free the EM */ 633 fc_exch_mgr_free(lp);
638out_netdev_cleanup: 634out_netdev_cleanup:
639 fcoe_netdev_cleanup(fc); 635 fcoe_netdev_cleanup(fc);
640out_host_put: 636out_host_put:
@@ -1277,7 +1273,7 @@ int fcoe_percpu_receive_thread(void *arg)
1277 fh = fc_frame_header_get(fp); 1273 fh = fc_frame_header_get(fp);
1278 if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && 1274 if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA &&
1279 fh->fh_type == FC_TYPE_FCP) { 1275 fh->fh_type == FC_TYPE_FCP) {
1280 fc_exch_recv(lp, lp->emp, fp); 1276 fc_exch_recv(lp, fp);
1281 continue; 1277 continue;
1282 } 1278 }
1283 if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) { 1279 if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) {
@@ -1298,7 +1294,7 @@ int fcoe_percpu_receive_thread(void *arg)
1298 fc_frame_free(fp); 1294 fc_frame_free(fp);
1299 continue; 1295 continue;
1300 } 1296 }
1301 fc_exch_recv(lp, lp->emp, fp); 1297 fc_exch_recv(lp, fp);
1302 } 1298 }
1303 return 0; 1299 return 0;
1304} 1300}
diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c
index 78caa6be1130..4db719d6ada1 100644
--- a/drivers/scsi/fcoe/libfcoe.c
+++ b/drivers/scsi/fcoe/libfcoe.c
@@ -885,7 +885,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
885 stats->RxFrames++; 885 stats->RxFrames++;
886 stats->RxWords += skb->len / FIP_BPW; 886 stats->RxWords += skb->len / FIP_BPW;
887 887
888 fc_exch_recv(lp, lp->emp, fp); 888 fc_exch_recv(lp, fp);
889 return; 889 return;
890 890
891len_err: 891len_err:
diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c
index 07e6eedb83ce..50db3e36a619 100644
--- a/drivers/scsi/fnic/fnic_fcs.c
+++ b/drivers/scsi/fnic/fnic_fcs.c
@@ -115,7 +115,7 @@ void fnic_handle_frame(struct work_struct *work)
115 } 115 }
116 spin_unlock_irqrestore(&fnic->fnic_lock, flags); 116 spin_unlock_irqrestore(&fnic->fnic_lock, flags);
117 117
118 fc_exch_recv(lp, lp->emp, fp); 118 fc_exch_recv(lp, fp);
119 } 119 }
120 120
121} 121}
diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c
index 2c266c01dc5a..71c7bbe26d05 100644
--- a/drivers/scsi/fnic/fnic_main.c
+++ b/drivers/scsi/fnic/fnic_main.c
@@ -671,14 +671,6 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
671 lp->link_up = 0; 671 lp->link_up = 0;
672 lp->tt = fnic_transport_template; 672 lp->tt = fnic_transport_template;
673 673
674 lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3,
675 FCPIO_HOST_EXCH_RANGE_START,
676 FCPIO_HOST_EXCH_RANGE_END);
677 if (!lp->emp) {
678 err = -ENOMEM;
679 goto err_out_remove_scsi_host;
680 }
681
682 lp->max_retry_count = fnic->config.flogi_retries; 674 lp->max_retry_count = fnic->config.flogi_retries;
683 lp->max_rport_retry_count = fnic->config.plogi_retries; 675 lp->max_rport_retry_count = fnic->config.plogi_retries;
684 lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | 676 lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
@@ -693,12 +685,18 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
693 fc_set_wwnn(lp, fnic->config.node_wwn); 685 fc_set_wwnn(lp, fnic->config.node_wwn);
694 fc_set_wwpn(lp, fnic->config.port_wwn); 686 fc_set_wwpn(lp, fnic->config.port_wwn);
695 687
696 fc_exch_init(lp);
697 fc_lport_init(lp); 688 fc_lport_init(lp);
689 fc_exch_init(lp);
698 fc_elsct_init(lp); 690 fc_elsct_init(lp);
699 fc_rport_init(lp); 691 fc_rport_init(lp);
700 fc_disc_init(lp); 692 fc_disc_init(lp);
701 693
694 if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCPIO_HOST_EXCH_RANGE_START,
695 FCPIO_HOST_EXCH_RANGE_END, NULL)) {
696 err = -ENOMEM;
697 goto err_out_remove_scsi_host;
698 }
699
702 fc_lport_config(lp); 700 fc_lport_config(lp);
703 701
704 if (fc_set_mfs(lp, fnic->config.maxdatafieldsize + 702 if (fc_set_mfs(lp, fnic->config.maxdatafieldsize +
@@ -738,7 +736,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
738 return 0; 736 return 0;
739 737
740err_out_free_exch_mgr: 738err_out_free_exch_mgr:
741 fc_exch_mgr_free(lp->emp); 739 fc_exch_mgr_free(lp);
742err_out_remove_scsi_host: 740err_out_remove_scsi_host:
743 fc_remove_host(fnic->lport->host); 741 fc_remove_host(fnic->lport->host);
744 scsi_remove_host(fnic->lport->host); 742 scsi_remove_host(fnic->lport->host);
@@ -827,7 +825,7 @@ static void __devexit fnic_remove(struct pci_dev *pdev)
827 825
828 fc_remove_host(fnic->lport->host); 826 fc_remove_host(fnic->lport->host);
829 scsi_remove_host(fnic->lport->host); 827 scsi_remove_host(fnic->lport->host);
830 fc_exch_mgr_free(fnic->lport->emp); 828 fc_exch_mgr_free(fnic->lport);
831 vnic_dev_notify_unset(fnic->vdev); 829 vnic_dev_notify_unset(fnic->vdev);
832 fnic_free_vnic_resources(fnic); 830 fnic_free_vnic_resources(fnic);
833 fnic_free_intr(fnic); 831 fnic_free_intr(fnic);
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
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
index f1bde91f98a2..c2b928cfafb9 100644
--- a/include/scsi/libfc.h
+++ b/include/scsi/libfc.h
@@ -518,25 +518,6 @@ struct libfc_function_template {
518 void (*exch_done)(struct fc_seq *sp); 518 void (*exch_done)(struct fc_seq *sp);
519 519
520 /* 520 /*
521 * Assigns a EM and a free XID for an new exchange and then
522 * allocates a new exchange and sequence pair.
523 * The fp can be used to determine free XID.
524 *
525 * STATUS: OPTIONAL
526 */
527 struct fc_exch *(*exch_get)(struct fc_lport *lp, struct fc_frame *fp);
528
529 /*
530 * Release previously assigned XID by exch_get API.
531 * The LLD may implement this if XID is assigned by LLD
532 * in exch_get().
533 *
534 * STATUS: OPTIONAL
535 */
536 void (*exch_put)(struct fc_lport *lp, struct fc_exch_mgr *mp,
537 u16 ex_id);
538
539 /*
540 * Start a new sequence on the same exchange/sequence tuple. 521 * Start a new sequence on the same exchange/sequence tuple.
541 * 522 *
542 * STATUS: OPTIONAL 523 * STATUS: OPTIONAL
@@ -703,7 +684,6 @@ struct fc_lport {
703 684
704 /* Associations */ 685 /* Associations */
705 struct Scsi_Host *host; 686 struct Scsi_Host *host;
706 struct fc_exch_mgr *emp;
707 struct list_head ema_list; 687 struct list_head ema_list;
708 struct fc_rport *dns_rp; 688 struct fc_rport *dns_rp;
709 struct fc_rport *ptp_rp; 689 struct fc_rport *ptp_rp;
@@ -996,27 +976,25 @@ void fc_exch_mgr_del(struct fc_exch_mgr_anchor *ema);
996 * a new exchange. 976 * a new exchange.
997 * The LLD may choose to have multiple EMs, 977 * The LLD may choose to have multiple EMs,
998 * e.g. one EM instance per CPU receive thread in LLD. 978 * e.g. one EM instance per CPU receive thread in LLD.
999 * The LLD can use exch_get() of struct libfc_function_template
1000 * to specify XID for a new exchange within
1001 * a specified EM instance.
1002 * 979 *
1003 * The em_idx to uniquely identify an EM instance. 980 * Specified match function is used in allocating exchanges
981 * from newly allocated EM.
1004 */ 982 */
1005struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, 983struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp,
1006 enum fc_class class, 984 enum fc_class class,
1007 u16 min_xid, 985 u16 min_xid,
1008 u16 max_xid); 986 u16 max_xid,
987 bool (*match)(struct fc_frame *));
1009 988
1010/* 989/*
1011 * Free an exchange manager. 990 * Free all exchange managers of a lport.
1012 */ 991 */
1013void fc_exch_mgr_free(struct fc_exch_mgr *mp); 992void fc_exch_mgr_free(struct fc_lport *lport);
1014 993
1015/* 994/*
1016 * Receive a frame on specified local port and exchange manager. 995 * Receive a frame on specified local port and exchange manager.
1017 */ 996 */
1018void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, 997void fc_exch_recv(struct fc_lport *lp, struct fc_frame *fp);
1019 struct fc_frame *fp);
1020 998
1021/* 999/*
1022 * This function is for exch_seq_send function pointer in 1000 * This function is for exch_seq_send function pointer in
@@ -1058,19 +1036,9 @@ int fc_seq_exch_abort(const struct fc_seq *req_sp, unsigned int timer_msec);
1058void fc_exch_done(struct fc_seq *sp); 1036void fc_exch_done(struct fc_seq *sp);
1059 1037
1060/* 1038/*
1061 * Assigns a EM and XID for a frame and then allocates
1062 * a new exchange and sequence pair.
1063 * The fp can be used to determine free XID.
1064 */
1065struct fc_exch *fc_exch_get(struct fc_lport *lp, struct fc_frame *fp);
1066
1067/*
1068 * Allocate a new exchange and sequence pair. 1039 * Allocate a new exchange and sequence pair.
1069 * if ex_id is zero then next free exchange id
1070 * from specified exchange manger mp will be assigned.
1071 */ 1040 */
1072struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, 1041struct fc_exch *fc_exch_alloc(struct fc_lport *lport, struct fc_frame *fp);
1073 struct fc_frame *fp, u16 ex_id);
1074/* 1042/*
1075 * Start a new sequence on the same exchange as the supplied sequence. 1043 * Start a new sequence on the same exchange as the supplied sequence.
1076 */ 1044 */