[SCSI] bnx2i: Cleaned up various error conditions in ep_connect/disconnect
authorEddie Wai <eddie.wai@broadcom.com>
Tue, 23 Nov 2010 23:29:30 +0000 (15:29 -0800)
committerJames Bottomley <James.Bottomley@suse.de>
Tue, 21 Dec 2010 18:24:15 +0000 (12:24 -0600)
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>
drivers/scsi/bnx2i/bnx2i_iscsi.c

index f622e89..24997c6 100644 (file)
@@ -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);