diff options
| -rw-r--r-- | drivers/s390/cio/device.c | 49 | 
1 files changed, 38 insertions, 11 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index a8b373f69cf0..6b264bdb5bfb 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c  | |||
| @@ -296,30 +296,57 @@ static void ccw_device_unregister(struct ccw_device *cdev) | |||
| 296 | device_del(&cdev->dev); | 296 | device_del(&cdev->dev); | 
| 297 | } | 297 | } | 
| 298 | 298 | ||
| 299 | static void ccw_device_remove_orphan_cb(struct device *dev) | ||
| 300 | { | ||
| 301 | struct ccw_device *cdev = to_ccwdev(dev); | ||
| 302 | |||
| 303 | ccw_device_unregister(cdev); | ||
| 304 | put_device(&cdev->dev); | ||
| 305 | } | ||
| 306 | |||
| 307 | static void ccw_device_remove_sch_cb(struct device *dev) | ||
| 308 | { | ||
| 309 | struct subchannel *sch; | ||
| 310 | |||
| 311 | sch = to_subchannel(dev); | ||
| 312 | css_sch_device_unregister(sch); | ||
| 313 | /* Reset intparm to zeroes. */ | ||
| 314 | sch->schib.pmcw.intparm = 0; | ||
| 315 | cio_modify(sch); | ||
| 316 | put_device(&sch->dev); | ||
| 317 | } | ||
| 318 | |||
| 299 | static void | 319 | static void | 
| 300 | ccw_device_remove_disconnected(struct ccw_device *cdev) | 320 | ccw_device_remove_disconnected(struct ccw_device *cdev) | 
| 301 | { | 321 | { | 
| 302 | struct subchannel *sch; | ||
| 303 | unsigned long flags; | 322 | unsigned long flags; | 
| 323 | int rc; | ||
| 324 | |||
| 304 | /* | 325 | /* | 
| 305 | * Forced offline in disconnected state means | 326 | * Forced offline in disconnected state means | 
| 306 | * 'throw away device'. | 327 | * 'throw away device'. | 
| 307 | */ | 328 | */ | 
| 308 | if (ccw_device_is_orphan(cdev)) { | 329 | if (ccw_device_is_orphan(cdev)) { | 
| 309 | /* Deregister ccw device. */ | 330 | /* | 
| 331 | * Deregister ccw device. | ||
| 332 | * Unfortunately, we cannot do this directly from the | ||
| 333 | * attribute method. | ||
| 334 | */ | ||
| 310 | spin_lock_irqsave(cdev->ccwlock, flags); | 335 | spin_lock_irqsave(cdev->ccwlock, flags); | 
| 311 | cdev->private->state = DEV_STATE_NOT_OPER; | 336 | cdev->private->state = DEV_STATE_NOT_OPER; | 
| 312 | spin_unlock_irqrestore(cdev->ccwlock, flags); | 337 | spin_unlock_irqrestore(cdev->ccwlock, flags); | 
| 313 | ccw_device_unregister(cdev); | 338 | rc = device_schedule_callback(&cdev->dev, | 
| 314 | put_device(&cdev->dev); | 339 | ccw_device_remove_orphan_cb); | 
| 315 | return ; | 340 | if (rc) | 
| 341 | dev_info(&cdev->dev, "Couldn't unregister orphan\n"); | ||
| 342 | return; | ||
| 316 | } | 343 | } | 
| 317 | sch = to_subchannel(cdev->dev.parent); | 344 | /* Deregister subchannel, which will kill the ccw device. */ | 
| 318 | css_sch_device_unregister(sch); | 345 | rc = device_schedule_callback(cdev->dev.parent, | 
| 319 | /* Reset intparm to zeroes. */ | 346 | ccw_device_remove_sch_cb); | 
| 320 | sch->schib.pmcw.intparm = 0; | 347 | if (rc) | 
| 321 | cio_modify(sch); | 348 | dev_info(&cdev->dev, | 
| 322 | put_device(&sch->dev); | 349 | "Couldn't unregister disconnected device\n"); | 
| 323 | } | 350 | } | 
| 324 | 351 | ||
| 325 | int | 352 | int | 
