From 789fc0adbaf3a3ca95a3894aedacfc01863e8ae3 Mon Sep 17 00:00:00 2001 From: Sven Anders & Marcus Junker Date: Thu, 24 Aug 2006 17:11:50 +0200 Subject: [WATCHDOG] NS pc87413-wdt Watchdog driver New watchdog driver for the NS pc87413-wdt Watchdog Timer. Signed-off-by: Sven Anders Signed-off-by: Marcus Junker Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/Kconfig | 14 + drivers/char/watchdog/Makefile | 1 + drivers/char/watchdog/pc87413_wdt.c | 610 ++++++++++++++++++++++++++++++++++++ 3 files changed, 625 insertions(+) create mode 100644 drivers/char/watchdog/pc87413_wdt.c (limited to 'drivers/char') diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 0187b118532..d3e99982b69 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -363,6 +363,20 @@ config SCx200_WDT If compiled as a module, it will be called scx200_wdt. +config PC87413_WDT + tristate "NS PC87413 watchdog" + depends on WATCHDOG && X86 + ---help--- + This is the driver for the hardware watchdog on the PC87413 chipset + This watchdog simply watches your kernel to make sure it doesn't + freeze, and if it does, it reboots your computer after a certain + amount of time. + + To compile this driver as a module, choose M here: the + module will be called pc87413_wdt. + + Most people will say N. + config 60XX_WDT tristate "SBC-60XX Watchdog Timer" depends on WATCHDOG && X86 diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index 36440497047..e6a9f6f1d4b 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o +obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o obj-$(CONFIG_SBC8360_WDT) += sbc8360.o obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o diff --git a/drivers/char/watchdog/pc87413_wdt.c b/drivers/char/watchdog/pc87413_wdt.c new file mode 100644 index 00000000000..a6d42cf385e --- /dev/null +++ b/drivers/char/watchdog/pc87413_wdt.c @@ -0,0 +1,610 @@ +/* + * NS pc87413-wdt Watchdog Timer driver for Linux 2.6.x.x + * + * This code is based on wdt.c with original copyright + * + * (C) Copyright 2006 Marcus Junker, + * and Sven Anders, + * + * 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 of the License, or (at your option) any later version. + * + * Neither Marcus Junker, Sven Anders nor ANDURAS AG + * admit liability nor provide warranty for any of this software. + * This material is provided "AS-IS" and at no charge. + * + * Release 1.00. + * + */ + + +/* #define DEBUG 1 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define WATCHDOG_NAME "pc87413 WDT" +#define PFX WATCHDOG_NAME ": " +#define DPFX WATCHDOG_NAME " - DEBUG: " + +#define WDT_INDEX_IO_PORT (io+0) /* */ +#define WDT_DATA_IO_PORT (WDT_INDEX_IO_PORT+1) +#define SWC_LDN 0x04 +#define SIOCFG2 0x22 /* Serial IO register */ +#define WDCTL 0x10 /* Watchdog-Timer-Controll-Register */ +#define WDTO 0x11 /* Watchdog timeout register */ +#define WDCFG 0x12 /* Watchdog config register */ + +#define WD_TIMEOUT 1 /* minutes (1 ... 255) */ + + +static int pc87413_is_open=0; + +/* + * You must set these - there is no sane way to probe for this board. + * You can use pc87413=x to set these now. + */ + + + +/** + * module_params + * + * Setup options. The board isn't really probe-able so we have to + * get the user to tell us the configuration. + */ + +static int io=0x2E; /* Normally used addres on Portwell Boards */ +module_param(io, int, 0); +MODULE_PARM_DESC(wdt_io, WATCHDOG_NAME " io port (default 0x2E)"); + +static int timeout = WD_TIMEOUT; /* in minutes */ +module_param(timeout, int, 0); +MODULE_PARM_DESC(timeout, "Watchdog timeout in minutes. 1<= timeout <=63, default=" __MODULE_STRING(WD_TIMEOUT) "."); + + +/****************************************** + * Helper functions + ******************************************/ + +static void +pc87413_select_wdt_out (void) +{ + + unsigned int cr_data=0; + + /* Select multiple pin,pin55,as WDT output */ + + outb_p(SIOCFG2, WDT_INDEX_IO_PORT); + + cr_data = inb (WDT_DATA_IO_PORT); + + cr_data |= 0x80; /* Set Bit7 to 1*/ + outb_p(SIOCFG2, WDT_INDEX_IO_PORT); + + outb_p(cr_data, WDT_DATA_IO_PORT); + + + #ifdef DEBUG + printk(KERN_INFO DPFX "Select multiple pin,pin55,as WDT output: Bit7 to 1: %d\n", cr_data); + #endif +} + +static void +pc87413_enable_swc(void) +{ + + unsigned int cr_data=0; + + /* Step 2: Enable SWC functions */ + + outb_p(0x07, WDT_INDEX_IO_PORT); /* Point SWC_LDN (LDN=4) */ + outb_p(SWC_LDN, WDT_DATA_IO_PORT); + + outb_p(0x30, WDT_INDEX_IO_PORT); /* Read Index 0x30 First */ + cr_data = inb (WDT_DATA_IO_PORT); + cr_data |= 0x01; /* Set Bit0 to 1 */ + outb_p(0x30, WDT_INDEX_IO_PORT); + outb_p(cr_data, WDT_DATA_IO_PORT); /* Index0x30_bit0P1 */ + + #ifdef DEBUG + printk(KERN_INFO DPFX "pc87413 - Enable SWC functions\n"); + #endif +} + +static unsigned int +pc87413_get_swc_base(void) +{ + unsigned int swc_base_addr = 0; + unsigned char addr_l, addr_h = 0; + + /* Step 3: Read SWC I/O Base Address */ + + outb_p(0x60, WDT_INDEX_IO_PORT); /* Read Index 0x60 */ + addr_h = inb (WDT_DATA_IO_PORT); + + outb_p(0x61, WDT_INDEX_IO_PORT); /* Read Index 0x61 */ + + addr_l = inb (WDT_DATA_IO_PORT); + + + swc_base_addr = (addr_h << 8) + addr_l; + + #ifdef DEBUG + printk(KERN_INFO DPFX "Read SWC I/O Base Address: low %d, high %d, res %d\n", addr_l, addr_h, swc_base_addr); + #endif + + return swc_base_addr; +} + +static void +pc87413_swc_bank3(unsigned int swc_base_addr) +{ + /* Step 4: Select Bank3 of SWC */ + + outb_p (inb (swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f); + + #ifdef DEBUG + printk(KERN_INFO DPFX "Select Bank3 of SWC\n"); + #endif + +} + +static void +pc87413_programm_wdto (unsigned int swc_base_addr, char pc87413_time) +{ + /* Step 5: Programm WDTO, Twd. */ + + outb_p (pc87413_time, swc_base_addr + WDTO); + + #ifdef DEBUG + printk(KERN_INFO DPFX "Set WDTO to %d minutes\n", pc87413_time); + #endif +} + +static void +pc87413_enable_wden (unsigned int swc_base_addr) +{ + /* Step 6: Enable WDEN */ + + outb_p(inb (swc_base_addr + WDCTL) | 0x01, swc_base_addr + WDCTL); + + #ifdef DEBUG + printk(KERN_INFO DPFX "Enable WDEN\n"); + #endif +} + +static void +pc87413_enable_sw_wd_tren (unsigned int swc_base_addr) +{ + /* Enable SW_WD_TREN */ + + outb_p(inb (swc_base_addr + WDCFG) | 0x80, swc_base_addr + WDCFG); + + #ifdef DEBUG + printk(KERN_INFO DPFX "Enable SW_WD_TREN\n"); + #endif +} + +static void +pc87413_disable_sw_wd_tren (unsigned int swc_base_addr) +{ + /* Disable SW_WD_TREN */ + + outb_p(inb (swc_base_addr + WDCFG) & 0x7f, swc_base_addr + WDCFG); + + #ifdef DEBUG + printk(KERN_INFO DPFX "pc87413 - Disable SW_WD_TREN\n"); + #endif +} + + +static void +pc87413_enable_sw_wd_trg (unsigned int swc_base_addr) +{ + + /* Enable SW_WD_TRG */ + + outb_p(inb (swc_base_addr + WDCTL) | 0x80, swc_base_addr + WDCTL); + + #ifdef DEBUG + printk(KERN_INFO DPFX "pc87413 - Enable SW_WD_TRG\n"); + #endif +} + +static void +pc87413_disable_sw_wd_trg (unsigned int swc_base_addr) +{ + + /* Disable SW_WD_TRG */ + + outb_p(inb (swc_base_addr + WDCTL) & 0x7f, swc_base_addr + WDCTL); + + #ifdef DEBUG + printk(KERN_INFO DPFX "Disable SW_WD_TRG\n"); + #endif +} + + + +static void +pc87413_disable(void) +{ + unsigned int swc_base_addr; + + pc87413_select_wdt_out(); + pc87413_enable_swc(); + swc_base_addr = pc87413_get_swc_base(); + pc87413_swc_bank3(swc_base_addr); + pc87413_disable_sw_wd_tren(swc_base_addr); + pc87413_disable_sw_wd_trg(swc_base_addr); + pc87413_programm_wdto(swc_base_addr, 0); +} + + +static void +pc87413_refresh(char pc87413_time) +{ + unsigned int swc_base_addr; + + pc87413_select_wdt_out(); + pc87413_enable_swc(); + swc_base_addr = pc87413_get_swc_base(); + pc87413_swc_bank3(swc_base_addr); + pc87413_disable_sw_wd_tren(swc_base_addr); + pc87413_disable_sw_wd_trg(swc_base_addr); + pc87413_programm_wdto(swc_base_addr, pc87413_time); + pc87413_enable_wden(swc_base_addr); + pc87413_enable_sw_wd_tren(swc_base_addr); + pc87413_enable_sw_wd_trg(swc_base_addr); +} + + +static void +pc87413_enable(char pc87413_time) +{ + unsigned int swc_base_addr; + + pc87413_select_wdt_out(); + pc87413_enable_swc(); + swc_base_addr = pc87413_get_swc_base(); + pc87413_swc_bank3(swc_base_addr); + pc87413_programm_wdto(swc_base_addr, pc87413_time); + pc87413_enable_wden(swc_base_addr); + pc87413_enable_sw_wd_tren(swc_base_addr); + pc87413_enable_sw_wd_trg(swc_base_addr); + +} + + +/******************************************* + * Kernel methods. + *******************************************/ + + +/** + * pc87413_status: + * + * Extract the status information from a WDT watchdog device. There are + * several board variants so we have to know which bits are valid. Some + * bits default to one and some to zero in order to be maximally painful. + * + * we then map the bits onto the status ioctl flags. + */ + +static int pc87413_status(void) +{ + /* Not supported */ + + return 1; +} + +static long long pc87413_llseek(struct file *file, long long offset, int origin) +{ + return -ESPIPE; +} + +/** + * pc87413_write: + * @file: file handle to the watchdog + * @buf: buffer to write (unused as data does not matter here + * @count: count of bytes + * @ppos: pointer to the position to write. No seeks allowed + * + * A write to a watchdog device is defined as a keepalive signal. Any + * write of data will do, as we we don't define content meaning. + */ + +static ssize_t +pc87413_write (struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + if (count) { + pc87413_refresh (WD_TIMEOUT); + #ifdef DEBUG + printk(KERN_INFO DPFX "Write\n"); + #endif + } + return count; +} + +/* + * Read reports the temperature in degrees Fahrenheit. + */ +static ssize_t +pc87413_read(struct file *file, char *buf, size_t count, loff_t *ptr) +{ + +// char timeout; +// +// outb_p(0x08, WDT_EFER); /* Select locical device 8 */ +// outb_p(0x0F6, WDT_EFER); /* Select CRF6 */ +// timeout = inb(WDT_EFDR); /* Read Timeout counter from CRF6 */ + + +// if(copy_to_user(buf,&timeout,1)) +// return -EFAULT; + return 1; + + +} + + /** + * pc87413_ioctl: + * @inode: inode of the device + * @file: file handle to the device + * @cmd: watchdog command + * @arg: argument pointer + * + * The watchdog API defines a common set of functions for all watchdogs + * according to their available features. We only actually usefully support + * querying capabilities and current status. + */ + +static int +pc87413_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident= + { + .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, + .firmware_version = 1, + .identity = "pc87413(HF/F)" + }; + + ident.options=1; /* Mask down to the card we have */ + + switch(cmd) + { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; + case WDIOC_GETSTATUS: + return put_user(pc87413_status(),(int *)arg); + case WDIOC_GETBOOTSTATUS: + return put_user(0, (int *)arg); + case WDIOC_KEEPALIVE: + pc87413_refresh(WD_TIMEOUT); + #ifdef DEBUG + printk(KERN_INFO DPFX "keepalive\n"); + #endif + return 0; + } +} + +/** + * pc87413_open: + * @inode: inode of device + * @file: file handle to device + * + * One of our two misc devices has been opened. The watchdog device is + * single open and on opening we load the counters. Counter zero is a + * 100Hz cascade, into counter 1 which downcounts to reboot. When the + * counter triggers counter 2 downcounts the length of the reset pulse + * which set set to be as long as possible. + */ + +static int +pc87413_open(struct inode *inode, struct file *file) +{ + switch(MINOR(inode->i_rdev)) + { + case WATCHDOG_MINOR: + if(pc87413_is_open) + return -EBUSY; + /* + * Activate + */ + + pc87413_is_open=1; + pc87413_refresh(WD_TIMEOUT); + #ifdef DEBUG + printk(KERN_INFO DPFX "Open\n"); + #endif + return 0; + case TEMP_MINOR: + return 0; + default: + return -ENODEV; + } +} + +/** + * pc87413_close: + * @inode: inode to board + * @file: file handle to board + * + * The watchdog has a configurable API. There is a religious dispute + * between people who want their watchdog to be able to shut down and + * those who want to be sure if the watchdog manager dies the machine + * reboots. In the former case we disable the counters, in the latter + * case you have to open it again very soon. + */ + +static int +pc87413_release(struct inode *inode, struct file *file) +{ + if(MINOR(inode->i_rdev)==WATCHDOG_MINOR) + { +#ifndef CONFIG_WATCHDOG_NOWAYOUT + pc87413_disable(); +#endif + pc87413_is_open=0; + #ifdef DEBUG + printk(KERN_INFO DPFX "Release\n"); + #endif + } + return 0; +} + +/** + * notify_sys: + * @this: our notifier block + * @code: the event being reported + * @unused: unused + * + * Our notifier is called on system shutdowns. We want to turn the card + * off at reboot otherwise the machine will reboot again during memory + * test or worse yet during the following fsck. This would suck, in fact + * trust me - if it happens it does suck. + */ + +static int +pc87413_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if(code==SYS_DOWN || code==SYS_HALT) + { + /* Turn the card off */ + pc87413_disable(); + } + return NOTIFY_DONE; +} + + +/***************************************************** + * Kernel Interfaces + *****************************************************/ + + +static struct file_operations pc87413_fops = { + .owner = THIS_MODULE, + .llseek = pc87413_llseek, + .read = pc87413_read, + .write = pc87413_write, + .ioctl = pc87413_ioctl, + .open = pc87413_open, + .release = pc87413_release, +}; + +static struct miscdevice pc87413_miscdev= +{ + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &pc87413_fops +}; + +/* + * The WDT card needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block pc87413_notifier= +{ + pc87413_notify_sys, + NULL, + 0 +}; + + +/** + * pc87413_exit: + * + * Unload the watchdog. You cannot do this with any file handles open. + * If your watchdog is set to continue ticking on close and you unload + * it, well it keeps ticking. We won't get the interrupt but the board + * will not touch PC memory so all is fine. You just have to load a new + * module in 60 seconds or reboot. + */ + +static void +pc87413_exit(void) +{ + pc87413_disable(); + misc_deregister(&pc87413_miscdev); + unregister_reboot_notifier(&pc87413_notifier); + /* release_region(io,2); */ +} + + +/** + * pc87413_init: + * + * Set up the WDT watchdog board. All we have to do is grab the + * resources we require and bitch if anyone beat us to them. + * The open() function will actually kick the board off. + */ + +static int +pc87413_init(void) +{ + int ret; + + printk(KERN_INFO PFX "Version 1.00 at io 0x%X\n", WDT_INDEX_IO_PORT); + + + /* request_region(io, 2, "pc87413"); */ + + + ret = register_reboot_notifier(&pc87413_notifier); + if (ret != 0) { + printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", + ret); + } + + + + ret = misc_register(&pc87413_miscdev); + + if (ret != 0) { + printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", + WATCHDOG_MINOR, ret); + unregister_reboot_notifier(&pc87413_notifier); + return ret; + } + + printk (KERN_INFO PFX "initialized. timeout=%d min \n", timeout); + + + pc87413_enable(WD_TIMEOUT); + + return 0; +} + + +module_init(pc87413_init); +module_exit(pc87413_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Marcus Junker , Sven Anders "); +MODULE_DESCRIPTION("PC87413 WDT driver"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); + -- cgit v1.2.3 From 00b3b3e6605d7446cd410c7c9bb98f5336a15ca1 Mon Sep 17 00:00:00 2001 From: Sven Anders & Marcus Junker Date: Mon, 16 Oct 2006 18:18:09 +0200 Subject: [WATCHDOG] NS pc87413-wdt Watchdog driver v1.1 Change the driver for proper spin_locking, remove the TEMP_MINOR stuff, make sure the device works as a Virtual File System that is non_seekable, ... Signed-off-by: Sven Anders Signed-off-by: Marcus Junker Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/pc87413_wdt.c | 634 +++++++++++++++++++----------------- 1 file changed, 330 insertions(+), 304 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/pc87413_wdt.c b/drivers/char/watchdog/pc87413_wdt.c index a6d42cf385e..4d5612146cd 100644 --- a/drivers/char/watchdog/pc87413_wdt.c +++ b/drivers/char/watchdog/pc87413_wdt.c @@ -1,27 +1,23 @@ /* * NS pc87413-wdt Watchdog Timer driver for Linux 2.6.x.x * - * This code is based on wdt.c with original copyright + * This code is based on wdt.c with original copyright. * - * (C) Copyright 2006 Marcus Junker, - * and Sven Anders, + * (C) Copyright 2006 Sven Anders, + * and Marcus Junker, * * 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 of the License, or (at your option) any later version. * - * Neither Marcus Junker, Sven Anders nor ANDURAS AG + * Neither Sven Anders, Marcus Junker nor ANDURAS AG * admit liability nor provide warranty for any of this software. * This material is provided "AS-IS" and at no charge. * - * Release 1.00. - * + * Release 1.1 */ - -/* #define DEBUG 1 */ - #include #include #include @@ -41,57 +37,44 @@ #include #include -#define WATCHDOG_NAME "pc87413 WDT" -#define PFX WATCHDOG_NAME ": " -#define DPFX WATCHDOG_NAME " - DEBUG: " - -#define WDT_INDEX_IO_PORT (io+0) /* */ -#define WDT_DATA_IO_PORT (WDT_INDEX_IO_PORT+1) -#define SWC_LDN 0x04 -#define SIOCFG2 0x22 /* Serial IO register */ -#define WDCTL 0x10 /* Watchdog-Timer-Controll-Register */ -#define WDTO 0x11 /* Watchdog timeout register */ -#define WDCFG 0x12 /* Watchdog config register */ - -#define WD_TIMEOUT 1 /* minutes (1 ... 255) */ +/* #define DEBUG 1 */ +#define DEFAULT_TIMEOUT 1 /* 1 minute */ +#define MAX_TIMEOUT 255 -static int pc87413_is_open=0; +#define VERSION "1.1" +#define MODNAME "pc87413 WDT" +#define PFX MODNAME ": " +#define DPFX MODNAME " - DEBUG: " -/* - * You must set these - there is no sane way to probe for this board. - * You can use pc87413=x to set these now. - */ +#define WDT_INDEX_IO_PORT (io+0) /* I/O port base (index register) */ +#define WDT_DATA_IO_PORT (WDT_INDEX_IO_PORT+1) +#define SWC_LDN 0x04 +#define SIOCFG2 0x22 /* Serial IO register */ +#define WDCTL 0x10 /* Watchdog-Timer-Controll-Register */ +#define WDTO 0x11 /* Watchdog timeout register */ +#define WDCFG 0x12 /* Watchdog config register */ +static int io = 0x2E; /* Address used on Portwell Boards */ +static int timeout = DEFAULT_TIMEOUT; /* timeout value */ +static unsigned long timer_enabled = 0; /* is the timer enabled? */ -/** - * module_params - * - * Setup options. The board isn't really probe-able so we have to - * get the user to tell us the configuration. - */ +static char expect_close; /* is the close expected? */ -static int io=0x2E; /* Normally used addres on Portwell Boards */ -module_param(io, int, 0); -MODULE_PARM_DESC(wdt_io, WATCHDOG_NAME " io port (default 0x2E)"); +static spinlock_t io_lock; /* to guard the watchdog from io races */ -static int timeout = WD_TIMEOUT; /* in minutes */ -module_param(timeout, int, 0); -MODULE_PARM_DESC(timeout, "Watchdog timeout in minutes. 1<= timeout <=63, default=" __MODULE_STRING(WD_TIMEOUT) "."); +static int nowayout = WATCHDOG_NOWAYOUT; +/* -- Low level function ----------------------------------------*/ -/****************************************** - * Helper functions - ******************************************/ +/* Select pins for Watchdog output */ -static void -pc87413_select_wdt_out (void) +static inline void pc87413_select_wdt_out (void) { + unsigned int cr_data = 0; - unsigned int cr_data=0; - - /* Select multiple pin,pin55,as WDT output */ + /* Step 1: Select multiple pin,pin55,as WDT output */ outb_p(SIOCFG2, WDT_INDEX_IO_PORT); @@ -102,17 +85,17 @@ pc87413_select_wdt_out (void) outb_p(cr_data, WDT_DATA_IO_PORT); - - #ifdef DEBUG - printk(KERN_INFO DPFX "Select multiple pin,pin55,as WDT output: Bit7 to 1: %d\n", cr_data); - #endif +#ifdef DEBUG + printk(KERN_INFO DPFX "Select multiple pin,pin55,as WDT output:" + " Bit7 to 1: %d\n", cr_data); +#endif } -static void -pc87413_enable_swc(void) -{ +/* Enable SWC functions */ - unsigned int cr_data=0; +static inline void pc87413_enable_swc(void) +{ + unsigned int cr_data=0; /* Step 2: Enable SWC functions */ @@ -120,150 +103,162 @@ pc87413_enable_swc(void) outb_p(SWC_LDN, WDT_DATA_IO_PORT); outb_p(0x30, WDT_INDEX_IO_PORT); /* Read Index 0x30 First */ - cr_data = inb (WDT_DATA_IO_PORT); + cr_data = inb(WDT_DATA_IO_PORT); cr_data |= 0x01; /* Set Bit0 to 1 */ outb_p(0x30, WDT_INDEX_IO_PORT); outb_p(cr_data, WDT_DATA_IO_PORT); /* Index0x30_bit0P1 */ - #ifdef DEBUG +#ifdef DEBUG printk(KERN_INFO DPFX "pc87413 - Enable SWC functions\n"); - #endif +#endif } -static unsigned int -pc87413_get_swc_base(void) +/* Read SWC I/O base address */ + +static inline unsigned int pc87413_get_swc_base(void) { - unsigned int swc_base_addr = 0; - unsigned char addr_l, addr_h = 0; + unsigned int swc_base_addr = 0; + unsigned char addr_l, addr_h = 0; /* Step 3: Read SWC I/O Base Address */ outb_p(0x60, WDT_INDEX_IO_PORT); /* Read Index 0x60 */ - addr_h = inb (WDT_DATA_IO_PORT); + addr_h = inb(WDT_DATA_IO_PORT); outb_p(0x61, WDT_INDEX_IO_PORT); /* Read Index 0x61 */ - addr_l = inb (WDT_DATA_IO_PORT); - + addr_l = inb(WDT_DATA_IO_PORT); swc_base_addr = (addr_h << 8) + addr_l; - #ifdef DEBUG - printk(KERN_INFO DPFX "Read SWC I/O Base Address: low %d, high %d, res %d\n", addr_l, addr_h, swc_base_addr); - #endif +#ifdef DEBUG + printk(KERN_INFO DPFX "Read SWC I/O Base Address: low %d, high %d," + " res %d\n", addr_l, addr_h, swc_base_addr); +#endif return swc_base_addr; } -static void -pc87413_swc_bank3(unsigned int swc_base_addr) +/* Select Bank 3 of SWC */ + +static inline void pc87413_swc_bank3(unsigned int swc_base_addr) { /* Step 4: Select Bank3 of SWC */ - outb_p (inb (swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f); + outb_p(inb(swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f); - #ifdef DEBUG +#ifdef DEBUG printk(KERN_INFO DPFX "Select Bank3 of SWC\n"); - #endif - +#endif } -static void -pc87413_programm_wdto (unsigned int swc_base_addr, char pc87413_time) +/* Set watchdog timeout to x minutes */ + +static inline void pc87413_programm_wdto(unsigned int swc_base_addr, + char pc87413_time) { /* Step 5: Programm WDTO, Twd. */ - outb_p (pc87413_time, swc_base_addr + WDTO); + outb_p(pc87413_time, swc_base_addr + WDTO); - #ifdef DEBUG +#ifdef DEBUG printk(KERN_INFO DPFX "Set WDTO to %d minutes\n", pc87413_time); - #endif +#endif } -static void -pc87413_enable_wden (unsigned int swc_base_addr) +/* Enable WDEN */ + +static inline void pc87413_enable_wden(unsigned int swc_base_addr) { /* Step 6: Enable WDEN */ outb_p(inb (swc_base_addr + WDCTL) | 0x01, swc_base_addr + WDCTL); - #ifdef DEBUG +#ifdef DEBUG printk(KERN_INFO DPFX "Enable WDEN\n"); - #endif +#endif } -static void -pc87413_enable_sw_wd_tren (unsigned int swc_base_addr) +/* Enable SW_WD_TREN */ +static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr) { /* Enable SW_WD_TREN */ outb_p(inb (swc_base_addr + WDCFG) | 0x80, swc_base_addr + WDCFG); - #ifdef DEBUG +#ifdef DEBUG printk(KERN_INFO DPFX "Enable SW_WD_TREN\n"); - #endif +#endif } -static void -pc87413_disable_sw_wd_tren (unsigned int swc_base_addr) +/* Disable SW_WD_TREN */ + +static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr) { /* Disable SW_WD_TREN */ outb_p(inb (swc_base_addr + WDCFG) & 0x7f, swc_base_addr + WDCFG); - #ifdef DEBUG +#ifdef DEBUG printk(KERN_INFO DPFX "pc87413 - Disable SW_WD_TREN\n"); - #endif +#endif } +/* Enable SW_WD_TRG */ -static void -pc87413_enable_sw_wd_trg (unsigned int swc_base_addr) +static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr) { - /* Enable SW_WD_TRG */ outb_p(inb (swc_base_addr + WDCTL) | 0x80, swc_base_addr + WDCTL); - #ifdef DEBUG +#ifdef DEBUG printk(KERN_INFO DPFX "pc87413 - Enable SW_WD_TRG\n"); - #endif +#endif } -static void -pc87413_disable_sw_wd_trg (unsigned int swc_base_addr) -{ +/* Disable SW_WD_TRG */ +static inline void pc87413_disable_sw_wd_trg(unsigned int swc_base_addr) +{ /* Disable SW_WD_TRG */ outb_p(inb (swc_base_addr + WDCTL) & 0x7f, swc_base_addr + WDCTL); - #ifdef DEBUG +#ifdef DEBUG printk(KERN_INFO DPFX "Disable SW_WD_TRG\n"); - #endif +#endif } +/* -- Higher level functions ------------------------------------*/ +/* Enable the watchdog */ -static void -pc87413_disable(void) +static void pc87413_enable(void) { - unsigned int swc_base_addr; + unsigned int swc_base_addr; + + spin_lock(&io_lock); pc87413_select_wdt_out(); pc87413_enable_swc(); swc_base_addr = pc87413_get_swc_base(); pc87413_swc_bank3(swc_base_addr); - pc87413_disable_sw_wd_tren(swc_base_addr); - pc87413_disable_sw_wd_trg(swc_base_addr); - pc87413_programm_wdto(swc_base_addr, 0); + pc87413_programm_wdto(swc_base_addr, timeout); + pc87413_enable_wden(swc_base_addr); + pc87413_enable_sw_wd_tren(swc_base_addr); + pc87413_enable_sw_wd_trg(swc_base_addr); + + spin_unlock(&io_lock); } +/* Disable the watchdog */ -static void -pc87413_refresh(char pc87413_time) +static void pc87413_disable(void) { - unsigned int swc_base_addr; + unsigned int swc_base_addr; + + spin_lock(&io_lock); pc87413_select_wdt_out(); pc87413_enable_swc(); @@ -271,102 +266,144 @@ pc87413_refresh(char pc87413_time) pc87413_swc_bank3(swc_base_addr); pc87413_disable_sw_wd_tren(swc_base_addr); pc87413_disable_sw_wd_trg(swc_base_addr); - pc87413_programm_wdto(swc_base_addr, pc87413_time); - pc87413_enable_wden(swc_base_addr); - pc87413_enable_sw_wd_tren(swc_base_addr); - pc87413_enable_sw_wd_trg(swc_base_addr); + pc87413_programm_wdto(swc_base_addr, 0); + + spin_unlock(&io_lock); } +/* Refresh the watchdog */ -static void -pc87413_enable(char pc87413_time) +static void pc87413_refresh(void) { - unsigned int swc_base_addr; + unsigned int swc_base_addr; + + spin_lock(&io_lock); pc87413_select_wdt_out(); pc87413_enable_swc(); swc_base_addr = pc87413_get_swc_base(); pc87413_swc_bank3(swc_base_addr); - pc87413_programm_wdto(swc_base_addr, pc87413_time); + pc87413_disable_sw_wd_tren(swc_base_addr); + pc87413_disable_sw_wd_trg(swc_base_addr); + pc87413_programm_wdto(swc_base_addr, timeout); pc87413_enable_wden(swc_base_addr); pc87413_enable_sw_wd_tren(swc_base_addr); pc87413_enable_sw_wd_trg(swc_base_addr); + spin_unlock(&io_lock); } +/* -- File operations -------------------------------------------*/ + +/** + * pc87413_open: + * @inode: inode of device + * @file: file handle to device + * + */ + +static int pc87413_open(struct inode *inode, struct file *file) +{ + /* /dev/watchdog can only be opened once */ + + if (test_and_set_bit(0, &timer_enabled)) + return -EBUSY; + + if (nowayout) + __module_get(THIS_MODULE); -/******************************************* - * Kernel methods. - *******************************************/ + /* Reload and activate timer */ + pc87413_refresh(); + printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to" + " %d minute(s).\n", timeout); + + return nonseekable_open(inode, file); +} /** - * pc87413_status: - * - * Extract the status information from a WDT watchdog device. There are - * several board variants so we have to know which bits are valid. Some - * bits default to one and some to zero in order to be maximally painful. + * pc87413_release: + * @inode: inode to board + * @file: file handle to board * - * we then map the bits onto the status ioctl flags. + * The watchdog has a configurable API. There is a religious dispute + * between people who want their watchdog to be able to shut down and + * those who want to be sure if the watchdog manager dies the machine + * reboots. In the former case we disable the counters, in the latter + * case you have to open it again very soon. */ -static int pc87413_status(void) +static int pc87413_release(struct inode *inode, struct file *file) { - /* Not supported */ + /* Shut off the timer. */ + + if (expect_close == 42) { + pc87413_disable(); + printk(KERN_INFO MODNAME "Watchdog disabled," + " sleeping again...\n"); + } else { + printk(KERN_CRIT MODNAME "Unexpected close, not stopping" + " watchdog!\n"); + pc87413_refresh(); + } + + clear_bit(0, &timer_enabled); + expect_close = 0; - return 1; + return 0; } -static long long pc87413_llseek(struct file *file, long long offset, int origin) +/** + * pc87413_status: + * + * return, if the watchdog is enabled (timeout is set...) + */ + + +static int pc87413_status(void) { - return -ESPIPE; + return 1; /* currently not supported */ } /** * pc87413_write: * @file: file handle to the watchdog - * @buf: buffer to write (unused as data does not matter here - * @count: count of bytes + * @data: data buffer to write + * @len: length in bytes * @ppos: pointer to the position to write. No seeks allowed * * A write to a watchdog device is defined as a keepalive signal. Any * write of data will do, as we we don't define content meaning. */ -static ssize_t -pc87413_write (struct file *file, const char __user *buf, size_t count, loff_t *ppos) +static ssize_t pc87413_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) { - if (count) { - pc87413_refresh (WD_TIMEOUT); - #ifdef DEBUG - printk(KERN_INFO DPFX "Write\n"); - #endif + /* See if we got the magic character 'V' and reload the timer */ + if (len) { + if (!nowayout) { + size_t i; + + /* reset expect flag */ + expect_close = 0; + + /* scan to see whether or not we got the magic character */ + for (i = 0; i != len; i++) { + char c; + if (get_user(c, data+i)) + return -EFAULT; + if (c == 'V') + expect_close = 42; + } + } + + /* someone wrote to us, we should reload the timer */ + pc87413_refresh(); } - return count; -} - -/* - * Read reports the temperature in degrees Fahrenheit. - */ -static ssize_t -pc87413_read(struct file *file, char *buf, size_t count, loff_t *ptr) -{ - -// char timeout; -// -// outb_p(0x08, WDT_EFER); /* Select locical device 8 */ -// outb_p(0x0F6, WDT_EFER); /* Select CRF6 */ -// timeout = inb(WDT_EFDR); /* Read Timeout counter from CRF6 */ - - -// if(copy_to_user(buf,&timeout,1)) -// return -EFAULT; - return 1; - - + return len; } - /** +/** * pc87413_ioctl: * @inode: inode of the device * @file: file handle to the device @@ -378,103 +415,92 @@ pc87413_read(struct file *file, char *buf, size_t count, loff_t *ptr) * querying capabilities and current status. */ -static int -pc87413_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) +static int pc87413_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - static struct watchdog_info ident= - { - .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, - .firmware_version = 1, - .identity = "pc87413(HF/F)" + int new_timeout; + + union { + struct watchdog_info __user *ident; + int __user *i; + } uarg; + + static struct watchdog_info ident = { + .options = WDIOF_KEEPALIVEPING | + WDIOF_SETTIMEOUT | + WDIOF_MAGICCLOSE, + .firmware_version = 1, + .identity = "PC87413(HF/F) watchdog" }; - ident.options=1; /* Mask down to the card we have */ + uarg.i = (int __user *)arg; - switch(cmd) - { + switch(cmd) { default: - return -ENOIOCTLCMD; + return -ENOTTY; + case WDIOC_GETSUPPORT: - return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; + return copy_to_user(uarg.ident, &ident, + sizeof(ident)) ? -EFAULT : 0; + case WDIOC_GETSTATUS: - return put_user(pc87413_status(),(int *)arg); + return put_user(pc87413_status(), uarg.i); + case WDIOC_GETBOOTSTATUS: - return put_user(0, (int *)arg); + return put_user(0, uarg.i); + case WDIOC_KEEPALIVE: - pc87413_refresh(WD_TIMEOUT); - #ifdef DEBUG - printk(KERN_INFO DPFX "keepalive\n"); - #endif + pc87413_refresh(); +#ifdef DEBUG + printk(KERN_INFO DPFX "keepalive\n"); +#endif return 0; - } -} -/** - * pc87413_open: - * @inode: inode of device - * @file: file handle to device - * - * One of our two misc devices has been opened. The watchdog device is - * single open and on opening we load the counters. Counter zero is a - * 100Hz cascade, into counter 1 which downcounts to reboot. When the - * counter triggers counter 2 downcounts the length of the reset pulse - * which set set to be as long as possible. - */ + case WDIOC_SETTIMEOUT: + if (get_user(new_timeout, uarg.i)) + return -EFAULT; -static int -pc87413_open(struct inode *inode, struct file *file) -{ - switch(MINOR(inode->i_rdev)) - { - case WATCHDOG_MINOR: - if(pc87413_is_open) - return -EBUSY; - /* - * Activate - */ - - pc87413_is_open=1; - pc87413_refresh(WD_TIMEOUT); - #ifdef DEBUG - printk(KERN_INFO DPFX "Open\n"); - #endif - return 0; - case TEMP_MINOR: - return 0; - default: - return -ENODEV; - } -} + // the API states this is given in secs + new_timeout /= 60; -/** - * pc87413_close: - * @inode: inode to board - * @file: file handle to board - * - * The watchdog has a configurable API. There is a religious dispute - * between people who want their watchdog to be able to shut down and - * those who want to be sure if the watchdog manager dies the machine - * reboots. In the former case we disable the counters, in the latter - * case you have to open it again very soon. - */ + if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) + return -EINVAL; -static int -pc87413_release(struct inode *inode, struct file *file) -{ - if(MINOR(inode->i_rdev)==WATCHDOG_MINOR) - { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - pc87413_disable(); -#endif - pc87413_is_open=0; - #ifdef DEBUG - printk(KERN_INFO DPFX "Release\n"); - #endif + timeout = new_timeout; + pc87413_refresh(); + + // fall through and return the new timeout... + + case WDIOC_GETTIMEOUT: + + new_timeout = timeout * 60; + + return put_user(new_timeout, uarg.i); + + case WDIOC_SETOPTIONS: + { + int options, retval = -EINVAL; + + if (get_user(options, uarg.i)) + return -EFAULT; + + if (options & WDIOS_DISABLECARD) { + pc87413_disable(); + retval = 0; + } + + if (options & WDIOS_ENABLECARD) { + pc87413_enable(); + retval = 0; + } + + return retval; + } } - return 0; } +/* -- Notifier funtions -----------------------------------------*/ + /** * notify_sys: * @this: our notifier block @@ -487,11 +513,11 @@ pc87413_release(struct inode *inode, struct file *file) * trust me - if it happens it does suck. */ -static int -pc87413_notify_sys(struct notifier_block *this, unsigned long code, - void *unused) +static int pc87413_notify_sys(struct notifier_block *this, + unsigned long code, + void *unused) { - if(code==SYS_DOWN || code==SYS_HALT) + if (code == SYS_DOWN || code == SYS_HALT) { /* Turn the card off */ pc87413_disable(); @@ -499,112 +525,112 @@ pc87413_notify_sys(struct notifier_block *this, unsigned long code, return NOTIFY_DONE; } - -/***************************************************** - * Kernel Interfaces - *****************************************************/ - +/* -- Module's structures ---------------------------------------*/ static struct file_operations pc87413_fops = { .owner = THIS_MODULE, - .llseek = pc87413_llseek, - .read = pc87413_read, + .llseek = no_llseek, .write = pc87413_write, .ioctl = pc87413_ioctl, .open = pc87413_open, .release = pc87413_release, }; -static struct miscdevice pc87413_miscdev= +static struct notifier_block pc87413_notifier = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &pc87413_fops + .notifier_call = pc87413_notify_sys, }; -/* - * The WDT card needs to learn about soft shutdowns in order to - * turn the timebomb registers off. - */ - -static struct notifier_block pc87413_notifier= +static struct miscdevice pc87413_miscdev= { - pc87413_notify_sys, - NULL, - 0 + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &pc87413_fops }; +/* -- Module init functions -------------------------------------*/ /** - * pc87413_exit: - * - * Unload the watchdog. You cannot do this with any file handles open. - * If your watchdog is set to continue ticking on close and you unload - * it, well it keeps ticking. We won't get the interrupt but the board - * will not touch PC memory so all is fine. You just have to load a new - * module in 60 seconds or reboot. - */ - -static void -pc87413_exit(void) -{ - pc87413_disable(); - misc_deregister(&pc87413_miscdev); - unregister_reboot_notifier(&pc87413_notifier); - /* release_region(io,2); */ -} - - -/** - * pc87413_init: + * pc87413_init: module's "constructor" * * Set up the WDT watchdog board. All we have to do is grab the * resources we require and bitch if anyone beat us to them. * The open() function will actually kick the board off. */ -static int -pc87413_init(void) +static int __init pc87413_init(void) { int ret; - printk(KERN_INFO PFX "Version 1.00 at io 0x%X\n", WDT_INDEX_IO_PORT); + spin_lock_init(&io_lock); + printk(KERN_INFO PFX "Version " VERSION " at io 0x%X\n", WDT_INDEX_IO_PORT); /* request_region(io, 2, "pc87413"); */ - ret = register_reboot_notifier(&pc87413_notifier); if (ret != 0) { - printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", - ret); + printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", + ret); } - - ret = misc_register(&pc87413_miscdev); if (ret != 0) { - printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", - WATCHDOG_MINOR, ret); + printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", + WATCHDOG_MINOR, ret); unregister_reboot_notifier(&pc87413_notifier); return ret; } - printk (KERN_INFO PFX "initialized. timeout=%d min \n", timeout); + printk(KERN_INFO PFX "initialized. timeout=%d min \n", timeout); - - pc87413_enable(WD_TIMEOUT); + pc87413_enable(); return 0; } +/** + * pc87413_exit: module's "destructor" + * + * Unload the watchdog. You cannot do this with any file handles open. + * If your watchdog is set to continue ticking on close and you unload + * it, well it keeps ticking. We won't get the interrupt but the board + * will not touch PC memory so all is fine. You just have to load a new + * module in 60 seconds or reboot. + */ + +static void __exit pc87413_exit(void) +{ + /* Stop the timer before we leave */ + if (!nowayout) + { + pc87413_disable(); + printk(KERN_INFO MODNAME "Watchdog disabled.\n"); + } + + misc_deregister(&pc87413_miscdev); + unregister_reboot_notifier(&pc87413_notifier); + /* release_region(io,2); */ + + printk(MODNAME " watchdog component driver removed.\n"); +} module_init(pc87413_init); module_exit(pc87413_exit); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Marcus Junker , Sven Anders "); +MODULE_AUTHOR("Sven Anders , Marcus Junker ,"); MODULE_DESCRIPTION("PC87413 WDT driver"); +MODULE_LICENSE("GPL"); + MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); +module_param(io, int, 0); +MODULE_PARM_DESC(wdt_io, MODNAME " I/O port (default: " __MODULE_STRING(io) ")."); + +module_param(timeout, int, 0); +MODULE_PARM_DESC(timeout, "Watchdog timeout in minutes (default=" __MODULE_STRING(timeout) ")."); + +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + -- cgit v1.2.3 From 0835caa2bf1933d5f41fd98e469107f4c00d547f Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Mon, 23 Oct 2006 18:21:52 +0200 Subject: [WATCHDOG] NS pc87413-wdt Watchdog driver - fixes Some small fixes: * the status should return 0 and not 1 (1 means: * wdt_io is not a module-param, io is. Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/pc87413_wdt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/pc87413_wdt.c b/drivers/char/watchdog/pc87413_wdt.c index 4d5612146cd..bd7727ba1ad 100644 --- a/drivers/char/watchdog/pc87413_wdt.c +++ b/drivers/char/watchdog/pc87413_wdt.c @@ -362,7 +362,7 @@ static int pc87413_release(struct inode *inode, struct file *file) static int pc87413_status(void) { - return 1; /* currently not supported */ + return 0; /* currently not supported */ } /** @@ -626,7 +626,7 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); module_param(io, int, 0); -MODULE_PARM_DESC(wdt_io, MODNAME " I/O port (default: " __MODULE_STRING(io) ")."); +MODULE_PARM_DESC(io, MODNAME " I/O port (default: " __MODULE_STRING(io) ")."); module_param(timeout, int, 0); MODULE_PARM_DESC(timeout, "Watchdog timeout in minutes (default=" __MODULE_STRING(timeout) ")."); -- cgit v1.2.3 From fd0c5eca447254682a8372bc73b6bdcc16bf6777 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 27 Oct 2006 17:20:42 -0700 Subject: [WATCHDOG] config.h removal config.h got removed Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/pc87413_wdt.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/pc87413_wdt.c b/drivers/char/watchdog/pc87413_wdt.c index bd7727ba1ad..1d447e32af4 100644 --- a/drivers/char/watchdog/pc87413_wdt.c +++ b/drivers/char/watchdog/pc87413_wdt.c @@ -18,7 +18,6 @@ * Release 1.1 */ -#include #include #include #include -- cgit v1.2.3 From 58c6570add83e30c0905885171fbffc134441165 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 29 Oct 2006 03:43:19 +0900 Subject: [WATCHDOG] sc1200wdt.c pnp unregister fix. If no devices found or invalid parameter is specified, scl200wdt_pnp_driver is left unregistered. It breaks global list of pnp drivers. Signed-off-by: Akinobu Mita Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/sc1200wdt.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c index d8d0f28e0ac..e3239833e4b 100644 --- a/drivers/char/watchdog/sc1200wdt.c +++ b/drivers/char/watchdog/sc1200wdt.c @@ -392,7 +392,7 @@ static int __init sc1200wdt_init(void) if (io == -1) { printk(KERN_ERR PFX "io parameter must be specified\n"); ret = -EINVAL; - goto out_clean; + goto out_pnp; } #if defined CONFIG_PNP @@ -405,7 +405,7 @@ static int __init sc1200wdt_init(void) if (!request_region(io, io_len, SC1200_MODULE_NAME)) { printk(KERN_ERR PFX "Unable to register IO port %#x\n", io); ret = -EBUSY; - goto out_clean; + goto out_pnp; } ret = sc1200wdt_probe(); @@ -435,6 +435,11 @@ out_rbt: out_io: release_region(io, io_len); +out_pnp: +#if defined CONFIG_PNP + if (isapnp) + pnp_unregister_driver(&scl200wdt_pnp_driver); +#endif goto out_clean; } -- cgit v1.2.3 From e033351d5359f348d2913eb83fbb37023d8f21af Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Sun, 12 Nov 2006 18:05:09 +0100 Subject: [WATCHDOG] Add iTCO vendor specific support Add vendor specific support to the intel TCO timer based watchdog devices. At this moment we only have additional support for some SuperMicro Inc. motherboards. Signed-off-by: Robert Seretny Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/Kconfig | 8 + drivers/char/watchdog/Makefile | 2 +- drivers/char/watchdog/iTCO_vendor_support.c | 307 ++++++++++++++++++++++++++++ drivers/char/watchdog/iTCO_wdt.c | 29 ++- 4 files changed, 342 insertions(+), 4 deletions(-) create mode 100644 drivers/char/watchdog/iTCO_vendor_support.c (limited to 'drivers/char') diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index d3e99982b69..a52ecad7d56 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -340,6 +340,14 @@ config ITCO_WDT To compile this driver as a module, choose M here: the module will be called iTCO_wdt. +config ITCO_VENDOR_SUPPORT + bool "Intel TCO Timer/Watchdog Specific Vendor Support" + depends on ITCO_WDT + ---help--- + Add vendor specific support to the intel TCO timer based watchdog + devices. At this moment we only have additional support for some + SuperMicro Inc. motherboards. + config SC1200_WDT tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog" depends on WATCHDOG && X86 diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index e6a9f6f1d4b..81abdfa10a0 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -47,7 +47,7 @@ obj-$(CONFIG_IBMASR) += ibmasr.o obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o -obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o +obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o diff --git a/drivers/char/watchdog/iTCO_vendor_support.c b/drivers/char/watchdog/iTCO_vendor_support.c new file mode 100644 index 00000000000..41508399009 --- /dev/null +++ b/drivers/char/watchdog/iTCO_vendor_support.c @@ -0,0 +1,307 @@ +/* + * intel TCO vendor specific watchdog driver support + * + * (c) Copyright 2006 Wim Van Sebroeck . + * + * 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 of the License, or (at your option) any later version. + * + * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + */ + +/* + * Includes, defines, variables, module parameters, ... + */ + +/* Module and version information */ +#define DRV_NAME "iTCO_vendor_support" +#define DRV_VERSION "1.01" +#define DRV_RELDATE "11-Nov-2006" +#define PFX DRV_NAME ": " + +/* Includes */ +#include /* For module specific items */ +#include /* For new moduleparam's */ +#include /* For standard types (like size_t) */ +#include /* For the -ENODEV/... values */ +#include /* For printk/panic/... */ +#include /* For __init/__exit/... */ +#include /* For io-port access */ + +#include /* For inb/outb/... */ + +/* iTCO defines */ +#define SMI_EN acpibase + 0x30 /* SMI Control and Enable Register */ +#define TCOBASE acpibase + 0x60 /* TCO base address */ +#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */ + +/* List of vendor support modes */ +#define SUPERMICRO_OLD_BOARD 1 /* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */ +#define SUPERMICRO_NEW_BOARD 2 /* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems */ + +static int vendorsupport = 0; +module_param(vendorsupport, int, 0); +MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+"); + +/* + * Vendor Specific Support + */ + +/* + * Vendor Support: 1 + * Board: Super Micro Computer Inc. 370SSE+-OEM1/P3TSSE + * iTCO chipset: ICH2 + * + * Code contributed by: R. Seretny + * Documentation obtained by R. Seretny from SuperMicro Technical Support + * + * To enable Watchdog function: + * BIOS setup -> Power -> TCO Logic SMI Enable -> Within5Minutes + * This setting enables SMI to clear the watchdog expired flag. + * If BIOS or CPU fail which may cause SMI hang, then system will + * reboot. When application starts to use watchdog function, + * application has to take over the control from SMI. + * + * For P3TSSE, J36 jumper needs to be removed to enable the Watchdog + * function. + * + * Note: The system will reboot when Expire Flag is set TWICE. + * So, if the watchdog timer is 20 seconds, then the maximum hang + * time is about 40 seconds, and the minimum hang time is about + * 20.6 seconds. + */ + +static void supermicro_old_pre_start(unsigned long acpibase) +{ + unsigned long val32; + + val32 = inl(SMI_EN); + val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ + outl(val32, SMI_EN); /* Needed to activate watchdog */ +} + +static void supermicro_old_pre_stop(unsigned long acpibase) +{ + unsigned long val32; + + val32 = inl(SMI_EN); + val32 &= 0x00002000; /* Turn on SMI clearing watchdog */ + outl(val32, SMI_EN); /* Needed to deactivate watchdog */ +} + +static void supermicro_old_pre_keepalive(unsigned long acpibase) +{ + /* Reload TCO Timer (done in iTCO_wdt_keepalive) + */ + /* Clear "Expire Flag" (Bit 3 of TC01_STS register) */ + outb(0x08, TCO1_STS); +} + +/* + * Vendor Support: 2 + * Board: Super Micro Computer Inc. P4SBx, P4DPx + * iTCO chipset: ICH4 + * + * Code contributed by: R. Seretny + * Documentation obtained by R. Seretny from SuperMicro Technical Support + * + * To enable Watchdog function: + * 1. BIOS + * For P4SBx: + * BIOS setup -> Advanced -> Integrated Peripherals -> Watch Dog Feature + * For P4DPx: + * BIOS setup -> Advanced -> I/O Device Configuration -> Watch Dog + * This setting enables or disables Watchdog function. When enabled, the + * default watchdog timer is set to be 5 minutes (about 4’35”). It is + * enough to load and run the OS. The application (service or driver) has + * to take over the control once OS is running up and before watchdog + * expires. + * + * 2. JUMPER + * For P4SBx: JP39 + * For P4DPx: JP37 + * This jumper is used for safety. Closed is enabled. This jumper + * prevents user enables watchdog in BIOS by accident. + * + * To enable Watch Dog function, both BIOS and JUMPER must be enabled. + * + * The documentation lists motherboards P4SBx and P4DPx series as of + * 20-March-2002. However, this code works flawlessly with much newer + * motherboards, such as my X6DHR-8G2 (SuperServer 6014H-82). + * + * The original iTCO driver as written does not actually reset the + * watchdog timer on these machines, as a result they reboot after five + * minutes. + * + * NOTE: You may leave the Watchdog function disabled in the SuperMicro + * BIOS to avoid a "boot-race"... This driver will enable watchdog + * functionality even if it's disabled in the BIOS once the /dev/watchdog + * file is opened. + */ + +/* I/O Port's */ +#define SM_REGINDEX 0x2e /* SuperMicro ICH4+ Register Index */ +#define SM_DATAIO 0x2f /* SuperMicro ICH4+ Register Data I/O */ + +/* Control Register's */ +#define SM_CTLPAGESW 0x07 /* SuperMicro ICH4+ Control Page Switch */ +#define SM_CTLPAGE 0x08 /* SuperMicro ICH4+ Control Page Num */ + +#define SM_WATCHENABLE 0x30 /* Watchdog enable: Bit 0: 0=off, 1=on */ + +#define SM_WATCHPAGE 0x87 /* Watchdog unlock control page */ + +#define SM_ENDWATCH 0xAA /* Watchdog lock control page */ + +#define SM_COUNTMODE 0xf5 /* Watchdog count mode select */ + /* (Bit 3: 0 = seconds, 1 = minutes */ + +#define SM_WATCHTIMER 0xf6 /* 8-bits, Watchdog timer counter (RW) */ + +#define SM_RESETCONTROL 0xf7 /* Watchdog reset control */ + /* Bit 6: timer is reset by kbd interrupt */ + /* Bit 7: timer is reset by mouse interrupt */ + +static void supermicro_new_unlock_watchdog(void) +{ + outb(SM_WATCHPAGE, SM_REGINDEX); /* Write 0x87 to port 0x2e twice */ + outb(SM_WATCHPAGE, SM_REGINDEX); + + outb(SM_CTLPAGESW, SM_REGINDEX); /* Switch to watchdog control page */ + outb(SM_CTLPAGE, SM_DATAIO); +} + +static void supermicro_new_lock_watchdog(void) +{ + outb(SM_ENDWATCH, SM_REGINDEX); +} + +static void supermicro_new_pre_start(unsigned int heartbeat) +{ + unsigned int val; + + supermicro_new_unlock_watchdog(); + + /* Watchdog timer setting needs to be in seconds*/ + outb(SM_COUNTMODE, SM_REGINDEX); + val = inb(SM_DATAIO); + val &= 0xF7; + outb(val, SM_DATAIO); + + /* Write heartbeat interval to WDOG */ + outb (SM_WATCHTIMER, SM_REGINDEX); + outb((heartbeat & 255), SM_DATAIO); + + /* Make sure keyboard/mouse interrupts don't interfere */ + outb(SM_RESETCONTROL, SM_REGINDEX); + val = inb(SM_DATAIO); + val &= 0x3f; + outb(val, SM_DATAIO); + + /* enable watchdog by setting bit 0 of Watchdog Enable to 1 */ + outb(SM_WATCHENABLE, SM_REGINDEX); + val = inb(SM_DATAIO); + val |= 0x01; + outb(val, SM_DATAIO); + + supermicro_new_lock_watchdog(); +} + +static void supermicro_new_pre_stop(void) +{ + unsigned int val; + + supermicro_new_unlock_watchdog(); + + /* disable watchdog by setting bit 0 of Watchdog Enable to 0 */ + outb(SM_WATCHENABLE, SM_REGINDEX); + val = inb(SM_DATAIO); + val &= 0xFE; + outb(val, SM_DATAIO); + + supermicro_new_lock_watchdog(); +} + +static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat) +{ + supermicro_new_unlock_watchdog(); + + /* reset watchdog timeout to heartveat value */ + outb(SM_WATCHTIMER, SM_REGINDEX); + outb((heartbeat & 255), SM_DATAIO); + + supermicro_new_lock_watchdog(); +} + +/* + * Generic Support Functions + */ + +void iTCO_vendor_pre_start(unsigned long acpibase, + unsigned int heartbeat) +{ + if (vendorsupport == SUPERMICRO_OLD_BOARD) + supermicro_old_pre_start(acpibase); + else if (vendorsupport == SUPERMICRO_NEW_BOARD) + supermicro_new_pre_start(heartbeat); +} +EXPORT_SYMBOL(iTCO_vendor_pre_start); + +void iTCO_vendor_pre_stop(unsigned long acpibase) +{ + if (vendorsupport == SUPERMICRO_OLD_BOARD) + supermicro_old_pre_stop(acpibase); + else if (vendorsupport == SUPERMICRO_NEW_BOARD) + supermicro_new_pre_stop(); +} +EXPORT_SYMBOL(iTCO_vendor_pre_stop); + +void iTCO_vendor_pre_keepalive(unsigned long acpibase, unsigned int heartbeat) +{ + if (vendorsupport == SUPERMICRO_OLD_BOARD) + supermicro_old_pre_keepalive(acpibase); + else if (vendorsupport == SUPERMICRO_NEW_BOARD) + supermicro_new_pre_set_heartbeat(heartbeat); +} +EXPORT_SYMBOL(iTCO_vendor_pre_keepalive); + +void iTCO_vendor_pre_set_heartbeat(unsigned int heartbeat) +{ + if (vendorsupport == SUPERMICRO_NEW_BOARD) + supermicro_new_pre_set_heartbeat(heartbeat); +} +EXPORT_SYMBOL(iTCO_vendor_pre_set_heartbeat); + +int iTCO_vendor_check_noreboot_on(void) +{ + switch(vendorsupport) { + case SUPERMICRO_OLD_BOARD: + return 0; + default: + return 1; + } +} +EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on); + +static int __init iTCO_vendor_init_module(void) +{ + printk (KERN_INFO PFX "vendor-support=%d\n", vendorsupport); + return 0; +} + +static void __exit iTCO_vendor_exit_module(void) +{ + printk (KERN_INFO PFX "Module Unloaded\n"); +} + +module_init(iTCO_vendor_init_module); +module_exit(iTCO_vendor_exit_module); + +MODULE_AUTHOR("Wim Van Sebroeck , R. Seretny "); +MODULE_DESCRIPTION("Intel TCO Vendor Specific WatchDog Timer Driver Support"); +MODULE_VERSION(DRV_VERSION); +MODULE_LICENSE("GPL"); + diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c index b6f29cb8bd3..7eac922df86 100644 --- a/drivers/char/watchdog/iTCO_wdt.c +++ b/drivers/char/watchdog/iTCO_wdt.c @@ -48,8 +48,8 @@ /* Module and version information */ #define DRV_NAME "iTCO_wdt" -#define DRV_VERSION "1.00" -#define DRV_RELDATE "08-Oct-2006" +#define DRV_VERSION "1.01" +#define DRV_RELDATE "11-Nov-2006" #define PFX DRV_NAME ": " /* Includes */ @@ -189,6 +189,21 @@ static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +/* iTCO Vendor Specific Support hooks */ +#ifdef CONFIG_ITCO_VENDOR_SUPPORT +extern void iTCO_vendor_pre_start(unsigned long, unsigned int); +extern void iTCO_vendor_pre_stop(unsigned long); +extern void iTCO_vendor_pre_keepalive(unsigned long, unsigned int); +extern void iTCO_vendor_pre_set_heartbeat(unsigned int); +extern int iTCO_vendor_check_noreboot_on(void); +#else +#define iTCO_vendor_pre_start(acpibase, heartbeat) {} +#define iTCO_vendor_pre_stop(acpibase) {} +#define iTCO_vendor_pre_keepalive(acpibase,heartbeat) {} +#define iTCO_vendor_pre_set_heartbeat(heartbeat) {} +#define iTCO_vendor_check_noreboot_on() 1 /* 1=check noreboot; 0=don't check */ +#endif + /* * Some TCO specific functions */ @@ -249,6 +264,8 @@ static int iTCO_wdt_start(void) spin_lock(&iTCO_wdt_private.io_lock); + iTCO_vendor_pre_start(iTCO_wdt_private.ACPIBASE, heartbeat); + /* disable chipset's NO_REBOOT bit */ if (iTCO_wdt_unset_NO_REBOOT_bit()) { printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); @@ -273,6 +290,8 @@ static int iTCO_wdt_stop(void) spin_lock(&iTCO_wdt_private.io_lock); + iTCO_vendor_pre_stop(iTCO_wdt_private.ACPIBASE); + /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ val = inw(TCO1_CNT); val |= 0x0800; @@ -293,6 +312,8 @@ static int iTCO_wdt_keepalive(void) { spin_lock(&iTCO_wdt_private.io_lock); + iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat); + /* Reload the timer by writing to the TCO Timer Counter register */ if (iTCO_wdt_private.iTCO_version == 2) { outw(0x01, TCO_RLD); @@ -319,6 +340,8 @@ static int iTCO_wdt_set_heartbeat(int t) ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f))) return -EINVAL; + iTCO_vendor_pre_set_heartbeat(tmrval); + /* Write new heartbeat to watchdog */ if (iTCO_wdt_private.iTCO_version == 2) { spin_lock(&iTCO_wdt_private.io_lock); @@ -569,7 +592,7 @@ static int iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device_id *ent, } /* Check chipset's NO_REBOOT bit */ - if (iTCO_wdt_unset_NO_REBOOT_bit()) { + if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) { printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); ret = -ENODEV; /* Cannot reset NO_REBOOT bit */ goto out; -- cgit v1.2.3 From 825d3748c1b5f9272e4f9769f1c2da85174ece28 Mon Sep 17 00:00:00 2001 From: Thomas Koeller Date: Mon, 14 Aug 2006 21:55:29 +0200 Subject: [WATCHDOG] MIPS RM9000 on-chip watchdog device This is a driver for the on-chip watchdog device found on some MIPS RM9000 processors. Signed-off-by: Thomas Koeller Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/Kconfig | 10 + drivers/char/watchdog/Makefile | 1 + drivers/char/watchdog/rm9k_wdt.c | 431 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 442 insertions(+) create mode 100644 drivers/char/watchdog/rm9k_wdt.c (limited to 'drivers/char') diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index a52ecad7d56..ea09d0c974e 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -575,6 +575,16 @@ config INDYDOG timer expired and no process has written to /dev/watchdog during that time. +config WDT_RM9K_GPI + tristate "RM9000/GPI hardware watchdog" + depends on WATCHDOG && CPU_RM9000 + help + Watchdog implementation using the GPI hardware found on + PMC-Sierra RM9xxx CPUs. + + To compile this driver as a module, choose M here: the + module will be called rm9k_wdt. + # S390 Architecture config ZVM_WATCHDOG diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index 81abdfa10a0..2cd8ff8d10a 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o # MIPS Architecture obj-$(CONFIG_INDYDOG) += indydog.o +obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o # S390 Architecture diff --git a/drivers/char/watchdog/rm9k_wdt.c b/drivers/char/watchdog/rm9k_wdt.c new file mode 100644 index 00000000000..8cd12ab9bff --- /dev/null +++ b/drivers/char/watchdog/rm9k_wdt.c @@ -0,0 +1,431 @@ +/* + * Watchdog implementation for GPI h/w found on PMC-Sierra RM9xxx + * chips. + * + * Copyright (C) 2004 by Basler Vision Technologies AG + * Author: Thomas Koeller + * + * 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 of the License, 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; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#define CLOCK 125000000 +#define MAX_TIMEOUT_SECONDS 32 +#define CPCCR 0x0080 +#define CPGIG1SR 0x0044 +#define CPGIG1ER 0x0054 + + + +/* Function prototypes */ +static int __init wdt_gpi_probe(struct device *); +static int __exit wdt_gpi_remove(struct device *); +static void wdt_gpi_set_timeout(unsigned int); +static int wdt_gpi_open(struct inode *, struct file *); +static int wdt_gpi_release(struct inode *, struct file *); +static ssize_t wdt_gpi_write(struct file *, const char __user *, size_t, loff_t *); +static long wdt_gpi_ioctl(struct file *, unsigned int, unsigned long); +static const struct resource *wdt_gpi_get_resource(struct platform_device *, const char *, unsigned int); +static int wdt_gpi_notify(struct notifier_block *, unsigned long, void *); +static irqreturn_t wdt_gpi_irqhdl(int, void *, struct pt_regs *); + + + + +static const char wdt_gpi_name[] = "wdt_gpi"; +static atomic_t opencnt; +static int expect_close; +static int locked = 0; + + + +/* These are set from device resources */ +static void __iomem * wd_regs; +static unsigned int wd_irq, wd_ctr; + + + +/* Module arguments */ +static int timeout = MAX_TIMEOUT_SECONDS; +module_param(timeout, int, 0444); +static unsigned long resetaddr = 0xbffdc200; +module_param(resetaddr, ulong, 0444); +static unsigned long flagaddr = 0xbffdc104; +module_param(flagaddr, ulong, 0444); +static int powercycle = 0; +module_param(powercycle, bool, 0444); + +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, bool, 0444); + + + +static struct file_operations fops = { + .owner = THIS_MODULE, + .open = wdt_gpi_open, + .release = wdt_gpi_release, + .write = wdt_gpi_write, + .unlocked_ioctl = wdt_gpi_ioctl, +}; + +static struct miscdevice miscdev = { + .minor = WATCHDOG_MINOR, + .name = wdt_gpi_name, + .fops = &fops, +}; + +static struct device_driver wdt_gpi_driver = { + .name = (char *) wdt_gpi_name, + .bus = &platform_bus_type, + .owner = THIS_MODULE, + .probe = wdt_gpi_probe, + .remove = __exit_p(wdt_gpi_remove), + .shutdown = NULL, + .suspend = NULL, + .resume = NULL, +}; + +static struct notifier_block wdt_gpi_shutdown = { + .notifier_call = wdt_gpi_notify, +}; + + + +static const struct resource * +wdt_gpi_get_resource(struct platform_device *pdv, const char *name, + unsigned int type) +{ + char buf[80]; + if (snprintf(buf, sizeof buf, "%s_0", name) >= sizeof buf) + return NULL; + return platform_get_resource_byname(pdv, type, buf); +} + + + +/* No hotplugging on the platform bus - use __init */ +static int __init wdt_gpi_probe(struct device *dev) +{ + int res; + struct platform_device * const pdv = to_platform_device(dev); + const struct resource + * const rr = wdt_gpi_get_resource(pdv, WDT_RESOURCE_REGS, + IORESOURCE_MEM), + * const ri = wdt_gpi_get_resource(pdv, WDT_RESOURCE_IRQ, + IORESOURCE_IRQ), + * const rc = wdt_gpi_get_resource(pdv, WDT_RESOURCE_COUNTER, + 0); + + if (unlikely(!rr || !ri || !rc)) + return -ENXIO; + + wd_regs = ioremap_nocache(rr->start, rr->end + 1 - rr->start); + if (unlikely(!wd_regs)) + return -ENOMEM; + wd_irq = ri->start; + wd_ctr = rc->start; + res = misc_register(&miscdev); + if (res) + iounmap(wd_regs); + else + register_reboot_notifier(&wdt_gpi_shutdown); + return res; +} + + + +static int __exit wdt_gpi_remove(struct device *dev) +{ + int res; + + unregister_reboot_notifier(&wdt_gpi_shutdown); + res = misc_deregister(&miscdev); + iounmap(wd_regs); + wd_regs = NULL; + return res; +} + + +static void wdt_gpi_set_timeout(unsigned int to) +{ + u32 reg; + const u32 wdval = (to * CLOCK) & ~0x0000000f; + + lock_titan_regs(); + reg = titan_readl(CPCCR) & ~(0xf << (wd_ctr * 4)); + titan_writel(reg, CPCCR); + wmb(); + __raw_writel(wdval, wd_regs + 0x0000); + wmb(); + titan_writel(reg | (0x2 << (wd_ctr * 4)), CPCCR); + wmb(); + titan_writel(reg | (0x5 << (wd_ctr * 4)), CPCCR); + iob(); + unlock_titan_regs(); +} + + + +static int wdt_gpi_open(struct inode *i, struct file *f) +{ + int res; + u32 reg; + + if (unlikely(0 > atomic_dec_if_positive(&opencnt))) + return -EBUSY; + + expect_close = 0; + if (locked) { + module_put(THIS_MODULE); + free_irq(wd_irq, &miscdev); + locked = 0; + } + + res = request_irq(wd_irq, wdt_gpi_irqhdl, SA_SHIRQ | SA_INTERRUPT, + wdt_gpi_name, &miscdev); + if (unlikely(res)) + return res; + + wdt_gpi_set_timeout(timeout); + + lock_titan_regs(); + reg = titan_readl(CPGIG1ER); + titan_writel(reg | (0x100 << wd_ctr), CPGIG1ER); + iob(); + unlock_titan_regs(); + + printk(KERN_INFO "%s: watchdog started, timeout = %u seconds\n", + wdt_gpi_name, timeout); + return 0; +} + + + +static int wdt_gpi_release(struct inode *i, struct file *f) +{ + if (nowayout) { + printk(KERN_NOTICE "%s: no way out - watchdog left running\n", + wdt_gpi_name); + __module_get(THIS_MODULE); + locked = 1; + } else { + if (expect_close) { + u32 reg; + + lock_titan_regs(); + reg = titan_readl(CPCCR) & ~(0xf << (wd_ctr * 4)); + titan_writel(reg, CPCCR); + reg = titan_readl(CPGIG1ER); + titan_writel(reg & ~(0x100 << wd_ctr), CPGIG1ER); + iob(); + unlock_titan_regs(); + free_irq(wd_irq, &miscdev); + printk(KERN_INFO "%s: watchdog stopped\n", wdt_gpi_name); + } else { + printk(KERN_NOTICE "%s: unexpected close() -" + " watchdog left running\n", + wdt_gpi_name); + wdt_gpi_set_timeout(timeout); + __module_get(THIS_MODULE); + locked = 1; + } + } + + atomic_inc(&opencnt); + return 0; +} + + + +static ssize_t +wdt_gpi_write(struct file *f, const char __user *d, size_t s, loff_t *o) +{ + char val; + + wdt_gpi_set_timeout(timeout); + expect_close = (s > 0) && !get_user(val, d) && (val == 'V'); + return s ? 1 : 0; +} + + + +static long +wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg) +{ + long res = -ENOTTY; + const long size = _IOC_SIZE(cmd); + int stat; + static struct watchdog_info wdinfo = { + .identity = "RM9xxx/GPI watchdog", + .firmware_version = 0, + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING + }; + + if (unlikely(_IOC_TYPE(cmd) != WATCHDOG_IOCTL_BASE)) + return -ENOTTY; + + if ((_IOC_DIR(cmd) & _IOC_READ) + && !access_ok(VERIFY_WRITE, arg, size)) + return -EFAULT; + + if ((_IOC_DIR(cmd) & _IOC_WRITE) + && !access_ok(VERIFY_READ, arg, size)) + return -EFAULT; + + expect_close = 0; + + switch (cmd) { + case WDIOC_GETSUPPORT: + wdinfo.options = nowayout ? + WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING : + WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE; + res = __copy_to_user((void __user *)arg, &wdinfo, size) ? + -EFAULT : size; + break; + + case WDIOC_GETSTATUS: + break; + + case WDIOC_GETBOOTSTATUS: + stat = (*(volatile char *) flagaddr & 0x01) + ? WDIOF_CARDRESET : 0; + res = __copy_to_user((void __user *)arg, &stat, size) ? + -EFAULT : size; + break; + + case WDIOC_SETOPTIONS: + break; + + case WDIOC_KEEPALIVE: + wdt_gpi_set_timeout(timeout); + res = size; + break; + + case WDIOC_SETTIMEOUT: + { + int val; + if (unlikely(__copy_from_user(&val, (const void __user *) arg, + size))) { + res = -EFAULT; + break; + } + + if (val > 32) + val = 32; + timeout = val; + wdt_gpi_set_timeout(val); + res = size; + printk("%s: timeout set to %u seconds\n", + wdt_gpi_name, timeout); + } + break; + + case WDIOC_GETTIMEOUT: + res = __copy_to_user((void __user *) arg, &timeout, size) ? + -EFAULT : size; + break; + } + + return res; +} + + + + +static irqreturn_t wdt_gpi_irqhdl(int irq, void *ctxt, struct pt_regs *regs) +{ + if (!unlikely(__raw_readl(wd_regs + 0x0008) & 0x1)) + return IRQ_NONE; + __raw_writel(0x1, wd_regs + 0x0008); + + + printk(KERN_WARNING "%s: watchdog expired - resetting system\n", + wdt_gpi_name); + + *(volatile char *) flagaddr |= 0x01; + *(volatile char *) resetaddr = powercycle ? 0x01 : 0x2; + iob(); + while (1) + cpu_relax(); +} + + + +static int +wdt_gpi_notify(struct notifier_block *this, unsigned long code, void *unused) +{ + if(code == SYS_DOWN || code == SYS_HALT) { + u32 reg; + + lock_titan_regs(); + reg = titan_readl(CPCCR) & ~(0xf << (wd_ctr * 4)); + titan_writel(reg, CPCCR); + reg = titan_readl(CPGIG1ER); + titan_writel(reg & ~(0x100 << wd_ctr), CPGIG1ER); + iob(); + unlock_titan_regs(); + } + return NOTIFY_DONE; +} + + + +static int __init wdt_gpi_init_module(void) +{ + atomic_set(&opencnt, 1); + if (timeout > MAX_TIMEOUT_SECONDS) + timeout = MAX_TIMEOUT_SECONDS; + return driver_register(&wdt_gpi_driver); +} + + + +static void __exit wdt_gpi_cleanup_module(void) +{ + driver_unregister(&wdt_gpi_driver); +} + +module_init(wdt_gpi_init_module); +module_exit(wdt_gpi_cleanup_module); + + + +MODULE_AUTHOR("Thomas Koeller "); +MODULE_DESCRIPTION("Basler eXcite watchdog driver for gpi devices"); +MODULE_VERSION("0.1"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds"); +MODULE_PARM_DESC(resetaddr, "Address to write to to force a reset"); +MODULE_PARM_DESC(flagaddr, "Address to write to boot flags to"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be disabled once started"); +MODULE_PARM_DESC(powercycle, "Cycle power if watchdog expires"); -- cgit v1.2.3 From cd57eeab7c4c108ce6e84545bdf37ae91b930781 Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Fri, 17 Nov 2006 21:51:35 +0100 Subject: [WATCHDOG] MIPS RM9000 on-chip watchdog device - patch 1 Locate parameter descriptions close to parameter definition - not in bottom of file. Signed-off-by: Sam Ravnborg Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/rm9k_wdt.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/rm9k_wdt.c b/drivers/char/watchdog/rm9k_wdt.c index 8cd12ab9bff..da3fc63bca6 100644 --- a/drivers/char/watchdog/rm9k_wdt.c +++ b/drivers/char/watchdog/rm9k_wdt.c @@ -45,7 +45,6 @@ #define CPGIG1ER 0x0054 - /* Function prototypes */ static int __init wdt_gpi_probe(struct device *); static int __exit wdt_gpi_remove(struct device *); @@ -59,33 +58,37 @@ static int wdt_gpi_notify(struct notifier_block *, unsigned long, void *); static irqreturn_t wdt_gpi_irqhdl(int, void *, struct pt_regs *); - - static const char wdt_gpi_name[] = "wdt_gpi"; static atomic_t opencnt; static int expect_close; static int locked = 0; - /* These are set from device resources */ static void __iomem * wd_regs; static unsigned int wd_irq, wd_ctr; - /* Module arguments */ static int timeout = MAX_TIMEOUT_SECONDS; module_param(timeout, int, 0444); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds"); + static unsigned long resetaddr = 0xbffdc200; module_param(resetaddr, ulong, 0444); +MODULE_PARM_DESC(resetaddr, "Address to write to to force a reset"); + static unsigned long flagaddr = 0xbffdc104; module_param(flagaddr, ulong, 0444); +MODULE_PARM_DESC(flagaddr, "Address to write to boot flags to"); + static int powercycle = 0; module_param(powercycle, bool, 0444); +MODULE_PARM_DESC(powercycle, "Cycle power if watchdog expires"); static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0444); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be disabled once started"); @@ -424,8 +427,4 @@ MODULE_DESCRIPTION("Basler eXcite watchdog driver for gpi devices"); MODULE_VERSION("0.1"); MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); -MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds"); -MODULE_PARM_DESC(resetaddr, "Address to write to to force a reset"); -MODULE_PARM_DESC(flagaddr, "Address to write to boot flags to"); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be disabled once started"); -MODULE_PARM_DESC(powercycle, "Cycle power if watchdog expires"); + -- cgit v1.2.3 From 97846e3ccbcbcc966e23a91b0d190efd1f889c9b Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Fri, 17 Nov 2006 23:15:48 +0100 Subject: [WATCHDOG] MIPS RM9000 on-chip watchdog device - patch 2 Reorganize source code so that it is structured as follows: - Function prototypes - Local variables - Module arguments - Interrupt handler - Watchdog functions - /dev/watchdog operations - Shutdown notifier - Kernel interfaces - Init & exit procedures - Device driver init & exit Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/rm9k_wdt.c | 216 ++++++++++++++++++--------------------- 1 file changed, 101 insertions(+), 115 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/rm9k_wdt.c b/drivers/char/watchdog/rm9k_wdt.c index da3fc63bca6..1aad9138f71 100644 --- a/drivers/char/watchdog/rm9k_wdt.c +++ b/drivers/char/watchdog/rm9k_wdt.c @@ -46,8 +46,7 @@ /* Function prototypes */ -static int __init wdt_gpi_probe(struct device *); -static int __exit wdt_gpi_remove(struct device *); +static irqreturn_t wdt_gpi_irqhdl(int, void *, struct pt_regs *); static void wdt_gpi_set_timeout(unsigned int); static int wdt_gpi_open(struct inode *, struct file *); static int wdt_gpi_release(struct inode *, struct file *); @@ -55,7 +54,8 @@ static ssize_t wdt_gpi_write(struct file *, const char __user *, size_t, loff_t static long wdt_gpi_ioctl(struct file *, unsigned int, unsigned long); static const struct resource *wdt_gpi_get_resource(struct platform_device *, const char *, unsigned int); static int wdt_gpi_notify(struct notifier_block *, unsigned long, void *); -static irqreturn_t wdt_gpi_irqhdl(int, void *, struct pt_regs *); +static int __init wdt_gpi_probe(struct device *); +static int __exit wdt_gpi_remove(struct device *); static const char wdt_gpi_name[] = "wdt_gpi"; @@ -91,93 +91,26 @@ module_param(nowayout, bool, 0444); MODULE_PARM_DESC(nowayout, "Watchdog cannot be disabled once started"); - -static struct file_operations fops = { - .owner = THIS_MODULE, - .open = wdt_gpi_open, - .release = wdt_gpi_release, - .write = wdt_gpi_write, - .unlocked_ioctl = wdt_gpi_ioctl, -}; - -static struct miscdevice miscdev = { - .minor = WATCHDOG_MINOR, - .name = wdt_gpi_name, - .fops = &fops, -}; - -static struct device_driver wdt_gpi_driver = { - .name = (char *) wdt_gpi_name, - .bus = &platform_bus_type, - .owner = THIS_MODULE, - .probe = wdt_gpi_probe, - .remove = __exit_p(wdt_gpi_remove), - .shutdown = NULL, - .suspend = NULL, - .resume = NULL, -}; - -static struct notifier_block wdt_gpi_shutdown = { - .notifier_call = wdt_gpi_notify, -}; - - - -static const struct resource * -wdt_gpi_get_resource(struct platform_device *pdv, const char *name, - unsigned int type) -{ - char buf[80]; - if (snprintf(buf, sizeof buf, "%s_0", name) >= sizeof buf) - return NULL; - return platform_get_resource_byname(pdv, type, buf); -} - - - -/* No hotplugging on the platform bus - use __init */ -static int __init wdt_gpi_probe(struct device *dev) +/* Interrupt handler */ +static irqreturn_t wdt_gpi_irqhdl(int irq, void *ctxt, struct pt_regs *regs) { - int res; - struct platform_device * const pdv = to_platform_device(dev); - const struct resource - * const rr = wdt_gpi_get_resource(pdv, WDT_RESOURCE_REGS, - IORESOURCE_MEM), - * const ri = wdt_gpi_get_resource(pdv, WDT_RESOURCE_IRQ, - IORESOURCE_IRQ), - * const rc = wdt_gpi_get_resource(pdv, WDT_RESOURCE_COUNTER, - 0); - - if (unlikely(!rr || !ri || !rc)) - return -ENXIO; - - wd_regs = ioremap_nocache(rr->start, rr->end + 1 - rr->start); - if (unlikely(!wd_regs)) - return -ENOMEM; - wd_irq = ri->start; - wd_ctr = rc->start; - res = misc_register(&miscdev); - if (res) - iounmap(wd_regs); - else - register_reboot_notifier(&wdt_gpi_shutdown); - return res; -} - + if (!unlikely(__raw_readl(wd_regs + 0x0008) & 0x1)) + return IRQ_NONE; + __raw_writel(0x1, wd_regs + 0x0008); -static int __exit wdt_gpi_remove(struct device *dev) -{ - int res; + printk(KERN_WARNING "%s: watchdog expired - resetting system\n", + wdt_gpi_name); - unregister_reboot_notifier(&wdt_gpi_shutdown); - res = misc_deregister(&miscdev); - iounmap(wd_regs); - wd_regs = NULL; - return res; + *(volatile char *) flagaddr |= 0x01; + *(volatile char *) resetaddr = powercycle ? 0x01 : 0x2; + iob(); + while (1) + cpu_relax(); } +/* Watchdog functions */ static void wdt_gpi_set_timeout(unsigned int to) { u32 reg; @@ -197,7 +130,7 @@ static void wdt_gpi_set_timeout(unsigned int to) } - +/* /dev/watchdog operations */ static int wdt_gpi_open(struct inode *i, struct file *f) { int res; @@ -231,8 +164,6 @@ static int wdt_gpi_open(struct inode *i, struct file *f) return 0; } - - static int wdt_gpi_release(struct inode *i, struct file *f) { if (nowayout) { @@ -267,8 +198,6 @@ static int wdt_gpi_release(struct inode *i, struct file *f) return 0; } - - static ssize_t wdt_gpi_write(struct file *f, const char __user *d, size_t s, loff_t *o) { @@ -279,8 +208,6 @@ wdt_gpi_write(struct file *f, const char __user *d, size_t s, loff_t *o) return s ? 1 : 0; } - - static long wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { @@ -362,27 +289,7 @@ wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg) } - - -static irqreturn_t wdt_gpi_irqhdl(int irq, void *ctxt, struct pt_regs *regs) -{ - if (!unlikely(__raw_readl(wd_regs + 0x0008) & 0x1)) - return IRQ_NONE; - __raw_writel(0x1, wd_regs + 0x0008); - - - printk(KERN_WARNING "%s: watchdog expired - resetting system\n", - wdt_gpi_name); - - *(volatile char *) flagaddr |= 0x01; - *(volatile char *) resetaddr = powercycle ? 0x01 : 0x2; - iob(); - while (1) - cpu_relax(); -} - - - +/* Shutdown notifier*/ static int wdt_gpi_notify(struct notifier_block *this, unsigned long code, void *unused) { @@ -401,6 +308,89 @@ wdt_gpi_notify(struct notifier_block *this, unsigned long code, void *unused) } +/* Kernel interfaces */ +static struct file_operations fops = { + .owner = THIS_MODULE, + .open = wdt_gpi_open, + .release = wdt_gpi_release, + .write = wdt_gpi_write, + .unlocked_ioctl = wdt_gpi_ioctl, +}; + +static struct miscdevice miscdev = { + .minor = WATCHDOG_MINOR, + .name = wdt_gpi_name, + .fops = &fops, +}; + +static struct notifier_block wdt_gpi_shutdown = { + .notifier_call = wdt_gpi_notify, +}; + + +/* Init & exit procedures */ +static const struct resource * +wdt_gpi_get_resource(struct platform_device *pdv, const char *name, + unsigned int type) +{ + char buf[80]; + if (snprintf(buf, sizeof buf, "%s_0", name) >= sizeof buf) + return NULL; + return platform_get_resource_byname(pdv, type, buf); +} + +/* No hotplugging on the platform bus - use __init */ +static int __init wdt_gpi_probe(struct device *dev) +{ + int res; + struct platform_device * const pdv = to_platform_device(dev); + const struct resource + * const rr = wdt_gpi_get_resource(pdv, WDT_RESOURCE_REGS, + IORESOURCE_MEM), + * const ri = wdt_gpi_get_resource(pdv, WDT_RESOURCE_IRQ, + IORESOURCE_IRQ), + * const rc = wdt_gpi_get_resource(pdv, WDT_RESOURCE_COUNTER, + 0); + + if (unlikely(!rr || !ri || !rc)) + return -ENXIO; + + wd_regs = ioremap_nocache(rr->start, rr->end + 1 - rr->start); + if (unlikely(!wd_regs)) + return -ENOMEM; + wd_irq = ri->start; + wd_ctr = rc->start; + res = misc_register(&miscdev); + if (res) + iounmap(wd_regs); + else + register_reboot_notifier(&wdt_gpi_shutdown); + return res; +} + +static int __exit wdt_gpi_remove(struct device *dev) +{ + int res; + + unregister_reboot_notifier(&wdt_gpi_shutdown); + res = misc_deregister(&miscdev); + iounmap(wd_regs); + wd_regs = NULL; + return res; +} + + +/* Device driver init & exit */ +static struct device_driver wdt_gpi_driver = { + .name = (char *) wdt_gpi_name, + .bus = &platform_bus_type, + .owner = THIS_MODULE, + .probe = wdt_gpi_probe, + .remove = __exit_p(wdt_gpi_remove), + .shutdown = NULL, + .suspend = NULL, + .resume = NULL, +}; static int __init wdt_gpi_init_module(void) { @@ -410,8 +400,6 @@ static int __init wdt_gpi_init_module(void) return driver_register(&wdt_gpi_driver); } - - static void __exit wdt_gpi_cleanup_module(void) { driver_unregister(&wdt_gpi_driver); @@ -420,8 +408,6 @@ static void __exit wdt_gpi_cleanup_module(void) module_init(wdt_gpi_init_module); module_exit(wdt_gpi_cleanup_module); - - MODULE_AUTHOR("Thomas Koeller "); MODULE_DESCRIPTION("Basler eXcite watchdog driver for gpi devices"); MODULE_VERSION("0.1"); -- cgit v1.2.3 From 414a675964e5636b53b37827b646138f166507d3 Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Fri, 17 Nov 2006 23:36:08 +0100 Subject: [WATCHDOG] MIPS RM9000 on-chip watchdog device - patch 3 Move start and stop code into seperate functions Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/rm9k_wdt.c | 56 +++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 27 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/rm9k_wdt.c b/drivers/char/watchdog/rm9k_wdt.c index 1aad9138f71..22aab8703ed 100644 --- a/drivers/char/watchdog/rm9k_wdt.c +++ b/drivers/char/watchdog/rm9k_wdt.c @@ -111,6 +111,30 @@ static irqreturn_t wdt_gpi_irqhdl(int irq, void *ctxt, struct pt_regs *regs) /* Watchdog functions */ +static void wdt_gpi_start(void) +{ + u32 reg; + + lock_titan_regs(); + reg = titan_readl(CPGIG1ER); + titan_writel(reg | (0x100 << wd_ctr), CPGIG1ER); + iob(); + unlock_titan_regs(); +} + +static void wdt_gpi_stop(void) +{ + u32 reg; + + lock_titan_regs(); + reg = titan_readl(CPCCR) & ~(0xf << (wd_ctr * 4)); + titan_writel(reg, CPCCR); + reg = titan_readl(CPGIG1ER); + titan_writel(reg & ~(0x100 << wd_ctr), CPGIG1ER); + iob(); + unlock_titan_regs(); +} + static void wdt_gpi_set_timeout(unsigned int to) { u32 reg; @@ -134,7 +158,6 @@ static void wdt_gpi_set_timeout(unsigned int to) static int wdt_gpi_open(struct inode *i, struct file *f) { int res; - u32 reg; if (unlikely(0 > atomic_dec_if_positive(&opencnt))) return -EBUSY; @@ -152,12 +175,7 @@ static int wdt_gpi_open(struct inode *i, struct file *f) return res; wdt_gpi_set_timeout(timeout); - - lock_titan_regs(); - reg = titan_readl(CPGIG1ER); - titan_writel(reg | (0x100 << wd_ctr), CPGIG1ER); - iob(); - unlock_titan_regs(); + wdt_gpi_start(); printk(KERN_INFO "%s: watchdog started, timeout = %u seconds\n", wdt_gpi_name, timeout); @@ -173,15 +191,7 @@ static int wdt_gpi_release(struct inode *i, struct file *f) locked = 1; } else { if (expect_close) { - u32 reg; - - lock_titan_regs(); - reg = titan_readl(CPCCR) & ~(0xf << (wd_ctr * 4)); - titan_writel(reg, CPCCR); - reg = titan_readl(CPGIG1ER); - titan_writel(reg & ~(0x100 << wd_ctr), CPGIG1ER); - iob(); - unlock_titan_regs(); + wdt_gpi_stop(); free_irq(wd_irq, &miscdev); printk(KERN_INFO "%s: watchdog stopped\n", wdt_gpi_name); } else { @@ -293,17 +303,9 @@ wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg) static int wdt_gpi_notify(struct notifier_block *this, unsigned long code, void *unused) { - if(code == SYS_DOWN || code == SYS_HALT) { - u32 reg; - - lock_titan_regs(); - reg = titan_readl(CPCCR) & ~(0xf << (wd_ctr * 4)); - titan_writel(reg, CPCCR); - reg = titan_readl(CPGIG1ER); - titan_writel(reg & ~(0x100 << wd_ctr), CPGIG1ER); - iob(); - unlock_titan_regs(); - } + if (code == SYS_DOWN || code == SYS_HALT) + wdt_gpi_stop(); + return NOTIFY_DONE; } -- cgit v1.2.3 From d5d06ff7f181c06ef8c94b353ae3fef8f06b3085 Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Fri, 17 Nov 2006 23:50:06 +0100 Subject: [WATCHDOG] MIPS RM9000 on-chip watchdog device - patch 4 a number of small patches: - include notifier.h include file - re-arrange prototype functions - remove =0 initializations - change printk logging levels to what's used in other drivers - /dev/watchdog is a VFS so use nonseekable_open - Style: Instead of "if (constant op function_or_variable)" we prefer "if (function_or_variable op constant)" - arg is a __user pointer - use MAX_TIMEOUT_SECONDS instead of 32 in WDIOC_SETTIMEOUT Signed-off-by: Randy Dunlap Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/rm9k_wdt.c | 42 +++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/rm9k_wdt.c b/drivers/char/watchdog/rm9k_wdt.c index 22aab8703ed..ec3909371c2 100644 --- a/drivers/char/watchdog/rm9k_wdt.c +++ b/drivers/char/watchdog/rm9k_wdt.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -47,13 +48,15 @@ /* Function prototypes */ static irqreturn_t wdt_gpi_irqhdl(int, void *, struct pt_regs *); +static void wdt_gpi_start(void); +static void wdt_gpi_stop(void); static void wdt_gpi_set_timeout(unsigned int); static int wdt_gpi_open(struct inode *, struct file *); static int wdt_gpi_release(struct inode *, struct file *); static ssize_t wdt_gpi_write(struct file *, const char __user *, size_t, loff_t *); static long wdt_gpi_ioctl(struct file *, unsigned int, unsigned long); -static const struct resource *wdt_gpi_get_resource(struct platform_device *, const char *, unsigned int); static int wdt_gpi_notify(struct notifier_block *, unsigned long, void *); +static const struct resource *wdt_gpi_get_resource(struct platform_device *, const char *, unsigned int); static int __init wdt_gpi_probe(struct device *); static int __exit wdt_gpi_remove(struct device *); @@ -61,7 +64,7 @@ static int __exit wdt_gpi_remove(struct device *); static const char wdt_gpi_name[] = "wdt_gpi"; static atomic_t opencnt; static int expect_close; -static int locked = 0; +static int locked; /* These are set from device resources */ @@ -82,7 +85,7 @@ static unsigned long flagaddr = 0xbffdc104; module_param(flagaddr, ulong, 0444); MODULE_PARM_DESC(flagaddr, "Address to write to boot flags to"); -static int powercycle = 0; +static int powercycle; module_param(powercycle, bool, 0444); MODULE_PARM_DESC(powercycle, "Cycle power if watchdog expires"); @@ -99,7 +102,7 @@ static irqreturn_t wdt_gpi_irqhdl(int irq, void *ctxt, struct pt_regs *regs) __raw_writel(0x1, wd_regs + 0x0008); - printk(KERN_WARNING "%s: watchdog expired - resetting system\n", + printk(KERN_CRIT "%s: watchdog expired - resetting system\n", wdt_gpi_name); *(volatile char *) flagaddr |= 0x01; @@ -155,11 +158,11 @@ static void wdt_gpi_set_timeout(unsigned int to) /* /dev/watchdog operations */ -static int wdt_gpi_open(struct inode *i, struct file *f) +static int wdt_gpi_open(struct inode *inode, struct file *file) { int res; - if (unlikely(0 > atomic_dec_if_positive(&opencnt))) + if (unlikely(atomic_dec_if_positive(&opencnt) < 0)) return -EBUSY; expect_close = 0; @@ -179,13 +182,13 @@ static int wdt_gpi_open(struct inode *i, struct file *f) printk(KERN_INFO "%s: watchdog started, timeout = %u seconds\n", wdt_gpi_name, timeout); - return 0; + return nonseekable_open(inode, file); } -static int wdt_gpi_release(struct inode *i, struct file *f) +static int wdt_gpi_release(struct inode *inode, struct file *file) { if (nowayout) { - printk(KERN_NOTICE "%s: no way out - watchdog left running\n", + printk(KERN_INFO "%s: no way out - watchdog left running\n", wdt_gpi_name); __module_get(THIS_MODULE); locked = 1; @@ -195,7 +198,7 @@ static int wdt_gpi_release(struct inode *i, struct file *f) free_irq(wd_irq, &miscdev); printk(KERN_INFO "%s: watchdog stopped\n", wdt_gpi_name); } else { - printk(KERN_NOTICE "%s: unexpected close() -" + printk(KERN_CRIT "%s: unexpected close() -" " watchdog left running\n", wdt_gpi_name); wdt_gpi_set_timeout(timeout); @@ -224,6 +227,7 @@ wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg) long res = -ENOTTY; const long size = _IOC_SIZE(cmd); int stat; + void __user *argp = (void __user *)arg; static struct watchdog_info wdinfo = { .identity = "RM9xxx/GPI watchdog", .firmware_version = 0, @@ -248,8 +252,7 @@ wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg) wdinfo.options = nowayout ? WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING : WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE; - res = __copy_to_user((void __user *)arg, &wdinfo, size) ? - -EFAULT : size; + res = __copy_to_user(argp, &wdinfo, size) ? -EFAULT : size; break; case WDIOC_GETSTATUS: @@ -258,7 +261,7 @@ wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg) case WDIOC_GETBOOTSTATUS: stat = (*(volatile char *) flagaddr & 0x01) ? WDIOF_CARDRESET : 0; - res = __copy_to_user((void __user *)arg, &stat, size) ? + res = __copy_to_user(argp, &stat, size) ? -EFAULT : size; break; @@ -273,24 +276,23 @@ wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg) case WDIOC_SETTIMEOUT: { int val; - if (unlikely(__copy_from_user(&val, (const void __user *) arg, - size))) { + if (unlikely(__copy_from_user(&val, argp, size))) { res = -EFAULT; break; } - if (val > 32) - val = 32; + if (val > MAX_TIMEOUT_SECONDS) + val = MAX_TIMEOUT_SECONDS; timeout = val; wdt_gpi_set_timeout(val); res = size; - printk("%s: timeout set to %u seconds\n", + printk(KERN_INFO "%s: timeout set to %u seconds\n", wdt_gpi_name, timeout); } break; case WDIOC_GETTIMEOUT: - res = __copy_to_user((void __user *) arg, &timeout, size) ? + res = __copy_to_user(argp, &timeout, size) ? -EFAULT : size; break; } @@ -299,7 +301,7 @@ wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg) } -/* Shutdown notifier*/ +/* Shutdown notifier */ static int wdt_gpi_notify(struct notifier_block *this, unsigned long code, void *unused) { -- cgit v1.2.3 From 7d915a38985d2826acbdc9dc9cca8a93e23e5278 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 22 Nov 2006 09:37:54 -0800 Subject: [AGP] Fix intel 965 AGP memory mapping function This introduces a i965-specific "mask_memory()" function that knows about the extended physical addresses that the i965 supports. This allows us to correctly map in physical memory in the >4GB range into the GTT. Also simplify/clean-up the i965 case for the aperture sizing by just returning the fixed 512kB size from "fetch_size()". We don't really care that not all of the aperture may be visible - the only thing that cares about the aperture size is the Intel "stolen memory" calculation, which depends on the fixed size. Cc: Keith Packard Cc: Eric Anholt Cc: Dave Jones Signed-off-by: Linus Torvalds --- drivers/char/agp/intel-agp.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index d1ede7db5a1..aceece71a85 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -387,11 +387,7 @@ static void intel_i830_init_gtt_entries(void) /* We obtain the size of the GTT, which is also stored (for some * reason) at the top of stolen memory. Then we add 4KB to that * for the video BIOS popup, which is also stored in there. */ - - if (IS_I965) - size = 512 + 4; - else - size = agp_bridge->driver->fetch_size() + 4; + size = agp_bridge->driver->fetch_size() + 4; if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { @@ -805,6 +801,26 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) return 0; } + +/* + * The i965 supports 36-bit physical addresses, but to keep + * the format of the GTT the same, the bits that don't fit + * in a 32-bit word are shifted down to bits 4..7. + * + * Gcc is smart enough to notice that "(addr >> 28) & 0xf0" + * is always zero on 32-bit architectures, so no need to make + * this conditional. + */ +static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge, + unsigned long addr, int type) +{ + /* Shift high bits down */ + addr |= (addr >> 28) & 0xf0; + + /* Type checking must be done elsewhere */ + return addr | bridge->driver->masks[type].mask; +} + static int intel_i965_fetch_size(void) { struct aper_size_info_fixed *values; @@ -832,7 +848,8 @@ static int intel_i965_fetch_size(void) agp_bridge->previous_size = agp_bridge->current_size = (void *)(values + offset); - return values[offset].size; + /* The i965 GTT is always sized as if it had a 512kB aperture size */ + return 512; } /* The intel i965 automatically initializes the agp aperture during POST. @@ -1584,7 +1601,7 @@ static struct agp_bridge_driver intel_i965_driver = { .fetch_size = intel_i965_fetch_size, .cleanup = intel_i915_cleanup, .tlb_flush = intel_i810_tlbflush, - .mask_memory = intel_i810_mask_memory, + .mask_memory = intel_i965_mask_memory, .masks = intel_i810_masks, .agp_enable = intel_i810_agp_enable, .cache_flush = global_cache_flush, -- cgit v1.2.3 From 66c669baa7d70b8d135da67f36c8dba12cea71b8 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 22 Nov 2006 14:55:29 -0800 Subject: [AGP] Allocate AGP pages with GFP_DMA32 by default Not all graphic page remappers support physical addresses over the 4GB mark for remapping, so while some do (the AMD64 GART always did, and I just fixed the i965 to do so properly), we're safest off just forcing GFP_DMA32 allocations to make sure graphics pages get allocated in the low 32-bit address space by default. AGP sub-drivers that really care, and can do better, could just choose to implement their own allocator (or we could add another "64-bit safe" default allocator for their use), but quite frankly, you're not likely to care in practice. So for now, this trivial change means that we won't be allocating pages that we can't map correctly by mistake on x86-64. [ On traditional 32-bit x86, this could never happen, because GFP_KERNEL would never allocate any highmem memory anyway ] Acked-by: Andi Kleen Acked-by: Dave Jones Cc: Eric Anholt Cc: Keith Packard Signed-off-by: Linus Torvalds --- drivers/char/agp/generic.c | 2 +- drivers/char/agp/intel-agp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index c3920016168..5ff457b41ef 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -1054,7 +1054,7 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge) { struct page * page; - page = alloc_page(GFP_KERNEL); + page = alloc_page(GFP_KERNEL | GFP_DMA32); if (page == NULL) return NULL; diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index aceece71a85..555b3a8ab49 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -169,7 +169,7 @@ static void *i8xx_alloc_pages(void) { struct page * page; - page = alloc_pages(GFP_KERNEL, 2); + page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2); if (page == NULL) return NULL; -- cgit v1.2.3 From 5e66b0b5f187c811419ff10cfb5668c028a64d57 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sat, 25 Nov 2006 11:09:35 -0800 Subject: [PATCH] tlclk: fix platform_device_register_simple() error check The return value of platform_device_register_simple() should be checked by IS_ERR(). This patch also fix misc_register() error case. Because misc_register() returns error code. Cc: Sebastien Bouchard Signed-off-by: Akinobu Mita Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tlclk.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c index 2444a0e24b3..244d30a03fe 100644 --- a/drivers/char/tlclk.c +++ b/drivers/char/tlclk.c @@ -792,15 +792,14 @@ static int __init tlclk_init(void) ret = misc_register(&tlclk_miscdev); if (ret < 0) { printk(KERN_ERR "tlclk: misc_register returns %d.\n", ret); - ret = -EBUSY; goto out3; } tlclk_device = platform_device_register_simple("telco_clock", -1, NULL, 0); - if (!tlclk_device) { + if (IS_ERR(tlclk_device)) { printk(KERN_ERR "tlclk: platform_device_register failed.\n"); - ret = -EBUSY; + ret = PTR_ERR(tlclk_device); goto out4; } -- cgit v1.2.3 From 3cb2fccc5f48a4d6269dfd00b4db570fca2a04d5 Mon Sep 17 00:00:00 2001 From: Matt LaPlante Date: Thu, 30 Nov 2006 05:22:59 +0100 Subject: Fix misc Kconfig typos Fix various Kconfig typos. Signed-off-by: Matt LaPlante Acked-by: Randy Dunlap Signed-off-by: Adrian Bunk --- drivers/char/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 2af12fc4511..ad8b537ad47 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -994,7 +994,7 @@ config HPET help If you say Y here, you will have a miscdevice named "/dev/hpet/". Each open selects one of the timers supported by the HPET. The timers are - non-periodioc and/or periodic. + non-periodic and/or periodic. config HPET_RTC_IRQ bool "HPET Control RTC IRQ" if !HPET_EMULATE_RTC -- cgit v1.2.3 From 0779bf2d2ecc4d9b1e9437ae659f50e6776a7666 Mon Sep 17 00:00:00 2001 From: Matt LaPlante Date: Thu, 30 Nov 2006 05:24:39 +0100 Subject: Fix misc .c/.h comment typos Fix various .c/.h typos in comments (no code changes). Signed-off-by: Matt LaPlante Signed-off-by: Adrian Bunk --- drivers/char/rio/riocmd.c | 2 +- drivers/char/rio/rioinit.c | 2 +- drivers/char/rio/rioparam.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c index 4df6ab2206a..167ebc84e8d 100644 --- a/drivers/char/rio/riocmd.c +++ b/drivers/char/rio/riocmd.c @@ -922,7 +922,7 @@ int RIOUnUse(unsigned long iPortP, struct CmdBlk *CmdBlkP) ** ** Packet is an actual packet structure to be filled in with the packet ** information associated with the command. You need to fill in everything, -** as the command processore doesn't process the command packet in any way. +** as the command processor doesn't process the command packet in any way. ** ** The PreFuncP is called before the packet is enqueued on the host rup. ** PreFuncP is called as (*PreFuncP)(PreArg, CmdBlkP);. PreFuncP must diff --git a/drivers/char/rio/rioinit.c b/drivers/char/rio/rioinit.c index 99f3df02b61..0794844369d 100644 --- a/drivers/char/rio/rioinit.c +++ b/drivers/char/rio/rioinit.c @@ -222,7 +222,7 @@ int RIOBoardTest(unsigned long paddr, void __iomem *caddr, unsigned char type, i ** which value will be written into memory. ** Call with op set to zero means that the RAM will not be read and checked ** before it is written. -** Call with op not zero, and the RAM will be read and compated with val[op-1] +** Call with op not zero and the RAM will be read and compared with val[op-1] ** to check that the data from the previous phase was retained. */ diff --git a/drivers/char/rio/rioparam.c b/drivers/char/rio/rioparam.c index 1066d976070..bb498d24adc 100644 --- a/drivers/char/rio/rioparam.c +++ b/drivers/char/rio/rioparam.c @@ -87,8 +87,8 @@ static char *_rioparam_c_sccs_ = "@(#)rioparam.c 1.3"; ** command bit set onto the port. The command bit is in the len field, ** and gets ORed in with the actual byte count. ** -** When you send a packet with the command bit set, then the first -** data byte ( data[0] ) is interpretted as the command to execute. +** When you send a packet with the command bit set the first +** data byte (data[0]) is interpreted as the command to execute. ** It also governs what data structure overlay should accompany the packet. ** Commands are defined in cirrus/cirrus.h ** @@ -103,7 +103,7 @@ static char *_rioparam_c_sccs_ = "@(#)rioparam.c 1.3"; ** ** Most commands do not use the remaining bytes in the data array. The ** exceptions are OPEN MOPEN and CONFIG. (NB. As with the SI CONFIG and -** OPEN are currently analagous). With these three commands the following +** OPEN are currently analogous). With these three commands the following ** 11 data bytes are all used to pass config information such as baud rate etc. ** The fields are also defined in cirrus.h. Some contain straightforward ** information such as the transmit XON character. Two contain the transmit and -- cgit v1.2.3 From 6265d62f31e42cc839f929439a95f602d70d6bf7 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 8 Nov 2006 15:34:02 +0100 Subject: usb: pcwd_usb free urb cleanup - usb_free_urb() cleanup Signed-off-by: Mariusz Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/char/watchdog/pcwd_usb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c index bda45334d80..e275dd4a705 100644 --- a/drivers/char/watchdog/pcwd_usb.c +++ b/drivers/char/watchdog/pcwd_usb.c @@ -561,8 +561,7 @@ static struct notifier_block usb_pcwd_notifier = { */ static inline void usb_pcwd_delete (struct usb_pcwd_private *usb_pcwd) { - if (usb_pcwd->intr_urb != NULL) - usb_free_urb (usb_pcwd->intr_urb); + usb_free_urb(usb_pcwd->intr_urb); if (usb_pcwd->intr_buffer != NULL) usb_buffer_free(usb_pcwd->udev, usb_pcwd->intr_size, usb_pcwd->intr_buffer, usb_pcwd->intr_dma); -- cgit v1.2.3 From 805952a889c4d0fdab23307c14c5ce9571f81233 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 7 Aug 2006 22:19:37 -0700 Subject: Driver core: convert vt code to use struct device Converts from using struct "class_device" to "struct device" making everything show up properly in /sys/devices/ with symlinks from the /sys/class directory. Signed-off-by: Greg Kroah-Hartman --- drivers/char/vt.c | 81 +++++++++++++++++++++++++++---------------------------- 1 file changed, 39 insertions(+), 42 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 8e4413f6fba..87587b4385a 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -112,7 +112,7 @@ struct con_driver { const struct consw *con; const char *desc; - struct class_device *class_dev; + struct device *dev; int node; int first; int last; @@ -3023,10 +3023,10 @@ static inline int vt_unbind(struct con_driver *con) } #endif /* CONFIG_VT_HW_CONSOLE_BINDING */ -static ssize_t store_bind(struct class_device *class_device, +static ssize_t store_bind(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct con_driver *con = class_get_devdata(class_device); + struct con_driver *con = dev_get_drvdata(dev); int bind = simple_strtoul(buf, NULL, 0); if (bind) @@ -3037,17 +3037,19 @@ static ssize_t store_bind(struct class_device *class_device, return count; } -static ssize_t show_bind(struct class_device *class_device, char *buf) +static ssize_t show_bind(struct device *dev, struct device_attribute *attr, + char *buf) { - struct con_driver *con = class_get_devdata(class_device); + struct con_driver *con = dev_get_drvdata(dev); int bind = con_is_bound(con->con); return snprintf(buf, PAGE_SIZE, "%i\n", bind); } -static ssize_t show_name(struct class_device *class_device, char *buf) +static ssize_t show_name(struct device *dev, struct device_attribute *attr, + char *buf) { - struct con_driver *con = class_get_devdata(class_device); + struct con_driver *con = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE, "%s %s\n", (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)", @@ -3055,43 +3057,40 @@ static ssize_t show_name(struct class_device *class_device, char *buf) } -static struct class_device_attribute class_device_attrs[] = { +static struct device_attribute device_attrs[] = { __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind), __ATTR(name, S_IRUGO, show_name, NULL), }; -static int vtconsole_init_class_device(struct con_driver *con) +static int vtconsole_init_device(struct con_driver *con) { int i; int error = 0; con->flag |= CON_DRIVER_FLAG_ATTR; - class_set_devdata(con->class_dev, con); - for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) { - error = class_device_create_file(con->class_dev, - &class_device_attrs[i]); + dev_set_drvdata(con->dev, con); + for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { + error = device_create_file(con->dev, &device_attrs[i]); if (error) break; } if (error) { while (--i >= 0) - class_device_remove_file(con->class_dev, - &class_device_attrs[i]); + device_remove_file(con->dev, &device_attrs[i]); con->flag &= ~CON_DRIVER_FLAG_ATTR; } return error; } -static void vtconsole_deinit_class_device(struct con_driver *con) +static void vtconsole_deinit_device(struct con_driver *con) { int i; if (con->flag & CON_DRIVER_FLAG_ATTR) { - for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) - class_device_remove_file(con->class_dev, - &class_device_attrs[i]); + for (i = 0; i < ARRAY_SIZE(device_attrs); i++) + device_remove_file(con->dev, &device_attrs[i]); con->flag &= ~CON_DRIVER_FLAG_ATTR; } } @@ -3179,18 +3178,17 @@ int register_con_driver(const struct consw *csw, int first, int last) if (retval) goto err; - con_driver->class_dev = class_device_create(vtconsole_class, NULL, - MKDEV(0, con_driver->node), - NULL, "vtcon%i", - con_driver->node); + con_driver->dev = device_create(vtconsole_class, NULL, + MKDEV(0, con_driver->node), + "vtcon%i", con_driver->node); - if (IS_ERR(con_driver->class_dev)) { - printk(KERN_WARNING "Unable to create class_device for %s; " + if (IS_ERR(con_driver->dev)) { + printk(KERN_WARNING "Unable to create device for %s; " "errno = %ld\n", con_driver->desc, - PTR_ERR(con_driver->class_dev)); - con_driver->class_dev = NULL; + PTR_ERR(con_driver->dev)); + con_driver->dev = NULL; } else { - vtconsole_init_class_device(con_driver); + vtconsole_init_device(con_driver); } err: @@ -3226,12 +3224,12 @@ int unregister_con_driver(const struct consw *csw) if (con_driver->con == csw && con_driver->flag & CON_DRIVER_FLAG_MODULE) { - vtconsole_deinit_class_device(con_driver); - class_device_destroy(vtconsole_class, - MKDEV(0, con_driver->node)); + vtconsole_deinit_device(con_driver); + device_destroy(vtconsole_class, + MKDEV(0, con_driver->node)); con_driver->con = NULL; con_driver->desc = NULL; - con_driver->class_dev = NULL; + con_driver->dev = NULL; con_driver->node = 0; con_driver->flag = 0; con_driver->first = 0; @@ -3289,19 +3287,18 @@ static int __init vtconsole_class_init(void) for (i = 0; i < MAX_NR_CON_DRIVER; i++) { struct con_driver *con = ®istered_con_driver[i]; - if (con->con && !con->class_dev) { - con->class_dev = - class_device_create(vtconsole_class, NULL, - MKDEV(0, con->node), NULL, - "vtcon%i", con->node); + if (con->con && !con->dev) { + con->dev = device_create(vtconsole_class, NULL, + MKDEV(0, con->node), + "vtcon%i", con->node); - if (IS_ERR(con->class_dev)) { + if (IS_ERR(con->dev)) { printk(KERN_WARNING "Unable to create " - "class_device for %s; errno = %ld\n", - con->desc, PTR_ERR(con->class_dev)); - con->class_dev = NULL; + "device for %s; errno = %ld\n", + con->desc, PTR_ERR(con->dev)); + con->dev = NULL; } else { - vtconsole_init_class_device(con); + vtconsole_init_device(con); } } } -- cgit v1.2.3 From cd15422b9f39155e2d9ea56ae95c6f62aa5df42e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 7 Aug 2006 22:19:37 -0700 Subject: Driver core: convert vc code to use struct device Converts from using struct "class_device" to "struct device" making everything show up properly in /sys/devices/ with symlinks from the /sys/class directory. Signed-off-by: Greg Kroah-Hartman --- drivers/char/vc_screen.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index bd7a98c6ea7..f442b574b44 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -476,16 +476,16 @@ static struct class *vc_class; void vcs_make_sysfs(struct tty_struct *tty) { - class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1), - NULL, "vcs%u", tty->index + 1); - class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129), - NULL, "vcsa%u", tty->index + 1); + device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1), + "vcs%u", tty->index + 1); + device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129), + "vcsa%u", tty->index + 1); } void vcs_remove_sysfs(struct tty_struct *tty) { - class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1)); - class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129)); + device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1)); + device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129)); } int __init vcs_init(void) @@ -494,7 +494,7 @@ int __init vcs_init(void) panic("unable to get major %d for vcs device", VCS_MAJOR); vc_class = class_create(THIS_MODULE, "vc"); - class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); - class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); + device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), "vcs"); + device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), "vcsa"); return 0; } -- cgit v1.2.3 From 94fbcded4ea0dc14cbfb222a5c68372f150d1476 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Jul 2006 16:16:04 -0700 Subject: Driver core: change misc class_devices to be real devices This also ment that some of the misc drivers had to also be fixed up as they were assuming the device was a class_device. Signed-off-by: Greg Kroah-Hartman --- drivers/char/hw_random/core.c | 38 +++++++++++++++++++------------------- drivers/char/misc.c | 13 ++++--------- drivers/char/tpm/tpm.c | 2 +- 3 files changed, 24 insertions(+), 29 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 154a81d328c..ebace201bec 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -162,7 +162,8 @@ static struct miscdevice rng_miscdev = { }; -static ssize_t hwrng_attr_current_store(struct class_device *class, +static ssize_t hwrng_attr_current_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) { int err; @@ -192,7 +193,8 @@ static ssize_t hwrng_attr_current_store(struct class_device *class, return err ? : len; } -static ssize_t hwrng_attr_current_show(struct class_device *class, +static ssize_t hwrng_attr_current_show(struct device *dev, + struct device_attribute *attr, char *buf) { int err; @@ -210,7 +212,8 @@ static ssize_t hwrng_attr_current_show(struct class_device *class, return ret; } -static ssize_t hwrng_attr_available_show(struct class_device *class, +static ssize_t hwrng_attr_available_show(struct device *dev, + struct device_attribute *attr, char *buf) { int err; @@ -234,20 +237,18 @@ static ssize_t hwrng_attr_available_show(struct class_device *class, return ret; } -static CLASS_DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR, - hwrng_attr_current_show, - hwrng_attr_current_store); -static CLASS_DEVICE_ATTR(rng_available, S_IRUGO, - hwrng_attr_available_show, - NULL); +static DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR, + hwrng_attr_current_show, + hwrng_attr_current_store); +static DEVICE_ATTR(rng_available, S_IRUGO, + hwrng_attr_available_show, + NULL); static void unregister_miscdev(void) { - class_device_remove_file(rng_miscdev.class, - &class_device_attr_rng_available); - class_device_remove_file(rng_miscdev.class, - &class_device_attr_rng_current); + device_remove_file(rng_miscdev.this_device, &dev_attr_rng_available); + device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current); misc_deregister(&rng_miscdev); } @@ -258,20 +259,19 @@ static int register_miscdev(void) err = misc_register(&rng_miscdev); if (err) goto out; - err = class_device_create_file(rng_miscdev.class, - &class_device_attr_rng_current); + err = device_create_file(rng_miscdev.this_device, + &dev_attr_rng_current); if (err) goto err_misc_dereg; - err = class_device_create_file(rng_miscdev.class, - &class_device_attr_rng_available); + err = device_create_file(rng_miscdev.this_device, + &dev_attr_rng_available); if (err) goto err_remove_current; out: return err; err_remove_current: - class_device_remove_file(rng_miscdev.class, - &class_device_attr_rng_current); + device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current); err_misc_dereg: misc_deregister(&rng_miscdev); goto out; diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 62ebe09656e..7a484fc7cb9 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -169,11 +169,6 @@ fail: return err; } -/* - * TODO for 2.7: - * - add a struct kref to struct miscdevice and make all usages of - * them dynamic. - */ static struct class *misc_class; static const struct file_operations misc_fops = { @@ -228,10 +223,10 @@ int misc_register(struct miscdevice * misc) misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7); dev = MKDEV(MISC_MAJOR, misc->minor); - misc->class = class_device_create(misc_class, NULL, dev, misc->dev, + misc->this_device = device_create(misc_class, misc->parent, dev, "%s", misc->name); - if (IS_ERR(misc->class)) { - err = PTR_ERR(misc->class); + if (IS_ERR(misc->this_device)) { + err = PTR_ERR(misc->this_device); goto out; } @@ -264,7 +259,7 @@ int misc_deregister(struct miscdevice * misc) down(&misc_sem); list_del(&misc->list); - class_device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); + device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); if (i < DYNAMIC_MINORS && i>0) { misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); } diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 6ad2d3bb945..6e1329d404d 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -1130,7 +1130,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); chip->vendor.miscdev.name = devname; - chip->vendor.miscdev.dev = dev; + chip->vendor.miscdev.parent = dev; chip->dev = get_device(dev); if (misc_register(&chip->vendor.miscdev)) { -- cgit v1.2.3 From 01107d343076c34b9e1ce5d073292bd7f3097fda Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 7 Aug 2006 22:19:37 -0700 Subject: Driver core: convert tty core to use struct device Converts from using struct "class_device" to "struct device" making everything show up properly in /sys/devices/ with symlinks from the /sys/class directory. Also fixes up the isdn drivers that were putting something in the class device's directory. Signed-off-by: Greg Kroah-Hartman --- drivers/char/tty_io.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index e90ea39c7c4..50dc49205a2 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -3612,7 +3612,8 @@ static struct class *tty_class; * This field is optional, if there is no known struct device * for this tty device it can be set to NULL safely. * - * Returns a pointer to the class device (or ERR_PTR(-EFOO) on error). + * Returns a pointer to the struct device for this tty device + * (or ERR_PTR(-EFOO) on error). * * This call is required to be made to register an individual tty device * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If @@ -3622,8 +3623,8 @@ static struct class *tty_class; * Locking: ?? */ -struct class_device *tty_register_device(struct tty_driver *driver, - unsigned index, struct device *device) +struct device *tty_register_device(struct tty_driver *driver, unsigned index, + struct device *device) { char name[64]; dev_t dev = MKDEV(driver->major, driver->minor_start) + index; @@ -3639,7 +3640,7 @@ struct class_device *tty_register_device(struct tty_driver *driver, else tty_line_name(driver, index, name); - return class_device_create(tty_class, NULL, dev, device, "%s", name); + return device_create(tty_class, device, dev, name); } /** @@ -3655,7 +3656,7 @@ struct class_device *tty_register_device(struct tty_driver *driver, void tty_unregister_device(struct tty_driver *driver, unsigned index) { - class_device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); + device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); } EXPORT_SYMBOL(tty_register_device); @@ -3895,20 +3896,20 @@ static int __init tty_init(void) if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) panic("Couldn't register /dev/tty driver\n"); - class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); + device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), "tty"); cdev_init(&console_cdev, &console_fops); if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) panic("Couldn't register /dev/console driver\n"); - class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); + device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), "console"); #ifdef CONFIG_UNIX98_PTYS cdev_init(&ptmx_cdev, &ptmx_fops); if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) panic("Couldn't register /dev/ptmx driver\n"); - class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); + device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), "ptmx"); #endif #ifdef CONFIG_VT @@ -3916,7 +3917,7 @@ static int __init tty_init(void) if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) panic("Couldn't register /dev/tty0 driver\n"); - class_device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); + device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), "tty0"); vty_init(); #endif -- cgit v1.2.3 From 38ca6c34d385f143027ff40dd271c61adcc9b23c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 7 Aug 2006 22:19:37 -0700 Subject: Driver core: convert raw device code to use struct device Converts from using struct "class_device" to "struct device" making everything show up properly in /sys/devices/ with symlinks from the /sys/class directory. Signed-off-by: Greg Kroah-Hartman --- drivers/char/raw.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 89b718e326e..3b32313f6eb 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -127,9 +127,9 @@ raw_ioctl(struct inode *inode, struct file *filp, static void bind_device(struct raw_config_request *rq) { - class_device_destroy(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor)); - class_device_create(raw_class, NULL, MKDEV(RAW_MAJOR, rq->raw_minor), - NULL, "raw%d", rq->raw_minor); + device_destroy(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor)); + device_create(raw_class, NULL, MKDEV(RAW_MAJOR, rq->raw_minor), + "raw%d", rq->raw_minor); } /* @@ -200,7 +200,7 @@ static int raw_ctl_ioctl(struct inode *inode, struct file *filp, if (rq.block_major == 0 && rq.block_minor == 0) { /* unbind */ rawdev->binding = NULL; - class_device_destroy(raw_class, + device_destroy(raw_class, MKDEV(RAW_MAJOR, rq.raw_minor)); } else { rawdev->binding = bdget(dev); @@ -283,7 +283,7 @@ static int __init raw_init(void) ret = PTR_ERR(raw_class); goto error_region; } - class_device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); + device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), "rawctl"); return 0; @@ -295,7 +295,7 @@ error: static void __exit raw_exit(void) { - class_device_destroy(raw_class, MKDEV(RAW_MAJOR, 0)); + device_destroy(raw_class, MKDEV(RAW_MAJOR, 0)); class_destroy(raw_class); cdev_del(&raw_cdev); unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), MAX_RAW_MINORS); -- cgit v1.2.3 From 04880edae5e1027d61241beb5ac37b520755f2ab Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 12 Sep 2006 17:00:10 +0200 Subject: Driver core: convert ppdev code to use struct device Converts from using struct "class_device" to "struct device" making everything show up properly in /sys/devices/ with symlinks from the /sys/class directory. Signed-off-by: Greg Kroah-Hartman --- drivers/char/ppdev.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index efc485edad1..c1e3dd837fc 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -752,13 +752,13 @@ static const struct file_operations pp_fops = { static void pp_attach(struct parport *port) { - class_device_create(ppdev_class, NULL, MKDEV(PP_MAJOR, port->number), - NULL, "parport%d", port->number); + device_create(ppdev_class, NULL, MKDEV(PP_MAJOR, port->number), + "parport%d", port->number); } static void pp_detach(struct parport *port) { - class_device_destroy(ppdev_class, MKDEV(PP_MAJOR, port->number)); + device_destroy(ppdev_class, MKDEV(PP_MAJOR, port->number)); } static struct parport_driver pp_driver = { -- cgit v1.2.3 From ebf644c4623bc3eb57683199cd2b9080028b0f6f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 25 Jul 2006 17:13:31 -0700 Subject: Driver core: change mem class_devices to be real devices Signed-off-by: Greg Kroah-Hartman --- drivers/char/mem.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 55473371b7c..e67eef4867b 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -980,10 +980,10 @@ static int __init chr_dev_init(void) mem_class = class_create(THIS_MODULE, "mem"); for (i = 0; i < ARRAY_SIZE(devlist); i++) - class_device_create(mem_class, NULL, - MKDEV(MEM_MAJOR, devlist[i].minor), - NULL, devlist[i].name); - + device_create(mem_class, NULL, + MKDEV(MEM_MAJOR, devlist[i].minor), + devlist[i].name); + return 0; } -- cgit v1.2.3 From b09b845ca6724c3bbdc00c0cb2313258c7189ca9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 14 Nov 2006 20:52:19 -0800 Subject: [RANDOM]: Annotate random.h IP helpers. Signed-off-by: Al Viro Signed-off-by: David S. Miller --- drivers/char/random.c | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/random.c b/drivers/char/random.c index eb6b13f4211..d40df30c2b1 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1466,8 +1466,8 @@ static __init int seqgen_init(void) late_initcall(seqgen_init); #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -__u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, - __u16 sport, __u16 dport) +__u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr, + __be16 sport, __be16 dport) { struct timeval tv; __u32 seq; @@ -1479,10 +1479,10 @@ __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, */ memcpy(hash, saddr, 16); - hash[4]=(sport << 16) + dport; + hash[4]=((__force u16)sport << 16) + (__force u16)dport; memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7); - seq = twothirdsMD4Transform(daddr, hash) & HASH_MASK; + seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK; seq += keyptr->count; do_gettimeofday(&tv); @@ -1496,7 +1496,7 @@ EXPORT_SYMBOL(secure_tcpv6_sequence_number); /* The code below is shamelessly stolen from secure_tcp_sequence_number(). * All blames to Andrey V. Savochkin . */ -__u32 secure_ip_id(__u32 daddr) +__u32 secure_ip_id(__be32 daddr) { struct keydata *keyptr; __u32 hash[4]; @@ -1508,7 +1508,7 @@ __u32 secure_ip_id(__u32 daddr) * The dest ip address is placed in the starting vector, * which is then hashed with random data. */ - hash[0] = daddr; + hash[0] = (__force __u32)daddr; hash[1] = keyptr->secret[9]; hash[2] = keyptr->secret[10]; hash[3] = keyptr->secret[11]; @@ -1518,8 +1518,8 @@ __u32 secure_ip_id(__u32 daddr) #ifdef CONFIG_INET -__u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, - __u16 sport, __u16 dport) +__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, + __be16 sport, __be16 dport) { struct timeval tv; __u32 seq; @@ -1532,9 +1532,9 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, * Note that the words are placed into the starting vector, which is * then mixed with a partial MD4 over random data. */ - hash[0]=saddr; - hash[1]=daddr; - hash[2]=(sport << 16) + dport; + hash[0]=(__force u32)saddr; + hash[1]=(__force u32)daddr; + hash[2]=((__force u16)sport << 16) + (__force u16)dport; hash[3]=keyptr->secret[11]; seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK; @@ -1559,7 +1559,7 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, EXPORT_SYMBOL(secure_tcp_sequence_number); /* Generate secure starting point for ephemeral IPV4 transport port search */ -u32 secure_ipv4_port_ephemeral(__u32 saddr, __u32 daddr, __u16 dport) +u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) { struct keydata *keyptr = get_keyptr(); u32 hash[4]; @@ -1568,25 +1568,25 @@ u32 secure_ipv4_port_ephemeral(__u32 saddr, __u32 daddr, __u16 dport) * Pick a unique starting offset for each ephemeral port search * (saddr, daddr, dport) and 48bits of random data. */ - hash[0] = saddr; - hash[1] = daddr; - hash[2] = dport ^ keyptr->secret[10]; + hash[0] = (__force u32)saddr; + hash[1] = (__force u32)daddr; + hash[2] = (__force u32)dport ^ keyptr->secret[10]; hash[3] = keyptr->secret[11]; return half_md4_transform(hash, keyptr->secret); } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -u32 secure_ipv6_port_ephemeral(const __u32 *saddr, const __u32 *daddr, __u16 dport) +u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, __be16 dport) { struct keydata *keyptr = get_keyptr(); u32 hash[12]; memcpy(hash, saddr, 16); - hash[4] = dport; + hash[4] = (__force u32)dport; memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7); - return twothirdsMD4Transform(daddr, hash); + return twothirdsMD4Transform((const __u32 *)daddr, hash); } #endif @@ -1595,17 +1595,17 @@ u32 secure_ipv6_port_ephemeral(const __u32 *saddr, const __u32 *daddr, __u16 dpo * bit's 32-47 increase every key exchange * 0-31 hash(source, dest) */ -u64 secure_dccp_sequence_number(__u32 saddr, __u32 daddr, - __u16 sport, __u16 dport) +u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, + __be16 sport, __be16 dport) { struct timeval tv; u64 seq; __u32 hash[4]; struct keydata *keyptr = get_keyptr(); - hash[0] = saddr; - hash[1] = daddr; - hash[2] = (sport << 16) + dport; + hash[0] = (__force u32)saddr; + hash[1] = (__force u32)daddr; + hash[2] = ((__force u16)sport << 16) + (__force u16)dport; hash[3] = keyptr->secret[11]; seq = half_md4_transform(hash, keyptr->secret); @@ -1641,7 +1641,7 @@ unsigned int get_random_int(void) * drain on it), and uses halfMD4Transform within the second. We * also mix it with jiffies and the PID: */ - return secure_ip_id(current->pid + jiffies); + return secure_ip_id((__force __be32)(current->pid + jiffies)); } /* -- cgit v1.2.3 From d916faace3efc0bf19fe9a615a1ab8fa1a24cd93 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sun, 3 Dec 2006 22:22:41 -0500 Subject: Remove long-unmaintained ftape driver subsystem. It's bitrotten, long unmaintained, long hidden under BROKEN_ON_SMP, etc. As scheduled in feature-removal-schedule.txt, and ack'd several times on lkml. Signed-off-by: Jeff Garzik --- drivers/char/Kconfig | 33 - drivers/char/Makefile | 1 - drivers/char/ftape/Kconfig | 330 ------ drivers/char/ftape/Makefile | 28 - drivers/char/ftape/README.PCI | 81 -- drivers/char/ftape/RELEASE-NOTES | 966 --------------- drivers/char/ftape/compressor/Makefile | 31 - drivers/char/ftape/compressor/lzrw3.c | 743 ------------ drivers/char/ftape/compressor/lzrw3.h | 253 ---- drivers/char/ftape/compressor/zftape-compress.c | 1203 ------------------- drivers/char/ftape/compressor/zftape-compress.h | 83 -- drivers/char/ftape/lowlevel/Makefile | 43 - drivers/char/ftape/lowlevel/fc-10.c | 175 --- drivers/char/ftape/lowlevel/fc-10.h | 39 - drivers/char/ftape/lowlevel/fdc-io.c | 1349 --------------------- drivers/char/ftape/lowlevel/fdc-io.h | 252 ---- drivers/char/ftape/lowlevel/fdc-isr.c | 1170 ------------------- drivers/char/ftape/lowlevel/fdc-isr.h | 55 - drivers/char/ftape/lowlevel/ftape-bsm.c | 491 -------- drivers/char/ftape/lowlevel/ftape-bsm.h | 66 -- drivers/char/ftape/lowlevel/ftape-buffer.c | 130 --- drivers/char/ftape/lowlevel/ftape-buffer.h | 32 - drivers/char/ftape/lowlevel/ftape-calibr.c | 275 ----- drivers/char/ftape/lowlevel/ftape-calibr.h | 37 - drivers/char/ftape/lowlevel/ftape-ctl.c | 896 -------------- drivers/char/ftape/lowlevel/ftape-ctl.h | 162 --- drivers/char/ftape/lowlevel/ftape-ecc.c | 853 -------------- drivers/char/ftape/lowlevel/ftape-ecc.h | 84 -- drivers/char/ftape/lowlevel/ftape-format.c | 344 ------ drivers/char/ftape/lowlevel/ftape-format.h | 37 - drivers/char/ftape/lowlevel/ftape-init.c | 160 --- drivers/char/ftape/lowlevel/ftape-init.h | 43 - drivers/char/ftape/lowlevel/ftape-io.c | 992 ---------------- drivers/char/ftape/lowlevel/ftape-io.h | 90 -- drivers/char/ftape/lowlevel/ftape-proc.c | 214 ---- drivers/char/ftape/lowlevel/ftape-proc.h | 35 - drivers/char/ftape/lowlevel/ftape-read.c | 621 ---------- drivers/char/ftape/lowlevel/ftape-read.h | 51 - drivers/char/ftape/lowlevel/ftape-rw.c | 1092 ----------------- drivers/char/ftape/lowlevel/ftape-rw.h | 111 -- drivers/char/ftape/lowlevel/ftape-setup.c | 104 -- drivers/char/ftape/lowlevel/ftape-tracing.c | 118 -- drivers/char/ftape/lowlevel/ftape-tracing.h | 179 --- drivers/char/ftape/lowlevel/ftape-write.c | 336 ------ drivers/char/ftape/lowlevel/ftape-write.h | 53 - drivers/char/ftape/lowlevel/ftape_syms.c | 87 -- drivers/char/ftape/zftape/Makefile | 36 - drivers/char/ftape/zftape/zftape-buffers.c | 149 --- drivers/char/ftape/zftape/zftape-buffers.h | 55 - drivers/char/ftape/zftape/zftape-ctl.c | 1417 ----------------------- drivers/char/ftape/zftape/zftape-ctl.h | 58 - drivers/char/ftape/zftape/zftape-eof.c | 199 ---- drivers/char/ftape/zftape/zftape-eof.h | 52 - drivers/char/ftape/zftape/zftape-init.c | 377 ------ drivers/char/ftape/zftape/zftape-init.h | 77 -- drivers/char/ftape/zftape/zftape-read.c | 377 ------ drivers/char/ftape/zftape/zftape-read.h | 53 - drivers/char/ftape/zftape/zftape-rw.c | 375 ------ drivers/char/ftape/zftape/zftape-rw.h | 101 -- drivers/char/ftape/zftape/zftape-vtbl.c | 757 ------------ drivers/char/ftape/zftape/zftape-vtbl.h | 227 ---- drivers/char/ftape/zftape/zftape-write.c | 483 -------- drivers/char/ftape/zftape/zftape-write.h | 38 - drivers/char/ftape/zftape/zftape_syms.c | 43 - 64 files changed, 19402 deletions(-) delete mode 100644 drivers/char/ftape/Kconfig delete mode 100644 drivers/char/ftape/Makefile delete mode 100644 drivers/char/ftape/README.PCI delete mode 100644 drivers/char/ftape/RELEASE-NOTES delete mode 100644 drivers/char/ftape/compressor/Makefile delete mode 100644 drivers/char/ftape/compressor/lzrw3.c delete mode 100644 drivers/char/ftape/compressor/lzrw3.h delete mode 100644 drivers/char/ftape/compressor/zftape-compress.c delete mode 100644 drivers/char/ftape/compressor/zftape-compress.h delete mode 100644 drivers/char/ftape/lowlevel/Makefile delete mode 100644 drivers/char/ftape/lowlevel/fc-10.c delete mode 100644 drivers/char/ftape/lowlevel/fc-10.h delete mode 100644 drivers/char/ftape/lowlevel/fdc-io.c delete mode 100644 drivers/char/ftape/lowlevel/fdc-io.h delete mode 100644 drivers/char/ftape/lowlevel/fdc-isr.c delete mode 100644 drivers/char/ftape/lowlevel/fdc-isr.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-bsm.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-bsm.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-buffer.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-buffer.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-calibr.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-calibr.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-ctl.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-ctl.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-ecc.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-ecc.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-format.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-format.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-init.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-init.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-io.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-io.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-proc.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-proc.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-read.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-read.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-rw.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-rw.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-setup.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-tracing.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-tracing.h delete mode 100644 drivers/char/ftape/lowlevel/ftape-write.c delete mode 100644 drivers/char/ftape/lowlevel/ftape-write.h delete mode 100644 drivers/char/ftape/lowlevel/ftape_syms.c delete mode 100644 drivers/char/ftape/zftape/Makefile delete mode 100644 drivers/char/ftape/zftape/zftape-buffers.c delete mode 100644 drivers/char/ftape/zftape/zftape-buffers.h delete mode 100644 drivers/char/ftape/zftape/zftape-ctl.c delete mode 100644 drivers/char/ftape/zftape/zftape-ctl.h delete mode 100644 drivers/char/ftape/zftape/zftape-eof.c delete mode 100644 drivers/char/ftape/zftape/zftape-eof.h delete mode 100644 drivers/char/ftape/zftape/zftape-init.c delete mode 100644 drivers/char/ftape/zftape/zftape-init.h delete mode 100644 drivers/char/ftape/zftape/zftape-read.c delete mode 100644 drivers/char/ftape/zftape/zftape-read.h delete mode 100644 drivers/char/ftape/zftape/zftape-rw.c delete mode 100644 drivers/char/ftape/zftape/zftape-rw.h delete mode 100644 drivers/char/ftape/zftape/zftape-vtbl.c delete mode 100644 drivers/char/ftape/zftape/zftape-vtbl.h delete mode 100644 drivers/char/ftape/zftape/zftape-write.c delete mode 100644 drivers/char/ftape/zftape/zftape-write.h delete mode 100644 drivers/char/ftape/zftape/zftape_syms.c (limited to 'drivers/char') diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index ad8b537ad47..24f922f1278 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -855,39 +855,6 @@ config TANBAC_TB0219 depends TANBAC_TB022X select GPIO_VR41XX -menu "Ftape, the floppy tape device driver" - -config FTAPE - tristate "Ftape (QIC-80/Travan) support" - depends on BROKEN_ON_SMP && (ALPHA || X86) - ---help--- - If you have a tape drive that is connected to your floppy - controller, say Y here. - - Some tape drives (like the Seagate "Tape Store 3200" or the Iomega - "Ditto 3200" or the Exabyte "Eagle TR-3") come with a "high speed" - controller of their own. These drives (and their companion - controllers) are also supported if you say Y here. - - If you have a special controller (such as the CMS FC-10, FC-20, - Mountain Mach-II, or any controller that is based on the Intel 82078 - FDC like the high speed controllers by Seagate and Exabyte and - Iomega's "Ditto Dash") you must configure it by selecting the - appropriate entries from the "Floppy tape controllers" sub-menu - below and possibly modify the default values for the IRQ and DMA - channel and the IO base in ftape's configuration menu. - - If you want to use your floppy tape drive on a PCI-bus based system, - please read the file . - - The ftape kernel driver is also available as a runtime loadable - module. To compile this driver as a module, choose M here: the - module will be called ftape. - -source "drivers/char/ftape/Kconfig" - -endmenu - source "drivers/char/agp/Kconfig" source "drivers/char/drm/Kconfig" diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 777cad04509..b1fcdab9094 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -78,7 +78,6 @@ obj-$(CONFIG_TOSHIBA) += toshiba.o obj-$(CONFIG_I8K) += i8k.o obj-$(CONFIG_DS1620) += ds1620.o obj-$(CONFIG_HW_RANDOM) += hw_random/ -obj-$(CONFIG_FTAPE) += ftape/ obj-$(CONFIG_COBALT_LCD) += lcd.o obj-$(CONFIG_PPDEV) += ppdev.o obj-$(CONFIG_NWBUTTON) += nwbutton.o diff --git a/drivers/char/ftape/Kconfig b/drivers/char/ftape/Kconfig deleted file mode 100644 index 0d65189a7ae..00000000000 --- a/drivers/char/ftape/Kconfig +++ /dev/null @@ -1,330 +0,0 @@ -# -# Ftape configuration -# -config ZFTAPE - tristate "Zftape, the VFS interface" - depends on FTAPE - ---help--- - Normally, you want to say Y or M. DON'T say N here or you - WON'T BE ABLE TO USE YOUR FLOPPY TAPE DRIVE. - - The ftape module itself no longer contains the routines necessary - to interface with the kernel VFS layer (i.e. to actually write data - to and read data from the tape drive). Instead the file system - interface (i.e. the hardware independent part of the driver) has - been moved to a separate module. - - To compile this driver as a module, choose M here: the - module will be called zftape. - - Regardless of whether you say Y or M here, an additional runtime - loadable module called `zft-compressor' which contains code to - support user transparent on-the-fly compression based on Ross - William's lzrw3 algorithm will be produced. If you have enabled the - kernel module loader (i.e. have said Y to "Kernel module loader - support", above) then `zft-compressor' will be loaded - automatically by zftape when needed. - - Despite its name, zftape does NOT use compression by default. - -config ZFT_DFLT_BLK_SZ - int "Default block size" - depends on ZFTAPE - default "10240" - ---help--- - If unsure leave this at its default value, i.e. 10240. Note that - you specify only the default block size here. The block size can be - changed at run time using the MTSETBLK tape operation with the - MTIOCTOP ioctl (i.e. with "mt -f /dev/qft0 setblk #BLKSZ" from the - shell command line). - - The probably most striking difference between zftape and previous - versions of ftape is the fact that all data must be written or read - in multiples of a fixed block size. The block size defaults to - 10240 which is what GNU tar uses. The values for the block size - should be either 1 or multiples of 1024 up to a maximum value of - 63488 (i.e. 62 K). If you specify `1' then zftape's builtin - compression will be disabled. - - Reasonable values are `10240' (GNU tar's default block size), - `5120' (afio's default block size), `32768' (default block size some - backup programs assume for SCSI tape drives) or `1' (no restriction - on block size, but disables builtin compression). - -comment "The compressor will be built as a module only!" - depends on FTAPE && ZFTAPE - -config ZFT_COMPRESSOR - tristate - depends on FTAPE!=n && ZFTAPE!=n - default m - -config FT_NR_BUFFERS - int "Number of ftape buffers (EXPERIMENTAL)" - depends on FTAPE && EXPERIMENTAL - default "3" - help - Please leave this at `3' unless you REALLY know what you are doing. - It is not necessary to change this value. Values below 3 make the - proper use of ftape impossible, values greater than 3 are a waste of - memory. You can change the amount of DMA memory used by ftape at - runtime with "mt -f /dev/qft0 setdrvbuffer #NUMBUFFERS". Each buffer - wastes 32 KB of memory. Please note that this memory cannot be - swapped out. - -config FT_PROC_FS - bool "Enable procfs status report (+2kb)" - depends on FTAPE && PROC_FS - ---help--- - Optional. Saying Y will result in creation of a directory - `/proc/ftape' under the /proc file system. The files can be viewed - with your favorite pager (i.e. use "more /proc/ftape/history" or - "less /proc/ftape/history" or simply "cat /proc/ftape/history"). The - file will contain some status information about the inserted - cartridge, the kernel driver, your tape drive, the floppy disk - controller and the error history for the most recent use of the - kernel driver. Saying Y will enlarge the size of the ftape driver - by approximately 2 KB. - - WARNING: When compiling ftape as a module (i.e. saying M to "Floppy - tape drive") it is dangerous to use ftape's /proc file system - interface. Accessing `/proc/ftape' while the module is unloaded will - result in a kernel Oops. This cannot be fixed from inside ftape. - -choice - prompt "Debugging output" - depends on FTAPE - default FT_NORMAL_DEBUG - -config FT_NORMAL_DEBUG - bool "Normal" - ---help--- - This option controls the amount of debugging output the ftape driver - is ABLE to produce; it does not increase or diminish the debugging - level itself. If unsure, leave this at its default setting, - i.e. choose "Normal". - - Ftape can print lots of debugging messages to the system console - resp. kernel log files. Reducing the amount of possible debugging - output reduces the size of the kernel module by some KB, so it might - be a good idea to use "None" for emergency boot floppies. - - If you want to save memory then the following strategy is - recommended: leave this option at its default setting "Normal" until - you know that the driver works as expected, afterwards reconfigure - the kernel, this time specifying "Reduced" or "None" and recompile - and install the kernel as usual. Note that choosing "Excessive" - debugging output does not increase the amount of debugging output - printed to the console but only makes it possible to produce - "Excessive" debugging output. - - Please read for a short description - how to control the amount of debugging output. - -config FT_FULL_DEBUG - bool "Excessive" - help - Extremely verbose output for driver debugging purposes. - -config FT_NO_TRACE - bool "Reduced" - help - Reduced tape driver debugging output. - -config FT_NO_TRACE_AT_ALL - bool "None" - help - Suppress all debugging output from the tape drive. - -endchoice - -comment "Hardware configuration" - depends on FTAPE - -choice - prompt "Floppy tape controllers" - depends on FTAPE - default FT_STD_FDC - -config FT_STD_FDC - bool "Standard" - ---help--- - Only change this setting if you have a special controller. If you - didn't plug any add-on card into your computer system but just - plugged the floppy tape cable into the already existing floppy drive - controller then you don't want to change the default setting, - i.e. choose "Standard". - - Choose "MACH-2" if you have a Mountain Mach-2 controller. - Choose "FC-10/FC-20" if you have a Colorado FC-10 or FC-20 - controller. - Choose "Alt/82078" if you have another controller that is located at - an IO base address different from the standard floppy drive - controller's base address of `0x3f0', or uses an IRQ (interrupt) - channel different from `6', or a DMA channel different from - `2'. This is necessary for any controller card that is based on - Intel's 82078 FDC such as Seagate's, Exabyte's and Iomega's "high - speed" controllers. - - If you choose something other than "Standard" then please make - sure that the settings for the IO base address and the IRQ and DMA - channel in the configuration menus below are correct. Use the manual - of your tape drive to determine the correct settings! - - If you are already successfully using your tape drive with another - operating system then you definitely should use the same settings - for the IO base, the IRQ and DMA channel that have proven to work - with that other OS. - - Note that this menu lets you specify only the default setting for - the hardware setup. The hardware configuration can be changed at - boot time (when ftape is compiled into the kernel, i.e. if you - have said Y to "Floppy tape drive") or module load time (i.e. if you - have said M to "Floppy tape drive"). - - Please read also the file which - contains a short description of the parameters that can be set at - boot or load time. If you want to use your floppy tape drive on a - PCI-bus based system, please read the file - . - -config FT_MACH2 - bool "MACH-2" - -config FT_PROBE_FC10 - bool "FC-10/FC-20" - -config FT_ALT_FDC - bool "Alt/82078" - -endchoice - -comment "Consult the manuals of your tape drive for the correct settings!" - depends on FTAPE && !FT_STD_FDC - -config FT_FDC_BASE - hex "IO base of the floppy disk controller" - depends on FTAPE && !FT_STD_FDC - default "0" - ---help--- - You don't need to specify a value if the following default - settings for the base IO address are correct: - <<< MACH-2 : 0x1E0 >>> - <<< FC-10/FC-20: 0x180 >>> - <<< Secondary : 0x370 >>> - Secondary refers to a secondary FDC controller like the "high speed" - controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash. - Please make sure that the setting for the IO base address - specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR - CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already - successfully using the tape drive with another operating system then - you definitely should use the same settings for the IO base that has - proven to work with that other OS. - - Note that this menu lets you specify only the default setting for - the IO base. The hardware configuration can be changed at boot time - (when ftape is compiled into the kernel, i.e. if you specified Y to - "Floppy tape drive") or module load time (i.e. if you have said M to - "Floppy tape drive"). - - Please read also the file which - contains a short description of the parameters that can be set at - boot or load time. - -config FT_FDC_IRQ - int "IRQ channel of the floppy disk controller" - depends on FTAPE && !FT_STD_FDC - default "0" - ---help--- - You don't need to specify a value if the following default - settings for the interrupt channel are correct: - <<< MACH-2 : 6 >>> - <<< FC-10/FC-20: 9 >>> - <<< Secondary : 6 >>> - Secondary refers to secondary a FDC controller like the "high speed" - controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash. - Please make sure that the setting for the IO base address - specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR - CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already - successfully using the tape drive with another operating system then - you definitely should use the same settings for the IO base that has - proven to work with that other OS. - - Note that this menu lets you specify only the default setting for - the IRQ channel. The hardware configuration can be changed at boot - time (when ftape is compiled into the kernel, i.e. if you said Y to - "Floppy tape drive") or module load time (i.e. if you said M to - "Floppy tape drive"). - - Please read also the file which - contains a short description of the parameters that can be set at - boot or load time. - -config FT_FDC_DMA - int "DMA channel of the floppy disk controller" - depends on FTAPE && !FT_STD_FDC - default "0" - ---help--- - You don't need to specify a value if the following default - settings for the DMA channel are correct: - <<< MACH-2 : 2 >>> - <<< FC-10/FC-20: 3 >>> - <<< Secondary : 2 >>> - Secondary refers to a secondary FDC controller like the "high speed" - controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash. - Please make sure that the setting for the IO base address - specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR - CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already - successfully using the tape drive with another operating system then - you definitely should use the same settings for the IO base that has - proven to work with that other OS. - - Note that this menu lets you specify only the default setting for - the DMA channel. The hardware configuration can be changed at boot - time (when ftape is compiled into the kernel, i.e. if you said Y to - "Floppy tape drive") or module load time (i.e. if you said M to - "Floppy tape drive"). - - Please read also the file which - contains a short description of the parameters that can be set at - boot or load time. - -config FT_FDC_THR - int "Default FIFO threshold (EXPERIMENTAL)" - depends on FTAPE && EXPERIMENTAL - default "8" - help - Set the FIFO threshold of the FDC. If this is higher the DMA - controller may serve the FDC after a higher latency time. If this is - lower, fewer DMA transfers occur leading to less bus contention. - You may try to tune this if ftape annoys you with "reduced data - rate because of excessive overrun errors" messages. However, this - doesn't seem to have too much effect. - - If unsure, don't touch the initial value, i.e. leave it at "8". - -config FT_FDC_MAX_RATE - int "Maximal data rate to use (EXPERIMENTAL)" - depends on FTAPE && EXPERIMENTAL - default "2000" - ---help--- - With some motherboard/FDC combinations ftape will not be able to - run your FDC/tape drive combination at the highest available - speed. If this is the case you'll encounter "reduced data rate - because of excessive overrun errors" messages and lots of retries - before ftape finally decides to reduce the data rate. - - In this case it might be desirable to tell ftape beforehand that - it need not try to run the tape drive at the highest available - speed. If unsure, leave this disabled, i.e. leave it at 2000 - bits/sec. - -config FT_ALPHA_CLOCK - int "CPU clock frequency of your DEC Alpha" if ALPHA - depends on FTAPE - default "0" - help - On some DEC Alpha machines the CPU clock frequency cannot be - determined automatically, so you need to specify it here ONLY if - running a DEC Alpha, otherwise this setting has no effect. - diff --git a/drivers/char/ftape/Makefile b/drivers/char/ftape/Makefile deleted file mode 100644 index 0e67d2f8b7e..00000000000 --- a/drivers/char/ftape/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (C) 1997 Claus 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/Makefile,v $ -# $Revision: 1.4 $ -# $Date: 1997/10/05 19:17:56 $ -# -# Makefile for the QIC-40/80/3010/3020 floppy-tape driver for -# Linux. -# - -obj-$(CONFIG_FTAPE) += lowlevel/ -obj-$(CONFIG_ZFTAPE) += zftape/ -obj-$(CONFIG_ZFT_COMPRESSOR) += compressor/ diff --git a/drivers/char/ftape/README.PCI b/drivers/char/ftape/README.PCI deleted file mode 100644 index 18de159d36e..00000000000 --- a/drivers/char/ftape/README.PCI +++ /dev/null @@ -1,81 +0,0 @@ -Some notes for ftape users with PCI motherboards: -================================================= - -The problem: ------------- - -There have been some problem reports from people using PCI-bus based -systems getting overrun errors. -I wasn't able to reproduce these until I ran ftape on a Intel Plato -(Premiere PCI II) motherboard with bios version 1.00.08AX1. -It turned out that if GAT (Guaranteed Access Timing) is enabled (?) -ftape gets a lot of overrun errors. -The problem disappears when disabling GAT in the bios. -Note that Intel removed this setting (permanently disabled) from the -1.00.10AX1 bios ! - -It looks like that if GAT is enabled there are often large periods -(greater than 120 us !??) on the ISA bus that the DMA controller cannot -service the floppy disk controller. -I cannot imagine this being acceptable in a decent PCI implementation. -Maybe this is a `feature' of the chipset. I can only speculate why -Intel choose to remove the option from the latest Bios... - -The lesson of this all is that there may be other motherboard -implementations having the same of similar problems. -If you experience a lot of overrun errors during a backup to tape, -see if there is some setting in the Bios that may influence the -bus timing. - -I judge this a hardware problem and not a limitation of ftape ;-) -My DOS backup software seems to be suffering from the same problems -and even refuses to run at 1 Mbps ! -Ftape will reduce the data-rate from 1 Mbps to 500 Kbps if the number -of overrun errors on a track exceeds a threshold. - - -Possible solutions: -------------------- - -Some of the problems were solved by upgrading the (flash) bios. -Other suggest that it has to do with the FDC being on the PCI -bus, but that is not the case with the Intel Premiere II boards. -[If upgrading the bios doesn't solve the problem you could try -a floppy disk controller on the isa-bus]. - -Here is a list of systems and recommended BIOS settings: - - - Intel Premiere PCI (Revenge): - -Bios version 1.00.09.AF2 is reported to work. - - - - Intel Premiere PCI II (Plato): - -Bios version 1.00.10.AX1 and version 11 beta are ok. -If using version 1.00.08.AX1, GAT must be disabled ! - - - - ASUS PCI/I-SP3G: - -Preferred settings: ISA-GAT-mode : disabled - DMA-linebuffer-mode : standard - ISA-masterbuffer-mode : standard - - - DELL Dimension XPS P90 - -Bios version A2 is reported to be broken, while bios version A5 works. -You can get a flash bios upgrade from http://www.dell.com - - -To see if you're having the GAT problem, try making a backup -under DOS. If it's very slow and often repositions you're -probably having this problem. - - --//-- - LocalWords: ftape PCI bios GAT ISA DMA chipset Mbps Kbps FDC isa AF ok ASUS - LocalWords: SP linebuffer masterbuffer XPS http www com diff --git a/drivers/char/ftape/RELEASE-NOTES b/drivers/char/ftape/RELEASE-NOTES deleted file mode 100644 index 03799dbc05a..00000000000 --- a/drivers/char/ftape/RELEASE-NOTES +++ /dev/null @@ -1,966 +0,0 @@ -Hey, Emacs, we're -*-Text-*- mode! - -===== Release notes for ftape-3.04d 25/11/97 ===== -- The correct pre-processor statement for "else if" is "#elif" not - "elsif". -- Need to call zft_reset_position() when overwriting cartridges - previously written with ftape-2.x, sftape, or ancient - (pre-ftape-3.x) versions of zftape. - -===== Release notes for ftape-3.04c 16/11/97 ===== -- fdc_probe() was calling DUMPREGS with a result length of "1" which - was just fine. Undo previous change. - -===== Release notes for ftape-3.04b 14/11/97 ===== - -- patches/2.x.x/floppy.c.diff was somewhat broken, releasing i/o - regions it never had allocated. -- fdc_probe() was calling DUMPREGS with a result length of "1" instead - of "10" -- Writing deleted data marks if the first segents on track zero are - should work now. -- ftformat should now be able to handle those cases where the tape - drive sets the read only status bit (QIC-40/80 cartridges with - QIC-3010/3020 tape drives) because the header segment is damaged. -- the MTIOCFTCMD ioctl may now be issued by the superuser ONLY. - -===== Release notes for ftape-3.04a 12/11/97 ===== -- Fix an "infinite loop can't be killed by signal" bug in - ftape_get_drive_status(). Only relevant when trying to access - buggy/misconfigured hardware -- Try to compensate a bug in the HP Colorado T3000's firmware: it - doesn't set the write protect bit for QIC80/QIC40 cartridges. - -===== Release notes for ftape-3.04 06/11/97 ===== -- If positioning with fast seeking fails fall back to a slow seek - before giving up. -- (nearly) no retries on "no data errors" when verifying after - formatting. Improved tuning of the bad sector map after formatting. -- the directory layout has changed again to allow for easier kernel - integration -- Module parameter "ftape_tracing" now is called "ft_tracing" because - the "ftape_tracing" variable has the version checksum attached to it. -- `/proc/ftape' interface for 2.0.* kernels. `/proc/ftape' no longer - is a directory but a file that contains all the information formerly - provided in separate files under the `/proc/ftape/' directory. -- Most of the configuration options have been prefixed by "CONFIG_FT_" - in preparation of the kernel inclusion. The Makefiles under - "./ftape/" should be directly usable by the kernel. -- The MODVERSIONS stuff is now auto-detected. -- Broke backslashed multi line options in MCONFIG into separate lines - using GNU-make's "+=" feature. -- The html and dvi version of the manual is now installed under - '/usr/doc/ftape` with 'make install` -- New SMP define in MCONFIG. ftape works with SMP if this is defined. -- attempt to cope with "excessive overrun errors" by gradually - increasing FDC FIFO threshold. But this doesn't seem to have too - much an effect. -- New load time configuration parameter "ft_fdc_rate_limit". If you - encounter too many overrun errors with a 2Mb controller then you - might want to set this to 1000. -- overrun errors on the last sector in a segment sometimes result in - a zero DMA residue. Dunno why, but compensate for it. -- there were still fdc_read() timeout errors. I think I have fixed it - now, please FIXME. -- Sometimes ftape_write() failed to re-start the tape drive when a - segment without a good sector was reached ("wait for empty segment - failed"). This is fixed. Especially important for > QIC-3010. -- sftape (aka ftape-2.x) has vanished. I didn't work on it for - ages. It is probably still possible to use the old code with - ftape-3.04, if one really needs it (BUT RECOMPILE IT) -- zftape no longer alters the contents of already existing volume - table entries, which makes it possible to fill in missing fields, - like time stamps using some user space program. -- ./contrib/vtblc/ contains such a program. -- new perl script ./contrib/scripts/listtape that list the contents of a - floppy tape cartridge parsing the output of "mt volinfo" + "mt fsf" -- the MTWEOF implementation has changed a little bit (after I had a - look at amanda). Calling MTWEOF while the tape is still held open - after writing something to the tape now will terminate the current - volume, and start a new one at the current position. -- the volume table maintained by zftape now is a doubly linked list - that grows dynamically as needed. - - formatting floppy tape cartridges - --------------------------------- - * there is a new user space formatting program that does most of the - dirty work in user space (auto-detect, computing the sector - coordinates, adjusting time stamps and statistics). It has a - simple command line interface. - * ftape-format.o has vanished, it has been folded into the low level - ftape.o module, and the ioctl interface into zftape.o. Most of the - complicated stuff has been moved to user space, so there was no - need for a separate module anymore. - * there is a new ioctl MTIOCFTCMD that sends a bare QIC-117 command - to the tape drive. - * there is a new mmap() feature to map the dma buffers into user - space to be used by the user level formatting program. - * Formatting of yet unformatted or totally degaussed cartridges - should be possible now. FIXME. - -===== Release notes for ftape-3.03b, ==== - -ftape-3.03b was released as a beta release only. Its main new feature -was support of the DITTO-2GB drive. This was made possible by reverse -engineering done by after Iomega failed to support -ftape. Although they had promised to do so (this makes me feel a bit -sad and uncomfortable about Iomega). - -===== Release notes for ftape-3.03a, 22/05/97 ==== - -- Finally fixed auto-un-loading of modules for kernels > 2.1.18 -- Add an "uninstall" target to the Makefile -- removed the kdtime hack -- texi2www didn't properly set the back-reference from a footnote back - to the regular text. - - zftape specific - --------------- - * hide the old compression map volume. Taper doesn't accept the - presence of non-Taper volumes and Taper-written volume on the same - tape. - * EOD (End Of Data) handling was still broken: the expected behavior - is to return a zero byte count at the first attempt to read past - EOD, return a zero byte count at the second attempt to read past - EOD and THEN return -EIO. - - ftape-format specific - --------------------- - * Detection of QIC-40 cartridges in select_tape_format() was broken - and made it impossible to format QIC-3010/3020 cartridges. - * There are strange "TR-1 Extra" cartridges out there which weren't - detected properly because the don't strictly conform to the - QIC-80, Rev. N, spec. - -===== Release notes for ftape-3.03, 30/04/97 ===== - -- Removed kernel integration code from the package. I plan to provide - a package that can be integrated into the stock kernel separately - (hopefully soon). - As a result, a simple `make' command now will build everything. -- ALL compile time configuration options have been moved to the file - `MCONFIG'. -- Quite a few `low level' changes to allow formatting of cartridges. -- formatting is implemented as a separate module `ftape-format.o'. The - modified `mt' program contains sample code that shows how to use it. -- The VFS interface has been moved from the `ftape.o' module to the - high level modules `zftape.o' resp. `sftape.o'. `ftape.o' contains - the hardware support only. -- A bit of /proc support for kernels > 2.1.28 -- Moved documentation to Doc subdir. INSTALL now contains some real - installation notes. -- `install' target in Makefile. - -zftape specific: ----------------- - -- zftape works for large cartridges now ( > 2^31 bytes) -- MTIOCVOLINFO and MTIOCGETSIZE now return the size in KILOBYTES, - NO LONGER in bytes. - -- permissions for write access to a cartridge have changed: - * zftape now also takes the file access mode into account - * zftape no longer allows writing in the middle of the recorded - media. The tape has to be positioned at BOT or EOD for write - access. - -- MTBSF has changed. It used to position at the beginning of the - previous file when called with count 1. This was different from the - expected behavior for other Un*x tape drivers (i.e. SCSI). MTBSF - with count 1 should merely position at the beginning of the current - volume. Fixed. As a result, `tar --verify' now produces the desired - result: it verifies the last written volume, not the pre-last - written volume. - -- The compression map has vanished --> no need for `mt erase' any - more. Fast seeking in a compressed volume is still be possible, but - takes slightly longer. As a side effect, you may experience an - additional volume showing up in front of all others for old - cartridges. This is the tape volume that holds the compression map. - -- The compression support for zftape has been moved to a separate - module `zft-compressor'. DON'T forget to load it before trying to - read back compressed volumes. The stock `zftape.o' module probes for - the module `zft-compressor' using the kerneld message channel; you - have to install `zft-compressor.o' in a place where modprobe can - find it if you want to use this. - -- New experimental feature that tries to get the broken down GMT time - from user space via a kernel daemon message channel. You need to - compile and start the `kdtime' daemon contained in the contrib - directory to use it. Needed (?) for time stamps in the header - segments and the volume table. - -- variable block size mode via MTSETBLK 0 - -- keep modules locked in memory after the block size has been changed - -sftape specific: ----------------- - -- end of tape handling should be fixed, i.e. multi volume archives - written with `afio' can be read back now. - - -===== Release notes for ftape-3.02a, 09/01/97 ===== - -No big news: -- call zft_init() resp. sft_init() when compiling the entire stuff - into the kernel image. -- fix bug in ftape-setup.c when NO_TRACE_AT_ALL was defined. -- fix bug in sftape-eof.c/zftape-eof.c for old kernels (1.2.*) -- add support for new module interface for recent kernels - -===== Release notes for ftape-3.02, 16/12/96 ===== -- Fixed the `FDC unlock command failed' bug in fdc-io.c. When the FIFO - was already locked when ftape was loaded, ftape failed to unlock it. -- Fixed compilation of `contrib/gnumt'. It now finds `mtio.h' even if - ftape is NOT included into the kernel source tree. -- fc-10.c: include for inb() and outb(). -- ftape/sftape/zftape: all global variable now have either a `ftape_', - a `ft_', `sft_', `zft_' or `qic_' prefix to prevent name clashes - with other parts of the kernel when including ftape into the kernel - source tree. -- Kerneld support has changed. `ftape' now searches for a module - `ftape-frontend' when none of the frontend (`sftape' or `zftape') is - loaded. Please refer to the `Installation/Loading ftape' section of - the TeXinfo manual. -- Add load resp. boot-time configuration of ftape. There are now - variables ft_fdc_base, ft_fdc_dma and ft_fdc_irq corresponding to - the former FDC_BASE etc. compile time definitions. One can also use - the kernel command line parameters to configure the driver if it is - compiled into the kernel. Also, the FC-10/FC-20 support is load-time - configurable now as well as the MACH-II hack (ft_probe_fc10, - resp. ft_mach2). Please refer to the section `Installation/Configure - ftape' of the TeXinfo manual. -- I removed the MODVERSIONS option from `Makefile.module'. Let me alone - with ftape and MODVERSIONS unless you include the ftape sources into - the kernel source tree. -- new vendors in `vendors.h': - * HP Colorado T3000 - * ComByte DoublePlay (including a bug fix for their broken - formatting software, thanks to whraven@njackn.com) - * Iomega DITTO 2GIG. NOTE: this drive cannot work with ftape because - the logical data layout of the cartridges used by this drive does - NOT conform to the QIC standards, it is a special Iomega specific - format. I've sent mail to Iomega but didn't receive an answer - yet. If you want this drive to be supported by ftape, ask Iomega - to give me information about it. -- zftape: - * re-introduced the MTIOC_ZFTAPE_GETBLKSZ ioctl for compatibility - with zftape 1.06a and earlier. Please don't use it when writing - new software, use the MTIOCVOLINFO ioctl instead. - * Major overhaul of the code that updates the header segments. Never - change the tape label unless erasing the tape. Thus we almost - never need to write the header segments, unless we would modify - the bad sector map which isn't done yet. Updating of volume table - and compression map more secure now although it takes a bit - longer. - * Fixed bug when aborting a write operation with a signal: zftape - now finishes the current volume (i.e. writes an eof marker) at the - current position. It didn't before which led to somehow *strange* - behavior in this cases. - * Keep module locked in memory when using it with the non-rewinding - devices and the tape is not logical at BOT. Needed for kerneld - support. -- sftape: - * Keep module locked in memory when using it with the non-rewinding - devices and the tape is not logical at BOT. Needed for kerneld - support. - -===== Release notes for ftape-3.01, 14/11/96 ===== - -- Fixed silly bugs in ftape-3.00: - * MAKEDEV.ftape: major device number must be 27, not 23 - * sftape/sftape-read.c: sftape_read_header_segments() called - itself recursively instead of calling ftape_read_header_segment() - * zftape/qic-vtbl.h: conversion of ftape's file marks to zftape's - internal volume table was broken. - * patches/2.x.x/linux-2.0.21.dif: my RCS (resp. CVS) system replaced - the `$Revison:' etc. macros in the `ftape.h' concerning part of the - patch :-( Fixed. - * info/ftape.info: Fixed misspellings (`cp' <-> `cp -r' etc.) - * when ftape/sftape or ftape/zftape was compiled into the kernel the - variable ftape_status was declared twice. Fixed. - * removed reference to undeclared variable kernel_version when not - compiling as module - * fixed a bug introduced by the use of bit-fields for some flags - (i.e. write_protected, no_cartridge, formatted) - * flag `header_read' is now reset correctly to zero when tape is - removed. -- fixed a bug in sftape/sftape-eof.c that was already in the original - ftape code. MTFSF/BSF was not handled correctly when positioned - right before the file mark (think of tar) -- Changed TRACE macros (following a suggestion of Marcin Dalecki) to use - the predefined __FUNCTION__ macro of GCC. Spares about 4k of code. -- added new vendor id for Iomega DITTO 2GIG -- fixed a bug already present in zftape-1.06 when aborting a write - with a signal: we now finish the current volume at that - position. Header segments remain NOT up to date until an explicit call - to MTREW or MTOFFL is done. - -===== Release notes for ftape-3.00, 14/10/96 ===== - -- Merged ftape with zftape. There are three modules now: - ftape for the hardware support, sftape for the implementation of the - original ftape eof mark stuff and zftape that implements zftape's way - of handling things (compression, volume table, tape blocks of - constant length) -- Documentation in TeXinfo format in the `info' subdirectory. -- New ioctls for zftape. See zftape/zftape.h -- Dummy formatting ioctl for ftape. See ftape.h -- Kernel patch files for the 2.*.* series to include ftape-3.00 in the - kernel source tree. These includes a kernel compatible Config.in - script and fairly large online information for the kernel configure - script. -- Support for compiling with Linux-1.2.13. -- Modified GNU mt from their cpio package that can handle the new - ioctls. -- ftape/sftape/zftape is kerneld save now! - -Notes on sftape: -- sftape implements the eof handling code of the original ftape. If - you like to stick with the original ftape stuff, you have to use - this module, not zftape. -- sftape is kerneld save, unlike the original ftape. -- we keep the entire header segment now in memory, so no need to read - it before updating the header segments. Additional memory - consumption: 256 bytes. - -Notes for zftape: -- zftape has support for tapes with format code 6 now, which use a - slightly different volume table format compared with other floppy - tapes. -- new ioctls for zftape. Have a look at zftape/zftape.h -- The internal volume table representation has changed for zftape. Old - cartridges are converted automatically. -- zftape no longer uses compression map segments, which have vanished - from the QIC specs, but creates volume table entry that reserves - enough space for the compression map. -- zftape is kerneld save now. -- we keep the entire header segment now in memory, so no need to read - it before updating the header segments. Additional memory - consumption: 256 bytes. - -Notes for contrib/gnumt: -- modified mt from the GNU cpio package that supports all the new - ioctls of zftape. -Notes for contrib/swapout: -- This contains the swapout.c program that was written by Kai - Harrekilde-Pederson. I simply added a Makefile. - -===== Release notes for ftape-2.10, 14/10/96 ===== - -The ftape maintainer has changed. -Kai Harrekilde-Petersen -has resigned from maintaining ftape, and I, -Claus-Justus Heine , -have taken over. - -- Added support for tapes with `format code 6', i.e. QIC-3020 tapes - with more than 2^16 segments. -- merged changes made by Bas Laarhoven with ftape-2.09. Refer - to his release notes below. I've included them into this - file unchanged for your reference. -- disabled call stack back trace for now. This new feature - introduced by the interim release 2.0.x still seems to - be buggy. -- Tried to minimize differences between the ftape version - to be included into the kernel source tree and the standalone - module version. -- Reintroduced support for Linux-1.2.13. Please refer to the - Install-guide. - -===== Release notes for ftape-2.09, 16/06/96 ===== - -There aren't any really big news in this release, mostly just that I -(the maintainer) have changed my email address (due to a new job). My -new address is - -- The CLK_48MHZ and FDC_82078SL options has gone (all 2Mbps cards seem - to use a 48MHz oscillator anyway and I haven't heard of an 'SL - chip out there). -- The S82078B has been `downgraded' to i82077AA compability. -- TESTING option revived. Right now, it'll enable the (seriously broken) - 2Mbps code. If you enable it, you'll experience a tape drive that's - *really* out to lunch! -- Some (bold) changes in the init code. Please notify me if they - break things for you. - -===== Release notes for ftape-2.08, 14/03/96 ===== - -If you correct a problem with ftape, please send your patch to -khp@dolphinics.no too. - -- Updated to reflect that NR_MEM_LISTS is gone in 1.3.74 -- Teac 700 added to list of known drives. -- The registered device name is now "ft" rather than "ftape". - -===== Release notes for ftape-2.07a, 14/03/96 ===== - -Bugfixes by Marcin Dalecki : -- In the last release it just compiled against 1.3.70; - now the params to request_irq() and free_irq are() are fixed, so it also - works in 1.3.73 :-) -- Support for modules is now correct for newer kernels. - -===== Release notes for ftape-2.07, 04/03/96 ===== - - -- ftape updated to compile against 1.3.70. -- Iomega 700 and Wangtek 3200 recognised. - - -===== Release notes for ftape-2.06b, 13/02/96 ===== - -Another simple bugfix version. - -- Jumbo 700 recognised. -- Typo in vendors.h fixed. - - -===== Release notes for ftape-2.06a, 10/02/96 ===== - -This release is a simple bugfix version. - -- Linux/SMP: ftape *should* work. -- FC-10/20: Only accepts IRQs 3-7, or 9. If IRQ 9, properly tell the card - to use IRQ 2. Thanks to Greg Crider (gcrider@iclnet.org) for finding and - locating this bug and testing the patch. -- Insight drive recognised correctly again. -- Motor-on wakeup version of the Iomega 250 drive added - - -===== Release notes for ftape-2.06, 28/01/96 ===== - -Special thanks go to Neal Friedman and Steven Sorbom for their -help in producing and testing this release. - -I have continued to clean up the code, with an eye towards inclusion -of ftape in Linus' official kernel (In fact, as I type this, I am -running on a kernel with ftape support statically linked). I have -test-compiled ftape against my 1.2.13 tree without problems. -Hopefully, everything should be OK for the v1.2.x people. - -WARNING! Alan Cox has mailed me that ftape does *NOT* work with -Linux/SMP. If you try to run ftape under Linux/SMP, it will cause a -kernel deadlock (which is worse than a panic). - -- QIC-3020/TR-3: 1Mbps support works. Neal is capable of reading and - writing data to a tape. ftape will automatically detect the type of - tape (e.g. TR-3 vs QIC-80) and move the fdc in and out of - "perpendicular mode" as necessary. -- 2Mbps support is disabled by default, since it is not fully - debugged. If you are adventurous, remove -DFDC_82078SL in the - Makefile and see what happens :-) -- fdc detection: silly bugs removed (Only 2Mbps fdcs were affected) - and added detection of the National Semiconductors PC8744 fdc chip - (used in the PC873xx "super-IO" chips). -- Removed warning about incompatible types when compiling with Linux - 1.2.x. -- README.PCI updated with info about the DELL Dimension XPS P90. -- Connor TST3200R added to detected drives. -- `swapout' utility added to distribution. It will dirty 5Meg of - memory, trying to swap out other programs. Just say `make swapout' - to build it. ftape will do this automatically Real Soon Now (ie: - when I have found out which kernel memory alloc function to call). - - -===== Release notes for ftape-2.05, 08/01/96 ===== - -- For v1.2.x Kernels, you must apply the patch linux-1.2/ksyms.patch to - the kernel and rebuild it (it adds the __get_dma_pages symbol to - ksyms.c). -- Included new asm-i386/io.h file from v1.3.x kernel series, to enable - gcc v.2.7.[12] to compile v1.2.x kernels (linux-1.2/io.h). -- Module versions: If you wish to compile ftape as a versioned module, - you must first compile your kernel with CONFIG_MODVERSIONS=y. - Otherwise, you will get complaints that does not - exist (if that happens, a `touch modversions.h' will help you out). -- CLK_48MHZ: new define in the Makefile (default: non-zero). If you have - a tape controller card that uses the i82078(-1) chip, but cannot get - it to work with ftape, try set it to 0 (and please report this). -- QIC-3010/3020: Complete support is still missing, but will hopefully - come soon. Steven Sorbom has kindly provided me with hints about - this. Writing of QIC-3020 tapes definitely does NOT work (do not try - it! - the drive will not be in "perpendicular mode" and this will ruin - the formatting info on the tape). -- ftape_num_buffers is out of fashion: use NR_BUFFERS instead (and - recompile if you want to change it :-). - - -===== Release notes for ftape-2.04, 01/01/96 ===== - -This version by Kai Harrekilde-Petersen - -- ALERT! Support for Kernels earlier then v1.1.85 is about to go away. - I intend to clean up some of the code (getting rid of an annoyingly - large numbers of #ifdef mostly), which means that support for - pre-1.1.85 kernels must go as well. -- NR_FTAPE_BUFFERS is gone; You can instead select the number of dma - buffers by saying `insmod ftape.o ftape_num_buffer=' instead. -- Configure script gone. ftape will now automagically determine your - kernel version by /usr/include/linux/version.h instead. -- CONFIG_MODVERSIONS now work. All combinations of versioned / - unversioned kernel and ftape module works (at least with my 1.3.52 - kernel). -- If you have problems with inserting ftape into an old (1.2.x) - kernel (e.g. insmod says "1.2.8 does not match 1.2.8), recompile - your modules utilities with your new compiler. -- Reveal TB1400 drive added to vendors.h -- Support for the i82078-1 (2Mbps) chip is coming along. The - biggest problem is that I don't have such a card, which makes - testing / debugging somewhat problematic. The second biggest - problem is that I do not have the QIC-3010/3020 standards either. - Status right now is that the chip is detected, and it should be - possible to put it into 2Mbps mode. However, I do not know what - "extras" are needed to complete the support. Although putting the - i82078 into 1Mbps mode ought to work out of the box, it doesn't - (right now, ftape complains about id am errors). - - -===== Release notes for ftape-2.04beta5, 29/12/95 ===== - -Bas offline linux-tape ----------------------- -For reasons only known to the majordomo mail list processor, Bas was -kicked off the linux-tape list sometime during the summer. Being -overworked at his for-pay job, he didn't notice it much. Instead I -(Kai, khp@dolphinics.no) has worked on ftape to produce the 2.04(beta) -version. - -zftape ------- -Note that there exists a much improved version of ftape, written by -Claus-Justus Heine which is named -zftape, which conforms to the QIC-80 specs on how to mark backups, and -is capable of doing automatic compression. However, zftape makes -substantial changes to ftape, and I (Kai) have therefore declined to -integrate zftape into ftape. Hopefully, this will happen soon. - -CONFIG_QIC117 removed from the kernel -------------------------------------- -The biggest change of all is that ftape now will allocate its dma -buffers when it is inserted. The means that the CONFIG_QIC117 option -has disappeared from the Linux kernel as of v1.3.34. If you have an -earlier kernel, simply answer 'no' to the question will do the trick -(if you get complains about __get_free_pages() missing, contact the -linux-tape mailing list). - -Note that ftape-2.04beta will work equally well on kernels with and -without `ftape support'. The only catch is, that you will waste -around 96-128Kb of precious DMA'able memory on a box that has ftape -support compiled in. - -Now for the real changes: - -- FC-20 can now use DMA channels 1, 2, and 3. Thanks to Daniel - Cohen, catman@wpi.edu. -- ftape no longer requires a (gigantic) 96Kb buffer to be statically - allocated by the kernel. -- Added new Iomega drive (8882) to vendors.h -- -fno-strength-reduce added to Makefile, since GCC is broken. -- i82078-1 (2Mbps) FDC support started. - - -===== Release notes for ftape-2.03b, 27/05/95 ===== - -- Prevented verify_area to return error if called with zero length. -- Fixed a bug in flush_buffers that caused too much padding to be - written when a final segment had bad sectors. -- Increased maximum fast-seek overshoot value from 5 to 10 segments. -- Breaking loop after 5 retries when positioning fails. -- Fixed wrong calculation of tape length for QIC-3010 and QIC-3020 - tapes (densities were swapped). -- Fixed wrong calculation of overshoot on seek_forward: Wrong sign - of error. -- Suppress (false) error message due to new tape loaded. -- Added two new CMS drives (11c3 and 11c5) to vendors.h. - - -===== Release notes for ftape-2.03a, 09/05/95 ===== - -- Fixed display of old error (even if already cleared) in ftape_open. -- Improved tape length detection, ioctls would fail for 425 ft tapes. - Until the tape length is calculated with data from the header - segment, we'll use worst-case values. -- Clear eof_mark after rewinding ioctls. -- Fixed wrong version message (2.03 had 2.02g id). -- Fixed bug that caused the fdc to be reset very frequently. - This shouldn't affect normal operation but the timing of the - report routines has changed again and that may cause problems. - We'll just have to find out.... -- Implemented correct write precompensation setting for QIC-3010/3020. -- Cleaned up fdc_interrupt_wait routine. Hope it still works :-) -- Finally removed (already disabled) special eof mark handling for - gnu tar. -- Changed order of get_dma_residue and disable_dma in fdc-isr.c - because the current order would fail on at least one system. - We're back to the original order again, hope (and expect) this - doesn't break any other system. - - -===== Release notes for ftape-2.03, 07/05/95 ===== - -(Changes refer to the first ftape-2.02 release) - -Support for wide and extended length tapes ------------------------------------------- -The Conner TSM 420 and 850 drives are reported to be working. -I haven't received any reports about other brands; the TSM 420 -and 850 seem to be the most widely used wide drives. -Extended length tapes (425 ft) with normal QIC-80 drives -are operating too (At least I've had no reports stating otherwise). -_Not_ yet completely supported (although they may work) are -QIC-3020 drives and 2 Mbps floppy disk controllers won't work at -the highest speed. -If someone is kind enough to send me one of these, I'll include -support for it too ;-) - -Easier configuration --------------------- -Problems due to wrong settings in the Makefile are prevented -by using a configuration script that sets the necessary (kernel -version dependent) compile time options. -This kernel version is now determined from the sources found -at /usr/src/linux, or if not found, the old way using -/proc/version. -Versioned modules will be used automatically when supported -by- and configured in- the kernel. -Note that the current modules code (1.1.87) is still broken -and _needs_ the fix included in the insmod directory. -Please don't send me any more Oops reports caused by insmod :-( - -Reduced module size -------------------- -The standard module size is much reduced and some compile time -options can even reduce it further. (I don't recommend this -for normal use but it can be handy for rescue diskettes) - -Option: Approx. module size: - - 150 Kb -NO_TRACE 125 Kb -NO_TRACE_AT_ALL 67 Kb - - -Much improved driver interruption ---------------------------------- -Most possible loops have been broken and signal detection -has been improved. -In most cases the driver can be aborted by ^C (SIGINT) and -SIGKILL (kill -9) will generate be a sure kill. -(Note that aborting a tape operation may damage the last -data written to tape) - -Improved error recovery ------------------------ -Ftape now returns an error (ENODATA) to the application if -a segment proves to be unrecoverable and then skips the -bad segment. -This causes most applications to continue to work (tar -and afio) loosing only a small amount (up to 29 Kb) of data. -Retried read operations will now be done slightly off-track -to improve the chance of success. Serious head off-track -errors will be detected. - -FC-10 and FC-20 controllers ---------------------------- -Ftape now supports both the old CMS FC-10 and the newer FC-20 -controllers. -Because the operation of these cards is still undocumented, -thus far they will only work with the default settings (See -Makefile). Any feed-back on how to use them with other settings -will be welcome ! -Compilation will fail if one changes the settings to illegal -values. - -Kernels and compilers ---------------------- -Ftape is currently being developed using the 2.5.8 compiler. -The older 2.4.5 probably works too (Set option in Makefile!). -I have no experience with any later compilers nor Elf support. -Any information on this is welcome. -The latest kernel I have tested ftape with is 1.2.6. - -Compression ------------ -An impressive collection of changes for ftape including -on-the-fly compression is still lying on my desk. -If 2.03 proves to be reliable I might start integrating these -but as usual, I'm short in time :-( - -Formatting ----------- -There is still no way to format tapes under Linux. As far as -I know all attempts to write such a program have died now. -Since formatted tapes are rather common now, I think all we -need is a utility that writes a worst case pattern and verifies -that with the drive put in verify mode, reducing margins. -Any takers ? - -Furthermore ------------ -Cleaned up messages. -Prepared to support multiple tape drives on one fdc. -Thanks to all the people who sent bug reports and helped me -improve the driver. Without trying to be complete I'll mention -Gary Anderson (without his accurate reports and unreliable -hardware there wouldn't be a 2.03), Stefan Kneifel (FC-20), -Robert Broughton (FC-20, you were almost there ;-), Bjorn -Ekwall (for the versioned modules and buggy insmod ;-), Peter -Fox, Christopher Oliver, Ralph Whittaker and not the least -Linus Torvalds (for Linux and keeping me busy because of -changes to the kernel ;-) -Thanks to anyone I forgot, for the bug reports, the ftape -bashing and the mental support... - - -That's it for now. Have Fun, - -Bas. - - -===== Release notes for ftape-2.02g, 06/05/95 ===== - -- Added extra test to break read-id loop with signal. -- Changed rewind code to handle negative overshoot for drives - that take very long to start or stop. -- Let use of get/set i/o-regions depend on kernel version. -- Changed code to use a more general test for conditional - compilations depending on kernel version. -- Improved micro-step functionality to go off-track only - while reading (id & data). -- Added failure on tape-not-referenced bit in ftape_command. -- Added FOREVER option to read-wait routine. -- Changed read-id to use shorter timeout causing smaller - rewinds on timeout. -- Made kernel-interface functions static. - - -===== Release notes for ftape-2.02f, 03/05/95 ===== - -- Added support for dual tape drives on my system, extended Configure - script to detect host 'dodo'. -- Log media defect in history if ecc failed and no data was returned. -- Fixed Configure script that was failing for kernel versions with - double digit version or revision numbers. - - -===== Release notes for ftape-2.02e, 01/05/95 ===== - -- Fixed reposition loop at logical eot (failing read_id). -- Fixed 34 segment offset when rewinding. -- Added fast seek capability for more than 255 segments. -- Fixed wrong busy result from ftape_command causing reverse - seek to fail. -- Added breakout from infinite rewind loop (if something fails). - - -===== Release notes for ftape-2.02d, 30/04/95 ===== - -- Improved abortion on signals: Interrupt will make a graceful - exit, Kill will be less nice and should be used if everything - else fails. -- Included check for tape-head off track. -- Implemented exit from tape-start loop. -- Added kernel io-port registration. -- Implemented skip of failing segment (ENODATA) on ecc failure. - This allows afio and tar to continue when the tape is damaged. -- Made distinction between drive names with different codes. - - -===== Release notes for ftape-2.02c, 22/04/95 ===== - -- Fixed too tight command queueing after tape stop/pause command - issued from within interrupt service routine (Showed as timeout - on Acknowledge errors during retries on some systems) -- Tried to fix timeouts when using 425 ft tape because the extended - length doesn't seem to be detected by the hardware. - We now use the format code from the header segment so adjust the - timing after reading the header segment. -- Fixed some messages stating 'unexpected something...' being not - unexpected anymore. -- Started preparations for merge of dynamic buffer allocation and - compression code. -- Changed some debug messages to include relevant segment information - at level 4. -- Included early bail-out when drive offline, preventing a lot of - false messages. -- Moved ftape_parameter_xxx() offsets into function instead of in calls. -- Removed 'weird, drive busy but no data' error when caused by - an error during a read-id. -- Improved 'timeout on acknowledge' diagnostics. -- Moved MODULE option into Configure. -- Reduced code size when no tracing at all was set (Claus Heine). -- No longer log error code 0 (no error) as an error. - - -===== Release notes for ftape-2.02b, 09/04/95 ===== - -- Relaxed timing for status operation and displaying - abnormal results. Hopefully this shows what's going - wrong with the Conner TSM850R drives. -- Created script for configuration, using version number - of kernel source if available, otherwise /proc/version. -- Fixed conditionals in kernel-interface.c. -- Removed unavoidable TRACE output. - - -===== Release notes for ftape-2.02a, 01/04/95 ===== - -- Implemented `new-style' (versioned) modules support for new - kernels. -- Reduced size of module by moving static data to bss. -- Now using version number of kernel source instead of running - kernel for kernel versions >= 1.1.82 -- Added feedback on drive speeds to vendor information. -- Included fixed insmod sources to distribution (Let's hope - the modules distribution get fixed soon :-/). - -Note that I haven't yet implemented any of the code extension I -received. I hope to find some time to do this soon. - - -===== Release notes for ftape-2.02, 15/01/95 ===== - - -- Fixed failing repositioning when overshoot was incremented. -- Fixed rate selection: Because of a deficiency in the QIC-117 - specification one cannot distinguish between a not implemented - and a failing command. Therefor we now try to find out if the - drive does support this command before usage. -- Fixed error retry using wrong offset in fdc-isr. -- Improved retry code to retry only once on a single no-data - error in a segment. -- Validate sector number extracted from eof mark because an - invalid file mark (due to ???) could cause kernel panic. -- Split ftape-io.c into ftape-io.c and ftape-ctl.c files. -- Corrected too high media error count after writing to - a bad tape. -- Added #include again because old kernel versions - need it. -- Fixed fdc not being disabled when open failed because no tape - drive was found. -- Fixed problem with soft error in sector 32 (shift operator with - shiftcount 32 is not defined). - - -===== Release notes for ftape-2.01, 08/01/95 ===== - - -- Removed TESTING setting from distributed Makefile. -- Fixed `mt asf' failure: Rewind was deferred to close which - overruled the fsf ioctl. -- Prevented non-interruptible commands being interrupted. -- Added missing timeout.pause setting. -- Maximum tape speed read from drive type information table. - If the information is not in the table (0) the drive will - determine the speed itself and put a message in the logfile. - This information should then be added to the table in the - vendors.h file (and reported to me). -- Added call to ftape_init_drive after soft reset for those - (antique) drives that don't do an implicit seek_load_point - after a reset or power up. -- Don't try to set data rate if reset failed. -- Prevent update of seek variables when starting from the - beginning or the end of the tape. -- Fixed wrong adjustment of overshoot in seek_forward(). -- Added sync to Makefile (again). -- Added code to diagnose timer problems (calibr.c). -- Replaced time differences by timediff calls. -- Removed reference to do_floppy from object for recent kernels. -- Fixed wrong display of 'failing dma controller' message. -- Removed various no longer used #include statements. -- Added max. tape speed value to vendor-struct. -- Changed ftape-command to check pre-conditions and wait - if needed. -- Further updated qic117.h to rev G. -- Combined command name table and restrictions table to one. - Extended this table with some new fields. -- Increased timeout on Ack timer value and included code to - report out of spec behaviour. -- Increased rewind timeout margin to calculated + 20%. -- Improved data rate selection so it won't fail on some - older (pre standard) drives. -- Changed initialisation code so drive will be rewound if the - driver is reloaded and the tape is not at bot. -- Moved some of the flush operations from close to the ioctls. -- Added exit code value to failing verify area message. -- Loop until tape halted in smart-stop. -- Fast seek handled specially if located at bot or eot. -- Being more conservative on overshoot value. - - -===== Release notes for ftape-2.00, 31/12/94 ===== - - The Install-guide is completely rewritten and now also includes -some information on how to use the driver. If you're either new -to ftape or new to Unix tape devices make sure to read it ! - - If you own a pci system and experience problems with the -ftape driver make sure to read the README.PCI file. It contains -some hints on how to fix your hardware. - - For anybody who hasn't noticed: The version number of the -driver has been incremented (The latest released version has -been version 1.14d). - This has been done for two major reasons: - - o A new (better) error recovery scheme is implemented. - o Support for new drive types has been added. - - All these improvements/changes will probably include a couple -of new (and old?) bugs. If you encounter any problems that you think -I'm not yet aware of, feel free to send a report to . - I recommend keeping a version of ftape-1.14d available, just -in case ;-) - - This version should work with all kernel versions from 1.0.9 up -to 1.1.72 (and probably earlier and later versions too). - - -Major new features: - -- Better handling of tapes with defects: When a sector repeatedly - (SOFT_RETRIES in ftape.h) cannot be written to or read from it is - marked as an hard error and gets skipped. - The error correction code can handle up to three of these hard - errors provided there are no other errors in that segment (32 Kb). - -- Allows writing to tapes with defects (although the risk of loosing - data increases !) - Look for the media-defects entry printed with the statistics when - the tape is closed. A non-zero value here shows a bad tape. - [the actual count is wrong (too high), this is a known bug]. - -- Use of backup header segment if first one is failing. - -- Support for extended length tapes with QIC-80: both 425 and 1100 ft. - 0.25 inch tapes are now recognized and handled. - -- Support for new QIC-80 drives with 8 mm `wide' tapes (e.g. Conner - TSM 420). - -- Support for new QIC-3010 and QIC-3020 drives (experimental) with - both 0.25 inch and 8 mm tapes. - -Some minor features were added, a couple of small bugs were fixed and -probably some new ones introduced ;-). - -[lseek() didn't make it into this version] - -Have fun, - -Bas. ----- - LocalWords: ftape MCONFIG mt VFS zftape resp sftape proc subdir MTIOCVOLINFO - LocalWords: MTIOCGETSIZE BOT EOD MTBSF zft kerneld modprobe kdtime contrib TR - LocalWords: MTSETBLK afio uninstall texi www EIO QIC init sft eof aka dma GB - LocalWords: SIGKILL MTIOCFTCMD mmap Iomega FDC fdc io gnumt mtio fc asm inb - LocalWords: outb ft qic frontend TeXinfo irq mach MODVERSIONS CONFIG html dvi - LocalWords: usr doc SMP Mb Dunno FIXME vtblc perl listtape volinfo fsf MTWEOF - LocalWords: amanda degaussed ComByte DoublePlay whraven njackn com MTIOC vtbl - LocalWords: GETBLKSZ MAKEDEV zftape's linux dif CVS Revison cp MTREW MTOFFL - LocalWords: MTFSF BSF Marcin Dalecki GCC Config cpio swapout Kai Harrekilde - LocalWords: Pederson khp dolphinics Justus claus momo rwth aachen Laarhoven diff --git a/drivers/char/ftape/compressor/Makefile b/drivers/char/ftape/compressor/Makefile deleted file mode 100644 index 1fbd6c4019d..00000000000 --- a/drivers/char/ftape/compressor/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright (C) 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/compressor/Makefile,v $ -# $Revision: 1.1 $ -# $Date: 1997/10/05 19:12:28 $ -# -# Makefile for the optional compressor for th zftape VFS -# interface to the QIC-40/80/3010/3020 floppy-tape driver for -# Linux. -# - -obj-$(CONFIG_ZFT_COMPRESSOR) += zft-compressor.o - -zft-compressor-objs := zftape-compress.o lzrw3.o - -CFLAGS_lzrw3.o := -O6 -funroll-all-loops diff --git a/drivers/char/ftape/compressor/lzrw3.c b/drivers/char/ftape/compressor/lzrw3.c deleted file mode 100644 index a032a0ee2a9..00000000000 --- a/drivers/char/ftape/compressor/lzrw3.c +++ /dev/null @@ -1,743 +0,0 @@ -/* - * $Source: /homes/cvs/ftape-stacked/ftape/compressor/lzrw3.c,v $ - * $Revision: 1.1 $ - * $Date: 1997/10/05 19:12:29 $ - * - * Implementation of Ross Williams lzrw3 algorithm. Adaption for zftape. - * - */ - -#include "../compressor/lzrw3.h" /* Defines single exported function "compress". */ - -/******************************************************************************/ -/* */ -/* LZRW3.C */ -/* */ -/******************************************************************************/ -/* */ -/* Author : Ross Williams. */ -/* Date : 30-Jun-1991. */ -/* Release : 1. */ -/* */ -/******************************************************************************/ -/* */ -/* This file contains an implementation of the LZRW3 data compression */ -/* algorithm in C. */ -/* */ -/* The algorithm is a general purpose compression algorithm that runs fast */ -/* and gives reasonable compression. The algorithm is a member of the Lempel */ -/* Ziv family of algorithms and bases its compression on the presence in the */ -/* data of repeated substrings. */ -/* */ -/* This algorithm is unpatented and the code is public domain. As the */ -/* algorithm is based on the LZ77 class of algorithms, it is unlikely to be */ -/* the subject of a patent challenge. */ -/* */ -/* Unlike the LZRW1 and LZRW1-A algorithms, the LZRW3 algorithm is */ -/* deterministic and is guaranteed to yield the same compressed */ -/* representation for a given file each time it is run. */ -/* */ -/* The LZRW3 algorithm was originally designed and implemented */ -/* by Ross Williams on 31-Dec-1990. */ -/* */ -/* Here are the results of applying this code, compiled under THINK C 4.0 */ -/* and running on a Mac-SE (8MHz 68000), to the standard calgary corpus. */ -/* */ -/* +----------------------------------------------------------------+ */ -/* | DATA COMPRESSION TEST | */ -/* | ===================== | */ -/* | Time of run : Sun 30-Jun-1991 09:31PM | */ -/* | Timing accuracy : One part in 100 | */ -/* | Context length : 262144 bytes (= 256.0000K) | */ -/* | Test suite : Calgary Corpus Suite | */ -/* | Files in suite : 14 | */ -/* | Algorithm : LZRW3 | */ -/* | Note: All averages are calculated from the un-rounded values. | */ -/* +----------------------------------------------------------------+ */ -/* | File Name Length CxB ComLen %Remn Bits Com K/s Dec K/s | */ -/* | ---------- ------ --- ------ ----- ---- ------- ------- | */ -/* | rpus:Bib.D 111261 1 55033 49.5 3.96 19.46 32.27 | */ -/* | us:Book1.D 768771 3 467962 60.9 4.87 17.03 31.07 | */ -/* | us:Book2.D 610856 3 317102 51.9 4.15 19.39 34.15 | */ -/* | rpus:Geo.D 102400 1 82424 80.5 6.44 11.65 18.18 | */ -/* | pus:News.D 377109 2 205670 54.5 4.36 17.14 27.47 | */ -/* | pus:Obj1.D 21504 1 13027 60.6 4.85 13.40 18.95 | */ -/* | pus:Obj2.D 246814 1 116286 47.1 3.77 19.31 30.10 | */ -/* | s:Paper1.D 53161 1 27522 51.8 4.14 18.60 31.15 | */ -/* | s:Paper2.D 82199 1 45160 54.9 4.40 18.45 32.84 | */ -/* | rpus:Pic.D 513216 2 122388 23.8 1.91 35.29 51.05 | */ -/* | us:Progc.D 39611 1 19669 49.7 3.97 18.87 30.64 | */ -/* | us:Progl.D 71646 1 28247 39.4 3.15 24.34 40.66 | */ -/* | us:Progp.D 49379 1 19377 39.2 3.14 23.91 39.23 | */ -/* | us:Trans.D 93695 1 33481 35.7 2.86 25.48 40.37 | */ -/* +----------------------------------------------------------------+ */ -/* | Average 224401 1 110953 50.0 4.00 20.17 32.72 | */ -/* +----------------------------------------------------------------+ */ -/* */ -/******************************************************************************/ - -/******************************************************************************/ - -/* The following structure is returned by the "compress" function below when */ -/* the user asks the function to return identifying information. */ -/* The most important field in the record is the working memory field which */ -/* tells the calling program how much working memory should be passed to */ -/* "compress" when it is called to perform a compression or decompression. */ -/* LZRW3 uses the same amount of memory during compression and decompression. */ -/* For more information on this structure see "compress.h". */ - -#define U(X) ((ULONG) X) -#define SIZE_P_BYTE (U(sizeof(UBYTE *))) -#define SIZE_WORD (U(sizeof(UWORD ))) -#define ALIGNMENT_FUDGE (U(16)) -#define MEM_REQ ( U(4096)*(SIZE_P_BYTE) + ALIGNMENT_FUDGE ) - -static struct compress_identity identity = -{ - U(0x032DDEA8), /* Algorithm identification number. */ - MEM_REQ, /* Working memory (bytes) required. */ - "LZRW3", /* Name of algorithm. */ - "1.0", /* Version number of algorithm. */ - "31-Dec-1990", /* Date of algorithm. */ - "Public Domain", /* Copyright notice. */ - "Ross N. Williams", /* Author of algorithm. */ - "Renaissance Software", /* Affiliation of author. */ - "Public Domain" /* Vendor of algorithm. */ -}; - -LOCAL void compress_compress (UBYTE *,UBYTE *,ULONG,UBYTE *, LONG *); -LOCAL void compress_decompress(UBYTE *,UBYTE *,LONG, UBYTE *, ULONG *); - -/******************************************************************************/ - -/* This function is the only function exported by this module. */ -/* Depending on its first parameter, the function can be requested to */ -/* compress a block of memory, decompress a block of memory, or to identify */ -/* itself. For more information, see the specification file "compress.h". */ - -EXPORT void lzrw3_compress( - UWORD action, /* Action to be performed. */ - UBYTE *wrk_mem, /* Address of working memory we can use.*/ - UBYTE *src_adr, /* Address of input data. */ - LONG src_len, /* Length of input data. */ - UBYTE *dst_adr, /* Address to put output data. */ - void *p_dst_len /* Address of longword for length of output data.*/ -) -{ - switch (action) - { - case COMPRESS_ACTION_IDENTITY: - *((struct compress_identity **)p_dst_len)= &identity; - break; - case COMPRESS_ACTION_COMPRESS: - compress_compress(wrk_mem,src_adr,src_len,dst_adr,(LONG *)p_dst_len); - break; - case COMPRESS_ACTION_DECOMPRESS: - compress_decompress(wrk_mem,src_adr,src_len,dst_adr,(LONG *)p_dst_len); - break; - } -} - -/******************************************************************************/ -/* */ -/* BRIEF DESCRIPTION OF THE LZRW3 ALGORITHM */ -/* ======================================== */ -/* The LZRW3 algorithm is identical to the LZRW1-A algorithm except that */ -/* instead of transmitting history offsets, it transmits hash table indexes. */ -/* In order to decode the indexes, the decompressor must maintain an */ -/* identical hash table. Copy items are straightforward:when the decompressor */ -/* receives a copy item, it simply looks up the hash table to translate the */ -/* index into a pointer into the data already decompressed. To update the */ -/* hash table, it replaces the same table entry with a pointer to the start */ -/* of the newly decoded phrase. The tricky part is with literal items, for at */ -/* the time that the decompressor receives a literal item the decompressor */ -/* does not have the three bytes in the Ziv (that the compressor has) to */ -/* perform the three-byte hash. To solve this problem, in LZRW3, both the */ -/* compressor and decompressor are wired up so that they "buffer" these */ -/* literals and update their hash tables only when three bytes are available. */ -/* This makes the maximum buffering 2 bytes. */ -/* */ -/* Replacement of offsets by hash table indexes yields a few percent extra */ -/* compression at the cost of some speed. LZRW3 is slower than LZRW1, LZRW1-A */ -/* and LZRW2, but yields better compression. */ -/* */ -/* Extra compression could be obtained by using a hash table of depth two. */ -/* However, increasing the depth above one incurs a significant decrease in */ -/* compression speed which was not considered worthwhile. Another reason for */ -/* keeping the depth down to one was to allow easy comparison with the */ -/* LZRW1-A and LZRW2 algorithms so as to demonstrate the exact effect of the */ -/* use of direct hash indexes. */ -/* */ -/* +---+ */ -/* |___|4095 */ -/* |___| */ -/* +---------------------*_|<---+ /----+---\ */ -/* | |___| +---|Hash | */ -/* | |___| |Function| */ -/* | |___| \--------/ */ -/* | |___|0 ^ */ -/* | +---+ | */ -/* | Hash +-----+ */ -/* | Table | */ -/* | --- */ -/* v ^^^ */ -/* +-------------------------------------|----------------+ */ -/* |||||||||||||||||||||||||||||||||||||||||||||||||||||||| */ -/* +-------------------------------------|----------------+ */ -/* | |1......18| | */ -/* |<------- Lempel=History ------------>|<--Ziv-->| | */ -/* | (=bytes already processed) |<-Still to go-->| */ -/* |<-------------------- INPUT BLOCK ------------------->| */ -/* */ -/* The diagram above for LZRW3 looks almost identical to the diagram for */ -/* LZRW1. The difference is that in LZRW3, the compressor transmits hash */ -/* table indices instead of Lempel offsets. For this to work, the */ -/* decompressor must maintain a hash table as well as the compressor and both */ -/* compressor and decompressor must "buffer" literals, as the decompressor */ -/* cannot hash phrases commencing with a literal until another two bytes have */ -/* arrived. */ -/* */ -/* LZRW3 Algorithm Execution Summary */ -/* --------------------------------- */ -/* 1. Hash the first three bytes of the Ziv to yield a hash table index h. */ -/* 2. Look up the hash table yielding history pointer p. */ -/* 3. Match where p points with the Ziv. If there is a match of three or */ -/* more bytes, code those bytes (in the Ziv) as a copy item, otherwise */ -/* code the next byte in the Ziv as a literal item. */ -/* 4. Update the hash table as possible subject to the constraint that only */ -/* phrases commencing three bytes back from the Ziv can be hashed and */ -/* entered into the hash table. (This enables the decompressor to keep */ -/* pace). See the description and code for more details. */ -/* */ -/******************************************************************************/ -/* */ -/* DEFINITION OF COMPRESSED FILE FORMAT */ -/* ==================================== */ -/* * A compressed file consists of a COPY FLAG followed by a REMAINDER. */ -/* * The copy flag CF uses up four bytes with the first byte being the */ -/* least significant. */ -/* * If CF=1, then the compressed file represents the remainder of the file */ -/* exactly. Otherwise CF=0 and the remainder of the file consists of zero */ -/* or more GROUPS, each of which represents one or more bytes. */ -/* * Each group consists of two bytes of CONTROL information followed by */ -/* sixteen ITEMs except for the last group which can contain from one */ -/* to sixteen items. */ -/* * An item can be either a LITERAL item or a COPY item. */ -/* * Each item corresponds to a bit in the control bytes. */ -/* * The first control byte corresponds to the first 8 items in the group */ -/* with bit 0 corresponding to the first item in the group and bit 7 to */ -/* the eighth item in the group. */ -/* * The second control byte corresponds to the second 8 items in the group */ -/* with bit 0 corresponding to the ninth item in the group and bit 7 to */ -/* the sixteenth item in the group. */ -/* * A zero bit in a control word means that the corresponding item is a */ -/* literal item. A one bit corresponds to a copy item. */ -/* * A literal item consists of a single byte which represents itself. */ -/* * A copy item consists of two bytes that represent from 3 to 18 bytes. */ -/* * The first byte in a copy item will be denoted C1. */ -/* * The second byte in a copy item will be denoted C2. */ -/* * Bits will be selected using square brackets. */ -/* For example: C1[0..3] is the low nibble of the first control byte. */ -/* of copy item C1. */ -/* * The LENGTH of a copy item is defined to be C1[0..3]+3 which is a number */ -/* in the range [3,18]. */ -/* * The INDEX of a copy item is defined to be C1[4..7]*256+C2[0..8] which */ -/* is a number in the range [0,4095]. */ -/* * A copy item represents the sequence of bytes */ -/* text[POS-OFFSET..POS-OFFSET+LENGTH-1] where */ -/* text is the entire text of the uncompressed string. */ -/* POS is the index in the text of the character following the */ -/* string represented by all the items preceeding the item */ -/* being defined. */ -/* OFFSET is obtained from INDEX by looking up the hash table. */ -/* */ -/******************************************************************************/ - -/* The following #define defines the length of the copy flag that appears at */ -/* the start of the compressed file. The value of four bytes was chosen */ -/* because the fast_copy routine on my Macintosh runs faster if the source */ -/* and destination blocks are relatively longword aligned. */ -/* The actual flag data appears in the first byte. The rest are zeroed so as */ -/* to normalize the compressed representation (i.e. not non-deterministic). */ -#define FLAG_BYTES 4 - -/* The following #defines define the meaning of the values of the copy */ -/* flag at the start of the compressed file. */ -#define FLAG_COMPRESS 0 /* Signals that output was result of compression. */ -#define FLAG_COPY 1 /* Signals that output was simply copied over. */ - -/* The 68000 microprocessor (on which this algorithm was originally developed */ -/* is fussy about non-aligned arrays of words. To avoid these problems the */ -/* following macro can be used to "waste" from 0 to 3 bytes so as to align */ -/* the argument pointer. */ -#define ULONG_ALIGN_UP(X) ((((ULONG)X)+sizeof(ULONG)-1)&~(sizeof(ULONG)-1)) - - -/* The following constant defines the maximum length of an uncompressed item. */ -/* This definition must not be changed; its value is hardwired into the code. */ -/* The longest number of bytes that can be spanned by a single item is 18 */ -/* for the longest copy item. */ -#define MAX_RAW_ITEM (18) - -/* The following constant defines the maximum length of an uncompressed group.*/ -/* This definition must not be changed; its value is hardwired into the code. */ -/* A group contains at most 16 items which explains this definition. */ -#define MAX_RAW_GROUP (16*MAX_RAW_ITEM) - -/* The following constant defines the maximum length of a compressed group. */ -/* This definition must not be changed; its value is hardwired into the code. */ -/* A compressed group consists of two control bytes followed by up to 16 */ -/* compressed items each of which can have a maximum length of two bytes. */ -#define MAX_CMP_GROUP (2+16*2) - -/* The following constant defines the number of entries in the hash table. */ -/* This definition must not be changed; its value is hardwired into the code. */ -#define HASH_TABLE_LENGTH (4096) - -/* LZRW3, unlike LZRW1(-A), must initialize its hash table so as to enable */ -/* the compressor and decompressor to stay in step maintaining identical hash */ -/* tables. In an early version of the algorithm, the tables were simply */ -/* initialized to zero and a check for zero was included just before the */ -/* matching code. However, this test costs time. A better solution is to */ -/* initialize all the entries in the hash table to point to a constant */ -/* string. The decompressor does the same. This solution requires no extra */ -/* test. The contents of the string do not matter so long as the string is */ -/* the same for the compressor and decompressor and contains at least */ -/* MAX_RAW_ITEM bytes. I chose consecutive decimal digits because they do not */ -/* have white space problems (e.g. there is no chance that the compiler will */ -/* replace more than one space by a TAB) and because they make the length of */ -/* the string obvious by inspection. */ -#define START_STRING_18 ((UBYTE *) "123456789012345678") - -/* In this algorithm, hash values have to be calculated at more than one */ -/* point. The following macro neatens the code up for this. */ -#define HASH(PTR) \ - (((40543*(((*(PTR))<<8)^((*((PTR)+1))<<4)^(*((PTR)+2))))>>4) & 0xFFF) - -/******************************************************************************/ - -/* Input : Hand over the required amount of working memory in p_wrk_mem. */ -/* Input : Specify input block using p_src_first and src_len. */ -/* Input : Point p_dst_first to the start of the output zone (OZ). */ -/* Input : Point p_dst_len to a ULONG to receive the output length. */ -/* Input : Input block and output zone must not overlap. */ -/* Output : Length of output block written to *p_dst_len. */ -/* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. May */ -/* Output : write in OZ=Mem[p_dst_first..p_dst_first+src_len+MAX_CMP_GROUP-1].*/ -/* Output : Upon completion guaranteed *p_dst_len<=src_len+FLAG_BYTES. */ -LOCAL void compress_compress(UBYTE *p_wrk_mem, - UBYTE *p_src_first, ULONG src_len, - UBYTE *p_dst_first, LONG *p_dst_len) -{ - /* p_src and p_dst step through the source and destination blocks. */ - register UBYTE *p_src = p_src_first; - register UBYTE *p_dst = p_dst_first; - - /* The following variables are never modified and are used in the */ - /* calculations that determine when the main loop terminates. */ - UBYTE *p_src_post = p_src_first+src_len; - UBYTE *p_dst_post = p_dst_first+src_len; - UBYTE *p_src_max1 = p_src_first+src_len-MAX_RAW_ITEM; - UBYTE *p_src_max16 = p_src_first+src_len-MAX_RAW_ITEM*16; - - /* The variables 'p_control' and 'control' are used to buffer control bits. */ - /* Before each group is processed, the next two bytes of the output block */ - /* are set aside for the control word for the group about to be processed. */ - /* 'p_control' is set to point to the first byte of that word. Meanwhile, */ - /* 'control' buffers the control bits being generated during the processing */ - /* of the group. Instead of having a counter to keep track of how many items */ - /* have been processed (=the number of bits in the control word), at the */ - /* start of each group, the top word of 'control' is filled with 1 bits. */ - /* As 'control' is shifted for each item, the 1 bits in the top word are */ - /* absorbed or destroyed. When they all run out (i.e. when the top word is */ - /* all zero bits, we know that we are at the end of a group. */ -# define TOPWORD 0xFFFF0000 - UBYTE *p_control; - register ULONG control=TOPWORD; - - /* THe variable 'hash' always points to the first element of the hash table. */ - UBYTE **hash= (UBYTE **) ULONG_ALIGN_UP(p_wrk_mem); - - /* The following two variables represent the literal buffer. p_h1 points to */ - /* the hash table entry corresponding to the youngest literal. p_h2 points */ - /* to the hash table entry corresponding to the second youngest literal. */ - /* Note: p_h1=0=>p_h2=0 because zero values denote absence of a pending */ - /* literal. The variables are initialized to zero meaning an empty "buffer". */ - UBYTE **p_h1=NULL; - UBYTE **p_h2=NULL; - - /* To start, we write the flag bytes. Being optimistic, we set the flag to */ - /* FLAG_COMPRESS. The remaining flag bytes are zeroed so as to keep the */ - /* algorithm deterministic. */ - *p_dst++=FLAG_COMPRESS; - {UWORD i; for (i=2;i<=FLAG_BYTES;i++) *p_dst++=0;} - - /* Reserve the first word of output as the control word for the first group. */ - /* Note: This is undone at the end if the input block is empty. */ - p_control=p_dst; p_dst+=2; - - /* Initialize all elements of the hash table to point to a constant string. */ - /* Use of an unrolled loop speeds this up considerably. */ - {UWORD i; UBYTE **p_h=hash; -# define ZH *p_h++=START_STRING_18 - for (i=0;i<256;i++) /* 256=HASH_TABLE_LENGTH/16. */ - {ZH;ZH;ZH;ZH; - ZH;ZH;ZH;ZH; - ZH;ZH;ZH;ZH; - ZH;ZH;ZH;ZH;} - } - - /* The main loop processes either 1 or 16 items per iteration. As its */ - /* termination logic is complicated, I have opted for an infinite loop */ - /* structure containing 'break' and 'goto' statements. */ - while (TRUE) - {/* Begin main processing loop. */ - - /* Note: All the variables here except unroll should be defined within */ - /* the inner loop. Unfortunately the loop hasn't got a block. */ - register UBYTE *p; /* Scans through targ phrase during matching. */ - register UBYTE *p_ziv= NULL ; /* Points to first byte of current Ziv. */ - register UWORD unroll; /* Loop counter for unrolled inner loop. */ - register UWORD index; /* Index of current hash table entry. */ - register UBYTE **p_h0 = NULL ; /* Pointer to current hash table entry. */ - - /* Test for overrun and jump to overrun code if necessary. */ - if (p_dst>p_dst_post) - goto overrun; - - /* The following cascade of if statements efficiently catches and deals */ - /* with varying degrees of closeness to the end of the input block. */ - /* When we get very close to the end, we stop updating the table and */ - /* code the remaining bytes as literals. This makes the code simpler. */ - unroll=16; - if (p_src>p_src_max16) - { - unroll=1; - if (p_src>p_src_max1) - { - if (p_src==p_src_post) - break; - else - goto literal; - } - } - - /* This inner unrolled loop processes 'unroll' (whose value is either 1 */ - /* or 16) items. I have chosen to implement this loop with labels and */ - /* gotos to heighten the ease with which the loop may be implemented with */ - /* a single decrement and branch instruction in assembly language and */ - /* also because the labels act as highly readable place markers. */ - /* (Also because we jump into the loop for endgame literals (see above)). */ - - begin_unrolled_loop: - - /* To process the next phrase, we hash the next three bytes and use */ - /* the resultant hash table index to look up the hash table. A pointer */ - /* to the entry is stored in p_h0 so as to avoid an array lookup. The */ - /* hash table entry *p_h0 is looked up yielding a pointer p to a */ - /* potential match of the Ziv in the history. */ - index=HASH(p_src); - p_h0=&hash[index]; - p=*p_h0; - - /* Having looked up the candidate position, we are in a position to */ - /* attempt a match. The match loop has been unrolled using the PS */ - /* macro so that failure within the first three bytes automatically */ - /* results in the literal branch being taken. The coding is simple. */ - /* p_ziv saves p_src so we can let p_src wander. */ -# define PS *p++!=*p_src++ - p_ziv=p_src; - if (PS || PS || PS) - { - /* Literal. */ - - /* Code the literal byte as itself and a zero control bit. */ - p_src=p_ziv; literal: *p_dst++=*p_src++; control&=0xFFFEFFFF; - - /* We have just coded a literal. If we had two pending ones, that */ - /* makes three and we can update the hash table. */ - if (p_h2!=0) - {*p_h2=p_ziv-2;} - - /* In any case, rotate the hash table pointers for next time. */ - p_h2=p_h1; p_h1=p_h0; - - } - else - { - /* Copy */ - - /* Match up to 15 remaining bytes using an unrolled loop and code. */ -#if 0 - PS || PS || PS || PS || PS || PS || PS || PS || - PS || PS || PS || PS || PS || PS || PS || p_src++; -#else - if ( - !( PS || PS || PS || PS || PS || PS || PS || PS || - PS || PS || PS || PS || PS || PS || PS ) - ) p_src++; -#endif - *p_dst++=((index&0xF00)>>4)|(--p_src-p_ziv-3); - *p_dst++=index&0xFF; - - /* As we have just coded three bytes, we are now in a position to */ - /* update the hash table with the literal bytes that were pending */ - /* upon the arrival of extra context bytes. */ - if (p_h1!=0) - { - if (p_h2) - {*p_h2=p_ziv-2; p_h2=NULL;} - *p_h1=p_ziv-1; p_h1=NULL; - } - - /* In any case, we can update the hash table based on the current */ - /* position as we just coded at least three bytes in a copy items. */ - *p_h0=p_ziv; - - } - control>>=1; - - /* This loop is all set up for a decrement and jump instruction! */ -#ifndef linux -` end_unrolled_loop: if (--unroll) goto begin_unrolled_loop; -#else - /* end_unrolled_loop: */ if (--unroll) goto begin_unrolled_loop; -#endif - - /* At this point it will nearly always be the end of a group in which */ - /* case, we have to do some control-word processing. However, near the */ - /* end of the input block, the inner unrolled loop is only executed once. */ - /* This necessitates the 'if' test. */ - if ((control&TOPWORD)==0) - { - /* Write the control word to the place we saved for it in the output. */ - *p_control++= control &0xFF; - *p_control = (control>>8) &0xFF; - - /* Reserve the next word in the output block for the control word */ - /* for the group about to be processed. */ - p_control=p_dst; p_dst+=2; - - /* Reset the control bits buffer. */ - control=TOPWORD; - } - - } /* End main processing loop. */ - - /* After the main processing loop has executed, all the input bytes have */ - /* been processed. However, the control word has still to be written to the */ - /* word reserved for it in the output at the start of the most recent group. */ - /* Before writing, the control word has to be shifted so that all the bits */ - /* are in the right place. The "empty" bit positions are filled with 1s */ - /* which partially fill the top word. */ - while(control&TOPWORD) control>>=1; - *p_control++= control &0xFF; - *p_control++=(control>>8) &0xFF; - - /* If the last group contained no items, delete the control word too. */ - if (p_control==p_dst) p_dst-=2; - - /* Write the length of the output block to the dst_len parameter and return. */ - *p_dst_len=p_dst-p_dst_first; - return; - - /* Jump here as soon as an overrun is detected. An overrun is defined to */ - /* have occurred if p_dst>p_dst_first+src_len. That is, the moment the */ - /* length of the output written so far exceeds the length of the input block.*/ - /* The algorithm checks for overruns at least at the end of each group */ - /* which means that the maximum overrun is MAX_CMP_GROUP bytes. */ - /* Once an overrun occurs, the only thing to do is to set the copy flag and */ - /* copy the input over. */ - overrun: -#if 0 - *p_dst_first=FLAG_COPY; - fast_copy(p_src_first,p_dst_first+FLAG_BYTES,src_len); - *p_dst_len=src_len+FLAG_BYTES; -#else - fast_copy(p_src_first,p_dst_first,src_len); - *p_dst_len= -src_len; /* return a negative number to indicate uncompressed data */ -#endif -} - -/******************************************************************************/ - -/* Input : Hand over the required amount of working memory in p_wrk_mem. */ -/* Input : Specify input block using p_src_first and src_len. */ -/* Input : Point p_dst_first to the start of the output zone. */ -/* Input : Point p_dst_len to a ULONG to receive the output length. */ -/* Input : Input block and output zone must not overlap. User knows */ -/* Input : upperbound on output block length from earlier compression. */ -/* Input : In any case, maximum expansion possible is nine times. */ -/* Output : Length of output block written to *p_dst_len. */ -/* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */ -/* Output : Writes only in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */ -LOCAL void compress_decompress( UBYTE *p_wrk_mem, - UBYTE *p_src_first, LONG src_len, - UBYTE *p_dst_first, ULONG *p_dst_len) -{ - /* Byte pointers p_src and p_dst scan through the input and output blocks. */ - register UBYTE *p_src = p_src_first+FLAG_BYTES; - register UBYTE *p_dst = p_dst_first; - /* we need to avoid a SEGV when trying to uncompress corrupt data */ - register UBYTE *p_dst_post = p_dst_first + *p_dst_len; - - /* The following two variables are never modified and are used to control */ - /* the main loop. */ - UBYTE *p_src_post = p_src_first+src_len; - UBYTE *p_src_max16 = p_src_first+src_len-(MAX_CMP_GROUP-2); - - /* The hash table is the only resident of the working memory. The hash table */ - /* contains HASH_TABLE_LENGTH=4096 pointers to positions in the history. To */ - /* keep Macintoshes happy, it is longword aligned. */ - UBYTE **hash = (UBYTE **) ULONG_ALIGN_UP(p_wrk_mem); - - /* The variable 'control' is used to buffer the control bits which appear in */ - /* groups of 16 bits (control words) at the start of each compressed group. */ - /* When each group is read, bit 16 of the register is set to one. Whenever */ - /* a new bit is needed, the register is shifted right. When the value of the */ - /* register becomes 1, we know that we have reached the end of a group. */ - /* Initializing the register to 1 thus instructs the code to follow that it */ - /* should read a new control word immediately. */ - register ULONG control=1; - - /* The value of 'literals' is always in the range 0..3. It is the number of */ - /* consecutive literal items just seen. We have to record this number so as */ - /* to know when to update the hash table. When literals gets to 3, there */ - /* have been three consecutive literals and we can update at the position of */ - /* the oldest of the three. */ - register UWORD literals=0; - - /* Check the leading copy flag to see if the compressor chose to use a copy */ - /* operation instead of a compression operation. If a copy operation was */ - /* used, then all we need to do is copy the data over, set the output length */ - /* and return. */ -#if 0 - if (*p_src_first==FLAG_COPY) - { - fast_copy(p_src_first+FLAG_BYTES,p_dst_first,src_len-FLAG_BYTES); - *p_dst_len=src_len-FLAG_BYTES; - return; - } -#else - if ( src_len < 0 ) - { - fast_copy(p_src_first,p_dst_first,-src_len ); - *p_dst_len = (ULONG)-src_len; - return; - } -#endif - - /* Initialize all elements of the hash table to point to a constant string. */ - /* Use of an unrolled loop speeds this up considerably. */ - {UWORD i; UBYTE **p_h=hash; -# define ZJ *p_h++=START_STRING_18 - for (i=0;i<256;i++) /* 256=HASH_TABLE_LENGTH/16. */ - {ZJ;ZJ;ZJ;ZJ; - ZJ;ZJ;ZJ;ZJ; - ZJ;ZJ;ZJ;ZJ; - ZJ;ZJ;ZJ;ZJ;} - } - - /* The outer loop processes either 1 or 16 items per iteration depending on */ - /* how close p_src is to the end of the input block. */ - while (p_src!=p_src_post) - {/* Start of outer loop */ - - register UWORD unroll; /* Counts unrolled loop executions. */ - - /* When 'control' has the value 1, it means that the 16 buffered control */ - /* bits that were read in at the start of the current group have all been */ - /* shifted out and that all that is left is the 1 bit that was injected */ - /* into bit 16 at the start of the current group. When we reach the end */ - /* of a group, we have to load a new control word and inject a new 1 bit. */ - if (control==1) - { - control=0x10000|*p_src++; - control|=(*p_src++)<<8; - } - - /* If it is possible that we are within 16 groups from the end of the */ - /* input, execute the unrolled loop only once, else process a whole group */ - /* of 16 items by looping 16 times. */ - unroll= p_src<=p_src_max16 ? 16 : 1; - - /* This inner loop processes one phrase (item) per iteration. */ - while (unroll--) - { /* Begin unrolled inner loop. */ - - /* Process a literal or copy item depending on the next control bit. */ - if (control&1) - { - /* Copy item. */ - - register UBYTE *p; /* Points to place from which to copy. */ - register UWORD lenmt; /* Length of copy item minus three. */ - register UBYTE **p_hte; /* Pointer to current hash table entry.*/ - register UBYTE *p_ziv=p_dst; /* Pointer to start of current Ziv. */ - - /* Read and dismantle the copy word. Work out from where to copy. */ - lenmt=*p_src++; - p_hte=&hash[((lenmt&0xF0)<<4)|*p_src++]; - p=*p_hte; - lenmt&=0xF; - - /* Now perform the copy using a half unrolled loop. */ - *p_dst++=*p++; - *p_dst++=*p++; - *p_dst++=*p++; - while (lenmt--) - *p_dst++=*p++; - - /* Because we have just received 3 or more bytes in a copy item */ - /* (whose bytes we have just installed in the output), we are now */ - /* in a position to flush all the pending literal hashings that had */ - /* been postponed for lack of bytes. */ - if (literals>0) - { - register UBYTE *r=p_ziv-literals; - hash[HASH(r)]=r; - if (literals==2) - {r++; hash[HASH(r)]=r;} - literals=0; - } - - /* In any case, we can immediately update the hash table with the */ - /* current position. We don't need to do a HASH(...) to work out */ - /* where to put the pointer, as the compressor just told us!!! */ - *p_hte=p_ziv; - - } - else - { - /* Literal item. */ - - /* Copy over the literal byte. */ - *p_dst++=*p_src++; - - /* If we now have three literals waiting to be hashed into the hash */ - /* table, we can do one of them now (because there are three). */ - if (++literals == 3) - {register UBYTE *p=p_dst-3; hash[HASH(p)]=p; literals=2;} - } - - /* Shift the control buffer so the next control bit is in bit 0. */ - control>>=1; -#if 1 - if (p_dst > p_dst_post) - { - /* Shit: we tried to decompress corrupt data */ - *p_dst_len = 0; - return; - } -#endif - } /* End unrolled inner loop. */ - - } /* End of outer loop */ - - /* Write the length of the decompressed data before returning. */ - *p_dst_len=p_dst-p_dst_first; -} - -/******************************************************************************/ -/* End of LZRW3.C */ -/******************************************************************************/ diff --git a/drivers/char/ftape/compressor/lzrw3.h b/drivers/char/ftape/compressor/lzrw3.h deleted file mode 100644 index 533feba4752..00000000000 --- a/drivers/char/ftape/compressor/lzrw3.h +++ /dev/null @@ -1,253 +0,0 @@ -#ifndef _LZRW3_H -#define _LZRW3_H -/* - * $Source: /homes/cvs/ftape-stacked/ftape/compressor/lzrw3.h,v $ - * $Revision: 1.1 $ - * $Date: 1997/10/05 19:12:30 $ - * - * include files for lzrw3. Only slighty modified from the original - * version. Assembles the three include files compress.h, port.h and - * fastcopy.h from the original lzrw3 package. - * - */ - -#include -#include - -/******************************************************************************/ -/* */ -/* COMPRESS.H */ -/* */ -/******************************************************************************/ -/* */ -/* Author : Ross Williams. */ -/* Date : December 1989. */ -/* */ -/* This header file defines the interface to a set of functions called */ -/* 'compress', each member of which implements a particular data compression */ -/* algorithm. */ -/* */ -/* Normally in C programming, for each .H file, there is a corresponding .C */ -/* file that implements the functions promised in the .H file. */ -/* Here, there are many .C files corresponding to this header file. */ -/* Each comforming implementation file contains a single function */ -/* called 'compress' that implements a single data compression */ -/* algorithm that conforms with the interface specified in this header file. */ -/* Only one algorithm can be linked in at a time in this organization. */ -/* */ -/******************************************************************************/ -/* */ -/* DEFINITION OF FUNCTION COMPRESS */ -/* =============================== */ -/* */ -/* Summary of Function Compress */ -/* ---------------------------- */ -/* The action that 'compress' takes depends on its first argument called */ -/* 'action'. The function provides three actions: */ -/* */ -/* - Return information about the algorithm. */ -/* - Compress a block of memory. */ -/* - Decompress a block of memory. */ -/* */ -/* Parameters */ -/* ---------- */ -/* See the formal C definition later for a description of the parameters. */ -/* */ -/* Constants */ -/* --------- */ -/* COMPRESS_OVERRUN: The constant COMPRESS_OVERRUN defines by how many bytes */ -/* an algorithm is allowed to expand a block during a compression operation. */ -/* */ -/* Although compression algorithms usually compress data, there will always */ -/* be data that a given compressor will expand (this can be proven). */ -/* Fortunately, the degree of expansion can be limited to a single bit, by */ -/* copying over the input data if the data gets bigger during compression. */ -/* To allow for this possibility, the first bit of a compressed */ -/* representation can be used as a flag indicating whether the */ -/* input data was copied over, or truly compressed. In practice, the first */ -/* byte would be used to store this bit so as to maintain byte alignment. */ -/* */ -/* Unfortunately, in general, the only way to tell if an algorithm will */ -/* expand a particular block of data is to run the algorithm on the data. */ -/* If the algorithm does not continuously monitor how many output bytes it */ -/* has written, it might write an output block far larger than the input */ -/* block before realizing that it has done so. */ -/* On the other hand, continuous checks on output length are inefficient. */ -/* */ -/* To cater for all these problems, this interface definition: */ -/* > Allows a compression algorithm to return an output block that is up to */ -/* COMPRESS_OVERRUN bytes longer than the input block. */ -/* > Allows a compression algorithm to write up to COMPRESS_OVERRUN bytes */ -/* more than the length of the input block to the memory of the output */ -/* block regardless of the length of the output block eventually returned. */ -/* This allows an algorithm to overrun the length of the input block in the */ -/* output block by up to COMPRESS_OVERRUN bytes between expansion checks. */ -/* */ -/* The problem does not arise for decompression. */ -/* */ -/* Identity Action */ -/* --------------- */ -/* > action must be COMPRESS_ACTION_IDENTITY. */ -/* > p_dst_len must point to a longword to receive a longword address. */ -/* > The value of the other parameters does not matter. */ -/* > After execution, the longword that p_dst_len points to will be a pointer */ -/* to a structure of type compress_identity. */ -/* Thus, for example, after the call, (*p_dst_len)->memory will return the */ -/* number of bytes of working memory that the algorithm requires to run. */ -/* > The values of the identity structure returned are fixed constant */ -/* attributes of the algorithm and must not vary from call to call. */ -/* */ -/* Common Requirements for Compression and Decompression Actions */ -/* ------------------------------------------------------------- */ -/* > wrk_mem must point to an unused block of memory of a length specified in */ -/* the algorithm's identity block. The identity block can be obtained by */ -/* making a separate call to compress, specifying the identity action. */ -/* > The INPUT BLOCK is defined to be Memory[src_addr,src_addr+src_len-1]. */ -/* > dst_len will be used to denote *p_dst_len. */ -/* > dst_len is not read by compress, only written. */ -/* > The value of dst_len is defined only upon termination. */ -/* > The OUTPUT BLOCK is defined to be Memory[dst_addr,dst_addr+dst_len-1]. */ -/* */ -/* Compression Action */ -/* ------------------ */ -/* > action must be COMPRESS_ACTION_COMPRESS. */ -/* > src_len must be in the range [0,COMPRESS_MAX_ORG]. */ -/* > The OUTPUT ZONE is defined to be */ -/* Memory[dst_addr,dst_addr+src_len-1+COMPRESS_OVERRUN]. */ -/* > The function can modify any part of the output zone regardless of the */ -/* final length of the output block. */ -/* > The input block and the output zone must not overlap. */ -/* > dst_len will be in the range [0,src_len+COMPRESS_OVERRUN]. */ -/* > dst_len will be in the range [0,COMPRESS_MAX_COM] (from prev fact). */ -/* > The output block will consist of a representation of the input block. */ -/* */ -/* Decompression Action */ -/* -------------------- */ -/* > action must be COMPRESS_ACTION_DECOMPRESS. */ -/* > The input block must be the result of an earlier compression operation. */ -/* > If the previous fact is true, the following facts must also be true: */ -/* > src_len will be in the range [0,COMPRESS_MAX_COM]. */ -/* > dst_len will be in the range [0,COMPRESS_MAX_ORG]. */ -/* > The input and output blocks must not overlap. */ -/* > Only the output block is modified. */ -/* > Upon termination, the output block will consist of the bytes contained */ -/* in the input block passed to the earlier compression operation. */ -/* */ -/******************************************************************************/ - -/******************************************************************************/ -/* */ -/* PORT.H */ -/* */ -/******************************************************************************/ -/* */ -/* This module contains macro definitions and types that are likely to */ -/* change between computers. */ -/* */ -/******************************************************************************/ - -#ifndef DONE_PORT /* Only do this if not previously done. */ - - #ifdef THINK_C - #define UBYTE unsigned char /* Unsigned byte */ - #define UWORD unsigned int /* Unsigned word (2 bytes) */ - #define ULONG unsigned long /* Unsigned word (4 bytes) */ - #define BOOL unsigned char /* Boolean */ - #define FOPEN_BINARY_READ "rb" /* Mode string for binary reading. */ - #define FOPEN_BINARY_WRITE "wb" /* Mode string for binary writing. */ - #define FOPEN_TEXT_APPEND "a" /* Mode string for text appending. */ - #define REAL double /* USed for floating point stuff. */ - #endif - #if defined(LINUX) || defined(linux) - #define UBYTE __u8 /* Unsigned byte */ - #define UWORD __u16 /* Unsigned word (2 bytes) */ - #define ULONG __u32 /* Unsigned word (4 bytes) */ - #define LONG __s32 /* Signed word (4 bytes) */ - #define BOOL is not used here /* Boolean */ - #define FOPEN_BINARY_READ not used /* Mode string for binary reading. */ - #define FOPEN_BINARY_WRITE not used /* Mode string for binary writing. */ - #define FOPEN_TEXT_APPEND not used /* Mode string for text appending. */ - #define REAL not used /* USed for floating point stuff. */ - #ifndef TRUE - #define TRUE 1 - #endif - #endif - - #define DONE_PORT /* Don't do all this again. */ - #define MALLOC_FAIL NULL /* Failure status from malloc() */ - #define LOCAL static /* For non-exported routines. */ - #define EXPORT /* Signals exported function. */ - #define then /* Useful for aligning ifs. */ - -#endif - -/******************************************************************************/ -/* End of PORT.H */ -/******************************************************************************/ - -#define COMPRESS_ACTION_IDENTITY 0 -#define COMPRESS_ACTION_COMPRESS 1 -#define COMPRESS_ACTION_DECOMPRESS 2 - -#define COMPRESS_OVERRUN 1024 -#define COMPRESS_MAX_COM 0x70000000 -#define COMPRESS_MAX_ORG (COMPRESS_MAX_COM-COMPRESS_OVERRUN) - -#define COMPRESS_MAX_STRLEN 255 - -/* The following structure provides information about the algorithm. */ -/* > The top bit of id must be zero. The remaining bits must be chosen by */ -/* the author of the algorithm by tossing a coin 31 times. */ -/* > The amount of memory requested by the algorithm is specified in bytes */ -/* and must be in the range [0,0x70000000]. */ -/* > All strings s must be such that strlen(s)<=COMPRESS_MAX_STRLEN. */ -struct compress_identity - { - ULONG id; /* Identifying number of algorithm. */ - ULONG memory; /* Number of bytes of working memory required. */ - - char *name; /* Name of algorithm. */ - char *version; /* Version number. */ - char *date; /* Date of release of this version. */ - char *copyright; /* Copyright message. */ - - char *author; /* Author of algorithm. */ - char *affiliation; /* Affiliation of author. */ - char *vendor; /* Where the algorithm can be obtained. */ - }; - -void lzrw3_compress( /* Single function interface to compression algorithm. */ -UWORD action, /* Action to be performed. */ -UBYTE *wrk_mem, /* Working memory temporarily given to routine to use. */ -UBYTE *src_adr, /* Address of input data. */ -LONG src_len, /* Length of input data. */ -UBYTE *dst_adr, /* Address of output data. */ -void *p_dst_len /* Pointer to a longword where routine will write: */ - /* If action=..IDENTITY => Adr of id structure. */ - /* If action=..COMPRESS => Length of output data. */ - /* If action=..DECOMPRESS => Length of output data. */ -); - -/******************************************************************************/ -/* End of COMPRESS.H */ -/******************************************************************************/ - - -/******************************************************************************/ -/* fast_copy.h */ -/******************************************************************************/ - -/* This function copies a block of memory very quickly. */ -/* The exact speed depends on the relative alignment of the blocks of memory. */ -/* PRE : 0<=src_len<=(2^32)-1 . */ -/* PRE : Source and destination blocks must not overlap. */ -/* POST : MEM[dst_adr,dst_adr+src_len-1]=MEM[src_adr,src_adr+src_len-1]. */ -/* POST : MEM[dst_adr,dst_adr+src_len-1] is the only memory changed. */ - -#define fast_copy(src,dst,len) memcpy(dst,src,len) - -/******************************************************************************/ -/* End of fast_copy.h */ -/******************************************************************************/ - -#endif diff --git a/drivers/char/ftape/compressor/zftape-compress.c b/drivers/char/ftape/compressor/zftape-compress.c deleted file mode 100644 index 65ffc0be3df..00000000000 --- a/drivers/char/ftape/compressor/zftape-compress.c +++ /dev/null @@ -1,1203 +0,0 @@ -/* - * Copyright (C) 1994-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. - - * - * This file implements a "generic" interface between the * - * zftape-driver and a compression-algorithm. The * - * compression-algorithm currently used is a LZ77. I use the * - * implementation lzrw3 by Ross N. Williams (Renaissance * - * Software). The compression program itself is in the file - * lzrw3.c * and lzrw3.h. To adopt another compression algorithm - * the functions * zft_compress() and zft_uncompress() must be - * changed * appropriately. See below. - */ - -#include -#include -#include - -#include - -#include - -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-eof.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-write.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-rw.h" -#include "../compressor/zftape-compress.h" -#include "../zftape/zftape-vtbl.h" -#include "../compressor/lzrw3.h" - -/* - * global variables - */ - -/* I handle the allocation of this buffer as a special case, because - * it's size varies depending on the tape length inserted. - */ - -/* local variables - */ -static void *zftc_wrk_mem = NULL; -static __u8 *zftc_buf = NULL; -static void *zftc_scratch_buf = NULL; - -/* compression statistics - */ -static unsigned int zftc_wr_uncompressed = 0; -static unsigned int zftc_wr_compressed = 0; -static unsigned int zftc_rd_uncompressed = 0; -static unsigned int zftc_rd_compressed = 0; - -/* forward */ -static int zftc_write(int *write_cnt, - __u8 *dst_buf, const int seg_sz, - const __u8 __user *src_buf, const int req_len, - const zft_position *pos, const zft_volinfo *volume); -static int zftc_read(int *read_cnt, - __u8 __user *dst_buf, const int to_do, - const __u8 *src_buf, const int seg_sz, - const zft_position *pos, const zft_volinfo *volume); -static int zftc_seek(unsigned int new_block_pos, - zft_position *pos, const zft_volinfo *volume, - __u8 *buffer); -static void zftc_lock (void); -static void zftc_reset (void); -static void zftc_cleanup(void); -static void zftc_stats (void); - -/* compressed segment. This conforms to QIC-80-MC, Revision K. - * - * Rev. K applies to tapes with `fixed length format' which is - * indicated by format code 2,3 and 5. See below for format code 4 and 6 - * - * 2 bytes: offset of compression segment structure - * 29k > offset >= 29k-18: data from previous segment ens in this - * segment and no compressed block starts - * in this segment - * offset == 0: data from previous segment occupies entire - * segment and continues in next segment - * n bytes: remainder from previous segment - * - * Rev. K: - * 4 bytes: 4 bytes: files set byte offset - * Post Rev. K and QIC-3020/3020: - * 8 bytes: 8 bytes: files set byte offset - * 2 bytes: byte count N (amount of data following) - * bit 15 is set if data is compressed, bit 15 is not - * set if data is uncompressed - * N bytes: data (as much as specified in the byte count) - * 2 bytes: byte count N_1 of next cluster - * N_1 bytes: data of next cluset - * 2 bytes: byte count N_2 of next cluster - * N_2 bytes: ... - * - * Note that the `N' byte count accounts only for the bytes that in the - * current segment if the cluster spans to the next segment. - */ - -typedef struct -{ - int cmpr_pos; /* actual position in compression buffer */ - int cmpr_sz; /* what is left in the compression buffer - * when copying the compressed data to the - * deblock buffer - */ - unsigned int first_block; /* location of header information in - * this segment - */ - unsigned int count; /* amount of data of current block - * contained in current segment - */ - unsigned int offset; /* offset in current segment */ - unsigned int spans:1; /* might continue in next segment */ - unsigned int uncmpr; /* 0x8000 if this block contains - * uncompressed data - */ - __s64 foffs; /* file set byte offset, same as in - * compression map segment - */ -} cmpr_info; - -static cmpr_info cseg; /* static data. Must be kept uptodate and shared by - * read, write and seek functions - */ - -#define DUMP_CMPR_INFO(level, msg, info) \ - TRACE(level, msg "\n" \ - KERN_INFO "cmpr_pos : %d\n" \ - KERN_INFO "cmpr_sz : %d\n" \ - KERN_INFO "first_block: %d\n" \ - KERN_INFO "count : %d\n" \ - KERN_INFO "offset : %d\n" \ - KERN_INFO "spans : %d\n" \ - KERN_INFO "uncmpr : 0x%04x\n" \ - KERN_INFO "foffs : " LL_X, \ - (info)->cmpr_pos, (info)->cmpr_sz, (info)->first_block, \ - (info)->count, (info)->offset, (info)->spans == 1, \ - (info)->uncmpr, LL((info)->foffs)) - -/* dispatch compression segment info, return error code - * - * afterwards, cseg->offset points to start of data of the NEXT - * compressed block, and cseg->count contains the amount of data - * left in the actual compressed block. cseg->spans is set to 1 if - * the block is continued in the following segment. Otherwise it is - * set to 0. - */ -static int get_cseg (cmpr_info *cinfo, const __u8 *buff, - const unsigned int seg_sz, - const zft_volinfo *volume) -{ - TRACE_FUN(ft_t_flow); - - cinfo->first_block = GET2(buff, 0); - if (cinfo->first_block == 0) { /* data spans to next segment */ - cinfo->count = seg_sz - sizeof(__u16); - cinfo->offset = seg_sz; - cinfo->spans = 1; - } else { /* cluster definetely ends in this segment */ - if (cinfo->first_block > seg_sz) { - /* data corrupted */ - TRACE_ABORT(-EIO, ft_t_err, "corrupted data:\n" - KERN_INFO "segment size: %d\n" - KERN_INFO "first block : %d", - seg_sz, cinfo->first_block); - } - cinfo->count = cinfo->first_block - sizeof(__u16); - cinfo->offset = cinfo->first_block; - cinfo->spans = 0; - } - /* now get the offset the first block should have in the - * uncompressed data stream. - * - * For this magic `18' refer to CRF-3 standard or QIC-80MC, - * Rev. K. - */ - if ((seg_sz - cinfo->offset) > 18) { - if (volume->qic113) { /* > revision K */ - TRACE(ft_t_data_flow, "New QIC-113 compliance"); - cinfo->foffs = GET8(buff, cinfo->offset); - cinfo->offset += sizeof(__s64); - } else { - TRACE(/* ft_t_data_flow */ ft_t_noise, "pre QIC-113 version"); - cinfo->foffs = (__s64)GET4(buff, cinfo->offset); - cinfo->offset += sizeof(__u32); - } - } - if (cinfo->foffs > volume->size) { - TRACE_ABORT(-EIO, ft_t_err, "Inconsistency:\n" - KERN_INFO "offset in current volume: %d\n" - KERN_INFO "size of current volume : %d", - (int)(cinfo->foffs>>10), (int)(volume->size>>10)); - } - if (cinfo->cmpr_pos + cinfo->count > volume->blk_sz) { - TRACE_ABORT(-EIO, ft_t_err, "Inconsistency:\n" - KERN_INFO "block size : %d\n" - KERN_INFO "data record: %d", - volume->blk_sz, cinfo->cmpr_pos + cinfo->count); - } - DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */, "", cinfo); - TRACE_EXIT 0; -} - -/* This one is called, when a new cluster starts in same segment. - * - * Note: if this is the first cluster in the current segment, we must - * not check whether there are more than 18 bytes available because - * this have already been done in get_cseg() and there may be less - * than 18 bytes available due to header information. - * - */ -static void get_next_cluster(cmpr_info *cluster, const __u8 *buff, - const int seg_sz, const int finish) -{ - TRACE_FUN(ft_t_flow); - - if (seg_sz - cluster->offset > 18 || cluster->foffs != 0) { - cluster->count = GET2(buff, cluster->offset); - cluster->uncmpr = cluster->count & 0x8000; - cluster->count -= cluster->uncmpr; - cluster->offset += sizeof(__u16); - cluster->foffs = 0; - if ((cluster->offset + cluster->count) < seg_sz) { - cluster->spans = 0; - } else if (cluster->offset + cluster->count == seg_sz) { - cluster->spans = !finish; - } else { - /* either an error or a volume written by an - * old version. If this is a data error, then we'll - * catch it later. - */ - TRACE(ft_t_data_flow, "Either error or old volume"); - cluster->spans = 1; - cluster->count = seg_sz - cluster->offset; - } - } else { - cluster->count = 0; - cluster->spans = 0; - cluster->foffs = 0; - } - DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */ , "", cluster); - TRACE_EXIT; -} - -static void zftc_lock(void) -{ -} - -/* this function is needed for zftape_reset_position in zftape-io.c - */ -static void zftc_reset(void) -{ - TRACE_FUN(ft_t_flow); - - memset((void *)&cseg, '\0', sizeof(cseg)); - zftc_stats(); - TRACE_EXIT; -} - -static int cmpr_mem_initialized = 0; -static unsigned int alloc_blksz = 0; - -static int zft_allocate_cmpr_mem(unsigned int blksz) -{ - TRACE_FUN(ft_t_flow); - - if (cmpr_mem_initialized && blksz == alloc_blksz) { - TRACE_EXIT 0; - } - TRACE_CATCH(zft_vmalloc_once(&zftc_wrk_mem, CMPR_WRK_MEM_SIZE), - zftc_cleanup()); - TRACE_CATCH(zft_vmalloc_always(&zftc_buf, blksz + CMPR_OVERRUN), - zftc_cleanup()); - alloc_blksz = blksz; - TRACE_CATCH(zft_vmalloc_always(&zftc_scratch_buf, blksz+CMPR_OVERRUN), - zftc_cleanup()); - cmpr_mem_initialized = 1; - TRACE_EXIT 0; -} - -static void zftc_cleanup(void) -{ - TRACE_FUN(ft_t_flow); - - zft_vfree(&zftc_wrk_mem, CMPR_WRK_MEM_SIZE); - zft_vfree(&zftc_buf, alloc_blksz + CMPR_OVERRUN); - zft_vfree(&zftc_scratch_buf, alloc_blksz + CMPR_OVERRUN); - cmpr_mem_initialized = alloc_blksz = 0; - TRACE_EXIT; -} - -/***************************************************************************** - * * - * The following two functions "ftape_compress()" and * - * "ftape_uncompress()" are the interface to the actual compression * - * algorithm (i.e. they are calling the "compress()" function from * - * the lzrw3 package for now). These routines could quite easily be * - * changed to adopt another compression algorithm instead of lzrw3, * - * which currently is used. * - * * - *****************************************************************************/ - -/* called by zft_compress_write() to perform the compression. Must - * return the size of the compressed data. - * - * NOTE: The size of the compressed data should not exceed the size of - * the uncompressed data. Most compression algorithms have means - * to store data unchanged if the "compressed" data amount would - * exceed the original one. Mostly this is done by storing some - * flag-bytes in front of the compressed data to indicate if it - * is compressed or not. Thus the worst compression result - * length is the original length plus those flag-bytes. - * - * We don't want that, as the QIC-80 standard provides a means - * of marking uncompressed blocks by simply setting bit 15 of - * the compressed block's length. Thus a compessed block can - * have at most a length of 2^15-1 bytes. The QIC-80 standard - * restricts the block-length even further, allowing only 29k - - * 6 bytes. - * - * Currently, the maximum blocksize used by zftape is 28k. - * - * In short: don't exceed the length of the input-package, set - * bit 15 of the compressed size to 1 if you have copied data - * instead of compressing it. - */ -static int zft_compress(__u8 *in_buffer, unsigned int in_sz, __u8 *out_buffer) -{ - __s32 compressed_sz; - TRACE_FUN(ft_t_flow); - - - lzrw3_compress(COMPRESS_ACTION_COMPRESS, zftc_wrk_mem, - in_buffer, in_sz, out_buffer, &compressed_sz); - if (TRACE_LEVEL >= ft_t_info) { - /* the compiler will optimize this away when - * compiled with NO_TRACE_AT_ALL option - */ - TRACE(ft_t_data_flow, "\n" - KERN_INFO "before compression: %d bytes\n" - KERN_INFO "after compresison : %d bytes", - in_sz, - (int)(compressed_sz < 0 - ? -compressed_sz : compressed_sz)); - /* for statistical purposes - */ - zftc_wr_compressed += (compressed_sz < 0 - ? -compressed_sz : compressed_sz); - zftc_wr_uncompressed += in_sz; - } - TRACE_EXIT (int)compressed_sz; -} - -/* called by zft_compress_read() to decompress the data. Must - * return the size of the decompressed data for sanity checks - * (compared with zft_blk_sz) - * - * NOTE: Read the note for zft_compress() above! If bit 15 of the - * parameter in_sz is set, then the data in in_buffer isn't - * compressed, which must be handled by the un-compression - * algorithm. (I changed lzrw3 to handle this.) - * - * The parameter max_out_sz is needed to prevent buffer overruns when - * uncompressing corrupt data. - */ -static unsigned int zft_uncompress(__u8 *in_buffer, - int in_sz, - __u8 *out_buffer, - unsigned int max_out_sz) -{ - TRACE_FUN(ft_t_flow); - - lzrw3_compress(COMPRESS_ACTION_DECOMPRESS, zftc_wrk_mem, - in_buffer, (__s32)in_sz, - out_buffer, (__u32 *)&max_out_sz); - - if (TRACE_LEVEL >= ft_t_info) { - TRACE(ft_t_data_flow, "\n" - KERN_INFO "before decompression: %d bytes\n" - KERN_INFO "after decompression : %d bytes", - in_sz < 0 ? -in_sz : in_sz,(int)max_out_sz); - /* for statistical purposes - */ - zftc_rd_compressed += in_sz < 0 ? -in_sz : in_sz; - zftc_rd_uncompressed += max_out_sz; - } - TRACE_EXIT (unsigned int)max_out_sz; -} - -/* print some statistics about the efficiency of the compression to - * the kernel log - */ -static void zftc_stats(void) -{ - TRACE_FUN(ft_t_flow); - - if (TRACE_LEVEL < ft_t_info) { - TRACE_EXIT; - } - if (zftc_wr_uncompressed != 0) { - if (zftc_wr_compressed > (1<<14)) { - TRACE(ft_t_info, "compression statistics (writing):\n" - KERN_INFO " compr./uncmpr. : %3d %%", - (((zftc_wr_compressed>>10) * 100) - / (zftc_wr_uncompressed>>10))); - } else { - TRACE(ft_t_info, "compression statistics (writing):\n" - KERN_INFO " compr./uncmpr. : %3d %%", - ((zftc_wr_compressed * 100) - / zftc_wr_uncompressed)); - } - } - if (zftc_rd_uncompressed != 0) { - if (zftc_rd_compressed > (1<<14)) { - TRACE(ft_t_info, "compression statistics (reading):\n" - KERN_INFO " compr./uncmpr. : %3d %%", - (((zftc_rd_compressed>>10) * 100) - / (zftc_rd_uncompressed>>10))); - } else { - TRACE(ft_t_info, "compression statistics (reading):\n" - KERN_INFO " compr./uncmpr. : %3d %%", - ((zftc_rd_compressed * 100) - / zftc_rd_uncompressed)); - } - } - /* only print it once: */ - zftc_wr_uncompressed = - zftc_wr_compressed = - zftc_rd_uncompressed = - zftc_rd_compressed = 0; - TRACE_EXIT; -} - -/* start new compressed block - */ -static int start_new_cseg(cmpr_info *cluster, - char *dst_buf, - const zft_position *pos, - const unsigned int blk_sz, - const char *src_buf, - const int this_segs_sz, - const int qic113) -{ - int size_left; - int cp_cnt; - int buf_pos; - TRACE_FUN(ft_t_flow); - - size_left = this_segs_sz - sizeof(__u16) - cluster->cmpr_sz; - TRACE(ft_t_data_flow,"\n" - KERN_INFO "segment size : %d\n" - KERN_INFO "compressed_sz: %d\n" - KERN_INFO "size_left : %d", - this_segs_sz, cluster->cmpr_sz, size_left); - if (size_left > 18) { /* start a new cluseter */ - cp_cnt = cluster->cmpr_sz; - cluster->cmpr_sz = 0; - buf_pos = cp_cnt + sizeof(__u16); - PUT2(dst_buf, 0, buf_pos); - - if (qic113) { - __s64 foffs = pos->volume_pos; - if (cp_cnt) foffs += (__s64)blk_sz; - - TRACE(ft_t_data_flow, "new style QIC-113 header"); - PUT8(dst_buf, buf_pos, foffs); - buf_pos += sizeof(__s64); - } else { - __u32 foffs = (__u32)pos->volume_pos; - if (cp_cnt) foffs += (__u32)blk_sz; - - TRACE(ft_t_data_flow, "old style QIC-80MC header"); - PUT4(dst_buf, buf_pos, foffs); - buf_pos += sizeof(__u32); - } - } else if (size_left >= 0) { - cp_cnt = cluster->cmpr_sz; - cluster->cmpr_sz = 0; - buf_pos = cp_cnt + sizeof(__u16); - PUT2(dst_buf, 0, buf_pos); - /* zero unused part of segment. */ - memset(dst_buf + buf_pos, '\0', size_left); - buf_pos = this_segs_sz; - } else { /* need entire segment and more space */ - PUT2(dst_buf, 0, 0); - cp_cnt = this_segs_sz - sizeof(__u16); - cluster->cmpr_sz -= cp_cnt; - buf_pos = this_segs_sz; - } - memcpy(dst_buf + sizeof(__u16), src_buf + cluster->cmpr_pos, cp_cnt); - cluster->cmpr_pos += cp_cnt; - TRACE_EXIT buf_pos; -} - -/* return-value: the number of bytes removed from the user-buffer - * `src_buf' or error code - * - * int *write_cnt : how much actually has been moved to the - * dst_buf. Need not be initialized when - * function returns with an error code - * (negativ return value) - * __u8 *dst_buf : kernel space buffer where the has to be - * copied to. The contents of this buffers - * goes to a specific segment. - * const int seg_sz : the size of the segment dst_buf will be - * copied to. - * const zft_position *pos : struct containing the coordinates in - * the current volume (byte position, - * segment id of current segment etc) - * const zft_volinfo *volume: information about the current volume, - * size etc. - * const __u8 *src_buf : user space buffer that contains the - * data the user wants to be written to - * tape. - * const int req_len : the amount of data the user wants to be - * written to tape. - */ -static int zftc_write(int *write_cnt, - __u8 *dst_buf, const int seg_sz, - const __u8 __user *src_buf, const int req_len, - const zft_position *pos, const zft_volinfo *volume) -{ - int req_len_left = req_len; - int result; - int len_left; - int buf_pos_write = pos->seg_byte_pos; - TRACE_FUN(ft_t_flow); - - /* Note: we do not unlock the module because - * there are some values cached in that `cseg' variable. We - * don't don't want to use this information when being - * unloaded by kerneld even when the tape is full or when we - * cannot allocate enough memory. - */ - if (pos->tape_pos > (volume->size-volume->blk_sz-ZFT_CMPR_OVERHEAD)) { - TRACE_EXIT -ENOSPC; - } - if (zft_allocate_cmpr_mem(volume->blk_sz) < 0) { - /* should we unlock the module? But it shouldn't - * be locked anyway ... - */ - TRACE_EXIT -ENOMEM; - } - if (buf_pos_write == 0) { /* fill a new segment */ - *write_cnt = buf_pos_write = start_new_cseg(&cseg, - dst_buf, - pos, - volume->blk_sz, - zftc_buf, - seg_sz, - volume->qic113); - if (cseg.cmpr_sz == 0 && cseg.cmpr_pos != 0) { - req_len_left -= result = volume->blk_sz; - cseg.cmpr_pos = 0; - } else { - result = 0; - } - } else { - *write_cnt = result = 0; - } - - len_left = seg_sz - buf_pos_write; - while ((req_len_left > 0) && (len_left > 18)) { - /* now we have some size left for a new compressed - * block. We know, that the compression buffer is - * empty (else there wouldn't be any space left). - */ - if (copy_from_user(zftc_scratch_buf, src_buf + result, - volume->blk_sz) != 0) { - TRACE_EXIT -EFAULT; - } - req_len_left -= volume->blk_sz; - cseg.cmpr_sz = zft_compress(zftc_scratch_buf, volume->blk_sz, - zftc_buf); - if (cseg.cmpr_sz < 0) { - cseg.uncmpr = 0x8000; - cseg.cmpr_sz = -cseg.cmpr_sz; - } else { - cseg.uncmpr = 0; - } - /* increment "result" iff we copied the entire - * compressed block to the zft_deblock_buf - */ - len_left -= sizeof(__u16); - if (len_left >= cseg.cmpr_sz) { - len_left -= cseg.count = cseg.cmpr_sz; - cseg.cmpr_pos = cseg.cmpr_sz = 0; - result += volume->blk_sz; - } else { - cseg.cmpr_sz -= - cseg.cmpr_pos = - cseg.count = len_left; - len_left = 0; - } - PUT2(dst_buf, buf_pos_write, cseg.uncmpr | cseg.count); - buf_pos_write += sizeof(__u16); - memcpy(dst_buf + buf_pos_write, zftc_buf, cseg.count); - buf_pos_write += cseg.count; - *write_cnt += cseg.count + sizeof(__u16); - FT_SIGNAL_EXIT(_DONT_BLOCK); - } - /* erase the remainder of the segment if less than 18 bytes - * left (18 bytes is due to the QIC-80 standard) - */ - if (len_left <= 18) { - memset(dst_buf + buf_pos_write, '\0', len_left); - (*write_cnt) += len_left; - } - TRACE(ft_t_data_flow, "returning %d", result); - TRACE_EXIT result; -} - -/* out: - * - * int *read_cnt: the number of bytes we removed from the zft_deblock_buf - * (result) - * int *to_do : the remaining size of the read-request. - * - * in: - * - * char *buff : buff is the address of the upper part of the user - * buffer, that hasn't been filled with data yet. - - * int buf_pos_read : copy of from _ftape_read() - * int buf_len_read : copy of buf_len_rd from _ftape_read() - * char *zft_deblock_buf: zft_deblock_buf - * unsigned short blk_sz: the block size valid for this volume, may differ - * from zft_blk_sz. - * int finish: if != 0 means that this is the last segment belonging - * to this volume - * returns the amount of data actually copied to the user-buffer - * - * to_do MUST NOT SHRINK except to indicate an EOF. In this case *to_do has to - * be set to 0 - */ -static int zftc_read (int *read_cnt, - __u8 __user *dst_buf, const int to_do, - const __u8 *src_buf, const int seg_sz, - const zft_position *pos, const zft_volinfo *volume) -{ - int uncompressed_sz; - int result = 0; - int remaining = to_do; - TRACE_FUN(ft_t_flow); - - TRACE_CATCH(zft_allocate_cmpr_mem(volume->blk_sz),); - if (pos->seg_byte_pos == 0) { - /* new segment just read - */ - TRACE_CATCH(get_cseg(&cseg, src_buf, seg_sz, volume), - *read_cnt = 0); - memcpy(zftc_buf + cseg.cmpr_pos, src_buf + sizeof(__u16), - cseg.count); - cseg.cmpr_pos += cseg.count; - *read_cnt = cseg.offset; - DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */, "", &cseg); - } else { - *read_cnt = 0; - } - /* loop and uncompress until user buffer full or - * deblock-buffer empty - */ - TRACE(ft_t_data_flow, "compressed_sz: %d, compos : %d, *read_cnt: %d", - cseg.cmpr_sz, cseg.cmpr_pos, *read_cnt); - while ((cseg.spans == 0) && (remaining > 0)) { - if (cseg.cmpr_pos != 0) { /* cmpr buf is not empty */ - uncompressed_sz = - zft_uncompress(zftc_buf, - cseg.uncmpr == 0x8000 ? - -cseg.cmpr_pos : cseg.cmpr_pos, - zftc_scratch_buf, - volume->blk_sz); - if (uncompressed_sz != volume->blk_sz) { - *read_cnt = 0; - TRACE_ABORT(-EIO, ft_t_warn, - "Uncompressed blk (%d) != blk size (%d)", - uncompressed_sz, volume->blk_sz); - } - if (copy_to_user(dst_buf + result, - zftc_scratch_buf, - uncompressed_sz) != 0 ) { - TRACE_EXIT -EFAULT; - } - remaining -= uncompressed_sz; - result += uncompressed_sz; - cseg.cmpr_pos = 0; - } - if (remaining > 0) { - get_next_cluster(&cseg, src_buf, seg_sz, - volume->end_seg == pos->seg_pos); - if (cseg.count != 0) { - memcpy(zftc_buf, src_buf + cseg.offset, - cseg.count); - cseg.cmpr_pos = cseg.count; - cseg.offset += cseg.count; - *read_cnt += cseg.count + sizeof(__u16); - } else { - remaining = 0; - } - } - TRACE(ft_t_data_flow, "\n" - KERN_INFO "compressed_sz: %d\n" - KERN_INFO "compos : %d\n" - KERN_INFO "*read_cnt : %d", - cseg.cmpr_sz, cseg.cmpr_pos, *read_cnt); - } - if (seg_sz - cseg.offset <= 18) { - *read_cnt += seg_sz - cseg.offset; - TRACE(ft_t_data_flow, "expanding read cnt to: %d", *read_cnt); - } - TRACE(ft_t_data_flow, "\n" - KERN_INFO "segment size : %d\n" - KERN_INFO "read count : %d\n" - KERN_INFO "buf_pos_read : %d\n" - KERN_INFO "remaining : %d", - seg_sz, *read_cnt, pos->seg_byte_pos, - seg_sz - *read_cnt - pos->seg_byte_pos); - TRACE(ft_t_data_flow, "returning: %d", result); - TRACE_EXIT result; -} - -/* seeks to the new data-position. Reads sometimes a segment. - * - * start_seg and end_seg give the boundaries of the current volume - * blk_sz is the blk_sz of the current volume as stored in the - * volume label - * - * We don't allow blocksizes less than 1024 bytes, therefore we don't need - * a 64 bit argument for new_block_pos. - */ - -static int seek_in_segment(const unsigned int to_do, cmpr_info *c_info, - const char *src_buf, const int seg_sz, - const int seg_pos, const zft_volinfo *volume); -static int slow_seek_forward_until_error(const unsigned int distance, - cmpr_info *c_info, zft_position *pos, - const zft_volinfo *volume, __u8 *buf); -static int search_valid_segment(unsigned int segment, - const unsigned int end_seg, - const unsigned int max_foffs, - zft_position *pos, cmpr_info *c_info, - const zft_volinfo *volume, __u8 *buf); -static int slow_seek_forward(unsigned int dest, cmpr_info *c_info, - zft_position *pos, const zft_volinfo *volume, - __u8 *buf); -static int compute_seg_pos(unsigned int dest, zft_position *pos, - const zft_volinfo *volume); - -#define ZFT_SLOW_SEEK_THRESHOLD 10 /* segments */ -#define ZFT_FAST_SEEK_MAX_TRIALS 10 /* times */ -#define ZFT_FAST_SEEK_BACKUP 10 /* segments */ - -static int zftc_seek(unsigned int new_block_pos, - zft_position *pos, const zft_volinfo *volume, __u8 *buf) -{ - unsigned int dest; - int limit; - int distance; - int result = 0; - int seg_dist; - int new_seg; - int old_seg = 0; - int fast_seek_trials = 0; - TRACE_FUN(ft_t_flow); - - if (new_block_pos == 0) { - pos->seg_pos = volume->start_seg; - pos->seg_byte_pos = 0; - pos->volume_pos = 0; - zftc_reset(); - TRACE_EXIT 0; - } - dest = new_block_pos * (volume->blk_sz >> 10); - distance = dest - (pos->volume_pos >> 10); - while (distance != 0) { - seg_dist = compute_seg_pos(dest, pos, volume); - TRACE(ft_t_noise, "\n" - KERN_INFO "seg_dist: %d\n" - KERN_INFO "distance: %d\n" - KERN_INFO "dest : %d\n" - KERN_INFO "vpos : %d\n" - KERN_INFO "seg_pos : %d\n" - KERN_INFO "trials : %d", - seg_dist, distance, dest, - (unsigned int)(pos->volume_pos>>10), pos->seg_pos, - fast_seek_trials); - if (distance > 0) { - if (seg_dist < 0) { - TRACE(ft_t_bug, "BUG: distance %d > 0, " - "segment difference %d < 0", - distance, seg_dist); - result = -EIO; - break; - } - new_seg = pos->seg_pos + seg_dist; - if (new_seg > volume->end_seg) { - new_seg = volume->end_seg; - } - if (old_seg == new_seg || /* loop */ - seg_dist <= ZFT_SLOW_SEEK_THRESHOLD || - fast_seek_trials >= ZFT_FAST_SEEK_MAX_TRIALS) { - TRACE(ft_t_noise, "starting slow seek:\n" - KERN_INFO "fast seek failed too often: %s\n" - KERN_INFO "near target position : %s\n" - KERN_INFO "looping between two segs : %s", - (fast_seek_trials >= - ZFT_FAST_SEEK_MAX_TRIALS) - ? "yes" : "no", - (seg_dist <= ZFT_SLOW_SEEK_THRESHOLD) - ? "yes" : "no", - (old_seg == new_seg) - ? "yes" : "no"); - result = slow_seek_forward(dest, &cseg, - pos, volume, buf); - break; - } - old_seg = new_seg; - limit = volume->end_seg; - fast_seek_trials ++; - for (;;) { - result = search_valid_segment(new_seg, limit, - volume->size, - pos, &cseg, - volume, buf); - if (result == 0 || result == -EINTR) { - break; - } - if (new_seg == volume->start_seg) { - result = -EIO; /* set errror - * condition - */ - break; - } - limit = new_seg; - new_seg -= ZFT_FAST_SEEK_BACKUP; - if (new_seg < volume->start_seg) { - new_seg = volume->start_seg; - } - } - if (result < 0) { - TRACE(ft_t_warn, - "Couldn't find a readable segment"); - break; - } - } else /* if (distance < 0) */ { - if (seg_dist > 0) { - TRACE(ft_t_bug, "BUG: distance %d < 0, " - "segment difference %d >0", - distance, seg_dist); - result = -EIO; - break; - } - new_seg = pos->seg_pos + seg_dist; - if (fast_seek_trials > 0 && seg_dist == 0) { - /* this avoids sticking to the same - * segment all the time. On the other hand: - * if we got here for the first time, and the - * deblock_buffer still contains a valid - * segment, then there is no need to skip to - * the previous segment if the desired position - * is inside this segment. - */ - new_seg --; - } - if (new_seg < volume->start_seg) { - new_seg = volume->start_seg; - } - limit = pos->seg_pos; - fast_seek_trials ++; - for (;;) { - result = search_valid_segment(new_seg, limit, - pos->volume_pos, - pos, &cseg, - volume, buf); - if (result == 0 || result == -EINTR) { - break; - } - if (new_seg == volume->start_seg) { - result = -EIO; /* set errror - * condition - */ - break; - } - limit = new_seg; - new_seg -= ZFT_FAST_SEEK_BACKUP; - if (new_seg < volume->start_seg) { - new_seg = volume->start_seg; - } - } - if (result < 0) { - TRACE(ft_t_warn, - "Couldn't find a readable segment"); - break; - } - } - distance = dest - (pos->volume_pos >> 10); - } - TRACE_EXIT result; -} - - -/* advance inside the given segment at most to_do bytes. - * of kilobytes moved - */ - -static int seek_in_segment(const unsigned int to_do, - cmpr_info *c_info, - const char *src_buf, - const int seg_sz, - const int seg_pos, - const zft_volinfo *volume) -{ - int result = 0; - int blk_sz = volume->blk_sz >> 10; - int remaining = to_do; - TRACE_FUN(ft_t_flow); - - if (c_info->offset == 0) { - /* new segment just read - */ - TRACE_CATCH(get_cseg(c_info, src_buf, seg_sz, volume),); - c_info->cmpr_pos += c_info->count; - DUMP_CMPR_INFO(ft_t_noise, "", c_info); - } - /* loop and uncompress until user buffer full or - * deblock-buffer empty - */ - TRACE(ft_t_noise, "compressed_sz: %d, compos : %d", - c_info->cmpr_sz, c_info->cmpr_pos); - while (c_info->spans == 0 && remaining > 0) { - if (c_info->cmpr_pos != 0) { /* cmpr buf is not empty */ - result += blk_sz; - remaining -= blk_sz; - c_info->cmpr_pos = 0; - } - if (remaining > 0) { - get_next_cluster(c_info, src_buf, seg_sz, - volume->end_seg == seg_pos); - if (c_info->count != 0) { - c_info->cmpr_pos = c_info->count; - c_info->offset += c_info->count; - } else { - break; - } - } - /* Allow escape from this loop on signal! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - DUMP_CMPR_INFO(ft_t_noise, "", c_info); - TRACE(ft_t_noise, "to_do: %d", remaining); - } - if (seg_sz - c_info->offset <= 18) { - c_info->offset = seg_sz; - } - TRACE(ft_t_noise, "\n" - KERN_INFO "segment size : %d\n" - KERN_INFO "buf_pos_read : %d\n" - KERN_INFO "remaining : %d", - seg_sz, c_info->offset, - seg_sz - c_info->offset); - TRACE_EXIT result; -} - -static int slow_seek_forward_until_error(const unsigned int distance, - cmpr_info *c_info, - zft_position *pos, - const zft_volinfo *volume, - __u8 *buf) -{ - unsigned int remaining = distance; - int seg_sz; - int seg_pos; - int result; - TRACE_FUN(ft_t_flow); - - seg_pos = pos->seg_pos; - do { - TRACE_CATCH(seg_sz = zft_fetch_segment(seg_pos, buf, - FT_RD_AHEAD),); - /* now we have the contents of the actual segment in - * the deblock buffer - */ - TRACE_CATCH(result = seek_in_segment(remaining, c_info, buf, - seg_sz, seg_pos,volume),); - remaining -= result; - pos->volume_pos += result<<10; - pos->seg_pos = seg_pos; - pos->seg_byte_pos = c_info->offset; - seg_pos ++; - if (seg_pos <= volume->end_seg && c_info->offset == seg_sz) { - pos->seg_pos ++; - pos->seg_byte_pos = 0; - c_info->offset = 0; - } - /* Allow escape from this loop on signal! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - TRACE(ft_t_noise, "\n" - KERN_INFO "remaining: %d\n" - KERN_INFO "seg_pos: %d\n" - KERN_INFO "end_seg: %d\n" - KERN_INFO "result: %d", - remaining, seg_pos, volume->end_seg, result); - } while (remaining > 0 && seg_pos <= volume->end_seg); - TRACE_EXIT 0; -} - -/* return segment id of next segment containing valid data, -EIO otherwise - */ -static int search_valid_segment(unsigned int segment, - const unsigned int end_seg, - const unsigned int max_foffs, - zft_position *pos, - cmpr_info *c_info, - const zft_volinfo *volume, - __u8 *buf) -{ - cmpr_info tmp_info; - int seg_sz; - TRACE_FUN(ft_t_flow); - - memset(&tmp_info, 0, sizeof(cmpr_info)); - while (segment <= end_seg) { - FT_SIGNAL_EXIT(_DONT_BLOCK); - TRACE(ft_t_noise, - "Searching readable segment between %d and %d", - segment, end_seg); - seg_sz = zft_fetch_segment(segment, buf, FT_RD_AHEAD); - if ((seg_sz > 0) && - (get_cseg (&tmp_info, buf, seg_sz, volume) >= 0) && - (tmp_info.foffs != 0 || segment == volume->start_seg)) { - if ((tmp_info.foffs>>10) > max_foffs) { - TRACE_ABORT(-EIO, ft_t_noise, "\n" - KERN_INFO "cseg.foff: %d\n" - KERN_INFO "dest : %d", - (int)(tmp_info.foffs >> 10), - max_foffs); - } - DUMP_CMPR_INFO(ft_t_noise, "", &tmp_info); - *c_info = tmp_info; - pos->seg_pos = segment; - pos->volume_pos = c_info->foffs; - pos->seg_byte_pos = c_info->offset; - TRACE(ft_t_noise, "found segment at %d", segment); - TRACE_EXIT 0; - } - segment++; - } - TRACE_EXIT -EIO; -} - -static int slow_seek_forward(unsigned int dest, - cmpr_info *c_info, - zft_position *pos, - const zft_volinfo *volume, - __u8 *buf) -{ - unsigned int distance; - int result = 0; - TRACE_FUN(ft_t_flow); - - distance = dest - (pos->volume_pos >> 10); - while ((distance > 0) && - (result = slow_seek_forward_until_error(distance, - c_info, - pos, - volume, - buf)) < 0) { - if (result == -EINTR) { - break; - } - TRACE(ft_t_noise, "seg_pos: %d", pos->seg_pos); - /* the failing segment is either pos->seg_pos or - * pos->seg_pos + 1. There is no need to further try - * that segment, because ftape_read_segment() already - * has tried very much to read it. So we start with - * following segment, which is pos->seg_pos + 1 - */ - if(search_valid_segment(pos->seg_pos+1, volume->end_seg, dest, - pos, c_info, - volume, buf) < 0) { - TRACE(ft_t_noise, "search_valid_segment() failed"); - result = -EIO; - break; - } - distance = dest - (pos->volume_pos >> 10); - result = 0; - TRACE(ft_t_noise, "segment: %d", pos->seg_pos); - /* found valid segment, retry the seek */ - } - TRACE_EXIT result; -} - -static int compute_seg_pos(const unsigned int dest, - zft_position *pos, - const zft_volinfo *volume) -{ - int segment; - int distance = dest - (pos->volume_pos >> 10); - unsigned int raw_size; - unsigned int virt_size; - unsigned int factor; - TRACE_FUN(ft_t_flow); - - if (distance >= 0) { - raw_size = volume->end_seg - pos->seg_pos + 1; - virt_size = ((unsigned int)(volume->size>>10) - - (unsigned int)(pos->volume_pos>>10) - + FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS - 1); - virt_size /= FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS; - if (virt_size == 0 || raw_size == 0) { - TRACE_EXIT 0; - } - if (raw_size >= (1<<25)) { - factor = raw_size/(virt_size>>7); - } else { - factor = (raw_size<<7)/virt_size; - } - segment = distance/(FT_SECTORS_PER_SEGMENT-FT_ECC_SECTORS); - segment = (segment * factor)>>7; - } else { - raw_size = pos->seg_pos - volume->start_seg + 1; - virt_size = ((unsigned int)(pos->volume_pos>>10) - + FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS - 1); - virt_size /= FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS; - if (virt_size == 0 || raw_size == 0) { - TRACE_EXIT 0; - } - if (raw_size >= (1<<25)) { - factor = raw_size/(virt_size>>7); - } else { - factor = (raw_size<<7)/virt_size; - } - segment = distance/(FT_SECTORS_PER_SEGMENT-FT_ECC_SECTORS); - } - TRACE(ft_t_noise, "factor: %d/%d", factor, 1<<7); - TRACE_EXIT segment; -} - -static struct zft_cmpr_ops cmpr_ops = { - zftc_write, - zftc_read, - zftc_seek, - zftc_lock, - zftc_reset, - zftc_cleanup -}; - -int zft_compressor_init(void) -{ - TRACE_FUN(ft_t_flow); - -#ifdef MODULE - printk(KERN_INFO "zftape compressor v1.00a 970514 for " FTAPE_VERSION "\n"); - if (TRACE_LEVEL >= ft_t_info) { - printk( -KERN_INFO "(c) 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n" -KERN_INFO "Compressor for zftape (lzrw3 algorithm)\n"); - } -#else /* !MODULE */ - /* print a short no-nonsense boot message */ - printk(KERN_INFO "zftape compressor v1.00a 970514\n"); - printk(KERN_INFO "For use with " FTAPE_VERSION "\n"); -#endif /* MODULE */ - TRACE(ft_t_info, "zft_compressor_init @ 0x%p", zft_compressor_init); - TRACE(ft_t_info, "installing compressor for zftape ..."); - TRACE_CATCH(zft_cmpr_register(&cmpr_ops),); - TRACE_EXIT 0; -} - -#ifdef MODULE - -MODULE_AUTHOR( - "(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de"); -MODULE_DESCRIPTION( -"Compression routines for zftape. Uses the lzrw3 algorithm by Ross Williams"); -MODULE_LICENSE("GPL"); - -/* Called by modules package when installing the driver - */ -int init_module(void) -{ - return zft_compressor_init(); -} - -#endif /* MODULE */ diff --git a/drivers/char/ftape/compressor/zftape-compress.h b/drivers/char/ftape/compressor/zftape-compress.h deleted file mode 100644 index f200741e33b..00000000000 --- a/drivers/char/ftape/compressor/zftape-compress.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef _ZFTAPE_COMPRESS_H -#define _ZFTAPE_COMPRESS_H -/* - * Copyright (c) 1994-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/compressor/zftape-compress.h,v $ - * $Revision: 1.1 $ - * $Date: 1997/10/05 19:12:32 $ - * - * This file contains macros and definitions for zftape's - * builtin compression code. - * - */ - -#include "../zftape/zftape-buffers.h" -#include "../zftape/zftape-vtbl.h" -#include "../compressor/lzrw3.h" - -/* CMPR_WRK_MEM_SIZE gives the size of the compression wrk_mem */ -/* I got these out of lzrw3.c */ -#define U(X) ((__u32) X) -#define SIZE_P_BYTE (U(sizeof(__u8 *))) -#define ALIGNMENT_FUDGE (U(16)) - -#define CMPR_WRK_MEM_SIZE (U(4096)*(SIZE_P_BYTE) + ALIGNMENT_FUDGE) - -/* the maximum number of bytes the size of the "compressed" data can - * exceed the uncompressed data. As it is quite useless to compress - * data twice it is sometimes the case that it is more efficient to - * copy a block of data but to feed it to the "compression" - * algorithm. In this case there are some flag bytes or the like - * proceding the "compressed" data. THAT MUST NOT BE THE CASE for the - * algorithm we use for this driver. Instead, the high bit 15 of - * compressed_size: - * - * compressed_size = ftape_compress() - * - * must be set in such a case. - * - * Nevertheless, it might also be as for lzrw3 that there is an - * "intermediate" overrun that exceeds the amount of the compressed - * data that is actually produced. During the algorithm we need in the - * worst case MAX_CMP_GROUP bytes more than the input-size. - */ -#define MAX_CMP_GROUP (2+16*2) /* from lzrw3.c */ - -#define CMPR_OVERRUN MAX_CMP_GROUP /* during compression */ - -/****************************************************/ - -#define CMPR_BUFFER_SIZE (MAX_BLOCK_SIZE + CMPR_OVERRUN) - -/* the compression map stores the byte offset compressed blocks within - * the current volume for catridges with format code 2,3 and 5 - * (and old versions of zftape) and the offset measured in kilobytes for - * format code 4 and 6. This gives us a possible max. size of a - * compressed volume of 1024*4GIG which should be enough. - */ -typedef __u32 CmprMap; - -/* globals - */ - -/* exported functions - */ - -#endif /* _ZFTAPE_COMPRESS_H */ diff --git a/drivers/char/ftape/lowlevel/Makefile b/drivers/char/ftape/lowlevel/Makefile deleted file mode 100644 index febab07ba42..00000000000 --- a/drivers/char/ftape/lowlevel/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -# -# Copyright (C) 1996, 1997 Clau-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/Makefile,v $ -# $Revision: 1.4 $ -# $Date: 1997/10/07 09:26:02 $ -# -# Makefile for the lowlevel part QIC-40/80/3010/3020 floppy-tape -# driver for Linux. -# - -obj-$(CONFIG_FTAPE) += ftape.o - -ftape-objs := ftape-init.o fdc-io.o fdc-isr.o \ - ftape-bsm.o ftape-ctl.o ftape-read.o ftape-rw.o \ - ftape-write.o ftape-io.o ftape-calibr.o ftape-ecc.o fc-10.o \ - ftape-buffer.o ftape-format.o ftape_syms.o - -ifeq ($(CONFIG_FTAPE),y) -ftape-objs += ftape-setup.o -endif - -ifndef CONFIG_FT_NO_TRACE_AT_ALL -ftape-objs += ftape-tracing.o -endif - -ifeq ($(CONFIG_FT_PROC_FS),y) -ftape-objs += ftape-proc.o -endif diff --git a/drivers/char/ftape/lowlevel/fc-10.c b/drivers/char/ftape/lowlevel/fc-10.c deleted file mode 100644 index 9bc1cddade7..00000000000 --- a/drivers/char/ftape/lowlevel/fc-10.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * - - Copyright (C) 1993,1994 Jon Tombs. - - 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. - - The entire guts of this program was written by dosemu, modified to - record reads and writes to the ports in the 0x180-0x188 address space, - while running the CMS program TAPE.EXE V2.0.5 supplied with the drive. - - Modified to use an array of addresses and generally cleaned up (made - much shorter) 4 June 94, dosemu isn't that good at writing short code it - would seem :-). Made independent of 0x180, but I doubt it will work - at any other address. - - Modified for distribution with ftape source. 21 June 94, SJL. - - Modifications on 20 October 95, by Daniel Cohen (catman@wpi.edu): - Modified to support different DMA, IRQ, and IO Ports. Borland's - Turbo Debugger in virtual 8086 mode (TD386.EXE with hardware breakpoints - provided by the TDH386.SYS Device Driver) was used on the CMS program - TAPE V4.0.5. I set breakpoints on I/O to ports 0x180-0x187. Note that - CMS's program will not successfully configure the tape drive if you set - breakpoints on IO Reads, but you can set them on IO Writes without problems. - Known problems: - - You can not use DMA Channels 5 or 7. - - Modification on 29 January 96, by Daniel Cohen (catman@wpi.edu): - Modified to only accept IRQs 3 - 7, or 9. Since we can only send a 3 bit - number representing the IRQ to the card, special handling is required when - IRQ 9 is selected. IRQ 2 and 9 are the same, and we should request IRQ 9 - from the kernel while telling the card to use IRQ 2. Thanks to Greg - Crider (gcrider@iclnet.org) for finding and locating this bug, as well as - testing the patch. - - Modification on 11 December 96, by Claus Heine (claus@momo.math.rwth-aachen.de): - Modified a little to use variahle ft_fdc_base, ft_fdc_irq, ft_fdc_dma - instead of preprocessor symbols. Thus we can compile this into the module - or kernel and let the user specify the options as command line arguments. - - * - * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fc-10.c,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:04 $ - * - * This file contains code for the CMS FC-10/FC-20 card. - */ - -#include -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/fc-10.h" - -static __u16 inbs_magic[] = { - 0x3, 0x3, 0x0, 0x4, 0x7, 0x2, 0x5, 0x3, 0x1, 0x4, - 0x3, 0x5, 0x2, 0x0, 0x3, 0x7, 0x4, 0x2, - 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 -}; - -static __u16 fc10_ports[] = { - 0x180, 0x210, 0x2A0, 0x300, 0x330, 0x340, 0x370 -}; - -int fc10_enable(void) -{ - int i; - __u8 cardConfig = 0x00; - __u8 x; - TRACE_FUN(ft_t_flow); - -/* This code will only work if the FC-10 (or FC-20) is set to - * use DMA channels 1, 2, or 3. DMA channels 5 and 7 seem to be - * initialized by the same command as channels 1 and 3, respectively. - */ - if (ft_fdc_dma > 3) { - TRACE_ABORT(0, ft_t_err, -"Error: The FC-10/20 must be set to use DMA channels 1, 2, or 3!"); - } -/* Only allow the FC-10/20 to use IRQ 3-7, or 9. Note that CMS's program - * only accepts IRQ's 2-7, but in linux, IRQ 2 is the same as IRQ 9. - */ - if (ft_fdc_irq < 3 || ft_fdc_irq == 8 || ft_fdc_irq > 9) { - TRACE_ABORT(0, ft_t_err, -"Error: The FC-10/20 must be set to use IRQ levels 3 - 7, or 9!\n" -KERN_INFO "Note: IRQ 9 is the same as IRQ 2"); - } - /* Clear state machine ??? - */ - for (i = 0; i < NR_ITEMS(inbs_magic); i++) { - inb(ft_fdc_base + inbs_magic[i]); - } - outb(0x0, ft_fdc_base); - - x = inb(ft_fdc_base); - if (x == 0x13 || x == 0x93) { - for (i = 1; i < 8; i++) { - if (inb(ft_fdc_base + i) != x) { - TRACE_EXIT 0; - } - } - } else { - TRACE_EXIT 0; - } - - outb(0x8, ft_fdc_base); - - for (i = 0; i < 8; i++) { - if (inb(ft_fdc_base + i) != 0x0) { - TRACE_EXIT 0; - } - } - outb(0x10, ft_fdc_base); - - for (i = 0; i < 8; i++) { - if (inb(ft_fdc_base + i) != 0xff) { - TRACE_EXIT 0; - } - } - - /* Okay, we found a FC-10 card ! ??? - */ - outb(0x0, fdc.ccr); - - /* Clear state machine again ??? - */ - for (i = 0; i < NR_ITEMS(inbs_magic); i++) { - inb(ft_fdc_base + inbs_magic[i]); - } - /* Send io port */ - for (i = 0; i < NR_ITEMS(fc10_ports); i++) - if (ft_fdc_base == fc10_ports[i]) - cardConfig = i + 1; - if (cardConfig == 0) { - TRACE_EXIT 0; /* Invalid I/O Port */ - } - /* and IRQ - If using IRQ 9, tell the FC card it is actually IRQ 2 */ - if (ft_fdc_irq != 9) - cardConfig |= ft_fdc_irq << 3; - else - cardConfig |= 2 << 3; - - /* and finally DMA Channel */ - cardConfig |= ft_fdc_dma << 6; - outb(cardConfig, ft_fdc_base); /* DMA [2 bits]/IRQ [3 bits]/BASE [3 bits] */ - - /* Enable FC-10 ??? - */ - outb(0, fdc.ccr); - outb(0, fdc.dor2); - outb(FDC_DMA_MODE /* 8 */, fdc.dor); - outb(FDC_DMA_MODE /* 8 */, fdc.dor); - outb(1, fdc.dor2); - - /************************************* - * - * cH: why the hell should this be necessary? This is done - * by fdc_reset()!!! - * - *************************************/ - /* Initialize fdc, select drive B: - */ - outb(FDC_DMA_MODE, fdc.dor); /* assert reset, dma & irq enabled */ - /* 0x08 */ - outb(FDC_DMA_MODE|FDC_RESET_NOT, fdc.dor); /* release reset */ - /* 0x08 | 0x04 = 0x0c */ - outb(FDC_DMA_MODE|FDC_RESET_NOT|FDC_MOTOR_1|FTAPE_SEL_B, fdc.dor); - /* 0x08 | 0x04 | 0x20 | 0x01 = 0x2d */ - /* select drive 1 */ /* why not drive 0 ???? */ - TRACE_EXIT (x == 0x93) ? 2 : 1; -} diff --git a/drivers/char/ftape/lowlevel/fc-10.h b/drivers/char/ftape/lowlevel/fc-10.h deleted file mode 100644 index da7b88bca88..00000000000 --- a/drivers/char/ftape/lowlevel/fc-10.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _FC_10_H -#define _FC_10_H - -/* - * Copyright (C) 1994-1996 Bas Laarhoven. - - 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/fc-10.h,v $ - * $Revision: 1.1 $ - * $Date: 1997/09/19 09:05:22 $ - * - * This file contains definitions for the FC-10 code - * of the QIC-40/80 floppy-tape driver for Linux. - */ - -/* - * fc-10.c defined global vars. - */ - -/* - * fc-10.c defined global functions. - */ -extern int fc10_enable(void); - -#endif diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c deleted file mode 100644 index bbcf918f056..00000000000 --- a/drivers/char/ftape/lowlevel/fdc-io.c +++ /dev/null @@ -1,1349 +0,0 @@ -/* - * 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/fdc-io.c,v $ - * $Revision: 1.7.4.2 $ - * $Date: 1997/11/16 14:48:17 $ - * - * This file contains the low-level floppy disk interface code - * for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for - * Linux. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/fdc-isr.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-calibr.h" -#include "../lowlevel/fc-10.h" - -/* Global vars. - */ -static int ftape_motor; -volatile int ftape_current_cylinder = -1; -volatile fdc_mode_enum fdc_mode = fdc_idle; -fdc_config_info fdc; -DECLARE_WAIT_QUEUE_HEAD(ftape_wait_intr); - -unsigned int ft_fdc_base = CONFIG_FT_FDC_BASE; -unsigned int ft_fdc_irq = CONFIG_FT_FDC_IRQ; -unsigned int ft_fdc_dma = CONFIG_FT_FDC_DMA; -unsigned int ft_fdc_threshold = CONFIG_FT_FDC_THR; /* bytes */ -unsigned int ft_fdc_rate_limit = CONFIG_FT_FDC_MAX_RATE; /* bits/sec */ -int ft_probe_fc10 = CONFIG_FT_PROBE_FC10; -int ft_mach2 = CONFIG_FT_MACH2; - -/* Local vars. - */ -static spinlock_t fdc_io_lock; -static unsigned int fdc_calibr_count; -static unsigned int fdc_calibr_time; -static int fdc_status; -volatile __u8 fdc_head; /* FDC head from sector id */ -volatile __u8 fdc_cyl; /* FDC track from sector id */ -volatile __u8 fdc_sect; /* FDC sector from sector id */ -static int fdc_data_rate = 500; /* data rate (Kbps) */ -static int fdc_rate_code; /* data rate code (0 == 500 Kbps) */ -static int fdc_seek_rate = 2; /* step rate (msec) */ -static void (*do_ftape) (void); -static int fdc_fifo_state; /* original fifo setting - fifo enabled */ -static int fdc_fifo_thr; /* original fifo setting - threshold */ -static int fdc_lock_state; /* original lock setting - locked */ -static int fdc_fifo_locked; /* has fifo && lock set ? */ -static __u8 fdc_precomp; /* default precomp. value (nsec) */ -static __u8 fdc_prec_code; /* fdc precomp. select code */ - -static char ftape_id[] = "ftape"; /* used by request irq and free irq */ - -static int fdc_set_seek_rate(int seek_rate); - -void fdc_catch_stray_interrupts(int count) -{ - unsigned long flags; - - spin_lock_irqsave(&fdc_io_lock, flags); - if (count == 0) { - ft_expected_stray_interrupts = 0; - } else { - ft_expected_stray_interrupts += count; - } - spin_unlock_irqrestore(&fdc_io_lock, flags); -} - -/* Wait during a timeout period for a given FDC status. - * If usecs == 0 then just test status, else wait at least for usecs. - * Returns -ETIME on timeout. Function must be calibrated first ! - */ -static int fdc_wait(unsigned int usecs, __u8 mask, __u8 state) -{ - int count_1 = (fdc_calibr_count * usecs + - fdc_calibr_count - 1) / fdc_calibr_time; - - do { - fdc_status = inb_p(fdc.msr); - if ((fdc_status & mask) == state) { - return 0; - } - } while (count_1-- >= 0); - return -ETIME; -} - -int fdc_ready_wait(unsigned int usecs) -{ - return fdc_wait(usecs, FDC_DATA_READY | FDC_BUSY, FDC_DATA_READY); -} - -/* Why can't we just use udelay()? - */ -static void fdc_usec_wait(unsigned int usecs) -{ - fdc_wait(usecs, 0, 1); /* will always timeout ! */ -} - -static int fdc_ready_out_wait(unsigned int usecs) -{ - fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ - return fdc_wait(usecs, FDC_DATA_OUT_READY, FDC_DATA_OUT_READY); -} - -void fdc_wait_calibrate(void) -{ - ftape_calibrate("fdc_wait", - fdc_usec_wait, &fdc_calibr_count, &fdc_calibr_time); -} - -/* Wait for a (short) while for the FDC to become ready - * and transfer the next command byte. - * Return -ETIME on timeout on getting ready (depends on hardware!). - */ -static int fdc_write(const __u8 data) -{ - fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ - if (fdc_wait(150, FDC_DATA_READY_MASK, FDC_DATA_IN_READY) < 0) { - return -ETIME; - } else { - outb(data, fdc.fifo); - return 0; - } -} - -/* Wait for a (short) while for the FDC to become ready - * and transfer the next result byte. - * Return -ETIME if timeout on getting ready (depends on hardware!). - */ -static int fdc_read(__u8 * data) -{ - fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ - if (fdc_wait(150, FDC_DATA_READY_MASK, FDC_DATA_OUT_READY) < 0) { - return -ETIME; - } else { - *data = inb(fdc.fifo); - return 0; - } -} - -/* Output a cmd_len long command string to the FDC. - * The FDC should be ready to receive a new command or - * an error (EBUSY or ETIME) will occur. - */ -int fdc_command(const __u8 * cmd_data, int cmd_len) -{ - int result = 0; - unsigned long flags; - int count = cmd_len; - int retry = 0; -#ifdef TESTING - static unsigned int last_time; - unsigned int time; -#endif - TRACE_FUN(ft_t_any); - - fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ - spin_lock_irqsave(&fdc_io_lock, flags); - if (!in_interrupt()) - /* Yes, I know, too much comments inside this function - * ... - * - * Yet another bug in the original driver. All that - * havoc is caused by the fact that the isr() sends - * itself a command to the floppy tape driver (pause, - * micro step pause). Now, the problem is that - * commands are transmitted via the fdc_seek - * command. But: the fdc performs seeks in the - * background i.e. it doesn't signal busy while - * sending the step pulses to the drive. Therefore the - * non-interrupt level driver has no chance to tell - * whether the isr() just has issued a seek. Therefore - * we HAVE TO have a look at the ft_hide_interrupt - * flag: it signals the non-interrupt level part of - * the driver that it has to wait for the fdc until it - * has completet seeking. - * - * THIS WAS PRESUMABLY THE REASON FOR ALL THAT - * "fdc_read timeout" errors, I HOPE :-) - */ - if (ft_hide_interrupt) { - restore_flags(flags); - TRACE(ft_t_info, - "Waiting for the isr() completing fdc_seek()"); - if (fdc_interrupt_wait(2 * FT_SECOND) < 0) { - TRACE(ft_t_warn, - "Warning: timeout waiting for isr() seek to complete"); - } - if (ft_hide_interrupt || !ft_seek_completed) { - /* There cannot be another - * interrupt. The isr() only stops - * the tape and the next interrupt - * won't come until we have send our - * command to the drive. - */ - TRACE_ABORT(-EIO, ft_t_bug, - "BUG? isr() is still seeking?\n" - KERN_INFO "hide: %d\n" - KERN_INFO "seek: %d", - ft_hide_interrupt, - ft_seek_completed); - - } - fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ - spin_lock_irqsave(&fdc_io_lock, flags); - } - fdc_status = inb(fdc.msr); - if ((fdc_status & FDC_DATA_READY_MASK) != FDC_DATA_IN_READY) { - spin_unlock_irqrestore(&fdc_io_lock, flags); - TRACE_ABORT(-EBUSY, ft_t_err, "fdc not ready"); - } - fdc_mode = *cmd_data; /* used by isr */ -#ifdef TESTING - if (fdc_mode == FDC_SEEK) { - time = ftape_timediff(last_time, ftape_timestamp()); - if (time < 6000) { - TRACE(ft_t_bug,"Warning: short timeout between seek commands: %d", - time); - } - } -#endif - if (!in_interrupt()) { - /* shouldn't be cleared if called from isr - */ - ft_interrupt_seen = 0; - } - while (count) { - result = fdc_write(*cmd_data); - if (result < 0) { - TRACE(ft_t_fdc_dma, - "fdc_mode = %02x, status = %02x at index %d", - (int) fdc_mode, (int) fdc_status, - cmd_len - count); - if (++retry <= 3) { - TRACE(ft_t_warn, "fdc_write timeout, retry"); - } else { - TRACE(ft_t_err, "fdc_write timeout, fatal"); - /* recover ??? */ - break; - } - } else { - --count; - ++cmd_data; - } - } -#ifdef TESTING - if (fdc_mode == FDC_SEEK) { - last_time = ftape_timestamp(); - } -#endif - spin_unlock_irqrestore(&fdc_io_lock, flags); - TRACE_EXIT result; -} - -/* Input a res_len long result string from the FDC. - * The FDC should be ready to send the result or an error - * (EBUSY or ETIME) will occur. - */ -int fdc_result(__u8 * res_data, int res_len) -{ - int result = 0; - unsigned long flags; - int count = res_len; - int retry = 0; - TRACE_FUN(ft_t_any); - - spin_lock_irqsave(&fdc_io_lock, flags); - fdc_status = inb(fdc.msr); - if ((fdc_status & FDC_DATA_READY_MASK) != FDC_DATA_OUT_READY) { - TRACE(ft_t_err, "fdc not ready"); - result = -EBUSY; - } else while (count) { - if (!(fdc_status & FDC_BUSY)) { - spin_unlock_irqrestore(&fdc_io_lock, flags); - TRACE_ABORT(-EIO, ft_t_err, "premature end of result phase"); - } - result = fdc_read(res_data); - if (result < 0) { - TRACE(ft_t_fdc_dma, - "fdc_mode = %02x, status = %02x at index %d", - (int) fdc_mode, - (int) fdc_status, - res_len - count); - if (++retry <= 3) { - TRACE(ft_t_warn, "fdc_read timeout, retry"); - } else { - TRACE(ft_t_err, "fdc_read timeout, fatal"); - /* recover ??? */ - break; - ++retry; - } - } else { - --count; - ++res_data; - } - } - spin_unlock_irqrestore(&fdc_io_lock, flags); - fdc_usec_wait(FT_RQM_DELAY); /* allow FDC to negate BSY */ - TRACE_EXIT result; -} - -/* Handle command and result phases for - * commands without data phase. - */ -static int fdc_issue_command(const __u8 * out_data, int out_count, - __u8 * in_data, int in_count) -{ - TRACE_FUN(ft_t_any); - - if (out_count > 0) { - TRACE_CATCH(fdc_command(out_data, out_count),); - } - /* will take 24 - 30 usec for fdc_sense_drive_status and - * fdc_sense_interrupt_status commands. - * 35 fails sometimes (5/9/93 SJL) - * On a loaded system it incidentally takes longer than - * this for the fdc to get ready ! ?????? WHY ?????? - * So until we know what's going on use a very long timeout. - */ - TRACE_CATCH(fdc_ready_out_wait(500 /* usec */),); - if (in_count > 0) { - TRACE_CATCH(fdc_result(in_data, in_count), - TRACE(ft_t_err, "result phase aborted")); - } - TRACE_EXIT 0; -} - -/* Wait for FDC interrupt with timeout (in milliseconds). - * Signals are blocked so the wait will not be aborted. - * Note: interrupts must be enabled ! (23/05/93 SJL) - */ -int fdc_interrupt_wait(unsigned int time) -{ - DECLARE_WAITQUEUE(wait,current); - sigset_t old_sigmask; - static int resetting; - long timeout; - - TRACE_FUN(ft_t_fdc_dma); - - if (waitqueue_active(&ftape_wait_intr)) { - TRACE_ABORT(-EIO, ft_t_err, "error: nested call"); - } - /* timeout time will be up to USPT microseconds too long ! */ - timeout = (1000 * time + FT_USPT - 1) / FT_USPT; - - spin_lock_irq(¤t->sighand->siglock); - old_sigmask = current->blocked; - sigfillset(¤t->blocked); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&ftape_wait_intr, &wait); - while (!ft_interrupt_seen && timeout) - timeout = schedule_timeout_interruptible(timeout); - - spin_lock_irq(¤t->sighand->siglock); - current->blocked = old_sigmask; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - remove_wait_queue(&ftape_wait_intr, &wait); - /* the following IS necessary. True: as well - * wake_up_interruptible() as the schedule() set TASK_RUNNING - * when they wakeup a task, BUT: it may very well be that - * ft_interrupt_seen is already set to 1 when we enter here - * in which case schedule() gets never called, and - * TASK_RUNNING never set. This has the funny effect that we - * execute all the code until we leave kernel space, but then - * the task is stopped (a task CANNOT be preempted while in - * kernel mode. Sending a pair of SIGSTOP/SIGCONT to the - * tasks wakes it up again. Funny! :-) - */ - current->state = TASK_RUNNING; - if (ft_interrupt_seen) { /* woken up by interrupt */ - ft_interrupt_seen = 0; - TRACE_EXIT 0; - } - /* Original comment: - * In first instance, next statement seems unnecessary since - * it will be cleared in fdc_command. However, a small part of - * the software seems to rely on this being cleared here - * (ftape_close might fail) so stick to it until things get fixed ! - */ - /* My deeply sought of knowledge: - * Behold NO! It is obvious. fdc_reset() doesn't call fdc_command() - * but nevertheless uses fdc_interrupt_wait(). OF COURSE this needs to - * be reset here. - */ - ft_interrupt_seen = 0; /* clear for next call */ - if (!resetting) { - resetting = 1; /* break infinite recursion if reset fails */ - TRACE(ft_t_any, "cleanup reset"); - fdc_reset(); - resetting = 0; - } - TRACE_EXIT (signal_pending(current)) ? -EINTR : -ETIME; -} - -/* Start/stop drive motor. Enable DMA mode. - */ -void fdc_motor(int motor) -{ - int unit = ft_drive_sel; - int data = unit | FDC_RESET_NOT | FDC_DMA_MODE; - TRACE_FUN(ft_t_any); - - ftape_motor = motor; - if (ftape_motor) { - data |= FDC_MOTOR_0 << unit; - TRACE(ft_t_noise, "turning motor %d on", unit); - } else { - TRACE(ft_t_noise, "turning motor %d off", unit); - } - if (ft_mach2) { - outb_p(data, fdc.dor2); - } else { - outb_p(data, fdc.dor); - } - ftape_sleep(10 * FT_MILLISECOND); - TRACE_EXIT; -} - -static void fdc_update_dsr(void) -{ - TRACE_FUN(ft_t_any); - - TRACE(ft_t_flow, "rate = %d Kbps, precomp = %d ns", - fdc_data_rate, fdc_precomp); - if (fdc.type >= i82077) { - outb_p((fdc_rate_code & 0x03) | fdc_prec_code, fdc.dsr); - } else { - outb_p(fdc_rate_code & 0x03, fdc.ccr); - } - TRACE_EXIT; -} - -void fdc_set_write_precomp(int precomp) -{ - TRACE_FUN(ft_t_any); - - TRACE(ft_t_noise, "New precomp: %d nsec", precomp); - fdc_precomp = precomp; - /* write precompensation can be set in multiples of 41.67 nsec. - * round the parameter to the nearest multiple and convert it - * into a fdc setting. Note that 0 means default to the fdc, - * 7 is used instead of that. - */ - fdc_prec_code = ((fdc_precomp + 21) / 42) << 2; - if (fdc_prec_code == 0 || fdc_prec_code > (6 << 2)) { - fdc_prec_code = 7 << 2; - } - fdc_update_dsr(); - TRACE_EXIT; -} - -/* Reprogram the 82078 registers to use Data Rate Table 1 on all drives. - */ -static void fdc_set_drive_specs(void) -{ - __u8 cmd[] = { FDC_DRIVE_SPEC, 0x00, 0x00, 0x00, 0x00, 0xc0}; - int result; - TRACE_FUN(ft_t_any); - - TRACE(ft_t_flow, "Setting of drive specs called"); - if (fdc.type >= i82078_1) { - cmd[1] = (0 << 5) | (2 << 2); - cmd[2] = (1 << 5) | (2 << 2); - cmd[3] = (2 << 5) | (2 << 2); - cmd[4] = (3 << 5) | (2 << 2); - result = fdc_command(cmd, NR_ITEMS(cmd)); - if (result < 0) { - TRACE(ft_t_err, "Setting of drive specs failed"); - } - } - TRACE_EXIT; -} - -/* Select clock for fdc, must correspond with tape drive setting ! - * This also influences the fdc timing so we must adjust some values. - */ -int fdc_set_data_rate(int rate) -{ - int bad_rate = 0; - TRACE_FUN(ft_t_any); - - /* Select clock for fdc, must correspond with tape drive setting ! - * This also influences the fdc timing so we must adjust some values. - */ - TRACE(ft_t_fdc_dma, "new rate = %d", rate); - switch (rate) { - case 250: - fdc_rate_code = fdc_data_rate_250; - break; - case 500: - fdc_rate_code = fdc_data_rate_500; - break; - case 1000: - if (fdc.type < i82077) { - bad_rate = 1; - } else { - fdc_rate_code = fdc_data_rate_1000; - } - break; - case 2000: - if (fdc.type < i82078_1) { - bad_rate = 1; - } else { - fdc_rate_code = fdc_data_rate_2000; - } - break; - default: - bad_rate = 1; - } - if (bad_rate) { - TRACE_ABORT(-EIO, - ft_t_fdc_dma, "%d is not a valid data rate", rate); - } - fdc_data_rate = rate; - fdc_update_dsr(); - fdc_set_seek_rate(fdc_seek_rate); /* clock changed! */ - ftape_udelay(1000); - TRACE_EXIT 0; -} - -/* keep the unit select if keep_select is != 0, - */ -static void fdc_dor_reset(int keep_select) -{ - __u8 fdc_ctl = ft_drive_sel; - - if (keep_select != 0) { - fdc_ctl |= FDC_DMA_MODE; - if (ftape_motor) { - fdc_ctl |= FDC_MOTOR_0 << ft_drive_sel; - } - } - ftape_udelay(10); /* ??? but seems to be necessary */ - if (ft_mach2) { - outb_p(fdc_ctl & 0x0f, fdc.dor); - outb_p(fdc_ctl, fdc.dor2); - } else { - outb_p(fdc_ctl, fdc.dor); - } - fdc_usec_wait(10); /* delay >= 14 fdc clocks */ - if (keep_select == 0) { - fdc_ctl = 0; - } - fdc_ctl |= FDC_RESET_NOT; - if (ft_mach2) { - outb_p(fdc_ctl & 0x0f, fdc.dor); - outb_p(fdc_ctl, fdc.dor2); - } else { - outb_p(fdc_ctl, fdc.dor); - } -} - -/* Reset the floppy disk controller. Leave the ftape_unit selected. - */ -void fdc_reset(void) -{ - int st0; - int i; - int dummy; - unsigned long flags; - TRACE_FUN(ft_t_any); - - spin_lock_irqsave(&fdc_io_lock, flags); - - fdc_dor_reset(1); /* keep unit selected */ - - fdc_mode = fdc_idle; - - /* maybe the spin_lock_irq* pair is not necessary, BUT: - * the following line MUST be here. Otherwise fdc_interrupt_wait() - * won't wait. Note that fdc_reset() is called from - * ftape_dumb_stop() when the fdc is busy transferring data. In this - * case fdc_isr() MOST PROBABLY sets ft_interrupt_seen, and tries - * to get the result bytes from the fdc etc. CLASH. - */ - ft_interrupt_seen = 0; - - /* Program data rate - */ - fdc_update_dsr(); /* restore data rate and precomp */ - - spin_unlock_irqrestore(&fdc_io_lock, flags); - - /* - * Wait for first polling cycle to complete - */ - if (fdc_interrupt_wait(1 * FT_SECOND) < 0) { - TRACE(ft_t_err, "no drive polling interrupt!"); - } else { /* clear all disk-changed statuses */ - for (i = 0; i < 4; ++i) { - if(fdc_sense_interrupt_status(&st0, &dummy) != 0) { - TRACE(ft_t_err, "sense failed for %d", i); - } - if (i == ft_drive_sel) { - ftape_current_cylinder = dummy; - } - } - TRACE(ft_t_noise, "drive polling completed"); - } - /* - * SPECIFY COMMAND - */ - fdc_set_seek_rate(fdc_seek_rate); - /* - * DRIVE SPECIFICATION COMMAND (if fdc type known) - */ - if (fdc.type >= i82078_1) { - fdc_set_drive_specs(); - } - TRACE_EXIT; -} - -#if !defined(CLK_48MHZ) -# define CLK_48MHZ 1 -#endif - -/* When we're done, put the fdc into reset mode so that the regular - * floppy disk driver will figure out that something is wrong and - * initialize the controller the way it wants. - */ -void fdc_disable(void) -{ - __u8 cmd1[] = {FDC_CONFIGURE, 0x00, 0x00, 0x00}; - __u8 cmd2[] = {FDC_LOCK}; - __u8 cmd3[] = {FDC_UNLOCK}; - __u8 stat[1]; - TRACE_FUN(ft_t_flow); - - if (!fdc_fifo_locked) { - fdc_reset(); - TRACE_EXIT; - } - if (fdc_issue_command(cmd3, 1, stat, 1) < 0 || stat[0] != 0x00) { - fdc_dor_reset(0); - TRACE_ABORT(/**/, ft_t_bug, - "couldn't unlock fifo, configuration remains changed"); - } - fdc_fifo_locked = 0; - if (CLK_48MHZ && fdc.type >= i82078) { - cmd1[0] |= FDC_CLK48_BIT; - } - cmd1[2] = ((fdc_fifo_state) ? 0 : 0x20) + (fdc_fifo_thr - 1); - if (fdc_command(cmd1, NR_ITEMS(cmd1)) < 0) { - fdc_dor_reset(0); - TRACE_ABORT(/**/, ft_t_bug, - "couldn't reconfigure fifo to old state"); - } - if (fdc_lock_state && - fdc_issue_command(cmd2, 1, stat, 1) < 0) { - fdc_dor_reset(0); - TRACE_ABORT(/**/, ft_t_bug, "couldn't lock old state again"); - } - TRACE(ft_t_noise, "fifo restored: %sabled, thr. %d, %slocked", - fdc_fifo_state ? "en" : "dis", - fdc_fifo_thr, (fdc_lock_state) ? "" : "not "); - fdc_dor_reset(0); - TRACE_EXIT; -} - -/* Specify FDC seek-rate (milliseconds) - */ -static int fdc_set_seek_rate(int seek_rate) -{ - /* set step rate, dma mode, and minimal head load and unload times - */ - __u8 in[3] = { FDC_SPECIFY, 1, (1 << 1)}; - - fdc_seek_rate = seek_rate; - in[1] |= (16 - (fdc_data_rate * fdc_seek_rate) / 500) << 4; - - return fdc_command(in, 3); -} - -/* Sense drive status: get unit's drive status (ST3) - */ -int fdc_sense_drive_status(int *st3) -{ - __u8 out[2]; - __u8 in[1]; - TRACE_FUN(ft_t_any); - - out[0] = FDC_SENSED; - out[1] = ft_drive_sel; - TRACE_CATCH(fdc_issue_command(out, 2, in, 1),); - *st3 = in[0]; - TRACE_EXIT 0; -} - -/* Sense Interrupt Status command: - * should be issued at the end of each seek. - * get ST0 and current cylinder. - */ -int fdc_sense_interrupt_status(int *st0, int *current_cylinder) -{ - __u8 out[1]; - __u8 in[2]; - TRACE_FUN(ft_t_any); - - out[0] = FDC_SENSEI; - TRACE_CATCH(fdc_issue_command(out, 1, in, 2),); - *st0 = in[0]; - *current_cylinder = in[1]; - TRACE_EXIT 0; -} - -/* step to track - */ -int fdc_seek(int track) -{ - __u8 out[3]; - int st0, pcn; -#ifdef TESTING - unsigned int time; -#endif - TRACE_FUN(ft_t_any); - - out[0] = FDC_SEEK; - out[1] = ft_drive_sel; - out[2] = track; -#ifdef TESTING - time = ftape_timestamp(); -#endif - /* We really need this command to work ! - */ - ft_seek_completed = 0; - TRACE_CATCH(fdc_command(out, 3), - fdc_reset(); - TRACE(ft_t_noise, "destination was: %d, resetting FDC...", - track)); - /* Handle interrupts until ft_seek_completed or timeout. - */ - for (;;) { - TRACE_CATCH(fdc_interrupt_wait(2 * FT_SECOND),); - if (ft_seek_completed) { - TRACE_CATCH(fdc_sense_interrupt_status(&st0, &pcn),); - if ((st0 & ST0_SEEK_END) == 0) { - TRACE_ABORT(-EIO, ft_t_err, - "no seek-end after seek completion !??"); - } - break; - } - } -#ifdef TESTING - time = ftape_timediff(time, ftape_timestamp()) / abs(track - ftape_current_cylinder); - if ((time < 900 || time > 3100) && abs(track - ftape_current_cylinder) > 5) { - TRACE(ft_t_warn, "Wrong FDC STEP interval: %d usecs (%d)", - time, track - ftape_current_cylinder); - } -#endif - /* Verify whether we issued the right tape command. - */ - /* Verify that we seek to the proper track. */ - if (pcn != track) { - TRACE_ABORT(-EIO, ft_t_err, "bad seek.."); - } - ftape_current_cylinder = track; - TRACE_EXIT 0; -} - -static int perpend_mode; /* set if fdc is in perpendicular mode */ - -static int perpend_off(void) -{ - __u8 perpend[] = {FDC_PERPEND, 0x00}; - TRACE_FUN(ft_t_any); - - if (perpend_mode) { - /* Turn off perpendicular mode */ - perpend[1] = 0x80; - TRACE_CATCH(fdc_command(perpend, 2), - TRACE(ft_t_err,"Perpendicular mode exit failed!")); - perpend_mode = 0; - } - TRACE_EXIT 0; -} - -static int handle_perpend(int segment_id) -{ - __u8 perpend[] = {FDC_PERPEND, 0x00}; - TRACE_FUN(ft_t_any); - - /* When writing QIC-3020 tapes, turn on perpendicular mode - * if tape is moving in forward direction (even tracks). - */ - if (ft_qic_std == QIC_TAPE_QIC3020 && - ((segment_id / ft_segments_per_track) & 1) == 0) { -/* FIXME: some i82077 seem to support perpendicular mode as - * well. - */ -#if 0 - if (fdc.type < i82077AA) {} -#else - if (fdc.type < i82077 && ft_data_rate < 1000) { -#endif - /* fdc does not support perpendicular mode: complain - */ - TRACE_ABORT(-EIO, ft_t_err, - "Your FDC does not support QIC-3020."); - } - perpend[1] = 0x03 /* 0x83 + (0x4 << ft_drive_sel) */ ; - TRACE_CATCH(fdc_command(perpend, 2), - TRACE(ft_t_err,"Perpendicular mode entry failed!")); - TRACE(ft_t_flow, "Perpendicular mode set"); - perpend_mode = 1; - TRACE_EXIT 0; - } - TRACE_EXIT perpend_off(); -} - -static inline void fdc_setup_dma(char mode, - volatile void *addr, unsigned int count) -{ - /* Program the DMA controller. - */ - disable_dma(fdc.dma); - clear_dma_ff(fdc.dma); - set_dma_mode(fdc.dma, mode); - set_dma_addr(fdc.dma, virt_to_bus((void*)addr)); - set_dma_count(fdc.dma, count); - enable_dma(fdc.dma); -} - -/* Setup fdc and dma for formatting the next segment - */ -int fdc_setup_formatting(buffer_struct * buff) -{ - unsigned long flags; - __u8 out[6] = { - FDC_FORMAT, 0x00, 3, 4 * FT_SECTORS_PER_SEGMENT, 0x00, 0x6b - }; - TRACE_FUN(ft_t_any); - - TRACE_CATCH(handle_perpend(buff->segment_id),); - /* Program the DMA controller. - */ - TRACE(ft_t_fdc_dma, - "phys. addr. = %lx", virt_to_bus((void*) buff->ptr)); - spin_lock_irqsave(&fdc_io_lock, flags); - fdc_setup_dma(DMA_MODE_WRITE, buff->ptr, FT_SECTORS_PER_SEGMENT * 4); - /* Issue FDC command to start reading/writing. - */ - out[1] = ft_drive_sel; - out[4] = buff->gap3; - TRACE_CATCH(fdc_setup_error = fdc_command(out, sizeof(out)), - restore_flags(flags); fdc_mode = fdc_idle); - spin_unlock_irqrestore(&fdc_io_lock, flags); - TRACE_EXIT 0; -} - - -/* Setup Floppy Disk Controller and DMA to read or write the next cluster - * of good sectors from or to the current segment. - */ -int fdc_setup_read_write(buffer_struct * buff, __u8 operation) -{ - unsigned long flags; - __u8 out[9]; - int dma_mode; - TRACE_FUN(ft_t_any); - - switch(operation) { - case FDC_VERIFY: - if (fdc.type < i82077) { - operation = FDC_READ; - } - case FDC_READ: - case FDC_READ_DELETED: - dma_mode = DMA_MODE_READ; - TRACE(ft_t_fdc_dma, "xfer %d sectors to 0x%p", - buff->sector_count, buff->ptr); - TRACE_CATCH(perpend_off(),); - break; - case FDC_WRITE_DELETED: - TRACE(ft_t_noise, "deleting segment %d", buff->segment_id); - case FDC_WRITE: - dma_mode = DMA_MODE_WRITE; - /* When writing QIC-3020 tapes, turn on perpendicular mode - * if tape is moving in forward direction (even tracks). - */ - TRACE_CATCH(handle_perpend(buff->segment_id),); - TRACE(ft_t_fdc_dma, "xfer %d sectors from 0x%p", - buff->sector_count, buff->ptr); - break; - default: - TRACE_ABORT(-EIO, - ft_t_bug, "bug: invalid operation parameter"); - } - TRACE(ft_t_fdc_dma, "phys. addr. = %lx",virt_to_bus((void*)buff->ptr)); - spin_lock_irqsave(&fdc_io_lock, flags); - if (operation != FDC_VERIFY) { - fdc_setup_dma(dma_mode, buff->ptr, - FT_SECTOR_SIZE * buff->sector_count); - } - /* Issue FDC command to start reading/writing. - */ - out[0] = operation; - out[1] = ft_drive_sel; - out[2] = buff->cyl; - out[3] = buff->head; - out[4] = buff->sect + buff->sector_offset; - out[5] = 3; /* Sector size of 1K. */ - out[6] = out[4] + buff->sector_count - 1; /* last sector */ - out[7] = 109; /* Gap length. */ - out[8] = 0xff; /* No limit to transfer size. */ - TRACE(ft_t_fdc_dma, "C: 0x%02x, H: 0x%02x, R: 0x%02x, cnt: 0x%02x", - out[2], out[3], out[4], out[6] - out[4] + 1); - spin_unlock_irqrestore(&fdc_io_lock, flags); - TRACE_CATCH(fdc_setup_error = fdc_command(out, 9),fdc_mode = fdc_idle); - TRACE_EXIT 0; -} - -int fdc_fifo_threshold(__u8 threshold, - int *fifo_state, int *lock_state, int *fifo_thr) -{ - const __u8 cmd0[] = {FDC_DUMPREGS}; - __u8 cmd1[] = {FDC_CONFIGURE, 0, (0x0f & (threshold - 1)), 0}; - const __u8 cmd2[] = {FDC_LOCK}; - const __u8 cmd3[] = {FDC_UNLOCK}; - __u8 reg[10]; - __u8 stat; - int i; - int result; - TRACE_FUN(ft_t_any); - - if (CLK_48MHZ && fdc.type >= i82078) { - cmd1[0] |= FDC_CLK48_BIT; - } - /* Dump fdc internal registers for examination - */ - TRACE_CATCH(fdc_command(cmd0, NR_ITEMS(cmd0)), - TRACE(ft_t_warn, "dumpreg cmd failed, fifo unchanged")); - /* Now read fdc internal registers from fifo - */ - for (i = 0; i < (int)NR_ITEMS(reg); ++i) { - fdc_read(®[i]); - TRACE(ft_t_fdc_dma, "Register %d = 0x%02x", i, reg[i]); - } - if (fifo_state && lock_state && fifo_thr) { - *fifo_state = (reg[8] & 0x20) == 0; - *lock_state = reg[7] & 0x80; - *fifo_thr = 1 + (reg[8] & 0x0f); - } - TRACE(ft_t_noise, - "original fifo state: %sabled, threshold %d, %slocked", - ((reg[8] & 0x20) == 0) ? "en" : "dis", - 1 + (reg[8] & 0x0f), (reg[7] & 0x80) ? "" : "not "); - /* If fdc is already locked, unlock it first ! */ - if (reg[7] & 0x80) { - fdc_ready_wait(100); - TRACE_CATCH(fdc_issue_command(cmd3, NR_ITEMS(cmd3), &stat, 1), - TRACE(ft_t_bug, "FDC unlock command failed, " - "configuration unchanged")); - } - fdc_fifo_locked = 0; - /* Enable fifo and set threshold at xx bytes to allow a - * reasonably large latency and reduce number of dma bursts. - */ - fdc_ready_wait(100); - if ((result = fdc_command(cmd1, NR_ITEMS(cmd1))) < 0) { - TRACE(ft_t_bug, "configure cmd failed, fifo unchanged"); - } - /* Now lock configuration so reset will not change it - */ - if(fdc_issue_command(cmd2, NR_ITEMS(cmd2), &stat, 1) < 0 || - stat != 0x10) { - TRACE_ABORT(-EIO, ft_t_bug, - "FDC lock command failed, stat = 0x%02x", stat); - } - fdc_fifo_locked = 1; - TRACE_EXIT result; -} - -static int fdc_fifo_enable(void) -{ - TRACE_FUN(ft_t_any); - - if (fdc_fifo_locked) { - TRACE_ABORT(0, ft_t_warn, "Fifo not enabled because locked"); - } - TRACE_CATCH(fdc_fifo_threshold(ft_fdc_threshold /* bytes */, - &fdc_fifo_state, - &fdc_lock_state, - &fdc_fifo_thr),); - TRACE_CATCH(fdc_fifo_threshold(ft_fdc_threshold /* bytes */, - NULL, NULL, NULL),); - TRACE_EXIT 0; -} - -/* Determine fd controller type - */ -static __u8 fdc_save_state[2]; - -static int fdc_probe(void) -{ - __u8 cmd[1]; - __u8 stat[16]; /* must be able to hold dumpregs & save results */ - int i; - TRACE_FUN(ft_t_any); - - /* Try to find out what kind of fd controller we have to deal with - * Scheme borrowed from floppy driver: - * first try if FDC_DUMPREGS command works - * (this indicates that we have a 82072 or better) - * then try the FDC_VERSION command (82072 doesn't support this) - * then try the FDC_UNLOCK command (some older 82077's don't support this) - * then try the FDC_PARTID command (82078's support this) - */ - cmd[0] = FDC_DUMPREGS; - if (fdc_issue_command(cmd, 1, stat, 1) != 0) { - TRACE_ABORT(no_fdc, ft_t_bug, "No FDC found"); - } - if (stat[0] == 0x80) { - /* invalid command: must be pre 82072 */ - TRACE_ABORT(i8272, - ft_t_warn, "Type 8272A/765A compatible FDC found"); - } - fdc_result(&stat[1], 9); - fdc_save_state[0] = stat[7]; - fdc_save_state[1] = stat[8]; - cmd[0] = FDC_VERSION; - if (fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] == 0x80) { - TRACE_ABORT(i8272, ft_t_warn, "Type 82072 FDC found"); - } - if (*stat != 0x90) { - TRACE_ABORT(i8272, ft_t_warn, "Unknown FDC found"); - } - cmd[0] = FDC_UNLOCK; - if(fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] != 0x00) { - TRACE_ABORT(i8272, ft_t_warn, - "Type pre-1991 82077 FDC found, " - "treating it like a 82072"); - } - if (fdc_save_state[0] & 0x80) { /* was locked */ - cmd[0] = FDC_LOCK; /* restore lock */ - (void)fdc_issue_command(cmd, 1, stat, 1); - TRACE(ft_t_warn, "FDC is already locked"); - } - /* Test for a i82078 FDC */ - cmd[0] = FDC_PARTID; - if (fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] == 0x80) { - /* invalid command: not a i82078xx type FDC */ - for (i = 0; i < 4; ++i) { - outb_p(i, fdc.tdr); - if ((inb_p(fdc.tdr) & 0x03) != i) { - TRACE_ABORT(i82077, - ft_t_warn, "Type 82077 FDC found"); - } - } - TRACE_ABORT(i82077AA, ft_t_warn, "Type 82077AA FDC found"); - } - /* FDC_PARTID cmd succeeded */ - switch (stat[0] >> 5) { - case 0x0: - /* i82078SL or i82078-1. The SL part cannot run at - * 2Mbps (the SL and -1 dies are identical; they are - * speed graded after production, according to Intel). - * Some SL's can be detected by doing a SAVE cmd and - * look at bit 7 of the first byte (the SEL3V# bit). - * If it is 0, the part runs off 3Volts, and hence it - * is a SL. - */ - cmd[0] = FDC_SAVE; - if(fdc_issue_command(cmd, 1, stat, 16) < 0) { - TRACE(ft_t_err, "FDC_SAVE failed. Dunno why"); - /* guess we better claim the fdc to be a i82078 */ - TRACE_ABORT(i82078, - ft_t_warn, - "Type i82078 FDC (i suppose) found"); - } - if ((stat[0] & FDC_SEL3V_BIT)) { - /* fdc running off 5Volts; Pray that it's a i82078-1 - */ - TRACE_ABORT(i82078_1, ft_t_warn, - "Type i82078-1 or 5Volt i82078SL FDC found"); - } - TRACE_ABORT(i82078, ft_t_warn, - "Type 3Volt i82078SL FDC (1Mbps) found"); - case 0x1: - case 0x2: /* S82078B */ - /* The '78B isn't '78 compatible. Detect it as a '77AA */ - TRACE_ABORT(i82077AA, ft_t_warn, "Type i82077AA FDC found"); - case 0x3: /* NSC PC8744 core; used in several super-IO chips */ - TRACE_ABORT(i82077AA, - ft_t_warn, "Type 82077AA compatible FDC found"); - default: - TRACE(ft_t_warn, "A previously undetected FDC found"); - TRACE_ABORT(i82077AA, ft_t_warn, - "Treating it as a 82077AA. Please report partid= %d", - stat[0]); - } /* switch(stat[ 0] >> 5) */ - TRACE_EXIT no_fdc; -} - -static int fdc_request_regions(void) -{ - TRACE_FUN(ft_t_flow); - - if (ft_mach2 || ft_probe_fc10) { - if (!request_region(fdc.sra, 8, "fdc (ft)")) { -#ifndef BROKEN_FLOPPY_DRIVER - TRACE_EXIT -EBUSY; -#else - TRACE(ft_t_warn, -"address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); -#endif - } - } else { - if (!request_region(fdc.sra, 6, "fdc (ft)")) { -#ifndef BROKEN_FLOPPY_DRIVER - TRACE_EXIT -EBUSY; -#else - TRACE(ft_t_warn, -"address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); -#endif - } - if (!request_region(fdc.sra + 7, 1, "fdc (ft)")) { -#ifndef BROKEN_FLOPPY_DRIVER - release_region(fdc.sra, 6); - TRACE_EXIT -EBUSY; -#else - TRACE(ft_t_warn, -"address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra + 7); -#endif - } - } - TRACE_EXIT 0; -} - -void fdc_release_regions(void) -{ - TRACE_FUN(ft_t_flow); - - if (fdc.sra != 0) { - if (fdc.dor2 != 0) { - release_region(fdc.sra, 8); - } else { - release_region(fdc.sra, 6); - release_region(fdc.dir, 1); - } - } - TRACE_EXIT; -} - -static int fdc_config_regs(unsigned int fdc_base, - unsigned int fdc_irq, - unsigned int fdc_dma) -{ - TRACE_FUN(ft_t_flow); - - fdc.irq = fdc_irq; - fdc.dma = fdc_dma; - fdc.sra = fdc_base; - fdc.srb = fdc_base + 1; - fdc.dor = fdc_base + 2; - fdc.tdr = fdc_base + 3; - fdc.msr = fdc.dsr = fdc_base + 4; - fdc.fifo = fdc_base + 5; - fdc.dir = fdc.ccr = fdc_base + 7; - fdc.dor2 = (ft_mach2 || ft_probe_fc10) ? fdc_base + 6 : 0; - TRACE_CATCH(fdc_request_regions(), fdc.sra = 0); - TRACE_EXIT 0; -} - -static int fdc_config(void) -{ - static int already_done; - TRACE_FUN(ft_t_any); - - if (already_done) { - TRACE_CATCH(fdc_request_regions(),); - *(fdc.hook) = fdc_isr; /* hook our handler in */ - TRACE_EXIT 0; - } - if (ft_probe_fc10) { - int fc_type; - - TRACE_CATCH(fdc_config_regs(ft_fdc_base, - ft_fdc_irq, ft_fdc_dma),); - fc_type = fc10_enable(); - if (fc_type != 0) { - TRACE(ft_t_warn, "FC-%c0 controller found", '0' + fc_type); - fdc.type = fc10; - fdc.hook = &do_ftape; - *(fdc.hook) = fdc_isr; /* hook our handler in */ - already_done = 1; - TRACE_EXIT 0; - } else { - TRACE(ft_t_warn, "FC-10/20 controller not found"); - fdc_release_regions(); - fdc.type = no_fdc; - ft_probe_fc10 = 0; - ft_fdc_base = 0x3f0; - ft_fdc_irq = 6; - ft_fdc_dma = 2; - } - } - TRACE(ft_t_warn, "fdc base: 0x%x, irq: %d, dma: %d", - ft_fdc_base, ft_fdc_irq, ft_fdc_dma); - TRACE_CATCH(fdc_config_regs(ft_fdc_base, ft_fdc_irq, ft_fdc_dma),); - fdc.hook = &do_ftape; - *(fdc.hook) = fdc_isr; /* hook our handler in */ - already_done = 1; - TRACE_EXIT 0; -} - -static irqreturn_t ftape_interrupt(int irq, void *dev_id) -{ - void (*handler) (void) = *fdc.hook; - int handled = 0; - TRACE_FUN(ft_t_any); - - *fdc.hook = NULL; - if (handler) { - handled = 1; - handler(); - } else { - TRACE(ft_t_bug, "Unexpected ftape interrupt"); - } - TRACE_EXIT IRQ_RETVAL(handled); -} - -static int fdc_grab_irq_and_dma(void) -{ - TRACE_FUN(ft_t_any); - - if (fdc.hook == &do_ftape) { - /* Get fast interrupt handler. - */ - if (request_irq(fdc.irq, ftape_interrupt, - IRQF_DISABLED, "ft", ftape_id)) { - TRACE_ABORT(-EIO, ft_t_bug, - "Unable to grab IRQ%d for ftape driver", - fdc.irq); - } - if (request_dma(fdc.dma, ftape_id)) { - free_irq(fdc.irq, ftape_id); - TRACE_ABORT(-EIO, ft_t_bug, - "Unable to grab DMA%d for ftape driver", - fdc.dma); - } - } - if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) { - /* Using same dma channel or irq as standard fdc, need - * to disable the dma-gate on the std fdc. This - * couldn't be done in the floppy driver as some - * laptops are using the dma-gate to enter a low power - * or even suspended state :-( - */ - outb_p(FDC_RESET_NOT, 0x3f2); - TRACE(ft_t_noise, "DMA-gate on standard fdc disabled"); - } - TRACE_EXIT 0; -} - -int fdc_release_irq_and_dma(void) -{ - TRACE_FUN(ft_t_any); - - if (fdc.hook == &do_ftape) { - disable_dma(fdc.dma); /* just in case... */ - free_dma(fdc.dma); - free_irq(fdc.irq, ftape_id); - } - if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) { - /* Using same dma channel as standard fdc, need to - * disable the dma-gate on the std fdc. This couldn't - * be done in the floppy driver as some laptops are - * using the dma-gate to enter a low power or even - * suspended state :-( - */ - outb_p(FDC_RESET_NOT | FDC_DMA_MODE, 0x3f2); - TRACE(ft_t_noise, "DMA-gate on standard fdc enabled again"); - } - TRACE_EXIT 0; -} - -int fdc_init(void) -{ - TRACE_FUN(ft_t_any); - - /* find a FDC to use */ - TRACE_CATCH(fdc_config(),); - TRACE_CATCH(fdc_grab_irq_and_dma(), fdc_release_regions()); - ftape_motor = 0; - fdc_catch_stray_interrupts(0); /* clear number of awainted - * stray interrupte - */ - fdc_catch_stray_interrupts(1); /* one always comes (?) */ - TRACE(ft_t_flow, "resetting fdc"); - fdc_set_seek_rate(2); /* use nominal QIC step rate */ - fdc_reset(); /* init fdc & clear track counters */ - if (fdc.type == no_fdc) { /* no FC-10 or FC-20 found */ - fdc.type = fdc_probe(); - fdc_reset(); /* update with new knowledge */ - } - if (fdc.type == no_fdc) { - fdc_release_irq_and_dma(); - fdc_release_regions(); - TRACE_EXIT -ENXIO; - } - if (fdc.type >= i82077) { - if (fdc_fifo_enable() < 0) { - TRACE(ft_t_warn, "couldn't enable fdc fifo !"); - } else { - TRACE(ft_t_flow, "fdc fifo enabled and locked"); - } - } - TRACE_EXIT 0; -} diff --git a/drivers/char/ftape/lowlevel/fdc-io.h b/drivers/char/ftape/lowlevel/fdc-io.h deleted file mode 100644 index 7ec3c72178b..00000000000 --- a/drivers/char/ftape/lowlevel/fdc-io.h +++ /dev/null @@ -1,252 +0,0 @@ -#ifndef _FDC_IO_H -#define _FDC_IO_H - -/* - * 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/fdc-io.h,v $ - * $Revision: 1.3 $ - * $Date: 1997/10/05 19:18:06 $ - * - * This file contains the declarations for the low level - * functions that communicate with the floppy disk controller, - * for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for - * Linux. - */ - -#include - -#include "../lowlevel/ftape-bsm.h" - -#define FDC_SK_BIT (0x20) -#define FDC_MT_BIT (0x80) - -#define FDC_READ (FD_READ & ~(FDC_SK_BIT | FDC_MT_BIT)) -#define FDC_WRITE (FD_WRITE & ~FDC_MT_BIT) -#define FDC_READ_DELETED (0x4c) -#define FDC_WRITE_DELETED (0x49) -#define FDC_VERIFY (0x56) -#define FDC_READID (0x4a) -#define FDC_SENSED (0x04) -#define FDC_SENSEI (FD_SENSEI) -#define FDC_FORMAT (FD_FORMAT) -#define FDC_RECAL (FD_RECALIBRATE) -#define FDC_SEEK (FD_SEEK) -#define FDC_SPECIFY (FD_SPECIFY) -#define FDC_RECALIBR (FD_RECALIBRATE) -#define FDC_VERSION (FD_VERSION) -#define FDC_PERPEND (FD_PERPENDICULAR) -#define FDC_DUMPREGS (FD_DUMPREGS) -#define FDC_LOCK (FD_LOCK) -#define FDC_UNLOCK (FD_UNLOCK) -#define FDC_CONFIGURE (FD_CONFIGURE) -#define FDC_DRIVE_SPEC (0x8e) /* i82078 has this (any others?) */ -#define FDC_PARTID (0x18) /* i82078 has this */ -#define FDC_SAVE (0x2e) /* i82078 has this (any others?) */ -#define FDC_RESTORE (0x4e) /* i82078 has this (any others?) */ - -#define FDC_STATUS_MASK (STATUS_BUSY | STATUS_DMA | STATUS_DIR | STATUS_READY) -#define FDC_DATA_READY (STATUS_READY) -#define FDC_DATA_OUTPUT (STATUS_DIR) -#define FDC_DATA_READY_MASK (STATUS_READY | STATUS_DIR) -#define FDC_DATA_OUT_READY (STATUS_READY | STATUS_DIR) -#define FDC_DATA_IN_READY (STATUS_READY) -#define FDC_BUSY (STATUS_BUSY) -#define FDC_CLK48_BIT (0x80) -#define FDC_SEL3V_BIT (0x40) - -#define ST0_INT_MASK (ST0_INTR) -#define FDC_INT_NORMAL (ST0_INTR & 0x00) -#define FDC_INT_ABNORMAL (ST0_INTR & 0x40) -#define FDC_INT_INVALID (ST0_INTR & 0x80) -#define FDC_INT_READYCH (ST0_INTR & 0xC0) -#define ST0_SEEK_END (ST0_SE) -#define ST3_TRACK_0 (ST3_TZ) - -#define FDC_RESET_NOT (0x04) -#define FDC_DMA_MODE (0x08) -#define FDC_MOTOR_0 (0x10) -#define FDC_MOTOR_1 (0x20) - -typedef struct { - void (**hook) (void); /* our wedge into the isr */ - enum { - no_fdc, i8272, i82077, i82077AA, fc10, - i82078, i82078_1 - } type; /* FDC type */ - unsigned int irq; /* FDC irq nr */ - unsigned int dma; /* FDC dma channel nr */ - __u16 sra; /* Status register A (PS/2 only) */ - __u16 srb; /* Status register B (PS/2 only) */ - __u16 dor; /* Digital output register */ - __u16 tdr; /* Tape Drive Register (82077SL-1 & - 82078 only) */ - __u16 msr; /* Main Status Register */ - __u16 dsr; /* Datarate Select Register (8207x only) */ - __u16 fifo; /* Data register / Fifo on 8207x */ - __u16 dir; /* Digital Input Register */ - __u16 ccr; /* Configuration Control Register */ - __u16 dor2; /* Alternate dor on MACH-2 controller, - also used with FC-10, meaning unknown */ -} fdc_config_info; - -typedef enum { - fdc_data_rate_250 = 2, - fdc_data_rate_300 = 1, /* any fdc in default configuration */ - fdc_data_rate_500 = 0, - fdc_data_rate_1000 = 3, - fdc_data_rate_2000 = 1, /* i82078-1: when using Data Rate Table #2 */ -} fdc_data_rate_type; - -typedef enum { - fdc_idle = 0, - fdc_reading_data = FDC_READ, - fdc_seeking = FDC_SEEK, - fdc_writing_data = FDC_WRITE, - fdc_deleting = FDC_WRITE_DELETED, - fdc_reading_id = FDC_READID, - fdc_recalibrating = FDC_RECAL, - fdc_formatting = FDC_FORMAT, - fdc_verifying = FDC_VERIFY -} fdc_mode_enum; - -typedef enum { - waiting = 0, - reading, - writing, - formatting, - verifying, - deleting, - done, - error, - mmapped, -} buffer_state_enum; - -typedef struct { - __u8 *address; - volatile buffer_state_enum status; - volatile __u8 *ptr; - volatile unsigned int bytes; - volatile unsigned int segment_id; - - /* bitmap for remainder of segment not yet handled. - * one bit set for each bad sector that must be skipped. - */ - volatile SectorMap bad_sector_map; - - /* bitmap with bad data blocks in data buffer. - * the errors in this map may be retried. - */ - volatile SectorMap soft_error_map; - - /* bitmap with bad data blocks in data buffer - * the errors in this map may not be retried. - */ - volatile SectorMap hard_error_map; - - /* retry counter for soft errors. - */ - volatile int retry; - - /* sectors to skip on retry ??? - */ - volatile unsigned int skip; - - /* nr of data blocks in data buffer - */ - volatile unsigned int data_offset; - - /* offset in segment for first sector to be handled. - */ - volatile unsigned int sector_offset; - - /* size of cluster of good sectors to be handled. - */ - volatile unsigned int sector_count; - - /* size of remaining part of segment to be handled. - */ - volatile unsigned int remaining; - - /* points to next segment (contiguous) to be handled, - * or is zero if no read-ahead is allowed. - */ - volatile unsigned int next_segment; - - /* flag being set if deleted data was read. - */ - volatile int deleted; - - /* floppy coordinates of first sector in segment */ - volatile __u8 head; - volatile __u8 cyl; - volatile __u8 sect; - - /* gap to use when formatting */ - __u8 gap3; - /* flag set when buffer is mmaped */ - int mmapped; -} buffer_struct; - -/* - * fdc-io.c defined public variables - */ -extern volatile fdc_mode_enum fdc_mode; -extern int fdc_setup_error; /* outdated ??? */ -extern wait_queue_head_t ftape_wait_intr; -extern volatile int ftape_current_cylinder; /* track nr FDC thinks we're on */ -extern volatile __u8 fdc_head; /* FDC head */ -extern volatile __u8 fdc_cyl; /* FDC track */ -extern volatile __u8 fdc_sect; /* FDC sector */ -extern fdc_config_info fdc; /* FDC hardware configuration */ - -extern unsigned int ft_fdc_base; -extern unsigned int ft_fdc_irq; -extern unsigned int ft_fdc_dma; -extern unsigned int ft_fdc_threshold; -extern unsigned int ft_fdc_rate_limit; -extern int ft_probe_fc10; -extern int ft_mach2; -/* - * fdc-io.c defined public functions - */ -extern void fdc_catch_stray_interrupts(int count); -extern int fdc_ready_wait(unsigned int timeout); -extern int fdc_command(const __u8 * cmd_data, int cmd_len); -extern int fdc_result(__u8 * res_data, int res_len); -extern int fdc_interrupt_wait(unsigned int time); -extern int fdc_seek(int track); -extern int fdc_sense_drive_status(int *st3); -extern void fdc_motor(int motor); -extern void fdc_reset(void); -extern void fdc_disable(void); -extern int fdc_fifo_threshold(__u8 threshold, - int *fifo_state, int *lock_state, int *fifo_thr); -extern void fdc_wait_calibrate(void); -extern int fdc_sense_interrupt_status(int *st0, int *current_cylinder); -extern void fdc_save_drive_specs(void); -extern void fdc_restore_drive_specs(void); -extern int fdc_set_data_rate(int rate); -extern void fdc_set_write_precomp(int precomp); -extern int fdc_release_irq_and_dma(void); -extern void fdc_release_regions(void); -extern int fdc_init(void); -extern int fdc_setup_read_write(buffer_struct * buff, __u8 operation); -extern int fdc_setup_formatting(buffer_struct * buff); -#endif diff --git a/drivers/char/ftape/lowlevel/fdc-isr.c b/drivers/char/ftape/lowlevel/fdc-isr.c deleted file mode 100644 index ad2bc733ae1..00000000000 --- a/drivers/char/ftape/lowlevel/fdc-isr.c +++ /dev/null @@ -1,1170 +0,0 @@ -/* - * Copyright (C) 1994-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/fdc-isr.c,v $ - * $Revision: 1.9 $ - * $Date: 1997/10/17 23:01:53 $ - * - * This file contains the interrupt service routine and - * associated code for the QIC-40/80/3010/3020 floppy-tape driver - * "ftape" for Linux. - */ - -#include -#include - -#define volatile /* */ - -#include -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/fdc-isr.h" -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-calibr.h" -#include "../lowlevel/ftape-bsm.h" - -/* Global vars. - */ -volatile int ft_expected_stray_interrupts; -volatile int ft_interrupt_seen; -volatile int ft_seek_completed; -volatile int ft_hide_interrupt; -/* Local vars. - */ -typedef enum { - no_error = 0, id_am_error = 0x01, id_crc_error = 0x02, - data_am_error = 0x04, data_crc_error = 0x08, - no_data_error = 0x10, overrun_error = 0x20, -} error_cause; -static int stop_read_ahead; - - -static void print_error_cause(int cause) -{ - TRACE_FUN(ft_t_any); - - switch (cause) { - case no_data_error: - TRACE(ft_t_noise, "no data error"); - break; - case id_am_error: - TRACE(ft_t_noise, "id am error"); - break; - case id_crc_error: - TRACE(ft_t_noise, "id crc error"); - break; - case data_am_error: - TRACE(ft_t_noise, "data am error"); - break; - case data_crc_error: - TRACE(ft_t_noise, "data crc error"); - break; - case overrun_error: - TRACE(ft_t_noise, "overrun error"); - break; - default:; - } - TRACE_EXIT; -} - -static char *fdc_mode_txt(fdc_mode_enum mode) -{ - switch (mode) { - case fdc_idle: - return "fdc_idle"; - case fdc_reading_data: - return "fdc_reading_data"; - case fdc_seeking: - return "fdc_seeking"; - case fdc_writing_data: - return "fdc_writing_data"; - case fdc_reading_id: - return "fdc_reading_id"; - case fdc_recalibrating: - return "fdc_recalibrating"; - case fdc_formatting: - return "fdc_formatting"; - case fdc_verifying: - return "fdc_verifying"; - default: - return "unknown"; - } -} - -static inline error_cause decode_irq_cause(fdc_mode_enum mode, __u8 st[]) -{ - error_cause cause = no_error; - TRACE_FUN(ft_t_any); - - /* Valid st[], decode cause of interrupt. - */ - switch (st[0] & ST0_INT_MASK) { - case FDC_INT_NORMAL: - TRACE(ft_t_fdc_dma,"normal completion: %s",fdc_mode_txt(mode)); - break; - case FDC_INT_ABNORMAL: - TRACE(ft_t_flow, "abnormal completion %s", fdc_mode_txt(mode)); - TRACE(ft_t_fdc_dma, "ST0: 0x%02x, ST1: 0x%02x, ST2: 0x%02x", - st[0], st[1], st[2]); - TRACE(ft_t_fdc_dma, - "C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x", - st[3], st[4], st[5], st[6]); - if (st[1] & 0x01) { - if (st[2] & 0x01) { - cause = data_am_error; - } else { - cause = id_am_error; - } - } else if (st[1] & 0x20) { - if (st[2] & 0x20) { - cause = data_crc_error; - } else { - cause = id_crc_error; - } - } else if (st[1] & 0x04) { - cause = no_data_error; - } else if (st[1] & 0x10) { - cause = overrun_error; - } - print_error_cause(cause); - break; - case FDC_INT_INVALID: - TRACE(ft_t_flow, "invalid completion %s", fdc_mode_txt(mode)); - break; - case FDC_INT_READYCH: - if (st[0] & ST0_SEEK_END) { - TRACE(ft_t_flow, "drive poll completed"); - } else { - TRACE(ft_t_flow, "ready change %s",fdc_mode_txt(mode)); - } - break; - default: - break; - } - TRACE_EXIT cause; -} - -static void update_history(error_cause cause) -{ - switch (cause) { - case id_am_error: - ft_history.id_am_errors++; - break; - case id_crc_error: - ft_history.id_crc_errors++; - break; - case data_am_error: - ft_history.data_am_errors++; - break; - case data_crc_error: - ft_history.data_crc_errors++; - break; - case overrun_error: - ft_history.overrun_errors++; - break; - case no_data_error: - ft_history.no_data_errors++; - break; - default:; - } -} - -static void skip_bad_sector(buffer_struct * buff) -{ - TRACE_FUN(ft_t_any); - - /* Mark sector as soft error and skip it - */ - if (buff->remaining > 0) { - ++buff->sector_offset; - ++buff->data_offset; - --buff->remaining; - buff->ptr += FT_SECTOR_SIZE; - buff->bad_sector_map >>= 1; - } else { - /* Hey, what is this????????????? C code: if we shift - * more than 31 bits, we get no shift. That's bad!!!!!! - */ - ++buff->sector_offset; /* hack for error maps */ - TRACE(ft_t_warn, "skipping last sector in segment"); - } - TRACE_EXIT; -} - -static void update_error_maps(buffer_struct * buff, unsigned int error_offset) -{ - int hard = 0; - TRACE_FUN(ft_t_any); - - if (buff->retry < FT_SOFT_RETRIES) { - buff->soft_error_map |= (1 << error_offset); - } else { - buff->hard_error_map |= (1 << error_offset); - buff->soft_error_map &= ~buff->hard_error_map; - buff->retry = -1; /* will be set to 0 in setup_segment */ - hard = 1; - } - TRACE(ft_t_noise, "sector %d : %s error\n" - KERN_INFO "hard map: 0x%08lx\n" - KERN_INFO "soft map: 0x%08lx", - FT_SECTOR(error_offset), hard ? "hard" : "soft", - (long) buff->hard_error_map, (long) buff->soft_error_map); - TRACE_EXIT; -} - -static void print_progress(buffer_struct *buff, error_cause cause) -{ - TRACE_FUN(ft_t_any); - - switch (cause) { - case no_error: - TRACE(ft_t_flow,"%d Sector(s) transferred", buff->sector_count); - break; - case no_data_error: - TRACE(ft_t_flow, "Sector %d not found", - FT_SECTOR(buff->sector_offset)); - break; - case overrun_error: - /* got an overrun error on the first byte, must be a - * hardware problem - */ - TRACE(ft_t_bug, - "Unexpected error: failing DMA or FDC controller ?"); - break; - case data_crc_error: - TRACE(ft_t_flow, "Error in sector %d", - FT_SECTOR(buff->sector_offset - 1)); - break; - case id_crc_error: - case id_am_error: - case data_am_error: - TRACE(ft_t_flow, "Error in sector %d", - FT_SECTOR(buff->sector_offset)); - break; - default: - TRACE(ft_t_flow, "Unexpected error at sector %d", - FT_SECTOR(buff->sector_offset)); - break; - } - TRACE_EXIT; -} - -/* - * Error cause: Amount xferred: Action: - * - * id_am_error 0 mark bad and skip - * id_crc_error 0 mark bad and skip - * data_am_error 0 mark bad and skip - * data_crc_error % 1024 mark bad and skip - * no_data_error 0 retry on write - * mark bad and skip on read - * overrun_error [ 0..all-1 ] mark bad and skip - * no_error all continue - */ - -/* the arg `sector' is returned by the fdc and tells us at which sector we - * are positioned at (relative to starting sector of segment) - */ -static void determine_verify_progress(buffer_struct *buff, - error_cause cause, - __u8 sector) -{ - TRACE_FUN(ft_t_any); - - if (cause == no_error && sector == 1) { - buff->sector_offset = FT_SECTORS_PER_SEGMENT; - buff->remaining = 0; - if (TRACE_LEVEL >= ft_t_flow) { - print_progress(buff, cause); - } - } else { - buff->sector_offset = sector - buff->sect; - buff->remaining = FT_SECTORS_PER_SEGMENT - buff->sector_offset; - TRACE(ft_t_noise, "%ssector offset: 0x%04x", - (cause == no_error) ? "unexpected " : "", - buff->sector_offset); - switch (cause) { - case overrun_error: - break; -#if 0 - case no_data_error: - buff->retry = FT_SOFT_RETRIES; - if (buff->hard_error_map && - buff->sector_offset > 1 && - (buff->hard_error_map & - (1 << (buff->sector_offset-2)))) { - buff->retry --; - } - break; -#endif - default: - buff->retry = FT_SOFT_RETRIES; - break; - } - if (TRACE_LEVEL >= ft_t_flow) { - print_progress(buff, cause); - } - /* Sector_offset points to the problem area Now adjust - * sector_offset so it always points one past he failing - * sector. I.e. skip the bad sector. - */ - ++buff->sector_offset; - --buff->remaining; - update_error_maps(buff, buff->sector_offset - 1); - } - TRACE_EXIT; -} - -static void determine_progress(buffer_struct *buff, - error_cause cause, - __u8 sector) -{ - unsigned int dma_residue; - TRACE_FUN(ft_t_any); - - /* Using less preferred order of disable_dma and - * get_dma_residue because this seems to fail on at least one - * system if reversed! - */ - dma_residue = get_dma_residue(fdc.dma); - disable_dma(fdc.dma); - if (cause != no_error || dma_residue != 0) { - TRACE(ft_t_noise, "%sDMA residue: 0x%04x", - (cause == no_error) ? "unexpected " : "", - dma_residue); - /* adjust to actual value: */ - if (dma_residue == 0) { - /* this happens sometimes with overrun errors. - * I don't know whether we could ignore the - * overrun error. Play save. - */ - buff->sector_count --; - } else { - buff->sector_count -= ((dma_residue + - (FT_SECTOR_SIZE - 1)) / - FT_SECTOR_SIZE); - } - } - /* Update var's influenced by the DMA operation. - */ - if (buff->sector_count > 0) { - buff->sector_offset += buff->sector_count; - buff->data_offset += buff->sector_count; - buff->ptr += (buff->sector_count * - FT_SECTOR_SIZE); - buff->remaining -= buff->sector_count; - buff->bad_sector_map >>= buff->sector_count; - } - if (TRACE_LEVEL >= ft_t_flow) { - print_progress(buff, cause); - } - if (cause != no_error) { - if (buff->remaining == 0) { - TRACE(ft_t_warn, "foo?\n" - KERN_INFO "count : %d\n" - KERN_INFO "offset: %d\n" - KERN_INFO "soft : %08x\n" - KERN_INFO "hard : %08x", - buff->sector_count, - buff->sector_offset, - buff->soft_error_map, - buff->hard_error_map); - } - /* Sector_offset points to the problem area, except if we got - * a data_crc_error. In that case it points one past the - * failing sector. - * - * Now adjust sector_offset so it always points one past he - * failing sector. I.e. skip the bad sector. - */ - if (cause != data_crc_error) { - skip_bad_sector(buff); - } - update_error_maps(buff, buff->sector_offset - 1); - } - TRACE_EXIT; -} - -static int calc_steps(int cmd) -{ - if (ftape_current_cylinder > cmd) { - return ftape_current_cylinder - cmd; - } else { - return ftape_current_cylinder + cmd; - } -} - -static void pause_tape(int retry, int mode) -{ - int result; - __u8 out[3] = {FDC_SEEK, ft_drive_sel, 0}; - TRACE_FUN(ft_t_any); - - /* We'll use a raw seek command to get the tape to rewind and - * stop for a retry. - */ - ++ft_history.rewinds; - if (qic117_cmds[ftape_current_command].non_intr) { - TRACE(ft_t_warn, "motion command may be issued too soon"); - } - if (retry && (mode == fdc_reading_data || - mode == fdc_reading_id || - mode == fdc_verifying)) { - ftape_current_command = QIC_MICRO_STEP_PAUSE; - ftape_might_be_off_track = 1; - } else { - ftape_current_command = QIC_PAUSE; - } - out[2] = calc_steps(ftape_current_command); - result = fdc_command(out, 3); /* issue QIC_117 command */ - ftape_current_cylinder = out[ 2]; - if (result < 0) { - TRACE(ft_t_noise, "qic-pause failed, status = %d", result); - } else { - ft_location.known = 0; - ft_runner_status = idle; - ft_hide_interrupt = 1; - ftape_tape_running = 0; - } - TRACE_EXIT; -} - -static void continue_xfer(buffer_struct *buff, - fdc_mode_enum mode, - unsigned int skip) -{ - int write = 0; - TRACE_FUN(ft_t_any); - - if (mode == fdc_writing_data || mode == fdc_deleting) { - write = 1; - } - /* This part can be removed if it never happens - */ - if (skip > 0 && - (ft_runner_status != running || - (write && (buff->status != writing)) || - (!write && (buff->status != reading && - buff->status != verifying)))) { - TRACE(ft_t_err, "unexpected runner/buffer state %d/%d", - ft_runner_status, buff->status); - buff->status = error; - /* finish this buffer: */ - (void)ftape_next_buffer(ft_queue_head); - ft_runner_status = aborting; - fdc_mode = fdc_idle; - } else if (buff->remaining > 0 && ftape_calc_next_cluster(buff) > 0) { - /* still sectors left in current segment, continue - * with this segment - */ - if (fdc_setup_read_write(buff, mode) < 0) { - /* failed, abort operation - */ - buff->bytes = buff->ptr - buff->address; - buff->status = error; - /* finish this buffer: */ - (void)ftape_next_buffer(ft_queue_head); - ft_runner_status = aborting; - fdc_mode = fdc_idle; - } - } else { - /* current segment completed - */ - unsigned int last_segment = buff->segment_id; - int eot = ((last_segment + 1) % ft_segments_per_track) == 0; - unsigned int next = buff->next_segment; /* 0 means stop ! */ - - buff->bytes = buff->ptr - buff->address; - buff->status = done; - buff = ftape_next_buffer(ft_queue_head); - if (eot) { - /* finished last segment on current track, - * can't continue - */ - ft_runner_status = logical_eot; - fdc_mode = fdc_idle; - TRACE_EXIT; - } - if (next <= 0) { - /* don't continue with next segment - */ - TRACE(ft_t_noise, "no %s allowed, stopping tape", - (write) ? "write next" : "read ahead"); - pause_tape(0, mode); - ft_runner_status = idle; /* not quite true until - * next irq - */ - TRACE_EXIT; - } - /* continue with next segment - */ - if (buff->status != waiting) { - TRACE(ft_t_noise, "all input buffers %s, pausing tape", - (write) ? "empty" : "full"); - pause_tape(0, mode); - ft_runner_status = idle; /* not quite true until - * next irq - */ - TRACE_EXIT; - } - if (write && next != buff->segment_id) { - TRACE(ft_t_noise, - "segments out of order, aborting write"); - ft_runner_status = do_abort; - fdc_mode = fdc_idle; - TRACE_EXIT; - } - ftape_setup_new_segment(buff, next, 0); - if (stop_read_ahead) { - buff->next_segment = 0; - stop_read_ahead = 0; - } - if (ftape_calc_next_cluster(buff) == 0 || - fdc_setup_read_write(buff, mode) != 0) { - TRACE(ft_t_err, "couldn't start %s-ahead", - write ? "write" : "read"); - ft_runner_status = do_abort; - fdc_mode = fdc_idle; - } else { - /* keep on going */ - switch (ft_driver_state) { - case reading: buff->status = reading; break; - case verifying: buff->status = verifying; break; - case writing: buff->status = writing; break; - case deleting: buff->status = deleting; break; - default: - TRACE(ft_t_err, - "BUG: ft_driver_state %d should be one out of " - "{reading, writing, verifying, deleting}", - ft_driver_state); - buff->status = write ? writing : reading; - break; - } - } - } - TRACE_EXIT; -} - -static void retry_sector(buffer_struct *buff, - int mode, - unsigned int skip) -{ - TRACE_FUN(ft_t_any); - - TRACE(ft_t_noise, "%s error, will retry", - (mode == fdc_writing_data || mode == fdc_deleting) ? "write" : "read"); - pause_tape(1, mode); - ft_runner_status = aborting; - buff->status = error; - buff->skip = skip; - TRACE_EXIT; -} - -static unsigned int find_resume_point(buffer_struct *buff) -{ - int i = 0; - SectorMap mask; - SectorMap map; - TRACE_FUN(ft_t_any); - - /* This function is to be called after all variables have been - * updated to point past the failing sector. - * If there are any soft errors before the failing sector, - * find the first soft error and return the sector offset. - * Otherwise find the last hard error. - * Note: there should always be at least one hard or soft error ! - */ - if (buff->sector_offset < 1 || buff->sector_offset > 32) { - TRACE(ft_t_bug, "BUG: sector_offset = %d", - buff->sector_offset); - TRACE_EXIT 0; - } - if (buff->sector_offset >= 32) { /* C-limitation on shift ! */ - mask = 0xffffffff; - } else { - mask = (1 << buff->sector_offset) - 1; - } - map = buff->soft_error_map & mask; - if (map) { - while ((map & (1 << i)) == 0) { - ++i; - } - TRACE(ft_t_noise, "at sector %d", FT_SECTOR(i)); - } else { - map = buff->hard_error_map & mask; - i = buff->sector_offset - 1; - if (map) { - while ((map & (1 << i)) == 0) { - --i; - } - TRACE(ft_t_noise, "after sector %d", FT_SECTOR(i)); - ++i; /* first sector after last hard error */ - } else { - TRACE(ft_t_bug, "BUG: no soft or hard errors"); - } - } - TRACE_EXIT i; -} - -/* check possible dma residue when formatting, update position record in - * buffer struct. This is, of course, modelled after determine_progress(), but - * we don't need to set up for retries because the format process cannot be - * interrupted (except at the end of the tape track). - */ -static int determine_fmt_progress(buffer_struct *buff, error_cause cause) -{ - unsigned int dma_residue; - TRACE_FUN(ft_t_any); - - /* Using less preferred order of disable_dma and - * get_dma_residue because this seems to fail on at least one - * system if reversed! - */ - dma_residue = get_dma_residue(fdc.dma); - disable_dma(fdc.dma); - if (cause != no_error || dma_residue != 0) { - TRACE(ft_t_info, "DMA residue = 0x%04x", dma_residue); - fdc_mode = fdc_idle; - switch(cause) { - case no_error: - ft_runner_status = aborting; - buff->status = idle; - break; - case overrun_error: - /* got an overrun error on the first byte, must be a - * hardware problem - */ - TRACE(ft_t_bug, - "Unexpected error: failing DMA controller ?"); - ft_runner_status = do_abort; - buff->status = error; - break; - default: - TRACE(ft_t_noise, "Unexpected error at segment %d", - buff->segment_id); - ft_runner_status = do_abort; - buff->status = error; - break; - } - TRACE_EXIT -EIO; /* can only retry entire track in format mode - */ - } - /* Update var's influenced by the DMA operation. - */ - buff->ptr += FT_SECTORS_PER_SEGMENT * 4; - buff->bytes -= FT_SECTORS_PER_SEGMENT * 4; - buff->remaining -= FT_SECTORS_PER_SEGMENT; - buff->segment_id ++; /* done with segment */ - TRACE_EXIT 0; -} - -/* - * Continue formatting, switch buffers if there is no data left in - * current buffer. This is, of course, modelled after - * continue_xfer(), but we don't need to set up for retries because - * the format process cannot be interrupted (except at the end of the - * tape track). - */ -static void continue_formatting(buffer_struct *buff) -{ - TRACE_FUN(ft_t_any); - - if (buff->remaining <= 0) { /* no space left in dma buffer */ - unsigned int next = buff->next_segment; - - if (next == 0) { /* end of tape track */ - buff->status = done; - ft_runner_status = logical_eot; - fdc_mode = fdc_idle; - TRACE(ft_t_noise, "Done formatting track %d", - ft_location.track); - TRACE_EXIT; - } - /* - * switch to next buffer! - */ - buff->status = done; - buff = ftape_next_buffer(ft_queue_head); - - if (buff->status != waiting || next != buff->segment_id) { - goto format_setup_error; - } - } - if (fdc_setup_formatting(buff) < 0) { - goto format_setup_error; - } - buff->status = formatting; - TRACE(ft_t_fdc_dma, "Formatting segment %d on track %d", - buff->segment_id, ft_location.track); - TRACE_EXIT; - format_setup_error: - ft_runner_status = do_abort; - fdc_mode = fdc_idle; - buff->status = error; - TRACE(ft_t_err, "Error setting up for segment %d on track %d", - buff->segment_id, ft_location.track); - TRACE_EXIT; - -} - -/* this handles writing, read id, reading and formatting - */ -static void handle_fdc_busy(buffer_struct *buff) -{ - static int no_data_error_count; - int retry = 0; - error_cause cause; - __u8 in[7]; - int skip; - fdc_mode_enum fmode = fdc_mode; - TRACE_FUN(ft_t_any); - - if (fdc_result(in, 7) < 0) { /* better get it fast ! */ - TRACE(ft_t_err, - "Probably fatal error during FDC Result Phase\n" - KERN_INFO - "drive may hang until (power on) reset :-("); - /* what to do next ???? - */ - TRACE_EXIT; - } - cause = decode_irq_cause(fdc_mode, in); -#ifdef TESTING - { int i; - for (i = 0; i < (int)ft_nr_buffers; ++i) - TRACE(ft_t_any, "buffer[%d] status: %d, segment_id: %d", - i, ft_buffer[i]->status, ft_buffer[i]->segment_id); - } -#endif - if (fmode == fdc_reading_data && ft_driver_state == verifying) { - fmode = fdc_verifying; - } - switch (fmode) { - case fdc_verifying: - if (ft_runner_status == aborting || - ft_runner_status == do_abort) { - TRACE(ft_t_noise,"aborting %s",fdc_mode_txt(fdc_mode)); - break; - } - if (buff->retry > 0) { - TRACE(ft_t_flow, "this is retry nr %d", buff->retry); - } - switch (cause) { - case no_error: - no_data_error_count = 0; - determine_verify_progress(buff, cause, in[5]); - if (in[2] & 0x40) { - /* This should not happen when verifying - */ - TRACE(ft_t_warn, - "deleted data in segment %d/%d", - buff->segment_id, - FT_SECTOR(buff->sector_offset - 1)); - buff->remaining = 0; /* abort transfer */ - buff->hard_error_map = EMPTY_SEGMENT; - skip = 1; - } else { - skip = 0; - } - continue_xfer(buff, fdc_mode, skip); - break; - case no_data_error: - no_data_error_count ++; - case overrun_error: - retry ++; - case id_am_error: - case id_crc_error: - case data_am_error: - case data_crc_error: - determine_verify_progress(buff, cause, in[5]); - if (cause == no_data_error) { - if (no_data_error_count >= 2) { - TRACE(ft_t_warn, - "retrying because of successive " - "no data errors"); - no_data_error_count = 0; - } else { - retry --; - } - } else { - no_data_error_count = 0; - } - if (retry) { - skip = find_resume_point(buff); - } else { - skip = buff->sector_offset; - } - if (retry && skip < 32) { - retry_sector(buff, fdc_mode, skip); - } else { - continue_xfer(buff, fdc_mode, skip); - } - update_history(cause); - break; - default: - /* Don't know why this could happen - * but find out. - */ - determine_verify_progress(buff, cause, in[5]); - retry_sector(buff, fdc_mode, 0); - TRACE(ft_t_err, "Error: unexpected error"); - break; - } - break; - case fdc_reading_data: -#ifdef TESTING - /* I'm sorry, but: NOBODY ever used this trace - * messages for ages. I guess that Bas was the last person - * that ever really used this (thank you, between the lines) - */ - if (cause == no_error) { - TRACE(ft_t_flow,"reading segment %d",buff->segment_id); - } else { - TRACE(ft_t_noise, "error reading segment %d", - buff->segment_id); - TRACE(ft_t_noise, "\n" - KERN_INFO - "IRQ:C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x\n" - KERN_INFO - "BUF:C: 0x%02x, H: 0x%02x, R: 0x%02x", - in[3], in[4], in[5], in[6], - buff->cyl, buff->head, buff->sect); - } -#endif - if (ft_runner_status == aborting || - ft_runner_status == do_abort) { - TRACE(ft_t_noise,"aborting %s",fdc_mode_txt(fdc_mode)); - break; - } - if (buff->bad_sector_map == FAKE_SEGMENT) { - /* This condition occurs when reading a `fake' - * sector that's not accessible. Doesn't - * really matter as we would have ignored it - * anyway ! - * - * Chance is that we're past the next segment - * now, so the next operation may fail and - * result in a retry. - */ - buff->remaining = 0; /* skip failing sector */ - /* buff->ptr = buff->address; */ - /* fake success: */ - continue_xfer(buff, fdc_mode, 1); - /* trace calls are expensive: place them AFTER - * the real stuff has been done. - * - */ - TRACE(ft_t_noise, "skipping empty segment %d (read), size? %d", - buff->segment_id, buff->ptr - buff->address); - TRACE_EXIT; - } - if (buff->retry > 0) { - TRACE(ft_t_flow, "this is retry nr %d", buff->retry); - } - switch (cause) { - case no_error: - determine_progress(buff, cause, in[5]); - if (in[2] & 0x40) { - /* Handle deleted data in header segments. - * Skip segment and force read-ahead. - */ - TRACE(ft_t_warn, - "deleted data in segment %d/%d", - buff->segment_id, - FT_SECTOR(buff->sector_offset - 1)); - buff->deleted = 1; - buff->remaining = 0;/*abort transfer */ - buff->soft_error_map |= - (-1L << buff->sector_offset); - if (buff->segment_id == 0) { - /* stop on next segment */ - stop_read_ahead = 1; - } - /* force read-ahead: */ - buff->next_segment = - buff->segment_id + 1; - skip = (FT_SECTORS_PER_SEGMENT - - buff->sector_offset); - } else { - skip = 0; - } - continue_xfer(buff, fdc_mode, skip); - break; - case no_data_error: - /* Tape started too far ahead of or behind the - * right sector. This may also happen in the - * middle of a segment ! - * - * Handle no-data as soft error. If next - * sector fails too, a retry (with needed - * reposition) will follow. - */ - retry ++; - case id_am_error: - case id_crc_error: - case data_am_error: - case data_crc_error: - case overrun_error: - retry += (buff->soft_error_map != 0 || - buff->hard_error_map != 0); - determine_progress(buff, cause, in[5]); -#if 1 || defined(TESTING) - if (cause == overrun_error) retry ++; -#endif - if (retry) { - skip = find_resume_point(buff); - } else { - skip = buff->sector_offset; - } - /* Try to resume with next sector on single - * errors (let ecc correct it), but retry on - * no_data (we'll be past the target when we - * get here so we cannot retry) or on - * multiple errors (reduce chance on ecc - * failure). - */ - /* cH: 23/02/97: if the last sector in the - * segment was a hard error, then there is - * no sense in a retry. This occasion seldom - * occurs but ... @:`@%&$ - */ - if (retry && skip < 32) { - retry_sector(buff, fdc_mode, skip); - } else { - continue_xfer(buff, fdc_mode, skip); - } - update_history(cause); - break; - default: - /* Don't know why this could happen - * but find out. - */ - determine_progress(buff, cause, in[5]); - retry_sector(buff, fdc_mode, 0); - TRACE(ft_t_err, "Error: unexpected error"); - break; - } - break; - case fdc_reading_id: - if (cause == no_error) { - fdc_cyl = in[3]; - fdc_head = in[4]; - fdc_sect = in[5]; - TRACE(ft_t_fdc_dma, - "id read: C: 0x%02x, H: 0x%02x, R: 0x%02x", - fdc_cyl, fdc_head, fdc_sect); - } else { /* no valid information, use invalid sector */ - fdc_cyl = fdc_head = fdc_sect = 0; - TRACE(ft_t_flow, "Didn't find valid sector Id"); - } - fdc_mode = fdc_idle; - break; - case fdc_deleting: - case fdc_writing_data: -#ifdef TESTING - if (cause == no_error) { - TRACE(ft_t_flow, "writing segment %d", buff->segment_id); - } else { - TRACE(ft_t_noise, "error writing segment %d", - buff->segment_id); - } -#endif - if (ft_runner_status == aborting || - ft_runner_status == do_abort) { - TRACE(ft_t_flow, "aborting %s",fdc_mode_txt(fdc_mode)); - break; - } - if (buff->retry > 0) { - TRACE(ft_t_flow, "this is retry nr %d", buff->retry); - } - if (buff->bad_sector_map == FAKE_SEGMENT) { - /* This condition occurs when trying to write to a - * `fake' sector that's not accessible. Doesn't really - * matter as it isn't used anyway ! Might be located - * at wrong segment, then we'll fail on the next - * segment. - */ - TRACE(ft_t_noise, "skipping empty segment (write)"); - buff->remaining = 0; /* skip failing sector */ - /* fake success: */ - continue_xfer(buff, fdc_mode, 1); - break; - } - switch (cause) { - case no_error: - determine_progress(buff, cause, in[5]); - continue_xfer(buff, fdc_mode, 0); - break; - case no_data_error: - case id_am_error: - case id_crc_error: - case data_am_error: - case overrun_error: - update_history(cause); - determine_progress(buff, cause, in[5]); - skip = find_resume_point(buff); - retry_sector(buff, fdc_mode, skip); - break; - default: - if (in[1] & 0x02) { - TRACE(ft_t_err, "media not writable"); - } else { - TRACE(ft_t_bug, "unforeseen write error"); - } - fdc_mode = fdc_idle; - break; - } - break; /* fdc_deleting || fdc_writing_data */ - case fdc_formatting: - /* The interrupt comes after formatting a segment. We then - * have to set up QUICKLY for the next segment. But - * afterwards, there is plenty of time. - */ - switch (cause) { - case no_error: - /* would like to keep most of the formatting stuff - * outside the isr code, but timing is too critical - */ - if (determine_fmt_progress(buff, cause) >= 0) { - continue_formatting(buff); - } - break; - case no_data_error: - case id_am_error: - case id_crc_error: - case data_am_error: - case overrun_error: - default: - determine_fmt_progress(buff, cause); - update_history(cause); - if (in[1] & 0x02) { - TRACE(ft_t_err, "media not writable"); - } else { - TRACE(ft_t_bug, "unforeseen write error"); - } - break; - } /* cause */ - break; - default: - TRACE(ft_t_warn, "Warning: unexpected irq during: %s", - fdc_mode_txt(fdc_mode)); - fdc_mode = fdc_idle; - break; - } - TRACE_EXIT; -} - -/* FDC interrupt service routine. - */ -void fdc_isr(void) -{ - static int isr_active; -#ifdef TESTING - unsigned int t0 = ftape_timestamp(); -#endif - TRACE_FUN(ft_t_any); - - if (isr_active++) { - --isr_active; - TRACE(ft_t_bug, "BUG: nested interrupt, not good !"); - *fdc.hook = fdc_isr; /* hook our handler into the fdc - * code again - */ - TRACE_EXIT; - } - sti(); - if (inb_p(fdc.msr) & FDC_BUSY) { /* Entering Result Phase */ - ft_hide_interrupt = 0; - handle_fdc_busy(ftape_get_buffer(ft_queue_head)); - if (ft_runner_status == do_abort) { - /* cease operation, remember tape position - */ - TRACE(ft_t_flow, "runner aborting"); - ft_runner_status = aborting; - ++ft_expected_stray_interrupts; - } - } else { /* !FDC_BUSY */ - /* clear interrupt, cause should be gotten by issuing - * a Sense Interrupt Status command. - */ - if (fdc_mode == fdc_recalibrating || fdc_mode == fdc_seeking) { - if (ft_hide_interrupt) { - int st0; - int pcn; - - if (fdc_sense_interrupt_status(&st0, &pcn) < 0) - TRACE(ft_t_err, - "sense interrupt status failed"); - ftape_current_cylinder = pcn; - TRACE(ft_t_flow, "handled hidden interrupt"); - } - ft_seek_completed = 1; - fdc_mode = fdc_idle; - } else if (!waitqueue_active(&ftape_wait_intr)) { - if (ft_expected_stray_interrupts == 0) { - TRACE(ft_t_warn, "unexpected stray interrupt"); - } else { - TRACE(ft_t_flow, "expected stray interrupt"); - --ft_expected_stray_interrupts; - } - } else { - if (fdc_mode == fdc_reading_data || - fdc_mode == fdc_verifying || - fdc_mode == fdc_writing_data || - fdc_mode == fdc_deleting || - fdc_mode == fdc_formatting || - fdc_mode == fdc_reading_id) { - if (inb_p(fdc.msr) & FDC_BUSY) { - TRACE(ft_t_bug, - "***** FDC failure, busy too late"); - } else { - TRACE(ft_t_bug, - "***** FDC failure, no busy"); - } - } else { - TRACE(ft_t_fdc_dma, "awaited stray interrupt"); - } - } - ft_hide_interrupt = 0; - } - /* Handle sleep code. - */ - if (!ft_hide_interrupt) { - ft_interrupt_seen ++; - if (waitqueue_active(&ftape_wait_intr)) { - wake_up_interruptible(&ftape_wait_intr); - } - } else { - TRACE(ft_t_flow, "hiding interrupt while %s", - waitqueue_active(&ftape_wait_intr) ? "waiting":"active"); - } -#ifdef TESTING - t0 = ftape_timediff(t0, ftape_timestamp()); - if (t0 >= 1000) { - /* only tell us about long calls */ - TRACE(ft_t_noise, "isr() duration: %5d usec", t0); - } -#endif - *fdc.hook = fdc_isr; /* hook our handler into the fdc code again */ - --isr_active; - TRACE_EXIT; -} diff --git a/drivers/char/ftape/lowlevel/fdc-isr.h b/drivers/char/ftape/lowlevel/fdc-isr.h deleted file mode 100644 index 065aa978942..00000000000 --- a/drivers/char/ftape/lowlevel/fdc-isr.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef _FDC_ISR_H -#define _FDC_ISR_H - -/* - * 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/fdc-isr.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:07 $ - * - * This file declares the global variables necessary to - * synchronize the interrupt service routine (isr) with the - * remainder of the QIC-40/80/3010/3020 floppy-tape driver - * "ftape" for Linux. - */ - -/* - * fdc-isr.c defined public variables - */ -extern volatile int ft_expected_stray_interrupts; /* masks stray interrupts */ -extern volatile int ft_seek_completed; /* flag set by isr */ -extern volatile int ft_interrupt_seen; /* flag set by isr */ -extern volatile int ft_hide_interrupt; /* flag set by isr */ - -/* - * fdc-io.c defined public functions - */ -extern void fdc_isr(void); - -/* - * A kernel hook that steals one interrupt from the floppy - * driver (Should be fixed when the new fdc driver gets ready) - * See the linux kernel source files: - * drivers/block/floppy.c & drivers/block/blk.h - * for the details. - */ -extern void (*do_floppy) (void); - -#endif diff --git a/drivers/char/ftape/lowlevel/ftape-bsm.c b/drivers/char/ftape/lowlevel/ftape-bsm.c deleted file mode 100644 index d1a301cc344..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-bsm.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Copyright (C) 1994-1996 Bas Laarhoven, - * (C) 1996-1997 Claus 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-bsm.c,v $ - * $Revision: 1.3 $ - * $Date: 1997/10/05 19:15:15 $ - * - * This file contains the bad-sector map handling code for - * the QIC-117 floppy tape driver for Linux. - * QIC-40, QIC-80, QIC-3010 and QIC-3020 maps are implemented. - */ - -#include - -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-bsm.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-rw.h" - -/* Global vars. - */ - -/* Local vars. - */ -static __u8 *bad_sector_map; -static SectorCount *bsm_hash_ptr; - -typedef enum { - forward, backward -} mode_type; - -#if 0 -static void ftape_put_bad_sector_entry(int segment_id, SectorMap new_map); -#endif - -#if 0 -/* fix_tape converts a normal QIC-80 tape into a 'wide' tape. - * For testing purposes only ! - */ -void fix_tape(__u8 * buffer, ft_format_type new_code) -{ - static __u8 list[BAD_SECTOR_MAP_SIZE]; - SectorMap *src_ptr = (SectorMap *) list; - __u8 *dst_ptr = bad_sector_map; - SectorMap map; - unsigned int sector = 1; - int i; - - if (format_code != fmt_var && format_code != fmt_big) { - memcpy(list, bad_sector_map, sizeof(list)); - memset(bad_sector_map, 0, sizeof(bad_sector_map)); - while ((__u8 *) src_ptr - list < sizeof(list)) { - map = *src_ptr++; - if (map == EMPTY_SEGMENT) { - *(SectorMap *) dst_ptr = 0x800000 + sector; - dst_ptr += 3; - sector += SECTORS_PER_SEGMENT; - } else { - for (i = 0; i < SECTORS_PER_SEGMENT; ++i) { - if (map & 1) { - *(SewctorMap *) dst_ptr = sector; - dst_ptr += 3; - } - map >>= 1; - ++sector; - } - } - } - } - bad_sector_map_changed = 1; - *(buffer + 4) = new_code; /* put new format code */ - if (format_code != fmt_var && new_code == fmt_big) { - PUT4(buffer, FT_6_HSEG_1, (__u32)GET2(buffer, 6)); - PUT4(buffer, FT_6_HSEG_2, (__u32)GET2(buffer, 8)); - PUT4(buffer, FT_6_FRST_SEG, (__u32)GET2(buffer, 10)); - PUT4(buffer, FT_6_LAST_SEG, (__u32)GET2(buffer, 12)); - memset(buffer+6, '\0', 8); - } - format_code = new_code; -} - -#endif - -/* given buffer that contains a header segment, find the end of - * of the bsm list - */ -__u8 * ftape_find_end_of_bsm_list(__u8 * address) -{ - __u8 *ptr = address + FT_HEADER_END; /* start of bsm list */ - __u8 *limit = address + FT_SEGMENT_SIZE; - while (ptr + 2 < limit) { - if (ptr[0] || ptr[1] || ptr[2]) { - ptr += 3; - } else { - return ptr; - } - } - return NULL; -} - -static inline void put_sector(SectorCount *ptr, unsigned int sector) -{ - ptr->bytes[0] = sector & 0xff; - sector >>= 8; - ptr->bytes[1] = sector & 0xff; - sector >>= 8; - ptr->bytes[2] = sector & 0xff; -} - -static inline unsigned int get_sector(SectorCount *ptr) -{ -#if 1 - unsigned int sector; - - sector = ptr->bytes[0]; - sector += ptr->bytes[1] << 8; - sector += ptr->bytes[2] << 16; - - return sector; -#else - /* GET4 gets the next four bytes in Intel little endian order - * and converts them to host byte order and handles unaligned - * access. - */ - return (GET4(ptr, 0) & 0x00ffffff); /* back to host byte order */ -#endif -} - -static void bsm_debug_fake(void) -{ - /* for testing of bad sector handling at end of tape - */ -#if 0 - ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 3, - 0x000003e0; - ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 2, - 0xff3fffff; - ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 1, - 0xffffe000; -#endif - /* Enable to test bad sector handling - */ -#if 0 - ftape_put_bad_sector_entry(30, 0xfffffffe) - ftape_put_bad_sector_entry(32, 0x7fffffff); - ftape_put_bad_sector_entry(34, 0xfffeffff); - ftape_put_bad_sector_entry(36, 0x55555555); - ftape_put_bad_sector_entry(38, 0xffffffff); - ftape_put_bad_sector_entry(50, 0xffff0000); - ftape_put_bad_sector_entry(51, 0xffffffff); - ftape_put_bad_sector_entry(52, 0xffffffff); - ftape_put_bad_sector_entry(53, 0x0000ffff); -#endif - /* Enable when testing multiple volume tar dumps. - */ -#if 0 - { - int i; - - for (i = ft_first_data_segment; - i <= ft_last_data_segment - 7; ++i) { - ftape_put_bad_sector_entry(i, EMPTY_SEGMENT); - } - } -#endif - /* Enable when testing bit positions in *_error_map - */ -#if 0 - { - int i; - - for (i = first_data_segment; i <= last_data_segment; ++i) { - ftape_put_bad_sector_entry(i, - ftape_get_bad_sector_entry(i) - | 0x00ff00ff); - } - } -#endif -} - -static void print_bad_sector_map(void) -{ - unsigned int good_sectors; - unsigned int total_bad = 0; - int i; - TRACE_FUN(ft_t_flow); - - if (ft_format_code == fmt_big || - ft_format_code == fmt_var || - ft_format_code == fmt_1100ft) { - SectorCount *ptr = (SectorCount *)bad_sector_map; - unsigned int sector; - __u16 *ptr16; - - while((sector = get_sector(ptr++)) != 0) { - if ((ft_format_code == fmt_big || - ft_format_code == fmt_var) && - sector & 0x800000) { - total_bad += FT_SECTORS_PER_SEGMENT - 3; - TRACE(ft_t_noise, "bad segment at sector: %6d", - sector & 0x7fffff); - } else { - ++total_bad; - TRACE(ft_t_noise, "bad sector: %6d", sector); - } - } - /* Display old ftape's end-of-file marks - */ - ptr16 = (__u16*)ptr; - while ((sector = get_unaligned(ptr16++)) != 0) { - TRACE(ft_t_noise, "Old ftape eof mark: %4d/%2d", - sector, get_unaligned(ptr16++)); - } - } else { /* fixed size format */ - for (i = ft_first_data_segment; - i < (int)(ft_segments_per_track * ft_tracks_per_tape); ++i) { - SectorMap map = ((SectorMap *) bad_sector_map)[i]; - - if (map) { - TRACE(ft_t_noise, - "bsm for segment %4d: 0x%08x", i, (unsigned int)map); - total_bad += ((map == EMPTY_SEGMENT) - ? FT_SECTORS_PER_SEGMENT - 3 - : count_ones(map)); - } - } - } - good_sectors = - ((ft_segments_per_track * ft_tracks_per_tape - ft_first_data_segment) - * (FT_SECTORS_PER_SEGMENT - 3)) - total_bad; - TRACE(ft_t_info, "%d Kb usable on this tape", good_sectors); - if (total_bad == 0) { - TRACE(ft_t_info, - "WARNING: this tape has no bad blocks registered !"); - } else { - TRACE(ft_t_info, "%d bad sectors", total_bad); - } - TRACE_EXIT; -} - - -void ftape_extract_bad_sector_map(__u8 * buffer) -{ - TRACE_FUN(ft_t_any); - - /* Fill the bad sector map with the contents of buffer. - */ - if (ft_format_code == fmt_var || ft_format_code == fmt_big) { - /* QIC-3010/3020 and wide QIC-80 tapes no longer have a failed - * sector log but use this area to extend the bad sector map. - */ - bad_sector_map = &buffer[FT_HEADER_END]; - } else { - /* non-wide QIC-80 tapes have a failed sector log area that - * mustn't be included in the bad sector map. - */ - bad_sector_map = &buffer[FT_FSL + FT_FSL_SIZE]; - } - if (ft_format_code == fmt_1100ft || - ft_format_code == fmt_var || - ft_format_code == fmt_big) { - bsm_hash_ptr = (SectorCount *)bad_sector_map; - } else { - bsm_hash_ptr = NULL; - } - bsm_debug_fake(); - if (TRACE_LEVEL >= ft_t_info) { - print_bad_sector_map(); - } - TRACE_EXIT; -} - -static inline SectorMap cvt2map(unsigned int sector) -{ - return 1 << (((sector & 0x7fffff) - 1) % FT_SECTORS_PER_SEGMENT); -} - -static inline int cvt2segment(unsigned int sector) -{ - return ((sector & 0x7fffff) - 1) / FT_SECTORS_PER_SEGMENT; -} - -static int forward_seek_entry(int segment_id, - SectorCount **ptr, - SectorMap *map) -{ - unsigned int sector; - int segment; - - do { - sector = get_sector((*ptr)++); - segment = cvt2segment(sector); - } while (sector != 0 && segment < segment_id); - (*ptr) --; /* point to first sector >= segment_id */ - /* Get all sectors in segment_id - */ - if (sector == 0 || segment != segment_id) { - *map = 0; - return 0; - } else if ((sector & 0x800000) && - (ft_format_code == fmt_var || ft_format_code == fmt_big)) { - *map = EMPTY_SEGMENT; - return FT_SECTORS_PER_SEGMENT; - } else { - int count = 1; - SectorCount *tmp_ptr = (*ptr) + 1; - - *map = cvt2map(sector); - while ((sector = get_sector(tmp_ptr++)) != 0 && - (segment = cvt2segment(sector)) == segment_id) { - *map |= cvt2map(sector); - ++count; - } - return count; - } -} - -static int backwards_seek_entry(int segment_id, - SectorCount **ptr, - SectorMap *map) -{ - unsigned int sector; - int segment; /* max unsigned int */ - - if (*ptr <= (SectorCount *)bad_sector_map) { - *map = 0; - return 0; - } - do { - sector = get_sector(--(*ptr)); - segment = cvt2segment(sector); - } while (*ptr > (SectorCount *)bad_sector_map && segment > segment_id); - if (segment > segment_id) { /* at start of list, no entry found */ - *map = 0; - return 0; - } else if (segment < segment_id) { - /* before smaller entry, adjust for overshoot */ - (*ptr) ++; - *map = 0; - return 0; - } else if ((sector & 0x800000) && - (ft_format_code == fmt_big || ft_format_code == fmt_var)) { - *map = EMPTY_SEGMENT; - return FT_SECTORS_PER_SEGMENT; - } else { /* get all sectors in segment_id */ - int count = 1; - - *map = cvt2map(sector); - while(*ptr > (SectorCount *)bad_sector_map) { - sector = get_sector(--(*ptr)); - segment = cvt2segment(sector); - if (segment != segment_id) { - break; - } - *map |= cvt2map(sector); - ++count; - } - if (segment < segment_id) { - (*ptr) ++; - } - return count; - } -} - -#if 0 -static void ftape_put_bad_sector_entry(int segment_id, SectorMap new_map) -{ - SectorCount *ptr = (SectorCount *)bad_sector_map; - int count; - int new_count; - SectorMap map; - TRACE_FUN(ft_t_any); - - if (ft_format_code == fmt_1100ft || - ft_format_code == fmt_var || - ft_format_code == fmt_big) { - count = forward_seek_entry(segment_id, &ptr, &map); - new_count = count_ones(new_map); - /* If format code == 4 put empty segment instead of 32 - * bad sectors. - */ - if (ft_format_code == fmt_var || ft_format_code == fmt_big) { - if (new_count == FT_SECTORS_PER_SEGMENT) { - new_count = 1; - } - if (count == FT_SECTORS_PER_SEGMENT) { - count = 1; - } - } - if (count != new_count) { - /* insert (or delete if < 0) new_count - count - * entries. Move trailing part of list - * including terminating 0. - */ - SectorCount *hi_ptr = ptr; - - do { - } while (get_sector(hi_ptr++) != 0); - /* Note: ptr is of type byte *, and each bad sector - * consumes 3 bytes. - */ - memmove(ptr + new_count, ptr + count, - (size_t)(hi_ptr - (ptr + count))*sizeof(SectorCount)); - } - TRACE(ft_t_noise, "putting map 0x%08x at %p, segment %d", - (unsigned int)new_map, ptr, segment_id); - if (new_count == 1 && new_map == EMPTY_SEGMENT) { - put_sector(ptr++, (0x800001 + - segment_id * - FT_SECTORS_PER_SEGMENT)); - } else { - int i = 0; - - while (new_map) { - if (new_map & 1) { - put_sector(ptr++, - 1 + segment_id * - FT_SECTORS_PER_SEGMENT + i); - } - ++i; - new_map >>= 1; - } - } - } else { - ((SectorMap *) bad_sector_map)[segment_id] = new_map; - } - TRACE_EXIT; -} -#endif /* 0 */ - -SectorMap ftape_get_bad_sector_entry(int segment_id) -{ - if (ft_used_header_segment == -1) { - /* When reading header segment we'll need a blank map. - */ - return 0; - } else if (bsm_hash_ptr != NULL) { - /* Invariants: - * map - mask value returned on last call. - * bsm_hash_ptr - points to first sector greater or equal to - * first sector in last_referenced segment. - * last_referenced - segment id used in the last call, - * sector and map belong to this id. - * This code is designed for sequential access and retries. - * For true random access it may have to be redesigned. - */ - static int last_reference = -1; - static SectorMap map; - - if (segment_id > last_reference) { - /* Skip all sectors before segment_id - */ - forward_seek_entry(segment_id, &bsm_hash_ptr, &map); - } else if (segment_id < last_reference) { - /* Skip backwards until begin of buffer or - * first sector in segment_id - */ - backwards_seek_entry(segment_id, &bsm_hash_ptr, &map); - } /* segment_id == last_reference : keep map */ - last_reference = segment_id; - return map; - } else { - return ((SectorMap *) bad_sector_map)[segment_id]; - } -} - -/* This is simply here to prevent us from overwriting other kernel - * data. Writes will result in NULL Pointer dereference. - */ -void ftape_init_bsm(void) -{ - bad_sector_map = NULL; - bsm_hash_ptr = NULL; -} diff --git a/drivers/char/ftape/lowlevel/ftape-bsm.h b/drivers/char/ftape/lowlevel/ftape-bsm.h deleted file mode 100644 index ed45465af4d..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-bsm.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef _FTAPE_BSM_H -#define _FTAPE_BSM_H - -/* - * Copyright (C) 1994-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-bsm.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:07 $ - * - * This file contains definitions for the bad sector map handling - * routines for the QIC-117 floppy-tape driver for Linux. - */ - -#include -#include - -#define EMPTY_SEGMENT (0xffffffff) -#define FAKE_SEGMENT (0xfffffffe) - -/* maximum (format code 4) bad sector map size (bytes). - */ -#define BAD_SECTOR_MAP_SIZE (29 * SECTOR_SIZE - 256) - -/* format code 4 bad sector entry, ftape uses this - * internally for all format codes - */ -typedef __u32 SectorMap; -/* variable and 1100 ft bad sector map entry. These three bytes represent - * a single sector address measured from BOT. - */ -typedef struct NewSectorMap { - __u8 bytes[3]; -} SectorCount; - - -/* - * ftape-bsm.c defined global vars. - */ - -/* - * ftape-bsm.c defined global functions. - */ -extern void update_bad_sector_map(__u8 * buffer); -extern void ftape_extract_bad_sector_map(__u8 * buffer); -extern SectorMap ftape_get_bad_sector_entry(int segment_id); -extern __u8 *ftape_find_end_of_bsm_list(__u8 * address); -extern void ftape_init_bsm(void); - -#endif diff --git a/drivers/char/ftape/lowlevel/ftape-buffer.c b/drivers/char/ftape/lowlevel/ftape-buffer.c deleted file mode 100644 index c706ff16277..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-buffer.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 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-buffer.c,v $ - * $Revision: 1.3 $ - * $Date: 1997/10/16 23:33:11 $ - * - * This file contains the allocator/dealloctor for ftape's dynamic dma - * buffer. - */ - -#include -#include -#include -#include - -#include -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-buffer.h" - -/* DMA'able memory allocation stuff. - */ - -static inline void *dmaalloc(size_t size) -{ - unsigned long addr; - - if (size == 0) { - return NULL; - } - addr = __get_dma_pages(GFP_KERNEL, get_order(size)); - if (addr) { - struct page *page; - - for (page = virt_to_page(addr); page < virt_to_page(addr+size); page++) - SetPageReserved(page); - } - return (void *)addr; -} - -static inline void dmafree(void *addr, size_t size) -{ - if (size > 0) { - struct page *page; - - for (page = virt_to_page((unsigned long)addr); - page < virt_to_page((unsigned long)addr+size); page++) - ClearPageReserved(page); - free_pages((unsigned long) addr, get_order(size)); - } -} - -static int add_one_buffer(void) -{ - TRACE_FUN(ft_t_flow); - - if (ft_nr_buffers >= FT_MAX_NR_BUFFERS) { - TRACE_EXIT -ENOMEM; - } - ft_buffer[ft_nr_buffers] = kmalloc(sizeof(buffer_struct), GFP_KERNEL); - if (ft_buffer[ft_nr_buffers] == NULL) { - TRACE_EXIT -ENOMEM; - } - memset(ft_buffer[ft_nr_buffers], 0, sizeof(buffer_struct)); - ft_buffer[ft_nr_buffers]->address = dmaalloc(FT_BUFF_SIZE); - if (ft_buffer[ft_nr_buffers]->address == NULL) { - kfree(ft_buffer[ft_nr_buffers]); - ft_buffer[ft_nr_buffers] = NULL; - TRACE_EXIT -ENOMEM; - } - ft_nr_buffers ++; - TRACE(ft_t_info, "buffer nr #%d @ %p, dma area @ %p", - ft_nr_buffers, - ft_buffer[ft_nr_buffers-1], - ft_buffer[ft_nr_buffers-1]->address); - TRACE_EXIT 0; -} - -static void del_one_buffer(void) -{ - TRACE_FUN(ft_t_flow); - if (ft_nr_buffers > 0) { - TRACE(ft_t_info, "releasing buffer nr #%d @ %p, dma area @ %p", - ft_nr_buffers, - ft_buffer[ft_nr_buffers-1], - ft_buffer[ft_nr_buffers-1]->address); - ft_nr_buffers --; - dmafree(ft_buffer[ft_nr_buffers]->address, FT_BUFF_SIZE); - kfree(ft_buffer[ft_nr_buffers]); - ft_buffer[ft_nr_buffers] = NULL; - } - TRACE_EXIT; -} - -int ftape_set_nr_buffers(int cnt) -{ - int delta = cnt - ft_nr_buffers; - TRACE_FUN(ft_t_flow); - - if (delta > 0) { - while (delta--) { - if (add_one_buffer() < 0) { - TRACE_EXIT -ENOMEM; - } - } - } else if (delta < 0) { - while (delta++) { - del_one_buffer(); - } - } - ftape_zap_read_buffers(); - TRACE_EXIT 0; -} diff --git a/drivers/char/ftape/lowlevel/ftape-buffer.h b/drivers/char/ftape/lowlevel/ftape-buffer.h deleted file mode 100644 index eec99cee8f8..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-buffer.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _FTAPE_BUFFER_H -#define _FTAPE_BUFFER_H - -/* - * Copyright (C) 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-buffer.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:08 $ - * - * This file contains the allocator/dealloctor for ftape's dynamic dma - * buffer. - */ - -extern int ftape_set_nr_buffers(int cnt); - -#endif diff --git a/drivers/char/ftape/lowlevel/ftape-calibr.c b/drivers/char/ftape/lowlevel/ftape-calibr.c deleted file mode 100644 index 8e50bfd35a5..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-calibr.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (C) 1993-1996 Bas Laarhoven. - - 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-calibr.c,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:08 $ - * - * GP calibration routine for processor speed dependent - * functions. - */ - -#include -#include -#include -#include -#if defined(__alpha__) -# include -#elif defined(__x86_64__) -# include -# include -#elif defined(__i386__) -# include -#endif -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-calibr.h" -#include "../lowlevel/fdc-io.h" - -#undef DEBUG - -#if !defined(__alpha__) && !defined(__i386__) && !defined(__x86_64__) -# error Ftape is not implemented for this architecture! -#endif - -#if defined(__alpha__) || defined(__x86_64__) -static unsigned long ps_per_cycle = 0; -#endif - -static spinlock_t calibr_lock; - -/* - * Note: On Intel PCs, the clock ticks at 100 Hz (HZ==100) which is - * too slow for certain timeouts (and that clock doesn't even tick - * when interrupts are disabled). For that reason, the 8254 timer is - * used directly to implement fine-grained timeouts. However, on - * Alpha PCs, the 8254 is *not* used to implement the clock tick - * (which is 1024 Hz, normally) and the 8254 timer runs at some - * "random" frequency (it seems to run at 18Hz, but it's not safe to - * rely on this value). Instead, we use the Alpha's "rpcc" - * instruction to read cycle counts. As this is a 32 bit counter, - * it will overflow only once per 30 seconds (on a 200MHz machine), - * which is plenty. - */ - -unsigned int ftape_timestamp(void) -{ -#if defined(__alpha__) - unsigned long r; - - asm volatile ("rpcc %0" : "=r" (r)); - return r; -#elif defined(__x86_64__) - unsigned long r; - rdtscl(r); - return r; -#elif defined(__i386__) - -/* - * Note that there is some time between counter underflowing and jiffies - * increasing, so the code below won't always give correct output. - * -Vojtech - */ - - unsigned long flags; - __u16 lo; - __u16 hi; - - spin_lock_irqsave(&calibr_lock, flags); - outb_p(0x00, 0x43); /* latch the count ASAP */ - lo = inb_p(0x40); /* read the latched count */ - lo |= inb(0x40) << 8; - hi = jiffies; - spin_unlock_irqrestore(&calibr_lock, flags); - return ((hi + 1) * (unsigned int) LATCH) - lo; /* downcounter ! */ -#endif -} - -static unsigned int short_ftape_timestamp(void) -{ -#if defined(__alpha__) || defined(__x86_64__) - return ftape_timestamp(); -#elif defined(__i386__) - unsigned int count; - unsigned long flags; - - spin_lock_irqsave(&calibr_lock, flags); - outb_p(0x00, 0x43); /* latch the count ASAP */ - count = inb_p(0x40); /* read the latched count */ - count |= inb(0x40) << 8; - spin_unlock_irqrestore(&calibr_lock, flags); - return (LATCH - count); /* normal: downcounter */ -#endif -} - -static unsigned int diff(unsigned int t0, unsigned int t1) -{ -#if defined(__alpha__) || defined(__x86_64__) - return (t1 - t0); -#elif defined(__i386__) - /* - * This is tricky: to work for both short and full ftape_timestamps - * we'll have to discriminate between these. - * If it _looks_ like short stamps with wrapping around we'll - * asume it are. This will generate a small error if it really - * was a (very large) delta from full ftape_timestamps. - */ - return (t1 <= t0 && t0 <= LATCH) ? t1 + LATCH - t0 : t1 - t0; -#endif -} - -static unsigned int usecs(unsigned int count) -{ -#if defined(__alpha__) || defined(__x86_64__) - return (ps_per_cycle * count) / 1000000UL; -#elif defined(__i386__) - return (10000 * count) / ((CLOCK_TICK_RATE + 50) / 100); -#endif -} - -unsigned int ftape_timediff(unsigned int t0, unsigned int t1) -{ - /* - * Calculate difference in usec for ftape_timestamp results t0 & t1. - * Note that on the i386 platform with short time-stamps, the - * maximum allowed timespan is 1/HZ or we'll lose ticks! - */ - return usecs(diff(t0, t1)); -} - -/* To get an indication of the I/O performance, - * measure the duration of the inb() function. - */ -static void time_inb(void) -{ - int i; - int t0, t1; - unsigned long flags; - int status; - TRACE_FUN(ft_t_any); - - spin_lock_irqsave(&calibr_lock, flags); - t0 = short_ftape_timestamp(); - for (i = 0; i < 1000; ++i) { - status = inb(fdc.msr); - } - t1 = short_ftape_timestamp(); - spin_unlock_irqrestore(&calibr_lock, flags); - TRACE(ft_t_info, "inb() duration: %d nsec", ftape_timediff(t0, t1)); - TRACE_EXIT; -} - -static void init_clock(void) -{ - TRACE_FUN(ft_t_any); - -#if defined(__x86_64__) - ps_per_cycle = 1000000000UL / cpu_khz; -#elif defined(__alpha__) - extern struct hwrpb_struct *hwrpb; - ps_per_cycle = (1000*1000*1000*1000UL) / hwrpb->cycle_freq; -#endif - TRACE_EXIT; -} - -/* - * Input: function taking int count as parameter. - * pointers to calculated calibration variables. - */ -void ftape_calibrate(char *name, - void (*fun) (unsigned int), - unsigned int *calibr_count, - unsigned int *calibr_time) -{ - static int first_time = 1; - int i; - unsigned int tc = 0; - unsigned int count; - unsigned int time; -#if defined(__i386__) - unsigned int old_tc = 0; - unsigned int old_count = 1; - unsigned int old_time = 1; -#endif - TRACE_FUN(ft_t_flow); - - if (first_time) { /* get idea of I/O performance */ - init_clock(); - time_inb(); - first_time = 0; - } - /* value of timeout must be set so that on very slow systems - * it will give a time less than one jiffy, and on - * very fast systems it'll give reasonable precision. - */ - - count = 40; - for (i = 0; i < 15; ++i) { - unsigned int t0; - unsigned int t1; - unsigned int once; - unsigned int multiple; - unsigned long flags; - - *calibr_count = - *calibr_time = count; /* set TC to 1 */ - spin_lock_irqsave(&calibr_lock, flags); - fun(0); /* dummy, get code into cache */ - t0 = short_ftape_timestamp(); - fun(0); /* overhead + one test */ - t1 = short_ftape_timestamp(); - once = diff(t0, t1); - t0 = short_ftape_timestamp(); - fun(count); /* overhead + count tests */ - t1 = short_ftape_timestamp(); - multiple = diff(t0, t1); - spin_unlock_irqrestore(&calibr_lock, flags); - time = ftape_timediff(0, multiple - once); - tc = (1000 * time) / (count - 1); - TRACE(ft_t_any, "once:%3d us,%6d times:%6d us, TC:%5d ns", - usecs(once), count - 1, usecs(multiple), tc); -#if defined(__alpha__) || defined(__x86_64__) - /* - * Increase the calibration count exponentially until the - * calibration time exceeds 100 ms. - */ - if (time >= 100*1000) { - break; - } -#elif defined(__i386__) - /* - * increase the count until the resulting time nears 2/HZ, - * then the tc will drop sharply because we lose LATCH counts. - */ - if (tc <= old_tc / 2) { - time = old_time; - count = old_count; - break; - } - old_tc = tc; - old_count = count; - old_time = time; -#endif - count *= 2; - } - *calibr_count = count - 1; - *calibr_time = time; - TRACE(ft_t_info, "TC for `%s()' = %d nsec (at %d counts)", - name, (1000 * *calibr_time) / *calibr_count, *calibr_count); - TRACE_EXIT; -} diff --git a/drivers/char/ftape/lowlevel/ftape-calibr.h b/drivers/char/ftape/lowlevel/ftape-calibr.h deleted file mode 100644 index 0c7e75246c7..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-calibr.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef _FTAPE_CALIBR_H -#define _FTAPE_CALIBR_H - -/* - * Copyright (C) 1993-1996 Bas Laarhoven. - - 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-calibr.h,v $ - * $Revision: 1.1 $ - * $Date: 1997/09/19 09:05:26 $ - * - * This file contains a gp calibration routine for - * hardware dependent timeout functions. - */ - -extern void ftape_calibrate(char *name, - void (*fun) (unsigned int), - unsigned int *calibr_count, - unsigned int *calibr_time); -extern unsigned int ftape_timestamp(void); -extern unsigned int ftape_timediff(unsigned int t0, unsigned int t1); - -#endif /* _FTAPE_CALIBR_H */ diff --git a/drivers/char/ftape/lowlevel/ftape-ctl.c b/drivers/char/ftape/lowlevel/ftape-ctl.c deleted file mode 100644 index 5d7c1ce92d5..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-ctl.c +++ /dev/null @@ -1,896 +0,0 @@ -/* - * Copyright (C) 1993-1996 Bas Laarhoven, - * 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-ctl.c,v $ - * $Revision: 1.4 $ - * $Date: 1997/11/11 14:37:44 $ - * - * This file contains the non-read/write ftape functions for the - * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. - */ - -#include -#include -#include - -#include -#include -#include -#include - -/* ease porting between pre-2.4.x and later kernels */ -#define vma_get_pgoff(v) ((v)->vm_pgoff) - -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-write.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-bsm.h" - -/* Global vars. - */ -ftape_info ftape_status = { -/* vendor information */ - { 0, }, /* drive type */ -/* data rates */ - 500, /* used data rate */ - 500, /* drive max rate */ - 500, /* fdc max rate */ -/* drive selection, either FTAPE_SEL_A/B/C/D */ - -1, /* drive selection */ -/* flags set after decode the drive and tape status */ - 0, /* formatted */ - 1, /* no tape */ - 1, /* write protected */ - 1, /* new tape */ -/* values of last queried drive/tape status and error */ - {{0,}}, /* last error code */ - {{0,}}, /* drive status, configuration, tape status */ -/* cartridge geometry */ - 20, /* tracks_per_tape */ - 102, /* segments_per_track */ -/* location of header segments, etc. */ - -1, /* used_header_segment */ - -1, /* header_segment_1 */ - -1, /* header_segment_2 */ - -1, /* first_data_segment */ - -1, /* last_data_segment */ -/* the format code as stored in the header segment */ - fmt_normal, /* format code */ -/* the default for the qic std: unknown */ - -1, -/* is tape running? */ - idle, /* runner_state */ -/* is tape reading/writing/verifying/formatting/deleting */ - idle, /* driver state */ -/* flags fatal hardware error */ - 1, /* failure */ -/* history record */ - { 0, } /* history record */ -}; - -int ftape_segments_per_head = 1020; -int ftape_segments_per_cylinder = 4; -int ftape_init_drive_needed = 1; /* need to be global for ftape_reset_drive() - * in ftape-io.c - */ - -/* Local vars. - */ -static const vendor_struct vendors[] = QIC117_VENDORS; -static const wakeup_method methods[] = WAKEUP_METHODS; - -const ftape_info *ftape_get_status(void) -{ -#if defined(STATUS_PARANOYA) - static ftape_info get_status; - - get_status = ftape_status; - return &get_status; -#else - return &ftape_status; /* maybe return only a copy of it to assure - * read only access - */ -#endif -} - -static int ftape_not_operational(int status) -{ - /* return true if status indicates tape can not be used. - */ - return ((status ^ QIC_STATUS_CARTRIDGE_PRESENT) & - (QIC_STATUS_ERROR | - QIC_STATUS_CARTRIDGE_PRESENT | - QIC_STATUS_NEW_CARTRIDGE)); -} - -int ftape_seek_to_eot(void) -{ - int status; - TRACE_FUN(ft_t_any); - - TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),); - while ((status & QIC_STATUS_AT_EOT) == 0) { - if (ftape_not_operational(status)) { - TRACE_EXIT -EIO; - } - TRACE_CATCH(ftape_command_wait(QIC_PHYSICAL_FORWARD, - ftape_timeout.rewind,&status),); - } - TRACE_EXIT 0; -} - -int ftape_seek_to_bot(void) -{ - int status; - TRACE_FUN(ft_t_any); - - TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),); - while ((status & QIC_STATUS_AT_BOT) == 0) { - if (ftape_not_operational(status)) { - TRACE_EXIT -EIO; - } - TRACE_CATCH(ftape_command_wait(QIC_PHYSICAL_REVERSE, - ftape_timeout.rewind,&status),); - } - TRACE_EXIT 0; -} - -static int ftape_new_cartridge(void) -{ - ft_location.track = -1; /* force seek on first access */ - ftape_zap_read_buffers(); - ftape_zap_write_buffers(); - return 0; -} - -int ftape_abort_operation(void) -{ - int result = 0; - int status; - TRACE_FUN(ft_t_flow); - - if (ft_runner_status == running) { - TRACE(ft_t_noise, "aborting runner, waiting"); - - ft_runner_status = do_abort; - /* set timeout so that the tape will run to logical EOT - * if we missed the last sector and there are no queue pulses. - */ - result = ftape_dumb_stop(); - } - if (ft_runner_status != idle) { - if (ft_runner_status == do_abort) { - TRACE(ft_t_noise, "forcing runner abort"); - } - TRACE(ft_t_noise, "stopping tape"); - result = ftape_stop_tape(&status); - ft_location.known = 0; - ft_runner_status = idle; - } - ftape_reset_buffer(); - ftape_zap_read_buffers(); - ftape_set_state(idle); - TRACE_EXIT result; -} - -static int lookup_vendor_id(unsigned int vendor_id) -{ - int i = 0; - - while (vendors[i].vendor_id != vendor_id) { - if (++i >= NR_ITEMS(vendors)) { - return -1; - } - } - return i; -} - -static void ftape_detach_drive(void) -{ - TRACE_FUN(ft_t_any); - - TRACE(ft_t_flow, "disabling tape drive and fdc"); - ftape_put_drive_to_sleep(ft_drive_type.wake_up); - fdc_catch_stray_interrupts(1); /* one always comes */ - fdc_disable(); - fdc_release_irq_and_dma(); - fdc_release_regions(); - TRACE_EXIT; -} - -static void clear_history(void) -{ - ft_history.used = 0; - ft_history.id_am_errors = - ft_history.id_crc_errors = - ft_history.data_am_errors = - ft_history.data_crc_errors = - ft_history.overrun_errors = - ft_history.no_data_errors = - ft_history.retries = - ft_history.crc_errors = - ft_history.crc_failures = - ft_history.ecc_failures = - ft_history.corrected = - ft_history.defects = - ft_history.rewinds = 0; -} - -static int ftape_activate_drive(vendor_struct * drive_type) -{ - int result = 0; - TRACE_FUN(ft_t_flow); - - /* If we already know the drive type, wake it up. - * Else try to find out what kind of drive is attached. - */ - if (drive_type->wake_up != unknown_wake_up) { - TRACE(ft_t_flow, "enabling tape drive and fdc"); - result = ftape_wakeup_drive(drive_type->wake_up); - if (result < 0) { - TRACE(ft_t_err, "known wakeup method failed"); - } - } else { - wake_up_types method; - const ft_trace_t old_tracing = TRACE_LEVEL; - if (TRACE_LEVEL < ft_t_flow) { - SET_TRACE_LEVEL(ft_t_bug); - } - - /* Try to awaken the drive using all known methods. - * Lower tracing for a while. - */ - for (method=no_wake_up; method < NR_ITEMS(methods); ++method) { - drive_type->wake_up = method; -#ifdef CONFIG_FT_TWO_DRIVES - /* Test setup for dual drive configuration. - * /dev/rft2 uses mountain wakeup - * /dev/rft3 uses colorado wakeup - * Other systems will use the normal scheme. - */ - if ((ft_drive_sel < 2) || - (ft_drive_sel == 2 && method == FT_WAKE_UP_1) || - (ft_drive_sel == 3 && method == FT_WAKE_UP_2)) { - result=ftape_wakeup_drive(drive_type->wake_up); - } else { - result = -EIO; - } -#else - result = ftape_wakeup_drive(drive_type->wake_up); -#endif - if (result >= 0) { - TRACE(ft_t_warn, "drive wakeup method: %s", - methods[drive_type->wake_up].name); - break; - } - } - SET_TRACE_LEVEL(old_tracing); - - if (method >= NR_ITEMS(methods)) { - /* no response at all, cannot open this drive */ - drive_type->wake_up = unknown_wake_up; - TRACE(ft_t_err, "no tape drive found !"); - result = -ENODEV; - } - } - TRACE_EXIT result; -} - -static int ftape_get_drive_status(void) -{ - int result; - int status; - TRACE_FUN(ft_t_flow); - - ft_no_tape = ft_write_protected = 0; - /* Tape drive is activated now. - * First clear error status if present. - */ - do { - result = ftape_ready_wait(ftape_timeout.reset, &status); - if (result < 0) { - if (result == -ETIME) { - TRACE(ft_t_err, "ftape_ready_wait timeout"); - } else if (result == -EINTR) { - TRACE(ft_t_err, "ftape_ready_wait aborted"); - } else { - TRACE(ft_t_err, "ftape_ready_wait failed"); - } - TRACE_EXIT -EIO; - } - /* Clear error condition (drive is ready !) - */ - if (status & QIC_STATUS_ERROR) { - unsigned int error; - qic117_cmd_t command; - - TRACE(ft_t_err, "error status set"); - result = ftape_report_error(&error, &command, 1); - if (result < 0) { - TRACE(ft_t_err, - "report_error_code failed: %d", result); - /* hope it's working next time */ - ftape_reset_drive(); - TRACE_EXIT -EIO; - } else if (error != 0) { - TRACE(ft_t_noise, "error code : %d", error); - TRACE(ft_t_noise, "error command: %d", command); - } - } - if (status & QIC_STATUS_NEW_CARTRIDGE) { - unsigned int error; - qic117_cmd_t command; - const ft_trace_t old_tracing = TRACE_LEVEL; - SET_TRACE_LEVEL(ft_t_bug); - - /* Undocumented feature: Must clear (not present!) - * error here or we'll fail later. - */ - ftape_report_error(&error, &command, 1); - - SET_TRACE_LEVEL(old_tracing); - TRACE(ft_t_info, "status: new cartridge"); - ft_new_tape = 1; - } else { - ft_new_tape = 0; - } - FT_SIGNAL_EXIT(_DONT_BLOCK); - } while (status & QIC_STATUS_ERROR); - - ft_no_tape = !(status & QIC_STATUS_CARTRIDGE_PRESENT); - ft_write_protected = (status & QIC_STATUS_WRITE_PROTECT) != 0; - if (ft_no_tape) { - TRACE(ft_t_warn, "no cartridge present"); - } else { - if (ft_write_protected) { - TRACE(ft_t_noise, "Write protected cartridge"); - } - } - TRACE_EXIT 0; -} - -static void ftape_log_vendor_id(void) -{ - int vendor_index; - TRACE_FUN(ft_t_flow); - - ftape_report_vendor_id(&ft_drive_type.vendor_id); - vendor_index = lookup_vendor_id(ft_drive_type.vendor_id); - if (ft_drive_type.vendor_id == UNKNOWN_VENDOR && - ft_drive_type.wake_up == wake_up_colorado) { - vendor_index = 0; - /* hack to get rid of all this mail */ - ft_drive_type.vendor_id = 0; - } - if (vendor_index < 0) { - /* Unknown vendor id, first time opening device. The - * drive_type remains set to type found at wakeup - * time, this will probably keep the driver operating - * for this new vendor. - */ - TRACE(ft_t_warn, "\n" - KERN_INFO "============ unknown vendor id ===========\n" - KERN_INFO "A new, yet unsupported tape drive is found\n" - KERN_INFO "Please report the following values:\n" - KERN_INFO " Vendor id : 0x%04x\n" - KERN_INFO " Wakeup method : %s\n" - KERN_INFO "And a description of your tape drive\n" - KERN_INFO "to "THE_FTAPE_MAINTAINER"\n" - KERN_INFO "==========================================", - ft_drive_type.vendor_id, - methods[ft_drive_type.wake_up].name); - ft_drive_type.speed = 0; /* unknown */ - } else { - ft_drive_type.name = vendors[vendor_index].name; - ft_drive_type.speed = vendors[vendor_index].speed; - TRACE(ft_t_info, "tape drive type: %s", ft_drive_type.name); - /* scan all methods for this vendor_id in table */ - while(ft_drive_type.wake_up != vendors[vendor_index].wake_up) { - if (vendor_index < NR_ITEMS(vendors) - 1 && - vendors[vendor_index + 1].vendor_id - == - ft_drive_type.vendor_id) { - ++vendor_index; - } else { - break; - } - } - if (ft_drive_type.wake_up != vendors[vendor_index].wake_up) { - TRACE(ft_t_warn, "\n" - KERN_INFO "==========================================\n" - KERN_INFO "wakeup type mismatch:\n" - KERN_INFO "found: %s, expected: %s\n" - KERN_INFO "please report this to "THE_FTAPE_MAINTAINER"\n" - KERN_INFO "==========================================", - methods[ft_drive_type.wake_up].name, - methods[vendors[vendor_index].wake_up].name); - } - } - TRACE_EXIT; -} - -void ftape_calc_timeouts(unsigned int qic_std, - unsigned int data_rate, - unsigned int tape_len) -{ - int speed; /* deci-ips ! */ - int ff_speed; - int length; - TRACE_FUN(ft_t_any); - - /* tape transport speed - * data rate: QIC-40 QIC-80 QIC-3010 QIC-3020 - * - * 250 Kbps 25 ips n/a n/a n/a - * 500 Kbps 50 ips 34 ips 22.6 ips n/a - * 1 Mbps n/a 68 ips 45.2 ips 22.6 ips - * 2 Mbps n/a n/a n/a 45.2 ips - * - * fast tape transport speed is at least 68 ips. - */ - switch (qic_std) { - case QIC_TAPE_QIC40: - speed = (data_rate == 250) ? 250 : 500; - break; - case QIC_TAPE_QIC80: - speed = (data_rate == 500) ? 340 : 680; - break; - case QIC_TAPE_QIC3010: - speed = (data_rate == 500) ? 226 : 452; - break; - case QIC_TAPE_QIC3020: - speed = (data_rate == 1000) ? 226 : 452; - break; - default: - TRACE(ft_t_bug, "Unknown qic_std (bug) ?"); - speed = 500; - break; - } - if (ft_drive_type.speed == 0) { - unsigned long t0; - static int dt = 0; /* keep gcc from complaining */ - static int first_time = 1; - - /* Measure the time it takes to wind to EOT and back to BOT. - * If the tape length is known, calculate the rewind speed. - * Else keep the time value for calculation of the rewind - * speed later on, when the length _is_ known. - * Ask for a report only when length and speed are both known. - */ - if (first_time) { - ftape_seek_to_bot(); - t0 = jiffies; - ftape_seek_to_eot(); - ftape_seek_to_bot(); - dt = (int) (((jiffies - t0) * FT_USPT) / 1000); - if (dt < 1) { - dt = 1; /* prevent div by zero on failures */ - } - first_time = 0; - TRACE(ft_t_info, - "trying to determine seek timeout, got %d msec", - dt); - } - if (tape_len != 0) { - ft_drive_type.speed = - (2 * 12 * tape_len * 1000) / dt; - TRACE(ft_t_warn, "\n" - KERN_INFO "==========================================\n" - KERN_INFO "drive type: %s\n" - KERN_INFO "delta time = %d ms, length = %d ft\n" - KERN_INFO "has a maximum tape speed of %d ips\n" - KERN_INFO "please report this to "THE_FTAPE_MAINTAINER"\n" - KERN_INFO "==========================================", - ft_drive_type.name, dt, tape_len, - ft_drive_type.speed); - } - } - /* Handle unknown length tapes as very long ones. We'll - * determine the actual length from a header segment later. - * This is normal for all modern (Wide,TR1/2/3) formats. - */ - if (tape_len <= 0) { - TRACE(ft_t_noise, - "Unknown tape length, using maximal timeouts"); - length = QIC_TOP_TAPE_LEN; /* use worst case values */ - } else { - length = tape_len; /* use actual values */ - } - if (ft_drive_type.speed == 0) { - ff_speed = speed; - } else { - ff_speed = ft_drive_type.speed; - } - /* time to go from bot to eot at normal speed (data rate): - * time = (1+delta) * length (ft) * 12 (inch/ft) / speed (ips) - * delta = 10 % for seek speed, 20 % for rewind speed. - */ - ftape_timeout.seek = (length * 132 * FT_SECOND) / speed; - ftape_timeout.rewind = (length * 144 * FT_SECOND) / (10 * ff_speed); - ftape_timeout.reset = 20 * FT_SECOND + ftape_timeout.rewind; - TRACE(ft_t_noise, "timeouts for speed = %d, length = %d\n" - KERN_INFO "seek timeout : %d sec\n" - KERN_INFO "rewind timeout: %d sec\n" - KERN_INFO "reset timeout : %d sec", - speed, length, - (ftape_timeout.seek + 500) / 1000, - (ftape_timeout.rewind + 500) / 1000, - (ftape_timeout.reset + 500) / 1000); - TRACE_EXIT; -} - -/* This function calibrates the datarate (i.e. determines the maximal - * usable data rate) and sets the global variable ft_qic_std to qic_std - * - */ -int ftape_calibrate_data_rate(unsigned int qic_std) -{ - int rate = ft_fdc_rate_limit; - int result; - TRACE_FUN(ft_t_flow); - - ft_qic_std = qic_std; - - if (ft_qic_std == -1) { - TRACE_ABORT(-EIO, ft_t_err, - "Unable to determine data rate if QIC standard is unknown"); - } - - /* Select highest rate supported by both fdc and drive. - * Start with highest rate supported by the fdc. - */ - while (fdc_set_data_rate(rate) < 0 && rate > 250) { - rate /= 2; - } - TRACE(ft_t_info, - "Highest FDC supported data rate: %d Kbps", rate); - ft_fdc_max_rate = rate; - do { - result = ftape_set_data_rate(rate, ft_qic_std); - } while (result == -EINVAL && (rate /= 2) > 250); - if (result < 0) { - TRACE_ABORT(-EIO, ft_t_err, "set datarate failed"); - } - ft_data_rate = rate; - TRACE_EXIT 0; -} - -static int ftape_init_drive(void) -{ - int status; - qic_model model; - unsigned int qic_std; - unsigned int data_rate; - TRACE_FUN(ft_t_flow); - - ftape_init_drive_needed = 0; /* don't retry if this fails ? */ - TRACE_CATCH(ftape_report_raw_drive_status(&status),); - if (status & QIC_STATUS_CARTRIDGE_PRESENT) { - if (!(status & QIC_STATUS_AT_BOT)) { - /* Antique drives will get here after a soft reset, - * modern ones only if the driver is loaded when the - * tape wasn't rewound properly. - */ - /* Tape should be at bot if new cartridge ! */ - ftape_seek_to_bot(); - } - if (!(status & QIC_STATUS_REFERENCED)) { - TRACE(ft_t_flow, "starting seek_load_point"); - TRACE_CATCH(ftape_command_wait(QIC_SEEK_LOAD_POINT, - ftape_timeout.reset, - &status),); - } - } - ft_formatted = (status & QIC_STATUS_REFERENCED) != 0; - if (!ft_formatted) { - TRACE(ft_t_warn, "Warning: tape is not formatted !"); - } - - /* report configuration aborts when ftape_tape_len == -1 - * unknown qic_std is okay if not formatted. - */ - TRACE_CATCH(ftape_report_configuration(&model, - &data_rate, - &qic_std, - &ftape_tape_len),); - - /* Maybe add the following to the /proc entry - */ - TRACE(ft_t_info, "%s drive @ %d Kbps", - (model == prehistoric) ? "prehistoric" : - ((model == pre_qic117c) ? "pre QIC-117C" : - ((model == post_qic117b) ? "post QIC-117B" : - "post QIC-117D")), data_rate); - - if (ft_formatted) { - /* initialize ft_used_data_rate to maximum value - * and set ft_qic_std - */ - TRACE_CATCH(ftape_calibrate_data_rate(qic_std),); - if (ftape_tape_len == 0) { - TRACE(ft_t_info, "unknown length QIC-%s tape", - (ft_qic_std == QIC_TAPE_QIC40) ? "40" : - ((ft_qic_std == QIC_TAPE_QIC80) ? "80" : - ((ft_qic_std == QIC_TAPE_QIC3010) - ? "3010" : "3020"))); - } else { - TRACE(ft_t_info, "%d ft. QIC-%s tape", ftape_tape_len, - (ft_qic_std == QIC_TAPE_QIC40) ? "40" : - ((ft_qic_std == QIC_TAPE_QIC80) ? "80" : - ((ft_qic_std == QIC_TAPE_QIC3010) - ? "3010" : "3020"))); - } - ftape_calc_timeouts(ft_qic_std, ft_data_rate, ftape_tape_len); - /* soft write-protect QIC-40/QIC-80 cartridges used with a - * Colorado T3000 drive. Buggy hardware! - */ - if ((ft_drive_type.vendor_id == 0x011c6) && - ((ft_qic_std == QIC_TAPE_QIC40 || - ft_qic_std == QIC_TAPE_QIC80) && - !ft_write_protected)) { - TRACE(ft_t_warn, "\n" - KERN_INFO "The famous Colorado T3000 bug:\n" - KERN_INFO "%s drives can't write QIC40 and QIC80\n" - KERN_INFO "cartridges but don't set the write-protect flag!", - ft_drive_type.name); - ft_write_protected = 1; - } - } else { - /* Doesn't make too much sense to set the data rate - * because we don't know what to use for the write - * precompensation. - * Need to do this again when formatting the cartridge. - */ - ft_data_rate = data_rate; - ftape_calc_timeouts(QIC_TAPE_QIC40, - data_rate, - ftape_tape_len); - } - ftape_new_cartridge(); - TRACE_EXIT 0; -} - -static void ftape_munmap(void) -{ - int i; - TRACE_FUN(ft_t_flow); - - for (i = 0; i < ft_nr_buffers; i++) { - ft_buffer[i]->mmapped = 0; - } - TRACE_EXIT; -} - -/* Map the dma buffers into the virtual address range given by vma. - * We only check the caller doesn't map non-existent buffers. We - * don't check for multiple mappings. - */ -int ftape_mmap(struct vm_area_struct *vma) -{ - int num_buffers; - int i; - TRACE_FUN(ft_t_flow); - - if (ft_failure) { - TRACE_EXIT -ENODEV; - } - if (!(vma->vm_flags & (VM_READ|VM_WRITE))) { - TRACE_ABORT(-EINVAL, ft_t_err, "Undefined mmap() access"); - } - if (vma_get_pgoff(vma) != 0) { - TRACE_ABORT(-EINVAL, ft_t_err, "page offset must be 0"); - } - if ((vma->vm_end - vma->vm_start) % FT_BUFF_SIZE != 0) { - TRACE_ABORT(-EINVAL, ft_t_err, - "size = %ld, should be a multiple of %d", - vma->vm_end - vma->vm_start, - FT_BUFF_SIZE); - } - num_buffers = (vma->vm_end - vma->vm_start) / FT_BUFF_SIZE; - if (num_buffers > ft_nr_buffers) { - TRACE_ABORT(-EINVAL, - ft_t_err, "size = %ld, should be less than %d", - vma->vm_end - vma->vm_start, - ft_nr_buffers * FT_BUFF_SIZE); - } - if (ft_driver_state != idle) { - /* this also clears the buffer states - */ - ftape_abort_operation(); - } else { - ftape_reset_buffer(); - } - for (i = 0; i < num_buffers; i++) { - unsigned long pfn; - - pfn = virt_to_phys(ft_buffer[i]->address) >> PAGE_SHIFT; - TRACE_CATCH(remap_pfn_range(vma, vma->vm_start + - i * FT_BUFF_SIZE, - pfn, - FT_BUFF_SIZE, - vma->vm_page_prot), - _res = -EAGAIN); - TRACE(ft_t_noise, "remapped dma buffer @ %p to location @ %p", - ft_buffer[i]->address, - (void *)(vma->vm_start + i * FT_BUFF_SIZE)); - } - for (i = 0; i < num_buffers; i++) { - memset(ft_buffer[i]->address, 0xAA, FT_BUFF_SIZE); - ft_buffer[i]->mmapped++; - } - TRACE_EXIT 0; -} - -static void ftape_init_driver(void); /* forward declaration */ - -/* OPEN routine called by kernel-interface code - */ -int ftape_enable(int drive_selection) -{ - TRACE_FUN(ft_t_any); - - if (ft_drive_sel == -1 || ft_drive_sel != drive_selection) { - /* Other selection than last time - */ - ftape_init_driver(); - } - ft_drive_sel = FTAPE_SEL(drive_selection); - ft_failure = 0; - TRACE_CATCH(fdc_init(),); /* init & detect fdc */ - TRACE_CATCH(ftape_activate_drive(&ft_drive_type), - fdc_disable(); - fdc_release_irq_and_dma(); - fdc_release_regions()); - TRACE_CATCH(ftape_get_drive_status(), ftape_detach_drive()); - if (ft_drive_type.vendor_id == UNKNOWN_VENDOR) { - ftape_log_vendor_id(); - } - if (ft_new_tape) { - ftape_init_drive_needed = 1; - } - if (!ft_no_tape && ftape_init_drive_needed) { - TRACE_CATCH(ftape_init_drive(), ftape_detach_drive()); - } - ftape_munmap(); /* clear the mmap flag */ - clear_history(); - TRACE_EXIT 0; -} - -/* release routine called by the high level interface modules - * zftape or sftape. - */ -void ftape_disable(void) -{ - int i; - TRACE_FUN(ft_t_any); - - for (i = 0; i < ft_nr_buffers; i++) { - if (ft_buffer[i]->mmapped) { - TRACE(ft_t_noise, "first byte of buffer %d: 0x%02x", - i, *ft_buffer[i]->address); - } - } - if (sigtestsetmask(¤t->pending.signal, _DONT_BLOCK) && - !(sigtestsetmask(¤t->pending.signal, _NEVER_BLOCK)) && - ftape_tape_running) { - TRACE(ft_t_warn, - "Interrupted by fatal signal and tape still running"); - ftape_dumb_stop(); - ftape_abort_operation(); /* it's annoying */ - } else { - ftape_set_state(idle); - } - ftape_detach_drive(); - if (ft_history.used) { - TRACE(ft_t_info, "== Non-fatal errors this run: =="); - TRACE(ft_t_info, "fdc isr statistics:\n" - KERN_INFO " id_am_errors : %3d\n" - KERN_INFO " id_crc_errors : %3d\n" - KERN_INFO " data_am_errors : %3d\n" - KERN_INFO " data_crc_errors : %3d\n" - KERN_INFO " overrun_errors : %3d\n" - KERN_INFO " no_data_errors : %3d\n" - KERN_INFO " retries : %3d", - ft_history.id_am_errors, ft_history.id_crc_errors, - ft_history.data_am_errors, ft_history.data_crc_errors, - ft_history.overrun_errors, ft_history.no_data_errors, - ft_history.retries); - if (ft_history.used & 1) { - TRACE(ft_t_info, "ecc statistics:\n" - KERN_INFO " crc_errors : %3d\n" - KERN_INFO " crc_failures : %3d\n" - KERN_INFO " ecc_failures : %3d\n" - KERN_INFO " sectors corrected: %3d", - ft_history.crc_errors, ft_history.crc_failures, - ft_history.ecc_failures, ft_history.corrected); - } - if (ft_history.defects > 0) { - TRACE(ft_t_warn, "Warning: %d media defects!", - ft_history.defects); - } - if (ft_history.rewinds > 0) { - TRACE(ft_t_info, "tape motion statistics:\n" - KERN_INFO "repositions : %3d", - ft_history.rewinds); - } - } - ft_failure = 1; - TRACE_EXIT; -} - -static void ftape_init_driver(void) -{ - TRACE_FUN(ft_t_flow); - - ft_drive_type.vendor_id = UNKNOWN_VENDOR; - ft_drive_type.speed = 0; - ft_drive_type.wake_up = unknown_wake_up; - ft_drive_type.name = "Unknown"; - - ftape_timeout.seek = 650 * FT_SECOND; - ftape_timeout.reset = 670 * FT_SECOND; - ftape_timeout.rewind = 650 * FT_SECOND; - ftape_timeout.head_seek = 15 * FT_SECOND; - ftape_timeout.stop = 5 * FT_SECOND; - ftape_timeout.pause = 16 * FT_SECOND; - - ft_qic_std = -1; - ftape_tape_len = 0; /* unknown */ - ftape_current_command = 0; - ftape_current_cylinder = -1; - - ft_segments_per_track = 102; - ftape_segments_per_head = 1020; - ftape_segments_per_cylinder = 4; - ft_tracks_per_tape = 20; - - ft_failure = 1; - - ft_formatted = 0; - ft_no_tape = 1; - ft_write_protected = 1; - ft_new_tape = 1; - - ft_driver_state = idle; - - ft_data_rate = - ft_fdc_max_rate = 500; - ft_drive_max_rate = 0; /* triggers set_rate_test() */ - - ftape_init_drive_needed = 1; - - ft_header_segment_1 = -1; - ft_header_segment_2 = -1; - ft_used_header_segment = -1; - ft_first_data_segment = -1; - ft_last_data_segment = -1; - - ft_location.track = -1; - ft_location.known = 0; - - ftape_tape_running = 0; - ftape_might_be_off_track = 1; - - ftape_new_cartridge(); /* init some tape related variables */ - ftape_init_bsm(); - TRACE_EXIT; -} diff --git a/drivers/char/ftape/lowlevel/ftape-ctl.h b/drivers/char/ftape/lowlevel/ftape-ctl.h deleted file mode 100644 index 5f5e30bc361..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-ctl.h +++ /dev/null @@ -1,162 +0,0 @@ -#ifndef _FTAPE_CTL_H -#define _FTAPE_CTL_H - -/* - * 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-ctl.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:09 $ - * - * This file contains the non-standard IOCTL related definitions - * for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for - * Linux. - */ - -#include -#include -#include - -#include "../lowlevel/ftape-rw.h" -#include - -typedef struct { - int used; /* any reading or writing done */ - /* isr statistics */ - unsigned int id_am_errors; /* id address mark not found */ - unsigned int id_crc_errors; /* crc error in id address mark */ - unsigned int data_am_errors; /* data address mark not found */ - unsigned int data_crc_errors; /* crc error in data field */ - unsigned int overrun_errors; /* fdc access timing problem */ - unsigned int no_data_errors; /* sector not found */ - unsigned int retries; /* number of tape retries */ - /* ecc statistics */ - unsigned int crc_errors; /* crc error in data */ - unsigned int crc_failures; /* bad data without crc error */ - unsigned int ecc_failures; /* failed to correct */ - unsigned int corrected; /* total sectors corrected */ - /* general statistics */ - unsigned int rewinds; /* number of tape rewinds */ - unsigned int defects; /* bad sectors due to media defects */ -} history_record; - -/* this structure contains * ALL * information that we want - * our child modules to know about, but don't want them to - * modify. - */ -typedef struct { - /* vendor information */ - vendor_struct fti_drive_type; - /* data rates */ - unsigned int fti_used_data_rate; - unsigned int fti_drive_max_rate; - unsigned int fti_fdc_max_rate; - /* drive selection, either FTAPE_SEL_A/B/C/D */ - int fti_drive_sel; - /* flags set after decode the drive and tape status */ - unsigned int fti_formatted :1; - unsigned int fti_no_tape :1; - unsigned int fti_write_protected:1; - unsigned int fti_new_tape :1; - /* values of last queried drive/tape status and error */ - ft_drive_error fti_last_error; - ft_drive_status fti_last_status; - /* cartridge geometry */ - unsigned int fti_tracks_per_tape; - unsigned int fti_segments_per_track; - /* location of header segments, etc. */ - int fti_used_header_segment; - int fti_header_segment_1; - int fti_header_segment_2; - int fti_first_data_segment; - int fti_last_data_segment; - /* the format code as stored in the header segment */ - ft_format_type fti_format_code; - /* the following is the sole reason for the ftape_set_status() call */ - unsigned int fti_qic_std; - /* is tape running? */ - volatile enum runner_status_enum fti_runner_status; - /* is tape reading/writing/verifying/formatting/deleting */ - buffer_state_enum fti_state; - /* flags fatal hardware error */ - unsigned int fti_failure:1; - /* history record */ - history_record fti_history; -} ftape_info; - -/* vendor information */ -#define ft_drive_type ftape_status.fti_drive_type -/* data rates */ -#define ft_data_rate ftape_status.fti_used_data_rate -#define ft_drive_max_rate ftape_status.fti_drive_max_rate -#define ft_fdc_max_rate ftape_status.fti_fdc_max_rate -/* drive selection, either FTAPE_SEL_A/B/C/D */ -#define ft_drive_sel ftape_status.fti_drive_sel -/* flags set after decode the drive and tape status */ -#define ft_formatted ftape_status.fti_formatted -#define ft_no_tape ftape_status.fti_no_tape -#define ft_write_protected ftape_status.fti_write_protected -#define ft_new_tape ftape_status.fti_new_tape -/* values of last queried drive/tape status and error */ -#define ft_last_error ftape_status.fti_last_error -#define ft_last_status ftape_status.fti_last_status -/* cartridge geometry */ -#define ft_tracks_per_tape ftape_status.fti_tracks_per_tape -#define ft_segments_per_track ftape_status.fti_segments_per_track -/* the format code as stored in the header segment */ -#define ft_format_code ftape_status.fti_format_code -/* the qic status as returned by report drive configuration */ -#define ft_qic_std ftape_status.fti_qic_std -#define ft_used_header_segment ftape_status.fti_used_header_segment -#define ft_header_segment_1 ftape_status.fti_header_segment_1 -#define ft_header_segment_2 ftape_status.fti_header_segment_2 -#define ft_first_data_segment ftape_status.fti_first_data_segment -#define ft_last_data_segment ftape_status.fti_last_data_segment -/* is tape running? */ -#define ft_runner_status ftape_status.fti_runner_status -/* is tape reading/writing/verifying/formatting/deleting */ -#define ft_driver_state ftape_status.fti_state -/* flags fatal hardware error */ -#define ft_failure ftape_status.fti_failure -/* history record */ -#define ft_history ftape_status.fti_history - -/* - * ftape-ctl.c defined global vars. - */ -extern ftape_info ftape_status; -extern int ftape_segments_per_head; -extern int ftape_segments_per_cylinder; -extern int ftape_init_drive_needed; - -/* - * ftape-ctl.c defined global functions. - */ -extern int ftape_mmap(struct vm_area_struct *vma); -extern int ftape_enable(int drive_selection); -extern void ftape_disable(void); -extern int ftape_seek_to_bot(void); -extern int ftape_seek_to_eot(void); -extern int ftape_abort_operation(void); -extern void ftape_calc_timeouts(unsigned int qic_std, - unsigned int data_rate, - unsigned int tape_len); -extern int ftape_calibrate_data_rate(unsigned int qic_std); -extern const ftape_info *ftape_get_status(void); -#endif diff --git a/drivers/char/ftape/lowlevel/ftape-ecc.c b/drivers/char/ftape/lowlevel/ftape-ecc.c deleted file mode 100644 index e5632f674bc..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-ecc.c +++ /dev/null @@ -1,853 +0,0 @@ -/* - * - * Copyright (c) 1993 Ning and David Mosberger. - - This is based on code originally written by Bas Laarhoven (bas@vimec.nl) - and David L. Brown, Jr., and incorporates improvements suggested by - Kai Harrekilde-Petersen. - - 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-ecc.c,v $ - * $Revision: 1.3 $ - * $Date: 1997/10/05 19:18:10 $ - * - * This file contains the Reed-Solomon error correction code - * for the QIC-40/80 floppy-tape driver for Linux. - */ - -#include - -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-ecc.h" - -/* Machines that are big-endian should define macro BIG_ENDIAN. - * Unfortunately, there doesn't appear to be a standard include file - * that works for all OSs. - */ - -#if defined(__sparc__) || defined(__hppa) -#define BIG_ENDIAN -#endif /* __sparc__ || __hppa */ - -#if defined(__mips__) -#error Find a smart way to determine the Endianness of the MIPS CPU -#endif - -/* Notice: to minimize the potential for confusion, we use r to - * denote the independent variable of the polynomials in the - * Galois Field GF(2^8). We reserve x for polynomials that - * that have coefficients in GF(2^8). - * - * The Galois Field in which coefficient arithmetic is performed are - * the polynomials over Z_2 (i.e., 0 and 1) modulo the irreducible - * polynomial f(r), where f(r)=r^8 + r^7 + r^2 + r + 1. A polynomial - * is represented as a byte with the MSB as the coefficient of r^7 and - * the LSB as the coefficient of r^0. For example, the binary - * representation of f(x) is 0x187 (of course, this doesn't fit into 8 - * bits). In this field, the polynomial r is a primitive element. - * That is, r^i with i in 0,...,255 enumerates all elements in the - * field. - * - * The generator polynomial for the QIC-80 ECC is - * - * g(x) = x^3 + r^105*x^2 + r^105*x + 1 - * - * which can be factored into: - * - * g(x) = (x-r^-1)(x-r^0)(x-r^1) - * - * the byte representation of the coefficients are: - * - * r^105 = 0xc0 - * r^-1 = 0xc3 - * r^0 = 0x01 - * r^1 = 0x02 - * - * Notice that r^-1 = r^254 as exponent arithmetic is performed - * modulo 2^8-1 = 255. - * - * For more information on Galois Fields and Reed-Solomon codes, refer - * to any good book. I found _An Introduction to Error Correcting - * Codes with Applications_ by S. A. Vanstone and P. C. van Oorschot - * to be a good introduction into the former. _CODING THEORY: The - * Essentials_ I found very useful for its concise description of - * Reed-Solomon encoding/decoding. - * - */ - -typedef __u8 Matrix[3][3]; - -/* - * gfpow[] is defined such that gfpow[i] returns r^i if - * i is in the range [0..255]. - */ -static const __u8 gfpow[] = -{ - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, - 0x87, 0x89, 0x95, 0xad, 0xdd, 0x3d, 0x7a, 0xf4, - 0x6f, 0xde, 0x3b, 0x76, 0xec, 0x5f, 0xbe, 0xfb, - 0x71, 0xe2, 0x43, 0x86, 0x8b, 0x91, 0xa5, 0xcd, - 0x1d, 0x3a, 0x74, 0xe8, 0x57, 0xae, 0xdb, 0x31, - 0x62, 0xc4, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, 0x67, - 0xce, 0x1b, 0x36, 0x6c, 0xd8, 0x37, 0x6e, 0xdc, - 0x3f, 0x7e, 0xfc, 0x7f, 0xfe, 0x7b, 0xf6, 0x6b, - 0xd6, 0x2b, 0x56, 0xac, 0xdf, 0x39, 0x72, 0xe4, - 0x4f, 0x9e, 0xbb, 0xf1, 0x65, 0xca, 0x13, 0x26, - 0x4c, 0x98, 0xb7, 0xe9, 0x55, 0xaa, 0xd3, 0x21, - 0x42, 0x84, 0x8f, 0x99, 0xb5, 0xed, 0x5d, 0xba, - 0xf3, 0x61, 0xc2, 0x03, 0x06, 0x0c, 0x18, 0x30, - 0x60, 0xc0, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, - 0x47, 0x8e, 0x9b, 0xb1, 0xe5, 0x4d, 0x9a, 0xb3, - 0xe1, 0x45, 0x8a, 0x93, 0xa1, 0xc5, 0x0d, 0x1a, - 0x34, 0x68, 0xd0, 0x27, 0x4e, 0x9c, 0xbf, 0xf9, - 0x75, 0xea, 0x53, 0xa6, 0xcb, 0x11, 0x22, 0x44, - 0x88, 0x97, 0xa9, 0xd5, 0x2d, 0x5a, 0xb4, 0xef, - 0x59, 0xb2, 0xe3, 0x41, 0x82, 0x83, 0x81, 0x85, - 0x8d, 0x9d, 0xbd, 0xfd, 0x7d, 0xfa, 0x73, 0xe6, - 0x4b, 0x96, 0xab, 0xd1, 0x25, 0x4a, 0x94, 0xaf, - 0xd9, 0x35, 0x6a, 0xd4, 0x2f, 0x5e, 0xbc, 0xff, - 0x79, 0xf2, 0x63, 0xc6, 0x0b, 0x16, 0x2c, 0x58, - 0xb0, 0xe7, 0x49, 0x92, 0xa3, 0xc1, 0x05, 0x0a, - 0x14, 0x28, 0x50, 0xa0, 0xc7, 0x09, 0x12, 0x24, - 0x48, 0x90, 0xa7, 0xc9, 0x15, 0x2a, 0x54, 0xa8, - 0xd7, 0x29, 0x52, 0xa4, 0xcf, 0x19, 0x32, 0x64, - 0xc8, 0x17, 0x2e, 0x5c, 0xb8, 0xf7, 0x69, 0xd2, - 0x23, 0x46, 0x8c, 0x9f, 0xb9, 0xf5, 0x6d, 0xda, - 0x33, 0x66, 0xcc, 0x1f, 0x3e, 0x7c, 0xf8, 0x77, - 0xee, 0x5b, 0xb6, 0xeb, 0x51, 0xa2, 0xc3, 0x01 -}; - -/* - * This is a log table. That is, gflog[r^i] returns i (modulo f(r)). - * gflog[0] is undefined and the first element is therefore not valid. - */ -static const __u8 gflog[256] = -{ - 0xff, 0x00, 0x01, 0x63, 0x02, 0xc6, 0x64, 0x6a, - 0x03, 0xcd, 0xc7, 0xbc, 0x65, 0x7e, 0x6b, 0x2a, - 0x04, 0x8d, 0xce, 0x4e, 0xc8, 0xd4, 0xbd, 0xe1, - 0x66, 0xdd, 0x7f, 0x31, 0x6c, 0x20, 0x2b, 0xf3, - 0x05, 0x57, 0x8e, 0xe8, 0xcf, 0xac, 0x4f, 0x83, - 0xc9, 0xd9, 0xd5, 0x41, 0xbe, 0x94, 0xe2, 0xb4, - 0x67, 0x27, 0xde, 0xf0, 0x80, 0xb1, 0x32, 0x35, - 0x6d, 0x45, 0x21, 0x12, 0x2c, 0x0d, 0xf4, 0x38, - 0x06, 0x9b, 0x58, 0x1a, 0x8f, 0x79, 0xe9, 0x70, - 0xd0, 0xc2, 0xad, 0xa8, 0x50, 0x75, 0x84, 0x48, - 0xca, 0xfc, 0xda, 0x8a, 0xd6, 0x54, 0x42, 0x24, - 0xbf, 0x98, 0x95, 0xf9, 0xe3, 0x5e, 0xb5, 0x15, - 0x68, 0x61, 0x28, 0xba, 0xdf, 0x4c, 0xf1, 0x2f, - 0x81, 0xe6, 0xb2, 0x3f, 0x33, 0xee, 0x36, 0x10, - 0x6e, 0x18, 0x46, 0xa6, 0x22, 0x88, 0x13, 0xf7, - 0x2d, 0xb8, 0x0e, 0x3d, 0xf5, 0xa4, 0x39, 0x3b, - 0x07, 0x9e, 0x9c, 0x9d, 0x59, 0x9f, 0x1b, 0x08, - 0x90, 0x09, 0x7a, 0x1c, 0xea, 0xa0, 0x71, 0x5a, - 0xd1, 0x1d, 0xc3, 0x7b, 0xae, 0x0a, 0xa9, 0x91, - 0x51, 0x5b, 0x76, 0x72, 0x85, 0xa1, 0x49, 0xeb, - 0xcb, 0x7c, 0xfd, 0xc4, 0xdb, 0x1e, 0x8b, 0xd2, - 0xd7, 0x92, 0x55, 0xaa, 0x43, 0x0b, 0x25, 0xaf, - 0xc0, 0x73, 0x99, 0x77, 0x96, 0x5c, 0xfa, 0x52, - 0xe4, 0xec, 0x5f, 0x4a, 0xb6, 0xa2, 0x16, 0x86, - 0x69, 0xc5, 0x62, 0xfe, 0x29, 0x7d, 0xbb, 0xcc, - 0xe0, 0xd3, 0x4d, 0x8c, 0xf2, 0x1f, 0x30, 0xdc, - 0x82, 0xab, 0xe7, 0x56, 0xb3, 0x93, 0x40, 0xd8, - 0x34, 0xb0, 0xef, 0x26, 0x37, 0x0c, 0x11, 0x44, - 0x6f, 0x78, 0x19, 0x9a, 0x47, 0x74, 0xa7, 0xc1, - 0x23, 0x53, 0x89, 0xfb, 0x14, 0x5d, 0xf8, 0x97, - 0x2e, 0x4b, 0xb9, 0x60, 0x0f, 0xed, 0x3e, 0xe5, - 0xf6, 0x87, 0xa5, 0x17, 0x3a, 0xa3, 0x3c, 0xb7 -}; - -/* This is a multiplication table for the factor 0xc0 (i.e., r^105 (mod f(r)). - * gfmul_c0[f] returns r^105 * f(r) (modulo f(r)). - */ -static const __u8 gfmul_c0[256] = -{ - 0x00, 0xc0, 0x07, 0xc7, 0x0e, 0xce, 0x09, 0xc9, - 0x1c, 0xdc, 0x1b, 0xdb, 0x12, 0xd2, 0x15, 0xd5, - 0x38, 0xf8, 0x3f, 0xff, 0x36, 0xf6, 0x31, 0xf1, - 0x24, 0xe4, 0x23, 0xe3, 0x2a, 0xea, 0x2d, 0xed, - 0x70, 0xb0, 0x77, 0xb7, 0x7e, 0xbe, 0x79, 0xb9, - 0x6c, 0xac, 0x6b, 0xab, 0x62, 0xa2, 0x65, 0xa5, - 0x48, 0x88, 0x4f, 0x8f, 0x46, 0x86, 0x41, 0x81, - 0x54, 0x94, 0x53, 0x93, 0x5a, 0x9a, 0x5d, 0x9d, - 0xe0, 0x20, 0xe7, 0x27, 0xee, 0x2e, 0xe9, 0x29, - 0xfc, 0x3c, 0xfb, 0x3b, 0xf2, 0x32, 0xf5, 0x35, - 0xd8, 0x18, 0xdf, 0x1f, 0xd6, 0x16, 0xd1, 0x11, - 0xc4, 0x04, 0xc3, 0x03, 0xca, 0x0a, 0xcd, 0x0d, - 0x90, 0x50, 0x97, 0x57, 0x9e, 0x5e, 0x99, 0x59, - 0x8c, 0x4c, 0x8b, 0x4b, 0x82, 0x42, 0x85, 0x45, - 0xa8, 0x68, 0xaf, 0x6f, 0xa6, 0x66, 0xa1, 0x61, - 0xb4, 0x74, 0xb3, 0x73, 0xba, 0x7a, 0xbd, 0x7d, - 0x47, 0x87, 0x40, 0x80, 0x49, 0x89, 0x4e, 0x8e, - 0x5b, 0x9b, 0x5c, 0x9c, 0x55, 0x95, 0x52, 0x92, - 0x7f, 0xbf, 0x78, 0xb8, 0x71, 0xb1, 0x76, 0xb6, - 0x63, 0xa3, 0x64, 0xa4, 0x6d, 0xad, 0x6a, 0xaa, - 0x37, 0xf7, 0x30, 0xf0, 0x39, 0xf9, 0x3e, 0xfe, - 0x2b, 0xeb, 0x2c, 0xec, 0x25, 0xe5, 0x22, 0xe2, - 0x0f, 0xcf, 0x08, 0xc8, 0x01, 0xc1, 0x06, 0xc6, - 0x13, 0xd3, 0x14, 0xd4, 0x1d, 0xdd, 0x1a, 0xda, - 0xa7, 0x67, 0xa0, 0x60, 0xa9, 0x69, 0xae, 0x6e, - 0xbb, 0x7b, 0xbc, 0x7c, 0xb5, 0x75, 0xb2, 0x72, - 0x9f, 0x5f, 0x98, 0x58, 0x91, 0x51, 0x96, 0x56, - 0x83, 0x43, 0x84, 0x44, 0x8d, 0x4d, 0x8a, 0x4a, - 0xd7, 0x17, 0xd0, 0x10, 0xd9, 0x19, 0xde, 0x1e, - 0xcb, 0x0b, 0xcc, 0x0c, 0xc5, 0x05, 0xc2, 0x02, - 0xef, 0x2f, 0xe8, 0x28, 0xe1, 0x21, 0xe6, 0x26, - 0xf3, 0x33, 0xf4, 0x34, 0xfd, 0x3d, 0xfa, 0x3a -}; - - -/* Returns V modulo 255 provided V is in the range -255,-254,...,509. - */ -static inline __u8 mod255(int v) -{ - if (v > 0) { - if (v < 255) { - return v; - } else { - return v - 255; - } - } else { - return v + 255; - } -} - - -/* Add two numbers in the field. Addition in this field is equivalent - * to a bit-wise exclusive OR operation---subtraction is therefore - * identical to addition. - */ -static inline __u8 gfadd(__u8 a, __u8 b) -{ - return a ^ b; -} - - -/* Add two vectors of numbers in the field. Each byte in A and B gets - * added individually. - */ -static inline unsigned long gfadd_long(unsigned long a, unsigned long b) -{ - return a ^ b; -} - - -/* Multiply two numbers in the field: - */ -static inline __u8 gfmul(__u8 a, __u8 b) -{ - if (a && b) { - return gfpow[mod255(gflog[a] + gflog[b])]; - } else { - return 0; - } -} - - -/* Just like gfmul, except we have already looked up the log of the - * second number. - */ -static inline __u8 gfmul_exp(__u8 a, int b) -{ - if (a) { - return gfpow[mod255(gflog[a] + b)]; - } else { - return 0; - } -} - - -/* Just like gfmul_exp, except that A is a vector of numbers. That - * is, each byte in A gets multiplied by gfpow[mod255(B)]. - */ -static inline unsigned long gfmul_exp_long(unsigned long a, int b) -{ - __u8 t; - - if (sizeof(long) == 4) { - return ( - ((t = (__u32)a >> 24 & 0xff) ? - (((__u32) gfpow[mod255(gflog[t] + b)]) << 24) : 0) | - ((t = (__u32)a >> 16 & 0xff) ? - (((__u32) gfpow[mod255(gflog[t] + b)]) << 16) : 0) | - ((t = (__u32)a >> 8 & 0xff) ? - (((__u32) gfpow[mod255(gflog[t] + b)]) << 8) : 0) | - ((t = (__u32)a >> 0 & 0xff) ? - (((__u32) gfpow[mod255(gflog[t] + b)]) << 0) : 0)); - } else if (sizeof(long) == 8) { - return ( - ((t = (__u64)a >> 56 & 0xff) ? - (((__u64) gfpow[mod255(gflog[t] + b)]) << 56) : 0) | - ((t = (__u64)a >> 48 & 0xff) ? - (((__u64) gfpow[mod255(gflog[t] + b)]) << 48) : 0) | - ((t = (__u64)a >> 40 & 0xff) ? - (((__u64) gfpow[mod255(gflog[t] + b)]) << 40) : 0) | - ((t = (__u64)a >> 32 & 0xff) ? - (((__u64) gfpow[mod255(gflog[t] + b)]) << 32) : 0) | - ((t = (__u64)a >> 24 & 0xff) ? - (((__u64) gfpow[mod255(gflog[t] + b)]) << 24) : 0) | - ((t = (__u64)a >> 16 & 0xff) ? - (((__u64) gfpow[mod255(gflog[t] + b)]) << 16) : 0) | - ((t = (__u64)a >> 8 & 0xff) ? - (((__u64) gfpow[mod255(gflog[t] + b)]) << 8) : 0) | - ((t = (__u64)a >> 0 & 0xff) ? - (((__u64) gfpow[mod255(gflog[t] + b)]) << 0) : 0)); - } else { - TRACE_FUN(ft_t_any); - TRACE_ABORT(-1, ft_t_err, "Error: size of long is %d bytes", - (int)sizeof(long)); - } -} - - -/* Divide two numbers in the field. Returns a/b (modulo f(x)). - */ -static inline __u8 gfdiv(__u8 a, __u8 b) -{ - if (!b) { - TRACE_FUN(ft_t_any); - TRACE_ABORT(0xff, ft_t_bug, "Error: division by zero"); - } else if (a == 0) { - return 0; - } else { - return gfpow[mod255(gflog[a] - gflog[b])]; - } -} - - -/* The following functions return the inverse of the matrix of the - * linear system that needs to be solved to determine the error - * magnitudes. The first deals with matrices of rank 3, while the - * second deals with matrices of rank 2. The error indices are passed - * in arguments L0,..,L2 (0=first sector, 31=last sector). The error - * indices must be sorted in ascending order, i.e., L00 CRC failures)"); - } - log_det = 255 - gflog[det]; - - /* Now, calculate all of the coefficients: - */ - Ainv[0][0]= gfmul_exp(gfadd(gfpow[l1], gfpow[l2]), log_det); - Ainv[0][1]= gfmul_exp(gfadd(t21, t12), log_det); - Ainv[0][2]= gfmul_exp(gfadd(gfpow[255 - l1], gfpow[255 - l2]),log_det); - - Ainv[1][0]= gfmul_exp(gfadd(gfpow[l0], gfpow[l2]), log_det); - Ainv[1][1]= gfmul_exp(gfadd(t20, t02), log_det); - Ainv[1][2]= gfmul_exp(gfadd(gfpow[255 - l0], gfpow[255 - l2]),log_det); - - Ainv[2][0]= gfmul_exp(gfadd(gfpow[l0], gfpow[l1]), log_det); - Ainv[2][1]= gfmul_exp(gfadd(t10, t01), log_det); - Ainv[2][2]= gfmul_exp(gfadd(gfpow[255 - l0], gfpow[255 - l1]),log_det); - - return 1; -} - - -static inline int gfinv2(__u8 l0, __u8 l1, Matrix Ainv) -{ - __u8 det; - __u8 t1, t2; - int log_det; - - t1 = gfpow[255 - l0]; - t2 = gfpow[255 - l1]; - det = gfadd(t1, t2); - if (!det) { - TRACE_FUN(ft_t_any); - TRACE_ABORT(0, ft_t_err, - "Inversion failed (2 CRC errors, >0 CRC failures)"); - } - log_det = 255 - gflog[det]; - - /* Now, calculate all of the coefficients: - */ - Ainv[0][0] = Ainv[1][0] = gfpow[log_det]; - - Ainv[0][1] = gfmul_exp(t2, log_det); - Ainv[1][1] = gfmul_exp(t1, log_det); - - return 1; -} - - -/* Multiply matrix A by vector S and return result in vector B. M is - * assumed to be of order NxN, S and B of order Nx1. - */ -static inline void gfmat_mul(int n, Matrix A, - __u8 *s, __u8 *b) -{ - int i, j; - __u8 dot_prod; - - for (i = 0; i < n; ++i) { - dot_prod = 0; - for (j = 0; j < n; ++j) { - dot_prod = gfadd(dot_prod, gfmul(A[i][j], s[j])); - } - b[i] = dot_prod; - } -} - - - -/* The Reed Solomon ECC codes are computed over the N-th byte of each - * block, where N=SECTOR_SIZE. There are up to 29 blocks of data, and - * 3 blocks of ECC. The blocks are stored contiguously in memory. A - * segment, consequently, is assumed to have at least 4 blocks: one or - * more data blocks plus three ECC blocks. - * - * Notice: In QIC-80 speak, a CRC error is a sector with an incorrect - * CRC. A CRC failure is a sector with incorrect data, but - * a valid CRC. In the error control literature, the former - * is usually called "erasure", the latter "error." - */ -/* Compute the parity bytes for C columns of data, where C is the - * number of bytes that fit into a long integer. We use a linear - * feed-back register to do this. The parity bytes P[0], P[STRIDE], - * P[2*STRIDE] are computed such that: - * - * x^k * p(x) + m(x) = 0 (modulo g(x)) - * - * where k = NBLOCKS, - * p(x) = P[0] + P[STRIDE]*x + P[2*STRIDE]*x^2, and - * m(x) = sum_{i=0}^k m_i*x^i. - * m_i = DATA[i*SECTOR_SIZE] - */ -static inline void set_parity(unsigned long *data, - int nblocks, - unsigned long *p, - int stride) -{ - unsigned long p0, p1, p2, t1, t2, *end; - - end = data + nblocks * (FT_SECTOR_SIZE / sizeof(long)); - p0 = p1 = p2 = 0; - while (data < end) { - /* The new parity bytes p0_i, p1_i, p2_i are computed - * from the old values p0_{i-1}, p1_{i-1}, p2_{i-1} - * recursively as: - * - * p0_i = p1_{i-1} + r^105 * (m_{i-1} - p0_{i-1}) - * p1_i = p2_{i-1} + r^105 * (m_{i-1} - p0_{i-1}) - * p2_i = (m_{i-1} - p0_{i-1}) - * - * With the initial condition: p0_0 = p1_0 = p2_0 = 0. - */ - t1 = gfadd_long(*data, p0); - /* - * Multiply each byte in t1 by 0xc0: - */ - if (sizeof(long) == 4) { - t2= (((__u32) gfmul_c0[(__u32)t1 >> 24 & 0xff]) << 24 | - ((__u32) gfmul_c0[(__u32)t1 >> 16 & 0xff]) << 16 | - ((__u32) gfmul_c0[(__u32)t1 >> 8 & 0xff]) << 8 | - ((__u32) gfmul_c0[(__u32)t1 >> 0 & 0xff]) << 0); - } else if (sizeof(long) == 8) { - t2= (((__u64) gfmul_c0[(__u64)t1 >> 56 & 0xff]) << 56 | - ((__u64) gfmul_c0[(__u64)t1 >> 48 & 0xff]) << 48 | - ((__u64) gfmul_c0[(__u64)t1 >> 40 & 0xff]) << 40 | - ((__u64) gfmul_c0[(__u64)t1 >> 32 & 0xff]) << 32 | - ((__u64) gfmul_c0[(__u64)t1 >> 24 & 0xff]) << 24 | - ((__u64) gfmul_c0[(__u64)t1 >> 16 & 0xff]) << 16 | - ((__u64) gfmul_c0[(__u64)t1 >> 8 & 0xff]) << 8 | - ((__u64) gfmul_c0[(__u64)t1 >> 0 & 0xff]) << 0); - } else { - TRACE_FUN(ft_t_any); - TRACE(ft_t_err, "Error: long is of size %d", - (int) sizeof(long)); - TRACE_EXIT; - } - p0 = gfadd_long(t2, p1); - p1 = gfadd_long(t2, p2); - p2 = t1; - data += FT_SECTOR_SIZE / sizeof(long); - } - *p = p0; - p += stride; - *p = p1; - p += stride; - *p = p2; - return; -} - - -/* Compute the 3 syndrome values. DATA should point to the first byte - * of the column for which the syndromes are desired. The syndromes - * are computed over the first NBLOCKS of rows. The three bytes will - * be placed in S[0], S[1], and S[2]. - * - * S[i] is the value of the "message" polynomial m(x) evaluated at the - * i-th root of the generator polynomial g(x). - * - * As g(x)=(x-r^-1)(x-1)(x-r^1) we evaluate the message polynomial at - * x=r^-1 to get S[0], at x=r^0=1 to get S[1], and at x=r to get S[2]. - * This could be done directly and efficiently via the Horner scheme. - * However, it would require multiplication tables for the factors - * r^-1 (0xc3) and r (0x02). The following scheme does not require - * any multiplication tables beyond what's needed for set_parity() - * anyway and is slightly faster if there are no errors and slightly - * slower if there are errors. The latter is hopefully the infrequent - * case. - * - * To understand the alternative algorithm, notice that set_parity(m, - * k, p) computes parity bytes such that: - * - * x^k * p(x) = m(x) (modulo g(x)). - * - * That is, to evaluate m(r^m), where r^m is a root of g(x), we can - * simply evaluate (r^m)^k*p(r^m). Also, notice that p is 0 if and - * only if s is zero. That is, if all parity bytes are 0, we know - * there is no error in the data and consequently there is no need to - * compute s(x) at all! In all other cases, we compute s(x) from p(x) - * by evaluating (r^m)^k*p(r^m) for m=-1, m=0, and m=1. The p(x) - * polynomial is evaluated via the Horner scheme. - */ -static int compute_syndromes(unsigned long *data, int nblocks, unsigned long *s) -{ - unsigned long p[3]; - - set_parity(data, nblocks, p, 1); - if (p[0] | p[1] | p[2]) { - /* Some of the checked columns do not have a zero - * syndrome. For simplicity, we compute the syndromes - * for all columns that we have computed the - * remainders for. - */ - s[0] = gfmul_exp_long( - gfadd_long(p[0], - gfmul_exp_long( - gfadd_long(p[1], - gfmul_exp_long(p[2], -1)), - -1)), - -nblocks); - s[1] = gfadd_long(gfadd_long(p[2], p[1]), p[0]); - s[2] = gfmul_exp_long( - gfadd_long(p[0], - gfmul_exp_long( - gfadd_long(p[1], - gfmul_exp_long(p[2], 1)), - 1)), - nblocks); - return 0; - } else { - return 1; - } -} - - -/* Correct the block in the column pointed to by DATA. There are NBAD - * CRC errors and their indices are in BAD_LOC[0], up to - * BAD_LOC[NBAD-1]. If NBAD>1, Ainv holds the inverse of the matrix - * of the linear system that needs to be solved to determine the error - * magnitudes. S[0], S[1], and S[2] are the syndrome values. If row - * j gets corrected, then bit j will be set in CORRECTION_MAP. - */ -static inline int correct_block(__u8 *data, int nblocks, - int nbad, int *bad_loc, Matrix Ainv, - __u8 *s, - SectorMap * correction_map) -{ - int ncorrected = 0; - int i; - __u8 t1, t2; - __u8 c0, c1, c2; /* check bytes */ - __u8 error_mag[3], log_error_mag; - __u8 *dp, l, e; - TRACE_FUN(ft_t_any); - - switch (nbad) { - case 0: - /* might have a CRC failure: */ - if (s[0] == 0) { - /* more than one error */ - TRACE_ABORT(-1, ft_t_err, - "ECC failed (0 CRC errors, >1 CRC failures)"); - } - t1 = gfdiv(s[1], s[0]); - if ((bad_loc[nbad++] = gflog[t1]) >= nblocks) { - TRACE(ft_t_err, - "ECC failed (0 CRC errors, >1 CRC failures)"); - TRACE_ABORT(-1, ft_t_err, - "attempt to correct data at %d", bad_loc[0]); - } - error_mag[0] = s[1]; - break; - case 1: - t1 = gfadd(gfmul_exp(s[1], bad_loc[0]), s[2]); - t2 = gfadd(gfmul_exp(s[0], bad_loc[0]), s[1]); - if (t1 == 0 && t2 == 0) { - /* one erasure, no error: */ - Ainv[0][0] = gfpow[bad_loc[0]]; - } else if (t1 == 0 || t2 == 0) { - /* one erasure and more than one error: */ - TRACE_ABORT(-1, ft_t_err, - "ECC failed (1 erasure, >1 error)"); - } else { - /* one erasure, one error: */ - if ((bad_loc[nbad++] = gflog[gfdiv(t1, t2)]) - >= nblocks) { - TRACE(ft_t_err, "ECC failed " - "(1 CRC errors, >1 CRC failures)"); - TRACE_ABORT(-1, ft_t_err, - "attempt to correct data at %d", - bad_loc[1]); - } - if (!gfinv2(bad_loc[0], bad_loc[1], Ainv)) { - /* inversion failed---must have more - * than one error - */ - TRACE_EXIT -1; - } - } - /* FALL THROUGH TO ERROR MAGNITUDE COMPUTATION: - */ - case 2: - case 3: - /* compute error magnitudes: */ - gfmat_mul(nbad, Ainv, s, error_mag); - break; - - default: - TRACE_ABORT(-1, ft_t_err, - "Internal Error: number of CRC errors > 3"); - } - - /* Perform correction by adding ERROR_MAG[i] to the byte at - * offset BAD_LOC[i]. Also add the value of the computed - * error polynomial to the syndrome values. If the correction - * was successful, the resulting check bytes should be zero - * (i.e., the corrected data is a valid code word). - */ - c0 = s[0]; - c1 = s[1]; - c2 = s[2]; - for (i = 0; i < nbad; ++i) { - e = error_mag[i]; - if (e) { - /* correct the byte at offset L by magnitude E: */ - l = bad_loc[i]; - dp = &data[l * FT_SECTOR_SIZE]; - *dp = gfadd(*dp, e); - *correction_map |= 1 << l; - ++ncorrected; - - log_error_mag = gflog[e]; - c0 = gfadd(c0, gfpow[mod255(log_error_mag - l)]); - c1 = gfadd(c1, e); - c2 = gfadd(c2, gfpow[mod255(log_error_mag + l)]); - } - } - if (c0 || c1 || c2) { - TRACE_ABORT(-1, ft_t_err, - "ECC self-check failed, too many errors"); - } - TRACE_EXIT ncorrected; -} - - -#if defined(ECC_SANITY_CHECK) || defined(ECC_PARANOID) - -/* Perform a sanity check on the computed parity bytes: - */ -static int sanity_check(unsigned long *data, int nblocks) -{ - TRACE_FUN(ft_t_any); - unsigned long s[3]; - - if (!compute_syndromes(data, nblocks, s)) { - TRACE_ABORT(0, ft_bug, - "Internal Error: syndrome self-check failed"); - } - TRACE_EXIT 1; -} - -#endif /* defined(ECC_SANITY_CHECK) || defined(ECC_PARANOID) */ - -/* Compute the parity for an entire segment of data. - */ -int ftape_ecc_set_segment_parity(struct memory_segment *mseg) -{ - int i; - __u8 *parity_bytes; - - parity_bytes = &mseg->data[(mseg->blocks - 3) * FT_SECTOR_SIZE]; - for (i = 0; i < FT_SECTOR_SIZE; i += sizeof(long)) { - set_parity((unsigned long *) &mseg->data[i], mseg->blocks - 3, - (unsigned long *) &parity_bytes[i], - FT_SECTOR_SIZE / sizeof(long)); -#ifdef ECC_PARANOID - if (!sanity_check((unsigned long *) &mseg->data[i], - mseg->blocks)) { - return -1; - } -#endif /* ECC_PARANOID */ - } - return 0; -} - - -/* Checks and corrects (if possible) the segment MSEG. Returns one of - * ECC_OK, ECC_CORRECTED, and ECC_FAILED. - */ -int ftape_ecc_correct_data(struct memory_segment *mseg) -{ - int col, i, result; - int ncorrected = 0; - int nerasures = 0; /* # of erasures (CRC errors) */ - int erasure_loc[3]; /* erasure locations */ - unsigned long ss[3]; - __u8 s[3]; - Matrix Ainv; - TRACE_FUN(ft_t_flow); - - mseg->corrected = 0; - - /* find first column that has non-zero syndromes: */ - for (col = 0; col < FT_SECTOR_SIZE; col += sizeof(long)) { - if (!compute_syndromes((unsigned long *) &mseg->data[col], - mseg->blocks, ss)) { - /* something is wrong---have to fix things */ - break; - } - } - if (col >= FT_SECTOR_SIZE) { - /* all syndromes are ok, therefore nothing to correct */ - TRACE_EXIT ECC_OK; - } - /* count the number of CRC errors if there were any: */ - if (mseg->read_bad) { - for (i = 0; i < mseg->blocks; i++) { - if (BAD_CHECK(mseg->read_bad, i)) { - if (nerasures >= 3) { - /* this is too much for ECC */ - TRACE_ABORT(ECC_FAILED, ft_t_err, - "ECC failed (>3 CRC errors)"); - } /* if */ - erasure_loc[nerasures++] = i; - } - } - } - /* - * If there are at least 2 CRC errors, determine inverse of matrix - * of linear system to be solved: - */ - switch (nerasures) { - case 2: - if (!gfinv2(erasure_loc[0], erasure_loc[1], Ainv)) { - TRACE_EXIT ECC_FAILED; - } - break; - case 3: - if (!gfinv3(erasure_loc[0], erasure_loc[1], - erasure_loc[2], Ainv)) { - TRACE_EXIT ECC_FAILED; - } - break; - default: - /* this is not an error condition... */ - break; - } - - do { - for (i = 0; i < sizeof(long); ++i) { - s[0] = ss[0]; - s[1] = ss[1]; - s[2] = ss[2]; - if (s[0] | s[1] | s[2]) { -#ifdef BIG_ENDIAN - result = correct_block( - &mseg->data[col + sizeof(long) - 1 - i], - mseg->blocks, - nerasures, - erasure_loc, - Ainv, - s, - &mseg->corrected); -#else - result = correct_block(&mseg->data[col + i], - mseg->blocks, - nerasures, - erasure_loc, - Ainv, - s, - &mseg->corrected); -#endif - if (result < 0) { - TRACE_EXIT ECC_FAILED; - } - ncorrected += result; - } - ss[0] >>= 8; - ss[1] >>= 8; - ss[2] >>= 8; - } - -#ifdef ECC_SANITY_CHECK - if (!sanity_check((unsigned long *) &mseg->data[col], - mseg->blocks)) { - TRACE_EXIT ECC_FAILED; - } -#endif /* ECC_SANITY_CHECK */ - - /* find next column with non-zero syndromes: */ - while ((col += sizeof(long)) < FT_SECTOR_SIZE) { - if (!compute_syndromes((unsigned long *) - &mseg->data[col], mseg->blocks, ss)) { - /* something is wrong---have to fix things */ - break; - } - } - } while (col < FT_SECTOR_SIZE); - if (ncorrected && nerasures == 0) { - TRACE(ft_t_warn, "block contained error not caught by CRC"); - } - TRACE((ncorrected > 0) ? ft_t_noise : ft_t_any, "number of corrections: %d", ncorrected); - TRACE_EXIT ncorrected ? ECC_CORRECTED : ECC_OK; -} diff --git a/drivers/char/ftape/lowlevel/ftape-ecc.h b/drivers/char/ftape/lowlevel/ftape-ecc.h deleted file mode 100644 index 4829146fe9a..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-ecc.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef _FTAPE_ECC_H_ -#define _FTAPE_ECC_H_ - -/* - * Copyright (C) 1993 Ning and David Mosberger. - * Original: - * Copyright (C) 1993 Bas Laarhoven. - * Copyright (C) 1992 David L. Brown, Jr. - - 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-ecc.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:11 $ - * - * This file contains the definitions for the - * Reed-Solomon error correction code - * for the QIC-40/80 tape streamer device driver. - */ - -#include "../lowlevel/ftape-bsm.h" - -#define BAD_CLEAR(entry) ((entry)=0) -#define BAD_SET(entry,sector) ((entry)|=(1<<(sector))) -#define BAD_CHECK(entry,sector) ((entry)&(1<<(sector))) - -/* - * Return values for ecc_correct_data: - */ -enum { - ECC_OK, /* Data was correct. */ - ECC_CORRECTED, /* Correctable error in data. */ - ECC_FAILED, /* Could not correct data. */ -}; - -/* - * Representation of an in memory segment. MARKED_BAD lists the - * sectors that were marked bad during formatting. If the N-th sector - * in a segment is marked bad, bit 1< -#include - -#include -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-ecc.h" -#include "../lowlevel/ftape-bsm.h" -#include "../lowlevel/ftape-format.h" - -#if defined(TESTING) -#define FT_FMT_SEGS_PER_BUF 50 -#else -#define FT_FMT_SEGS_PER_BUF (FT_BUFF_SIZE/(4*FT_SECTORS_PER_SEGMENT)) -#endif - -static spinlock_t ftape_format_lock; - -/* - * first segment of the new buffer - */ -static int switch_segment; - -/* - * at most 256 segments fit into one 32 kb buffer. Even TR-1 cartridges have - * more than this many segments per track, so better be careful. - * - * buffer_struct *buff: buffer to store the formatting coordinates in - * int start: starting segment for this buffer. - * int spt: segments per track - * - * Note: segment ids are relative to the start of the track here. - */ -static void setup_format_buffer(buffer_struct *buff, int start, int spt, - __u8 gap3) -{ - int to_do = spt - start; - TRACE_FUN(ft_t_flow); - - if (to_do > FT_FMT_SEGS_PER_BUF) { - to_do = FT_FMT_SEGS_PER_BUF; - } - buff->ptr = buff->address; - buff->remaining = to_do * FT_SECTORS_PER_SEGMENT; /* # sectors */ - buff->bytes = buff->remaining * 4; /* need 4 bytes per sector */ - buff->gap3 = gap3; - buff->segment_id = start; - buff->next_segment = start + to_do; - if (buff->next_segment >= spt) { - buff->next_segment = 0; /* 0 means: stop runner */ - } - buff->status = waiting; /* tells the isr that it can use - * this buffer - */ - TRACE_EXIT; -} - - -/* - * start formatting a new track. - */ -int ftape_format_track(const unsigned int track, const __u8 gap3) -{ - unsigned long flags; - buffer_struct *tail, *head; - int status; - TRACE_FUN(ft_t_flow); - - TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),); - if (track & 1) { - if (!(status & QIC_STATUS_AT_EOT)) { - TRACE_CATCH(ftape_seek_to_eot(),); - } - } else { - if (!(status & QIC_STATUS_AT_BOT)) { - TRACE_CATCH(ftape_seek_to_bot(),); - } - } - ftape_abort_operation(); /* this sets ft_head = ft_tail = 0 */ - ftape_set_state(formatting); - - TRACE(ft_t_noise, - "Formatting track %d, logical: from segment %d to %d", - track, track * ft_segments_per_track, - (track + 1) * ft_segments_per_track - 1); - - /* - * initialize the buffer switching protocol for this track - */ - head = ftape_get_buffer(ft_queue_head); /* tape isn't running yet */ - tail = ftape_get_buffer(ft_queue_tail); /* tape isn't running yet */ - switch_segment = 0; - do { - FT_SIGNAL_EXIT(_DONT_BLOCK); - setup_format_buffer(tail, switch_segment, - ft_segments_per_track, gap3); - switch_segment = tail->next_segment; - } while ((switch_segment != 0) && - ((tail = ftape_next_buffer(ft_queue_tail)) != head)); - /* go */ - head->status = formatting; - TRACE_CATCH(ftape_seek_head_to_track(track),); - TRACE_CATCH(ftape_command(QIC_LOGICAL_FORWARD),); - spin_lock_irqsave(&ftape_format_lock, flags); - TRACE_CATCH(fdc_setup_formatting(head), restore_flags(flags)); - spin_unlock_irqrestore(&ftape_format_lock, flags); - TRACE_EXIT 0; -} - -/* return segment id of segment currently being formatted and do the - * buffer switching stuff. - */ -int ftape_format_status(unsigned int *segment_id) -{ - buffer_struct *tail = ftape_get_buffer(ft_queue_tail); - int result; - TRACE_FUN(ft_t_flow); - - while (switch_segment != 0 && - ftape_get_buffer(ft_queue_head) != tail) { - FT_SIGNAL_EXIT(_DONT_BLOCK); - /* need more buffers, first wait for empty buffer - */ - TRACE_CATCH(ftape_wait_segment(formatting),); - /* don't worry for gap3. If we ever hit this piece of code, - * then all buffer already have the correct gap3 set! - */ - setup_format_buffer(tail, switch_segment, - ft_segments_per_track, tail->gap3); - switch_segment = tail->next_segment; - if (switch_segment != 0) { - tail = ftape_next_buffer(ft_queue_tail); - } - } - /* should runner stop ? - */ - if (ft_runner_status == aborting || ft_runner_status == do_abort) { - buffer_struct *head = ftape_get_buffer(ft_queue_head); - TRACE(ft_t_warn, "Error formatting segment %d", - ftape_get_buffer(ft_queue_head)->segment_id); - (void)ftape_abort_operation(); - TRACE_EXIT (head->status != error) ? -EAGAIN : -EIO; - } - /* - * don't care if the timer expires, this is just kind of a - * "select" operation that lets the calling process sleep - * until something has happened - */ - if (fdc_interrupt_wait(5 * FT_SECOND) < 0) { - TRACE(ft_t_noise, "End of track %d at segment %d", - ft_location.track, - ftape_get_buffer(ft_queue_head)->segment_id); - result = 1; /* end of track, unlock module */ - } else { - result = 0; - } - /* - * the calling process should use the seg id to determine - * which parts of the dma buffers can be safely overwritten - * with new data. - */ - *segment_id = ftape_get_buffer(ft_queue_head)->segment_id; - /* - * Internally we start counting segment ids from the start of - * each track when formatting, but externally we keep them - * relative to the start of the tape: - */ - *segment_id += ft_location.track * ft_segments_per_track; - TRACE_EXIT result; -} - -/* - * The segment id is relative to the start of the tape - */ -int ftape_verify_segment(const unsigned int segment_id, SectorMap *bsm) -{ - int result; - int verify_done = 0; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Verifying segment %d", segment_id); - - if (ft_driver_state != verifying) { - TRACE(ft_t_noise, "calling ftape_abort_operation"); - if (ftape_abort_operation() < 0) { - TRACE(ft_t_err, "ftape_abort_operation failed"); - TRACE_EXIT -EIO; - } - } - *bsm = 0x00000000; - ftape_set_state(verifying); - for (;;) { - buffer_struct *tail; - /* - * Allow escape from this loop on signal - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - /* - * Search all full buffers for the first matching the - * wanted segment. Clear other buffers on the fly. - */ - tail = ftape_get_buffer(ft_queue_tail); - while (!verify_done && tail->status == done) { - /* - * Allow escape from this loop on signal ! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - if (tail->segment_id == segment_id) { - /* If out buffer is already full, - * return its contents. - */ - TRACE(ft_t_flow, "found segment in cache: %d", - segment_id); - if ((tail->soft_error_map | - tail->hard_error_map) != 0) { - TRACE(ft_t_info,"bsm[%d] = 0x%08lx", - segment_id, - (unsigned long) - (tail->soft_error_map | - tail->hard_error_map)); - *bsm = (tail->soft_error_map | - tail->hard_error_map); - } - verify_done = 1; - } else { - TRACE(ft_t_flow,"zapping segment in cache: %d", - tail->segment_id); - } - tail->status = waiting; - tail = ftape_next_buffer(ft_queue_tail); - } - if (!verify_done && tail->status == verifying) { - if (tail->segment_id == segment_id) { - switch(ftape_wait_segment(verifying)) { - case 0: - break; - case -EINTR: - TRACE_ABORT(-EINTR, ft_t_warn, - "interrupted by " - "non-blockable signal"); - break; - default: - ftape_abort_operation(); - ftape_set_state(verifying); - /* be picky */ - TRACE_ABORT(-EIO, ft_t_warn, - "wait_segment failed"); - } - } else { - /* We're reading the wrong segment, - * stop runner. - */ - TRACE(ft_t_noise, "verifying wrong segment"); - ftape_abort_operation(); - ftape_set_state(verifying); - } - } - /* should runner stop ? - */ - if (ft_runner_status == aborting) { - buffer_struct *head = ftape_get_buffer(ft_queue_head); - if (head->status == error || - head->status == verifying) { - /* no data or overrun error */ - head->status = waiting; - } - TRACE_CATCH(ftape_dumb_stop(),); - } else { - /* If just passed last segment on tape: wait - * for BOT or EOT mark. Sets ft_runner_status to - * idle if at lEOT and successful - */ - TRACE_CATCH(ftape_handle_logical_eot(),); - } - if (verify_done) { - TRACE_EXIT 0; - } - /* Now at least one buffer is idle! - * Restart runner & tape if needed. - */ - /* We could optimize the following a little bit. We know that - * the bad sector map is empty. - */ - tail = ftape_get_buffer(ft_queue_tail); - if (tail->status == waiting) { - buffer_struct *head = ftape_get_buffer(ft_queue_head); - - ftape_setup_new_segment(head, segment_id, -1); - ftape_calc_next_cluster(head); - if (ft_runner_status == idle) { - result = ftape_start_tape(segment_id, - head->sector_offset); - switch(result) { - case 0: - break; - case -ETIME: - case -EINTR: - TRACE_ABORT(result, ft_t_err, "Error: " - "segment %d unreachable", - segment_id); - break; - default: - *bsm = EMPTY_SEGMENT; - TRACE_EXIT 0; - break; - } - } - head->status = verifying; - fdc_setup_read_write(head, FDC_VERIFY); - } - } - /* not reached */ - TRACE_EXIT -EIO; -} diff --git a/drivers/char/ftape/lowlevel/ftape-format.h b/drivers/char/ftape/lowlevel/ftape-format.h deleted file mode 100644 index f1516156664..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-format.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef _FTAPE_FORMAT_H -#define _FTAPE_FORMAT_H - -/* - * Copyright (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-format.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:13 $ - * - * This file contains the low level definitions for the - * formatting support for the QIC-40/80/3010/3020 floppy-tape - * driver "ftape" for Linux. - */ - -#ifdef __KERNEL__ -extern int ftape_format_track(const unsigned int track, const __u8 gap3); -extern int ftape_format_status(unsigned int *segment_id); -extern int ftape_verify_segment(const unsigned int segment_id, SectorMap *bsm); -#endif /* __KERNEL__ */ - -#endif diff --git a/drivers/char/ftape/lowlevel/ftape-init.c b/drivers/char/ftape/lowlevel/ftape-init.c deleted file mode 100644 index 4998132a81d..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-init.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * 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. - - * - * This file contains the code that interfaces the kernel - * for the QIC-40/80/3010/3020 floppy-tape driver for Linux. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#ifdef CONFIG_ZFTAPE -#include -#endif - -#include "../lowlevel/ftape-init.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-write.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/ftape-buffer.h" -#include "../lowlevel/ftape-proc.h" -#include "../lowlevel/ftape-tracing.h" - - -#if defined(MODULE) && !defined(CONFIG_FT_NO_TRACE_AT_ALL) -static int ft_tracing = -1; -#endif - - -/* Called by modules package when installing the driver - * or by kernel during the initialization phase - */ -static int __init ftape_init(void) -{ - TRACE_FUN(ft_t_flow); - -#ifdef MODULE -#ifndef CONFIG_FT_NO_TRACE_AT_ALL - if (ft_tracing != -1) { - ftape_tracing = ft_tracing; - } -#endif - printk(KERN_INFO FTAPE_VERSION "\n"); - if (TRACE_LEVEL >= ft_t_info) { - printk( -KERN_INFO "(c) 1993-1996 Bas Laarhoven (bas@vimec.nl)\n" -KERN_INFO "(c) 1995-1996 Kai Harrekilde-Petersen (khp@dolphinics.no)\n" -KERN_INFO "(c) 1996-1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n" -KERN_INFO "QIC-117 driver for QIC-40/80/3010/3020 floppy tape drives\n"); - } -#else /* !MODULE */ - /* print a short no-nonsense boot message */ - printk(KERN_INFO FTAPE_VERSION "\n"); -#endif /* MODULE */ - TRACE(ft_t_info, "installing QIC-117 floppy tape hardware drive ... "); - TRACE(ft_t_info, "ftape_init @ 0x%p", ftape_init); - /* Allocate the DMA buffers. They are deallocated at cleanup() time. - */ -#ifdef TESTING -#ifdef MODULE - while (ftape_set_nr_buffers(CONFIG_FT_NR_BUFFERS) < 0) { - ftape_sleep(FT_SECOND/20); - if (signal_pending(current)) { - (void)ftape_set_nr_buffers(0); - TRACE(ft_t_bug, - "Killed by signal while allocating buffers."); - TRACE_ABORT(-EINTR, - ft_t_bug, "Free up memory and retry"); - } - } -#else - TRACE_CATCH(ftape_set_nr_buffers(CONFIG_FT_NR_BUFFERS), - (void)ftape_set_nr_buffers(0)); -#endif -#else - TRACE_CATCH(ftape_set_nr_buffers(CONFIG_FT_NR_BUFFERS), - (void)ftape_set_nr_buffers(0)); -#endif - ft_drive_sel = -1; - ft_failure = 1; /* inhibit any operation but open */ - ftape_udelay_calibrate(); /* must be before fdc_wait_calibrate ! */ - fdc_wait_calibrate(); -#if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) - (void)ftape_proc_init(); -#endif -#ifdef CONFIG_ZFTAPE - (void)zft_init(); -#endif - TRACE_EXIT 0; -} - -module_param(ft_fdc_base, uint, 0); -MODULE_PARM_DESC(ft_fdc_base, "Base address of FDC controller."); -module_param(ft_fdc_irq, uint, 0); -MODULE_PARM_DESC(ft_fdc_irq, "IRQ (interrupt channel) to use."); -module_param(ft_fdc_dma, uint, 0); -MODULE_PARM_DESC(ft_fdc_dma, "DMA channel to use."); -module_param(ft_fdc_threshold, uint, 0); -MODULE_PARM_DESC(ft_fdc_threshold, "Threshold of the FDC Fifo."); -module_param(ft_fdc_rate_limit, uint, 0); -MODULE_PARM_DESC(ft_fdc_rate_limit, "Maximal data rate for FDC."); -module_param(ft_probe_fc10, bool, 0); -MODULE_PARM_DESC(ft_probe_fc10, - "If non-zero, probe for a Colorado FC-10/FC-20 controller."); -module_param(ft_mach2, bool, 0); -MODULE_PARM_DESC(ft_mach2, - "If non-zero, probe for a Mountain MACH-2 controller."); -#if defined(MODULE) && !defined(CONFIG_FT_NO_TRACE_AT_ALL) -module_param(ft_tracing, int, 0644); -MODULE_PARM_DESC(ft_tracing, - "Amount of debugging output, 0 <= tracing <= 8, default 3."); -#endif - -MODULE_AUTHOR( - "(c) 1993-1996 Bas Laarhoven (bas@vimec.nl), " - "(c) 1995-1996 Kai Harrekilde-Petersen (khp@dolphinics.no), " - "(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)"); -MODULE_DESCRIPTION( - "QIC-117 driver for QIC-40/80/3010/3020 floppy tape drives."); -MODULE_LICENSE("GPL"); - -static void __exit ftape_exit(void) -{ - TRACE_FUN(ft_t_flow); - -#if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) - ftape_proc_destroy(); -#endif - (void)ftape_set_nr_buffers(0); - printk(KERN_INFO "ftape: unloaded.\n"); - TRACE_EXIT; -} - -module_init(ftape_init); -module_exit(ftape_exit); diff --git a/drivers/char/ftape/lowlevel/ftape-init.h b/drivers/char/ftape/lowlevel/ftape-init.h deleted file mode 100644 index 99a7b8ab086..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-init.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef _FTAPE_INIT_H -#define _FTAPE_INIT_H - -/* - * 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-init.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:16 $ - * - * This file contains the definitions for the interface to - * the Linux kernel for floppy tape driver ftape. - * - */ - -#include -#include - -#define _NEVER_BLOCK (sigmask(SIGKILL) | sigmask(SIGSTOP)) -#define _DONT_BLOCK (_NEVER_BLOCK | sigmask(SIGINT)) -#define _DO_BLOCK (sigmask(SIGPIPE)) - -#ifndef QIC117_TAPE_MAJOR -#define QIC117_TAPE_MAJOR 27 -#endif - -#endif diff --git a/drivers/char/ftape/lowlevel/ftape-io.c b/drivers/char/ftape/lowlevel/ftape-io.c deleted file mode 100644 index 259015aeff5..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-io.c +++ /dev/null @@ -1,992 +0,0 @@ -/* - * Copyright (C) 1993-1996 Bas Laarhoven, - * (C) 1996 Kai Harrekilde-Petersen, - * (C) 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-io.c,v $ - * $Revision: 1.4 $ - * $Date: 1997/11/11 14:02:36 $ - * - * This file contains the general control functions for the - * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-write.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-init.h" -#include "../lowlevel/ftape-calibr.h" - -/* Global vars. - */ -/* NOTE: sectors start numbering at 1, all others at 0 ! */ -ft_timeout_table ftape_timeout; -unsigned int ftape_tape_len; -volatile qic117_cmd_t ftape_current_command; -const struct qic117_command_table qic117_cmds[] = QIC117_COMMANDS; -int ftape_might_be_off_track; - -/* Local vars. - */ -static int diagnostic_mode; -static unsigned int ftape_udelay_count; -static unsigned int ftape_udelay_time; - -void ftape_udelay(unsigned int usecs) -{ - volatile int count = (ftape_udelay_count * usecs + - ftape_udelay_count - 1) / ftape_udelay_time; - volatile int i; - - while (count-- > 0) { - for (i = 0; i < 20; ++i); - } -} - -void ftape_udelay_calibrate(void) -{ - ftape_calibrate("ftape_udelay", - ftape_udelay, &ftape_udelay_count, &ftape_udelay_time); -} - -/* Delay (msec) routine. - */ -void ftape_sleep(unsigned int time) -{ - TRACE_FUN(ft_t_any); - - time *= 1000; /* msecs -> usecs */ - if (time < FT_USPT) { - /* Time too small for scheduler, do a busy wait ! */ - ftape_udelay(time); - } else { - long timeout; - unsigned long flags; - unsigned int ticks = (time + FT_USPT - 1) / FT_USPT; - - TRACE(ft_t_any, "%d msec, %d ticks", time/1000, ticks); - timeout = ticks; - save_flags(flags); - sti(); - msleep_interruptible(jiffies_to_msecs(timeout)); - /* Mmm. Isn't current->blocked == 0xffffffff ? - */ - if (signal_pending(current)) { - TRACE(ft_t_err, "awoken by non-blocked signal :-("); - } - restore_flags(flags); - } - TRACE_EXIT; -} - -/* send a command or parameter to the drive - * Generates # of step pulses. - */ -static inline int ft_send_to_drive(int arg) -{ - /* Always wait for a command_timeout period to separate - * individuals commands and/or parameters. - */ - ftape_sleep(3 * FT_MILLISECOND); - /* Keep cylinder nr within range, step towards home if possible. - */ - if (ftape_current_cylinder >= arg) { - return fdc_seek(ftape_current_cylinder - arg); - } else { - return fdc_seek(ftape_current_cylinder + arg); - } -} - -/* forward */ int ftape_report_raw_drive_status(int *status); - -static int ft_check_cmd_restrictions(qic117_cmd_t command) -{ - int status = -1; - TRACE_FUN(ft_t_any); - - TRACE(ft_t_flow, "%s", qic117_cmds[command].name); - /* A new motion command during an uninterruptible (motion) - * command requires a ready status before the new command can - * be issued. Otherwise a new motion command needs to be - * checked against required status. - */ - if (qic117_cmds[command].cmd_type == motion && - qic117_cmds[ftape_current_command].non_intr) { - ftape_report_raw_drive_status(&status); - if ((status & QIC_STATUS_READY) == 0) { - TRACE(ft_t_noise, - "motion cmd (%d) during non-intr cmd (%d)", - command, ftape_current_command); - TRACE(ft_t_noise, "waiting until drive gets ready"); - ftape_ready_wait(ftape_timeout.seek, - &status); - } - } - if (qic117_cmds[command].mask != 0) { - __u8 difference; - /* Some commands do require a certain status: - */ - if (status == -1) { /* not yet set */ - ftape_report_raw_drive_status(&status); - } - difference = ((status ^ qic117_cmds[command].state) & - qic117_cmds[command].mask); - /* Wait until the drive gets - * ready. This may last forever if - * the drive never gets ready... - */ - while ((difference & QIC_STATUS_READY) != 0) { - TRACE(ft_t_noise, "command %d issued while not ready", - command); - TRACE(ft_t_noise, "waiting until drive gets ready"); - if (ftape_ready_wait(ftape_timeout.seek, - &status) == -EINTR) { - /* Bail out on signal ! - */ - TRACE_ABORT(-EINTR, ft_t_warn, - "interrupted by non-blockable signal"); - } - difference = ((status ^ qic117_cmds[command].state) & - qic117_cmds[command].mask); - } - while ((difference & QIC_STATUS_ERROR) != 0) { - int err; - qic117_cmd_t cmd; - - TRACE(ft_t_noise, - "command %d issued while error pending", - command); - TRACE(ft_t_noise, "clearing error status"); - ftape_report_error(&err, &cmd, 1); - ftape_report_raw_drive_status(&status); - difference = ((status ^ qic117_cmds[command].state) & - qic117_cmds[command].mask); - if ((difference & QIC_STATUS_ERROR) != 0) { - /* Bail out on fatal signal ! - */ - FT_SIGNAL_EXIT(_NEVER_BLOCK); - } - } - if (difference) { - /* Any remaining difference can't be solved - * here. - */ - if (difference & (QIC_STATUS_CARTRIDGE_PRESENT | - QIC_STATUS_NEW_CARTRIDGE | - QIC_STATUS_REFERENCED)) { - TRACE(ft_t_warn, - "Fatal: tape removed or reinserted !"); - ft_failure = 1; - } else { - TRACE(ft_t_err, "wrong state: 0x%02x should be: 0x%02x", - status & qic117_cmds[command].mask, - qic117_cmds[command].state); - } - TRACE_EXIT -EIO; - } - if (~status & QIC_STATUS_READY & qic117_cmds[command].mask) { - TRACE_ABORT(-EBUSY, ft_t_err, "Bad: still busy!"); - } - } - TRACE_EXIT 0; -} - -/* Issue a tape command: - */ -int ftape_command(qic117_cmd_t command) -{ - int result = 0; - static int level; - TRACE_FUN(ft_t_any); - - if ((unsigned int)command > NR_ITEMS(qic117_cmds)) { - /* This is a bug we'll want to know about too. - */ - TRACE_ABORT(-EIO, ft_t_bug, "bug - bad command: %d", command); - } - if (++level > 5) { /* This is a bug we'll want to know about. */ - --level; - TRACE_ABORT(-EIO, ft_t_bug, "bug - recursion for command: %d", - command); - } - /* disable logging and restriction check for some commands, - * check all other commands that have a prescribed starting - * status. - */ - if (diagnostic_mode) { - TRACE(ft_t_flow, "diagnostic command %d", command); - } else if (command == QIC_REPORT_DRIVE_STATUS || - command == QIC_REPORT_NEXT_BIT) { - TRACE(ft_t_any, "%s", qic117_cmds[command].name); - } else { - TRACE_CATCH(ft_check_cmd_restrictions(command), --level); - } - /* Now all conditions are met or result was < 0. - */ - result = ft_send_to_drive((unsigned int)command); - if (qic117_cmds[command].cmd_type == motion && - command != QIC_LOGICAL_FORWARD && command != QIC_STOP_TAPE) { - ft_location.known = 0; - } - ftape_current_command = command; - --level; - TRACE_EXIT result; -} - -/* Send a tape command parameter: - * Generates command # of step pulses. - * Skips tape-status call ! - */ -int ftape_parameter(unsigned int parameter) -{ - TRACE_FUN(ft_t_any); - - TRACE(ft_t_flow, "called with parameter = %d", parameter); - TRACE_EXIT ft_send_to_drive(parameter + 2); -} - -/* Wait for the drive to get ready. - * timeout time in milli-seconds - * Returned status is valid if result != -EIO - * - * Should we allow to be killed by SIGINT? (^C) - * Would be nice at least for large timeouts. - */ -int ftape_ready_wait(unsigned int timeout, int *status) -{ - unsigned long t0; - unsigned int poll_delay; - int signal_retries; - TRACE_FUN(ft_t_any); - - /* the following ** REALLY ** reduces the system load when - * e.g. one simply rewinds or retensions. The tape is slow - * anyway. It is really not necessary to detect error - * conditions with 1/10 seconds granularity - * - * On my AMD 133MHZ 486: 100 ms: 23% system load - * 1 sec: 5% - * 5 sec: 0.6%, yeah - */ - if (timeout <= FT_SECOND) { - poll_delay = 100 * FT_MILLISECOND; - signal_retries = 20; /* two seconds */ - } else if (timeout < 20 * FT_SECOND) { - TRACE(ft_t_flow, "setting poll delay to 1 second"); - poll_delay = FT_SECOND; - signal_retries = 2; /* two seconds */ - } else { - TRACE(ft_t_flow, "setting poll delay to 5 seconds"); - poll_delay = 5 * FT_SECOND; - signal_retries = 1; /* five seconds */ - } - for (;;) { - t0 = jiffies; - TRACE_CATCH(ftape_report_raw_drive_status(status),); - if (*status & QIC_STATUS_READY) { - TRACE_EXIT 0; - } - if (!signal_retries--) { - FT_SIGNAL_EXIT(_NEVER_BLOCK); - } - if ((int)timeout >= 0) { - /* this will fail when jiffies wraps around about - * once every year :-) - */ - timeout -= ((jiffies - t0) * FT_SECOND) / HZ; - if (timeout <= 0) { - TRACE_ABORT(-ETIME, ft_t_err, "timeout"); - } - ftape_sleep(poll_delay); - timeout -= poll_delay; - } else { - ftape_sleep(poll_delay); - } - } - TRACE_EXIT -ETIME; -} - -/* Issue command and wait up to timeout milli seconds for drive ready - */ -int ftape_command_wait(qic117_cmd_t command, unsigned int timeout, int *status) -{ - int result; - - /* Drive should be ready, issue command - */ - result = ftape_command(command); - if (result >= 0) { - result = ftape_ready_wait(timeout, status); - } - return result; -} - -static int ftape_parameter_wait(unsigned int parm, unsigned int timeout, int *status) -{ - int result; - - /* Drive should be ready, issue command - */ - result = ftape_parameter(parm); - if (result >= 0) { - result = ftape_ready_wait(timeout, status); - } - return result; -} - -/*-------------------------------------------------------------------------- - * Report operations - */ - -/* Query the drive about its status. The command is sent and - result_length bits of status are returned (2 extra bits are read - for start and stop). */ - -int ftape_report_operation(int *status, - qic117_cmd_t command, - int result_length) -{ - int i, st3; - unsigned int t0; - unsigned int dt; - TRACE_FUN(ft_t_any); - - TRACE_CATCH(ftape_command(command),); - t0 = ftape_timestamp(); - i = 0; - do { - ++i; - ftape_sleep(3 * FT_MILLISECOND); /* see remark below */ - TRACE_CATCH(fdc_sense_drive_status(&st3),); - dt = ftape_timediff(t0, ftape_timestamp()); - /* Ack should be asserted within Ttimout + Tack = 6 msec. - * Looks like some drives fail to do this so extend this - * period to 300 msec. - */ - } while (!(st3 & ST3_TRACK_0) && dt < 300000); - if (!(st3 & ST3_TRACK_0)) { - TRACE(ft_t_err, - "No acknowledge after %u msec. (%i iter)", dt / 1000, i); - TRACE_ABORT(-EIO, ft_t_err, "timeout on Acknowledge"); - } - /* dt may be larger than expected because of other tasks - * scheduled while we were sleeping. - */ - if (i > 1 && dt > 6000) { - TRACE(ft_t_err, "Acknowledge after %u msec. (%i iter)", - dt / 1000, i); - } - *status = 0; - for (i = 0; i < result_length + 1; i++) { - TRACE_CATCH(ftape_command(QIC_REPORT_NEXT_BIT),); - TRACE_CATCH(fdc_sense_drive_status(&st3),); - if (i < result_length) { - *status |= ((st3 & ST3_TRACK_0) ? 1 : 0) << i; - } else if ((st3 & ST3_TRACK_0) == 0) { - TRACE_ABORT(-EIO, ft_t_err, "missing status stop bit"); - } - } - /* this command will put track zero and index back into normal state */ - (void)ftape_command(QIC_REPORT_NEXT_BIT); - TRACE_EXIT 0; -} - -/* Report the current drive status. */ - -int ftape_report_raw_drive_status(int *status) -{ - int result; - int count = 0; - TRACE_FUN(ft_t_any); - - do { - result = ftape_report_operation(status, - QIC_REPORT_DRIVE_STATUS, 8); - } while (result < 0 && ++count <= 3); - if (result < 0) { - TRACE_ABORT(-EIO, ft_t_err, - "report_operation failed after %d trials", count); - } - if ((*status & 0xff) == 0xff) { - TRACE_ABORT(-EIO, ft_t_err, - "impossible drive status 0xff"); - } - if (*status & QIC_STATUS_READY) { - ftape_current_command = QIC_NO_COMMAND; /* completed */ - } - ft_last_status.status.drive_status = (__u8)(*status & 0xff); - TRACE_EXIT 0; -} - -int ftape_report_drive_status(int *status) -{ - TRACE_FUN(ft_t_any); - - TRACE_CATCH(ftape_report_raw_drive_status(status),); - if (*status & QIC_STATUS_NEW_CARTRIDGE || - !(*status & QIC_STATUS_CARTRIDGE_PRESENT)) { - ft_failure = 1; /* will inhibit further operations */ - TRACE_EXIT -EIO; - } - if (*status & QIC_STATUS_READY && *status & QIC_STATUS_ERROR) { - /* Let caller handle all errors */ - TRACE_ABORT(1, ft_t_warn, "warning: error status set!"); - } - TRACE_EXIT 0; -} - -int ftape_report_error(unsigned int *error, - qic117_cmd_t *command, int report) -{ - static const ftape_error ftape_errors[] = QIC117_ERRORS; - int code; - TRACE_FUN(ft_t_any); - - TRACE_CATCH(ftape_report_operation(&code, QIC_REPORT_ERROR_CODE, 16),); - *error = (unsigned int)(code & 0xff); - *command = (qic117_cmd_t)((code>>8)&0xff); - /* remember hardware status, maybe useful for status ioctls - */ - ft_last_error.error.command = (__u8)*command; - ft_last_error.error.error = (__u8)*error; - if (!report) { - TRACE_EXIT 0; - } - if (*error == 0) { - TRACE_ABORT(0, ft_t_info, "No error"); - } - TRACE(ft_t_info, "errorcode: %d", *error); - if (*error < NR_ITEMS(ftape_errors)) { - TRACE(ft_t_noise, "%sFatal ERROR:", - (ftape_errors[*error].fatal ? "" : "Non-")); - TRACE(ft_t_noise, "%s ...", ftape_errors[*error].message); - } else { - TRACE(ft_t_noise, "Unknown ERROR !"); - } - if ((unsigned int)*command < NR_ITEMS(qic117_cmds) && - qic117_cmds[*command].name != NULL) { - TRACE(ft_t_noise, "... caused by command \'%s\'", - qic117_cmds[*command].name); - } else { - TRACE(ft_t_noise, "... caused by unknown command %d", - *command); - } - TRACE_EXIT 0; -} - -int ftape_report_configuration(qic_model *model, - unsigned int *rate, - int *qic_std, - int *tape_len) -{ - int result; - int config; - int status; - static const unsigned int qic_rates[ 4] = { 250, 2000, 500, 1000 }; - TRACE_FUN(ft_t_any); - - result = ftape_report_operation(&config, - QIC_REPORT_DRIVE_CONFIGURATION, 8); - if (result < 0) { - ft_last_status.status.drive_config = (__u8)0x00; - *model = prehistoric; - *rate = 500; - *qic_std = QIC_TAPE_QIC40; - *tape_len = 205; - TRACE_EXIT 0; - } else { - ft_last_status.status.drive_config = (__u8)(config & 0xff); - } - *rate = qic_rates[(config & QIC_CONFIG_RATE_MASK) >> QIC_CONFIG_RATE_SHIFT]; - result = ftape_report_operation(&status, QIC_REPORT_TAPE_STATUS, 8); - if (result < 0) { - ft_last_status.status.tape_status = (__u8)0x00; - /* pre- QIC117 rev C spec. drive, QIC_CONFIG_80 bit is valid. - */ - *qic_std = (config & QIC_CONFIG_80) ? - QIC_TAPE_QIC80 : QIC_TAPE_QIC40; - /* ?? how's about 425ft tapes? */ - *tape_len = (config & QIC_CONFIG_LONG) ? 307 : 0; - *model = pre_qic117c; - result = 0; - } else { - ft_last_status.status.tape_status = (__u8)(status & 0xff); - *model = post_qic117b; - TRACE(ft_t_any, "report tape status result = %02x", status); - /* post- QIC117 rev C spec. drive, QIC_CONFIG_80 bit is - * invalid. - */ - switch (status & QIC_TAPE_STD_MASK) { - case QIC_TAPE_QIC40: - case QIC_TAPE_QIC80: - case QIC_TAPE_QIC3020: - case QIC_TAPE_QIC3010: - *qic_std = status & QIC_TAPE_STD_MASK; - break; - default: - *qic_std = -1; - break; - } - switch (status & QIC_TAPE_LEN_MASK) { - case QIC_TAPE_205FT: - /* 205 or 425+ ft 550 Oe tape */ - *tape_len = 0; - break; - case QIC_TAPE_307FT: - /* 307.5 ft 550 Oe Extended Length (XL) tape */ - *tape_len = 307; - break; - case QIC_TAPE_VARIABLE: - /* Variable length 550 Oe tape */ - *tape_len = 0; - break; - case QIC_TAPE_1100FT: - /* 1100 ft 550 Oe tape */ - *tape_len = 1100; - break; - case QIC_TAPE_FLEX: - /* Variable length 900 Oe tape */ - *tape_len = 0; - break; - default: - *tape_len = -1; - break; - } - if (*qic_std == -1 || *tape_len == -1) { - TRACE(ft_t_any, - "post qic-117b spec drive with unknown tape"); - } - result = *tape_len == -1 ? -EIO : 0; - if (status & QIC_TAPE_WIDE) { - switch (*qic_std) { - case QIC_TAPE_QIC80: - TRACE(ft_t_info, "TR-1 tape detected"); - break; - case QIC_TAPE_QIC3010: - TRACE(ft_t_info, "TR-2 tape detected"); - break; - case QIC_TAPE_QIC3020: - TRACE(ft_t_info, "TR-3 tape detected"); - break; - default: - TRACE(ft_t_warn, - "Unknown Travan tape type detected"); - break; - } - } - } - TRACE_EXIT (result < 0) ? -EIO : 0; -} - -static int ftape_report_rom_version(int *version) -{ - - if (ftape_report_operation(version, QIC_REPORT_ROM_VERSION, 8) < 0) { - return -EIO; - } else { - return 0; - } -} - -void ftape_report_vendor_id(unsigned int *id) -{ - int result; - TRACE_FUN(ft_t_any); - - /* We'll try to get a vendor id from the drive. First - * according to the QIC-117 spec, a 16-bit id is requested. - * If that fails we'll try an 8-bit version, otherwise we'll - * try an undocumented query. - */ - result = ftape_report_operation((int *) id, QIC_REPORT_VENDOR_ID, 16); - if (result < 0) { - result = ftape_report_operation((int *) id, - QIC_REPORT_VENDOR_ID, 8); - if (result < 0) { - /* The following is an undocumented call found - * in the CMS code. - */ - result = ftape_report_operation((int *) id, 24, 8); - if (result < 0) { - *id = UNKNOWN_VENDOR; - } else { - TRACE(ft_t_noise, "got old 8 bit id: %04x", - *id); - *id |= 0x20000; - } - } else { - TRACE(ft_t_noise, "got 8 bit id: %04x", *id); - *id |= 0x10000; - } - } else { - TRACE(ft_t_noise, "got 16 bit id: %04x", *id); - } - if (*id == 0x0047) { - int version; - int sign; - - if (ftape_report_rom_version(&version) < 0) { - TRACE(ft_t_bug, "report rom version failed"); - TRACE_EXIT; - } - TRACE(ft_t_noise, "CMS rom version: %d", version); - ftape_command(QIC_ENTER_DIAGNOSTIC_1); - ftape_command(QIC_ENTER_DIAGNOSTIC_1); - diagnostic_mode = 1; - if (ftape_report_operation(&sign, 9, 8) < 0) { - unsigned int error; - qic117_cmd_t command; - - ftape_report_error(&error, &command, 1); - ftape_command(QIC_ENTER_PRIMARY_MODE); - diagnostic_mode = 0; - TRACE_EXIT; /* failure ! */ - } else { - TRACE(ft_t_noise, "CMS signature: %02x", sign); - } - if (sign == 0xa5) { - result = ftape_report_operation(&sign, 37, 8); - if (result < 0) { - if (version >= 63) { - *id = 0x8880; - TRACE(ft_t_noise, - "This is an Iomega drive !"); - } else { - *id = 0x0047; - TRACE(ft_t_noise, - "This is a real CMS drive !"); - } - } else { - *id = 0x0047; - TRACE(ft_t_noise, "CMS status: %d", sign); - } - } else { - *id = UNKNOWN_VENDOR; - } - ftape_command(QIC_ENTER_PRIMARY_MODE); - diagnostic_mode = 0; - } - TRACE_EXIT; -} - -static int qic_rate_code(unsigned int rate) -{ - switch (rate) { - case 250: - return QIC_CONFIG_RATE_250; - case 500: - return QIC_CONFIG_RATE_500; - case 1000: - return QIC_CONFIG_RATE_1000; - case 2000: - return QIC_CONFIG_RATE_2000; - default: - return QIC_CONFIG_RATE_500; - } -} - -static int ftape_set_rate_test(unsigned int *max_rate) -{ - unsigned int error; - qic117_cmd_t command; - int status; - int supported = 0; - TRACE_FUN(ft_t_any); - - /* Check if the drive does support the select rate command - * by testing all different settings. If any one is accepted - * we assume the command is supported, else not. - */ - for (*max_rate = 2000; *max_rate >= 250; *max_rate /= 2) { - if (ftape_command(QIC_SELECT_RATE) < 0) { - continue; - } - if (ftape_parameter_wait(qic_rate_code(*max_rate), - 1 * FT_SECOND, &status) < 0) { - continue; - } - if (status & QIC_STATUS_ERROR) { - ftape_report_error(&error, &command, 0); - continue; - } - supported = 1; /* did accept a request */ - break; - } - TRACE(ft_t_noise, "Select Rate command is%s supported", - supported ? "" : " not"); - TRACE_EXIT supported; -} - -int ftape_set_data_rate(unsigned int new_rate /* Kbps */, unsigned int qic_std) -{ - int status; - int result = 0; - unsigned int data_rate = new_rate; - static int supported; - int rate_changed = 0; - qic_model dummy_model; - unsigned int dummy_qic_std, dummy_tape_len; - TRACE_FUN(ft_t_any); - - if (ft_drive_max_rate == 0) { /* first time */ - supported = ftape_set_rate_test(&ft_drive_max_rate); - } - if (supported) { - ftape_command(QIC_SELECT_RATE); - result = ftape_parameter_wait(qic_rate_code(new_rate), - 1 * FT_SECOND, &status); - if (result >= 0 && !(status & QIC_STATUS_ERROR)) { - rate_changed = 1; - } - } - TRACE_CATCH(result = ftape_report_configuration(&dummy_model, - &data_rate, - &dummy_qic_std, - &dummy_tape_len),); - if (data_rate != new_rate) { - if (!supported) { - TRACE(ft_t_warn, "Rate change not supported!"); - } else if (rate_changed) { - TRACE(ft_t_warn, "Requested: %d, got %d", - new_rate, data_rate); - } else { - TRACE(ft_t_warn, "Rate change failed!"); - } - result = -EINVAL; - } - /* - * Set data rate and write precompensation as specified: - * - * | QIC-40/80 | QIC-3010/3020 - * rate | precomp | precomp - * ----------+-------------+-------------- - * 250 Kbps. | 250 ns. | 0 ns. - * 500 Kbps. | 125 ns. | 0 ns. - * 1 Mbps. | 42 ns. | 0 ns. - * 2 Mbps | N/A | 0 ns. - */ - if ((qic_std == QIC_TAPE_QIC40 && data_rate > 500) || - (qic_std == QIC_TAPE_QIC80 && data_rate > 1000)) { - TRACE_ABORT(-EINVAL, - ft_t_warn, "Datarate too high for QIC-mode"); - } - TRACE_CATCH(fdc_set_data_rate(data_rate),_res = -EINVAL); - ft_data_rate = data_rate; - if (qic_std == QIC_TAPE_QIC40 || qic_std == QIC_TAPE_QIC80) { - switch (data_rate) { - case 250: - fdc_set_write_precomp(250); - break; - default: - case 500: - fdc_set_write_precomp(125); - break; - case 1000: - fdc_set_write_precomp(42); - break; - } - } else { - fdc_set_write_precomp(0); - } - TRACE_EXIT result; -} - -/* The next two functions are used to cope with excessive overrun errors - */ -int ftape_increase_threshold(void) -{ - TRACE_FUN(ft_t_flow); - - if (fdc.type < i82077 || ft_fdc_threshold >= 12) { - TRACE_ABORT(-EIO, ft_t_err, "cannot increase fifo threshold"); - } - if (fdc_fifo_threshold(++ft_fdc_threshold, NULL, NULL, NULL) < 0) { - TRACE(ft_t_err, "cannot increase fifo threshold"); - ft_fdc_threshold --; - fdc_reset(); - } - TRACE(ft_t_info, "New FIFO threshold: %d", ft_fdc_threshold); - TRACE_EXIT 0; -} - -int ftape_half_data_rate(void) -{ - if (ft_data_rate < 500) { - return -1; - } - if (ftape_set_data_rate(ft_data_rate / 2, ft_qic_std) < 0) { - return -EIO; - } - ftape_calc_timeouts(ft_qic_std, ft_data_rate, ftape_tape_len); - return 0; -} - -/* Seek the head to the specified track. - */ -int ftape_seek_head_to_track(unsigned int track) -{ - int status; - TRACE_FUN(ft_t_any); - - ft_location.track = -1; /* remains set in case of error */ - if (track >= ft_tracks_per_tape) { - TRACE_ABORT(-EINVAL, ft_t_bug, "track out of bounds"); - } - TRACE(ft_t_flow, "seeking track %d", track); - TRACE_CATCH(ftape_command(QIC_SEEK_HEAD_TO_TRACK),); - TRACE_CATCH(ftape_parameter_wait(track, ftape_timeout.head_seek, - &status),); - ft_location.track = track; - ftape_might_be_off_track = 0; - TRACE_EXIT 0; -} - -int ftape_wakeup_drive(wake_up_types method) -{ - int status; - int motor_on = 0; - TRACE_FUN(ft_t_any); - - switch (method) { - case wake_up_colorado: - TRACE_CATCH(ftape_command(QIC_PHANTOM_SELECT),); - TRACE_CATCH(ftape_parameter(0 /* ft_drive_sel ?? */),); - break; - case wake_up_mountain: - TRACE_CATCH(ftape_command(QIC_SOFT_SELECT),); - ftape_sleep(FT_MILLISECOND); /* NEEDED */ - TRACE_CATCH(ftape_parameter(18),); - break; - case wake_up_insight: - ftape_sleep(100 * FT_MILLISECOND); - motor_on = 1; - fdc_motor(motor_on); /* enable is done by motor-on */ - case no_wake_up: - break; - default: - TRACE_EXIT -ENODEV; /* unknown wakeup method */ - break; - } - /* If wakeup succeeded we shouldn't get an error here.. - */ - TRACE_CATCH(ftape_report_raw_drive_status(&status), - if (motor_on) { - fdc_motor(0); - }); - TRACE_EXIT 0; -} - -int ftape_put_drive_to_sleep(wake_up_types method) -{ - TRACE_FUN(ft_t_any); - - switch (method) { - case wake_up_colorado: - TRACE_CATCH(ftape_command(QIC_PHANTOM_DESELECT),); - break; - case wake_up_mountain: - TRACE_CATCH(ftape_command(QIC_SOFT_DESELECT),); - break; - case wake_up_insight: - fdc_motor(0); /* enable is done by motor-on */ - case no_wake_up: /* no wakeup / no sleep ! */ - break; - default: - TRACE_EXIT -ENODEV; /* unknown wakeup method */ - } - TRACE_EXIT 0; -} - -int ftape_reset_drive(void) -{ - int result = 0; - int status; - unsigned int err_code; - qic117_cmd_t err_command; - int i; - TRACE_FUN(ft_t_any); - - /* We want to re-establish contact with our drive. Fire a - * number of reset commands (single step pulses) and pray for - * success. - */ - for (i = 0; i < 2; ++i) { - TRACE(ft_t_flow, "Resetting fdc"); - fdc_reset(); - ftape_sleep(10 * FT_MILLISECOND); - TRACE(ft_t_flow, "Reset command to drive"); - result = ftape_command(QIC_RESET); - if (result == 0) { - ftape_sleep(1 * FT_SECOND); /* drive not - * accessible - * during 1 second - */ - TRACE(ft_t_flow, "Re-selecting drive"); - - /* Strange, the QIC-117 specs don't mention - * this but the drive gets deselected after a - * soft reset ! So we need to enable it - * again. - */ - if (ftape_wakeup_drive(ft_drive_type.wake_up) < 0) { - TRACE(ft_t_err, "Wakeup failed !"); - } - TRACE(ft_t_flow, "Waiting until drive gets ready"); - result= ftape_ready_wait(ftape_timeout.reset, &status); - if (result == 0 && (status & QIC_STATUS_ERROR)) { - result = ftape_report_error(&err_code, - &err_command, 1); - if (result == 0 && err_code == 27) { - /* Okay, drive saw reset - * command and responded as it - * should - */ - break; - } else { - result = -EIO; - } - } else { - result = -EIO; - } - } - FT_SIGNAL_EXIT(_DONT_BLOCK); - } - if (result != 0) { - TRACE(ft_t_err, "General failure to reset tape drive"); - } else { - /* Restore correct settings: keep original rate - */ - ftape_set_data_rate(ft_data_rate, ft_qic_std); - } - ftape_init_drive_needed = 1; - TRACE_EXIT result; -} diff --git a/drivers/char/ftape/lowlevel/ftape-io.h b/drivers/char/ftape/lowlevel/ftape-io.h deleted file mode 100644 index 26a7baad871..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-io.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef _FTAPE_IO_H -#define _FTAPE_IO_H - -/* - * Copyright (C) 1993-1996 Bas Laarhoven, - * (C) 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-io.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:18 $ - * - * This file contains definitions for the glue part of the - * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. - */ - -#include -#include - -typedef struct { - unsigned int seek; - unsigned int reset; - unsigned int rewind; - unsigned int head_seek; - unsigned int stop; - unsigned int pause; -} ft_timeout_table; - -typedef enum { - prehistoric, pre_qic117c, post_qic117b, post_qic117d -} qic_model; - -/* - * ftape-io.c defined global vars. - */ -extern ft_timeout_table ftape_timeout; -extern unsigned int ftape_tape_len; -extern volatile qic117_cmd_t ftape_current_command; -extern const struct qic117_command_table qic117_cmds[]; -extern int ftape_might_be_off_track; - -/* - * ftape-io.c defined global functions. - */ -extern void ftape_udelay(unsigned int usecs); -extern void ftape_udelay_calibrate(void); -extern void ftape_sleep(unsigned int time); -extern void ftape_report_vendor_id(unsigned int *id); -extern int ftape_command(qic117_cmd_t command); -extern int ftape_command_wait(qic117_cmd_t command, - unsigned int timeout, - int *status); -extern int ftape_parameter(unsigned int parameter); -extern int ftape_report_operation(int *status, - qic117_cmd_t command, - int result_length); -extern int ftape_report_configuration(qic_model *model, - unsigned int *rate, - int *qic_std, - int *tape_len); -extern int ftape_report_drive_status(int *status); -extern int ftape_report_raw_drive_status(int *status); -extern int ftape_report_status(int *status); -extern int ftape_ready_wait(unsigned int timeout, int *status); -extern int ftape_seek_head_to_track(unsigned int track); -extern int ftape_set_data_rate(unsigned int new_rate, unsigned int qic_std); -extern int ftape_report_error(unsigned int *error, - qic117_cmd_t *command, - int report); -extern int ftape_reset_drive(void); -extern int ftape_put_drive_to_sleep(wake_up_types method); -extern int ftape_wakeup_drive(wake_up_types method); -extern int ftape_increase_threshold(void); -extern int ftape_half_data_rate(void); - -#endif diff --git a/drivers/char/ftape/lowlevel/ftape-proc.c b/drivers/char/ftape/lowlevel/ftape-proc.c deleted file mode 100644 index e805b15e0a1..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-proc.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 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-proc.c,v $ - * $Revision: 1.11 $ - * $Date: 1997/10/24 14:47:37 $ - * - * This file contains the procfs interface for the - * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. - - * Old code removed, switched to dynamic proc entry. - */ - - -#if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) - -#include - -#include -#include -#include - -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-proc.h" -#include "../lowlevel/ftape-tracing.h" - -static size_t get_driver_info(char *buf) -{ - const char *debug_level[] = { "bugs" , - "errors", - "warnings", - "informational", - "noisy", - "program flow", - "fdc and dma", - "data flow", - "anything" }; - - return sprintf(buf, - "version : %s\n" - "used data rate: %d kbit/sec\n" - "dma memory : %d kb\n" - "debug messages: %s\n", - FTAPE_VERSION, - ft_data_rate, - FT_BUFF_SIZE * ft_nr_buffers >> 10, - debug_level[TRACE_LEVEL]); -} - -static size_t get_tapedrive_info(char *buf) -{ - return sprintf(buf, - "vendor id : 0x%04x\n" - "drive name: %s\n" - "wind speed: %d ips\n" - "wakeup : %s\n" - "max. rate : %d kbit/sec\n", - ft_drive_type.vendor_id, - ft_drive_type.name, - ft_drive_type.speed, - ((ft_drive_type.wake_up == no_wake_up) - ? "No wakeup needed" : - ((ft_drive_type.wake_up == wake_up_colorado) - ? "Colorado" : - ((ft_drive_type.wake_up == wake_up_mountain) - ? "Mountain" : - ((ft_drive_type.wake_up == wake_up_insight) - ? "Motor on" : - "Unknown")))), - ft_drive_max_rate); -} - -static size_t get_cartridge_info(char *buf) -{ - if (ftape_init_drive_needed) { - return sprintf(buf, "uninitialized\n"); - } - if (ft_no_tape) { - return sprintf(buf, "no cartridge inserted\n"); - } - return sprintf(buf, - "segments : %5d\n" - "tracks : %5d\n" - "length : %5dft\n" - "formatted : %3s\n" - "writable : %3s\n" - "QIC spec. : QIC-%s\n" - "fmt-code : %1d\n", - ft_segments_per_track, - ft_tracks_per_tape, - ftape_tape_len, - (ft_formatted == 1) ? "yes" : "no", - (ft_write_protected == 1) ? "no" : "yes", - ((ft_qic_std == QIC_TAPE_QIC40) ? "40" : - ((ft_qic_std == QIC_TAPE_QIC80) ? "80" : - ((ft_qic_std == QIC_TAPE_QIC3010) ? "3010" : - ((ft_qic_std == QIC_TAPE_QIC3020) ? "3020" : - "???")))), - ft_format_code); -} - -static size_t get_controller_info(char *buf) -{ - const char *fdc_name[] = { "no fdc", - "i8272", - "i82077", - "i82077AA", - "Colorado FC-10 or FC-20", - "i82078", - "i82078_1" }; - - return sprintf(buf, - "FDC type : %s\n" - "FDC base : 0x%03x\n" - "FDC irq : %d\n" - "FDC dma : %d\n" - "FDC thr. : %d\n" - "max. rate : %d kbit/sec\n", - ft_mach2 ? "Mountain MACH-2" : fdc_name[fdc.type], - fdc.sra, fdc.irq, fdc.dma, - ft_fdc_threshold, ft_fdc_max_rate); -} - -static size_t get_history_info(char *buf) -{ - size_t len; - - len = sprintf(buf, - "\nFDC isr statistics\n" - " id_am_errors : %3d\n" - " id_crc_errors : %3d\n" - " data_am_errors : %3d\n" - " data_crc_errors : %3d\n" - " overrun_errors : %3d\n" - " no_data_errors : %3d\n" - " retries : %3d\n", - ft_history.id_am_errors, ft_history.id_crc_errors, - ft_history.data_am_errors, ft_history.data_crc_errors, - ft_history.overrun_errors, ft_history.no_data_errors, - ft_history.retries); - len += sprintf(buf + len, - "\nECC statistics\n" - " crc_errors : %3d\n" - " crc_failures : %3d\n" - " ecc_failures : %3d\n" - " sectors corrected: %3d\n", - ft_history.crc_errors, ft_history.crc_failures, - ft_history.ecc_failures, ft_history.corrected); - len += sprintf(buf + len, - "\ntape quality statistics\n" - " media defects : %3d\n", - ft_history.defects); - len += sprintf(buf + len, - "\ntape motion statistics\n" - " repositions : %3d\n", - ft_history.rewinds); - return len; -} - -static int ftape_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - char *ptr = page; - size_t len; - - ptr += sprintf(ptr, "Kernel Driver\n\n"); - ptr += get_driver_info(ptr); - ptr += sprintf(ptr, "\nTape Drive\n\n"); - ptr += get_tapedrive_info(ptr); - ptr += sprintf(ptr, "\nFDC Controller\n\n"); - ptr += get_controller_info(ptr); - ptr += sprintf(ptr, "\nTape Cartridge\n\n"); - ptr += get_cartridge_info(ptr); - ptr += sprintf(ptr, "\nHistory Record\n\n"); - ptr += get_history_info(ptr); - - len = strlen(page); - *start = NULL; - if (off+count >= len) { - *eof = 1; - } else { - *eof = 0; - } - return len; -} - -int __init ftape_proc_init(void) -{ - return create_proc_read_entry("ftape", 0, &proc_root, - ftape_read_proc, NULL) != NULL; -} - -void ftape_proc_destroy(void) -{ - remove_proc_entry("ftape", &proc_root); -} - -#endif /* defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) */ diff --git a/drivers/char/ftape/lowlevel/ftape-proc.h b/drivers/char/ftape/lowlevel/ftape-proc.h deleted file mode 100644 index 264dfcc1d22..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-proc.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _FTAPE_PROC_H -#define _FTAPE_PROC_H - -/* - * Copyright (C) 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-proc.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:20 $ - * - * This file contains definitions for the procfs interface of the - * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. - */ - -#include - -extern int ftape_proc_init(void); -extern void ftape_proc_destroy(void); - -#endif diff --git a/drivers/char/ftape/lowlevel/ftape-read.c b/drivers/char/ftape/lowlevel/ftape-read.c deleted file mode 100644 index d967d8cd86d..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-read.c +++ /dev/null @@ -1,621 +0,0 @@ -/* - * 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-read.c,v $ - * $Revision: 1.6 $ - * $Date: 1997/10/21 14:39:22 $ - * - * This file contains the reading code - * for the QIC-117 floppy-tape driver for Linux. - * - */ - -#include -#include -#include - -#include -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-write.h" -#include "../lowlevel/ftape-ecc.h" -#include "../lowlevel/ftape-bsm.h" - -/* Global vars. - */ - -/* Local vars. - */ - -void ftape_zap_read_buffers(void) -{ - int i; - - for (i = 0; i < ft_nr_buffers; ++i) { -/* changed to "fit" with dynamic allocation of tape_buffer. --khp */ - ft_buffer[i]->status = waiting; - ft_buffer[i]->bytes = 0; - ft_buffer[i]->skip = 0; - ft_buffer[i]->retry = 0; - } -/* ftape_reset_buffer(); */ -} - -static SectorMap convert_sector_map(buffer_struct * buff) -{ - int i = 0; - SectorMap bad_map = ftape_get_bad_sector_entry(buff->segment_id); - SectorMap src_map = buff->soft_error_map | buff->hard_error_map; - SectorMap dst_map = 0; - TRACE_FUN(ft_t_any); - - if (bad_map || src_map) { - TRACE(ft_t_flow, "bad_map = 0x%08lx", (long) bad_map); - TRACE(ft_t_flow, "src_map = 0x%08lx", (long) src_map); - } - while (bad_map) { - while ((bad_map & 1) == 0) { - if (src_map & 1) { - dst_map |= (1 << i); - } - src_map >>= 1; - bad_map >>= 1; - ++i; - } - /* (bad_map & 1) == 1 */ - src_map >>= 1; - bad_map >>= 1; - } - if (src_map) { - dst_map |= (src_map << i); - } - if (dst_map) { - TRACE(ft_t_flow, "dst_map = 0x%08lx", (long) dst_map); - } - TRACE_EXIT dst_map; -} - -static int correct_and_copy_fraction(buffer_struct *buff, __u8 * destination, - int start, int size) -{ - struct memory_segment mseg; - int result; - SectorMap read_bad; - TRACE_FUN(ft_t_any); - - mseg.read_bad = convert_sector_map(buff); - mseg.marked_bad = 0; /* not used... */ - mseg.blocks = buff->bytes / FT_SECTOR_SIZE; - mseg.data = buff->address; - /* If there are no data sectors we can skip this segment. - */ - if (mseg.blocks <= 3) { - TRACE_ABORT(0, ft_t_noise, "empty segment"); - } - read_bad = mseg.read_bad; - ft_history.crc_errors += count_ones(read_bad); - result = ftape_ecc_correct_data(&mseg); - if (read_bad != 0 || mseg.corrected != 0) { - TRACE(ft_t_noise, "crc error map: 0x%08lx", (unsigned long)read_bad); - TRACE(ft_t_noise, "corrected map: 0x%08lx", (unsigned long)mseg.corrected); - ft_history.corrected += count_ones(mseg.corrected); - } - if (result == ECC_CORRECTED || result == ECC_OK) { - if (result == ECC_CORRECTED) { - TRACE(ft_t_info, "ecc corrected segment: %d", buff->segment_id); - } - if(start < 0) { - start= 0; - } - if((start+size) > ((mseg.blocks - 3) * FT_SECTOR_SIZE)) { - size = (mseg.blocks - 3) * FT_SECTOR_SIZE - start; - } - if (size < 0) { - size= 0; - } - if(size > 0) { - memcpy(destination + start, mseg.data + start, size); - } - if ((read_bad ^ mseg.corrected) & mseg.corrected) { - /* sectors corrected without crc errors set */ - ft_history.crc_failures++; - } - TRACE_EXIT size; /* (mseg.blocks - 3) * FT_SECTOR_SIZE; */ - } else { - ft_history.ecc_failures++; - TRACE_ABORT(-EAGAIN, - ft_t_err, "ecc failure on segment %d", - buff->segment_id); - } - TRACE_EXIT 0; -} - -/* Read given segment into buffer at address. - */ -int ftape_read_segment_fraction(const int segment_id, - void *address, - const ft_read_mode_t read_mode, - const int start, - const int size) -{ - int result = 0; - int retry = 0; - int bytes_read = 0; - int read_done = 0; - TRACE_FUN(ft_t_flow); - - ft_history.used |= 1; - TRACE(ft_t_data_flow, "segment_id = %d", segment_id); - if (ft_driver_state != reading) { - TRACE(ft_t_noise, "calling ftape_abort_operation"); - TRACE_CATCH(ftape_abort_operation(),); - ftape_set_state(reading); - } - for(;;) { - buffer_struct *tail; - /* Allow escape from this loop on signal ! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - /* Search all full buffers for the first matching the - * wanted segment. Clear other buffers on the fly. - */ - tail = ftape_get_buffer(ft_queue_tail); - while (!read_done && tail->status == done) { - /* Allow escape from this loop on signal ! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - if (tail->segment_id == segment_id) { - /* If out buffer is already full, - * return its contents. - */ - TRACE(ft_t_flow, "found segment in cache: %d", - segment_id); - if (tail->deleted) { - /* Return a value that - * read_header_segment - * understands. As this - * should only occur when - * searching for the header - * segments it shouldn't be - * misinterpreted elsewhere. - */ - TRACE_EXIT 0; - } - result = correct_and_copy_fraction( - tail, - address, - start, - size); - TRACE(ft_t_flow, "segment contains (bytes): %d", - result); - if (result < 0) { - if (result != -EAGAIN) { - TRACE_EXIT result; - } - /* keep read_done == 0, will - * trigger - * ftape_abort_operation - * because reading wrong - * segment. - */ - TRACE(ft_t_err, "ecc failed, retry"); - ++retry; - } else { - read_done = 1; - bytes_read = result; - } - } else { - TRACE(ft_t_flow,"zapping segment in cache: %d", - tail->segment_id); - } - tail->status = waiting; - tail = ftape_next_buffer(ft_queue_tail); - } - if (!read_done && tail->status == reading) { - if (tail->segment_id == segment_id) { - switch(ftape_wait_segment(reading)) { - case 0: - break; - case -EINTR: - TRACE_ABORT(-EINTR, ft_t_warn, - "interrupted by " - "non-blockable signal"); - break; - default: - TRACE(ft_t_noise, - "wait_segment failed"); - ftape_abort_operation(); - ftape_set_state(reading); - break; - } - } else { - /* We're reading the wrong segment, - * stop runner. - */ - TRACE(ft_t_noise, "reading wrong segment"); - ftape_abort_operation(); - ftape_set_state(reading); - } - } - /* should runner stop ? - */ - if (ft_runner_status == aborting) { - buffer_struct *head = ftape_get_buffer(ft_queue_head); - switch(head->status) { - case error: - ft_history.defects += - count_ones(head->hard_error_map); - case reading: - head->status = waiting; - break; - default: - break; - } - TRACE_CATCH(ftape_dumb_stop(),); - } else { - /* If just passed last segment on tape: wait - * for BOT or EOT mark. Sets ft_runner_status to - * idle if at lEOT and successful - */ - TRACE_CATCH(ftape_handle_logical_eot(),); - } - /* If we got a segment: quit, or else retry up to limit. - * - * If segment to read is empty, do not start runner for it, - * but wait for next read call. - */ - if (read_done || - ftape_get_bad_sector_entry(segment_id) == EMPTY_SEGMENT ) { - /* bytes_read = 0; should still be zero */ - TRACE_EXIT bytes_read; - - } - if (retry > FT_RETRIES_ON_ECC_ERROR) { - ft_history.defects++; - TRACE_ABORT(-ENODATA, ft_t_err, - "too many retries on ecc failure"); - } - /* Now at least one buffer is empty ! - * Restart runner & tape if needed. - */ - TRACE(ft_t_any, "head: %d, tail: %d, ft_runner_status: %d", - ftape_buffer_id(ft_queue_head), - ftape_buffer_id(ft_queue_tail), - ft_runner_status); - TRACE(ft_t_any, "buffer[].status, [head]: %d, [tail]: %d", - ftape_get_buffer(ft_queue_head)->status, - ftape_get_buffer(ft_queue_tail)->status); - tail = ftape_get_buffer(ft_queue_tail); - if (tail->status == waiting) { - buffer_struct *head = ftape_get_buffer(ft_queue_head); - - ftape_setup_new_segment(head, segment_id, -1); - if (read_mode == FT_RD_SINGLE) { - /* disable read-ahead */ - head->next_segment = 0; - } - ftape_calc_next_cluster(head); - if (ft_runner_status == idle) { - result = ftape_start_tape(segment_id, - head->sector_offset); - if (result < 0) { - TRACE_ABORT(result, ft_t_err, "Error: " - "segment %d unreachable", - segment_id); - } - } - head->status = reading; - fdc_setup_read_write(head, FDC_READ); - } - } - /* not reached */ - TRACE_EXIT -EIO; -} - -int ftape_read_header_segment(__u8 *address) -{ - int result; - int header_segment; - int first_failed = 0; - int status; - TRACE_FUN(ft_t_flow); - - ft_used_header_segment = -1; - TRACE_CATCH(ftape_report_drive_status(&status),); - TRACE(ft_t_flow, "reading..."); - /* We're looking for the first header segment. - * A header segment cannot contain bad sectors, therefor at the - * tape start, segments with bad sectors are (according to QIC-40/80) - * written with deleted data marks and must be skipped. - */ - memset(address, '\0', (FT_SECTORS_PER_SEGMENT - 3) * FT_SECTOR_SIZE); - result = 0; -#define HEADER_SEGMENT_BOUNDARY 68 /* why not 42? */ - for (header_segment = 0; - header_segment < HEADER_SEGMENT_BOUNDARY && result == 0; - ++header_segment) { - /* Set no read-ahead, the isr will force read-ahead whenever - * it encounters deleted data ! - */ - result = ftape_read_segment(header_segment, - address, - FT_RD_SINGLE); - if (result < 0 && !first_failed) { - TRACE(ft_t_err, "header segment damaged, trying backup"); - first_failed = 1; - result = 0; /* force read of next (backup) segment */ - } - } - if (result < 0 || header_segment >= HEADER_SEGMENT_BOUNDARY) { - TRACE_ABORT(-EIO, ft_t_err, - "no readable header segment found"); - } - TRACE_CATCH(ftape_abort_operation(),); - ft_used_header_segment = header_segment; - result = ftape_decode_header_segment(address); - TRACE_EXIT result; -} - -int ftape_decode_header_segment(__u8 *address) -{ - unsigned int max_floppy_side; - unsigned int max_floppy_track; - unsigned int max_floppy_sector; - unsigned int new_tape_len; - TRACE_FUN(ft_t_flow); - - if (GET4(address, FT_SIGNATURE) == FT_D2G_MAGIC) { - /* Ditto 2GB header segment. They encrypt the bad sector map. - * We decrypt it and store them in normal format. - * I hope this is correct. - */ - int i; - TRACE(ft_t_warn, - "Found Ditto 2GB tape, " - "trying to decrypt bad sector map"); - for (i=256; i < 29 * FT_SECTOR_SIZE; i++) { - address[i] = ~(address[i] - (i&0xff)); - } - PUT4(address, 0,FT_HSEG_MAGIC); - } else if (GET4(address, FT_SIGNATURE) != FT_HSEG_MAGIC) { - TRACE_ABORT(-EIO, ft_t_err, - "wrong signature in header segment"); - } - ft_format_code = (ft_format_type) address[FT_FMT_CODE]; - if (ft_format_code != fmt_big) { - ft_header_segment_1 = GET2(address, FT_HSEG_1); - ft_header_segment_2 = GET2(address, FT_HSEG_2); - ft_first_data_segment = GET2(address, FT_FRST_SEG); - ft_last_data_segment = GET2(address, FT_LAST_SEG); - } else { - ft_header_segment_1 = GET4(address, FT_6_HSEG_1); - ft_header_segment_2 = GET4(address, FT_6_HSEG_2); - ft_first_data_segment = GET4(address, FT_6_FRST_SEG); - ft_last_data_segment = GET4(address, FT_6_LAST_SEG); - } - TRACE(ft_t_noise, "first data segment: %d", ft_first_data_segment); - TRACE(ft_t_noise, "last data segment: %d", ft_last_data_segment); - TRACE(ft_t_noise, "header segments are %d and %d", - ft_header_segment_1, ft_header_segment_2); - - /* Verify tape parameters... - * QIC-40/80 spec: tape_parameters: - * - * segments-per-track segments_per_track - * tracks-per-cartridge tracks_per_tape - * max-floppy-side (segments_per_track * - * tracks_per_tape - 1) / - * ftape_segments_per_head - * max-floppy-track ftape_segments_per_head / - * ftape_segments_per_cylinder - 1 - * max-floppy-sector ftape_segments_per_cylinder * - * FT_SECTORS_PER_SEGMENT - */ - ft_segments_per_track = GET2(address, FT_SPT); - ft_tracks_per_tape = address[FT_TPC]; - max_floppy_side = address[FT_FHM]; - max_floppy_track = address[FT_FTM]; - max_floppy_sector = address[FT_FSM]; - TRACE(ft_t_noise, "(fmt/spt/tpc/fhm/ftm/fsm) = %d/%d/%d/%d/%d/%d", - ft_format_code, ft_segments_per_track, ft_tracks_per_tape, - max_floppy_side, max_floppy_track, max_floppy_sector); - new_tape_len = ftape_tape_len; - switch (ft_format_code) { - case fmt_425ft: - new_tape_len = 425; - break; - case fmt_normal: - if (ftape_tape_len == 0) { /* otherwise 307 ft */ - new_tape_len = 205; - } - break; - case fmt_1100ft: - new_tape_len = 1100; - break; - case fmt_var:{ - int segments_per_1000_inch = 1; /* non-zero default for switch */ - switch (ft_qic_std) { - case QIC_TAPE_QIC40: - segments_per_1000_inch = 332; - break; - case QIC_TAPE_QIC80: - segments_per_1000_inch = 488; - break; - case QIC_TAPE_QIC3010: - segments_per_1000_inch = 730; - break; - case QIC_TAPE_QIC3020: - segments_per_1000_inch = 1430; - break; - } - new_tape_len = (1000 * ft_segments_per_track + - (segments_per_1000_inch - 1)) / segments_per_1000_inch; - break; - } - case fmt_big:{ - int segments_per_1000_inch = 1; /* non-zero default for switch */ - switch (ft_qic_std) { - case QIC_TAPE_QIC40: - segments_per_1000_inch = 332; - break; - case QIC_TAPE_QIC80: - segments_per_1000_inch = 488; - break; - case QIC_TAPE_QIC3010: - segments_per_1000_inch = 730; - break; - case QIC_TAPE_QIC3020: - segments_per_1000_inch = 1430; - break; - default: - TRACE_ABORT(-EIO, ft_t_bug, - "%x QIC-standard with fmt-code %d, please report", - ft_qic_std, ft_format_code); - } - new_tape_len = ((1000 * ft_segments_per_track + - (segments_per_1000_inch - 1)) / - segments_per_1000_inch); - break; - } - default: - TRACE_ABORT(-EIO, ft_t_err, - "unknown tape format, please report !"); - } - if (new_tape_len != ftape_tape_len) { - ftape_tape_len = new_tape_len; - TRACE(ft_t_info, "calculated tape length is %d ft", - ftape_tape_len); - ftape_calc_timeouts(ft_qic_std, ft_data_rate, ftape_tape_len); - } - if (ft_segments_per_track == 0 && ft_tracks_per_tape == 0 && - max_floppy_side == 0 && max_floppy_track == 0 && - max_floppy_sector == 0) { - /* QIC-40 Rev E and earlier has no values in the header. - */ - ft_segments_per_track = 68; - ft_tracks_per_tape = 20; - max_floppy_side = 1; - max_floppy_track = 169; - max_floppy_sector = 128; - } - /* This test will compensate for the wrong parameter on tapes - * formatted by Conner software. - */ - if (ft_segments_per_track == 150 && - ft_tracks_per_tape == 28 && - max_floppy_side == 7 && - max_floppy_track == 149 && - max_floppy_sector == 128) { -TRACE(ft_t_info, "the famous CONNER bug: max_floppy_side off by one !"); - max_floppy_side = 6; - } - /* These tests will compensate for the wrong parameter on tapes - * formatted by ComByte Windows software. - * - * First, for 205 foot tapes - */ - if (ft_segments_per_track == 100 && - ft_tracks_per_tape == 28 && - max_floppy_side == 9 && - max_floppy_track == 149 && - max_floppy_sector == 128) { -TRACE(ft_t_info, "the ComByte bug: max_floppy_side incorrect!"); - max_floppy_side = 4; - } - /* Next, for 307 foot tapes. */ - if (ft_segments_per_track == 150 && - ft_tracks_per_tape == 28 && - max_floppy_side == 9 && - max_floppy_track == 149 && - max_floppy_sector == 128) { -TRACE(ft_t_info, "the ComByte bug: max_floppy_side incorrect!"); - max_floppy_side = 6; - } - /* This test will compensate for the wrong parameter on tapes - * formatted by Colorado Windows software. - */ - if (ft_segments_per_track == 150 && - ft_tracks_per_tape == 28 && - max_floppy_side == 6 && - max_floppy_track == 150 && - max_floppy_sector == 128) { -TRACE(ft_t_info, "the famous Colorado bug: max_floppy_track off by one !"); - max_floppy_track = 149; - } - ftape_segments_per_head = ((max_floppy_sector/FT_SECTORS_PER_SEGMENT) * - (max_floppy_track + 1)); - /* This test will compensate for some bug reported by Dima - * Brodsky. Seems to be a Colorado bug, either. (freebee - * Imation tape shipped together with Colorado T3000 - */ - if ((ft_format_code == fmt_var || ft_format_code == fmt_big) && - ft_tracks_per_tape == 50 && - max_floppy_side == 54 && - max_floppy_track == 255 && - max_floppy_sector == 128) { -TRACE(ft_t_info, "the famous ??? bug: max_floppy_track off by one !"); - max_floppy_track = 254; - } - /* - * Verify drive_configuration with tape parameters - */ - if (ftape_segments_per_head == 0 || ftape_segments_per_cylinder == 0 || - ((ft_segments_per_track * ft_tracks_per_tape - 1) / ftape_segments_per_head - != max_floppy_side) || - (ftape_segments_per_head / ftape_segments_per_cylinder - 1 != max_floppy_track) || - (ftape_segments_per_cylinder * FT_SECTORS_PER_SEGMENT != max_floppy_sector) -#ifdef TESTING - || ((ft_format_code == fmt_var || ft_format_code == fmt_big) && - (max_floppy_track != 254 || max_floppy_sector != 128)) -#endif - ) { - char segperheadz = ftape_segments_per_head ? ' ' : '?'; - char segpercylz = ftape_segments_per_cylinder ? ' ' : '?'; - TRACE(ft_t_err,"Tape parameters inconsistency, please report"); - TRACE(ft_t_err, "reported = %d/%d/%d/%d/%d/%d", - ft_format_code, - ft_segments_per_track, - ft_tracks_per_tape, - max_floppy_side, - max_floppy_track, - max_floppy_sector); - TRACE(ft_t_err, "required = %d/%d/%d/%d%c/%d%c/%d", - ft_format_code, - ft_segments_per_track, - ft_tracks_per_tape, - ftape_segments_per_head ? - ((ft_segments_per_track * ft_tracks_per_tape -1) / - ftape_segments_per_head ) : - (ft_segments_per_track * ft_tracks_per_tape -1), - segperheadz, - ftape_segments_per_cylinder ? - (ftape_segments_per_head / - ftape_segments_per_cylinder - 1 ) : - ftape_segments_per_head - 1, - segpercylz, - (ftape_segments_per_cylinder * FT_SECTORS_PER_SEGMENT)); - TRACE_EXIT -EIO; - } - ftape_extract_bad_sector_map(address); - TRACE_EXIT 0; -} diff --git a/drivers/char/ftape/lowlevel/ftape-read.h b/drivers/char/ftape/lowlevel/ftape-read.h deleted file mode 100644 index 069f99f2a98..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-read.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef _FTAPE_READ_H -#define _FTAPE_READ_H - -/* - * Copyright (C) 1994-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-read.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:22 $ - * - * This file contains the definitions for the read functions - * for the QIC-117 floppy-tape driver for Linux. - * - */ - -/* ftape-read.c defined global functions. - */ -typedef enum { - FT_RD_SINGLE = 0, - FT_RD_AHEAD = 1, -} ft_read_mode_t; - -extern int ftape_read_header_segment(__u8 *address); -extern int ftape_decode_header_segment(__u8 *address); -extern int ftape_read_segment_fraction(const int segment, - void *address, - const ft_read_mode_t read_mode, - const int start, - const int size); -#define ftape_read_segment(segment, address, read_mode) \ - ftape_read_segment_fraction(segment, address, read_mode, \ - 0, FT_SEGMENT_SIZE) -extern void ftape_zap_read_buffers(void); - -#endif /* _FTAPE_READ_H */ diff --git a/drivers/char/ftape/lowlevel/ftape-rw.c b/drivers/char/ftape/lowlevel/ftape-rw.c deleted file mode 100644 index c0d6dc2cbfd..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-rw.c +++ /dev/null @@ -1,1092 +0,0 @@ -/* - * 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 -#include - -#include -#include -#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); - if (retry) { - buff->soft_error_map &= offset_mask; /* keep skipped part */ - } else { - buff->hard_error_map = buff->soft_error_map = 0; - } - buff->bad_sector_map = ftape_get_bad_sector_entry(buff->segment_id); - if (buff->bad_sector_map != 0) { - TRACE(ft_t_noise, "segment: %d, bad sector map: %08lx", - buff->segment_id, (long)buff->bad_sector_map); - } else { - TRACE(ft_t_flow, "segment: %d", buff->segment_id); - } - if (buff->sector_offset > 0) { - buff->bad_sector_map >>= buff->sector_offset; - } - if (buff->sector_offset != 0 || buff->remaining != FT_SECTORS_PER_SEGMENT) { - TRACE(ft_t_flow, "sector offset = %d, count = %d", - buff->sector_offset, buff->remaining); - } - /* Segments with 3 or less sectors are not written with valid - * data because there is no space left for the ecc. The - * data written is whatever happens to be in the buffer. - * Reading such a segment will return a zero byte-count. - * To allow us to read/write segments with all bad sectors - * we fake one readable sector in the segment. This - * prevents having to handle these segments in a very - * special way. It is not important if the reading of this - * bad sector fails or not (the data is ignored). It is - * only read to keep the driver running. - * - * The QIC-40/80 spec. has no information on how to handle - * this case, so this is my interpretation. - */ - if (buff->bad_sector_map == EMPTY_SEGMENT) { - TRACE(ft_t_flow, "empty segment %d, fake first sector good", - buff->segment_id); - if (buff->ptr != buff->address) { - TRACE(ft_t_bug, "This is a bug: %p/%p", - buff->ptr, buff->address); - } - buff->bad_sector_map = FAKE_SEGMENT; - } - fdc_setup_error = 0; - buff->next_segment = segment_id + 1; - TRACE_EXIT 0; -} - -/* Calculate Floppy Disk Controller and DMA parameters for a new segment. - */ -int ftape_setup_new_segment(buffer_struct * buff, int segment_id, int skip) -{ - int result = 0; - static int old_segment_id = -1; - static buffer_state_enum old_ft_driver_state = idle; - int retry = 0; - unsigned offset = 0; - int count = FT_SECTORS_PER_SEGMENT; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_flow, "%s segment %d (old = %d)", - (ft_driver_state == reading || ft_driver_state == verifying) - ? "reading" : "writing", - segment_id, old_segment_id); - if (ft_driver_state != old_ft_driver_state) { /* when verifying */ - old_segment_id = -1; - old_ft_driver_state = ft_driver_state; - } - if (segment_id == old_segment_id) { - ++buff->retry; - ++ft_history.retries; - TRACE(ft_t_flow, "setting up for retry nr %d", buff->retry); - retry = 1; - if (skip && buff->skip > 0) { /* allow skip on retry */ - offset = buff->skip; - count -= offset; - TRACE(ft_t_flow, "skipping %d sectors", offset); - } - } else { - buff->retry = 0; - buff->skip = 0; - old_segment_id = segment_id; - } - result = setup_segment(buff, segment_id, offset, count, retry); - TRACE_EXIT result; -} - -/* Determine size of next cluster of good sectors. - */ -int ftape_calc_next_cluster(buffer_struct * buff) -{ - /* Skip bad sectors. - */ - while (buff->remaining > 0 && (buff->bad_sector_map & 1) != 0) { - buff->bad_sector_map >>= 1; - ++buff->sector_offset; - --buff->remaining; - } - /* Find next cluster of good sectors - */ - if (buff->bad_sector_map == 0) { /* speed up */ - buff->sector_count = buff->remaining; - } else { - SectorMap map = buff->bad_sector_map; - - buff->sector_count = 0; - while (buff->sector_count < buff->remaining && (map & 1) == 0) { - ++buff->sector_count; - map >>= 1; - } - } - return buff->sector_count; -} - -/* if just passed the last segment on a track, wait for BOT - * or EOT mark. - */ -int ftape_handle_logical_eot(void) -{ - TRACE_FUN(ft_t_flow); - - if (ft_runner_status == logical_eot) { - int status; - - TRACE(ft_t_noise, "tape at logical EOT"); - TRACE_CATCH(ftape_ready_wait(ftape_timeout.seek, &status),); - if ((status & (QIC_STATUS_AT_BOT | QIC_STATUS_AT_EOT)) == 0) { - TRACE_ABORT(-EIO, ft_t_err, "eot/bot not reached"); - } - ft_runner_status = end_of_tape; - } - if (ft_runner_status == end_of_tape) { - TRACE(ft_t_noise, "runner stopped because of logical EOT"); - ft_runner_status = idle; - } - TRACE_EXIT 0; -} - -static int check_bot_eot(int status) -{ - TRACE_FUN(ft_t_flow); - - if (status & (QIC_STATUS_AT_BOT | QIC_STATUS_AT_EOT)) { - ft_location.bot = ((ft_location.track & 1) == 0 ? - (status & QIC_STATUS_AT_BOT) != 0: - (status & QIC_STATUS_AT_EOT) != 0); - ft_location.eot = !ft_location.bot; - ft_location.segment = (ft_location.track + - (ft_location.bot ? 0 : 1)) * ft_segments_per_track - 1; - ft_location.sector = -1; - ft_location.known = 1; - TRACE(ft_t_flow, "tape at logical %s", - ft_location.bot ? "bot" : "eot"); - TRACE(ft_t_flow, "segment = %d", ft_location.segment); - } else { - ft_location.known = 0; - } - TRACE_EXIT ft_location.known; -} - -/* Read Id of first sector passing tape head. - */ -static int ftape_read_id(void) -{ - int status; - __u8 out[2]; - TRACE_FUN(ft_t_any); - - /* Assume tape is running on entry, be able to handle - * situation where it stopped or is stopping. - */ - ft_location.known = 0; /* default is location not known */ - out[0] = FDC_READID; - out[1] = ft_drive_sel; - TRACE_CATCH(fdc_command(out, 2),); - switch (fdc_interrupt_wait(20 * FT_SECOND)) { - case 0: - if (fdc_sect == 0) { - if (ftape_report_drive_status(&status) >= 0 && - (status & QIC_STATUS_READY)) { - ftape_tape_running = 0; - TRACE(ft_t_flow, "tape has stopped"); - check_bot_eot(status); - } - } else { - ft_location.known = 1; - ft_location.segment = (ftape_segments_per_head - * fdc_head - + ftape_segments_per_cylinder - * fdc_cyl - + (fdc_sect - 1) - / FT_SECTORS_PER_SEGMENT); - ft_location.sector = ((fdc_sect - 1) - % FT_SECTORS_PER_SEGMENT); - ft_location.eot = ft_location.bot = 0; - } - break; - case -ETIME: - /* Didn't find id on tape, must be near end: Wait - * until stopped. - */ - if (ftape_ready_wait(FT_FOREVER, &status) >= 0) { - ftape_tape_running = 0; - TRACE(ft_t_flow, "tape has stopped"); - check_bot_eot(status); - } - break; - default: - /* Interrupted or otherwise failing - * fdc_interrupt_wait() - */ - TRACE(ft_t_err, "fdc_interrupt_wait failed"); - break; - } - if (!ft_location.known) { - TRACE_ABORT(-EIO, ft_t_flow, "no id found"); - } - if (ft_location.sector == 0) { - TRACE(ft_t_flow, "passing segment %d/%d", - ft_location.segment, ft_location.sector); - } else { - TRACE(ft_t_fdc_dma, "passing segment %d/%d", - ft_location.segment, ft_location.sector); - } - TRACE_EXIT 0; -} - -static int logical_forward(void) -{ - ftape_tape_running = 1; - return ftape_command(QIC_LOGICAL_FORWARD); -} - -int ftape_stop_tape(int *pstatus) -{ - int retry = 0; - int result; - TRACE_FUN(ft_t_flow); - - do { - result = ftape_command_wait(QIC_STOP_TAPE, - ftape_timeout.stop, pstatus); - if (result == 0) { - if ((*pstatus & QIC_STATUS_READY) == 0) { - result = -EIO; - } else { - ftape_tape_running = 0; - } - } - } while (result < 0 && ++retry <= 3); - if (result < 0) { - TRACE(ft_t_err, "failed ! (fatal)"); - } - TRACE_EXIT result; -} - -int ftape_dumb_stop(void) -{ - int result; - int status; - TRACE_FUN(ft_t_flow); - - /* Abort current fdc operation if it's busy (probably read - * or write operation pending) with a reset. - */ - if (fdc_ready_wait(100 /* usec */) < 0) { - TRACE(ft_t_noise, "aborting fdc operation"); - fdc_reset(); - } - /* Reading id's after the last segment on a track may fail - * but eventually the drive will become ready (logical eot). - */ - result = ftape_report_drive_status(&status); - ft_location.known = 0; - do { - if (result == 0 && status & QIC_STATUS_READY) { - /* Tape is not running any more. - */ - TRACE(ft_t_noise, "tape already halted"); - check_bot_eot(status); - ftape_tape_running = 0; - } else if (ftape_tape_running) { - /* Tape is (was) still moving. - */ -#ifdef TESTING - ftape_read_id(); -#endif - result = ftape_stop_tape(&status); - } else { - /* Tape not yet ready but stopped. - */ - result = ftape_ready_wait(ftape_timeout.pause,&status); - } - } while (ftape_tape_running - && !(sigtestsetmask(¤t->pending.signal, _NEVER_BLOCK))); -#ifndef TESTING - ft_location.known = 0; -#endif - if (ft_runner_status == aborting || ft_runner_status == do_abort) { - ft_runner_status = idle; - } - TRACE_EXIT result; -} - -/* Wait until runner has finished tail buffer. - * - */ -int ftape_wait_segment(buffer_state_enum state) -{ - int status; - int result = 0; - TRACE_FUN(ft_t_flow); - - while (ft_buffer[ft_tail]->status == state) { - TRACE(ft_t_flow, "state: %d", ft_buffer[ft_tail]->status); - /* First buffer still being worked on, wait up to timeout. - * - * Note: we check two times for being killed. 50 - * seconds are quite long. Note that - * fdc_interrupt_wait() is not killable by any - * means. ftape_read_segment() wants us to return - * -EINTR in case of a signal. - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - result = fdc_interrupt_wait(50 * FT_SECOND); - FT_SIGNAL_EXIT(_DONT_BLOCK); - if (result < 0) { - TRACE_ABORT(result, - ft_t_err, "fdc_interrupt_wait failed"); - } - if (fdc_setup_error) { - /* recover... FIXME */ - TRACE_ABORT(-EIO, ft_t_err, "setup error"); - } - } - if (ft_buffer[ft_tail]->status != error) { - TRACE_EXIT 0; - } - TRACE_CATCH(ftape_report_drive_status(&status),); - TRACE(ft_t_noise, "ftape_report_drive_status: 0x%02x", status); - if ((status & QIC_STATUS_READY) && - (status & QIC_STATUS_ERROR)) { - unsigned int error; - qic117_cmd_t command; - - /* Report and clear error state. - * In case the drive can't operate at the selected - * rate, select the next lower data rate. - */ - ftape_report_error(&error, &command, 1); - if (error == 31 && command == QIC_LOGICAL_FORWARD) { - /* drive does not accept this data rate */ - if (ft_data_rate > 250) { - TRACE(ft_t_info, - "Probable data rate conflict"); - TRACE(ft_t_info, - "Lowering data rate to %d Kbps", - ft_data_rate / 2); - ftape_half_data_rate(); - if (ft_buffer[ft_tail]->retry > 0) { - /* give it a chance */ - --ft_buffer[ft_tail]->retry; - } - } else { - /* no rate is accepted... */ - TRACE(ft_t_err, "We're dead :("); - } - } else { - TRACE(ft_t_err, "Unknown error"); - } - TRACE_EXIT -EIO; /* g.p. error */ - } - TRACE_EXIT 0; -} - -/* forward */ static int seek_forward(int segment_id, int fast); - -static int fast_seek(int count, int reverse) -{ - int result = 0; - int status; - TRACE_FUN(ft_t_flow); - - if (count > 0) { - /* If positioned at begin or end of tape, fast seeking needs - * special treatment. - * Starting from logical bot needs a (slow) seek to the first - * segment before the high speed seek. Most drives do this - * automatically but some older don't, so we treat them - * all the same. - * Starting from logical eot is even more difficult because - * we cannot (slow) reverse seek to the last segment. - * TO BE IMPLEMENTED. - */ - inhibit_correction = 0; - if (ft_location.known && - ((ft_location.bot && !reverse) || - (ft_location.eot && reverse))) { - if (!reverse) { - /* (slow) skip to first segment on a track - */ - seek_forward(ft_location.track * ft_segments_per_track, 0); - --count; - } else { - /* When seeking backwards from - * end-of-tape the number of erased - * gaps found seems to be higher than - * expected. Therefor the drive must - * skip some more segments than - * calculated, but we don't know how - * many. Thus we will prevent the - * re-calculation of offset and - * overshoot when seeking backwards. - */ - inhibit_correction = 1; - count += 3; /* best guess */ - } - } - } else { - TRACE(ft_t_flow, "warning: zero or negative count: %d", count); - } - if (count > 0) { - int i; - int nibbles = count > 255 ? 3 : 2; - - if (count > 4095) { - TRACE(ft_t_noise, "skipping clipped at 4095 segment"); - count = 4095; - } - /* Issue this tape command first. */ - if (!reverse) { - TRACE(ft_t_noise, "skipping %d segment(s)", count); - result = ftape_command(nibbles == 3 ? - QIC_SKIP_EXTENDED_FORWARD : QIC_SKIP_FORWARD); - } else { - TRACE(ft_t_noise, "backing up %d segment(s)", count); - result = ftape_command(nibbles == 3 ? - QIC_SKIP_EXTENDED_REVERSE : QIC_SKIP_REVERSE); - } - if (result < 0) { - TRACE(ft_t_noise, "Skip command failed"); - } else { - --count; /* 0 means one gap etc. */ - for (i = 0; i < nibbles; ++i) { - if (result >= 0) { - result = ftape_parameter(count & 15); - count /= 16; - } - } - result = ftape_ready_wait(ftape_timeout.rewind, &status); - if (result >= 0) { - ftape_tape_running = 0; - } - } - } - TRACE_EXIT result; -} - -static int validate(int id) -{ - /* Check to see if position found is off-track as reported - * once. Because all tracks in one direction lie next to - * each other, if off-track the error will be approximately - * 2 * ft_segments_per_track. - */ - if (ft_location.track == -1) { - return 1; /* unforseen situation, don't generate error */ - } else { - /* Use margin of ft_segments_per_track on both sides - * because ftape needs some margin and the error we're - * looking for is much larger ! - */ - int lo = (ft_location.track - 1) * ft_segments_per_track; - int hi = (ft_location.track + 2) * ft_segments_per_track; - - return (id >= lo && id < hi); - } -} - -static int seek_forward(int segment_id, int fast) -{ - int failures = 0; - int count; - static int margin = 1; /* fixed: stop this before target */ - static int overshoot = 1; - static int min_count = 8; - int expected = -1; - int target = segment_id - margin; - int fast_seeking; - int prev_segment = ft_location.segment; - TRACE_FUN(ft_t_flow); - - if (!ft_location.known) { - TRACE_ABORT(-EIO, ft_t_err, - "fatal: cannot seek from unknown location"); - } - if (!validate(segment_id)) { - ftape_sleep(1 * FT_SECOND); - ft_failure = 1; - TRACE_ABORT(-EIO, ft_t_err, - "fatal: head off track (bad hardware?)"); - } - TRACE(ft_t_noise, "from %d/%d to %d/0 - %d", - ft_location.segment, ft_location.sector,segment_id,margin); - count = target - ft_location.segment - overshoot; - fast_seeking = (fast && - count > (min_count + (ft_location.bot ? 1 : 0))); - if (fast_seeking) { - TRACE(ft_t_noise, "fast skipping %d segments", count); - expected = segment_id - margin; - fast_seek(count, 0); - } - if (!ftape_tape_running) { - logical_forward(); - } - while (ft_location.segment < segment_id) { - /* This requires at least one sector in a (bad) segment to - * have a valid and readable sector id ! - * It looks like this is not guaranteed, so we must try - * to find a way to skip an EMPTY_SEGMENT. !!! FIXME !!! - */ - if (ftape_read_id() < 0 || !ft_location.known || - sigtestsetmask(¤t->pending.signal, _DONT_BLOCK)) { - ft_location.known = 0; - if (!ftape_tape_running || - ++failures > FT_SECTORS_PER_SEGMENT) { - TRACE_ABORT(-EIO, ft_t_err, - "read_id failed completely"); - } - FT_SIGNAL_EXIT(_DONT_BLOCK); - TRACE(ft_t_flow, "read_id failed, retry (%d)", - failures); - continue; - } - if (fast_seeking) { - TRACE(ft_t_noise, "ended at %d/%d (%d,%d)", - ft_location.segment, ft_location.sector, - overshoot, inhibit_correction); - if (!inhibit_correction && - (ft_location.segment < expected || - ft_location.segment > expected + margin)) { - int error = ft_location.segment - expected; - TRACE(ft_t_noise, - "adjusting overshoot from %d to %d", - overshoot, overshoot + error); - overshoot += error; - /* All overshoots have the same - * direction, so it should never - * become negative, but who knows. - */ - if (overshoot < -5 || - overshoot > OVERSHOOT_LIMIT) { - if (overshoot < 0) { - /* keep sane value */ - overshoot = -5; - } else { - /* keep sane value */ - overshoot = OVERSHOOT_LIMIT; - } - TRACE(ft_t_noise, - "clipped overshoot to %d", - overshoot); - } - } - fast_seeking = 0; - } - if (ft_location.known) { - if (ft_location.segment > prev_segment + 1) { - TRACE(ft_t_noise, - "missed segment %d while skipping", - prev_segment + 1); - } - prev_segment = ft_location.segment; - } - } - if (ft_location.segment > segment_id) { - TRACE_ABORT(-EIO, - ft_t_noise, "failed: skip ended at segment %d/%d", - ft_location.segment, ft_location.sector); - } - TRACE_EXIT 0; -} - -static int skip_reverse(int segment_id, int *pstatus) -{ - int failures = 0; - static int overshoot = 1; - static int min_rewind = 2; /* 1 + overshoot */ - static const int margin = 1; /* stop this before target */ - int expected = 0; - int count = 1; - int short_seek; - int target = segment_id - margin; - TRACE_FUN(ft_t_flow); - - if (ft_location.known && !validate(segment_id)) { - ftape_sleep(1 * FT_SECOND); - ft_failure = 1; - TRACE_ABORT(-EIO, ft_t_err, - "fatal: head off track (bad hardware?)"); - } - do { - if (!ft_location.known) { - TRACE(ft_t_warn, "warning: location not known"); - } - TRACE(ft_t_noise, "from %d/%d to %d/0 - %d", - ft_location.segment, ft_location.sector, - segment_id, margin); - /* min_rewind == 1 + overshoot_when_doing_minimum_rewind - * overshoot == overshoot_when_doing_larger_rewind - * Initially min_rewind == 1 + overshoot, optimization - * of both values will be done separately. - * overshoot and min_rewind can be negative as both are - * sums of three components: - * any_overshoot == rewind_overshoot - - * stop_overshoot - - * start_overshoot - */ - if (ft_location.segment - target - (min_rewind - 1) < 1) { - short_seek = 1; - } else { - count = ft_location.segment - target - overshoot; - short_seek = (count < 1); - } - if (short_seek) { - count = 1; /* do shortest rewind */ - expected = ft_location.segment - min_rewind; - if (expected/ft_segments_per_track != ft_location.track) { - expected = (ft_location.track * - ft_segments_per_track); - } - } else { - expected = target; - } - fast_seek(count, 1); - logical_forward(); - if (ftape_read_id() < 0 || !ft_location.known || - (sigtestsetmask(¤t->pending.signal, _DONT_BLOCK))) { - if ((!ftape_tape_running && !ft_location.known) || - ++failures > FT_SECTORS_PER_SEGMENT) { - TRACE_ABORT(-EIO, ft_t_err, - "read_id failed completely"); - } - FT_SIGNAL_EXIT(_DONT_BLOCK); - TRACE_CATCH(ftape_report_drive_status(pstatus),); - TRACE(ft_t_noise, "ftape_read_id failed, retry (%d)", - failures); - continue; - } - TRACE(ft_t_noise, "ended at %d/%d (%d,%d,%d)", - ft_location.segment, ft_location.sector, - min_rewind, overshoot, inhibit_correction); - if (!inhibit_correction && - (ft_location.segment < expected || - ft_location.segment > expected + margin)) { - int error = expected - ft_location.segment; - if (short_seek) { - TRACE(ft_t_noise, - "adjusting min_rewind from %d to %d", - min_rewind, min_rewind + error); - min_rewind += error; - if (min_rewind < -5) { - /* is this right ? FIXME ! */ - /* keep sane value */ - min_rewind = -5; - TRACE(ft_t_noise, - "clipped min_rewind to %d", - min_rewind); - } - } else { - TRACE(ft_t_noise, - "adjusting overshoot from %d to %d", - overshoot, overshoot + error); - overshoot += error; - if (overshoot < -5 || - overshoot > OVERSHOOT_LIMIT) { - if (overshoot < 0) { - /* keep sane value */ - overshoot = -5; - } else { - /* keep sane value */ - overshoot = OVERSHOOT_LIMIT; - } - TRACE(ft_t_noise, - "clipped overshoot to %d", - overshoot); - } - } - } - } while (ft_location.segment > segment_id); - if (ft_location.known) { - TRACE(ft_t_noise, "current location: %d/%d", - ft_location.segment, ft_location.sector); - } - TRACE_EXIT 0; -} - -static int determine_position(void) -{ - int retry = 0; - int status; - int result; - TRACE_FUN(ft_t_flow); - - if (!ftape_tape_running) { - /* This should only happen if tape is stopped by isr. - */ - TRACE(ft_t_flow, "waiting for tape stop"); - if (ftape_ready_wait(ftape_timeout.pause, &status) < 0) { - TRACE(ft_t_flow, "drive still running (fatal)"); - ftape_tape_running = 1; /* ? */ - } - } else { - ftape_report_drive_status(&status); - } - if (status & QIC_STATUS_READY) { - /* Drive must be ready to check error state ! - */ - TRACE(ft_t_flow, "drive is ready"); - if (status & QIC_STATUS_ERROR) { - unsigned int error; - qic117_cmd_t command; - - /* Report and clear error state, try to continue. - */ - TRACE(ft_t_flow, "error status set"); - ftape_report_error(&error, &command, 1); - ftape_ready_wait(ftape_timeout.reset, &status); - ftape_tape_running = 0; /* ? */ - } - if (check_bot_eot(status)) { - if (ft_location.bot) { - if ((status & QIC_STATUS_READY) == 0) { - /* tape moving away from - * bot/eot, let's see if we - * can catch up with the first - * segment on this track. - */ - } else { - TRACE(ft_t_flow, - "start tape from logical bot"); - logical_forward(); /* start moving */ - } - } else { - if ((status & QIC_STATUS_READY) == 0) { - TRACE(ft_t_noise, "waiting for logical end of track"); - result = ftape_ready_wait(ftape_timeout.reset, &status); - /* error handling needed ? */ - } else { - TRACE(ft_t_noise, - "tape at logical end of track"); - } - } - } else { - TRACE(ft_t_flow, "start tape"); - logical_forward(); /* start moving */ - ft_location.known = 0; /* not cleared by logical forward ! */ - } - } - /* tape should be moving now, start reading id's - */ - while (!ft_location.known && - retry++ < FT_SECTORS_PER_SEGMENT && - (result = ftape_read_id()) < 0) { - - TRACE(ft_t_flow, "location unknown"); - - /* exit on signal - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - - /* read-id somehow failed, tape may - * have reached end or some other - * error happened. - */ - TRACE(ft_t_flow, "read-id failed"); - TRACE_CATCH(ftape_report_drive_status(&status),); - TRACE(ft_t_err, "ftape_report_drive_status: 0x%02x", status); - if (status & QIC_STATUS_READY) { - ftape_tape_running = 0; - TRACE(ft_t_noise, "tape stopped for unknown reason! " - "status = 0x%02x", status); - if (status & QIC_STATUS_ERROR || - !check_bot_eot(status)) { - /* oops, tape stopped but not at end! - */ - TRACE_EXIT -EIO; - } - } - } - TRACE(ft_t_flow, - "tape is positioned at segment %d", ft_location.segment); - TRACE_EXIT ft_location.known ? 0 : -EIO; -} - -/* Get the tape running and position it just before the - * requested segment. - * Seek tape-track and reposition as needed. - */ -int ftape_start_tape(int segment_id, int sector_offset) -{ - int track = segment_id / ft_segments_per_track; - int result = -EIO; - int status; - static int last_segment = -1; - static int bad_bus_timing = 0; - /* number of segments passing the head between starting the tape - * and being able to access the first sector. - */ - static int start_offset = 1; - int retry; - TRACE_FUN(ft_t_flow); - - /* If sector_offset > 0, seek into wanted segment instead of - * into previous. - * This allows error recovery if a part of the segment is bad - * (erased) causing the tape drive to generate an index pulse - * thus causing a no-data error before the requested sector - * is reached. - */ - ftape_tape_running = 0; - TRACE(ft_t_noise, "target segment: %d/%d%s", segment_id, sector_offset, - ft_buffer[ft_head]->retry > 0 ? " retry" : ""); - if (ft_buffer[ft_head]->retry > 0) { /* this is a retry */ - int dist = segment_id - last_segment; - - if ((int)ft_history.overrun_errors < overrun_count_offset) { - overrun_count_offset = ft_history.overrun_errors; - } else if (dist < 0 || dist > 50) { - overrun_count_offset = ft_history.overrun_errors; - } else if ((ft_history.overrun_errors - - overrun_count_offset) >= 8) { - if (ftape_increase_threshold() >= 0) { - --ft_buffer[ft_head]->retry; - overrun_count_offset = - ft_history.overrun_errors; - TRACE(ft_t_warn, "increased threshold because " - "of excessive overrun errors"); - } else if (!bad_bus_timing && ft_data_rate >= 1000) { - ftape_half_data_rate(); - --ft_buffer[ft_head]->retry; - bad_bus_timing = 1; - overrun_count_offset = - ft_history.overrun_errors; - TRACE(ft_t_warn, "reduced datarate because " - "of excessive overrun errors"); - } - } - } - last_segment = segment_id; - if (ft_location.track != track || - (ftape_might_be_off_track && ft_buffer[ft_head]->retry== 0)) { - /* current track unknown or not equal to destination - */ - ftape_ready_wait(ftape_timeout.seek, &status); - ftape_seek_head_to_track(track); - /* overrun_count_offset = ft_history.overrun_errors; */ - } - result = -EIO; - retry = 0; - while (result < 0 && - retry++ <= 5 && - !ft_failure && - !(sigtestsetmask(¤t->pending.signal, _DONT_BLOCK))) { - - if (retry && start_offset < 5) { - start_offset ++; - } - /* Check if we are able to catch the requested - * segment in time. - */ - if ((ft_location.known || (determine_position() == 0)) && - ft_location.segment >= - (segment_id - - ((ftape_tape_running || ft_location.bot) - ? 0 : start_offset))) { - /* Too far ahead (in or past target segment). - */ - if (ftape_tape_running) { - if ((result = ftape_stop_tape(&status)) < 0) { - TRACE(ft_t_err, - "stop tape failed with code %d", - result); - break; - } - TRACE(ft_t_noise, "tape stopped"); - ftape_tape_running = 0; - } - TRACE(ft_t_noise, "repositioning"); - ++ft_history.rewinds; - if (segment_id % ft_segments_per_track < start_offset){ - TRACE(ft_t_noise, "end of track condition\n" - KERN_INFO "segment_id : %d\n" - KERN_INFO "ft_segments_per_track: %d\n" - KERN_INFO "start_offset : %d", - segment_id, ft_segments_per_track, - start_offset); - - /* If seeking to first segments on - * track better do a complete rewind - * to logical begin of track to get a - * more steady tape motion. - */ - result = ftape_command_wait( - (ft_location.track & 1) - ? QIC_PHYSICAL_FORWARD - : QIC_PHYSICAL_REVERSE, - ftape_timeout.rewind, &status); - check_bot_eot(status); /* update location */ - } else { - result= skip_reverse(segment_id - start_offset, - &status); - } - } - if (!ft_location.known) { - TRACE(ft_t_bug, "panic: location not known"); - result = -EIO; - continue; /* while() will check for failure */ - } - TRACE(ft_t_noise, "current segment: %d/%d", - ft_location.segment, ft_location.sector); - /* We're on the right track somewhere before the - * wanted segment. Start tape movement if needed and - * skip to just before or inside the requested - * segment. Keep tape running. - */ - result = 0; - if (ft_location.segment < - (segment_id - ((ftape_tape_running || ft_location.bot) - ? 0 : start_offset))) { - if (sector_offset > 0) { - result = seek_forward(segment_id, - retry <= 3); - } else { - result = seek_forward(segment_id - 1, - retry <= 3); - } - } - if (result == 0 && - ft_location.segment != - (segment_id - (sector_offset > 0 ? 0 : 1))) { - result = -EIO; - } - } - if (result < 0) { - TRACE(ft_t_err, "failed to reposition"); - } else { - ft_runner_status = running; - } - TRACE_EXIT result; -} diff --git a/drivers/char/ftape/lowlevel/ftape-rw.h b/drivers/char/ftape/lowlevel/ftape-rw.h deleted file mode 100644 index 32f4feeb887..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-rw.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef _FTAPE_RW_H -#define _FTAPE_RW_H - -/* - * 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.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:25 $ - * - * This file contains the definitions for the read and write - * functions for the QIC-117 floppy-tape driver for Linux. - * - * Claus-Justus Heine (1996/09/20): Add definition of format code 6 - * Claus-Justus Heine (1996/10/04): Changed GET/PUT macros to cast to (__u8 *) - * - */ - -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/ftape-init.h" -#include "../lowlevel/ftape-bsm.h" - -#include - -#define GET2(address, offset) get_unaligned((__u16*)((__u8 *)address + offset)) -#define GET4(address, offset) get_unaligned((__u32*)((__u8 *)address + offset)) -#define GET8(address, offset) get_unaligned((__u64*)((__u8 *)address + offset)) -#define PUT2(address, offset , value) put_unaligned((value), (__u16*)((__u8 *)address + offset)) -#define PUT4(address, offset , value) put_unaligned((value), (__u32*)((__u8 *)address + offset)) -#define PUT8(address, offset , value) put_unaligned((value), (__u64*)((__u8 *)address + offset)) - -enum runner_status_enum { - idle = 0, - running, - do_abort, - aborting, - logical_eot, - end_of_tape, -}; - -typedef enum ft_buffer_queue { - ft_queue_head = 0, - ft_queue_tail = 1 -} ft_buffer_queue_t; - - -typedef struct { - int track; /* tape head position */ - volatile int segment; /* current segment */ - volatile int sector; /* sector offset within current segment */ - volatile unsigned int bot; /* logical begin of track */ - volatile unsigned int eot; /* logical end of track */ - volatile unsigned int known; /* validates bot, segment, sector */ -} location_record; - -/* Count nr of 1's in pattern. - */ -static inline int count_ones(unsigned long mask) -{ - int bits; - - for (bits = 0; mask != 0; mask >>= 1) { - if (mask & 1) { - ++bits; - } - } - return bits; -} - -#define FT_MAX_NR_BUFFERS 16 /* arbitrary value */ -/* ftape-rw.c defined global vars. - */ -extern buffer_struct *ft_buffer[FT_MAX_NR_BUFFERS]; -extern int ft_nr_buffers; -extern location_record ft_location; -extern volatile int ftape_tape_running; - -/* ftape-rw.c defined global functions. - */ -extern int ftape_setup_new_segment(buffer_struct * buff, - int segment_id, - int offset); -extern int ftape_calc_next_cluster(buffer_struct * buff); -extern buffer_struct *ftape_next_buffer (ft_buffer_queue_t pos); -extern buffer_struct *ftape_get_buffer (ft_buffer_queue_t pos); -extern int ftape_buffer_id (ft_buffer_queue_t pos); -extern void ftape_reset_buffer(void); -extern void ftape_tape_parameters(__u8 drive_configuration); -extern int ftape_wait_segment(buffer_state_enum state); -extern int ftape_dumb_stop(void); -extern int ftape_start_tape(int segment_id, int offset); -extern int ftape_stop_tape(int *pstatus); -extern int ftape_handle_logical_eot(void); -extern buffer_state_enum ftape_set_state(buffer_state_enum new_state); -#endif /* _FTAPE_RW_H */ diff --git a/drivers/char/ftape/lowlevel/ftape-setup.c b/drivers/char/ftape/lowlevel/ftape-setup.c deleted file mode 100644 index 678340acd0b..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-setup.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (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-setup.c,v $ - * $Revision: 1.7 $ - * $Date: 1997/10/10 09:57:06 $ - * - * This file contains the code for processing the kernel command - * line options for the QIC-40/80/3010/3020 floppy-tape driver - * "ftape" for Linux. - */ - -#include -#include -#include - -#include -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/fdc-io.h" - -static struct param_table { - const char *name; - int *var; - int def_param; - int min; - int max; -} config_params[] __initdata = { -#ifndef CONFIG_FT_NO_TRACE_AT_ALL - { "tracing", &ftape_tracing, 3, ft_t_bug, ft_t_any}, -#endif - { "ioport", &ft_fdc_base, CONFIG_FT_FDC_BASE, 0x0, 0xfff}, - { "irq", &ft_fdc_irq, CONFIG_FT_FDC_IRQ, 2, 15}, - { "dma", &ft_fdc_dma, CONFIG_FT_FDC_DMA, 0, 3}, - { "threshold", &ft_fdc_threshold, CONFIG_FT_FDC_THR, 1, 16}, - { "datarate", &ft_fdc_rate_limit, CONFIG_FT_FDC_MAX_RATE, 500, 2000}, - { "fc10", &ft_probe_fc10, CONFIG_FT_PROBE_FC10, 0, 1}, - { "mach2", &ft_mach2, CONFIG_FT_MACH2, 0, 1} -}; - -static int __init ftape_setup(char *str) -{ - int i; - int param; - int ints[2]; - - TRACE_FUN(ft_t_flow); - - str = get_options(str, ARRAY_SIZE(ints), ints); - if (str) { - for (i=0; i < NR_ITEMS(config_params); i++) { - if (strcmp(str,config_params[i].name) == 0){ - if (ints[0]) { - param = ints[1]; - } else { - param = config_params[i].def_param; - } - if (param < config_params[i].min || - param > config_params[i].max) { - TRACE(ft_t_err, - "parameter %s out of range %d ... %d", - config_params[i].name, - config_params[i].min, - config_params[i].max); - goto out; - } - if(config_params[i].var) { - TRACE(ft_t_info, "%s=%d", str, param); - *config_params[i].var = param; - } - goto out; - } - } - } - if (str) { - TRACE(ft_t_err, "unknown ftape option [%s]", str); - - TRACE(ft_t_err, "allowed options are:"); - for (i=0; i < NR_ITEMS(config_params); i++) { - TRACE(ft_t_err, " %s",config_params[i].name); - } - } else { - TRACE(ft_t_err, "botched ftape option"); - } - out: - TRACE_EXIT 1; -} - -__setup("ftape=", ftape_setup); diff --git a/drivers/char/ftape/lowlevel/ftape-tracing.c b/drivers/char/ftape/lowlevel/ftape-tracing.c deleted file mode 100644 index 7fdc6567440..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-tracing.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * 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-tracing.c,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:27 $ - * - * This file contains the reading code - * for the QIC-117 floppy-tape driver for Linux. - */ - -#include -#include "../lowlevel/ftape-tracing.h" - -/* Global vars. - */ -/* tracing - * set it to: to log : - * 0 bugs - * 1 + errors - * 2 + warnings - * 3 + information - * 4 + more information - * 5 + program flow - * 6 + fdc/dma info - * 7 + data flow - * 8 + everything else - */ -ft_trace_t ftape_tracing = ft_t_info; /* Default level: information and up */ -int ftape_function_nest_level; - -/* Local vars. - */ -static __u8 trace_id; -static char spacing[] = "* "; - -void ftape_trace_call(const char *file, const char *name) -{ - char *indent; - - /* Since printk seems not to work with "%*s" format - * we'll use this work-around. - */ - if (ftape_function_nest_level < 0) { - printk(KERN_INFO "function nest level (%d) < 0\n", - ftape_function_nest_level); - ftape_function_nest_level = 0; - } - if (ftape_function_nest_level < sizeof(spacing)) { - indent = (spacing + - sizeof(spacing) - 1 - - ftape_function_nest_level); - } else { - indent = spacing; - } - printk(KERN_INFO "[%03d]%s+%s (%s)\n", - (int) trace_id++, indent, file, name); -} - -void ftape_trace_exit(const char *file, const char *name) -{ - char *indent; - - /* Since printk seems not to work with "%*s" format - * we'll use this work-around. - */ - if (ftape_function_nest_level < 0) { - printk(KERN_INFO "function nest level (%d) < 0\n", ftape_function_nest_level); - ftape_function_nest_level = 0; - } - if (ftape_function_nest_level < sizeof(spacing)) { - indent = (spacing + - sizeof(spacing) - 1 - - ftape_function_nest_level); - } else { - indent = spacing; - } - printk(KERN_INFO "[%03d]%s-%s (%s)\n", - (int) trace_id++, indent, file, name); -} - -void ftape_trace_log(const char *file, const char *function) -{ - char *indent; - - /* Since printk seems not to work with "%*s" format - * we'll use this work-around. - */ - if (ftape_function_nest_level < 0) { - printk(KERN_INFO "function nest level (%d) < 0\n", ftape_function_nest_level); - ftape_function_nest_level = 0; - } - if (ftape_function_nest_level < sizeof(spacing)) { - indent = (spacing + - sizeof(spacing) - 1 - - ftape_function_nest_level); - } else { - indent = spacing; - } - printk(KERN_INFO "[%03d]%s%s (%s) - ", - (int) trace_id++, indent, file, function); -} diff --git a/drivers/char/ftape/lowlevel/ftape-tracing.h b/drivers/char/ftape/lowlevel/ftape-tracing.h deleted file mode 100644 index 2950810c708..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-tracing.h +++ /dev/null @@ -1,179 +0,0 @@ -#ifndef _FTAPE_TRACING_H -#define _FTAPE_TRACING_H - -/* - * Copyright (C) 1994-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-tracing.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:28 $ - * - * This file contains definitions that eases the debugging of the - * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. - */ - -#include - -/* - * Be very careful with TRACE_EXIT and TRACE_ABORT. - * - * if (something) TRACE_EXIT error; - * - * will NOT work. Use - * - * if (something) { - * TRACE_EXIT error; - * } - * - * instead. Maybe a bit dangerous, but save lots of lines of code. - */ - -#define LL_X "%d/%d KB" -#define LL(x) (unsigned int)((__u64)(x)>>10), (unsigned int)((x)&1023) - -typedef enum { - ft_t_nil = -1, - ft_t_bug, - ft_t_err, - ft_t_warn, - ft_t_info, - ft_t_noise, - ft_t_flow, - ft_t_fdc_dma, - ft_t_data_flow, - ft_t_any -} ft_trace_t; - -#ifdef CONFIG_FT_NO_TRACE_AT_ALL -/* the compiler will optimize away most TRACE() macros - */ -#define FT_TRACE_TOP_LEVEL ft_t_bug -#define TRACE_FUN(level) do {} while(0) -#define TRACE_EXIT return -#define TRACE(l, m, i...) \ -{ \ - if ((ft_trace_t)(l) == FT_TRACE_TOP_LEVEL) { \ - printk(KERN_INFO"ftape%s(%s):\n" \ - KERN_INFO m".\n" ,__FILE__, __FUNCTION__ , ##i); \ - } \ -} -#define SET_TRACE_LEVEL(l) if ((l) == (l)) do {} while(0) -#define TRACE_LEVEL FT_TRACE_TOP_LEVEL - -#else - -#ifdef CONFIG_FT_NO_TRACE -/* the compiler will optimize away many TRACE() macros - * the ftape_simple_trace_call() function simply increments - * the function nest level. - */ -#define FT_TRACE_TOP_LEVEL ft_t_warn -#define TRACE_FUN(level) ftape_function_nest_level++ -#define TRACE_EXIT ftape_function_nest_level--; return - -#else -#ifdef CONFIG_FT_FULL_DEBUG -#define FT_TRACE_TOP_LEVEL ft_t_any -#else -#define FT_TRACE_TOP_LEVEL ft_t_flow -#endif -#define TRACE_FUN(level) \ - const ft_trace_t _tracing = level; \ - if (ftape_tracing >= (ft_trace_t)(level) && \ - (ft_trace_t)(level) <= FT_TRACE_TOP_LEVEL) \ - ftape_trace_call(__FILE__, __FUNCTION__); \ - ftape_function_nest_level ++; - -#define TRACE_EXIT \ - --ftape_function_nest_level; \ - if (ftape_tracing >= (ft_trace_t)(_tracing) && \ - (ft_trace_t)(_tracing) <= FT_TRACE_TOP_LEVEL) \ - ftape_trace_exit(__FILE__, __FUNCTION__); \ - return - -#endif - -#define TRACE(l, m, i...) \ -{ \ - if (ftape_tracing >= (ft_trace_t)(l) && \ - (ft_trace_t)(l) <= FT_TRACE_TOP_LEVEL) { \ - ftape_trace_log(__FILE__, __FUNCTION__); \ - printk(m".\n" ,##i); \ - } \ -} - -#define SET_TRACE_LEVEL(l) \ -{ \ - if ((ft_trace_t)(l) <= FT_TRACE_TOP_LEVEL) { \ - ftape_tracing = (ft_trace_t)(l); \ - } else { \ - ftape_tracing = FT_TRACE_TOP_LEVEL; \ - } \ -} -#define TRACE_LEVEL \ -((ftape_tracing <= FT_TRACE_TOP_LEVEL) ? ftape_tracing : FT_TRACE_TOP_LEVEL) - - -/* Global variables declared in tracing.c - */ -extern ft_trace_t ftape_tracing; /* sets default level */ -extern int ftape_function_nest_level; - -/* Global functions declared in tracing.c - */ -extern void ftape_trace_call(const char *file, const char *name); -extern void ftape_trace_exit(const char *file, const char *name); -extern void ftape_trace_log (const char *file, const char *name); - -#endif /* !defined(CONFIG_FT_NO_TRACE_AT_ALL) */ - -/* - * Abort with a message. - */ -#define TRACE_ABORT(res, i...) \ -{ \ - TRACE(i); \ - TRACE_EXIT res; \ -} - -/* The following transforms the common "if(result < 0) ... " into a - * one-liner. - */ -#define _TRACE_CATCH(level, fun, action) \ -{ \ - int _res = (fun); \ - if (_res < 0) { \ - do { action /* */ ; } while(0); \ - TRACE_ABORT(_res, level, "%s failed: %d", #fun, _res); \ - } \ -} - -#define TRACE_CATCH(fun, fail) _TRACE_CATCH(ft_t_err, fun, fail) - -/* Abort the current function when signalled. This doesn't belong here, - * but rather into ftape-rw.h (maybe) - */ -#define FT_SIGNAL_EXIT(sig_mask) \ - if (sigtestsetmask(¤t->pending.signal, sig_mask)) { \ - TRACE_ABORT(-EINTR, \ - ft_t_warn, \ - "interrupted by non-blockable signal"); \ - } - -#endif /* _FTAPE_TRACING_H */ diff --git a/drivers/char/ftape/lowlevel/ftape-write.c b/drivers/char/ftape/lowlevel/ftape-write.c deleted file mode 100644 index 45601ec801e..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-write.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright (C) 1993-1995 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-write.c,v $ - * $Revision: 1.3.4.1 $ - * $Date: 1997/11/14 18:07:04 $ - * - * This file contains the writing code - * for the QIC-117 floppy-tape driver for Linux. - */ - -#include -#include -#include - -#include -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-write.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-ecc.h" -#include "../lowlevel/ftape-bsm.h" -#include "../lowlevel/fdc-isr.h" - -/* Global vars. - */ - -/* Local vars. - */ -static int last_write_failed; - -void ftape_zap_write_buffers(void) -{ - int i; - - for (i = 0; i < ft_nr_buffers; ++i) { - ft_buffer[i]->status = done; - } - ftape_reset_buffer(); -} - -static int copy_and_gen_ecc(void *destination, - const void *source, - const SectorMap bad_sector_map) -{ - int result; - struct memory_segment mseg; - int bads = count_ones(bad_sector_map); - TRACE_FUN(ft_t_any); - - if (bads > 0) { - TRACE(ft_t_noise, "bad sectors in map: %d", bads); - } - if (bads + 3 >= FT_SECTORS_PER_SEGMENT) { - TRACE(ft_t_noise, "empty segment"); - mseg.blocks = 0; /* skip entire segment */ - result = 0; /* nothing written */ - } else { - mseg.blocks = FT_SECTORS_PER_SEGMENT - bads; - mseg.data = destination; - memcpy(mseg.data, source, (mseg.blocks - 3) * FT_SECTOR_SIZE); - result = ftape_ecc_set_segment_parity(&mseg); - if (result < 0) { - TRACE(ft_t_err, "ecc_set_segment_parity failed"); - } else { - result = (mseg.blocks - 3) * FT_SECTOR_SIZE; - } - } - TRACE_EXIT result; -} - - -int ftape_start_writing(const ft_write_mode_t mode) -{ - buffer_struct *head = ftape_get_buffer(ft_queue_head); - int segment_id = head->segment_id; - int result; - buffer_state_enum wanted_state = (mode == FT_WR_DELETE - ? deleting - : writing); - TRACE_FUN(ft_t_flow); - - if ((ft_driver_state != wanted_state) || head->status != waiting) { - TRACE_EXIT 0; - } - ftape_setup_new_segment(head, segment_id, 1); - if (mode == FT_WR_SINGLE) { - /* stop tape instead of pause */ - head->next_segment = 0; - } - ftape_calc_next_cluster(head); /* prepare */ - head->status = ft_driver_state; /* either writing or deleting */ - if (ft_runner_status == idle) { - TRACE(ft_t_noise, - "starting runner for segment %d", segment_id); - TRACE_CATCH(ftape_start_tape(segment_id,head->sector_offset),); - } else { - TRACE(ft_t_noise, "runner not idle, not starting tape"); - } - /* go */ - result = fdc_setup_read_write(head, (mode == FT_WR_DELETE - ? FDC_WRITE_DELETED : FDC_WRITE)); - ftape_set_state(wanted_state); /* should not be necessary */ - TRACE_EXIT result; -} - -/* Wait until all data is actually written to tape. - * - * There is a problem: when the tape runs into logical EOT, then this - * failes. We need to restart the runner in this case. - */ -int ftape_loop_until_writes_done(void) -{ - buffer_struct *head; - TRACE_FUN(ft_t_flow); - - while ((ft_driver_state == writing || ft_driver_state == deleting) && - ftape_get_buffer(ft_queue_head)->status != done) { - /* set the runner status to idle if at lEOT */ - TRACE_CATCH(ftape_handle_logical_eot(), last_write_failed = 1); - /* restart the tape if necessary */ - if (ft_runner_status == idle) { - TRACE(ft_t_noise, "runner is idle, restarting"); - if (ft_driver_state == deleting) { - TRACE_CATCH(ftape_start_writing(FT_WR_DELETE), - last_write_failed = 1); - } else { - TRACE_CATCH(ftape_start_writing(FT_WR_MULTI), - last_write_failed = 1); - } - } - TRACE(ft_t_noise, "tail: %d, head: %d", - ftape_buffer_id(ft_queue_tail), - ftape_buffer_id(ft_queue_head)); - TRACE_CATCH(fdc_interrupt_wait(5 * FT_SECOND), - last_write_failed = 1); - head = ftape_get_buffer(ft_queue_head); - if (head->status == error) { - /* Allow escape from loop when signaled ! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - if (head->hard_error_map != 0) { - /* Implement hard write error recovery here - */ - } - /* retry this one */ - head->status = waiting; - if (ft_runner_status == aborting) { - ftape_dumb_stop(); - } - if (ft_runner_status != idle) { - TRACE_ABORT(-EIO, ft_t_err, - "unexpected state: " - "ft_runner_status != idle"); - } - ftape_start_writing(ft_driver_state == deleting - ? FT_WR_MULTI : FT_WR_DELETE); - } - TRACE(ft_t_noise, "looping until writes done"); - } - ftape_set_state(idle); - TRACE_EXIT 0; -} - -/* Write given segment from buffer at address to tape. - */ -static int write_segment(const int segment_id, - const void *address, - const ft_write_mode_t write_mode) -{ - int bytes_written = 0; - buffer_struct *tail; - buffer_state_enum wanted_state = (write_mode == FT_WR_DELETE - ? deleting : writing); - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "segment_id = %d", segment_id); - if (ft_driver_state != wanted_state) { - if (ft_driver_state == deleting || - wanted_state == deleting) { - TRACE_CATCH(ftape_loop_until_writes_done(),); - } - TRACE(ft_t_noise, "calling ftape_abort_operation"); - TRACE_CATCH(ftape_abort_operation(),); - ftape_zap_write_buffers(); - ftape_set_state(wanted_state); - } - /* if all buffers full we'll have to wait... - */ - ftape_wait_segment(wanted_state); - tail = ftape_get_buffer(ft_queue_tail); - switch(tail->status) { - case done: - ft_history.defects += count_ones(tail->hard_error_map); - break; - case waiting: - /* this could happen with multiple EMPTY_SEGMENTs, but - * shouldn't happen any more as we re-start the runner even - * with an empty segment. - */ - bytes_written = -EAGAIN; - break; - case error: - /* setup for a retry - */ - tail->status = waiting; - bytes_written = -EAGAIN; /* force retry */ - if (tail->hard_error_map != 0) { - TRACE(ft_t_warn, - "warning: %d hard error(s) in written segment", - count_ones(tail->hard_error_map)); - TRACE(ft_t_noise, "hard_error_map = 0x%08lx", - (long)tail->hard_error_map); - /* Implement hard write error recovery here - */ - } - break; - default: - TRACE_ABORT(-EIO, ft_t_err, - "wait for empty segment failed, tail status: %d", - tail->status); - } - /* should runner stop ? - */ - if (ft_runner_status == aborting) { - buffer_struct *head = ftape_get_buffer(ft_queue_head); - if (head->status == wanted_state) { - head->status = done; /* ???? */ - } - /* don't call abort_operation(), we don't want to zap - * the dma buffers - */ - TRACE_CATCH(ftape_dumb_stop(),); - } else { - /* If just passed last segment on tape: wait for BOT - * or EOT mark. Sets ft_runner_status to idle if at lEOT - * and successful - */ - TRACE_CATCH(ftape_handle_logical_eot(),); - } - if (tail->status == done) { - /* now at least one buffer is empty, fill it with our - * data. skip bad sectors and generate ecc. - * copy_and_gen_ecc return nr of bytes written, range - * 0..29 Kb inclusive! - * - * Empty segments are handled inside coyp_and_gen_ecc() - */ - if (write_mode != FT_WR_DELETE) { - TRACE_CATCH(bytes_written = copy_and_gen_ecc( - tail->address, address, - ftape_get_bad_sector_entry(segment_id)),); - } - tail->segment_id = segment_id; - tail->status = waiting; - tail = ftape_next_buffer(ft_queue_tail); - } - /* Start tape only if all buffers full or flush mode. - * This will give higher probability of streaming. - */ - if (ft_runner_status != running && - ((tail->status == waiting && - ftape_get_buffer(ft_queue_head) == tail) || - write_mode != FT_WR_ASYNC)) { - TRACE_CATCH(ftape_start_writing(write_mode),); - } - TRACE_EXIT bytes_written; -} - -/* Write as much as fits from buffer to the given segment on tape - * and handle retries. - * Return the number of bytes written (>= 0), or: - * -EIO write failed - * -EINTR interrupted by signal - * -ENOSPC device full - */ -int ftape_write_segment(const int segment_id, - const void *buffer, - const ft_write_mode_t flush) -{ - int retry = 0; - int result; - TRACE_FUN(ft_t_flow); - - ft_history.used |= 2; - if (segment_id >= ft_tracks_per_tape*ft_segments_per_track) { - /* tape full */ - TRACE_ABORT(-ENOSPC, ft_t_err, - "invalid segment id: %d (max %d)", - segment_id, - ft_tracks_per_tape * ft_segments_per_track -1); - } - for (;;) { - if ((result = write_segment(segment_id, buffer, flush)) >= 0) { - if (result == 0) { /* empty segment */ - TRACE(ft_t_noise, - "empty segment, nothing written"); - } - TRACE_EXIT result; - } - if (result == -EAGAIN) { - if (++retry > 100) { /* give up */ - TRACE_ABORT(-EIO, ft_t_err, - "write failed, >100 retries in segment"); - } - TRACE(ft_t_warn, "write error, retry %d (%d)", - retry, - ftape_get_buffer(ft_queue_tail)->segment_id); - } else { - TRACE_ABORT(result, ft_t_err, - "write_segment failed, error: %d", result); - } - /* Allow escape from loop when signaled ! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - } -} diff --git a/drivers/char/ftape/lowlevel/ftape-write.h b/drivers/char/ftape/lowlevel/ftape-write.h deleted file mode 100644 index 0e7f898b7af..00000000000 --- a/drivers/char/ftape/lowlevel/ftape-write.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _FTAPE_WRITE_H -#define _FTAPE_WRITE_H - -/* - * Copyright (C) 1994-1995 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-write.h,v $ - $Author: claus $ - * - $Revision: 1.2 $ - $Date: 1997/10/05 19:18:30 $ - $State: Exp $ - * - * This file contains the definitions for the write functions - * for the QIC-117 floppy-tape driver for Linux. - * - */ - - -/* ftape-write.c defined global functions. - */ -typedef enum { - FT_WR_ASYNC = 0, /* start tape only when all buffers are full */ - FT_WR_MULTI = 1, /* start tape, but don't necessarily stop */ - FT_WR_SINGLE = 2, /* write a single segment and stop afterwards */ - FT_WR_DELETE = 3 /* write deleted data marks */ -} ft_write_mode_t; - -extern int ftape_start_writing(const ft_write_mode_t mode); -extern int ftape_write_segment(const int segment, - const void *address, - const ft_write_mode_t flushing); -extern void ftape_zap_write_buffers(void); -extern int ftape_loop_until_writes_done(void); - -#endif /* _FTAPE_WRITE_H */ - diff --git a/drivers/char/ftape/lowlevel/ftape_syms.c b/drivers/char/ftape/lowlevel/ftape_syms.c deleted file mode 100644 index 8e0dc4a07ca..00000000000 --- a/drivers/char/ftape/lowlevel/ftape_syms.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (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_syms.c,v $ - * $Revision: 1.4 $ - * $Date: 1997/10/17 00:03:51 $ - * - * This file contains the symbols that the ftape low level - * part of the QIC-40/80/3010/3020 floppy-tape driver "ftape" - * exports to its high level clients - */ - -#include - -#include -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-init.h" -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-write.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/ftape-bsm.h" -#include "../lowlevel/ftape-buffer.h" -#include "../lowlevel/ftape-format.h" - -/* bad sector handling from ftape-bsm.c */ -EXPORT_SYMBOL(ftape_get_bad_sector_entry); -EXPORT_SYMBOL(ftape_find_end_of_bsm_list); -/* from ftape-rw.c */ -EXPORT_SYMBOL(ftape_set_state); -/* from ftape-ctl.c */ -EXPORT_SYMBOL(ftape_seek_to_bot); -EXPORT_SYMBOL(ftape_seek_to_eot); -EXPORT_SYMBOL(ftape_abort_operation); -EXPORT_SYMBOL(ftape_get_status); -EXPORT_SYMBOL(ftape_enable); -EXPORT_SYMBOL(ftape_disable); -EXPORT_SYMBOL(ftape_mmap); -EXPORT_SYMBOL(ftape_calibrate_data_rate); -/* from ftape-io.c */ -EXPORT_SYMBOL(ftape_reset_drive); -EXPORT_SYMBOL(ftape_command); -EXPORT_SYMBOL(ftape_parameter); -EXPORT_SYMBOL(ftape_ready_wait); -EXPORT_SYMBOL(ftape_report_operation); -EXPORT_SYMBOL(ftape_report_error); -/* from ftape-read.c */ -EXPORT_SYMBOL(ftape_read_segment_fraction); -EXPORT_SYMBOL(ftape_zap_read_buffers); -EXPORT_SYMBOL(ftape_read_header_segment); -EXPORT_SYMBOL(ftape_decode_header_segment); -/* from ftape-write.c */ -EXPORT_SYMBOL(ftape_write_segment); -EXPORT_SYMBOL(ftape_start_writing); -EXPORT_SYMBOL(ftape_loop_until_writes_done); -/* from ftape-buffer.h */ -EXPORT_SYMBOL(ftape_set_nr_buffers); -/* from ftape-format.h */ -EXPORT_SYMBOL(ftape_format_track); -EXPORT_SYMBOL(ftape_format_status); -EXPORT_SYMBOL(ftape_verify_segment); -/* from tracing.c */ -#ifndef CONFIG_FT_NO_TRACE_AT_ALL -EXPORT_SYMBOL(ftape_tracing); -EXPORT_SYMBOL(ftape_function_nest_level); -EXPORT_SYMBOL(ftape_trace_call); -EXPORT_SYMBOL(ftape_trace_exit); -EXPORT_SYMBOL(ftape_trace_log); -#endif - diff --git a/drivers/char/ftape/zftape/Makefile b/drivers/char/ftape/zftape/Makefile deleted file mode 100644 index 6d91c1f77c0..00000000000 --- a/drivers/char/ftape/zftape/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright (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/zftape/Makefile,v $ -# $Revision: 1.4 $ -# $Date: 1997/10/05 19:18:58 $ -# -# Makefile for the QIC-40/80/3010/3020 zftape interface VFS to -# ftape -# - - -# ZFT_OBSOLETE - enable the MTIOC_ZFTAPE_GETBLKSZ ioctl. You should -# leave this enabled for compatibility with taper. - -obj-$(CONFIG_ZFTAPE) += zftape.o - -zftape-objs := zftape-rw.o zftape-ctl.o zftape-read.o \ - zftape-write.o zftape-vtbl.o zftape-eof.o \ - zftape-init.o zftape-buffers.o zftape_syms.o - -EXTRA_CFLAGS := -DZFT_OBSOLETE diff --git a/drivers/char/ftape/zftape/zftape-buffers.c b/drivers/char/ftape/zftape/zftape-buffers.c deleted file mode 100644 index 7ebce2ec789..00000000000 --- a/drivers/char/ftape/zftape/zftape-buffers.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 1995-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/zftape/zftape-buffers.c,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:59 $ - * - * This file contains the dynamic buffer allocation routines - * of zftape - */ - -#include -#include -#include -#include - -#include - -#include - -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-eof.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-write.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-rw.h" -#include "../zftape/zftape-vtbl.h" - -/* global variables - */ - -/* local varibales - */ -static unsigned int used_memory; -static unsigned int peak_memory; - -void zft_memory_stats(void) -{ - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Memory usage (vmalloc allocations):\n" - KERN_INFO "total allocated: %d\n" - KERN_INFO "peak allocation: %d", - used_memory, peak_memory); - peak_memory = used_memory; - TRACE_EXIT; -} - -int zft_vcalloc_once(void *new, size_t size) -{ - TRACE_FUN(ft_t_flow); - if (zft_vmalloc_once(new, size) < 0) { - TRACE_EXIT -ENOMEM; - } - memset(*(void **)new, '\0', size); - TRACE_EXIT 0; -} -int zft_vmalloc_once(void *new, size_t size) -{ - TRACE_FUN(ft_t_flow); - - if (*(void **)new != NULL || size == 0) { - TRACE_EXIT 0; - } - if ((*(void **)new = vmalloc(size)) == NULL) { - TRACE_EXIT -ENOMEM; - } - used_memory += size; - if (peak_memory < used_memory) { - peak_memory = used_memory; - } - TRACE_ABORT(0, ft_t_noise, - "allocated buffer @ %p, %zd bytes", *(void **)new, size); -} -int zft_vmalloc_always(void *new, size_t size) -{ - TRACE_FUN(ft_t_flow); - - zft_vfree(new, size); - TRACE_EXIT zft_vmalloc_once(new, size); -} -void zft_vfree(void *old, size_t size) -{ - TRACE_FUN(ft_t_flow); - - if (*(void **)old) { - vfree(*(void **)old); - used_memory -= size; - TRACE(ft_t_noise, "released buffer @ %p, %zd bytes", - *(void **)old, size); - *(void **)old = NULL; - } - TRACE_EXIT; -} - -void *zft_kmalloc(size_t size) -{ - void *new; - - while ((new = kmalloc(size, GFP_KERNEL)) == NULL) { - msleep_interruptible(100); - } - memset(new, 0, size); - used_memory += size; - if (peak_memory < used_memory) { - peak_memory = used_memory; - } - return new; -} - -void zft_kfree(void *old, size_t size) -{ - kfree(old); - used_memory -= size; -} - -/* there are some more buffers that are allocated on demand. - * cleanup_module() calles this function to be sure to have released - * them - */ -void zft_uninit_mem(void) -{ - TRACE_FUN(ft_t_flow); - - zft_vfree(&zft_hseg_buf, FT_SEGMENT_SIZE); - zft_vfree(&zft_deblock_buf, FT_SEGMENT_SIZE); zft_deblock_segment = -1; - zft_free_vtbl(); - if (zft_cmpr_lock(0 /* don't load */) == 0) { - (*zft_cmpr_ops->cleanup)(); - (*zft_cmpr_ops->reset)(); /* unlock it again */ - } - zft_memory_stats(); - TRACE_EXIT; -} diff --git a/drivers/char/ftape/zftape/zftape-buffers.h b/drivers/char/ftape/zftape/zftape-buffers.h deleted file mode 100644 index 798e3128c68..00000000000 --- a/drivers/char/ftape/zftape/zftape-buffers.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef _FTAPE_DYNMEM_H -#define _FTAPE_DYNMEM_H - -/* - * Copyright (C) 1995-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/zftape/zftape-buffers.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:18:59 $ - * - * memory allocation routines. - * - */ - -/* we do not allocate all of the really large buffer memory before - * someone tries to open the drive. ftape_open() may fail with - * -ENOMEM, but that's better having 200k of vmalloced memory which - * cannot be swapped out. - */ - -extern void zft_memory_stats(void); -extern int zft_vmalloc_once(void *new, size_t size); -extern int zft_vcalloc_once(void *new, size_t size); -extern int zft_vmalloc_always(void *new, size_t size); -extern void zft_vfree(void *old, size_t size); -extern void *zft_kmalloc(size_t size); -extern void zft_kfree(void *old, size_t size); - -/* called by cleanup_module() - */ -extern void zft_uninit_mem(void); - -#endif - - - - - - - diff --git a/drivers/char/ftape/zftape/zftape-ctl.c b/drivers/char/ftape/zftape/zftape-ctl.c deleted file mode 100644 index 22ba0f5d00c..00000000000 --- a/drivers/char/ftape/zftape/zftape-ctl.c +++ /dev/null @@ -1,1417 +0,0 @@ -/* - * Copyright (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/zftape/zftape-ctl.c,v $ - * $Revision: 1.2.6.2 $ - * $Date: 1997/11/14 18:07:33 $ - * - * This file contains the non-read/write zftape functions - * for the QIC-40/80/3010/3020 floppy-tape driver for Linux. - */ - -#include -#include -#include -#include - -#include - -#include - -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-eof.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-write.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-rw.h" -#include "../zftape/zftape-vtbl.h" - -/* Global vars. - */ -int zft_write_protected; /* this is when cartridge rdonly or O_RDONLY */ -int zft_header_read; -int zft_offline; -unsigned int zft_unit; -int zft_resid; -int zft_mt_compression; - -/* Local vars. - */ -static int going_offline; - -typedef int (mt_fun)(int *argptr); -typedef int (*mt_funp)(int *argptr); -typedef struct -{ - mt_funp function; - unsigned offline : 1; /* op permitted if offline or no_tape */ - unsigned write_protected : 1; /* op permitted if write-protected */ - unsigned not_formatted : 1; /* op permitted if tape not formatted */ - unsigned raw_mode : 1; /* op permitted if zft_mode == 0 */ - unsigned need_idle_state : 1; /* need to call def_idle_state */ - char *name; -} fun_entry; - -static mt_fun mt_dummy, mt_reset, mt_fsr, mt_bsr, mt_rew, mt_offl, mt_nop, - mt_weof, mt_erase, mt_ras2, mt_setblk, mt_setdensity, - mt_seek, mt_tell, mt_reten, mt_eom, mt_fsf, mt_bsf, - mt_fsfm, mt_bsfm, mt_setdrvbuffer, mt_compression; - -static fun_entry mt_funs[]= -{ - {mt_reset , 1, 1, 1, 1, 0, "MT_RESET" }, /* 0 */ - {mt_fsf , 0, 1, 0, 0, 1, "MT_FSF" }, - {mt_bsf , 0, 1, 0, 0, 1, "MT_BSF" }, - {mt_fsr , 0, 1, 0, 1, 1, "MT_FSR" }, - {mt_bsr , 0, 1, 0, 1, 1, "MT_BSR" }, - {mt_weof , 0, 0, 0, 0, 0, "MT_WEOF" }, /* 5 */ - {mt_rew , 0, 1, 1, 1, 0, "MT_REW" }, - {mt_offl , 0, 1, 1, 1, 0, "MT_OFFL" }, - {mt_nop , 1, 1, 1, 1, 0, "MT_NOP" }, - {mt_reten , 0, 1, 1, 1, 0, "MT_RETEN" }, - {mt_bsfm , 0, 1, 0, 0, 1, "MT_BSFM" }, /* 10 */ - {mt_fsfm , 0, 1, 0, 0, 1, "MT_FSFM" }, - {mt_eom , 0, 1, 0, 0, 1, "MT_EOM" }, - {mt_erase , 0, 0, 0, 1, 0, "MT_ERASE" }, - {mt_dummy , 1, 1, 1, 1, 0, "MT_RAS1" }, - {mt_ras2 , 0, 0, 0, 1, 0, "MT_RAS2" }, - {mt_dummy , 1, 1, 1, 1, 0, "MT_RAS3" }, - {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, - {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, - {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, - {mt_setblk , 1, 1, 1, 1, 1, "MT_SETBLK"}, /* 20 */ - {mt_setdensity , 1, 1, 1, 1, 0, "MT_SETDENSITY"}, - {mt_seek , 0, 1, 0, 1, 1, "MT_SEEK" }, - {mt_dummy , 0, 1, 0, 1, 1, "MT_TELL" }, /* wr-only ?! */ - {mt_setdrvbuffer, 1, 1, 1, 1, 0, "MT_SETDRVBUFFER" }, - {mt_dummy , 1, 1, 1, 1, 0, "MT_FSS" }, /* 25 */ - {mt_dummy , 1, 1, 1, 1, 0, "MT_BSS" }, - {mt_dummy , 1, 1, 1, 1, 0, "MT_WSM" }, - {mt_dummy , 1, 1, 1, 1, 0, "MT_LOCK" }, - {mt_dummy , 1, 1, 1, 1, 0, "MT_UNLOCK"}, - {mt_dummy , 1, 1, 1, 1, 0, "MT_LOAD" }, /* 30 */ - {mt_dummy , 1, 1, 1, 1, 0, "MT_UNLOAD"}, - {mt_compression , 1, 1, 1, 0, 1, "MT_COMPRESSION"}, - {mt_dummy , 1, 1, 1, 1, 0, "MT_SETPART"}, - {mt_dummy , 1, 1, 1, 1, 0, "MT_MKPART"} -}; - -#define NR_MT_CMDS NR_ITEMS(mt_funs) - -void zft_reset_position(zft_position *pos) -{ - TRACE_FUN(ft_t_flow); - - pos->seg_byte_pos = - pos->volume_pos = 0; - if (zft_header_read) { - /* need to keep track of the volume table and - * compression map. We therefor simply - * position at the beginning of the first - * volume. This covers old ftape archives as - * well has various flavours of the - * compression map segments. The worst case is - * that the compression map shows up as a - * additional volume in front of all others. - */ - pos->seg_pos = zft_find_volume(0)->start_seg; - pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); - } else { - pos->tape_pos = 0; - pos->seg_pos = -1; - } - zft_just_before_eof = 0; - zft_deblock_segment = -1; - zft_io_state = zft_idle; - zft_zap_read_buffers(); - zft_prevent_flush(); - /* unlock the compresison module if it is loaded. - * The zero arg means not to try to load the module. - */ - if (zft_cmpr_lock(0) == 0) { - (*zft_cmpr_ops->reset)(); /* unlock */ - } - TRACE_EXIT; -} - -static void zft_init_driver(void) -{ - TRACE_FUN(ft_t_flow); - - zft_resid = - zft_header_read = - zft_old_ftape = - zft_offline = - zft_write_protected = - going_offline = - zft_mt_compression = - zft_header_changed = - zft_volume_table_changed = - zft_written_segments = 0; - zft_blk_sz = CONFIG_ZFT_DFLT_BLK_SZ; - zft_reset_position(&zft_pos); /* does most of the stuff */ - ftape_zap_read_buffers(); - ftape_set_state(idle); - TRACE_EXIT; -} - -int zft_def_idle_state(void) -{ - int result = 0; - TRACE_FUN(ft_t_flow); - - if (!zft_header_read) { - result = zft_read_header_segments(); - } else if ((result = zft_flush_buffers()) >= 0 && zft_qic_mode) { - /* don't move past eof - */ - (void)zft_close_volume(&zft_pos); - } - if (ftape_abort_operation() < 0) { - TRACE(ft_t_warn, "ftape_abort_operation() failed"); - result = -EIO; - } - /* clear remaining read buffers */ - zft_zap_read_buffers(); - zft_io_state = zft_idle; - TRACE_EXIT result; -} - -/***************************************************************************** - * * - * functions for the MTIOCTOP commands * - * * - *****************************************************************************/ - -static int mt_dummy(int *dummy) -{ - TRACE_FUN(ft_t_flow); - - TRACE_EXIT -ENOSYS; -} - -static int mt_reset(int *dummy) -{ - TRACE_FUN(ft_t_flow); - - (void)ftape_seek_to_bot(); - TRACE_CATCH(ftape_reset_drive(), - zft_init_driver(); zft_uninit_mem(); zft_offline = 1); - /* fake a re-open of the device. This will set all flage and - * allocate buffers as appropriate. The new tape condition will - * force the open routine to do anything we need. - */ - TRACE_CATCH(_zft_open(-1 /* fake reopen */, 0 /* dummy */),); - TRACE_EXIT 0; -} - -static int mt_fsf(int *arg) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = zft_skip_volumes(*arg, &zft_pos); - zft_just_before_eof = 0; - TRACE_EXIT result; -} - -static int mt_bsf(int *arg) -{ - int result = 0; - TRACE_FUN(ft_t_flow); - - if (*arg != 0) { - result = zft_skip_volumes(-*arg + 1, &zft_pos); - } - TRACE_EXIT result; -} - -static int seek_block(__s64 data_offset, - __s64 block_increment, - zft_position *pos) -{ - int result = 0; - __s64 new_block_pos; - __s64 vol_block_count; - const zft_volinfo *volume; - int exceed; - TRACE_FUN(ft_t_flow); - - volume = zft_find_volume(pos->seg_pos); - if (volume->start_seg == 0 || volume->end_seg == 0) { - TRACE_EXIT -EIO; - } - new_block_pos = (zft_div_blksz(data_offset, volume->blk_sz) - + block_increment); - vol_block_count = zft_div_blksz(volume->size, volume->blk_sz); - if (new_block_pos < 0) { - TRACE(ft_t_noise, - "new_block_pos " LL_X " < 0", LL(new_block_pos)); - zft_resid = (int)new_block_pos; - new_block_pos = 0; - exceed = 1; - } else if (new_block_pos > vol_block_count) { - TRACE(ft_t_noise, - "new_block_pos " LL_X " exceeds size of volume " LL_X, - LL(new_block_pos), LL(vol_block_count)); - zft_resid = (int)(vol_block_count - new_block_pos); - new_block_pos = vol_block_count; - exceed = 1; - } else { - exceed = 0; - } - if (zft_use_compression && volume->use_compression) { - TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),); - result = (*zft_cmpr_ops->seek)(new_block_pos, pos, volume, - zft_deblock_buf); - pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); - pos->tape_pos += pos->seg_byte_pos; - } else { - pos->volume_pos = zft_mul_blksz(new_block_pos, volume->blk_sz); - pos->tape_pos = zft_calc_tape_pos(volume->start_seg); - pos->tape_pos += pos->volume_pos; - pos->seg_pos = zft_calc_seg_byte_coord(&pos->seg_byte_pos, - pos->tape_pos); - } - zft_just_before_eof = volume->size == pos->volume_pos; - if (zft_just_before_eof) { - /* why this? because zft_file_no checks agains start - * and end segment of a volume. We do not want to - * advance to the next volume with this function. - */ - TRACE(ft_t_noise, "set zft_just_before_eof"); - zft_position_before_eof(pos, volume); - } - TRACE(ft_t_noise, "\n" - KERN_INFO "new_seg_pos : %d\n" - KERN_INFO "new_tape_pos: " LL_X "\n" - KERN_INFO "vol_size : " LL_X "\n" - KERN_INFO "seg_byte_pos: %d\n" - KERN_INFO "blk_sz : %d", - pos->seg_pos, LL(pos->tape_pos), - LL(volume->size), pos->seg_byte_pos, - volume->blk_sz); - if (!exceed) { - zft_resid = new_block_pos - zft_div_blksz(pos->volume_pos, - volume->blk_sz); - } - if (zft_resid < 0) { - zft_resid = -zft_resid; - } - TRACE_EXIT ((exceed || zft_resid != 0) && result >= 0) ? -EINVAL : result; -} - -static int mt_fsr(int *arg) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = seek_block(zft_pos.volume_pos, *arg, &zft_pos); - TRACE_EXIT result; -} - -static int mt_bsr(int *arg) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = seek_block(zft_pos.volume_pos, -*arg, &zft_pos); - TRACE_EXIT result; -} - -static int mt_weof(int *arg) -{ - int result; - TRACE_FUN(ft_t_flow); - - TRACE_CATCH(zft_flush_buffers(),); - result = zft_weof(*arg, &zft_pos); - TRACE_EXIT result; -} - -static int mt_rew(int *dummy) -{ - int result; - TRACE_FUN(ft_t_flow); - - if(zft_header_read) { - (void)zft_def_idle_state(); - } - result = ftape_seek_to_bot(); - zft_reset_position(&zft_pos); - TRACE_EXIT result; -} - -static int mt_offl(int *dummy) -{ - int result; - TRACE_FUN(ft_t_flow); - - going_offline= 1; - result = mt_rew(NULL); - TRACE_EXIT result; -} - -static int mt_nop(int *dummy) -{ - TRACE_FUN(ft_t_flow); - /* should we set tape status? - */ - if (!zft_offline) { /* offline includes no_tape */ - (void)zft_def_idle_state(); - } - TRACE_EXIT 0; -} - -static int mt_reten(int *dummy) -{ - int result; - TRACE_FUN(ft_t_flow); - - if(zft_header_read) { - (void)zft_def_idle_state(); - } - result = ftape_seek_to_eot(); - if (result >= 0) { - result = ftape_seek_to_bot(); - } - TRACE_EXIT(result); -} - -static int fsfbsfm(int arg, zft_position *pos) -{ - const zft_volinfo *vtbl; - __s64 block_pos; - TRACE_FUN(ft_t_flow); - - /* What to do? This should seek to the next file-mark and - * position BEFORE. That is, a next write would just extend - * the current file. Well. Let's just seek to the end of the - * current file, if count == 1. If count > 1, then do a - * "mt_fsf(count - 1)", and then seek to the end of that file. - * If count == 0, do nothing - */ - if (arg == 0) { - TRACE_EXIT 0; - } - zft_just_before_eof = 0; - TRACE_CATCH(zft_skip_volumes(arg < 0 ? arg : arg-1, pos), - if (arg > 0) { - zft_resid ++; - }); - vtbl = zft_find_volume(pos->seg_pos); - block_pos = zft_div_blksz(vtbl->size, vtbl->blk_sz); - (void)seek_block(0, block_pos, pos); - if (pos->volume_pos != vtbl->size) { - zft_just_before_eof = 0; - zft_resid = 1; - /* we didn't managed to go there */ - TRACE_ABORT(-EIO, ft_t_err, - "wanted file position " LL_X ", arrived at " LL_X, - LL(vtbl->size), LL(pos->volume_pos)); - } - zft_just_before_eof = 1; - TRACE_EXIT 0; -} - -static int mt_bsfm(int *arg) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = fsfbsfm(-*arg, &zft_pos); - TRACE_EXIT result; -} - -static int mt_fsfm(int *arg) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = fsfbsfm(*arg, &zft_pos); - TRACE_EXIT result; -} - -static int mt_eom(int *dummy) -{ - TRACE_FUN(ft_t_flow); - - zft_skip_to_eom(&zft_pos); - TRACE_EXIT 0; -} - -static int mt_erase(int *dummy) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = zft_erase(); - TRACE_EXIT result; -} - -static int mt_ras2(int *dummy) -{ - int result; - TRACE_FUN(ft_t_flow); - - result = -ENOSYS; - TRACE_EXIT result; -} - -/* Sets the new blocksize in BYTES - * - */ -static int mt_setblk(int *new_size) -{ - TRACE_FUN(ft_t_flow); - - if((unsigned int)(*new_size) > ZFT_MAX_BLK_SZ) { - TRACE_ABORT(-EINVAL, ft_t_info, - "desired blk_sz (%d) should be <= %d bytes", - *new_size, ZFT_MAX_BLK_SZ); - } - if ((*new_size & (FT_SECTOR_SIZE-1)) != 0) { - TRACE_ABORT(-EINVAL, ft_t_info, - "desired blk_sz (%d) must be a multiple of %d bytes", - *new_size, FT_SECTOR_SIZE); - } - if (*new_size == 0) { - if (zft_use_compression) { - TRACE_ABORT(-EINVAL, ft_t_info, - "Variable block size not yet " - "supported with compression"); - } - *new_size = 1; - } - zft_blk_sz = *new_size; - TRACE_EXIT 0; -} - -static int mt_setdensity(int *arg) -{ - TRACE_FUN(ft_t_flow); - - SET_TRACE_LEVEL(*arg); - TRACE(TRACE_LEVEL, "tracing set to %d", TRACE_LEVEL); - if ((int)TRACE_LEVEL != *arg) { - TRACE_EXIT -EINVAL; - } - TRACE_EXIT 0; -} - -static int mt_seek(int *new_block_pos) -{ - int result= 0; - TRACE_FUN(ft_t_any); - - result = seek_block(0, (__s64)*new_block_pos, &zft_pos); - TRACE_EXIT result; -} - -/* OK, this is totally different from SCSI, but the worst thing that can - * happen is that there is not enough defragmentated memory that can be - * allocated. Also, there is a hardwired limit of 16 dma buffers in the - * stock ftape module. This shouldn't bring the system down. - * - * NOTE: the argument specifies the total number of dma buffers to use. - * The driver needs at least 3 buffers to function at all. - * - */ -static int mt_setdrvbuffer(int *cnt) -{ - TRACE_FUN(ft_t_flow); - - if (*cnt < 3) { - TRACE_EXIT -EINVAL; - } - TRACE_CATCH(ftape_set_nr_buffers(*cnt),); - TRACE_EXIT 0; -} -/* return the block position from start of volume - */ -static int mt_tell(int *arg) -{ - TRACE_FUN(ft_t_flow); - - *arg = zft_div_blksz(zft_pos.volume_pos, - zft_find_volume(zft_pos.seg_pos)->blk_sz); - TRACE_EXIT 0; -} - -static int mt_compression(int *arg) -{ - TRACE_FUN(ft_t_flow); - - /* Ok. We could also check whether compression is available at - * all by trying to load the compression module. We could - * also check for a block size of 1 byte which is illegal - * with compression. Instead of doing it here we rely on - * zftape_write() to do the proper checks. - */ - if ((unsigned int)*arg > 1) { - TRACE_EXIT -EINVAL; - } - if (*arg != 0 && zft_blk_sz == 1) { /* variable block size */ - TRACE_ABORT(-EINVAL, ft_t_info, - "Compression not yet supported " - "with variable block size"); - } - zft_mt_compression = *arg; - if ((zft_unit & ZFT_ZIP_MODE) == 0) { - zft_use_compression = zft_mt_compression; - } - TRACE_EXIT 0; -} - -/* check whether write access is allowed. Write access is denied when - * + zft_write_protected == 1 -- this accounts for either hard write - * protection of the cartridge or for - * O_RDONLY access mode of the tape device - * + zft_offline == 1 -- this meany that there is either no tape - * or that the MTOFFLINE ioctl has been - * previously issued (`soft eject') - * + ft_formatted == 0 -- this means that the cartridge is not - * formatted - * Then we distinuguish two cases. When zft_qic_mode is TRUE, then we try - * to emulate a `traditional' (aka SCSI like) UN*X tape device. Therefore we - * deny writes when - * + zft_qic_mode ==1 && - * (!zft_tape_at_lbot() && -- tape no at logical BOT - * !(zft_tape_at_eom() || -- tape not at logical EOM (or EOD) - * (zft_tape_at_eom() && - * zft_old_ftape()))) -- we can't add new volume to tapes - * written by old ftape because ftape - * don't use the volume table - * - * when the drive is in true raw mode (aka /dev/rawft0) then we don't - * care about LBOT and EOM conditions. This device is intended for a - * user level program that wants to truly implement the QIC-80 compliance - * at the logical data layout level of the cartridge, i.e. implement all - * that volume table and volume directory stuff etc.< - */ -int zft_check_write_access(zft_position *pos) -{ - TRACE_FUN(ft_t_flow); - - if (zft_offline) { /* offline includes no_tape */ - TRACE_ABORT(-ENXIO, - ft_t_info, "tape is offline or no cartridge"); - } - if (!ft_formatted) { - TRACE_ABORT(-EACCES, ft_t_info, "tape is not formatted"); - } - if (zft_write_protected) { - TRACE_ABORT(-EACCES, ft_t_info, "cartridge write protected"); - } - if (zft_qic_mode) { - /* check BOT condition */ - if (!zft_tape_at_lbot(pos)) { - /* protect cartridges written by old ftape if - * not at BOT because they use the vtbl - * segment for storing data - */ - if (zft_old_ftape) { - TRACE_ABORT(-EACCES, ft_t_warn, - "Cannot write to cartridges written by old ftape when not at BOT"); - } - /* not at BOT, but allow writes at EOD, of course - */ - if (!zft_tape_at_eod(pos)) { - TRACE_ABORT(-EACCES, ft_t_info, - "tape not at BOT and not at EOD"); - } - } - /* fine. Now the tape is either at BOT or at EOD. */ - } - /* or in raw mode in which case we don't care about BOT and EOD */ - TRACE_EXIT 0; -} - -/* OPEN routine called by kernel-interface code - * - * NOTE: this is also called by mt_reset() with dev_minor == -1 - * to fake a reopen after a reset. - */ -int _zft_open(unsigned int dev_minor, unsigned int access_mode) -{ - static unsigned int tape_unit; - static unsigned int file_access_mode; - int result; - TRACE_FUN(ft_t_flow); - - if ((int)dev_minor == -1) { - /* fake reopen */ - zft_unit = tape_unit; - access_mode = file_access_mode; - zft_init_driver(); /* reset all static data to defaults */ - } else { - tape_unit = dev_minor; - file_access_mode = access_mode; - if ((result = ftape_enable(FTAPE_SEL(dev_minor))) < 0) { - TRACE_ABORT(-ENXIO, ft_t_err, - "ftape_enable failed: %d", result); - } - if (ft_new_tape || ft_no_tape || !ft_formatted || - (FTAPE_SEL(zft_unit) != FTAPE_SEL(dev_minor)) || - (zft_unit & ZFT_RAW_MODE) != (dev_minor & ZFT_RAW_MODE)) { - /* reset all static data to defaults, - */ - zft_init_driver(); - } - zft_unit = dev_minor; - } - zft_set_flags(zft_unit); /* decode the minor bits */ - if (zft_blk_sz == 1 && zft_use_compression) { - ftape_disable(); /* resets ft_no_tape */ - TRACE_ABORT(-ENODEV, ft_t_warn, "Variable block size not yet " - "supported with compression"); - } - /* no need for most of the buffers when no tape or not - * formatted. for the read/write operations, it is the - * regardless whether there is no tape, a not-formatted tape - * or the whether the driver is soft offline. - * Nevertheless we allow some ioctls with non-formatted tapes, - * like rewind and reset. - */ - if (ft_no_tape || !ft_formatted) { - zft_uninit_mem(); - } - if (ft_no_tape) { - zft_offline = 1; /* so we need not test two variables */ - } - if ((access_mode == O_WRONLY || access_mode == O_RDWR) && - (ft_write_protected || ft_no_tape)) { - ftape_disable(); /* resets ft_no_tape */ - TRACE_ABORT(ft_no_tape ? -ENXIO : -EROFS, - ft_t_warn, "wrong access mode %s cartridge", - ft_no_tape ? "without a" : "with write protected"); - } - zft_write_protected = (access_mode == O_RDONLY || - ft_write_protected != 0); - if (zft_write_protected) { - TRACE(ft_t_noise, - "read only access mode: %d, " - "drive write protected: %d", - access_mode == O_RDONLY, - ft_write_protected != 0); - } - if (!zft_offline) { - TRACE_CATCH(zft_vmalloc_once(&zft_deblock_buf,FT_SEGMENT_SIZE), - ftape_disable()); - } - /* zft_seg_pos should be greater than the vtbl segpos but not - * if in compatibility mode and only after we read in the - * header segments - * - * might also be a problem if the user makes a backup with a - * *qft* device and rewinds it with a raw device. - */ - if (zft_qic_mode && - !zft_old_ftape && - zft_pos.seg_pos >= 0 && - zft_header_read && - zft_pos.seg_pos <= ft_first_data_segment) { - TRACE(ft_t_noise, "you probably mixed up the zftape devices!"); - zft_reset_position(&zft_pos); - } - TRACE_EXIT 0; -} - -/* RELEASE routine called by kernel-interface code - */ -int _zft_close(void) -{ - int result = 0; - TRACE_FUN(ft_t_flow); - - if (zft_offline) { - /* call the hardware release routine. Puts the drive offline */ - ftape_disable(); - TRACE_EXIT 0; - } - if (!(ft_write_protected || zft_old_ftape)) { - result = zft_flush_buffers(); - TRACE(ft_t_noise, "writing file mark at current position"); - if (zft_qic_mode && zft_close_volume(&zft_pos) == 0) { - zft_move_past_eof(&zft_pos); - } - if ((zft_tape_at_lbot(&zft_pos) || - !(zft_unit & FTAPE_NO_REWIND))) { - if (result >= 0) { - result = zft_update_header_segments(); - } else { - TRACE(ft_t_err, - "Error: unable to update header segments"); - } - } - } - ftape_abort_operation(); - if (!(zft_unit & FTAPE_NO_REWIND)) { - TRACE(ft_t_noise, "rewinding tape"); - if (ftape_seek_to_bot() < 0 && result >= 0) { - result = -EIO; /* keep old value */ - } - zft_reset_position(&zft_pos); - } - zft_zap_read_buffers(); - /* now free up memory as much as possible. We don't destroy - * the deblock buffer if it containes a valid segment. - */ - if (zft_deblock_segment == -1) { - zft_vfree(&zft_deblock_buf, FT_SEGMENT_SIZE); - } - /* high level driver status, forces creation of a new volume - * when calling ftape_write again and not zft_just_before_eof - */ - zft_io_state = zft_idle; - if (going_offline) { - zft_init_driver(); - zft_uninit_mem(); - going_offline = 0; - zft_offline = 1; - } else if (zft_cmpr_lock(0 /* don't load */) == 0) { - (*zft_cmpr_ops->reset)(); /* unlock it again */ - } - zft_memory_stats(); - /* call the hardware release routine. Puts the drive offline */ - ftape_disable(); - TRACE_EXIT result; -} - -/* - * the wrapper function around the wrapper MTIOCTOP ioctl - */ -static int mtioctop(struct mtop *mtop, int arg_size) -{ - int result = 0; - fun_entry *mt_fun_entry; - TRACE_FUN(ft_t_flow); - - if (arg_size != sizeof(struct mtop) || mtop->mt_op >= NR_MT_CMDS) { - TRACE_EXIT -EINVAL; - } - TRACE(ft_t_noise, "calling MTIOCTOP command: %s", - mt_funs[mtop->mt_op].name); - mt_fun_entry= &mt_funs[mtop->mt_op]; - zft_resid = mtop->mt_count; - if (!mt_fun_entry->offline && zft_offline) { - if (ft_no_tape) { - TRACE_ABORT(-ENXIO, ft_t_info, "no tape present"); - } else { - TRACE_ABORT(-ENXIO, ft_t_info, "drive is offline"); - } - } - if (!mt_fun_entry->not_formatted && !ft_formatted) { - TRACE_ABORT(-EACCES, ft_t_info, "tape is not formatted"); - } - if (!mt_fun_entry->write_protected) { - TRACE_CATCH(zft_check_write_access(&zft_pos),); - } - if (mt_fun_entry->need_idle_state && !(zft_offline || !ft_formatted)) { - TRACE_CATCH(zft_def_idle_state(),); - } - if (!zft_qic_mode && !mt_fun_entry->raw_mode) { - TRACE_ABORT(-EACCES, ft_t_info, -"Drive needs to be in QIC-80 compatibility mode for this command"); - } - result = (mt_fun_entry->function)(&mtop->mt_count); - if (zft_tape_at_lbot(&zft_pos)) { - TRACE_CATCH(zft_update_header_segments(),); - } - if (result >= 0) { - zft_resid = 0; - } - TRACE_EXIT result; -} - -/* - * standard MTIOCGET ioctl - */ -static int mtiocget(struct mtget *mtget, int arg_size) -{ - const zft_volinfo *volume; - __s64 max_tape_pos; - TRACE_FUN(ft_t_flow); - - if (arg_size != sizeof(struct mtget)) { - TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", - arg_size); - } - mtget->mt_type = ft_drive_type.vendor_id + 0x800000; - mtget->mt_dsreg = ft_last_status.space; - mtget->mt_erreg = ft_last_error.space; /* error register */ - mtget->mt_resid = zft_resid; /* residuum of writes, reads and - * MTIOCTOP commands - */ - if (!zft_offline) { /* neither no_tape nor soft offline */ - mtget->mt_gstat = GMT_ONLINE(~0UL); - /* should rather return the status of the cartridge - * than the access mode of the file, therefor use - * ft_write_protected, not zft_write_protected - */ - if (ft_write_protected) { - mtget->mt_gstat |= GMT_WR_PROT(~0UL); - } - if(zft_header_read) { /* this catches non-formatted */ - volume = zft_find_volume(zft_pos.seg_pos); - mtget->mt_fileno = volume->count; - max_tape_pos = zft_capacity - zft_blk_sz; - if (zft_use_compression) { - max_tape_pos -= ZFT_CMPR_OVERHEAD; - } - if (zft_tape_at_eod(&zft_pos)) { - mtget->mt_gstat |= GMT_EOD(~0UL); - } - if (zft_pos.tape_pos > max_tape_pos) { - mtget->mt_gstat |= GMT_EOT(~0UL); - } - mtget->mt_blkno = zft_div_blksz(zft_pos.volume_pos, - volume->blk_sz); - if (zft_just_before_eof) { - mtget->mt_gstat |= GMT_EOF(~0UL); - } - if (zft_tape_at_lbot(&zft_pos)) { - mtget->mt_gstat |= GMT_BOT(~0UL); - } - } else { - mtget->mt_fileno = mtget->mt_blkno = -1; - if (mtget->mt_dsreg & QIC_STATUS_AT_BOT) { - mtget->mt_gstat |= GMT_BOT(~0UL); - } - } - } else { - if (ft_no_tape) { - mtget->mt_gstat = GMT_DR_OPEN(~0UL); - } else { - mtget->mt_gstat = 0UL; - } - mtget->mt_fileno = mtget->mt_blkno = -1; - } - TRACE_EXIT 0; -} - -#ifdef MTIOCRDFTSEG -/* - * Read a floppy tape segment. This is useful for manipulating the - * volume table, and read the old header segment before re-formatting - * the cartridge. - */ -static int mtiocrdftseg(struct mtftseg * mtftseg, int arg_size) -{ - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCRDFTSEG"); - if (zft_qic_mode) { - TRACE_ABORT(-EACCES, ft_t_info, - "driver needs to be in raw mode for this ioctl"); - } - if (arg_size != sizeof(struct mtftseg)) { - TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", - arg_size); - } - if (zft_offline) { - TRACE_EXIT -ENXIO; - } - if (mtftseg->mt_mode != FT_RD_SINGLE && - mtftseg->mt_mode != FT_RD_AHEAD) { - TRACE_ABORT(-EINVAL, ft_t_info, "invalid read mode"); - } - if (!ft_formatted) { - TRACE_EXIT -EACCES; /* -ENXIO ? */ - - } - if (!zft_header_read) { - TRACE_CATCH(zft_def_idle_state(),); - } - if (mtftseg->mt_segno > ft_last_data_segment) { - TRACE_ABORT(-EINVAL, ft_t_info, "segment number is too large"); - } - mtftseg->mt_result = ftape_read_segment(mtftseg->mt_segno, - zft_deblock_buf, - mtftseg->mt_mode); - if (mtftseg->mt_result < 0) { - /* a negativ result is not an ioctl error. if - * the user wants to read damaged tapes, - * it's up to her/him - */ - TRACE_EXIT 0; - } - if (copy_to_user(mtftseg->mt_data, - zft_deblock_buf, - mtftseg->mt_result) != 0) { - TRACE_EXIT -EFAULT; - } - TRACE_EXIT 0; -} -#endif - -#ifdef MTIOCWRFTSEG -/* - * write a floppy tape segment. This version features writing of - * deleted address marks, and gracefully ignores the (software) - * ft_formatted flag to support writing of header segments after - * formatting. - */ -static int mtiocwrftseg(struct mtftseg * mtftseg, int arg_size) -{ - int result; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCWRFTSEG"); - if (zft_write_protected || zft_qic_mode) { - TRACE_EXIT -EACCES; - } - if (arg_size != sizeof(struct mtftseg)) { - TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", - arg_size); - } - if (zft_offline) { - TRACE_EXIT -ENXIO; - } - if (mtftseg->mt_mode != FT_WR_ASYNC && - mtftseg->mt_mode != FT_WR_MULTI && - mtftseg->mt_mode != FT_WR_SINGLE && - mtftseg->mt_mode != FT_WR_DELETE) { - TRACE_ABORT(-EINVAL, ft_t_info, "invalid write mode"); - } - /* - * We don't check for ft_formatted, because this gives - * only the software status of the driver. - * - * We assume that the user knows what it is - * doing. And rely on the low level stuff to fail - * when the tape isn't formatted. We only make sure - * that The header segment buffer is allocated, - * because it holds the bad sector map. - */ - if (zft_hseg_buf == NULL) { - TRACE_EXIT -ENXIO; - } - if (mtftseg->mt_mode != FT_WR_DELETE) { - if (copy_from_user(zft_deblock_buf, - mtftseg->mt_data, - FT_SEGMENT_SIZE) != 0) { - TRACE_EXIT -EFAULT; - } - } - mtftseg->mt_result = ftape_write_segment(mtftseg->mt_segno, - zft_deblock_buf, - mtftseg->mt_mode); - if (mtftseg->mt_result >= 0 && mtftseg->mt_mode == FT_WR_SINGLE) { - /* - * a negativ result is not an ioctl error. if - * the user wants to write damaged tapes, - * it's up to her/him - */ - if ((result = ftape_loop_until_writes_done()) < 0) { - mtftseg->mt_result = result; - } - } - TRACE_EXIT 0; -} -#endif - -#ifdef MTIOCVOLINFO -/* - * get information about volume positioned at. - */ -static int mtiocvolinfo(struct mtvolinfo *volinfo, int arg_size) -{ - const zft_volinfo *volume; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCVOLINFO"); - if (arg_size != sizeof(struct mtvolinfo)) { - TRACE_ABORT(-EINVAL, - ft_t_info, "bad argument size: %d", arg_size); - } - if (zft_offline) { - TRACE_EXIT -ENXIO; - } - if (!ft_formatted) { - TRACE_EXIT -EACCES; - } - TRACE_CATCH(zft_def_idle_state(),); - volume = zft_find_volume(zft_pos.seg_pos); - volinfo->mt_volno = volume->count; - volinfo->mt_blksz = volume->blk_sz == 1 ? 0 : volume->blk_sz; - volinfo->mt_size = volume->size >> 10; - volinfo->mt_rawsize = ((zft_calc_tape_pos(volume->end_seg + 1) >> 10) - - (zft_calc_tape_pos(volume->start_seg) >> 10)); - volinfo->mt_cmpr = volume->use_compression; - TRACE_EXIT 0; -} -#endif - -#ifdef ZFT_OBSOLETE -static int mtioc_zftape_getblksz(struct mtblksz *blksz, int arg_size) -{ - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "\n" - KERN_INFO "Mag tape ioctl command: MTIOC_ZTAPE_GETBLKSZ\n" - KERN_INFO "This ioctl is here merely for compatibility.\n" - KERN_INFO "Please use MTIOCVOLINFO instead"); - if (arg_size != sizeof(struct mtblksz)) { - TRACE_ABORT(-EINVAL, - ft_t_info, "bad argument size: %d", arg_size); - } - if (zft_offline) { - TRACE_EXIT -ENXIO; - } - if (!ft_formatted) { - TRACE_EXIT -EACCES; - } - TRACE_CATCH(zft_def_idle_state(),); - blksz->mt_blksz = zft_find_volume(zft_pos.seg_pos)->blk_sz; - TRACE_EXIT 0; -} -#endif - -#ifdef MTIOCGETSIZE -/* - * get the capacity of the tape cartridge. - */ -static int mtiocgetsize(struct mttapesize *size, int arg_size) -{ - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOC_ZFTAPE_GETSIZE"); - if (arg_size != sizeof(struct mttapesize)) { - TRACE_ABORT(-EINVAL, - ft_t_info, "bad argument size: %d", arg_size); - } - if (zft_offline) { - TRACE_EXIT -ENXIO; - } - if (!ft_formatted) { - TRACE_EXIT -EACCES; - } - TRACE_CATCH(zft_def_idle_state(),); - size->mt_capacity = (unsigned int)(zft_capacity>>10); - size->mt_used = (unsigned int)(zft_get_eom_pos()>>10); - TRACE_EXIT 0; -} -#endif - -static int mtiocpos(struct mtpos *mtpos, int arg_size) -{ - int result; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCPOS"); - if (arg_size != sizeof(struct mtpos)) { - TRACE_ABORT(-EINVAL, - ft_t_info, "bad argument size: %d", arg_size); - } - result = mt_tell((int *)&mtpos->mt_blkno); - TRACE_EXIT result; -} - -#ifdef MTIOCFTFORMAT -/* - * formatting of floppy tape cartridges. This is intended to be used - * together with the MTIOCFTCMD ioctl and the new mmap feature - */ - -/* - * This function uses ftape_decode_header_segment() to inform the low - * level ftape module about the new parameters. - * - * It erases the hseg_buf. The calling process must specify all - * parameters to assure proper operation. - * - * return values: -EINVAL - wrong argument size - * -EINVAL - if ftape_decode_header_segment() failed. - */ -static int set_format_parms(struct ftfmtparms *p, __u8 *hseg_buf) -{ - ft_trace_t old_level = TRACE_LEVEL; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "MTIOCFTFORMAT operation FTFMT_SETPARMS"); - memset(hseg_buf, 0, FT_SEGMENT_SIZE); - PUT4(hseg_buf, FT_SIGNATURE, FT_HSEG_MAGIC); - - /* fill in user specified parameters - */ - hseg_buf[FT_FMT_CODE] = (__u8)p->ft_fmtcode; - PUT2(hseg_buf, FT_SPT, p->ft_spt); - hseg_buf[FT_TPC] = (__u8)p->ft_tpc; - hseg_buf[FT_FHM] = (__u8)p->ft_fhm; - hseg_buf[FT_FTM] = (__u8)p->ft_ftm; - - /* fill in sane defaults to make ftape happy. - */ - hseg_buf[FT_FSM] = (__u8)128; /* 128 is hard wired all over ftape */ - if (p->ft_fmtcode == fmt_big) { - PUT4(hseg_buf, FT_6_HSEG_1, 0); - PUT4(hseg_buf, FT_6_HSEG_2, 1); - PUT4(hseg_buf, FT_6_FRST_SEG, 2); - PUT4(hseg_buf, FT_6_LAST_SEG, p->ft_spt * p->ft_tpc - 1); - } else { - PUT2(hseg_buf, FT_HSEG_1, 0); - PUT2(hseg_buf, FT_HSEG_2, 1); - PUT2(hseg_buf, FT_FRST_SEG, 2); - PUT2(hseg_buf, FT_LAST_SEG, p->ft_spt * p->ft_tpc - 1); - } - - /* Synchronize with the low level module. This is particularly - * needed for unformatted cartridges as the QIC std was previously - * unknown BUT is needed to set data rate and to calculate timeouts. - */ - TRACE_CATCH(ftape_calibrate_data_rate(p->ft_qicstd&QIC_TAPE_STD_MASK), - _res = -EINVAL); - - /* The following will also recalcualte the timeouts for the tape - * length and QIC std we want to format to. - * abort with -EINVAL rather than -EIO - */ - SET_TRACE_LEVEL(ft_t_warn); - TRACE_CATCH(ftape_decode_header_segment(hseg_buf), - SET_TRACE_LEVEL(old_level); _res = -EINVAL); - SET_TRACE_LEVEL(old_level); - TRACE_EXIT 0; -} - -/* - * Return the internal SOFTWARE status of the kernel driver. This does - * NOT query the tape drive about its status. - */ -static int get_format_parms(struct ftfmtparms *p, __u8 *hseg_buffer) -{ - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "MTIOCFTFORMAT operation FTFMT_GETPARMS"); - p->ft_qicstd = ft_qic_std; - p->ft_fmtcode = ft_format_code; - p->ft_fhm = hseg_buffer[FT_FHM]; - p->ft_ftm = hseg_buffer[FT_FTM]; - p->ft_spt = ft_segments_per_track; - p->ft_tpc = ft_tracks_per_tape; - TRACE_EXIT 0; -} - -static int mtiocftformat(struct mtftformat *mtftformat, int arg_size) -{ - int result; - union fmt_arg *arg = &mtftformat->fmt_arg; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCFTFORMAT"); - if (zft_offline) { - if (ft_no_tape) { - TRACE_ABORT(-ENXIO, ft_t_info, "no tape present"); - } else { - TRACE_ABORT(-ENXIO, ft_t_info, "drive is offline"); - } - } - if (zft_qic_mode) { - TRACE_ABORT(-EACCES, ft_t_info, - "driver needs to be in raw mode for this ioctl"); - } - if (zft_hseg_buf == NULL) { - TRACE_CATCH(zft_vcalloc_once(&zft_hseg_buf, FT_SEGMENT_SIZE),); - } - zft_header_read = 0; - switch(mtftformat->fmt_op) { - case FTFMT_SET_PARMS: - TRACE_CATCH(set_format_parms(&arg->fmt_parms, zft_hseg_buf),); - TRACE_EXIT 0; - case FTFMT_GET_PARMS: - TRACE_CATCH(get_format_parms(&arg->fmt_parms, zft_hseg_buf),); - TRACE_EXIT 0; - case FTFMT_FORMAT_TRACK: - if ((ft_formatted && zft_check_write_access(&zft_pos) < 0) || - (!ft_formatted && zft_write_protected)) { - TRACE_ABORT(-EACCES, ft_t_info, "Write access denied"); - } - TRACE_CATCH(ftape_format_track(arg->fmt_track.ft_track, - arg->fmt_track.ft_gap3),); - TRACE_EXIT 0; - case FTFMT_STATUS: - TRACE_CATCH(ftape_format_status(&arg->fmt_status.ft_segment),); - TRACE_EXIT 0; - case FTFMT_VERIFY: - TRACE_CATCH(ftape_verify_segment(arg->fmt_verify.ft_segment, - (SectorMap *)&arg->fmt_verify.ft_bsm),); - TRACE_EXIT 0; - default: - TRACE_ABORT(-EINVAL, ft_t_err, "Invalid format operation"); - } - TRACE_EXIT result; -} -#endif - -#ifdef MTIOCFTCMD -/* - * send a QIC-117 command to the drive, with optional timeouts, - * parameter and result bits. This is intended to be used together - * with the formatting ioctl. - */ -static int mtiocftcmd(struct mtftcmd *ftcmd, int arg_size) -{ - int i; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCFTCMD"); - if (!capable(CAP_SYS_ADMIN)) { - TRACE_ABORT(-EPERM, ft_t_info, - "need CAP_SYS_ADMIN capability to send raw qic-117 commands"); - } - if (zft_qic_mode) { - TRACE_ABORT(-EACCES, ft_t_info, - "driver needs to be in raw mode for this ioctl"); - } - if (arg_size != sizeof(struct mtftcmd)) { - TRACE_ABORT(-EINVAL, - ft_t_info, "bad argument size: %d", arg_size); - } - if (ftcmd->ft_wait_before) { - TRACE_CATCH(ftape_ready_wait(ftcmd->ft_wait_before, - &ftcmd->ft_status),); - } - if (ftcmd->ft_status & QIC_STATUS_ERROR) - goto ftmtcmd_error; - if (ftcmd->ft_result_bits != 0) { - TRACE_CATCH(ftape_report_operation(&ftcmd->ft_result, - ftcmd->ft_cmd, - ftcmd->ft_result_bits),); - } else { - TRACE_CATCH(ftape_command(ftcmd->ft_cmd),); - if (ftcmd->ft_status & QIC_STATUS_ERROR) - goto ftmtcmd_error; - for (i = 0; i < ftcmd->ft_parm_cnt; i++) { - TRACE_CATCH(ftape_parameter(ftcmd->ft_parms[i]&0x0f),); - if (ftcmd->ft_status & QIC_STATUS_ERROR) - goto ftmtcmd_error; - } - } - if (ftcmd->ft_wait_after != 0) { - TRACE_CATCH(ftape_ready_wait(ftcmd->ft_wait_after, - &ftcmd->ft_status),); - } -ftmtcmd_error: - if (ftcmd->ft_status & QIC_STATUS_ERROR) { - TRACE(ft_t_noise, "error status set"); - TRACE_CATCH(ftape_report_error(&ftcmd->ft_error, - &ftcmd->ft_cmd, 1),); - } - TRACE_EXIT 0; /* this is not an i/o error */ -} -#endif - -/* IOCTL routine called by kernel-interface code - */ -int _zft_ioctl(unsigned int command, void __user * arg) -{ - int result; - union { struct mtop mtop; - struct mtget mtget; - struct mtpos mtpos; -#ifdef MTIOCRDFTSEG - struct mtftseg mtftseg; -#endif -#ifdef MTIOCVOLINFO - struct mtvolinfo mtvolinfo; -#endif -#ifdef MTIOCGETSIZE - struct mttapesize mttapesize; -#endif -#ifdef MTIOCFTFORMAT - struct mtftformat mtftformat; -#endif -#ifdef ZFT_OBSOLETE - struct mtblksz mtblksz; -#endif -#ifdef MTIOCFTCMD - struct mtftcmd mtftcmd; -#endif - } krnl_arg; - int arg_size = _IOC_SIZE(command); - int dir = _IOC_DIR(command); - TRACE_FUN(ft_t_flow); - - /* This check will only catch arguments that are too large ! - */ - if (dir & (_IOC_READ | _IOC_WRITE) && arg_size > sizeof(krnl_arg)) { - TRACE_ABORT(-EINVAL, - ft_t_info, "bad argument size: %d", arg_size); - } - if (dir & _IOC_WRITE) { - if (copy_from_user(&krnl_arg, arg, arg_size) != 0) { - TRACE_EXIT -EFAULT; - } - } - TRACE(ft_t_flow, "called with ioctl command: 0x%08x", command); - switch (command) { - case MTIOCTOP: - result = mtioctop(&krnl_arg.mtop, arg_size); - break; - case MTIOCGET: - result = mtiocget(&krnl_arg.mtget, arg_size); - break; - case MTIOCPOS: - result = mtiocpos(&krnl_arg.mtpos, arg_size); - break; -#ifdef MTIOCVOLINFO - case MTIOCVOLINFO: - result = mtiocvolinfo(&krnl_arg.mtvolinfo, arg_size); - break; -#endif -#ifdef ZFT_OBSOLETE - case MTIOC_ZFTAPE_GETBLKSZ: - result = mtioc_zftape_getblksz(&krnl_arg.mtblksz, arg_size); - break; -#endif -#ifdef MTIOCRDFTSEG - case MTIOCRDFTSEG: /* read a segment via ioctl */ - result = mtiocrdftseg(&krnl_arg.mtftseg, arg_size); - break; -#endif -#ifdef MTIOCWRFTSEG - case MTIOCWRFTSEG: /* write a segment via ioctl */ - result = mtiocwrftseg(&krnl_arg.mtftseg, arg_size); - break; -#endif -#ifdef MTIOCGETSIZE - case MTIOCGETSIZE: - result = mtiocgetsize(&krnl_arg.mttapesize, arg_size); - break; -#endif -#ifdef MTIOCFTFORMAT - case MTIOCFTFORMAT: - result = mtiocftformat(&krnl_arg.mtftformat, arg_size); - break; -#endif -#ifdef MTIOCFTCMD - case MTIOCFTCMD: - result = mtiocftcmd(&krnl_arg.mtftcmd, arg_size); - break; -#endif - default: - result = -EINVAL; - break; - } - if ((result >= 0) && (dir & _IOC_READ)) { - if (copy_to_user(arg, &krnl_arg, arg_size) != 0) { - TRACE_EXIT -EFAULT; - } - } - TRACE_EXIT result; -} diff --git a/drivers/char/ftape/zftape/zftape-ctl.h b/drivers/char/ftape/zftape/zftape-ctl.h deleted file mode 100644 index 8e6f2d7ac74..00000000000 --- a/drivers/char/ftape/zftape/zftape-ctl.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _ZFTAPE_CTL_H -#define _ZFTAPE_CTL_H - -/* - * Copyright (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/zftape/zftape-ctl.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:02 $ - * - * This file contains the non-standard IOCTL related definitions - * for the QIC-40/80 floppy-tape driver for Linux. - */ - -#include -#include - -#include "../zftape/zftape-rw.h" - -#ifdef CONFIG_ZFTAPE_MODULE -#define ftape_status (*zft_status) -#endif - -extern int zft_offline; -extern int zft_mt_compression; -extern int zft_write_protected; -extern int zft_header_read; -extern unsigned int zft_unit; -extern int zft_resid; - -extern void zft_reset_position(zft_position *pos); -extern int zft_check_write_access(zft_position *pos); -extern int zft_def_idle_state(void); - -/* hooks for the VFS interface - */ -extern int _zft_open(unsigned int dev_minor, unsigned int access_mode); -extern int _zft_close(void); -extern int _zft_ioctl(unsigned int command, void __user *arg); -#endif - - - diff --git a/drivers/char/ftape/zftape/zftape-eof.c b/drivers/char/ftape/zftape/zftape-eof.c deleted file mode 100644 index dcadcaee9ac..00000000000 --- a/drivers/char/ftape/zftape/zftape-eof.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * I use these routines just to decide when I have to fake a - * volume-table to preserve compatibility to original ftape. - */ -/* - * Copyright (C) 1994-1995 Bas Laarhoven. - * - * Modified for zftape 1996, 1997 Claus 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/zftape/zftape-eof.c,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:02 $ - * - * This file contains the eof mark handling code - * for the QIC-40/80 floppy-tape driver for Linux. - */ - -#include -#include - -#include - -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-rw.h" -#include "../zftape/zftape-eof.h" - -/* Global vars. - */ - -/* a copy of the failed sector log from the header segment. - */ -eof_mark_union *zft_eof_map; - -/* number of eof marks (entries in bad sector log) on tape. - */ -int zft_nr_eof_marks = -1; - - -/* Local vars. - */ - -static char linux_tape_label[] = "Linux raw format V"; -enum { - min_fmt_version = 1, max_fmt_version = 2 -}; -static unsigned ftape_fmt_version = 0; - - -/* Ftape (mis)uses the bad sector log to record end-of-file marks. - * Initially (when the tape is erased) all entries in the bad sector - * log are added to the tape's bad sector map. The bad sector log then - * is cleared. - * - * The bad sector log normally contains entries of the form: - * even 16-bit word: segment number of bad sector - * odd 16-bit word: encoded date - * There can be a total of 448 entries (1792 bytes). - * - * My guess is that no program is using this bad sector log (the * - * format seems useless as there is no indication of the bad sector - * itself, only the segment) However, if any program does use the bad - * sector log, the format used by ftape will let the program think - * there are some bad sectors and no harm is done. - * - * The eof mark entries that ftape stores in the bad sector log: even - * 16-bit word: segment number of eof mark odd 16-bit word: sector - * number of eof mark [1..32] - * - * The zft_eof_map as maintained is a sorted list of eof mark entries. - * - * - * The tape name field in the header segments is used to store a linux - * tape identification string and a version number. This way the tape - * can be recognized as a Linux raw format tape when using tools under - * other OS's. - * - * 'Wide' QIC tapes (format code 4) don't have a failed sector list - * anymore. That space is used for the (longer) bad sector map that - * now is a variable length list too. We now store our end-of-file - * marker list after the bad-sector-map on tape. The list is delimited - * by a (__u32) 0 entry. - */ - -int zft_ftape_validate_label(char *label) -{ - static char tmp_label[45]; - int result = 0; - TRACE_FUN(ft_t_any); - - memcpy(tmp_label, label, FT_LABEL_SZ); - tmp_label[FT_LABEL_SZ] = '\0'; - TRACE(ft_t_noise, "tape label = `%s'", tmp_label); - ftape_fmt_version = 0; - if (memcmp(label, linux_tape_label, strlen(linux_tape_label)) == 0) { - int pos = strlen(linux_tape_label); - while (label[pos] >= '0' && label[pos] <= '9') { - ftape_fmt_version *= 10; - ftape_fmt_version = label[ pos++] - '0'; - } - result = (ftape_fmt_version >= min_fmt_version && - ftape_fmt_version <= max_fmt_version); - } - TRACE(ft_t_noise, "format version = %d", ftape_fmt_version); - TRACE_EXIT result; -} - -static __u8 * find_end_of_eof_list(__u8 * ptr, __u8 * limit) -{ - while (ptr + 3 < limit) { - - if (get_unaligned((__u32*)ptr)) { - ptr += sizeof(__u32); - } else { - return ptr; - } - } - return NULL; -} - -void zft_ftape_extract_file_marks(__u8* address) -{ - int i; - TRACE_FUN(ft_t_any); - - zft_eof_map = NULL; - if (ft_format_code == fmt_var || ft_format_code == fmt_big) { - __u8* end; - __u8* start = ftape_find_end_of_bsm_list(address); - - zft_nr_eof_marks = 0; - if (start) { - start += 3; /* skip end of list mark */ - end = find_end_of_eof_list(start, - address + FT_SEGMENT_SIZE); - if (end && end - start <= FT_FSL_SIZE) { - zft_nr_eof_marks = ((end - start) / - sizeof(eof_mark_union)); - zft_eof_map = (eof_mark_union *)start; - } else { - TRACE(ft_t_err, - "EOF Mark List is too long or damaged!"); - } - } else { - TRACE(ft_t_err, - "Bad Sector List is too long or damaged !"); - } - } else { - zft_eof_map = (eof_mark_union *)&address[FT_FSL]; - zft_nr_eof_marks = GET2(address, FT_FSL_CNT); - } - TRACE(ft_t_noise, "number of file marks: %d", zft_nr_eof_marks); - if (ftape_fmt_version == 1) { - TRACE(ft_t_info, "swapping version 1 fields"); - /* version 1 format uses swapped sector and segment - * fields, correct that ! - */ - for (i = 0; i < zft_nr_eof_marks; ++i) { - __u16 tmp = GET2(&zft_eof_map[i].mark.segment,0); - PUT2(&zft_eof_map[i].mark.segment, 0, - GET2(&zft_eof_map[i].mark.date,0)); - PUT2(&zft_eof_map[i].mark.date, 0, tmp); - } - } - for (i = 0; i < zft_nr_eof_marks; ++i) { - TRACE(ft_t_noise, "eof mark: %5d/%2d", - GET2(&zft_eof_map[i].mark.segment, 0), - GET2(&zft_eof_map[i].mark.date,0)); - } - TRACE_EXIT; -} - -void zft_clear_ftape_file_marks(void) -{ - TRACE_FUN(ft_t_flow); - /* Clear failed sector log: remove all tape marks. We - * don't use old ftape-style EOF-marks. - */ - TRACE(ft_t_info, "Clearing old ftape's eof map"); - memset(zft_eof_map, 0, zft_nr_eof_marks * sizeof(__u32)); - zft_nr_eof_marks = 0; - PUT2(zft_hseg_buf, FT_FSL_CNT, 0); /* nr of eof-marks */ - zft_header_changed = 1; - zft_update_label(zft_hseg_buf); - TRACE_EXIT; -} diff --git a/drivers/char/ftape/zftape/zftape-eof.h b/drivers/char/ftape/zftape/zftape-eof.h deleted file mode 100644 index 26568c26c51..00000000000 --- a/drivers/char/ftape/zftape/zftape-eof.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef _ZFTAPE_EOF_H -#define _ZFTAPE_EOF_H - -/* - * Copyright (C) 1994-1995 Bas Laarhoven. - * adaptaed for zftape 1996, 1997 by Claus 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/zftape/zftape-eof.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:03 $ - * - * Definitions and declarations for the end of file markers - * for the QIC-40/80 floppy-tape driver for Linux. - */ - -#include -#include "../zftape/zftape-buffers.h" -/* failed sector log size (only used if format code != 4). - */ - -typedef union { - ft_fsl_entry mark; - __u32 entry; -} eof_mark_union; - -/* ftape-eof.c defined global vars. - */ -extern int zft_nr_eof_marks; -extern eof_mark_union *zft_eof_map; - -/* ftape-eof.c defined global functions. - */ -extern void zft_ftape_extract_file_marks(__u8* address); -extern int zft_ftape_validate_label(char* label); -extern void zft_clear_ftape_file_marks(void); - -#endif diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c deleted file mode 100644 index 164a1aa77a2..00000000000 --- a/drivers/char/ftape/zftape/zftape-init.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright (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. - - * - * This file contains the code that registers the zftape frontend - * to the ftape floppy tape driver for Linux - */ - -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_KMOD -#include -#endif -#include -#include - -#include -#include -#include - -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-write.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-buffers.h" - -MODULE_AUTHOR("(c) 1996, 1997 Claus-Justus Heine " - "(claus@momo.math.rwth-aachen.de)"); -MODULE_DESCRIPTION(ZFTAPE_VERSION " - " - "VFS interface for the Linux floppy tape driver. " - "Support for QIC-113 compatible volume table " - "and builtin compression (lzrw3 algorithm)"); -MODULE_SUPPORTED_DEVICE("char-major-27"); -MODULE_LICENSE("GPL"); - -/* Global vars. - */ -struct zft_cmpr_ops *zft_cmpr_ops = NULL; -const ftape_info *zft_status; - -/* Local vars. - */ -static unsigned long busy_flag; - -static sigset_t orig_sigmask; - -/* the interface to the kernel vfs layer - */ - -/* Note about llseek(): - * - * st.c and tpqic.c update fp->f_pos but don't implment llseek() and - * initialize the llseek component of the file_ops struct with NULL. - * This means that the user will get the default seek, but the tape - * device will not respect the new position, but happily read from the - * old position. Think a zftape specific llseek() function would be - * better, returning -ESPIPE. TODO. - */ - -static int zft_open (struct inode *ino, struct file *filep); -static int zft_close(struct inode *ino, struct file *filep); -static int zft_ioctl(struct inode *ino, struct file *filep, - unsigned int command, unsigned long arg); -static int zft_mmap(struct file *filep, struct vm_area_struct *vma); -static ssize_t zft_read (struct file *fp, char __user *buff, - size_t req_len, loff_t *ppos); -static ssize_t zft_write(struct file *fp, const char __user *buff, - size_t req_len, loff_t *ppos); - -static const struct file_operations zft_cdev = -{ - .owner = THIS_MODULE, - .read = zft_read, - .write = zft_write, - .ioctl = zft_ioctl, - .mmap = zft_mmap, - .open = zft_open, - .release = zft_close, -}; - -static struct class *zft_class; - -/* Open floppy tape device - */ -static int zft_open(struct inode *ino, struct file *filep) -{ - int result; - TRACE_FUN(ft_t_flow); - - nonseekable_open(ino, filep); - TRACE(ft_t_flow, "called for minor %d", iminor(ino)); - if ( test_and_set_bit(0,&busy_flag) ) { - TRACE_ABORT(-EBUSY, ft_t_warn, "failed: already busy"); - } - if ((iminor(ino) & ~(ZFT_MINOR_OP_MASK | FTAPE_NO_REWIND)) - > - FTAPE_SEL_D) { - clear_bit(0,&busy_flag); - TRACE_ABORT(-ENXIO, ft_t_err, "failed: invalid unit nr"); - } - orig_sigmask = current->blocked; - sigfillset(¤t->blocked); - result = _zft_open(iminor(ino), filep->f_flags & O_ACCMODE); - if (result < 0) { - current->blocked = orig_sigmask; /* restore mask */ - clear_bit(0,&busy_flag); - TRACE_ABORT(result, ft_t_err, "_ftape_open failed"); - } else { - /* Mask signals that will disturb proper operation of the - * program that is calling. - */ - current->blocked = orig_sigmask; - sigaddsetmask (¤t->blocked, _DO_BLOCK); - TRACE_EXIT 0; - } -} - -/* Close floppy tape device - */ -static int zft_close(struct inode *ino, struct file *filep) -{ - int result; - TRACE_FUN(ft_t_flow); - - if ( !test_bit(0,&busy_flag) || iminor(ino) != zft_unit) { - TRACE(ft_t_err, "failed: not busy or wrong unit"); - TRACE_EXIT 0; - } - sigfillset(¤t->blocked); - result = _zft_close(); - if (result < 0) { - TRACE(ft_t_err, "_zft_close failed"); - } - current->blocked = orig_sigmask; /* restore before open state */ - clear_bit(0,&busy_flag); - TRACE_EXIT 0; -} - -/* Ioctl for floppy tape device - */ -static int zft_ioctl(struct inode *ino, struct file *filep, - unsigned int command, unsigned long arg) -{ - int result = -EIO; - sigset_t old_sigmask; - TRACE_FUN(ft_t_flow); - - if ( !test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) { - TRACE_ABORT(-EIO, ft_t_err, - "failed: not busy, failure or wrong unit"); - } - old_sigmask = current->blocked; /* save mask */ - sigfillset(¤t->blocked); - /* This will work as long as sizeof(void *) == sizeof(long) */ - result = _zft_ioctl(command, (void __user *) arg); - current->blocked = old_sigmask; /* restore mask */ - TRACE_EXIT result; -} - -/* Ioctl for floppy tape device - */ -static int zft_mmap(struct file *filep, struct vm_area_struct *vma) -{ - int result = -EIO; - sigset_t old_sigmask; - TRACE_FUN(ft_t_flow); - - if ( !test_bit(0,&busy_flag) || - iminor(filep->f_dentry->d_inode) != zft_unit || - ft_failure) - { - TRACE_ABORT(-EIO, ft_t_err, - "failed: not busy, failure or wrong unit"); - } - old_sigmask = current->blocked; /* save mask */ - sigfillset(¤t->blocked); - if ((result = ftape_mmap(vma)) >= 0) { -#ifndef MSYNC_BUG_WAS_FIXED - static struct vm_operations_struct dummy = { NULL, }; - vma->vm_ops = &dummy; -#endif - } - current->blocked = old_sigmask; /* restore mask */ - TRACE_EXIT result; -} - -/* Read from floppy tape device - */ -static ssize_t zft_read(struct file *fp, char __user *buff, - size_t req_len, loff_t *ppos) -{ - int result = -EIO; - sigset_t old_sigmask; - struct inode *ino = fp->f_dentry->d_inode; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_data_flow, "called with count: %ld", (unsigned long)req_len); - if (!test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) { - TRACE_ABORT(-EIO, ft_t_err, - "failed: not busy, failure or wrong unit"); - } - old_sigmask = current->blocked; /* save mask */ - sigfillset(¤t->blocked); - result = _zft_read(buff, req_len); - current->blocked = old_sigmask; /* restore mask */ - TRACE(ft_t_data_flow, "return with count: %d", result); - TRACE_EXIT result; -} - -/* Write to tape device - */ -static ssize_t zft_write(struct file *fp, const char __user *buff, - size_t req_len, loff_t *ppos) -{ - int result = -EIO; - sigset_t old_sigmask; - struct inode *ino = fp->f_dentry->d_inode; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_flow, "called with count: %ld", (unsigned long)req_len); - if (!test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) { - TRACE_ABORT(-EIO, ft_t_err, - "failed: not busy, failure or wrong unit"); - } - old_sigmask = current->blocked; /* save mask */ - sigfillset(¤t->blocked); - result = _zft_write(buff, req_len); - current->blocked = old_sigmask; /* restore mask */ - TRACE(ft_t_data_flow, "return with count: %d", result); - TRACE_EXIT result; -} - -/* END OF VFS INTERFACE - * - *****************************************************************************/ - -/* driver/module initialization - */ - -/* the compression module has to call this function to hook into the zftape - * code - */ -int zft_cmpr_register(struct zft_cmpr_ops *new_ops) -{ - TRACE_FUN(ft_t_flow); - - if (zft_cmpr_ops != NULL) { - TRACE_EXIT -EBUSY; - } else { - zft_cmpr_ops = new_ops; - TRACE_EXIT 0; - } -} - -/* lock the zft-compressor() module. - */ -int zft_cmpr_lock(int try_to_load) -{ - if (zft_cmpr_ops == NULL) { -#ifdef CONFIG_KMOD - if (try_to_load) { - request_module("zft-compressor"); - if (zft_cmpr_ops == NULL) { - return -ENOSYS; - } - } else { - return -ENOSYS; - } -#else - return -ENOSYS; -#endif - } - (*zft_cmpr_ops->lock)(); - return 0; -} - -#ifdef CONFIG_ZFT_COMPRESSOR -extern int zft_compressor_init(void); -#endif - -/* Called by modules package when installing the driver or by kernel - * during the initialization phase - */ -int __init zft_init(void) -{ - int i; - TRACE_FUN(ft_t_flow); - -#ifdef MODULE - printk(KERN_INFO ZFTAPE_VERSION "\n"); - if (TRACE_LEVEL >= ft_t_info) { - printk( -KERN_INFO -"(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n" -KERN_INFO -"vfs interface for ftape floppy tape driver.\n" -KERN_INFO -"Support for QIC-113 compatible volume table, dynamic memory allocation\n" -KERN_INFO -"and builtin compression (lzrw3 algorithm).\n"); - } -#else /* !MODULE */ - /* print a short no-nonsense boot message */ - printk(KERN_INFO ZFTAPE_VERSION "\n"); -#endif /* MODULE */ - TRACE(ft_t_info, "zft_init @ 0x%p", zft_init); - TRACE(ft_t_info, - "installing zftape VFS interface for ftape driver ..."); - TRACE_CATCH(register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),); - - zft_class = class_create(THIS_MODULE, "zft"); - for (i = 0; i < 4; i++) { - class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i); - class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i); - class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i); - class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i); - class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i); - class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i); - } - -#ifdef CONFIG_ZFT_COMPRESSOR - (void)zft_compressor_init(); -#endif - zft_status = ftape_get_status(); /* fetch global data of ftape - * hardware driver - */ - TRACE_EXIT 0; -} - - -/* Called by modules package when removing the driver - */ -static void zft_exit(void) -{ - int i; - TRACE_FUN(ft_t_flow); - - if (unregister_chrdev(QIC117_TAPE_MAJOR, "zft") != 0) { - TRACE(ft_t_warn, "failed"); - } else { - TRACE(ft_t_info, "successful"); - } - for (i = 0; i < 4; i++) { - class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i)); - class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4)); - class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16)); - class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20)); - class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32)); - class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36)); - } - class_destroy(zft_class); - zft_uninit_mem(); /* release remaining memory, if any */ - printk(KERN_INFO "zftape successfully unloaded.\n"); - TRACE_EXIT; -} - -module_init(zft_init); -module_exit(zft_exit); diff --git a/drivers/char/ftape/zftape/zftape-init.h b/drivers/char/ftape/zftape/zftape-init.h deleted file mode 100644 index 937e5d48c20..00000000000 --- a/drivers/char/ftape/zftape/zftape-init.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef _ZFTAPE_INIT_H -#define _ZFTAPE_INIT_H - -/* - * Copyright (C) 1996, 1997 Claus 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/zftape/zftape-init.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:05 $ - * - * This file contains definitions and macro for the vfs - * interface defined by zftape - * - */ - -#include - -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-write.h" -#include "../lowlevel/ftape-bsm.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-buffer.h" -#include "../lowlevel/ftape-format.h" - -#include "../zftape/zftape-rw.h" - -#ifdef MODULE -#define ftape_status (*zft_status) -#endif - -extern const ftape_info *zft_status; /* needed for zftape-vtbl.h */ - -#include "../zftape/zftape-vtbl.h" - -struct zft_cmpr_ops { - int (*write)(int *write_cnt, - __u8 *dst_buf, const int seg_sz, - const __u8 __user *src_buf, const int req_len, - const zft_position *pos, const zft_volinfo *volume); - int (*read)(int *read_cnt, - __u8 __user *dst_buf, const int req_len, - const __u8 *src_buf, const int seg_sz, - const zft_position *pos, const zft_volinfo *volume); - int (*seek)(unsigned int new_block_pos, - zft_position *pos, const zft_volinfo *volume, - __u8 *buffer); - void (*lock) (void); - void (*reset) (void); - void (*cleanup)(void); -}; - -extern struct zft_cmpr_ops *zft_cmpr_ops; -/* zftape-init.c defined global functions. - */ -extern int zft_cmpr_register(struct zft_cmpr_ops *new_ops); -extern int zft_cmpr_lock(int try_to_load); - -#endif - - diff --git a/drivers/char/ftape/zftape/zftape-read.c b/drivers/char/ftape/zftape/zftape-read.c deleted file mode 100644 index 214bf03dce6..00000000000 --- a/drivers/char/ftape/zftape/zftape-read.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright (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/zftape/zftape-read.c,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:06 $ - * - * This file contains the high level reading code - * for the QIC-117 floppy-tape driver for Linux. - */ - -#include -#include - -#include - -#include - -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-eof.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-write.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-rw.h" -#include "../zftape/zftape-vtbl.h" - -/* Global vars. - */ -int zft_just_before_eof; - -/* Local vars. - */ -static int buf_len_rd; - -void zft_zap_read_buffers(void) -{ - buf_len_rd = 0; -} - -int zft_read_header_segments(void) -{ - TRACE_FUN(ft_t_flow); - - zft_header_read = 0; - TRACE_CATCH(zft_vmalloc_once(&zft_hseg_buf, FT_SEGMENT_SIZE),); - TRACE_CATCH(ftape_read_header_segment(zft_hseg_buf),); - TRACE(ft_t_info, "Segments written since first format: %d", - (int)GET4(zft_hseg_buf, FT_SEG_CNT)); - zft_qic113 = (ft_format_code != fmt_normal && - ft_format_code != fmt_1100ft && - ft_format_code != fmt_425ft); - TRACE(ft_t_info, "ft_first_data_segment: %d, ft_last_data_segment: %d", - ft_first_data_segment, ft_last_data_segment); - zft_capacity = zft_get_capacity(); - zft_old_ftape = zft_ftape_validate_label(&zft_hseg_buf[FT_LABEL]); - if (zft_old_ftape) { - TRACE(ft_t_info, -"Found old ftaped tape, emulating eof marks, entering read-only mode"); - zft_ftape_extract_file_marks(zft_hseg_buf); - TRACE_CATCH(zft_fake_volume_headers(zft_eof_map, - zft_nr_eof_marks),); - } else { - /* the specs say that the volume table must be - * initialized with zeroes during formatting, so it - * MUST be readable, i.e. contain vaid ECC - * information. - */ - TRACE_CATCH(ftape_read_segment(ft_first_data_segment, - zft_deblock_buf, - FT_RD_SINGLE),); - TRACE_CATCH(zft_extract_volume_headers(zft_deblock_buf),); - } - zft_header_read = 1; - zft_set_flags(zft_unit); - zft_reset_position(&zft_pos); - TRACE_EXIT 0; -} - -int zft_fetch_segment_fraction(const unsigned int segment, void *buffer, - const ft_read_mode_t read_mode, - const unsigned int start, - const unsigned int size) -{ - int seg_sz; - TRACE_FUN(ft_t_flow); - - if (segment == zft_deblock_segment) { - TRACE(ft_t_data_flow, - "re-using segment %d already in deblock buffer", - segment); - seg_sz = zft_get_seg_sz(segment); - if (start > seg_sz) { - TRACE_ABORT(-EINVAL, ft_t_bug, - "trying to read beyond end of segment:\n" - KERN_INFO "seg_sz : %d\n" - KERN_INFO "start : %d\n" - KERN_INFO "segment: %d", - seg_sz, start, segment); - } - if ((start + size) > seg_sz) { - TRACE_EXIT seg_sz - start; - } - TRACE_EXIT size; - } - seg_sz = ftape_read_segment_fraction(segment, buffer, read_mode, - start, size); - TRACE(ft_t_data_flow, "segment %d, result %d", segment, seg_sz); - if ((int)seg_sz >= 0 && start == 0 && size == FT_SEGMENT_SIZE) { - /* this implicitly assumes that we are always called with - * buffer == zft_deblock_buf - */ - zft_deblock_segment = segment; - } else { - zft_deblock_segment = -1; - } - TRACE_EXIT seg_sz; -} - -/* - * out: - * - * int *read_cnt: the number of bytes we removed from the - * zft_deblock_buf (result) - * - * int *to_do : the remaining size of the read-request. Is changed. - * - * in: - * - * char *buff : buff is the address of the upper part of the user - * buffer, that hasn't been filled with data yet. - * int buf_pos_read: copy of buf_pos_rd - * int buf_len_read: copy of buf_len_rd - * char *zft_deblock_buf: ftape_zft_deblock_buf - * - * returns the amount of data actually copied to the user-buffer - * - * to_do MUST NOT SHRINK except to indicate an EOT. In this case to_do - * has to be set to 0. We cannot return -ENOSPC, because we return the - * amount of data actually * copied to the user-buffer - */ -static int zft_simple_read (int *read_cnt, - __u8 __user *dst_buf, - const int to_do, - const __u8 *src_buf, - const int seg_sz, - const zft_position *pos, - const zft_volinfo *volume) -{ - TRACE_FUN(ft_t_flow); - - if (seg_sz - pos->seg_byte_pos < to_do) { - *read_cnt = seg_sz - pos->seg_byte_pos; - } else { - *read_cnt = to_do; - } - if (copy_to_user(dst_buf, - src_buf + pos->seg_byte_pos, *read_cnt) != 0) { - TRACE_EXIT -EFAULT; - } - TRACE(ft_t_noise, "nr bytes just read: %d", *read_cnt); - TRACE_EXIT *read_cnt; -} - -/* req_len: gets clipped due to EOT of EOF. - * req_clipped: is a flag indicating whether req_len was clipped or not - * volume: contains information on current volume (blk_sz etc.) - */ -static int check_read_access(int *req_len, - const zft_volinfo **volume, - int *req_clipped, - const zft_position *pos) -{ - static __s64 remaining; - static int eod; - TRACE_FUN(ft_t_flow); - - if (zft_io_state != zft_reading) { - if (zft_offline) { /* offline includes no_tape */ - TRACE_ABORT(-ENXIO, ft_t_warn, - "tape is offline or no cartridge"); - } - if (!ft_formatted) { - TRACE_ABORT(-EACCES, - ft_t_warn, "tape is not formatted"); - } - /* now enter defined state, read header segment if not - * already done and flush write buffers - */ - TRACE_CATCH(zft_def_idle_state(),); - zft_io_state = zft_reading; - if (zft_tape_at_eod(pos)) { - eod = 1; - TRACE_EXIT 1; - } - eod = 0; - *volume = zft_find_volume(pos->seg_pos); - /* get the space left until EOF */ - remaining = zft_check_for_eof(*volume, pos); - buf_len_rd = 0; - TRACE(ft_t_noise, "remaining: " LL_X ", vol_no: %d", - LL(remaining), (*volume)->count); - } else if (zft_tape_at_eod(pos)) { - if (++eod > 2) { - TRACE_EXIT -EIO; /* st.c also returns -EIO */ - } else { - TRACE_EXIT 1; - } - } - if ((*req_len % (*volume)->blk_sz) != 0) { - /* this message is informational only. The user gets the - * proper return value - */ - TRACE_ABORT(-EINVAL, ft_t_info, - "req_len %d not a multiple of block size %d", - *req_len, (*volume)->blk_sz); - } - /* As GNU tar doesn't accept partial read counts when the - * multiple volume flag is set, we make sure to return the - * requested amount of data. Except, of course, at the end of - * the tape or file mark. - */ - remaining -= *req_len; - if (remaining <= 0) { - TRACE(ft_t_noise, - "clipped request from %d to %d.", - *req_len, (int)(*req_len + remaining)); - *req_len += remaining; - *req_clipped = 1; - } else { - *req_clipped = 0; - } - TRACE_EXIT 0; -} - -/* this_segs_size: the current segment's size. - * buff: the USER-SPACE buffer provided by the calling function. - * req_len: how much data should be read at most. - * volume: contains information on current volume (blk_sz etc.) - */ -static int empty_deblock_buf(__u8 __user *usr_buf, const int req_len, - const __u8 *src_buf, const int seg_sz, - zft_position *pos, - const zft_volinfo *volume) -{ - int cnt; - int result = 0; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_data_flow, "this_segs_size: %d", seg_sz); - if (zft_use_compression && volume->use_compression) { - TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),); - TRACE_CATCH(result= (*zft_cmpr_ops->read)(&cnt, - usr_buf, req_len, - src_buf, seg_sz, - pos, volume),); - } else { - TRACE_CATCH(result= zft_simple_read (&cnt, - usr_buf, req_len, - src_buf, seg_sz, - pos, volume),); - } - pos->volume_pos += result; - pos->tape_pos += cnt; - pos->seg_byte_pos += cnt; - buf_len_rd -= cnt; /* remaining bytes in buffer */ - TRACE(ft_t_data_flow, "buf_len_rd: %d, cnt: %d", buf_len_rd, cnt); - if(pos->seg_byte_pos >= seg_sz) { - pos->seg_pos++; - pos->seg_byte_pos = 0; - } - TRACE(ft_t_data_flow, "bytes moved out of deblock-buffer: %d", cnt); - TRACE_EXIT result; -} - - -/* note: we store the segment id of the segment that is inside the - * deblock buffer. This spares a lot of ftape_read_segment()s when we - * use small block-sizes. The block-size may be 1kb (SECTOR_SIZE). In - * this case a MTFSR 28 maybe still inside the same segment. - */ -int _zft_read(char __user *buff, int req_len) -{ - int req_clipped; - int result = 0; - int bytes_read = 0; - static unsigned int seg_sz = 0; - static const zft_volinfo *volume = NULL; - TRACE_FUN(ft_t_flow); - - zft_resid = req_len; - result = check_read_access(&req_len, &volume, - &req_clipped, &zft_pos); - switch(result) { - case 0: - break; /* nothing special */ - case 1: - TRACE(ft_t_noise, "EOD reached"); - TRACE_EXIT 0; /* EOD */ - default: - TRACE_ABORT(result, ft_t_noise, - "check_read_access() failed with result %d", - result); - TRACE_EXIT result; - } - while (req_len > 0) { - /* Allow escape from this loop on signal ! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - /* buf_len_rd == 0 means that we need to read a new - * segment. - */ - if (buf_len_rd == 0) { - while((result = zft_fetch_segment(zft_pos.seg_pos, - zft_deblock_buf, - FT_RD_AHEAD)) == 0) { - zft_pos.seg_pos ++; - zft_pos.seg_byte_pos = 0; - } - if (result < 0) { - zft_resid -= bytes_read; - TRACE_ABORT(result, ft_t_noise, - "zft_fetch_segment(): %d", - result); - } - seg_sz = result; - buf_len_rd = seg_sz - zft_pos.seg_byte_pos; - } - TRACE_CATCH(result = empty_deblock_buf(buff, - req_len, - zft_deblock_buf, - seg_sz, - &zft_pos, - volume), - zft_resid -= bytes_read); - TRACE(ft_t_data_flow, "bytes just read: %d", result); - bytes_read += result; /* what we got so far */ - buff += result; /* index in user-buffer */ - req_len -= result; /* what's left from req_len */ - } /* while (req_len > 0) */ - if (req_clipped) { - TRACE(ft_t_data_flow, - "maybe partial count because of eof mark"); - if (zft_just_before_eof && bytes_read == 0) { - /* req_len was > 0, but user didn't get - * anything the user has read in the eof-mark - */ - zft_move_past_eof(&zft_pos); - ftape_abort_operation(); - } else { - /* don't skip to the next file before the user - * tried to read a second time past EOF Just - * mark that we are at EOF and maybe decrement - * zft_seg_pos to stay in the same volume; - */ - zft_just_before_eof = 1; - zft_position_before_eof(&zft_pos, volume); - TRACE(ft_t_noise, "just before eof"); - } - } - zft_resid -= result; /* for MTSTATUS */ - TRACE_EXIT bytes_read; -} diff --git a/drivers/char/ftape/zftape/zftape-read.h b/drivers/char/ftape/zftape/zftape-read.h deleted file mode 100644 index 42941de0c23..00000000000 --- a/drivers/char/ftape/zftape/zftape-read.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _ZFTAPE_READ_H -#define _ZFTAPE_READ_H - -/* - * Copyright (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/zftape/zftape-read.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:07 $ - * - * This file contains the definitions for the read functions - * for the zftape driver for Linux. - * - */ - -#include "../lowlevel/ftape-read.h" - -/* ftape-read.c defined global vars. - */ -extern int zft_just_before_eof; - -/* ftape-read.c defined global functions. - */ -extern void zft_zap_read_buffers(void); -extern int zft_read_header_segments(void); -extern int zft_fetch_segment_fraction(const unsigned int segment, - void *buffer, - const ft_read_mode_t read_mode, - const unsigned int start, - const unsigned int size); -#define zft_fetch_segment(segment, address, read_mode) \ - zft_fetch_segment_fraction(segment, address, read_mode, \ - 0, FT_SEGMENT_SIZE) -/* hook for the VFS interface - */ -extern int _zft_read(char __user *buff, int req_len); - -#endif /* _ZFTAPE_READ_H */ diff --git a/drivers/char/ftape/zftape/zftape-rw.c b/drivers/char/ftape/zftape/zftape-rw.c deleted file mode 100644 index dab63468688..00000000000 --- a/drivers/char/ftape/zftape/zftape-rw.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (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/zftape/zftape-rw.c,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:08 $ - * - * This file contains some common code for the r/w code for - * zftape. - */ - -#include -#include - -#include -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-eof.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-write.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-rw.h" -#include "../zftape/zftape-vtbl.h" - -/* Global vars. - */ - -__u8 *zft_deblock_buf; -__u8 *zft_hseg_buf; -int zft_deblock_segment = -1; -zft_status_enum zft_io_state = zft_idle; -int zft_header_changed; -int zft_qic113; /* conform to old specs. and old zftape */ -int zft_use_compression; -zft_position zft_pos = { - -1, /* seg_pos */ - 0, /* seg_byte_pos */ - 0, /* tape_pos */ - 0 /* volume_pos */ -}; -unsigned int zft_blk_sz = CONFIG_ZFT_DFLT_BLK_SZ; -__s64 zft_capacity; - -unsigned int zft_written_segments; -int zft_label_changed; - -/* Local vars. - */ - -unsigned int zft_get_seg_sz(unsigned int segment) -{ - int size; - TRACE_FUN(ft_t_any); - - size = FT_SEGMENT_SIZE - - count_ones(ftape_get_bad_sector_entry(segment))*FT_SECTOR_SIZE; - if (size > 0) { - TRACE_EXIT (unsigned)size; - } else { - TRACE_EXIT 0; - } -} - -/* ftape_set_flags(). Claus-Justus Heine, 1994/1995 - */ -void zft_set_flags(unsigned minor_unit) -{ - TRACE_FUN(ft_t_flow); - - zft_use_compression = zft_qic_mode = 0; - switch (minor_unit & ZFT_MINOR_OP_MASK) { - case (ZFT_Q80_MODE | ZFT_ZIP_MODE): - case ZFT_ZIP_MODE: - zft_use_compression = 1; - case 0: - case ZFT_Q80_MODE: - zft_qic_mode = 1; - if (zft_mt_compression) { /* override the default */ - zft_use_compression = 1; - } - break; - case ZFT_RAW_MODE: - TRACE(ft_t_noise, "switching to raw mode"); - break; - default: - TRACE(ft_t_warn, "Warning:\n" - KERN_INFO "Wrong combination of minor device bits.\n" - KERN_INFO "Switching to raw read-only mode."); - zft_write_protected = 1; - break; - } - TRACE_EXIT; -} - -/* computes the segment and byte offset inside the segment - * corresponding to tape_pos. - * - * tape_pos gives the offset in bytes from the beginning of the - * ft_first_data_segment *seg_byte_pos is the offset in the current - * segment in bytes - * - * Of, if this routine was called often one should cache the last data - * pos it was called with, but actually this is only needed in - * ftape_seek_block(), that is, almost never. - */ -int zft_calc_seg_byte_coord(int *seg_byte_pos, __s64 tape_pos) -{ - int segment; - int seg_sz; - TRACE_FUN(ft_t_flow); - - if (tape_pos == 0) { - *seg_byte_pos = 0; - segment = ft_first_data_segment; - } else { - seg_sz = 0; - - for (segment = ft_first_data_segment; - ((tape_pos > 0) && (segment <= ft_last_data_segment)); - segment++) { - seg_sz = zft_get_seg_sz(segment); - tape_pos -= seg_sz; - } - if(tape_pos >= 0) { - /* the case tape_pos > != 0 means that the - * argument tape_pos lies beyond the EOT. - */ - *seg_byte_pos= 0; - } else { /* tape_pos < 0 */ - segment--; - *seg_byte_pos= tape_pos + seg_sz; - } - } - TRACE_EXIT(segment); -} - -/* ftape_calc_tape_pos(). - * - * computes the offset in bytes from the beginning of the - * ft_first_data_segment inverse to ftape_calc_seg_byte_coord - * - * We should do some caching. But how: - * - * Each time the header segments are read in, this routine is called - * with ft_tracks_per_tape*segments_per_track argumnet. So this should be - * the time to reset the cache. - * - * Also, it might be in the future that the bad sector map gets - * changed. -> reset the cache - */ -static int seg_pos; -static __s64 tape_pos; - -__s64 zft_get_capacity(void) -{ - seg_pos = ft_first_data_segment; - tape_pos = 0; - - while (seg_pos <= ft_last_data_segment) { - tape_pos += zft_get_seg_sz(seg_pos ++); - } - return tape_pos; -} - -__s64 zft_calc_tape_pos(int segment) -{ - int d1, d2, d3; - TRACE_FUN(ft_t_any); - - if (segment > ft_last_data_segment) { - TRACE_EXIT zft_capacity; - } - if (segment < ft_first_data_segment) { - TRACE_EXIT 0; - } - d2 = segment - seg_pos; - if (-d2 > 10) { - d1 = segment - ft_first_data_segment; - if (-d2 > d1) { - tape_pos = 0; - seg_pos = ft_first_data_segment; - d2 = d1; - } - } - if (d2 > 10) { - d3 = ft_last_data_segment - segment; - if (d2 > d3) { - tape_pos = zft_capacity; - seg_pos = ft_last_data_segment + 1; - d2 = -d3; - } - } - if (d2 > 0) { - while (seg_pos < segment) { - tape_pos += zft_get_seg_sz(seg_pos++); - } - } else { - while (seg_pos > segment) { - tape_pos -= zft_get_seg_sz(--seg_pos); - } - } - TRACE(ft_t_noise, "new cached pos: %d", seg_pos); - - TRACE_EXIT tape_pos; -} - -/* copy Z-label string to buffer, keeps track of the correct offset in - * `buffer' - */ -void zft_update_label(__u8 *buffer) -{ - TRACE_FUN(ft_t_flow); - - if (strncmp(&buffer[FT_LABEL], ZFTAPE_LABEL, - sizeof(ZFTAPE_LABEL)-1) != 0) { - TRACE(ft_t_info, "updating label from \"%s\" to \"%s\"", - &buffer[FT_LABEL], ZFTAPE_LABEL); - strcpy(&buffer[FT_LABEL], ZFTAPE_LABEL); - memset(&buffer[FT_LABEL] + sizeof(ZFTAPE_LABEL) - 1, ' ', - FT_LABEL_SZ - sizeof(ZFTAPE_LABEL + 1)); - PUT4(buffer, FT_LABEL_DATE, 0); - zft_label_changed = zft_header_changed = 1; /* changed */ - } - TRACE_EXIT; -} - -int zft_verify_write_segments(unsigned int segment, - __u8 *data, size_t size, - __u8 *buffer) -{ - int result; - __u8 *write_buf; - __u8 *src_buf; - int single; - int seg_pos; - int seg_sz; - int remaining; - ft_write_mode_t write_mode; - TRACE_FUN(ft_t_flow); - - seg_pos = segment; - seg_sz = zft_get_seg_sz(seg_pos); - src_buf = data; - single = size <= seg_sz; - remaining = size; - do { - TRACE(ft_t_noise, "\n" - KERN_INFO "remaining: %d\n" - KERN_INFO "seg_sz : %d\n" - KERN_INFO "segment : %d", - remaining, seg_sz, seg_pos); - if (remaining == seg_sz) { - write_buf = src_buf; - write_mode = single ? FT_WR_SINGLE : FT_WR_MULTI; - remaining = 0; - } else if (remaining > seg_sz) { - write_buf = src_buf; - write_mode = FT_WR_ASYNC; /* don't start tape */ - remaining -= seg_sz; - } else { /* remaining < seg_sz */ - write_buf = buffer; - memcpy(write_buf, src_buf, remaining); - memset(&write_buf[remaining],'\0',seg_sz-remaining); - write_mode = single ? FT_WR_SINGLE : FT_WR_MULTI; - remaining = 0; - } - if ((result = ftape_write_segment(seg_pos, - write_buf, - write_mode)) != seg_sz) { - TRACE(ft_t_err, "Error: " - "Couldn't write segment %d", seg_pos); - TRACE_EXIT result < 0 ? result : -EIO; /* bail out */ - } - zft_written_segments ++; - seg_sz = zft_get_seg_sz(++seg_pos); - src_buf += result; - } while (remaining > 0); - if (ftape_get_status()->fti_state == writing) { - TRACE_CATCH(ftape_loop_until_writes_done(),); - TRACE_CATCH(ftape_abort_operation(),); - zft_prevent_flush(); - } - seg_pos = segment; - src_buf = data; - remaining = size; - do { - TRACE_CATCH(result = ftape_read_segment(seg_pos, buffer, - single ? FT_RD_SINGLE - : FT_RD_AHEAD),); - if (memcmp(src_buf, buffer, - remaining > result ? result : remaining) != 0) { - TRACE_ABORT(-EIO, ft_t_err, - "Failed to verify written segment %d", - seg_pos); - } - remaining -= result; - TRACE(ft_t_noise, "verify successful:\n" - KERN_INFO "segment : %d\n" - KERN_INFO "segsize : %d\n" - KERN_INFO "remaining: %d", - seg_pos, result, remaining); - src_buf += seg_sz; - seg_pos++; - } while (remaining > 0); - TRACE_EXIT size; -} - - -/* zft_erase(). implemented compression-handling - * - * calculate the first data-segment when using/not using compression. - * - * update header-segment and compression-map-segment. - */ -int zft_erase(void) -{ - int result = 0; - TRACE_FUN(ft_t_flow); - - if (!zft_header_read) { - TRACE_CATCH(zft_vmalloc_once((void **)&zft_hseg_buf, - FT_SEGMENT_SIZE),); - /* no need to read the vtbl and compression map */ - TRACE_CATCH(ftape_read_header_segment(zft_hseg_buf),); - if ((zft_old_ftape = - zft_ftape_validate_label(&zft_hseg_buf[FT_LABEL]))) { - zft_ftape_extract_file_marks(zft_hseg_buf); - } - TRACE(ft_t_noise, - "ft_first_data_segment: %d, ft_last_data_segment: %d", - ft_first_data_segment, ft_last_data_segment); - zft_qic113 = (ft_format_code != fmt_normal && - ft_format_code != fmt_1100ft && - ft_format_code != fmt_425ft); - } - if (zft_old_ftape) { - zft_clear_ftape_file_marks(); - zft_old_ftape = 0; /* no longer old ftape */ - } - PUT2(zft_hseg_buf, FT_CMAP_START, 0); - zft_volume_table_changed = 1; - zft_capacity = zft_get_capacity(); - zft_init_vtbl(); - /* the rest must be done in ftape_update_header_segments - */ - zft_header_read = 1; - zft_header_changed = 1; /* force update of timestamp */ - result = zft_update_header_segments(); - - ftape_abort_operation(); - - zft_reset_position(&zft_pos); - zft_set_flags (zft_unit); - TRACE_EXIT result; -} - -unsigned int zft_get_time(void) -{ - unsigned int date = FT_TIME_STAMP(2097, 11, 30, 23, 59, 59); /* fun */ - return date; -} diff --git a/drivers/char/ftape/zftape/zftape-rw.h b/drivers/char/ftape/zftape/zftape-rw.h deleted file mode 100644 index 1ceec22b60b..00000000000 --- a/drivers/char/ftape/zftape/zftape-rw.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef _ZFTAPE_RW_H -#define _ZFTAPE_RW_H - -/* - * Copyright (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/zftape/zftape-rw.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:09 $ - * - * This file contains the definitions for the read and write - * functions for the QIC-117 floppy-tape driver for Linux. - * - */ - -#include "../zftape/zftape-buffers.h" - -#define SEGMENTS_PER_TAPE (ft_segments_per_track * ft_tracks_per_tape) - -/* QIC-113 Rev. G says that `a maximum of 63488 raw bytes may be - * compressed into a single frame'. - * Maybe we should stick to 32kb to make it more `beautiful' - */ -#define ZFT_MAX_BLK_SZ (62*1024) /* bytes */ -#if !defined(CONFIG_ZFT_DFLT_BLK_SZ) -# define CONFIG_ZFT_DFLT_BLK_SZ (10*1024) /* bytes, default of gnu tar */ -#elif CONFIG_ZFT_DFLT_BLK_SZ == 0 -# undef CONFIG_ZFT_DFLT_BLK_SZ -# define CONFIG_ZFT_DFLT_BLK_SZ 1 -#elif (CONFIG_ZFT_DFLT_BLK_SZ % 1024) != 0 -# error CONFIG_ZFT_DFLT_BLK_SZ must be 1 or a multiple of 1024 -#endif -/* The *optional* compression routines need some overhead per tape - * block for their purposes. Instead of asking the actual compression - * implementation how much it needs, we restrict this overhead to be - * maximal of ZFT_CMPT_OVERHEAD size. We need this for EOT - * conditions. The tape is assumed to be logical at EOT when the - * distance from the physical EOT is less than - * one tape block + ZFT_CMPR_OVERHEAD - */ -#define ZFT_CMPR_OVERHEAD 16 /* bytes */ - -typedef enum -{ - zft_idle = 0, - zft_reading, - zft_writing, -} zft_status_enum; - -typedef struct /* all values measured in bytes */ -{ - int seg_pos; /* segment currently positioned at */ - int seg_byte_pos; /* offset in current segment */ - __s64 tape_pos; /* real offset from BOT */ - __s64 volume_pos; /* pos. in uncompressed data stream in - * current volume - */ -} zft_position; - -extern zft_position zft_pos; -extern __u8 *zft_deblock_buf; -extern __u8 *zft_hseg_buf; -extern int zft_deblock_segment; -extern zft_status_enum zft_io_state; -extern int zft_header_changed; -extern int zft_qic113; /* conform to old specs. and old zftape */ -extern int zft_use_compression; -extern unsigned int zft_blk_sz; -extern __s64 zft_capacity; -extern unsigned int zft_written_segments; -extern int zft_label_changed; - -/* zftape-rw.c exported functions - */ -extern unsigned int zft_get_seg_sz(unsigned int segment); -extern void zft_set_flags(unsigned int minor_unit); -extern int zft_calc_seg_byte_coord(int *seg_byte_pos, __s64 tape_pos); -extern __s64 zft_calc_tape_pos(int segment); -extern __s64 zft_get_capacity(void); -extern void zft_update_label(__u8 *buffer); -extern int zft_erase(void); -extern int zft_verify_write_segments(unsigned int segment, - __u8 *data, size_t size, __u8 *buffer); -extern unsigned int zft_get_time(void); -#endif /* _ZFTAPE_RW_H */ - diff --git a/drivers/char/ftape/zftape/zftape-vtbl.c b/drivers/char/ftape/zftape/zftape-vtbl.c deleted file mode 100644 index ad7f8be6340..00000000000 --- a/drivers/char/ftape/zftape/zftape-vtbl.c +++ /dev/null @@ -1,757 +0,0 @@ -/* - * Copyright (c) 1995-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/zftape/zftape-vtbl.c,v $ - * $Revision: 1.7.6.1 $ - * $Date: 1997/11/24 13:48:31 $ - * - * This file defines a volume table as defined in various QIC - * standards. - * - * This is a minimal implementation, just allowing ordinary DOS - * :( prgrams to identify the cartridge as used. - */ - -#include -#include -#include - -#include -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-eof.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-write.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-rw.h" -#include "../zftape/zftape-vtbl.h" - -#define ZFT_CMAP_HACK /* leave this defined to hide the compression map */ - -/* - * global variables - */ -int zft_qic_mode = 1; /* use the vtbl */ -int zft_old_ftape; /* prevents old ftaped tapes to be overwritten */ -int zft_volume_table_changed; /* for write_header_segments() */ - -/* - * private variables (only exported for inline functions) - */ -LIST_HEAD(zft_vtbl); - -/* We could also allocate these dynamically when extracting the volume table - * sizeof(zft_volinfo) is about 32 or something close to that - */ -static zft_volinfo tape_vtbl; -static zft_volinfo eot_vtbl; -static zft_volinfo *cur_vtbl; - -static inline void zft_new_vtbl_entry(void) -{ - struct list_head *tmp = &zft_last_vtbl->node; - zft_volinfo *new = zft_kmalloc(sizeof(zft_volinfo)); - - list_add(&new->node, tmp); - new->count = zft_eom_vtbl->count ++; -} - -void zft_free_vtbl(void) -{ - for (;;) { - struct list_head *tmp = zft_vtbl.prev; - zft_volinfo *vtbl; - - if (tmp == &zft_vtbl) - break; - list_del(tmp); - vtbl = list_entry(tmp, zft_volinfo, node); - zft_kfree(vtbl, sizeof(zft_volinfo)); - } - INIT_LIST_HEAD(&zft_vtbl); - cur_vtbl = NULL; -} - -/* initialize vtbl, called by ftape_new_cartridge() - */ -void zft_init_vtbl(void) -{ - zft_volinfo *new; - - zft_free_vtbl(); - - /* Create the two dummy vtbl entries - */ - new = zft_kmalloc(sizeof(zft_volinfo)); - list_add(&new->node, &zft_vtbl); - new = zft_kmalloc(sizeof(zft_volinfo)); - list_add(&new->node, &zft_vtbl); - zft_head_vtbl->end_seg = ft_first_data_segment; - zft_head_vtbl->blk_sz = zft_blk_sz; - zft_head_vtbl->count = -1; - zft_eom_vtbl->start_seg = ft_first_data_segment + 1; - zft_eom_vtbl->end_seg = ft_last_data_segment + 1; - zft_eom_vtbl->blk_sz = zft_blk_sz; - zft_eom_vtbl->count = 0; - - /* Reset the pointer for zft_find_volume() - */ - cur_vtbl = zft_eom_vtbl; - - /* initialize the dummy vtbl entries for zft_qic_mode == 0 - */ - eot_vtbl.start_seg = ft_last_data_segment + 1; - eot_vtbl.end_seg = ft_last_data_segment + 1; - eot_vtbl.blk_sz = zft_blk_sz; - eot_vtbl.count = -1; - tape_vtbl.start_seg = ft_first_data_segment; - tape_vtbl.end_seg = ft_last_data_segment; - tape_vtbl.blk_sz = zft_blk_sz; - tape_vtbl.size = zft_capacity; - tape_vtbl.count = 0; -} - -/* check for a valid VTBL signature. - */ -static int vtbl_signature_valid(__u8 signature[4]) -{ - const char *vtbl_ids[] = VTBL_IDS; /* valid signatures */ - int j; - - for (j = 0; - (j < NR_ITEMS(vtbl_ids)) && (memcmp(signature, vtbl_ids[j], 4) != 0); - j++); - return j < NR_ITEMS(vtbl_ids); -} - -/* We used to store the block-size of the volume in the volume-label, - * using the keyword "blocksize". The blocksize written to the - * volume-label is in bytes. - * - * We use this now only for compatibility with old zftape version. We - * store the blocksize directly as binary number in the vendor - * extension part of the volume entry. - */ -static int check_volume_label(const char *label, int *blk_sz) -{ - int valid_format; - char *blocksize; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "called with \"%s\" / \"%s\"", label, ZFT_VOL_NAME); - if (strncmp(label, ZFT_VOL_NAME, strlen(ZFT_VOL_NAME)) != 0) { - *blk_sz = 1; /* smallest block size that we allow */ - valid_format = 0; - } else { - TRACE(ft_t_noise, "got old style zftape vtbl entry"); - /* get the default blocksize */ - /* use the kernel strstr() */ - blocksize= strstr(label, " blocksize "); - if (blocksize) { - blocksize += strlen(" blocksize "); - for(*blk_sz= 0; - *blocksize >= '0' && *blocksize <= '9'; - blocksize++) { - *blk_sz *= 10; - *blk_sz += *blocksize - '0'; - } - if (*blk_sz > ZFT_MAX_BLK_SZ) { - *blk_sz= 1; - valid_format= 0; - } else { - valid_format = 1; - } - } else { - *blk_sz= 1; - valid_format= 0; - } - } - TRACE_EXIT valid_format; -} - -/* check for a zftape volume - */ -static int check_volume(__u8 *entry, zft_volinfo *volume) -{ - TRACE_FUN(ft_t_flow); - - if(strncmp(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG, - strlen(ZFTAPE_SIG)) == 0) { - TRACE(ft_t_noise, "got new style zftape vtbl entry"); - volume->blk_sz = GET2(entry, VTBL_EXT+EXT_ZFTAPE_BLKSZ); - volume->qic113 = entry[VTBL_EXT+EXT_ZFTAPE_QIC113]; - TRACE_EXIT 1; - } else { - TRACE_EXIT check_volume_label(&entry[VTBL_DESC], &volume->blk_sz); - } -} - - -/* create zftape specific vtbl entry, the volume bounds are inserted - * in the calling function, zft_create_volume_headers() - */ -static void create_zft_volume(__u8 *entry, zft_volinfo *vtbl) -{ - TRACE_FUN(ft_t_flow); - - memset(entry, 0, VTBL_SIZE); - memcpy(&entry[VTBL_SIG], VTBL_ID, 4); - sprintf(&entry[VTBL_DESC], ZFT_VOL_NAME" %03d", vtbl->count); - entry[VTBL_FLAGS] = (VTBL_FL_NOT_VERIFIED | VTBL_FL_SEG_SPANNING); - entry[VTBL_M_NO] = 1; /* multi_cartridge_count */ - strcpy(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG); - PUT2(entry, VTBL_EXT+EXT_ZFTAPE_BLKSZ, vtbl->blk_sz); - if (zft_qic113) { - PUT8(entry, VTBL_DATA_SIZE, vtbl->size); - entry[VTBL_CMPR] = VTBL_CMPR_UNREG; - if (vtbl->use_compression) { /* use compression: */ - entry[VTBL_CMPR] |= VTBL_CMPR_USED; - } - entry[VTBL_EXT+EXT_ZFTAPE_QIC113] = 1; - } else { - PUT4(entry, VTBL_DATA_SIZE, vtbl->size); - entry[VTBL_K_CMPR] = VTBL_CMPR_UNREG; - if (vtbl->use_compression) { /* use compression: */ - entry[VTBL_K_CMPR] |= VTBL_CMPR_USED; - } - } - if (ft_format_code == fmt_big) { - /* SCSI like vtbl, store the number of used - * segments as 4 byte value - */ - PUT4(entry, VTBL_SCSI_SEGS, vtbl->end_seg-vtbl->start_seg + 1); - } else { - /* normal, QIC-80MC like vtbl - */ - PUT2(entry, VTBL_START, vtbl->start_seg); - PUT2(entry, VTBL_END, vtbl->end_seg); - } - TRACE_EXIT; -} - -/* this one creates the volume headers for each volume. It is assumed - * that buffer already contains the old volume-table, so that vtbl - * entries without the zft_volume flag set can savely be ignored. - */ -static void zft_create_volume_headers(__u8 *buffer) -{ - __u8 *entry; - struct list_head *tmp; - zft_volinfo *vtbl; - TRACE_FUN(ft_t_flow); - -#ifdef ZFT_CMAP_HACK - if((strncmp(&buffer[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG, - strlen(ZFTAPE_SIG)) == 0) && - buffer[VTBL_EXT+EXT_ZFTAPE_CMAP] != 0) { - TRACE(ft_t_noise, "deleting cmap volume"); - memmove(buffer, buffer + VTBL_SIZE, - FT_SEGMENT_SIZE - VTBL_SIZE); - } -#endif - entry = buffer; - for (tmp = zft_head_vtbl->node.next; - tmp != &zft_eom_vtbl->node; - tmp = tmp->next) { - vtbl = list_entry(tmp, zft_volinfo, node); - /* we now fill in the values only for newly created volumes. - */ - if (vtbl->new_volume) { - create_zft_volume(entry, vtbl); - vtbl->new_volume = 0; /* clear the flag */ - } - - DUMP_VOLINFO(ft_t_noise, &entry[VTBL_DESC], vtbl); - entry += VTBL_SIZE; - } - memset(entry, 0, FT_SEGMENT_SIZE - zft_eom_vtbl->count * VTBL_SIZE); - TRACE_EXIT; -} - -/* write volume table to tape. Calls zft_create_volume_headers() - */ -int zft_update_volume_table(unsigned int segment) -{ - int result = 0; - __u8 *verify_buf = NULL; - TRACE_FUN(ft_t_flow); - - TRACE_CATCH(result = ftape_read_segment(ft_first_data_segment, - zft_deblock_buf, - FT_RD_SINGLE),); - zft_create_volume_headers(zft_deblock_buf); - TRACE(ft_t_noise, "writing volume table segment %d", segment); - if (zft_vmalloc_once(&verify_buf, FT_SEGMENT_SIZE) == 0) { - TRACE_CATCH(zft_verify_write_segments(segment, - zft_deblock_buf, result, - verify_buf), - zft_vfree(&verify_buf, FT_SEGMENT_SIZE)); - zft_vfree(&verify_buf, FT_SEGMENT_SIZE); - } else { - TRACE_CATCH(ftape_write_segment(segment, zft_deblock_buf, - FT_WR_SINGLE),); - } - TRACE_EXIT 0; -} - -/* non zftape volumes are handled in raw mode. Thus we need to - * calculate the raw amount of data contained in those segments. - */ -static void extract_alien_volume(__u8 *entry, zft_volinfo *vtbl) -{ - TRACE_FUN(ft_t_flow); - - vtbl->size = (zft_calc_tape_pos(zft_last_vtbl->end_seg+1) - - zft_calc_tape_pos(zft_last_vtbl->start_seg)); - vtbl->use_compression = 0; - vtbl->qic113 = zft_qic113; - if (vtbl->qic113) { - TRACE(ft_t_noise, - "Fake alien volume's size from " LL_X " to " LL_X, - LL(GET8(entry, VTBL_DATA_SIZE)), LL(vtbl->size)); - } else { - TRACE(ft_t_noise, - "Fake alien volume's size from %d to " LL_X, - (int)GET4(entry, VTBL_DATA_SIZE), LL(vtbl->size)); - } - TRACE_EXIT; -} - - -/* extract an zftape specific volume - */ -static void extract_zft_volume(__u8 *entry, zft_volinfo *vtbl) -{ - TRACE_FUN(ft_t_flow); - - if (vtbl->qic113) { - vtbl->size = GET8(entry, VTBL_DATA_SIZE); - vtbl->use_compression = - (entry[VTBL_CMPR] & VTBL_CMPR_USED) != 0; - } else { - vtbl->size = GET4(entry, VTBL_DATA_SIZE); - if (entry[VTBL_K_CMPR] & VTBL_CMPR_UNREG) { - vtbl->use_compression = - (entry[VTBL_K_CMPR] & VTBL_CMPR_USED) != 0; - } else if (entry[VTBL_CMPR] & VTBL_CMPR_UNREG) { - vtbl->use_compression = - (entry[VTBL_CMPR] & VTBL_CMPR_USED) != 0; - } else { - TRACE(ft_t_warn, "Geeh! There is something wrong:\n" - KERN_INFO "QIC compression (Rev = K): %x\n" - KERN_INFO "QIC compression (Rev > K): %x", - entry[VTBL_K_CMPR], entry[VTBL_CMPR]); - } - } - TRACE_EXIT; -} - -/* extract the volume table from buffer. "buffer" must already contain - * the vtbl-segment - */ -int zft_extract_volume_headers(__u8 *buffer) -{ - __u8 *entry; - TRACE_FUN(ft_t_flow); - - zft_init_vtbl(); - entry = buffer; -#ifdef ZFT_CMAP_HACK - if ((strncmp(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG, - strlen(ZFTAPE_SIG)) == 0) && - entry[VTBL_EXT+EXT_ZFTAPE_CMAP] != 0) { - TRACE(ft_t_noise, "ignoring cmap volume"); - entry += VTBL_SIZE; - } -#endif - /* the end of the vtbl is indicated by an invalid signature - */ - while (vtbl_signature_valid(&entry[VTBL_SIG]) && - (entry - buffer) < FT_SEGMENT_SIZE) { - zft_new_vtbl_entry(); - if (ft_format_code == fmt_big) { - /* SCSI like vtbl, stores only the number of - * segments used - */ - unsigned int num_segments= GET4(entry, VTBL_SCSI_SEGS); - zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; - zft_last_vtbl->end_seg = - zft_last_vtbl->start_seg + num_segments - 1; - } else { - /* `normal', QIC-80 like vtbl - */ - zft_last_vtbl->start_seg = GET2(entry, VTBL_START); - zft_last_vtbl->end_seg = GET2(entry, VTBL_END); - } - zft_eom_vtbl->start_seg = zft_last_vtbl->end_seg + 1; - /* check if we created this volume and get the - * blk_sz - */ - zft_last_vtbl->zft_volume = check_volume(entry, zft_last_vtbl); - if (zft_last_vtbl->zft_volume == 0) { - extract_alien_volume(entry, zft_last_vtbl); - } else { - extract_zft_volume(entry, zft_last_vtbl); - } - DUMP_VOLINFO(ft_t_noise, &entry[VTBL_DESC], zft_last_vtbl); - entry +=VTBL_SIZE; - } -#if 0 -/* - * undefine to test end of tape handling - */ - zft_new_vtbl_entry(); - zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; - zft_last_vtbl->end_seg = ft_last_data_segment - 10; - zft_last_vtbl->blk_sz = zft_blk_sz; - zft_last_vtbl->zft_volume = 1; - zft_last_vtbl->qic113 = zft_qic113; - zft_last_vtbl->size = (zft_calc_tape_pos(zft_last_vtbl->end_seg+1) - - zft_calc_tape_pos(zft_last_vtbl->start_seg)); -#endif - TRACE_EXIT 0; -} - -/* this functions translates the failed_sector_log, misused as - * EOF-marker list, into a virtual volume table. The table mustn't be - * written to tape, because this would occupy the first data segment, - * which should be the volume table, but is actually the first segment - * that is filled with data (when using standard ftape). We assume, - * that we get a non-empty failed_sector_log. - */ -int zft_fake_volume_headers (eof_mark_union *eof_map, int num_failed_sectors) -{ - unsigned int segment, sector; - int have_eom = 0; - int vol_no; - TRACE_FUN(ft_t_flow); - - if ((num_failed_sectors >= 2) && - (GET2(&eof_map[num_failed_sectors - 1].mark.segment, 0) - == - GET2(&eof_map[num_failed_sectors - 2].mark.segment, 0) + 1) && - (GET2(&eof_map[num_failed_sectors - 1].mark.date, 0) == 1)) { - /* this should be eom. We keep the remainder of the - * tape as another volume. - */ - have_eom = 1; - } - zft_init_vtbl(); - zft_eom_vtbl->start_seg = ft_first_data_segment; - for(vol_no = 0; vol_no < num_failed_sectors - have_eom; vol_no ++) { - zft_new_vtbl_entry(); - - segment = GET2(&eof_map[vol_no].mark.segment, 0); - sector = GET2(&eof_map[vol_no].mark.date, 0); - - zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; - zft_last_vtbl->end_seg = segment; - zft_eom_vtbl->start_seg = segment + 1; - zft_last_vtbl->blk_sz = 1; - zft_last_vtbl->size = - (zft_calc_tape_pos(zft_last_vtbl->end_seg) - - zft_calc_tape_pos(zft_last_vtbl->start_seg) - + (sector-1) * FT_SECTOR_SIZE); - TRACE(ft_t_noise, - "failed sector log: segment: %d, sector: %d", - segment, sector); - DUMP_VOLINFO(ft_t_noise, "Faked volume", zft_last_vtbl); - } - if (!have_eom) { - zft_new_vtbl_entry(); - zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; - zft_last_vtbl->end_seg = ft_last_data_segment; - zft_eom_vtbl->start_seg = ft_last_data_segment + 1; - zft_last_vtbl->size = zft_capacity; - zft_last_vtbl->size -= zft_calc_tape_pos(zft_last_vtbl->start_seg); - zft_last_vtbl->blk_sz = 1; - DUMP_VOLINFO(ft_t_noise, "Faked volume",zft_last_vtbl); - } - TRACE_EXIT 0; -} - -/* update the internal volume table - * - * if before start of last volume: erase all following volumes if - * inside a volume: set end of volume to infinity - * - * this function is intended to be called every time _ftape_write() is - * called - * - * return: 0 if no new volume was created, 1 if a new volume was - * created - * - * NOTE: we don't need to check for zft_mode as ftape_write() does - * that already. This function gets never called without accessing - * zftape via the *qft* devices - */ - -int zft_open_volume(zft_position *pos, int blk_sz, int use_compression) -{ - TRACE_FUN(ft_t_flow); - - if (!zft_qic_mode) { - TRACE_EXIT 0; - } - if (zft_tape_at_lbot(pos)) { - zft_init_vtbl(); - if(zft_old_ftape) { - /* clear old ftape's eof marks */ - zft_clear_ftape_file_marks(); - zft_old_ftape = 0; /* no longer old ftape */ - } - zft_reset_position(pos); - } - if (pos->seg_pos != zft_last_vtbl->end_seg + 1) { - TRACE_ABORT(-EIO, ft_t_bug, - "BUG: seg_pos: %d, zft_last_vtbl->end_seg: %d", - pos->seg_pos, zft_last_vtbl->end_seg); - } - TRACE(ft_t_noise, "create new volume"); - if (zft_eom_vtbl->count >= ZFT_MAX_VOLUMES) { - TRACE_ABORT(-ENOSPC, ft_t_err, - "Error: maxmimal number of volumes exhausted " - "(maxmimum is %d)", ZFT_MAX_VOLUMES); - } - zft_new_vtbl_entry(); - pos->volume_pos = pos->seg_byte_pos = 0; - zft_last_vtbl->start_seg = pos->seg_pos; - zft_last_vtbl->end_seg = ft_last_data_segment; /* infinity */ - zft_last_vtbl->blk_sz = blk_sz; - zft_last_vtbl->size = zft_capacity; - zft_last_vtbl->zft_volume = 1; - zft_last_vtbl->use_compression = use_compression; - zft_last_vtbl->qic113 = zft_qic113; - zft_last_vtbl->new_volume = 1; - zft_last_vtbl->open = 1; - zft_volume_table_changed = 1; - zft_eom_vtbl->start_seg = ft_last_data_segment + 1; - TRACE_EXIT 0; -} - -/* perform mtfsf, mtbsf, not allowed without zft_qic_mode - */ -int zft_skip_volumes(int count, zft_position *pos) -{ - const zft_volinfo *vtbl; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "count: %d", count); - - vtbl= zft_find_volume(pos->seg_pos); - while (count > 0 && vtbl != zft_eom_vtbl) { - vtbl = list_entry(vtbl->node.next, zft_volinfo, node); - count --; - } - while (count < 0 && vtbl != zft_first_vtbl) { - vtbl = list_entry(vtbl->node.prev, zft_volinfo, node); - count ++; - } - pos->seg_pos = vtbl->start_seg; - pos->seg_byte_pos = 0; - pos->volume_pos = 0; - pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); - zft_just_before_eof = vtbl->size == 0; - if (zft_cmpr_ops) { - (*zft_cmpr_ops->reset)(); - } - zft_deblock_segment = -1; /* no need to keep cache */ - TRACE(ft_t_noise, "repositioning to:\n" - KERN_INFO "zft_seg_pos : %d\n" - KERN_INFO "zft_seg_byte_pos : %d\n" - KERN_INFO "zft_tape_pos : " LL_X "\n" - KERN_INFO "zft_volume_pos : " LL_X "\n" - KERN_INFO "file number : %d", - pos->seg_pos, pos->seg_byte_pos, - LL(pos->tape_pos), LL(pos->volume_pos), vtbl->count); - zft_resid = count < 0 ? -count : count; - TRACE_EXIT zft_resid ? -EINVAL : 0; -} - -/* the following simply returns the raw data position of the EOM - * marker, MTIOCSIZE ioctl - */ -__s64 zft_get_eom_pos(void) -{ - if (zft_qic_mode) { - return zft_calc_tape_pos(zft_eom_vtbl->start_seg); - } else { - /* there is only one volume in raw mode */ - return zft_capacity; - } -} - -/* skip to eom, used for MTEOM - */ -void zft_skip_to_eom(zft_position *pos) -{ - TRACE_FUN(ft_t_flow); - pos->seg_pos = zft_eom_vtbl->start_seg; - pos->seg_byte_pos = - pos->volume_pos = - zft_just_before_eof = 0; - pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); - TRACE(ft_t_noise, "ftape positioned to segment %d, data pos " LL_X, - pos->seg_pos, LL(pos->tape_pos)); - TRACE_EXIT; -} - -/* write an EOF-marker by setting zft_last_vtbl->end_seg to seg_pos. - * NOTE: this function assumes that zft_last_vtbl points to a valid - * vtbl entry - * - * NOTE: this routine always positions before the EOF marker - */ -int zft_close_volume(zft_position *pos) -{ - TRACE_FUN(ft_t_any); - - if (zft_vtbl_empty || !zft_last_vtbl->open) { /* should not happen */ - TRACE(ft_t_noise, "There are no volumes to finish"); - TRACE_EXIT -EIO; - } - if (pos->seg_byte_pos == 0 && - pos->seg_pos != zft_last_vtbl->start_seg) { - pos->seg_pos --; - pos->seg_byte_pos = zft_get_seg_sz(pos->seg_pos); - } - zft_last_vtbl->end_seg = pos->seg_pos; - zft_last_vtbl->size = pos->volume_pos; - zft_volume_table_changed = 1; - zft_just_before_eof = 1; - zft_eom_vtbl->start_seg = zft_last_vtbl->end_seg + 1; - zft_last_vtbl->open = 0; /* closed */ - TRACE_EXIT 0; -} - -/* write count file-marks at current position. - * - * The tape is positioned after the eof-marker, that is at byte 0 of - * the segment following the eof-marker - * - * this function is only allowed in zft_qic_mode - * - * Only allowed when tape is at BOT or EOD. - */ -int zft_weof(unsigned int count, zft_position *pos) -{ - - TRACE_FUN(ft_t_flow); - - if (!count) { /* write zero EOF marks should be a real no-op */ - TRACE_EXIT 0; - } - zft_volume_table_changed = 1; - if (zft_tape_at_lbot(pos)) { - zft_init_vtbl(); - if(zft_old_ftape) { - /* clear old ftape's eof marks */ - zft_clear_ftape_file_marks(); - zft_old_ftape = 0; /* no longer old ftape */ - } - } - if (zft_last_vtbl->open) { - zft_close_volume(pos); - zft_move_past_eof(pos); - count --; - } - /* now it's easy, just append eof-marks, that is empty - * volumes, to the end of the already recorded media. - */ - while (count > 0 && - pos->seg_pos <= ft_last_data_segment && - zft_eom_vtbl->count < ZFT_MAX_VOLUMES) { - TRACE(ft_t_noise, - "Writing zero sized file at segment %d", pos->seg_pos); - zft_new_vtbl_entry(); - zft_last_vtbl->start_seg = pos->seg_pos; - zft_last_vtbl->end_seg = pos->seg_pos; - zft_last_vtbl->size = 0; - zft_last_vtbl->blk_sz = zft_blk_sz; - zft_last_vtbl->zft_volume = 1; - zft_last_vtbl->use_compression = 0; - pos->tape_pos += zft_get_seg_sz(pos->seg_pos); - zft_eom_vtbl->start_seg = ++ pos->seg_pos; - count --; - } - if (count > 0) { - /* there are two possibilities: end of tape, or the - * maximum number of files is exhausted. - */ - zft_resid = count; - TRACE(ft_t_noise,"Number of marks NOT written: %d", zft_resid); - if (zft_eom_vtbl->count == ZFT_MAX_VOLUMES) { - TRACE_ABORT(-EINVAL, ft_t_warn, - "maximum allowed number of files " - "exhausted: %d", ZFT_MAX_VOLUMES); - } else { - TRACE_ABORT(-ENOSPC, - ft_t_noise, "reached end of tape"); - } - } - TRACE_EXIT 0; -} - -const zft_volinfo *zft_find_volume(unsigned int seg_pos) -{ - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_any, "called with seg_pos %d",seg_pos); - if (!zft_qic_mode) { - if (seg_pos > ft_last_data_segment) { - TRACE_EXIT &eot_vtbl; - } - tape_vtbl.blk_sz = zft_blk_sz; - TRACE_EXIT &tape_vtbl; - } - if (seg_pos < zft_first_vtbl->start_seg) { - TRACE_EXIT (cur_vtbl = zft_first_vtbl); - } - while (seg_pos > cur_vtbl->end_seg) { - cur_vtbl = list_entry(cur_vtbl->node.next, zft_volinfo, node); - TRACE(ft_t_noise, "%d - %d", cur_vtbl->start_seg, cur_vtbl->end_seg); - } - while (seg_pos < cur_vtbl->start_seg) { - cur_vtbl = list_entry(cur_vtbl->node.prev, zft_volinfo, node); - TRACE(ft_t_noise, "%d - %d", cur_vtbl->start_seg, cur_vtbl->end_seg); - } - if (seg_pos > cur_vtbl->end_seg || seg_pos < cur_vtbl->start_seg) { - TRACE(ft_t_bug, "This cannot happen"); - } - DUMP_VOLINFO(ft_t_noise, "", cur_vtbl); - TRACE_EXIT cur_vtbl; -} - -/* this function really assumes that we are just before eof - */ -void zft_move_past_eof(zft_position *pos) -{ - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_noise, "old seg. pos: %d", pos->seg_pos); - pos->tape_pos += zft_get_seg_sz(pos->seg_pos++) - pos->seg_byte_pos; - pos->seg_byte_pos = 0; - pos->volume_pos = 0; - if (zft_cmpr_ops) { - (*zft_cmpr_ops->reset)(); - } - zft_just_before_eof = 0; - zft_deblock_segment = -1; /* no need to cache it anymore */ - TRACE(ft_t_noise, "new seg. pos: %d", pos->seg_pos); - TRACE_EXIT; -} diff --git a/drivers/char/ftape/zftape/zftape-vtbl.h b/drivers/char/ftape/zftape/zftape-vtbl.h deleted file mode 100644 index f31d196d175..00000000000 --- a/drivers/char/ftape/zftape/zftape-vtbl.h +++ /dev/null @@ -1,227 +0,0 @@ -#ifndef _ZFTAPE_VTBL_H -#define _ZFTAPE_VTBL_H - -/* - * Copyright (c) 1995-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/zftape/zftape-vtbl.h,v $ - * $Revision: 1.3 $ - * $Date: 1997/10/28 14:30:09 $ - * - * This file defines a volume table as defined in the QIC-80 - * development standards. - */ - -#include - -#include "../lowlevel/ftape-tracing.h" - -#include "../zftape/zftape-eof.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-rw.h" - -#define VTBL_SIZE 128 /* bytes */ - -/* The following are offsets in the vtbl. */ -#define VTBL_SIG 0 -#define VTBL_START 4 -#define VTBL_END 6 -#define VTBL_DESC 8 -#define VTBL_DATE 52 -#define VTBL_FLAGS 56 -#define VTBL_FL_VENDOR_SPECIFIC (1<<0) -#define VTBL_FL_MUTLI_CARTRIDGE (1<<1) -#define VTBL_FL_NOT_VERIFIED (1<<2) -#define VTBL_FL_REDIR_INHIBIT (1<<3) -#define VTBL_FL_SEG_SPANNING (1<<4) -#define VTBL_FL_DIRECTORY_LAST (1<<5) -#define VTBL_FL_RESERVED_6 (1<<6) -#define VTBL_FL_RESERVED_7 (1<<7) -#define VTBL_M_NO 57 -#define VTBL_EXT 58 -#define EXT_ZFTAPE_SIG 0 -#define EXT_ZFTAPE_BLKSZ 10 -#define EXT_ZFTAPE_CMAP 12 -#define EXT_ZFTAPE_QIC113 13 -#define VTBL_PWD 84 -#define VTBL_DIR_SIZE 92 -#define VTBL_DATA_SIZE 96 -#define VTBL_OS_VERSION 104 -#define VTBL_SRC_DRIVE 106 -#define VTBL_DEV 122 -#define VTBL_RESERVED_1 123 -#define VTBL_CMPR 124 -#define VTBL_CMPR_UNREG 0x3f -#define VTBL_CMPR_USED 0x80 -#define VTBL_FMT 125 -#define VTBL_RESERVED_2 126 -#define VTBL_RESERVED_3 127 -/* compatibility with pre revision K */ -#define VTBL_K_CMPR 120 - -/* the next is used by QIC-3020 tapes with format code 6 (>2^16 - * segments) It is specified in QIC-113, Rev. G, Section 5 (SCSI - * volume table). The difference is simply, that we only store the - * number of segments used, not the starting segment. - */ -#define VTBL_SCSI_SEGS 4 /* is a 4 byte value */ - -/* one vtbl is 128 bytes, that results in a maximum number of - * 29*1024/128 = 232 volumes. - */ -#define ZFT_MAX_VOLUMES (FT_SEGMENT_SIZE/VTBL_SIZE) -#define VTBL_ID "VTBL" -#define VTBL_IDS { VTBL_ID, "XTBL", "UTID", "EXVT" } /* other valid ids */ -#define ZFT_VOL_NAME "zftape volume" /* volume label used by me */ -#define ZFTAPE_SIG "LINUX ZFT" - -/* global variables - */ -typedef struct zft_internal_vtbl -{ - struct list_head node; - int count; - unsigned int start_seg; /* 32 bits are enough for now */ - unsigned int end_seg; /* 32 bits are enough for now */ - __s64 size; /* uncompressed size */ - unsigned int blk_sz; /* block size for this volume */ - unsigned int zft_volume :1; /* zftape created this volume */ - unsigned int use_compression:1; /* compressed volume */ - unsigned int qic113 :1; /* layout of compressed block - * info and vtbl conforms to - * QIC-113, Rev. G - */ - unsigned int new_volume :1; /* it was created by us, this - * run. this allows the - * fields that aren't really - * used by zftape to be filled - * in by some user level - * program. - */ - unsigned int open :1; /* just in progress of being - * written - */ -} zft_volinfo; - -extern struct list_head zft_vtbl; -#define zft_head_vtbl list_entry(zft_vtbl.next, zft_volinfo, node) -#define zft_eom_vtbl list_entry(zft_vtbl.prev, zft_volinfo, node) -#define zft_last_vtbl list_entry(zft_eom_vtbl->node.prev, zft_volinfo, node) -#define zft_first_vtbl list_entry(zft_head_vtbl->node.next, zft_volinfo, node) -#define zft_vtbl_empty (zft_eom_vtbl->node.prev == &zft_head_vtbl->node) - -#define DUMP_VOLINFO(level, desc, info) \ -{ \ - char tmp[21]; \ - strlcpy(tmp, desc, sizeof(tmp)); \ - TRACE(level, "Volume %d:\n" \ - KERN_INFO "description : %s\n" \ - KERN_INFO "first segment: %d\n" \ - KERN_INFO "last segment: %d\n" \ - KERN_INFO "size : " LL_X "\n" \ - KERN_INFO "block size : %d\n" \ - KERN_INFO "compression : %d\n" \ - KERN_INFO "zftape volume: %d\n" \ - KERN_INFO "QIC-113 conf.: %d", \ - (info)->count, tmp, (info)->start_seg, (info)->end_seg, \ - LL((info)->size), (info)->blk_sz, \ - (info)->use_compression != 0, (info)->zft_volume != 0, \ - (info)->qic113 != 0); \ -} - -extern int zft_qic_mode; -extern int zft_old_ftape; -extern int zft_volume_table_changed; - -/* exported functions */ -extern void zft_init_vtbl (void); -extern void zft_free_vtbl (void); -extern int zft_extract_volume_headers(__u8 *buffer); -extern int zft_update_volume_table (unsigned int segment); -extern int zft_open_volume (zft_position *pos, - int blk_sz, int use_compression); -extern int zft_close_volume (zft_position *pos); -extern const zft_volinfo *zft_find_volume(unsigned int seg_pos); -extern int zft_skip_volumes (int count, zft_position *pos); -extern __s64 zft_get_eom_pos (void); -extern void zft_skip_to_eom (zft_position *pos); -extern int zft_fake_volume_headers (eof_mark_union *eof_map, - int num_failed_sectors); -extern int zft_weof (unsigned int count, zft_position *pos); -extern void zft_move_past_eof (zft_position *pos); - -static inline int zft_tape_at_eod (const zft_position *pos); -static inline int zft_tape_at_lbot (const zft_position *pos); -static inline void zft_position_before_eof (zft_position *pos, - const zft_volinfo *volume); -static inline __s64 zft_check_for_eof(const zft_volinfo *vtbl, - const zft_position *pos); - -/* this function decrements the zft_seg_pos counter if we are right - * at the beginning of a segment. This is to handle fsfm/bsfm -- we - * need to position before the eof mark. NOTE: zft_tape_pos is not - * changed - */ -static inline void zft_position_before_eof(zft_position *pos, - const zft_volinfo *volume) -{ - TRACE_FUN(ft_t_flow); - - if (pos->seg_pos == volume->end_seg + 1 && pos->seg_byte_pos == 0) { - pos->seg_pos --; - pos->seg_byte_pos = zft_get_seg_sz(pos->seg_pos); - } - TRACE_EXIT; -} - -/* Mmmh. Is the position at the end of the last volume, that is right - * before the last EOF mark also logical an EOD condition? - */ -static inline int zft_tape_at_eod(const zft_position *pos) -{ - TRACE_FUN(ft_t_any); - - if (zft_qic_mode) { - TRACE_EXIT (pos->seg_pos >= zft_eom_vtbl->start_seg || - zft_last_vtbl->open); - } else { - TRACE_EXIT pos->seg_pos > ft_last_data_segment; - } -} - -static inline int zft_tape_at_lbot(const zft_position *pos) -{ - if (zft_qic_mode) { - return (pos->seg_pos <= zft_first_vtbl->start_seg && - pos->volume_pos == 0); - } else { - return (pos->seg_pos <= ft_first_data_segment && - pos->volume_pos == 0); - } -} - -/* This one checks for EOF. return remaing space (may be negative) - */ -static inline __s64 zft_check_for_eof(const zft_volinfo *vtbl, - const zft_position *pos) -{ - return (__s64)(vtbl->size - pos->volume_pos); -} - -#endif /* _ZFTAPE_VTBL_H */ diff --git a/drivers/char/ftape/zftape/zftape-write.c b/drivers/char/ftape/zftape/zftape-write.c deleted file mode 100644 index 94327b8c97b..00000000000 --- a/drivers/char/ftape/zftape/zftape-write.c +++ /dev/null @@ -1,483 +0,0 @@ -/* - * Copyright (C) 1996, 1997 Claus 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/zftape/zftape-write.c,v $ - * $Revision: 1.3 $ - * $Date: 1997/11/06 00:50:29 $ - * - * This file contains the writing code - * for the QIC-117 floppy-tape driver for Linux. - */ - -#include -#include - -#include - -#include - -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-eof.h" -#include "../zftape/zftape-ctl.h" -#include "../zftape/zftape-write.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-rw.h" -#include "../zftape/zftape-vtbl.h" - -/* Global vars. - */ - -/* Local vars. - */ -static int last_write_failed; -static int need_flush; - -void zft_prevent_flush(void) -{ - need_flush = 0; -} - -static int zft_write_header_segments(__u8* buffer) -{ - int header_1_ok = 0; - int header_2_ok = 0; - unsigned int time_stamp; - TRACE_FUN(ft_t_noise); - - TRACE_CATCH(ftape_abort_operation(),); - ftape_seek_to_bot(); /* prevents extra rewind */ - if (GET4(buffer, 0) != FT_HSEG_MAGIC) { - TRACE_ABORT(-EIO, ft_t_err, - "wrong header signature found, aborting"); - } - /* Be optimistic: */ - PUT4(buffer, FT_SEG_CNT, - zft_written_segments + GET4(buffer, FT_SEG_CNT) + 2); - if ((time_stamp = zft_get_time()) != 0) { - PUT4(buffer, FT_WR_DATE, time_stamp); - if (zft_label_changed) { - PUT4(buffer, FT_LABEL_DATE, time_stamp); - } - } - TRACE(ft_t_noise, - "writing first header segment %d", ft_header_segment_1); - header_1_ok = zft_verify_write_segments(ft_header_segment_1, - buffer, FT_SEGMENT_SIZE, - zft_deblock_buf) >= 0; - TRACE(ft_t_noise, - "writing second header segment %d", ft_header_segment_2); - header_2_ok = zft_verify_write_segments(ft_header_segment_2, - buffer, FT_SEGMENT_SIZE, - zft_deblock_buf) >= 0; - if (!header_1_ok) { - TRACE(ft_t_warn, "Warning: " - "update of first header segment failed"); - } - if (!header_2_ok) { - TRACE(ft_t_warn, "Warning: " - "update of second header segment failed"); - } - if (!header_1_ok && !header_2_ok) { - TRACE_ABORT(-EIO, ft_t_err, "Error: " - "update of both header segments failed."); - } - TRACE_EXIT 0; -} - -int zft_update_header_segments(void) -{ - TRACE_FUN(ft_t_noise); - - /* must NOT use zft_write_protected, as it also includes the - * file access mode. But we also want to update when soft - * write protection is enabled (O_RDONLY) - */ - if (ft_write_protected || zft_old_ftape) { - TRACE_ABORT(0, ft_t_noise, "Tape set read-only: no update"); - } - if (!zft_header_read) { - TRACE_ABORT(0, ft_t_noise, "Nothing to update"); - } - if (!zft_header_changed) { - zft_header_changed = zft_written_segments > 0; - } - if (!zft_header_changed && !zft_volume_table_changed) { - TRACE_ABORT(0, ft_t_noise, "Nothing to update"); - } - TRACE(ft_t_noise, "Updating header segments"); - if (ftape_get_status()->fti_state == writing) { - TRACE_CATCH(ftape_loop_until_writes_done(),); - } - TRACE_CATCH(ftape_abort_operation(),); - - zft_deblock_segment = -1; /* invalidate the cache */ - if (zft_header_changed) { - TRACE_CATCH(zft_write_header_segments(zft_hseg_buf),); - } - if (zft_volume_table_changed) { - TRACE_CATCH(zft_update_volume_table(ft_first_data_segment),); - } - zft_header_changed = - zft_volume_table_changed = - zft_label_changed = - zft_written_segments = 0; - TRACE_CATCH(ftape_abort_operation(),); - ftape_seek_to_bot(); - TRACE_EXIT 0; -} - -static int read_merge_buffer(int seg_pos, __u8 *buffer, int offset, int seg_sz) -{ - int result = 0; - const ft_trace_t old_tracing = TRACE_LEVEL; - TRACE_FUN(ft_t_flow); - - if (zft_qic_mode) { - /* writing in the middle of a volume is NOT allowed - * - */ - TRACE(ft_t_noise, "No need to read a segment"); - memset(buffer + offset, 0, seg_sz - offset); - TRACE_EXIT 0; - } - TRACE(ft_t_any, "waiting"); - ftape_start_writing(FT_WR_MULTI); - TRACE_CATCH(ftape_loop_until_writes_done(),); - - TRACE(ft_t_noise, "trying to read segment %d from offset %d", - seg_pos, offset); - SET_TRACE_LEVEL(ft_t_bug); - result = zft_fetch_segment_fraction(seg_pos, buffer, - FT_RD_SINGLE, - offset, seg_sz - offset); - SET_TRACE_LEVEL(old_tracing); - if (result != (seg_sz - offset)) { - TRACE(ft_t_noise, "Ignore error: read_segment() result: %d", - result); - memset(buffer + offset, 0, seg_sz - offset); - } - TRACE_EXIT 0; -} - -/* flush the write buffer to tape and write an eof-marker at the - * current position if not in raw mode. This function always - * positions the tape before the eof-marker. _ftape_close() should - * then advance to the next segment. - * - * the parameter "finish_volume" describes whether to position before - * or after the possibly created file-mark. We always position after - * the file-mark when called from ftape_close() and a flush was needed - * (that is ftape_write() was the last tape operation before calling - * ftape_flush) But we always position before the file-mark when this - * function get's called from outside ftape_close() - */ -int zft_flush_buffers(void) -{ - int result; - int data_remaining; - int this_segs_size; - TRACE_FUN(ft_t_flow); - - TRACE(ft_t_data_flow, - "entered, ftape_state = %d", ftape_get_status()->fti_state); - if (ftape_get_status()->fti_state != writing && !need_flush) { - TRACE_ABORT(0, ft_t_noise, "no need for flush"); - } - zft_io_state = zft_idle; /* triggers some initializations for the - * read and write routines - */ - if (last_write_failed) { - ftape_abort_operation(); - TRACE_EXIT -EIO; - } - TRACE(ft_t_noise, "flushing write buffers"); - this_segs_size = zft_get_seg_sz(zft_pos.seg_pos); - if (this_segs_size == zft_pos.seg_byte_pos) { - zft_pos.seg_pos ++; - data_remaining = zft_pos.seg_byte_pos = 0; - } else { - data_remaining = zft_pos.seg_byte_pos; - } - /* If there is any data not written to tape yet, append zero's - * up to the end of the sector (if using compression) or merge - * it with the data existing on the tape Then write the - * segment(s) to tape. - */ - TRACE(ft_t_noise, "Position:\n" - KERN_INFO "seg_pos : %d\n" - KERN_INFO "byte pos : %d\n" - KERN_INFO "remaining: %d", - zft_pos.seg_pos, zft_pos.seg_byte_pos, data_remaining); - if (data_remaining > 0) { - do { - this_segs_size = zft_get_seg_sz(zft_pos.seg_pos); - if (this_segs_size > data_remaining) { - TRACE_CATCH(read_merge_buffer(zft_pos.seg_pos, - zft_deblock_buf, - data_remaining, - this_segs_size), - last_write_failed = 1); - } - result = ftape_write_segment(zft_pos.seg_pos, - zft_deblock_buf, - FT_WR_MULTI); - if (result != this_segs_size) { - TRACE(ft_t_err, "flush buffers failed"); - zft_pos.tape_pos -= zft_pos.seg_byte_pos; - zft_pos.seg_byte_pos = 0; - - last_write_failed = 1; - TRACE_EXIT result; - } - zft_written_segments ++; - TRACE(ft_t_data_flow, - "flush, moved out buffer: %d", result); - /* need next segment for more data (empty segments?) - */ - if (result < data_remaining) { - if (result > 0) { - /* move remainder to buffer beginning - */ - memmove(zft_deblock_buf, - zft_deblock_buf + result, - FT_SEGMENT_SIZE - result); - } - } - data_remaining -= result; - zft_pos.seg_pos ++; - } while (data_remaining > 0); - TRACE(ft_t_any, "result: %d", result); - zft_deblock_segment = --zft_pos.seg_pos; - if (data_remaining == 0) { /* first byte next segment */ - zft_pos.seg_byte_pos = this_segs_size; - } else { /* after data previous segment, data_remaining < 0 */ - zft_pos.seg_byte_pos = data_remaining + result; - } - } else { - TRACE(ft_t_noise, "zft_deblock_buf empty"); - zft_pos.seg_pos --; - zft_pos.seg_byte_pos = zft_get_seg_sz (zft_pos.seg_pos); - ftape_start_writing(FT_WR_MULTI); - } - TRACE(ft_t_any, "waiting"); - if ((result = ftape_loop_until_writes_done()) < 0) { - /* that's really bad. What to to with zft_tape_pos? - */ - TRACE(ft_t_err, "flush buffers failed"); - } - TRACE(ft_t_any, "zft_seg_pos: %d, zft_seg_byte_pos: %d", - zft_pos.seg_pos, zft_pos.seg_byte_pos); - last_write_failed = - need_flush = 0; - TRACE_EXIT result; -} - -/* return-value: the number of bytes removed from the user-buffer - * - * out: - * int *write_cnt: how much actually has been moved to the - * zft_deblock_buf - * int req_len : MUST NOT BE CHANGED, except at EOT, in - * which case it may be adjusted - * in : - * char *buff : the user buffer - * int buf_pos_write : copy of buf_len_wr int - * this_segs_size : the size in bytes of the actual segment - * char - * *zft_deblock_buf : zft_deblock_buf - */ -static int zft_simple_write(int *cnt, - __u8 *dst_buf, const int seg_sz, - const __u8 __user *src_buf, const int req_len, - const zft_position *pos,const zft_volinfo *volume) -{ - int space_left; - TRACE_FUN(ft_t_flow); - - /* volume->size holds the tape capacity while volume is open */ - if (pos->tape_pos + volume->blk_sz > volume->size) { - TRACE_EXIT -ENOSPC; - } - /* remaining space in this segment, NOT zft_deblock_buf - */ - space_left = seg_sz - pos->seg_byte_pos; - *cnt = req_len < space_left ? req_len : space_left; - if (copy_from_user(dst_buf + pos->seg_byte_pos, src_buf, *cnt) != 0) { - TRACE_EXIT -EFAULT; - } - TRACE_EXIT *cnt; -} - -static int check_write_access(int req_len, - const zft_volinfo **volume, - zft_position *pos, - const unsigned int blk_sz) -{ - int result; - TRACE_FUN(ft_t_flow); - - if ((req_len % zft_blk_sz) != 0) { - TRACE_ABORT(-EINVAL, ft_t_info, - "write-count %d must be multiple of block-size %d", - req_len, blk_sz); - } - if (zft_io_state == zft_writing) { - /* all other error conditions have been checked earlier - */ - TRACE_EXIT 0; - } - zft_io_state = zft_idle; - TRACE_CATCH(zft_check_write_access(pos),); - /* If we haven't read the header segment yet, do it now. - * This will verify the configuration, get the bad sector - * table and read the volume table segment - */ - if (!zft_header_read) { - TRACE_CATCH(zft_read_header_segments(),); - } - /* fine. Now the tape is either at BOT or at EOD, - * Write start of volume now - */ - TRACE_CATCH(zft_open_volume(pos, blk_sz, zft_use_compression),); - *volume = zft_find_volume(pos->seg_pos); - DUMP_VOLINFO(ft_t_noise, "", *volume); - zft_just_before_eof = 0; - /* now merge with old data if necessary */ - if (!zft_qic_mode && pos->seg_byte_pos != 0){ - result = zft_fetch_segment(pos->seg_pos, - zft_deblock_buf, - FT_RD_SINGLE); - if (result < 0) { - if (result == -EINTR || result == -ENOSPC) { - TRACE_EXIT result; - } - TRACE(ft_t_noise, - "ftape_read_segment() result: %d. " - "This might be normal when using " - "a newly\nformatted tape", result); - memset(zft_deblock_buf, '\0', pos->seg_byte_pos); - } - } - zft_io_state = zft_writing; - TRACE_EXIT 0; -} - -static int fill_deblock_buf(__u8 *dst_buf, const int seg_sz, - zft_position *pos, const zft_volinfo *volume, - const char __user *usr_buf, const int req_len) -{ - int cnt = 0; - int result = 0; - TRACE_FUN(ft_t_flow); - - if (seg_sz == 0) { - TRACE_ABORT(0, ft_t_data_flow, "empty segment"); - } - TRACE(ft_t_data_flow, "\n" - KERN_INFO "remaining req_len: %d\n" - KERN_INFO " buf_pos: %d", - req_len, pos->seg_byte_pos); - /* zft_deblock_buf will not contain a valid segment any longer */ - zft_deblock_segment = -1; - if (zft_use_compression) { - TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),); - TRACE_CATCH(result= (*zft_cmpr_ops->write)(&cnt, - dst_buf, seg_sz, - usr_buf, req_len, - pos, volume),); - } else { - TRACE_CATCH(result= zft_simple_write(&cnt, - dst_buf, seg_sz, - usr_buf, req_len, - pos, volume),); - } - pos->volume_pos += result; - pos->seg_byte_pos += cnt; - pos->tape_pos += cnt; - TRACE(ft_t_data_flow, "\n" - KERN_INFO "removed from user-buffer : %d bytes.\n" - KERN_INFO "copied to zft_deblock_buf: %d bytes.\n" - KERN_INFO "zft_tape_pos : " LL_X " bytes.", - result, cnt, LL(pos->tape_pos)); - TRACE_EXIT result; -} - - -/* called by the kernel-interface routine "zft_write()" - */ -int _zft_write(const char __user *buff, int req_len) -{ - int result = 0; - int written = 0; - int write_cnt; - int seg_sz; - static const zft_volinfo *volume = NULL; - TRACE_FUN(ft_t_flow); - - zft_resid = req_len; - last_write_failed = 1; /* reset to 0 when successful */ - /* check if write is allowed - */ - TRACE_CATCH(check_write_access(req_len, &volume,&zft_pos,zft_blk_sz),); - while (req_len > 0) { - /* Allow us to escape from this loop with a signal ! - */ - FT_SIGNAL_EXIT(_DONT_BLOCK); - seg_sz = zft_get_seg_sz(zft_pos.seg_pos); - if ((write_cnt = fill_deblock_buf(zft_deblock_buf, - seg_sz, - &zft_pos, - volume, - buff, - req_len)) < 0) { - zft_resid -= written; - if (write_cnt == -ENOSPC) { - /* leave the remainder to flush_buffers() - */ - TRACE(ft_t_info, "No space left on device"); - last_write_failed = 0; - if (!need_flush) { - need_flush = written > 0; - } - TRACE_EXIT written > 0 ? written : -ENOSPC; - } else { - TRACE_EXIT result; - } - } - if (zft_pos.seg_byte_pos == seg_sz) { - TRACE_CATCH(ftape_write_segment(zft_pos.seg_pos, - zft_deblock_buf, - FT_WR_ASYNC), - zft_resid -= written); - zft_written_segments ++; - zft_pos.seg_byte_pos = 0; - zft_deblock_segment = zft_pos.seg_pos; - ++zft_pos.seg_pos; - } - written += write_cnt; - buff += write_cnt; - req_len -= write_cnt; - } /* while (req_len > 0) */ - TRACE(ft_t_data_flow, "remaining in blocking buffer: %d", - zft_pos.seg_byte_pos); - TRACE(ft_t_data_flow, "just written bytes: %d", written); - last_write_failed = 0; - zft_resid -= written; - need_flush = need_flush || written > 0; - TRACE_EXIT written; /* bytes written */ -} diff --git a/drivers/char/ftape/zftape/zftape-write.h b/drivers/char/ftape/zftape/zftape-write.h deleted file mode 100644 index ea887015b49..00000000000 --- a/drivers/char/ftape/zftape/zftape-write.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef _ZFTAPE_WRITE_H -#define _ZFTAPE_WRITE_H - -/* - * Copyright (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/zftape/zftape-write.h,v $ - * $Revision: 1.2 $ - * $Date: 1997/10/05 19:19:13 $ - * - * This file contains the definitions for the write functions - * for the zftape driver for Linux. - * - */ - -extern int zft_flush_buffers(void); -extern int zft_update_header_segments(void); -extern void zft_prevent_flush(void); - -/* hook for the VFS interface - */ -extern int _zft_write(const char __user *buff, int req_len); -#endif /* _ZFTAPE_WRITE_H */ diff --git a/drivers/char/ftape/zftape/zftape_syms.c b/drivers/char/ftape/zftape/zftape_syms.c deleted file mode 100644 index 2db1401682d..00000000000 --- a/drivers/char/ftape/zftape/zftape_syms.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 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/zftape/zftape_syms.c,v $ - * $Revision: 1.3 $ - * $Date: 1997/10/05 19:19:14 $ - * - * This file contains the symbols that the zftape frontend to - * the ftape floppy tape driver exports - */ - -#include - -#include - -#include "../zftape/zftape-init.h" -#include "../zftape/zftape-read.h" -#include "../zftape/zftape-buffers.h" -#include "../zftape/zftape-ctl.h" - -/* zftape-init.c */ -EXPORT_SYMBOL(zft_cmpr_register); -/* zftape-read.c */ -EXPORT_SYMBOL(zft_fetch_segment_fraction); -/* zftape-buffers.c */ -EXPORT_SYMBOL(zft_vmalloc_once); -EXPORT_SYMBOL(zft_vmalloc_always); -EXPORT_SYMBOL(zft_vfree); -- cgit v1.2.3