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 | |
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')
-rw-r--r-- | drivers/s390/cio/chsc.c | 17 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.h | 7 | ||||
-rw-r--r-- | drivers/s390/cio/scm.c | 50 |
3 files changed, 73 insertions, 1 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 121865385c05..4d51a7c4eb8b 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -398,6 +398,20 @@ static void chsc_process_sei_chp_config(struct chsc_sei_area *sei_area) | |||
398 | } | 398 | } |
399 | } | 399 | } |
400 | 400 | ||
401 | static void chsc_process_sei_scm_change(struct chsc_sei_area *sei_area) | ||
402 | { | ||
403 | int ret; | ||
404 | |||
405 | CIO_CRW_EVENT(4, "chsc: scm change notification\n"); | ||
406 | if (sei_area->rs != 7) | ||
407 | return; | ||
408 | |||
409 | ret = scm_update_information(); | ||
410 | if (ret) | ||
411 | CIO_CRW_EVENT(0, "chsc: updating change notification" | ||
412 | " failed (rc=%d).\n", ret); | ||
413 | } | ||
414 | |||
401 | static void chsc_process_sei(struct chsc_sei_area *sei_area) | 415 | static void chsc_process_sei(struct chsc_sei_area *sei_area) |
402 | { | 416 | { |
403 | /* Check if we might have lost some information. */ | 417 | /* Check if we might have lost some information. */ |
@@ -419,6 +433,9 @@ static void chsc_process_sei(struct chsc_sei_area *sei_area) | |||
419 | case 8: /* channel-path-configuration notification */ | 433 | case 8: /* channel-path-configuration notification */ |
420 | chsc_process_sei_chp_config(sei_area); | 434 | chsc_process_sei_chp_config(sei_area); |
421 | break; | 435 | break; |
436 | case 12: /* scm change notification */ | ||
437 | chsc_process_sei_scm_change(sei_area); | ||
438 | break; | ||
422 | default: /* other stuff */ | 439 | default: /* other stuff */ |
423 | CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n", | 440 | CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n", |
424 | sei_area->cc); | 441 | sei_area->cc); |
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 3aa94fe7a676..662dab4b93e6 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h | |||
@@ -154,4 +154,11 @@ struct chsc_scm_info { | |||
154 | 154 | ||
155 | int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token); | 155 | int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token); |
156 | 156 | ||
157 | #ifdef CONFIG_SCM_BUS | ||
158 | int scm_update_information(void); | ||
159 | #else /* CONFIG_SCM_BUS */ | ||
160 | #define scm_update_information() 0 | ||
161 | #endif /* CONFIG_SCM_BUS */ | ||
162 | |||
163 | |||
157 | #endif | 164 | #endif |
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; |