diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-19 14:35:30 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-19 14:35:30 -0400 |
commit | ba0234ec35127fe21d373db53cbaf9fe20620cb6 (patch) | |
tree | a2cbef204482512ae9e723f2bf4d22051975ef45 /drivers/s390 | |
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/s390')
-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 *); | |||
65 | static void dasd_block_tasklet(struct dasd_block *); | 65 | static void dasd_block_tasklet(struct dasd_block *); |
66 | static void do_kick_device(struct work_struct *); | 66 | static void do_kick_device(struct work_struct *); |
67 | static void do_restore_device(struct work_struct *); | 67 | static void do_restore_device(struct work_struct *); |
68 | static void do_reload_device(struct work_struct *); | ||
68 | static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); | 69 | static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); |
69 | static void dasd_device_timeout(unsigned long); | 70 | static void dasd_device_timeout(unsigned long); |
70 | static void dasd_block_timeout(unsigned long); | 71 | static void dasd_block_timeout(unsigned long); |
@@ -115,6 +116,7 @@ struct dasd_device *dasd_alloc_device(void) | |||
115 | device->timer.data = (unsigned long) device; | 116 | device->timer.data = (unsigned long) device; |
116 | INIT_WORK(&device->kick_work, do_kick_device); | 117 | INIT_WORK(&device->kick_work, do_kick_device); |
117 | INIT_WORK(&device->restore_device, do_restore_device); | 118 | INIT_WORK(&device->restore_device, do_restore_device); |
119 | INIT_WORK(&device->reload_device, do_reload_device); | ||
118 | device->state = DASD_STATE_NEW; | 120 | device->state = DASD_STATE_NEW; |
119 | device->target = DASD_STATE_NEW; | 121 | device->target = DASD_STATE_NEW; |
120 | mutex_init(&device->state_mutex); | 122 | mutex_init(&device->state_mutex); |
@@ -521,6 +523,26 @@ void dasd_kick_device(struct dasd_device *device) | |||
521 | } | 523 | } |
522 | 524 | ||
523 | /* | 525 | /* |
526 | * dasd_reload_device will schedule a call do do_reload_device to the kernel | ||
527 | * event daemon. | ||
528 | */ | ||
529 | static void do_reload_device(struct work_struct *work) | ||
530 | { | ||
531 | struct dasd_device *device = container_of(work, struct dasd_device, | ||
532 | reload_device); | ||
533 | device->discipline->reload(device); | ||
534 | dasd_put_device(device); | ||
535 | } | ||
536 | |||
537 | void dasd_reload_device(struct dasd_device *device) | ||
538 | { | ||
539 | dasd_get_device(device); | ||
540 | /* queue call to dasd_reload_device to the kernel event daemon. */ | ||
541 | schedule_work(&device->reload_device); | ||
542 | } | ||
543 | EXPORT_SYMBOL(dasd_reload_device); | ||
544 | |||
545 | /* | ||
524 | * dasd_restore_device will schedule a call do do_restore_device to the kernel | 546 | * dasd_restore_device will schedule a call do do_restore_device to the kernel |
525 | * event daemon. | 547 | * event daemon. |
526 | */ | 548 | */ |
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( | |||
1418 | struct dasd_ccw_req *erp) | 1418 | struct dasd_ccw_req *erp) |
1419 | { | 1419 | { |
1420 | struct dasd_ccw_req *cqr = erp->refers; | 1420 | struct dasd_ccw_req *cqr = erp->refers; |
1421 | char *sense; | ||
1421 | 1422 | ||
1422 | if (cqr->block && | 1423 | if (cqr->block && |
1423 | (cqr->block->base != cqr->startdev)) { | 1424 | (cqr->block->base != cqr->startdev)) { |
1425 | |||
1426 | sense = dasd_get_sense(&erp->refers->irb); | ||
1427 | /* | ||
1428 | * dynamic pav may have changed base alias mapping | ||
1429 | */ | ||
1430 | if (!test_bit(DASD_FLAG_OFFLINE, &cqr->startdev->flags) && sense | ||
1431 | && (sense[0] == 0x10) && (sense[7] == 0x0F) | ||
1432 | && (sense[8] == 0x67)) { | ||
1433 | /* | ||
1434 | * remove device from alias handling to prevent new | ||
1435 | * requests from being scheduled on the | ||
1436 | * wrong alias device | ||
1437 | */ | ||
1438 | dasd_alias_remove_device(cqr->startdev); | ||
1439 | |||
1440 | /* schedule worker to reload device */ | ||
1441 | dasd_reload_device(cqr->startdev); | ||
1442 | } | ||
1443 | |||
1424 | if (cqr->startdev->features & DASD_FEATURE_ERPLOG) { | 1444 | if (cqr->startdev->features & DASD_FEATURE_ERPLOG) { |
1425 | DBF_DEV_EVENT(DBF_ERR, cqr->startdev, | 1445 | DBF_DEV_EVENT(DBF_ERR, cqr->startdev, |
1426 | "ERP on alias device for request %p," | 1446 | "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) | |||
190 | struct alias_server *server, *newserver; | 190 | struct alias_server *server, *newserver; |
191 | struct alias_lcu *lcu, *newlcu; | 191 | struct alias_lcu *lcu, *newlcu; |
192 | int is_lcu_known; | 192 | int is_lcu_known; |
193 | struct dasd_uid *uid; | 193 | struct dasd_uid uid; |
194 | 194 | ||
195 | private = (struct dasd_eckd_private *) device->private; | 195 | private = (struct dasd_eckd_private *) device->private; |
196 | uid = &private->uid; | 196 | |
197 | device->discipline->get_uid(device, &uid); | ||
197 | spin_lock_irqsave(&aliastree.lock, flags); | 198 | spin_lock_irqsave(&aliastree.lock, flags); |
198 | is_lcu_known = 1; | 199 | is_lcu_known = 1; |
199 | server = _find_server(uid); | 200 | server = _find_server(&uid); |
200 | if (!server) { | 201 | if (!server) { |
201 | spin_unlock_irqrestore(&aliastree.lock, flags); | 202 | spin_unlock_irqrestore(&aliastree.lock, flags); |
202 | newserver = _allocate_server(uid); | 203 | newserver = _allocate_server(&uid); |
203 | if (IS_ERR(newserver)) | 204 | if (IS_ERR(newserver)) |
204 | return PTR_ERR(newserver); | 205 | return PTR_ERR(newserver); |
205 | spin_lock_irqsave(&aliastree.lock, flags); | 206 | spin_lock_irqsave(&aliastree.lock, flags); |
206 | server = _find_server(uid); | 207 | server = _find_server(&uid); |
207 | if (!server) { | 208 | if (!server) { |
208 | list_add(&newserver->server, &aliastree.serverlist); | 209 | list_add(&newserver->server, &aliastree.serverlist); |
209 | server = newserver; | 210 | server = newserver; |
@@ -214,14 +215,14 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) | |||
214 | } | 215 | } |
215 | } | 216 | } |
216 | 217 | ||
217 | lcu = _find_lcu(server, uid); | 218 | lcu = _find_lcu(server, &uid); |
218 | if (!lcu) { | 219 | if (!lcu) { |
219 | spin_unlock_irqrestore(&aliastree.lock, flags); | 220 | spin_unlock_irqrestore(&aliastree.lock, flags); |
220 | newlcu = _allocate_lcu(uid); | 221 | newlcu = _allocate_lcu(&uid); |
221 | if (IS_ERR(newlcu)) | 222 | if (IS_ERR(newlcu)) |
222 | return PTR_ERR(newlcu); | 223 | return PTR_ERR(newlcu); |
223 | spin_lock_irqsave(&aliastree.lock, flags); | 224 | spin_lock_irqsave(&aliastree.lock, flags); |
224 | lcu = _find_lcu(server, uid); | 225 | lcu = _find_lcu(server, &uid); |
225 | if (!lcu) { | 226 | if (!lcu) { |
226 | list_add(&newlcu->lcu, &server->lculist); | 227 | list_add(&newlcu->lcu, &server->lculist); |
227 | lcu = newlcu; | 228 | lcu = newlcu; |
@@ -256,20 +257,20 @@ void dasd_alias_lcu_setup_complete(struct dasd_device *device) | |||
256 | unsigned long flags; | 257 | unsigned long flags; |
257 | struct alias_server *server; | 258 | struct alias_server *server; |
258 | struct alias_lcu *lcu; | 259 | struct alias_lcu *lcu; |
259 | struct dasd_uid *uid; | 260 | struct dasd_uid uid; |
260 | 261 | ||
261 | private = (struct dasd_eckd_private *) device->private; | 262 | private = (struct dasd_eckd_private *) device->private; |
262 | uid = &private->uid; | 263 | device->discipline->get_uid(device, &uid); |
263 | lcu = NULL; | 264 | lcu = NULL; |
264 | spin_lock_irqsave(&aliastree.lock, flags); | 265 | spin_lock_irqsave(&aliastree.lock, flags); |
265 | server = _find_server(uid); | 266 | server = _find_server(&uid); |
266 | if (server) | 267 | if (server) |
267 | lcu = _find_lcu(server, uid); | 268 | lcu = _find_lcu(server, &uid); |
268 | spin_unlock_irqrestore(&aliastree.lock, flags); | 269 | spin_unlock_irqrestore(&aliastree.lock, flags); |
269 | if (!lcu) { | 270 | if (!lcu) { |
270 | DBF_EVENT_DEVID(DBF_ERR, device->cdev, | 271 | DBF_EVENT_DEVID(DBF_ERR, device->cdev, |
271 | "could not find lcu for %04x %02x", | 272 | "could not find lcu for %04x %02x", |
272 | uid->ssid, uid->real_unit_addr); | 273 | uid.ssid, uid.real_unit_addr); |
273 | WARN_ON(1); | 274 | WARN_ON(1); |
274 | return; | 275 | return; |
275 | } | 276 | } |
@@ -282,20 +283,20 @@ void dasd_alias_wait_for_lcu_setup(struct dasd_device *device) | |||
282 | unsigned long flags; | 283 | unsigned long flags; |
283 | struct alias_server *server; | 284 | struct alias_server *server; |
284 | struct alias_lcu *lcu; | 285 | struct alias_lcu *lcu; |
285 | struct dasd_uid *uid; | 286 | struct dasd_uid uid; |
286 | 287 | ||
287 | private = (struct dasd_eckd_private *) device->private; | 288 | private = (struct dasd_eckd_private *) device->private; |
288 | uid = &private->uid; | 289 | device->discipline->get_uid(device, &uid); |
289 | lcu = NULL; | 290 | lcu = NULL; |
290 | spin_lock_irqsave(&aliastree.lock, flags); | 291 | spin_lock_irqsave(&aliastree.lock, flags); |
291 | server = _find_server(uid); | 292 | server = _find_server(&uid); |
292 | if (server) | 293 | if (server) |
293 | lcu = _find_lcu(server, uid); | 294 | lcu = _find_lcu(server, &uid); |
294 | spin_unlock_irqrestore(&aliastree.lock, flags); | 295 | spin_unlock_irqrestore(&aliastree.lock, flags); |
295 | if (!lcu) { | 296 | if (!lcu) { |
296 | DBF_EVENT_DEVID(DBF_ERR, device->cdev, | 297 | DBF_EVENT_DEVID(DBF_ERR, device->cdev, |
297 | "could not find lcu for %04x %02x", | 298 | "could not find lcu for %04x %02x", |
298 | uid->ssid, uid->real_unit_addr); | 299 | uid.ssid, uid.real_unit_addr); |
299 | WARN_ON(1); | 300 | WARN_ON(1); |
300 | return; | 301 | return; |
301 | } | 302 | } |
@@ -314,9 +315,11 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) | |||
314 | struct alias_lcu *lcu; | 315 | struct alias_lcu *lcu; |
315 | struct alias_server *server; | 316 | struct alias_server *server; |
316 | int was_pending; | 317 | int was_pending; |
318 | struct dasd_uid uid; | ||
317 | 319 | ||
318 | private = (struct dasd_eckd_private *) device->private; | 320 | private = (struct dasd_eckd_private *) device->private; |
319 | lcu = private->lcu; | 321 | lcu = private->lcu; |
322 | device->discipline->get_uid(device, &uid); | ||
320 | spin_lock_irqsave(&lcu->lock, flags); | 323 | spin_lock_irqsave(&lcu->lock, flags); |
321 | list_del_init(&device->alias_list); | 324 | list_del_init(&device->alias_list); |
322 | /* make sure that the workers don't use this device */ | 325 | /* 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) | |||
353 | _schedule_lcu_update(lcu, NULL); | 356 | _schedule_lcu_update(lcu, NULL); |
354 | spin_unlock(&lcu->lock); | 357 | spin_unlock(&lcu->lock); |
355 | } | 358 | } |
356 | server = _find_server(&private->uid); | 359 | server = _find_server(&uid); |
357 | if (server && list_empty(&server->lculist)) { | 360 | if (server && list_empty(&server->lculist)) { |
358 | list_del(&server->server); | 361 | list_del(&server->server); |
359 | _free_server(server); | 362 | _free_server(server); |
@@ -366,19 +369,30 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) | |||
366 | * in the lcu is up to date and will update the device uid before | 369 | * in the lcu is up to date and will update the device uid before |
367 | * adding it to a pav group. | 370 | * adding it to a pav group. |
368 | */ | 371 | */ |
372 | |||
369 | static int _add_device_to_lcu(struct alias_lcu *lcu, | 373 | static int _add_device_to_lcu(struct alias_lcu *lcu, |
370 | struct dasd_device *device) | 374 | struct dasd_device *device, |
375 | struct dasd_device *pos) | ||
371 | { | 376 | { |
372 | 377 | ||
373 | struct dasd_eckd_private *private; | 378 | struct dasd_eckd_private *private; |
374 | struct alias_pav_group *group; | 379 | struct alias_pav_group *group; |
375 | struct dasd_uid *uid; | 380 | struct dasd_uid uid; |
381 | unsigned long flags; | ||
376 | 382 | ||
377 | private = (struct dasd_eckd_private *) device->private; | 383 | private = (struct dasd_eckd_private *) device->private; |
378 | uid = &private->uid; | 384 | |
379 | uid->type = lcu->uac->unit[uid->real_unit_addr].ua_type; | 385 | /* only lock if not already locked */ |
380 | uid->base_unit_addr = lcu->uac->unit[uid->real_unit_addr].base_ua; | 386 | if (device != pos) |
381 | dasd_set_uid(device->cdev, &private->uid); | 387 | spin_lock_irqsave_nested(get_ccwdev_lock(device->cdev), flags, |
388 | CDEV_NESTED_SECOND); | ||
389 | private->uid.type = lcu->uac->unit[private->uid.real_unit_addr].ua_type; | ||
390 | private->uid.base_unit_addr = | ||
391 | lcu->uac->unit[private->uid.real_unit_addr].base_ua; | ||
392 | uid = private->uid; | ||
393 | |||
394 | if (device != pos) | ||
395 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
382 | 396 | ||
383 | /* if we have no PAV anyway, we don't need to bother with PAV groups */ | 397 | /* if we have no PAV anyway, we don't need to bother with PAV groups */ |
384 | if (lcu->pav == NO_PAV) { | 398 | if (lcu->pav == NO_PAV) { |
@@ -386,25 +400,25 @@ static int _add_device_to_lcu(struct alias_lcu *lcu, | |||
386 | return 0; | 400 | return 0; |
387 | } | 401 | } |
388 | 402 | ||
389 | group = _find_group(lcu, uid); | 403 | group = _find_group(lcu, &uid); |
390 | if (!group) { | 404 | if (!group) { |
391 | group = kzalloc(sizeof(*group), GFP_ATOMIC); | 405 | group = kzalloc(sizeof(*group), GFP_ATOMIC); |
392 | if (!group) | 406 | if (!group) |
393 | return -ENOMEM; | 407 | return -ENOMEM; |
394 | memcpy(group->uid.vendor, uid->vendor, sizeof(uid->vendor)); | 408 | memcpy(group->uid.vendor, uid.vendor, sizeof(uid.vendor)); |
395 | memcpy(group->uid.serial, uid->serial, sizeof(uid->serial)); | 409 | memcpy(group->uid.serial, uid.serial, sizeof(uid.serial)); |
396 | group->uid.ssid = uid->ssid; | 410 | group->uid.ssid = uid.ssid; |
397 | if (uid->type == UA_BASE_DEVICE) | 411 | if (uid.type == UA_BASE_DEVICE) |
398 | group->uid.base_unit_addr = uid->real_unit_addr; | 412 | group->uid.base_unit_addr = uid.real_unit_addr; |
399 | else | 413 | else |
400 | group->uid.base_unit_addr = uid->base_unit_addr; | 414 | group->uid.base_unit_addr = uid.base_unit_addr; |
401 | memcpy(group->uid.vduit, uid->vduit, sizeof(uid->vduit)); | 415 | memcpy(group->uid.vduit, uid.vduit, sizeof(uid.vduit)); |
402 | INIT_LIST_HEAD(&group->group); | 416 | INIT_LIST_HEAD(&group->group); |
403 | INIT_LIST_HEAD(&group->baselist); | 417 | INIT_LIST_HEAD(&group->baselist); |
404 | INIT_LIST_HEAD(&group->aliaslist); | 418 | INIT_LIST_HEAD(&group->aliaslist); |
405 | list_add(&group->group, &lcu->grouplist); | 419 | list_add(&group->group, &lcu->grouplist); |
406 | } | 420 | } |
407 | if (uid->type == UA_BASE_DEVICE) | 421 | if (uid.type == UA_BASE_DEVICE) |
408 | list_move(&device->alias_list, &group->baselist); | 422 | list_move(&device->alias_list, &group->baselist); |
409 | else | 423 | else |
410 | list_move(&device->alias_list, &group->aliaslist); | 424 | list_move(&device->alias_list, &group->aliaslist); |
@@ -525,7 +539,10 @@ static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu) | |||
525 | if (rc) | 539 | if (rc) |
526 | return rc; | 540 | return rc; |
527 | 541 | ||
528 | spin_lock_irqsave(&lcu->lock, flags); | 542 | /* need to take cdev lock before lcu lock */ |
543 | spin_lock_irqsave_nested(get_ccwdev_lock(refdev->cdev), flags, | ||
544 | CDEV_NESTED_FIRST); | ||
545 | spin_lock(&lcu->lock); | ||
529 | lcu->pav = NO_PAV; | 546 | lcu->pav = NO_PAV; |
530 | for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) { | 547 | for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) { |
531 | switch (lcu->uac->unit[i].ua_type) { | 548 | switch (lcu->uac->unit[i].ua_type) { |
@@ -542,9 +559,10 @@ static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu) | |||
542 | 559 | ||
543 | list_for_each_entry_safe(device, tempdev, &lcu->active_devices, | 560 | list_for_each_entry_safe(device, tempdev, &lcu->active_devices, |
544 | alias_list) { | 561 | alias_list) { |
545 | _add_device_to_lcu(lcu, device); | 562 | _add_device_to_lcu(lcu, device, refdev); |
546 | } | 563 | } |
547 | spin_unlock_irqrestore(&lcu->lock, flags); | 564 | spin_unlock(&lcu->lock); |
565 | spin_unlock_irqrestore(get_ccwdev_lock(refdev->cdev), flags); | ||
548 | return 0; | 566 | return 0; |
549 | } | 567 | } |
550 | 568 | ||
@@ -628,9 +646,12 @@ int dasd_alias_add_device(struct dasd_device *device) | |||
628 | private = (struct dasd_eckd_private *) device->private; | 646 | private = (struct dasd_eckd_private *) device->private; |
629 | lcu = private->lcu; | 647 | lcu = private->lcu; |
630 | rc = 0; | 648 | rc = 0; |
631 | spin_lock_irqsave(&lcu->lock, flags); | 649 | |
650 | /* need to take cdev lock before lcu lock */ | ||
651 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
652 | spin_lock(&lcu->lock); | ||
632 | if (!(lcu->flags & UPDATE_PENDING)) { | 653 | if (!(lcu->flags & UPDATE_PENDING)) { |
633 | rc = _add_device_to_lcu(lcu, device); | 654 | rc = _add_device_to_lcu(lcu, device, device); |
634 | if (rc) | 655 | if (rc) |
635 | lcu->flags |= UPDATE_PENDING; | 656 | lcu->flags |= UPDATE_PENDING; |
636 | } | 657 | } |
@@ -638,10 +659,19 @@ int dasd_alias_add_device(struct dasd_device *device) | |||
638 | list_move(&device->alias_list, &lcu->active_devices); | 659 | list_move(&device->alias_list, &lcu->active_devices); |
639 | _schedule_lcu_update(lcu, device); | 660 | _schedule_lcu_update(lcu, device); |
640 | } | 661 | } |
641 | spin_unlock_irqrestore(&lcu->lock, flags); | 662 | spin_unlock(&lcu->lock); |
663 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
642 | return rc; | 664 | return rc; |
643 | } | 665 | } |
644 | 666 | ||
667 | int dasd_alias_update_add_device(struct dasd_device *device) | ||
668 | { | ||
669 | struct dasd_eckd_private *private; | ||
670 | private = (struct dasd_eckd_private *) device->private; | ||
671 | private->lcu->flags |= UPDATE_PENDING; | ||
672 | return dasd_alias_add_device(device); | ||
673 | } | ||
674 | |||
645 | int dasd_alias_remove_device(struct dasd_device *device) | 675 | int dasd_alias_remove_device(struct dasd_device *device) |
646 | { | 676 | { |
647 | struct dasd_eckd_private *private; | 677 | struct dasd_eckd_private *private; |
@@ -740,19 +770,30 @@ static void _restart_all_base_devices_on_lcu(struct alias_lcu *lcu) | |||
740 | struct alias_pav_group *pavgroup; | 770 | struct alias_pav_group *pavgroup; |
741 | struct dasd_device *device; | 771 | struct dasd_device *device; |
742 | struct dasd_eckd_private *private; | 772 | struct dasd_eckd_private *private; |
773 | unsigned long flags; | ||
743 | 774 | ||
744 | /* active and inactive list can contain alias as well as base devices */ | 775 | /* active and inactive list can contain alias as well as base devices */ |
745 | list_for_each_entry(device, &lcu->active_devices, alias_list) { | 776 | list_for_each_entry(device, &lcu->active_devices, alias_list) { |
746 | private = (struct dasd_eckd_private *) device->private; | 777 | private = (struct dasd_eckd_private *) device->private; |
747 | if (private->uid.type != UA_BASE_DEVICE) | 778 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
779 | if (private->uid.type != UA_BASE_DEVICE) { | ||
780 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), | ||
781 | flags); | ||
748 | continue; | 782 | continue; |
783 | } | ||
784 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
749 | dasd_schedule_block_bh(device->block); | 785 | dasd_schedule_block_bh(device->block); |
750 | dasd_schedule_device_bh(device); | 786 | dasd_schedule_device_bh(device); |
751 | } | 787 | } |
752 | list_for_each_entry(device, &lcu->inactive_devices, alias_list) { | 788 | list_for_each_entry(device, &lcu->inactive_devices, alias_list) { |
753 | private = (struct dasd_eckd_private *) device->private; | 789 | private = (struct dasd_eckd_private *) device->private; |
754 | if (private->uid.type != UA_BASE_DEVICE) | 790 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
791 | if (private->uid.type != UA_BASE_DEVICE) { | ||
792 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), | ||
793 | flags); | ||
755 | continue; | 794 | continue; |
795 | } | ||
796 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
756 | dasd_schedule_block_bh(device->block); | 797 | dasd_schedule_block_bh(device->block); |
757 | dasd_schedule_device_bh(device); | 798 | dasd_schedule_device_bh(device); |
758 | } | 799 | } |
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 { | |||
49 | unsigned int devindex; | 49 | unsigned int devindex; |
50 | unsigned short features; | 50 | unsigned short features; |
51 | struct dasd_device *device; | 51 | struct dasd_device *device; |
52 | struct dasd_uid uid; | ||
53 | }; | 52 | }; |
54 | 53 | ||
55 | /* | 54 | /* |
@@ -936,42 +935,46 @@ dasd_device_status_show(struct device *dev, struct device_attribute *attr, | |||
936 | 935 | ||
937 | static DEVICE_ATTR(status, 0444, dasd_device_status_show, NULL); | 936 | static DEVICE_ATTR(status, 0444, dasd_device_status_show, NULL); |
938 | 937 | ||
939 | static ssize_t | 938 | static ssize_t dasd_alias_show(struct device *dev, |
940 | dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf) | 939 | struct device_attribute *attr, char *buf) |
941 | { | 940 | { |
942 | struct dasd_devmap *devmap; | 941 | struct dasd_device *device; |
943 | int alias; | 942 | struct dasd_uid uid; |
944 | 943 | ||
945 | devmap = dasd_find_busid(dev_name(dev)); | 944 | device = dasd_device_from_cdev(to_ccwdev(dev)); |
946 | spin_lock(&dasd_devmap_lock); | 945 | if (IS_ERR(device)) |
947 | if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) { | ||
948 | spin_unlock(&dasd_devmap_lock); | ||
949 | return sprintf(buf, "0\n"); | 946 | return sprintf(buf, "0\n"); |
947 | |||
948 | if (device->discipline && device->discipline->get_uid && | ||
949 | !device->discipline->get_uid(device, &uid)) { | ||
950 | if (uid.type == UA_BASE_PAV_ALIAS || | ||
951 | uid.type == UA_HYPER_PAV_ALIAS) | ||
952 | return sprintf(buf, "1\n"); | ||
950 | } | 953 | } |
951 | if (devmap->uid.type == UA_BASE_PAV_ALIAS || | 954 | dasd_put_device(device); |
952 | devmap->uid.type == UA_HYPER_PAV_ALIAS) | 955 | |
953 | alias = 1; | 956 | return sprintf(buf, "0\n"); |
954 | else | ||
955 | alias = 0; | ||
956 | spin_unlock(&dasd_devmap_lock); | ||
957 | return sprintf(buf, alias ? "1\n" : "0\n"); | ||
958 | } | 957 | } |
959 | 958 | ||
960 | static DEVICE_ATTR(alias, 0444, dasd_alias_show, NULL); | 959 | static DEVICE_ATTR(alias, 0444, dasd_alias_show, NULL); |
961 | 960 | ||
962 | static ssize_t | 961 | static ssize_t dasd_vendor_show(struct device *dev, |
963 | dasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) | 962 | struct device_attribute *attr, char *buf) |
964 | { | 963 | { |
965 | struct dasd_devmap *devmap; | 964 | struct dasd_device *device; |
965 | struct dasd_uid uid; | ||
966 | char *vendor; | 966 | char *vendor; |
967 | 967 | ||
968 | devmap = dasd_find_busid(dev_name(dev)); | 968 | device = dasd_device_from_cdev(to_ccwdev(dev)); |
969 | spin_lock(&dasd_devmap_lock); | 969 | vendor = ""; |
970 | if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0) | 970 | if (IS_ERR(device)) |
971 | vendor = devmap->uid.vendor; | 971 | return snprintf(buf, PAGE_SIZE, "%s\n", vendor); |
972 | else | 972 | |
973 | vendor = ""; | 973 | if (device->discipline && device->discipline->get_uid && |
974 | spin_unlock(&dasd_devmap_lock); | 974 | !device->discipline->get_uid(device, &uid)) |
975 | vendor = uid.vendor; | ||
976 | |||
977 | dasd_put_device(device); | ||
975 | 978 | ||
976 | return snprintf(buf, PAGE_SIZE, "%s\n", vendor); | 979 | return snprintf(buf, PAGE_SIZE, "%s\n", vendor); |
977 | } | 980 | } |
@@ -985,48 +988,51 @@ static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL); | |||
985 | static ssize_t | 988 | static ssize_t |
986 | dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) | 989 | dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) |
987 | { | 990 | { |
988 | struct dasd_devmap *devmap; | 991 | struct dasd_device *device; |
992 | struct dasd_uid uid; | ||
989 | char uid_string[UID_STRLEN]; | 993 | char uid_string[UID_STRLEN]; |
990 | char ua_string[3]; | 994 | char ua_string[3]; |
991 | struct dasd_uid *uid; | ||
992 | 995 | ||
993 | devmap = dasd_find_busid(dev_name(dev)); | 996 | device = dasd_device_from_cdev(to_ccwdev(dev)); |
994 | spin_lock(&dasd_devmap_lock); | 997 | uid_string[0] = 0; |
995 | if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) { | 998 | if (IS_ERR(device)) |
996 | spin_unlock(&dasd_devmap_lock); | 999 | return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); |
997 | return sprintf(buf, "\n"); | 1000 | |
998 | } | 1001 | if (device->discipline && device->discipline->get_uid && |
999 | uid = &devmap->uid; | 1002 | !device->discipline->get_uid(device, &uid)) { |
1000 | switch (uid->type) { | 1003 | switch (uid.type) { |
1001 | case UA_BASE_DEVICE: | 1004 | case UA_BASE_DEVICE: |
1002 | sprintf(ua_string, "%02x", uid->real_unit_addr); | 1005 | snprintf(ua_string, sizeof(ua_string), "%02x", |
1003 | break; | 1006 | uid.real_unit_addr); |
1004 | case UA_BASE_PAV_ALIAS: | 1007 | break; |
1005 | sprintf(ua_string, "%02x", uid->base_unit_addr); | 1008 | case UA_BASE_PAV_ALIAS: |
1006 | break; | 1009 | snprintf(ua_string, sizeof(ua_string), "%02x", |
1007 | case UA_HYPER_PAV_ALIAS: | 1010 | uid.base_unit_addr); |
1008 | sprintf(ua_string, "xx"); | 1011 | break; |
1009 | break; | 1012 | case UA_HYPER_PAV_ALIAS: |
1010 | default: | 1013 | snprintf(ua_string, sizeof(ua_string), "xx"); |
1011 | /* should not happen, treat like base device */ | 1014 | break; |
1012 | sprintf(ua_string, "%02x", uid->real_unit_addr); | 1015 | default: |
1013 | break; | 1016 | /* should not happen, treat like base device */ |
1017 | snprintf(ua_string, sizeof(ua_string), "%02x", | ||
1018 | uid.real_unit_addr); | ||
1019 | break; | ||
1020 | } | ||
1021 | |||
1022 | if (strlen(uid.vduit) > 0) | ||
1023 | snprintf(uid_string, sizeof(uid_string), | ||
1024 | "%s.%s.%04x.%s.%s", | ||
1025 | uid.vendor, uid.serial, uid.ssid, ua_string, | ||
1026 | uid.vduit); | ||
1027 | else | ||
1028 | snprintf(uid_string, sizeof(uid_string), | ||
1029 | "%s.%s.%04x.%s", | ||
1030 | uid.vendor, uid.serial, uid.ssid, ua_string); | ||
1014 | } | 1031 | } |
1015 | if (strlen(uid->vduit) > 0) | 1032 | dasd_put_device(device); |
1016 | snprintf(uid_string, sizeof(uid_string), | 1033 | |
1017 | "%s.%s.%04x.%s.%s", | ||
1018 | uid->vendor, uid->serial, | ||
1019 | uid->ssid, ua_string, | ||
1020 | uid->vduit); | ||
1021 | else | ||
1022 | snprintf(uid_string, sizeof(uid_string), | ||
1023 | "%s.%s.%04x.%s", | ||
1024 | uid->vendor, uid->serial, | ||
1025 | uid->ssid, ua_string); | ||
1026 | spin_unlock(&dasd_devmap_lock); | ||
1027 | return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); | 1034 | return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); |
1028 | } | 1035 | } |
1029 | |||
1030 | static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL); | 1036 | static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL); |
1031 | 1037 | ||
1032 | /* | 1038 | /* |
@@ -1094,50 +1100,6 @@ static struct attribute_group dasd_attr_group = { | |||
1094 | }; | 1100 | }; |
1095 | 1101 | ||
1096 | /* | 1102 | /* |
1097 | * Return copy of the device unique identifier. | ||
1098 | */ | ||
1099 | int | ||
1100 | dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid) | ||
1101 | { | ||
1102 | struct dasd_devmap *devmap; | ||
1103 | |||
1104 | devmap = dasd_find_busid(dev_name(&cdev->dev)); | ||
1105 | if (IS_ERR(devmap)) | ||
1106 | return PTR_ERR(devmap); | ||
1107 | spin_lock(&dasd_devmap_lock); | ||
1108 | *uid = devmap->uid; | ||
1109 | spin_unlock(&dasd_devmap_lock); | ||
1110 | return 0; | ||
1111 | } | ||
1112 | EXPORT_SYMBOL_GPL(dasd_get_uid); | ||
1113 | |||
1114 | /* | ||
1115 | * Register the given device unique identifier into devmap struct. | ||
1116 | * In addition check if the related storage server subsystem ID is already | ||
1117 | * contained in the dasd_server_ssid_list. If subsystem ID is not contained, | ||
1118 | * create new entry. | ||
1119 | * Return 0 if server was already in serverlist, | ||
1120 | * 1 if the server was added successful | ||
1121 | * <0 in case of error. | ||
1122 | */ | ||
1123 | int | ||
1124 | dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid) | ||
1125 | { | ||
1126 | struct dasd_devmap *devmap; | ||
1127 | |||
1128 | devmap = dasd_find_busid(dev_name(&cdev->dev)); | ||
1129 | if (IS_ERR(devmap)) | ||
1130 | return PTR_ERR(devmap); | ||
1131 | |||
1132 | spin_lock(&dasd_devmap_lock); | ||
1133 | devmap->uid = *uid; | ||
1134 | spin_unlock(&dasd_devmap_lock); | ||
1135 | |||
1136 | return 0; | ||
1137 | } | ||
1138 | EXPORT_SYMBOL_GPL(dasd_set_uid); | ||
1139 | |||
1140 | /* | ||
1141 | * Return value of the specified feature. | 1103 | * Return value of the specified feature. |
1142 | */ | 1104 | */ |
1143 | int | 1105 | 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) | |||
692 | /* | 692 | /* |
693 | * Generate device unique id that specifies the physical device. | 693 | * Generate device unique id that specifies the physical device. |
694 | */ | 694 | */ |
695 | static int dasd_eckd_generate_uid(struct dasd_device *device, | 695 | static int dasd_eckd_generate_uid(struct dasd_device *device) |
696 | struct dasd_uid *uid) | ||
697 | { | 696 | { |
698 | struct dasd_eckd_private *private; | 697 | struct dasd_eckd_private *private; |
698 | struct dasd_uid *uid; | ||
699 | int count; | 699 | int count; |
700 | unsigned long flags; | ||
700 | 701 | ||
701 | private = (struct dasd_eckd_private *) device->private; | 702 | private = (struct dasd_eckd_private *) device->private; |
702 | if (!private) | 703 | if (!private) |
703 | return -ENODEV; | 704 | return -ENODEV; |
704 | if (!private->ned || !private->gneq) | 705 | if (!private->ned || !private->gneq) |
705 | return -ENODEV; | 706 | return -ENODEV; |
706 | 707 | uid = &private->uid; | |
708 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
707 | memset(uid, 0, sizeof(struct dasd_uid)); | 709 | memset(uid, 0, sizeof(struct dasd_uid)); |
708 | memcpy(uid->vendor, private->ned->HDA_manufacturer, | 710 | memcpy(uid->vendor, private->ned->HDA_manufacturer, |
709 | sizeof(uid->vendor) - 1); | 711 | sizeof(uid->vendor) - 1); |
@@ -726,9 +728,25 @@ static int dasd_eckd_generate_uid(struct dasd_device *device, | |||
726 | private->vdsneq->uit[count]); | 728 | private->vdsneq->uit[count]); |
727 | } | 729 | } |
728 | } | 730 | } |
731 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
729 | return 0; | 732 | return 0; |
730 | } | 733 | } |
731 | 734 | ||
735 | static int dasd_eckd_get_uid(struct dasd_device *device, struct dasd_uid *uid) | ||
736 | { | ||
737 | struct dasd_eckd_private *private; | ||
738 | unsigned long flags; | ||
739 | |||
740 | if (device->private) { | ||
741 | private = (struct dasd_eckd_private *)device->private; | ||
742 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
743 | *uid = private->uid; | ||
744 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
745 | return 0; | ||
746 | } | ||
747 | return -EINVAL; | ||
748 | } | ||
749 | |||
732 | static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device, | 750 | static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device, |
733 | void *rcd_buffer, | 751 | void *rcd_buffer, |
734 | struct ciw *ciw, __u8 lpm) | 752 | struct ciw *ciw, __u8 lpm) |
@@ -1088,6 +1106,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
1088 | { | 1106 | { |
1089 | struct dasd_eckd_private *private; | 1107 | struct dasd_eckd_private *private; |
1090 | struct dasd_block *block; | 1108 | struct dasd_block *block; |
1109 | struct dasd_uid temp_uid; | ||
1091 | int is_known, rc; | 1110 | int is_known, rc; |
1092 | int readonly; | 1111 | int readonly; |
1093 | 1112 | ||
@@ -1124,13 +1143,13 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
1124 | if (rc) | 1143 | if (rc) |
1125 | goto out_err1; | 1144 | goto out_err1; |
1126 | 1145 | ||
1127 | /* Generate device unique id and register in devmap */ | 1146 | /* Generate device unique id */ |
1128 | rc = dasd_eckd_generate_uid(device, &private->uid); | 1147 | rc = dasd_eckd_generate_uid(device); |
1129 | if (rc) | 1148 | if (rc) |
1130 | goto out_err1; | 1149 | goto out_err1; |
1131 | dasd_set_uid(device->cdev, &private->uid); | ||
1132 | 1150 | ||
1133 | if (private->uid.type == UA_BASE_DEVICE) { | 1151 | dasd_eckd_get_uid(device, &temp_uid); |
1152 | if (temp_uid.type == UA_BASE_DEVICE) { | ||
1134 | block = dasd_alloc_block(); | 1153 | block = dasd_alloc_block(); |
1135 | if (IS_ERR(block)) { | 1154 | if (IS_ERR(block)) { |
1136 | DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", | 1155 | DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", |
@@ -1451,6 +1470,7 @@ static int dasd_eckd_ready_to_online(struct dasd_device *device) | |||
1451 | 1470 | ||
1452 | static int dasd_eckd_online_to_ready(struct dasd_device *device) | 1471 | static int dasd_eckd_online_to_ready(struct dasd_device *device) |
1453 | { | 1472 | { |
1473 | cancel_work_sync(&device->reload_device); | ||
1454 | return dasd_alias_remove_device(device); | 1474 | return dasd_alias_remove_device(device); |
1455 | }; | 1475 | }; |
1456 | 1476 | ||
@@ -1709,10 +1729,27 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, | |||
1709 | { | 1729 | { |
1710 | char mask; | 1730 | char mask; |
1711 | char *sense = NULL; | 1731 | char *sense = NULL; |
1732 | struct dasd_eckd_private *private; | ||
1712 | 1733 | ||
1734 | private = (struct dasd_eckd_private *) device->private; | ||
1713 | /* first of all check for state change pending interrupt */ | 1735 | /* first of all check for state change pending interrupt */ |
1714 | mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; | 1736 | mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; |
1715 | if ((scsw_dstat(&irb->scsw) & mask) == mask) { | 1737 | if ((scsw_dstat(&irb->scsw) & mask) == mask) { |
1738 | /* for alias only and not in offline processing*/ | ||
1739 | if (!device->block && private->lcu && | ||
1740 | !test_bit(DASD_FLAG_OFFLINE, &device->flags)) { | ||
1741 | /* | ||
1742 | * the state change could be caused by an alias | ||
1743 | * reassignment remove device from alias handling | ||
1744 | * to prevent new requests from being scheduled on | ||
1745 | * the wrong alias device | ||
1746 | */ | ||
1747 | dasd_alias_remove_device(device); | ||
1748 | |||
1749 | /* schedule worker to reload device */ | ||
1750 | dasd_reload_device(device); | ||
1751 | } | ||
1752 | |||
1716 | dasd_generic_handle_state_change(device); | 1753 | dasd_generic_handle_state_change(device); |
1717 | return; | 1754 | return; |
1718 | } | 1755 | } |
@@ -3259,7 +3296,7 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, | |||
3259 | dasd_eckd_dump_sense_ccw(device, req, irb); | 3296 | dasd_eckd_dump_sense_ccw(device, req, irb); |
3260 | } | 3297 | } |
3261 | 3298 | ||
3262 | int dasd_eckd_pm_freeze(struct dasd_device *device) | 3299 | static int dasd_eckd_pm_freeze(struct dasd_device *device) |
3263 | { | 3300 | { |
3264 | /* | 3301 | /* |
3265 | * the device should be disconnected from our LCU structure | 3302 | * the device should be disconnected from our LCU structure |
@@ -3272,7 +3309,7 @@ int dasd_eckd_pm_freeze(struct dasd_device *device) | |||
3272 | return 0; | 3309 | return 0; |
3273 | } | 3310 | } |
3274 | 3311 | ||
3275 | int dasd_eckd_restore_device(struct dasd_device *device) | 3312 | static int dasd_eckd_restore_device(struct dasd_device *device) |
3276 | { | 3313 | { |
3277 | struct dasd_eckd_private *private; | 3314 | struct dasd_eckd_private *private; |
3278 | struct dasd_eckd_characteristics temp_rdc_data; | 3315 | struct dasd_eckd_characteristics temp_rdc_data; |
@@ -3287,15 +3324,16 @@ int dasd_eckd_restore_device(struct dasd_device *device) | |||
3287 | if (rc) | 3324 | if (rc) |
3288 | goto out_err; | 3325 | goto out_err; |
3289 | 3326 | ||
3290 | /* Generate device unique id and register in devmap */ | 3327 | dasd_eckd_get_uid(device, &temp_uid); |
3291 | rc = dasd_eckd_generate_uid(device, &private->uid); | 3328 | /* Generate device unique id */ |
3292 | dasd_get_uid(device->cdev, &temp_uid); | 3329 | rc = dasd_eckd_generate_uid(device); |
3330 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
3293 | if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0) | 3331 | if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0) |
3294 | dev_err(&device->cdev->dev, "The UID of the DASD has " | 3332 | dev_err(&device->cdev->dev, "The UID of the DASD has " |
3295 | "changed\n"); | 3333 | "changed\n"); |
3334 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
3296 | if (rc) | 3335 | if (rc) |
3297 | goto out_err; | 3336 | goto out_err; |
3298 | dasd_set_uid(device->cdev, &private->uid); | ||
3299 | 3337 | ||
3300 | /* register lcu with alias handling, enable PAV if this is a new lcu */ | 3338 | /* register lcu with alias handling, enable PAV if this is a new lcu */ |
3301 | is_known = dasd_alias_make_device_known_to_lcu(device); | 3339 | is_known = dasd_alias_make_device_known_to_lcu(device); |
@@ -3336,6 +3374,56 @@ out_err: | |||
3336 | return -1; | 3374 | return -1; |
3337 | } | 3375 | } |
3338 | 3376 | ||
3377 | static int dasd_eckd_reload_device(struct dasd_device *device) | ||
3378 | { | ||
3379 | struct dasd_eckd_private *private; | ||
3380 | int rc, old_base; | ||
3381 | char print_uid[60]; | ||
3382 | struct dasd_uid uid; | ||
3383 | unsigned long flags; | ||
3384 | |||
3385 | private = (struct dasd_eckd_private *) device->private; | ||
3386 | |||
3387 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
3388 | old_base = private->uid.base_unit_addr; | ||
3389 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
3390 | |||
3391 | /* Read Configuration Data */ | ||
3392 | rc = dasd_eckd_read_conf(device); | ||
3393 | if (rc) | ||
3394 | goto out_err; | ||
3395 | |||
3396 | rc = dasd_eckd_generate_uid(device); | ||
3397 | if (rc) | ||
3398 | goto out_err; | ||
3399 | /* | ||
3400 | * update unit address configuration and | ||
3401 | * add device to alias management | ||
3402 | */ | ||
3403 | dasd_alias_update_add_device(device); | ||
3404 | |||
3405 | dasd_eckd_get_uid(device, &uid); | ||
3406 | |||
3407 | if (old_base != uid.base_unit_addr) { | ||
3408 | if (strlen(uid.vduit) > 0) | ||
3409 | snprintf(print_uid, sizeof(print_uid), | ||
3410 | "%s.%s.%04x.%02x.%s", uid.vendor, uid.serial, | ||
3411 | uid.ssid, uid.base_unit_addr, uid.vduit); | ||
3412 | else | ||
3413 | snprintf(print_uid, sizeof(print_uid), | ||
3414 | "%s.%s.%04x.%02x", uid.vendor, uid.serial, | ||
3415 | uid.ssid, uid.base_unit_addr); | ||
3416 | |||
3417 | dev_info(&device->cdev->dev, | ||
3418 | "An Alias device was reassigned to a new base device " | ||
3419 | "with UID: %s\n", print_uid); | ||
3420 | } | ||
3421 | return 0; | ||
3422 | |||
3423 | out_err: | ||
3424 | return -1; | ||
3425 | } | ||
3426 | |||
3339 | static struct ccw_driver dasd_eckd_driver = { | 3427 | static struct ccw_driver dasd_eckd_driver = { |
3340 | .name = "dasd-eckd", | 3428 | .name = "dasd-eckd", |
3341 | .owner = THIS_MODULE, | 3429 | .owner = THIS_MODULE, |
@@ -3389,6 +3477,8 @@ static struct dasd_discipline dasd_eckd_discipline = { | |||
3389 | .ioctl = dasd_eckd_ioctl, | 3477 | .ioctl = dasd_eckd_ioctl, |
3390 | .freeze = dasd_eckd_pm_freeze, | 3478 | .freeze = dasd_eckd_pm_freeze, |
3391 | .restore = dasd_eckd_restore_device, | 3479 | .restore = dasd_eckd_restore_device, |
3480 | .reload = dasd_eckd_reload_device, | ||
3481 | .get_uid = dasd_eckd_get_uid, | ||
3392 | }; | 3482 | }; |
3393 | 3483 | ||
3394 | static int __init | 3484 | 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 { | |||
426 | struct dasd_device *next; | 426 | struct dasd_device *next; |
427 | }; | 427 | }; |
428 | 428 | ||
429 | |||
430 | struct dasd_eckd_private { | 429 | struct dasd_eckd_private { |
431 | struct dasd_eckd_characteristics rdc_data; | 430 | struct dasd_eckd_characteristics rdc_data; |
432 | u8 *conf_data; | 431 | u8 *conf_data; |
@@ -463,4 +462,5 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *, struct irb *); | |||
463 | void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *); | 462 | void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *); |
464 | void dasd_alias_lcu_setup_complete(struct dasd_device *); | 463 | void dasd_alias_lcu_setup_complete(struct dasd_device *); |
465 | void dasd_alias_wait_for_lcu_setup(struct dasd_device *); | 464 | void dasd_alias_wait_for_lcu_setup(struct dasd_device *); |
465 | int dasd_alias_update_add_device(struct dasd_device *); | ||
466 | #endif /* DASD_ECKD_H */ | 466 | #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; | |||
81 | #define DASD_SIM_MSG_TO_OP 0x03 | 81 | #define DASD_SIM_MSG_TO_OP 0x03 |
82 | #define DASD_SIM_LOG 0x0C | 82 | #define DASD_SIM_LOG 0x0C |
83 | 83 | ||
84 | /* lock class for nested cdev lock */ | ||
85 | #define CDEV_NESTED_FIRST 1 | ||
86 | #define CDEV_NESTED_SECOND 2 | ||
87 | |||
84 | /* | 88 | /* |
85 | * SECTION: MACROs for klogd and s390 debug feature (dbf) | 89 | * SECTION: MACROs for klogd and s390 debug feature (dbf) |
86 | */ | 90 | */ |
@@ -229,6 +233,24 @@ struct dasd_ccw_req { | |||
229 | typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *); | 233 | typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *); |
230 | 234 | ||
231 | /* | 235 | /* |
236 | * Unique identifier for dasd device. | ||
237 | */ | ||
238 | #define UA_NOT_CONFIGURED 0x00 | ||
239 | #define UA_BASE_DEVICE 0x01 | ||
240 | #define UA_BASE_PAV_ALIAS 0x02 | ||
241 | #define UA_HYPER_PAV_ALIAS 0x03 | ||
242 | |||
243 | struct dasd_uid { | ||
244 | __u8 type; | ||
245 | char vendor[4]; | ||
246 | char serial[15]; | ||
247 | __u16 ssid; | ||
248 | __u8 real_unit_addr; | ||
249 | __u8 base_unit_addr; | ||
250 | char vduit[33]; | ||
251 | }; | ||
252 | |||
253 | /* | ||
232 | * the struct dasd_discipline is | 254 | * the struct dasd_discipline is |
233 | * sth like a table of virtual functions, if you think of dasd_eckd | 255 | * sth like a table of virtual functions, if you think of dasd_eckd |
234 | * inheriting dasd... | 256 | * inheriting dasd... |
@@ -312,28 +334,15 @@ struct dasd_discipline { | |||
312 | /* suspend/resume functions */ | 334 | /* suspend/resume functions */ |
313 | int (*freeze) (struct dasd_device *); | 335 | int (*freeze) (struct dasd_device *); |
314 | int (*restore) (struct dasd_device *); | 336 | int (*restore) (struct dasd_device *); |
315 | }; | ||
316 | 337 | ||
317 | extern struct dasd_discipline *dasd_diag_discipline_pointer; | 338 | /* reload device after state change */ |
318 | 339 | int (*reload) (struct dasd_device *); | |
319 | /* | ||
320 | * Unique identifier for dasd device. | ||
321 | */ | ||
322 | #define UA_NOT_CONFIGURED 0x00 | ||
323 | #define UA_BASE_DEVICE 0x01 | ||
324 | #define UA_BASE_PAV_ALIAS 0x02 | ||
325 | #define UA_HYPER_PAV_ALIAS 0x03 | ||
326 | 340 | ||
327 | struct dasd_uid { | 341 | int (*get_uid) (struct dasd_device *, struct dasd_uid *); |
328 | __u8 type; | ||
329 | char vendor[4]; | ||
330 | char serial[15]; | ||
331 | __u16 ssid; | ||
332 | __u8 real_unit_addr; | ||
333 | __u8 base_unit_addr; | ||
334 | char vduit[33]; | ||
335 | }; | 342 | }; |
336 | 343 | ||
344 | extern struct dasd_discipline *dasd_diag_discipline_pointer; | ||
345 | |||
337 | /* | 346 | /* |
338 | * Notification numbers for extended error reporting notifications: | 347 | * Notification numbers for extended error reporting notifications: |
339 | * The DASD_EER_DISABLE notification is sent before a dasd_device (and it's | 348 | * The DASD_EER_DISABLE notification is sent before a dasd_device (and it's |
@@ -386,6 +395,7 @@ struct dasd_device { | |||
386 | struct tasklet_struct tasklet; | 395 | struct tasklet_struct tasklet; |
387 | struct work_struct kick_work; | 396 | struct work_struct kick_work; |
388 | struct work_struct restore_device; | 397 | struct work_struct restore_device; |
398 | struct work_struct reload_device; | ||
389 | struct timer_list timer; | 399 | struct timer_list timer; |
390 | 400 | ||
391 | debug_info_t *debug_area; | 401 | debug_info_t *debug_area; |
@@ -582,6 +592,7 @@ void dasd_enable_device(struct dasd_device *); | |||
582 | void dasd_set_target_state(struct dasd_device *, int); | 592 | void dasd_set_target_state(struct dasd_device *, int); |
583 | void dasd_kick_device(struct dasd_device *); | 593 | void dasd_kick_device(struct dasd_device *); |
584 | void dasd_restore_device(struct dasd_device *); | 594 | void dasd_restore_device(struct dasd_device *); |
595 | void dasd_reload_device(struct dasd_device *); | ||
585 | 596 | ||
586 | void dasd_add_request_head(struct dasd_ccw_req *); | 597 | void dasd_add_request_head(struct dasd_ccw_req *); |
587 | void dasd_add_request_tail(struct dasd_ccw_req *); | 598 | void dasd_add_request_tail(struct dasd_ccw_req *); |
@@ -629,8 +640,6 @@ void dasd_devmap_exit(void); | |||
629 | struct dasd_device *dasd_create_device(struct ccw_device *); | 640 | struct dasd_device *dasd_create_device(struct ccw_device *); |
630 | void dasd_delete_device(struct dasd_device *); | 641 | void dasd_delete_device(struct dasd_device *); |
631 | 642 | ||
632 | int dasd_get_uid(struct ccw_device *, struct dasd_uid *); | ||
633 | int dasd_set_uid(struct ccw_device *, struct dasd_uid *); | ||
634 | int dasd_get_feature(struct ccw_device *, int); | 643 | int dasd_get_feature(struct ccw_device *, int); |
635 | int dasd_set_feature(struct ccw_device *, int, int); | 644 | int dasd_set_feature(struct ccw_device *, int, int); |
636 | 645 | ||
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 | |||
148 | This driver depends on the IUCV support driver. | 148 | This driver depends on the IUCV support driver. |
149 | 149 | ||
150 | config VMCP | 150 | config VMCP |
151 | tristate "Support for the z/VM CP interface (VM only)" | 151 | bool "Support for the z/VM CP interface" |
152 | depends on S390 | 152 | depends on S390 |
153 | help | 153 | help |
154 | Select this option if you want to be able to interact with the control | 154 | Select this option if you want to be able to interact with the control |
155 | program on z/VM | 155 | program on z/VM |
156 | 156 | ||
157 | |||
158 | config MONREADER | 157 | config MONREADER |
159 | tristate "API for reading z/VM monitor service records" | 158 | tristate "API for reading z/VM monitor service records" |
160 | depends on IUCV | 159 | 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) | |||
484 | raw3270_del_view(&fp->view); | 484 | raw3270_del_view(&fp->view); |
485 | goto out; | 485 | goto out; |
486 | } | 486 | } |
487 | nonseekable_open(inode, filp); | ||
487 | filp->private_data = fp; | 488 | filp->private_data = fp; |
488 | out: | 489 | out: |
489 | mutex_unlock(&fs3270_mutex); | 490 | 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] = { | |||
49 | struct kbd_data * | 49 | struct kbd_data * |
50 | kbd_alloc(void) { | 50 | kbd_alloc(void) { |
51 | struct kbd_data *kbd; | 51 | struct kbd_data *kbd; |
52 | int i, len; | 52 | int i; |
53 | 53 | ||
54 | kbd = kzalloc(sizeof(struct kbd_data), GFP_KERNEL); | 54 | kbd = kzalloc(sizeof(struct kbd_data), GFP_KERNEL); |
55 | if (!kbd) | 55 | if (!kbd) |
@@ -59,12 +59,11 @@ kbd_alloc(void) { | |||
59 | goto out_kbd; | 59 | goto out_kbd; |
60 | for (i = 0; i < ARRAY_SIZE(key_maps); i++) { | 60 | for (i = 0; i < ARRAY_SIZE(key_maps); i++) { |
61 | if (key_maps[i]) { | 61 | if (key_maps[i]) { |
62 | kbd->key_maps[i] = | 62 | kbd->key_maps[i] = kmemdup(key_maps[i], |
63 | kmalloc(sizeof(u_short)*NR_KEYS, GFP_KERNEL); | 63 | sizeof(u_short) * NR_KEYS, |
64 | GFP_KERNEL); | ||
64 | if (!kbd->key_maps[i]) | 65 | if (!kbd->key_maps[i]) |
65 | goto out_maps; | 66 | goto out_maps; |
66 | memcpy(kbd->key_maps[i], key_maps[i], | ||
67 | sizeof(u_short)*NR_KEYS); | ||
68 | } | 67 | } |
69 | } | 68 | } |
70 | kbd->func_table = kzalloc(sizeof(func_table), GFP_KERNEL); | 69 | kbd->func_table = kzalloc(sizeof(func_table), GFP_KERNEL); |
@@ -72,23 +71,21 @@ kbd_alloc(void) { | |||
72 | goto out_maps; | 71 | goto out_maps; |
73 | for (i = 0; i < ARRAY_SIZE(func_table); i++) { | 72 | for (i = 0; i < ARRAY_SIZE(func_table); i++) { |
74 | if (func_table[i]) { | 73 | if (func_table[i]) { |
75 | len = strlen(func_table[i]) + 1; | 74 | kbd->func_table[i] = kstrdup(func_table[i], |
76 | kbd->func_table[i] = kmalloc(len, GFP_KERNEL); | 75 | GFP_KERNEL); |
77 | if (!kbd->func_table[i]) | 76 | if (!kbd->func_table[i]) |
78 | goto out_func; | 77 | goto out_func; |
79 | memcpy(kbd->func_table[i], func_table[i], len); | ||
80 | } | 78 | } |
81 | } | 79 | } |
82 | kbd->fn_handler = | 80 | kbd->fn_handler = |
83 | kzalloc(sizeof(fn_handler_fn *) * NR_FN_HANDLER, GFP_KERNEL); | 81 | kzalloc(sizeof(fn_handler_fn *) * NR_FN_HANDLER, GFP_KERNEL); |
84 | if (!kbd->fn_handler) | 82 | if (!kbd->fn_handler) |
85 | goto out_func; | 83 | goto out_func; |
86 | kbd->accent_table = | 84 | kbd->accent_table = kmemdup(accent_table, |
87 | kmalloc(sizeof(struct kbdiacruc)*MAX_DIACR, GFP_KERNEL); | 85 | sizeof(struct kbdiacruc) * MAX_DIACR, |
86 | GFP_KERNEL); | ||
88 | if (!kbd->accent_table) | 87 | if (!kbd->accent_table) |
89 | goto out_fn_handler; | 88 | goto out_fn_handler; |
90 | memcpy(kbd->accent_table, accent_table, | ||
91 | sizeof(struct kbdiacruc)*MAX_DIACR); | ||
92 | kbd->accent_table_size = accent_table_size; | 89 | kbd->accent_table_size = accent_table_size; |
93 | return kbd; | 90 | return kbd; |
94 | 91 | ||
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 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright IBM Corp. 2004,2007 | 2 | * Copyright IBM Corp. 2004,2010 |
3 | * Interface implementation for communication with the z/VM control program | 3 | * Interface implementation for communication with the z/VM control program |
4 | * Author(s): Christian Borntraeger <borntraeger@de.ibm.com> | ||
5 | * | 4 | * |
5 | * Author(s): Christian Borntraeger <borntraeger@de.ibm.com> | ||
6 | * | 6 | * |
7 | * z/VMs CP offers the possibility to issue commands via the diagnose code 8 | 7 | * z/VMs CP offers the possibility to issue commands via the diagnose code 8 |
8 | * this driver implements a character device that issues these commands and | 8 | * this driver implements a character device that issues these commands and |
9 | * returns the answer of CP. | 9 | * returns the answer of CP. |
10 | 10 | * | |
11 | * The idea of this driver is based on cpint from Neale Ferguson and #CP in CMS | 11 | * The idea of this driver is based on cpint from Neale Ferguson and #CP in CMS |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #define KMSG_COMPONENT "vmcp" | ||
15 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
16 | |||
17 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
18 | #include <linux/init.h> | 15 | #include <linux/init.h> |
19 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
20 | #include <linux/miscdevice.h> | 17 | #include <linux/miscdevice.h> |
21 | #include <linux/module.h> | ||
22 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
23 | #include <asm/compat.h> | 19 | #include <asm/compat.h> |
24 | #include <asm/cpcmd.h> | 20 | #include <asm/cpcmd.h> |
@@ -26,10 +22,6 @@ | |||
26 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
27 | #include "vmcp.h" | 23 | #include "vmcp.h" |
28 | 24 | ||
29 | MODULE_LICENSE("GPL"); | ||
30 | MODULE_AUTHOR("Christian Borntraeger <borntraeger@de.ibm.com>"); | ||
31 | MODULE_DESCRIPTION("z/VM CP interface"); | ||
32 | |||
33 | static debug_info_t *vmcp_debug; | 25 | static debug_info_t *vmcp_debug; |
34 | 26 | ||
35 | static int vmcp_open(struct inode *inode, struct file *file) | 27 | static int vmcp_open(struct inode *inode, struct file *file) |
@@ -197,11 +189,8 @@ static int __init vmcp_init(void) | |||
197 | { | 189 | { |
198 | int ret; | 190 | int ret; |
199 | 191 | ||
200 | if (!MACHINE_IS_VM) { | 192 | if (!MACHINE_IS_VM) |
201 | pr_warning("The z/VM CP interface device driver cannot be " | 193 | return 0; |
202 | "loaded without z/VM\n"); | ||
203 | return -ENODEV; | ||
204 | } | ||
205 | 194 | ||
206 | vmcp_debug = debug_register("vmcp", 1, 1, 240); | 195 | vmcp_debug = debug_register("vmcp", 1, 1, 240); |
207 | if (!vmcp_debug) | 196 | if (!vmcp_debug) |
@@ -214,19 +203,8 @@ static int __init vmcp_init(void) | |||
214 | } | 203 | } |
215 | 204 | ||
216 | ret = misc_register(&vmcp_dev); | 205 | ret = misc_register(&vmcp_dev); |
217 | if (ret) { | 206 | if (ret) |
218 | debug_unregister(vmcp_debug); | 207 | debug_unregister(vmcp_debug); |
219 | return ret; | 208 | return ret; |
220 | } | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static void __exit vmcp_exit(void) | ||
226 | { | ||
227 | misc_deregister(&vmcp_dev); | ||
228 | debug_unregister(vmcp_debug); | ||
229 | } | 209 | } |
230 | 210 | device_initcall(vmcp_init); | |
231 | module_init(vmcp_init); | ||
232 | module_exit(vmcp_exit); | ||
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) | |||
445 | } | 445 | } |
446 | kfree(chunk_array); | 446 | kfree(chunk_array); |
447 | filp->private_data = buf; | 447 | filp->private_data = buf; |
448 | return 0; | 448 | return nonseekable_open(inode, filp); |
449 | } | 449 | } |
450 | 450 | ||
451 | static int zcore_memmap_release(struct inode *inode, struct file *filp) | 451 | 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, | |||
473 | 473 | ||
474 | static int zcore_reipl_open(struct inode *inode, struct file *filp) | 474 | static int zcore_reipl_open(struct inode *inode, struct file *filp) |
475 | { | 475 | { |
476 | return 0; | 476 | return nonseekable_open(inode, filp); |
477 | } | 477 | } |
478 | 478 | ||
479 | static int zcore_reipl_release(struct inode *inode, struct file *filp) | 479 | 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, | |||
803 | 803 | ||
804 | static const struct file_operations chsc_fops = { | 804 | static const struct file_operations chsc_fops = { |
805 | .owner = THIS_MODULE, | 805 | .owner = THIS_MODULE, |
806 | .open = nonseekable_open, | ||
806 | .unlocked_ioctl = chsc_ioctl, | 807 | .unlocked_ioctl = chsc_ioctl, |
807 | .compat_ioctl = chsc_ioctl, | 808 | .compat_ioctl = chsc_ioctl, |
808 | }; | 809 | }; |
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) | |||
616 | struct pt_regs *old_regs; | 616 | struct pt_regs *old_regs; |
617 | 617 | ||
618 | old_regs = set_irq_regs(regs); | 618 | old_regs = set_irq_regs(regs); |
619 | s390_idle_check(); | 619 | s390_idle_check(regs, S390_lowcore.int_clock, |
620 | S390_lowcore.async_enter_timer); | ||
620 | irq_enter(); | 621 | irq_enter(); |
621 | __get_cpu_var(s390_idle).nohz_delay = 1; | 622 | __get_cpu_var(s390_idle).nohz_delay = 1; |
622 | if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) | 623 | 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) | |||
648 | static void __init | 648 | static void __init |
649 | css_generate_pgid(struct channel_subsystem *css, u32 tod_high) | 649 | css_generate_pgid(struct channel_subsystem *css, u32 tod_high) |
650 | { | 650 | { |
651 | struct cpuid cpu_id; | ||
652 | |||
651 | if (css_general_characteristics.mcss) { | 653 | if (css_general_characteristics.mcss) { |
652 | css->global_pgid.pgid_high.ext_cssid.version = 0x80; | 654 | css->global_pgid.pgid_high.ext_cssid.version = 0x80; |
653 | css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid; | 655 | css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid; |
@@ -658,8 +660,9 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high) | |||
658 | css->global_pgid.pgid_high.cpu_addr = 0; | 660 | css->global_pgid.pgid_high.cpu_addr = 0; |
659 | #endif | 661 | #endif |
660 | } | 662 | } |
661 | css->global_pgid.cpu_id = S390_lowcore.cpu_id.ident; | 663 | get_cpu_id(&cpu_id); |
662 | css->global_pgid.cpu_model = S390_lowcore.cpu_id.machine; | 664 | css->global_pgid.cpu_id = cpu_id.ident; |
665 | css->global_pgid.cpu_model = cpu_id.machine; | ||
663 | css->global_pgid.tod_high = tod_high; | 666 | css->global_pgid.tod_high = tod_high; |
664 | 667 | ||
665 | } | 668 | } |
@@ -1062,6 +1065,7 @@ static ssize_t cio_settle_write(struct file *file, const char __user *buf, | |||
1062 | } | 1065 | } |
1063 | 1066 | ||
1064 | static const struct file_operations cio_settle_proc_fops = { | 1067 | static const struct file_operations cio_settle_proc_fops = { |
1068 | .open = nonseekable_open, | ||
1065 | .write = cio_settle_write, | 1069 | .write = cio_settle_write, |
1066 | }; | 1070 | }; |
1067 | 1071 | ||
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 @@ | |||
13 | #include <asm/debug.h> | 13 | #include <asm/debug.h> |
14 | #include "chsc.h" | 14 | #include "chsc.h" |
15 | 15 | ||
16 | #define QDIO_BUSY_BIT_PATIENCE 100 /* 100 microseconds */ | 16 | #define QDIO_BUSY_BIT_PATIENCE (100 << 12) /* 100 microseconds */ |
17 | #define QDIO_INPUT_THRESHOLD 500 /* 500 microseconds */ | 17 | #define QDIO_INPUT_THRESHOLD (500 << 12) /* 500 microseconds */ |
18 | 18 | ||
19 | /* | 19 | /* |
20 | * if an asynchronous HiperSockets queue runs full, the 10 seconds timer wait | 20 | * if an asynchronous HiperSockets queue runs full, the 10 seconds timer wait |
@@ -296,10 +296,8 @@ struct qdio_q { | |||
296 | struct qdio_irq *irq_ptr; | 296 | struct qdio_irq *irq_ptr; |
297 | struct sl *sl; | 297 | struct sl *sl; |
298 | /* | 298 | /* |
299 | * Warning: Leave this member at the end so it won't be cleared in | 299 | * A page is allocated under this pointer and used for slib and sl. |
300 | * qdio_fill_qs. A page is allocated under this pointer and used for | 300 | * slib is 2048 bytes big and sl points to offset PAGE_SIZE / 2. |
301 | * slib and sl. slib is 2048 bytes big and sl points to offset | ||
302 | * PAGE_SIZE / 2. | ||
303 | */ | 301 | */ |
304 | struct slib *slib; | 302 | struct slib *slib; |
305 | } __attribute__ ((aligned(256))); | 303 | } __attribute__ ((aligned(256))); |
@@ -372,11 +370,6 @@ static inline int multicast_outbound(struct qdio_q *q) | |||
372 | (q->nr == q->irq_ptr->nr_output_qs - 1); | 370 | (q->nr == q->irq_ptr->nr_output_qs - 1); |
373 | } | 371 | } |
374 | 372 | ||
375 | static inline unsigned long long get_usecs(void) | ||
376 | { | ||
377 | return monotonic_clock() >> 12; | ||
378 | } | ||
379 | |||
380 | #define pci_out_supported(q) \ | 373 | #define pci_out_supported(q) \ |
381 | (q->irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) | 374 | (q->irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) |
382 | #define is_qebsm(q) (q->irq_ptr->sch_token != 0) | 375 | #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: | |||
336 | WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2); | 336 | WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2); |
337 | 337 | ||
338 | if (!start_time) { | 338 | if (!start_time) { |
339 | start_time = get_usecs(); | 339 | start_time = get_clock(); |
340 | goto again; | 340 | goto again; |
341 | } | 341 | } |
342 | if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE) | 342 | if ((get_clock() - start_time) < QDIO_BUSY_BIT_PATIENCE) |
343 | goto again; | 343 | goto again; |
344 | } | 344 | } |
345 | return cc; | 345 | return cc; |
@@ -536,7 +536,7 @@ static int qdio_inbound_q_moved(struct qdio_q *q) | |||
536 | if ((bufnr != q->last_move) || q->qdio_error) { | 536 | if ((bufnr != q->last_move) || q->qdio_error) { |
537 | q->last_move = bufnr; | 537 | q->last_move = bufnr; |
538 | if (!is_thinint_irq(q->irq_ptr) && MACHINE_IS_LPAR) | 538 | if (!is_thinint_irq(q->irq_ptr) && MACHINE_IS_LPAR) |
539 | q->u.in.timestamp = get_usecs(); | 539 | q->u.in.timestamp = get_clock(); |
540 | return 1; | 540 | return 1; |
541 | } else | 541 | } else |
542 | return 0; | 542 | return 0; |
@@ -567,7 +567,7 @@ static inline int qdio_inbound_q_done(struct qdio_q *q) | |||
567 | * At this point we know, that inbound first_to_check | 567 | * At this point we know, that inbound first_to_check |
568 | * has (probably) not moved (see qdio_inbound_processing). | 568 | * has (probably) not moved (see qdio_inbound_processing). |
569 | */ | 569 | */ |
570 | if (get_usecs() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) { | 570 | if (get_clock() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) { |
571 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%02x", | 571 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%02x", |
572 | q->first_to_check); | 572 | q->first_to_check); |
573 | return 1; | 573 | return 1; |
@@ -606,7 +606,7 @@ static void qdio_kick_handler(struct qdio_q *q) | |||
606 | static void __qdio_inbound_processing(struct qdio_q *q) | 606 | static void __qdio_inbound_processing(struct qdio_q *q) |
607 | { | 607 | { |
608 | qperf_inc(q, tasklet_inbound); | 608 | qperf_inc(q, tasklet_inbound); |
609 | again: | 609 | |
610 | if (!qdio_inbound_q_moved(q)) | 610 | if (!qdio_inbound_q_moved(q)) |
611 | return; | 611 | return; |
612 | 612 | ||
@@ -615,7 +615,10 @@ again: | |||
615 | if (!qdio_inbound_q_done(q)) { | 615 | if (!qdio_inbound_q_done(q)) { |
616 | /* means poll time is not yet over */ | 616 | /* means poll time is not yet over */ |
617 | qperf_inc(q, tasklet_inbound_resched); | 617 | qperf_inc(q, tasklet_inbound_resched); |
618 | goto again; | 618 | if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) { |
619 | tasklet_schedule(&q->tasklet); | ||
620 | return; | ||
621 | } | ||
619 | } | 622 | } |
620 | 623 | ||
621 | qdio_stop_polling(q); | 624 | qdio_stop_polling(q); |
@@ -625,7 +628,8 @@ again: | |||
625 | */ | 628 | */ |
626 | if (!qdio_inbound_q_done(q)) { | 629 | if (!qdio_inbound_q_done(q)) { |
627 | qperf_inc(q, tasklet_inbound_resched2); | 630 | qperf_inc(q, tasklet_inbound_resched2); |
628 | goto again; | 631 | if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) |
632 | tasklet_schedule(&q->tasklet); | ||
629 | } | 633 | } |
630 | } | 634 | } |
631 | 635 | ||
@@ -955,6 +959,9 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
955 | return; | 959 | return; |
956 | } | 960 | } |
957 | 961 | ||
962 | if (irq_ptr->perf_stat_enabled) | ||
963 | irq_ptr->perf_stat.qdio_int++; | ||
964 | |||
958 | if (IS_ERR(irb)) { | 965 | if (IS_ERR(irb)) { |
959 | switch (PTR_ERR(irb)) { | 966 | switch (PTR_ERR(irb)) { |
960 | case -EIO: | 967 | case -EIO: |
@@ -1016,30 +1023,6 @@ int qdio_get_ssqd_desc(struct ccw_device *cdev, | |||
1016 | } | 1023 | } |
1017 | EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); | 1024 | EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); |
1018 | 1025 | ||
1019 | /** | ||
1020 | * qdio_cleanup - shutdown queues and free data structures | ||
1021 | * @cdev: associated ccw device | ||
1022 | * @how: use halt or clear to shutdown | ||
1023 | * | ||
1024 | * This function calls qdio_shutdown() for @cdev with method @how. | ||
1025 | * and qdio_free(). The qdio_free() return value is ignored since | ||
1026 | * !irq_ptr is already checked. | ||
1027 | */ | ||
1028 | int qdio_cleanup(struct ccw_device *cdev, int how) | ||
1029 | { | ||
1030 | struct qdio_irq *irq_ptr = cdev->private->qdio_data; | ||
1031 | int rc; | ||
1032 | |||
1033 | if (!irq_ptr) | ||
1034 | return -ENODEV; | ||
1035 | |||
1036 | rc = qdio_shutdown(cdev, how); | ||
1037 | |||
1038 | qdio_free(cdev); | ||
1039 | return rc; | ||
1040 | } | ||
1041 | EXPORT_SYMBOL_GPL(qdio_cleanup); | ||
1042 | |||
1043 | static void qdio_shutdown_queues(struct ccw_device *cdev) | 1026 | static void qdio_shutdown_queues(struct ccw_device *cdev) |
1044 | { | 1027 | { |
1045 | struct qdio_irq *irq_ptr = cdev->private->qdio_data; | 1028 | struct qdio_irq *irq_ptr = cdev->private->qdio_data; |
@@ -1157,28 +1140,6 @@ int qdio_free(struct ccw_device *cdev) | |||
1157 | EXPORT_SYMBOL_GPL(qdio_free); | 1140 | EXPORT_SYMBOL_GPL(qdio_free); |
1158 | 1141 | ||
1159 | /** | 1142 | /** |
1160 | * qdio_initialize - allocate and establish queues for a qdio subchannel | ||
1161 | * @init_data: initialization data | ||
1162 | * | ||
1163 | * This function first allocates queues via qdio_allocate() and on success | ||
1164 | * establishes them via qdio_establish(). | ||
1165 | */ | ||
1166 | int qdio_initialize(struct qdio_initialize *init_data) | ||
1167 | { | ||
1168 | int rc; | ||
1169 | |||
1170 | rc = qdio_allocate(init_data); | ||
1171 | if (rc) | ||
1172 | return rc; | ||
1173 | |||
1174 | rc = qdio_establish(init_data); | ||
1175 | if (rc) | ||
1176 | qdio_free(init_data->cdev); | ||
1177 | return rc; | ||
1178 | } | ||
1179 | EXPORT_SYMBOL_GPL(qdio_initialize); | ||
1180 | |||
1181 | /** | ||
1182 | * qdio_allocate - allocate qdio queues and associated data | 1143 | * qdio_allocate - allocate qdio queues and associated data |
1183 | * @init_data: initialization data | 1144 | * @init_data: initialization data |
1184 | */ | 1145 | */ |
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 | |||
106 | static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr, | 106 | static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr, |
107 | qdio_handler_t *handler, int i) | 107 | qdio_handler_t *handler, int i) |
108 | { | 108 | { |
109 | /* must be cleared by every qdio_establish */ | 109 | struct slib *slib = q->slib; |
110 | memset(q, 0, ((char *)&q->slib) - ((char *)q)); | ||
111 | memset(q->slib, 0, PAGE_SIZE); | ||
112 | 110 | ||
111 | /* queue must be cleared for qdio_establish */ | ||
112 | memset(q, 0, sizeof(*q)); | ||
113 | memset(slib, 0, PAGE_SIZE); | ||
114 | q->slib = slib; | ||
113 | q->irq_ptr = irq_ptr; | 115 | q->irq_ptr = irq_ptr; |
114 | q->mask = 1 << (31 - i); | 116 | q->mask = 1 << (31 - i); |
115 | q->nr = i; | 117 | 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) | |||
95 | for_each_input_queue(irq_ptr, q, i) | 95 | for_each_input_queue(irq_ptr, q, i) |
96 | list_add_rcu(&q->entry, &tiq_list); | 96 | list_add_rcu(&q->entry, &tiq_list); |
97 | mutex_unlock(&tiq_list_lock); | 97 | mutex_unlock(&tiq_list_lock); |
98 | xchg(irq_ptr->dsci, 1); | 98 | xchg(irq_ptr->dsci, 1 << 7); |
99 | } | 99 | } |
100 | 100 | ||
101 | void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) | 101 | void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) |
@@ -173,7 +173,7 @@ static void tiqdio_thinint_handler(void *ind, void *drv_data) | |||
173 | 173 | ||
174 | /* prevent racing */ | 174 | /* prevent racing */ |
175 | if (*tiqdio_alsi) | 175 | if (*tiqdio_alsi) |
176 | xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1); | 176 | xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1 << 7); |
177 | } | 177 | } |
178 | } | 178 | } |
179 | 179 | ||
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, | |||
302 | static int zcrypt_open(struct inode *inode, struct file *filp) | 302 | static int zcrypt_open(struct inode *inode, struct file *filp) |
303 | { | 303 | { |
304 | atomic_inc(&zcrypt_open_count); | 304 | atomic_inc(&zcrypt_open_count); |
305 | return 0; | 305 | return nonseekable_open(inode, filp); |
306 | } | 306 | } |
307 | 307 | ||
308 | /** | 308 | /** |
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) | |||
1292 | QETH_QDIO_CLEANING)) { | 1292 | QETH_QDIO_CLEANING)) { |
1293 | case QETH_QDIO_ESTABLISHED: | 1293 | case QETH_QDIO_ESTABLISHED: |
1294 | if (card->info.type == QETH_CARD_TYPE_IQD) | 1294 | if (card->info.type == QETH_CARD_TYPE_IQD) |
1295 | rc = qdio_cleanup(CARD_DDEV(card), | 1295 | rc = qdio_shutdown(CARD_DDEV(card), |
1296 | QDIO_FLAG_CLEANUP_USING_HALT); | 1296 | QDIO_FLAG_CLEANUP_USING_HALT); |
1297 | else | 1297 | else |
1298 | rc = qdio_cleanup(CARD_DDEV(card), | 1298 | rc = qdio_shutdown(CARD_DDEV(card), |
1299 | QDIO_FLAG_CLEANUP_USING_CLEAR); | 1299 | QDIO_FLAG_CLEANUP_USING_CLEAR); |
1300 | if (rc) | 1300 | if (rc) |
1301 | QETH_DBF_TEXT_(TRACE, 3, "1err%d", rc); | 1301 | QETH_DBF_TEXT_(TRACE, 3, "1err%d", rc); |
1302 | qdio_free(CARD_DDEV(card)); | ||
1302 | atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED); | 1303 | atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED); |
1303 | break; | 1304 | break; |
1304 | case QETH_QDIO_CLEANING: | 1305 | case QETH_QDIO_CLEANING: |
@@ -3810,10 +3811,18 @@ static int qeth_qdio_establish(struct qeth_card *card) | |||
3810 | 3811 | ||
3811 | if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED, | 3812 | if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED, |
3812 | QETH_QDIO_ESTABLISHED) == QETH_QDIO_ALLOCATED) { | 3813 | QETH_QDIO_ESTABLISHED) == QETH_QDIO_ALLOCATED) { |
3813 | rc = qdio_initialize(&init_data); | 3814 | rc = qdio_allocate(&init_data); |
3814 | if (rc) | 3815 | if (rc) { |
3816 | atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED); | ||
3817 | goto out; | ||
3818 | } | ||
3819 | rc = qdio_establish(&init_data); | ||
3820 | if (rc) { | ||
3815 | atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED); | 3821 | atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED); |
3822 | qdio_free(CARD_DDEV(card)); | ||
3823 | } | ||
3816 | } | 3824 | } |
3825 | out: | ||
3817 | kfree(out_sbal_ptrs); | 3826 | kfree(out_sbal_ptrs); |
3818 | kfree(in_sbal_ptrs); | 3827 | kfree(in_sbal_ptrs); |
3819 | kfree(qib_param_field); | 3828 | 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, | |||
254 | } | 254 | } |
255 | 255 | ||
256 | static const struct file_operations zfcp_cfdc_fops = { | 256 | static const struct file_operations zfcp_cfdc_fops = { |
257 | .open = nonseekable_open, | ||
257 | .unlocked_ioctl = zfcp_cfdc_dev_ioctl, | 258 | .unlocked_ioctl = zfcp_cfdc_dev_ioctl, |
258 | #ifdef CONFIG_COMPAT | 259 | #ifdef CONFIG_COMPAT |
259 | .compat_ioctl = zfcp_cfdc_dev_ioctl | 260 | .compat_ioctl = zfcp_cfdc_dev_ioctl |