aboutsummaryrefslogtreecommitdiff
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Kconfig43
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/agp/amd64-agp.c2
-rw-r--r--drivers/char/agp/generic.c2
-rw-r--r--drivers/char/agp/intel-agp.c33
-rw-r--r--drivers/char/cyclades.c9
-rw-r--r--drivers/char/decserial.c38
-rw-r--r--drivers/char/drm/drm_sman.c1
-rw-r--r--drivers/char/drm/drm_vm.c8
-rw-r--r--drivers/char/drm/via_dmablit.c6
-rw-r--r--drivers/char/epca.c8
-rw-r--r--drivers/char/esp.c14
-rw-r--r--drivers/char/ftape/Kconfig330
-rw-r--r--drivers/char/ftape/Makefile28
-rw-r--r--drivers/char/ftape/README.PCI81
-rw-r--r--drivers/char/ftape/RELEASE-NOTES966
-rw-r--r--drivers/char/ftape/compressor/Makefile31
-rw-r--r--drivers/char/ftape/compressor/lzrw3.c743
-rw-r--r--drivers/char/ftape/compressor/lzrw3.h253
-rw-r--r--drivers/char/ftape/compressor/zftape-compress.c1203
-rw-r--r--drivers/char/ftape/compressor/zftape-compress.h83
-rw-r--r--drivers/char/ftape/lowlevel/Makefile43
-rw-r--r--drivers/char/ftape/lowlevel/fc-10.c175
-rw-r--r--drivers/char/ftape/lowlevel/fc-10.h39
-rw-r--r--drivers/char/ftape/lowlevel/fdc-io.c1349
-rw-r--r--drivers/char/ftape/lowlevel/fdc-io.h252
-rw-r--r--drivers/char/ftape/lowlevel/fdc-isr.c1170
-rw-r--r--drivers/char/ftape/lowlevel/fdc-isr.h55
-rw-r--r--drivers/char/ftape/lowlevel/ftape-bsm.c491
-rw-r--r--drivers/char/ftape/lowlevel/ftape-bsm.h66
-rw-r--r--drivers/char/ftape/lowlevel/ftape-buffer.c130
-rw-r--r--drivers/char/ftape/lowlevel/ftape-buffer.h32
-rw-r--r--drivers/char/ftape/lowlevel/ftape-calibr.c275
-rw-r--r--drivers/char/ftape/lowlevel/ftape-calibr.h37
-rw-r--r--drivers/char/ftape/lowlevel/ftape-ctl.c896
-rw-r--r--drivers/char/ftape/lowlevel/ftape-ctl.h162
-rw-r--r--drivers/char/ftape/lowlevel/ftape-ecc.c853
-rw-r--r--drivers/char/ftape/lowlevel/ftape-ecc.h84
-rw-r--r--drivers/char/ftape/lowlevel/ftape-format.c344
-rw-r--r--drivers/char/ftape/lowlevel/ftape-format.h37
-rw-r--r--drivers/char/ftape/lowlevel/ftape-init.c160
-rw-r--r--drivers/char/ftape/lowlevel/ftape-init.h43
-rw-r--r--drivers/char/ftape/lowlevel/ftape-io.c992
-rw-r--r--drivers/char/ftape/lowlevel/ftape-io.h90
-rw-r--r--drivers/char/ftape/lowlevel/ftape-proc.c214
-rw-r--r--drivers/char/ftape/lowlevel/ftape-proc.h35
-rw-r--r--drivers/char/ftape/lowlevel/ftape-read.c621
-rw-r--r--drivers/char/ftape/lowlevel/ftape-read.h51
-rw-r--r--drivers/char/ftape/lowlevel/ftape-rw.c1092
-rw-r--r--drivers/char/ftape/lowlevel/ftape-rw.h111
-rw-r--r--drivers/char/ftape/lowlevel/ftape-setup.c104
-rw-r--r--drivers/char/ftape/lowlevel/ftape-tracing.c118
-rw-r--r--drivers/char/ftape/lowlevel/ftape-tracing.h179
-rw-r--r--drivers/char/ftape/lowlevel/ftape-write.c336
-rw-r--r--drivers/char/ftape/lowlevel/ftape-write.h53
-rw-r--r--drivers/char/ftape/lowlevel/ftape_syms.c87
-rw-r--r--drivers/char/ftape/zftape/Makefile36
-rw-r--r--drivers/char/ftape/zftape/zftape-buffers.c149
-rw-r--r--drivers/char/ftape/zftape/zftape-buffers.h55
-rw-r--r--drivers/char/ftape/zftape/zftape-ctl.c1417
-rw-r--r--drivers/char/ftape/zftape/zftape-ctl.h58
-rw-r--r--drivers/char/ftape/zftape/zftape-eof.c199
-rw-r--r--drivers/char/ftape/zftape/zftape-eof.h52
-rw-r--r--drivers/char/ftape/zftape/zftape-init.c377
-rw-r--r--drivers/char/ftape/zftape/zftape-init.h77
-rw-r--r--drivers/char/ftape/zftape/zftape-read.c377
-rw-r--r--drivers/char/ftape/zftape/zftape-read.h53
-rw-r--r--drivers/char/ftape/zftape/zftape-rw.c375
-rw-r--r--drivers/char/ftape/zftape/zftape-rw.h101
-rw-r--r--drivers/char/ftape/zftape/zftape-vtbl.c757
-rw-r--r--drivers/char/ftape/zftape/zftape-vtbl.h227
-rw-r--r--drivers/char/ftape/zftape/zftape-write.c483
-rw-r--r--drivers/char/ftape/zftape/zftape-write.h38
-rw-r--r--drivers/char/ftape/zftape/zftape_syms.c43
-rw-r--r--drivers/char/genrtc.c4
-rw-r--r--drivers/char/hpet.c1
-rw-r--r--drivers/char/hvc_console.c1
-rw-r--r--drivers/char/hvcs.c426
-rw-r--r--drivers/char/hvsi.c16
-rw-r--r--drivers/char/hw_random/Kconfig19
-rw-r--r--drivers/char/hw_random/Makefile3
-rw-r--r--drivers/char/hw_random/core.c39
-rw-r--r--drivers/char/ip2/i2cmd.h5
-rw-r--r--drivers/char/ip2/i2lib.c13
-rw-r--r--drivers/char/ip2/ip2main.c23
-rw-r--r--drivers/char/ipmi/ipmi_bt_sm.c641
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c25
-rw-r--r--drivers/char/ipmi/ipmi_kcs_sm.c18
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c746
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c114
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c384
-rw-r--r--drivers/char/ipmi/ipmi_smic_sm.c14
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c121
-rw-r--r--drivers/char/isicom.c15
-rw-r--r--drivers/char/istallion.c12
-rw-r--r--drivers/char/mem.c8
-rw-r--r--drivers/char/misc.c15
-rw-r--r--drivers/char/mmtimer.c23
-rw-r--r--drivers/char/moxa.c13
-rw-r--r--drivers/char/mspec.c8
-rw-r--r--drivers/char/mxser.c9
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c26
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c26
-rw-r--r--drivers/char/pcmcia/synclink_cs.c41
-rw-r--r--drivers/char/ppdev.c6
-rw-r--r--drivers/char/random.c54
-rw-r--r--drivers/char/raw.c12
-rw-r--r--drivers/char/rio/rio_linux.c8
-rw-r--r--drivers/char/rio/riocmd.c2
-rw-r--r--drivers/char/rio/rioinit.c2
-rw-r--r--drivers/char/rio/rioparam.c6
-rw-r--r--drivers/char/riscom8.c17
-rw-r--r--drivers/char/serial167.c6
-rw-r--r--drivers/char/sonypi.c4
-rw-r--r--drivers/char/specialix.c14
-rw-r--r--drivers/char/stallion.c10
-rw-r--r--drivers/char/synclink.c35
-rw-r--r--drivers/char/synclink_gt.c37
-rw-r--r--drivers/char/synclinkmp.c34
-rw-r--r--drivers/char/sysrq.c18
-rw-r--r--drivers/char/tlclk.c5
-rw-r--r--drivers/char/toshiba.c1
-rw-r--r--drivers/char/tpm/tpm.c9
-rw-r--r--drivers/char/tpm/tpm.h1
-rw-r--r--drivers/char/tty_io.c50
-rw-r--r--drivers/char/vc_screen.c16
-rw-r--r--drivers/char/vt.c103
-rw-r--r--drivers/char/watchdog/Kconfig32
-rw-r--r--drivers/char/watchdog/Makefile4
-rw-r--r--drivers/char/watchdog/at91rm9200_wdt.c1
-rw-r--r--drivers/char/watchdog/iTCO_vendor_support.c307
-rw-r--r--drivers/char/watchdog/iTCO_wdt.c29
-rw-r--r--drivers/char/watchdog/pc87413_wdt.c635
-rw-r--r--drivers/char/watchdog/pcwd_usb.c5
-rw-r--r--drivers/char/watchdog/rm9k_wdt.c420
135 files changed, 3544 insertions, 20681 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 39a9f8cc641..24f922f1278 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -409,14 +409,6 @@ config SGI_MBCS
If you have an SGI Altix with an attached SABrick
say Y or M here, otherwise say N.
-config MSPEC
- tristate "Memory special operations driver"
- depends on IA64
- help
- If you have an ia64 and you want to enable memory special
- operations support (formerly known as fetchop), say Y here,
- otherwise say N.
-
source "drivers/serial/Kconfig"
config UNIX98_PTYS
@@ -863,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"
@@ -1002,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 777cad04509..b1fcdab9094 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -78,7 +78,6 @@ obj-$(CONFIG_TOSHIBA) += toshiba.o
obj-$(CONFIG_I8K) += i8k.o
obj-$(CONFIG_DS1620) += ds1620.o
obj-$(CONFIG_HW_RANDOM) += hw_random/
-obj-$(CONFIG_FTAPE) += ftape/
obj-$(CONFIG_COBALT_LCD) += lcd.o
obj-$(CONFIG_PPDEV) += ppdev.o
obj-$(CONFIG_NWBUTTON) += nwbutton.o
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 00b17ae3973..2f2c4efff8a 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/agp/generic.c b/drivers/char/agp/generic.c
index c3920016168..5ff457b41ef 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -1054,7 +1054,7 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge)
{
struct page * page;
- page = alloc_page(GFP_KERNEL);
+ page = alloc_page(GFP_KERNEL | GFP_DMA32);
if (page == NULL)
return NULL;
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index d1ede7db5a1..555b3a8ab49 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -169,7 +169,7 @@ static void *i8xx_alloc_pages(void)
{
struct page * page;
- page = alloc_pages(GFP_KERNEL, 2);
+ page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2);
if (page == NULL)
return NULL;
@@ -387,11 +387,7 @@ static void intel_i830_init_gtt_entries(void)
/* We obtain the size of the GTT, which is also stored (for some
* reason) at the top of stolen memory. Then we add 4KB to that
* for the video BIOS popup, which is also stored in there. */
-
- if (IS_I965)
- size = 512 + 4;
- else
- size = agp_bridge->driver->fetch_size() + 4;
+ size = agp_bridge->driver->fetch_size() + 4;
if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
@@ -805,6 +801,26 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
return 0;
}
+
+/*
+ * The i965 supports 36-bit physical addresses, but to keep
+ * the format of the GTT the same, the bits that don't fit
+ * in a 32-bit word are shifted down to bits 4..7.
+ *
+ * Gcc is smart enough to notice that "(addr >> 28) & 0xf0"
+ * is always zero on 32-bit architectures, so no need to make
+ * this conditional.
+ */
+static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
+ unsigned long addr, int type)
+{
+ /* Shift high bits down */
+ addr |= (addr >> 28) & 0xf0;
+
+ /* Type checking must be done elsewhere */
+ return addr | bridge->driver->masks[type].mask;
+}
+
static int intel_i965_fetch_size(void)
{
struct aper_size_info_fixed *values;
@@ -832,7 +848,8 @@ static int intel_i965_fetch_size(void)
agp_bridge->previous_size = agp_bridge->current_size = (void *)(values + offset);
- return values[offset].size;
+ /* The i965 GTT is always sized as if it had a 512kB aperture size */
+ return 512;
}
/* The intel i965 automatically initializes the agp aperture during POST.
@@ -1584,7 +1601,7 @@ static struct agp_bridge_driver intel_i965_driver = {
.fetch_size = intel_i965_fetch_size,
.cleanup = intel_i915_cleanup,
.tlb_flush = intel_i810_tlbflush,
- .mask_memory = intel_i810_mask_memory,
+ .mask_memory = intel_i965_mask_memory,
.masks = intel_i810_masks,
.agp_enable = intel_i810_agp_enable,
.cache_flush = global_cache_flush,
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index e608dadece2..acb2de5e3a9 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 85f404e25c7..8ea2bea2b18 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 425c82336ee..19c81d2e13d 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 b40ae438f53..ae2691942dd 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 60c1695db30..806f9ce5f47 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 706733c0b36..7c71eb77980 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 15a4ea89632..93b55196251 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 0d65189a7ae..00000000000
--- a/drivers/char/ftape/Kconfig
+++ /dev/null
@@ -1,330 +0,0 @@
-#
-# Ftape configuration
-#
-config ZFTAPE
- tristate "Zftape, the VFS interface"
- depends on FTAPE
- ---help---
- Normally, you want to say Y or M. DON'T say N here or you
- WON'T BE ABLE TO USE YOUR FLOPPY TAPE DRIVE.
-
- The ftape module itself no longer contains the routines necessary
- to interface with the kernel VFS layer (i.e. to actually write data
- to and read data from the tape drive). Instead the file system
- interface (i.e. the hardware independent part of the driver) has
- been moved to a separate module.
-
- To compile this driver as a module, choose M here: the
- module will be called zftape.
-
- Regardless of whether you say Y or M here, an additional runtime
- loadable module called `zft-compressor' which contains code to
- support user transparent on-the-fly compression based on Ross
- William's lzrw3 algorithm will be produced. If you have enabled the
- kernel module loader (i.e. have said Y to "Kernel module loader
- support", above) then `zft-compressor' will be loaded
- automatically by zftape when needed.
-
- Despite its name, zftape does NOT use compression by default.
-
-config ZFT_DFLT_BLK_SZ
- int "Default block size"
- depends on ZFTAPE
- default "10240"
- ---help---
- If unsure leave this at its default value, i.e. 10240. Note that
- you specify only the default block size here. The block size can be
- changed at run time using the MTSETBLK tape operation with the
- MTIOCTOP ioctl (i.e. with "mt -f /dev/qft0 setblk #BLKSZ" from the
- shell command line).
-
- The probably most striking difference between zftape and previous
- versions of ftape is the fact that all data must be written or read
- in multiples of a fixed block size. The block size defaults to
- 10240 which is what GNU tar uses. The values for the block size
- should be either 1 or multiples of 1024 up to a maximum value of
- 63488 (i.e. 62 K). If you specify `1' then zftape's builtin
- compression will be disabled.
-
- Reasonable values are `10240' (GNU tar's default block size),
- `5120' (afio's default block size), `32768' (default block size some
- backup programs assume for SCSI tape drives) or `1' (no restriction
- on block size, but disables builtin compression).
-
-comment "The compressor will be built as a module only!"
- depends on FTAPE && ZFTAPE
-
-config ZFT_COMPRESSOR
- tristate
- depends on FTAPE!=n && ZFTAPE!=n
- default m
-
-config FT_NR_BUFFERS
- int "Number of ftape buffers (EXPERIMENTAL)"
- depends on FTAPE && EXPERIMENTAL
- default "3"
- help
- Please leave this at `3' unless you REALLY know what you are doing.
- It is not necessary to change this value. Values below 3 make the
- proper use of ftape impossible, values greater than 3 are a waste of
- memory. You can change the amount of DMA memory used by ftape at
- runtime with "mt -f /dev/qft0 setdrvbuffer #NUMBUFFERS". Each buffer
- wastes 32 KB of memory. Please note that this memory cannot be
- swapped out.
-
-config FT_PROC_FS
- bool "Enable procfs status report (+2kb)"
- depends on FTAPE && PROC_FS
- ---help---
- Optional. Saying Y will result in creation of a directory
- `/proc/ftape' under the /proc file system. The files can be viewed
- with your favorite pager (i.e. use "more /proc/ftape/history" or
- "less /proc/ftape/history" or simply "cat /proc/ftape/history"). The
- file will contain some status information about the inserted
- cartridge, the kernel driver, your tape drive, the floppy disk
- controller and the error history for the most recent use of the
- kernel driver. Saying Y will enlarge the size of the ftape driver
- by approximately 2 KB.
-
- WARNING: When compiling ftape as a module (i.e. saying M to "Floppy
- tape drive") it is dangerous to use ftape's /proc file system
- interface. Accessing `/proc/ftape' while the module is unloaded will
- result in a kernel Oops. This cannot be fixed from inside ftape.
-
-choice
- prompt "Debugging output"
- depends on FTAPE
- default FT_NORMAL_DEBUG
-
-config FT_NORMAL_DEBUG
- bool "Normal"
- ---help---
- This option controls the amount of debugging output the ftape driver
- is ABLE to produce; it does not increase or diminish the debugging
- level itself. If unsure, leave this at its default setting,
- i.e. choose "Normal".
-
- Ftape can print lots of debugging messages to the system console
- resp. kernel log files. Reducing the amount of possible debugging
- output reduces the size of the kernel module by some KB, so it might
- be a good idea to use "None" for emergency boot floppies.
-
- If you want to save memory then the following strategy is
- recommended: leave this option at its default setting "Normal" until
- you know that the driver works as expected, afterwards reconfigure
- the kernel, this time specifying "Reduced" or "None" and recompile
- and install the kernel as usual. Note that choosing "Excessive"
- debugging output does not increase the amount of debugging output
- printed to the console but only makes it possible to produce
- "Excessive" debugging output.
-
- Please read <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 0e67d2f8b7e..00000000000
--- a/drivers/char/ftape/Makefile
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# Copyright (C) 1997 Claus Heine.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; see the file COPYING. If not, write to
-# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-# $Source: /homes/cvs/ftape-stacked/ftape/Makefile,v $
-# $Revision: 1.4 $
-# $Date: 1997/10/05 19:17:56 $
-#
-# Makefile for the QIC-40/80/3010/3020 floppy-tape driver for
-# Linux.
-#
-
-obj-$(CONFIG_FTAPE) += lowlevel/
-obj-$(CONFIG_ZFTAPE) += zftape/
-obj-$(CONFIG_ZFT_COMPRESSOR) += compressor/
diff --git a/drivers/char/ftape/README.PCI b/drivers/char/ftape/README.PCI
deleted file mode 100644
index 18de159d36e..00000000000
--- a/drivers/char/ftape/README.PCI
+++ /dev/null
@@ -1,81 +0,0 @@
-Some notes for ftape users with PCI motherboards:
-=================================================
-
-The problem:
-------------
-
-There have been some problem reports from people using PCI-bus based
-systems getting overrun errors.
-I wasn't able to reproduce these until I ran ftape on a Intel Plato
-(Premiere PCI II) motherboard with bios version 1.00.08AX1.
-It turned out that if GAT (Guaranteed Access Timing) is enabled (?)
-ftape gets a lot of overrun errors.
-The problem disappears when disabling GAT in the bios.
-Note that Intel removed this setting (permanently disabled) from the
-1.00.10AX1 bios !
-
-It looks like that if GAT is enabled there are often large periods
-(greater than 120 us !??) on the ISA bus that the DMA controller cannot
-service the floppy disk controller.
-I cannot imagine this being acceptable in a decent PCI implementation.
-Maybe this is a `feature' of the chipset. I can only speculate why
-Intel choose to remove the option from the latest Bios...
-
-The lesson of this all is that there may be other motherboard
-implementations having the same of similar problems.
-If you experience a lot of overrun errors during a backup to tape,
-see if there is some setting in the Bios that may influence the
-bus timing.
-
-I judge this a hardware problem and not a limitation of ftape ;-)
-My DOS backup software seems to be suffering from the same problems
-and even refuses to run at 1 Mbps !
-Ftape will reduce the data-rate from 1 Mbps to 500 Kbps if the number
-of overrun errors on a track exceeds a threshold.
-
-
-Possible solutions:
--------------------
-
-Some of the problems were solved by upgrading the (flash) bios.
-Other suggest that it has to do with the FDC being on the PCI
-bus, but that is not the case with the Intel Premiere II boards.
-[If upgrading the bios doesn't solve the problem you could try
-a floppy disk controller on the isa-bus].
-
-Here is a list of systems and recommended BIOS settings:
-
-
- Intel Premiere PCI (Revenge):
-
-Bios version 1.00.09.AF2 is reported to work.
-
-
-
- Intel Premiere PCI II (Plato):
-
-Bios version 1.00.10.AX1 and version 11 beta are ok.
-If using version 1.00.08.AX1, GAT must be disabled !
-
-
-
- ASUS PCI/I-SP3G:
-
-Preferred settings: ISA-GAT-mode : disabled
- DMA-linebuffer-mode : standard
- ISA-masterbuffer-mode : standard
-
-
- DELL Dimension XPS P90
-
-Bios version A2 is reported to be broken, while bios version A5 works.
-You can get a flash bios upgrade from http://www.dell.com
-
-
-To see if you're having the GAT problem, try making a backup
-under DOS. If it's very slow and often repositions you're
-probably having this problem.
-
- --//--
- LocalWords: ftape PCI bios GAT ISA DMA chipset Mbps Kbps FDC isa AF ok ASUS
- LocalWords: SP linebuffer masterbuffer XPS http www com
diff --git a/drivers/char/ftape/RELEASE-NOTES b/drivers/char/ftape/RELEASE-NOTES
deleted file mode 100644
index 03799dbc05a..00000000000
--- a/drivers/char/ftape/RELEASE-NOTES
+++ /dev/null
@@ -1,966 +0,0 @@
-Hey, Emacs, we're -*-Text-*- mode!
-
-===== Release notes for ftape-3.04d 25/11/97 =====
-- The correct pre-processor statement for "else if" is "#elif" not
- "elsif".
-- Need to call zft_reset_position() when overwriting cartridges
- previously written with ftape-2.x, sftape, or ancient
- (pre-ftape-3.x) versions of zftape.
-
-===== Release notes for ftape-3.04c 16/11/97 =====
-- fdc_probe() was calling DUMPREGS with a result length of "1" which
- was just fine. Undo previous change.
-
-===== Release notes for ftape-3.04b 14/11/97 =====
-
-- patches/2.x.x/floppy.c.diff was somewhat broken, releasing i/o
- regions it never had allocated.
-- fdc_probe() was calling DUMPREGS with a result length of "1" instead
- of "10"
-- Writing deleted data marks if the first segents on track zero are
- should work now.
-- ftformat should now be able to handle those cases where the tape
- drive sets the read only status bit (QIC-40/80 cartridges with
- QIC-3010/3020 tape drives) because the header segment is damaged.
-- the MTIOCFTCMD ioctl may now be issued by the superuser ONLY.
-
-===== Release notes for ftape-3.04a 12/11/97 =====
-- Fix an "infinite loop can't be killed by signal" bug in
- ftape_get_drive_status(). Only relevant when trying to access
- buggy/misconfigured hardware
-- Try to compensate a bug in the HP Colorado T3000's firmware: it
- doesn't set the write protect bit for QIC80/QIC40 cartridges.
-
-===== Release notes for ftape-3.04 06/11/97 =====
-- If positioning with fast seeking fails fall back to a slow seek
- before giving up.
-- (nearly) no retries on "no data errors" when verifying after
- formatting. Improved tuning of the bad sector map after formatting.
-- the directory layout has changed again to allow for easier kernel
- integration
-- Module parameter "ftape_tracing" now is called "ft_tracing" because
- the "ftape_tracing" variable has the version checksum attached to it.
-- `/proc/ftape' interface for 2.0.* kernels. `/proc/ftape' no longer
- is a directory but a file that contains all the information formerly
- provided in separate files under the `/proc/ftape/' directory.
-- Most of the configuration options have been prefixed by "CONFIG_FT_"
- in preparation of the kernel inclusion. The Makefiles under
- "./ftape/" should be directly usable by the kernel.
-- The MODVERSIONS stuff is now auto-detected.
-- Broke backslashed multi line options in MCONFIG into separate lines
- using GNU-make's "+=" feature.
-- The html and dvi version of the manual is now installed under
- '/usr/doc/ftape` with 'make install`
-- New SMP define in MCONFIG. ftape works with SMP if this is defined.
-- attempt to cope with "excessive overrun errors" by gradually
- increasing FDC FIFO threshold. But this doesn't seem to have too
- much an effect.
-- New load time configuration parameter "ft_fdc_rate_limit". If you
- encounter too many overrun errors with a 2Mb controller then you
- might want to set this to 1000.
-- overrun errors on the last sector in a segment sometimes result in
- a zero DMA residue. Dunno why, but compensate for it.
-- there were still fdc_read() timeout errors. I think I have fixed it
- now, please FIXME.
-- Sometimes ftape_write() failed to re-start the tape drive when a
- segment without a good sector was reached ("wait for empty segment
- failed"). This is fixed. Especially important for > QIC-3010.
-- sftape (aka ftape-2.x) has vanished. I didn't work on it for
- ages. It is probably still possible to use the old code with
- ftape-3.04, if one really needs it (BUT RECOMPILE IT)
-- zftape no longer alters the contents of already existing volume
- table entries, which makes it possible to fill in missing fields,
- like time stamps using some user space program.
-- ./contrib/vtblc/ contains such a program.
-- new perl script ./contrib/scripts/listtape that list the contents of a
- floppy tape cartridge parsing the output of "mt volinfo" + "mt fsf"
-- the MTWEOF implementation has changed a little bit (after I had a
- look at amanda). Calling MTWEOF while the tape is still held open
- after writing something to the tape now will terminate the current
- volume, and start a new one at the current position.
-- the volume table maintained by zftape now is a doubly linked list
- that grows dynamically as needed.
-
- formatting floppy tape cartridges
- ---------------------------------
- * there is a new user space formatting program that does most of the
- dirty work in user space (auto-detect, computing the sector
- coordinates, adjusting time stamps and statistics). It has a
- simple command line interface.
- * ftape-format.o has vanished, it has been folded into the low level
- ftape.o module, and the ioctl interface into zftape.o. Most of the
- complicated stuff has been moved to user space, so there was no
- need for a separate module anymore.
- * there is a new ioctl MTIOCFTCMD that sends a bare QIC-117 command
- to the tape drive.
- * there is a new mmap() feature to map the dma buffers into user
- space to be used by the user level formatting program.
- * Formatting of yet unformatted or totally degaussed cartridges
- should be possible now. FIXME.
-
-===== Release notes for ftape-3.03b, <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 1fbd6c4019d..00000000000
--- a/drivers/char/ftape/compressor/Makefile
+++ /dev/null
@@ -1,31 +0,0 @@
-#
-# Copyright (C) 1997 Claus-Justus Heine.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; see the file COPYING. If not, write to
-# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-# $Source: /homes/cvs/ftape-stacked/ftape/compressor/Makefile,v $
-# $Revision: 1.1 $
-# $Date: 1997/10/05 19:12:28 $
-#
-# Makefile for the optional compressor for th zftape VFS
-# interface to the QIC-40/80/3010/3020 floppy-tape driver for
-# Linux.
-#
-
-obj-$(CONFIG_ZFT_COMPRESSOR) += zft-compressor.o
-
-zft-compressor-objs := zftape-compress.o lzrw3.o
-
-CFLAGS_lzrw3.o := -O6 -funroll-all-loops
diff --git a/drivers/char/ftape/compressor/lzrw3.c b/drivers/char/ftape/compressor/lzrw3.c
deleted file mode 100644
index a032a0ee2a9..00000000000
--- a/drivers/char/ftape/compressor/lzrw3.c
+++ /dev/null
@@ -1,743 +0,0 @@
-/*
- * $Source: /homes/cvs/ftape-stacked/ftape/compressor/lzrw3.c,v $
- * $Revision: 1.1 $
- * $Date: 1997/10/05 19:12:29 $
- *
- * Implementation of Ross Williams lzrw3 algorithm. Adaption for zftape.
- *
- */
-
-#include "../compressor/lzrw3.h" /* Defines single exported function "compress". */
-
-/******************************************************************************/
-/* */
-/* LZRW3.C */
-/* */
-/******************************************************************************/
-/* */
-/* Author : Ross Williams. */
-/* Date : 30-Jun-1991. */
-/* Release : 1. */
-/* */
-/******************************************************************************/
-/* */
-/* This file contains an implementation of the LZRW3 data compression */
-/* algorithm in C. */
-/* */
-/* The algorithm is a general purpose compression algorithm that runs fast */
-/* and gives reasonable compression. The algorithm is a member of the Lempel */
-/* Ziv family of algorithms and bases its compression on the presence in the */
-/* data of repeated substrings. */
-/* */
-/* This algorithm is unpatented and the code is public domain. As the */
-/* algorithm is based on the LZ77 class of algorithms, it is unlikely to be */
-/* the subject of a patent challenge. */
-/* */
-/* Unlike the LZRW1 and LZRW1-A algorithms, the LZRW3 algorithm is */
-/* deterministic and is guaranteed to yield the same compressed */
-/* representation for a given file each time it is run. */
-/* */
-/* The LZRW3 algorithm was originally designed and implemented */
-/* by Ross Williams on 31-Dec-1990. */
-/* */
-/* Here are the results of applying this code, compiled under THINK C 4.0 */
-/* and running on a Mac-SE (8MHz 68000), to the standard calgary corpus. */
-/* */
-/* +----------------------------------------------------------------+ */
-/* | DATA COMPRESSION TEST | */
-/* | ===================== | */
-/* | Time of run : Sun 30-Jun-1991 09:31PM | */
-/* | Timing accuracy : One part in 100 | */
-/* | Context length : 262144 bytes (= 256.0000K) | */
-/* | Test suite : Calgary Corpus Suite | */
-/* | Files in suite : 14 | */
-/* | Algorithm : LZRW3 | */
-/* | Note: All averages are calculated from the un-rounded values. | */
-/* +----------------------------------------------------------------+ */
-/* | File Name Length CxB ComLen %Remn Bits Com K/s Dec K/s | */
-/* | ---------- ------ --- ------ ----- ---- ------- ------- | */
-/* | rpus:Bib.D 111261 1 55033 49.5 3.96 19.46 32.27 | */
-/* | us:Book1.D 768771 3 467962 60.9 4.87 17.03 31.07 | */
-/* | us:Book2.D 610856 3 317102 51.9 4.15 19.39 34.15 | */
-/* | rpus:Geo.D 102400 1 82424 80.5 6.44 11.65 18.18 | */
-/* | pus:News.D 377109 2 205670 54.5 4.36 17.14 27.47 | */
-/* | pus:Obj1.D 21504 1 13027 60.6 4.85 13.40 18.95 | */
-/* | pus:Obj2.D 246814 1 116286 47.1 3.77 19.31 30.10 | */
-/* | s:Paper1.D 53161 1 27522 51.8 4.14 18.60 31.15 | */
-/* | s:Paper2.D 82199 1 45160 54.9 4.40 18.45 32.84 | */
-/* | rpus:Pic.D 513216 2 122388 23.8 1.91 35.29 51.05 | */
-/* | us:Progc.D 39611 1 19669 49.7 3.97 18.87 30.64 | */
-/* | us:Progl.D 71646 1 28247 39.4 3.15 24.34 40.66 | */
-/* | us:Progp.D 49379 1 19377 39.2 3.14 23.91 39.23 | */
-/* | us:Trans.D 93695 1 33481 35.7 2.86 25.48 40.37 | */
-/* +----------------------------------------------------------------+ */
-/* | Average 224401 1 110953 50.0 4.00 20.17 32.72 | */
-/* +----------------------------------------------------------------+ */
-/* */
-/******************************************************************************/
-
-/******************************************************************************/
-
-/* The following structure is returned by the "compress" function below when */
-/* the user asks the function to return identifying information. */
-/* The most important field in the record is the working memory field which */
-/* tells the calling program how much working memory should be passed to */
-/* "compress" when it is called to perform a compression or decompression. */
-/* LZRW3 uses the same amount of memory during compression and decompression. */
-/* For more information on this structure see "compress.h". */
-
-#define U(X) ((ULONG) X)
-#define SIZE_P_BYTE (U(sizeof(UBYTE *)))
-#define SIZE_WORD (U(sizeof(UWORD )))
-#define ALIGNMENT_FUDGE (U(16))
-#define MEM_REQ ( U(4096)*(SIZE_P_BYTE) + ALIGNMENT_FUDGE )
-
-static struct compress_identity identity =
-{
- U(0x032DDEA8), /* Algorithm identification number. */
- MEM_REQ, /* Working memory (bytes) required. */
- "LZRW3", /* Name of algorithm. */
- "1.0", /* Version number of algorithm. */
- "31-Dec-1990", /* Date of algorithm. */
- "Public Domain", /* Copyright notice. */
- "Ross N. Williams", /* Author of algorithm. */
- "Renaissance Software", /* Affiliation of author. */
- "Public Domain" /* Vendor of algorithm. */
-};
-
-LOCAL void compress_compress (UBYTE *,UBYTE *,ULONG,UBYTE *, LONG *);
-LOCAL void compress_decompress(UBYTE *,UBYTE *,LONG, UBYTE *, ULONG *);
-
-/******************************************************************************/
-
-/* This function is the only function exported by this module. */
-/* Depending on its first parameter, the function can be requested to */
-/* compress a block of memory, decompress a block of memory, or to identify */
-/* itself. For more information, see the specification file "compress.h". */
-
-EXPORT void lzrw3_compress(
- UWORD action, /* Action to be performed. */
- UBYTE *wrk_mem, /* Address of working memory we can use.*/
- UBYTE *src_adr, /* Address of input data. */
- LONG src_len, /* Length of input data. */
- UBYTE *dst_adr, /* Address to put output data. */
- void *p_dst_len /* Address of longword for length of output data.*/
-)
-{
- switch (action)
- {
- case COMPRESS_ACTION_IDENTITY:
- *((struct compress_identity **)p_dst_len)= &identity;
- break;
- case COMPRESS_ACTION_COMPRESS:
- compress_compress(wrk_mem,src_adr,src_len,dst_adr,(LONG *)p_dst_len);
- break;
- case COMPRESS_ACTION_DECOMPRESS:
- compress_decompress(wrk_mem,src_adr,src_len,dst_adr,(LONG *)p_dst_len);
- break;
- }
-}
-
-/******************************************************************************/
-/* */
-/* BRIEF DESCRIPTION OF THE LZRW3 ALGORITHM */
-/* ======================================== */
-/* The LZRW3 algorithm is identical to the LZRW1-A algorithm except that */
-/* instead of transmitting history offsets, it transmits hash table indexes. */
-/* In order to decode the indexes, the decompressor must maintain an */
-/* identical hash table. Copy items are straightforward:when the decompressor */
-/* receives a copy item, it simply looks up the hash table to translate the */
-/* index into a pointer into the data already decompressed. To update the */
-/* hash table, it replaces the same table entry with a pointer to the start */
-/* of the newly decoded phrase. The tricky part is with literal items, for at */
-/* the time that the decompressor receives a literal item the decompressor */
-/* does not have the three bytes in the Ziv (that the compressor has) to */
-/* perform the three-byte hash. To solve this problem, in LZRW3, both the */
-/* compressor and decompressor are wired up so that they "buffer" these */
-/* literals and update their hash tables only when three bytes are available. */
-/* This makes the maximum buffering 2 bytes. */
-/* */
-/* Replacement of offsets by hash table indexes yields a few percent extra */
-/* compression at the cost of some speed. LZRW3 is slower than LZRW1, LZRW1-A */
-/* and LZRW2, but yields better compression. */
-/* */
-/* Extra compression could be obtained by using a hash table of depth two. */
-/* However, increasing the depth above one incurs a significant decrease in */
-/* compression speed which was not considered worthwhile. Another reason for */
-/* keeping the depth down to one was to allow easy comparison with the */
-/* LZRW1-A and LZRW2 algorithms so as to demonstrate the exact effect of the */
-/* use of direct hash indexes. */
-/* */
-/* +---+ */
-/* |___|4095 */
-/* |___| */
-/* +---------------------*_|<---+ /----+---\ */
-/* | |___| +---|Hash | */
-/* | |___| |Function| */
-/* | |___| \--------/ */
-/* | |___|0 ^ */
-/* | +---+ | */
-/* | Hash +-----+ */
-/* | Table | */
-/* | --- */
-/* v ^^^ */
-/* +-------------------------------------|----------------+ */
-/* |||||||||||||||||||||||||||||||||||||||||||||||||||||||| */
-/* +-------------------------------------|----------------+ */
-/* | |1......18| | */
-/* |<------- Lempel=History ------------>|<--Ziv-->| | */
-/* | (=bytes already processed) |<-Still to go-->| */
-/* |<-------------------- INPUT BLOCK ------------------->| */
-/* */
-/* The diagram above for LZRW3 looks almost identical to the diagram for */
-/* LZRW1. The difference is that in LZRW3, the compressor transmits hash */
-/* table indices instead of Lempel offsets. For this to work, the */
-/* decompressor must maintain a hash table as well as the compressor and both */
-/* compressor and decompressor must "buffer" literals, as the decompressor */
-/* cannot hash phrases commencing with a literal until another two bytes have */
-/* arrived. */
-/* */
-/* LZRW3 Algorithm Execution Summary */
-/* --------------------------------- */
-/* 1. Hash the first three bytes of the Ziv to yield a hash table index h. */
-/* 2. Look up the hash table yielding history pointer p. */
-/* 3. Match where p points with the Ziv. If there is a match of three or */
-/* more bytes, code those bytes (in the Ziv) as a copy item, otherwise */
-/* code the next byte in the Ziv as a literal item. */
-/* 4. Update the hash table as possible subject to the constraint that only */
-/* phrases commencing three bytes back from the Ziv can be hashed and */
-/* entered into the hash table. (This enables the decompressor to keep */
-/* pace). See the description and code for more details. */
-/* */
-/******************************************************************************/
-/* */
-/* DEFINITION OF COMPRESSED FILE FORMAT */
-/* ==================================== */
-/* * A compressed file consists of a COPY FLAG followed by a REMAINDER. */
-/* * The copy flag CF uses up four bytes with the first byte being the */
-/* least significant. */
-/* * If CF=1, then the compressed file represents the remainder of the file */
-/* exactly. Otherwise CF=0 and the remainder of the file consists of zero */
-/* or more GROUPS, each of which represents one or more bytes. */
-/* * Each group consists of two bytes of CONTROL information followed by */
-/* sixteen ITEMs except for the last group which can contain from one */
-/* to sixteen items. */
-/* * An item can be either a LITERAL item or a COPY item. */
-/* * Each item corresponds to a bit in the control bytes. */
-/* * The first control byte corresponds to the first 8 items in the group */
-/* with bit 0 corresponding to the first item in the group and bit 7 to */
-/* the eighth item in the group. */
-/* * The second control byte corresponds to the second 8 items in the group */
-/* with bit 0 corresponding to the ninth item in the group and bit 7 to */
-/* the sixteenth item in the group. */
-/* * A zero bit in a control word means that the corresponding item is a */
-/* literal item. A one bit corresponds to a copy item. */
-/* * A literal item consists of a single byte which represents itself. */
-/* * A copy item consists of two bytes that represent from 3 to 18 bytes. */
-/* * The first byte in a copy item will be denoted C1. */
-/* * The second byte in a copy item will be denoted C2. */
-/* * Bits will be selected using square brackets. */
-/* For example: C1[0..3] is the low nibble of the first control byte. */
-/* of copy item C1. */
-/* * The LENGTH of a copy item is defined to be C1[0..3]+3 which is a number */
-/* in the range [3,18]. */
-/* * The INDEX of a copy item is defined to be C1[4..7]*256+C2[0..8] which */
-/* is a number in the range [0,4095]. */
-/* * A copy item represents the sequence of bytes */
-/* text[POS-OFFSET..POS-OFFSET+LENGTH-1] where */
-/* text is the entire text of the uncompressed string. */
-/* POS is the index in the text of the character following the */
-/* string represented by all the items preceeding the item */
-/* being defined. */
-/* OFFSET is obtained from INDEX by looking up the hash table. */
-/* */
-/******************************************************************************/
-
-/* The following #define defines the length of the copy flag that appears at */
-/* the start of the compressed file. The value of four bytes was chosen */
-/* because the fast_copy routine on my Macintosh runs faster if the source */
-/* and destination blocks are relatively longword aligned. */
-/* The actual flag data appears in the first byte. The rest are zeroed so as */
-/* to normalize the compressed representation (i.e. not non-deterministic). */
-#define FLAG_BYTES 4
-
-/* The following #defines define the meaning of the values of the copy */
-/* flag at the start of the compressed file. */
-#define FLAG_COMPRESS 0 /* Signals that output was result of compression. */
-#define FLAG_COPY 1 /* Signals that output was simply copied over. */
-
-/* The 68000 microprocessor (on which this algorithm was originally developed */
-/* is fussy about non-aligned arrays of words. To avoid these problems the */
-/* following macro can be used to "waste" from 0 to 3 bytes so as to align */
-/* the argument pointer. */
-#define ULONG_ALIGN_UP(X) ((((ULONG)X)+sizeof(ULONG)-1)&~(sizeof(ULONG)-1))
-
-
-/* The following constant defines the maximum length of an uncompressed item. */
-/* This definition must not be changed; its value is hardwired into the code. */
-/* The longest number of bytes that can be spanned by a single item is 18 */
-/* for the longest copy item. */
-#define MAX_RAW_ITEM (18)
-
-/* The following constant defines the maximum length of an uncompressed group.*/
-/* This definition must not be changed; its value is hardwired into the code. */
-/* A group contains at most 16 items which explains this definition. */
-#define MAX_RAW_GROUP (16*MAX_RAW_ITEM)
-
-/* The following constant defines the maximum length of a compressed group. */
-/* This definition must not be changed; its value is hardwired into the code. */
-/* A compressed group consists of two control bytes followed by up to 16 */
-/* compressed items each of which can have a maximum length of two bytes. */
-#define MAX_CMP_GROUP (2+16*2)
-
-/* The following constant defines the number of entries in the hash table. */
-/* This definition must not be changed; its value is hardwired into the code. */
-#define HASH_TABLE_LENGTH (4096)
-
-/* LZRW3, unlike LZRW1(-A), must initialize its hash table so as to enable */
-/* the compressor and decompressor to stay in step maintaining identical hash */
-/* tables. In an early version of the algorithm, the tables were simply */
-/* initialized to zero and a check for zero was included just before the */
-/* matching code. However, this test costs time. A better solution is to */
-/* initialize all the entries in the hash table to point to a constant */
-/* string. The decompressor does the same. This solution requires no extra */
-/* test. The contents of the string do not matter so long as the string is */
-/* the same for the compressor and decompressor and contains at least */
-/* MAX_RAW_ITEM bytes. I chose consecutive decimal digits because they do not */
-/* have white space problems (e.g. there is no chance that the compiler will */
-/* replace more than one space by a TAB) and because they make the length of */
-/* the string obvious by inspection. */
-#define START_STRING_18 ((UBYTE *) "123456789012345678")
-
-/* In this algorithm, hash values have to be calculated at more than one */
-/* point. The following macro neatens the code up for this. */
-#define HASH(PTR) \
- (((40543*(((*(PTR))<<8)^((*((PTR)+1))<<4)^(*((PTR)+2))))>>4) & 0xFFF)
-
-/******************************************************************************/
-
-/* Input : Hand over the required amount of working memory in p_wrk_mem. */
-/* Input : Specify input block using p_src_first and src_len. */
-/* Input : Point p_dst_first to the start of the output zone (OZ). */
-/* Input : Point p_dst_len to a ULONG to receive the output length. */
-/* Input : Input block and output zone must not overlap. */
-/* Output : Length of output block written to *p_dst_len. */
-/* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. May */
-/* Output : write in OZ=Mem[p_dst_first..p_dst_first+src_len+MAX_CMP_GROUP-1].*/
-/* Output : Upon completion guaranteed *p_dst_len<=src_len+FLAG_BYTES. */
-LOCAL void compress_compress(UBYTE *p_wrk_mem,
- UBYTE *p_src_first, ULONG src_len,
- UBYTE *p_dst_first, LONG *p_dst_len)
-{
- /* p_src and p_dst step through the source and destination blocks. */
- register UBYTE *p_src = p_src_first;
- register UBYTE *p_dst = p_dst_first;
-
- /* The following variables are never modified and are used in the */
- /* calculations that determine when the main loop terminates. */
- UBYTE *p_src_post = p_src_first+src_len;
- UBYTE *p_dst_post = p_dst_first+src_len;
- UBYTE *p_src_max1 = p_src_first+src_len-MAX_RAW_ITEM;
- UBYTE *p_src_max16 = p_src_first+src_len-MAX_RAW_ITEM*16;
-
- /* The variables 'p_control' and 'control' are used to buffer control bits. */
- /* Before each group is processed, the next two bytes of the output block */
- /* are set aside for the control word for the group about to be processed. */
- /* 'p_control' is set to point to the first byte of that word. Meanwhile, */
- /* 'control' buffers the control bits being generated during the processing */
- /* of the group. Instead of having a counter to keep track of how many items */
- /* have been processed (=the number of bits in the control word), at the */
- /* start of each group, the top word of 'control' is filled with 1 bits. */
- /* As 'control' is shifted for each item, the 1 bits in the top word are */
- /* absorbed or destroyed. When they all run out (i.e. when the top word is */
- /* all zero bits, we know that we are at the end of a group. */
-# define TOPWORD 0xFFFF0000
- UBYTE *p_control;
- register ULONG control=TOPWORD;
-
- /* THe variable 'hash' always points to the first element of the hash table. */
- UBYTE **hash= (UBYTE **) ULONG_ALIGN_UP(p_wrk_mem);
-
- /* The following two variables represent the literal buffer. p_h1 points to */
- /* the hash table entry corresponding to the youngest literal. p_h2 points */
- /* to the hash table entry corresponding to the second youngest literal. */
- /* Note: p_h1=0=>p_h2=0 because zero values denote absence of a pending */
- /* literal. The variables are initialized to zero meaning an empty "buffer". */
- UBYTE **p_h1=NULL;
- UBYTE **p_h2=NULL;
-
- /* To start, we write the flag bytes. Being optimistic, we set the flag to */
- /* FLAG_COMPRESS. The remaining flag bytes are zeroed so as to keep the */
- /* algorithm deterministic. */
- *p_dst++=FLAG_COMPRESS;
- {UWORD i; for (i=2;i<=FLAG_BYTES;i++) *p_dst++=0;}
-
- /* Reserve the first word of output as the control word for the first group. */
- /* Note: This is undone at the end if the input block is empty. */
- p_control=p_dst; p_dst+=2;
-
- /* Initialize all elements of the hash table to point to a constant string. */
- /* Use of an unrolled loop speeds this up considerably. */
- {UWORD i; UBYTE **p_h=hash;
-# define ZH *p_h++=START_STRING_18
- for (i=0;i<256;i++) /* 256=HASH_TABLE_LENGTH/16. */
- {ZH;ZH;ZH;ZH;
- ZH;ZH;ZH;ZH;
- ZH;ZH;ZH;ZH;
- ZH;ZH;ZH;ZH;}
- }
-
- /* The main loop processes either 1 or 16 items per iteration. As its */
- /* termination logic is complicated, I have opted for an infinite loop */
- /* structure containing 'break' and 'goto' statements. */
- while (TRUE)
- {/* Begin main processing loop. */
-
- /* Note: All the variables here except unroll should be defined within */
- /* the inner loop. Unfortunately the loop hasn't got a block. */
- register UBYTE *p; /* Scans through targ phrase during matching. */
- register UBYTE *p_ziv= NULL ; /* Points to first byte of current Ziv. */
- register UWORD unroll; /* Loop counter for unrolled inner loop. */
- register UWORD index; /* Index of current hash table entry. */
- register UBYTE **p_h0 = NULL ; /* Pointer to current hash table entry. */
-
- /* Test for overrun and jump to overrun code if necessary. */
- if (p_dst>p_dst_post)
- goto overrun;
-
- /* The following cascade of if statements efficiently catches and deals */
- /* with varying degrees of closeness to the end of the input block. */
- /* When we get very close to the end, we stop updating the table and */
- /* code the remaining bytes as literals. This makes the code simpler. */
- unroll=16;
- if (p_src>p_src_max16)
- {
- unroll=1;
- if (p_src>p_src_max1)
- {
- if (p_src==p_src_post)
- break;
- else
- goto literal;
- }
- }
-
- /* This inner unrolled loop processes 'unroll' (whose value is either 1 */
- /* or 16) items. I have chosen to implement this loop with labels and */
- /* gotos to heighten the ease with which the loop may be implemented with */
- /* a single decrement and branch instruction in assembly language and */
- /* also because the labels act as highly readable place markers. */
- /* (Also because we jump into the loop for endgame literals (see above)). */
-
- begin_unrolled_loop:
-
- /* To process the next phrase, we hash the next three bytes and use */
- /* the resultant hash table index to look up the hash table. A pointer */
- /* to the entry is stored in p_h0 so as to avoid an array lookup. The */
- /* hash table entry *p_h0 is looked up yielding a pointer p to a */
- /* potential match of the Ziv in the history. */
- index=HASH(p_src);
- p_h0=&hash[index];
- p=*p_h0;
-
- /* Having looked up the candidate position, we are in a position to */
- /* attempt a match. The match loop has been unrolled using the PS */
- /* macro so that failure within the first three bytes automatically */
- /* results in the literal branch being taken. The coding is simple. */
- /* p_ziv saves p_src so we can let p_src wander. */
-# define PS *p++!=*p_src++
- p_ziv=p_src;
- if (PS || PS || PS)
- {
- /* Literal. */
-
- /* Code the literal byte as itself and a zero control bit. */
- p_src=p_ziv; literal: *p_dst++=*p_src++; control&=0xFFFEFFFF;
-
- /* We have just coded a literal. If we had two pending ones, that */
- /* makes three and we can update the hash table. */
- if (p_h2!=0)
- {*p_h2=p_ziv-2;}
-
- /* In any case, rotate the hash table pointers for next time. */
- p_h2=p_h1; p_h1=p_h0;
-
- }
- else
- {
- /* Copy */
-
- /* Match up to 15 remaining bytes using an unrolled loop and code. */
-#if 0
- PS || PS || PS || PS || PS || PS || PS || PS ||
- PS || PS || PS || PS || PS || PS || PS || p_src++;
-#else
- if (
- !( PS || PS || PS || PS || PS || PS || PS || PS ||
- PS || PS || PS || PS || PS || PS || PS )
- ) p_src++;
-#endif
- *p_dst++=((index&0xF00)>>4)|(--p_src-p_ziv-3);
- *p_dst++=index&0xFF;
-
- /* As we have just coded three bytes, we are now in a position to */
- /* update the hash table with the literal bytes that were pending */
- /* upon the arrival of extra context bytes. */
- if (p_h1!=0)
- {
- if (p_h2)
- {*p_h2=p_ziv-2; p_h2=NULL;}
- *p_h1=p_ziv-1; p_h1=NULL;
- }
-
- /* In any case, we can update the hash table based on the current */
- /* position as we just coded at least three bytes in a copy items. */
- *p_h0=p_ziv;
-
- }
- control>>=1;
-
- /* This loop is all set up for a decrement and jump instruction! */
-#ifndef linux
-` end_unrolled_loop: if (--unroll) goto begin_unrolled_loop;
-#else
- /* end_unrolled_loop: */ if (--unroll) goto begin_unrolled_loop;
-#endif
-
- /* At this point it will nearly always be the end of a group in which */
- /* case, we have to do some control-word processing. However, near the */
- /* end of the input block, the inner unrolled loop is only executed once. */
- /* This necessitates the 'if' test. */
- if ((control&TOPWORD)==0)
- {
- /* Write the control word to the place we saved for it in the output. */
- *p_control++= control &0xFF;
- *p_control = (control>>8) &0xFF;
-
- /* Reserve the next word in the output block for the control word */
- /* for the group about to be processed. */
- p_control=p_dst; p_dst+=2;
-
- /* Reset the control bits buffer. */
- control=TOPWORD;
- }
-
- } /* End main processing loop. */
-
- /* After the main processing loop has executed, all the input bytes have */
- /* been processed. However, the control word has still to be written to the */
- /* word reserved for it in the output at the start of the most recent group. */
- /* Before writing, the control word has to be shifted so that all the bits */
- /* are in the right place. The "empty" bit positions are filled with 1s */
- /* which partially fill the top word. */
- while(control&TOPWORD) control>>=1;
- *p_control++= control &0xFF;
- *p_control++=(control>>8) &0xFF;
-
- /* If the last group contained no items, delete the control word too. */
- if (p_control==p_dst) p_dst-=2;
-
- /* Write the length of the output block to the dst_len parameter and return. */
- *p_dst_len=p_dst-p_dst_first;
- return;
-
- /* Jump here as soon as an overrun is detected. An overrun is defined to */
- /* have occurred if p_dst>p_dst_first+src_len. That is, the moment the */
- /* length of the output written so far exceeds the length of the input block.*/
- /* The algorithm checks for overruns at least at the end of each group */
- /* which means that the maximum overrun is MAX_CMP_GROUP bytes. */
- /* Once an overrun occurs, the only thing to do is to set the copy flag and */
- /* copy the input over. */
- overrun:
-#if 0
- *p_dst_first=FLAG_COPY;
- fast_copy(p_src_first,p_dst_first+FLAG_BYTES,src_len);
- *p_dst_len=src_len+FLAG_BYTES;
-#else
- fast_copy(p_src_first,p_dst_first,src_len);
- *p_dst_len= -src_len; /* return a negative number to indicate uncompressed data */
-#endif
-}
-
-/******************************************************************************/
-
-/* Input : Hand over the required amount of working memory in p_wrk_mem. */
-/* Input : Specify input block using p_src_first and src_len. */
-/* Input : Point p_dst_first to the start of the output zone. */
-/* Input : Point p_dst_len to a ULONG to receive the output length. */
-/* Input : Input block and output zone must not overlap. User knows */
-/* Input : upperbound on output block length from earlier compression. */
-/* Input : In any case, maximum expansion possible is nine times. */
-/* Output : Length of output block written to *p_dst_len. */
-/* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */
-/* Output : Writes only in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */
-LOCAL void compress_decompress( UBYTE *p_wrk_mem,
- UBYTE *p_src_first, LONG src_len,
- UBYTE *p_dst_first, ULONG *p_dst_len)
-{
- /* Byte pointers p_src and p_dst scan through the input and output blocks. */
- register UBYTE *p_src = p_src_first+FLAG_BYTES;
- register UBYTE *p_dst = p_dst_first;
- /* we need to avoid a SEGV when trying to uncompress corrupt data */
- register UBYTE *p_dst_post = p_dst_first + *p_dst_len;
-
- /* The following two variables are never modified and are used to control */
- /* the main loop. */
- UBYTE *p_src_post = p_src_first+src_len;
- UBYTE *p_src_max16 = p_src_first+src_len-(MAX_CMP_GROUP-2);
-
- /* The hash table is the only resident of the working memory. The hash table */
- /* contains HASH_TABLE_LENGTH=4096 pointers to positions in the history. To */
- /* keep Macintoshes happy, it is longword aligned. */
- UBYTE **hash = (UBYTE **) ULONG_ALIGN_UP(p_wrk_mem);
-
- /* The variable 'control' is used to buffer the control bits which appear in */
- /* groups of 16 bits (control words) at the start of each compressed group. */
- /* When each group is read, bit 16 of the register is set to one. Whenever */
- /* a new bit is needed, the register is shifted right. When the value of the */
- /* register becomes 1, we know that we have reached the end of a group. */
- /* Initializing the register to 1 thus instructs the code to follow that it */
- /* should read a new control word immediately. */
- register ULONG control=1;
-
- /* The value of 'literals' is always in the range 0..3. It is the number of */
- /* consecutive literal items just seen. We have to record this number so as */
- /* to know when to update the hash table. When literals gets to 3, there */
- /* have been three consecutive literals and we can update at the position of */
- /* the oldest of the three. */
- register UWORD literals=0;
-
- /* Check the leading copy flag to see if the compressor chose to use a copy */
- /* operation instead of a compression operation. If a copy operation was */
- /* used, then all we need to do is copy the data over, set the output length */
- /* and return. */
-#if 0
- if (*p_src_first==FLAG_COPY)
- {
- fast_copy(p_src_first+FLAG_BYTES,p_dst_first,src_len-FLAG_BYTES);
- *p_dst_len=src_len-FLAG_BYTES;
- return;
- }
-#else
- if ( src_len < 0 )
- {
- fast_copy(p_src_first,p_dst_first,-src_len );
- *p_dst_len = (ULONG)-src_len;
- return;
- }
-#endif
-
- /* Initialize all elements of the hash table to point to a constant string. */
- /* Use of an unrolled loop speeds this up considerably. */
- {UWORD i; UBYTE **p_h=hash;
-# define ZJ *p_h++=START_STRING_18
- for (i=0;i<256;i++) /* 256=HASH_TABLE_LENGTH/16. */
- {ZJ;ZJ;ZJ;ZJ;
- ZJ;ZJ;ZJ;ZJ;
- ZJ;ZJ;ZJ;ZJ;
- ZJ;ZJ;ZJ;ZJ;}
- }
-
- /* The outer loop processes either 1 or 16 items per iteration depending on */
- /* how close p_src is to the end of the input block. */
- while (p_src!=p_src_post)
- {/* Start of outer loop */
-
- register UWORD unroll; /* Counts unrolled loop executions. */
-
- /* When 'control' has the value 1, it means that the 16 buffered control */
- /* bits that were read in at the start of the current group have all been */
- /* shifted out and that all that is left is the 1 bit that was injected */
- /* into bit 16 at the start of the current group. When we reach the end */
- /* of a group, we have to load a new control word and inject a new 1 bit. */
- if (control==1)
- {
- control=0x10000|*p_src++;
- control|=(*p_src++)<<8;
- }
-
- /* If it is possible that we are within 16 groups from the end of the */
- /* input, execute the unrolled loop only once, else process a whole group */
- /* of 16 items by looping 16 times. */
- unroll= p_src<=p_src_max16 ? 16 : 1;
-
- /* This inner loop processes one phrase (item) per iteration. */
- while (unroll--)
- { /* Begin unrolled inner loop. */
-
- /* Process a literal or copy item depending on the next control bit. */
- if (control&1)
- {
- /* Copy item. */
-
- register UBYTE *p; /* Points to place from which to copy. */
- register UWORD lenmt; /* Length of copy item minus three. */
- register UBYTE **p_hte; /* Pointer to current hash table entry.*/
- register UBYTE *p_ziv=p_dst; /* Pointer to start of current Ziv. */
-
- /* Read and dismantle the copy word. Work out from where to copy. */
- lenmt=*p_src++;
- p_hte=&hash[((lenmt&0xF0)<<4)|*p_src++];
- p=*p_hte;
- lenmt&=0xF;
-
- /* Now perform the copy using a half unrolled loop. */
- *p_dst++=*p++;
- *p_dst++=*p++;
- *p_dst++=*p++;
- while (lenmt--)
- *p_dst++=*p++;
-
- /* Because we have just received 3 or more bytes in a copy item */
- /* (whose bytes we have just installed in the output), we are now */
- /* in a position to flush all the pending literal hashings that had */
- /* been postponed for lack of bytes. */
- if (literals>0)
- {
- register UBYTE *r=p_ziv-literals;
- hash[HASH(r)]=r;
- if (literals==2)
- {r++; hash[HASH(r)]=r;}
- literals=0;
- }
-
- /* In any case, we can immediately update the hash table with the */
- /* current position. We don't need to do a HASH(...) to work out */
- /* where to put the pointer, as the compressor just told us!!! */
- *p_hte=p_ziv;
-
- }
- else
- {
- /* Literal item. */
-
- /* Copy over the literal byte. */
- *p_dst++=*p_src++;
-
- /* If we now have three literals waiting to be hashed into the hash */
- /* table, we can do one of them now (because there are three). */
- if (++literals == 3)
- {register UBYTE *p=p_dst-3; hash[HASH(p)]=p; literals=2;}
- }
-
- /* Shift the control buffer so the next control bit is in bit 0. */
- control>>=1;
-#if 1
- if (p_dst > p_dst_post)
- {
- /* Shit: we tried to decompress corrupt data */
- *p_dst_len = 0;
- return;
- }
-#endif
- } /* End unrolled inner loop. */
-
- } /* End of outer loop */
-
- /* Write the length of the decompressed data before returning. */
- *p_dst_len=p_dst-p_dst_first;
-}
-
-/******************************************************************************/
-/* End of LZRW3.C */
-/******************************************************************************/
diff --git a/drivers/char/ftape/compressor/lzrw3.h b/drivers/char/ftape/compressor/lzrw3.h
deleted file mode 100644
index 533feba4752..00000000000
--- a/drivers/char/ftape/compressor/lzrw3.h
+++ /dev/null
@@ -1,253 +0,0 @@
-#ifndef _LZRW3_H
-#define _LZRW3_H
-/*
- * $Source: /homes/cvs/ftape-stacked/ftape/compressor/lzrw3.h,v $
- * $Revision: 1.1 $
- * $Date: 1997/10/05 19:12:30 $
- *
- * include files for lzrw3. Only slighty modified from the original
- * version. Assembles the three include files compress.h, port.h and
- * fastcopy.h from the original lzrw3 package.
- *
- */
-
-#include <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 65ffc0be3df..00000000000
--- a/drivers/char/ftape/compressor/zftape-compress.c
+++ /dev/null
@@ -1,1203 +0,0 @@
-/*
- * Copyright (C) 1994-1997 Claus-Justus Heine
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
- USA.
-
- *
- * This file implements a "generic" interface between the *
- * zftape-driver and a compression-algorithm. The *
- * compression-algorithm currently used is a LZ77. I use the *
- * implementation lzrw3 by Ross N. Williams (Renaissance *
- * Software). The compression program itself is in the file
- * lzrw3.c * and lzrw3.h. To adopt another compression algorithm
- * the functions * zft_compress() and zft_uncompress() must be
- * changed * appropriately. See below.
- */
-
-#include <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 f200741e33b..00000000000
--- a/drivers/char/ftape/compressor/zftape-compress.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef _ZFTAPE_COMPRESS_H
-#define _ZFTAPE_COMPRESS_H
-/*
- * Copyright (c) 1994-1997 Claus-Justus Heine
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
- USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/compressor/zftape-compress.h,v $
- * $Revision: 1.1 $
- * $Date: 1997/10/05 19:12:32 $
- *
- * This file contains macros and definitions for zftape's
- * builtin compression code.
- *
- */
-
-#include "../zftape/zftape-buffers.h"
-#include "../zftape/zftape-vtbl.h"
-#include "../compressor/lzrw3.h"
-
-/* CMPR_WRK_MEM_SIZE gives the size of the compression wrk_mem */
-/* I got these out of lzrw3.c */
-#define U(X) ((__u32) X)
-#define SIZE_P_BYTE (U(sizeof(__u8 *)))
-#define ALIGNMENT_FUDGE (U(16))
-
-#define CMPR_WRK_MEM_SIZE (U(4096)*(SIZE_P_BYTE) + ALIGNMENT_FUDGE)
-
-/* the maximum number of bytes the size of the "compressed" data can
- * exceed the uncompressed data. As it is quite useless to compress
- * data twice it is sometimes the case that it is more efficient to
- * copy a block of data but to feed it to the "compression"
- * algorithm. In this case there are some flag bytes or the like
- * proceding the "compressed" data. THAT MUST NOT BE THE CASE for the
- * algorithm we use for this driver. Instead, the high bit 15 of
- * compressed_size:
- *
- * compressed_size = ftape_compress()
- *
- * must be set in such a case.
- *
- * Nevertheless, it might also be as for lzrw3 that there is an
- * "intermediate" overrun that exceeds the amount of the compressed
- * data that is actually produced. During the algorithm we need in the
- * worst case MAX_CMP_GROUP bytes more than the input-size.
- */
-#define MAX_CMP_GROUP (2+16*2) /* from lzrw3.c */
-
-#define CMPR_OVERRUN MAX_CMP_GROUP /* during compression */
-
-/****************************************************/
-
-#define CMPR_BUFFER_SIZE (MAX_BLOCK_SIZE + CMPR_OVERRUN)
-
-/* the compression map stores the byte offset compressed blocks within
- * the current volume for catridges with format code 2,3 and 5
- * (and old versions of zftape) and the offset measured in kilobytes for
- * format code 4 and 6. This gives us a possible max. size of a
- * compressed volume of 1024*4GIG which should be enough.
- */
-typedef __u32 CmprMap;
-
-/* globals
- */
-
-/* exported functions
- */
-
-#endif /* _ZFTAPE_COMPRESS_H */
diff --git a/drivers/char/ftape/lowlevel/Makefile b/drivers/char/ftape/lowlevel/Makefile
deleted file mode 100644
index febab07ba42..00000000000
--- a/drivers/char/ftape/lowlevel/Makefile
+++ /dev/null
@@ -1,43 +0,0 @@
-#
-# Copyright (C) 1996, 1997 Clau-Justus Heine.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; see the file COPYING. If not, write to
-# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-# $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/Makefile,v $
-# $Revision: 1.4 $
-# $Date: 1997/10/07 09:26:02 $
-#
-# Makefile for the lowlevel part QIC-40/80/3010/3020 floppy-tape
-# driver for Linux.
-#
-
-obj-$(CONFIG_FTAPE) += ftape.o
-
-ftape-objs := ftape-init.o fdc-io.o fdc-isr.o \
- ftape-bsm.o ftape-ctl.o ftape-read.o ftape-rw.o \
- ftape-write.o ftape-io.o ftape-calibr.o ftape-ecc.o fc-10.o \
- ftape-buffer.o ftape-format.o ftape_syms.o
-
-ifeq ($(CONFIG_FTAPE),y)
-ftape-objs += ftape-setup.o
-endif
-
-ifndef CONFIG_FT_NO_TRACE_AT_ALL
-ftape-objs += ftape-tracing.o
-endif
-
-ifeq ($(CONFIG_FT_PROC_FS),y)
-ftape-objs += ftape-proc.o
-endif
diff --git a/drivers/char/ftape/lowlevel/fc-10.c b/drivers/char/ftape/lowlevel/fc-10.c
deleted file mode 100644
index 9bc1cddade7..00000000000
--- a/drivers/char/ftape/lowlevel/fc-10.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- *
-
- Copyright (C) 1993,1994 Jon Tombs.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- The entire guts of this program was written by dosemu, modified to
- record reads and writes to the ports in the 0x180-0x188 address space,
- while running the CMS program TAPE.EXE V2.0.5 supplied with the drive.
-
- Modified to use an array of addresses and generally cleaned up (made
- much shorter) 4 June 94, dosemu isn't that good at writing short code it
- would seem :-). Made independent of 0x180, but I doubt it will work
- at any other address.
-
- Modified for distribution with ftape source. 21 June 94, SJL.
-
- Modifications on 20 October 95, by Daniel Cohen (catman@wpi.edu):
- Modified to support different DMA, IRQ, and IO Ports. Borland's
- Turbo Debugger in virtual 8086 mode (TD386.EXE with hardware breakpoints
- provided by the TDH386.SYS Device Driver) was used on the CMS program
- TAPE V4.0.5. I set breakpoints on I/O to ports 0x180-0x187. Note that
- CMS's program will not successfully configure the tape drive if you set
- breakpoints on IO Reads, but you can set them on IO Writes without problems.
- Known problems:
- - You can not use DMA Channels 5 or 7.
-
- Modification on 29 January 96, by Daniel Cohen (catman@wpi.edu):
- Modified to only accept IRQs 3 - 7, or 9. Since we can only send a 3 bit
- number representing the IRQ to the card, special handling is required when
- IRQ 9 is selected. IRQ 2 and 9 are the same, and we should request IRQ 9
- from the kernel while telling the card to use IRQ 2. Thanks to Greg
- Crider (gcrider@iclnet.org) for finding and locating this bug, as well as
- testing the patch.
-
- Modification on 11 December 96, by Claus Heine (claus@momo.math.rwth-aachen.de):
- Modified a little to use variahle ft_fdc_base, ft_fdc_irq, ft_fdc_dma
- instead of preprocessor symbols. Thus we can compile this into the module
- or kernel and let the user specify the options as command line arguments.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fc-10.c,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:18:04 $
- *
- * This file contains code for the CMS FC-10/FC-20 card.
- */
-
-#include <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 da7b88bca88..00000000000
--- a/drivers/char/ftape/lowlevel/fc-10.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef _FC_10_H
-#define _FC_10_H
-
-/*
- * Copyright (C) 1994-1996 Bas Laarhoven.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fc-10.h,v $
- * $Revision: 1.1 $
- * $Date: 1997/09/19 09:05:22 $
- *
- * This file contains definitions for the FC-10 code
- * of the QIC-40/80 floppy-tape driver for Linux.
- */
-
-/*
- * fc-10.c defined global vars.
- */
-
-/*
- * fc-10.c defined global functions.
- */
-extern int fc10_enable(void);
-
-#endif
diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c
deleted file mode 100644
index bbcf918f056..00000000000
--- a/drivers/char/ftape/lowlevel/fdc-io.c
+++ /dev/null
@@ -1,1349 +0,0 @@
-/*
- * Copyright (C) 1993-1996 Bas Laarhoven,
- * (C) 1996-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-io.c,v $
- * $Revision: 1.7.4.2 $
- * $Date: 1997/11/16 14:48:17 $
- *
- * This file contains the low-level floppy disk interface code
- * for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for
- * Linux.
- */
-
-#include <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(&current->sighand->siglock);
- old_sigmask = current->blocked;
- sigfillset(&current->blocked);
- recalc_sigpending();
- spin_unlock_irq(&current->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(&current->sighand->siglock);
- current->blocked = old_sigmask;
- recalc_sigpending();
- spin_unlock_irq(&current->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(&reg[i]);
- TRACE(ft_t_fdc_dma, "Register %d = 0x%02x", i, reg[i]);
- }
- if (fifo_state && lock_state && fifo_thr) {
- *fifo_state = (reg[8] & 0x20) == 0;
- *lock_state = reg[7] & 0x80;
- *fifo_thr = 1 + (reg[8] & 0x0f);
- }
- TRACE(ft_t_noise,
- "original fifo state: %sabled, threshold %d, %slocked",
- ((reg[8] & 0x20) == 0) ? "en" : "dis",
- 1 + (reg[8] & 0x0f), (reg[7] & 0x80) ? "" : "not ");
- /* If fdc is already locked, unlock it first ! */
- if (reg[7] & 0x80) {
- fdc_ready_wait(100);
- TRACE_CATCH(fdc_issue_command(cmd3, NR_ITEMS(cmd3), &stat, 1),
- TRACE(ft_t_bug, "FDC unlock command failed, "
- "configuration unchanged"));
- }
- fdc_fifo_locked = 0;
- /* Enable fifo and set threshold at xx bytes to allow a
- * reasonably large latency and reduce number of dma bursts.
- */
- fdc_ready_wait(100);
- if ((result = fdc_command(cmd1, NR_ITEMS(cmd1))) < 0) {
- TRACE(ft_t_bug, "configure cmd failed, fifo unchanged");
- }
- /* Now lock configuration so reset will not change it
- */
- if(fdc_issue_command(cmd2, NR_ITEMS(cmd2), &stat, 1) < 0 ||
- stat != 0x10) {
- TRACE_ABORT(-EIO, ft_t_bug,
- "FDC lock command failed, stat = 0x%02x", stat);
- }
- fdc_fifo_locked = 1;
- TRACE_EXIT result;
-}
-
-static int fdc_fifo_enable(void)
-{
- TRACE_FUN(ft_t_any);
-
- if (fdc_fifo_locked) {
- TRACE_ABORT(0, ft_t_warn, "Fifo not enabled because locked");
- }
- TRACE_CATCH(fdc_fifo_threshold(ft_fdc_threshold /* bytes */,
- &fdc_fifo_state,
- &fdc_lock_state,
- &fdc_fifo_thr),);
- TRACE_CATCH(fdc_fifo_threshold(ft_fdc_threshold /* bytes */,
- NULL, NULL, NULL),);
- TRACE_EXIT 0;
-}
-
-/* Determine fd controller type
- */
-static __u8 fdc_save_state[2];
-
-static int fdc_probe(void)
-{
- __u8 cmd[1];
- __u8 stat[16]; /* must be able to hold dumpregs & save results */
- int i;
- TRACE_FUN(ft_t_any);
-
- /* Try to find out what kind of fd controller we have to deal with
- * Scheme borrowed from floppy driver:
- * first try if FDC_DUMPREGS command works
- * (this indicates that we have a 82072 or better)
- * then try the FDC_VERSION command (82072 doesn't support this)
- * then try the FDC_UNLOCK command (some older 82077's don't support this)
- * then try the FDC_PARTID command (82078's support this)
- */
- cmd[0] = FDC_DUMPREGS;
- if (fdc_issue_command(cmd, 1, stat, 1) != 0) {
- TRACE_ABORT(no_fdc, ft_t_bug, "No FDC found");
- }
- if (stat[0] == 0x80) {
- /* invalid command: must be pre 82072 */
- TRACE_ABORT(i8272,
- ft_t_warn, "Type 8272A/765A compatible FDC found");
- }
- fdc_result(&stat[1], 9);
- fdc_save_state[0] = stat[7];
- fdc_save_state[1] = stat[8];
- cmd[0] = FDC_VERSION;
- if (fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] == 0x80) {
- TRACE_ABORT(i8272, ft_t_warn, "Type 82072 FDC found");
- }
- if (*stat != 0x90) {
- TRACE_ABORT(i8272, ft_t_warn, "Unknown FDC found");
- }
- cmd[0] = FDC_UNLOCK;
- if(fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] != 0x00) {
- TRACE_ABORT(i8272, ft_t_warn,
- "Type pre-1991 82077 FDC found, "
- "treating it like a 82072");
- }
- if (fdc_save_state[0] & 0x80) { /* was locked */
- cmd[0] = FDC_LOCK; /* restore lock */
- (void)fdc_issue_command(cmd, 1, stat, 1);
- TRACE(ft_t_warn, "FDC is already locked");
- }
- /* Test for a i82078 FDC */
- cmd[0] = FDC_PARTID;
- if (fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] == 0x80) {
- /* invalid command: not a i82078xx type FDC */
- for (i = 0; i < 4; ++i) {
- outb_p(i, fdc.tdr);
- if ((inb_p(fdc.tdr) & 0x03) != i) {
- TRACE_ABORT(i82077,
- ft_t_warn, "Type 82077 FDC found");
- }
- }
- TRACE_ABORT(i82077AA, ft_t_warn, "Type 82077AA FDC found");
- }
- /* FDC_PARTID cmd succeeded */
- switch (stat[0] >> 5) {
- case 0x0:
- /* i82078SL or i82078-1. The SL part cannot run at
- * 2Mbps (the SL and -1 dies are identical; they are
- * speed graded after production, according to Intel).
- * Some SL's can be detected by doing a SAVE cmd and
- * look at bit 7 of the first byte (the SEL3V# bit).
- * If it is 0, the part runs off 3Volts, and hence it
- * is a SL.
- */
- cmd[0] = FDC_SAVE;
- if(fdc_issue_command(cmd, 1, stat, 16) < 0) {
- TRACE(ft_t_err, "FDC_SAVE failed. Dunno why");
- /* guess we better claim the fdc to be a i82078 */
- TRACE_ABORT(i82078,
- ft_t_warn,
- "Type i82078 FDC (i suppose) found");
- }
- if ((stat[0] & FDC_SEL3V_BIT)) {
- /* fdc running off 5Volts; Pray that it's a i82078-1
- */
- TRACE_ABORT(i82078_1, ft_t_warn,
- "Type i82078-1 or 5Volt i82078SL FDC found");
- }
- TRACE_ABORT(i82078, ft_t_warn,
- "Type 3Volt i82078SL FDC (1Mbps) found");
- case 0x1:
- case 0x2: /* S82078B */
- /* The '78B isn't '78 compatible. Detect it as a '77AA */
- TRACE_ABORT(i82077AA, ft_t_warn, "Type i82077AA FDC found");
- case 0x3: /* NSC PC8744 core; used in several super-IO chips */
- TRACE_ABORT(i82077AA,
- ft_t_warn, "Type 82077AA compatible FDC found");
- default:
- TRACE(ft_t_warn, "A previously undetected FDC found");
- TRACE_ABORT(i82077AA, ft_t_warn,
- "Treating it as a 82077AA. Please report partid= %d",
- stat[0]);
- } /* switch(stat[ 0] >> 5) */
- TRACE_EXIT no_fdc;
-}
-
-static int fdc_request_regions(void)
-{
- TRACE_FUN(ft_t_flow);
-
- if (ft_mach2 || ft_probe_fc10) {
- if (!request_region(fdc.sra, 8, "fdc (ft)")) {
-#ifndef BROKEN_FLOPPY_DRIVER
- TRACE_EXIT -EBUSY;
-#else
- TRACE(ft_t_warn,
-"address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra);
-#endif
- }
- } else {
- if (!request_region(fdc.sra, 6, "fdc (ft)")) {
-#ifndef BROKEN_FLOPPY_DRIVER
- TRACE_EXIT -EBUSY;
-#else
- TRACE(ft_t_warn,
-"address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra);
-#endif
- }
- if (!request_region(fdc.sra + 7, 1, "fdc (ft)")) {
-#ifndef BROKEN_FLOPPY_DRIVER
- release_region(fdc.sra, 6);
- TRACE_EXIT -EBUSY;
-#else
- TRACE(ft_t_warn,
-"address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra + 7);
-#endif
- }
- }
- TRACE_EXIT 0;
-}
-
-void fdc_release_regions(void)
-{
- TRACE_FUN(ft_t_flow);
-
- if (fdc.sra != 0) {
- if (fdc.dor2 != 0) {
- release_region(fdc.sra, 8);
- } else {
- release_region(fdc.sra, 6);
- release_region(fdc.dir, 1);
- }
- }
- TRACE_EXIT;
-}
-
-static int fdc_config_regs(unsigned int fdc_base,
- unsigned int fdc_irq,
- unsigned int fdc_dma)
-{
- TRACE_FUN(ft_t_flow);
-
- fdc.irq = fdc_irq;
- fdc.dma = fdc_dma;
- fdc.sra = fdc_base;
- fdc.srb = fdc_base + 1;
- fdc.dor = fdc_base + 2;
- fdc.tdr = fdc_base + 3;
- fdc.msr = fdc.dsr = fdc_base + 4;
- fdc.fifo = fdc_base + 5;
- fdc.dir = fdc.ccr = fdc_base + 7;
- fdc.dor2 = (ft_mach2 || ft_probe_fc10) ? fdc_base + 6 : 0;
- TRACE_CATCH(fdc_request_regions(), fdc.sra = 0);
- TRACE_EXIT 0;
-}
-
-static int fdc_config(void)
-{
- static int already_done;
- TRACE_FUN(ft_t_any);
-
- if (already_done) {
- TRACE_CATCH(fdc_request_regions(),);
- *(fdc.hook) = fdc_isr; /* hook our handler in */
- TRACE_EXIT 0;
- }
- if (ft_probe_fc10) {
- int fc_type;
-
- TRACE_CATCH(fdc_config_regs(ft_fdc_base,
- ft_fdc_irq, ft_fdc_dma),);
- fc_type = fc10_enable();
- if (fc_type != 0) {
- TRACE(ft_t_warn, "FC-%c0 controller found", '0' + fc_type);
- fdc.type = fc10;
- fdc.hook = &do_ftape;
- *(fdc.hook) = fdc_isr; /* hook our handler in */
- already_done = 1;
- TRACE_EXIT 0;
- } else {
- TRACE(ft_t_warn, "FC-10/20 controller not found");
- fdc_release_regions();
- fdc.type = no_fdc;
- ft_probe_fc10 = 0;
- ft_fdc_base = 0x3f0;
- ft_fdc_irq = 6;
- ft_fdc_dma = 2;
- }
- }
- TRACE(ft_t_warn, "fdc base: 0x%x, irq: %d, dma: %d",
- ft_fdc_base, ft_fdc_irq, ft_fdc_dma);
- TRACE_CATCH(fdc_config_regs(ft_fdc_base, ft_fdc_irq, ft_fdc_dma),);
- fdc.hook = &do_ftape;
- *(fdc.hook) = fdc_isr; /* hook our handler in */
- already_done = 1;
- TRACE_EXIT 0;
-}
-
-static irqreturn_t ftape_interrupt(int irq, void *dev_id)
-{
- void (*handler) (void) = *fdc.hook;
- int handled = 0;
- TRACE_FUN(ft_t_any);
-
- *fdc.hook = NULL;
- if (handler) {
- handled = 1;
- handler();
- } else {
- TRACE(ft_t_bug, "Unexpected ftape interrupt");
- }
- TRACE_EXIT IRQ_RETVAL(handled);
-}
-
-static int fdc_grab_irq_and_dma(void)
-{
- TRACE_FUN(ft_t_any);
-
- if (fdc.hook == &do_ftape) {
- /* Get fast interrupt handler.
- */
- if (request_irq(fdc.irq, ftape_interrupt,
- IRQF_DISABLED, "ft", ftape_id)) {
- TRACE_ABORT(-EIO, ft_t_bug,
- "Unable to grab IRQ%d for ftape driver",
- fdc.irq);
- }
- if (request_dma(fdc.dma, ftape_id)) {
- free_irq(fdc.irq, ftape_id);
- TRACE_ABORT(-EIO, ft_t_bug,
- "Unable to grab DMA%d for ftape driver",
- fdc.dma);
- }
- }
- if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) {
- /* Using same dma channel or irq as standard fdc, need
- * to disable the dma-gate on the std fdc. This
- * couldn't be done in the floppy driver as some
- * laptops are using the dma-gate to enter a low power
- * or even suspended state :-(
- */
- outb_p(FDC_RESET_NOT, 0x3f2);
- TRACE(ft_t_noise, "DMA-gate on standard fdc disabled");
- }
- TRACE_EXIT 0;
-}
-
-int fdc_release_irq_and_dma(void)
-{
- TRACE_FUN(ft_t_any);
-
- if (fdc.hook == &do_ftape) {
- disable_dma(fdc.dma); /* just in case... */
- free_dma(fdc.dma);
- free_irq(fdc.irq, ftape_id);
- }
- if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) {
- /* Using same dma channel as standard fdc, need to
- * disable the dma-gate on the std fdc. This couldn't
- * be done in the floppy driver as some laptops are
- * using the dma-gate to enter a low power or even
- * suspended state :-(
- */
- outb_p(FDC_RESET_NOT | FDC_DMA_MODE, 0x3f2);
- TRACE(ft_t_noise, "DMA-gate on standard fdc enabled again");
- }
- TRACE_EXIT 0;
-}
-
-int fdc_init(void)
-{
- TRACE_FUN(ft_t_any);
-
- /* find a FDC to use */
- TRACE_CATCH(fdc_config(),);
- TRACE_CATCH(fdc_grab_irq_and_dma(), fdc_release_regions());
- ftape_motor = 0;
- fdc_catch_stray_interrupts(0); /* clear number of awainted
- * stray interrupte
- */
- fdc_catch_stray_interrupts(1); /* one always comes (?) */
- TRACE(ft_t_flow, "resetting fdc");
- fdc_set_seek_rate(2); /* use nominal QIC step rate */
- fdc_reset(); /* init fdc & clear track counters */
- if (fdc.type == no_fdc) { /* no FC-10 or FC-20 found */
- fdc.type = fdc_probe();
- fdc_reset(); /* update with new knowledge */
- }
- if (fdc.type == no_fdc) {
- fdc_release_irq_and_dma();
- fdc_release_regions();
- TRACE_EXIT -ENXIO;
- }
- if (fdc.type >= i82077) {
- if (fdc_fifo_enable() < 0) {
- TRACE(ft_t_warn, "couldn't enable fdc fifo !");
- } else {
- TRACE(ft_t_flow, "fdc fifo enabled and locked");
- }
- }
- TRACE_EXIT 0;
-}
diff --git a/drivers/char/ftape/lowlevel/fdc-io.h b/drivers/char/ftape/lowlevel/fdc-io.h
deleted file mode 100644
index 7ec3c72178b..00000000000
--- a/drivers/char/ftape/lowlevel/fdc-io.h
+++ /dev/null
@@ -1,252 +0,0 @@
-#ifndef _FDC_IO_H
-#define _FDC_IO_H
-
-/*
- * Copyright (C) 1993-1996 Bas Laarhoven,
- * (C) 1996-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-io.h,v $
- * $Revision: 1.3 $
- * $Date: 1997/10/05 19:18:06 $
- *
- * This file contains the declarations for the low level
- * functions that communicate with the floppy disk controller,
- * for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for
- * Linux.
- */
-
-#include <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 ad2bc733ae1..00000000000
--- a/drivers/char/ftape/lowlevel/fdc-isr.c
+++ /dev/null
@@ -1,1170 +0,0 @@
-/*
- * Copyright (C) 1994-1996 Bas Laarhoven,
- * (C) 1996-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-isr.c,v $
- * $Revision: 1.9 $
- * $Date: 1997/10/17 23:01:53 $
- *
- * This file contains the interrupt service routine and
- * associated code for the QIC-40/80/3010/3020 floppy-tape driver
- * "ftape" for Linux.
- */
-
-#include <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 065aa978942..00000000000
--- a/drivers/char/ftape/lowlevel/fdc-isr.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef _FDC_ISR_H
-#define _FDC_ISR_H
-
-/*
- * Copyright (C) 1993-1996 Bas Laarhoven,
- * (C) 1996-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-isr.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:18:07 $
- *
- * This file declares the global variables necessary to
- * synchronize the interrupt service routine (isr) with the
- * remainder of the QIC-40/80/3010/3020 floppy-tape driver
- * "ftape" for Linux.
- */
-
-/*
- * fdc-isr.c defined public variables
- */
-extern volatile int ft_expected_stray_interrupts; /* masks stray interrupts */
-extern volatile int ft_seek_completed; /* flag set by isr */
-extern volatile int ft_interrupt_seen; /* flag set by isr */
-extern volatile int ft_hide_interrupt; /* flag set by isr */
-
-/*
- * fdc-io.c defined public functions
- */
-extern void fdc_isr(void);
-
-/*
- * A kernel hook that steals one interrupt from the floppy
- * driver (Should be fixed when the new fdc driver gets ready)
- * See the linux kernel source files:
- * drivers/block/floppy.c & drivers/block/blk.h
- * for the details.
- */
-extern void (*do_floppy) (void);
-
-#endif
diff --git a/drivers/char/ftape/lowlevel/ftape-bsm.c b/drivers/char/ftape/lowlevel/ftape-bsm.c
deleted file mode 100644
index d1a301cc344..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-bsm.c
+++ /dev/null
@@ -1,491 +0,0 @@
-/*
- * Copyright (C) 1994-1996 Bas Laarhoven,
- * (C) 1996-1997 Claus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-bsm.c,v $
- * $Revision: 1.3 $
- * $Date: 1997/10/05 19:15:15 $
- *
- * This file contains the bad-sector map handling code for
- * the QIC-117 floppy tape driver for Linux.
- * QIC-40, QIC-80, QIC-3010 and QIC-3020 maps are implemented.
- */
-
-#include <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 ed45465af4d..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-bsm.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef _FTAPE_BSM_H
-#define _FTAPE_BSM_H
-
-/*
- * Copyright (C) 1994-1996 Bas Laarhoven,
- * (C) 1996-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-bsm.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:18:07 $
- *
- * This file contains definitions for the bad sector map handling
- * routines for the QIC-117 floppy-tape driver for Linux.
- */
-
-#include <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 c706ff16277..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-buffer.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 1997 Claus-Justus Heine
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-buffer.c,v $
- * $Revision: 1.3 $
- * $Date: 1997/10/16 23:33:11 $
- *
- * This file contains the allocator/dealloctor for ftape's dynamic dma
- * buffer.
- */
-
-#include <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 eec99cee8f8..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-buffer.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef _FTAPE_BUFFER_H
-#define _FTAPE_BUFFER_H
-
-/*
- * Copyright (C) 1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-buffer.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:18:08 $
- *
- * This file contains the allocator/dealloctor for ftape's dynamic dma
- * buffer.
- */
-
-extern int ftape_set_nr_buffers(int cnt);
-
-#endif
diff --git a/drivers/char/ftape/lowlevel/ftape-calibr.c b/drivers/char/ftape/lowlevel/ftape-calibr.c
deleted file mode 100644
index 8e50bfd35a5..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-calibr.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright (C) 1993-1996 Bas Laarhoven.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-calibr.c,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:18:08 $
- *
- * GP calibration routine for processor speed dependent
- * functions.
- */
-
-#include <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 0c7e75246c7..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-calibr.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef _FTAPE_CALIBR_H
-#define _FTAPE_CALIBR_H
-
-/*
- * Copyright (C) 1993-1996 Bas Laarhoven.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-calibr.h,v $
- * $Revision: 1.1 $
- * $Date: 1997/09/19 09:05:26 $
- *
- * This file contains a gp calibration routine for
- * hardware dependent timeout functions.
- */
-
-extern void ftape_calibrate(char *name,
- void (*fun) (unsigned int),
- unsigned int *calibr_count,
- unsigned int *calibr_time);
-extern unsigned int ftape_timestamp(void);
-extern unsigned int ftape_timediff(unsigned int t0, unsigned int t1);
-
-#endif /* _FTAPE_CALIBR_H */
diff --git a/drivers/char/ftape/lowlevel/ftape-ctl.c b/drivers/char/ftape/lowlevel/ftape-ctl.c
deleted file mode 100644
index 5d7c1ce92d5..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-ctl.c
+++ /dev/null
@@ -1,896 +0,0 @@
-/*
- * Copyright (C) 1993-1996 Bas Laarhoven,
- * 1996-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-ctl.c,v $
- * $Revision: 1.4 $
- * $Date: 1997/11/11 14:37:44 $
- *
- * This file contains the non-read/write ftape functions for the
- * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux.
- */
-
-#include <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(&current->pending.signal, _DONT_BLOCK) &&
- !(sigtestsetmask(&current->pending.signal, _NEVER_BLOCK)) &&
- ftape_tape_running) {
- TRACE(ft_t_warn,
- "Interrupted by fatal signal and tape still running");
- ftape_dumb_stop();
- ftape_abort_operation(); /* it's annoying */
- } else {
- ftape_set_state(idle);
- }
- ftape_detach_drive();
- if (ft_history.used) {
- TRACE(ft_t_info, "== Non-fatal errors this run: ==");
- TRACE(ft_t_info, "fdc isr statistics:\n"
- KERN_INFO " id_am_errors : %3d\n"
- KERN_INFO " id_crc_errors : %3d\n"
- KERN_INFO " data_am_errors : %3d\n"
- KERN_INFO " data_crc_errors : %3d\n"
- KERN_INFO " overrun_errors : %3d\n"
- KERN_INFO " no_data_errors : %3d\n"
- KERN_INFO " retries : %3d",
- ft_history.id_am_errors, ft_history.id_crc_errors,
- ft_history.data_am_errors, ft_history.data_crc_errors,
- ft_history.overrun_errors, ft_history.no_data_errors,
- ft_history.retries);
- if (ft_history.used & 1) {
- TRACE(ft_t_info, "ecc statistics:\n"
- KERN_INFO " crc_errors : %3d\n"
- KERN_INFO " crc_failures : %3d\n"
- KERN_INFO " ecc_failures : %3d\n"
- KERN_INFO " sectors corrected: %3d",
- ft_history.crc_errors, ft_history.crc_failures,
- ft_history.ecc_failures, ft_history.corrected);
- }
- if (ft_history.defects > 0) {
- TRACE(ft_t_warn, "Warning: %d media defects!",
- ft_history.defects);
- }
- if (ft_history.rewinds > 0) {
- TRACE(ft_t_info, "tape motion statistics:\n"
- KERN_INFO "repositions : %3d",
- ft_history.rewinds);
- }
- }
- ft_failure = 1;
- TRACE_EXIT;
-}
-
-static void ftape_init_driver(void)
-{
- TRACE_FUN(ft_t_flow);
-
- ft_drive_type.vendor_id = UNKNOWN_VENDOR;
- ft_drive_type.speed = 0;
- ft_drive_type.wake_up = unknown_wake_up;
- ft_drive_type.name = "Unknown";
-
- ftape_timeout.seek = 650 * FT_SECOND;
- ftape_timeout.reset = 670 * FT_SECOND;
- ftape_timeout.rewind = 650 * FT_SECOND;
- ftape_timeout.head_seek = 15 * FT_SECOND;
- ftape_timeout.stop = 5 * FT_SECOND;
- ftape_timeout.pause = 16 * FT_SECOND;
-
- ft_qic_std = -1;
- ftape_tape_len = 0; /* unknown */
- ftape_current_command = 0;
- ftape_current_cylinder = -1;
-
- ft_segments_per_track = 102;
- ftape_segments_per_head = 1020;
- ftape_segments_per_cylinder = 4;
- ft_tracks_per_tape = 20;
-
- ft_failure = 1;
-
- ft_formatted = 0;
- ft_no_tape = 1;
- ft_write_protected = 1;
- ft_new_tape = 1;
-
- ft_driver_state = idle;
-
- ft_data_rate =
- ft_fdc_max_rate = 500;
- ft_drive_max_rate = 0; /* triggers set_rate_test() */
-
- ftape_init_drive_needed = 1;
-
- ft_header_segment_1 = -1;
- ft_header_segment_2 = -1;
- ft_used_header_segment = -1;
- ft_first_data_segment = -1;
- ft_last_data_segment = -1;
-
- ft_location.track = -1;
- ft_location.known = 0;
-
- ftape_tape_running = 0;
- ftape_might_be_off_track = 1;
-
- ftape_new_cartridge(); /* init some tape related variables */
- ftape_init_bsm();
- TRACE_EXIT;
-}
diff --git a/drivers/char/ftape/lowlevel/ftape-ctl.h b/drivers/char/ftape/lowlevel/ftape-ctl.h
deleted file mode 100644
index 5f5e30bc361..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-ctl.h
+++ /dev/null
@@ -1,162 +0,0 @@
-#ifndef _FTAPE_CTL_H
-#define _FTAPE_CTL_H
-
-/*
- * Copyright (C) 1993-1996 Bas Laarhoven,
- * (C) 1996-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-ctl.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:18:09 $
- *
- * This file contains the non-standard IOCTL related definitions
- * for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for
- * Linux.
- */
-
-#include <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 e5632f674bc..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-ecc.c
+++ /dev/null
@@ -1,853 +0,0 @@
-/*
- *
- * Copyright (c) 1993 Ning and David Mosberger.
-
- This is based on code originally written by Bas Laarhoven (bas@vimec.nl)
- and David L. Brown, Jr., and incorporates improvements suggested by
- Kai Harrekilde-Petersen.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
- USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-ecc.c,v $
- * $Revision: 1.3 $
- * $Date: 1997/10/05 19:18:10 $
- *
- * This file contains the Reed-Solomon error correction code
- * for the QIC-40/80 floppy-tape driver for Linux.
- */
-
-#include <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 4829146fe9a..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-ecc.h
+++ /dev/null
@@ -1,84 +0,0 @@
-#ifndef _FTAPE_ECC_H_
-#define _FTAPE_ECC_H_
-
-/*
- * Copyright (C) 1993 Ning and David Mosberger.
- * Original:
- * Copyright (C) 1993 Bas Laarhoven.
- * Copyright (C) 1992 David L. Brown, Jr.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
- USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-ecc.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:18:11 $
- *
- * This file contains the definitions for the
- * Reed-Solomon error correction code
- * for the QIC-40/80 tape streamer device driver.
- */
-
-#include "../lowlevel/ftape-bsm.h"
-
-#define BAD_CLEAR(entry) ((entry)=0)
-#define BAD_SET(entry,sector) ((entry)|=(1<<(sector)))
-#define BAD_CHECK(entry,sector) ((entry)&(1<<(sector)))
-
-/*
- * Return values for ecc_correct_data:
- */
-enum {
- ECC_OK, /* Data was correct. */
- ECC_CORRECTED, /* Correctable error in data. */
- ECC_FAILED, /* Could not correct data. */
-};
-
-/*
- * Representation of an in memory segment. MARKED_BAD lists the
- * sectors that were marked bad during formatting. If the N-th sector
- * in a segment is marked bad, bit 1<<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 5dd4c59a3f3..00000000000
--- 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 f1516156664..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-format.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef _FTAPE_FORMAT_H
-#define _FTAPE_FORMAT_H
-
-/*
- * Copyright (C) 1996-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-format.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:18:13 $
- *
- * This file contains the low level definitions for the
- * formatting support for the QIC-40/80/3010/3020 floppy-tape
- * driver "ftape" for Linux.
- */
-
-#ifdef __KERNEL__
-extern int ftape_format_track(const unsigned int track, const __u8 gap3);
-extern int ftape_format_status(unsigned int *segment_id);
-extern int ftape_verify_segment(const unsigned int segment_id, SectorMap *bsm);
-#endif /* __KERNEL__ */
-
-#endif
diff --git a/drivers/char/ftape/lowlevel/ftape-init.c b/drivers/char/ftape/lowlevel/ftape-init.c
deleted file mode 100644
index 4998132a81d..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-init.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 1993-1996 Bas Laarhoven,
- * (C) 1996-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * This file contains the code that interfaces the kernel
- * for the QIC-40/80/3010/3020 floppy-tape driver for Linux.
- */
-
-#include <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 99a7b8ab086..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-init.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef _FTAPE_INIT_H
-#define _FTAPE_INIT_H
-
-/*
- * Copyright (C) 1993-1996 Bas Laarhoven,
- * (C) 1996-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-init.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:18:16 $
- *
- * This file contains the definitions for the interface to
- * the Linux kernel for floppy tape driver ftape.
- *
- */
-
-#include <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 259015aeff5..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-io.c
+++ /dev/null
@@ -1,992 +0,0 @@
-/*
- * Copyright (C) 1993-1996 Bas Laarhoven,
- * (C) 1996 Kai Harrekilde-Petersen,
- * (C) 1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-io.c,v $
- * $Revision: 1.4 $
- * $Date: 1997/11/11 14:02:36 $
- *
- * This file contains the general control functions for the
- * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux.
- */
-
-#include <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 26a7baad871..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-io.h
+++ /dev/null
@@ -1,90 +0,0 @@
-#ifndef _FTAPE_IO_H
-#define _FTAPE_IO_H
-
-/*
- * Copyright (C) 1993-1996 Bas Laarhoven,
- * (C) 1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-io.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:18:18 $
- *
- * This file contains definitions for the glue part of the
- * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux.
- */
-
-#include <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 e805b15e0a1..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-proc.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 1997 Claus-Justus Heine
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-proc.c,v $
- * $Revision: 1.11 $
- * $Date: 1997/10/24 14:47:37 $
- *
- * This file contains the procfs interface for the
- * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux.
-
- * Old code removed, switched to dynamic proc entry.
- */
-
-
-#if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS)
-
-#include <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 264dfcc1d22..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-proc.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef _FTAPE_PROC_H
-#define _FTAPE_PROC_H
-
-/*
- * Copyright (C) 1997 Claus-Justus Heine
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-proc.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:18:20 $
- *
- * This file contains definitions for the procfs interface of the
- * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux.
- */
-
-#include <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 d967d8cd86d..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-read.c
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
- * Copyright (C) 1993-1996 Bas Laarhoven,
- * (C) 1996-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-read.c,v $
- * $Revision: 1.6 $
- * $Date: 1997/10/21 14:39:22 $
- *
- * This file contains the reading code
- * for the QIC-117 floppy-tape driver for Linux.
- *
- */
-
-#include <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 069f99f2a98..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-read.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef _FTAPE_READ_H
-#define _FTAPE_READ_H
-
-/*
- * Copyright (C) 1994-1996 Bas Laarhoven,
- * (C) 1996-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-read.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:18:22 $
- *
- * This file contains the definitions for the read functions
- * for the QIC-117 floppy-tape driver for Linux.
- *
- */
-
-/* ftape-read.c defined global functions.
- */
-typedef enum {
- FT_RD_SINGLE = 0,
- FT_RD_AHEAD = 1,
-} ft_read_mode_t;
-
-extern int ftape_read_header_segment(__u8 *address);
-extern int ftape_decode_header_segment(__u8 *address);
-extern int ftape_read_segment_fraction(const int segment,
- void *address,
- const ft_read_mode_t read_mode,
- const int start,
- const int size);
-#define ftape_read_segment(segment, address, read_mode) \
- ftape_read_segment_fraction(segment, address, read_mode, \
- 0, FT_SEGMENT_SIZE)
-extern void ftape_zap_read_buffers(void);
-
-#endif /* _FTAPE_READ_H */
diff --git a/drivers/char/ftape/lowlevel/ftape-rw.c b/drivers/char/ftape/lowlevel/ftape-rw.c
deleted file mode 100644
index c0d6dc2cbfd..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-rw.c
+++ /dev/null
@@ -1,1092 +0,0 @@
-/*
- * Copyright (C) 1993-1996 Bas Laarhoven,
- * (C) 1996-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-rw.c,v $
- * $Revision: 1.7 $
- * $Date: 1997/10/28 14:26:49 $
- *
- * This file contains some common code for the segment read and
- * segment write routines for the QIC-117 floppy-tape driver for
- * Linux.
- */
-
-#include <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(&current->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(&current->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(&current->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(&current->pending.signal, _DONT_BLOCK))) {
-
- if (retry && start_offset < 5) {
- start_offset ++;
- }
- /* Check if we are able to catch the requested
- * segment in time.
- */
- if ((ft_location.known || (determine_position() == 0)) &&
- ft_location.segment >=
- (segment_id -
- ((ftape_tape_running || ft_location.bot)
- ? 0 : start_offset))) {
- /* Too far ahead (in or past target segment).
- */
- if (ftape_tape_running) {
- if ((result = ftape_stop_tape(&status)) < 0) {
- TRACE(ft_t_err,
- "stop tape failed with code %d",
- result);
- break;
- }
- TRACE(ft_t_noise, "tape stopped");
- ftape_tape_running = 0;
- }
- TRACE(ft_t_noise, "repositioning");
- ++ft_history.rewinds;
- if (segment_id % ft_segments_per_track < start_offset){
- TRACE(ft_t_noise, "end of track condition\n"
- KERN_INFO "segment_id : %d\n"
- KERN_INFO "ft_segments_per_track: %d\n"
- KERN_INFO "start_offset : %d",
- segment_id, ft_segments_per_track,
- start_offset);
-
- /* If seeking to first segments on
- * track better do a complete rewind
- * to logical begin of track to get a
- * more steady tape motion.
- */
- result = ftape_command_wait(
- (ft_location.track & 1)
- ? QIC_PHYSICAL_FORWARD
- : QIC_PHYSICAL_REVERSE,
- ftape_timeout.rewind, &status);
- check_bot_eot(status); /* update location */
- } else {
- result= skip_reverse(segment_id - start_offset,
- &status);
- }
- }
- if (!ft_location.known) {
- TRACE(ft_t_bug, "panic: location not known");
- result = -EIO;
- continue; /* while() will check for failure */
- }
- TRACE(ft_t_noise, "current segment: %d/%d",
- ft_location.segment, ft_location.sector);
- /* We're on the right track somewhere before the
- * wanted segment. Start tape movement if needed and
- * skip to just before or inside the requested
- * segment. Keep tape running.
- */
- result = 0;
- if (ft_location.segment <
- (segment_id - ((ftape_tape_running || ft_location.bot)
- ? 0 : start_offset))) {
- if (sector_offset > 0) {
- result = seek_forward(segment_id,
- retry <= 3);
- } else {
- result = seek_forward(segment_id - 1,
- retry <= 3);
- }
- }
- if (result == 0 &&
- ft_location.segment !=
- (segment_id - (sector_offset > 0 ? 0 : 1))) {
- result = -EIO;
- }
- }
- if (result < 0) {
- TRACE(ft_t_err, "failed to reposition");
- } else {
- ft_runner_status = running;
- }
- TRACE_EXIT result;
-}
diff --git a/drivers/char/ftape/lowlevel/ftape-rw.h b/drivers/char/ftape/lowlevel/ftape-rw.h
deleted file mode 100644
index 32f4feeb887..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-rw.h
+++ /dev/null
@@ -1,111 +0,0 @@
-#ifndef _FTAPE_RW_H
-#define _FTAPE_RW_H
-
-/*
- * Copyright (C) 1993-1996 Bas Laarhoven,
- * (C) 1996-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-rw.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:18:25 $
- *
- * This file contains the definitions for the read and write
- * functions for the QIC-117 floppy-tape driver for Linux.
- *
- * Claus-Justus Heine (1996/09/20): Add definition of format code 6
- * Claus-Justus Heine (1996/10/04): Changed GET/PUT macros to cast to (__u8 *)
- *
- */
-
-#include "../lowlevel/fdc-io.h"
-#include "../lowlevel/ftape-init.h"
-#include "../lowlevel/ftape-bsm.h"
-
-#include <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 678340acd0b..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-setup.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 1996, 1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-setup.c,v $
- * $Revision: 1.7 $
- * $Date: 1997/10/10 09:57:06 $
- *
- * This file contains the code for processing the kernel command
- * line options for the QIC-40/80/3010/3020 floppy-tape driver
- * "ftape" for Linux.
- */
-
-#include <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 7fdc6567440..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-tracing.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 1993-1996 Bas Laarhoven,
- * (C) 1996-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-tracing.c,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:18:27 $
- *
- * This file contains the reading code
- * for the QIC-117 floppy-tape driver for Linux.
- */
-
-#include <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 2950810c708..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-tracing.h
+++ /dev/null
@@ -1,179 +0,0 @@
-#ifndef _FTAPE_TRACING_H
-#define _FTAPE_TRACING_H
-
-/*
- * Copyright (C) 1994-1996 Bas Laarhoven,
- * (C) 1996-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-tracing.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:18:28 $
- *
- * This file contains definitions that eases the debugging of the
- * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux.
- */
-
-#include <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(&current->pending.signal, sig_mask)) { \
- TRACE_ABORT(-EINTR, \
- ft_t_warn, \
- "interrupted by non-blockable signal"); \
- }
-
-#endif /* _FTAPE_TRACING_H */
diff --git a/drivers/char/ftape/lowlevel/ftape-write.c b/drivers/char/ftape/lowlevel/ftape-write.c
deleted file mode 100644
index 45601ec801e..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-write.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright (C) 1993-1995 Bas Laarhoven,
- * (C) 1996-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-write.c,v $
- * $Revision: 1.3.4.1 $
- * $Date: 1997/11/14 18:07:04 $
- *
- * This file contains the writing code
- * for the QIC-117 floppy-tape driver for Linux.
- */
-
-#include <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 0e7f898b7af..00000000000
--- a/drivers/char/ftape/lowlevel/ftape-write.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef _FTAPE_WRITE_H
-#define _FTAPE_WRITE_H
-
-/*
- * Copyright (C) 1994-1995 Bas Laarhoven,
- * (C) 1996-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-write.h,v $
- $Author: claus $
- *
- $Revision: 1.2 $
- $Date: 1997/10/05 19:18:30 $
- $State: Exp $
- *
- * This file contains the definitions for the write functions
- * for the QIC-117 floppy-tape driver for Linux.
- *
- */
-
-
-/* ftape-write.c defined global functions.
- */
-typedef enum {
- FT_WR_ASYNC = 0, /* start tape only when all buffers are full */
- FT_WR_MULTI = 1, /* start tape, but don't necessarily stop */
- FT_WR_SINGLE = 2, /* write a single segment and stop afterwards */
- FT_WR_DELETE = 3 /* write deleted data marks */
-} ft_write_mode_t;
-
-extern int ftape_start_writing(const ft_write_mode_t mode);
-extern int ftape_write_segment(const int segment,
- const void *address,
- const ft_write_mode_t flushing);
-extern void ftape_zap_write_buffers(void);
-extern int ftape_loop_until_writes_done(void);
-
-#endif /* _FTAPE_WRITE_H */
-
diff --git a/drivers/char/ftape/lowlevel/ftape_syms.c b/drivers/char/ftape/lowlevel/ftape_syms.c
deleted file mode 100644
index 8e0dc4a07ca..00000000000
--- a/drivers/char/ftape/lowlevel/ftape_syms.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 1996-1997 Claus-Justus Heine
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape_syms.c,v $
- * $Revision: 1.4 $
- * $Date: 1997/10/17 00:03:51 $
- *
- * This file contains the symbols that the ftape low level
- * part of the QIC-40/80/3010/3020 floppy-tape driver "ftape"
- * exports to its high level clients
- */
-
-#include <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 6d91c1f77c0..00000000000
--- a/drivers/char/ftape/zftape/Makefile
+++ /dev/null
@@ -1,36 +0,0 @@
-#
-# Copyright (C) 1996, 1997 Claus-Justus Heine.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; see the file COPYING. If not, write to
-# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-# $Source: /homes/cvs/ftape-stacked/ftape/zftape/Makefile,v $
-# $Revision: 1.4 $
-# $Date: 1997/10/05 19:18:58 $
-#
-# Makefile for the QIC-40/80/3010/3020 zftape interface VFS to
-# ftape
-#
-
-
-# ZFT_OBSOLETE - enable the MTIOC_ZFTAPE_GETBLKSZ ioctl. You should
-# leave this enabled for compatibility with taper.
-
-obj-$(CONFIG_ZFTAPE) += zftape.o
-
-zftape-objs := zftape-rw.o zftape-ctl.o zftape-read.o \
- zftape-write.o zftape-vtbl.o zftape-eof.o \
- zftape-init.o zftape-buffers.o zftape_syms.o
-
-EXTRA_CFLAGS := -DZFT_OBSOLETE
diff --git a/drivers/char/ftape/zftape/zftape-buffers.c b/drivers/char/ftape/zftape/zftape-buffers.c
deleted file mode 100644
index da06f138334..00000000000
--- a/drivers/char/ftape/zftape/zftape-buffers.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 1995-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-buffers.c,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:18:59 $
- *
- * This file contains the dynamic buffer allocation routines
- * of zftape
- */
-
-#include <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, %d 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, %d bytes",
- *(void **)old, size);
- *(void **)old = NULL;
- }
- TRACE_EXIT;
-}
-
-void *zft_kmalloc(size_t size)
-{
- void *new;
-
- while ((new = kmalloc(size, GFP_KERNEL)) == NULL) {
- msleep_interruptible(100);
- }
- memset(new, 0, size);
- used_memory += size;
- if (peak_memory < used_memory) {
- peak_memory = used_memory;
- }
- return new;
-}
-
-void zft_kfree(void *old, size_t size)
-{
- kfree(old);
- used_memory -= size;
-}
-
-/* there are some more buffers that are allocated on demand.
- * cleanup_module() calles this function to be sure to have released
- * them
- */
-void zft_uninit_mem(void)
-{
- TRACE_FUN(ft_t_flow);
-
- zft_vfree(&zft_hseg_buf, FT_SEGMENT_SIZE);
- zft_vfree(&zft_deblock_buf, FT_SEGMENT_SIZE); zft_deblock_segment = -1;
- zft_free_vtbl();
- if (zft_cmpr_lock(0 /* don't load */) == 0) {
- (*zft_cmpr_ops->cleanup)();
- (*zft_cmpr_ops->reset)(); /* unlock it again */
- }
- zft_memory_stats();
- TRACE_EXIT;
-}
diff --git a/drivers/char/ftape/zftape/zftape-buffers.h b/drivers/char/ftape/zftape/zftape-buffers.h
deleted file mode 100644
index 798e3128c68..00000000000
--- a/drivers/char/ftape/zftape/zftape-buffers.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef _FTAPE_DYNMEM_H
-#define _FTAPE_DYNMEM_H
-
-/*
- * Copyright (C) 1995-1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-buffers.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:18:59 $
- *
- * memory allocation routines.
- *
- */
-
-/* we do not allocate all of the really large buffer memory before
- * someone tries to open the drive. ftape_open() may fail with
- * -ENOMEM, but that's better having 200k of vmalloced memory which
- * cannot be swapped out.
- */
-
-extern void zft_memory_stats(void);
-extern int zft_vmalloc_once(void *new, size_t size);
-extern int zft_vcalloc_once(void *new, size_t size);
-extern int zft_vmalloc_always(void *new, size_t size);
-extern void zft_vfree(void *old, size_t size);
-extern void *zft_kmalloc(size_t size);
-extern void zft_kfree(void *old, size_t size);
-
-/* called by cleanup_module()
- */
-extern void zft_uninit_mem(void);
-
-#endif
-
-
-
-
-
-
-
diff --git a/drivers/char/ftape/zftape/zftape-ctl.c b/drivers/char/ftape/zftape/zftape-ctl.c
deleted file mode 100644
index 22ba0f5d00c..00000000000
--- a/drivers/char/ftape/zftape/zftape-ctl.c
+++ /dev/null
@@ -1,1417 +0,0 @@
-/*
- * Copyright (C) 1996, 1997 Claus-Justus Heine
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-ctl.c,v $
- * $Revision: 1.2.6.2 $
- * $Date: 1997/11/14 18:07:33 $
- *
- * This file contains the non-read/write zftape functions
- * for the QIC-40/80/3010/3020 floppy-tape driver for Linux.
- */
-
-#include <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 8e6f2d7ac74..00000000000
--- a/drivers/char/ftape/zftape/zftape-ctl.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef _ZFTAPE_CTL_H
-#define _ZFTAPE_CTL_H
-
-/*
- * Copyright (C) 1996, 1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-ctl.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:19:02 $
- *
- * This file contains the non-standard IOCTL related definitions
- * for the QIC-40/80 floppy-tape driver for Linux.
- */
-
-#include <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 dcadcaee9ac..00000000000
--- a/drivers/char/ftape/zftape/zftape-eof.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * I use these routines just to decide when I have to fake a
- * volume-table to preserve compatibility to original ftape.
- */
-/*
- * Copyright (C) 1994-1995 Bas Laarhoven.
- *
- * Modified for zftape 1996, 1997 Claus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-eof.c,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:19:02 $
- *
- * This file contains the eof mark handling code
- * for the QIC-40/80 floppy-tape driver for Linux.
- */
-
-#include <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 26568c26c51..00000000000
--- a/drivers/char/ftape/zftape/zftape-eof.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef _ZFTAPE_EOF_H
-#define _ZFTAPE_EOF_H
-
-/*
- * Copyright (C) 1994-1995 Bas Laarhoven.
- * adaptaed for zftape 1996, 1997 by Claus Heine
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-eof.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:19:03 $
- *
- * Definitions and declarations for the end of file markers
- * for the QIC-40/80 floppy-tape driver for Linux.
- */
-
-#include <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 164a1aa77a2..00000000000
--- a/drivers/char/ftape/zftape/zftape-init.c
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Copyright (C) 1996, 1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * This file contains the code that registers the zftape frontend
- * to the ftape floppy tape driver for Linux
- */
-
-#include <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(&current->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 (&current->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(&current->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(&current->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(&current->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(&current->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(&current->blocked);
- result = _zft_write(buff, req_len);
- current->blocked = old_sigmask; /* restore mask */
- TRACE(ft_t_data_flow, "return with count: %d", result);
- TRACE_EXIT result;
-}
-
-/* END OF VFS INTERFACE
- *
- *****************************************************************************/
-
-/* driver/module initialization
- */
-
-/* the compression module has to call this function to hook into the zftape
- * code
- */
-int zft_cmpr_register(struct zft_cmpr_ops *new_ops)
-{
- TRACE_FUN(ft_t_flow);
-
- if (zft_cmpr_ops != NULL) {
- TRACE_EXIT -EBUSY;
- } else {
- zft_cmpr_ops = new_ops;
- TRACE_EXIT 0;
- }
-}
-
-/* lock the zft-compressor() module.
- */
-int zft_cmpr_lock(int try_to_load)
-{
- if (zft_cmpr_ops == NULL) {
-#ifdef CONFIG_KMOD
- if (try_to_load) {
- request_module("zft-compressor");
- if (zft_cmpr_ops == NULL) {
- return -ENOSYS;
- }
- } else {
- return -ENOSYS;
- }
-#else
- return -ENOSYS;
-#endif
- }
- (*zft_cmpr_ops->lock)();
- return 0;
-}
-
-#ifdef CONFIG_ZFT_COMPRESSOR
-extern int zft_compressor_init(void);
-#endif
-
-/* Called by modules package when installing the driver or by kernel
- * during the initialization phase
- */
-int __init zft_init(void)
-{
- int i;
- TRACE_FUN(ft_t_flow);
-
-#ifdef MODULE
- printk(KERN_INFO ZFTAPE_VERSION "\n");
- if (TRACE_LEVEL >= ft_t_info) {
- printk(
-KERN_INFO
-"(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n"
-KERN_INFO
-"vfs interface for ftape floppy tape driver.\n"
-KERN_INFO
-"Support for QIC-113 compatible volume table, dynamic memory allocation\n"
-KERN_INFO
-"and builtin compression (lzrw3 algorithm).\n");
- }
-#else /* !MODULE */
- /* print a short no-nonsense boot message */
- printk(KERN_INFO ZFTAPE_VERSION "\n");
-#endif /* MODULE */
- TRACE(ft_t_info, "zft_init @ 0x%p", zft_init);
- TRACE(ft_t_info,
- "installing zftape VFS interface for ftape driver ...");
- TRACE_CATCH(register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),);
-
- zft_class = class_create(THIS_MODULE, "zft");
- for (i = 0; i < 4; i++) {
- class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i);
- class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i);
- class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i);
- class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i);
- class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i);
- class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i);
- }
-
-#ifdef CONFIG_ZFT_COMPRESSOR
- (void)zft_compressor_init();
-#endif
- zft_status = ftape_get_status(); /* fetch global data of ftape
- * hardware driver
- */
- TRACE_EXIT 0;
-}
-
-
-/* Called by modules package when removing the driver
- */
-static void zft_exit(void)
-{
- int i;
- TRACE_FUN(ft_t_flow);
-
- if (unregister_chrdev(QIC117_TAPE_MAJOR, "zft") != 0) {
- TRACE(ft_t_warn, "failed");
- } else {
- TRACE(ft_t_info, "successful");
- }
- for (i = 0; i < 4; i++) {
- class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i));
- class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4));
- class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16));
- class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20));
- class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32));
- class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36));
- }
- class_destroy(zft_class);
- zft_uninit_mem(); /* release remaining memory, if any */
- printk(KERN_INFO "zftape successfully unloaded.\n");
- TRACE_EXIT;
-}
-
-module_init(zft_init);
-module_exit(zft_exit);
diff --git a/drivers/char/ftape/zftape/zftape-init.h b/drivers/char/ftape/zftape/zftape-init.h
deleted file mode 100644
index 937e5d48c20..00000000000
--- a/drivers/char/ftape/zftape/zftape-init.h
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef _ZFTAPE_INIT_H
-#define _ZFTAPE_INIT_H
-
-/*
- * Copyright (C) 1996, 1997 Claus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-init.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:19:05 $
- *
- * This file contains definitions and macro for the vfs
- * interface defined by zftape
- *
- */
-
-#include <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 214bf03dce6..00000000000
--- a/drivers/char/ftape/zftape/zftape-read.c
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Copyright (C) 1996, 1997 Claus-Justus Heine
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-read.c,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:19:06 $
- *
- * This file contains the high level reading code
- * for the QIC-117 floppy-tape driver for Linux.
- */
-
-#include <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 42941de0c23..00000000000
--- a/drivers/char/ftape/zftape/zftape-read.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef _ZFTAPE_READ_H
-#define _ZFTAPE_READ_H
-
-/*
- * Copyright (C) 1996, 1997 Claus-Justus Heine
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-read.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:19:07 $
- *
- * This file contains the definitions for the read functions
- * for the zftape driver for Linux.
- *
- */
-
-#include "../lowlevel/ftape-read.h"
-
-/* ftape-read.c defined global vars.
- */
-extern int zft_just_before_eof;
-
-/* ftape-read.c defined global functions.
- */
-extern void zft_zap_read_buffers(void);
-extern int zft_read_header_segments(void);
-extern int zft_fetch_segment_fraction(const unsigned int segment,
- void *buffer,
- const ft_read_mode_t read_mode,
- const unsigned int start,
- const unsigned int size);
-#define zft_fetch_segment(segment, address, read_mode) \
- zft_fetch_segment_fraction(segment, address, read_mode, \
- 0, FT_SEGMENT_SIZE)
-/* hook for the VFS interface
- */
-extern int _zft_read(char __user *buff, int req_len);
-
-#endif /* _ZFTAPE_READ_H */
diff --git a/drivers/char/ftape/zftape/zftape-rw.c b/drivers/char/ftape/zftape/zftape-rw.c
deleted file mode 100644
index dab63468688..00000000000
--- a/drivers/char/ftape/zftape/zftape-rw.c
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * Copyright (C) 1996, 1997 Claus-Justus Heine
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-rw.c,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:19:08 $
- *
- * This file contains some common code for the r/w code for
- * zftape.
- */
-
-#include <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 1ceec22b60b..00000000000
--- a/drivers/char/ftape/zftape/zftape-rw.h
+++ /dev/null
@@ -1,101 +0,0 @@
-#ifndef _ZFTAPE_RW_H
-#define _ZFTAPE_RW_H
-
-/*
- * Copyright (C) 1996, 1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-rw.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:19:09 $
- *
- * This file contains the definitions for the read and write
- * functions for the QIC-117 floppy-tape driver for Linux.
- *
- */
-
-#include "../zftape/zftape-buffers.h"
-
-#define SEGMENTS_PER_TAPE (ft_segments_per_track * ft_tracks_per_tape)
-
-/* QIC-113 Rev. G says that `a maximum of 63488 raw bytes may be
- * compressed into a single frame'.
- * Maybe we should stick to 32kb to make it more `beautiful'
- */
-#define ZFT_MAX_BLK_SZ (62*1024) /* bytes */
-#if !defined(CONFIG_ZFT_DFLT_BLK_SZ)
-# define CONFIG_ZFT_DFLT_BLK_SZ (10*1024) /* bytes, default of gnu tar */
-#elif CONFIG_ZFT_DFLT_BLK_SZ == 0
-# undef CONFIG_ZFT_DFLT_BLK_SZ
-# define CONFIG_ZFT_DFLT_BLK_SZ 1
-#elif (CONFIG_ZFT_DFLT_BLK_SZ % 1024) != 0
-# error CONFIG_ZFT_DFLT_BLK_SZ must be 1 or a multiple of 1024
-#endif
-/* The *optional* compression routines need some overhead per tape
- * block for their purposes. Instead of asking the actual compression
- * implementation how much it needs, we restrict this overhead to be
- * maximal of ZFT_CMPT_OVERHEAD size. We need this for EOT
- * conditions. The tape is assumed to be logical at EOT when the
- * distance from the physical EOT is less than
- * one tape block + ZFT_CMPR_OVERHEAD
- */
-#define ZFT_CMPR_OVERHEAD 16 /* bytes */
-
-typedef enum
-{
- zft_idle = 0,
- zft_reading,
- zft_writing,
-} zft_status_enum;
-
-typedef struct /* all values measured in bytes */
-{
- int seg_pos; /* segment currently positioned at */
- int seg_byte_pos; /* offset in current segment */
- __s64 tape_pos; /* real offset from BOT */
- __s64 volume_pos; /* pos. in uncompressed data stream in
- * current volume
- */
-} zft_position;
-
-extern zft_position zft_pos;
-extern __u8 *zft_deblock_buf;
-extern __u8 *zft_hseg_buf;
-extern int zft_deblock_segment;
-extern zft_status_enum zft_io_state;
-extern int zft_header_changed;
-extern int zft_qic113; /* conform to old specs. and old zftape */
-extern int zft_use_compression;
-extern unsigned int zft_blk_sz;
-extern __s64 zft_capacity;
-extern unsigned int zft_written_segments;
-extern int zft_label_changed;
-
-/* zftape-rw.c exported functions
- */
-extern unsigned int zft_get_seg_sz(unsigned int segment);
-extern void zft_set_flags(unsigned int minor_unit);
-extern int zft_calc_seg_byte_coord(int *seg_byte_pos, __s64 tape_pos);
-extern __s64 zft_calc_tape_pos(int segment);
-extern __s64 zft_get_capacity(void);
-extern void zft_update_label(__u8 *buffer);
-extern int zft_erase(void);
-extern int zft_verify_write_segments(unsigned int segment,
- __u8 *data, size_t size, __u8 *buffer);
-extern unsigned int zft_get_time(void);
-#endif /* _ZFTAPE_RW_H */
-
diff --git a/drivers/char/ftape/zftape/zftape-vtbl.c b/drivers/char/ftape/zftape/zftape-vtbl.c
deleted file mode 100644
index ad7f8be6340..00000000000
--- a/drivers/char/ftape/zftape/zftape-vtbl.c
+++ /dev/null
@@ -1,757 +0,0 @@
-/*
- * Copyright (c) 1995-1997 Claus-Justus Heine
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
- USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-vtbl.c,v $
- * $Revision: 1.7.6.1 $
- * $Date: 1997/11/24 13:48:31 $
- *
- * This file defines a volume table as defined in various QIC
- * standards.
- *
- * This is a minimal implementation, just allowing ordinary DOS
- * :( prgrams to identify the cartridge as used.
- */
-
-#include <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 f31d196d175..00000000000
--- a/drivers/char/ftape/zftape/zftape-vtbl.h
+++ /dev/null
@@ -1,227 +0,0 @@
-#ifndef _ZFTAPE_VTBL_H
-#define _ZFTAPE_VTBL_H
-
-/*
- * Copyright (c) 1995-1997 Claus-Justus Heine
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
- USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-vtbl.h,v $
- * $Revision: 1.3 $
- * $Date: 1997/10/28 14:30:09 $
- *
- * This file defines a volume table as defined in the QIC-80
- * development standards.
- */
-
-#include <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 94327b8c97b..00000000000
--- a/drivers/char/ftape/zftape/zftape-write.c
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * Copyright (C) 1996, 1997 Claus Heine
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-write.c,v $
- * $Revision: 1.3 $
- * $Date: 1997/11/06 00:50:29 $
- *
- * This file contains the writing code
- * for the QIC-117 floppy-tape driver for Linux.
- */
-
-#include <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 ea887015b49..00000000000
--- a/drivers/char/ftape/zftape/zftape-write.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef _ZFTAPE_WRITE_H
-#define _ZFTAPE_WRITE_H
-
-/*
- * Copyright (C) 1996, 1997 Claus-Justus Heine
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-write.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:19:13 $
- *
- * This file contains the definitions for the write functions
- * for the zftape driver for Linux.
- *
- */
-
-extern int zft_flush_buffers(void);
-extern int zft_update_header_segments(void);
-extern void zft_prevent_flush(void);
-
-/* hook for the VFS interface
- */
-extern int _zft_write(const char __user *buff, int req_len);
-#endif /* _ZFTAPE_WRITE_H */
diff --git a/drivers/char/ftape/zftape/zftape_syms.c b/drivers/char/ftape/zftape/zftape_syms.c
deleted file mode 100644
index 2db1401682d..00000000000
--- a/drivers/char/ftape/zftape/zftape_syms.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 1997 Claus-Justus Heine
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape_syms.c,v $
- * $Revision: 1.3 $
- * $Date: 1997/10/05 19:19:14 $
- *
- * This file contains the symbols that the zftape frontend to
- * the ftape floppy tape driver exports
- */
-
-#include <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 817dc409ac2..23b25ada65e 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 091a11cd878..20dc3be5ecf 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 9902ffad3b1..cc2cd46bedc 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 8728255c946..d090622f1de 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 2cf63e7305a..82a41d5b4ed 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 9f7635f7517..5f3acd8e64b 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 e263ae96f94..c41fa19454e 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 154a81d328c..26a860adcb3 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 baa4e721b75..29277ec6b8e 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 54d93f0345e..78045767ec3 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 a3f32d46d2f..cda2459c1d6 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 0030cd8e2e9..6c59baa887a 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 81fcf0ce21d..375d3378eec 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 2062675f9e9..c1b8228cb7b 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 34a4fd13fa8..5703ee28e1c 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)
@@ -376,13 +387,23 @@ static void free_recv_msg_list(struct list_head *q)
}
}
+static void free_smi_msg_list(struct list_head *q)
+{
+ struct ipmi_smi_msg *msg, *msg2;
+
+ list_for_each_entry_safe(msg, msg2, q, link) {
+ list_del(&msg->link);
+ ipmi_free_smi_msg(msg);
+ }
+}
+
static void clean_up_interface_data(ipmi_smi_t intf)
{
int i;
struct cmd_rcvr *rcvr, *rcvr2;
struct list_head list;
- free_recv_msg_list(&intf->waiting_msgs);
+ free_smi_msg_list(&intf->waiting_msgs);
free_recv_msg_list(&intf->waiting_events);
/* Wholesale remove all the entries from the list in the
@@ -413,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;
- 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))
+ mutex_lock(&smi_watchers_mutex);
+
+ mutex_lock(&ipmi_interfaces_mutex);
+
+ /* 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);
+ }
+
+ /* 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);
}
- spin_unlock_irqrestore(&interfaces_lock, flags);
+
+ 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
@@ -580,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. */
@@ -717,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;
}
@@ -766,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;
@@ -797,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);
@@ -807,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;
}
@@ -836,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);
@@ -862,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);
@@ -877,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,
@@ -921,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;
@@ -933,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;
@@ -1057,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
@@ -1168,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) {
@@ -1194,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);
@@ -1236,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++;
@@ -1510,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;
@@ -1594,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)
{
@@ -1682,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,
@@ -1807,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,
@@ -1844,7 +2020,7 @@ static ssize_t provides_dev_sdrs_show(struct device *dev,
struct bmc_device *bmc = dev_get_drvdata(dev);
return snprintf(buf, 10, "%u\n",
- bmc->id.device_revision && 0x80 >> 7);
+ (bmc->id.device_revision & 0x80) >> 7);
}
static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
@@ -1853,7 +2029,7 @@ static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
struct bmc_device *bmc = dev_get_drvdata(dev);
return snprintf(buf, 20, "%u\n",
- bmc->id.device_revision && 0x0F);
+ bmc->id.device_revision & 0x0F);
}
static ssize_t firmware_rev_show(struct device *dev,
@@ -1930,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,
@@ -1963,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);
}
@@ -1971,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);
@@ -1980,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);
}
@@ -1987,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;
@@ -2056,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;
@@ -2096,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");
@@ -2108,9 +2374,11 @@ static int ipmi_bmc_register(ipmi_smi_t intf)
dev_set_drvdata(&bmc->dev->dev, bmc);
kref_init(&bmc->refcount);
- rv = platform_device_register(bmc->dev);
+ 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",
@@ -2120,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);
@@ -2192,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
@@ -2399,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. */
@@ -2427,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;
@@ -2460,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)
@@ -2487,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. */
@@ -2511,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;
@@ -2650,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. */
@@ -2706,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);
@@ -3232,7 +3480,9 @@ void ipmi_smi_msg_received(ipmi_smi_t intf,
report the error immediately. */
if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
&& (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
- && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR))
+ && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)
+ && (msg->rsp[2] != IPMI_BUS_ERR)
+ && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR))
{
int chan = msg->rsp[3] & 0xf;
@@ -3297,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,
@@ -3338,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;
@@ -3381,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);
}
}
@@ -3399,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,
@@ -3430,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;
@@ -3587,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;
@@ -3621,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. */
@@ -3648,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
@@ -3780,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)
@@ -3788,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);
@@ -3811,7 +4079,6 @@ static struct notifier_block panic_block = {
static int ipmi_init_msghandler(void)
{
- int i;
int rv;
if (initialized)
@@ -3826,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 8d941db8345..597eb4f88b8 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 157fa81a264..81a0c89598e 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)
@@ -1211,7 +1260,7 @@ static void intf_mem_outb(struct si_sm_io *io, unsigned int offset,
static unsigned char intf_mem_inw(struct si_sm_io *io, unsigned int offset)
{
return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift)
- && 0xff;
+ & 0xff;
}
static void intf_mem_outw(struct si_sm_io *io, unsigned int offset,
@@ -1223,7 +1272,7 @@ static void intf_mem_outw(struct si_sm_io *io, unsigned int offset,
static unsigned char intf_mem_inl(struct si_sm_io *io, unsigned int offset)
{
return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift)
- && 0xff;
+ & 0xff;
}
static void intf_mem_outl(struct si_sm_io *io, unsigned int offset,
@@ -1236,7 +1285,7 @@ static void intf_mem_outl(struct si_sm_io *io, unsigned int offset,
static unsigned char mem_inq(struct si_sm_io *io, unsigned int offset)
{
return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift)
- && 0xff;
+ & 0xff;
}
static void mem_outq(struct si_sm_io *io, unsigned int offset,
@@ -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);
}
/*
@@ -2346,7 +2630,7 @@ static int try_smi_init(struct smi_info *new_smi)
new_smi->dev = &new_smi->pdev->dev;
new_smi->dev->driver = &ipmi_driver;
- rv = platform_device_register(new_smi->pdev);
+ rv = platform_device_add(new_smi->pdev);
if (rv) {
printk(KERN_ERR
"ipmi_si_intf:"
@@ -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 39d7e5ef1a2..e64ea7d25d2 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 73f759eaa5a..90fb2a54191 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(&register_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(&register_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(&register_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(&register_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 e9e9bf31c36..1637c1d9a4b 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)
@@ -1062,11 +1062,12 @@ static void isicom_shutdown_port(struct isi_port *port)
static void isicom_close(struct tty_struct *tty, struct file *filp)
{
struct isi_port *port = tty->driver_data;
- struct isi_board *card = port->card;
+ struct isi_board *card;
unsigned long flags;
if (!port)
return;
+ card = port->card;
if (isicom_paranoia_check(port, tty->name, "isicom_close"))
return;
@@ -1473,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;
@@ -1965,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 ffdf9df1a67..8f591945ebd 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 55473371b7c..e67eef4867b 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -980,10 +980,10 @@ static int __init chr_dev_init(void)
mem_class = class_create(THIS_MODULE, "mem");
for (i = 0; i < ARRAY_SIZE(devlist); i++)
- class_device_create(mem_class, NULL,
- MKDEV(MEM_MAJOR, devlist[i].minor),
- NULL, devlist[i].name);
-
+ device_create(mem_class, NULL,
+ MKDEV(MEM_MAJOR, devlist[i].minor),
+ devlist[i].name);
+
return 0;
}
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 62ebe09656e..7e975f60692 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 22b9905c1e5..c09160383a5 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 96cb1f07332..8b316953173 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/mspec.c b/drivers/char/mspec.c
index 5c0dec39cf6..235e8922611 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -72,7 +72,11 @@ enum {
MSPEC_UNCACHED
};
+#ifdef CONFIG_SGI_SN
static int is_sn2;
+#else
+#define is_sn2 0
+#endif
/*
* One of these structures is allocated when an mspec region is mmaped. The
@@ -211,7 +215,7 @@ mspec_nopfn(struct vm_area_struct *vma, unsigned long address)
if (vdata->type == MSPEC_FETCHOP)
paddr = TO_AMO(maddr);
else
- paddr = __pa(TO_CAC(maddr));
+ paddr = maddr & ~__IA64_UNCACHED_OFFSET;
pfn = paddr >> PAGE_SHIFT;
@@ -335,6 +339,7 @@ mspec_init(void)
* The fetchop device only works on SN2 hardware, uncached and cached
* memory drivers should both be valid on all ia64 hardware
*/
+#ifdef CONFIG_SGI_SN
if (ia64_platform_is("sn2")) {
is_sn2 = 1;
if (is_shub2()) {
@@ -363,6 +368,7 @@ mspec_init(void)
goto free_scratch_pages;
}
}
+#endif
ret = misc_register(&cached_miscdev);
if (ret) {
printk(KERN_ERR "%s: failed to register device %i\n",
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 048d91142c1..5ed2486b758 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 50d20aafeb1..211c93fda6f 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 55cf4be4297..9b1ff7e8f89 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 1a0bc30b79d..74d21c1c104 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 efc485edad1..c1e3dd837fc 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -752,13 +752,13 @@ static const struct file_operations pp_fops = {
static void pp_attach(struct parport *port)
{
- class_device_create(ppdev_class, NULL, MKDEV(PP_MAJOR, port->number),
- NULL, "parport%d", port->number);
+ device_create(ppdev_class, NULL, MKDEV(PP_MAJOR, port->number),
+ "parport%d", port->number);
}
static void pp_detach(struct parport *port)
{
- class_device_destroy(ppdev_class, MKDEV(PP_MAJOR, port->number));
+ device_destroy(ppdev_class, MKDEV(PP_MAJOR, port->number));
}
static struct parport_driver pp_driver = {
diff --git a/drivers/char/random.c b/drivers/char/random.c
index eb6b13f4211..4c6782a1ecd 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 89b718e326e..3b32313f6eb 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -127,9 +127,9 @@ raw_ioctl(struct inode *inode, struct file *filp,
static void bind_device(struct raw_config_request *rq)
{
- class_device_destroy(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor));
- class_device_create(raw_class, NULL, MKDEV(RAW_MAJOR, rq->raw_minor),
- NULL, "raw%d", rq->raw_minor);
+ device_destroy(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor));
+ device_create(raw_class, NULL, MKDEV(RAW_MAJOR, rq->raw_minor),
+ "raw%d", rq->raw_minor);
}
/*
@@ -200,7 +200,7 @@ static int raw_ctl_ioctl(struct inode *inode, struct file *filp,
if (rq.block_major == 0 && rq.block_minor == 0) {
/* unbind */
rawdev->binding = NULL;
- class_device_destroy(raw_class,
+ device_destroy(raw_class,
MKDEV(RAW_MAJOR, rq.raw_minor));
} else {
rawdev->binding = bdget(dev);
@@ -283,7 +283,7 @@ static int __init raw_init(void)
ret = PTR_ERR(raw_class);
goto error_region;
}
- class_device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl");
+ device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), "rawctl");
return 0;
@@ -295,7 +295,7 @@ error:
static void __exit raw_exit(void)
{
- class_device_destroy(raw_class, MKDEV(RAW_MAJOR, 0));
+ device_destroy(raw_class, MKDEV(RAW_MAJOR, 0));
class_destroy(raw_class);
cdev_del(&raw_cdev);
unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), MAX_RAW_MINORS);
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index 7ac68cb3bed..e79b2ede851 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 4df6ab2206a..167ebc84e8d 100644
--- a/drivers/char/rio/riocmd.c
+++ b/drivers/char/rio/riocmd.c
@@ -922,7 +922,7 @@ int RIOUnUse(unsigned long iPortP, struct CmdBlk *CmdBlkP)
**
** Packet is an actual packet structure to be filled in with the packet
** information associated with the command. You need to fill in everything,
-** as the command processore doesn't process the command packet in any way.
+** as the command processor doesn't process the command packet in any way.
**
** The PreFuncP is called before the packet is enqueued on the host rup.
** PreFuncP is called as (*PreFuncP)(PreArg, CmdBlkP);. PreFuncP must
diff --git a/drivers/char/rio/rioinit.c b/drivers/char/rio/rioinit.c
index 99f3df02b61..0794844369d 100644
--- a/drivers/char/rio/rioinit.c
+++ b/drivers/char/rio/rioinit.c
@@ -222,7 +222,7 @@ int RIOBoardTest(unsigned long paddr, void __iomem *caddr, unsigned char type, i
** which value will be written into memory.
** Call with op set to zero means that the RAM will not be read and checked
** before it is written.
-** Call with op not zero, and the RAM will be read and compated with val[op-1]
+** Call with op not zero and the RAM will be read and compared with val[op-1]
** to check that the data from the previous phase was retained.
*/
diff --git a/drivers/char/rio/rioparam.c b/drivers/char/rio/rioparam.c
index 1066d976070..bb498d24adc 100644
--- a/drivers/char/rio/rioparam.c
+++ b/drivers/char/rio/rioparam.c
@@ -87,8 +87,8 @@ static char *_rioparam_c_sccs_ = "@(#)rioparam.c 1.3";
** command bit set onto the port. The command bit is in the len field,
** and gets ORed in with the actual byte count.
**
-** When you send a packet with the command bit set, then the first
-** data byte ( data[0] ) is interpretted as the command to execute.
+** When you send a packet with the command bit set the first
+** data byte (data[0]) is interpreted as the command to execute.
** It also governs what data structure overlay should accompany the packet.
** Commands are defined in cirrus/cirrus.h
**
@@ -103,7 +103,7 @@ static char *_rioparam_c_sccs_ = "@(#)rioparam.c 1.3";
**
** Most commands do not use the remaining bytes in the data array. The
** exceptions are OPEN MOPEN and CONFIG. (NB. As with the SI CONFIG and
-** OPEN are currently analagous). With these three commands the following
+** OPEN are currently analogous). With these three commands the following
** 11 data bytes are all used to pass config information such as baud rate etc.
** The fields are also defined in cirrus.h. Some contain straightforward
** information such as the transmit XON character. Two contain the transmit and
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 5ab32b38f45..0a77bfcd5b5 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 3af7f0958c5..9ba13af234b 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 c084149153d..fc87070f186 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 7e1bd9562c2..99137ab66b6 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 522e88e395c..5e2de62bce7 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 06784adcc35..645187b9141 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 d4334c79f8d..e4730a7312b 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 3e932b68137..20a96ef250b 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 5f49280779f..05810c8d20b 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/tlclk.c b/drivers/char/tlclk.c
index 2444a0e24b3..244d30a03fe 100644
--- a/drivers/char/tlclk.c
+++ b/drivers/char/tlclk.c
@@ -792,15 +792,14 @@ static int __init tlclk_init(void)
ret = misc_register(&tlclk_miscdev);
if (ret < 0) {
printk(KERN_ERR "tlclk: misc_register returns %d.\n", ret);
- ret = -EBUSY;
goto out3;
}
tlclk_device = platform_device_register_simple("telco_clock",
-1, NULL, 0);
- if (!tlclk_device) {
+ if (IS_ERR(tlclk_device)) {
printk(KERN_ERR "tlclk: platform_device_register failed.\n");
- ret = -EBUSY;
+ ret = PTR_ERR(tlclk_device);
goto out4;
}
diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c
index dd36fd04a84..07067c31c4e 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 6ad2d3bb945..33e1f66e39c 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 050ced247f6..bb9a43c6cf3 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 e90ea39c7c4..b3cfc8bc613 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 bd7a98c6ea7..f442b574b44 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -476,16 +476,16 @@ static struct class *vc_class;
void vcs_make_sysfs(struct tty_struct *tty)
{
- class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1),
- NULL, "vcs%u", tty->index + 1);
- class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129),
- NULL, "vcsa%u", tty->index + 1);
+ device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1),
+ "vcs%u", tty->index + 1);
+ device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129),
+ "vcsa%u", tty->index + 1);
}
void vcs_remove_sysfs(struct tty_struct *tty)
{
- class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1));
- class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129));
+ device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1));
+ device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129));
}
int __init vcs_init(void)
@@ -494,7 +494,7 @@ int __init vcs_init(void)
panic("unable to get major %d for vcs device", VCS_MAJOR);
vc_class = class_create(THIS_MODULE, "vc");
- class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs");
- class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa");
+ device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), "vcs");
+ device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), "vcsa");
return 0;
}
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 8e4413f6fba..a8239dac994 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 = &registered_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 0187b118532..ea09d0c974e 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 36440497047..2cd8ff8d10a 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/at91rm9200_wdt.c b/drivers/char/watchdog/at91rm9200_wdt.c
index 4e7a1145e78..cb86967e2c5 100644
--- a/drivers/char/watchdog/at91rm9200_wdt.c
+++ b/drivers/char/watchdog/at91rm9200_wdt.c
@@ -21,6 +21,7 @@
#include <linux/watchdog.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
+#include <asm/arch/at91_st.h>
#define WDT_DEFAULT_TIME 5 /* seconds */
diff --git a/drivers/char/watchdog/iTCO_vendor_support.c b/drivers/char/watchdog/iTCO_vendor_support.c
new file mode 100644
index 00000000000..41508399009
--- /dev/null
+++ b/drivers/char/watchdog/iTCO_vendor_support.c
@@ -0,0 +1,307 @@
+/*
+ * intel TCO vendor specific watchdog driver support
+ *
+ * (c) Copyright 2006 Wim Van Sebroeck <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 b6f29cb8bd3..7eac922df86 100644
--- a/drivers/char/watchdog/iTCO_wdt.c
+++ b/drivers/char/watchdog/iTCO_wdt.c
@@ -48,8 +48,8 @@
/* Module and version information */
#define DRV_NAME "iTCO_wdt"
-#define DRV_VERSION "1.00"
-#define DRV_RELDATE "08-Oct-2006"
+#define DRV_VERSION "1.01"
+#define DRV_RELDATE "11-Nov-2006"
#define PFX DRV_NAME ": "
/* Includes */
@@ -189,6 +189,21 @@ static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+/* iTCO Vendor Specific Support hooks */
+#ifdef CONFIG_ITCO_VENDOR_SUPPORT
+extern void iTCO_vendor_pre_start(unsigned long, unsigned int);
+extern void iTCO_vendor_pre_stop(unsigned long);
+extern void iTCO_vendor_pre_keepalive(unsigned long, unsigned int);
+extern void iTCO_vendor_pre_set_heartbeat(unsigned int);
+extern int iTCO_vendor_check_noreboot_on(void);
+#else
+#define iTCO_vendor_pre_start(acpibase, heartbeat) {}
+#define iTCO_vendor_pre_stop(acpibase) {}
+#define iTCO_vendor_pre_keepalive(acpibase,heartbeat) {}
+#define iTCO_vendor_pre_set_heartbeat(heartbeat) {}
+#define iTCO_vendor_check_noreboot_on() 1 /* 1=check noreboot; 0=don't check */
+#endif
+
/*
* Some TCO specific functions
*/
@@ -249,6 +264,8 @@ static int iTCO_wdt_start(void)
spin_lock(&iTCO_wdt_private.io_lock);
+ iTCO_vendor_pre_start(iTCO_wdt_private.ACPIBASE, heartbeat);
+
/* disable chipset's NO_REBOOT bit */
if (iTCO_wdt_unset_NO_REBOOT_bit()) {
printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
@@ -273,6 +290,8 @@ static int iTCO_wdt_stop(void)
spin_lock(&iTCO_wdt_private.io_lock);
+ iTCO_vendor_pre_stop(iTCO_wdt_private.ACPIBASE);
+
/* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
val = inw(TCO1_CNT);
val |= 0x0800;
@@ -293,6 +312,8 @@ static int iTCO_wdt_keepalive(void)
{
spin_lock(&iTCO_wdt_private.io_lock);
+ iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat);
+
/* Reload the timer by writing to the TCO Timer Counter register */
if (iTCO_wdt_private.iTCO_version == 2) {
outw(0x01, TCO_RLD);
@@ -319,6 +340,8 @@ static int iTCO_wdt_set_heartbeat(int t)
((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f)))
return -EINVAL;
+ iTCO_vendor_pre_set_heartbeat(tmrval);
+
/* Write new heartbeat to watchdog */
if (iTCO_wdt_private.iTCO_version == 2) {
spin_lock(&iTCO_wdt_private.io_lock);
@@ -569,7 +592,7 @@ static int iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device_id *ent,
}
/* Check chipset's NO_REBOOT bit */
- if (iTCO_wdt_unset_NO_REBOOT_bit()) {
+ if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {
printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
ret = -ENODEV; /* Cannot reset NO_REBOOT bit */
goto out;
diff --git a/drivers/char/watchdog/pc87413_wdt.c b/drivers/char/watchdog/pc87413_wdt.c
new file mode 100644
index 00000000000..1d447e32af4
--- /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 bda45334d80..61138726b50 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 00000000000..ec3909371c2
--- /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);
+