974 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * PAV alias management for the DASD ECKD discipline4 *5 * Copyright IBM Corp. 20076 * Author(s): Stefan Weinhuber <wein@de.ibm.com>7 */8 9#include <linux/list.h>10#include <linux/slab.h>11#include <asm/ebcdic.h>12#include "dasd_int.h"13#include "dasd_eckd.h"14 15/*16 * General concept of alias management:17 * - PAV and DASD alias management is specific to the eckd discipline.18 * - A device is connected to an lcu as long as the device exists.19 * dasd_alias_make_device_known_to_lcu will be called wenn the20 * device is checked by the eckd discipline and21 * dasd_alias_disconnect_device_from_lcu will be called22 * before the device is deleted.23 * - The dasd_alias_add_device / dasd_alias_remove_device24 * functions mark the point when a device is 'ready for service'.25 * - A summary unit check is a rare occasion, but it is mandatory to26 * support it. It requires some complex recovery actions before the27 * devices can be used again (see dasd_alias_handle_summary_unit_check).28 * - dasd_alias_get_start_dev will find an alias device that can be used29 * instead of the base device and does some (very simple) load balancing.30 * This is the function that gets called for each I/O, so when improving31 * something, this function should get faster or better, the rest has just32 * to be correct.33 */34 35 36static void summary_unit_check_handling_work(struct work_struct *);37static void lcu_update_work(struct work_struct *);38static int _schedule_lcu_update(struct alias_lcu *, struct dasd_device *);39 40static struct alias_root aliastree = {41 .serverlist = LIST_HEAD_INIT(aliastree.serverlist),42 .lock = __SPIN_LOCK_UNLOCKED(aliastree.lock),43};44 45static struct alias_server *_find_server(struct dasd_uid *uid)46{47 struct alias_server *pos;48 list_for_each_entry(pos, &aliastree.serverlist, server) {49 if (!strncmp(pos->uid.vendor, uid->vendor,50 sizeof(uid->vendor))51 && !strncmp(pos->uid.serial, uid->serial,52 sizeof(uid->serial)))53 return pos;54 }55 return NULL;56}57 58static struct alias_lcu *_find_lcu(struct alias_server *server,59 struct dasd_uid *uid)60{61 struct alias_lcu *pos;62 list_for_each_entry(pos, &server->lculist, lcu) {63 if (pos->uid.ssid == uid->ssid)64 return pos;65 }66 return NULL;67}68 69static struct alias_pav_group *_find_group(struct alias_lcu *lcu,70 struct dasd_uid *uid)71{72 struct alias_pav_group *pos;73 __u8 search_unit_addr;74 75 /* for hyper pav there is only one group */76 if (lcu->pav == HYPER_PAV) {77 if (list_empty(&lcu->grouplist))78 return NULL;79 else80 return list_first_entry(&lcu->grouplist,81 struct alias_pav_group, group);82 }83 84 /* for base pav we have to find the group that matches the base */85 if (uid->type == UA_BASE_DEVICE)86 search_unit_addr = uid->real_unit_addr;87 else88 search_unit_addr = uid->base_unit_addr;89 list_for_each_entry(pos, &lcu->grouplist, group) {90 if (pos->uid.base_unit_addr == search_unit_addr &&91 !strncmp(pos->uid.vduit, uid->vduit, sizeof(uid->vduit)))92 return pos;93 }94 return NULL;95}96 97static struct alias_server *_allocate_server(struct dasd_uid *uid)98{99 struct alias_server *server;100 101 server = kzalloc(sizeof(*server), GFP_KERNEL);102 if (!server)103 return ERR_PTR(-ENOMEM);104 memcpy(server->uid.vendor, uid->vendor, sizeof(uid->vendor));105 memcpy(server->uid.serial, uid->serial, sizeof(uid->serial));106 INIT_LIST_HEAD(&server->server);107 INIT_LIST_HEAD(&server->lculist);108 return server;109}110 111static void _free_server(struct alias_server *server)112{113 kfree(server);114}115 116static struct alias_lcu *_allocate_lcu(struct dasd_uid *uid)117{118 struct alias_lcu *lcu;119 120 lcu = kzalloc(sizeof(*lcu), GFP_KERNEL);121 if (!lcu)122 return ERR_PTR(-ENOMEM);123 lcu->uac = kzalloc(sizeof(*(lcu->uac)), GFP_KERNEL | GFP_DMA);124 if (!lcu->uac)125 goto out_err1;126 lcu->rsu_cqr = kzalloc(sizeof(*lcu->rsu_cqr), GFP_KERNEL | GFP_DMA);127 if (!lcu->rsu_cqr)128 goto out_err2;129 lcu->rsu_cqr->cpaddr = kzalloc(sizeof(struct ccw1),130 GFP_KERNEL | GFP_DMA);131 if (!lcu->rsu_cqr->cpaddr)132 goto out_err3;133 lcu->rsu_cqr->data = kzalloc(16, GFP_KERNEL | GFP_DMA);134 if (!lcu->rsu_cqr->data)135 goto out_err4;136 137 memcpy(lcu->uid.vendor, uid->vendor, sizeof(uid->vendor));138 memcpy(lcu->uid.serial, uid->serial, sizeof(uid->serial));139 lcu->uid.ssid = uid->ssid;140 lcu->pav = NO_PAV;141 lcu->flags = NEED_UAC_UPDATE | UPDATE_PENDING;142 INIT_LIST_HEAD(&lcu->lcu);143 INIT_LIST_HEAD(&lcu->inactive_devices);144 INIT_LIST_HEAD(&lcu->active_devices);145 INIT_LIST_HEAD(&lcu->grouplist);146 INIT_WORK(&lcu->suc_data.worker, summary_unit_check_handling_work);147 INIT_DELAYED_WORK(&lcu->ruac_data.dwork, lcu_update_work);148 spin_lock_init(&lcu->lock);149 init_completion(&lcu->lcu_setup);150 return lcu;151 152out_err4:153 kfree(lcu->rsu_cqr->cpaddr);154out_err3:155 kfree(lcu->rsu_cqr);156out_err2:157 kfree(lcu->uac);158out_err1:159 kfree(lcu);160 return ERR_PTR(-ENOMEM);161}162 163static void _free_lcu(struct alias_lcu *lcu)164{165 kfree(lcu->rsu_cqr->data);166 kfree(lcu->rsu_cqr->cpaddr);167 kfree(lcu->rsu_cqr);168 kfree(lcu->uac);169 kfree(lcu);170}171 172/*173 * This is the function that will allocate all the server and lcu data,174 * so this function must be called first for a new device.175 * If the return value is 1, the lcu was already known before, if it176 * is 0, this is a new lcu.177 * Negative return code indicates that something went wrong (e.g. -ENOMEM)178 */179int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)180{181 struct dasd_eckd_private *private = device->private;182 unsigned long flags;183 struct alias_server *server, *newserver;184 struct alias_lcu *lcu, *newlcu;185 struct dasd_uid uid;186 187 device->discipline->get_uid(device, &uid);188 spin_lock_irqsave(&aliastree.lock, flags);189 server = _find_server(&uid);190 if (!server) {191 spin_unlock_irqrestore(&aliastree.lock, flags);192 newserver = _allocate_server(&uid);193 if (IS_ERR(newserver))194 return PTR_ERR(newserver);195 spin_lock_irqsave(&aliastree.lock, flags);196 server = _find_server(&uid);197 if (!server) {198 list_add(&newserver->server, &aliastree.serverlist);199 server = newserver;200 } else {201 /* someone was faster */202 _free_server(newserver);203 }204 }205 206 lcu = _find_lcu(server, &uid);207 if (!lcu) {208 spin_unlock_irqrestore(&aliastree.lock, flags);209 newlcu = _allocate_lcu(&uid);210 if (IS_ERR(newlcu))211 return PTR_ERR(newlcu);212 spin_lock_irqsave(&aliastree.lock, flags);213 lcu = _find_lcu(server, &uid);214 if (!lcu) {215 list_add(&newlcu->lcu, &server->lculist);216 lcu = newlcu;217 } else {218 /* someone was faster */219 _free_lcu(newlcu);220 }221 }222 spin_lock(&lcu->lock);223 list_add(&device->alias_list, &lcu->inactive_devices);224 private->lcu = lcu;225 spin_unlock(&lcu->lock);226 spin_unlock_irqrestore(&aliastree.lock, flags);227 228 return 0;229}230 231/*232 * This function removes a device from the scope of alias management.233 * The complicated part is to make sure that it is not in use by234 * any of the workers. If necessary cancel the work.235 */236void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)237{238 struct dasd_eckd_private *private = device->private;239 unsigned long flags;240 struct alias_lcu *lcu;241 struct alias_server *server;242 int was_pending;243 struct dasd_uid uid;244 245 lcu = private->lcu;246 /* nothing to do if already disconnected */247 if (!lcu)248 return;249 device->discipline->get_uid(device, &uid);250 spin_lock_irqsave(&lcu->lock, flags);251 /* make sure that the workers don't use this device */252 if (device == lcu->suc_data.device) {253 spin_unlock_irqrestore(&lcu->lock, flags);254 cancel_work_sync(&lcu->suc_data.worker);255 spin_lock_irqsave(&lcu->lock, flags);256 if (device == lcu->suc_data.device) {257 dasd_put_device(device);258 lcu->suc_data.device = NULL;259 }260 }261 was_pending = 0;262 if (device == lcu->ruac_data.device) {263 spin_unlock_irqrestore(&lcu->lock, flags);264 was_pending = 1;265 cancel_delayed_work_sync(&lcu->ruac_data.dwork);266 spin_lock_irqsave(&lcu->lock, flags);267 if (device == lcu->ruac_data.device) {268 dasd_put_device(device);269 lcu->ruac_data.device = NULL;270 }271 }272 private->lcu = NULL;273 spin_unlock_irqrestore(&lcu->lock, flags);274 275 spin_lock_irqsave(&aliastree.lock, flags);276 spin_lock(&lcu->lock);277 list_del_init(&device->alias_list);278 if (list_empty(&lcu->grouplist) &&279 list_empty(&lcu->active_devices) &&280 list_empty(&lcu->inactive_devices)) {281 list_del(&lcu->lcu);282 spin_unlock(&lcu->lock);283 _free_lcu(lcu);284 lcu = NULL;285 } else {286 if (was_pending)287 _schedule_lcu_update(lcu, NULL);288 spin_unlock(&lcu->lock);289 }290 server = _find_server(&uid);291 if (server && list_empty(&server->lculist)) {292 list_del(&server->server);293 _free_server(server);294 }295 spin_unlock_irqrestore(&aliastree.lock, flags);296}297 298/*299 * This function assumes that the unit address configuration stored300 * in the lcu is up to date and will update the device uid before301 * adding it to a pav group.302 */303 304static int _add_device_to_lcu(struct alias_lcu *lcu,305 struct dasd_device *device,306 struct dasd_device *pos)307{308 309 struct dasd_eckd_private *private = device->private;310 struct alias_pav_group *group;311 struct dasd_uid uid;312 313 spin_lock(get_ccwdev_lock(device->cdev));314 private->uid.type = lcu->uac->unit[private->uid.real_unit_addr].ua_type;315 private->uid.base_unit_addr =316 lcu->uac->unit[private->uid.real_unit_addr].base_ua;317 uid = private->uid;318 spin_unlock(get_ccwdev_lock(device->cdev));319 /* if we have no PAV anyway, we don't need to bother with PAV groups */320 if (lcu->pav == NO_PAV) {321 list_move(&device->alias_list, &lcu->active_devices);322 return 0;323 }324 group = _find_group(lcu, &uid);325 if (!group) {326 group = kzalloc(sizeof(*group), GFP_ATOMIC);327 if (!group)328 return -ENOMEM;329 memcpy(group->uid.vendor, uid.vendor, sizeof(uid.vendor));330 memcpy(group->uid.serial, uid.serial, sizeof(uid.serial));331 group->uid.ssid = uid.ssid;332 if (uid.type == UA_BASE_DEVICE)333 group->uid.base_unit_addr = uid.real_unit_addr;334 else335 group->uid.base_unit_addr = uid.base_unit_addr;336 memcpy(group->uid.vduit, uid.vduit, sizeof(uid.vduit));337 INIT_LIST_HEAD(&group->group);338 INIT_LIST_HEAD(&group->baselist);339 INIT_LIST_HEAD(&group->aliaslist);340 list_add(&group->group, &lcu->grouplist);341 }342 if (uid.type == UA_BASE_DEVICE)343 list_move(&device->alias_list, &group->baselist);344 else345 list_move(&device->alias_list, &group->aliaslist);346 private->pavgroup = group;347 return 0;348};349 350static void _remove_device_from_lcu(struct alias_lcu *lcu,351 struct dasd_device *device)352{353 struct dasd_eckd_private *private = device->private;354 struct alias_pav_group *group;355 356 list_move(&device->alias_list, &lcu->inactive_devices);357 group = private->pavgroup;358 if (!group)359 return;360 private->pavgroup = NULL;361 if (list_empty(&group->baselist) && list_empty(&group->aliaslist)) {362 list_del(&group->group);363 kfree(group);364 return;365 }366 if (group->next == device)367 group->next = NULL;368};369 370static int371suborder_not_supported(struct dasd_ccw_req *cqr)372{373 char *sense;374 char reason;375 char msg_format;376 char msg_no;377 378 /*379 * intrc values ENODEV, ENOLINK and EPERM380 * will be optained from sleep_on to indicate that no381 * IO operation can be started382 */383 if (cqr->intrc == -ENODEV)384 return 1;385 386 if (cqr->intrc == -ENOLINK)387 return 1;388 389 if (cqr->intrc == -EPERM)390 return 1;391 392 sense = dasd_get_sense(&cqr->irb);393 if (!sense)394 return 0;395 396 reason = sense[0];397 msg_format = (sense[7] & 0xF0);398 msg_no = (sense[7] & 0x0F);399 400 /* command reject, Format 0 MSG 4 - invalid parameter */401 if ((reason == 0x80) && (msg_format == 0x00) && (msg_no == 0x04))402 return 1;403 404 return 0;405}406 407static int read_unit_address_configuration(struct dasd_device *device,408 struct alias_lcu *lcu)409{410 struct dasd_psf_prssd_data *prssdp;411 struct dasd_ccw_req *cqr;412 struct ccw1 *ccw;413 int rc;414 unsigned long flags;415 416 cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */,417 (sizeof(struct dasd_psf_prssd_data)),418 device, NULL);419 if (IS_ERR(cqr))420 return PTR_ERR(cqr);421 cqr->startdev = device;422 cqr->memdev = device;423 clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);424 cqr->retries = 10;425 cqr->expires = 20 * HZ;426 427 /* Prepare for Read Subsystem Data */428 prssdp = (struct dasd_psf_prssd_data *) cqr->data;429 memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));430 prssdp->order = PSF_ORDER_PRSSD;431 prssdp->suborder = 0x0e; /* Read unit address configuration */432 /* all other bytes of prssdp must be zero */433 434 ccw = cqr->cpaddr;435 ccw->cmd_code = DASD_ECKD_CCW_PSF;436 ccw->count = sizeof(struct dasd_psf_prssd_data);437 ccw->flags |= CCW_FLAG_CC;438 ccw->cda = virt_to_dma32(prssdp);439 440 /* Read Subsystem Data - feature codes */441 memset(lcu->uac, 0, sizeof(*(lcu->uac)));442 443 ccw++;444 ccw->cmd_code = DASD_ECKD_CCW_RSSD;445 ccw->count = sizeof(*(lcu->uac));446 ccw->cda = virt_to_dma32(lcu->uac);447 448 cqr->buildclk = get_tod_clock();449 cqr->status = DASD_CQR_FILLED;450 451 /* need to unset flag here to detect race with summary unit check */452 spin_lock_irqsave(&lcu->lock, flags);453 lcu->flags &= ~NEED_UAC_UPDATE;454 spin_unlock_irqrestore(&lcu->lock, flags);455 456 rc = dasd_sleep_on(cqr);457 if (!rc)458 goto out;459 460 if (suborder_not_supported(cqr)) {461 /* suborder not supported or device unusable for IO */462 rc = -EOPNOTSUPP;463 } else {464 /* IO failed but should be retried */465 spin_lock_irqsave(&lcu->lock, flags);466 lcu->flags |= NEED_UAC_UPDATE;467 spin_unlock_irqrestore(&lcu->lock, flags);468 }469out:470 dasd_sfree_request(cqr, cqr->memdev);471 return rc;472}473 474static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu)475{476 unsigned long flags;477 struct alias_pav_group *pavgroup, *tempgroup;478 struct dasd_device *device, *tempdev;479 int i, rc;480 struct dasd_eckd_private *private;481 482 spin_lock_irqsave(&lcu->lock, flags);483 list_for_each_entry_safe(pavgroup, tempgroup, &lcu->grouplist, group) {484 list_for_each_entry_safe(device, tempdev, &pavgroup->baselist,485 alias_list) {486 list_move(&device->alias_list, &lcu->active_devices);487 private = device->private;488 private->pavgroup = NULL;489 }490 list_for_each_entry_safe(device, tempdev, &pavgroup->aliaslist,491 alias_list) {492 list_move(&device->alias_list, &lcu->active_devices);493 private = device->private;494 private->pavgroup = NULL;495 }496 list_del(&pavgroup->group);497 kfree(pavgroup);498 }499 spin_unlock_irqrestore(&lcu->lock, flags);500 501 rc = read_unit_address_configuration(refdev, lcu);502 if (rc)503 return rc;504 505 spin_lock_irqsave(&lcu->lock, flags);506 /*507 * there is another update needed skip the remaining handling508 * the data might already be outdated509 * but especially do not add the device to an LCU with pending510 * update511 */512 if (lcu->flags & NEED_UAC_UPDATE)513 goto out;514 lcu->pav = NO_PAV;515 for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) {516 switch (lcu->uac->unit[i].ua_type) {517 case UA_BASE_PAV_ALIAS:518 lcu->pav = BASE_PAV;519 break;520 case UA_HYPER_PAV_ALIAS:521 lcu->pav = HYPER_PAV;522 break;523 }524 if (lcu->pav != NO_PAV)525 break;526 }527 528 list_for_each_entry_safe(device, tempdev, &lcu->active_devices,529 alias_list) {530 _add_device_to_lcu(lcu, device, refdev);531 }532out:533 spin_unlock_irqrestore(&lcu->lock, flags);534 return 0;535}536 537static void lcu_update_work(struct work_struct *work)538{539 struct alias_lcu *lcu;540 struct read_uac_work_data *ruac_data;541 struct dasd_device *device;542 unsigned long flags;543 int rc;544 545 ruac_data = container_of(work, struct read_uac_work_data, dwork.work);546 lcu = container_of(ruac_data, struct alias_lcu, ruac_data);547 device = ruac_data->device;548 rc = _lcu_update(device, lcu);549 /*550 * Need to check flags again, as there could have been another551 * prepare_update or a new device a new device while we were still552 * processing the data553 */554 spin_lock_irqsave(&lcu->lock, flags);555 if ((rc && (rc != -EOPNOTSUPP)) || (lcu->flags & NEED_UAC_UPDATE)) {556 DBF_DEV_EVENT(DBF_WARNING, device, "could not update"557 " alias data in lcu (rc = %d), retry later", rc);558 if (!schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ))559 dasd_put_device(device);560 } else {561 dasd_put_device(device);562 lcu->ruac_data.device = NULL;563 lcu->flags &= ~UPDATE_PENDING;564 }565 spin_unlock_irqrestore(&lcu->lock, flags);566}567 568static int _schedule_lcu_update(struct alias_lcu *lcu,569 struct dasd_device *device)570{571 struct dasd_device *usedev = NULL;572 struct alias_pav_group *group;573 574 lcu->flags |= NEED_UAC_UPDATE;575 if (lcu->ruac_data.device) {576 /* already scheduled or running */577 return 0;578 }579 if (device && !list_empty(&device->alias_list))580 usedev = device;581 582 if (!usedev && !list_empty(&lcu->grouplist)) {583 group = list_first_entry(&lcu->grouplist,584 struct alias_pav_group, group);585 if (!list_empty(&group->baselist))586 usedev = list_first_entry(&group->baselist,587 struct dasd_device,588 alias_list);589 else if (!list_empty(&group->aliaslist))590 usedev = list_first_entry(&group->aliaslist,591 struct dasd_device,592 alias_list);593 }594 if (!usedev && !list_empty(&lcu->active_devices)) {595 usedev = list_first_entry(&lcu->active_devices,596 struct dasd_device, alias_list);597 }598 /*599 * if we haven't found a proper device yet, give up for now, the next600 * device that will be set active will trigger an lcu update601 */602 if (!usedev)603 return -EINVAL;604 dasd_get_device(usedev);605 lcu->ruac_data.device = usedev;606 if (!schedule_delayed_work(&lcu->ruac_data.dwork, 0))607 dasd_put_device(usedev);608 return 0;609}610 611int dasd_alias_add_device(struct dasd_device *device)612{613 struct dasd_eckd_private *private = device->private;614 __u8 uaddr = private->uid.real_unit_addr;615 struct alias_lcu *lcu = private->lcu;616 unsigned long flags;617 int rc;618 619 rc = 0;620 spin_lock_irqsave(&lcu->lock, flags);621 /*622 * Check if device and lcu type differ. If so, the uac data may be623 * outdated and needs to be updated.624 */625 if (private->uid.type != lcu->uac->unit[uaddr].ua_type) {626 lcu->flags |= UPDATE_PENDING;627 DBF_DEV_EVENT(DBF_WARNING, device, "%s",628 "uid type mismatch - trigger rescan");629 }630 if (!(lcu->flags & UPDATE_PENDING)) {631 rc = _add_device_to_lcu(lcu, device, device);632 if (rc)633 lcu->flags |= UPDATE_PENDING;634 }635 if (lcu->flags & UPDATE_PENDING) {636 list_move(&device->alias_list, &lcu->active_devices);637 private->pavgroup = NULL;638 _schedule_lcu_update(lcu, device);639 }640 spin_unlock_irqrestore(&lcu->lock, flags);641 return rc;642}643 644int dasd_alias_update_add_device(struct dasd_device *device)645{646 struct dasd_eckd_private *private = device->private;647 648 private->lcu->flags |= UPDATE_PENDING;649 return dasd_alias_add_device(device);650}651 652int dasd_alias_remove_device(struct dasd_device *device)653{654 struct dasd_eckd_private *private = device->private;655 struct alias_lcu *lcu = private->lcu;656 unsigned long flags;657 658 /* nothing to do if already removed */659 if (!lcu)660 return 0;661 spin_lock_irqsave(&lcu->lock, flags);662 _remove_device_from_lcu(lcu, device);663 spin_unlock_irqrestore(&lcu->lock, flags);664 return 0;665}666 667struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device)668{669 struct dasd_eckd_private *alias_priv, *private = base_device->private;670 struct alias_lcu *lcu = private->lcu;671 struct dasd_device *alias_device;672 struct alias_pav_group *group;673 unsigned long flags;674 675 if (!lcu)676 return NULL;677 if (lcu->pav == NO_PAV ||678 lcu->flags & (NEED_UAC_UPDATE | UPDATE_PENDING))679 return NULL;680 if (unlikely(!(private->features.feature[8] & 0x01))) {681 /*682 * PAV enabled but prefix not, very unlikely683 * seems to be a lost pathgroup684 * use base device to do IO685 */686 DBF_DEV_EVENT(DBF_ERR, base_device, "%s",687 "Prefix not enabled with PAV enabled\n");688 return NULL;689 }690 691 spin_lock_irqsave(&lcu->lock, flags);692 group = private->pavgroup;693 if (!group) {694 spin_unlock_irqrestore(&lcu->lock, flags);695 return NULL;696 }697 alias_device = group->next;698 if (!alias_device) {699 if (list_empty(&group->aliaslist)) {700 spin_unlock_irqrestore(&lcu->lock, flags);701 return NULL;702 } else {703 alias_device = list_first_entry(&group->aliaslist,704 struct dasd_device,705 alias_list);706 }707 }708 if (list_is_last(&alias_device->alias_list, &group->aliaslist))709 group->next = list_first_entry(&group->aliaslist,710 struct dasd_device, alias_list);711 else712 group->next = list_first_entry(&alias_device->alias_list,713 struct dasd_device, alias_list);714 spin_unlock_irqrestore(&lcu->lock, flags);715 alias_priv = alias_device->private;716 if ((alias_priv->count < private->count) && !alias_device->stopped &&717 !test_bit(DASD_FLAG_OFFLINE, &alias_device->flags))718 return alias_device;719 else720 return NULL;721}722 723/*724 * Summary unit check handling depends on the way alias devices725 * are handled so it is done here rather then in dasd_eckd.c726 */727static int reset_summary_unit_check(struct alias_lcu *lcu,728 struct dasd_device *device,729 char reason)730{731 struct dasd_ccw_req *cqr;732 int rc = 0;733 struct ccw1 *ccw;734 735 cqr = lcu->rsu_cqr;736 memcpy((char *) &cqr->magic, "ECKD", 4);737 ASCEBC((char *) &cqr->magic, 4);738 ccw = cqr->cpaddr;739 ccw->cmd_code = DASD_ECKD_CCW_RSCK;740 ccw->flags = CCW_FLAG_SLI;741 ccw->count = 16;742 ccw->cda = virt_to_dma32(cqr->data);743 ((char *)cqr->data)[0] = reason;744 745 clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);746 cqr->retries = 255; /* set retry counter to enable basic ERP */747 cqr->startdev = device;748 cqr->memdev = device;749 cqr->block = NULL;750 cqr->expires = 5 * HZ;751 cqr->buildclk = get_tod_clock();752 cqr->status = DASD_CQR_FILLED;753 754 rc = dasd_sleep_on_immediatly(cqr);755 return rc;756}757 758static void _restart_all_base_devices_on_lcu(struct alias_lcu *lcu)759{760 struct alias_pav_group *pavgroup;761 struct dasd_device *device;762 struct dasd_eckd_private *private;763 764 /* active and inactive list can contain alias as well as base devices */765 list_for_each_entry(device, &lcu->active_devices, alias_list) {766 private = device->private;767 if (private->uid.type != UA_BASE_DEVICE)768 continue;769 dasd_schedule_block_bh(device->block);770 dasd_schedule_device_bh(device);771 }772 list_for_each_entry(device, &lcu->inactive_devices, alias_list) {773 private = device->private;774 if (private->uid.type != UA_BASE_DEVICE)775 continue;776 dasd_schedule_block_bh(device->block);777 dasd_schedule_device_bh(device);778 }779 list_for_each_entry(pavgroup, &lcu->grouplist, group) {780 list_for_each_entry(device, &pavgroup->baselist, alias_list) {781 dasd_schedule_block_bh(device->block);782 dasd_schedule_device_bh(device);783 }784 }785}786 787static void flush_all_alias_devices_on_lcu(struct alias_lcu *lcu)788{789 struct alias_pav_group *pavgroup;790 struct dasd_device *device, *temp;791 struct dasd_eckd_private *private;792 unsigned long flags;793 LIST_HEAD(active);794 795 /*796 * Problem here ist that dasd_flush_device_queue may wait797 * for termination of a request to complete. We can't keep798 * the lcu lock during that time, so we must assume that799 * the lists may have changed.800 * Idea: first gather all active alias devices in a separate list,801 * then flush the first element of this list unlocked, and afterwards802 * check if it is still on the list before moving it to the803 * active_devices list.804 */805 806 spin_lock_irqsave(&lcu->lock, flags);807 list_for_each_entry_safe(device, temp, &lcu->active_devices,808 alias_list) {809 private = device->private;810 if (private->uid.type == UA_BASE_DEVICE)811 continue;812 list_move(&device->alias_list, &active);813 }814 815 list_for_each_entry(pavgroup, &lcu->grouplist, group) {816 list_splice_init(&pavgroup->aliaslist, &active);817 }818 while (!list_empty(&active)) {819 device = list_first_entry(&active, struct dasd_device,820 alias_list);821 spin_unlock_irqrestore(&lcu->lock, flags);822 dasd_flush_device_queue(device);823 spin_lock_irqsave(&lcu->lock, flags);824 /*825 * only move device around if it wasn't moved away while we826 * were waiting for the flush827 */828 if (device == list_first_entry(&active,829 struct dasd_device, alias_list)) {830 list_move(&device->alias_list, &lcu->active_devices);831 private = device->private;832 private->pavgroup = NULL;833 }834 }835 spin_unlock_irqrestore(&lcu->lock, flags);836}837 838static void _stop_all_devices_on_lcu(struct alias_lcu *lcu)839{840 struct alias_pav_group *pavgroup;841 struct dasd_device *device;842 843 list_for_each_entry(device, &lcu->active_devices, alias_list) {844 spin_lock(get_ccwdev_lock(device->cdev));845 dasd_device_set_stop_bits(device, DASD_STOPPED_SU);846 spin_unlock(get_ccwdev_lock(device->cdev));847 }848 list_for_each_entry(device, &lcu->inactive_devices, alias_list) {849 spin_lock(get_ccwdev_lock(device->cdev));850 dasd_device_set_stop_bits(device, DASD_STOPPED_SU);851 spin_unlock(get_ccwdev_lock(device->cdev));852 }853 list_for_each_entry(pavgroup, &lcu->grouplist, group) {854 list_for_each_entry(device, &pavgroup->baselist, alias_list) {855 spin_lock(get_ccwdev_lock(device->cdev));856 dasd_device_set_stop_bits(device, DASD_STOPPED_SU);857 spin_unlock(get_ccwdev_lock(device->cdev));858 }859 list_for_each_entry(device, &pavgroup->aliaslist, alias_list) {860 spin_lock(get_ccwdev_lock(device->cdev));861 dasd_device_set_stop_bits(device, DASD_STOPPED_SU);862 spin_unlock(get_ccwdev_lock(device->cdev));863 }864 }865}866 867static void _unstop_all_devices_on_lcu(struct alias_lcu *lcu)868{869 struct alias_pav_group *pavgroup;870 struct dasd_device *device;871 872 list_for_each_entry(device, &lcu->active_devices, alias_list) {873 spin_lock(get_ccwdev_lock(device->cdev));874 dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);875 spin_unlock(get_ccwdev_lock(device->cdev));876 }877 list_for_each_entry(device, &lcu->inactive_devices, alias_list) {878 spin_lock(get_ccwdev_lock(device->cdev));879 dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);880 spin_unlock(get_ccwdev_lock(device->cdev));881 }882 list_for_each_entry(pavgroup, &lcu->grouplist, group) {883 list_for_each_entry(device, &pavgroup->baselist, alias_list) {884 spin_lock(get_ccwdev_lock(device->cdev));885 dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);886 spin_unlock(get_ccwdev_lock(device->cdev));887 }888 list_for_each_entry(device, &pavgroup->aliaslist, alias_list) {889 spin_lock(get_ccwdev_lock(device->cdev));890 dasd_device_remove_stop_bits(device, DASD_STOPPED_SU);891 spin_unlock(get_ccwdev_lock(device->cdev));892 }893 }894}895 896static void summary_unit_check_handling_work(struct work_struct *work)897{898 struct alias_lcu *lcu;899 struct summary_unit_check_work_data *suc_data;900 unsigned long flags;901 struct dasd_device *device;902 903 suc_data = container_of(work, struct summary_unit_check_work_data,904 worker);905 lcu = container_of(suc_data, struct alias_lcu, suc_data);906 device = suc_data->device;907 908 /* 1. flush alias devices */909 flush_all_alias_devices_on_lcu(lcu);910 911 /* 2. reset summary unit check */912 spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);913 dasd_device_remove_stop_bits(device,914 (DASD_STOPPED_SU | DASD_STOPPED_PENDING));915 spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);916 reset_summary_unit_check(lcu, device, suc_data->reason);917 918 spin_lock_irqsave(&lcu->lock, flags);919 _unstop_all_devices_on_lcu(lcu);920 _restart_all_base_devices_on_lcu(lcu);921 /* 3. read new alias configuration */922 _schedule_lcu_update(lcu, device);923 lcu->suc_data.device = NULL;924 dasd_put_device(device);925 spin_unlock_irqrestore(&lcu->lock, flags);926}927 928void dasd_alias_handle_summary_unit_check(struct work_struct *work)929{930 struct dasd_device *device = container_of(work, struct dasd_device,931 suc_work);932 struct dasd_eckd_private *private = device->private;933 struct alias_lcu *lcu;934 unsigned long flags;935 936 lcu = private->lcu;937 if (!lcu) {938 DBF_DEV_EVENT(DBF_WARNING, device, "%s",939 "device not ready to handle summary"940 " unit check (no lcu structure)");941 goto out;942 }943 spin_lock_irqsave(&lcu->lock, flags);944 /* If this device is about to be removed just return and wait for945 * the next interrupt on a different device946 */947 if (list_empty(&device->alias_list)) {948 DBF_DEV_EVENT(DBF_WARNING, device, "%s",949 "device is in offline processing,"950 " don't do summary unit check handling");951 goto out_unlock;952 }953 if (lcu->suc_data.device) {954 /* already scheduled or running */955 DBF_DEV_EVENT(DBF_WARNING, device, "%s",956 "previous instance of summary unit check worker"957 " still pending");958 goto out_unlock;959 }960 _stop_all_devices_on_lcu(lcu);961 /* prepare for lcu_update */962 lcu->flags |= NEED_UAC_UPDATE | UPDATE_PENDING;963 lcu->suc_data.reason = private->suc_reason;964 lcu->suc_data.device = device;965 dasd_get_device(device);966 if (!schedule_work(&lcu->suc_data.worker))967 dasd_put_device(device);968out_unlock:969 spin_unlock_irqrestore(&lcu->lock, flags);970out:971 clear_bit(DASD_FLAG_SUC, &device->flags);972 dasd_put_device(device);973};974