xref: /openbmc/linux/drivers/s390/block/scm_drv.c (revision 39b6f3aa)
1 /*
2  * Device driver for s390 storage class memory.
3  *
4  * Copyright IBM Corp. 2012
5  * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com>
6  */
7 
8 #define KMSG_COMPONENT "scm_block"
9 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
10 
11 #include <linux/module.h>
12 #include <linux/slab.h>
13 #include <asm/eadm.h>
14 #include "scm_blk.h"
15 
16 static void scm_notify(struct scm_device *scmdev, enum scm_event event)
17 {
18 	struct scm_blk_dev *bdev = dev_get_drvdata(&scmdev->dev);
19 
20 	switch (event) {
21 	case SCM_CHANGE:
22 		pr_info("%lx: The capabilities of the SCM increment changed\n",
23 			(unsigned long) scmdev->address);
24 		SCM_LOG(2, "State changed");
25 		SCM_LOG_STATE(2, scmdev);
26 		break;
27 	case SCM_AVAIL:
28 		SCM_LOG(2, "Increment available");
29 		SCM_LOG_STATE(2, scmdev);
30 		scm_blk_set_available(bdev);
31 		break;
32 	}
33 }
34 
35 static int scm_probe(struct scm_device *scmdev)
36 {
37 	struct scm_blk_dev *bdev;
38 	int ret;
39 
40 	SCM_LOG(2, "probe");
41 	SCM_LOG_STATE(2, scmdev);
42 
43 	if (scmdev->attrs.oper_state != OP_STATE_GOOD)
44 		return -EINVAL;
45 
46 	bdev = kzalloc(sizeof(*bdev), GFP_KERNEL);
47 	if (!bdev)
48 		return -ENOMEM;
49 
50 	dev_set_drvdata(&scmdev->dev, bdev);
51 	ret = scm_blk_dev_setup(bdev, scmdev);
52 	if (ret) {
53 		dev_set_drvdata(&scmdev->dev, NULL);
54 		kfree(bdev);
55 		goto out;
56 	}
57 
58 out:
59 	return ret;
60 }
61 
62 static int scm_remove(struct scm_device *scmdev)
63 {
64 	struct scm_blk_dev *bdev = dev_get_drvdata(&scmdev->dev);
65 
66 	scm_blk_dev_cleanup(bdev);
67 	dev_set_drvdata(&scmdev->dev, NULL);
68 	kfree(bdev);
69 
70 	return 0;
71 }
72 
73 static struct scm_driver scm_drv = {
74 	.drv = {
75 		.name = "scm_block",
76 		.owner = THIS_MODULE,
77 	},
78 	.notify = scm_notify,
79 	.probe = scm_probe,
80 	.remove = scm_remove,
81 	.handler = scm_blk_irq,
82 };
83 
84 int __init scm_drv_init(void)
85 {
86 	return scm_driver_register(&scm_drv);
87 }
88 
89 void scm_drv_cleanup(void)
90 {
91 	scm_driver_unregister(&scm_drv);
92 }
93