diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/cio/css.c | 13 | ||||
-rw-r--r-- | drivers/s390/cio/css.h | 2 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 107 | ||||
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 3 |
4 files changed, 78 insertions, 47 deletions
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 26cf2f5ae2e7..55895c83d499 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -135,14 +135,19 @@ css_register_subchannel(struct subchannel *sch) sch->dev.parent = &css[0]->device; sch->dev.bus = &css_bus_type; sch->dev.release = &css_subchannel_release; - + /* make it known to the system */ ret = css_sch_device_register(sch); - if (ret) + if (ret) { printk (KERN_WARNING "%s: could not register %s\n", __func__, sch->dev.bus_id); - else - css_get_ssd_info(sch); + return ret; + } + css_get_ssd_info(sch); + ret = subchannel_add_files(&sch->dev); + if (ret) + printk(KERN_WARNING "%s: could not add attributes to %s\n", + __func__, sch->dev.bus_id); return ret; } diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index dfd5462f993f..ac845c1ebf83 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -189,4 +189,6 @@ extern int need_rescan; extern struct workqueue_struct *slow_path_wq; extern struct work_struct slow_path_work; + +int subchannel_add_files (struct device *); #endif diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 0f604621de40..e644fd6905ee 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -294,6 +294,18 @@ online_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, cdev->online ? "1\n" : "0\n"); } +static void ccw_device_unregister(struct work_struct *work) +{ + struct ccw_device_private *priv; + struct ccw_device *cdev; + + priv = container_of(work, struct ccw_device_private, kick_work); + cdev = priv->cdev; + if (test_and_clear_bit(1, &cdev->private->registered)) + device_unregister(&cdev->dev); + put_device(&cdev->dev); +} + static void ccw_device_remove_disconnected(struct ccw_device *cdev) { @@ -498,8 +510,7 @@ static struct attribute_group subch_attr_group = { .attrs = subch_attrs, }; -static inline int -subchannel_add_files (struct device *dev) +int subchannel_add_files (struct device *dev) { return sysfs_create_group(&dev->kobj, &subch_attr_group); } @@ -676,6 +687,55 @@ ccw_device_release(struct device *dev) kfree(cdev); } +static struct ccw_device * io_subchannel_allocate_dev(struct subchannel *sch) +{ + struct ccw_device *cdev; + + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + if (cdev) { + cdev->private = kzalloc(sizeof(struct ccw_device_private), + GFP_KERNEL | GFP_DMA); + if (cdev->private) + return cdev; + } + kfree(cdev); + return ERR_PTR(-ENOMEM); +} + +static int io_subchannel_initialize_dev(struct subchannel *sch, + struct ccw_device *cdev) +{ + cdev->private->cdev = cdev; + atomic_set(&cdev->private->onoff, 0); + cdev->dev.parent = &sch->dev; + cdev->dev.release = ccw_device_release; + INIT_LIST_HEAD(&cdev->private->kick_work.entry); + /* Do first half of device_register. */ + device_initialize(&cdev->dev); + if (!get_device(&sch->dev)) { + if (cdev->dev.release) + cdev->dev.release(&cdev->dev); + return -ENODEV; + } + return 0; +} + +static struct ccw_device * io_subchannel_create_ccwdev(struct subchannel *sch) +{ + struct ccw_device *cdev; + int ret; + + cdev = io_subchannel_allocate_dev(sch); + if (!IS_ERR(cdev)) { + ret = io_subchannel_initialize_dev(sch, cdev); + if (ret) { + kfree(cdev); + cdev = ERR_PTR(ret); + } + } + return cdev; +} + /* * Register recognized device. */ @@ -724,11 +784,6 @@ io_subchannel_register(struct work_struct *work) wake_up(&ccw_device_init_wq); return; } - - ret = subchannel_add_files(cdev->dev.parent); - if (ret) - printk(KERN_WARNING "%s: could not add attributes to %s\n", - __func__, sch->dev.bus_id); put_device(&cdev->dev); out: cdev->private->flags.recog_done = 1; @@ -851,7 +906,6 @@ io_subchannel_probe (struct subchannel *sch) cdev = sch->dev.driver_data; device_initialize(&cdev->dev); ccw_device_register(cdev); - subchannel_add_files(&sch->dev); /* * Check if the device is already online. If it is * the reference count needs to be corrected @@ -864,28 +918,9 @@ io_subchannel_probe (struct subchannel *sch) get_device(&cdev->dev); return 0; } - cdev = kzalloc (sizeof(*cdev), GFP_KERNEL); - if (!cdev) - return -ENOMEM; - cdev->private = kzalloc(sizeof(struct ccw_device_private), - GFP_KERNEL | GFP_DMA); - if (!cdev->private) { - kfree(cdev); - return -ENOMEM; - } - cdev->private->cdev = cdev; - atomic_set(&cdev->private->onoff, 0); - cdev->dev.parent = &sch->dev; - cdev->dev.release = ccw_device_release; - INIT_LIST_HEAD(&cdev->private->kick_work.entry); - /* Do first half of device_register. */ - device_initialize(&cdev->dev); - - if (!get_device(&sch->dev)) { - if (cdev->dev.release) - cdev->dev.release(&cdev->dev); - return -ENODEV; - } + cdev = io_subchannel_create_ccwdev(sch); + if (IS_ERR(cdev)) + return PTR_ERR(cdev); rc = io_subchannel_recog(cdev, sch); if (rc) { @@ -899,18 +934,6 @@ io_subchannel_probe (struct subchannel *sch) return rc; } -static void ccw_device_unregister(struct work_struct *work) -{ - struct ccw_device_private *priv; - struct ccw_device *cdev; - - priv = container_of(work, struct ccw_device_private, kick_work); - cdev = priv->cdev; - if (test_and_clear_bit(1, &cdev->private->registered)) - device_unregister(&cdev->dev); - put_device(&cdev->dev); -} - static int io_subchannel_remove (struct subchannel *sch) { diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 0f0301ce37fe..a487fb0e7d3d 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -1106,7 +1106,8 @@ device_trigger_reprobe(struct subchannel *sch) /* Update some values. */ if (stsch(sch->schid, &sch->schib)) return; - + if (!sch->schib.pmcw.dnv) + return; /* * The pim, pam, pom values may not be accurate, but they are the best * we have before performing device selection :/ |