lkml.org 
[lkml]   [2009]   [Nov]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[patch 28/52] [PATCH] cio: introduce parent-initiated device move
    From: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>

    Change the initiative to update subchannel-ccw device associations
    to the subchannel: when there is an indication that the internal
    association no longer reflects the current hardware state, mark
    each affected subchannel as requiring attention. Once processing
    reaches a subchannel, determine the correct association for that
    subchannel at that time and perform the necessary device_move
    operations.

    This change fixes problems with the previous approach which would
    leave devices in an inconsistent state when a new hardware change
    occurred while a device_move was already scheduled.

    Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    ---

    drivers/s390/cio/css.c | 9
    drivers/s390/cio/device.c | 515 ++++++++++++++----------------------------
    drivers/s390/cio/device_fsm.c | 8
    3 files changed, 193 insertions(+), 339 deletions(-)

    Index: quilt-2.6/drivers/s390/cio/css.c
    ===================================================================
    --- quilt-2.6.orig/drivers/s390/cio/css.c 2009-11-13 15:48:33.000000000 +0100
    +++ quilt-2.6/drivers/s390/cio/css.c 2009-11-13 16:08:18.000000000 +0100
    @@ -376,8 +376,8 @@
    /* Unusable - ignore. */
    return 0;
    }
    - CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, unknown, "
    - "slow path.\n", schid.ssid, schid.sch_no, CIO_OPER);
    + CIO_MSG_EVENT(4, "event: sch 0.%x.%04x, new\n", schid.ssid,
    + schid.sch_no);

    return css_probe_device(schid);
    }
    @@ -394,6 +394,10 @@
    "Got subchannel machine check but "
    "no sch_event handler provided.\n");
    }
    + if (ret != 0 && ret != -EAGAIN) {
    + CIO_MSG_EVENT(2, "eval: sch 0.%x.%04x, rc=%d\n",
    + sch->schid.ssid, sch->schid.sch_no, ret);
    + }
    return ret;
    }

    @@ -684,6 +688,7 @@
    css->pseudo_subchannel->dev.parent = &css->device;
    css->pseudo_subchannel->dev.release = css_subchannel_release;
    dev_set_name(&css->pseudo_subchannel->dev, "defunct");
    + mutex_init(&css->pseudo_subchannel->reg_mutex);
    ret = cio_create_sch_lock(css->pseudo_subchannel);
    if (ret) {
    kfree(css->pseudo_subchannel);
    Index: quilt-2.6/drivers/s390/cio/device.c
    ===================================================================
    --- quilt-2.6.orig/drivers/s390/cio/device.c 2009-11-13 16:08:17.000000000 +0100
    +++ quilt-2.6/drivers/s390/cio/device.c 2009-11-13 16:08:18.000000000 +0100
    @@ -673,57 +673,19 @@
    return ret;
    }

    -struct match_data {
    - struct ccw_dev_id dev_id;
    - struct ccw_device * sibling;
    -};
    -
    -static int
    -match_devno(struct device * dev, void * data)
    -{
    - struct match_data * d = data;
    - struct ccw_device * cdev;
    -
    - cdev = to_ccwdev(dev);
    - if ((cdev->private->state == DEV_STATE_DISCONNECTED) &&
    - !ccw_device_is_orphan(cdev) &&
    - ccw_dev_id_is_equal(&cdev->private->dev_id, &d->dev_id) &&
    - (cdev != d->sibling))
    - return 1;
    - return 0;
    -}
    -
    -static struct ccw_device * get_disc_ccwdev_by_dev_id(struct ccw_dev_id *dev_id,
    - struct ccw_device *sibling)
    +static int match_dev_id(struct device *dev, void *data)
    {
    - struct device *dev;
    - struct match_data data;
    -
    - data.dev_id = *dev_id;
    - data.sibling = sibling;
    - dev = bus_find_device(&ccw_bus_type, NULL, &data, match_devno);
    -
    - return dev ? to_ccwdev(dev) : NULL;
    -}
    -
    -static int match_orphan(struct device *dev, void *data)
    -{
    - struct ccw_dev_id *dev_id;
    - struct ccw_device *cdev;
    + struct ccw_device *cdev = to_ccwdev(dev);
    + struct ccw_dev_id *dev_id = data;

    - dev_id = data;
    - cdev = to_ccwdev(dev);
    return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id);
    }

    -static struct ccw_device *
    -get_orphaned_ccwdev_by_dev_id(struct channel_subsystem *css,
    - struct ccw_dev_id *dev_id)
    +static struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id)
    {
    struct device *dev;

    - dev = device_find_child(&css->pseudo_subchannel->dev, dev_id,
    - match_orphan);
    + dev = bus_find_device(&ccw_bus_type, NULL, dev_id, match_dev_id);

    return dev ? to_ccwdev(dev) : NULL;
    }
    @@ -808,75 +770,6 @@

    static int io_subchannel_recog(struct ccw_device *, struct subchannel *);

    -static void sch_attach_device(struct subchannel *sch,
    - struct ccw_device *cdev)
    -{
    - css_update_ssd_info(sch);
    - spin_lock_irq(sch->lock);
    - sch_set_cdev(sch, cdev);
    - cdev->private->schid = sch->schid;
    - cdev->ccwlock = sch->lock;
    - ccw_device_trigger_reprobe(cdev);
    - spin_unlock_irq(sch->lock);
    -}
    -
    -static void sch_attach_disconnected_device(struct subchannel *sch,
    - struct ccw_device *cdev)
    -{
    - struct subchannel *other_sch;
    - int ret;
    -
    - /* Get reference for new parent. */
    - if (!get_device(&sch->dev))
    - return;
    - other_sch = to_subchannel(cdev->dev.parent);
    - /* Note: device_move() changes cdev->dev.parent */
    - ret = device_move(&cdev->dev, &sch->dev, DPM_ORDER_PARENT_BEFORE_DEV);
    - if (ret) {
    - CIO_MSG_EVENT(0, "Moving disconnected device 0.%x.%04x failed "
    - "(ret=%d)!\n", cdev->private->dev_id.ssid,
    - cdev->private->dev_id.devno, ret);
    - /* Put reference for new parent. */
    - put_device(&sch->dev);
    - return;
    - }
    - sch_set_cdev(other_sch, NULL);
    - /* No need to keep a subchannel without ccw device around. */
    - css_sch_device_unregister(other_sch);
    - sch_attach_device(sch, cdev);
    - /* Put reference for old parent. */
    - put_device(&other_sch->dev);
    -}
    -
    -static void sch_attach_orphaned_device(struct subchannel *sch,
    - struct ccw_device *cdev)
    -{
    - int ret;
    - struct subchannel *pseudo_sch;
    -
    - /* Get reference for new parent. */
    - if (!get_device(&sch->dev))
    - return;
    - pseudo_sch = to_subchannel(cdev->dev.parent);
    - /*
    - * Try to move the ccw device to its new subchannel.
    - * Note: device_move() changes cdev->dev.parent
    - */
    - ret = device_move(&cdev->dev, &sch->dev, DPM_ORDER_PARENT_BEFORE_DEV);
    - if (ret) {
    - CIO_MSG_EVENT(0, "Moving device 0.%x.%04x from orphanage "
    - "failed (ret=%d)!\n",
    - cdev->private->dev_id.ssid,
    - cdev->private->dev_id.devno, ret);
    - /* Put reference for new parent. */
    - put_device(&sch->dev);
    - return;
    - }
    - sch_attach_device(sch, cdev);
    - /* Put reference on pseudo subchannel. */
    - put_device(&pseudo_sch->dev);
    -}
    -
    static void sch_create_and_recog_new_device(struct subchannel *sch)
    {
    struct ccw_device *cdev;
    @@ -901,70 +794,6 @@
    }
    }

    -
    -void ccw_device_move_to_orphanage(struct work_struct *work)
    -{
    - struct ccw_device_private *priv;
    - struct ccw_device *cdev;
    - struct ccw_device *replacing_cdev;
    - struct subchannel *sch;
    - int ret;
    - struct channel_subsystem *css;
    - struct ccw_dev_id dev_id;
    -
    - priv = container_of(work, struct ccw_device_private, kick_work);
    - cdev = priv->cdev;
    - sch = to_subchannel(cdev->dev.parent);
    - css = to_css(sch->dev.parent);
    - dev_id.devno = sch->schib.pmcw.dev;
    - dev_id.ssid = sch->schid.ssid;
    -
    - /* Increase refcount for pseudo subchannel. */
    - get_device(&css->pseudo_subchannel->dev);
    - /*
    - * Move the orphaned ccw device to the orphanage so the replacing
    - * ccw device can take its place on the subchannel.
    - * Note: device_move() changes cdev->dev.parent
    - */
    - ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev,
    - DPM_ORDER_NONE);
    - if (ret) {
    - CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to orphanage failed "
    - "(ret=%d)!\n", cdev->private->dev_id.ssid,
    - cdev->private->dev_id.devno, ret);
    - /* Decrease refcount for pseudo subchannel again. */
    - put_device(&css->pseudo_subchannel->dev);
    - return;
    - }
    - cdev->ccwlock = css->pseudo_subchannel->lock;
    - /*
    - * Search for the replacing ccw device
    - * - among the disconnected devices
    - * - in the orphanage
    - */
    - replacing_cdev = get_disc_ccwdev_by_dev_id(&dev_id, cdev);
    - if (replacing_cdev) {
    - sch_attach_disconnected_device(sch, replacing_cdev);
    - /* Release reference from get_disc_ccwdev_by_dev_id() */
    - put_device(&replacing_cdev->dev);
    - /* Release reference of subchannel from old cdev. */
    - put_device(&sch->dev);
    - return;
    - }
    - replacing_cdev = get_orphaned_ccwdev_by_dev_id(css, &dev_id);
    - if (replacing_cdev) {
    - sch_attach_orphaned_device(sch, replacing_cdev);
    - /* Release reference from get_orphaned_ccwdev_by_dev_id() */
    - put_device(&replacing_cdev->dev);
    - /* Release reference of subchannel from old cdev. */
    - put_device(&sch->dev);
    - return;
    - }
    - sch_create_and_recog_new_device(sch);
    - /* Release reference of subchannel from old cdev. */
    - put_device(&sch->dev);
    -}
    -
    /*
    * Register recognized device.
    */
    @@ -1131,53 +960,56 @@
    return rc;
    }

    -static void ccw_device_move_to_sch(struct work_struct *work)
    +static int ccw_device_move_to_sch(struct ccw_device *cdev,
    + struct subchannel *sch)
    {
    - struct ccw_device_private *priv;
    + struct subchannel *old_sch;
    int rc;
    - struct subchannel *sch;
    - struct ccw_device *cdev;
    - struct subchannel *former_parent;

    - priv = container_of(work, struct ccw_device_private, kick_work);
    - sch = priv->sch;
    - cdev = priv->cdev;
    - former_parent = to_subchannel(cdev->dev.parent);
    - /* Get reference for new parent. */
    + old_sch = to_subchannel(cdev->dev.parent);
    + /* Obtain child reference for new parent. */
    if (!get_device(&sch->dev))
    - return;
    + return -ENODEV;
    mutex_lock(&sch->reg_mutex);
    - /*
    - * Try to move the ccw device to its new subchannel.
    - * Note: device_move() changes cdev->dev.parent
    - */
    rc = device_move(&cdev->dev, &sch->dev, DPM_ORDER_PARENT_BEFORE_DEV);
    mutex_unlock(&sch->reg_mutex);
    if (rc) {
    - CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to subchannel "
    - "0.%x.%04x failed (ret=%d)!\n",
    + CIO_MSG_EVENT(0, "device_move(0.%x.%04x,0.%x.%04x)=%d\n",
    cdev->private->dev_id.ssid,
    cdev->private->dev_id.devno, sch->schid.ssid,
    - sch->schid.sch_no, rc);
    - css_sch_device_unregister(sch);
    - /* Put reference for new parent again. */
    + sch->schib.pmcw.dev, rc);
    + /* Release child reference for new parent. */
    put_device(&sch->dev);
    - goto out;
    - }
    - if (!sch_is_pseudo_sch(former_parent)) {
    - spin_lock_irq(former_parent->lock);
    - sch_set_cdev(former_parent, NULL);
    - spin_unlock_irq(former_parent->lock);
    - css_sch_device_unregister(former_parent);
    - /* Reset intparm to zeroes. */
    - former_parent->config.intparm = 0;
    - cio_commit_config(former_parent);
    + return rc;
    }
    - sch_attach_device(sch, cdev);
    -out:
    - /* Put reference for old parent. */
    - put_device(&former_parent->dev);
    - put_device(&cdev->dev);
    + /* Clean up old subchannel. */
    + if (!sch_is_pseudo_sch(old_sch)) {
    + spin_lock_irq(old_sch->lock);
    + sch_set_cdev(old_sch, NULL);
    + cio_disable_subchannel(old_sch);
    + spin_unlock_irq(old_sch->lock);
    + css_schedule_eval(old_sch->schid);
    + }
    + /* Release child reference for old parent. */
    + put_device(&old_sch->dev);
    + /* Initialize new subchannel. */
    + spin_lock_irq(sch->lock);
    + cdev->private->schid = sch->schid;
    + cdev->ccwlock = sch->lock;
    + if (!sch_is_pseudo_sch(sch))
    + sch_set_cdev(sch, cdev);
    + spin_unlock_irq(sch->lock);
    + if (!sch_is_pseudo_sch(sch))
    + css_update_ssd_info(sch);
    + return 0;
    +}
    +
    +static int ccw_device_move_to_orph(struct ccw_device *cdev)
    +{
    + struct subchannel *sch = to_subchannel(cdev->dev.parent);
    + struct channel_subsystem *css = to_css(sch->dev.parent);
    +
    + return ccw_device_move_to_sch(cdev, css->pseudo_subchannel);
    }

    static void io_subchannel_irq(struct subchannel *sch)
    @@ -1244,8 +1076,6 @@
    {
    struct ccw_device *cdev;
    int rc;
    - unsigned long flags;
    - struct ccw_dev_id dev_id;

    if (cio_is_console(sch->schid)) {
    rc = sysfs_create_group(&sch->dev.kobj,
    @@ -1290,37 +1120,7 @@
    GFP_KERNEL | GFP_DMA);
    if (!sch->private)
    goto out_schedule;
    - /*
    - * First check if a fitting device may be found amongst the
    - * disconnected devices or in the orphanage.
    - */
    - dev_id.devno = sch->schib.pmcw.dev;
    - dev_id.ssid = sch->schid.ssid;
    - cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL);
    - if (!cdev)
    - cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent),
    - &dev_id);
    - if (cdev) {
    - /*
    - * Schedule moving the device until when we have a registered
    - * subchannel to move to and succeed the probe. We can
    - * unregister later again, when the probe is through.
    - */
    - cdev->private->sch = sch;
    - PREPARE_WORK(&cdev->private->kick_work,
    - ccw_device_move_to_sch);
    - queue_work(slow_path_wq, &cdev->private->kick_work);
    - return 0;
    - }
    - cdev = io_subchannel_create_ccwdev(sch);
    - if (IS_ERR(cdev))
    - goto out_schedule;
    - rc = io_subchannel_recog(cdev, sch);
    - if (rc) {
    - spin_lock_irqsave(sch->lock, flags);
    - io_subchannel_recog_done(cdev);
    - spin_unlock_irqrestore(sch->lock, flags);
    - }
    + css_schedule_eval(sch->schid);
    return 0;

    out_schedule:
    @@ -1349,16 +1149,6 @@
    return 0;
    }

    -static int io_subchannel_notify(struct subchannel *sch, int event)
    -{
    - struct ccw_device *cdev;
    -
    - cdev = sch_get_cdev(sch);
    - if (!cdev)
    - return 0;
    - return ccw_device_notify(cdev, event);
    -}
    -
    static void io_subchannel_verify(struct subchannel *sch)
    {
    struct ccw_device *cdev;
    @@ -1482,19 +1272,6 @@
    cio_disable_subchannel(sch);
    }

    -static int io_subchannel_get_status(struct subchannel *sch)
    -{
    - struct schib schib;
    -
    - if (stsch(sch->schid, &schib) || !schib.pmcw.dnv)
    - return CIO_GONE;
    - if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev))
    - return CIO_REVALIDATE;
    - if (!sch->lpm)
    - return CIO_NO_PATH;
    - return CIO_OPER;
    -}
    -
    static int device_is_disconnected(struct ccw_device *cdev)
    {
    if (!cdev)
    @@ -1626,91 +1403,165 @@
    cdev->private->state = DEV_STATE_NOT_OPER;
    }

    -static int io_subchannel_sch_event(struct subchannel *sch, int slow)
    +enum io_sch_action {
    + IO_SCH_UNREG,
    + IO_SCH_ORPH_UNREG,
    + IO_SCH_ATTACH,
    + IO_SCH_UNREG_ATTACH,
    + IO_SCH_ORPH_ATTACH,
    + IO_SCH_REPROBE,
    + IO_SCH_VERIFY,
    + IO_SCH_DISC,
    + IO_SCH_NOP,
    +};
    +
    +static enum io_sch_action sch_get_action(struct subchannel *sch)
    +{
    + struct ccw_device *cdev;
    +
    + cdev = sch_get_cdev(sch);
    + if (cio_update_schib(sch)) {
    + /* Not operational. */
    + if (!cdev)
    + return IO_SCH_UNREG;
    + if (!ccw_device_notify(cdev, CIO_GONE))
    + return IO_SCH_UNREG;
    + return IO_SCH_ORPH_UNREG;
    + }
    + /* Operational. */
    + if (!cdev)
    + return IO_SCH_ATTACH;
    + if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
    + if (!ccw_device_notify(cdev, CIO_GONE))
    + return IO_SCH_UNREG_ATTACH;
    + return IO_SCH_ORPH_ATTACH;
    + }
    + if ((sch->schib.pmcw.pam & sch->opm) == 0) {
    + if (!ccw_device_notify(cdev, CIO_NO_PATH))
    + return IO_SCH_UNREG;
    + return IO_SCH_DISC;
    + }
    + if (device_is_disconnected(cdev))
    + return IO_SCH_REPROBE;
    + if (cdev->online)
    + return IO_SCH_VERIFY;
    + return IO_SCH_NOP;
    +}
    +
    +/**
    + * io_subchannel_sch_event - process subchannel event
    + * @sch: subchannel
    + * @process: non-zero if function is called in process context
    + *
    + * An unspecified event occurred for this subchannel. Adjust data according
    + * to the current operational state of the subchannel and device. Return
    + * zero when the event has been handled sufficiently or -EAGAIN when this
    + * function should be called again in process context.
    + */
    +static int io_subchannel_sch_event(struct subchannel *sch, int process)
    {
    - int event, ret, disc;
    unsigned long flags;
    - enum { NONE, UNREGISTER, UNREGISTER_PROBE, REPROBE, DISC } action;
    struct ccw_device *cdev;
    + struct ccw_dev_id dev_id;
    + enum io_sch_action action;
    + int rc = -EAGAIN;

    spin_lock_irqsave(sch->lock, flags);
    + if (!device_is_registered(&sch->dev))
    + goto out_unlock;
    + action = sch_get_action(sch);
    + CIO_MSG_EVENT(2, "event: sch 0.%x.%04x, process=%d, action=%d\n",
    + sch->schid.ssid, sch->schid.sch_no, process,
    + action);
    + /* Perform immediate actions while holding the lock. */
    cdev = sch_get_cdev(sch);
    - disc = device_is_disconnected(cdev);
    - if (disc && slow) {
    - /* Disconnected devices are evaluated directly only.*/
    - spin_unlock_irqrestore(sch->lock, flags);
    - return 0;
    - }
    - /* No interrupt after machine check - kill pending timers. */
    - if (cdev)
    - ccw_device_set_timeout(cdev, 0);
    - if (!disc && !slow) {
    - /* Non-disconnected devices are evaluated on the slow path. */
    - spin_unlock_irqrestore(sch->lock, flags);
    - return -EAGAIN;
    + switch (action) {
    + case IO_SCH_REPROBE:
    + /* Trigger device recognition. */
    + ccw_device_trigger_reprobe(cdev);
    + rc = 0;
    + goto out_unlock;
    + case IO_SCH_VERIFY:
    + /* Trigger path verification. */
    + io_subchannel_verify(sch);
    + rc = 0;
    + goto out_unlock;
    + case IO_SCH_DISC:
    + ccw_device_set_disconnected(cdev);
    + rc = 0;
    + goto out_unlock;
    + case IO_SCH_ORPH_UNREG:
    + case IO_SCH_ORPH_ATTACH:
    + ccw_device_set_disconnected(cdev);
    + break;
    + case IO_SCH_UNREG_ATTACH:
    + case IO_SCH_UNREG:
    + if (cdev)
    + ccw_device_set_notoper(cdev);
    + break;
    + case IO_SCH_NOP:
    + rc = 0;
    + goto out_unlock;
    + default:
    + break;
    }
    - event = io_subchannel_get_status(sch);
    - CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, %s, %s path.\n",
    - sch->schid.ssid, sch->schid.sch_no, event,
    - disc ? "disconnected" : "normal",
    - slow ? "slow" : "fast");
    - /* Analyze subchannel status. */
    - action = NONE;
    - switch (event) {
    - case CIO_NO_PATH:
    - if (disc) {
    - /* Check if paths have become available. */
    - action = REPROBE;
    - break;
    - }
    - /* fall through */
    - case CIO_GONE:
    - /* Ask driver what to do with device. */
    - if (io_subchannel_notify(sch, event))
    - action = DISC;
    - else
    - action = UNREGISTER;
    + spin_unlock_irqrestore(sch->lock, flags);
    + /* All other actions require process context. */
    + if (!process)
    + goto out;
    + /* Handle attached ccw device. */
    + switch (action) {
    + case IO_SCH_ORPH_UNREG:
    + case IO_SCH_ORPH_ATTACH:
    + /* Move ccw device to orphanage. */
    + rc = ccw_device_move_to_orph(cdev);
    + if (rc)
    + goto out;
    break;
    - case CIO_REVALIDATE:
    - /* Device will be removed, so no notify necessary. */
    - if (disc)
    - /* Reprobe because immediate unregister might block. */
    - action = REPROBE;
    - else
    - action = UNREGISTER_PROBE;
    + case IO_SCH_UNREG_ATTACH:
    + /* Unregister ccw device. */
    + ccw_device_unregister(cdev);
    break;
    - case CIO_OPER:
    - if (disc)
    - /* Get device operational again. */
    - action = REPROBE;
    + default:
    break;
    }
    - /* Perform action. */
    - ret = 0;
    + /* Handle subchannel. */
    switch (action) {
    - case UNREGISTER:
    - case UNREGISTER_PROBE:
    - ccw_device_set_notoper(cdev);
    - /* Unregister device (will use subchannel lock). */
    - spin_unlock_irqrestore(sch->lock, flags);
    + case IO_SCH_ORPH_UNREG:
    + case IO_SCH_UNREG:
    css_sch_device_unregister(sch);
    - spin_lock_irqsave(sch->lock, flags);
    break;
    - case REPROBE:
    + case IO_SCH_ORPH_ATTACH:
    + case IO_SCH_UNREG_ATTACH:
    + case IO_SCH_ATTACH:
    + dev_id.ssid = sch->schid.ssid;
    + dev_id.devno = sch->schib.pmcw.dev;
    + cdev = get_ccwdev_by_dev_id(&dev_id);
    + if (!cdev) {
    + sch_create_and_recog_new_device(sch);
    + break;
    + }
    + rc = ccw_device_move_to_sch(cdev, sch);
    + if (rc) {
    + /* Release reference from get_ccwdev_by_dev_id() */
    + put_device(&cdev->dev);
    + goto out;
    + }
    + spin_lock_irqsave(sch->lock, flags);
    ccw_device_trigger_reprobe(cdev);
    - break;
    - case DISC:
    - ccw_device_set_disconnected(cdev);
    + spin_unlock_irqrestore(sch->lock, flags);
    + /* Release reference from get_ccwdev_by_dev_id() */
    + put_device(&cdev->dev);
    break;
    default:
    break;
    }
    - spin_unlock_irqrestore(sch->lock, flags);
    - /* Probe if necessary. */
    - if (action == UNREGISTER_PROBE)
    - ret = css_probe_device(sch->schid);
    + return 0;

    - return ret;
    +out_unlock:
    + spin_unlock_irqrestore(sch->lock, flags);
    +out:
    + return rc;
    }

    #ifdef CONFIG_CCW_CONSOLE
    Index: quilt-2.6/drivers/s390/cio/device_fsm.c
    ===================================================================
    --- quilt-2.6.orig/drivers/s390/cio/device_fsm.c 2009-11-13 15:48:33.000000000 +0100
    +++ quilt-2.6/drivers/s390/cio/device_fsm.c 2009-11-13 16:08:18.000000000 +0100
    @@ -1072,11 +1072,9 @@

    /* We should also udate ssd info, but this has to wait. */
    /* Check if this is another device which appeared on the same sch. */
    - if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
    - PREPARE_WORK(&cdev->private->kick_work,
    - ccw_device_move_to_orphanage);
    - queue_work(slow_path_wq, &cdev->private->kick_work);
    - } else
    + if (sch->schib.pmcw.dev != cdev->private->dev_id.devno)
    + css_schedule_eval(sch->schid);
    + else
    ccw_device_start_id(cdev, 0);
    }



    \
     
     \ /
      Last update: 2009-11-13 16:25    [W:0.080 / U:214.232 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site