vmur.c (f3e59ff348c077a6afd4edb23d7e69e9cba62fdc) vmur.c (bf18140d30541c2c1e5c0f57879634f3d0d04912)
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Linux driver for System z and s390 unit record devices
4 * (z/VM virtual punch, reader, printer)
5 *
6 * Copyright IBM Corp. 2001, 2009
7 * Authors: Malcolm Beattie <beattiem@uk.ibm.com>
8 * Michael Holzheu <holzheu@de.ibm.com>
9 * Frank Munzert <munzert@de.ibm.com>
10 */
11
12#define KMSG_COMPONENT "vmur"
13#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
14
15#include <linux/cdev.h>
16#include <linux/slab.h>
17#include <linux/module.h>
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Linux driver for System z and s390 unit record devices
4 * (z/VM virtual punch, reader, printer)
5 *
6 * Copyright IBM Corp. 2001, 2009
7 * Authors: Malcolm Beattie <beattiem@uk.ibm.com>
8 * Michael Holzheu <holzheu@de.ibm.com>
9 * Frank Munzert <munzert@de.ibm.com>
10 */
11
12#define KMSG_COMPONENT "vmur"
13#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
14
15#include <linux/cdev.h>
16#include <linux/slab.h>
17#include <linux/module.h>
18#include <linux/kobject.h>
18
19#include <linux/uaccess.h>
20#include <asm/cio.h>
21#include <asm/ccwdev.h>
22#include <asm/debug.h>
23#include <asm/diag.h>
19
20#include <linux/uaccess.h>
21#include <asm/cio.h>
22#include <asm/ccwdev.h>
23#include <asm/debug.h>
24#include <asm/diag.h>
25#include <asm/scsw.h>
24
25#include "vmur.h"
26
27/*
28 * Driver overview
29 *
30 * Unit record device support is implemented as a character device driver.
31 * We can fit at least 16 bits into a device minor number and use the

--- 41 unchanged lines hidden (view full) ---

73 .remove = ur_remove,
74 .set_online = ur_set_online,
75 .set_offline = ur_set_offline,
76 .int_class = IRQIO_VMR,
77};
78
79static DEFINE_MUTEX(vmur_mutex);
80
26
27#include "vmur.h"
28
29/*
30 * Driver overview
31 *
32 * Unit record device support is implemented as a character device driver.
33 * We can fit at least 16 bits into a device minor number and use the

--- 41 unchanged lines hidden (view full) ---

75 .remove = ur_remove,
76 .set_online = ur_set_online,
77 .set_offline = ur_set_offline,
78 .int_class = IRQIO_VMR,
79};
80
81static DEFINE_MUTEX(vmur_mutex);
82
83static void ur_uevent(struct work_struct *ws);
84
81/*
82 * Allocation, freeing, getting and putting of urdev structures
83 *
84 * Each ur device (urd) contains a reference to its corresponding ccw device
85 * (cdev) using the urd->cdev pointer. Each ccw device has a reference to the
86 * ur device using dev_get_drvdata(&cdev->dev) pointer.
87 *
88 * urd references:

--- 14 unchanged lines hidden (view full) ---

103
104 urd = kzalloc(sizeof(struct urdev), GFP_KERNEL);
105 if (!urd)
106 return NULL;
107 urd->reclen = cdev->id.driver_info;
108 ccw_device_get_id(cdev, &urd->dev_id);
109 mutex_init(&urd->io_mutex);
110 init_waitqueue_head(&urd->wait);
85/*
86 * Allocation, freeing, getting and putting of urdev structures
87 *
88 * Each ur device (urd) contains a reference to its corresponding ccw device
89 * (cdev) using the urd->cdev pointer. Each ccw device has a reference to the
90 * ur device using dev_get_drvdata(&cdev->dev) pointer.
91 *
92 * urd references:

--- 14 unchanged lines hidden (view full) ---

107
108 urd = kzalloc(sizeof(struct urdev), GFP_KERNEL);
109 if (!urd)
110 return NULL;
111 urd->reclen = cdev->id.driver_info;
112 ccw_device_get_id(cdev, &urd->dev_id);
113 mutex_init(&urd->io_mutex);
114 init_waitqueue_head(&urd->wait);
115 INIT_WORK(&urd->uevent_work, ur_uevent);
111 spin_lock_init(&urd->open_lock);
112 refcount_set(&urd->ref_count, 1);
113 urd->cdev = cdev;
114 get_device(&cdev->dev);
115 return urd;
116}
117
118static void urdev_free(struct urdev *urd)

--- 151 unchanged lines hidden (view full) ---

270 TRACE("do_ur_io: I/O complete\n");
271 rc = 0;
272
273out:
274 mutex_unlock(&urd->io_mutex);
275 return rc;
276}
277
116 spin_lock_init(&urd->open_lock);
117 refcount_set(&urd->ref_count, 1);
118 urd->cdev = cdev;
119 get_device(&cdev->dev);
120 return urd;
121}
122
123static void urdev_free(struct urdev *urd)

--- 151 unchanged lines hidden (view full) ---

275 TRACE("do_ur_io: I/O complete\n");
276 rc = 0;
277
278out:
279 mutex_unlock(&urd->io_mutex);
280 return rc;
281}
282
283static void ur_uevent(struct work_struct *ws)
284{
285 struct urdev *urd = container_of(ws, struct urdev, uevent_work);
286 char *envp[] = {
287 "EVENT=unsol_de", /* Unsolicited device-end interrupt */
288 NULL
289 };
290
291 kobject_uevent_env(&urd->cdev->dev.kobj, KOBJ_CHANGE, envp);
292 urdev_put(urd);
293}
294
278/*
279 * ur interrupt handler, called from the ccw_device layer
280 */
281static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm,
282 struct irb *irb)
283{
284 struct urdev *urd;
285
286 if (!IS_ERR(irb)) {
287 TRACE("ur_int_handler: intparm=0x%lx cstat=%02x dstat=%02x res=%u\n",
288 intparm, irb->scsw.cmd.cstat, irb->scsw.cmd.dstat,
289 irb->scsw.cmd.count);
290 }
295/*
296 * ur interrupt handler, called from the ccw_device layer
297 */
298static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm,
299 struct irb *irb)
300{
301 struct urdev *urd;
302
303 if (!IS_ERR(irb)) {
304 TRACE("ur_int_handler: intparm=0x%lx cstat=%02x dstat=%02x res=%u\n",
305 intparm, irb->scsw.cmd.cstat, irb->scsw.cmd.dstat,
306 irb->scsw.cmd.count);
307 }
308 urd = dev_get_drvdata(&cdev->dev);
291 if (!intparm) {
292 TRACE("ur_int_handler: unsolicited interrupt\n");
309 if (!intparm) {
310 TRACE("ur_int_handler: unsolicited interrupt\n");
311
312 if (scsw_dstat(&irb->scsw) & DEV_STAT_DEV_END) {
313 /*
314 * Userspace might be interested in a transition to
315 * device-ready state.
316 */
317 urdev_get(urd);
318 schedule_work(&urd->uevent_work);
319 }
320
293 return;
294 }
321 return;
322 }
295 urd = dev_get_drvdata(&cdev->dev);
296 /* On special conditions irb is an error pointer */
297 if (IS_ERR(irb))
298 urd->io_request_rc = PTR_ERR(irb);
299 else if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
300 urd->io_request_rc = 0;
301 else
302 urd->io_request_rc = -EIO;
303

--- 618 unchanged lines hidden (view full) ---

922 goto fail_urdev_put;
923 }
924 if (!force && (refcount_read(&urd->ref_count) > 2)) {
925 /* There is still a user of urd (e.g. ur_open) */
926 TRACE("ur_set_offline: BUSY\n");
927 rc = -EBUSY;
928 goto fail_urdev_put;
929 }
323 /* On special conditions irb is an error pointer */
324 if (IS_ERR(irb))
325 urd->io_request_rc = PTR_ERR(irb);
326 else if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
327 urd->io_request_rc = 0;
328 else
329 urd->io_request_rc = -EIO;
330

--- 618 unchanged lines hidden (view full) ---

949 goto fail_urdev_put;
950 }
951 if (!force && (refcount_read(&urd->ref_count) > 2)) {
952 /* There is still a user of urd (e.g. ur_open) */
953 TRACE("ur_set_offline: BUSY\n");
954 rc = -EBUSY;
955 goto fail_urdev_put;
956 }
957 if (cancel_work_sync(&urd->uevent_work)) {
958 /* Work not run yet - need to release reference here */
959 urdev_put(urd);
960 }
930 device_destroy(vmur_class, urd->char_device->dev);
931 cdev_del(urd->char_device);
932 urd->char_device = NULL;
933 rc = 0;
934
935fail_urdev_put:
936 urdev_put(urd);
937 return rc;

--- 97 unchanged lines hidden ---
961 device_destroy(vmur_class, urd->char_device->dev);
962 cdev_del(urd->char_device);
963 urd->char_device = NULL;
964 rc = 0;
965
966fail_urdev_put:
967 urdev_put(urd);
968 return rc;

--- 97 unchanged lines hidden ---