Commit ddc1c945 authored by Stefan Haberland's avatar Stefan Haberland Committed by Martin Schwidefsky
Browse files

s390/dasd: configurable IFCC handling



Make the behavior in case of constant IFCC/CCC errors configurable.
Add a sysfs attribute to switch between path disabled after threshold
exceeded (default) and message only.

Reviewed-by: default avatarJan Hoeppner <hoeppner@linux.vnet.ibm.com>
Reviewed-by: default avatarSebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: default avatarStefan Haberland <sth@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 66aec647
Loading
Loading
Loading
Loading
+20 −18
Original line number Diff line number Diff line
@@ -68,25 +68,27 @@ typedef struct dasd_information2_t {
#define DASD_FORMAT_CDL  2
/*
 * values to be used for dasd_information_t.features
 * 0x00: default features
 * 0x01: readonly (ro)
 * 0x02: use diag discipline (diag)
 * 0x04: set the device initially online (internal use only)
 * 0x08: enable ERP related logging
 * 0x10: allow I/O to fail on lost paths
 * 0x20: allow I/O to fail when a lock was stolen
 * 0x40: give access to raw eckd data
 * 0x80: enable discard support
 * 0x100: default features
 * 0x001: readonly (ro)
 * 0x002: use diag discipline (diag)
 * 0x004: set the device initially online (internal use only)
 * 0x008: enable ERP related logging
 * 0x010: allow I/O to fail on lost paths
 * 0x020: allow I/O to fail when a lock was stolen
 * 0x040: give access to raw eckd data
 * 0x080: enable discard support
 * 0x100: enable autodisable for IFCC errors (default)
 */
#define DASD_FEATURE_DEFAULT	     0x00
#define DASD_FEATURE_READONLY	     0x01
#define DASD_FEATURE_USEDIAG	     0x02
#define DASD_FEATURE_INITIAL_ONLINE  0x04
#define DASD_FEATURE_ERPLOG	     0x08
#define DASD_FEATURE_FAILFAST	     0x10
#define DASD_FEATURE_FAILONSLCK      0x20
#define DASD_FEATURE_USERAW	     0x40
#define DASD_FEATURE_DISCARD	     0x80
#define DASD_FEATURE_READONLY	      0x001
#define DASD_FEATURE_USEDIAG	      0x002
#define DASD_FEATURE_INITIAL_ONLINE   0x004
#define DASD_FEATURE_ERPLOG	      0x008
#define DASD_FEATURE_FAILFAST	      0x010
#define DASD_FEATURE_FAILONSLCK       0x020
#define DASD_FEATURE_USERAW	      0x040
#define DASD_FEATURE_DISCARD	      0x080
#define DASD_FEATURE_PATH_AUTODISABLE 0x100
#define DASD_FEATURE_DEFAULT	      DASD_FEATURE_PATH_AUTODISABLE

#define DASD_PARTN_BITS 2

+15 −2
Original line number Diff line number Diff line
@@ -2214,15 +2214,28 @@ static void dasd_3990_erp_disable_path(struct dasd_device *device, __u8 lpum)
{
	int pos = pathmask_to_pos(lpum);

	if (!(device->features & DASD_FEATURE_PATH_AUTODISABLE)) {
		dev_err(&device->cdev->dev,
			"Path %x.%02x (pathmask %02x) is operational despite excessive IFCCs\n",
			device->path[pos].cssid, device->path[pos].chpid, lpum);
		goto out;
	}

	/* no remaining path, cannot disable */
	if (!(dasd_path_get_opm(device) & ~lpum))
		return;
	if (!(dasd_path_get_opm(device) & ~lpum)) {
		dev_err(&device->cdev->dev,
			"Last path %x.%02x (pathmask %02x) is operational despite excessive IFCCs\n",
			device->path[pos].cssid, device->path[pos].chpid, lpum);
		goto out;
	}

	dev_err(&device->cdev->dev,
		"Path %x.%02x (pathmask %02x) is disabled - IFCC threshold exceeded\n",
		device->path[pos].cssid, device->path[pos].chpid, lpum);
	dasd_path_remove_opm(device, lpum);
	dasd_path_add_ifccpm(device, lpum);

out:
	device->path[pos].errorclk = 0;
	atomic_set(&device->path[pos].error_count, 0);
}
+42 −1
Original line number Diff line number Diff line
@@ -1550,9 +1550,49 @@ dasd_path_threshold_store(struct device *dev, struct device_attribute *attr,
	dasd_put_device(device);
	return count;
}

static DEVICE_ATTR(path_threshold, 0644, dasd_path_threshold_show,
		   dasd_path_threshold_store);

/*
 * configure if path is disabled after IFCC/CCC error threshold is
 * exceeded
 */
static ssize_t
dasd_path_autodisable_show(struct device *dev,
				   struct device_attribute *attr, char *buf)
{
	struct dasd_devmap *devmap;
	int flag;

	devmap = dasd_find_busid(dev_name(dev));
	if (!IS_ERR(devmap))
		flag = (devmap->features & DASD_FEATURE_PATH_AUTODISABLE) != 0;
	else
		flag = (DASD_FEATURE_DEFAULT &
			DASD_FEATURE_PATH_AUTODISABLE) != 0;
	return snprintf(buf, PAGE_SIZE, flag ? "1\n" : "0\n");
}

static ssize_t
dasd_path_autodisable_store(struct device *dev,
				    struct device_attribute *attr,
				    const char *buf, size_t count)
{
	unsigned int val;
	int rc;

	if (kstrtouint(buf, 0, &val) || val > 1)
		return -EINVAL;

	rc = dasd_set_feature(to_ccwdev(dev),
			      DASD_FEATURE_PATH_AUTODISABLE, val);

	return rc ? : count;
}

static DEVICE_ATTR(path_autodisable, 0644,
		   dasd_path_autodisable_show,
		   dasd_path_autodisable_store);
/*
 * interval for IFCC/CCC checks
 * meaning time with no IFCC/CCC error before the error counter
@@ -1623,6 +1663,7 @@ static struct attribute * dasd_attrs[] = {
	&dev_attr_host_access_count.attr,
	&dev_attr_path_masks.attr,
	&dev_attr_path_threshold.attr,
	&dev_attr_path_autodisable.attr,
	&dev_attr_path_interval.attr,
	&dev_attr_path_reset.attr,
	&dev_attr_hpf.attr,