summaryrefslogtreecommitdiff
path: root/drivers/s390/char/tape_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/char/tape_core.c')
-rw-r--r--drivers/s390/char/tape_core.c127
1 files changed, 53 insertions, 74 deletions
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index 3c379da2eef8..0250076a7d9f 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* basic function of the tape device driver
*
@@ -10,9 +11,9 @@
* Stefan Bader <shbader@de.ibm.com>
*/
-#define KMSG_COMPONENT "tape"
-#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+#define pr_fmt(fmt) "tape: " fmt
+#include <linux/export.h>
#include <linux/module.h>
#include <linux/init.h> // for kernel parameters
#include <linux/kmod.h> // for requesting modules
@@ -32,7 +33,7 @@
static void __tape_do_irq (struct ccw_device *, unsigned long, struct irb *);
static void tape_delayed_next_request(struct work_struct *);
-static void tape_long_busy_timeout(unsigned long data);
+static void tape_long_busy_timeout(struct timer_list *t);
/*
* One list to contain all tape devices of all disciplines, so
@@ -95,7 +96,7 @@ tape_medium_state_show(struct device *dev, struct device_attribute *attr, char *
struct tape_device *tdev;
tdev = dev_get_drvdata(dev);
- return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->medium_state);
+ return sysfs_emit(buf, "%i\n", tdev->medium_state);
}
static
@@ -107,7 +108,7 @@ tape_first_minor_show(struct device *dev, struct device_attribute *attr, char *b
struct tape_device *tdev;
tdev = dev_get_drvdata(dev);
- return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->first_minor);
+ return sysfs_emit(buf, "%i\n", tdev->first_minor);
}
static
@@ -119,8 +120,8 @@ tape_state_show(struct device *dev, struct device_attribute *attr, char *buf)
struct tape_device *tdev;
tdev = dev_get_drvdata(dev);
- return scnprintf(buf, PAGE_SIZE, "%s\n", (tdev->first_minor < 0) ?
- "OFFLINE" : tape_state_verbose[tdev->tape_state]);
+ return sysfs_emit(buf, "%s\n", (tdev->first_minor < 0) ?
+ "OFFLINE" : tape_state_verbose[tdev->tape_state]);
}
static
@@ -134,17 +135,17 @@ tape_operation_show(struct device *dev, struct device_attribute *attr, char *buf
tdev = dev_get_drvdata(dev);
if (tdev->first_minor < 0)
- return scnprintf(buf, PAGE_SIZE, "N/A\n");
+ return sysfs_emit(buf, "N/A\n");
spin_lock_irq(get_ccwdev_lock(tdev->cdev));
if (list_empty(&tdev->req_queue))
- rc = scnprintf(buf, PAGE_SIZE, "---\n");
+ rc = sysfs_emit(buf, "---\n");
else {
struct tape_request *req;
req = list_entry(tdev->req_queue.next, struct tape_request,
list);
- rc = scnprintf(buf,PAGE_SIZE, "%s\n", tape_op_verbose[req->op]);
+ rc = sysfs_emit(buf, "%s\n", tape_op_verbose[req->op]);
}
spin_unlock_irq(get_ccwdev_lock(tdev->cdev));
return rc;
@@ -160,7 +161,7 @@ tape_blocksize_show(struct device *dev, struct device_attribute *attr, char *buf
tdev = dev_get_drvdata(dev);
- return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->char_data.block_size);
+ return sysfs_emit(buf, "%i\n", tdev->char_data.block_size);
}
static
@@ -175,7 +176,7 @@ static struct attribute *tape_attrs[] = {
NULL
};
-static struct attribute_group tape_attr_group = {
+static const struct attribute_group tape_attr_group = {
.attrs = tape_attrs,
};
@@ -381,8 +382,7 @@ tape_generic_online(struct tape_device *device,
return -EINVAL;
}
- init_timer(&device->lb_timeout);
- device->lb_timeout.function = tape_long_busy_timeout;
+ timer_setup(&device->lb_timeout, tape_long_busy_timeout, 0);
/* Let the discipline have a go at the device. */
device->discipline = discipline;
@@ -428,55 +428,6 @@ tape_cleanup_device(struct tape_device *device)
}
/*
- * Suspend device.
- *
- * Called by the common I/O layer if the drive should be suspended on user
- * request. We refuse to suspend if the device is loaded or in use for the
- * following reason:
- * While the Linux guest is suspended, it might be logged off which causes
- * devices to be detached. Tape devices are automatically rewound and unloaded
- * during DETACH processing (unless the tape device was attached with the
- * NOASSIGN or MULTIUSER option). After rewind/unload, there is no way to
- * resume the original state of the tape device, since we would need to
- * manually re-load the cartridge which was active at suspend time.
- */
-int tape_generic_pm_suspend(struct ccw_device *cdev)
-{
- struct tape_device *device;
-
- device = dev_get_drvdata(&cdev->dev);
- if (!device) {
- return -ENODEV;
- }
-
- DBF_LH(3, "(%08x): tape_generic_pm_suspend(%p)\n",
- device->cdev_id, device);
-
- if (device->medium_state != MS_UNLOADED) {
- pr_err("A cartridge is loaded in tape device %s, "
- "refusing to suspend\n", dev_name(&cdev->dev));
- return -EBUSY;
- }
-
- spin_lock_irq(get_ccwdev_lock(device->cdev));
- switch (device->tape_state) {
- case TS_INIT:
- case TS_NOT_OPER:
- case TS_UNUSED:
- spin_unlock_irq(get_ccwdev_lock(device->cdev));
- break;
- default:
- pr_err("Tape device %s is busy, refusing to "
- "suspend\n", dev_name(&cdev->dev));
- spin_unlock_irq(get_ccwdev_lock(device->cdev));
- return -EBUSY;
- }
-
- DBF_LH(3, "(%08x): Drive suspended.\n", device->cdev_id);
- return 0;
-}
-
-/*
* Set device offline.
*
* Called by the common I/O layer if the drive should set offline on user
@@ -677,6 +628,7 @@ tape_generic_remove(struct ccw_device *cdev)
switch (device->tape_state) {
case TS_INIT:
tape_state_set(device, TS_NOT_OPER);
+ fallthrough;
case TS_NOT_OPER:
/*
* Nothing to do.
@@ -773,6 +725,36 @@ tape_free_request (struct tape_request * request)
kfree(request);
}
+int
+tape_check_idalbuffer(struct tape_device *device, size_t size)
+{
+ struct idal_buffer **new;
+ size_t old_size = 0;
+
+ old_size = idal_buffer_array_datasize(device->char_data.ibs);
+ if (old_size == size)
+ return 0;
+
+ if (size > MAX_BLOCKSIZE) {
+ DBF_EVENT(3, "Invalid blocksize (%zd > %d)\n",
+ size, MAX_BLOCKSIZE);
+ return -EINVAL;
+ }
+
+ /* The current idal buffer is not correct. Allocate a new one. */
+ new = idal_buffer_array_alloc(size, 0);
+ if (IS_ERR(new))
+ return -ENOMEM;
+
+ /* Free old idal buffer array */
+ if (device->char_data.ibs)
+ idal_buffer_array_free(&device->char_data.ibs);
+
+ device->char_data.ibs = new;
+
+ return 0;
+}
+
static int
__tape_start_io(struct tape_device *device, struct tape_request *request)
{
@@ -867,18 +849,16 @@ tape_delayed_next_request(struct work_struct *work)
spin_unlock_irq(get_ccwdev_lock(device->cdev));
}
-static void tape_long_busy_timeout(unsigned long data)
+static void tape_long_busy_timeout(struct timer_list *t)
{
+ struct tape_device *device = timer_container_of(device, t, lb_timeout);
struct tape_request *request;
- struct tape_device *device;
- device = (struct tape_device *) data;
spin_lock_irq(get_ccwdev_lock(device->cdev));
request = list_entry(device->req_queue.next, struct tape_request, list);
BUG_ON(request->status != TAPE_REQUEST_LONG_BUSY);
DBF_LH(6, "%08x: Long busy timeout.\n", device->cdev_id);
__tape_start_next_request(device);
- device->lb_timeout.data = 0UL;
tape_put_device(device);
spin_unlock_irq(get_ccwdev_lock(device->cdev));
}
@@ -951,6 +931,7 @@ __tape_start_request(struct tape_device *device, struct tape_request *request)
break;
if (device->tape_state == TS_UNUSED)
break;
+ fallthrough;
default:
if (device->tape_state == TS_BLKUSE)
break;
@@ -1118,6 +1099,7 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
case -ETIMEDOUT:
DBF_LH(1, "(%08x): Request timed out\n",
device->cdev_id);
+ fallthrough;
case -EIO:
__tape_end_request(device, request, -EIO);
break;
@@ -1146,9 +1128,10 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
}
/* May be an unsolicited irq */
- if(request != NULL)
+ if (request != NULL) {
request->rescnt = irb->scsw.cmd.count;
- else if ((irb->scsw.cmd.dstat == 0x85 || irb->scsw.cmd.dstat == 0x80) &&
+ memcpy(&request->irb, irb, sizeof(*irb));
+ } else if ((irb->scsw.cmd.dstat == 0x85 || irb->scsw.cmd.dstat == 0x80) &&
!list_empty(&device->req_queue)) {
/* Not Ready to Ready after long busy ? */
struct tape_request *req;
@@ -1156,8 +1139,7 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
struct tape_request, list);
if (req->status == TAPE_REQUEST_LONG_BUSY) {
DBF_EVENT(3, "(%08x): del timer\n", device->cdev_id);
- if (del_timer(&device->lb_timeout)) {
- device->lb_timeout.data = 0UL;
+ if (timer_delete(&device->lb_timeout)) {
tape_put_device(device);
__tape_start_next_request(device);
}
@@ -1212,8 +1194,6 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
case TAPE_IO_PENDING:
break;
case TAPE_IO_LONG_BUSY:
- device->lb_timeout.data =
- (unsigned long) tape_get_device(device);
device->lb_timeout.expires = jiffies +
LONG_BUSY_TIMEOUT * HZ;
DBF_EVENT(3, "(%08x): add timer\n", device->cdev_id);
@@ -1362,7 +1342,6 @@ EXPORT_SYMBOL(tape_generic_remove);
EXPORT_SYMBOL(tape_generic_probe);
EXPORT_SYMBOL(tape_generic_online);
EXPORT_SYMBOL(tape_generic_offline);
-EXPORT_SYMBOL(tape_generic_pm_suspend);
EXPORT_SYMBOL(tape_put_device);
EXPORT_SYMBOL(tape_get_device);
EXPORT_SYMBOL(tape_state_verbose);