: PCI Error Recovery
PATCH 1/1 : PCI Error Recovery
Hi,
I've attached patches implementing PCI error recovery code. These should apply cleanly against kernel-2.6.12-git4
Details of what this is, and how it works, are in a documentation file, part way down the patch.
These patches implement "native" error recovery for four devices:
-- the e100, e1000 network cards
-- the ipr and sym53c8xx_2 scsi device drivers
I've lightly tested against multi-port versions fo the sym53c8xx_2 and the e1000 cards. I have not yet done serious stress testing.
Please review and if appropriate, please apply.
linux/pci.h renamed from linux/pci.h.linas-orig +76 -0
@@ -660,6 +660,81 @@ struct pci_dynids { unsigned int use_driver_data:1; /* pci_driver->driver_data is used */ }; +/* ---------------------------------------------------------------- */ +/** PCI error recovery infrastructure. If a PCI device driver provides +* a set fof callbacks in struct pci_error_handlers, then that device driver +* will be notified of PCI bus errors, and can be driven to recovery. +*/ + +enum pci_channel_state { + pci_channel_io_normal =0 ,/* I/O channel is in normal state */ + pci_channel_io_frozen =1 ,/* I/O to channel is blocked */ + pci_channel_io_perm_failure,/* pci card is dead */ +}; + +enum pcierr_result { +PCIERR_RESULT_NONE =0 ,/* no result/none/not supported in device driver */ +PCIERR_RESULT_CAN_RECOVER =1 ,/* Device driver can recover without slot reset */ +PCIERR_RESULT_NEED_RESET ,/* Device driver wants slot to be reset. */ +PCIERR_RESULT_DISCONNECT ,/* Device has completely failed, is unrecoverable */ +PCIERR_RESULT_RECOVERED ,/* Device driver is fully recovered and operational */ +}; + +/* PCI bus error event callbacks */ +struct pci_error_handlers +{ +int (*error_detected)(struct pci_dev *dev,enum pci_channel_state error); +int (*mmio_enabled)(struct pci_dev *dev);/* MMIO has been reanbled, but not DMA */ +int (*link_reset)(struct pci_dev *dev);/* PCI Express link has been reset */ +int (*slot_reset)(struct pci_dev *dev);/* PCI slot has been reset */ +void (*resume)(struct pci_dev *dev);/* Device driver may resume normal operations */ +}; + +/** +* PCI Error notifier event flags. +*/ +#define PEH_NOTIFY_ERROR 1 + +/** PEH event -- structure holding pci controller data that describes +* a change in the isolation status of a PCI slot. A pointer +* to this struct is passed as the data pointer in a notify callback. +*/ +struct peh_event { +struct list_head list; +struct pci_dev *dev;/* affected device */ +enum pci_channel_state state;/* PCI bus state for the affected device */ +int time_unavail;/* milliseconds until device might be available */ +}; + +/** +* peh_send_failure_event - generate a PCI error event +* @dev pci device +* +* This routine builds a PCI error event which will be delivered +* to all listeners on the peh_notifier_chain. +* +* This routine can be called within an interrupt context; +* the actual event will be delivered in a normal context +* (from a workqueue). +*/ +int peh_send_failure_event (struct pci_dev *dev, +enum pci_channel_state state, +int time_unavail); + +/** +* peh_register_notifier - Register to find out about EEH events. +* @nb: notifier block to callback on events +*/ +int peh_register_notifier (struct notifier_block *nb); + +/** +* peh_unregister_notifier - Unregister to an EEH event notifier. +* @nb: notifier block to callback on events +*/ +int peh_unregister_notifier (struct notifier_block *nb); + +/* ---------------------------------------------------------------- */ +struct module ;struct pci_driver {struct list_head node;
@@ -673,6 +748,7 @@ struct pci_driver {int (*enable_wake) (struct pci_dev *dev,pci_power_t state,int enable);/* Enable wake event */ void (*shutdown) (struct pci_dev *dev); +struct pci_error_handlers err_handler;struct device_driver driver;struct pci_dynids dynids; };
pci-error-recovery.txt renamed from pci-error-recovery.txt.linas-orig +242 -0
242 lines not on this page · raw message
pci/Makefile renamed from pci/Makefile.linas-orig +1 -1
@@ -3,7 +3,7 @@ # obj-y += access.o bus.o probe.o remove.o pci.o quirks.o \ - names.o pci-driver.o search.o pci-sysfs.o \ + names.o pci-driver.o pci-error.o search.o pci-sysfs.o \ rom.o obj-$(CONFIG_PROC_FS) += proc.o
pci/pci-error.c renamed from pci/pci-error.c.linas-orig +152 -0
152 lines not on this page · raw message
scsi/ipr.c renamed from scsi/ipr.c.linas-orig +86 -0
98 lines not on this page · raw message
scsi/sym53c8xx_2/sym_glue.c renamed from scsi/sym53c8xx_2/sym_glue.c.linas-orig +120 -0
156 lines not on this page · raw message
scsi/sym53c8xx_2/sym_glue.h renamed from scsi/sym53c8xx_2/sym_glue.h.linas-orig +4 -0
@@ -181,6 +181,10 @@ struct sym_shcb {char chip_name[8 ];struct pci_dev *device; +/* pci bus i/o state; waiter for clearing of i/o state */ +enum pci_channel_state io_state; +struct sym_eh_wait *io_reset_wait; +struct Scsi_Host *host;void __iomem * ioaddr;/* MMIO kernel io address */
scsi/sym53c8xx_2/sym_hipd.c renamed from scsi/sym53c8xx_2/sym_hipd.c.linas-orig +10 -0
@@ -2806,6 +2806,7 @@ void sym_interrupt (struct sym_hcb *np)u_char istat, istatc;u_char dstat;u_short sist; +u_int icnt;/* * interrupt on the fly ?
@@ -2847,6 +2848,7 @@ void sym_interrupt (struct sym_hcb *np) sist =0 ; dstat =0 ; istatc = istat; + icnt =0 ; do { if (istatc & SIP) sist |= INW(np, nc_sist);
@@ -2854,6 +2856,14 @@ void sym_interrupt (struct sym_hcb *np) dstat |=INB (np, nc_dstat); istatc =INB (np, nc_istat); istat |= istatc; +#ifdef CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY +/* Prevent deadlock waiting on a condition that may never clear. */ + icnt ++; +if (100 < icnt) { +if (eeh_slot_is_isolated (np->s.device)) +return ; + } +#endif /* CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY */ }while (istatc & (SIP |DIP ));if (DEBUG_FLAGS &DEBUG_TINY )
scsi/Kconfig renamed from scsi/Kconfig.linas-orig +16 -0
@@ -1040,6 +1040,14 @@ config SCSI_SYM53C8XX_IOMAPPED the card. This is significantly slower then using memory mapped IO. Most people should answer N. +config SCSI_SYM53C8XX_EEH_RECOVERY + bool "Enable PCI bus error recovery" + depends on SCSI_SYM53C8XX_2 && PPC_PSERIES + help + If you say Y here, the driver will be able to recover from + PCI bus errors on many PowerPC platforms. IBM pSeries users + should answer Y. + config SCSI_IPR tristate "IBM Power Linux RAID adapter support" depends on PCI && SCSI
@@ -1065,6 +1073,14 @@ config SCSI_IPR_DUMP If you enable this support, the iprdump daemon can be used to capture adapter failure analysis information. +config SCSI_IPR_EEH_RECOVERY + bool "Enable PCI bus error recovery" + depends on SCSI_IPR && PPC_PSERIES + help + If you say Y here, the driver will be able to recover from + PCI bus errors on many PowerPC platforms. IBM pSeries users + should answer Y. + config SCSI_ZALON tristate "Zalon SCSI support" depends on GSC && SCSI
net/e100.c renamed from net/e100.c.linas-orig +68 -0
80 lines not on this page · raw message
net/e1000/e1000_main.c renamed from net/e1000/e1000_main.c.linas-orig +102 -1
125 lines not on this page · raw message
net/Kconfig renamed from net/Kconfig.linas-orig +16 -0
@@ -1392,6 +1392,14 @@ config E100 <file:Documentation/networking/net-modules.txt>. The module will be called e100. +config E100_EEH_RECOVERY + bool "Enable PCI bus error recovery" + depends on E100 && PPC_PSERIES + help + If you say Y here, the driver will be able to recover from + PCI bus errors on many PowerPC platforms. IBM pSeries users + should answer Y. + config LNE390 tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)" depends on NET_PCI && EISA && EXPERIMENTAL
@@ -1839,6 +1847,14 @@ config E1000_NAPI If in doubt, say N. +config E1000_EEH_RECOVERY + bool "Enable PCI bus error recovery" + depends on E1000 && PPC_PSERIES + help + If you say Y here, the driver will be able to recover from + PCI bus errors on many PowerPC platforms. IBM pSeries users + should answer Y. + config MYRI_SBUS tristate "MyriCOM Gigabit Ethernet support" depends on SBUS
ppc64/configs/pSeries_defconfig renamed from ppc64/configs/pSeries_defconfig.linas-orig +4 -0
@@ -311,9 +311,11 @@ CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MOD CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +CONFIG_SCSI_SYM53C8XX_EEH_RECOVERY=y CONFIG_SCSI_IPR=y CONFIG_SCSI_IPR_TRACE=y CONFIG_SCSI_IPR_DUMP=y +CONFIG_SCSI_IPR_EEH_RECOVERY=y # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set CONFIG_SCSI_QLA2XXX=y
@@ -544,6 +546,7 @@ CONFIG_PCNET32=y # CONFIG_DGRS is not set # CONFIG_EEPRO100 is not set CONFIG_E100=y +CONFIG_E100_EEH_RECOVERY=y # CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set
@@ -562,6 +565,7 @@ CONFIG_ACENIC_OMIT_TIGON_I=y # CONFIG_DL2K is not set CONFIG_E1000=y # CONFIG_E1000_NAPI is not set +CONFIG_E1000_EEH_RECOVERY=y # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set
asm-ppc64/eeh.h renamed from asm-ppc64/eeh.h.linas-orig +85 -32
195 lines not on this page · raw message
asm-ppc64/prom.h renamed from asm-ppc64/prom.h.linas-orig +5 -0
@@ -119,6 +119,7 @@ struct property {*/ struct pci_controller ;struct iommu_table ; +struct eeh_recovery_ops ;struct device_node {char *name;
@@ -137,9 +138,13 @@ struct device_node {int devfn;/* for pci devices */ int eeh_mode;/* See eeh.h for possible EEH_MODEs */ int eeh_config_addr; +int eeh_check_count;/* number of times device driver ignored error */ +int eeh_freeze_count;/* number of times this device froze up. */ +int eeh_is_bridge;/* device is pci-to-pci bridge */ int pci_ext_config_space;/* for pci devices */ struct pci_controller *phb;/* for pci devices */ struct iommu_table *iommu_table;/* for phb's or bridges */ +u32 config_space[16 ];/* saved PCI config space */ struct property *properties;struct device_node *parent;
asm-ppc64/rtas.h renamed from asm-ppc64/rtas.h.linas-orig +2 -0
@@ -240,4 +240,6 @@ extern unsigned long rtas_rmo_buf;#define GLOBAL_INTERRUPT_QUEUE 9005 +extern int rtas_write_config (struct device_node *dn,int where,int size,u32 val); +#endif /* _PPC64_RTAS_H */
ppc64/kernel/eeh.c renamed from ppc64/kernel/eeh.c.linas-orig +408 -156
803 lines not on this page · raw message
ppc64/kernel/pSeries_pci.c renamed from ppc64/kernel/pSeries_pci.c.linas-orig +2 -2
@@ -62,7 +62,7 @@ static int config_access_valid(struct dereturn 0 ; } -static int rtas_read_config (struct device_node *dn,int where,int size,u32 *val) +int rtas_read_config (struct device_node *dn,int where,int size,u32 *val) {int returnval =-1 ;unsigned long buid, addr;
@@ -112,7 +112,7 @@ static int rtas_pci_read_config(struct preturn PCIBIOS_DEVICE_NOT_FOUND ; } -static int rtas_write_config (struct device_node *dn,int where,int size,u32 val) +int rtas_write_config (struct device_node *dn,int where,int size,u32 val) {unsigned long buid, addr;int ret;
pci/hotplug/rpaphp.h renamed from pci/hotplug/rpaphp.h.linas-orig +2 -1
@@ -113,7 +113,8 @@ extern int rpaphp_enable_pci_slot(structextern int register_pci_slot (struct slot *slot);extern int rpaphp_unconfig_pci_adapter (struct slot *slot);extern int rpaphp_get_pci_adapter_status (struct slot *slot,int is_init,u8 * value); -extern struct hotplug_slot *rpaphp_find_hotplug_slot (struct pci_dev *dev); +extern void init_eeh_handler (void ); +extern void exit_eeh_handler (void );/* rpaphp_core.c */ extern int rpaphp_add_slot (struct device_node *dn);
pci/hotplug/rpaphp_core.c renamed from pci/hotplug/rpaphp_core.c.linas-orig +6 -0
@@ -460,12 +460,18 @@ static int __init rpaphp_init(void) {info (DRIVER_DESC " version: " DRIVER_VERSION "\n" ); +/* Get set to handle EEH events. */ +init_eeh_handler (); +/* read all the PRA info from the system */ return init_rpa (); } static void __exit rpaphp_exit(void) { +/* Let EEH know we are going away. */ +exit_eeh_handler (); +cleanup_slots (); }
pci/hotplug/rpaphp_pci.c renamed from pci/hotplug/rpaphp_pci.c.linas-orig +18 -40
103 lines not on this page · raw message
pci/hotplug/rpaphp_eeh.c renamed from pci/hotplug/rpaphp_eeh.c.linas-orig +380 -0
380 lines not on this page · raw message
pci/hotplug/Makefile renamed from pci/hotplug/Makefile.linas-orig +1 -0
@@ -41,6 +41,7 @@ acpiphp-objs := acpiphp_core.o \ acpiphp_res.o rpaphp-objs := rpaphp_core.o \ + rpaphp_eeh.o \ rpaphp_pci.o \ rpaphp_slot.o \ rpaphp_vio.o