From: Martin Schwidefsky Tape driver changes: - Add missing break in tape_34xx_work_handler to avoid misleading message. - Cleanup offline/remove code. --- 25-akpm/drivers/s390/char/tape_34xx.c | 5 - 25-akpm/drivers/s390/char/tape_class.c | 6 - 25-akpm/drivers/s390/char/tape_core.c | 112 +++++++++++++++++++++------------ 3 files changed, 78 insertions(+), 45 deletions(-) diff -puN drivers/s390/char/tape_34xx.c~s390-3-12-tape-driver-fixes drivers/s390/char/tape_34xx.c --- 25/drivers/s390/char/tape_34xx.c~s390-3-12-tape-driver-fixes 2004-04-08 13:55:03.125549016 -0700 +++ 25-akpm/drivers/s390/char/tape_34xx.c 2004-04-08 13:55:03.133547800 -0700 @@ -113,6 +113,7 @@ tape_34xx_work_handler(void *data) switch(p->op) { case TO_MSEN: tape_34xx_medium_sense(p->device); + break; default: DBF_EVENT(3, "T34XX: internal error: unknown work\n"); } @@ -1342,7 +1343,7 @@ tape_34xx_init (void) { int rc; - DBF_EVENT(3, "34xx init: $Revision: 1.19 $\n"); + DBF_EVENT(3, "34xx init: $Revision: 1.20 $\n"); /* Register driver for 3480/3490 tapes. */ rc = ccw_driver_register(&tape_34xx_driver); if (rc) @@ -1361,7 +1362,7 @@ tape_34xx_exit(void) MODULE_DEVICE_TABLE(ccw, tape_34xx_ids); MODULE_AUTHOR("(C) 2001-2002 IBM Deutschland Entwicklung GmbH"); MODULE_DESCRIPTION("Linux on zSeries channel attached 3480 tape " - "device driver ($Revision: 1.19 $)"); + "device driver ($Revision: 1.20 $)"); MODULE_LICENSE("GPL"); module_init(tape_34xx_init); diff -puN drivers/s390/char/tape_class.c~s390-3-12-tape-driver-fixes drivers/s390/char/tape_class.c --- 25/drivers/s390/char/tape_class.c~s390-3-12-tape-driver-fixes 2004-04-08 13:55:03.127548712 -0700 +++ 25-akpm/drivers/s390/char/tape_class.c 2004-04-08 13:55:03.133547800 -0700 @@ -1,6 +1,6 @@ /* * (C) Copyright IBM Corp. 2004 - * tape_class.c ($Revision: 1.6 $) + * tape_class.c ($Revision: 1.8 $) * * Tape class device support * @@ -12,7 +12,7 @@ MODULE_AUTHOR("Stefan Bader "); MODULE_DESCRIPTION( "(C) Copyright IBM Corp. 2004 All Rights Reserved.\n" - "tape_class.c ($Revision: 1.6 $)" + "tape_class.c ($Revision: 1.8 $)" ); MODULE_LICENSE("GPL"); @@ -85,7 +85,7 @@ struct tape_class_device *register_tape_ return tcd; fail_with_cdev: - cdev_del(&tcd->char_device); + cdev_del(tcd->char_device); fail_with_tcd: kfree(tcd); diff -puN drivers/s390/char/tape_core.c~s390-3-12-tape-driver-fixes drivers/s390/char/tape_core.c --- 25/drivers/s390/char/tape_core.c~s390-3-12-tape-driver-fixes 2004-04-08 13:55:03.128548560 -0700 +++ 25-akpm/drivers/s390/char/tape_core.c 2004-04-08 13:55:03.135547496 -0700 @@ -377,6 +377,16 @@ out: return rc; } +static inline void +tape_cleanup_device(struct tape_device *device) +{ + tapeblock_cleanup_device(device); + tapechar_cleanup_device(device); + device->discipline->cleanup_device(device); + tape_remove_minor(device); + tape_med_state_set(device, MS_UNKNOWN); +} + /* * Set device offline. * @@ -399,12 +409,13 @@ tape_generic_offline(struct tape_device switch (device->tape_state) { case TS_INIT: case TS_NOT_OPER: + spin_unlock_irq(get_ccwdev_lock(device->cdev)); break; case TS_UNUSED: - tapeblock_cleanup_device(device); - tapechar_cleanup_device(device); - device->discipline->cleanup_device(device); - tape_remove_minor(device); + tape_state_set(device, TS_INIT); + spin_unlock_irq(get_ccwdev_lock(device->cdev)); + tape_cleanup_device(device); + break; default: DBF_EVENT(3, "(%08x): Set offline failed " "- drive in use.\n", @@ -415,9 +426,6 @@ tape_generic_offline(struct tape_device spin_unlock_irq(get_ccwdev_lock(device->cdev)); return -EBUSY; } - spin_unlock_irq(get_ccwdev_lock(device->cdev)); - - tape_med_state_set(device, MS_UNKNOWN); DBF_LH(3, "(%08x): Drive set offline.\n", device->cdev_id); return 0; @@ -543,26 +551,12 @@ tape_generic_probe(struct ccw_device *cd return 0; } -/* - * Driverfs tape remove function. - * - * This function is called whenever the common I/O layer detects the device - * gone. This can happen at any time and we cannot refuse. - */ -void -tape_generic_remove(struct ccw_device *cdev) +static inline void +__tape_discard_requests(struct tape_device *device) { - struct tape_device * device; struct tape_request * request; struct list_head * l, *n; - device = cdev->dev.driver_data; - DBF_LH(3, "(%08x): tape_generic_remove(%p)\n", device->cdev_id, cdev); - - /* - * No more requests may be processed. So just post them as i/o errors. - */ - spin_lock_irq(get_ccwdev_lock(device->cdev)); list_for_each_safe(l, n, &device->req_queue) { request = list_entry(l, struct tape_request, list); if (request->status == TAPE_REQUEST_IN_IO) @@ -575,28 +569,66 @@ tape_generic_remove(struct ccw_device *c if (request->callback != NULL) request->callback(request, request->callback_data); } +} - if (device->tape_state != TS_UNUSED && device->tape_state != TS_INIT) { - DBF_EVENT(3, "(%08x): Drive in use vanished!\n", - device->cdev_id); - PRINT_WARN("(%s): Drive in use vanished - expect trouble!\n", - device->cdev->dev.bus_id); - PRINT_WARN("State was %i\n", device->tape_state); - device->tape_state = TS_NOT_OPER; - tapeblock_cleanup_device(device); - tapechar_cleanup_device(device); - device->discipline->cleanup_device(device); - tape_remove_minor(device); +/* + * Driverfs tape remove function. + * + * This function is called whenever the common I/O layer detects the device + * gone. This can happen at any time and we cannot refuse. + */ +void +tape_generic_remove(struct ccw_device *cdev) +{ + struct tape_device * device; + + device = cdev->dev.driver_data; + if (!device) { + PRINT_ERR("No device pointer in tape_generic_remove!\n"); + return; + } + DBF_LH(3, "(%08x): tape_generic_remove(%p)\n", device->cdev_id, cdev); + + spin_lock_irq(get_ccwdev_lock(device->cdev)); + switch (device->tape_state) { + case TS_INIT: + tape_state_set(device, TS_NOT_OPER); + case TS_NOT_OPER: + /* + * Nothing to do. + */ + spin_unlock_irq(get_ccwdev_lock(device->cdev)); + break; + case TS_UNUSED: + /* + * Need only to release the device. + */ + tape_state_set(device, TS_NOT_OPER); + spin_unlock_irq(get_ccwdev_lock(device->cdev)); + tape_cleanup_device(device); + break; + default: + /* + * There may be requests on the queue. We will not get + * an interrupt for a request that was running. So we + * just post them all as I/O errors. + */ + DBF_EVENT(3, "(%08x): Drive in use vanished!\n", + device->cdev_id); + PRINT_WARN("(%s): Drive in use vanished - " + "expect trouble!\n", + device->cdev->dev.bus_id); + PRINT_WARN("State was %i\n", device->tape_state); + tape_state_set(device, TS_NOT_OPER); + __tape_discard_requests(device); + spin_unlock_irq(get_ccwdev_lock(device->cdev)); + tape_cleanup_device(device); } - device->tape_state = TS_NOT_OPER; - tape_med_state_set(device, MS_UNKNOWN); - spin_unlock_irq(get_ccwdev_lock(device->cdev)); if (cdev->dev.driver_data != NULL) { sysfs_remove_group(&cdev->dev.kobj, &tape_attr_group); cdev->dev.driver_data = tape_put_device(cdev->dev.driver_data); } - } /* @@ -1149,7 +1181,7 @@ tape_init (void) #ifdef DBF_LIKE_HELL debug_set_level(tape_dbf_area, 6); #endif - DBF_EVENT(3, "tape init: ($Revision: 1.48 $)\n"); + DBF_EVENT(3, "tape init: ($Revision: 1.49 $)\n"); tape_proc_init(); tapechar_init (); tapeblock_init (); @@ -1174,7 +1206,7 @@ tape_exit(void) MODULE_AUTHOR("(C) 2001 IBM Deutschland Entwicklung GmbH by Carsten Otte and " "Michael Holzheu (cotte@de.ibm.com,holzheu@de.ibm.com)"); MODULE_DESCRIPTION("Linux on zSeries channel attached " - "tape device driver ($Revision: 1.48 $)"); + "tape device driver ($Revision: 1.49 $)"); MODULE_LICENSE("GPL"); module_init(tape_init); _