aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Leech <christopher.leech@intel.com>2009-02-27 13:56:32 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-03-10 10:09:40 -0400
commit55c8bafba549e3e82f6999db8c5a62fc3c255c14 (patch)
tree3ae4d7375fc1c5faaa16cc70277ca24e33a6f9b0
parentc826a3145736e3baabebccfd0aecfbb6dae059f2 (diff)
[SCSI] fcoe: fix handling of pending queue, prevent out of order frames (v3)
In fcoe_check_wait_queue() the queue length could temporarily drop to 0, before the last frame was successfully sent. This resulted in out of order data frames within a single sequence, leading to IO timeout errors. This builds on the approach from Vasu Dev to only fix the queue management in fcoe_check_wait_queue, where my first patch added locking to the transmit path even when the pending queue was not in use. This patch continues to use fcoe_pending_queue.qlen instead of introducing a new length counter, but takes precautions to ensure it never drops to 0 before the final frame in the queue has successfully been passed to the netdev qdisc layer. It also includes some cleanup of fcoe_check_wait_queue and removes the fcoe_insert_wait_queue(_head) wrapper functions. Signed-off-by: Chris Leech <christopher.leech@intel.com> Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r--drivers/scsi/fcoe/libfcoe.c81
1 files changed, 24 insertions, 57 deletions
diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c
index 14dd8a0402b6..0e0b494fc17c 100644
--- a/drivers/scsi/fcoe/libfcoe.c
+++ b/drivers/scsi/fcoe/libfcoe.c
@@ -70,8 +70,6 @@ struct fcoe_percpu_s *fcoe_percpu[NR_CPUS];
70 70
71/* Function Prototyes */ 71/* Function Prototyes */
72static int fcoe_check_wait_queue(struct fc_lport *); 72static int fcoe_check_wait_queue(struct fc_lport *);
73static void fcoe_insert_wait_queue_head(struct fc_lport *, struct sk_buff *);
74static void fcoe_insert_wait_queue(struct fc_lport *, struct sk_buff *);
75static void fcoe_recv_flogi(struct fcoe_softc *, struct fc_frame *, u8 *); 73static void fcoe_recv_flogi(struct fcoe_softc *, struct fc_frame *, u8 *);
76#ifdef CONFIG_HOTPLUG_CPU 74#ifdef CONFIG_HOTPLUG_CPU
77static int fcoe_cpu_callback(struct notifier_block *, ulong, void *); 75static int fcoe_cpu_callback(struct notifier_block *, ulong, void *);
@@ -501,7 +499,9 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
501 rc = fcoe_start_io(skb); 499 rc = fcoe_start_io(skb);
502 500
503 if (rc) { 501 if (rc) {
504 fcoe_insert_wait_queue(lp, skb); 502 spin_lock_bh(&fc->fcoe_pending_queue.lock);
503 __skb_queue_tail(&fc->fcoe_pending_queue, skb);
504 spin_unlock_bh(&fc->fcoe_pending_queue.lock);
505 if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) 505 if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
506 lp->qfull = 1; 506 lp->qfull = 1;
507 } 507 }
@@ -756,33 +756,36 @@ void fcoe_watchdog(ulong vp)
756 */ 756 */
757static int fcoe_check_wait_queue(struct fc_lport *lp) 757static int fcoe_check_wait_queue(struct fc_lport *lp)
758{ 758{
759 struct fcoe_softc *fc = lport_priv(lp);
759 struct sk_buff *skb; 760 struct sk_buff *skb;
760 struct fcoe_softc *fc;
761 int rc = -1; 761 int rc = -1;
762 762
763 fc = lport_priv(lp);
764 spin_lock_bh(&fc->fcoe_pending_queue.lock); 763 spin_lock_bh(&fc->fcoe_pending_queue.lock);
765
766 if (fc->fcoe_pending_queue_active) 764 if (fc->fcoe_pending_queue_active)
767 goto out; 765 goto out;
768 fc->fcoe_pending_queue_active = 1; 766 fc->fcoe_pending_queue_active = 1;
769 if (fc->fcoe_pending_queue.qlen) { 767
770 while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) { 768 while (fc->fcoe_pending_queue.qlen) {
771 spin_unlock_bh(&fc->fcoe_pending_queue.lock); 769 /* keep qlen > 0 until fcoe_start_io succeeds */
772 rc = fcoe_start_io(skb); 770 fc->fcoe_pending_queue.qlen++;
773 if (rc) 771 skb = __skb_dequeue(&fc->fcoe_pending_queue);
774 fcoe_insert_wait_queue_head(lp, skb); 772
775 spin_lock_bh(&fc->fcoe_pending_queue.lock); 773 spin_unlock_bh(&fc->fcoe_pending_queue.lock);
776 if (rc) 774 rc = fcoe_start_io(skb);
777 break; 775 spin_lock_bh(&fc->fcoe_pending_queue.lock);
776
777 if (rc) {
778 __skb_queue_head(&fc->fcoe_pending_queue, skb);
779 /* undo temporary increment above */
780 fc->fcoe_pending_queue.qlen--;
781 break;
778 } 782 }
779 /* 783 /* undo temporary increment above */
780 * if interface pending queue is below FCOE_LOW_QUEUE_DEPTH 784 fc->fcoe_pending_queue.qlen--;
781 * then clear qfull flag.
782 */
783 if (fc->fcoe_pending_queue.qlen < FCOE_LOW_QUEUE_DEPTH)
784 lp->qfull = 0;
785 } 785 }
786
787 if (fc->fcoe_pending_queue.qlen < FCOE_LOW_QUEUE_DEPTH)
788 lp->qfull = 0;
786 fc->fcoe_pending_queue_active = 0; 789 fc->fcoe_pending_queue_active = 0;
787 rc = fc->fcoe_pending_queue.qlen; 790 rc = fc->fcoe_pending_queue.qlen;
788out: 791out:
@@ -791,42 +794,6 @@ out:
791} 794}
792 795
793/** 796/**
794 * fcoe_insert_wait_queue_head() - puts skb to fcoe pending queue head
795 * @lp: the fc_port for this skb
796 * @skb: the associated skb to be xmitted
797 *
798 * Returns: none
799 */
800static void fcoe_insert_wait_queue_head(struct fc_lport *lp,
801 struct sk_buff *skb)
802{
803 struct fcoe_softc *fc;
804
805 fc = lport_priv(lp);
806 spin_lock_bh(&fc->fcoe_pending_queue.lock);
807 __skb_queue_head(&fc->fcoe_pending_queue, skb);
808 spin_unlock_bh(&fc->fcoe_pending_queue.lock);
809}
810
811/**
812 * fcoe_insert_wait_queue() - put the skb into fcoe pending queue tail
813 * @lp: the fc_port for this skb
814 * @skb: the associated skb to be xmitted
815 *
816 * Returns: none
817 */
818static void fcoe_insert_wait_queue(struct fc_lport *lp,
819 struct sk_buff *skb)
820{
821 struct fcoe_softc *fc;
822
823 fc = lport_priv(lp);
824 spin_lock_bh(&fc->fcoe_pending_queue.lock);
825 __skb_queue_tail(&fc->fcoe_pending_queue, skb);
826 spin_unlock_bh(&fc->fcoe_pending_queue.lock);
827}
828
829/**
830 * fcoe_dev_setup() - setup link change notification interface 797 * fcoe_dev_setup() - setup link change notification interface
831 */ 798 */
832static void fcoe_dev_setup() 799static void fcoe_dev_setup()