root/drivers/char/ftape/fdc-isr.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. print_error_cause
  2. get_fdc_mode_text
  3. decode_irq_cause
  4. update_history
  5. skip_bad_sector
  6. update_error_maps
  7. determine_progress
  8. calc_steps
  9. pause_tape
  10. stop_tape
  11. continue_xfer
  12. retry_sector
  13. find_resume_point
  14. fdc_isr

   1 /*
   2  *      Copyright (C) 1994-1995 Bas Laarhoven.
   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  $Source: /home/bas/distr/ftape-2.03b/RCS/fdc-isr.c,v $
  19  $Author: bas $
  20  *
  21  $Revision: 1.36 $
  22  $Date: 1995/05/27 08:54:21 $
  23  $State: Beta $
  24  *
  25  *      This file contains the interrupt service routine and associated
  26  *      code for the QIC-40/80 tape streamer device driver.
  27  */
  28 
  29 #include <linux/module.h>
  30 #include <linux/ftape.h>
  31 #include <asm/io.h>
  32 #include <asm/dma.h>
  33 
  34 #define volatile                /* */
  35 
  36 #include "tracing.h"
  37 #include "fdc-isr.h"
  38 #include "qic117.h"
  39 #include "fdc-io.h"
  40 #include "ftape-ctl.h"
  41 #include "ftape-rw.h"
  42 #include "ftape-io.h"
  43 #include "calibr.h"
  44 #include "ftape-bsm.h"
  45 
  46 /*      Global vars.
  47  */
  48 volatile int expected_stray_interrupts = 0;
  49 volatile int seek_completed = 0;
  50 volatile int interrupt_seen = 0;
  51 volatile int expect_stray_interrupt = 0;
  52 int random_rw = 0;
  53 
  54 /*      Local vars.
  55  */
  56 typedef enum {
  57         no_error = 0, id_am_error = 0x01, id_crc_error = 0x02,
  58         data_am_error = 0x04, data_crc_error = 0x08,
  59         no_data_error = 0x10, overrun_error = 0x20,
  60 } error_cause;
  61 static int hide_interrupt;
  62 static int stop_read_ahead = 0;
  63 
  64 
  65 static void print_error_cause(int cause)
     /* [previous][next][first][last][top][bottom][index][help] */
  66 {
  67         TRACE_FUN(8, "print_error_cause");
  68 
  69         switch (cause) {
  70         case no_data_error:
  71                 TRACE(4, "no data error");
  72                 break;
  73         case id_am_error:
  74                 TRACE(4, "id am error");
  75                 break;
  76         case id_crc_error:
  77                 TRACE(4, "id crc error");
  78                 break;
  79         case data_am_error:
  80                 TRACE(4, "data am error");
  81                 break;
  82         case data_crc_error:
  83                 TRACE(4, "data crc error");
  84                 break;
  85         case overrun_error:
  86                 TRACE(4, "overrun error");
  87                 break;
  88         default:
  89         }
  90         TRACE_EXIT;
  91 }
  92 
  93 static char *
  94 get_fdc_mode_text(fdc_mode_enum fdc_mode)
     /* [previous][next][first][last][top][bottom][index][help] */
  95 {
  96         switch (fdc_mode) {
  97         case fdc_idle:
  98                 return "fdc_idle";
  99         case fdc_reading_data:
 100                 return "fdc_reading_data";
 101         case fdc_seeking:
 102                 return "fdc_seeking";
 103         case fdc_writing_data:
 104                 return "fdc_writing_data";
 105         case fdc_reading_id:
 106                 return "fdc_reading_id";
 107         case fdc_recalibrating:
 108                 return "fdc_recalibrating";
 109         default:
 110                 return "unknown";
 111         }
 112 }
 113 
 114 static void
 115 decode_irq_cause(fdc_mode_enum fdc_mode, byte st[],
     /* [previous][next][first][last][top][bottom][index][help] */
 116                  char **fdc_mode_txt, error_cause * cause)
 117 {
 118         TRACE_FUN(8, "decode_irq_cause");
 119 
 120         /*  Valid st[], decode cause of interrupt.
 121          */
 122         *fdc_mode_txt = get_fdc_mode_text(fdc_mode);
 123         switch (st[0] & ST0_INT_MASK) {
 124         case FDC_INT_NORMAL:
 125                 TRACEx1(fdc_mode == fdc_reading_id ? 6 : 5,
 126                         "normal completion: %s", *fdc_mode_txt);
 127                 *cause = no_error;
 128                 break;
 129         case FDC_INT_ABNORMAL:
 130                 TRACEx1(5, "abnormal completion %s", *fdc_mode_txt);
 131                 TRACEx3(6, "ST0: 0x%02x, ST1: 0x%02x, ST2: 0x%02x",
 132                         st[0], st[1], st[2]);
 133                 TRACEx4(6, "C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x",
 134                         st[3], st[4], st[5], st[6]);
 135                 if (st[1] & 0x01) {
 136                         if (st[2] & 0x01) {
 137                                 *cause = data_am_error;
 138                         } else {
 139                                 *cause = id_am_error;
 140                         }
 141                 } else if (st[1] & 0x20) {
 142                         if (st[2] & 0x20) {
 143                                 *cause = data_crc_error;
 144                         } else {
 145                                 *cause = id_crc_error;
 146                         }
 147                 } else if (st[1] & 0x04) {
 148                         *cause = no_data_error;
 149                 } else if (st[1] & 0x10) {
 150                         *cause = overrun_error;
 151                 }
 152                 print_error_cause(*cause);
 153                 break;
 154         case FDC_INT_INVALID:
 155                 TRACEx1(5, "invalid completion %s", *fdc_mode_txt);
 156                 *cause = no_error;
 157                 break;
 158         case FDC_INT_READYCH:
 159                 TRACEx1(5, "ready change %s", *fdc_mode_txt);
 160                 *cause = no_error;
 161                 break;
 162         default:
 163         }
 164         TRACE_EXIT;
 165 }
 166 
 167 static void update_history(error_cause cause)
     /* [previous][next][first][last][top][bottom][index][help] */
 168 {
 169         switch (cause) {
 170         case id_am_error:
 171                 history.id_am_errors++;
 172                 break;
 173         case id_crc_error:
 174                 history.id_crc_errors++;
 175                 break;
 176         case data_am_error:
 177                 history.data_am_errors++;
 178                 break;
 179         case data_crc_error:
 180                 history.data_crc_errors++;
 181                 break;
 182         case overrun_error:
 183                 history.overrun_errors++;
 184                 break;
 185         case no_data_error:
 186                 history.no_data_errors++;
 187                 break;
 188         default:
 189         }
 190 }
 191 
 192 static void skip_bad_sector(buffer_struct * buff)
     /* [previous][next][first][last][top][bottom][index][help] */
 193 {
 194         TRACE_FUN(8, "skip_bad_sector");
 195 
 196         /* Mark sector as soft error and skip it
 197          */
 198         if (buff->remaining > 0) {
 199                 ++buff->sector_offset;
 200                 ++buff->data_offset;
 201                 --buff->remaining;
 202                 buff->ptr += SECTOR_SIZE;
 203                 buff->bad_sector_map >>= 1;
 204         } else {
 205                 ++buff->sector_offset;  /* hack for error maps */
 206                 TRACE(1, "skipping last sector in segment");
 207         }
 208         TRACE_EXIT;
 209 }
 210 
 211 static void update_error_maps(buffer_struct * buff, unsigned error_offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 212 {
 213         TRACE_FUN(8, "update_error_maps");
 214         int hard = 0;
 215 
 216         /* error_offset is a sector offset !
 217          */
 218         if (buff->retry < SOFT_RETRIES) {
 219                 buff->soft_error_map |= (1 << error_offset);
 220         } else {
 221                 buff->hard_error_map |= (1 << error_offset);
 222                 buff->soft_error_map &= ~buff->hard_error_map;
 223                 buff->retry = -1;       /* will be set to 0 in setup_segment */
 224                 hard = 1;
 225         }
 226         TRACEx2(4, "sector %d : %s error", SECTOR(error_offset),
 227                 hard ? "hard" : "soft");
 228         TRACEx2(5, "hard map: 0x%08lx, soft map: 0x%08lx",
 229                 buff->hard_error_map, buff->soft_error_map);
 230         TRACE_EXIT;
 231 }
 232 
 233 /*
 234  *  Error cause:   Amount xferred:  Action:
 235  *
 236  *  id_am_error         0           mark bad and skip
 237  *  id_crc_error        0           mark bad and skip
 238  *  data_am_error       0           mark bad and skip
 239  *  data_crc_error    % 1024        mark bad and skip
 240  *  no_data_error       0           retry on write
 241  *                                  mark bad and skip on read
 242  *  overrun_error  [ 0..all-1 ]     mark bad and skip
 243  *  no_error           all          continue
 244  */
 245 static void determine_progress(buffer_struct * buff, error_cause cause, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 246 {
 247         TRACE_FUN(8, "determine_progress");
 248         unsigned nr_not_xferred;
 249         unsigned nr_xferred;
 250         unsigned dma_residue;
 251 
 252         /*  Using less preferred order of disable_dma and get_dma_residue
 253          *  because this seems to fail on at least one system if reversed!
 254          */
 255         dma_residue = get_dma_residue(fdc.dma);
 256         disable_dma(fdc.dma);
 257         nr_xferred = buff->sector_count * SECTOR_SIZE - dma_residue;
 258         if (cause == no_error && dma_residue == 0) {
 259                 nr_not_xferred = 0;
 260         } else {
 261                 if (cause == no_error) {
 262                         TRACEx1(4, "unexpected DMA residue: 0x%04x", dma_residue);
 263                 } else {
 264                         TRACEx1(6, "DMA residue = 0x%04x", dma_residue);
 265                 }
 266                 nr_not_xferred = ((dma_residue + (SECTOR_SIZE - 1)) / SECTOR_SIZE);
 267                 buff->sector_count -= nr_not_xferred;   /* adjust to actual value */
 268         }
 269         /*  Update var's influenced by the DMA operation.
 270          */
 271         if (buff->sector_count > 0) {
 272                 buff->sector_offset += buff->sector_count;
 273                 buff->data_offset += buff->sector_count;
 274                 buff->ptr += buff->sector_count * SECTOR_SIZE;
 275                 buff->remaining -= buff->sector_count;
 276                 buff->bad_sector_map >>= buff->sector_count;
 277         }
 278         if (cause == no_error) {
 279                 TRACEx1(5, "%d Sector(s) transferred", buff->sector_count);
 280         } else if (cause == no_data_error) {
 281                 TRACEx1(5, "Sector %d not found", SECTOR(buff->sector_offset));
 282         } else if (nr_xferred > 0 || cause == id_crc_error ||
 283                    cause == id_am_error || cause == data_am_error) {
 284                 TRACEx1(5, "Error in sector %d", SECTOR(buff->sector_offset));
 285         } else if (cause == overrun_error) {
 286                 /* got an overrun error on the first byte, must be a hardware problem
 287                  */
 288                 TRACE(-1, "Unexpected error: failing DMA controller ?");
 289         } else {
 290                 TRACEx1(4, "Unexpected error at sector %d", SECTOR(buff->sector_offset));
 291         }
 292         /*  Sector_offset points to the problem area, except if we got
 293          *  a data_crc_error. In that case it points one past the failing
 294          *  sector.
 295          *  Now adjust sector_offset so it allways points one past he
 296          *  failing sector. I.e. skip the bad sector.
 297          */
 298         if (cause != no_error) {
 299                 if (cause != data_crc_error) {
 300                         skip_bad_sector(buff);
 301                 }
 302                 update_error_maps(buff, buff->sector_offset - 1);
 303         }
 304         TRACE_EXIT;
 305 }
 306 
 307 static int calc_steps(int cmd)
     /* [previous][next][first][last][top][bottom][index][help] */
 308 {
 309         if (current_cylinder > cmd) {
 310                 return current_cylinder - cmd;
 311         } else {
 312                 return current_cylinder + cmd;
 313         }
 314 }
 315 
 316 static void pause_tape(unsigned segment, int retry, int fdc_mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 317 {
 318         TRACE_FUN(8, "pause_tape");
 319         int result;
 320         /*  The 3rd initializer needs to be explicit or else gcc will
 321          *  generate a reference to memset :-(
 322          */
 323         byte out[3] =
 324         {FDC_SEEK, FTAPE_UNIT, 0};
 325 
 326         /*  We'll use a raw seek command to get the tape to rewind
 327          *  and stop for a retry.
 328          */
 329         ++history.rewinds;
 330         if (qic117_cmds[current_command].non_intr) {
 331                 TRACE(2, "motion command may be issued too soon");
 332         }
 333         if (retry && (fdc_mode == fdc_reading_data || fdc_mode == fdc_reading_id)) {
 334                 current_command = QIC_MICRO_STEP_PAUSE;
 335                 might_be_off_track = 1;
 336         } else {
 337                 current_command = QIC_PAUSE;
 338         }
 339         out[2] = calc_steps(current_command);
 340         result = fdc_command(out, 3);   /* issue QIC_117 command */
 341         if (result < 0) {
 342                 TRACEx1(4, "qic-pause failed, status = %d", result);
 343         } else {
 344                 location.known = 0;
 345                 runner_status = idle;
 346                 hide_interrupt = 1;
 347                 tape_running = 0;
 348         }
 349         TRACE_EXIT;
 350 }
 351 
 352 static void stop_tape(unsigned segment)
     /* [previous][next][first][last][top][bottom][index][help] */
 353 {
 354         TRACE_FUN(8, "stop_tape");
 355         int result;
 356         byte out[3] =
 357         {FDC_SEEK, FTAPE_UNIT, calc_steps(QIC_STOP_TAPE)};
 358 
 359         if (qic117_cmds[current_command].non_intr) {
 360                 TRACE(2, "motion command may be issued too soon");
 361         }
 362         current_command = QIC_STOP_TAPE;
 363         /*  We'll use a raw seek command to get the tape to stop
 364          */
 365         result = fdc_command(out, 3);   /* issue QIC_117 command */
 366         if (result < 0) {
 367                 TRACEx1(4, "qic-stop failed, status = %d", result);
 368         } else {
 369                 runner_status = idle;
 370                 hide_interrupt = 1;
 371                 tape_running = 0;
 372         }
 373         TRACE_EXIT;
 374 }
 375 
 376 static void continue_xfer(buffer_struct ** p_buff, error_cause cause,
     /* [previous][next][first][last][top][bottom][index][help] */
 377                           int fdc_mode, unsigned skip)
 378 {
 379         TRACE_FUN(8, "continue_xfer");
 380         buffer_struct *buff = *p_buff;
 381         int write = (fdc_mode == fdc_writing_data);
 382         byte fdc_op = (write) ? FDC_WRITE : FDC_READ;
 383 
 384         if (skip > 0) {
 385                 /* This part can be removed if it never happens
 386                  */
 387                 if (runner_status != running ||
 388                     (buff->status != (write ? writing : reading))) {
 389                         TRACEx2(1, "unexpected runner/buffer state %d/%d",
 390                                 runner_status, buff->status);
 391                         buff->status = error;
 392                         *p_buff = next_buffer(&head);   /* finish this buffer */
 393                         runner_status = aborting;
 394                         fdc_mode = fdc_idle;
 395                 }
 396         }
 397         if (buff->remaining > 0 && calc_next_cluster(&buffer[head]) > 0) {
 398                 /* still sectors left in current segment, continue with this segment
 399                  */
 400                 if (setup_fdc_and_dma(&buffer[head], fdc_op) < 0) {
 401                         /* failed, abort operation
 402                          */
 403                         buff->bytes = buff->ptr - buff->address;
 404                         buff->status = error;
 405                         buff = *p_buff = next_buffer(&head);    /* finish this buffer */
 406                         runner_status = aborting;
 407                         fdc_mode = fdc_idle;
 408                 }
 409         } else {
 410                 /* current segment completed
 411                  */
 412                 unsigned last_segment = buff->segment_id;
 413                 int eot = ((last_segment + 1) % segments_per_track) == 0;
 414                 int next = buff->next_segment;  /* 0 means stop ! */
 415 
 416                 buff->bytes = buff->ptr - buff->address;
 417                 buff->status = done;
 418                 buff = *p_buff = next_buffer(&head);
 419                 if (eot) {
 420                         /* finished last segment on current track, can't continue
 421                          */
 422                         runner_status = logical_eot;
 423                         fdc_mode = fdc_idle;
 424                 } else if (next > 0) {
 425                         /* continue with next segment
 426                          */
 427                         if (buff->status == waiting) {
 428                                 if (write && next != buff->segment_id) {
 429                                         TRACE(5, "segments out of order, aborting write");
 430                                         runner_status = do_abort;
 431                                         fdc_mode = fdc_idle;
 432                                 } else {
 433                                         setup_new_segment(&buffer[head], next, 0);
 434                                         if (stop_read_ahead) {
 435                                                 buff->next_segment = 0;
 436                                                 stop_read_ahead = 0;
 437                                         }
 438                                         if (calc_next_cluster(&buffer[head]) == 0 ||
 439                                             setup_fdc_and_dma(&buffer[head], fdc_op) != 0) {
 440                                                 TRACEx1(1, "couldn't start %s-ahead", (write) ? "write" : "read");
 441                                                 runner_status = do_abort;
 442                                                 fdc_mode = fdc_idle;
 443                                         } else {
 444                                                 buff->status = (write) ? writing : reading;     /* keep on going */
 445                                         }
 446                                 }
 447                         } else {
 448                                 TRACEx1(5, "all input buffers %s, pausing tape",
 449                                         (write) ? "empty" : "full");
 450                                 pause_tape(last_segment, 0, fdc_mode);
 451                                 runner_status = idle;   /* not quite true until next irq */
 452                         }
 453                 } else {
 454                         /* don't continue with next segment
 455                          */
 456                         TRACEx1(5, "no %s allowed, stopping tape",
 457                                 (write) ? "write next" : "read ahead");
 458                         if (random_rw) {
 459                                 stop_tape(last_segment);
 460                         } else {
 461                                 pause_tape(last_segment, 0, fdc_mode);
 462                         }
 463                         runner_status = idle;   /* not quite true until next irq */
 464                 }
 465         }
 466         TRACE_EXIT;
 467         return;
 468 }
 469 
 470 static void
 471 retry_sector(buffer_struct ** p_buff, error_cause cause, int fdc_mode,
     /* [previous][next][first][last][top][bottom][index][help] */
 472              unsigned skip)
 473 {
 474         TRACE_FUN(8, "retry_sector");
 475         buffer_struct *buff = *p_buff;
 476 
 477         TRACEx1(4, "%s error, will retry",
 478                 (fdc_mode == fdc_writing_data) ? "write" : "read");
 479         pause_tape(buff->segment_id, 1, fdc_mode);
 480         runner_status = aborting;
 481         buff->status = error;
 482         buff->skip = skip;
 483         TRACE_EXIT;
 484 }
 485 
 486 static unsigned
 487 find_resume_point(buffer_struct * buff)
     /* [previous][next][first][last][top][bottom][index][help] */
 488 {
 489         TRACE_FUN(8, "find_resume_point");
 490         int i = 0;
 491         unsigned long mask;
 492         unsigned long map;
 493 
 494         /*  This function is to be called after all variables have been
 495          *  updated to point past the failing sector.
 496          *  If there are any soft errors before the failing sector,
 497          *  find the first soft error and return the sector offset.
 498          *  Otherwise find the last hard error.
 499          *  Note: there should allways be at least one hard or soft error !
 500          */
 501         if (buff->sector_offset < 1 || buff->sector_offset > 32) {
 502                 TRACEx1(1, "bug: sector_offset = %d", buff->sector_offset);
 503         } else {
 504                 if (buff->sector_offset >= 32) {        /* C-limitation on shift ! */
 505                         mask = 0xffffffff;
 506                 } else {
 507                         mask = (1 << buff->sector_offset) - 1;
 508                 }
 509                 map = buff->soft_error_map & mask;
 510                 if (map) {
 511                         while ((map & (1 << i)) == 0) {
 512                                 ++i;
 513                         }
 514                         TRACEx1(4, "at sector %d", SECTOR(i));
 515                 } else {
 516                         map = buff->hard_error_map & mask;
 517                         i = buff->sector_offset - 1;
 518                         if (map) {
 519                                 while ((map & (1 << i)) == 0) {
 520                                         --i;
 521                                 }
 522                                 TRACEx1(4, "after sector %d", SECTOR(i));
 523                                 ++i;    /* first sector after last hard error */
 524                         } else {
 525                                 TRACE(1, "bug: no soft or hard errors");
 526                         }
 527                 }
 528         }
 529         TRACE_EXIT;
 530         return i;
 531 }
 532 
 533 /*      FDC interrupt service routine.
 534  */
 535 void
 536 fdc_isr(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 537 {
 538         TRACE_FUN(8, "fdc_isr");
 539         int result;
 540         int status;
 541         error_cause cause = no_error;
 542         byte in[7];
 543         static int isr_active = 0;
 544         int t0;
 545         buffer_struct *buff = &buffer[head];
 546         int skip;
 547 
 548         t0 = timestamp();
 549         if (isr_active) {
 550                 TRACE(-1, "nested interrupt, not good !");
 551                 *fdc.hook = fdc_isr;    /* hook our handler into the fdc code again */
 552                 TRACE_EXIT;
 553                 return;
 554         }
 555         ++isr_active;
 556         sti();                  /* enables interrupts again */
 557         status = inb_p(fdc.msr);
 558         if (status & FDC_BUSY) {        /*  Entering Result Phase */
 559                 hide_interrupt = 0;
 560                 result = fdc_result(in, 7);     /* better get it fast ! */
 561                 if (result < 0) {
 562                         /*  Entered unknown state...
 563                          */
 564                         TRACE(1, "probably fatal error during FDC Result Phase");
 565                         TRACE(1, "drive may hang until (power) reset :-(");
 566                         /*  what to do next ????
 567                          */
 568                 } else {
 569                         int i;
 570                         char *fdc_mode_txt;
 571 
 572                         decode_irq_cause(fdc_mode, in, &fdc_mode_txt, &cause);
 573                         for (i = 0; i < NR_BUFFERS; ++i) {
 574                                 TRACEx3(8, "buffer[%d] status: %d, segment_id: %d",
 575                                         i, buffer[i].status, buffer[i].segment_id);
 576                         }
 577                         switch (fdc_mode) {
 578 
 579                         case fdc_reading_data:{
 580 
 581                                         if (cause == no_error) {
 582                                                 TRACEi(5, "reading segment", buff->segment_id);
 583                                         } else {
 584                                                 TRACEi(4, "error reading segment", buff->segment_id);
 585                                         }
 586                                         if (runner_status == aborting || runner_status == do_abort) {
 587                                                 TRACEx1(4, "aborting %s", fdc_mode_txt);
 588                                                 break;
 589                                         }
 590                                         if (buff->retry > 0) {
 591                                                 TRACEx1(5, "this is retry nr %d", buff->retry);
 592                                         }
 593                                         if (buff->bad_sector_map == FAKE_SEGMENT) {
 594                                                 /* This condition occurs when reading a `fake' sector that's
 595                                                  * not accessible. Doesn't really matter as we would have
 596                                                  * ignored it anyway !
 597                                                  * Chance is that we're past the next segment now, so the
 598                                                  * next operation may fail and result in a retry.
 599                                                  */
 600                                                 TRACE(4, "skipping empty segment (read)");
 601                                                 buff->remaining = 0;    /* skip failing sector */
 602                                                 continue_xfer(&buff, no_error, fdc_mode, 1);    /* fake success */
 603                                         } else {
 604                                                 switch (cause) {
 605                                                 case no_error:{
 606                                                                 determine_progress(buff, cause, fdc_reading_data);
 607                                                                 if (in[2] & 0x40) {
 608                                                                         /*  Handle deleted data in header segments.
 609                                                                          *  Skip segment and force read-ahead.
 610                                                                          */
 611                                                                         TRACEx1(2, "deleted data in sector %d",
 612                                                                                 SECTOR(buff->sector_offset - 1));
 613                                                                         buff->deleted = 1;
 614                                                                         buff->remaining = 0;    /* abort transfer */
 615                                                                         buff->soft_error_map |= (-1L << buff->sector_offset);
 616                                                                         if (buff->segment_id == 0) {
 617                                                                                 stop_read_ahead = 1;    /* stop on next segment */
 618                                                                         }
 619                                                                         buff->next_segment = buff->segment_id + 1;      /* force read-ahead */
 620                                                                         skip = (SECTORS_PER_SEGMENT - buff->sector_offset);
 621                                                                 } else {
 622                                                                         skip = 0;
 623                                                                 }
 624                                                                 continue_xfer(&buff, cause, fdc_mode, skip);
 625                                                                 break;
 626                                                         }
 627                                                 case no_data_error:
 628                                                         /*  Tape started too far ahead of or behind the right sector.
 629                                                          *  This may also happen in the middle of a segment !
 630                                                          *  Handle no-data as soft error. If next sector fails too,
 631                                                          *  a retry (with needed reposition) will follow.
 632                                                          */
 633                                                 case id_am_error:
 634                                                 case id_crc_error:
 635                                                 case data_am_error:
 636                                                 case data_crc_error:
 637                                                 case overrun_error:{
 638                                                                 int first_error = (buff->soft_error_map == 0 &&
 639                                                                                    buff->hard_error_map == 0);
 640 
 641                                                                 update_history(cause);
 642                                                                 determine_progress(buff, cause, fdc_reading_data);
 643                                                                 if (first_error) {
 644                                                                         skip = buff->sector_offset;
 645                                                                 } else {
 646                                                                         skip = find_resume_point(buff);
 647                                                                 }
 648                                                                 /*  Try to resume with next sector on single errors (let ecc
 649                                                                  *  correct it), but retry on no_data (we'll be past the
 650                                                                  *  target when we get here so we cannot retry) or on multiple
 651                                                                  *  errors (reduce chance on ecc failure).
 652                                                                  */
 653                                                                 if (first_error && cause != no_data_error) {
 654                                                                         continue_xfer(&buff, cause, fdc_mode, skip);
 655                                                                 } else {
 656                                                                         retry_sector(&buff, cause, fdc_mode, skip);
 657                                                                 }
 658                                                                 break;
 659                                                         }
 660                                                 default:{
 661                                                                 /*  Don't know why this could happen but find out.
 662                                                                  */
 663                                                                 TRACE(1, "unexpected error");
 664                                                                 determine_progress(buff, cause, fdc_reading_data);
 665                                                                 retry_sector(&buff, cause, fdc_mode, 0);
 666                                                                 break;
 667                                                         }
 668                                                 }
 669                                         }
 670                                         break;
 671                                 }
 672 
 673                         case fdc_reading_id:{
 674 
 675                                         if (cause == no_error) {
 676                                                 fdc_cyl = in[3];
 677                                                 fdc_head = in[4];
 678                                                 fdc_sect = in[5];
 679                                                 TRACEx3(6, "id read: C: 0x%02x, H: 0x%02x, R: 0x%02x",
 680                                                         fdc_cyl, fdc_head, fdc_sect);
 681                                         } else {        /* no valid information, use invalid sector */
 682                                                 fdc_cyl =
 683                                                     fdc_head =
 684                                                     fdc_sect = 0;
 685                                                 TRACE(5, "Didn't find valid sector Id");
 686                                         }
 687                                         fdc_mode = fdc_idle;
 688                                         break;
 689                                 }
 690 
 691                         case fdc_writing_data:{
 692 
 693                                         if (cause == no_error) {
 694                                                 TRACEi(5, "writing segment", buff->segment_id);
 695                                         } else {
 696                                                 TRACEi(4, "error writing segment", buff->segment_id);
 697                                         }
 698                                         if (runner_status == aborting || runner_status == do_abort) {
 699                                                 TRACEx1(5, "aborting %s", fdc_mode_txt);
 700                                                 break;
 701                                         }
 702                                         if (buff->retry > 0) {
 703                                                 TRACEx1(5, "this is retry nr %d", buff->retry);
 704                                         }
 705                                         if (buff->bad_sector_map == FAKE_SEGMENT) {
 706                                                 /* This condition occurs when trying to write to a `fake'
 707                                                  * sector that's not accessible. Doesn't really matter as
 708                                                  * it isn't used anyway ! Might be located at wrong segment,
 709                                                  * then we'll fail on the next segment.
 710                                                  */
 711                                                 TRACE(4, "skipping empty segment (write)");
 712                                                 buff->remaining = 0;    /* skip failing sector */
 713                                                 continue_xfer(&buff, no_error, fdc_mode, 1);    /* fake success */
 714                                         } else {
 715                                                 switch (cause) {
 716                                                 case no_error:{
 717                                                                 determine_progress(buff, cause, fdc_writing_data);
 718                                                                 continue_xfer(&buff, cause, fdc_mode, 0);
 719                                                                 break;
 720                                                         }
 721                                                 case no_data_error:
 722                                                 case id_am_error:
 723                                                 case id_crc_error:
 724                                                 case data_am_error:
 725                                                 case overrun_error:{
 726                                                                 update_history(cause);
 727                                                                 determine_progress(buff, cause, fdc_writing_data);
 728                                                                 skip = find_resume_point(buff);
 729                                                                 retry_sector(&buff, cause, fdc_mode, skip);
 730                                                                 break;
 731                                                         }
 732                                                 default:{
 733                                                                 if (in[1] & 0x02) {
 734                                                                         TRACE(1, "media not writable");
 735                                                                 } else {
 736                                                                         TRACE(-1, "unforseen write error");
 737                                                                 }
 738                                                                 fdc_mode = fdc_idle;
 739                                                                 break;
 740                                                         }
 741                                                 }
 742                                         }
 743                                         break;
 744                                 }
 745                         default:
 746 
 747                                 TRACEx1(1, "Warning: unexpected irq during: %s",
 748                                         fdc_mode_txt);
 749                                 fdc_mode = fdc_idle;
 750                                 break;
 751                         }
 752                 }
 753                 if (runner_status == do_abort) {
 754                         /*      cease operation, remember tape position
 755                          */
 756                         TRACE(5, "runner aborting");
 757                         runner_status = aborting;
 758                         ++expected_stray_interrupts;
 759                 }
 760         } else { /* !FDC_BUSY  */
 761                 /*  clear interrupt, cause should be gotten by issueing
 762                  *  a Sense Interrupt Status command.
 763                  */
 764                 if (fdc_mode == fdc_recalibrating || fdc_mode == fdc_seeking) {
 765                         if (hide_interrupt) {
 766                                 int st0;
 767                                 int pcn;
 768 
 769                                 result = fdc_sense_interrupt_status(&st0, &pcn);
 770                                 current_cylinder = pcn;
 771                                 TRACE(5, "handled hidden interrupt");
 772                         }
 773                         seek_completed = 1;
 774                         fdc_mode = fdc_idle;
 775                 } else if (!wait_intr) {
 776                         if (expected_stray_interrupts == 0) {
 777                                 TRACE(2, "unexpected stray interrupt");
 778                         } else {
 779                                 TRACE(5, "expected stray interrupt");
 780                                 --expected_stray_interrupts;
 781                         }
 782                 } else {
 783                         if (fdc_mode == fdc_reading_data || fdc_mode == fdc_writing_data ||
 784                             fdc_mode == fdc_reading_id) {
 785                                 byte status = inb_p(fdc.msr);
 786                                 if (status & FDC_BUSY) {
 787                                         TRACE(-1, "***** FDC failure, busy too late");
 788                                 } else {
 789                                         TRACE(-1, "***** FDC failure, no busy");
 790                                 }
 791                         } else {
 792                                 TRACE(6, "awaited stray interrupt");
 793                         }
 794                 }
 795                 hide_interrupt = 0;
 796         }
 797         /*    Handle sleep code.
 798          */
 799         if (!hide_interrupt) {
 800                 ++interrupt_seen;
 801                 if (wait_intr) {
 802                         wake_up_interruptible(&wait_intr);
 803                 }
 804         } else {
 805                 TRACEx1(5, "hiding interrupt while %s", wait_intr ? "waiting" : "active");
 806         }
 807         t0 = timediff(t0, timestamp());
 808         if (t0 >= 1000) {       /* only tell us about long calls */
 809                 TRACEx1(7, "isr() duration: %5d usec", t0);
 810         }
 811         *fdc.hook = fdc_isr;    /* hook our handler into the fdc code again */
 812         TRACE_EXIT;
 813         --isr_active;
 814 }

/* [previous][next][first][last][top][bottom][index][help] */