diff options
Diffstat (limited to 'drivers/s390/block')
-rw-r--r-- | drivers/s390/block/dasd.c | 32 | ||||
-rw-r--r-- | drivers/s390/block/dasd_3990_erp.c | 2 | ||||
-rw-r--r-- | drivers/s390/block/dasd_devmap.c | 28 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 132 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eer.c | 6 | ||||
-rw-r--r-- | drivers/s390/block/dasd_fba.c | 4 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 4 | ||||
-rw-r--r-- | drivers/s390/block/dasd_proc.c | 2 | ||||
-rw-r--r-- | drivers/s390/block/dcssblk.c | 516 | ||||
-rw-r--r-- | drivers/s390/block/xpram.c | 37 |
10 files changed, 564 insertions, 199 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index acb78017e7d0..0a225ccda026 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -215,7 +215,7 @@ static int dasd_state_known_to_basic(struct dasd_device *device) | |||
215 | return rc; | 215 | return rc; |
216 | } | 216 | } |
217 | /* register 'device' debug area, used for all DBF_DEV_XXX calls */ | 217 | /* register 'device' debug area, used for all DBF_DEV_XXX calls */ |
218 | device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 1, | 218 | device->debug_area = debug_register(dev_name(&device->cdev->dev), 1, 1, |
219 | 8 * sizeof(long)); | 219 | 8 * sizeof(long)); |
220 | debug_register_view(device->debug_area, &debug_sprintf_view); | 220 | debug_register_view(device->debug_area, &debug_sprintf_view); |
221 | debug_set_level(device->debug_area, DBF_WARNING); | 221 | debug_set_level(device->debug_area, DBF_WARNING); |
@@ -933,7 +933,7 @@ static void dasd_handle_killed_request(struct ccw_device *cdev, | |||
933 | MESSAGE(KERN_DEBUG, | 933 | MESSAGE(KERN_DEBUG, |
934 | "invalid status in handle_killed_request: " | 934 | "invalid status in handle_killed_request: " |
935 | "bus_id %s, status %02x", | 935 | "bus_id %s, status %02x", |
936 | cdev->dev.bus_id, cqr->status); | 936 | dev_name(&cdev->dev), cqr->status); |
937 | return; | 937 | return; |
938 | } | 938 | } |
939 | 939 | ||
@@ -942,7 +942,7 @@ static void dasd_handle_killed_request(struct ccw_device *cdev, | |||
942 | device != dasd_device_from_cdev_locked(cdev) || | 942 | device != dasd_device_from_cdev_locked(cdev) || |
943 | strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { | 943 | strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { |
944 | MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s", | 944 | MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s", |
945 | cdev->dev.bus_id); | 945 | dev_name(&cdev->dev)); |
946 | return; | 946 | return; |
947 | } | 947 | } |
948 | 948 | ||
@@ -982,11 +982,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
982 | break; | 982 | break; |
983 | case -ETIMEDOUT: | 983 | case -ETIMEDOUT: |
984 | printk(KERN_WARNING"%s(%s): request timed out\n", | 984 | printk(KERN_WARNING"%s(%s): request timed out\n", |
985 | __func__, cdev->dev.bus_id); | 985 | __func__, dev_name(&cdev->dev)); |
986 | break; | 986 | break; |
987 | default: | 987 | default: |
988 | printk(KERN_WARNING"%s(%s): unknown error %ld\n", | 988 | printk(KERN_WARNING"%s(%s): unknown error %ld\n", |
989 | __func__, cdev->dev.bus_id, PTR_ERR(irb)); | 989 | __func__, dev_name(&cdev->dev), PTR_ERR(irb)); |
990 | } | 990 | } |
991 | dasd_handle_killed_request(cdev, intparm); | 991 | dasd_handle_killed_request(cdev, intparm); |
992 | return; | 992 | return; |
@@ -995,7 +995,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
995 | now = get_clock(); | 995 | now = get_clock(); |
996 | 996 | ||
997 | DBF_EVENT(DBF_ERR, "Interrupt: bus_id %s CS/DS %04x ip %08x", | 997 | DBF_EVENT(DBF_ERR, "Interrupt: bus_id %s CS/DS %04x ip %08x", |
998 | cdev->dev.bus_id, ((irb->scsw.cmd.cstat << 8) | | 998 | dev_name(&cdev->dev), ((irb->scsw.cmd.cstat << 8) | |
999 | irb->scsw.cmd.dstat), (unsigned int) intparm); | 999 | irb->scsw.cmd.dstat), (unsigned int) intparm); |
1000 | 1000 | ||
1001 | /* check for unsolicited interrupts */ | 1001 | /* check for unsolicited interrupts */ |
@@ -1019,7 +1019,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1019 | if (!device || | 1019 | if (!device || |
1020 | strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { | 1020 | strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { |
1021 | MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s", | 1021 | MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s", |
1022 | cdev->dev.bus_id); | 1022 | dev_name(&cdev->dev)); |
1023 | return; | 1023 | return; |
1024 | } | 1024 | } |
1025 | 1025 | ||
@@ -1037,7 +1037,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1037 | if (cqr->status != DASD_CQR_IN_IO) { | 1037 | if (cqr->status != DASD_CQR_IN_IO) { |
1038 | MESSAGE(KERN_DEBUG, | 1038 | MESSAGE(KERN_DEBUG, |
1039 | "invalid status: bus_id %s, status %02x", | 1039 | "invalid status: bus_id %s, status %02x", |
1040 | cdev->dev.bus_id, cqr->status); | 1040 | dev_name(&cdev->dev), cqr->status); |
1041 | return; | 1041 | return; |
1042 | } | 1042 | } |
1043 | DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p", | 1043 | DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p", |
@@ -2134,14 +2134,14 @@ int dasd_generic_probe(struct ccw_device *cdev, | |||
2134 | if (ret) { | 2134 | if (ret) { |
2135 | printk(KERN_WARNING | 2135 | printk(KERN_WARNING |
2136 | "dasd_generic_probe: could not set ccw-device options " | 2136 | "dasd_generic_probe: could not set ccw-device options " |
2137 | "for %s\n", cdev->dev.bus_id); | 2137 | "for %s\n", dev_name(&cdev->dev)); |
2138 | return ret; | 2138 | return ret; |
2139 | } | 2139 | } |
2140 | ret = dasd_add_sysfs_files(cdev); | 2140 | ret = dasd_add_sysfs_files(cdev); |
2141 | if (ret) { | 2141 | if (ret) { |
2142 | printk(KERN_WARNING | 2142 | printk(KERN_WARNING |
2143 | "dasd_generic_probe: could not add sysfs entries " | 2143 | "dasd_generic_probe: could not add sysfs entries " |
2144 | "for %s\n", cdev->dev.bus_id); | 2144 | "for %s\n", dev_name(&cdev->dev)); |
2145 | return ret; | 2145 | return ret; |
2146 | } | 2146 | } |
2147 | cdev->handler = &dasd_int_handler; | 2147 | cdev->handler = &dasd_int_handler; |
@@ -2152,13 +2152,13 @@ int dasd_generic_probe(struct ccw_device *cdev, | |||
2152 | * initial probe. | 2152 | * initial probe. |
2153 | */ | 2153 | */ |
2154 | if ((dasd_get_feature(cdev, DASD_FEATURE_INITIAL_ONLINE) > 0 ) || | 2154 | if ((dasd_get_feature(cdev, DASD_FEATURE_INITIAL_ONLINE) > 0 ) || |
2155 | (dasd_autodetect && dasd_busid_known(cdev->dev.bus_id) != 0)) | 2155 | (dasd_autodetect && dasd_busid_known(dev_name(&cdev->dev)) != 0)) |
2156 | ret = ccw_device_set_online(cdev); | 2156 | ret = ccw_device_set_online(cdev); |
2157 | if (ret) | 2157 | if (ret) |
2158 | printk(KERN_WARNING | 2158 | printk(KERN_WARNING |
2159 | "dasd_generic_probe: could not initially " | 2159 | "dasd_generic_probe: could not initially " |
2160 | "online ccw-device %s; return code: %d\n", | 2160 | "online ccw-device %s; return code: %d\n", |
2161 | cdev->dev.bus_id, ret); | 2161 | dev_name(&cdev->dev), ret); |
2162 | return 0; | 2162 | return 0; |
2163 | } | 2163 | } |
2164 | 2164 | ||
@@ -2224,7 +2224,7 @@ int dasd_generic_set_online(struct ccw_device *cdev, | |||
2224 | printk (KERN_WARNING | 2224 | printk (KERN_WARNING |
2225 | "dasd_generic couldn't online device %s " | 2225 | "dasd_generic couldn't online device %s " |
2226 | "- discipline DIAG not available\n", | 2226 | "- discipline DIAG not available\n", |
2227 | cdev->dev.bus_id); | 2227 | dev_name(&cdev->dev)); |
2228 | dasd_delete_device(device); | 2228 | dasd_delete_device(device); |
2229 | return -ENODEV; | 2229 | return -ENODEV; |
2230 | } | 2230 | } |
@@ -2248,7 +2248,7 @@ int dasd_generic_set_online(struct ccw_device *cdev, | |||
2248 | printk (KERN_WARNING | 2248 | printk (KERN_WARNING |
2249 | "dasd_generic couldn't online device %s " | 2249 | "dasd_generic couldn't online device %s " |
2250 | "with discipline %s rc=%i\n", | 2250 | "with discipline %s rc=%i\n", |
2251 | cdev->dev.bus_id, discipline->name, rc); | 2251 | dev_name(&cdev->dev), discipline->name, rc); |
2252 | module_put(discipline->owner); | 2252 | module_put(discipline->owner); |
2253 | module_put(base_discipline->owner); | 2253 | module_put(base_discipline->owner); |
2254 | dasd_delete_device(device); | 2254 | dasd_delete_device(device); |
@@ -2259,7 +2259,7 @@ int dasd_generic_set_online(struct ccw_device *cdev, | |||
2259 | if (device->state <= DASD_STATE_KNOWN) { | 2259 | if (device->state <= DASD_STATE_KNOWN) { |
2260 | printk (KERN_WARNING | 2260 | printk (KERN_WARNING |
2261 | "dasd_generic discipline not found for %s\n", | 2261 | "dasd_generic discipline not found for %s\n", |
2262 | cdev->dev.bus_id); | 2262 | dev_name(&cdev->dev)); |
2263 | rc = -ENODEV; | 2263 | rc = -ENODEV; |
2264 | dasd_set_target_state(device, DASD_STATE_NEW); | 2264 | dasd_set_target_state(device, DASD_STATE_NEW); |
2265 | if (device->block) | 2265 | if (device->block) |
@@ -2267,7 +2267,7 @@ int dasd_generic_set_online(struct ccw_device *cdev, | |||
2267 | dasd_delete_device(device); | 2267 | dasd_delete_device(device); |
2268 | } else | 2268 | } else |
2269 | pr_debug("dasd_generic device %s found\n", | 2269 | pr_debug("dasd_generic device %s found\n", |
2270 | cdev->dev.bus_id); | 2270 | dev_name(&cdev->dev)); |
2271 | 2271 | ||
2272 | /* FIXME: we have to wait for the root device but we don't want | 2272 | /* FIXME: we have to wait for the root device but we don't want |
2273 | * to wait for each single device but for all at once. */ | 2273 | * to wait for each single device but for all at once. */ |
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 5c6e6f331cb0..b8f9c00633f3 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c | |||
@@ -1397,7 +1397,7 @@ static struct dasd_ccw_req *dasd_3990_erp_inspect_alias( | |||
1397 | DEV_MESSAGE(KERN_ERR, cqr->startdev, | 1397 | DEV_MESSAGE(KERN_ERR, cqr->startdev, |
1398 | "ERP on alias device for request %p," | 1398 | "ERP on alias device for request %p," |
1399 | " recover on base device %s", cqr, | 1399 | " recover on base device %s", cqr, |
1400 | cqr->block->base->cdev->dev.bus_id); | 1400 | dev_name(&cqr->block->base->cdev->dev)); |
1401 | } | 1401 | } |
1402 | dasd_eckd_reset_ccw_to_base_io(cqr); | 1402 | dasd_eckd_reset_ccw_to_base_io(cqr); |
1403 | erp->startdev = cqr->block->base; | 1403 | erp->startdev = cqr->block->base; |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index cd3335c1c307..921443b01d16 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
@@ -515,9 +515,9 @@ dasd_devmap_from_cdev(struct ccw_device *cdev) | |||
515 | { | 515 | { |
516 | struct dasd_devmap *devmap; | 516 | struct dasd_devmap *devmap; |
517 | 517 | ||
518 | devmap = dasd_find_busid(cdev->dev.bus_id); | 518 | devmap = dasd_find_busid(dev_name(&cdev->dev)); |
519 | if (IS_ERR(devmap)) | 519 | if (IS_ERR(devmap)) |
520 | devmap = dasd_add_busid(cdev->dev.bus_id, | 520 | devmap = dasd_add_busid(dev_name(&cdev->dev), |
521 | DASD_FEATURE_DEFAULT); | 521 | DASD_FEATURE_DEFAULT); |
522 | return devmap; | 522 | return devmap; |
523 | } | 523 | } |
@@ -584,7 +584,7 @@ dasd_delete_device(struct dasd_device *device) | |||
584 | unsigned long flags; | 584 | unsigned long flags; |
585 | 585 | ||
586 | /* First remove device pointer from devmap. */ | 586 | /* First remove device pointer from devmap. */ |
587 | devmap = dasd_find_busid(device->cdev->dev.bus_id); | 587 | devmap = dasd_find_busid(dev_name(&device->cdev->dev)); |
588 | BUG_ON(IS_ERR(devmap)); | 588 | BUG_ON(IS_ERR(devmap)); |
589 | spin_lock(&dasd_devmap_lock); | 589 | spin_lock(&dasd_devmap_lock); |
590 | if (devmap->device != device) { | 590 | if (devmap->device != device) { |
@@ -674,7 +674,7 @@ dasd_ro_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
674 | struct dasd_devmap *devmap; | 674 | struct dasd_devmap *devmap; |
675 | int ro_flag; | 675 | int ro_flag; |
676 | 676 | ||
677 | devmap = dasd_find_busid(dev->bus_id); | 677 | devmap = dasd_find_busid(dev_name(dev)); |
678 | if (!IS_ERR(devmap)) | 678 | if (!IS_ERR(devmap)) |
679 | ro_flag = (devmap->features & DASD_FEATURE_READONLY) != 0; | 679 | ro_flag = (devmap->features & DASD_FEATURE_READONLY) != 0; |
680 | else | 680 | else |
@@ -723,7 +723,7 @@ dasd_erplog_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
723 | struct dasd_devmap *devmap; | 723 | struct dasd_devmap *devmap; |
724 | int erplog; | 724 | int erplog; |
725 | 725 | ||
726 | devmap = dasd_find_busid(dev->bus_id); | 726 | devmap = dasd_find_busid(dev_name(dev)); |
727 | if (!IS_ERR(devmap)) | 727 | if (!IS_ERR(devmap)) |
728 | erplog = (devmap->features & DASD_FEATURE_ERPLOG) != 0; | 728 | erplog = (devmap->features & DASD_FEATURE_ERPLOG) != 0; |
729 | else | 729 | else |
@@ -770,7 +770,7 @@ dasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
770 | struct dasd_devmap *devmap; | 770 | struct dasd_devmap *devmap; |
771 | int use_diag; | 771 | int use_diag; |
772 | 772 | ||
773 | devmap = dasd_find_busid(dev->bus_id); | 773 | devmap = dasd_find_busid(dev_name(dev)); |
774 | if (!IS_ERR(devmap)) | 774 | if (!IS_ERR(devmap)) |
775 | use_diag = (devmap->features & DASD_FEATURE_USEDIAG) != 0; | 775 | use_diag = (devmap->features & DASD_FEATURE_USEDIAG) != 0; |
776 | else | 776 | else |
@@ -876,7 +876,7 @@ dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
876 | struct dasd_devmap *devmap; | 876 | struct dasd_devmap *devmap; |
877 | int alias; | 877 | int alias; |
878 | 878 | ||
879 | devmap = dasd_find_busid(dev->bus_id); | 879 | devmap = dasd_find_busid(dev_name(dev)); |
880 | spin_lock(&dasd_devmap_lock); | 880 | spin_lock(&dasd_devmap_lock); |
881 | if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) { | 881 | if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) { |
882 | spin_unlock(&dasd_devmap_lock); | 882 | spin_unlock(&dasd_devmap_lock); |
@@ -899,7 +899,7 @@ dasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
899 | struct dasd_devmap *devmap; | 899 | struct dasd_devmap *devmap; |
900 | char *vendor; | 900 | char *vendor; |
901 | 901 | ||
902 | devmap = dasd_find_busid(dev->bus_id); | 902 | devmap = dasd_find_busid(dev_name(dev)); |
903 | spin_lock(&dasd_devmap_lock); | 903 | spin_lock(&dasd_devmap_lock); |
904 | if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0) | 904 | if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0) |
905 | vendor = devmap->uid.vendor; | 905 | vendor = devmap->uid.vendor; |
@@ -924,7 +924,7 @@ dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
924 | char ua_string[3]; | 924 | char ua_string[3]; |
925 | struct dasd_uid *uid; | 925 | struct dasd_uid *uid; |
926 | 926 | ||
927 | devmap = dasd_find_busid(dev->bus_id); | 927 | devmap = dasd_find_busid(dev_name(dev)); |
928 | spin_lock(&dasd_devmap_lock); | 928 | spin_lock(&dasd_devmap_lock); |
929 | if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) { | 929 | if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) { |
930 | spin_unlock(&dasd_devmap_lock); | 930 | spin_unlock(&dasd_devmap_lock); |
@@ -972,7 +972,7 @@ dasd_eer_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
972 | struct dasd_devmap *devmap; | 972 | struct dasd_devmap *devmap; |
973 | int eer_flag; | 973 | int eer_flag; |
974 | 974 | ||
975 | devmap = dasd_find_busid(dev->bus_id); | 975 | devmap = dasd_find_busid(dev_name(dev)); |
976 | if (!IS_ERR(devmap) && devmap->device) | 976 | if (!IS_ERR(devmap) && devmap->device) |
977 | eer_flag = dasd_eer_enabled(devmap->device); | 977 | eer_flag = dasd_eer_enabled(devmap->device); |
978 | else | 978 | else |
@@ -1034,7 +1034,7 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid) | |||
1034 | { | 1034 | { |
1035 | struct dasd_devmap *devmap; | 1035 | struct dasd_devmap *devmap; |
1036 | 1036 | ||
1037 | devmap = dasd_find_busid(cdev->dev.bus_id); | 1037 | devmap = dasd_find_busid(dev_name(&cdev->dev)); |
1038 | if (IS_ERR(devmap)) | 1038 | if (IS_ERR(devmap)) |
1039 | return PTR_ERR(devmap); | 1039 | return PTR_ERR(devmap); |
1040 | spin_lock(&dasd_devmap_lock); | 1040 | spin_lock(&dasd_devmap_lock); |
@@ -1057,7 +1057,7 @@ dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid) | |||
1057 | { | 1057 | { |
1058 | struct dasd_devmap *devmap; | 1058 | struct dasd_devmap *devmap; |
1059 | 1059 | ||
1060 | devmap = dasd_find_busid(cdev->dev.bus_id); | 1060 | devmap = dasd_find_busid(dev_name(&cdev->dev)); |
1061 | if (IS_ERR(devmap)) | 1061 | if (IS_ERR(devmap)) |
1062 | return PTR_ERR(devmap); | 1062 | return PTR_ERR(devmap); |
1063 | 1063 | ||
@@ -1077,7 +1077,7 @@ dasd_get_feature(struct ccw_device *cdev, int feature) | |||
1077 | { | 1077 | { |
1078 | struct dasd_devmap *devmap; | 1078 | struct dasd_devmap *devmap; |
1079 | 1079 | ||
1080 | devmap = dasd_find_busid(cdev->dev.bus_id); | 1080 | devmap = dasd_find_busid(dev_name(&cdev->dev)); |
1081 | if (IS_ERR(devmap)) | 1081 | if (IS_ERR(devmap)) |
1082 | return PTR_ERR(devmap); | 1082 | return PTR_ERR(devmap); |
1083 | 1083 | ||
@@ -1093,7 +1093,7 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag) | |||
1093 | { | 1093 | { |
1094 | struct dasd_devmap *devmap; | 1094 | struct dasd_devmap *devmap; |
1095 | 1095 | ||
1096 | devmap = dasd_find_busid(cdev->dev.bus_id); | 1096 | devmap = dasd_find_busid(dev_name(&cdev->dev)); |
1097 | if (IS_ERR(devmap)) | 1097 | if (IS_ERR(devmap)) |
1098 | return PTR_ERR(devmap); | 1098 | return PTR_ERR(devmap); |
1099 | 1099 | ||
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 773b3fe275b2..49f9d221e23d 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -6,6 +6,8 @@ | |||
6 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 6 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
7 | * Bugreports.to..: <Linux390@de.ibm.com> | 7 | * Bugreports.to..: <Linux390@de.ibm.com> |
8 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 | 8 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 |
9 | * EMC Symmetrix ioctl Copyright EMC Corporation, 2008 | ||
10 | * Author.........: Nigel Hislop <hislop_nigel@emc.com> | ||
9 | * | 11 | * |
10 | */ | 12 | */ |
11 | 13 | ||
@@ -84,7 +86,7 @@ dasd_eckd_probe (struct ccw_device *cdev) | |||
84 | if (ret) { | 86 | if (ret) { |
85 | printk(KERN_WARNING | 87 | printk(KERN_WARNING |
86 | "dasd_eckd_probe: could not set ccw-device options " | 88 | "dasd_eckd_probe: could not set ccw-device options " |
87 | "for %s\n", cdev->dev.bus_id); | 89 | "for %s\n", dev_name(&cdev->dev)); |
88 | return ret; | 90 | return ret; |
89 | } | 91 | } |
90 | ret = dasd_generic_probe(cdev, &dasd_eckd_discipline); | 92 | ret = dasd_generic_probe(cdev, &dasd_eckd_discipline); |
@@ -1501,12 +1503,27 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, | |||
1501 | return; | 1503 | return; |
1502 | } | 1504 | } |
1503 | 1505 | ||
1504 | /* just report other unsolicited interrupts */ | 1506 | if ((irb->scsw.cmd.cc == 1) && |
1505 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | 1507 | (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) && |
1506 | "unsolicited interrupt received"); | 1508 | (irb->scsw.cmd.actl & SCSW_ACTL_START_PEND) && |
1507 | device->discipline->dump_sense(device, NULL, irb); | 1509 | (irb->scsw.cmd.stctl & SCSW_STCTL_STATUS_PEND)) { |
1508 | dasd_schedule_device_bh(device); | 1510 | /* fake irb do nothing, they are handled elsewhere */ |
1511 | dasd_schedule_device_bh(device); | ||
1512 | return; | ||
1513 | } | ||
1514 | |||
1515 | if (!(irb->esw.esw0.erw.cons)) { | ||
1516 | /* just report other unsolicited interrupts */ | ||
1517 | DEV_MESSAGE(KERN_ERR, device, "%s", | ||
1518 | "unsolicited interrupt received"); | ||
1519 | } else { | ||
1520 | DEV_MESSAGE(KERN_ERR, device, "%s", | ||
1521 | "unsolicited interrupt received " | ||
1522 | "(sense available)"); | ||
1523 | device->discipline->dump_sense(device, NULL, irb); | ||
1524 | } | ||
1509 | 1525 | ||
1526 | dasd_schedule_device_bh(device); | ||
1510 | return; | 1527 | return; |
1511 | }; | 1528 | }; |
1512 | 1529 | ||
@@ -2068,6 +2085,103 @@ dasd_eckd_set_attrib(struct dasd_device *device, void __user *argp) | |||
2068 | return 0; | 2085 | return 0; |
2069 | } | 2086 | } |
2070 | 2087 | ||
2088 | /* | ||
2089 | * Issue syscall I/O to EMC Symmetrix array. | ||
2090 | * CCWs are PSF and RSSD | ||
2091 | */ | ||
2092 | static int dasd_symm_io(struct dasd_device *device, void __user *argp) | ||
2093 | { | ||
2094 | struct dasd_symmio_parms usrparm; | ||
2095 | char *psf_data, *rssd_result; | ||
2096 | struct dasd_ccw_req *cqr; | ||
2097 | struct ccw1 *ccw; | ||
2098 | int rc; | ||
2099 | |||
2100 | /* Copy parms from caller */ | ||
2101 | rc = -EFAULT; | ||
2102 | if (copy_from_user(&usrparm, argp, sizeof(usrparm))) | ||
2103 | goto out; | ||
2104 | #ifndef CONFIG_64BIT | ||
2105 | /* Make sure pointers are sane even on 31 bit. */ | ||
2106 | if ((usrparm.psf_data >> 32) != 0 || (usrparm.rssd_result >> 32) != 0) { | ||
2107 | rc = -EINVAL; | ||
2108 | goto out; | ||
2109 | } | ||
2110 | #endif | ||
2111 | /* alloc I/O data area */ | ||
2112 | psf_data = kzalloc(usrparm.psf_data_len, GFP_KERNEL | GFP_DMA); | ||
2113 | rssd_result = kzalloc(usrparm.rssd_result_len, GFP_KERNEL | GFP_DMA); | ||
2114 | if (!psf_data || !rssd_result) { | ||
2115 | rc = -ENOMEM; | ||
2116 | goto out_free; | ||
2117 | } | ||
2118 | |||
2119 | /* get syscall header from user space */ | ||
2120 | rc = -EFAULT; | ||
2121 | if (copy_from_user(psf_data, | ||
2122 | (void __user *)(unsigned long) usrparm.psf_data, | ||
2123 | usrparm.psf_data_len)) | ||
2124 | goto out_free; | ||
2125 | |||
2126 | /* sanity check on syscall header */ | ||
2127 | if (psf_data[0] != 0x17 && psf_data[1] != 0xce) { | ||
2128 | rc = -EINVAL; | ||
2129 | goto out_free; | ||
2130 | } | ||
2131 | |||
2132 | /* setup CCWs for PSF + RSSD */ | ||
2133 | cqr = dasd_smalloc_request("ECKD", 2 , 0, device); | ||
2134 | if (IS_ERR(cqr)) { | ||
2135 | DEV_MESSAGE(KERN_WARNING, device, "%s", | ||
2136 | "Could not allocate initialization request"); | ||
2137 | rc = PTR_ERR(cqr); | ||
2138 | goto out_free; | ||
2139 | } | ||
2140 | |||
2141 | cqr->startdev = device; | ||
2142 | cqr->memdev = device; | ||
2143 | cqr->retries = 3; | ||
2144 | cqr->expires = 10 * HZ; | ||
2145 | cqr->buildclk = get_clock(); | ||
2146 | cqr->status = DASD_CQR_FILLED; | ||
2147 | |||
2148 | /* Build the ccws */ | ||
2149 | ccw = cqr->cpaddr; | ||
2150 | |||
2151 | /* PSF ccw */ | ||
2152 | ccw->cmd_code = DASD_ECKD_CCW_PSF; | ||
2153 | ccw->count = usrparm.psf_data_len; | ||
2154 | ccw->flags |= CCW_FLAG_CC; | ||
2155 | ccw->cda = (__u32)(addr_t) psf_data; | ||
2156 | |||
2157 | ccw++; | ||
2158 | |||
2159 | /* RSSD ccw */ | ||
2160 | ccw->cmd_code = DASD_ECKD_CCW_RSSD; | ||
2161 | ccw->count = usrparm.rssd_result_len; | ||
2162 | ccw->flags = CCW_FLAG_SLI ; | ||
2163 | ccw->cda = (__u32)(addr_t) rssd_result; | ||
2164 | |||
2165 | rc = dasd_sleep_on(cqr); | ||
2166 | if (rc) | ||
2167 | goto out_sfree; | ||
2168 | |||
2169 | rc = -EFAULT; | ||
2170 | if (copy_to_user((void __user *)(unsigned long) usrparm.rssd_result, | ||
2171 | rssd_result, usrparm.rssd_result_len)) | ||
2172 | goto out_sfree; | ||
2173 | rc = 0; | ||
2174 | |||
2175 | out_sfree: | ||
2176 | dasd_sfree_request(cqr, cqr->memdev); | ||
2177 | out_free: | ||
2178 | kfree(rssd_result); | ||
2179 | kfree(psf_data); | ||
2180 | out: | ||
2181 | DBF_DEV_EVENT(DBF_WARNING, device, "Symmetrix ioctl: rc=%d", rc); | ||
2182 | return rc; | ||
2183 | } | ||
2184 | |||
2071 | static int | 2185 | static int |
2072 | dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp) | 2186 | dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp) |
2073 | { | 2187 | { |
@@ -2086,6 +2200,8 @@ dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp) | |||
2086 | return dasd_eckd_reserve(device); | 2200 | return dasd_eckd_reserve(device); |
2087 | case BIODASDSLCK: | 2201 | case BIODASDSLCK: |
2088 | return dasd_eckd_steal_lock(device); | 2202 | return dasd_eckd_steal_lock(device); |
2203 | case BIODASDSYMMIO: | ||
2204 | return dasd_symm_io(device, argp); | ||
2089 | default: | 2205 | default: |
2090 | return -ENOIOCTLCMD; | 2206 | return -ENOIOCTLCMD; |
2091 | } | 2207 | } |
@@ -2145,13 +2261,13 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, | |||
2145 | /* dump the sense data */ | 2261 | /* dump the sense data */ |
2146 | len = sprintf(page, KERN_ERR PRINTK_HEADER | 2262 | len = sprintf(page, KERN_ERR PRINTK_HEADER |
2147 | " I/O status report for device %s:\n", | 2263 | " I/O status report for device %s:\n", |
2148 | device->cdev->dev.bus_id); | 2264 | dev_name(&device->cdev->dev)); |
2149 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | 2265 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER |
2150 | " in req: %p CS: 0x%02X DS: 0x%02X\n", req, | 2266 | " in req: %p CS: 0x%02X DS: 0x%02X\n", req, |
2151 | irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); | 2267 | irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); |
2152 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | 2268 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER |
2153 | " device %s: Failing CCW: %p\n", | 2269 | " device %s: Failing CCW: %p\n", |
2154 | device->cdev->dev.bus_id, | 2270 | dev_name(&device->cdev->dev), |
2155 | (void *) (addr_t) irb->scsw.cmd.cpa); | 2271 | (void *) (addr_t) irb->scsw.cmd.cpa); |
2156 | if (irb->esw.esw0.erw.cons) { | 2272 | if (irb->esw.esw0.erw.cons) { |
2157 | for (sl = 0; sl < 4; sl++) { | 2273 | for (sl = 0; sl < 4; sl++) { |
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index bf512ac75b9e..892e2878d61b 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c | |||
@@ -309,7 +309,8 @@ static void dasd_eer_write_standard_trigger(struct dasd_device *device, | |||
309 | do_gettimeofday(&tv); | 309 | do_gettimeofday(&tv); |
310 | header.tv_sec = tv.tv_sec; | 310 | header.tv_sec = tv.tv_sec; |
311 | header.tv_usec = tv.tv_usec; | 311 | header.tv_usec = tv.tv_usec; |
312 | strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE); | 312 | strncpy(header.busid, dev_name(&device->cdev->dev), |
313 | DASD_EER_BUSID_SIZE); | ||
313 | 314 | ||
314 | spin_lock_irqsave(&bufferlock, flags); | 315 | spin_lock_irqsave(&bufferlock, flags); |
315 | list_for_each_entry(eerb, &bufferlist, list) { | 316 | list_for_each_entry(eerb, &bufferlist, list) { |
@@ -349,7 +350,8 @@ static void dasd_eer_write_snss_trigger(struct dasd_device *device, | |||
349 | do_gettimeofday(&tv); | 350 | do_gettimeofday(&tv); |
350 | header.tv_sec = tv.tv_sec; | 351 | header.tv_sec = tv.tv_sec; |
351 | header.tv_usec = tv.tv_usec; | 352 | header.tv_usec = tv.tv_usec; |
352 | strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE); | 353 | strncpy(header.busid, dev_name(&device->cdev->dev), |
354 | DASD_EER_BUSID_SIZE); | ||
353 | 355 | ||
354 | spin_lock_irqsave(&bufferlock, flags); | 356 | spin_lock_irqsave(&bufferlock, flags); |
355 | list_for_each_entry(eerb, &bufferlist, list) { | 357 | list_for_each_entry(eerb, &bufferlist, list) { |
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index aa0c533423a5..93d9b6452a94 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c | |||
@@ -451,13 +451,13 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, | |||
451 | } | 451 | } |
452 | len = sprintf(page, KERN_ERR PRINTK_HEADER | 452 | len = sprintf(page, KERN_ERR PRINTK_HEADER |
453 | " I/O status report for device %s:\n", | 453 | " I/O status report for device %s:\n", |
454 | device->cdev->dev.bus_id); | 454 | dev_name(&device->cdev->dev)); |
455 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | 455 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER |
456 | " in req: %p CS: 0x%02X DS: 0x%02X\n", req, | 456 | " in req: %p CS: 0x%02X DS: 0x%02X\n", req, |
457 | irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); | 457 | irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); |
458 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | 458 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER |
459 | " device %s: Failing CCW: %p\n", | 459 | " device %s: Failing CCW: %p\n", |
460 | device->cdev->dev.bus_id, | 460 | dev_name(&device->cdev->dev), |
461 | (void *) (addr_t) irb->scsw.cmd.cpa); | 461 | (void *) (addr_t) irb->scsw.cmd.cpa); |
462 | if (irb->esw.esw0.erw.cons) { | 462 | if (irb->esw.esw0.erw.cons) { |
463 | for (sl = 0; sl < 4; sl++) { | 463 | for (sl = 0; sl < 4; sl++) { |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 31ecaa4a40e4..489d5fe488fb 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
@@ -126,7 +126,7 @@ do { \ | |||
126 | #define DEV_MESSAGE(d_loglevel,d_device,d_string,d_args...)\ | 126 | #define DEV_MESSAGE(d_loglevel,d_device,d_string,d_args...)\ |
127 | do { \ | 127 | do { \ |
128 | printk(d_loglevel PRINTK_HEADER " %s: " d_string "\n", \ | 128 | printk(d_loglevel PRINTK_HEADER " %s: " d_string "\n", \ |
129 | d_device->cdev->dev.bus_id, d_args); \ | 129 | dev_name(&d_device->cdev->dev), d_args); \ |
130 | DBF_DEV_EVENT(DBF_ALERT, d_device, d_string, d_args); \ | 130 | DBF_DEV_EVENT(DBF_ALERT, d_device, d_string, d_args); \ |
131 | } while(0) | 131 | } while(0) |
132 | 132 | ||
@@ -140,7 +140,7 @@ do { \ | |||
140 | #define DEV_MESSAGE_LOG(d_loglevel,d_device,d_string,d_args...)\ | 140 | #define DEV_MESSAGE_LOG(d_loglevel,d_device,d_string,d_args...)\ |
141 | do { \ | 141 | do { \ |
142 | printk(d_loglevel PRINTK_HEADER " %s: " d_string "\n", \ | 142 | printk(d_loglevel PRINTK_HEADER " %s: " d_string "\n", \ |
143 | d_device->cdev->dev.bus_id, d_args); \ | 143 | dev_name(&d_device->cdev->dev), d_args); \ |
144 | } while(0) | 144 | } while(0) |
145 | 145 | ||
146 | #define MESSAGE_LOG(d_loglevel,d_string,d_args...)\ | 146 | #define MESSAGE_LOG(d_loglevel,d_string,d_args...)\ |
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index e3b5c4d3036e..9088de84b45d 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c | |||
@@ -67,7 +67,7 @@ dasd_devices_show(struct seq_file *m, void *v) | |||
67 | return 0; | 67 | return 0; |
68 | } | 68 | } |
69 | /* Print device number. */ | 69 | /* Print device number. */ |
70 | seq_printf(m, "%s", device->cdev->dev.bus_id); | 70 | seq_printf(m, "%s", dev_name(&device->cdev->dev)); |
71 | /* Print discipline string. */ | 71 | /* Print discipline string. */ |
72 | if (device != NULL && device->discipline != NULL) | 72 | if (device != NULL && device->discipline != NULL) |
73 | seq_printf(m, "(%s)", device->discipline->name); | 73 | seq_printf(m, "(%s)", device->discipline->name); |
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 9481e4a3f76e..a7ff167d5b81 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c | |||
@@ -31,7 +31,6 @@ | |||
31 | #define PRINT_WARN(x...) printk(KERN_WARNING DCSSBLK_NAME " warning: " x) | 31 | #define PRINT_WARN(x...) printk(KERN_WARNING DCSSBLK_NAME " warning: " x) |
32 | #define PRINT_ERR(x...) printk(KERN_ERR DCSSBLK_NAME " error: " x) | 32 | #define PRINT_ERR(x...) printk(KERN_ERR DCSSBLK_NAME " error: " x) |
33 | 33 | ||
34 | |||
35 | static int dcssblk_open(struct inode *inode, struct file *filp); | 34 | static int dcssblk_open(struct inode *inode, struct file *filp); |
36 | static int dcssblk_release(struct inode *inode, struct file *filp); | 35 | static int dcssblk_release(struct inode *inode, struct file *filp); |
37 | static int dcssblk_make_request(struct request_queue *q, struct bio *bio); | 36 | static int dcssblk_make_request(struct request_queue *q, struct bio *bio); |
@@ -48,6 +47,30 @@ static struct block_device_operations dcssblk_devops = { | |||
48 | .direct_access = dcssblk_direct_access, | 47 | .direct_access = dcssblk_direct_access, |
49 | }; | 48 | }; |
50 | 49 | ||
50 | struct dcssblk_dev_info { | ||
51 | struct list_head lh; | ||
52 | struct device dev; | ||
53 | char segment_name[BUS_ID_SIZE]; | ||
54 | atomic_t use_count; | ||
55 | struct gendisk *gd; | ||
56 | unsigned long start; | ||
57 | unsigned long end; | ||
58 | int segment_type; | ||
59 | unsigned char save_pending; | ||
60 | unsigned char is_shared; | ||
61 | struct request_queue *dcssblk_queue; | ||
62 | int num_of_segments; | ||
63 | struct list_head seg_list; | ||
64 | }; | ||
65 | |||
66 | struct segment_info { | ||
67 | struct list_head lh; | ||
68 | char segment_name[BUS_ID_SIZE]; | ||
69 | unsigned long start; | ||
70 | unsigned long end; | ||
71 | int segment_type; | ||
72 | }; | ||
73 | |||
51 | static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf, | 74 | static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf, |
52 | size_t count); | 75 | size_t count); |
53 | static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf, | 76 | static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf, |
@@ -58,30 +81,20 @@ static ssize_t dcssblk_save_show(struct device *dev, struct device_attribute *at | |||
58 | static ssize_t dcssblk_shared_store(struct device * dev, struct device_attribute *attr, const char * buf, | 81 | static ssize_t dcssblk_shared_store(struct device * dev, struct device_attribute *attr, const char * buf, |
59 | size_t count); | 82 | size_t count); |
60 | static ssize_t dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf); | 83 | static ssize_t dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf); |
84 | static ssize_t dcssblk_seglist_show(struct device *dev, | ||
85 | struct device_attribute *attr, | ||
86 | char *buf); | ||
61 | 87 | ||
62 | static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store); | 88 | static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store); |
63 | static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store); | 89 | static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store); |
64 | static DEVICE_ATTR(save, S_IWUSR | S_IRUGO, dcssblk_save_show, | 90 | static DEVICE_ATTR(save, S_IWUSR | S_IRUSR, dcssblk_save_show, |
65 | dcssblk_save_store); | 91 | dcssblk_save_store); |
66 | static DEVICE_ATTR(shared, S_IWUSR | S_IRUGO, dcssblk_shared_show, | 92 | static DEVICE_ATTR(shared, S_IWUSR | S_IRUSR, dcssblk_shared_show, |
67 | dcssblk_shared_store); | 93 | dcssblk_shared_store); |
94 | static DEVICE_ATTR(seglist, S_IRUSR, dcssblk_seglist_show, NULL); | ||
68 | 95 | ||
69 | static struct device *dcssblk_root_dev; | 96 | static struct device *dcssblk_root_dev; |
70 | 97 | ||
71 | struct dcssblk_dev_info { | ||
72 | struct list_head lh; | ||
73 | struct device dev; | ||
74 | char segment_name[BUS_ID_SIZE]; | ||
75 | atomic_t use_count; | ||
76 | struct gendisk *gd; | ||
77 | unsigned long start; | ||
78 | unsigned long end; | ||
79 | int segment_type; | ||
80 | unsigned char save_pending; | ||
81 | unsigned char is_shared; | ||
82 | struct request_queue *dcssblk_queue; | ||
83 | }; | ||
84 | |||
85 | static LIST_HEAD(dcssblk_devices); | 98 | static LIST_HEAD(dcssblk_devices); |
86 | static struct rw_semaphore dcssblk_devices_sem; | 99 | static struct rw_semaphore dcssblk_devices_sem; |
87 | 100 | ||
@@ -91,8 +104,15 @@ static struct rw_semaphore dcssblk_devices_sem; | |||
91 | static void | 104 | static void |
92 | dcssblk_release_segment(struct device *dev) | 105 | dcssblk_release_segment(struct device *dev) |
93 | { | 106 | { |
94 | PRINT_DEBUG("segment release fn called for %s\n", dev->bus_id); | 107 | struct dcssblk_dev_info *dev_info; |
95 | kfree(container_of(dev, struct dcssblk_dev_info, dev)); | 108 | struct segment_info *entry, *temp; |
109 | |||
110 | dev_info = container_of(dev, struct dcssblk_dev_info, dev); | ||
111 | list_for_each_entry_safe(entry, temp, &dev_info->seg_list, lh) { | ||
112 | list_del(&entry->lh); | ||
113 | kfree(entry); | ||
114 | } | ||
115 | kfree(dev_info); | ||
96 | module_put(THIS_MODULE); | 116 | module_put(THIS_MODULE); |
97 | } | 117 | } |
98 | 118 | ||
@@ -142,6 +162,169 @@ dcssblk_get_device_by_name(char *name) | |||
142 | return NULL; | 162 | return NULL; |
143 | } | 163 | } |
144 | 164 | ||
165 | /* | ||
166 | * get the struct segment_info from seg_list | ||
167 | * for the given name. | ||
168 | * down_read(&dcssblk_devices_sem) must be held. | ||
169 | */ | ||
170 | static struct segment_info * | ||
171 | dcssblk_get_segment_by_name(char *name) | ||
172 | { | ||
173 | struct dcssblk_dev_info *dev_info; | ||
174 | struct segment_info *entry; | ||
175 | |||
176 | list_for_each_entry(dev_info, &dcssblk_devices, lh) { | ||
177 | list_for_each_entry(entry, &dev_info->seg_list, lh) { | ||
178 | if (!strcmp(name, entry->segment_name)) | ||
179 | return entry; | ||
180 | } | ||
181 | } | ||
182 | return NULL; | ||
183 | } | ||
184 | |||
185 | /* | ||
186 | * get the highest address of the multi-segment block. | ||
187 | */ | ||
188 | static unsigned long | ||
189 | dcssblk_find_highest_addr(struct dcssblk_dev_info *dev_info) | ||
190 | { | ||
191 | unsigned long highest_addr; | ||
192 | struct segment_info *entry; | ||
193 | |||
194 | highest_addr = 0; | ||
195 | list_for_each_entry(entry, &dev_info->seg_list, lh) { | ||
196 | if (highest_addr < entry->end) | ||
197 | highest_addr = entry->end; | ||
198 | } | ||
199 | return highest_addr; | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * get the lowest address of the multi-segment block. | ||
204 | */ | ||
205 | static unsigned long | ||
206 | dcssblk_find_lowest_addr(struct dcssblk_dev_info *dev_info) | ||
207 | { | ||
208 | int set_first; | ||
209 | unsigned long lowest_addr; | ||
210 | struct segment_info *entry; | ||
211 | |||
212 | set_first = 0; | ||
213 | lowest_addr = 0; | ||
214 | list_for_each_entry(entry, &dev_info->seg_list, lh) { | ||
215 | if (set_first == 0) { | ||
216 | lowest_addr = entry->start; | ||
217 | set_first = 1; | ||
218 | } else { | ||
219 | if (lowest_addr > entry->start) | ||
220 | lowest_addr = entry->start; | ||
221 | } | ||
222 | } | ||
223 | return lowest_addr; | ||
224 | } | ||
225 | |||
226 | /* | ||
227 | * Check continuity of segments. | ||
228 | */ | ||
229 | static int | ||
230 | dcssblk_is_continuous(struct dcssblk_dev_info *dev_info) | ||
231 | { | ||
232 | int i, j, rc; | ||
233 | struct segment_info *sort_list, *entry, temp; | ||
234 | |||
235 | if (dev_info->num_of_segments <= 1) | ||
236 | return 0; | ||
237 | |||
238 | sort_list = kzalloc( | ||
239 | sizeof(struct segment_info) * dev_info->num_of_segments, | ||
240 | GFP_KERNEL); | ||
241 | if (sort_list == NULL) | ||
242 | return -ENOMEM; | ||
243 | i = 0; | ||
244 | list_for_each_entry(entry, &dev_info->seg_list, lh) { | ||
245 | memcpy(&sort_list[i], entry, sizeof(struct segment_info)); | ||
246 | i++; | ||
247 | } | ||
248 | |||
249 | /* sort segments */ | ||
250 | for (i = 0; i < dev_info->num_of_segments; i++) | ||
251 | for (j = 0; j < dev_info->num_of_segments; j++) | ||
252 | if (sort_list[j].start > sort_list[i].start) { | ||
253 | memcpy(&temp, &sort_list[i], | ||
254 | sizeof(struct segment_info)); | ||
255 | memcpy(&sort_list[i], &sort_list[j], | ||
256 | sizeof(struct segment_info)); | ||
257 | memcpy(&sort_list[j], &temp, | ||
258 | sizeof(struct segment_info)); | ||
259 | } | ||
260 | |||
261 | /* check continuity */ | ||
262 | for (i = 0; i < dev_info->num_of_segments - 1; i++) { | ||
263 | if ((sort_list[i].end + 1) != sort_list[i+1].start) { | ||
264 | PRINT_ERR("Segment %s is not contiguous with " | ||
265 | "segment %s\n", | ||
266 | sort_list[i].segment_name, | ||
267 | sort_list[i+1].segment_name); | ||
268 | rc = -EINVAL; | ||
269 | goto out; | ||
270 | } | ||
271 | /* EN and EW are allowed in a block device */ | ||
272 | if (sort_list[i].segment_type != sort_list[i+1].segment_type) { | ||
273 | if (!(sort_list[i].segment_type & SEGMENT_EXCLUSIVE) || | ||
274 | (sort_list[i].segment_type == SEG_TYPE_ER) || | ||
275 | !(sort_list[i+1].segment_type & | ||
276 | SEGMENT_EXCLUSIVE) || | ||
277 | (sort_list[i+1].segment_type == SEG_TYPE_ER)) { | ||
278 | PRINT_ERR("Segment %s has different type from " | ||
279 | "segment %s\n", | ||
280 | sort_list[i].segment_name, | ||
281 | sort_list[i+1].segment_name); | ||
282 | rc = -EINVAL; | ||
283 | goto out; | ||
284 | } | ||
285 | } | ||
286 | } | ||
287 | rc = 0; | ||
288 | out: | ||
289 | kfree(sort_list); | ||
290 | return rc; | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * Load a segment | ||
295 | */ | ||
296 | static int | ||
297 | dcssblk_load_segment(char *name, struct segment_info **seg_info) | ||
298 | { | ||
299 | int rc; | ||
300 | |||
301 | /* already loaded? */ | ||
302 | down_read(&dcssblk_devices_sem); | ||
303 | *seg_info = dcssblk_get_segment_by_name(name); | ||
304 | up_read(&dcssblk_devices_sem); | ||
305 | if (*seg_info != NULL) | ||
306 | return -EEXIST; | ||
307 | |||
308 | /* get a struct segment_info */ | ||
309 | *seg_info = kzalloc(sizeof(struct segment_info), GFP_KERNEL); | ||
310 | if (*seg_info == NULL) | ||
311 | return -ENOMEM; | ||
312 | |||
313 | strcpy((*seg_info)->segment_name, name); | ||
314 | |||
315 | /* load the segment */ | ||
316 | rc = segment_load(name, SEGMENT_SHARED, | ||
317 | &(*seg_info)->start, &(*seg_info)->end); | ||
318 | if (rc < 0) { | ||
319 | segment_warning(rc, (*seg_info)->segment_name); | ||
320 | kfree(*seg_info); | ||
321 | } else { | ||
322 | INIT_LIST_HEAD(&(*seg_info)->lh); | ||
323 | (*seg_info)->segment_type = rc; | ||
324 | } | ||
325 | return rc; | ||
326 | } | ||
327 | |||
145 | static void dcssblk_unregister_callback(struct device *dev) | 328 | static void dcssblk_unregister_callback(struct device *dev) |
146 | { | 329 | { |
147 | device_unregister(dev); | 330 | device_unregister(dev); |
@@ -165,6 +348,7 @@ static ssize_t | |||
165 | dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count) | 348 | dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count) |
166 | { | 349 | { |
167 | struct dcssblk_dev_info *dev_info; | 350 | struct dcssblk_dev_info *dev_info; |
351 | struct segment_info *entry, *temp; | ||
168 | int rc; | 352 | int rc; |
169 | 353 | ||
170 | if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) | 354 | if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) |
@@ -172,46 +356,46 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch | |||
172 | down_write(&dcssblk_devices_sem); | 356 | down_write(&dcssblk_devices_sem); |
173 | dev_info = container_of(dev, struct dcssblk_dev_info, dev); | 357 | dev_info = container_of(dev, struct dcssblk_dev_info, dev); |
174 | if (atomic_read(&dev_info->use_count)) { | 358 | if (atomic_read(&dev_info->use_count)) { |
175 | PRINT_ERR("share: segment %s is busy!\n", | ||
176 | dev_info->segment_name); | ||
177 | rc = -EBUSY; | 359 | rc = -EBUSY; |
178 | goto out; | 360 | goto out; |
179 | } | 361 | } |
180 | if (inbuf[0] == '1') { | 362 | if (inbuf[0] == '1') { |
181 | // reload segment in shared mode | 363 | /* reload segments in shared mode */ |
182 | rc = segment_modify_shared(dev_info->segment_name, | 364 | list_for_each_entry(entry, &dev_info->seg_list, lh) { |
183 | SEGMENT_SHARED); | 365 | rc = segment_modify_shared(entry->segment_name, |
184 | if (rc < 0) { | 366 | SEGMENT_SHARED); |
185 | BUG_ON(rc == -EINVAL); | 367 | if (rc < 0) { |
186 | if (rc != -EAGAIN) | 368 | BUG_ON(rc == -EINVAL); |
187 | goto removeseg; | 369 | if (rc != -EAGAIN) |
188 | } else { | 370 | goto removeseg; |
189 | dev_info->is_shared = 1; | ||
190 | switch (dev_info->segment_type) { | ||
191 | case SEG_TYPE_SR: | ||
192 | case SEG_TYPE_ER: | ||
193 | case SEG_TYPE_SC: | ||
194 | set_disk_ro(dev_info->gd,1); | ||
195 | } | 371 | } |
196 | } | 372 | } |
373 | dev_info->is_shared = 1; | ||
374 | switch (dev_info->segment_type) { | ||
375 | case SEG_TYPE_SR: | ||
376 | case SEG_TYPE_ER: | ||
377 | case SEG_TYPE_SC: | ||
378 | set_disk_ro(dev_info->gd, 1); | ||
379 | } | ||
197 | } else if (inbuf[0] == '0') { | 380 | } else if (inbuf[0] == '0') { |
198 | // reload segment in exclusive mode | 381 | /* reload segments in exclusive mode */ |
199 | if (dev_info->segment_type == SEG_TYPE_SC) { | 382 | if (dev_info->segment_type == SEG_TYPE_SC) { |
200 | PRINT_ERR("Segment type SC (%s) cannot be loaded in " | 383 | PRINT_ERR("Segment type SC (%s) cannot be loaded in " |
201 | "non-shared mode\n", dev_info->segment_name); | 384 | "non-shared mode\n", dev_info->segment_name); |
202 | rc = -EINVAL; | 385 | rc = -EINVAL; |
203 | goto out; | 386 | goto out; |
204 | } | 387 | } |
205 | rc = segment_modify_shared(dev_info->segment_name, | 388 | list_for_each_entry(entry, &dev_info->seg_list, lh) { |
206 | SEGMENT_EXCLUSIVE); | 389 | rc = segment_modify_shared(entry->segment_name, |
207 | if (rc < 0) { | 390 | SEGMENT_EXCLUSIVE); |
208 | BUG_ON(rc == -EINVAL); | 391 | if (rc < 0) { |
209 | if (rc != -EAGAIN) | 392 | BUG_ON(rc == -EINVAL); |
210 | goto removeseg; | 393 | if (rc != -EAGAIN) |
211 | } else { | 394 | goto removeseg; |
212 | dev_info->is_shared = 0; | 395 | } |
213 | set_disk_ro(dev_info->gd, 0); | ||
214 | } | 396 | } |
397 | dev_info->is_shared = 0; | ||
398 | set_disk_ro(dev_info->gd, 0); | ||
215 | } else { | 399 | } else { |
216 | rc = -EINVAL; | 400 | rc = -EINVAL; |
217 | goto out; | 401 | goto out; |
@@ -220,8 +404,14 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch | |||
220 | goto out; | 404 | goto out; |
221 | 405 | ||
222 | removeseg: | 406 | removeseg: |
223 | PRINT_ERR("Could not reload segment %s, removing it now!\n", | 407 | PRINT_ERR("Could not reload segment(s) of the device %s, removing " |
224 | dev_info->segment_name); | 408 | "segment(s) now!\n", |
409 | dev_info->segment_name); | ||
410 | temp = entry; | ||
411 | list_for_each_entry(entry, &dev_info->seg_list, lh) { | ||
412 | if (entry != temp) | ||
413 | segment_unload(entry->segment_name); | ||
414 | } | ||
225 | list_del(&dev_info->lh); | 415 | list_del(&dev_info->lh); |
226 | 416 | ||
227 | del_gendisk(dev_info->gd); | 417 | del_gendisk(dev_info->gd); |
@@ -254,6 +444,7 @@ static ssize_t | |||
254 | dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count) | 444 | dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count) |
255 | { | 445 | { |
256 | struct dcssblk_dev_info *dev_info; | 446 | struct dcssblk_dev_info *dev_info; |
447 | struct segment_info *entry; | ||
257 | 448 | ||
258 | if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) | 449 | if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) |
259 | return -EINVAL; | 450 | return -EINVAL; |
@@ -263,14 +454,16 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char | |||
263 | if (inbuf[0] == '1') { | 454 | if (inbuf[0] == '1') { |
264 | if (atomic_read(&dev_info->use_count) == 0) { | 455 | if (atomic_read(&dev_info->use_count) == 0) { |
265 | // device is idle => we save immediately | 456 | // device is idle => we save immediately |
266 | PRINT_INFO("Saving segment %s\n", | 457 | PRINT_INFO("Saving segment(s) of the device %s\n", |
267 | dev_info->segment_name); | 458 | dev_info->segment_name); |
268 | segment_save(dev_info->segment_name); | 459 | list_for_each_entry(entry, &dev_info->seg_list, lh) { |
460 | segment_save(entry->segment_name); | ||
461 | } | ||
269 | } else { | 462 | } else { |
270 | // device is busy => we save it when it becomes | 463 | // device is busy => we save it when it becomes |
271 | // idle in dcssblk_release | 464 | // idle in dcssblk_release |
272 | PRINT_INFO("Segment %s is currently busy, it will " | 465 | PRINT_INFO("Device %s is currently busy, segment(s) " |
273 | "be saved when it becomes idle...\n", | 466 | "will be saved when it becomes idle...\n", |
274 | dev_info->segment_name); | 467 | dev_info->segment_name); |
275 | dev_info->save_pending = 1; | 468 | dev_info->save_pending = 1; |
276 | } | 469 | } |
@@ -279,7 +472,8 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char | |||
279 | // device is busy & the user wants to undo his save | 472 | // device is busy & the user wants to undo his save |
280 | // request | 473 | // request |
281 | dev_info->save_pending = 0; | 474 | dev_info->save_pending = 0; |
282 | PRINT_INFO("Pending save for segment %s deactivated\n", | 475 | PRINT_INFO("Pending save for segment(s) of the device " |
476 | "%s deactivated\n", | ||
283 | dev_info->segment_name); | 477 | dev_info->segment_name); |
284 | } | 478 | } |
285 | } else { | 479 | } else { |
@@ -291,66 +485,123 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char | |||
291 | } | 485 | } |
292 | 486 | ||
293 | /* | 487 | /* |
488 | * device attribute for showing all segments in a device | ||
489 | */ | ||
490 | static ssize_t | ||
491 | dcssblk_seglist_show(struct device *dev, struct device_attribute *attr, | ||
492 | char *buf) | ||
493 | { | ||
494 | int i; | ||
495 | |||
496 | struct dcssblk_dev_info *dev_info; | ||
497 | struct segment_info *entry; | ||
498 | |||
499 | down_read(&dcssblk_devices_sem); | ||
500 | dev_info = container_of(dev, struct dcssblk_dev_info, dev); | ||
501 | i = 0; | ||
502 | buf[0] = '\0'; | ||
503 | list_for_each_entry(entry, &dev_info->seg_list, lh) { | ||
504 | strcpy(&buf[i], entry->segment_name); | ||
505 | i += strlen(entry->segment_name); | ||
506 | buf[i] = '\n'; | ||
507 | i++; | ||
508 | } | ||
509 | up_read(&dcssblk_devices_sem); | ||
510 | return i; | ||
511 | } | ||
512 | |||
513 | /* | ||
294 | * device attribute for adding devices | 514 | * device attribute for adding devices |
295 | */ | 515 | */ |
296 | static ssize_t | 516 | static ssize_t |
297 | dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 517 | dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
298 | { | 518 | { |
299 | int rc, i; | 519 | int rc, i, j, num_of_segments; |
300 | struct dcssblk_dev_info *dev_info; | 520 | struct dcssblk_dev_info *dev_info; |
521 | struct segment_info *seg_info, *temp; | ||
301 | char *local_buf; | 522 | char *local_buf; |
302 | unsigned long seg_byte_size; | 523 | unsigned long seg_byte_size; |
303 | 524 | ||
304 | dev_info = NULL; | 525 | dev_info = NULL; |
526 | seg_info = NULL; | ||
305 | if (dev != dcssblk_root_dev) { | 527 | if (dev != dcssblk_root_dev) { |
306 | rc = -EINVAL; | 528 | rc = -EINVAL; |
307 | goto out_nobuf; | 529 | goto out_nobuf; |
308 | } | 530 | } |
531 | if ((count < 1) || (buf[0] == '\0') || (buf[0] == '\n')) { | ||
532 | rc = -ENAMETOOLONG; | ||
533 | goto out_nobuf; | ||
534 | } | ||
535 | |||
309 | local_buf = kmalloc(count + 1, GFP_KERNEL); | 536 | local_buf = kmalloc(count + 1, GFP_KERNEL); |
310 | if (local_buf == NULL) { | 537 | if (local_buf == NULL) { |
311 | rc = -ENOMEM; | 538 | rc = -ENOMEM; |
312 | goto out_nobuf; | 539 | goto out_nobuf; |
313 | } | 540 | } |
541 | |||
314 | /* | 542 | /* |
315 | * parse input | 543 | * parse input |
316 | */ | 544 | */ |
545 | num_of_segments = 0; | ||
317 | for (i = 0; ((buf[i] != '\0') && (buf[i] != '\n') && i < count); i++) { | 546 | for (i = 0; ((buf[i] != '\0') && (buf[i] != '\n') && i < count); i++) { |
318 | local_buf[i] = toupper(buf[i]); | 547 | for (j = i; (buf[j] != ':') && |
548 | (buf[j] != '\0') && | ||
549 | (buf[j] != '\n') && | ||
550 | j < count; j++) { | ||
551 | local_buf[j-i] = toupper(buf[j]); | ||
552 | } | ||
553 | local_buf[j-i] = '\0'; | ||
554 | if (((j - i) == 0) || ((j - i) > 8)) { | ||
555 | rc = -ENAMETOOLONG; | ||
556 | goto seg_list_del; | ||
557 | } | ||
558 | |||
559 | rc = dcssblk_load_segment(local_buf, &seg_info); | ||
560 | if (rc < 0) | ||
561 | goto seg_list_del; | ||
562 | /* | ||
563 | * get a struct dcssblk_dev_info | ||
564 | */ | ||
565 | if (num_of_segments == 0) { | ||
566 | dev_info = kzalloc(sizeof(struct dcssblk_dev_info), | ||
567 | GFP_KERNEL); | ||
568 | if (dev_info == NULL) { | ||
569 | rc = -ENOMEM; | ||
570 | goto out; | ||
571 | } | ||
572 | strcpy(dev_info->segment_name, local_buf); | ||
573 | dev_info->segment_type = seg_info->segment_type; | ||
574 | INIT_LIST_HEAD(&dev_info->seg_list); | ||
575 | } | ||
576 | list_add_tail(&seg_info->lh, &dev_info->seg_list); | ||
577 | num_of_segments++; | ||
578 | i = j; | ||
579 | |||
580 | if ((buf[j] == '\0') || (buf[j] == '\n')) | ||
581 | break; | ||
319 | } | 582 | } |
320 | local_buf[i] = '\0'; | 583 | |
321 | if ((i == 0) || (i > 8)) { | 584 | /* no trailing colon at the end of the input */ |
585 | if ((i > 0) && (buf[i-1] == ':')) { | ||
322 | rc = -ENAMETOOLONG; | 586 | rc = -ENAMETOOLONG; |
323 | goto out; | 587 | goto seg_list_del; |
324 | } | ||
325 | /* | ||
326 | * already loaded? | ||
327 | */ | ||
328 | down_read(&dcssblk_devices_sem); | ||
329 | dev_info = dcssblk_get_device_by_name(local_buf); | ||
330 | up_read(&dcssblk_devices_sem); | ||
331 | if (dev_info != NULL) { | ||
332 | PRINT_WARN("Segment %s already loaded!\n", local_buf); | ||
333 | rc = -EEXIST; | ||
334 | goto out; | ||
335 | } | ||
336 | /* | ||
337 | * get a struct dcssblk_dev_info | ||
338 | */ | ||
339 | dev_info = kzalloc(sizeof(struct dcssblk_dev_info), GFP_KERNEL); | ||
340 | if (dev_info == NULL) { | ||
341 | rc = -ENOMEM; | ||
342 | goto out; | ||
343 | } | 588 | } |
589 | strlcpy(local_buf, buf, i + 1); | ||
590 | dev_info->num_of_segments = num_of_segments; | ||
591 | rc = dcssblk_is_continuous(dev_info); | ||
592 | if (rc < 0) | ||
593 | goto seg_list_del; | ||
594 | |||
595 | dev_info->start = dcssblk_find_lowest_addr(dev_info); | ||
596 | dev_info->end = dcssblk_find_highest_addr(dev_info); | ||
344 | 597 | ||
345 | strcpy(dev_info->segment_name, local_buf); | 598 | dev_set_name(&dev_info->dev, dev_info->segment_name); |
346 | strlcpy(dev_info->dev.bus_id, local_buf, BUS_ID_SIZE); | ||
347 | dev_info->dev.release = dcssblk_release_segment; | 599 | dev_info->dev.release = dcssblk_release_segment; |
348 | INIT_LIST_HEAD(&dev_info->lh); | 600 | INIT_LIST_HEAD(&dev_info->lh); |
349 | |||
350 | dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK); | 601 | dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK); |
351 | if (dev_info->gd == NULL) { | 602 | if (dev_info->gd == NULL) { |
352 | rc = -ENOMEM; | 603 | rc = -ENOMEM; |
353 | goto free_dev_info; | 604 | goto seg_list_del; |
354 | } | 605 | } |
355 | dev_info->gd->major = dcssblk_major; | 606 | dev_info->gd->major = dcssblk_major; |
356 | dev_info->gd->fops = &dcssblk_devops; | 607 | dev_info->gd->fops = &dcssblk_devops; |
@@ -360,59 +611,43 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char | |||
360 | dev_info->gd->driverfs_dev = &dev_info->dev; | 611 | dev_info->gd->driverfs_dev = &dev_info->dev; |
361 | blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request); | 612 | blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request); |
362 | blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096); | 613 | blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096); |
363 | /* | 614 | |
364 | * load the segment | ||
365 | */ | ||
366 | rc = segment_load(local_buf, SEGMENT_SHARED, | ||
367 | &dev_info->start, &dev_info->end); | ||
368 | if (rc < 0) { | ||
369 | segment_warning(rc, dev_info->segment_name); | ||
370 | goto dealloc_gendisk; | ||
371 | } | ||
372 | seg_byte_size = (dev_info->end - dev_info->start + 1); | 615 | seg_byte_size = (dev_info->end - dev_info->start + 1); |
373 | set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors | 616 | set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors |
374 | PRINT_INFO("Loaded segment %s, size = %lu Byte, " | 617 | PRINT_INFO("Loaded segment(s) %s, size = %lu Byte, " |
375 | "capacity = %lu (512 Byte) sectors\n", local_buf, | 618 | "capacity = %lu (512 Byte) sectors\n", local_buf, |
376 | seg_byte_size, seg_byte_size >> 9); | 619 | seg_byte_size, seg_byte_size >> 9); |
377 | 620 | ||
378 | dev_info->segment_type = rc; | ||
379 | dev_info->save_pending = 0; | 621 | dev_info->save_pending = 0; |
380 | dev_info->is_shared = 1; | 622 | dev_info->is_shared = 1; |
381 | dev_info->dev.parent = dcssblk_root_dev; | 623 | dev_info->dev.parent = dcssblk_root_dev; |
382 | 624 | ||
383 | /* | 625 | /* |
384 | * get minor, add to list | 626 | *get minor, add to list |
385 | */ | 627 | */ |
386 | down_write(&dcssblk_devices_sem); | 628 | down_write(&dcssblk_devices_sem); |
387 | if (dcssblk_get_device_by_name(local_buf)) { | 629 | if (dcssblk_get_segment_by_name(local_buf)) { |
388 | up_write(&dcssblk_devices_sem); | ||
389 | rc = -EEXIST; | 630 | rc = -EEXIST; |
390 | goto unload_seg; | 631 | goto release_gd; |
391 | } | 632 | } |
392 | rc = dcssblk_assign_free_minor(dev_info); | 633 | rc = dcssblk_assign_free_minor(dev_info); |
393 | if (rc) { | 634 | if (rc) |
394 | up_write(&dcssblk_devices_sem); | 635 | goto release_gd; |
395 | PRINT_ERR("No free minor number available! " | ||
396 | "Unloading segment...\n"); | ||
397 | goto unload_seg; | ||
398 | } | ||
399 | sprintf(dev_info->gd->disk_name, "dcssblk%d", | 636 | sprintf(dev_info->gd->disk_name, "dcssblk%d", |
400 | MINOR(disk_devt(dev_info->gd))); | 637 | MINOR(disk_devt(dev_info->gd))); |
401 | list_add_tail(&dev_info->lh, &dcssblk_devices); | 638 | list_add_tail(&dev_info->lh, &dcssblk_devices); |
402 | 639 | ||
403 | if (!try_module_get(THIS_MODULE)) { | 640 | if (!try_module_get(THIS_MODULE)) { |
404 | rc = -ENODEV; | 641 | rc = -ENODEV; |
405 | goto list_del; | 642 | goto dev_list_del; |
406 | } | 643 | } |
407 | /* | 644 | /* |
408 | * register the device | 645 | * register the device |
409 | */ | 646 | */ |
410 | rc = device_register(&dev_info->dev); | 647 | rc = device_register(&dev_info->dev); |
411 | if (rc) { | 648 | if (rc) { |
412 | PRINT_ERR("Segment %s could not be registered RC=%d\n", | ||
413 | local_buf, rc); | ||
414 | module_put(THIS_MODULE); | 649 | module_put(THIS_MODULE); |
415 | goto list_del; | 650 | goto dev_list_del; |
416 | } | 651 | } |
417 | get_device(&dev_info->dev); | 652 | get_device(&dev_info->dev); |
418 | rc = device_create_file(&dev_info->dev, &dev_attr_shared); | 653 | rc = device_create_file(&dev_info->dev, &dev_attr_shared); |
@@ -421,6 +656,9 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char | |||
421 | rc = device_create_file(&dev_info->dev, &dev_attr_save); | 656 | rc = device_create_file(&dev_info->dev, &dev_attr_save); |
422 | if (rc) | 657 | if (rc) |
423 | goto unregister_dev; | 658 | goto unregister_dev; |
659 | rc = device_create_file(&dev_info->dev, &dev_attr_seglist); | ||
660 | if (rc) | ||
661 | goto unregister_dev; | ||
424 | 662 | ||
425 | add_disk(dev_info->gd); | 663 | add_disk(dev_info->gd); |
426 | 664 | ||
@@ -434,7 +672,6 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char | |||
434 | set_disk_ro(dev_info->gd,0); | 672 | set_disk_ro(dev_info->gd,0); |
435 | break; | 673 | break; |
436 | } | 674 | } |
437 | PRINT_DEBUG("Segment %s loaded successfully\n", local_buf); | ||
438 | up_write(&dcssblk_devices_sem); | 675 | up_write(&dcssblk_devices_sem); |
439 | rc = count; | 676 | rc = count; |
440 | goto out; | 677 | goto out; |
@@ -445,20 +682,27 @@ unregister_dev: | |||
445 | dev_info->gd->queue = NULL; | 682 | dev_info->gd->queue = NULL; |
446 | put_disk(dev_info->gd); | 683 | put_disk(dev_info->gd); |
447 | device_unregister(&dev_info->dev); | 684 | device_unregister(&dev_info->dev); |
448 | segment_unload(dev_info->segment_name); | 685 | list_for_each_entry(seg_info, &dev_info->seg_list, lh) { |
686 | segment_unload(seg_info->segment_name); | ||
687 | } | ||
449 | put_device(&dev_info->dev); | 688 | put_device(&dev_info->dev); |
450 | up_write(&dcssblk_devices_sem); | 689 | up_write(&dcssblk_devices_sem); |
451 | goto out; | 690 | goto out; |
452 | list_del: | 691 | dev_list_del: |
453 | list_del(&dev_info->lh); | 692 | list_del(&dev_info->lh); |
454 | up_write(&dcssblk_devices_sem); | 693 | release_gd: |
455 | unload_seg: | ||
456 | segment_unload(local_buf); | ||
457 | dealloc_gendisk: | ||
458 | blk_cleanup_queue(dev_info->dcssblk_queue); | 694 | blk_cleanup_queue(dev_info->dcssblk_queue); |
459 | dev_info->gd->queue = NULL; | 695 | dev_info->gd->queue = NULL; |
460 | put_disk(dev_info->gd); | 696 | put_disk(dev_info->gd); |
461 | free_dev_info: | 697 | up_write(&dcssblk_devices_sem); |
698 | seg_list_del: | ||
699 | if (dev_info == NULL) | ||
700 | goto out; | ||
701 | list_for_each_entry_safe(seg_info, temp, &dev_info->seg_list, lh) { | ||
702 | list_del(&seg_info->lh); | ||
703 | segment_unload(seg_info->segment_name); | ||
704 | kfree(seg_info); | ||
705 | } | ||
462 | kfree(dev_info); | 706 | kfree(dev_info); |
463 | out: | 707 | out: |
464 | kfree(local_buf); | 708 | kfree(local_buf); |
@@ -473,6 +717,7 @@ static ssize_t | |||
473 | dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 717 | dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
474 | { | 718 | { |
475 | struct dcssblk_dev_info *dev_info; | 719 | struct dcssblk_dev_info *dev_info; |
720 | struct segment_info *entry; | ||
476 | int rc, i; | 721 | int rc, i; |
477 | char *local_buf; | 722 | char *local_buf; |
478 | 723 | ||
@@ -499,26 +744,28 @@ dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const ch | |||
499 | dev_info = dcssblk_get_device_by_name(local_buf); | 744 | dev_info = dcssblk_get_device_by_name(local_buf); |
500 | if (dev_info == NULL) { | 745 | if (dev_info == NULL) { |
501 | up_write(&dcssblk_devices_sem); | 746 | up_write(&dcssblk_devices_sem); |
502 | PRINT_WARN("Segment %s is not loaded!\n", local_buf); | 747 | PRINT_WARN("Device %s is not loaded!\n", local_buf); |
503 | rc = -ENODEV; | 748 | rc = -ENODEV; |
504 | goto out_buf; | 749 | goto out_buf; |
505 | } | 750 | } |
506 | if (atomic_read(&dev_info->use_count) != 0) { | 751 | if (atomic_read(&dev_info->use_count) != 0) { |
507 | up_write(&dcssblk_devices_sem); | 752 | up_write(&dcssblk_devices_sem); |
508 | PRINT_WARN("Segment %s is in use!\n", local_buf); | 753 | PRINT_WARN("Device %s is in use!\n", local_buf); |
509 | rc = -EBUSY; | 754 | rc = -EBUSY; |
510 | goto out_buf; | 755 | goto out_buf; |
511 | } | 756 | } |
512 | list_del(&dev_info->lh); | ||
513 | 757 | ||
758 | list_del(&dev_info->lh); | ||
514 | del_gendisk(dev_info->gd); | 759 | del_gendisk(dev_info->gd); |
515 | blk_cleanup_queue(dev_info->dcssblk_queue); | 760 | blk_cleanup_queue(dev_info->dcssblk_queue); |
516 | dev_info->gd->queue = NULL; | 761 | dev_info->gd->queue = NULL; |
517 | put_disk(dev_info->gd); | 762 | put_disk(dev_info->gd); |
518 | device_unregister(&dev_info->dev); | 763 | device_unregister(&dev_info->dev); |
519 | segment_unload(dev_info->segment_name); | 764 | |
520 | PRINT_DEBUG("Segment %s unloaded successfully\n", | 765 | /* unload all related segments */ |
521 | dev_info->segment_name); | 766 | list_for_each_entry(entry, &dev_info->seg_list, lh) |
767 | segment_unload(entry->segment_name); | ||
768 | |||
522 | put_device(&dev_info->dev); | 769 | put_device(&dev_info->dev); |
523 | up_write(&dcssblk_devices_sem); | 770 | up_write(&dcssblk_devices_sem); |
524 | 771 | ||
@@ -550,6 +797,7 @@ static int | |||
550 | dcssblk_release(struct inode *inode, struct file *filp) | 797 | dcssblk_release(struct inode *inode, struct file *filp) |
551 | { | 798 | { |
552 | struct dcssblk_dev_info *dev_info; | 799 | struct dcssblk_dev_info *dev_info; |
800 | struct segment_info *entry; | ||
553 | int rc; | 801 | int rc; |
554 | 802 | ||
555 | dev_info = inode->i_bdev->bd_disk->private_data; | 803 | dev_info = inode->i_bdev->bd_disk->private_data; |
@@ -560,9 +808,11 @@ dcssblk_release(struct inode *inode, struct file *filp) | |||
560 | down_write(&dcssblk_devices_sem); | 808 | down_write(&dcssblk_devices_sem); |
561 | if (atomic_dec_and_test(&dev_info->use_count) | 809 | if (atomic_dec_and_test(&dev_info->use_count) |
562 | && (dev_info->save_pending)) { | 810 | && (dev_info->save_pending)) { |
563 | PRINT_INFO("Segment %s became idle and is being saved now\n", | 811 | PRINT_INFO("Device %s became idle and is being saved now\n", |
564 | dev_info->segment_name); | 812 | dev_info->segment_name); |
565 | segment_save(dev_info->segment_name); | 813 | list_for_each_entry(entry, &dev_info->seg_list, lh) { |
814 | segment_save(entry->segment_name); | ||
815 | } | ||
566 | dev_info->save_pending = 0; | 816 | dev_info->save_pending = 0; |
567 | } | 817 | } |
568 | up_write(&dcssblk_devices_sem); | 818 | up_write(&dcssblk_devices_sem); |
@@ -602,7 +852,8 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) | |||
602 | case SEG_TYPE_SC: | 852 | case SEG_TYPE_SC: |
603 | /* cannot write to these segments */ | 853 | /* cannot write to these segments */ |
604 | if (bio_data_dir(bio) == WRITE) { | 854 | if (bio_data_dir(bio) == WRITE) { |
605 | PRINT_WARN("rejecting write to ro segment %s\n", dev_info->dev.bus_id); | 855 | PRINT_WARN("rejecting write to ro device %s\n", |
856 | dev_name(&dev_info->dev)); | ||
606 | goto fail; | 857 | goto fail; |
607 | } | 858 | } |
608 | } | 859 | } |
@@ -657,7 +908,7 @@ static void | |||
657 | dcssblk_check_params(void) | 908 | dcssblk_check_params(void) |
658 | { | 909 | { |
659 | int rc, i, j, k; | 910 | int rc, i, j, k; |
660 | char buf[9]; | 911 | char buf[DCSSBLK_PARM_LEN + 1]; |
661 | struct dcssblk_dev_info *dev_info; | 912 | struct dcssblk_dev_info *dev_info; |
662 | 913 | ||
663 | for (i = 0; (i < DCSSBLK_PARM_LEN) && (dcssblk_segments[i] != '\0'); | 914 | for (i = 0; (i < DCSSBLK_PARM_LEN) && (dcssblk_segments[i] != '\0'); |
@@ -665,15 +916,16 @@ dcssblk_check_params(void) | |||
665 | for (j = i; (dcssblk_segments[j] != ',') && | 916 | for (j = i; (dcssblk_segments[j] != ',') && |
666 | (dcssblk_segments[j] != '\0') && | 917 | (dcssblk_segments[j] != '\0') && |
667 | (dcssblk_segments[j] != '(') && | 918 | (dcssblk_segments[j] != '(') && |
668 | (j - i) < 8; j++) | 919 | (j < DCSSBLK_PARM_LEN); j++) |
669 | { | 920 | { |
670 | buf[j-i] = dcssblk_segments[j]; | 921 | buf[j-i] = dcssblk_segments[j]; |
671 | } | 922 | } |
672 | buf[j-i] = '\0'; | 923 | buf[j-i] = '\0'; |
673 | rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i); | 924 | rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i); |
674 | if ((rc >= 0) && (dcssblk_segments[j] == '(')) { | 925 | if ((rc >= 0) && (dcssblk_segments[j] == '(')) { |
675 | for (k = 0; buf[k] != '\0'; k++) | 926 | for (k = 0; (buf[k] != ':') && (buf[k] != '\0'); k++) |
676 | buf[k] = toupper(buf[k]); | 927 | buf[k] = toupper(buf[k]); |
928 | buf[k] = '\0'; | ||
677 | if (!strncmp(&dcssblk_segments[j], "(local)", 7)) { | 929 | if (!strncmp(&dcssblk_segments[j], "(local)", 7)) { |
678 | down_read(&dcssblk_devices_sem); | 930 | down_read(&dcssblk_devices_sem); |
679 | dev_info = dcssblk_get_device_by_name(buf); | 931 | dev_info = dcssblk_get_device_by_name(buf); |
@@ -740,10 +992,12 @@ module_exit(dcssblk_exit); | |||
740 | 992 | ||
741 | module_param_string(segments, dcssblk_segments, DCSSBLK_PARM_LEN, 0444); | 993 | module_param_string(segments, dcssblk_segments, DCSSBLK_PARM_LEN, 0444); |
742 | MODULE_PARM_DESC(segments, "Name of DCSS segment(s) to be loaded, " | 994 | MODULE_PARM_DESC(segments, "Name of DCSS segment(s) to be loaded, " |
743 | "comma-separated list, each name max. 8 chars.\n" | 995 | "comma-separated list, names in each set separated " |
744 | "Adding \"(local)\" to segment name equals echoing 0 to " | 996 | "by commas are separated by colons, each set contains " |
745 | "/sys/devices/dcssblk/<segment name>/shared after loading " | 997 | "names of contiguous segments and each name max. 8 chars.\n" |
746 | "the segment - \n" | 998 | "Adding \"(local)\" to the end of each set equals echoing 0 " |
747 | "e.g. segments=\"mydcss1,mydcss2,mydcss3(local)\""); | 999 | "to /sys/devices/dcssblk/<device name>/shared after loading " |
1000 | "the contiguous segments - \n" | ||
1001 | "e.g. segments=\"mydcss1,mydcss2:mydcss3,mydcss4(local)\""); | ||
748 | 1002 | ||
749 | MODULE_LICENSE("GPL"); | 1003 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index dd9b986389a2..03916989ed2d 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c | |||
@@ -56,6 +56,7 @@ typedef struct { | |||
56 | static xpram_device_t xpram_devices[XPRAM_MAX_DEVS]; | 56 | static xpram_device_t xpram_devices[XPRAM_MAX_DEVS]; |
57 | static unsigned int xpram_sizes[XPRAM_MAX_DEVS]; | 57 | static unsigned int xpram_sizes[XPRAM_MAX_DEVS]; |
58 | static struct gendisk *xpram_disks[XPRAM_MAX_DEVS]; | 58 | static struct gendisk *xpram_disks[XPRAM_MAX_DEVS]; |
59 | static struct request_queue *xpram_queues[XPRAM_MAX_DEVS]; | ||
59 | static unsigned int xpram_pages; | 60 | static unsigned int xpram_pages; |
60 | static int xpram_devs; | 61 | static int xpram_devs; |
61 | 62 | ||
@@ -330,18 +331,22 @@ static int __init xpram_setup_sizes(unsigned long pages) | |||
330 | return 0; | 331 | return 0; |
331 | } | 332 | } |
332 | 333 | ||
333 | static struct request_queue *xpram_queue; | ||
334 | |||
335 | static int __init xpram_setup_blkdev(void) | 334 | static int __init xpram_setup_blkdev(void) |
336 | { | 335 | { |
337 | unsigned long offset; | 336 | unsigned long offset; |
338 | int i, rc = -ENOMEM; | 337 | int i, rc = -ENOMEM; |
339 | 338 | ||
340 | for (i = 0; i < xpram_devs; i++) { | 339 | for (i = 0; i < xpram_devs; i++) { |
341 | struct gendisk *disk = alloc_disk(1); | 340 | xpram_disks[i] = alloc_disk(1); |
342 | if (!disk) | 341 | if (!xpram_disks[i]) |
342 | goto out; | ||
343 | xpram_queues[i] = blk_alloc_queue(GFP_KERNEL); | ||
344 | if (!xpram_queues[i]) { | ||
345 | put_disk(xpram_disks[i]); | ||
343 | goto out; | 346 | goto out; |
344 | xpram_disks[i] = disk; | 347 | } |
348 | blk_queue_make_request(xpram_queues[i], xpram_make_request); | ||
349 | blk_queue_hardsect_size(xpram_queues[i], 4096); | ||
345 | } | 350 | } |
346 | 351 | ||
347 | /* | 352 | /* |
@@ -352,18 +357,6 @@ static int __init xpram_setup_blkdev(void) | |||
352 | goto out; | 357 | goto out; |
353 | 358 | ||
354 | /* | 359 | /* |
355 | * Assign the other needed values: make request function, sizes and | ||
356 | * hardsect size. All the minor devices feature the same value. | ||
357 | */ | ||
358 | xpram_queue = blk_alloc_queue(GFP_KERNEL); | ||
359 | if (!xpram_queue) { | ||
360 | rc = -ENOMEM; | ||
361 | goto out_unreg; | ||
362 | } | ||
363 | blk_queue_make_request(xpram_queue, xpram_make_request); | ||
364 | blk_queue_hardsect_size(xpram_queue, 4096); | ||
365 | |||
366 | /* | ||
367 | * Setup device structures. | 360 | * Setup device structures. |
368 | */ | 361 | */ |
369 | offset = 0; | 362 | offset = 0; |
@@ -377,18 +370,18 @@ static int __init xpram_setup_blkdev(void) | |||
377 | disk->first_minor = i; | 370 | disk->first_minor = i; |
378 | disk->fops = &xpram_devops; | 371 | disk->fops = &xpram_devops; |
379 | disk->private_data = &xpram_devices[i]; | 372 | disk->private_data = &xpram_devices[i]; |
380 | disk->queue = xpram_queue; | 373 | disk->queue = xpram_queues[i]; |
381 | sprintf(disk->disk_name, "slram%d", i); | 374 | sprintf(disk->disk_name, "slram%d", i); |
382 | set_capacity(disk, xpram_sizes[i] << 1); | 375 | set_capacity(disk, xpram_sizes[i] << 1); |
383 | add_disk(disk); | 376 | add_disk(disk); |
384 | } | 377 | } |
385 | 378 | ||
386 | return 0; | 379 | return 0; |
387 | out_unreg: | ||
388 | unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); | ||
389 | out: | 380 | out: |
390 | while (i--) | 381 | while (i--) { |
382 | blk_cleanup_queue(xpram_queues[i]); | ||
391 | put_disk(xpram_disks[i]); | 383 | put_disk(xpram_disks[i]); |
384 | } | ||
392 | return rc; | 385 | return rc; |
393 | } | 386 | } |
394 | 387 | ||
@@ -400,10 +393,10 @@ static void __exit xpram_exit(void) | |||
400 | int i; | 393 | int i; |
401 | for (i = 0; i < xpram_devs; i++) { | 394 | for (i = 0; i < xpram_devs; i++) { |
402 | del_gendisk(xpram_disks[i]); | 395 | del_gendisk(xpram_disks[i]); |
396 | blk_cleanup_queue(xpram_queues[i]); | ||
403 | put_disk(xpram_disks[i]); | 397 | put_disk(xpram_disks[i]); |
404 | } | 398 | } |
405 | unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); | 399 | unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); |
406 | blk_cleanup_queue(xpram_queue); | ||
407 | } | 400 | } |
408 | 401 | ||
409 | static int __init xpram_init(void) | 402 | static int __init xpram_init(void) |