X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fs390%2Fblock%2Fdasd_devmap.c;h=ad1841a96c87b4cfd4ea5b2f4727a288604fd3d3;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=812bb006625a9d0089529b7c089361ece6efd9a3;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 812bb0066..ad1841a96 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -11,7 +11,7 @@ * functions may not be called from interrupt context. In particular * dasd_get_device is a no-no from interrupt context. * - * $Revision: 1.30 $ + * $Revision: 1.37 $ */ #include @@ -26,6 +26,9 @@ #include "dasd_int.h" +kmem_cache_t *dasd_page_cache; +EXPORT_SYMBOL(dasd_page_cache); + /* * dasd_devmap_t is used to store the features and the relation * between device number and device index. To find a dasd_devmap_t @@ -67,11 +70,10 @@ int dasd_autodetect = 0; /* is true, when autodetection is active */ * strings when running as a module. */ static char *dasd[256]; - /* * Single spinlock to protect devmap structures and lists. */ -static spinlock_t dasd_devmap_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(dasd_devmap_lock); /* * Hash lists for devmap structures. @@ -204,94 +206,144 @@ 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 -dasd_ranges_list(char *str) -{ +static char * +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; + } + if (strncmp ("fixedbuffers", parsestring, length) == 0) { + if (dasd_page_cache) + return residual_str; + dasd_page_cache = + kmem_cache_create("dasd_page_cache", PAGE_SIZE, 0, + SLAB_CACHE_DMA, NULL, NULL ); + if (!dasd_page_cache) + MESSAGE(KERN_WARNING, "%s", "Failed to create slab, " + "fixed buffer mode disabled."); + else + MESSAGE (KERN_INFO, "%s", + "turning on fixed buffer 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; int from, from_id0, from_id1; int to, to_id0, to_id1; int features, rc; - char bus_id[BUS_ID_SIZE+1], *orig_str; - - orig_str = str; - while (1) { - 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); - } - } - if (rc == 0 && - (from_id0 != to_id0 || from_id1 != to_id1 || from > to)) - rc = -EINVAL; - if (rc) { - MESSAGE(KERN_ERR, "Invalid device range %s", orig_str); - return rc; - } - features = dasd_feature_list(str, &str); - if (features < 0) - return -EINVAL; - while (from <= to) { - sprintf(bus_id, "%01x.%01x.%04x", - from_id0, from_id1, from++); - devmap = dasd_add_busid(bus_id, features); - if (IS_ERR(devmap)) - return PTR_ERR(devmap); + char bus_id[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); } - if (*str != ',') - break; - str++; } - if (*str != '\0') { - MESSAGE(KERN_WARNING, - "junk at end of dasd parameter string: %s\n", str); - return -EINVAL; + if (rc == 0 && + (from_id0 != to_id0 || from_id1 != to_id1 || from > to)) + rc = -EINVAL; + if (rc) { + MESSAGE(KERN_ERR, "Invalid device range %s", parsestring); + return ERR_PTR(rc); } - return 0; + features = dasd_feature_list(str, &str); + if (features < 0) + return ERR_PTR(-EINVAL); + while (from <= to) { + 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; + } + if (*str == ',') + return str + 1; + if (*str == '\0') + return str; + MESSAGE(KERN_WARNING, + "junk at end of dasd parameter string: %s\n", str); + return ERR_PTR(-EINVAL); } -/* - * Parse a single dasd= parameter. - */ -static int -dasd_parameter(char *str) -{ - if (strcmp ("autodetect", str) == 0) { - dasd_autodetect = 1; - 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); +static inline 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; } /* - * 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 dasd_parse(void) { int rc, i; + char *parsestring; rc = 0; for (i = 0; i < 256; i++) { if (dasd[i] == NULL) 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) { DBF_EVENT(DBF_ALERT, "%s", "invalid range found"); break; @@ -432,7 +484,8 @@ dasd_devmap_from_cdev(struct ccw_device *cdev) devmap = dasd_find_busid(cdev->dev.bus_id); if (IS_ERR(devmap)) - devmap = dasd_add_busid(cdev->dev.bus_id, DASD_FEATURE_DEFAULT); + devmap = dasd_add_busid(cdev->dev.bus_id, + DASD_FEATURE_DEFAULT); return devmap; } @@ -500,6 +553,8 @@ dasd_delete_device(struct dasd_device *device) /* First remove device pointer from devmap. */ devmap = dasd_find_busid(device->cdev->dev.bus_id); + if (IS_ERR(devmap)) + BUG(); spin_lock(&dasd_devmap_lock); if (devmap->device != device) { spin_unlock(&dasd_devmap_lock); @@ -573,8 +628,8 @@ dasd_ro_show(struct device *dev, char *buf) struct dasd_devmap *devmap; int ro_flag; - devmap = dev->driver_data; - if (devmap) + devmap = dasd_find_busid(dev->bus_id); + if (!IS_ERR(devmap)) ro_flag = (devmap->features & DASD_FEATURE_READONLY) != 0; else ro_flag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_READONLY) != 0; @@ -588,6 +643,8 @@ dasd_ro_store(struct device *dev, const char *buf, size_t count) int ro_flag; devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); + if (IS_ERR(devmap)) + return PTR_ERR(devmap); ro_flag = buf[0] == '1'; spin_lock(&dasd_devmap_lock); if (ro_flag) @@ -612,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 * to talk to the device */ -/* TODO: Implement */ static ssize_t dasd_use_diag_show(struct device *dev, char *buf) { struct dasd_devmap *devmap; int use_diag; - devmap = dev->driver_data; - if (devmap) + devmap = dasd_find_busid(dev->bus_id); + if (!IS_ERR(devmap)) use_diag = (devmap->features & DASD_FEATURE_USEDIAG) != 0; else use_diag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USEDIAG) != 0; @@ -631,21 +687,25 @@ static ssize_t dasd_use_diag_store(struct device *dev, const char *buf, size_t count) { struct dasd_devmap *devmap; + ssize_t rc; int use_diag; devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); + if (IS_ERR(devmap)) + return PTR_ERR(devmap); use_diag = buf[0] == '1'; spin_lock(&dasd_devmap_lock); /* Changing diag discipline flag is only allowed in offline state. */ + rc = count; if (!devmap->device) { if (use_diag) devmap->features |= DASD_FEATURE_USEDIAG; else devmap->features &= ~DASD_FEATURE_USEDIAG; } else - count = -EPERM; + rc = -EPERM; spin_unlock(&dasd_devmap_lock); - return count; + return rc; } static