diff options
Diffstat (limited to 'drivers/s390/block/dasd_alias.c')
-rw-r--r-- | drivers/s390/block/dasd_alias.c | 62 |
1 files changed, 62 insertions, 0 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. |