From: Linus Torvalds Date: Fri, 23 Nov 2007 20:09:17 +0000 (-0500) Subject: Import 0.99.14i X-Git-Tag: 0.99.14i X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=27c43263ea7536bced39d359f0d96cb5cd12ea2e;p=history.git Import 0.99.14i --- diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 630c01e58aa9..a2083b827878 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -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 diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h index 08a2035a6720..381b86bbe3b1 100644 --- a/drivers/scsi/scsi.h +++ b/drivers/scsi/scsi.h @@ -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 diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index a1386553d935..1e5c2e9a7879 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -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 @@ -25,15 +27,16 @@ 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 @@ -52,10 +55,7 @@ #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. */ @@ -66,26 +66,43 @@ 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, -/* 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, /* 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) /* 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; } /* 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) /* 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) /* 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, /* 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; diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index 0c50024497b7..7b530faa68af 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -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 diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index f051d0ebaea1..59cb05070f7d 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -27,21 +27,38 @@ #include #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); } diff --git a/include/linux/in.h b/include/linux/in.h index 7ea09236a2c7..0ce11f50cc2e 100644 --- a/include/linux/in.h +++ b/include/linux/in.h @@ -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 */ diff --git a/ipc/msg.c b/ipc/msg.c index b4acda60ab81..fa900515ea79 100644 --- 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)); diff --git a/ipc/sem.c b/ipc/sem.c index de26b0493efd..a8ec596d0737 100644 --- 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)); diff --git a/ipc/shm.c b/ipc/shm.c index 4790a6a8c188..b486e625bef4 100644 --- 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) diff --git a/kernel/printk.c b/kernel/printk.c index e2d42764a058..13c6b243f2b7 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -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; diff --git a/net/inet/icmp.c b/net/inet/icmp.c index b4d8d1aebfa0..abd1cb5780c6 100644 --- a/net/inet/icmp.c +++ b/net/inet/icmp.c @@ -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: diff --git a/net/inet/inet.h b/net/inet/inet.h index 9c42bef6c4dd..bda8f3465345 100644 --- a/net/inet/inet.h +++ b/net/inet/inet.h @@ -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. */ diff --git a/net/inet/route.c b/net/inet/route.c index a06c349d411d..2f20c9057b25 100644 --- a/net/inet/route.c +++ b/net/inet/route.c @@ -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); } diff --git a/tools/build.c b/tools/build.c index 7576c45d7730..cddaaa21ceb4 100644 --- a/tools/build.c +++ b/tools/build.c @@ -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); }