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