summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeiko Carstens <hca@linux.ibm.com>2026-02-04 08:32:01 +0100
committerHeiko Carstens <hca@linux.ibm.com>2026-02-04 08:32:01 +0100
commit01d098dcfdd433862dec89c8b4f9c6372211fe73 (patch)
treeaa652ff029fc6f75d99e438e5ecad1aafa2f7fb2
parentf8a9c11000e52a8e59f15e49edaf5a2857705f9a (diff)
parent9872dae6102eb4d8c3cde83ded9df0d60f4e67d0 (diff)
Merge branch 'tape-devices'
Jan Höppner says: ==================== Quite a lot of the tape device driver code is outdated as devices and storage systems supported by that code aren't supported by IBM anymore for a long time. Especially physical tape devices are not supported or used directly anymore. The only tape storage system supported by IBM is the Virtual Tape Server (VTS) family with TS7700 systems [1]. Host systems will only talk to VTS and are presented with the virtualized 3490E tape device type only. VTS can and still uses tape libraries with physical 3592 cartridges as storage backends (e.g. TS4500). However, these are never seen by any host. The general goal/idea for the tape device driver is to only support VTS from now on. This series gets rid of old outdated code that is not relevant to VTS. There is probably quite a bit more that could be cleaned up or could be improved. However, this is a first run to cleanup the code base and somewhat reduce maintenance burden. [1] https://www.ibm.com/products/ts7700 [2] https://www.ibm.com/products/ts4500 ==================== Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
-rw-r--r--arch/s390/include/uapi/asm/tape390.h103
-rw-r--r--drivers/s390/char/Kconfig15
-rw-r--r--drivers/s390/char/Makefile3
-rw-r--r--drivers/s390/char/tape.h9
-rw-r--r--drivers/s390/char/tape_3490.c833
-rw-r--r--drivers/s390/char/tape_34xx.c1204
-rw-r--r--drivers/s390/char/tape_3590.c1612
-rw-r--r--drivers/s390/char/tape_3590.h175
-rw-r--r--drivers/s390/char/tape_char.c5
-rw-r--r--drivers/s390/char/tape_core.c4
-rw-r--r--drivers/s390/char/tape_std.c32
-rw-r--r--drivers/s390/char/tape_std.h45
12 files changed, 845 insertions, 3195 deletions
diff --git a/arch/s390/include/uapi/asm/tape390.h b/arch/s390/include/uapi/asm/tape390.h
deleted file mode 100644
index 90266c696486..000000000000
--- a/arch/s390/include/uapi/asm/tape390.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*************************************************************************
- *
- * enables user programs to display messages and control encryption
- * on s390 tape devices
- *
- * Copyright IBM Corp. 2001, 2006
- * Author(s): Michael Holzheu <holzheu@de.ibm.com>
- *
- *************************************************************************/
-
-#ifndef _TAPE390_H
-#define _TAPE390_H
-
-#define TAPE390_DISPLAY _IOW('d', 1, struct display_struct)
-
-/*
- * The TAPE390_DISPLAY ioctl calls the Load Display command
- * which transfers 17 bytes of data from the channel to the subsystem:
- * - 1 format control byte, and
- * - two 8-byte messages
- *
- * Format control byte:
- * 0-2: New Message Overlay
- * 3: Alternate Messages
- * 4: Blink Message
- * 5: Display Low/High Message
- * 6: Reserved
- * 7: Automatic Load Request
- *
- */
-
-typedef struct display_struct {
- char cntrl;
- char message1[8];
- char message2[8];
-} display_struct;
-
-/*
- * Tape encryption support
- */
-
-struct tape390_crypt_info {
- char capability;
- char status;
- char medium_status;
-} __attribute__ ((packed));
-
-
-/* Macros for "capable" field */
-#define TAPE390_CRYPT_SUPPORTED_MASK 0x01
-#define TAPE390_CRYPT_SUPPORTED(x) \
- ((x.capability & TAPE390_CRYPT_SUPPORTED_MASK))
-
-/* Macros for "status" field */
-#define TAPE390_CRYPT_ON_MASK 0x01
-#define TAPE390_CRYPT_ON(x) (((x.status) & TAPE390_CRYPT_ON_MASK))
-
-/* Macros for "medium status" field */
-#define TAPE390_MEDIUM_LOADED_MASK 0x01
-#define TAPE390_MEDIUM_ENCRYPTED_MASK 0x02
-#define TAPE390_MEDIUM_ENCRYPTED(x) \
- (((x.medium_status) & TAPE390_MEDIUM_ENCRYPTED_MASK))
-#define TAPE390_MEDIUM_LOADED(x) \
- (((x.medium_status) & TAPE390_MEDIUM_LOADED_MASK))
-
-/*
- * The TAPE390_CRYPT_SET ioctl is used to switch on/off encryption.
- * The "encryption_capable" and "tape_status" fields are ignored for this ioctl!
- */
-#define TAPE390_CRYPT_SET _IOW('d', 2, struct tape390_crypt_info)
-
-/*
- * The TAPE390_CRYPT_QUERY ioctl is used to query the encryption state.
- */
-#define TAPE390_CRYPT_QUERY _IOR('d', 3, struct tape390_crypt_info)
-
-/* Values for "kekl1/2_type" and "kekl1/2_type_on_tape" fields */
-#define TAPE390_KEKL_TYPE_NONE 0
-#define TAPE390_KEKL_TYPE_LABEL 1
-#define TAPE390_KEKL_TYPE_HASH 2
-
-struct tape390_kekl {
- unsigned char type;
- unsigned char type_on_tape;
- char label[65];
-} __attribute__ ((packed));
-
-struct tape390_kekl_pair {
- struct tape390_kekl kekl[2];
-} __attribute__ ((packed));
-
-/*
- * The TAPE390_KEKL_SET ioctl is used to set Key Encrypting Key labels.
- */
-#define TAPE390_KEKL_SET _IOW('d', 4, struct tape390_kekl_pair)
-
-/*
- * The TAPE390_KEKL_QUERY ioctl is used to query Key Encrypting Key labels.
- */
-#define TAPE390_KEKL_QUERY _IOR('d', 5, struct tape390_kekl_pair)
-
-#endif
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig
index 80c4e5101c97..1139d260ea93 100644
--- a/drivers/s390/char/Kconfig
+++ b/drivers/s390/char/Kconfig
@@ -121,21 +121,12 @@ config S390_TAPE
comment "S/390 tape hardware support"
depends on S390_TAPE
-config S390_TAPE_34XX
+config S390_TAPE_3490
def_tristate m
- prompt "Support for 3480/3490 tape hardware"
+ prompt "Support for 3490 tape hardware"
depends on S390_TAPE
help
- Select this option if you want to access IBM 3480/3490 magnetic
- tape subsystems and 100% compatibles.
- It is safe to say "Y" here.
-
-config S390_TAPE_3590
- def_tristate m
- prompt "Support for 3590 tape hardware"
- depends on S390_TAPE
- help
- Select this option if you want to access IBM 3590 magnetic
+ Select this option if you want to access IBM 3490 magnetic
tape subsystems and 100% compatibles.
It is safe to say "Y" here.
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index dcbd51152ee3..8256fac51c13 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -41,8 +41,7 @@ obj-$(CONFIG_VMCP) += vmcp.o
tape-$(CONFIG_PROC_FS) += tape_proc.o
tape-objs := tape_core.o tape_std.o tape_char.o $(tape-y)
obj-$(CONFIG_S390_TAPE) += tape.o tape_class.o
-obj-$(CONFIG_S390_TAPE_34XX) += tape_34xx.o
-obj-$(CONFIG_S390_TAPE_3590) += tape_3590.o
+obj-$(CONFIG_S390_TAPE_3490) += tape_3490.o
obj-$(CONFIG_MONREADER) += monreader.o
obj-$(CONFIG_MONWRITER) += monwriter.o
obj-$(CONFIG_S390_VMUR) += vmur.o
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index 3953b31b0c55..bfbfb3b48aca 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * tape device driver for 3480/3490E/3590 tapes.
+ * tape device driver for 3490E tapes.
*
* S390 and zSeries version
* Copyright IBM Corp. 2001, 2009
@@ -98,10 +98,6 @@ enum tape_op {
TO_DIS, /* Tape display */
TO_ASSIGN, /* Assign tape to channel path */
TO_UNASSIGN, /* Unassign tape from channel path */
- TO_CRYPT_ON, /* Enable encrpytion */
- TO_CRYPT_OFF, /* Disable encrpytion */
- TO_KEKL_SET, /* Set KEK label */
- TO_KEKL_QUERY, /* Query KEK label */
TO_RDC, /* Read device characteristics */
TO_SIZE, /* #entries in tape_op_t */
};
@@ -155,8 +151,6 @@ struct tape_discipline {
struct tape_request *(*read_block)(struct tape_device *);
struct tape_request *(*write_block)(struct tape_device *);
void (*process_eov)(struct tape_device*);
- /* ioctl function for additional ioctls. */
- int (*ioctl_fn)(struct tape_device *, unsigned int, unsigned long);
/* Array of tape commands with TAPE_NR_MTOPS entries */
tape_mtop_fn *mtop_array;
};
@@ -192,7 +186,6 @@ struct tape_device {
/* Device discipline information. */
struct tape_discipline * discipline;
- void * discdata;
/* Generic status flags */
long tape_generic_status;
diff --git a/drivers/s390/char/tape_3490.c b/drivers/s390/char/tape_3490.c
new file mode 100644
index 000000000000..83898f92ad0f
--- /dev/null
+++ b/drivers/s390/char/tape_3490.c
@@ -0,0 +1,833 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * tape device discipline for 3490 tapes.
+ *
+ * Copyright IBM Corp. 2001, 2009
+ * Author(s): Carsten Otte <cotte@de.ibm.com>
+ * Tuan Ngo-Anh <ngoanh@de.ibm.com>
+ * Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#define pr_fmt(fmt) "tape_3490: " fmt
+
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bio.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+
+#define TAPE_DBF_AREA tape_3490_dbf
+
+#include "tape.h"
+#include "tape_std.h"
+
+/*
+ * Pointer to debug area.
+ */
+debug_info_t *TAPE_DBF_AREA = NULL;
+EXPORT_SYMBOL(TAPE_DBF_AREA);
+
+struct tape_3490_block_id {
+ unsigned int unused : 10;
+ unsigned int block : 22;
+};
+
+/*
+ * Medium sense for 3490 tapes. There is no 'real' medium sense call.
+ * So we just do a normal sense.
+ */
+static void __tape_3490_medium_sense(struct tape_request *request)
+{
+ struct tape_device *device = request->device;
+ unsigned char *sense;
+
+ if (request->rc == 0) {
+ sense = request->cpdata;
+
+ /*
+ * This isn't quite correct. But since INTERVENTION_REQUIRED
+ * means that the drive is 'neither ready nor on-line' it is
+ * only slightly inaccurate to say there is no tape loaded if
+ * the drive isn't online...
+ */
+ if (sense[0] & SENSE_INTERVENTION_REQUIRED)
+ tape_med_state_set(device, MS_UNLOADED);
+ else
+ tape_med_state_set(device, MS_LOADED);
+
+ if (sense[1] & SENSE_WRITE_PROTECT)
+ device->tape_generic_status |= GMT_WR_PROT(~0);
+ else
+ device->tape_generic_status &= ~GMT_WR_PROT(~0);
+ } else
+ DBF_EVENT(4, "tape_3490: medium sense failed with rc=%d\n",
+ request->rc);
+ tape_free_request(request);
+}
+
+static int tape_3490_medium_sense(struct tape_device *device)
+{
+ struct tape_request *request;
+ int rc;
+
+ request = tape_alloc_request(1, 32);
+ if (IS_ERR(request)) {
+ DBF_EXCEPTION(6, "MSEN fail\n");
+ return PTR_ERR(request);
+ }
+
+ request->op = TO_MSEN;
+ tape_ccw_end(request->cpaddr, SENSE, 32, request->cpdata);
+ rc = tape_do_io_interruptible(device, request);
+ __tape_3490_medium_sense(request);
+ return rc;
+}
+
+static void tape_3490_medium_sense_async(struct tape_device *device)
+{
+ struct tape_request *request;
+
+ request = tape_alloc_request(1, 32);
+ if (IS_ERR(request)) {
+ DBF_EXCEPTION(6, "MSEN fail\n");
+ return;
+ }
+
+ request->op = TO_MSEN;
+ tape_ccw_end(request->cpaddr, SENSE, 32, request->cpdata);
+ request->callback = (void *) __tape_3490_medium_sense;
+ request->callback_data = NULL;
+ tape_do_io_async(device, request);
+}
+
+struct tape_3490_work {
+ struct tape_device *device;
+ enum tape_op op;
+ struct work_struct work;
+};
+
+/*
+ * These functions are currently used only to schedule a medium_sense for
+ * later execution. This is because we get an interrupt whenever a medium
+ * is inserted but cannot call tape_do_io* from an interrupt context.
+ * Maybe that's useful for other actions we want to start from the
+ * interrupt handler.
+ * Note: the work handler is called by the system work queue. The tape
+ * commands started by the handler need to be asynchrounous, otherwise
+ * a deadlock can occur e.g. in case of a deferred cc=1 (see __tape_do_irq).
+ */
+static void
+tape_3490_work_handler(struct work_struct *work)
+{
+ struct tape_3490_work *p =
+ container_of(work, struct tape_3490_work, work);
+ struct tape_device *device = p->device;
+
+ switch(p->op) {
+ case TO_MSEN:
+ tape_3490_medium_sense_async(device);
+ break;
+ default:
+ DBF_EVENT(3, "T3490: internal error: unknown work\n");
+ }
+ tape_put_device(device);
+ kfree(p);
+}
+
+static int
+tape_3490_schedule_work(struct tape_device *device, enum tape_op op)
+{
+ struct tape_3490_work *p;
+
+ if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL)
+ return -ENOMEM;
+
+ INIT_WORK(&p->work, tape_3490_work_handler);
+
+ p->device = tape_get_device(device);
+ p->op = op;
+
+ schedule_work(&p->work);
+ return 0;
+}
+
+/*
+ * Done Handler is called when dev stat = DEVICE-END (successful operation)
+ */
+static inline int
+tape_3490_done(struct tape_request *request)
+{
+ DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]);
+ return TAPE_IO_SUCCESS;
+}
+
+static inline int
+tape_3490_erp_failed(struct tape_request *request, int rc)
+{
+ DBF_EVENT(3, "Error recovery failed for %s (RC=%d)\n",
+ tape_op_verbose[request->op], rc);
+ return rc;
+}
+
+static inline int
+tape_3490_erp_succeeded(struct tape_request *request)
+{
+ DBF_EVENT(3, "Error Recovery successful for %s\n",
+ tape_op_verbose[request->op]);
+ return tape_3490_done(request);
+}
+
+static inline int
+tape_3490_erp_retry(struct tape_request *request)
+{
+ DBF_EVENT(3, "xerp retr %s\n", tape_op_verbose[request->op]);
+ return TAPE_IO_RETRY;
+}
+
+/*
+ * This function is called, when no request is outstanding and we get an
+ * interrupt
+ */
+static int
+tape_3490_unsolicited_irq(struct tape_device *device, struct irb *irb)
+{
+ if (irb->scsw.cmd.dstat == 0x85) { /* READY */
+ /* A medium was inserted in the drive. */
+ DBF_EVENT(6, "xuud med\n");
+ tape_3490_schedule_work(device, TO_MSEN);
+ } else {
+ DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id);
+ tape_dump_sense_dbf(device, NULL, irb);
+ }
+ return TAPE_IO_SUCCESS;
+}
+
+static int
+tape_3490_erp_bug(struct tape_device *device, struct tape_request *request,
+ struct irb *irb, int no)
+{
+ if (request->op != TO_ASSIGN) {
+ dev_err(&device->cdev->dev, "An unexpected condition %d "
+ "occurred in tape error recovery\n", no);
+ tape_dump_sense_dbf(device, request, irb);
+ }
+ return tape_3490_erp_failed(request, -EIO);
+}
+
+/*
+ * Handle data overrun between cu and drive. The channel speed might
+ * be too slow.
+ */
+static int
+tape_3490_erp_overrun(struct tape_device *device, struct tape_request *request,
+ struct irb *irb)
+{
+ if (irb->ecw[3] == 0x40) {
+ dev_warn (&device->cdev->dev, "A data overrun occurred between"
+ " the control unit and tape unit\n");
+ return tape_3490_erp_failed(request, -EIO);
+ }
+ return tape_3490_erp_bug(device, request, irb, -1);
+}
+
+/*
+ * Handle record sequence error.
+ */
+static int
+tape_3490_erp_sequence(struct tape_device *device,
+ struct tape_request *request, struct irb *irb)
+{
+ if (irb->ecw[3] == 0x41) {
+ /*
+ * cu detected incorrect block-id sequence on tape.
+ */
+ dev_warn (&device->cdev->dev, "The block ID sequence on the "
+ "tape is incorrect\n");
+ return tape_3490_erp_failed(request, -EIO);
+ }
+ /*
+ * Record sequence error bit is set, but erpa does not
+ * show record sequence error.
+ */
+ return tape_3490_erp_bug(device, request, irb, -2);
+}
+
+/*
+ * This function analyses the tape's sense-data in case of a unit-check.
+ * If possible, it tries to recover from the error. Else the user is
+ * informed about the problem.
+ */
+static int
+tape_3490_unit_check(struct tape_device *device, struct tape_request *request,
+ struct irb *irb)
+{
+ int inhibit_cu_recovery;
+ __u8* sense;
+
+ inhibit_cu_recovery = (*device->modeset_byte & 0x80) ? 1 : 0;
+ sense = irb->ecw;
+
+ if (
+ sense[0] & SENSE_COMMAND_REJECT &&
+ sense[1] & SENSE_WRITE_PROTECT
+ ) {
+ if (
+ request->op == TO_DSE ||
+ request->op == TO_WRI ||
+ request->op == TO_WTM
+ ) {
+ /* medium is write protected */
+ return tape_3490_erp_failed(request, -EACCES);
+ } else {
+ return tape_3490_erp_bug(device, request, irb, -3);
+ }
+ }
+
+ /*
+ * Special cases for various tape-states when reaching
+ * end of recorded area
+ *
+ * FIXME: Maybe a special case of the special case:
+ * sense[0] == SENSE_EQUIPMENT_CHECK &&
+ * sense[1] == SENSE_DRIVE_ONLINE &&
+ * sense[3] == 0x47 (Volume Fenced)
+ *
+ * This was caused by continued FSF or FSR after an
+ * 'End Of Data'.
+ */
+ if ((
+ sense[0] == SENSE_DATA_CHECK ||
+ sense[0] == SENSE_EQUIPMENT_CHECK ||
+ sense[0] == (SENSE_EQUIPMENT_CHECK | SENSE_DEFERRED_UNIT_CHECK)
+ ) && (
+ sense[1] == SENSE_DRIVE_ONLINE ||
+ sense[1] == (SENSE_BEGINNING_OF_TAPE | SENSE_WRITE_MODE)
+ )) {
+ switch (request->op) {
+ /*
+ * sense[0] == SENSE_DATA_CHECK &&
+ * sense[1] == SENSE_DRIVE_ONLINE
+ * sense[3] == 0x36 (End Of Data)
+ *
+ * Further seeks might return a 'Volume Fenced'.
+ */
+ case TO_FSF:
+ case TO_FSB:
+ /* Trying to seek beyond end of recorded area */
+ return tape_3490_erp_failed(request, -ENOSPC);
+ case TO_BSB:
+ return tape_3490_erp_retry(request);
+
+ /*
+ * sense[0] == SENSE_DATA_CHECK &&
+ * sense[1] == SENSE_DRIVE_ONLINE &&
+ * sense[3] == 0x36 (End Of Data)
+ */
+ case TO_LBL:
+ /* Block could not be located. */
+ return tape_3490_erp_failed(request, -EIO);
+
+ case TO_RFO:
+ /* Read beyond end of recorded area -> 0 bytes read */
+ return tape_3490_erp_failed(request, 0);
+
+ /*
+ * sense[0] == SENSE_EQUIPMENT_CHECK &&
+ * sense[1] == SENSE_DRIVE_ONLINE &&
+ * sense[3] == 0x38 (Physical End Of Volume)
+ */
+ case TO_WRI:
+ /* Writing at physical end of volume */
+ return tape_3490_erp_failed(request, -ENOSPC);
+ default:
+ return tape_3490_erp_failed(request, 0);
+ }
+ }
+
+ /* Sensing special bits */
+ if (sense[0] & SENSE_BUS_OUT_CHECK)
+ return tape_3490_erp_retry(request);
+
+ if (sense[0] & SENSE_DATA_CHECK) {
+ /*
+ * hardware failure, damaged tape or improper
+ * operating conditions
+ */
+ switch (sense[3]) {
+ case 0x23:
+ /* a read data check occurred */
+ if ((sense[2] & SENSE_TAPE_SYNC_MODE) ||
+ inhibit_cu_recovery)
+ // data check is not permanent, may be
+ // recovered. We always use async-mode with
+ // cu-recovery, so this should *never* happen.
+ return tape_3490_erp_bug(device, request,
+ irb, -4);
+
+ /* data check is permanent, CU recovery has failed */
+ dev_warn (&device->cdev->dev, "A read error occurred "
+ "that cannot be recovered\n");
+ return tape_3490_erp_failed(request, -EIO);
+ case 0x25:
+ // a write data check occurred
+ if ((sense[2] & SENSE_TAPE_SYNC_MODE) ||
+ inhibit_cu_recovery)
+ // data check is not permanent, may be
+ // recovered. We always use async-mode with
+ // cu-recovery, so this should *never* happen.
+ return tape_3490_erp_bug(device, request,
+ irb, -5);
+
+ // data check is permanent, cu-recovery has failed
+ dev_warn (&device->cdev->dev, "A write error on the "
+ "tape cannot be recovered\n");
+ return tape_3490_erp_failed(request, -EIO);
+ case 0x28:
+ /* ID-Mark at tape start couldn't be written */
+ dev_warn (&device->cdev->dev, "Writing the ID-mark "
+ "failed\n");
+ return tape_3490_erp_failed(request, -EIO);
+ case 0x31:
+ /* Tape void. Tried to read beyond end of device. */
+ dev_warn (&device->cdev->dev, "Reading the tape beyond"
+ " the end of the recorded area failed\n");
+ return tape_3490_erp_failed(request, -ENOSPC);
+ case 0x41:
+ /* Record sequence error. */
+ dev_warn (&device->cdev->dev, "The tape contains an "
+ "incorrect block ID sequence\n");
+ return tape_3490_erp_failed(request, -EIO);
+ }
+ }
+
+ if (sense[0] & SENSE_OVERRUN)
+ return tape_3490_erp_overrun(device, request, irb);
+
+ if (sense[1] & SENSE_RECORD_SEQUENCE_ERR)
+ return tape_3490_erp_sequence(device, request, irb);
+
+ /* Sensing erpa codes */
+ switch (sense[3]) {
+ case 0x00:
+ /* Unit check with erpa code 0. Report and ignore. */
+ return TAPE_IO_SUCCESS;
+ case 0x27:
+ /*
+ * Command reject. May indicate illegal channel program or
+ * buffer over/underrun. Since all channel programs are
+ * issued by this driver and ought be correct, we assume a
+ * over/underrun situation and retry the channel program.
+ */
+ return tape_3490_erp_retry(request);
+ case 0x29:
+ /*
+ * Function incompatible. Either the tape is idrc compressed
+ * but the hardware isn't capable to do idrc, or a perform
+ * subsystem func is issued and the CU is not on-line.
+ */
+ return tape_3490_erp_failed(request, -EIO);
+ case 0x2b:
+ /*
+ * Environmental data present. Indicates either unload
+ * completed ok or read buffered log command completed ok.
+ */
+ if (request->op == TO_RUN) {
+ /* Rewind unload completed ok. */
+ tape_med_state_set(device, MS_UNLOADED);
+ return tape_3490_erp_succeeded(request);
+ }
+ /* tape_3490 doesn't use read buffered log commands. */
+ return tape_3490_erp_bug(device, request, irb, sense[3]);
+ case 0x2c:
+ /*
+ * Permanent equipment check. CU has tried recovery, but
+ * did not succeed.
+ */
+ return tape_3490_erp_failed(request, -EIO);
+ case 0x2d:
+ /* Data security erase failure. */
+ if (request->op == TO_DSE)
+ return tape_3490_erp_failed(request, -EIO);
+ /* Data security erase failure, but no such command issued. */
+ return tape_3490_erp_bug(device, request, irb, sense[3]);
+ case 0x2e:
+ /*
+ * Not capable. This indicates either that the drive fails
+ * reading the format id mark or that format specified
+ * is not supported by the drive.
+ */
+ dev_warn (&device->cdev->dev, "The tape unit cannot process "
+ "the tape format\n");
+ return tape_3490_erp_failed(request, -EMEDIUMTYPE);
+ case 0x30:
+ /* The medium is write protected. */
+ dev_warn (&device->cdev->dev, "The tape medium is write-"
+ "protected\n");
+ return tape_3490_erp_failed(request, -EACCES);
+ case 0x35:
+ /*
+ * Drive equipment check. One of the following:
+ * - cu cannot recover from a drive detected error
+ * - a check code message is shown on drive display
+ * - the cartridge loader does not respond correctly
+ * - a failure occurs during an index, load, or unload cycle
+ */
+ dev_warn (&device->cdev->dev, "An equipment check has occurred"
+ " on the tape unit\n");
+ return tape_3490_erp_failed(request, -EIO);
+ case 0x36:
+ /* End of data. */
+ return tape_3490_erp_failed(request, -EIO);
+ case 0x38:
+ /*
+ * Physical end of tape. A read/write operation reached
+ * the physical end of tape.
+ */
+ if (request->op==TO_WRI ||
+ request->op==TO_DSE ||
+ request->op==TO_WTM)
+ return tape_3490_erp_failed(request, -ENOSPC);
+ return tape_3490_erp_failed(request, -EIO);
+ case 0x39:
+ /* Backward at Beginning of tape. */
+ return tape_3490_erp_failed(request, -EIO);
+ case 0x42:
+ /*
+ * Degraded mode. A condition that can cause degraded
+ * performance is detected.
+ */
+ dev_warn (&device->cdev->dev, "The tape subsystem is running "
+ "in degraded mode\n");
+ return tape_3490_erp_retry(request);
+ case 0x43:
+ /* Drive not ready. */
+ tape_med_state_set(device, MS_UNLOADED);
+ /* Some commands commands are successful even in this case */
+ if (sense[1] & SENSE_DRIVE_ONLINE) {
+ switch(request->op) {
+ case TO_ASSIGN:
+ case TO_UNASSIGN:
+ case TO_DIS:
+ case TO_NOP:
+ return tape_3490_done(request);
+ break;
+ default:
+ break;
+ }
+ }
+ return tape_3490_erp_failed(request, -ENOMEDIUM);
+ case 0x44:
+ /* Locate Block unsuccessful. */
+ if (request->op != TO_BLOCK && request->op != TO_LBL)
+ /* No locate block was issued. */
+ return tape_3490_erp_bug(device, request,
+ irb, sense[3]);
+ return tape_3490_erp_failed(request, -EIO);
+ case 0x45:
+ /* The drive is assigned to a different channel path. */
+ dev_warn (&device->cdev->dev, "The tape unit is already "
+ "assigned\n");
+ return tape_3490_erp_failed(request, -EIO);
+ case 0x47:
+ /* Volume fenced. CU reports volume integrity is lost. */
+ dev_warn (&device->cdev->dev, "The control unit has fenced "
+ "access to the tape volume\n");
+ return tape_3490_erp_failed(request, -EIO);
+ case 0x48:
+ /* Log sense data and retry request. */
+ return tape_3490_erp_retry(request);
+ case 0x4d:
+ /*
+ * Resetting event received. Since the driver does
+ * not support resetting event recovery (which has to
+ * be handled by the I/O Layer), retry our command.
+ */
+ return tape_3490_erp_retry(request);
+ case 0x4e:
+ /*
+ * Maximum block size exceeded. This indicates, that
+ * the block to be written is larger than allowed for
+ * buffered mode.
+ */
+ dev_warn (&device->cdev->dev,
+ "The maximum block size for buffered mode is exceeded\n");
+ return tape_3490_erp_failed(request, -ENOBUFS);
+ case 0x50:
+ /*
+ * Read buffered log (Overflow). CU is running in extended
+ * buffered log mode, and a counter overflows. This should
+ * never happen, since we're never running in extended
+ * buffered log mode.
+ */
+ return tape_3490_erp_retry(request);
+ case 0x51:
+ /*
+ * Read buffered log (EOV). EOF processing occurs while the
+ * CU is in extended buffered log mode. This should never
+ * happen, since we're never running in extended buffered
+ * log mode.
+ */
+ return tape_3490_erp_retry(request);
+ case 0x52:
+ /* End of Volume complete. Rewind unload completed ok. */
+ if (request->op == TO_RUN) {
+ tape_med_state_set(device, MS_UNLOADED);
+ return tape_3490_erp_succeeded(request);
+ }
+ return tape_3490_erp_bug(device, request, irb, sense[3]);
+ case 0x53:
+ /* Global command intercept. */
+ return tape_3490_erp_retry(request);
+ case 0x54:
+ /* Channel interface recovery (temporary). */
+ return tape_3490_erp_retry(request);
+ case 0x55:
+ /* Channel interface recovery (permanent). */
+ dev_warn (&device->cdev->dev, "A channel interface error cannot be"
+ " recovered\n");
+ return tape_3490_erp_failed(request, -EIO);
+ case 0x56:
+ /* Channel protocol error. */
+ dev_warn (&device->cdev->dev, "A channel protocol error "
+ "occurred\n");
+ return tape_3490_erp_failed(request, -EIO);
+ case 0x57:
+ /* Global status intercept. */
+ return tape_3490_erp_retry(request);
+ /* The following erpas should have been covered earlier. */
+ case 0x23: /* Read data check. */
+ case 0x25: /* Write data check. */
+ case 0x28: /* Write id mark check. */
+ case 0x31: /* Tape void. */
+ case 0x40: /* Overrun error. */
+ case 0x41: /* Record sequence error. */
+ /* All other erpas are reserved for future use. */
+ default:
+ return tape_3490_erp_bug(device, request, irb, sense[3]);
+ }
+}
+
+/*
+ * 3490 interrupt handler
+ */
+static int
+tape_3490_irq(struct tape_device *device, struct tape_request *request,
+ struct irb *irb)
+{
+ if (request == NULL)
+ return tape_3490_unsolicited_irq(device, irb);
+
+ if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) &&
+ (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) &&
+ (request->op == TO_WRI)) {
+ /* Write at end of volume */
+ return tape_3490_erp_failed(request, -ENOSPC);
+ }
+
+ if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)
+ return tape_3490_unit_check(device, request, irb);
+
+ if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) {
+ /*
+ * A unit exception occurs on skipping over a tapemark block.
+ */
+ if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) {
+ if (request->op == TO_BSB || request->op == TO_FSB)
+ request->rescnt++;
+ else
+ DBF_EVENT(5, "Unit Exception!\n");
+ }
+ return tape_3490_done(request);
+ }
+
+ DBF_EVENT(6, "xunknownirq\n");
+ tape_dump_sense_dbf(device, request, irb);
+ return TAPE_IO_STOP;
+}
+
+static int
+tape_3490_setup_device(struct tape_device * device)
+{
+ int rc;
+
+ DBF_EVENT(6, "3490 device setup\n");
+ if ((rc = tape_std_assign(device)) == 0) {
+ if ((rc = tape_3490_medium_sense(device)) != 0) {
+ DBF_LH(3, "3490 medium sense returned %d\n", rc);
+ }
+ }
+ return rc;
+}
+
+static void
+tape_3490_cleanup_device(struct tape_device *device)
+{
+ tape_std_unassign(device);
+}
+
+
+/*
+ * MTTELL: Tell block. Return the number of block relative to current file.
+ */
+static int
+tape_3490_mttell(struct tape_device *device, int mt_count)
+{
+ struct {
+ struct tape_3490_block_id cbid;
+ struct tape_3490_block_id dbid;
+ } __attribute__ ((packed)) block_id;
+ int rc;
+
+ rc = tape_std_read_block_id(device, (__u64 *) &block_id);
+ if (rc)
+ return rc;
+
+ return block_id.cbid.block;
+}
+
+/*
+ * MTSEEK: seek to the specified block.
+ */
+static int
+tape_3490_mtseek(struct tape_device *device, int mt_count)
+{
+ struct tape_request *request;
+ struct tape_3490_block_id * bid;
+
+ if (mt_count > 0x3fffff) {
+ DBF_EXCEPTION(6, "xsee parm\n");
+ return -EINVAL;
+ }
+ request = tape_alloc_request(3, 4);
+ if (IS_ERR(request))
+ return PTR_ERR(request);
+
+ /* setup ccws */
+ request->op = TO_LBL;
+ bid = (struct tape_3490_block_id *) request->cpdata;
+ bid->block = mt_count;
+
+ tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
+ tape_ccw_cc(request->cpaddr + 1, LOCATE, 4, request->cpdata);
+ tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);
+
+ /* execute it */
+ return tape_do_io_free(device, request);
+}
+
+/*
+ * List of 3490 tape commands.
+ */
+static tape_mtop_fn tape_3490_mtop[TAPE_NR_MTOPS] = {
+ [MTRESET] = tape_std_mtreset,
+ [MTFSF] = tape_std_mtfsf,
+ [MTBSF] = tape_std_mtbsf,
+ [MTFSR] = tape_std_mtfsr,
+ [MTBSR] = tape_std_mtbsr,
+ [MTWEOF] = tape_std_mtweof,
+ [MTREW] = tape_std_mtrew,
+ [MTOFFL] = tape_std_mtoffl,
+ [MTNOP] = tape_std_mtnop,
+ [MTRETEN] = tape_std_mtreten,
+ [MTBSFM] = tape_std_mtbsfm,
+ [MTFSFM] = tape_std_mtfsfm,
+ [MTEOM] = tape_std_mteom,
+ [MTERASE] = tape_std_mterase,
+ [MTRAS1] = NULL,
+ [MTRAS2] = NULL,
+ [MTRAS3] = NULL,
+ [MTSETBLK] = tape_std_mtsetblk,
+ [MTSETDENSITY] = NULL,
+ [MTSEEK] = tape_3490_mtseek,
+ [MTTELL] = tape_3490_mttell,
+ [MTSETDRVBUFFER] = NULL,
+ [MTFSS] = NULL,
+ [MTBSS] = NULL,
+ [MTWSM] = NULL,
+ [MTLOCK] = NULL,
+ [MTUNLOCK] = NULL,
+ [MTLOAD] = tape_std_mtload,
+ [MTUNLOAD] = tape_std_mtunload,
+ [MTCOMPRESSION] = tape_std_mtcompression,
+ [MTSETPART] = NULL,
+ [MTMKPART] = NULL
+};
+
+/*
+ * Tape discipline structure for 3490.
+ */
+static struct tape_discipline tape_discipline_3490 = {
+ .owner = THIS_MODULE,
+ .setup_device = tape_3490_setup_device,
+ .cleanup_device = tape_3490_cleanup_device,
+ .process_eov = tape_std_process_eov,
+ .irq = tape_3490_irq,
+ .read_block = tape_std_read_block,
+ .write_block = tape_std_write_block,
+ .mtop_array = tape_3490_mtop
+};
+
+static struct ccw_device_id tape_3490_ids[] = {
+ { CCW_DEVICE_DEVTYPE(0x3490, 0, 0x3490, 0), .driver_info = tape_3490},
+ { /* end of list */ },
+};
+
+static int
+tape_3490_online(struct ccw_device *cdev)
+{
+ return tape_generic_online(
+ dev_get_drvdata(&cdev->dev),
+ &tape_discipline_3490
+ );
+}
+
+static struct ccw_driver tape_3490_driver = {
+ .driver = {
+ .name = "tape_3490",
+ .owner = THIS_MODULE,
+ },
+ .ids = tape_3490_ids,
+ .probe = tape_generic_probe,
+ .remove = tape_generic_remove,
+ .set_online = tape_3490_online,
+ .set_offline = tape_generic_offline,
+ .int_class = IRQIO_TAP,
+};
+
+static int
+tape_3490_init (void)
+{
+ int rc;
+
+ TAPE_DBF_AREA = debug_register ( "tape_3490", 2, 2, 4*sizeof(long));
+ debug_register_view(TAPE_DBF_AREA, &debug_sprintf_view);
+#ifdef DBF_LIKE_HELL
+ debug_set_level(TAPE_DBF_AREA, 6);
+#endif
+
+ DBF_EVENT(3, "3490 init\n");
+ /* Register driver for 3490 tapes. */
+ rc = ccw_driver_register(&tape_3490_driver);
+ if (rc)
+ DBF_EVENT(3, "3490 init failed\n");
+ else
+ DBF_EVENT(3, "3490 registered\n");
+ return rc;
+}
+
+static void
+tape_3490_exit(void)
+{
+ ccw_driver_unregister(&tape_3490_driver);
+
+ debug_unregister(TAPE_DBF_AREA);
+}
+
+MODULE_DEVICE_TABLE(ccw, tape_3490_ids);
+MODULE_AUTHOR("(C) 2001-2002 IBM Deutschland Entwicklung GmbH");
+MODULE_DESCRIPTION("Linux on zSeries channel attached 3490 tape device driver");
+MODULE_LICENSE("GPL");
+
+module_init(tape_3490_init);
+module_exit(tape_3490_exit);
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c
deleted file mode 100644
index a13e0ac1a4e2..000000000000
--- a/drivers/s390/char/tape_34xx.c
+++ /dev/null
@@ -1,1204 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * tape device discipline for 3480/3490 tapes.
- *
- * Copyright IBM Corp. 2001, 2009
- * Author(s): Carsten Otte <cotte@de.ibm.com>
- * Tuan Ngo-Anh <ngoanh@de.ibm.com>
- * Martin Schwidefsky <schwidefsky@de.ibm.com>
- */
-
-#define pr_fmt(fmt) "tape_34xx: " fmt
-
-#include <linux/export.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/bio.h>
-#include <linux/workqueue.h>
-#include <linux/slab.h>
-
-#define TAPE_DBF_AREA tape_34xx_dbf
-
-#include "tape.h"
-#include "tape_std.h"
-
-/*
- * Pointer to debug area.
- */
-debug_info_t *TAPE_DBF_AREA = NULL;
-EXPORT_SYMBOL(TAPE_DBF_AREA);
-
-#define TAPE34XX_FMT_3480 0
-#define TAPE34XX_FMT_3480_2_XF 1
-#define TAPE34XX_FMT_3480_XF 2
-
-struct tape_34xx_block_id {
- unsigned int wrap : 1;
- unsigned int segment : 7;
- unsigned int format : 2;
- unsigned int block : 22;
-};
-
-/*
- * A list of block ID's is used to faster seek blocks.
- */
-struct tape_34xx_sbid {
- struct list_head list;
- struct tape_34xx_block_id bid;
-};
-
-static void tape_34xx_delete_sbid_from(struct tape_device *, int);
-
-/*
- * Medium sense for 34xx tapes. There is no 'real' medium sense call.
- * So we just do a normal sense.
- */
-static void __tape_34xx_medium_sense(struct tape_request *request)
-{
- struct tape_device *device = request->device;
- unsigned char *sense;
-
- if (request->rc == 0) {
- sense = request->cpdata;
-
- /*
- * This isn't quite correct. But since INTERVENTION_REQUIRED
- * means that the drive is 'neither ready nor on-line' it is
- * only slightly inaccurate to say there is no tape loaded if
- * the drive isn't online...
- */
- if (sense[0] & SENSE_INTERVENTION_REQUIRED)
- tape_med_state_set(device, MS_UNLOADED);
- else
- tape_med_state_set(device, MS_LOADED);
-
- if (sense[1] & SENSE_WRITE_PROTECT)
- device->tape_generic_status |= GMT_WR_PROT(~0);
- else
- device->tape_generic_status &= ~GMT_WR_PROT(~0);
- } else
- DBF_EVENT(4, "tape_34xx: medium sense failed with rc=%d\n",
- request->rc);
- tape_free_request(request);
-}
-
-static int tape_34xx_medium_sense(struct tape_device *device)
-{
- struct tape_request *request;
- int rc;
-
- request = tape_alloc_request(1, 32);
- if (IS_ERR(request)) {
- DBF_EXCEPTION(6, "MSEN fail\n");
- return PTR_ERR(request);
- }
-
- request->op = TO_MSEN;
- tape_ccw_end(request->cpaddr, SENSE, 32, request->cpdata);
- rc = tape_do_io_interruptible(device, request);
- __tape_34xx_medium_sense(request);
- return rc;
-}
-
-static void tape_34xx_medium_sense_async(struct tape_device *device)
-{
- struct tape_request *request;
-
- request = tape_alloc_request(1, 32);
- if (IS_ERR(request)) {
- DBF_EXCEPTION(6, "MSEN fail\n");
- return;
- }
-
- request->op = TO_MSEN;
- tape_ccw_end(request->cpaddr, SENSE, 32, request->cpdata);
- request->callback = (void *) __tape_34xx_medium_sense;
- request->callback_data = NULL;
- tape_do_io_async(device, request);
-}
-
-struct tape_34xx_work {
- struct tape_device *device;
- enum tape_op op;
- struct work_struct work;
-};
-
-/*
- * These functions are currently used only to schedule a medium_sense for
- * later execution. This is because we get an interrupt whenever a medium
- * is inserted but cannot call tape_do_io* from an interrupt context.
- * Maybe that's useful for other actions we want to start from the
- * interrupt handler.
- * Note: the work handler is called by the system work queue. The tape
- * commands started by the handler need to be asynchrounous, otherwise
- * a deadlock can occur e.g. in case of a deferred cc=1 (see __tape_do_irq).
- */
-static void
-tape_34xx_work_handler(struct work_struct *work)
-{
- struct tape_34xx_work *p =
- container_of(work, struct tape_34xx_work, work);
- struct tape_device *device = p->device;
-
- switch(p->op) {
- case TO_MSEN:
- tape_34xx_medium_sense_async(device);
- break;
- default:
- DBF_EVENT(3, "T34XX: internal error: unknown work\n");
- }
- tape_put_device(device);
- kfree(p);
-}
-
-static int
-tape_34xx_schedule_work(struct tape_device *device, enum tape_op op)
-{
- struct tape_34xx_work *p;
-
- if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL)
- return -ENOMEM;
-
- INIT_WORK(&p->work, tape_34xx_work_handler);
-
- p->device = tape_get_device(device);
- p->op = op;
-
- schedule_work(&p->work);
- return 0;
-}
-
-/*
- * Done Handler is called when dev stat = DEVICE-END (successful operation)
- */
-static inline int
-tape_34xx_done(struct tape_request *request)
-{
- DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]);
-
- switch (request->op) {
- case TO_DSE:
- case TO_RUN:
- case TO_WRI:
- case TO_WTM:
- case TO_ASSIGN:
- case TO_UNASSIGN:
- tape_34xx_delete_sbid_from(request->device, 0);
- break;
- default:
- ;
- }
- return TAPE_IO_SUCCESS;
-}
-
-static inline int
-tape_34xx_erp_failed(struct tape_request *request, int rc)
-{
- DBF_EVENT(3, "Error recovery failed for %s (RC=%d)\n",
- tape_op_verbose[request->op], rc);
- return rc;
-}
-
-static inline int
-tape_34xx_erp_succeeded(struct tape_request *request)
-{
- DBF_EVENT(3, "Error Recovery successful for %s\n",
- tape_op_verbose[request->op]);
- return tape_34xx_done(request);
-}
-
-static inline int
-tape_34xx_erp_retry(struct tape_request *request)
-{
- DBF_EVENT(3, "xerp retr %s\n", tape_op_verbose[request->op]);
- return TAPE_IO_RETRY;
-}
-
-/*
- * This function is called, when no request is outstanding and we get an
- * interrupt
- */
-static int
-tape_34xx_unsolicited_irq(struct tape_device *device, struct irb *irb)
-{
- if (irb->scsw.cmd.dstat == 0x85) { /* READY */
- /* A medium was inserted in the drive. */
- DBF_EVENT(6, "xuud med\n");
- tape_34xx_delete_sbid_from(device, 0);
- tape_34xx_schedule_work(device, TO_MSEN);
- } else {
- DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id);
- tape_dump_sense_dbf(device, NULL, irb);
- }
- return TAPE_IO_SUCCESS;
-}
-
-static int
-tape_34xx_erp_bug(struct tape_device *device, struct tape_request *request,
- struct irb *irb, int no)
-{
- if (request->op != TO_ASSIGN) {
- dev_err(&device->cdev->dev, "An unexpected condition %d "
- "occurred in tape error recovery\n", no);
- tape_dump_sense_dbf(device, request, irb);
- }
- return tape_34xx_erp_failed(request, -EIO);
-}
-
-/*
- * Handle data overrun between cu and drive. The channel speed might
- * be too slow.
- */
-static int
-tape_34xx_erp_overrun(struct tape_device *device, struct tape_request *request,
- struct irb *irb)
-{
- if (irb->ecw[3] == 0x40) {
- dev_warn (&device->cdev->dev, "A data overrun occurred between"
- " the control unit and tape unit\n");
- return tape_34xx_erp_failed(request, -EIO);
- }
- return tape_34xx_erp_bug(device, request, irb, -1);
-}
-
-/*
- * Handle record sequence error.
- */
-static int
-tape_34xx_erp_sequence(struct tape_device *device,
- struct tape_request *request, struct irb *irb)
-{
- if (irb->ecw[3] == 0x41) {
- /*
- * cu detected incorrect block-id sequence on tape.
- */
- dev_warn (&device->cdev->dev, "The block ID sequence on the "
- "tape is incorrect\n");
- return tape_34xx_erp_failed(request, -EIO);
- }
- /*
- * Record sequence error bit is set, but erpa does not
- * show record sequence error.
- */
- return tape_34xx_erp_bug(device, request, irb, -2);
-}
-
-/*
- * This function analyses the tape's sense-data in case of a unit-check.
- * If possible, it tries to recover from the error. Else the user is
- * informed about the problem.
- */
-static int
-tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
- struct irb *irb)
-{
- int inhibit_cu_recovery;
- __u8* sense;
-
- inhibit_cu_recovery = (*device->modeset_byte & 0x80) ? 1 : 0;
- sense = irb->ecw;
-
- if (
- sense[0] & SENSE_COMMAND_REJECT &&
- sense[1] & SENSE_WRITE_PROTECT
- ) {
- if (
- request->op == TO_DSE ||
- request->op == TO_WRI ||
- request->op == TO_WTM
- ) {
- /* medium is write protected */
- return tape_34xx_erp_failed(request, -EACCES);
- } else {
- return tape_34xx_erp_bug(device, request, irb, -3);
- }
- }
-
- /*
- * Special cases for various tape-states when reaching
- * end of recorded area
- *
- * FIXME: Maybe a special case of the special case:
- * sense[0] == SENSE_EQUIPMENT_CHECK &&
- * sense[1] == SENSE_DRIVE_ONLINE &&
- * sense[3] == 0x47 (Volume Fenced)
- *
- * This was caused by continued FSF or FSR after an
- * 'End Of Data'.
- */
- if ((
- sense[0] == SENSE_DATA_CHECK ||
- sense[0] == SENSE_EQUIPMENT_CHECK ||
- sense[0] == (SENSE_EQUIPMENT_CHECK | SENSE_DEFERRED_UNIT_CHECK)
- ) && (
- sense[1] == SENSE_DRIVE_ONLINE ||
- sense[1] == (SENSE_BEGINNING_OF_TAPE | SENSE_WRITE_MODE)
- )) {
- switch (request->op) {
- /*
- * sense[0] == SENSE_DATA_CHECK &&
- * sense[1] == SENSE_DRIVE_ONLINE
- * sense[3] == 0x36 (End Of Data)
- *
- * Further seeks might return a 'Volume Fenced'.
- */
- case TO_FSF:
- case TO_FSB:
- /* Trying to seek beyond end of recorded area */
- return tape_34xx_erp_failed(request, -ENOSPC);
- case TO_BSB:
- return tape_34xx_erp_retry(request);
-
- /*
- * sense[0] == SENSE_DATA_CHECK &&
- * sense[1] == SENSE_DRIVE_ONLINE &&
- * sense[3] == 0x36 (End Of Data)
- */
- case TO_LBL:
- /* Block could not be located. */
- tape_34xx_delete_sbid_from(device, 0);
- return tape_34xx_erp_failed(request, -EIO);
-
- case TO_RFO:
- /* Read beyond end of recorded area -> 0 bytes read */
- return tape_34xx_erp_failed(request, 0);
-
- /*
- * sense[0] == SENSE_EQUIPMENT_CHECK &&
- * sense[1] == SENSE_DRIVE_ONLINE &&
- * sense[3] == 0x38 (Physical End Of Volume)
- */
- case TO_WRI:
- /* Writing at physical end of volume */
- return tape_34xx_erp_failed(request, -ENOSPC);
- default:
- return tape_34xx_erp_failed(request, 0);
- }
- }
-
- /* Sensing special bits */
- if (sense[0] & SENSE_BUS_OUT_CHECK)
- return tape_34xx_erp_retry(request);
-
- if (sense[0] & SENSE_DATA_CHECK) {
- /*
- * hardware failure, damaged tape or improper
- * operating conditions
- */
- switch (sense[3]) {
- case 0x23:
- /* a read data check occurred */
- if ((sense[2] & SENSE_TAPE_SYNC_MODE) ||
- inhibit_cu_recovery)
- // data check is not permanent, may be
- // recovered. We always use async-mode with
- // cu-recovery, so this should *never* happen.
- return tape_34xx_erp_bug(device, request,
- irb, -4);
-
- /* data check is permanent, CU recovery has failed */
- dev_warn (&device->cdev->dev, "A read error occurred "
- "that cannot be recovered\n");
- return tape_34xx_erp_failed(request, -EIO);
- case 0x25:
- // a write data check occurred
- if ((sense[2] & SENSE_TAPE_SYNC_MODE) ||
- inhibit_cu_recovery)
- // data check is not permanent, may be
- // recovered. We always use async-mode with
- // cu-recovery, so this should *never* happen.
- return tape_34xx_erp_bug(device, request,
- irb, -5);
-
- // data check is permanent, cu-recovery has failed
- dev_warn (&device->cdev->dev, "A write error on the "
- "tape cannot be recovered\n");
- return tape_34xx_erp_failed(request, -EIO);
- case 0x28:
- /* ID-Mark at tape start couldn't be written */
- dev_warn (&device->cdev->dev, "Writing the ID-mark "
- "failed\n");
- return tape_34xx_erp_failed(request, -EIO);
- case 0x31:
- /* Tape void. Tried to read beyond end of device. */
- dev_warn (&device->cdev->dev, "Reading the tape beyond"
- " the end of the recorded area failed\n");
- return tape_34xx_erp_failed(request, -ENOSPC);
- case 0x41:
- /* Record sequence error. */
- dev_warn (&device->cdev->dev, "The tape contains an "
- "incorrect block ID sequence\n");
- return tape_34xx_erp_failed(request, -EIO);
- default:
- /* all data checks for 3480 should result in one of
- * the above erpa-codes. For 3490, other data-check
- * conditions do exist. */
- if (device->cdev->id.driver_info == tape_3480)
- return tape_34xx_erp_bug(device, request,
- irb, -6);
- }
- }
-
- if (sense[0] & SENSE_OVERRUN)
- return tape_34xx_erp_overrun(device, request, irb);
-
- if (sense[1] & SENSE_RECORD_SEQUENCE_ERR)
- return tape_34xx_erp_sequence(device, request, irb);
-
- /* Sensing erpa codes */
- switch (sense[3]) {
- case 0x00:
- /* Unit check with erpa code 0. Report and ignore. */
- return TAPE_IO_SUCCESS;
- case 0x21:
- /*
- * Data streaming not operational. CU will switch to
- * interlock mode. Reissue the command.
- */
- return tape_34xx_erp_retry(request);
- case 0x22:
- /*
- * Path equipment check. Might be drive adapter error, buffer
- * error on the lower interface, internal path not usable,
- * or error during cartridge load.
- */
- dev_warn (&device->cdev->dev, "A path equipment check occurred"
- " for the tape device\n");
- return tape_34xx_erp_failed(request, -EIO);
- case 0x24:
- /*
- * Load display check. Load display was command was issued,
- * but the drive is displaying a drive check message. Can
- * be threated as "device end".
- */
- return tape_34xx_erp_succeeded(request);
- case 0x27:
- /*
- * Command reject. May indicate illegal channel program or
- * buffer over/underrun. Since all channel programs are
- * issued by this driver and ought be correct, we assume a
- * over/underrun situation and retry the channel program.
- */
- return tape_34xx_erp_retry(request);
- case 0x29:
- /*
- * Function incompatible. Either the tape is idrc compressed
- * but the hardware isn't capable to do idrc, or a perform
- * subsystem func is issued and the CU is not on-line.
- */
- return tape_34xx_erp_failed(request, -EIO);
- case 0x2a:
- /*
- * Unsolicited environmental data. An internal counter
- * overflows, we can ignore this and reissue the cmd.
- */
- return tape_34xx_erp_retry(request);
- case 0x2b:
- /*
- * Environmental data present. Indicates either unload
- * completed ok or read buffered log command completed ok.
- */
- if (request->op == TO_RUN) {
- /* Rewind unload completed ok. */
- tape_med_state_set(device, MS_UNLOADED);
- return tape_34xx_erp_succeeded(request);
- }
- /* tape_34xx doesn't use read buffered log commands. */
- return tape_34xx_erp_bug(device, request, irb, sense[3]);
- case 0x2c:
- /*
- * Permanent equipment check. CU has tried recovery, but
- * did not succeed.
- */
- return tape_34xx_erp_failed(request, -EIO);
- case 0x2d:
- /* Data security erase failure. */
- if (request->op == TO_DSE)
- return tape_34xx_erp_failed(request, -EIO);
- /* Data security erase failure, but no such command issued. */
- return tape_34xx_erp_bug(device, request, irb, sense[3]);
- case 0x2e:
- /*
- * Not capable. This indicates either that the drive fails
- * reading the format id mark or that format specified
- * is not supported by the drive.
- */
- dev_warn (&device->cdev->dev, "The tape unit cannot process "
- "the tape format\n");
- return tape_34xx_erp_failed(request, -EMEDIUMTYPE);
- case 0x30:
- /* The medium is write protected. */
- dev_warn (&device->cdev->dev, "The tape medium is write-"
- "protected\n");
- return tape_34xx_erp_failed(request, -EACCES);
- case 0x32:
- // Tension loss. We cannot recover this, it's an I/O error.
- dev_warn (&device->cdev->dev, "The tape does not have the "
- "required tape tension\n");
- return tape_34xx_erp_failed(request, -EIO);
- case 0x33:
- /*
- * Load Failure. The cartridge was not inserted correctly or
- * the tape is not threaded correctly.
- */
- dev_warn (&device->cdev->dev, "The tape unit failed to load"
- " the cartridge\n");
- tape_34xx_delete_sbid_from(device, 0);
- return tape_34xx_erp_failed(request, -EIO);
- case 0x34:
- /*
- * Unload failure. The drive cannot maintain tape tension
- * and control tape movement during an unload operation.
- */
- dev_warn (&device->cdev->dev, "Automatic unloading of the tape"
- " cartridge failed\n");
- if (request->op == TO_RUN)
- return tape_34xx_erp_failed(request, -EIO);
- return tape_34xx_erp_bug(device, request, irb, sense[3]);
- case 0x35:
- /*
- * Drive equipment check. One of the following:
- * - cu cannot recover from a drive detected error
- * - a check code message is shown on drive display
- * - the cartridge loader does not respond correctly
- * - a failure occurs during an index, load, or unload cycle
- */
- dev_warn (&device->cdev->dev, "An equipment check has occurred"
- " on the tape unit\n");
- return tape_34xx_erp_failed(request, -EIO);
- case 0x36:
- if (device->cdev->id.driver_info == tape_3490)
- /* End of data. */
- return tape_34xx_erp_failed(request, -EIO);
- /* This erpa is reserved for 3480 */
- return tape_34xx_erp_bug(device, request, irb, sense[3]);
- case 0x37:
- /*
- * Tape length error. The tape is shorter than reported in
- * the beginning-of-tape data.
- */
- dev_warn (&device->cdev->dev, "The tape information states an"
- " incorrect length\n");
- return tape_34xx_erp_failed(request, -EIO);
- case 0x38:
- /*
- * Physical end of tape. A read/write operation reached
- * the physical end of tape.
- */
- if (request->op==TO_WRI ||
- request->op==TO_DSE ||
- request->op==TO_WTM)
- return tape_34xx_erp_failed(request, -ENOSPC);
- return tape_34xx_erp_failed(request, -EIO);
- case 0x39:
- /* Backward at Beginning of tape. */
- return tape_34xx_erp_failed(request, -EIO);
- case 0x3a:
- /* Drive switched to not ready. */
- dev_warn (&device->cdev->dev, "The tape unit is not ready\n");
- return tape_34xx_erp_failed(request, -EIO);
- case 0x3b:
- /* Manual rewind or unload. This causes an I/O error. */
- dev_warn (&device->cdev->dev, "The tape medium has been "
- "rewound or unloaded manually\n");
- tape_34xx_delete_sbid_from(device, 0);
- return tape_34xx_erp_failed(request, -EIO);
- case 0x42:
- /*
- * Degraded mode. A condition that can cause degraded
- * performance is detected.
- */
- dev_warn (&device->cdev->dev, "The tape subsystem is running "
- "in degraded mode\n");
- return tape_34xx_erp_retry(request);
- case 0x43:
- /* Drive not ready. */
- tape_34xx_delete_sbid_from(device, 0);
- tape_med_state_set(device, MS_UNLOADED);
- /* Some commands commands are successful even in this case */
- if (sense[1] & SENSE_DRIVE_ONLINE) {
- switch(request->op) {
- case TO_ASSIGN:
- case TO_UNASSIGN:
- case TO_DIS:
- case TO_NOP:
- return tape_34xx_done(request);
- break;
- default:
- break;
- }
- }
- return tape_34xx_erp_failed(request, -ENOMEDIUM);
- case 0x44:
- /* Locate Block unsuccessful. */
- if (request->op != TO_BLOCK && request->op != TO_LBL)
- /* No locate block was issued. */
- return tape_34xx_erp_bug(device, request,
- irb, sense[3]);
- return tape_34xx_erp_failed(request, -EIO);
- case 0x45:
- /* The drive is assigned to a different channel path. */
- dev_warn (&device->cdev->dev, "The tape unit is already "
- "assigned\n");
- return tape_34xx_erp_failed(request, -EIO);
- case 0x46:
- /*
- * Drive not on-line. Drive may be switched offline,
- * the power supply may be switched off or
- * the drive address may not be set correctly.
- */
- dev_warn (&device->cdev->dev, "The tape unit is not online\n");
- return tape_34xx_erp_failed(request, -EIO);
- case 0x47:
- /* Volume fenced. CU reports volume integrity is lost. */
- dev_warn (&device->cdev->dev, "The control unit has fenced "
- "access to the tape volume\n");
- tape_34xx_delete_sbid_from(device, 0);
- return tape_34xx_erp_failed(request, -EIO);
- case 0x48:
- /* Log sense data and retry request. */
- return tape_34xx_erp_retry(request);
- case 0x49:
- /* Bus out check. A parity check error on the bus was found. */
- dev_warn (&device->cdev->dev, "A parity error occurred on the "
- "tape bus\n");
- return tape_34xx_erp_failed(request, -EIO);
- case 0x4a:
- /* Control unit erp failed. */
- dev_warn (&device->cdev->dev, "I/O error recovery failed on "
- "the tape control unit\n");
- return tape_34xx_erp_failed(request, -EIO);
- case 0x4b:
- /*
- * CU and drive incompatible. The drive requests micro-program
- * patches, which are not available on the CU.
- */
- dev_warn (&device->cdev->dev, "The tape unit requires a "
- "firmware update\n");
- return tape_34xx_erp_failed(request, -EIO);
- case 0x4c:
- /*
- * Recovered Check-One failure. Cu develops a hardware error,
- * but is able to recover.
- */
- return tape_34xx_erp_retry(request);
- case 0x4d:
- if (device->cdev->id.driver_info == tape_3490)
- /*
- * Resetting event received. Since the driver does
- * not support resetting event recovery (which has to
- * be handled by the I/O Layer), retry our command.
- */
- return tape_34xx_erp_retry(request);
- /* This erpa is reserved for 3480. */
- return tape_34xx_erp_bug(device, request, irb, sense[3]);
- case 0x4e:
- if (device->cdev->id.driver_info == tape_3490) {
- /*
- * Maximum block size exceeded. This indicates, that
- * the block to be written is larger than allowed for
- * buffered mode.
- */
- dev_warn (&device->cdev->dev, "The maximum block size"
- " for buffered mode is exceeded\n");
- return tape_34xx_erp_failed(request, -ENOBUFS);
- }
- /* This erpa is reserved for 3480. */
- return tape_34xx_erp_bug(device, request, irb, sense[3]);
- case 0x50:
- /*
- * Read buffered log (Overflow). CU is running in extended
- * buffered log mode, and a counter overflows. This should
- * never happen, since we're never running in extended
- * buffered log mode.
- */
- return tape_34xx_erp_retry(request);
- case 0x51:
- /*
- * Read buffered log (EOV). EOF processing occurs while the
- * CU is in extended buffered log mode. This should never
- * happen, since we're never running in extended buffered
- * log mode.
- */
- return tape_34xx_erp_retry(request);
- case 0x52:
- /* End of Volume complete. Rewind unload completed ok. */
- if (request->op == TO_RUN) {
- tape_med_state_set(device, MS_UNLOADED);
- tape_34xx_delete_sbid_from(device, 0);
- return tape_34xx_erp_succeeded(request);
- }
- return tape_34xx_erp_bug(device, request, irb, sense[3]);
- case 0x53:
- /* Global command intercept. */
- return tape_34xx_erp_retry(request);
- case 0x54:
- /* Channel interface recovery (temporary). */
- return tape_34xx_erp_retry(request);
- case 0x55:
- /* Channel interface recovery (permanent). */
- dev_warn (&device->cdev->dev, "A channel interface error cannot be"
- " recovered\n");
- return tape_34xx_erp_failed(request, -EIO);
- case 0x56:
- /* Channel protocol error. */
- dev_warn (&device->cdev->dev, "A channel protocol error "
- "occurred\n");
- return tape_34xx_erp_failed(request, -EIO);
- case 0x57:
- /*
- * 3480: Attention intercept.
- * 3490: Global status intercept.
- */
- return tape_34xx_erp_retry(request);
- case 0x5a:
- /*
- * Tape length incompatible. The tape inserted is too long,
- * which could cause damage to the tape or the drive.
- */
- dev_warn (&device->cdev->dev, "The tape unit does not support "
- "the tape length\n");
- return tape_34xx_erp_failed(request, -EIO);
- case 0x5b:
- /* Format 3480 XF incompatible */
- if (sense[1] & SENSE_BEGINNING_OF_TAPE)
- /* The tape will get overwritten. */
- return tape_34xx_erp_retry(request);
- dev_warn (&device->cdev->dev, "The tape unit does not support"
- " format 3480 XF\n");
- return tape_34xx_erp_failed(request, -EIO);
- case 0x5c:
- /* Format 3480-2 XF incompatible */
- dev_warn (&device->cdev->dev, "The tape unit does not support tape "
- "format 3480-2 XF\n");
- return tape_34xx_erp_failed(request, -EIO);
- case 0x5d:
- /* Tape length violation. */
- dev_warn (&device->cdev->dev, "The tape unit does not support"
- " the current tape length\n");
- return tape_34xx_erp_failed(request, -EMEDIUMTYPE);
- case 0x5e:
- /* Compaction algorithm incompatible. */
- dev_warn (&device->cdev->dev, "The tape unit does not support"
- " the compaction algorithm\n");
- return tape_34xx_erp_failed(request, -EMEDIUMTYPE);
-
- /* The following erpas should have been covered earlier. */
- case 0x23: /* Read data check. */
- case 0x25: /* Write data check. */
- case 0x26: /* Data check (read opposite). */
- case 0x28: /* Write id mark check. */
- case 0x31: /* Tape void. */
- case 0x40: /* Overrun error. */
- case 0x41: /* Record sequence error. */
- /* All other erpas are reserved for future use. */
- default:
- return tape_34xx_erp_bug(device, request, irb, sense[3]);
- }
-}
-
-/*
- * 3480/3490 interrupt handler
- */
-static int
-tape_34xx_irq(struct tape_device *device, struct tape_request *request,
- struct irb *irb)
-{
- if (request == NULL)
- return tape_34xx_unsolicited_irq(device, irb);
-
- if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) &&
- (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) &&
- (request->op == TO_WRI)) {
- /* Write at end of volume */
- return tape_34xx_erp_failed(request, -ENOSPC);
- }
-
- if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)
- return tape_34xx_unit_check(device, request, irb);
-
- if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) {
- /*
- * A unit exception occurs on skipping over a tapemark block.
- */
- if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) {
- if (request->op == TO_BSB || request->op == TO_FSB)
- request->rescnt++;
- else
- DBF_EVENT(5, "Unit Exception!\n");
- }
- return tape_34xx_done(request);
- }
-
- DBF_EVENT(6, "xunknownirq\n");
- tape_dump_sense_dbf(device, request, irb);
- return TAPE_IO_STOP;
-}
-
-/*
- * ioctl_overload
- */
-static int
-tape_34xx_ioctl(struct tape_device *device, unsigned int cmd, unsigned long arg)
-{
- if (cmd == TAPE390_DISPLAY) {
- struct display_struct disp;
-
- if (copy_from_user(&disp, (char __user *) arg, sizeof(disp)) != 0)
- return -EFAULT;
-
- return tape_std_display(device, &disp);
- } else
- return -EINVAL;
-}
-
-static inline void
-tape_34xx_append_new_sbid(struct tape_34xx_block_id bid, struct list_head *l)
-{
- struct tape_34xx_sbid * new_sbid;
-
- new_sbid = kmalloc(sizeof(*new_sbid), GFP_ATOMIC);
- if (!new_sbid)
- return;
-
- new_sbid->bid = bid;
- list_add(&new_sbid->list, l);
-}
-
-/*
- * Build up the search block ID list. The block ID consists of a logical
- * block number and a hardware specific part. The hardware specific part
- * helps the tape drive to speed up searching for a specific block.
- */
-static void
-tape_34xx_add_sbid(struct tape_device *device, struct tape_34xx_block_id bid)
-{
- struct list_head * sbid_list;
- struct tape_34xx_sbid * sbid;
- struct list_head * l;
-
- /*
- * immediately return if there is no list at all or the block to add
- * is located in segment 1 of wrap 0 because this position is used
- * if no hardware position data is supplied.
- */
- sbid_list = (struct list_head *) device->discdata;
- if (!sbid_list || (bid.segment < 2 && bid.wrap == 0))
- return;
-
- /*
- * Search the position where to insert the new entry. Hardware
- * acceleration uses only the segment and wrap number. So we
- * need only one entry for a specific wrap/segment combination.
- * If there is a block with a lower number but the same hard-
- * ware position data we just update the block number in the
- * existing entry.
- */
- list_for_each(l, sbid_list) {
- sbid = list_entry(l, struct tape_34xx_sbid, list);
-
- if (
- (sbid->bid.segment == bid.segment) &&
- (sbid->bid.wrap == bid.wrap)
- ) {
- if (bid.block < sbid->bid.block)
- sbid->bid = bid;
- else return;
- break;
- }
-
- /* Sort in according to logical block number. */
- if (bid.block < sbid->bid.block) {
- tape_34xx_append_new_sbid(bid, l->prev);
- break;
- }
- }
- /* List empty or new block bigger than last entry. */
- if (l == sbid_list)
- tape_34xx_append_new_sbid(bid, l->prev);
-
- DBF_LH(4, "Current list is:\n");
- list_for_each(l, sbid_list) {
- sbid = list_entry(l, struct tape_34xx_sbid, list);
- DBF_LH(4, "%d:%03d@%05d\n",
- sbid->bid.wrap,
- sbid->bid.segment,
- sbid->bid.block
- );
- }
-}
-
-/*
- * Delete all entries from the search block ID list that belong to tape blocks
- * equal or higher than the given number.
- */
-static void
-tape_34xx_delete_sbid_from(struct tape_device *device, int from)
-{
- struct list_head * sbid_list;
- struct tape_34xx_sbid * sbid;
- struct list_head * l;
- struct list_head * n;
-
- sbid_list = (struct list_head *) device->discdata;
- if (!sbid_list)
- return;
-
- list_for_each_safe(l, n, sbid_list) {
- sbid = list_entry(l, struct tape_34xx_sbid, list);
- if (sbid->bid.block >= from) {
- DBF_LH(4, "Delete sbid %d:%03d@%05d\n",
- sbid->bid.wrap,
- sbid->bid.segment,
- sbid->bid.block
- );
- list_del(l);
- kfree(sbid);
- }
- }
-}
-
-/*
- * Merge hardware position data into a block id.
- */
-static void
-tape_34xx_merge_sbid(
- struct tape_device * device,
- struct tape_34xx_block_id * bid
-) {
- struct tape_34xx_sbid * sbid;
- struct tape_34xx_sbid * sbid_to_use;
- struct list_head * sbid_list;
- struct list_head * l;
-
- sbid_list = (struct list_head *) device->discdata;
- bid->wrap = 0;
- bid->segment = 1;
-
- if (!sbid_list || list_empty(sbid_list))
- return;
-
- sbid_to_use = NULL;
- list_for_each(l, sbid_list) {
- sbid = list_entry(l, struct tape_34xx_sbid, list);
-
- if (sbid->bid.block >= bid->block)
- break;
- sbid_to_use = sbid;
- }
- if (sbid_to_use) {
- bid->wrap = sbid_to_use->bid.wrap;
- bid->segment = sbid_to_use->bid.segment;
- DBF_LH(4, "Use %d:%03d@%05d for %05d\n",
- sbid_to_use->bid.wrap,
- sbid_to_use->bid.segment,
- sbid_to_use->bid.block,
- bid->block
- );
- }
-}
-
-static int
-tape_34xx_setup_device(struct tape_device * device)
-{
- int rc;
- struct list_head * discdata;
-
- DBF_EVENT(6, "34xx device setup\n");
- if ((rc = tape_std_assign(device)) == 0) {
- if ((rc = tape_34xx_medium_sense(device)) != 0) {
- DBF_LH(3, "34xx medium sense returned %d\n", rc);
- }
- }
- discdata = kmalloc(sizeof(struct list_head), GFP_KERNEL);
- if (discdata) {
- INIT_LIST_HEAD(discdata);
- device->discdata = discdata;
- }
-
- return rc;
-}
-
-static void
-tape_34xx_cleanup_device(struct tape_device *device)
-{
- tape_std_unassign(device);
-
- if (device->discdata) {
- tape_34xx_delete_sbid_from(device, 0);
- kfree(device->discdata);
- device->discdata = NULL;
- }
-}
-
-
-/*
- * MTTELL: Tell block. Return the number of block relative to current file.
- */
-static int
-tape_34xx_mttell(struct tape_device *device, int mt_count)
-{
- struct {
- struct tape_34xx_block_id cbid;
- struct tape_34xx_block_id dbid;
- } __attribute__ ((packed)) block_id;
- int rc;
-
- rc = tape_std_read_block_id(device, (__u64 *) &block_id);
- if (rc)
- return rc;
-
- tape_34xx_add_sbid(device, block_id.cbid);
- return block_id.cbid.block;
-}
-
-/*
- * MTSEEK: seek to the specified block.
- */
-static int
-tape_34xx_mtseek(struct tape_device *device, int mt_count)
-{
- struct tape_request *request;
- struct tape_34xx_block_id * bid;
-
- if (mt_count > 0x3fffff) {
- DBF_EXCEPTION(6, "xsee parm\n");
- return -EINVAL;
- }
- request = tape_alloc_request(3, 4);
- if (IS_ERR(request))
- return PTR_ERR(request);
-
- /* setup ccws */
- request->op = TO_LBL;
- bid = (struct tape_34xx_block_id *) request->cpdata;
- bid->format = (*device->modeset_byte & 0x08) ?
- TAPE34XX_FMT_3480_XF : TAPE34XX_FMT_3480;
- bid->block = mt_count;
- tape_34xx_merge_sbid(device, bid);
-
- tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
- tape_ccw_cc(request->cpaddr + 1, LOCATE, 4, request->cpdata);
- tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);
-
- /* execute it */
- return tape_do_io_free(device, request);
-}
-
-/*
- * List of 3480/3490 magnetic tape commands.
- */
-static tape_mtop_fn tape_34xx_mtop[TAPE_NR_MTOPS] = {
- [MTRESET] = tape_std_mtreset,
- [MTFSF] = tape_std_mtfsf,
- [MTBSF] = tape_std_mtbsf,
- [MTFSR] = tape_std_mtfsr,
- [MTBSR] = tape_std_mtbsr,
- [MTWEOF] = tape_std_mtweof,
- [MTREW] = tape_std_mtrew,
- [MTOFFL] = tape_std_mtoffl,
- [MTNOP] = tape_std_mtnop,
- [MTRETEN] = tape_std_mtreten,
- [MTBSFM] = tape_std_mtbsfm,
- [MTFSFM] = tape_std_mtfsfm,
- [MTEOM] = tape_std_mteom,
- [MTERASE] = tape_std_mterase,
- [MTRAS1] = NULL,
- [MTRAS2] = NULL,
- [MTRAS3] = NULL,
- [MTSETBLK] = tape_std_mtsetblk,
- [MTSETDENSITY] = NULL,
- [MTSEEK] = tape_34xx_mtseek,
- [MTTELL] = tape_34xx_mttell,
- [MTSETDRVBUFFER] = NULL,
- [MTFSS] = NULL,
- [MTBSS] = NULL,
- [MTWSM] = NULL,
- [MTLOCK] = NULL,
- [MTUNLOCK] = NULL,
- [MTLOAD] = tape_std_mtload,
- [MTUNLOAD] = tape_std_mtunload,
- [MTCOMPRESSION] = tape_std_mtcompression,
- [MTSETPART] = NULL,
- [MTMKPART] = NULL
-};
-
-/*
- * Tape discipline structure for 3480 and 3490.
- */
-static struct tape_discipline tape_discipline_34xx = {
- .owner = THIS_MODULE,
- .setup_device = tape_34xx_setup_device,
- .cleanup_device = tape_34xx_cleanup_device,
- .process_eov = tape_std_process_eov,
- .irq = tape_34xx_irq,
- .read_block = tape_std_read_block,
- .write_block = tape_std_write_block,
- .ioctl_fn = tape_34xx_ioctl,
- .mtop_array = tape_34xx_mtop
-};
-
-static struct ccw_device_id tape_34xx_ids[] = {
- { CCW_DEVICE_DEVTYPE(0x3480, 0, 0x3480, 0), .driver_info = tape_3480},
- { CCW_DEVICE_DEVTYPE(0x3490, 0, 0x3490, 0), .driver_info = tape_3490},
- { /* end of list */ },
-};
-
-static int
-tape_34xx_online(struct ccw_device *cdev)
-{
- return tape_generic_online(
- dev_get_drvdata(&cdev->dev),
- &tape_discipline_34xx
- );
-}
-
-static struct ccw_driver tape_34xx_driver = {
- .driver = {
- .name = "tape_34xx",
- .owner = THIS_MODULE,
- },
- .ids = tape_34xx_ids,
- .probe = tape_generic_probe,
- .remove = tape_generic_remove,
- .set_online = tape_34xx_online,
- .set_offline = tape_generic_offline,
- .int_class = IRQIO_TAP,
-};
-
-static int
-tape_34xx_init (void)
-{
- int rc;
-
- TAPE_DBF_AREA = debug_register ( "tape_34xx", 2, 2, 4*sizeof(long));
- debug_register_view(TAPE_DBF_AREA, &debug_sprintf_view);
-#ifdef DBF_LIKE_HELL
- debug_set_level(TAPE_DBF_AREA, 6);
-#endif
-
- DBF_EVENT(3, "34xx init\n");
- /* Register driver for 3480/3490 tapes. */
- rc = ccw_driver_register(&tape_34xx_driver);
- if (rc)
- DBF_EVENT(3, "34xx init failed\n");
- else
- DBF_EVENT(3, "34xx registered\n");
- return rc;
-}
-
-static void
-tape_34xx_exit(void)
-{
- ccw_driver_unregister(&tape_34xx_driver);
-
- debug_unregister(TAPE_DBF_AREA);
-}
-
-MODULE_DEVICE_TABLE(ccw, tape_34xx_ids);
-MODULE_AUTHOR("(C) 2001-2002 IBM Deutschland Entwicklung GmbH");
-MODULE_DESCRIPTION("Linux on zSeries channel attached 3480 tape device driver");
-MODULE_LICENSE("GPL");
-
-module_init(tape_34xx_init);
-module_exit(tape_34xx_exit);
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
deleted file mode 100644
index 0d80f43b175d..000000000000
--- a/drivers/s390/char/tape_3590.c
+++ /dev/null
@@ -1,1612 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * tape device discipline for 3590 tapes.
- *
- * Copyright IBM Corp. 2001, 2009
- * Author(s): Stefan Bader <shbader@de.ibm.com>
- * Michael Holzheu <holzheu@de.ibm.com>
- * Martin Schwidefsky <schwidefsky@de.ibm.com>
- */
-
-#define pr_fmt(fmt) "tape_3590: " fmt
-
-#include <linux/export.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/bio.h>
-#include <asm/ebcdic.h>
-
-#define TAPE_DBF_AREA tape_3590_dbf
-#define BUFSIZE 512 /* size of buffers for dynamic generated messages */
-
-#include "tape.h"
-#include "tape_std.h"
-#include "tape_3590.h"
-
-static struct workqueue_struct *tape_3590_wq;
-
-/*
- * Pointer to debug area.
- */
-debug_info_t *TAPE_DBF_AREA = NULL;
-EXPORT_SYMBOL(TAPE_DBF_AREA);
-
-/*******************************************************************
- * Error Recovery functions:
- * - Read Opposite: implemented
- * - Read Device (buffered) log: BRA
- * - Read Library log: BRA
- * - Swap Devices: BRA
- * - Long Busy: implemented
- * - Special Intercept: BRA
- * - Read Alternate: implemented
- *******************************************************************/
-
-static const char *tape_3590_msg[TAPE_3590_MAX_MSG] = {
- [0x00] = "",
- [0x10] = "Lost Sense",
- [0x11] = "Assigned Elsewhere",
- [0x12] = "Allegiance Reset",
- [0x13] = "Shared Access Violation",
- [0x20] = "Command Reject",
- [0x21] = "Configuration Error",
- [0x22] = "Protection Exception",
- [0x23] = "Write Protect",
- [0x24] = "Write Length",
- [0x25] = "Read-Only Format",
- [0x31] = "Beginning of Partition",
- [0x33] = "End of Partition",
- [0x34] = "End of Data",
- [0x35] = "Block not found",
- [0x40] = "Device Intervention",
- [0x41] = "Loader Intervention",
- [0x42] = "Library Intervention",
- [0x50] = "Write Error",
- [0x51] = "Erase Error",
- [0x52] = "Formatting Error",
- [0x53] = "Read Error",
- [0x54] = "Unsupported Format",
- [0x55] = "No Formatting",
- [0x56] = "Positioning lost",
- [0x57] = "Read Length",
- [0x60] = "Unsupported Medium",
- [0x61] = "Medium Length Error",
- [0x62] = "Medium removed",
- [0x64] = "Load Check",
- [0x65] = "Unload Check",
- [0x70] = "Equipment Check",
- [0x71] = "Bus out Check",
- [0x72] = "Protocol Error",
- [0x73] = "Interface Error",
- [0x74] = "Overrun",
- [0x75] = "Halt Signal",
- [0x90] = "Device fenced",
- [0x91] = "Device Path fenced",
- [0xa0] = "Volume misplaced",
- [0xa1] = "Volume inaccessible",
- [0xa2] = "Volume in input",
- [0xa3] = "Volume ejected",
- [0xa4] = "All categories reserved",
- [0xa5] = "Duplicate Volume",
- [0xa6] = "Library Manager Offline",
- [0xa7] = "Library Output Station full",
- [0xa8] = "Vision System non-operational",
- [0xa9] = "Library Manager Equipment Check",
- [0xaa] = "Library Equipment Check",
- [0xab] = "All Library Cells full",
- [0xac] = "No Cleaner Volumes in Library",
- [0xad] = "I/O Station door open",
- [0xae] = "Subsystem environmental alert",
-};
-
-static int crypt_supported(struct tape_device *device)
-{
- return TAPE390_CRYPT_SUPPORTED(TAPE_3590_CRYPT_INFO(device));
-}
-
-static int crypt_enabled(struct tape_device *device)
-{
- return TAPE390_CRYPT_ON(TAPE_3590_CRYPT_INFO(device));
-}
-
-static void ext_to_int_kekl(struct tape390_kekl *in,
- struct tape3592_kekl *out)
-{
- int len;
-
- memset(out, 0, sizeof(*out));
- if (in->type == TAPE390_KEKL_TYPE_HASH)
- out->flags |= 0x40;
- if (in->type_on_tape == TAPE390_KEKL_TYPE_HASH)
- out->flags |= 0x80;
- len = min(sizeof(out->label), strlen(in->label));
- memcpy(out->label, in->label, len);
- memset(out->label + len, ' ', sizeof(out->label) - len);
- ASCEBC(out->label, sizeof(out->label));
-}
-
-static void int_to_ext_kekl(struct tape3592_kekl *in,
- struct tape390_kekl *out)
-{
- memset(out, 0, sizeof(*out));
- if(in->flags & 0x40)
- out->type = TAPE390_KEKL_TYPE_HASH;
- else
- out->type = TAPE390_KEKL_TYPE_LABEL;
- if(in->flags & 0x80)
- out->type_on_tape = TAPE390_KEKL_TYPE_HASH;
- else
- out->type_on_tape = TAPE390_KEKL_TYPE_LABEL;
- memcpy(out->label, in->label, sizeof(in->label));
- EBCASC(out->label, sizeof(in->label));
- strim(out->label);
-}
-
-static void int_to_ext_kekl_pair(struct tape3592_kekl_pair *in,
- struct tape390_kekl_pair *out)
-{
- if (in->count == 0) {
- out->kekl[0].type = TAPE390_KEKL_TYPE_NONE;
- out->kekl[0].type_on_tape = TAPE390_KEKL_TYPE_NONE;
- out->kekl[1].type = TAPE390_KEKL_TYPE_NONE;
- out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE;
- } else if (in->count == 1) {
- int_to_ext_kekl(&in->kekl[0], &out->kekl[0]);
- out->kekl[1].type = TAPE390_KEKL_TYPE_NONE;
- out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE;
- } else if (in->count == 2) {
- int_to_ext_kekl(&in->kekl[0], &out->kekl[0]);
- int_to_ext_kekl(&in->kekl[1], &out->kekl[1]);
- } else {
- printk("Invalid KEKL number: %d\n", in->count);
- BUG();
- }
-}
-
-static int check_ext_kekl(struct tape390_kekl *kekl)
-{
- if (kekl->type == TAPE390_KEKL_TYPE_NONE)
- goto invalid;
- if (kekl->type > TAPE390_KEKL_TYPE_HASH)
- goto invalid;
- if (kekl->type_on_tape == TAPE390_KEKL_TYPE_NONE)
- goto invalid;
- if (kekl->type_on_tape > TAPE390_KEKL_TYPE_HASH)
- goto invalid;
- if ((kekl->type == TAPE390_KEKL_TYPE_HASH) &&
- (kekl->type_on_tape == TAPE390_KEKL_TYPE_LABEL))
- goto invalid;
-
- return 0;
-invalid:
- return -EINVAL;
-}
-
-static int check_ext_kekl_pair(struct tape390_kekl_pair *kekls)
-{
- if (check_ext_kekl(&kekls->kekl[0]))
- goto invalid;
- if (check_ext_kekl(&kekls->kekl[1]))
- goto invalid;
-
- return 0;
-invalid:
- return -EINVAL;
-}
-
-/*
- * Query KEKLs
- */
-static int tape_3592_kekl_query(struct tape_device *device,
- struct tape390_kekl_pair *ext_kekls)
-{
- struct tape_request *request;
- struct tape3592_kekl_query_order *order;
- struct tape3592_kekl_query_data *int_kekls;
- int rc;
-
- DBF_EVENT(6, "tape3592_kekl_query\n");
- int_kekls = kmalloc(sizeof(*int_kekls), GFP_KERNEL|GFP_DMA);
- if (!int_kekls)
- return -ENOMEM;
- request = tape_alloc_request(2, sizeof(*order));
- if (IS_ERR(request)) {
- rc = PTR_ERR(request);
- goto fail_malloc;
- }
- order = request->cpdata;
- memset(order,0,sizeof(*order));
- order->code = 0xe2;
- order->max_count = 2;
- request->op = TO_KEKL_QUERY;
- tape_ccw_cc(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order);
- tape_ccw_end(request->cpaddr + 1, READ_SS_DATA, sizeof(*int_kekls),
- int_kekls);
- rc = tape_do_io(device, request);
- if (rc)
- goto fail_request;
- int_to_ext_kekl_pair(&int_kekls->kekls, ext_kekls);
-
- rc = 0;
-fail_request:
- tape_free_request(request);
-fail_malloc:
- kfree(int_kekls);
- return rc;
-}
-
-/*
- * IOCTL: Query KEKLs
- */
-static int tape_3592_ioctl_kekl_query(struct tape_device *device,
- unsigned long arg)
-{
- int rc;
- struct tape390_kekl_pair *ext_kekls;
-
- DBF_EVENT(6, "tape_3592_ioctl_kekl_query\n");
- if (!crypt_supported(device))
- return -ENOSYS;
- if (!crypt_enabled(device))
- return -EUNATCH;
- ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL);
- if (!ext_kekls)
- return -ENOMEM;
- rc = tape_3592_kekl_query(device, ext_kekls);
- if (rc != 0)
- goto fail;
- if (copy_to_user((char __user *) arg, ext_kekls, sizeof(*ext_kekls))) {
- rc = -EFAULT;
- goto fail;
- }
- rc = 0;
-fail:
- kfree(ext_kekls);
- return rc;
-}
-
-static int tape_3590_mttell(struct tape_device *device, int mt_count);
-
-/*
- * Set KEKLs
- */
-static int tape_3592_kekl_set(struct tape_device *device,
- struct tape390_kekl_pair *ext_kekls)
-{
- struct tape_request *request;
- struct tape3592_kekl_set_order *order;
-
- DBF_EVENT(6, "tape3592_kekl_set\n");
- if (check_ext_kekl_pair(ext_kekls)) {
- DBF_EVENT(6, "invalid kekls\n");
- return -EINVAL;
- }
- if (tape_3590_mttell(device, 0) != 0)
- return -EBADSLT;
- request = tape_alloc_request(1, sizeof(*order));
- if (IS_ERR(request))
- return PTR_ERR(request);
- order = request->cpdata;
- memset(order, 0, sizeof(*order));
- order->code = 0xe3;
- order->kekls.count = 2;
- ext_to_int_kekl(&ext_kekls->kekl[0], &order->kekls.kekl[0]);
- ext_to_int_kekl(&ext_kekls->kekl[1], &order->kekls.kekl[1]);
- request->op = TO_KEKL_SET;
- tape_ccw_end(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order);
-
- return tape_do_io_free(device, request);
-}
-
-/*
- * IOCTL: Set KEKLs
- */
-static int tape_3592_ioctl_kekl_set(struct tape_device *device,
- unsigned long arg)
-{
- int rc;
- struct tape390_kekl_pair *ext_kekls;
-
- DBF_EVENT(6, "tape_3592_ioctl_kekl_set\n");
- if (!crypt_supported(device))
- return -ENOSYS;
- if (!crypt_enabled(device))
- return -EUNATCH;
- ext_kekls = memdup_user((char __user *)arg, sizeof(*ext_kekls));
- if (IS_ERR(ext_kekls))
- return PTR_ERR(ext_kekls);
- rc = tape_3592_kekl_set(device, ext_kekls);
- kfree(ext_kekls);
- return rc;
-}
-
-/*
- * Enable encryption
- */
-static struct tape_request *__tape_3592_enable_crypt(struct tape_device *device)
-{
- struct tape_request *request;
- char *data;
-
- DBF_EVENT(6, "tape_3592_enable_crypt\n");
- if (!crypt_supported(device))
- return ERR_PTR(-ENOSYS);
- request = tape_alloc_request(2, 72);
- if (IS_ERR(request))
- return request;
- data = request->cpdata;
- memset(data,0,72);
-
- data[0] = 0x05;
- data[36 + 0] = 0x03;
- data[36 + 1] = 0x03;
- data[36 + 4] = 0x40;
- data[36 + 6] = 0x01;
- data[36 + 14] = 0x2f;
- data[36 + 18] = 0xc3;
- data[36 + 35] = 0x72;
- request->op = TO_CRYPT_ON;
- tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data);
- tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36);
- return request;
-}
-
-static int tape_3592_enable_crypt(struct tape_device *device)
-{
- struct tape_request *request;
-
- request = __tape_3592_enable_crypt(device);
- if (IS_ERR(request))
- return PTR_ERR(request);
- return tape_do_io_free(device, request);
-}
-
-static void tape_3592_enable_crypt_async(struct tape_device *device)
-{
- struct tape_request *request;
-
- request = __tape_3592_enable_crypt(device);
- if (!IS_ERR(request))
- tape_do_io_async_free(device, request);
-}
-
-/*
- * Disable encryption
- */
-static struct tape_request *__tape_3592_disable_crypt(struct tape_device *device)
-{
- struct tape_request *request;
- char *data;
-
- DBF_EVENT(6, "tape_3592_disable_crypt\n");
- if (!crypt_supported(device))
- return ERR_PTR(-ENOSYS);
- request = tape_alloc_request(2, 72);
- if (IS_ERR(request))
- return request;
- data = request->cpdata;
- memset(data,0,72);
-
- data[0] = 0x05;
- data[36 + 0] = 0x03;
- data[36 + 1] = 0x03;
- data[36 + 35] = 0x32;
-
- request->op = TO_CRYPT_OFF;
- tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data);
- tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36);
-
- return request;
-}
-
-static int tape_3592_disable_crypt(struct tape_device *device)
-{
- struct tape_request *request;
-
- request = __tape_3592_disable_crypt(device);
- if (IS_ERR(request))
- return PTR_ERR(request);
- return tape_do_io_free(device, request);
-}
-
-static void tape_3592_disable_crypt_async(struct tape_device *device)
-{
- struct tape_request *request;
-
- request = __tape_3592_disable_crypt(device);
- if (!IS_ERR(request))
- tape_do_io_async_free(device, request);
-}
-
-/*
- * IOCTL: Set encryption status
- */
-static int tape_3592_ioctl_crypt_set(struct tape_device *device,
- unsigned long arg)
-{
- struct tape390_crypt_info info;
-
- DBF_EVENT(6, "tape_3592_ioctl_crypt_set\n");
- if (!crypt_supported(device))
- return -ENOSYS;
- if (copy_from_user(&info, (char __user *)arg, sizeof(info)))
- return -EFAULT;
- if (info.status & ~TAPE390_CRYPT_ON_MASK)
- return -EINVAL;
- if (info.status & TAPE390_CRYPT_ON_MASK)
- return tape_3592_enable_crypt(device);
- else
- return tape_3592_disable_crypt(device);
-}
-
-static int tape_3590_sense_medium(struct tape_device *device);
-
-/*
- * IOCTL: Query enryption status
- */
-static int tape_3592_ioctl_crypt_query(struct tape_device *device,
- unsigned long arg)
-{
- DBF_EVENT(6, "tape_3592_ioctl_crypt_query\n");
- if (!crypt_supported(device))
- return -ENOSYS;
- tape_3590_sense_medium(device);
- if (copy_to_user((char __user *) arg, &TAPE_3590_CRYPT_INFO(device),
- sizeof(TAPE_3590_CRYPT_INFO(device))))
- return -EFAULT;
- else
- return 0;
-}
-
-/*
- * 3590 IOCTL Overload
- */
-static int
-tape_3590_ioctl(struct tape_device *device, unsigned int cmd, unsigned long arg)
-{
- switch (cmd) {
- case TAPE390_DISPLAY: {
- struct display_struct disp;
-
- if (copy_from_user(&disp, (char __user *) arg, sizeof(disp)))
- return -EFAULT;
-
- return tape_std_display(device, &disp);
- }
- case TAPE390_KEKL_SET:
- return tape_3592_ioctl_kekl_set(device, arg);
- case TAPE390_KEKL_QUERY:
- return tape_3592_ioctl_kekl_query(device, arg);
- case TAPE390_CRYPT_SET:
- return tape_3592_ioctl_crypt_set(device, arg);
- case TAPE390_CRYPT_QUERY:
- return tape_3592_ioctl_crypt_query(device, arg);
- default:
- return -EINVAL; /* no additional ioctls */
- }
-}
-
-/*
- * SENSE Medium: Get Sense data about medium state
- */
-static int tape_3590_sense_medium(struct tape_device *device)
-{
- struct tape_request *request;
-
- request = tape_alloc_request(1, 128);
- if (IS_ERR(request))
- return PTR_ERR(request);
- request->op = TO_MSEN;
- tape_ccw_end(request->cpaddr, MEDIUM_SENSE, 128, request->cpdata);
- return tape_do_io_free(device, request);
-}
-
-static void tape_3590_sense_medium_async(struct tape_device *device)
-{
- struct tape_request *request;
-
- request = tape_alloc_request(1, 128);
- if (IS_ERR(request))
- return;
- request->op = TO_MSEN;
- tape_ccw_end(request->cpaddr, MEDIUM_SENSE, 128, request->cpdata);
- tape_do_io_async_free(device, request);
-}
-
-/*
- * MTTELL: Tell block. Return the number of block relative to current file.
- */
-static int
-tape_3590_mttell(struct tape_device *device, int mt_count)
-{
- __u64 block_id;
- int rc;
-
- rc = tape_std_read_block_id(device, &block_id);
- if (rc)
- return rc;
- return block_id >> 32;
-}
-
-/*
- * MTSEEK: seek to the specified block.
- */
-static int
-tape_3590_mtseek(struct tape_device *device, int count)
-{
- struct tape_request *request;
-
- DBF_EVENT(6, "xsee id: %x\n", count);
- request = tape_alloc_request(3, 4);
- if (IS_ERR(request))
- return PTR_ERR(request);
- request->op = TO_LBL;
- tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
- *(__u32 *) request->cpdata = count;
- tape_ccw_cc(request->cpaddr + 1, LOCATE, 4, request->cpdata);
- tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);
- return tape_do_io_free(device, request);
-}
-
-/*
- * Read Attention Msg
- * This should be done after an interrupt with attention bit (0x80)
- * in device state.
- *
- * After a "read attention message" request there are two possible
- * results:
- *
- * 1. A unit check is presented, when attention sense is present (e.g. when
- * a medium has been unloaded). The attention sense comes then
- * together with the unit check. The recovery action is either "retry"
- * (in case there is an attention message pending) or "permanent error".
- *
- * 2. The attention msg is written to the "read subsystem data" buffer.
- * In this case we probably should print it to the console.
- */
-static void tape_3590_read_attmsg_async(struct tape_device *device)
-{
- struct tape_request *request;
- char *buf;
-
- request = tape_alloc_request(3, 4096);
- if (IS_ERR(request))
- return;
- request->op = TO_READ_ATTMSG;
- buf = request->cpdata;
- buf[0] = PREP_RD_SS_DATA;
- buf[6] = RD_ATTMSG; /* read att msg */
- tape_ccw_cc(request->cpaddr, PERFORM_SS_FUNC, 12, buf);
- tape_ccw_cc(request->cpaddr + 1, READ_SS_DATA, 4096 - 12, buf + 12);
- tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);
- tape_do_io_async_free(device, request);
-}
-
-/*
- * These functions are used to schedule follow-up actions from within an
- * interrupt context (like unsolicited interrupts).
- * Note: the work handler is called by the system work queue. The tape
- * commands started by the handler need to be asynchrounous, otherwise
- * a deadlock can occur e.g. in case of a deferred cc=1 (see __tape_do_irq).
- */
-struct work_handler_data {
- struct tape_device *device;
- enum tape_op op;
- struct work_struct work;
-};
-
-static void
-tape_3590_work_handler(struct work_struct *work)
-{
- struct work_handler_data *p =
- container_of(work, struct work_handler_data, work);
-
- switch (p->op) {
- case TO_MSEN:
- tape_3590_sense_medium_async(p->device);
- break;
- case TO_READ_ATTMSG:
- tape_3590_read_attmsg_async(p->device);
- break;
- case TO_CRYPT_ON:
- tape_3592_enable_crypt_async(p->device);
- break;
- case TO_CRYPT_OFF:
- tape_3592_disable_crypt_async(p->device);
- break;
- default:
- DBF_EVENT(3, "T3590: work handler undefined for "
- "operation 0x%02x\n", p->op);
- }
- tape_put_device(p->device);
- kfree(p);
-}
-
-static int
-tape_3590_schedule_work(struct tape_device *device, enum tape_op op)
-{
- struct work_handler_data *p;
-
- if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL)
- return -ENOMEM;
-
- INIT_WORK(&p->work, tape_3590_work_handler);
-
- p->device = tape_get_device(device);
- p->op = op;
-
- queue_work(tape_3590_wq, &p->work);
- return 0;
-}
-
-static void tape_3590_med_state_set(struct tape_device *device,
- struct tape_3590_med_sense *sense)
-{
- struct tape390_crypt_info *c_info;
-
- c_info = &TAPE_3590_CRYPT_INFO(device);
-
- DBF_EVENT(6, "medium state: %x:%x\n", sense->macst, sense->masst);
- switch (sense->macst) {
- case 0x04:
- case 0x05:
- case 0x06:
- tape_med_state_set(device, MS_UNLOADED);
- TAPE_3590_CRYPT_INFO(device).medium_status = 0;
- return;
- case 0x08:
- case 0x09:
- tape_med_state_set(device, MS_LOADED);
- break;
- default:
- tape_med_state_set(device, MS_UNKNOWN);
- return;
- }
- c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK;
- if (sense->flags & MSENSE_CRYPT_MASK) {
- DBF_EVENT(6, "Medium is encrypted (%04x)\n", sense->flags);
- c_info->medium_status |= TAPE390_MEDIUM_ENCRYPTED_MASK;
- } else {
- DBF_EVENT(6, "Medium is not encrypted %04x\n", sense->flags);
- c_info->medium_status &= ~TAPE390_MEDIUM_ENCRYPTED_MASK;
- }
-}
-
-/*
- * The done handler is called at device/channel end and wakes up the sleeping
- * process
- */
-static int
-tape_3590_done(struct tape_device *device, struct tape_request *request)
-{
-
- DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]);
-
- switch (request->op) {
- case TO_BSB:
- case TO_BSF:
- case TO_DSE:
- case TO_FSB:
- case TO_FSF:
- case TO_LBL:
- case TO_RFO:
- case TO_RBA:
- case TO_REW:
- case TO_WRI:
- case TO_WTM:
- case TO_BLOCK:
- case TO_LOAD:
- tape_med_state_set(device, MS_LOADED);
- break;
- case TO_RUN:
- tape_med_state_set(device, MS_UNLOADED);
- tape_3590_schedule_work(device, TO_CRYPT_OFF);
- break;
- case TO_MSEN:
- tape_3590_med_state_set(device, request->cpdata);
- break;
- case TO_CRYPT_ON:
- TAPE_3590_CRYPT_INFO(device).status
- |= TAPE390_CRYPT_ON_MASK;
- *(device->modeset_byte) |= 0x03;
- break;
- case TO_CRYPT_OFF:
- TAPE_3590_CRYPT_INFO(device).status
- &= ~TAPE390_CRYPT_ON_MASK;
- *(device->modeset_byte) &= ~0x03;
- break;
- case TO_RBI: /* RBI seems to succeed even without medium loaded. */
- case TO_NOP: /* Same to NOP. */
- case TO_READ_CONFIG:
- case TO_READ_ATTMSG:
- case TO_DIS:
- case TO_ASSIGN:
- case TO_UNASSIGN:
- case TO_SIZE:
- case TO_KEKL_SET:
- case TO_KEKL_QUERY:
- case TO_RDC:
- break;
- }
- return TAPE_IO_SUCCESS;
-}
-
-/*
- * This function is called, when error recovery was successful
- */
-static inline int
-tape_3590_erp_succeeded(struct tape_device *device, struct tape_request *request)
-{
- DBF_EVENT(3, "Error Recovery successful for %s\n",
- tape_op_verbose[request->op]);
- return tape_3590_done(device, request);
-}
-
-/*
- * This function is called, when error recovery was not successful
- */
-static inline int
-tape_3590_erp_failed(struct tape_device *device, struct tape_request *request,
- struct irb *irb, int rc)
-{
- DBF_EVENT(3, "Error Recovery failed for %s\n",
- tape_op_verbose[request->op]);
- tape_dump_sense_dbf(device, request, irb);
- return rc;
-}
-
-/*
- * Error Recovery do retry
- */
-static inline int
-tape_3590_erp_retry(struct tape_device *device, struct tape_request *request,
- struct irb *irb)
-{
- DBF_EVENT(2, "Retry: %s\n", tape_op_verbose[request->op]);
- tape_dump_sense_dbf(device, request, irb);
- return TAPE_IO_RETRY;
-}
-
-/*
- * Handle unsolicited interrupts
- */
-static int
-tape_3590_unsolicited_irq(struct tape_device *device, struct irb *irb)
-{
- if (irb->scsw.cmd.dstat == DEV_STAT_CHN_END)
- /* Probably result of halt ssch */
- return TAPE_IO_PENDING;
- else if (irb->scsw.cmd.dstat == 0x85)
- /* Device Ready */
- DBF_EVENT(3, "unsol.irq! tape ready: %08x\n", device->cdev_id);
- else if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
- tape_3590_schedule_work(device, TO_READ_ATTMSG);
- } else {
- DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id);
- tape_dump_sense_dbf(device, NULL, irb);
- }
- /* check medium state */
- tape_3590_schedule_work(device, TO_MSEN);
- return TAPE_IO_SUCCESS;
-}
-
-/*
- * Basic Recovery routine
- */
-static int
-tape_3590_erp_basic(struct tape_device *device, struct tape_request *request,
- struct irb *irb, int rc)
-{
- struct tape_3590_sense *sense;
-
- sense = (struct tape_3590_sense *) irb->ecw;
-
- switch (sense->bra) {
- case SENSE_BRA_PER:
- return tape_3590_erp_failed(device, request, irb, rc);
- case SENSE_BRA_CONT:
- return tape_3590_erp_succeeded(device, request);
- case SENSE_BRA_RE:
- return tape_3590_erp_retry(device, request, irb);
- case SENSE_BRA_DRE:
- return tape_3590_erp_failed(device, request, irb, rc);
- default:
- BUG();
- return TAPE_IO_STOP;
- }
-}
-
-/*
- * RDL: Read Device (buffered) log
- */
-static int
-tape_3590_erp_read_buf_log(struct tape_device *device,
- struct tape_request *request, struct irb *irb)
-{
- /*
- * We just do the basic error recovery at the moment (retry).
- * Perhaps in the future, we read the log and dump it somewhere...
- */
- return tape_3590_erp_basic(device, request, irb, -EIO);
-}
-
-/*
- * SWAP: Swap Devices
- */
-static int
-tape_3590_erp_swap(struct tape_device *device, struct tape_request *request,
- struct irb *irb)
-{
- /*
- * This error recovery should swap the tapes
- * if the original has a problem. The operation
- * should proceed with the new tape... this
- * should probably be done in user space!
- */
- dev_warn (&device->cdev->dev, "The tape medium must be loaded into a "
- "different tape unit\n");
- return tape_3590_erp_basic(device, request, irb, -EIO);
-}
-
-/*
- * LBY: Long Busy
- */
-static int
-tape_3590_erp_long_busy(struct tape_device *device,
- struct tape_request *request, struct irb *irb)
-{
- DBF_EVENT(6, "Device is busy\n");
- return TAPE_IO_LONG_BUSY;
-}
-
-/*
- * SPI: Special Intercept
- */
-static int
-tape_3590_erp_special_interrupt(struct tape_device *device,
- struct tape_request *request, struct irb *irb)
-{
- return tape_3590_erp_basic(device, request, irb, -EIO);
-}
-
-/*
- * Print an MIM (Media Information Message) (message code f0)
- */
-static void
-tape_3590_print_mim_msg_f0(struct tape_device *device, struct irb *irb)
-{
- struct tape_3590_sense *sense;
- char *exception, *service;
-
- exception = kmalloc(BUFSIZE, GFP_ATOMIC);
- service = kmalloc(BUFSIZE, GFP_ATOMIC);
-
- if (!exception || !service)
- goto out_nomem;
-
- sense = (struct tape_3590_sense *) irb->ecw;
- /* Exception Message */
- switch (sense->fmt.f70.emc) {
- case 0x02:
- snprintf(exception, BUFSIZE, "Data degraded");
- break;
- case 0x03:
- snprintf(exception, BUFSIZE, "Data degraded in partition %i",
- sense->fmt.f70.mp);
- break;
- case 0x04:
- snprintf(exception, BUFSIZE, "Medium degraded");
- break;
- case 0x05:
- snprintf(exception, BUFSIZE, "Medium degraded in partition %i",
- sense->fmt.f70.mp);
- break;
- case 0x06:
- snprintf(exception, BUFSIZE, "Block 0 Error");
- break;
- case 0x07:
- snprintf(exception, BUFSIZE, "Medium Exception 0x%02x",
- sense->fmt.f70.md);
- break;
- default:
- snprintf(exception, BUFSIZE, "0x%02x",
- sense->fmt.f70.emc);
- break;
- }
- /* Service Message */
- switch (sense->fmt.f70.smc) {
- case 0x02:
- snprintf(service, BUFSIZE, "Reference Media maintenance "
- "procedure %i", sense->fmt.f70.md);
- break;
- default:
- snprintf(service, BUFSIZE, "0x%02x",
- sense->fmt.f70.smc);
- break;
- }
-
- dev_warn (&device->cdev->dev, "Tape media information: exception %s, "
- "service %s\n", exception, service);
-
-out_nomem:
- kfree(exception);
- kfree(service);
-}
-
-/*
- * Print an I/O Subsystem Service Information Message (message code f1)
- */
-static void
-tape_3590_print_io_sim_msg_f1(struct tape_device *device, struct irb *irb)
-{
- struct tape_3590_sense *sense;
- char *exception, *service;
-
- exception = kmalloc(BUFSIZE, GFP_ATOMIC);
- service = kmalloc(BUFSIZE, GFP_ATOMIC);
-
- if (!exception || !service)
- goto out_nomem;
-
- sense = (struct tape_3590_sense *) irb->ecw;
- /* Exception Message */
- switch (sense->fmt.f71.emc) {
- case 0x01:
- snprintf(exception, BUFSIZE, "Effect of failure is unknown");
- break;
- case 0x02:
- snprintf(exception, BUFSIZE, "CU Exception - no performance "
- "impact");
- break;
- case 0x03:
- snprintf(exception, BUFSIZE, "CU Exception on channel "
- "interface 0x%02x", sense->fmt.f71.md[0]);
- break;
- case 0x04:
- snprintf(exception, BUFSIZE, "CU Exception on device path "
- "0x%02x", sense->fmt.f71.md[0]);
- break;
- case 0x05:
- snprintf(exception, BUFSIZE, "CU Exception on library path "
- "0x%02x", sense->fmt.f71.md[0]);
- break;
- case 0x06:
- snprintf(exception, BUFSIZE, "CU Exception on node 0x%02x",
- sense->fmt.f71.md[0]);
- break;
- case 0x07:
- snprintf(exception, BUFSIZE, "CU Exception on partition "
- "0x%02x", sense->fmt.f71.md[0]);
- break;
- default:
- snprintf(exception, BUFSIZE, "0x%02x",
- sense->fmt.f71.emc);
- }
- /* Service Message */
- switch (sense->fmt.f71.smc) {
- case 0x01:
- snprintf(service, BUFSIZE, "Repair impact is unknown");
- break;
- case 0x02:
- snprintf(service, BUFSIZE, "Repair will not impact cu "
- "performance");
- break;
- case 0x03:
- if (sense->fmt.f71.mdf == 0)
- snprintf(service, BUFSIZE, "Repair will disable node "
- "0x%x on CU", sense->fmt.f71.md[1]);
- else
- snprintf(service, BUFSIZE, "Repair will disable "
- "nodes (0x%x-0x%x) on CU", sense->fmt.f71.md[1],
- sense->fmt.f71.md[2]);
- break;
- case 0x04:
- if (sense->fmt.f71.mdf == 0)
- snprintf(service, BUFSIZE, "Repair will disable "
- "channel path 0x%x on CU",
- sense->fmt.f71.md[1]);
- else
- snprintf(service, BUFSIZE, "Repair will disable channel"
- " paths (0x%x-0x%x) on CU",
- sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
- break;
- case 0x05:
- if (sense->fmt.f71.mdf == 0)
- snprintf(service, BUFSIZE, "Repair will disable device"
- " path 0x%x on CU", sense->fmt.f71.md[1]);
- else
- snprintf(service, BUFSIZE, "Repair will disable device"
- " paths (0x%x-0x%x) on CU",
- sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
- break;
- case 0x06:
- if (sense->fmt.f71.mdf == 0)
- snprintf(service, BUFSIZE, "Repair will disable "
- "library path 0x%x on CU",
- sense->fmt.f71.md[1]);
- else
- snprintf(service, BUFSIZE, "Repair will disable "
- "library paths (0x%x-0x%x) on CU",
- sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
- break;
- case 0x07:
- snprintf(service, BUFSIZE, "Repair will disable access to CU");
- break;
- default:
- snprintf(service, BUFSIZE, "0x%02x",
- sense->fmt.f71.smc);
- }
-
- dev_warn (&device->cdev->dev, "I/O subsystem information: exception"
- " %s, service %s\n", exception, service);
-out_nomem:
- kfree(exception);
- kfree(service);
-}
-
-/*
- * Print an Device Subsystem Service Information Message (message code f2)
- */
-static void
-tape_3590_print_dev_sim_msg_f2(struct tape_device *device, struct irb *irb)
-{
- struct tape_3590_sense *sense;
- char *exception, *service;
-
- exception = kmalloc(BUFSIZE, GFP_ATOMIC);
- service = kmalloc(BUFSIZE, GFP_ATOMIC);
-
- if (!exception || !service)
- goto out_nomem;
-
- sense = (struct tape_3590_sense *) irb->ecw;
- /* Exception Message */
- switch (sense->fmt.f71.emc) {
- case 0x01:
- snprintf(exception, BUFSIZE, "Effect of failure is unknown");
- break;
- case 0x02:
- snprintf(exception, BUFSIZE, "DV Exception - no performance"
- " impact");
- break;
- case 0x03:
- snprintf(exception, BUFSIZE, "DV Exception on channel "
- "interface 0x%02x", sense->fmt.f71.md[0]);
- break;
- case 0x04:
- snprintf(exception, BUFSIZE, "DV Exception on loader 0x%02x",
- sense->fmt.f71.md[0]);
- break;
- case 0x05:
- snprintf(exception, BUFSIZE, "DV Exception on message display"
- " 0x%02x", sense->fmt.f71.md[0]);
- break;
- case 0x06:
- snprintf(exception, BUFSIZE, "DV Exception in tape path");
- break;
- case 0x07:
- snprintf(exception, BUFSIZE, "DV Exception in drive");
- break;
- default:
- snprintf(exception, BUFSIZE, "0x%02x",
- sense->fmt.f71.emc);
- }
- /* Service Message */
- switch (sense->fmt.f71.smc) {
- case 0x01:
- snprintf(service, BUFSIZE, "Repair impact is unknown");
- break;
- case 0x02:
- snprintf(service, BUFSIZE, "Repair will not impact device "
- "performance");
- break;
- case 0x03:
- if (sense->fmt.f71.mdf == 0)
- snprintf(service, BUFSIZE, "Repair will disable "
- "channel path 0x%x on DV",
- sense->fmt.f71.md[1]);
- else
- snprintf(service, BUFSIZE, "Repair will disable "
- "channel path (0x%x-0x%x) on DV",
- sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
- break;
- case 0x04:
- if (sense->fmt.f71.mdf == 0)
- snprintf(service, BUFSIZE, "Repair will disable "
- "interface 0x%x on DV", sense->fmt.f71.md[1]);
- else
- snprintf(service, BUFSIZE, "Repair will disable "
- "interfaces (0x%x-0x%x) on DV",
- sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
- break;
- case 0x05:
- if (sense->fmt.f71.mdf == 0)
- snprintf(service, BUFSIZE, "Repair will disable loader"
- " 0x%x on DV", sense->fmt.f71.md[1]);
- else
- snprintf(service, BUFSIZE, "Repair will disable loader"
- " (0x%x-0x%x) on DV",
- sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
- break;
- case 0x07:
- snprintf(service, BUFSIZE, "Repair will disable access to DV");
- break;
- case 0x08:
- if (sense->fmt.f71.mdf == 0)
- snprintf(service, BUFSIZE, "Repair will disable "
- "message display 0x%x on DV",
- sense->fmt.f71.md[1]);
- else
- snprintf(service, BUFSIZE, "Repair will disable "
- "message displays (0x%x-0x%x) on DV",
- sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
- break;
- case 0x09:
- snprintf(service, BUFSIZE, "Clean DV");
- break;
- default:
- snprintf(service, BUFSIZE, "0x%02x",
- sense->fmt.f71.smc);
- }
-
- dev_warn (&device->cdev->dev, "Device subsystem information: exception"
- " %s, service %s\n", exception, service);
-out_nomem:
- kfree(exception);
- kfree(service);
-}
-
-/*
- * Print standard ERA Message
- */
-static void
-tape_3590_print_era_msg(struct tape_device *device, struct irb *irb)
-{
- struct tape_3590_sense *sense;
-
- sense = (struct tape_3590_sense *) irb->ecw;
- if (sense->mc == 0)
- return;
- if ((sense->mc > 0) && (sense->mc < TAPE_3590_MAX_MSG)) {
- if (tape_3590_msg[sense->mc] != NULL)
- dev_warn (&device->cdev->dev, "The tape unit has "
- "issued sense message %s\n",
- tape_3590_msg[sense->mc]);
- else
- dev_warn (&device->cdev->dev, "The tape unit has "
- "issued an unknown sense message code 0x%x\n",
- sense->mc);
- return;
- }
- if (sense->mc == 0xf0) {
- /* Standard Media Information Message */
- dev_warn (&device->cdev->dev, "MIM SEV=%i, MC=%02x, ES=%x/%x, "
- "RC=%02x-%04x-%02x\n", sense->fmt.f70.sev, sense->mc,
- sense->fmt.f70.emc, sense->fmt.f70.smc,
- sense->fmt.f70.refcode, sense->fmt.f70.mid,
- sense->fmt.f70.fid);
- tape_3590_print_mim_msg_f0(device, irb);
- return;
- }
- if (sense->mc == 0xf1) {
- /* Standard I/O Subsystem Service Information Message */
- dev_warn (&device->cdev->dev, "IOSIM SEV=%i, DEVTYPE=3590/%02x,"
- " MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n",
- sense->fmt.f71.sev, device->cdev->id.dev_model,
- sense->mc, sense->fmt.f71.emc, sense->fmt.f71.smc,
- sense->fmt.f71.refcode1, sense->fmt.f71.refcode2,
- sense->fmt.f71.refcode3);
- tape_3590_print_io_sim_msg_f1(device, irb);
- return;
- }
- if (sense->mc == 0xf2) {
- /* Standard Device Service Information Message */
- dev_warn (&device->cdev->dev, "DEVSIM SEV=%i, DEVTYPE=3590/%02x"
- ", MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n",
- sense->fmt.f71.sev, device->cdev->id.dev_model,
- sense->mc, sense->fmt.f71.emc, sense->fmt.f71.smc,
- sense->fmt.f71.refcode1, sense->fmt.f71.refcode2,
- sense->fmt.f71.refcode3);
- tape_3590_print_dev_sim_msg_f2(device, irb);
- return;
- }
- if (sense->mc == 0xf3) {
- /* Standard Library Service Information Message */
- return;
- }
- dev_warn (&device->cdev->dev, "The tape unit has issued an unknown "
- "sense message code %x\n", sense->mc);
-}
-
-static int tape_3590_crypt_error(struct tape_device *device,
- struct tape_request *request, struct irb *irb)
-{
- u8 cu_rc;
- u16 ekm_rc2;
- char *sense;
-
- sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data;
- cu_rc = sense[0];
- ekm_rc2 = *((u16*) &sense[10]);
- if ((cu_rc == 0) && (ekm_rc2 == 0xee31))
- /* key not defined on EKM */
- return tape_3590_erp_basic(device, request, irb, -EKEYREJECTED);
- if ((cu_rc == 1) || (cu_rc == 2))
- /* No connection to EKM */
- return tape_3590_erp_basic(device, request, irb, -ENOTCONN);
-
- dev_err (&device->cdev->dev, "The tape unit failed to obtain the "
- "encryption key from EKM\n");
-
- return tape_3590_erp_basic(device, request, irb, -ENOKEY);
-}
-
-/*
- * 3590 error Recovery routine:
- * If possible, it tries to recover from the error. If this is not possible,
- * inform the user about the problem.
- */
-static int
-tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
- struct irb *irb)
-{
- struct tape_3590_sense *sense;
-
- sense = (struct tape_3590_sense *) irb->ecw;
-
- DBF_EVENT(6, "Unit Check: RQC = %x\n", sense->rc_rqc);
-
- /*
- * First check all RC-QRCs where we want to do something special
- * - "break": basic error recovery is done
- * - "goto out:": just print error message if available
- */
- switch (sense->rc_rqc) {
-
- case 0x1110:
- tape_3590_print_era_msg(device, irb);
- return tape_3590_erp_read_buf_log(device, request, irb);
-
- case 0x2230:
- case 0x2231:
- tape_3590_print_era_msg(device, irb);
- return tape_3590_erp_special_interrupt(device, request, irb);
- case 0x2240:
- return tape_3590_crypt_error(device, request, irb);
-
- case 0x3010:
- DBF_EVENT(2, "(%08x): Backward at Beginning of Partition\n",
- device->cdev_id);
- return tape_3590_erp_basic(device, request, irb, -ENOSPC);
- case 0x3012:
- DBF_EVENT(2, "(%08x): Forward at End of Partition\n",
- device->cdev_id);
- return tape_3590_erp_basic(device, request, irb, -ENOSPC);
- case 0x3020:
- DBF_EVENT(2, "(%08x): End of Data Mark\n", device->cdev_id);
- return tape_3590_erp_basic(device, request, irb, -ENOSPC);
-
- case 0x3122:
- DBF_EVENT(2, "(%08x): Rewind Unload initiated\n",
- device->cdev_id);
- return tape_3590_erp_basic(device, request, irb, -EIO);
- case 0x3123:
- DBF_EVENT(2, "(%08x): Rewind Unload complete\n",
- device->cdev_id);
- tape_med_state_set(device, MS_UNLOADED);
- tape_3590_schedule_work(device, TO_CRYPT_OFF);
- return tape_3590_erp_basic(device, request, irb, 0);
-
- case 0x4010:
- /*
- * print additional msg since default msg
- * "device intervention" is not very meaningfull
- */
- tape_med_state_set(device, MS_UNLOADED);
- tape_3590_schedule_work(device, TO_CRYPT_OFF);
- return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);
- case 0x4012: /* Device Long Busy */
- /* XXX: Also use long busy handling here? */
- DBF_EVENT(6, "(%08x): LONG BUSY\n", device->cdev_id);
- tape_3590_print_era_msg(device, irb);
- return tape_3590_erp_basic(device, request, irb, -EBUSY);
- case 0x4014:
- DBF_EVENT(6, "(%08x): Crypto LONG BUSY\n", device->cdev_id);
- return tape_3590_erp_long_busy(device, request, irb);
-
- case 0x5010:
- if (sense->rac == 0xd0) {
- /* Swap */
- tape_3590_print_era_msg(device, irb);
- return tape_3590_erp_swap(device, request, irb);
- }
- return tape_3590_erp_basic(device, request, irb, -EIO);
- case 0x5020:
- case 0x5021:
- case 0x5022:
- case 0x5040:
- case 0x5041:
- case 0x5042:
- tape_3590_print_era_msg(device, irb);
- return tape_3590_erp_swap(device, request, irb);
-
- case 0x5110:
- case 0x5111:
- return tape_3590_erp_basic(device, request, irb, -EMEDIUMTYPE);
-
- case 0x5120:
- case 0x1120:
- tape_med_state_set(device, MS_UNLOADED);
- tape_3590_schedule_work(device, TO_CRYPT_OFF);
- return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);
-
- case 0x6020:
- return tape_3590_erp_basic(device, request, irb, -EMEDIUMTYPE);
-
- case 0x8011:
- return tape_3590_erp_basic(device, request, irb, -EPERM);
- case 0x8013:
- dev_warn (&device->cdev->dev, "A different host has privileged"
- " access to the tape unit\n");
- return tape_3590_erp_basic(device, request, irb, -EPERM);
- default:
- return tape_3590_erp_basic(device, request, irb, -EIO);
- }
-}
-
-/*
- * 3590 interrupt handler:
- */
-static int
-tape_3590_irq(struct tape_device *device, struct tape_request *request,
- struct irb *irb)
-{
- if (request == NULL)
- return tape_3590_unsolicited_irq(device, irb);
-
- if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) &&
- (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) &&
- (request->op == TO_WRI)) {
- /* Write at end of volume */
- DBF_EVENT(2, "End of volume\n");
- return tape_3590_erp_failed(device, request, irb, -ENOSPC);
- }
-
- if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)
- return tape_3590_unit_check(device, request, irb);
-
- if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) {
- if (irb->scsw.cmd.dstat == DEV_STAT_UNIT_EXCEP) {
- if (request->op == TO_FSB || request->op == TO_BSB)
- request->rescnt++;
- else
- DBF_EVENT(5, "Unit Exception!\n");
- }
-
- return tape_3590_done(device, request);
- }
-
- if (irb->scsw.cmd.dstat & DEV_STAT_CHN_END) {
- DBF_EVENT(2, "channel end\n");
- return TAPE_IO_PENDING;
- }
-
- if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
- DBF_EVENT(2, "Unit Attention when busy..\n");
- return TAPE_IO_PENDING;
- }
-
- DBF_EVENT(6, "xunknownirq\n");
- tape_dump_sense_dbf(device, request, irb);
- return TAPE_IO_STOP;
-}
-
-
-static int tape_3590_read_dev_chars(struct tape_device *device,
- struct tape_3590_rdc_data *rdc_data)
-{
- int rc;
- struct tape_request *request;
-
- request = tape_alloc_request(1, sizeof(*rdc_data));
- if (IS_ERR(request))
- return PTR_ERR(request);
- request->op = TO_RDC;
- tape_ccw_end(request->cpaddr, CCW_CMD_RDC, sizeof(*rdc_data),
- request->cpdata);
- rc = tape_do_io(device, request);
- if (rc == 0)
- memcpy(rdc_data, request->cpdata, sizeof(*rdc_data));
- tape_free_request(request);
- return rc;
-}
-
-/*
- * Setup device function
- */
-static int
-tape_3590_setup_device(struct tape_device *device)
-{
- int rc;
- struct tape_3590_disc_data *data;
- struct tape_3590_rdc_data *rdc_data;
-
- DBF_EVENT(6, "3590 device setup\n");
- data = kzalloc(sizeof(struct tape_3590_disc_data), GFP_KERNEL | GFP_DMA);
- if (data == NULL)
- return -ENOMEM;
- data->read_back_op = READ_PREVIOUS;
- device->discdata = data;
-
- rdc_data = kmalloc(sizeof(*rdc_data), GFP_KERNEL | GFP_DMA);
- if (!rdc_data) {
- rc = -ENOMEM;
- goto fail_kmalloc;
- }
- rc = tape_3590_read_dev_chars(device, rdc_data);
- if (rc) {
- DBF_LH(3, "Read device characteristics failed!\n");
- goto fail_rdc_data;
- }
- rc = tape_std_assign(device);
- if (rc)
- goto fail_rdc_data;
- if (rdc_data->data[31] == 0x13) {
- data->crypt_info.capability |= TAPE390_CRYPT_SUPPORTED_MASK;
- tape_3592_disable_crypt(device);
- } else {
- DBF_EVENT(6, "Device has NO crypto support\n");
- }
- /* Try to find out if medium is loaded */
- rc = tape_3590_sense_medium(device);
- if (rc) {
- DBF_LH(3, "3590 medium sense returned %d\n", rc);
- goto fail_rdc_data;
- }
- return 0;
-
-fail_rdc_data:
- kfree(rdc_data);
-fail_kmalloc:
- kfree(data);
- return rc;
-}
-
-/*
- * Cleanup device function
- */
-static void
-tape_3590_cleanup_device(struct tape_device *device)
-{
- flush_workqueue(tape_3590_wq);
- tape_std_unassign(device);
-
- kfree(device->discdata);
- device->discdata = NULL;
-}
-
-/*
- * List of 3590 magnetic tape commands.
- */
-static tape_mtop_fn tape_3590_mtop[TAPE_NR_MTOPS] = {
- [MTRESET] = tape_std_mtreset,
- [MTFSF] = tape_std_mtfsf,
- [MTBSF] = tape_std_mtbsf,
- [MTFSR] = tape_std_mtfsr,
- [MTBSR] = tape_std_mtbsr,
- [MTWEOF] = tape_std_mtweof,
- [MTREW] = tape_std_mtrew,
- [MTOFFL] = tape_std_mtoffl,
- [MTNOP] = tape_std_mtnop,
- [MTRETEN] = tape_std_mtreten,
- [MTBSFM] = tape_std_mtbsfm,
- [MTFSFM] = tape_std_mtfsfm,
- [MTEOM] = tape_std_mteom,
- [MTERASE] = tape_std_mterase,
- [MTRAS1] = NULL,
- [MTRAS2] = NULL,
- [MTRAS3] = NULL,
- [MTSETBLK] = tape_std_mtsetblk,
- [MTSETDENSITY] = NULL,
- [MTSEEK] = tape_3590_mtseek,
- [MTTELL] = tape_3590_mttell,
- [MTSETDRVBUFFER] = NULL,
- [MTFSS] = NULL,
- [MTBSS] = NULL,
- [MTWSM] = NULL,
- [MTLOCK] = NULL,
- [MTUNLOCK] = NULL,
- [MTLOAD] = tape_std_mtload,
- [MTUNLOAD] = tape_std_mtunload,
- [MTCOMPRESSION] = tape_std_mtcompression,
- [MTSETPART] = NULL,
- [MTMKPART] = NULL
-};
-
-/*
- * Tape discipline structure for 3590.
- */
-static struct tape_discipline tape_discipline_3590 = {
- .owner = THIS_MODULE,
- .setup_device = tape_3590_setup_device,
- .cleanup_device = tape_3590_cleanup_device,
- .process_eov = tape_std_process_eov,
- .irq = tape_3590_irq,
- .read_block = tape_std_read_block,
- .write_block = tape_std_write_block,
- .ioctl_fn = tape_3590_ioctl,
- .mtop_array = tape_3590_mtop
-};
-
-static struct ccw_device_id tape_3590_ids[] = {
- {CCW_DEVICE_DEVTYPE(0x3590, 0, 0x3590, 0), .driver_info = tape_3590},
- {CCW_DEVICE_DEVTYPE(0x3592, 0, 0x3592, 0), .driver_info = tape_3592},
- { /* end of list */ }
-};
-
-static int
-tape_3590_online(struct ccw_device *cdev)
-{
- return tape_generic_online(dev_get_drvdata(&cdev->dev),
- &tape_discipline_3590);
-}
-
-static struct ccw_driver tape_3590_driver = {
- .driver = {
- .name = "tape_3590",
- .owner = THIS_MODULE,
- },
- .ids = tape_3590_ids,
- .probe = tape_generic_probe,
- .remove = tape_generic_remove,
- .set_offline = tape_generic_offline,
- .set_online = tape_3590_online,
- .int_class = IRQIO_TAP,
-};
-
-/*
- * Setup discipline structure.
- */
-static int
-tape_3590_init(void)
-{
- int rc;
-
- TAPE_DBF_AREA = debug_register("tape_3590", 2, 2, 4 * sizeof(long));
- debug_register_view(TAPE_DBF_AREA, &debug_sprintf_view);
-#ifdef DBF_LIKE_HELL
- debug_set_level(TAPE_DBF_AREA, 6);
-#endif
-
- DBF_EVENT(3, "3590 init\n");
-
- tape_3590_wq = alloc_workqueue("tape_3590", WQ_PERCPU, 0);
- if (!tape_3590_wq)
- return -ENOMEM;
-
- /* Register driver for 3590 tapes. */
- rc = ccw_driver_register(&tape_3590_driver);
- if (rc) {
- destroy_workqueue(tape_3590_wq);
- DBF_EVENT(3, "3590 init failed\n");
- } else
- DBF_EVENT(3, "3590 registered\n");
- return rc;
-}
-
-static void
-tape_3590_exit(void)
-{
- ccw_driver_unregister(&tape_3590_driver);
- destroy_workqueue(tape_3590_wq);
- debug_unregister(TAPE_DBF_AREA);
-}
-
-MODULE_DEVICE_TABLE(ccw, tape_3590_ids);
-MODULE_AUTHOR("(C) 2001,2006 IBM Corporation");
-MODULE_DESCRIPTION("Linux on zSeries channel attached 3590 tape device driver");
-MODULE_LICENSE("GPL");
-
-module_init(tape_3590_init);
-module_exit(tape_3590_exit);
diff --git a/drivers/s390/char/tape_3590.h b/drivers/s390/char/tape_3590.h
deleted file mode 100644
index b398d8a3ed3c..000000000000
--- a/drivers/s390/char/tape_3590.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * tape device discipline for 3590 tapes.
- *
- * Copyright IBM Corp. 2001, 2006
- * Author(s): Stefan Bader <shbader@de.ibm.com>
- * Michael Holzheu <holzheu@de.ibm.com>
- * Martin Schwidefsky <schwidefsky@de.ibm.com>
- */
-
-#ifndef _TAPE_3590_H
-#define _TAPE_3590_H
-
-#define MEDIUM_SENSE 0xc2
-#define READ_PREVIOUS 0x0a
-#define MODE_SENSE 0xcf
-#define PERFORM_SS_FUNC 0x77
-#define READ_SS_DATA 0x3e
-
-#define PREP_RD_SS_DATA 0x18
-#define RD_ATTMSG 0x3
-
-#define SENSE_BRA_PER 0
-#define SENSE_BRA_CONT 1
-#define SENSE_BRA_RE 2
-#define SENSE_BRA_DRE 3
-
-#define SENSE_FMT_LIBRARY 0x23
-#define SENSE_FMT_UNSOLICITED 0x40
-#define SENSE_FMT_COMMAND_REJ 0x41
-#define SENSE_FMT_COMMAND_EXEC0 0x50
-#define SENSE_FMT_COMMAND_EXEC1 0x51
-#define SENSE_FMT_EVENT0 0x60
-#define SENSE_FMT_EVENT1 0x61
-#define SENSE_FMT_MIM 0x70
-#define SENSE_FMT_SIM 0x71
-
-#define MSENSE_UNASSOCIATED 0x00
-#define MSENSE_ASSOCIATED_MOUNT 0x01
-#define MSENSE_ASSOCIATED_UMOUNT 0x02
-#define MSENSE_CRYPT_MASK 0x00000010
-
-#define TAPE_3590_MAX_MSG 0xb0
-
-/* Datatypes */
-
-struct tape_3590_disc_data {
- struct tape390_crypt_info crypt_info;
- int read_back_op;
-};
-
-#define TAPE_3590_CRYPT_INFO(device) \
- ((struct tape_3590_disc_data*)(device->discdata))->crypt_info
-#define TAPE_3590_READ_BACK_OP(device) \
- ((struct tape_3590_disc_data*)(device->discdata))->read_back_op
-
-struct tape_3590_sense {
-
- unsigned int command_rej:1;
- unsigned int interv_req:1;
- unsigned int bus_out_check:1;
- unsigned int eq_check:1;
- unsigned int data_check:1;
- unsigned int overrun:1;
- unsigned int def_unit_check:1;
- unsigned int assgnd_elsew:1;
-
- unsigned int locate_fail:1;
- unsigned int inst_online:1;
- unsigned int reserved:1;
- unsigned int blk_seq_err:1;
- unsigned int begin_part:1;
- unsigned int wr_mode:1;
- unsigned int wr_prot:1;
- unsigned int not_cap:1;
-
- unsigned int bra:2;
- unsigned int lc:3;
- unsigned int vlf_active:1;
- unsigned int stm:1;
- unsigned int med_pos:1;
-
- unsigned int rac:8;
-
- unsigned int rc_rqc:16;
-
- unsigned int mc:8;
-
- unsigned int sense_fmt:8;
-
- union {
- struct {
- unsigned int emc:4;
- unsigned int smc:4;
- unsigned int sev:2;
- unsigned int reserved:6;
- unsigned int md:8;
- unsigned int refcode:8;
- unsigned int mid:16;
- unsigned int mp:16;
- unsigned char volid[6];
- unsigned int fid:8;
- } f70;
- struct {
- unsigned int emc:4;
- unsigned int smc:4;
- unsigned int sev:2;
- unsigned int reserved1:5;
- unsigned int mdf:1;
- unsigned char md[3];
- unsigned int simid:8;
- unsigned int uid:16;
- unsigned int refcode1:16;
- unsigned int refcode2:16;
- unsigned int refcode3:16;
- unsigned int reserved2:8;
- } f71;
- unsigned char data[14];
- } fmt;
- unsigned char pad[10];
-
-} __attribute__ ((packed));
-
-struct tape_3590_med_sense {
- unsigned int macst:4;
- unsigned int masst:4;
- char pad1[7];
- unsigned int flags;
- char pad2[116];
-} __attribute__ ((packed));
-
-struct tape_3590_rdc_data {
- char data[64];
-} __attribute__ ((packed));
-
-/* Datastructures for 3592 encryption support */
-
-struct tape3592_kekl {
- __u8 flags;
- char label[64];
-} __attribute__ ((packed));
-
-struct tape3592_kekl_pair {
- __u8 count;
- struct tape3592_kekl kekl[2];
-} __attribute__ ((packed));
-
-struct tape3592_kekl_query_data {
- __u16 len;
- __u8 fmt;
- __u8 mc;
- __u32 id;
- __u8 flags;
- struct tape3592_kekl_pair kekls;
- char reserved[116];
-} __attribute__ ((packed));
-
-struct tape3592_kekl_query_order {
- __u8 code;
- __u8 flags;
- char reserved1[2];
- __u8 max_count;
- char reserved2[35];
-} __attribute__ ((packed));
-
-struct tape3592_kekl_set_order {
- __u8 code;
- __u8 flags;
- char reserved1[2];
- __u8 op;
- struct tape3592_kekl_pair kekls;
- char reserved2[120];
-} __attribute__ ((packed));
-
-#endif /* _TAPE_3590_H */
diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c
index c5d3c303c15c..879331e2f283 100644
--- a/drivers/s390/char/tape_char.c
+++ b/drivers/s390/char/tape_char.c
@@ -412,10 +412,7 @@ __tapechar_ioctl(struct tape_device *device,
return put_user_mtget(data, &get);
}
- /* Try the discipline ioctl function. */
- if (device->discipline->ioctl_fn == NULL)
- return -EINVAL;
- return device->discipline->ioctl_fn(device, no, (unsigned long)data);
+ return -EINVAL;
}
static long
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index 0250076a7d9f..7cf7167dcf56 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -74,9 +74,7 @@ const char *tape_op_verbose[TO_SIZE] =
[TO_LOAD] = "LOA", [TO_READ_CONFIG] = "RCF",
[TO_READ_ATTMSG] = "RAT",
[TO_DIS] = "DIS", [TO_ASSIGN] = "ASS",
- [TO_UNASSIGN] = "UAS", [TO_CRYPT_ON] = "CON",
- [TO_CRYPT_OFF] = "COF", [TO_KEKL_SET] = "KLS",
- [TO_KEKL_QUERY] = "KLQ",[TO_RDC] = "RDC",
+ [TO_UNASSIGN] = "UAS", [TO_RDC] = "RDC",
};
static int devid_to_int(struct ccw_dev_id *dev_id)
diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c
index 43a5586685ff..96b7440126d2 100644
--- a/drivers/s390/char/tape_std.c
+++ b/drivers/s390/char/tape_std.c
@@ -22,7 +22,6 @@
#include <asm/types.h>
#include <asm/idals.h>
#include <asm/ebcdic.h>
-#include <asm/tape390.h>
#define TAPE_DBF_AREA tape_core_dbf
@@ -119,36 +118,6 @@ tape_std_unassign (struct tape_device *device)
}
/*
- * TAPE390_DISPLAY: Show a string on the tape display.
- */
-int
-tape_std_display(struct tape_device *device, struct display_struct *disp)
-{
- struct tape_request *request;
- int rc;
-
- request = tape_alloc_request(2, 17);
- if (IS_ERR(request)) {
- DBF_EVENT(3, "TAPE: load display failed\n");
- return PTR_ERR(request);
- }
- request->op = TO_DIS;
-
- *(unsigned char *) request->cpdata = disp->cntrl;
- DBF_EVENT(5, "TAPE: display cntrl=%04x\n", disp->cntrl);
- memcpy(((unsigned char *) request->cpdata) + 1, disp->message1, 8);
- memcpy(((unsigned char *) request->cpdata) + 9, disp->message2, 8);
- ASCEBC(((unsigned char*) request->cpdata) + 1, 16);
-
- tape_ccw_cc(request->cpaddr, LOAD_DISPLAY, 17, request->cpdata);
- tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
-
- rc = tape_do_io_interruptible(device, request);
- tape_free_request(request);
- return rc;
-}
-
-/*
* Read block id.
*/
int
@@ -696,7 +665,6 @@ tape_std_process_eov(struct tape_device *device)
EXPORT_SYMBOL(tape_std_assign);
EXPORT_SYMBOL(tape_std_unassign);
-EXPORT_SYMBOL(tape_std_display);
EXPORT_SYMBOL(tape_std_read_block_id);
EXPORT_SYMBOL(tape_std_mtload);
EXPORT_SYMBOL(tape_std_mtsetblk);
diff --git a/drivers/s390/char/tape_std.h b/drivers/s390/char/tape_std.h
index 2cf9f725b3b3..2b67b0dc9ddd 100644
--- a/drivers/s390/char/tape_std.h
+++ b/drivers/s390/char/tape_std.h
@@ -11,8 +11,6 @@
#ifndef _TAPE_STD_H
#define _TAPE_STD_H
-#include <asm/tape390.h>
-
/*
* Biggest block size of 256K to handle.
*/
@@ -21,54 +19,25 @@
/*
* The CCW commands for the Tape type of command.
*/
-#define INVALID_00 0x00 /* Invalid cmd */
#define BACKSPACEBLOCK 0x27 /* Back Space block */
#define BACKSPACEFILE 0x2f /* Back Space file */
#define DATA_SEC_ERASE 0x97 /* Data security erase */
#define ERASE_GAP 0x17 /* Erase Gap */
#define FORSPACEBLOCK 0x37 /* Forward space block */
#define FORSPACEFILE 0x3F /* Forward Space file */
-#define FORCE_STREAM_CNT 0xEB /* Forced streaming count # */
#define NOP 0x03 /* No operation */
#define READ_FORWARD 0x02 /* Read forward */
#define REWIND 0x07 /* Rewind */
#define REWIND_UNLOAD 0x0F /* Rewind and Unload */
#define SENSE 0x04 /* Sense */
-#define NEW_MODE_SET 0xEB /* Guess it is Mode set */
#define WRITE_CMD 0x01 /* Write */
#define WRITETAPEMARK 0x1F /* Write Tape Mark */
-#define ASSIGN 0xB7 /* 3420 REJECT,3480 OK */
-#define CONTROL_ACCESS 0xE3 /* Set high speed */
-#define DIAG_MODE_SET 0x0B /* 3420 NOP, 3480 REJECT */
-#define LOAD_DISPLAY 0x9F /* 3420 REJECT,3480 OK */
-#define LOCATE 0x4F /* 3420 REJ, 3480 NOP */
-#define LOOP_WRITE_TO_READ 0x8B /* 3480 REJECT */
-#define MODE_SET_DB 0xDB /* 3420 REJECT,3480 OK */
-#define MODE_SET_C3 0xC3 /* for 3420 */
-#define MODE_SET_CB 0xCB /* for 3420 */
-#define MODE_SET_D3 0xD3 /* for 3420 */
-#define READ_BACKWARD 0x0C /* */
-#define READ_BLOCK_ID 0x22 /* 3420 REJECT,3480 OK */
-#define READ_BUFFER 0x12 /* 3420 REJECT,3480 OK */
-#define READ_BUFF_LOG 0x24 /* 3420 REJECT,3480 OK */
-#define RELEASE 0xD4 /* 3420 NOP, 3480 REJECT */
-#define REQ_TRK_IN_ERROR 0x1B /* 3420 NOP, 3480 REJECT */
-#define RESERVE 0xF4 /* 3420 NOP, 3480 REJECT */
-#define SENSE_GROUP_ID 0x34 /* 3420 REJECT,3480 OK */
-#define SENSE_ID 0xE4 /* 3420 REJECT,3480 OK */
-#define READ_DEV_CHAR 0x64 /* Read device characteristics */
-#define SET_DIAGNOSE 0x4B /* 3420 NOP, 3480 REJECT */
-#define SET_GROUP_ID 0xAF /* 3420 REJECT,3480 OK */
-#define SET_TAPE_WRITE_IMMED 0xC3 /* for 3480 */
-#define SUSPEND 0x5B /* 3420 REJ, 3480 NOP */
-#define SYNC 0x43 /* Synchronize (flush buffer) */
-#define UNASSIGN 0xC7 /* 3420 REJECT,3480 OK */
-#define PERF_SUBSYS_FUNC 0x77 /* 3490 CMD */
-#define READ_CONFIG_DATA 0xFA /* 3490 CMD */
-#define READ_MESSAGE_ID 0x4E /* 3490 CMD */
-#define READ_SUBSYS_DATA 0x3E /* 3490 CMD */
-#define SET_INTERFACE_ID 0x73 /* 3490 CMD */
+#define ASSIGN 0xB7 /* Assign */
+#define LOCATE 0x4F /* Locate Block */
+#define MODE_SET_DB 0xDB /* Mode Set */
+#define READ_BLOCK_ID 0x22 /* Read Block ID */
+#define UNASSIGN 0xC7 /* Unassign */
#define SENSE_COMMAND_REJECT 0x80
#define SENSE_INTERVENTION_REQUIRED 0x40
@@ -105,7 +74,6 @@ struct tape_request *tape_std_write_block(struct tape_device *);
int tape_std_assign(struct tape_device *);
int tape_std_unassign(struct tape_device *);
int tape_std_read_block_id(struct tape_device *device, __u64 *id);
-int tape_std_display(struct tape_device *, struct display_struct *disp);
int tape_std_terminate_write(struct tape_device *);
/* Standard magnetic tape commands. */
@@ -133,10 +101,7 @@ void tape_std_process_eov(struct tape_device *);
/* S390 tape types */
enum s390_tape_type {
- tape_3480,
tape_3490,
- tape_3590,
- tape_3592,
};
#endif // _TAPE_STD_H