diff options
author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2012-08-28 10:47:02 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2012-09-26 09:44:59 -0400 |
commit | 40ff4cc06697e8ba3f8ce93b0592ddbcf70cd444 (patch) | |
tree | fde6248c494240b4fbbc449bb3ddd1025ad099f9 /drivers/s390/cio/scm.c | |
parent | 1d1c8f78bed5f8e769757525bd9c2dec69f11a44 (diff) |
s390: add scm notification
Detect an scm change notification in store event information.
Update affected scm devices and notify their drivers.
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/scm.c')
-rw-r--r-- | drivers/s390/cio/scm.c | 50 |
1 files changed, 49 insertions, 1 deletions
diff --git a/drivers/s390/cio/scm.c b/drivers/s390/cio/scm.c index 874b64a4bf26..aa4476e92050 100644 --- a/drivers/s390/cio/scm.c +++ b/drivers/s390/cio/scm.c | |||
@@ -196,6 +196,47 @@ static void scmdev_setup(struct scm_device *scmdev, struct sale *sale, | |||
196 | spin_lock_init(&scmdev->lock); | 196 | spin_lock_init(&scmdev->lock); |
197 | } | 197 | } |
198 | 198 | ||
199 | /* | ||
200 | * Check for state-changes, notify the driver and userspace. | ||
201 | */ | ||
202 | static void scmdev_update(struct scm_device *scmdev, struct sale *sale) | ||
203 | { | ||
204 | struct scm_driver *scmdrv; | ||
205 | bool changed; | ||
206 | |||
207 | device_lock(&scmdev->dev); | ||
208 | changed = scmdev->attrs.rank != sale->rank || | ||
209 | scmdev->attrs.oper_state != sale->op_state; | ||
210 | scmdev->attrs.rank = sale->rank; | ||
211 | scmdev->attrs.oper_state = sale->op_state; | ||
212 | if (!scmdev->dev.driver) | ||
213 | goto out; | ||
214 | scmdrv = to_scm_drv(scmdev->dev.driver); | ||
215 | if (changed && scmdrv->notify) | ||
216 | scmdrv->notify(scmdev); | ||
217 | out: | ||
218 | device_unlock(&scmdev->dev); | ||
219 | if (changed) | ||
220 | kobject_uevent(&scmdev->dev.kobj, KOBJ_CHANGE); | ||
221 | } | ||
222 | |||
223 | static int check_address(struct device *dev, void *data) | ||
224 | { | ||
225 | struct scm_device *scmdev = to_scm_dev(dev); | ||
226 | struct sale *sale = data; | ||
227 | |||
228 | return scmdev->address == sale->sa; | ||
229 | } | ||
230 | |||
231 | static struct scm_device *scmdev_find(struct sale *sale) | ||
232 | { | ||
233 | struct device *dev; | ||
234 | |||
235 | dev = bus_find_device(&scm_bus_type, NULL, sale, check_address); | ||
236 | |||
237 | return dev ? to_scm_dev(dev) : NULL; | ||
238 | } | ||
239 | |||
199 | static int scm_add(struct chsc_scm_info *scm_info, size_t num) | 240 | static int scm_add(struct chsc_scm_info *scm_info, size_t num) |
200 | { | 241 | { |
201 | struct sale *sale, *scmal = scm_info->scmal; | 242 | struct sale *sale, *scmal = scm_info->scmal; |
@@ -203,6 +244,13 @@ static int scm_add(struct chsc_scm_info *scm_info, size_t num) | |||
203 | int ret; | 244 | int ret; |
204 | 245 | ||
205 | for (sale = scmal; sale < scmal + num; sale++) { | 246 | for (sale = scmal; sale < scmal + num; sale++) { |
247 | scmdev = scmdev_find(sale); | ||
248 | if (scmdev) { | ||
249 | scmdev_update(scmdev, sale); | ||
250 | /* Release reference from scm_find(). */ | ||
251 | put_device(&scmdev->dev); | ||
252 | continue; | ||
253 | } | ||
206 | scmdev = kzalloc(sizeof(*scmdev), GFP_KERNEL); | 254 | scmdev = kzalloc(sizeof(*scmdev), GFP_KERNEL); |
207 | if (!scmdev) | 255 | if (!scmdev) |
208 | return -ENODEV; | 256 | return -ENODEV; |
@@ -218,7 +266,7 @@ static int scm_add(struct chsc_scm_info *scm_info, size_t num) | |||
218 | return 0; | 266 | return 0; |
219 | } | 267 | } |
220 | 268 | ||
221 | static int scm_update_information(void) | 269 | int scm_update_information(void) |
222 | { | 270 | { |
223 | struct chsc_scm_info *scm_info; | 271 | struct chsc_scm_info *scm_info; |
224 | u64 token = 0; | 272 | u64 token = 0; |