scsi: qedi: Convert to hotplug state machine
[linux-2.6-block.git] / drivers / scsi / qedi / qedi_main.c
index 19ead8d17e55fbfc20315aac9111d7da4a175b7d..5eda21d903e93dfc96702552d2de9deb7f01c734 100644 (file)
@@ -1612,30 +1612,29 @@ static int qedi_percpu_io_thread(void *arg)
        return 0;
 }
 
-static void qedi_percpu_thread_create(unsigned int cpu)
+static int qedi_cpu_online(unsigned int cpu)
 {
-       struct qedi_percpu_s *p;
+       struct qedi_percpu_s *p = this_cpu_ptr(&qedi_percpu);
        struct task_struct *thread;
 
-       p = &per_cpu(qedi_percpu, cpu);
-
        thread = kthread_create_on_node(qedi_percpu_io_thread, (void *)p,
                                        cpu_to_node(cpu),
                                        "qedi_thread/%d", cpu);
-       if (likely(!IS_ERR(thread))) {
-               kthread_bind(thread, cpu);
-               p->iothread = thread;
-               wake_up_process(thread);
-       }
+       if (IS_ERR(thread))
+               return PTR_ERR(thread);
+
+       kthread_bind(thread, cpu);
+       p->iothread = thread;
+       wake_up_process(thread);
+       return 0;
 }
 
-static void qedi_percpu_thread_destroy(unsigned int cpu)
+static int qedi_cpu_offline(unsigned int cpu)
 {
-       struct qedi_percpu_s *p;
-       struct task_struct *thread;
+       struct qedi_percpu_s *p = this_cpu_ptr(&qedi_percpu);
        struct qedi_work *work, *tmp;
+       struct task_struct *thread;
 
-       p = &per_cpu(qedi_percpu, cpu);
        spin_lock_bh(&p->p_work_lock);
        thread = p->iothread;
        p->iothread = NULL;
@@ -1650,35 +1649,9 @@ static void qedi_percpu_thread_destroy(unsigned int cpu)
        spin_unlock_bh(&p->p_work_lock);
        if (thread)
                kthread_stop(thread);
+       return 0;
 }
 
-static int qedi_cpu_callback(struct notifier_block *nfb,
-                            unsigned long action, void *hcpu)
-{
-       unsigned int cpu = (unsigned long)hcpu;
-
-       switch (action) {
-       case CPU_ONLINE:
-       case CPU_ONLINE_FROZEN:
-               QEDI_ERR(NULL, "CPU %d online.\n", cpu);
-               qedi_percpu_thread_create(cpu);
-               break;
-       case CPU_DEAD:
-       case CPU_DEAD_FROZEN:
-               QEDI_ERR(NULL, "CPU %d offline.\n", cpu);
-               qedi_percpu_thread_destroy(cpu);
-               break;
-       default:
-               break;
-       }
-
-       return NOTIFY_OK;
-}
-
-static struct notifier_block qedi_cpu_notifier = {
-       .notifier_call = qedi_cpu_callback,
-};
-
 void qedi_reset_host_mtu(struct qedi_ctx *qedi, u16 mtu)
 {
        struct qed_ll2_params params;
@@ -2038,6 +2011,8 @@ static struct pci_device_id qedi_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, qedi_pci_tbl);
 
+static enum cpuhp_state qedi_cpuhp_state;
+
 static struct pci_driver qedi_pci_driver = {
        .name = QEDI_MODULE_NAME,
        .id_table = qedi_pci_tbl,
@@ -2047,16 +2022,13 @@ static struct pci_driver qedi_pci_driver = {
 
 static int __init qedi_init(void)
 {
-       int rc = 0;
-       int ret;
        struct qedi_percpu_s *p;
-       unsigned int cpu = 0;
+       int cpu, rc = 0;
 
        qedi_ops = qed_get_iscsi_ops();
        if (!qedi_ops) {
                QEDI_ERR(NULL, "Failed to get qed iSCSI operations\n");
-               rc = -EINVAL;
-               goto exit_qedi_init_0;
+               return -EINVAL;
        }
 
 #ifdef CONFIG_DEBUG_FS
@@ -2070,15 +2042,6 @@ static int __init qedi_init(void)
                goto exit_qedi_init_1;
        }
 
-       register_hotcpu_notifier(&qedi_cpu_notifier);
-
-       ret = pci_register_driver(&qedi_pci_driver);
-       if (ret) {
-               QEDI_ERR(NULL, "Failed to register driver\n");
-               rc = -EINVAL;
-               goto exit_qedi_init_2;
-       }
-
        for_each_possible_cpu(cpu) {
                p = &per_cpu(qedi_percpu, cpu);
                INIT_LIST_HEAD(&p->work_list);
@@ -2086,11 +2049,22 @@ static int __init qedi_init(void)
                p->iothread = NULL;
        }
 
-       for_each_online_cpu(cpu)
-               qedi_percpu_thread_create(cpu);
+       rc = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "scsi/qedi:online",
+                              qedi_cpu_online, qedi_cpu_offline);
+       if (rc < 0)
+               goto exit_qedi_init_2;
+       qedi_cpuhp_state = rc;
 
-       return rc;
+       rc = pci_register_driver(&qedi_pci_driver);
+       if (rc) {
+               QEDI_ERR(NULL, "Failed to register driver\n");
+               goto exit_qedi_hp;
+       }
+
+       return 0;
 
+exit_qedi_hp:
+       cpuhp_remove_state(qedi_cpuhp_state);
 exit_qedi_init_2:
        iscsi_unregister_transport(&qedi_iscsi_transport);
 exit_qedi_init_1:
@@ -2098,19 +2072,13 @@ exit_qedi_init_1:
        qedi_dbg_exit();
 #endif
        qed_put_iscsi_ops();
-exit_qedi_init_0:
        return rc;
 }
 
 static void __exit qedi_cleanup(void)
 {
-       unsigned int cpu = 0;
-
-       for_each_online_cpu(cpu)
-               qedi_percpu_thread_destroy(cpu);
-
        pci_unregister_driver(&qedi_pci_driver);
-       unregister_hotcpu_notifier(&qedi_cpu_notifier);
+       cpuhp_remove_state(qedi_cpuhp_state);
        iscsi_unregister_transport(&qedi_iscsi_transport);
 
 #ifdef CONFIG_DEBUG_FS