diff options
Diffstat (limited to 'drivers/scsi/aacraid/linit.c')
-rw-r--r-- | drivers/scsi/aacraid/linit.c | 104 |
1 files changed, 92 insertions, 12 deletions
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 5c487ff096c7..d76e1a8cb93a 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 | ||
@@ -223,12 +221,12 @@ static struct aac_driver_ident aac_drivers[] = { | |||
223 | { aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Perc 320/DC*/ | 221 | { aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Perc 320/DC*/ |
224 | { aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/ | 222 | { aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/ |
225 | { aac_sa_init, "aacraid", "ADAPTEC ", "AAC-364 ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/ | 223 | { aac_sa_init, "aacraid", "ADAPTEC ", "AAC-364 ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/ |
226 | { aac_sa_init, "percraid", "DELL ", "PERCRAID ", 4, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell PERC2/QC */ | 224 | { aac_sa_init, "percraid", "DELL ", "PERCRAID ", 4, AAC_QUIRK_34SG }, /* Dell PERC2/QC */ |
227 | { aac_sa_init, "hpnraid", "HP ", "NetRAID ", 4, AAC_QUIRK_34SG }, /* HP NetRAID-4M */ | 225 | { aac_sa_init, "hpnraid", "HP ", "NetRAID ", 4, AAC_QUIRK_34SG }, /* HP NetRAID-4M */ |
228 | 226 | ||
229 | { aac_rx_init, "aacraid", "DELL ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell Catchall */ | 227 | { aac_rx_init, "aacraid", "DELL ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell Catchall */ |
230 | { aac_rx_init, "aacraid", "Legend ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend Catchall */ | 228 | { aac_rx_init, "aacraid", "Legend ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend Catchall */ |
231 | { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec Catch All */ | 229 | { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Catch All */ |
232 | { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Rocket Catch All */ | 230 | { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Rocket Catch All */ |
233 | { aac_nark_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec NEMER/ARK Catch All */ | 231 | { aac_nark_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec NEMER/ARK Catch All */ |
234 | }; | 232 | }; |
@@ -403,10 +401,6 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev, | |||
403 | 401 | ||
404 | static int aac_slave_configure(struct scsi_device *sdev) | 402 | static int aac_slave_configure(struct scsi_device *sdev) |
405 | { | 403 | { |
406 | if (sdev_channel(sdev) == CONTAINER_CHANNEL) { | ||
407 | sdev->skip_ms_page_8 = 1; | ||
408 | sdev->skip_ms_page_3f = 1; | ||
409 | } | ||
410 | if ((sdev->type == TYPE_DISK) && | 404 | if ((sdev->type == TYPE_DISK) && |
411 | (sdev_channel(sdev) != CONTAINER_CHANNEL)) { | 405 | (sdev_channel(sdev) != CONTAINER_CHANNEL)) { |
412 | if (expose_physicals == 0) | 406 | if (expose_physicals == 0) |
@@ -450,6 +444,43 @@ static int aac_slave_configure(struct scsi_device *sdev) | |||
450 | return 0; | 444 | return 0; |
451 | } | 445 | } |
452 | 446 | ||
447 | /** | ||
448 | * aac_change_queue_depth - alter queue depths | ||
449 | * @sdev: SCSI device we are considering | ||
450 | * @depth: desired queue depth | ||
451 | * | ||
452 | * Alters queue depths for target device based on the host adapter's | ||
453 | * total capacity and the queue depth supported by the target device. | ||
454 | */ | ||
455 | |||
456 | static int aac_change_queue_depth(struct scsi_device *sdev, int depth) | ||
457 | { | ||
458 | if (sdev->tagged_supported && (sdev->type == TYPE_DISK) && | ||
459 | (sdev_channel(sdev) == CONTAINER_CHANNEL)) { | ||
460 | struct scsi_device * dev; | ||
461 | struct Scsi_Host *host = sdev->host; | ||
462 | unsigned num = 0; | ||
463 | |||
464 | __shost_for_each_device(dev, host) { | ||
465 | if (dev->tagged_supported && (dev->type == TYPE_DISK) && | ||
466 | (sdev_channel(dev) == CONTAINER_CHANNEL)) | ||
467 | ++num; | ||
468 | ++num; | ||
469 | } | ||
470 | if (num >= host->can_queue) | ||
471 | num = host->can_queue - 1; | ||
472 | if (depth > (host->can_queue - num)) | ||
473 | depth = host->can_queue - num; | ||
474 | if (depth > 256) | ||
475 | depth = 256; | ||
476 | else if (depth < 2) | ||
477 | depth = 2; | ||
478 | scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth); | ||
479 | } else | ||
480 | scsi_adjust_queue_depth(sdev, 0, 1); | ||
481 | return sdev->queue_depth; | ||
482 | } | ||
483 | |||
453 | static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg) | 484 | static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg) |
454 | { | 485 | { |
455 | struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata; | 486 | struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata; |
@@ -548,6 +579,14 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) | |||
548 | ssleep(1); | 579 | ssleep(1); |
549 | } | 580 | } |
550 | 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 */ | ||
551 | 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 */ |
552 | } | 591 | } |
553 | 592 | ||
@@ -731,15 +770,21 @@ static ssize_t aac_show_bios_version(struct class_device *class_dev, | |||
731 | return len; | 770 | return len; |
732 | } | 771 | } |
733 | 772 | ||
734 | static ssize_t aac_show_serial_number(struct class_device *class_dev, | 773 | ssize_t aac_show_serial_number(struct class_device *class_dev, char *buf) |
735 | char *buf) | ||
736 | { | 774 | { |
737 | struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata; | 775 | struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata; |
738 | int len = 0; | 776 | int len = 0; |
739 | 777 | ||
740 | if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0) | 778 | if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0) |
741 | len = snprintf(buf, PAGE_SIZE, "%x\n", | 779 | len = snprintf(buf, PAGE_SIZE, "%06X\n", |
742 | le32_to_cpu(dev->adapter_info.serial[0])); | 780 | le32_to_cpu(dev->adapter_info.serial[0])); |
781 | if (len && | ||
782 | !memcmp(&dev->supplement_adapter_info.MfgPcbaSerialNo[ | ||
783 | sizeof(dev->supplement_adapter_info.MfgPcbaSerialNo)+2-len], | ||
784 | buf, len)) | ||
785 | len = snprintf(buf, PAGE_SIZE, "%.*s\n", | ||
786 | (int)sizeof(dev->supplement_adapter_info.MfgPcbaSerialNo), | ||
787 | dev->supplement_adapter_info.MfgPcbaSerialNo); | ||
743 | return len; | 788 | return len; |
744 | } | 789 | } |
745 | 790 | ||
@@ -755,6 +800,31 @@ static ssize_t aac_show_max_id(struct class_device *class_dev, char *buf) | |||
755 | class_to_shost(class_dev)->max_id); | 800 | class_to_shost(class_dev)->max_id); |
756 | } | 801 | } |
757 | 802 | ||
803 | static ssize_t aac_store_reset_adapter(struct class_device *class_dev, | ||
804 | const char *buf, size_t count) | ||
805 | { | ||
806 | int retval = -EACCES; | ||
807 | |||
808 | if (!capable(CAP_SYS_ADMIN)) | ||
809 | return retval; | ||
810 | retval = aac_reset_adapter((struct aac_dev*)class_to_shost(class_dev)->hostdata, buf[0] == '!'); | ||
811 | if (retval >= 0) | ||
812 | retval = count; | ||
813 | return retval; | ||
814 | } | ||
815 | |||
816 | static ssize_t aac_show_reset_adapter(struct class_device *class_dev, | ||
817 | char *buf) | ||
818 | { | ||
819 | struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata; | ||
820 | int len, tmp; | ||
821 | |||
822 | tmp = aac_adapter_check_health(dev); | ||
823 | if ((tmp == 0) && dev->in_reset) | ||
824 | tmp = -EBUSY; | ||
825 | len = snprintf(buf, PAGE_SIZE, "0x%x", tmp); | ||
826 | return len; | ||
827 | } | ||
758 | 828 | ||
759 | static struct class_device_attribute aac_model = { | 829 | static struct class_device_attribute aac_model = { |
760 | .attr = { | 830 | .attr = { |
@@ -812,6 +882,14 @@ static struct class_device_attribute aac_max_id = { | |||
812 | }, | 882 | }, |
813 | .show = aac_show_max_id, | 883 | .show = aac_show_max_id, |
814 | }; | 884 | }; |
885 | static struct class_device_attribute aac_reset = { | ||
886 | .attr = { | ||
887 | .name = "reset_host", | ||
888 | .mode = S_IWUSR|S_IRUGO, | ||
889 | }, | ||
890 | .store = aac_store_reset_adapter, | ||
891 | .show = aac_show_reset_adapter, | ||
892 | }; | ||
815 | 893 | ||
816 | static struct class_device_attribute *aac_attrs[] = { | 894 | static struct class_device_attribute *aac_attrs[] = { |
817 | &aac_model, | 895 | &aac_model, |
@@ -822,6 +900,7 @@ static struct class_device_attribute *aac_attrs[] = { | |||
822 | &aac_serial_number, | 900 | &aac_serial_number, |
823 | &aac_max_channel, | 901 | &aac_max_channel, |
824 | &aac_max_id, | 902 | &aac_max_id, |
903 | &aac_reset, | ||
825 | NULL | 904 | NULL |
826 | }; | 905 | }; |
827 | 906 | ||
@@ -848,6 +927,7 @@ static struct scsi_host_template aac_driver_template = { | |||
848 | .bios_param = aac_biosparm, | 927 | .bios_param = aac_biosparm, |
849 | .shost_attrs = aac_attrs, | 928 | .shost_attrs = aac_attrs, |
850 | .slave_configure = aac_slave_configure, | 929 | .slave_configure = aac_slave_configure, |
930 | .change_queue_depth = aac_change_queue_depth, | ||
851 | .eh_abort_handler = aac_eh_abort, | 931 | .eh_abort_handler = aac_eh_abort, |
852 | .eh_host_reset_handler = aac_eh_reset, | 932 | .eh_host_reset_handler = aac_eh_reset, |
853 | .can_queue = AAC_NUM_IO_FIB, | 933 | .can_queue = AAC_NUM_IO_FIB, |
@@ -1086,7 +1166,7 @@ static int __init aac_init(void) | |||
1086 | { | 1166 | { |
1087 | int error; | 1167 | int error; |
1088 | 1168 | ||
1089 | printk(KERN_INFO "Adaptec %s driver (%s)\n", | 1169 | printk(KERN_INFO "Adaptec %s driver %s\n", |
1090 | AAC_DRIVERNAME, aac_driver_version); | 1170 | AAC_DRIVERNAME, aac_driver_version); |
1091 | 1171 | ||
1092 | error = pci_register_driver(&aac_pci_driver); | 1172 | error = pci_register_driver(&aac_pci_driver); |