patch-1.3.30 linux/drivers/scsi/st.c
Next file: linux/drivers/scsi/st.h
Previous file: linux/drivers/scsi/sr.c
Back to the patch index
Back to the overall index
- Lines: 952
- Date:
Wed Sep 27 12:34:52 1995
- Orig file:
v1.3.29/linux/drivers/scsi/st.c
- Orig date:
Mon Sep 25 12:26:22 1995
diff -u --recursive --new-file v1.3.29/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
@@ -11,7 +11,7 @@
Copyright 1992, 1993, 1994, 1995 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Tue Sep 19 21:51:41 1995 by root@kai.makisara.fi
+ Last modified: Mon Sep 25 19:52:16 1995 by root@kai.makisara.fi
Some small formal changes - aeb, 950809
*/
#ifdef MODULE
@@ -30,6 +30,7 @@
#include <linux/ioctl.h>
#include <linux/fcntl.h>
#include <asm/segment.h>
+#include <asm/dma.h>
#include <asm/system.h>
/* The driver prints some debugging information on the console if DEBUG
@@ -79,10 +80,11 @@
static int st_write_threshold = ST_WRITE_THRESHOLD;
static int st_max_buffers = ST_MAX_BUFFERS;
-#define MAX_SCSI_TAPES 8
Scsi_Tape * scsi_tapes = NULL;
static ST_buffer *new_tape_buffer(int);
+static int enlarge_buffer(ST_buffer *, int);
+static void normalize_buffer(ST_buffer *);
static int st_init(void);
static int st_attach(Scsi_Device *);
@@ -107,7 +109,9 @@
int dev = TAPE_NR(SCpnt->request.rq_dev);
int result = SCpnt->result;
unsigned char * sense = SCpnt->sense_buffer, scode;
+#if DEBUG
const char *stp;
+#endif
if (!result /* && SCpnt->sense_buffer[0] == 0 */ )
return 0;
@@ -145,14 +149,18 @@
) {
scsi_tapes[dev].recover_count++;
scsi_tapes[dev].mt_status->mt_erreg += (1 << MT_ST_SOFTERR_SHIFT);
- if (SCpnt->data_cmnd[0] == READ_6)
- stp = "read";
- else if (SCpnt->data_cmnd[0] == WRITE_6)
- stp = "write";
- else
- stp = "ioctl";
- printk("st%d: Recovered %s error (%d).\n", dev, stp,
- scsi_tapes[dev].recover_count);
+#if DEBUG
+ if (debugging) { /* This is compiled always on purpose */
+ if (SCpnt->data_cmnd[0] == READ_6)
+ stp = "read";
+ else if (SCpnt->data_cmnd[0] == WRITE_6)
+ stp = "write";
+ else
+ stp = "ioctl";
+ printk("st%d: Recovered %s error (%d).\n", dev, stp,
+ scsi_tapes[dev].recover_count);
+ }
+#endif
return 0;
}
return (-EIO);
@@ -187,9 +195,11 @@
}
else
(STp->buffer)->last_result = SCpnt->result;
- (STp->buffer)->last_result_fatal = st_chk_result(SCpnt);
- if ((STp->buffer)->writing)
+ if ((STp->buffer)->writing) {
+ /* Process errors before releasing request */
+ (STp->buffer)->last_result_fatal = st_chk_result(SCpnt);
SCpnt->request.rq_status = RQ_INACTIVE;
+ }
else
SCpnt->request.rq_status = RQ_SCSI_DONE;
if (!(STp->buffer)->writing || STp->write_pending)
@@ -203,16 +213,46 @@
}
+/* Do the scsi command */
+ static Scsi_Cmnd *
+st_do_scsi(Scsi_Cmnd *SCpnt, Scsi_Tape *STp, unsigned char *cmd, int bytes,
+ int timeout, int retries)
+{
+ unsigned int flags;
+
+ if (SCpnt == NULL)
+ if ((SCpnt = allocate_device(NULL, STp->device, 1)) == NULL) {
+ printk("st%d: Can't get SCSI request.\n", TAPE_NR(STp->devt));
+ return NULL;
+ }
+
+ cmd[1] |= (SCpnt->lun << 5) & 0xe0;
+ SCpnt->request.rq_status = RQ_SCSI_BUSY;
+ SCpnt->request.rq_dev = STp->devt;
+
+ scsi_do_cmd(SCpnt, (void *)cmd, (STp->buffer)->b_data, bytes,
+ st_sleep_done, timeout, retries);
+
+ /* this must be done with interrupts off */
+ save_flags (flags);
+ cli();
+ if (SCpnt->request.rq_status != RQ_SCSI_DONE)
+ sleep_on( &(STp->waiting) );
+ restore_flags(flags);
+
+ (STp->buffer)->last_result_fatal = st_chk_result(SCpnt);
+
+ return SCpnt;
+}
+
+
/* Handle the write-behind checking */
static void
-write_behind_check(kdev_t devt)
+write_behind_check(Scsi_Tape *STp)
{
- int dev = TAPE_NR(devt);
- Scsi_Tape * STp;
ST_buffer * STbuffer;
unsigned long flags;
- STp = &(scsi_tapes[dev]);
STbuffer = STp->buffer;
save_flags(flags);
@@ -250,36 +290,23 @@
/* Back over EOF if it has been inadvertently crossed (ioctl not used because
it messes up the block number). */
static int
-back_over_eof(kdev_t devt)
+back_over_eof(Scsi_Tape *STp)
{
- int dev = TAPE_NR(devt);
Scsi_Cmnd *SCpnt;
- Scsi_Tape *STp = &(scsi_tapes[dev]);
unsigned char cmd[10];
- unsigned int flags;
- SCpnt = allocate_device(NULL, STp->device, 1);
- SCpnt->request.rq_dev = devt;
cmd[0] = SPACE;
- cmd[1] = ((SCpnt->lun << 5) & 0xe0) | 0x01; /* Space FileMarks */
+ cmd[1] = 0x01; /* Space FileMarks */
cmd[2] = cmd[3] = cmd[4] = 0xff; /* -1 filemarks */
cmd[5] = 0;
- SCpnt->request.rq_status = RQ_SCSI_BUSY;
- scsi_do_cmd(SCpnt,
- (void *) cmd, (void *) (STp->buffer)->b_data, 0,
- st_sleep_done, ST_TIMEOUT, MAX_RETRIES);
+ SCpnt = st_do_scsi(NULL, STp, cmd, 0, ST_TIMEOUT, MAX_RETRIES);
+ if (!SCpnt)
+ return (-EBUSY);
- /* need to do the check with interrupts off. -RAB */
- save_flags(flags);
- cli();
- if (SCpnt->request.rq_status != RQ_SCSI_DONE)
- sleep_on( &(STp->waiting) );
- restore_flags(flags);
-
SCpnt->request.rq_status = RQ_INACTIVE;
if ((STp->buffer)->last_result != 0) {
- printk("st%d: Backing over filemark failed.\n", dev);
+ printk("st%d: Backing over filemark failed.\n", TAPE_NR(STp->devt));
if ((STp->mt_status)->mt_fileno >= 0)
(STp->mt_status)->mt_fileno += 1;
(STp->mt_status)->mt_blkno = 0;
@@ -291,22 +318,19 @@
/* Flush the write buffer (never need to write if variable blocksize). */
static int
-flush_write_buffer(kdev_t devt)
+flush_write_buffer(Scsi_Tape *STp)
{
- int dev = TAPE_NR(devt);
int offset, transfer, blks;
int result;
- unsigned int flags;
unsigned char cmd[10];
Scsi_Cmnd *SCpnt;
- Scsi_Tape *STp = &(scsi_tapes[dev]);
if ((STp->buffer)->writing) {
- write_behind_check(devt);
+ write_behind_check(STp);
if ((STp->buffer)->last_result_fatal) {
#if DEBUG
if (debugging)
- printk("st%d: Async write error (flush) %x.\n", dev,
+ printk("st%d: Async write error (flush) %x.\n", TAPE_NR(STp->devt),
(STp->buffer)->last_result);
#endif
if ((STp->buffer)->last_result == INT_MAX)
@@ -320,39 +344,30 @@
result = 0;
if (STp->dirty == 1) {
- SCpnt = allocate_device(NULL, STp->device, 1);
offset = (STp->buffer)->buffer_bytes;
transfer = ((offset + STp->block_size - 1) /
STp->block_size) * STp->block_size;
#if DEBUG
if (debugging)
- printk("st%d: Flushing %d bytes.\n", dev, transfer);
+ printk("st%d: Flushing %d bytes.\n", TAPE_NR(STp->devt), transfer);
#endif
memset((STp->buffer)->b_data + offset, 0, transfer - offset);
memset(cmd, 0, 10);
cmd[0] = WRITE_6;
- cmd[1] = ((SCpnt->lun << 5) & 0xe0) | 1;
+ cmd[1] = 1;
blks = transfer / STp->block_size;
cmd[2] = blks >> 16;
cmd[3] = blks >> 8;
cmd[4] = blks;
- SCpnt->request.rq_status = RQ_SCSI_BUSY;
- SCpnt->request.rq_dev = devt;
- scsi_do_cmd (SCpnt,
- (void *) cmd, (STp->buffer)->b_data, transfer,
- st_sleep_done, ST_TIMEOUT, MAX_WRITE_RETRIES);
-
- /* this must be done with interrupts off */
- save_flags (flags);
- cli();
- if (SCpnt->request.rq_status != RQ_SCSI_DONE)
- sleep_on( &(STp->waiting) );
- restore_flags(flags);
-
+
+ SCpnt = st_do_scsi(NULL, STp, cmd, transfer, ST_TIMEOUT, MAX_WRITE_RETRIES);
+ if (!SCpnt)
+ return (-EBUSY);
+
if ((STp->buffer)->last_result_fatal != 0) {
- printk("st%d: Error on flush.\n", dev);
+ printk("st%d: Error on flush.\n", TAPE_NR(STp->devt));
if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
(SCpnt->sense_buffer[2] & 0x40) &&
(SCpnt->sense_buffer[2] & 0x0f) != VOLUME_OVERFLOW) {
@@ -384,8 +399,7 @@
int backspace, result;
Scsi_Tape * STp;
ST_buffer * STbuffer;
- kdev_t devt = inode->i_rdev;
- int dev = TAPE_NR(devt);
+ int dev = TAPE_NR(inode->i_rdev);
STp = &(scsi_tapes[dev]);
STbuffer = STp->buffer;
@@ -401,7 +415,7 @@
return 0;
if (STp->rw == ST_WRITING) /* Writing */
- return flush_write_buffer(devt);
+ return flush_write_buffer(STp);
if (STp->block_size == 0)
return 0;
@@ -415,7 +429,7 @@
result = 0;
if (!seek_next) {
if ((STp->eof == ST_FM) && !STp->eof_hit) {
- result = back_over_eof(devt); /* Back over the EOF hit */
+ result = back_over_eof(STp); /* Back over the EOF hit */
if (!result) {
STp->eof = ST_NOEOF;
STp->eof_hit = 0;
@@ -434,15 +448,12 @@
scsi_tape_open(struct inode * inode, struct file * filp)
{
unsigned short flags;
- unsigned int processor_flags;
int i;
unsigned char cmd[10];
Scsi_Cmnd * SCpnt;
Scsi_Tape * STp;
- kdev_t devt = inode->i_rdev;
- int dev;
+ int dev = TAPE_NR(inode->i_rdev);
- dev = TAPE_NR(devt);
if (dev >= st_template.dev_max || !scsi_tapes[dev].device)
return (-ENXIO);
STp = &(scsi_tapes[dev]);
@@ -483,50 +494,24 @@
STp->nbr_waits = STp->nbr_finished = 0;
#endif
- SCpnt = allocate_device(NULL, STp->device, 1);
- SCpnt->request.rq_dev = devt;
- if (!SCpnt) {
- printk("st%d: Tape request not allocated", dev);
- return (-EBUSY);
- }
-
memset ((void *) &cmd[0], 0, 10);
cmd[0] = TEST_UNIT_READY;
- cmd[1] = (SCpnt->lun << 5) & 0xe0;
- SCpnt->request.rq_status = RQ_SCSI_BUSY;
- scsi_do_cmd(SCpnt,
- (void *) cmd, (void *) (STp->buffer)->b_data,
- 0, st_sleep_done, ST_LONG_TIMEOUT,
- MAX_READY_RETRIES);
-
- /* this must be done with interrupts off */
- save_flags (processor_flags);
- cli();
- if (SCpnt->request.rq_status != RQ_SCSI_DONE)
- sleep_on( &(STp->waiting) );
- restore_flags(processor_flags);
+
+ SCpnt = st_do_scsi(NULL, STp, cmd, 0, ST_LONG_TIMEOUT, MAX_READY_RETRIES);
+ if (!SCpnt)
+ return (-EBUSY);
if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
(SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
(STp->mt_status)->mt_fileno = 0 ;
memset ((void *) &cmd[0], 0, 10);
cmd[0] = TEST_UNIT_READY;
- cmd[1] = (SCpnt->lun << 5) & 0xe0;
- SCpnt->request.rq_status = RQ_SCSI_BUSY;
- scsi_do_cmd(SCpnt,
- (void *) cmd, (void *) (STp->buffer)->b_data,
- 0, st_sleep_done, ST_LONG_TIMEOUT,
- MAX_READY_RETRIES);
-
- /* this must be done with interrupts off */
- save_flags (processor_flags);
- cli();
- if (SCpnt->request.rq_status != RQ_SCSI_DONE)
- sleep_on( &(STp->waiting) );
- restore_flags(processor_flags);
+
+ SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, ST_LONG_TIMEOUT, MAX_READY_RETRIES);
(STp->mt_status)->mt_fileno = STp->drv_block = 0;
STp->eof = ST_NOEOF;
+ (STp->device)->was_reset = 0;
}
if ((STp->buffer)->last_result_fatal != 0) {
@@ -554,18 +539,8 @@
memset ((void *) &cmd[0], 0, 10);
cmd[0] = READ_BLOCK_LIMITS;
- cmd[1] = (SCpnt->lun << 5) & 0xe0;
- SCpnt->request.rq_status = RQ_SCSI_BUSY;
- scsi_do_cmd(SCpnt,
- (void *) cmd, (void *) (STp->buffer)->b_data,
- 6, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES);
-
- /* this must be done with interrupts off */
- save_flags (processor_flags);
- cli();
- if (SCpnt->request.rq_status != RQ_SCSI_DONE)
- sleep_on( &(STp->waiting) );
- restore_flags(processor_flags);
+
+ SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, ST_TIMEOUT, MAX_READY_RETRIES);
if (!SCpnt->result && !SCpnt->sense_buffer[0]) {
STp->max_block = ((STp->buffer)->b_data[1] << 16) |
@@ -588,19 +563,9 @@
memset ((void *) &cmd[0], 0, 10);
cmd[0] = MODE_SENSE;
- cmd[1] = (SCpnt->lun << 5) & 0xe0;
cmd[4] = 12;
- SCpnt->request.rq_status = RQ_SCSI_BUSY;
- scsi_do_cmd(SCpnt,
- (void *) cmd, (void *) (STp->buffer)->b_data,
- 12, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES);
-
- /* this must be done with interrupts off */
- save_flags (processor_flags);
- cli();
- if (SCpnt->request.rq_status != RQ_SCSI_DONE)
- sleep_on( &(STp->waiting) );
- restore_flags(processor_flags);
+
+ SCpnt = st_do_scsi(SCpnt, STp, cmd, 12, ST_TIMEOUT, MAX_READY_RETRIES);
if ((STp->buffer)->last_result_fatal != 0) {
#if DEBUG
@@ -633,7 +598,8 @@
#endif
}
- if (STp->block_size > st_buffer_size) {
+ if (STp->block_size > (STp->buffer)->buffer_size &&
+ !enlarge_buffer(STp->buffer, STp->block_size)) {
printk("st%d: Blocksize %d too large for buffer.\n", dev,
STp->block_size);
(STp->buffer)->in_use = 0;
@@ -643,15 +609,10 @@
}
SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
- if (STp->block_size > 0) {
+ if (STp->block_size > 0)
(STp->buffer)->buffer_blocks = st_buffer_size / STp->block_size;
- (STp->buffer)->buffer_size =
- (STp->buffer)->buffer_blocks * STp->block_size;
- }
- else {
+ else
(STp->buffer)->buffer_blocks = 1;
- (STp->buffer)->buffer_size = st_buffer_size;
- }
(STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;
#if DEBUG
@@ -693,7 +654,6 @@
static unsigned char cmd[10];
Scsi_Cmnd * SCpnt;
Scsi_Tape * STp;
- unsigned int flags;
kdev_t devt = inode->i_rdev;
int dev;
@@ -702,9 +662,9 @@
STp = &(scsi_tapes[dev]);
- if ( STp->rw == ST_WRITING) {
+ if ( STp->rw == ST_WRITING && !(STp->device)->was_reset) {
- result = flush_write_buffer(devt);
+ result = flush_write_buffer(STp);
#if DEBUG
if (debugging) {
@@ -715,38 +675,25 @@
#endif
if (result == 0 || result == (-ENOSPC)) {
- SCpnt = allocate_device(NULL, STp->device, 1);
- SCpnt->request.rq_dev = devt;
memset(cmd, 0, 10);
cmd[0] = WRITE_FILEMARKS;
- cmd[1] = (SCpnt->lun << 5) & 0xe0;
cmd[4] = 1 + STp->two_fm;
- SCpnt->request.rq_status = RQ_SCSI_BUSY;
- scsi_do_cmd( SCpnt,
- (void *) cmd, (void *) (STp->buffer)->b_data,
- 0, st_sleep_done, ST_TIMEOUT, MAX_WRITE_RETRIES);
-
- /* this must be done with interrupts off */
- save_flags (flags);
- cli();
- if (SCpnt->request.rq_status != RQ_SCSI_DONE)
- sleep_on( &(STp->waiting) );
- restore_flags(flags);
- if ((STp->buffer)->last_result_fatal != 0) {
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
+ SCpnt = st_do_scsi(NULL, STp, cmd, 0, ST_TIMEOUT, MAX_WRITE_RETRIES);
+ if (!SCpnt)
+ return;
+
+ if ((STp->buffer)->last_result_fatal != 0)
printk("st%d: Error on write filemark.\n", dev);
- }
else {
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
if ((STp->mt_status)->mt_fileno >= 0)
(STp->mt_status)->mt_fileno++ ;
STp->drv_block = 0;
if (STp->two_fm)
- back_over_eof(devt);
+ back_over_eof(STp);
}
-
+ SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
}
#if DEBUG
@@ -759,7 +706,7 @@
flush_buffer(inode, filp, 0);
#else
if ((STp->eof == ST_FM) && !STp->eof_hit)
- back_over_eof(devt);
+ back_over_eof(STp);
#endif
}
@@ -769,8 +716,10 @@
if (STp->door_locked == ST_LOCKED_AUTO)
st_int_ioctl(inode, filp, MTUNLOCK, 0);
- if (STp->buffer != NULL)
+ if (STp->buffer != NULL) {
+ normalize_buffer(STp->buffer);
(STp->buffer)->in_use = 0;
+ }
STp->in_use = 0;
if (scsi_tapes[dev].device->host->hostt->usage_count)
@@ -790,13 +739,10 @@
int doing_write = 0;
static unsigned char cmd[10];
const char *b_point;
- Scsi_Cmnd * SCpnt;
+ Scsi_Cmnd * SCpnt = NULL;
Scsi_Tape * STp;
- unsigned int flags;
- kdev_t devt = inode->i_rdev;
- int dev;
+ int dev = TAPE_NR(inode->i_rdev);
- dev = TAPE_NR(devt);
STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY)
return (-EIO);
@@ -818,7 +764,9 @@
if (STp->write_prot)
return (-EACCES);
- if (STp->block_size == 0 && count > st_buffer_size)
+ if (STp->block_size == 0 &&
+ count > (STp->buffer)->buffer_size &&
+ !enlarge_buffer(STp->buffer, count))
return (-EOVERFLOW);
if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
@@ -836,7 +784,7 @@
STp->moves_after_eof++;
if ((STp->buffer)->writing) {
- write_behind_check(devt);
+ write_behind_check(STp);
if ((STp->buffer)->last_result_fatal) {
#if DEBUG
if (debugging)
@@ -864,18 +812,15 @@
write_threshold = 1;
}
else
- write_threshold = (STp->buffer)->buffer_size;
+ write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
if (!STp->do_async_writes)
write_threshold--;
- SCpnt = allocate_device(NULL, STp->device, 1);
- SCpnt->request.rq_dev = devt;
-
total = count;
memset(cmd, 0, 10);
cmd[0] = WRITE_6;
- cmd[1] = ((SCpnt->lun << 5) & 0xe0) | (STp->block_size != 0);
+ cmd[1] = (STp->block_size != 0);
STp->rw = ST_WRITING;
@@ -888,7 +833,8 @@
if (STp->block_size == 0)
do_count = count;
else {
- do_count = (STp->buffer)->buffer_size - (STp->buffer)->buffer_bytes;
+ do_count = (STp->buffer)->buffer_blocks * STp->block_size -
+ (STp->buffer)->buffer_bytes;
if (do_count > count)
do_count = count;
}
@@ -905,17 +851,10 @@
cmd[2] = blks >> 16;
cmd[3] = blks >> 8;
cmd[4] = blks;
- SCpnt->request.rq_status = RQ_SCSI_BUSY;
- scsi_do_cmd (SCpnt,
- (void *) cmd, (STp->buffer)->b_data, transfer,
- st_sleep_done, ST_TIMEOUT, MAX_WRITE_RETRIES);
- /* this must be done with interrupts off */
- save_flags (flags);
- cli();
- if (SCpnt->request.rq_status != RQ_SCSI_DONE)
- sleep_on( &(STp->waiting) );
- restore_flags(flags);
+ SCpnt = st_do_scsi(SCpnt, STp, cmd, transfer, ST_TIMEOUT, MAX_WRITE_RETRIES);
+ if (!SCpnt)
+ return (-EBUSY);
if ((STp->buffer)->last_result_fatal != 0) {
#if DEBUG
@@ -1005,6 +944,11 @@
((STp->buffer)->buffer_bytes >= STp->write_threshold ||
STp->block_size == 0) ) {
/* Schedule an asynchronous write */
+ if (!SCpnt) {
+ SCpnt = allocate_device(NULL, STp->device, 1);
+ if (!SCpnt)
+ return (-EBUSY);
+ }
if (STp->block_size == 0)
(STp->buffer)->writing = (STp->buffer)->buffer_bytes;
else
@@ -1021,6 +965,7 @@
cmd[3] = blks >> 8;
cmd[4] = blks;
SCpnt->request.rq_status = RQ_SCSI_BUSY;
+ SCpnt->request.rq_dev = STp->devt;
STp->write_pending = 1;
scsi_do_cmd (SCpnt,
(void *) cmd, (STp->buffer)->b_data,
@@ -1042,13 +987,10 @@
int total;
int transfer, blks, bytes;
static unsigned char cmd[10];
- Scsi_Cmnd * SCpnt;
+ Scsi_Cmnd * SCpnt = NULL;
Scsi_Tape * STp;
- unsigned int flags;
- kdev_t devt = inode->i_rdev;
- int dev;
+ int dev = TAPE_NR(inode->i_rdev);
- dev = TAPE_NR(devt);
STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY)
return (-EIO);
@@ -1059,7 +1001,9 @@
}
#endif
- if (STp->block_size == 0 && count > st_buffer_size)
+ if (STp->block_size == 0 &&
+ count > (STp->buffer)->buffer_size &&
+ !enlarge_buffer(STp->buffer, count))
return (-EOVERFLOW);
if (!(STp->do_read_ahead) && STp->block_size != 0 &&
@@ -1090,9 +1034,6 @@
STp->rw = ST_READING;
- SCpnt = allocate_device(NULL, STp->device, 1);
- SCpnt->request.rq_dev = devt;
-
for (total = 0; total < count; ) {
if ((STp->buffer)->buffer_bytes == 0 &&
@@ -1100,7 +1041,7 @@
memset(cmd, 0, 10);
cmd[0] = READ_6;
- cmd[1] = ((SCpnt->lun << 5) & 0xe0) | (STp->block_size != 0);
+ cmd[1] = (STp->block_size != 0);
if (STp->block_size == 0)
blks = bytes = count;
else {
@@ -1110,8 +1051,8 @@
}
else {
bytes = count;
- if (bytes > st_buffer_size)
- bytes = st_buffer_size;
+ if (bytes > (STp->buffer)->buffer_size)
+ bytes = (STp->buffer)->buffer_size;
blks = bytes / STp->block_size;
bytes = blks * STp->block_size;
}
@@ -1120,17 +1061,9 @@
cmd[3] = blks >> 8;
cmd[4] = blks;
- SCpnt->request.rq_status = RQ_SCSI_BUSY;
- scsi_do_cmd (SCpnt,
- (void *) cmd, (STp->buffer)->b_data,
- bytes, st_sleep_done, ST_TIMEOUT, MAX_RETRIES);
-
- /* this must be done with interrupts off */
- save_flags (flags);
- cli();
- if (SCpnt->request.rq_status != RQ_SCSI_DONE)
- sleep_on( &(STp->waiting) );
- restore_flags(flags);
+ SCpnt = st_do_scsi(SCpnt, STp, cmd, bytes, ST_TIMEOUT, MAX_RETRIES);
+ if (!SCpnt)
+ return (-EBUSY);
(STp->buffer)->read_pointer = 0;
STp->eof_hit = 0;
@@ -1291,10 +1224,8 @@
{
int value;
Scsi_Tape *STp;
- kdev_t devt = inode->i_rdev;
- int dev;
+ int dev = TAPE_NR(inode->i_rdev);
- dev = TAPE_NR(devt);
STp = &(scsi_tapes[dev]);
if ((options & MT_ST_OPTIONS) == MT_ST_BOOLEANS) {
STp->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
@@ -1345,9 +1276,7 @@
Scsi_Cmnd * SCpnt;
Scsi_Tape * STp;
int fileno, blkno, at_sm, undone, datalen;
- unsigned int flags;
- kdev_t devt = inode->i_rdev;
- int dev = TAPE_NR(devt);
+ int dev = TAPE_NR(inode->i_rdev);
STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY && cmd_in != MTLOAD)
@@ -1687,20 +1616,9 @@
return (-ENOSYS);
}
- SCpnt = allocate_device(NULL, STp->device, 1);
- SCpnt->request.rq_dev = devt;
- cmd[1] |= (SCpnt->lun << 5) & 0xe0;
- SCpnt->request.rq_status = RQ_SCSI_BUSY;
- scsi_do_cmd(SCpnt,
- (void *) cmd, (void *) (STp->buffer)->b_data, datalen,
- st_sleep_done, timeout, MAX_RETRIES);
-
- /* this must be done with interrupts off */
- save_flags (flags);
- cli();
- if (SCpnt->request.rq_status != RQ_SCSI_DONE)
- sleep_on( &(STp->waiting) );
- restore_flags(flags);
+ SCpnt = st_do_scsi(NULL, STp, cmd, datalen, timeout, MAX_RETRIES);
+ if (!SCpnt)
+ return (-EBUSY);
ioctl_result = (STp->buffer)->last_result_fatal;
@@ -1730,18 +1648,10 @@
ioctl_result = st_int_ioctl(inode, file, MTBSF, 1);
else if (cmd_in == MTSETBLK) {
STp->block_size = arg;
- if (arg != 0) {
+ if (arg != 0)
(STp->buffer)->buffer_blocks =
- st_buffer_size / STp->block_size;
- (STp->buffer)->buffer_size =
- (STp->buffer)->buffer_blocks * STp->block_size;
- }
- else {
- (STp->buffer)->buffer_blocks = 1;
- (STp->buffer)->buffer_size = st_buffer_size;
- }
- (STp->buffer)->buffer_bytes =
- (STp->buffer)->read_pointer = 0;
+ (STp->buffer)->buffer_size / STp->block_size;
+ (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;
}
else if (cmd_in == MTSETDRVBUFFER)
STp->drv_buffer = (arg & 7);
@@ -1830,9 +1740,7 @@
unsigned char scmd[10];
Scsi_Cmnd *SCpnt;
Scsi_Tape *STp;
- unsigned int flags;
- kdev_t devt = inode->i_rdev;
- int dev = TAPE_NR(devt);
+ int dev = TAPE_NR(inode->i_rdev);
STp = &(scsi_tapes[dev]);
#if DEBUG
@@ -1885,7 +1793,8 @@
mtc.mt_op != MTEOM)
return (-EIO);
STp->device->was_reset = 0;
- if (STp->door_locked != ST_UNLOCKED) {
+ if (STp->door_locked != ST_UNLOCKED &&
+ STp->door_locked != ST_LOCK_FAILS) {
if (st_int_ioctl(inode, file, MTLOCK, 0)) {
printk("st%d: Could not relock door after bus reset.\n", dev);
STp->door_locked = ST_UNLOCKED;
@@ -1978,9 +1887,6 @@
if (i)
return i;
- SCpnt = allocate_device(NULL, STp->device, 1);
- SCpnt->request.rq_dev = devt;
-
memset (scmd, 0, 10);
if ((STp->device)->scsi_level < SCSI_2) {
scmd[0] = QFA_REQUEST_BLOCK;
@@ -1990,18 +1896,9 @@
scmd[0] = READ_POSITION;
scmd[1] = 1;
}
- SCpnt->request.rq_status = RQ_SCSI_BUSY;
- scmd[1] |= (SCpnt->lun << 5) & 0xe0;
- scsi_do_cmd(SCpnt,
- (void *) scmd, (void *) (STp->buffer)->b_data,
- 20, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES);
-
- /* this must be done with interrupts off */
- save_flags (flags);
- cli();
- if (SCpnt->request.rq_status != RQ_SCSI_DONE)
- sleep_on( &(STp->waiting) );
- restore_flags(flags);
+ SCpnt = st_do_scsi(NULL, STp, scmd, 20, ST_TIMEOUT, MAX_READY_RETRIES);
+ if (!SCpnt)
+ return (-EBUSY);
if ((STp->buffer)->last_result_fatal != 0) {
mt_pos.mt_blkno = (-1);
@@ -2039,20 +1936,24 @@
static ST_buffer *
new_tape_buffer( int from_initialization )
{
- int priority;
+ int priority, a_size;
ST_buffer *tb;
if (st_nbr_buffers >= st_template.dev_max)
return NULL; /* Should never happen */
- if (from_initialization)
- priority = GFP_ATOMIC;
- else
- priority = GFP_KERNEL;
+ if (from_initialization) {
+ priority = GFP_ATOMIC | GFP_DMA;
+ a_size = st_buffer_size;
+ }
+ else {
+ priority = GFP_KERNEL | GFP_DMA;
+ for (a_size = PAGE_SIZE; a_size < st_buffer_size; a_size <<= 1)
+ ; /* Make sure we allocate efficiently */
+ }
tb = (ST_buffer *)scsi_init_malloc(sizeof(ST_buffer), priority);
if (tb) {
- tb->b_data = (unsigned char *)scsi_init_malloc(st_buffer_size,
- priority | GFP_DMA);
+ tb->b_data = (unsigned char *)scsi_init_malloc(a_size, priority);
if (!tb->b_data) {
scsi_init_free((char *)tb, sizeof(ST_buffer));
tb = NULL;
@@ -2064,15 +1965,67 @@
}
#if DEBUG
- printk("st: Allocated tape buffer %d.\n", st_nbr_buffers);
+ if (debugging)
+ printk("st: Allocated tape buffer %d (%d bytes).\n", st_nbr_buffers,
+ a_size);
#endif
tb->in_use = 0;
+ tb->buffer_size = a_size;
tb->writing = 0;
+ tb->orig_b_data = NULL;
st_buffers[st_nbr_buffers++] = tb;
return tb;
}
+/* Try to allocate a temporary enlarged tape buffer */
+ static int
+enlarge_buffer(ST_buffer *STbuffer, int new_size)
+{
+ int a_size;
+ unsigned char *tbd;
+
+ normalize_buffer(STbuffer);
+
+ for (a_size = PAGE_SIZE; a_size < new_size; a_size <<= 1)
+ ; /* Make sure that we allocate efficiently */
+
+ tbd = (unsigned char *)scsi_init_malloc(a_size, GFP_DMA | GFP_KERNEL);
+ if (!tbd)
+ return FALSE;
+
+#if DEBUG
+ if (debugging)
+ printk("st: Buffer enlarged to %d bytes.\n", a_size);
+#endif
+
+ STbuffer->orig_b_data = STbuffer->b_data;
+ STbuffer->orig_size = STbuffer->buffer_size;
+ STbuffer->b_data = tbd;
+ STbuffer->buffer_size = a_size;
+ return TRUE;
+}
+
+
+/* Release the extra buffer */
+ static void
+normalize_buffer(ST_buffer *STbuffer)
+{
+ if (STbuffer->orig_b_data == NULL)
+ return;
+
+ scsi_init_free(STbuffer->b_data, STbuffer->buffer_size);
+ STbuffer->b_data = STbuffer->orig_b_data;
+ STbuffer->orig_b_data = NULL;
+ STbuffer->buffer_size = STbuffer->orig_size;
+
+#if DEBUG
+ if (debugging)
+ printk("st: Buffer normalized to %d bytes.\n", STbuffer->buffer_size);
+#endif
+}
+
+
/* Set the boot options. Syntax: st=xxx,yyy
where xxx is buffer size in 512 byte blocks and yyy is write threshold
in 512 byte blocks. */
@@ -2127,6 +2080,7 @@
else
scsi_tapes[i].mt_status->mt_type = MT_ISSCSI2;
+ tpnt->devt = MKDEV(SCSI_TAPE_MAJOR, i);
tpnt->dirty = 0;
tpnt->rw = ST_IDLE;
tpnt->eof = ST_NOEOF;
@@ -2183,8 +2137,8 @@
if (scsi_tapes) return 0;
st_template.dev_max = st_template.dev_noticed + ST_EXTRA_DEVS;
- if (st_template.dev_max < MAX_SCSI_TAPES)
- st_template.dev_max = MAX_SCSI_TAPES;
+ if (st_template.dev_max < ST_MAX_TAPES)
+ st_template.dev_max = ST_MAX_TAPES;
scsi_tapes =
(Scsi_Tape *) scsi_init_malloc(st_template.dev_max * sizeof(Scsi_Tape),
GFP_ATOMIC);
@@ -2309,10 +2263,11 @@
if (st_buffers != NULL) {
for (i=0; i < st_nbr_buffers; i++)
if (st_buffers[i] != NULL) {
- scsi_init_free((char *) st_buffers[i]->b_data, st_buffer_size);
+ scsi_init_free((char *) st_buffers[i]->b_data,
+ st_buffers[i]->buffer_size);
scsi_init_free((char *) st_buffers[i], sizeof(ST_buffer));
}
-
+
scsi_init_free((char *) st_buffers,
st_template.dev_max * sizeof(ST_buffer *));
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this