]> git.neil.brown.name Git - history.git/commitdiff
Import 0.99.14i 0.99.14i
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:17 +0000 (15:09 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:17 +0000 (15:09 -0500)
14 files changed:
drivers/scsi/scsi.c
drivers/scsi/scsi.h
drivers/scsi/st.c
drivers/scsi/st.h
fs/nfs/proc.c
include/linux/in.h
ipc/msg.c
ipc/sem.c
ipc/shm.c
kernel/printk.c
net/inet/icmp.c
net/inet/inet.h
net/inet/route.c
tools/build.c

index 630c01e58aa944254c25a73fcb32f8b495e7be5c..a2083b8278783f0553b07aa85fb1001e133269ba 100644 (file)
@@ -922,8 +922,12 @@ static int check_sense (Scsi_Cmnd * SCpnt)
                switch (SCpnt->sense_buffer[2] & 0xf)
                {
                case NO_SENSE:
-               case RECOVERED_ERROR:
                        return 0;
+               case RECOVERED_ERROR:
+                       if (scsi_devices[SCpnt->index].type == TYPE_TAPE)
+                         return SUGGEST_IS_OK;
+                       else
+                         return 0;
 
                case ABORTED_COMMAND:
                        return SUGGEST_RETRY;   
@@ -1041,6 +1045,8 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
                                                update_timeout(SCpnt, oldto);
                                                status = REDO;
                                                break;
+                                       case SUGGEST_IS_OK:
+                                               break;
                                        case SUGGEST_REMAP:                     
                                        case SUGGEST_RETRY: 
 #ifdef DEBUG
index 08a2035a6720d85af8f06c1b4b0c3f41b4af8ea2..381b86bbe3b1d373ae0c3aa8be0596267d08ef69 100644 (file)
@@ -192,6 +192,7 @@ extern const unsigned char scsi_command_size[8];
 #define SUGGEST_REMAP          0x30
 #define SUGGEST_DIE            0x40
 #define SUGGEST_SENSE          0x80
+#define SUGGEST_IS_OK          0xff
 
 #define DRIVER_SENSE           0x08
 
index a1386553d9353e8982c18a738505bc82a9bab325..1e5c2e9a7879417a3c298e2accfe5bd5c6b231eb 100644 (file)
@@ -5,6 +5,8 @@
 
   History:
   Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
+  Contribution and ideas from several people including Eric Youngdale and
+  Wolfgang Denk.
 
   Features:
   - support for different block sizes and internal buffering
   Nonrewind device has the minor number equal to tape number + 128.
 
   Problems:
-  The end of media detection may not work correctly because of the buffering.
-  If you want to do multiple tape backups relying on end of tape detection,
-  you should disable write behind and in addition to that check that the
-  tapes are readable.
+  The end of media detection works correctly in writing only if the drive
+  writes the buffer contents after the early-warning mark. If you want to
+  be sure that EOM is reported correctly, you should uncomment the line
+  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
                 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 "scsi.h"
 #include "scsi_ioctl.h"
 #include "st.h"
-
-#define MAX_RETRIES 0
-#define MAX_READY_RETRIES 5
-#define NO_TAPE  NOT_READY
+#include "constants.h"
 
 /* Uncomment the following if you want the rewind, etc. commands return
    before command completion. */
    to the filemarks even wihout ST_IN_FILE_POS defined */
 /* #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
-#define ST_LONG_TIMEOUT 200000
+/* Uncomment the following if you want all data from a write command to
+   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 */
 #define ST_BUFFER_BLOCKS 64
-/* Write-behind can be disabled by setting ST_WRITE_THRESHOLD_BLOCKS equal to or
-   larger than ST_BUFFER_BLOCKS */
+/* Write-behind can be disabled by setting ST_WRITE_THRESHOLD_BLOCKS equal
+   to or larger than ST_BUFFER_BLOCKS */
 #define ST_WRITE_THRESHOLD_BLOCKS 60
 #define ST_BLOCK_SIZE 512
 #define ST_BUFFER_SIZE (ST_BUFFER_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
    6-byte SCSI read and write commands. */
 #if ST_BUFFER_SIZE >= (2 << 24 - 1)
 #error "Buffer size should not exceed (2 << 24 - 1) bytes!"
 #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 ST_buffer *st_buffers[2];
 
@@ -99,72 +116,113 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
 
 
 \f
-/* 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 */
-static int st_chk_result(Scsi_Cmnd * SCpnt)
+       static int
+st_chk_result(Scsi_Cmnd * SCpnt)
 {
-#ifdef DEBUG
   int dev = SCpnt->request.dev;
-#endif
   int result = SCpnt->result;
   unsigned char * sense = SCpnt->sense_buffer;
+  char *stp;
 
-  if (!result)
+  if (!result && SCpnt->sense_buffer[0] == 0)
     return 0;
 #ifdef DEBUG
   printk("st%d: Error: %x\n", dev, result);
   print_sense("st", SCpnt);
 #endif
+/*  if ((sense[0] & 0x70) == 0x70 &&
+       ((sense[2] & 0x80) ))
+    return 0; */
   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 (-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
 /* 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();
-  if (scsi_tapes[dev].buffer->last_result < 0) {
-    scsi_tapes[dev].buffer->writing = (- scsi_tapes[dev].buffer->writing);
-    sleep_on( &scsi_tapes[dev].waiting );
-    scsi_tapes[dev].buffer->writing = (- scsi_tapes[dev].buffer->writing);
+  if (STbuffer->last_result < 0) {
+    STbuffer->writing = (- STbuffer->writing);
+    sleep_on( &(STp->waiting) );
+    STbuffer->writing = (- STbuffer->writing);
   }
   sti();
 
-  if (scsi_tapes[dev].buffer->writing < scsi_tapes[dev].buffer->buffer_bytes)
-    memcpy(scsi_tapes[dev].buffer->b_data,
-          scsi_tapes[dev].buffer->b_data + scsi_tapes[dev].buffer->writing,
-          scsi_tapes[dev].buffer->buffer_bytes -
-          scsi_tapes[dev].buffer->writing);
-  scsi_tapes[dev].buffer->buffer_bytes -= scsi_tapes[dev].buffer->writing;
-  scsi_tapes[dev].buffer->writing = 0;
+  if (STbuffer->writing < STbuffer->buffer_bytes)
+    memcpy(STbuffer->b_data,
+          STbuffer->b_data + STbuffer->writing,
+          STbuffer->buffer_bytes - STbuffer->writing);
+  STbuffer->buffer_bytes -= STbuffer->writing;
+  STbuffer->writing = 0;
 
   return;
 }
@@ -172,63 +230,72 @@ static void write_behind_check(int dev)
 
 
 /* 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 result;
   unsigned char cmd[10];
   Scsi_Cmnd *SCpnt;
+  Scsi_Tape *STp = &(scsi_tapes[dev]);
 
 #if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS
-  if (scsi_tapes[dev].buffer->writing) {
+  if ((STp->buffer)->writing) {
     write_behind_check(dev);
-    if (scsi_tapes[dev].buffer->last_result) {
+    if ((STp->buffer)->last_result_fatal) {
 #ifdef DEBUG
       printk("st%d: Async write error %x.\n", dev,
-            scsi_tapes[dev].buffer->last_result);
+            (STp->buffer)->last_result);
 #endif
+      if ((STp->buffer)->last_result == INT_MAX)
+       return (-ENOSPC);
       return (-EIO);
     }
   }
 #endif
 
   result = 0;
-  if (scsi_tapes[dev].dirty==1) {
-    SCpnt = allocate_device(NULL, scsi_tapes[dev].device->index, 1);
+  if (STp->dirty == 1) {
+    SCpnt = allocate_device(NULL, (STp->device)->index, 1);
 
-    offset = scsi_tapes[dev].buffer->buffer_bytes;
-    transfer = ((offset + scsi_tapes[dev].block_size - 1) /
-               scsi_tapes[dev].block_size) * scsi_tapes[dev].block_size;
+    offset = (STp->buffer)->buffer_bytes;
+    transfer = ((offset + STp->block_size - 1) /
+               STp->block_size) * STp->block_size;
 #ifdef DEBUG
     printk("st%d: Flushing %d bytes.\n", dev, transfer);
 #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;
     memset(cmd, 0, 10);
     cmd[0] = WRITE_6;
     cmd[1] = 1;
-    blks = transfer / scsi_tapes[dev].block_size;
+    blks = transfer / STp->block_size;
     cmd[2] = blks >> 16;
     cmd[3] = blks >> 8;
     cmd[4] = blks;
     SCpnt->request.dev = dev;
     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);
 
-    if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting );
+    if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) );
 
-    if (SCpnt->result != 0) {
-      printk("st%d: Error on flush:\n", dev);
-#ifdef DEBUG
-      st_chk_result(SCpnt);
-#endif
-      result = (-EIO);
+    if ((STp->buffer)->last_result_fatal != 0) {
+      printk("st%d: Error on flush.\n", dev);
+      if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
+         (SCpnt->sense_buffer[2] & 0x40) &&
+         (SCpnt->sense_buffer[2] & 0x0f) != VOLUME_OVERFLOW) {
+       STp->dirty = 0;
+       (STp->buffer)->buffer_bytes = 0;
+       result = (-ENOSPC);
+      }
+      else
+       result = (-EIO);
     }
     else {
-      scsi_tapes[dev].dirty = 0;
-      scsi_tapes[dev].buffer->buffer_bytes = 0;
+      STp->dirty = 0;
+      (STp->buffer)->buffer_bytes = 0;
     }
     SCpnt->request.dev = -1;  /* Mark as not busy */
   }
@@ -238,33 +305,41 @@ static int flush_write_buffer(int dev)
 
 /* Flush the tape buffer. The tape will be positioned correctly unless
    seek_next is true. */
-static int flush_buffer(struct inode * inode, struct file * filp,
-                       int seek_next)
+       static int
+flush_buffer(struct inode * inode, struct file * filp, int seek_next)
 {
   int dev;
   int backspace, result;
+  Scsi_Tape * STp;
+  ST_buffer * STbuffer;
 
   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);
 
-  if (scsi_tapes[dev].block_size == 0)
+  if (STp->block_size == 0)
     return 0;
 
-  backspace = (scsi_tapes[dev].buffer->buffer_bytes +
-    scsi_tapes[dev].buffer->read_pointer) / scsi_tapes[dev].block_size -
-      (scsi_tapes[dev].buffer->read_pointer + scsi_tapes[dev].block_size - 1) /
-       scsi_tapes[dev].block_size;
-  scsi_tapes[dev].buffer->buffer_bytes = 0;
-  scsi_tapes[dev].buffer->read_pointer = 0;
+  backspace = ((STp->buffer)->buffer_bytes +
+    (STp->buffer)->read_pointer) / STp->block_size -
+      ((STp->buffer)->read_pointer + STp->block_size - 1) /
+       STp->block_size;
+  (STp->buffer)->buffer_bytes = 0;
+  (STp->buffer)->read_pointer = 0;
   result = 0;
-  if (!seek_next && backspace > 0) {
-    result = st_int_ioctl(inode, filp, MTBSR, backspace);
-    if (!result) {
-      scsi_tapes[dev].eof = 0;
-      scsi_tapes[dev].eof_hit = 0;
+  if (!seek_next) {
+    if ((STp->eof == ST_FM) && !STp->eof_hit) {
+      result = st_int_ioctl(inode, filp, MTBSF, 1); /* Back over the EOF hit */
+      if (!result) {
+       STp->eof = ST_NOEOF;
+       STp->eof_hit = 0;
+      }
     }
+    if (!result && backspace > 0)
+      result = st_int_ioctl(inode, filp, MTBSR, backspace);
   }
   return result;
 
@@ -272,18 +347,21 @@ static int flush_buffer(struct inode * inode, struct file * filp,
 
 \f
 /* 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;
     unsigned short flags;
     int i;
     unsigned char cmd[10];
     Scsi_Cmnd * SCpnt;
+    Scsi_Tape * STp;
 
     dev = MINOR(inode->i_rdev) & 127;
     if (dev >= NR_ST)
       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);
       return (-EBUSY);
     }
@@ -296,20 +374,21 @@ static int scsi_tape_open(struct inode * inode, struct file * filp)
       printk("st%d: No free buffers.\n", dev);
       return (-EBUSY);
     }
-    st_buffers[i]->in_use = 1;
-    st_buffers[i]->writing = 0;
-    scsi_tapes[dev].buffer = st_buffers[i];
-    scsi_tapes[dev].in_use = 1;
+    STp->buffer = st_buffers[i];
+    (STp->buffer)->in_use = 1;
+    (STp->buffer)->writing = 0;
+    STp->in_use = 1;
 
     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;
-    scsi_tapes[dev].rw = 0;
-    scsi_tapes[dev].eof = 0;
-    scsi_tapes[dev].eof_hit = 0;
+    STp->dirty = 0;
+    STp->rw = ST_IDLE;
+    STp->eof = ST_NOEOF;
+    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) {
       printk("st%d: Tape request not allocated", dev);
       return (-EBUSY);
@@ -320,40 +399,34 @@ static int scsi_tape_open(struct inode * inode, struct file * filp)
     cmd[0] = TEST_UNIT_READY;
     SCpnt->request.dev = dev;
     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,
                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 &&
        (SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
-#ifdef DEBUG
-      print_sense("st", SCpnt);
-#endif
       SCpnt->sense_buffer[0]=0;
       memset ((void *) &cmd[0], 0, 10);
       cmd[0] = TEST_UNIT_READY;
       SCpnt->request.dev = dev;
       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,
                  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) {
-#ifdef DEBUG
-      print_sense("st", SCpnt);
-#endif
+    if ((STp->buffer)->last_result_fatal != 0) {
       if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
          (SCpnt->sense_buffer[2] & 0x0f) == NO_TAPE)
        printk("st%d: No tape.\n", dev);
       else
        printk("st%d: Error %x.\n", dev, SCpnt->result);
-      scsi_tapes[dev].buffer->in_use = 0;
-      scsi_tapes[dev].in_use = 0;
+      (STp->buffer)->in_use = 0;
+      STp->in_use = 0;
       SCpnt->request.dev = -1;  /* Mark as not busy */
       return (-EIO);
     }
@@ -363,23 +436,23 @@ static int scsi_tape_open(struct inode * inode, struct file * filp)
     cmd[0] = READ_BLOCK_LIMITS;
     SCpnt->request.dev = dev;
     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);
 
-    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]) {
-      scsi_tapes[dev].max_block = (scsi_tapes[dev].buffer->b_data[1] << 16) |
-       (scsi_tapes[dev].buffer->b_data[2] << 8) | scsi_tapes[dev].buffer->b_data[3];
-      scsi_tapes[dev].min_block = (scsi_tapes[dev].buffer->b_data[4] << 8) |
-       scsi_tapes[dev].buffer->b_data[5];
+      STp->max_block = ((STp->buffer)->b_data[1] << 16) |
+       ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3];
+      STp->min_block = ((STp->buffer)->b_data[4] << 8) |
+       (STp->buffer)->b_data[5];
 #ifdef DEBUG
-      printk("st%d: Block limits %d - %d bytes.\n", dev, scsi_tapes[dev].min_block,
-            scsi_tapes[dev].max_block);
+      printk("st%d: Block limits %d - %d bytes.\n", dev, STp->min_block,
+            STp->max_block);
 #endif
     }
     else {
-      scsi_tapes[dev].min_block = scsi_tapes[dev].max_block = (-1);
+      STp->min_block = STp->max_block = (-1);
 #ifdef DEBUG
       printk("st%d: Can't read block limits.\n", dev);
 #endif
@@ -391,73 +464,69 @@ static int scsi_tape_open(struct inode * inode, struct file * filp)
     cmd[4] = 12;
     SCpnt->request.dev = dev;
     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);
 
-    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 (i) {
+    if ((STp->buffer)->last_result_fatal != 0) {
 #ifdef DEBUG
       printk("st%d: No Mode Sense.\n", dev);
 #endif
-      scsi_tapes[dev].buffer->b_data[2] =
-      scsi_tapes[dev].buffer->b_data[3] = 0;
+      (STp->buffer)->b_data[2] =
+      (STp->buffer)->b_data[3] = 0;
     }
     SCpnt->request.dev = -1;  /* Mark as not busy */
 
 #ifdef DEBUG
     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],
-          scsi_tapes[dev].buffer->b_data[2], scsi_tapes[dev].buffer->b_data[3]);
+          (STp->buffer)->b_data[0], (STp->buffer)->b_data[1],
+          (STp->buffer)->b_data[2], (STp->buffer)->b_data[3]);
 #endif
 
-    if (scsi_tapes[dev].buffer->b_data[3] >= 8) {
-      scsi_tapes[dev].drv_buffer = (scsi_tapes[dev].buffer->b_data[2] >> 4) & 7;
-      scsi_tapes[dev].density = scsi_tapes[dev].buffer->b_data[4];
-      scsi_tapes[dev].block_size = scsi_tapes[dev].buffer->b_data[9] * 65536 +
-       scsi_tapes[dev].buffer->b_data[10] * 256 + scsi_tapes[dev].buffer->b_data[11];
+    if ((STp->buffer)->b_data[3] >= 8) {
+      STp->drv_buffer = ((STp->buffer)->b_data[2] >> 4) & 7;
+      STp->density = (STp->buffer)->b_data[4];
+      STp->block_size = (STp->buffer)->b_data[9] * 65536 +
+       (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11];
 #ifdef DEBUG
-      printk("st%d: Density %x, tape length: %x, blocksize: %d, drv buffer: %d\n", dev,
-            scsi_tapes[dev].buffer->b_data[4], scsi_tapes[dev].buffer->b_data[5] *
-            65536 + scsi_tapes[dev].buffer->b_data[6] * 256 +
-            scsi_tapes[dev].buffer->b_data[7], scsi_tapes[dev].buffer->b_data[9] *
-            65536 + scsi_tapes[dev].buffer->b_data[10] * 256 +
-            scsi_tapes[dev].buffer->b_data[11],
-            scsi_tapes[dev].drv_buffer);
+      printk(
+       "st%d: Density %x, tape length: %x, blocksize: %d, drv buffer: %d\n",
+            dev, STp->density, (STp->buffer)->b_data[5] * 65536 +
+            (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7],
+            STp->block_size, STp->drv_buffer);
 #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,
-              scsi_tapes[dev].block_size);
-       scsi_tapes[dev].buffer->in_use = 0;
-       scsi_tapes[dev].in_use = 0;
+              STp->block_size);
+       (STp->buffer)->in_use = 0;
+       STp->in_use = 0;
        return (-EIO);
       }
 
     }
     else
-      scsi_tapes[dev].block_size = ST_BLOCK_SIZE;
+      STp->block_size = ST_BLOCK_SIZE;
 
-    if (scsi_tapes[dev].block_size > 0) {
-      scsi_tapes[dev].buffer->buffer_blocks =
-       ST_BUFFER_SIZE / scsi_tapes[dev].block_size;
-      scsi_tapes[dev].buffer->buffer_size =
-       scsi_tapes[dev].buffer->buffer_blocks * scsi_tapes[dev].block_size;
+    if (STp->block_size > 0) {
+      (STp->buffer)->buffer_blocks = ST_BUFFER_SIZE / STp->block_size;
+      (STp->buffer)->buffer_size =
+       (STp->buffer)->buffer_blocks * STp->block_size;
     }
     else {
-      scsi_tapes[dev].buffer->buffer_blocks = 1;
-      scsi_tapes[dev].buffer->buffer_size = ST_BUFFER_SIZE;
+      (STp->buffer)->buffer_blocks = 1;
+      (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
     printk("st%d: Block size: %d, buffer size: %d (%d blocks).\n", dev,
-          scsi_tapes[dev].block_size, scsi_tapes[dev].buffer->buffer_size,
-          scsi_tapes[dev].buffer->buffer_blocks);
+          STp->block_size, (STp->buffer)->buffer_size,
+          (STp->buffer)->buffer_blocks);
 #endif
 
-    if (scsi_tapes[dev].buffer->b_data[2] & 0x80) {
-      scsi_tapes[dev].write_prot = 1;
+    if ((STp->buffer)->b_data[2] & 0x80) {
+      STp->write_prot = 1;
 #ifdef DEBUG
       printk( "st%d: Write protected\n", dev);
 #endif
@@ -468,19 +537,22 @@ static int scsi_tape_open(struct inode * inode, struct file * filp)
 
 \f
 /* 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 result;
     int rewind;
     static unsigned char cmd[10];
     Scsi_Cmnd * SCpnt;
+    Scsi_Tape * STp;
    
     dev = MINOR(inode->i_rdev);
     rewind = (dev & 0x80) == 0;
     dev = dev & 127;
+    STp = &(scsi_tapes[dev]);
 
-    if ( scsi_tapes[dev].rw == 2) {
+    if ( STp->rw == ST_WRITING) {
 
       result = flush_write_buffer(dev);
 
@@ -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);
 #endif
 
-      if (!result) {
-       SCpnt = allocate_device(NULL, scsi_tapes[dev].device->index, 1);
+      if (result == 0 || result == (-ENOSPC)) {
+       SCpnt = allocate_device(NULL, (STp->device)->index, 1);
 
        SCpnt->sense_buffer[0] = 0;
        memset(cmd, 0, 10);
@@ -497,17 +569,14 @@ static void scsi_tape_close(struct inode * inode, struct file * filp)
        cmd[4] = 1;
        SCpnt->request.dev = dev;
        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);
 
-       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);
-#ifdef DEBUG
-         st_chk_result(SCpnt);
-#endif
-       }
+
        SCpnt->request.dev = -1;  /* Mark as not busy */
       }
 
@@ -516,9 +585,10 @@ static void scsi_tape_close(struct inode * inode, struct file * filp)
 #endif
     }
     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 */
-#ifdef ST_IN_FILE_POS
+#else
       flush_buffer(inode, filp, 0);
 #endif
     }
@@ -526,117 +596,169 @@ static void scsi_tape_close(struct inode * inode, struct file * filp)
     if (rewind)
       st_int_ioctl(inode, filp, MTREW, 1);
 
-    scsi_tapes[dev].buffer->in_use = 0;
-    scsi_tapes[dev].in_use = 0;
+    (STp->buffer)->in_use = 0;
+    STp->in_use = 0;
 
     return;
 }
 
 \f
 /* 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 total, do_count, blks, retval;
+    int total, do_count, blks, retval, transfer;
+    int write_threshold;
     static unsigned char cmd[10];
     char *b_point;
     Scsi_Cmnd * SCpnt;
+    Scsi_Tape * STp;
 
     dev = MINOR(inode->i_rdev) & 127;
+    STp = &(scsi_tapes[dev]);
 #ifdef DEBUG
-    if (!scsi_tapes[dev].in_use) {
+    if (!STp->in_use) {
       printk("st%d: Incorrect device.\n", dev);
       return (-EIO);
     }
 #endif
 
-    if (scsi_tapes[dev].write_prot)
+    if (STp->write_prot)
       return (-EACCES);
 
-    if (scsi_tapes[dev].block_size == 0 && count > ST_BUFFER_SIZE)
+    if (STp->block_size == 0 && count > ST_BUFFER_SIZE)
       return (-EOVERFLOW);
 
-    if (scsi_tapes[dev].rw == 1) {
+    if (STp->rw == ST_READING) {
       retval = flush_buffer(inode, filp, 0);
       if (retval)
        return retval;
-      scsi_tapes[dev].rw = 2;
+      STp->rw = ST_WRITING;
     }
 
 #if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS
-    if (scsi_tapes[dev].buffer->writing) {
+    if ((STp->buffer)->writing) {
       write_behind_check(dev);
-      if (scsi_tapes[dev].buffer->last_result) {
+      if ((STp->buffer)->last_result_fatal) {
 #ifdef DEBUG
        printk("st%d: Async write error %x.\n", dev,
-              scsi_tapes[dev].buffer->last_result);
+              (STp->buffer)->last_result);
 #endif
-       /*if (scsi_tapes[dev].buffer->last_result = INT_MAX)
-         retval = (-ENOSPC);
-       else */
+       if ((STp->buffer)->last_result == INT_MAX) {
+         retval = (-ENOSPC);  /* All has been written */
+         STp->eof = ST_EOM_OK;
+       }
+       else
          retval = (-EIO);
        return retval;
       }
     }
 #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;
 
     memset(cmd, 0, 10);
     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;
     while(
 #if ST_WRITE_THRESHOLD_BLOCKS  < ST_BUFFER_BLOCKS
-         scsi_tapes[dev].block_size != 0 &&
-         (scsi_tapes[dev].buffer->buffer_bytes + count) >
-         scsi_tapes[dev].buffer->buffer_size)
+         STp->block_size != 0 &&
+         ((STp->buffer)->buffer_bytes + count) >
+         write_threshold)
 #else
-         (scsi_tapes[dev].block_size == 0 && count > 0) ||
-         (scsi_tapes[dev].buffer->buffer_bytes + count) >=
-         scsi_tapes[dev].buffer->buffer_size)
+         (STp->block_size == 0 && count > 0) ||
+         ((STp->buffer)->buffer_bytes + count) >=
+         write_threshold)
 #endif
     {
-      if (scsi_tapes[dev].block_size == 0)
+      if (STp->block_size == 0)
        do_count = count;
-      else
-       do_count = scsi_tapes[dev].buffer->buffer_size -
-         scsi_tapes[dev].buffer->buffer_bytes;
-      memcpy_fromfs(scsi_tapes[dev].buffer->b_data +
-                   scsi_tapes[dev].buffer->buffer_bytes, b_point, do_count);
+      else {
+       do_count = (STp->buffer)->buffer_size - (STp->buffer)->buffer_bytes;
+       if (do_count > count)
+         do_count = 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;
       else
-       blks = scsi_tapes[dev].buffer->buffer_blocks;
+       blks = ((STp->buffer)->buffer_bytes + do_count) /
+         STp->block_size;
       cmd[2] = blks >> 16;
       cmd[3] = blks >> 8;
       cmd[4] = blks;
       SCpnt->sense_buffer[0] = 0;
       SCpnt->request.dev = dev;
       scsi_do_cmd (SCpnt,
-                  (void *) cmd, scsi_tapes[dev].buffer->b_data,
-                  scsi_tapes[dev].buffer->buffer_size,
+                  (void *) cmd, (STp->buffer)->b_data,
+                  (STp->buffer)->buffer_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 || SCpnt->sense_buffer[0] != 0) {
+      if ((STp->buffer)->last_result_fatal != 0) {
 #ifdef DEBUG
        printk("st%d: Error on write:\n", dev);
-       st_chk_result(SCpnt);
 #endif
        if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
-           (SCpnt->sense_buffer[2] & 0x40))
-         retval = (-ENOSPC); /* EOM */
+           (SCpnt->sense_buffer[2] & 0x40)) {
+         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
          retval = (-EIO);
+
        SCpnt->request.dev = -1;  /* Mark as not busy */
+       (STp->buffer)->buffer_bytes = 0;
+       STp->dirty = 0;
        if (count < total)
          return total - count;
        else
@@ -645,48 +767,47 @@ int st_write(struct inode * inode, struct file * filp, char * buf, int count)
       filp->f_pos += do_count;
       b_point += do_count;
       count -= do_count;
-      scsi_tapes[dev].buffer->buffer_bytes = 0;
-      scsi_tapes[dev].dirty = 0;
+      (STp->buffer)->buffer_bytes = 0;
+      STp->dirty = 0;
     }
     if (count != 0) {
-      scsi_tapes[dev].dirty = 1;
-      memcpy_fromfs(scsi_tapes[dev].buffer->b_data +
-                   scsi_tapes[dev].buffer->buffer_bytes,b_point,count);
+      STp->dirty = 1;
+      memcpy_fromfs((STp->buffer)->b_data +
+                   (STp->buffer)->buffer_bytes,b_point,count);
       filp->f_pos += count;
-      scsi_tapes[dev].buffer->buffer_bytes += count;
+      (STp->buffer)->buffer_bytes += count;
       count = 0;
     }
 
-    do_count = st_chk_result(SCpnt);
-    if (do_count) {
+    if ((STp->buffer)->last_result_fatal != 0) {
       SCpnt->request.dev = -1;
-      return do_count;
+      return (STp->buffer)->last_result_fatal;
     }
 
 #if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS
-    if (scsi_tapes[dev].buffer->buffer_bytes >= ST_WRITE_THRESHOLD ||
-       scsi_tapes[dev].block_size == 0) {
+    if ((STp->buffer)->buffer_bytes >= ST_WRITE_THRESHOLD ||
+       STp->block_size == 0) {
       /* Schedule an asynchronous write */
-      if (scsi_tapes[dev].block_size == 0)
-       scsi_tapes[dev].buffer->writing = scsi_tapes[dev].buffer->buffer_bytes;
+      if (STp->block_size == 0)
+       (STp->buffer)->writing = (STp->buffer)->buffer_bytes;
       else
-       scsi_tapes[dev].buffer->writing = (scsi_tapes[dev].buffer->buffer_bytes /
-         scsi_tapes[dev].block_size) * scsi_tapes[dev].block_size;
-      scsi_tapes[dev].dirty = 0;
+       (STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
+         STp->block_size) * STp->block_size;
+      STp->dirty = 0;
 
-      if (scsi_tapes[dev].block_size == 0)
-       blks = scsi_tapes[dev].buffer->writing;
+      if (STp->block_size == 0)
+       blks = (STp->buffer)->writing;
       else
-       blks = scsi_tapes[dev].buffer->writing / scsi_tapes[dev].block_size;
+       blks = (STp->buffer)->writing / STp->block_size;
       cmd[2] = blks >> 16;
       cmd[3] = blks >> 8;
       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->request.dev = dev;
       scsi_do_cmd (SCpnt,
-                  (void *) cmd, scsi_tapes[dev].buffer->b_data,
-                  scsi_tapes[dev].buffer->writing,
+                  (void *) cmd, (STp->buffer)->b_data,
+                  (STp->buffer)->writing,
                   st_sleep_done, ST_TIMEOUT, MAX_RETRIES);
     }
     else
@@ -698,58 +819,61 @@ int st_write(struct inode * inode, struct file * filp, char * buf, int count)
 
 \f
 /* 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 total;
     int transfer, blks, bytes;
     static unsigned char cmd[10];
     Scsi_Cmnd * SCpnt;
+    Scsi_Tape * STp;
 
     dev = MINOR(inode->i_rdev) & 127;
+    STp = &(scsi_tapes[dev]);
 #ifdef DEBUG
-    if (!scsi_tapes[dev].in_use) {
+    if (!STp->in_use) {
       printk("st%d: Incorrect device.\n", dev);
       return (-EIO);
     }
 #endif
 
-    if (scsi_tapes[dev].block_size == 0 && count > ST_BUFFER_SIZE)
+    if (STp->block_size == 0 && count > ST_BUFFER_SIZE)
       return (-EOVERFLOW);
 
-    if (scsi_tapes[dev].rw == 2) {
+    if (STp->rw == ST_WRITING) {
       transfer = flush_buffer(inode, filp, 0);
       if (transfer)
        return transfer;
-      scsi_tapes[dev].rw = 1;
+      STp->rw = ST_READING;
     }
 
 #ifdef DEBUG
-    if (scsi_tapes[dev].eof)
+    if (STp->eof != ST_NOEOF)
       printk("st%d: EOF flag up. Bytes %d\n", dev,
-            scsi_tapes[dev].buffer->buffer_bytes);
+            (STp->buffer)->buffer_bytes);
 #endif
-    if ((scsi_tapes[dev].buffer->buffer_bytes == 0) &&
-       scsi_tapes[dev].eof == 2)  /* EOM or Blank Check */
+    if (((STp->buffer)->buffer_bytes == 0) &&
+       STp->eof == ST_EOM_OK)  /* EOM or Blank Check */
       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; ) {
 
-      if (scsi_tapes[dev].buffer->buffer_bytes == 0 &&
-         scsi_tapes[dev].eof == 0) {
+      if ((STp->buffer)->buffer_bytes == 0 &&
+         STp->eof == ST_NOEOF) {
 
        memset(cmd, 0, 10);
        cmd[0] = READ_6;
-       cmd[1] = (scsi_tapes[dev].block_size != 0);
-       if (scsi_tapes[dev].block_size == 0)
+       cmd[1] = (STp->block_size != 0);
+       if (STp->block_size == 0)
          blks = bytes = count;
        else {
-         blks = scsi_tapes[dev].buffer->buffer_blocks;
-         bytes = blks * scsi_tapes[dev].block_size;
+         blks = (STp->buffer)->buffer_blocks;
+         bytes = blks * STp->block_size;
        }
        cmd[2] = blks >> 16;
        cmd[3] = blks >> 8;
@@ -758,16 +882,16 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
        SCpnt->sense_buffer[0] = 0;
        SCpnt->request.dev = dev;
        scsi_do_cmd (SCpnt,
-                    (void *) cmd, scsi_tapes[dev].buffer->b_data,
-                    scsi_tapes[dev].buffer->buffer_size,
+                    (void *) cmd, (STp->buffer)->b_data,
+                    (STp->buffer)->buffer_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) );
 
-       scsi_tapes[dev].buffer->read_pointer = 0;
-       scsi_tapes[dev].eof_hit = 0;
+       (STp->buffer)->read_pointer = 0;
+       STp->eof_hit = 0;
 
-       if (SCpnt->result != 0 || SCpnt->sense_buffer[0] != 0) {
+       if ((STp->buffer)->last_result_fatal) {
 #ifdef DEBUG
          printk("st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", dev,
                 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)
          if ((SCpnt->sense_buffer[0] & 0x70) == 0x70) { /* extended sense */
 
            if ((SCpnt->sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */
-             transfer = (SCpnt->sense_buffer[3] << 24) |
-               (SCpnt->sense_buffer[4] << 16) |
-                 (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6];
+
+             if ((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
+               transfer = 0;
+             if (STp->block_size == 0 &&
+                 (SCpnt->sense_buffer[2] & 0x0f) == MEDIUM_ERROR)
+               transfer = bytes;
 
              if (SCpnt->sense_buffer[2] & 0x20) {
-               if (scsi_tapes[dev].block_size == 0) {
+               if (STp->block_size == 0) {
                  if (transfer <= 0)
                    transfer = 0;
-                 scsi_tapes[dev].buffer->buffer_bytes = count - transfer;
+                 (STp->buffer)->buffer_bytes = count - transfer;
                }
                else {
                  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)
                }
              }
              else if (SCpnt->sense_buffer[2] & 0x40) {
-               scsi_tapes[dev].eof = 2; /* What should be done at EOM ? */
-               scsi_tapes[dev].buffer->buffer_bytes =
-                 (scsi_tapes[dev].buffer->buffer_blocks - transfer) *
-                   scsi_tapes[dev].block_size;
+               STp->eof = ST_EOM_OK;
+               if (STp->block_size == 0)
+                 (STp->buffer)->buffer_bytes = count - transfer;
+               else
+                 (STp->buffer)->buffer_bytes =
+                   ((STp->buffer)->buffer_blocks - transfer) *
+                     STp->block_size;
 #ifdef DEBUG
-               printk("st%d: EOM detected (%d blocks read).\n", dev,
-                      scsi_tapes[dev].buffer->buffer_blocks - transfer);
+               printk("st%d: EOM detected (%d bytes read).\n", dev,
+                      (STp->buffer)->buffer_bytes);
 #endif
              }
              else if (SCpnt->sense_buffer[2] & 0x80) {
-               scsi_tapes[dev].eof = 1;
-               if (scsi_tapes[dev].block_size == 0)
-                 scsi_tapes[dev].buffer->buffer_bytes =
-                   count - transfer;
+               STp->eof = ST_FM;
+               if (STp->block_size == 0)
+                 (STp->buffer)->buffer_bytes = 0;
                else
-                 scsi_tapes[dev].buffer->buffer_bytes =
-                   (scsi_tapes[dev].buffer->buffer_blocks - transfer) *
-                     scsi_tapes[dev].block_size;
+                 (STp->buffer)->buffer_bytes =
+                   ((STp->buffer)->buffer_blocks - transfer) *
+                     STp->block_size;
 #ifdef DEBUG
-               printk("st%d: EOF detected (%d blocks read, transferred %d bytes).\n",
-                      dev, scsi_tapes[dev].buffer->buffer_blocks - transfer, total);
+               printk(
+                "st%d: EOF detected (%d bytes read, transferred %d bytes).\n",
+                      dev, (STp->buffer)->buffer_bytes, total);
 #endif
              } /* end of EOF, EOM, ILI test */
            }
            else { /* nonzero sense key */
 #ifdef DEBUG
-             printk("st%d: Tape error. Sense key %x\n", dev,
-                    SCpnt->sense_buffer[2] & 0x0f);
-             print_sense("st", SCpnt);
+             printk("st%d: Tape error while reading.\n", dev);
 #endif
              SCpnt->request.dev = -1;
              if (total)
@@ -833,44 +965,44 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
            }
          }
          else {
-           transfer = st_chk_result(SCpnt);
+           transfer = (STp->buffer)->last_result_fatal;
            SCpnt->request.dev = -1;  /* Mark as not busy */
            return transfer;
          }
        }
-       else /* Read successfu| */
-         scsi_tapes[dev].buffer->buffer_bytes = bytes;
+       else /* Read successful */
+         (STp->buffer)->buffer_bytes = bytes;
 
-      } /* if (scsi_tapes[dev].buffer->buffer_bytes == 0 &&
-          scsi_tapes[dev].eof == 0) */
+      } /* if ((STp->buffer)->buffer_bytes == 0 &&
+          STp->eof == ST_NOEOF) */
 
-      if (scsi_tapes[dev].buffer->buffer_bytes > 0) {
+      if ((STp->buffer)->buffer_bytes > 0) {
 #ifdef DEBUG
-       if (scsi_tapes[dev].eof)
+       if (STp->eof != ST_NOEOF)
          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
-       transfer = scsi_tapes[dev].buffer->buffer_bytes < count - total ?
-         scsi_tapes[dev].buffer->buffer_bytes : count - total;
-       memcpy_tofs(buf, scsi_tapes[dev].buffer->b_data +
-                   scsi_tapes[dev].buffer->read_pointer,transfer);
+       transfer = (STp->buffer)->buffer_bytes < count - total ?
+         (STp->buffer)->buffer_bytes : count - total;
+       memcpy_tofs(buf, (STp->buffer)->b_data +
+                   (STp->buffer)->read_pointer,transfer);
        filp->f_pos += transfer;
        buf += transfer;
        total += transfer;
-       scsi_tapes[dev].buffer->buffer_bytes -= transfer;
-       scsi_tapes[dev].buffer->read_pointer += transfer;
+       (STp->buffer)->buffer_bytes -= transfer;
+       (STp->buffer)->read_pointer += transfer;
       }
-      else if (scsi_tapes[dev].eof) {
-       scsi_tapes[dev].eof_hit = 1;
+      else if (STp->eof != ST_NOEOF) {
+       STp->eof_hit = 1;
        SCpnt->request.dev = -1;  /* Mark as not busy */
-       if (total == 0 && scsi_tapes[dev].eof == 1)
-         scsi_tapes[dev].eof = 0;
-       if (total == 0 && scsi_tapes[dev].eof == 2)
-         return (-EIO);
+       if (total == 0 && STp->eof == ST_FM)
+         STp->eof = 0;
+       if (total == 0 && STp->eof == ST_EOM_OK)
+         return (-EIO);  /* ST_EOM_ERROR not used in read */
        return total;
       }
 
-      if (scsi_tapes[dev].block_size == 0)
+      if (STp->block_size == 0)
        count = total;  /* Read only one variable length block */
 
     } /* for (total = 0; total < count; ) */
@@ -882,7 +1014,8 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
 
 \f
 /* 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)
 {
    int dev = MINOR(inode->i_rdev);
@@ -891,8 +1024,10 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
    int ioctl_result;
    unsigned char cmd[10];
    Scsi_Cmnd * SCpnt;
+   Scsi_Tape * STp;
 
    dev = dev & 127;
+   STp = &(scsi_tapes[dev]);
 
    memset(cmd, 0, 10);
    switch (cmd_in) {
@@ -904,7 +1039,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
        cmd[3] = (arg >> 8);
        cmd[4] = arg;
 #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]);
 #endif
        break; 
@@ -920,7 +1055,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
        if (cmd[2] & 0x80)
         ltmp = 0xff000000;
        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
        break; 
       case MTFSR:
@@ -949,7 +1084,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
 #endif
        break; 
      case MTWEOF:
-       if (scsi_tapes[dev].write_prot)
+       if (STp->write_prot)
         return (-EACCES);
        cmd[0] = WRITE_FILEMARKS;
        cmd[2] = (arg >> 16);
@@ -1006,7 +1141,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
 #endif
        break; 
      case MTERASE:
-       if (scsi_tapes[dev].write_prot)
+       if (STp->write_prot)
         return (-EACCES);
        cmd[0] = ERASE;
        cmd[1] = 1;  /* To the end of tape */
@@ -1015,7 +1150,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
 #endif
        break;
      case MTSEEK:
-       if (scsi_tapes[dev].device->scsi_level < SCSI_2) {
+       if ((STp->device)->scsi_level < SCSI_2) {
         cmd[0] = QFA_SEEK_BLOCK;
         cmd[2] = (arg >> 16);
         cmd[3] = (arg >> 8);
@@ -1041,11 +1176,11 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
      case MTSETBLK:  /* Set block length */
      case MTSETDENSITY: /* Set tape density */
      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 */
        if (cmd_in == MTSETBLK &&
           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)) {
         printk("st%d: Illegal block size.\n", dev);
         return (-EINVAL);
@@ -1053,37 +1188,37 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
        cmd[0] = MODE_SELECT;
        cmd[4] = 12;
 
-       memset(scsi_tapes[dev].buffer->b_data, 0, 12);
+       memset((STp->buffer)->b_data, 0, 12);
        if (cmd_in == MTSETDRVBUFFER)
-        scsi_tapes[dev].buffer->b_data[2] = (arg & 7) << 4;
+        (STp->buffer)->b_data[2] = (arg & 7) << 4;
        else
-        scsi_tapes[dev].buffer->b_data[2] = 
-          scsi_tapes[dev].drv_buffer << 4;
-       scsi_tapes[dev].buffer->b_data[3] = 8;     /* block descriptor length */
+        (STp->buffer)->b_data[2] = 
+          STp->drv_buffer << 4;
+       (STp->buffer)->b_data[3] = 8;     /* block descriptor length */
        if (cmd_in == MTSETDENSITY)
-        scsi_tapes[dev].buffer->b_data[4] = arg;
+        (STp->buffer)->b_data[4] = arg;
        else
-        scsi_tapes[dev].buffer->b_data[4] = scsi_tapes[dev].density;
+        (STp->buffer)->b_data[4] = STp->density;
        if (cmd_in == MTSETBLK)
         ltmp = arg;
        else
-        ltmp = scsi_tapes[dev].block_size;
-       scsi_tapes[dev].buffer->b_data[9] = (ltmp >> 16);
-       scsi_tapes[dev].buffer->b_data[10] = (ltmp >> 8);
-       scsi_tapes[dev].buffer->b_data[11] = ltmp;
+        ltmp = STp->block_size;
+       (STp->buffer)->b_data[9] = (ltmp >> 16);
+       (STp->buffer)->b_data[10] = (ltmp >> 8);
+       (STp->buffer)->b_data[11] = ltmp;
        timeout = ST_TIMEOUT;
 #ifdef DEBUG
        if (cmd_in == MTSETBLK)
         printk("st%d: Setting block size to %d bytes.\n", dev,
-               scsi_tapes[dev].buffer->b_data[9] * 65536 +
-               scsi_tapes[dev].buffer->b_data[10] * 256 +
-               scsi_tapes[dev].buffer->b_data[11]);
+               (STp->buffer)->b_data[9] * 65536 +
+               (STp->buffer)->b_data[10] * 256 +
+               (STp->buffer)->b_data[11]);
        else if (cmd_in == MTSETDENSITY)
         printk("st%d: Setting density code to %x.\n", dev,
-               scsi_tapes[dev].buffer->b_data[4]);
+               (STp->buffer)->b_data[4]);
        else
-        printk("st%d: Setting drive buffer code to %d.\n",
-               (scsi_tapes[dev].buffer->b_data[2] >> 4) & 7);
+        printk("st%d: Setting drive buffer code to %d.\n", dev,
+               ((STp->buffer)->b_data[2] >> 4) & 7);
 #endif
        break;
      default:
@@ -1091,16 +1226,16 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
        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->request.dev = dev;
    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);
 
-   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 */
 
@@ -1110,31 +1245,31 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
      else if (cmd_in == MTFSFM)
        ioctl_result = st_int_ioctl(inode, file, MTBSF, 1);
      else if (cmd_in == MTSETBLK) {
-       scsi_tapes[dev].block_size = arg;
+       STp->block_size = arg;
        if (arg != 0) {
-        scsi_tapes[dev].buffer->buffer_blocks =
-          ST_BUFFER_SIZE / scsi_tapes[dev].block_size;
-        scsi_tapes[dev].buffer->buffer_size =
-          scsi_tapes[dev].buffer->buffer_blocks * scsi_tapes[dev].block_size;
+        (STp->buffer)->buffer_blocks =
+          ST_BUFFER_SIZE / STp->block_size;
+        (STp->buffer)->buffer_size =
+          (STp->buffer)->buffer_blocks * STp->block_size;
        }
        else {
-        scsi_tapes[dev].buffer->buffer_blocks = 1;
-        scsi_tapes[dev].buffer->buffer_size = ST_BUFFER_SIZE;
+        (STp->buffer)->buffer_blocks = 1;
+        (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;
      }
      else if (cmd_in == MTSETDRVBUFFER)
-       scsi_tapes[dev].drv_buffer = arg;
+       STp->drv_buffer = arg;
      else if (cmd_in == MTSETDENSITY)
-       scsi_tapes[dev].density = arg;
+       STp->density = arg;
      if (cmd_in == MTEOM || cmd_in == MTWEOF) {
-       scsi_tapes[dev].eof = 2;
-       scsi_tapes[dev].eof_hit = 0;
+       STp->eof = ST_EOM_OK;
+       STp->eof_hit = 0;
      }
      else if (cmd_in != MTSETBLK && cmd_in != MTNOP) {
-       scsi_tapes[dev].eof = 0;
-       scsi_tapes[dev].eof_hit = 0;
+       STp->eof = ST_NOEOF;
+       STp->eof_hit = 0;
      }
    }
 
@@ -1144,8 +1279,9 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
 
 \f
 /* The ioctl command */
-static int st_ioctl(struct inode * inode,struct file * file,
-            unsigned int cmd_in, unsigned long arg)
+       static int
+st_ioctl(struct inode * inode,struct file * file,
+        unsigned int cmd_in, unsigned long arg)
 {
    int dev = MINOR(inode->i_rdev);
    int i, cmd, result;
@@ -1153,10 +1289,12 @@ static int st_ioctl(struct inode * inode,struct file * file,
    struct mtpos mt_pos;
    unsigned char scmd[10];
    Scsi_Cmnd *SCpnt;
+   Scsi_Tape *STp;
 
    dev = dev & 127;
+   STp = &(scsi_tapes[dev]);
 #ifdef DEBUG
-   if (!scsi_tapes[dev].in_use) {
+   if (!STp->in_use) {
      printk("st%d: Incorrect device.\n", dev);
      return (-EIO);
    }
@@ -1190,7 +1328,7 @@ static int st_ioctl(struct inode * inode,struct file * file,
      if (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));
      return 0;
    }
@@ -1209,11 +1347,11 @@ static int st_ioctl(struct inode * inode,struct file * file,
      if (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;
      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[4] = 3;
      }
@@ -1224,12 +1362,12 @@ static int st_ioctl(struct inode * inode,struct file * file,
      SCpnt->request.dev = dev;
      SCpnt->sense_buffer[0] = 0;
      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);
 
-     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);
 #ifdef DEBUG
        printk("st%d: Can't read tape position.\n", dev);
@@ -1238,15 +1376,15 @@ static int st_ioctl(struct inode * inode,struct file * file,
      }
      else {
        result = 0;
-       if (scsi_tapes[dev].device->scsi_level < SCSI_2)
-        mt_pos.mt_blkno = (scsi_tapes[dev].buffer->b_data[0] << 16) 
-          + (scsi_tapes[dev].buffer->b_data[1] << 8) 
-            + scsi_tapes[dev].buffer->b_data[2];
+       if ((STp->device)->scsi_level < SCSI_2)
+        mt_pos.mt_blkno = ((STp->buffer)->b_data[0] << 16) 
+          + ((STp->buffer)->b_data[1] << 8) 
+            + (STp->buffer)->b_data[2];
        else
-        mt_pos.mt_blkno = (scsi_tapes[dev].buffer->b_data[4] << 24)
-          + (scsi_tapes[dev].buffer->b_data[5] << 16) 
-            + (scsi_tapes[dev].buffer->b_data[6] << 8) 
-              + scsi_tapes[dev].buffer->b_data[7];
+        mt_pos.mt_blkno = ((STp->buffer)->b_data[4] << 24)
+          + ((STp->buffer)->b_data[5] << 16) 
+            + ((STp->buffer)->b_data[6] << 8) 
+              + (STp->buffer)->b_data[7];
 
      }
 
@@ -1256,7 +1394,7 @@ static int st_ioctl(struct inode * inode,struct file * file,
      return result;
    }
    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)
   for (i=0; i < NR_ST; ++i) {
     scsi_tapes[i].capacity = 0xfffff;
     scsi_tapes[i].dirty = 0;
-    scsi_tapes[i].rw = 0;
-    scsi_tapes[i].eof = 0;
+    scsi_tapes[i].rw = ST_IDLE;
+    scsi_tapes[i].eof = ST_NOEOF;
     scsi_tapes[i].waiting = NULL;
     scsi_tapes[i].in_use = 0;
     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)
   for (i=0; i < st_nbr_buffers; i++) {
     st_buffers[i] = (ST_buffer *) mem_start;
 #ifdef DEBUG
-    printk("st: Buffer address: %x\n", st_buffers[i]);
+    printk("st: Buffer address: %p\n", st_buffers[i]);
 #endif
     mem_start += sizeof(ST_buffer) - 1 + ST_BUFFER_BLOCKS * ST_BLOCK_SIZE;
     st_buffers[i]->mt_status = (struct mtget *) mem_start;
index 0c50024497b7be482ebc8da7a65d34932f6f2759..7b530faa68af19029de87357611fa425b105b920 100644 (file)
@@ -18,6 +18,7 @@ typedef struct {
   int read_pointer;
   int writing;
   int last_result;
+  int last_result_fatal;
   unsigned char b_data[1];
 } ST_buffer;
 
@@ -37,9 +38,20 @@ typedef struct {
   int block_size;
   int min_block;
   int max_block;
+  int recover_count;
   Scsi_Cmnd SCpnt;
 } 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 */
 #define        QFA_REQUEST_BLOCK       0x02
index f051d0ebaea13dd34c1b3585a5f1ccbda0f552e3..59cb05070f7d3d9898b456d9c0902050318dcf84 100644 (file)
 #include <linux/in.h>
 
 #ifdef NFS_PROC_DEBUG
+
 static int proc_debug = 0;
-#define PRINTK if (proc_debug) printk
-#else
-#define PRINTK if (0) printk
-#endif
+#define PRINTK(format, args...) \
+       do {                                            \
+               if (proc_debug)                         \
+                       printk(format , ## args);       \
+       } while (0)
+
+#else /* !NFS_PROC_DEBUG */
+
+#define PRINTK(format, args...) do ; while (0)
 
-#define PREP_PAGE_RPC(code)    \
-  if (!(p0 = (int*)__get_free_page(GFP_KERNEL)))\
-       return NFSERR_IO;\
-  p=nfs_rpc_header(p0,code)
+#endif /* !NFS_PROC_DEBUG */
 
 static int *nfs_rpc_header(int *p, int procedure);
 static int *nfs_rpc_verify(int *p);
 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
  * between machine dependent and xdr data formats.
@@ -166,6 +183,10 @@ static int *xdr_decode_fsinfo(int *p, struct nfs_fsinfo *res)
        return p;
 }
 
+/*
+ * One function for each procedure in the NFS protocol.
+ */
+
 int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
                     struct nfs_fattr *fattr)
 {
@@ -173,10 +194,12 @@ int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
        int status;
 
        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);
        if ((status = nfs_rpc_call(server, p0, p)) < 0) {
-               free_page((long) p0);
+               nfs_rpc_free(p0);
                return status;
        }
        if (!(p = nfs_rpc_verify(p0)))
@@ -187,7 +210,7 @@ int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
        }
        else
                PRINTK("NFS reply getattr failed = %d\n", status);
-       free_page((long) p0);
+       nfs_rpc_free(p0);
        return -nfs_stat_to_errno(status);
 }
 
@@ -198,11 +221,13 @@ int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
        int status;
 
        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_sattr(p, sattr);
        if ((status = nfs_rpc_call(server, p0, p)) < 0) {
-               free_page((long) p0);
+               nfs_rpc_free(p0);
                return status;
        }
        if (!(p = nfs_rpc_verify(p0)))
@@ -213,7 +238,7 @@ int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
        }
        else
                PRINTK("NFS reply setattr failed = %d\n", status);
-       free_page((long) p0);
+       nfs_rpc_free(p0);
        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
        if (!strcmp(name, "xyzzy"))
                proc_debug = 1 - proc_debug;
 #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_string(p, name);
        if ((status = nfs_rpc_call(server, p0, p)) < 0) {
-               free_page((long) p0);
+               nfs_rpc_free(p0);
                return status;
        }
        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
        }
        else
                PRINTK("NFS reply lookup failed = %d\n", status);
-       free_page((long) p0);
+       nfs_rpc_free(p0);
        return -nfs_stat_to_errno(status);
 }
 
@@ -255,10 +282,12 @@ int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
        int status;
 
        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);
        if ((status = nfs_rpc_call(server, p0, p)) < 0) {
-               free_page((long) p0);
+               nfs_rpc_free(p0);
                return status;
        }
        if (!(p = nfs_rpc_verify(p0)))
@@ -273,7 +302,7 @@ int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
        }
        else
                PRINTK("NFS reply readlink failed = %d\n", status);
-       free_page((long) p0);
+       nfs_rpc_free(p0);
        return -nfs_stat_to_errno(status);
 }
 
@@ -285,13 +314,15 @@ int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
        int len = 0; /* = 0 is for gcc */
 
        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++ = htonl(offset);
        *p++ = htonl(count);
        *p++ = htonl(count); /* traditional, could be any value */
        if ((status = nfs_rpc_call(server, p0, p)) < 0) {
-               free_page((long) p0);
+               nfs_rpc_free(p0);
                return status;
        }
        if (!(p = nfs_rpc_verify(p0)))
@@ -307,7 +338,7 @@ int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
        }
        else
                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);
 }
 
@@ -318,14 +349,16 @@ int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
        int status;
 
        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++ = htonl(offset); /* traditional, could be any value */
        *p++ = htonl(offset);
        *p++ = htonl(count); /* traditional, could be any value */
        p = xdr_encode_data(p, data, count);
        if ((status = nfs_rpc_call(server, p0, p)) < 0) {
-               free_page((long) p0);
+               nfs_rpc_free(p0);
                return status;
        }
        if (!(p = nfs_rpc_verify(p0)))
@@ -336,7 +369,7 @@ int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
        }
        else
                PRINTK("NFS reply write failed = %d\n", status);
-       free_page((long) p0);
+       nfs_rpc_free(p0);
        return -nfs_stat_to_errno(status);
 }
 
@@ -348,12 +381,14 @@ int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
        int status;
 
        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_string(p, name);
        p = xdr_encode_sattr(p, sattr);
        if ((status = nfs_rpc_call(server, p0, p)) < 0) {
-               free_page((long) p0);
+               nfs_rpc_free(p0);
                return status;
        }
        if (!(p = nfs_rpc_verify(p0)))
@@ -365,7 +400,7 @@ int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
        }
        else
                PRINTK("NFS reply create failed = %d\n", status);
-       free_page((long) p0);
+       nfs_rpc_free(p0);
        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
        int status;
 
        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_string(p, name);
        if ((status = nfs_rpc_call(server, p0, p)) < 0) {
-               free_page((long) p0);
+               nfs_rpc_free(p0);
                return status;
        }
        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
        }
        else
                PRINTK("NFS reply remove failed = %d\n", status);
-       free_page((long) p0);
+       nfs_rpc_free(p0);
        return -nfs_stat_to_errno(status);
 }
 
@@ -401,13 +438,15 @@ int nfs_proc_rename(struct nfs_server *server,
        int status;
 
        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_string(p, old_name);
        p = xdr_encode_fhandle(p, new_dir);
        p = xdr_encode_string(p, new_name);
        if ((status = nfs_rpc_call(server, p0, p)) < 0) {
-               free_page((long) p0);
+               nfs_rpc_free(p0);
                return status;
        }
        if (!(p = nfs_rpc_verify(p0)))
@@ -417,7 +456,7 @@ int nfs_proc_rename(struct nfs_server *server,
        }
        else
                PRINTK("NFS reply rename failed = %d\n", status);
-       free_page((long) p0);
+       nfs_rpc_free(p0);
        return -nfs_stat_to_errno(status);
 }
 
@@ -428,12 +467,14 @@ int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
        int status;
 
        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, dir);
        p = xdr_encode_string(p, name);
        if ((status = nfs_rpc_call(server, p0, p)) < 0) {
-               free_page((long) p0);
+               nfs_rpc_free(p0);
                return status;
        }
        if (!(p = nfs_rpc_verify(p0)))
@@ -443,7 +484,7 @@ int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
        }
        else
                PRINTK("NFS reply link failed = %d\n", status);
-       free_page((long) p0);
+       nfs_rpc_free(p0);
        return -nfs_stat_to_errno(status);
 }
 
@@ -454,13 +495,15 @@ int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
        int status;
 
        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_string(p, name);
        p = xdr_encode_string(p, path);
        p = xdr_encode_sattr(p, sattr);
        if ((status = nfs_rpc_call(server, p0, p)) < 0) {
-               free_page((long) p0);
+               nfs_rpc_free(p0);
                return status;
        }
        if (!(p = nfs_rpc_verify(p0)))
@@ -470,7 +513,7 @@ int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
        }
        else
                PRINTK("NFS reply symlink failed = %d\n", status);
-       free_page((long) p0);
+       nfs_rpc_free(p0);
        return -nfs_stat_to_errno(status);
 }
 
@@ -482,12 +525,14 @@ int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
        int status;
 
        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_string(p, name);
        p = xdr_encode_sattr(p, sattr);
        if ((status = nfs_rpc_call(server, p0, p)) < 0) {
-               free_page((long) p0);
+               nfs_rpc_free(p0);
                return status;
        }
        if (!(p = nfs_rpc_verify(p0)))
@@ -499,7 +544,7 @@ int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
        }
        else
                PRINTK("NFS reply mkdir failed = %d\n", status);
-       free_page((long) p0);
+       nfs_rpc_free(p0);
        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
        int status;
 
        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_string(p, name);
        if ((status = nfs_rpc_call(server, p0, p)) < 0) {
-               free_page((long) p0);
+               nfs_rpc_free(p0);
                return status;
        }
        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
        }
        else
                PRINTK("NFS reply rmdir failed = %d\n", status);
-       free_page((long) p0);
+       nfs_rpc_free(p0);
        return -nfs_stat_to_errno(status);
 }
 
@@ -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);
        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++ = htonl(cookie);
        *p++ = htonl(size);
        if ((status = nfs_rpc_call(server, p0, p)) < 0) {
-               free_page((long) p0);
+               nfs_rpc_free(p0);
                return status;
        }
        if (!(p = nfs_rpc_verify(p0)))
@@ -568,7 +617,7 @@ int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
        }
        else
                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);
 }
 
@@ -579,10 +628,12 @@ int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
        int status;
 
        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);
        if ((status = nfs_rpc_call(server, p0, p)) < 0) {
-               free_page((long) p0);
+               nfs_rpc_free(p0);
                return status;
        }
        if (!(p = nfs_rpc_verify(p0)))
@@ -593,7 +644,7 @@ int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
        }
        else
                PRINTK("NFS reply statfs failed = %d\n", status);
-       free_page((long) p0);
+       nfs_rpc_free(p0);
        return -nfs_stat_to_errno(status);
 }
 
index 7ea09236a2c77f4c574d53053cec3a25c30a9afe..0ce11f50cc2e59984743cc7d479962f919c3a25c 100644 (file)
@@ -132,6 +132,15 @@ __ntohl(unsigned long int 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
 __ntohs(unsigned short int x)
 {
@@ -141,31 +150,35 @@ __ntohs(unsigned short int 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
-__htons(unsigned short int x)
+__constant_ntohs(unsigned short int x)
 {
-       __asm__("xchgb %b0,%h0"         /* swap bytes           */
-               : "=q" (x)
-               :  "0" (x));
-       return x;
+       return (((x & 0x00ff) << 8) |
+               ((x & 0xff00) >> 8));
 }
 
+#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__
-#  define ntohl(x)     __ntohl((x))
-#  define ntohs(x)     __ntohs((x))
-#  define htonl(x)     __htonl((x))
-#  define htons(x)     __htons((x))
+#  define ntohl(x) \
+(__builtin_constant_p((x)) ? \
+ __constant_ntohl((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 /* _LINUX_IN_H */
index b4acda60ab81e987e16b70974b24d4c9523b9e22..fa900515ea7937aa30fbfaf0e7793cb45dd4399d 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -20,7 +20,7 @@ static int findkey (key_t key);
 static struct msqid_ds *msgque[MSGMNI];
 static int msgbytes = 0;
 static int msghdrs = 0;
-static int msg_seq = 0;
+static unsigned short msg_seq = 0;
 static int used_queues = 0;
 static int max_msqid = 0;
 static struct wait_queue *msg_lock = NULL;
@@ -264,7 +264,7 @@ found:
        used_queues++;
        if (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)
@@ -295,8 +295,7 @@ static void freeque (int id)
        struct msg *msgp, *msgh;
 
        msq->msg_perm.seq++;
-       if ((int)((++msg_seq + 1) * MSGMNI) < 0)
-               msg_seq = 0;
+       msg_seq++;
        msgbytes -= msq->msg_cbytes;
        if (id == max_msqid)
                while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED));
index de26b0493efdfb714056a027313ff7068b46d957..a8ec596d0737c545440d73307f3aefbb3a8b6abd 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -20,9 +20,10 @@ static void freeary (int id);
 static struct semid_ds *semary[SEMMNI];
 static int used_sems = 0, used_semids = 0;                    
 static struct wait_queue *sem_lock = NULL;
-static int sem_seq = 0;
 static int max_semid = 0;
 
+static unsigned short sem_seq = 0;
+
 void sem_init (void)
 {
        int i=0;
@@ -95,7 +96,7 @@ found:
        semary[id] = sma;
        if (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)
@@ -128,8 +129,7 @@ static void freeary (int id)
        struct sem_undo *un;
 
        sma->sem_perm.seq++;
-       if ((int)((++sem_seq + 1) * SEMMNI) < 0)
-               sem_seq = 0;
+       sem_seq++;
        used_sems -= sma->sem_nsems;
        if (id == max_semid)
                while (max_semid && (semary[--max_semid] == IPC_UNUSED));
index 4790a6a8c1884d678d0564f43d80c2c2eef4c46f..b486e625bef4f0eeb002ba6c1d2614359ebda9e3 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -23,11 +23,12 @@ static void killseg (int id);
 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_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 struct wait_queue *shm_lock = NULL;
 static struct shmid_ds *shm_segs[SHMMNI];
 
+static unsigned short shm_seq = 0; /* incremented, for recognizing stale ids */
+
 /* some statistics */
 static ulong swap_attempts = 0;
 static ulong swap_successes = 0;
@@ -119,7 +120,7 @@ found:
        used_segs++;
        if (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)
@@ -165,8 +166,7 @@ static void killseg (int id)
        }
        shp->shm_perm.seq++;     /* for shmat */
        numpages = shp->shm_npages; 
-       if ((int)((++shm_seq + 1) * SHMMNI) < 0)
-               shm_seq = 0;
+       shm_seq++;
        shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;
        used_segs--;
        if (id == max_shmid) 
index e2d42764a0588196d86d9e7cfb30faa324f21829..13c6b243f2b79f38ee3183ef0ec7fe23983123a7 100644 (file)
@@ -80,7 +80,7 @@ asmlinkage int sys_syslog(int type, char * buf, int len)
                                        sti();
                                        return -ERESTARTSYS;
                                }
-                                       interruptible_sleep_on(&log_wait);
+                               interruptible_sleep_on(&log_wait);
                        }
                        i = 0;
                        while (log_size && i < len) {
@@ -88,9 +88,11 @@ asmlinkage int sys_syslog(int type, char * buf, int len)
                                log_start++;
                                log_size--;
                                log_start &= LOG_BUF_LEN-1;
+                               sti();
                                put_fs_byte(c,buf);
                                buf++;
                                i++;
+                               cli();
                        }
                        sti();
                        return i;
index b4d8d1aebfa02dc9d9473bb61faa8d7f1001f023..abd1cb5780c6e455b126cf69f1dc7c4d42aa4df7 100644 (file)
@@ -210,11 +210,11 @@ icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev)
   ip = iph->daddr;
   switch(icmph->code & 7) {
        case ICMP_REDIR_NET:
-               rt_add((RTF_DYNAMIC | RTF_MODIFIED),
+               rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
                        ip, icmph->un.gateway, dev);
                break;
        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);
                break;
        case ICMP_REDIR_NETTOS:
index 9c42bef6c4ddd9db4be7e2d62f6aa5eb72b68037..bda8f3465345023b86527fb192c080b91fdaff6b 100644 (file)
@@ -59,7 +59,7 @@
 #ifdef INET_DEBUG
 #  define      DPRINTF(x)      dprintf x 
 #else
-#   define     DPRINTF(x)      /*zilch*/
+#   define     DPRINTF(x)      do ; while (0)
 #endif
 
 /* Debug levels. One per module. */
index a06c349d411d4f332d3e15dc483463c773c081d3..2f20c9057b25a2d4f932760201309c8b1b097b39 100644 (file)
@@ -112,6 +112,16 @@ void rt_flush(struct device *dev)
 
 /*
  * 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)
 {
@@ -119,7 +129,29 @@ static unsigned long guess_mask(unsigned long dst)
 
        while (mask & dst)
                mask <<= 8;
-       return ~mask;
+       if (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)
        unsigned long mask;
        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) {
                mask = 0xffffffff;
-               rt->rt_dst = dst;
        } else {
                if (!((dst ^ dev->pa_addr) & dev->pa_mask)) {
                        mask = dev->pa_mask;
                        dst &= mask;
+                       flags &= ~RTF_GATEWAY;
                        if (flags & RTF_DYNAMIC) {
-                               kfree_s(rt, sizeof(struct rtable));
                                /*printk("Dynamic route to my own net rejected\n");*/
                                return;
                        }
                } else
                        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_print(rt);
        /*
@@ -181,11 +211,11 @@ rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev)
        /* remove old route if we are getting a duplicate. */
        rp = &rt_base;
        while ((r = *rp) != NULL) {
-               if (r->rt_dst != dst) {
-                       rp = &r->rt_next;
-                       continue;
-               }
-               *rp = r->rt_next;
+               if (r->rt_dst != dst) {
+                       rp = &r->rt_next;
+                       continue;
+               }
+               *rp = r->rt_next;
                kfree_s(r, sizeof(struct rtable));
        }
        /* add the new route */
@@ -206,7 +236,6 @@ static int
 rt_new(struct rtentry *r)
 {
   struct device *dev;
-  struct rtable *rt;
 
   if ((r->rt_dst.sa_family != AF_INET) ||
       (r->rt_gateway.sa_family != AF_INET)) {
@@ -226,11 +255,7 @@ rt_new(struct rtentry *r)
   if (!(r->rt_flags & RTF_GATEWAY))
        dev = dev_check(((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr);
   else
-       if ((rt = rt_route(((struct sockaddr_in *) &r->rt_gateway)->sin_addr.
-                          s_addr,NULL)))
-           dev = rt->rt_dev;
-       else
-           dev = NULL;
+       dev = get_gw_dev(((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr);
 
   DPRINTF((DBG_RT, "RT: dev for %s gw ",
        in_ntoa((*(struct sockaddr_in *)&r->rt_dst).sin_addr.s_addr)));
@@ -269,13 +294,14 @@ rt_get_info(char *buffer)
   pos = buffer;
 
   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! */
   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_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);
 }
index 7576c45d773065b2c56be44f4da04d1d89ad879f..cddaaa21ceb4951627250e44dc4f969ef6d37121 100644 (file)
@@ -212,14 +212,16 @@ int main(int argc, char ** argv)
                                fprintf(stderr, "Unexpected EOF\n");
                        die("Can't read 'system'");
                }
-               write(1, buf, l);
+               if (write(1, buf, l) != l)
+                       die("Write failed");
                sz -= l;
        }
        close(id);
        if (lseek(1,500,0) == 500) {
                buf[0] = (sys_size & 0xff);
                buf[1] = ((sys_size >> 8) & 0xff);
-               write(1, buf, 2);
+               if (write(1, buf, 2) != 2)
+                       die("Write failed");
        }
        return(0);
 }