diff options
author | Salyzyn, Mark <mark_salyzyn@adaptec.com> | 2007-06-12 09:33:54 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-06-17 16:00:47 -0400 |
commit | 29c976844d0bef07d97babc8db60fa6c46788133 (patch) | |
tree | 9543cef49748d0fe7ac08a5a1780c213e0fc37bd /drivers/scsi/aacraid/linit.c | |
parent | 1a655040c24ebf3954ad5cf8848391cb420b1ffb (diff) |
[SCSI] aacraid: add user initiated reset
Add the ability for an application to issue a hardware reset to the
adapter via sysfs. Typical uses include restarting the adapter after it
has been flashed. Bumped revision number for the driver and added a
feature to periodically check the adapter's health (check_interval),
update the adapter's concept of time (update_interval) and block
checking/resetting of the adapter (check_reset).
Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/aacraid/linit.c')
-rw-r--r-- | drivers/scsi/aacraid/linit.c | 46 |
1 files changed, 43 insertions, 3 deletions
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 6f92d077679f..f8c2aaf72aff 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c | |||
@@ -39,10 +39,8 @@ | |||
39 | #include <linux/pci.h> | 39 | #include <linux/pci.h> |
40 | #include <linux/slab.h> | 40 | #include <linux/slab.h> |
41 | #include <linux/spinlock.h> | 41 | #include <linux/spinlock.h> |
42 | #include <linux/dma-mapping.h> | ||
43 | #include <linux/syscalls.h> | 42 | #include <linux/syscalls.h> |
44 | #include <linux/delay.h> | 43 | #include <linux/delay.h> |
45 | #include <linux/smp_lock.h> | ||
46 | #include <linux/kthread.h> | 44 | #include <linux/kthread.h> |
47 | #include <asm/semaphore.h> | 45 | #include <asm/semaphore.h> |
48 | 46 | ||
@@ -581,6 +579,14 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) | |||
581 | ssleep(1); | 579 | ssleep(1); |
582 | } | 580 | } |
583 | printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME); | 581 | printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME); |
582 | /* | ||
583 | * This adapter needs a blind reset, only do so for Adapters that | ||
584 | * support a register, instead of a commanded, reset. | ||
585 | */ | ||
586 | if ((aac->supplement_adapter_info.SupportedOptions2 & | ||
587 | le32_to_cpu(AAC_OPTION_MU_RESET|AAC_OPTION_IGNORE_RESET)) == | ||
588 | le32_to_cpu(AAC_OPTION_MU_RESET)) | ||
589 | aac_reset_adapter(aac, 2); /* Bypass wait for command quiesce */ | ||
584 | return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */ | 590 | return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */ |
585 | } | 591 | } |
586 | 592 | ||
@@ -788,6 +794,31 @@ static ssize_t aac_show_max_id(struct class_device *class_dev, char *buf) | |||
788 | class_to_shost(class_dev)->max_id); | 794 | class_to_shost(class_dev)->max_id); |
789 | } | 795 | } |
790 | 796 | ||
797 | static ssize_t aac_store_reset_adapter(struct class_device *class_dev, | ||
798 | const char *buf, size_t count) | ||
799 | { | ||
800 | int retval = -EACCES; | ||
801 | |||
802 | if (!capable(CAP_SYS_ADMIN)) | ||
803 | return retval; | ||
804 | retval = aac_reset_adapter((struct aac_dev*)class_to_shost(class_dev)->hostdata, buf[0] == '!'); | ||
805 | if (retval >= 0) | ||
806 | retval = count; | ||
807 | return retval; | ||
808 | } | ||
809 | |||
810 | static ssize_t aac_show_reset_adapter(struct class_device *class_dev, | ||
811 | char *buf) | ||
812 | { | ||
813 | struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata; | ||
814 | int len, tmp; | ||
815 | |||
816 | tmp = aac_adapter_check_health(dev); | ||
817 | if ((tmp == 0) && dev->in_reset) | ||
818 | tmp = -EBUSY; | ||
819 | len = snprintf(buf, PAGE_SIZE, "0x%x", tmp); | ||
820 | return len; | ||
821 | } | ||
791 | 822 | ||
792 | static struct class_device_attribute aac_model = { | 823 | static struct class_device_attribute aac_model = { |
793 | .attr = { | 824 | .attr = { |
@@ -845,6 +876,14 @@ static struct class_device_attribute aac_max_id = { | |||
845 | }, | 876 | }, |
846 | .show = aac_show_max_id, | 877 | .show = aac_show_max_id, |
847 | }; | 878 | }; |
879 | static struct class_device_attribute aac_reset = { | ||
880 | .attr = { | ||
881 | .name = "reset_host", | ||
882 | .mode = S_IWUSR|S_IRUGO, | ||
883 | }, | ||
884 | .store = aac_store_reset_adapter, | ||
885 | .show = aac_show_reset_adapter, | ||
886 | }; | ||
848 | 887 | ||
849 | static struct class_device_attribute *aac_attrs[] = { | 888 | static struct class_device_attribute *aac_attrs[] = { |
850 | &aac_model, | 889 | &aac_model, |
@@ -855,6 +894,7 @@ static struct class_device_attribute *aac_attrs[] = { | |||
855 | &aac_serial_number, | 894 | &aac_serial_number, |
856 | &aac_max_channel, | 895 | &aac_max_channel, |
857 | &aac_max_id, | 896 | &aac_max_id, |
897 | &aac_reset, | ||
858 | NULL | 898 | NULL |
859 | }; | 899 | }; |
860 | 900 | ||
@@ -1118,7 +1158,7 @@ static int __init aac_init(void) | |||
1118 | { | 1158 | { |
1119 | int error; | 1159 | int error; |
1120 | 1160 | ||
1121 | printk(KERN_INFO "Adaptec %s driver (%s)\n", | 1161 | printk(KERN_INFO "Adaptec %s driver %s\n", |
1122 | AAC_DRIVERNAME, aac_driver_version); | 1162 | AAC_DRIVERNAME, aac_driver_version); |
1123 | 1163 | ||
1124 | error = pci_register_driver(&aac_pci_driver); | 1164 | error = pci_register_driver(&aac_pci_driver); |