m68k/scsi: a3000 - Do not use legacy Scsi_Host.base
[safe/jmp/linux-2.6] / drivers / scsi / bnx2i / bnx2i_init.c
index ae4b2d5..af6a00a 100644 (file)
 
 static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list);
 static u32 adapter_count;
-static int bnx2i_reg_device;
 
 #define DRV_MODULE_NAME                "bnx2i"
-#define DRV_MODULE_VERSION     "2.0.1d"
-#define DRV_MODULE_RELDATE     "Mar 25, 2009"
+#define DRV_MODULE_VERSION     "2.1.1"
+#define DRV_MODULE_RELDATE     "Mar 24, 2010"
 
 static char version[] __devinitdata =
                "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
@@ -27,11 +26,16 @@ static char version[] __devinitdata =
 
 
 MODULE_AUTHOR("Anil Veerabhadrappa <anilgv@broadcom.com>");
-MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 iSCSI Driver");
+MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/57710/57711"
+                  " iSCSI Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_MODULE_VERSION);
 
-static DEFINE_RWLOCK(bnx2i_dev_lock);
+static DEFINE_MUTEX(bnx2i_dev_lock);
+
+unsigned int event_coal_min = 24;
+module_param(event_coal_min, int, 0664);
+MODULE_PARM_DESC(event_coal_min, "Event Coalescing Minimum Commands");
 
 unsigned int event_coal_div = 1;
 module_param(event_coal_div, int, 0664);
@@ -84,8 +88,12 @@ void bnx2i_identify_device(struct bnx2i_hba *hba)
                set_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type);
                hba->mail_queue_access = BNX2I_MQ_BIN_MODE;
        } else if (hba->pci_did == PCI_DEVICE_ID_NX2_57710 ||
-                  hba->pci_did == PCI_DEVICE_ID_NX2_57711)
+                  hba->pci_did == PCI_DEVICE_ID_NX2_57711 ||
+                  hba->pci_did == PCI_DEVICE_ID_NX2_57711E)
                set_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type);
+       else
+               printk(KERN_ALERT "bnx2i: unknown device, 0x%x\n",
+                                 hba->pci_did);
 }
 
 
@@ -100,14 +108,14 @@ struct bnx2i_hba *get_adapter_list_head(void)
        if (!adapter_count)
                goto hba_not_found;
 
-       read_lock(&bnx2i_dev_lock);
+       mutex_lock(&bnx2i_dev_lock);
        list_for_each_entry(tmp_hba, &adapter_list, link) {
                if (tmp_hba->cnic && tmp_hba->cnic->cm_select_dev) {
                        hba = tmp_hba;
                        break;
                }
        }
-       read_unlock(&bnx2i_dev_lock);
+       mutex_unlock(&bnx2i_dev_lock);
 hba_not_found:
        return hba;
 }
@@ -122,14 +130,14 @@ struct bnx2i_hba *bnx2i_find_hba_for_cnic(struct cnic_dev *cnic)
 {
        struct bnx2i_hba *hba, *temp;
 
-       read_lock(&bnx2i_dev_lock);
+       mutex_lock(&bnx2i_dev_lock);
        list_for_each_entry_safe(hba, temp, &adapter_list, link) {
                if (hba->cnic == cnic) {
-                       read_unlock(&bnx2i_dev_lock);
+                       mutex_unlock(&bnx2i_dev_lock);
                        return hba;
                }
        }
-       read_unlock(&bnx2i_dev_lock);
+       mutex_unlock(&bnx2i_dev_lock);
        return NULL;
 }
 
@@ -170,11 +178,22 @@ void bnx2i_stop(void *handle)
        struct bnx2i_hba *hba = handle;
 
        /* check if cleanup happened in GOING_DOWN context */
-       clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
        if (!test_and_clear_bit(ADAPTER_STATE_GOING_DOWN,
                                &hba->adapter_state))
                iscsi_host_for_each_session(hba->shost,
                                            bnx2i_drop_session);
+
+       /* Wait for all endpoints to be torn down, Chip will be reset once
+        *  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);
+       /* This flag should be cleared last so that ep_disconnect() gracefully
+        * cleans up connection context
+        */
+       clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
 }
 
 /**
@@ -186,18 +205,17 @@ void bnx2i_stop(void *handle)
  */
 void bnx2i_register_device(struct bnx2i_hba *hba)
 {
+       int rc;
+
        if (test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state) ||
            test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
                return;
        }
 
-       hba->cnic->register_device(hba->cnic, CNIC_ULP_ISCSI, hba);
+       rc = hba->cnic->register_device(hba->cnic, CNIC_ULP_ISCSI, hba);
 
-       spin_lock(&hba->lock);
-       bnx2i_reg_device++;
-       spin_unlock(&hba->lock);
-
-       set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
+       if (!rc)
+               set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
 }
 
 
@@ -211,10 +229,10 @@ void bnx2i_reg_dev_all(void)
 {
        struct bnx2i_hba *hba, *temp;
 
-       read_lock(&bnx2i_dev_lock);
+       mutex_lock(&bnx2i_dev_lock);
        list_for_each_entry_safe(hba, temp, &adapter_list, link)
                bnx2i_register_device(hba);
-       read_unlock(&bnx2i_dev_lock);
+       mutex_unlock(&bnx2i_dev_lock);
 }
 
 
@@ -234,10 +252,6 @@ static void bnx2i_unreg_one_device(struct bnx2i_hba *hba)
 
        hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
 
-       spin_lock(&hba->lock);
-       bnx2i_reg_device--;
-       spin_unlock(&hba->lock);
-
        /* ep_disconnect could come before NETDEV_DOWN, driver won't
         * see NETDEV_DOWN as it already unregistered itself.
         */
@@ -255,10 +269,10 @@ void bnx2i_unreg_dev_all(void)
 {
        struct bnx2i_hba *hba, *temp;
 
-       read_lock(&bnx2i_dev_lock);
+       mutex_lock(&bnx2i_dev_lock);
        list_for_each_entry_safe(hba, temp, &adapter_list, link)
                bnx2i_unreg_one_device(hba);
-       read_unlock(&bnx2i_dev_lock);
+       mutex_unlock(&bnx2i_dev_lock);
 }
 
 
@@ -267,35 +281,35 @@ void bnx2i_unreg_dev_all(void)
  * @hba:       bnx2i adapter instance
  * @cnic:      cnic device handle
  *
- * Global resource lock and host adapter lock is held during critical sections
- *     below. This routine is called from cnic_register_driver() context and
- *     work horse thread which does majority of device specific initialization
+ * Global resource lock is held during critical sections below. This routine is
+ *     called from either cnic_register_driver() or device hot plug context and
+ *     and does majority of device specific initialization
  */
 static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic)
 {
        int rc;
 
-       read_lock(&bnx2i_dev_lock);
-       if (bnx2i_reg_device &&
-           !test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
-               rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba);
-               if (rc)         /* duplicate registration */
-                       printk(KERN_ERR "bnx2i- dev reg failed\n");
-
-               spin_lock(&hba->lock);
-               bnx2i_reg_device++;
+       mutex_lock(&bnx2i_dev_lock);
+       hba->cnic = cnic;
+       rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba);
+       if (!rc) {
                hba->age++;
-               spin_unlock(&hba->lock);
-
                set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
-       }
-       read_unlock(&bnx2i_dev_lock);
-
-       write_lock(&bnx2i_dev_lock);
-       list_add_tail(&hba->link, &adapter_list);
-       adapter_count++;
-       write_unlock(&bnx2i_dev_lock);
-       return 0;
+               list_add_tail(&hba->link, &adapter_list);
+               adapter_count++;
+       } else if (rc == -EBUSY)        /* duplicate registration */
+               printk(KERN_ALERT "bnx2i, duplicate registration"
+                                 "hba=%p, cnic=%p\n", hba, cnic);
+       else if (rc == -EAGAIN)
+               printk(KERN_ERR "bnx2i, driver not registered\n");
+       else if (rc == -EINVAL)
+               printk(KERN_ERR "bnx2i, invalid type %d\n", CNIC_ULP_ISCSI);
+       else
+               printk(KERN_ERR "bnx2i dev reg, unknown error, %d\n", rc);
+
+       mutex_unlock(&bnx2i_dev_lock);
+
+       return rc;
 }
 
 
@@ -323,8 +337,7 @@ void bnx2i_ulp_init(struct cnic_dev *dev)
        if (bnx2i_init_one(hba, dev)) {
                printk(KERN_ERR "bnx2i - hba %p init failed\n", hba);
                bnx2i_free_hba(hba);
-       } else
-               hba->cnic = dev;
+       }
 }
 
 
@@ -343,19 +356,15 @@ void bnx2i_ulp_exit(struct cnic_dev *dev)
                                 "found, dev 0x%p\n", dev);
                return;
        }
-       write_lock(&bnx2i_dev_lock);
+       mutex_lock(&bnx2i_dev_lock);
        list_del_init(&hba->link);
        adapter_count--;
 
        if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
                hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
                clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
-
-               spin_lock(&hba->lock);
-               bnx2i_reg_device--;
-               spin_unlock(&hba->lock);
        }
-       write_unlock(&bnx2i_dev_lock);
+       mutex_unlock(&bnx2i_dev_lock);
 
        bnx2i_free_hba(hba);
 }
@@ -374,9 +383,11 @@ static int __init bnx2i_mod_init(void)
 
        printk(KERN_INFO "%s", version);
 
-       if (!is_power_of_2(sq_size))
+       if (sq_size && !is_power_of_2(sq_size))
                sq_size = roundup_pow_of_two(sq_size);
 
+       mutex_init(&bnx2i_dev_lock);
+
        bnx2i_scsi_xport_template =
                        iscsi_register_transport(&bnx2i_iscsi_transport);
        if (!bnx2i_scsi_xport_template) {
@@ -412,7 +423,7 @@ static void __exit bnx2i_mod_exit(void)
 {
        struct bnx2i_hba *hba;
 
-       write_lock(&bnx2i_dev_lock);
+       mutex_lock(&bnx2i_dev_lock);
        while (!list_empty(&adapter_list)) {
                hba = list_entry(adapter_list.next, struct bnx2i_hba, link);
                list_del(&hba->link);
@@ -421,14 +432,11 @@ static void __exit bnx2i_mod_exit(void)
                if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
                        hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
                        clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
-                       bnx2i_reg_device--;
                }
 
-               write_unlock(&bnx2i_dev_lock);
                bnx2i_free_hba(hba);
-               write_lock(&bnx2i_dev_lock);
        }
-       write_unlock(&bnx2i_dev_lock);
+       mutex_unlock(&bnx2i_dev_lock);
 
        iscsi_unregister_transport(&bnx2i_iscsi_transport);
        cnic_unregister_driver(CNIC_ULP_ISCSI);