Commit 35181f43 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: common i/o layer.

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

Common i/o layer fixes:

- Remove documentation entry for non-existent cio_notoper_msg parameter.

- Add documentation for availability attritube.

- Replace function of the steal_lock attribute by "echo force" to the
  online attribute.

- Trigger device sensing in the online function for unknown devices.

- Always try to get devices online even if they are marked reserved.
  Someone could have released the device while it was offline.

- Add try_module_get/module_put pairs to the online function of ccw devices
  and ccwgroup devices.

- Add owner field to ccwgroup driver structure.  Set owner field in ctc,
  lcs and qeth.

- Fix alignment problems in channel measurement block interface.
parent df6560ba
...@@ -14,15 +14,6 @@ Command line parameters ...@@ -14,15 +14,6 @@ Command line parameters
Default is off. Default is off.
* cio_notoper_msg = yes | no
Determines whether messages of the type "Device 0.0.4711 became 'not
operational'" should be shown during startup; after startup, they will always
be shown.
Default is on.
* cio_ignore = {all} | * cio_ignore = {all} |
{<device> | <range of devices>} | {<device> | <range of devices>} |
{!<device> | !<range of devices>} {!<device> | !<range of devices>}
......
...@@ -31,6 +31,9 @@ cutype: The control unit type / model. ...@@ -31,6 +31,9 @@ cutype: The control unit type / model.
devtype: The device type / model, if applicable. devtype: The device type / model, if applicable.
availability: Can be 'good' or 'boxed'; 'no path' or 'no device' for
disconnected devices.
online: An interface to set the device online and offline. online: An interface to set the device online and offline.
In the special case of the device being disconnected (see the In the special case of the device being disconnected (see the
notify function under 1.2), piping 0 to online will focibly delete notify function under 1.2), piping 0 to online will focibly delete
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Bugreports.to..: <Linux390@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
* *
* $Revision: 1.50 $ * $Revision: 1.51 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -85,7 +85,7 @@ dasd_eckd_probe (struct ccw_device *cdev) ...@@ -85,7 +85,7 @@ dasd_eckd_probe (struct ccw_device *cdev)
ret = dasd_generic_probe (cdev, &dasd_eckd_discipline); ret = dasd_generic_probe (cdev, &dasd_eckd_discipline);
if (ret) if (ret)
return ret; return ret;
ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP); ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP | CCWDEV_ALLOW_FORCE);
return 0; return 0;
} }
......
/* /*
* drivers/s390/cio/ccwgroup.c * drivers/s390/cio/ccwgroup.c
* bus driver for ccwgroup * bus driver for ccwgroup
* $Revision: 1.23 $ * $Revision: 1.24 $
* *
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -293,22 +293,28 @@ static ssize_t ...@@ -293,22 +293,28 @@ static ssize_t
ccwgroup_online_store (struct device *dev, const char *buf, size_t count) ccwgroup_online_store (struct device *dev, const char *buf, size_t count)
{ {
struct ccwgroup_device *gdev; struct ccwgroup_device *gdev;
struct ccwgroup_driver *gdrv;
unsigned int value; unsigned int value;
int ret;
gdev = to_ccwgroupdev(dev); gdev = to_ccwgroupdev(dev);
if (!dev->driver) if (!dev->driver)
return count; return count;
value = simple_strtoul(buf, 0, 0); gdrv = to_ccwgroupdrv (gdev->dev.driver);
if (!try_module_get(gdrv->owner))
return -EINVAL;
value = simple_strtoul(buf, 0, 0);
ret = count;
if (value == 1) if (value == 1)
ccwgroup_set_online(gdev); ccwgroup_set_online(gdev);
else if (value == 0) else if (value == 0)
ccwgroup_set_offline(gdev); ccwgroup_set_offline(gdev);
else else
return -EINVAL; ret = -EINVAL;
module_put(gdrv->owner);
return count; return ret;
} }
static ssize_t static ssize_t
......
/* /*
* linux/drivers/s390/cio/cmf.c ($Revision: 1.11 $) * linux/drivers/s390/cio/cmf.c ($Revision: 1.13 $)
* *
* Linux on zSeries Channel Measurement Facility support * Linux on zSeries Channel Measurement Facility support
* *
...@@ -138,7 +138,7 @@ static inline u64 time_to_avg_nsec(u32 value, u32 count) ...@@ -138,7 +138,7 @@ static inline u64 time_to_avg_nsec(u32 value, u32 count)
if (count == 0) if (count == 0)
return 0; return 0;
/* value comes in units of 128 5sec */ /* value comes in units of 128 sec */
ret = time_to_nsec(value); ret = time_to_nsec(value);
do_div(ret, count); do_div(ret, count);
...@@ -390,12 +390,13 @@ alloc_cmb (struct ccw_device *cdev) ...@@ -390,12 +390,13 @@ alloc_cmb (struct ccw_device *cdev)
WARN_ON(!list_empty(&cmb_area.list)); WARN_ON(!list_empty(&cmb_area.list));
spin_unlock(&cmb_area.lock); spin_unlock(&cmb_area.lock);
mem = kmalloc(size, GFP_KERNEL | GFP_DMA); mem = (void*)__get_free_pages(GFP_KERNEL | GFP_DMA,
get_order(size));
spin_lock(&cmb_area.lock); spin_lock(&cmb_area.lock);
if (cmb_area.mem) { if (cmb_area.mem) {
/* ok, another thread was faster */ /* ok, another thread was faster */
kfree(mem); free_pages((unsigned long)mem, get_order(size));
} else if (!mem) { } else if (!mem) {
/* no luck */ /* no luck */
ret = -ENOMEM; ret = -ENOMEM;
...@@ -435,8 +436,10 @@ free_cmb(struct ccw_device *cdev) ...@@ -435,8 +436,10 @@ free_cmb(struct ccw_device *cdev)
list_del_init(&priv->cmb_list); list_del_init(&priv->cmb_list);
if (list_empty(&cmb_area.list)) { if (list_empty(&cmb_area.list)) {
ssize_t size;
size = sizeof(struct cmb) * cmb_area.num_channels;
cmf_activate(NULL, 0); cmf_activate(NULL, 0);
kfree(cmb_area.mem); free_pages((unsigned long)cmb_area.mem, get_order(size));
cmb_area.mem = NULL; cmb_area.mem = NULL;
} }
out: out:
...@@ -595,11 +598,22 @@ struct cmbe { ...@@ -595,11 +598,22 @@ struct cmbe {
u32 reserved[7]; u32 reserved[7];
}; };
/* kmalloc only guarantees 8 byte alignment, but we need cmbe
* pointers to be naturally aligned. Make sure to allocate
* enough space for two cmbes */
static inline struct cmbe* cmbe_align(struct cmbe *c)
{
unsigned long addr;
addr = ((unsigned long)c + sizeof (struct cmbe) - sizeof(long)) &
~(sizeof (struct cmbe) - sizeof(long));
return (struct cmbe*)addr;
}
static int static int
alloc_cmbe (struct ccw_device *cdev) alloc_cmbe (struct ccw_device *cdev)
{ {
struct cmbe *cmbe; struct cmbe *cmbe;
cmbe = kmalloc (sizeof (*cmbe), GFP_KERNEL /* | GFP_DMA ? */); cmbe = kmalloc (sizeof (*cmbe) * 2, GFP_KERNEL);
if (!cmbe) if (!cmbe)
return -ENOMEM; return -ENOMEM;
...@@ -647,7 +661,7 @@ set_cmbe(struct ccw_device *cdev, u32 mme) ...@@ -647,7 +661,7 @@ set_cmbe(struct ccw_device *cdev, u32 mme)
if (!cdev->private->cmb) if (!cdev->private->cmb)
return -EINVAL; return -EINVAL;
mba = mme ? (unsigned long)cdev->private->cmb : 0; mba = mme ? (unsigned long) cmbe_align(cdev->private->cmb) : 0;
return set_schib_wait(cdev, mme, 1, mba); return set_schib_wait(cdev, mme, 1, mba);
} }
...@@ -669,7 +683,7 @@ read_cmbe (struct ccw_device *cdev, int index) ...@@ -669,7 +683,7 @@ read_cmbe (struct ccw_device *cdev, int index)
return 0; return 0;
} }
cmb = *(struct cmbe*)cdev->private->cmb; cmb = *cmbe_align(cdev->private->cmb);
spin_unlock_irqrestore(cdev->ccwlock, flags); spin_unlock_irqrestore(cdev->ccwlock, flags);
switch (index) { switch (index) {
...@@ -720,7 +734,7 @@ readall_cmbe (struct ccw_device *cdev, struct cmbdata *data) ...@@ -720,7 +734,7 @@ readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
return -ENODEV; return -ENODEV;
} }
cmb = *(struct cmbe*)cdev->private->cmb; cmb = *cmbe_align(cdev->private->cmb);
time = get_clock() - cdev->private->cmb_start_time; time = get_clock() - cdev->private->cmb_start_time;
spin_unlock_irqrestore(cdev->ccwlock, flags); spin_unlock_irqrestore(cdev->ccwlock, flags);
...@@ -760,7 +774,7 @@ reset_cmbe(struct ccw_device *cdev) ...@@ -760,7 +774,7 @@ reset_cmbe(struct ccw_device *cdev)
{ {
struct cmbe *cmb; struct cmbe *cmb;
spin_lock_irq(cdev->ccwlock); spin_lock_irq(cdev->ccwlock);
cmb = cdev->private->cmb; cmb = cmbe_align(cdev->private->cmb);
if (cmb) if (cmb)
memset (cmb, 0, sizeof (*cmb)); memset (cmb, 0, sizeof (*cmb));
cdev->private->cmb_start_time = get_clock(); cdev->private->cmb_start_time = get_clock();
......
...@@ -74,6 +74,7 @@ struct ccw_device_private { ...@@ -74,6 +74,7 @@ struct ccw_device_private {
unsigned int fast:1; /* post with "channel end" */ unsigned int fast:1; /* post with "channel end" */
unsigned int repall:1; /* report every interrupt status */ unsigned int repall:1; /* report every interrupt status */
unsigned int pgroup:1; /* do path grouping */ unsigned int pgroup:1; /* do path grouping */
unsigned int force:1; /* allow forced online */
} __attribute__ ((packed)) options; } __attribute__ ((packed)) options;
struct { struct {
unsigned int pgid_single:1; /* use single path for Set PGID */ unsigned int pgid_single:1; /* use single path for Set PGID */
......
/* /*
* drivers/s390/cio/device.c * drivers/s390/cio/device.c
* bus driver for ccw devices * bus driver for ccw devices
* $Revision: 1.103 $ * $Revision: 1.107 $
* *
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -263,10 +263,10 @@ ccw_device_set_offline(struct ccw_device *cdev) ...@@ -263,10 +263,10 @@ ccw_device_set_offline(struct ccw_device *cdev)
if (!cdev) if (!cdev)
return -ENODEV; return -ENODEV;
if (!cdev->online || !cdev->drv) if (!cdev->online)
return -EINVAL; return -EINVAL;
if (cdev->drv->set_offline) { if (cdev->drv && cdev->drv->set_offline) {
ret = cdev->drv->set_offline(cdev); ret = cdev->drv->set_offline(cdev);
if (ret != 0) if (ret != 0)
return ret; return ret;
...@@ -292,7 +292,7 @@ ccw_device_set_online(struct ccw_device *cdev) ...@@ -292,7 +292,7 @@ ccw_device_set_online(struct ccw_device *cdev)
if (!cdev) if (!cdev)
return -ENODEV; return -ENODEV;
if (cdev->online || !cdev->drv) if (cdev->online)
return -EINVAL; return -EINVAL;
spin_lock_irq(cdev->ccwlock); spin_lock_irq(cdev->ccwlock);
...@@ -307,7 +307,8 @@ ccw_device_set_online(struct ccw_device *cdev) ...@@ -307,7 +307,8 @@ ccw_device_set_online(struct ccw_device *cdev)
} }
if (cdev->private->state != DEV_STATE_ONLINE) if (cdev->private->state != DEV_STATE_ONLINE)
return -ENODEV; return -ENODEV;
if (!cdev->drv->set_online || cdev->drv->set_online(cdev) == 0) { if (!cdev->drv || !cdev->drv->set_online ||
cdev->drv->set_online(cdev) == 0) {
cdev->online = 1; cdev->online = 1;
return 0; return 0;
} }
...@@ -326,52 +327,54 @@ static ssize_t ...@@ -326,52 +327,54 @@ static ssize_t
online_store (struct device *dev, const char *buf, size_t count) online_store (struct device *dev, const char *buf, size_t count)
{ {
struct ccw_device *cdev = to_ccwdev(dev); struct ccw_device *cdev = to_ccwdev(dev);
int i; int i, force;
char *tmp; char *tmp;
if (!cdev->drv)
return count;
if (atomic_compare_and_swap(0, 1, &cdev->private->onoff)) if (atomic_compare_and_swap(0, 1, &cdev->private->onoff))
return -EAGAIN; return -EAGAIN;
i = simple_strtoul(buf, &tmp, 16); if (cdev->drv && !try_module_get(cdev->drv->owner)) {
if (i == 1 && cdev->drv->set_online) atomic_set(&cdev->private->onoff, 0);
return -EINVAL;
}
if (!strncmp(buf, "force\n", count)) {
force = 1;
i = 1;
} else {
force = 0;
i = simple_strtoul(buf, &tmp, 16);
}
if (i == 1) {
/* Do device recognition, if needed. */
if (cdev->id.cu_type == 0) {
ccw_device_recognition(cdev);
wait_event(cdev->private->wait_q,
dev_fsm_final_state(cdev));
}
ccw_device_set_online(cdev); ccw_device_set_online(cdev);
else if (i == 0 && cdev->drv->set_offline) { } else if (i == 0) {
if (cdev->private->state == DEV_STATE_DISCONNECTED) if (cdev->private->state == DEV_STATE_DISCONNECTED)
ccw_device_remove_disconnected(cdev); ccw_device_remove_disconnected(cdev);
else else
ccw_device_set_offline(cdev); ccw_device_set_offline(cdev);
} }
atomic_set(&cdev->private->onoff, 0); if (force && cdev->private->state == DEV_STATE_BOXED) {
return count; int ret;
} ret = ccw_device_stlck(cdev);
if (ret)
static void ccw_device_unbox_recog(void *data); goto out;
/* Do device recognition, if needed. */
static ssize_t if (cdev->id.cu_type == 0) {
stlck_store(struct device *dev, const char *buf, size_t count) ccw_device_recognition(cdev);
{ wait_event(cdev->private->wait_q,
struct ccw_device *cdev = to_ccwdev(dev); dev_fsm_final_state(cdev));
int ret; }
ccw_device_set_online(cdev);
/* We don't care what was piped to the attribute 8) */
ret = ccw_device_stlck(cdev);
if (ret != 0) {
printk(KERN_WARNING
"Unconditional reserve failed on device %s, rc=%d\n",
dev->bus_id, ret);
return ret;
} }
out:
/* if (cdev->drv)
* Device was successfully unboxed. module_put(cdev->drv->owner);
* Trigger removal of stlck attribute and device recognition. atomic_set(&cdev->private->onoff, 0);
*/
INIT_WORK(&cdev->private->kick_work,
ccw_device_unbox_recog, (void *) cdev);
queue_work(ccw_device_work, &cdev->private->kick_work);
return count; return count;
} }
...@@ -403,33 +406,9 @@ static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL); ...@@ -403,33 +406,9 @@ static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL);
static DEVICE_ATTR(devtype, 0444, devtype_show, NULL); static DEVICE_ATTR(devtype, 0444, devtype_show, NULL);
static DEVICE_ATTR(cutype, 0444, cutype_show, NULL); static DEVICE_ATTR(cutype, 0444, cutype_show, NULL);
static DEVICE_ATTR(online, 0644, online_show, online_store); static DEVICE_ATTR(online, 0644, online_show, online_store);
static DEVICE_ATTR(steal_lock, 0200, NULL, stlck_store);
extern struct device_attribute dev_attr_cmb_enable; extern struct device_attribute dev_attr_cmb_enable;
static DEVICE_ATTR(availability, 0444, available_show, NULL); static DEVICE_ATTR(availability, 0444, available_show, NULL);
/* A device has been unboxed. Start device recognition. */
static void
ccw_device_unbox_recog(void *data)
{
struct ccw_device *cdev;
cdev = (struct ccw_device *)data;
if (!cdev)
return;
/* Remove stlck attribute. */
device_remove_file(&cdev->dev, &dev_attr_steal_lock);
spin_lock_irq(cdev->ccwlock);
/* Device is no longer boxed. */
cdev->private->state = DEV_STATE_NOT_OPER;
/* Finally start device recognition. */
ccw_device_recognition(cdev);
spin_unlock_irq(cdev->ccwlock);
}
static struct attribute * subch_attrs[] = { static struct attribute * subch_attrs[] = {
&dev_attr_chpids.attr, &dev_attr_chpids.attr,
&dev_attr_pimpampom.attr, &dev_attr_pimpampom.attr,
...@@ -471,22 +450,6 @@ device_remove_files(struct device *dev) ...@@ -471,22 +450,6 @@ device_remove_files(struct device *dev)
sysfs_remove_group(&dev->kobj, &ccwdev_attr_group); sysfs_remove_group(&dev->kobj, &ccwdev_attr_group);
} }
/*
* Add a "steal lock" attribute to boxed devices.
* This allows to trigger an unconditional reserve ccw to eckd dasds
* (if the device is something else, there should be no problems more than
* a command reject; we don't have any means of finding out the device's
* type if it was boxed at ipl/attach for older devices and under VM).
*/
void
ccw_device_add_stlck(void *data)
{
struct ccw_device *cdev;
cdev = (struct ccw_device *)data;
device_create_file(&cdev->dev, &dev_attr_steal_lock);
}
/* this is a simple abstraction for device_register that sets the /* this is a simple abstraction for device_register that sets the
* correct bus type and adds the bus specific files */ * correct bus type and adds the bus specific files */
int int
...@@ -565,8 +528,6 @@ io_subchannel_register(void *data) ...@@ -565,8 +528,6 @@ io_subchannel_register(void *data)
if (ret) if (ret)
printk(KERN_WARNING "%s: could not add attributes to %s\n", printk(KERN_WARNING "%s: could not add attributes to %s\n",
__func__, sch->dev.bus_id); __func__, sch->dev.bus_id);
if (cdev->private->state == DEV_STATE_BOXED)
device_create_file(&cdev->dev, &dev_attr_steal_lock);
put_device(&cdev->dev); put_device(&cdev->dev);
out: out:
put_device(&sch->dev); put_device(&sch->dev);
...@@ -935,6 +896,7 @@ ccw_device_remove (struct device *dev) ...@@ -935,6 +896,7 @@ ccw_device_remove (struct device *dev)
pr_debug("ccw_device_offline returned %d, device %s\n", pr_debug("ccw_device_offline returned %d, device %s\n",
ret, cdev->dev.bus_id); ret, cdev->dev.bus_id);
} }
ccw_device_set_timeout(cdev, 0);
cdev->drv = 0; cdev->drv = 0;
return 0; return 0;
} }
......
...@@ -102,7 +102,6 @@ void ccw_device_disband_done(struct ccw_device *, int); ...@@ -102,7 +102,6 @@ void ccw_device_disband_done(struct ccw_device *, int);
int ccw_device_call_handler(struct ccw_device *); int ccw_device_call_handler(struct ccw_device *);
void ccw_device_add_stlck(void *);
int ccw_device_stlck(struct ccw_device *); int ccw_device_stlck(struct ccw_device *);
/* qdio needs this. */ /* qdio needs this. */
......
...@@ -317,14 +317,10 @@ ccw_device_done(struct ccw_device *cdev, int state) ...@@ -317,14 +317,10 @@ ccw_device_done(struct ccw_device *cdev, int state)
cdev->private->state = state; cdev->private->state = state;
if (state == DEV_STATE_BOXED) { if (state == DEV_STATE_BOXED)
CIO_DEBUG(KERN_WARNING, 2, CIO_DEBUG(KERN_WARNING, 2,
"Boxed device %04x on subchannel %04x\n", "Boxed device %04x on subchannel %04x\n",
cdev->private->devno, sch->irq); cdev->private->devno, sch->irq);
INIT_WORK(&cdev->private->kick_work,
ccw_device_add_stlck, (void *) cdev);
queue_work(ccw_device_work, &cdev->private->kick_work);
}
if (cdev->private->flags.donotify) { if (cdev->private->flags.donotify) {
cdev->private->flags.donotify = 0; cdev->private->flags.donotify = 0;
...@@ -377,7 +373,8 @@ ccw_device_recognition(struct ccw_device *cdev) ...@@ -377,7 +373,8 @@ ccw_device_recognition(struct ccw_device *cdev)
struct subchannel *sch; struct subchannel *sch;
int ret; int ret;
if (cdev->private->state != DEV_STATE_NOT_OPER) if ((cdev->private->state != DEV_STATE_NOT_OPER) &&
(cdev->private->state != DEV_STATE_BOXED))
return -EINVAL; return -EINVAL;
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc); ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc);
...@@ -492,7 +489,8 @@ ccw_device_online(struct ccw_device *cdev) ...@@ -492,7 +489,8 @@ ccw_device_online(struct ccw_device *cdev)
struct subchannel *sch; struct subchannel *sch;
int ret; int ret;
if (cdev->private->state != DEV_STATE_OFFLINE) if ((cdev->private->state != DEV_STATE_OFFLINE) &&
(cdev->private->state != DEV_STATE_BOXED))
return -EINVAL; return -EINVAL;
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
if (css_init_done && !get_device(&cdev->dev)) if (css_init_done && !get_device(&cdev->dev))
...@@ -615,6 +613,13 @@ ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -615,6 +613,13 @@ ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event)
struct subchannel *sch; struct subchannel *sch;
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
if (sch->driver->notify &&
sch->driver->notify(&sch->dev, sch->lpm ? CIO_GONE : CIO_NO_PATH)) {
ccw_device_set_timeout(cdev, 0);
cdev->private->state = DEV_STATE_DISCONNECTED;
wake_up(&cdev->private->wait_q);
return;
}
cdev->private->state = DEV_STATE_NOT_OPER; cdev->private->state = DEV_STATE_NOT_OPER;
cio_disable_subchannel(sch); cio_disable_subchannel(sch);
if (sch->schib.scsw.actl != 0) { if (sch->schib.scsw.actl != 0) {
...@@ -627,21 +632,6 @@ ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -627,21 +632,6 @@ ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event)
wake_up(&cdev->private->wait_q); wake_up(&cdev->private->wait_q);
} }
static void
ccw_device_disconnected_notoper(struct ccw_device *cdev,
enum dev_event dev_event)
{
struct subchannel *sch;
sch = to_subchannel(cdev->dev.parent);
cdev->private->state = DEV_STATE_NOT_OPER;
cio_disable_subchannel(sch);
device_unregister(&sch->dev);
sch->schib.pmcw.intparm = 0;
cio_modify(sch);
wake_up(&cdev->private->wait_q);
}
/* /*
* Handle path verification event. * Handle path verification event.
*/ */
...@@ -1103,7 +1093,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { ...@@ -1103,7 +1093,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
}, },
/* special states for devices gone not operational */ /* special states for devices gone not operational */
[DEV_STATE_DISCONNECTED] { [DEV_STATE_DISCONNECTED] {
[DEV_EVENT_NOTOPER] ccw_device_disconnected_notoper, [DEV_EVENT_NOTOPER] ccw_device_nop,
[DEV_EVENT_INTERRUPT] ccw_device_start_id, [DEV_EVENT_INTERRUPT] ccw_device_start_id,
[DEV_EVENT_TIMEOUT] ccw_device_bug, [DEV_EVENT_TIMEOUT] ccw_device_bug,
[DEV_EVENT_VERIFY] ccw_device_nop, [DEV_EVENT_VERIFY] ccw_device_nop,
......
...@@ -38,6 +38,7 @@ ccw_device_set_options(struct ccw_device *cdev, unsigned long flags) ...@@ -38,6 +38,7 @@ ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
cdev->private->options.fast = (flags & CCWDEV_EARLY_NOTIFICATION) != 0; cdev->private->options.fast = (flags & CCWDEV_EARLY_NOTIFICATION) != 0;
cdev->private->options.repall = (flags & CCWDEV_REPORT_ALL) != 0; cdev->private->options.repall = (flags & CCWDEV_REPORT_ALL) != 0;
cdev->private->options.pgroup = (flags & CCWDEV_DO_PATHGROUP) != 0; cdev->private->options.pgroup = (flags & CCWDEV_DO_PATHGROUP) != 0;
cdev->private->options.force = (flags & CCWDEV_ALLOW_FORCE) != 0;
return 0; return 0;
} }
...@@ -453,6 +454,9 @@ ccw_device_stlck(struct ccw_device *cdev) ...@@ -453,6 +454,9 @@ ccw_device_stlck(struct ccw_device *cdev)
if (!cdev) if (!cdev)
return -ENODEV; return -ENODEV;
if (cdev->drv && !cdev->private->options.force)
return -EINVAL;
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
CIO_TRACE_EVENT(2, "stl lock"); CIO_TRACE_EVENT(2, "stl lock");
......
/* /*
* $Id: ctcmain.c,v 1.54 2004/02/18 12:35:59 ptiedem Exp $ * $Id: ctcmain.c,v 1.56 2004/02/27 17:53:26 mschwide Exp $
* *
* CTC / ESCON network driver * CTC / ESCON network driver
* *
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *
* RELEASE-TAG: CTC/ESCON network driver $Revision: 1.54 $ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.56 $
* *
*/ */
...@@ -319,7 +319,7 @@ static void ...@@ -319,7 +319,7 @@ static void
print_banner(void) print_banner(void)
{ {
static int printed = 0; static int printed = 0;
char vbuf[] = "$Revision: 1.54 $"; char vbuf[] = "$Revision: 1.56 $";
char *version = vbuf; char *version = vbuf;
if (printed) if (printed)
...@@ -3161,6 +3161,7 @@ ctc_remove_device(struct ccwgroup_device *cgdev) ...@@ -3161,6 +3161,7 @@ ctc_remove_device(struct ccwgroup_device *cgdev)
} }
static struct ccwgroup_driver ctc_group_driver = { static struct ccwgroup_driver ctc_group_driver = {
.owner = THIS_MODULE,
.name = "ctc", .name = "ctc",
.max_slaves = 2, .max_slaves = 2,
.driver_id = 0xC3E3C3, .driver_id = 0xC3E3C3,
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* Frank Pavlic (pavlic@de.ibm.com) and * Frank Pavlic (pavlic@de.ibm.com) and
* Martin Schwidefsky <schwidefsky@de.ibm.com> * Martin Schwidefsky <schwidefsky@de.ibm.com>
* *
* $Revision: 1.66 $ $Date: 2004/02/19 13:46:01 $ * $Revision: 1.67 $ $Date: 2004/02/26 18:26:50 $
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
/** /**
* initialization string for output * initialization string for output
*/ */
#define VERSION_LCS_C "$Revision: 1.66 $" #define VERSION_LCS_C "$Revision: 1.67 $"
static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")"; static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")";
...@@ -1926,6 +1926,7 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev) ...@@ -1926,6 +1926,7 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev)
* LCS ccwgroup driver registration * LCS ccwgroup driver registration
*/ */
static struct ccwgroup_driver lcs_group_driver = { static struct ccwgroup_driver lcs_group_driver = {
.owner = THIS_MODULE,
.name = "lcs", .name = "lcs",
.max_slaves = 2, .max_slaves = 2,
.driver_id = 0xD3C3E2, .driver_id = 0xD3C3E2,
......
...@@ -10773,6 +10773,7 @@ qeth_remove_device(struct ccwgroup_device *gdev) ...@@ -10773,6 +10773,7 @@ qeth_remove_device(struct ccwgroup_device *gdev)
} }
static struct ccwgroup_driver qeth_ccwgroup_driver = { static struct ccwgroup_driver qeth_ccwgroup_driver = {
.owner = THIS_MODULE,
.name = "qeth", .name = "qeth",
.driver_id = 0xD8C5E3C8, .driver_id = 0xD8C5E3C8,
.probe = qeth_probe_device, .probe = qeth_probe_device,
......
...@@ -118,6 +118,8 @@ extern int ccw_device_set_options(struct ccw_device *, unsigned long); ...@@ -118,6 +118,8 @@ extern int ccw_device_set_options(struct ccw_device *, unsigned long);
#define CCWDEV_REPORT_ALL 0x0002 #define CCWDEV_REPORT_ALL 0x0002
/* Try to perform path grouping. */ /* Try to perform path grouping. */
#define CCWDEV_DO_PATHGROUP 0x0004 #define CCWDEV_DO_PATHGROUP 0x0004
/* Allow forced onlining of boxed devices. */
#define CCWDEV_ALLOW_FORCE 0x0008
/* /*
* ccw_device_start() * ccw_device_start()
......
...@@ -17,6 +17,7 @@ struct ccwgroup_device { ...@@ -17,6 +17,7 @@ struct ccwgroup_device {
}; };
struct ccwgroup_driver { struct ccwgroup_driver {
struct module *owner;
char *name; char *name;
int max_slaves; int max_slaves;
unsigned long driver_id; unsigned long driver_id;
......
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