summaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r--drivers/s390/cio/ccwgroup.c6
-rw-r--r--drivers/s390/cio/device.c35
-rw-r--r--drivers/s390/cio/device.h1
-rw-r--r--drivers/s390/cio/device_fsm.c4
-rw-r--r--drivers/s390/cio/qdio_main.c36
5 files changed, 48 insertions, 34 deletions
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 2864581d8ecb..5c567414c4bb 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -428,7 +428,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const
gdev = to_ccwgroupdev(dev);
gdrv = to_ccwgroupdrv(dev->driver);
- if (!try_module_get(gdrv->owner))
+ if (!try_module_get(gdrv->driver.owner))
return -EINVAL;
ret = strict_strtoul(buf, 0, &value);
@@ -442,7 +442,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const
else
ret = -EINVAL;
out:
- module_put(gdrv->owner);
+ module_put(gdrv->driver.owner);
return (ret == 0) ? count : ret;
}
@@ -616,8 +616,6 @@ int ccwgroup_driver_register(struct ccwgroup_driver *cdriver)
{
/* register our new driver with the core */
cdriver->driver.bus = &ccwgroup_bus_type;
- cdriver->driver.name = cdriver->name;
- cdriver->driver.owner = cdriver->owner;
return driver_register(&cdriver->driver);
}
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index e50b12163afe..8e04c00cf0ad 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -127,7 +127,7 @@ static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env)
return ret;
}
-struct bus_type ccw_bus_type;
+static struct bus_type ccw_bus_type;
static void io_subchannel_irq(struct subchannel *);
static int io_subchannel_probe(struct subchannel *);
@@ -541,15 +541,24 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
int force, ret;
unsigned long i;
- if (!dev_fsm_final_state(cdev) &&
- cdev->private->state != DEV_STATE_DISCONNECTED)
- return -EAGAIN;
+ /* Prevent conflict between multiple on-/offline processing requests. */
if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0)
return -EAGAIN;
+ /* Prevent conflict between internal I/Os and on-/offline processing. */
+ if (!dev_fsm_final_state(cdev) &&
+ cdev->private->state != DEV_STATE_DISCONNECTED) {
+ ret = -EAGAIN;
+ goto out_onoff;
+ }
+ /* Prevent conflict between pending work and on-/offline processing.*/
+ if (work_pending(&cdev->private->todo_work)) {
+ ret = -EAGAIN;
+ goto out_onoff;
+ }
- if (cdev->drv && !try_module_get(cdev->drv->owner)) {
- atomic_set(&cdev->private->onoff, 0);
- return -EINVAL;
+ if (cdev->drv && !try_module_get(cdev->drv->driver.owner)) {
+ ret = -EINVAL;
+ goto out_onoff;
}
if (!strncmp(buf, "force\n", count)) {
force = 1;
@@ -573,7 +582,8 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
}
out:
if (cdev->drv)
- module_put(cdev->drv->owner);
+ module_put(cdev->drv->driver.owner);
+out_onoff:
atomic_set(&cdev->private->onoff, 0);
return (ret < 0) ? ret : count;
}
@@ -1311,10 +1321,12 @@ static int purge_fn(struct device *dev, void *data)
spin_lock_irq(cdev->ccwlock);
if (is_blacklisted(id->ssid, id->devno) &&
- (cdev->private->state == DEV_STATE_OFFLINE)) {
+ (cdev->private->state == DEV_STATE_OFFLINE) &&
+ (atomic_cmpxchg(&cdev->private->onoff, 0, 1) == 0)) {
CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", id->ssid,
id->devno);
ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
+ atomic_set(&cdev->private->onoff, 0);
}
spin_unlock_irq(cdev->ccwlock);
/* Abort loop in case of pending signal. */
@@ -1970,7 +1982,7 @@ static const struct dev_pm_ops ccw_pm_ops = {
.restore = ccw_device_pm_restore,
};
-struct bus_type ccw_bus_type = {
+static struct bus_type ccw_bus_type = {
.name = "ccw",
.match = ccw_bus_match,
.uevent = ccw_uevent,
@@ -1993,8 +2005,6 @@ int ccw_driver_register(struct ccw_driver *cdriver)
struct device_driver *drv = &cdriver->driver;
drv->bus = &ccw_bus_type;
- drv->name = cdriver->name;
- drv->owner = cdriver->owner;
return driver_register(drv);
}
@@ -2112,5 +2122,4 @@ EXPORT_SYMBOL(ccw_device_set_offline);
EXPORT_SYMBOL(ccw_driver_register);
EXPORT_SYMBOL(ccw_driver_unregister);
EXPORT_SYMBOL(get_ccwdev_by_busid);
-EXPORT_SYMBOL(ccw_bus_type);
EXPORT_SYMBOL_GPL(ccw_device_get_subchannel_id);
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 379de2d1ec49..7e297c7bb5ff 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -133,7 +133,6 @@ void ccw_device_set_notoper(struct ccw_device *cdev);
/* qdio needs this. */
void ccw_device_set_timeout(struct ccw_device *, int);
extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *);
-extern struct bus_type ccw_bus_type;
/* Channel measurement facility related */
void retry_set_schib(struct ccw_device *cdev);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index a845695ac314..6084103672b5 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -318,7 +318,7 @@ ccw_device_sense_id_done(struct ccw_device *cdev, int err)
/**
* ccw_device_notify() - inform the device's driver about an event
- * @cdev: device for which an event occured
+ * @cdev: device for which an event occurred
* @event: event that occurred
*
* Returns:
@@ -688,7 +688,7 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
(scsw_stctl(&cdev->private->irb.scsw) & SCSW_STCTL_STATUS_PEND)) {
/*
* No final status yet or final status not yet delivered
- * to the device driver. Can't do path verfication now,
+ * to the device driver. Can't do path verification now,
* delay until final status was delivered.
*/
cdev->private->flags.doverify = 1;
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 5640c89cd9de..e8f267eb8887 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -407,8 +407,11 @@ static inline void account_sbals(struct qdio_q *q, int count)
q->q_stats.nr_sbals[pos]++;
}
-static void announce_buffer_error(struct qdio_q *q, int count)
+static void process_buffer_error(struct qdio_q *q, int count)
{
+ unsigned char state = (q->is_input_q) ? SLSB_P_INPUT_NOT_INIT :
+ SLSB_P_OUTPUT_NOT_INIT;
+
q->qdio_error |= QDIO_ERROR_SLSB_STATE;
/* special handling for no target buffer empty */
@@ -426,6 +429,12 @@ static void announce_buffer_error(struct qdio_q *q, int count)
DBF_ERROR("F14:%2x F15:%2x",
q->sbal[q->first_to_check]->element[14].flags & 0xff,
q->sbal[q->first_to_check]->element[15].flags & 0xff);
+
+ /*
+ * Interrupts may be avoided as long as the error is present
+ * so change the buffer state immediately to avoid starvation.
+ */
+ set_buf_states(q, q->first_to_check, state, count);
}
static inline void inbound_primed(struct qdio_q *q, int count)
@@ -506,8 +515,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q)
account_sbals(q, count);
break;
case SLSB_P_INPUT_ERROR:
- announce_buffer_error(q, count);
- /* process the buffer, the upper layer will take care of it */
+ process_buffer_error(q, count);
q->first_to_check = add_buf(q->first_to_check, count);
atomic_sub(count, &q->nr_buf_used);
if (q->irq_ptr->perf_stat_enabled)
@@ -677,8 +685,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q)
account_sbals(q, count);
break;
case SLSB_P_OUTPUT_ERROR:
- announce_buffer_error(q, count);
- /* process the buffer, the upper layer will take care of it */
+ process_buffer_error(q, count);
q->first_to_check = add_buf(q->first_to_check, count);
atomic_sub(count, &q->nr_buf_used);
if (q->irq_ptr->perf_stat_enabled)
@@ -1508,7 +1515,8 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags,
if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)
return -EBUSY;
-
+ if (!count)
+ return 0;
if (callflags & QDIO_FLAG_SYNC_INPUT)
return handle_inbound(irq_ptr->input_qs[q_nr],
callflags, bufnr, count);
@@ -1648,26 +1656,26 @@ static int __init init_QDIO(void)
{
int rc;
- rc = qdio_setup_init();
+ rc = qdio_debug_init();
if (rc)
return rc;
+ rc = qdio_setup_init();
+ if (rc)
+ goto out_debug;
rc = tiqdio_allocate_memory();
if (rc)
goto out_cache;
- rc = qdio_debug_init();
- if (rc)
- goto out_ti;
rc = tiqdio_register_thinints();
if (rc)
- goto out_debug;
+ goto out_ti;
return 0;
-out_debug:
- qdio_debug_exit();
out_ti:
tiqdio_free_memory();
out_cache:
qdio_setup_exit();
+out_debug:
+ qdio_debug_exit();
return rc;
}
@@ -1675,8 +1683,8 @@ static void __exit exit_QDIO(void)
{
tiqdio_unregister_thinints();
tiqdio_free_memory();
- qdio_debug_exit();
qdio_setup_exit();
+ qdio_debug_exit();
}
module_init(init_QDIO);
OpenPOWER on IntegriCloud