mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 09:04:39 +02:00
Merge branch 'tape-block-sizes'
Jan Höppner says: ==================== The tape device driver is limited to a block size of 65535 bytes since a single CCW can only transfer up to 64K-1 bytes (The count field is a 16bit value). This series introduces data chaining for all read/write functions to support block sizes larger than 65535. The tape device type 3490 (emulated) and 3590/3592 can handle up to 256K. [1] [1] https://www.ibm.com/docs/en/zos/3.1.0?topic=blksize-system-determined-block-size ==================== Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
This commit is contained in:
commit
5e09c0a03e
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#include <asm/scsw.h>
|
||||
|
||||
#define CCW_MAX_BYTE_COUNT 65535
|
||||
|
||||
/**
|
||||
* struct ccw1 - channel command word
|
||||
* @cmd_code: command code
|
||||
|
|
|
|||
|
|
@ -180,6 +180,82 @@ static inline void idal_buffer_free(struct idal_buffer *ib)
|
|||
kfree(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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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 *);
|
||||
|
|
@ -346,13 +348,22 @@ tape_ccw_repeat(struct ccw1 *ccw, __u8 cmd_code, int count)
|
|||
return ccw;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
|
|
|||
|
|
@ -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 "
|
||||
|
|
|
|||
|
|
@ -550,31 +550,6 @@ tape_3590_mtseek(struct tape_device *device, int count)
|
|||
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)
|
||||
|
|
@ -896,60 +871,6 @@ tape_3590_erp_special_interrupt(struct tape_device *device,
|
|||
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:
|
||||
return tape_3590_erp_failed(device, request, irb, -EIO);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print an MIM (Media Information Message) (message code f0)
|
||||
*/
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 *);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user