linux/drivers/s390/cio/scm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Recognize and maintain s390 storage class memory.
   4 *
   5 * Copyright IBM Corp. 2012
   6 * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com>
   7 */
   8
   9#include <linux/device.h>
  10#include <linux/module.h>
  11#include <linux/mutex.h>
  12#include <linux/slab.h>
  13#include <linux/init.h>
  14#include <linux/err.h>
  15#include <asm/eadm.h>
  16#include "chsc.h"
  17
  18static struct device *scm_root;
  19
  20#define to_scm_dev(n) container_of(n, struct scm_device, dev)
  21#define to_scm_drv(d) container_of(d, struct scm_driver, drv)
  22
  23static int scmdev_probe(struct device *dev)
  24{
  25        struct scm_device *scmdev = to_scm_dev(dev);
  26        struct scm_driver *scmdrv = to_scm_drv(dev->driver);
  27
  28        return scmdrv->probe ? scmdrv->probe(scmdev) : -ENODEV;
  29}
  30
  31static void scmdev_remove(struct device *dev)
  32{
  33        struct scm_device *scmdev = to_scm_dev(dev);
  34        struct scm_driver *scmdrv = to_scm_drv(dev->driver);
  35
  36        if (scmdrv->remove)
  37                scmdrv->remove(scmdev);
  38}
  39
  40static int scmdev_uevent(struct device *dev, struct kobj_uevent_env *env)
  41{
  42        return add_uevent_var(env, "MODALIAS=scm:scmdev");
  43}
  44
  45static struct bus_type scm_bus_type = {
  46        .name  = "scm",
  47        .probe = scmdev_probe,
  48        .remove = scmdev_remove,
  49        .uevent = scmdev_uevent,
  50};
  51
  52/**
  53 * scm_driver_register() - register a scm driver
  54 * @scmdrv: driver to be registered
  55 */
  56int scm_driver_register(struct scm_driver *scmdrv)
  57{
  58        struct device_driver *drv = &scmdrv->drv;
  59
  60        drv->bus = &scm_bus_type;
  61
  62        return driver_register(drv);
  63}
  64EXPORT_SYMBOL_GPL(scm_driver_register);
  65
  66/**
  67 * scm_driver_unregister() - deregister a scm driver
  68 * @scmdrv: driver to be deregistered
  69 */
  70void scm_driver_unregister(struct scm_driver *scmdrv)
  71{
  72        driver_unregister(&scmdrv->drv);
  73}
  74EXPORT_SYMBOL_GPL(scm_driver_unregister);
  75
  76void scm_irq_handler(struct aob *aob, blk_status_t error)
  77{
  78        struct aob_rq_header *aobrq = (void *) aob->request.data;
  79        struct scm_device *scmdev = aobrq->scmdev;
  80        struct scm_driver *scmdrv = to_scm_drv(scmdev->dev.driver);
  81
  82        scmdrv->handler(scmdev, aobrq->data, error);
  83}
  84EXPORT_SYMBOL_GPL(scm_irq_handler);
  85
  86#define scm_attr(name)                                                  \
  87static ssize_t show_##name(struct device *dev,                          \
  88               struct device_attribute *attr, char *buf)                \
  89{                                                                       \
  90        struct scm_device *scmdev = to_scm_dev(dev);                    \
  91        int ret;                                                        \
  92                                                                        \
  93        device_lock(dev);                                               \
  94        ret = sprintf(buf, "%u\n", scmdev->attrs.name);                 \
  95        device_unlock(dev);                                             \
  96                                                                        \
  97        return ret;                                                     \
  98}                                                                       \
  99static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
 100
 101scm_attr(persistence);
 102scm_attr(oper_state);
 103scm_attr(data_state);
 104scm_attr(rank);
 105scm_attr(release);
 106scm_attr(res_id);
 107
 108static struct attribute *scmdev_attrs[] = {
 109        &dev_attr_persistence.attr,
 110        &dev_attr_oper_state.attr,
 111        &dev_attr_data_state.attr,
 112        &dev_attr_rank.attr,
 113        &dev_attr_release.attr,
 114        &dev_attr_res_id.attr,
 115        NULL,
 116};
 117
 118static struct attribute_group scmdev_attr_group = {
 119        .attrs = scmdev_attrs,
 120};
 121
 122static const struct attribute_group *scmdev_attr_groups[] = {
 123        &scmdev_attr_group,
 124        NULL,
 125};
 126
 127static void scmdev_release(struct device *dev)
 128{
 129        struct scm_device *scmdev = to_scm_dev(dev);
 130
 131        kfree(scmdev);
 132}
 133
 134static void scmdev_setup(struct scm_device *scmdev, struct sale *sale,
 135                         unsigned int size, unsigned int max_blk_count)
 136{
 137        dev_set_name(&scmdev->dev, "%016llx", (unsigned long long) sale->sa);
 138        scmdev->nr_max_block = max_blk_count;
 139        scmdev->address = sale->sa;
 140        scmdev->size = 1UL << size;
 141        scmdev->attrs.rank = sale->rank;
 142        scmdev->attrs.persistence = sale->p;
 143        scmdev->attrs.oper_state = sale->op_state;
 144        scmdev->attrs.data_state = sale->data_state;
 145        scmdev->attrs.rank = sale->rank;
 146        scmdev->attrs.release = sale->r;
 147        scmdev->attrs.res_id = sale->rid;
 148        scmdev->dev.parent = scm_root;
 149        scmdev->dev.bus = &scm_bus_type;
 150        scmdev->dev.release = scmdev_release;
 151        scmdev->dev.groups = scmdev_attr_groups;
 152}
 153
 154/*
 155 * Check for state-changes, notify the driver and userspace.
 156 */
 157static void scmdev_update(struct scm_device *scmdev, struct sale *sale)
 158{
 159        struct scm_driver *scmdrv;
 160        bool changed;
 161
 162        device_lock(&scmdev->dev);
 163        changed = scmdev->attrs.rank != sale->rank ||
 164                  scmdev->attrs.oper_state != sale->op_state;
 165        scmdev->attrs.rank = sale->rank;
 166        scmdev->attrs.oper_state = sale->op_state;
 167        if (!scmdev->dev.driver)
 168                goto out;
 169        scmdrv = to_scm_drv(scmdev->dev.driver);
 170        if (changed && scmdrv->notify)
 171                scmdrv->notify(scmdev, SCM_CHANGE);
 172out:
 173        device_unlock(&scmdev->dev);
 174        if (changed)
 175                kobject_uevent(&scmdev->dev.kobj, KOBJ_CHANGE);
 176}
 177
 178static int check_address(struct device *dev, const void *data)
 179{
 180        struct scm_device *scmdev = to_scm_dev(dev);
 181        const struct sale *sale = data;
 182
 183        return scmdev->address == sale->sa;
 184}
 185
 186static struct scm_device *scmdev_find(struct sale *sale)
 187{
 188        struct device *dev;
 189
 190        dev = bus_find_device(&scm_bus_type, NULL, sale, check_address);
 191
 192        return dev ? to_scm_dev(dev) : NULL;
 193}
 194
 195static int scm_add(struct chsc_scm_info *scm_info, size_t num)
 196{
 197        struct sale *sale, *scmal = scm_info->scmal;
 198        struct scm_device *scmdev;
 199        int ret;
 200
 201        for (sale = scmal; sale < scmal + num; sale++) {
 202                scmdev = scmdev_find(sale);
 203                if (scmdev) {
 204                        scmdev_update(scmdev, sale);
 205                        /* Release reference from scm_find(). */
 206                        put_device(&scmdev->dev);
 207                        continue;
 208                }
 209                scmdev = kzalloc(sizeof(*scmdev), GFP_KERNEL);
 210                if (!scmdev)
 211                        return -ENODEV;
 212                scmdev_setup(scmdev, sale, scm_info->is, scm_info->mbc);
 213                ret = device_register(&scmdev->dev);
 214                if (ret) {
 215                        /* Release reference from device_initialize(). */
 216                        put_device(&scmdev->dev);
 217                        return ret;
 218                }
 219        }
 220
 221        return 0;
 222}
 223
 224int scm_update_information(void)
 225{
 226        struct chsc_scm_info *scm_info;
 227        u64 token = 0;
 228        size_t num;
 229        int ret;
 230
 231        scm_info = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
 232        if (!scm_info)
 233                return -ENOMEM;
 234
 235        do {
 236                ret = chsc_scm_info(scm_info, token);
 237                if (ret)
 238                        break;
 239
 240                num = (scm_info->response.length -
 241                       (offsetof(struct chsc_scm_info, scmal) -
 242                        offsetof(struct chsc_scm_info, response))
 243                      ) / sizeof(struct sale);
 244
 245                ret = scm_add(scm_info, num);
 246                if (ret)
 247                        break;
 248
 249                token = scm_info->restok;
 250        } while (token);
 251
 252        free_page((unsigned long)scm_info);
 253
 254        return ret;
 255}
 256
 257static int scm_dev_avail(struct device *dev, void *unused)
 258{
 259        struct scm_driver *scmdrv = to_scm_drv(dev->driver);
 260        struct scm_device *scmdev = to_scm_dev(dev);
 261
 262        if (dev->driver && scmdrv->notify)
 263                scmdrv->notify(scmdev, SCM_AVAIL);
 264
 265        return 0;
 266}
 267
 268int scm_process_availability_information(void)
 269{
 270        return bus_for_each_dev(&scm_bus_type, NULL, NULL, scm_dev_avail);
 271}
 272
 273static int __init scm_init(void)
 274{
 275        int ret;
 276
 277        ret = bus_register(&scm_bus_type);
 278        if (ret)
 279                return ret;
 280
 281        scm_root = root_device_register("scm");
 282        if (IS_ERR(scm_root)) {
 283                bus_unregister(&scm_bus_type);
 284                return PTR_ERR(scm_root);
 285        }
 286
 287        scm_update_information();
 288        return 0;
 289}
 290subsys_initcall_sync(scm_init);
 291