Commit 55d21e2b authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: dasd driver

From: Stefan Weinhuber <wein@de.ibm.com>

dasd driver changes:
 - Fix parameter parsing to allow sequences of devices, ranges
   and keywords.
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 cb1b057d
...@@ -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.30 $ * $Revision: 1.33 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -204,19 +204,57 @@ dasd_feature_list(char *str, char **endp) ...@@ -204,19 +204,57 @@ dasd_feature_list(char *str, char **endp)
} }
/* /*
* Read comma separated list of dasd ranges. * Try to match the first element on the comma separated parse string
* with one of the known keywords. If a keyword is found, take the approprate
* 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 inline int static char *
dasd_ranges_list(char *str) dasd_parse_keyword( char *parsestring ) {
{
char *nextcomma, *residual_str;
int length;
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) {
dasd_autodetect = 1;
MESSAGE (KERN_INFO, "%s",
"turning to autodetection mode");
return residual_str;
}
if (strncmp ("probeonly", parsestring, length) == 0) {
dasd_probeonly = 1;
MESSAGE(KERN_INFO, "%s",
"turning to probeonly mode");
return residual_str;
}
return ERR_PTR(-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
* successfull, 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.
*/
static char *
dasd_parse_range( char *parsestring ) {
struct dasd_devmap *devmap; struct dasd_devmap *devmap;
int from, from_id0, from_id1; int from, from_id0, from_id1;
int to, to_id0, to_id1; int to, to_id0, to_id1;
int features, rc; int features, rc;
char bus_id[BUS_ID_SIZE+1], *orig_str; char bus_id[BUS_ID_SIZE+1], *str;
orig_str = str; str = parsestring;
while (1) {
rc = dasd_busid(&str, &from_id0, &from_id1, &from); rc = dasd_busid(&str, &from_id0, &from_id1, &from);
if (rc == 0) { if (rc == 0) {
to = from; to = from;
...@@ -231,67 +269,65 @@ dasd_ranges_list(char *str) ...@@ -231,67 +269,65 @@ dasd_ranges_list(char *str)
(from_id0 != to_id0 || from_id1 != to_id1 || from > to)) (from_id0 != to_id0 || from_id1 != to_id1 || from > to))
rc = -EINVAL; rc = -EINVAL;
if (rc) { if (rc) {
MESSAGE(KERN_ERR, "Invalid device range %s", orig_str); MESSAGE(KERN_ERR, "Invalid device range %s", parsestring);
return rc; return ERR_PTR(rc);
} }
features = dasd_feature_list(str, &str); features = dasd_feature_list(str, &str);
if (features < 0) if (features < 0)
return -EINVAL; return ERR_PTR(-EINVAL);
while (from <= to) { while (from <= to) {
sprintf(bus_id, "%01x.%01x.%04x", sprintf(bus_id, "%01x.%01x.%04x",
from_id0, from_id1, from++); from_id0, from_id1, from++);
devmap = dasd_add_busid(bus_id, features); devmap = dasd_add_busid(bus_id, features);
if (IS_ERR(devmap)) if (IS_ERR(devmap))
return PTR_ERR(devmap); return (char *)devmap;
}
if (*str != ',')
break;
str++;
} }
if (*str != '\0') { if (*str == ',')
return str + 1;
if (*str == '\0')
return str;
MESSAGE(KERN_WARNING, MESSAGE(KERN_WARNING,
"junk at end of dasd parameter string: %s\n", str); "junk at end of dasd parameter string: %s\n", str);
return -EINVAL; return ERR_PTR(-EINVAL);
}
return 0;
} }
/* static inline char *
* Parse a single dasd= parameter. dasd_parse_next_element( char *parsestring ) {
*/ char * residual_str;
static int residual_str = dasd_parse_keyword(parsestring);
dasd_parameter(char *str) if (!IS_ERR(residual_str))
{ return residual_str;
if (strcmp ("autodetect", str) == 0) { residual_str = dasd_parse_range(parsestring);
dasd_autodetect = 1; return residual_str;
MESSAGE (KERN_INFO, "%s",
"turning to autodetection mode");
return 0;
}
if (strcmp ("probeonly", str) == 0) {
dasd_probeonly = 1;
MESSAGE(KERN_INFO, "%s",
"turning to probeonly mode");
return 0;
}
/* turn off autodetect mode and scan for dasd ranges */
dasd_autodetect = 0;
return dasd_ranges_list(str);
} }
/* /*
* Parse parameters stored in dasd[] and dasd_disciplines[]. * Parse parameters stored in dasd[]
* The 'dasd=...' parameter allows to specify a comma separated list of
* keywords and device ranges. When the dasd driver is build into the kernel,
* the complete list will be stored as one element of the dasd[] array.
* When the dasd driver is build as a module, then the list is broken into
* it's elements and each dasd[] entry contains one element.
*/ */
int int
dasd_parse(void) dasd_parse(void)
{ {
int rc, i; int rc, i;
char *parsestring;
rc = 0; rc = 0;
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
if (dasd[i] == NULL) if (dasd[i] == NULL)
break; break;
rc = dasd_parameter(dasd[i]); 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) { if (rc) {
DBF_EVENT(DBF_ALERT, "%s", "invalid range found"); DBF_EVENT(DBF_ALERT, "%s", "invalid range found");
break; break;
......
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