linux-old/drivers/char/ftape/lowlevel/fdc-isr.c
<<
>>
Prefs
   1/*
   2 *      Copyright (C) 1994-1996 Bas Laarhoven,
   3 *                (C) 1996-1997 Claus-Justus Heine.
   4
   5 This program is free software; you can redistribute it and/or modify
   6 it under the terms of the GNU General Public License as published by
   7 the Free Software Foundation; either version 2, or (at your option)
   8 any later version.
   9
  10 This program is distributed in the hope that it will be useful,
  11 but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 GNU General Public License for more details.
  14
  15 You should have received a copy of the GNU General Public License
  16 along with this program; see the file COPYING.  If not, write to
  17 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  18
  19 *
  20 * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-isr.c,v $
  21 * $Revision: 1.9 $
  22 * $Date: 1997/10/17 23:01:53 $
  23 *
  24 *      This file contains the interrupt service routine and
  25 *      associated code for the QIC-40/80/3010/3020 floppy-tape driver
  26 *      "ftape" for Linux.
  27 */
  28
  29#include <asm/io.h>
  30#include <asm/dma.h>
  31
  32#define volatile                /* */
  33
  34#include <linux/ftape.h>
  35#include <linux/qic117.h>
  36#include "../lowlevel/ftape-tracing.h"
  37#include "../lowlevel/fdc-isr.h"
  38#include "../lowlevel/fdc-io.h"
  39#include "../lowlevel/ftape-ctl.h"
  40#include "../lowlevel/ftape-rw.h"
  41#include "../lowlevel/ftape-io.h"
  42#include "../lowlevel/ftape-calibr.h"
  43#include "../lowlevel/ftape-bsm.h"
  44
  45/*      Global vars.
  46 */
  47volatile int ft_expected_stray_interrupts;
  48volatile int ft_interrupt_seen;
  49volatile int ft_seek_completed;
  50volatile int ft_hide_interrupt;
  51/*      Local vars.
  52 */
  53typedef enum {
  54        no_error = 0, id_am_error = 0x01, id_crc_error = 0x02,
  55        data_am_error = 0x04, data_crc_error = 0x08,
  56        no_data_error = 0x10, overrun_error = 0x20,
  57} error_cause;
  58static int stop_read_ahead;
  59
  60
  61static void print_error_cause(int cause)
  62{
  63        TRACE_FUN(ft_t_any);
  64
  65        switch (cause) {
  66        case no_data_error:
  67                TRACE(ft_t_noise, "no data error");
  68                break;
  69        case id_am_error:
  70                TRACE(ft_t_noise, "id am error");
  71                break;
  72        case id_crc_error:
  73                TRACE(ft_t_noise, "id crc error");
  74                break;
  75        case data_am_error:
  76                TRACE(ft_t_noise, "data am error");
  77                break;
  78        case data_crc_error:
  79                TRACE(ft_t_noise, "data crc error");
  80                break;
  81        case overrun_error:
  82                TRACE(ft_t_noise, "overrun error");
  83                break;
  84        default:;
  85        }
  86        TRACE_EXIT;
  87}
  88
  89static char *fdc_mode_txt(fdc_mode_enum mode)
  90{
  91        switch (mode) {
  92        case fdc_idle:
  93                return "fdc_idle";
  94        case fdc_reading_data:
  95                return "fdc_reading_data";
  96        case fdc_seeking:
  97                return "fdc_seeking";
  98        case fdc_writing_data:
  99                return "fdc_writing_data";
 100        case fdc_reading_id:
 101                return "fdc_reading_id";
 102        case fdc_recalibrating:
 103                return "fdc_recalibrating";
 104        case fdc_formatting:
 105                return "fdc_formatting";
 106        case fdc_verifying:
 107                return "fdc_verifying";
 108        default:
 109                return "unknown";
 110        }
 111}
 112
 113static inline error_cause decode_irq_cause(fdc_mode_enum mode, __u8 st[])
 114{
 115        error_cause cause = no_error;
 116        TRACE_FUN(ft_t_any);
 117
 118        /*  Valid st[], decode cause of interrupt.
 119         */
 120        switch (st[0] & ST0_INT_MASK) {
 121        case FDC_INT_NORMAL:
 122                TRACE(ft_t_fdc_dma,"normal completion: %s",fdc_mode_txt(mode));
 123                break;
 124        case FDC_INT_ABNORMAL:
 125                TRACE(ft_t_flow, "abnormal completion %s", fdc_mode_txt(mode));
 126                TRACE(ft_t_fdc_dma, "ST0: 0x%02x, ST1: 0x%02x, ST2: 0x%02x",
 127                      st[0], st[1], st[2]);
 128                TRACE(ft_t_fdc_dma,
 129                      "C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x",
 130                      st[3], st[4], st[5], st[6]);
 131                if (st[1] & 0x01) {
 132                        if (st[2] & 0x01) {
 133                                cause = data_am_error;
 134                        } else {
 135                                cause = id_am_error;
 136                        }
 137                } else if (st[1] & 0x20) {
 138                        if (st[2] & 0x20) {
 139                                cause = data_crc_error;
 140                        } else {
 141                                cause = id_crc_error;
 142                        }
 143                } else if (st[1] & 0x04) {
 144                        cause = no_data_error;
 145                } else if (st[1] & 0x10) {
 146                        cause = overrun_error;
 147                }
 148                print_error_cause(cause);
 149                break;
 150        case FDC_INT_INVALID:
 151                TRACE(ft_t_flow, "invalid completion %s", fdc_mode_txt(mode));
 152                break;
 153        case FDC_INT_READYCH:
 154                if (st[0] & ST0_SEEK_END) {
 155                        TRACE(ft_t_flow, "drive poll completed");
 156                } else {
 157                        TRACE(ft_t_flow, "ready change %s",fdc_mode_txt(mode));
 158                }
 159                break;
 160        default:
 161                break;
 162        }
 163        TRACE_EXIT cause;
 164}
 165
 166static void update_history(error_cause cause)
 167{
 168        switch (cause) {
 169        case id_am_error:
 170                ft_history.id_am_errors++;
 171                break;
 172        case id_crc_error:
 173                ft_history.id_crc_errors++;
 174                break;
 175        case data_am_error:
 176                ft_history.data_am_errors++;
 177                break;
 178        case data_crc_error:
 179                ft_history.data_crc_errors++;
 180                break;
 181        case overrun_error:
 182                ft_history.overrun_errors++;
 183                break;
 184        case no_data_error:
 185                ft_history.no_data_errors++;
 186                break;
 187        default:;
 188        }
 189}
 190
 191static void skip_bad_sector(buffer_struct * buff)
 192{
 193        TRACE_FUN(ft_t_any);
 194
 195        /*  Mark sector as soft error and skip it
 196         */
 197        if (buff->remaining > 0) {
 198                ++buff->sector_offset;
 199                ++buff->data_offset;
 200                --buff->remaining;
 201                buff->ptr += FT_SECTOR_SIZE;
 202                buff->bad_sector_map >>= 1;
 203        } else {
 204                /*  Hey, what is this????????????? C code: if we shift 
 205                 *  more than 31 bits, we get no shift. That's bad!!!!!!
 206                 */
 207                ++buff->sector_offset;  /* hack for error maps */
 208                TRACE(ft_t_warn, "skipping last sector in segment");
 209        }
 210        TRACE_EXIT;
 211}
 212
 213static void update_error_maps(buffer_struct * buff, unsigned int error_offset)
 214{
 215        int hard = 0;
 216        TRACE_FUN(ft_t_any);
 217
 218        if (buff->retry < FT_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        TRACE(ft_t_noise, "sector %d : %s error\n"
 227              KERN_INFO "hard map: 0x%08lx\n"
 228              KERN_INFO "soft map: 0x%08lx",
 229              FT_SECTOR(error_offset), hard ? "hard" : "soft",
 230              (long) buff->hard_error_map, (long) buff->soft_error_map);
 231        TRACE_EXIT;
 232}
 233
 234static void print_progress(buffer_struct *buff, error_cause cause)
 235{
 236        TRACE_FUN(ft_t_any);
 237
 238        switch (cause) {
 239        case no_error: 
 240                TRACE(ft_t_flow,"%d Sector(s) transferred", buff->sector_count);
 241                break;
 242        case no_data_error:
 243                TRACE(ft_t_flow, "Sector %d not found",
 244                      FT_SECTOR(buff->sector_offset));
 245                break;
 246        case overrun_error:
 247                /*  got an overrun error on the first byte, must be a
 248                 *  hardware problem
 249                 */
 250                TRACE(ft_t_bug,
 251                      "Unexpected error: failing DMA or FDC controller ?");
 252                break;
 253        case data_crc_error:
 254                TRACE(ft_t_flow, "Error in sector %d",
 255                      FT_SECTOR(buff->sector_offset - 1));
 256                break;
 257        case id_crc_error:
 258        case id_am_error:
 259        case data_am_error:
 260                TRACE(ft_t_flow, "Error in sector %d",
 261                      FT_SECTOR(buff->sector_offset));
 262                break;
 263        default:
 264                TRACE(ft_t_flow, "Unexpected error at sector %d",
 265                      FT_SECTOR(buff->sector_offset));
 266                break;
 267        }
 268        TRACE_EXIT;
 269}
 270
 271/*
 272 *  Error cause:   Amount xferred:  Action:
 273 *
 274 *  id_am_error         0           mark bad and skip
 275 *  id_crc_error        0           mark bad and skip
 276 *  data_am_error       0           mark bad and skip
 277 *  data_crc_error    % 1024        mark bad and skip
 278 *  no_data_error       0           retry on write
 279 *                                  mark bad and skip on read
 280 *  overrun_error  [ 0..all-1 ]     mark bad and skip
 281 *  no_error           all          continue
 282 */
 283
 284/*  the arg `sector' is returned by the fdc and tells us at which sector we
 285 *  are positioned at (relative to starting sector of segment)
 286 */
 287static void determine_verify_progress(buffer_struct *buff,
 288                                      error_cause cause,
 289                                      __u8 sector)
 290{
 291        TRACE_FUN(ft_t_any);
 292
 293        if (cause == no_error && sector == 1) {
 294                buff->sector_offset = FT_SECTORS_PER_SEGMENT;
 295                buff->remaining     = 0;
 296                if (TRACE_LEVEL >= ft_t_flow) {
 297                        print_progress(buff, cause);
 298                }
 299        } else {
 300                buff->sector_offset = sector - buff->sect;
 301                buff->remaining = FT_SECTORS_PER_SEGMENT - buff->sector_offset;
 302                TRACE(ft_t_noise, "%ssector offset: 0x%04x", 
 303                      (cause == no_error) ? "unexpected " : "",
 304                      buff->sector_offset);
 305                switch (cause) {
 306                case overrun_error:
 307                        break;
 308#if 0
 309                case no_data_error:
 310                        buff->retry = FT_SOFT_RETRIES;
 311                        if (buff->hard_error_map    &&
 312                            buff->sector_offset > 1 &&
 313                            (buff->hard_error_map & 
 314                             (1 << (buff->sector_offset-2)))) {
 315                                buff->retry --;
 316                        }
 317                        break;
 318#endif
 319                default:
 320                        buff->retry = FT_SOFT_RETRIES;
 321                        break;
 322                }
 323                if (TRACE_LEVEL >= ft_t_flow) {
 324                        print_progress(buff, cause);
 325                }
 326                /*  Sector_offset points to the problem area Now adjust
 327                 *  sector_offset so it always points one past he failing
 328                 *  sector. I.e. skip the bad sector.
 329                 */
 330                ++buff->sector_offset;
 331                --buff->remaining;
 332                update_error_maps(buff, buff->sector_offset - 1);
 333        }
 334        TRACE_EXIT;
 335}
 336
 337static void determine_progress(buffer_struct *buff,
 338                               error_cause cause,
 339                               __u8 sector)
 340{
 341        unsigned int dma_residue;
 342        TRACE_FUN(ft_t_any);
 343
 344        /*  Using less preferred order of disable_dma and
 345         *  get_dma_residue because this seems to fail on at least one
 346         *  system if reversed!
 347         */
 348        dma_residue = get_dma_residue(fdc.dma);
 349        disable_dma(fdc.dma);
 350        if (cause != no_error || dma_residue != 0) {
 351                TRACE(ft_t_noise, "%sDMA residue: 0x%04x", 
 352                      (cause == no_error) ? "unexpected " : "",
 353                      dma_residue);
 354                /* adjust to actual value: */
 355                if (dma_residue == 0) {
 356                        /* this happens sometimes with overrun errors.
 357                         * I don't know whether we could ignore the
 358                         * overrun error. Play save.
 359                         */
 360                        buff->sector_count --;
 361                } else {
 362                        buff->sector_count -= ((dma_residue + 
 363                                                (FT_SECTOR_SIZE - 1)) /
 364                                               FT_SECTOR_SIZE);
 365                }
 366        }
 367        /*  Update var's influenced by the DMA operation.
 368         */
 369        if (buff->sector_count > 0) {
 370                buff->sector_offset   += buff->sector_count;
 371                buff->data_offset     += buff->sector_count;
 372                buff->ptr             += (buff->sector_count *
 373                                          FT_SECTOR_SIZE);
 374                buff->remaining       -= buff->sector_count;
 375                buff->bad_sector_map >>= buff->sector_count;
 376        }
 377        if (TRACE_LEVEL >= ft_t_flow) {
 378                print_progress(buff, cause);
 379        }
 380        if (cause != no_error) {
 381                if (buff->remaining == 0) {
 382                        TRACE(ft_t_warn, "foo?\n"
 383                              KERN_INFO "count : %d\n"
 384                              KERN_INFO "offset: %d\n"
 385                              KERN_INFO "soft  : %08x\n"
 386                              KERN_INFO "hard  : %08x",
 387                              buff->sector_count,
 388                              buff->sector_offset,
 389                              buff->soft_error_map,
 390                              buff->hard_error_map);
 391                }
 392                /*  Sector_offset points to the problem area, except if we got
 393                 *  a data_crc_error. In that case it points one past the
 394                 *  failing sector.
 395                 *
 396                 *  Now adjust sector_offset so it always points one past he
 397                 *  failing sector. I.e. skip the bad sector.  
 398                 */
 399                if (cause != data_crc_error) {
 400                        skip_bad_sector(buff);
 401                }
 402                update_error_maps(buff, buff->sector_offset - 1);
 403        }
 404        TRACE_EXIT;
 405}
 406
 407static int calc_steps(int cmd)
 408{
 409        if (ftape_current_cylinder > cmd) {
 410                return ftape_current_cylinder - cmd;
 411        } else {
 412                return ftape_current_cylinder + cmd;
 413        }
 414}
 415
 416static void pause_tape(int retry, int mode)
 417{
 418        int result;
 419        __u8 out[3] = {FDC_SEEK, ft_drive_sel, 0};
 420        TRACE_FUN(ft_t_any);
 421
 422        /*  We'll use a raw seek command to get the tape to rewind and
 423         *  stop for a retry.
 424         */
 425        ++ft_history.rewinds;
 426        if (qic117_cmds[ftape_current_command].non_intr) {
 427                TRACE(ft_t_warn, "motion command may be issued too soon");
 428        }
 429        if (retry && (mode == fdc_reading_data ||
 430                      mode == fdc_reading_id   ||
 431                      mode == fdc_verifying)) {
 432                ftape_current_command = QIC_MICRO_STEP_PAUSE;
 433                ftape_might_be_off_track = 1;
 434        } else {
 435                ftape_current_command = QIC_PAUSE;
 436        }
 437        out[2] = calc_steps(ftape_current_command);
 438        result = fdc_command(out, 3); /* issue QIC_117 command */
 439        ftape_current_cylinder = out[ 2];
 440        if (result < 0) {
 441                TRACE(ft_t_noise, "qic-pause failed, status = %d", result);
 442        } else {
 443                ft_location.known  = 0;
 444                ft_runner_status   = idle;
 445                ft_hide_interrupt     = 1;
 446                ftape_tape_running = 0;
 447        }
 448        TRACE_EXIT;
 449}
 450
 451static void continue_xfer(buffer_struct *buff,
 452                          fdc_mode_enum mode, 
 453                          unsigned int skip)
 454{
 455        int write = 0;
 456        TRACE_FUN(ft_t_any);
 457
 458        if (mode == fdc_writing_data || mode == fdc_deleting) {
 459                write = 1;
 460        }
 461        /*  This part can be removed if it never happens
 462         */
 463        if (skip > 0 &&
 464            (ft_runner_status != running ||
 465             (write && (buff->status != writing)) ||
 466             (!write && (buff->status != reading && 
 467                         buff->status != verifying)))) {
 468                TRACE(ft_t_err, "unexpected runner/buffer state %d/%d",
 469                      ft_runner_status, buff->status);
 470                buff->status = error;
 471                /* finish this buffer: */
 472                (void)ftape_next_buffer(ft_queue_head);
 473                ft_runner_status = aborting;
 474                fdc_mode         = fdc_idle;
 475        } else if (buff->remaining > 0 && ftape_calc_next_cluster(buff) > 0) {
 476                /*  still sectors left in current segment, continue
 477                 *  with this segment
 478                 */
 479                if (fdc_setup_read_write(buff, mode) < 0) {
 480                        /* failed, abort operation
 481                         */
 482                        buff->bytes = buff->ptr - buff->address;
 483                        buff->status = error;
 484                        /* finish this buffer: */
 485                        (void)ftape_next_buffer(ft_queue_head);
 486                        ft_runner_status = aborting;
 487                        fdc_mode         = fdc_idle;
 488                }
 489        } else {
 490                /* current segment completed
 491                 */
 492                unsigned int last_segment = buff->segment_id;
 493                int eot = ((last_segment + 1) % ft_segments_per_track) == 0;
 494                unsigned int next = buff->next_segment; /* 0 means stop ! */
 495
 496                buff->bytes = buff->ptr - buff->address;
 497                buff->status = done;
 498                buff = ftape_next_buffer(ft_queue_head);
 499                if (eot) {
 500                        /*  finished last segment on current track,
 501                         *  can't continue
 502                         */
 503                        ft_runner_status = logical_eot;
 504                        fdc_mode         = fdc_idle;
 505                        TRACE_EXIT;
 506                }
 507                if (next <= 0) {
 508                        /*  don't continue with next segment
 509                         */
 510                        TRACE(ft_t_noise, "no %s allowed, stopping tape",
 511                              (write) ? "write next" : "read ahead");
 512                        pause_tape(0, mode);
 513                        ft_runner_status = idle;  /*  not quite true until
 514                                                   *  next irq 
 515                                                   */
 516                        TRACE_EXIT;
 517                }
 518                /*  continue with next segment
 519                 */
 520                if (buff->status != waiting) {
 521                        TRACE(ft_t_noise, "all input buffers %s, pausing tape",
 522                              (write) ? "empty" : "full");
 523                        pause_tape(0, mode);
 524                        ft_runner_status = idle;  /*  not quite true until
 525                                                   *  next irq 
 526                                                   */
 527                        TRACE_EXIT;
 528                }
 529                if (write && next != buff->segment_id) {
 530                        TRACE(ft_t_noise, 
 531                              "segments out of order, aborting write");
 532                        ft_runner_status = do_abort;
 533                        fdc_mode         = fdc_idle;
 534                        TRACE_EXIT;
 535                }
 536                ftape_setup_new_segment(buff, next, 0);
 537                if (stop_read_ahead) {
 538                        buff->next_segment = 0;
 539                        stop_read_ahead = 0;
 540                }
 541                if (ftape_calc_next_cluster(buff) == 0 ||
 542                    fdc_setup_read_write(buff, mode) != 0) {
 543                        TRACE(ft_t_err, "couldn't start %s-ahead",
 544                              write ? "write" : "read");
 545                        ft_runner_status = do_abort;
 546                        fdc_mode         = fdc_idle;
 547                } else {
 548                        /* keep on going */
 549                        switch (ft_driver_state) {
 550                        case   reading: buff->status = reading;   break;
 551                        case verifying: buff->status = verifying; break;
 552                        case   writing: buff->status = writing;   break;
 553                        case  deleting: buff->status = deleting;  break;
 554                        default:
 555                                TRACE(ft_t_err, 
 556                      "BUG: ft_driver_state %d should be one out of "
 557                      "{reading, writing, verifying, deleting}",
 558                                      ft_driver_state);
 559                                buff->status = write ? writing : reading;
 560                                break;
 561                        }
 562                }
 563        }
 564        TRACE_EXIT;
 565}
 566
 567static void retry_sector(buffer_struct *buff, 
 568                         int mode,
 569                         unsigned int skip)
 570{
 571        TRACE_FUN(ft_t_any);
 572
 573        TRACE(ft_t_noise, "%s error, will retry",
 574              (mode == fdc_writing_data || mode == fdc_deleting) ? "write" : "read");
 575        pause_tape(1, mode);
 576        ft_runner_status = aborting;
 577        buff->status     = error;
 578        buff->skip       = skip;
 579        TRACE_EXIT;
 580}
 581
 582static unsigned int find_resume_point(buffer_struct *buff)
 583{
 584        int i = 0;
 585        SectorMap mask;
 586        SectorMap map;
 587        TRACE_FUN(ft_t_any);
 588
 589        /*  This function is to be called after all variables have been
 590         *  updated to point past the failing sector.
 591         *  If there are any soft errors before the failing sector,
 592         *  find the first soft error and return the sector offset.
 593         *  Otherwise find the last hard error.
 594         *  Note: there should always be at least one hard or soft error !
 595         */
 596        if (buff->sector_offset < 1 || buff->sector_offset > 32) {
 597                TRACE(ft_t_bug, "BUG: sector_offset = %d",
 598                      buff->sector_offset);
 599                TRACE_EXIT 0;
 600        }
 601        if (buff->sector_offset >= 32) { /* C-limitation on shift ! */
 602                mask = 0xffffffff;
 603        } else {
 604                mask = (1 << buff->sector_offset) - 1;
 605        }
 606        map = buff->soft_error_map & mask;
 607        if (map) {
 608                while ((map & (1 << i)) == 0) {
 609                        ++i;
 610                }
 611                TRACE(ft_t_noise, "at sector %d", FT_SECTOR(i));
 612        } else {
 613                map = buff->hard_error_map & mask;
 614                i = buff->sector_offset - 1;
 615                if (map) {
 616                        while ((map & (1 << i)) == 0) {
 617                                --i;
 618                        }
 619                        TRACE(ft_t_noise, "after sector %d", FT_SECTOR(i));
 620                        ++i; /* first sector after last hard error */
 621                } else {
 622                        TRACE(ft_t_bug, "BUG: no soft or hard errors");
 623                }
 624        }
 625        TRACE_EXIT i;
 626}
 627
 628/*  check possible dma residue when formatting, update position record in
 629 *  buffer struct. This is, of course, modelled after determine_progress(), but
 630 *  we don't need to set up for retries because the format process cannot be
 631 *  interrupted (except at the end of the tape track).
 632 */
 633static int determine_fmt_progress(buffer_struct *buff, error_cause cause)
 634{
 635        unsigned int dma_residue;
 636        TRACE_FUN(ft_t_any);
 637
 638        /*  Using less preferred order of disable_dma and
 639         *  get_dma_residue because this seems to fail on at least one
 640         *  system if reversed!
 641         */
 642        dma_residue = get_dma_residue(fdc.dma);
 643        disable_dma(fdc.dma);
 644        if (cause != no_error || dma_residue != 0) {
 645                TRACE(ft_t_info, "DMA residue = 0x%04x", dma_residue);
 646                fdc_mode = fdc_idle;
 647                switch(cause) {
 648                case no_error:
 649                        ft_runner_status = aborting;
 650                        buff->status = idle;
 651                        break;
 652                case overrun_error:
 653                        /*  got an overrun error on the first byte, must be a
 654                         *  hardware problem 
 655                         */
 656                        TRACE(ft_t_bug, 
 657                              "Unexpected error: failing DMA controller ?");
 658                        ft_runner_status = do_abort;
 659                        buff->status = error;
 660                        break;
 661                default:
 662                        TRACE(ft_t_noise, "Unexpected error at segment %d",
 663                              buff->segment_id);
 664                        ft_runner_status = do_abort;
 665                        buff->status = error;
 666                        break;
 667                }
 668                TRACE_EXIT -EIO; /* can only retry entire track in format mode
 669                                  */
 670        }
 671        /*  Update var's influenced by the DMA operation.
 672         */
 673        buff->ptr             += FT_SECTORS_PER_SEGMENT * 4;
 674        buff->bytes           -= FT_SECTORS_PER_SEGMENT * 4;
 675        buff->remaining       -= FT_SECTORS_PER_SEGMENT;
 676        buff->segment_id ++; /* done with segment */
 677        TRACE_EXIT 0;
 678}
 679
 680/*
 681 *  Continue formatting, switch buffers if there is no data left in
 682 *  current buffer. This is, of course, modelled after
 683 *  continue_xfer(), but we don't need to set up for retries because
 684 *  the format process cannot be interrupted (except at the end of the
 685 *  tape track).
 686 */
 687static void continue_formatting(buffer_struct *buff)
 688{
 689        TRACE_FUN(ft_t_any);
 690
 691        if (buff->remaining <= 0) { /*  no space left in dma buffer */
 692                unsigned int next = buff->next_segment; 
 693
 694                if (next == 0) { /* end of tape track */
 695                        buff->status     = done;
 696                        ft_runner_status = logical_eot;
 697                        fdc_mode         = fdc_idle;
 698                        TRACE(ft_t_noise, "Done formatting track %d",
 699                              ft_location.track);
 700                        TRACE_EXIT;
 701                }
 702                /*
 703                 *  switch to next buffer!
 704                 */
 705                buff->status   = done;
 706                buff = ftape_next_buffer(ft_queue_head);
 707
 708                if (buff->status != waiting  || next != buff->segment_id) {
 709                        goto format_setup_error;
 710                }
 711        }
 712        if (fdc_setup_formatting(buff) < 0) {
 713                goto format_setup_error;
 714        }
 715        buff->status = formatting;
 716        TRACE(ft_t_fdc_dma, "Formatting segment %d on track %d",
 717              buff->segment_id, ft_location.track);
 718        TRACE_EXIT;
 719 format_setup_error:
 720        ft_runner_status = do_abort;
 721        fdc_mode         = fdc_idle;
 722        buff->status     = error;
 723        TRACE(ft_t_err, "Error setting up for segment %d on track %d",
 724              buff->segment_id, ft_location.track);
 725        TRACE_EXIT;
 726
 727}
 728
 729/*  this handles writing, read id, reading and formatting
 730 */
 731static void handle_fdc_busy(buffer_struct *buff)
 732{
 733        static int no_data_error_count;
 734        int retry = 0;
 735        error_cause cause;
 736        __u8 in[7];
 737        int skip;
 738        fdc_mode_enum fmode = fdc_mode;
 739        TRACE_FUN(ft_t_any);
 740
 741        if (fdc_result(in, 7) < 0) { /* better get it fast ! */
 742                TRACE(ft_t_err, 
 743                      "Probably fatal error during FDC Result Phase\n"
 744                      KERN_INFO
 745                      "drive may hang until (power on) reset :-(");
 746                /*  what to do next ????
 747                 */
 748                TRACE_EXIT;
 749        }
 750        cause = decode_irq_cause(fdc_mode, in);
 751#ifdef TESTING
 752        { int i;
 753        for (i = 0; i < (int)ft_nr_buffers; ++i)
 754                TRACE(ft_t_any, "buffer[%d] status: %d, segment_id: %d",
 755                      i, ft_buffer[i]->status, ft_buffer[i]->segment_id);
 756        }
 757#endif
 758        if (fmode == fdc_reading_data && ft_driver_state == verifying) {
 759                fmode = fdc_verifying;
 760        }
 761        switch (fmode) {
 762        case fdc_verifying:
 763                if (ft_runner_status == aborting ||
 764                    ft_runner_status == do_abort) {
 765                        TRACE(ft_t_noise,"aborting %s",fdc_mode_txt(fdc_mode));
 766                        break;
 767                }
 768                if (buff->retry > 0) {
 769                        TRACE(ft_t_flow, "this is retry nr %d", buff->retry);
 770                }
 771                switch (cause) {
 772                case no_error:
 773                        no_data_error_count = 0;
 774                        determine_verify_progress(buff, cause, in[5]);
 775                        if (in[2] & 0x40) {
 776                                /*  This should not happen when verifying
 777                                 */
 778                                TRACE(ft_t_warn,
 779                                      "deleted data in segment %d/%d",
 780                                      buff->segment_id,
 781                                      FT_SECTOR(buff->sector_offset - 1));
 782                                buff->remaining = 0; /* abort transfer */
 783                                buff->hard_error_map = EMPTY_SEGMENT;
 784                                skip = 1;
 785                        } else {
 786                                skip = 0;
 787                        }
 788                        continue_xfer(buff, fdc_mode, skip);
 789                        break;
 790                case no_data_error:
 791                        no_data_error_count ++;
 792                case overrun_error:
 793                        retry ++;
 794                case id_am_error:
 795                case id_crc_error:
 796                case data_am_error:
 797                case data_crc_error:
 798                        determine_verify_progress(buff, cause, in[5]); 
 799                        if (cause == no_data_error) {
 800                                if (no_data_error_count >= 2) {
 801                                        TRACE(ft_t_warn,
 802                                              "retrying because of successive "
 803                                              "no data errors");
 804                                        no_data_error_count = 0;
 805                                } else {
 806                                        retry --;
 807                                }
 808                        } else {
 809                                no_data_error_count = 0;
 810                        }
 811                        if (retry) {
 812                                skip = find_resume_point(buff);
 813                        } else {
 814                                skip = buff->sector_offset;
 815                        }
 816                        if (retry && skip < 32) {
 817                                retry_sector(buff, fdc_mode, skip);
 818                        } else {
 819                                continue_xfer(buff, fdc_mode, skip);
 820                        }
 821                        update_history(cause);
 822                        break;
 823                default:
 824                        /*  Don't know why this could happen 
 825                         *  but find out.
 826                         */
 827                        determine_verify_progress(buff, cause, in[5]);
 828                        retry_sector(buff, fdc_mode, 0);
 829                        TRACE(ft_t_err, "Error: unexpected error");
 830                        break;
 831                }
 832                break;
 833        case fdc_reading_data:
 834#ifdef TESTING
 835                /* I'm sorry, but: NOBODY ever used this trace
 836                 * messages for ages. I guess that Bas was the last person
 837                 * that ever really used this (thank you, between the lines)
 838                 */
 839                if (cause == no_error) {
 840                        TRACE(ft_t_flow,"reading segment %d",buff->segment_id);
 841                } else {
 842                        TRACE(ft_t_noise, "error reading segment %d",
 843                              buff->segment_id);
 844                        TRACE(ft_t_noise, "\n"
 845                              KERN_INFO
 846                             "IRQ:C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x\n"
 847                              KERN_INFO
 848                              "BUF:C: 0x%02x, H: 0x%02x, R: 0x%02x",
 849                              in[3], in[4], in[5], in[6],
 850                              buff->cyl, buff->head, buff->sect);
 851                }
 852#endif
 853                if (ft_runner_status == aborting ||
 854                    ft_runner_status == do_abort) {
 855                        TRACE(ft_t_noise,"aborting %s",fdc_mode_txt(fdc_mode));
 856                        break;
 857                }
 858                if (buff->bad_sector_map == FAKE_SEGMENT) {
 859                        /* This condition occurs when reading a `fake'
 860                         * sector that's not accessible. Doesn't
 861                         * really matter as we would have ignored it
 862                         * anyway !
 863                         *
 864                         * Chance is that we're past the next segment
 865                         * now, so the next operation may fail and
 866                         * result in a retry.  
 867                         */
 868                        buff->remaining = 0;    /* skip failing sector */
 869                        /* buff->ptr       = buff->address; */
 870                        /* fake success: */
 871                        continue_xfer(buff, fdc_mode, 1);
 872                        /*  trace calls are expensive: place them AFTER
 873                         *  the real stuff has been done.
 874                         *  
 875                         */
 876                        TRACE(ft_t_noise, "skipping empty segment %d (read), size? %d",
 877                              buff->segment_id, buff->ptr - buff->address);
 878                        TRACE_EXIT;
 879                }
 880                if (buff->retry > 0) {
 881                        TRACE(ft_t_flow, "this is retry nr %d", buff->retry);
 882                }
 883                switch (cause) {
 884                case no_error:
 885                        determine_progress(buff, cause, in[5]);
 886                        if (in[2] & 0x40) {
 887                                /*  Handle deleted data in header segments.
 888                                 *  Skip segment and force read-ahead.
 889                                 */
 890                                TRACE(ft_t_warn,
 891                                      "deleted data in segment %d/%d",
 892                                      buff->segment_id,
 893                                      FT_SECTOR(buff->sector_offset - 1));
 894                                buff->deleted = 1;
 895                                buff->remaining = 0;/*abort transfer */
 896                                buff->soft_error_map |=
 897                                                (-1L << buff->sector_offset);
 898                                if (buff->segment_id == 0) {
 899                                        /* stop on next segment */
 900                                        stop_read_ahead = 1;
 901                                }
 902                                /* force read-ahead: */
 903                                buff->next_segment = 
 904                                        buff->segment_id + 1;
 905                                skip = (FT_SECTORS_PER_SEGMENT - 
 906                                        buff->sector_offset);
 907                        } else {
 908                                skip = 0;
 909                        }
 910                        continue_xfer(buff, fdc_mode, skip);
 911                        break;
 912                case no_data_error:
 913                        /* Tape started too far ahead of or behind the
 914                         * right sector.  This may also happen in the
 915                         * middle of a segment !
 916                         *
 917                         * Handle no-data as soft error. If next
 918                         * sector fails too, a retry (with needed
 919                         * reposition) will follow.
 920                         */
 921                        retry ++;
 922                case id_am_error:
 923                case id_crc_error:
 924                case data_am_error:
 925                case data_crc_error:
 926                case overrun_error:
 927                        retry += (buff->soft_error_map != 0 ||
 928                                  buff->hard_error_map != 0);
 929                        determine_progress(buff, cause, in[5]); 
 930#if 1 || defined(TESTING)
 931                        if (cause == overrun_error) retry ++;
 932#endif
 933                        if (retry) {
 934                                skip = find_resume_point(buff);
 935                        } else {
 936                                skip = buff->sector_offset;
 937                        }
 938                        /*  Try to resume with next sector on single
 939                         *  errors (let ecc correct it), but retry on
 940                         *  no_data (we'll be past the target when we
 941                         *  get here so we cannot retry) or on
 942                         *  multiple errors (reduce chance on ecc
 943                         *  failure).
 944                         */
 945                        /*  cH: 23/02/97: if the last sector in the 
 946                         *  segment was a hard error, then there is 
 947                         *  no sense in a retry. This occasion seldom
 948                         *  occurs but ... @:³²¸`@%&§$
 949                         */
 950                        if (retry && skip < 32) {
 951                                retry_sector(buff, fdc_mode, skip);
 952                        } else {
 953                                continue_xfer(buff, fdc_mode, skip);
 954                        }
 955                        update_history(cause);
 956                        break;
 957                default:
 958                        /*  Don't know why this could happen 
 959                         *  but find out.
 960                         */
 961                        determine_progress(buff, cause, in[5]);
 962                        retry_sector(buff, fdc_mode, 0);
 963                        TRACE(ft_t_err, "Error: unexpected error");
 964                        break;
 965                }
 966                break;
 967        case fdc_reading_id:
 968                if (cause == no_error) {
 969                        fdc_cyl = in[3];
 970                        fdc_head = in[4];
 971                        fdc_sect = in[5];
 972                        TRACE(ft_t_fdc_dma,
 973                              "id read: C: 0x%02x, H: 0x%02x, R: 0x%02x",
 974                              fdc_cyl, fdc_head, fdc_sect);
 975                } else {        /* no valid information, use invalid sector */
 976                        fdc_cyl = fdc_head = fdc_sect = 0;
 977                        TRACE(ft_t_flow, "Didn't find valid sector Id");
 978                }
 979                fdc_mode = fdc_idle;
 980                break;
 981        case fdc_deleting:
 982        case fdc_writing_data:
 983#ifdef TESTING
 984                if (cause == no_error) {
 985                        TRACE(ft_t_flow, "writing segment %d", buff->segment_id);
 986                } else {
 987                        TRACE(ft_t_noise, "error writing segment %d",
 988                              buff->segment_id);
 989                }
 990#endif
 991                if (ft_runner_status == aborting ||
 992                    ft_runner_status == do_abort) {
 993                        TRACE(ft_t_flow, "aborting %s",fdc_mode_txt(fdc_mode));
 994                        break;
 995                }
 996                if (buff->retry > 0) {
 997                        TRACE(ft_t_flow, "this is retry nr %d", buff->retry);
 998                }
 999                if (buff->bad_sector_map == FAKE_SEGMENT) {
1000                        /* This condition occurs when trying to write to a
1001                         * `fake' sector that's not accessible. Doesn't really
1002                         * matter as it isn't used anyway ! Might be located
1003                         * at wrong segment, then we'll fail on the next
1004                         * segment.
1005                         */
1006                        TRACE(ft_t_noise, "skipping empty segment (write)");
1007                        buff->remaining = 0;    /* skip failing sector */
1008                        /* fake success: */
1009                        continue_xfer(buff, fdc_mode, 1);
1010                        break;
1011                }
1012                switch (cause) {
1013                case no_error:
1014                        determine_progress(buff, cause, in[5]);
1015                        continue_xfer(buff, fdc_mode, 0);
1016                        break;
1017                case no_data_error:
1018                case id_am_error:
1019                case id_crc_error:
1020                case data_am_error:
1021                case overrun_error:
1022                        update_history(cause);
1023                        determine_progress(buff, cause, in[5]);
1024                        skip = find_resume_point(buff);
1025                        retry_sector(buff, fdc_mode, skip);
1026                        break;
1027                default:
1028                        if (in[1] & 0x02) {
1029                                TRACE(ft_t_err, "media not writable");
1030                        } else {
1031                                TRACE(ft_t_bug, "unforeseen write error");
1032                        }
1033                        fdc_mode = fdc_idle;
1034                        break;
1035                }
1036                break; /* fdc_deleting || fdc_writing_data */
1037        case fdc_formatting:
1038                /*  The interrupt comes after formatting a segment. We then
1039                 *  have to set up QUICKLY for the next segment. But
1040                 *  afterwards, there is plenty of time.
1041                 */
1042                switch (cause) {
1043                case no_error:
1044                        /*  would like to keep most of the formatting stuff
1045                         *  outside the isr code, but timing is too critical
1046                         */
1047                        if (determine_fmt_progress(buff, cause) >= 0) {
1048                                continue_formatting(buff);
1049                        }
1050                        break;
1051                case no_data_error:
1052                case id_am_error:
1053                case id_crc_error:
1054                case data_am_error:
1055                case overrun_error:
1056                default:
1057                        determine_fmt_progress(buff, cause);
1058                        update_history(cause);
1059                        if (in[1] & 0x02) {
1060                                TRACE(ft_t_err, "media not writable");
1061                        } else {
1062                                TRACE(ft_t_bug, "unforeseen write error");
1063                        }
1064                        break;
1065                } /* cause */
1066                break;
1067        default:
1068                TRACE(ft_t_warn, "Warning: unexpected irq during: %s",
1069                      fdc_mode_txt(fdc_mode));
1070                fdc_mode = fdc_idle;
1071                break;
1072        }
1073        TRACE_EXIT;
1074}
1075
1076/*      FDC interrupt service routine.
1077 */
1078void fdc_isr(void)
1079{
1080        static int isr_active;
1081#ifdef TESTING
1082        unsigned int t0 = ftape_timestamp();
1083#endif
1084        TRACE_FUN(ft_t_any);
1085
1086        if (isr_active++) {
1087                --isr_active;
1088                TRACE(ft_t_bug, "BUG: nested interrupt, not good !");
1089                *fdc.hook = fdc_isr; /*  hook our handler into the fdc
1090                                      *  code again 
1091                                      */
1092                TRACE_EXIT;
1093        }
1094        sti();
1095        if (inb_p(fdc.msr) & FDC_BUSY) {        /*  Entering Result Phase */
1096                ft_hide_interrupt = 0;
1097                handle_fdc_busy(ftape_get_buffer(ft_queue_head));
1098                if (ft_runner_status == do_abort) {
1099                        /*      cease operation, remember tape position
1100                         */
1101                        TRACE(ft_t_flow, "runner aborting");
1102                        ft_runner_status = aborting;
1103                        ++ft_expected_stray_interrupts;
1104                }
1105        } else { /* !FDC_BUSY */
1106                /*  clear interrupt, cause should be gotten by issuing
1107                 *  a Sense Interrupt Status command.
1108                 */
1109                if (fdc_mode == fdc_recalibrating || fdc_mode == fdc_seeking) {
1110                        if (ft_hide_interrupt) {
1111                                int st0;
1112                                int pcn;
1113
1114                                if (fdc_sense_interrupt_status(&st0, &pcn) < 0)
1115                                        TRACE(ft_t_err,
1116                                              "sense interrupt status failed");
1117                                ftape_current_cylinder = pcn;
1118                                TRACE(ft_t_flow, "handled hidden interrupt");
1119                        }
1120                        ft_seek_completed = 1;
1121                        fdc_mode = fdc_idle;
1122#if LINUX_VERSION_CODE >= KERNEL_VER(2,0,16)
1123                } else if (!waitqueue_active(&ftape_wait_intr)) {
1124#else
1125                } else if (!ftape_wait_intr) {
1126#endif
1127                        if (ft_expected_stray_interrupts == 0) {
1128                                TRACE(ft_t_warn, "unexpected stray interrupt");
1129                        } else {
1130                                TRACE(ft_t_flow, "expected stray interrupt");
1131                                --ft_expected_stray_interrupts;
1132                        }
1133                } else {
1134                        if (fdc_mode == fdc_reading_data ||
1135                            fdc_mode == fdc_verifying    ||
1136                            fdc_mode == fdc_writing_data ||
1137                            fdc_mode == fdc_deleting     ||
1138                            fdc_mode == fdc_formatting   ||
1139                            fdc_mode == fdc_reading_id) {
1140                                if (inb_p(fdc.msr) & FDC_BUSY) {
1141                                        TRACE(ft_t_bug,
1142                                        "***** FDC failure, busy too late");
1143                                } else {
1144                                        TRACE(ft_t_bug,
1145                                              "***** FDC failure, no busy");
1146                                }
1147                        } else {
1148                                TRACE(ft_t_fdc_dma, "awaited stray interrupt");
1149                        }
1150                }
1151                ft_hide_interrupt = 0;
1152        }
1153        /*    Handle sleep code.
1154         */
1155        if (!ft_hide_interrupt) {
1156                ft_interrupt_seen ++;
1157#if LINUX_VERSION_CODE >= KERNEL_VER(2,0,16)
1158                if (waitqueue_active(&ftape_wait_intr)) {
1159                        wake_up_interruptible(&ftape_wait_intr);
1160                }
1161#else
1162                if (ftape_wait_intr) {
1163                        wake_up_interruptible(&ftape_wait_intr);
1164                }
1165#endif
1166        } else {
1167#if LINUX_VERSION_CODE >= KERNEL_VER(2,0,16)
1168                TRACE(ft_t_flow, "hiding interrupt while %s", 
1169                      waitqueue_active(&ftape_wait_intr) ? "waiting":"active");
1170#else
1171                TRACE(ft_t_flow, "hiding interrupt while %s", 
1172                      ftape_wait_intr ? "waiting" : "active");
1173#endif
1174        }
1175#ifdef TESTING
1176        t0 = ftape_timediff(t0, ftape_timestamp());
1177        if (t0 >= 1000) {
1178                /* only tell us about long calls */
1179                TRACE(ft_t_noise, "isr() duration: %5d usec", t0);
1180        }
1181#endif
1182        *fdc.hook = fdc_isr;    /* hook our handler into the fdc code again */
1183        --isr_active;
1184        TRACE_EXIT;
1185}
1186
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.