summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/s390/include/asm/cio.h2
-rw-r--r--arch/s390/include/asm/idals.h76
-rw-r--r--drivers/s390/char/tape.h21
-rw-r--r--drivers/s390/char/tape_34xx.c28
-rw-r--r--drivers/s390/char/tape_3590.c89
-rw-r--r--drivers/s390/char/tape_char.c111
-rw-r--r--drivers/s390/char/tape_core.c35
-rw-r--r--drivers/s390/char/tape_std.c80
-rw-r--r--drivers/s390/char/tape_std.h9
9 files changed, 214 insertions, 237 deletions
diff --git a/arch/s390/include/asm/cio.h b/arch/s390/include/asm/cio.h
index b6b619f340a5..0a82ae2300b6 100644
--- a/arch/s390/include/asm/cio.h
+++ b/arch/s390/include/asm/cio.h
@@ -18,6 +18,8 @@
#include <asm/scsw.h>
+#define CCW_MAX_BYTE_COUNT 65535
+
/**
* struct ccw1 - channel command word
* @cmd_code: command code
diff --git a/arch/s390/include/asm/idals.h b/arch/s390/include/asm/idals.h
index ac68c657b28c..e5000ee6cdc6 100644
--- a/arch/s390/include/asm/idals.h
+++ b/arch/s390/include/asm/idals.h
@@ -181,6 +181,82 @@ static inline void idal_buffer_free(struct idal_buffer *ib)
}
/*
+ * Allocate an array of IDAL buffers to cover a total data size of @size. The
+ * resulting array is null-terminated.
+ *
+ * The amount of individual IDAL buffers is determined based on @size.
+ * Each IDAL buffer can have a maximum size of @CCW_MAX_BYTE_COUNT.
+ */
+static inline struct idal_buffer **idal_buffer_array_alloc(size_t size, int page_order)
+{
+ struct idal_buffer **ibs;
+ size_t ib_size; /* Size of a single idal buffer */
+ int count; /* Amount of individual idal buffers */
+ int i;
+
+ count = (size + CCW_MAX_BYTE_COUNT - 1) / CCW_MAX_BYTE_COUNT;
+ ibs = kmalloc_array(count + 1, sizeof(*ibs), GFP_KERNEL);
+ for (i = 0; i < count; i++) {
+ /* Determine size for the current idal buffer */
+ ib_size = min(size, CCW_MAX_BYTE_COUNT);
+ size -= ib_size;
+ ibs[i] = idal_buffer_alloc(ib_size, page_order);
+ if (IS_ERR(ibs[i])) {
+ while (i--)
+ idal_buffer_free(ibs[i]);
+ kfree(ibs);
+ ibs = NULL;
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+ ibs[i] = NULL;
+ return ibs;
+}
+
+/*
+ * Free array of IDAL buffers
+ */
+static inline void idal_buffer_array_free(struct idal_buffer ***ibs)
+{
+ struct idal_buffer **p;
+
+ if (!ibs || !*ibs)
+ return;
+ for (p = *ibs; *p; p++)
+ idal_buffer_free(*p);
+ kfree(*ibs);
+ *ibs = NULL;
+}
+
+/*
+ * Determine size of IDAL buffer array
+ */
+static inline int idal_buffer_array_size(struct idal_buffer **ibs)
+{
+ int size = 0;
+
+ while (ibs && *ibs) {
+ size++;
+ ibs++;
+ }
+ return size;
+}
+
+/*
+ * Determine total data size covered by IDAL buffer array
+ */
+static inline size_t idal_buffer_array_datasize(struct idal_buffer **ibs)
+{
+ size_t size = 0;
+
+ while (ibs && *ibs) {
+ size += (*ibs)->size;
+ ibs++;
+ }
+ return size;
+}
+
+/*
* Test if a idal list is really needed.
*/
static inline bool __idal_buffer_is_needed(struct idal_buffer *ib)
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index 0aba30efb483..3953b31b0c55 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -130,6 +130,7 @@ struct tape_request {
int retries; /* retry counter for error recovery. */
int rescnt; /* residual count from devstat. */
struct timer_list timer; /* timer for std_assign_timeout(). */
+ struct irb irb; /* device status */
/* Callback for delivering final status. */
void (*callback)(struct tape_request *, void *);
@@ -151,8 +152,8 @@ struct tape_discipline {
int (*setup_device)(struct tape_device *);
void (*cleanup_device)(struct tape_device *);
int (*irq)(struct tape_device *, struct tape_request *, struct irb *);
- struct tape_request *(*read_block)(struct tape_device *, size_t);
- struct tape_request *(*write_block)(struct tape_device *, size_t);
+ 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);
@@ -172,7 +173,7 @@ struct tape_discipline {
/* Char Frontend Data */
struct tape_char_data {
- struct idal_buffer *idal_buf; /* idal buffer for user char data */
+ struct idal_buffer **ibs; /* idal buffer array for user char data */
int block_size; /* of size block_size. */
};
@@ -234,6 +235,7 @@ struct tape_device {
/* Externals from tape_core.c */
extern struct tape_request *tape_alloc_request(int cplength, int datasize);
extern void tape_free_request(struct tape_request *);
+extern int tape_check_idalbuffer(struct tape_device *device, size_t size);
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 *);
@@ -347,12 +349,21 @@ tape_ccw_repeat(struct ccw1 *ccw, __u8 cmd_code, int count)
}
static inline struct ccw1 *
+tape_ccw_dc_idal(struct ccw1 *ccw, __u8 cmd_code, struct idal_buffer *idal)
+{
+ ccw->cmd_code = cmd_code;
+ ccw->flags = CCW_FLAG_DC;
+ idal_buffer_set_cda(idal, ccw);
+ return ccw + 1;
+}
+
+static inline struct ccw1 *
tape_ccw_cc_idal(struct ccw1 *ccw, __u8 cmd_code, struct idal_buffer *idal)
{
ccw->cmd_code = cmd_code;
ccw->flags = CCW_FLAG_CC;
idal_buffer_set_cda(idal, ccw);
- return ccw++;
+ return ccw + 1;
}
static inline struct ccw1 *
@@ -361,7 +372,7 @@ tape_ccw_end_idal(struct ccw1 *ccw, __u8 cmd_code, struct idal_buffer *idal)
ccw->cmd_code = cmd_code;
ccw->flags = 0;
idal_buffer_set_cda(idal, ccw);
- return ccw++;
+ return ccw + 1;
}
/* Global vars */
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c
index 1e4984acb648..9d0fb4b867c4 100644
--- a/drivers/s390/char/tape_34xx.c
+++ b/drivers/s390/char/tape_34xx.c
@@ -234,31 +234,6 @@ tape_34xx_unsolicited_irq(struct tape_device *device, struct irb *irb)
return TAPE_IO_SUCCESS;
}
-/*
- * Read Opposite Error Recovery Function:
- * Used, when Read Forward does not work
- */
-static int
-tape_34xx_erp_read_opposite(struct tape_device *device,
- struct tape_request *request)
-{
- if (request->op == TO_RFO) {
- /*
- * We did read forward, but the data could not be read
- * *correctly*. We transform the request to a read backward
- * and try again.
- */
- tape_std_read_backward(device, request);
- return tape_34xx_erp_retry(request);
- }
-
- /*
- * We tried to read forward and backward, but hat no
- * success -> failed.
- */
- return tape_34xx_erp_failed(request, -EIO);
-}
-
static int
tape_34xx_erp_bug(struct tape_device *device, struct tape_request *request,
struct irb *irb, int no)
@@ -440,9 +415,6 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
dev_warn (&device->cdev->dev, "A write error on the "
"tape cannot be recovered\n");
return tape_34xx_erp_failed(request, -EIO);
- case 0x26:
- /* Data Check (read opposite) occurred. */
- return tape_34xx_erp_read_opposite(device, request);
case 0x28:
/* ID-Mark at tape start couldn't be written */
dev_warn (&device->cdev->dev, "Writing the ID-mark "
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 2a2931d303cb..5b25f5415e4c 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -551,31 +551,6 @@ tape_3590_mtseek(struct tape_device *device, int count)
}
/*
- * 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.
@@ -897,60 +872,6 @@ tape_3590_erp_special_interrupt(struct tape_device *device,
}
/*
- * 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:
- return tape_3590_erp_failed(device, request, irb, -EIO);
- }
-}
-
-/*
* Print an MIM (Media Information Message) (message code f0)
*/
static void
@@ -1348,10 +1269,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
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);
@@ -1405,12 +1322,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
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:
diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c
index 058a3b95f959..5bcb22d9e47a 100644
--- a/drivers/s390/char/tape_char.c
+++ b/drivers/s390/char/tape_char.c
@@ -93,33 +93,6 @@ tapechar_cleanup_device(struct tape_device *device)
device->nt = NULL;
}
-static int
-tapechar_check_idalbuffer(struct tape_device *device, size_t block_size)
-{
- struct idal_buffer *new;
-
- if (device->char_data.idal_buf != NULL &&
- device->char_data.idal_buf->size == block_size)
- return 0;
-
- if (block_size > MAX_BLOCKSIZE) {
- DBF_EVENT(3, "Invalid blocksize (%zd > %d)\n",
- block_size, MAX_BLOCKSIZE);
- return -EINVAL;
- }
-
- /* The current idal buffer is not correct. Allocate a new one. */
- new = idal_buffer_alloc(block_size, 0);
- if (IS_ERR(new))
- return -ENOMEM;
-
- if (device->char_data.idal_buf != NULL)
- idal_buffer_free(device->char_data.idal_buf);
-
- device->char_data.idal_buf = new;
-
- return 0;
-}
/*
* Tape device read function
@@ -127,9 +100,12 @@ tapechar_check_idalbuffer(struct tape_device *device, size_t block_size)
static ssize_t
tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
{
- struct tape_device *device;
struct tape_request *request;
+ struct ccw1 *ccw, *last_ccw;
+ struct tape_device *device;
+ struct idal_buffer **ibs;
size_t block_size;
+ size_t read = 0;
int rc;
DBF_EVENT(6, "TCHAR:read\n");
@@ -156,24 +132,37 @@ tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
block_size = count;
}
- rc = tapechar_check_idalbuffer(device, block_size);
+ rc = tape_check_idalbuffer(device, block_size);
if (rc)
return rc;
DBF_EVENT(6, "TCHAR:nbytes: %lx\n", block_size);
/* Let the discipline build the ccw chain. */
- request = device->discipline->read_block(device, block_size);
+ request = device->discipline->read_block(device);
if (IS_ERR(request))
return PTR_ERR(request);
/* Execute it. */
rc = tape_do_io(device, request);
if (rc == 0) {
- rc = block_size - request->rescnt;
DBF_EVENT(6, "TCHAR:rbytes: %x\n", rc);
- /* Copy data from idal buffer to user space. */
- if (idal_buffer_to_user(device->char_data.idal_buf,
- data, rc) != 0)
- rc = -EFAULT;
+ /* Channel Program Address (cpa) points to last CCW + 8 */
+ last_ccw = dma32_to_virt(request->irb.scsw.cmd.cpa);
+ ccw = request->cpaddr;
+ ibs = device->char_data.ibs;
+ while (++ccw < last_ccw) {
+ /* Copy data from idal buffer to user space. */
+ if (idal_buffer_to_user(*ibs++, data, ccw->count) != 0) {
+ rc = -EFAULT;
+ break;
+ }
+ read += ccw->count;
+ data += ccw->count;
+ }
+ if (&last_ccw[-1] == &request->cpaddr[1] &&
+ request->rescnt == last_ccw[-1].count)
+ rc = 0;
+ else
+ rc = read - request->rescnt;
}
tape_free_request(request);
return rc;
@@ -185,10 +174,12 @@ tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
static ssize_t
tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t *ppos)
{
- struct tape_device *device;
struct tape_request *request;
+ struct ccw1 *ccw, *last_ccw;
+ struct tape_device *device;
+ struct idal_buffer **ibs;
+ size_t written = 0;
size_t block_size;
- size_t written;
int nblocks;
int i, rc;
@@ -208,35 +199,45 @@ tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t
nblocks = 1;
}
- rc = tapechar_check_idalbuffer(device, block_size);
+ rc = tape_check_idalbuffer(device, block_size);
if (rc)
return rc;
- DBF_EVENT(6,"TCHAR:nbytes: %lx\n", block_size);
+ DBF_EVENT(6, "TCHAR:nbytes: %lx\n", block_size);
DBF_EVENT(6, "TCHAR:nblocks: %x\n", nblocks);
/* Let the discipline build the ccw chain. */
- request = device->discipline->write_block(device, block_size);
+ request = device->discipline->write_block(device);
if (IS_ERR(request))
return PTR_ERR(request);
- rc = 0;
- written = 0;
+
for (i = 0; i < nblocks; i++) {
- /* Copy data from user space to idal buffer. */
- if (idal_buffer_from_user(device->char_data.idal_buf,
- data, block_size)) {
- rc = -EFAULT;
- break;
+ size_t wbytes = 0; /* Used to trace written data in dbf */
+
+ ibs = device->char_data.ibs;
+ while (ibs && *ibs) {
+ if (idal_buffer_from_user(*ibs, data, (*ibs)->size)) {
+ rc = -EFAULT;
+ goto out;
+ }
+ data += (*ibs)->size;
+ ibs++;
}
rc = tape_do_io(device, request);
if (rc)
- break;
- DBF_EVENT(6, "TCHAR:wbytes: %lx\n",
- block_size - request->rescnt);
- written += block_size - request->rescnt;
+ goto out;
+
+ /* Channel Program Address (cpa) points to last CCW + 8 */
+ last_ccw = dma32_to_virt(request->irb.scsw.cmd.cpa);
+ ccw = request->cpaddr;
+ while (++ccw < last_ccw)
+ wbytes += ccw->count;
+ DBF_EVENT(6, "TCHAR:wbytes: %lx\n", wbytes - request->rescnt);
+ written += wbytes - request->rescnt;
if (request->rescnt != 0)
break;
- data += block_size;
}
+
+out:
tape_free_request(request);
if (rc == -ENOSPC) {
/*
@@ -324,10 +325,8 @@ tapechar_release(struct inode *inode, struct file *filp)
}
}
- if (device->char_data.idal_buf != NULL) {
- idal_buffer_free(device->char_data.idal_buf);
- device->char_data.idal_buf = NULL;
- }
+ if (device->char_data.ibs)
+ idal_buffer_array_free(&device->char_data.ibs);
tape_release(device);
filp->private_data = NULL;
tape_put_device(device);
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index 6ec812280221..ab1a2dc7d711 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -726,6 +726,36 @@ tape_free_request (struct tape_request * request)
kfree(request);
}
+int
+tape_check_idalbuffer(struct tape_device *device, size_t size)
+{
+ struct idal_buffer **new;
+ size_t old_size = 0;
+
+ old_size = idal_buffer_array_datasize(device->char_data.ibs);
+ if (old_size == size)
+ return 0;
+
+ if (size > MAX_BLOCKSIZE) {
+ DBF_EVENT(3, "Invalid blocksize (%zd > %d)\n",
+ size, MAX_BLOCKSIZE);
+ return -EINVAL;
+ }
+
+ /* The current idal buffer is not correct. Allocate a new one. */
+ new = idal_buffer_array_alloc(size, 0);
+ if (IS_ERR(new))
+ return -ENOMEM;
+
+ /* Free old idal buffer array */
+ if (device->char_data.ibs)
+ idal_buffer_array_free(&device->char_data.ibs);
+
+ device->char_data.ibs = new;
+
+ return 0;
+}
+
static int
__tape_start_io(struct tape_device *device, struct tape_request *request)
{
@@ -1099,9 +1129,10 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
}
/* May be an unsolicited irq */
- if(request != NULL)
+ if (request != NULL) {
request->rescnt = irb->scsw.cmd.count;
- else if ((irb->scsw.cmd.dstat == 0x85 || irb->scsw.cmd.dstat == 0x80) &&
+ memcpy(&request->irb, irb, sizeof(*irb));
+ } else if ((irb->scsw.cmd.dstat == 0x85 || irb->scsw.cmd.dstat == 0x80) &&
!list_empty(&device->req_queue)) {
/* Not Ready to Ready after long busy ? */
struct tape_request *req;
diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c
index 176ae8e2eb6b..4e1c52313fbc 100644
--- a/drivers/s390/char/tape_std.c
+++ b/drivers/s390/char/tape_std.c
@@ -212,7 +212,7 @@ tape_std_mtload(struct tape_device *device, int count)
int
tape_std_mtsetblk(struct tape_device *device, int count)
{
- struct idal_buffer *new;
+ int rc;
DBF_LH(6, "tape_std_mtsetblk(%d)\n", count);
if (count <= 0) {
@@ -224,26 +224,12 @@ tape_std_mtsetblk(struct tape_device *device, int count)
device->char_data.block_size = 0;
return 0;
}
- if (device->char_data.idal_buf != NULL &&
- device->char_data.idal_buf->size == count)
- /* We already have a idal buffer of that size. */
- return 0;
- if (count > MAX_BLOCKSIZE) {
- DBF_EVENT(3, "Invalid block size (%d > %d) given.\n",
- count, MAX_BLOCKSIZE);
- return -EINVAL;
- }
+ rc = tape_check_idalbuffer(device, count);
+ if (rc)
+ return rc;
- /* Allocate a new idal buffer. */
- new = idal_buffer_alloc(count, 0);
- if (IS_ERR(new))
- return -ENOMEM;
- if (device->char_data.idal_buf != NULL)
- idal_buffer_free(device->char_data.idal_buf);
- device->char_data.idal_buf = new;
device->char_data.block_size = count;
-
DBF_LH(6, "new blocksize is %d\n", device->char_data.block_size);
return 0;
@@ -641,63 +627,54 @@ tape_std_mtcompression(struct tape_device *device, int mt_count)
* Read Block
*/
struct tape_request *
-tape_std_read_block(struct tape_device *device, size_t count)
+tape_std_read_block(struct tape_device *device)
{
struct tape_request *request;
+ struct idal_buffer **ibs;
+ struct ccw1 *ccw;
+ size_t count;
- /*
- * We have to alloc 4 ccws in order to be able to transform request
- * into a read backward request in error case.
- */
- request = tape_alloc_request(4, 0);
+ ibs = device->char_data.ibs;
+ count = idal_buffer_array_size(ibs);
+ request = tape_alloc_request(count + 1 /* MODE_SET_DB */, 0);
if (IS_ERR(request)) {
DBF_EXCEPTION(6, "xrbl fail");
return request;
}
request->op = TO_RFO;
- tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
- tape_ccw_end_idal(request->cpaddr + 1, READ_FORWARD,
- device->char_data.idal_buf);
+ ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
+ while (count-- > 1)
+ ccw = tape_ccw_dc_idal(ccw, READ_FORWARD, *ibs++);
+ tape_ccw_end_idal(ccw, READ_FORWARD, *ibs);
+
DBF_EVENT(6, "xrbl ccwg\n");
return request;
}
/*
- * Read Block backward transformation function.
- */
-void
-tape_std_read_backward(struct tape_device *device, struct tape_request *request)
-{
- /*
- * 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);
- tape_ccw_cc_idal(request->cpaddr + 1, READ_BACKWARD,
- 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");}
-
-/*
* Write Block
*/
struct tape_request *
-tape_std_write_block(struct tape_device *device, size_t count)
+tape_std_write_block(struct tape_device *device)
{
struct tape_request *request;
+ struct idal_buffer **ibs;
+ struct ccw1 *ccw;
+ size_t count;
- request = tape_alloc_request(2, 0);
+ count = idal_buffer_array_size(device->char_data.ibs);
+ request = tape_alloc_request(count + 1 /* MODE_SET_DB */, 0);
if (IS_ERR(request)) {
DBF_EXCEPTION(6, "xwbl fail\n");
return request;
}
request->op = TO_WRI;
- tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
- tape_ccw_end_idal(request->cpaddr + 1, WRITE_CMD,
- device->char_data.idal_buf);
+ ccw = tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
+ ibs = device->char_data.ibs;
+ while (count-- > 1)
+ ccw = tape_ccw_dc_idal(ccw, WRITE_CMD, *ibs++);
+ tape_ccw_end_idal(ccw, WRITE_CMD, *ibs);
+
DBF_EVENT(6, "xwbl ccwg\n");
return request;
}
@@ -741,6 +718,5 @@ EXPORT_SYMBOL(tape_std_mterase);
EXPORT_SYMBOL(tape_std_mtunload);
EXPORT_SYMBOL(tape_std_mtcompression);
EXPORT_SYMBOL(tape_std_read_block);
-EXPORT_SYMBOL(tape_std_read_backward);
EXPORT_SYMBOL(tape_std_write_block);
EXPORT_SYMBOL(tape_std_process_eov);
diff --git a/drivers/s390/char/tape_std.h b/drivers/s390/char/tape_std.h
index dcc63ff587f9..2cf9f725b3b3 100644
--- a/drivers/s390/char/tape_std.h
+++ b/drivers/s390/char/tape_std.h
@@ -14,10 +14,9 @@
#include <asm/tape390.h>
/*
- * Biggest block size to handle. Currently 64K because we only build
- * channel programs without data chaining.
+ * Biggest block size of 256K to handle.
*/
-#define MAX_BLOCKSIZE 65535
+#define MAX_BLOCKSIZE 262144
/*
* The CCW commands for the Tape type of command.
@@ -97,10 +96,10 @@
#define SENSE_TAPE_POSITIONING 0x01
/* discipline functions */
-struct tape_request *tape_std_read_block(struct tape_device *, size_t);
+struct tape_request *tape_std_read_block(struct tape_device *);
void tape_std_read_backward(struct tape_device *device,
struct tape_request *request);
-struct tape_request *tape_std_write_block(struct tape_device *, size_t);
+struct tape_request *tape_std_write_block(struct tape_device *);
/* Some non-mtop commands. */
int tape_std_assign(struct tape_device *);