diff options
Diffstat (limited to 'drivers/char')
130 files changed, 3485 insertions, 20650 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 2af12fc45115..24f922f12783 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 <file:drivers/char/ftape/README.PCI>. - - 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" @@ -994,7 +961,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 diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 777cad045094..b1fcdab90947 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/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 00b17ae39736..2f2c4efff8a3 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -459,7 +459,7 @@ static const struct aper_size_info_32 nforce3_sizes[5] = /* Handle shadow device of the Nvidia NForce3 */ /* CHECK-ME original 2.4 version set up some IORRs. Check if that is needed. */ -static int __devinit nforce3_agp_init(struct pci_dev *pdev) +static int nforce3_agp_init(struct pci_dev *pdev) { u32 tmp, apbase, apbar, aplimit; struct pci_dev *dev1; diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index e608dadece2f..acb2de5e3a98 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -926,9 +926,10 @@ cy_sched_event(struct cyclades_port *info, int event) * had to poll every port to see if that port needed servicing. */ static void -do_softint(void *private_) +do_softint(struct work_struct *work) { - struct cyclades_port *info = (struct cyclades_port *) private_; + struct cyclades_port *info = + container_of(work, struct cyclades_port, tqueue); struct tty_struct *tty; tty = info->tty; @@ -5328,7 +5329,7 @@ cy_init(void) info->blocked_open = 0; info->default_threshold = 0; info->default_timeout = 0; - INIT_WORK(&info->tqueue, do_softint, info); + INIT_WORK(&info->tqueue, do_softint); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->shutdown_wait); @@ -5403,7 +5404,7 @@ cy_init(void) info->blocked_open = 0; info->default_threshold = 0; info->default_timeout = 0; - INIT_WORK(&info->tqueue, do_softint, info); + INIT_WORK(&info->tqueue, do_softint); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->shutdown_wait); diff --git a/drivers/char/decserial.c b/drivers/char/decserial.c index 85f404e25c73..8ea2bea2b183 100644 --- a/drivers/char/decserial.c +++ b/drivers/char/decserial.c @@ -23,20 +23,12 @@ extern int zs_init(void); #endif -#ifdef CONFIG_DZ -extern int dz_init(void); -#endif - #ifdef CONFIG_SERIAL_CONSOLE #ifdef CONFIG_ZS extern void zs_serial_console_init(void); #endif -#ifdef CONFIG_DZ -extern void dz_serial_console_init(void); -#endif - #endif /* rs_init - starts up the serial interface - @@ -46,23 +38,11 @@ extern void dz_serial_console_init(void); int __init rs_init(void) { - -#if defined(CONFIG_ZS) && defined(CONFIG_DZ) +#ifdef CONFIG_ZS if (IOASIC) return zs_init(); - else - return dz_init(); -#else - -#ifdef CONFIG_ZS - return zs_init(); -#endif - -#ifdef CONFIG_DZ - return dz_init(); -#endif - #endif + return -ENXIO; } __initcall(rs_init); @@ -76,21 +56,9 @@ __initcall(rs_init); */ static int __init decserial_console_init(void) { -#if defined(CONFIG_ZS) && defined(CONFIG_DZ) +#ifdef CONFIG_ZS if (IOASIC) zs_serial_console_init(); - else - dz_serial_console_init(); -#else - -#ifdef CONFIG_ZS - zs_serial_console_init(); -#endif - -#ifdef CONFIG_DZ - dz_serial_console_init(); -#endif - #endif return 0; } diff --git a/drivers/char/drm/drm_sman.c b/drivers/char/drm/drm_sman.c index 425c82336ee0..19c81d2e13d0 100644 --- a/drivers/char/drm/drm_sman.c +++ b/drivers/char/drm/drm_sman.c @@ -162,6 +162,7 @@ drm_sman_set_manager(drm_sman_t * sman, unsigned int manager, return 0; } +EXPORT_SYMBOL(drm_sman_set_manager); static drm_owner_item_t *drm_sman_get_owner_item(drm_sman_t * sman, unsigned long owner) diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c index b40ae438f531..ae2691942ddb 100644 --- a/drivers/char/drm/drm_vm.c +++ b/drivers/char/drm/drm_vm.c @@ -147,14 +147,14 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma, if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ if (!map) - return NOPAGE_OOM; /* Nothing allocated */ + return NOPAGE_SIGBUS; /* Nothing allocated */ offset = address - vma->vm_start; i = (unsigned long)map->handle + offset; page = (map->type == _DRM_CONSISTENT) ? virt_to_page((void *)i) : vmalloc_to_page((void *)i); if (!page) - return NOPAGE_OOM; + return NOPAGE_SIGBUS; get_page(page); DRM_DEBUG("shm_nopage 0x%lx\n", address); @@ -272,7 +272,7 @@ static __inline__ struct page *drm_do_vm_dma_nopage(struct vm_area_struct *vma, if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ if (!dma->pagelist) - return NOPAGE_OOM; /* Nothing allocated */ + return NOPAGE_SIGBUS; /* Nothing allocated */ offset = address - vma->vm_start; /* vm_[pg]off[set] should be 0 */ page_nr = offset >> PAGE_SHIFT; @@ -310,7 +310,7 @@ static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma, if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ if (!entry->pagelist) - return NOPAGE_OOM; /* Nothing allocated */ + return NOPAGE_SIGBUS; /* Nothing allocated */ offset = address - vma->vm_start; map_offset = map->offset - (unsigned long)dev->sg->virtual; diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c index 60c1695db300..806f9ce5f47b 100644 --- a/drivers/char/drm/via_dmablit.c +++ b/drivers/char/drm/via_dmablit.c @@ -500,9 +500,9 @@ via_dmablit_timer(unsigned long data) static void -via_dmablit_workqueue(void *data) +via_dmablit_workqueue(struct work_struct *work) { - drm_via_blitq_t *blitq = (drm_via_blitq_t *) data; + drm_via_blitq_t *blitq = container_of(work, drm_via_blitq_t, wq); drm_device_t *dev = blitq->dev; unsigned long irqsave; drm_via_sg_info_t *cur_sg; @@ -571,7 +571,7 @@ via_init_dmablit(drm_device_t *dev) DRM_INIT_WAITQUEUE(blitq->blit_queue + j); } DRM_INIT_WAITQUEUE(&blitq->busy_queue); - INIT_WORK(&blitq->wq, via_dmablit_workqueue, blitq); + INIT_WORK(&blitq->wq, via_dmablit_workqueue); init_timer(&blitq->poll_timer); blitq->poll_timer.function = &via_dmablit_timer; blitq->poll_timer.data = (unsigned long) blitq; diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 706733c0b36a..7c71eb779802 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -200,7 +200,7 @@ static int pc_ioctl(struct tty_struct *, struct file *, static int info_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long); static void pc_set_termios(struct tty_struct *, struct termios *); -static void do_softint(void *); +static void do_softint(struct work_struct *work); static void pc_stop(struct tty_struct *); static void pc_start(struct tty_struct *); static void pc_throttle(struct tty_struct * tty); @@ -1505,7 +1505,7 @@ static void post_fep_init(unsigned int crd) ch->brdchan = bc; ch->mailbox = gd; - INIT_WORK(&ch->tqueue, do_softint, ch); + INIT_WORK(&ch->tqueue, do_softint); ch->board = &boards[crd]; spin_lock_irqsave(&epca_lock, flags); @@ -2566,9 +2566,9 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios) /* --------------------- Begin do_softint ----------------------- */ -static void do_softint(void *private_) +static void do_softint(struct work_struct *work) { /* Begin do_softint */ - struct channel *ch = (struct channel *) private_; + struct channel *ch = container_of(work, struct channel, tqueue); /* Called in response to a modem change event */ if (ch && ch->magic == EPCA_MAGIC) { /* Begin EPCA_MAGIC */ struct tty_struct *tty = ch->tty; diff --git a/drivers/char/esp.c b/drivers/char/esp.c index 15a4ea896328..93b551962513 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -723,9 +723,10 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) * ------------------------------------------------------------------- */ -static void do_softint(void *private_) +static void do_softint(struct work_struct *work) { - struct esp_struct *info = (struct esp_struct *) private_; + struct esp_struct *info = + container_of(work, struct esp_struct, tqueue); struct tty_struct *tty; tty = info->tty; @@ -746,9 +747,10 @@ static void do_softint(void *private_) * do_serial_hangup() -> tty->hangup() -> esp_hangup() * */ -static void do_serial_hangup(void *private_) +static void do_serial_hangup(struct work_struct *work) { - struct esp_struct *info = (struct esp_struct *) private_; + struct esp_struct *info = + container_of(work, struct esp_struct, tqueue_hangup); struct tty_struct *tty; tty = info->tty; @@ -2501,8 +2503,8 @@ static int __init espserial_init(void) info->magic = ESP_MAGIC; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; - INIT_WORK(&info->tqueue, do_softint, info); - INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info); + INIT_WORK(&info->tqueue, do_softint); + INIT_WORK(&info->tqueue_hangup, do_serial_hangup); info->config.rx_timeout = rx_timeout; info->config.flow_on = flow_on; info->config.flow_off = flow_off; diff --git a/drivers/char/ftape/Kconfig b/drivers/char/ftape/Kconfig deleted file mode 100644 index 0d65189a7ae8..000000000000 --- 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 <file:Documentation/ftape.txt> 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 <file:Documentation/ftape.txt> 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 - <file:drivers/char/ftape/README.PCI>. - -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 <file:Documentation/ftape.txt> 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 <file:Documentation/ftape.txt> 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 <file:Documentation/ftape.txt> 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 0e67d2f8b7ec..000000000000 --- 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 18de159d36e0..000000000000 --- 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 03799dbc05a4..000000000000 --- 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, <forgot the exact date> ==== - -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 <fill in his name> 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 <asm/io.h> 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 <khp@dolphinics.no> -has resigned from maintaining ftape, and I, -Claus-Justus Heine <claus@momo.math.rwth-aachen.de>, -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 <khp@dolphinics.no> - -- 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 <dalecki@namu03.gwdg.de>: -- 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 <linux/modversions.h> 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 <khp@dolphinics.no> - -- 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=<n>' 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 <claus@willi.math.rwth-aachen.de> 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: - -<standard> 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 <asm/segment.h> 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 <bas@vimec.nl>. - 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 1fbd6c4019db..000000000000 --- 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 a032a0ee2a99..000000000000 --- 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 533feba47526..000000000000 --- 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 <linux/types.h> -#include <linux/string.h> - -/******************************************************************************/ -/* */ -/* 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 65ffc0be3df9..000000000000 --- 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 <linux/errno.h> -#include <linux/mm.h> -#include <linux/module.h> - -#include <linux/zftape.h> - -#include <asm/uaccess.h> - -#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 f200741e33bf..000000000000 --- 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 febab07ba427..000000000000 --- 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 9bc1cddade76..000000000000 --- 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 <asm/io.h> -#include <linux/ftape.h> -#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 da7b88bca889..000000000000 --- 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 bbcf918f056f..000000000000 --- 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 <linux/errno.h> -#include <linux/sched.h> -#include <linux/ioport.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/dma.h> -#include <asm/irq.h> - -#include <linux/ftape.h> -#include <linux/qic117.h> -#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 7ec3c72178bb..000000000000 --- 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 <linux/fdreg.h> - -#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 ad2bc733ae1b..000000000000 --- 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 <asm/io.h> -#include <asm/dma.h> - -#define volatile /* */ - -#include <linux/ftape.h> -#include <linux/qic117.h> -#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 065aa978942d..000000000000 --- 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 d1a301cc344f..000000000000 --- 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 <linux/string.h> - -#include <linux/ftape.h> -#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 ed45465af4d4..000000000000 --- 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 <linux/ftape.h> -#include <linux/ftape-header-segment.h> - -#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 c706ff162771..000000000000 --- 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 <linux/slab.h> -#include <linux/mm.h> -#include <linux/mman.h> -#include <asm/dma.h> - -#include <linux/ftape.h> -#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 eec99cee8f82..000000000000 --- 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 8e50bfd35a52..000000000000 --- 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 <linux/errno.h> -#include <linux/jiffies.h> -#include <asm/system.h> -#include <asm/io.h> -#if defined(__alpha__) -# include <asm/hwrpb.h> -#elif defined(__x86_64__) -# include <asm/msr.h> -# include <asm/timex.h> -#elif defined(__i386__) -# include <linux/timex.h> -#endif -#include <linux/ftape.h> -#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 0c7e75246c7d..000000000000 --- 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 5d7c1ce92d59..000000000000 --- 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 <linux/errno.h> -#include <linux/mm.h> -#include <linux/mman.h> - -#include <linux/ftape.h> -#include <linux/qic117.h> -#include <asm/uaccess.h> -#include <asm/io.h> - -/* 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 5f5e30bc3615..000000000000 --- 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 <linux/ioctl.h> -#include <linux/mtio.h> -#include <linux/ftape-vendors.h> - -#include "../lowlevel/ftape-rw.h" -#include <linux/ftape-header-segment.h> - -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 e5632f674bc8..000000000000 --- 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 <linux/ftape.h> - -#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., L0<L1<L2. - * - * The linear system that needs to be solved for the error magnitudes - * is A * b = s, where s is the known vector of syndromes, b is the - * vector of error magnitudes and A in the ORDER=3 case: - * - * A_3 = {{1/r^L[0], 1/r^L[1], 1/r^L[2]}, - * { 1, 1, 1}, - * { r^L[0], r^L[1], r^L[2]}} - */ -static inline int gfinv3(__u8 l0, - __u8 l1, - __u8 l2, - Matrix Ainv) -{ - __u8 det; - __u8 t20, t10, t21, t12, t01, t02; - int log_det; - - /* compute some intermediate results: */ - t20 = gfpow[l2 - l0]; /* t20 = r^l2/r^l0 */ - t10 = gfpow[l1 - l0]; /* t10 = r^l1/r^l0 */ - t21 = gfpow[l2 - l1]; /* t21 = r^l2/r^l1 */ - t12 = gfpow[l1 - l2 + 255]; /* t12 = r^l1/r^l2 */ - t01 = gfpow[l0 - l1 + 255]; /* t01 = r^l0/r^l1 */ - t02 = gfpow[l0 - l2 + 255]; /* t02 = r^l0/r^l2 */ - /* Calculate the determinant of matrix A_3^-1 (sometimes - * called the Vandermonde determinant): - */ - det = gfadd(t20, gfadd(t10, gfadd(t21, gfadd(t12, gfadd(t01, t02))))); - if (!det) { - TRACE_FUN(ft_t_any); - TRACE_ABORT(0, ft_t_err, - "Inversion failed (3 CRC errors, >0 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 4829146fe9a0..000000000000 --- 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<<N will be set in MARKED_BAD. - * The sectors should be read in from the disk and packed, as if the - * bad sectors were not there, and the segment just contained fewer - * sectors. READ_SECTORS is a bitmap of errors encountered while - * reading the data. These offsets are relative to the packed data. - * BLOCKS is a count of the sectors not marked bad. This is just to - * prevent having to count the zero bits in MARKED_BAD each time this - * is needed. DATA is the actual sector packed data from (or to) the - * tape. - */ - struct memory_segment { - SectorMap marked_bad; - SectorMap read_bad; - int blocks; - __u8 *data; - SectorMap corrected; - }; - -/* - * ecc.c defined global variables: - */ -#ifdef TEST -extern int ftape_ecc_tracing; -#endif - -/* - * ecc.c defined global functions: - */ -extern int ftape_ecc_correct_data(struct memory_segment *data); -extern int ftape_ecc_set_segment_parity(struct memory_segment *data); - -#endif /* _FTAPE_ECC_H_ */ diff --git a/drivers/char/ftape/lowlevel/ftape-format.c b/drivers/char/ftape/lowlevel/ftape-format.c deleted file mode 100644 index 5dd4c59a3f34..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-format.c +++ /dev/null @@ -1,344 +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-format.c,v $ - * $Revision: 1.2.4.1 $ - * $Date: 1997/11/14 16:05:39 $ - * - * This file contains the code to support formatting of floppy - * tape cartridges with the QIC-40/80/3010/3020 floppy-tape - * driver "ftape" for Linux. - */ - -#include <linux/string.h> -#include <linux/errno.h> - -#include <linux/ftape.h> -#include <linux/qic117.h> -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-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 f15161566643..000000000000 --- 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 4998132a81d1..000000000000 --- 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 <linux/module.h> -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/signal.h> -#include <linux/major.h> - -#include <linux/ftape.h> -#include <linux/init.h> -#include <linux/qic117.h> -#ifdef CONFIG_ZFTAPE -#include <linux/zftape.h> -#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 99a7b8ab086f..000000000000 --- 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 <linux/linkage.h> -#include <linux/signal.h> - -#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 259015aeff55..000000000000 --- 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 <linux/errno.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <asm/system.h> -#include <linux/ioctl.h> -#include <linux/mtio.h> -#include <linux/delay.h> - -#include <linux/ftape.h> -#include <linux/qic117.h> -#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 26a7baad8717..000000000000 --- 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 <linux/qic117.h> -#include <linux/ftape-vendors.h> - -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 e805b15e0a12..000000000000 --- 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 <linux/proc_fs.h> - -#include <linux/ftape.h> -#include <linux/init.h> -#include <linux/qic117.h> - -#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 264dfcc1d22d..000000000000 --- 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 <linux/proc_fs.h> - -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 d967d8cd86dc..000000000000 --- 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 <linux/string.h> -#include <linux/errno.h> -#include <linux/mm.h> - -#include <linux/ftape.h> -#include <linux/qic117.h> -#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 069f99f2a984..000000000000 --- 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 c0d6dc2cbfd3..000000000000 --- 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 <linux/string.h> -#include <linux/errno.h> - -#include <linux/ftape.h> -#include <linux/qic117.h> -#include "../lowlevel/ftape-tracing.h" -#include "../lowlevel/ftape-rw.h" -#include "../lowlevel/fdc-io.h" -#include "../lowlevel/ftape-init.h" -#include "../lowlevel/ftape-io.h" -#include "../lowlevel/ftape-ctl.h" -#include "../lowlevel/ftape-read.h" -#include "../lowlevel/ftape-ecc.h" -#include "../lowlevel/ftape-bsm.h" - -/* Global vars. - */ -int ft_nr_buffers; -buffer_struct *ft_buffer[FT_MAX_NR_BUFFERS]; -static volatile int ft_head; -static volatile int ft_tail; /* not volatile but need same type as head */ -int fdc_setup_error; -location_record ft_location = {-1, 0}; -volatile int ftape_tape_running; - -/* Local vars. - */ -static int overrun_count_offset; -static int inhibit_correction; - -/* maxmimal allowed overshoot when fast seeking - */ -#define OVERSHOOT_LIMIT 10 - -/* Increment cyclic buffer nr. - */ -buffer_struct *ftape_next_buffer(ft_buffer_queue_t pos) -{ - switch (pos) { - case ft_queue_head: - if (++ft_head >= ft_nr_buffers) { - ft_head = 0; - } - return ft_buffer[ft_head]; - case ft_queue_tail: - if (++ft_tail >= ft_nr_buffers) { - ft_tail = 0; - } - return ft_buffer[ft_tail]; - default: - return NULL; - } -} -int ftape_buffer_id(ft_buffer_queue_t pos) -{ - switch(pos) { - case ft_queue_head: return ft_head; - case ft_queue_tail: return ft_tail; - default: return -1; - } -} -buffer_struct *ftape_get_buffer(ft_buffer_queue_t pos) -{ - switch(pos) { - case ft_queue_head: return ft_buffer[ft_head]; - case ft_queue_tail: return ft_buffer[ft_tail]; - default: return NULL; - } -} -void ftape_reset_buffer(void) -{ - ft_head = ft_tail = 0; -} - -buffer_state_enum ftape_set_state(buffer_state_enum new_state) -{ - buffer_state_enum old_state = ft_driver_state; - - ft_driver_state = new_state; - return old_state; -} -/* Calculate Floppy Disk Controller and DMA parameters for a segment. - * head: selects buffer struct in array. - * offset: number of physical sectors to skip (including bad ones). - * count: number of physical sectors to handle (including bad ones). - */ -static int setup_segment(buffer_struct * buff, - int segment_id, - unsigned int sector_offset, - unsigned int sector_count, - int retry) -{ - SectorMap offset_mask; - SectorMap mask; - TRACE_FUN(ft_t_any); - - buff->segment_id = segment_id; - buff->sector_offset = sector_offset; - buff->remaining = sector_count; - buff->head = segment_id / ftape_segments_per_head; - buff->cyl = (segment_id % ftape_segments_per_head) / ftape_segments_per_cylinder; - buff->sect = (segment_id % ftape_segments_per_cylinder) * FT_SECTORS_PER_SEGMENT + 1; - buff->deleted = 0; - offset_mask = (1 << buff->sector_offset) - 1; - mask = ftape_get_bad_sector_entry(segment_id) & offset_mask; - while (mask) { - if (mask & 1) { - offset_mask >>= 1; /* don't count bad sector */ - } - mask >>= 1; - } - buff->data_offset = count_ones(offset_mask); /* good sectors to skip */ - buff->ptr = buff->address + buff->data_offset * FT_SECTOR_SIZE; - TRACE(ft_t_flow, "data offset = %d sectors", buff->data_offset); - 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 32f4feeb887c..000000000000 --- 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 <asm/unaligned.h> - -#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 678340acd0b7..000000000000 --- 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 <linux/string.h> -#include <linux/errno.h> -#include <linux/mm.h> - -#include <linux/ftape.h> -#include <linux/init.h> -#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 7fdc6567440b..000000000000 --- 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 <linux/ftape.h> -#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 2950810c7085..000000000000 --- 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 <linux/kernel.h> - -/* - * 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 45601ec801ee..000000000000 --- 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 <linux/string.h> -#include <linux/errno.h> -#include <linux/mm.h> - -#include <linux/ftape.h> -#include <linux/qic117.h> -#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 0e7f898b7af9..000000000000 --- 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 8e0dc4a07ca6..000000000000 --- 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 <linux/module.h> - -#include <linux/ftape.h> -#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 6d91c1f77c05..000000000000 --- 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 7ebce2ec7897..000000000000 --- 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 <linux/errno.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/delay.h> - -#include <linux/zftape.h> - -#include <linux/vmalloc.h> - -#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 798e3128c682..000000000000 --- 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 22ba0f5d00cf..000000000000 --- 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 <linux/errno.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/fcntl.h> - -#include <linux/zftape.h> - -#include <asm/uaccess.h> - -#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 8e6f2d7ac74e..000000000000 --- 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 <linux/ioctl.h> -#include <linux/mtio.h> - -#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 dcadcaee9ac1..000000000000 --- 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 <linux/string.h> -#include <linux/errno.h> - -#include <linux/zftape.h> - -#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 26568c26c518..000000000000 --- 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 <linux/ftape-header-segment.h> -#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 164a1aa77a2f..000000000000 --- 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 <linux/module.h> -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/signal.h> -#include <linux/major.h> -#include <linux/slab.h> -#ifdef CONFIG_KMOD -#include <linux/kmod.h> -#endif -#include <linux/fcntl.h> -#include <linux/smp_lock.h> - -#include <linux/zftape.h> -#include <linux/init.h> -#include <linux/device.h> - -#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 937e5d48c20e..000000000000 --- 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 <linux/ftape-header-segment.h> - -#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 214bf03dce68..000000000000 --- 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 <linux/errno.h> -#include <linux/mm.h> - -#include <linux/zftape.h> - -#include <asm/uaccess.h> - -#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 42941de0c23a..000000000000 --- 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 dab634686885..000000000000 --- 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 <linux/errno.h> -#include <linux/mm.h> - -#include <linux/zftape.h> -#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 1ceec22b60bd..000000000000 --- 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 ad7f8be6340b..000000000000 --- 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 <linux/errno.h> -#include <linux/mm.h> -#include <linux/slab.h> - -#include <linux/zftape.h> -#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 f31d196d1759..000000000000 --- 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 <linux/list.h> - -#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 94327b8c97b9..000000000000 --- 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 <linux/errno.h> -#include <linux/mm.h> - -#include <linux/zftape.h> - -#include <asm/uaccess.h> - -#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 ea887015b493..000000000000 --- 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 2db1401682df..000000000000 --- 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 <linux/module.h> - -#include <linux/zftape.h> - -#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); diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c index 817dc409ac20..23b25ada65ea 100644 --- a/drivers/char/genrtc.c +++ b/drivers/char/genrtc.c @@ -102,7 +102,7 @@ static void gen_rtc_interrupt(unsigned long arg); * Routine to poll RTC seconds field for change as often as possible, * after first RTC_UIE use timer to reduce polling */ -static void genrtc_troutine(void *data) +static void genrtc_troutine(struct work_struct *work) { unsigned int tmp = get_rtc_ss(); @@ -255,7 +255,7 @@ static inline int gen_set_rtc_irq_bit(unsigned char bit) irq_active = 1; stop_rtc_timers = 0; lostint = 0; - INIT_WORK(&genrtc_task, genrtc_troutine, NULL); + INIT_WORK(&genrtc_task, genrtc_troutine); oldsecs = get_rtc_ss(); init_timer(&timer_task); diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 091a11cd878c..20dc3be5ecfc 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -21,6 +21,7 @@ #include <linux/fcntl.h> #include <linux/init.h> #include <linux/poll.h> +#include <linux/mm.h> #include <linux/proc_fs.h> #include <linux/spinlock.h> #include <linux/sysctl.h> diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 9902ffad3b12..cc2cd46bedc6 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -38,6 +38,7 @@ #include <linux/sched.h> #include <linux/spinlock.h> #include <linux/delay.h> +#include <linux/freezer.h> #include <asm/uaccess.h> diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 8728255c9463..d090622f1dea 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -337,11 +337,6 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp); static void hvcs_close(struct tty_struct *tty, struct file *filp); static void hvcs_hangup(struct tty_struct * tty); -static void hvcs_create_device_attrs(struct hvcs_struct *hvcsd); -static void hvcs_remove_device_attrs(struct vio_dev *vdev); -static void hvcs_create_driver_attrs(void); -static void hvcs_remove_driver_attrs(void); - static int __devinit hvcs_probe(struct vio_dev *dev, const struct vio_device_id *id); static int __devexit hvcs_remove(struct vio_dev *dev); @@ -353,6 +348,172 @@ static void __exit hvcs_module_exit(void); #define HVCS_TRY_WRITE 0x00000004 #define HVCS_READ_MASK (HVCS_SCHED_READ | HVCS_QUICK_READ) +static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod) +{ + return viod->dev.driver_data; +} +/* The sysfs interface for the driver and devices */ + +static ssize_t hvcs_partner_vtys_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct vio_dev *viod = to_vio_dev(dev); + struct hvcs_struct *hvcsd = from_vio_dev(viod); + unsigned long flags; + int retval; + + spin_lock_irqsave(&hvcsd->lock, flags); + retval = sprintf(buf, "%X\n", hvcsd->p_unit_address); + spin_unlock_irqrestore(&hvcsd->lock, flags); + return retval; +} +static DEVICE_ATTR(partner_vtys, S_IRUGO, hvcs_partner_vtys_show, NULL); + +static ssize_t hvcs_partner_clcs_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct vio_dev *viod = to_vio_dev(dev); + struct hvcs_struct *hvcsd = from_vio_dev(viod); + unsigned long flags; + int retval; + + spin_lock_irqsave(&hvcsd->lock, flags); + retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]); + spin_unlock_irqrestore(&hvcsd->lock, flags); + return retval; +} +static DEVICE_ATTR(partner_clcs, S_IRUGO, hvcs_partner_clcs_show, NULL); + +static ssize_t hvcs_current_vty_store(struct device *dev, struct device_attribute *attr, const char * buf, + size_t count) +{ + /* + * Don't need this feature at the present time because firmware doesn't + * yet support multiple partners. + */ + printk(KERN_INFO "HVCS: Denied current_vty change: -EPERM.\n"); + return -EPERM; +} + +static ssize_t hvcs_current_vty_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct vio_dev *viod = to_vio_dev(dev); + struct hvcs_struct *hvcsd = from_vio_dev(viod); + unsigned long flags; + int retval; + + spin_lock_irqsave(&hvcsd->lock, flags); + retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]); + spin_unlock_irqrestore(&hvcsd->lock, flags); + return retval; +} + +static DEVICE_ATTR(current_vty, + S_IRUGO | S_IWUSR, hvcs_current_vty_show, hvcs_current_vty_store); + +static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct vio_dev *viod = to_vio_dev(dev); + struct hvcs_struct *hvcsd = from_vio_dev(viod); + unsigned long flags; + + /* writing a '0' to this sysfs entry will result in the disconnect. */ + if (simple_strtol(buf, NULL, 0) != 0) + return -EINVAL; + + spin_lock_irqsave(&hvcsd->lock, flags); + + if (hvcsd->open_count > 0) { + spin_unlock_irqrestore(&hvcsd->lock, flags); + printk(KERN_INFO "HVCS: vterm state unchanged. " + "The hvcs device node is still in use.\n"); + return -EPERM; + } + + if (hvcsd->connected == 0) { + spin_unlock_irqrestore(&hvcsd->lock, flags); + printk(KERN_INFO "HVCS: vterm state unchanged. The" + " vty-server is not connected to a vty.\n"); + return -EPERM; + } + + hvcs_partner_free(hvcsd); + printk(KERN_INFO "HVCS: Closed vty-server@%X and" + " partner vty@%X:%d connection.\n", + hvcsd->vdev->unit_address, + hvcsd->p_unit_address, + (uint32_t)hvcsd->p_partition_ID); + + spin_unlock_irqrestore(&hvcsd->lock, flags); + return count; +} + +static ssize_t hvcs_vterm_state_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct vio_dev *viod = to_vio_dev(dev); + struct hvcs_struct *hvcsd = from_vio_dev(viod); + unsigned long flags; + int retval; + + spin_lock_irqsave(&hvcsd->lock, flags); + retval = sprintf(buf, "%d\n", hvcsd->connected); + spin_unlock_irqrestore(&hvcsd->lock, flags); + return retval; +} +static DEVICE_ATTR(vterm_state, S_IRUGO | S_IWUSR, + hvcs_vterm_state_show, hvcs_vterm_state_store); + +static ssize_t hvcs_index_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct vio_dev *viod = to_vio_dev(dev); + struct hvcs_struct *hvcsd = from_vio_dev(viod); + unsigned long flags; + int retval; + + spin_lock_irqsave(&hvcsd->lock, flags); + retval = sprintf(buf, "%d\n", hvcsd->index); + spin_unlock_irqrestore(&hvcsd->lock, flags); + return retval; +} + +static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL); + +static struct attribute *hvcs_attrs[] = { + &dev_attr_partner_vtys.attr, + &dev_attr_partner_clcs.attr, + &dev_attr_current_vty.attr, + &dev_attr_vterm_state.attr, + &dev_attr_index.attr, + NULL, +}; + +static struct attribute_group hvcs_attr_group = { + .attrs = hvcs_attrs, +}; + +static ssize_t hvcs_rescan_show(struct device_driver *ddp, char *buf) +{ + /* A 1 means it is updating, a 0 means it is done updating */ + return snprintf(buf, PAGE_SIZE, "%d\n", hvcs_rescan_status); +} + +static ssize_t hvcs_rescan_store(struct device_driver *ddp, const char * buf, + size_t count) +{ + if ((simple_strtol(buf, NULL, 0) != 1) + && (hvcs_rescan_status != 0)) + return -EINVAL; + + hvcs_rescan_status = 1; + printk(KERN_INFO "HVCS: rescanning partner info for all" + " vty-servers.\n"); + hvcs_rescan_devices_list(); + hvcs_rescan_status = 0; + return count; +} + +static DRIVER_ATTR(rescan, + S_IRUGO | S_IWUSR, hvcs_rescan_show, hvcs_rescan_store); + static void hvcs_kick(void) { hvcs_kicked = 1; @@ -575,7 +736,7 @@ static void destroy_hvcs_struct(struct kobject *kobj) spin_unlock_irqrestore(&hvcsd->lock, flags); spin_unlock(&hvcs_structs_lock); - hvcs_remove_device_attrs(vdev); + sysfs_remove_group(&vdev->dev.kobj, &hvcs_attr_group); kfree(hvcsd); } @@ -608,6 +769,7 @@ static int __devinit hvcs_probe( { struct hvcs_struct *hvcsd; int index; + int retval; if (!dev || !id) { printk(KERN_ERR "HVCS: probed with invalid parameter.\n"); @@ -658,14 +820,16 @@ static int __devinit hvcs_probe( * the hvcs_struct has been added to the devices list then the user app * will get -ENODEV. */ - spin_lock(&hvcs_structs_lock); - list_add_tail(&(hvcsd->next), &hvcs_structs); - spin_unlock(&hvcs_structs_lock); - hvcs_create_device_attrs(hvcsd); + retval = sysfs_create_group(&dev->dev.kobj, &hvcs_attr_group); + if (retval) { + printk(KERN_ERR "HVCS: Can't create sysfs attrs for vty-server@%X\n", + hvcsd->vdev->unit_address); + return retval; + } printk(KERN_INFO "HVCS: vty-server@%X added to the vio bus.\n", dev->unit_address); @@ -1354,8 +1518,10 @@ static int __init hvcs_module_init(void) if (!hvcs_tty_driver) return -ENOMEM; - if (hvcs_alloc_index_list(num_ttys_to_alloc)) - return -ENOMEM; + if (hvcs_alloc_index_list(num_ttys_to_alloc)) { + rc = -ENOMEM; + goto index_fail; + } hvcs_tty_driver->owner = THIS_MODULE; @@ -1385,41 +1551,57 @@ static int __init hvcs_module_init(void) * dynamically assigned major and minor numbers for our devices. */ if (tty_register_driver(hvcs_tty_driver)) { - printk(KERN_ERR "HVCS: registration " - " as a tty driver failed.\n"); - hvcs_free_index_list(); - put_tty_driver(hvcs_tty_driver); - return -EIO; + printk(KERN_ERR "HVCS: registration as a tty driver failed.\n"); + rc = -EIO; + goto register_fail; } hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!hvcs_pi_buff) { - tty_unregister_driver(hvcs_tty_driver); - hvcs_free_index_list(); - put_tty_driver(hvcs_tty_driver); - return -ENOMEM; + rc = -ENOMEM; + goto buff_alloc_fail; } hvcs_task = kthread_run(khvcsd, NULL, "khvcsd"); if (IS_ERR(hvcs_task)) { printk(KERN_ERR "HVCS: khvcsd creation failed. Driver not loaded.\n"); - kfree(hvcs_pi_buff); - tty_unregister_driver(hvcs_tty_driver); - hvcs_free_index_list(); - put_tty_driver(hvcs_tty_driver); - return -EIO; + rc = -EIO; + goto kthread_fail; } rc = vio_register_driver(&hvcs_vio_driver); + if (rc) { + printk(KERN_ERR "HVCS: can't register vio driver\n"); + goto vio_fail; + } /* * This needs to be done AFTER the vio_register_driver() call or else * the kobjects won't be initialized properly. */ - hvcs_create_driver_attrs(); + rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan); + if (rc) { + printk(KERN_ERR "HVCS: sysfs attr create failed\n"); + goto attr_fail; + } printk(KERN_INFO "HVCS: driver module inserted.\n"); + return 0; + +attr_fail: + vio_unregister_driver(&hvcs_vio_driver); +vio_fail: + kthread_stop(hvcs_task); +kthread_fail: + kfree(hvcs_pi_buff); +buff_alloc_fail: + tty_unregister_driver(hvcs_tty_driver); +register_fail: + hvcs_free_index_list(); +index_fail: + put_tty_driver(hvcs_tty_driver); + hvcs_tty_driver = NULL; return rc; } @@ -1441,7 +1623,7 @@ static void __exit hvcs_module_exit(void) hvcs_pi_buff = NULL; spin_unlock(&hvcs_pi_lock); - hvcs_remove_driver_attrs(); + driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan); vio_unregister_driver(&hvcs_vio_driver); @@ -1456,191 +1638,3 @@ static void __exit hvcs_module_exit(void) module_init(hvcs_module_init); module_exit(hvcs_module_exit); - -static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod) -{ - return viod->dev.driver_data; -} -/* The sysfs interface for the driver and devices */ - -static ssize_t hvcs_partner_vtys_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct vio_dev *viod = to_vio_dev(dev); - struct hvcs_struct *hvcsd = from_vio_dev(viod); - unsigned long flags; - int retval; - - spin_lock_irqsave(&hvcsd->lock, flags); - retval = sprintf(buf, "%X\n", hvcsd->p_unit_address); - spin_unlock_irqrestore(&hvcsd->lock, flags); - return retval; -} -static DEVICE_ATTR(partner_vtys, S_IRUGO, hvcs_partner_vtys_show, NULL); - -static ssize_t hvcs_partner_clcs_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct vio_dev *viod = to_vio_dev(dev); - struct hvcs_struct *hvcsd = from_vio_dev(viod); - unsigned long flags; - int retval; - - spin_lock_irqsave(&hvcsd->lock, flags); - retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]); - spin_unlock_irqrestore(&hvcsd->lock, flags); - return retval; -} -static DEVICE_ATTR(partner_clcs, S_IRUGO, hvcs_partner_clcs_show, NULL); - -static ssize_t hvcs_current_vty_store(struct device *dev, struct device_attribute *attr, const char * buf, - size_t count) -{ - /* - * Don't need this feature at the present time because firmware doesn't - * yet support multiple partners. - */ - printk(KERN_INFO "HVCS: Denied current_vty change: -EPERM.\n"); - return -EPERM; -} - -static ssize_t hvcs_current_vty_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct vio_dev *viod = to_vio_dev(dev); - struct hvcs_struct *hvcsd = from_vio_dev(viod); - unsigned long flags; - int retval; - - spin_lock_irqsave(&hvcsd->lock, flags); - retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]); - spin_unlock_irqrestore(&hvcsd->lock, flags); - return retval; -} - -static DEVICE_ATTR(current_vty, - S_IRUGO | S_IWUSR, hvcs_current_vty_show, hvcs_current_vty_store); - -static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct vio_dev *viod = to_vio_dev(dev); - struct hvcs_struct *hvcsd = from_vio_dev(viod); - unsigned long flags; - - /* writing a '0' to this sysfs entry will result in the disconnect. */ - if (simple_strtol(buf, NULL, 0) != 0) - return -EINVAL; - - spin_lock_irqsave(&hvcsd->lock, flags); - - if (hvcsd->open_count > 0) { - spin_unlock_irqrestore(&hvcsd->lock, flags); - printk(KERN_INFO "HVCS: vterm state unchanged. " - "The hvcs device node is still in use.\n"); - return -EPERM; - } - - if (hvcsd->connected == 0) { - spin_unlock_irqrestore(&hvcsd->lock, flags); - printk(KERN_INFO "HVCS: vterm state unchanged. The" - " vty-server is not connected to a vty.\n"); - return -EPERM; - } - - hvcs_partner_free(hvcsd); - printk(KERN_INFO "HVCS: Closed vty-server@%X and" - " partner vty@%X:%d connection.\n", - hvcsd->vdev->unit_address, - hvcsd->p_unit_address, - (uint32_t)hvcsd->p_partition_ID); - - spin_unlock_irqrestore(&hvcsd->lock, flags); - return count; -} - -static ssize_t hvcs_vterm_state_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct vio_dev *viod = to_vio_dev(dev); - struct hvcs_struct *hvcsd = from_vio_dev(viod); - unsigned long flags; - int retval; - - spin_lock_irqsave(&hvcsd->lock, flags); - retval = sprintf(buf, "%d\n", hvcsd->connected); - spin_unlock_irqrestore(&hvcsd->lock, flags); - return retval; -} -static DEVICE_ATTR(vterm_state, S_IRUGO | S_IWUSR, - hvcs_vterm_state_show, hvcs_vterm_state_store); - -static ssize_t hvcs_index_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct vio_dev *viod = to_vio_dev(dev); - struct hvcs_struct *hvcsd = from_vio_dev(viod); - unsigned long flags; - int retval; - - spin_lock_irqsave(&hvcsd->lock, flags); - retval = sprintf(buf, "%d\n", hvcsd->index); - spin_unlock_irqrestore(&hvcsd->lock, flags); - return retval; -} - -static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL); - -static struct attribute *hvcs_attrs[] = { - &dev_attr_partner_vtys.attr, - &dev_attr_partner_clcs.attr, - &dev_attr_current_vty.attr, - &dev_attr_vterm_state.attr, - &dev_attr_index.attr, - NULL, -}; - -static struct attribute_group hvcs_attr_group = { - .attrs = hvcs_attrs, -}; - -static void hvcs_create_device_attrs(struct hvcs_struct *hvcsd) -{ - struct vio_dev *vdev = hvcsd->vdev; - sysfs_create_group(&vdev->dev.kobj, &hvcs_attr_group); -} - -static void hvcs_remove_device_attrs(struct vio_dev *vdev) -{ - sysfs_remove_group(&vdev->dev.kobj, &hvcs_attr_group); -} - -static ssize_t hvcs_rescan_show(struct device_driver *ddp, char *buf) -{ - /* A 1 means it is updating, a 0 means it is done updating */ - return snprintf(buf, PAGE_SIZE, "%d\n", hvcs_rescan_status); -} - -static ssize_t hvcs_rescan_store(struct device_driver *ddp, const char * buf, - size_t count) -{ - if ((simple_strtol(buf, NULL, 0) != 1) - && (hvcs_rescan_status != 0)) - return -EINVAL; - - hvcs_rescan_status = 1; - printk(KERN_INFO "HVCS: rescanning partner info for all" - " vty-servers.\n"); - hvcs_rescan_devices_list(); - hvcs_rescan_status = 0; - return count; -} -static DRIVER_ATTR(rescan, - S_IRUGO | S_IWUSR, hvcs_rescan_show, hvcs_rescan_store); - -static void hvcs_create_driver_attrs(void) -{ - struct device_driver *driverfs = &(hvcs_vio_driver.driver); - driver_create_file(driverfs, &driver_attr_rescan); -} - -static void hvcs_remove_driver_attrs(void) -{ - struct device_driver *driverfs = &(hvcs_vio_driver.driver); - driver_remove_file(driverfs, &driver_attr_rescan); -} diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index 2cf63e7305a3..82a41d5b4ed0 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -69,7 +69,7 @@ #define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) struct hvsi_struct { - struct work_struct writer; + struct delayed_work writer; struct work_struct handshaker; wait_queue_head_t emptyq; /* woken when outbuf is emptied */ wait_queue_head_t stateq; /* woken when HVSI state changes */ @@ -744,9 +744,10 @@ static int hvsi_handshake(struct hvsi_struct *hp) return 0; } -static void hvsi_handshaker(void *arg) +static void hvsi_handshaker(struct work_struct *work) { - struct hvsi_struct *hp = (struct hvsi_struct *)arg; + struct hvsi_struct *hp = + container_of(work, struct hvsi_struct, handshaker); if (hvsi_handshake(hp) >= 0) return; @@ -951,9 +952,10 @@ static void hvsi_push(struct hvsi_struct *hp) } /* hvsi_write_worker will keep rescheduling itself until outbuf is empty */ -static void hvsi_write_worker(void *arg) +static void hvsi_write_worker(struct work_struct *work) { - struct hvsi_struct *hp = (struct hvsi_struct *)arg; + struct hvsi_struct *hp = + container_of(work, struct hvsi_struct, writer.work); unsigned long flags; #ifdef DEBUG static long start_j = 0; @@ -1287,8 +1289,8 @@ static int __init hvsi_console_init(void) } hp = &hvsi_ports[hvsi_count]; - INIT_WORK(&hp->writer, hvsi_write_worker, hp); - INIT_WORK(&hp->handshaker, hvsi_handshaker, hp); + INIT_DELAYED_WORK(&hp->writer, hvsi_write_worker); + INIT_WORK(&hp->handshaker, hvsi_handshaker); init_waitqueue_head(&hp->emptyq); init_waitqueue_head(&hp->stateq); spin_lock_init(&hp->lock); diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 9f7635f75178..5f3acd8e64b8 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -3,17 +3,20 @@ # config HW_RANDOM - bool "Hardware Random Number Generator Core support" - default y + tristate "Hardware Random Number Generator Core support" + default m ---help--- Hardware Random Number Generator Core infrastructure. + To compile this driver as a module, choose M here: the + module will be called rng-core. + If unsure, say Y. config HW_RANDOM_INTEL tristate "Intel HW Random Number Generator support" depends on HW_RANDOM && (X86 || IA64) && PCI - default y + default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number Generator hardware found on Intel i8xx-based motherboards. @@ -26,7 +29,7 @@ config HW_RANDOM_INTEL config HW_RANDOM_AMD tristate "AMD HW Random Number Generator support" depends on HW_RANDOM && X86 && PCI - default y + default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number Generator hardware found on AMD 76x-based motherboards. @@ -39,7 +42,7 @@ config HW_RANDOM_AMD config HW_RANDOM_GEODE tristate "AMD Geode HW Random Number Generator support" depends on HW_RANDOM && X86 && PCI - default y + default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number Generator hardware found on the AMD Geode LX. @@ -52,7 +55,7 @@ config HW_RANDOM_GEODE config HW_RANDOM_VIA tristate "VIA HW Random Number Generator support" depends on HW_RANDOM && X86_32 - default y + default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number Generator hardware found on VIA based motherboards. @@ -65,7 +68,7 @@ config HW_RANDOM_VIA config HW_RANDOM_IXP4XX tristate "Intel IXP4xx NPU HW Random Number Generator support" depends on HW_RANDOM && ARCH_IXP4XX - default y + default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number Generator hardware found on the Intel IXP4xx NPU. @@ -78,7 +81,7 @@ config HW_RANDOM_IXP4XX config HW_RANDOM_OMAP tristate "OMAP Random Number Generator support" depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP24XX) - default y + default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number Generator hardware found on OMAP16xx and OMAP24xx multimedia diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index e263ae96f940..c41fa19454e3 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -2,7 +2,8 @@ # Makefile for HW Random Number Generator (RNG) device drivers. # -obj-$(CONFIG_HW_RANDOM) += core.o +obj-$(CONFIG_HW_RANDOM) += rng-core.o +rng-core-y := core.o obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 154a81d328c1..26a860adcb38 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -36,6 +36,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> +#include <linux/sched.h> #include <linux/init.h> #include <linux/miscdevice.h> #include <linux/delay.h> @@ -162,7 +163,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 +194,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 +213,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 +238,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 +260,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/ip2/i2cmd.h b/drivers/char/ip2/i2cmd.h index baa4e721b758..29277ec6b8ed 100644 --- a/drivers/char/ip2/i2cmd.h +++ b/drivers/char/ip2/i2cmd.h @@ -367,11 +367,6 @@ static UCHAR cc02[]; #define CSE_NULL 3 // Replace with a null #define CSE_MARK 4 // Replace with a 3-character sequence (as Unix) -#define CMD_SET_REPLACEMENT(arg,ch) \ - (((cmdSyntaxPtr)(ct36a))->cmd[1] = (arg), \ - (((cmdSyntaxPtr)(ct36a))->cmd[2] = (ch), \ - (cmdSyntaxPtr)(ct36a)) - #define CSE_REPLACE 0x8 // Replace the errored character with the // replacement character defined here diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c index 54d93f0345e8..78045767ec33 100644 --- a/drivers/char/ip2/i2lib.c +++ b/drivers/char/ip2/i2lib.c @@ -84,8 +84,8 @@ static void iiSendPendingMail(i2eBordStrPtr); static void serviceOutgoingFifo(i2eBordStrPtr); // Functions defined in ip2.c as part of interrupt handling -static void do_input(void *); -static void do_status(void *); +static void do_input(struct work_struct *); +static void do_status(struct work_struct *); //*************** //* Debug Data * @@ -331,8 +331,8 @@ i2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh) pCh->ClosingWaitTime = 30*HZ; // Initialize task queue objects - INIT_WORK(&pCh->tqueue_input, do_input, pCh); - INIT_WORK(&pCh->tqueue_status, do_status, pCh); + INIT_WORK(&pCh->tqueue_input, do_input); + INIT_WORK(&pCh->tqueue_status, do_status); #ifdef IP2DEBUG_TRACE pCh->trace = ip2trace; @@ -1016,7 +1016,6 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count) unsigned short channel; unsigned short stuffIndex; unsigned long flags; - int rc = 0; int bailout = 10; @@ -1573,7 +1572,7 @@ i2StripFifo(i2eBordStrPtr pB) #ifdef USE_IQ schedule_work(&pCh->tqueue_input); #else - do_input(pCh); + do_input(&pCh->tqueue_input); #endif // Note we do not need to maintain any flow-control credits at this @@ -1810,7 +1809,7 @@ i2StripFifo(i2eBordStrPtr pB) #ifdef USE_IQ schedule_work(&pCh->tqueue_status); #else - do_status(pCh); + do_status(&pCh->tqueue_status); #endif } } diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index a3f32d46d2f8..cda2459c1d60 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -189,12 +189,12 @@ static int ip2_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); static void set_irq(int, int); -static void ip2_interrupt_bh(i2eBordStrPtr pB); +static void ip2_interrupt_bh(struct work_struct *work); static irqreturn_t ip2_interrupt(int irq, void *dev_id); static void ip2_poll(unsigned long arg); static inline void service_all_boards(void); -static void do_input(void *p); -static void do_status(void *p); +static void do_input(struct work_struct *); +static void do_status(struct work_struct *); static void ip2_wait_until_sent(PTTY,int); @@ -918,7 +918,7 @@ ip2_init_board( int boardnum ) pCh++; } ex_exit: - INIT_WORK(&pB->tqueue_interrupt, (void(*)(void*)) ip2_interrupt_bh, pB); + INIT_WORK(&pB->tqueue_interrupt, ip2_interrupt_bh); return; err_release_region: @@ -1125,8 +1125,8 @@ service_all_boards(void) /******************************************************************************/ -/* Function: ip2_interrupt_bh(pB) */ -/* Parameters: pB - pointer to the board structure */ +/* Function: ip2_interrupt_bh(work) */ +/* Parameters: work - pointer to the board structure */ /* Returns: Nothing */ /* */ /* Description: */ @@ -1135,8 +1135,9 @@ service_all_boards(void) /* */ /******************************************************************************/ static void -ip2_interrupt_bh(i2eBordStrPtr pB) +ip2_interrupt_bh(struct work_struct *work) { + i2eBordStrPtr pB = container_of(work, i2eBordStr, tqueue_interrupt); // pB better well be set or we have a problem! We can only get // here from the IMMEDIATE queue. Here, we process the boards. // Checking pB doesn't cost much and it saves us from the sanity checkers. @@ -1245,9 +1246,9 @@ ip2_poll(unsigned long arg) ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 ); } -static void do_input(void *p) +static void do_input(struct work_struct *work) { - i2ChanStrPtr pCh = p; + i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_input); unsigned long flags; ip2trace(CHANN, ITRC_INPUT, 21, 0 ); @@ -1279,9 +1280,9 @@ static inline void isig(int sig, struct tty_struct *tty, int flush) } } -static void do_status(void *p) +static void do_status(struct work_struct *work) { - i2ChanStrPtr pCh = p; + i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_status); int status; status = i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) ); diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index 0030cd8e2e95..6c59baa887a8 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -33,11 +33,13 @@ #include <linux/ipmi_msgdefs.h> /* for completion codes */ #include "ipmi_si_sm.h" -static int bt_debug = 0x00; /* Production value 0, see following flags */ +#define BT_DEBUG_OFF 0 /* Used in production */ +#define BT_DEBUG_ENABLE 1 /* Generic messages */ +#define BT_DEBUG_MSG 2 /* Prints all request/response buffers */ +#define BT_DEBUG_STATES 4 /* Verbose look at state changes */ + +static int bt_debug = BT_DEBUG_OFF; -#define BT_DEBUG_ENABLE 1 -#define BT_DEBUG_MSG 2 -#define BT_DEBUG_STATES 4 module_param(bt_debug, int, 0644); MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); @@ -47,38 +49,54 @@ MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); Since the Open IPMI architecture is single-message oriented at this stage, the queue depth of BT is of no concern. */ -#define BT_NORMAL_TIMEOUT 5000000 /* seconds in microseconds */ -#define BT_RETRY_LIMIT 2 -#define BT_RESET_DELAY 6000000 /* 6 seconds after warm reset */ +#define BT_NORMAL_TIMEOUT 5 /* seconds */ +#define BT_NORMAL_RETRY_LIMIT 2 +#define BT_RESET_DELAY 6 /* seconds after warm reset */ + +/* States are written in chronological order and usually cover + multiple rows of the state table discussion in the IPMI spec. */ enum bt_states { - BT_STATE_IDLE, + BT_STATE_IDLE = 0, /* Order is critical in this list */ BT_STATE_XACTION_START, BT_STATE_WRITE_BYTES, - BT_STATE_WRITE_END, BT_STATE_WRITE_CONSUME, - BT_STATE_B2H_WAIT, - BT_STATE_READ_END, - BT_STATE_RESET1, /* These must come last */ + BT_STATE_READ_WAIT, + BT_STATE_CLEAR_B2H, + BT_STATE_READ_BYTES, + BT_STATE_RESET1, /* These must come last */ BT_STATE_RESET2, BT_STATE_RESET3, BT_STATE_RESTART, - BT_STATE_HOSED + BT_STATE_PRINTME, + BT_STATE_CAPABILITIES_BEGIN, + BT_STATE_CAPABILITIES_END, + BT_STATE_LONG_BUSY /* BT doesn't get hosed :-) */ }; +/* Macros seen at the end of state "case" blocks. They help with legibility + and debugging. */ + +#define BT_STATE_CHANGE(X,Y) { bt->state = X; return Y; } + +#define BT_SI_SM_RETURN(Y) { last_printed = BT_STATE_PRINTME; return Y; } + struct si_sm_data { enum bt_states state; - enum bt_states last_state; /* assist printing and resets */ unsigned char seq; /* BT sequence number */ struct si_sm_io *io; - unsigned char write_data[IPMI_MAX_MSG_LENGTH]; - int write_count; - unsigned char read_data[IPMI_MAX_MSG_LENGTH]; - int read_count; - int truncated; - long timeout; - unsigned int error_retries; /* end of "common" fields */ + unsigned char write_data[IPMI_MAX_MSG_LENGTH]; + int write_count; + unsigned char read_data[IPMI_MAX_MSG_LENGTH]; + int read_count; + int truncated; + long timeout; /* microseconds countdown */ + int error_retries; /* end of "common" fields */ int nonzero_status; /* hung BMCs stay all 0 */ + enum bt_states complete; /* to divert the state machine */ + int BT_CAP_outreqs; + long BT_CAP_req2rsp; + int BT_CAP_retries; /* Recommended retries */ }; #define BT_CLR_WR_PTR 0x01 /* See IPMI 1.5 table 11.6.4 */ @@ -111,86 +129,118 @@ struct si_sm_data { static char *state2txt(unsigned char state) { switch (state) { - case BT_STATE_IDLE: return("IDLE"); - case BT_STATE_XACTION_START: return("XACTION"); - case BT_STATE_WRITE_BYTES: return("WR_BYTES"); - case BT_STATE_WRITE_END: return("WR_END"); - case BT_STATE_WRITE_CONSUME: return("WR_CONSUME"); - case BT_STATE_B2H_WAIT: return("B2H_WAIT"); - case BT_STATE_READ_END: return("RD_END"); - case BT_STATE_RESET1: return("RESET1"); - case BT_STATE_RESET2: return("RESET2"); - case BT_STATE_RESET3: return("RESET3"); - case BT_STATE_RESTART: return("RESTART"); - case BT_STATE_HOSED: return("HOSED"); + case BT_STATE_IDLE: return("IDLE"); + case BT_STATE_XACTION_START: return("XACTION"); + case BT_STATE_WRITE_BYTES: return("WR_BYTES"); + case BT_STATE_WRITE_CONSUME: return("WR_CONSUME"); + case BT_STATE_READ_WAIT: return("RD_WAIT"); + case BT_STATE_CLEAR_B2H: return("CLEAR_B2H"); + case BT_STATE_READ_BYTES: return("RD_BYTES"); + case BT_STATE_RESET1: return("RESET1"); + case BT_STATE_RESET2: return("RESET2"); + case BT_STATE_RESET3: return("RESET3"); + case BT_STATE_RESTART: return("RESTART"); + case BT_STATE_LONG_BUSY: return("LONG_BUSY"); + case BT_STATE_CAPABILITIES_BEGIN: return("CAP_BEGIN"); + case BT_STATE_CAPABILITIES_END: return("CAP_END"); } return("BAD STATE"); } #define STATE2TXT state2txt(bt->state) -static char *status2txt(unsigned char status, char *buf) +static char *status2txt(unsigned char status) { + /* + * This cannot be called by two threads at the same time and + * the buffer is always consumed immediately, so the static is + * safe to use. + */ + static char buf[40]; + strcpy(buf, "[ "); - if (status & BT_B_BUSY) strcat(buf, "B_BUSY "); - if (status & BT_H_BUSY) strcat(buf, "H_BUSY "); - if (status & BT_OEM0) strcat(buf, "OEM0 "); - if (status & BT_SMS_ATN) strcat(buf, "SMS "); - if (status & BT_B2H_ATN) strcat(buf, "B2H "); - if (status & BT_H2B_ATN) strcat(buf, "H2B "); + if (status & BT_B_BUSY) + strcat(buf, "B_BUSY "); + if (status & BT_H_BUSY) + strcat(buf, "H_BUSY "); + if (status & BT_OEM0) + strcat(buf, "OEM0 "); + if (status & BT_SMS_ATN) + strcat(buf, "SMS "); + if (status & BT_B2H_ATN) + strcat(buf, "B2H "); + if (status & BT_H2B_ATN) + strcat(buf, "H2B "); strcat(buf, "]"); return buf; } -#define STATUS2TXT(buf) status2txt(status, buf) +#define STATUS2TXT status2txt(status) + +/* called externally at insmod time, and internally on cleanup */ -/* This will be called from within this module on a hosed condition */ -#define FIRST_SEQ 0 static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io) { - bt->state = BT_STATE_IDLE; - bt->last_state = BT_STATE_IDLE; - bt->seq = FIRST_SEQ; - bt->io = io; - bt->write_count = 0; - bt->read_count = 0; - bt->error_retries = 0; - bt->nonzero_status = 0; - bt->truncated = 0; - bt->timeout = BT_NORMAL_TIMEOUT; + memset(bt, 0, sizeof(struct si_sm_data)); + if (bt->io != io) { /* external: one-time only things */ + bt->io = io; + bt->seq = 0; + } + bt->state = BT_STATE_IDLE; /* start here */ + bt->complete = BT_STATE_IDLE; /* end here */ + bt->BT_CAP_req2rsp = BT_NORMAL_TIMEOUT * 1000000; + bt->BT_CAP_retries = BT_NORMAL_RETRY_LIMIT; + /* BT_CAP_outreqs == zero is a flag to read BT Capabilities */ return 3; /* We claim 3 bytes of space; ought to check SPMI table */ } +/* Jam a completion code (probably an error) into a response */ + +static void force_result(struct si_sm_data *bt, unsigned char completion_code) +{ + bt->read_data[0] = 4; /* # following bytes */ + bt->read_data[1] = bt->write_data[1] | 4; /* Odd NetFn/LUN */ + bt->read_data[2] = bt->write_data[2]; /* seq (ignored) */ + bt->read_data[3] = bt->write_data[3]; /* Command */ + bt->read_data[4] = completion_code; + bt->read_count = 5; +} + +/* The upper state machine starts here */ + static int bt_start_transaction(struct si_sm_data *bt, unsigned char *data, unsigned int size) { unsigned int i; - if ((size < 2) || (size > (IPMI_MAX_MSG_LENGTH - 2))) - return -1; + if (size < 2) + return IPMI_REQ_LEN_INVALID_ERR; + if (size > IPMI_MAX_MSG_LENGTH) + return IPMI_REQ_LEN_EXCEEDED_ERR; - if ((bt->state != BT_STATE_IDLE) && (bt->state != BT_STATE_HOSED)) - return -2; + if (bt->state == BT_STATE_LONG_BUSY) + return IPMI_NODE_BUSY_ERR; + + if (bt->state != BT_STATE_IDLE) + return IPMI_NOT_IN_MY_STATE_ERR; if (bt_debug & BT_DEBUG_MSG) { - printk(KERN_WARNING "+++++++++++++++++++++++++++++++++++++\n"); - printk(KERN_WARNING "BT: write seq=0x%02X:", bt->seq); + printk(KERN_WARNING "BT: +++++++++++++++++ New command\n"); + printk(KERN_WARNING "BT: NetFn/LUN CMD [%d data]:", size - 2); for (i = 0; i < size; i ++) - printk (" %02x", data[i]); + printk (" %02x", data[i]); printk("\n"); } bt->write_data[0] = size + 1; /* all data plus seq byte */ bt->write_data[1] = *data; /* NetFn/LUN */ - bt->write_data[2] = bt->seq; + bt->write_data[2] = bt->seq++; memcpy(bt->write_data + 3, data + 1, size - 1); bt->write_count = size + 2; - bt->error_retries = 0; bt->nonzero_status = 0; - bt->read_count = 0; bt->truncated = 0; bt->state = BT_STATE_XACTION_START; - bt->last_state = BT_STATE_IDLE; - bt->timeout = BT_NORMAL_TIMEOUT; + bt->timeout = bt->BT_CAP_req2rsp; + force_result(bt, IPMI_ERR_UNSPECIFIED); return 0; } @@ -198,38 +248,30 @@ static int bt_start_transaction(struct si_sm_data *bt, it calls this. Strip out the length and seq bytes. */ static int bt_get_result(struct si_sm_data *bt, - unsigned char *data, - unsigned int length) + unsigned char *data, + unsigned int length) { int i, msg_len; msg_len = bt->read_count - 2; /* account for length & seq */ - /* Always NetFn, Cmd, cCode */ if (msg_len < 3 || msg_len > IPMI_MAX_MSG_LENGTH) { - printk(KERN_DEBUG "BT results: bad msg_len = %d\n", msg_len); - data[0] = bt->write_data[1] | 0x4; /* Kludge a response */ - data[1] = bt->write_data[3]; - data[2] = IPMI_ERR_UNSPECIFIED; + force_result(bt, IPMI_ERR_UNSPECIFIED); msg_len = 3; - } else { - data[0] = bt->read_data[1]; - data[1] = bt->read_data[3]; - if (length < msg_len) - bt->truncated = 1; - if (bt->truncated) { /* can be set in read_all_bytes() */ - data[2] = IPMI_ERR_MSG_TRUNCATED; - msg_len = 3; - } else - memcpy(data + 2, bt->read_data + 4, msg_len - 2); + } + data[0] = bt->read_data[1]; + data[1] = bt->read_data[3]; + if (length < msg_len || bt->truncated) { + data[2] = IPMI_ERR_MSG_TRUNCATED; + msg_len = 3; + } else + memcpy(data + 2, bt->read_data + 4, msg_len - 2); - if (bt_debug & BT_DEBUG_MSG) { - printk (KERN_WARNING "BT: res (raw)"); - for (i = 0; i < msg_len; i++) - printk(" %02x", data[i]); - printk ("\n"); - } + if (bt_debug & BT_DEBUG_MSG) { + printk (KERN_WARNING "BT: result %d bytes:", msg_len); + for (i = 0; i < msg_len; i++) + printk(" %02x", data[i]); + printk ("\n"); } - bt->read_count = 0; /* paranoia */ return msg_len; } @@ -238,22 +280,40 @@ static int bt_get_result(struct si_sm_data *bt, static void reset_flags(struct si_sm_data *bt) { + if (bt_debug) + printk(KERN_WARNING "IPMI BT: flag reset %s\n", + status2txt(BT_STATUS)); if (BT_STATUS & BT_H_BUSY) - BT_CONTROL(BT_H_BUSY); - if (BT_STATUS & BT_B_BUSY) - BT_CONTROL(BT_B_BUSY); - BT_CONTROL(BT_CLR_WR_PTR); - BT_CONTROL(BT_SMS_ATN); - - if (BT_STATUS & BT_B2H_ATN) { - int i; - BT_CONTROL(BT_H_BUSY); - BT_CONTROL(BT_B2H_ATN); - BT_CONTROL(BT_CLR_RD_PTR); - for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++) - BMC2HOST; - BT_CONTROL(BT_H_BUSY); - } + BT_CONTROL(BT_H_BUSY); /* force clear */ + BT_CONTROL(BT_CLR_WR_PTR); /* always reset */ + BT_CONTROL(BT_SMS_ATN); /* always clear */ + BT_INTMASK_W(BT_BMC_HWRST); +} + +/* Get rid of an unwanted/stale response. This should only be needed for + BMCs that support multiple outstanding requests. */ + +static void drain_BMC2HOST(struct si_sm_data *bt) +{ + int i, size; + + if (!(BT_STATUS & BT_B2H_ATN)) /* Not signalling a response */ + return; + + BT_CONTROL(BT_H_BUSY); /* now set */ + BT_CONTROL(BT_B2H_ATN); /* always clear */ + BT_STATUS; /* pause */ + BT_CONTROL(BT_B2H_ATN); /* some BMCs are stubborn */ + BT_CONTROL(BT_CLR_RD_PTR); /* always reset */ + if (bt_debug) + printk(KERN_WARNING "IPMI BT: stale response %s; ", + status2txt(BT_STATUS)); + size = BMC2HOST; + for (i = 0; i < size ; i++) + BMC2HOST; + BT_CONTROL(BT_H_BUSY); /* now clear */ + if (bt_debug) + printk("drained %d bytes\n", size + 1); } static inline void write_all_bytes(struct si_sm_data *bt) @@ -261,201 +321,256 @@ static inline void write_all_bytes(struct si_sm_data *bt) int i; if (bt_debug & BT_DEBUG_MSG) { - printk(KERN_WARNING "BT: write %d bytes seq=0x%02X", + printk(KERN_WARNING "BT: write %d bytes seq=0x%02X", bt->write_count, bt->seq); for (i = 0; i < bt->write_count; i++) printk (" %02x", bt->write_data[i]); printk ("\n"); } for (i = 0; i < bt->write_count; i++) - HOST2BMC(bt->write_data[i]); + HOST2BMC(bt->write_data[i]); } static inline int read_all_bytes(struct si_sm_data *bt) { unsigned char i; + /* length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode. + Keep layout of first four bytes aligned with write_data[] */ + bt->read_data[0] = BMC2HOST; bt->read_count = bt->read_data[0]; - if (bt_debug & BT_DEBUG_MSG) - printk(KERN_WARNING "BT: read %d bytes:", bt->read_count); - /* minimum: length, NetFn, Seq, Cmd, cCode == 5 total, or 4 more - following the length byte. */ if (bt->read_count < 4 || bt->read_count >= IPMI_MAX_MSG_LENGTH) { if (bt_debug & BT_DEBUG_MSG) - printk("bad length %d\n", bt->read_count); + printk(KERN_WARNING "BT: bad raw rsp len=%d\n", + bt->read_count); bt->truncated = 1; return 1; /* let next XACTION START clean it up */ } for (i = 1; i <= bt->read_count; i++) - bt->read_data[i] = BMC2HOST; - bt->read_count++; /* account for the length byte */ + bt->read_data[i] = BMC2HOST; + bt->read_count++; /* Account internally for length byte */ if (bt_debug & BT_DEBUG_MSG) { - for (i = 0; i < bt->read_count; i++) + int max = bt->read_count; + + printk(KERN_WARNING "BT: got %d bytes seq=0x%02X", + max, bt->read_data[2]); + if (max > 16) + max = 16; + for (i = 0; i < max; i++) printk (" %02x", bt->read_data[i]); - printk ("\n"); + printk ("%s\n", bt->read_count == max ? "" : " ..."); } - if (bt->seq != bt->write_data[2]) /* idiot check */ - printk(KERN_DEBUG "BT: internal error: sequence mismatch\n"); - /* per the spec, the (NetFn, Seq, Cmd) tuples should match */ - if ((bt->read_data[3] == bt->write_data[3]) && /* Cmd */ - (bt->read_data[2] == bt->write_data[2]) && /* Sequence */ - ((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8))) + /* per the spec, the (NetFn[1], Seq[2], Cmd[3]) tuples must match */ + if ((bt->read_data[3] == bt->write_data[3]) && + (bt->read_data[2] == bt->write_data[2]) && + ((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8))) return 1; if (bt_debug & BT_DEBUG_MSG) - printk(KERN_WARNING "BT: bad packet: " + printk(KERN_WARNING "IPMI BT: bad packet: " "want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n", - bt->write_data[1], bt->write_data[2], bt->write_data[3], + bt->write_data[1] | 0x04, bt->write_data[2], bt->write_data[3], bt->read_data[1], bt->read_data[2], bt->read_data[3]); return 0; } -/* Modifies bt->state appropriately, need to get into the bt_event() switch */ +/* Restart if retries are left, or return an error completion code */ -static void error_recovery(struct si_sm_data *bt, char *reason) +static enum si_sm_result error_recovery(struct si_sm_data *bt, + unsigned char status, + unsigned char cCode) { - unsigned char status; - char buf[40]; /* For getting status */ + char *reason; - bt->timeout = BT_NORMAL_TIMEOUT; /* various places want to retry */ + bt->timeout = bt->BT_CAP_req2rsp; - status = BT_STATUS; - printk(KERN_DEBUG "BT: %s in %s %s\n", reason, STATE2TXT, - STATUS2TXT(buf)); + switch (cCode) { + case IPMI_TIMEOUT_ERR: + reason = "timeout"; + break; + default: + reason = "internal error"; + break; + } + + printk(KERN_WARNING "IPMI BT: %s in %s %s ", /* open-ended line */ + reason, STATE2TXT, STATUS2TXT); + /* Per the IPMI spec, retries are based on the sequence number + known only to this module, so manage a restart here. */ (bt->error_retries)++; - if (bt->error_retries > BT_RETRY_LIMIT) { - printk(KERN_DEBUG "retry limit (%d) exceeded\n", BT_RETRY_LIMIT); - bt->state = BT_STATE_HOSED; - if (!bt->nonzero_status) - printk(KERN_ERR "IPMI: BT stuck, try power cycle\n"); - else if (bt->error_retries <= BT_RETRY_LIMIT + 1) { - printk(KERN_DEBUG "IPMI: BT reset (takes 5 secs)\n"); - bt->state = BT_STATE_RESET1; - } - return; + if (bt->error_retries < bt->BT_CAP_retries) { + printk("%d retries left\n", + bt->BT_CAP_retries - bt->error_retries); + bt->state = BT_STATE_RESTART; + return SI_SM_CALL_WITHOUT_DELAY; } - /* Sometimes the BMC queues get in an "off-by-one" state...*/ - if ((bt->state == BT_STATE_B2H_WAIT) && (status & BT_B2H_ATN)) { - printk(KERN_DEBUG "retry B2H_WAIT\n"); - return; + printk("failed %d retries, sending error response\n", + bt->BT_CAP_retries); + if (!bt->nonzero_status) + printk(KERN_ERR "IPMI BT: stuck, try power cycle\n"); + + /* this is most likely during insmod */ + else if (bt->seq <= (unsigned char)(bt->BT_CAP_retries & 0xFF)) { + printk(KERN_WARNING "IPMI: BT reset (takes 5 secs)\n"); + bt->state = BT_STATE_RESET1; + return SI_SM_CALL_WITHOUT_DELAY; } - printk(KERN_DEBUG "restart command\n"); - bt->state = BT_STATE_RESTART; + /* Concoct a useful error message, set up the next state, and + be done with this sequence. */ + + bt->state = BT_STATE_IDLE; + switch (cCode) { + case IPMI_TIMEOUT_ERR: + if (status & BT_B_BUSY) { + cCode = IPMI_NODE_BUSY_ERR; + bt->state = BT_STATE_LONG_BUSY; + } + break; + default: + break; + } + force_result(bt, cCode); + return SI_SM_TRANSACTION_COMPLETE; } -/* Check the status and (possibly) advance the BT state machine. The - default return is SI_SM_CALL_WITH_DELAY. */ +/* Check status and (usually) take action and change this state machine. */ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) { - unsigned char status; - char buf[40]; /* For getting status */ + unsigned char status, BT_CAP[8]; + static enum bt_states last_printed = BT_STATE_PRINTME; int i; status = BT_STATUS; bt->nonzero_status |= status; - - if ((bt_debug & BT_DEBUG_STATES) && (bt->state != bt->last_state)) + if ((bt_debug & BT_DEBUG_STATES) && (bt->state != last_printed)) { printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n", STATE2TXT, - STATUS2TXT(buf), + STATUS2TXT, bt->timeout, time); - bt->last_state = bt->state; + last_printed = bt->state; + } - if (bt->state == BT_STATE_HOSED) - return SI_SM_HOSED; + /* Commands that time out may still (eventually) provide a response. + This stale response will get in the way of a new response so remove + it if possible (hopefully during IDLE). Even if it comes up later + it will be rejected by its (now-forgotten) seq number. */ + + if ((bt->state < BT_STATE_WRITE_BYTES) && (status & BT_B2H_ATN)) { + drain_BMC2HOST(bt); + BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); + } - if (bt->state != BT_STATE_IDLE) { /* do timeout test */ + if ((bt->state != BT_STATE_IDLE) && + (bt->state < BT_STATE_PRINTME)) { /* check timeout */ bt->timeout -= time; - if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) { - error_recovery(bt, "timed out"); - return SI_SM_CALL_WITHOUT_DELAY; - } + if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) + return error_recovery(bt, + status, + IPMI_TIMEOUT_ERR); } switch (bt->state) { - case BT_STATE_IDLE: /* check for asynchronous messages */ + /* Idle state first checks for asynchronous messages from another + channel, then does some opportunistic housekeeping. */ + + case BT_STATE_IDLE: if (status & BT_SMS_ATN) { BT_CONTROL(BT_SMS_ATN); /* clear it */ return SI_SM_ATTN; } - return SI_SM_IDLE; - case BT_STATE_XACTION_START: - if (status & BT_H_BUSY) { + if (status & BT_H_BUSY) /* clear a leftover H_BUSY */ BT_CONTROL(BT_H_BUSY); - break; - } - if (status & BT_B2H_ATN) - break; - bt->state = BT_STATE_WRITE_BYTES; - return SI_SM_CALL_WITHOUT_DELAY; /* for logging */ - case BT_STATE_WRITE_BYTES: + /* Read BT capabilities if it hasn't been done yet */ + if (!bt->BT_CAP_outreqs) + BT_STATE_CHANGE(BT_STATE_CAPABILITIES_BEGIN, + SI_SM_CALL_WITHOUT_DELAY); + bt->timeout = bt->BT_CAP_req2rsp; + BT_SI_SM_RETURN(SI_SM_IDLE); + + case BT_STATE_XACTION_START: if (status & (BT_B_BUSY | BT_H2B_ATN)) - break; + BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); + if (BT_STATUS & BT_H_BUSY) + BT_CONTROL(BT_H_BUSY); /* force clear */ + BT_STATE_CHANGE(BT_STATE_WRITE_BYTES, + SI_SM_CALL_WITHOUT_DELAY); + + case BT_STATE_WRITE_BYTES: + if (status & BT_H_BUSY) + BT_CONTROL(BT_H_BUSY); /* clear */ BT_CONTROL(BT_CLR_WR_PTR); write_all_bytes(bt); - BT_CONTROL(BT_H2B_ATN); /* clears too fast to catch? */ - bt->state = BT_STATE_WRITE_CONSUME; - return SI_SM_CALL_WITHOUT_DELAY; /* it MIGHT sail through */ - - case BT_STATE_WRITE_CONSUME: /* BMCs usually blow right thru here */ - if (status & (BT_H2B_ATN | BT_B_BUSY)) - break; - bt->state = BT_STATE_B2H_WAIT; - /* fall through with status */ - - /* Stay in BT_STATE_B2H_WAIT until a packet matches. However, spinning - hard here, constantly reading status, seems to hold off the - generation of B2H_ATN so ALWAYS return CALL_WITH_DELAY. */ - - case BT_STATE_B2H_WAIT: - if (!(status & BT_B2H_ATN)) - break; - - /* Assume ordered, uncached writes: no need to wait */ - if (!(status & BT_H_BUSY)) - BT_CONTROL(BT_H_BUSY); /* set */ - BT_CONTROL(BT_B2H_ATN); /* clear it, ACK to the BMC */ - BT_CONTROL(BT_CLR_RD_PTR); /* reset the queue */ - i = read_all_bytes(bt); - BT_CONTROL(BT_H_BUSY); /* clear */ - if (!i) /* Try this state again */ - break; - bt->state = BT_STATE_READ_END; - return SI_SM_CALL_WITHOUT_DELAY; /* for logging */ - - case BT_STATE_READ_END: - - /* I could wait on BT_H_BUSY to go clear for a truly clean - exit. However, this is already done in XACTION_START - and the (possible) extra loop/status/possible wait affects - performance. So, as long as it works, just ignore H_BUSY */ - -#ifdef MAKE_THIS_TRUE_IF_NECESSARY + BT_CONTROL(BT_H2B_ATN); /* can clear too fast to catch */ + BT_STATE_CHANGE(BT_STATE_WRITE_CONSUME, + SI_SM_CALL_WITHOUT_DELAY); - if (status & BT_H_BUSY) - break; -#endif - bt->seq++; - bt->state = BT_STATE_IDLE; - return SI_SM_TRANSACTION_COMPLETE; + case BT_STATE_WRITE_CONSUME: + if (status & (BT_B_BUSY | BT_H2B_ATN)) + BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); + BT_STATE_CHANGE(BT_STATE_READ_WAIT, + SI_SM_CALL_WITHOUT_DELAY); + + /* Spinning hard can suppress B2H_ATN and force a timeout */ + + case BT_STATE_READ_WAIT: + if (!(status & BT_B2H_ATN)) + BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); + BT_CONTROL(BT_H_BUSY); /* set */ + + /* Uncached, ordered writes should just proceeed serially but + some BMCs don't clear B2H_ATN with one hit. Fast-path a + workaround without too much penalty to the general case. */ + + BT_CONTROL(BT_B2H_ATN); /* clear it to ACK the BMC */ + BT_STATE_CHANGE(BT_STATE_CLEAR_B2H, + SI_SM_CALL_WITHOUT_DELAY); + + case BT_STATE_CLEAR_B2H: + if (status & BT_B2H_ATN) { /* keep hitting it */ + BT_CONTROL(BT_B2H_ATN); + BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); + } + BT_STATE_CHANGE(BT_STATE_READ_BYTES, + SI_SM_CALL_WITHOUT_DELAY); + + case BT_STATE_READ_BYTES: + if (!(status & BT_H_BUSY)) /* check in case of retry */ + BT_CONTROL(BT_H_BUSY); + BT_CONTROL(BT_CLR_RD_PTR); /* start of BMC2HOST buffer */ + i = read_all_bytes(bt); /* true == packet seq match */ + BT_CONTROL(BT_H_BUSY); /* NOW clear */ + if (!i) /* Not my message */ + BT_STATE_CHANGE(BT_STATE_READ_WAIT, + SI_SM_CALL_WITHOUT_DELAY); + bt->state = bt->complete; + return bt->state == BT_STATE_IDLE ? /* where to next? */ + SI_SM_TRANSACTION_COMPLETE : /* normal */ + SI_SM_CALL_WITHOUT_DELAY; /* Startup magic */ + + case BT_STATE_LONG_BUSY: /* For example: after FW update */ + if (!(status & BT_B_BUSY)) { + reset_flags(bt); /* next state is now IDLE */ + bt_init_data(bt, bt->io); + } + return SI_SM_CALL_WITH_DELAY; /* No repeat printing */ case BT_STATE_RESET1: - reset_flags(bt); - bt->timeout = BT_RESET_DELAY; - bt->state = BT_STATE_RESET2; - break; + reset_flags(bt); + drain_BMC2HOST(bt); + BT_STATE_CHANGE(BT_STATE_RESET2, + SI_SM_CALL_WITH_DELAY); case BT_STATE_RESET2: /* Send a soft reset */ BT_CONTROL(BT_CLR_WR_PTR); @@ -464,29 +579,59 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) HOST2BMC(42); /* Sequence number */ HOST2BMC(3); /* Cmd == Soft reset */ BT_CONTROL(BT_H2B_ATN); - bt->state = BT_STATE_RESET3; - break; + bt->timeout = BT_RESET_DELAY * 1000000; + BT_STATE_CHANGE(BT_STATE_RESET3, + SI_SM_CALL_WITH_DELAY); - case BT_STATE_RESET3: + case BT_STATE_RESET3: /* Hold off everything for a bit */ if (bt->timeout > 0) - return SI_SM_CALL_WITH_DELAY; - bt->state = BT_STATE_RESTART; /* printk in debug modes */ - break; + return SI_SM_CALL_WITH_DELAY; + drain_BMC2HOST(bt); + BT_STATE_CHANGE(BT_STATE_RESTART, + SI_SM_CALL_WITH_DELAY); - case BT_STATE_RESTART: /* don't reset retries! */ - reset_flags(bt); - bt->write_data[2] = ++bt->seq; + case BT_STATE_RESTART: /* don't reset retries or seq! */ bt->read_count = 0; bt->nonzero_status = 0; - bt->timeout = BT_NORMAL_TIMEOUT; - bt->state = BT_STATE_XACTION_START; - break; - - default: /* HOSED is supposed to be caught much earlier */ - error_recovery(bt, "internal logic error"); - break; - } - return SI_SM_CALL_WITH_DELAY; + bt->timeout = bt->BT_CAP_req2rsp; + BT_STATE_CHANGE(BT_STATE_XACTION_START, + SI_SM_CALL_WITH_DELAY); + + /* Get BT Capabilities, using timing of upper level state machine. + Set outreqs to prevent infinite loop on timeout. */ + case BT_STATE_CAPABILITIES_BEGIN: + bt->BT_CAP_outreqs = 1; + { + unsigned char GetBT_CAP[] = { 0x18, 0x36 }; + bt->state = BT_STATE_IDLE; + bt_start_transaction(bt, GetBT_CAP, sizeof(GetBT_CAP)); + } + bt->complete = BT_STATE_CAPABILITIES_END; + BT_STATE_CHANGE(BT_STATE_XACTION_START, + SI_SM_CALL_WITH_DELAY); + + case BT_STATE_CAPABILITIES_END: + i = bt_get_result(bt, BT_CAP, sizeof(BT_CAP)); + bt_init_data(bt, bt->io); + if ((i == 8) && !BT_CAP[2]) { + bt->BT_CAP_outreqs = BT_CAP[3]; + bt->BT_CAP_req2rsp = BT_CAP[6] * 1000000; + bt->BT_CAP_retries = BT_CAP[7]; + } else + printk(KERN_WARNING "IPMI BT: using default values\n"); + if (!bt->BT_CAP_outreqs) + bt->BT_CAP_outreqs = 1; + printk(KERN_WARNING "IPMI BT: req2rsp=%ld secs retries=%d\n", + bt->BT_CAP_req2rsp / 1000000L, bt->BT_CAP_retries); + bt->timeout = bt->BT_CAP_req2rsp; + return SI_SM_CALL_WITHOUT_DELAY; + + default: /* should never occur */ + return error_recovery(bt, + status, + IPMI_ERR_UNSPECIFIED); + } + return SI_SM_CALL_WITH_DELAY; } static int bt_detect(struct si_sm_data *bt) @@ -497,7 +642,7 @@ static int bt_detect(struct si_sm_data *bt) test that first. The calling routine uses negative logic. */ if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) - return 1; + return 1; reset_flags(bt); return 0; } @@ -513,11 +658,11 @@ static int bt_size(void) struct si_sm_handlers bt_smi_handlers = { - .init_data = bt_init_data, - .start_transaction = bt_start_transaction, - .get_result = bt_get_result, - .event = bt_event, - .detect = bt_detect, - .cleanup = bt_cleanup, - .size = bt_size, + .init_data = bt_init_data, + .start_transaction = bt_start_transaction, + .get_result = bt_get_result, + .event = bt_event, + .detect = bt_detect, + .cleanup = bt_cleanup, + .size = bt_size, }; diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 81fcf0ce21d1..375d3378eecd 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -596,6 +596,31 @@ static int ipmi_ioctl(struct inode *inode, rv = 0; break; } + + case IPMICTL_GET_MAINTENANCE_MODE_CMD: + { + int mode; + + mode = ipmi_get_maintenance_mode(priv->user); + if (copy_to_user(arg, &mode, sizeof(mode))) { + rv = -EFAULT; + break; + } + rv = 0; + break; + } + + case IPMICTL_SET_MAINTENANCE_MODE_CMD: + { + int mode; + + if (copy_from_user(&mode, arg, sizeof(mode))) { + rv = -EFAULT; + break; + } + rv = ipmi_set_maintenance_mode(priv->user, mode); + break; + } } return rv; diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c index 2062675f9e99..c1b8228cb7b6 100644 --- a/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/drivers/char/ipmi/ipmi_kcs_sm.c @@ -93,8 +93,8 @@ enum kcs_states { state machine. */ }; -#define MAX_KCS_READ_SIZE 80 -#define MAX_KCS_WRITE_SIZE 80 +#define MAX_KCS_READ_SIZE IPMI_MAX_MSG_LENGTH +#define MAX_KCS_WRITE_SIZE IPMI_MAX_MSG_LENGTH /* Timeouts in microseconds. */ #define IBF_RETRY_TIMEOUT 1000000 @@ -261,12 +261,14 @@ static int start_kcs_transaction(struct si_sm_data *kcs, unsigned char *data, { unsigned int i; - if ((size < 2) || (size > MAX_KCS_WRITE_SIZE)) { - return -1; - } - if ((kcs->state != KCS_IDLE) && (kcs->state != KCS_HOSED)) { - return -2; - } + if (size < 2) + return IPMI_REQ_LEN_INVALID_ERR; + if (size > MAX_KCS_WRITE_SIZE) + return IPMI_REQ_LEN_EXCEEDED_ERR; + + if ((kcs->state != KCS_IDLE) && (kcs->state != KCS_HOSED)) + return IPMI_NOT_IN_MY_STATE_ERR; + if (kcs_debug & KCS_DEBUG_MSG) { printk(KERN_DEBUG "start_kcs_transaction -"); for (i = 0; i < size; i ++) { diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index c47add8e47df..5703ee28e1cc 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -48,7 +48,7 @@ #define PFX "IPMI message handler: " -#define IPMI_DRIVER_VERSION "39.0" +#define IPMI_DRIVER_VERSION "39.1" static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); static int ipmi_init_msghandler(void); @@ -59,6 +59,9 @@ static int initialized = 0; static struct proc_dir_entry *proc_ipmi_root = NULL; #endif /* CONFIG_PROC_FS */ +/* Remain in auto-maintenance mode for this amount of time (in ms). */ +#define IPMI_MAINTENANCE_MODE_TIMEOUT 30000 + #define MAX_EVENTS_IN_QUEUE 25 /* Don't let a message sit in a queue forever, always time it with at lest @@ -193,17 +196,28 @@ struct ipmi_smi struct kref refcount; + /* Used for a list of interfaces. */ + struct list_head link; + /* The list of upper layers that are using me. seq_lock * protects this. */ struct list_head users; + /* Information to supply to users. */ + unsigned char ipmi_version_major; + unsigned char ipmi_version_minor; + /* Used for wake ups at startup. */ wait_queue_head_t waitq; struct bmc_device *bmc; char *my_dev_name; + char *sysfs_name; - /* This is the lower-layer's sender routine. */ + /* This is the lower-layer's sender routine. Note that you + * must either be holding the ipmi_interfaces_mutex or be in + * an umpreemptible region to use this. You must fetch the + * value into a local variable and make sure it is not NULL. */ struct ipmi_smi_handlers *handlers; void *send_info; @@ -242,6 +256,7 @@ struct ipmi_smi spinlock_t events_lock; /* For dealing with event stuff. */ struct list_head waiting_events; unsigned int waiting_events_count; /* How many events in queue? */ + int delivering_events; /* The event receiver for my BMC, only really used at panic shutdown as a place to store this. */ @@ -250,6 +265,12 @@ struct ipmi_smi unsigned char local_sel_device; unsigned char local_event_generator; + /* For handling of maintenance mode. */ + int maintenance_mode; + int maintenance_mode_enable; + int auto_maintenance_timeout; + spinlock_t maintenance_mode_lock; /* Used in a timer... */ + /* A cheap hack, if this is non-null and a message to an interface comes in with a NULL user, call this routine with it. Note that the message will still be freed by the @@ -338,13 +359,6 @@ struct ipmi_smi }; #define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev) -/* Used to mark an interface entry that cannot be used but is not a - * free entry, either, primarily used at creation and deletion time so - * a slot doesn't get reused too quickly. */ -#define IPMI_INVALID_INTERFACE_ENTRY ((ipmi_smi_t) ((long) 1)) -#define IPMI_INVALID_INTERFACE(i) (((i) == NULL) \ - || (i == IPMI_INVALID_INTERFACE_ENTRY)) - /** * The driver model view of the IPMI messaging driver. */ @@ -354,16 +368,13 @@ static struct device_driver ipmidriver = { }; static DEFINE_MUTEX(ipmidriver_mutex); -#define MAX_IPMI_INTERFACES 4 -static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES]; - -/* Directly protects the ipmi_interfaces data structure. */ -static DEFINE_SPINLOCK(interfaces_lock); +static struct list_head ipmi_interfaces = LIST_HEAD_INIT(ipmi_interfaces); +static DEFINE_MUTEX(ipmi_interfaces_mutex); /* List of watchers that want to know when smi's are added and deleted. */ static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers); -static DECLARE_RWSEM(smi_watchers_sem); +static DEFINE_MUTEX(smi_watchers_mutex); static void free_recv_msg_list(struct list_head *q) @@ -423,48 +434,84 @@ static void intf_free(struct kref *ref) kfree(intf); } +struct watcher_entry { + int intf_num; + ipmi_smi_t intf; + struct list_head link; +}; + int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher) { - int i; - unsigned long flags; + ipmi_smi_t intf; + struct list_head to_deliver = LIST_HEAD_INIT(to_deliver); + struct watcher_entry *e, *e2; + + mutex_lock(&smi_watchers_mutex); + + mutex_lock(&ipmi_interfaces_mutex); - down_write(&smi_watchers_sem); - list_add(&(watcher->link), &smi_watchers); - up_write(&smi_watchers_sem); - spin_lock_irqsave(&interfaces_lock, flags); - for (i = 0; i < MAX_IPMI_INTERFACES; i++) { - ipmi_smi_t intf = ipmi_interfaces[i]; - if (IPMI_INVALID_INTERFACE(intf)) + /* Build a list of things to deliver. */ + list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { + if (intf->intf_num == -1) continue; - spin_unlock_irqrestore(&interfaces_lock, flags); - watcher->new_smi(i, intf->si_dev); - spin_lock_irqsave(&interfaces_lock, flags); + e = kmalloc(sizeof(*e), GFP_KERNEL); + if (!e) + goto out_err; + kref_get(&intf->refcount); + e->intf = intf; + e->intf_num = intf->intf_num; + list_add_tail(&e->link, &to_deliver); } - spin_unlock_irqrestore(&interfaces_lock, flags); + + /* We will succeed, so add it to the list. */ + list_add(&watcher->link, &smi_watchers); + + mutex_unlock(&ipmi_interfaces_mutex); + + list_for_each_entry_safe(e, e2, &to_deliver, link) { + list_del(&e->link); + watcher->new_smi(e->intf_num, e->intf->si_dev); + kref_put(&e->intf->refcount, intf_free); + kfree(e); + } + + mutex_unlock(&smi_watchers_mutex); + return 0; + + out_err: + mutex_unlock(&ipmi_interfaces_mutex); + mutex_unlock(&smi_watchers_mutex); + list_for_each_entry_safe(e, e2, &to_deliver, link) { + list_del(&e->link); + kref_put(&e->intf->refcount, intf_free); + kfree(e); + } + return -ENOMEM; } int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher) { - down_write(&smi_watchers_sem); + mutex_lock(&smi_watchers_mutex); list_del(&(watcher->link)); - up_write(&smi_watchers_sem); + mutex_unlock(&smi_watchers_mutex); return 0; } +/* + * Must be called with smi_watchers_mutex held. + */ static void call_smi_watchers(int i, struct device *dev) { struct ipmi_smi_watcher *w; - down_read(&smi_watchers_sem); list_for_each_entry(w, &smi_watchers, link) { if (try_module_get(w->owner)) { w->new_smi(i, dev); module_put(w->owner); } } - up_read(&smi_watchers_sem); } static int @@ -590,6 +637,17 @@ static void deliver_response(struct ipmi_recv_msg *msg) } } +static void +deliver_err_response(struct ipmi_recv_msg *msg, int err) +{ + msg->recv_type = IPMI_RESPONSE_RECV_TYPE; + msg->msg_data[0] = err; + msg->msg.netfn |= 1; /* Convert to a response. */ + msg->msg.data_len = 1; + msg->msg.data = msg->msg_data; + deliver_response(msg); +} + /* Find the next sequence number not being used and add the given message with the given timeout to the sequence table. This must be called with the interface's seq_lock held. */ @@ -727,14 +785,8 @@ static int intf_err_seq(ipmi_smi_t intf, } spin_unlock_irqrestore(&(intf->seq_lock), flags); - if (msg) { - msg->recv_type = IPMI_RESPONSE_RECV_TYPE; - msg->msg_data[0] = err; - msg->msg.netfn |= 1; /* Convert to a response. */ - msg->msg.data_len = 1; - msg->msg.data = msg->msg_data; - deliver_response(msg); - } + if (msg) + deliver_err_response(msg, err); return rv; } @@ -776,17 +828,18 @@ int ipmi_create_user(unsigned int if_num, if (!new_user) return -ENOMEM; - spin_lock_irqsave(&interfaces_lock, flags); - intf = ipmi_interfaces[if_num]; - if ((if_num >= MAX_IPMI_INTERFACES) || IPMI_INVALID_INTERFACE(intf)) { - spin_unlock_irqrestore(&interfaces_lock, flags); - rv = -EINVAL; - goto out_kfree; + mutex_lock(&ipmi_interfaces_mutex); + list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { + if (intf->intf_num == if_num) + goto found; } + /* Not found, return an error */ + rv = -EINVAL; + goto out_kfree; + found: /* Note that each existing user holds a refcount to the interface. */ kref_get(&intf->refcount); - spin_unlock_irqrestore(&interfaces_lock, flags); kref_init(&new_user->refcount); new_user->handler = handler; @@ -807,6 +860,10 @@ int ipmi_create_user(unsigned int if_num, } } + /* Hold the lock so intf->handlers is guaranteed to be good + * until now */ + mutex_unlock(&ipmi_interfaces_mutex); + new_user->valid = 1; spin_lock_irqsave(&intf->seq_lock, flags); list_add_rcu(&new_user->link, &intf->users); @@ -817,6 +874,7 @@ int ipmi_create_user(unsigned int if_num, out_kref: kref_put(&intf->refcount, intf_free); out_kfree: + mutex_unlock(&ipmi_interfaces_mutex); kfree(new_user); return rv; } @@ -846,6 +904,7 @@ int ipmi_destroy_user(ipmi_user_t user) && (intf->seq_table[i].recv_msg->user == user)) { intf->seq_table[i].inuse = 0; + ipmi_free_recv_msg(intf->seq_table[i].recv_msg); } } spin_unlock_irqrestore(&intf->seq_lock, flags); @@ -872,9 +931,13 @@ int ipmi_destroy_user(ipmi_user_t user) kfree(rcvr); } - module_put(intf->handlers->owner); - if (intf->handlers->dec_usecount) - intf->handlers->dec_usecount(intf->send_info); + mutex_lock(&ipmi_interfaces_mutex); + if (intf->handlers) { + module_put(intf->handlers->owner); + if (intf->handlers->dec_usecount) + intf->handlers->dec_usecount(intf->send_info); + } + mutex_unlock(&ipmi_interfaces_mutex); kref_put(&intf->refcount, intf_free); @@ -887,8 +950,8 @@ void ipmi_get_version(ipmi_user_t user, unsigned char *major, unsigned char *minor) { - *major = ipmi_version_major(&user->intf->bmc->id); - *minor = ipmi_version_minor(&user->intf->bmc->id); + *major = user->intf->ipmi_version_major; + *minor = user->intf->ipmi_version_minor; } int ipmi_set_my_address(ipmi_user_t user, @@ -931,6 +994,65 @@ int ipmi_get_my_LUN(ipmi_user_t user, return 0; } +int ipmi_get_maintenance_mode(ipmi_user_t user) +{ + int mode; + unsigned long flags; + + spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags); + mode = user->intf->maintenance_mode; + spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags); + + return mode; +} +EXPORT_SYMBOL(ipmi_get_maintenance_mode); + +static void maintenance_mode_update(ipmi_smi_t intf) +{ + if (intf->handlers->set_maintenance_mode) + intf->handlers->set_maintenance_mode( + intf->send_info, intf->maintenance_mode_enable); +} + +int ipmi_set_maintenance_mode(ipmi_user_t user, int mode) +{ + int rv = 0; + unsigned long flags; + ipmi_smi_t intf = user->intf; + + spin_lock_irqsave(&intf->maintenance_mode_lock, flags); + if (intf->maintenance_mode != mode) { + switch (mode) { + case IPMI_MAINTENANCE_MODE_AUTO: + intf->maintenance_mode = mode; + intf->maintenance_mode_enable + = (intf->auto_maintenance_timeout > 0); + break; + + case IPMI_MAINTENANCE_MODE_OFF: + intf->maintenance_mode = mode; + intf->maintenance_mode_enable = 0; + break; + + case IPMI_MAINTENANCE_MODE_ON: + intf->maintenance_mode = mode; + intf->maintenance_mode_enable = 1; + break; + + default: + rv = -EINVAL; + goto out_unlock; + } + + maintenance_mode_update(intf); + } + out_unlock: + spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags); + + return rv; +} +EXPORT_SYMBOL(ipmi_set_maintenance_mode); + int ipmi_set_gets_events(ipmi_user_t user, int val) { unsigned long flags; @@ -943,20 +1065,33 @@ int ipmi_set_gets_events(ipmi_user_t user, int val) spin_lock_irqsave(&intf->events_lock, flags); user->gets_events = val; - if (val) { - /* Deliver any queued events. */ + if (intf->delivering_events) + /* + * Another thread is delivering events for this, so + * let it handle any new events. + */ + goto out; + + /* Deliver any queued events. */ + while (user->gets_events && !list_empty(&intf->waiting_events)) { list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link) list_move_tail(&msg->link, &msgs); intf->waiting_events_count = 0; - } - /* Hold the events lock while doing this to preserve order. */ - list_for_each_entry_safe(msg, msg2, &msgs, link) { - msg->user = user; - kref_get(&user->refcount); - deliver_response(msg); + intf->delivering_events = 1; + spin_unlock_irqrestore(&intf->events_lock, flags); + + list_for_each_entry_safe(msg, msg2, &msgs, link) { + msg->user = user; + kref_get(&user->refcount); + deliver_response(msg); + } + + spin_lock_irqsave(&intf->events_lock, flags); + intf->delivering_events = 0; } + out: spin_unlock_irqrestore(&intf->events_lock, flags); return 0; @@ -1067,7 +1202,8 @@ int ipmi_unregister_for_cmd(ipmi_user_t user, void ipmi_user_set_run_to_completion(ipmi_user_t user, int val) { ipmi_smi_t intf = user->intf; - intf->handlers->set_run_to_completion(intf->send_info, val); + if (intf->handlers) + intf->handlers->set_run_to_completion(intf->send_info, val); } static unsigned char @@ -1178,10 +1314,11 @@ static int i_ipmi_request(ipmi_user_t user, int retries, unsigned int retry_time_ms) { - int rv = 0; - struct ipmi_smi_msg *smi_msg; - struct ipmi_recv_msg *recv_msg; - unsigned long flags; + int rv = 0; + struct ipmi_smi_msg *smi_msg; + struct ipmi_recv_msg *recv_msg; + unsigned long flags; + struct ipmi_smi_handlers *handlers; if (supplied_recv) { @@ -1204,6 +1341,13 @@ static int i_ipmi_request(ipmi_user_t user, } } + rcu_read_lock(); + handlers = intf->handlers; + if (!handlers) { + rv = -ENODEV; + goto out_err; + } + recv_msg->user = user; if (user) kref_get(&user->refcount); @@ -1246,6 +1390,24 @@ static int i_ipmi_request(ipmi_user_t user, goto out_err; } + if (((msg->netfn == IPMI_NETFN_APP_REQUEST) + && ((msg->cmd == IPMI_COLD_RESET_CMD) + || (msg->cmd == IPMI_WARM_RESET_CMD))) + || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST)) + { + spin_lock_irqsave(&intf->maintenance_mode_lock, flags); + intf->auto_maintenance_timeout + = IPMI_MAINTENANCE_MODE_TIMEOUT; + if (!intf->maintenance_mode + && !intf->maintenance_mode_enable) + { + intf->maintenance_mode_enable = 1; + maintenance_mode_update(intf); + } + spin_unlock_irqrestore(&intf->maintenance_mode_lock, + flags); + } + if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) { spin_lock_irqsave(&intf->counter_lock, flags); intf->sent_invalid_commands++; @@ -1520,11 +1682,14 @@ static int i_ipmi_request(ipmi_user_t user, printk("\n"); } #endif - intf->handlers->sender(intf->send_info, smi_msg, priority); + + handlers->sender(intf->send_info, smi_msg, priority); + rcu_read_unlock(); return 0; out_err: + rcu_read_unlock(); ipmi_free_smi_msg(smi_msg); ipmi_free_recv_msg(recv_msg); return rv; @@ -1604,6 +1769,7 @@ int ipmi_request_supply_msgs(ipmi_user_t user, -1, 0); } +#ifdef CONFIG_PROC_FS static int ipmb_file_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -1692,6 +1858,7 @@ static int stat_file_read_proc(char *page, char **start, off_t off, return (out - ((char *) page)); } +#endif /* CONFIG_PROC_FS */ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, read_proc_t *read_proc, write_proc_t *write_proc, @@ -1817,13 +1984,12 @@ static int __find_bmc_prod_dev_id(struct device *dev, void *data) struct bmc_device *bmc = dev_get_drvdata(dev); return (bmc->id.product_id == id->product_id - && bmc->id.product_id == id->product_id && bmc->id.device_id == id->device_id); } static struct bmc_device *ipmi_find_bmc_prod_dev_id( struct device_driver *drv, - unsigned char product_id, unsigned char device_id) + unsigned int product_id, unsigned char device_id) { struct prod_dev_id id = { .product_id = product_id, @@ -1940,6 +2106,9 @@ static ssize_t guid_show(struct device *dev, struct device_attribute *attr, static void remove_files(struct bmc_device *bmc) { + if (!bmc->dev) + return; + device_remove_file(&bmc->dev->dev, &bmc->device_id_attr); device_remove_file(&bmc->dev->dev, @@ -1973,7 +2142,8 @@ cleanup_bmc_device(struct kref *ref) bmc = container_of(ref, struct bmc_device, refcount); remove_files(bmc); - platform_device_unregister(bmc->dev); + if (bmc->dev) + platform_device_unregister(bmc->dev); kfree(bmc); } @@ -1981,7 +2151,11 @@ static void ipmi_bmc_unregister(ipmi_smi_t intf) { struct bmc_device *bmc = intf->bmc; - sysfs_remove_link(&intf->si_dev->kobj, "bmc"); + if (intf->sysfs_name) { + sysfs_remove_link(&intf->si_dev->kobj, intf->sysfs_name); + kfree(intf->sysfs_name); + intf->sysfs_name = NULL; + } if (intf->my_dev_name) { sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name); kfree(intf->my_dev_name); @@ -1990,6 +2164,7 @@ static void ipmi_bmc_unregister(ipmi_smi_t intf) mutex_lock(&ipmidriver_mutex); kref_put(&bmc->refcount, cleanup_bmc_device); + intf->bmc = NULL; mutex_unlock(&ipmidriver_mutex); } @@ -1997,6 +2172,56 @@ static int create_files(struct bmc_device *bmc) { int err; + bmc->device_id_attr.attr.name = "device_id"; + bmc->device_id_attr.attr.owner = THIS_MODULE; + bmc->device_id_attr.attr.mode = S_IRUGO; + bmc->device_id_attr.show = device_id_show; + + bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs"; + bmc->provides_dev_sdrs_attr.attr.owner = THIS_MODULE; + bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO; + bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show; + + bmc->revision_attr.attr.name = "revision"; + bmc->revision_attr.attr.owner = THIS_MODULE; + bmc->revision_attr.attr.mode = S_IRUGO; + bmc->revision_attr.show = revision_show; + + bmc->firmware_rev_attr.attr.name = "firmware_revision"; + bmc->firmware_rev_attr.attr.owner = THIS_MODULE; + bmc->firmware_rev_attr.attr.mode = S_IRUGO; + bmc->firmware_rev_attr.show = firmware_rev_show; + + bmc->version_attr.attr.name = "ipmi_version"; + bmc->version_attr.attr.owner = THIS_MODULE; + bmc->version_attr.attr.mode = S_IRUGO; + bmc->version_attr.show = ipmi_version_show; + + bmc->add_dev_support_attr.attr.name = "additional_device_support"; + bmc->add_dev_support_attr.attr.owner = THIS_MODULE; + bmc->add_dev_support_attr.attr.mode = S_IRUGO; + bmc->add_dev_support_attr.show = add_dev_support_show; + + bmc->manufacturer_id_attr.attr.name = "manufacturer_id"; + bmc->manufacturer_id_attr.attr.owner = THIS_MODULE; + bmc->manufacturer_id_attr.attr.mode = S_IRUGO; + bmc->manufacturer_id_attr.show = manufacturer_id_show; + + bmc->product_id_attr.attr.name = "product_id"; + bmc->product_id_attr.attr.owner = THIS_MODULE; + bmc->product_id_attr.attr.mode = S_IRUGO; + bmc->product_id_attr.show = product_id_show; + + bmc->guid_attr.attr.name = "guid"; + bmc->guid_attr.attr.owner = THIS_MODULE; + bmc->guid_attr.attr.mode = S_IRUGO; + bmc->guid_attr.show = guid_show; + + bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision"; + bmc->aux_firmware_rev_attr.attr.owner = THIS_MODULE; + bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO; + bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show; + err = device_create_file(&bmc->dev->dev, &bmc->device_id_attr); if (err) goto out; @@ -2066,7 +2291,8 @@ out: return err; } -static int ipmi_bmc_register(ipmi_smi_t intf) +static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum, + const char *sysfs_name) { int rv; struct bmc_device *bmc = intf->bmc; @@ -2106,9 +2332,39 @@ static int ipmi_bmc_register(ipmi_smi_t intf) bmc->id.product_id, bmc->id.device_id); } else { - bmc->dev = platform_device_alloc("ipmi_bmc", - bmc->id.device_id); + char name[14]; + unsigned char orig_dev_id = bmc->id.device_id; + int warn_printed = 0; + + snprintf(name, sizeof(name), + "ipmi_bmc.%4.4x", bmc->id.product_id); + + while (ipmi_find_bmc_prod_dev_id(&ipmidriver, + bmc->id.product_id, + bmc->id.device_id)) + { + if (!warn_printed) { + printk(KERN_WARNING PFX + "This machine has two different BMCs" + " with the same product id and device" + " id. This is an error in the" + " firmware, but incrementing the" + " device id to work around the problem." + " Prod ID = 0x%x, Dev ID = 0x%x\n", + bmc->id.product_id, bmc->id.device_id); + warn_printed = 1; + } + bmc->id.device_id++; /* Wraps at 255 */ + if (bmc->id.device_id == orig_dev_id) { + printk(KERN_ERR PFX + "Out of device ids!\n"); + break; + } + } + + bmc->dev = platform_device_alloc(name, bmc->id.device_id); if (!bmc->dev) { + mutex_unlock(&ipmidriver_mutex); printk(KERN_ERR "ipmi_msghandler:" " Unable to allocate platform device\n"); @@ -2121,6 +2377,8 @@ static int ipmi_bmc_register(ipmi_smi_t intf) rv = platform_device_add(bmc->dev); mutex_unlock(&ipmidriver_mutex); if (rv) { + platform_device_put(bmc->dev); + bmc->dev = NULL; printk(KERN_ERR "ipmi_msghandler:" " Unable to register bmc device: %d\n", @@ -2130,57 +2388,6 @@ static int ipmi_bmc_register(ipmi_smi_t intf) return rv; } - bmc->device_id_attr.attr.name = "device_id"; - bmc->device_id_attr.attr.owner = THIS_MODULE; - bmc->device_id_attr.attr.mode = S_IRUGO; - bmc->device_id_attr.show = device_id_show; - - bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs"; - bmc->provides_dev_sdrs_attr.attr.owner = THIS_MODULE; - bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO; - bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show; - - bmc->revision_attr.attr.name = "revision"; - bmc->revision_attr.attr.owner = THIS_MODULE; - bmc->revision_attr.attr.mode = S_IRUGO; - bmc->revision_attr.show = revision_show; - - bmc->firmware_rev_attr.attr.name = "firmware_revision"; - bmc->firmware_rev_attr.attr.owner = THIS_MODULE; - bmc->firmware_rev_attr.attr.mode = S_IRUGO; - bmc->firmware_rev_attr.show = firmware_rev_show; - - bmc->version_attr.attr.name = "ipmi_version"; - bmc->version_attr.attr.owner = THIS_MODULE; - bmc->version_attr.attr.mode = S_IRUGO; - bmc->version_attr.show = ipmi_version_show; - - bmc->add_dev_support_attr.attr.name - = "additional_device_support"; - bmc->add_dev_support_attr.attr.owner = THIS_MODULE; - bmc->add_dev_support_attr.attr.mode = S_IRUGO; - bmc->add_dev_support_attr.show = add_dev_support_show; - - bmc->manufacturer_id_attr.attr.name = "manufacturer_id"; - bmc->manufacturer_id_attr.attr.owner = THIS_MODULE; - bmc->manufacturer_id_attr.attr.mode = S_IRUGO; - bmc->manufacturer_id_attr.show = manufacturer_id_show; - - bmc->product_id_attr.attr.name = "product_id"; - bmc->product_id_attr.attr.owner = THIS_MODULE; - bmc->product_id_attr.attr.mode = S_IRUGO; - bmc->product_id_attr.show = product_id_show; - - bmc->guid_attr.attr.name = "guid"; - bmc->guid_attr.attr.owner = THIS_MODULE; - bmc->guid_attr.attr.mode = S_IRUGO; - bmc->guid_attr.show = guid_show; - - bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision"; - bmc->aux_firmware_rev_attr.attr.owner = THIS_MODULE; - bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO; - bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show; - rv = create_files(bmc); if (rv) { mutex_lock(&ipmidriver_mutex); @@ -2202,29 +2409,44 @@ static int ipmi_bmc_register(ipmi_smi_t intf) * create symlink from system interface device to bmc device * and back. */ + intf->sysfs_name = kstrdup(sysfs_name, GFP_KERNEL); + if (!intf->sysfs_name) { + rv = -ENOMEM; + printk(KERN_ERR + "ipmi_msghandler: allocate link to BMC: %d\n", + rv); + goto out_err; + } + rv = sysfs_create_link(&intf->si_dev->kobj, - &bmc->dev->dev.kobj, "bmc"); + &bmc->dev->dev.kobj, intf->sysfs_name); if (rv) { + kfree(intf->sysfs_name); + intf->sysfs_name = NULL; printk(KERN_ERR "ipmi_msghandler: Unable to create bmc symlink: %d\n", rv); goto out_err; } - size = snprintf(dummy, 0, "ipmi%d", intf->intf_num); + size = snprintf(dummy, 0, "ipmi%d", ifnum); intf->my_dev_name = kmalloc(size+1, GFP_KERNEL); if (!intf->my_dev_name) { + kfree(intf->sysfs_name); + intf->sysfs_name = NULL; rv = -ENOMEM; printk(KERN_ERR "ipmi_msghandler: allocate link from BMC: %d\n", rv); goto out_err; } - snprintf(intf->my_dev_name, size+1, "ipmi%d", intf->intf_num); + snprintf(intf->my_dev_name, size+1, "ipmi%d", ifnum); rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj, intf->my_dev_name); if (rv) { + kfree(intf->sysfs_name); + intf->sysfs_name = NULL; kfree(intf->my_dev_name); intf->my_dev_name = NULL; printk(KERN_ERR @@ -2409,17 +2631,14 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, void *send_info, struct ipmi_device_id *device_id, struct device *si_dev, + const char *sysfs_name, unsigned char slave_addr) { int i, j; int rv; ipmi_smi_t intf; - unsigned long flags; - int version_major; - int version_minor; - - version_major = ipmi_version_major(device_id); - version_minor = ipmi_version_minor(device_id); + ipmi_smi_t tintf; + struct list_head *link; /* Make sure the driver is actually initialized, this handles problems with initialization order. */ @@ -2437,12 +2656,16 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, if (!intf) return -ENOMEM; memset(intf, 0, sizeof(*intf)); + + intf->ipmi_version_major = ipmi_version_major(device_id); + intf->ipmi_version_minor = ipmi_version_minor(device_id); + intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL); if (!intf->bmc) { kfree(intf); return -ENOMEM; } - intf->intf_num = -1; + intf->intf_num = -1; /* Mark it invalid for now. */ kref_init(&intf->refcount); intf->bmc->id = *device_id; intf->si_dev = si_dev; @@ -2470,26 +2693,30 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, INIT_LIST_HEAD(&intf->waiting_events); intf->waiting_events_count = 0; mutex_init(&intf->cmd_rcvrs_mutex); + spin_lock_init(&intf->maintenance_mode_lock); INIT_LIST_HEAD(&intf->cmd_rcvrs); init_waitqueue_head(&intf->waitq); spin_lock_init(&intf->counter_lock); intf->proc_dir = NULL; - rv = -ENOMEM; - spin_lock_irqsave(&interfaces_lock, flags); - for (i = 0; i < MAX_IPMI_INTERFACES; i++) { - if (ipmi_interfaces[i] == NULL) { - intf->intf_num = i; - /* Reserve the entry till we are done. */ - ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY; - rv = 0; + mutex_lock(&smi_watchers_mutex); + mutex_lock(&ipmi_interfaces_mutex); + /* Look for a hole in the numbers. */ + i = 0; + link = &ipmi_interfaces; + list_for_each_entry_rcu(tintf, &ipmi_interfaces, link) { + if (tintf->intf_num != i) { + link = &tintf->link; break; } + i++; } - spin_unlock_irqrestore(&interfaces_lock, flags); - if (rv) - goto out; + /* Add the new interface in numeric order. */ + if (i == 0) + list_add_rcu(&intf->link, &ipmi_interfaces); + else + list_add_tail_rcu(&intf->link, link); rv = handlers->start_processing(send_info, intf); if (rv) @@ -2497,8 +2724,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, get_guid(intf); - if ((version_major > 1) - || ((version_major == 1) && (version_minor >= 5))) + if ((intf->ipmi_version_major > 1) + || ((intf->ipmi_version_major == 1) + && (intf->ipmi_version_minor >= 5))) { /* Start scanning the channels to see what is available. */ @@ -2521,64 +2749,67 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, if (rv == 0) rv = add_proc_entries(intf, i); - rv = ipmi_bmc_register(intf); + rv = ipmi_bmc_register(intf, i, sysfs_name); out: if (rv) { if (intf->proc_dir) remove_proc_entries(intf); + intf->handlers = NULL; + list_del_rcu(&intf->link); + mutex_unlock(&ipmi_interfaces_mutex); + mutex_unlock(&smi_watchers_mutex); + synchronize_rcu(); kref_put(&intf->refcount, intf_free); - if (i < MAX_IPMI_INTERFACES) { - spin_lock_irqsave(&interfaces_lock, flags); - ipmi_interfaces[i] = NULL; - spin_unlock_irqrestore(&interfaces_lock, flags); - } } else { - spin_lock_irqsave(&interfaces_lock, flags); - ipmi_interfaces[i] = intf; - spin_unlock_irqrestore(&interfaces_lock, flags); + /* After this point the interface is legal to use. */ + intf->intf_num = i; + mutex_unlock(&ipmi_interfaces_mutex); call_smi_watchers(i, intf->si_dev); + mutex_unlock(&smi_watchers_mutex); } return rv; } +static void cleanup_smi_msgs(ipmi_smi_t intf) +{ + int i; + struct seq_table *ent; + + /* No need for locks, the interface is down. */ + for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) { + ent = &(intf->seq_table[i]); + if (!ent->inuse) + continue; + deliver_err_response(ent->recv_msg, IPMI_ERR_UNSPECIFIED); + } +} + int ipmi_unregister_smi(ipmi_smi_t intf) { - int i; struct ipmi_smi_watcher *w; - unsigned long flags; + int intf_num = intf->intf_num; ipmi_bmc_unregister(intf); - spin_lock_irqsave(&interfaces_lock, flags); - for (i = 0; i < MAX_IPMI_INTERFACES; i++) { - if (ipmi_interfaces[i] == intf) { - /* Set the interface number reserved until we - * are done. */ - ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY; - intf->intf_num = -1; - break; - } - } - spin_unlock_irqrestore(&interfaces_lock,flags); + mutex_lock(&smi_watchers_mutex); + mutex_lock(&ipmi_interfaces_mutex); + intf->intf_num = -1; + intf->handlers = NULL; + list_del_rcu(&intf->link); + mutex_unlock(&ipmi_interfaces_mutex); + synchronize_rcu(); - if (i == MAX_IPMI_INTERFACES) - return -ENODEV; + cleanup_smi_msgs(intf); remove_proc_entries(intf); /* Call all the watcher interfaces to tell them that an interface is gone. */ - down_read(&smi_watchers_sem); list_for_each_entry(w, &smi_watchers, link) - w->smi_gone(i); - up_read(&smi_watchers_sem); - - /* Allow the entry to be reused now. */ - spin_lock_irqsave(&interfaces_lock, flags); - ipmi_interfaces[i] = NULL; - spin_unlock_irqrestore(&interfaces_lock,flags); + w->smi_gone(intf_num); + mutex_unlock(&smi_watchers_mutex); kref_put(&intf->refcount, intf_free); return 0; @@ -2660,6 +2891,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, struct ipmi_ipmb_addr *ipmb_addr; struct ipmi_recv_msg *recv_msg; unsigned long flags; + struct ipmi_smi_handlers *handlers; if (msg->rsp_size < 10) { /* Message not big enough, just ignore it. */ @@ -2716,10 +2948,16 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, printk("\n"); } #endif - intf->handlers->sender(intf->send_info, msg, 0); - - rv = -1; /* We used the message, so return the value that - causes it to not be freed or queued. */ + rcu_read_lock(); + handlers = intf->handlers; + if (handlers) { + handlers->sender(intf->send_info, msg, 0); + /* We used the message, so return the value + that causes it to not be freed or + queued. */ + rv = -1; + } + rcu_read_unlock(); } else { /* Deliver the message to the user. */ spin_lock_irqsave(&intf->counter_lock, flags); @@ -3309,16 +3547,6 @@ void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf) rcu_read_unlock(); } -static void -handle_msg_timeout(struct ipmi_recv_msg *msg) -{ - msg->recv_type = IPMI_RESPONSE_RECV_TYPE; - msg->msg_data[0] = IPMI_TIMEOUT_COMPLETION_CODE; - msg->msg.netfn |= 1; /* Convert to a response. */ - msg->msg.data_len = 1; - msg->msg.data = msg->msg_data; - deliver_response(msg); -} static struct ipmi_smi_msg * smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, @@ -3350,7 +3578,11 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, struct list_head *timeouts, long timeout_period, int slot, unsigned long *flags) { - struct ipmi_recv_msg *msg; + struct ipmi_recv_msg *msg; + struct ipmi_smi_handlers *handlers; + + if (intf->intf_num == -1) + return; if (!ent->inuse) return; @@ -3393,13 +3625,19 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, return; spin_unlock_irqrestore(&intf->seq_lock, *flags); + /* Send the new message. We send with a zero * priority. It timed out, I doubt time is * that critical now, and high priority * messages are really only for messages to the * local MC, which don't get resent. */ - intf->handlers->sender(intf->send_info, - smi_msg, 0); + handlers = intf->handlers; + if (handlers) + intf->handlers->sender(intf->send_info, + smi_msg, 0); + else + ipmi_free_smi_msg(smi_msg); + spin_lock_irqsave(&intf->seq_lock, *flags); } } @@ -3411,18 +3649,12 @@ static void ipmi_timeout_handler(long timeout_period) struct ipmi_recv_msg *msg, *msg2; struct ipmi_smi_msg *smi_msg, *smi_msg2; unsigned long flags; - int i, j; + int i; INIT_LIST_HEAD(&timeouts); - spin_lock(&interfaces_lock); - for (i = 0; i < MAX_IPMI_INTERFACES; i++) { - intf = ipmi_interfaces[i]; - if (IPMI_INVALID_INTERFACE(intf)) - continue; - kref_get(&intf->refcount); - spin_unlock(&interfaces_lock); - + rcu_read_lock(); + list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { /* See if any waiting messages need to be processed. */ spin_lock_irqsave(&intf->waiting_msgs_lock, flags); list_for_each_entry_safe(smi_msg, smi_msg2, @@ -3442,35 +3674,60 @@ static void ipmi_timeout_handler(long timeout_period) have timed out, putting them in the timeouts list. */ spin_lock_irqsave(&intf->seq_lock, flags); - for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) - check_msg_timeout(intf, &(intf->seq_table[j]), - &timeouts, timeout_period, j, + for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) + check_msg_timeout(intf, &(intf->seq_table[i]), + &timeouts, timeout_period, i, &flags); spin_unlock_irqrestore(&intf->seq_lock, flags); list_for_each_entry_safe(msg, msg2, &timeouts, link) - handle_msg_timeout(msg); - - kref_put(&intf->refcount, intf_free); - spin_lock(&interfaces_lock); + deliver_err_response(msg, IPMI_TIMEOUT_COMPLETION_CODE); + + /* + * Maintenance mode handling. Check the timeout + * optimistically before we claim the lock. It may + * mean a timeout gets missed occasionally, but that + * only means the timeout gets extended by one period + * in that case. No big deal, and it avoids the lock + * most of the time. + */ + if (intf->auto_maintenance_timeout > 0) { + spin_lock_irqsave(&intf->maintenance_mode_lock, flags); + if (intf->auto_maintenance_timeout > 0) { + intf->auto_maintenance_timeout + -= timeout_period; + if (!intf->maintenance_mode + && (intf->auto_maintenance_timeout <= 0)) + { + intf->maintenance_mode_enable = 0; + maintenance_mode_update(intf); + } + } + spin_unlock_irqrestore(&intf->maintenance_mode_lock, + flags); + } } - spin_unlock(&interfaces_lock); + rcu_read_unlock(); } static void ipmi_request_event(void) { - ipmi_smi_t intf; - int i; + ipmi_smi_t intf; + struct ipmi_smi_handlers *handlers; - spin_lock(&interfaces_lock); - for (i = 0; i < MAX_IPMI_INTERFACES; i++) { - intf = ipmi_interfaces[i]; - if (IPMI_INVALID_INTERFACE(intf)) + rcu_read_lock(); + /* Called from the timer, no need to check if handlers is + * valid. */ + list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { + /* No event requests when in maintenance mode. */ + if (intf->maintenance_mode_enable) continue; - intf->handlers->request_events(intf->send_info); + handlers = intf->handlers; + if (handlers) + handlers->request_events(intf->send_info); } - spin_unlock(&interfaces_lock); + rcu_read_unlock(); } static struct timer_list ipmi_timer; @@ -3599,7 +3856,6 @@ static void send_panic_events(char *str) struct kernel_ipmi_msg msg; ipmi_smi_t intf; unsigned char data[16]; - int i; struct ipmi_system_interface_addr *si; struct ipmi_addr addr; struct ipmi_smi_msg smi_msg; @@ -3633,9 +3889,9 @@ static void send_panic_events(char *str) recv_msg.done = dummy_recv_done_handler; /* For every registered interface, send the event. */ - for (i = 0; i < MAX_IPMI_INTERFACES; i++) { - intf = ipmi_interfaces[i]; - if (IPMI_INVALID_INTERFACE(intf)) + list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { + if (!intf->handlers) + /* Interface is not ready. */ continue; /* Send the event announcing the panic. */ @@ -3660,13 +3916,14 @@ static void send_panic_events(char *str) if (!str) return; - for (i = 0; i < MAX_IPMI_INTERFACES; i++) { + /* For every registered interface, send the event. */ + list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { char *p = str; struct ipmi_ipmb_addr *ipmb; int j; - intf = ipmi_interfaces[i]; - if (IPMI_INVALID_INTERFACE(intf)) + if (intf->intf_num == -1) + /* Interface was not ready yet. */ continue; /* First job here is to figure out where to send the @@ -3792,7 +4049,6 @@ static int panic_event(struct notifier_block *this, unsigned long event, void *ptr) { - int i; ipmi_smi_t intf; if (has_panicked) @@ -3800,9 +4056,9 @@ static int panic_event(struct notifier_block *this, has_panicked = 1; /* For every registered interface, set it to run to completion. */ - for (i = 0; i < MAX_IPMI_INTERFACES; i++) { - intf = ipmi_interfaces[i]; - if (IPMI_INVALID_INTERFACE(intf)) + list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { + if (!intf->handlers) + /* Interface is not ready. */ continue; intf->handlers->set_run_to_completion(intf->send_info, 1); @@ -3823,7 +4079,6 @@ static struct notifier_block panic_block = { static int ipmi_init_msghandler(void) { - int i; int rv; if (initialized) @@ -3838,9 +4093,6 @@ static int ipmi_init_msghandler(void) printk(KERN_INFO "ipmi message handler version " IPMI_DRIVER_VERSION "\n"); - for (i = 0; i < MAX_IPMI_INTERFACES; i++) - ipmi_interfaces[i] = NULL; - #ifdef CONFIG_PROC_FS proc_ipmi_root = proc_mkdir("ipmi", NULL); if (!proc_ipmi_root) { diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index 8d941db83457..597eb4f88b84 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -43,6 +43,9 @@ #define PFX "IPMI poweroff: " +static void ipmi_po_smi_gone(int if_num); +static void ipmi_po_new_smi(int if_num, struct device *device); + /* Definitions for controlling power off (if the system supports it). It * conveniently matches the IPMI chassis control values. */ #define IPMI_CHASSIS_POWER_DOWN 0 /* power down, the default. */ @@ -51,6 +54,37 @@ /* the IPMI data command */ static int poweroff_powercycle; +/* Which interface to use, -1 means the first we see. */ +static int ifnum_to_use = -1; + +/* Our local state. */ +static int ready = 0; +static ipmi_user_t ipmi_user; +static int ipmi_ifnum; +static void (*specific_poweroff_func)(ipmi_user_t user) = NULL; + +/* Holds the old poweroff function so we can restore it on removal. */ +static void (*old_poweroff_func)(void); + +static int set_param_ifnum(const char *val, struct kernel_param *kp) +{ + int rv = param_set_int(val, kp); + if (rv) + return rv; + if ((ifnum_to_use < 0) || (ifnum_to_use == ipmi_ifnum)) + return 0; + + ipmi_po_smi_gone(ipmi_ifnum); + ipmi_po_new_smi(ifnum_to_use, NULL); + return 0; +} + +module_param_call(ifnum_to_use, set_param_ifnum, param_get_int, + &ifnum_to_use, 0644); +MODULE_PARM_DESC(ifnum_to_use, "The interface number to use for the watchdog " + "timer. Setting to -1 defaults to the first registered " + "interface"); + /* parameter definition to allow user to flag power cycle */ module_param(poweroff_powercycle, int, 0644); MODULE_PARM_DESC(poweroff_powercycle, " Set to non-zero to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down."); @@ -142,6 +176,42 @@ static int ipmi_request_in_rc_mode(ipmi_user_t user, #define IPMI_ATCA_GET_ADDR_INFO_CMD 0x01 #define IPMI_PICMG_ID 0 +#define IPMI_NETFN_OEM 0x2e +#define IPMI_ATCA_PPS_GRACEFUL_RESTART 0x11 +#define IPMI_ATCA_PPS_IANA "\x00\x40\x0A" +#define IPMI_MOTOROLA_MANUFACTURER_ID 0x0000A1 +#define IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID 0x0051 + +static void (*atca_oem_poweroff_hook)(ipmi_user_t user) = NULL; + +static void pps_poweroff_atca (ipmi_user_t user) +{ + struct ipmi_system_interface_addr smi_addr; + struct kernel_ipmi_msg send_msg; + int rv; + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; + + printk(KERN_INFO PFX "PPS powerdown hook used"); + + send_msg.netfn = IPMI_NETFN_OEM; + send_msg.cmd = IPMI_ATCA_PPS_GRACEFUL_RESTART; + send_msg.data = IPMI_ATCA_PPS_IANA; + send_msg.data_len = 3; + rv = ipmi_request_in_rc_mode(user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) { + printk(KERN_ERR PFX "Unable to send ATCA ," + " IPMI error 0x%x\n", rv); + } + return; +} + static int ipmi_atca_detect (ipmi_user_t user) { struct ipmi_system_interface_addr smi_addr; @@ -167,6 +237,13 @@ static int ipmi_atca_detect (ipmi_user_t user) rv = ipmi_request_wait_for_response(user, (struct ipmi_addr *) &smi_addr, &send_msg); + + printk(KERN_INFO PFX "ATCA Detect mfg 0x%X prod 0x%X\n", mfg_id, prod_id); + if((mfg_id == IPMI_MOTOROLA_MANUFACTURER_ID) + && (prod_id == IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID)) { + printk(KERN_INFO PFX "Installing Pigeon Point Systems Poweroff Hook\n"); + atca_oem_poweroff_hook = pps_poweroff_atca; + } return !rv; } @@ -200,12 +277,19 @@ static void ipmi_poweroff_atca (ipmi_user_t user) rv = ipmi_request_in_rc_mode(user, (struct ipmi_addr *) &smi_addr, &send_msg); - if (rv) { + /** At this point, the system may be shutting down, and most + ** serial drivers (if used) will have interrupts turned off + ** it may be better to ignore IPMI_UNKNOWN_ERR_COMPLETION_CODE + ** return code + **/ + if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) { printk(KERN_ERR PFX "Unable to send ATCA powerdown message," " IPMI error 0x%x\n", rv); goto out; } + if(atca_oem_poweroff_hook) + return atca_oem_poweroff_hook(user); out: return; } @@ -440,15 +524,6 @@ static struct poweroff_function poweroff_functions[] = { / sizeof(struct poweroff_function)) -/* Our local state. */ -static int ready = 0; -static ipmi_user_t ipmi_user; -static void (*specific_poweroff_func)(ipmi_user_t user) = NULL; - -/* Holds the old poweroff function so we can restore it on removal. */ -static void (*old_poweroff_func)(void); - - /* Called on a powerdown request. */ static void ipmi_poweroff_function (void) { @@ -473,6 +548,9 @@ static void ipmi_po_new_smi(int if_num, struct device *device) if (ready) return; + if ((ifnum_to_use >= 0) && (ifnum_to_use != if_num)) + return; + rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, &ipmi_user); if (rv) { @@ -481,6 +559,8 @@ static void ipmi_po_new_smi(int if_num, struct device *device) return; } + ipmi_ifnum = if_num; + /* * Do a get device ide and store some results, since this is * used by several functions. @@ -541,9 +621,15 @@ static void ipmi_po_new_smi(int if_num, struct device *device) static void ipmi_po_smi_gone(int if_num) { - /* This can never be called, because once poweroff driver is - registered, the interface can't go away until the power - driver is unregistered. */ + if (!ready) + return; + + if (ipmi_ifnum != if_num) + return; + + ready = 0; + ipmi_destroy_user(ipmi_user); + pm_power_off = old_poweroff_func; } static struct ipmi_smi_watcher smi_watcher = @@ -616,9 +702,9 @@ static int ipmi_poweroff_init (void) printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); goto out_err; } -#endif out_err: +#endif return rv; } diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index bb1fac104fda..81a0c89598e7 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -61,6 +61,10 @@ #include "ipmi_si_sm.h" #include <linux/init.h> #include <linux/dmi.h> +#include <linux/string.h> +#include <linux/ctype.h> + +#define PFX "ipmi_si: " /* Measure times between events in the driver. */ #undef DEBUG_TIMING @@ -92,7 +96,7 @@ enum si_intf_state { enum si_type { SI_KCS, SI_SMIC, SI_BT }; -static char *si_to_str[] = { "KCS", "SMIC", "BT" }; +static char *si_to_str[] = { "kcs", "smic", "bt" }; #define DEVICE_NAME "ipmi_si" @@ -222,7 +226,10 @@ struct smi_info static int force_kipmid[SI_MAX_PARMS]; static int num_force_kipmid; +static int unload_when_empty = 1; + static int try_smi_init(struct smi_info *smi); +static void cleanup_one_si(struct smi_info *to_clean); static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list); static int register_xaction_notifier(struct notifier_block * nb) @@ -240,14 +247,18 @@ static void deliver_recv_msg(struct smi_info *smi_info, spin_lock(&(smi_info->si_lock)); } -static void return_hosed_msg(struct smi_info *smi_info) +static void return_hosed_msg(struct smi_info *smi_info, int cCode) { struct ipmi_smi_msg *msg = smi_info->curr_msg; + if (cCode < 0 || cCode > IPMI_ERR_UNSPECIFIED) + cCode = IPMI_ERR_UNSPECIFIED; + /* else use it as is */ + /* Make it a reponse */ msg->rsp[0] = msg->data[0] | 4; msg->rsp[1] = msg->data[1]; - msg->rsp[2] = 0xFF; /* Unknown error. */ + msg->rsp[2] = cCode; msg->rsp_size = 3; smi_info->curr_msg = NULL; @@ -298,7 +309,7 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) smi_info->curr_msg->data, smi_info->curr_msg->data_size); if (err) { - return_hosed_msg(smi_info); + return_hosed_msg(smi_info, err); } rv = SI_SM_CALL_WITHOUT_DELAY; @@ -640,7 +651,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, /* If we were handling a user message, format a response to send to the upper layer to tell it about the error. */ - return_hosed_msg(smi_info); + return_hosed_msg(smi_info, IPMI_ERR_UNSPECIFIED); } si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0); } @@ -684,22 +695,24 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, { /* We are idle and the upper layer requested that I fetch events, so do so. */ - unsigned char msg[2]; + atomic_set(&smi_info->req_events, 0); - spin_lock(&smi_info->count_lock); - smi_info->flag_fetches++; - spin_unlock(&smi_info->count_lock); + smi_info->curr_msg = ipmi_alloc_smi_msg(); + if (!smi_info->curr_msg) + goto out; - atomic_set(&smi_info->req_events, 0); - msg[0] = (IPMI_NETFN_APP_REQUEST << 2); - msg[1] = IPMI_GET_MSG_FLAGS_CMD; + smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2); + smi_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD; + smi_info->curr_msg->data_size = 2; smi_info->handlers->start_transaction( - smi_info->si_sm, msg, 2); - smi_info->si_state = SI_GETTING_FLAGS; + smi_info->si_sm, + smi_info->curr_msg->data, + smi_info->curr_msg->data_size); + smi_info->si_state = SI_GETTING_EVENTS; goto restart; } - + out: return si_sm_result; } @@ -714,6 +727,15 @@ static void sender(void *send_info, struct timeval t; #endif + if (atomic_read(&smi_info->stop_operation)) { + msg->rsp[0] = msg->data[0] | 4; + msg->rsp[1] = msg->data[1]; + msg->rsp[2] = IPMI_ERR_UNSPECIFIED; + msg->rsp_size = 3; + deliver_recv_msg(smi_info, msg); + return; + } + spin_lock_irqsave(&(smi_info->msg_lock), flags); #ifdef DEBUG_TIMING do_gettimeofday(&t); @@ -805,13 +827,21 @@ static void poll(void *send_info) { struct smi_info *smi_info = send_info; - smi_event_handler(smi_info, 0); + /* + * Make sure there is some delay in the poll loop so we can + * drive time forward and timeout things. + */ + udelay(10); + smi_event_handler(smi_info, 10); } static void request_events(void *send_info) { struct smi_info *smi_info = send_info; + if (atomic_read(&smi_info->stop_operation)) + return; + atomic_set(&smi_info->req_events, 1); } @@ -949,12 +979,21 @@ static int smi_start_processing(void *send_info, return 0; } +static void set_maintenance_mode(void *send_info, int enable) +{ + struct smi_info *smi_info = send_info; + + if (!enable) + atomic_set(&smi_info->req_events, 0); +} + static struct ipmi_smi_handlers handlers = { .owner = THIS_MODULE, .start_processing = smi_start_processing, .sender = sender, .request_events = request_events, + .set_maintenance_mode = set_maintenance_mode, .set_run_to_completion = set_run_to_completion, .poll = poll, }; @@ -987,6 +1026,16 @@ static int num_regshifts = 0; static int slave_addrs[SI_MAX_PARMS]; static int num_slave_addrs = 0; +#define IPMI_IO_ADDR_SPACE 0 +#define IPMI_MEM_ADDR_SPACE 1 +static char *addr_space_to_str[] = { "I/O", "mem" }; + +static int hotmod_handler(const char *val, struct kernel_param *kp); + +module_param_call(hotmod, hotmod_handler, NULL, NULL, 0200); +MODULE_PARM_DESC(hotmod, "Add and remove interfaces. See" + " Documentation/IPMI.txt in the kernel sources for the" + " gory details."); module_param_named(trydefaults, si_trydefaults, bool, 0); MODULE_PARM_DESC(trydefaults, "Setting this to 'false' will disable the" @@ -1038,12 +1087,12 @@ module_param_array(force_kipmid, int, &num_force_kipmid, 0); MODULE_PARM_DESC(force_kipmid, "Force the kipmi daemon to be enabled (1) or" " disabled(0). Normally the IPMI driver auto-detects" " this, but the value may be overridden by this parm."); +module_param(unload_when_empty, int, 0); +MODULE_PARM_DESC(unload_when_empty, "Unload the module if no interfaces are" + " specified or found, default is 1. Setting to 0" + " is useful for hot add of devices using hotmod."); -#define IPMI_IO_ADDR_SPACE 0 -#define IPMI_MEM_ADDR_SPACE 1 -static char *addr_space_to_str[] = { "I/O", "memory" }; - static void std_irq_cleanup(struct smi_info *info) { if (info->si_type == SI_BT) @@ -1317,6 +1366,234 @@ static int mem_setup(struct smi_info *info) return 0; } +/* + * Parms come in as <op1>[:op2[:op3...]]. ops are: + * add|remove,kcs|bt|smic,mem|i/o,<address>[,<opt1>[,<opt2>[,...]]] + * Options are: + * rsp=<regspacing> + * rsi=<regsize> + * rsh=<regshift> + * irq=<irq> + * ipmb=<ipmb addr> + */ +enum hotmod_op { HM_ADD, HM_REMOVE }; +struct hotmod_vals { + char *name; + int val; +}; +static struct hotmod_vals hotmod_ops[] = { + { "add", HM_ADD }, + { "remove", HM_REMOVE }, + { NULL } +}; +static struct hotmod_vals hotmod_si[] = { + { "kcs", SI_KCS }, + { "smic", SI_SMIC }, + { "bt", SI_BT }, + { NULL } +}; +static struct hotmod_vals hotmod_as[] = { + { "mem", IPMI_MEM_ADDR_SPACE }, + { "i/o", IPMI_IO_ADDR_SPACE }, + { NULL } +}; +static int ipmi_strcasecmp(const char *s1, const char *s2) +{ + while (*s1 || *s2) { + if (!*s1) + return -1; + if (!*s2) + return 1; + if (*s1 != *s2) + return *s1 - *s2; + s1++; + s2++; + } + return 0; +} +static int parse_str(struct hotmod_vals *v, int *val, char *name, char **curr) +{ + char *s; + int i; + + s = strchr(*curr, ','); + if (!s) { + printk(KERN_WARNING PFX "No hotmod %s given.\n", name); + return -EINVAL; + } + *s = '\0'; + s++; + for (i = 0; hotmod_ops[i].name; i++) { + if (ipmi_strcasecmp(*curr, v[i].name) == 0) { + *val = v[i].val; + *curr = s; + return 0; + } + } + + printk(KERN_WARNING PFX "Invalid hotmod %s '%s'\n", name, *curr); + return -EINVAL; +} + +static int hotmod_handler(const char *val, struct kernel_param *kp) +{ + char *str = kstrdup(val, GFP_KERNEL); + int rv = -EINVAL; + char *next, *curr, *s, *n, *o; + enum hotmod_op op; + enum si_type si_type; + int addr_space; + unsigned long addr; + int regspacing; + int regsize; + int regshift; + int irq; + int ipmb; + int ival; + struct smi_info *info; + + if (!str) + return -ENOMEM; + + /* Kill any trailing spaces, as we can get a "\n" from echo. */ + ival = strlen(str) - 1; + while ((ival >= 0) && isspace(str[ival])) { + str[ival] = '\0'; + ival--; + } + + for (curr = str; curr; curr = next) { + regspacing = 1; + regsize = 1; + regshift = 0; + irq = 0; + ipmb = 0x20; + + next = strchr(curr, ':'); + if (next) { + *next = '\0'; + next++; + } + + rv = parse_str(hotmod_ops, &ival, "operation", &curr); + if (rv) + break; + op = ival; + + rv = parse_str(hotmod_si, &ival, "interface type", &curr); + if (rv) + break; + si_type = ival; + + rv = parse_str(hotmod_as, &addr_space, "address space", &curr); + if (rv) + break; + + s = strchr(curr, ','); + if (s) { + *s = '\0'; + s++; + } + addr = simple_strtoul(curr, &n, 0); + if ((*n != '\0') || (*curr == '\0')) { + printk(KERN_WARNING PFX "Invalid hotmod address" + " '%s'\n", curr); + break; + } + + while (s) { + curr = s; + s = strchr(curr, ','); + if (s) { + *s = '\0'; + s++; + } + o = strchr(curr, '='); + if (o) { + *o = '\0'; + o++; + } +#define HOTMOD_INT_OPT(name, val) \ + if (ipmi_strcasecmp(curr, name) == 0) { \ + if (!o) { \ + printk(KERN_WARNING PFX \ + "No option given for '%s'\n", \ + curr); \ + goto out; \ + } \ + val = simple_strtoul(o, &n, 0); \ + if ((*n != '\0') || (*o == '\0')) { \ + printk(KERN_WARNING PFX \ + "Bad option given for '%s'\n", \ + curr); \ + goto out; \ + } \ + } + + HOTMOD_INT_OPT("rsp", regspacing) + else HOTMOD_INT_OPT("rsi", regsize) + else HOTMOD_INT_OPT("rsh", regshift) + else HOTMOD_INT_OPT("irq", irq) + else HOTMOD_INT_OPT("ipmb", ipmb) + else { + printk(KERN_WARNING PFX + "Invalid hotmod option '%s'\n", + curr); + goto out; + } +#undef HOTMOD_INT_OPT + } + + if (op == HM_ADD) { + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + rv = -ENOMEM; + goto out; + } + + info->addr_source = "hotmod"; + info->si_type = si_type; + info->io.addr_data = addr; + info->io.addr_type = addr_space; + if (addr_space == IPMI_MEM_ADDR_SPACE) + info->io_setup = mem_setup; + else + info->io_setup = port_setup; + + info->io.addr = NULL; + info->io.regspacing = regspacing; + if (!info->io.regspacing) + info->io.regspacing = DEFAULT_REGSPACING; + info->io.regsize = regsize; + if (!info->io.regsize) + info->io.regsize = DEFAULT_REGSPACING; + info->io.regshift = regshift; + info->irq = irq; + if (info->irq) + info->irq_setup = std_irq_setup; + info->slave_addr = ipmb; + + try_smi_init(info); + } else { + /* remove */ + struct smi_info *e, *tmp_e; + + mutex_lock(&smi_infos_lock); + list_for_each_entry_safe(e, tmp_e, &smi_infos, link) { + if (e->io.addr_type != addr_space) + continue; + if (e->si_type != si_type) + continue; + if (e->io.addr_data == addr) + cleanup_one_si(e); + } + mutex_unlock(&smi_infos_lock); + } + } + out: + kfree(str); + return rv; +} static __devinit void hardcode_find_bmc(void) { @@ -1333,11 +1610,11 @@ static __devinit void hardcode_find_bmc(void) info->addr_source = "hardcoded"; - if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) { + if (!si_type[i] || ipmi_strcasecmp(si_type[i], "kcs") == 0) { info->si_type = SI_KCS; - } else if (strcmp(si_type[i], "smic") == 0) { + } else if (ipmi_strcasecmp(si_type[i], "smic") == 0) { info->si_type = SI_SMIC; - } else if (strcmp(si_type[i], "bt") == 0) { + } else if (ipmi_strcasecmp(si_type[i], "bt") == 0) { info->si_type = SI_BT; } else { printk(KERN_WARNING @@ -1952,19 +2229,9 @@ static int try_get_dev_id(struct smi_info *smi_info) static int type_file_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { - char *out = (char *) page; struct smi_info *smi = data; - switch (smi->si_type) { - case SI_KCS: - return sprintf(out, "kcs\n"); - case SI_SMIC: - return sprintf(out, "smic\n"); - case SI_BT: - return sprintf(out, "bt\n"); - default: - return 0; - } + return sprintf(page, "%s\n", si_to_str[smi->si_type]); } static int stat_file_read_proc(char *page, char **start, off_t off, @@ -2000,7 +2267,24 @@ static int stat_file_read_proc(char *page, char **start, off_t off, out += sprintf(out, "incoming_messages: %ld\n", smi->incoming_messages); - return (out - ((char *) page)); + return out - page; +} + +static int param_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct smi_info *smi = data; + + return sprintf(page, + "%s,%s,0x%lx,rsp=%d,rsi=%d,rsh=%d,irq=%d,ipmb=%d\n", + si_to_str[smi->si_type], + addr_space_to_str[smi->io.addr_type], + smi->io.addr_data, + smi->io.regspacing, + smi->io.regsize, + smi->io.regshift, + smi->irq, + smi->slave_addr); } /* @@ -2362,6 +2646,7 @@ static int try_smi_init(struct smi_info *new_smi) new_smi, &new_smi->device_id, new_smi->dev, + "bmc", new_smi->slave_addr); if (rv) { printk(KERN_ERR @@ -2390,6 +2675,16 @@ static int try_smi_init(struct smi_info *new_smi) goto out_err_stop_timer; } + rv = ipmi_smi_add_proc_entry(new_smi->intf, "params", + param_read_proc, NULL, + new_smi, THIS_MODULE); + if (rv) { + printk(KERN_ERR + "ipmi_si: Unable to create proc entry: %d\n", + rv); + goto out_err_stop_timer; + } + list_add_tail(&new_smi->link, &smi_infos); mutex_unlock(&smi_infos_lock); @@ -2483,7 +2778,12 @@ static __devinit int init_ipmi_si(void) #endif #ifdef CONFIG_PCI - pci_module_init(&ipmi_pci_driver); + rv = pci_register_driver(&ipmi_pci_driver); + if (rv){ + printk(KERN_ERR + "init_ipmi_si: Unable to register PCI driver: %d\n", + rv); + } #endif if (si_trydefaults) { @@ -2498,7 +2798,7 @@ static __devinit int init_ipmi_si(void) } mutex_lock(&smi_infos_lock); - if (list_empty(&smi_infos)) { + if (unload_when_empty && list_empty(&smi_infos)) { mutex_unlock(&smi_infos_lock); #ifdef CONFIG_PCI pci_unregister_driver(&ipmi_pci_driver); @@ -2513,7 +2813,7 @@ static __devinit int init_ipmi_si(void) } module_init(init_ipmi_si); -static void __devexit cleanup_one_si(struct smi_info *to_clean) +static void cleanup_one_si(struct smi_info *to_clean) { int rv; unsigned long flags; diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c index 39d7e5ef1a2b..e64ea7d25d24 100644 --- a/drivers/char/ipmi/ipmi_smic_sm.c +++ b/drivers/char/ipmi/ipmi_smic_sm.c @@ -141,12 +141,14 @@ static int start_smic_transaction(struct si_sm_data *smic, { unsigned int i; - if ((size < 2) || (size > MAX_SMIC_WRITE_SIZE)) { - return -1; - } - if ((smic->state != SMIC_IDLE) && (smic->state != SMIC_HOSED)) { - return -2; - } + if (size < 2) + return IPMI_REQ_LEN_INVALID_ERR; + if (size > MAX_SMIC_WRITE_SIZE) + return IPMI_REQ_LEN_EXCEEDED_ERR; + + if ((smic->state != SMIC_IDLE) && (smic->state != SMIC_HOSED)) + return IPMI_NOT_IN_MY_STATE_ERR; + if (smic_debug & SMIC_DEBUG_MSG) { printk(KERN_INFO "start_smic_transaction -"); for (i = 0; i < size; i ++) { diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 73f759eaa5a6..90fb2a541916 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -135,6 +135,7 @@ static int nowayout = WATCHDOG_NOWAYOUT; static ipmi_user_t watchdog_user = NULL; +static int watchdog_ifnum; /* Default the timeout to 10 seconds. */ static int timeout = 10; @@ -161,6 +162,8 @@ static struct fasync_struct *fasync_q = NULL; static char pretimeout_since_last_heartbeat = 0; static char expect_close; +static int ifnum_to_use = -1; + static DECLARE_RWSEM(register_sem); /* Parameters to ipmi_set_timeout */ @@ -169,6 +172,8 @@ static DECLARE_RWSEM(register_sem); #define IPMI_SET_TIMEOUT_FORCE_HB 2 static int ipmi_set_timeout(int do_heartbeat); +static void ipmi_register_watchdog(int ipmi_intf); +static void ipmi_unregister_watchdog(int ipmi_intf); /* If true, the driver will start running as soon as it is configured and ready. */ @@ -245,6 +250,26 @@ static int get_param_str(char *buffer, struct kernel_param *kp) return strlen(buffer); } + +static int set_param_wdog_ifnum(const char *val, struct kernel_param *kp) +{ + int rv = param_set_int(val, kp); + if (rv) + return rv; + if ((ifnum_to_use < 0) || (ifnum_to_use == watchdog_ifnum)) + return 0; + + ipmi_unregister_watchdog(watchdog_ifnum); + ipmi_register_watchdog(ifnum_to_use); + return 0; +} + +module_param_call(ifnum_to_use, set_param_wdog_ifnum, get_param_int, + &ifnum_to_use, 0644); +MODULE_PARM_DESC(ifnum_to_use, "The interface number to use for the watchdog " + "timer. Setting to -1 defaults to the first registered " + "interface"); + module_param_call(timeout, set_param_int, get_param_int, &timeout, 0644); MODULE_PARM_DESC(timeout, "Timeout value in seconds."); @@ -263,12 +288,13 @@ module_param_call(preop, set_param_str, get_param_str, preop_op, 0644); MODULE_PARM_DESC(preop, "Pretimeout driver operation. One of: " "preop_none, preop_panic, preop_give_data."); -module_param(start_now, int, 0); +module_param(start_now, int, 0444); MODULE_PARM_DESC(start_now, "Set to 1 to start the watchdog as" "soon as the driver is loaded."); module_param(nowayout, int, 0644); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " + "(default=CONFIG_WATCHDOG_NOWAYOUT)"); /* Default state of the timer. */ static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE; @@ -872,6 +898,11 @@ static void ipmi_register_watchdog(int ipmi_intf) if (watchdog_user) goto out; + if ((ifnum_to_use >= 0) && (ifnum_to_use != ipmi_intf)) + goto out; + + watchdog_ifnum = ipmi_intf; + rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &watchdog_user); if (rv < 0) { printk(KERN_CRIT PFX "Unable to register with ipmi\n"); @@ -901,6 +932,39 @@ static void ipmi_register_watchdog(int ipmi_intf) } } +static void ipmi_unregister_watchdog(int ipmi_intf) +{ + int rv; + + down_write(®ister_sem); + + if (!watchdog_user) + goto out; + + if (watchdog_ifnum != ipmi_intf) + goto out; + + /* Make sure no one can call us any more. */ + misc_deregister(&ipmi_wdog_miscdev); + + /* Wait to make sure the message makes it out. The lower layer has + pointers to our buffers, we want to make sure they are done before + we release our memory. */ + while (atomic_read(&set_timeout_tofree)) + schedule_timeout_uninterruptible(1); + + /* Disconnect from IPMI. */ + rv = ipmi_destroy_user(watchdog_user); + if (rv) { + printk(KERN_WARNING PFX "error unlinking from IPMI: %d\n", + rv); + } + watchdog_user = NULL; + + out: + up_write(®ister_sem); +} + #ifdef HAVE_NMI_HANDLER static int ipmi_nmi(void *dev_id, int cpu, int handled) @@ -1004,9 +1068,7 @@ static void ipmi_new_smi(int if_num, struct device *device) static void ipmi_smi_gone(int if_num) { - /* This can never be called, because once the watchdog is - registered, the interface can't go away until the watchdog - is unregistered. */ + ipmi_unregister_watchdog(if_num); } static struct ipmi_smi_watcher smi_watcher = @@ -1148,30 +1210,32 @@ static int __init ipmi_wdog_init(void) check_parms(); + register_reboot_notifier(&wdog_reboot_notifier); + atomic_notifier_chain_register(&panic_notifier_list, + &wdog_panic_notifier); + rv = ipmi_smi_watcher_register(&smi_watcher); if (rv) { #ifdef HAVE_NMI_HANDLER if (preaction_val == WDOG_PRETIMEOUT_NMI) release_nmi(&ipmi_nmi_handler); #endif + atomic_notifier_chain_unregister(&panic_notifier_list, + &wdog_panic_notifier); + unregister_reboot_notifier(&wdog_reboot_notifier); printk(KERN_WARNING PFX "can't register smi watcher\n"); return rv; } - register_reboot_notifier(&wdog_reboot_notifier); - atomic_notifier_chain_register(&panic_notifier_list, - &wdog_panic_notifier); - printk(KERN_INFO PFX "driver initialized\n"); return 0; } -static __exit void ipmi_unregister_watchdog(void) +static void __exit ipmi_wdog_exit(void) { - int rv; - - down_write(®ister_sem); + ipmi_smi_watcher_unregister(&smi_watcher); + ipmi_unregister_watchdog(watchdog_ifnum); #ifdef HAVE_NMI_HANDLER if (nmi_handler_registered) @@ -1179,37 +1243,8 @@ static __exit void ipmi_unregister_watchdog(void) #endif atomic_notifier_chain_unregister(&panic_notifier_list, - &wdog_panic_notifier); + &wdog_panic_notifier); unregister_reboot_notifier(&wdog_reboot_notifier); - - if (! watchdog_user) - goto out; - - /* Make sure no one can call us any more. */ - misc_deregister(&ipmi_wdog_miscdev); - - /* Wait to make sure the message makes it out. The lower layer has - pointers to our buffers, we want to make sure they are done before - we release our memory. */ - while (atomic_read(&set_timeout_tofree)) - schedule_timeout_uninterruptible(1); - - /* Disconnect from IPMI. */ - rv = ipmi_destroy_user(watchdog_user); - if (rv) { - printk(KERN_WARNING PFX "error unlinking from IPMI: %d\n", - rv); - } - watchdog_user = NULL; - - out: - up_write(®ister_sem); -} - -static void __exit ipmi_wdog_exit(void) -{ - ipmi_smi_watcher_unregister(&smi_watcher); - ipmi_unregister_watchdog(); } module_exit(ipmi_wdog_exit); module_init(ipmi_wdog_init); diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 58c955e390b3..1637c1d9a4ba 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -530,9 +530,9 @@ sched_again: /* Interrupt handlers */ -static void isicom_bottomhalf(void *data) +static void isicom_bottomhalf(struct work_struct *work) { - struct isi_port *port = (struct isi_port *) data; + struct isi_port *port = container_of(work, struct isi_port, bh_tqueue); struct tty_struct *tty = port->tty; if (!tty) @@ -1474,9 +1474,9 @@ static void isicom_start(struct tty_struct *tty) } /* hangup et all */ -static void do_isicom_hangup(void *data) +static void do_isicom_hangup(struct work_struct *work) { - struct isi_port *port = data; + struct isi_port *port = container_of(work, struct isi_port, hangup_tq); struct tty_struct *tty; tty = port->tty; @@ -1966,8 +1966,8 @@ static int __devinit isicom_setup(void) port->channel = channel; port->close_delay = 50 * HZ/100; port->closing_wait = 3000 * HZ/100; - INIT_WORK(&port->hangup_tq, do_isicom_hangup, port); - INIT_WORK(&port->bh_tqueue, isicom_bottomhalf, port); + INIT_WORK(&port->hangup_tq, do_isicom_hangup); + INIT_WORK(&port->bh_tqueue, isicom_bottomhalf); port->status = 0; init_waitqueue_head(&port->open_wait); init_waitqueue_head(&port->close_wait); diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index ffdf9df1a67a..8f591945ebd9 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -663,7 +663,7 @@ static int stli_initopen(stlibrd_t *brdp, stliport_t *portp); static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait); static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait); static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *filp); -static void stli_dohangup(void *arg); +static void stli_dohangup(struct work_struct *); static int stli_setport(stliport_t *portp); static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback); static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback); @@ -1990,9 +1990,9 @@ static void stli_start(struct tty_struct *tty) * aren't that time critical). */ -static void stli_dohangup(void *arg) +static void stli_dohangup(struct work_struct *ugly_api) { - stliport_t *portp = (stliport_t *) arg; + stliport_t *portp = container_of(ugly_api, stliport_t, tqhangup); if (portp->tty != NULL) { tty_hangup(portp->tty); } @@ -2898,7 +2898,7 @@ static int stli_initports(stlibrd_t *brdp) portp->baud_base = STL_BAUDBASE; portp->close_delay = STL_CLOSEDELAY; portp->closing_wait = 30 * HZ; - INIT_WORK(&portp->tqhangup, stli_dohangup, portp); + INIT_WORK(&portp->tqhangup, stli_dohangup); init_waitqueue_head(&portp->open_wait); init_waitqueue_head(&portp->close_wait); init_waitqueue_head(&portp->raw_wait); @@ -3476,6 +3476,8 @@ static int stli_initecp(stlibrd_t *brdp) if (sig.magic != cpu_to_le32(ECP_MAGIC)) { release_region(brdp->iobase, brdp->iosize); + iounmap(brdp->membase); + brdp->membase = NULL; return -ENODEV; } @@ -3632,6 +3634,8 @@ static int stli_initonb(stlibrd_t *brdp) sig.magic3 != cpu_to_le16(ONB_MAGIC3)) { release_region(brdp->iobase, brdp->iosize); + iounmap(brdp->membase); + brdp->membase = NULL; return -ENODEV; } diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 55473371b7c6..e67eef4867ba 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; } diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 62ebe09656e3..7e975f606924 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 = { @@ -204,6 +199,8 @@ int misc_register(struct miscdevice * misc) dev_t dev; int err = 0; + INIT_LIST_HEAD(&misc->list); + down(&misc_sem); list_for_each_entry(c, &misc_list, list) { if (c->minor == misc->minor) { @@ -228,10 +225,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 +261,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/mmtimer.c b/drivers/char/mmtimer.c index 22b9905c1e52..c09160383a53 100644 --- a/drivers/char/mmtimer.c +++ b/drivers/char/mmtimer.c @@ -680,7 +680,7 @@ static int __init mmtimer_init(void) if (sn_rtc_cycles_per_second < 100000) { printk(KERN_ERR "%s: unable to determine clock frequency\n", MMTIMER_NAME); - return -1; + goto out1; } mmtimer_femtoperiod = ((unsigned long)1E15 + sn_rtc_cycles_per_second / @@ -689,13 +689,13 @@ static int __init mmtimer_init(void) if (request_irq(SGI_MMTIMER_VECTOR, mmtimer_interrupt, IRQF_PERCPU, MMTIMER_NAME, NULL)) { printk(KERN_WARNING "%s: unable to allocate interrupt.", MMTIMER_NAME); - return -1; + goto out1; } if (misc_register(&mmtimer_miscdev)) { printk(KERN_ERR "%s: failed to register device\n", MMTIMER_NAME); - return -1; + goto out2; } /* Get max numbered node, calculate slots needed */ @@ -709,16 +709,18 @@ static int __init mmtimer_init(void) if (timers == NULL) { printk(KERN_ERR "%s: failed to allocate memory for device\n", MMTIMER_NAME); - return -1; + goto out3; } + memset(timers,0,(sizeof(mmtimer_t *)*maxn)); + /* Allocate mmtimer_t's for each online node */ for_each_online_node(node) { timers[node] = kmalloc_node(sizeof(mmtimer_t)*NUM_COMPARATORS, GFP_KERNEL, node); if (timers[node] == NULL) { printk(KERN_ERR "%s: failed to allocate memory for device\n", MMTIMER_NAME); - return -1; + goto out4; } for (i=0; i< NUM_COMPARATORS; i++) { mmtimer_t * base = timers[node] + i; @@ -739,6 +741,17 @@ static int __init mmtimer_init(void) sn_rtc_cycles_per_second/(unsigned long)1E6); return 0; + +out4: + for_each_online_node(node) { + kfree(timers[node]); + } +out3: + misc_deregister(&mmtimer_miscdev); +out2: + free_irq(SGI_MMTIMER_VECTOR, NULL); +out1: + return -1; } module_init(mmtimer_init); diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 96cb1f07332b..8b316953173d 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -222,7 +222,7 @@ static struct semaphore moxaBuffSem; /* * static functions: */ -static void do_moxa_softint(void *); +static void do_moxa_softint(struct work_struct *); static int moxa_open(struct tty_struct *, struct file *); static void moxa_close(struct tty_struct *, struct file *); static int moxa_write(struct tty_struct *, const unsigned char *, int); @@ -363,7 +363,7 @@ static int __init moxa_init(void) for (i = 0, ch = moxaChannels; i < MAX_PORTS; i++, ch++) { ch->type = PORT_16550A; ch->port = i; - INIT_WORK(&ch->tqueue, do_moxa_softint, ch); + INIT_WORK(&ch->tqueue, do_moxa_softint); ch->tty = NULL; ch->close_delay = 5 * HZ / 10; ch->closing_wait = 30 * HZ; @@ -498,9 +498,12 @@ static void __exit moxa_exit(void) printk("Couldn't unregister MOXA Intellio family serial driver\n"); put_tty_driver(moxaDriver); - for (i = 0; i < MAX_BOARDS; i++) + for (i = 0; i < MAX_BOARDS; i++) { + if (moxaBaseAddr[i]) + iounmap(moxaBaseAddr[i]); if (moxa_boards[i].busType == MOXA_BUS_TYPE_PCI) pci_dev_put(moxa_boards[i].pciInfo.pdev); + } if (verbose) printk("Done\n"); @@ -509,9 +512,9 @@ static void __exit moxa_exit(void) module_init(moxa_init); module_exit(moxa_exit); -static void do_moxa_softint(void *private_) +static void do_moxa_softint(struct work_struct *work) { - struct moxa_str *ch = (struct moxa_str *) private_; + struct moxa_str *ch = container_of(work, struct moxa_str, tqueue); struct tty_struct *tty; if (ch && (tty = ch->tty)) { diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 048d91142c17..5ed2486b7581 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -389,7 +389,7 @@ static int mxser_init(void); /* static void mxser_poll(unsigned long); */ static int mxser_get_ISA_conf(int, struct mxser_hwconf *); static int mxser_get_PCI_conf(int, int, int, struct mxser_hwconf *); -static void mxser_do_softint(void *); +static void mxser_do_softint(struct work_struct *); static int mxser_open(struct tty_struct *, struct file *); static void mxser_close(struct tty_struct *, struct file *); static int mxser_write(struct tty_struct *, const unsigned char *, int); @@ -590,7 +590,7 @@ static int mxser_initbrd(int board, struct mxser_hwconf *hwconf) info->custom_divisor = hwconf->baud_base[i] * 16; info->close_delay = 5 * HZ / 10; info->closing_wait = 30 * HZ; - INIT_WORK(&info->tqueue, mxser_do_softint, info); + INIT_WORK(&info->tqueue, mxser_do_softint); info->normal_termios = mxvar_sdriver->init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); @@ -917,9 +917,10 @@ static int mxser_init(void) return 0; } -static void mxser_do_softint(void *private_) +static void mxser_do_softint(struct work_struct *work) { - struct mxser_struct *info = private_; + struct mxser_struct *info = + container_of(work, struct mxser_struct, tqueue); struct tty_struct *tty; tty = info->tty; diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 50d20aafeb18..211c93fda6fc 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -1764,29 +1764,11 @@ static int cm4000_config(struct pcmcia_device * link, int devno) int rc; /* read the config-tuples */ - tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - if ((fail_rc = pcmcia_get_first_tuple(link, &tuple)) != CS_SUCCESS) { - fail_fn = GetFirstTuple; - goto cs_failed; - } - if ((fail_rc = pcmcia_get_tuple_data(link, &tuple)) != CS_SUCCESS) { - fail_fn = GetTupleData; - goto cs_failed; - } - if ((fail_rc = - pcmcia_parse_tuple(link, &tuple, &parse)) != CS_SUCCESS) { - fail_fn = ParseTuple; - goto cs_failed; - } - - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - link->io.BasePort2 = 0; link->io.NumPorts2 = 0; link->io.Attributes2 = 0; @@ -1841,8 +1823,6 @@ static int cm4000_config(struct pcmcia_device * link, int devno) return 0; -cs_failed: - cs_error(link, fail_fn, fail_rc); cs_release: cm4000_release(link); return -ENODEV; @@ -1973,14 +1953,14 @@ static int __init cmm_init(void) printk(KERN_INFO "%s\n", version); cmm_class = class_create(THIS_MODULE, "cardman_4000"); - if (!cmm_class) - return -1; + if (IS_ERR(cmm_class)) + return PTR_ERR(cmm_class); major = register_chrdev(0, DEVICE_NAME, &cm4000_fops); if (major < 0) { printk(KERN_WARNING MODULE_NAME ": could not get major number\n"); - return -1; + return major; } rc = pcmcia_register_driver(&cm4000_driver); diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 55cf4be42976..9b1ff7e8f896 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -523,29 +523,11 @@ static int reader_config(struct pcmcia_device *link, int devno) int fail_fn, fail_rc; int rc; - tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - if ((fail_rc = pcmcia_get_first_tuple(link, &tuple)) != CS_SUCCESS) { - fail_fn = GetFirstTuple; - goto cs_failed; - } - if ((fail_rc = pcmcia_get_tuple_data(link, &tuple)) != CS_SUCCESS) { - fail_fn = GetTupleData; - goto cs_failed; - } - if ((fail_rc = pcmcia_parse_tuple(link, &tuple, &parse)) - != CS_SUCCESS) { - fail_fn = ParseTuple; - goto cs_failed; - } - - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - link->io.BasePort2 = 0; link->io.NumPorts2 = 0; link->io.Attributes2 = 0; @@ -609,8 +591,6 @@ static int reader_config(struct pcmcia_device *link, int devno) return 0; -cs_failed: - cs_error(link, fail_fn, fail_rc); cs_release: reader_release(link); return -ENODEV; @@ -721,14 +701,14 @@ static int __init cm4040_init(void) printk(KERN_INFO "%s\n", version); cmx_class = class_create(THIS_MODULE, "cardman_4040"); - if (!cmx_class) - return -1; + if (IS_ERR(cmx_class)) + return PTR_ERR(cmx_class); major = register_chrdev(0, DEVICE_NAME, &reader_fops); if (major < 0) { printk(KERN_WARNING MODULE_NAME ": could not get major number\n"); - return -1; + return major; } rc = pcmcia_register_driver(&reader_driver); diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 1a0bc30b79d1..74d21c1c104f 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -75,8 +75,10 @@ #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> -#ifdef CONFIG_HDLC_MODULE -#define CONFIG_HDLC 1 +#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_CS_MODULE)) +#define SYNCLINK_GENERIC_HDLC 1 +#else +#define SYNCLINK_GENERIC_HDLC 0 #endif #define GET_USER(error,value,addr) error = get_user(value,addr) @@ -235,7 +237,7 @@ typedef struct _mgslpc_info { int dosyncppp; spinlock_t netlock; -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC struct net_device *netdev; #endif @@ -392,7 +394,7 @@ static void tx_timeout(unsigned long context); static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg); -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC #define dev_to_port(D) (dev_to_hdlc(D)->priv) static void hdlcdev_tx_done(MGSLPC_INFO *info); static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size); @@ -421,7 +423,7 @@ static irqreturn_t mgslpc_isr(int irq, void *dev_id); /* * Bottom half interrupt handlers */ -static void bh_handler(void* Context); +static void bh_handler(struct work_struct *work); static void bh_transmit(MGSLPC_INFO *info); static void bh_status(MGSLPC_INFO *info); @@ -547,7 +549,7 @@ static int mgslpc_probe(struct pcmcia_device *link) memset(info, 0, sizeof(MGSLPC_INFO)); info->magic = MGSLPC_MAGIC; - INIT_WORK(&info->task, bh_handler, info); + INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; @@ -604,17 +606,10 @@ static int mgslpc_config(struct pcmcia_device *link) if (debug_level >= DEBUG_LEVEL_INFO) printk("mgslpc_config(0x%p)\n", link); - /* read CONFIG tuple to find its configuration registers */ - tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; /* get CIS configuration entry */ @@ -842,9 +837,9 @@ static int bh_action(MGSLPC_INFO *info) return rc; } -static void bh_handler(void* Context) +static void bh_handler(struct work_struct *work) { - MGSLPC_INFO *info = (MGSLPC_INFO*)Context; + MGSLPC_INFO *info = container_of(work, MGSLPC_INFO, task); int action; if (!info) @@ -1060,7 +1055,7 @@ static void tx_done(MGSLPC_INFO *info) info->drop_rts_on_tx_done = 0; } -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC if (info->netcount) hdlcdev_tx_done(info); else @@ -1171,7 +1166,7 @@ static void dcd_change(MGSLPC_INFO *info) } else info->input_signal_events.dcd_down++; -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC if (info->netcount) { if (info->serial_signals & SerialSignal_DCD) netif_carrier_on(info->netdev); @@ -2960,7 +2955,7 @@ static void mgslpc_add_device(MGSLPC_INFO *info) printk( "SyncLink PC Card %s:IO=%04X IRQ=%d\n", info->device_name, info->io_base, info->irq_level); -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC hdlcdev_init(info); #endif } @@ -2976,7 +2971,7 @@ static void mgslpc_remove_device(MGSLPC_INFO *remove_info) last->next_device = info->next_device; else mgslpc_device_list = info->next_device; -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC hdlcdev_exit(info); #endif release_resources(info); @@ -3908,7 +3903,7 @@ static int rx_get_frame(MGSLPC_INFO *info) return_frame = 1; } framesize = 0; -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC { struct net_device_stats *stats = hdlc_stats(info->netdev); stats->rx_errors++; @@ -3942,7 +3937,7 @@ static int rx_get_frame(MGSLPC_INFO *info) ++framesize; } -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC if (info->netcount) hdlcdev_rx(info, buf->data, framesize); else @@ -4098,7 +4093,7 @@ static void tx_timeout(unsigned long context) spin_unlock_irqrestore(&info->lock,flags); -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC if (info->netcount) hdlcdev_tx_done(info); else @@ -4106,7 +4101,7 @@ static void tx_timeout(unsigned long context) bh_transmit(info); } -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC /** * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index efc485edad1c..c1e3dd837fc8 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 = { diff --git a/drivers/char/random.c b/drivers/char/random.c index eb6b13f4211a..4c6782a1ecdb 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1422,9 +1422,9 @@ static struct keydata { static unsigned int ip_cnt; -static void rekey_seq_generator(void *private_); +static void rekey_seq_generator(struct work_struct *work); -static DECLARE_WORK(rekey_work, rekey_seq_generator, NULL); +static DECLARE_DELAYED_WORK(rekey_work, rekey_seq_generator); /* * Lock avoidance: @@ -1438,7 +1438,7 @@ static DECLARE_WORK(rekey_work, rekey_seq_generator, NULL); * happen, and even if that happens only a not perfectly compliant * ISN is generated, nothing fatal. */ -static void rekey_seq_generator(void *private_) +static void rekey_seq_generator(struct work_struct *work) { struct keydata *keyptr = &ip_keydata[1 ^ (ip_cnt & 1)]; @@ -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 <saw@msu.ru>. */ -__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)); } /* diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 89b718e326e5..3b32313f6eb4 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); diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 7ac68cb3bedd..e79b2ede8510 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -1026,6 +1026,7 @@ static int __init rio_init(void) found++; } else { iounmap(p->RIOHosts[p->RIONumHosts].Caddr); + p->RIOHosts[p->RIONumHosts].Caddr = NULL; } } @@ -1078,6 +1079,7 @@ static int __init rio_init(void) found++; } else { iounmap(p->RIOHosts[p->RIONumHosts].Caddr); + p->RIOHosts[p->RIONumHosts].Caddr = NULL; } #else printk(KERN_ERR "Found an older RIO PCI card, but the driver is not " "compiled to support it.\n"); @@ -1117,8 +1119,10 @@ static int __init rio_init(void) } } - if (!okboard) + if (!okboard) { iounmap(hp->Caddr); + hp->Caddr = NULL; + } } } @@ -1188,6 +1192,8 @@ static void __exit rio_exit(void) } /* It is safe/allowed to del_timer a non-active timer */ del_timer(&hp->timer); + if (hp->Caddr) + iounmap(hp->Caddr); if (hp->Type == RIO_PCI) pci_dev_put(hp->pdev); } diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c index 4df6ab2206a1..167ebc84e8d7 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 99f3df02b61c..0794844369d6 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 1066d9760704..bb498d24adcc 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 diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 5ab32b38f45a..0a77bfcd5b5e 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -82,11 +82,6 @@ static struct riscom_board * IRQ_to_board[16]; static struct tty_driver *riscom_driver; -static unsigned long baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 76800, 0, -}; - static struct riscom_board rc_board[RC_NBOARD] = { { .base = RC_IOBASE1, @@ -1516,9 +1511,9 @@ static void rc_start(struct tty_struct * tty) * do_rc_hangup() -> tty->hangup() -> rc_hangup() * */ -static void do_rc_hangup(void *private_) +static void do_rc_hangup(struct work_struct *ugly_api) { - struct riscom_port *port = (struct riscom_port *) private_; + struct riscom_port *port = container_of(ugly_api, struct riscom_port, tqueue_hangup); struct tty_struct *tty; tty = port->tty; @@ -1567,9 +1562,9 @@ static void rc_set_termios(struct tty_struct * tty, struct termios * old_termios } } -static void do_softint(void *private_) +static void do_softint(struct work_struct *ugly_api) { - struct riscom_port *port = (struct riscom_port *) private_; + struct riscom_port *port = container_of(ugly_api, struct riscom_port, tqueue); struct tty_struct *tty; if(!(tty = port->tty)) @@ -1632,8 +1627,8 @@ static inline int rc_init_drivers(void) memset(rc_port, 0, sizeof(rc_port)); for (i = 0; i < RC_NPORT * RC_NBOARD; i++) { rc_port[i].magic = RISCOM8_MAGIC; - INIT_WORK(&rc_port[i].tqueue, do_softint, &rc_port[i]); - INIT_WORK(&rc_port[i].tqueue_hangup, do_rc_hangup, &rc_port[i]); + INIT_WORK(&rc_port[i].tqueue, do_softint); + INIT_WORK(&rc_port[i].tqueue_hangup, do_rc_hangup); rc_port[i].close_delay = 50 * HZ/100; rc_port[i].closing_wait = 3000 * HZ/100; init_waitqueue_head(&rc_port[i].open_wait); diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index 3af7f0958c5d..9ba13af234be 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -706,9 +706,9 @@ cd2401_rx_interrupt(int irq, void *dev_id) * had to poll every port to see if that port needed servicing. */ static void -do_softint(void *private_) +do_softint(struct work_struct *ugly_api) { - struct cyclades_port *info = (struct cyclades_port *) private_; + struct cyclades_port *info = container_of(ugly_api, struct cyclades_port, tqueue); struct tty_struct *tty; tty = info->tty; @@ -2273,7 +2273,7 @@ scrn[1] = '\0'; info->blocked_open = 0; info->default_threshold = 0; info->default_timeout = 0; - INIT_WORK(&info->tqueue, do_softint, info); + INIT_WORK(&info->tqueue, do_softint); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); /* info->session */ diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index c084149153de..fc87070f1866 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -765,7 +765,7 @@ static void sonypi_setbluetoothpower(u8 state) sonypi_device.bluetooth_power = state; } -static void input_keyrelease(void *data) +static void input_keyrelease(struct work_struct *work) { struct sonypi_keypress kp; @@ -1412,7 +1412,7 @@ static int __devinit sonypi_probe(struct platform_device *dev) goto err_inpdev_unregister; } - INIT_WORK(&sonypi_device.input_work, input_keyrelease, NULL); + INIT_WORK(&sonypi_device.input_work, input_keyrelease); } sonypi_enable(0); diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index 7e1bd9562c2a..99137ab66b62 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -2261,9 +2261,10 @@ static void sx_start(struct tty_struct * tty) * do_sx_hangup() -> tty->hangup() -> sx_hangup() * */ -static void do_sx_hangup(void *private_) +static void do_sx_hangup(struct work_struct *work) { - struct specialix_port *port = (struct specialix_port *) private_; + struct specialix_port *port = + container_of(work, struct specialix_port, tqueue_hangup); struct tty_struct *tty; func_enter(); @@ -2336,9 +2337,10 @@ static void sx_set_termios(struct tty_struct * tty, struct termios * old_termios } -static void do_softint(void *private_) +static void do_softint(struct work_struct *work) { - struct specialix_port *port = (struct specialix_port *) private_; + struct specialix_port *port = + container_of(work, struct specialix_port, tqueue); struct tty_struct *tty; func_enter(); @@ -2411,8 +2413,8 @@ static int sx_init_drivers(void) memset(sx_port, 0, sizeof(sx_port)); for (i = 0; i < SX_NPORT * SX_NBOARD; i++) { sx_port[i].magic = SPECIALIX_MAGIC; - INIT_WORK(&sx_port[i].tqueue, do_softint, &sx_port[i]); - INIT_WORK(&sx_port[i].tqueue_hangup, do_sx_hangup, &sx_port[i]); + INIT_WORK(&sx_port[i].tqueue, do_softint); + INIT_WORK(&sx_port[i].tqueue_hangup, do_sx_hangup); sx_port[i].close_delay = 50 * HZ/100; sx_port[i].closing_wait = 3000 * HZ/100; init_waitqueue_head(&sx_port[i].open_wait); diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 522e88e395cc..5e2de62bce70 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -500,7 +500,7 @@ static int stl_echatintr(stlbrd_t *brdp); static int stl_echmcaintr(stlbrd_t *brdp); static int stl_echpciintr(stlbrd_t *brdp); static int stl_echpci64intr(stlbrd_t *brdp); -static void stl_offintr(void *private); +static void stl_offintr(struct work_struct *); static stlbrd_t *stl_allocbrd(void); static stlport_t *stl_getport(int brdnr, int panelnr, int portnr); @@ -2081,14 +2081,12 @@ static int stl_echpci64intr(stlbrd_t *brdp) /* * Service an off-level request for some channel. */ -static void stl_offintr(void *private) +static void stl_offintr(struct work_struct *work) { - stlport_t *portp; + stlport_t *portp = container_of(work, stlport_t, tqueue); struct tty_struct *tty; unsigned int oldsigs; - portp = private; - #ifdef DEBUG printk("stl_offintr(portp=%x)\n", (int) portp); #endif @@ -2156,7 +2154,7 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) portp->baud_base = STL_BAUDBASE; portp->close_delay = STL_CLOSEDELAY; portp->closing_wait = 30 * HZ; - INIT_WORK(&portp->tqueue, stl_offintr, portp); + INIT_WORK(&portp->tqueue, stl_offintr); init_waitqueue_head(&portp->open_wait); init_waitqueue_head(&portp->close_wait); portp->stats.brd = portp->brdnr; diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 06784adcc35c..645187b9141e 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -101,8 +101,10 @@ #include <linux/hdlc.h> #include <linux/dma-mapping.h> -#ifdef CONFIG_HDLC_MODULE -#define CONFIG_HDLC 1 +#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_MODULE)) +#define SYNCLINK_GENERIC_HDLC 1 +#else +#define SYNCLINK_GENERIC_HDLC 0 #endif #define GET_USER(error,value,addr) error = get_user(value,addr) @@ -320,7 +322,7 @@ struct mgsl_struct { int dosyncppp; spinlock_t netlock; -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC struct net_device *netdev; #endif }; @@ -728,7 +730,7 @@ static void usc_loopmode_send_done( struct mgsl_struct * info ); static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg); -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC #define dev_to_port(D) (dev_to_hdlc(D)->priv) static void hdlcdev_tx_done(struct mgsl_struct *info); static void hdlcdev_rx(struct mgsl_struct *info, char *buf, int size); @@ -802,7 +804,7 @@ static int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, u /* * Bottom half interrupt handlers */ -static void mgsl_bh_handler(void* Context); +static void mgsl_bh_handler(struct work_struct *work); static void mgsl_bh_receive(struct mgsl_struct *info); static void mgsl_bh_transmit(struct mgsl_struct *info); static void mgsl_bh_status(struct mgsl_struct *info); @@ -1071,9 +1073,10 @@ static int mgsl_bh_action(struct mgsl_struct *info) /* * Perform bottom half processing of work items queued by ISR. */ -static void mgsl_bh_handler(void* Context) +static void mgsl_bh_handler(struct work_struct *work) { - struct mgsl_struct *info = (struct mgsl_struct*)Context; + struct mgsl_struct *info = + container_of(work, struct mgsl_struct, task); int action; if (!info) @@ -1276,7 +1279,7 @@ static void mgsl_isr_transmit_status( struct mgsl_struct *info ) info->drop_rts_on_tx_done = 0; } -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC if (info->netcount) hdlcdev_tx_done(info); else @@ -1341,7 +1344,7 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info ) info->input_signal_events.dcd_up++; } else info->input_signal_events.dcd_down++; -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC if (info->netcount) { if (status & MISCSTATUS_DCD) netif_carrier_on(info->netdev); @@ -4312,7 +4315,7 @@ static void mgsl_add_device( struct mgsl_struct *info ) info->max_frame_size ); } -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC hdlcdev_init(info); #endif @@ -4337,7 +4340,7 @@ static struct mgsl_struct* mgsl_allocate_device(void) } else { memset(info, 0, sizeof(struct mgsl_struct)); info->magic = MGSL_MAGIC; - INIT_WORK(&info->task, mgsl_bh_handler, info); + INIT_WORK(&info->task, mgsl_bh_handler); info->max_frame_size = 4096; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; @@ -4470,7 +4473,7 @@ static void synclink_cleanup(void) info = mgsl_device_list; while(info) { -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC hdlcdev_exit(info); #endif mgsl_release_resources(info); @@ -6644,7 +6647,7 @@ static int mgsl_get_rx_frame(struct mgsl_struct *info) return_frame = 1; } framesize = 0; -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC { struct net_device_stats *stats = hdlc_stats(info->netdev); stats->rx_errors++; @@ -6720,7 +6723,7 @@ static int mgsl_get_rx_frame(struct mgsl_struct *info) *ptmp); } -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC if (info->netcount) hdlcdev_rx(info,info->intermediate_rxbuffer,framesize); else @@ -7624,7 +7627,7 @@ static void mgsl_tx_timeout(unsigned long context) spin_unlock_irqrestore(&info->irq_spinlock,flags); -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC if (info->netcount) hdlcdev_tx_done(info); else @@ -7700,7 +7703,7 @@ static int usc_loopmode_active( struct mgsl_struct * info) return usc_InReg( info, CCSR ) & BIT7 ? 1 : 0 ; } -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC /** * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index d4334c79f8d4..e4730a7312b5 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -83,8 +83,10 @@ #include "linux/synclink.h" -#ifdef CONFIG_HDLC_MODULE -#define CONFIG_HDLC 1 +#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_GT_MODULE)) +#define SYNCLINK_GENERIC_HDLC 1 +#else +#define SYNCLINK_GENERIC_HDLC 0 #endif /* @@ -171,7 +173,7 @@ static void set_break(struct tty_struct *tty, int break_state); /* * generic HDLC support and callbacks */ -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC #define dev_to_port(D) (dev_to_hdlc(D)->priv) static void hdlcdev_tx_done(struct slgt_info *info); static void hdlcdev_rx(struct slgt_info *info, char *buf, int size); @@ -359,7 +361,7 @@ struct slgt_info { int netcount; int dosyncppp; spinlock_t netlock; -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC struct net_device *netdev; #endif @@ -485,7 +487,7 @@ static void enable_loopback(struct slgt_info *info); static void set_rate(struct slgt_info *info, u32 data_rate); static int bh_action(struct slgt_info *info); -static void bh_handler(void* context); +static void bh_handler(struct work_struct *work); static void bh_transmit(struct slgt_info *info); static void isr_serial(struct slgt_info *info); static void isr_rdma(struct slgt_info *info); @@ -1354,7 +1356,7 @@ static void set_break(struct tty_struct *tty, int break_state) spin_unlock_irqrestore(&info->lock,flags); } -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC /** * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) @@ -1878,9 +1880,9 @@ static int bh_action(struct slgt_info *info) /* * perform bottom half processing */ -static void bh_handler(void* context) +static void bh_handler(struct work_struct *work) { - struct slgt_info *info = context; + struct slgt_info *info = container_of(work, struct slgt_info, task); int action; if (!info) @@ -2002,7 +2004,7 @@ static void dcd_change(struct slgt_info *info) } else { info->input_signal_events.dcd_down++; } -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC if (info->netcount) { if (info->signals & SerialSignal_DCD) netif_carrier_on(info->netdev); @@ -2180,7 +2182,7 @@ static void isr_txeom(struct slgt_info *info, unsigned short status) set_signals(info); } -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC if (info->netcount) hdlcdev_tx_done(info); else @@ -3306,7 +3308,7 @@ static void add_device(struct slgt_info *info) devstr, info->device_name, info->phys_reg_addr, info->irq_level, info->max_frame_size); -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC hdlcdev_init(info); #endif } @@ -3326,7 +3328,7 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev } else { memset(info, 0, sizeof(struct slgt_info)); info->magic = MGSL_MAGIC; - INIT_WORK(&info->task, bh_handler, info); + INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; info->raw_rx_size = DMABUFSIZE; info->close_delay = 5*HZ/10; @@ -3488,7 +3490,7 @@ static void slgt_cleanup(void) /* release devices */ info = slgt_device_list; while(info) { -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC hdlcdev_exit(info); #endif free_dma_bufs(info); @@ -3522,6 +3524,7 @@ static int __init slgt_init(void) if (!slgt_device_list) { printk("%s no devices found\n",driver_name); + pci_unregister_driver(&pci_driver); return -ENODEV; } @@ -4433,7 +4436,7 @@ check_again: framesize = 0; } -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC if (framesize == 0) { struct net_device_stats *stats = hdlc_stats(info->netdev); stats->rx_errors++; @@ -4476,7 +4479,7 @@ check_again: framesize++; } -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC if (info->netcount) hdlcdev_rx(info,info->tmp_rbuf, framesize); else @@ -4779,7 +4782,7 @@ static void tx_timeout(unsigned long context) info->tx_count = 0; spin_unlock_irqrestore(&info->lock,flags); -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC if (info->netcount) hdlcdev_tx_done(info); else @@ -4799,6 +4802,6 @@ static void rx_timeout(unsigned long context) spin_lock_irqsave(&info->lock, flags); info->pending_bh |= BH_RECEIVE; spin_unlock_irqrestore(&info->lock, flags); - bh_handler(info); + bh_handler(&info->task); } diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 3e932b681371..20a96ef250be 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -67,8 +67,10 @@ #include <linux/workqueue.h> #include <linux/hdlc.h> -#ifdef CONFIG_HDLC_MODULE -#define CONFIG_HDLC 1 +#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINKMP_MODULE)) +#define SYNCLINK_GENERIC_HDLC 1 +#else +#define SYNCLINK_GENERIC_HDLC 0 #endif #define GET_USER(error,value,addr) error = get_user(value,addr) @@ -280,7 +282,7 @@ typedef struct _synclinkmp_info { int dosyncppp; spinlock_t netlock; -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC struct net_device *netdev; #endif @@ -536,7 +538,7 @@ static void throttle(struct tty_struct * tty); static void unthrottle(struct tty_struct * tty); static void set_break(struct tty_struct *tty, int break_state); -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC #define dev_to_port(D) (dev_to_hdlc(D)->priv) static void hdlcdev_tx_done(SLMP_INFO *info); static void hdlcdev_rx(SLMP_INFO *info, char *buf, int size); @@ -602,7 +604,7 @@ static void enable_loopback(SLMP_INFO *info, int enable); static void set_rate(SLMP_INFO *info, u32 data_rate); static int bh_action(SLMP_INFO *info); -static void bh_handler(void* Context); +static void bh_handler(struct work_struct *work); static void bh_receive(SLMP_INFO *info); static void bh_transmit(SLMP_INFO *info); static void bh_status(SLMP_INFO *info); @@ -1607,7 +1609,7 @@ static void set_break(struct tty_struct *tty, int break_state) spin_unlock_irqrestore(&info->lock,flags); } -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC /** * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) @@ -2063,9 +2065,9 @@ int bh_action(SLMP_INFO *info) /* Perform bottom half processing of work items queued by ISR. */ -void bh_handler(void* Context) +void bh_handler(struct work_struct *work) { - SLMP_INFO *info = (SLMP_INFO*)Context; + SLMP_INFO *info = container_of(work, SLMP_INFO, task); int action; if (!info) @@ -2339,7 +2341,7 @@ static void isr_txeom(SLMP_INFO * info, unsigned char status) set_signals(info); } -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC if (info->netcount) hdlcdev_tx_done(info); else @@ -2523,7 +2525,7 @@ void isr_io_pin( SLMP_INFO *info, u16 status ) info->input_signal_events.dcd_up++; } else info->input_signal_events.dcd_down++; -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC if (info->netcount) { if (status & SerialSignal_DCD) netif_carrier_on(info->netdev); @@ -3783,7 +3785,7 @@ void add_device(SLMP_INFO *info) info->irq_level, info->max_frame_size ); -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC hdlcdev_init(info); #endif } @@ -3805,7 +3807,7 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev) } else { memset(info, 0, sizeof(SLMP_INFO)); info->magic = MGSL_MAGIC; - INIT_WORK(&info->task, bh_handler, info); + INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; @@ -3977,7 +3979,7 @@ static void synclinkmp_cleanup(void) /* release devices */ info = synclinkmp_device_list; while(info) { -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC hdlcdev_exit(info); #endif free_dma_bufs(info); @@ -4979,7 +4981,7 @@ CheckAgain: info->icount.rxcrc++; framesize = 0; -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC { struct net_device_stats *stats = hdlc_stats(info->netdev); stats->rx_errors++; @@ -5020,7 +5022,7 @@ CheckAgain: index = 0; } -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC if (info->netcount) hdlcdev_rx(info,info->tmp_rx_buf,framesize); else @@ -5531,7 +5533,7 @@ void tx_timeout(unsigned long context) spin_unlock_irqrestore(&info->lock,flags); -#ifdef CONFIG_HDLC +#if SYNCLINK_GENERIC_HDLC if (info->netcount) hdlcdev_tx_done(info); else diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 5f49280779fb..05810c8d20bc 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -182,6 +182,18 @@ static struct sysrq_key_op sysrq_showstate_op = { .enable_mask = SYSRQ_ENABLE_DUMP, }; +static void sysrq_handle_showstate_blocked(int key, struct tty_struct *tty) +{ + show_state_filter(TASK_UNINTERRUPTIBLE); +} +static struct sysrq_key_op sysrq_showstate_blocked_op = { + .handler = sysrq_handle_showstate_blocked, + .help_msg = "showBlockedTasks", + .action_msg = "Show Blocked State", + .enable_mask = SYSRQ_ENABLE_DUMP, +}; + + static void sysrq_handle_showmem(int key, struct tty_struct *tty) { show_mem(); @@ -219,13 +231,13 @@ static struct sysrq_key_op sysrq_term_op = { .enable_mask = SYSRQ_ENABLE_SIGNAL, }; -static void moom_callback(void *ignored) +static void moom_callback(struct work_struct *ignored) { out_of_memory(&NODE_DATA(0)->node_zonelists[ZONE_NORMAL], GFP_KERNEL, 0); } -static DECLARE_WORK(moom_work, moom_callback, NULL); +static DECLARE_WORK(moom_work, moom_callback); static void sysrq_handle_moom(int key, struct tty_struct *tty) { @@ -304,7 +316,7 @@ static struct sysrq_key_op *sysrq_key_table[36] = { /* May be assigned at init time by SMP VOYAGER */ NULL, /* v */ NULL, /* w */ - NULL, /* x */ + &sysrq_showstate_blocked_op, /* x */ NULL, /* y */ NULL /* z */ }; diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index dd36fd04a842..07067c31c4ec 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c @@ -249,6 +249,7 @@ int tosh_smm(SMMRegisters *regs) return eax; } +EXPORT_SYMBOL(tosh_smm); static int tosh_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 6ad2d3bb945c..33e1f66e39cb 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -325,9 +325,9 @@ static void user_reader_timeout(unsigned long ptr) schedule_work(&chip->work); } -static void timeout_work(void *ptr) +static void timeout_work(struct work_struct *work) { - struct tpm_chip *chip = ptr; + struct tpm_chip *chip = container_of(work, struct tpm_chip, work); down(&chip->buffer_mutex); atomic_set(&chip->data_pending, 0); @@ -1105,7 +1105,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend init_MUTEX(&chip->tpm_mutex); INIT_LIST_HEAD(&chip->list); - INIT_WORK(&chip->work, timeout_work, chip); + INIT_WORK(&chip->work, timeout_work); init_timer(&chip->user_read_timer); chip->user_read_timer.function = user_reader_timeout; @@ -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)) { @@ -1155,6 +1155,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { list_del(&chip->list); + misc_deregister(&chip->vendor.miscdev); put_device(dev); clear_bit(chip->dev_num, dev_mask); kfree(chip); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 050ced247f68..bb9a43c6cf3d 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -22,6 +22,7 @@ #include <linux/pci.h> #include <linux/delay.h> #include <linux/fs.h> +#include <linux/sched.h> #include <linux/miscdevice.h> #include <linux/platform_device.h> #include <linux/io.h> diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index e90ea39c7c4b..b3cfc8bc613c 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1254,7 +1254,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); /** * do_tty_hangup - actual handler for hangup events - * @data: tty device + * @work: tty device * * This can be called by the "eventd" kernel thread. That is process * synchronous but doesn't hold any locks, so we need to make sure we @@ -1274,9 +1274,10 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); * tasklist_lock to walk task list for hangup event * */ -static void do_tty_hangup(void *data) +static void do_tty_hangup(struct work_struct *work) { - struct tty_struct *tty = (struct tty_struct *) data; + struct tty_struct *tty = + container_of(work, struct tty_struct, hangup_work); struct file * cons_filp = NULL; struct file *filp, *f = NULL; struct task_struct *p; @@ -1433,7 +1434,7 @@ void tty_vhangup(struct tty_struct * tty) printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf)); #endif - do_tty_hangup((void *) tty); + do_tty_hangup(&tty->hangup_work); } EXPORT_SYMBOL(tty_vhangup); @@ -3304,12 +3305,13 @@ int tty_ioctl(struct inode * inode, struct file * file, * Nasty bug: do_SAK is being called in interrupt context. This can * deadlock. We punt it up to process context. AKPM - 16Mar2001 */ -static void __do_SAK(void *arg) +static void __do_SAK(struct work_struct *work) { + struct tty_struct *tty = + container_of(work, struct tty_struct, SAK_work); #ifdef TTY_SOFT_SAK tty_hangup(tty); #else - struct tty_struct *tty = arg; struct task_struct *g, *p; int session; int i; @@ -3388,7 +3390,7 @@ void do_SAK(struct tty_struct *tty) { if (!tty) return; - PREPARE_WORK(&tty->SAK_work, __do_SAK, tty); + PREPARE_WORK(&tty->SAK_work, __do_SAK); schedule_work(&tty->SAK_work); } @@ -3396,7 +3398,7 @@ EXPORT_SYMBOL(do_SAK); /** * flush_to_ldisc - * @private_: tty structure passed from work queue. + * @work: tty structure passed from work queue. * * This routine is called out of the software interrupt to flush data * from the buffer chain to the line discipline. @@ -3406,9 +3408,10 @@ EXPORT_SYMBOL(do_SAK); * receive_buf method is single threaded for each tty instance. */ -static void flush_to_ldisc(void *private_) +static void flush_to_ldisc(struct work_struct *work) { - struct tty_struct *tty = (struct tty_struct *) private_; + struct tty_struct *tty = + container_of(work, struct tty_struct, buf.work.work); unsigned long flags; struct tty_ldisc *disc; struct tty_buffer *tbuf, *head; @@ -3553,7 +3556,7 @@ void tty_flip_buffer_push(struct tty_struct *tty) spin_unlock_irqrestore(&tty->buf.lock, flags); if (tty->low_latency) - flush_to_ldisc((void *) tty); + flush_to_ldisc(&tty->buf.work.work); else schedule_delayed_work(&tty->buf.work, 1); } @@ -3580,17 +3583,17 @@ static void initialize_tty_struct(struct tty_struct *tty) tty->overrun_time = jiffies; tty->buf.head = tty->buf.tail = NULL; tty_buffer_init(tty); - INIT_WORK(&tty->buf.work, flush_to_ldisc, tty); + INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc); init_MUTEX(&tty->buf.pty_sem); mutex_init(&tty->termios_mutex); init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->read_wait); - INIT_WORK(&tty->hangup_work, do_tty_hangup, tty); + INIT_WORK(&tty->hangup_work, do_tty_hangup); mutex_init(&tty->atomic_read_lock); mutex_init(&tty->atomic_write_lock); spin_lock_init(&tty->read_lock); INIT_LIST_HEAD(&tty->tty_files); - INIT_WORK(&tty->SAK_work, NULL, NULL); + INIT_WORK(&tty->SAK_work, NULL); } /* @@ -3612,7 +3615,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 +3626,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 +3643,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 +3659,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 +3899,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 +3920,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 diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index bd7a98c6ea7a..f442b574b44a 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; } diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 8e4413f6fbaf..a8239dac994f 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; @@ -152,10 +152,10 @@ static void gotoxy(struct vc_data *vc, int new_x, int new_y); static void save_cur(struct vc_data *vc); static void reset_terminal(struct vc_data *vc, int do_clear); static void con_flush_chars(struct tty_struct *tty); -static void set_vesa_blanking(char __user *p); +static int set_vesa_blanking(char __user *p); static void set_cursor(struct vc_data *vc); static void hide_cursor(struct vc_data *vc); -static void console_callback(void *ignored); +static void console_callback(struct work_struct *ignored); static void blank_screen_t(unsigned long dummy); static void set_palette(struct vc_data *vc); @@ -174,7 +174,7 @@ static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ static int blankinterval = 10*60*HZ; static int vesa_off_interval; -static DECLARE_WORK(console_work, console_callback, NULL); +static DECLARE_WORK(console_work, console_callback); /* * fg_console is the current virtual console, @@ -2154,7 +2154,7 @@ out: * with other console code and prevention of re-entrancy is * ensured with console_sem. */ -static void console_callback(void *ignored) +static void console_callback(struct work_struct *ignored) { acquire_console_sem(); @@ -2369,7 +2369,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) ret = __put_user(data, p); break; case TIOCL_SETVESABLANK: - set_vesa_blanking(p); + ret = set_vesa_blanking(p); break; case TIOCL_GETKMSGREDIRECT: data = kmsg_redirect; @@ -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); } } } @@ -3316,11 +3313,15 @@ postcore_initcall(vtconsole_class_init); * Screen blanking */ -static void set_vesa_blanking(char __user *p) +static int set_vesa_blanking(char __user *p) { - unsigned int mode; - get_user(mode, p + 1); - vesa_blank_mode = (mode < 4) ? mode : 0; + unsigned int mode; + + if (get_user(mode, p + 1)) + return -EFAULT; + + vesa_blank_mode = (mode < 4) ? mode : 0; + return 0; } void do_blank_screen(int entering_gfx) diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 0187b1185323..ea09d0c974ea 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 @@ -363,6 +371,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 @@ -553,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 36440497047c..2cd8ff8d10ac 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -47,9 +47,10 @@ 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 obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o obj-$(CONFIG_SBC8360_WDT) += sbc8360.o obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o @@ -72,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/iTCO_vendor_support.c b/drivers/char/watchdog/iTCO_vendor_support.c new file mode 100644 index 000000000000..415083990097 --- /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 <wim@iguana.be>. + * + * 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 <linux/module.h> /* For module specific items */ +#include <linux/moduleparam.h> /* For new moduleparam's */ +#include <linux/types.h> /* For standard types (like size_t) */ +#include <linux/errno.h> /* For the -ENODEV/... values */ +#include <linux/kernel.h> /* For printk/panic/... */ +#include <linux/init.h> /* For __init/__exit/... */ +#include <linux/ioport.h> /* For io-port access */ + +#include <asm/io.h> /* 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 <lkpatches@paypc.com> + * 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 <lkpatches@paypc.com> + * 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 <wim@iguana.be>, R. Seretny <lkpatches@paypc.com>"); +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 b6f29cb8bd39..7eac922df867 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; diff --git a/drivers/char/watchdog/pc87413_wdt.c b/drivers/char/watchdog/pc87413_wdt.c new file mode 100644 index 000000000000..1d447e32af41 --- /dev/null +++ b/drivers/char/watchdog/pc87413_wdt.c @@ -0,0 +1,635 @@ +/* + * 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 Sven Anders, <anders@anduras.de> + * and Marcus Junker, <junker@anduras.de> + * + * 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 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.1 + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/notifier.h> +#include <linux/fs.h> +#include <linux/reboot.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/moduleparam.h> +#include <linux/version.h> + +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/system.h> + +/* #define DEBUG 1 */ + +#define DEFAULT_TIMEOUT 1 /* 1 minute */ +#define MAX_TIMEOUT 255 + +#define VERSION "1.1" +#define MODNAME "pc87413 WDT" +#define PFX MODNAME ": " +#define DPFX MODNAME " - DEBUG: " + +#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? */ + +static char expect_close; /* is the close expected? */ + +static spinlock_t io_lock; /* to guard the watchdog from io races */ + +static int nowayout = WATCHDOG_NOWAYOUT; + +/* -- Low level function ----------------------------------------*/ + +/* Select pins for Watchdog output */ + +static inline void pc87413_select_wdt_out (void) +{ + unsigned int cr_data = 0; + + /* Step 1: 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 +} + +/* Enable SWC functions */ + +static inline 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 +} + +/* 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; + + /* 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; +} + +/* 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); + +#ifdef DEBUG + printk(KERN_INFO DPFX "Select Bank3 of SWC\n"); +#endif +} + +/* 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); + +#ifdef DEBUG + printk(KERN_INFO DPFX "Set WDTO to %d minutes\n", pc87413_time); +#endif +} + +/* 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 + printk(KERN_INFO DPFX "Enable WDEN\n"); +#endif +} + +/* 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 + printk(KERN_INFO DPFX "Enable SW_WD_TREN\n"); +#endif +} + +/* 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 + printk(KERN_INFO DPFX "pc87413 - Disable SW_WD_TREN\n"); +#endif +} + +/* Enable SW_WD_TRG */ + +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 + printk(KERN_INFO DPFX "pc87413 - Enable SW_WD_TRG\n"); +#endif +} + +/* 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 + printk(KERN_INFO DPFX "Disable SW_WD_TRG\n"); +#endif +} + +/* -- Higher level functions ------------------------------------*/ + +/* Enable the watchdog */ + +static void pc87413_enable(void) +{ + 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, 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_disable(void) +{ + 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); + + spin_unlock(&io_lock); +} + +/* Refresh the watchdog */ + +static void pc87413_refresh(void) +{ + 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, 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); + + /* 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_release: + * @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) +{ + /* 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 0; +} + +/** + * pc87413_status: + * + * return, if the watchdog is enabled (timeout is set...) + */ + + +static int pc87413_status(void) +{ + return 0; /* currently not supported */ +} + +/** + * pc87413_write: + * @file: file handle to the watchdog + * @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 *data, + size_t len, loff_t *ppos) +{ + /* 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 len; +} + +/** + * 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) +{ + 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" + }; + + uarg.i = (int __user *)arg; + + switch(cmd) { + default: + return -ENOTTY; + + case WDIOC_GETSUPPORT: + return copy_to_user(uarg.ident, &ident, + sizeof(ident)) ? -EFAULT : 0; + + case WDIOC_GETSTATUS: + return put_user(pc87413_status(), uarg.i); + + case WDIOC_GETBOOTSTATUS: + return put_user(0, uarg.i); + + case WDIOC_KEEPALIVE: + pc87413_refresh(); +#ifdef DEBUG + printk(KERN_INFO DPFX "keepalive\n"); +#endif + return 0; + + case WDIOC_SETTIMEOUT: + if (get_user(new_timeout, uarg.i)) + return -EFAULT; + + // the API states this is given in secs + new_timeout /= 60; + + if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) + return -EINVAL; + + 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; + } + } +} + +/* -- Notifier funtions -----------------------------------------*/ + +/** + * 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; +} + +/* -- Module's structures ---------------------------------------*/ + +static struct file_operations pc87413_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = pc87413_write, + .ioctl = pc87413_ioctl, + .open = pc87413_open, + .release = pc87413_release, +}; + +static struct notifier_block pc87413_notifier = +{ + .notifier_call = pc87413_notify_sys, +}; + +static struct miscdevice pc87413_miscdev= +{ + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &pc87413_fops +}; + +/* -- Module init functions -------------------------------------*/ + +/** + * 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 __init pc87413_init(void) +{ + int ret; + + 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); + } + + 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(); + + 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_AUTHOR("Sven Anders <anders@anduras.de>, Marcus Junker <junker@anduras.de>,"); +MODULE_DESCRIPTION("PC87413 WDT driver"); +MODULE_LICENSE("GPL"); + +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); + +module_param(io, int, 0); +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) ")."); + +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c index bda45334d802..61138726b501 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); @@ -635,7 +634,7 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi usb_pcwd->intr_size = (le16_to_cpu(endpoint->wMaxPacketSize) > 8 ? le16_to_cpu(endpoint->wMaxPacketSize) : 8); /* set up the memory buffer's */ - if (!(usb_pcwd->intr_buffer = usb_buffer_alloc(udev, usb_pcwd->intr_size, SLAB_ATOMIC, &usb_pcwd->intr_dma))) { + if (!(usb_pcwd->intr_buffer = usb_buffer_alloc(udev, usb_pcwd->intr_size, GFP_ATOMIC, &usb_pcwd->intr_dma))) { printk(KERN_ERR PFX "Out of memory\n"); goto error; } diff --git a/drivers/char/watchdog/rm9k_wdt.c b/drivers/char/watchdog/rm9k_wdt.c new file mode 100644 index 000000000000..ec3909371c21 --- /dev/null +++ b/drivers/char/watchdog/rm9k_wdt.c @@ -0,0 +1,420 @@ +/* + * Watchdog implementation for GPI h/w found on PMC-Sierra RM9xxx + * chips. + * + * Copyright (C) 2004 by Basler Vision Technologies AG + * Author: Thomas Koeller <thomas.koeller@baslerweb.com> + * + * 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 <linux/platform_device.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/interrupt.h> +#include <linux/fs.h> +#include <linux/reboot.h> +#include <linux/notifier.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <asm/io.h> +#include <asm/atomic.h> +#include <asm/processor.h> +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/rm9k-ocd.h> + +#include <rm9k_wdt.h> + + +#define CLOCK 125000000 +#define MAX_TIMEOUT_SECONDS 32 +#define CPCCR 0x0080 +#define CPGIG1SR 0x0044 +#define CPGIG1ER 0x0054 + + +/* 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 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 *); + + +static const char wdt_gpi_name[] = "wdt_gpi"; +static atomic_t opencnt; +static int expect_close; +static int locked; + + +/* 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; +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"); + + +/* Interrupt handler */ +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_CRIT "%s: watchdog expired - resetting system\n", + wdt_gpi_name); + + *(volatile char *) flagaddr |= 0x01; + *(volatile char *) resetaddr = powercycle ? 0x01 : 0x2; + iob(); + while (1) + cpu_relax(); +} + + +/* 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; + 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(); +} + + +/* /dev/watchdog operations */ +static int wdt_gpi_open(struct inode *inode, struct file *file) +{ + int res; + + if (unlikely(atomic_dec_if_positive(&opencnt) < 0)) + 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); + wdt_gpi_start(); + + printk(KERN_INFO "%s: watchdog started, timeout = %u seconds\n", + wdt_gpi_name, timeout); + return nonseekable_open(inode, file); +} + +static int wdt_gpi_release(struct inode *inode, struct file *file) +{ + if (nowayout) { + printk(KERN_INFO "%s: no way out - watchdog left running\n", + wdt_gpi_name); + __module_get(THIS_MODULE); + locked = 1; + } else { + if (expect_close) { + wdt_gpi_stop(); + free_irq(wd_irq, &miscdev); + printk(KERN_INFO "%s: watchdog stopped\n", wdt_gpi_name); + } else { + printk(KERN_CRIT "%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; + void __user *argp = (void __user *)arg; + 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(argp, &wdinfo, size) ? -EFAULT : size; + break; + + case WDIOC_GETSTATUS: + break; + + case WDIOC_GETBOOTSTATUS: + stat = (*(volatile char *) flagaddr & 0x01) + ? WDIOF_CARDRESET : 0; + res = __copy_to_user(argp, &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, argp, size))) { + res = -EFAULT; + break; + } + + if (val > MAX_TIMEOUT_SECONDS) + val = MAX_TIMEOUT_SECONDS; + timeout = val; + wdt_gpi_set_timeout(val); + res = size; + printk(KERN_INFO "%s: timeout set to %u seconds\n", + wdt_gpi_name, timeout); + } + break; + + case WDIOC_GETTIMEOUT: + res = __copy_to_user(argp, &timeout, size) ? + -EFAULT : size; + break; + } + + return res; +} + + +/* Shutdown notifier */ +static int +wdt_gpi_notify(struct notifier_block *this, unsigned long code, void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) + wdt_gpi_stop(); + + return NOTIFY_DONE; +} + + +/* 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) +{ + 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 <thomas.koeller@baslerweb.com>"); +MODULE_DESCRIPTION("Basler eXcite watchdog driver for gpi devices"); +MODULE_VERSION("0.1"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); + |