]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.31/patches.drivers/Out-of-order-tx-frames-was-causing-several-check-con.patch
Add a patch to fix Intel E100 wake-on-lan problems.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.drivers / Out-of-order-tx-frames-was-causing-several-check-con.patch
1 From 9a24511a01552376ad031ac877b62461d58f6a4d Mon Sep 17 00:00:00 2001
2 From: Vasu Dev <vasu.dev@intel.com>
3 Date: Thu, 5 Feb 2009 01:32:29 -0800
4 References: bnc#473604
5 Subject: [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
12 This was causing some test apps to exit due to write failure under heavy
13 load.
14
15 This was due to a race around adding and removing tx frame skb in
16 fcoe_pending_queue, Chris Leech helped me to find that brief unlocking
17 period 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
19 up on a failed fcoe_start_io could change skb/tx frame order in
20 fcoe_pending_queue. Thanks Chris.
21
22 This patch allows only single context to pull skb from fcoe_pending_queue
23 at any time to prevent above described ordering issue/race by use of
24 fcoe_pending_queue_active flag.
25
26 This patch simplified fcoe_watchdog with modified fcoe_check_wait_queue by
27 use of FCOE_LOW_QUEUE_DEPTH instead previously used several conditionals
28 to clear and set lp->qfull.
29
30 I think FCOE_MAX_QUEUE_DEPTH with FCOE_LOW_QUEUE_DEPTH will work better
31 in re/setting lp->qfull and these could be fine tuned for performance.
32
33 Signed-off-by: Vasu Dev <vasu.dev@intel.com>
34 Acked-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
41 diff --git a/drivers/scsi/fcoe/fcoe_sw.c b/drivers/scsi/fcoe/fcoe_sw.c
42 index 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,
53 diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c
54 index 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 /**
150 diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h
151 index 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 --
163 1.5.4.5
164