]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
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 |