diff options
-rw-r--r-- | drivers/s390/block/dasd_alias.c | 62 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 37 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.h | 4 |
3 files changed, 89 insertions, 14 deletions
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index cdc6c049c353..fd1231738ef4 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c | |||
@@ -152,6 +152,7 @@ static struct alias_lcu *_allocate_lcu(struct dasd_uid *uid) | |||
152 | INIT_WORK(&lcu->suc_data.worker, summary_unit_check_handling_work); | 152 | INIT_WORK(&lcu->suc_data.worker, summary_unit_check_handling_work); |
153 | INIT_DELAYED_WORK(&lcu->ruac_data.dwork, lcu_update_work); | 153 | INIT_DELAYED_WORK(&lcu->ruac_data.dwork, lcu_update_work); |
154 | spin_lock_init(&lcu->lock); | 154 | spin_lock_init(&lcu->lock); |
155 | init_completion(&lcu->lcu_setup); | ||
155 | return lcu; | 156 | return lcu; |
156 | 157 | ||
157 | out_err4: | 158 | out_err4: |
@@ -240,6 +241,67 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) | |||
240 | } | 241 | } |
241 | 242 | ||
242 | /* | 243 | /* |
244 | * The first device to be registered on an LCU will have to do | ||
245 | * some additional setup steps to configure that LCU on the | ||
246 | * storage server. All further devices should wait with their | ||
247 | * initialization until the first device is done. | ||
248 | * To synchronize this work, the first device will call | ||
249 | * dasd_alias_lcu_setup_complete when it is done, and all | ||
250 | * other devices will wait for it with dasd_alias_wait_for_lcu_setup. | ||
251 | */ | ||
252 | void dasd_alias_lcu_setup_complete(struct dasd_device *device) | ||
253 | { | ||
254 | struct dasd_eckd_private *private; | ||
255 | unsigned long flags; | ||
256 | struct alias_server *server; | ||
257 | struct alias_lcu *lcu; | ||
258 | struct dasd_uid *uid; | ||
259 | |||
260 | private = (struct dasd_eckd_private *) device->private; | ||
261 | uid = &private->uid; | ||
262 | lcu = NULL; | ||
263 | spin_lock_irqsave(&aliastree.lock, flags); | ||
264 | server = _find_server(uid); | ||
265 | if (server) | ||
266 | lcu = _find_lcu(server, uid); | ||
267 | spin_unlock_irqrestore(&aliastree.lock, flags); | ||
268 | if (!lcu) { | ||
269 | DBF_EVENT_DEVID(DBF_ERR, device->cdev, | ||
270 | "could not find lcu for %04x %02x", | ||
271 | uid->ssid, uid->real_unit_addr); | ||
272 | WARN_ON(1); | ||
273 | return; | ||
274 | } | ||
275 | complete_all(&lcu->lcu_setup); | ||
276 | } | ||
277 | |||
278 | void dasd_alias_wait_for_lcu_setup(struct dasd_device *device) | ||
279 | { | ||
280 | struct dasd_eckd_private *private; | ||
281 | unsigned long flags; | ||
282 | struct alias_server *server; | ||
283 | struct alias_lcu *lcu; | ||
284 | struct dasd_uid *uid; | ||
285 | |||
286 | private = (struct dasd_eckd_private *) device->private; | ||
287 | uid = &private->uid; | ||
288 | lcu = NULL; | ||
289 | spin_lock_irqsave(&aliastree.lock, flags); | ||
290 | server = _find_server(uid); | ||
291 | if (server) | ||
292 | lcu = _find_lcu(server, uid); | ||
293 | spin_unlock_irqrestore(&aliastree.lock, flags); | ||
294 | if (!lcu) { | ||
295 | DBF_EVENT_DEVID(DBF_ERR, device->cdev, | ||
296 | "could not find lcu for %04x %02x", | ||
297 | uid->ssid, uid->real_unit_addr); | ||
298 | WARN_ON(1); | ||
299 | return; | ||
300 | } | ||
301 | wait_for_completion(&lcu->lcu_setup); | ||
302 | } | ||
303 | |||
304 | /* | ||
243 | * This function removes a device from the scope of alias management. | 305 | * This function removes a device from the scope of alias management. |
244 | * The complicated part is to make sure that it is not in use by | 306 | * The complicated part is to make sure that it is not in use by |
245 | * any of the workers. If necessary cancel the work. | 307 | * any of the workers. If necessary cancel the work. |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index e38a09b5feae..5819dc02a143 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -1059,7 +1059,7 @@ dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav) | |||
1059 | /* | 1059 | /* |
1060 | * Valide storage server of current device. | 1060 | * Valide storage server of current device. |
1061 | */ | 1061 | */ |
1062 | static int dasd_eckd_validate_server(struct dasd_device *device) | 1062 | static void dasd_eckd_validate_server(struct dasd_device *device) |
1063 | { | 1063 | { |
1064 | int rc; | 1064 | int rc; |
1065 | struct dasd_eckd_private *private; | 1065 | struct dasd_eckd_private *private; |
@@ -1076,8 +1076,6 @@ static int dasd_eckd_validate_server(struct dasd_device *device) | |||
1076 | private = (struct dasd_eckd_private *) device->private; | 1076 | private = (struct dasd_eckd_private *) device->private; |
1077 | DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "PSF-SSC for SSID %04x " | 1077 | DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "PSF-SSC for SSID %04x " |
1078 | "returned rc=%d", private->uid.ssid, rc); | 1078 | "returned rc=%d", private->uid.ssid, rc); |
1079 | /* RE-Read Configuration Data */ | ||
1080 | return dasd_eckd_read_conf(device); | ||
1081 | } | 1079 | } |
1082 | 1080 | ||
1083 | /* | 1081 | /* |
@@ -1149,12 +1147,21 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
1149 | rc = is_known; | 1147 | rc = is_known; |
1150 | goto out_err2; | 1148 | goto out_err2; |
1151 | } | 1149 | } |
1150 | /* | ||
1151 | * dasd_eckd_vaildate_server is done on the first device that | ||
1152 | * is found for an LCU. All later other devices have to wait | ||
1153 | * for it, so they will read the correct feature codes. | ||
1154 | */ | ||
1152 | if (!is_known) { | 1155 | if (!is_known) { |
1153 | /* new lcu found */ | 1156 | dasd_eckd_validate_server(device); |
1154 | rc = dasd_eckd_validate_server(device); /* will switch pav on */ | 1157 | dasd_alias_lcu_setup_complete(device); |
1155 | if (rc) | 1158 | } else |
1156 | goto out_err3; | 1159 | dasd_alias_wait_for_lcu_setup(device); |
1157 | } | 1160 | |
1161 | /* device may report different configuration data after LCU setup */ | ||
1162 | rc = dasd_eckd_read_conf(device); | ||
1163 | if (rc) | ||
1164 | goto out_err3; | ||
1158 | 1165 | ||
1159 | /* Read Feature Codes */ | 1166 | /* Read Feature Codes */ |
1160 | dasd_eckd_read_features(device); | 1167 | dasd_eckd_read_features(device); |
@@ -3282,11 +3289,15 @@ int dasd_eckd_restore_device(struct dasd_device *device) | |||
3282 | if (is_known < 0) | 3289 | if (is_known < 0) |
3283 | return is_known; | 3290 | return is_known; |
3284 | if (!is_known) { | 3291 | if (!is_known) { |
3285 | /* new lcu found */ | 3292 | dasd_eckd_validate_server(device); |
3286 | rc = dasd_eckd_validate_server(device); /* will switch pav on */ | 3293 | dasd_alias_lcu_setup_complete(device); |
3287 | if (rc) | 3294 | } else |
3288 | goto out_err; | 3295 | dasd_alias_wait_for_lcu_setup(device); |
3289 | } | 3296 | |
3297 | /* RE-Read Configuration Data */ | ||
3298 | rc = dasd_eckd_read_conf(device); | ||
3299 | if (rc) | ||
3300 | goto out_err; | ||
3290 | 3301 | ||
3291 | /* Read Feature Codes */ | 3302 | /* Read Feature Codes */ |
3292 | dasd_eckd_read_features(device); | 3303 | dasd_eckd_read_features(device); |
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index ad45bcac3ce4..864d53c04201 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h | |||
@@ -414,6 +414,7 @@ struct alias_lcu { | |||
414 | struct summary_unit_check_work_data suc_data; | 414 | struct summary_unit_check_work_data suc_data; |
415 | struct read_uac_work_data ruac_data; | 415 | struct read_uac_work_data ruac_data; |
416 | struct dasd_ccw_req *rsu_cqr; | 416 | struct dasd_ccw_req *rsu_cqr; |
417 | struct completion lcu_setup; | ||
417 | }; | 418 | }; |
418 | 419 | ||
419 | struct alias_pav_group { | 420 | struct alias_pav_group { |
@@ -460,5 +461,6 @@ int dasd_alias_remove_device(struct dasd_device *); | |||
460 | struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *); | 461 | struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *); |
461 | void dasd_alias_handle_summary_unit_check(struct dasd_device *, struct irb *); | 462 | void dasd_alias_handle_summary_unit_check(struct dasd_device *, struct irb *); |
462 | void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *); | 463 | void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *); |
463 | 464 | void dasd_alias_lcu_setup_complete(struct dasd_device *); | |
465 | void dasd_alias_wait_for_lcu_setup(struct dasd_device *); | ||
464 | #endif /* DASD_ECKD_H */ | 466 | #endif /* DASD_ECKD_H */ |