aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2010-10-13 10:06:47 -0400
committerDavid S. Miller <davem@davemloft.net>2010-10-14 13:45:54 -0400
commitfdf24086f4752aee5dfb40143c736250df017820 (patch)
treeb4bf02475161d17d7e7335d801c69e9947ec92b7 /drivers/net
parenta2c9e769dbb92336ddacba01d399ad0f509e7094 (diff)
cnic: Defer iscsi connection cleanup
The bnx2x devices require a 2 second quiet time before sending the last RAMROD command to destroy a connection. This sleep wait adds up to a long delay when iscsid is serially destroying maultiple connections. Create a workqueue to perform the final connection cleanup in the background to speed up the process. This significantly speeds up the process as the wait time can be done in parallel for multiple connections. 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/cnic.c110
-rw-r--r--drivers/net/cnic.h3
2 files changed, 109 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
84static struct workqueue_struct *cnic_wq;
85
84static void cnic_shutdown_rings(struct cnic_dev *); 86static void cnic_shutdown_rings(struct cnic_dev *);
85static void cnic_init_rings(struct cnic_dev *); 87static void cnic_init_rings(struct cnic_dev *);
86static int cnic_cm_set_pg(struct cnic_sock *); 88static 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
1779destroy_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
3300static void cnic_cm_stop_bnx2x_hw(struct cnic_dev *dev) 3326static 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
3304static int cnic_cm_init_bnx2x_hw(struct cnic_dev *dev) 3356static 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
3388static 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
3336static int cnic_cm_open(struct cnic_dev *dev) 3428static 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
4747module_init(cnic_init); 4849module_init(cnic_init);
diff --git a/drivers/net/cnic.h b/drivers/net/cnic.h
index 9907cc24807a..47cd801af857 100644
--- a/drivers/net/cnic.h
+++ b/drivers/net/cnic.h
@@ -170,6 +170,7 @@ struct cnic_context {
170 unsigned long timestamp; 170 unsigned long timestamp;
171 unsigned long ctx_flags; 171 unsigned long ctx_flags;
172#define CTX_FL_OFFLD_START 0 172#define CTX_FL_OFFLD_START 0
173#define CTX_FL_DELETE_WAIT 1
173 u8 ulp_proto_id; 174 u8 ulp_proto_id;
174 union { 175 union {
175 struct cnic_iscsi *iscsi; 176 struct cnic_iscsi *iscsi;
@@ -287,6 +288,8 @@ struct cnic_local {
287 int hq_size; 288 int hq_size;
288 int num_cqs; 289 int num_cqs;
289 290
291 struct delayed_work delete_task;
292
290 struct cnic_ctx *ctx_arr; 293 struct cnic_ctx *ctx_arr;
291 int ctx_blks; 294 int ctx_blks;
292 int ctx_blk_size; 295 int ctx_blk_size;