Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d01bb89 authored by Sebastian Ott's avatar Sebastian Ott Committed by Martin Schwidefsky
Browse files

[S390] cio: trigger subchannel event at resume time



ccw_device_pm_restore: trigger subchannel event to better handle
changes to the subchannel device.

Signed-off-by: default avatarSebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 76e6fb4b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1020,7 +1020,7 @@ static int css_settle(struct device_driver *drv, void *unused)
	return 0;
}

static inline int css_complete_work(void)
int css_complete_work(void)
{
	int ret;

+1 −0
Original line number Diff line number Diff line
@@ -146,6 +146,7 @@ extern struct channel_subsystem *channel_subsystems[];
/* Helper functions to build lists for the slow path. */
void css_schedule_eval(struct subchannel_id schid);
void css_schedule_eval_all(void);
int css_complete_work(void);

int sch_is_pseudo_sch(struct subchannel *);
struct schib;
+61 −50
Original line number Diff line number Diff line
@@ -1400,6 +1400,12 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
		rc = 0;
		goto out_unlock;
	case IO_SCH_VERIFY:
		if (cdev->private->flags.resuming == 1) {
			if (cio_enable_subchannel(sch, (u32)(addr_t)sch)) {
				ccw_device_set_notoper(cdev);
				break;
			}
		}
		/* Trigger path verification. */
		io_subchannel_verify(sch);
		rc = 0;
@@ -1438,6 +1444,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
		break;
	case IO_SCH_UNREG_ATTACH:
		/* Unregister ccw device. */
		if (!cdev->private->flags.resuming)
			ccw_device_unregister(cdev);
		break;
	default:
@@ -1447,6 +1454,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
	switch (action) {
	case IO_SCH_ORPH_UNREG:
	case IO_SCH_UNREG:
		if (!cdev || !cdev->private->flags.resuming)
			css_sch_device_unregister(sch);
		break;
	case IO_SCH_ORPH_ATTACH:
@@ -1769,20 +1777,36 @@ static void __ccw_device_pm_restore(struct ccw_device *cdev)
{
	struct subchannel *sch = to_subchannel(cdev->dev.parent);

	if (cio_is_console(sch->schid))
		goto out;
	spin_lock_irq(sch->lock);
	if (cio_is_console(sch->schid)) {
		cio_enable_subchannel(sch, (u32)(addr_t)sch);
		goto out_unlock;
	}
	/*
	 * While we were sleeping, devices may have gone or become
	 * available again. Kick re-detection.
	 */
	spin_lock_irq(sch->lock);
	cdev->private->flags.resuming = 1;
	css_schedule_eval(sch->schid);
	spin_unlock_irq(sch->lock);
	css_complete_work();

	/* cdev may have been moved to a different subchannel. */
	sch = to_subchannel(cdev->dev.parent);
	spin_lock_irq(sch->lock);
	if (cdev->private->state != DEV_STATE_ONLINE &&
	    cdev->private->state != DEV_STATE_OFFLINE)
		goto out_unlock;

	ccw_device_recognition(cdev);
	spin_unlock_irq(sch->lock);
	wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev) ||
		   cdev->private->state == DEV_STATE_DISCONNECTED);
out:
	spin_lock_irq(sch->lock);

out_unlock:
	cdev->private->flags.resuming = 0;
	spin_unlock_irq(sch->lock);
}

static int resume_handle_boxed(struct ccw_device *cdev)
@@ -1806,40 +1830,31 @@ static int resume_handle_disc(struct ccw_device *cdev)
static int ccw_device_pm_restore(struct device *dev)
{
	struct ccw_device *cdev = to_ccwdev(dev);
	struct subchannel *sch = to_subchannel(cdev->dev.parent);
	int ret = 0, cm_enabled;
	struct subchannel *sch;
	int ret = 0;

	__ccw_device_pm_restore(cdev);
	sch = to_subchannel(cdev->dev.parent);
	spin_lock_irq(sch->lock);
	if (cio_is_console(sch->schid)) {
		cio_enable_subchannel(sch, (u32)(addr_t)sch);
		spin_unlock_irq(sch->lock);
	if (cio_is_console(sch->schid))
		goto out_restore;
	}
	cdev->private->flags.donotify = 0;

	/* check recognition results */
	switch (cdev->private->state) {
	case DEV_STATE_OFFLINE:
	case DEV_STATE_ONLINE:
		cdev->private->flags.donotify = 0;
		break;
	case DEV_STATE_BOXED:
		ret = resume_handle_boxed(cdev);
		spin_unlock_irq(sch->lock);
		if (ret)
			goto out;
			goto out_unlock;
		goto out_restore;
	case DEV_STATE_DISCONNECTED:
		goto out_disc_unlock;
	default:
		goto out_unreg_unlock;
	}
	/* check if the device id has changed */
	if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
		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;
		ret = resume_handle_disc(cdev);
		if (ret)
			goto out_unlock;
		goto out_restore;
	}
	/* check if the device type has changed */
	if (!ccw_device_test_sense_data(cdev)) {
@@ -1848,24 +1863,30 @@ static int ccw_device_pm_restore(struct device *dev)
		ret = -ENODEV;
		goto out_unlock;
	}
	if (!cdev->online) {
		ret = 0;
	if (!cdev->online)
		goto out_unlock;
	}
	ret = ccw_device_online(cdev);
	if (ret)
		goto out_disc_unlock;

	cm_enabled = cdev->private->cmb != NULL;
	if (ccw_device_online(cdev)) {
		ret = resume_handle_disc(cdev);
		if (ret)
			goto out_unlock;
		goto out_restore;
	}
	spin_unlock_irq(sch->lock);

	wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
	if (cdev->private->state != DEV_STATE_ONLINE) {
	spin_lock_irq(sch->lock);
		goto out_disc_unlock;

	if (ccw_device_notify(cdev, CIO_OPER) == NOTIFY_BAD) {
		ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
		ret = -ENODEV;
		goto out_unlock;
	}
	if (cm_enabled) {

	/* reenable cmf, if needed */
	if (cdev->private->cmb) {
		spin_unlock_irq(sch->lock);
		ret = ccw_set_cmf(cdev, 1);
		spin_lock_irq(sch->lock);
		if (ret) {
			CIO_MSG_EVENT(2, "resume: cdev 0.%x.%04x: cmf failed "
				      "(rc=%d)\n", cdev->private->dev_id.ssid,
@@ -1875,21 +1896,11 @@ static int ccw_device_pm_restore(struct device *dev)
	}

out_restore:
	spin_unlock_irq(sch->lock);
	if (cdev->online && cdev->drv && cdev->drv->restore)
		ret = cdev->drv->restore(cdev);
out:
	return ret;

out_disc_unlock:
	ret = resume_handle_disc(cdev);
	spin_unlock_irq(sch->lock);
	if (ret)
		return ret;
	goto out_restore;

out_unreg_unlock:
	ccw_device_sched_todo(cdev, CDEV_TODO_UNREG_EVAL);
	ret = -ENODEV;
out_unlock:
	spin_unlock_irq(sch->lock);
	return ret;