summaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r--drivers/s390/cio/Makefile2
-rw-r--r--drivers/s390/cio/chp.c3
-rw-r--r--drivers/s390/cio/chsc.h24
-rw-r--r--drivers/s390/cio/cio.c56
-rw-r--r--drivers/s390/cio/cio.h4
-rw-r--r--drivers/s390/cio/css.c32
-rw-r--r--drivers/s390/cio/device.c172
-rw-r--r--drivers/s390/cio/device_fsm.c22
-rw-r--r--drivers/s390/cio/qdio.h4
-rw-r--r--drivers/s390/cio/qdio_debug.c55
-rw-r--r--drivers/s390/cio/qdio_main.c4
-rw-r--r--drivers/s390/cio/scsw.c843
12 files changed, 167 insertions, 1054 deletions
diff --git a/drivers/s390/cio/Makefile b/drivers/s390/cio/Makefile
index adb3dd301528..fa4c9662f65e 100644
--- a/drivers/s390/cio/Makefile
+++ b/drivers/s390/cio/Makefile
@@ -2,7 +2,7 @@
# Makefile for the S/390 common i/o drivers
#
-obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o scsw.o \
+obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o \
fcx.o itcw.o crw.o
ccw_device-objs += device.o device_fsm.o device_ops.o
ccw_device-objs += device_id.o device_pgid.o device_status.o
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index 3e5f304ad88f..40002830d48a 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -417,7 +417,8 @@ int chp_new(struct chp_id chpid)
if (ret) {
CIO_MSG_EVENT(0, "Could not register chp%x.%02x: %d\n",
chpid.cssid, chpid.id, ret);
- goto out_free;
+ put_device(&chp->dev);
+ goto out;
}
ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group);
if (ret) {
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index 425e8f89a6c5..37aa611d4ac5 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -37,29 +37,6 @@ struct channel_path_desc {
struct channel_path;
-struct css_general_char {
- u64 : 12;
- u32 dynio : 1; /* bit 12 */
- u32 : 28;
- u32 aif : 1; /* bit 41 */
- u32 : 3;
- u32 mcss : 1; /* bit 45 */
- u32 fcs : 1; /* bit 46 */
- u32 : 1;
- u32 ext_mb : 1; /* bit 48 */
- u32 : 7;
- u32 aif_tdd : 1; /* bit 56 */
- u32 : 1;
- u32 qebsm : 1; /* bit 58 */
- u32 : 8;
- u32 aif_osa : 1; /* bit 67 */
- u32 : 14;
- u32 cib : 1; /* bit 82 */
- u32 : 5;
- u32 fcx : 1; /* bit 88 */
- u32 : 7;
-}__attribute__((packed));
-
struct css_chsc_char {
u64 res;
u64 : 20;
@@ -72,7 +49,6 @@ struct css_chsc_char {
u32 : 19;
}__attribute__((packed));
-extern struct css_general_char css_general_characteristics;
extern struct css_chsc_char css_chsc_characteristics;
struct chsc_ssd_info {
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 5ec7789bd9d8..138124fcfcad 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -139,12 +139,11 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */
__u8 lpm, /* logical path mask */
__u8 key) /* storage key */
{
- char dbf_txt[15];
int ccode;
union orb *orb;
- CIO_TRACE_EVENT(4, "stIO");
- CIO_TRACE_EVENT(4, dev_name(&sch->dev));
+ CIO_TRACE_EVENT(5, "stIO");
+ CIO_TRACE_EVENT(5, dev_name(&sch->dev));
orb = &to_io_private(sch)->orb;
memset(orb, 0, sizeof(union orb));
@@ -169,8 +168,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */
ccode = ssch(sch->schid, orb);
/* process condition code */
- sprintf(dbf_txt, "ccode:%d", ccode);
- CIO_TRACE_EVENT(4, dbf_txt);
+ CIO_HEX_EVENT(5, &ccode, sizeof(ccode));
switch (ccode) {
case 0:
@@ -201,16 +199,14 @@ cio_start (struct subchannel *sch, struct ccw1 *cpa, __u8 lpm)
int
cio_resume (struct subchannel *sch)
{
- char dbf_txt[15];
int ccode;
- CIO_TRACE_EVENT (4, "resIO");
+ CIO_TRACE_EVENT(4, "resIO");
CIO_TRACE_EVENT(4, dev_name(&sch->dev));
ccode = rsch (sch->schid);
- sprintf (dbf_txt, "ccode:%d", ccode);
- CIO_TRACE_EVENT (4, dbf_txt);
+ CIO_HEX_EVENT(4, &ccode, sizeof(ccode));
switch (ccode) {
case 0:
@@ -235,13 +231,12 @@ cio_resume (struct subchannel *sch)
int
cio_halt(struct subchannel *sch)
{
- char dbf_txt[15];
int ccode;
if (!sch)
return -ENODEV;
- CIO_TRACE_EVENT (2, "haltIO");
+ CIO_TRACE_EVENT(2, "haltIO");
CIO_TRACE_EVENT(2, dev_name(&sch->dev));
/*
@@ -249,8 +244,7 @@ cio_halt(struct subchannel *sch)
*/
ccode = hsch (sch->schid);
- sprintf (dbf_txt, "ccode:%d", ccode);
- CIO_TRACE_EVENT (2, dbf_txt);
+ CIO_HEX_EVENT(2, &ccode, sizeof(ccode));
switch (ccode) {
case 0:
@@ -270,13 +264,12 @@ cio_halt(struct subchannel *sch)
int
cio_clear(struct subchannel *sch)
{
- char dbf_txt[15];
int ccode;
if (!sch)
return -ENODEV;
- CIO_TRACE_EVENT (2, "clearIO");
+ CIO_TRACE_EVENT(2, "clearIO");
CIO_TRACE_EVENT(2, dev_name(&sch->dev));
/*
@@ -284,8 +277,7 @@ cio_clear(struct subchannel *sch)
*/
ccode = csch (sch->schid);
- sprintf (dbf_txt, "ccode:%d", ccode);
- CIO_TRACE_EVENT (2, dbf_txt);
+ CIO_HEX_EVENT(2, &ccode, sizeof(ccode));
switch (ccode) {
case 0:
@@ -306,19 +298,17 @@ cio_clear(struct subchannel *sch)
int
cio_cancel (struct subchannel *sch)
{
- char dbf_txt[15];
int ccode;
if (!sch)
return -ENODEV;
- CIO_TRACE_EVENT (2, "cancelIO");
+ CIO_TRACE_EVENT(2, "cancelIO");
CIO_TRACE_EVENT(2, dev_name(&sch->dev));
ccode = xsch (sch->schid);
- sprintf (dbf_txt, "ccode:%d", ccode);
- CIO_TRACE_EVENT (2, dbf_txt);
+ CIO_HEX_EVENT(2, &ccode, sizeof(ccode));
switch (ccode) {
case 0: /* success */
@@ -429,11 +419,10 @@ EXPORT_SYMBOL_GPL(cio_update_schib);
*/
int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
{
- char dbf_txt[15];
int retry;
int ret;
- CIO_TRACE_EVENT (2, "ensch");
+ CIO_TRACE_EVENT(2, "ensch");
CIO_TRACE_EVENT(2, dev_name(&sch->dev));
if (sch_is_pseudo_sch(sch))
@@ -460,8 +449,7 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
} else
break;
}
- sprintf (dbf_txt, "ret:%d", ret);
- CIO_TRACE_EVENT (2, dbf_txt);
+ CIO_HEX_EVENT(2, &ret, sizeof(ret));
return ret;
}
EXPORT_SYMBOL_GPL(cio_enable_subchannel);
@@ -472,11 +460,10 @@ EXPORT_SYMBOL_GPL(cio_enable_subchannel);
*/
int cio_disable_subchannel(struct subchannel *sch)
{
- char dbf_txt[15];
int retry;
int ret;
- CIO_TRACE_EVENT (2, "dissch");
+ CIO_TRACE_EVENT(2, "dissch");
CIO_TRACE_EVENT(2, dev_name(&sch->dev));
if (sch_is_pseudo_sch(sch))
@@ -495,8 +482,7 @@ int cio_disable_subchannel(struct subchannel *sch)
} else
break;
}
- sprintf (dbf_txt, "ret:%d", ret);
- CIO_TRACE_EVENT (2, dbf_txt);
+ CIO_HEX_EVENT(2, &ret, sizeof(ret));
return ret;
}
EXPORT_SYMBOL_GPL(cio_disable_subchannel);
@@ -578,11 +564,6 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
goto out;
}
mutex_init(&sch->reg_mutex);
- /* Set a name for the subchannel */
- if (cio_is_console(schid))
- sch->dev.init_name = cio_get_console_sch_name(schid);
- else
- dev_set_name(&sch->dev, "0.%x.%04x", schid.ssid, schid.sch_no);
/*
* The first subchannel that is not-operational (ccode==3)
@@ -686,7 +667,6 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
#ifdef CONFIG_CCW_CONSOLE
static struct subchannel console_subchannel;
-static char console_sch_name[10] = "0.x.xxxx";
static struct io_subchannel_private console_priv;
static int console_subchannel_in_use;
@@ -873,12 +853,6 @@ cio_get_console_subchannel(void)
return &console_subchannel;
}
-const char *cio_get_console_sch_name(struct subchannel_id schid)
-{
- snprintf(console_sch_name, 10, "0.%x.%04x", schid.ssid, schid.sch_no);
- return (const char *)console_sch_name;
-}
-
#endif
static int
__disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 5150fba742ac..2e43558c704b 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -133,15 +133,11 @@ extern int cio_is_console(struct subchannel_id);
extern struct subchannel *cio_get_console_subchannel(void);
extern spinlock_t * cio_get_console_lock(void);
extern void *cio_get_console_priv(void);
-extern const char *cio_get_console_sch_name(struct subchannel_id schid);
-extern const char *cio_get_console_cdev_name(struct subchannel *sch);
#else
#define cio_is_console(schid) 0
#define cio_get_console_subchannel() NULL
#define cio_get_console_lock() NULL
#define cio_get_console_priv() NULL
-#define cio_get_console_sch_name(schid) NULL
-#define cio_get_console_cdev_name(sch) NULL
#endif
#endif
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 85d43c6bcb66..e995123fd805 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -152,24 +152,15 @@ css_alloc_subchannel(struct subchannel_id schid)
}
static void
-css_free_subchannel(struct subchannel *sch)
-{
- if (sch) {
- /* Reset intparm to zeroes. */
- sch->config.intparm = 0;
- cio_commit_config(sch);
- kfree(sch->lock);
- kfree(sch);
- }
-}
-
-static void
css_subchannel_release(struct device *dev)
{
struct subchannel *sch;
sch = to_subchannel(dev);
if (!cio_is_console(sch->schid)) {
+ /* Reset intparm to zeroes. */
+ sch->config.intparm = 0;
+ cio_commit_config(sch);
kfree(sch->lock);
kfree(sch);
}
@@ -180,6 +171,8 @@ static int css_sch_device_register(struct subchannel *sch)
int ret;
mutex_lock(&sch->reg_mutex);
+ dev_set_name(&sch->dev, "0.%x.%04x", sch->schid.ssid,
+ sch->schid.sch_no);
ret = device_register(&sch->dev);
mutex_unlock(&sch->reg_mutex);
return ret;
@@ -327,7 +320,7 @@ int css_probe_device(struct subchannel_id schid)
return PTR_ERR(sch);
ret = css_register_subchannel(sch);
if (ret)
- css_free_subchannel(sch);
+ put_device(&sch->dev);
return ret;
}
@@ -644,7 +637,10 @@ __init_channel_subsystem(struct subchannel_id schid, void *data)
* not working) so we do it now. This is true e.g. for the
* console subchannel.
*/
- css_register_subchannel(sch);
+ if (css_register_subchannel(sch)) {
+ if (!cio_is_console(schid))
+ put_device(&sch->dev);
+ }
return 0;
}
@@ -661,8 +657,8 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high)
css->global_pgid.pgid_high.cpu_addr = 0;
#endif
}
- css->global_pgid.cpu_id = ((cpuid_t *) __LC_CPUID)->ident;
- css->global_pgid.cpu_model = ((cpuid_t *) __LC_CPUID)->machine;
+ css->global_pgid.cpu_id = S390_lowcore.cpu_id.ident;
+ css->global_pgid.cpu_model = S390_lowcore.cpu_id.machine;
css->global_pgid.tod_high = tod_high;
}
@@ -920,8 +916,10 @@ init_channel_subsystem (void)
goto out_device;
}
ret = device_register(&css->pseudo_subchannel->dev);
- if (ret)
+ if (ret) {
+ put_device(&css->pseudo_subchannel->dev);
goto out_file;
+ }
}
ret = register_reboot_notifier(&css_reboot_notifier);
if (ret)
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index d593bc76afe3..0f95405c2c5e 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -307,8 +307,11 @@ int ccw_device_is_orphan(struct ccw_device *cdev)
static void ccw_device_unregister(struct ccw_device *cdev)
{
- if (test_and_clear_bit(1, &cdev->private->registered))
+ if (test_and_clear_bit(1, &cdev->private->registered)) {
device_del(&cdev->dev);
+ /* Release reference from device_initialize(). */
+ put_device(&cdev->dev);
+ }
}
static void ccw_device_remove_orphan_cb(struct work_struct *work)
@@ -319,7 +322,6 @@ static void ccw_device_remove_orphan_cb(struct work_struct *work)
priv = container_of(work, struct ccw_device_private, kick_work);
cdev = priv->cdev;
ccw_device_unregister(cdev);
- put_device(&cdev->dev);
/* Release cdev reference for workqueue processing. */
put_device(&cdev->dev);
}
@@ -333,15 +335,15 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
* Forced offline in disconnected state means
* 'throw away device'.
*/
- /* Get cdev reference for workqueue processing. */
- if (!get_device(&cdev->dev))
- return;
if (ccw_device_is_orphan(cdev)) {
/*
* Deregister ccw device.
* Unfortunately, we cannot do this directly from the
* attribute method.
*/
+ /* Get cdev reference for workqueue processing. */
+ if (!get_device(&cdev->dev))
+ return;
spin_lock_irqsave(cdev->ccwlock, flags);
cdev->private->state = DEV_STATE_NOT_OPER;
spin_unlock_irqrestore(cdev->ccwlock, flags);
@@ -380,30 +382,34 @@ int ccw_device_set_offline(struct ccw_device *cdev)
}
cdev->online = 0;
spin_lock_irq(cdev->ccwlock);
- ret = ccw_device_offline(cdev);
- if (ret == -ENODEV) {
- if (cdev->private->state != DEV_STATE_NOT_OPER) {
- cdev->private->state = DEV_STATE_OFFLINE;
- dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
- }
+ /* Wait until a final state or DISCONNECTED is reached */
+ while (!dev_fsm_final_state(cdev) &&
+ cdev->private->state != DEV_STATE_DISCONNECTED) {
spin_unlock_irq(cdev->ccwlock);
- /* Give up reference from ccw_device_set_online(). */
- put_device(&cdev->dev);
- return ret;
+ wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) ||
+ cdev->private->state == DEV_STATE_DISCONNECTED));
+ spin_lock_irq(cdev->ccwlock);
}
+ ret = ccw_device_offline(cdev);
+ if (ret)
+ goto error;
spin_unlock_irq(cdev->ccwlock);
- if (ret == 0) {
- wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
- /* Give up reference from ccw_device_set_online(). */
- put_device(&cdev->dev);
- } else {
- CIO_MSG_EVENT(0, "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;
+ wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) ||
+ cdev->private->state == DEV_STATE_DISCONNECTED));
+ /* Give up reference from ccw_device_set_online(). */
+ put_device(&cdev->dev);
+ return 0;
+
+error:
+ CIO_MSG_EVENT(0, "ccw_device_offline returned %d, device 0.%x.%04x\n",
+ ret, cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
+ cdev->private->state = DEV_STATE_OFFLINE;
+ dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+ spin_unlock_irq(cdev->ccwlock);
+ /* Give up reference from ccw_device_set_online(). */
+ put_device(&cdev->dev);
+ return -ENODEV;
}
/**
@@ -421,6 +427,7 @@ int ccw_device_set_offline(struct ccw_device *cdev)
int ccw_device_set_online(struct ccw_device *cdev)
{
int ret;
+ int ret2;
if (!cdev)
return -ENODEV;
@@ -444,28 +451,53 @@ int ccw_device_set_online(struct ccw_device *cdev)
put_device(&cdev->dev);
return ret;
}
- if (cdev->private->state != DEV_STATE_ONLINE) {
+ spin_lock_irq(cdev->ccwlock);
+ /* Check if online processing was successful */
+ if ((cdev->private->state != DEV_STATE_ONLINE) &&
+ (cdev->private->state != DEV_STATE_W4SENSE)) {
+ spin_unlock_irq(cdev->ccwlock);
/* Give up online reference since onlining failed. */
put_device(&cdev->dev);
return -ENODEV;
}
- if (!cdev->drv->set_online || cdev->drv->set_online(cdev) == 0) {
- cdev->online = 1;
- return 0;
- }
+ spin_unlock_irq(cdev->ccwlock);
+ if (cdev->drv->set_online)
+ ret = cdev->drv->set_online(cdev);
+ if (ret)
+ goto rollback;
+ cdev->online = 1;
+ return 0;
+
+rollback:
spin_lock_irq(cdev->ccwlock);
- ret = ccw_device_offline(cdev);
+ /* Wait until a final state or DISCONNECTED is reached */
+ while (!dev_fsm_final_state(cdev) &&
+ cdev->private->state != DEV_STATE_DISCONNECTED) {
+ spin_unlock_irq(cdev->ccwlock);
+ wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) ||
+ cdev->private->state == DEV_STATE_DISCONNECTED));
+ spin_lock_irq(cdev->ccwlock);
+ }
+ ret2 = ccw_device_offline(cdev);
+ if (ret2)
+ goto error;
spin_unlock_irq(cdev->ccwlock);
- if (ret == 0)
- wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
- else
- CIO_MSG_EVENT(0, "ccw_device_offline returned %d, "
- "device 0.%x.%04x\n",
- ret, cdev->private->dev_id.ssid,
- cdev->private->dev_id.devno);
+ wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) ||
+ cdev->private->state == DEV_STATE_DISCONNECTED));
/* Give up online reference since onlining failed. */
put_device(&cdev->dev);
- return (ret == 0) ? -ENODEV : ret;
+ return ret;
+
+error:
+ CIO_MSG_EVENT(0, "rollback ccw_device_offline returned %d, "
+ "device 0.%x.%04x\n",
+ ret2, cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
+ cdev->private->state = DEV_STATE_OFFLINE;
+ spin_unlock_irq(cdev->ccwlock);
+ /* Give up online reference since onlining failed. */
+ put_device(&cdev->dev);
+ return ret;
}
static int online_store_handle_offline(struct ccw_device *cdev)
@@ -637,8 +669,12 @@ static int ccw_device_register(struct ccw_device *cdev)
int ret;
dev->bus = &ccw_bus_type;
-
- if ((ret = device_add(dev)))
+ ret = dev_set_name(&cdev->dev, "0.%x.%04x", cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
+ if (ret)
+ return ret;
+ ret = device_add(dev);
+ if (ret)
return ret;
set_bit(1, &cdev->private->registered);
@@ -1024,9 +1060,6 @@ static void ccw_device_call_sch_unregister(struct work_struct *work)
return;
sch = to_subchannel(cdev->dev.parent);
css_sch_device_unregister(sch);
- /* Reset intparm to zeroes. */
- sch->config.intparm = 0;
- cio_commit_config(sch);
/* Release cdev reference for workqueue processing.*/
put_device(&cdev->dev);
/* Release subchannel reference for local processing. */
@@ -1035,6 +1068,9 @@ static void ccw_device_call_sch_unregister(struct work_struct *work)
void ccw_device_schedule_sch_unregister(struct ccw_device *cdev)
{
+ /* Get cdev reference for workqueue processing. */
+ if (!get_device(&cdev->dev))
+ return;
PREPARE_WORK(&cdev->private->kick_work,
ccw_device_call_sch_unregister);
queue_work(slow_path_wq, &cdev->private->kick_work);
@@ -1055,9 +1091,6 @@ io_subchannel_recog_done(struct ccw_device *cdev)
/* Device did not respond in time. */
case DEV_STATE_NOT_OPER:
cdev->private->flags.recog_done = 1;
- /* Remove device found not operational. */
- if (!get_device(&cdev->dev))
- break;
ccw_device_schedule_sch_unregister(cdev);
if (atomic_dec_and_test(&ccw_device_init_count))
wake_up(&ccw_device_init_wq);
@@ -1095,13 +1128,6 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
init_waitqueue_head(&priv->wait_q);
init_timer(&priv->timer);
- /* Set an initial name for the device. */
- if (cio_is_console(sch->schid))
- cdev->dev.init_name = cio_get_console_cdev_name(sch);
- else
- dev_set_name(&cdev->dev, "0.%x.%04x",
- sch->schid.ssid, sch->schib.pmcw.dev);
-
/* Increase counter of devices currently in recognition. */
atomic_inc(&ccw_device_init_count);
@@ -1171,8 +1197,8 @@ static void io_subchannel_irq(struct subchannel *sch)
cdev = sch_get_cdev(sch);
- CIO_TRACE_EVENT(3, "IRQ");
- CIO_TRACE_EVENT(3, dev_name(&sch->dev));
+ CIO_TRACE_EVENT(6, "IRQ");
+ CIO_TRACE_EVENT(6, dev_name(&sch->dev));
if (cdev)
dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
}
@@ -1210,9 +1236,6 @@ static void io_subchannel_do_unreg(struct work_struct *work)
sch = container_of(work, struct subchannel, work);
css_sch_device_unregister(sch);
- /* Reset intparm to zeroes. */
- sch->config.intparm = 0;
- cio_commit_config(sch);
put_device(&sch->dev);
}
@@ -1334,7 +1357,6 @@ io_subchannel_remove (struct subchannel *sch)
cdev->private->state = DEV_STATE_NOT_OPER;
spin_unlock_irqrestore(cdev->ccwlock, flags);
ccw_device_unregister(cdev);
- put_device(&cdev->dev);
kfree(sch->private);
sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group);
return 0;
@@ -1571,8 +1593,6 @@ static int purge_fn(struct device *dev, void *data)
spin_unlock_irq(cdev->ccwlock);
if (!unreg)
goto out;
- if (!get_device(&cdev->dev))
- goto out;
CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", priv->dev_id.ssid,
priv->dev_id.devno);
ccw_device_schedule_sch_unregister(cdev);
@@ -1688,10 +1708,6 @@ static int io_subchannel_sch_event(struct subchannel *sch, int slow)
spin_unlock_irqrestore(sch->lock, flags);
css_sch_device_unregister(sch);
spin_lock_irqsave(sch->lock, flags);
-
- /* Reset intparm to zeroes. */
- sch->config.intparm = 0;
- cio_commit_config(sch);
break;
case REPROBE:
ccw_device_trigger_reprobe(cdev);
@@ -1712,7 +1728,6 @@ static int io_subchannel_sch_event(struct subchannel *sch, int slow)
#ifdef CONFIG_CCW_CONSOLE
static struct ccw_device console_cdev;
-static char console_cdev_name[10] = "0.x.xxxx";
static struct ccw_device_private console_private;
static int console_cdev_in_use;
@@ -1796,13 +1811,6 @@ int ccw_device_force_console(void)
return ccw_device_pm_restore(&console_cdev.dev);
}
EXPORT_SYMBOL_GPL(ccw_device_force_console);
-
-const char *cio_get_console_cdev_name(struct subchannel *sch)
-{
- snprintf(console_cdev_name, 10, "0.%x.%04x",
- sch->schid.ssid, sch->schib.pmcw.dev);
- return (const char *)console_cdev_name;
-}
#endif
/*
@@ -2020,7 +2028,9 @@ static void __ccw_device_pm_restore(struct ccw_device *cdev)
spin_unlock_irq(sch->lock);
if (ret) {
CIO_MSG_EVENT(0, "Couldn't start recognition for device "
- "%s (ret=%d)\n", dev_name(&cdev->dev), ret);
+ "0.%x.%04x (ret=%d)\n",
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno, ret);
spin_lock_irq(sch->lock);
cdev->private->state = DEV_STATE_DISCONNECTED;
spin_unlock_irq(sch->lock);
@@ -2083,8 +2093,9 @@ static int ccw_device_pm_restore(struct device *dev)
}
/* check if the device id has changed */
if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
- CIO_MSG_EVENT(0, "resume: sch %s: failed (devno changed from "
- "%04x to %04x)\n", dev_name(&sch->dev),
+ CIO_MSG_EVENT(0, "resume: sch 0.%x.%04x: failed (devno "
+ "changed from %04x to %04x)\n",
+ sch->schid.ssid, sch->schid.sch_no,
cdev->private->dev_id.devno,
sch->schib.pmcw.dev);
goto out_unreg_unlock;
@@ -2117,8 +2128,9 @@ static int ccw_device_pm_restore(struct device *dev)
if (cm_enabled) {
ret = ccw_set_cmf(cdev, 1);
if (ret) {
- CIO_MSG_EVENT(2, "resume: cdev %s: cmf failed "
- "(rc=%d)\n", dev_name(&cdev->dev), ret);
+ CIO_MSG_EVENT(2, "resume: cdev 0.%x.%04x: cmf failed "
+ "(rc=%d)\n", cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno, ret);
ret = 0;
}
}
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 3db88c52d287..e728ce447f6e 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -394,6 +394,13 @@ ccw_device_done(struct ccw_device *cdev, int state)
ccw_device_schedule_sch_unregister(cdev);
cdev->private->flags.donotify = 0;
}
+ if (state == DEV_STATE_NOT_OPER) {
+ CIO_MSG_EVENT(0, "Device %04x gone on subchannel %04x\n",
+ cdev->private->dev_id.devno, sch->schid.sch_no);
+ if (!ccw_device_notify(cdev, CIO_GONE))
+ ccw_device_schedule_sch_unregister(cdev);
+ cdev->private->flags.donotify = 0;
+ }
if (cdev->private->flags.donotify) {
cdev->private->flags.donotify = 0;
@@ -731,6 +738,17 @@ static void ccw_device_generic_notoper(struct ccw_device *cdev,
}
/*
+ * Handle path verification event in offline state.
+ */
+static void ccw_device_offline_verify(struct ccw_device *cdev,
+ enum dev_event dev_event)
+{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+
+ css_schedule_eval(sch->schid);
+}
+
+/*
* Handle path verification event.
*/
static void
@@ -887,6 +905,8 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
}
call_handler:
cdev->private->state = DEV_STATE_ONLINE;
+ /* In case sensing interfered with setting the device online */
+ wake_up(&cdev->private->wait_q);
/* Call the handler. */
if (ccw_device_call_handler(cdev) && cdev->private->flags.doverify)
/* Start delayed path verification. */
@@ -1149,7 +1169,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_offline_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_nop,
- [DEV_EVENT_VERIFY] = ccw_device_nop,
+ [DEV_EVENT_VERIFY] = ccw_device_offline_verify,
},
[DEV_STATE_VERIFY] = {
[DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index b1241f8fae88..ff7748a9199d 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -1,7 +1,7 @@
/*
* linux/drivers/s390/cio/qdio.h
*
- * Copyright 2000,2008 IBM Corp.
+ * Copyright 2000,2009 IBM Corp.
* Author(s): Utz Bacher <utz.bacher@de.ibm.com>
* Jan Glauber <jang@linux.vnet.ibm.com>
*/
@@ -246,6 +246,7 @@ struct qdio_q {
atomic_t nr_buf_used;
struct qdio_irq *irq_ptr;
+ struct dentry *debugfs_q;
struct tasklet_struct tasklet;
/* error condition during a data transfer */
@@ -267,6 +268,7 @@ struct qdio_irq {
struct qib qib;
u32 *dsci; /* address of device state change indicator */
struct ccw_device *cdev;
+ struct dentry *debugfs_dev;
unsigned long int_parm;
struct subchannel_id schid;
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c
index b8626d4df116..1b78f639ead3 100644
--- a/drivers/s390/cio/qdio_debug.c
+++ b/drivers/s390/cio/qdio_debug.c
@@ -1,14 +1,12 @@
/*
* drivers/s390/cio/qdio_debug.c
*
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2009
*
* Author: Jan Glauber (jang@linux.vnet.ibm.com)
*/
-#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
-#include <asm/qdio.h>
#include <asm/debug.h>
#include "qdio_debug.h"
#include "qdio.h"
@@ -17,10 +15,7 @@ debug_info_t *qdio_dbf_setup;
debug_info_t *qdio_dbf_error;
static struct dentry *debugfs_root;
-#define MAX_DEBUGFS_QUEUES 32
-static struct dentry *debugfs_queues[MAX_DEBUGFS_QUEUES] = { NULL };
-static DEFINE_MUTEX(debugfs_mutex);
-#define QDIO_DEBUGFS_NAME_LEN 40
+#define QDIO_DEBUGFS_NAME_LEN 10
void qdio_allocate_dbf(struct qdio_initialize *init_data,
struct qdio_irq *irq_ptr)
@@ -130,20 +125,6 @@ static int qstat_seq_open(struct inode *inode, struct file *filp)
filp->f_path.dentry->d_inode->i_private);
}
-static void remove_debugfs_entry(struct qdio_q *q)
-{
- int i;
-
- for (i = 0; i < MAX_DEBUGFS_QUEUES; i++) {
- if (!debugfs_queues[i])
- continue;
- if (debugfs_queues[i]->d_inode->i_private == q) {
- debugfs_remove(debugfs_queues[i]);
- debugfs_queues[i] = NULL;
- }
- }
-}
-
static struct file_operations debugfs_fops = {
.owner = THIS_MODULE,
.open = qstat_seq_open,
@@ -155,22 +136,15 @@ static struct file_operations debugfs_fops = {
static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
{
- int i = 0;
char name[QDIO_DEBUGFS_NAME_LEN];
- while (debugfs_queues[i] != NULL) {
- i++;
- if (i >= MAX_DEBUGFS_QUEUES)
- return;
- }
- snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%s_%d",
- dev_name(&cdev->dev),
+ snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
q->is_input_q ? "input" : "output",
q->nr);
- debugfs_queues[i] = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
- debugfs_root, q, &debugfs_fops);
- if (IS_ERR(debugfs_queues[i]))
- debugfs_queues[i] = NULL;
+ q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
+ q->irq_ptr->debugfs_dev, q, &debugfs_fops);
+ if (IS_ERR(q->debugfs_q))
+ q->debugfs_q = NULL;
}
void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
@@ -178,12 +152,14 @@ void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
struct qdio_q *q;
int i;
- mutex_lock(&debugfs_mutex);
+ irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
+ debugfs_root);
+ if (IS_ERR(irq_ptr->debugfs_dev))
+ irq_ptr->debugfs_dev = NULL;
for_each_input_queue(irq_ptr, q, i)
setup_debugfs_entry(q, cdev);
for_each_output_queue(irq_ptr, q, i)
setup_debugfs_entry(q, cdev);
- mutex_unlock(&debugfs_mutex);
}
void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
@@ -191,17 +167,16 @@ void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cd
struct qdio_q *q;
int i;
- mutex_lock(&debugfs_mutex);
for_each_input_queue(irq_ptr, q, i)
- remove_debugfs_entry(q);
+ debugfs_remove(q->debugfs_q);
for_each_output_queue(irq_ptr, q, i)
- remove_debugfs_entry(q);
- mutex_unlock(&debugfs_mutex);
+ debugfs_remove(q->debugfs_q);
+ debugfs_remove(irq_ptr->debugfs_dev);
}
int __init qdio_debug_init(void)
{
- debugfs_root = debugfs_create_dir("qdio_queues", NULL);
+ debugfs_root = debugfs_create_dir("qdio", NULL);
qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 0038750ad945..9aef402a5f1b 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -798,8 +798,10 @@ static void __tiqdio_inbound_processing(struct qdio_q *q)
if (!qdio_inbound_q_done(q)) {
qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop);
- if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED))
+ if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) {
tasklet_schedule(&q->tasklet);
+ return;
+ }
}
qdio_stop_polling(q);
diff --git a/drivers/s390/cio/scsw.c b/drivers/s390/cio/scsw.c
deleted file mode 100644
index f8da25ab576d..000000000000
--- a/drivers/s390/cio/scsw.c
+++ /dev/null
@@ -1,843 +0,0 @@
-/*
- * Helper functions for scsw access.
- *
- * Copyright IBM Corp. 2008
- * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <asm/cio.h>
-#include "css.h"
-#include "chsc.h"
-
-/**
- * scsw_is_tm - check for transport mode scsw
- * @scsw: pointer to scsw
- *
- * Return non-zero if the specified scsw is a transport mode scsw, zero
- * otherwise.
- */
-int scsw_is_tm(union scsw *scsw)
-{
- return css_general_characteristics.fcx && (scsw->tm.x == 1);
-}
-EXPORT_SYMBOL(scsw_is_tm);
-
-/**
- * scsw_key - return scsw key field
- * @scsw: pointer to scsw
- *
- * Return the value of the key field of the specified scsw, regardless of
- * whether it is a transport mode or command mode scsw.
- */
-u32 scsw_key(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw->tm.key;
- else
- return scsw->cmd.key;
-}
-EXPORT_SYMBOL(scsw_key);
-
-/**
- * scsw_eswf - return scsw eswf field
- * @scsw: pointer to scsw
- *
- * Return the value of the eswf field of the specified scsw, regardless of
- * whether it is a transport mode or command mode scsw.
- */
-u32 scsw_eswf(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw->tm.eswf;
- else
- return scsw->cmd.eswf;
-}
-EXPORT_SYMBOL(scsw_eswf);
-
-/**
- * scsw_cc - return scsw cc field
- * @scsw: pointer to scsw
- *
- * Return the value of the cc field of the specified scsw, regardless of
- * whether it is a transport mode or command mode scsw.
- */
-u32 scsw_cc(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw->tm.cc;
- else
- return scsw->cmd.cc;
-}
-EXPORT_SYMBOL(scsw_cc);
-
-/**
- * scsw_ectl - return scsw ectl field
- * @scsw: pointer to scsw
- *
- * Return the value of the ectl field of the specified scsw, regardless of
- * whether it is a transport mode or command mode scsw.
- */
-u32 scsw_ectl(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw->tm.ectl;
- else
- return scsw->cmd.ectl;
-}
-EXPORT_SYMBOL(scsw_ectl);
-
-/**
- * scsw_pno - return scsw pno field
- * @scsw: pointer to scsw
- *
- * Return the value of the pno field of the specified scsw, regardless of
- * whether it is a transport mode or command mode scsw.
- */
-u32 scsw_pno(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw->tm.pno;
- else
- return scsw->cmd.pno;
-}
-EXPORT_SYMBOL(scsw_pno);
-
-/**
- * scsw_fctl - return scsw fctl field
- * @scsw: pointer to scsw
- *
- * Return the value of the fctl field of the specified scsw, regardless of
- * whether it is a transport mode or command mode scsw.
- */
-u32 scsw_fctl(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw->tm.fctl;
- else
- return scsw->cmd.fctl;
-}
-EXPORT_SYMBOL(scsw_fctl);
-
-/**
- * scsw_actl - return scsw actl field
- * @scsw: pointer to scsw
- *
- * Return the value of the actl field of the specified scsw, regardless of
- * whether it is a transport mode or command mode scsw.
- */
-u32 scsw_actl(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw->tm.actl;
- else
- return scsw->cmd.actl;
-}
-EXPORT_SYMBOL(scsw_actl);
-
-/**
- * scsw_stctl - return scsw stctl field
- * @scsw: pointer to scsw
- *
- * Return the value of the stctl field of the specified scsw, regardless of
- * whether it is a transport mode or command mode scsw.
- */
-u32 scsw_stctl(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw->tm.stctl;
- else
- return scsw->cmd.stctl;
-}
-EXPORT_SYMBOL(scsw_stctl);
-
-/**
- * scsw_dstat - return scsw dstat field
- * @scsw: pointer to scsw
- *
- * Return the value of the dstat field of the specified scsw, regardless of
- * whether it is a transport mode or command mode scsw.
- */
-u32 scsw_dstat(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw->tm.dstat;
- else
- return scsw->cmd.dstat;
-}
-EXPORT_SYMBOL(scsw_dstat);
-
-/**
- * scsw_cstat - return scsw cstat field
- * @scsw: pointer to scsw
- *
- * Return the value of the cstat field of the specified scsw, regardless of
- * whether it is a transport mode or command mode scsw.
- */
-u32 scsw_cstat(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw->tm.cstat;
- else
- return scsw->cmd.cstat;
-}
-EXPORT_SYMBOL(scsw_cstat);
-
-/**
- * scsw_cmd_is_valid_key - check key field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the key field of the specified command mode scsw is
- * valid, zero otherwise.
- */
-int scsw_cmd_is_valid_key(union scsw *scsw)
-{
- return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
-}
-EXPORT_SYMBOL(scsw_cmd_is_valid_key);
-
-/**
- * scsw_cmd_is_valid_sctl - check fctl field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the fctl field of the specified command mode scsw is
- * valid, zero otherwise.
- */
-int scsw_cmd_is_valid_sctl(union scsw *scsw)
-{
- return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
-}
-EXPORT_SYMBOL(scsw_cmd_is_valid_sctl);
-
-/**
- * scsw_cmd_is_valid_eswf - check eswf field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the eswf field of the specified command mode scsw is
- * valid, zero otherwise.
- */
-int scsw_cmd_is_valid_eswf(union scsw *scsw)
-{
- return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND);
-}
-EXPORT_SYMBOL(scsw_cmd_is_valid_eswf);
-
-/**
- * scsw_cmd_is_valid_cc - check cc field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the cc field of the specified command mode scsw is
- * valid, zero otherwise.
- */
-int scsw_cmd_is_valid_cc(union scsw *scsw)
-{
- return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) &&
- (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND);
-}
-EXPORT_SYMBOL(scsw_cmd_is_valid_cc);
-
-/**
- * scsw_cmd_is_valid_fmt - check fmt field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the fmt field of the specified command mode scsw is
- * valid, zero otherwise.
- */
-int scsw_cmd_is_valid_fmt(union scsw *scsw)
-{
- return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
-}
-EXPORT_SYMBOL(scsw_cmd_is_valid_fmt);
-
-/**
- * scsw_cmd_is_valid_pfch - check pfch field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the pfch field of the specified command mode scsw is
- * valid, zero otherwise.
- */
-int scsw_cmd_is_valid_pfch(union scsw *scsw)
-{
- return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
-}
-EXPORT_SYMBOL(scsw_cmd_is_valid_pfch);
-
-/**
- * scsw_cmd_is_valid_isic - check isic field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the isic field of the specified command mode scsw is
- * valid, zero otherwise.
- */
-int scsw_cmd_is_valid_isic(union scsw *scsw)
-{
- return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
-}
-EXPORT_SYMBOL(scsw_cmd_is_valid_isic);
-
-/**
- * scsw_cmd_is_valid_alcc - check alcc field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the alcc field of the specified command mode scsw is
- * valid, zero otherwise.
- */
-int scsw_cmd_is_valid_alcc(union scsw *scsw)
-{
- return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
-}
-EXPORT_SYMBOL(scsw_cmd_is_valid_alcc);
-
-/**
- * scsw_cmd_is_valid_ssi - check ssi field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the ssi field of the specified command mode scsw is
- * valid, zero otherwise.
- */
-int scsw_cmd_is_valid_ssi(union scsw *scsw)
-{
- return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
-}
-EXPORT_SYMBOL(scsw_cmd_is_valid_ssi);
-
-/**
- * scsw_cmd_is_valid_zcc - check zcc field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the zcc field of the specified command mode scsw is
- * valid, zero otherwise.
- */
-int scsw_cmd_is_valid_zcc(union scsw *scsw)
-{
- return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) &&
- (scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS);
-}
-EXPORT_SYMBOL(scsw_cmd_is_valid_zcc);
-
-/**
- * scsw_cmd_is_valid_ectl - check ectl field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the ectl field of the specified command mode scsw is
- * valid, zero otherwise.
- */
-int scsw_cmd_is_valid_ectl(union scsw *scsw)
-{
- return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) &&
- !(scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) &&
- (scsw->cmd.stctl & SCSW_STCTL_ALERT_STATUS);
-}
-EXPORT_SYMBOL(scsw_cmd_is_valid_ectl);
-
-/**
- * scsw_cmd_is_valid_pno - check pno field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the pno field of the specified command mode scsw is
- * valid, zero otherwise.
- */
-int scsw_cmd_is_valid_pno(union scsw *scsw)
-{
- return (scsw->cmd.fctl != 0) &&
- (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) &&
- (!(scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) ||
- ((scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) &&
- (scsw->cmd.actl & SCSW_ACTL_SUSPENDED)));
-}
-EXPORT_SYMBOL(scsw_cmd_is_valid_pno);
-
-/**
- * scsw_cmd_is_valid_fctl - check fctl field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the fctl field of the specified command mode scsw is
- * valid, zero otherwise.
- */
-int scsw_cmd_is_valid_fctl(union scsw *scsw)
-{
- /* Only valid if pmcw.dnv == 1*/
- return 1;
-}
-EXPORT_SYMBOL(scsw_cmd_is_valid_fctl);
-
-/**
- * scsw_cmd_is_valid_actl - check actl field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the actl field of the specified command mode scsw is
- * valid, zero otherwise.
- */
-int scsw_cmd_is_valid_actl(union scsw *scsw)
-{
- /* Only valid if pmcw.dnv == 1*/
- return 1;
-}
-EXPORT_SYMBOL(scsw_cmd_is_valid_actl);
-
-/**
- * scsw_cmd_is_valid_stctl - check stctl field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the stctl field of the specified command mode scsw is
- * valid, zero otherwise.
- */
-int scsw_cmd_is_valid_stctl(union scsw *scsw)
-{
- /* Only valid if pmcw.dnv == 1*/
- return 1;
-}
-EXPORT_SYMBOL(scsw_cmd_is_valid_stctl);
-
-/**
- * scsw_cmd_is_valid_dstat - check dstat field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the dstat field of the specified command mode scsw is
- * valid, zero otherwise.
- */
-int scsw_cmd_is_valid_dstat(union scsw *scsw)
-{
- return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) &&
- (scsw->cmd.cc != 3);
-}
-EXPORT_SYMBOL(scsw_cmd_is_valid_dstat);
-
-/**
- * scsw_cmd_is_valid_cstat - check cstat field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the cstat field of the specified command mode scsw is
- * valid, zero otherwise.
- */
-int scsw_cmd_is_valid_cstat(union scsw *scsw)
-{
- return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) &&
- (scsw->cmd.cc != 3);
-}
-EXPORT_SYMBOL(scsw_cmd_is_valid_cstat);
-
-/**
- * scsw_tm_is_valid_key - check key field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the key field of the specified transport mode scsw is
- * valid, zero otherwise.
- */
-int scsw_tm_is_valid_key(union scsw *scsw)
-{
- return (scsw->tm.fctl & SCSW_FCTL_START_FUNC);
-}
-EXPORT_SYMBOL(scsw_tm_is_valid_key);
-
-/**
- * scsw_tm_is_valid_eswf - check eswf field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the eswf field of the specified transport mode scsw is
- * valid, zero otherwise.
- */
-int scsw_tm_is_valid_eswf(union scsw *scsw)
-{
- return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND);
-}
-EXPORT_SYMBOL(scsw_tm_is_valid_eswf);
-
-/**
- * scsw_tm_is_valid_cc - check cc field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the cc field of the specified transport mode scsw is
- * valid, zero otherwise.
- */
-int scsw_tm_is_valid_cc(union scsw *scsw)
-{
- return (scsw->tm.fctl & SCSW_FCTL_START_FUNC) &&
- (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND);
-}
-EXPORT_SYMBOL(scsw_tm_is_valid_cc);
-
-/**
- * scsw_tm_is_valid_fmt - check fmt field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the fmt field of the specified transport mode scsw is
- * valid, zero otherwise.
- */
-int scsw_tm_is_valid_fmt(union scsw *scsw)
-{
- return 1;
-}
-EXPORT_SYMBOL(scsw_tm_is_valid_fmt);
-
-/**
- * scsw_tm_is_valid_x - check x field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the x field of the specified transport mode scsw is
- * valid, zero otherwise.
- */
-int scsw_tm_is_valid_x(union scsw *scsw)
-{
- return 1;
-}
-EXPORT_SYMBOL(scsw_tm_is_valid_x);
-
-/**
- * scsw_tm_is_valid_q - check q field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the q field of the specified transport mode scsw is
- * valid, zero otherwise.
- */
-int scsw_tm_is_valid_q(union scsw *scsw)
-{
- return 1;
-}
-EXPORT_SYMBOL(scsw_tm_is_valid_q);
-
-/**
- * scsw_tm_is_valid_ectl - check ectl field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the ectl field of the specified transport mode scsw is
- * valid, zero otherwise.
- */
-int scsw_tm_is_valid_ectl(union scsw *scsw)
-{
- return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) &&
- !(scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) &&
- (scsw->tm.stctl & SCSW_STCTL_ALERT_STATUS);
-}
-EXPORT_SYMBOL(scsw_tm_is_valid_ectl);
-
-/**
- * scsw_tm_is_valid_pno - check pno field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the pno field of the specified transport mode scsw is
- * valid, zero otherwise.
- */
-int scsw_tm_is_valid_pno(union scsw *scsw)
-{
- return (scsw->tm.fctl != 0) &&
- (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) &&
- (!(scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) ||
- ((scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) &&
- (scsw->tm.actl & SCSW_ACTL_SUSPENDED)));
-}
-EXPORT_SYMBOL(scsw_tm_is_valid_pno);
-
-/**
- * scsw_tm_is_valid_fctl - check fctl field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the fctl field of the specified transport mode scsw is
- * valid, zero otherwise.
- */
-int scsw_tm_is_valid_fctl(union scsw *scsw)
-{
- /* Only valid if pmcw.dnv == 1*/
- return 1;
-}
-EXPORT_SYMBOL(scsw_tm_is_valid_fctl);
-
-/**
- * scsw_tm_is_valid_actl - check actl field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the actl field of the specified transport mode scsw is
- * valid, zero otherwise.
- */
-int scsw_tm_is_valid_actl(union scsw *scsw)
-{
- /* Only valid if pmcw.dnv == 1*/
- return 1;
-}
-EXPORT_SYMBOL(scsw_tm_is_valid_actl);
-
-/**
- * scsw_tm_is_valid_stctl - check stctl field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the stctl field of the specified transport mode scsw is
- * valid, zero otherwise.
- */
-int scsw_tm_is_valid_stctl(union scsw *scsw)
-{
- /* Only valid if pmcw.dnv == 1*/
- return 1;
-}
-EXPORT_SYMBOL(scsw_tm_is_valid_stctl);
-
-/**
- * scsw_tm_is_valid_dstat - check dstat field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the dstat field of the specified transport mode scsw is
- * valid, zero otherwise.
- */
-int scsw_tm_is_valid_dstat(union scsw *scsw)
-{
- return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) &&
- (scsw->tm.cc != 3);
-}
-EXPORT_SYMBOL(scsw_tm_is_valid_dstat);
-
-/**
- * scsw_tm_is_valid_cstat - check cstat field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the cstat field of the specified transport mode scsw is
- * valid, zero otherwise.
- */
-int scsw_tm_is_valid_cstat(union scsw *scsw)
-{
- return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) &&
- (scsw->tm.cc != 3);
-}
-EXPORT_SYMBOL(scsw_tm_is_valid_cstat);
-
-/**
- * scsw_tm_is_valid_fcxs - check fcxs field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the fcxs field of the specified transport mode scsw is
- * valid, zero otherwise.
- */
-int scsw_tm_is_valid_fcxs(union scsw *scsw)
-{
- return 1;
-}
-EXPORT_SYMBOL(scsw_tm_is_valid_fcxs);
-
-/**
- * scsw_tm_is_valid_schxs - check schxs field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the schxs field of the specified transport mode scsw is
- * valid, zero otherwise.
- */
-int scsw_tm_is_valid_schxs(union scsw *scsw)
-{
- return (scsw->tm.cstat & (SCHN_STAT_PROG_CHECK |
- SCHN_STAT_INTF_CTRL_CHK |
- SCHN_STAT_PROT_CHECK |
- SCHN_STAT_CHN_DATA_CHK));
-}
-EXPORT_SYMBOL(scsw_tm_is_valid_schxs);
-
-/**
- * scsw_is_valid_actl - check actl field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the actl field of the specified scsw is valid,
- * regardless of whether it is a transport mode or command mode scsw.
- * Return zero if the field does not contain a valid value.
- */
-int scsw_is_valid_actl(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw_tm_is_valid_actl(scsw);
- else
- return scsw_cmd_is_valid_actl(scsw);
-}
-EXPORT_SYMBOL(scsw_is_valid_actl);
-
-/**
- * scsw_is_valid_cc - check cc field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the cc field of the specified scsw is valid,
- * regardless of whether it is a transport mode or command mode scsw.
- * Return zero if the field does not contain a valid value.
- */
-int scsw_is_valid_cc(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw_tm_is_valid_cc(scsw);
- else
- return scsw_cmd_is_valid_cc(scsw);
-}
-EXPORT_SYMBOL(scsw_is_valid_cc);
-
-/**
- * scsw_is_valid_cstat - check cstat field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the cstat field of the specified scsw is valid,
- * regardless of whether it is a transport mode or command mode scsw.
- * Return zero if the field does not contain a valid value.
- */
-int scsw_is_valid_cstat(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw_tm_is_valid_cstat(scsw);
- else
- return scsw_cmd_is_valid_cstat(scsw);
-}
-EXPORT_SYMBOL(scsw_is_valid_cstat);
-
-/**
- * scsw_is_valid_dstat - check dstat field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the dstat field of the specified scsw is valid,
- * regardless of whether it is a transport mode or command mode scsw.
- * Return zero if the field does not contain a valid value.
- */
-int scsw_is_valid_dstat(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw_tm_is_valid_dstat(scsw);
- else
- return scsw_cmd_is_valid_dstat(scsw);
-}
-EXPORT_SYMBOL(scsw_is_valid_dstat);
-
-/**
- * scsw_is_valid_ectl - check ectl field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the ectl field of the specified scsw is valid,
- * regardless of whether it is a transport mode or command mode scsw.
- * Return zero if the field does not contain a valid value.
- */
-int scsw_is_valid_ectl(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw_tm_is_valid_ectl(scsw);
- else
- return scsw_cmd_is_valid_ectl(scsw);
-}
-EXPORT_SYMBOL(scsw_is_valid_ectl);
-
-/**
- * scsw_is_valid_eswf - check eswf field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the eswf field of the specified scsw is valid,
- * regardless of whether it is a transport mode or command mode scsw.
- * Return zero if the field does not contain a valid value.
- */
-int scsw_is_valid_eswf(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw_tm_is_valid_eswf(scsw);
- else
- return scsw_cmd_is_valid_eswf(scsw);
-}
-EXPORT_SYMBOL(scsw_is_valid_eswf);
-
-/**
- * scsw_is_valid_fctl - check fctl field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the fctl field of the specified scsw is valid,
- * regardless of whether it is a transport mode or command mode scsw.
- * Return zero if the field does not contain a valid value.
- */
-int scsw_is_valid_fctl(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw_tm_is_valid_fctl(scsw);
- else
- return scsw_cmd_is_valid_fctl(scsw);
-}
-EXPORT_SYMBOL(scsw_is_valid_fctl);
-
-/**
- * scsw_is_valid_key - check key field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the key field of the specified scsw is valid,
- * regardless of whether it is a transport mode or command mode scsw.
- * Return zero if the field does not contain a valid value.
- */
-int scsw_is_valid_key(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw_tm_is_valid_key(scsw);
- else
- return scsw_cmd_is_valid_key(scsw);
-}
-EXPORT_SYMBOL(scsw_is_valid_key);
-
-/**
- * scsw_is_valid_pno - check pno field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the pno field of the specified scsw is valid,
- * regardless of whether it is a transport mode or command mode scsw.
- * Return zero if the field does not contain a valid value.
- */
-int scsw_is_valid_pno(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw_tm_is_valid_pno(scsw);
- else
- return scsw_cmd_is_valid_pno(scsw);
-}
-EXPORT_SYMBOL(scsw_is_valid_pno);
-
-/**
- * scsw_is_valid_stctl - check stctl field validity
- * @scsw: pointer to scsw
- *
- * Return non-zero if the stctl field of the specified scsw is valid,
- * regardless of whether it is a transport mode or command mode scsw.
- * Return zero if the field does not contain a valid value.
- */
-int scsw_is_valid_stctl(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw_tm_is_valid_stctl(scsw);
- else
- return scsw_cmd_is_valid_stctl(scsw);
-}
-EXPORT_SYMBOL(scsw_is_valid_stctl);
-
-/**
- * scsw_cmd_is_solicited - check for solicited scsw
- * @scsw: pointer to scsw
- *
- * Return non-zero if the command mode scsw indicates that the associated
- * status condition is solicited, zero if it is unsolicited.
- */
-int scsw_cmd_is_solicited(union scsw *scsw)
-{
- return (scsw->cmd.cc != 0) || (scsw->cmd.stctl !=
- (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS));
-}
-EXPORT_SYMBOL(scsw_cmd_is_solicited);
-
-/**
- * scsw_tm_is_solicited - check for solicited scsw
- * @scsw: pointer to scsw
- *
- * Return non-zero if the transport mode scsw indicates that the associated
- * status condition is solicited, zero if it is unsolicited.
- */
-int scsw_tm_is_solicited(union scsw *scsw)
-{
- return (scsw->tm.cc != 0) || (scsw->tm.stctl !=
- (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS));
-}
-EXPORT_SYMBOL(scsw_tm_is_solicited);
-
-/**
- * scsw_is_solicited - check for solicited scsw
- * @scsw: pointer to scsw
- *
- * Return non-zero if the transport or command mode scsw indicates that the
- * associated status condition is solicited, zero if it is unsolicited.
- */
-int scsw_is_solicited(union scsw *scsw)
-{
- if (scsw_is_tm(scsw))
- return scsw_tm_is_solicited(scsw);
- else
- return scsw_cmd_is_solicited(scsw);
-}
-EXPORT_SYMBOL(scsw_is_solicited);