diff options
author | Boaz Harrosh <bharrosh@panasas.com> | 2008-02-27 18:27:16 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-02-27 18:53:43 -0500 |
commit | b31ddd31c266c2ad1b708cad0d3d8e0aa7fa2737 (patch) | |
tree | ecc7a9aeb4eb74a103b15423ac6aeb60f4be7420 | |
parent | 31ed0bf439a15363c28c7a239f52eb127cb6feb3 (diff) |
[SCSI] gdth: bugfix for the at-exit problems
gdth_exit would first remove all cards then stop the timer
and would not sync with the timer function. This caused a crash
in gdth_timer() when module was unloaded.
So del_timer_sync the timer before we delete the cards.
also the reboot notifier function would crash. So clean
that up and fix the crashes.
Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Tested-by: Joerg Dorchain: <joerg@dorchain.net>
Tested-by: Stefan Priebe <s.priebe@allied-internet.ag>
Tested-by: Jon Chelton <jchelton@ffpglobal.com>
Cc: Stable Tree <stable@kernel.org>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r-- | drivers/scsi/gdth.c | 82 |
1 files changed, 28 insertions, 54 deletions
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 6d67f5c0eb8e..23d1a28b929d 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c | |||
@@ -182,7 +182,6 @@ static int gdth_ioctl(struct inode *inode, struct file *filep, | |||
182 | unsigned int cmd, unsigned long arg); | 182 | unsigned int cmd, unsigned long arg); |
183 | 183 | ||
184 | static void gdth_flush(gdth_ha_str *ha); | 184 | static void gdth_flush(gdth_ha_str *ha); |
185 | static int gdth_halt(struct notifier_block *nb, ulong event, void *buf); | ||
186 | static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *)); | 185 | static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *)); |
187 | static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp, | 186 | static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp, |
188 | struct gdth_cmndinfo *cmndinfo); | 187 | struct gdth_cmndinfo *cmndinfo); |
@@ -417,12 +416,6 @@ static inline void gdth_set_sglist(struct scsi_cmnd *cmd, | |||
417 | #include "gdth_proc.h" | 416 | #include "gdth_proc.h" |
418 | #include "gdth_proc.c" | 417 | #include "gdth_proc.c" |
419 | 418 | ||
420 | /* notifier block to get a notify on system shutdown/halt/reboot */ | ||
421 | static struct notifier_block gdth_notifier = { | ||
422 | gdth_halt, NULL, 0 | ||
423 | }; | ||
424 | static int notifier_disabled = 0; | ||
425 | |||
426 | static gdth_ha_str *gdth_find_ha(int hanum) | 419 | static gdth_ha_str *gdth_find_ha(int hanum) |
427 | { | 420 | { |
428 | gdth_ha_str *ha; | 421 | gdth_ha_str *ha; |
@@ -3794,6 +3787,8 @@ static void gdth_timeout(ulong data) | |||
3794 | gdth_ha_str *ha; | 3787 | gdth_ha_str *ha; |
3795 | ulong flags; | 3788 | ulong flags; |
3796 | 3789 | ||
3790 | BUG_ON(list_empty(&gdth_instances)); | ||
3791 | |||
3797 | ha = list_first_entry(&gdth_instances, gdth_ha_str, list); | 3792 | ha = list_first_entry(&gdth_instances, gdth_ha_str, list); |
3798 | spin_lock_irqsave(&ha->smp_lock, flags); | 3793 | spin_lock_irqsave(&ha->smp_lock, flags); |
3799 | 3794 | ||
@@ -4669,45 +4664,6 @@ static void gdth_flush(gdth_ha_str *ha) | |||
4669 | } | 4664 | } |
4670 | } | 4665 | } |
4671 | 4666 | ||
4672 | /* shutdown routine */ | ||
4673 | static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) | ||
4674 | { | ||
4675 | gdth_ha_str *ha; | ||
4676 | #ifndef __alpha__ | ||
4677 | gdth_cmd_str gdtcmd; | ||
4678 | char cmnd[MAX_COMMAND_SIZE]; | ||
4679 | #endif | ||
4680 | |||
4681 | if (notifier_disabled) | ||
4682 | return NOTIFY_OK; | ||
4683 | |||
4684 | TRACE2(("gdth_halt() event %d\n",(int)event)); | ||
4685 | if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF) | ||
4686 | return NOTIFY_DONE; | ||
4687 | |||
4688 | notifier_disabled = 1; | ||
4689 | printk("GDT-HA: Flushing all host drives .. "); | ||
4690 | list_for_each_entry(ha, &gdth_instances, list) { | ||
4691 | gdth_flush(ha); | ||
4692 | |||
4693 | #ifndef __alpha__ | ||
4694 | /* controller reset */ | ||
4695 | memset(cmnd, 0xff, MAX_COMMAND_SIZE); | ||
4696 | gdtcmd.BoardNode = LOCALBOARD; | ||
4697 | gdtcmd.Service = CACHESERVICE; | ||
4698 | gdtcmd.OpCode = GDT_RESET; | ||
4699 | TRACE2(("gdth_halt(): reset controller %d\n", ha->hanum)); | ||
4700 | gdth_execute(ha->shost, &gdtcmd, cmnd, 10, NULL); | ||
4701 | #endif | ||
4702 | } | ||
4703 | printk("Done.\n"); | ||
4704 | |||
4705 | #ifdef GDTH_STATISTICS | ||
4706 | del_timer(&gdth_timer); | ||
4707 | #endif | ||
4708 | return NOTIFY_OK; | ||
4709 | } | ||
4710 | |||
4711 | /* configure lun */ | 4667 | /* configure lun */ |
4712 | static int gdth_slave_configure(struct scsi_device *sdev) | 4668 | static int gdth_slave_configure(struct scsi_device *sdev) |
4713 | { | 4669 | { |
@@ -5142,13 +5098,13 @@ static void gdth_remove_one(gdth_ha_str *ha) | |||
5142 | 5098 | ||
5143 | scsi_remove_host(shp); | 5099 | scsi_remove_host(shp); |
5144 | 5100 | ||
5101 | gdth_flush(ha); | ||
5102 | |||
5145 | if (ha->sdev) { | 5103 | if (ha->sdev) { |
5146 | scsi_free_host_dev(ha->sdev); | 5104 | scsi_free_host_dev(ha->sdev); |
5147 | ha->sdev = NULL; | 5105 | ha->sdev = NULL; |
5148 | } | 5106 | } |
5149 | 5107 | ||
5150 | gdth_flush(ha); | ||
5151 | |||
5152 | if (shp->irq) | 5108 | if (shp->irq) |
5153 | free_irq(shp->irq,ha); | 5109 | free_irq(shp->irq,ha); |
5154 | 5110 | ||
@@ -5174,6 +5130,24 @@ static void gdth_remove_one(gdth_ha_str *ha) | |||
5174 | scsi_host_put(shp); | 5130 | scsi_host_put(shp); |
5175 | } | 5131 | } |
5176 | 5132 | ||
5133 | static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) | ||
5134 | { | ||
5135 | gdth_ha_str *ha; | ||
5136 | |||
5137 | TRACE2(("gdth_halt() event %d\n", (int)event)); | ||
5138 | if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF) | ||
5139 | return NOTIFY_DONE; | ||
5140 | |||
5141 | list_for_each_entry(ha, &gdth_instances, list) | ||
5142 | gdth_flush(ha); | ||
5143 | |||
5144 | return NOTIFY_OK; | ||
5145 | } | ||
5146 | |||
5147 | static struct notifier_block gdth_notifier = { | ||
5148 | gdth_halt, NULL, 0 | ||
5149 | }; | ||
5150 | |||
5177 | static int __init gdth_init(void) | 5151 | static int __init gdth_init(void) |
5178 | { | 5152 | { |
5179 | if (disable) { | 5153 | if (disable) { |
@@ -5236,7 +5210,6 @@ static int __init gdth_init(void) | |||
5236 | add_timer(&gdth_timer); | 5210 | add_timer(&gdth_timer); |
5237 | #endif | 5211 | #endif |
5238 | major = register_chrdev(0,"gdth", &gdth_fops); | 5212 | major = register_chrdev(0,"gdth", &gdth_fops); |
5239 | notifier_disabled = 0; | ||
5240 | register_reboot_notifier(&gdth_notifier); | 5213 | register_reboot_notifier(&gdth_notifier); |
5241 | gdth_polling = FALSE; | 5214 | gdth_polling = FALSE; |
5242 | return 0; | 5215 | return 0; |
@@ -5246,14 +5219,15 @@ static void __exit gdth_exit(void) | |||
5246 | { | 5219 | { |
5247 | gdth_ha_str *ha; | 5220 | gdth_ha_str *ha; |
5248 | 5221 | ||
5249 | list_for_each_entry(ha, &gdth_instances, list) | 5222 | unregister_chrdev(major, "gdth"); |
5250 | gdth_remove_one(ha); | 5223 | unregister_reboot_notifier(&gdth_notifier); |
5251 | 5224 | ||
5252 | #ifdef GDTH_STATISTICS | 5225 | #ifdef GDTH_STATISTICS |
5253 | del_timer(&gdth_timer); | 5226 | del_timer_sync(&gdth_timer); |
5254 | #endif | 5227 | #endif |
5255 | unregister_chrdev(major,"gdth"); | 5228 | |
5256 | unregister_reboot_notifier(&gdth_notifier); | 5229 | list_for_each_entry(ha, &gdth_instances, list) |
5230 | gdth_remove_one(ha); | ||
5257 | } | 5231 | } |
5258 | 5232 | ||
5259 | module_init(gdth_init); | 5233 | module_init(gdth_init); |