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>
This commit is contained in:
parent
1d1c8f78be
commit
40ff4cc066
|
@ -102,6 +102,7 @@ struct scm_driver {
|
|||
struct device_driver drv;
|
||||
int (*probe) (struct scm_device *scmdev);
|
||||
int (*remove) (struct scm_device *scmdev);
|
||||
void (*notify) (struct scm_device *scmdev);
|
||||
void (*handler) (struct scm_device *scmdev, void *data, int error);
|
||||
};
|
||||
|
||||
|
|
|
@ -398,6 +398,20 @@ static void chsc_process_sei_chp_config(struct chsc_sei_area *sei_area)
|
|||
}
|
||||
}
|
||||
|
||||
static void chsc_process_sei_scm_change(struct chsc_sei_area *sei_area)
|
||||
{
|
||||
int ret;
|
||||
|
||||
CIO_CRW_EVENT(4, "chsc: scm change notification\n");
|
||||
if (sei_area->rs != 7)
|
||||
return;
|
||||
|
||||
ret = scm_update_information();
|
||||
if (ret)
|
||||
CIO_CRW_EVENT(0, "chsc: updating change notification"
|
||||
" failed (rc=%d).\n", ret);
|
||||
}
|
||||
|
||||
static void chsc_process_sei(struct chsc_sei_area *sei_area)
|
||||
{
|
||||
/* Check if we might have lost some information. */
|
||||
|
@ -419,6 +433,9 @@ static void chsc_process_sei(struct chsc_sei_area *sei_area)
|
|||
case 8: /* channel-path-configuration notification */
|
||||
chsc_process_sei_chp_config(sei_area);
|
||||
break;
|
||||
case 12: /* scm change notification */
|
||||
chsc_process_sei_scm_change(sei_area);
|
||||
break;
|
||||
default: /* other stuff */
|
||||
CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n",
|
||||
sei_area->cc);
|
||||
|
|
|
@ -154,4 +154,11 @@ struct chsc_scm_info {
|
|||
|
||||
int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token);
|
||||
|
||||
#ifdef CONFIG_SCM_BUS
|
||||
int scm_update_information(void);
|
||||
#else /* CONFIG_SCM_BUS */
|
||||
#define scm_update_information() 0
|
||||
#endif /* CONFIG_SCM_BUS */
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -196,6 +196,47 @@ static void scmdev_setup(struct scm_device *scmdev, struct sale *sale,
|
|||
spin_lock_init(&scmdev->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for state-changes, notify the driver and userspace.
|
||||
*/
|
||||
static void scmdev_update(struct scm_device *scmdev, struct sale *sale)
|
||||
{
|
||||
struct scm_driver *scmdrv;
|
||||
bool changed;
|
||||
|
||||
device_lock(&scmdev->dev);
|
||||
changed = scmdev->attrs.rank != sale->rank ||
|
||||
scmdev->attrs.oper_state != sale->op_state;
|
||||
scmdev->attrs.rank = sale->rank;
|
||||
scmdev->attrs.oper_state = sale->op_state;
|
||||
if (!scmdev->dev.driver)
|
||||
goto out;
|
||||
scmdrv = to_scm_drv(scmdev->dev.driver);
|
||||
if (changed && scmdrv->notify)
|
||||
scmdrv->notify(scmdev);
|
||||
out:
|
||||
device_unlock(&scmdev->dev);
|
||||
if (changed)
|
||||
kobject_uevent(&scmdev->dev.kobj, KOBJ_CHANGE);
|
||||
}
|
||||
|
||||
static int check_address(struct device *dev, void *data)
|
||||
{
|
||||
struct scm_device *scmdev = to_scm_dev(dev);
|
||||
struct sale *sale = data;
|
||||
|
||||
return scmdev->address == sale->sa;
|
||||
}
|
||||
|
||||
static struct scm_device *scmdev_find(struct sale *sale)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
dev = bus_find_device(&scm_bus_type, NULL, sale, check_address);
|
||||
|
||||
return dev ? to_scm_dev(dev) : NULL;
|
||||
}
|
||||
|
||||
static int scm_add(struct chsc_scm_info *scm_info, size_t num)
|
||||
{
|
||||
struct sale *sale, *scmal = scm_info->scmal;
|
||||
|
@ -203,6 +244,13 @@ static int scm_add(struct chsc_scm_info *scm_info, size_t num)
|
|||
int ret;
|
||||
|
||||
for (sale = scmal; sale < scmal + num; sale++) {
|
||||
scmdev = scmdev_find(sale);
|
||||
if (scmdev) {
|
||||
scmdev_update(scmdev, sale);
|
||||
/* Release reference from scm_find(). */
|
||||
put_device(&scmdev->dev);
|
||||
continue;
|
||||
}
|
||||
scmdev = kzalloc(sizeof(*scmdev), GFP_KERNEL);
|
||||
if (!scmdev)
|
||||
return -ENODEV;
|
||||
|
@ -218,7 +266,7 @@ static int scm_add(struct chsc_scm_info *scm_info, size_t num)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int scm_update_information(void)
|
||||
int scm_update_information(void)
|
||||
{
|
||||
struct chsc_scm_info *scm_info;
|
||||
u64 token = 0;
|
||||
|
|
Loading…
Reference in New Issue