Commit 40221738 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: dcss segments cleanup

From: Carsten Otte <cotte@de.ibm.com>
From: Gerald Schaefer <geraldsc@de.ibm.com>

Cleanup segment load/unload infrastructure.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f3351c55
This diff is collapsed.
...@@ -139,6 +139,53 @@ dcssblk_get_device_by_name(char *name) ...@@ -139,6 +139,53 @@ dcssblk_get_device_by_name(char *name)
return NULL; return NULL;
} }
/*
* print appropriate error message for segment_load()/segment_info()
* return code
*/
static void
dcssblk_segment_warn(int rc, char* seg_name)
{
switch (rc) {
case -ENOENT:
PRINT_WARN("cannot load/query segment %s, does not exist\n",
seg_name);
break;
case -ENOSYS:
PRINT_WARN("cannot load/query segment %s, not running on VM\n",
seg_name);
break;
case -EIO:
PRINT_WARN("cannot load/query segment %s, hardware error\n",
seg_name);
break;
case -ENOTSUPP:
PRINT_WARN("cannot load/query segment %s, is a multi-part "
"segment\n", seg_name);
break;
case -ENOSPC:
PRINT_WARN("cannot load/query segment %s, overlaps with "
"storage\n", seg_name);
break;
case -EBUSY:
PRINT_WARN("cannot load/query segment %s, overlaps with "
"already loaded dcss\n", seg_name);
break;
case -EPERM:
PRINT_WARN("cannot load/query segment %s, already loaded in "
"incompatible mode\n", seg_name);
break;
case -ENOMEM:
PRINT_WARN("cannot load/query segment %s, out of memory\n",
seg_name);
break;
default:
PRINT_WARN("cannot load/query segment %s, return value %i\n",
seg_name, rc);
break;
}
}
/* /*
* device attribute for switching shared/nonshared (exclusive) * device attribute for switching shared/nonshared (exclusive)
* operation (show + store) * operation (show + store)
...@@ -185,61 +232,38 @@ dcssblk_shared_store(struct device *dev, const char *inbuf, size_t count) ...@@ -185,61 +232,38 @@ dcssblk_shared_store(struct device *dev, const char *inbuf, size_t count)
if (inbuf[0] == '1') { if (inbuf[0] == '1') {
// reload segment in shared mode // reload segment in shared mode
segment_unload(dev_info->segment_name); segment_unload(dev_info->segment_name);
rc = segment_load(dev_info->segment_name, SEGMENT_SHARED_RO, rc = segment_load(dev_info->segment_name, SEGMENT_SHARED,
&dev_info->start, &dev_info->end); &dev_info->start, &dev_info->end);
if (rc < 0) { if (rc < 0) {
PRINT_ERR("Segment %s not reloaded, rc=%d\n", dcssblk_segment_warn(rc, dev_info->segment_name);
dev_info->segment_name, rc);
goto removeseg; goto removeseg;
} }
dev_info->is_shared = 1; dev_info->is_shared = 1;
PRINT_INFO("Segment %s reloaded, shared mode.\n", if (rc == SEG_TYPE_SR || rc == SEG_TYPE_ER || rc == SEG_TYPE_SC)
dev_info->segment_name); set_disk_ro(dev_info->gd, 1);
} else if (inbuf[0] == '0') { } else if (inbuf[0] == '0') {
// reload segment in exclusive mode // reload segment in exclusive mode
if (dev_info->segment_type == SEG_TYPE_SC) {
PRINT_ERR("Segment type SC (%s) cannot be loaded in "
"non-shared mode\n", dev_info->segment_name);
up_write(&dcssblk_devices_sem);
return -EINVAL;
}
segment_unload(dev_info->segment_name); segment_unload(dev_info->segment_name);
rc = segment_load(dev_info->segment_name, SEGMENT_EXCLUSIVE_RW, rc = segment_load(dev_info->segment_name, SEGMENT_EXCLUSIVE,
&dev_info->start, &dev_info->end); &dev_info->start, &dev_info->end);
if (rc < 0) { if (rc < 0) {
PRINT_ERR("Segment %s not reloaded, rc=%d\n", dcssblk_segment_warn(rc, dev_info->segment_name);
dev_info->segment_name, rc);
goto removeseg; goto removeseg;
} }
dev_info->is_shared = 0; dev_info->is_shared = 0;
PRINT_INFO("Segment %s reloaded, exclusive (read-write) mode.\n", set_disk_ro(dev_info->gd, 0);
dev_info->segment_name);
} else { } else {
up_write(&dcssblk_devices_sem); up_write(&dcssblk_devices_sem);
PRINT_WARN("Invalid value, must be 0 or 1\n"); PRINT_WARN("Invalid value, must be 0 or 1\n");
return -EINVAL; return -EINVAL;
} }
dev_info->segment_type = rc;
rc = count; rc = count;
switch (dev_info->segment_type) {
case SEGMENT_SHARED_RO:
case SEGMENT_EXCLUSIVE_RO:
set_disk_ro(dev_info->gd, 1);
break;
case SEGMENT_SHARED_RW:
case SEGMENT_EXCLUSIVE_RW:
set_disk_ro(dev_info->gd, 0);
break;
}
if ((inbuf[0] == '1') &&
((dev_info->segment_type == SEGMENT_EXCLUSIVE_RO) ||
(dev_info->segment_type == SEGMENT_EXCLUSIVE_RW))) {
PRINT_WARN("Could not get shared copy of segment %s\n",
dev_info->segment_name);
rc = -EPERM;
}
if ((inbuf[0] == '0') &&
((dev_info->segment_type == SEGMENT_SHARED_RO) ||
(dev_info->segment_type == SEGMENT_SHARED_RW))) {
PRINT_WARN("Could not get exclusive copy of segment %s\n",
dev_info->segment_name);
rc = -EPERM;
}
up_write(&dcssblk_devices_sem); up_write(&dcssblk_devices_sem);
goto out; goto out;
...@@ -292,7 +316,7 @@ dcssblk_save_store(struct device *dev, const char *inbuf, size_t count) ...@@ -292,7 +316,7 @@ dcssblk_save_store(struct device *dev, const char *inbuf, size_t count)
// device is idle => we save immediately // device is idle => we save immediately
PRINT_INFO("Saving segment %s\n", PRINT_INFO("Saving segment %s\n",
dev_info->segment_name); dev_info->segment_name);
segment_replace(dev_info->segment_name); segment_save(dev_info->segment_name);
} else { } else {
// device is busy => we save it when it becomes // device is busy => we save it when it becomes
// idle in dcssblk_release // idle in dcssblk_release
...@@ -390,18 +414,17 @@ dcssblk_add_store(struct device *dev, const char *buf, size_t count) ...@@ -390,18 +414,17 @@ dcssblk_add_store(struct device *dev, const char *buf, size_t count)
/* /*
* load the segment * load the segment
*/ */
rc = segment_load(local_buf, SEGMENT_SHARED_RO, rc = segment_load(local_buf, SEGMENT_SHARED,
&dev_info->start, &dev_info->end); &dev_info->start, &dev_info->end);
if (rc < 0) { if (rc < 0) {
PRINT_ERR("Segment %s not loaded, rc=%d\n", local_buf, rc); dcssblk_segment_warn(rc, dev_info->segment_name);
goto dealloc_gendisk; goto dealloc_gendisk;
} }
seg_byte_size = (dev_info->end - dev_info->start + 1); seg_byte_size = (dev_info->end - dev_info->start + 1);
set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors
PRINT_INFO("Loaded segment %s from %p to %p, size = %lu Byte, " PRINT_INFO("Loaded segment %s, size = %lu Byte, "
"capacity = %lu sectors (512 Byte)\n", local_buf, "capacity = %lu (512 Byte) sectors\n", local_buf,
(void *) dev_info->start, (void *) dev_info->end, seg_byte_size, seg_byte_size >> 9);
seg_byte_size, seg_byte_size >> 9);
dev_info->segment_type = rc; dev_info->segment_type = rc;
dev_info->save_pending = 0; dev_info->save_pending = 0;
...@@ -451,12 +474,12 @@ dcssblk_add_store(struct device *dev, const char *buf, size_t count) ...@@ -451,12 +474,12 @@ dcssblk_add_store(struct device *dev, const char *buf, size_t count)
blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096); blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096);
switch (dev_info->segment_type) { switch (dev_info->segment_type) {
case SEGMENT_SHARED_RO: case SEG_TYPE_SR:
case SEGMENT_EXCLUSIVE_RO: case SEG_TYPE_ER:
case SEG_TYPE_SC:
set_disk_ro(dev_info->gd,1); set_disk_ro(dev_info->gd,1);
break; break;
case SEGMENT_SHARED_RW: default:
case SEGMENT_EXCLUSIVE_RW:
set_disk_ro(dev_info->gd,0); set_disk_ro(dev_info->gd,0);
break; break;
} }
...@@ -589,7 +612,7 @@ dcssblk_release(struct inode *inode, struct file *filp) ...@@ -589,7 +612,7 @@ dcssblk_release(struct inode *inode, struct file *filp)
&& (dev_info->save_pending)) { && (dev_info->save_pending)) {
PRINT_INFO("Segment %s became idle and is being saved now\n", PRINT_INFO("Segment %s became idle and is being saved now\n",
dev_info->segment_name); dev_info->segment_name);
segment_replace(dev_info->segment_name); segment_save(dev_info->segment_name);
dev_info->save_pending = 0; dev_info->save_pending = 0;
} }
up_write(&dcssblk_devices_sem); up_write(&dcssblk_devices_sem);
......
...@@ -115,6 +115,53 @@ dcss_mkname(char *ascii_name, char *ebcdic_name) ...@@ -115,6 +115,53 @@ dcss_mkname(char *ascii_name, char *ebcdic_name)
ASCEBC(ebcdic_name, 8); ASCEBC(ebcdic_name, 8);
} }
/*
* print appropriate error message for segment_load()/segment_info()
* return code
*/
static void
mon_segment_warn(int rc, char* seg_name)
{
switch (rc) {
case -ENOENT:
P_WARNING("cannot load/query segment %s, does not exist\n",
seg_name);
break;
case -ENOSYS:
P_WARNING("cannot load/query segment %s, not running on VM\n",
seg_name);
break;
case -EIO:
P_WARNING("cannot load/query segment %s, hardware error\n",
seg_name);
break;
case -ENOTSUPP:
P_WARNING("cannot load/query segment %s, is a multi-part "
"segment\n", seg_name);
break;
case -ENOSPC:
P_WARNING("cannot load/query segment %s, overlaps with "
"storage\n", seg_name);
break;
case -EBUSY:
P_WARNING("cannot load/query segment %s, overlaps with "
"already loaded dcss\n", seg_name);
break;
case -EPERM:
P_WARNING("cannot load/query segment %s, already loaded in "
"incompatible mode\n", seg_name);
break;
case -ENOMEM:
P_WARNING("cannot load/query segment %s, out of memory\n",
seg_name);
break;
default:
P_WARNING("cannot load/query segment %s, return value %i\n",
seg_name, rc);
break;
}
}
static inline unsigned long static inline unsigned long
mon_mca_start(struct mon_msg *monmsg) mon_mca_start(struct mon_msg *monmsg)
{ {
...@@ -534,10 +581,21 @@ mon_init(void) ...@@ -534,10 +581,21 @@ mon_init(void)
return -ENODEV; return -ENODEV;
} }
rc = segment_load(mon_dcss_name, SEGMENT_SHARED_RO, rc = segment_info(mon_dcss_name);
if (rc < 0) {
mon_segment_warn(rc, mon_dcss_name);
return rc;
}
if (rc != SEG_TYPE_SC) {
P_ERROR("segment %s has unsupported type, should be SC\n",
mon_dcss_name);
return -EINVAL;
}
rc = segment_load(mon_dcss_name, SEGMENT_SHARED,
&mon_dcss_start, &mon_dcss_end); &mon_dcss_start, &mon_dcss_end);
if (rc < 0) { if (rc < 0) {
P_ERROR("Segment %s not loaded, rc = %d\n", mon_dcss_name, rc); mon_segment_warn(rc, mon_dcss_name);
return -EINVAL; return -EINVAL;
} }
dcss_mkname(mon_dcss_name, &user_data_connect[8]); dcss_mkname(mon_dcss_name, &user_data_connect[8]);
......
...@@ -8,12 +8,23 @@ ...@@ -8,12 +8,23 @@
#ifndef _ASM_S390X_DCSS_H #ifndef _ASM_S390X_DCSS_H
#define _ASM_S390X_DCSS_H #define _ASM_S390X_DCSS_H
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#define SEGMENT_SHARED_RW 0
#define SEGMENT_SHARED_RO 1 /* possible values for segment type as returned by segment_info */
#define SEGMENT_EXCLUSIVE_RW 2 #define SEG_TYPE_SW 0
#define SEGMENT_EXCLUSIVE_RO 3 #define SEG_TYPE_EW 1
#define SEG_TYPE_SR 2
#define SEG_TYPE_ER 3
#define SEG_TYPE_SN 4
#define SEG_TYPE_EN 5
#define SEG_TYPE_SC 6
#define SEGMENT_SHARED 0
#define SEGMENT_EXCLUSIVE 1
extern int segment_load (char *name,int segtype,unsigned long *addr,unsigned long *length); extern int segment_load (char *name,int segtype,unsigned long *addr,unsigned long *length);
extern void segment_unload(char *name); extern void segment_unload(char *name);
extern void segment_replace(char *name); extern void segment_save(char *name);
extern int segment_info (char* name);
#endif #endif
#endif #endif
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