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 >
C/C++ Source or Header  |  1992-10-12  |  28KB  |  1,135 lines

  1. /* Read data from the tape.
  2.    Copyright (C) 1992 David L. Brown, Jr.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.    
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.    
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; see the file COPYING.  If not, write to
  16.    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /*
  19.  * read.c,v 1.25 1992/10/13 02:21:14 dbrown Exp
  20.  *
  21.  * read.c,v
  22.  * Revision 1.25  1992/10/13  02:21:14  dbrown
  23.  * Changed directory for include.
  24.  *
  25.  * Revision 1.24  1992/10/13  01:55:31  dbrown
  26.  * Added FSF copyright.
  27.  *
  28.  * Revision 1.23  1992/10/12  05:15:47  dbrown
  29.  * Fixed some bugs with beginning of track and write errors.
  30.  *
  31.  * Upped storred buffers to 3.  This should never be needed.  Somehow,
  32.  * this is requiring 5 in one instance.
  33.  *
  34.  * Revision 1.22  1992/10/11  02:22:26  dbrown
  35.  * Write now works occasionally.
  36.  *
  37.  * Revision 1.21  1992/10/11  00:25:05  dbrown
  38.  * Fixed many bugs in write code.  More to go...
  39.  *
  40.  * Revision 1.20  1992/10/10  07:00:37  dbrown
  41.  * Turned off debugging.
  42.  *
  43.  * Revision 1.19  1992/10/10  06:46:39  dbrown
  44.  * Changed write some.  This current write code is GARBAGE.
  45.  *
  46.  * Revision 1.18  1992/10/10  06:17:54  dbrown
  47.  * Started implementing write.  Doesn't actually do the write yet.
  48.  *
  49.  * Revision 1.17  1992/10/10  04:51:10  dbrown
  50.  * Initial attempt to make write usefully robust (so anything can be written).
  51.  *
  52.  * Revision 1.16  1992/10/09  05:56:58  dbrown
  53.  * Read is reliable.  Write is flaky and can't handle errors.
  54.  *
  55.  * Revision 1.15  1992/03/27  21:41:24  dbrown
  56.  * Synchronize with the driver if doing a write after a read.
  57.  *
  58.  * Revision 1.14  92/03/27  02:38:46  dbrown
  59.  * Supports both short and long tapes.
  60.  * Made debugging prints optional.
  61.  * 
  62.  * Revision 1.13  92/03/27  01:13:51  dbrown
  63.  * Now can write.
  64.  * 
  65.  * Revision 1.12  92/03/27  00:34:34  dbrown
  66.  * Retries more times.
  67.  * Handles error bits back from result.
  68.  * 
  69.  * Revision 1.11  92/03/24  15:34:31  dbrown
  70.  * Fixed for new read protocol.
  71.  * 
  72.  * Revision 1.10  92/03/23  09:35:22  dbrown
  73.  * Made read correctly.
  74.  * 
  75.  * Revision 1.9  92/03/22  22:29:22  dbrown
  76.  * Fixed seek forward by too much.
  77.  * Last of the old paradigm.
  78.  * 
  79.  * Revision 1.8  92/03/21  17:22:09  dbrown
  80.  * Seek code seems to work somewhat correctly.
  81.  * 
  82.  * Revision 1.7  92/03/21  16:26:01  dbrown
  83.  * Still trying to get read working across tracks.
  84.  * 
  85.  * Revision 1.6  92/03/21  15:38:54  dbrown
  86.  * Started adding support for more than track 0.
  87.  * 
  88.  * Revision 1.5  92/03/21  14:41:35  dbrown
  89.  * Fixed error messages.
  90.  * Moved wait_for_ready to not check during read.
  91.  * 
  92.  * Revision 1.4  92/03/21  14:31:07  dbrown
  93.  * Started modifying to use read ahead.
  94.  * 
  95.  * Revision 1.3  92/03/21  12:31:02  dbrown
  96.  * Added initial support for reading from tape.
  97.  * 
  98.  * Revision 1.2  92/03/19  23:01:07  dbrown
  99.  * Now compiles for tape but doesn't do anything.
  100.  * 
  101.  */
  102.  
  103. #include <assert.h>
  104. #include <stdio.h>
  105. #include <sys/file.h>
  106. #include "qic.h"
  107. #include "ecc.h"
  108. #include "header.h"
  109.  
  110. /* Debug */
  111.  
  112. #undef DEBUG_IO
  113. #ifdef DEBUG_IO
  114. # define DFPRINTF(x) fprintf x
  115. #else /* not DEBUG_IO */
  116. # define DFPRINTF(x)
  117. #endif /* not DEBUG_IO */
  118.  
  119. #ifndef FLOPPY
  120.  
  121. #include <sys/ioctl.h>
  122. #include <fdtape-io.h>
  123.  
  124. extern int errno;
  125.  
  126. /* Tape device. */
  127.  
  128. int tape_fd = -1;
  129.  
  130. /* Guess at the current segment number. */
  131.  
  132. int current_segment;
  133.  
  134. /* Track the tape head is on. */
  135.  
  136. int current_track;
  137.  
  138. /* Number of segments per track.  Set by open_tape. */
  139.  
  140. int segments_per_track = 150;
  141.  
  142. /* Open up the tape device. */
  143.  
  144. void
  145. open_tape ()
  146. {
  147.   int value, result;
  148.   int status;
  149.   struct fdt_error tape_error;
  150.  
  151.   if (tape_fd < 0)
  152.     {
  153.       tape_fd = open ("/dev/ftape", O_RDWR);
  154.       if (tape_fd < 0)
  155.     error (1, errno, "Cannot open tape drive");
  156.  
  157.       /* Wait for drive ready. */
  158.       status = wait_for_ready ();
  159.       if (status & QIC_STATUS_NEW_CARTRIDGE)
  160.     {
  161.       DFPRINTF ((stderr, "ioctl FDT_REPORT_ERROR_CODE\n"));
  162.       result = ioctl (tape_fd, FDT_REPORT_ERROR_CODE, &tape_error);
  163.       if (result != 0)
  164.         error (1, errno, "Cannot read tape drive status");
  165.       status = wait_for_ready ();
  166.     }
  167.       if (status & QIC_STATUS_ERROR)
  168.     {
  169.       DFPRINTF ((stderr, "ioctl FDT_REPORT_ERROR_CODE\n"));
  170.       result = ioctl (tape_fd, FDT_REPORT_ERROR_CODE, &tape_error);
  171.       if (result != 0)
  172.         error (1, errno, "Cannot read tape drive status");
  173.     }
  174.  
  175.       if (!(status & QIC_STATUS_CARTRIDGE_PRESENT))
  176.     error (1, 0, "Please insert a cartridge");
  177.  
  178.       /* Get drive configuration. */
  179.       {
  180.     int configuration;
  181.  
  182.     DFPRINTF ((stderr, "ioctl FDT_REPORT_CONFIGURATION\n"));
  183.     result = ioctl (tape_fd, FDT_REPORT_CONFIGURATION, &configuration);
  184.     if (result != 0)
  185.       error (1, errno, "Cannot get drive configuration");
  186.  
  187.     if (configuration & QIC_CONFIG_LONG)
  188.       segments_per_track = 150;
  189.     else
  190.       segments_per_track = 100;
  191.  
  192.     DFPRINTF ((stderr, "ioctl FDT_SET_TRACK_LENGTH\n"));
  193.     result = ioctl (tape_fd, FDT_SET_TRACK_LENGTH, &segments_per_track);
  194.     if (result != 0)
  195.       error (1, errno, "Cannot set track length in driver");
  196.     if (!(configuration & QIC_CONFIG_80))
  197.       error (1, 0, "Error: cannot handle QIC-40 cartridges (yet!)\n");
  198.       }
  199.  
  200.       /* Rewind the tape and go to track 0. */
  201.       DFPRINTF ((stderr, "ioctl FDT_SEEK_TO_BEGINNING\n"));
  202.       result = ioctl (tape_fd, FDT_SEEK_TO_BEGINNING, 0);
  203.       if (result != 0)
  204.     error (1, errno, "Cannot rewind tape");
  205.  
  206.       value = 0;
  207.       DFPRINTF ((stderr, "ioctl FDT_SEEK_TO_TRACK\n"));
  208.       result = ioctl (tape_fd, FDT_SEEK_TO_TRACK, &value);
  209.       if (result != 0)
  210.     error (1, errno, "Cannot move tape head");
  211.       current_segment = 0;
  212.       current_track = -1;
  213.     }
  214. }
  215.  
  216. /* Is a read ahead in progress? */
  217.  
  218. static int read_ahead_running = 0;
  219.  
  220. /* Is a write probably in progress? */
  221.  
  222. static int write_ahead_running = 0;
  223.  
  224. /* Write one memory segment.  -1 return is success, >= 0 is failure. */
  225. int
  226. write_segment (struct memory_segment *data, int segment)
  227. {
  228.   int return_value = 0;
  229.   int value, result;
  230.   int count;
  231.   struct tape_write twrite;
  232.   struct error_map emap;
  233.   struct write_cease wc;
  234.  
  235.   open_tape ();
  236.  
  237.   DFPRINTF ((stderr, "W: Marked bad: 0x%08x\n", data->marked_bad));
  238.  
  239.   for (count = 1; count > 0; count--)
  240.     {
  241.       DFPRINTF ((stderr, "write %d, cur= %d\n",
  242.          segment, current_segment));
  243.       if (segment != current_segment
  244.       || segment % segments_per_track == 0)
  245.     {
  246.       must_not_be_writing ();
  247.     }
  248.  
  249.       if (segment / segments_per_track != current_track)
  250.     {
  251.       must_not_be_writing ();
  252.       /* Seek the heads. */
  253.       wait_for_ready ();
  254.       current_track = segment / segments_per_track;
  255.       DFPRINTF ((stderr, "Move tape heads to track %d\n",
  256.              current_track));
  257.       DFPRINTF ((stderr, "ioctl FDT_SEEK_TO_TRACK\n"));
  258.       result = ioctl (tape_fd, FDT_SEEK_TO_TRACK, ¤t_track);
  259.       if (result != 0)
  260.         error (1, errno, "Cannot move tape head");
  261.  
  262.       /* Unsure of where we are on the new track. */
  263.       current_segment = segment;
  264.  
  265.       emap.count = segments_per_track;
  266.       emap.error_masks = ¤t_header.bad_sectors[segment
  267.                              - (segment
  268.                                 % segments_per_track)];
  269.  
  270.       DFPRINTF ((stderr, "ioctl FDT_SUBMIT_ERROR_MAP\n"));
  271.       result = ioctl (tape_fd, FDT_SUBMIT_ERROR_MAP, &emap);
  272.       if (result != 0)
  273.         error (1, errno, "Cannot submit error map.");
  274.  
  275.     }
  276.  
  277.       /* If the write request is at the beginning of a track,
  278.      rewind the tape to the appropriate end. */
  279.  
  280.       if (segment % segments_per_track == 0)
  281.     {
  282.       int command;
  283.       must_not_be_writing ();
  284.       if ((current_track & 1) == 0)
  285.         command = FDT_SEEK_TO_BEGINNING;
  286.       else
  287.         command = FDT_SEEK_TO_END;
  288.       DFPRINTF ((stderr, "Wind tape to start of track %d\n",
  289.              current_track));
  290.       result = ioctl (tape_fd, command, 0);
  291.       if (result != 0)
  292.         error (1, errno, "Error winding tape to end");
  293.  
  294.       emap.count = segments_per_track;
  295.       emap.error_masks = ¤t_header.bad_sectors[segment
  296.                              - (segment
  297.                                 % segments_per_track)];
  298.  
  299.       DFPRINTF ((stderr, "ioctl FDT_SUBMIT_ERROR_MAP\n"));
  300.       result = ioctl (tape_fd, FDT_SUBMIT_ERROR_MAP, &emap);
  301.       if (result != 0)
  302.         error (1, errno, "Cannot submit error map.");
  303.     }
  304.  
  305.       /* If the last write was distant from the desired write seek
  306.      the tape heads.  First seek if a reverse seek is
  307.      appropriate. */
  308.  
  309.       else if (segment < current_segment)
  310.     {
  311.       must_not_be_writing ();
  312.       wait_for_ready ();
  313.       /* Seek one extra segment in reverse. */
  314.       value = current_segment - segment;
  315.       /* If error appears to be due to running off the end of
  316.          the tape then go back a little further. */
  317.       if (current_segment % segments_per_track
  318.           == segments_per_track - 1)
  319.         value += 4;
  320.       DFPRINTF ((stderr, "Seek backward by %d\n", value));
  321.       result = ioctl (tape_fd, FDT_SEEK_REVERSE, &value);
  322.       if (result != 0)
  323.         error (1, errno, "Cannot seek tape");
  324.     }
  325.  
  326.       /* Also try seeking forward. */
  327.  
  328.       else if (segment > current_segment + 3)
  329.     {
  330.       must_not_be_writing ();
  331.       wait_for_ready ();
  332.       /* Seek 2 less forward than what it appears we need to. */
  333.       value = segment - current_segment - 3;
  334.       DFPRINTF ((stderr, "Seek forward by %d\n", value));
  335.       result = ioctl (tape_fd, FDT_SEEK_FORWARD, &value);
  336.       if (result != 0)
  337.         error (1, errno, "Cannot seek tape");
  338.     }
  339.  
  340.       twrite.buffer = data->data;
  341.       twrite.segment = segment;
  342.       DFPRINTF ((stderr, "Start write\n"));
  343.       write_ahead_running = 1;
  344.       result = ioctl (tape_fd, FDT_WRITE, &twrite);
  345.       if (result != 0)
  346.     error (1, errno, "Error writing");
  347.       else if (twrite.actual_segment != -1)
  348.     {
  349.       DFPRINTF ((stderr, "Actually on: %d\n",
  350.              twrite.actual_segment));
  351.       write_ahead_running = 0;
  352.       result = ioctl (tape_fd, FDT_CEASE_WRITING, &wc);
  353.       if (result != 0)
  354.         error (1, errno, "Error stopping errored write");
  355.       if (wc.actual_segment != twrite.actual_segment
  356.           || wc.error_location != twrite.error_location)
  357.         error (1, 0, "Tape driver problem reporting write position\n"
  358.            "wcact = %d, wract = %d, wcerr = %d, wrerr = %d\n",
  359.            wc.actual_segment, twrite.actual_segment,
  360.            wc.error_location, twrite.error_location);
  361.       if (twrite.actual_segment == -2)
  362.         current_segment = (segments_per_track * current_track
  363.                    + segments_per_track - 1);
  364.       else if (twrite.actual_segment == -3)
  365.         {
  366.           DFPRINTF ((stderr, "Write position problem, retrying.\n"));
  367.           /*continue;*/
  368.         }
  369.       else
  370.         {
  371.           if (current_segment / segments_per_track
  372.           != twrite.actual_segment / segments_per_track)
  373.         {
  374.           error (1, 0, "Tape is not on correct track");
  375.         }
  376.           /* Add one because we can't read what the heads are on. */
  377.           current_segment = twrite.actual_segment + 1;
  378.         }
  379.       return_value = twrite.error_location;
  380.     }
  381.       else
  382.     {
  383.       count = 0;
  384.       return_value = -1;
  385.       current_segment = segment + 1;
  386.     }
  387.     }
  388.  
  389.   return return_value;
  390. }
  391.  
  392. int
  393. do_reseek_logic (int actual_segment)
  394. {
  395.   if (actual_segment == -2)
  396.     current_segment = (segments_per_track * current_track
  397.                + segments_per_track - 1);
  398.   else if (actual_segment == -3)
  399.     {
  400.       DFPRINTF ((stderr, "Write position problem, retrying.\n"));
  401.     }
  402.   else
  403.     {
  404.       if (current_segment / segments_per_track
  405.       != actual_segment / segments_per_track)
  406.     {
  407.       error (1, 0, "Tape is not on correct track");
  408.     }
  409.       /* Add one because we can't read what the heads are on. */
  410.       current_segment = actual_segment + 1;
  411.     }
  412. }
  413.  
  414. int
  415. wait_for_ready ()
  416. {
  417.   int result, status;
  418.   int timeout;
  419.  
  420.   if (read_ahead_running)
  421.     {
  422.       DFPRINTF ((stderr, "ioctl FDT_READ_STOP\n"));
  423.       result = ioctl (tape_fd, FDT_READ_STOP, 0);
  424.       if (result != 0)
  425.     error (0, errno, "Abort unnecessary.");
  426.       read_ahead_running = 0;
  427.     }
  428.   if (write_ahead_running)
  429.     {
  430.       write_cease ();
  431.     }
  432.  
  433.   for (timeout = 46000; timeout > 0; timeout--)
  434.     {
  435.       DFPRINTF ((stderr, "ioctl FDT_REPORT_STATUS\n"));
  436.       result = ioctl (tape_fd, FDT_REPORT_STATUS, &status);
  437.       if (result != 0)
  438.     error (1, errno, "Cannot get drive status");
  439.       if ((status & 1        /* !!! MAGIC !!! */) == 0)
  440.     {
  441.       usleep (100000);
  442.     }
  443.       else
  444.     timeout = 0;
  445.     }
  446.   return status;
  447. }
  448.  
  449. /* Count of segments left to read in run. */
  450.  
  451. static int read_ahead_left;
  452.  
  453. /* Read in one memory segment. */
  454.  
  455. void
  456. read_segment (struct memory_segment *data, int segment)
  457. {
  458.   int value, result;
  459.   int count;
  460.   struct error_map emap;
  461.   struct tape_read tread;
  462.  
  463.   open_tape ();
  464.  
  465.   data->read_bad = 0xffffffff;
  466.  
  467.   if (write_ahead_running)
  468.     {
  469.       write_cease ();
  470.     }
  471.  
  472.   DFPRINTF ((stderr, "Marked bad: 0x%08x\n", data->marked_bad));
  473.  
  474.   for (count = 10; count > 0; count--)
  475.     {
  476.       DFPRINTF ((stderr, "segment = %d, current_segment = %d\n",
  477.            segment, current_segment));
  478.       if (read_ahead_running)
  479.     {
  480.       if (segment != current_segment || current_segment < 3
  481.           || segment % segments_per_track == 0)
  482.         {
  483.           DFPRINTF ((stderr, "ioctl FDT_READ_STOP\n"));
  484.           result = ioctl (tape_fd, FDT_READ_STOP, 0);
  485.           if (result != 0)
  486.         error (0, errno, "Abort unnecessary.");
  487.           read_ahead_running = 0;
  488.         }
  489.     }
  490.       if (!read_ahead_running)
  491.     {
  492.       if (segment / segments_per_track != current_track)
  493.         {
  494.           /* Seek the heads. */
  495.           /*wait_for_ready ();*/
  496.           current_track = segment / segments_per_track;
  497.           DFPRINTF ((stderr, "Move tape heads to track %d\n",
  498.                current_track));
  499.           result = ioctl (tape_fd, FDT_SEEK_TO_TRACK, ¤t_track);
  500.           if (result != 0)
  501.         error (1, errno, "Cannot move tape head");
  502.  
  503.           /* Unsure of where we are on the new track. */
  504.           current_segment = segment;
  505.         }
  506.  
  507.       /* If the read request is at the beginning of a track,
  508.          rewind the tape to the appropriate end. */
  509.  
  510.       if (segment % segments_per_track == 0)
  511.         {
  512.           int command;
  513.           if ((current_track & 1) == 0)
  514.         command = FDT_SEEK_TO_BEGINNING;
  515.           else
  516.         command = FDT_SEEK_TO_END;
  517.           DFPRINTF ((stderr, "Wind tape to start of track %d\n",
  518.                current_track));
  519.           result = ioctl (tape_fd, command, 0);
  520.           if (result != 0)
  521.         error (1, errno, "Error winding tape to end");
  522.         }
  523.  
  524.       /* If the last read was distant from the desired read seek
  525.          the tape heads.  First seek if a reverse seek is
  526.          appropriate. */
  527.  
  528.       else if (segment < current_segment)
  529.         {
  530.           wait_for_ready ();
  531.           /* Seek one extra segment in reverse. */
  532.           value = current_segment - segment;
  533.           /* If error appears to be due to running off the end of
  534.          the tape then go back a little further. */
  535.           if (current_segment % segments_per_track
  536.           == segments_per_track - 1)
  537.         value += 4;
  538.           DFPRINTF ((stderr, "Seek backward by %d\n", value));
  539.           result = ioctl (tape_fd, FDT_SEEK_REVERSE, &value);
  540.           if (result != 0)
  541.         error (1, errno, "Cannot seek tape");
  542.         }
  543.  
  544.       /* Also try seeking forward. */
  545.  
  546.       else if (segment > current_segment + 3)
  547.         {
  548.           wait_for_ready ();
  549.           /* Seek 2 less forward than what it appears we need to. */
  550.           value = segment - current_segment - 3;
  551.           DFPRINTF ((stderr, "Seek forward by %d\n", value));
  552.           result = ioctl (tape_fd, FDT_SEEK_FORWARD, &value);
  553.           if (result != 0)
  554.         error (1, errno, "Cannot seek tape");
  555.         }
  556.  
  557.       /* Don't read ahead if reading the header. */
  558.       if (segment == 0 || segment == 1)
  559.         {
  560.           read_ahead_left = 1;
  561.           emap.count = 2;
  562.           /* Tacky, should see if done elsewhere. */
  563.           current_header.bad_sectors[segment] = 0;
  564.         }
  565.       else
  566.         {
  567.           emap.count = segments_per_track;
  568.           read_ahead_left = (segments_per_track
  569.                  - (segment % segments_per_track));
  570.         }
  571.  
  572.       emap.error_masks = ¤t_header.bad_sectors[segment
  573.                              - (segment
  574.                                 % segments_per_track)];
  575.       DFPRINTF ((stderr, "Start reading %d-%d\n",
  576.            segment, segment + emap.count - 1));
  577.       DFPRINTF ((stderr, "ioctl FDT_SUBMIT_ERROR_MAP\n"));
  578.       result = ioctl (tape_fd, FDT_SUBMIT_ERROR_MAP, &emap);
  579.       if (result != 0)
  580.         error (1, errno, "Cannot submit error map.");
  581.       read_ahead_running = 1;
  582.     }
  583.  
  584.       tread.buffer = data->data;
  585.       tread.segment = segment;
  586.       tread.count = read_ahead_left;
  587.       DFPRINTF ((stderr, "Start read\n"));
  588.       result = ioctl (tape_fd, FDT_READ, &tread);
  589. #if 0
  590.       DFPRINTF ((stderr, "Read result = %d\n", tread.result));
  591. #endif
  592.       read_ahead_left--;
  593.       if (result != 0)
  594.     error (1, errno, "Error reading");
  595.       else if (tread.actual_segment != -1)
  596.     {
  597.       DFPRINTF ((stderr, "Actually read: %d\n", tread.actual_segment));
  598.       if (tread.actual_segment == -2)
  599.         current_segment = (segments_per_track * current_track
  600.                    + segments_per_track - 1);
  601.       else if (tread.actual_segment == -3)
  602.         {
  603.           fprintf (stderr, "Read error, retrying.\n");
  604.           continue;
  605.         }
  606.       else
  607.         {
  608.           if (current_segment / segments_per_track
  609.           != tread.actual_segment / segments_per_track)
  610.         {
  611.           error (1, 0, "Tape is not on correct track");
  612.         }
  613.           /* Add one because we can't read what the heads are on. */
  614.           current_segment = tread.actual_segment + 1;
  615.         }
  616.     }
  617.       else
  618.     {
  619.       count = 0;
  620.       /*BAD_CLEAR (data->read_bad); /* Need to use result from read. */
  621.       /* !!! Depends on word ordering being proper. !!! */
  622.       data->read_bad = tread.error_bits;
  623.       /*data->read_bad = 0;*/
  624.       current_segment = segment + 1;
  625.     }
  626.     }
  627. }
  628.  
  629. /* Read in one memory segment and produce correct data.  Returns
  630.    non-zero if the data read is valid. */
  631.  
  632. int
  633. read_good_segment (struct memory_segment *data, int segment)
  634. {
  635.   int result;
  636.  
  637.   read_segment (data, segment);
  638.   result = ecc_correct_data (data);
  639.   if (result != ECC_FAILED)
  640.     return 1;
  641.   else
  642.     return 0;
  643. }
  644.  
  645. /* Close the tape device and prepare for a new volume. */
  646. void
  647. close_down (void)
  648. {
  649.   static int recursion_count = 0;
  650.   int result;
  651.  
  652.   if (recursion_count > 0)
  653.     return;
  654.   recursion_count++;
  655.   if (tape_fd == -1)
  656.     return;
  657. #if 0                /* Done in wait for ready */
  658.   if (read_ahead_running)
  659.     {
  660.       result = ioctl (tape_fd, FDT_READ_STOP, 0);
  661.       if (result != 0)
  662.     error (0, errno, "Unnecessary abort");
  663.     }
  664. #endif
  665.   /* Rewind the tape. */
  666.   wait_for_ready ();
  667.   DFPRINTF ((stderr, "ioctl FDT_SEEK_TO_BEGINNING\n"));
  668.   result = ioctl (tape_fd, FDT_SEEK_TO_BEGINNING, 0);
  669.   if (result != 0)
  670.     {
  671.       error (0, errno, "Cannot rewind tape");
  672.       exit (1);
  673.     }
  674.   close (tape_fd);
  675.   tape_fd = -1;
  676.   recursion_count--;
  677. }
  678.  
  679. /* Write one memory segment with ecc data. */
  680.  
  681. static char kept_buffers[3][32768];
  682. static int kept_segment[3] = { -1, -1 };
  683. static struct memory_segment kept_data[3];
  684. static int last_written_segment;
  685.  
  686. void
  687. write_good_segment (struct memory_segment *data, int segment)
  688. {
  689.   int go_back;
  690.   int redo;            /* Where to redo from. */
  691.   int count = 10;
  692.   int result;
  693.   int which;
  694.   struct write_cease wc;
  695.   struct memory_segment *to_write;
  696.  
  697.   set_segment_parity (data);
  698.  
  699.   open_tape ();
  700.  
  701.   if (read_ahead_running)
  702.     {
  703.       /* Wait for the read ahead to finish. */
  704.  
  705.       DFPRINTF ((stderr, "ioctl FDT_READ_STOP\n"));
  706.       result = ioctl (tape_fd, FDT_READ_STOP, 0);
  707.       if (result != 0)
  708.     error (1, errno, "Cannot synchronize with driver");
  709.       read_ahead_running = 0;
  710.     }
  711.  
  712.   if (segment / segments_per_track != current_track
  713.       || segment != current_segment
  714.       || segment % segments_per_track == 0)
  715.     write_cease ();
  716.  
  717.   go_back = write_segment (data, segment);
  718.   if (go_back != -1)
  719.     {
  720. #if 0
  721.       DFPRINTF ((stderr, "ioctl FDT_CEASE_WRITING\n"));
  722.       result = ioctl (tape_fd, FDT_CEASE_WRITING, &wc);
  723.       if (result != 0)
  724.     perror (1, errno, "Can't stop driver write command");
  725.       redo = wc.error_location;
  726. #else
  727.       redo = go_back;
  728. #endif
  729.     }
  730.   while (go_back != -1
  731.      && count-- > 0)
  732.     {
  733.       if (kept_segment[0] == redo)
  734.     to_write = &kept_data[0];
  735.       else if (kept_segment[1] == redo)
  736.     to_write = &kept_data[1];
  737.       else if (kept_segment[2] == redo)
  738.     to_write = &kept_data[2];
  739.       else if (redo == segment)
  740.     to_write = data;
  741.       else
  742.     error (1, 0, "Fatal: write not flushed");
  743.  
  744.       go_back = write_segment (to_write, redo);
  745.       if (go_back == -1)
  746.     {
  747.       redo++;
  748.       if (redo <= segment)
  749.         go_back = redo;
  750.     }
  751.       else
  752.     {
  753. #if 0
  754.       DFPRINTF ((stderr, "ioctl FDT_CEASE_WRITING\n"));
  755.       result = ioctl (tape_fd, FDT_CEASE_WRITING, &wc);
  756.       if (result != 0)
  757.         perror (1, errno, "Can't stop driver write command");
  758.       redo = wc.error_location;
  759. #else
  760.       redo = go_back;
  761. #endif
  762.     }
  763.     }
  764.   if (go_back == -1)
  765.     {
  766.       which = 0;
  767.       if (kept_segment[1] < kept_segment[0]
  768.       && kept_segment[2] < kept_segment[0])
  769.     which = 1;
  770.       if (kept_segment[0] < kept_segment[1]
  771.       && kept_segment[2] < kept_segment[1])
  772.     which = 2;
  773.  
  774.       kept_segment[which] = segment;
  775.       kept_data[which].data = kept_buffers[which];
  776.       kept_data[which].marked_bad = data->marked_bad;
  777.       kept_data[which].read_bad = data->read_bad;
  778.       kept_data[which].blocks = data->blocks;
  779.       bcopy (data->data, kept_data[which].data,
  780.          32768);
  781.       last_written_segment = segment;
  782.     }
  783.   else
  784.     error (1, 0, "Fatal, can't write successfully");
  785. }
  786.  
  787. int
  788. write_cease ()
  789. {
  790.   int redo, go_back, count = 10;
  791.   int result;
  792.   struct write_cease wc;
  793.   struct memory_segment *to_write;
  794.   int had_trouble = 0;
  795.   int problem_count = 10;
  796.  
  797.   do
  798.     {
  799.       had_trouble = 0;
  800.       DFPRINTF ((stderr, "ioctl FDT_CEASE_WRITING\n"));
  801.       result = ioctl (tape_fd, FDT_CEASE_WRITING, &wc);
  802.       if (result != 0)
  803.     error (1, errno, "Can't stop driver write command");
  804.       write_ahead_running = 0;
  805.       go_back = -1;
  806.       if (wc.actual_segment != -1)
  807.     {
  808.       do_reseek_logic (wc.actual_segment);
  809.       had_trouble = 1;
  810.       redo = wc.error_location;
  811.       go_back = redo;
  812.       while (go_back != -1
  813.          && count-- > 0)
  814.         {
  815.           if (kept_segment[0] == redo)
  816.         to_write = &kept_data[0];
  817.           else if (kept_segment[1] == redo)
  818.         to_write = &kept_data[1];
  819.           else if (kept_segment[2] == redo)
  820.         to_write = &kept_data[2];
  821.           else
  822.         error (1, 0, "Fatal: write not flushed (2)");
  823.  
  824.           go_back = write_segment (to_write, redo);
  825.           if (go_back == -1)
  826.         {
  827.           redo++;
  828.           if (redo <= last_written_segment)
  829.             go_back = redo;
  830.         }
  831.           else
  832.         {
  833.           DFPRINTF ((stderr, "ioctl FDT_CEASE_WRITING\n"));
  834.           result = ioctl (tape_fd, FDT_CEASE_WRITING, &wc);
  835.           if (result != 0)
  836.             if (result != 0)
  837.               perror (1, errno, "Can't stop driver write command");
  838.           redo = wc.error_location;
  839.           do_reseek_logic (wc.actual_segment);
  840.         }
  841.         }
  842.     }
  843.  
  844.       if (go_back != -1)
  845.     error (1, 0, "Cannot successfully write data");
  846.     }
  847.   while (had_trouble
  848.      && --problem_count > 0);
  849.  
  850.   if (problem_count <= 0)
  851.     error (1, 0, "Gave up on write termination");
  852. }
  853.  
  854. int
  855. must_not_be_writing ()
  856. {
  857.   if (write_ahead_running)
  858.     error (0, 0, "Write has not been terminated properly.\n"),
  859.     abort ();            /* Dump core so the reason can be
  860.                    determined. */
  861. }
  862.  
  863. #else /* FLOPPY */
  864. /* This is the floppy solution to the reader. */
  865.  
  866. /* Last position of the file pointer.  -1 if the file itself is invalid. */
  867. static int data_file_at = -1;
  868.  
  869. /* File handle of the data. */
  870. static int data_file = -1;
  871.  
  872. /* Last operation, 0 = read, 1 = write. */
  873. static int last_operation = 0;
  874.  
  875. #define FILE_NAME "/dev/rfd0a"
  876.  
  877. /* Seek to a position, if necessary. */
  878.  
  879. static void
  880. seek_to (int position, int operation)
  881. {
  882.   int result;
  883.  
  884.   if (data_file == -1)
  885.     {
  886.       data_file = open (FILE_NAME, O_RDWR);
  887.       assert (data_file);
  888.       data_file_at = -1;
  889.  
  890.       /* Turn of write verify. */
  891.       disable_write_verify (data_file);
  892.     }
  893.  
  894.   if (data_file_at != position || last_operation != operation)
  895.     {
  896. #if 0
  897.       DPRINTF (("Seek: from %d to %d\n", data_file_at, position));
  898. #endif
  899.       result = lseek (data_file, position * BLOCK_SIZE, L_SET);
  900.       if (result == -1)
  901.     {
  902.       perror ("Can't lseek on device");
  903.       exit (1);
  904.     }
  905.       data_file_at = position;
  906.       last_operation = operation;
  907.     }
  908.  
  909. /* Close down the file. */
  910.  
  911. void
  912. close_down (void)
  913. {
  914.   if (data_file != -1)
  915.     {
  916.       close (data_file);
  917.       data_file = -1;
  918.     }
  919. }
  920.  
  921. /* Read in a chunk of data.  Returns 1 if success. */
  922.  
  923. static int
  924. read_chunk (char *data, int size, int position)
  925. {
  926.   int result;
  927.  
  928.   seek_to (position, 0);
  929.  
  930. #if 0
  931.   DPRINTF (("Read chunk: segment %d, sector %d, count %d, ",
  932.       position / BLOCKS_PER_SEGMENT, position % BLOCKS_PER_SEGMENT,
  933.       size));
  934. #endif
  935.  
  936.   result = read (data_file, data, size * BLOCK_SIZE);
  937.   if (result != size * BLOCK_SIZE)
  938.     {
  939.       close_down();
  940.       result = 0;
  941.     }
  942.   else
  943.     {
  944.       result = 1;
  945.       data_file_at += size;
  946.     }
  947.  
  948. #if 0
  949.   DPRINTF (("%s\n", result ? "OK" : "Failed"));
  950. #endif
  951.   return (result);
  952. }
  953.  
  954. /* Write out a chunk of data.  Returns 1 if success. */
  955.  
  956. static int
  957. write_chunk (char *data, int size, int position)
  958. {
  959.   int result;
  960.  
  961.   seek_to (position, 1);
  962.  
  963. #if 0
  964.   DPRINTF (("Write chunk: segment %d, sector %d, count %d, ",
  965.       position / BLOCKS_PER_SEGMENT, position % BLOCKS_PER_SEGMENT,
  966.       size));
  967. #endif
  968.  
  969.   result = write (data_file, data, size * BLOCK_SIZE);
  970.   if (result != size * BLOCK_SIZE)
  971.     {
  972.       close_down();
  973.       result = 0;
  974.     }
  975.   else
  976.     {
  977.       data_file_at += size;
  978.       result = 1;
  979.     }
  980.  
  981. #if 0
  982.   DPRINTF (("%s\n", result ? "OK" : "Failed"));
  983. #endif
  984.   return (result);
  985. }
  986.  
  987. /* Read in one memory segment. */
  988.  
  989. void
  990. read_segment (struct memory_segment *data, int segment)
  991. {
  992.   int physical;            /* Physical current block. */
  993.   int logical;            /* Logical current block. */
  994.   int chunk;
  995.   int result;
  996.   int initial_offset = segment * BLOCKS_PER_SEGMENT;
  997.  
  998.   BAD_CLEAR (data->read_bad);
  999.   physical = 0;
  1000.   logical = 0;
  1001.   while (physical < BLOCKS_PER_SEGMENT)
  1002.     {
  1003.       chunk = 0;
  1004.       while (physical+chunk < BLOCKS_PER_SEGMENT
  1005.          && !BAD_CHECK (data->marked_bad, physical+chunk))
  1006.     chunk++;
  1007.       if (chunk == 0)
  1008.     {
  1009.       physical++;
  1010.     }
  1011.       else
  1012.     {
  1013.       if (read_chunk (data->data + logical * BLOCK_SIZE, chunk,
  1014.               physical + initial_offset))
  1015.         {
  1016.           logical += chunk;
  1017.           physical += chunk;
  1018.         }
  1019.       else
  1020.         {
  1021.           /* If the chunk size was 1, just mark bad, and go on. */
  1022.           if (chunk == 1)
  1023.         {
  1024.           BAD_SET (data->read_bad, physical);
  1025.           physical++;
  1026.         }
  1027.           else
  1028.         {
  1029.           /* Otherwise read in each block and test it. */
  1030.           for (; chunk > 0; chunk--)
  1031.             {
  1032.               if (read_chunk (data->data + logical * BLOCK_SIZE,
  1033.                       1, physical + initial_offset))
  1034.             {
  1035.               physical++;
  1036.               logical++;
  1037.             }
  1038.               else
  1039.             {
  1040.               BAD_SET (data->read_bad, physical);
  1041.               physical++;
  1042.             }
  1043.             }
  1044.         }
  1045.         }
  1046.     }
  1047.     }
  1048.   data->blocks = logical;
  1049. }
  1050.  
  1051. /* Read in one memory segment and and produce correct data.  Returns
  1052.    non-zero if the data read is valid. */
  1053.  
  1054. int
  1055. read_good_segment (struct memory_segment *data, int segment)
  1056. {
  1057.   int result;
  1058.  
  1059.   read_segment (data, segment);
  1060.   result = ecc_correct_data (data);
  1061.   if (result != ECC_FAILED)
  1062.     return 1;
  1063.   else
  1064.     return 0;
  1065. }
  1066.  
  1067. /* Write one memory segment. */
  1068.  
  1069. void
  1070. write_segment (struct memory_segment *data, int segment)
  1071. {
  1072.   int physical;
  1073.   int logical;
  1074.   int chunk;
  1075.   int initial_offset = segment * BLOCKS_PER_SEGMENT;
  1076.  
  1077.   physical = 0;
  1078.   logical = 0;
  1079.   while (physical < BLOCKS_PER_SEGMENT)
  1080.     {
  1081.       chunk = 0;
  1082.       while (physical+chunk < BLOCKS_PER_SEGMENT
  1083.          && !BAD_CHECK (data->marked_bad, physical+chunk))
  1084.     chunk++;
  1085.       if (chunk == 0)
  1086.     {
  1087.       physical++;
  1088.     }
  1089.       else
  1090.     {
  1091.       if (write_chunk (data->data + logical * BLOCK_SIZE, chunk,
  1092.                physical + initial_offset))
  1093.         {
  1094.           logical += chunk;
  1095.           physical += chunk;
  1096.         }
  1097.       else
  1098.         {
  1099.           perror ("Fatal write error");
  1100.           exit (1);
  1101.         }
  1102.     }
  1103.     }
  1104. }
  1105.  
  1106. /* Write one memory segment with ecc data. */
  1107.  
  1108. void
  1109. write_good_segment (struct memory_segment *data, int segment)
  1110. {
  1111.   set_segment_parity (data);
  1112.   write_segment (data, segment);
  1113. }
  1114.  
  1115.  
  1116. /* This is at the end because of the stupid include files. */
  1117.  
  1118. #include <sys/types.h>
  1119. #include <sys/ioctl.h>
  1120. #include <i386at/disk.h>
  1121.  
  1122. void
  1123. disable_write_verify (int fd)
  1124. {
  1125.   extern int errno;
  1126.   union vfy_io v;
  1127.  
  1128.   *((int *) &v) = 0;
  1129.   if (ioctl (fd, V_VERIFY, &v) == -1)
  1130.     error (1, errno, "Can't disable verify on device");
  1131. }
  1132.  
  1133. #endif /* FLOPPY */
  1134.