aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block
diff options
context:
space:
mode:
authorStefan Weinhuber <wein@de.ibm.com>2009-12-07 06:51:53 -0500
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2009-12-07 06:51:35 -0500
commitf4ac1d0255748fe0f8e128a26b1c29490cae5c08 (patch)
tree2e5e9c31f32194c1042440bce54301e86125f142 /drivers/s390/block
parentb8ed5dd54895647c2690575aad6f07748c2c618a (diff)
[S390] dasd: let device initialization wait for LCU setup
The first DASD that is set online for a specific logical control unit has to do certain setup steps on the storage server to make full use of it, for example it will enable PAV. The features and characteristics reported by the storage server will depend on this setup, so all other devices on the same LCU will need to wait for the setup to be finished. Signed-off-by: Stefan Weinhuber <wein@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/block')
-rw-r--r--drivers/s390/block/dasd_alias.c62
-rw-r--r--drivers/s390/block/dasd_eckd.c37
-rw-r--r--drivers/s390/block/dasd_eckd.h4
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
157out_err4: 158out_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 */
252void 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
278void 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 */
1062static int dasd_eckd_validate_server(struct dasd_device *device) 1062static 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
419struct alias_pav_group { 420struct alias_pav_group {
@@ -460,5 +461,6 @@ int dasd_alias_remove_device(struct dasd_device *);
460struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *); 461struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *);
461void dasd_alias_handle_summary_unit_check(struct dasd_device *, struct irb *); 462void dasd_alias_handle_summary_unit_check(struct dasd_device *, struct irb *);
462void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *); 463void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *);
463 464void dasd_alias_lcu_setup_complete(struct dasd_device *);
465void dasd_alias_wait_for_lcu_setup(struct dasd_device *);
464#endif /* DASD_ECKD_H */ 466#endif /* DASD_ECKD_H */