diff options
author | Kashyap, Desai <kashyap.desai@lsi.com> | 2010-04-05 04:50:07 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-04-11 14:42:41 -0400 |
commit | ef7c80c1f18f2c5eea2dabd214f12e0c93ac29cf (patch) | |
tree | 5ae27b0d8f20e5ff8a09e8d8817b1884c0a1434c /drivers/scsi/mpt2sas | |
parent | ebda4d38df542e1ff4747c4daadfc7da250b4fa6 (diff) |
[SCSI] mpt2sas: Added support for PCIe Advanced Error Recovery.
Added support in the driver to support EEH and
PCIe Advanced Error Recovery. This involves adding new
pci_error_handler interface for recovering the controller from PCI Bus
errors, such as SERR and PERR. Some tools are available for simulating
PCI errors in order to validate this interface:
http://www.kernel.org/pub/linux/utils/pci/aer-inject
Signed-off-by: Kashyap Desai <kashyap.desai@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/mpt2sas')
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.c | 6 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_scsih.c | 118 |
2 files changed, 124 insertions, 0 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index f980b8822f92..b04ccad7d972 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c | |||
@@ -58,6 +58,7 @@ | |||
58 | #include <linux/sort.h> | 58 | #include <linux/sort.h> |
59 | #include <linux/io.h> | 59 | #include <linux/io.h> |
60 | #include <linux/time.h> | 60 | #include <linux/time.h> |
61 | #include <linux/aer.h> | ||
61 | 62 | ||
62 | #include "mpt2sas_base.h" | 63 | #include "mpt2sas_base.h" |
63 | 64 | ||
@@ -1256,6 +1257,9 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) | |||
1256 | goto out_fail; | 1257 | goto out_fail; |
1257 | } | 1258 | } |
1258 | 1259 | ||
1260 | /* AER (Advanced Error Reporting) hooks */ | ||
1261 | pci_enable_pcie_error_reporting(pdev); | ||
1262 | |||
1259 | pci_set_master(pdev); | 1263 | pci_set_master(pdev); |
1260 | 1264 | ||
1261 | if (_base_config_dma_addressing(ioc, pdev) != 0) { | 1265 | if (_base_config_dma_addressing(ioc, pdev) != 0) { |
@@ -1311,6 +1315,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) | |||
1311 | ioc->chip_phys = 0; | 1315 | ioc->chip_phys = 0; |
1312 | ioc->pci_irq = -1; | 1316 | ioc->pci_irq = -1; |
1313 | pci_release_selected_regions(ioc->pdev, ioc->bars); | 1317 | pci_release_selected_regions(ioc->pdev, ioc->bars); |
1318 | pci_disable_pcie_error_reporting(pdev); | ||
1314 | pci_disable_device(pdev); | 1319 | pci_disable_device(pdev); |
1315 | return r; | 1320 | return r; |
1316 | } | 1321 | } |
@@ -3547,6 +3552,7 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc) | |||
3547 | ioc->pci_irq = -1; | 3552 | ioc->pci_irq = -1; |
3548 | ioc->chip_phys = 0; | 3553 | ioc->chip_phys = 0; |
3549 | pci_release_selected_regions(ioc->pdev, ioc->bars); | 3554 | pci_release_selected_regions(ioc->pdev, ioc->bars); |
3555 | pci_disable_pcie_error_reporting(pdev); | ||
3550 | pci_disable_device(pdev); | 3556 | pci_disable_device(pdev); |
3551 | return; | 3557 | return; |
3552 | } | 3558 | } |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 1f0466aa6c18..bb5659ca128d 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c | |||
@@ -52,6 +52,7 @@ | |||
52 | #include <linux/delay.h> | 52 | #include <linux/delay.h> |
53 | #include <linux/pci.h> | 53 | #include <linux/pci.h> |
54 | #include <linux/interrupt.h> | 54 | #include <linux/interrupt.h> |
55 | #include <linux/aer.h> | ||
55 | #include <linux/raid_class.h> | 56 | #include <linux/raid_class.h> |
56 | #include <linux/slab.h> | 57 | #include <linux/slab.h> |
57 | 58 | ||
@@ -6664,6 +6665,122 @@ _scsih_resume(struct pci_dev *pdev) | |||
6664 | } | 6665 | } |
6665 | #endif /* CONFIG_PM */ | 6666 | #endif /* CONFIG_PM */ |
6666 | 6667 | ||
6668 | /** | ||
6669 | * _scsih_pci_error_detected - Called when a PCI error is detected. | ||
6670 | * @pdev: PCI device struct | ||
6671 | * @state: PCI channel state | ||
6672 | * | ||
6673 | * Description: Called when a PCI error is detected. | ||
6674 | * | ||
6675 | * Return value: | ||
6676 | * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT | ||
6677 | */ | ||
6678 | static pci_ers_result_t | ||
6679 | _scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) | ||
6680 | { | ||
6681 | struct Scsi_Host *shost = pci_get_drvdata(pdev); | ||
6682 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
6683 | |||
6684 | printk(MPT2SAS_INFO_FMT "PCI error: detected callback, state(%d)!!\n", | ||
6685 | ioc->name, state); | ||
6686 | |||
6687 | switch (state) { | ||
6688 | case pci_channel_io_normal: | ||
6689 | return PCI_ERS_RESULT_CAN_RECOVER; | ||
6690 | case pci_channel_io_frozen: | ||
6691 | scsi_block_requests(ioc->shost); | ||
6692 | mpt2sas_base_stop_watchdog(ioc); | ||
6693 | mpt2sas_base_free_resources(ioc); | ||
6694 | return PCI_ERS_RESULT_NEED_RESET; | ||
6695 | case pci_channel_io_perm_failure: | ||
6696 | _scsih_remove(pdev); | ||
6697 | return PCI_ERS_RESULT_DISCONNECT; | ||
6698 | } | ||
6699 | return PCI_ERS_RESULT_NEED_RESET; | ||
6700 | } | ||
6701 | |||
6702 | /** | ||
6703 | * _scsih_pci_slot_reset - Called when PCI slot has been reset. | ||
6704 | * @pdev: PCI device struct | ||
6705 | * | ||
6706 | * Description: This routine is called by the pci error recovery | ||
6707 | * code after the PCI slot has been reset, just before we | ||
6708 | * should resume normal operations. | ||
6709 | */ | ||
6710 | static pci_ers_result_t | ||
6711 | _scsih_pci_slot_reset(struct pci_dev *pdev) | ||
6712 | { | ||
6713 | struct Scsi_Host *shost = pci_get_drvdata(pdev); | ||
6714 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
6715 | int rc; | ||
6716 | |||
6717 | printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n", | ||
6718 | ioc->name); | ||
6719 | |||
6720 | ioc->pdev = pdev; | ||
6721 | rc = mpt2sas_base_map_resources(ioc); | ||
6722 | if (rc) | ||
6723 | return PCI_ERS_RESULT_DISCONNECT; | ||
6724 | |||
6725 | |||
6726 | rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, | ||
6727 | FORCE_BIG_HAMMER); | ||
6728 | |||
6729 | printk(MPT2SAS_WARN_FMT "hard reset: %s\n", ioc->name, | ||
6730 | (rc == 0) ? "success" : "failed"); | ||
6731 | |||
6732 | if (!rc) | ||
6733 | return PCI_ERS_RESULT_RECOVERED; | ||
6734 | else | ||
6735 | return PCI_ERS_RESULT_DISCONNECT; | ||
6736 | } | ||
6737 | |||
6738 | /** | ||
6739 | * _scsih_pci_resume() - resume normal ops after PCI reset | ||
6740 | * @pdev: pointer to PCI device | ||
6741 | * | ||
6742 | * Called when the error recovery driver tells us that its | ||
6743 | * OK to resume normal operation. Use completion to allow | ||
6744 | * halted scsi ops to resume. | ||
6745 | */ | ||
6746 | static void | ||
6747 | _scsih_pci_resume(struct pci_dev *pdev) | ||
6748 | { | ||
6749 | struct Scsi_Host *shost = pci_get_drvdata(pdev); | ||
6750 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
6751 | |||
6752 | printk(MPT2SAS_INFO_FMT "PCI error: resume callback!!\n", ioc->name); | ||
6753 | |||
6754 | pci_cleanup_aer_uncorrect_error_status(pdev); | ||
6755 | mpt2sas_base_start_watchdog(ioc); | ||
6756 | scsi_unblock_requests(ioc->shost); | ||
6757 | } | ||
6758 | |||
6759 | /** | ||
6760 | * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers | ||
6761 | * @pdev: pointer to PCI device | ||
6762 | */ | ||
6763 | static pci_ers_result_t | ||
6764 | _scsih_pci_mmio_enabled(struct pci_dev *pdev) | ||
6765 | { | ||
6766 | struct Scsi_Host *shost = pci_get_drvdata(pdev); | ||
6767 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
6768 | |||
6769 | printk(MPT2SAS_INFO_FMT "PCI error: mmio enabled callback!!\n", | ||
6770 | ioc->name); | ||
6771 | |||
6772 | /* TODO - dump whatever for debugging purposes */ | ||
6773 | |||
6774 | /* Request a slot reset. */ | ||
6775 | return PCI_ERS_RESULT_NEED_RESET; | ||
6776 | } | ||
6777 | |||
6778 | static struct pci_error_handlers _scsih_err_handler = { | ||
6779 | .error_detected = _scsih_pci_error_detected, | ||
6780 | .mmio_enabled = _scsih_pci_mmio_enabled, | ||
6781 | .slot_reset = _scsih_pci_slot_reset, | ||
6782 | .resume = _scsih_pci_resume, | ||
6783 | }; | ||
6667 | 6784 | ||
6668 | static struct pci_driver scsih_driver = { | 6785 | static struct pci_driver scsih_driver = { |
6669 | .name = MPT2SAS_DRIVER_NAME, | 6786 | .name = MPT2SAS_DRIVER_NAME, |
@@ -6671,6 +6788,7 @@ static struct pci_driver scsih_driver = { | |||
6671 | .probe = _scsih_probe, | 6788 | .probe = _scsih_probe, |
6672 | .remove = __devexit_p(_scsih_remove), | 6789 | .remove = __devexit_p(_scsih_remove), |
6673 | .shutdown = _scsih_shutdown, | 6790 | .shutdown = _scsih_shutdown, |
6791 | .err_handler = &_scsih_err_handler, | ||
6674 | #ifdef CONFIG_PM | 6792 | #ifdef CONFIG_PM |
6675 | .suspend = _scsih_suspend, | 6793 | .suspend = _scsih_suspend, |
6676 | .resume = _scsih_resume, | 6794 | .resume = _scsih_resume, |