aboutsummaryrefslogtreecommitdiff
path: root/drivers/s390/char
diff options
context:
space:
mode:
authorDmitry Torokhov <dtor_core@ameritech.net>2006-04-02 00:08:05 -0500
committerDmitry Torokhov <dtor_core@ameritech.net>2006-04-02 00:08:05 -0500
commit95d465fd750897ab32462a6702fbfe1b122cbbc0 (patch)
tree65c38b2f11c51bb6932e44dd6c92f15b0091abfe /drivers/s390/char
parent642fde17dceceb56c7ba2762733ac688666ae657 (diff)
parent683aa4012f53b2ada0f430487e05d37b0d94e90a (diff)
Manual merge with Linus.
Conflicts: arch/powerpc/kernel/setup-common.c drivers/input/keyboard/hil_kbd.c drivers/input/mouse/hil_ptr.c
Diffstat (limited to 'drivers/s390/char')
-rw-r--r--drivers/s390/char/Makefile1
-rw-r--r--drivers/s390/char/fs3270.c3
-rw-r--r--drivers/s390/char/keyboard.c12
-rw-r--r--drivers/s390/char/monreader.c6
-rw-r--r--drivers/s390/char/raw3270.c42
-rw-r--r--drivers/s390/char/tape.h1
-rw-r--r--drivers/s390/char/tape_34xx.c8
-rw-r--r--drivers/s390/char/tape_3590.c1301
-rw-r--r--drivers/s390/char/tape_3590.h124
-rw-r--r--drivers/s390/char/tape_class.c3
-rw-r--r--drivers/s390/char/tape_core.c57
-rw-r--r--drivers/s390/char/tape_std.c15
-rw-r--r--drivers/s390/char/tape_std.h12
-rw-r--r--drivers/s390/char/tty3270.c9
-rw-r--r--drivers/s390/char/vmlogrdr.c3
15 files changed, 1514 insertions, 83 deletions
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index 6377a96735d..0c0162ff6c0 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -26,4 +26,5 @@ 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_MONREADER) += monreader.o
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index 5f6fa4c6784..a6415377bc7 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -368,10 +368,9 @@ fs3270_alloc_view(void)
{
struct fs3270 *fp;
- fp = (struct fs3270 *) kmalloc(sizeof(struct fs3270),GFP_KERNEL);
+ fp = kzalloc(sizeof(struct fs3270),GFP_KERNEL);
if (!fp)
return ERR_PTR(-ENOMEM);
- memset(fp, 0, sizeof(struct fs3270));
fp->init = raw3270_request_alloc(0);
if (IS_ERR(fp->init)) {
kfree(fp);
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
index a317a123dab..6badd840340 100644
--- a/drivers/s390/char/keyboard.c
+++ b/drivers/s390/char/keyboard.c
@@ -50,14 +50,12 @@ kbd_alloc(void) {
struct kbd_data *kbd;
int i, len;
- kbd = kmalloc(sizeof(struct kbd_data), GFP_KERNEL);
+ kbd = kzalloc(sizeof(struct kbd_data), GFP_KERNEL);
if (!kbd)
goto out;
- memset(kbd, 0, sizeof(struct kbd_data));
- kbd->key_maps = kmalloc(sizeof(key_maps), GFP_KERNEL);
+ kbd->key_maps = kzalloc(sizeof(key_maps), GFP_KERNEL);
if (!key_maps)
goto out_kbd;
- memset(kbd->key_maps, 0, sizeof(key_maps));
for (i = 0; i < ARRAY_SIZE(key_maps); i++) {
if (key_maps[i]) {
kbd->key_maps[i] =
@@ -68,10 +66,9 @@ kbd_alloc(void) {
sizeof(u_short)*NR_KEYS);
}
}
- kbd->func_table = kmalloc(sizeof(func_table), GFP_KERNEL);
+ kbd->func_table = kzalloc(sizeof(func_table), GFP_KERNEL);
if (!kbd->func_table)
goto out_maps;
- memset(kbd->func_table, 0, sizeof(func_table));
for (i = 0; i < ARRAY_SIZE(func_table); i++) {
if (func_table[i]) {
len = strlen(func_table[i]) + 1;
@@ -82,10 +79,9 @@ kbd_alloc(void) {
}
}
kbd->fn_handler =
- kmalloc(sizeof(fn_handler_fn *) * NR_FN_HANDLER, GFP_KERNEL);
+ kzalloc(sizeof(fn_handler_fn *) * NR_FN_HANDLER, GFP_KERNEL);
if (!kbd->fn_handler)
goto out_func;
- memset(kbd->fn_handler, 0, sizeof(fn_handler_fn *) * NR_FN_HANDLER);
kbd->accent_table =
kmalloc(sizeof(struct kbdiacr)*MAX_DIACR, GFP_KERNEL);
if (!kbd->accent_table)
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c
index 5fd3ad86738..fb7bc9e5eeb 100644
--- a/drivers/s390/char/monreader.c
+++ b/drivers/s390/char/monreader.c
@@ -257,14 +257,13 @@ mon_alloc_mem(void)
int i,j;
struct mon_private *monpriv;
- monpriv = kmalloc(sizeof(struct mon_private), GFP_KERNEL);
+ monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL);
if (!monpriv) {
P_ERROR("no memory for monpriv\n");
return NULL;
}
- memset(monpriv, 0, sizeof(struct mon_private));
for (i = 0; i < MON_MSGLIM; i++) {
- monpriv->msg_array[i] = kmalloc(sizeof(struct mon_msg),
+ monpriv->msg_array[i] = kzalloc(sizeof(struct mon_msg),
GFP_KERNEL);
if (!monpriv->msg_array[i]) {
P_ERROR("open, no memory for msg_array\n");
@@ -272,7 +271,6 @@ mon_alloc_mem(void)
kfree(monpriv->msg_array[j]);
return NULL;
}
- memset(monpriv->msg_array[i], 0, sizeof(struct mon_msg));
}
return monpriv;
}
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 1026f2bc318..eecb2afad5c 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -28,6 +28,7 @@
#include <linux/major.h>
#include <linux/kdev_t.h>
#include <linux/device.h>
+#include <linux/mutex.h>
struct class *class3270;
@@ -59,7 +60,7 @@ struct raw3270 {
#define RAW3270_FLAGS_CONSOLE 8 /* Device is the console. */
/* Semaphore to protect global data of raw3270 (devices, views, etc). */
-static DECLARE_MUTEX(raw3270_sem);
+static DEFINE_MUTEX(raw3270_mutex);
/* List of 3270 devices. */
static struct list_head raw3270_devices = LIST_HEAD_INIT(raw3270_devices);
@@ -115,10 +116,9 @@ raw3270_request_alloc(size_t size)
struct raw3270_request *rq;
/* Allocate request structure */
- rq = kmalloc(sizeof(struct raw3270_request), GFP_KERNEL | GFP_DMA);
+ rq = kzalloc(sizeof(struct raw3270_request), GFP_KERNEL | GFP_DMA);
if (!rq)
return ERR_PTR(-ENOMEM);
- memset(rq, 0, sizeof(struct raw3270_request));
/* alloc output buffer. */
if (size > 0) {
@@ -816,7 +816,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
* number for it. Note: there is no device with minor 0,
* see special case for fs3270.c:fs3270_open().
*/
- down(&raw3270_sem);
+ mutex_lock(&raw3270_mutex);
/* Keep the list sorted. */
minor = RAW3270_FIRSTMINOR;
rp->minor = -1;
@@ -833,7 +833,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
rp->minor = minor;
list_add_tail(&rp->list, &raw3270_devices);
}
- up(&raw3270_sem);
+ mutex_unlock(&raw3270_mutex);
/* No free minor number? Then give up. */
if (rp->minor == -1)
return -EUSERS;
@@ -1004,7 +1004,7 @@ raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor)
if (minor <= 0)
return -ENODEV;
- down(&raw3270_sem);
+ mutex_lock(&raw3270_mutex);
rc = -ENODEV;
list_for_each_entry(rp, &raw3270_devices, list) {
if (rp->minor != minor)
@@ -1025,7 +1025,7 @@ raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor)
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
break;
}
- up(&raw3270_sem);
+ mutex_unlock(&raw3270_mutex);
return rc;
}
@@ -1039,7 +1039,7 @@ raw3270_find_view(struct raw3270_fn *fn, int minor)
struct raw3270_view *view, *tmp;
unsigned long flags;
- down(&raw3270_sem);
+ mutex_lock(&raw3270_mutex);
view = ERR_PTR(-ENODEV);
list_for_each_entry(rp, &raw3270_devices, list) {
if (rp->minor != minor)
@@ -1058,7 +1058,7 @@ raw3270_find_view(struct raw3270_fn *fn, int minor)
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
break;
}
- up(&raw3270_sem);
+ mutex_unlock(&raw3270_mutex);
return view;
}
@@ -1105,7 +1105,7 @@ raw3270_delete_device(struct raw3270 *rp)
struct ccw_device *cdev;
/* Remove from device chain. */
- down(&raw3270_sem);
+ mutex_lock(&raw3270_mutex);
if (rp->clttydev)
class_device_destroy(class3270,
MKDEV(IBM_TTY3270_MAJOR, rp->minor));
@@ -1113,7 +1113,7 @@ raw3270_delete_device(struct raw3270 *rp)
class_device_destroy(class3270,
MKDEV(IBM_FS3270_MAJOR, rp->minor));
list_del_init(&rp->list);
- up(&raw3270_sem);
+ mutex_unlock(&raw3270_mutex);
/* Disconnect from ccw_device. */
cdev = rp->cdev;
@@ -1209,13 +1209,13 @@ int raw3270_register_notifier(void (*notifier)(int, int))
if (!np)
return -ENOMEM;
np->notifier = notifier;
- down(&raw3270_sem);
+ mutex_lock(&raw3270_mutex);
list_add_tail(&np->list, &raw3270_notifier);
list_for_each_entry(rp, &raw3270_devices, list) {
get_device(&rp->cdev->dev);
notifier(rp->minor, 1);
}
- up(&raw3270_sem);
+ mutex_unlock(&raw3270_mutex);
return 0;
}
@@ -1223,14 +1223,14 @@ void raw3270_unregister_notifier(void (*notifier)(int, int))
{
struct raw3270_notifier *np;
- down(&raw3270_sem);
+ mutex_lock(&raw3270_mutex);
list_for_each_entry(np, &raw3270_notifier, list)
if (np->notifier == notifier) {
list_del(&np->list);
kfree(np);
break;
}
- up(&raw3270_sem);
+ mutex_unlock(&raw3270_mutex);
}
/*
@@ -1257,10 +1257,10 @@ raw3270_set_online (struct ccw_device *cdev)
goto failure;
raw3270_create_attributes(rp);
set_bit(RAW3270_FLAGS_READY, &rp->flags);
- down(&raw3270_sem);
+ mutex_lock(&raw3270_mutex);
list_for_each_entry(np, &raw3270_notifier, list)
np->notifier(rp->minor, 1);
- up(&raw3270_sem);
+ mutex_unlock(&raw3270_mutex);
return 0;
failure:
@@ -1308,10 +1308,10 @@ raw3270_remove (struct ccw_device *cdev)
}
spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
- down(&raw3270_sem);
+ mutex_lock(&raw3270_mutex);
list_for_each_entry(np, &raw3270_notifier, list)
np->notifier(rp->minor, 0);
- up(&raw3270_sem);
+ mutex_unlock(&raw3270_mutex);
/* Reset 3270 device. */
raw3270_reset_device(rp);
@@ -1371,13 +1371,13 @@ raw3270_init(void)
rc = ccw_driver_register(&raw3270_ccw_driver);
if (rc == 0) {
/* Create attributes for early (= console) device. */
- down(&raw3270_sem);
+ mutex_lock(&raw3270_mutex);
class3270 = class_create(THIS_MODULE, "3270");
list_for_each_entry(rp, &raw3270_devices, list) {
get_device(&rp->cdev->dev);
raw3270_create_attributes(rp);
}
- up(&raw3270_sem);
+ mutex_unlock(&raw3270_mutex);
}
return rc;
}
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index 01d865d9379..cd51ace8b61 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -250,6 +250,7 @@ extern void tape_free_request(struct tape_request *);
extern int tape_do_io(struct tape_device *, struct tape_request *);
extern int tape_do_io_async(struct tape_device *, struct tape_request *);
extern int tape_do_io_interruptible(struct tape_device *, struct tape_request *);
+extern int tape_cancel_io(struct tape_device *, struct tape_request *);
void tape_hotplug_event(struct tape_device *, int major, int action);
static inline int
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c
index 682039cac15..d4f2da73807 100644
--- a/drivers/s390/char/tape_34xx.c
+++ b/drivers/s390/char/tape_34xx.c
@@ -2,8 +2,7 @@
* drivers/s390/char/tape_34xx.c
* tape device discipline for 3480/3490 tapes.
*
- * S390 and zSeries version
- * Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright (C) IBM Corp. 2001,2006
* Author(s): Carsten Otte <cotte@de.ibm.com>
* Tuan Ngo-Anh <ngoanh@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -28,11 +27,6 @@
debug_info_t *TAPE_DBF_AREA = NULL;
EXPORT_SYMBOL(TAPE_DBF_AREA);
-enum tape_34xx_type {
- tape_3480,
- tape_3490,
-};
-
#define TAPE34XX_FMT_3480 0
#define TAPE34XX_FMT_3480_2_XF 1
#define TAPE34XX_FMT_3480_XF 2
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
new file mode 100644
index 00000000000..c3915f60a3a
--- /dev/null
+++ b/drivers/s390/char/tape_3590.c
@@ -0,0 +1,1301 @@
+/*
+ * drivers/s390/char/tape_3590.c
+ * tape device discipline for 3590 tapes.
+ *
+ * Copyright (C) IBM Corp. 2001,2006
+ * Author(s): Stefan Bader <shbader@de.ibm.com>
+ * Michael Holzheu <holzheu@de.ibm.com>
+ * Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bio.h>
+
+#define TAPE_DBF_AREA tape_3590_dbf
+
+#include "tape.h"
+#include "tape_std.h"
+#include "tape_3590.h"
+
+/*
+ * Pointer to debug area.
+ */
+debug_info_t *TAPE_DBF_AREA = NULL;
+EXPORT_SYMBOL(TAPE_DBF_AREA);
+
+/*******************************************************************
+ * Error Recovery fuctions:
+ * - Read Opposite: implemented
+ * - Read Device (buffered) log: BRA
+ * - Read Library log: BRA
+ * - Swap Devices: BRA
+ * - Long Busy: BRA
+ * - Special Intercept: BRA
+ * - Read Alternate: implemented
+ *******************************************************************/
+
+#define PRINTK_HEADER "TAPE_3590: "
+
+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",
+};
+
+/*
+ * 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);
+ }
+ 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);
+}
+
+/*
+ * 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 Opposite Error Recovery Function:
+ * Used, when Read Forward does not work
+ */
+static void
+tape_3590_read_opposite(struct tape_device *device,
+ struct tape_request *request)
+{
+ struct tape_3590_disc_data *data;
+
+ /*
+ * We have allocated 4 ccws in tape_std_read, so we can now
+ * transform the request to a read backward, followed by a
+ * forward space block.
+ */
+ request->op = TO_RBA;
+ tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
+ data = device->discdata;
+ tape_ccw_cc_idal(request->cpaddr + 1, data->read_back_op,
+ device->char_data.idal_buf);
+ tape_ccw_cc(request->cpaddr + 2, FORSPACEBLOCK, 0, NULL);
+ tape_ccw_end(request->cpaddr + 3, NOP, 0, NULL);
+ DBF_EVENT(6, "xrop ccwg\n");
+}
+
+/*
+ * 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 int
+tape_3590_read_attmsg(struct tape_device *device)
+{
+ struct tape_request *request;
+ char *buf;
+
+ request = tape_alloc_request(3, 4096);
+ if (IS_ERR(request))
+ return PTR_ERR(request);
+ 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);
+ return tape_do_io_free(device, request);
+}
+
+/*
+ * These functions are used to schedule follow-up actions from within an
+ * interrupt context (like unsolicited interrupts).
+ */
+static void
+tape_3590_work_handler(void *data)
+{
+ struct {
+ struct tape_device *device;
+ enum tape_op op;
+ struct work_struct work;
+ } *p = data;
+
+ switch (p->op) {
+ case TO_MSEN:
+ tape_3590_sense_medium(p->device);
+ break;
+ case TO_READ_ATTMSG:
+ tape_3590_read_attmsg(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 {
+ struct tape_device *device;
+ enum tape_op op;
+ struct work_struct work;
+ } *p;
+
+ if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL)
+ return -ENOMEM;
+
+ INIT_WORK(&p->work, tape_3590_work_handler, p);
+
+ p->device = tape_get_device_reference(device);
+ p->op = op;
+
+ schedule_work(&p->work);
+ return 0;
+}
+
+#ifdef CONFIG_S390_TAPE_BLOCK
+/*
+ * Tape Block READ
+ */
+static struct tape_request *
+tape_3590_bread(struct tape_device *device, struct request *req)
+{
+ struct tape_request *request;
+ struct ccw1 *ccw;
+ int count = 0, start_block, i;
+ unsigned off;
+ char *dst;
+ struct bio_vec *bv;
+ struct bio *bio;
+
+ DBF_EVENT(6, "xBREDid:");
+ start_block = req->sector >> TAPEBLOCK_HSEC_S2B;
+ DBF_EVENT(6, "start_block = %i\n", start_block);
+
+ rq_for_each_bio(bio, req) {
+ bio_for_each_segment(bv, bio, i) {
+ count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9);
+ }
+ }
+ request = tape_alloc_request(2 + count + 1, 4);
+ if (IS_ERR(request))
+ return request;
+ request->op = TO_BLOCK;
+ *(__u32 *) request->cpdata = start_block;
+ ccw = request->cpaddr;
+ ccw = tape_ccw_cc(ccw, MODE_SET_DB, 1, device->modeset_byte);
+
+ /*
+ * We always setup a nop after the mode set ccw. This slot is
+ * used in tape_std_check_locate to insert a locate ccw if the
+ * current tape position doesn't match the start block to be read.
+ */
+ ccw = tape_ccw_cc(ccw, NOP, 0, NULL);
+
+ rq_for_each_bio(bio, req) {
+ bio_for_each_segment(bv, bio, i) {
+ dst = kmap(bv->bv_page) + bv->bv_offset;
+ for (off = 0; off < bv->bv_len;
+ off += TAPEBLOCK_HSEC_SIZE) {
+ ccw->flags = CCW_FLAG_CC;
+ ccw->cmd_code = READ_FORWARD;
+ ccw->count = TAPEBLOCK_HSEC_SIZE;
+ set_normalized_cda(ccw, (void *) __pa(dst));
+ ccw++;
+ dst += TAPEBLOCK_HSEC_SIZE;
+ }
+ if (off > bv->bv_len)
+ BUG();
+ }
+ }
+ ccw = tape_ccw_end(ccw, NOP, 0, NULL);
+ DBF_EVENT(6, "xBREDccwg\n");
+ return request;
+}
+
+static void
+tape_3590_free_bread(struct tape_request *request)
+{
+ struct ccw1 *ccw;
+
+ /* Last ccw is a nop and doesn't need clear_normalized_cda */
+ for (ccw = request->cpaddr; ccw->flags & CCW_FLAG_CC; ccw++)
+ if (ccw->cmd_code == READ_FORWARD)
+ clear_normalized_cda(ccw);
+ tape_free_request(request);
+}
+
+/*
+ * check_locate is called just before the tape request is passed to
+ * the common io layer for execution. It has to check the current
+ * tape position and insert a locate ccw if it doesn't match the
+ * start block for the request.
+ */
+static void
+tape_3590_check_locate(struct tape_device *device, struct tape_request *request)
+{
+ __u32 *start_block;
+
+ start_block = (__u32 *) request->cpdata;
+ if (*start_block != device->blk_data.block_position) {
+ /* Add the start offset of the file to get the real block. */
+ *start_block += device->bof;
+ tape_ccw_cc(request->cpaddr + 1, LOCATE, 4, request->cpdata);
+ }
+}
+#endif
+
+/*
+ * 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)
+{
+ struct tape_3590_med_sense *sense;
+
+ 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);
+ break;
+ case TO_MSEN:
+ sense = (struct tape_3590_med_sense *) request->cpdata;
+ if (sense->masst == MSENSE_UNASSOCIATED)
+ tape_med_state_set(device, MS_UNLOADED);
+ if (sense->masst == MSENSE_ASSOCIATED_MOUNT)
+ tape_med_state_set(device, MS_LOADED);
+ 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:
+ break;
+ case TO_SIZE:
+ break;
+ }
+ return TAPE_IO_SUCCESS;
+}
+
+/*
+ * This fuction is called, when error recovery was successfull
+ */
+static inline int
+tape_3590_erp_succeded(struct tape_device *device, struct tape_request *request)
+{
+ DBF_EVENT(3, "Error Recovery successfull for %s\n",
+ tape_op_verbose[request->op]);
+ return tape_3590_done(device, request);
+}
+
+/*
+ * This fuction is called, when error recovery was not successfull
+ */
+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.dstat == DEV_STAT_CHN_END)
+ /* Probably result of halt ssch */
+ return TAPE_IO_PENDING;
+ else if (irb->scsw.dstat == 0x85)
+ /* Device Ready -> check medium state */
+ tape_3590_schedule_work(device, TO_MSEN);
+ else if (irb->scsw.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);
+ PRINT_WARN("Unsolicited IRQ (Device End) caught.\n");
+ tape_dump_sense(device, NULL, irb);
+ }
+ 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_succeded(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:
+ PRINT_ERR("Unknown BRA %x - This should not happen!\n",
+ sense->bra);
+ 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!
+ */
+ PRINT_WARN("(%s): Swap Tape Device!\n", device->cdev->dev.bus_id);
+ 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)
+{
+ /* FIXME: how about WAITING for a minute ? */
+ PRINT_WARN("(%s): Device is busy! Please wait a minute!\n",
+ device->cdev->dev.bus_id);
+ return tape_3590_erp_basic(device, request, irb, -EBUSY);
+}
+
+/*
+ * 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);
+}
+
+/*
+ * RDA: Read Alternate
+ */
+static int
+tape_3590_erp_read_alternate(struct tape_device *device,
+ struct tape_request *request, struct irb *irb)
+{
+ struct tape_3590_disc_data *data;
+
+ /*
+ * The issued Read Backward or Read Previous command is not
+ * supported by the device
+ * The recovery action should be to issue another command:
+ * Read Revious: if Read Backward is not supported
+ * Read Backward: if Read Previous is not supported
+ */
+ data = device->discdata;
+ if (data->read_back_op == READ_PREVIOUS) {
+ DBF_EVENT(2, "(%08x): No support for READ_PREVIOUS command\n",
+ device->cdev_id);
+ data->read_back_op = READ_BACKWARD;
+ } else {
+ DBF_EVENT(2, "(%08x): No support for READ_BACKWARD command\n",
+ device->cdev_id);
+ data->read_back_op = READ_PREVIOUS;
+ }
+ tape_3590_read_opposite(device, request);
+ return tape_3590_erp_retry(device, request, irb);
+}
+
+/*
+ * Error Recovery read opposite
+ */
+static int
+tape_3590_erp_read_opposite(struct tape_device *device,
+ struct tape_request *request, struct irb *irb)
+{
+ switch (request->op) {
+ case TO_RFO:
+ /*
+ * We did read forward, but the data could not be read.
+ * We will read backward and then skip forward again.
+ */
+ tape_3590_read_opposite(device, request);
+ return tape_3590_erp_retry(device, request, irb);
+ case TO_RBA:
+ /* We tried to read forward and backward, but hat no success */
+ return tape_3590_erp_failed(device, request, irb, -EIO);
+ break;
+ default:
+ PRINT_WARN("read_opposite_recovery_called_with_op: %s\n",
+ tape_op_verbose[request->op]);
+ return tape_3590_erp_failed(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;
+
+ sense = (struct tape_3590_sense *) irb->ecw;
+ /* Exception Message */
+ switch (sense->fmt.f70.emc) {
+ case 0x02:
+ PRINT_WARN("(%s): Data degraded\n", device->cdev->dev.bus_id);
+ break;
+ case 0x03:
+ PRINT_WARN("(%s): Data degraded in partion %i\n",
+ device->cdev->dev.bus_id, sense->fmt.f70.mp);
+ break;
+ case 0x04:
+ PRINT_WARN("(%s): Medium degraded\n", device->cdev->dev.bus_id);
+ break;
+ case 0x05:
+ PRINT_WARN("(%s): Medium degraded in partition %i\n",
+ device->cdev->dev.bus_id, sense->fmt.f70.mp);
+ break;
+ case 0x06:
+ PRINT_WARN("(%s): Block 0 Error\n", device->cdev->dev.bus_id);
+ break;
+ case 0x07:
+ PRINT_WARN("(%s): Medium Exception 0x%02x\n",
+ device->cdev->dev.bus_id, sense->fmt.f70.md);
+ break;
+ default:
+ PRINT_WARN("(%s): MIM ExMsg: 0x%02x\n",
+ device->cdev->dev.bus_id, sense->fmt.f70.emc);
+ break;
+ }
+ /* Service Message */
+ switch (sense->fmt.f70.smc) {
+ case 0x02:
+ PRINT_WARN("(%s): Reference Media maintenance procedure %i\n",
+ device->cdev->dev.bus_id, sense->fmt.f70.md);
+ break;
+ default:
+ PRINT_WARN("(%s): MIM ServiceMsg: 0x%02x\n",
+ device->cdev->dev.bus_id, sense->fmt.f70.smc);
+ break;
+ }
+}
+
+/*
+ * 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;
+
+ sense = (struct tape_3590_sense *) irb->ecw;
+ /* Exception Message */
+ switch (sense->fmt.f71.emc) {
+ case 0x01:
+ PRINT_WARN("(%s): Effect of failure is unknown\n",
+ device->cdev->dev.bus_id);
+ break;
+ case 0x02:
+ PRINT_WARN("(%s): CU Exception - no performance impact\n",
+ device->cdev->dev.bus_id);
+ break;
+ case 0x03:
+ PRINT_WARN("(%s): CU Exception on channel interface 0x%02x\n",
+ device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+ break;
+ case 0x04:
+ PRINT_WARN("(%s): CU Exception on device path 0x%02x\n",
+ device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+ break;
+ case 0x05:
+ PRINT_WARN("(%s): CU Exception on library path 0x%02x\n",
+ device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+ break;
+ case 0x06:
+ PRINT_WARN("(%s): CU Exception on node 0x%02x\n",
+ device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+ break;
+ case 0x07:
+ PRINT_WARN("(%s): CU Exception on partition 0x%02x\n",
+ device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+ break;
+ default:
+ PRINT_WARN("(%s): SIM ExMsg: 0x%02x\n",
+ device->cdev->dev.bus_id, sense->fmt.f71.emc);
+ }
+ /* Service Message */
+ switch (sense->fmt.f71.smc) {
+ case 0x01:
+ PRINT_WARN("(%s): Repair impact is unknown\n",
+ device->cdev->dev.bus_id);
+ break;
+ case 0x02:
+ PRINT_WARN("(%s): Repair will not impact cu performance\n",
+ device->cdev->dev.bus_id);
+ break;
+ case 0x03:
+ if (sense->fmt.f71.mdf == 0)
+ PRINT_WARN("(%s): Repair will disable node "
+ "0x%x on CU\n",
+ device->cdev->dev.bus_id,
+ sense->fmt.f71.md[1]);
+ else
+ PRINT_WARN("(%s): Repair will disable nodes "
+ "(0x%x-0x%x) on CU\n",
+ device->cdev->dev.bus_id,
+ sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
+ break;
+ case 0x04:
+ if (sense->fmt.f71.mdf == 0)
+ PRINT_WARN("(%s): Repair will disable cannel path "
+ "0x%x on CU\n",
+ device->cdev->dev.bus_id,
+ sense->fmt.f71.md[1]);
+ else
+ PRINT_WARN("(%s): Repair will disable cannel paths "
+ "(0x%x-0x%x) on CU\n",
+ device->cdev->dev.bus_id,
+ sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
+ break;
+ case 0x05:
+ if (sense->fmt.f71.mdf == 0)
+ PRINT_WARN("(%s): Repair will disable device path "
+ "0x%x on CU\n",
+ device->cdev->dev.bus_id,
+ sense->fmt.f71.md[1]);
+ else
+ PRINT_WARN("(%s): Repair will disable device paths "
+ "(0x%x-0x%x) on CU\n",
+ device->cdev->dev.bus_id,
+ sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
+ break;
+ case 0x06:
+ if (sense->fmt.f71.mdf == 0)
+ PRINT_WARN("(%s): Repair will disable library path "
+ "0x%x on CU\n",
+ device->cdev->dev.bus_id,
+ sense->fmt.f71.md[1]);
+ else
+ PRINT_WARN("(%s): Repair will disable library paths "
+ "(0x%x-0x%x) on CU\n",
+ device->cdev->dev.bus_id,
+ sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
+ break;
+ case 0x07:
+ PRINT_WARN("(%s): Repair will disable access to CU\n",
+ device->cdev->dev.bus_id);
+ break;
+ default:
+ PRINT_WARN("(%s): SIM ServiceMsg: 0x%02x\n",
+ device->cdev->dev.bus_id, sense->fmt.f71.smc);
+ }
+}
+
+/*
+ * 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;
+
+ sense = (struct tape_3590_sense *) irb->ecw;
+ /* Exception Message */
+ switch (sense->fmt.f71.emc) {
+ case 0x01:
+ PRINT_WARN("(%s): Effect of failure is unknown\n",
+ device->cdev->dev.bus_id);
+ break;
+ case 0x02:
+ PRINT_WARN("(%s): DV Exception - no performance impact\n",
+ device->cdev->dev.bus_id);
+ break;
+ case 0x03:
+ PRINT_WARN("(%s): DV Exception on channel interface 0x%02x\n",
+ device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+ break;
+ case 0x04:
+ PRINT_WARN("(%s): DV Exception on loader 0x%02x\n",
+ device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+ break;
+ case 0x05:
+ PRINT_WARN("(%s): DV Exception on message display 0x%02x\n",
+ device->cdev->dev.bus_id, sense->fmt.f71.md[0]);
+ break;
+ case 0x06:
+ PRINT_WARN("(%s): DV Exception in tape path\n",
+ device->cdev->dev.bus_id);
+ break;
+ case 0x07:
+ PRINT_WARN("(%s): DV Exception in drive\n",
+ device->cdev->dev.bus_id);
+ break;
+ default:
+ PRINT_WARN("(%s): DSIM ExMsg: 0x%02x\n",
+ device->cdev->dev.bus_id, sense->fmt.f71.emc);
+ }
+ /* Service Message */
+ switch (sense->fmt.f71.smc) {
+ case 0x01:
+ PRINT_WARN("(%s): Repair impact is unknown\n",
+ device->cdev->dev.bus_id);
+ break;
+ case 0x02:
+ PRINT_WARN("(%s): Repair will not impact device performance\n",
+ device->cdev->dev.bus_id);
+ break;
+ case 0x03:
+ if (sense->fmt.f71.mdf == 0)
+ PRINT_WARN("(%s): Repair will disable channel path "
+ "0x%x on DV\n",
+ device->cdev->dev.bus_id,
+ sense->fmt.f71.md[1]);
+ else
+ PRINT_WARN("(%s): Repair will disable channel path "
+ "(0x%x-0x%x) on DV\n",
+ device->cdev->dev.bus_id,
+ sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
+ break;
+ case 0x04:
+ if (sense->fmt.f71.mdf == 0)
+ PRINT_WARN("(%s): Repair will disable interface 0x%x "
+ "on DV\n",
+ device->cdev->dev.bus_id,
+ sense->fmt.f71.md[1]);
+ else
+ PRINT_WARN("(%s): Repair will disable interfaces "
+ "(0x%x-0x%x) on DV\n",
+ device->cdev->dev.bus_id,
+ sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
+ break;
+ case 0x05:
+ if (sense->fmt.f71.mdf == 0)
+ PRINT_WARN("(%s): Repair will disable loader 0x%x "
+ "on DV\n",
+ device->cdev->dev.bus_id,
+ sense->fmt.f71.md[1]);
+ else
+ PRINT_WARN("(%s): Repair will disable loader "
+ "(0x%x-0x%x) on DV\n",
+ device->cdev->dev.bus_id,
+ sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
+ break;
+ case 0x07:
+ PRINT_WARN("(%s): Repair will disable access to DV\n",
+ device->cdev->dev.bus_id);
+ break;
+ case 0x08:
+ if (sense->fmt.f71.mdf == 0)
+ PRINT_WARN("(%s): Repair will disable message "
+ "display 0x%x on DV\n",
+ device->cdev->dev.bus_id,
+ sense->fmt.f71.md[1]);
+ else
+ PRINT_WARN("(%s): Repair will disable message "
+ "displays (0x%x-0x%x) on DV\n",
+ device->cdev->dev.bus_id,
+ sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
+ break;
+ case 0x09:
+ PRINT_WARN("(%s): Clean DV\n", device->cdev->dev.bus_id);
+ break;
+ default:
+ PRINT_WARN("(%s): DSIM ServiceMsg: 0x%02x\n",
+ device->cdev->dev.bus_id, sense->fmt.f71.smc);
+ }
+}
+
+/*
+ * 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)
+ PRINT_WARN("(%s): %s\n", device->cdev->dev.bus_id,
+ tape_3590_msg[sense->mc]);
+ else {
+ PRINT_WARN("(%s): Message Code 0x%x\n",
+ device->cdev->dev.bus_id, sense->mc);
+ }
+ return;
+ }
+ if (sense->mc == 0xf0) {
+ /* Standard Media Information Message */
+ PRINT_WARN("(%s): MIM SEV=%i, MC=%02x, ES=%x/%x, "
+ "RC=%02x-%04x-%02x\n", device->cdev->dev.bus_id,
+ 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 */
+ PRINT_WARN("(%s): IOSIM SEV=%i, DEVTYPE=3590/%02x, "
+ "MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n",
+ device->cdev->dev.bus_id, 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 */
+ PRINT_WARN("(%s): DEVSIM SEV=%i, DEVTYPE=3590/%02x, "
+ "MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n",
+ device->cdev->dev.bus_id, 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;
+ }
+ PRINT_WARN("(%s): Device Message(%x)\n",
+ device->cdev->dev.bus_id, sense->mc);
+}
+
+/*
+ * 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;
+ int rc;
+
+#ifdef CONFIG_S390_TAPE_BLOCK
+ if (request->op == TO_BLOCK) {
+ /*
+ * Recovery for block device requests. Set the block_position
+ * to something invalid and retry.
+ */
+ device->blk_data.block_position = -1;
+ if (request->retries-- <= 0)
+ return tape_3590_erp_failed(device, request, irb, -EIO);
+ else
+ return tape_3590_erp_retry(device, request, irb);
+ }
+#endif
+
+ sense = (struct tape_3590_sense *) irb->ecw;
+
+ /*
+ * 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
+ */
+ rc = -EIO;
+ switch (sense->rc_rqc) {
+
+ case 0x1110:
+ tape_3590_print_era_msg(device, irb);
+ return tape_3590_erp_read_buf_log(device, request, irb);
+
+ case 0x2011:
+ tape_3590_print_era_msg(device, irb);
+ return tape_3590_erp_read_alternate(device, request, irb);
+
+ case 0x2230:
+ case 0x2231:
+ tape_3590_print_era_msg(device, irb);
+ return tape_3590_erp_special_interrupt(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);
+ return tape_3590_erp_basic(device, request, irb, 0);
+
+ case 0x4010:
+ /*
+ * print additional msg since default msg
+ * "device intervention" is not very meaningfull
+ */
+ PRINT_WARN("(%s): Tape operation when medium not loaded\n",
+ device->cdev->dev.bus_id);
+ tape_med_state_set(device, MS_UNLOADED);
+ return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);
+ case 0x4012: /* Device Long Busy */
+ tape_3590_print_era_msg(device, irb);
+ 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);
+ }
+ if (sense->rac == 0x26) {
+ /* Read Opposite */
+ tape_3590_print_era_msg(device, irb);
+ return tape_3590_erp_read_opposite(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);
+ return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);
+
+ case 0x6020:
+ PRINT_WARN("(%s): Cartridge of wrong type ?\n",
+ device->cdev->dev.bus_id);
+ return tape_3590_erp_basic(device, request, irb, -EMEDIUMTYPE);
+
+ case 0x8011:
+ PRINT_WARN("(%s): Another host has reserved the tape device\n",
+ device->cdev->dev.bus_id);
+ return tape_3590_erp_basic(device, request, irb, -EPERM);
+ case 0x8013:
+ PRINT_WARN("(%s): Another host has priviliged access to the "
+ "tape device\n", device->cdev->dev.bus_id);
+ PRINT_WARN("(%s): To solve the problem unload the current "
+ "cartridge!\n", device->cdev->dev.bus_id);
+ 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.dstat & DEV_STAT_UNIT_EXCEP) &&
+ (irb->scsw.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.dstat & DEV_STAT_UNIT_CHECK)
+ return tape_3590_unit_check(device, request, irb);
+
+ if (irb->scsw.dstat & DEV_STAT_DEV_END) {
+ if (irb->scsw.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.dstat & DEV_STAT_CHN_END) {
+ DBF_EVENT(2, "cannel end\n");
+ return TAPE_IO_PENDING;
+ }
+
+ if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
+ DBF_EVENT(2, "Unit Attention when busy..\n");
+ return TAPE_IO_PENDING;
+ }
+
+ DBF_EVENT(6, "xunknownirq\n");
+ PRINT_ERR("Unexpected interrupt.\n");
+ PRINT_ERR("Current op is: %s", tape_op_verbose[request->op]);
+ tape_dump_sense(device, request, irb);
+ return TAPE_IO_STOP;
+}
+
+/*
+ * Setup device function
+ */
+static int
+tape_3590_setup_device(struct tape_device *device)
+{
+ int rc;
+ struct tape_3590_disc_data *data;
+
+ DBF_EVENT(6, "3590 device setup\n");
+ data = kmalloc(sizeof(struct tape_3590_disc_data),
+ GFP_KERNEL | GFP_DMA);
+ if (data == NULL)
+ return -ENOMEM;
+ data->read_back_op = READ_PREVIOUS;
+ device->discdata = data;
+
+ if ((rc = tape_std_assign(device)) == 0) {
+ /* Try to find out if medium is loaded */
+ if ((rc = tape_3590_sense_medium(device)) != 0)
+ DBF_LH(3, "3590 medium sense returned %d\n", rc);
+ }
+
+ return rc;
+}
+
+/*
+ * Cleanup device function
+ */
+static void
+tape_3590_cleanup_device(struct tape_device *device)
+{
+ 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,
+#ifdef CONFIG_S390_TAPE_BLOCK
+ .bread = tape_3590_bread,
+ .free_bread = tape_3590_free_bread,
+ .check_locate = tape_3590_check_locate,
+#endif
+ .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},
+ { /* end of list */ }
+};
+
+static int
+tape_3590_online(struct ccw_device *cdev)
+{
+ return tape_generic_online(cdev->dev.driver_data,
+ &tape_discipline_3590);
+}
+
+static int
+tape_3590_offline(struct ccw_device *cdev)
+{
+ return tape_generic_offline(cdev->dev.driver_data);
+}
+
+static struct ccw_driver tape_3590_driver = {
+ .name = "tape_3590",
+ .owner = THIS_MODULE,
+ .ids = tape_3590_ids,
+ .probe = tape_generic_probe,
+ .remove = tape_generic_remove,
+ .set_offline = tape_3590_offline,
+ .set_online = tape_3590_online,
+};
+
+/*
+ * 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");
+ /* Register driver for 3590 tapes. */
+ rc = ccw_driver_register(&tape_3590_driver);
+ if (rc)
+ 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);
+
+ 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
new file mode 100644
index 00000000000..cf274b9445a
--- /dev/null
+++ b/drivers/s390/char/tape_3590.h
@@ -0,0 +1,124 @@
+/*
+ * drivers/s390/char/tape_3590.h
+ * tape device discipline for 3590 tapes.
+ *
+ * Copyright (C) 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 TAPE_3590_MAX_MSG 0xb0
+
+/* Datatypes */
+
+struct tape_3590_disc_data {
+ unsigned char modeset_byte;
+ int 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 pad[127];
+} __attribute__ ((packed));
+
+#endif /* _TAPE_3590_H */
diff --git a/drivers/s390/char/tape_class.c b/drivers/s390/char/tape_class.c
index b3569c82bb1..a5c68e60fcf 100644
--- a/drivers/s390/char/tape_class.c
+++ b/drivers/s390/char/tape_class.c
@@ -44,11 +44,10 @@ struct tape_class_device *register_tape_dev(
int rc;
char * s;
- tcd = kmalloc(sizeof(struct tape_class_device), GFP_KERNEL);
+ tcd = kzalloc(sizeof(struct tape_class_device), GFP_KERNEL);
if (!tcd)
return ERR_PTR(-ENOMEM);
- memset(tcd, 0, sizeof(struct tape_class_device));
strncpy(tcd->device_name, device_name, TAPECLASS_NAME_LEN);
for (s = strchr(tcd->device_name, '/'); s; s = strchr(s, '/'))
*s = '!';
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index 4ea438c749c..389ee2c0f44 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -453,16 +453,14 @@ tape_alloc_device(void)
{
struct tape_device *device;
- device = (struct tape_device *)
- kmalloc(sizeof(struct tape_device), GFP_KERNEL);
+ device = kzalloc(sizeof(struct tape_device), GFP_KERNEL);
if (device == NULL) {
DBF_EXCEPTION(2, "ti:no mem\n");
PRINT_INFO ("can't allocate memory for "
"tape info structure\n");
return ERR_PTR(-ENOMEM);
}
- memset(device, 0, sizeof(struct tape_device));
- device->modeset_byte = (char *) kmalloc(1, GFP_KERNEL | GFP_DMA);
+ device->modeset_byte = kmalloc(1, GFP_KERNEL | GFP_DMA);
if (device->modeset_byte == NULL) {
DBF_EXCEPTION(2, "ti:no mem\n");
PRINT_INFO("can't allocate memory for modeset byte\n");
@@ -659,34 +657,30 @@ tape_alloc_request(int cplength, int datasize)
DBF_LH(6, "tape_alloc_request(%d, %d)\n", cplength, datasize);
- request = (struct tape_request *) kmalloc(sizeof(struct tape_request),
- GFP_KERNEL);
+ request = kzalloc(sizeof(struct tape_request), GFP_KERNEL);
if (request == NULL) {
DBF_EXCEPTION(1, "cqra nomem\n");
return ERR_PTR(-ENOMEM);
}
- memset(request, 0, sizeof(struct tape_request));
/* allocate channel program */
if (cplength > 0) {
- request->cpaddr = kmalloc(cplength*sizeof(struct ccw1),
+ request->cpaddr = kcalloc(cplength, sizeof(struct ccw1),
GFP_ATOMIC | GFP_DMA);
if (request->cpaddr == NULL) {
DBF_EXCEPTION(1, "cqra nomem\n");
kfree(request);
return ERR_PTR(-ENOMEM);
}
- memset(request->cpaddr, 0, cplength*sizeof(struct ccw1));
}
/* alloc small kernel buffer */
if (datasize > 0) {
- request->cpdata = kmalloc(datasize, GFP_KERNEL | GFP_DMA);
+ request->cpdata = kzalloc(datasize, GFP_KERNEL | GFP_DMA);
if (request->cpdata == NULL) {
DBF_EXCEPTION(1, "cqra nomem\n");
kfree(request->cpaddr);
kfree(request);
return ERR_PTR(-ENOMEM);
}
- memset(request->cpdata, 0, datasize);
}
DBF_LH(6, "New request %p(%p/%p)\n", request, request->cpaddr,
request->cpdata);
@@ -761,6 +755,13 @@ __tape_start_next_request(struct tape_device *device)
*/
if (request->status == TAPE_REQUEST_IN_IO)
return;
+ /*
+ * Request has already been stopped. We have to wait until
+ * the request is removed from the queue in the interrupt
+ * handling.
+ */
+ if (request->status == TAPE_REQUEST_DONE)
+ return;
/*
* We wanted to cancel the request but the common I/O layer
@@ -1015,7 +1016,7 @@ tape_do_io_interruptible(struct tape_device *device,
wq,
(request->callback == NULL)
);
- } while (rc != -ERESTARTSYS);
+ } while (rc == -ERESTARTSYS);
DBF_EVENT(3, "IO stopped on %08x\n", device->cdev_id);
rc = -ERESTARTSYS;
@@ -1024,6 +1025,20 @@ tape_do_io_interruptible(struct tape_device *device,
}
/*
+ * Stop running ccw.
+ */
+int
+tape_cancel_io(struct tape_device *device, struct tape_request *request)
+{
+ int rc;
+
+ spin_lock_irq(get_ccwdev_lock(device->cdev));
+ rc = __tape_cancel_io(device, request);
+ spin_unlock_irq(get_ccwdev_lock(device->cdev));
+ return rc;
+}
+
+/*
* Tape interrupt routine, called from the ccw_device layer
*/
static void
@@ -1064,15 +1079,16 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
/*
* If the condition code is not zero and the start function bit is
* still set, this is an deferred error and the last start I/O did
- * not succeed. Restart the request now.
+ * not succeed. At this point the condition that caused the deferred
+ * error might still apply. So we just schedule the request to be
+ * started later.
*/
- if (irb->scsw.cc != 0 && (irb->scsw.fctl & SCSW_FCTL_START_FUNC)) {
- PRINT_WARN("(%s): deferred cc=%i. restaring\n",
- cdev->dev.bus_id,
- irb->scsw.cc);
- rc = __tape_start_io(device, request);
- if (rc)
- __tape_end_request(device, request, rc);
+ if (irb->scsw.cc != 0 && (irb->scsw.fctl & SCSW_FCTL_START_FUNC) &&
+ (request->status == TAPE_REQUEST_IN_IO)) {
+ DBF_EVENT(3,"(%08x): deferred cc=%i, fctl=%i. restarting\n",
+ device->cdev_id, irb->scsw.cc, irb->scsw.fctl);
+ request->status = TAPE_REQUEST_QUEUED;
+ schedule_delayed_work(&device->tape_dnr, HZ);
return;
}
@@ -1286,4 +1302,5 @@ EXPORT_SYMBOL(tape_dump_sense_dbf);
EXPORT_SYMBOL(tape_do_io);
EXPORT_SYMBOL(tape_do_io_async);
EXPORT_SYMBOL(tape_do_io_interruptible);
+EXPORT_SYMBOL(tape_cancel_io);
EXPORT_SYMBOL(tape_mtop);
diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c
index 2f9fe30989a..99cf881f41d 100644
--- a/drivers/s390/char/tape_std.c
+++ b/drivers/s390/char/tape_std.c
@@ -37,20 +37,19 @@ tape_std_assign_timeout(unsigned long data)
{
struct tape_request * request;
struct tape_device * device;
+ int rc;
request = (struct tape_request *) data;
if ((device = request->device) == NULL)
BUG();
- spin_lock_irq(get_ccwdev_lock(device->cdev));
- if (request->callback != NULL) {
- DBF_EVENT(3, "%08x: Assignment timeout. Device busy.\n",
+ DBF_EVENT(3, "%08x: Assignment timeout. Device busy.\n",
device->cdev_id);
- PRINT_ERR("%s: Assignment timeout. Device busy.\n",
- device->cdev->dev.bus_id);
- ccw_device_clear(device->cdev, (long) request);
- }
- spin_unlock_irq(get_ccwdev_lock(device->cdev));
+ rc = tape_cancel_io(device, request);
+ if(rc)
+ PRINT_ERR("(%s): Assign timeout: Cancel failed with rc = %i\n",
+ device->cdev->dev.bus_id, rc);
+
}
int
diff --git a/drivers/s390/char/tape_std.h b/drivers/s390/char/tape_std.h
index 3ab6aafb734..2d311798edf 100644
--- a/drivers/s390/char/tape_std.h
+++ b/drivers/s390/char/tape_std.h
@@ -1,9 +1,8 @@
/*
- * drivers/s390/char/tape_34xx.h
+ * drivers/s390/char/tape_std.h
* standard tape device functions for ibm tapes.
*
- * S390 and zSeries version
- * Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright (C) IBM Corp. 2001,2006
* Author(s): Carsten Otte <cotte@de.ibm.com>
* Tuan Ngo-Anh <ngoanh@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -149,4 +148,11 @@ void tape_std_error_recovery_do_retry(struct tape_device *);
void tape_std_error_recovery_read_opposite(struct tape_device *);
void tape_std_error_recovery_HWBUG(struct tape_device *, int condno);
+/* S390 tape types */
+enum s390_tape_type {
+ tape_3480,
+ tape_3490,
+ tape_3590,
+};
+
#endif // _TAPE_STD_H
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 4b906937038..9a141776873 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -691,10 +691,9 @@ tty3270_alloc_view(void)
struct tty3270 *tp;
int pages;
- tp = kmalloc(sizeof(struct tty3270),GFP_KERNEL);
+ tp = kzalloc(sizeof(struct tty3270), GFP_KERNEL);
if (!tp)
goto out_err;
- memset(tp, 0, sizeof(struct tty3270));
tp->freemem_pages =
kmalloc(sizeof(void *) * TTY3270_STRING_PAGES, GFP_KERNEL);
if (!tp->freemem_pages)
@@ -767,16 +766,14 @@ tty3270_alloc_screen(struct tty3270 *tp)
int lines;
size = sizeof(struct tty3270_line) * (tp->view.rows - 2);
- tp->screen = kmalloc(size, GFP_KERNEL);
+ tp->screen = kzalloc(size, GFP_KERNEL);
if (!tp->screen)
goto out_err;
- memset(tp->screen, 0, size);
for (lines = 0; lines < tp->view.rows - 2; lines++) {
size = sizeof(struct tty3270_cell) * tp->view.cols;
- tp->screen[lines].cells = kmalloc(size, GFP_KERNEL);
+ tp->screen[lines].cells = kzalloc(size, GFP_KERNEL);
if (!tp->screen[lines].cells)
goto out_screen;
- memset(tp->screen[lines].cells, 0, size);
}
return 0;
out_screen:
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index b2d75de144c..c625b69ebd1 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -759,9 +759,8 @@ vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) {
struct device *dev;
int ret;
- dev = kmalloc(sizeof(struct device), GFP_KERNEL);
+ dev = kzalloc(sizeof(struct device), GFP_KERNEL);
if (dev) {
- memset(dev, 0, sizeof(struct device));
snprintf(dev->bus_id, BUS_ID_SIZE, "%s",
priv->internal_name);
dev->bus = &iucv_bus;