]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - 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
CommitLineData
2cb7cef9
BS
1From 9a24511a01552376ad031ac877b62461d58f6a4d Mon Sep 17 00:00:00 2001
2From: Vasu Dev <vasu.dev@intel.com>
3Date: Thu, 5 Feb 2009 01:32:29 -0800
4References: bnc#473604
5Subject: [PATCH] Out of order tx frames was causing several check condition SCSI status
6 frames followed by these errors in log.
7
8 [sdp] Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE,SUGGEST_OK
9 [sdp] Sense Key : Aborted Command [current]
10 [sdp] Add. Sense: Data phase error
11
12This was causing some test apps to exit due to write failure under heavy
13load.
14
15This was due to a race around adding and removing tx frame skb in
16fcoe_pending_queue, Chris Leech helped me to find that brief unlocking
17period when pulling skb from fcoe_pending_queue in various contexts
18(fcoe_watchdog and fcoe_xmit) and then adding skb back into fcoe_pending_queue
19up on a failed fcoe_start_io could change skb/tx frame order in
20fcoe_pending_queue. Thanks Chris.
21
22This patch allows only single context to pull skb from fcoe_pending_queue
23at any time to prevent above described ordering issue/race by use of
24fcoe_pending_queue_active flag.
25
26This patch simplified fcoe_watchdog with modified fcoe_check_wait_queue by
27use of FCOE_LOW_QUEUE_DEPTH instead previously used several conditionals
28to clear and set lp->qfull.
29
30I think FCOE_MAX_QUEUE_DEPTH with FCOE_LOW_QUEUE_DEPTH will work better
31in re/setting lp->qfull and these could be fine tuned for performance.
32
33Signed-off-by: Vasu Dev <vasu.dev@intel.com>
34Acked-by: John Jolly <jjolly@suse.de>
35---
36 drivers/scsi/fcoe/fcoe_sw.c | 1 +
37 drivers/scsi/fcoe/libfcoe.c | 45 ++++++++++++++++++++----------------------
38 include/scsi/libfcoe.h | 1 +
39 3 files changed, 23 insertions(+), 24 deletions(-)
40
41diff --git a/drivers/scsi/fcoe/fcoe_sw.c b/drivers/scsi/fcoe/fcoe_sw.c
42index cf83675..da12c93 100644
43--- a/drivers/scsi/fcoe/fcoe_sw.c
44+++ b/drivers/scsi/fcoe/fcoe_sw.c
45@@ -191,6 +191,7 @@ static int fcoe_sw_netdev_config(struct fc_lport *lp, struct net_device *netdev)
46
47
48 skb_queue_head_init(&fc->fcoe_pending_queue);
49+ fc->fcoe_pending_queue_active = 0;
50
51 /* setup Source Mac Address */
52 memcpy(fc->ctl_src_addr, fc->real_dev->dev_addr,
53diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c
54index 8bc8078..9f8204b 100644
55--- a/drivers/scsi/fcoe/libfcoe.c
56+++ b/drivers/scsi/fcoe/libfcoe.c
57@@ -49,6 +49,7 @@
58 static int debug_fcoe;
59
60 #define FCOE_MAX_QUEUE_DEPTH 256
61+#define FCOE_LOW_QUEUE_DEPTH 32
62
63 /* destination address mode */
64 #define FCOE_GW_ADDR_MODE 0x00
65@@ -727,21 +728,12 @@ static void fcoe_recv_flogi(struct fcoe_softc *fc, struct fc_frame *fp, u8 *sa)
66 **/
67 void fcoe_watchdog(ulong vp)
68 {
69- struct fc_lport *lp;
70 struct fcoe_softc *fc;
71- int qfilled = 0;
72
73 read_lock(&fcoe_hostlist_lock);
74 list_for_each_entry(fc, &fcoe_hostlist, list) {
75- lp = fc->lp;
76- if (lp) {
77- if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
78- qfilled = 1;
79- if (fcoe_check_wait_queue(lp) < FCOE_MAX_QUEUE_DEPTH) {
80- if (qfilled)
81- lp->qfull = 0;
82- }
83- }
84+ if (fc->lp)
85+ fcoe_check_wait_queue(fc->lp);
86 }
87 read_unlock(&fcoe_hostlist_lock);
88
89@@ -757,8 +749,8 @@ void fcoe_watchdog(ulong vp)
90 *
91 * This empties the wait_queue, dequeue the head of the wait_queue queue
92 * and calls fcoe_start_io() for each packet, if all skb have been
93- * transmitted, return 0 if a error occurs, then restore wait_queue and
94- * try again later.
95+ * transmitted, return qlen or -1 if a error occurs, then restore
96+ * wait_queue and try again later.
97 *
98 * The wait_queue is used when the skb transmit fails. skb will go
99 * in the wait_queue which will be emptied by the time function OR
100@@ -768,33 +760,38 @@ void fcoe_watchdog(ulong vp)
101 **/
102 static int fcoe_check_wait_queue(struct fc_lport *lp)
103 {
104- int rc;
105 struct sk_buff *skb;
106 struct fcoe_softc *fc;
107+ int rc = -1;
108
109 fc = fcoe_softc(lp);
110 spin_lock_bh(&fc->fcoe_pending_queue.lock);
111
112- /*
113- * if interface pending queue full then set qfull in lport.
114- */
115- if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
116- lp->qfull = 1;
117+ if (fc->fcoe_pending_queue_active)
118+ goto out;
119+ fc->fcoe_pending_queue_active = 1;
120 if (fc->fcoe_pending_queue.qlen) {
121 while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) {
122 spin_unlock_bh(&fc->fcoe_pending_queue.lock);
123 rc = fcoe_start_io(skb);
124- if (rc) {
125+ if (rc)
126 fcoe_insert_wait_queue_head(lp, skb);
127- return rc;
128- }
129 spin_lock_bh(&fc->fcoe_pending_queue.lock);
130+ if (rc)
131+ break;
132 }
133- if (fc->fcoe_pending_queue.qlen < FCOE_MAX_QUEUE_DEPTH)
134+ /*
135+ * if interface pending queue is below FCOE_LOW_QUEUE_DEPTH
136+ * then clear qfull flag.
137+ */
138+ if (fc->fcoe_pending_queue.qlen < FCOE_LOW_QUEUE_DEPTH)
139 lp->qfull = 0;
140 }
141+ fc->fcoe_pending_queue_active = 0;
142+ rc = fc->fcoe_pending_queue.qlen;
143+out:
144 spin_unlock_bh(&fc->fcoe_pending_queue.lock);
145- return fc->fcoe_pending_queue.qlen;
146+ return rc;
147 }
148
149 /**
150diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h
151index 89fdbb9..ab09986 100644
152--- a/include/scsi/libfcoe.h
153+++ b/include/scsi/libfcoe.h
154@@ -46,6 +46,7 @@ struct fcoe_softc {
155 struct net_device *phys_dev; /* device with ethtool_ops */
156 struct packet_type fcoe_packet_type;
157 struct sk_buff_head fcoe_pending_queue;
158+ u8 fcoe_pending_queue_active;
159
160 u8 dest_addr[ETH_ALEN];
161 u8 ctl_src_addr[ETH_ALEN];
162--
1631.5.4.5
164