/*
* Copyright (C) 1993-1996 Bas Laarhoven,
* (C) 1996-1997 Claus-Justus Heine.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-rw.c,v $
* $Revision: 1.7 $
* $Date: 1997/10/28 14:26:49 $
*
* This file contains some common code for the segment read and
* segment write routines for the QIC-117 floppy-tape driver for
* Linux.
*/
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/ftape.h>
#include <linux/qic117.h>
#include "../lowlevel/ftape-tracing.h"
#include "../lowlevel/ftape-rw.h"
#include "../lowlevel/fdc-io.h"
#include "../lowlevel/ftape-init.h"
#include "../lowlevel/ftape-io.h"
#include "../lowlevel/ftape-ctl.h"
#include "../lowlevel/ftape-read.h"
#include "../lowlevel/ftape-ecc.h"
#include "../lowlevel/ftape-bsm.h"
/* Global vars.
*/
int ft_nr_buffers;
buffer_struct *ft_buffer[FT_MAX_NR_BUFFERS];
static volatile int ft_head;
static volatile int ft_tail; /* not volatile but need same type as head */
int fdc_setup_error;
location_record ft_location = {-1, 0};
volatile int ftape_tape_running;
/* Local vars.
*/
static int overrun_count_offset;
static int inhibit_correction;
/* maxmimal allowed overshoot when fast seeking
*/
#define OVERSHOOT_LIMIT 10
/* Increment cyclic buffer nr.
*/
buffer_struct *ftape_next_buffer(ft_buffer_queue_t pos)
{
switch (pos) {
case ft_queue_head:
if (++ft_head >= ft_nr_buffers) {
ft_head = 0;
}
return ft_buffer[ft_head];
case ft_queue_tail:
if (++ft_tail >= ft_nr_buffers) {
ft_tail = 0;
}
return ft_buffer[ft_tail];
default:
return NULL;
}
}
int ftape_buffer_id(ft_buffer_queue_t pos)
{
switch(pos) {
case ft_queue_head: return ft_head;
case ft_queue_tail: return ft_tail;
default: return -1;
}
}
buffer_struct *ftape_get_buffer(ft_buffer_queue_t pos)
{
switch(pos) {
case ft_queue_head: return ft_buffer[ft_head];
case ft_queue_tail: return ft_buffer[ft_tail];
default: return NULL;
}
}
void ftape_reset_buffer(void)
{
ft_head = ft_tail = 0;
}
buffer_state_enum ftape_set_state(buffer_state_enum new_state)
{
buffer_state_enum old_state = ft_driver_state;
ft_driver_state = new_state;
return old_state;
}
/* Calculate Floppy Disk Controller and DMA parameters for a segment.
* head: selects buffer struct in array.
* offset: number of physical sectors to skip (including bad ones).
* count: number of physical sectors to handle (including bad ones).
*/
static int setup_segment(buffer_struct * buff,
int segment_id,
unsigned int sector_offset,
unsigned int sector_count,
int retry)
{
SectorMap offset_mask;
SectorMap mask;
TRACE_FUN(ft_t_any);
buff->segment_id = segment_id;
buff->sector_offset = sector_offset;
buff->remaining = sector_count;
buff->head = segment_id / ftape_segments_per_head;
buff->cyl = (segment_id % ftape_segments_per_head) / ftape_segments_per_cylinder;
buff->sect = (segment_id % ftape_segments_per_cylinder) * FT_SECTORS_PER_SEGMENT + 1;
buff->deleted = 0;
offset_mask = (1 << buff->sector_offset) - 1;
mask = ftape_get_bad_sector_entry(segment_id) & offset_mask;
while (mask) {
if (mask & 1) {
offset_mask >>= 1; /* don't count bad sector */
}
mask >>= 1;
}
buff->data_offset = count_ones(offset_mask); /* good sectors to skip */
buff->ptr = buff->address + buff->data_offset * FT_SECTOR_SIZE;
TRACE(ft_t_flow, "data offset = %d sectors", buff->data_offset);