Commit 27c43263 authored by Linus Torvalds's avatar Linus Torvalds

Import 0.99.14i

parent 3b100d90
...@@ -922,7 +922,11 @@ static int check_sense (Scsi_Cmnd * SCpnt) ...@@ -922,7 +922,11 @@ static int check_sense (Scsi_Cmnd * SCpnt)
switch (SCpnt->sense_buffer[2] & 0xf) switch (SCpnt->sense_buffer[2] & 0xf)
{ {
case NO_SENSE: case NO_SENSE:
return 0;
case RECOVERED_ERROR: case RECOVERED_ERROR:
if (scsi_devices[SCpnt->index].type == TYPE_TAPE)
return SUGGEST_IS_OK;
else
return 0; return 0;
case ABORTED_COMMAND: case ABORTED_COMMAND:
...@@ -1041,6 +1045,8 @@ static void scsi_done (Scsi_Cmnd * SCpnt) ...@@ -1041,6 +1045,8 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
update_timeout(SCpnt, oldto); update_timeout(SCpnt, oldto);
status = REDO; status = REDO;
break; break;
case SUGGEST_IS_OK:
break;
case SUGGEST_REMAP: case SUGGEST_REMAP:
case SUGGEST_RETRY: case SUGGEST_RETRY:
#ifdef DEBUG #ifdef DEBUG
......
...@@ -192,6 +192,7 @@ extern const unsigned char scsi_command_size[8]; ...@@ -192,6 +192,7 @@ extern const unsigned char scsi_command_size[8];
#define SUGGEST_REMAP 0x30 #define SUGGEST_REMAP 0x30
#define SUGGEST_DIE 0x40 #define SUGGEST_DIE 0x40
#define SUGGEST_SENSE 0x80 #define SUGGEST_SENSE 0x80
#define SUGGEST_IS_OK 0xff
#define DRIVER_SENSE 0x08 #define DRIVER_SENSE 0x08
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
History: History:
Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara. Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
Contribution and ideas from several people including Eric Youngdale and
Wolfgang Denk.
Features: Features:
- support for different block sizes and internal buffering - support for different block sizes and internal buffering
...@@ -25,15 +27,16 @@ ...@@ -25,15 +27,16 @@
Nonrewind device has the minor number equal to tape number + 128. Nonrewind device has the minor number equal to tape number + 128.
Problems: Problems:
The end of media detection may not work correctly because of the buffering. The end of media detection works correctly in writing only if the drive
If you want to do multiple tape backups relying on end of tape detection, writes the buffer contents after the early-warning mark. If you want to
you should disable write behind and in addition to that check that the be sure that EOM is reported correctly, you should uncomment the line
tapes are readable. defining ST_NO_DELAYED_WRITES. Note that when delayed writes are disabled
each write byte count must be an integral number of blocks.
Copyright 1992, 1993 Kai Makisara Copyright 1992, 1993 Kai Makisara
email makisara@vtinsx.ins.vtt.fi or Kai.Makisara@vtt.fi email makisara@vtinsx.ins.vtt.fi or Kai.Makisara@vtt.fi
Last modified: Sat Jul 10 17:40:05 1993 by root Last modified: Thu Nov 25 21:49:02 1993 by root@kai.home
*/ */
#include <linux/fs.h> #include <linux/fs.h>
...@@ -52,10 +55,7 @@ ...@@ -52,10 +55,7 @@
#include "scsi.h" #include "scsi.h"
#include "scsi_ioctl.h" #include "scsi_ioctl.h"
#include "st.h" #include "st.h"
#include "constants.h"
#define MAX_RETRIES 0
#define MAX_READY_RETRIES 5
#define NO_TAPE NOT_READY
/* Uncomment the following if you want the rewind, etc. commands return /* Uncomment the following if you want the rewind, etc. commands return
before command completion. */ before command completion. */
...@@ -66,26 +66,43 @@ ...@@ -66,26 +66,43 @@
to the filemarks even wihout ST_IN_FILE_POS defined */ to the filemarks even wihout ST_IN_FILE_POS defined */
/* #define ST_IN_FILE_POS */ /* #define ST_IN_FILE_POS */
/* #define DEBUG */ /* Uncomment the following if you want recovered write errors to be
fatal. */
/* #define ST_RECOVERED_WRITE_FATAL */
#define ST_TIMEOUT 9000 /* Uncomment the following if you want all data from a write command to
#define ST_LONG_TIMEOUT 200000 be written to tape before the command returns. Disables write-behind. */
/* #define ST_NO_DELAYED_WRITES */
/* Number of ST_BLOCK_SIZE blocks in the buffers */ /* Number of ST_BLOCK_SIZE blocks in the buffers */
#define ST_BUFFER_BLOCKS 64 #define ST_BUFFER_BLOCKS 64
/* Write-behind can be disabled by setting ST_WRITE_THRESHOLD_BLOCKS equal to or /* Write-behind can be disabled by setting ST_WRITE_THRESHOLD_BLOCKS equal
larger than ST_BUFFER_BLOCKS */ to or larger than ST_BUFFER_BLOCKS */
#define ST_WRITE_THRESHOLD_BLOCKS 60 #define ST_WRITE_THRESHOLD_BLOCKS 60
#define ST_BLOCK_SIZE 512 #define ST_BLOCK_SIZE 512
#define ST_BUFFER_SIZE (ST_BUFFER_BLOCKS * ST_BLOCK_SIZE) #define ST_BUFFER_SIZE (ST_BUFFER_BLOCKS * ST_BLOCK_SIZE)
#define ST_WRITE_THRESHOLD (ST_WRITE_THRESHOLD_BLOCKS * ST_BLOCK_SIZE) #define ST_WRITE_THRESHOLD (ST_WRITE_THRESHOLD_BLOCKS * ST_BLOCK_SIZE)
#ifdef ST_NO_DELAYED_WRITES
#undef ST_WRITE_THRESHOLD_BLOCKS
#define ST_WRITE_THRESHOLD_BLOCKS ST_BUFFER_BLOCKS
#endif
/* The buffer size should fit into the 24 bits reserved for length in the /* The buffer size should fit into the 24 bits reserved for length in the
6-byte SCSI read and write commands. */ 6-byte SCSI read and write commands. */
#if ST_BUFFER_SIZE >= (2 << 24 - 1) #if ST_BUFFER_SIZE >= (2 << 24 - 1)
#error "Buffer size should not exceed (2 << 24 - 1) bytes!" #error "Buffer size should not exceed (2 << 24 - 1) bytes!"
#endif #endif
/* #define DEBUG */
#define MAX_RETRIES 0
#define MAX_READY_RETRIES 5
#define NO_TAPE NOT_READY
#define ST_TIMEOUT 9000
#define ST_LONG_TIMEOUT 200000
static int st_nbr_buffers; static int st_nbr_buffers;
static ST_buffer *st_buffers[2]; static ST_buffer *st_buffers[2];
...@@ -99,72 +116,113 @@ static int st_int_ioctl(struct inode * inode,struct file * file, ...@@ -99,72 +116,113 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
/* Wakeup from interrupt */
static void st_sleep_done (Scsi_Cmnd * SCpnt)
{
int st_nbr;
if ((st_nbr = SCpnt->request.dev) < NR_ST && st_nbr >= 0) {
if (scsi_tapes[st_nbr].buffer->writing &&
(SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
(SCpnt->sense_buffer[2] & 0x40))
scsi_tapes[st_nbr].buffer->last_result = INT_MAX;
else
scsi_tapes[st_nbr].buffer->last_result = SCpnt->result;
if (scsi_tapes[st_nbr].buffer->writing)
SCpnt->request.dev = -1;
else
SCpnt->request.dev = 0xffff;
if (scsi_tapes[st_nbr].buffer->writing <= 0)
wake_up( &scsi_tapes[st_nbr].waiting );
}
#ifdef DEBUG
else
printk("st?: Illegal interrupt device %x\n", st_nbr);
#endif
}
/* Convert the result to success code */ /* Convert the result to success code */
static int st_chk_result(Scsi_Cmnd * SCpnt) static int
st_chk_result(Scsi_Cmnd * SCpnt)
{ {
#ifdef DEBUG
int dev = SCpnt->request.dev; int dev = SCpnt->request.dev;
#endif
int result = SCpnt->result; int result = SCpnt->result;
unsigned char * sense = SCpnt->sense_buffer; unsigned char * sense = SCpnt->sense_buffer;
char *stp;
if (!result) if (!result && SCpnt->sense_buffer[0] == 0)
return 0; return 0;
#ifdef DEBUG #ifdef DEBUG
printk("st%d: Error: %x\n", dev, result); printk("st%d: Error: %x\n", dev, result);
print_sense("st", SCpnt); print_sense("st", SCpnt);
#endif #endif
/* if ((sense[0] & 0x70) == 0x70 &&
((sense[2] & 0x80) ))
return 0; */
if ((sense[0] & 0x70) == 0x70 && if ((sense[0] & 0x70) == 0x70 &&
((sense[2] & 0x80) /* || ((sense[2] & 0x0f) == 8) */ )) sense[2] == RECOVERED_ERROR
#ifdef ST_RECOVERED_WRITE_FATAL
&& SCpnt->cmnd[0] != WRITE_6
&& SCpnt->cmnd[0] != WRITE_FILEMARKS
#endif
) {
scsi_tapes[dev].recover_count++;
if (SCpnt->cmnd[0] == READ_6)
stp = "read";
else if (SCpnt->cmnd[0] == WRITE_6)
stp = "write";
else
stp = "ioctl";
printk("st%d: Recovered %s error (%d).\n", dev, stp,
scsi_tapes[dev].recover_count);
return 0; return 0;
}
return (-EIO); return (-EIO);
} }
/* Wakeup from interrupt */
static void
st_sleep_done (Scsi_Cmnd * SCpnt)
{
int st_nbr, remainder;
Scsi_Tape * STp;
if ((st_nbr = SCpnt->request.dev) < NR_ST && st_nbr >= 0) {
STp = &(scsi_tapes[st_nbr]);
if ((STp->buffer)->writing &&
(SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
(SCpnt->sense_buffer[2] & 0x40)) {
/* EOM at write-behind, has all been written? */
if ((SCpnt->sense_buffer[0] & 0x80) != 0)
remainder = (SCpnt->sense_buffer[3] << 24) |
(SCpnt->sense_buffer[4] << 16) |
(SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6];
else
remainder = 0;
if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW ||
remainder > 0)
(STp->buffer)->last_result = SCpnt->result; /* Error */
else
(STp->buffer)->last_result = INT_MAX; /* OK */
}
else
(STp->buffer)->last_result = SCpnt->result;
(STp->buffer)->last_result_fatal = st_chk_result(SCpnt);
if ((STp->buffer)->writing)
SCpnt->request.dev = -1;
else
SCpnt->request.dev = 0xffff;
if ((STp->buffer)->writing <= 0)
wake_up( &(STp->waiting) );
}
#ifdef DEBUG
else
printk("st?: Illegal interrupt device %x\n", st_nbr);
#endif
}
#if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS #if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS
/* Handle the write-behind checking */ /* Handle the write-behind checking */
static void write_behind_check(int dev) static void
write_behind_check(int dev)
{ {
Scsi_Tape * STp;
ST_buffer * STbuffer;
STp = &(scsi_tapes[dev]);
STbuffer = STp->buffer;
cli(); cli();
if (scsi_tapes[dev].buffer->last_result < 0) { if (STbuffer->last_result < 0) {
scsi_tapes[dev].buffer->writing = (- scsi_tapes[dev].buffer->writing); STbuffer->writing = (- STbuffer->writing);
sleep_on( &scsi_tapes[dev].waiting ); sleep_on( &(STp->waiting) );
scsi_tapes[dev].buffer->writing = (- scsi_tapes[dev].buffer->writing); STbuffer->writing = (- STbuffer->writing);
} }
sti(); sti();
if (scsi_tapes[dev].buffer->writing < scsi_tapes[dev].buffer->buffer_bytes) if (STbuffer->writing < STbuffer->buffer_bytes)
memcpy(scsi_tapes[dev].buffer->b_data, memcpy(STbuffer->b_data,
scsi_tapes[dev].buffer->b_data + scsi_tapes[dev].buffer->writing, STbuffer->b_data + STbuffer->writing,
scsi_tapes[dev].buffer->buffer_bytes - STbuffer->buffer_bytes - STbuffer->writing);
scsi_tapes[dev].buffer->writing); STbuffer->buffer_bytes -= STbuffer->writing;
scsi_tapes[dev].buffer->buffer_bytes -= scsi_tapes[dev].buffer->writing; STbuffer->writing = 0;
scsi_tapes[dev].buffer->writing = 0;
return; return;
} }
...@@ -172,63 +230,72 @@ static void write_behind_check(int dev) ...@@ -172,63 +230,72 @@ static void write_behind_check(int dev)
/* Flush the write buffer (never need to write if variable blocksize). */ /* Flush the write buffer (never need to write if variable blocksize). */
static int flush_write_buffer(int dev) static int
flush_write_buffer(int dev)
{ {
int offset, transfer, blks; int offset, transfer, blks;
int result; int result;
unsigned char cmd[10]; unsigned char cmd[10];
Scsi_Cmnd *SCpnt; Scsi_Cmnd *SCpnt;
Scsi_Tape *STp = &(scsi_tapes[dev]);
#if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS #if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS
if (scsi_tapes[dev].buffer->writing) { if ((STp->buffer)->writing) {
write_behind_check(dev); write_behind_check(dev);
if (scsi_tapes[dev].buffer->last_result) { if ((STp->buffer)->last_result_fatal) {
#ifdef DEBUG #ifdef DEBUG
printk("st%d: Async write error %x.\n", dev, printk("st%d: Async write error %x.\n", dev,
scsi_tapes[dev].buffer->last_result); (STp->buffer)->last_result);
#endif #endif
if ((STp->buffer)->last_result == INT_MAX)
return (-ENOSPC);
return (-EIO); return (-EIO);
} }
} }
#endif #endif
result = 0; result = 0;
if (scsi_tapes[dev].dirty==1) { if (STp->dirty == 1) {
SCpnt = allocate_device(NULL, scsi_tapes[dev].device->index, 1); SCpnt = allocate_device(NULL, (STp->device)->index, 1);
offset = scsi_tapes[dev].buffer->buffer_bytes; offset = (STp->buffer)->buffer_bytes;
transfer = ((offset + scsi_tapes[dev].block_size - 1) / transfer = ((offset + STp->block_size - 1) /
scsi_tapes[dev].block_size) * scsi_tapes[dev].block_size; STp->block_size) * STp->block_size;
#ifdef DEBUG #ifdef DEBUG
printk("st%d: Flushing %d bytes.\n", dev, transfer); printk("st%d: Flushing %d bytes.\n", dev, transfer);
#endif #endif
memset(scsi_tapes[dev].buffer->b_data + offset, 0, transfer - offset); memset((STp->buffer)->b_data + offset, 0, transfer - offset);
SCpnt->sense_buffer[0] = 0; SCpnt->sense_buffer[0] = 0;
memset(cmd, 0, 10); memset(cmd, 0, 10);
cmd[0] = WRITE_6; cmd[0] = WRITE_6;
cmd[1] = 1; cmd[1] = 1;
blks = transfer / scsi_tapes[dev].block_size; blks = transfer / STp->block_size;
cmd[2] = blks >> 16; cmd[2] = blks >> 16;
cmd[3] = blks >> 8; cmd[3] = blks >> 8;
cmd[4] = blks; cmd[4] = blks;
SCpnt->request.dev = dev; SCpnt->request.dev = dev;
scsi_do_cmd (SCpnt, scsi_do_cmd (SCpnt,
(void *) cmd, scsi_tapes[dev].buffer->b_data, transfer, (void *) cmd, (STp->buffer)->b_data, transfer,
st_sleep_done, ST_TIMEOUT, MAX_RETRIES); st_sleep_done, ST_TIMEOUT, MAX_RETRIES);
if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting ); if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) );
if (SCpnt->result != 0) { if ((STp->buffer)->last_result_fatal != 0) {
printk("st%d: Error on flush:\n", dev); printk("st%d: Error on flush.\n", dev);
#ifdef DEBUG if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
st_chk_result(SCpnt); (SCpnt->sense_buffer[2] & 0x40) &&
#endif (SCpnt->sense_buffer[2] & 0x0f) != VOLUME_OVERFLOW) {
STp->dirty = 0;
(STp->buffer)->buffer_bytes = 0;
result = (-ENOSPC);
}
else
result = (-EIO); result = (-EIO);
} }
else { else {
scsi_tapes[dev].dirty = 0; STp->dirty = 0;
scsi_tapes[dev].buffer->buffer_bytes = 0; (STp->buffer)->buffer_bytes = 0;
} }
SCpnt->request.dev = -1; /* Mark as not busy */ SCpnt->request.dev = -1; /* Mark as not busy */
} }
...@@ -238,52 +305,63 @@ static int flush_write_buffer(int dev) ...@@ -238,52 +305,63 @@ static int flush_write_buffer(int dev)
/* Flush the tape buffer. The tape will be positioned correctly unless /* Flush the tape buffer. The tape will be positioned correctly unless
seek_next is true. */ seek_next is true. */
static int flush_buffer(struct inode * inode, struct file * filp, static int
int seek_next) flush_buffer(struct inode * inode, struct file * filp, int seek_next)
{ {
int dev; int dev;
int backspace, result; int backspace, result;
Scsi_Tape * STp;
ST_buffer * STbuffer;
dev = MINOR(inode->i_rdev) & 127; dev = MINOR(inode->i_rdev) & 127;
STp = &(scsi_tapes[dev]);
STbuffer = STp->buffer;
if (scsi_tapes[dev].rw == 2) /* Writing */ if (STp->rw == ST_WRITING) /* Writing */
return flush_write_buffer(dev); return flush_write_buffer(dev);
if (scsi_tapes[dev].block_size == 0) if (STp->block_size == 0)
return 0; return 0;
backspace = (scsi_tapes[dev].buffer->buffer_bytes + backspace = ((STp->buffer)->buffer_bytes +
scsi_tapes[dev].buffer->read_pointer) / scsi_tapes[dev].block_size - (STp->buffer)->read_pointer) / STp->block_size -
(scsi_tapes[dev].buffer->read_pointer + scsi_tapes[dev].block_size - 1) / ((STp->buffer)->read_pointer + STp->block_size - 1) /
scsi_tapes[dev].block_size; STp->block_size;
scsi_tapes[dev].buffer->buffer_bytes = 0; (STp->buffer)->buffer_bytes = 0;
scsi_tapes[dev].buffer->read_pointer = 0; (STp->buffer)->read_pointer = 0;
result = 0; result = 0;
if (!seek_next && backspace > 0) { if (!seek_next) {
result = st_int_ioctl(inode, filp, MTBSR, backspace); if ((STp->eof == ST_FM) && !STp->eof_hit) {
result = st_int_ioctl(inode, filp, MTBSF, 1); /* Back over the EOF hit */
if (!result) { if (!result) {
scsi_tapes[dev].eof = 0; STp->eof = ST_NOEOF;
scsi_tapes[dev].eof_hit = 0; STp->eof_hit = 0;
} }
} }
if (!result && backspace > 0)
result = st_int_ioctl(inode, filp, MTBSR, backspace);
}
return result; return result;
} }
/* Open the device */ /* Open the device */
static int scsi_tape_open(struct inode * inode, struct file * filp) static int
scsi_tape_open(struct inode * inode, struct file * filp)
{ {
int dev; int dev;
unsigned short flags; unsigned short flags;
int i; int i;
unsigned char cmd[10]; unsigned char cmd[10];
Scsi_Cmnd * SCpnt; Scsi_Cmnd * SCpnt;
Scsi_Tape * STp;
dev = MINOR(inode->i_rdev) & 127; dev = MINOR(inode->i_rdev) & 127;
if (dev >= NR_ST) if (dev >= NR_ST)
return (-ENODEV); return (-ENODEV);
if (scsi_tapes[dev].in_use) { STp = &(scsi_tapes[dev]);
if (STp->in_use) {
printk("st%d: Device already in use.\n", dev); printk("st%d: Device already in use.\n", dev);
return (-EBUSY); return (-EBUSY);
} }
...@@ -296,20 +374,21 @@ static int scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -296,20 +374,21 @@ static int scsi_tape_open(struct inode * inode, struct file * filp)
printk("st%d: No free buffers.\n", dev); printk("st%d: No free buffers.\n", dev);
return (-EBUSY); return (-EBUSY);
} }
st_buffers[i]->in_use = 1; STp->buffer = st_buffers[i];
st_buffers[i]->writing = 0; (STp->buffer)->in_use = 1;
scsi_tapes[dev].buffer = st_buffers[i]; (STp->buffer)->writing = 0;
scsi_tapes[dev].in_use = 1; STp->in_use = 1;
flags = filp->f_flags; flags = filp->f_flags;
scsi_tapes[dev].write_prot = ((flags & O_ACCMODE) == O_RDONLY); STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
scsi_tapes[dev].dirty = 0; STp->dirty = 0;
scsi_tapes[dev].rw = 0; STp->rw = ST_IDLE;
scsi_tapes[dev].eof = 0; STp->eof = ST_NOEOF;
scsi_tapes[dev].eof_hit = 0; STp->eof_hit = 0;
STp->recover_count = 0;
SCpnt = allocate_device(NULL, scsi_tapes[dev].device->index, 1); SCpnt = allocate_device(NULL, (STp->device)->index, 1);
if (!SCpnt) { if (!SCpnt) {
printk("st%d: Tape request not allocated", dev); printk("st%d: Tape request not allocated", dev);
return (-EBUSY); return (-EBUSY);
...@@ -320,40 +399,34 @@ static int scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -320,40 +399,34 @@ static int scsi_tape_open(struct inode * inode, struct file * filp)
cmd[0] = TEST_UNIT_READY; cmd[0] = TEST_UNIT_READY;
SCpnt->request.dev = dev; SCpnt->request.dev = dev;
scsi_do_cmd(SCpnt, scsi_do_cmd(SCpnt,
(void *) cmd, (void *) scsi_tapes[dev].buffer->b_data, (void *) cmd, (void *) (STp->buffer)->b_data,
ST_BLOCK_SIZE, st_sleep_done, ST_LONG_TIMEOUT, ST_BLOCK_SIZE, st_sleep_done, ST_LONG_TIMEOUT,
MAX_READY_RETRIES); MAX_READY_RETRIES);
if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting ); if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) );
if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
(SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ (SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
#ifdef DEBUG
print_sense("st", SCpnt);
#endif
SCpnt->sense_buffer[0]=0; SCpnt->sense_buffer[0]=0;
memset ((void *) &cmd[0], 0, 10); memset ((void *) &cmd[0], 0, 10);
cmd[0] = TEST_UNIT_READY; cmd[0] = TEST_UNIT_READY;
SCpnt->request.dev = dev; SCpnt->request.dev = dev;
scsi_do_cmd(SCpnt, scsi_do_cmd(SCpnt,
(void *) cmd, (void *) scsi_tapes[dev].buffer->b_data, (void *) cmd, (void *) (STp->buffer)->b_data,
ST_BLOCK_SIZE, st_sleep_done, ST_LONG_TIMEOUT, ST_BLOCK_SIZE, st_sleep_done, ST_LONG_TIMEOUT,
MAX_READY_RETRIES); MAX_READY_RETRIES);
if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting ); if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) );
} }
if (SCpnt->result != 0) { if ((STp->buffer)->last_result_fatal != 0) {
#ifdef DEBUG
print_sense("st", SCpnt);
#endif
if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
(SCpnt->sense_buffer[2] & 0x0f) == NO_TAPE) (SCpnt->sense_buffer[2] & 0x0f) == NO_TAPE)
printk("st%d: No tape.\n", dev); printk("st%d: No tape.\n", dev);
else else
printk("st%d: Error %x.\n", dev, SCpnt->result); printk("st%d: Error %x.\n", dev, SCpnt->result);
scsi_tapes[dev].buffer->in_use = 0; (STp->buffer)->in_use = 0;
scsi_tapes[dev].in_use = 0; STp->in_use = 0;
SCpnt->request.dev = -1; /* Mark as not busy */ SCpnt->request.dev = -1; /* Mark as not busy */
return (-EIO); return (-EIO);
} }
...@@ -363,23 +436,23 @@ static int scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -363,23 +436,23 @@ static int scsi_tape_open(struct inode * inode, struct file * filp)
cmd[0] = READ_BLOCK_LIMITS; cmd[0] = READ_BLOCK_LIMITS;
SCpnt->request.dev = dev; SCpnt->request.dev = dev;
scsi_do_cmd(SCpnt, scsi_do_cmd(SCpnt,
(void *) cmd, (void *) scsi_tapes[dev].buffer->b_data, (void *) cmd, (void *) (STp->buffer)->b_data,
ST_BLOCK_SIZE, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES); ST_BLOCK_SIZE, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES);
if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting ); if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) );
if (!SCpnt->result && !SCpnt->sense_buffer[0]) { if (!SCpnt->result && !SCpnt->sense_buffer[0]) {
scsi_tapes[dev].max_block = (scsi_tapes[dev].buffer->b_data[1] << 16) | STp->max_block = ((STp->buffer)->b_data[1] << 16) |
(scsi_tapes[dev].buffer->b_data[2] << 8) | scsi_tapes[dev].buffer->b_data[3]; ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3];
scsi_tapes[dev].min_block = (scsi_tapes[dev].buffer->b_data[4] << 8) | STp->min_block = ((STp->buffer)->b_data[4] << 8) |
scsi_tapes[dev].buffer->b_data[5]; (STp->buffer)->b_data[5];
#ifdef DEBUG #ifdef DEBUG
printk("st%d: Block limits %d - %d bytes.\n", dev, scsi_tapes[dev].min_block, printk("st%d: Block limits %d - %d bytes.\n", dev, STp->min_block,
scsi_tapes[dev].max_block); STp->max_block);
#endif #endif
} }
else { else {
scsi_tapes[dev].min_block = scsi_tapes[dev].max_block = (-1); STp->min_block = STp->max_block = (-1);
#ifdef DEBUG #ifdef DEBUG
printk("st%d: Can't read block limits.\n", dev); printk("st%d: Can't read block limits.\n", dev);
#endif #endif
...@@ -391,73 +464,69 @@ static int scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -391,73 +464,69 @@ static int scsi_tape_open(struct inode * inode, struct file * filp)
cmd[4] = 12; cmd[4] = 12;
SCpnt->request.dev = dev; SCpnt->request.dev = dev;
scsi_do_cmd(SCpnt, scsi_do_cmd(SCpnt,
(void *) cmd, (void *) scsi_tapes[dev].buffer->b_data, (void *) cmd, (void *) (STp->buffer)->b_data,
ST_BLOCK_SIZE, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES); ST_BLOCK_SIZE, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES);
if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting ); if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) );
i = st_chk_result(SCpnt); if ((STp->buffer)->last_result_fatal != 0) {
if (i) {
#ifdef DEBUG #ifdef DEBUG
printk("st%d: No Mode Sense.\n", dev); printk("st%d: No Mode Sense.\n", dev);
#endif #endif
scsi_tapes[dev].buffer->b_data[2] = (STp->buffer)->b_data[2] =
scsi_tapes[dev].buffer->b_data[3] = 0; (STp->buffer)->b_data[3] = 0;
} }
SCpnt->request.dev = -1; /* Mark as not busy */ SCpnt->request.dev = -1; /* Mark as not busy */
#ifdef DEBUG #ifdef DEBUG
printk("st%d: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n", dev, printk("st%d: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n", dev,
scsi_tapes[dev].buffer->b_data[0], scsi_tapes[dev].buffer->b_data[1], (STp->buffer)->b_data[0], (STp->buffer)->b_data[1],
scsi_tapes[dev].buffer->b_data[2], scsi_tapes[dev].buffer->b_data[3]); (STp->buffer)->b_data[2], (STp->buffer)->b_data[3]);
#endif #endif
if (scsi_tapes[dev].buffer->b_data[3] >= 8) { if ((STp->buffer)->b_data[3] >= 8) {
scsi_tapes[dev].drv_buffer = (scsi_tapes[dev].buffer->b_data[2] >> 4) & 7; STp->drv_buffer = ((STp->buffer)->b_data[2] >> 4) & 7;
scsi_tapes[dev].density = scsi_tapes[dev].buffer->b_data[4]; STp->density = (STp->buffer)->b_data[4];
scsi_tapes[dev].block_size = scsi_tapes[dev].buffer->b_data[9] * 65536 + STp->block_size = (STp->buffer)->b_data[9] * 65536 +
scsi_tapes[dev].buffer->b_data[10] * 256 + scsi_tapes[dev].buffer->b_data[11]; (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11];
#ifdef DEBUG #ifdef DEBUG
printk("st%d: Density %x, tape length: %x, blocksize: %d, drv buffer: %d\n", dev, printk(
scsi_tapes[dev].buffer->b_data[4], scsi_tapes[dev].buffer->b_data[5] * "st%d: Density %x, tape length: %x, blocksize: %d, drv buffer: %d\n",
65536 + scsi_tapes[dev].buffer->b_data[6] * 256 + dev, STp->density, (STp->buffer)->b_data[5] * 65536 +
scsi_tapes[dev].buffer->b_data[7], scsi_tapes[dev].buffer->b_data[9] * (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7],
65536 + scsi_tapes[dev].buffer->b_data[10] * 256 + STp->block_size, STp->drv_buffer);
scsi_tapes[dev].buffer->b_data[11],
scsi_tapes[dev].drv_buffer);
#endif #endif
if (scsi_tapes[dev].block_size > ST_BUFFER_SIZE) { if (STp->block_size > ST_BUFFER_SIZE) {
printk("st%d: Blocksize %d too large for buffer.\n", dev, printk("st%d: Blocksize %d too large for buffer.\n", dev,
scsi_tapes[dev].block_size); STp->block_size);
scsi_tapes[dev].buffer->in_use = 0; (STp->buffer)->in_use = 0;
scsi_tapes[dev].in_use = 0; STp->in_use = 0;
return (-EIO); return (-EIO);
} }
} }
else else
scsi_tapes[dev].block_size = ST_BLOCK_SIZE; STp->block_size = ST_BLOCK_SIZE;
if (scsi_tapes[dev].block_size > 0) { if (STp->block_size > 0) {
scsi_tapes[dev].buffer->buffer_blocks = (STp->buffer)->buffer_blocks = ST_BUFFER_SIZE / STp->block_size;
ST_BUFFER_SIZE / scsi_tapes[dev].block_size; (STp->buffer)->buffer_size =
scsi_tapes[dev].buffer->buffer_size = (STp->buffer)->buffer_blocks * STp->block_size;
scsi_tapes[dev].buffer->buffer_blocks * scsi_tapes[dev].block_size;
} }
else { else {
scsi_tapes[dev].buffer->buffer_blocks = 1; (STp->buffer)->buffer_blocks = 1;
scsi_tapes[dev].buffer->buffer_size = ST_BUFFER_SIZE; (STp->buffer)->buffer_size = ST_BUFFER_SIZE;
} }
scsi_tapes[dev].buffer->buffer_bytes = scsi_tapes[dev].buffer->read_pointer = 0; (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;
#ifdef DEBUG #ifdef DEBUG
printk("st%d: Block size: %d, buffer size: %d (%d blocks).\n", dev, printk("st%d: Block size: %d, buffer size: %d (%d blocks).\n", dev,
scsi_tapes[dev].block_size, scsi_tapes[dev].buffer->buffer_size, STp->block_size, (STp->buffer)->buffer_size,
scsi_tapes[dev].buffer->buffer_blocks); (STp->buffer)->buffer_blocks);
#endif #endif
if (scsi_tapes[dev].buffer->b_data[2] & 0x80) { if ((STp->buffer)->b_data[2] & 0x80) {
scsi_tapes[dev].write_prot = 1; STp->write_prot = 1;
#ifdef DEBUG #ifdef DEBUG
printk( "st%d: Write protected\n", dev); printk( "st%d: Write protected\n", dev);
#endif #endif
...@@ -468,19 +537,22 @@ static int scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -468,19 +537,22 @@ static int scsi_tape_open(struct inode * inode, struct file * filp)
/* Close the device*/ /* Close the device*/
static void scsi_tape_close(struct inode * inode, struct file * filp) static void
scsi_tape_close(struct inode * inode, struct file * filp)
{ {
int dev; int dev;
int result; int result;
int rewind; int rewind;
static unsigned char cmd[10]; static unsigned char cmd[10];
Scsi_Cmnd * SCpnt; Scsi_Cmnd * SCpnt;
Scsi_Tape * STp;
dev = MINOR(inode->i_rdev); dev = MINOR(inode->i_rdev);
rewind = (dev & 0x80) == 0; rewind = (dev & 0x80) == 0;
dev = dev & 127; dev = dev & 127;
STp = &(scsi_tapes[dev]);
if ( scsi_tapes[dev].rw == 2) { if ( STp->rw == ST_WRITING) {
result = flush_write_buffer(dev); result = flush_write_buffer(dev);
...@@ -488,8 +560,8 @@ static void scsi_tape_close(struct inode * inode, struct file * filp) ...@@ -488,8 +560,8 @@ static void scsi_tape_close(struct inode * inode, struct file * filp)
printk("st%d: File length %d bytes.\n", dev, filp->f_pos); printk("st%d: File length %d bytes.\n", dev, filp->f_pos);
#endif #endif
if (!result) { if (result == 0 || result == (-ENOSPC)) {
SCpnt = allocate_device(NULL, scsi_tapes[dev].device->index, 1); SCpnt = allocate_device(NULL, (STp->device)->index, 1);
SCpnt->sense_buffer[0] = 0; SCpnt->sense_buffer[0] = 0;
memset(cmd, 0, 10); memset(cmd, 0, 10);
...@@ -497,17 +569,14 @@ static void scsi_tape_close(struct inode * inode, struct file * filp) ...@@ -497,17 +569,14 @@ static void scsi_tape_close(struct inode * inode, struct file * filp)
cmd[4] = 1; cmd[4] = 1;
SCpnt->request.dev = dev; SCpnt->request.dev = dev;
scsi_do_cmd( SCpnt, scsi_do_cmd( SCpnt,
(void *) cmd, (void *) scsi_tapes[dev].buffer->b_data, (void *) cmd, (void *) (STp->buffer)->b_data,
ST_BLOCK_SIZE, st_sleep_done, ST_TIMEOUT, MAX_RETRIES); ST_BLOCK_SIZE, st_sleep_done, ST_TIMEOUT, MAX_RETRIES);
if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting ); if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) );
if (SCpnt->result) { if ((STp->buffer)->last_result_fatal != 0)
printk("st%d: Error on write filemark.\n", dev); printk("st%d: Error on write filemark.\n", dev);
#ifdef DEBUG
st_chk_result(SCpnt);
#endif
}
SCpnt->request.dev = -1; /* Mark as not busy */ SCpnt->request.dev = -1; /* Mark as not busy */
} }
...@@ -516,9 +585,10 @@ static void scsi_tape_close(struct inode * inode, struct file * filp) ...@@ -516,9 +585,10 @@ static void scsi_tape_close(struct inode * inode, struct file * filp)
#endif #endif
} }
else if (!rewind) { else if (!rewind) {
if ((scsi_tapes[dev].eof == 1) && !scsi_tapes[dev].eof_hit) #ifndef ST_IN_FILE_POS
if ((STp->eof == ST_FM) && !STp->eof_hit)
st_int_ioctl(inode, filp, MTBSF, 1); /* Back over the EOF hit */ st_int_ioctl(inode, filp, MTBSF, 1); /* Back over the EOF hit */
#ifdef ST_IN_FILE_POS #else
flush_buffer(inode, filp, 0); flush_buffer(inode, filp, 0);
#endif #endif
} }
...@@ -526,117 +596,169 @@ static void scsi_tape_close(struct inode * inode, struct file * filp) ...@@ -526,117 +596,169 @@ static void scsi_tape_close(struct inode * inode, struct file * filp)
if (rewind) if (rewind)
st_int_ioctl(inode, filp, MTREW, 1); st_int_ioctl(inode, filp, MTREW, 1);
scsi_tapes[dev].buffer->in_use = 0; (STp->buffer)->in_use = 0;
scsi_tapes[dev].in_use = 0; STp->in_use = 0;
return; return;
} }
/* Write command */ /* Write command */
int st_write(struct inode * inode, struct file * filp, char * buf, int count) static int
st_write(struct inode * inode, struct file * filp, char * buf, int count)
{ {
int dev; int dev;
int total, do_count, blks, retval; int total, do_count, blks, retval, transfer;
int write_threshold;
static unsigned char cmd[10]; static unsigned char cmd[10];
char *b_point; char *b_point;
Scsi_Cmnd * SCpnt; Scsi_Cmnd * SCpnt;
Scsi_Tape * STp;
dev = MINOR(inode->i_rdev) & 127; dev = MINOR(inode->i_rdev) & 127;
STp = &(scsi_tapes[dev]);
#ifdef DEBUG #ifdef DEBUG
if (!scsi_tapes[dev].in_use) { if (!STp->in_use) {
printk("st%d: Incorrect device.\n", dev); printk("st%d: Incorrect device.\n", dev);
return (-EIO); return (-EIO);
} }
#endif #endif
if (scsi_tapes[dev].write_prot) if (STp->write_prot)
return (-EACCES); return (-EACCES);
if (scsi_tapes[dev].block_size == 0 && count > ST_BUFFER_SIZE) if (STp->block_size == 0 && count > ST_BUFFER_SIZE)
return (-EOVERFLOW); return (-EOVERFLOW);
if (scsi_tapes[dev].rw == 1) { if (STp->rw == ST_READING) {
retval = flush_buffer(inode, filp, 0); retval = flush_buffer(inode, filp, 0);
if (retval) if (retval)
return retval; return retval;
scsi_tapes[dev].rw = 2; STp->rw = ST_WRITING;
} }
#if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS #if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS
if (scsi_tapes[dev].buffer->writing) { if ((STp->buffer)->writing) {
write_behind_check(dev); write_behind_check(dev);
if (scsi_tapes[dev].buffer->last_result) { if ((STp->buffer)->last_result_fatal) {
#ifdef DEBUG #ifdef DEBUG
printk("st%d: Async write error %x.\n", dev, printk("st%d: Async write error %x.\n", dev,
scsi_tapes[dev].buffer->last_result); (STp->buffer)->last_result);
#endif #endif
/*if (scsi_tapes[dev].buffer->last_result = INT_MAX) if ((STp->buffer)->last_result == INT_MAX) {
retval = (-ENOSPC); retval = (-ENOSPC); /* All has been written */
else */ STp->eof = ST_EOM_OK;
}
else
retval = (-EIO); retval = (-EIO);
return retval; return retval;
} }
} }
#endif #endif
SCpnt = allocate_device(NULL, scsi_tapes[dev].device->index, 1); if (STp->eof == ST_EOM_OK)
return (-ENOSPC);
else if (STp->eof == ST_EOM_ERROR)
return (-EIO);
#ifdef ST_NO_DELAYED_WRITES
if (STp->block_size != 0 && (count % STp->block_size) != 0)
return (-EIO); /* Write must be integral number of blocks */
write_threshold = 1;
#else
write_threshold = (STp->buffer)->buffer_size;
#endif
SCpnt = allocate_device(NULL, (STp->device)->index, 1);
total = count; total = count;
memset(cmd, 0, 10); memset(cmd, 0, 10);
cmd[0] = WRITE_6; cmd[0] = WRITE_6;
cmd[1] = (scsi_tapes[dev].block_size != 0); cmd[1] = (STp->block_size != 0);
scsi_tapes[dev].rw = 2; STp->rw = ST_WRITING;
b_point = buf; b_point = buf;
while( while(
#if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS #if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS
scsi_tapes[dev].block_size != 0 && STp->block_size != 0 &&
(scsi_tapes[dev].buffer->buffer_bytes + count) > ((STp->buffer)->buffer_bytes + count) >
scsi_tapes[dev].buffer->buffer_size) write_threshold)
#else #else
(scsi_tapes[dev].block_size == 0 && count > 0) || (STp->block_size == 0 && count > 0) ||
(scsi_tapes[dev].buffer->buffer_bytes + count) >= ((STp->buffer)->buffer_bytes + count) >=
scsi_tapes[dev].buffer->buffer_size) write_threshold)
#endif #endif
{ {
if (scsi_tapes[dev].block_size == 0) if (STp->block_size == 0)
do_count = count; do_count = count;
else else {
do_count = scsi_tapes[dev].buffer->buffer_size - do_count = (STp->buffer)->buffer_size - (STp->buffer)->buffer_bytes;
scsi_tapes[dev].buffer->buffer_bytes; if (do_count > count)
memcpy_fromfs(scsi_tapes[dev].buffer->b_data + do_count = count;
scsi_tapes[dev].buffer->buffer_bytes, b_point, do_count); }
memcpy_fromfs((STp->buffer)->b_data +
(STp->buffer)->buffer_bytes, b_point, do_count);
if (scsi_tapes[dev].block_size == 0) if (STp->block_size == 0)
blks = do_count; blks = do_count;
else else
blks = scsi_tapes[dev].buffer->buffer_blocks; blks = ((STp->buffer)->buffer_bytes + do_count) /
STp->block_size;
cmd[2] = blks >> 16; cmd[2] = blks >> 16;
cmd[3] = blks >> 8; cmd[3] = blks >> 8;
cmd[4] = blks; cmd[4] = blks;
SCpnt->sense_buffer[0] = 0; SCpnt->sense_buffer[0] = 0;
SCpnt->request.dev = dev; SCpnt->request.dev = dev;
scsi_do_cmd (SCpnt, scsi_do_cmd (SCpnt,
(void *) cmd, scsi_tapes[dev].buffer->b_data, (void *) cmd, (STp->buffer)->b_data,
scsi_tapes[dev].buffer->buffer_size, (STp->buffer)->buffer_size,
st_sleep_done, ST_TIMEOUT, MAX_RETRIES); st_sleep_done, ST_TIMEOUT, MAX_RETRIES);
if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting ); if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) );
if (SCpnt->result || SCpnt->sense_buffer[0] != 0) { if ((STp->buffer)->last_result_fatal != 0) {
#ifdef DEBUG #ifdef DEBUG
printk("st%d: Error on write:\n", dev); printk("st%d: Error on write:\n", dev);
st_chk_result(SCpnt);
#endif #endif
if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
(SCpnt->sense_buffer[2] & 0x40)) (SCpnt->sense_buffer[2] & 0x40)) {
retval = (-ENOSPC); /* EOM */ if (STp->block_size != 0 && (SCpnt->sense_buffer[0] & 0x80) != 0)
transfer = (SCpnt->sense_buffer[3] << 24) |
(SCpnt->sense_buffer[4] << 16) |
(SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6];
else if (STp->block_size == 0 &&
(SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW)
transfer = do_count;
else
transfer = 0;
if (STp->block_size != 0)
transfer *= STp->block_size;
if (transfer <= do_count) {
filp->f_pos += do_count - transfer;
count -= do_count - transfer;
STp->eof = ST_EOM_OK;
retval = (-ENOSPC); /* EOM within current request */
#ifdef DEBUG
printk("st%d: EOM with %d bytes unwritten.\n",
dev, transfer);
#endif
}
else {
STp->eof = ST_EOM_ERROR;
retval = (-EIO); /* EOM for old data */
#ifdef DEBUG
printk("st%d: EOM with lost data.\n", dev);
#endif
}
}
else else
retval = (-EIO); retval = (-EIO);
SCpnt->request.dev = -1; /* Mark as not busy */ SCpnt->request.dev = -1; /* Mark as not busy */
(STp->buffer)->buffer_bytes = 0;
STp->dirty = 0;
if (count < total) if (count < total)
return total - count; return total - count;
else else
...@@ -645,48 +767,47 @@ int st_write(struct inode * inode, struct file * filp, char * buf, int count) ...@@ -645,48 +767,47 @@ int st_write(struct inode * inode, struct file * filp, char * buf, int count)
filp->f_pos += do_count; filp->f_pos += do_count;
b_point += do_count; b_point += do_count;
count -= do_count; count -= do_count;
scsi_tapes[dev].buffer->buffer_bytes = 0; (STp->buffer)->buffer_bytes = 0;
scsi_tapes[dev].dirty = 0; STp->dirty = 0;
} }
if (count != 0) { if (count != 0) {
scsi_tapes[dev].dirty = 1; STp->dirty = 1;
memcpy_fromfs(scsi_tapes[dev].buffer->b_data + memcpy_fromfs((STp->buffer)->b_data +
scsi_tapes[dev].buffer->buffer_bytes,b_point,count); (STp->buffer)->buffer_bytes,b_point,count);
filp->f_pos += count; filp->f_pos += count;
scsi_tapes[dev].buffer->buffer_bytes += count; (STp->buffer)->buffer_bytes += count;
count = 0; count = 0;
} }
do_count = st_chk_result(SCpnt); if ((STp->buffer)->last_result_fatal != 0) {
if (do_count) {
SCpnt->request.dev = -1; SCpnt->request.dev = -1;
return do_count; return (STp->buffer)->last_result_fatal;
} }
#if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS #if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS
if (scsi_tapes[dev].buffer->buffer_bytes >= ST_WRITE_THRESHOLD || if ((STp->buffer)->buffer_bytes >= ST_WRITE_THRESHOLD ||
scsi_tapes[dev].block_size == 0) { STp->block_size == 0) {
/* Schedule an asynchronous write */ /* Schedule an asynchronous write */
if (scsi_tapes[dev].block_size == 0) if (STp->block_size == 0)
scsi_tapes[dev].buffer->writing = scsi_tapes[dev].buffer->buffer_bytes; (STp->buffer)->writing = (STp->buffer)->buffer_bytes;
else else
scsi_tapes[dev].buffer->writing = (scsi_tapes[dev].buffer->buffer_bytes / (STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
scsi_tapes[dev].block_size) * scsi_tapes[dev].block_size; STp->block_size) * STp->block_size;
scsi_tapes[dev].dirty = 0; STp->dirty = 0;
if (scsi_tapes[dev].block_size == 0) if (STp->block_size == 0)
blks = scsi_tapes[dev].buffer->writing; blks = (STp->buffer)->writing;
else else
blks = scsi_tapes[dev].buffer->writing / scsi_tapes[dev].block_size; blks = (STp->buffer)->writing / STp->block_size;
cmd[2] = blks >> 16; cmd[2] = blks >> 16;
cmd[3] = blks >> 8; cmd[3] = blks >> 8;
cmd[4] = blks; cmd[4] = blks;
SCpnt->result = scsi_tapes[dev].buffer->last_result = -1; SCpnt->result = (STp->buffer)->last_result = -1;
SCpnt->sense_buffer[0] = 0; SCpnt->sense_buffer[0] = 0;
SCpnt->request.dev = dev; SCpnt->request.dev = dev;
scsi_do_cmd (SCpnt, scsi_do_cmd (SCpnt,
(void *) cmd, scsi_tapes[dev].buffer->b_data, (void *) cmd, (STp->buffer)->b_data,
scsi_tapes[dev].buffer->writing, (STp->buffer)->writing,
st_sleep_done, ST_TIMEOUT, MAX_RETRIES); st_sleep_done, ST_TIMEOUT, MAX_RETRIES);
} }
else else
...@@ -698,58 +819,61 @@ int st_write(struct inode * inode, struct file * filp, char * buf, int count) ...@@ -698,58 +819,61 @@ int st_write(struct inode * inode, struct file * filp, char * buf, int count)
/* Read command */ /* Read command */
int st_read(struct inode * inode, struct file * filp, char * buf, int count) static int
st_read(struct inode * inode, struct file * filp, char * buf, int count)
{ {
int dev; int dev;
int total; int total;
int transfer, blks, bytes; int transfer, blks, bytes;
static unsigned char cmd[10]; static unsigned char cmd[10];
Scsi_Cmnd * SCpnt; Scsi_Cmnd * SCpnt;
Scsi_Tape * STp;
dev = MINOR(inode->i_rdev) & 127; dev = MINOR(inode->i_rdev) & 127;
STp = &(scsi_tapes[dev]);
#ifdef DEBUG #ifdef DEBUG
if (!scsi_tapes[dev].in_use) { if (!STp->in_use) {
printk("st%d: Incorrect device.\n", dev); printk("st%d: Incorrect device.\n", dev);
return (-EIO); return (-EIO);
} }
#endif #endif
if (scsi_tapes[dev].block_size == 0 && count > ST_BUFFER_SIZE) if (STp->block_size == 0 && count > ST_BUFFER_SIZE)
return (-EOVERFLOW); return (-EOVERFLOW);
if (scsi_tapes[dev].rw == 2) { if (STp->rw == ST_WRITING) {
transfer = flush_buffer(inode, filp, 0); transfer = flush_buffer(inode, filp, 0);
if (transfer) if (transfer)
return transfer; return transfer;
scsi_tapes[dev].rw = 1; STp->rw = ST_READING;
} }
#ifdef DEBUG #ifdef DEBUG
if (scsi_tapes[dev].eof) if (STp->eof != ST_NOEOF)
printk("st%d: EOF flag up. Bytes %d\n", dev, printk("st%d: EOF flag up. Bytes %d\n", dev,
scsi_tapes[dev].buffer->buffer_bytes); (STp->buffer)->buffer_bytes);
#endif #endif
if ((scsi_tapes[dev].buffer->buffer_bytes == 0) && if (((STp->buffer)->buffer_bytes == 0) &&
scsi_tapes[dev].eof == 2) /* EOM or Blank Check */ STp->eof == ST_EOM_OK) /* EOM or Blank Check */
return (-EIO); return (-EIO);
scsi_tapes[dev].rw = 1; STp->rw = ST_READING;
SCpnt = allocate_device(NULL, scsi_tapes[dev].device->index, 1); SCpnt = allocate_device(NULL, (STp->device)->index, 1);
for (total = 0; total < count; ) { for (total = 0; total < count; ) {
if (scsi_tapes[dev].buffer->buffer_bytes == 0 && if ((STp->buffer)->buffer_bytes == 0 &&
scsi_tapes[dev].eof == 0) { STp->eof == ST_NOEOF) {
memset(cmd, 0, 10); memset(cmd, 0, 10);
cmd[0] = READ_6; cmd[0] = READ_6;
cmd[1] = (scsi_tapes[dev].block_size != 0); cmd[1] = (STp->block_size != 0);
if (scsi_tapes[dev].block_size == 0) if (STp->block_size == 0)
blks = bytes = count; blks = bytes = count;
else { else {
blks = scsi_tapes[dev].buffer->buffer_blocks; blks = (STp->buffer)->buffer_blocks;
bytes = blks * scsi_tapes[dev].block_size; bytes = blks * STp->block_size;
} }
cmd[2] = blks >> 16; cmd[2] = blks >> 16;
cmd[3] = blks >> 8; cmd[3] = blks >> 8;
...@@ -758,16 +882,16 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count) ...@@ -758,16 +882,16 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
SCpnt->sense_buffer[0] = 0; SCpnt->sense_buffer[0] = 0;
SCpnt->request.dev = dev; SCpnt->request.dev = dev;
scsi_do_cmd (SCpnt, scsi_do_cmd (SCpnt,
(void *) cmd, scsi_tapes[dev].buffer->b_data, (void *) cmd, (STp->buffer)->b_data,
scsi_tapes[dev].buffer->buffer_size, (STp->buffer)->buffer_size,
st_sleep_done, ST_TIMEOUT, MAX_RETRIES); st_sleep_done, ST_TIMEOUT, MAX_RETRIES);
if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting ); if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) );
scsi_tapes[dev].buffer->read_pointer = 0; (STp->buffer)->read_pointer = 0;
scsi_tapes[dev].eof_hit = 0; STp->eof_hit = 0;
if (SCpnt->result != 0 || SCpnt->sense_buffer[0] != 0) { if ((STp->buffer)->last_result_fatal) {
#ifdef DEBUG #ifdef DEBUG
printk("st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", dev, printk("st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", dev,
SCpnt->sense_buffer[0], SCpnt->sense_buffer[1], SCpnt->sense_buffer[0], SCpnt->sense_buffer[1],
...@@ -778,15 +902,22 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count) ...@@ -778,15 +902,22 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
if ((SCpnt->sense_buffer[0] & 0x70) == 0x70) { /* extended sense */ if ((SCpnt->sense_buffer[0] & 0x70) == 0x70) { /* extended sense */
if ((SCpnt->sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */ if ((SCpnt->sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */
if ((SCpnt->sense_buffer[0] & 0x80) != 0)
transfer = (SCpnt->sense_buffer[3] << 24) | transfer = (SCpnt->sense_buffer[3] << 24) |
(SCpnt->sense_buffer[4] << 16) | (SCpnt->sense_buffer[4] << 16) |
(SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6];
else
transfer = 0;
if (STp->block_size == 0 &&
(SCpnt->sense_buffer[2] & 0x0f) == MEDIUM_ERROR)
transfer = bytes;
if (SCpnt->sense_buffer[2] & 0x20) { if (SCpnt->sense_buffer[2] & 0x20) {
if (scsi_tapes[dev].block_size == 0) { if (STp->block_size == 0) {
if (transfer <= 0) if (transfer <= 0)
transfer = 0; transfer = 0;
scsi_tapes[dev].buffer->buffer_bytes = count - transfer; (STp->buffer)->buffer_bytes = count - transfer;
} }
else { else {
printk("st%d: Incorrect block size.\n", dev); printk("st%d: Incorrect block size.\n", dev);
...@@ -795,35 +926,36 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count) ...@@ -795,35 +926,36 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
} }
} }
else if (SCpnt->sense_buffer[2] & 0x40) { else if (SCpnt->sense_buffer[2] & 0x40) {
scsi_tapes[dev].eof = 2; /* What should be done at EOM ? */ STp->eof = ST_EOM_OK;
scsi_tapes[dev].buffer->buffer_bytes = if (STp->block_size == 0)
(scsi_tapes[dev].buffer->buffer_blocks - transfer) * (STp->buffer)->buffer_bytes = count - transfer;
scsi_tapes[dev].block_size; else
(STp->buffer)->buffer_bytes =
((STp->buffer)->buffer_blocks - transfer) *
STp->block_size;
#ifdef DEBUG #ifdef DEBUG
printk("st%d: EOM detected (%d blocks read).\n", dev, printk("st%d: EOM detected (%d bytes read).\n", dev,
scsi_tapes[dev].buffer->buffer_blocks - transfer); (STp->buffer)->buffer_bytes);
#endif #endif
} }
else if (SCpnt->sense_buffer[2] & 0x80) { else if (SCpnt->sense_buffer[2] & 0x80) {
scsi_tapes[dev].eof = 1; STp->eof = ST_FM;
if (scsi_tapes[dev].block_size == 0) if (STp->block_size == 0)
scsi_tapes[dev].buffer->buffer_bytes = (STp->buffer)->buffer_bytes = 0;
count - transfer;
else else
scsi_tapes[dev].buffer->buffer_bytes = (STp->buffer)->buffer_bytes =
(scsi_tapes[dev].buffer->buffer_blocks - transfer) * ((STp->buffer)->buffer_blocks - transfer) *
scsi_tapes[dev].block_size; STp->block_size;
#ifdef DEBUG #ifdef DEBUG
printk("st%d: EOF detected (%d blocks read, transferred %d bytes).\n", printk(
dev, scsi_tapes[dev].buffer->buffer_blocks - transfer, total); "st%d: EOF detected (%d bytes read, transferred %d bytes).\n",
dev, (STp->buffer)->buffer_bytes, total);
#endif #endif
} /* end of EOF, EOM, ILI test */ } /* end of EOF, EOM, ILI test */
} }
else { /* nonzero sense key */ else { /* nonzero sense key */
#ifdef DEBUG #ifdef DEBUG
printk("st%d: Tape error. Sense key %x\n", dev, printk("st%d: Tape error while reading.\n", dev);
SCpnt->sense_buffer[2] & 0x0f);
print_sense("st", SCpnt);
#endif #endif
SCpnt->request.dev = -1; SCpnt->request.dev = -1;
if (total) if (total)
...@@ -833,44 +965,44 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count) ...@@ -833,44 +965,44 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
} }
} }
else { else {
transfer = st_chk_result(SCpnt); transfer = (STp->buffer)->last_result_fatal;
SCpnt->request.dev = -1; /* Mark as not busy */ SCpnt->request.dev = -1; /* Mark as not busy */
return transfer; return transfer;
} }
} }
else /* Read successfu| */ else /* Read successful */
scsi_tapes[dev].buffer->buffer_bytes = bytes; (STp->buffer)->buffer_bytes = bytes;
} /* if (scsi_tapes[dev].buffer->buffer_bytes == 0 && } /* if ((STp->buffer)->buffer_bytes == 0 &&
scsi_tapes[dev].eof == 0) */ STp->eof == ST_NOEOF) */
if (scsi_tapes[dev].buffer->buffer_bytes > 0) { if ((STp->buffer)->buffer_bytes > 0) {
#ifdef DEBUG #ifdef DEBUG
if (scsi_tapes[dev].eof) if (STp->eof != ST_NOEOF)
printk("st%d: EOF up. Left %d, needed %d.\n", dev, printk("st%d: EOF up. Left %d, needed %d.\n", dev,
scsi_tapes[dev].buffer->buffer_bytes, count - total); (STp->buffer)->buffer_bytes, count - total);
#endif #endif
transfer = scsi_tapes[dev].buffer->buffer_bytes < count - total ? transfer = (STp->buffer)->buffer_bytes < count - total ?
scsi_tapes[dev].buffer->buffer_bytes : count - total; (STp->buffer)->buffer_bytes : count - total;
memcpy_tofs(buf, scsi_tapes[dev].buffer->b_data + memcpy_tofs(buf, (STp->buffer)->b_data +
scsi_tapes[dev].buffer->read_pointer,transfer); (STp->buffer)->read_pointer,transfer);
filp->f_pos += transfer; filp->f_pos += transfer;
buf += transfer; buf += transfer;
total += transfer; total += transfer;
scsi_tapes[dev].buffer->buffer_bytes -= transfer; (STp->buffer)->buffer_bytes -= transfer;
scsi_tapes[dev].buffer->read_pointer += transfer; (STp->buffer)->read_pointer += transfer;
} }
else if (scsi_tapes[dev].eof) { else if (STp->eof != ST_NOEOF) {
scsi_tapes[dev].eof_hit = 1; STp->eof_hit = 1;
SCpnt->request.dev = -1; /* Mark as not busy */ SCpnt->request.dev = -1; /* Mark as not busy */
if (total == 0 && scsi_tapes[dev].eof == 1) if (total == 0 && STp->eof == ST_FM)
scsi_tapes[dev].eof = 0; STp->eof = 0;
if (total == 0 && scsi_tapes[dev].eof == 2) if (total == 0 && STp->eof == ST_EOM_OK)
return (-EIO); return (-EIO); /* ST_EOM_ERROR not used in read */
return total; return total;
} }
if (scsi_tapes[dev].block_size == 0) if (STp->block_size == 0)
count = total; /* Read only one variable length block */ count = total; /* Read only one variable length block */
} /* for (total = 0; total < count; ) */ } /* for (total = 0; total < count; ) */
...@@ -882,7 +1014,8 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count) ...@@ -882,7 +1014,8 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
/* Internal ioctl function */ /* Internal ioctl function */
static int st_int_ioctl(struct inode * inode,struct file * file, static int
st_int_ioctl(struct inode * inode,struct file * file,
unsigned int cmd_in, unsigned long arg) unsigned int cmd_in, unsigned long arg)
{ {
int dev = MINOR(inode->i_rdev); int dev = MINOR(inode->i_rdev);
...@@ -891,8 +1024,10 @@ static int st_int_ioctl(struct inode * inode,struct file * file, ...@@ -891,8 +1024,10 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
int ioctl_result; int ioctl_result;
unsigned char cmd[10]; unsigned char cmd[10];
Scsi_Cmnd * SCpnt; Scsi_Cmnd * SCpnt;
Scsi_Tape * STp;
dev = dev & 127; dev = dev & 127;
STp = &(scsi_tapes[dev]);
memset(cmd, 0, 10); memset(cmd, 0, 10);
switch (cmd_in) { switch (cmd_in) {
...@@ -904,7 +1039,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file, ...@@ -904,7 +1039,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
cmd[3] = (arg >> 8); cmd[3] = (arg >> 8);
cmd[4] = arg; cmd[4] = arg;
#ifdef DEBUG #ifdef DEBUG
printk("st%d: Spacing tape forward %d files.\n", dev, printk("st%d: Spacing tape forward over %d filemarks.\n", dev,
cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
#endif #endif
break; break;
...@@ -920,7 +1055,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file, ...@@ -920,7 +1055,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
if (cmd[2] & 0x80) if (cmd[2] & 0x80)
ltmp = 0xff000000; ltmp = 0xff000000;
ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
printk("st%d: Spacing tape backward %d files.\n", dev, (-ltmp)); printk("st%d: Spacing tape backward over %d filemarks.\n", dev, (-ltmp));
#endif #endif
break; break;
case MTFSR: case MTFSR:
...@@ -949,7 +1084,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file, ...@@ -949,7 +1084,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
#endif #endif
break; break;
case MTWEOF: case MTWEOF:
if (scsi_tapes[dev].write_prot) if (STp->write_prot)
return (-EACCES); return (-EACCES);
cmd[0] = WRITE_FILEMARKS; cmd[0] = WRITE_FILEMARKS;
cmd[2] = (arg >> 16); cmd[2] = (arg >> 16);
...@@ -1006,7 +1141,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file, ...@@ -1006,7 +1141,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
#endif #endif
break; break;
case MTERASE: case MTERASE:
if (scsi_tapes[dev].write_prot) if (STp->write_prot)
return (-EACCES); return (-EACCES);
cmd[0] = ERASE; cmd[0] = ERASE;
cmd[1] = 1; /* To the end of tape */ cmd[1] = 1; /* To the end of tape */
...@@ -1015,7 +1150,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file, ...@@ -1015,7 +1150,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
#endif #endif
break; break;
case MTSEEK: case MTSEEK:
if (scsi_tapes[dev].device->scsi_level < SCSI_2) { if ((STp->device)->scsi_level < SCSI_2) {
cmd[0] = QFA_SEEK_BLOCK; cmd[0] = QFA_SEEK_BLOCK;
cmd[2] = (arg >> 16); cmd[2] = (arg >> 16);
cmd[3] = (arg >> 8); cmd[3] = (arg >> 8);
...@@ -1041,11 +1176,11 @@ static int st_int_ioctl(struct inode * inode,struct file * file, ...@@ -1041,11 +1176,11 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
case MTSETBLK: /* Set block length */ case MTSETBLK: /* Set block length */
case MTSETDENSITY: /* Set tape density */ case MTSETDENSITY: /* Set tape density */
case MTSETDRVBUFFER: /* Set drive buffering */ case MTSETDRVBUFFER: /* Set drive buffering */
if (scsi_tapes[dev].dirty || scsi_tapes[dev].buffer->buffer_bytes != 0) if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
return (-EIO); /* Not allowed if data in buffer */ return (-EIO); /* Not allowed if data in buffer */
if (cmd_in == MTSETBLK && if (cmd_in == MTSETBLK &&
arg != 0 && arg != 0 &&
(arg < scsi_tapes[dev].min_block || arg > scsi_tapes[dev].max_block || (arg < STp->min_block || arg > STp->max_block ||
arg > ST_BUFFER_SIZE)) { arg > ST_BUFFER_SIZE)) {
printk("st%d: Illegal block size.\n", dev); printk("st%d: Illegal block size.\n", dev);
return (-EINVAL); return (-EINVAL);
...@@ -1053,37 +1188,37 @@ static int st_int_ioctl(struct inode * inode,struct file * file, ...@@ -1053,37 +1188,37 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
cmd[0] = MODE_SELECT; cmd[0] = MODE_SELECT;
cmd[4] = 12; cmd[4] = 12;
memset(scsi_tapes[dev].buffer->b_data, 0, 12); memset((STp->buffer)->b_data, 0, 12);
if (cmd_in == MTSETDRVBUFFER) if (cmd_in == MTSETDRVBUFFER)
scsi_tapes[dev].buffer->b_data[2] = (arg & 7) << 4; (STp->buffer)->b_data[2] = (arg & 7) << 4;
else else
scsi_tapes[dev].buffer->b_data[2] = (STp->buffer)->b_data[2] =
scsi_tapes[dev].drv_buffer << 4; STp->drv_buffer << 4;
scsi_tapes[dev].buffer->b_data[3] = 8; /* block descriptor length */ (STp->buffer)->b_data[3] = 8; /* block descriptor length */
if (cmd_in == MTSETDENSITY) if (cmd_in == MTSETDENSITY)
scsi_tapes[dev].buffer->b_data[4] = arg; (STp->buffer)->b_data[4] = arg;
else else
scsi_tapes[dev].buffer->b_data[4] = scsi_tapes[dev].density; (STp->buffer)->b_data[4] = STp->density;
if (cmd_in == MTSETBLK) if (cmd_in == MTSETBLK)
ltmp = arg; ltmp = arg;
else else
ltmp = scsi_tapes[dev].block_size; ltmp = STp->block_size;
scsi_tapes[dev].buffer->b_data[9] = (ltmp >> 16); (STp->buffer)->b_data[9] = (ltmp >> 16);
scsi_tapes[dev].buffer->b_data[10] = (ltmp >> 8); (STp->buffer)->b_data[10] = (ltmp >> 8);
scsi_tapes[dev].buffer->b_data[11] = ltmp; (STp->buffer)->b_data[11] = ltmp;
timeout = ST_TIMEOUT; timeout = ST_TIMEOUT;
#ifdef DEBUG #ifdef DEBUG
if (cmd_in == MTSETBLK) if (cmd_in == MTSETBLK)
printk("st%d: Setting block size to %d bytes.\n", dev, printk("st%d: Setting block size to %d bytes.\n", dev,
scsi_tapes[dev].buffer->b_data[9] * 65536 + (STp->buffer)->b_data[9] * 65536 +
scsi_tapes[dev].buffer->b_data[10] * 256 + (STp->buffer)->b_data[10] * 256 +
scsi_tapes[dev].buffer->b_data[11]); (STp->buffer)->b_data[11]);
else if (cmd_in == MTSETDENSITY) else if (cmd_in == MTSETDENSITY)
printk("st%d: Setting density code to %x.\n", dev, printk("st%d: Setting density code to %x.\n", dev,
scsi_tapes[dev].buffer->b_data[4]); (STp->buffer)->b_data[4]);
else else
printk("st%d: Setting drive buffer code to %d.\n", printk("st%d: Setting drive buffer code to %d.\n", dev,
(scsi_tapes[dev].buffer->b_data[2] >> 4) & 7); ((STp->buffer)->b_data[2] >> 4) & 7);
#endif #endif
break; break;
default: default:
...@@ -1091,16 +1226,16 @@ static int st_int_ioctl(struct inode * inode,struct file * file, ...@@ -1091,16 +1226,16 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
return (-ENOSYS); return (-ENOSYS);
} }
SCpnt = allocate_device(NULL, scsi_tapes[dev].device->index, 1); SCpnt = allocate_device(NULL, (STp->device)->index, 1);
SCpnt->sense_buffer[0] = 0; SCpnt->sense_buffer[0] = 0;
SCpnt->request.dev = dev; SCpnt->request.dev = dev;
scsi_do_cmd(SCpnt, scsi_do_cmd(SCpnt,
(void *) cmd, (void *) scsi_tapes[dev].buffer->b_data, ST_BLOCK_SIZE, (void *) cmd, (void *) (STp->buffer)->b_data, ST_BLOCK_SIZE,
st_sleep_done, timeout, MAX_RETRIES); st_sleep_done, timeout, MAX_RETRIES);
if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting ); if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) );
ioctl_result = st_chk_result(SCpnt); ioctl_result = (STp->buffer)->last_result_fatal;
SCpnt->request.dev = -1; /* Mark as not busy */ SCpnt->request.dev = -1; /* Mark as not busy */
...@@ -1110,31 +1245,31 @@ static int st_int_ioctl(struct inode * inode,struct file * file, ...@@ -1110,31 +1245,31 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
else if (cmd_in == MTFSFM) else if (cmd_in == MTFSFM)
ioctl_result = st_int_ioctl(inode, file, MTBSF, 1); ioctl_result = st_int_ioctl(inode, file, MTBSF, 1);
else if (cmd_in == MTSETBLK) { else if (cmd_in == MTSETBLK) {
scsi_tapes[dev].block_size = arg; STp->block_size = arg;
if (arg != 0) { if (arg != 0) {
scsi_tapes[dev].buffer->buffer_blocks = (STp->buffer)->buffer_blocks =
ST_BUFFER_SIZE / scsi_tapes[dev].block_size; ST_BUFFER_SIZE / STp->block_size;
scsi_tapes[dev].buffer->buffer_size = (STp->buffer)->buffer_size =
scsi_tapes[dev].buffer->buffer_blocks * scsi_tapes[dev].block_size; (STp->buffer)->buffer_blocks * STp->block_size;
} }
else { else {
scsi_tapes[dev].buffer->buffer_blocks = 1; (STp->buffer)->buffer_blocks = 1;
scsi_tapes[dev].buffer->buffer_size = ST_BUFFER_SIZE; (STp->buffer)->buffer_size = ST_BUFFER_SIZE;
} }
scsi_tapes[dev].buffer->buffer_bytes = (STp->buffer)->buffer_bytes =
scsi_tapes[dev].buffer->read_pointer = 0; (STp->buffer)->read_pointer = 0;
} }
else if (cmd_in == MTSETDRVBUFFER) else if (cmd_in == MTSETDRVBUFFER)
scsi_tapes[dev].drv_buffer = arg; STp->drv_buffer = arg;
else if (cmd_in == MTSETDENSITY) else if (cmd_in == MTSETDENSITY)
scsi_tapes[dev].density = arg; STp->density = arg;
if (cmd_in == MTEOM || cmd_in == MTWEOF) { if (cmd_in == MTEOM || cmd_in == MTWEOF) {
scsi_tapes[dev].eof = 2; STp->eof = ST_EOM_OK;
scsi_tapes[dev].eof_hit = 0; STp->eof_hit = 0;
} }
else if (cmd_in != MTSETBLK && cmd_in != MTNOP) { else if (cmd_in != MTSETBLK && cmd_in != MTNOP) {
scsi_tapes[dev].eof = 0; STp->eof = ST_NOEOF;
scsi_tapes[dev].eof_hit = 0; STp->eof_hit = 0;
} }
} }
...@@ -1144,7 +1279,8 @@ static int st_int_ioctl(struct inode * inode,struct file * file, ...@@ -1144,7 +1279,8 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
/* The ioctl command */ /* The ioctl command */
static int st_ioctl(struct inode * inode,struct file * file, static int
st_ioctl(struct inode * inode,struct file * file,
unsigned int cmd_in, unsigned long arg) unsigned int cmd_in, unsigned long arg)
{ {
int dev = MINOR(inode->i_rdev); int dev = MINOR(inode->i_rdev);
...@@ -1153,10 +1289,12 @@ static int st_ioctl(struct inode * inode,struct file * file, ...@@ -1153,10 +1289,12 @@ static int st_ioctl(struct inode * inode,struct file * file,
struct mtpos mt_pos; struct mtpos mt_pos;
unsigned char scmd[10]; unsigned char scmd[10];
Scsi_Cmnd *SCpnt; Scsi_Cmnd *SCpnt;
Scsi_Tape *STp;
dev = dev & 127; dev = dev & 127;
STp = &(scsi_tapes[dev]);
#ifdef DEBUG #ifdef DEBUG
if (!scsi_tapes[dev].in_use) { if (!STp->in_use) {
printk("st%d: Incorrect device.\n", dev); printk("st%d: Incorrect device.\n", dev);
return (-EIO); return (-EIO);
} }
...@@ -1190,7 +1328,7 @@ static int st_ioctl(struct inode * inode,struct file * file, ...@@ -1190,7 +1328,7 @@ static int st_ioctl(struct inode * inode,struct file * file,
if (i) if (i)
return i; return i;
memcpy_tofs((char *)arg, (char *)scsi_tapes[dev].buffer->mt_status, memcpy_tofs((char *)arg, (char *)(STp->buffer)->mt_status,
sizeof(struct mtget)); sizeof(struct mtget));
return 0; return 0;
} }
...@@ -1209,11 +1347,11 @@ static int st_ioctl(struct inode * inode,struct file * file, ...@@ -1209,11 +1347,11 @@ static int st_ioctl(struct inode * inode,struct file * file,
if (i) if (i)
return i; return i;
SCpnt = allocate_device(NULL, scsi_tapes[dev].device->index, 1); SCpnt = allocate_device(NULL, (STp->device)->index, 1);
SCpnt->sense_buffer[0]=0; SCpnt->sense_buffer[0]=0;
memset (scmd, 0, 10); memset (scmd, 0, 10);
if (scsi_tapes[dev].device->scsi_level < SCSI_2) { if ((STp->device)->scsi_level < SCSI_2) {
scmd[0] = QFA_REQUEST_BLOCK; scmd[0] = QFA_REQUEST_BLOCK;
scmd[4] = 3; scmd[4] = 3;
} }
...@@ -1224,12 +1362,12 @@ static int st_ioctl(struct inode * inode,struct file * file, ...@@ -1224,12 +1362,12 @@ static int st_ioctl(struct inode * inode,struct file * file,
SCpnt->request.dev = dev; SCpnt->request.dev = dev;
SCpnt->sense_buffer[0] = 0; SCpnt->sense_buffer[0] = 0;
scsi_do_cmd(SCpnt, scsi_do_cmd(SCpnt,
(void *) scmd, (void *) scsi_tapes[dev].buffer->b_data, (void *) scmd, (void *) (STp->buffer)->b_data,
ST_BLOCK_SIZE, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES); ST_BLOCK_SIZE, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES);
if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting ); if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) );
if (SCpnt->result || SCpnt->sense_buffer[0]) { if ((STp->buffer)->last_result_fatal != 0) {
mt_pos.mt_blkno = (-1); mt_pos.mt_blkno = (-1);
#ifdef DEBUG #ifdef DEBUG
printk("st%d: Can't read tape position.\n", dev); printk("st%d: Can't read tape position.\n", dev);
...@@ -1238,15 +1376,15 @@ static int st_ioctl(struct inode * inode,struct file * file, ...@@ -1238,15 +1376,15 @@ static int st_ioctl(struct inode * inode,struct file * file,
} }
else { else {
result = 0; result = 0;
if (scsi_tapes[dev].device->scsi_level < SCSI_2) if ((STp->device)->scsi_level < SCSI_2)
mt_pos.mt_blkno = (scsi_tapes[dev].buffer->b_data[0] << 16) mt_pos.mt_blkno = ((STp->buffer)->b_data[0] << 16)
+ (scsi_tapes[dev].buffer->b_data[1] << 8) + ((STp->buffer)->b_data[1] << 8)
+ scsi_tapes[dev].buffer->b_data[2]; + (STp->buffer)->b_data[2];
else else
mt_pos.mt_blkno = (scsi_tapes[dev].buffer->b_data[4] << 24) mt_pos.mt_blkno = ((STp->buffer)->b_data[4] << 24)
+ (scsi_tapes[dev].buffer->b_data[5] << 16) + ((STp->buffer)->b_data[5] << 16)
+ (scsi_tapes[dev].buffer->b_data[6] << 8) + ((STp->buffer)->b_data[6] << 8)
+ scsi_tapes[dev].buffer->b_data[7]; + (STp->buffer)->b_data[7];
} }
...@@ -1256,7 +1394,7 @@ static int st_ioctl(struct inode * inode,struct file * file, ...@@ -1256,7 +1394,7 @@ static int st_ioctl(struct inode * inode,struct file * file,
return result; return result;
} }
else else
return scsi_ioctl(scsi_tapes[dev].device, cmd_in, (void *) arg); return scsi_ioctl(STp->device, cmd_in, (void *) arg);
} }
...@@ -1303,8 +1441,8 @@ unsigned long st_init(unsigned long mem_start, unsigned long mem_end) ...@@ -1303,8 +1441,8 @@ unsigned long st_init(unsigned long mem_start, unsigned long mem_end)
for (i=0; i < NR_ST; ++i) { for (i=0; i < NR_ST; ++i) {
scsi_tapes[i].capacity = 0xfffff; scsi_tapes[i].capacity = 0xfffff;
scsi_tapes[i].dirty = 0; scsi_tapes[i].dirty = 0;
scsi_tapes[i].rw = 0; scsi_tapes[i].rw = ST_IDLE;
scsi_tapes[i].eof = 0; scsi_tapes[i].eof = ST_NOEOF;
scsi_tapes[i].waiting = NULL; scsi_tapes[i].waiting = NULL;
scsi_tapes[i].in_use = 0; scsi_tapes[i].in_use = 0;
scsi_tapes[i].drv_buffer = 1; /* Try buffering if no mode sense */ scsi_tapes[i].drv_buffer = 1; /* Try buffering if no mode sense */
...@@ -1320,7 +1458,7 @@ unsigned long st_init(unsigned long mem_start, unsigned long mem_end) ...@@ -1320,7 +1458,7 @@ unsigned long st_init(unsigned long mem_start, unsigned long mem_end)
for (i=0; i < st_nbr_buffers; i++) { for (i=0; i < st_nbr_buffers; i++) {
st_buffers[i] = (ST_buffer *) mem_start; st_buffers[i] = (ST_buffer *) mem_start;
#ifdef DEBUG #ifdef DEBUG
printk("st: Buffer address: %x\n", st_buffers[i]); printk("st: Buffer address: %p\n", st_buffers[i]);
#endif #endif
mem_start += sizeof(ST_buffer) - 1 + ST_BUFFER_BLOCKS * ST_BLOCK_SIZE; mem_start += sizeof(ST_buffer) - 1 + ST_BUFFER_BLOCKS * ST_BLOCK_SIZE;
st_buffers[i]->mt_status = (struct mtget *) mem_start; st_buffers[i]->mt_status = (struct mtget *) mem_start;
......
...@@ -18,6 +18,7 @@ typedef struct { ...@@ -18,6 +18,7 @@ typedef struct {
int read_pointer; int read_pointer;
int writing; int writing;
int last_result; int last_result;
int last_result_fatal;
unsigned char b_data[1]; unsigned char b_data[1];
} ST_buffer; } ST_buffer;
...@@ -37,9 +38,20 @@ typedef struct { ...@@ -37,9 +38,20 @@ typedef struct {
int block_size; int block_size;
int min_block; int min_block;
int max_block; int max_block;
int recover_count;
Scsi_Cmnd SCpnt; Scsi_Cmnd SCpnt;
} Scsi_Tape; } Scsi_Tape;
/* Values of eof */
#define ST_NOEOF 0
#define ST_FM 1
#define ST_EOM_OK 2
#define ST_EOM_ERROR 3
/* Values of rw */
#define ST_IDLE 0
#define ST_READING 1
#define ST_WRITING 2
/* Positioning SCSI-commands for Tandberg, etc. drives */ /* Positioning SCSI-commands for Tandberg, etc. drives */
#define QFA_REQUEST_BLOCK 0x02 #define QFA_REQUEST_BLOCK 0x02
......
...@@ -27,21 +27,38 @@ ...@@ -27,21 +27,38 @@
#include <linux/in.h> #include <linux/in.h>
#ifdef NFS_PROC_DEBUG #ifdef NFS_PROC_DEBUG
static int proc_debug = 0; static int proc_debug = 0;
#define PRINTK if (proc_debug) printk #define PRINTK(format, args...) \
#else do { \
#define PRINTK if (0) printk if (proc_debug) \
#endif printk(format , ## args); \
} while (0)
#else /* !NFS_PROC_DEBUG */
#define PRINTK(format, args...) do ; while (0)
#define PREP_PAGE_RPC(code) \ #endif /* !NFS_PROC_DEBUG */
if (!(p0 = (int*)__get_free_page(GFP_KERNEL)))\
return NFSERR_IO;\
p=nfs_rpc_header(p0,code)
static int *nfs_rpc_header(int *p, int procedure); static int *nfs_rpc_header(int *p, int procedure);
static int *nfs_rpc_verify(int *p); static int *nfs_rpc_verify(int *p);
static int nfs_stat_to_errno(int stat); static int nfs_stat_to_errno(int stat);
/*
* Our memory allocation and release functions.
*/
static inline int *nfs_rpc_alloc(void)
{
return (int *) __get_free_page(GFP_KERNEL);
}
static inline void nfs_rpc_free(int *p)
{
free_page((long) p);
}
/* /*
* Here are a bunch of xdr encode/decode functions that convert * Here are a bunch of xdr encode/decode functions that convert
* between machine dependent and xdr data formats. * between machine dependent and xdr data formats.
...@@ -166,6 +183,10 @@ static int *xdr_decode_fsinfo(int *p, struct nfs_fsinfo *res) ...@@ -166,6 +183,10 @@ static int *xdr_decode_fsinfo(int *p, struct nfs_fsinfo *res)
return p; return p;
} }
/*
* One function for each procedure in the NFS protocol.
*/
int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fattr *fattr) struct nfs_fattr *fattr)
{ {
...@@ -173,10 +194,12 @@ int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -173,10 +194,12 @@ int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
int status; int status;
PRINTK("NFS call getattr\n"); PRINTK("NFS call getattr\n");
PREP_PAGE_RPC(NFSPROC_GETATTR); if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_GETATTR);
p = xdr_encode_fhandle(p, fhandle); p = xdr_encode_fhandle(p, fhandle);
if ((status = nfs_rpc_call(server, p0, p)) < 0) { if ((status = nfs_rpc_call(server, p0, p)) < 0) {
free_page((long) p0); nfs_rpc_free(p0);
return status; return status;
} }
if (!(p = nfs_rpc_verify(p0))) if (!(p = nfs_rpc_verify(p0)))
...@@ -187,7 +210,7 @@ int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -187,7 +210,7 @@ int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
} }
else else
PRINTK("NFS reply getattr failed = %d\n", status); PRINTK("NFS reply getattr failed = %d\n", status);
free_page((long) p0); nfs_rpc_free(p0);
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
} }
...@@ -198,11 +221,13 @@ int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -198,11 +221,13 @@ int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
int status; int status;
PRINTK("NFS call setattr\n"); PRINTK("NFS call setattr\n");
PREP_PAGE_RPC(NFSPROC_SETATTR); if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_SETATTR);
p = xdr_encode_fhandle(p, fhandle); p = xdr_encode_fhandle(p, fhandle);
p = xdr_encode_sattr(p, sattr); p = xdr_encode_sattr(p, sattr);
if ((status = nfs_rpc_call(server, p0, p)) < 0) { if ((status = nfs_rpc_call(server, p0, p)) < 0) {
free_page((long) p0); nfs_rpc_free(p0);
return status; return status;
} }
if (!(p = nfs_rpc_verify(p0))) if (!(p = nfs_rpc_verify(p0)))
...@@ -213,7 +238,7 @@ int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -213,7 +238,7 @@ int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
} }
else else
PRINTK("NFS reply setattr failed = %d\n", status); PRINTK("NFS reply setattr failed = %d\n", status);
free_page((long) p0); nfs_rpc_free(p0);
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
} }
...@@ -228,11 +253,13 @@ int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *n ...@@ -228,11 +253,13 @@ int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *n
if (!strcmp(name, "xyzzy")) if (!strcmp(name, "xyzzy"))
proc_debug = 1 - proc_debug; proc_debug = 1 - proc_debug;
#endif #endif
PREP_PAGE_RPC(NFSPROC_LOOKUP); if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_LOOKUP);
p = xdr_encode_fhandle(p, dir); p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name); p = xdr_encode_string(p, name);
if ((status = nfs_rpc_call(server, p0, p)) < 0) { if ((status = nfs_rpc_call(server, p0, p)) < 0) {
free_page((long) p0); nfs_rpc_free(p0);
return status; return status;
} }
if (!(p = nfs_rpc_verify(p0))) if (!(p = nfs_rpc_verify(p0)))
...@@ -244,7 +271,7 @@ int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *n ...@@ -244,7 +271,7 @@ int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *n
} }
else else
PRINTK("NFS reply lookup failed = %d\n", status); PRINTK("NFS reply lookup failed = %d\n", status);
free_page((long) p0); nfs_rpc_free(p0);
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
} }
...@@ -255,10 +282,12 @@ int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -255,10 +282,12 @@ int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
int status; int status;
PRINTK("NFS call readlink\n"); PRINTK("NFS call readlink\n");
PREP_PAGE_RPC(NFSPROC_READLINK); if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_READLINK);
p = xdr_encode_fhandle(p, fhandle); p = xdr_encode_fhandle(p, fhandle);
if ((status = nfs_rpc_call(server, p0, p)) < 0) { if ((status = nfs_rpc_call(server, p0, p)) < 0) {
free_page((long) p0); nfs_rpc_free(p0);
return status; return status;
} }
if (!(p = nfs_rpc_verify(p0))) if (!(p = nfs_rpc_verify(p0)))
...@@ -273,7 +302,7 @@ int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -273,7 +302,7 @@ int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
} }
else else
PRINTK("NFS reply readlink failed = %d\n", status); PRINTK("NFS reply readlink failed = %d\n", status);
free_page((long) p0); nfs_rpc_free(p0);
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
} }
...@@ -285,13 +314,15 @@ int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -285,13 +314,15 @@ int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
int len = 0; /* = 0 is for gcc */ int len = 0; /* = 0 is for gcc */
PRINTK("NFS call read %d @ %d\n", count, offset); PRINTK("NFS call read %d @ %d\n", count, offset);
PREP_PAGE_RPC(NFSPROC_READ); if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_READ);
p = xdr_encode_fhandle(p, fhandle); p = xdr_encode_fhandle(p, fhandle);
*p++ = htonl(offset); *p++ = htonl(offset);
*p++ = htonl(count); *p++ = htonl(count);
*p++ = htonl(count); /* traditional, could be any value */ *p++ = htonl(count); /* traditional, could be any value */
if ((status = nfs_rpc_call(server, p0, p)) < 0) { if ((status = nfs_rpc_call(server, p0, p)) < 0) {
free_page((long) p0); nfs_rpc_free(p0);
return status; return status;
} }
if (!(p = nfs_rpc_verify(p0))) if (!(p = nfs_rpc_verify(p0)))
...@@ -307,7 +338,7 @@ int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -307,7 +338,7 @@ int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
} }
else else
PRINTK("NFS reply read failed = %d\n", status); PRINTK("NFS reply read failed = %d\n", status);
free_page((long) p0); nfs_rpc_free(p0);
return (status == NFS_OK) ? len : -nfs_stat_to_errno(status); return (status == NFS_OK) ? len : -nfs_stat_to_errno(status);
} }
...@@ -318,14 +349,16 @@ int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -318,14 +349,16 @@ int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
int status; int status;
PRINTK("NFS call write %d @ %d\n", count, offset); PRINTK("NFS call write %d @ %d\n", count, offset);
PREP_PAGE_RPC(NFSPROC_WRITE); if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_WRITE);
p = xdr_encode_fhandle(p, fhandle); p = xdr_encode_fhandle(p, fhandle);
*p++ = htonl(offset); /* traditional, could be any value */ *p++ = htonl(offset); /* traditional, could be any value */
*p++ = htonl(offset); *p++ = htonl(offset);
*p++ = htonl(count); /* traditional, could be any value */ *p++ = htonl(count); /* traditional, could be any value */
p = xdr_encode_data(p, data, count); p = xdr_encode_data(p, data, count);
if ((status = nfs_rpc_call(server, p0, p)) < 0) { if ((status = nfs_rpc_call(server, p0, p)) < 0) {
free_page((long) p0); nfs_rpc_free(p0);
return status; return status;
} }
if (!(p = nfs_rpc_verify(p0))) if (!(p = nfs_rpc_verify(p0)))
...@@ -336,7 +369,7 @@ int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -336,7 +369,7 @@ int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
} }
else else
PRINTK("NFS reply write failed = %d\n", status); PRINTK("NFS reply write failed = %d\n", status);
free_page((long) p0); nfs_rpc_free(p0);
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
} }
...@@ -348,12 +381,14 @@ int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir, ...@@ -348,12 +381,14 @@ int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
int status; int status;
PRINTK("NFS call create %s\n", name); PRINTK("NFS call create %s\n", name);
PREP_PAGE_RPC(NFSPROC_CREATE); if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_CREATE);
p = xdr_encode_fhandle(p, dir); p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name); p = xdr_encode_string(p, name);
p = xdr_encode_sattr(p, sattr); p = xdr_encode_sattr(p, sattr);
if ((status = nfs_rpc_call(server, p0, p)) < 0) { if ((status = nfs_rpc_call(server, p0, p)) < 0) {
free_page((long) p0); nfs_rpc_free(p0);
return status; return status;
} }
if (!(p = nfs_rpc_verify(p0))) if (!(p = nfs_rpc_verify(p0)))
...@@ -365,7 +400,7 @@ int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir, ...@@ -365,7 +400,7 @@ int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
} }
else else
PRINTK("NFS reply create failed = %d\n", status); PRINTK("NFS reply create failed = %d\n", status);
free_page((long) p0); nfs_rpc_free(p0);
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
} }
...@@ -375,11 +410,13 @@ int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *n ...@@ -375,11 +410,13 @@ int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *n
int status; int status;
PRINTK("NFS call remove %s\n", name); PRINTK("NFS call remove %s\n", name);
PREP_PAGE_RPC(NFSPROC_REMOVE); if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_REMOVE);
p = xdr_encode_fhandle(p, dir); p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name); p = xdr_encode_string(p, name);
if ((status = nfs_rpc_call(server, p0, p)) < 0) { if ((status = nfs_rpc_call(server, p0, p)) < 0) {
free_page((long) p0); nfs_rpc_free(p0);
return status; return status;
} }
if (!(p = nfs_rpc_verify(p0))) if (!(p = nfs_rpc_verify(p0)))
...@@ -389,7 +426,7 @@ int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *n ...@@ -389,7 +426,7 @@ int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *n
} }
else else
PRINTK("NFS reply remove failed = %d\n", status); PRINTK("NFS reply remove failed = %d\n", status);
free_page((long) p0); nfs_rpc_free(p0);
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
} }
...@@ -401,13 +438,15 @@ int nfs_proc_rename(struct nfs_server *server, ...@@ -401,13 +438,15 @@ int nfs_proc_rename(struct nfs_server *server,
int status; int status;
PRINTK("NFS call rename %s -> %s\n", old_name, new_name); PRINTK("NFS call rename %s -> %s\n", old_name, new_name);
PREP_PAGE_RPC(NFSPROC_RENAME); if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_RENAME);
p = xdr_encode_fhandle(p, old_dir); p = xdr_encode_fhandle(p, old_dir);
p = xdr_encode_string(p, old_name); p = xdr_encode_string(p, old_name);
p = xdr_encode_fhandle(p, new_dir); p = xdr_encode_fhandle(p, new_dir);
p = xdr_encode_string(p, new_name); p = xdr_encode_string(p, new_name);
if ((status = nfs_rpc_call(server, p0, p)) < 0) { if ((status = nfs_rpc_call(server, p0, p)) < 0) {
free_page((long) p0); nfs_rpc_free(p0);
return status; return status;
} }
if (!(p = nfs_rpc_verify(p0))) if (!(p = nfs_rpc_verify(p0)))
...@@ -417,7 +456,7 @@ int nfs_proc_rename(struct nfs_server *server, ...@@ -417,7 +456,7 @@ int nfs_proc_rename(struct nfs_server *server,
} }
else else
PRINTK("NFS reply rename failed = %d\n", status); PRINTK("NFS reply rename failed = %d\n", status);
free_page((long) p0); nfs_rpc_free(p0);
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
} }
...@@ -428,12 +467,14 @@ int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -428,12 +467,14 @@ int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
int status; int status;
PRINTK("NFS call link %s\n", name); PRINTK("NFS call link %s\n", name);
PREP_PAGE_RPC(NFSPROC_LINK); if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_LINK);
p = xdr_encode_fhandle(p, fhandle); p = xdr_encode_fhandle(p, fhandle);
p = xdr_encode_fhandle(p, dir); p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name); p = xdr_encode_string(p, name);
if ((status = nfs_rpc_call(server, p0, p)) < 0) { if ((status = nfs_rpc_call(server, p0, p)) < 0) {
free_page((long) p0); nfs_rpc_free(p0);
return status; return status;
} }
if (!(p = nfs_rpc_verify(p0))) if (!(p = nfs_rpc_verify(p0)))
...@@ -443,7 +484,7 @@ int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -443,7 +484,7 @@ int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
} }
else else
PRINTK("NFS reply link failed = %d\n", status); PRINTK("NFS reply link failed = %d\n", status);
free_page((long) p0); nfs_rpc_free(p0);
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
} }
...@@ -454,13 +495,15 @@ int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir, ...@@ -454,13 +495,15 @@ int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
int status; int status;
PRINTK("NFS call symlink %s -> %s\n", name, path); PRINTK("NFS call symlink %s -> %s\n", name, path);
PREP_PAGE_RPC(NFSPROC_SYMLINK); if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_SYMLINK);
p = xdr_encode_fhandle(p, dir); p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name); p = xdr_encode_string(p, name);
p = xdr_encode_string(p, path); p = xdr_encode_string(p, path);
p = xdr_encode_sattr(p, sattr); p = xdr_encode_sattr(p, sattr);
if ((status = nfs_rpc_call(server, p0, p)) < 0) { if ((status = nfs_rpc_call(server, p0, p)) < 0) {
free_page((long) p0); nfs_rpc_free(p0);
return status; return status;
} }
if (!(p = nfs_rpc_verify(p0))) if (!(p = nfs_rpc_verify(p0)))
...@@ -470,7 +513,7 @@ int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir, ...@@ -470,7 +513,7 @@ int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
} }
else else
PRINTK("NFS reply symlink failed = %d\n", status); PRINTK("NFS reply symlink failed = %d\n", status);
free_page((long) p0); nfs_rpc_free(p0);
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
} }
...@@ -482,12 +525,14 @@ int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir, ...@@ -482,12 +525,14 @@ int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
int status; int status;
PRINTK("NFS call mkdir %s\n", name); PRINTK("NFS call mkdir %s\n", name);
PREP_PAGE_RPC(NFSPROC_MKDIR); if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_MKDIR);
p = xdr_encode_fhandle(p, dir); p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name); p = xdr_encode_string(p, name);
p = xdr_encode_sattr(p, sattr); p = xdr_encode_sattr(p, sattr);
if ((status = nfs_rpc_call(server, p0, p)) < 0) { if ((status = nfs_rpc_call(server, p0, p)) < 0) {
free_page((long) p0); nfs_rpc_free(p0);
return status; return status;
} }
if (!(p = nfs_rpc_verify(p0))) if (!(p = nfs_rpc_verify(p0)))
...@@ -499,7 +544,7 @@ int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir, ...@@ -499,7 +544,7 @@ int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
} }
else else
PRINTK("NFS reply mkdir failed = %d\n", status); PRINTK("NFS reply mkdir failed = %d\n", status);
free_page((long) p0); nfs_rpc_free(p0);
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
} }
...@@ -509,11 +554,13 @@ int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *na ...@@ -509,11 +554,13 @@ int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *na
int status; int status;
PRINTK("NFS call rmdir %s\n", name); PRINTK("NFS call rmdir %s\n", name);
PREP_PAGE_RPC(NFSPROC_RMDIR); if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_RMDIR);
p = xdr_encode_fhandle(p, dir); p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name); p = xdr_encode_string(p, name);
if ((status = nfs_rpc_call(server, p0, p)) < 0) { if ((status = nfs_rpc_call(server, p0, p)) < 0) {
free_page((long) p0); nfs_rpc_free(p0);
return status; return status;
} }
if (!(p = nfs_rpc_verify(p0))) if (!(p = nfs_rpc_verify(p0)))
...@@ -523,7 +570,7 @@ int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *na ...@@ -523,7 +570,7 @@ int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *na
} }
else else
PRINTK("NFS reply rmdir failed = %d\n", status); PRINTK("NFS reply rmdir failed = %d\n", status);
free_page((long) p0); nfs_rpc_free(p0);
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
} }
...@@ -538,12 +585,14 @@ int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -538,12 +585,14 @@ int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
PRINTK("NFS call readdir %d @ %d\n", count, cookie); PRINTK("NFS call readdir %d @ %d\n", count, cookie);
size = server->rsize; size = server->rsize;
PREP_PAGE_RPC(NFSPROC_READDIR); if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_READDIR);
p = xdr_encode_fhandle(p, fhandle); p = xdr_encode_fhandle(p, fhandle);
*p++ = htonl(cookie); *p++ = htonl(cookie);
*p++ = htonl(size); *p++ = htonl(size);
if ((status = nfs_rpc_call(server, p0, p)) < 0) { if ((status = nfs_rpc_call(server, p0, p)) < 0) {
free_page((long) p0); nfs_rpc_free(p0);
return status; return status;
} }
if (!(p = nfs_rpc_verify(p0))) if (!(p = nfs_rpc_verify(p0)))
...@@ -568,7 +617,7 @@ int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -568,7 +617,7 @@ int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
} }
else else
PRINTK("NFS reply readdir failed = %d\n", status); PRINTK("NFS reply readdir failed = %d\n", status);
free_page((long) p0); nfs_rpc_free(p0);
return (status == NFS_OK) ? i : -nfs_stat_to_errno(status); return (status == NFS_OK) ? i : -nfs_stat_to_errno(status);
} }
...@@ -579,10 +628,12 @@ int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -579,10 +628,12 @@ int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
int status; int status;
PRINTK("NFS call statfs\n"); PRINTK("NFS call statfs\n");
PREP_PAGE_RPC(NFSPROC_STATFS); if (!(p0 = nfs_rpc_alloc()))
return -EIO;
p = nfs_rpc_header(p0, NFSPROC_STATFS);
p = xdr_encode_fhandle(p, fhandle); p = xdr_encode_fhandle(p, fhandle);
if ((status = nfs_rpc_call(server, p0, p)) < 0) { if ((status = nfs_rpc_call(server, p0, p)) < 0) {
free_page((long) p0); nfs_rpc_free(p0);
return status; return status;
} }
if (!(p = nfs_rpc_verify(p0))) if (!(p = nfs_rpc_verify(p0)))
...@@ -593,7 +644,7 @@ int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -593,7 +644,7 @@ int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
} }
else else
PRINTK("NFS reply statfs failed = %d\n", status); PRINTK("NFS reply statfs failed = %d\n", status);
free_page((long) p0); nfs_rpc_free(p0);
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
} }
......
...@@ -132,6 +132,15 @@ __ntohl(unsigned long int x) ...@@ -132,6 +132,15 @@ __ntohl(unsigned long int x)
return x; return x;
} }
static __inline__ unsigned long int
__constant_ntohl(unsigned long int x)
{
return (((x & 0x000000ff) << 24) |
((x & 0x0000ff00) << 8) |
((x & 0x00ff0000) >> 8) |
((x & 0xff000000) >> 24));
}
static __inline__ unsigned short int static __inline__ unsigned short int
__ntohs(unsigned short int x) __ntohs(unsigned short int x)
{ {
...@@ -141,31 +150,35 @@ __ntohs(unsigned short int x) ...@@ -141,31 +150,35 @@ __ntohs(unsigned short int x)
return x; return x;
} }
static __inline__ unsigned long int
__htonl(unsigned long int x)
{
__asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */
"rorl $16,%0\n\t" /* swap words */
"xchgb %b0,%h0" /* swap higher bytes */
:"=q" (x)
: "0" (x));
return x;
}
static __inline__ unsigned short int static __inline__ unsigned short int
__htons(unsigned short int x) __constant_ntohs(unsigned short int x)
{ {
__asm__("xchgb %b0,%h0" /* swap bytes */ return (((x & 0x00ff) << 8) |
: "=q" (x) ((x & 0xff00) >> 8));
: "0" (x));
return x;
} }
#define __htonl(x) __ntohl(x)
#define __htons(x) __ntohs(x)
#define __constant_htonl(x) __constant_ntohl(x)
#define __constant_htons(x) __constant_ntohs(x)
#ifdef __OPTIMIZE__ #ifdef __OPTIMIZE__
# define ntohl(x) __ntohl((x)) # define ntohl(x) \
# define ntohs(x) __ntohs((x)) (__builtin_constant_p((x)) ? \
# define htonl(x) __htonl((x)) __constant_ntohl((x)) : \
# define htons(x) __htons((x)) __ntohl((x)))
# define ntohs(x) \
(__builtin_constant_p((x)) ? \
__constant_ntohs((x)) : \
__ntohs((x)))
# define htonl(x) \
(__builtin_constant_p((x)) ? \
__constant_htonl((x)) : \
__htonl((x)))
# define htons(x) \
(__builtin_constant_p((x)) ? \
__constant_htons((x)) : \
__htons((x)))
#endif #endif
#endif /* _LINUX_IN_H */ #endif /* _LINUX_IN_H */
...@@ -20,7 +20,7 @@ static int findkey (key_t key); ...@@ -20,7 +20,7 @@ static int findkey (key_t key);
static struct msqid_ds *msgque[MSGMNI]; static struct msqid_ds *msgque[MSGMNI];
static int msgbytes = 0; static int msgbytes = 0;
static int msghdrs = 0; static int msghdrs = 0;
static int msg_seq = 0; static unsigned short msg_seq = 0;
static int used_queues = 0; static int used_queues = 0;
static int max_msqid = 0; static int max_msqid = 0;
static struct wait_queue *msg_lock = NULL; static struct wait_queue *msg_lock = NULL;
...@@ -264,7 +264,7 @@ static int newque (key_t key, int msgflg) ...@@ -264,7 +264,7 @@ static int newque (key_t key, int msgflg)
used_queues++; used_queues++;
if (msg_lock) if (msg_lock)
wake_up (&msg_lock); wake_up (&msg_lock);
return msg_seq * MSGMNI + id; return (int) msg_seq * MSGMNI + id;
} }
int sys_msgget (key_t key, int msgflg) int sys_msgget (key_t key, int msgflg)
...@@ -295,8 +295,7 @@ static void freeque (int id) ...@@ -295,8 +295,7 @@ static void freeque (int id)
struct msg *msgp, *msgh; struct msg *msgp, *msgh;
msq->msg_perm.seq++; msq->msg_perm.seq++;
if ((int)((++msg_seq + 1) * MSGMNI) < 0) msg_seq++;
msg_seq = 0;
msgbytes -= msq->msg_cbytes; msgbytes -= msq->msg_cbytes;
if (id == max_msqid) if (id == max_msqid)
while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED)); while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED));
......
...@@ -20,9 +20,10 @@ static void freeary (int id); ...@@ -20,9 +20,10 @@ static void freeary (int id);
static struct semid_ds *semary[SEMMNI]; static struct semid_ds *semary[SEMMNI];
static int used_sems = 0, used_semids = 0; static int used_sems = 0, used_semids = 0;
static struct wait_queue *sem_lock = NULL; static struct wait_queue *sem_lock = NULL;
static int sem_seq = 0;
static int max_semid = 0; static int max_semid = 0;
static unsigned short sem_seq = 0;
void sem_init (void) void sem_init (void)
{ {
int i=0; int i=0;
...@@ -95,7 +96,7 @@ static int newary (key_t key, int nsems, int semflg) ...@@ -95,7 +96,7 @@ static int newary (key_t key, int nsems, int semflg)
semary[id] = sma; semary[id] = sma;
if (sem_lock) if (sem_lock)
wake_up (&sem_lock); wake_up (&sem_lock);
return sem_seq * SEMMNI + id; return (int) sem_seq * SEMMNI + id;
} }
int sys_semget (key_t key, int nsems, int semflg) int sys_semget (key_t key, int nsems, int semflg)
...@@ -128,8 +129,7 @@ static void freeary (int id) ...@@ -128,8 +129,7 @@ static void freeary (int id)
struct sem_undo *un; struct sem_undo *un;
sma->sem_perm.seq++; sma->sem_perm.seq++;
if ((int)((++sem_seq + 1) * SEMMNI) < 0) sem_seq++;
sem_seq = 0;
used_sems -= sma->sem_nsems; used_sems -= sma->sem_nsems;
if (id == max_semid) if (id == max_semid)
while (max_semid && (semary[--max_semid] == IPC_UNUSED)); while (max_semid && (semary[--max_semid] == IPC_UNUSED));
......
...@@ -23,11 +23,12 @@ static void killseg (int id); ...@@ -23,11 +23,12 @@ static void killseg (int id);
static int shm_tot = 0; /* total number of shared memory pages */ static int shm_tot = 0; /* total number of shared memory pages */
static int shm_rss = 0; /* number of shared memory pages that are in memory */ static int shm_rss = 0; /* number of shared memory pages that are in memory */
static int shm_swp = 0; /* number of shared memory pages that are in swap */ static int shm_swp = 0; /* number of shared memory pages that are in swap */
static int shm_seq = 0; /* is incremented, for recognizing stale ids */
static int max_shmid = 0; /* every used id is <= max_shmid */ static int max_shmid = 0; /* every used id is <= max_shmid */
static struct wait_queue *shm_lock = NULL; static struct wait_queue *shm_lock = NULL;
static struct shmid_ds *shm_segs[SHMMNI]; static struct shmid_ds *shm_segs[SHMMNI];
static unsigned short shm_seq = 0; /* incremented, for recognizing stale ids */
/* some statistics */ /* some statistics */
static ulong swap_attempts = 0; static ulong swap_attempts = 0;
static ulong swap_successes = 0; static ulong swap_successes = 0;
...@@ -119,7 +120,7 @@ static int newseg (key_t key, int shmflg, int size) ...@@ -119,7 +120,7 @@ static int newseg (key_t key, int shmflg, int size)
used_segs++; used_segs++;
if (shm_lock) if (shm_lock)
wake_up (&shm_lock); wake_up (&shm_lock);
return id + shm_seq*SHMMNI; return id + (int)shm_seq*SHMMNI;
} }
int sys_shmget (key_t key, int size, int shmflg) int sys_shmget (key_t key, int size, int shmflg)
...@@ -165,8 +166,7 @@ static void killseg (int id) ...@@ -165,8 +166,7 @@ static void killseg (int id)
} }
shp->shm_perm.seq++; /* for shmat */ shp->shm_perm.seq++; /* for shmat */
numpages = shp->shm_npages; numpages = shp->shm_npages;
if ((int)((++shm_seq + 1) * SHMMNI) < 0) shm_seq++;
shm_seq = 0;
shm_segs[id] = (struct shmid_ds *) IPC_UNUSED; shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;
used_segs--; used_segs--;
if (id == max_shmid) if (id == max_shmid)
......
...@@ -88,9 +88,11 @@ asmlinkage int sys_syslog(int type, char * buf, int len) ...@@ -88,9 +88,11 @@ asmlinkage int sys_syslog(int type, char * buf, int len)
log_start++; log_start++;
log_size--; log_size--;
log_start &= LOG_BUF_LEN-1; log_start &= LOG_BUF_LEN-1;
sti();
put_fs_byte(c,buf); put_fs_byte(c,buf);
buf++; buf++;
i++; i++;
cli();
} }
sti(); sti();
return i; return i;
......
...@@ -210,11 +210,11 @@ icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev) ...@@ -210,11 +210,11 @@ icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev)
ip = iph->daddr; ip = iph->daddr;
switch(icmph->code & 7) { switch(icmph->code & 7) {
case ICMP_REDIR_NET: case ICMP_REDIR_NET:
rt_add((RTF_DYNAMIC | RTF_MODIFIED), rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
ip, icmph->un.gateway, dev); ip, icmph->un.gateway, dev);
break; break;
case ICMP_REDIR_HOST: case ICMP_REDIR_HOST:
rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST), rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
ip, icmph->un.gateway, dev); ip, icmph->un.gateway, dev);
break; break;
case ICMP_REDIR_NETTOS: case ICMP_REDIR_NETTOS:
......
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
#ifdef INET_DEBUG #ifdef INET_DEBUG
# define DPRINTF(x) dprintf x # define DPRINTF(x) dprintf x
#else #else
# define DPRINTF(x) /*zilch*/ # define DPRINTF(x) do ; while (0)
#endif #endif
/* Debug levels. One per module. */ /* Debug levels. One per module. */
......
...@@ -112,6 +112,16 @@ void rt_flush(struct device *dev) ...@@ -112,6 +112,16 @@ void rt_flush(struct device *dev)
/* /*
* Used by 'rt_add()' when we can't get the netmask from the device.. * Used by 'rt_add()' when we can't get the netmask from the device..
*
* If the lower byte or two are zero, we guess the mask based on the
* number of zero 8-bit net numbers, otherwise we use the "default"
* masks judging by the destination address.
*
* We should really use masks everywhere, but the current system
* interface for adding routes doesn't even contain a netmask field.
* Similarly, ICMP redirect messages contain only the address to
* redirect.. Anyway, this function should give reasonable values
* for almost anything.
*/ */
static unsigned long guess_mask(unsigned long dst) static unsigned long guess_mask(unsigned long dst)
{ {
...@@ -119,7 +129,29 @@ static unsigned long guess_mask(unsigned long dst) ...@@ -119,7 +129,29 @@ static unsigned long guess_mask(unsigned long dst)
while (mask & dst) while (mask & dst)
mask <<= 8; mask <<= 8;
if (mask)
return ~mask; return ~mask;
dst = ntohl(dst);
if (IN_CLASSA(dst))
return htonl(IN_CLASSA_NET);
if (IN_CLASSB(dst))
return htonl(IN_CLASSB_NET);
return htonl(IN_CLASSC_NET);
}
static inline struct device * get_gw_dev(unsigned long gw)
{
struct rtable * rt;
for (rt = rt_base ; rt ; rt = rt->rt_next) {
if ((gw ^ rt->rt_dst) & rt->rt_mask)
continue;
/* gateways behind gateways are a no-no */
if (rt->rt_flags & RTF_GATEWAY)
return NULL;
return rt->rt_dev;
}
return NULL;
} }
/* /*
...@@ -133,42 +165,40 @@ rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev) ...@@ -133,42 +165,40 @@ rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev)
unsigned long mask; unsigned long mask;
unsigned long cpuflags; unsigned long cpuflags;
/* Allocate an entry. */
rt = (struct rtable *) kmalloc(sizeof(struct rtable), GFP_ATOMIC);
if (rt == NULL) {
DPRINTF((DBG_RT, "RT: no memory for new route!\n"));
return;
}
/* Fill in the fields. */
memset(rt, 0, sizeof(struct rtable));
rt->rt_flags = (flags | RTF_UP);
/*
* Gateway to our own interface is really direct
*/
if (gw == dev->pa_addr || gw == dst) {
gw=0;
rt->rt_flags&=~RTF_GATEWAY;
}
if (gw != 0)
rt->rt_flags |= RTF_GATEWAY;
rt->rt_dev = dev;
rt->rt_gateway = gw;
if (flags & RTF_HOST) { if (flags & RTF_HOST) {
mask = 0xffffffff; mask = 0xffffffff;
rt->rt_dst = dst;
} else { } else {
if (!((dst ^ dev->pa_addr) & dev->pa_mask)) { if (!((dst ^ dev->pa_addr) & dev->pa_mask)) {
mask = dev->pa_mask; mask = dev->pa_mask;
dst &= mask; dst &= mask;
flags &= ~RTF_GATEWAY;
if (flags & RTF_DYNAMIC) { if (flags & RTF_DYNAMIC) {
kfree_s(rt, sizeof(struct rtable));
/*printk("Dynamic route to my own net rejected\n");*/ /*printk("Dynamic route to my own net rejected\n");*/
return; return;
} }
} else } else
mask = guess_mask(dst); mask = guess_mask(dst);
rt->rt_dst = dst;
} }
if (gw == dev->pa_addr)
flags &= ~RTF_GATEWAY;
if (flags & RTF_GATEWAY) {
/* don't try to add a gateway we can't reach.. */
if (dev != get_gw_dev(gw))
return;
flags |= RTF_GATEWAY;
} else
gw = 0;
/* Allocate an entry. */
rt = (struct rtable *) kmalloc(sizeof(struct rtable), GFP_ATOMIC);
if (rt == NULL) {
DPRINTF((DBG_RT, "RT: no memory for new route!\n"));
return;
}
memset(rt, 0, sizeof(struct rtable));
rt->rt_flags = flags | RTF_UP;
rt->rt_dst = dst;
rt->rt_dev = dev;
rt->rt_gateway = gw;
rt->rt_mask = mask; rt->rt_mask = mask;
rt_print(rt); rt_print(rt);
/* /*
...@@ -206,7 +236,6 @@ static int ...@@ -206,7 +236,6 @@ static int
rt_new(struct rtentry *r) rt_new(struct rtentry *r)
{ {
struct device *dev; struct device *dev;
struct rtable *rt;
if ((r->rt_dst.sa_family != AF_INET) || if ((r->rt_dst.sa_family != AF_INET) ||
(r->rt_gateway.sa_family != AF_INET)) { (r->rt_gateway.sa_family != AF_INET)) {
...@@ -226,11 +255,7 @@ rt_new(struct rtentry *r) ...@@ -226,11 +255,7 @@ rt_new(struct rtentry *r)
if (!(r->rt_flags & RTF_GATEWAY)) if (!(r->rt_flags & RTF_GATEWAY))
dev = dev_check(((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr); dev = dev_check(((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr);
else else
if ((rt = rt_route(((struct sockaddr_in *) &r->rt_gateway)->sin_addr. dev = get_gw_dev(((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr);
s_addr,NULL)))
dev = rt->rt_dev;
else
dev = NULL;
DPRINTF((DBG_RT, "RT: dev for %s gw ", DPRINTF((DBG_RT, "RT: dev for %s gw ",
in_ntoa((*(struct sockaddr_in *)&r->rt_dst).sin_addr.s_addr))); in_ntoa((*(struct sockaddr_in *)&r->rt_dst).sin_addr.s_addr)));
...@@ -269,13 +294,14 @@ rt_get_info(char *buffer) ...@@ -269,13 +294,14 @@ rt_get_info(char *buffer)
pos = buffer; pos = buffer;
pos += sprintf(pos, pos += sprintf(pos,
"Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\n"); "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\n");
/* This isn't quite right -- r->rt_dst is a struct! */ /* This isn't quite right -- r->rt_dst is a struct! */
for (r = rt_base; r != NULL; r = r->rt_next) { for (r = rt_base; r != NULL; r = r->rt_next) {
pos += sprintf(pos, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\n", pos += sprintf(pos, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\n",
r->rt_dev->name, r->rt_dst, r->rt_gateway, r->rt_dev->name, r->rt_dst, r->rt_gateway,
r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric); r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric,
r->rt_mask);
} }
return(pos - buffer); return(pos - buffer);
} }
......
...@@ -212,14 +212,16 @@ int main(int argc, char ** argv) ...@@ -212,14 +212,16 @@ int main(int argc, char ** argv)
fprintf(stderr, "Unexpected EOF\n"); fprintf(stderr, "Unexpected EOF\n");
die("Can't read 'system'"); die("Can't read 'system'");
} }
write(1, buf, l); if (write(1, buf, l) != l)
die("Write failed");
sz -= l; sz -= l;
} }
close(id); close(id);
if (lseek(1,500,0) == 500) { if (lseek(1,500,0) == 500) {
buf[0] = (sys_size & 0xff); buf[0] = (sys_size & 0xff);
buf[1] = ((sys_size >> 8) & 0xff); buf[1] = ((sys_size >> 8) & 0xff);
write(1, buf, 2); if (write(1, buf, 2) != 2)
die("Write failed");
} }
return(0); return(0);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment