[SCSI] fcoe: Out of order tx frames was causing several check condition SCSI status
[linux-2.6] / drivers / staging / benet / be_ethtool.c
1 /*
2  * Copyright (C) 2005 - 2008 ServerEngines
3  * All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License version 2
7  * as published by the Free Software Foundation.  The full GNU General
8  * Public License is included in this distribution in the file called COPYING.
9  *
10  * Contact Information:
11  * linux-drivers@serverengines.com
12  *
13  * ServerEngines
14  * 209 N. Fair Oaks Ave
15  * Sunnyvale, CA 94085
16  */
17 /*
18  * be_ethtool.c
19  *
20  *      This file contains various functions that ethtool can use
21  *      to talk to the driver and the BE H/W.
22  */
23
24 #include "benet.h"
25
26 #include <linux/ethtool.h>
27
28 static const char benet_gstrings_stats[][ETH_GSTRING_LEN] = {
29 /* net_device_stats */
30         "rx_packets",
31         "tx_packets",
32         "rx_bytes",
33         "tx_bytes",
34         "rx_errors",
35         "tx_errors",
36         "rx_dropped",
37         "tx_dropped",
38         "multicast",
39         "collisions",
40         "rx_length_errors",
41         "rx_over_errors",
42         "rx_crc_errors",
43         "rx_frame_errors",
44         "rx_fifo_errors",
45         "rx_missed_errors",
46         "tx_aborted_errors",
47         "tx_carrier_errors",
48         "tx_fifo_errors",
49         "tx_heartbeat_errors",
50         "tx_window_errors",
51         "rx_compressed",
52         "tc_compressed",
53 /* BE driver Stats */
54         "bes_tx_reqs",
55         "bes_tx_fails",
56         "bes_fwd_reqs",
57         "bes_tx_wrbs",
58         "bes_interrupts",
59         "bes_events",
60         "bes_tx_events",
61         "bes_rx_events",
62         "bes_tx_compl",
63         "bes_rx_compl",
64         "bes_ethrx_post_fail",
65         "bes_802_3_dropped_frames",
66         "bes_802_3_malformed_frames",
67         "bes_rx_misc_pkts",
68         "bes_eth_tx_rate",
69         "bes_eth_rx_rate",
70         "Num Packets collected",
71         "Num Times Flushed",
72 };
73
74 #define NET_DEV_STATS_LEN \
75         (sizeof(struct net_device_stats)/sizeof(unsigned long))
76
77 #define BENET_STATS_LEN  ARRAY_SIZE(benet_gstrings_stats)
78
79 static void
80 be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
81 {
82         struct be_net_object *pnob = netdev_priv(netdev);
83         struct be_adapter *adapter = pnob->adapter;
84
85         strncpy(drvinfo->driver, be_driver_name, 32);
86         strncpy(drvinfo->version, be_drvr_ver, 32);
87         strncpy(drvinfo->fw_version, be_fw_ver, 32);
88         strcpy(drvinfo->bus_info, pci_name(adapter->pdev));
89         drvinfo->testinfo_len = 0;
90         drvinfo->regdump_len = 0;
91         drvinfo->eedump_len = 0;
92 }
93
94 static int
95 be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
96 {
97         struct be_net_object *pnob = netdev_priv(netdev);
98         struct be_adapter *adapter = pnob->adapter;
99
100         coalesce->rx_max_coalesced_frames = adapter->max_rx_coal;
101
102         coalesce->rx_coalesce_usecs = adapter->cur_eqd;
103         coalesce->rx_coalesce_usecs_high = adapter->max_eqd;
104         coalesce->rx_coalesce_usecs_low = adapter->min_eqd;
105
106         coalesce->tx_coalesce_usecs = adapter->cur_eqd;
107         coalesce->tx_coalesce_usecs_high = adapter->max_eqd;
108         coalesce->tx_coalesce_usecs_low = adapter->min_eqd;
109
110         coalesce->use_adaptive_rx_coalesce = adapter->enable_aic;
111         coalesce->use_adaptive_tx_coalesce = adapter->enable_aic;
112
113         return 0;
114 }
115
116 /*
117  * This routine is used to set interrup coalescing delay *as well as*
118  * the number of pkts to coalesce for LRO.
119  */
120 static int
121 be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
122 {
123         struct be_net_object *pnob = netdev_priv(netdev);
124         struct be_adapter *adapter = pnob->adapter;
125         struct be_eq_object *eq_objectp;
126         u32 max, min, cur;
127         int status;
128
129         adapter->max_rx_coal = coalesce->rx_max_coalesced_frames;
130         if (adapter->max_rx_coal >= BE_LRO_MAX_PKTS)
131                 adapter->max_rx_coal = BE_LRO_MAX_PKTS;
132
133         if (adapter->enable_aic == 0 &&
134                 coalesce->use_adaptive_rx_coalesce == 1) {
135                 /* if AIC is being turned on now, start with an EQD of 0 */
136                 adapter->cur_eqd = 0;
137         }
138         adapter->enable_aic = coalesce->use_adaptive_rx_coalesce;
139
140         /* round off to nearest multiple of 8 */
141         max = (((coalesce->rx_coalesce_usecs_high + 4) >> 3) << 3);
142         min = (((coalesce->rx_coalesce_usecs_low + 4) >> 3) << 3);
143         cur = (((coalesce->rx_coalesce_usecs + 4) >> 3) << 3);
144
145         if (adapter->enable_aic) {
146                 /* accept low and high if AIC is enabled */
147                 if (max > MAX_EQD)
148                         max = MAX_EQD;
149                 if (min > max)
150                         min = max;
151                 adapter->max_eqd = max;
152                 adapter->min_eqd = min;
153                 if (adapter->cur_eqd > max)
154                         adapter->cur_eqd = max;
155                 if (adapter->cur_eqd < min)
156                         adapter->cur_eqd = min;
157         } else {
158                 /* accept specified coalesce_usecs only if AIC is disabled */
159                 if (cur > MAX_EQD)
160                         cur = MAX_EQD;
161                 eq_objectp = &pnob->event_q_obj;
162                 status =
163                     be_eq_modify_delay(&pnob->fn_obj, 1, &eq_objectp, &cur,
164                                        NULL, NULL, NULL);
165                 if (status == BE_SUCCESS)
166                         adapter->cur_eqd = cur;
167         }
168         return 0;
169 }
170
171 static u32 be_get_rx_csum(struct net_device *netdev)
172 {
173         struct be_net_object *pnob = netdev_priv(netdev);
174         struct be_adapter *adapter = pnob->adapter;
175         return adapter->rx_csum;
176 }
177
178 static int be_set_rx_csum(struct net_device *netdev, uint32_t data)
179 {
180         struct be_net_object *pnob = netdev_priv(netdev);
181         struct be_adapter *adapter = pnob->adapter;
182
183         if (data)
184                 adapter->rx_csum = 1;
185         else
186                 adapter->rx_csum = 0;
187
188         return 0;
189 }
190
191 static void
192 be_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data)
193 {
194         switch (stringset) {
195         case ETH_SS_STATS:
196                 memcpy(data, *benet_gstrings_stats,
197                        sizeof(benet_gstrings_stats));
198                 break;
199         }
200 }
201
202 static int be_get_stats_count(struct net_device *netdev)
203 {
204         return BENET_STATS_LEN;
205 }
206
207 static void
208 be_get_ethtool_stats(struct net_device *netdev,
209                      struct ethtool_stats *stats, uint64_t *data)
210 {
211         struct be_net_object *pnob = netdev_priv(netdev);
212         struct be_adapter *adapter = pnob->adapter;
213         int i;
214
215         benet_get_stats(netdev);
216
217         for (i = 0; i <= NET_DEV_STATS_LEN; i++)
218                 data[i] = ((unsigned long *)&adapter->benet_stats)[i];
219
220         data[i] = adapter->be_stat.bes_tx_reqs;
221         data[i++] = adapter->be_stat.bes_tx_fails;
222         data[i++] = adapter->be_stat.bes_fwd_reqs;
223         data[i++] = adapter->be_stat.bes_tx_wrbs;
224
225         data[i++] = adapter->be_stat.bes_ints;
226         data[i++] = adapter->be_stat.bes_events;
227         data[i++] = adapter->be_stat.bes_tx_events;
228         data[i++] = adapter->be_stat.bes_rx_events;
229         data[i++] = adapter->be_stat.bes_tx_compl;
230         data[i++] = adapter->be_stat.bes_rx_compl;
231         data[i++] = adapter->be_stat.bes_ethrx_post_fail;
232         data[i++] = adapter->be_stat.bes_802_3_dropped_frames;
233         data[i++] = adapter->be_stat.bes_802_3_malformed_frames;
234         data[i++] = adapter->be_stat.bes_rx_misc_pkts;
235         data[i++] = adapter->be_stat.bes_eth_tx_rate;
236         data[i++] = adapter->be_stat.bes_eth_rx_rate;
237         data[i++] = adapter->be_stat.bes_rx_coal;
238         data[i++] = adapter->be_stat.bes_rx_flush;
239
240 }
241
242 static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
243 {
244         ecmd->speed = SPEED_10000;
245         ecmd->duplex = DUPLEX_FULL;
246         ecmd->autoneg = AUTONEG_DISABLE;
247         return 0;
248 }
249
250 /* Get the Ring parameters from the pnob */
251 static void
252 be_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
253 {
254         struct be_net_object *pnob = netdev_priv(netdev);
255
256         /* Pre Set Maxims */
257         ring->rx_max_pending = pnob->rx_q_len;
258         ring->rx_mini_max_pending = ring->rx_mini_max_pending;
259         ring->rx_jumbo_max_pending = ring->rx_jumbo_max_pending;
260         ring->tx_max_pending = pnob->tx_q_len;
261
262         /* Current hardware Settings                */
263         ring->rx_pending = atomic_read(&pnob->rx_q_posted);
264         ring->rx_mini_pending = ring->rx_mini_pending;
265         ring->rx_jumbo_pending = ring->rx_jumbo_pending;
266         ring->tx_pending = atomic_read(&pnob->tx_q_used);
267
268 }
269
270 static void
271 be_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
272 {
273         struct be_net_object *pnob = netdev_priv(netdev);
274         bool rxfc, txfc;
275         int status;
276
277         status = be_eth_get_flow_control(&pnob->fn_obj, &txfc, &rxfc);
278         if (status != BE_SUCCESS) {
279                 dev_info(&netdev->dev, "Unable to get pause frame settings\n");
280                 /* return defaults */
281                 ecmd->rx_pause = 1;
282                 ecmd->tx_pause = 0;
283                 ecmd->autoneg = AUTONEG_ENABLE;
284                 return;
285         }
286
287         if (txfc == true)
288                 ecmd->tx_pause = 1;
289         else
290                 ecmd->tx_pause = 0;
291
292         if (rxfc == true)
293                 ecmd->rx_pause = 1;
294         else
295                 ecmd->rx_pause = 0;
296
297         ecmd->autoneg = AUTONEG_ENABLE;
298 }
299
300 static int
301 be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
302 {
303         struct be_net_object *pnob = netdev_priv(netdev);
304         bool txfc, rxfc;
305         int status;
306
307         if (ecmd->autoneg != AUTONEG_ENABLE)
308                 return -EINVAL;
309
310         if (ecmd->tx_pause)
311                 txfc = true;
312         else
313                 txfc = false;
314
315         if (ecmd->rx_pause)
316                 rxfc = true;
317         else
318                 rxfc = false;
319
320         status = be_eth_set_flow_control(&pnob->fn_obj, txfc, rxfc);
321         if (status != BE_SUCCESS) {
322                 dev_info(&netdev->dev, "Unable to set pause frame settings\n");
323                 return -1;
324         }
325         return 0;
326 }
327
328 struct ethtool_ops be_ethtool_ops = {
329         .get_settings = be_get_settings,
330         .get_drvinfo = be_get_drvinfo,
331         .get_link = ethtool_op_get_link,
332         .get_coalesce = be_get_coalesce,
333         .set_coalesce = be_set_coalesce,
334         .get_ringparam = be_get_ringparam,
335         .get_pauseparam = be_get_pauseparam,
336         .set_pauseparam = be_set_pauseparam,
337         .get_rx_csum = be_get_rx_csum,
338         .set_rx_csum = be_set_rx_csum,
339         .get_tx_csum = ethtool_op_get_tx_csum,
340         .set_tx_csum = ethtool_op_set_tx_csum,
341         .get_sg = ethtool_op_get_sg,
342         .set_sg = ethtool_op_set_sg,
343         .get_tso = ethtool_op_get_tso,
344         .set_tso = ethtool_op_set_tso,
345         .get_strings = be_get_strings,
346         .get_stats_count = be_get_stats_count,
347         .get_ethtool_stats = be_get_ethtool_stats,
348 };