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