]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.39/patches.drivers/Out-of-order-tx-frames-was-causing-several-check-con.patch
Imported linux-2.6.27.39 suse/xen patches.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.drivers / Out-of-order-tx-frames-was-causing-several-check-con.patch
diff --git a/src/patches/suse-2.6.27.39/patches.drivers/Out-of-order-tx-frames-was-causing-several-check-con.patch b/src/patches/suse-2.6.27.39/patches.drivers/Out-of-order-tx-frames-was-causing-several-check-con.patch
new file mode 100644 (file)
index 0000000..a77a045
--- /dev/null
@@ -0,0 +1,164 @@
+From 9a24511a01552376ad031ac877b62461d58f6a4d Mon Sep 17 00:00:00 2001
+From: Vasu Dev <vasu.dev@intel.com>
+Date: Thu, 5 Feb 2009 01:32:29 -0800
+References: bnc#473604
+Subject: [PATCH] Out of order tx frames was causing several check condition SCSI status
+ frames followed by these errors in log.
+
+       [sdp] Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE,SUGGEST_OK
+       [sdp] Sense Key : Aborted Command [current]
+       [sdp] Add. Sense: Data phase error
+
+This was causing some test apps to exit due to write failure under heavy
+load.
+
+This was due to a race around adding and removing tx frame skb in
+fcoe_pending_queue, Chris Leech helped me to find that brief unlocking
+period when pulling skb from fcoe_pending_queue in various contexts
+(fcoe_watchdog and fcoe_xmit) and then adding skb back into fcoe_pending_queue
+up on a failed fcoe_start_io could change skb/tx frame order in
+fcoe_pending_queue. Thanks Chris.
+
+This patch allows only single context to pull skb from fcoe_pending_queue
+at any time to prevent above described ordering issue/race by use of
+fcoe_pending_queue_active flag.
+
+This patch simplified fcoe_watchdog with modified fcoe_check_wait_queue by
+use of FCOE_LOW_QUEUE_DEPTH instead previously used several conditionals
+to clear and set lp->qfull.
+
+I think FCOE_MAX_QUEUE_DEPTH with FCOE_LOW_QUEUE_DEPTH  will work better
+in re/setting lp->qfull and these could be fine tuned for performance.
+
+Signed-off-by: Vasu Dev <vasu.dev@intel.com>
+Acked-by: John Jolly <jjolly@suse.de>
+---
+ drivers/scsi/fcoe/fcoe_sw.c |    1 +
+ drivers/scsi/fcoe/libfcoe.c |   45 ++++++++++++++++++++----------------------
+ include/scsi/libfcoe.h      |    1 +
+ 3 files changed, 23 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/scsi/fcoe/fcoe_sw.c b/drivers/scsi/fcoe/fcoe_sw.c
+index cf83675..da12c93 100644
+--- a/drivers/scsi/fcoe/fcoe_sw.c
++++ b/drivers/scsi/fcoe/fcoe_sw.c
+@@ -191,6 +191,7 @@ static int fcoe_sw_netdev_config(struct fc_lport *lp, struct net_device *netdev)
+       skb_queue_head_init(&fc->fcoe_pending_queue);
++      fc->fcoe_pending_queue_active = 0;
+       /* setup Source Mac Address */
+       memcpy(fc->ctl_src_addr, fc->real_dev->dev_addr,
+diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c
+index 8bc8078..9f8204b 100644
+--- a/drivers/scsi/fcoe/libfcoe.c
++++ b/drivers/scsi/fcoe/libfcoe.c
+@@ -49,6 +49,7 @@
+ static int debug_fcoe;
+ #define FCOE_MAX_QUEUE_DEPTH  256
++#define FCOE_LOW_QUEUE_DEPTH  32
+ /* destination address mode */
+ #define FCOE_GW_ADDR_MODE         0x00
+@@ -727,21 +728,12 @@ static void fcoe_recv_flogi(struct fcoe_softc *fc, struct fc_frame *fp, u8 *sa)
+  **/
+ void fcoe_watchdog(ulong vp)
+ {
+-      struct fc_lport *lp;
+       struct fcoe_softc *fc;
+-      int qfilled = 0;
+       read_lock(&fcoe_hostlist_lock);
+       list_for_each_entry(fc, &fcoe_hostlist, list) {
+-              lp = fc->lp;
+-              if (lp) {
+-                      if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
+-                              qfilled = 1;
+-                      if (fcoe_check_wait_queue(lp) <  FCOE_MAX_QUEUE_DEPTH) {
+-                              if (qfilled)
+-                                      lp->qfull = 0;
+-                      }
+-              }
++              if (fc->lp)
++                      fcoe_check_wait_queue(fc->lp);
+       }
+       read_unlock(&fcoe_hostlist_lock);
+@@ -757,8 +749,8 @@ void fcoe_watchdog(ulong vp)
+  *
+  * This empties the wait_queue, dequeue the head of the wait_queue queue
+  * and calls fcoe_start_io() for each packet, if all skb have been
+- * transmitted, return 0 if a error occurs, then restore wait_queue and
+- * try again later.
++ * transmitted, return qlen or -1 if a error occurs, then restore
++ * wait_queue and  try again later.
+  *
+  * The wait_queue is used when the skb transmit fails. skb will go
+  * in the wait_queue which will be emptied by the time function OR
+@@ -768,33 +760,38 @@ void fcoe_watchdog(ulong vp)
+  **/
+ static int fcoe_check_wait_queue(struct fc_lport *lp)
+ {
+-      int rc;
+       struct sk_buff *skb;
+       struct fcoe_softc *fc;
++      int rc = -1;
+       fc = fcoe_softc(lp);
+       spin_lock_bh(&fc->fcoe_pending_queue.lock);
+-      /*
+-       * if interface pending queue full then set qfull in lport.
+-       */
+-      if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
+-              lp->qfull = 1;
++      if (fc->fcoe_pending_queue_active)
++              goto out;
++      fc->fcoe_pending_queue_active = 1;
+       if (fc->fcoe_pending_queue.qlen) {
+               while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) {
+                       spin_unlock_bh(&fc->fcoe_pending_queue.lock);
+                       rc = fcoe_start_io(skb);
+-                      if (rc) {
++                      if (rc)
+                               fcoe_insert_wait_queue_head(lp, skb);
+-                              return rc;
+-                      }
+                       spin_lock_bh(&fc->fcoe_pending_queue.lock);
++                      if (rc)
++                              break;
+               }
+-              if (fc->fcoe_pending_queue.qlen < FCOE_MAX_QUEUE_DEPTH)
++              /*
++               * if interface pending queue is below FCOE_LOW_QUEUE_DEPTH
++               * then clear qfull flag.
++               */
++              if (fc->fcoe_pending_queue.qlen < FCOE_LOW_QUEUE_DEPTH)
+                       lp->qfull = 0;
+       }
++      fc->fcoe_pending_queue_active = 0;
++      rc = fc->fcoe_pending_queue.qlen;
++out:
+       spin_unlock_bh(&fc->fcoe_pending_queue.lock);
+-      return fc->fcoe_pending_queue.qlen;
++      return rc;
+ }
+ /**
+diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h
+index 89fdbb9..ab09986 100644
+--- a/include/scsi/libfcoe.h
++++ b/include/scsi/libfcoe.h
+@@ -46,6 +46,7 @@ struct fcoe_softc {
+       struct net_device *phys_dev;            /* device with ethtool_ops */
+       struct packet_type  fcoe_packet_type;
+       struct sk_buff_head fcoe_pending_queue;
++      u8      fcoe_pending_queue_active;
+       u8 dest_addr[ETH_ALEN];
+       u8 ctl_src_addr[ETH_ALEN];
+-- 
+1.5.4.5
+