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 --- |