|
@@ -334,20 +334,29 @@ ccw_device_oper_notify(struct work_struct *work)
|
|
|
struct ccw_device *cdev;
|
|
|
struct subchannel *sch;
|
|
|
int ret;
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
priv = container_of(work, struct ccw_device_private, kick_work);
|
|
|
cdev = priv->cdev;
|
|
|
+ spin_lock_irqsave(cdev->ccwlock, flags);
|
|
|
sch = to_subchannel(cdev->dev.parent);
|
|
|
- ret = (sch->driver && sch->driver->notify) ?
|
|
|
- sch->driver->notify(&sch->dev, CIO_OPER) : 0;
|
|
|
- if (!ret)
|
|
|
- /* Driver doesn't want device back. */
|
|
|
- ccw_device_do_unreg_rereg(work);
|
|
|
- else {
|
|
|
+ if (sch->driver && sch->driver->notify) {
|
|
|
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
|
|
|
+ ret = sch->driver->notify(&sch->dev, CIO_OPER);
|
|
|
+ spin_lock_irqsave(cdev->ccwlock, flags);
|
|
|
+ } else
|
|
|
+ ret = 0;
|
|
|
+ if (ret) {
|
|
|
/* Reenable channel measurements, if needed. */
|
|
|
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
|
|
|
cmf_reenable(cdev);
|
|
|
+ spin_lock_irqsave(cdev->ccwlock, flags);
|
|
|
wake_up(&cdev->private->wait_q);
|
|
|
}
|
|
|
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
|
|
|
+ if (!ret)
|
|
|
+ /* Driver doesn't want device back. */
|
|
|
+ ccw_device_do_unreg_rereg(work);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -534,15 +543,21 @@ ccw_device_nopath_notify(struct work_struct *work)
|
|
|
struct ccw_device *cdev;
|
|
|
struct subchannel *sch;
|
|
|
int ret;
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
priv = container_of(work, struct ccw_device_private, kick_work);
|
|
|
cdev = priv->cdev;
|
|
|
+ spin_lock_irqsave(cdev->ccwlock, flags);
|
|
|
sch = to_subchannel(cdev->dev.parent);
|
|
|
/* Extra sanity. */
|
|
|
if (sch->lpm)
|
|
|
- return;
|
|
|
- ret = (sch->driver && sch->driver->notify) ?
|
|
|
- sch->driver->notify(&sch->dev, CIO_NO_PATH) : 0;
|
|
|
+ goto out_unlock;
|
|
|
+ if (sch->driver && sch->driver->notify) {
|
|
|
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
|
|
|
+ ret = sch->driver->notify(&sch->dev, CIO_NO_PATH);
|
|
|
+ spin_lock_irqsave(cdev->ccwlock, flags);
|
|
|
+ } else
|
|
|
+ ret = 0;
|
|
|
if (!ret) {
|
|
|
if (get_device(&sch->dev)) {
|
|
|
/* Driver doesn't want to keep device. */
|
|
@@ -562,6 +577,8 @@ ccw_device_nopath_notify(struct work_struct *work)
|
|
|
cdev->private->state = DEV_STATE_DISCONNECTED;
|
|
|
wake_up(&cdev->private->wait_q);
|
|
|
}
|
|
|
+out_unlock:
|
|
|
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
|
|
|
}
|
|
|
|
|
|
void
|
|
@@ -607,10 +624,13 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
|
|
|
default:
|
|
|
/* Reset oper notify indication after verify error. */
|
|
|
cdev->private->flags.donotify = 0;
|
|
|
- PREPARE_WORK(&cdev->private->kick_work,
|
|
|
- ccw_device_nopath_notify);
|
|
|
- queue_work(ccw_device_notify_work, &cdev->private->kick_work);
|
|
|
- ccw_device_done(cdev, DEV_STATE_NOT_OPER);
|
|
|
+ if (cdev->online) {
|
|
|
+ PREPARE_WORK(&cdev->private->kick_work,
|
|
|
+ ccw_device_nopath_notify);
|
|
|
+ queue_work(ccw_device_notify_work,
|
|
|
+ &cdev->private->kick_work);
|
|
|
+ } else
|
|
|
+ ccw_device_done(cdev, DEV_STATE_NOT_OPER);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
@@ -756,15 +776,22 @@ static void
|
|
|
ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event)
|
|
|
{
|
|
|
struct subchannel *sch;
|
|
|
+ int ret;
|
|
|
|
|
|
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->flags.fake_irb = 0;
|
|
|
- cdev->private->state = DEV_STATE_DISCONNECTED;
|
|
|
- wake_up(&cdev->private->wait_q);
|
|
|
- return;
|
|
|
+ if (sch->driver->notify) {
|
|
|
+ spin_unlock_irq(cdev->ccwlock);
|
|
|
+ ret = sch->driver->notify(&sch->dev,
|
|
|
+ sch->lpm ? CIO_GONE : CIO_NO_PATH);
|
|
|
+ spin_lock_irq(cdev->ccwlock);
|
|
|
+ } else
|
|
|
+ ret = 0;
|
|
|
+ if (ret) {
|
|
|
+ ccw_device_set_timeout(cdev, 0);
|
|
|
+ cdev->private->flags.fake_irb = 0;
|
|
|
+ cdev->private->state = DEV_STATE_DISCONNECTED;
|
|
|
+ wake_up(&cdev->private->wait_q);
|
|
|
+ return;
|
|
|
}
|
|
|
cdev->private->state = DEV_STATE_NOT_OPER;
|
|
|
cio_disable_subchannel(sch);
|