if (ret == 1)
return 0;
- return -EBUSY;
+ return ret;
}
static void cnic_reply_bnx2x_kcqes(struct cnic_dev *dev, int ulp_type,
done:
cqes[0] = (struct kcqe *) &kcqe;
cnic_reply_bnx2x_kcqes(dev, CNIC_ULP_ISCSI, cqes, 1);
- return ret;
+ return 0;
}
cqes[0] = (struct kcqe *) &kcqe;
cnic_reply_bnx2x_kcqes(dev, CNIC_ULP_ISCSI, cqes, 1);
- return ret;
+ return 0;
}
static void cnic_init_storm_conn_bufs(struct cnic_dev *dev,
return ret;
}
+static void cnic_bnx2x_kwqe_err(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct kcqe kcqe;
+ struct kcqe *cqes[1];
+ u32 cid;
+ u32 opcode = KWQE_OPCODE(kwqe->kwqe_op_flag);
+ u32 layer_code = kwqe->kwqe_op_flag & KWQE_LAYER_MASK;
+ int ulp_type;
+
+ cid = kwqe->kwqe_info0;
+ memset(&kcqe, 0, sizeof(kcqe));
+
+ if (layer_code == KWQE_FLAGS_LAYER_MASK_L5_ISCSI) {
+ ulp_type = CNIC_ULP_ISCSI;
+ if (opcode == ISCSI_KWQE_OPCODE_UPDATE_CONN)
+ cid = kwqe->kwqe_info1;
+
+ kcqe.kcqe_op_flag = (opcode + 0x10) << KCQE_FLAGS_OPCODE_SHIFT;
+ kcqe.kcqe_op_flag |= KCQE_FLAGS_LAYER_MASK_L5_ISCSI;
+ kcqe.kcqe_info1 = ISCSI_KCQE_COMPLETION_STATUS_NIC_ERROR;
+ kcqe.kcqe_info2 = cid;
+ cnic_get_l5_cid(cp, BNX2X_SW_CID(cid), &kcqe.kcqe_info0);
+
+ } else if (layer_code == KWQE_FLAGS_LAYER_MASK_L4) {
+ struct l4_kcq *l4kcqe = (struct l4_kcq *) &kcqe;
+ u32 kcqe_op;
+
+ ulp_type = CNIC_ULP_L4;
+ if (opcode == L4_KWQE_OPCODE_VALUE_CONNECT1)
+ kcqe_op = L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE;
+ else if (opcode == L4_KWQE_OPCODE_VALUE_RESET)
+ kcqe_op = L4_KCQE_OPCODE_VALUE_RESET_COMP;
+ else if (opcode == L4_KWQE_OPCODE_VALUE_CLOSE)
+ kcqe_op = L4_KCQE_OPCODE_VALUE_CLOSE_COMP;
+ else
+ return;
+
+ kcqe.kcqe_op_flag = (kcqe_op << KCQE_FLAGS_OPCODE_SHIFT) |
+ KCQE_FLAGS_LAYER_MASK_L4;
+ l4kcqe->status = L4_KCQE_COMPLETION_STATUS_NIC_ERROR;
+ l4kcqe->cid = cid;
+ cnic_get_l5_cid(cp, BNX2X_SW_CID(cid), &l4kcqe->conn_id);
+ } else {
+ return;
+ }
+
+ cqes[0] = (struct kcqe *) &kcqe;
+ cnic_reply_bnx2x_kcqes(dev, ulp_type, cqes, 1);
+}
+
static int cnic_submit_bnx2x_iscsi_kwqes(struct cnic_dev *dev,
struct kwqe *wqes[], u32 num_wqes)
{
opcode);
break;
}
- if (ret < 0)
+ if (ret < 0) {
netdev_err(dev->netdev, "KWQE(0x%x) failed\n",
opcode);
+
+ /* Possibly bnx2x parity error, send completion
+ * to ulp drivers with error code to speed up
+ * cleanup and reset recovery.
+ */
+ if (ret == -EIO || ret == -EAGAIN)
+ cnic_bnx2x_kwqe_err(dev, kwqe);
+ }
i += work;
}
return 0;
case L4_KCQE_OPCODE_VALUE_RESET_COMP:
case L5CM_RAMROD_CMD_ID_SEARCHER_DELETE:
case L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD:
+ if (l4kcqe->status == L4_KCQE_COMPLETION_STATUS_NIC_ERROR)
+ set_bit(SK_F_HW_ERR, &csk->flags);
+
cp->close_conn(csk, opcode);
break;
case L4_KCQE_OPCODE_VALUE_CLOSE_COMP:
case L4_KCQE_OPCODE_VALUE_RESET_COMP:
if (cnic_ready_to_close(csk, opcode)) {
- if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags))
+ if (test_bit(SK_F_HW_ERR, &csk->flags))
+ close_complete = 1;
+ else if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags))
cmd = L5CM_RAMROD_CMD_ID_SEARCHER_DELETE;
else
close_complete = 1;