diff options
Diffstat (limited to 'drivers/net/cnic.c')
-rw-r--r-- | drivers/net/cnic.c | 110 |
1 files changed, 106 insertions, 4 deletions
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index ee66c48e28bc..b12bba795f2e 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c | |||
@@ -81,6 +81,8 @@ static struct cnic_ops cnic_bnx2x_ops = { | |||
81 | .cnic_ctl = cnic_ctl, | 81 | .cnic_ctl = cnic_ctl, |
82 | }; | 82 | }; |
83 | 83 | ||
84 | static struct workqueue_struct *cnic_wq; | ||
85 | |||
84 | static void cnic_shutdown_rings(struct cnic_dev *); | 86 | static void cnic_shutdown_rings(struct cnic_dev *); |
85 | static void cnic_init_rings(struct cnic_dev *); | 87 | static void cnic_init_rings(struct cnic_dev *); |
86 | static int cnic_cm_set_pg(struct cnic_sock *); | 88 | static int cnic_cm_set_pg(struct cnic_sock *); |
@@ -1629,10 +1631,11 @@ static int cnic_bnx2x_iscsi_ofld1(struct cnic_dev *dev, struct kwqe *wqes[], | |||
1629 | struct iscsi_kwqe_conn_offload1 *req1; | 1631 | struct iscsi_kwqe_conn_offload1 *req1; |
1630 | struct iscsi_kwqe_conn_offload2 *req2; | 1632 | struct iscsi_kwqe_conn_offload2 *req2; |
1631 | struct cnic_local *cp = dev->cnic_priv; | 1633 | struct cnic_local *cp = dev->cnic_priv; |
1634 | struct cnic_context *ctx; | ||
1632 | struct iscsi_kcqe kcqe; | 1635 | struct iscsi_kcqe kcqe; |
1633 | struct kcqe *cqes[1]; | 1636 | struct kcqe *cqes[1]; |
1634 | u32 l5_cid; | 1637 | u32 l5_cid; |
1635 | int ret; | 1638 | int ret = 0; |
1636 | 1639 | ||
1637 | if (num < 2) { | 1640 | if (num < 2) { |
1638 | *work = num; | 1641 | *work = num; |
@@ -1656,9 +1659,15 @@ static int cnic_bnx2x_iscsi_ofld1(struct cnic_dev *dev, struct kwqe *wqes[], | |||
1656 | kcqe.iscsi_conn_id = l5_cid; | 1659 | kcqe.iscsi_conn_id = l5_cid; |
1657 | kcqe.completion_status = ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE; | 1660 | kcqe.completion_status = ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE; |
1658 | 1661 | ||
1662 | ctx = &cp->ctx_tbl[l5_cid]; | ||
1663 | if (test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags)) { | ||
1664 | kcqe.completion_status = | ||
1665 | ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY; | ||
1666 | goto done; | ||
1667 | } | ||
1668 | |||
1659 | if (atomic_inc_return(&cp->iscsi_conn) > dev->max_iscsi_conn) { | 1669 | if (atomic_inc_return(&cp->iscsi_conn) > dev->max_iscsi_conn) { |
1660 | atomic_dec(&cp->iscsi_conn); | 1670 | atomic_dec(&cp->iscsi_conn); |
1661 | ret = 0; | ||
1662 | goto done; | 1671 | goto done; |
1663 | } | 1672 | } |
1664 | ret = cnic_alloc_bnx2x_conn_resc(dev, l5_cid); | 1673 | ret = cnic_alloc_bnx2x_conn_resc(dev, l5_cid); |
@@ -1748,8 +1757,16 @@ static int cnic_bnx2x_iscsi_destroy(struct cnic_dev *dev, struct kwqe *kwqe) | |||
1748 | if (!test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags)) | 1757 | if (!test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags)) |
1749 | goto skip_cfc_delete; | 1758 | goto skip_cfc_delete; |
1750 | 1759 | ||
1751 | while (!time_after(jiffies, ctx->timestamp + (2 * HZ))) | 1760 | if (!time_after(jiffies, ctx->timestamp + (2 * HZ))) { |
1752 | msleep(250); | 1761 | unsigned long delta = ctx->timestamp + (2 * HZ) - jiffies; |
1762 | |||
1763 | if (delta > (2 * HZ)) | ||
1764 | delta = 0; | ||
1765 | |||
1766 | set_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags); | ||
1767 | queue_delayed_work(cnic_wq, &cp->delete_task, delta); | ||
1768 | goto destroy_reply; | ||
1769 | } | ||
1753 | 1770 | ||
1754 | ret = cnic_bnx2x_destroy_ramrod(dev, l5_cid); | 1771 | ret = cnic_bnx2x_destroy_ramrod(dev, l5_cid); |
1755 | 1772 | ||
@@ -1757,7 +1774,9 @@ skip_cfc_delete: | |||
1757 | cnic_free_bnx2x_conn_resc(dev, l5_cid); | 1774 | cnic_free_bnx2x_conn_resc(dev, l5_cid); |
1758 | 1775 | ||
1759 | atomic_dec(&cp->iscsi_conn); | 1776 | atomic_dec(&cp->iscsi_conn); |
1777 | clear_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags); | ||
1760 | 1778 | ||
1779 | destroy_reply: | ||
1761 | memset(&kcqe, 0, sizeof(kcqe)); | 1780 | memset(&kcqe, 0, sizeof(kcqe)); |
1762 | kcqe.op_code = ISCSI_KCQE_OPCODE_DESTROY_CONN; | 1781 | kcqe.op_code = ISCSI_KCQE_OPCODE_DESTROY_CONN; |
1763 | kcqe.iscsi_conn_id = l5_cid; | 1782 | kcqe.iscsi_conn_id = l5_cid; |
@@ -2748,6 +2767,13 @@ static int cnic_cm_create(struct cnic_dev *dev, int ulp_type, u32 cid, | |||
2748 | if (l5_cid >= MAX_CM_SK_TBL_SZ) | 2767 | if (l5_cid >= MAX_CM_SK_TBL_SZ) |
2749 | return -EINVAL; | 2768 | return -EINVAL; |
2750 | 2769 | ||
2770 | if (cp->ctx_tbl) { | ||
2771 | struct cnic_context *ctx = &cp->ctx_tbl[l5_cid]; | ||
2772 | |||
2773 | if (test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags)) | ||
2774 | return -EAGAIN; | ||
2775 | } | ||
2776 | |||
2751 | csk1 = &cp->csk_tbl[l5_cid]; | 2777 | csk1 = &cp->csk_tbl[l5_cid]; |
2752 | if (atomic_read(&csk1->ref_count)) | 2778 | if (atomic_read(&csk1->ref_count)) |
2753 | return -EAGAIN; | 2779 | return -EAGAIN; |
@@ -3299,6 +3325,32 @@ static void cnic_close_bnx2x_conn(struct cnic_sock *csk, u32 opcode) | |||
3299 | 3325 | ||
3300 | static void cnic_cm_stop_bnx2x_hw(struct cnic_dev *dev) | 3326 | static void cnic_cm_stop_bnx2x_hw(struct cnic_dev *dev) |
3301 | { | 3327 | { |
3328 | struct cnic_local *cp = dev->cnic_priv; | ||
3329 | int i; | ||
3330 | |||
3331 | if (!cp->ctx_tbl) | ||
3332 | return; | ||
3333 | |||
3334 | if (!netif_running(dev->netdev)) | ||
3335 | return; | ||
3336 | |||
3337 | for (i = 0; i < cp->max_cid_space; i++) { | ||
3338 | struct cnic_context *ctx = &cp->ctx_tbl[i]; | ||
3339 | |||
3340 | while (test_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags)) | ||
3341 | msleep(10); | ||
3342 | |||
3343 | if (test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags)) | ||
3344 | netdev_warn(dev->netdev, "CID %x not deleted\n", | ||
3345 | ctx->cid); | ||
3346 | } | ||
3347 | |||
3348 | cancel_delayed_work(&cp->delete_task); | ||
3349 | flush_workqueue(cnic_wq); | ||
3350 | |||
3351 | if (atomic_read(&cp->iscsi_conn) != 0) | ||
3352 | netdev_warn(dev->netdev, "%d iSCSI connections not destroyed\n", | ||
3353 | atomic_read(&cp->iscsi_conn)); | ||
3302 | } | 3354 | } |
3303 | 3355 | ||
3304 | static int cnic_cm_init_bnx2x_hw(struct cnic_dev *dev) | 3356 | static int cnic_cm_init_bnx2x_hw(struct cnic_dev *dev) |
@@ -3333,6 +3385,46 @@ static int cnic_cm_init_bnx2x_hw(struct cnic_dev *dev) | |||
3333 | return 0; | 3385 | return 0; |
3334 | } | 3386 | } |
3335 | 3387 | ||
3388 | static void cnic_delete_task(struct work_struct *work) | ||
3389 | { | ||
3390 | struct cnic_local *cp; | ||
3391 | struct cnic_dev *dev; | ||
3392 | u32 i; | ||
3393 | int need_resched = 0; | ||
3394 | |||
3395 | cp = container_of(work, struct cnic_local, delete_task.work); | ||
3396 | dev = cp->dev; | ||
3397 | |||
3398 | for (i = 0; i < cp->max_cid_space; i++) { | ||
3399 | struct cnic_context *ctx = &cp->ctx_tbl[i]; | ||
3400 | |||
3401 | if (!test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags) || | ||
3402 | !test_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags)) | ||
3403 | continue; | ||
3404 | |||
3405 | if (!time_after(jiffies, ctx->timestamp + (2 * HZ))) { | ||
3406 | need_resched = 1; | ||
3407 | continue; | ||
3408 | } | ||
3409 | |||
3410 | if (!test_and_clear_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags)) | ||
3411 | continue; | ||
3412 | |||
3413 | cnic_bnx2x_destroy_ramrod(dev, i); | ||
3414 | |||
3415 | cnic_free_bnx2x_conn_resc(dev, i); | ||
3416 | if (ctx->ulp_proto_id == CNIC_ULP_ISCSI) | ||
3417 | atomic_dec(&cp->iscsi_conn); | ||
3418 | |||
3419 | clear_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags); | ||
3420 | } | ||
3421 | |||
3422 | if (need_resched) | ||
3423 | queue_delayed_work(cnic_wq, &cp->delete_task, | ||
3424 | msecs_to_jiffies(10)); | ||
3425 | |||
3426 | } | ||
3427 | |||
3336 | static int cnic_cm_open(struct cnic_dev *dev) | 3428 | static int cnic_cm_open(struct cnic_dev *dev) |
3337 | { | 3429 | { |
3338 | struct cnic_local *cp = dev->cnic_priv; | 3430 | struct cnic_local *cp = dev->cnic_priv; |
@@ -3347,6 +3439,8 @@ static int cnic_cm_open(struct cnic_dev *dev) | |||
3347 | if (err) | 3439 | if (err) |
3348 | goto err_out; | 3440 | goto err_out; |
3349 | 3441 | ||
3442 | INIT_DELAYED_WORK(&cp->delete_task, cnic_delete_task); | ||
3443 | |||
3350 | dev->cm_create = cnic_cm_create; | 3444 | dev->cm_create = cnic_cm_create; |
3351 | dev->cm_destroy = cnic_cm_destroy; | 3445 | dev->cm_destroy = cnic_cm_destroy; |
3352 | dev->cm_connect = cnic_cm_connect; | 3446 | dev->cm_connect = cnic_cm_connect; |
@@ -4735,6 +4829,13 @@ static int __init cnic_init(void) | |||
4735 | return rc; | 4829 | return rc; |
4736 | } | 4830 | } |
4737 | 4831 | ||
4832 | cnic_wq = create_singlethread_workqueue("cnic_wq"); | ||
4833 | if (!cnic_wq) { | ||
4834 | cnic_release(); | ||
4835 | unregister_netdevice_notifier(&cnic_netdev_notifier); | ||
4836 | return -ENOMEM; | ||
4837 | } | ||
4838 | |||
4738 | return 0; | 4839 | return 0; |
4739 | } | 4840 | } |
4740 | 4841 | ||
@@ -4742,6 +4843,7 @@ static void __exit cnic_exit(void) | |||
4742 | { | 4843 | { |
4743 | unregister_netdevice_notifier(&cnic_netdev_notifier); | 4844 | unregister_netdevice_notifier(&cnic_netdev_notifier); |
4744 | cnic_release(); | 4845 | cnic_release(); |
4846 | destroy_workqueue(cnic_wq); | ||
4745 | } | 4847 | } |
4746 | 4848 | ||
4747 | module_init(cnic_init); | 4849 | module_init(cnic_init); |