diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 5eeb62c3f33a..31677c075a8e 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -186,9 +186,8 @@ static inline void cmf_activate(void *area, unsigned int onoff) static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address) { - struct subchannel *sch; - - sch = to_subchannel(cdev->dev.parent); + struct subchannel *sch = to_subchannel(cdev->dev.parent); + int ret; sch->config.mme = mme; sch->config.mbfc = mbfc; @@ -198,7 +197,15 @@ static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc, else sch->config.mbi = address; - return cio_commit_config(sch); + ret = cio_commit_config(sch); + if (!mme && ret == -ENODEV) { + /* + * The task was to disable measurement block updates but + * the subchannel is already gone. Report success. + */ + ret = 0; + } + return ret; } struct set_schib_struct { @@ -606,12 +613,6 @@ static void free_cmb(struct ccw_device *cdev) spin_lock_irq(cdev->ccwlock); priv = cdev->private; - - if (list_empty(&priv->cmb_list)) { - /* already freed */ - goto out; - } - cmb_data = priv->cmb; priv->cmb = NULL; if (cmb_data) @@ -626,7 +627,6 @@ static void free_cmb(struct ccw_device *cdev) free_pages((unsigned long)cmb_area.mem, get_order(size)); cmb_area.mem = NULL; } -out: spin_unlock_irq(cdev->ccwlock); spin_unlock(&cmb_area.lock); } @@ -1227,6 +1227,7 @@ int enable_cmf(struct ccw_device *cdev) int ret; device_lock(&cdev->dev); + get_device(&cdev->dev); ret = cmbops->alloc(cdev); if (ret) goto out; @@ -1242,6 +1243,9 @@ int enable_cmf(struct ccw_device *cdev) cmbops->free(cdev); } out: + if (ret) + put_device(&cdev->dev); + device_unlock(&cdev->dev); return ret; } @@ -1265,6 +1269,7 @@ int __disable_cmf(struct ccw_device *cdev) sysfs_remove_group(&cdev->dev.kobj, cmbops->attr_group); cmbops->free(cdev); + put_device(&cdev->dev); return ret; } diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 20b92c703944..6aae68412802 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1787,6 +1787,8 @@ static int ccw_device_remove(struct device *dev) cdev->drv = NULL; cdev->private->int_class = IRQIO_CIO; spin_unlock_irq(cdev->ccwlock); + __disable_cmf(cdev); + return 0; }