Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 33b62a30 authored by Stefan Weinhuber's avatar Stefan Weinhuber Committed by Martin Schwidefsky
Browse files

[S390] dasd: automatic recognition of read-only devices



In z/VM it is possible to attach a device as read-only. To prevent
unintentional write requests and subsequent I/O errors, we can detect
this configuration using the z/VM DIAG 210 interface and set the
respective linux block device to read-only as well.

Signed-off-by: default avatarStefan Weinhuber <wein@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 584dfddf
Loading
Loading
Loading
Loading
+36 −0
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@
#include <asm/ebcdic.h>
#include <asm/ebcdic.h>
#include <asm/idals.h>
#include <asm/idals.h>
#include <asm/itcw.h>
#include <asm/itcw.h>
#include <asm/diag.h>


/* This is ugly... */
/* This is ugly... */
#define PRINTK_HEADER "dasd:"
#define PRINTK_HEADER "dasd:"
@@ -2212,6 +2213,13 @@ static int dasd_open(struct block_device *bdev, fmode_t mode)
		goto out;
		goto out;
	}
	}


	if ((mode & FMODE_WRITE) &&
	    (test_bit(DASD_FLAG_DEVICE_RO, &base->flags) ||
	     (base->features & DASD_FEATURE_READONLY))) {
		rc = -EROFS;
		goto out;
	}

	return 0;
	return 0;


out:
out:
@@ -2289,6 +2297,34 @@ dasd_exit(void)
 * SECTION: common functions for ccw_driver use
 * SECTION: common functions for ccw_driver use
 */
 */


/*
 * Is the device read-only?
 * Note that this function does not report the setting of the
 * readonly device attribute, but how it is configured in z/VM.
 */
int dasd_device_is_ro(struct dasd_device *device)
{
	struct ccw_dev_id dev_id;
	struct diag210 diag_data;
	int rc;

	if (!MACHINE_IS_VM)
		return 0;
	ccw_device_get_id(device->cdev, &dev_id);
	memset(&diag_data, 0, sizeof(diag_data));
	diag_data.vrdcdvno = dev_id.devno;
	diag_data.vrdclen = sizeof(diag_data);
	rc = diag210(&diag_data);
	if (rc == 0 || rc == 2) {
		return diag_data.vrdcvfla & 0x80;
	} else {
		DBF_EVENT(DBF_WARNING, "diag210 failed for dev=%04x with rc=%d",
			  dev_id.devno, rc);
		return 0;
	}
}
EXPORT_SYMBOL_GPL(dasd_device_is_ro);

static void dasd_generic_auto_online(void *data, async_cookie_t cookie)
static void dasd_generic_auto_online(void *data, async_cookie_t cookie)
{
{
	struct ccw_device *cdev = data;
	struct ccw_device *cdev = data;
+4 −0
Original line number Original line Diff line number Diff line
@@ -1045,6 +1045,10 @@ dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)


		erp->retries = 5;
		erp->retries = 5;


	} else if (sense[1] & SNS1_WRITE_INHIBITED) {
		dev_err(&device->cdev->dev, "An I/O request was rejected"
			" because writing is inhibited\n");
		erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
	} else {
	} else {
		/* fatal error -  set status to FAILED
		/* fatal error -  set status to FAILED
		   internal error 09 - Command Reject */
		   internal error 09 - Command Reject */
+8 −5
Original line number Original line Diff line number Diff line
@@ -742,6 +742,7 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr,
	      const char *buf, size_t count)
	      const char *buf, size_t count)
{
{
	struct dasd_devmap *devmap;
	struct dasd_devmap *devmap;
	struct dasd_device *device;
	int val;
	int val;
	char *endp;
	char *endp;


@@ -758,12 +759,14 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr,
		devmap->features |= DASD_FEATURE_READONLY;
		devmap->features |= DASD_FEATURE_READONLY;
	else
	else
		devmap->features &= ~DASD_FEATURE_READONLY;
		devmap->features &= ~DASD_FEATURE_READONLY;
	if (devmap->device)
	device = devmap->device;
		devmap->device->features = devmap->features;
	if (device) {
	if (devmap->device && devmap->device->block
		device->features = devmap->features;
	    && devmap->device->block->gdp)
		val = val || test_bit(DASD_FLAG_DEVICE_RO, &device->flags);
		set_disk_ro(devmap->device->block->gdp, val);
	}
	spin_unlock(&dasd_devmap_lock);
	spin_unlock(&dasd_devmap_lock);
	if (device && device->block && device->block->gdp)
		set_disk_ro(device->block->gdp, val);
	return count;
	return count;
}
}


+2 −4
Original line number Original line Diff line number Diff line
@@ -145,12 +145,10 @@ dasd_diag_erp(struct dasd_device *device)
	mdsk_term_io(device);
	mdsk_term_io(device);
	rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);
	rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);
	if (rc == 4) {
	if (rc == 4) {
		if (!(device->features & DASD_FEATURE_READONLY)) {
		if (!(test_and_set_bit(DASD_FLAG_DEVICE_RO, &device->flags)))
			pr_warning("%s: The access mode of a DIAG device "
			pr_warning("%s: The access mode of a DIAG device "
				   "changed to read-only\n",
				   "changed to read-only\n",
				   dev_name(&device->cdev->dev));
				   dev_name(&device->cdev->dev));
			device->features |= DASD_FEATURE_READONLY;
		}
		rc = 0;
		rc = 0;
	}
	}
	if (rc)
	if (rc)
@@ -449,7 +447,7 @@ dasd_diag_check_device(struct dasd_device *device)
		rc = -EIO;
		rc = -EIO;
	} else {
	} else {
		if (rc == 4)
		if (rc == 4)
			device->features |= DASD_FEATURE_READONLY;
			set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
		pr_info("%s: New DASD with %ld byte/block, total size %ld "
		pr_info("%s: New DASD with %ld byte/block, total size %ld "
			"KB%s\n", dev_name(&device->cdev->dev),
			"KB%s\n", dev_name(&device->cdev->dev),
			(unsigned long) block->bp_block,
			(unsigned long) block->bp_block,
+8 −2
Original line number Original line Diff line number Diff line
@@ -1089,6 +1089,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
	struct dasd_eckd_private *private;
	struct dasd_eckd_private *private;
	struct dasd_block *block;
	struct dasd_block *block;
	int is_known, rc;
	int is_known, rc;
	int readonly;


	if (!ccw_device_is_pathgroup(device->cdev)) {
	if (!ccw_device_is_pathgroup(device->cdev)) {
		dev_warn(&device->cdev->dev,
		dev_warn(&device->cdev->dev,
@@ -1182,15 +1183,20 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
	else
	else
		private->real_cyl = private->rdc_data.no_cyl;
		private->real_cyl = private->rdc_data.no_cyl;


	readonly = dasd_device_is_ro(device);
	if (readonly)
		set_bit(DASD_FLAG_DEVICE_RO, &device->flags);

	dev_info(&device->cdev->dev, "New DASD %04X/%02X (CU %04X/%02X) "
	dev_info(&device->cdev->dev, "New DASD %04X/%02X (CU %04X/%02X) "
		 "with %d cylinders, %d heads, %d sectors\n",
		 "with %d cylinders, %d heads, %d sectors%s\n",
		 private->rdc_data.dev_type,
		 private->rdc_data.dev_type,
		 private->rdc_data.dev_model,
		 private->rdc_data.dev_model,
		 private->rdc_data.cu_type,
		 private->rdc_data.cu_type,
		 private->rdc_data.cu_model.model,
		 private->rdc_data.cu_model.model,
		 private->real_cyl,
		 private->real_cyl,
		 private->rdc_data.trk_per_cyl,
		 private->rdc_data.trk_per_cyl,
		 private->rdc_data.sec_per_trk);
		 private->rdc_data.sec_per_trk,
		 readonly ? ", read-only device" : "");
	return 0;
	return 0;


out_err3:
out_err3:
Loading