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

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

[S390] cio: dont unregister a busy device in ccw_device_set_offline



If we detect a busy subchannel after the driver's set_offline
callback returned in ccw_device_set_offline, the current behavior
is to unregister the device, which may lead to undesired
consequences. Change this to just quiesce the subchannel and go on
with the offline processing.

Note: This is no excuse for not fixing these drivers -
after the set_offline callback they should have no running IO!

Signed-off-by: default avatarSebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent de1b0438
Loading
Loading
Loading
Loading
+20 −9
Original line number Diff line number Diff line
@@ -314,6 +314,8 @@ static void ccw_device_unregister(struct ccw_device *cdev)
	}
}

static void io_subchannel_quiesce(struct subchannel *);

/**
 * ccw_device_set_offline() - disable a ccw device for I/O
 * @cdev: target ccw device
@@ -327,7 +329,8 @@ static void ccw_device_unregister(struct ccw_device *cdev)
 */
int ccw_device_set_offline(struct ccw_device *cdev)
{
	int ret;
	struct subchannel *sch;
	int ret, state;

	if (!cdev)
		return -ENODEV;
@@ -341,6 +344,7 @@ int ccw_device_set_offline(struct ccw_device *cdev)
	}
	cdev->online = 0;
	spin_lock_irq(cdev->ccwlock);
	sch = to_subchannel(cdev->dev.parent);
	/* Wait until a final state or DISCONNECTED is reached */
	while (!dev_fsm_final_state(cdev) &&
	       cdev->private->state != DEV_STATE_DISCONNECTED) {
@@ -349,9 +353,21 @@ int ccw_device_set_offline(struct ccw_device *cdev)
			   cdev->private->state == DEV_STATE_DISCONNECTED));
		spin_lock_irq(cdev->ccwlock);
	}
	do {
		ret = ccw_device_offline(cdev);
	if (ret)
		if (!ret)
			break;
		CIO_MSG_EVENT(0, "ccw_device_offline returned %d, device "
			      "0.%x.%04x\n", ret, cdev->private->dev_id.ssid,
			      cdev->private->dev_id.devno);
		if (ret != -EBUSY)
			goto error;
		state = cdev->private->state;
		spin_unlock_irq(cdev->ccwlock);
		io_subchannel_quiesce(sch);
		spin_lock_irq(cdev->ccwlock);
		cdev->private->state = state;
	} while (ret == -EBUSY);
	spin_unlock_irq(cdev->ccwlock);
	wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) ||
		   cdev->private->state == DEV_STATE_DISCONNECTED));
@@ -368,9 +384,6 @@ int ccw_device_set_offline(struct ccw_device *cdev)
	return 0;

error:
	CIO_MSG_EVENT(0, "ccw_device_offline returned %d, device 0.%x.%04x\n",
		      ret, cdev->private->dev_id.ssid,
		      cdev->private->dev_id.devno);
	cdev->private->state = DEV_STATE_OFFLINE;
	dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
	spin_unlock_irq(cdev->ccwlock);
@@ -1059,8 +1072,6 @@ static int io_subchannel_probe(struct subchannel *sch)
	return 0;
}

static void io_subchannel_quiesce(struct subchannel *);

static int
io_subchannel_remove (struct subchannel *sch)
{