Commit 03cd7b46 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: common i/o layer.

 - Remove initialization of device.name.
 - Don't do put_device after failed get_device in get_ccwdev_by_busid.
 - Fix read_dev_chars and read_conf_data.
 - Call interrupt function of ccw device if path verification has been started.
 - Replace atomic_return_add by atomic_add_return in qdio.
 - Use wait_event instead of homegrown wait loop.
 - Fix reestablish queue problem.
 - Add ungroup attribute to ccw_group devices and add links from each
   ccw device of a group to the group device.
 - Use BUS_ID_SIZE instead of DEVICE_ID_SIZE.
 - Delay path verification if a basic sense is required.
 - Move qdio shutdown code from qdio_free to qdio_shutdown.
parent 7d853ae3
/* /*
* drivers/s390/cio/ccwgroup.c * drivers/s390/cio/ccwgroup.c
* bus driver for ccwgroup * bus driver for ccwgroup
* $Revision: 1.7 $ * $Revision: 1.15 $
* *
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
* Author(s): Arnd Bergmann (arndb@de.ibm.com) * Author(s): Arnd Bergmann (arndb@de.ibm.com)
* Cornelia Huck (cohuck@de.ibm.com)
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -14,6 +15,7 @@ ...@@ -14,6 +15,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/dcache.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include <asm/ccwdev.h> #include <asm/ccwdev.h>
...@@ -56,6 +58,45 @@ static struct bus_type ccwgroup_bus_type = { ...@@ -56,6 +58,45 @@ static struct bus_type ccwgroup_bus_type = {
.hotplug = ccwgroup_hotplug, .hotplug = ccwgroup_hotplug,
}; };
static inline void
__ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
{
int i;
char str[8];
for (i = 0; i < gdev->count; i++) {
sprintf(str, "cdev%d", i);
sysfs_remove_link(&gdev->dev.kobj, str);
/* Hack: Make sure we act on still valid subdirs. */
if (atomic_read(&gdev->cdev[i]->dev.kobj.dentry->d_count))
sysfs_remove_link(&gdev->cdev[i]->dev.kobj,
"group_device");
}
}
/*
* Provide an 'ungroup' attribute so the user can remove group devices no
* longer needed or accidentially created. Saves memory :)
*/
static ssize_t
ccwgroup_ungroup_store(struct device *dev, const char *buf, size_t count)
{
struct ccwgroup_device *gdev;
gdev = to_ccwgroupdev(dev);
if (gdev->state != CCWGROUP_OFFLINE)
return -EINVAL;
__ccwgroup_remove_symlinks(gdev);
device_unregister(dev);
return count;
}
static DEVICE_ATTR(ungroup, 0200, NULL, ccwgroup_ungroup_store);
static void static void
ccwgroup_release (struct device *dev) ccwgroup_release (struct device *dev)
{ {
...@@ -69,6 +110,40 @@ ccwgroup_release (struct device *dev) ...@@ -69,6 +110,40 @@ ccwgroup_release (struct device *dev)
kfree(gdev); kfree(gdev);
} }
static inline int
__ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
{
char str[8];
int i, rc;
for (i = 0; i < gdev->count; i++) {
rc = sysfs_create_link(&gdev->cdev[i]->dev.kobj, &gdev->dev.kobj,
"group_device");
if (rc) {
for (--i; i >= 0; i--)
sysfs_remove_link(&gdev->cdev[i]->dev.kobj,
"group_device");
return rc;
}
}
for (i = 0; i < gdev->count; i++) {
sprintf(str, "cdev%d", i);
rc = sysfs_create_link(&gdev->dev.kobj, &gdev->cdev[i]->dev.kobj,
str);
if (rc) {
for (--i; i >= 0; i--) {
sprintf(str, "cdev%d", i);
sysfs_remove_link(&gdev->dev.kobj, str);
}
for (i = 0; i < gdev->count; i++)
sysfs_remove_link(&gdev->cdev[i]->dev.kobj,
"group_device");
return rc;
}
}
return 0;
}
/* /*
* try to add a new ccwgroup device for one driver * try to add a new ccwgroup device for one driver
* argc and argv[] are a list of bus_id's of devices * argc and argv[] are a list of bus_id's of devices
...@@ -82,6 +157,7 @@ ccwgroup_create(struct device *root, ...@@ -82,6 +157,7 @@ ccwgroup_create(struct device *root,
{ {
struct ccwgroup_device *gdev; struct ccwgroup_device *gdev;
int i; int i;
int rc;
if (argc > 256) /* disallow dumb users */ if (argc > 256) /* disallow dumb users */
return -EINVAL; return -EINVAL;
...@@ -90,6 +166,8 @@ ccwgroup_create(struct device *root, ...@@ -90,6 +166,8 @@ ccwgroup_create(struct device *root,
if (!gdev) if (!gdev)
return -ENOMEM; return -ENOMEM;
memset(gdev, 0, sizeof(*gdev) + argc*sizeof(gdev->cdev[0]));
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]); gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]);
...@@ -97,8 +175,10 @@ ccwgroup_create(struct device *root, ...@@ -97,8 +175,10 @@ ccwgroup_create(struct device *root,
* order to be grouped */ * order to be grouped */
if (!gdev->cdev[i] if (!gdev->cdev[i]
|| gdev->cdev[i]->id.driver_info != || gdev->cdev[i]->id.driver_info !=
gdev->cdev[0]->id.driver_info) gdev->cdev[0]->id.driver_info) {
rc = -EINVAL;
goto error; goto error;
}
} }
*gdev = (struct ccwgroup_device) { *gdev = (struct ccwgroup_device) {
...@@ -114,9 +194,24 @@ ccwgroup_create(struct device *root, ...@@ -114,9 +194,24 @@ ccwgroup_create(struct device *root,
snprintf (gdev->dev.bus_id, BUS_ID_SIZE, "%s", snprintf (gdev->dev.bus_id, BUS_ID_SIZE, "%s",
gdev->cdev[0]->dev.bus_id); gdev->cdev[0]->dev.bus_id);
/* TODO: make symlinks for sysfs */ rc = device_register(&gdev->dev);
return device_register(&gdev->dev);
if (rc)
goto error;
rc = device_create_file(&gdev->dev, &dev_attr_ungroup);
if (rc) {
device_unregister(&gdev->dev);
goto error;
}
rc = __ccwgroup_create_symlinks(gdev);
if (!rc)
return 0;
device_remove_file(&gdev->dev, &dev_attr_ungroup);
device_unregister(&gdev->dev);
error: error:
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
if (gdev->cdev[i]) if (gdev->cdev[i])
...@@ -124,7 +219,7 @@ ccwgroup_create(struct device *root, ...@@ -124,7 +219,7 @@ ccwgroup_create(struct device *root,
kfree(gdev); kfree(gdev);
return -EINVAL; return rc;
} }
static int __init static int __init
...@@ -213,7 +308,7 @@ ccwgroup_online_show (struct device *dev, char *buf) ...@@ -213,7 +308,7 @@ ccwgroup_online_show (struct device *dev, char *buf)
online = (to_ccwgroupdev(dev)->state == CCWGROUP_ONLINE); online = (to_ccwgroupdev(dev)->state == CCWGROUP_ONLINE);
return sprintf(buf, online ? "yes\n" : "no\n"); return sprintf(buf, online ? "1\n" : "0\n");
} }
static DEVICE_ATTR(online, 0644, ccwgroup_online_show, ccwgroup_online_store); static DEVICE_ATTR(online, 0644, ccwgroup_online_show, ccwgroup_online_store);
...@@ -286,9 +381,59 @@ ccwgroup_probe_ccwdev(struct ccw_device *cdev) ...@@ -286,9 +381,59 @@ ccwgroup_probe_ccwdev(struct ccw_device *cdev)
return 0; return 0;
} }
static inline struct ccwgroup_device *
__ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
{
struct ccwgroup_device *gdev;
struct list_head *entry;
struct device *dev;
int i, found;
/*
* Find groupdevice cdev belongs to.
* Unfortunately, we can't use bus_for_each_dev() because of the
* semaphore (and return value of fn() is int).
*/
if (!get_bus(&ccwgroup_bus_type))
return NULL;
gdev = NULL;
down_read(&ccwgroup_bus_type.subsys.rwsem);
list_for_each(entry, &ccwgroup_bus_type.devices.list) {
dev = get_device(container_of(entry, struct device, bus_list));
found = 0;
if (!dev)
continue;
gdev = to_ccwgroupdev(dev);
for (i = 0; i < gdev->count && (!found); i++) {
if (gdev->cdev[i] == cdev)
found = 1;
}
if (found)
break;
put_device(dev);
gdev = NULL;
}
up_read(&ccwgroup_bus_type.subsys.rwsem);
put_bus(&ccwgroup_bus_type);
return gdev;
}
int int
ccwgroup_remove_ccwdev(struct ccw_device *cdev) ccwgroup_remove_ccwdev(struct ccw_device *cdev)
{ {
struct ccwgroup_device *gdev;
/* If one of its devices is gone, the whole group is done for. */
gdev = __ccwgroup_get_gdev_by_cdev(cdev);
if (gdev) {
ccwgroup_set_offline(gdev);
__ccwgroup_remove_symlinks(gdev);
device_unregister(&gdev->dev);
put_device(&gdev->dev);
}
return 0; return 0;
} }
......
/* /*
* drivers/s390/cio/chsc.c * drivers/s390/cio/chsc.c
* S/390 common I/O routines -- channel subsystem call * S/390 common I/O routines -- channel subsystem call
* $Revision: 1.74 $ * $Revision: 1.77 $
* *
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -865,9 +865,7 @@ new_channel_path(int chpid, int status) ...@@ -865,9 +865,7 @@ new_channel_path(int chpid, int status)
chp->state = status; chp->state = status;
chp->dev.parent = &css_bus_device; chp->dev.parent = &css_bus_device;
snprintf(chp->dev.name, DEVICE_NAME_SIZE, snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp0.%x", chpid);
"channel path %x", chpid);
snprintf(chp->dev.bus_id, DEVICE_ID_SIZE, "chp%x", chpid);
/* make it known to the system */ /* make it known to the system */
ret = device_register(&chp->dev); ret = device_register(&chp->dev);
......
/* /*
* drivers/s390/cio/cio.c * drivers/s390/cio/cio.c
* S/390 common I/O routines -- low level i/o calls * S/390 common I/O routines -- low level i/o calls
* $Revision: 1.100 $ * $Revision: 1.105 $
* *
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -277,11 +277,6 @@ cio_halt(struct subchannel *sch) ...@@ -277,11 +277,6 @@ cio_halt(struct subchannel *sch)
if (!sch) if (!sch)
return -ENODEV; return -ENODEV;
/*
* we ignore the halt_io() request if ending_status was received but
* a SENSE operation is waiting for completion.
*/
sprintf (dbf_txt, "haltIO%x", sch->irq); sprintf (dbf_txt, "haltIO%x", sch->irq);
CIO_TRACE_EVENT (2, dbf_txt); CIO_TRACE_EVENT (2, dbf_txt);
...@@ -316,10 +311,6 @@ cio_clear(struct subchannel *sch) ...@@ -316,10 +311,6 @@ cio_clear(struct subchannel *sch)
if (!sch) if (!sch)
return -ENODEV; return -ENODEV;
/*
* we ignore the clear_io() request if ending_status was received but
* a SENSE operation is waiting for completion.
*/
sprintf (dbf_txt, "clearIO%x", sch->irq); sprintf (dbf_txt, "clearIO%x", sch->irq);
CIO_TRACE_EVENT (2, dbf_txt); CIO_TRACE_EVENT (2, dbf_txt);
...@@ -380,7 +371,7 @@ cio_cancel (struct subchannel *sch) ...@@ -380,7 +371,7 @@ cio_cancel (struct subchannel *sch)
} }
/* /*
* Function: cio_cancel * Function: cio_modify
* Issues a "Modify Subchannel" on the specified subchannel * Issues a "Modify Subchannel" on the specified subchannel
*/ */
static int static int
...@@ -469,11 +460,6 @@ cio_disable_subchannel (struct subchannel *sch) ...@@ -469,11 +460,6 @@ cio_disable_subchannel (struct subchannel *sch)
sprintf (dbf_txt, "dissch%x", sch->irq); sprintf (dbf_txt, "dissch%x", sch->irq);
CIO_TRACE_EVENT (2, dbf_txt); CIO_TRACE_EVENT (2, dbf_txt);
/*
* If device isn't operational we have to perform delayed
* disabling when the next interrupt occurs - unless the
* irq is re-requested prior to the interrupt to occur.
*/
ccode = stsch (sch->irq, &sch->schib); ccode = stsch (sch->irq, &sch->schib);
if (ccode == 3) /* Not operational. */ if (ccode == 3) /* Not operational. */
return -ENODEV; return -ENODEV;
......
/* /*
* drivers/s390/cio/css.c * drivers/s390/cio/css.c
* driver for channel subsystem * driver for channel subsystem
* $Revision: 1.43 $ * $Revision: 1.49 $
* *
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -27,7 +27,6 @@ unsigned int highest_subchannel; ...@@ -27,7 +27,6 @@ unsigned int highest_subchannel;
int css_init_done = 0; int css_init_done = 0;
struct device css_bus_device = { struct device css_bus_device = {
.name = "Channel Subsystem 0",
.bus_id = "css0", .bus_id = "css0",
}; };
...@@ -79,17 +78,6 @@ css_free_subchannel(int irq) ...@@ -79,17 +78,6 @@ css_free_subchannel(int irq)
static int static int
css_register_subchannel(struct subchannel *sch) css_register_subchannel(struct subchannel *sch)
{ {
static const char *subchannel_types[] = {
"I/O Subchannel",
"CHSC Subchannel",
"Message Subchannel",
"ADM Subchannel",
"undefined subchannel type 4",
"undefined subchannel type 5",
"undefined subchannel type 6",
"undefined subchannel type 7",
"undefined subchannel type 8",
};
int ret; int ret;
/* Initialize the subchannel structure */ /* Initialize the subchannel structure */
...@@ -97,8 +85,7 @@ css_register_subchannel(struct subchannel *sch) ...@@ -97,8 +85,7 @@ css_register_subchannel(struct subchannel *sch)
sch->dev.bus = &css_bus_type; sch->dev.bus = &css_bus_type;
/* Set a name for the subchannel */ /* Set a name for the subchannel */
strlcpy (sch->dev.name, subchannel_types[sch->st], DEVICE_NAME_SIZE); snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", sch->irq);
snprintf (sch->dev.bus_id, DEVICE_ID_SIZE, "0:%04x", sch->irq);
/* make it known to the system */ /* make it known to the system */
ret = device_register(&sch->dev); ret = device_register(&sch->dev);
......
...@@ -78,6 +78,7 @@ struct ccw_device_private { ...@@ -78,6 +78,7 @@ struct ccw_device_private {
unsigned int pgid_single:1; /* use single path for Set PGID */ unsigned int pgid_single:1; /* use single path for Set PGID */
unsigned int esid:1; /* Ext. SenseID supported by HW */ unsigned int esid:1; /* Ext. SenseID supported by HW */
unsigned int dosense:1; /* delayed SENSE required */ unsigned int dosense:1; /* delayed SENSE required */
unsigned int doverify:1; /* delayed path verification */
} __attribute__((packed)) flags; } __attribute__((packed)) flags;
unsigned long intparm; /* user interruption parameter */ unsigned long intparm; /* user interruption parameter */
struct qdio_irq *qdio_data; struct qdio_irq *qdio_data;
......
/* /*
* drivers/s390/cio/device.c * drivers/s390/cio/device.c
* bus driver for ccw devices * bus driver for ccw devices
* $Revision: 1.60 $ * $Revision: 1.70 $
* *
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -229,7 +229,7 @@ online_show (struct device *dev, char *buf) ...@@ -229,7 +229,7 @@ online_show (struct device *dev, char *buf)
{ {
struct ccw_device *cdev = to_ccwdev(dev); struct ccw_device *cdev = to_ccwdev(dev);
return sprintf(buf, cdev->online ? "yes\n" : "no\n"); return sprintf(buf, cdev->online ? "1\n" : "0\n");
} }
void void
...@@ -537,8 +537,7 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) ...@@ -537,8 +537,7 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
init_timer(&cdev->private->timer); init_timer(&cdev->private->timer);
/* Set an initial name for the device. */ /* Set an initial name for the device. */
snprintf (cdev->dev.name, DEVICE_NAME_SIZE,"ccw device"); snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.0.%04x",
snprintf (cdev->dev.bus_id, DEVICE_ID_SIZE, "0:%04x",
sch->schib.pmcw.dev); sch->schib.pmcw.dev);
/* Increase counter of devices currently in recognition. */ /* Increase counter of devices currently in recognition. */
...@@ -679,6 +678,7 @@ ccw_device_probe_console(void) ...@@ -679,6 +678,7 @@ ccw_device_probe_console(void)
console_cdev_in_use = 0; console_cdev_in_use = 0;
return ERR_PTR(ret); return ERR_PTR(ret);
} }
console_cdev.online = 1;
return &console_cdev; return &console_cdev;
} }
#endif #endif
...@@ -702,10 +702,12 @@ get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id) ...@@ -702,10 +702,12 @@ get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id)
list_for_each_entry(d, &drv->devices, driver_list) { list_for_each_entry(d, &drv->devices, driver_list) {
dev = get_device(d); dev = get_device(d);
if (dev && !strncmp(bus_id, dev->bus_id, DEVICE_ID_SIZE)) if (dev && !strncmp(bus_id, dev->bus_id, BUS_ID_SIZE))
break; break;
else else if (dev) {
put_device(dev); put_device(dev);
dev = NULL;
}
} }
up_read(&drv->bus->subsys.rwsem); up_read(&drv->bus->subsys.rwsem);
put_driver(drv); put_driver(drv);
......
...@@ -15,8 +15,6 @@ enum dev_state { ...@@ -15,8 +15,6 @@ enum dev_state {
DEV_STATE_DISBAND_PGID, DEV_STATE_DISBAND_PGID,
DEV_STATE_BOXED, DEV_STATE_BOXED,
/* states to wait for i/o completion before doing something */ /* states to wait for i/o completion before doing something */
DEV_STATE_ONLINE_VERIFY,
DEV_STATE_W4SENSE_VERIFY,
DEV_STATE_CLEAR_VERIFY, DEV_STATE_CLEAR_VERIFY,
DEV_STATE_TIMEOUT_KILL, DEV_STATE_TIMEOUT_KILL,
/* last element! */ /* last element! */
...@@ -95,7 +93,7 @@ void ccw_device_disband_start(struct ccw_device *); ...@@ -95,7 +93,7 @@ void ccw_device_disband_start(struct ccw_device *);
void ccw_device_disband_irq(struct ccw_device *, enum dev_event); void ccw_device_disband_irq(struct ccw_device *, enum dev_event);
void ccw_device_disband_done(struct ccw_device *, int); void ccw_device_disband_done(struct ccw_device *, int);
void ccw_device_call_handler(struct ccw_device *); int ccw_device_call_handler(struct ccw_device *);
void ccw_device_add_stlck(void *); void ccw_device_add_stlck(void *);
int ccw_device_stlck(struct ccw_device *); int ccw_device_stlck(struct ccw_device *);
......
...@@ -269,6 +269,7 @@ ccw_device_recog_timeout(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -269,6 +269,7 @@ ccw_device_recog_timeout(struct ccw_device *cdev, enum dev_event dev_event)
void void
ccw_device_verify_done(struct ccw_device *cdev, int err) ccw_device_verify_done(struct ccw_device *cdev, int err)
{ {
cdev->private->flags.doverify = 0;
switch (err) { switch (err) {
case 0: case 0:
ccw_device_done(cdev, DEV_STATE_ONLINE); ccw_device_done(cdev, DEV_STATE_ONLINE);
...@@ -419,13 +420,21 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -419,13 +420,21 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
{ {
struct subchannel *sch; struct subchannel *sch;
sch = to_subchannel(cdev->dev.parent); if (!cdev->private->options.pgroup)
return;
if (cdev->private->state == DEV_STATE_W4SENSE) { if (cdev->private->state == DEV_STATE_W4SENSE) {
cdev->private->state = DEV_STATE_W4SENSE_VERIFY; cdev->private->flags.doverify = 1;
return; return;
} }
if (sch->schib.scsw.actl != 0) { sch = to_subchannel(cdev->dev.parent);
cdev->private->state = DEV_STATE_ONLINE_VERIFY; if (sch->schib.scsw.actl != 0 ||
(cdev->private->irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)) {
/*
* No final status yet or final status not yet delivered
* to the device driver. Can't do path verfication now,
* delay until final status was delivered.
*/
cdev->private->flags.doverify = 1;
return; return;
} }
/* Device is idle, we can do the path verification. */ /* Device is idle, we can do the path verification. */
...@@ -453,19 +462,14 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -453,19 +462,14 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event)
ccw_device_accumulate_irb(cdev, irb); ccw_device_accumulate_irb(cdev, irb);
if (cdev->private->flags.dosense) { if (cdev->private->flags.dosense) {
if (ccw_device_do_sense(cdev, irb) == 0) { if (ccw_device_do_sense(cdev, irb) == 0) {
/* Check if we have to trigger path verification. */ cdev->private->state = DEV_STATE_W4SENSE;
if (irb->esw.esw0.erw.pvrf)
cdev->private->state = DEV_STATE_W4SENSE_VERIFY;
else
cdev->private->state = DEV_STATE_W4SENSE;
} }
return; return;
} }
if (irb->esw.esw0.erw.pvrf) /* Call the handler. */
/* Try to start path verification. */ if (ccw_device_call_handler(cdev) && cdev->private->flags.doverify)
/* Start delayed path verification. */
ccw_device_online_verify(cdev, 0); ccw_device_online_verify(cdev, 0);
/* No basic sense required, call the handler. */
ccw_device_call_handler(cdev);
} }
/* /*
...@@ -485,32 +489,6 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -485,32 +489,6 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
ERR_PTR(-ETIMEDOUT)); ERR_PTR(-ETIMEDOUT));
} }
static void
ccw_device_irq_verify(struct ccw_device *cdev, enum dev_event dev_event)
{
struct irb *irb;
irb = (struct irb *) __LC_IRB;
/* Check for unsolicited interrupt. */
if (irb->scsw.stctl ==
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
if (cdev->handler)
cdev->handler (cdev, 0, irb);
return;
}
/* Accumulate status and find out if a basic sense is needed. */
ccw_device_accumulate_irb(cdev, irb);
if (cdev->private->flags.dosense) {
if (ccw_device_do_sense(cdev, irb) == 0)
cdev->private->state = DEV_STATE_W4SENSE_VERIFY;
return;
}
/* Try to start delayed device verification. */
ccw_device_online_verify(cdev, 0);
/* No basic sense required, call the handler. */
ccw_device_call_handler(cdev);
}
/* /*
* Got an interrupt for a basic sense. * Got an interrupt for a basic sense.
*/ */
...@@ -530,46 +508,15 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -530,46 +508,15 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
/* Add basic sense info to irb. */ /* Add basic sense info to irb. */
ccw_device_accumulate_basic_sense(cdev, irb); ccw_device_accumulate_basic_sense(cdev, irb);
if (cdev->private->flags.dosense) { if (cdev->private->flags.dosense) {
/* Check if we have to trigger path verification. */
if (irb->esw.esw0.erw.pvrf)
cdev->private->state = DEV_STATE_W4SENSE_VERIFY;
/* Another basic sense is needed. */ /* Another basic sense is needed. */
ccw_device_do_sense(cdev, irb); ccw_device_do_sense(cdev, irb);
return; return;
} }
cdev->private->state = DEV_STATE_ONLINE; cdev->private->state = DEV_STATE_ONLINE;
if (irb->esw.esw0.erw.pvrf)
/* Try to start path verification. */
ccw_device_online_verify(cdev, 0);
/* Call the handler. */ /* Call the handler. */
ccw_device_call_handler(cdev); if (ccw_device_call_handler(cdev) && cdev->private->flags.doverify)
} /* Start delayed path verification. */
ccw_device_online_verify(cdev, 0);
static void
ccw_device_w4sense_verify(struct ccw_device *cdev, enum dev_event dev_event)
{
struct irb *irb;
irb = (struct irb *) __LC_IRB;
/* Check for unsolicited interrupt. */
if (irb->scsw.stctl ==
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
if (cdev->handler)
cdev->handler (cdev, 0, irb);
return;
}
/* Add basic sense info to irb. */
ccw_device_accumulate_basic_sense(cdev, irb);
if (cdev->private->flags.dosense) {
/* Another basic sense is needed. */
ccw_device_do_sense(cdev, irb);
return;
}
cdev->private->state = DEV_STATE_ONLINE_VERIFY;
/* Start delayed device verification. */
ccw_device_online_verify(cdev, 0);
/* Call the handler. */
ccw_device_call_handler(cdev);
} }
static void static void
...@@ -718,18 +665,6 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { ...@@ -718,18 +665,6 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_EVENT_VERIFY] ccw_device_nop, [DEV_EVENT_VERIFY] ccw_device_nop,
}, },
/* states to wait for i/o completion before doing something */ /* states to wait for i/o completion before doing something */
[DEV_STATE_ONLINE_VERIFY] {
[DEV_EVENT_NOTOPER] ccw_device_online_notoper,
[DEV_EVENT_INTERRUPT] ccw_device_irq_verify,
[DEV_EVENT_TIMEOUT] ccw_device_nop,
[DEV_EVENT_VERIFY] ccw_device_nop,
},
[DEV_STATE_W4SENSE_VERIFY] {
[DEV_EVENT_NOTOPER] ccw_device_online_notoper,
[DEV_EVENT_INTERRUPT] ccw_device_w4sense_verify,
[DEV_EVENT_TIMEOUT] ccw_device_nop,
[DEV_EVENT_VERIFY] ccw_device_nop,
},
[DEV_STATE_CLEAR_VERIFY] { [DEV_STATE_CLEAR_VERIFY] {
[DEV_EVENT_NOTOPER] ccw_device_online_notoper, [DEV_EVENT_NOTOPER] ccw_device_online_notoper,
[DEV_EVENT_INTERRUPT] ccw_device_clear_verify, [DEV_EVENT_INTERRUPT] ccw_device_clear_verify,
......
...@@ -342,3 +342,4 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -342,3 +342,4 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event)
} }
} }
EXPORT_SYMBOL(diag210);
This diff is collapsed.
...@@ -67,7 +67,8 @@ ccw_device_path_notoper(struct ccw_device *cdev) ...@@ -67,7 +67,8 @@ ccw_device_path_notoper(struct ccw_device *cdev)
sch->schib.pmcw.pnom); sch->schib.pmcw.pnom);
sch->lpm &= ~sch->schib.pmcw.pnom; sch->lpm &= ~sch->schib.pmcw.pnom;
dev_fsm_event(cdev, DEV_EVENT_VERIFY); if (cdev->private->options.pgroup)
cdev->private->flags.doverify = 1;
} }
/* /*
...@@ -92,6 +93,21 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb) ...@@ -92,6 +93,21 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb)
memcpy (&cdev->private->irb.ecw, irb->ecw, sizeof (irb->ecw)); memcpy (&cdev->private->irb.ecw, irb->ecw, sizeof (irb->ecw));
} }
/*
* Check if extended status word is valid.
*/
static inline int
ccw_device_accumulate_esw_valid(struct irb *irb)
{
if (irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND)
return 0;
if (irb->scsw.stctl ==
(SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND) &&
!(irb->scsw.actl & SCSW_ACTL_SUSPENDED))
return 0;
return 1;
}
/* /*
* Copy valid bits from the extended status word to device irb. * Copy valid bits from the extended status word to device irb.
*/ */
...@@ -101,12 +117,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb) ...@@ -101,12 +117,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
struct irb *cdev_irb; struct irb *cdev_irb;
struct sublog *cdev_sublog, *sublog; struct sublog *cdev_sublog, *sublog;
/* Check if extended status word is valid. */ if (!ccw_device_accumulate_esw_valid(irb))
if (irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND)
return;
if (irb->scsw.stctl ==
(SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND) &&
!(irb->scsw.actl & SCSW_ACTL_SUSPENDED))
return; return;
cdev_irb = &cdev->private->irb; cdev_irb = &cdev->private->irb;
...@@ -169,6 +180,8 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb) ...@@ -169,6 +180,8 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
cdev_irb->esw.esw0.erw.auth = irb->esw.esw0.erw.auth; cdev_irb->esw.esw0.erw.auth = irb->esw.esw0.erw.auth;
/* Copy path verification required flag. */ /* Copy path verification required flag. */
cdev_irb->esw.esw0.erw.pvrf = irb->esw.esw0.erw.pvrf; cdev_irb->esw.esw0.erw.pvrf = irb->esw.esw0.erw.pvrf;
if (irb->esw.esw0.erw.pvrf && cdev->private->options.pgroup)
cdev->private->flags.doverify = 1;
/* Copy concurrent sense bit. */ /* Copy concurrent sense bit. */
cdev_irb->esw.esw0.erw.cons = irb->esw.esw0.erw.cons; cdev_irb->esw.esw0.erw.cons = irb->esw.esw0.erw.cons;
if (irb->esw.esw0.erw.cons) if (irb->esw.esw0.erw.cons)
...@@ -339,6 +352,10 @@ ccw_device_accumulate_basic_sense(struct ccw_device *cdev, struct irb *irb) ...@@ -339,6 +352,10 @@ ccw_device_accumulate_basic_sense(struct ccw_device *cdev, struct irb *irb)
cdev->private->irb.esw.esw0.erw.cons = 1; cdev->private->irb.esw.esw0.erw.cons = 1;
cdev->private->flags.dosense = 0; cdev->private->flags.dosense = 0;
} }
/* Check if path verification is required. */
if (ccw_device_accumulate_esw_valid(irb) &&
irb->esw.esw0.erw.pvrf && cdev->private->options.pgroup)
cdev->private->flags.doverify = 1;
} }
/* /*
......
This diff is collapsed.
#ifndef _CIO_QDIO_H #ifndef _CIO_QDIO_H
#define _CIO_QDIO_H #define _CIO_QDIO_H
#define VERSION_CIO_QDIO_H "$Revision: 1.18 $" #define VERSION_CIO_QDIO_H "$Revision: 1.20 $"
//#define QDIO_DBF_LIKE_HELL //#define QDIO_DBF_LIKE_HELL
...@@ -56,7 +56,6 @@ ...@@ -56,7 +56,6 @@
#define QDIO_STATS_CLASSES 2 #define QDIO_STATS_CLASSES 2
#define QDIO_STATS_COUNT_NEEDED 2*/ #define QDIO_STATS_COUNT_NEEDED 2*/
#define QDIO_NO_USE_COUNT_TIME 10
#define QDIO_NO_USE_COUNT_TIMEOUT 1000 /* wait for 1 sec on each q before #define QDIO_NO_USE_COUNT_TIMEOUT 1000 /* wait for 1 sec on each q before
exiting without having use_count exiting without having use_count
of the queue to 0 */ of the queue to 0 */
...@@ -577,9 +576,6 @@ struct qdio_q { ...@@ -577,9 +576,6 @@ struct qdio_q {
volatile struct qdio_q *list_next; volatile struct qdio_q *list_next;
volatile struct qdio_q *list_prev; volatile struct qdio_q *list_prev;
struct slib *slib; /* a page is allocated under this pointer,
sl points into this page, offset PAGE_SIZE/2
(after slib) */
struct sl *sl; struct sl *sl;
volatile struct sbal *sbal[QDIO_MAX_BUFFERS_PER_Q]; volatile struct sbal *sbal[QDIO_MAX_BUFFERS_PER_Q];
...@@ -605,6 +601,11 @@ struct qdio_q { ...@@ -605,6 +601,11 @@ struct qdio_q {
__u64 last_transfer_time; __u64 last_transfer_time;
} timing; } timing;
unsigned int queue_type; unsigned int queue_type;
/* leave this member at the end. won't be cleared in qdio_fill_qs */
struct slib *slib; /* a page is allocated under this pointer,
sl points into this page, offset PAGE_SIZE/2
(after slib) */
} __attribute__ ((aligned(256))); } __attribute__ ((aligned(256)));
struct qdio_irq { struct qdio_irq {
...@@ -619,20 +620,14 @@ struct qdio_irq { ...@@ -619,20 +620,14 @@ struct qdio_irq {
unsigned int sync_done_on_outb_pcis; unsigned int sync_done_on_outb_pcis;
enum qdio_irq_states state; enum qdio_irq_states state;
struct semaphore setting_up_sema;
unsigned int no_input_qs; unsigned int no_input_qs;
unsigned int no_output_qs; unsigned int no_output_qs;
unsigned char qdioac; unsigned char qdioac;
struct qdio_q *input_qs[QDIO_MAX_QUEUES_PER_IRQ];
struct qdio_q *output_qs[QDIO_MAX_QUEUES_PER_IRQ];
struct ccw1 ccw; struct ccw1 ccw;
struct qdr *qdr;
struct ciw equeue; struct ciw equeue;
struct ciw aqueue; struct ciw aqueue;
...@@ -641,5 +636,10 @@ struct qdio_irq { ...@@ -641,5 +636,10 @@ struct qdio_irq {
void (*original_int_handler) (struct ccw_device *, void (*original_int_handler) (struct ccw_device *,
unsigned long, struct irb *); unsigned long, struct irb *);
/* leave these four members together at the end. won't be cleared in qdio_fill_irq */
struct qdr *qdr;
struct qdio_q *input_qs[QDIO_MAX_QUEUES_PER_IRQ];
struct qdio_q *output_qs[QDIO_MAX_QUEUES_PER_IRQ];
struct semaphore setting_up_sema;
}; };
#endif #endif
/* /*
* $Id: cu3088.c,v 1.26 2003/01/17 13:46:13 cohuck Exp $ * $Id: cu3088.c,v 1.30 2003/08/28 11:14:11 cohuck Exp $
* *
* CTC / LCS ccw_device driver * CTC / LCS ccw_device driver
* *
...@@ -56,7 +56,6 @@ static struct ccw_device_id cu3088_ids[] = { ...@@ -56,7 +56,6 @@ static struct ccw_device_id cu3088_ids[] = {
static struct ccw_driver cu3088_driver; static struct ccw_driver cu3088_driver;
struct device cu3088_root_dev = { struct device cu3088_root_dev = {
.name = "CU3088 Devices",
.bus_id = "cu3088", .bus_id = "cu3088",
}; };
...@@ -64,7 +63,7 @@ static ssize_t ...@@ -64,7 +63,7 @@ static ssize_t
group_write(struct device_driver *drv, const char *buf, size_t count) group_write(struct device_driver *drv, const char *buf, size_t count)
{ {
const char *start, *end; const char *start, *end;
char bus_ids[2][BUS_ID_SIZE+1], *argv[2]; char bus_ids[2][BUS_ID_SIZE], *argv[2];
int i; int i;
int ret; int ret;
struct ccwgroup_driver *cdrv; struct ccwgroup_driver *cdrv;
...@@ -79,7 +78,7 @@ group_write(struct device_driver *drv, const char *buf, size_t count) ...@@ -79,7 +78,7 @@ group_write(struct device_driver *drv, const char *buf, size_t count)
if (!(end = strchr(start, delim[i]))) if (!(end = strchr(start, delim[i])))
return count; return count;
len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start)+1; len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start + 1);
strlcpy (bus_ids[i], start, len); strlcpy (bus_ids[i], start, len);
argv[i] = bus_ids[i]; argv[i] = bus_ids[i];
start = end + 1; start = end + 1;
......
...@@ -76,7 +76,7 @@ typedef void qdio_handler_t(struct ccw_device *,unsigned int,unsigned int, ...@@ -76,7 +76,7 @@ typedef void qdio_handler_t(struct ccw_device *,unsigned int,unsigned int,
#define QDIO_FLAG_CLEANUP_USING_CLEAR 0x01 #define QDIO_FLAG_CLEANUP_USING_CLEAR 0x01
#define QDIO_FLAG_CLEANUP_USING_HALT 0x02 #define QDIO_FLAG_CLEANUP_USING_HALT 0x02
struct qdio_initialize{ struct qdio_initialize {
struct ccw_device *cdev; struct ccw_device *cdev;
unsigned char q_format; unsigned char q_format;
unsigned char adapter_name[8]; unsigned char adapter_name[8];
...@@ -99,9 +99,10 @@ struct qdio_initialize{ ...@@ -99,9 +99,10 @@ struct qdio_initialize{
void **input_sbal_addr_array; /* addr of n*128 void ptrs */ void **input_sbal_addr_array; /* addr of n*128 void ptrs */
void **output_sbal_addr_array; /* addr of n*128 void ptrs */ void **output_sbal_addr_array; /* addr of n*128 void ptrs */
}; };
extern int qdio_initialize(struct qdio_initialize *init_data); extern int qdio_initialize(struct qdio_initialize *init_data);
extern int qdio_allocate(struct qdio_initialize *init_data); extern int qdio_allocate(struct qdio_initialize *init_data);
extern int qdio_establish(struct ccw_device *); extern int qdio_establish(struct qdio_initialize *init_data);
extern int qdio_activate(struct ccw_device *,int flags); extern int qdio_activate(struct ccw_device *,int flags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment