diff options
author | Eddie Wai <eddie.wai@broadcom.com> | 2010-11-24 02:29:30 +0300 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-12-21 21:24:15 +0300 |
commit | a91031a6526441ff36552d53363037c3bbca0c5b (patch) | |
tree | aa1e70b241807bf19a78dffda99420bfe3ed60ed /drivers/scsi/bnx2i | |
parent | bee348770dcaeafa57bbd32129ce0cb16a4342d6 (diff) | |
download | linux-a91031a6526441ff36552d53363037c3bbca0c5b.tar.xz |
[SCSI] bnx2i: Cleaned up various error conditions in ep_connect/disconnect
Various error conditions inside ep_connect and ep_disconnect were
either not being handled or not being handled correctly. This patch
fixes all those issues.
Signed-off-by: Eddie Wai <eddie.wai@broadcom.com>
Acked-by: Anil Veerabhadrappa <anilgv@broadcom.com>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/bnx2i')
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i_iscsi.c | 67 |
1 files changed, 40 insertions, 27 deletions
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index f622e89041cd..24997c679f3c 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -411,7 +411,9 @@ static void bnx2i_free_ep(struct iscsi_endpoint *ep) bnx2i_ep->state = EP_STATE_IDLE; bnx2i_ep->hba->ofld_conns_active--; - bnx2i_free_iscsi_cid(bnx2i_ep->hba, bnx2i_ep->ep_iscsi_cid); + if (bnx2i_ep->ep_iscsi_cid != (u16) -1) + bnx2i_free_iscsi_cid(bnx2i_ep->hba, bnx2i_ep->ep_iscsi_cid); + if (bnx2i_ep->conn) { bnx2i_ep->conn->ep = NULL; bnx2i_ep->conn = NULL; @@ -1738,13 +1740,17 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, */ hba = bnx2i_check_route(dst_addr); - if (!hba || test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state)) { + if (!hba) { rc = -EINVAL; goto nohba; } + mutex_lock(&hba->net_dev_lock); + if (bnx2i_adapter_ready(hba) || !hba->cid_que.cid_free_cnt) { + rc = -EPERM; + goto check_busy; + } cnic = hba->cnic; - mutex_lock(&hba->net_dev_lock); ep = bnx2i_alloc_ep(hba); if (!ep) { rc = -ENOMEM; @@ -1752,23 +1758,21 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, } bnx2i_ep = ep->dd_data; - if (bnx2i_adapter_ready(hba)) { - rc = -EPERM; - goto net_if_down; - } - bnx2i_ep->num_active_cmds = 0; iscsi_cid = bnx2i_alloc_iscsi_cid(hba); if (iscsi_cid == -1) { - printk(KERN_ALERT "alloc_ep: unable to allocate iscsi cid\n"); + printk(KERN_ALERT "bnx2i (%s): alloc_ep - unable to allocate " + "iscsi cid\n", hba->netdev->name); rc = -ENOMEM; - goto iscsi_cid_err; + bnx2i_free_ep(ep); + goto check_busy; } bnx2i_ep->hba_age = hba->age; rc = bnx2i_alloc_qp_resc(hba, bnx2i_ep); if (rc != 0) { - printk(KERN_ALERT "bnx2i: ep_conn, alloc QP resc error\n"); + printk(KERN_ALERT "bnx2i (%s): ep_conn - alloc QP resc error" + "\n", hba->netdev->name); rc = -ENOMEM; goto qp_resc_err; } @@ -1807,7 +1811,12 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, bnx2i_ep_ofld_list_del(hba, bnx2i_ep); if (bnx2i_ep->state != EP_STATE_OFLD_COMPL) { - rc = -ENOSPC; + if (bnx2i_ep->state == EP_STATE_OFLD_FAILED_CID_BUSY) { + printk(KERN_ALERT "bnx2i (%s): iscsi cid %d is busy\n", + hba->netdev->name, bnx2i_ep->ep_iscsi_cid); + rc = -EBUSY; + } else + rc = -ENOSPC; goto conn_failed; } @@ -1815,7 +1824,8 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, iscsi_cid, &bnx2i_ep->cm_sk, bnx2i_ep); if (rc) { rc = -EINVAL; - goto conn_failed; + /* Need to terminate and cleanup the connection */ + goto release_ep; } bnx2i_ep->cm_sk->rcv_buf = 256 * 1024; @@ -1859,8 +1869,6 @@ release_ep: return ERR_PTR(rc); } conn_failed: -net_if_down: -iscsi_cid_err: bnx2i_free_qp_resc(hba, bnx2i_ep); qp_resc_err: bnx2i_free_ep(ep); @@ -1979,7 +1987,8 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) if (!cnic) return 0; - if (bnx2i_ep->state == EP_STATE_IDLE) + if (bnx2i_ep->state == EP_STATE_IDLE || + bnx2i_ep->state == EP_STATE_DISCONN_TIMEDOUT) return 0; if (!bnx2i_ep_tcp_conn_active(bnx2i_ep)) @@ -2005,9 +2014,10 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) if (session->state == ISCSI_STATE_LOGGING_OUT) { if (bnx2i_ep->state == EP_STATE_LOGOUT_SENT) { /* Logout sent, but no resp */ - printk(KERN_ALERT "bnx2i - WARNING " - "logout response was not " - "received!\n"); + printk(KERN_ALERT "bnx2i (%s): WARNING" + " logout response was not " + "received!\n", + bnx2i_ep->hba->netdev->name); } else if (bnx2i_ep->state == EP_STATE_LOGOUT_RESP_RCVD) close = 1; @@ -2025,9 +2035,8 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) else close_ret = cnic->cm_abort(bnx2i_ep->cm_sk); - /* No longer allow CFC delete if cm_close/abort fails the request */ if (close_ret) - printk(KERN_ALERT "bnx2i: %s close/abort(%d) returned %d\n", + printk(KERN_ALERT "bnx2i (%s): close/abort(%d) returned %d\n", bnx2i_ep->hba->netdev->name, close, close_ret); else /* wait for option-2 conn teardown */ @@ -2041,7 +2050,7 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) destroy_conn: bnx2i_ep_active_list_del(hba, bnx2i_ep); if (bnx2i_tear_down_conn(hba, bnx2i_ep)) - ret = -EINVAL; + return -EINVAL; out: bnx2i_ep->state = EP_STATE_IDLE; return ret; @@ -2080,14 +2089,17 @@ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep) mutex_lock(&hba->net_dev_lock); - if (bnx2i_ep->state == EP_STATE_IDLE) - goto return_bnx2i_ep; + if (bnx2i_ep->state == EP_STATE_DISCONN_TIMEDOUT) + goto out; - if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state)) + if (bnx2i_ep->state == EP_STATE_IDLE) goto free_resc; - if (bnx2i_ep->hba_age != hba->age) + if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) || + (bnx2i_ep->hba_age != hba->age)) { + bnx2i_ep_active_list_del(hba, bnx2i_ep); goto free_resc; + } /* Do all chip cleanup here */ if (bnx2i_hw_ep_disconnect(bnx2i_ep)) { @@ -2096,11 +2108,12 @@ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep) } free_resc: bnx2i_free_qp_resc(hba, bnx2i_ep); -return_bnx2i_ep: + if (bnx2i_conn) bnx2i_conn->ep = NULL; bnx2i_free_ep(ep); +out: mutex_unlock(&hba->net_dev_lock); wake_up_interruptible(&hba->eh_wait); |