summaryrefslogtreecommitdiffstats
path: root/drivers/s390/block
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/block')
-rw-r--r--drivers/s390/block/dasd_devmap.c258
-rw-r--r--drivers/s390/block/dasd_int.h2
2 files changed, 125 insertions, 135 deletions
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 4c8eff6b1aab..041bdc4429c1 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -107,7 +107,7 @@ dasd_hash_busid(const char *bus_id)
#ifndef MODULE
static int __init dasd_call_setup(char *opt)
{
- static int i;
+ static int i __initdata;
char *tmp;
while (i < DASD_MAX_PARAMS) {
@@ -129,14 +129,13 @@ __setup ("dasd=", dasd_call_setup);
/*
* Read a device busid/devno from a string.
*/
-static int
-
-dasd_busid(char **str, int *id0, int *id1, int *devno)
+static int __init dasd_busid(char *str, int *id0, int *id1, int *devno)
{
- int val, old_style;
+ unsigned int val;
+ char *tok;
/* Interpret ipldev busid */
- if (strncmp(DASD_IPLDEV, *str, strlen(DASD_IPLDEV)) == 0) {
+ if (strncmp(DASD_IPLDEV, str, strlen(DASD_IPLDEV)) == 0) {
if (ipl_info.type != IPL_TYPE_CCW) {
pr_err("The IPL device is not a CCW device\n");
return -EINVAL;
@@ -144,63 +143,50 @@ dasd_busid(char **str, int *id0, int *id1, int *devno)
*id0 = 0;
*id1 = ipl_info.data.ccw.dev_id.ssid;
*devno = ipl_info.data.ccw.dev_id.devno;
- *str += strlen(DASD_IPLDEV);
return 0;
}
- /* check for leading '0x' */
- old_style = 0;
- if ((*str)[0] == '0' && (*str)[1] == 'x') {
- *str += 2;
- old_style = 1;
- }
- if (!isxdigit((*str)[0])) /* We require at least one hex digit */
- return -EINVAL;
- val = simple_strtoul(*str, str, 16);
- if (old_style || (*str)[0] != '.') {
+
+ /* Old style 0xXXXX or XXXX */
+ if (!kstrtouint(str, 16, &val)) {
*id0 = *id1 = 0;
if (val < 0 || val > 0xffff)
return -EINVAL;
*devno = val;
return 0;
}
+
/* New style x.y.z busid */
- if (val < 0 || val > 0xff)
+ tok = strsep(&str, ".");
+ if (kstrtouint(tok, 16, &val) || val > 0xff)
return -EINVAL;
*id0 = val;
- (*str)++;
- if (!isxdigit((*str)[0])) /* We require at least one hex digit */
- return -EINVAL;
- val = simple_strtoul(*str, str, 16);
- if (val < 0 || val > 0xff || (*str)++[0] != '.')
+
+ tok = strsep(&str, ".");
+ if (kstrtouint(tok, 16, &val) || val > 0xff)
return -EINVAL;
*id1 = val;
- if (!isxdigit((*str)[0])) /* We require at least one hex digit */
- return -EINVAL;
- val = simple_strtoul(*str, str, 16);
- if (val < 0 || val > 0xffff)
+
+ tok = strsep(&str, ".");
+ if (kstrtouint(tok, 16, &val) || val > 0xffff)
return -EINVAL;
*devno = val;
+
return 0;
}
/*
- * Read colon separated list of dasd features. Currently there is
- * only one: "ro" for read-only devices. The default feature set
- * is empty (value 0).
+ * Read colon separated list of dasd features.
*/
-static int
-dasd_feature_list(char *str, char **endp)
+static int __init dasd_feature_list(char *str)
{
int features, len, rc;
+ features = 0;
rc = 0;
- if (*str != '(') {
- *endp = str;
+
+ if (!str)
return DASD_FEATURE_DEFAULT;
- }
- str++;
- features = 0;
while (1) {
for (len = 0;
@@ -225,15 +211,8 @@ dasd_feature_list(char *str, char **endp)
break;
str++;
}
- if (*str != ')') {
- pr_warn("A closing parenthesis ')' is missing in the dasd= parameter\n");
- rc = -EINVAL;
- } else
- str++;
- *endp = str;
- if (rc != 0)
- return rc;
- return features;
+
+ return rc ? : features;
}
/*
@@ -242,48 +221,38 @@ dasd_feature_list(char *str, char **endp)
* action and return a pointer to the residual string. If the first element
* could not be matched to any keyword then return an error code.
*/
-static char *
-dasd_parse_keyword( char *parsestring ) {
-
- char *nextcomma, *residual_str;
- int length;
+static int __init dasd_parse_keyword(char *keyword)
+{
+ int length = strlen(keyword);
- nextcomma = strchr(parsestring,',');
- if (nextcomma) {
- length = nextcomma - parsestring;
- residual_str = nextcomma + 1;
- } else {
- length = strlen(parsestring);
- residual_str = parsestring + length;
- }
- if (strncmp("autodetect", parsestring, length) == 0) {
+ if (strncmp("autodetect", keyword, length) == 0) {
dasd_autodetect = 1;
pr_info("The autodetection mode has been activated\n");
- return residual_str;
+ return 0;
}
- if (strncmp("probeonly", parsestring, length) == 0) {
+ if (strncmp("probeonly", keyword, length) == 0) {
dasd_probeonly = 1;
pr_info("The probeonly mode has been activated\n");
- return residual_str;
+ return 0;
}
- if (strncmp("nopav", parsestring, length) == 0) {
+ if (strncmp("nopav", keyword, length) == 0) {
if (MACHINE_IS_VM)
pr_info("'nopav' is not supported on z/VM\n");
else {
dasd_nopav = 1;
pr_info("PAV support has be deactivated\n");
}
- return residual_str;
+ return 0;
}
- if (strncmp("nofcx", parsestring, length) == 0) {
+ if (strncmp("nofcx", keyword, length) == 0) {
dasd_nofcx = 1;
pr_info("High Performance FICON support has been "
"deactivated\n");
- return residual_str;
+ return 0;
}
- if (strncmp("fixedbuffers", parsestring, length) == 0) {
+ if (strncmp("fixedbuffers", keyword, length) == 0) {
if (dasd_page_cache)
- return residual_str;
+ return 0;
dasd_page_cache =
kmem_cache_create("dasd_page_cache", PAGE_SIZE,
PAGE_SIZE, SLAB_CACHE_DMA,
@@ -294,73 +263,97 @@ dasd_parse_keyword( char *parsestring ) {
else
DBF_EVENT(DBF_INFO, "%s",
"turning on fixed buffer mode");
- return residual_str;
- }
- return ERR_PTR(-EINVAL);
+ return 0;
+ }
+
+ return -EINVAL;
}
/*
- * Try to interprete the first element on the comma separated parse string
- * as a device number or a range of devices. If the interpretation is
- * successful, create the matching dasd_devmap entries and return a pointer
- * to the residual string.
- * If interpretation fails or in case of an error, return an error code.
+ * Split a string of a device range into its pieces and return the from, to, and
+ * feature parts separately.
+ * e.g.:
+ * 0.0.1234-0.0.5678(ro:erplog) -> from: 0.0.1234 to: 0.0.5678 features: ro:erplog
+ * 0.0.8765(raw) -> from: 0.0.8765 to: null features: raw
+ * 0x4321 -> from: 0x4321 to: null features: null
*/
-static char *
-dasd_parse_range( char *parsestring ) {
+static int __init dasd_evaluate_range_param(char *range, char **from_str,
+ char **to_str, char **features_str)
+{
+ int rc = 0;
+ /* Do we have a range or a single device? */
+ if (strchr(range, '-')) {
+ *from_str = strsep(&range, "-");
+ *to_str = strsep(&range, "(");
+ *features_str = strsep(&range, ")");
+ } else {
+ *from_str = strsep(&range, "(");
+ *features_str = strsep(&range, ")");
+ }
+
+ if (*features_str && !range) {
+ pr_warn("A closing parenthesis ')' is missing in the dasd= parameter\n");
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+/*
+ * Try to interprete the range string as a device number or a range of devices.
+ * If the interpretation is successful, create the matching dasd_devmap entries.
+ * If interpretation fails or in case of an error, return an error code.
+ */
+static int __init dasd_parse_range(const char *range)
+{
struct dasd_devmap *devmap;
int from, from_id0, from_id1;
int to, to_id0, to_id1;
- int features, rc;
- char bus_id[DASD_BUS_ID_SIZE+1], *str;
-
- str = parsestring;
- rc = dasd_busid(&str, &from_id0, &from_id1, &from);
- if (rc == 0) {
- to = from;
- to_id0 = from_id0;
- to_id1 = from_id1;
- if (*str == '-') {
- str++;
- rc = dasd_busid(&str, &to_id0, &to_id1, &to);
+ int features;
+ char bus_id[DASD_BUS_ID_SIZE + 1];
+ char *features_str = NULL;
+ char *from_str = NULL;
+ char *to_str = NULL;
+ size_t len = strlen(range) + 1;
+ char tmp[len];
+
+ strlcpy(tmp, range, len);
+
+ if (dasd_evaluate_range_param(tmp, &from_str, &to_str, &features_str))
+ goto out_err;
+
+ if (dasd_busid(from_str, &from_id0, &from_id1, &from))
+ goto out_err;
+
+ to = from;
+ to_id0 = from_id0;
+ to_id1 = from_id1;
+ if (to_str) {
+ if (dasd_busid(to_str, &to_id0, &to_id1, &to))
+ goto out_err;
+ if (from_id0 != to_id0 || from_id1 != to_id1 || from > to) {
+ pr_err("%s is not a valid device range\n", range);
+ goto out_err;
}
}
- if (rc == 0 &&
- (from_id0 != to_id0 || from_id1 != to_id1 || from > to))
- rc = -EINVAL;
- if (rc) {
- pr_err("%s is not a valid device range\n", parsestring);
- return ERR_PTR(rc);
- }
- features = dasd_feature_list(str, &str);
+
+ features = dasd_feature_list(features_str);
if (features < 0)
- return ERR_PTR(-EINVAL);
+ goto out_err;
/* each device in dasd= parameter should be set initially online */
features |= DASD_FEATURE_INITIAL_ONLINE;
while (from <= to) {
- sprintf(bus_id, "%01x.%01x.%04x",
- from_id0, from_id1, from++);
+ sprintf(bus_id, "%01x.%01x.%04x", from_id0, from_id1, from++);
devmap = dasd_add_busid(bus_id, features);
if (IS_ERR(devmap))
- return (char *)devmap;
+ return PTR_ERR(devmap);
}
- if (*str == ',')
- return str + 1;
- if (*str == '\0')
- return str;
- pr_warn("The dasd= parameter value %s has an invalid ending\n", str);
- return ERR_PTR(-EINVAL);
-}
-static char *
-dasd_parse_next_element( char *parsestring ) {
- char * residual_str;
- residual_str = dasd_parse_keyword(parsestring);
- if (!IS_ERR(residual_str))
- return residual_str;
- residual_str = dasd_parse_range(parsestring);
- return residual_str;
+ return 0;
+
+out_err:
+ return -EINVAL;
}
/*
@@ -369,30 +362,27 @@ dasd_parse_next_element( char *parsestring ) {
* keywords and device ranges. The parameters in that list will be stored as
* separate elementes in dasd[].
*/
-int
-dasd_parse(void)
+int __init dasd_parse(void)
{
int rc, i;
- char *parsestring;
+ char *cur;
rc = 0;
for (i = 0; i < DASD_MAX_PARAMS; i++) {
- if (dasd[i] == NULL)
+ cur = dasd[i];
+ if (!cur)
break;
- parsestring = dasd[i];
- /* loop over the comma separated list in the parsestring */
- while (*parsestring) {
- parsestring = dasd_parse_next_element(parsestring);
- if(IS_ERR(parsestring)) {
- rc = PTR_ERR(parsestring);
- break;
- }
- }
- if (rc) {
- DBF_EVENT(DBF_ALERT, "%s", "invalid range found");
+ if (*cur == '\0')
+ continue;
+
+ rc = dasd_parse_keyword(cur);
+ if (rc)
+ rc = dasd_parse_range(cur);
+
+ if (rc)
break;
- }
}
+
return rc;
}
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 24be210c10e5..518dba2732d5 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -805,7 +805,7 @@ struct dasd_device *dasd_device_from_devindex(int);
void dasd_add_link_to_gendisk(struct gendisk *, struct dasd_device *);
struct dasd_device *dasd_device_from_gendisk(struct gendisk *);
-int dasd_parse(void);
+int dasd_parse(void) __init;
int dasd_busid_known(const char *);
/* externals in dasd_gendisk.c */