diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-19 11:35:30 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-19 11:35:30 -0700 |
commit | ba0234ec35127fe21d373db53cbaf9fe20620cb6 (patch) | |
tree | a2cbef204482512ae9e723f2bf4d22051975ef45 /drivers | |
parent | 537b60d17894b7c19a6060feae40299d7109d6e7 (diff) | |
parent | 939e379e9e183ae6291ac7caa4a5e1dfadae4ccc (diff) |
Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6: (24 commits)
[S390] drivers/s390/char: Use kmemdup
[S390] drivers/s390/char: Use kstrdup
[S390] debug: enable exception-trace debug facility
[S390] s390_hypfs: Add new attributes
[S390] qdio: remove API wrappers
[S390] qdio: set correct bit in dsci
[S390] qdio: dont convert timestamps to microseconds
[S390] qdio: remove memset hack
[S390] qdio: prevent starvation on PCI devices
[S390] qdio: count number of qdio interrupts
[S390] user space fault: report fault before calling do_exit
[S390] topology: expose core identifier
[S390] dasd: remove uid from devmap
[S390] dasd: add dynamic pav toleration
[S390] vdso: add missing vdso_install target
[S390] vdso: remove redundant check for CONFIG_64BIT
[S390] avoid default_llseek in s390 drivers
[S390] vmcp: disallow modular build
[S390] add breaking event address for user space
[S390] virtualization aware cpu measurement
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/s390/block/dasd.c | 22 | ||||
-rw-r--r-- | drivers/s390/block/dasd_3990_erp.c | 20 | ||||
-rw-r--r-- | drivers/s390/block/dasd_alias.c | 125 | ||||
-rw-r--r-- | drivers/s390/block/dasd_devmap.c | 174 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 116 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.h | 2 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 49 | ||||
-rw-r--r-- | drivers/s390/char/Kconfig | 3 | ||||
-rw-r--r-- | drivers/s390/char/fs3270.c | 1 | ||||
-rw-r--r-- | drivers/s390/char/keyboard.c | 21 | ||||
-rw-r--r-- | drivers/s390/char/vmcp.c | 38 | ||||
-rw-r--r-- | drivers/s390/char/zcore.c | 4 | ||||
-rw-r--r-- | drivers/s390/cio/chsc_sch.c | 1 | ||||
-rw-r--r-- | drivers/s390/cio/cio.c | 3 | ||||
-rw-r--r-- | drivers/s390/cio/css.c | 8 | ||||
-rw-r--r-- | drivers/s390/cio/qdio.h | 15 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_main.c | 67 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_setup.c | 8 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_thinint.c | 4 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_api.c | 2 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 17 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_cfdc.c | 1 |
22 files changed, 396 insertions, 305 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index fa2339cb1681..0e86247d791e 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -65,6 +65,7 @@ static void dasd_device_tasklet(struct dasd_device *); static void dasd_block_tasklet(struct dasd_block *); static void do_kick_device(struct work_struct *); static void do_restore_device(struct work_struct *); +static void do_reload_device(struct work_struct *); static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); static void dasd_device_timeout(unsigned long); static void dasd_block_timeout(unsigned long); @@ -115,6 +116,7 @@ struct dasd_device *dasd_alloc_device(void) device->timer.data = (unsigned long) device; INIT_WORK(&device->kick_work, do_kick_device); INIT_WORK(&device->restore_device, do_restore_device); + INIT_WORK(&device->reload_device, do_reload_device); device->state = DASD_STATE_NEW; device->target = DASD_STATE_NEW; mutex_init(&device->state_mutex); @@ -521,6 +523,26 @@ void dasd_kick_device(struct dasd_device *device) } /* + * dasd_reload_device will schedule a call do do_reload_device to the kernel + * event daemon. + */ +static void do_reload_device(struct work_struct *work) +{ + struct dasd_device *device = container_of(work, struct dasd_device, + reload_device); + device->discipline->reload(device); + dasd_put_device(device); +} + +void dasd_reload_device(struct dasd_device *device) +{ + dasd_get_device(device); + /* queue call to dasd_reload_device to the kernel event daemon. */ + schedule_work(&device->reload_device); +} +EXPORT_SYMBOL(dasd_reload_device); + +/* * dasd_restore_device will schedule a call do do_restore_device to the kernel * event daemon. */ diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 6632649dd6aa..85bfd8794856 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -1418,9 +1418,29 @@ static struct dasd_ccw_req *dasd_3990_erp_inspect_alias( struct dasd_ccw_req *erp) { struct dasd_ccw_req *cqr = erp->refers; + char *sense; if (cqr->block && (cqr->block->base != cqr->startdev)) { + + sense = dasd_get_sense(&erp->refers->irb); + /* + * dynamic pav may have changed base alias mapping + */ + if (!test_bit(DASD_FLAG_OFFLINE, &cqr->startdev->flags) && sense + && (sense[0] == 0x10) && (sense[7] == 0x0F) + && (sense[8] == 0x67)) { + /* + * remove device from alias handling to prevent new + * requests from being scheduled on the + * wrong alias device + */ + dasd_alias_remove_device(cqr->startdev); + + /* schedule worker to reload device */ + dasd_reload_device(cqr->startdev); + } + if (cqr->startdev->features & DASD_FEATURE_ERPLOG) { DBF_DEV_EVENT(DBF_ERR, cqr->startdev, "ERP on alias device for request %p," diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 8c4814258e93..4155805dcdff 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -190,20 +190,21 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) struct alias_server *server, *newserver; struct alias_lcu *lcu, *newlcu; int is_lcu_known; - struct dasd_uid *uid; + struct dasd_uid uid; private = (struct dasd_eckd_private *) device->private; - uid = &private->uid; + + device->discipline->get_uid(device, &uid); spin_lock_irqsave(&aliastree.lock, flags); is_lcu_known = 1; - server = _find_server(uid); + server = _find_server(&uid); if (!server) { spin_unlock_irqrestore(&aliastree.lock, flags); - newserver = _allocate_server(uid); + newserver = _allocate_server(&uid); if (IS_ERR(newserver)) return PTR_ERR(newserver); spin_lock_irqsave(&aliastree.lock, flags); - server = _find_server(uid); + server = _find_server(&uid); if (!server) { list_add(&newserver->server, &aliastree.serverlist); server = newserver; @@ -214,14 +215,14 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) } } - lcu = _find_lcu(server, uid); + lcu = _find_lcu(server, &uid); if (!lcu) { spin_unlock_irqrestore(&aliastree.lock, flags); - newlcu = _allocate_lcu(uid); + newlcu = _allocate_lcu(&uid); if (IS_ERR(newlcu)) return PTR_ERR(newlcu); spin_lock_irqsave(&aliastree.lock, flags); - lcu = _find_lcu(server, uid); + lcu = _find_lcu(server, &uid); if (!lcu) { list_add(&newlcu->lcu, &server->lculist); lcu = newlcu; @@ -256,20 +257,20 @@ void dasd_alias_lcu_setup_complete(struct dasd_device *device) unsigned long flags; struct alias_server *server; struct alias_lcu *lcu; - struct dasd_uid *uid; + struct dasd_uid uid; private = (struct dasd_eckd_private *) device->private; - uid = &private->uid; + device->discipline->get_uid(device, &uid); lcu = NULL; spin_lock_irqsave(&aliastree.lock, flags); - server = _find_server(uid); + server = _find_server(&uid); if (server) - lcu = _find_lcu(server, uid); + lcu = _find_lcu(server, &uid); spin_unlock_irqrestore(&aliastree.lock, flags); if (!lcu) { DBF_EVENT_DEVID(DBF_ERR, device->cdev, "could not find lcu for %04x %02x", - uid->ssid, uid->real_unit_addr); + uid.ssid, uid.real_unit_addr); WARN_ON(1); return; } @@ -282,20 +283,20 @@ void dasd_alias_wait_for_lcu_setup(struct dasd_device *device) unsigned long flags; struct alias_server *server; struct alias_lcu *lcu; - struct dasd_uid *uid; + struct dasd_uid uid; private = (struct dasd_eckd_private *) device->private; - uid = &private->uid; + device->discipline->get_uid(device, &uid); lcu = NULL; spin_lock_irqsave(&aliastree.lock, flags); - server = _find_server(uid); + server = _find_server(&uid); if (server) - lcu = _find_lcu(server, uid); + lcu = _find_lcu(server, &uid); spin_unlock_irqrestore(&aliastree.lock, flags); if (!lcu) { DBF_EVENT_DEVID(DBF_ERR, device->cdev, "could not find lcu for %04x %02x", - uid->ssid, uid->real_unit_addr); + uid.ssid, uid.real_unit_addr); WARN_ON(1); return; } @@ -314,9 +315,11 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) struct alias_lcu *lcu; struct alias_server *server; int was_pending; + struct dasd_uid uid; private = (struct dasd_eckd_private *) device->private; lcu = private->lcu; + device->discipline->get_uid(device, &uid); spin_lock_irqsave(&lcu->lock, flags); list_del_init(&device->alias_list); /* make sure that the workers don't use this device */ @@ -353,7 +356,7 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) _schedule_lcu_update(lcu, NULL); spin_unlock(&lcu->lock); } - server = _find_server(&private->uid); + server = _find_server(&uid); if (server && list_empty(&server->lculist)) { list_del(&server->server); _free_server(server); @@ -366,19 +369,30 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) * in the lcu is up to date and will update the device uid before * adding it to a pav group. */ + static int _add_device_to_lcu(struct alias_lcu *lcu, - struct dasd_device *device) + struct dasd_device *device, + struct dasd_device *pos) { struct dasd_eckd_private *private; struct alias_pav_group *group; - struct dasd_uid *uid; + struct dasd_uid uid; + unsigned long flags; private = (struct dasd_eckd_private *) device->private; - uid = &private->uid; - uid->type = lcu->uac->unit[uid->real_unit_addr].ua_type; - uid->base_unit_addr = lcu->uac->unit[uid->real_unit_addr].base_ua; - dasd_set_uid(device->cdev, &private->uid); + + /* only lock if not already locked */ + if (device != pos) + spin_lock_irqsave_nested(get_ccwdev_lock(device->cdev), flags, + CDEV_NESTED_SECOND); + private->uid.type = lcu->uac->unit[private->uid.real_unit_addr].ua_type; + private->uid.base_unit_addr = + lcu->uac->unit[private->uid.real_unit_addr].base_ua; + uid = private->uid; + + if (device != pos) + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); /* if we have no PAV anyway, we don't need to bother with PAV groups */ if (lcu->pav == NO_PAV) { @@ -386,25 +400,25 @@ static int _add_device_to_lcu(struct alias_lcu *lcu, return 0; } - group = _find_group(lcu, uid); + group = _find_group(lcu, &uid); if (!group) { group = kzalloc(sizeof(*group), GFP_ATOMIC); if (!group) return -ENOMEM; - memcpy(group->uid.vendor, uid->vendor, sizeof(uid->vendor)); - memcpy(group->uid.serial, uid->serial, sizeof(uid->serial)); - group->uid.ssid = uid->ssid; - if (uid->type == UA_BASE_DEVICE) - group->uid.base_unit_addr = uid->real_unit_addr; + memcpy(group->uid.vendor, uid.vendor, sizeof(uid.vendor)); + memcpy(group->uid.serial, uid.serial, sizeof(uid.serial)); + group->uid.ssid = uid.ssid; + if (uid.type == UA_BASE_DEVICE) + group->uid.base_unit_addr = uid.real_unit_addr; else - group->uid.base_unit_addr = uid->base_unit_addr; - memcpy(group->uid.vduit, uid->vduit, sizeof(uid->vduit)); + group->uid.base_unit_addr = uid.base_unit_addr; + memcpy(group->uid.vduit, uid.vduit, sizeof(uid.vduit)); INIT_LIST_HEAD(&group->group); INIT_LIST_HEAD(&group->baselist); INIT_LIST_HEAD(&group->aliaslist); list_add(&group->group, &lcu->grouplist); } - if (uid->type == UA_BASE_DEVICE) + if (uid.type == UA_BASE_DEVICE) list_move(&device->alias_list, &group->baselist); else list_move(&device->alias_list, &group->aliaslist); @@ -525,7 +539,10 @@ static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu) if (rc) return rc; - spin_lock_irqsave(&lcu->lock, flags); + /* need to take cdev lock before lcu lock */ + spin_lock_irqsave_nested(get_ccwdev_lock(refdev->cdev), flags, + CDEV_NESTED_FIRST); + spin_lock(&lcu->lock); lcu->pav = NO_PAV; for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) { switch (lcu->uac->unit[i].ua_type) { @@ -542,9 +559,10 @@ static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu) list_for_each_entry_safe(device, tempdev, &lcu->active_devices, alias_list) { - _add_device_to_lcu(lcu, device); + _add_device_to_lcu(lcu, device, refdev); } - spin_unlock_irqrestore(&lcu->lock, flags); + spin_unlock(&lcu->lock); + spin_unlock_irqrestore(get_ccwdev_lock(refdev->cdev), flags); return 0; } @@ -628,9 +646,12 @@ int dasd_alias_add_device(struct dasd_device *device) private = (struct dasd_eckd_private *) device->private; lcu = private->lcu; rc = 0; - spin_lock_irqsave(&lcu->lock, flags); + + /* need to take cdev lock before lcu lock */ + spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); + spin_lock(&lcu->lock); if (!(lcu->flags & UPDATE_PENDING)) { - rc = _add_device_to_lcu(lcu, device); + rc = _add_device_to_lcu(lcu, device, device); if (rc) lcu->flags |= UPDATE_PENDING; } @@ -638,10 +659,19 @@ int dasd_alias_add_device(struct dasd_device *device) list_move(&device->alias_list, &lcu->active_devices); _schedule_lcu_update(lcu, device); } - spin_unlock_irqrestore(&lcu->lock, flags); + spin_unlock(&lcu->lock); + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); return rc; } +int dasd_alias_update_add_device(struct dasd_device *device) +{ + struct dasd_eckd_private *private; + private = (struct dasd_eckd_private *) device->private; + private->lcu->flags |= UPDATE_PENDING; + return dasd_alias_add_device(device); +} + int dasd_alias_remove_device(struct dasd_device *device) { struct dasd_eckd_private *private; @@ -740,19 +770,30 @@ static void _restart_all_base_devices_on_lcu(struct alias_lcu *lcu) struct alias_pav_group *pavgroup; struct dasd_device *device; struct dasd_eckd_private *private; + unsigned long flags; /* active and inactive list can contain alias as well as base devices */ list_for_each_entry(device, &lcu->active_devices, alias_list) { private = (struct dasd_eckd_private *) device->private; - if (private->uid.type != UA_BASE_DEVICE) + spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); + if (private->uid.type != UA_BASE_DEVICE) { + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), + flags); continue; + } + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); dasd_schedule_block_bh(device->block); dasd_schedule_device_bh(device); } list_for_each_entry(device, &lcu->inactive_devices, alias_list) { private = (struct dasd_eckd_private *) device->private; - if (private->uid.type != UA_BASE_DEVICE) + spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); + if (private->uid.type != UA_BASE_DEVICE) { + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), + flags); continue; + } + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); dasd_schedule_block_bh(device->block); dasd_schedule_device_bh(device); } diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index eff9c812c5c2..34d51dd4c539 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -49,7 +49,6 @@ struct dasd_devmap { unsigned int devindex; unsigned short features; struct dasd_device *device; - struct dasd_uid uid; }; /* @@ -936,42 +935,46 @@ dasd_device_status_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(status, 0444, dasd_device_status_show, NULL); -static ssize_t -dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t dasd_alias_show(struct device *dev, + struct device_attribute *attr, char *buf) { - struct dasd_devmap *devmap; - int alias; + struct dasd_device *device; + struct dasd_uid uid; - devmap = dasd_find_busid(dev_name(dev)); - spin_lock(&dasd_devmap_lock); - if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) { - spin_unlock(&dasd_devmap_lock); + device = dasd_device_from_cdev(to_ccwdev(dev)); + if (IS_ERR(device)) return sprintf(buf, "0\n"); + + if (device->discipline && device->discipline->get_uid && + !device->discipline->get_uid(device, &uid)) { + if (uid.type == UA_BASE_PAV_ALIAS || + uid.type == UA_HYPER_PAV_ALIAS) + return sprintf(buf, "1\n"); } - if (devmap->uid.type == UA_BASE_PAV_ALIAS || - devmap->uid.type == UA_HYPER_PAV_ALIAS) - alias = 1; - else - alias = 0; - spin_unlock(&dasd_devmap_lock); - return sprintf(buf, alias ? "1\n" : "0\n"); + dasd_put_device(device); + + return sprintf(buf, "0\n"); } static DEVICE_ATTR(alias, 0444, dasd_alias_show, NULL); -static ssize_t -dasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t dasd_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) { - struct dasd_devmap *devmap; + struct dasd_device *device; + struct dasd_uid uid; char *vendor; - devmap = dasd_find_busid(dev_name(dev)); - spin_lock(&dasd_devmap_lock); - if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0) - vendor = devmap->uid.vendor; - else - vendor = ""; - spin_unlock(&dasd_devmap_lock); + device = dasd_device_from_cdev(to_ccwdev(dev)); + vendor = ""; + if (IS_ERR(device)) + return snprintf(buf, PAGE_SIZE, "%s\n", vendor); + + if (device->discipline && device->discipline->get_uid && + !device->discipline->get_uid(device, &uid)) + vendor = uid.vendor; + + dasd_put_device(device); return snprintf(buf, PAGE_SIZE, "%s\n", vendor); } @@ -985,48 +988,51 @@ static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL); static ssize_t dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct dasd_devmap *devmap; + struct dasd_device *device; + struct dasd_uid uid; char uid_string[UID_STRLEN]; char ua_string[3]; - struct dasd_uid *uid; - devmap = dasd_find_busid(dev_name(dev)); - spin_lock(&dasd_devmap_lock); - if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) { - spin_unlock(&dasd_devmap_lock); - return sprintf(buf, "\n"); - } - uid = &devmap->uid; - switch (uid->type) { - case UA_BASE_DEVICE: - sprintf(ua_string, "%02x", uid->real_unit_addr); - break; - case UA_BASE_PAV_ALIAS: - sprintf(ua_string, "%02x", uid->base_unit_addr); - break; - case UA_HYPER_PAV_ALIAS: - sprintf(ua_string, "xx"); - break; - default: - /* should not happen, treat like base device */ - sprintf(ua_string, "%02x", uid->real_unit_addr); - break; + device = dasd_device_from_cdev(to_ccwdev(dev)); + uid_string[0] = 0; + if (IS_ERR(device)) + return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); + + if (device->discipline && device->discipline->get_uid && + !device->discipline->get_uid(device, &uid)) { + switch (uid.type) { + case UA_BASE_DEVICE: + snprintf(ua_string, sizeof(ua_string), "%02x", + uid.real_unit_addr); + break; + case UA_BASE_PAV_ALIAS: + snprintf(ua_string, sizeof(ua_string), "%02x", + uid.base_unit_addr); + break; + case UA_HYPER_PAV_ALIAS: + snprintf(ua_string, sizeof(ua_string), "xx"); + break; + default: + /* should not happen, treat like base device */ + snprintf(ua_string, sizeof(ua_string), "%02x", + uid.real_unit_addr); + break; + } + + if (strlen(uid.vduit) > 0) + snprintf(uid_string, sizeof(uid_string), + "%s.%s.%04x.%s.%s", + uid.vendor, uid.serial, uid.ssid, ua_string, + uid.vduit); + else + snprintf(uid_string, sizeof(uid_string), + "%s.%s.%04x.%s", + uid.vendor, uid.serial, uid.ssid, ua_string); } - if (strlen(uid->vduit) > 0) - snprintf(uid_string, sizeof(uid_string), - "%s.%s.%04x.%s.%s", - uid->vendor, uid->serial, - uid->ssid, ua_string, - uid->vduit); - else - snprintf(uid_string, sizeof(uid_string), - "%s.%s.%04x.%s", - uid->vendor, uid->serial, - uid->ssid, ua_string); - spin_unlock(&dasd_devmap_lock); + dasd_put_device(device); + return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); } - static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL); /* @@ -1094,50 +1100,6 @@ static struct attribute_group dasd_attr_group = { }; /* - * Return copy of the device unique identifier. - */ -int -dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid) -{ - struct dasd_devmap *devmap; - - devmap = dasd_find_busid(dev_name(&cdev->dev)); - if (IS_ERR(devmap)) - return PTR_ERR(devmap); - spin_lock(&dasd_devmap_lock); - *uid = devmap->uid; - spin_unlock(&dasd_devmap_lock); - return 0; -} -EXPORT_SYMBOL_GPL(dasd_get_uid); - -/* - * Register the given device unique identifier into devmap struct. - * In addition check if the related storage server subsystem ID is already - * contained in the dasd_server_ssid_list. If subsystem ID is not contained, - * create new entry. - * Return 0 if server was already in serverlist, - * 1 if the server was added successful - * <0 in case of error. - */ -int -dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid) -{ - struct dasd_devmap *devmap; - - devmap = dasd_find_busid(dev_name(&cdev->dev)); - if (IS_ERR(devmap)) - return PTR_ERR(devmap); - - spin_lock(&dasd_devmap_lock); - devmap->uid = *uid; - spin_unlock(&dasd_devmap_lock); - - return 0; -} -EXPORT_SYMBOL_GPL(dasd_set_uid); - -/* * Return value of the specified feature. */ int diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 0cb233116855..5b1cd8d6e971 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -692,18 +692,20 @@ dasd_eckd_cdl_reclen(int recid) /* * Generate device unique id that specifies the physical device. */ -static int dasd_eckd_generate_uid(struct dasd_device *device, - struct dasd_uid *uid) +static int dasd_eckd_generate_uid(struct dasd_device *device) { struct dasd_eckd_private *private; + struct dasd_uid *uid; int count; + unsigned long flags; private = (struct dasd_eckd_private *) device->private; if (!private) return -ENODEV; if (!private->ned || !private->gneq) return -ENODEV; - + uid = &private->uid; + spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); memset(uid, 0, sizeof(struct dasd_uid)); memcpy(uid->vendor, private->ned->HDA_manufacturer, sizeof(uid->vendor) - 1); @@ -726,9 +728,25 @@ static int dasd_eckd_generate_uid(struct dasd_device *device, private->vdsneq->uit[count]); } } + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); return 0; } +static int dasd_eckd_get_uid(struct dasd_device *device, struct dasd_uid *uid) +{ + struct dasd_eckd_private *private; + unsigned long flags; + + if (device->private) { + private = (struct dasd_eckd_private *)device->private; + spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); + *uid = private->uid; + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); + return 0; + } + return -EINVAL; +} + static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device, void *rcd_buffer, struct ciw *ciw, __u8 lpm) @@ -1088,6 +1106,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) { struct dasd_eckd_private *private; struct dasd_block *block; + struct dasd_uid temp_uid; int is_known, rc; int readonly; @@ -1124,13 +1143,13 @@ dasd_eckd_check_characteristics(struct dasd_device *device) if (rc) goto out_err1; - /* Generate device unique id and register in devmap */ - rc = dasd_eckd_generate_uid(device, &private->uid); + /* Generate device unique id */ + rc = dasd_eckd_generate_uid(device); if (rc) goto out_err1; - dasd_set_uid(device->cdev, &private->uid); - if (private->uid.type == UA_BASE_DEVICE) { + dasd_eckd_get_uid(device, &temp_uid); + if (temp_uid.type == UA_BASE_DEVICE) { block = dasd_alloc_block(); if (IS_ERR(block)) { DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", @@ -1451,6 +1470,7 @@ static int dasd_eckd_ready_to_online(struct dasd_device *device) static int dasd_eckd_online_to_ready(struct dasd_device *device) { + cancel_work_sync(&device->reload_device); return dasd_alias_remove_device(device); }; @@ -1709,10 +1729,27 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, { char mask; char *sense = NULL; + struct dasd_eckd_private *private; + private = (struct dasd_eckd_private *) device->private; /* first of all check for state change pending interrupt */ mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; if ((scsw_dstat(&irb->scsw) & mask) == mask) { + /* for alias only and not in offline processing*/ + if (!device->block && private->lcu && + !test_bit(DASD_FLAG_OFFLINE, &device->flags)) { + /* + * the state change could be caused by an alias + * reassignment remove device from alias handling + * to prevent new requests from being scheduled on + * the wrong alias device + */ + dasd_alias_remove_device(device); + + /* schedule worker to reload device */ + dasd_reload_device(device); + } + dasd_generic_handle_state_change(device); return; } @@ -3259,7 +3296,7 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, dasd_eckd_dump_sense_ccw(device, req, irb); } -int dasd_eckd_pm_freeze(struct dasd_device *device) +static int dasd_eckd_pm_freeze(struct dasd_device *device) { /* * the device should be disconnected from our LCU structure @@ -3272,7 +3309,7 @@ int dasd_eckd_pm_freeze(struct dasd_device *device) return 0; } -int dasd_eckd_restore_device(struct dasd_device *device) +static int dasd_eckd_restore_device(struct dasd_device *device) { struct dasd_eckd_private *private; struct dasd_eckd_characteristics temp_rdc_data; @@ -3287,15 +3324,16 @@ int dasd_eckd_restore_device(struct dasd_device *device) if (rc) goto out_err; - /* Generate device unique id and register in devmap */ - rc = dasd_eckd_generate_uid(device, &private->uid); - dasd_get_uid(device->cdev, &temp_uid); + dasd_eckd_get_uid(device, &temp_uid); + /* Generate device unique id */ + rc = dasd_eckd_generate_uid(device); + spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0) dev_err(&device->cdev->dev, "The UID of the DASD has " "changed\n"); + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); if (rc) goto out_err; - dasd_set_uid(device->cdev, &private->uid); /* register lcu with alias handling, enable PAV if this is a new lcu */ is_known = dasd_alias_make_device_known_to_lcu(device); @@ -3336,6 +3374,56 @@ out_err: return -1; } +static int dasd_eckd_reload_device(struct dasd_device *device) +{ + struct dasd_eckd_private *private; + int rc, old_base; + char print_uid[60]; + struct dasd_uid uid; + unsigned long flags; + + private = (struct dasd_eckd_private *) device->private; + + spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); + old_base = private->uid.base_unit_addr; + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); + + /* Read Configuration Data */ + rc = dasd_eckd_read_conf(device); + if (rc) + goto out_err; + + rc = dasd_eckd_generate_uid(device); + if (rc) + goto out_err; + /* + * update unit address configuration and + * add device to alias management + */ + dasd_alias_update_add_device(device); + + dasd_eckd_get_uid(device, &uid); + + if (old_base != uid.base_unit_addr) { + if (strlen(uid.vduit) > 0) + snprintf(print_uid, sizeof(print_uid), + "%s.%s.%04x.%02x.%s", uid.vendor, uid.serial, + uid.ssid, uid.base_unit_addr, uid.vduit); + else + snprintf(print_uid, sizeof(print_uid), + "%s.%s.%04x.%02x", uid.vendor, uid.serial, + uid.ssid, uid.base_unit_addr); + + dev_info(&device->cdev->dev, + "An Alias device was reassigned to a new base device " + "with UID: %s\n", print_uid); + } + return 0; + +out_err: + return -1; +} + static struct ccw_driver dasd_eckd_driver = { .name = "dasd-eckd", .owner = THIS_MODULE, @@ -3389,6 +3477,8 @@ static struct dasd_discipline dasd_eckd_discipline = { .ioctl = dasd_eckd_ioctl, .freeze = dasd_eckd_pm_freeze, .restore = dasd_eckd_restore_device, + .reload = dasd_eckd_reload_device, + .get_uid = dasd_eckd_get_uid, }; static int __init diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index 864d53c04201..dd6385a5af14 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -426,7 +426,6 @@ struct alias_pav_group { struct dasd_device *next; }; - struct dasd_eckd_private { struct dasd_eckd_characteristics rdc_data; u8 *conf_data; @@ -463,4 +462,5 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *, struct irb *); void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *); void dasd_alias_lcu_setup_complete(struct dasd_device *); void dasd_alias_wait_for_lcu_setup(struct dasd_device *); +int dasd_alias_update_add_device(struct dasd_device *); #endif /* DASD_ECKD_H */ diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index a91d4a97d4f2..32fac186ba3f 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -81,6 +81,10 @@ struct dasd_block; #define DASD_SIM_MSG_TO_OP 0x03 #define DASD_SIM_LOG 0x0C +/* lock class for nested cdev lock */ +#define CDEV_NESTED_FIRST 1 +#define CDEV_NESTED_SECOND 2 + /* * SECTION: MACROs for klogd and s390 debug feature (dbf) */ @@ -229,6 +233,24 @@ struct dasd_ccw_req { typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *); /* + * Unique identifier for dasd device. + */ +#define UA_NOT_CONFIGURED 0x00 +#define UA_BASE_DEVICE 0x01 +#define UA_BASE_PAV_ALIAS 0x02 +#define UA_HYPER_PAV_ALIAS 0x03 + +struct dasd_uid { + __u8 type; + char vendor[4]; + char serial[15]; + __u16 ssid; + __u8 real_unit_addr; + __u8 base_unit_addr; + char vduit[33]; +}; + +/* * the struct dasd_discipline is * sth like a table of virtual functions, if you think of dasd_eckd * inheriting dasd... @@ -312,28 +334,15 @@ struct dasd_discipline { /* suspend/resume functions */ int (*freeze) (struct dasd_device *); int (*restore) (struct dasd_device *); -}; -extern struct dasd_discipline *dasd_diag_discipline_pointer; - -/* - * Unique identifier for dasd device. - */ -#define UA_NOT_CONFIGURED 0x00 -#define UA_BASE_DEVICE 0x01 -#define UA_BASE_PAV_ALIAS 0x02 -#define UA_HYPER_PAV_ALIAS 0x03 + /* reload device after state change */ + int (*reload) (struct dasd_device *); -struct dasd_uid { - __u8 type; - char vendor[4]; - char serial[15]; - __u16 ssid; - __u8 real_unit_addr; - __u8 base_unit_addr; - char vduit[33]; + int (*get_uid) (struct dasd_device *, struct dasd_uid *); }; +extern struct dasd_discipline *dasd_diag_discipline_pointer; + /* * Notification numbers for extended error reporting notifications: * The DASD_EER_DISABLE notification is sent before a dasd_device (and it's @@ -386,6 +395,7 @@ struct dasd_device { struct tasklet_struct tasklet; struct work_struct kick_work; struct work_struct restore_device; + struct work_struct reload_device; struct timer_list timer; debug_info_t *debug_area; @@ -582,6 +592,7 @@ void dasd_enable_device(struct dasd_device *); void dasd_set_target_state(struct dasd_device *, int); void dasd_kick_device(struct dasd_device *); void dasd_restore_device(struct dasd_device *); +void dasd_reload_device(struct dasd_device *); void dasd_add_request_head(struct dasd_ccw_req *); void dasd_add_request_tail(struct dasd_ccw_req *); @@ -629,8 +640,6 @@ void dasd_devmap_exit(void); struct dasd_device *dasd_create_device(struct ccw_device *); void dasd_delete_device(struct dasd_device *); -int dasd_get_uid(struct ccw_device *, struct dasd_uid *); -int dasd_set_uid(struct ccw_device *, struct dasd_uid *); int dasd_get_feature(struct ccw_device *, int); int dasd_set_feature(struct ccw_device *, int, int); diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig index 4e34d3686c23..40834f18754c 100644 --- a/drivers/s390/char/Kconfig +++ b/drivers/s390/char/Kconfig @@ -148,13 +148,12 @@ config VMLOGRDR This driver depends on the IUCV support driver. config VMCP - tristate "Support for the z/VM CP interface (VM only)" + bool "Support for the z/VM CP interface" depends on S390 help Select this option if you want to be able to interact with the control program on z/VM - config MONREADER tristate "API for reading z/VM monitor service records" depends on IUCV diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index 0eabcca3c92d..857dfcb7b359 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c @@ -484,6 +484,7 @@ fs3270_open(struct inode *inode, struct file *filp) raw3270_del_view(&fp->view); goto out; } + nonseekable_open(inode, filp); filp->private_data = fp; out: mutex_unlock(&fs3270_mutex); diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c index cb6bffe7141a..18d9a497863b 100644 --- a/drivers/s390/char/keyboard.c +++ b/drivers/s390/char/keyboard.c @@ -49,7 +49,7 @@ static unsigned char ret_diacr[NR_DEAD] = { struct kbd_data * kbd_alloc(void) { struct kbd_data *kbd; - int i, len; + int i; kbd = kzalloc(sizeof(struct kbd_data), GFP_KERNEL); if (!kbd) @@ -59,12 +59,11 @@ kbd_alloc(void) { goto out_kbd; for (i = 0; i < ARRAY_SIZE(key_maps); i++) { if (key_maps[i]) { - kbd->key_maps[i] = - kmalloc(sizeof(u_short)*NR_KEYS, GFP_KERNEL); + kbd->key_maps[i] = kmemdup(key_maps[i], + sizeof(u_short) * NR_KEYS, + GFP_KERNEL); if (!kbd->key_maps[i]) goto out_maps; - memcpy(kbd->key_maps[i], key_maps[i], - sizeof(u_short)*NR_KEYS); } } kbd->func_table = kzalloc(sizeof(func_table), GFP_KERNEL); @@ -72,23 +71,21 @@ kbd_alloc(void) { goto out_maps; for (i = 0; i < ARRAY_SIZE(func_table); i++) { if (func_table[i]) { - len = strlen(func_table[i]) + 1; - kbd->func_table[i] = kmalloc(len, GFP_KERNEL); + kbd->func_table[i] = kstrdup(func_table[i], + GFP_KERNEL); if (!kbd->func_table[i]) goto out_func; - memcpy(kbd->func_table[i], func_table[i], len); } } kbd->fn_handler = kzalloc(sizeof(fn_handler_fn *) * NR_FN_HANDLER, GFP_KERNEL); if (!kbd->fn_handler) goto out_func; - kbd->accent_table = - kmalloc(sizeof(struct kbdiacruc)*MAX_DIACR, GFP_KERNEL); + kbd->accent_table = kmemdup(accent_table, + sizeof(struct kbdiacruc) * MAX_DIACR, + GFP_KERNEL); if (!kbd->accent_table) goto out_fn_handler; - memcpy(kbd->accent_table, accent_table, - sizeof(struct kbdiacruc)*MAX_DIACR); kbd->accent_table_size = accent_table_size; return kbd; diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 5bb59d36a6d4..04e532eec032 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -1,24 +1,20 @@ /* - * Copyright IBM Corp. 2004,2007 + * Copyright IBM Corp. 2004,2010 * Interface implementation for communication with the z/VM control program - * Author(s): Christian Borntraeger <borntraeger@de.ibm.com> * + * Author(s): Christian Borntraeger <borntraeger@de.ibm.com> * * z/VMs CP offers the possibility to issue commands via the diagnose code 8 * this driver implements a character device that issues these commands and * returns the answer of CP. - + * * The idea of this driver is based on cpint from Neale Ferguson and #CP in CMS */ -#define KMSG_COMPONENT "vmcp" -#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt - #include <linux/fs.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/miscdevice.h> -#include <linux/module.h> #include <linux/slab.h> #include <asm/compat.h> #include <asm/cpcmd.h> @@ -26,10 +22,6 @@ #include <asm/uaccess.h> #include "vmcp.h" -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Christian Borntraeger <borntraeger@de.ibm.com>"); -MODULE_DESCRIPTION("z/VM CP interface"); - static debug_info_t *vmcp_debug; static int vmcp_open(struct inode *inode, struct file *file) @@ -197,11 +189,8 @@ static int __init vmcp_init(void) { int ret; - if (!MACHINE_IS_VM) { - pr_warning("The z/VM CP interface device driver cannot be " - "loaded without z/VM\n"); - return -ENODEV; - } + if (!MACHINE_IS_VM) + return 0; vmcp_debug = debug_register("vmcp", 1, 1, 240); if (!vmcp_debug) @@ -214,19 +203,8 @@ static int __init vmcp_init(void) } ret = misc_register(&vmcp_dev); - if (ret) { + if (ret) debug_unregister(vmcp_debug); - return ret; - } - - return 0; -} - -static void __exit vmcp_exit(void) -{ - misc_deregister(&vmcp_dev); - debug_unregister(vmcp_debug); + return ret; } - -module_init(vmcp_init); -module_exit(vmcp_exit); +device_initcall(vmcp_init); diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 7217966f7d31..f5ea3384a4b9 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -445,7 +445,7 @@ static int zcore_memmap_open(struct inode *inode, struct file *filp) } kfree(chunk_array); filp->private_data = buf; - return 0; + return nonseekable_open(inode, filp); } static int zcore_memmap_release(struct inode *inode, struct file *filp) @@ -473,7 +473,7 @@ static ssize_t zcore_reipl_write(struct file *filp, const char __user *buf, static int zcore_reipl_open(struct inode *inode, struct file *filp) { - return 0; + return nonseekable_open(inode, filp); } static int zcore_reipl_release(struct inode *inode, struct file *filp) diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 3b6f4adc5094..a83877c664a6 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -803,6 +803,7 @@ static long chsc_ioctl(struct file *filp, unsigned int cmd, static const struct file_operations chsc_fops = { .owner = THIS_MODULE, + .open = nonseekable_open, .unlocked_ioctl = chsc_ioctl, .compat_ioctl = chsc_ioctl, }; diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 5feea1a371e1..f4e6cf3aceb8 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -616,7 +616,8 @@ void __irq_entry do_IRQ(struct pt_regs *regs) struct pt_regs *old_regs; old_regs = set_irq_regs(regs); - s390_idle_check(); + s390_idle_check(regs, S390_lowcore.int_clock, + S390_lowcore.async_enter_timer); irq_enter(); __get_cpu_var(s390_idle).nohz_delay = 1; if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 511649115bd7..ac94ac751459 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -648,6 +648,8 @@ static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow) static void __init css_generate_pgid(struct channel_subsystem *css, u32 tod_high) { + struct cpuid cpu_id; + if (css_general_characteristics.mcss) { css->global_pgid.pgid_high.ext_cssid.version = 0x80; css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid; @@ -658,8 +660,9 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high) css->global_pgid.pgid_high.cpu_addr = 0; #endif } - css->global_pgid.cpu_id = S390_lowcore.cpu_id.ident; - css->global_pgid.cpu_model = S390_lowcore.cpu_id.machine; + get_cpu_id(&cpu_id); + css->global_pgid.cpu_id = cpu_id.ident; + css->global_pgid.cpu_model = cpu_id.machine; css->global_pgid.tod_high = tod_high; } @@ -1062,6 +1065,7 @@ static ssize_t cio_settle_write(struct file *file, const char __user *buf, } static const struct file_operations cio_settle_proc_fops = { + .open = nonseekable_open, .write = cio_settle_write, }; diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 48aa0647432b..f0037eefd44e 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -13,8 +13,8 @@ #include <asm/debug.h> #include "chsc.h" -#define QDIO_BUSY_BIT_PATIENCE 100 /* 100 microseconds */ -#define QDIO_INPUT_THRESHOLD 500 /* 500 microseconds */ +#define QDIO_BUSY_BIT_PATIENCE (100 << 12) /* 100 microseconds */ +#define QDIO_INPUT_THRESHOLD (500 << 12) /* 500 microseconds */ /* * if an asynchronous HiperSockets queue runs full, the 10 seconds timer wait @@ -296,10 +296,8 @@ struct qdio_q { struct qdio_irq *irq_ptr; struct sl *sl; /* - * Warning: Leave this member at the end so it won't be cleared in - * qdio_fill_qs. A page is allocated under this pointer and used for - * slib and sl. slib is 2048 bytes big and sl points to offset - * PAGE_SIZE / 2. + * A page is allocated under this pointer and used for slib and sl. + * slib is 2048 bytes big and sl points to offset PAGE_SIZE / 2. */ struct slib *slib; } __attribute__ ((aligned(256))); @@ -372,11 +370,6 @@ static inline int multicast_outbound(struct qdio_q *q) (q->nr == q->irq_ptr->nr_output_qs - 1); } -static inline unsigned long long get_usecs(void) -{ - return monotonic_clock() >> 12; -} - #define pci_out_supported(q) \ (q->irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) #define is_qebsm(q) (q->irq_ptr->sch_token != 0) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 88be7b9ea6e1..00520f9a7a8e 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -336,10 +336,10 @@ again: WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2); if (!start_time) { - start_time = get_usecs(); + start_time = get_clock(); goto again; } - if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE) + if ((get_clock() - start_time) < QDIO_BUSY_BIT_PATIENCE) goto again; } return cc; @@ -536,7 +536,7 @@ static int qdio_inbound_q_moved(struct qdio_q *q) if ((bufnr != q->last_move) || q->qdio_error) { q->last_move = bufnr; if (!is_thinint_irq(q->irq_ptr) && MACHINE_IS_LPAR) - q->u.in.timestamp = get_usecs(); + q->u.in.timestamp = get_clock(); return 1; } else return 0; @@ -567,7 +567,7 @@ static inline int qdio_inbound_q_done(struct qdio_q *q) * At this point we know, that inbound first_to_check * has (probably) not moved (see qdio_inbound_processing). */ - if (get_usecs() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) { + if (get_clock() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) { DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%02x", q->first_to_check); return 1; @@ -606,7 +606,7 @@ static void qdio_kick_handler(struct qdio_q *q) static void __qdio_inbound_processing(struct qdio_q *q) { qperf_inc(q, tasklet_inbound); -again: + if (!qdio_inbound_q_moved(q)) return; @@ -615,7 +615,10 @@ again: if (!qdio_inbound_q_done(q)) { /* means poll time is not yet over */ qperf_inc(q, tasklet_inbound_resched); - goto again; + if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) { + tasklet_schedule(&q->tasklet); + return; + } } qdio_stop_polling(q); @@ -625,7 +628,8 @@ again: */ if (!qdio_inbound_q_done(q)) { qperf_inc(q, tasklet_inbound_resched2); - goto again; + if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) + tasklet_schedule(&q->tasklet); } } @@ -955,6 +959,9 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, return; } + if (irq_ptr->perf_stat_enabled) + irq_ptr->perf_stat.qdio_int++; + if (IS_ERR(irb)) { switch (PTR_ERR(irb)) { case -EIO: @@ -1016,30 +1023,6 @@ int qdio_get_ssqd_desc(struct ccw_device *cdev, } EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); -/** - * qdio_cleanup - shutdown queues and free data structures - * @cdev: associated ccw device - * @how: use halt or clear to shutdown - * - * This function calls qdio_shutdown() for @cdev with method @how. - * and qdio_free(). The qdio_free() return value is ignored since - * !irq_ptr is already checked. - */ -int qdio_cleanup(struct ccw_device *cdev, int how) -{ - struct qdio_irq *irq_ptr = cdev->private->qdio_data; - int rc; - - if (!irq_ptr) - return -ENODEV; - - rc = qdio_shutdown(cdev, how); - - qdio_free(cdev); - return rc; -} -EXPORT_SYMBOL_GPL(qdio_cleanup); - static void qdio_shutdown_queues(struct ccw_device *cdev) { struct qdio_irq *irq_ptr = cdev->private->qdio_data; @@ -1157,28 +1140,6 @@ int qdio_free(struct ccw_device *cdev) EXPORT_SYMBOL_GPL(qdio_free); /** - * qdio_initialize - allocate and establish queues for a qdio subchannel - * @init_data: initialization data - * - * This function first allocates queues via qdio_allocate() and on success - * establishes them via qdio_establish(). - */ -int qdio_initialize(struct qdio_initialize *init_data) -{ - int rc; - - rc = qdio_allocate(init_data); - if (rc) - return rc; - - rc = qdio_establish(init_data); - if (rc) - qdio_free(init_data->cdev); - return rc; -} -EXPORT_SYMBOL_GPL(qdio_initialize); - -/** * qdio_allocate - allocate qdio queues and associated data * @init_data: initialization data */ diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 7f4a75465140..6326b67c45d2 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -106,10 +106,12 @@ int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, int nr_output_qs static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr, qdio_handler_t *handler, int i) { - /* must be cleared by every qdio_establish */ - memset(q, 0, ((char *)&q->slib) - ((char *)q)); - memset(q->slib, 0, PAGE_SIZE); + struct slib *slib = q->slib; + /* queue must be cleared for qdio_establish */ + memset(q, 0, sizeof(*q)); + memset(slib, 0, PAGE_SIZE); + q->slib = slib; q->irq_ptr = irq_ptr; q->mask = 1 << (31 - i); q->nr = i; diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index ce5f8910ff83..8daf1b99f153 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -95,7 +95,7 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr) for_each_input_queue(irq_ptr, q, i) list_add_rcu(&q->entry, &tiq_list); mutex_unlock(&tiq_list_lock); - xchg(irq_ptr->dsci, 1); + xchg(irq_ptr->dsci, 1 << 7); } void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) @@ -173,7 +173,7 @@ static void tiqdio_thinint_handler(void *ind, void *drv_data) /* prevent racing */ if (*tiqdio_alsi) - xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1); + xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1 << 7); } } diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 304caf549973..41e0aaefafd5 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -302,7 +302,7 @@ static ssize_t zcrypt_write(struct file *filp, const char __user *buf, static int zcrypt_open(struct inode *inode, struct file *filp) { atomic_inc(&zcrypt_open_count); - return 0; + return nonseekable_open(inode, filp); } /** diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 3ba738b2e271..28f71349fdec 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1292,13 +1292,14 @@ int qeth_qdio_clear_card(struct qeth_card *card, int use_halt) QETH_QDIO_CLEANING)) { case QETH_QDIO_ESTABLISHED: if (card->info.type == QETH_CARD_TYPE_IQD) - rc = qdio_cleanup(CARD_DDEV(card), + rc = qdio_shutdown(CARD_DDEV(card), QDIO_FLAG_CLEANUP_USING_HALT); else - rc = qdio_cleanup(CARD_DDEV(card), + rc = qdio_shutdown(CARD_DDEV(card), QDIO_FLAG_CLEANUP_USING_CLEAR); if (rc) QETH_DBF_TEXT_(TRACE, 3, "1err%d", rc); + qdio_free(CARD_DDEV(card)); atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED); break; case QETH_QDIO_CLEANING: @@ -3810,10 +3811,18 @@ static int qeth_qdio_establish(struct qeth_card *card) if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED, QETH_QDIO_ESTABLISHED) == QETH_QDIO_ALLOCATED) { - rc = qdio_initialize(&init_data); - if (rc) + rc = qdio_allocate(&init_data); + if (rc) { + atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED); + goto out; + } + rc = qdio_establish(&init_data); + if (rc) { atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED); + qdio_free(CARD_DDEV(card)); + } } +out: kfree(out_sbal_ptrs); kfree(in_sbal_ptrs); kfree(qib_param_field); diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index 25d9e0ae9c57..1a2db0a35737 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c @@ -254,6 +254,7 @@ static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, } static const struct file_operations zfcp_cfdc_fops = { + .open = nonseekable_open, .unlocked_ioctl = zfcp_cfdc_dev_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = zfcp_cfdc_dev_ioctl |