aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Ott <sebott@linux.vnet.ibm.com>2009-12-07 06:51:41 -0500
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2009-12-07 06:51:33 -0500
commitd40f7b75a23d1e59b6ec9d6701231fd4c6992ac6 (patch)
tree74dc2947aea7aadc5a2ec81e70c5e41111f5d3ae
parentde1b04388f63cbddf91d9f6c50c29be7232881ca (diff)
[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: Sebastian Ott <sebott@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--drivers/s390/cio/device.c29
1 files changed, 20 insertions, 9 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index dc97cb9f227f..9fecfb4223a8 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -314,6 +314,8 @@ static void ccw_device_unregister(struct ccw_device *cdev)
314 } 314 }
315} 315}
316 316
317static void io_subchannel_quiesce(struct subchannel *);
318
317/** 319/**
318 * ccw_device_set_offline() - disable a ccw device for I/O 320 * ccw_device_set_offline() - disable a ccw device for I/O
319 * @cdev: target ccw device 321 * @cdev: target ccw device
@@ -327,7 +329,8 @@ static void ccw_device_unregister(struct ccw_device *cdev)
327 */ 329 */
328int ccw_device_set_offline(struct ccw_device *cdev) 330int ccw_device_set_offline(struct ccw_device *cdev)
329{ 331{
330 int ret; 332 struct subchannel *sch;
333 int ret, state;
331 334
332 if (!cdev) 335 if (!cdev)
333 return -ENODEV; 336 return -ENODEV;
@@ -341,6 +344,7 @@ int ccw_device_set_offline(struct ccw_device *cdev)
341 } 344 }
342 cdev->online = 0; 345 cdev->online = 0;
343 spin_lock_irq(cdev->ccwlock); 346 spin_lock_irq(cdev->ccwlock);
347 sch = to_subchannel(cdev->dev.parent);
344 /* Wait until a final state or DISCONNECTED is reached */ 348 /* Wait until a final state or DISCONNECTED is reached */
345 while (!dev_fsm_final_state(cdev) && 349 while (!dev_fsm_final_state(cdev) &&
346 cdev->private->state != DEV_STATE_DISCONNECTED) { 350 cdev->private->state != DEV_STATE_DISCONNECTED) {
@@ -349,9 +353,21 @@ int ccw_device_set_offline(struct ccw_device *cdev)
349 cdev->private->state == DEV_STATE_DISCONNECTED)); 353 cdev->private->state == DEV_STATE_DISCONNECTED));
350 spin_lock_irq(cdev->ccwlock); 354 spin_lock_irq(cdev->ccwlock);
351 } 355 }
352 ret = ccw_device_offline(cdev); 356 do {
353 if (ret) 357 ret = ccw_device_offline(cdev);
354 goto error; 358 if (!ret)
359 break;
360 CIO_MSG_EVENT(0, "ccw_device_offline returned %d, device "
361 "0.%x.%04x\n", ret, cdev->private->dev_id.ssid,
362 cdev->private->dev_id.devno);
363 if (ret != -EBUSY)
364 goto error;
365 state = cdev->private->state;
366 spin_unlock_irq(cdev->ccwlock);
367 io_subchannel_quiesce(sch);
368 spin_lock_irq(cdev->ccwlock);
369 cdev->private->state = state;
370 } while (ret == -EBUSY);
355 spin_unlock_irq(cdev->ccwlock); 371 spin_unlock_irq(cdev->ccwlock);
356 wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) || 372 wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) ||
357 cdev->private->state == DEV_STATE_DISCONNECTED)); 373 cdev->private->state == DEV_STATE_DISCONNECTED));
@@ -368,9 +384,6 @@ int ccw_device_set_offline(struct ccw_device *cdev)
368 return 0; 384 return 0;
369 385
370error: 386error:
371 CIO_MSG_EVENT(0, "ccw_device_offline returned %d, device 0.%x.%04x\n",
372 ret, cdev->private->dev_id.ssid,
373 cdev->private->dev_id.devno);
374 cdev->private->state = DEV_STATE_OFFLINE; 387 cdev->private->state = DEV_STATE_OFFLINE;
375 dev_fsm_event(cdev, DEV_EVENT_NOTOPER); 388 dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
376 spin_unlock_irq(cdev->ccwlock); 389 spin_unlock_irq(cdev->ccwlock);
@@ -1059,8 +1072,6 @@ out_schedule:
1059 return 0; 1072 return 0;
1060} 1073}
1061 1074
1062static void io_subchannel_quiesce(struct subchannel *);
1063
1064static int 1075static int
1065io_subchannel_remove (struct subchannel *sch) 1076io_subchannel_remove (struct subchannel *sch)
1066{ 1077{