root/drivers/char/ftape/ftape-bsm.c

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

DEFINITIONS

This source file includes following definitions.
  1. fix_tape
  2. find_end_of_bsm_list
  3. store_bad_sector_map
  4. put_sector
  5. get_sector
  6. extract_bad_sector_map
  7. cvt2map
  8. cvt2segment
  9. forward_seek_entry
  10. backwards_seek_entry
  11. put_bad_sector_entry
  12. get_bad_sector_entry
  13. ftape_init_bsm

   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/ftape-bsm.c,v $
  19  $Author: bas $
  20  *
  21  $Revision: 1.7 $
  22  $Date: 1995/04/30 13:15:14 $
  23  $State: Beta $
  24  *
  25  *      This file contains the bad-sector map handling code for
  26  *      the QIC-117 floppy tape driver for Linux.
  27  *      QIC-40, QIC-80, QIC-3010 and QIC-3020 maps are implemented.
  28  */
  29 
  30 #include <linux/ftape.h>
  31 #include <linux/string.h>
  32 
  33 #include "tracing.h"
  34 #include "ftape-bsm.h"
  35 #include "ftape-ctl.h"
  36 #include "ftape-rw.h"
  37 
  38 
  39 /*      Global vars.
  40  */
  41 int bad_sector_map_changed = 0;
  42 
  43 /*      Local vars.
  44  */
  45 static byte bad_sector_map[BAD_SECTOR_MAP_SIZE];
  46 typedef enum {
  47         forward, backward
  48 } mode_type;
  49 
  50 #if 0
  51 /*  fix_tape converts a normal QIC-80 tape into a 'wide' tape.
  52  *  For testing purposes only !
  53  */
  54 void fix_tape(byte * buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
  55 {
  56         static byte list[BAD_SECTOR_MAP_SIZE];
  57         unsigned long *src_ptr = (unsigned long *) list;
  58         byte *dst_ptr = bad_sector_map;
  59         unsigned long map;
  60         unsigned sector = 1;
  61         int i;
  62 
  63         memcpy(list, bad_sector_map, sizeof(list));
  64         memset(bad_sector_map, 0, sizeof(bad_sector_map));
  65         while ((byte *) src_ptr - list < sizeof(list)) {
  66                 map = *src_ptr++;
  67                 if (map == EMPTY_SEGMENT) {
  68                         *(unsigned long *) dst_ptr = 0x800000 + sector;
  69                         dst_ptr += 3;
  70                         sector += SECTORS_PER_SEGMENT;
  71                 } else {
  72                         for (i = 0; i < SECTORS_PER_SEGMENT; ++i) {
  73                                 if (map & 1) {
  74                                         *(unsigned long *) dst_ptr = sector;
  75                                         dst_ptr += 3;
  76                                 }
  77                                 map >>= 1;
  78                                 ++sector;
  79                         }
  80                 }
  81         }
  82         bad_sector_map_changed = 1;
  83         *(buffer + 4) = 4;      /* put new format code */
  84         format_code = 4;
  85 }
  86 
  87 #endif
  88 
  89 byte *
  90  find_end_of_bsm_list(byte * ptr, byte * limit)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92         while (ptr + 2 < limit) {
  93                 if (ptr[0] || ptr[1] || ptr[2]) {
  94                         ptr += 3;
  95                 } else {
  96                         return ptr;
  97                 }
  98         }
  99         return NULL;
 100 }
 101 
 102 void store_bad_sector_map(byte * buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104         TRACE_FUN(8, "store_bad_sector_map");
 105         size_t count;
 106         size_t offset;
 107 
 108         /*  Store the bad sector map in buffer.
 109          */
 110         if (format_code == 4) {
 111                 offset = 256;
 112                 count = sizeof(bad_sector_map);
 113         } else {
 114                 offset = 2 * SECTOR_SIZE;       /* skip failed sector log */
 115                 count = sizeof(bad_sector_map) - (offset - 256);
 116         }
 117         memcpy(buffer + offset, bad_sector_map, count);
 118         TRACE_EXIT;
 119 }
 120 
 121 void put_sector(byte ** ptr, unsigned long sector)
     /* [previous][next][first][last][top][bottom][index][help] */
 122 {
 123         *(*ptr)++ = sector & 0xff;
 124         sector >>= 8;
 125         *(*ptr)++ = sector & 0xff;
 126         sector >>= 8;
 127         *(*ptr)++ = sector & 0xff;
 128 }
 129 
 130 unsigned long get_sector(byte ** ptr, mode_type mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 131 {
 132         unsigned long sector;
 133 
 134         if (mode == forward) {
 135                 sector = *(*ptr)++;
 136                 sector += *(*ptr)++ << 8;
 137                 sector += *(*ptr)++ << 16;
 138         } else {
 139                 sector = *--(*ptr) << 16;
 140                 sector += *--(*ptr) << 8;
 141                 sector += *--(*ptr);
 142         }
 143         return sector;
 144 }
 145 
 146 void extract_bad_sector_map(byte * buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
 147 {
 148         TRACE_FUN(8, "extract_bad_sector_map");
 149 
 150         /*  Fill the bad sector map with the contents of buffer.
 151          */
 152         if (format_code == 4) {
 153                 /* QIC-3010/3020 and wide QIC-80 tapes no longer have a failed
 154                  * sector log but use this area to extend the bad sector map.
 155                  */
 156                 memcpy(bad_sector_map, buffer + 256, sizeof(bad_sector_map));
 157         } else {
 158                 /* non-wide QIC-80 tapes have a failed sector log area that
 159                  * mustn't be included in the bad sector map.
 160                  */
 161                 memcpy(bad_sector_map, buffer + 256 + FAILED_SECTOR_LOG_SIZE,
 162                        sizeof(bad_sector_map) - FAILED_SECTOR_LOG_SIZE);
 163         }
 164 #if 0
 165         /* for testing of bad sector handling at end of tape
 166          */
 167         ((unsigned long *) bad_sector_map)[segments_per_track * tracks_per_tape - 3] = 0x000003e0;
 168         ((unsigned long *) bad_sector_map)[segments_per_track * tracks_per_tape - 2] = 0xff3fffff;
 169         ((unsigned long *) bad_sector_map)[segments_per_track * tracks_per_tape - 1] = 0xffffe000;
 170 #endif
 171 #if 0
 172         /*  Enable to test bad sector handling
 173          */
 174         ((unsigned long *) bad_sector_map)[30] = 0xfffffffe;
 175         ((unsigned long *) bad_sector_map)[32] = 0x7fffffff;
 176         ((unsigned long *) bad_sector_map)[34] = 0xfffeffff;
 177         ((unsigned long *) bad_sector_map)[36] = 0x55555555;
 178         ((unsigned long *) bad_sector_map)[38] = 0xffffffff;
 179         ((unsigned long *) bad_sector_map)[50] = 0xffff0000;
 180         ((unsigned long *) bad_sector_map)[51] = 0xffffffff;
 181         ((unsigned long *) bad_sector_map)[52] = 0xffffffff;
 182         ((unsigned long *) bad_sector_map)[53] = 0x0000ffff;
 183 #endif
 184 #if 0
 185         /*  Enable when testing multiple volume tar dumps.
 186          */
 187         for (i = first_data_segment; i <= ftape_last_segment.id - 7; ++i) {
 188                 ((unsigned long *) bad_sector_map)[i] = EMPTY_SEGMENT;
 189         }
 190 #endif
 191 #if 0
 192         /*  Enable when testing bit positions in *_error_map
 193          */
 194         for (i = first_data_segment; i <= ftape_last_segment.id; ++i) {
 195                 ((unsigned long *) bad_sector_map)[i] |= 0x00ff00ff;
 196         }
 197 #endif
 198         if (tracing > 2) {
 199                 unsigned int map;
 200                 int good_sectors = 0;
 201                 int bad_sectors;
 202                 unsigned int total_bad = 0;
 203                 int i;
 204 
 205                 if (format_code == 4 || format_code == 3) {
 206                         byte *ptr = bad_sector_map;
 207                         unsigned sector;
 208 
 209                         do {
 210                                 sector = get_sector(&ptr, forward);
 211                                 if (sector != 0) {
 212                                         if (format_code == 4 && sector & 0x800000) {
 213                                                 total_bad += SECTORS_PER_SEGMENT - 3;
 214                                                 TRACEx1(6, "bad segment at sector: %6d", sector & 0x7fffff);
 215                                         } else {
 216                                                 ++total_bad;
 217                                                 TRACEx1(6, "bad sector: %6d", sector);
 218                                         }
 219                                 }
 220                         } while (sector != 0);
 221                         /*  Display end-of-file marks
 222                          */
 223                         do {
 224                                 sector = *((unsigned short *) ptr)++;
 225                                 if (sector) {
 226                                         TRACEx2(4, "eof mark: %4d/%2d", sector,
 227                                             *((unsigned short *) ptr)++);
 228                                 }
 229                         } while (sector);
 230                 } else {
 231                         for (i = first_data_segment;
 232                          i < segments_per_track * tracks_per_tape; ++i) {
 233                                 map = ((unsigned long *) bad_sector_map)[i];
 234                                 bad_sectors = count_ones(map);
 235                                 if (bad_sectors > 0) {
 236                                         TRACEx2(6, "bsm for segment %4d: 0x%08x", i, map);
 237                                         if (bad_sectors > SECTORS_PER_SEGMENT - 3) {
 238                                                 bad_sectors = SECTORS_PER_SEGMENT - 3;
 239                                         }
 240                                         total_bad += bad_sectors;
 241                                 }
 242                         }
 243                 }
 244                 good_sectors = ((segments_per_track * tracks_per_tape - first_data_segment)
 245                                 * (SECTORS_PER_SEGMENT - 3)) - total_bad;
 246                 TRACEx1(3, "%d Kb usable on this tape",
 247                         good_sectors - ftape_last_segment.free);
 248                 if (total_bad == 0) {
 249                         TRACE(1, "WARNING: this tape has no bad blocks registered !");
 250                 } else {
 251                         TRACEx1(2, "%d bad sectors", total_bad);
 252                 }
 253         }
 254         TRACE_EXIT;
 255 }
 256 
 257 unsigned long cvt2map(int sector)
     /* [previous][next][first][last][top][bottom][index][help] */
 258 {
 259         return 1 << (((sector & 0x7fffff) - 1) % SECTORS_PER_SEGMENT);
 260 }
 261 
 262 int cvt2segment(int sector)
     /* [previous][next][first][last][top][bottom][index][help] */
 263 {
 264         return ((sector & 0x7fffff) - 1) / SECTORS_PER_SEGMENT;
 265 }
 266 
 267 int forward_seek_entry(int segment_id, byte ** ptr, unsigned long *map)
     /* [previous][next][first][last][top][bottom][index][help] */
 268 {
 269         byte *tmp_ptr;
 270         unsigned long sector;
 271         int segment;
 272         int count;
 273 
 274         do {
 275                 sector = get_sector(ptr, forward);
 276                 segment = cvt2segment(sector);
 277         } while (sector != 0 && segment < segment_id);
 278         tmp_ptr = *ptr - 3;     /* point to first sector >= segment_id */
 279         /*  Get all sectors in segment_id
 280          */
 281         if (format_code == 4 && (sector & 0x800000) && segment == segment_id) {
 282                 *map = EMPTY_SEGMENT;
 283                 count = 32;
 284         } else {
 285                 *map = 0;
 286                 count = 0;
 287                 while (sector != 0 && segment == segment_id) {
 288                         *map |= cvt2map(sector);
 289                         sector = get_sector(ptr, forward);
 290                         segment = cvt2segment(sector);
 291                         ++count;
 292                 }
 293         }
 294         *ptr = tmp_ptr;
 295         return count;
 296 }
 297 
 298 int backwards_seek_entry(int segment_id, byte ** ptr, unsigned long *map)
     /* [previous][next][first][last][top][bottom][index][help] */
 299 {
 300         unsigned long sector;
 301         int segment;
 302         int count;
 303 
 304         *map = 0;
 305         if (*ptr > bad_sector_map) {
 306                 do {
 307                         sector = get_sector(ptr, backward);
 308                         segment = cvt2segment(sector);
 309                 } while (*ptr > bad_sector_map && segment > segment_id);
 310                 count = 0;
 311                 if (segment > segment_id) {
 312                         /*  at start of list, no entry found */
 313                 } else if (segment < segment_id) {
 314                         /*  before smaller entry, adjust for overshoot */
 315                         *ptr += 3;
 316                 } else {
 317                         /*  get all sectors in segment_id */
 318                         if (format_code == 4 && (sector & 0x800000)) {
 319                                 *map = EMPTY_SEGMENT;
 320                                 count = 32;
 321                         } else {
 322                                 do {
 323                                         *map |= cvt2map(sector);
 324                                         ++count;
 325                                         if (*ptr <= bad_sector_map) {
 326                                                 break;
 327                                         }
 328                                         sector = get_sector(ptr, backward);
 329                                         segment = cvt2segment(sector);
 330                                 } while (segment == segment_id);
 331                                 if (segment < segment_id) {
 332                                         *ptr += 3;
 333                                 }
 334                         }
 335                 }
 336         } else {
 337                 count = 0;
 338         }
 339         return count;
 340 }
 341 
 342 void put_bad_sector_entry(int segment_id, unsigned long new_map)
     /* [previous][next][first][last][top][bottom][index][help] */
 343 {
 344         byte *ptr = bad_sector_map;
 345         int count;
 346         int new_count;
 347         unsigned long map;
 348 
 349         if (format_code == 3 || format_code == 4) {
 350                 count = forward_seek_entry(segment_id, &ptr, &map);
 351                 new_count = count_ones(new_map);
 352                 /*  If format code == 4 put empty segment instead of 32 bad sectors.
 353                  */
 354                 if (new_count == 32 && format_code == 4) {
 355                         new_count = 1;
 356                 }
 357                 if (count != new_count) {
 358                         /*  insert (or delete if < 0) new_count - count entries.
 359                          *  Move trailing part of list including terminating 0.
 360                          */
 361                         byte *hi_ptr = ptr;
 362 
 363                         do {
 364                         } while (get_sector(&hi_ptr, forward) != 0);
 365                         memmove(ptr + new_count, ptr + count, hi_ptr - (ptr + count));
 366                 }
 367                 if (new_count == 1 && new_map == EMPTY_SEGMENT) {
 368                         put_sector(&ptr, 0x800001 + segment_id * SECTORS_PER_SEGMENT);
 369                 } else {
 370                         int i = 0;
 371 
 372                         while (new_map) {
 373                                 if (new_map & 1) {
 374                                         put_sector(&ptr, 1 + segment_id * SECTORS_PER_SEGMENT + i);
 375                                 }
 376                                 ++i;
 377                                 new_map >>= 1;
 378                         }
 379                 }
 380         } else {
 381                 ((unsigned long *) bad_sector_map)[segment_id] = new_map;
 382         }
 383         bad_sector_map_changed = 1;
 384 }
 385 
 386 unsigned long get_bad_sector_entry(int segment_id)
     /* [previous][next][first][last][top][bottom][index][help] */
 387 {
 388         TRACE_FUN(8, "get_bad_sector_entry");
 389         static unsigned long map = 0;
 390 
 391         if (used_header_segment == -1) {
 392                 /*  When reading header segment we'll need a blank map.
 393                  */
 394                 map = 0;
 395         } else if (format_code == 3 || format_code == 4) {
 396                 /*  Invariants:
 397                  *    map - mask value returned on last call.
 398                  *    ptr - points to first sector greater or equal to
 399                  *          first sector in last_referenced segment.
 400                  *    last_referenced - segment id used in the last call,
 401                  *                      sector and map belong to this id.
 402                  *  This code is designed for sequential access and retries.
 403                  *  For true random access it may have to be redesigned.
 404                  */
 405                 static int last_reference = -1;
 406                 static byte *ptr = bad_sector_map;
 407 
 408                 if (segment_id > last_reference) {
 409                         /*  Skip all sectors before segment_id
 410                          */
 411                         forward_seek_entry(segment_id, &ptr, &map);
 412                 } else if (segment_id < last_reference) {
 413                         /*  Skip backwards until begin of buffer or first sector in segment_id
 414                          */
 415                         backwards_seek_entry(segment_id, &ptr, &map);
 416                 }               /* segment_id == last_reference : keep map */
 417                 last_reference = segment_id;
 418         } else {
 419                 map = ((unsigned long *) bad_sector_map)[segment_id];
 420         }
 421         TRACE_EXIT;
 422         return map;
 423 }
 424 
 425 void ftape_init_bsm(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 426 {
 427         memset(bad_sector_map, 0, sizeof(bad_sector_map));
 428 }

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