diff options
Diffstat (limited to 'drivers/scsi/bnx2i/bnx2i_init.c')
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i_init.c | 174 |
1 files changed, 150 insertions, 24 deletions
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c index 6adbdc34a9a5..1a947f1b9729 100644 --- a/drivers/scsi/bnx2i/bnx2i_init.c +++ b/drivers/scsi/bnx2i/bnx2i_init.c @@ -1,6 +1,6 @@ /* bnx2i.c: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2006 - 2010 Broadcom Corporation + * Copyright (c) 2006 - 2011 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * @@ -18,8 +18,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list); static u32 adapter_count; #define DRV_MODULE_NAME "bnx2i" -#define DRV_MODULE_VERSION "2.6.2.3" -#define DRV_MODULE_RELDATE "Dec 31, 2010" +#define DRV_MODULE_VERSION "2.7.0.3" +#define DRV_MODULE_RELDATE "Jun 15, 2011" static char version[] __devinitdata = "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \ @@ -30,7 +30,7 @@ MODULE_AUTHOR("Anil Veerabhadrappa <anilgv@broadcom.com> and " "Eddie Wai <eddie.wai@broadcom.com>"); MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/57710/57711/57712" - " iSCSI Driver"); + "/57800/57810/57840 iSCSI Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_MODULE_VERSION); @@ -40,7 +40,7 @@ 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; +unsigned int event_coal_div = 2; module_param(event_coal_div, int, 0664); MODULE_PARM_DESC(event_coal_div, "Event Coalescing Divide Factor"); @@ -66,6 +66,15 @@ MODULE_PARM_DESC(rq_size, "Configure RQ size"); u64 iscsi_error_mask = 0x00; +DEFINE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu); + +static int bnx2i_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu); +/* notification function for CPU hotplug events */ +static struct notifier_block bnx2i_cpu_notifier = { + .notifier_call = bnx2i_cpu_callback, +}; + /** * bnx2i_identify_device - identifies NetXtreme II device type @@ -88,11 +97,20 @@ void bnx2i_identify_device(struct bnx2i_hba *hba) (hba->pci_did == PCI_DEVICE_ID_NX2_5709S)) { 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_57711E || - hba->pci_did == PCI_DEVICE_ID_NX2_57712 || - hba->pci_did == PCI_DEVICE_ID_NX2_57712E) + } 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_57711E || + hba->pci_did == PCI_DEVICE_ID_NX2_57712 || + hba->pci_did == PCI_DEVICE_ID_NX2_57712E || + hba->pci_did == PCI_DEVICE_ID_NX2_57800 || + hba->pci_did == PCI_DEVICE_ID_NX2_57800_MF || + hba->pci_did == PCI_DEVICE_ID_NX2_57800_VF || + hba->pci_did == PCI_DEVICE_ID_NX2_57810 || + hba->pci_did == PCI_DEVICE_ID_NX2_57810_MF || + hba->pci_did == PCI_DEVICE_ID_NX2_57810_VF || + hba->pci_did == PCI_DEVICE_ID_NX2_57840 || + hba->pci_did == PCI_DEVICE_ID_NX2_57840_MF || + hba->pci_did == PCI_DEVICE_ID_NX2_57840_VF) set_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type); else printk(KERN_ALERT "bnx2i: unknown device, 0x%x\n", @@ -163,21 +181,14 @@ void bnx2i_start(void *handle) struct bnx2i_hba *hba = handle; int i = HZ; - if (!hba->cnic->max_iscsi_conn) { - printk(KERN_ALERT "bnx2i: dev %s does not support " - "iSCSI\n", hba->netdev->name); + /* + * We should never register devices that don't support iSCSI + * (see bnx2i_init_one), so something is wrong if we try to + * start a iSCSI adapter on hardware with 0 supported iSCSI + * connections + */ + BUG_ON(!hba->cnic->max_iscsi_conn); - if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { - mutex_lock(&bnx2i_dev_lock); - list_del_init(&hba->link); - adapter_count--; - hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); - clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); - mutex_unlock(&bnx2i_dev_lock); - bnx2i_free_hba(hba); - } - return; - } bnx2i_send_fw_iscsi_init_msg(hba); while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--) msleep(BNX2I_INIT_POLL_TIME); @@ -281,6 +292,13 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic) int rc; mutex_lock(&bnx2i_dev_lock); + if (!cnic->max_iscsi_conn) { + printk(KERN_ALERT "bnx2i: dev %s does not support " + "iSCSI\n", hba->netdev->name); + rc = -EOPNOTSUPP; + goto out; + } + hba->cnic = cnic; rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba); if (!rc) { @@ -298,6 +316,7 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic) else printk(KERN_ERR "bnx2i dev reg, unknown error, %d\n", rc); +out: mutex_unlock(&bnx2i_dev_lock); return rc; @@ -362,6 +381,91 @@ void bnx2i_ulp_exit(struct cnic_dev *dev) /** + * bnx2i_percpu_thread_create - Create a receive thread for an + * online CPU + * + * @cpu: cpu index for the online cpu + */ +static void bnx2i_percpu_thread_create(unsigned int cpu) +{ + struct bnx2i_percpu_s *p; + struct task_struct *thread; + + p = &per_cpu(bnx2i_percpu, cpu); + + thread = kthread_create(bnx2i_percpu_io_thread, (void *)p, + "bnx2i_thread/%d", cpu); + /* bind thread to the cpu */ + if (likely(!IS_ERR(thread))) { + kthread_bind(thread, cpu); + p->iothread = thread; + wake_up_process(thread); + } +} + + +static void bnx2i_percpu_thread_destroy(unsigned int cpu) +{ + struct bnx2i_percpu_s *p; + struct task_struct *thread; + struct bnx2i_work *work, *tmp; + + /* Prevent any new work from being queued for this CPU */ + p = &per_cpu(bnx2i_percpu, cpu); + spin_lock_bh(&p->p_work_lock); + thread = p->iothread; + p->iothread = NULL; + + /* Free all work in the list */ + list_for_each_entry_safe(work, tmp, &p->work_list, list) { + list_del_init(&work->list); + bnx2i_process_scsi_cmd_resp(work->session, + work->bnx2i_conn, &work->cqe); + kfree(work); + } + + spin_unlock_bh(&p->p_work_lock); + if (thread) + kthread_stop(thread); +} + + +/** + * bnx2i_cpu_callback - Handler for CPU hotplug events + * + * @nfb: The callback data block + * @action: The event triggering the callback + * @hcpu: The index of the CPU that the event is for + * + * This creates or destroys per-CPU data for iSCSI + * + * Returns NOTIFY_OK always. + */ +static int bnx2i_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + unsigned cpu = (unsigned long)hcpu; + + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + printk(KERN_INFO "bnx2i: CPU %x online: Create Rx thread\n", + cpu); + bnx2i_percpu_thread_create(cpu); + break; + case CPU_DEAD: + case CPU_DEAD_FROZEN: + printk(KERN_INFO "CPU %x offline: Remove Rx thread\n", cpu); + bnx2i_percpu_thread_destroy(cpu); + break; + default: + break; + } + return NOTIFY_OK; +} + + +/** * bnx2i_mod_init - module init entry point * * initialize any driver wide global data structures such as endpoint pool, @@ -371,6 +475,8 @@ void bnx2i_ulp_exit(struct cnic_dev *dev) static int __init bnx2i_mod_init(void) { int err; + unsigned cpu = 0; + struct bnx2i_percpu_s *p; printk(KERN_INFO "%s", version); @@ -393,6 +499,20 @@ static int __init bnx2i_mod_init(void) goto unreg_xport; } + /* Create percpu kernel threads to handle iSCSI I/O completions */ + for_each_possible_cpu(cpu) { + p = &per_cpu(bnx2i_percpu, cpu); + INIT_LIST_HEAD(&p->work_list); + spin_lock_init(&p->p_work_lock); + p->iothread = NULL; + } + + for_each_online_cpu(cpu) + bnx2i_percpu_thread_create(cpu); + + /* Initialize per CPU interrupt thread */ + register_hotcpu_notifier(&bnx2i_cpu_notifier); + return 0; unreg_xport: @@ -413,6 +533,7 @@ out: static void __exit bnx2i_mod_exit(void) { struct bnx2i_hba *hba; + unsigned cpu = 0; mutex_lock(&bnx2i_dev_lock); while (!list_empty(&adapter_list)) { @@ -430,6 +551,11 @@ static void __exit bnx2i_mod_exit(void) } mutex_unlock(&bnx2i_dev_lock); + unregister_hotcpu_notifier(&bnx2i_cpu_notifier); + + for_each_online_cpu(cpu) + bnx2i_percpu_thread_destroy(cpu); + iscsi_unregister_transport(&bnx2i_iscsi_transport); cnic_unregister_driver(CNIC_ULP_ISCSI); } |