diff options
author | Vasu Dev <vasu.dev@intel.com> | 2009-07-29 20:05:10 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-08-22 18:52:08 -0400 |
commit | 52ff878c912215210f53c0a080552dd6ba3055a2 (patch) | |
tree | efaf0c6a6585aedc02af5faa3b47f4f4685fc783 | |
parent | d459b7ea1b4c7aa3dacfeee174d02b2f7a95850d (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.c | 16 | ||||
-rw-r--r-- | drivers/scsi/fcoe/libfcoe.c | 2 | ||||
-rw-r--r-- | drivers/scsi/fnic/fnic_fcs.c | 2 | ||||
-rw-r--r-- | drivers/scsi/fnic/fnic_main.c | 20 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_exch.c | 191 | ||||
-rw-r--r-- | include/scsi/libfc.h | 48 |
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 | */ |
424 | static inline int fcoe_em_config(struct fc_lport *lp) | 424 | static 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 | ||
636 | out_lp_destroy: | 632 | out_lp_destroy: |
637 | fc_exch_mgr_free(lp->emp); /* Free the EM */ | 633 | fc_exch_mgr_free(lp); |
638 | out_netdev_cleanup: | 634 | out_netdev_cleanup: |
639 | fcoe_netdev_cleanup(fc); | 635 | fcoe_netdev_cleanup(fc); |
640 | out_host_put: | 636 | out_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 | ||
891 | len_err: | 891 | len_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 | ||
740 | err_out_free_exch_mgr: | 738 | err_out_free_exch_mgr: |
741 | fc_exch_mgr_free(lp->emp); | 739 | fc_exch_mgr_free(lp); |
742 | err_out_remove_scsi_host: | 740 | err_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 | */ |
525 | struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, | 524 | static 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 | */ | ||
593 | struct 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 | } | ||
582 | EXPORT_SYMBOL(fc_exch_alloc); | 607 | EXPORT_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 | */ |
620 | static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) | 645 | static 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 | */ |
661 | static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_exch_mgr *mp, | 688 | static 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); | ||
1473 | restart: | 1504 | restart: |
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 | } |
1494 | EXPORT_SYMBOL(fc_exch_mgr_reset); | 1527 | EXPORT_SYMBOL(fc_exch_mgr_reset); |
1495 | 1528 | ||
@@ -1778,7 +1811,8 @@ EXPORT_SYMBOL(fc_exch_mgr_del); | |||
1778 | 1811 | ||
1779 | struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, | 1812 | struct 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 | ||
1831 | free_mp: | 1876 | free_mp: |
@@ -1834,27 +1879,15 @@ free_mp: | |||
1834 | } | 1879 | } |
1835 | EXPORT_SYMBOL(fc_exch_mgr_alloc); | 1880 | EXPORT_SYMBOL(fc_exch_mgr_alloc); |
1836 | 1881 | ||
1837 | void fc_exch_mgr_free(struct fc_exch_mgr *mp) | 1882 | void 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 | } |
1848 | EXPORT_SYMBOL(fc_exch_mgr_free); | 1889 | EXPORT_SYMBOL(fc_exch_mgr_free); |
1849 | 1890 | ||
1850 | struct 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 | } | ||
1857 | EXPORT_SYMBOL(fc_exch_get); | ||
1858 | 1891 | ||
1859 | struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, | 1892 | struct 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 | */ |
1917 | void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, | 1950 | void 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 | } |
1957 | EXPORT_SYMBOL(fc_exch_recv); | 2009 | EXPORT_SYMBOL(fc_exch_recv); |
1958 | 2010 | ||
1959 | int fc_exch_init(struct fc_lport *lp) | 2011 | int 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 | */ |
1005 | struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, | 983 | struct 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 | */ |
1013 | void fc_exch_mgr_free(struct fc_exch_mgr *mp); | 992 | void 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 | */ |
1018 | void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, | 997 | void 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); | |||
1058 | void fc_exch_done(struct fc_seq *sp); | 1036 | void 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 | */ | ||
1065 | struct 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 | */ |
1072 | struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, | 1041 | struct 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 | */ |