Skip to content

Commit

Permalink
s390: add scm notification
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Sebastian Ott authored and Martin Schwidefsky committed Sep 26, 2012
1 parent 1d1c8f7 commit 40ff4cc
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 1 deletion.
1 change: 1 addition & 0 deletions arch/s390/include/asm/eadm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};

Expand Down
17 changes: 17 additions & 0 deletions drivers/s390/cio/chsc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand All @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions drivers/s390/cio/chsc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
50 changes: 49 additions & 1 deletion drivers/s390/cio/scm.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,13 +196,61 @@ 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;
struct scm_device *scmdev;
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;
Expand All @@ -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;
Expand Down

0 comments on commit 40ff4cc

Please sign in to comment.