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
5 Subject: [PATCH] Out of order tx frames was causing several check condition SCSI status
6 frames followed by these errors in log.
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
12 This was causing some test apps to exit due to write failure under heavy
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.
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.
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.
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.
33 Signed-off-by: Vasu Dev <vasu.dev@intel.com>
34 Acked-by: John Jolly <jjolly@suse.de>
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(-)
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)
48 skb_queue_head_init(&fc->fcoe_pending_queue);
49 + fc->fcoe_pending_queue_active = 0;
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
58 static int debug_fcoe;
60 #define FCOE_MAX_QUEUE_DEPTH 256
61 +#define FCOE_LOW_QUEUE_DEPTH 32
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)
67 void fcoe_watchdog(ulong vp)
69 - struct fc_lport *lp;
70 struct fcoe_softc *fc;
73 read_lock(&fcoe_hostlist_lock);
74 list_for_each_entry(fc, &fcoe_hostlist, list) {
77 - if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
79 - if (fcoe_check_wait_queue(lp) < FCOE_MAX_QUEUE_DEPTH) {
85 + fcoe_check_wait_queue(fc->lp);
87 read_unlock(&fcoe_hostlist_lock);
89 @@ -757,8 +749,8 @@ void fcoe_watchdog(ulong vp)
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
95 + * transmitted, return qlen or -1 if a error occurs, then restore
96 + * wait_queue and try again later.
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)
102 static int fcoe_check_wait_queue(struct fc_lport *lp)
106 struct fcoe_softc *fc;
110 spin_lock_bh(&fc->fcoe_pending_queue.lock);
113 - * if interface pending queue full then set qfull in lport.
115 - if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
117 + if (fc->fcoe_pending_queue_active)
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);
126 fcoe_insert_wait_queue_head(lp, skb);
129 spin_lock_bh(&fc->fcoe_pending_queue.lock);
133 - if (fc->fcoe_pending_queue.qlen < FCOE_MAX_QUEUE_DEPTH)
135 + * if interface pending queue is below FCOE_LOW_QUEUE_DEPTH
136 + * then clear qfull flag.
138 + if (fc->fcoe_pending_queue.qlen < FCOE_LOW_QUEUE_DEPTH)
141 + fc->fcoe_pending_queue_active = 0;
142 + rc = fc->fcoe_pending_queue.qlen;
144 spin_unlock_bh(&fc->fcoe_pending_queue.lock);
145 - return fc->fcoe_pending_queue.qlen;
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;
160 u8 dest_addr[ETH_ALEN];
161 u8 ctl_src_addr[ETH_ALEN];