aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorKashyap, Desai <kashyap.desai@lsi.com>2010-04-05 04:50:07 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-04-11 14:42:41 -0400
commitef7c80c1f18f2c5eea2dabd214f12e0c93ac29cf (patch)
tree5ae27b0d8f20e5ff8a09e8d8817b1884c0a1434c /drivers
parentebda4d38df542e1ff4747c4daadfc7da250b4fa6 (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')
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c6
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c118
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 */
6678static 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 */
6710static 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 */
6746static 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 */
6763static 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
6778static 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
6668static struct pci_driver scsih_driver = { 6785static 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,