diff options
| author | Horst Hummel <horst.hummel@de.ibm.com> | 2006-06-29 09:08:18 -0400 |
|---|---|---|
| committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2006-06-29 09:08:18 -0400 |
| commit | 405455734e1cdec09c37233216f9240cb1a058e5 (patch) | |
| tree | 36e88909f646b635117041b19a851031fc8ffb41 | |
| parent | 8f27766a883149926e7c1f69d9f1d8f68efcd65f (diff) | |
[S390] add PAV support to the dasd driver.
Add support for parallel-access-volumes to the dasd driver. This
allows concurrent access to dasd devices with multiple channel
programs.
Signed-off-by: Horst Hummel <horst.hummel@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
| -rw-r--r-- | drivers/s390/block/dasd.c | 51 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_devmap.c | 80 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_eckd.c | 140 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_eckd.h | 16 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_fba.c | 20 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_int.h | 2 | ||||
| -rw-r--r-- | include/asm-s390/dasd.h | 8 |
7 files changed, 227 insertions, 90 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 7e9978ad1445..bafcd2f20ae2 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
| @@ -1855,15 +1855,34 @@ dasd_generic_probe (struct ccw_device *cdev, | |||
| 1855 | { | 1855 | { |
| 1856 | int ret; | 1856 | int ret; |
| 1857 | 1857 | ||
| 1858 | ret = ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP); | ||
| 1859 | if (ret) { | ||
| 1860 | printk(KERN_WARNING | ||
| 1861 | "dasd_generic_probe: could not set ccw-device options " | ||
| 1862 | "for %s\n", cdev->dev.bus_id); | ||
| 1863 | return ret; | ||
| 1864 | } | ||
| 1858 | ret = dasd_add_sysfs_files(cdev); | 1865 | ret = dasd_add_sysfs_files(cdev); |
| 1859 | if (ret) { | 1866 | if (ret) { |
| 1860 | printk(KERN_WARNING | 1867 | printk(KERN_WARNING |
| 1861 | "dasd_generic_probe: could not add sysfs entries " | 1868 | "dasd_generic_probe: could not add sysfs entries " |
| 1862 | "for %s\n", cdev->dev.bus_id); | 1869 | "for %s\n", cdev->dev.bus_id); |
| 1863 | } else { | 1870 | return ret; |
| 1864 | cdev->handler = &dasd_int_handler; | ||
| 1865 | } | 1871 | } |
| 1872 | cdev->handler = &dasd_int_handler; | ||
| 1866 | 1873 | ||
| 1874 | /* | ||
| 1875 | * Automatically online either all dasd devices (dasd_autodetect) | ||
| 1876 | * or all devices specified with dasd= parameters during | ||
| 1877 | * initial probe. | ||
| 1878 | */ | ||
| 1879 | if ((dasd_get_feature(cdev, DASD_FEATURE_INITIAL_ONLINE) > 0 ) || | ||
| 1880 | (dasd_autodetect && dasd_busid_known(cdev->dev.bus_id) != 0)) | ||
| 1881 | ret = ccw_device_set_online(cdev); | ||
| 1882 | if (ret) | ||
| 1883 | printk(KERN_WARNING | ||
| 1884 | "dasd_generic_probe: could not initially online " | ||
| 1885 | "ccw-device %s\n", cdev->dev.bus_id); | ||
| 1867 | return ret; | 1886 | return ret; |
| 1868 | } | 1887 | } |
| 1869 | 1888 | ||
| @@ -1911,6 +1930,8 @@ dasd_generic_set_online (struct ccw_device *cdev, | |||
| 1911 | struct dasd_device *device; | 1930 | struct dasd_device *device; |
| 1912 | int rc; | 1931 | int rc; |
| 1913 | 1932 | ||
| 1933 | /* first online clears initial online feature flag */ | ||
| 1934 | dasd_set_feature(cdev, DASD_FEATURE_INITIAL_ONLINE, 0); | ||
| 1914 | device = dasd_create_device(cdev); | 1935 | device = dasd_create_device(cdev); |
| 1915 | if (IS_ERR(device)) | 1936 | if (IS_ERR(device)) |
| 1916 | return PTR_ERR(device); | 1937 | return PTR_ERR(device); |
| @@ -2065,31 +2086,6 @@ dasd_generic_notify(struct ccw_device *cdev, int event) | |||
| 2065 | return ret; | 2086 | return ret; |
| 2066 | } | 2087 | } |
| 2067 | 2088 | ||
| 2068 | /* | ||
| 2069 | * Automatically online either all dasd devices (dasd_autodetect) or | ||
| 2070 | * all devices specified with dasd= parameters. | ||
| 2071 | */ | ||
| 2072 | static int | ||
| 2073 | __dasd_auto_online(struct device *dev, void *data) | ||
| 2074 | { | ||
| 2075 | struct ccw_device *cdev; | ||
| 2076 | |||
| 2077 | cdev = to_ccwdev(dev); | ||
| 2078 | if (dasd_autodetect || dasd_busid_known(cdev->dev.bus_id) == 0) | ||
| 2079 | ccw_device_set_online(cdev); | ||
| 2080 | return 0; | ||
| 2081 | } | ||
| 2082 | |||
| 2083 | void | ||
| 2084 | dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver) | ||
| 2085 | { | ||
| 2086 | struct device_driver *drv; | ||
| 2087 | |||
| 2088 | drv = get_driver(&dasd_discipline_driver->driver); | ||
| 2089 | driver_for_each_device(drv, NULL, NULL, __dasd_auto_online); | ||
| 2090 | put_driver(drv); | ||
| 2091 | } | ||
| 2092 | |||
| 2093 | 2089 | ||
| 2094 | static int __init | 2090 | static int __init |
| 2095 | dasd_init(void) | 2091 | dasd_init(void) |
| @@ -2170,5 +2166,4 @@ EXPORT_SYMBOL_GPL(dasd_generic_remove); | |||
| 2170 | EXPORT_SYMBOL_GPL(dasd_generic_notify); | 2166 | EXPORT_SYMBOL_GPL(dasd_generic_notify); |
| 2171 | EXPORT_SYMBOL_GPL(dasd_generic_set_online); | 2167 | EXPORT_SYMBOL_GPL(dasd_generic_set_online); |
| 2172 | EXPORT_SYMBOL_GPL(dasd_generic_set_offline); | 2168 | EXPORT_SYMBOL_GPL(dasd_generic_set_offline); |
| 2173 | EXPORT_SYMBOL_GPL(dasd_generic_auto_online); | ||
| 2174 | 2169 | ||
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 672e50314b12..9e9ae7179602 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
| @@ -27,7 +27,7 @@ | |||
| 27 | #include "dasd_int.h" | 27 | #include "dasd_int.h" |
| 28 | 28 | ||
| 29 | kmem_cache_t *dasd_page_cache; | 29 | kmem_cache_t *dasd_page_cache; |
| 30 | EXPORT_SYMBOL(dasd_page_cache); | 30 | EXPORT_SYMBOL_GPL(dasd_page_cache); |
| 31 | 31 | ||
| 32 | /* | 32 | /* |
| 33 | * dasd_devmap_t is used to store the features and the relation | 33 | * dasd_devmap_t is used to store the features and the relation |
| @@ -49,6 +49,20 @@ struct dasd_devmap { | |||
| 49 | }; | 49 | }; |
| 50 | 50 | ||
| 51 | /* | 51 | /* |
| 52 | * dasd_servermap is used to store the server_id of all storage servers | ||
| 53 | * accessed by DASD device driver. | ||
| 54 | */ | ||
| 55 | struct dasd_servermap { | ||
| 56 | struct list_head list; | ||
| 57 | struct server_id { | ||
| 58 | char vendor[4]; | ||
| 59 | char serial[15]; | ||
| 60 | } sid; | ||
| 61 | }; | ||
| 62 | |||
| 63 | static struct list_head dasd_serverlist; | ||
| 64 | |||
| 65 | /* | ||
| 52 | * Parameter parsing functions for dasd= parameter. The syntax is: | 66 | * Parameter parsing functions for dasd= parameter. The syntax is: |
| 53 | * <devno> : (0x)?[0-9a-fA-F]+ | 67 | * <devno> : (0x)?[0-9a-fA-F]+ |
| 54 | * <busid> : [0-0a-f]\.[0-9a-f]\.(0x)?[0-9a-fA-F]+ | 68 | * <busid> : [0-0a-f]\.[0-9a-f]\.(0x)?[0-9a-fA-F]+ |
| @@ -64,6 +78,8 @@ struct dasd_devmap { | |||
| 64 | 78 | ||
| 65 | int dasd_probeonly = 0; /* is true, when probeonly mode is active */ | 79 | int dasd_probeonly = 0; /* is true, when probeonly mode is active */ |
| 66 | int dasd_autodetect = 0; /* is true, when autodetection is active */ | 80 | int dasd_autodetect = 0; /* is true, when autodetection is active */ |
| 81 | int dasd_nopav = 0; /* is true, when PAV is disabled */ | ||
| 82 | EXPORT_SYMBOL_GPL(dasd_nopav); | ||
| 67 | 83 | ||
| 68 | /* | 84 | /* |
| 69 | * char *dasd[] is intended to hold the ranges supplied by the dasd= statement | 85 | * char *dasd[] is intended to hold the ranges supplied by the dasd= statement |
| @@ -228,19 +244,24 @@ dasd_parse_keyword( char *parsestring ) { | |||
| 228 | length = strlen(parsestring); | 244 | length = strlen(parsestring); |
| 229 | residual_str = parsestring + length; | 245 | residual_str = parsestring + length; |
| 230 | } | 246 | } |
| 231 | if (strncmp ("autodetect", parsestring, length) == 0) { | 247 | if (strncmp("autodetect", parsestring, length) == 0) { |
| 232 | dasd_autodetect = 1; | 248 | dasd_autodetect = 1; |
| 233 | MESSAGE (KERN_INFO, "%s", | 249 | MESSAGE (KERN_INFO, "%s", |
| 234 | "turning to autodetection mode"); | 250 | "turning to autodetection mode"); |
| 235 | return residual_str; | 251 | return residual_str; |
| 236 | } | 252 | } |
| 237 | if (strncmp ("probeonly", parsestring, length) == 0) { | 253 | if (strncmp("probeonly", parsestring, length) == 0) { |
| 238 | dasd_probeonly = 1; | 254 | dasd_probeonly = 1; |
| 239 | MESSAGE(KERN_INFO, "%s", | 255 | MESSAGE(KERN_INFO, "%s", |
| 240 | "turning to probeonly mode"); | 256 | "turning to probeonly mode"); |
| 241 | return residual_str; | 257 | return residual_str; |
| 242 | } | 258 | } |
| 243 | if (strncmp ("fixedbuffers", parsestring, length) == 0) { | 259 | if (strncmp("nopav", parsestring, length) == 0) { |
| 260 | dasd_nopav = 1; | ||
| 261 | MESSAGE(KERN_INFO, "%s", "disable PAV mode"); | ||
| 262 | return residual_str; | ||
| 263 | } | ||
| 264 | if (strncmp("fixedbuffers", parsestring, length) == 0) { | ||
| 244 | if (dasd_page_cache) | 265 | if (dasd_page_cache) |
| 245 | return residual_str; | 266 | return residual_str; |
| 246 | dasd_page_cache = | 267 | dasd_page_cache = |
| @@ -294,6 +315,8 @@ dasd_parse_range( char *parsestring ) { | |||
| 294 | features = dasd_feature_list(str, &str); | 315 | features = dasd_feature_list(str, &str); |
| 295 | if (features < 0) | 316 | if (features < 0) |
| 296 | return ERR_PTR(-EINVAL); | 317 | return ERR_PTR(-EINVAL); |
| 318 | /* each device in dasd= parameter should be set initially online */ | ||
| 319 | features |= DASD_FEATURE_INITIAL_ONLINE; | ||
| 297 | while (from <= to) { | 320 | while (from <= to) { |
| 298 | sprintf(bus_id, "%01x.%01x.%04x", | 321 | sprintf(bus_id, "%01x.%01x.%04x", |
| 299 | from_id0, from_id1, from++); | 322 | from_id0, from_id1, from++); |
| @@ -836,6 +859,38 @@ static struct attribute_group dasd_attr_group = { | |||
| 836 | .attrs = dasd_attrs, | 859 | .attrs = dasd_attrs, |
| 837 | }; | 860 | }; |
| 838 | 861 | ||
| 862 | /* | ||
| 863 | * Check if the related storage server is already contained in the | ||
| 864 | * dasd_serverlist. If server is not contained, create new entry. | ||
| 865 | * Return 0 if server was already in serverlist, | ||
| 866 | * 1 if the server was added successfully | ||
| 867 | * <0 in case of error. | ||
| 868 | */ | ||
| 869 | static int | ||
| 870 | dasd_add_server(struct dasd_uid *uid) | ||
| 871 | { | ||
| 872 | struct dasd_servermap *new, *tmp; | ||
| 873 | |||
| 874 | /* check if server is already contained */ | ||
| 875 | list_for_each_entry(tmp, &dasd_serverlist, list) | ||
| 876 | // normale cmp? | ||
| 877 | if (strncmp(tmp->sid.vendor, uid->vendor, | ||
| 878 | sizeof(tmp->sid.vendor)) == 0 | ||
| 879 | && strncmp(tmp->sid.serial, uid->serial, | ||
| 880 | sizeof(tmp->sid.serial)) == 0) | ||
| 881 | return 0; | ||
| 882 | |||
| 883 | new = (struct dasd_servermap *) | ||
| 884 | kzalloc(sizeof(struct dasd_servermap), GFP_KERNEL); | ||
| 885 | if (!new) | ||
| 886 | return -ENOMEM; | ||
| 887 | |||
| 888 | strncpy(new->sid.vendor, uid->vendor, sizeof(new->sid.vendor)); | ||
| 889 | strncpy(new->sid.serial, uid->serial, sizeof(new->sid.serial)); | ||
| 890 | list_add(&new->list, &dasd_serverlist); | ||
| 891 | return 1; | ||
| 892 | } | ||
| 893 | |||
| 839 | 894 | ||
| 840 | /* | 895 | /* |
| 841 | * Return copy of the device unique identifier. | 896 | * Return copy of the device unique identifier. |
| @@ -856,21 +911,26 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid) | |||
| 856 | 911 | ||
| 857 | /* | 912 | /* |
| 858 | * Register the given device unique identifier into devmap struct. | 913 | * Register the given device unique identifier into devmap struct. |
| 914 | * Return 0 if server was already in serverlist, | ||
| 915 | * 1 if the server was added successful | ||
| 916 | * <0 in case of error. | ||
| 859 | */ | 917 | */ |
| 860 | int | 918 | int |
| 861 | dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid) | 919 | dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid) |
| 862 | { | 920 | { |
| 863 | struct dasd_devmap *devmap; | 921 | struct dasd_devmap *devmap; |
| 922 | int rc; | ||
| 864 | 923 | ||
| 865 | devmap = dasd_find_busid(cdev->dev.bus_id); | 924 | devmap = dasd_find_busid(cdev->dev.bus_id); |
| 866 | if (IS_ERR(devmap)) | 925 | if (IS_ERR(devmap)) |
| 867 | return PTR_ERR(devmap); | 926 | return PTR_ERR(devmap); |
| 868 | spin_lock(&dasd_devmap_lock); | 927 | spin_lock(&dasd_devmap_lock); |
| 869 | devmap->uid = *uid; | 928 | devmap->uid = *uid; |
| 929 | rc = dasd_add_server(uid); | ||
| 870 | spin_unlock(&dasd_devmap_lock); | 930 | spin_unlock(&dasd_devmap_lock); |
| 871 | return 0; | 931 | return rc; |
| 872 | } | 932 | } |
| 873 | EXPORT_SYMBOL(dasd_set_uid); | 933 | EXPORT_SYMBOL_GPL(dasd_set_uid); |
| 874 | 934 | ||
| 875 | /* | 935 | /* |
| 876 | * Return value of the specified feature. | 936 | * Return value of the specified feature. |
| @@ -882,7 +942,7 @@ dasd_get_feature(struct ccw_device *cdev, int feature) | |||
| 882 | 942 | ||
| 883 | devmap = dasd_find_busid(cdev->dev.bus_id); | 943 | devmap = dasd_find_busid(cdev->dev.bus_id); |
| 884 | if (IS_ERR(devmap)) | 944 | if (IS_ERR(devmap)) |
| 885 | return (int) PTR_ERR(devmap); | 945 | return PTR_ERR(devmap); |
| 886 | 946 | ||
| 887 | return ((devmap->features & feature) != 0); | 947 | return ((devmap->features & feature) != 0); |
| 888 | } | 948 | } |
| @@ -898,7 +958,7 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag) | |||
| 898 | 958 | ||
| 899 | devmap = dasd_find_busid(cdev->dev.bus_id); | 959 | devmap = dasd_find_busid(cdev->dev.bus_id); |
| 900 | if (IS_ERR(devmap)) | 960 | if (IS_ERR(devmap)) |
| 901 | return (int) PTR_ERR(devmap); | 961 | return PTR_ERR(devmap); |
| 902 | 962 | ||
| 903 | spin_lock(&dasd_devmap_lock); | 963 | spin_lock(&dasd_devmap_lock); |
| 904 | if (flag) | 964 | if (flag) |
| @@ -934,8 +994,10 @@ dasd_devmap_init(void) | |||
| 934 | dasd_max_devindex = 0; | 994 | dasd_max_devindex = 0; |
| 935 | for (i = 0; i < 256; i++) | 995 | for (i = 0; i < 256; i++) |
| 936 | INIT_LIST_HEAD(&dasd_hashlists[i]); | 996 | INIT_LIST_HEAD(&dasd_hashlists[i]); |
| 937 | return 0; | ||
| 938 | 997 | ||
| 998 | /* Initialize servermap structure. */ | ||
| 999 | INIT_LIST_HEAD(&dasd_serverlist); | ||
| 1000 | return 0; | ||
| 939 | } | 1001 | } |
| 940 | 1002 | ||
| 941 | void | 1003 | void |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 12257776e79b..0dfab30e8089 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <asm/io.h> | 24 | #include <asm/io.h> |
| 25 | #include <asm/todclk.h> | 25 | #include <asm/todclk.h> |
| 26 | #include <asm/uaccess.h> | 26 | #include <asm/uaccess.h> |
| 27 | #include <asm/cio.h> | ||
| 27 | #include <asm/ccwdev.h> | 28 | #include <asm/ccwdev.h> |
| 28 | 29 | ||
| 29 | #include "dasd_int.h" | 30 | #include "dasd_int.h" |
| @@ -89,17 +90,22 @@ dasd_eckd_probe (struct ccw_device *cdev) | |||
| 89 | { | 90 | { |
| 90 | int ret; | 91 | int ret; |
| 91 | 92 | ||
| 92 | ret = dasd_generic_probe (cdev, &dasd_eckd_discipline); | 93 | /* set ECKD specific ccw-device options */ |
| 93 | if (ret) | 94 | ret = ccw_device_set_options(cdev, CCWDEV_ALLOW_FORCE); |
| 95 | if (ret) { | ||
| 96 | printk(KERN_WARNING | ||
| 97 | "dasd_eckd_probe: could not set ccw-device options " | ||
| 98 | "for %s\n", cdev->dev.bus_id); | ||
| 94 | return ret; | 99 | return ret; |
| 95 | ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP | CCWDEV_ALLOW_FORCE); | 100 | } |
| 96 | return 0; | 101 | ret = dasd_generic_probe(cdev, &dasd_eckd_discipline); |
| 102 | return ret; | ||
| 97 | } | 103 | } |
| 98 | 104 | ||
| 99 | static int | 105 | static int |
| 100 | dasd_eckd_set_online(struct ccw_device *cdev) | 106 | dasd_eckd_set_online(struct ccw_device *cdev) |
| 101 | { | 107 | { |
| 102 | return dasd_generic_set_online (cdev, &dasd_eckd_discipline); | 108 | return dasd_generic_set_online(cdev, &dasd_eckd_discipline); |
| 103 | } | 109 | } |
| 104 | 110 | ||
| 105 | static struct ccw_driver dasd_eckd_driver = { | 111 | static struct ccw_driver dasd_eckd_driver = { |
| @@ -541,6 +547,86 @@ dasd_eckd_read_conf(struct dasd_device *device) | |||
| 541 | } | 547 | } |
| 542 | 548 | ||
| 543 | /* | 549 | /* |
| 550 | * Build CP for Perform Subsystem Function - SSC. | ||
| 551 | */ | ||
| 552 | struct dasd_ccw_req * | ||
| 553 | dasd_eckd_build_psf_ssc(struct dasd_device *device) | ||
| 554 | { | ||
| 555 | struct dasd_ccw_req *cqr; | ||
| 556 | struct dasd_psf_ssc_data *psf_ssc_data; | ||
| 557 | struct ccw1 *ccw; | ||
| 558 | |||
| 559 | cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ , | ||
| 560 | sizeof(struct dasd_psf_ssc_data), | ||
| 561 | device); | ||
| 562 | |||
| 563 | if (IS_ERR(cqr)) { | ||
| 564 | DEV_MESSAGE(KERN_WARNING, device, "%s", | ||
| 565 | "Could not allocate PSF-SSC request"); | ||
| 566 | return cqr; | ||
| 567 | } | ||
| 568 | psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data; | ||
| 569 | psf_ssc_data->order = PSF_ORDER_SSC; | ||
| 570 | psf_ssc_data->suborder = 0x08; | ||
| 571 | |||
| 572 | ccw = cqr->cpaddr; | ||
| 573 | ccw->cmd_code = DASD_ECKD_CCW_PSF; | ||
| 574 | ccw->cda = (__u32)(addr_t)psf_ssc_data; | ||
| 575 | ccw->count = 66; | ||
| 576 | |||
| 577 | cqr->device = device; | ||
| 578 | cqr->expires = 10*HZ; | ||
| 579 | cqr->buildclk = get_clock(); | ||
| 580 | cqr->status = DASD_CQR_FILLED; | ||
| 581 | return cqr; | ||
| 582 | } | ||
| 583 | |||
| 584 | /* | ||
| 585 | * Perform Subsystem Function. | ||
| 586 | * It is necessary to trigger CIO for channel revalidation since this | ||
| 587 | * call might change behaviour of DASD devices. | ||
| 588 | */ | ||
| 589 | static int | ||
| 590 | dasd_eckd_psf_ssc(struct dasd_device *device) | ||
| 591 | { | ||
| 592 | struct dasd_ccw_req *cqr; | ||
| 593 | int rc; | ||
| 594 | |||
| 595 | cqr = dasd_eckd_build_psf_ssc(device); | ||
| 596 | if (IS_ERR(cqr)) | ||
| 597 | return PTR_ERR(cqr); | ||
| 598 | |||
| 599 | rc = dasd_sleep_on(cqr); | ||
| 600 | if (!rc) | ||
| 601 | /* trigger CIO to reprobe devices */ | ||
| 602 | css_schedule_reprobe(); | ||
| 603 | dasd_sfree_request(cqr, cqr->device); | ||
| 604 | return rc; | ||
| 605 | } | ||
| 606 | |||
| 607 | /* | ||
| 608 | * Valide storage server of current device. | ||
| 609 | */ | ||
| 610 | static int | ||
| 611 | dasd_eckd_validate_server(struct dasd_device *device) | ||
| 612 | { | ||
| 613 | int rc; | ||
| 614 | |||
| 615 | /* Currently PAV is the only reason to 'validate' server on LPAR */ | ||
| 616 | if (dasd_nopav || MACHINE_IS_VM) | ||
| 617 | return 0; | ||
| 618 | |||
| 619 | rc = dasd_eckd_psf_ssc(device); | ||
| 620 | if (rc) | ||
| 621 | /* may be requested feature is not available on server, | ||
| 622 | * therefore just report error and go ahead */ | ||
| 623 | DEV_MESSAGE(KERN_INFO, device, | ||
| 624 | "Perform Subsystem Function returned rc=%d", rc); | ||
| 625 | /* RE-Read Configuration Data */ | ||
| 626 | return dasd_eckd_read_conf(device); | ||
| 627 | } | ||
| 628 | |||
| 629 | /* | ||
| 544 | * Check device characteristics. | 630 | * Check device characteristics. |
| 545 | * If the device is accessible using ECKD discipline, the device is enabled. | 631 | * If the device is accessible using ECKD discipline, the device is enabled. |
| 546 | */ | 632 | */ |
| @@ -570,16 +656,29 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
| 570 | private->attrib.operation = DASD_NORMAL_CACHE; | 656 | private->attrib.operation = DASD_NORMAL_CACHE; |
| 571 | private->attrib.nr_cyl = 0; | 657 | private->attrib.nr_cyl = 0; |
| 572 | 658 | ||
| 659 | /* Read Configuration Data */ | ||
| 660 | rc = dasd_eckd_read_conf(device); | ||
| 661 | if (rc) | ||
| 662 | return rc; | ||
| 663 | |||
| 664 | /* Generate device unique id and register in devmap */ | ||
| 665 | rc = dasd_eckd_generate_uid(device, &uid); | ||
| 666 | if (rc) | ||
| 667 | return rc; | ||
| 668 | rc = dasd_set_uid(device->cdev, &uid); | ||
| 669 | if (rc == 1) /* new server found */ | ||
| 670 | rc = dasd_eckd_validate_server(device); | ||
| 671 | if (rc) | ||
| 672 | return rc; | ||
| 673 | |||
| 573 | /* Read Device Characteristics */ | 674 | /* Read Device Characteristics */ |
| 574 | rdc_data = (void *) &(private->rdc_data); | 675 | rdc_data = (void *) &(private->rdc_data); |
| 575 | memset(rdc_data, 0, sizeof(rdc_data)); | 676 | memset(rdc_data, 0, sizeof(rdc_data)); |
| 576 | rc = read_dev_chars(device->cdev, &rdc_data, 64); | 677 | rc = read_dev_chars(device->cdev, &rdc_data, 64); |
| 577 | if (rc) { | 678 | if (rc) |
| 578 | DEV_MESSAGE(KERN_WARNING, device, | 679 | DEV_MESSAGE(KERN_WARNING, device, |
| 579 | "Read device characteristics returned error %d", | 680 | "Read device characteristics returned " |
| 580 | rc); | 681 | "rc=%d", rc); |
| 581 | return rc; | ||
| 582 | } | ||
| 583 | 682 | ||
| 584 | DEV_MESSAGE(KERN_INFO, device, | 683 | DEV_MESSAGE(KERN_INFO, device, |
| 585 | "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d", | 684 | "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d", |
| @@ -590,19 +689,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
| 590 | private->rdc_data.no_cyl, | 689 | private->rdc_data.no_cyl, |
| 591 | private->rdc_data.trk_per_cyl, | 690 | private->rdc_data.trk_per_cyl, |
| 592 | private->rdc_data.sec_per_trk); | 691 | private->rdc_data.sec_per_trk); |
| 593 | |||
| 594 | /* Read Configuration Data */ | ||
| 595 | rc = dasd_eckd_read_conf (device); | ||
| 596 | if (rc) | ||
| 597 | return rc; | ||
| 598 | |||
| 599 | /* Generate device unique id and register in devmap */ | ||
| 600 | rc = dasd_eckd_generate_uid(device, &uid); | ||
| 601 | if (rc) | ||
| 602 | return rc; | ||
| 603 | |||
| 604 | rc = dasd_set_uid(device->cdev, &uid); | ||
| 605 | |||
| 606 | return rc; | 692 | return rc; |
| 607 | } | 693 | } |
| 608 | 694 | ||
| @@ -1687,14 +1773,8 @@ static struct dasd_discipline dasd_eckd_discipline = { | |||
| 1687 | static int __init | 1773 | static int __init |
| 1688 | dasd_eckd_init(void) | 1774 | dasd_eckd_init(void) |
| 1689 | { | 1775 | { |
| 1690 | int ret; | ||
| 1691 | |||
| 1692 | ASCEBC(dasd_eckd_discipline.ebcname, 4); | 1776 | ASCEBC(dasd_eckd_discipline.ebcname, 4); |
| 1693 | 1777 | return ccw_driver_register(&dasd_eckd_driver); | |
| 1694 | ret = ccw_driver_register(&dasd_eckd_driver); | ||
| 1695 | if (!ret) | ||
| 1696 | dasd_generic_auto_online(&dasd_eckd_driver); | ||
| 1697 | return ret; | ||
| 1698 | } | 1778 | } |
| 1699 | 1779 | ||
| 1700 | static void __exit | 1780 | static void __exit |
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index 9d91c8632569..712ff1650134 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h | |||
| @@ -41,9 +41,10 @@ | |||
| 41 | #define DASD_ECKD_CCW_RESERVE 0xB4 | 41 | #define DASD_ECKD_CCW_RESERVE 0xB4 |
| 42 | 42 | ||
| 43 | /* | 43 | /* |
| 44 | *Perform Subsystem Function / Sub-Orders | 44 | * Perform Subsystem Function / Sub-Orders |
| 45 | */ | 45 | */ |
| 46 | #define PSF_ORDER_PRSSD 0x18 | 46 | #define PSF_ORDER_PRSSD 0x18 |
| 47 | #define PSF_ORDER_SSC 0x1D | ||
| 47 | 48 | ||
| 48 | /***************************************************************************** | 49 | /***************************************************************************** |
| 49 | * SECTION: Type Definitions | 50 | * SECTION: Type Definitions |
| @@ -353,4 +354,15 @@ struct dasd_psf_prssd_data { | |||
| 353 | unsigned char varies[9]; | 354 | unsigned char varies[9]; |
| 354 | } __attribute__ ((packed)); | 355 | } __attribute__ ((packed)); |
| 355 | 356 | ||
| 357 | /* | ||
| 358 | * Perform Subsystem Function - Set Subsystem Characteristics | ||
| 359 | */ | ||
| 360 | struct dasd_psf_ssc_data { | ||
| 361 | unsigned char order; | ||
| 362 | unsigned char flags; | ||
| 363 | unsigned char cu_type[4]; | ||
| 364 | unsigned char suborder; | ||
| 365 | unsigned char reserved[59]; | ||
| 366 | } __attribute__((packed)); | ||
| 367 | |||
| 356 | #endif /* DASD_ECKD_H */ | 368 | #endif /* DASD_ECKD_H */ |
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index d331c6e22c59..bb7755b9b19d 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c | |||
| @@ -56,19 +56,13 @@ static struct ccw_driver dasd_fba_driver; /* see below */ | |||
| 56 | static int | 56 | static int |
| 57 | dasd_fba_probe(struct ccw_device *cdev) | 57 | dasd_fba_probe(struct ccw_device *cdev) |
| 58 | { | 58 | { |
| 59 | int ret; | 59 | return dasd_generic_probe(cdev, &dasd_fba_discipline); |
| 60 | |||
| 61 | ret = dasd_generic_probe (cdev, &dasd_fba_discipline); | ||
| 62 | if (ret) | ||
| 63 | return ret; | ||
| 64 | ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP); | ||
| 65 | return 0; | ||
| 66 | } | 60 | } |
| 67 | 61 | ||
| 68 | static int | 62 | static int |
| 69 | dasd_fba_set_online(struct ccw_device *cdev) | 63 | dasd_fba_set_online(struct ccw_device *cdev) |
| 70 | { | 64 | { |
| 71 | return dasd_generic_set_online (cdev, &dasd_fba_discipline); | 65 | return dasd_generic_set_online(cdev, &dasd_fba_discipline); |
| 72 | } | 66 | } |
| 73 | 67 | ||
| 74 | static struct ccw_driver dasd_fba_driver = { | 68 | static struct ccw_driver dasd_fba_driver = { |
| @@ -569,16 +563,8 @@ static struct dasd_discipline dasd_fba_discipline = { | |||
| 569 | static int __init | 563 | static int __init |
| 570 | dasd_fba_init(void) | 564 | dasd_fba_init(void) |
| 571 | { | 565 | { |
| 572 | int ret; | ||
| 573 | |||
| 574 | ASCEBC(dasd_fba_discipline.ebcname, 4); | 566 | ASCEBC(dasd_fba_discipline.ebcname, 4); |
| 575 | 567 | return ccw_driver_register(&dasd_fba_driver); | |
| 576 | ret = ccw_driver_register(&dasd_fba_driver); | ||
| 577 | if (ret) | ||
| 578 | return ret; | ||
| 579 | |||
| 580 | dasd_generic_auto_online(&dasd_fba_driver); | ||
| 581 | return 0; | ||
| 582 | } | 568 | } |
| 583 | 569 | ||
| 584 | static void __exit | 570 | static void __exit |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 2c1fa85a3dad..03a83efc34c4 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
| @@ -513,12 +513,12 @@ void dasd_generic_remove (struct ccw_device *cdev); | |||
| 513 | int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *); | 513 | int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *); |
| 514 | int dasd_generic_set_offline (struct ccw_device *cdev); | 514 | int dasd_generic_set_offline (struct ccw_device *cdev); |
| 515 | int dasd_generic_notify(struct ccw_device *, int); | 515 | int dasd_generic_notify(struct ccw_device *, int); |
| 516 | void dasd_generic_auto_online (struct ccw_driver *); | ||
| 517 | 516 | ||
| 518 | /* externals in dasd_devmap.c */ | 517 | /* externals in dasd_devmap.c */ |
| 519 | extern int dasd_max_devindex; | 518 | extern int dasd_max_devindex; |
| 520 | extern int dasd_probeonly; | 519 | extern int dasd_probeonly; |
| 521 | extern int dasd_autodetect; | 520 | extern int dasd_autodetect; |
| 521 | extern int dasd_nopav; | ||
| 522 | 522 | ||
| 523 | int dasd_devmap_init(void); | 523 | int dasd_devmap_init(void); |
| 524 | void dasd_devmap_exit(void); | 524 | void dasd_devmap_exit(void); |
diff --git a/include/asm-s390/dasd.h b/include/asm-s390/dasd.h index 1630c26e8f45..c042f9578081 100644 --- a/include/asm-s390/dasd.h +++ b/include/asm-s390/dasd.h | |||
| @@ -68,10 +68,12 @@ typedef struct dasd_information2_t { | |||
| 68 | * 0x00: default features | 68 | * 0x00: default features |
| 69 | * 0x01: readonly (ro) | 69 | * 0x01: readonly (ro) |
| 70 | * 0x02: use diag discipline (diag) | 70 | * 0x02: use diag discipline (diag) |
| 71 | * 0x04: set the device initially online (internal use only) | ||
| 71 | */ | 72 | */ |
| 72 | #define DASD_FEATURE_DEFAULT 0 | 73 | #define DASD_FEATURE_DEFAULT 0x00 |
| 73 | #define DASD_FEATURE_READONLY 1 | 74 | #define DASD_FEATURE_READONLY 0x01 |
| 74 | #define DASD_FEATURE_USEDIAG 2 | 75 | #define DASD_FEATURE_USEDIAG 0x02 |
| 76 | #define DASD_FEATURE_INITIAL_ONLINE 0x04 | ||
| 75 | 77 | ||
| 76 | #define DASD_PARTN_BITS 2 | 78 | #define DASD_PARTN_BITS 2 |
| 77 | 79 | ||
