Commit 12c3a548 authored by Stefan Weinhuber's avatar Stefan Weinhuber Committed by Linus Torvalds

[PATCH] s390: dasd extended error reporting module

The DASD extended error reporting is a facility that allows to get detailed
information about certain problems in the DASD I/O.  This information can be
used to implement fail-over applications that can recover these problems.
Signed-off-by: default avatarStefan Weinhuber <wein@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent d237bf49
...@@ -55,13 +55,21 @@ config DASD_DIAG ...@@ -55,13 +55,21 @@ config DASD_DIAG
Disks under VM. If you are not running under VM or unsure what it is, Disks under VM. If you are not running under VM or unsure what it is,
say "N". say "N".
config DASD_EER
tristate "Extended error reporting (EER)"
depends on DASD
help
This driver provides a character device interface to the
DASD extended error reporting. This is only needed if you want to
use applications written for the EER facility.
config DASD_CMB config DASD_CMB
tristate "Compatibility interface for DASD channel measurement blocks" tristate "Compatibility interface for DASD channel measurement blocks"
depends on DASD depends on DASD
help help
This driver provides an additional interface to the channel measurement This driver provides an additional interface to the channel
facility, which is normally accessed though sysfs, with a set of measurement facility, which is normally accessed though sysfs, with
ioctl functions specific to the dasd driver. a set of ioctl functions specific to the dasd driver.
This is only needed if you want to use applications written for This is only needed if you want to use applications written for
linux-2.4 dasd channel measurement facility interface. linux-2.4 dasd channel measurement facility interface.
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o
dasd_fba_mod-objs := dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o dasd_fba_mod-objs := dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
dasd_diag_mod-objs := dasd_diag.o dasd_diag_mod-objs := dasd_diag.o
dasd_eer_mod-objs := dasd_eer.o
dasd_mod-objs := dasd.o dasd_ioctl.o dasd_proc.o dasd_devmap.o \ dasd_mod-objs := dasd.o dasd_ioctl.o dasd_proc.o dasd_devmap.o \
dasd_genhd.o dasd_erp.o dasd_genhd.o dasd_erp.o
...@@ -13,5 +14,6 @@ obj-$(CONFIG_DASD_DIAG) += dasd_diag_mod.o ...@@ -13,5 +14,6 @@ obj-$(CONFIG_DASD_DIAG) += dasd_diag_mod.o
obj-$(CONFIG_DASD_ECKD) += dasd_eckd_mod.o obj-$(CONFIG_DASD_ECKD) += dasd_eckd_mod.o
obj-$(CONFIG_DASD_FBA) += dasd_fba_mod.o obj-$(CONFIG_DASD_FBA) += dasd_fba_mod.o
obj-$(CONFIG_DASD_CMB) += dasd_cmb.o obj-$(CONFIG_DASD_CMB) += dasd_cmb.o
obj-$(CONFIG_DASD_EER) += dasd_eer.o
obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o
obj-$(CONFIG_DCSSBLK) += dcssblk.o obj-$(CONFIG_DCSSBLK) += dcssblk.o
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/hdreg.h> #include <linux/hdreg.h>
#include <linux/notifier.h>
#include <asm/ccwdev.h> #include <asm/ccwdev.h>
#include <asm/ebcdic.h> #include <asm/ebcdic.h>
...@@ -57,6 +58,7 @@ static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *); ...@@ -57,6 +58,7 @@ static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
static void dasd_flush_ccw_queue(struct dasd_device *, int); static void dasd_flush_ccw_queue(struct dasd_device *, int);
static void dasd_tasklet(struct dasd_device *); static void dasd_tasklet(struct dasd_device *);
static void do_kick_device(void *data); static void do_kick_device(void *data);
static void dasd_disable_eer(struct dasd_device *device);
/* /*
* SECTION: Operations on the device structure. * SECTION: Operations on the device structure.
...@@ -151,6 +153,8 @@ dasd_state_new_to_known(struct dasd_device *device) ...@@ -151,6 +153,8 @@ dasd_state_new_to_known(struct dasd_device *device)
static inline void static inline void
dasd_state_known_to_new(struct dasd_device * device) dasd_state_known_to_new(struct dasd_device * device)
{ {
/* disable extended error reporting for this device */
dasd_disable_eer(device);
/* Forget the discipline information. */ /* Forget the discipline information. */
device->discipline = NULL; device->discipline = NULL;
device->state = DASD_STATE_NEW; device->state = DASD_STATE_NEW;
...@@ -867,6 +871,9 @@ dasd_handle_state_change_pending(struct dasd_device *device) ...@@ -867,6 +871,9 @@ dasd_handle_state_change_pending(struct dasd_device *device)
struct dasd_ccw_req *cqr; struct dasd_ccw_req *cqr;
struct list_head *l, *n; struct list_head *l, *n;
/* first of all call extended error reporting */
dasd_write_eer_trigger(DASD_EER_STATECHANGE, device, NULL);
device->stopped &= ~DASD_STOPPED_PENDING; device->stopped &= ~DASD_STOPPED_PENDING;
/* restart all 'running' IO on queue */ /* restart all 'running' IO on queue */
...@@ -1086,6 +1093,19 @@ __dasd_process_ccw_queue(struct dasd_device * device, ...@@ -1086,6 +1093,19 @@ __dasd_process_ccw_queue(struct dasd_device * device,
} }
goto restart; goto restart;
} }
/* first of all call extended error reporting */
if (device->eer && cqr->status == DASD_CQR_FAILED) {
dasd_write_eer_trigger(DASD_EER_FATALERROR,
device, cqr);
/* restart request */
cqr->status = DASD_CQR_QUEUED;
cqr->retries = 255;
device->stopped |= DASD_STOPPED_QUIESCE;
goto restart;
}
/* Process finished ERP request. */ /* Process finished ERP request. */
if (cqr->refers) { if (cqr->refers) {
__dasd_process_erp(device, cqr); __dasd_process_erp(device, cqr);
...@@ -1223,7 +1243,8 @@ __dasd_start_head(struct dasd_device * device) ...@@ -1223,7 +1243,8 @@ __dasd_start_head(struct dasd_device * device)
cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
/* check FAILFAST */ /* check FAILFAST */
if (device->stopped & ~DASD_STOPPED_PENDING && if (device->stopped & ~DASD_STOPPED_PENDING &&
test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags)) { test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
(!device->eer)) {
cqr->status = DASD_CQR_FAILED; cqr->status = DASD_CQR_FAILED;
dasd_schedule_bh(device); dasd_schedule_bh(device);
} }
...@@ -1965,6 +1986,9 @@ dasd_generic_notify(struct ccw_device *cdev, int event) ...@@ -1965,6 +1986,9 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
switch (event) { switch (event) {
case CIO_GONE: case CIO_GONE:
case CIO_NO_PATH: case CIO_NO_PATH:
/* first of all call extended error reporting */
dasd_write_eer_trigger(DASD_EER_NOPATH, device, NULL);
if (device->state < DASD_STATE_BASIC) if (device->state < DASD_STATE_BASIC)
break; break;
/* Device is active. We want to keep it. */ /* Device is active. We want to keep it. */
...@@ -2022,6 +2046,51 @@ dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver) ...@@ -2022,6 +2046,51 @@ dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver)
put_driver(drv); put_driver(drv);
} }
/*
* notifications for extended error reports
*/
static struct notifier_block *dasd_eer_chain;
int
dasd_register_eer_notifier(struct notifier_block *nb)
{
return notifier_chain_register(&dasd_eer_chain, nb);
}
int
dasd_unregister_eer_notifier(struct notifier_block *nb)
{
return notifier_chain_unregister(&dasd_eer_chain, nb);
}
/*
* Notify the registered error reporting module of a problem
*/
void
dasd_write_eer_trigger(unsigned int id, struct dasd_device *device,
struct dasd_ccw_req *cqr)
{
if (device->eer) {
struct dasd_eer_trigger temp;
temp.id = id;
temp.device = device;
temp.cqr = cqr;
notifier_call_chain(&dasd_eer_chain, DASD_EER_TRIGGER,
(void *)&temp);
}
}
/*
* Tell the registered error reporting module to disable error reporting for
* a given device and to cleanup any private data structures on that device.
*/
static void
dasd_disable_eer(struct dasd_device *device)
{
notifier_call_chain(&dasd_eer_chain, DASD_EER_DISABLE, (void *)device);
}
static int __init static int __init
dasd_init(void) dasd_init(void)
{ {
...@@ -2103,6 +2172,11 @@ EXPORT_SYMBOL_GPL(dasd_generic_set_online); ...@@ -2103,6 +2172,11 @@ EXPORT_SYMBOL_GPL(dasd_generic_set_online);
EXPORT_SYMBOL_GPL(dasd_generic_set_offline); EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
EXPORT_SYMBOL_GPL(dasd_generic_auto_online); EXPORT_SYMBOL_GPL(dasd_generic_auto_online);
EXPORT_SYMBOL(dasd_register_eer_notifier);
EXPORT_SYMBOL(dasd_unregister_eer_notifier);
EXPORT_SYMBOL(dasd_write_eer_trigger);
/* /*
* Overrides for Emacs so that we follow Linus's tabbing style. * Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically * Emacs will notice this stuff at the end of the file and automatically
......
...@@ -1108,6 +1108,9 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense) ...@@ -1108,6 +1108,9 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)
case 0x0B: case 0x0B:
DEV_MESSAGE(KERN_WARNING, device, "%s", DEV_MESSAGE(KERN_WARNING, device, "%s",
"FORMAT F - Volume is suspended duplex"); "FORMAT F - Volume is suspended duplex");
/* call extended error reporting (EER) */
dasd_write_eer_trigger(DASD_EER_PPRCSUSPEND, device,
erp->refers);
break; break;
case 0x0C: case 0x0C:
DEV_MESSAGE(KERN_WARNING, device, "%s", DEV_MESSAGE(KERN_WARNING, device, "%s",
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#define DASD_ECKD_CCW_PSF 0x27 #define DASD_ECKD_CCW_PSF 0x27
#define DASD_ECKD_CCW_RSSD 0x3e #define DASD_ECKD_CCW_RSSD 0x3e
#define DASD_ECKD_CCW_LOCATE_RECORD 0x47 #define DASD_ECKD_CCW_LOCATE_RECORD 0x47
#define DASD_ECKD_CCW_SNSS 0x54
#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63 #define DASD_ECKD_CCW_DEFINE_EXTENT 0x63
#define DASD_ECKD_CCW_WRITE_MT 0x85 #define DASD_ECKD_CCW_WRITE_MT 0x85
#define DASD_ECKD_CCW_READ_MT 0x86 #define DASD_ECKD_CCW_READ_MT 0x86
......
This diff is collapsed.
...@@ -275,6 +275,34 @@ struct dasd_discipline { ...@@ -275,6 +275,34 @@ struct dasd_discipline {
extern struct dasd_discipline *dasd_diag_discipline_pointer; extern struct dasd_discipline *dasd_diag_discipline_pointer;
/*
* Notification numbers for extended error reporting notifications:
* The DASD_EER_DISABLE notification is sent before a dasd_device (and it's
* eer pointer) is freed. The error reporting module needs to do all necessary
* cleanup steps.
* The DASD_EER_TRIGGER notification sends the actual error reports (triggers).
*/
#define DASD_EER_DISABLE 0
#define DASD_EER_TRIGGER 1
/* Trigger IDs for extended error reporting DASD_EER_TRIGGER notification */
#define DASD_EER_FATALERROR 1
#define DASD_EER_NOPATH 2
#define DASD_EER_STATECHANGE 3
#define DASD_EER_PPRCSUSPEND 4
/*
* The dasd_eer_trigger structure contains all data that we need to send
* along with an DASD_EER_TRIGGER notification.
*/
struct dasd_eer_trigger {
unsigned int id;
struct dasd_device *device;
struct dasd_ccw_req *cqr;
};
struct dasd_device { struct dasd_device {
/* Block device stuff. */ /* Block device stuff. */
struct gendisk *gdp; struct gendisk *gdp;
...@@ -288,6 +316,9 @@ struct dasd_device { ...@@ -288,6 +316,9 @@ struct dasd_device {
unsigned long flags; /* per device flags */ unsigned long flags; /* per device flags */
unsigned short features; /* copy of devmap-features (read-only!) */ unsigned short features; /* copy of devmap-features (read-only!) */
/* extended error reporting stuff (eer) */
void *eer;
/* Device discipline stuff. */ /* Device discipline stuff. */
struct dasd_discipline *discipline; struct dasd_discipline *discipline;
char *private; char *private;
...@@ -488,6 +519,12 @@ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *); ...@@ -488,6 +519,12 @@ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
int dasd_generic_set_offline (struct ccw_device *cdev); int dasd_generic_set_offline (struct ccw_device *cdev);
int dasd_generic_notify(struct ccw_device *, int); int dasd_generic_notify(struct ccw_device *, int);
void dasd_generic_auto_online (struct ccw_driver *); void dasd_generic_auto_online (struct ccw_driver *);
int dasd_register_eer_notifier(struct notifier_block *);
int dasd_unregister_eer_notifier(struct notifier_block *);
void dasd_write_eer_trigger(unsigned int , struct dasd_device *,
struct dasd_ccw_req *);
/* externals in dasd_devmap.c */ /* externals in dasd_devmap.c */
extern int dasd_max_devindex; extern int dasd_max_devindex;
......
...@@ -204,7 +204,8 @@ typedef struct attrib_data_t { ...@@ -204,7 +204,8 @@ typedef struct attrib_data_t {
* *
* Here ist how the ioctl-nr should be used: * Here ist how the ioctl-nr should be used:
* 0 - 31 DASD driver itself * 0 - 31 DASD driver itself
* 32 - 239 still open * 32 - 229 still open
* 230 - 239 DASD extended error reporting
* 240 - 255 reserved for EMC * 240 - 255 reserved for EMC
*******************************************************************************/ *******************************************************************************/
...@@ -236,12 +237,22 @@ typedef struct attrib_data_t { ...@@ -236,12 +237,22 @@ typedef struct attrib_data_t {
#define BIODASDPSRD _IOR(DASD_IOCTL_LETTER,4,dasd_rssd_perf_stats_t) #define BIODASDPSRD _IOR(DASD_IOCTL_LETTER,4,dasd_rssd_perf_stats_t)
/* Get Attributes (cache operations) */ /* Get Attributes (cache operations) */
#define BIODASDGATTR _IOR(DASD_IOCTL_LETTER,5,attrib_data_t) #define BIODASDGATTR _IOR(DASD_IOCTL_LETTER,5,attrib_data_t)
/* retrieve extended error-reporting value */
#define BIODASDEERGET _IOR(DASD_IOCTL_LETTER,6,int)
/* #define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */ /* #define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */
#define BIODASDFMT _IOW(DASD_IOCTL_LETTER,1,format_data_t) #define BIODASDFMT _IOW(DASD_IOCTL_LETTER,1,format_data_t)
/* Set Attributes (cache operations) */ /* Set Attributes (cache operations) */
#define BIODASDSATTR _IOW(DASD_IOCTL_LETTER,2,attrib_data_t) #define BIODASDSATTR _IOW(DASD_IOCTL_LETTER,2,attrib_data_t)
/* retrieve extended error-reporting value */
#define BIODASDEERSET _IOW(DASD_IOCTL_LETTER,3,int)
/* remove all records from the eer buffer */
#define DASD_EER_PURGE _IO(DASD_IOCTL_LETTER,230)
/* set the number of pages that are used for the internal eer buffer */
#define DASD_EER_SETBUFSIZE _IOW(DASD_IOCTL_LETTER,230,int)
#endif /* DASD_H */ #endif /* DASD_H */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment