aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/block/dasd.c4
-rw-r--r--drivers/s390/block/dasd_diag.c1
-rw-r--r--drivers/s390/block/dasd_eckd.c4
-rw-r--r--drivers/s390/block/dasd_int.h2
-rw-r--r--drivers/s390/block/dcssblk.c2
-rw-r--r--drivers/s390/block/xpram.c2
-rw-r--r--drivers/s390/char/Kconfig12
-rw-r--r--drivers/s390/char/monwriter.c6
-rw-r--r--drivers/s390/char/raw3270.c7
-rw-r--r--drivers/s390/char/sclp_vt220.c62
-rw-r--r--drivers/s390/char/tape.h2
-rw-r--r--drivers/s390/char/tape_block.c4
-rw-r--r--drivers/s390/char/vmur.c428
-rw-r--r--drivers/s390/char/vmur.h6
-rw-r--r--drivers/s390/cio/blacklist.c19
-rw-r--r--drivers/s390/cio/ccwgroup.c3
-rw-r--r--drivers/s390/cio/chp.c19
-rw-r--r--drivers/s390/cio/chsc.c26
-rw-r--r--drivers/s390/cio/chsc.h2
-rw-r--r--drivers/s390/cio/cio.c13
-rw-r--r--drivers/s390/cio/cio_debug.h2
-rw-r--r--drivers/s390/cio/cmf.c20
-rw-r--r--drivers/s390/cio/css.c33
-rw-r--r--drivers/s390/cio/css.h1
-rw-r--r--drivers/s390/cio/device.c65
-rw-r--r--drivers/s390/cio/device_fsm.c20
-rw-r--r--drivers/s390/cio/device_id.c48
-rw-r--r--drivers/s390/cio/device_ops.c257
-rw-r--r--drivers/s390/cio/qdio.c97
-rw-r--r--drivers/s390/net/ctcmain.c6
-rw-r--r--drivers/s390/net/netiucv.c4
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c5
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c41
33 files changed, 526 insertions, 697 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index bfeca57..e6bfce6 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -1187,7 +1187,7 @@ dasd_end_request_cb(struct dasd_ccw_req * cqr, void *data)
static void
__dasd_process_blk_queue(struct dasd_device * device)
{
- request_queue_t *queue;
+ struct request_queue *queue;
struct request *req;
struct dasd_ccw_req *cqr;
int nr_queued;
@@ -1740,7 +1740,7 @@ dasd_cancel_req(struct dasd_ccw_req *cqr)
* Dasd request queue function. Called from ll_rw_blk.c
*/
static void
-do_dasd_request(request_queue_t * queue)
+do_dasd_request(struct request_queue * queue)
{
struct dasd_device *device;
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index eccac1c..d32c60d 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -24,6 +24,7 @@
#include <asm/s390_ext.h>
#include <asm/todclk.h>
#include <asm/vtoc.h>
+#include <asm/diag.h>
#include "dasd_int.h"
#include "dasd_diag.h"
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 418b4e6..ea63ba7 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -555,7 +555,7 @@ dasd_eckd_read_conf(struct dasd_device *device)
if (conf_data == NULL) {
MESSAGE(KERN_WARNING, "%s", "No configuration "
"data retrieved");
- continue; /* no errror */
+ continue; /* no error */
}
if (conf_len != sizeof (struct dasd_eckd_confdata)) {
MESSAGE(KERN_WARNING,
@@ -564,7 +564,7 @@ dasd_eckd_read_conf(struct dasd_device *device)
conf_len,
sizeof (struct dasd_eckd_confdata));
kfree(conf_data);
- continue; /* no errror */
+ continue; /* no error */
}
/* save first valid configuration data */
if (!conf_data_saved){
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 241294c..aeda526 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -293,7 +293,7 @@ struct dasd_uid {
struct dasd_device {
/* Block device stuff. */
struct gendisk *gdp;
- request_queue_t *request_queue;
+ struct request_queue *request_queue;
spinlock_t request_queue_lock;
struct block_device *bdev;
unsigned int devindex;
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 35765f6..4d8798b 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -621,7 +621,7 @@ out:
}
static int
-dcssblk_make_request(request_queue_t *q, struct bio *bio)
+dcssblk_make_request(struct request_queue *q, struct bio *bio)
{
struct dcssblk_dev_info *dev_info;
struct bio_vec *bvec;
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index a04d912..354a060 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -191,7 +191,7 @@ static unsigned long __init xpram_highest_page_index(void)
/*
* Block device make request function.
*/
-static int xpram_make_request(request_queue_t *q, struct bio *bio)
+static int xpram_make_request(struct request_queue *q, struct bio *bio)
{
xpram_device_t *xdev = bio->bi_bdev->bd_disk->private_data;
struct bio_vec *bvec;
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig
index 3f36cb3..6430338 100644
--- a/drivers/s390/char/Kconfig
+++ b/drivers/s390/char/Kconfig
@@ -44,15 +44,9 @@ config CCW_CONSOLE
depends on TN3215_CONSOLE || TN3270_CONSOLE
default y
-config SCLP
- bool "Support for SCLP"
- depends on S390
- help
- Include support for the SCLP interface to the service element.
-
config SCLP_TTY
bool "Support for SCLP line mode terminal"
- depends on SCLP
+ depends on S390
help
Include support for IBM SCLP line-mode terminals.
@@ -65,7 +59,7 @@ config SCLP_CONSOLE
config SCLP_VT220_TTY
bool "Support for SCLP VT220-compatible terminal"
- depends on SCLP
+ depends on S390
help
Include support for an IBM SCLP VT220-compatible terminal.
@@ -78,7 +72,7 @@ config SCLP_VT220_CONSOLE
config SCLP_CPI
tristate "Control-Program Identification"
- depends on SCLP
+ depends on S390
help
This option enables the hardware console interface for system
identification. This is commonly used for workload management and
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
index 268598e..20442fb 100644
--- a/drivers/s390/char/monwriter.c
+++ b/drivers/s390/char/monwriter.c
@@ -17,6 +17,7 @@
#include <linux/miscdevice.h>
#include <linux/ctype.h>
#include <linux/poll.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <asm/ebcdic.h>
#include <asm/io.h>
@@ -41,6 +42,7 @@ struct mon_private {
size_t hdr_to_read;
size_t data_to_read;
struct mon_buf *current_buf;
+ struct mutex thread_mutex;
};
/*
@@ -179,6 +181,7 @@ static int monwrite_open(struct inode *inode, struct file *filp)
return -ENOMEM;
INIT_LIST_HEAD(&monpriv->list);
monpriv->hdr_to_read = sizeof(monpriv->hdr);
+ mutex_init(&monpriv->thread_mutex);
filp->private_data = monpriv;
return nonseekable_open(inode, filp);
}
@@ -209,6 +212,7 @@ static ssize_t monwrite_write(struct file *filp, const char __user *data,
void *to;
int rc;
+ mutex_lock(&monpriv->thread_mutex);
for (written = 0; written < count; ) {
if (monpriv->hdr_to_read) {
len = min(count - written, monpriv->hdr_to_read);
@@ -247,11 +251,13 @@ static ssize_t monwrite_write(struct file *filp, const char __user *data,
}
monpriv->hdr_to_read = sizeof(monpriv->hdr);
}
+ mutex_unlock(&monpriv->thread_mutex);
return written;
out_error:
monpriv->data_to_read = 0;
monpriv->hdr_to_read = sizeof(struct monwrite_hdr);
+ mutex_unlock(&monpriv->thread_mutex);
return rc;
}
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 743944a..2edd5fb 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -21,6 +21,7 @@
#include <asm/ccwdev.h>
#include <asm/cio.h>
#include <asm/ebcdic.h>
+#include <asm/diag.h>
#include "raw3270.h"
@@ -147,8 +148,7 @@ raw3270_request_alloc(size_t size)
* Allocate a new 3270 ccw request from bootmem. Only works very
* early in the boot process. Only con3270.c should be using this.
*/
-struct raw3270_request *
-raw3270_request_alloc_bootmem(size_t size)
+struct raw3270_request __init *raw3270_request_alloc_bootmem(size_t size)
{
struct raw3270_request *rq;
@@ -848,8 +848,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
/*
* Setup 3270 device configured as console.
*/
-struct raw3270 *
-raw3270_setup_console(struct ccw_device *cdev)
+struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
{
struct raw3270 *rp;
char *ascebc;
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index 7263347..40cd21b 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -621,11 +621,24 @@ sclp_vt220_flush_buffer(struct tty_struct *tty)
/*
* Initialize all relevant components and register driver with system.
*/
-static int
-__sclp_vt220_init(int early)
+static void __init __sclp_vt220_cleanup(void)
+{
+ struct list_head *page, *p;
+
+ list_for_each_safe(page, p, &sclp_vt220_empty) {
+ list_del(page);
+ if (slab_is_available())
+ free_page((unsigned long) page);
+ else
+ free_bootmem((unsigned long) page, PAGE_SIZE);
+ }
+}
+
+static int __init __sclp_vt220_init(void)
{
void *page;
int i;
+ int num_pages;
if (sclp_vt220_initialized)
return 0;
@@ -642,13 +655,16 @@ __sclp_vt220_init(int early)
sclp_vt220_flush_later = 0;
/* Allocate pages for output buffering */
- for (i = 0; i < (early ? MAX_CONSOLE_PAGES : MAX_KMEM_PAGES); i++) {
- if (early)
- page = alloc_bootmem_low_pages(PAGE_SIZE);
- else
+ num_pages = slab_is_available() ? MAX_KMEM_PAGES : MAX_CONSOLE_PAGES;
+ for (i = 0; i < num_pages; i++) {
+ if (slab_is_available())
page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (!page)
+ else
+ page = alloc_bootmem_low_pages(PAGE_SIZE);
+ if (!page) {
+ __sclp_vt220_cleanup();
return -ENOMEM;
+ }
list_add_tail((struct list_head *) page, &sclp_vt220_empty);
}
return 0;
@@ -662,14 +678,13 @@ static const struct tty_operations sclp_vt220_ops = {
.flush_chars = sclp_vt220_flush_chars,
.write_room = sclp_vt220_write_room,
.chars_in_buffer = sclp_vt220_chars_in_buffer,
- .flush_buffer = sclp_vt220_flush_buffer
+ .flush_buffer = sclp_vt220_flush_buffer,
};
/*
* Register driver with SCLP and Linux and initialize internal tty structures.
*/
-static int __init
-sclp_vt220_tty_init(void)
+static int __init sclp_vt220_tty_init(void)
{
struct tty_driver *driver;
int rc;
@@ -679,18 +694,15 @@ sclp_vt220_tty_init(void)
driver = alloc_tty_driver(1);
if (!driver)
return -ENOMEM;
- rc = __sclp_vt220_init(0);
- if (rc) {
- put_tty_driver(driver);
- return rc;
- }
+ rc = __sclp_vt220_init();
+ if (rc)
+ goto out_driver;
rc = sclp_register(&sclp_vt220_register);
if (rc) {
printk(KERN_ERR SCLP_VT220_PRINT_HEADER
"could not register tty - "
"sclp_register returned %d\n", rc);
- put_tty_driver(driver);
- return rc;
+ goto out_init;
}
driver->owner = THIS_MODULE;
@@ -709,14 +721,20 @@ sclp_vt220_tty_init(void)
printk(KERN_ERR SCLP_VT220_PRINT_HEADER
"could not register tty - "
"tty_register_driver returned %d\n", rc);
- put_tty_driver(driver);
- return rc;
+ goto out_sclp;
}
sclp_vt220_driver = driver;
return 0;
-}
-module_init(sclp_vt220_tty_init);
+out_sclp:
+ sclp_unregister(&sclp_vt220_register);
+out_init:
+ __sclp_vt220_cleanup();
+out_driver:
+ put_tty_driver(driver);
+ return rc;
+}
+__initcall(sclp_vt220_tty_init);
#ifdef CONFIG_SCLP_VT220_CONSOLE
@@ -762,7 +780,7 @@ sclp_vt220_con_init(void)
if (!CONSOLE_IS_SCLP)
return 0;
- rc = __sclp_vt220_init(1);
+ rc = __sclp_vt220_init();
if (rc)
return rc;
/* Attach linux console */
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index 3b52f5c..dddf8d6 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -188,7 +188,7 @@ struct tape_blk_data
{
struct tape_device * device;
/* Block device request queue. */
- request_queue_t * request_queue;
+ struct request_queue * request_queue;
spinlock_t request_queue_lock;
/* Task to move entries from block request to CCS request queue. */
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index dd0ecae..eeb92e2 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -147,7 +147,7 @@ static void
tapeblock_requeue(struct work_struct *work) {
struct tape_blk_data * blkdat;
struct tape_device * device;
- request_queue_t * queue;
+ struct request_queue * queue;
int nr_queued;
struct request * req;
struct list_head * l;
@@ -194,7 +194,7 @@ tapeblock_requeue(struct work_struct *work) {
* Tape request queue function. Called from ll_rw_blk.c
*/
static void
-tapeblock_request_fn(request_queue_t *queue)
+tapeblock_request_fn(struct request_queue *queue)
{
struct tape_device *device;
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c
index e90b0f8..d70a6e6 100644
--- a/drivers/s390/char/vmur.c
+++ b/drivers/s390/char/vmur.c
@@ -14,6 +14,7 @@
#include <asm/cio.h>
#include <asm/ccwdev.h>
#include <asm/debug.h>
+#include <asm/diag.h>
#include "vmur.h"
@@ -68,8 +69,26 @@ static struct ccw_driver ur_driver = {
.set_offline = ur_set_offline,
};
+static DEFINE_MUTEX(vmur_mutex);
+
/*
* Allocation, freeing, getting and putting of urdev structures
+ *
+ * Each ur device (urd) contains a reference to its corresponding ccw device
+ * (cdev) using the urd->cdev pointer. Each ccw device has a reference to the
+ * ur device using the cdev->dev.driver_data pointer.
+ *
+ * urd references:
+ * - ur_probe gets a urd reference, ur_remove drops the reference
+ * (cdev->dev.driver_data)
+ * - ur_open gets a urd reference, ur_relase drops the reference
+ * (urf->urd)
+ *
+ * cdev references:
+ * - urdev_alloc get a cdev reference (urd->cdev)
+ * - urdev_free drops the cdev reference (urd->cdev)
+ *
+ * Setting and clearing of cdev->dev.driver_data is protected by the ccwdev lock
*/
static struct urdev *urdev_alloc(struct ccw_device *cdev)
{
@@ -78,51 +97,72 @@ static struct urdev *urdev_alloc(struct ccw_device *cdev)
urd = kzalloc(sizeof(struct urdev), GFP_KERNEL);
if (!urd)
return NULL;
- urd->cdev = cdev;
urd->reclen = cdev->id.driver_info;
ccw_device_get_id(cdev, &urd->dev_id);
mutex_init(&urd->io_mutex);
mutex_init(&urd->open_mutex);
+ atomic_set(&urd->ref_count, 1);
+ urd->cdev = cdev;
+ get_device(&cdev->dev);
return urd;
}
static void urdev_free(struct urdev *urd)
{
+ TRACE("urdev_free: %p\n", urd);
+ if (urd->cdev)
+ put_device(&urd->cdev->dev);
kfree(urd);
}
-/*
- * This is how the character device driver gets a reference to a
- * ur device. When this call returns successfully, a reference has
- * been taken (by get_device) on the underlying kobject. The recipient
- * of this urdev pointer must eventually drop it with urdev_put(urd)
- * which does the corresponding put_device().
- */
+static void urdev_get(struct urdev *urd)
+{
+ atomic_inc(&urd->ref_count);
+}
+
+static struct urdev *urdev_get_from_cdev(struct ccw_device *cdev)
+{
+ struct urdev *urd;
+ unsigned long flags;
+
+ spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+ urd = cdev->dev.driver_data;
+ if (urd)
+ urdev_get(urd);
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+ return urd;
+}
+
static struct urdev *urdev_get_from_devno(u16 devno)
{
char bus_id[16];
struct ccw_device *cdev;
+ struct urdev *urd;
sprintf(bus_id, "0.0.%04x", devno);
cdev = get_ccwdev_by_busid(&ur_driver, bus_id);
if (!cdev)
return NULL;
-
- return cdev->dev.driver_data;
+ urd = urdev_get_from_cdev(cdev);
+ put_device(&cdev->dev);
+ return urd;
}
static void urdev_put(struct urdev *urd)
{
- put_device(&urd->cdev->dev);
+ if (atomic_dec_and_test(&urd->ref_count))
+ urdev_free(urd);
}
/*
* Low-level functions to do I/O to a ur device.
* alloc_chan_prog
+ * free_chan_prog
* do_ur_io
* ur_int_handler
*
* alloc_chan_prog allocates and builds the channel program
+ * free_chan_prog frees memory of the channel program
*
* do_ur_io issues the channel program to the device and blocks waiting
* on a completion event it publishes at urd->io_done. The function
@@ -137,6 +177,16 @@ static void urdev_put(struct urdev *urd)
* address pointer that alloc_chan_prog returned.
*/
+static void free_chan_prog(struct ccw1 *cpa)
+{
+ struct ccw1 *ptr = cpa;
+
+ while (ptr->cda) {
+ kfree((void *)(addr_t) ptr->cda);
+ ptr++;
+ }
+ kfree(cpa);
+}
/*
* alloc_chan_prog
@@ -144,44 +194,45 @@ static void urdev_put(struct urdev *urd)
* with a final NOP CCW command-chained on (which ensures that CE and DE
* are presented together in a single interrupt instead of as separate
* interrupts unless an incorrect length indication kicks in first). The
- * data length in each CCW is reclen. The caller must ensure that count
- * is an integral multiple of reclen.
- * The channel program pointer returned by this function must be freed
- * with kfree. The caller is responsible for checking that
- * count/reclen is not ridiculously large.
+ * data length in each CCW is reclen.
*/
-static struct ccw1 *alloc_chan_prog(char *buf, size_t count, size_t reclen)
+static struct ccw1 *alloc_chan_prog(const char __user *ubuf, int rec_count,
+ int reclen)
{
- size_t num_ccws;
struct ccw1 *cpa;
+ void *kbuf;
int i;
- TRACE("alloc_chan_prog(%p, %zu, %zu)\n", buf, count, reclen);
+ TRACE("alloc_chan_prog(%p, %i, %i)\n", ubuf, rec_count, reclen);
/*
* We chain a NOP onto the writes to force CE+DE together.
* That means we allocate room for CCWs to cover count/reclen
* records plus a NOP.
*/
- num_ccws = count / reclen + 1;
- cpa = kmalloc(num_ccws * sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
+ cpa = kzalloc((rec_count + 1) * sizeof(struct ccw1),
+ GFP_KERNEL | GFP_DMA);
if (!cpa)
- return NULL;
+ return ERR_PTR(-ENOMEM);
- for (i = 0; count; i++) {
+ for (i = 0; i < rec_count; i++) {
cpa[i].cmd_code = WRITE_CCW_CMD;
cpa[i].flags = CCW_FLAG_CC | CCW_FLAG_SLI;
cpa[i].count = reclen;
- cpa[i].cda = __pa(buf);
- buf += reclen;
- count -= reclen;
+ kbuf = kmalloc(reclen, GFP_KERNEL | GFP_DMA);
+ if (!kbuf) {
+ free_chan_prog(cpa);
+ return ERR_PTR(-ENOMEM);
+ }
+ cpa[i].cda = (u32)(addr_t) kbuf;
+ if (copy_from_user(kbuf, ubuf, reclen)) {
+ free_chan_prog(cpa);
+ return ERR_PTR(-EFAULT);
+ }
+ ubuf += reclen;
}
/* The following NOP CCW forces CE+DE to be presented together */
cpa[i].cmd_code = CCW_CMD_NOOP;
- cpa[i].flags = 0;
- cpa[i].count = 0;
- cpa[i].cda = 0;
-
return cpa;
}
@@ -189,7 +240,7 @@ static int do_ur_io(struct urdev *urd, struct ccw1 *cpa)
{
int rc;
struct ccw_device *cdev = urd->cdev;
- DECLARE_COMPLETION(event);
+ DECLARE_COMPLETION_ONSTACK(event);
TRACE("do_ur_io: cpa=%p\n", cpa);
@@ -232,6 +283,7 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm,
return;
}
urd = cdev->dev.driver_data;
+ BUG_ON(!urd);
/* On special conditions irb is an error pointer */
if (IS_ERR(irb))
urd->io_request_rc = PTR_ERR(irb);
@@ -249,9 +301,15 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm,
static ssize_t ur_attr_reclen_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct urdev *urd = dev->driver_data;
+ struct urdev *urd;
+ int rc;
- return sprintf(buf, "%zu\n", urd->reclen);
+ urd = urdev_get_from_cdev(to_ccwdev(dev));
+ if (!urd)
+ return -ENODEV;
+ rc = sprintf(buf, "%zu\n", urd->reclen);
+ urdev_put(urd);
+ return rc;
}
static DEVICE_ATTR(reclen, 0444, ur_attr_reclen_show, NULL);
@@ -325,24 +383,11 @@ static ssize_t do_write(struct urdev *urd, const char __user *udata,
size_t count, size_t reclen, loff_t *ppos)
{
struct ccw1 *cpa;
- char *buf;
int rc;
- /* Data buffer must be under 2GB line for fmt1 CCWs: hence GFP_DMA */
- buf = kmalloc(count, GFP_KERNEL | GFP_DMA);
- if (!buf)
- return -ENOMEM;
-
- if (copy_from_user(buf, udata, count)) {
- rc = -EFAULT;
- goto fail_kfree_buf;
- }
-
- cpa = alloc_chan_prog(buf, count, reclen);
- if (!cpa) {
- rc = -ENOMEM;
- goto fail_kfree_buf;
- }
+ cpa = alloc_chan_prog(udata, count / reclen, reclen);
+ if (IS_ERR(cpa))
+ return PTR_ERR(cpa);
rc = do_ur_io(urd, cpa);
if (rc)
@@ -354,10 +399,9 @@ static ssize_t do_write(struct urdev *urd, const char __user *udata,
}
*ppos += count;
rc = count;
+
fail_kfree_cpa:
- kfree(cpa);
-fail_kfree_buf:
- kfree(buf);
+ free_chan_prog(cpa);
return rc;
}
@@ -380,31 +424,6 @@ static ssize_t ur_write(struct file *file, const char __user *udata,
return do_write(urf->urd, udata, count, urf->dev_reclen, ppos);
}
-static int do_diag_14(unsigned long rx, unsigned long ry1,
- unsigned long subcode)
-{
- register unsigned long _ry1 asm("2") = ry1;
- register unsigned long _ry2 asm("3") = subcode;
- int rc = 0;
-
- asm volatile(
-#ifdef CONFIG_64BIT
- " sam31\n"
- " diag %2,2,0x14\n"
- " sam64\n"
-#else
- " diag %2,2,0x14\n"
-#endif
- " ipm %0\n"
- " srl %0,28\n"
- : "=d" (rc), "+d" (_ry2)
- : "d" (rx), "d" (_ry1)
- : "cc");
-
- TRACE("diag 14: subcode=0x%lx, cc=%i\n", subcode, rc);
- return rc;
-}
-
/*
* diagnose code 0x14 subcode 0x0028 - position spool file to designated
* record
@@ -416,7 +435,7 @@ static int diag_position_to_record(int devno, int record)
{
int cc;
- cc = do_diag_14(record, devno, 0x28);
+ cc = diag14(record, devno, 0x28);
switch (cc) {
case 0:
return 0;
@@ -441,7 +460,7 @@ static int diag_read_file(int devno, char *buf)
{
int cc;
- cc = do_diag_14((unsigned long) buf, devno, 0x00);
+ cc = diag14((unsigned long) buf, devno, 0x00);
switch (cc) {
case 0:
return 0;
@@ -473,7 +492,7 @@ static ssize_t diag14_read(struct file *file, char __user *ubuf, size_t count,
return rc;
len = min((size_t) PAGE_SIZE, count);
- buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ buf = (char *) __get_free_page(GFP_KERNEL | GFP_DMA);
if (!buf)
return -ENOMEM;
@@ -486,7 +505,7 @@ static ssize_t diag14_read(struct file *file, char __user *ubuf, size_t count,
}
if (rc)
goto fail;
- if (reclen)
+ if (reclen && (copied == 0) && (*offs < PAGE_SIZE))
*((u16 *) &buf[FILE_RECLEN_OFFSET]) = reclen;
len = min(count - copied, PAGE_SIZE - res);
if (copy_to_user(ubuf + copied, buf + res, len)) {
@@ -500,7 +519,7 @@ static ssize_t diag14_read(struct file *file, char __user *ubuf, size_t count,
*offs += copied;
rc = copied;
fail:
- kfree(buf);
+ free_page((unsigned long) buf);
return rc;
}
@@ -534,7 +553,7 @@ static int diag_read_next_file_info(struct file_control_block *buf, int spid)
{
int cc;
- cc = do_diag_14((unsigned long) buf, spid, 0xfff);
+ cc = diag14((unsigned long) buf, spid, 0xfff);
switch (cc) {
case 0:
return 0;
@@ -543,56 +562,97 @@ static int diag_read_next_file_info(struct file_control_block *buf, int spid)
}
}
-static int verify_device(struct urdev *urd)
+static int verify_uri_device(struct urdev *urd)
{
- struct file_control_block fcb;
+ struct file_control_block *fcb;
char *buf;
int rc;
+ fcb = kmalloc(sizeof(*fcb), GFP_KERNEL | GFP_DMA);
+ if (!fcb)
+ return -ENOMEM;
+
+ /* check for empty reader device (beginning of chain) */
+ rc = diag_read_next_file_info(fcb, 0);
+ if (rc)
+ goto fail_free_fcb;
+
+ /* if file is in hold status, we do not read it */
+ if (fcb->file_stat & (FLG_SYSTEM_HOLD | FLG_USER_HOLD)) {
+ rc = -EPERM;
+ goto fail_free_fcb;
+ }
+
+ /* open file on virtual reader */
+ buf = (char *) __get_free_page(GFP_KERNEL | GFP_DMA);
+ if (!buf) {
+ rc = -ENOMEM;
+ goto fail_free_fcb;
+ }
+ rc = diag_read_file(urd->dev_id.devno, buf);
+ if ((rc != 0) && (rc != -ENODATA)) /* EOF does not hurt */
+ goto fail_free_buf;
+
+ /* check if the file on top of the queue is open now */
+ rc = diag_read_next_file_info(fcb, 0);
+ if (rc)
+ goto fail_free_buf;
+ if (!(fcb->file_stat & FLG_IN_USE)) {
+ rc = -EMFILE;
+ goto fail_free_buf;
+ }
+ rc = 0;
+
+fail_free_buf:
+ free_page((unsigned long) buf);
+fail_free_fcb:
+ kfree(fcb);
+ return rc;
+}
+
+static int verify_device(struct urdev *urd)
+{
switch (urd->class) {
case DEV_CLASS_UR_O:
return 0; /* no check needed here */
case DEV_CLASS_UR_I:
- /* check for empty reader device (beginning of chain) */
- rc = diag_read_next_file_info(&fcb, 0);
- if (rc)
- return rc;
-
- /* open file on virtual reader */
- buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- rc = diag_read_file(urd->dev_id.devno, buf);
- kfree(buf);
-
- if ((rc != 0) && (rc != -ENODATA)) /* EOF does not hurt */
- return rc;
- return 0;
+ return verify_uri_device(urd);
default:
return -ENOTSUPP;
}
}
-static int get_file_reclen(struct urdev *urd)
+static int get_uri_file_reclen(struct urdev *urd)
{
- struct file_control_block fcb;
+ struct file_control_block *fcb;
int rc;
+ fcb = kmalloc(sizeof(*fcb), GFP_KERNEL | GFP_DMA);
+ if (!fcb)
+ return -ENOMEM;
+ rc = diag_read_next_file_info(fcb, 0);
+ if (rc)
+ goto fail_free;
+ if (fcb->file_stat & FLG_CP_DUMP)
+ rc = 0;
+ else
+ rc = fcb->rec_len;
+
+fail_free:
+ kfree(fcb);
+ return rc;
+}
+
+static int get_file_reclen(struct urdev *urd)
+{
switch (urd->class) {
case DEV_CLASS_UR_O:
return 0;
case DEV_CLASS_UR_I:
- rc = diag_read_next_file_info(&fcb, 0);
- if (rc)
- return rc;
- break;
+ return get_uri_file_reclen(urd);
default:
return -ENOTSUPP;
}
- if (fcb.file_stat & FLG_CP_DUMP)
- return 0;
-
- return fcb.rec_len;
}
static int ur_open(struct inode *inode, struct file *file)
@@ -710,64 +770,63 @@ static struct file_operations ur_fops = {
/*
* ccw_device infrastructure:
- * ur_probe gets its own ref to the device (i.e. get_device),
- * creates the struct urdev, the device attributes, sets up
- * the interrupt handler and validates the virtual unit record device.
- * ur_remove removes the device attributes, frees the struct urdev
- * and drops (put_device) the ref to the device we got in ur_probe.
+ * ur_probe creates the struct urdev (with refcount = 1), the device
+ * attributes, sets up the interrupt handler and validates the virtual
+ * unit record device.
+ * ur_remove removes the device attributes and drops the reference to
+ * struct urdev.
+ *
+ * ur_probe, ur_remove, ur_set_online and ur_set_offline are serialized
+ * by the vmur_mutex lock.
+ *
+ * urd->char_device is used as indication that the online function has
+ * been completed successfully.
*/
static int ur_probe(struct ccw_device *cdev)
{
struct urdev *urd;
int rc;
- TRACE("ur_probe: cdev=%p state=%d\n", cdev, *(int *) cdev->private);
-
- if (!get_device(&cdev->dev))
- return -ENODEV;
+ TRACE("ur_probe: cdev=%p\n", cdev);
+ mutex_lock(&vmur_mutex);
urd = urdev_alloc(cdev);
if (!urd) {
rc = -ENOMEM;
- goto fail;
+ goto fail_unlock;
}
+
rc = ur_create_attributes(&cdev->dev);
if (rc) {
rc = -ENOMEM;
- goto fail;
+ goto fail_urdev_put;
}
- cdev->dev.driver_data = urd;
cdev->handler = ur_int_handler;
/* validate virtual unit record device */
urd->class = get_urd_class(urd);
if (urd->class < 0) {
rc = urd->class;
- goto fail;
+ goto fail_remove_attr;
}
if ((urd->class != DEV_CLASS_UR_I) && (urd->class != DEV_CLASS_UR_O)) {
rc = -ENOTSUPP;
- goto fail;
+ goto fail_remove_attr;
}
+ spin_lock_irq(get_ccwdev_lock(cdev));
+ cdev->dev.driver_data = urd;
+ spin_unlock_irq(get_ccwdev_lock(cdev));
+ mutex_unlock(&vmur_mutex);
return 0;
-fail:
- urdev_free(urd);
- put_device(&cdev->dev);
- return rc;
-}
-
-static void ur_remove(struct ccw_device *cdev)
-{
- struct urdev *urd = cdev->dev.driver_data;
-
- TRACE("ur_remove\n");
- if (cdev->online)
- ur_set_offline(cdev);
+fail_remove_attr:
ur_remove_attributes(&cdev->dev);
- urdev_free(urd);
- put_device(&cdev->dev);
+fail_urdev_put:
+ urdev_put(urd);
+fail_unlock:
+ mutex_unlock(&vmur_mutex);
+ return rc;
}
static int ur_set_online(struct ccw_device *cdev)
@@ -776,20 +835,29 @@ static int ur_set_online(struct ccw_device *cdev)
int minor, major, rc;
char node_id[16];
- TRACE("ur_set_online: cdev=%p state=%d\n", cdev,
- *(int *) cdev->private);
+ TRACE("ur_set_online: cdev=%p\n", cdev);
- if (!try_module_get(ur_driver.owner))
- return -EINVAL;
+ mutex_lock(&vmur_mutex);
+ urd = urdev_get_from_cdev(cdev);
+ if (!urd) {
+ /* ur_remove already deleted our urd */
+ rc = -ENODEV;
+ goto fail_unlock;
+ }
+
+ if (urd->char_device) {
+ /* Another ur_set_online was faster */
+ rc = -EBUSY;
+ goto fail_urdev_put;
+ }
- urd = (struct urdev *) cdev->dev.driver_data;
minor = urd->dev_id.devno;
major = MAJOR(ur_first_dev_maj_min);
urd->char_device = cdev_alloc();
if (!urd->char_device) {
rc = -ENOMEM;
- goto fail_module_put;
+ goto fail_urdev_put;
}
cdev_init(urd->char_device, &ur_fops);
@@ -818,29 +886,79 @@ static int ur_set_online(struct ccw_device *cdev)
TRACE("ur_set_online: device_create rc=%d\n", rc);
goto fail_free_cdev;
}
-
+ urdev_put(urd);
+ mutex_unlock(&vmur_mutex);
return 0;
fail_free_cdev:
cdev_del(urd->char_device);
-fail_module_put:
- module_put(ur_driver.owner);
-
+ urd->char_device = NULL;
+fail_urdev_put:
+ urdev_put(urd);
+fail_unlock:
+ mutex_unlock(&vmur_mutex);
return rc;
}
-static int ur_set_offline(struct ccw_device *cdev)
+static int ur_set_offline_force(struct ccw_device *cdev, int force)
{
struct urdev *urd;
+ int rc;
- TRACE("ur_set_offline: cdev=%p cdev->private=%p state=%d\n",
- cdev, cdev->private, *(int *) cdev->private);
- urd = (struct urdev *) cdev->dev.driver_data;
+ TRACE("ur_set_offline: cdev=%p\n", cdev);
+ urd = urdev_get_from_cdev(cdev);
+ if (!urd)
+ /* ur_remove already deleted our urd */
+ return -ENODEV;
+ if (!urd->char_device) {
+ /* Another ur_set_offline was faster */
+ rc = -EBUSY;
+ goto fail_urdev_put;
+ }
+ if (!force && (atomic_read(&urd->ref_count) > 2)) {
+ /* There is still a user of urd (e.g. ur_open) */
+ TRACE("ur_set_offline: BUSY\n");
+ rc = -EBUSY;
+ goto fail_urdev_put;
+ }
device_destroy(vmur_class, urd->char_device->dev);
cdev_del(urd->char_device);
- module_put(ur_driver.owner);
+ urd->char_device = NULL;
+ rc = 0;
- return 0;
+fail_urdev_put:
+ urdev_put(urd);
+ return rc;
+}
+
+static int ur_set_offline(struct ccw_device *cdev)
+{
+ int rc;
+
+ mutex_lock(&vmur_mutex);
+ rc = ur_set_offline_force(cdev, 0);
+ mutex_unlock(&vmur_mutex);
+ return rc;
+}
+
+static void ur_remove(struct ccw_device *cdev)
+{
+ unsigned long flags;
+
+ TRACE("ur_remove\n");
+
+ mutex_lock(&vmur_mutex);
+
+ if (cdev->online)
+ ur_set_offline_force(cdev, 1);
+ ur_remove_attributes(&cdev->dev);
+
+ spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+ urdev_put(cdev->dev.driver_data);
+ cdev->dev.driver_data = NULL;
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+
+ mutex_unlock(&vmur_mutex);
}
/*
diff --git a/drivers/s390/char/vmur.h b/drivers/s390/char/vmur.h
index 16d0a4e..fa95964 100644
--- a/drivers/s390/char/vmur.h
+++ b/drivers/s390/char/vmur.h
@@ -50,7 +50,10 @@ struct file_control_block {
char rest[200];
} __attribute__ ((packed));
-#define FLG_CP_DUMP 0x10
+#define FLG_SYSTEM_HOLD 0x04
+#define FLG_CP_DUMP 0x10
+#define FLG_USER_HOLD 0x20
+#define FLG_IN_USE 0x80
/*
* A struct urdev is created for each ur device that is made available
@@ -67,6 +70,7 @@ struct urdev {
size_t reclen; /* Record length for *write* CCWs */
int class; /* VM device class */
int io_request_rc; /* return code from I/O request */
+ atomic_t ref_count; /* reference counter */
};
/*
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index ec04048..bd5f16f 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -51,7 +51,7 @@ blacklist_range (range_action action, unsigned int from, unsigned int to,
to = from;
if (from > to || to > __MAX_SUBCHANNEL || ssid > __MAX_SSID) {
- printk (KERN_WARNING "Invalid blacklist range "
+ printk (KERN_WARNING "cio: Invalid blacklist range "
"0.%x.%04x to 0.%x.%04x, skipping\n",
ssid, from, ssid, to);
return;
@@ -119,7 +119,7 @@ blacklist_busid(char **str, int *id0, int *ssid, int *devno)
return 0;
confused:
strsep(str, ",\n");
- printk(KERN_WARNING "Invalid cio_ignore parameter '%s'\n", sav);
+ printk(KERN_WARNING "cio: Invalid cio_ignore parameter '%s'\n", sav);
return 1;
}
@@ -166,22 +166,19 @@ blacklist_parse_parameters (char *str, range_action action)
continue;
}
if (*str == '-') {
- printk(KERN_WARNING "invalid cio_ignore "
+ printk(KERN_WARNING "cio: invalid cio_ignore "
"parameter '%s'\n",
strsep(&str, ",\n"));
continue;
}
if ((from_id0 != to_id0) ||
(from_ssid != to_ssid)) {
- printk(KERN_WARNING "invalid cio_ignore range "
- "%x.%x.%04x-%x.%x.%04x\n",
- from_id0, from_ssid, from,
- to_id0, to_ssid, to);
+ printk(KERN_WARNING "cio: invalid cio_ignore "
+ "range %x.%x.%04x-%x.%x.%04x\n",
+ from_id0, from_ssid, from,
+ to_id0, to_ssid, to);
continue;
}
- pr_debug("blacklist_setup: adding range "
- "from %x.%x.%04x to %x.%x.%04x\n",
- from_id0, from_ssid, from, to_id0, to_ssid, to);
blacklist_range (ra, from, to, to_ssid);
}
}
@@ -239,7 +236,7 @@ blacklist_parse_proc_parameters (char *buf)
*/
blacklist_parse_parameters (buf + 4, add);
} else {
- printk (KERN_WARNING "cio_ignore: Parse error; \n"
+ printk (KERN_WARNING "cio: cio_ignore: Parse error; \n"
KERN_WARNING "try using 'free all|<devno-range>,"
"<devno-range>,...'\n"
KERN_WARNING "or 'add <devno-range>,"
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index e5ccda6..b0a18f5 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -359,7 +359,6 @@ ccwgroup_probe (struct device *dev)
if ((ret = device_create_file(dev, &dev_attr_online)))
return ret;
- pr_debug("%s: device %s\n", __func__, gdev->dev.bus_id);
ret = gdrv->probe ? gdrv->probe(gdev) : -ENODEV;
if (ret)
device_remove_file(dev, &dev_attr_online);
@@ -376,8 +375,6 @@ ccwgroup_remove (struct device *dev)
gdev = to_ccwgroupdev(dev);
gdrv = to_ccwgroupdrv(dev->driver);
- pr_debug("%s: device %s\n", __func__, gdev->dev.bus_id);
-
device_remove_file(dev, &dev_attr_online);
if (gdrv && gdrv->remove)
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index b57d93d..920dd71 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -121,14 +121,8 @@ static int s390_vary_chpid(struct chp_id chpid, int on)
CIO_TRACE_EVENT( 2, dbf_text);
status = chp_get_status(chpid);
- if (status < 0) {
- printk(KERN_ERR "Can't vary unknown chpid %x.%02x\n",
- chpid.cssid, chpid.id);
- return -EINVAL;
- }
-
if (!on && !status) {
- printk(KERN_ERR "chpid %x.%02x is already offline\n",
+ printk(KERN_ERR "cio: chpid %x.%02x is already offline\n",
chpid.cssid, chpid.id);
return -EINVAL;
}
@@ -421,21 +415,14 @@ int chp_new(struct chp_id chpid)
if (ret)
goto out_free;
} else {
- static int msg_done;
-
- if (!msg_done) {
- printk(KERN_WARNING "cio: Channel measurements not "
- "available, continuing.\n");
- msg_done = 1;
- }
chp->cmg = -1;
}
/* make it known to the system */
ret = device_register(&chp->dev);
if (ret) {
- printk(KERN_WARNING "%s: could not register %x.%02x\n",
- __func__, chpid.cssid, chpid.id);
+ CIO_MSG_EVENT(0, "Could not register chp%x.%02x: %d\n",
+ chpid.cssid, chpid.id, ret);
goto out_free;
}
ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group);
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index ea92ac4..597c0c7 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -990,16 +990,20 @@ out:
return ret;
}
-static int __init
-chsc_alloc_sei_area(void)
+int __init chsc_alloc_sei_area(void)
{
sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!sei_page)
- printk(KERN_WARNING"Can't allocate page for processing of " \
- "chsc machine checks!\n");
+ CIO_MSG_EVENT(0, "Can't allocate page for processing of "
+ "chsc machine checks!\n");
return (sei_page ? 0 : -ENOMEM);
}
+void __init chsc_free_sei_area(void)
+{
+ kfree(sei_page);
+}
+
int __init
chsc_enable_facility(int operation_code)
{
@@ -1051,8 +1055,6 @@ chsc_enable_facility(int operation_code)
return ret;
}
-subsys_initcall(chsc_alloc_sei_area);
-
struct css_general_char css_general_characteristics;
struct css_chsc_char css_chsc_characteristics;
@@ -1073,8 +1075,8 @@ chsc_determine_css_characteristics(void)
scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!scsc_area) {
- printk(KERN_WARNING"cio: Was not able to determine available" \
- "CHSCs due to no memory.\n");
+ CIO_MSG_EVENT(0, "Was not able to determine available"
+ "CHSCs due to no memory.\n");
return -ENOMEM;
}
@@ -1083,15 +1085,15 @@ chsc_determine_css_characteristics(void)
result = chsc(scsc_area);
if (result) {
- printk(KERN_WARNING"cio: Was not able to determine " \
- "available CHSCs, cc=%i.\n", result);
+ CIO_MSG_EVENT(0, "Was not able to determine available CHSCs, "
+ "cc=%i.\n", result);
result = -EIO;
goto exit;
}
if (scsc_area->response.code != 1) {
- printk(KERN_WARNING"cio: Was not able to determine " \
- "available CHSCs.\n");
+ CIO_MSG_EVENT(0, "Was not able to determine "
+ "available CHSCs.\n");
result = -EIO;
goto exit;
}
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index 2ad81d1..d1f5db1 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -79,6 +79,8 @@ extern int chsc_get_ssd_info(struct subchannel_id schid,
struct chsc_ssd_info *ssd);
extern int chsc_determine_css_characteristics(void);
extern int css_characteristics_avail;
+extern int chsc_alloc_sei_area(void);
+extern void chsc_free_sei_area(void);
extern int chsc_enable_facility(int);
struct channel_subsystem;
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index ea1defb..f2708d6 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -47,8 +47,8 @@ cio_setup (char *parm)
else if (!strcmp (parm, "no"))
cio_show_msg = 0;
else
- printk (KERN_ERR "cio_setup : invalid cio_msg parameter '%s'",
- parm);
+ printk(KERN_ERR "cio: cio_setup: "
+ "invalid cio_msg parameter '%s'", parm);
return 1;
}
@@ -80,7 +80,6 @@ cio_debug_init (void)
goto out_unregister;
debug_register_view (cio_debug_crw_id, &debug_sprintf_view);
debug_set_level (cio_debug_crw_id, 2);
- pr_debug("debugging initialized\n");
return 0;
out_unregister:
@@ -90,7 +89,7 @@ out_unregister:
debug_unregister (cio_debug_trace_id);
if (cio_debug_crw_id)
debug_unregister (cio_debug_crw_id);
- pr_debug("could not initialize debugging\n");
+ printk(KERN_WARNING"cio: could not initialize debugging\n");
return -1;
}
@@ -568,7 +567,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
*/
if (sch->st != 0) {
CIO_DEBUG(KERN_INFO, 0,
- "Subchannel 0.%x.%04x reports "
+ "cio: Subchannel 0.%x.%04x reports "
"non-I/O subchannel type %04X\n",
sch->schid.ssid, sch->schid.sch_no, sch->st);
/* We stop here for non-io subchannels. */
@@ -601,7 +600,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
sch->lpm = sch->schib.pmcw.pam & sch->opm;
CIO_DEBUG(KERN_INFO, 0,
- "Detected device %04x on subchannel 0.%x.%04X"
+ "cio: Detected device %04x on subchannel 0.%x.%04X"
" - PIM = %02X, PAM = %02X, POM = %02X\n",
sch->schib.pmcw.dev, sch->schid.ssid,
sch->schid.sch_no, sch->schib.pmcw.pim,
@@ -766,7 +765,7 @@ cio_get_console_sch_no(void)
/* unlike in 2.4, we cannot autoprobe here, since
* the channel subsystem is not fully initialized.
* With some luck, the HWC console can take over */
- printk(KERN_WARNING "No ccw console found!\n");
+ printk(KERN_WARNING "cio: No ccw console found!\n");
return -1;
}
return console_irq;
diff --git a/drivers/s390/cio/cio_debug.h b/drivers/s390/cio/cio_debug.h
index f88844a..c9bf898 100644
--- a/drivers/s390/cio/cio_debug.h
+++ b/drivers/s390/cio/cio_debug.h
@@ -23,6 +23,8 @@ extern debug_info_t *cio_debug_crw_id;
static inline void
CIO_HEX_EVENT(int level, void *data, int length)
{
+ if (unlikely(!cio_debug_trace_id))
+ return;
while (length > 0) {
debug_event(cio_debug_trace_id, level, data, length);
length -= cio_debug_trace_id->buf_size;
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 28abd69..34a7969 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -594,6 +594,9 @@ alloc_cmb (struct ccw_device *cdev)
free_pages((unsigned long)mem, get_order(size));
} else if (!mem) {
/* no luck */
+ printk(KERN_WARNING "cio: failed to allocate area "
+ "for measuring %d subchannels\n",
+ cmb_area.num_channels);
ret = -ENOMEM;
goto out;
} else {
@@ -1185,12 +1188,12 @@ static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *att
case '0':
ret = disable_cmf(cdev);
if (ret)
- printk(KERN_INFO "disable_cmf failed (%d)\n", ret);
+ dev_info(&cdev->dev, "disable_cmf failed (%d)\n", ret);
break;
case '1':
ret = enable_cmf(cdev);
if (ret && ret != -EBUSY)
- printk(KERN_INFO "enable_cmf failed (%d)\n", ret);
+ dev_info(&cdev->dev, "enable_cmf failed (%d)\n", ret);
break;
}
@@ -1279,26 +1282,19 @@ init_cmf(void)
case CMF_BASIC:
format_string = "basic";
cmbops = &cmbops_basic;
- if (cmb_area.num_channels > 4096 || cmb_area.num_channels < 1) {
- printk(KERN_ERR "Basic channel measurement facility"
- " can only use 1 to 4096 devices\n"
- KERN_ERR "when the cmf driver is built"
- " as a loadable module\n");
- return 1;
- }
break;
case CMF_EXTENDED:
format_string = "extended";
cmbops = &cmbops_extended;
break;
default:
- printk(KERN_ERR "Invalid format %d for channel "
+ printk(KERN_ERR "cio: Invalid format %d for channel "
"measurement facility\n", format);
return 1;
}
- printk(KERN_INFO "Channel measurement facility using %s format (%s)\n",
- format_string, detect_string);
+ printk(KERN_INFO "cio: Channel measurement facility using %s "
+ "format (%s)\n", format_string, detect_string);
return 0;
}
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index dfca0ef..5635e65 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -79,6 +79,7 @@ css_alloc_subchannel(struct subchannel_id schid)
sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
ret = cio_modify(sch);
if (ret) {
+ kfree(sch->lock);
kfree(sch);
return ERR_PTR(ret);
}
@@ -109,7 +110,7 @@ css_subchannel_release(struct device *dev)
}
}
-int css_sch_device_register(struct subchannel *sch)
+static int css_sch_device_register(struct subchannel *sch)
{
int ret;
@@ -184,8 +185,8 @@ static int css_register_subchannel(struct subchannel *sch)
/* make it known to the system */
ret = css_sch_device_register(sch);
if (ret) {
- printk (KERN_WARNING "%s: could not register %s\n",
- __func__, sch->dev.bus_id);
+ CIO_MSG_EVENT(0, "Could not register sch 0.%x.%04x: %d\n",
+ sch->schid.ssid, sch->schid.sch_no, ret);
return ret;
}
return ret;
@@ -371,15 +372,12 @@ static int __init slow_subchannel_init(void)
spin_lock_init(&slow_subchannel_lock);
slow_subchannel_set = idset_sch_new();
if (!slow_subchannel_set) {
- printk(KERN_WARNING "cio: could not allocate slow subchannel "
- "set\n");
+ CIO_MSG_EVENT(0, "could not allocate slow subchannel set\n");
return -ENOMEM;
}
return 0;
}
-subsys_initcall(slow_subchannel_init);
-
static void css_slow_path_func(struct work_struct *unused)
{
struct subchannel_id schid;
@@ -425,8 +423,8 @@ static int reprobe_subchannel(struct subchannel_id schid, void *data)
struct subchannel *sch;
int ret;
- CIO_DEBUG(KERN_INFO, 6, "cio: reprobe 0.%x.%04x\n",
- schid.ssid, schid.sch_no);
+ CIO_MSG_EVENT(6, "cio: reprobe 0.%x.%04x\n",
+ schid.ssid, schid.sch_no);
if (need_reprobe)
return -EAGAIN;
@@ -642,9 +640,20 @@ init_channel_subsystem (void)
{
int ret, i;
- if (chsc_determine_css_characteristics() == 0)
+ ret = chsc_determine_css_characteristics();
+ if (ret == -ENOMEM)
+ goto out; /* No need to continue. */
+ if (ret == 0)
css_characteristics_avail = 1;
+ ret = chsc_alloc_sei_area();
+ if (ret)
+ goto out;
+
+ ret = slow_subchannel_init();
+ if (ret)
+ goto out;
+
if ((ret = bus_register(&css_bus_type)))
goto out;
@@ -710,6 +719,10 @@ out_unregister:
out_bus:
bus_unregister(&css_bus_type);
out:
+ chsc_free_sei_area();
+ kfree(slow_subchannel_set);
+ printk(KERN_WARNING"cio: failed to initialize css driver (%d)!\n",
+ ret);
return ret;
}
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index ed79775..5d65e83 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -139,7 +139,6 @@ struct css_driver {
*/
extern struct bus_type css_bus_type;
-extern int css_sch_device_register(struct subchannel *);
extern void css_sch_device_unregister(struct subchannel *);
extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
extern int css_init_done;
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 001682e..e44d92e 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -117,7 +117,10 @@ static int ccw_uevent(struct device *dev, char **envp, int num_envp,
snprint_alias(modalias_buf, sizeof(modalias_buf), id, "");
ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
"MODALIAS=%s", modalias_buf);
- return ret;
+ if (ret)
+ return ret;
+ envp[i] = NULL;
+ return 0;
}
struct bus_type ccw_bus_type;
@@ -338,15 +341,20 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
rc = device_schedule_callback(&cdev->dev,
ccw_device_remove_orphan_cb);
if (rc)
- dev_info(&cdev->dev, "Couldn't unregister orphan\n");
+ CIO_MSG_EVENT(2, "Couldn't unregister orphan "
+ "0.%x.%04x\n",
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
return;
}
/* Deregister subchannel, which will kill the ccw device. */
rc = device_schedule_callback(cdev->dev.parent,
ccw_device_remove_sch_cb);
if (rc)
- dev_info(&cdev->dev,
- "Couldn't unregister disconnected device\n");
+ CIO_MSG_EVENT(2, "Couldn't unregister disconnected device "
+ "0.%x.%04x\n",
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
}
int
@@ -379,8 +387,10 @@ ccw_device_set_offline(struct ccw_device *cdev)
if (ret == 0)
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
else {
- pr_debug("ccw_device_offline returned %d, device %s\n",
- ret, cdev->dev.bus_id);
+ CIO_MSG_EVENT(2, "ccw_device_offline returned %d, "
+ "device 0.%x.%04x\n",
+ ret, cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
cdev->online = 1;
}
return ret;
@@ -402,8 +412,10 @@ ccw_device_set_online(struct ccw_device *cdev)
if (ret == 0)
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
else {
- pr_debug("ccw_device_online returned %d, device %s\n",
- ret, cdev->dev.bus_id);
+ CIO_MSG_EVENT(2, "ccw_device_online returned %d, "
+ "device 0.%x.%04x\n",
+ ret, cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
return ret;
}
if (cdev->private->state != DEV_STATE_ONLINE)
@@ -417,9 +429,11 @@ ccw_device_set_online(struct ccw_device *cdev)
spin_unlock_irq(cdev->ccwlock);
if (ret == 0)
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
- else
- pr_debug("ccw_device_offline returned %d, device %s\n",
- ret, cdev->dev.bus_id);
+ else
+ CIO_MSG_EVENT(2, "ccw_device_offline returned %d, "
+ "device 0.%x.%04x\n",
+ ret, cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
return (ret == 0) ? -ENODEV : ret;
}
@@ -439,9 +453,10 @@ static int online_store_recog_and_online(struct ccw_device *cdev)
if (cdev->id.cu_type == 0) {
ret = ccw_device_recognition(cdev);
if (ret) {
- printk(KERN_WARNING"Couldn't start recognition "
- "for device %s (ret=%d)\n",
- cdev->dev.bus_id, ret);
+ CIO_MSG_EVENT(0, "Couldn't start recognition "
+ "for device 0.%x.%04x (ret=%d)\n",
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno, ret);
return ret;
}
wait_event(cdev->private->wait_q,
@@ -461,8 +476,8 @@ static void online_store_handle_online(struct ccw_device *cdev, int force)
if (force && cdev->private->state == DEV_STATE_BOXED) {
ret = ccw_device_stlck(cdev);
if (ret) {
- printk(KERN_WARNING"ccw_device_stlck for device %s "
- "returned %d!\n", cdev->dev.bus_id, ret);
+ dev_warn(&cdev->dev,
+ "ccw_device_stlck returned %d!\n", ret);
return;
}
if (cdev->id.cu_type == 0)
@@ -893,8 +908,10 @@ io_subchannel_register(struct work_struct *work)
ret = device_reprobe(&cdev->dev);
if (ret)
/* We can't do much here. */
- dev_info(&cdev->dev, "device_reprobe() returned"
- " %d\n", ret);
+ CIO_MSG_EVENT(2, "device_reprobe() returned"
+ " %d for 0.%x.%04x\n", ret,
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
}
goto out;
}
@@ -907,8 +924,9 @@ io_subchannel_register(struct work_struct *work)
/* make it known to the system */
ret = ccw_device_register(cdev);
if (ret) {
- printk (KERN_WARNING "%s: could not register %s\n",
- __func__, cdev->dev.bus_id);
+ CIO_MSG_EVENT(0, "Could not register ccw dev 0.%x.%04x: %d\n",
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno, ret);
put_device(&cdev->dev);
spin_lock_irqsave(sch->lock, flags);
sch->dev.driver_data = NULL;
@@ -1361,7 +1379,6 @@ ccw_device_remove (struct device *dev)
struct ccw_driver *cdrv = cdev->drv;
int ret;
- pr_debug("removing device %s\n", cdev->dev.bus_id);
if (cdrv->remove)
cdrv->remove(cdev);
if (cdev->online) {
@@ -1374,8 +1391,10 @@ ccw_device_remove (struct device *dev)
dev_fsm_final_state(cdev));
else
//FIXME: we can't fail!
- pr_debug("ccw_device_offline returned %d, device %s\n",
- ret, cdev->dev.bus_id);
+ CIO_MSG_EVENT(2, "ccw_device_offline returned %d, "
+ "device 0.%x.%04x\n",
+ ret, cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
}
ccw_device_set_timeout(cdev, 0);
cdev->drv = NULL;
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 6bba809..8633dc5 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -268,7 +268,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
switch (state) {
case DEV_STATE_NOT_OPER:
CIO_DEBUG(KERN_WARNING, 2,
- "SenseID : unknown device %04x on subchannel "
+ "cio: SenseID : unknown device %04x on subchannel "
"0.%x.%04x\n", cdev->private->dev_id.devno,
sch->schid.ssid, sch->schid.sch_no);
break;
@@ -293,7 +293,8 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
return;
}
/* Issue device info message. */
- CIO_DEBUG(KERN_INFO, 2, "SenseID : device 0.%x.%04x reports: "
+ CIO_DEBUG(KERN_INFO, 2,
+ "cio: SenseID : device 0.%x.%04x reports: "
"CU Type/Mod = %04X/%02X, Dev Type/Mod = "
"%04X/%02X\n",
cdev->private->dev_id.ssid,
@@ -303,7 +304,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
break;
case DEV_STATE_BOXED:
CIO_DEBUG(KERN_WARNING, 2,
- "SenseID : boxed device %04x on subchannel "
+ "cio: SenseID : boxed device %04x on subchannel "
"0.%x.%04x\n", cdev->private->dev_id.devno,
sch->schid.ssid, sch->schid.sch_no);
break;
@@ -388,7 +389,7 @@ ccw_device_done(struct ccw_device *cdev, int state)
if (state == DEV_STATE_BOXED)
CIO_DEBUG(KERN_WARNING, 2,
- "Boxed device %04x on subchannel %04x\n",
+ "cio: Boxed device %04x on subchannel %04x\n",
cdev->private->dev_id.devno, sch->schid.sch_no);
if (cdev->private->flags.donotify) {
@@ -946,9 +947,10 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
/* Basic sense hasn't started. Try again. */
ccw_device_do_sense(cdev, irb);
else {
- printk(KERN_INFO "Huh? %s(%s): unsolicited "
- "interrupt...\n",
- __FUNCTION__, cdev->dev.bus_id);
+ CIO_MSG_EVENT(2, "Huh? 0.%x.%04x: unsolicited "
+ "interrupt during w4sense...\n",
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
if (cdev->handler)
cdev->handler (cdev, 0, irb);
}
@@ -1215,8 +1217,8 @@ ccw_device_nop(struct ccw_device *cdev, enum dev_event dev_event)
static void
ccw_device_bug(struct ccw_device *cdev, enum dev_event dev_event)
{
- printk(KERN_EMERG "dev_jumptable[%i][%i] == NULL\n",
- cdev->private->state, dev_event);
+ CIO_MSG_EVENT(0, "dev_jumptable[%i][%i] == NULL\n",
+ cdev->private->state, dev_event);
BUG();
}
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
index 60b9347..f232832 100644
--- a/drivers/s390/cio/device_id.c
+++ b/drivers/s390/cio/device_id.c
@@ -17,6 +17,7 @@
#include <asm/delay.h>
#include <asm/cio.h>
#include <asm/lowcore.h>
+#include <asm/diag.h>
#include "cio.h"
#include "cio_debug.h"
@@ -25,51 +26,6 @@
#include "ioasm.h"
/*
- * diag210 is used under VM to get information about a virtual device
- */
-int
-diag210(struct diag210 * addr)
-{
- /*
- * diag 210 needs its data below the 2GB border, so we
- * use a static data area to be sure
- */
- static struct diag210 diag210_tmp;
- static DEFINE_SPINLOCK(diag210_lock);
- unsigned long flags;
- int ccode;
-
- spin_lock_irqsave(&diag210_lock, flags);
- diag210_tmp = *addr;
-
-#ifdef CONFIG_64BIT
- asm volatile(
- " lhi %0,-1\n"
- " sam31\n"
- " diag %1,0,0x210\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- "1: sam64\n"
- EX_TABLE(0b,1b)
- : "=&d" (ccode) : "a" (&diag210_tmp) : "cc", "memory");
-#else
- asm volatile(
- " lhi %0,-1\n"
- " diag %1,0,0x210\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- "1:\n"
- EX_TABLE(0b,1b)
- : "=&d" (ccode) : "a" (&diag210_tmp) : "cc", "memory");
-#endif
-
- *addr = diag210_tmp;
- spin_unlock_irqrestore(&diag210_lock, flags);
-
- return ccode;
-}
-
-/*
* Input :
* devno - device number
* ps - pointer to sense ID data area
@@ -349,5 +305,3 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event)
break;
}
}
-
-EXPORT_SYMBOL(diag210);
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index a5d263f..14eba85 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -288,253 +288,6 @@ ccw_device_get_path_mask(struct ccw_device *cdev)
return sch->lpm;
}
-static void
-ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
-{
- if (!ip)
- /* unsolicited interrupt */
- return;
-
- /* Abuse intparm for error reporting. */
- if (IS_ERR(irb))
- cdev->private->intparm = -EIO;
- else if (irb->scsw.cc == 1)
- /* Retry for deferred condition code. */
- cdev->private->intparm = -EAGAIN;
- else if ((irb->scsw.dstat !=
- (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
- (irb->scsw.cstat != 0)) {
- /*
- * We didn't get channel end / device end. Check if path
- * verification has been started; we can retry after it has
- * finished. We also retry unit checks except for command reject
- * or intervention required. Also check for long busy
- * conditions.
- */
- if (cdev->private->flags.doverify ||
- cdev->private->state == DEV_STATE_VERIFY)
- cdev->private->intparm = -EAGAIN;
- else if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) &&
- !(irb->ecw[0] &
- (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ)))
- cdev->private->intparm = -EAGAIN;
- else if ((irb->scsw.dstat & DEV_STAT_ATTENTION) &&
- (irb->scsw.dstat & DEV_STAT_DEV_END) &&
- (irb->scsw.dstat & DEV_STAT_UNIT_EXCEP))
- cdev->private->intparm = -EAGAIN;
- else
- cdev->private->intparm = -EIO;
-
- } else
- cdev->private->intparm = 0;
- wake_up(&cdev->private->wait_q);
-}
-
-static int
-__ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, __u8 lpm)
-{
- int ret;
- struct subchannel *sch;
-
- sch = to_subchannel(cdev->dev.parent);
- do {
- ccw_device_set_timeout(cdev, 60 * HZ);
- ret = cio_start (sch, ccw, lpm);
- if (ret != 0)
- ccw_device_set_timeout(cdev, 0);
- if (ret == -EBUSY) {
- /* Try again later. */
- spin_unlock_irq(sch->lock);
- msleep(10);
- spin_lock_irq(sch->lock);
- continue;
- }
- if (ret != 0)
- /* Non-retryable error. */
- break;
- /* Wait for end of request. */
- cdev->private->intparm = magic;
- spin_unlock_irq(sch->lock);
- wait_event(cdev->private->wait_q,
- (cdev->private->intparm == -EIO) ||
- (cdev->private->intparm == -EAGAIN) ||
- (cdev->private->intparm == 0));
- spin_lock_irq(sch->lock);
- /* Check at least for channel end / device end */
- if (cdev->private->intparm == -EIO) {
- /* Non-retryable error. */
- ret = -EIO;
- break;
- }
- if (cdev->private->intparm == 0)
- /* Success. */
- break;
- /* Try again later. */
- spin_unlock_irq(sch->lock);
- msleep(10);
- spin_lock_irq(sch->lock);
- } while (1);
-
- return ret;
-}
-
-/**
- * read_dev_chars() - read device characteristics
- * @param cdev target ccw device
- * @param buffer pointer to buffer for rdc data
- * @param length size of rdc data
- * @returns 0 for success, negative error value on failure
- *
- * Context:
- * called for online device, lock not held
- **/
-int
-read_dev_chars (struct ccw_device *cdev, void **buffer, int length)
-{
- void (*handler)(struct ccw_device *, unsigned long, struct irb *);
- struct subchannel *sch;
- int ret;
- struct ccw1 *rdc_ccw;
-
- if (!cdev)
- return -ENODEV;
- if (!buffer || !length)
- return -EINVAL;
- sch = to_subchannel(cdev->dev.parent);
-
- CIO_TRACE_EVENT (4, "rddevch");
- CIO_TRACE_EVENT (4, sch->dev.bus_id);
-
- rdc_ccw = kzalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
- if (!rdc_ccw)
- return -ENOMEM;
- rdc_ccw->cmd_code = CCW_CMD_RDC;
- rdc_ccw->count = length;
- rdc_ccw->flags = CCW_FLAG_SLI;
- ret = set_normalized_cda (rdc_ccw, (*buffer));
- if (ret != 0) {
- kfree(rdc_ccw);
- return ret;
- }
-
- spin_lock_irq(sch->lock);
- /* Save interrupt handler. */
- handler = cdev->handler;
- /* Temporarily install own handler. */
- cdev->handler = ccw_device_wake_up;
- if (cdev->private->state != DEV_STATE_ONLINE)
- ret = -ENODEV;
- else if (((sch->schib.scsw.stctl & SCSW_STCTL_PRIM_STATUS) &&
- !(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) ||
- cdev->private->flags.doverify)
- ret = -EBUSY;
- else
- /* 0x00D9C4C3 == ebcdic "RDC" */
- ret = __ccw_device_retry_loop(cdev, rdc_ccw, 0x00D9C4C3, 0);
-
- /* Restore interrupt handler. */
- cdev->handler = handler;
- spin_unlock_irq(sch->lock);
-
- clear_normalized_cda (rdc_ccw);
- kfree(rdc_ccw);
-
- return ret;
-}
-
-/*
- * Read Configuration data using path mask
- */
-int
-read_conf_data_lpm (struct ccw_device *cdev, void **buffer, int *length, __u8 lpm)
-{
- void (*handler)(struct ccw_device *, unsigned long, struct irb *);
- struct subchannel *sch;
- struct ciw *ciw;
- char *rcd_buf;
- int ret;
- struct ccw1 *rcd_ccw;
-
- if (!cdev)
- return -ENODEV;
- if (!buffer || !length)
- return -EINVAL;
- sch = to_subchannel(cdev->dev.parent);
-
- CIO_TRACE_EVENT (4, "rdconf");
- CIO_TRACE_EVENT (4, sch->dev.bus_id);
-
- /*
- * scan for RCD command in extended SenseID data
- */
- ciw = ccw_device_get_ciw(cdev, CIW_TYPE_RCD);
- if (!ciw || ciw->cmd == 0)
- return -EOPNOTSUPP;
-
- /* Adjust requested path mask to excluded varied off paths. */
- if (lpm) {
- lpm &= sch->opm;
- if (lpm == 0)
- return -EACCES;
- }
-
- rcd_ccw = kzalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
- if (!rcd_ccw)
- return -ENOMEM;
- rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA);
- if (!rcd_buf) {
- kfree(rcd_ccw);
- return -ENOMEM;
- }
- rcd_ccw->cmd_code = ciw->cmd;
- rcd_ccw->cda = (__u32) __pa (rcd_buf);
- rcd_ccw->count = ciw->count;
- rcd_ccw->flags = CCW_FLAG_SLI;
-
- spin_lock_irq(sch->lock);
- /* Save interrupt handler. */
- handler = cdev->handler;
- /* Temporarily install own handler. */
- cdev->handler = ccw_device_wake_up;
- if (cdev->private->state != DEV_STATE_ONLINE)
- ret = -ENODEV;
- else if (((sch->schib.scsw.stctl & SCSW_STCTL_PRIM_STATUS) &&
- !(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) ||
- cdev->private->flags.doverify)
- ret = -EBUSY;
- else
- /* 0x00D9C3C4 == ebcdic "RCD" */
- ret = __ccw_device_retry_loop(cdev, rcd_ccw, 0x00D9C3C4, lpm);
-
- /* Restore interrupt handler. */
- cdev->handler = handler;
- spin_unlock_irq(sch->lock);
-
- /*
- * on success we update the user input parms
- */
- if (ret) {
- kfree (rcd_buf);
- *buffer = NULL;
- *length = 0;
- } else {
- *length = ciw->count;
- *buffer = rcd_buf;
- }
- kfree(rcd_ccw);
-
- return ret;
-}
-
-/*
- * Read Configuration data
- */
-int
-read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
-{
- return read_conf_data_lpm (cdev, buffer, length, 0);
-}
-
/*
* Try to break the lock on a boxed device.
*/
@@ -635,12 +388,6 @@ _ccw_device_get_subchannel_number(struct ccw_device *cdev)
return cdev->private->schid.sch_no;
}
-int
-_ccw_device_get_device_number(struct ccw_device *cdev)
-{
- return cdev->private->dev_id.devno;
-}
-
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ccw_device_set_options_mask);
@@ -655,9 +402,5 @@ EXPORT_SYMBOL(ccw_device_start_timeout_key);
EXPORT_SYMBOL(ccw_device_start_key);
EXPORT_SYMBOL(ccw_device_get_ciw);
EXPORT_SYMBOL(ccw_device_get_path_mask);
-EXPORT_SYMBOL(read_conf_data);
-EXPORT_SYMBOL(read_dev_chars);
EXPORT_SYMBOL(_ccw_device_get_subchannel_number);
-EXPORT_SYMBOL(_ccw_device_get_device_number);
EXPORT_SYMBOL_GPL(ccw_device_get_chp_desc);
-EXPORT_SYMBOL_GPL(read_conf_data_lpm);
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index ed026a1..d8d4798 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -81,6 +81,7 @@ static __u32 volatile spare_indicator;
static atomic_t spare_indicator_usecount;
#define QDIO_MEMPOOL_SCSSC_ELEMENTS 2
static mempool_t *qdio_mempool_scssc;
+static struct kmem_cache *qdio_q_cache;
static debug_info_t *qdio_dbf_setup;
static debug_info_t *qdio_dbf_sbal;
@@ -194,6 +195,8 @@ qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
again:
ccq = do_eqbs(irq->sch_token, state, q_no, start, cnt);
rc = qdio_check_ccq(q, ccq);
+ if ((ccq == 96) && (tmp_cnt != *cnt))
+ rc = 0;
if (rc == 1) {
QDIO_DBF_TEXT5(1,trace,"eqAGAIN");
goto again;
@@ -739,7 +742,8 @@ qdio_get_outbound_buffer_frontier(struct qdio_q *q)
first_not_to_check=f+qdio_min(atomic_read(&q->number_of_buffers_used),
(QDIO_MAX_BUFFERS_PER_Q-1));
- if ((!q->is_iqdio_q)&&(!q->hydra_gives_outbound_pcis))
+ if (((!q->is_iqdio_q) && (!q->hydra_gives_outbound_pcis)) ||
+ (q->queue_type == QDIO_IQDIO_QFMT_ASYNCH))
SYNC_MEMORY;
check_next:
@@ -1617,23 +1621,21 @@ static void
qdio_release_irq_memory(struct qdio_irq *irq_ptr)
{
int i;
+ struct qdio_q *q;
- for (i=0;i<QDIO_MAX_QUEUES_PER_IRQ;i++) {
- if (!irq_ptr->input_qs[i])
- goto next;
-
- kfree(irq_ptr->input_qs[i]->slib);
- kfree(irq_ptr->input_qs[i]);
-
-next:
- if (!irq_ptr->output_qs[i])
- continue;
-
- kfree(irq_ptr->output_qs[i]->slib);
- kfree(irq_ptr->output_qs[i]);
-
+ for (i = 0; i < QDIO_MAX_QUEUES_PER_IRQ; i++) {
+ q = irq_ptr->input_qs[i];
+ if (q) {
+ free_page((unsigned long) q->slib);
+ kmem_cache_free(qdio_q_cache, q);
+ }
+ q = irq_ptr->output_qs[i];
+ if (q) {
+ free_page((unsigned long) q->slib);
+ kmem_cache_free(qdio_q_cache, q);
+ }
}
- kfree(irq_ptr->qdr);
+ free_page((unsigned long) irq_ptr->qdr);
free_page((unsigned long) irq_ptr);
}
@@ -1680,44 +1682,35 @@ qdio_alloc_qs(struct qdio_irq *irq_ptr,
{
int i;
struct qdio_q *q;
- int result=-ENOMEM;
-
- for (i=0;i<no_input_qs;i++) {
- q = kzalloc(sizeof(struct qdio_q), GFP_KERNEL);
- if (!q) {
- QDIO_PRINT_ERR("kmalloc of q failed!\n");
- goto out;
- }
+ for (i = 0; i < no_input_qs; i++) {
+ q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL);
+ if (!q)
+ return -ENOMEM;
+ memset(q, 0, sizeof(*q));
- q->slib = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ q->slib = (struct slib *) __get_free_page(GFP_KERNEL);
if (!q->slib) {
- QDIO_PRINT_ERR("kmalloc of slib failed!\n");
- goto out;
+ kmem_cache_free(qdio_q_cache, q);
+ return -ENOMEM;
}
-
irq_ptr->input_qs[i]=q;
}
- for (i=0;i<no_output_qs;i++) {
- q = kzalloc(sizeof(struct qdio_q), GFP_KERNEL);
-
- if (!q) {
- goto out;
- }
+ for (i = 0; i < no_output_qs; i++) {
+ q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL);
+ if (!q)
+ return -ENOMEM;
+ memset(q, 0, sizeof(*q));
- q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL);
+ q->slib = (struct slib *) __get_free_page(GFP_KERNEL);
if (!q->slib) {
- QDIO_PRINT_ERR("kmalloc of slib failed!\n");
- goto out;
+ kmem_cache_free(qdio_q_cache, q);
+ return -ENOMEM;
}
-
irq_ptr->output_qs[i]=q;
}
-
- result=0;
-out:
- return result;
+ return 0;
}
static void
@@ -2985,17 +2978,17 @@ qdio_allocate(struct qdio_initialize *init_data)
QDIO_DBF_HEX0(0,setup,&irq_ptr,sizeof(void*));
if (!irq_ptr) {
- QDIO_PRINT_ERR("kmalloc of irq_ptr failed!\n");
+ QDIO_PRINT_ERR("allocation of irq_ptr failed!\n");
return -ENOMEM;
}
init_MUTEX(&irq_ptr->setting_up_sema);
/* QDR must be in DMA area since CCW data address is only 32 bit */
- irq_ptr->qdr=kmalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA);
+ irq_ptr->qdr = (struct qdr *) __get_free_page(GFP_KERNEL | GFP_DMA);
if (!(irq_ptr->qdr)) {
free_page((unsigned long) irq_ptr);
- QDIO_PRINT_ERR("kmalloc of irq_ptr->qdr failed!\n");
+ QDIO_PRINT_ERR("allocation of irq_ptr->qdr failed!\n");
return -ENOMEM;
}
QDIO_DBF_TEXT0(0,setup,"qdr:");
@@ -3004,6 +2997,7 @@ qdio_allocate(struct qdio_initialize *init_data)
if (qdio_alloc_qs(irq_ptr,
init_data->no_input_qs,
init_data->no_output_qs)) {
+ QDIO_PRINT_ERR("queue allocation failed!\n");
qdio_release_irq_memory(irq_ptr);
return -ENOMEM;
}
@@ -3895,9 +3889,19 @@ init_QDIO(void)
if (res)
return res;
+ qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q),
+ 256, 0, NULL);
+ if (!qdio_q_cache) {
+ qdio_release_qdio_memory();
+ return -ENOMEM;
+ }
+
res = qdio_register_dbf_views();
- if (res)
+ if (res) {
+ kmem_cache_destroy(qdio_q_cache);
+ qdio_release_qdio_memory();
return res;
+ }
QDIO_DBF_TEXT0(0,setup,"initQDIO");
res = bus_create_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
@@ -3929,6 +3933,7 @@ cleanup_QDIO(void)
qdio_release_qdio_memory();
qdio_unregister_dbf_views();
mempool_destroy(qdio_mempool_scssc);
+ kmem_cache_destroy(qdio_q_cache);
bus_remove_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
printk("qdio: %s: module removed\n",version);
}
diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c
index b20fd06..92e8a37 100644
--- a/drivers/s390/net/ctcmain.c
+++ b/drivers/s390/net/ctcmain.c
@@ -674,7 +674,7 @@ ch_action_txdone(fsm_instance * fi, int event, void *arg)
int first = 1;
int i;
unsigned long duration;
- struct timespec done_stamp = xtime;
+ struct timespec done_stamp = current_kernel_time();
DBF_TEXT(trace, 4, __FUNCTION__);
@@ -730,7 +730,7 @@ ch_action_txdone(fsm_instance * fi, int event, void *arg)
spin_unlock(&ch->collect_lock);
ch->ccw[1].count = ch->trans_skb->len;
fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
- ch->prof.send_stamp = xtime;
+ ch->prof.send_stamp = current_kernel_time();
rc = ccw_device_start(ch->cdev, &ch->ccw[0],
(unsigned long) ch, 0xff, 0);
ch->prof.doios_multi++;
@@ -2281,7 +2281,7 @@ transmit_skb(struct channel *ch, struct sk_buff *skb)
fsm_newstate(ch->fsm, CH_STATE_TX);
fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags);
- ch->prof.send_stamp = xtime;
+ ch->prof.send_stamp = current_kernel_time();
rc = ccw_device_start(ch->cdev, &ch->ccw[ccw_idx],
(unsigned long) ch, 0xff, 0);
spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags);
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 3d28e1a..2688894 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -753,7 +753,7 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg)
header.next = 0;
memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN);
- conn->prof.send_stamp = xtime;
+ conn->prof.send_stamp = current_kernel_time();
txmsg.class = 0;
txmsg.tag = 0;
rc = iucv_message_send(conn->path, &txmsg, 0, 0,
@@ -1185,7 +1185,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn,
memcpy(skb_put(nskb, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN);
fsm_newstate(conn->fsm, CONN_STATE_TX);
- conn->prof.send_stamp = xtime;
+ conn->prof.send_stamp = current_kernel_time();
msg.tag = 1;
msg.class = 0;
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index b240800..9929997 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -4154,8 +4154,9 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
fcp_rsp_iu->fcp_resid,
(int) zfcp_get_fcp_dl(fcp_cmnd_iu));
- scpnt->resid = fcp_rsp_iu->fcp_resid;
- if (scpnt->request_bufflen - scpnt->resid < scpnt->underflow)
+ scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid);
+ if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) <
+ scpnt->underflow)
set_host_byte(&scpnt->result, DID_ERROR);
}
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index c408bad..81daa82 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -36,8 +36,6 @@ static void zfcp_qdio_sbale_fill
(struct zfcp_fsf_req *, unsigned long, void *, int);
static int zfcp_qdio_sbals_from_segment
(struct zfcp_fsf_req *, unsigned long, void *, unsigned long);
-static int zfcp_qdio_sbals_from_buffer
- (struct zfcp_fsf_req *, unsigned long, void *, unsigned long, int);
static qdio_handler_t zfcp_qdio_request_handler;
static qdio_handler_t zfcp_qdio_response_handler;
@@ -632,28 +630,6 @@ out:
/**
- * zfcp_qdio_sbals_from_buffer - fill SBALs from buffer
- * @fsf_req: request to be processed
- * @sbtype: SBALE flags
- * @buffer: data buffer
- * @length: length of buffer
- * @max_sbals: upper bound for number of SBALs to be used
- */
-static int
-zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
- void *buffer, unsigned long length, int max_sbals)
-{
- struct scatterlist sg_segment;
-
- zfcp_address_to_sg(buffer, &sg_segment);
- sg_segment.length = length;
-
- return zfcp_qdio_sbals_from_sg(fsf_req, sbtype, &sg_segment, 1,
- max_sbals);
-}
-
-
-/**
* zfcp_qdio_sbals_from_scsicmnd - fill SBALs from scsi command
* @fsf_req: request to be processed
* @sbtype: SBALE flags
@@ -664,18 +640,13 @@ int
zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req,
unsigned long sbtype, struct scsi_cmnd *scsi_cmnd)
{
- if (scsi_cmnd->use_sg) {
+ if (scsi_sg_count(scsi_cmnd))
return zfcp_qdio_sbals_from_sg(fsf_req, sbtype,
- (struct scatterlist *)
- scsi_cmnd->request_buffer,
- scsi_cmnd->use_sg,
- ZFCP_MAX_SBALS_PER_REQ);
- } else {
- return zfcp_qdio_sbals_from_buffer(fsf_req, sbtype,
- scsi_cmnd->request_buffer,
- scsi_cmnd->request_bufflen,
- ZFCP_MAX_SBALS_PER_REQ);
- }
+ scsi_sglist(scsi_cmnd),
+ scsi_sg_count(scsi_cmnd),
+ ZFCP_MAX_SBALS_PER_REQ);
+ else
+ return 0;
}
/**