aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/bnx2i
diff options
context:
space:
mode:
authorEddie Wai <eddie.wai@broadcom.com>2010-07-01 18:34:52 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-07-27 13:03:58 -0400
commit55e15c975cbf9ef8b765eba9ebadc96f2a2e5752 (patch)
tree9d0249480f287463f6ef98f03d58406c9965ac18 /drivers/scsi/bnx2i
parent46012e8b8de325472790d154f4cfb1cf2d4fc49a (diff)
[SCSI] bnx2i: Optimized the bnx2i_stop connection clean up procedure
For cases where the iSCSI disconnection procedure times out due to the iSCSI daemon being slow or unresponsive, the bnx2i_stop routine will now perform hardware cleanup via bnx2i_hw_ep_disconnect on all active endpoints so that subsequent operations will perform properly. Also moved the mutex locks inside ep_connect and ep_disconnect so that proper exclusivity can resolve simultaneous calls to the ep_disconnect routine. v2: Removed the unnecessary read lock in the bnx2i_stop Signed-off-by: Eddie Wai <eddie.wai@broadcom.com> Reviewed-by: Michael Chan <mchan@broadcom.com> Reviewed-by: Benjamin Li <benli@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.h4
-rw-r--r--drivers/scsi/bnx2i/bnx2i_init.c33
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c12
3 files changed, 40 insertions, 9 deletions
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index c17c3a3d52b8..fed1a686da67 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -295,6 +295,7 @@ struct iscsi_cid_queue {
295 * @max_cqes: CQ size 295 * @max_cqes: CQ size
296 * @num_ccell: number of command cells per connection 296 * @num_ccell: number of command cells per connection
297 * @ofld_conns_active: active connection list 297 * @ofld_conns_active: active connection list
298 * @eh_wait: wait queue for the endpoint to shutdown
298 * @max_active_conns: max offload connections supported by this device 299 * @max_active_conns: max offload connections supported by this device
299 * @cid_que: iscsi cid queue 300 * @cid_que: iscsi cid queue
300 * @ep_rdwr_lock: read / write lock to synchronize various ep lists 301 * @ep_rdwr_lock: read / write lock to synchronize various ep lists
@@ -306,6 +307,7 @@ struct iscsi_cid_queue {
306 * @dummy_buffer: Dummy buffer to be used with zero length scsicmd reqs 307 * @dummy_buffer: Dummy buffer to be used with zero length scsicmd reqs
307 * @dummy_buf_dma: DMA address of 'dummy_buffer' memory buffer 308 * @dummy_buf_dma: DMA address of 'dummy_buffer' memory buffer
308 * @lock: lock to synchonize access to hba structure 309 * @lock: lock to synchonize access to hba structure
310 * @hba_shutdown_tmo: Timeout value to shutdown each connection
309 * @pci_did: PCI device ID 311 * @pci_did: PCI device ID
310 * @pci_vid: PCI vendor ID 312 * @pci_vid: PCI vendor ID
311 * @pci_sdid: PCI subsystem device ID 313 * @pci_sdid: PCI subsystem device ID
@@ -770,6 +772,8 @@ extern struct bnx2i_endpoint *bnx2i_find_ep_in_destroy_list(
770extern int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep); 772extern int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep);
771extern void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action); 773extern void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action);
772 774
775extern int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep);
776
773/* Debug related function prototypes */ 777/* Debug related function prototypes */
774extern void bnx2i_print_pend_cmd_queue(struct bnx2i_conn *conn); 778extern void bnx2i_print_pend_cmd_queue(struct bnx2i_conn *conn);
775extern void bnx2i_print_active_cmd_queue(struct bnx2i_conn *conn); 779extern void bnx2i_print_active_cmd_queue(struct bnx2i_conn *conn);
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c
index af6a00a600fb..f0f8361af4e9 100644
--- a/drivers/scsi/bnx2i/bnx2i_init.c
+++ b/drivers/scsi/bnx2i/bnx2i_init.c
@@ -176,6 +176,9 @@ void bnx2i_start(void *handle)
176void bnx2i_stop(void *handle) 176void bnx2i_stop(void *handle)
177{ 177{
178 struct bnx2i_hba *hba = handle; 178 struct bnx2i_hba *hba = handle;
179 struct list_head *pos, *tmp;
180 struct bnx2i_endpoint *bnx2i_ep;
181 int conns_active;
179 182
180 /* check if cleanup happened in GOING_DOWN context */ 183 /* check if cleanup happened in GOING_DOWN context */
181 if (!test_and_clear_bit(ADAPTER_STATE_GOING_DOWN, 184 if (!test_and_clear_bit(ADAPTER_STATE_GOING_DOWN,
@@ -187,9 +190,33 @@ void bnx2i_stop(void *handle)
187 * control returns to network driver. So it is required to cleanup and 190 * control returns to network driver. So it is required to cleanup and
188 * release all connection resources before returning from this routine. 191 * release all connection resources before returning from this routine.
189 */ 192 */
190 wait_event_interruptible_timeout(hba->eh_wait, 193 while (hba->ofld_conns_active) {
191 (hba->ofld_conns_active == 0), 194 conns_active = hba->ofld_conns_active;
192 hba->hba_shutdown_tmo); 195 wait_event_interruptible_timeout(hba->eh_wait,
196 (hba->ofld_conns_active != conns_active),
197 hba->hba_shutdown_tmo);
198 if (hba->ofld_conns_active == conns_active)
199 break;
200 }
201 if (hba->ofld_conns_active) {
202 /* Stage to force the disconnection
203 * This is the case where the daemon is either slow or
204 * not present
205 */
206 printk(KERN_ALERT "bnx2i: Wait timeout, force all eps "
207 "to disconnect (%d)\n", hba->ofld_conns_active);
208 mutex_lock(&hba->net_dev_lock);
209 list_for_each_safe(pos, tmp, &hba->ep_active_list) {
210 bnx2i_ep = list_entry(pos, struct bnx2i_endpoint, link);
211 /* Clean up the chip only */
212 bnx2i_hw_ep_disconnect(bnx2i_ep);
213 }
214 mutex_unlock(&hba->net_dev_lock);
215 if (hba->ofld_conns_active)
216 printk(KERN_ERR "bnx2i: EP disconnect timeout (%d)!\n",
217 hba->ofld_conns_active);
218 }
219
193 /* This flag should be cleared last so that ep_disconnect() gracefully 220 /* This flag should be cleared last so that ep_disconnect() gracefully
194 * cleans up connection context 221 * cleans up connection context
195 */ 222 */
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index fb5fe88de90f..1600e7cae191 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -708,7 +708,6 @@ bnx2i_find_ep_in_destroy_list(struct bnx2i_hba *hba, u32 iscsi_cid)
708 return ep; 708 return ep;
709} 709}
710 710
711
712/** 711/**
713 * bnx2i_ep_active_list_add - add an entry to ep active list 712 * bnx2i_ep_active_list_add - add an entry to ep active list
714 * @hba: pointer to adapter instance 713 * @hba: pointer to adapter instance
@@ -856,9 +855,9 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
856 mutex_init(&hba->net_dev_lock); 855 mutex_init(&hba->net_dev_lock);
857 init_waitqueue_head(&hba->eh_wait); 856 init_waitqueue_head(&hba->eh_wait);
858 if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) 857 if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
859 hba->hba_shutdown_tmo = 240 * HZ; 858 hba->hba_shutdown_tmo = 20 * HZ;
860 else /* 5706/5708/5709 */ 859 else /* 5706/5708/5709 */
861 hba->hba_shutdown_tmo = 30 * HZ; 860 hba->hba_shutdown_tmo = 20 * HZ;
862 861
863 if (iscsi_host_add(shost, &hba->pcidev->dev)) 862 if (iscsi_host_add(shost, &hba->pcidev->dev))
864 goto free_dump_mem; 863 goto free_dump_mem;
@@ -1700,10 +1699,11 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
1700 1699
1701 if (!hba || test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state)) { 1700 if (!hba || test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state)) {
1702 rc = -EINVAL; 1701 rc = -EINVAL;
1703 goto check_busy; 1702 goto nohba;
1704 } 1703 }
1705 1704
1706 cnic = hba->cnic; 1705 cnic = hba->cnic;
1706 mutex_lock(&hba->net_dev_lock);
1707 ep = bnx2i_alloc_ep(hba); 1707 ep = bnx2i_alloc_ep(hba);
1708 if (!ep) { 1708 if (!ep) {
1709 rc = -ENOMEM; 1709 rc = -ENOMEM;
@@ -1711,7 +1711,6 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
1711 } 1711 }
1712 bnx2i_ep = ep->dd_data; 1712 bnx2i_ep = ep->dd_data;
1713 1713
1714 mutex_lock(&hba->net_dev_lock);
1715 if (bnx2i_adapter_ready(hba)) { 1714 if (bnx2i_adapter_ready(hba)) {
1716 rc = -EPERM; 1715 rc = -EPERM;
1717 goto net_if_down; 1716 goto net_if_down;
@@ -1813,8 +1812,9 @@ iscsi_cid_err:
1813 bnx2i_free_qp_resc(hba, bnx2i_ep); 1812 bnx2i_free_qp_resc(hba, bnx2i_ep);
1814qp_resc_err: 1813qp_resc_err:
1815 bnx2i_free_ep(ep); 1814 bnx2i_free_ep(ep);
1816 mutex_unlock(&hba->net_dev_lock);
1817check_busy: 1815check_busy:
1816 mutex_unlock(&hba->net_dev_lock);
1817nohba:
1818 bnx2i_unreg_dev_all(); 1818 bnx2i_unreg_dev_all();
1819 return ERR_PTR(rc); 1819 return ERR_PTR(rc);
1820} 1820}