diff options
author | Stephen M. Cameron <scameron@beardog.cce.hp.com> | 2013-12-04 18:10:07 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-12-19 23:56:29 -0500 |
commit | 8a98db7386b5fed82dc1df25c904b6d0ae32a2cb (patch) | |
tree | 420021744c5931fd0a6b66a60582f16b0077f761 /drivers | |
parent | 95d8a25b52d551f631595ae4b5883d22a8d85a52 (diff) |
[SCSI] hpsa: use workqueue instead of kernel thread for lockup detection
Much simpler and avoids races starting/stopping the thread.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/hpsa.c | 103 | ||||
-rw-r--r-- | drivers/scsi/hpsa.h | 3 |
2 files changed, 28 insertions, 78 deletions
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 91e2d8398969..f929875a9187 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c | |||
@@ -168,10 +168,6 @@ static struct board_type products[] = { | |||
168 | 168 | ||
169 | static int number_of_controllers; | 169 | static int number_of_controllers; |
170 | 170 | ||
171 | static struct list_head hpsa_ctlr_list = LIST_HEAD_INIT(hpsa_ctlr_list); | ||
172 | static spinlock_t lockup_detector_lock; | ||
173 | static struct task_struct *hpsa_lockup_detector; | ||
174 | |||
175 | static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id); | 171 | static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id); |
176 | static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id); | 172 | static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id); |
177 | static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg); | 173 | static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg); |
@@ -4716,16 +4712,6 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) | |||
4716 | kfree(h); | 4712 | kfree(h); |
4717 | } | 4713 | } |
4718 | 4714 | ||
4719 | static void remove_ctlr_from_lockup_detector_list(struct ctlr_info *h) | ||
4720 | { | ||
4721 | assert_spin_locked(&lockup_detector_lock); | ||
4722 | if (!hpsa_lockup_detector) | ||
4723 | return; | ||
4724 | if (h->lockup_detected) | ||
4725 | return; /* already stopped the lockup detector */ | ||
4726 | list_del(&h->lockup_list); | ||
4727 | } | ||
4728 | |||
4729 | /* Called when controller lockup detected. */ | 4715 | /* Called when controller lockup detected. */ |
4730 | static void fail_all_cmds_on_list(struct ctlr_info *h, struct list_head *list) | 4716 | static void fail_all_cmds_on_list(struct ctlr_info *h, struct list_head *list) |
4731 | { | 4717 | { |
@@ -4744,8 +4730,6 @@ static void controller_lockup_detected(struct ctlr_info *h) | |||
4744 | { | 4730 | { |
4745 | unsigned long flags; | 4731 | unsigned long flags; |
4746 | 4732 | ||
4747 | assert_spin_locked(&lockup_detector_lock); | ||
4748 | remove_ctlr_from_lockup_detector_list(h); | ||
4749 | h->access.set_intr_mask(h, HPSA_INTR_OFF); | 4733 | h->access.set_intr_mask(h, HPSA_INTR_OFF); |
4750 | spin_lock_irqsave(&h->lock, flags); | 4734 | spin_lock_irqsave(&h->lock, flags); |
4751 | h->lockup_detected = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); | 4735 | h->lockup_detected = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); |
@@ -4765,7 +4749,6 @@ static void detect_controller_lockup(struct ctlr_info *h) | |||
4765 | u32 heartbeat; | 4749 | u32 heartbeat; |
4766 | unsigned long flags; | 4750 | unsigned long flags; |
4767 | 4751 | ||
4768 | assert_spin_locked(&lockup_detector_lock); | ||
4769 | now = get_jiffies_64(); | 4752 | now = get_jiffies_64(); |
4770 | /* If we've received an interrupt recently, we're ok. */ | 4753 | /* If we've received an interrupt recently, we're ok. */ |
4771 | if (time_after64(h->last_intr_timestamp + | 4754 | if (time_after64(h->last_intr_timestamp + |
@@ -4795,68 +4778,22 @@ static void detect_controller_lockup(struct ctlr_info *h) | |||
4795 | h->last_heartbeat_timestamp = now; | 4778 | h->last_heartbeat_timestamp = now; |
4796 | } | 4779 | } |
4797 | 4780 | ||
4798 | static int detect_controller_lockup_thread(void *notused) | 4781 | static void hpsa_monitor_ctlr_worker(struct work_struct *work) |
4799 | { | ||
4800 | struct ctlr_info *h; | ||
4801 | unsigned long flags; | ||
4802 | |||
4803 | while (1) { | ||
4804 | struct list_head *this, *tmp; | ||
4805 | |||
4806 | schedule_timeout_interruptible(HEARTBEAT_SAMPLE_INTERVAL); | ||
4807 | if (kthread_should_stop()) | ||
4808 | break; | ||
4809 | spin_lock_irqsave(&lockup_detector_lock, flags); | ||
4810 | list_for_each_safe(this, tmp, &hpsa_ctlr_list) { | ||
4811 | h = list_entry(this, struct ctlr_info, lockup_list); | ||
4812 | detect_controller_lockup(h); | ||
4813 | } | ||
4814 | spin_unlock_irqrestore(&lockup_detector_lock, flags); | ||
4815 | } | ||
4816 | return 0; | ||
4817 | } | ||
4818 | |||
4819 | static void add_ctlr_to_lockup_detector_list(struct ctlr_info *h) | ||
4820 | { | 4782 | { |
4821 | unsigned long flags; | 4783 | unsigned long flags; |
4822 | 4784 | struct ctlr_info *h = container_of(to_delayed_work(work), | |
4823 | h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; | 4785 | struct ctlr_info, monitor_ctlr_work); |
4824 | spin_lock_irqsave(&lockup_detector_lock, flags); | 4786 | detect_controller_lockup(h); |
4825 | list_add_tail(&h->lockup_list, &hpsa_ctlr_list); | 4787 | if (h->lockup_detected) |
4826 | spin_unlock_irqrestore(&lockup_detector_lock, flags); | 4788 | return; |
4827 | } | 4789 | spin_lock_irqsave(&h->lock, flags); |
4828 | 4790 | if (h->remove_in_progress) { | |
4829 | static void start_controller_lockup_detector(struct ctlr_info *h) | 4791 | spin_unlock_irqrestore(&h->lock, flags); |
4830 | { | ||
4831 | /* Start the lockup detector thread if not already started */ | ||
4832 | if (!hpsa_lockup_detector) { | ||
4833 | spin_lock_init(&lockup_detector_lock); | ||
4834 | hpsa_lockup_detector = | ||
4835 | kthread_run(detect_controller_lockup_thread, | ||
4836 | NULL, HPSA); | ||
4837 | } | ||
4838 | if (!hpsa_lockup_detector) { | ||
4839 | dev_warn(&h->pdev->dev, | ||
4840 | "Could not start lockup detector thread\n"); | ||
4841 | return; | 4792 | return; |
4842 | } | 4793 | } |
4843 | add_ctlr_to_lockup_detector_list(h); | 4794 | schedule_delayed_work(&h->monitor_ctlr_work, |
4844 | } | 4795 | h->heartbeat_sample_interval); |
4845 | 4796 | spin_unlock_irqrestore(&h->lock, flags); | |
4846 | static void stop_controller_lockup_detector(struct ctlr_info *h) | ||
4847 | { | ||
4848 | unsigned long flags; | ||
4849 | |||
4850 | spin_lock_irqsave(&lockup_detector_lock, flags); | ||
4851 | remove_ctlr_from_lockup_detector_list(h); | ||
4852 | /* If the list of ctlr's to monitor is empty, stop the thread */ | ||
4853 | if (list_empty(&hpsa_ctlr_list)) { | ||
4854 | spin_unlock_irqrestore(&lockup_detector_lock, flags); | ||
4855 | kthread_stop(hpsa_lockup_detector); | ||
4856 | spin_lock_irqsave(&lockup_detector_lock, flags); | ||
4857 | hpsa_lockup_detector = NULL; | ||
4858 | } | ||
4859 | spin_unlock_irqrestore(&lockup_detector_lock, flags); | ||
4860 | } | 4797 | } |
4861 | 4798 | ||
4862 | static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | 4799 | static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) |
@@ -5004,7 +4941,12 @@ reinit_after_soft_reset: | |||
5004 | 4941 | ||
5005 | hpsa_hba_inquiry(h); | 4942 | hpsa_hba_inquiry(h); |
5006 | hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */ | 4943 | hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */ |
5007 | start_controller_lockup_detector(h); | 4944 | |
4945 | /* Monitor the controller for firmware lockups */ | ||
4946 | h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; | ||
4947 | INIT_DELAYED_WORK(&h->monitor_ctlr_work, hpsa_monitor_ctlr_worker); | ||
4948 | schedule_delayed_work(&h->monitor_ctlr_work, | ||
4949 | h->heartbeat_sample_interval); | ||
5008 | return 0; | 4950 | return 0; |
5009 | 4951 | ||
5010 | clean4: | 4952 | clean4: |
@@ -5079,13 +5021,20 @@ static void hpsa_free_device_info(struct ctlr_info *h) | |||
5079 | static void hpsa_remove_one(struct pci_dev *pdev) | 5021 | static void hpsa_remove_one(struct pci_dev *pdev) |
5080 | { | 5022 | { |
5081 | struct ctlr_info *h; | 5023 | struct ctlr_info *h; |
5024 | unsigned long flags; | ||
5082 | 5025 | ||
5083 | if (pci_get_drvdata(pdev) == NULL) { | 5026 | if (pci_get_drvdata(pdev) == NULL) { |
5084 | dev_err(&pdev->dev, "unable to remove device\n"); | 5027 | dev_err(&pdev->dev, "unable to remove device\n"); |
5085 | return; | 5028 | return; |
5086 | } | 5029 | } |
5087 | h = pci_get_drvdata(pdev); | 5030 | h = pci_get_drvdata(pdev); |
5088 | stop_controller_lockup_detector(h); | 5031 | |
5032 | /* Get rid of any controller monitoring work items */ | ||
5033 | spin_lock_irqsave(&h->lock, flags); | ||
5034 | h->remove_in_progress = 1; | ||
5035 | cancel_delayed_work(&h->monitor_ctlr_work); | ||
5036 | spin_unlock_irqrestore(&h->lock, flags); | ||
5037 | |||
5089 | hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ | 5038 | hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ |
5090 | hpsa_shutdown(pdev); | 5039 | hpsa_shutdown(pdev); |
5091 | iounmap(h->vaddr); | 5040 | iounmap(h->vaddr); |
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 5f3f72f90bc9..01c328349c83 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h | |||
@@ -135,7 +135,8 @@ struct ctlr_info { | |||
135 | u32 heartbeat_sample_interval; | 135 | u32 heartbeat_sample_interval; |
136 | atomic_t firmware_flash_in_progress; | 136 | atomic_t firmware_flash_in_progress; |
137 | u32 lockup_detected; | 137 | u32 lockup_detected; |
138 | struct list_head lockup_list; | 138 | struct delayed_work monitor_ctlr_work; |
139 | int remove_in_progress; | ||
139 | u32 fifo_recently_full; | 140 | u32 fifo_recently_full; |
140 | /* Address of h->q[x] is passed to intr handler to know which queue */ | 141 | /* Address of h->q[x] is passed to intr handler to know which queue */ |
141 | u8 q[MAX_REPLY_QUEUES]; | 142 | u8 q[MAX_REPLY_QUEUES]; |