Skip to content

Commit

Permalink
[SCSI] bnx2i: Optimized the bnx2i_stop connection clean up procedure
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Eddie Wai authored and James Bottomley committed Jul 27, 2010
1 parent 46012e8 commit 55e15c9
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 9 deletions.
4 changes: 4 additions & 0 deletions drivers/scsi/bnx2i/bnx2i.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ struct iscsi_cid_queue {
* @max_cqes: CQ size
* @num_ccell: number of command cells per connection
* @ofld_conns_active: active connection list
* @eh_wait: wait queue for the endpoint to shutdown
* @max_active_conns: max offload connections supported by this device
* @cid_que: iscsi cid queue
* @ep_rdwr_lock: read / write lock to synchronize various ep lists
Expand All @@ -306,6 +307,7 @@ struct iscsi_cid_queue {
* @dummy_buffer: Dummy buffer to be used with zero length scsicmd reqs
* @dummy_buf_dma: DMA address of 'dummy_buffer' memory buffer
* @lock: lock to synchonize access to hba structure
* @hba_shutdown_tmo: Timeout value to shutdown each connection
* @pci_did: PCI device ID
* @pci_vid: PCI vendor ID
* @pci_sdid: PCI subsystem device ID
Expand Down Expand Up @@ -770,6 +772,8 @@ extern struct bnx2i_endpoint *bnx2i_find_ep_in_destroy_list(
extern int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep);
extern void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action);

extern int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep);

/* Debug related function prototypes */
extern void bnx2i_print_pend_cmd_queue(struct bnx2i_conn *conn);
extern void bnx2i_print_active_cmd_queue(struct bnx2i_conn *conn);
Expand Down
33 changes: 30 additions & 3 deletions drivers/scsi/bnx2i/bnx2i_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@ void bnx2i_start(void *handle)
void bnx2i_stop(void *handle)
{
struct bnx2i_hba *hba = handle;
struct list_head *pos, *tmp;
struct bnx2i_endpoint *bnx2i_ep;
int conns_active;

/* check if cleanup happened in GOING_DOWN context */
if (!test_and_clear_bit(ADAPTER_STATE_GOING_DOWN,
Expand All @@ -187,9 +190,33 @@ void bnx2i_stop(void *handle)
* control returns to network driver. So it is required to cleanup and
* release all connection resources before returning from this routine.
*/
wait_event_interruptible_timeout(hba->eh_wait,
(hba->ofld_conns_active == 0),
hba->hba_shutdown_tmo);
while (hba->ofld_conns_active) {
conns_active = hba->ofld_conns_active;
wait_event_interruptible_timeout(hba->eh_wait,
(hba->ofld_conns_active != conns_active),
hba->hba_shutdown_tmo);
if (hba->ofld_conns_active == conns_active)
break;
}
if (hba->ofld_conns_active) {
/* Stage to force the disconnection
* This is the case where the daemon is either slow or
* not present
*/
printk(KERN_ALERT "bnx2i: Wait timeout, force all eps "
"to disconnect (%d)\n", hba->ofld_conns_active);
mutex_lock(&hba->net_dev_lock);
list_for_each_safe(pos, tmp, &hba->ep_active_list) {
bnx2i_ep = list_entry(pos, struct bnx2i_endpoint, link);
/* Clean up the chip only */
bnx2i_hw_ep_disconnect(bnx2i_ep);
}
mutex_unlock(&hba->net_dev_lock);
if (hba->ofld_conns_active)
printk(KERN_ERR "bnx2i: EP disconnect timeout (%d)!\n",
hba->ofld_conns_active);
}

/* This flag should be cleared last so that ep_disconnect() gracefully
* cleans up connection context
*/
Expand Down
12 changes: 6 additions & 6 deletions drivers/scsi/bnx2i/bnx2i_iscsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,6 @@ bnx2i_find_ep_in_destroy_list(struct bnx2i_hba *hba, u32 iscsi_cid)
return ep;
}


/**
* bnx2i_ep_active_list_add - add an entry to ep active list
* @hba: pointer to adapter instance
Expand Down Expand Up @@ -856,9 +855,9 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
mutex_init(&hba->net_dev_lock);
init_waitqueue_head(&hba->eh_wait);
if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
hba->hba_shutdown_tmo = 240 * HZ;
hba->hba_shutdown_tmo = 20 * HZ;
else /* 5706/5708/5709 */
hba->hba_shutdown_tmo = 30 * HZ;
hba->hba_shutdown_tmo = 20 * HZ;

if (iscsi_host_add(shost, &hba->pcidev->dev))
goto free_dump_mem;
Expand Down Expand Up @@ -1700,18 +1699,18 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,

if (!hba || test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state)) {
rc = -EINVAL;
goto check_busy;
goto nohba;
}

cnic = hba->cnic;
mutex_lock(&hba->net_dev_lock);
ep = bnx2i_alloc_ep(hba);
if (!ep) {
rc = -ENOMEM;
goto check_busy;
}
bnx2i_ep = ep->dd_data;

mutex_lock(&hba->net_dev_lock);
if (bnx2i_adapter_ready(hba)) {
rc = -EPERM;
goto net_if_down;
Expand Down Expand Up @@ -1813,8 +1812,9 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
bnx2i_free_qp_resc(hba, bnx2i_ep);
qp_resc_err:
bnx2i_free_ep(ep);
mutex_unlock(&hba->net_dev_lock);
check_busy:
mutex_unlock(&hba->net_dev_lock);
nohba:
bnx2i_unreg_dev_all();
return ERR_PTR(rc);
}
Expand Down

0 comments on commit 55e15c9

Please sign in to comment.