aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2012-01-04 07:12:28 -0500
committerDavid S. Miller <davem@davemloft.net>2012-01-05 14:01:21 -0500
commit23021c21055f88a428b6deb6f803fa0d659e023f (patch)
treeb4f68704f88dc918d411662dd18c3e6c5b51d313 /drivers/net
parenta9e0a4f2ca5e97ae2cff0bda72b9645e047c1a3d (diff)
cnic: Improve error recovery on bnx2x devices
When a bnx2x device encounters parity errors, it will not respond to all SPQ messages. As a result, the shutdown sequence before reset can take a long time as the ulp drivers (bnx2i/bnx2fc) have to wait for timeout of all such messages. To improve this scenario, when bnx2x returns error on the SPQ, we'll send an immediate response to the ulp drivers to avoid such lengthy timeouts. Adjust the return code of relevant functions to return error only if the message cannot be sent on the SPQ so that we'll generate an error completion to the ulp drivers. Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/broadcom/cnic.c74
-rw-r--r--drivers/net/ethernet/broadcom/cnic_defs.h1
-rw-r--r--drivers/net/ethernet/broadcom/cnic_if.h7
3 files changed, 74 insertions, 8 deletions
diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c
index 567cb04fc8fd..dd3a0a232ea0 100644
--- a/drivers/net/ethernet/broadcom/cnic.c
+++ b/drivers/net/ethernet/broadcom/cnic.c
@@ -1361,7 +1361,7 @@ static int cnic_submit_kwqe_16(struct cnic_dev *dev, u32 cmd, u32 cid,
1361 if (ret == 1) 1361 if (ret == 1)
1362 return 0; 1362 return 0;
1363 1363
1364 return -EBUSY; 1364 return ret;
1365} 1365}
1366 1366
1367static void cnic_reply_bnx2x_kcqes(struct cnic_dev *dev, int ulp_type, 1367static void cnic_reply_bnx2x_kcqes(struct cnic_dev *dev, int ulp_type,
@@ -1849,7 +1849,7 @@ static int cnic_bnx2x_iscsi_ofld1(struct cnic_dev *dev, struct kwqe *wqes[],
1849done: 1849done:
1850 cqes[0] = (struct kcqe *) &kcqe; 1850 cqes[0] = (struct kcqe *) &kcqe;
1851 cnic_reply_bnx2x_kcqes(dev, CNIC_ULP_ISCSI, cqes, 1); 1851 cnic_reply_bnx2x_kcqes(dev, CNIC_ULP_ISCSI, cqes, 1);
1852 return ret; 1852 return 0;
1853} 1853}
1854 1854
1855 1855
@@ -1947,7 +1947,7 @@ destroy_reply:
1947 cqes[0] = (struct kcqe *) &kcqe; 1947 cqes[0] = (struct kcqe *) &kcqe;
1948 cnic_reply_bnx2x_kcqes(dev, CNIC_ULP_ISCSI, cqes, 1); 1948 cnic_reply_bnx2x_kcqes(dev, CNIC_ULP_ISCSI, cqes, 1);
1949 1949
1950 return ret; 1950 return 0;
1951} 1951}
1952 1952
1953static void cnic_init_storm_conn_bufs(struct cnic_dev *dev, 1953static void cnic_init_storm_conn_bufs(struct cnic_dev *dev,
@@ -2513,6 +2513,57 @@ static int cnic_bnx2x_fcoe_fw_destroy(struct cnic_dev *dev, struct kwqe *kwqe)
2513 return ret; 2513 return ret;
2514} 2514}
2515 2515
2516static void cnic_bnx2x_kwqe_err(struct cnic_dev *dev, struct kwqe *kwqe)
2517{
2518 struct cnic_local *cp = dev->cnic_priv;
2519 struct kcqe kcqe;
2520 struct kcqe *cqes[1];
2521 u32 cid;
2522 u32 opcode = KWQE_OPCODE(kwqe->kwqe_op_flag);
2523 u32 layer_code = kwqe->kwqe_op_flag & KWQE_LAYER_MASK;
2524 int ulp_type;
2525
2526 cid = kwqe->kwqe_info0;
2527 memset(&kcqe, 0, sizeof(kcqe));
2528
2529 if (layer_code == KWQE_FLAGS_LAYER_MASK_L5_ISCSI) {
2530 ulp_type = CNIC_ULP_ISCSI;
2531 if (opcode == ISCSI_KWQE_OPCODE_UPDATE_CONN)
2532 cid = kwqe->kwqe_info1;
2533
2534 kcqe.kcqe_op_flag = (opcode + 0x10) << KCQE_FLAGS_OPCODE_SHIFT;
2535 kcqe.kcqe_op_flag |= KCQE_FLAGS_LAYER_MASK_L5_ISCSI;
2536 kcqe.kcqe_info1 = ISCSI_KCQE_COMPLETION_STATUS_NIC_ERROR;
2537 kcqe.kcqe_info2 = cid;
2538 cnic_get_l5_cid(cp, BNX2X_SW_CID(cid), &kcqe.kcqe_info0);
2539
2540 } else if (layer_code == KWQE_FLAGS_LAYER_MASK_L4) {
2541 struct l4_kcq *l4kcqe = (struct l4_kcq *) &kcqe;
2542 u32 kcqe_op;
2543
2544 ulp_type = CNIC_ULP_L4;
2545 if (opcode == L4_KWQE_OPCODE_VALUE_CONNECT1)
2546 kcqe_op = L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE;
2547 else if (opcode == L4_KWQE_OPCODE_VALUE_RESET)
2548 kcqe_op = L4_KCQE_OPCODE_VALUE_RESET_COMP;
2549 else if (opcode == L4_KWQE_OPCODE_VALUE_CLOSE)
2550 kcqe_op = L4_KCQE_OPCODE_VALUE_CLOSE_COMP;
2551 else
2552 return;
2553
2554 kcqe.kcqe_op_flag = (kcqe_op << KCQE_FLAGS_OPCODE_SHIFT) |
2555 KCQE_FLAGS_LAYER_MASK_L4;
2556 l4kcqe->status = L4_KCQE_COMPLETION_STATUS_NIC_ERROR;
2557 l4kcqe->cid = cid;
2558 cnic_get_l5_cid(cp, BNX2X_SW_CID(cid), &l4kcqe->conn_id);
2559 } else {
2560 return;
2561 }
2562
2563 cqes[0] = (struct kcqe *) &kcqe;
2564 cnic_reply_bnx2x_kcqes(dev, ulp_type, cqes, 1);
2565}
2566
2516static int cnic_submit_bnx2x_iscsi_kwqes(struct cnic_dev *dev, 2567static int cnic_submit_bnx2x_iscsi_kwqes(struct cnic_dev *dev,
2517 struct kwqe *wqes[], u32 num_wqes) 2568 struct kwqe *wqes[], u32 num_wqes)
2518{ 2569{
@@ -2570,9 +2621,17 @@ static int cnic_submit_bnx2x_iscsi_kwqes(struct cnic_dev *dev,
2570 opcode); 2621 opcode);
2571 break; 2622 break;
2572 } 2623 }
2573 if (ret < 0) 2624 if (ret < 0) {
2574 netdev_err(dev->netdev, "KWQE(0x%x) failed\n", 2625 netdev_err(dev->netdev, "KWQE(0x%x) failed\n",
2575 opcode); 2626 opcode);
2627
2628 /* Possibly bnx2x parity error, send completion
2629 * to ulp drivers with error code to speed up
2630 * cleanup and reset recovery.
2631 */
2632 if (ret == -EIO || ret == -EAGAIN)
2633 cnic_bnx2x_kwqe_err(dev, kwqe);
2634 }
2576 i += work; 2635 i += work;
2577 } 2636 }
2578 return 0; 2637 return 0;
@@ -3849,6 +3908,9 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
3849 case L4_KCQE_OPCODE_VALUE_RESET_COMP: 3908 case L4_KCQE_OPCODE_VALUE_RESET_COMP:
3850 case L5CM_RAMROD_CMD_ID_SEARCHER_DELETE: 3909 case L5CM_RAMROD_CMD_ID_SEARCHER_DELETE:
3851 case L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD: 3910 case L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD:
3911 if (l4kcqe->status == L4_KCQE_COMPLETION_STATUS_NIC_ERROR)
3912 set_bit(SK_F_HW_ERR, &csk->flags);
3913
3852 cp->close_conn(csk, opcode); 3914 cp->close_conn(csk, opcode);
3853 break; 3915 break;
3854 3916
@@ -3976,7 +4038,9 @@ static void cnic_close_bnx2x_conn(struct cnic_sock *csk, u32 opcode)
3976 case L4_KCQE_OPCODE_VALUE_CLOSE_COMP: 4038 case L4_KCQE_OPCODE_VALUE_CLOSE_COMP:
3977 case L4_KCQE_OPCODE_VALUE_RESET_COMP: 4039 case L4_KCQE_OPCODE_VALUE_RESET_COMP:
3978 if (cnic_ready_to_close(csk, opcode)) { 4040 if (cnic_ready_to_close(csk, opcode)) {
3979 if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags)) 4041 if (test_bit(SK_F_HW_ERR, &csk->flags))
4042 close_complete = 1;
4043 else if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags))
3980 cmd = L5CM_RAMROD_CMD_ID_SEARCHER_DELETE; 4044 cmd = L5CM_RAMROD_CMD_ID_SEARCHER_DELETE;
3981 else 4045 else
3982 close_complete = 1; 4046 close_complete = 1;
diff --git a/drivers/net/ethernet/broadcom/cnic_defs.h b/drivers/net/ethernet/broadcom/cnic_defs.h
index 239de898f071..86936f6b6dbc 100644
--- a/drivers/net/ethernet/broadcom/cnic_defs.h
+++ b/drivers/net/ethernet/broadcom/cnic_defs.h
@@ -85,6 +85,7 @@
85 85
86/* KCQ (kernel completion queue) completion status */ 86/* KCQ (kernel completion queue) completion status */
87#define L4_KCQE_COMPLETION_STATUS_SUCCESS (0) 87#define L4_KCQE_COMPLETION_STATUS_SUCCESS (0)
88#define L4_KCQE_COMPLETION_STATUS_NIC_ERROR (4)
88#define L4_KCQE_COMPLETION_STATUS_TIMEOUT (0x93) 89#define L4_KCQE_COMPLETION_STATUS_TIMEOUT (0x93)
89 90
90#define L4_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAIL (0x83) 91#define L4_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAIL (0x83)
diff --git a/drivers/net/ethernet/broadcom/cnic_if.h b/drivers/net/ethernet/broadcom/cnic_if.h
index d1f6456d22bb..1517763d4e55 100644
--- a/drivers/net/ethernet/broadcom/cnic_if.h
+++ b/drivers/net/ethernet/broadcom/cnic_if.h
@@ -1,6 +1,6 @@
1/* cnic_if.h: Broadcom CNIC core network driver. 1/* cnic_if.h: Broadcom CNIC core network driver.
2 * 2 *
3 * Copyright (c) 2006-2011 Broadcom Corporation 3 * Copyright (c) 2006-2012 Broadcom Corporation
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License as published by
@@ -12,8 +12,8 @@
12#ifndef CNIC_IF_H 12#ifndef CNIC_IF_H
13#define CNIC_IF_H 13#define CNIC_IF_H
14 14
15#define CNIC_MODULE_VERSION "2.5.7" 15#define CNIC_MODULE_VERSION "2.5.8"
16#define CNIC_MODULE_RELDATE "July 20, 2011" 16#define CNIC_MODULE_RELDATE "Jan 3, 2012"
17 17
18#define CNIC_ULP_RDMA 0 18#define CNIC_ULP_RDMA 0
19#define CNIC_ULP_ISCSI 1 19#define CNIC_ULP_ISCSI 1
@@ -261,6 +261,7 @@ struct cnic_sock {
261#define SK_F_CONNECT_START 4 261#define SK_F_CONNECT_START 4
262#define SK_F_IPV6 5 262#define SK_F_IPV6 5
263#define SK_F_CLOSING 7 263#define SK_F_CLOSING 7
264#define SK_F_HW_ERR 8
264 265
265 atomic_t ref_count; 266 atomic_t ref_count;
266 u32 state; 267 u32 state;