diff options
-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 | */ |