home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-387-Vol-3of3.iso
/
f
/
ftp-102.zip
/
ftape-1.02
/
qic
/
read.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-12
|
28KB
|
1,135 lines
/* Read data from the tape.
Copyright (C) 1992 David L. Brown, Jr.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
* read.c,v 1.25 1992/10/13 02:21:14 dbrown Exp
*
* read.c,v
* Revision 1.25 1992/10/13 02:21:14 dbrown
* Changed directory for include.
*
* Revision 1.24 1992/10/13 01:55:31 dbrown
* Added FSF copyright.
*
* Revision 1.23 1992/10/12 05:15:47 dbrown
* Fixed some bugs with beginning of track and write errors.
*
* Upped storred buffers to 3. This should never be needed. Somehow,
* this is requiring 5 in one instance.
*
* Revision 1.22 1992/10/11 02:22:26 dbrown
* Write now works occasionally.
*
* Revision 1.21 1992/10/11 00:25:05 dbrown
* Fixed many bugs in write code. More to go...
*
* Revision 1.20 1992/10/10 07:00:37 dbrown
* Turned off debugging.
*
* Revision 1.19 1992/10/10 06:46:39 dbrown
* Changed write some. This current write code is GARBAGE.
*
* Revision 1.18 1992/10/10 06:17:54 dbrown
* Started implementing write. Doesn't actually do the write yet.
*
* Revision 1.17 1992/10/10 04:51:10 dbrown
* Initial attempt to make write usefully robust (so anything can be written).
*
* Revision 1.16 1992/10/09 05:56:58 dbrown
* Read is reliable. Write is flaky and can't handle errors.
*
* Revision 1.15 1992/03/27 21:41:24 dbrown
* Synchronize with the driver if doing a write after a read.
*
* Revision 1.14 92/03/27 02:38:46 dbrown
* Supports both short and long tapes.
* Made debugging prints optional.
*
* Revision 1.13 92/03/27 01:13:51 dbrown
* Now can write.
*
* Revision 1.12 92/03/27 00:34:34 dbrown
* Retries more times.
* Handles error bits back from result.
*
* Revision 1.11 92/03/24 15:34:31 dbrown
* Fixed for new read protocol.
*
* Revision 1.10 92/03/23 09:35:22 dbrown
* Made read correctly.
*
* Revision 1.9 92/03/22 22:29:22 dbrown
* Fixed seek forward by too much.
* Last of the old paradigm.
*
* Revision 1.8 92/03/21 17:22:09 dbrown
* Seek code seems to work somewhat correctly.
*
* Revision 1.7 92/03/21 16:26:01 dbrown
* Still trying to get read working across tracks.
*
* Revision 1.6 92/03/21 15:38:54 dbrown
* Started adding support for more than track 0.
*
* Revision 1.5 92/03/21 14:41:35 dbrown
* Fixed error messages.
* Moved wait_for_ready to not check during read.
*
* Revision 1.4 92/03/21 14:31:07 dbrown
* Started modifying to use read ahead.
*
* Revision 1.3 92/03/21 12:31:02 dbrown
* Added initial support for reading from tape.
*
* Revision 1.2 92/03/19 23:01:07 dbrown
* Now compiles for tape but doesn't do anything.
*
*/
#include <assert.h>
#include <stdio.h>
#include <sys/file.h>
#include "qic.h"
#include "ecc.h"
#include "header.h"
/* Debug */
#undef DEBUG_IO
#ifdef DEBUG_IO
# define DFPRINTF(x) fprintf x
#else /* not DEBUG_IO */
# define DFPRINTF(x)
#endif /* not DEBUG_IO */
#ifndef FLOPPY
#include <sys/ioctl.h>
#include <fdtape-io.h>
extern int errno;
/* Tape device. */
int tape_fd = -1;
/* Guess at the current segment number. */
int current_segment;
/* Track the tape head is on. */
int current_track;
/* Number of segments per track. Set by open_tape. */
int segments_per_track = 150;
/* Open up the tape device. */
void
open_tape ()
{
int value, result;
int status;
struct fdt_error tape_error;
if (tape_fd < 0)
{
tape_fd = open ("/dev/ftape", O_RDWR);
if (tape_fd < 0)
error (1, errno, "Cannot open tape drive");
/* Wait for drive ready. */
status = wait_for_ready ();
if (status & QIC_STATUS_NEW_CARTRIDGE)
{
DFPRINTF ((stderr, "ioctl FDT_REPORT_ERROR_CODE\n"));
result = ioctl (tape_fd, FDT_REPORT_ERROR_CODE, &tape_error);
if (result != 0)
error (1, errno, "Cannot read tape drive status");
status = wait_for_ready ();
}
if (status & QIC_STATUS_ERROR)
{
DFPRINTF ((stderr, "ioctl FDT_REPORT_ERROR_CODE\n"));
result = ioctl (tape_fd, FDT_REPORT_ERROR_CODE, &tape_error);
if (result != 0)
error (1, errno, "Cannot read tape drive status");
}
if (!(status & QIC_STATUS_CARTRIDGE_PRESENT))
error (1, 0, "Please insert a cartridge");
/* Get drive configuration. */
{
int configuration;
DFPRINTF ((stderr, "ioctl FDT_REPORT_CONFIGURATION\n"));
result = ioctl (tape_fd, FDT_REPORT_CONFIGURATION, &configuration);
if (result != 0)
error (1, errno, "Cannot get drive configuration");
if (configuration & QIC_CONFIG_LONG)
segments_per_track = 150;
else
segments_per_track = 100;
DFPRINTF ((stderr, "ioctl FDT_SET_TRACK_LENGTH\n"));
result = ioctl (tape_fd, FDT_SET_TRACK_LENGTH, &segments_per_track);
if (result != 0)
error (1, errno, "Cannot set track length in driver");
if (!(configuration & QIC_CONFIG_80))
error (1, 0, "Error: cannot handle QIC-40 cartridges (yet!)\n");
}
/* Rewind the tape and go to track 0. */
DFPRINTF ((stderr, "ioctl FDT_SEEK_TO_BEGINNING\n"));
result = ioctl (tape_fd, FDT_SEEK_TO_BEGINNING, 0);
if (result != 0)
error (1, errno, "Cannot rewind tape");
value = 0;
DFPRINTF ((stderr, "ioctl FDT_SEEK_TO_TRACK\n"));
result = ioctl (tape_fd, FDT_SEEK_TO_TRACK, &value);
if (result != 0)
error (1, errno, "Cannot move tape head");
current_segment = 0;
current_track = -1;
}
}
/* Is a read ahead in progress? */
static int read_ahead_running = 0;
/* Is a write probably in progress? */
static int write_ahead_running = 0;
/* Write one memory segment. -1 return is success, >= 0 is failure. */
int
write_segment (struct memory_segment *data, int segment)
{
int return_value = 0;
int value, result;
int count;
struct tape_write twrite;
struct error_map emap;
struct write_cease wc;
open_tape ();
DFPRINTF ((stderr, "W: Marked bad: 0x%08x\n", data->marked_bad));
for (count = 1; count > 0; count--)
{
DFPRINTF ((stderr, "write %d, cur= %d\n",
segment, current_segment));
if (segment != current_segment
|| segment % segments_per_track == 0)
{
must_not_be_writing ();
}
if (segment / segments_per_track != current_track)
{
must_not_be_writing ();
/* Seek the heads. */
wait_for_ready ();
current_track = segment / segments_per_track;
DFPRINTF ((stderr, "Move tape heads to track %d\n",
current_track));
DFPRINTF ((stderr, "ioctl FDT_SEEK_TO_TRACK\n"));
result = ioctl (tape_fd, FDT_SEEK_TO_TRACK, ¤t_track);
if (result != 0)
error (1, errno, "Cannot move tape head");
/* Unsure of where we are on the new track. */
current_segment = segment;
emap.count = segments_per_track;
emap.error_masks = ¤t_header.bad_sectors[segment
- (segment
% segments_per_track)];
DFPRINTF ((stderr, "ioctl FDT_SUBMIT_ERROR_MAP\n"));
result = ioctl (tape_fd, FDT_SUBMIT_ERROR_MAP, &emap);
if (result != 0)
error (1, errno, "Cannot submit error map.");
}
/* If the write request is at the beginning of a track,
rewind the tape to the appropriate end. */
if (segment % segments_per_track == 0)
{
int command;
must_not_be_writing ();
if ((current_track & 1) == 0)
command = FDT_SEEK_TO_BEGINNING;
else
command = FDT_SEEK_TO_END;
DFPRINTF ((stderr, "Wind tape to start of track %d\n",
current_track));
result = ioctl (tape_fd, command, 0);
if (result != 0)
error (1, errno, "Error winding tape to end");
emap.count = segments_per_track;
emap.error_masks = ¤t_header.bad_sectors[segment
- (segment
% segments_per_track)];
DFPRINTF ((stderr, "ioctl FDT_SUBMIT_ERROR_MAP\n"));
result = ioctl (tape_fd, FDT_SUBMIT_ERROR_MAP, &emap);
if (result != 0)
error (1, errno, "Cannot submit error map.");
}
/* If the last write was distant from the desired write seek
the tape heads. First seek if a reverse seek is
appropriate. */
else if (segment < current_segment)
{
must_not_be_writing ();
wait_for_ready ();
/* Seek one extra segment in reverse. */
value = current_segment - segment;
/* If error appears to be due to running off the end of
the tape then go back a little further. */
if (current_segment % segments_per_track
== segments_per_track - 1)
value += 4;
DFPRINTF ((stderr, "Seek backward by %d\n", value));
result = ioctl (tape_fd, FDT_SEEK_REVERSE, &value);
if (result != 0)
error (1, errno, "Cannot seek tape");
}
/* Also try seeking forward. */
else if (segment > current_segment + 3)
{
must_not_be_writing ();
wait_for_ready ();
/* Seek 2 less forward than what it appears we need to. */
value = segment - current_segment - 3;
DFPRINTF ((stderr, "Seek forward by %d\n", value));
result = ioctl (tape_fd, FDT_SEEK_FORWARD, &value);
if (result != 0)
error (1, errno, "Cannot seek tape");
}
twrite.buffer = data->data;
twrite.segment = segment;
DFPRINTF ((stderr, "Start write\n"));
write_ahead_running = 1;
result = ioctl (tape_fd, FDT_WRITE, &twrite);
if (result != 0)
error (1, errno, "Error writing");
else if (twrite.actual_segment != -1)
{
DFPRINTF ((stderr, "Actually on: %d\n",
twrite.actual_segment));
write_ahead_running = 0;
result = ioctl (tape_fd, FDT_CEASE_WRITING, &wc);
if (result != 0)
error (1, errno, "Error stopping errored write");
if (wc.actual_segment != twrite.actual_segment
|| wc.error_location != twrite.error_location)
error (1, 0, "Tape driver problem reporting write position\n"
"wcact = %d, wract = %d, wcerr = %d, wrerr = %d\n",
wc.actual_segment, twrite.actual_segment,
wc.error_location, twrite.error_location);
if (twrite.actual_segment == -2)
current_segment = (segments_per_track * current_track
+ segments_per_track - 1);
else if (twrite.actual_segment == -3)
{
DFPRINTF ((stderr, "Write position problem, retrying.\n"));
/*continue;*/
}
else
{
if (current_segment / segments_per_track
!= twrite.actual_segment / segments_per_track)
{
error (1, 0, "Tape is not on correct track");
}
/* Add one because we can't read what the heads are on. */
current_segment = twrite.actual_segment + 1;
}
return_value = twrite.error_location;
}
else
{
count = 0;
return_value = -1;
current_segment = segment + 1;
}
}
return return_value;
}
int
do_reseek_logic (int actual_segment)
{
if (actual_segment == -2)
current_segment = (segments_per_track * current_track
+ segments_per_track - 1);
else if (actual_segment == -3)
{
DFPRINTF ((stderr, "Write position problem, retrying.\n"));
}
else
{
if (current_segment / segments_per_track
!= actual_segment / segments_per_track)
{
error (1, 0, "Tape is not on correct track");
}
/* Add one because we can't read what the heads are on. */
current_segment = actual_segment + 1;
}
}
int
wait_for_ready ()
{
int result, status;
int timeout;
if (read_ahead_running)
{
DFPRINTF ((stderr, "ioctl FDT_READ_STOP\n"));
result = ioctl (tape_fd, FDT_READ_STOP, 0);
if (result != 0)
error (0, errno, "Abort unnecessary.");
read_ahead_running = 0;
}
if (write_ahead_running)
{
write_cease ();
}
for (timeout = 46000; timeout > 0; timeout--)
{
DFPRINTF ((stderr, "ioctl FDT_REPORT_STATUS\n"));
result = ioctl (tape_fd, FDT_REPORT_STATUS, &status);
if (result != 0)
error (1, errno, "Cannot get drive status");
if ((status & 1 /* !!! MAGIC !!! */) == 0)
{
usleep (100000);
}
else
timeout = 0;
}
return status;
}
/* Count of segments left to read in run. */
static int read_ahead_left;
/* Read in one memory segment. */
void
read_segment (struct memory_segment *data, int segment)
{
int value, result;
int count;
struct error_map emap;
struct tape_read tread;
open_tape ();
data->read_bad = 0xffffffff;
if (write_ahead_running)
{
write_cease ();
}
DFPRINTF ((stderr, "Marked bad: 0x%08x\n", data->marked_bad));
for (count = 10; count > 0; count--)
{
DFPRINTF ((stderr, "segment = %d, current_segment = %d\n",
segment, current_segment));
if (read_ahead_running)
{
if (segment != current_segment || current_segment < 3
|| segment % segments_per_track == 0)
{
DFPRINTF ((stderr, "ioctl FDT_READ_STOP\n"));
result = ioctl (tape_fd, FDT_READ_STOP, 0);
if (result != 0)
error (0, errno, "Abort unnecessary.");
read_ahead_running = 0;
}
}
if (!read_ahead_running)
{
if (segment / segments_per_track != current_track)
{
/* Seek the heads. */
/*wait_for_ready ();*/
current_track = segment / segments_per_track;
DFPRINTF ((stderr, "Move tape heads to track %d\n",
current_track));
result = ioctl (tape_fd, FDT_SEEK_TO_TRACK, ¤t_track);
if (result != 0)
error (1, errno, "Cannot move tape head");
/* Unsure of where we are on the new track. */
current_segment = segment;
}
/* If the read request is at the beginning of a track,
rewind the tape to the appropriate end. */
if (segment % segments_per_track == 0)
{
int command;
if ((current_track & 1) == 0)
command = FDT_SEEK_TO_BEGINNING;
else
command = FDT_SEEK_TO_END;
DFPRINTF ((stderr, "Wind tape to start of track %d\n",
current_track));
result = ioctl (tape_fd, command, 0);
if (result != 0)
error (1, errno, "Error winding tape to end");
}
/* If the last read was distant from the desired read seek
the tape heads. First seek if a reverse seek is
appropriate. */
else if (segment < current_segment)
{
wait_for_ready ();
/* Seek one extra segment in reverse. */
value = current_segment - segment;
/* If error appears to be due to running off the end of
the tape then go back a little further. */
if (current_segment % segments_per_track
== segments_per_track - 1)
value += 4;
DFPRINTF ((stderr, "Seek backward by %d\n", value));
result = ioctl (tape_fd, FDT_SEEK_REVERSE, &value);
if (result != 0)
error (1, errno, "Cannot seek tape");
}
/* Also try seeking forward. */
else if (segment > current_segment + 3)
{
wait_for_ready ();
/* Seek 2 less forward than what it appears we need to. */
value = segment - current_segment - 3;
DFPRINTF ((stderr, "Seek forward by %d\n", value));
result = ioctl (tape_fd, FDT_SEEK_FORWARD, &value);
if (result != 0)
error (1, errno, "Cannot seek tape");
}
/* Don't read ahead if reading the header. */
if (segment == 0 || segment == 1)
{
read_ahead_left = 1;
emap.count = 2;
/* Tacky, should see if done elsewhere. */
current_header.bad_sectors[segment] = 0;
}
else
{
emap.count = segments_per_track;
read_ahead_left = (segments_per_track
- (segment % segments_per_track));
}
emap.error_masks = ¤t_header.bad_sectors[segment
- (segment
% segments_per_track)];
DFPRINTF ((stderr, "Start reading %d-%d\n",
segment, segment + emap.count - 1));
DFPRINTF ((stderr, "ioctl FDT_SUBMIT_ERROR_MAP\n"));
result = ioctl (tape_fd, FDT_SUBMIT_ERROR_MAP, &emap);
if (result != 0)
error (1, errno, "Cannot submit error map.");
read_ahead_running = 1;
}
tread.buffer = data->data;
tread.segment = segment;
tread.count = read_ahead_left;
DFPRINTF ((stderr, "Start read\n"));
result = ioctl (tape_fd, FDT_READ, &tread);
#if 0
DFPRINTF ((stderr, "Read result = %d\n", tread.result));
#endif
read_ahead_left--;
if (result != 0)
error (1, errno, "Error reading");
else if (tread.actual_segment != -1)
{
DFPRINTF ((stderr, "Actually read: %d\n", tread.actual_segment));
if (tread.actual_segment == -2)
current_segment = (segments_per_track * current_track
+ segments_per_track - 1);
else if (tread.actual_segment == -3)
{
fprintf (stderr, "Read error, retrying.\n");
continue;
}
else
{
if (current_segment / segments_per_track
!= tread.actual_segment / segments_per_track)
{
error (1, 0, "Tape is not on correct track");
}
/* Add one because we can't read what the heads are on. */
current_segment = tread.actual_segment + 1;
}
}
else
{
count = 0;
/*BAD_CLEAR (data->read_bad); /* Need to use result from read. */
/* !!! Depends on word ordering being proper. !!! */
data->read_bad = tread.error_bits;
/*data->read_bad = 0;*/
current_segment = segment + 1;
}
}
}
/* Read in one memory segment and produce correct data. Returns
non-zero if the data read is valid. */
int
read_good_segment (struct memory_segment *data, int segment)
{
int result;
read_segment (data, segment);
result = ecc_correct_data (data);
if (result != ECC_FAILED)
return 1;
else
return 0;
}
/* Close the tape device and prepare for a new volume. */
void
close_down (void)
{
static int recursion_count = 0;
int result;
if (recursion_count > 0)
return;
recursion_count++;
if (tape_fd == -1)
return;
#if 0 /* Done in wait for ready */
if (read_ahead_running)
{
result = ioctl (tape_fd, FDT_READ_STOP, 0);
if (result != 0)
error (0, errno, "Unnecessary abort");
}
#endif
/* Rewind the tape. */
wait_for_ready ();
DFPRINTF ((stderr, "ioctl FDT_SEEK_TO_BEGINNING\n"));
result = ioctl (tape_fd, FDT_SEEK_TO_BEGINNING, 0);
if (result != 0)
{
error (0, errno, "Cannot rewind tape");
exit (1);
}
close (tape_fd);
tape_fd = -1;
recursion_count--;
}
/* Write one memory segment with ecc data. */
static char kept_buffers[3][32768];
static int kept_segment[3] = { -1, -1 };
static struct memory_segment kept_data[3];
static int last_written_segment;
void
write_good_segment (struct memory_segment *data, int segment)
{
int go_back;
int redo; /* Where to redo from. */
int count = 10;
int result;
int which;
struct write_cease wc;
struct memory_segment *to_write;
set_segment_parity (data);
open_tape ();
if (read_ahead_running)
{
/* Wait for the read ahead to finish. */
DFPRINTF ((stderr, "ioctl FDT_READ_STOP\n"));
result = ioctl (tape_fd, FDT_READ_STOP, 0);
if (result != 0)
error (1, errno, "Cannot synchronize with driver");
read_ahead_running = 0;
}
if (segment / segments_per_track != current_track
|| segment != current_segment
|| segment % segments_per_track == 0)
write_cease ();
go_back = write_segment (data, segment);
if (go_back != -1)
{
#if 0
DFPRINTF ((stderr, "ioctl FDT_CEASE_WRITING\n"));
result = ioctl (tape_fd, FDT_CEASE_WRITING, &wc);
if (result != 0)
perror (1, errno, "Can't stop driver write command");
redo = wc.error_location;
#else
redo = go_back;
#endif
}
while (go_back != -1
&& count-- > 0)
{
if (kept_segment[0] == redo)
to_write = &kept_data[0];
else if (kept_segment[1] == redo)
to_write = &kept_data[1];
else if (kept_segment[2] == redo)
to_write = &kept_data[2];
else if (redo == segment)
to_write = data;
else
error (1, 0, "Fatal: write not flushed");
go_back = write_segment (to_write, redo);
if (go_back == -1)
{
redo++;
if (redo <= segment)
go_back = redo;
}
else
{
#if 0
DFPRINTF ((stderr, "ioctl FDT_CEASE_WRITING\n"));
result = ioctl (tape_fd, FDT_CEASE_WRITING, &wc);
if (result != 0)
perror (1, errno, "Can't stop driver write command");
redo = wc.error_location;
#else
redo = go_back;
#endif
}
}
if (go_back == -1)
{
which = 0;
if (kept_segment[1] < kept_segment[0]
&& kept_segment[2] < kept_segment[0])
which = 1;
if (kept_segment[0] < kept_segment[1]
&& kept_segment[2] < kept_segment[1])
which = 2;
kept_segment[which] = segment;
kept_data[which].data = kept_buffers[which];
kept_data[which].marked_bad = data->marked_bad;
kept_data[which].read_bad = data->read_bad;
kept_data[which].blocks = data->blocks;
bcopy (data->data, kept_data[which].data,
32768);
last_written_segment = segment;
}
else
error (1, 0, "Fatal, can't write successfully");
}
int
write_cease ()
{
int redo, go_back, count = 10;
int result;
struct write_cease wc;
struct memory_segment *to_write;
int had_trouble = 0;
int problem_count = 10;
do
{
had_trouble = 0;
DFPRINTF ((stderr, "ioctl FDT_CEASE_WRITING\n"));
result = ioctl (tape_fd, FDT_CEASE_WRITING, &wc);
if (result != 0)
error (1, errno, "Can't stop driver write command");
write_ahead_running = 0;
go_back = -1;
if (wc.actual_segment != -1)
{
do_reseek_logic (wc.actual_segment);
had_trouble = 1;
redo = wc.error_location;
go_back = redo;
while (go_back != -1
&& count-- > 0)
{
if (kept_segment[0] == redo)
to_write = &kept_data[0];
else if (kept_segment[1] == redo)
to_write = &kept_data[1];
else if (kept_segment[2] == redo)
to_write = &kept_data[2];
else
error (1, 0, "Fatal: write not flushed (2)");
go_back = write_segment (to_write, redo);
if (go_back == -1)
{
redo++;
if (redo <= last_written_segment)
go_back = redo;
}
else
{
DFPRINTF ((stderr, "ioctl FDT_CEASE_WRITING\n"));
result = ioctl (tape_fd, FDT_CEASE_WRITING, &wc);
if (result != 0)
if (result != 0)
perror (1, errno, "Can't stop driver write command");
redo = wc.error_location;
do_reseek_logic (wc.actual_segment);
}
}
}
if (go_back != -1)
error (1, 0, "Cannot successfully write data");
}
while (had_trouble
&& --problem_count > 0);
if (problem_count <= 0)
error (1, 0, "Gave up on write termination");
}
int
must_not_be_writing ()
{
if (write_ahead_running)
error (0, 0, "Write has not been terminated properly.\n"),
abort (); /* Dump core so the reason can be
determined. */
}
#else /* FLOPPY */
/* This is the floppy solution to the reader. */
/* Last position of the file pointer. -1 if the file itself is invalid. */
static int data_file_at = -1;
/* File handle of the data. */
static int data_file = -1;
/* Last operation, 0 = read, 1 = write. */
static int last_operation = 0;
#define FILE_NAME "/dev/rfd0a"
/* Seek to a position, if necessary. */
static void
seek_to (int position, int operation)
{
int result;
if (data_file == -1)
{
data_file = open (FILE_NAME, O_RDWR);
assert (data_file);
data_file_at = -1;
/* Turn of write verify. */
disable_write_verify (data_file);
}
if (data_file_at != position || last_operation != operation)
{
#if 0
DPRINTF (("Seek: from %d to %d\n", data_file_at, position));
#endif
result = lseek (data_file, position * BLOCK_SIZE, L_SET);
if (result == -1)
{
perror ("Can't lseek on device");
exit (1);
}
data_file_at = position;
last_operation = operation;
}
}
/* Close down the file. */
void
close_down (void)
{
if (data_file != -1)
{
close (data_file);
data_file = -1;
}
}
/* Read in a chunk of data. Returns 1 if success. */
static int
read_chunk (char *data, int size, int position)
{
int result;
seek_to (position, 0);
#if 0
DPRINTF (("Read chunk: segment %d, sector %d, count %d, ",
position / BLOCKS_PER_SEGMENT, position % BLOCKS_PER_SEGMENT,
size));
#endif
result = read (data_file, data, size * BLOCK_SIZE);
if (result != size * BLOCK_SIZE)
{
close_down();
result = 0;
}
else
{
result = 1;
data_file_at += size;
}
#if 0
DPRINTF (("%s\n", result ? "OK" : "Failed"));
#endif
return (result);
}
/* Write out a chunk of data. Returns 1 if success. */
static int
write_chunk (char *data, int size, int position)
{
int result;
seek_to (position, 1);
#if 0
DPRINTF (("Write chunk: segment %d, sector %d, count %d, ",
position / BLOCKS_PER_SEGMENT, position % BLOCKS_PER_SEGMENT,
size));
#endif
result = write (data_file, data, size * BLOCK_SIZE);
if (result != size * BLOCK_SIZE)
{
close_down();
result = 0;
}
else
{
data_file_at += size;
result = 1;
}
#if 0
DPRINTF (("%s\n", result ? "OK" : "Failed"));
#endif
return (result);
}
/* Read in one memory segment. */
void
read_segment (struct memory_segment *data, int segment)
{
int physical; /* Physical current block. */
int logical; /* Logical current block. */
int chunk;
int result;
int initial_offset = segment * BLOCKS_PER_SEGMENT;
BAD_CLEAR (data->read_bad);
physical = 0;
logical = 0;
while (physical < BLOCKS_PER_SEGMENT)
{
chunk = 0;
while (physical+chunk < BLOCKS_PER_SEGMENT
&& !BAD_CHECK (data->marked_bad, physical+chunk))
chunk++;
if (chunk == 0)
{
physical++;
}
else
{
if (read_chunk (data->data + logical * BLOCK_SIZE, chunk,
physical + initial_offset))
{
logical += chunk;
physical += chunk;
}
else
{
/* If the chunk size was 1, just mark bad, and go on. */
if (chunk == 1)
{
BAD_SET (data->read_bad, physical);
physical++;
}
else
{
/* Otherwise read in each block and test it. */
for (; chunk > 0; chunk--)
{
if (read_chunk (data->data + logical * BLOCK_SIZE,
1, physical + initial_offset))
{
physical++;
logical++;
}
else
{
BAD_SET (data->read_bad, physical);
physical++;
}
}
}
}
}
}
data->blocks = logical;
}
/* Read in one memory segment and and produce correct data. Returns
non-zero if the data read is valid. */
int
read_good_segment (struct memory_segment *data, int segment)
{
int result;
read_segment (data, segment);
result = ecc_correct_data (data);
if (result != ECC_FAILED)
return 1;
else
return 0;
}
/* Write one memory segment. */
void
write_segment (struct memory_segment *data, int segment)
{
int physical;
int logical;
int chunk;
int initial_offset = segment * BLOCKS_PER_SEGMENT;
physical = 0;
logical = 0;
while (physical < BLOCKS_PER_SEGMENT)
{
chunk = 0;
while (physical+chunk < BLOCKS_PER_SEGMENT
&& !BAD_CHECK (data->marked_bad, physical+chunk))
chunk++;
if (chunk == 0)
{
physical++;
}
else
{
if (write_chunk (data->data + logical * BLOCK_SIZE, chunk,
physical + initial_offset))
{
logical += chunk;
physical += chunk;
}
else
{
perror ("Fatal write error");
exit (1);
}
}
}
}
/* Write one memory segment with ecc data. */
void
write_good_segment (struct memory_segment *data, int segment)
{
set_segment_parity (data);
write_segment (data, segment);
}
/* This is at the end because of the stupid include files. */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <i386at/disk.h>
void
disable_write_verify (int fd)
{
extern int errno;
union vfy_io v;
*((int *) &v) = 0;
if (ioctl (fd, V_VERIFY, &v) == -1)
error (1, errno, "Can't disable verify on device");
}
#endif /* FLOPPY */