Commit 3ce60745 authored by Heiko Carstens's avatar Heiko Carstens Committed by Linus Torvalds

[PATCH] s390: DASD driver

From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

dasd driver changes:
 - Modify format analysis routine to use block size provided by on-disk label.
 - Search data structures when referencing use_diag/ro attribute values.
 - Correct return code checking when allocating memory.
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 86df1439
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* functions may not be called from interrupt context. In particular * functions may not be called from interrupt context. In particular
* dasd_get_device is a no-no from interrupt context. * dasd_get_device is a no-no from interrupt context.
* *
* $Revision: 1.34 $ * $Revision: 1.35 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -553,6 +553,8 @@ dasd_delete_device(struct dasd_device *device) ...@@ -553,6 +553,8 @@ dasd_delete_device(struct dasd_device *device)
/* First remove device pointer from devmap. */ /* First remove device pointer from devmap. */
devmap = dasd_find_busid(device->cdev->dev.bus_id); devmap = dasd_find_busid(device->cdev->dev.bus_id);
if (IS_ERR(devmap))
BUG();
spin_lock(&dasd_devmap_lock); spin_lock(&dasd_devmap_lock);
if (devmap->device != device) { if (devmap->device != device) {
spin_unlock(&dasd_devmap_lock); spin_unlock(&dasd_devmap_lock);
...@@ -626,8 +628,8 @@ dasd_ro_show(struct device *dev, char *buf) ...@@ -626,8 +628,8 @@ dasd_ro_show(struct device *dev, char *buf)
struct dasd_devmap *devmap; struct dasd_devmap *devmap;
int ro_flag; int ro_flag;
devmap = dev->driver_data; devmap = dasd_find_busid(dev->bus_id);
if (devmap) if (!IS_ERR(devmap))
ro_flag = (devmap->features & DASD_FEATURE_READONLY) != 0; ro_flag = (devmap->features & DASD_FEATURE_READONLY) != 0;
else else
ro_flag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_READONLY) != 0; ro_flag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_READONLY) != 0;
...@@ -641,6 +643,8 @@ dasd_ro_store(struct device *dev, const char *buf, size_t count) ...@@ -641,6 +643,8 @@ dasd_ro_store(struct device *dev, const char *buf, size_t count)
int ro_flag; int ro_flag;
devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
if (IS_ERR(devmap))
return PTR_ERR(devmap);
ro_flag = buf[0] == '1'; ro_flag = buf[0] == '1';
spin_lock(&dasd_devmap_lock); spin_lock(&dasd_devmap_lock);
if (ro_flag) if (ro_flag)
...@@ -665,15 +669,14 @@ static DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store); ...@@ -665,15 +669,14 @@ static DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store);
* use_diag controls whether the driver should use diag rather than ssch * use_diag controls whether the driver should use diag rather than ssch
* to talk to the device * to talk to the device
*/ */
/* TODO: Implement */
static ssize_t static ssize_t
dasd_use_diag_show(struct device *dev, char *buf) dasd_use_diag_show(struct device *dev, char *buf)
{ {
struct dasd_devmap *devmap; struct dasd_devmap *devmap;
int use_diag; int use_diag;
devmap = dev->driver_data; devmap = dasd_find_busid(dev->bus_id);
if (devmap) if (!IS_ERR(devmap))
use_diag = (devmap->features & DASD_FEATURE_USEDIAG) != 0; use_diag = (devmap->features & DASD_FEATURE_USEDIAG) != 0;
else else
use_diag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USEDIAG) != 0; use_diag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USEDIAG) != 0;
...@@ -684,21 +687,25 @@ static ssize_t ...@@ -684,21 +687,25 @@ static ssize_t
dasd_use_diag_store(struct device *dev, const char *buf, size_t count) dasd_use_diag_store(struct device *dev, const char *buf, size_t count)
{ {
struct dasd_devmap *devmap; struct dasd_devmap *devmap;
ssize_t rc;
int use_diag; int use_diag;
devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
if (IS_ERR(devmap))
return PTR_ERR(devmap);
use_diag = buf[0] == '1'; use_diag = buf[0] == '1';
spin_lock(&dasd_devmap_lock); spin_lock(&dasd_devmap_lock);
/* Changing diag discipline flag is only allowed in offline state. */ /* Changing diag discipline flag is only allowed in offline state. */
rc = count;
if (!devmap->device) { if (!devmap->device) {
if (use_diag) if (use_diag)
devmap->features |= DASD_FEATURE_USEDIAG; devmap->features |= DASD_FEATURE_USEDIAG;
else else
devmap->features &= ~DASD_FEATURE_USEDIAG; devmap->features &= ~DASD_FEATURE_USEDIAG;
} else } else
count = -EPERM; rc = -EPERM;
spin_unlock(&dasd_devmap_lock); spin_unlock(&dasd_devmap_lock);
return count; return rc;
} }
static static
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Bugreports.to..: <Linux390@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
* *
* $Revision: 1.39 $ * $Revision: 1.40 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -274,6 +274,7 @@ dasd_diag_check_device(struct dasd_device *device) ...@@ -274,6 +274,7 @@ dasd_diag_check_device(struct dasd_device *device)
"No memory to allocate initialization request"); "No memory to allocate initialization request");
return -ENOMEM; return -ENOMEM;
} }
/* try all sizes - needed for ECKD devices */
for (bsize = 512; bsize <= PAGE_SIZE; bsize <<= 1) { for (bsize = 512; bsize <= PAGE_SIZE; bsize <<= 1) {
mdsk_init_io(device, bsize, 0, 64); mdsk_init_io(device, bsize, 0, 64);
memset(&bio, 0, sizeof (struct dasd_diag_bio)); memset(&bio, 0, sizeof (struct dasd_diag_bio));
...@@ -291,8 +292,9 @@ dasd_diag_check_device(struct dasd_device *device) ...@@ -291,8 +292,9 @@ dasd_diag_check_device(struct dasd_device *device)
break; break;
mdsk_term_io(device); mdsk_term_io(device);
} }
if (bsize <= PAGE_SIZE && label[3] == bsize && if (bsize <= PAGE_SIZE && label[0] == 0xc3d4e2f1) {
label[0] == 0xc3d4e2f1) { /* get formatted blocksize from label block */
bsize = (int) label[3];
device->blocks = label[7]; device->blocks = label[7];
device->bp_block = bsize; device->bp_block = bsize;
device->s2b_shift = 0; /* bits to shift 512 to get a block */ device->s2b_shift = 0; /* bits to shift 512 to get a block */
...@@ -305,8 +307,12 @@ dasd_diag_check_device(struct dasd_device *device) ...@@ -305,8 +307,12 @@ dasd_diag_check_device(struct dasd_device *device)
(device->blocks << device->s2b_shift) >> 1); (device->blocks << device->s2b_shift) >> 1);
rc = 0; rc = 0;
} else { } else {
DEV_MESSAGE(KERN_WARNING, device, "%s", if (bsize > PAGE_SIZE)
"volume has incompatible disk layout"); DEV_MESSAGE(KERN_WARNING, device, "%s",
"DIAG access failed");
else
DEV_MESSAGE(KERN_WARNING, device, "%s",
"volume is not CMS formatted");
rc = -EMEDIUMTYPE; rc = -EMEDIUMTYPE;
} }
free_page((long) label); free_page((long) label);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Bugreports.to..: <Linux390@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
* *
* $Revision: 1.65 $ * $Revision: 1.66 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -1192,10 +1192,10 @@ dasd_eckd_release(struct block_device *bdev, int no, long args) ...@@ -1192,10 +1192,10 @@ dasd_eckd_release(struct block_device *bdev, int no, long args)
cqr = dasd_smalloc_request(dasd_eckd_discipline.name, cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
1, 32, device); 1, 32, device);
if (cqr == NULL) { if (IS_ERR(cqr)) {
MESSAGE(KERN_WARNING, "%s", MESSAGE(KERN_WARNING, "%s",
"No memory to allocate initialization request"); "Could not allocate initialization request");
return -ENOMEM; return PTR_ERR(cqr);
} }
cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE; cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE;
cqr->cpaddr->flags |= CCW_FLAG_SLI; cqr->cpaddr->flags |= CCW_FLAG_SLI;
...@@ -1236,10 +1236,10 @@ dasd_eckd_reserve(struct block_device *bdev, int no, long args) ...@@ -1236,10 +1236,10 @@ dasd_eckd_reserve(struct block_device *bdev, int no, long args)
cqr = dasd_smalloc_request(dasd_eckd_discipline.name, cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
1, 32, device); 1, 32, device);
if (cqr == NULL) { if (IS_ERR(cqr)) {
MESSAGE(KERN_WARNING, "%s", MESSAGE(KERN_WARNING, "%s",
"No memory to allocate initialization request"); "Could not allocate initialization request");
return -ENOMEM; return PTR_ERR(cqr);
} }
cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE; cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE;
cqr->cpaddr->flags |= CCW_FLAG_SLI; cqr->cpaddr->flags |= CCW_FLAG_SLI;
...@@ -1279,10 +1279,10 @@ dasd_eckd_steal_lock(struct block_device *bdev, int no, long args) ...@@ -1279,10 +1279,10 @@ dasd_eckd_steal_lock(struct block_device *bdev, int no, long args)
cqr = dasd_smalloc_request(dasd_eckd_discipline.name, cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
1, 32, device); 1, 32, device);
if (cqr == NULL) { if (IS_ERR(cqr)) {
MESSAGE(KERN_WARNING, "%s", MESSAGE(KERN_WARNING, "%s",
"No memory to allocate initialization request"); "Could not allocate initialization request");
return -ENOMEM; return PTR_ERR(cqr);
} }
cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SLCK; cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SLCK;
cqr->cpaddr->flags |= CCW_FLAG_SLI; cqr->cpaddr->flags |= CCW_FLAG_SLI;
...@@ -1323,10 +1323,10 @@ dasd_eckd_performance(struct block_device *bdev, int no, long args) ...@@ -1323,10 +1323,10 @@ dasd_eckd_performance(struct block_device *bdev, int no, long args)
(sizeof (struct dasd_psf_prssd_data) + (sizeof (struct dasd_psf_prssd_data) +
sizeof (struct dasd_rssd_perf_stats_t)), sizeof (struct dasd_rssd_perf_stats_t)),
device); device);
if (cqr == NULL) { if (IS_ERR(cqr)) {
MESSAGE(KERN_WARNING, "%s", MESSAGE(KERN_WARNING, "%s",
"No memory to allocate initialization request"); "Could not allocate initialization request");
return -ENOMEM; return PTR_ERR(cqr);
} }
cqr->device = device; cqr->device = device;
cqr->retries = 0; cqr->retries = 0;
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* /proc interface for the dasd driver. * /proc interface for the dasd driver.
* *
* $Revision: 1.27 $ * $Revision: 1.29 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -248,6 +248,8 @@ dasd_statistics_write(struct file *file, const char __user *user_buf, ...@@ -248,6 +248,8 @@ dasd_statistics_write(struct file *file, const char __user *user_buf,
if (user_len > 65536) if (user_len > 65536)
user_len = 65536; user_len = 65536;
buffer = dasd_get_user_string(user_buf, user_len); buffer = dasd_get_user_string(user_buf, user_len);
if (IS_ERR(buffer))
return PTR_ERR(buffer);
MESSAGE(KERN_INFO, "/proc/dasd/statictics: '%s'", buffer); MESSAGE(KERN_INFO, "/proc/dasd/statictics: '%s'", buffer);
/* check for valid verbs */ /* check for valid verbs */
...@@ -258,20 +260,20 @@ dasd_statistics_write(struct file *file, const char __user *user_buf, ...@@ -258,20 +260,20 @@ dasd_statistics_write(struct file *file, const char __user *user_buf,
if (strcmp(str, "on") == 0) { if (strcmp(str, "on") == 0) {
/* switch on statistics profiling */ /* switch on statistics profiling */
dasd_profile_level = DASD_PROFILE_ON; dasd_profile_level = DASD_PROFILE_ON;
MESSAGE(KERN_INFO, "%s", "Statictics switched on"); MESSAGE(KERN_INFO, "%s", "Statistics switched on");
} else if (strcmp(str, "off") == 0) { } else if (strcmp(str, "off") == 0) {
/* switch off and reset statistics profiling */ /* switch off and reset statistics profiling */
memset(&dasd_global_profile, memset(&dasd_global_profile,
0, sizeof (struct dasd_profile_info_t)); 0, sizeof (struct dasd_profile_info_t));
dasd_profile_level = DASD_PROFILE_OFF; dasd_profile_level = DASD_PROFILE_OFF;
MESSAGE(KERN_INFO, "%s", "Statictics switched off"); MESSAGE(KERN_INFO, "%s", "Statistics switched off");
} else } else
goto out_error; goto out_error;
} else if (strncmp(str, "reset", 5) == 0) { } else if (strncmp(str, "reset", 5) == 0) {
/* reset the statistics */ /* reset the statistics */
memset(&dasd_global_profile, 0, memset(&dasd_global_profile, 0,
sizeof (struct dasd_profile_info_t)); sizeof (struct dasd_profile_info_t));
MESSAGE(KERN_INFO, "%s", "Statictics reset"); MESSAGE(KERN_INFO, "%s", "Statistics reset");
} else } else
goto out_error; goto out_error;
kfree(buffer); kfree(buffer);
......
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