diff options
Diffstat (limited to 'drivers/s390')
38 files changed, 1081 insertions, 456 deletions
diff --git a/drivers/s390/Kconfig b/drivers/s390/Kconfig index 96413c2cd1a..a86a650f3d6 100644 --- a/drivers/s390/Kconfig +++ b/drivers/s390/Kconfig @@ -187,6 +187,13 @@ config VMLOGRDR *SYMPTOM. This driver depends on the IUCV support driver. +config VMCP + tristate "Support for the z/VM CP interface (VM only)" + 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/block/dasd.c b/drivers/s390/block/dasd.c index ceeb3cf64a1..d5f53980749 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -7,7 +7,7 @@ * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 * - * $Revision: 1.164 $ + * $Revision: 1.165 $ */ #include <linux/config.h> @@ -176,7 +176,7 @@ dasd_state_known_to_basic(struct dasd_device * device) return rc; /* register 'device' debug area, used for all DBF_DEV_XXX calls */ - device->debug_area = debug_register(device->cdev->dev.bus_id, 0, 2, + device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 2, 8 * sizeof (long)); debug_register_view(device->debug_area, &debug_sprintf_view); debug_set_level(device->debug_area, DBF_EMERG); @@ -1740,6 +1740,10 @@ dasd_exit(void) dasd_proc_exit(); #endif dasd_ioctl_exit(); + if (dasd_page_cache != NULL) { + kmem_cache_destroy(dasd_page_cache); + dasd_page_cache = NULL; + } dasd_gendisk_exit(); dasd_devmap_exit(); devfs_remove("dasd"); @@ -1952,26 +1956,24 @@ dasd_generic_notify(struct ccw_device *cdev, int event) * Automatically online either all dasd devices (dasd_autodetect) or * all devices specified with dasd= parameters. */ +static int +__dasd_auto_online(struct device *dev, void *data) +{ + struct ccw_device *cdev; + + cdev = to_ccwdev(dev); + if (dasd_autodetect || dasd_busid_known(cdev->dev.bus_id) == 0) + ccw_device_set_online(cdev); + return 0; +} + void dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver) { struct device_driver *drv; - struct device *d, *dev; - struct ccw_device *cdev; drv = get_driver(&dasd_discipline_driver->driver); - down_read(&drv->bus->subsys.rwsem); - dev = NULL; - list_for_each_entry(d, &drv->devices, driver_list) { - dev = get_device(d); - if (!dev) - continue; - cdev = to_ccwdev(dev); - if (dasd_autodetect || dasd_busid_known(cdev->dev.bus_id) == 0) - ccw_device_set_online(cdev); - put_device(dev); - } - up_read(&drv->bus->subsys.rwsem); + driver_for_each_device(drv, NULL, NULL, __dasd_auto_online); put_driver(drv); } @@ -1983,7 +1985,7 @@ dasd_init(void) init_waitqueue_head(&dasd_init_waitq); /* register 'common' DASD debug area, used for all DBF_XXX calls */ - dasd_debug_area = debug_register("dasd", 0, 2, 8 * sizeof (long)); + dasd_debug_area = debug_register("dasd", 1, 2, 8 * sizeof (long)); if (dasd_debug_area == NULL) { rc = -ENOMEM; goto failed; diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 7963ae343ee..28cb4613b7f 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -4,7 +4,7 @@ * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.39 $ + * $Revision: 1.40 $ */ #include <linux/config.h> @@ -354,6 +354,8 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) } cqr->device = device; cqr->expires = 5 * 60 * HZ; /* 5 minutes */ + cqr->retries = 32; + cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; return cqr; } diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index d7f19745911..43c34f8c5e6 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -9,13 +9,14 @@ * * /proc interface for the dasd driver. * - * $Revision: 1.31 $ + * $Revision: 1.32 $ */ #include <linux/config.h> #include <linux/ctype.h> #include <linux/seq_file.h> #include <linux/vmalloc.h> +#include <linux/proc_fs.h> #include <asm/debug.h> #include <asm/uaccess.h> diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 16ab8d363ac..4fde4118899 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -35,14 +35,17 @@ static int dcssblk_open(struct inode *inode, struct file *filp); static int dcssblk_release(struct inode *inode, struct file *filp); static int dcssblk_make_request(struct request_queue *q, struct bio *bio); +static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum, + unsigned long *data); static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; static int dcssblk_major; static struct block_device_operations dcssblk_devops = { - .owner = THIS_MODULE, - .open = dcssblk_open, - .release = dcssblk_release, + .owner = THIS_MODULE, + .open = dcssblk_open, + .release = dcssblk_release, + .direct_access = dcssblk_direct_access, }; static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf, @@ -641,6 +644,20 @@ dcssblk_make_request(request_queue_t *q, struct bio *bio) /* Request beyond end of DCSS segment. */ goto fail; } + /* verify data transfer direction */ + if (dev_info->is_shared) { + switch (dev_info->segment_type) { + case SEG_TYPE_SR: + case SEG_TYPE_ER: + case SEG_TYPE_SC: + /* cannot write to these segments */ + if (bio_data_dir(bio) == WRITE) { + PRINT_WARN("rejecting write to ro segment %s\n", dev_info->dev.bus_id); + goto fail; + } + } + } + index = (bio->bi_sector >> 3); bio_for_each_segment(bvec, bio, i) { page_addr = (unsigned long) @@ -661,7 +678,26 @@ dcssblk_make_request(request_queue_t *q, struct bio *bio) bio_endio(bio, bytes_done, 0); return 0; fail: - bio_io_error(bio, bytes_done); + bio_io_error(bio, bio->bi_size); + return 0; +} + +static int +dcssblk_direct_access (struct block_device *bdev, sector_t secnum, + unsigned long *data) +{ + struct dcssblk_dev_info *dev_info; + unsigned long pgoff; + + dev_info = bdev->bd_disk->private_data; + if (!dev_info) + return -ENODEV; + if (secnum % (PAGE_SIZE/512)) + return -EINVAL; + pgoff = secnum / (PAGE_SIZE / 512); + if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start) + return -ERANGE; + *data = (unsigned long) (dev_info->start+pgoff*PAGE_SIZE); return 0; } @@ -682,7 +718,7 @@ dcssblk_check_params(void) buf[j-i] = dcssblk_segments[j]; } buf[j-i] = '\0'; - rc = dcssblk_add_store(dcssblk_root_dev, buf, j-i); + rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i); if ((rc >= 0) && (dcssblk_segments[j] == '(')) { for (k = 0; buf[k] != '\0'; k++) buf[k] = toupper(buf[k]); @@ -692,7 +728,7 @@ dcssblk_check_params(void) up_read(&dcssblk_devices_sem); if (dev_info) dcssblk_shared_store(&dev_info->dev, - "0\n", 2); + NULL, "0\n", 2); } } while ((dcssblk_segments[j] != ',') && diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index 14e8cce9f86..6377a96735d 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_SCLP_CPI) += sclp_cpi.o obj-$(CONFIG_ZVM_WATCHDOG) += vmwatchdog.o obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o +obj-$(CONFIG_VMCP) += vmcp.o tape-$(CONFIG_S390_TAPE_BLOCK) += tape_block.o tape-$(CONFIG_PROC_FS) += tape_proc.o diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 022f17bff73..f11a67fda40 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -860,8 +860,8 @@ con3215_init(void) /* Set the console mode for VM */ if (MACHINE_IS_VM) { - cpcmd("TERM CONMODE 3215", NULL, 0); - cpcmd("TERM AUTOCR OFF", NULL, 0); + cpcmd("TERM CONMODE 3215", NULL, 0, NULL); + cpcmd("TERM AUTOCR OFF", NULL, 0, NULL); } /* allocate 3215 request structures */ diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index d52fb57a6b1..fc7a213e591 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -591,8 +591,8 @@ con3270_init(void) /* Set the console mode for VM */ if (MACHINE_IS_VM) { - cpcmd("TERM CONMODE 3270", 0, 0); - cpcmd("TERM AUTOCR OFF", 0, 0); + cpcmd("TERM CONMODE 3270", NULL, 0, NULL); + cpcmd("TERM AUTOCR OFF", NULL, 0, NULL); } cdev = ccw_device_probe_console(); diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h index d04e6c2c3cc..01d865d9379 100644 --- a/drivers/s390/char/tape.h +++ b/drivers/s390/char/tape.h @@ -3,10 +3,11 @@ * tape device driver for 3480/3490E/3590 tapes. * * S390 and zSeries version - * Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Carsten Otte <cotte@de.ibm.com> * Tuan Ngo-Anh <ngoanh@de.ibm.com> * Martin Schwidefsky <schwidefsky@de.ibm.com> + * Stefan Bader <shbader@de.ibm.com> */ #ifndef _TAPE_H @@ -111,6 +112,7 @@ enum tape_request_status { TAPE_REQUEST_QUEUED, /* request is queued to be processed */ TAPE_REQUEST_IN_IO, /* request is currently in IO */ TAPE_REQUEST_DONE, /* request is completed. */ + TAPE_REQUEST_CANCEL, /* request should be canceled. */ }; /* Tape CCW request */ @@ -237,6 +239,9 @@ struct tape_device { /* Block dev frontend data */ struct tape_blk_data blk_data; #endif + + /* Function to start or stop the next request later. */ + struct work_struct tape_dnr; }; /* Externals from tape_core.c */ diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 480ec87976f..20be88e91fa 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -1351,13 +1351,13 @@ tape_34xx_init (void) { int rc; - TAPE_DBF_AREA = debug_register ( "tape_34xx", 1, 2, 4*sizeof(long)); + TAPE_DBF_AREA = debug_register ( "tape_34xx", 2, 2, 4*sizeof(long)); debug_register_view(TAPE_DBF_AREA, &debug_sprintf_view); #ifdef DBF_LIKE_HELL debug_set_level(TAPE_DBF_AREA, 6); #endif - DBF_EVENT(3, "34xx init: $Revision: 1.21 $\n"); + DBF_EVENT(3, "34xx init: $Revision: 1.23 $\n"); /* Register driver for 3480/3490 tapes. */ rc = ccw_driver_register(&tape_34xx_driver); if (rc) @@ -1378,7 +1378,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.21 $)"); + "device driver ($Revision: 1.23 $)"); MODULE_LICENSE("GPL"); module_init(tape_34xx_init); diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index b4df4a515b1..6c52e8307dc 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -3,11 +3,12 @@ * basic function of the tape device driver * * S390 and zSeries version - * Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Carsten Otte <cotte@de.ibm.com> * Michael Holzheu <holzheu@de.ibm.com> * Tuan Ngo-Anh <ngoanh@de.ibm.com> * Martin Schwidefsky <schwidefsky@de.ibm.com> + * Stefan Bader <shbader@de.ibm.com> */ #include <linux/config.h> @@ -28,7 +29,7 @@ #define PRINTK_HEADER "TAPE_CORE: " static void __tape_do_irq (struct ccw_device *, unsigned long, struct irb *); -static void __tape_remove_request(struct tape_device *, struct tape_request *); +static void tape_delayed_next_request(void * data); /* * One list to contain all tape devices of all disciplines, so @@ -257,7 +258,7 @@ tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate) * Stop running ccw. Has to be called with the device lock held. */ static inline int -__tape_halt_io(struct tape_device *device, struct tape_request *request) +__tape_cancel_io(struct tape_device *device, struct tape_request *request) { int retries; int rc; @@ -270,20 +271,23 @@ __tape_halt_io(struct tape_device *device, struct tape_request *request) for (retries = 0; retries < 5; retries++) { rc = ccw_device_clear(device->cdev, (long) request); - if (rc == 0) { /* Termination successful */ - request->rc = -EIO; - request->status = TAPE_REQUEST_DONE; - return 0; + switch (rc) { + case 0: + request->status = TAPE_REQUEST_DONE; + return 0; + case -EBUSY: + request->status = TAPE_REQUEST_CANCEL; + schedule_work(&device->tape_dnr); + return 0; + case -ENODEV: + DBF_EXCEPTION(2, "device gone, retry\n"); + break; + case -EIO: + DBF_EXCEPTION(2, "I/O error, retry\n"); + break; + default: + BUG(); } - - if (rc == -ENODEV) - DBF_EXCEPTION(2, "device gone, retry\n"); - else if (rc == -EIO) - DBF_EXCEPTION(2, "I/O error, retry\n"); - else if (rc == -EBUSY) - DBF_EXCEPTION(2, "device busy, retry late\n"); - else - BUG(); } return rc; @@ -473,6 +477,7 @@ tape_alloc_device(void) *device->modeset_byte = 0; device->first_minor = -1; atomic_set(&device->ref_count, 1); + INIT_WORK(&device->tape_dnr, tape_delayed_next_request, device); return device; } @@ -708,54 +713,119 @@ tape_free_request (struct tape_request * request) kfree(request); } +static inline int +__tape_start_io(struct tape_device *device, struct tape_request *request) +{ + int rc; + +#ifdef CONFIG_S390_TAPE_BLOCK + if (request->op == TO_BLOCK) + device->discipline->check_locate(device, request); +#endif + rc = ccw_device_start( + device->cdev, + request->cpaddr, + (unsigned long) request, + 0x00, + request->options + ); + if (rc == 0) { + request->status = TAPE_REQUEST_IN_IO; + } else if (rc == -EBUSY) { + /* The common I/O subsystem is currently busy. Retry later. */ + request->status = TAPE_REQUEST_QUEUED; + schedule_work(&device->tape_dnr); + rc = 0; + } else { + /* Start failed. Remove request and indicate failure. */ + DBF_EVENT(1, "tape: start request failed with RC = %i\n", rc); + } + return rc; +} + static inline void -__tape_do_io_list(struct tape_device *device) +__tape_start_next_request(struct tape_device *device) { struct list_head *l, *n; struct tape_request *request; int rc; - DBF_LH(6, "__tape_do_io_list(%p)\n", device); + DBF_LH(6, "__tape_start_next_request(%p)\n", device); /* * Try to start each request on request queue until one is * started successful. */ list_for_each_safe(l, n, &device->req_queue) { request = list_entry(l, struct tape_request, list); -#ifdef CONFIG_S390_TAPE_BLOCK - if (request->op == TO_BLOCK) - device->discipline->check_locate(device, request); -#endif - rc = ccw_device_start(device->cdev, request->cpaddr, - (unsigned long) request, 0x00, - request->options); - if (rc == 0) { - request->status = TAPE_REQUEST_IN_IO; - break; + + /* + * Avoid race condition if bottom-half was triggered more than + * once. + */ + if (request->status == TAPE_REQUEST_IN_IO) + return; + + /* + * We wanted to cancel the request but the common I/O layer + * was busy at that time. This can only happen if this + * function is called by delayed_next_request. + * Otherwise we start the next request on the queue. + */ + if (request->status == TAPE_REQUEST_CANCEL) { + rc = __tape_cancel_io(device, request); + } else { + rc = __tape_start_io(device, request); } - /* Start failed. Remove request and indicate failure. */ - DBF_EVENT(1, "tape: DOIO failed with er = %i\n", rc); + if (rc == 0) + return; - /* Set ending status and do callback. */ + /* Set ending status. */ request->rc = rc; request->status = TAPE_REQUEST_DONE; - __tape_remove_request(device, request); + + /* Remove from request queue. */ + list_del(&request->list); + + /* Do callback. */ + if (request->callback != NULL) + request->callback(request, request->callback_data); } } static void -__tape_remove_request(struct tape_device *device, struct tape_request *request) +tape_delayed_next_request(void *data) { - /* Remove from request queue. */ - list_del(&request->list); + struct tape_device * device; - /* Do callback. */ - if (request->callback != NULL) - request->callback(request, request->callback_data); + device = (struct tape_device *) data; + DBF_LH(6, "tape_delayed_next_request(%p)\n", device); + spin_lock_irq(get_ccwdev_lock(device->cdev)); + __tape_start_next_request(device); + spin_unlock_irq(get_ccwdev_lock(device->cdev)); +} + +static inline void +__tape_end_request( + struct tape_device * device, + struct tape_request * request, + int rc) +{ + DBF_LH(6, "__tape_end_request(%p, %p, %i)\n", device, request, rc); + if (request) { + request->rc = rc; + request->status = TAPE_REQUEST_DONE; + + /* Remove from request queue. */ + list_del(&request->list); + + /* Do callback. */ + if (request->callback != NULL) + request->callback(request, request->callback_data); + } /* Start next request. */ if (!list_empty(&device->req_queue)) - __tape_do_io_list(device); + __tape_start_next_request(device); } /* @@ -812,7 +882,7 @@ tape_dump_sense_dbf(struct tape_device *device, struct tape_request *request, * the device lock held. */ static inline int -__tape_do_io(struct tape_device *device, struct tape_request *request) +__tape_start_request(struct tape_device *device, struct tape_request *request) { int rc; @@ -837,24 +907,16 @@ __tape_do_io(struct tape_device *device, struct tape_request *request) if (list_empty(&device->req_queue)) { /* No other requests are on the queue. Start this one. */ -#ifdef CONFIG_S390_TAPE_BLOCK - if (request->op == TO_BLOCK) - device->discipline->check_locate(device, request); -#endif - rc = ccw_device_start(device->cdev, request->cpaddr, - (unsigned long) request, 0x00, - request->options); - if (rc) { - DBF_EVENT(1, "tape: DOIO failed with rc = %i\n", rc); + rc = __tape_start_io(device, request); + if (rc) return rc; - } + DBF_LH(5, "Request %p added for execution.\n", request); list_add(&request->list, &device->req_queue); - request->status = TAPE_REQUEST_IN_IO; } else { DBF_LH(5, "Request %p add to queue.\n", request); - list_add_tail(&request->list, &device->req_queue); request->status = TAPE_REQUEST_QUEUED; + list_add_tail(&request->list, &device->req_queue); } return 0; } @@ -872,7 +934,7 @@ tape_do_io_async(struct tape_device *device, struct tape_request *request) spin_lock_irq(get_ccwdev_lock(device->cdev)); /* Add request to request queue and try to start it. */ - rc = __tape_do_io(device, request); + rc = __tape_start_request(device, request); spin_unlock_irq(get_ccwdev_lock(device->cdev)); return rc; } @@ -901,7 +963,7 @@ tape_do_io(struct tape_device *device, struct tape_request *request) request->callback = __tape_wake_up; request->callback_data = &wq; /* Add request to request queue and try to start it. */ - rc = __tape_do_io(device, request); + rc = __tape_start_request(device, request); spin_unlock_irq(get_ccwdev_lock(device->cdev)); if (rc) return rc; @@ -935,7 +997,7 @@ tape_do_io_interruptible(struct tape_device *device, /* Setup callback */ request->callback = __tape_wake_up_interruptible; request->callback_data = &wq; - rc = __tape_do_io(device, request); + rc = __tape_start_request(device, request); spin_unlock_irq(get_ccwdev_lock(device->cdev)); if (rc) return rc; @@ -944,36 +1006,27 @@ tape_do_io_interruptible(struct tape_device *device, if (rc != -ERESTARTSYS) /* Request finished normally. */ return request->rc; + /* Interrupted by a signal. We have to stop the current request. */ spin_lock_irq(get_ccwdev_lock(device->cdev)); - rc = __tape_halt_io(device, request); + rc = __tape_cancel_io(device, request); + spin_unlock_irq(get_ccwdev_lock(device->cdev)); if (rc == 0) { + /* Wait for the interrupt that acknowledges the halt. */ + do { + rc = wait_event_interruptible( + wq, + (request->callback == NULL) + ); + } while (rc != -ERESTARTSYS); + DBF_EVENT(3, "IO stopped on %08x\n", device->cdev_id); rc = -ERESTARTSYS; } - spin_unlock_irq(get_ccwdev_lock(device->cdev)); return rc; } /* - * Handle requests that return an i/o error in the irb. - */ -static inline void -tape_handle_killed_request( - struct tape_device *device, - struct tape_request *request) -{ - if(request != NULL) { - /* Set ending status. FIXME: Should the request be retried? */ - request->rc = -EIO; - request->status = TAPE_REQUEST_DONE; - __tape_remove_request(device, request); - } else { - __tape_do_io_list(device); - } -} - -/* * Tape interrupt routine, called from the ccw_device layer */ static void @@ -981,7 +1034,6 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) { struct tape_device *device; struct tape_request *request; - int final; int rc; device = (struct tape_device *) cdev->dev.driver_data; @@ -996,12 +1048,13 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) /* On special conditions irb is an error pointer */ if (IS_ERR(irb)) { + /* FIXME: What to do with the request? */ switch (PTR_ERR(irb)) { case -ETIMEDOUT: PRINT_WARN("(%s): Request timed out\n", cdev->dev.bus_id); case -EIO: - tape_handle_killed_request(device, request); + __tape_end_request(device, request, -EIO); break; default: PRINT_ERR("(%s): Unexpected i/o error %li\n", @@ -1011,6 +1064,21 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) return; } + /* + * If the condition code is not zero and the start function bit is + * still set, this is an deferred error and the last start I/O did + * not succeed. Restart the request now. + */ + if (irb->scsw.cc != 0 && (irb->scsw.fctl & SCSW_FCTL_START_FUNC)) { + PRINT_WARN("(%s): deferred cc=%i. restaring\n", + cdev->dev.bus_id, + irb->scsw.cc); + rc = __tape_start_io(device, request); + if (rc) + __tape_end_request(device, request, rc); + return; + } + /* May be an unsolicited irq */ if(request != NULL) request->rescnt = irb->scsw.count; @@ -1042,7 +1110,7 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) * To detect these request the state will be set to TAPE_REQUEST_DONE. */ if(request != NULL && request->status == TAPE_REQUEST_DONE) { - __tape_remove_request(device, request); + __tape_end_request(device, request, -EIO); return; } @@ -1054,51 +1122,34 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) * rc == TAPE_IO_RETRY: request finished but needs another go. * rc == TAPE_IO_STOP: request needs to get terminated. */ - final = 0; switch (rc) { - case TAPE_IO_SUCCESS: - /* Upon normal completion the device _is_ online */ - device->tape_generic_status |= GMT_ONLINE(~0); - final = 1; - break; - case TAPE_IO_PENDING: - break; - case TAPE_IO_RETRY: -#ifdef CONFIG_S390_TAPE_BLOCK - if (request->op == TO_BLOCK) - device->discipline->check_locate(device, request); -#endif - rc = ccw_device_start(cdev, request->cpaddr, - (unsigned long) request, 0x00, - request->options); - if (rc) { - DBF_EVENT(1, "tape: DOIO failed with er = %i\n", rc); - final = 1; - } - break; - case TAPE_IO_STOP: - __tape_halt_io(device, request); - break; - default: - if (rc > 0) { - DBF_EVENT(6, "xunknownrc\n"); - PRINT_ERR("Invalid return code from discipline " - "interrupt function.\n"); - rc = -EIO; - } - final = 1; - break; - } - if (final) { - /* May be an unsolicited irq */ - if(request != NULL) { - /* Set ending status. */ - request->rc = rc; - request->status = TAPE_REQUEST_DONE; - __tape_remove_request(device, request); - } else { - __tape_do_io_list(device); - } + case TAPE_IO_SUCCESS: + /* Upon normal completion the device _is_ online */ + device->tape_generic_status |= GMT_ONLINE(~0); + __tape_end_request(device, request, rc); + break; + case TAPE_IO_PENDING: + break; + case TAPE_IO_RETRY: + rc = __tape_start_io(device, request); + if (rc) + __tape_end_request(device, request, rc); + break; + case TAPE_IO_STOP: + rc = __tape_cancel_io(device, request); + if (rc) + __tape_end_request(device, request, rc); + break; + default: + if (rc > 0) { + DBF_EVENT(6, "xunknownrc\n"); + PRINT_ERR("Invalid return code from discipline " + "interrupt function.\n"); + __tape_end_request(device, request, -EIO); + } else { + __tape_end_request(device, request, rc); + } + break; } } @@ -1186,12 +1237,12 @@ tape_mtop(struct tape_device *device, int mt_op, int mt_count) static int tape_init (void) { - TAPE_DBF_AREA = debug_register ( "tape", 1, 2, 4*sizeof(long)); + TAPE_DBF_AREA = debug_register ( "tape", 2, 2, 4*sizeof(long)); debug_register_view(TAPE_DBF_AREA, &debug_sprintf_view); #ifdef DBF_LIKE_HELL debug_set_level(TAPE_DBF_AREA, 6); #endif - DBF_EVENT(3, "tape init: ($Revision: 1.51 $)\n"); + DBF_EVENT(3, "tape init: ($Revision: 1.54 $)\n"); tape_proc_init(); tapechar_init (); tapeblock_init (); @@ -1216,7 +1267,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.51 $)"); + "tape device driver ($Revision: 1.54 $)"); MODULE_LICENSE("GPL"); module_init(tape_init); diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c index 801d17cca34..5fec0a10cc3 100644 --- a/drivers/s390/char/tape_proc.c +++ b/drivers/s390/char/tape_proc.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/vmalloc.h> #include <linux/seq_file.h> +#include <linux/proc_fs.h> #define TAPE_DBF_AREA tape_core_dbf diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c new file mode 100644 index 00000000000..8990d8076e7 --- /dev/null +++ b/drivers/s390/char/vmcp.c @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2004,2005 IBM Corporation + * Interface implementation for communication with the v/VM control program + * Author(s): Christian Borntraeger <cborntra@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 + */ + +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <asm/cpcmd.h> +#include <asm/debug.h> +#include <asm/uaccess.h> +#include "vmcp.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Borntraeger <cborntra@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) +{ + struct vmcp_session *session; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + session = kmalloc(sizeof(*session), GFP_KERNEL); + if (!session) + return -ENOMEM; + session->bufsize = PAGE_SIZE; + session->response = NULL; + session->resp_size = 0; + init_MUTEX(&session->mutex); + file->private_data = session; + return nonseekable_open(inode, file); +} + +static int vmcp_release(struct inode *inode, struct file *file) +{ + struct vmcp_session *session; + + session = (struct vmcp_session *)file->private_data; + file->private_data = NULL; + free_pages((unsigned long)session->response, get_order(session->bufsize)); + kfree(session); + return 0; +} + +static ssize_t +vmcp_read(struct file *file, char __user * buff, size_t count, loff_t * ppos) +{ + size_t tocopy; + struct vmcp_session *session; + + session = (struct vmcp_session *)file->private_data; + if (down_interruptible(&session->mutex)) + return -ERESTARTSYS; + if (!session->response) { + up(&session->mutex); + return 0; + } + if (*ppos > session->resp_size) { + up(&session->mutex); + return 0; + } + tocopy = min(session->resp_size - (size_t) (*ppos), count); + tocopy = min(tocopy,session->bufsize - (size_t) (*ppos)); + + if (copy_to_user(buff, session->response + (*ppos), tocopy)) { + up(&session->mutex); + return -EFAULT; + } + up(&session->mutex); + *ppos += tocopy; + return tocopy; +} + +static ssize_t +vmcp_write(struct file *file, const char __user * buff, size_t count, + loff_t * ppos) +{ + char *cmd; + struct vmcp_session *session; + + if (count > 240) + return -EINVAL; + cmd = kmalloc(count + 1, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + if (copy_from_user(cmd, buff, count)) { + kfree(cmd); + return -EFAULT; + } + cmd[count] = '\0'; + session = (struct vmcp_session *)file->private_data; + if (down_interruptible(&session->mutex)) + return -ERESTARTSYS; + if (!session->response) + session->response = (char *)__get_free_pages(GFP_KERNEL + | __GFP_REPEAT | GFP_DMA, + get_order(session->bufsize)); + if (!session->response) { + up(&session->mutex); + kfree(cmd); + return -ENOMEM; + } + debug_text_event(vmcp_debug, 1, cmd); + session->resp_size = __cpcmd(cmd, session->response, + session->bufsize, + &session->resp_code); + up(&session->mutex); + kfree(cmd); + *ppos = 0; /* reset the file pointer after a command */ + return count; +} + + +/* + * These ioctls are available, as the semantics of the diagnose 8 call + * does not fit very well into a Linux call. Diagnose X'08' is described in + * CP Programming Services SC24-6084-00 + * + * VMCP_GETCODE: gives the CP return code back to user space + * VMCP_SETBUF: sets the response buffer for the next write call. diagnose 8 + * expects adjacent pages in real storage and to make matters worse, we + * dont know the size of the response. Therefore we default to PAGESIZE and + * let userspace to change the response size, if userspace expects a bigger + * response + */ +static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct vmcp_session *session; + int temp; + + session = (struct vmcp_session *)file->private_data; + if (down_interruptible(&session->mutex)) + return -ERESTARTSYS; + switch (cmd) { + case VMCP_GETCODE: + temp = session->resp_code; + up(&session->mutex); + return put_user(temp, (int __user *)arg); + case VMCP_SETBUF: + free_pages((unsigned long)session->response, + get_order(session->bufsize)); + session->response=NULL; + temp = get_user(session->bufsize, (int __user *)arg); + if (get_order(session->bufsize) > 8) { + session->bufsize = PAGE_SIZE; + temp = -EINVAL; + } + up(&session->mutex); + return temp; + case VMCP_GETSIZE: + temp = session->resp_size; + up(&session->mutex); + return put_user(temp, (int __user *)arg); + default: + up(&session->mutex); + return -ENOIOCTLCMD; + } +} + +static struct file_operations vmcp_fops = { + .owner = THIS_MODULE, + .open = &vmcp_open, + .release = &vmcp_release, + .read = &vmcp_read, + .llseek = &no_llseek, + .write = &vmcp_write, + .unlocked_ioctl = &vmcp_ioctl, + .compat_ioctl = &vmcp_ioctl +}; + +static struct miscdevice vmcp_dev = { + .name = "vmcp", + .minor = MISC_DYNAMIC_MINOR, + .fops = &vmcp_fops, +}; + +static int __init vmcp_init(void) +{ + int ret; + + if (!MACHINE_IS_VM) { + printk(KERN_WARNING + "z/VM CP interface is only available under z/VM\n"); + return -ENODEV; + } + ret = misc_register(&vmcp_dev); + if (!ret) + printk(KERN_INFO "z/VM CP interface loaded\n"); + else + printk(KERN_WARNING + "z/VM CP interface not loaded. Could not register misc device.\n"); + vmcp_debug = debug_register("vmcp", 1, 1, 240); + debug_register_view(vmcp_debug, &debug_hex_ascii_view); + return ret; +} + +static void __exit vmcp_exit(void) +{ + WARN_ON(misc_deregister(&vmcp_dev) != 0); + debug_unregister(vmcp_debug); + printk(KERN_INFO "z/VM CP interface unloaded.\n"); +} + +module_init(vmcp_init); +module_exit(vmcp_exit); diff --git a/drivers/s390/char/vmcp.h b/drivers/s390/char/vmcp.h new file mode 100644 index 00000000000..87389e73046 --- /dev/null +++ b/drivers/s390/char/vmcp.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2004, 2005 IBM Corporation + * Interface implementation for communication with the v/VM control program + * Version 1.0 + * Author(s): Christian Borntraeger <cborntra@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 + */ + +#include <asm/semaphore.h> +#include <linux/ioctl.h> + +#define VMCP_GETCODE _IOR(0x10, 1, int) +#define VMCP_SETBUF _IOW(0x10, 2, int) +#define VMCP_GETSIZE _IOR(0x10, 3, int) + +struct vmcp_session { + unsigned int bufsize; + char *response; + int resp_size; + int resp_code; + /* As we use copy_from/to_user, which might * + * sleep and cannot use a spinlock */ + struct semaphore mutex; +}; diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index f7717327d15..491f00c032e 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -236,7 +236,7 @@ vmlogrdr_get_recording_class_AB(void) { int len,i; printk (KERN_DEBUG "vmlogrdr: query command: %s\n", cp_command); - cpcmd(cp_command, cp_response, sizeof(cp_response)); + cpcmd(cp_command, cp_response, sizeof(cp_response), NULL); printk (KERN_DEBUG "vmlogrdr: response: %s", cp_response); len = strnlen(cp_response,sizeof(cp_response)); // now the parsing @@ -288,7 +288,7 @@ vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) { printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command); - cpcmd(cp_command, cp_response, sizeof(cp_response)); + cpcmd(cp_command, cp_response, sizeof(cp_response), NULL); printk (KERN_DEBUG "vmlogrdr: recording response: %s", cp_response); } @@ -301,7 +301,7 @@ vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) { qid_string); printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command); - cpcmd(cp_command, cp_response, sizeof(cp_response)); + cpcmd(cp_command, cp_response, sizeof(cp_response), NULL); printk (KERN_DEBUG "vmlogrdr: recording response: %s", cp_response); /* The recording command will usually answer with 'Command complete' @@ -607,7 +607,7 @@ vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const c priv->recording_name); printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command); - cpcmd(cp_command, cp_response, sizeof(cp_response)); + cpcmd(cp_command, cp_response, sizeof(cp_response), NULL); printk (KERN_DEBUG "vmlogrdr: recording response: %s", cp_response); @@ -682,7 +682,7 @@ vmlogrdr_recording_status_show(struct device_driver *driver, char *buf) { char cp_command[] = "QUERY RECORDING "; int len; - cpcmd(cp_command, buf, 4096); + cpcmd(cp_command, buf, 4096, NULL); len = strlen(buf); return len; } diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c index 22cf4fec8da..5473c23fcb5 100644 --- a/drivers/s390/char/vmwatchdog.c +++ b/drivers/s390/char/vmwatchdog.c @@ -23,11 +23,7 @@ static char vmwdt_cmd[MAX_CMDLEN] = "IPL"; static int vmwdt_conceal; -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int vmwdt_nowayout = 1; -#else -static int vmwdt_nowayout = 0; -#endif +static int vmwdt_nowayout = WATCHDOG_NOWAYOUT; MODULE_LICENSE("GPL"); MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>"); diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 306525acb9f..91ea8e4777f 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -403,34 +403,22 @@ ccwgroup_driver_register (struct ccwgroup_driver *cdriver) return driver_register(&cdriver->driver); } -static inline struct device * -__get_next_ccwgroup_device(struct device_driver *drv) +static int +__ccwgroup_driver_unregister_device(struct device *dev, void *data) { - struct device *dev, *d; - - down_read(&drv->bus->subsys.rwsem); - dev = NULL; - list_for_each_entry(d, &drv->devices, driver_list) { - dev = get_device(d); - if (dev) - break; - } - up_read(&drv->bus->subsys.rwsem); - return dev; + __ccwgroup_remove_symlinks(to_ccwgroupdev(dev)); + device_unregister(dev); + put_device(dev); + return 0; } void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver) { - struct device *dev; - /* We don't want ccwgroup devices to live longer than their driver. */ get_driver(&cdriver->driver); - while ((dev = __get_next_ccwgroup_device(&cdriver->driver))) { - __ccwgroup_remove_symlinks(to_ccwgroupdev(dev)); - device_unregister(dev); - put_device(dev); - }; + driver_for_each_device(&cdriver->driver, NULL, NULL, + __ccwgroup_driver_unregister_device); put_driver(&cdriver->driver); driver_unregister(&cdriver->driver); } @@ -449,7 +437,7 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev) if (cdev->dev.driver_data) { gdev = (struct ccwgroup_device *)cdev->dev.driver_data; if (get_device(&gdev->dev)) { - if (!list_empty(&gdev->dev.node)) + if (klist_node_attached(&gdev->dev.knode_bus)) return gdev; put_device(&gdev->dev); } diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index b86f94ecd87..fa3c23b80e3 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/chsc.c * S/390 common I/O routines -- channel subsystem call - * $Revision: 1.119 $ + * $Revision: 1.120 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -412,11 +412,7 @@ s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask) if (chp_mask == 0) { spin_unlock_irq(&sch->lock); - - if (fla_mask != 0) - break; - else - continue; + continue; } old_lpm = sch->lpm; sch->lpm = ((sch->schib.pmcw.pim & @@ -430,7 +426,7 @@ s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask) spin_unlock_irq(&sch->lock); put_device(&sch->dev); - if (fla_mask != 0) + if (fla_mask == 0xffff) break; } return rc; diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 1d9b3f18d8d..ea813bdce1d 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/cio.c * S/390 common I/O routines -- low level i/o calls - * $Revision: 1.133 $ + * $Revision: 1.134 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -63,17 +63,17 @@ __setup ("cio_msg=", cio_setup); static int __init cio_debug_init (void) { - cio_debug_msg_id = debug_register ("cio_msg", 4, 4, 16*sizeof (long)); + cio_debug_msg_id = debug_register ("cio_msg", 16, 4, 16*sizeof (long)); if (!cio_debug_msg_id) goto out_unregister; debug_register_view (cio_debug_msg_id, &debug_sprintf_view); debug_set_level (cio_debug_msg_id, 2); - cio_debug_trace_id = debug_register ("cio_trace", 4, 4, 8); + cio_debug_trace_id = debug_register ("cio_trace", 16, 4, 8); if (!cio_debug_trace_id) goto out_unregister; debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view); debug_set_level (cio_debug_trace_id, 2); - cio_debug_crw_id = debug_register ("cio_crw", 2, 4, 16*sizeof (long)); + cio_debug_crw_id = debug_register ("cio_crw", 4, 4, 16*sizeof (long)); if (!cio_debug_crw_id) goto out_unregister; debug_register_view (cio_debug_crw_id, &debug_sprintf_view); diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 87bd70eeabe..555119cacc2 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -128,34 +128,28 @@ css_probe_device(int irq) return ret; } +static int +check_subchannel(struct device * dev, void * data) +{ + struct subchannel *sch; + int irq = (unsigned long)data; + + sch = to_subchannel(dev); + return (sch->irq == irq); +} + struct subchannel * get_subchannel_by_schid(int irq) { - struct subchannel *sch; - struct list_head *entry; struct device *dev; - if (!get_bus(&css_bus_type)) - return NULL; - down_read(&css_bus_type.subsys.rwsem); - sch = NULL; - list_for_each(entry, &css_bus_type.devices.list) { - dev = get_device(container_of(entry, - struct device, bus_list)); - if (!dev) - continue; - sch = to_subchannel(dev); - if (sch->irq == irq) - break; - put_device(dev); - sch = NULL; - } - up_read(&css_bus_type.subsys.rwsem); - put_bus(&css_bus_type); + dev = bus_find_device(&css_bus_type, NULL, + (void *)(unsigned long)irq, check_subchannel); - return sch; + return dev ? to_subchannel(dev) : NULL; } + static inline int css_get_subchannel_status(struct subchannel *sch, int schid) { diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 809e1108a06..14c76f5e417 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -514,36 +514,39 @@ ccw_device_register(struct ccw_device *cdev) return ret; } +struct match_data { + unsigned int devno; + struct ccw_device * sibling; +}; + +static int +match_devno(struct device * dev, void * data) +{ + struct match_data * d = (struct match_data *)data; + struct ccw_device * cdev; + + cdev = to_ccwdev(dev); + if ((cdev->private->state == DEV_STATE_DISCONNECTED) && + (cdev->private->devno == d->devno) && + (cdev != d->sibling)) { + cdev->private->state = DEV_STATE_NOT_OPER; + return 1; + } + return 0; +} + static struct ccw_device * get_disc_ccwdev_by_devno(unsigned int devno, struct ccw_device *sibling) { - struct ccw_device *cdev; - struct list_head *entry; struct device *dev; + struct match_data data = { + .devno = devno, + .sibling = sibling, + }; - if (!get_bus(&ccw_bus_type)) - return NULL; - down_read(&ccw_bus_type.subsys.rwsem); - cdev = NULL; - list_for_each(entry, &ccw_bus_type.devices.list) { - dev = get_device(container_of(entry, - struct device, bus_list)); - if (!dev) - continue; - cdev = to_ccwdev(dev); - if ((cdev->private->state == DEV_STATE_DISCONNECTED) && - (cdev->private->devno == devno) && - (cdev != sibling)) { - cdev->private->state = DEV_STATE_NOT_OPER; - break; - } - put_device(dev); - cdev = NULL; - } - up_read(&ccw_bus_type.subsys.rwsem); - put_bus(&ccw_bus_type); + dev = bus_find_device(&css_bus_type, NULL, &data, match_devno); - return cdev; + return dev ? to_ccwdev(dev) : NULL; } static void @@ -647,7 +650,7 @@ io_subchannel_register(void *data) cdev = (struct ccw_device *) data; sch = to_subchannel(cdev->dev.parent); - if (!list_empty(&sch->dev.children)) { + if (klist_node_attached(&cdev->dev.knode_parent)) { bus_rescan_devices(&ccw_bus_type); goto out; } @@ -1019,30 +1022,29 @@ ccw_device_probe_console(void) /* * get ccw_device matching the busid, but only if owned by cdrv */ +static int +__ccwdev_check_busid(struct device *dev, void *id) +{ + char *bus_id; + + bus_id = (char *)id; + + return (strncmp(bus_id, dev->bus_id, BUS_ID_SIZE) == 0); +} + + struct ccw_device * get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id) { - struct device *d, *dev; + struct device *dev; struct device_driver *drv; drv = get_driver(&cdrv->driver); if (!drv) - return 0; - - down_read(&drv->bus->subsys.rwsem); - - dev = NULL; - list_for_each_entry(d, &drv->devices, driver_list) { - dev = get_device(d); + return NULL; - if (dev && !strncmp(bus_id, dev->bus_id, BUS_ID_SIZE)) - break; - else if (dev) { - put_device(dev); - dev = NULL; - } - } - up_read(&drv->bus->subsys.rwsem); + dev = driver_find_device(drv, NULL, (void *)bus_id, + __ccwdev_check_busid); put_driver(drv); return dev ? to_ccwdev(dev) : 0; diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 9b7f6f548b1..ee7a05e0c3b 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -235,6 +235,9 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) sch->schib.pmcw.pam & sch->schib.pmcw.pom & sch->opm; + /* Check since device may again have become not operational. */ + if (!sch->schib.pmcw.dnv) + state = DEV_STATE_NOT_OPER; if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) /* Force reprobe on all chpids. */ old_lpm = 0; diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index 4ab2e0d9500..12a24d4331a 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c @@ -39,15 +39,14 @@ ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb) " ... device %04X on subchannel %04X, dev_stat " ": %02X sch_stat : %02X\n", cdev->private->devno, cdev->private->irq, - cdev->private->irb.scsw.dstat, - cdev->private->irb.scsw.cstat); + irb->scsw.dstat, irb->scsw.cstat); if (irb->scsw.cc != 3) { char dbf_text[15]; sprintf(dbf_text, "chk%x", cdev->private->irq); CIO_TRACE_EVENT(0, dbf_text); - CIO_HEX_EVENT(0, &cdev->private->irb, sizeof (struct irb)); + CIO_HEX_EVENT(0, irb, sizeof (struct irb)); } } diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index bbe9f45d143..d36258d6665 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -56,7 +56,7 @@ #include "ioasm.h" #include "chsc.h" -#define VERSION_QDIO_C "$Revision: 1.98 $" +#define VERSION_QDIO_C "$Revision: 1.101 $" /****************** MODULE PARAMETER VARIABLES ********************/ MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>"); @@ -432,7 +432,7 @@ tiqdio_clear_global_summary(void) /************************* OUTBOUND ROUTINES *******************************/ -inline static int +static inline int qdio_get_outbound_buffer_frontier(struct qdio_q *q) { int f,f_mod_no; @@ -510,7 +510,7 @@ out: } /* all buffers are processed */ -inline static int +static inline int qdio_is_outbound_q_done(struct qdio_q *q) { int no_used; @@ -532,7 +532,7 @@ qdio_is_outbound_q_done(struct qdio_q *q) return (no_used==0); } -inline static int +static inline int qdio_has_outbound_q_moved(struct qdio_q *q) { int i; @@ -552,7 +552,7 @@ qdio_has_outbound_q_moved(struct qdio_q *q) } } -inline static void +static inline void qdio_kick_outbound_q(struct qdio_q *q) { int result; @@ -641,7 +641,7 @@ qdio_kick_outbound_q(struct qdio_q *q) } } -inline static void +static inline void qdio_kick_outbound_handler(struct qdio_q *q) { int start, end, real_end, count; @@ -740,7 +740,7 @@ qdio_outbound_processing(struct qdio_q *q) /************************* INBOUND ROUTINES *******************************/ -inline static int +static inline int qdio_get_inbound_buffer_frontier(struct qdio_q *q) { int f,f_mod_no; @@ -865,7 +865,7 @@ out: return q->first_to_check; } -inline static int +static inline int qdio_has_inbound_q_moved(struct qdio_q *q) { int i; @@ -898,7 +898,7 @@ qdio_has_inbound_q_moved(struct qdio_q *q) } /* means, no more buffers to be filled */ -inline static int +static inline int tiqdio_is_inbound_q_done(struct qdio_q *q) { int no_used; @@ -951,7 +951,7 @@ tiqdio_is_inbound_q_done(struct qdio_q *q) return 0; } -inline static int +static inline int qdio_is_inbound_q_done(struct qdio_q *q) { int no_used; @@ -1010,7 +1010,7 @@ qdio_is_inbound_q_done(struct qdio_q *q) } } -inline static void +static inline void qdio_kick_inbound_handler(struct qdio_q *q) { int count, start, end, real_end, i; @@ -3342,7 +3342,7 @@ static int qdio_register_dbf_views(void) { qdio_dbf_setup=debug_register(QDIO_DBF_SETUP_NAME, - QDIO_DBF_SETUP_INDEX, + QDIO_DBF_SETUP_PAGES, QDIO_DBF_SETUP_NR_AREAS, QDIO_DBF_SETUP_LEN); if (!qdio_dbf_setup) @@ -3351,7 +3351,7 @@ qdio_register_dbf_views(void) debug_set_level(qdio_dbf_setup,QDIO_DBF_SETUP_LEVEL); qdio_dbf_sbal=debug_register(QDIO_DBF_SBAL_NAME, - QDIO_DBF_SBAL_INDEX, + QDIO_DBF_SBAL_PAGES, QDIO_DBF_SBAL_NR_AREAS, QDIO_DBF_SBAL_LEN); if (!qdio_dbf_sbal) @@ -3361,7 +3361,7 @@ qdio_register_dbf_views(void) debug_set_level(qdio_dbf_sbal,QDIO_DBF_SBAL_LEVEL); qdio_dbf_sense=debug_register(QDIO_DBF_SENSE_NAME, - QDIO_DBF_SENSE_INDEX, + QDIO_DBF_SENSE_PAGES, QDIO_DBF_SENSE_NR_AREAS, QDIO_DBF_SENSE_LEN); if (!qdio_dbf_sense) @@ -3371,7 +3371,7 @@ qdio_register_dbf_views(void) debug_set_level(qdio_dbf_sense,QDIO_DBF_SENSE_LEVEL); qdio_dbf_trace=debug_register(QDIO_DBF_TRACE_NAME, - QDIO_DBF_TRACE_INDEX, + QDIO_DBF_TRACE_PAGES, QDIO_DBF_TRACE_NR_AREAS, QDIO_DBF_TRACE_LEN); if (!qdio_dbf_trace) @@ -3382,7 +3382,7 @@ qdio_register_dbf_views(void) #ifdef CONFIG_QDIO_DEBUG qdio_dbf_slsb_out=debug_register(QDIO_DBF_SLSB_OUT_NAME, - QDIO_DBF_SLSB_OUT_INDEX, + QDIO_DBF_SLSB_OUT_PAGES, QDIO_DBF_SLSB_OUT_NR_AREAS, QDIO_DBF_SLSB_OUT_LEN); if (!qdio_dbf_slsb_out) @@ -3391,7 +3391,7 @@ qdio_register_dbf_views(void) debug_set_level(qdio_dbf_slsb_out,QDIO_DBF_SLSB_OUT_LEVEL); qdio_dbf_slsb_in=debug_register(QDIO_DBF_SLSB_IN_NAME, - QDIO_DBF_SLSB_IN_INDEX, + QDIO_DBF_SLSB_IN_PAGES, QDIO_DBF_SLSB_IN_NR_AREAS, QDIO_DBF_SLSB_IN_LEN); if (!qdio_dbf_slsb_in) diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index b6daadac4e8..6b8aa6a852b 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -3,7 +3,7 @@ #include <asm/page.h> -#define VERSION_CIO_QDIO_H "$Revision: 1.32 $" +#define VERSION_CIO_QDIO_H "$Revision: 1.33 $" #ifdef CONFIG_QDIO_DEBUG #define QDIO_VERBOSE_LEVEL 9 @@ -132,7 +132,7 @@ enum qdio_irq_states { #define QDIO_DBF_SETUP_NAME "qdio_setup" #define QDIO_DBF_SETUP_LEN 8 -#define QDIO_DBF_SETUP_INDEX 2 +#define QDIO_DBF_SETUP_PAGES 4 #define QDIO_DBF_SETUP_NR_AREAS 1 #ifdef CONFIG_QDIO_DEBUG #define QDIO_DBF_SETUP_LEVEL 6 @@ -142,7 +142,7 @@ enum qdio_irq_states { #define QDIO_DBF_SBAL_NAME "qdio_labs" /* sbal */ #define QDIO_DBF_SBAL_LEN 256 -#define QDIO_DBF_SBAL_INDEX 2 +#define QDIO_DBF_SBAL_PAGES 4 #define QDIO_DBF_SBAL_NR_AREAS 2 #ifdef CONFIG_QDIO_DEBUG #define QDIO_DBF_SBAL_LEVEL 6 @@ -154,16 +154,16 @@ enum qdio_irq_states { #define QDIO_DBF_TRACE_LEN 8 #define QDIO_DBF_TRACE_NR_AREAS 2 #ifdef CONFIG_QDIO_DEBUG -#define QDIO_DBF_TRACE_INDEX 4 +#define QDIO_DBF_TRACE_PAGES 16 #define QDIO_DBF_TRACE_LEVEL 4 /* -------- could be even more verbose here */ #else /* CONFIG_QDIO_DEBUG */ -#define QDIO_DBF_TRACE_INDEX 2 +#define QDIO_DBF_TRACE_PAGES 4 #define QDIO_DBF_TRACE_LEVEL 2 #endif /* CONFIG_QDIO_DEBUG */ #define QDIO_DBF_SENSE_NAME "qdio_sense" #define QDIO_DBF_SENSE_LEN 64 -#define QDIO_DBF_SENSE_INDEX 1 +#define QDIO_DBF_SENSE_PAGES 2 #define QDIO_DBF_SENSE_NR_AREAS 1 #ifdef CONFIG_QDIO_DEBUG #define QDIO_DBF_SENSE_LEVEL 6 @@ -176,13 +176,13 @@ enum qdio_irq_states { #define QDIO_DBF_SLSB_OUT_NAME "qdio_slsb_out" #define QDIO_DBF_SLSB_OUT_LEN QDIO_MAX_BUFFERS_PER_Q -#define QDIO_DBF_SLSB_OUT_INDEX 8 +#define QDIO_DBF_SLSB_OUT_PAGES 256 #define QDIO_DBF_SLSB_OUT_NR_AREAS 1 #define QDIO_DBF_SLSB_OUT_LEVEL 6 #define QDIO_DBF_SLSB_IN_NAME "qdio_slsb_in" #define QDIO_DBF_SLSB_IN_LEN QDIO_MAX_BUFFERS_PER_Q -#define QDIO_DBF_SLSB_IN_INDEX 8 +#define QDIO_DBF_SLSB_IN_PAGES 256 #define QDIO_DBF_SLSB_IN_NR_AREAS 1 #define QDIO_DBF_SLSB_IN_LEVEL 6 #endif /* CONFIG_QDIO_DEBUG */ diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index a99927d54eb..24c0af49c25 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -146,8 +146,8 @@ claw_unregister_debug_facility(void) static int claw_register_debug_facility(void) { - claw_dbf_setup = debug_register("claw_setup", 1, 1, 8); - claw_dbf_trace = debug_register("claw_trace", 1, 2, 8); + claw_dbf_setup = debug_register("claw_setup", 2, 1, 8); + claw_dbf_trace = debug_register("claw_trace", 2, 2, 8); if (claw_dbf_setup == NULL || claw_dbf_trace == NULL) { printk(KERN_WARNING "Not enough memory for debug facility.\n"); claw_unregister_debug_facility(); @@ -428,7 +428,7 @@ claw_pack_skb(struct claw_privbk *privptr) new_skb = NULL; /* assume no dice */ pkt_cnt = 0; CLAW_DBF_TEXT(4,trace,"PackSKBe"); - if (skb_queue_len(&p_ch->collect_queue) > 0) { + if (!skb_queue_empty(&p_ch->collect_queue)) { /* some data */ held_skb = skb_dequeue(&p_ch->collect_queue); if (p_env->packing != DO_PACKED) @@ -1254,7 +1254,7 @@ claw_write_next ( struct chbk * p_ch ) privptr = (struct claw_privbk *) dev->priv; claw_free_wrt_buf( dev ); if ((privptr->write_free_count > 0) && - (skb_queue_len(&p_ch->collect_queue) > 0)) { + !skb_queue_empty(&p_ch->collect_queue)) { pk_skb = claw_pack_skb(privptr); while (pk_skb != NULL) { rc = claw_hw_tx( pk_skb, dev,1); diff --git a/drivers/s390/net/ctcdbug.c b/drivers/s390/net/ctcdbug.c index 2c86bfa11b2..0e2a8bb9303 100644 --- a/drivers/s390/net/ctcdbug.c +++ b/drivers/s390/net/ctcdbug.c @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/ctcdbug.c ($Revision: 1.4 $) + * linux/drivers/s390/net/ctcdbug.c ($Revision: 1.6 $) * * CTC / ESCON network driver - s390 dbf exploit. * @@ -9,7 +9,7 @@ * Author(s): Original Code written by * Peter Tiedemann (ptiedem@de.ibm.com) * - * $Revision: 1.4 $ $Date: 2004/08/04 10:11:59 $ + * $Revision: 1.6 $ $Date: 2005/05/11 08:10:17 $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -51,15 +51,15 @@ int ctc_register_dbf_views(void) { ctc_dbf_setup = debug_register(CTC_DBF_SETUP_NAME, - CTC_DBF_SETUP_INDEX, + CTC_DBF_SETUP_PAGES, CTC_DBF_SETUP_NR_AREAS, CTC_DBF_SETUP_LEN); ctc_dbf_data = debug_register(CTC_DBF_DATA_NAME, - CTC_DBF_DATA_INDEX, + CTC_DBF_DATA_PAGES, CTC_DBF_DATA_NR_AREAS, CTC_DBF_DATA_LEN); ctc_dbf_trace = debug_register(CTC_DBF_TRACE_NAME, - CTC_DBF_TRACE_INDEX, + CTC_DBF_TRACE_PAGES, CTC_DBF_TRACE_NR_AREAS, CTC_DBF_TRACE_LEN); diff --git a/drivers/s390/net/ctcdbug.h b/drivers/s390/net/ctcdbug.h index 7fe2ebd1792..7d6afa1627c 100644 --- a/drivers/s390/net/ctcdbug.h +++ b/drivers/s390/net/ctcdbug.h @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/ctcdbug.h ($Revision: 1.5 $) + * linux/drivers/s390/net/ctcdbug.h ($Revision: 1.6 $) * * CTC / ESCON network driver - s390 dbf exploit. * @@ -9,7 +9,7 @@ * Author(s): Original Code written by * Peter Tiedemann (ptiedem@de.ibm.com) * - * $Revision: 1.5 $ $Date: 2005/02/27 19:46:44 $ + * $Revision: 1.6 $ $Date: 2005/05/11 08:10:17 $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,19 +35,19 @@ */ #define CTC_DBF_SETUP_NAME "ctc_setup" #define CTC_DBF_SETUP_LEN 16 -#define CTC_DBF_SETUP_INDEX 3 +#define CTC_DBF_SETUP_PAGES 8 #define CTC_DBF_SETUP_NR_AREAS 1 #define CTC_DBF_SETUP_LEVEL 3 #define CTC_DBF_DATA_NAME "ctc_data" #define CTC_DBF_DATA_LEN 128 -#define CTC_DBF_DATA_INDEX 3 +#define CTC_DBF_DATA_PAGES 8 #define CTC_DBF_DATA_NR_AREAS 1 #define CTC_DBF_DATA_LEVEL 3 #define CTC_DBF_TRACE_NAME "ctc_trace" #define CTC_DBF_TRACE_LEN 16 -#define CTC_DBF_TRACE_INDEX 2 +#define CTC_DBF_TRACE_PAGES 4 #define CTC_DBF_TRACE_NR_AREAS 2 #define CTC_DBF_TRACE_LEVEL 3 diff --git a/drivers/s390/net/ctctty.c b/drivers/s390/net/ctctty.c index 3080393e823..968f2c113ef 100644 --- a/drivers/s390/net/ctctty.c +++ b/drivers/s390/net/ctctty.c @@ -156,7 +156,7 @@ ctc_tty_readmodem(ctc_tty_info *info) skb_queue_head(&info->rx_queue, skb); else { kfree_skb(skb); - ret = skb_queue_len(&info->rx_queue); + ret = !skb_queue_empty(&info->rx_queue); } } } @@ -530,7 +530,7 @@ ctc_tty_write(struct tty_struct *tty, const u_char * buf, int count) total += c; count -= c; } - if (skb_queue_len(&info->tx_queue)) { + if (!skb_queue_empty(&info->tx_queue)) { info->lsr &= ~UART_LSR_TEMT; tasklet_schedule(&info->tasklet); } @@ -594,7 +594,7 @@ ctc_tty_flush_chars(struct tty_struct *tty) return; if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_flush_chars")) return; - if (tty->stopped || tty->hw_stopped || (!skb_queue_len(&info->tx_queue))) + if (tty->stopped || tty->hw_stopped || skb_queue_empty(&info->tx_queue)) return; tasklet_schedule(&info->tasklet); } diff --git a/drivers/s390/net/iucv.h b/drivers/s390/net/iucv.h index 198330217ef..0c4644d3d2f 100644 --- a/drivers/s390/net/iucv.h +++ b/drivers/s390/net/iucv.h @@ -37,19 +37,19 @@ */ #define IUCV_DBF_SETUP_NAME "iucv_setup" #define IUCV_DBF_SETUP_LEN 32 -#define IUCV_DBF_SETUP_INDEX 1 +#define IUCV_DBF_SETUP_PAGES 2 #define IUCV_DBF_SETUP_NR_AREAS 1 #define IUCV_DBF_SETUP_LEVEL 3 #define IUCV_DBF_DATA_NAME "iucv_data" #define IUCV_DBF_DATA_LEN 128 -#define IUCV_DBF_DATA_INDEX 1 +#define IUCV_DBF_DATA_PAGES 2 #define IUCV_DBF_DATA_NR_AREAS 1 #define IUCV_DBF_DATA_LEVEL 2 #define IUCV_DBF_TRACE_NAME "iucv_trace" #define IUCV_DBF_TRACE_LEN 16 -#define IUCV_DBF_TRACE_INDEX 2 +#define IUCV_DBF_TRACE_PAGES 4 #define IUCV_DBF_TRACE_NR_AREAS 1 #define IUCV_DBF_TRACE_LEVEL 3 diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index ab086242d30..46f34ba93ac 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -11,7 +11,7 @@ * Frank Pavlic (pavlic@de.ibm.com) and * Martin Schwidefsky <schwidefsky@de.ibm.com> * - * $Revision: 1.98 $ $Date: 2005/04/18 13:41:29 $ + * $Revision: 1.99 $ $Date: 2005/05/11 08:10:17 $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -59,7 +59,7 @@ /** * initialization string for output */ -#define VERSION_LCS_C "$Revision: 1.98 $" +#define VERSION_LCS_C "$Revision: 1.99 $" static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")"; static char debug_buffer[255]; @@ -93,8 +93,8 @@ lcs_unregister_debug_facility(void) static int lcs_register_debug_facility(void) { - lcs_dbf_setup = debug_register("lcs_setup", 1, 1, 8); - lcs_dbf_trace = debug_register("lcs_trace", 1, 2, 8); + lcs_dbf_setup = debug_register("lcs_setup", 2, 1, 8); + lcs_dbf_trace = debug_register("lcs_trace", 2, 2, 8); if (lcs_dbf_setup == NULL || lcs_dbf_trace == NULL) { PRINT_ERR("Not enough memory for debug facility.\n"); lcs_unregister_debug_facility(); diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 3fd4fb754b2..69425a7a6e9 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1,5 +1,5 @@ /* - * $Id: netiucv.c,v 1.63 2004/07/27 13:36:05 mschwide Exp $ + * $Id: netiucv.c,v 1.66 2005/05/11 08:10:17 holzheu Exp $ * * IUCV network driver * @@ -30,7 +30,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: IUCV network driver $Revision: 1.63 $ + * RELEASE-TAG: IUCV network driver $Revision: 1.66 $ * */ @@ -391,15 +391,15 @@ static int iucv_register_dbf_views(void) { iucv_dbf_setup = debug_register(IUCV_DBF_SETUP_NAME, - IUCV_DBF_SETUP_INDEX, + IUCV_DBF_SETUP_PAGES, IUCV_DBF_SETUP_NR_AREAS, IUCV_DBF_SETUP_LEN); iucv_dbf_data = debug_register(IUCV_DBF_DATA_NAME, - IUCV_DBF_DATA_INDEX, + IUCV_DBF_DATA_PAGES, IUCV_DBF_DATA_NR_AREAS, IUCV_DBF_DATA_LEN); iucv_dbf_trace = debug_register(IUCV_DBF_TRACE_NAME, - IUCV_DBF_TRACE_INDEX, + IUCV_DBF_TRACE_PAGES, IUCV_DBF_TRACE_NR_AREAS, IUCV_DBF_TRACE_LEN); @@ -2076,7 +2076,7 @@ DRIVER_ATTR(remove, 0200, NULL, remove_write); static void netiucv_banner(void) { - char vbuf[] = "$Revision: 1.63 $"; + char vbuf[] = "$Revision: 1.66 $"; char *version = vbuf; if ((version = strchr(version, ':'))) { diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index a755b57db46..3a0285669ad 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h @@ -42,44 +42,44 @@ */ #define QETH_DBF_SETUP_NAME "qeth_setup" #define QETH_DBF_SETUP_LEN 8 -#define QETH_DBF_SETUP_INDEX 3 +#define QETH_DBF_SETUP_PAGES 8 #define QETH_DBF_SETUP_NR_AREAS 1 #define QETH_DBF_SETUP_LEVEL 5 #define QETH_DBF_MISC_NAME "qeth_misc" #define QETH_DBF_MISC_LEN 128 -#define QETH_DBF_MISC_INDEX 1 +#define QETH_DBF_MISC_PAGES 2 #define QETH_DBF_MISC_NR_AREAS 1 #define QETH_DBF_MISC_LEVEL 2 #define QETH_DBF_DATA_NAME "qeth_data" #define QETH_DBF_DATA_LEN 96 -#define QETH_DBF_DATA_INDEX 3 +#define QETH_DBF_DATA_PAGES 8 #define QETH_DBF_DATA_NR_AREAS 1 #define QETH_DBF_DATA_LEVEL 2 #define QETH_DBF_CONTROL_NAME "qeth_control" #define QETH_DBF_CONTROL_LEN 256 -#define QETH_DBF_CONTROL_INDEX 3 +#define QETH_DBF_CONTROL_PAGES 8 #define QETH_DBF_CONTROL_NR_AREAS 2 #define QETH_DBF_CONTROL_LEVEL 5 #define QETH_DBF_TRACE_NAME "qeth_trace" #define QETH_DBF_TRACE_LEN 8 -#define QETH_DBF_TRACE_INDEX 2 +#define QETH_DBF_TRACE_PAGES 4 #define QETH_DBF_TRACE_NR_AREAS 2 #define QETH_DBF_TRACE_LEVEL 3 extern debug_info_t *qeth_dbf_trace; #define QETH_DBF_SENSE_NAME "qeth_sense" #define QETH_DBF_SENSE_LEN 64 -#define QETH_DBF_SENSE_INDEX 1 +#define QETH_DBF_SENSE_PAGES 2 #define QETH_DBF_SENSE_NR_AREAS 1 #define QETH_DBF_SENSE_LEVEL 2 #define QETH_DBF_QERR_NAME "qeth_qerr" #define QETH_DBF_QERR_LEN 8 -#define QETH_DBF_QERR_INDEX 1 +#define QETH_DBF_QERR_PAGES 2 #define QETH_DBF_QERR_NR_AREAS 2 #define QETH_DBF_QERR_LEVEL 2 @@ -824,7 +824,7 @@ extern struct list_head qeth_notify_list; #define QETH_CARD_IFNAME(card) (((card)->dev)? (card)->dev->name : "") -inline static __u8 +static inline __u8 qeth_get_ipa_adp_type(enum qeth_link_types link_type) { switch (link_type) { @@ -835,7 +835,7 @@ qeth_get_ipa_adp_type(enum qeth_link_types link_type) } } -inline static int +static inline int qeth_realloc_headroom(struct qeth_card *card, struct sk_buff **skb, int size) { struct sk_buff *new_skb = NULL; @@ -852,6 +852,7 @@ qeth_realloc_headroom(struct qeth_card *card, struct sk_buff **skb, int size) } return 0; } + static inline struct sk_buff * qeth_pskb_unshare(struct sk_buff *skb, int pri) { @@ -863,8 +864,7 @@ qeth_pskb_unshare(struct sk_buff *skb, int pri) return nskb; } - -inline static void * +static inline void * qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size) { void *hdr; @@ -887,7 +887,7 @@ qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size) } -inline static int +static inline int qeth_get_hlen(__u8 link_type) { #ifdef CONFIG_QETH_IPV6 @@ -911,7 +911,7 @@ qeth_get_hlen(__u8 link_type) #endif /* CONFIG_QETH_IPV6 */ } -inline static unsigned short +static inline unsigned short qeth_get_netdev_flags(struct qeth_card *card) { if (card->options.layer2) @@ -929,7 +929,7 @@ qeth_get_netdev_flags(struct qeth_card *card) } } -inline static int +static inline int qeth_get_initial_mtu_for_card(struct qeth_card * card) { switch (card->info.type) { @@ -950,7 +950,7 @@ qeth_get_initial_mtu_for_card(struct qeth_card * card) } } -inline static int +static inline int qeth_get_max_mtu_for_card(int cardtype) { switch (cardtype) { @@ -965,7 +965,7 @@ qeth_get_max_mtu_for_card(int cardtype) } } -inline static int +static inline int qeth_get_mtu_out_of_mpc(int cardtype) { switch (cardtype) { @@ -976,7 +976,7 @@ qeth_get_mtu_out_of_mpc(int cardtype) } } -inline static int +static inline int qeth_get_mtu_outof_framesize(int framesize) { switch (framesize) { @@ -993,7 +993,7 @@ qeth_get_mtu_outof_framesize(int framesize) } } -inline static int +static inline int qeth_mtu_is_valid(struct qeth_card * card, int mtu) { switch (card->info.type) { @@ -1008,7 +1008,7 @@ qeth_mtu_is_valid(struct qeth_card * card, int mtu) } } -inline static int +static inline int qeth_get_arphdr_type(int cardtype, int linktype) { switch (cardtype) { @@ -1027,7 +1027,7 @@ qeth_get_arphdr_type(int cardtype, int linktype) } #ifdef CONFIG_QETH_PERF_STATS -inline static int +static inline int qeth_get_micros(void) { return (int) (get_clock() >> 12); diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 208127a5033..79c74f3a11f 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -2210,7 +2210,7 @@ no_mem: return NULL; } -static inline unsigned short +static inline __be16 qeth_type_trans(struct sk_buff *skb, struct net_device *dev) { struct qeth_card *card; @@ -7639,31 +7639,31 @@ static int qeth_register_dbf_views(void) { qeth_dbf_setup = debug_register(QETH_DBF_SETUP_NAME, - QETH_DBF_SETUP_INDEX, + QETH_DBF_SETUP_PAGES, QETH_DBF_SETUP_NR_AREAS, QETH_DBF_SETUP_LEN); qeth_dbf_misc = debug_register(QETH_DBF_MISC_NAME, - QETH_DBF_MISC_INDEX, + QETH_DBF_MISC_PAGES, QETH_DBF_MISC_NR_AREAS, QETH_DBF_MISC_LEN); qeth_dbf_data = debug_register(QETH_DBF_DATA_NAME, - QETH_DBF_DATA_INDEX, + QETH_DBF_DATA_PAGES, QETH_DBF_DATA_NR_AREAS, QETH_DBF_DATA_LEN); qeth_dbf_control = debug_register(QETH_DBF_CONTROL_NAME, - QETH_DBF_CONTROL_INDEX, + QETH_DBF_CONTROL_PAGES, QETH_DBF_CONTROL_NR_AREAS, QETH_DBF_CONTROL_LEN); qeth_dbf_sense = debug_register(QETH_DBF_SENSE_NAME, - QETH_DBF_SENSE_INDEX, + QETH_DBF_SENSE_PAGES, QETH_DBF_SENSE_NR_AREAS, QETH_DBF_SENSE_LEN); qeth_dbf_qerr = debug_register(QETH_DBF_QERR_NAME, - QETH_DBF_QERR_INDEX, + QETH_DBF_QERR_PAGES, QETH_DBF_QERR_NR_AREAS, QETH_DBF_QERR_LEN); qeth_dbf_trace = debug_register(QETH_DBF_TRACE_NAME, - QETH_DBF_TRACE_INDEX, + QETH_DBF_TRACE_PAGES, QETH_DBF_TRACE_NR_AREAS, QETH_DBF_TRACE_LEN); @@ -8120,20 +8120,22 @@ static struct notifier_block qeth_ip6_notifier = { #endif static int -qeth_reboot_event(struct notifier_block *this, unsigned long event, void *ptr) +__qeth_reboot_event_card(struct device *dev, void *data) { - - struct device *entry; struct qeth_card *card; - down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem); - list_for_each_entry(entry, &qeth_ccwgroup_driver.driver.devices, - driver_list) { - card = (struct qeth_card *) entry->driver_data; - qeth_clear_ip_list(card, 0, 0); - qeth_qdio_clear_card(card, 0); - } - up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem); + card = (struct qeth_card *) dev->driver_data; + qeth_clear_ip_list(card, 0, 0); + qeth_qdio_clear_card(card, 0); + return 0; +} + +static int +qeth_reboot_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + + driver_for_each_device(&qeth_ccwgroup_driver.driver, NULL, NULL, + __qeth_reboot_event_card); return NOTIFY_DONE; } diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c index 04719196fd2..f2ccfea8fdb 100644 --- a/drivers/s390/net/qeth_proc.c +++ b/drivers/s390/net/qeth_proc.c @@ -27,23 +27,33 @@ const char *VERSION_QETH_PROC_C = "$Revision: 1.13 $"; #define QETH_PROCFILE_NAME "qeth" static struct proc_dir_entry *qeth_procfile; +static int +qeth_procfile_seq_match(struct device *dev, void *data) +{ + return 1; +} + static void * qeth_procfile_seq_start(struct seq_file *s, loff_t *offset) { - struct list_head *next_card = NULL; - int i = 0; + struct device *dev; + loff_t nr; down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem); - if (*offset == 0) + nr = *offset; + if (nr == 0) return SEQ_START_TOKEN; - /* get card at pos *offset */ - list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices) - if (++i == *offset) - return next_card; + dev = driver_find_device(&qeth_ccwgroup_driver.driver, NULL, + NULL, qeth_procfile_seq_match); - return NULL; + /* get card at pos *offset */ + nr = *offset; + while (nr-- > 1 && dev) + dev = driver_find_device(&qeth_ccwgroup_driver.driver, dev, + NULL, qeth_procfile_seq_match); + return (void *) dev; } static void @@ -55,23 +65,21 @@ qeth_procfile_seq_stop(struct seq_file *s, void* it) static void * qeth_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset) { - struct list_head *next_card = NULL; - struct list_head *current_card; + struct device *prev, *next; if (it == SEQ_START_TOKEN) { - next_card = qeth_ccwgroup_driver.driver.devices.next; - if (next_card->next == next_card) /* list empty */ - return NULL; - (*offset)++; - } else { - current_card = (struct list_head *)it; - if (current_card->next == &qeth_ccwgroup_driver.driver.devices) - return NULL; /* end of list reached */ - next_card = current_card->next; - (*offset)++; + next = driver_find_device(&qeth_ccwgroup_driver.driver, + NULL, NULL, qeth_procfile_seq_match); + if (next) + (*offset)++; + return (void *) next; } - - return next_card; + prev = (struct device *) it; + next = driver_find_device(&qeth_ccwgroup_driver.driver, + prev, NULL, qeth_procfile_seq_match); + if (next) + (*offset)++; + return (void *) next; } static inline const char * @@ -126,7 +134,7 @@ qeth_procfile_seq_show(struct seq_file *s, void *it) "-------------- ---- ------ ---------- ---- " "---- ----- -----\n"); } else { - device = list_entry(it, struct device, driver_list); + device = (struct device *) it; card = device->driver_data; seq_printf(s, "%s/%s/%s x%02X %-10s %-14s %-4i ", CARD_RDEV_ID(card), @@ -180,17 +188,20 @@ static struct proc_dir_entry *qeth_perf_procfile; static void * qeth_perf_procfile_seq_start(struct seq_file *s, loff_t *offset) { - struct list_head *next_card = NULL; - int i = 0; + struct device *dev = NULL; + int nr; down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem); /* get card at pos *offset */ - list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices){ - if (i == *offset) - return next_card; - i++; - } - return NULL; + dev = driver_find_device(&qeth_ccwgroup_driver.driver, NULL, NULL, + qeth_procfile_seq_match); + + /* get card at pos *offset */ + nr = *offset; + while (nr-- > 1 && dev) + dev = driver_find_device(&qeth_ccwgroup_driver.driver, dev, + NULL, qeth_procfile_seq_match); + return (void *) dev; } static void @@ -202,12 +213,14 @@ qeth_perf_procfile_seq_stop(struct seq_file *s, void* it) static void * qeth_perf_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset) { - struct list_head *current_card = (struct list_head *)it; + struct device *prev, *next; - if (current_card->next == &qeth_ccwgroup_driver.driver.devices) - return NULL; /* end of list reached */ - (*offset)++; - return current_card->next; + prev = (struct device *) it; + next = driver_find_device(&qeth_ccwgroup_driver.driver, prev, + NULL, qeth_procfile_seq_match); + if (next) + (*offset)++; + return (void *) next; } static int @@ -216,7 +229,7 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it) struct device *device; struct qeth_card *card; - device = list_entry(it, struct device, driver_list); + device = (struct device *) it; card = device->driver_data; seq_printf(s, "For card with devnos %s/%s/%s (%s):\n", CARD_RDEV_ID(card), @@ -318,8 +331,8 @@ static struct proc_dir_entry *qeth_ipato_procfile; static void * qeth_ipato_procfile_seq_start(struct seq_file *s, loff_t *offset) { - struct list_head *next_card = NULL; - int i = 0; + struct device *dev; + loff_t nr; down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem); /* TODO: finish this */ @@ -328,13 +341,16 @@ qeth_ipato_procfile_seq_start(struct seq_file *s, loff_t *offset) * output driver settings then; * else output setting for respective card */ + + dev = driver_find_device(&qeth_ccwgroup_driver.driver, NULL, NULL, + qeth_procfile_seq_match); + /* get card at pos *offset */ - list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices){ - if (i == *offset) - return next_card; - i++; - } - return NULL; + nr = *offset; + while (nr-- > 1 && dev) + dev = driver_find_device(&qeth_ccwgroup_driver.driver, dev, + NULL, qeth_procfile_seq_match); + return (void *) dev; } static void @@ -346,18 +362,14 @@ qeth_ipato_procfile_seq_stop(struct seq_file *s, void* it) static void * qeth_ipato_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset) { - struct list_head *current_card = (struct list_head *)it; + struct device *prev, *next; - /* TODO: finish this */ - /* - * maybe SEQ_SATRT_TOKEN can be returned for offset 0 - * output driver settings then; - * else output setting for respective card - */ - if (current_card->next == &qeth_ccwgroup_driver.driver.devices) - return NULL; /* end of list reached */ - (*offset)++; - return current_card->next; + prev = (struct device *) it; + next = driver_find_device(&qeth_ccwgroup_driver.driver, prev, + NULL, qeth_procfile_seq_match); + if (next) + (*offset)++; + return (void *) next; } static int @@ -372,7 +384,7 @@ qeth_ipato_procfile_seq_show(struct seq_file *s, void *it) * output driver settings then; * else output setting for respective card */ - device = list_entry(it, struct device, driver_list); + device = (struct device *) it; card = device->driver_data; return 0; diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index 1e3f7f3c662..d6469baa7e1 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c @@ -138,7 +138,7 @@ static void __exit smsg_exit(void) { if (smsg_handle > 0) { - cpcmd("SET SMSG OFF", 0, 0); + cpcmd("SET SMSG OFF", NULL, 0, NULL); iucv_sever(smsg_pathid, 0); iucv_unregister_program(smsg_handle); driver_unregister(&smsg_driver); @@ -177,7 +177,7 @@ smsg_init(void) smsg_handle = 0; return -EIO; } - cpcmd("SET SMSG IUCV", 0, 0); + cpcmd("SET SMSG IUCV", NULL, 0, NULL); return 0; } diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index ffa996c8a90..5bb255e02ac 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c @@ -31,14 +31,14 @@ extern void css_reiterate_subchannels(void); extern struct workqueue_struct *slow_path_wq; extern struct work_struct slow_path_work; -static void +static NORET_TYPE void s390_handle_damage(char *msg) { - printk(KERN_EMERG "%s\n", msg); #ifdef CONFIG_SMP smp_send_stop(); #endif disabled_wait((unsigned long) __builtin_return_address(0)); + for(;;); } /* @@ -122,40 +122,39 @@ repeat: return 0; } +struct mcck_struct { + int kill_task; + int channel_report; + int warning; + unsigned long long mcck_code; +}; + +static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck); + /* - * machine check handler. + * Main machine check handler function. Will be called with interrupts enabled + * or disabled and machine checks enabled or disabled. */ void -s390_do_machine_check(void) +s390_handle_mcck(void) { - struct mci *mci; - - mci = (struct mci *) &S390_lowcore.mcck_interruption_code; + unsigned long flags; + struct mcck_struct mcck; - if (mci->sd) /* system damage */ - s390_handle_damage("received system damage machine check\n"); + /* + * Disable machine checks and get the current state of accumulated + * machine checks. Afterwards delete the old state and enable machine + * checks again. + */ + local_irq_save(flags); + local_mcck_disable(); + mcck = __get_cpu_var(cpu_mcck); + memset(&__get_cpu_var(cpu_mcck), 0, sizeof(struct mcck_struct)); + clear_thread_flag(TIF_MCCK_PENDING); + local_mcck_enable(); + local_irq_restore(flags); - if (mci->pd) /* instruction processing damage */ - s390_handle_damage("received instruction processing " - "damage machine check\n"); - - if (mci->se) /* storage error uncorrected */ - s390_handle_damage("received storage error uncorrected " - "machine check\n"); - - if (mci->sc) /* storage error corrected */ - printk(KERN_WARNING - "received storage error corrected machine check\n"); - - if (mci->ke) /* storage key-error uncorrected */ - s390_handle_damage("received storage key-error uncorrected " - "machine check\n"); - - if (mci->ds && mci->fa) /* storage degradation */ - s390_handle_damage("received storage degradation machine " - "check\n"); - - if (mci->cp) /* channel report word pending */ + if (mcck.channel_report) up(&m_sem); #ifdef CONFIG_MACHCHK_WARNING @@ -168,7 +167,7 @@ s390_do_machine_check(void) * On VM we only get one interrupt per virtally presented machinecheck. * Though one suffices, we may get one interrupt per (virtual) processor. */ - if (mci->w) { /* WARNING pending ? */ + if (mcck.warning) { /* WARNING pending ? */ static int mchchk_wng_posted = 0; /* * Use single machine clear, as we cannot handle smp right now @@ -178,6 +177,261 @@ s390_do_machine_check(void) kill_proc(1, SIGPWR, 1); } #endif + + if (mcck.kill_task) { + local_irq_enable(); + printk(KERN_EMERG "mcck: Terminating task because of machine " + "malfunction (code 0x%016llx).\n", mcck.mcck_code); + printk(KERN_EMERG "mcck: task: %s, pid: %d.\n", + current->comm, current->pid); + do_exit(SIGSEGV); + } +} + +/* + * returns 0 if all registers could be validated + * returns 1 otherwise + */ +static int +s390_revalidate_registers(struct mci *mci) +{ + int kill_task; + u64 tmpclock; + u64 zero; + void *fpt_save_area, *fpt_creg_save_area; + + kill_task = 0; + zero = 0; + /* General purpose registers */ + if (!mci->gr) + /* + * General purpose registers couldn't be restored and have + * unknown contents. Process needs to be terminated. + */ + kill_task = 1; + + /* Revalidate floating point registers */ + if (!mci->fp) + /* + * Floating point registers can't be restored and + * therefore the process needs to be terminated. + */ + kill_task = 1; + +#ifndef __s390x__ + asm volatile("ld 0,0(%0)\n" + "ld 2,8(%0)\n" + "ld 4,16(%0)\n" + "ld 6,24(%0)" + : : "a" (&S390_lowcore.floating_pt_save_area)); +#endif + + if (MACHINE_HAS_IEEE) { +#ifdef __s390x__ + fpt_save_area = &S390_lowcore.floating_pt_save_area; + fpt_creg_save_area = &S390_lowcore.fpt_creg_save_area; +#else + fpt_save_area = (void *) S390_lowcore.extended_save_area_addr; + fpt_creg_save_area = fpt_save_area+128; +#endif + /* Floating point control register */ + if (!mci->fc) { + /* + * Floating point control register can't be restored. + * Task will be terminated. + */ + asm volatile ("lfpc 0(%0)" : : "a" (&zero)); + kill_task = 1; + + } + else + asm volatile ( + "lfpc 0(%0)" + : : "a" (fpt_creg_save_area)); + + asm volatile("ld 0,0(%0)\n" + "ld 1,8(%0)\n" + "ld 2,16(%0)\n" + "ld 3,24(%0)\n" + "ld 4,32(%0)\n" + "ld 5,40(%0)\n" + "ld 6,48(%0)\n" + "ld 7,56(%0)\n" + "ld 8,64(%0)\n" + "ld 9,72(%0)\n" + "ld 10,80(%0)\n" + "ld 11,88(%0)\n" + "ld 12,96(%0)\n" + "ld 13,104(%0)\n" + "ld 14,112(%0)\n" + "ld 15,120(%0)\n" + : : "a" (fpt_save_area)); + } + + /* Revalidate access registers */ + asm volatile("lam 0,15,0(%0)" + : : "a" (&S390_lowcore.access_regs_save_area)); + if (!mci->ar) + /* + * Access registers have unknown contents. + * Terminating task. + */ + kill_task = 1; + + /* Revalidate control registers */ + if (!mci->cr) + /* + * Control registers have unknown contents. + * Can't recover and therefore stopping machine. + */ + s390_handle_damage("invalid control registers."); + else +#ifdef __s390x__ + asm volatile("lctlg 0,15,0(%0)" + : : "a" (&S390_lowcore.cregs_save_area)); +#else + asm volatile("lctl 0,15,0(%0)" + : : "a" (&S390_lowcore.cregs_save_area)); +#endif + + /* + * We don't even try to revalidate the TOD register, since we simply + * can't write something sensible into that register. + */ + +#ifdef __s390x__ + /* + * See if we can revalidate the TOD programmable register with its + * old contents (should be zero) otherwise set it to zero. + */ + if (!mci->pr) + asm volatile("sr 0,0\n" + "sckpf" + : : : "0", "cc"); + else + asm volatile( + "l 0,0(%0)\n" + "sckpf" + : : "a" (&S390_lowcore.tod_progreg_save_area) : "0", "cc"); +#endif + + /* Revalidate clock comparator register */ + asm volatile ("stck 0(%1)\n" + "sckc 0(%1)" + : "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory"); + + /* Check if old PSW is valid */ + if (!mci->wp) + /* + * Can't tell if we come from user or kernel mode + * -> stopping machine. + */ + s390_handle_damage("old psw invalid."); + + if (!mci->ms || !mci->pm || !mci->ia) + kill_task = 1; + + return kill_task; +} + +/* + * machine check handler. + */ +void +s390_do_machine_check(struct pt_regs *regs) +{ + struct mci *mci; + struct mcck_struct *mcck; + int umode; + + mci = (struct mci *) &S390_lowcore.mcck_interruption_code; + mcck = &__get_cpu_var(cpu_mcck); + umode = user_mode(regs); + + if (mci->sd) + /* System damage -> stopping machine */ + s390_handle_damage("received system damage machine check."); + + if (mci->pd) { + if (mci->b) { + /* Processing backup -> verify if we can survive this */ + u64 z_mcic, o_mcic, t_mcic; +#ifdef __s390x__ + z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<29); + o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 | + 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 | + 1ULL<<30 | 1ULL<<21 | 1ULL<<20 | 1ULL<<17 | + 1ULL<<16); +#else + z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<57 | 1ULL<<50 | + 1ULL<<29); + o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 | + 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 | + 1ULL<<30 | 1ULL<<20 | 1ULL<<17 | 1ULL<<16); +#endif + t_mcic = *(u64 *)mci; + + if (((t_mcic & z_mcic) != 0) || + ((t_mcic & o_mcic) != o_mcic)) { + s390_handle_damage("processing backup machine " + "check with damage."); + } + if (!umode) + s390_handle_damage("processing backup machine " + "check in kernel mode."); + mcck->kill_task = 1; + mcck->mcck_code = *(unsigned long long *) mci; + } + else { + /* Processing damage -> stopping machine */ + s390_handle_damage("received instruction processing " + "damage machine check."); + } + } + if (s390_revalidate_registers(mci)) { + if (umode) { + /* + * Couldn't restore all register contents while in + * user mode -> mark task for termination. + */ + mcck->kill_task = 1; + mcck->mcck_code = *(unsigned long long *) mci; + set_thread_flag(TIF_MCCK_PENDING); + } + else + /* + * Couldn't restore all register contents while in + * kernel mode -> stopping machine. + */ + s390_handle_damage("unable to revalidate registers."); + } + + if (mci->se) + /* Storage error uncorrected */ + s390_handle_damage("received storage error uncorrected " + "machine check."); + + if (mci->ke) + /* Storage key-error uncorrected */ + s390_handle_damage("received storage key-error uncorrected " + "machine check."); + + if (mci->ds && mci->fa) + /* Storage degradation */ + s390_handle_damage("received storage degradation machine " + "check."); + + if (mci->cp) { + /* Channel report word pending */ + mcck->channel_report = 1; + set_thread_flag(TIF_MCCK_PENDING); + } + + if (mci->w) { + /* Warning pending */ + mcck->warning = 1; + set_thread_flag(TIF_MCCK_PENDING); + } } /* @@ -189,9 +443,8 @@ static int machine_check_init(void) { init_MUTEX_LOCKED(&m_sem); - ctl_clear_bit(14, 25); /* disable damage MCH */ - ctl_set_bit(14, 26); /* enable degradation MCH */ - ctl_set_bit(14, 27); /* enable system recovery MCH */ + ctl_clear_bit(14, 25); /* disable external damage MCH */ + ctl_set_bit(14, 27); /* enable system recovery MCH */ #ifdef CONFIG_MACHCHK_WARNING ctl_set_bit(14, 24); /* enable warning MCH */ #endif diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h index 7e26f0f1b0d..4eaa7017918 100644 --- a/drivers/s390/s390mach.h +++ b/drivers/s390/s390mach.h @@ -16,20 +16,45 @@ struct mci { __u32 sd : 1; /* 00 system damage */ __u32 pd : 1; /* 01 instruction-processing damage */ __u32 sr : 1; /* 02 system recovery */ - __u32 to_be_defined_1 : 4; /* 03-06 */ + __u32 to_be_defined_1 : 1; /* 03 */ + __u32 cd : 1; /* 04 timing-facility damage */ + __u32 ed : 1; /* 05 external damage */ + __u32 to_be_defined_2 : 1; /* 06 */ __u32 dg : 1; /* 07 degradation */ __u32 w : 1; /* 08 warning pending */ __u32 cp : 1; /* 09 channel-report pending */ - __u32 to_be_defined_2 : 6; /* 10-15 */ + __u32 sp : 1; /* 10 service-processor damage */ + __u32 ck : 1; /* 11 channel-subsystem damage */ + __u32 to_be_defined_3 : 2; /* 12-13 */ + __u32 b : 1; /* 14 backed up */ + __u32 to_be_defined_4 : 1; /* 15 */ __u32 se : 1; /* 16 storage error uncorrected */ __u32 sc : 1; /* 17 storage error corrected */ __u32 ke : 1; /* 18 storage-key error uncorrected */ __u32 ds : 1; /* 19 storage degradation */ - __u32 to_be_defined_3 : 4; /* 20-23 */ + __u32 wp : 1; /* 20 psw mwp validity */ + __u32 ms : 1; /* 21 psw mask and key validity */ + __u32 pm : 1; /* 22 psw program mask and cc validity */ + __u32 ia : 1; /* 23 psw instruction address validity */ __u32 fa : 1; /* 24 failing storage address validity */ - __u32 to_be_defined_4 : 7; /* 25-31 */ + __u32 to_be_defined_5 : 1; /* 25 */ + __u32 ec : 1; /* 26 external damage code validity */ + __u32 fp : 1; /* 27 floating point register validity */ + __u32 gr : 1; /* 28 general register validity */ + __u32 cr : 1; /* 29 control register validity */ + __u32 to_be_defined_6 : 1; /* 30 */ + __u32 st : 1; /* 31 storage logical validity */ __u32 ie : 1; /* 32 indirect storage error */ - __u32 to_be_defined_5 : 31; /* 33-63 */ + __u32 ar : 1; /* 33 access register validity */ + __u32 da : 1; /* 34 delayed access exception */ + __u32 to_be_defined_7 : 7; /* 35-41 */ + __u32 pr : 1; /* 42 tod programmable register validity */ + __u32 fc : 1; /* 43 fp control register validity */ + __u32 ap : 1; /* 44 ancillary report */ + __u32 to_be_defined_8 : 1; /* 45 */ + __u32 ct : 1; /* 46 cpu timer validity */ + __u32 cc : 1; /* 47 clock comparator validity */ + __u32 to_be_defined_9 : 16; /* 47-63 */ }; /* |