* @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
* @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
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);
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,
* 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
*/
return ep;
}
-
/**
* bnx2i_ep_active_list_add - add an entry to ep active list
* @hba: pointer to adapter instance
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;
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;
}
bnx2i_ep = ep->dd_data;
- mutex_lock(&hba->net_dev_lock);
if (bnx2i_adapter_ready(hba)) {
rc = -EPERM;
goto net_if_down;
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);
}