diff options
author | Dmitry Torokhov <dtor@insightbb.com> | 2006-12-08 01:07:56 -0500 |
---|---|---|
committer | Dmitry Torokhov <dtor@insightbb.com> | 2006-12-08 01:07:56 -0500 |
commit | bef986502fa398b1785a3979b1aa17cd902d3527 (patch) | |
tree | b59c1afe7b1dfcc001b86e54863f550d7ddc8c34 /drivers/char | |
parent | 4bdbd2807deeccc0793d57fb5120d7a53f2c0b3c (diff) | |
parent | c99767974ebd2a719d849fdeaaa1674456f5283f (diff) |
Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts:
drivers/usb/input/hid.h
Diffstat (limited to 'drivers/char')
135 files changed, 3544 insertions, 20681 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 39a9f8cc6412..24f922f12783 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig | |||
@@ -409,14 +409,6 @@ config SGI_MBCS | |||
409 | If you have an SGI Altix with an attached SABrick | 409 | If you have an SGI Altix with an attached SABrick |
410 | say Y or M here, otherwise say N. | 410 | say Y or M here, otherwise say N. |
411 | 411 | ||
412 | config MSPEC | ||
413 | tristate "Memory special operations driver" | ||
414 | depends on IA64 | ||
415 | help | ||
416 | If you have an ia64 and you want to enable memory special | ||
417 | operations support (formerly known as fetchop), say Y here, | ||
418 | otherwise say N. | ||
419 | |||
420 | source "drivers/serial/Kconfig" | 412 | source "drivers/serial/Kconfig" |
421 | 413 | ||
422 | config UNIX98_PTYS | 414 | config UNIX98_PTYS |
@@ -863,39 +855,6 @@ config TANBAC_TB0219 | |||
863 | depends TANBAC_TB022X | 855 | depends TANBAC_TB022X |
864 | select GPIO_VR41XX | 856 | select GPIO_VR41XX |
865 | 857 | ||
866 | menu "Ftape, the floppy tape device driver" | ||
867 | |||
868 | config FTAPE | ||
869 | tristate "Ftape (QIC-80/Travan) support" | ||
870 | depends on BROKEN_ON_SMP && (ALPHA || X86) | ||
871 | ---help--- | ||
872 | If you have a tape drive that is connected to your floppy | ||
873 | controller, say Y here. | ||
874 | |||
875 | Some tape drives (like the Seagate "Tape Store 3200" or the Iomega | ||
876 | "Ditto 3200" or the Exabyte "Eagle TR-3") come with a "high speed" | ||
877 | controller of their own. These drives (and their companion | ||
878 | controllers) are also supported if you say Y here. | ||
879 | |||
880 | If you have a special controller (such as the CMS FC-10, FC-20, | ||
881 | Mountain Mach-II, or any controller that is based on the Intel 82078 | ||
882 | FDC like the high speed controllers by Seagate and Exabyte and | ||
883 | Iomega's "Ditto Dash") you must configure it by selecting the | ||
884 | appropriate entries from the "Floppy tape controllers" sub-menu | ||
885 | below and possibly modify the default values for the IRQ and DMA | ||
886 | channel and the IO base in ftape's configuration menu. | ||
887 | |||
888 | If you want to use your floppy tape drive on a PCI-bus based system, | ||
889 | please read the file <file:drivers/char/ftape/README.PCI>. | ||
890 | |||
891 | The ftape kernel driver is also available as a runtime loadable | ||
892 | module. To compile this driver as a module, choose M here: the | ||
893 | module will be called ftape. | ||
894 | |||
895 | source "drivers/char/ftape/Kconfig" | ||
896 | |||
897 | endmenu | ||
898 | |||
899 | source "drivers/char/agp/Kconfig" | 858 | source "drivers/char/agp/Kconfig" |
900 | 859 | ||
901 | source "drivers/char/drm/Kconfig" | 860 | source "drivers/char/drm/Kconfig" |
@@ -1002,7 +961,7 @@ config HPET | |||
1002 | help | 961 | help |
1003 | If you say Y here, you will have a miscdevice named "/dev/hpet/". Each | 962 | If you say Y here, you will have a miscdevice named "/dev/hpet/". Each |
1004 | open selects one of the timers supported by the HPET. The timers are | 963 | open selects one of the timers supported by the HPET. The timers are |
1005 | non-periodioc and/or periodic. | 964 | non-periodic and/or periodic. |
1006 | 965 | ||
1007 | config HPET_RTC_IRQ | 966 | config HPET_RTC_IRQ |
1008 | bool "HPET Control RTC IRQ" if !HPET_EMULATE_RTC | 967 | bool "HPET Control RTC IRQ" if !HPET_EMULATE_RTC |
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 777cad045094..b1fcdab90947 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile | |||
@@ -78,7 +78,6 @@ obj-$(CONFIG_TOSHIBA) += toshiba.o | |||
78 | obj-$(CONFIG_I8K) += i8k.o | 78 | obj-$(CONFIG_I8K) += i8k.o |
79 | obj-$(CONFIG_DS1620) += ds1620.o | 79 | obj-$(CONFIG_DS1620) += ds1620.o |
80 | obj-$(CONFIG_HW_RANDOM) += hw_random/ | 80 | obj-$(CONFIG_HW_RANDOM) += hw_random/ |
81 | obj-$(CONFIG_FTAPE) += ftape/ | ||
82 | obj-$(CONFIG_COBALT_LCD) += lcd.o | 81 | obj-$(CONFIG_COBALT_LCD) += lcd.o |
83 | obj-$(CONFIG_PPDEV) += ppdev.o | 82 | obj-$(CONFIG_PPDEV) += ppdev.o |
84 | obj-$(CONFIG_NWBUTTON) += nwbutton.o | 83 | obj-$(CONFIG_NWBUTTON) += nwbutton.o |
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 00b17ae39736..2f2c4efff8a3 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c | |||
@@ -459,7 +459,7 @@ static const struct aper_size_info_32 nforce3_sizes[5] = | |||
459 | 459 | ||
460 | /* Handle shadow device of the Nvidia NForce3 */ | 460 | /* Handle shadow device of the Nvidia NForce3 */ |
461 | /* CHECK-ME original 2.4 version set up some IORRs. Check if that is needed. */ | 461 | /* CHECK-ME original 2.4 version set up some IORRs. Check if that is needed. */ |
462 | static int __devinit nforce3_agp_init(struct pci_dev *pdev) | 462 | static int nforce3_agp_init(struct pci_dev *pdev) |
463 | { | 463 | { |
464 | u32 tmp, apbase, apbar, aplimit; | 464 | u32 tmp, apbase, apbar, aplimit; |
465 | struct pci_dev *dev1; | 465 | struct pci_dev *dev1; |
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index c39200161688..5ff457b41efb 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) | |||
1054 | { | 1054 | { |
1055 | struct page * page; | 1055 | struct page * page; |
1056 | 1056 | ||
1057 | page = alloc_page(GFP_KERNEL); | 1057 | page = alloc_page(GFP_KERNEL | GFP_DMA32); |
1058 | if (page == NULL) | 1058 | if (page == NULL) |
1059 | return NULL; | 1059 | return NULL; |
1060 | 1060 | ||
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index d1ede7db5a12..555b3a8ab49c 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) | |||
169 | { | 169 | { |
170 | struct page * page; | 170 | struct page * page; |
171 | 171 | ||
172 | page = alloc_pages(GFP_KERNEL, 2); | 172 | page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2); |
173 | if (page == NULL) | 173 | if (page == NULL) |
174 | return NULL; | 174 | return NULL; |
175 | 175 | ||
@@ -387,11 +387,7 @@ static void intel_i830_init_gtt_entries(void) | |||
387 | /* We obtain the size of the GTT, which is also stored (for some | 387 | /* We obtain the size of the GTT, which is also stored (for some |
388 | * reason) at the top of stolen memory. Then we add 4KB to that | 388 | * reason) at the top of stolen memory. Then we add 4KB to that |
389 | * for the video BIOS popup, which is also stored in there. */ | 389 | * for the video BIOS popup, which is also stored in there. */ |
390 | 390 | size = agp_bridge->driver->fetch_size() + 4; | |
391 | if (IS_I965) | ||
392 | size = 512 + 4; | ||
393 | else | ||
394 | size = agp_bridge->driver->fetch_size() + 4; | ||
395 | 391 | ||
396 | if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB || | 392 | if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB || |
397 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { | 393 | 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) | |||
805 | 801 | ||
806 | return 0; | 802 | return 0; |
807 | } | 803 | } |
804 | |||
805 | /* | ||
806 | * The i965 supports 36-bit physical addresses, but to keep | ||
807 | * the format of the GTT the same, the bits that don't fit | ||
808 | * in a 32-bit word are shifted down to bits 4..7. | ||
809 | * | ||
810 | * Gcc is smart enough to notice that "(addr >> 28) & 0xf0" | ||
811 | * is always zero on 32-bit architectures, so no need to make | ||
812 | * this conditional. | ||
813 | */ | ||
814 | static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge, | ||
815 | unsigned long addr, int type) | ||
816 | { | ||
817 | /* Shift high bits down */ | ||
818 | addr |= (addr >> 28) & 0xf0; | ||
819 | |||
820 | /* Type checking must be done elsewhere */ | ||
821 | return addr | bridge->driver->masks[type].mask; | ||
822 | } | ||
823 | |||
808 | static int intel_i965_fetch_size(void) | 824 | static int intel_i965_fetch_size(void) |
809 | { | 825 | { |
810 | struct aper_size_info_fixed *values; | 826 | struct aper_size_info_fixed *values; |
@@ -832,7 +848,8 @@ static int intel_i965_fetch_size(void) | |||
832 | 848 | ||
833 | agp_bridge->previous_size = agp_bridge->current_size = (void *)(values + offset); | 849 | agp_bridge->previous_size = agp_bridge->current_size = (void *)(values + offset); |
834 | 850 | ||
835 | return values[offset].size; | 851 | /* The i965 GTT is always sized as if it had a 512kB aperture size */ |
852 | return 512; | ||
836 | } | 853 | } |
837 | 854 | ||
838 | /* The intel i965 automatically initializes the agp aperture during POST. | 855 | /* The intel i965 automatically initializes the agp aperture during POST. |
@@ -1584,7 +1601,7 @@ static struct agp_bridge_driver intel_i965_driver = { | |||
1584 | .fetch_size = intel_i965_fetch_size, | 1601 | .fetch_size = intel_i965_fetch_size, |
1585 | .cleanup = intel_i915_cleanup, | 1602 | .cleanup = intel_i915_cleanup, |
1586 | .tlb_flush = intel_i810_tlbflush, | 1603 | .tlb_flush = intel_i810_tlbflush, |
1587 | .mask_memory = intel_i810_mask_memory, | 1604 | .mask_memory = intel_i965_mask_memory, |
1588 | .masks = intel_i810_masks, | 1605 | .masks = intel_i810_masks, |
1589 | .agp_enable = intel_i810_agp_enable, | 1606 | .agp_enable = intel_i810_agp_enable, |
1590 | .cache_flush = global_cache_flush, | 1607 | .cache_flush = global_cache_flush, |
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index e608dadece2f..acb2de5e3a98 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c | |||
@@ -926,9 +926,10 @@ cy_sched_event(struct cyclades_port *info, int event) | |||
926 | * had to poll every port to see if that port needed servicing. | 926 | * had to poll every port to see if that port needed servicing. |
927 | */ | 927 | */ |
928 | static void | 928 | static void |
929 | do_softint(void *private_) | 929 | do_softint(struct work_struct *work) |
930 | { | 930 | { |
931 | struct cyclades_port *info = (struct cyclades_port *) private_; | 931 | struct cyclades_port *info = |
932 | container_of(work, struct cyclades_port, tqueue); | ||
932 | struct tty_struct *tty; | 933 | struct tty_struct *tty; |
933 | 934 | ||
934 | tty = info->tty; | 935 | tty = info->tty; |
@@ -5328,7 +5329,7 @@ cy_init(void) | |||
5328 | info->blocked_open = 0; | 5329 | info->blocked_open = 0; |
5329 | info->default_threshold = 0; | 5330 | info->default_threshold = 0; |
5330 | info->default_timeout = 0; | 5331 | info->default_timeout = 0; |
5331 | INIT_WORK(&info->tqueue, do_softint, info); | 5332 | INIT_WORK(&info->tqueue, do_softint); |
5332 | init_waitqueue_head(&info->open_wait); | 5333 | init_waitqueue_head(&info->open_wait); |
5333 | init_waitqueue_head(&info->close_wait); | 5334 | init_waitqueue_head(&info->close_wait); |
5334 | init_waitqueue_head(&info->shutdown_wait); | 5335 | init_waitqueue_head(&info->shutdown_wait); |
@@ -5403,7 +5404,7 @@ cy_init(void) | |||
5403 | info->blocked_open = 0; | 5404 | info->blocked_open = 0; |
5404 | info->default_threshold = 0; | 5405 | info->default_threshold = 0; |
5405 | info->default_timeout = 0; | 5406 | info->default_timeout = 0; |
5406 | INIT_WORK(&info->tqueue, do_softint, info); | 5407 | INIT_WORK(&info->tqueue, do_softint); |
5407 | init_waitqueue_head(&info->open_wait); | 5408 | init_waitqueue_head(&info->open_wait); |
5408 | init_waitqueue_head(&info->close_wait); | 5409 | init_waitqueue_head(&info->close_wait); |
5409 | init_waitqueue_head(&info->shutdown_wait); | 5410 | init_waitqueue_head(&info->shutdown_wait); |
diff --git a/drivers/char/decserial.c b/drivers/char/decserial.c index 85f404e25c73..8ea2bea2b183 100644 --- a/drivers/char/decserial.c +++ b/drivers/char/decserial.c | |||
@@ -23,20 +23,12 @@ | |||
23 | extern int zs_init(void); | 23 | extern int zs_init(void); |
24 | #endif | 24 | #endif |
25 | 25 | ||
26 | #ifdef CONFIG_DZ | ||
27 | extern int dz_init(void); | ||
28 | #endif | ||
29 | |||
30 | #ifdef CONFIG_SERIAL_CONSOLE | 26 | #ifdef CONFIG_SERIAL_CONSOLE |
31 | 27 | ||
32 | #ifdef CONFIG_ZS | 28 | #ifdef CONFIG_ZS |
33 | extern void zs_serial_console_init(void); | 29 | extern void zs_serial_console_init(void); |
34 | #endif | 30 | #endif |
35 | 31 | ||
36 | #ifdef CONFIG_DZ | ||
37 | extern void dz_serial_console_init(void); | ||
38 | #endif | ||
39 | |||
40 | #endif | 32 | #endif |
41 | 33 | ||
42 | /* rs_init - starts up the serial interface - | 34 | /* rs_init - starts up the serial interface - |
@@ -46,23 +38,11 @@ extern void dz_serial_console_init(void); | |||
46 | 38 | ||
47 | int __init rs_init(void) | 39 | int __init rs_init(void) |
48 | { | 40 | { |
49 | 41 | #ifdef CONFIG_ZS | |
50 | #if defined(CONFIG_ZS) && defined(CONFIG_DZ) | ||
51 | if (IOASIC) | 42 | if (IOASIC) |
52 | return zs_init(); | 43 | return zs_init(); |
53 | else | ||
54 | return dz_init(); | ||
55 | #else | ||
56 | |||
57 | #ifdef CONFIG_ZS | ||
58 | return zs_init(); | ||
59 | #endif | ||
60 | |||
61 | #ifdef CONFIG_DZ | ||
62 | return dz_init(); | ||
63 | #endif | ||
64 | |||
65 | #endif | 44 | #endif |
45 | return -ENXIO; | ||
66 | } | 46 | } |
67 | 47 | ||
68 | __initcall(rs_init); | 48 | __initcall(rs_init); |
@@ -76,21 +56,9 @@ __initcall(rs_init); | |||
76 | */ | 56 | */ |
77 | static int __init decserial_console_init(void) | 57 | static int __init decserial_console_init(void) |
78 | { | 58 | { |
79 | #if defined(CONFIG_ZS) && defined(CONFIG_DZ) | 59 | #ifdef CONFIG_ZS |
80 | if (IOASIC) | 60 | if (IOASIC) |
81 | zs_serial_console_init(); | 61 | zs_serial_console_init(); |
82 | else | ||
83 | dz_serial_console_init(); | ||
84 | #else | ||
85 | |||
86 | #ifdef CONFIG_ZS | ||
87 | zs_serial_console_init(); | ||
88 | #endif | ||
89 | |||
90 | #ifdef CONFIG_DZ | ||
91 | dz_serial_console_init(); | ||
92 | #endif | ||
93 | |||
94 | #endif | 62 | #endif |
95 | return 0; | 63 | return 0; |
96 | } | 64 | } |
diff --git a/drivers/char/drm/drm_sman.c b/drivers/char/drm/drm_sman.c index 425c82336ee0..19c81d2e13d0 100644 --- a/drivers/char/drm/drm_sman.c +++ b/drivers/char/drm/drm_sman.c | |||
@@ -162,6 +162,7 @@ drm_sman_set_manager(drm_sman_t * sman, unsigned int manager, | |||
162 | 162 | ||
163 | return 0; | 163 | return 0; |
164 | } | 164 | } |
165 | EXPORT_SYMBOL(drm_sman_set_manager); | ||
165 | 166 | ||
166 | static drm_owner_item_t *drm_sman_get_owner_item(drm_sman_t * sman, | 167 | static drm_owner_item_t *drm_sman_get_owner_item(drm_sman_t * sman, |
167 | unsigned long owner) | 168 | unsigned long owner) |
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c index b40ae438f531..ae2691942ddb 100644 --- a/drivers/char/drm/drm_vm.c +++ b/drivers/char/drm/drm_vm.c | |||
@@ -147,14 +147,14 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma, | |||
147 | if (address > vma->vm_end) | 147 | if (address > vma->vm_end) |
148 | return NOPAGE_SIGBUS; /* Disallow mremap */ | 148 | return NOPAGE_SIGBUS; /* Disallow mremap */ |
149 | if (!map) | 149 | if (!map) |
150 | return NOPAGE_OOM; /* Nothing allocated */ | 150 | return NOPAGE_SIGBUS; /* Nothing allocated */ |
151 | 151 | ||
152 | offset = address - vma->vm_start; | 152 | offset = address - vma->vm_start; |
153 | i = (unsigned long)map->handle + offset; | 153 | i = (unsigned long)map->handle + offset; |
154 | page = (map->type == _DRM_CONSISTENT) ? | 154 | page = (map->type == _DRM_CONSISTENT) ? |
155 | virt_to_page((void *)i) : vmalloc_to_page((void *)i); | 155 | virt_to_page((void *)i) : vmalloc_to_page((void *)i); |
156 | if (!page) | 156 | if (!page) |
157 | return NOPAGE_OOM; | 157 | return NOPAGE_SIGBUS; |
158 | get_page(page); | 158 | get_page(page); |
159 | 159 | ||
160 | DRM_DEBUG("shm_nopage 0x%lx\n", address); | 160 | 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, | |||
272 | if (address > vma->vm_end) | 272 | if (address > vma->vm_end) |
273 | return NOPAGE_SIGBUS; /* Disallow mremap */ | 273 | return NOPAGE_SIGBUS; /* Disallow mremap */ |
274 | if (!dma->pagelist) | 274 | if (!dma->pagelist) |
275 | return NOPAGE_OOM; /* Nothing allocated */ | 275 | return NOPAGE_SIGBUS; /* Nothing allocated */ |
276 | 276 | ||
277 | offset = address - vma->vm_start; /* vm_[pg]off[set] should be 0 */ | 277 | offset = address - vma->vm_start; /* vm_[pg]off[set] should be 0 */ |
278 | page_nr = offset >> PAGE_SHIFT; | 278 | page_nr = offset >> PAGE_SHIFT; |
@@ -310,7 +310,7 @@ static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma, | |||
310 | if (address > vma->vm_end) | 310 | if (address > vma->vm_end) |
311 | return NOPAGE_SIGBUS; /* Disallow mremap */ | 311 | return NOPAGE_SIGBUS; /* Disallow mremap */ |
312 | if (!entry->pagelist) | 312 | if (!entry->pagelist) |
313 | return NOPAGE_OOM; /* Nothing allocated */ | 313 | return NOPAGE_SIGBUS; /* Nothing allocated */ |
314 | 314 | ||
315 | offset = address - vma->vm_start; | 315 | offset = address - vma->vm_start; |
316 | map_offset = map->offset - (unsigned long)dev->sg->virtual; | 316 | map_offset = map->offset - (unsigned long)dev->sg->virtual; |
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c index 60c1695db300..806f9ce5f47b 100644 --- a/drivers/char/drm/via_dmablit.c +++ b/drivers/char/drm/via_dmablit.c | |||
@@ -500,9 +500,9 @@ via_dmablit_timer(unsigned long data) | |||
500 | 500 | ||
501 | 501 | ||
502 | static void | 502 | static void |
503 | via_dmablit_workqueue(void *data) | 503 | via_dmablit_workqueue(struct work_struct *work) |
504 | { | 504 | { |
505 | drm_via_blitq_t *blitq = (drm_via_blitq_t *) data; | 505 | drm_via_blitq_t *blitq = container_of(work, drm_via_blitq_t, wq); |
506 | drm_device_t *dev = blitq->dev; | 506 | drm_device_t *dev = blitq->dev; |
507 | unsigned long irqsave; | 507 | unsigned long irqsave; |
508 | drm_via_sg_info_t *cur_sg; | 508 | drm_via_sg_info_t *cur_sg; |
@@ -571,7 +571,7 @@ via_init_dmablit(drm_device_t *dev) | |||
571 | DRM_INIT_WAITQUEUE(blitq->blit_queue + j); | 571 | DRM_INIT_WAITQUEUE(blitq->blit_queue + j); |
572 | } | 572 | } |
573 | DRM_INIT_WAITQUEUE(&blitq->busy_queue); | 573 | DRM_INIT_WAITQUEUE(&blitq->busy_queue); |
574 | INIT_WORK(&blitq->wq, via_dmablit_workqueue, blitq); | 574 | INIT_WORK(&blitq->wq, via_dmablit_workqueue); |
575 | init_timer(&blitq->poll_timer); | 575 | init_timer(&blitq->poll_timer); |
576 | blitq->poll_timer.function = &via_dmablit_timer; | 576 | blitq->poll_timer.function = &via_dmablit_timer; |
577 | blitq->poll_timer.data = (unsigned long) blitq; | 577 | blitq->poll_timer.data = (unsigned long) blitq; |
diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 706733c0b36a..7c71eb779802 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c | |||
@@ -200,7 +200,7 @@ static int pc_ioctl(struct tty_struct *, struct file *, | |||
200 | static int info_ioctl(struct tty_struct *, struct file *, | 200 | static int info_ioctl(struct tty_struct *, struct file *, |
201 | unsigned int, unsigned long); | 201 | unsigned int, unsigned long); |
202 | static void pc_set_termios(struct tty_struct *, struct termios *); | 202 | static void pc_set_termios(struct tty_struct *, struct termios *); |
203 | static void do_softint(void *); | 203 | static void do_softint(struct work_struct *work); |
204 | static void pc_stop(struct tty_struct *); | 204 | static void pc_stop(struct tty_struct *); |
205 | static void pc_start(struct tty_struct *); | 205 | static void pc_start(struct tty_struct *); |
206 | static void pc_throttle(struct tty_struct * tty); | 206 | static void pc_throttle(struct tty_struct * tty); |
@@ -1505,7 +1505,7 @@ static void post_fep_init(unsigned int crd) | |||
1505 | 1505 | ||
1506 | ch->brdchan = bc; | 1506 | ch->brdchan = bc; |
1507 | ch->mailbox = gd; | 1507 | ch->mailbox = gd; |
1508 | INIT_WORK(&ch->tqueue, do_softint, ch); | 1508 | INIT_WORK(&ch->tqueue, do_softint); |
1509 | ch->board = &boards[crd]; | 1509 | ch->board = &boards[crd]; |
1510 | 1510 | ||
1511 | spin_lock_irqsave(&epca_lock, flags); | 1511 | spin_lock_irqsave(&epca_lock, flags); |
@@ -2566,9 +2566,9 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios) | |||
2566 | 2566 | ||
2567 | /* --------------------- Begin do_softint ----------------------- */ | 2567 | /* --------------------- Begin do_softint ----------------------- */ |
2568 | 2568 | ||
2569 | static void do_softint(void *private_) | 2569 | static void do_softint(struct work_struct *work) |
2570 | { /* Begin do_softint */ | 2570 | { /* Begin do_softint */ |
2571 | struct channel *ch = (struct channel *) private_; | 2571 | struct channel *ch = container_of(work, struct channel, tqueue); |
2572 | /* Called in response to a modem change event */ | 2572 | /* Called in response to a modem change event */ |
2573 | if (ch && ch->magic == EPCA_MAGIC) { /* Begin EPCA_MAGIC */ | 2573 | if (ch && ch->magic == EPCA_MAGIC) { /* Begin EPCA_MAGIC */ |
2574 | struct tty_struct *tty = ch->tty; | 2574 | struct tty_struct *tty = ch->tty; |
diff --git a/drivers/char/esp.c b/drivers/char/esp.c index 15a4ea896328..93b551962513 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c | |||
@@ -723,9 +723,10 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) | |||
723 | * ------------------------------------------------------------------- | 723 | * ------------------------------------------------------------------- |
724 | */ | 724 | */ |
725 | 725 | ||
726 | static void do_softint(void *private_) | 726 | static void do_softint(struct work_struct *work) |
727 | { | 727 | { |
728 | struct esp_struct *info = (struct esp_struct *) private_; | 728 | struct esp_struct *info = |
729 | container_of(work, struct esp_struct, tqueue); | ||
729 | struct tty_struct *tty; | 730 | struct tty_struct *tty; |
730 | 731 | ||
731 | tty = info->tty; | 732 | tty = info->tty; |
@@ -746,9 +747,10 @@ static void do_softint(void *private_) | |||
746 | * do_serial_hangup() -> tty->hangup() -> esp_hangup() | 747 | * do_serial_hangup() -> tty->hangup() -> esp_hangup() |
747 | * | 748 | * |
748 | */ | 749 | */ |
749 | static void do_serial_hangup(void *private_) | 750 | static void do_serial_hangup(struct work_struct *work) |
750 | { | 751 | { |
751 | struct esp_struct *info = (struct esp_struct *) private_; | 752 | struct esp_struct *info = |
753 | container_of(work, struct esp_struct, tqueue_hangup); | ||
752 | struct tty_struct *tty; | 754 | struct tty_struct *tty; |
753 | 755 | ||
754 | tty = info->tty; | 756 | tty = info->tty; |
@@ -2501,8 +2503,8 @@ static int __init espserial_init(void) | |||
2501 | info->magic = ESP_MAGIC; | 2503 | info->magic = ESP_MAGIC; |
2502 | info->close_delay = 5*HZ/10; | 2504 | info->close_delay = 5*HZ/10; |
2503 | info->closing_wait = 30*HZ; | 2505 | info->closing_wait = 30*HZ; |
2504 | INIT_WORK(&info->tqueue, do_softint, info); | 2506 | INIT_WORK(&info->tqueue, do_softint); |
2505 | INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info); | 2507 | INIT_WORK(&info->tqueue_hangup, do_serial_hangup); |
2506 | info->config.rx_timeout = rx_timeout; | 2508 | info->config.rx_timeout = rx_timeout; |
2507 | info->config.flow_on = flow_on; | 2509 | info->config.flow_on = flow_on; |
2508 | info->config.flow_off = flow_off; | 2510 | info->config.flow_off = flow_off; |
diff --git a/drivers/char/ftape/Kconfig b/drivers/char/ftape/Kconfig deleted file mode 100644 index 0d65189a7ae8..000000000000 --- a/drivers/char/ftape/Kconfig +++ /dev/null | |||
@@ -1,330 +0,0 @@ | |||
1 | # | ||
2 | # Ftape configuration | ||
3 | # | ||
4 | config ZFTAPE | ||
5 | tristate "Zftape, the VFS interface" | ||
6 | depends on FTAPE | ||
7 | ---help--- | ||
8 | Normally, you want to say Y or M. DON'T say N here or you | ||
9 | WON'T BE ABLE TO USE YOUR FLOPPY TAPE DRIVE. | ||
10 | |||
11 | The ftape module itself no longer contains the routines necessary | ||
12 | to interface with the kernel VFS layer (i.e. to actually write data | ||
13 | to and read data from the tape drive). Instead the file system | ||
14 | interface (i.e. the hardware independent part of the driver) has | ||
15 | been moved to a separate module. | ||
16 | |||
17 | To compile this driver as a module, choose M here: the | ||
18 | module will be called zftape. | ||
19 | |||
20 | Regardless of whether you say Y or M here, an additional runtime | ||
21 | loadable module called `zft-compressor' which contains code to | ||
22 | support user transparent on-the-fly compression based on Ross | ||
23 | William's lzrw3 algorithm will be produced. If you have enabled the | ||
24 | kernel module loader (i.e. have said Y to "Kernel module loader | ||
25 | support", above) then `zft-compressor' will be loaded | ||
26 | automatically by zftape when needed. | ||
27 | |||
28 | Despite its name, zftape does NOT use compression by default. | ||
29 | |||
30 | config ZFT_DFLT_BLK_SZ | ||
31 | int "Default block size" | ||
32 | depends on ZFTAPE | ||
33 | default "10240" | ||
34 | ---help--- | ||
35 | If unsure leave this at its default value, i.e. 10240. Note that | ||
36 | you specify only the default block size here. The block size can be | ||
37 | changed at run time using the MTSETBLK tape operation with the | ||
38 | MTIOCTOP ioctl (i.e. with "mt -f /dev/qft0 setblk #BLKSZ" from the | ||
39 | shell command line). | ||
40 | |||
41 | The probably most striking difference between zftape and previous | ||
42 | versions of ftape is the fact that all data must be written or read | ||
43 | in multiples of a fixed block size. The block size defaults to | ||
44 | 10240 which is what GNU tar uses. The values for the block size | ||
45 | should be either 1 or multiples of 1024 up to a maximum value of | ||
46 | 63488 (i.e. 62 K). If you specify `1' then zftape's builtin | ||
47 | compression will be disabled. | ||
48 | |||
49 | Reasonable values are `10240' (GNU tar's default block size), | ||
50 | `5120' (afio's default block size), `32768' (default block size some | ||
51 | backup programs assume for SCSI tape drives) or `1' (no restriction | ||
52 | on block size, but disables builtin compression). | ||
53 | |||
54 | comment "The compressor will be built as a module only!" | ||
55 | depends on FTAPE && ZFTAPE | ||
56 | |||
57 | config ZFT_COMPRESSOR | ||
58 | tristate | ||
59 | depends on FTAPE!=n && ZFTAPE!=n | ||
60 | default m | ||
61 | |||
62 | config FT_NR_BUFFERS | ||
63 | int "Number of ftape buffers (EXPERIMENTAL)" | ||
64 | depends on FTAPE && EXPERIMENTAL | ||
65 | default "3" | ||
66 | help | ||
67 | Please leave this at `3' unless you REALLY know what you are doing. | ||
68 | It is not necessary to change this value. Values below 3 make the | ||
69 | proper use of ftape impossible, values greater than 3 are a waste of | ||
70 | memory. You can change the amount of DMA memory used by ftape at | ||
71 | runtime with "mt -f /dev/qft0 setdrvbuffer #NUMBUFFERS". Each buffer | ||
72 | wastes 32 KB of memory. Please note that this memory cannot be | ||
73 | swapped out. | ||
74 | |||
75 | config FT_PROC_FS | ||
76 | bool "Enable procfs status report (+2kb)" | ||
77 | depends on FTAPE && PROC_FS | ||
78 | ---help--- | ||
79 | Optional. Saying Y will result in creation of a directory | ||
80 | `/proc/ftape' under the /proc file system. The files can be viewed | ||
81 | with your favorite pager (i.e. use "more /proc/ftape/history" or | ||
82 | "less /proc/ftape/history" or simply "cat /proc/ftape/history"). The | ||
83 | file will contain some status information about the inserted | ||
84 | cartridge, the kernel driver, your tape drive, the floppy disk | ||
85 | controller and the error history for the most recent use of the | ||
86 | kernel driver. Saying Y will enlarge the size of the ftape driver | ||
87 | by approximately 2 KB. | ||
88 | |||
89 | WARNING: When compiling ftape as a module (i.e. saying M to "Floppy | ||
90 | tape drive") it is dangerous to use ftape's /proc file system | ||
91 | interface. Accessing `/proc/ftape' while the module is unloaded will | ||
92 | result in a kernel Oops. This cannot be fixed from inside ftape. | ||
93 | |||
94 | choice | ||
95 | prompt "Debugging output" | ||
96 | depends on FTAPE | ||
97 | default FT_NORMAL_DEBUG | ||
98 | |||
99 | config FT_NORMAL_DEBUG | ||
100 | bool "Normal" | ||
101 | ---help--- | ||
102 | This option controls the amount of debugging output the ftape driver | ||
103 | is ABLE to produce; it does not increase or diminish the debugging | ||
104 | level itself. If unsure, leave this at its default setting, | ||
105 | i.e. choose "Normal". | ||
106 | |||
107 | Ftape can print lots of debugging messages to the system console | ||
108 | resp. kernel log files. Reducing the amount of possible debugging | ||
109 | output reduces the size of the kernel module by some KB, so it might | ||
110 | be a good idea to use "None" for emergency boot floppies. | ||
111 | |||
112 | If you want to save memory then the following strategy is | ||
113 | recommended: leave this option at its default setting "Normal" until | ||
114 | you know that the driver works as expected, afterwards reconfigure | ||
115 | the kernel, this time specifying "Reduced" or "None" and recompile | ||
116 | and install the kernel as usual. Note that choosing "Excessive" | ||
117 | debugging output does not increase the amount of debugging output | ||
118 | printed to the console but only makes it possible to produce | ||
119 | "Excessive" debugging output. | ||
120 | |||
121 | Please read <file:Documentation/ftape.txt> for a short description | ||
122 | how to control the amount of debugging output. | ||
123 | |||
124 | config FT_FULL_DEBUG | ||
125 | bool "Excessive" | ||
126 | help | ||
127 | Extremely verbose output for driver debugging purposes. | ||
128 | |||
129 | config FT_NO_TRACE | ||
130 | bool "Reduced" | ||
131 | help | ||
132 | Reduced tape driver debugging output. | ||
133 | |||
134 | config FT_NO_TRACE_AT_ALL | ||
135 | bool "None" | ||
136 | help | ||
137 | Suppress all debugging output from the tape drive. | ||
138 | |||
139 | endchoice | ||
140 | |||
141 | comment "Hardware configuration" | ||
142 | depends on FTAPE | ||
143 | |||
144 | choice | ||
145 | prompt "Floppy tape controllers" | ||
146 | depends on FTAPE | ||
147 | default FT_STD_FDC | ||
148 | |||
149 | config FT_STD_FDC | ||
150 | bool "Standard" | ||
151 | ---help--- | ||
152 | Only change this setting if you have a special controller. If you | ||
153 | didn't plug any add-on card into your computer system but just | ||
154 | plugged the floppy tape cable into the already existing floppy drive | ||
155 | controller then you don't want to change the default setting, | ||
156 | i.e. choose "Standard". | ||
157 | |||
158 | Choose "MACH-2" if you have a Mountain Mach-2 controller. | ||
159 | Choose "FC-10/FC-20" if you have a Colorado FC-10 or FC-20 | ||
160 | controller. | ||
161 | Choose "Alt/82078" if you have another controller that is located at | ||
162 | an IO base address different from the standard floppy drive | ||
163 | controller's base address of `0x3f0', or uses an IRQ (interrupt) | ||
164 | channel different from `6', or a DMA channel different from | ||
165 | `2'. This is necessary for any controller card that is based on | ||
166 | Intel's 82078 FDC such as Seagate's, Exabyte's and Iomega's "high | ||
167 | speed" controllers. | ||
168 | |||
169 | If you choose something other than "Standard" then please make | ||
170 | sure that the settings for the IO base address and the IRQ and DMA | ||
171 | channel in the configuration menus below are correct. Use the manual | ||
172 | of your tape drive to determine the correct settings! | ||
173 | |||
174 | If you are already successfully using your tape drive with another | ||
175 | operating system then you definitely should use the same settings | ||
176 | for the IO base, the IRQ and DMA channel that have proven to work | ||
177 | with that other OS. | ||
178 | |||
179 | Note that this menu lets you specify only the default setting for | ||
180 | the hardware setup. The hardware configuration can be changed at | ||
181 | boot time (when ftape is compiled into the kernel, i.e. if you | ||
182 | have said Y to "Floppy tape drive") or module load time (i.e. if you | ||
183 | have said M to "Floppy tape drive"). | ||
184 | |||
185 | Please read also the file <file:Documentation/ftape.txt> which | ||
186 | contains a short description of the parameters that can be set at | ||
187 | boot or load time. If you want to use your floppy tape drive on a | ||
188 | PCI-bus based system, please read the file | ||
189 | <file:drivers/char/ftape/README.PCI>. | ||
190 | |||
191 | config FT_MACH2 | ||
192 | bool "MACH-2" | ||
193 | |||
194 | config FT_PROBE_FC10 | ||
195 | bool "FC-10/FC-20" | ||
196 | |||
197 | config FT_ALT_FDC | ||
198 | bool "Alt/82078" | ||
199 | |||
200 | endchoice | ||
201 | |||
202 | comment "Consult the manuals of your tape drive for the correct settings!" | ||
203 | depends on FTAPE && !FT_STD_FDC | ||
204 | |||
205 | config FT_FDC_BASE | ||
206 | hex "IO base of the floppy disk controller" | ||
207 | depends on FTAPE && !FT_STD_FDC | ||
208 | default "0" | ||
209 | ---help--- | ||
210 | You don't need to specify a value if the following default | ||
211 | settings for the base IO address are correct: | ||
212 | <<< MACH-2 : 0x1E0 >>> | ||
213 | <<< FC-10/FC-20: 0x180 >>> | ||
214 | <<< Secondary : 0x370 >>> | ||
215 | Secondary refers to a secondary FDC controller like the "high speed" | ||
216 | controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash. | ||
217 | Please make sure that the setting for the IO base address | ||
218 | specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR | ||
219 | CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already | ||
220 | successfully using the tape drive with another operating system then | ||
221 | you definitely should use the same settings for the IO base that has | ||
222 | proven to work with that other OS. | ||
223 | |||
224 | Note that this menu lets you specify only the default setting for | ||
225 | the IO base. The hardware configuration can be changed at boot time | ||
226 | (when ftape is compiled into the kernel, i.e. if you specified Y to | ||
227 | "Floppy tape drive") or module load time (i.e. if you have said M to | ||
228 | "Floppy tape drive"). | ||
229 | |||
230 | Please read also the file <file:Documentation/ftape.txt> which | ||
231 | contains a short description of the parameters that can be set at | ||
232 | boot or load time. | ||
233 | |||
234 | config FT_FDC_IRQ | ||
235 | int "IRQ channel of the floppy disk controller" | ||
236 | depends on FTAPE && !FT_STD_FDC | ||
237 | default "0" | ||
238 | ---help--- | ||
239 | You don't need to specify a value if the following default | ||
240 | settings for the interrupt channel are correct: | ||
241 | <<< MACH-2 : 6 >>> | ||
242 | <<< FC-10/FC-20: 9 >>> | ||
243 | <<< Secondary : 6 >>> | ||
244 | Secondary refers to secondary a FDC controller like the "high speed" | ||
245 | controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash. | ||
246 | Please make sure that the setting for the IO base address | ||
247 | specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR | ||
248 | CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already | ||
249 | successfully using the tape drive with another operating system then | ||
250 | you definitely should use the same settings for the IO base that has | ||
251 | proven to work with that other OS. | ||
252 | |||
253 | Note that this menu lets you specify only the default setting for | ||
254 | the IRQ channel. The hardware configuration can be changed at boot | ||
255 | time (when ftape is compiled into the kernel, i.e. if you said Y to | ||
256 | "Floppy tape drive") or module load time (i.e. if you said M to | ||
257 | "Floppy tape drive"). | ||
258 | |||
259 | Please read also the file <file:Documentation/ftape.txt> which | ||
260 | contains a short description of the parameters that can be set at | ||
261 | boot or load time. | ||
262 | |||
263 | config FT_FDC_DMA | ||
264 | int "DMA channel of the floppy disk controller" | ||
265 | depends on FTAPE && !FT_STD_FDC | ||
266 | default "0" | ||
267 | ---help--- | ||
268 | You don't need to specify a value if the following default | ||
269 | settings for the DMA channel are correct: | ||
270 | <<< MACH-2 : 2 >>> | ||
271 | <<< FC-10/FC-20: 3 >>> | ||
272 | <<< Secondary : 2 >>> | ||
273 | Secondary refers to a secondary FDC controller like the "high speed" | ||
274 | controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash. | ||
275 | Please make sure that the setting for the IO base address | ||
276 | specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR | ||
277 | CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already | ||
278 | successfully using the tape drive with another operating system then | ||
279 | you definitely should use the same settings for the IO base that has | ||
280 | proven to work with that other OS. | ||
281 | |||
282 | Note that this menu lets you specify only the default setting for | ||
283 | the DMA channel. The hardware configuration can be changed at boot | ||
284 | time (when ftape is compiled into the kernel, i.e. if you said Y to | ||
285 | "Floppy tape drive") or module load time (i.e. if you said M to | ||
286 | "Floppy tape drive"). | ||
287 | |||
288 | Please read also the file <file:Documentation/ftape.txt> which | ||
289 | contains a short description of the parameters that can be set at | ||
290 | boot or load time. | ||
291 | |||
292 | config FT_FDC_THR | ||
293 | int "Default FIFO threshold (EXPERIMENTAL)" | ||
294 | depends on FTAPE && EXPERIMENTAL | ||
295 | default "8" | ||
296 | help | ||
297 | Set the FIFO threshold of the FDC. If this is higher the DMA | ||
298 | controller may serve the FDC after a higher latency time. If this is | ||
299 | lower, fewer DMA transfers occur leading to less bus contention. | ||
300 | You may try to tune this if ftape annoys you with "reduced data | ||
301 | rate because of excessive overrun errors" messages. However, this | ||
302 | doesn't seem to have too much effect. | ||
303 | |||
304 | If unsure, don't touch the initial value, i.e. leave it at "8". | ||
305 | |||
306 | config FT_FDC_MAX_RATE | ||
307 | int "Maximal data rate to use (EXPERIMENTAL)" | ||
308 | depends on FTAPE && EXPERIMENTAL | ||
309 | default "2000" | ||
310 | ---help--- | ||
311 | With some motherboard/FDC combinations ftape will not be able to | ||
312 | run your FDC/tape drive combination at the highest available | ||
313 | speed. If this is the case you'll encounter "reduced data rate | ||
314 | because of excessive overrun errors" messages and lots of retries | ||
315 | before ftape finally decides to reduce the data rate. | ||
316 | |||
317 | In this case it might be desirable to tell ftape beforehand that | ||
318 | it need not try to run the tape drive at the highest available | ||
319 | speed. If unsure, leave this disabled, i.e. leave it at 2000 | ||
320 | bits/sec. | ||
321 | |||
322 | config FT_ALPHA_CLOCK | ||
323 | int "CPU clock frequency of your DEC Alpha" if ALPHA | ||
324 | depends on FTAPE | ||
325 | default "0" | ||
326 | help | ||
327 | On some DEC Alpha machines the CPU clock frequency cannot be | ||
328 | determined automatically, so you need to specify it here ONLY if | ||
329 | running a DEC Alpha, otherwise this setting has no effect. | ||
330 | |||
diff --git a/drivers/char/ftape/Makefile b/drivers/char/ftape/Makefile deleted file mode 100644 index 0e67d2f8b7ec..000000000000 --- a/drivers/char/ftape/Makefile +++ /dev/null | |||
@@ -1,28 +0,0 @@ | |||
1 | # | ||
2 | # Copyright (C) 1997 Claus Heine. | ||
3 | # | ||
4 | # This program is free software; you can redistribute it and/or modify | ||
5 | # it under the terms of the GNU General Public License as published by | ||
6 | # the Free Software Foundation; either version 2, or (at your option) | ||
7 | # any later version. | ||
8 | # | ||
9 | # This program is distributed in the hope that it will be useful, | ||
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | # GNU General Public License for more details. | ||
13 | # | ||
14 | # You should have received a copy of the GNU General Public License | ||
15 | # along with this program; see the file COPYING. If not, write to | ||
16 | # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | # | ||
18 | # $Source: /homes/cvs/ftape-stacked/ftape/Makefile,v $ | ||
19 | # $Revision: 1.4 $ | ||
20 | # $Date: 1997/10/05 19:17:56 $ | ||
21 | # | ||
22 | # Makefile for the QIC-40/80/3010/3020 floppy-tape driver for | ||
23 | # Linux. | ||
24 | # | ||
25 | |||
26 | obj-$(CONFIG_FTAPE) += lowlevel/ | ||
27 | obj-$(CONFIG_ZFTAPE) += zftape/ | ||
28 | obj-$(CONFIG_ZFT_COMPRESSOR) += compressor/ | ||
diff --git a/drivers/char/ftape/README.PCI b/drivers/char/ftape/README.PCI deleted file mode 100644 index 18de159d36e0..000000000000 --- a/drivers/char/ftape/README.PCI +++ /dev/null | |||
@@ -1,81 +0,0 @@ | |||
1 | Some notes for ftape users with PCI motherboards: | ||
2 | ================================================= | ||
3 | |||
4 | The problem: | ||
5 | ------------ | ||
6 | |||
7 | There have been some problem reports from people using PCI-bus based | ||
8 | systems getting overrun errors. | ||
9 | I wasn't able to reproduce these until I ran ftape on a Intel Plato | ||
10 | (Premiere PCI II) motherboard with bios version 1.00.08AX1. | ||
11 | It turned out that if GAT (Guaranteed Access Timing) is enabled (?) | ||
12 | ftape gets a lot of overrun errors. | ||
13 | The problem disappears when disabling GAT in the bios. | ||
14 | Note that Intel removed this setting (permanently disabled) from the | ||
15 | 1.00.10AX1 bios ! | ||
16 | |||
17 | It looks like that if GAT is enabled there are often large periods | ||
18 | (greater than 120 us !??) on the ISA bus that the DMA controller cannot | ||
19 | service the floppy disk controller. | ||
20 | I cannot imagine this being acceptable in a decent PCI implementation. | ||
21 | Maybe this is a `feature' of the chipset. I can only speculate why | ||
22 | Intel choose to remove the option from the latest Bios... | ||
23 | |||
24 | The lesson of this all is that there may be other motherboard | ||
25 | implementations having the same of similar problems. | ||
26 | If you experience a lot of overrun errors during a backup to tape, | ||
27 | see if there is some setting in the Bios that may influence the | ||
28 | bus timing. | ||
29 | |||
30 | I judge this a hardware problem and not a limitation of ftape ;-) | ||
31 | My DOS backup software seems to be suffering from the same problems | ||
32 | and even refuses to run at 1 Mbps ! | ||
33 | Ftape will reduce the data-rate from 1 Mbps to 500 Kbps if the number | ||
34 | of overrun errors on a track exceeds a threshold. | ||
35 | |||
36 | |||
37 | Possible solutions: | ||
38 | ------------------- | ||
39 | |||
40 | Some of the problems were solved by upgrading the (flash) bios. | ||
41 | Other suggest that it has to do with the FDC being on the PCI | ||
42 | bus, but that is not the case with the Intel Premiere II boards. | ||
43 | [If upgrading the bios doesn't solve the problem you could try | ||
44 | a floppy disk controller on the isa-bus]. | ||
45 | |||
46 | Here is a list of systems and recommended BIOS settings: | ||
47 | |||
48 | |||
49 | Intel Premiere PCI (Revenge): | ||
50 | |||
51 | Bios version 1.00.09.AF2 is reported to work. | ||
52 | |||
53 | |||
54 | |||
55 | Intel Premiere PCI II (Plato): | ||
56 | |||
57 | Bios version 1.00.10.AX1 and version 11 beta are ok. | ||
58 | If using version 1.00.08.AX1, GAT must be disabled ! | ||
59 | |||
60 | |||
61 | |||
62 | ASUS PCI/I-SP3G: | ||
63 | |||
64 | Preferred settings: ISA-GAT-mode : disabled | ||
65 | DMA-linebuffer-mode : standard | ||
66 | ISA-masterbuffer-mode : standard | ||
67 | |||
68 | |||
69 | DELL Dimension XPS P90 | ||
70 | |||
71 | Bios version A2 is reported to be broken, while bios version A5 works. | ||
72 | You can get a flash bios upgrade from http://www.dell.com | ||
73 | |||
74 | |||
75 | To see if you're having the GAT problem, try making a backup | ||
76 | under DOS. If it's very slow and often repositions you're | ||
77 | probably having this problem. | ||
78 | |||
79 | --//-- | ||
80 | LocalWords: ftape PCI bios GAT ISA DMA chipset Mbps Kbps FDC isa AF ok ASUS | ||
81 | LocalWords: SP linebuffer masterbuffer XPS http www com | ||
diff --git a/drivers/char/ftape/RELEASE-NOTES b/drivers/char/ftape/RELEASE-NOTES deleted file mode 100644 index 03799dbc05a4..000000000000 --- a/drivers/char/ftape/RELEASE-NOTES +++ /dev/null | |||
@@ -1,966 +0,0 @@ | |||
1 | Hey, Emacs, we're -*-Text-*- mode! | ||
2 | |||
3 | ===== Release notes for ftape-3.04d 25/11/97 ===== | ||
4 | - The correct pre-processor statement for "else if" is "#elif" not | ||
5 | "elsif". | ||
6 | - Need to call zft_reset_position() when overwriting cartridges | ||
7 | previously written with ftape-2.x, sftape, or ancient | ||
8 | (pre-ftape-3.x) versions of zftape. | ||
9 | |||
10 | ===== Release notes for ftape-3.04c 16/11/97 ===== | ||
11 | - fdc_probe() was calling DUMPREGS with a result length of "1" which | ||
12 | was just fine. Undo previous change. | ||
13 | |||
14 | ===== Release notes for ftape-3.04b 14/11/97 ===== | ||
15 | |||
16 | - patches/2.x.x/floppy.c.diff was somewhat broken, releasing i/o | ||
17 | regions it never had allocated. | ||
18 | - fdc_probe() was calling DUMPREGS with a result length of "1" instead | ||
19 | of "10" | ||
20 | - Writing deleted data marks if the first segents on track zero are | ||
21 | should work now. | ||
22 | - ftformat should now be able to handle those cases where the tape | ||
23 | drive sets the read only status bit (QIC-40/80 cartridges with | ||
24 | QIC-3010/3020 tape drives) because the header segment is damaged. | ||
25 | - the MTIOCFTCMD ioctl may now be issued by the superuser ONLY. | ||
26 | |||
27 | ===== Release notes for ftape-3.04a 12/11/97 ===== | ||
28 | - Fix an "infinite loop can't be killed by signal" bug in | ||
29 | ftape_get_drive_status(). Only relevant when trying to access | ||
30 | buggy/misconfigured hardware | ||
31 | - Try to compensate a bug in the HP Colorado T3000's firmware: it | ||
32 | doesn't set the write protect bit for QIC80/QIC40 cartridges. | ||
33 | |||
34 | ===== Release notes for ftape-3.04 06/11/97 ===== | ||
35 | - If positioning with fast seeking fails fall back to a slow seek | ||
36 | before giving up. | ||
37 | - (nearly) no retries on "no data errors" when verifying after | ||
38 | formatting. Improved tuning of the bad sector map after formatting. | ||
39 | - the directory layout has changed again to allow for easier kernel | ||
40 | integration | ||
41 | - Module parameter "ftape_tracing" now is called "ft_tracing" because | ||
42 | the "ftape_tracing" variable has the version checksum attached to it. | ||
43 | - `/proc/ftape' interface for 2.0.* kernels. `/proc/ftape' no longer | ||
44 | is a directory but a file that contains all the information formerly | ||
45 | provided in separate files under the `/proc/ftape/' directory. | ||
46 | - Most of the configuration options have been prefixed by "CONFIG_FT_" | ||
47 | in preparation of the kernel inclusion. The Makefiles under | ||
48 | "./ftape/" should be directly usable by the kernel. | ||
49 | - The MODVERSIONS stuff is now auto-detected. | ||
50 | - Broke backslashed multi line options in MCONFIG into separate lines | ||
51 | using GNU-make's "+=" feature. | ||
52 | - The html and dvi version of the manual is now installed under | ||
53 | '/usr/doc/ftape` with 'make install` | ||
54 | - New SMP define in MCONFIG. ftape works with SMP if this is defined. | ||
55 | - attempt to cope with "excessive overrun errors" by gradually | ||
56 | increasing FDC FIFO threshold. But this doesn't seem to have too | ||
57 | much an effect. | ||
58 | - New load time configuration parameter "ft_fdc_rate_limit". If you | ||
59 | encounter too many overrun errors with a 2Mb controller then you | ||
60 | might want to set this to 1000. | ||
61 | - overrun errors on the last sector in a segment sometimes result in | ||
62 | a zero DMA residue. Dunno why, but compensate for it. | ||
63 | - there were still fdc_read() timeout errors. I think I have fixed it | ||
64 | now, please FIXME. | ||
65 | - Sometimes ftape_write() failed to re-start the tape drive when a | ||
66 | segment without a good sector was reached ("wait for empty segment | ||
67 | failed"). This is fixed. Especially important for > QIC-3010. | ||
68 | - sftape (aka ftape-2.x) has vanished. I didn't work on it for | ||
69 | ages. It is probably still possible to use the old code with | ||
70 | ftape-3.04, if one really needs it (BUT RECOMPILE IT) | ||
71 | - zftape no longer alters the contents of already existing volume | ||
72 | table entries, which makes it possible to fill in missing fields, | ||
73 | like time stamps using some user space program. | ||
74 | - ./contrib/vtblc/ contains such a program. | ||
75 | - new perl script ./contrib/scripts/listtape that list the contents of a | ||
76 | floppy tape cartridge parsing the output of "mt volinfo" + "mt fsf" | ||
77 | - the MTWEOF implementation has changed a little bit (after I had a | ||
78 | look at amanda). Calling MTWEOF while the tape is still held open | ||
79 | after writing something to the tape now will terminate the current | ||
80 | volume, and start a new one at the current position. | ||
81 | - the volume table maintained by zftape now is a doubly linked list | ||
82 | that grows dynamically as needed. | ||
83 | |||
84 | formatting floppy tape cartridges | ||
85 | --------------------------------- | ||
86 | * there is a new user space formatting program that does most of the | ||
87 | dirty work in user space (auto-detect, computing the sector | ||
88 | coordinates, adjusting time stamps and statistics). It has a | ||
89 | simple command line interface. | ||
90 | * ftape-format.o has vanished, it has been folded into the low level | ||
91 | ftape.o module, and the ioctl interface into zftape.o. Most of the | ||
92 | complicated stuff has been moved to user space, so there was no | ||
93 | need for a separate module anymore. | ||
94 | * there is a new ioctl MTIOCFTCMD that sends a bare QIC-117 command | ||
95 | to the tape drive. | ||
96 | * there is a new mmap() feature to map the dma buffers into user | ||
97 | space to be used by the user level formatting program. | ||
98 | * Formatting of yet unformatted or totally degaussed cartridges | ||
99 | should be possible now. FIXME. | ||
100 | |||
101 | ===== Release notes for ftape-3.03b, <forgot the exact date> ==== | ||
102 | |||
103 | ftape-3.03b was released as a beta release only. Its main new feature | ||
104 | was support of the DITTO-2GB drive. This was made possible by reverse | ||
105 | engineering done by <fill in his name> after Iomega failed to support | ||
106 | ftape. Although they had promised to do so (this makes me feel a bit | ||
107 | sad and uncomfortable about Iomega). | ||
108 | |||
109 | ===== Release notes for ftape-3.03a, 22/05/97 ==== | ||
110 | |||
111 | - Finally fixed auto-un-loading of modules for kernels > 2.1.18 | ||
112 | - Add an "uninstall" target to the Makefile | ||
113 | - removed the kdtime hack | ||
114 | - texi2www didn't properly set the back-reference from a footnote back | ||
115 | to the regular text. | ||
116 | |||
117 | zftape specific | ||
118 | --------------- | ||
119 | * hide the old compression map volume. Taper doesn't accept the | ||
120 | presence of non-Taper volumes and Taper-written volume on the same | ||
121 | tape. | ||
122 | * EOD (End Of Data) handling was still broken: the expected behavior | ||
123 | is to return a zero byte count at the first attempt to read past | ||
124 | EOD, return a zero byte count at the second attempt to read past | ||
125 | EOD and THEN return -EIO. | ||
126 | |||
127 | ftape-format specific | ||
128 | --------------------- | ||
129 | * Detection of QIC-40 cartridges in select_tape_format() was broken | ||
130 | and made it impossible to format QIC-3010/3020 cartridges. | ||
131 | * There are strange "TR-1 Extra" cartridges out there which weren't | ||
132 | detected properly because the don't strictly conform to the | ||
133 | QIC-80, Rev. N, spec. | ||
134 | |||
135 | ===== Release notes for ftape-3.03, 30/04/97 ===== | ||
136 | |||
137 | - Removed kernel integration code from the package. I plan to provide | ||
138 | a package that can be integrated into the stock kernel separately | ||
139 | (hopefully soon). | ||
140 | As a result, a simple `make' command now will build everything. | ||
141 | - ALL compile time configuration options have been moved to the file | ||
142 | `MCONFIG'. | ||
143 | - Quite a few `low level' changes to allow formatting of cartridges. | ||
144 | - formatting is implemented as a separate module `ftape-format.o'. The | ||
145 | modified `mt' program contains sample code that shows how to use it. | ||
146 | - The VFS interface has been moved from the `ftape.o' module to the | ||
147 | high level modules `zftape.o' resp. `sftape.o'. `ftape.o' contains | ||
148 | the hardware support only. | ||
149 | - A bit of /proc support for kernels > 2.1.28 | ||
150 | - Moved documentation to Doc subdir. INSTALL now contains some real | ||
151 | installation notes. | ||
152 | - `install' target in Makefile. | ||
153 | |||
154 | zftape specific: | ||
155 | ---------------- | ||
156 | |||
157 | - zftape works for large cartridges now ( > 2^31 bytes) | ||
158 | - MTIOCVOLINFO and MTIOCGETSIZE now return the size in KILOBYTES, | ||
159 | NO LONGER in bytes. | ||
160 | |||
161 | - permissions for write access to a cartridge have changed: | ||
162 | * zftape now also takes the file access mode into account | ||
163 | * zftape no longer allows writing in the middle of the recorded | ||
164 | media. The tape has to be positioned at BOT or EOD for write | ||
165 | access. | ||
166 | |||
167 | - MTBSF has changed. It used to position at the beginning of the | ||
168 | previous file when called with count 1. This was different from the | ||
169 | expected behavior for other Un*x tape drivers (i.e. SCSI). MTBSF | ||
170 | with count 1 should merely position at the beginning of the current | ||
171 | volume. Fixed. As a result, `tar --verify' now produces the desired | ||
172 | result: it verifies the last written volume, not the pre-last | ||
173 | written volume. | ||
174 | |||
175 | - The compression map has vanished --> no need for `mt erase' any | ||
176 | more. Fast seeking in a compressed volume is still be possible, but | ||
177 | takes slightly longer. As a side effect, you may experience an | ||
178 | additional volume showing up in front of all others for old | ||
179 | cartridges. This is the tape volume that holds the compression map. | ||
180 | |||
181 | - The compression support for zftape has been moved to a separate | ||
182 | module `zft-compressor'. DON'T forget to load it before trying to | ||
183 | read back compressed volumes. The stock `zftape.o' module probes for | ||
184 | the module `zft-compressor' using the kerneld message channel; you | ||
185 | have to install `zft-compressor.o' in a place where modprobe can | ||
186 | find it if you want to use this. | ||
187 | |||
188 | - New experimental feature that tries to get the broken down GMT time | ||
189 | from user space via a kernel daemon message channel. You need to | ||
190 | compile and start the `kdtime' daemon contained in the contrib | ||
191 | directory to use it. Needed (?) for time stamps in the header | ||
192 | segments and the volume table. | ||
193 | |||
194 | - variable block size mode via MTSETBLK 0 | ||
195 | |||
196 | - keep modules locked in memory after the block size has been changed | ||
197 | |||
198 | sftape specific: | ||
199 | ---------------- | ||
200 | |||
201 | - end of tape handling should be fixed, i.e. multi volume archives | ||
202 | written with `afio' can be read back now. | ||
203 | |||
204 | |||
205 | ===== Release notes for ftape-3.02a, 09/01/97 ===== | ||
206 | |||
207 | No big news: | ||
208 | - call zft_init() resp. sft_init() when compiling the entire stuff | ||
209 | into the kernel image. | ||
210 | - fix bug in ftape-setup.c when NO_TRACE_AT_ALL was defined. | ||
211 | - fix bug in sftape-eof.c/zftape-eof.c for old kernels (1.2.*) | ||
212 | - add support for new module interface for recent kernels | ||
213 | |||
214 | ===== Release notes for ftape-3.02, 16/12/96 ===== | ||
215 | - Fixed the `FDC unlock command failed' bug in fdc-io.c. When the FIFO | ||
216 | was already locked when ftape was loaded, ftape failed to unlock it. | ||
217 | - Fixed compilation of `contrib/gnumt'. It now finds `mtio.h' even if | ||
218 | ftape is NOT included into the kernel source tree. | ||
219 | - fc-10.c: include <asm/io.h> for inb() and outb(). | ||
220 | - ftape/sftape/zftape: all global variable now have either a `ftape_', | ||
221 | a `ft_', `sft_', `zft_' or `qic_' prefix to prevent name clashes | ||
222 | with other parts of the kernel when including ftape into the kernel | ||
223 | source tree. | ||
224 | - Kerneld support has changed. `ftape' now searches for a module | ||
225 | `ftape-frontend' when none of the frontend (`sftape' or `zftape') is | ||
226 | loaded. Please refer to the `Installation/Loading ftape' section of | ||
227 | the TeXinfo manual. | ||
228 | - Add load resp. boot-time configuration of ftape. There are now | ||
229 | variables ft_fdc_base, ft_fdc_dma and ft_fdc_irq corresponding to | ||
230 | the former FDC_BASE etc. compile time definitions. One can also use | ||
231 | the kernel command line parameters to configure the driver if it is | ||
232 | compiled into the kernel. Also, the FC-10/FC-20 support is load-time | ||
233 | configurable now as well as the MACH-II hack (ft_probe_fc10, | ||
234 | resp. ft_mach2). Please refer to the section `Installation/Configure | ||
235 | ftape' of the TeXinfo manual. | ||
236 | - I removed the MODVERSIONS option from `Makefile.module'. Let me alone | ||
237 | with ftape and MODVERSIONS unless you include the ftape sources into | ||
238 | the kernel source tree. | ||
239 | - new vendors in `vendors.h': | ||
240 | * HP Colorado T3000 | ||
241 | * ComByte DoublePlay (including a bug fix for their broken | ||
242 | formatting software, thanks to whraven@njackn.com) | ||
243 | * Iomega DITTO 2GIG. NOTE: this drive cannot work with ftape because | ||
244 | the logical data layout of the cartridges used by this drive does | ||
245 | NOT conform to the QIC standards, it is a special Iomega specific | ||
246 | format. I've sent mail to Iomega but didn't receive an answer | ||
247 | yet. If you want this drive to be supported by ftape, ask Iomega | ||
248 | to give me information about it. | ||
249 | - zftape: | ||
250 | * re-introduced the MTIOC_ZFTAPE_GETBLKSZ ioctl for compatibility | ||
251 | with zftape 1.06a and earlier. Please don't use it when writing | ||
252 | new software, use the MTIOCVOLINFO ioctl instead. | ||
253 | * Major overhaul of the code that updates the header segments. Never | ||
254 | change the tape label unless erasing the tape. Thus we almost | ||
255 | never need to write the header segments, unless we would modify | ||
256 | the bad sector map which isn't done yet. Updating of volume table | ||
257 | and compression map more secure now although it takes a bit | ||
258 | longer. | ||
259 | * Fixed bug when aborting a write operation with a signal: zftape | ||
260 | now finishes the current volume (i.e. writes an eof marker) at the | ||
261 | current position. It didn't before which led to somehow *strange* | ||
262 | behavior in this cases. | ||
263 | * Keep module locked in memory when using it with the non-rewinding | ||
264 | devices and the tape is not logical at BOT. Needed for kerneld | ||
265 | support. | ||
266 | - sftape: | ||
267 | * Keep module locked in memory when using it with the non-rewinding | ||
268 | devices and the tape is not logical at BOT. Needed for kerneld | ||
269 | support. | ||
270 | |||
271 | ===== Release notes for ftape-3.01, 14/11/96 ===== | ||
272 | |||
273 | - Fixed silly bugs in ftape-3.00: | ||
274 | * MAKEDEV.ftape: major device number must be 27, not 23 | ||
275 | * sftape/sftape-read.c: sftape_read_header_segments() called | ||
276 | itself recursively instead of calling ftape_read_header_segment() | ||
277 | * zftape/qic-vtbl.h: conversion of ftape's file marks to zftape's | ||
278 | internal volume table was broken. | ||
279 | * patches/2.x.x/linux-2.0.21.dif: my RCS (resp. CVS) system replaced | ||
280 | the `$Revison:' etc. macros in the `ftape.h' concerning part of the | ||
281 | patch :-( Fixed. | ||
282 | * info/ftape.info: Fixed misspellings (`cp' <-> `cp -r' etc.) | ||
283 | * when ftape/sftape or ftape/zftape was compiled into the kernel the | ||
284 | variable ftape_status was declared twice. Fixed. | ||
285 | * removed reference to undeclared variable kernel_version when not | ||
286 | compiling as module | ||
287 | * fixed a bug introduced by the use of bit-fields for some flags | ||
288 | (i.e. write_protected, no_cartridge, formatted) | ||
289 | * flag `header_read' is now reset correctly to zero when tape is | ||
290 | removed. | ||
291 | - fixed a bug in sftape/sftape-eof.c that was already in the original | ||
292 | ftape code. MTFSF/BSF was not handled correctly when positioned | ||
293 | right before the file mark (think of tar) | ||
294 | - Changed TRACE macros (following a suggestion of Marcin Dalecki) to use | ||
295 | the predefined __FUNCTION__ macro of GCC. Spares about 4k of code. | ||
296 | - added new vendor id for Iomega DITTO 2GIG | ||
297 | - fixed a bug already present in zftape-1.06 when aborting a write | ||
298 | with a signal: we now finish the current volume at that | ||
299 | position. Header segments remain NOT up to date until an explicit call | ||
300 | to MTREW or MTOFFL is done. | ||
301 | |||
302 | ===== Release notes for ftape-3.00, 14/10/96 ===== | ||
303 | |||
304 | - Merged ftape with zftape. There are three modules now: | ||
305 | ftape for the hardware support, sftape for the implementation of the | ||
306 | original ftape eof mark stuff and zftape that implements zftape's way | ||
307 | of handling things (compression, volume table, tape blocks of | ||
308 | constant length) | ||
309 | - Documentation in TeXinfo format in the `info' subdirectory. | ||
310 | - New ioctls for zftape. See zftape/zftape.h | ||
311 | - Dummy formatting ioctl for ftape. See ftape.h | ||
312 | - Kernel patch files for the 2.*.* series to include ftape-3.00 in the | ||
313 | kernel source tree. These includes a kernel compatible Config.in | ||
314 | script and fairly large online information for the kernel configure | ||
315 | script. | ||
316 | - Support for compiling with Linux-1.2.13. | ||
317 | - Modified GNU mt from their cpio package that can handle the new | ||
318 | ioctls. | ||
319 | - ftape/sftape/zftape is kerneld save now! | ||
320 | |||
321 | Notes on sftape: | ||
322 | - sftape implements the eof handling code of the original ftape. If | ||
323 | you like to stick with the original ftape stuff, you have to use | ||
324 | this module, not zftape. | ||
325 | - sftape is kerneld save, unlike the original ftape. | ||
326 | - we keep the entire header segment now in memory, so no need to read | ||
327 | it before updating the header segments. Additional memory | ||
328 | consumption: 256 bytes. | ||
329 | |||
330 | Notes for zftape: | ||
331 | - zftape has support for tapes with format code 6 now, which use a | ||
332 | slightly different volume table format compared with other floppy | ||
333 | tapes. | ||
334 | - new ioctls for zftape. Have a look at zftape/zftape.h | ||
335 | - The internal volume table representation has changed for zftape. Old | ||
336 | cartridges are converted automatically. | ||
337 | - zftape no longer uses compression map segments, which have vanished | ||
338 | from the QIC specs, but creates volume table entry that reserves | ||
339 | enough space for the compression map. | ||
340 | - zftape is kerneld save now. | ||
341 | - we keep the entire header segment now in memory, so no need to read | ||
342 | it before updating the header segments. Additional memory | ||
343 | consumption: 256 bytes. | ||
344 | |||
345 | Notes for contrib/gnumt: | ||
346 | - modified mt from the GNU cpio package that supports all the new | ||
347 | ioctls of zftape. | ||
348 | Notes for contrib/swapout: | ||
349 | - This contains the swapout.c program that was written by Kai | ||
350 | Harrekilde-Pederson. I simply added a Makefile. | ||
351 | |||
352 | ===== Release notes for ftape-2.10, 14/10/96 ===== | ||
353 | |||
354 | The ftape maintainer has changed. | ||
355 | Kai Harrekilde-Petersen <khp@dolphinics.no> | ||
356 | has resigned from maintaining ftape, and I, | ||
357 | Claus-Justus Heine <claus@momo.math.rwth-aachen.de>, | ||
358 | have taken over. | ||
359 | |||
360 | - Added support for tapes with `format code 6', i.e. QIC-3020 tapes | ||
361 | with more than 2^16 segments. | ||
362 | - merged changes made by Bas Laarhoven with ftape-2.09. Refer | ||
363 | to his release notes below. I've included them into this | ||
364 | file unchanged for your reference. | ||
365 | - disabled call stack back trace for now. This new feature | ||
366 | introduced by the interim release 2.0.x still seems to | ||
367 | be buggy. | ||
368 | - Tried to minimize differences between the ftape version | ||
369 | to be included into the kernel source tree and the standalone | ||
370 | module version. | ||
371 | - Reintroduced support for Linux-1.2.13. Please refer to the | ||
372 | Install-guide. | ||
373 | |||
374 | ===== Release notes for ftape-2.09, 16/06/96 ===== | ||
375 | |||
376 | There aren't any really big news in this release, mostly just that I | ||
377 | (the maintainer) have changed my email address (due to a new job). My | ||
378 | new address is <khp@dolphinics.no> | ||
379 | |||
380 | - The CLK_48MHZ and FDC_82078SL options has gone (all 2Mbps cards seem | ||
381 | to use a 48MHz oscillator anyway and I haven't heard of an 'SL | ||
382 | chip out there). | ||
383 | - The S82078B has been `downgraded' to i82077AA compability. | ||
384 | - TESTING option revived. Right now, it'll enable the (seriously broken) | ||
385 | 2Mbps code. If you enable it, you'll experience a tape drive that's | ||
386 | *really* out to lunch! | ||
387 | - Some (bold) changes in the init code. Please notify me if they | ||
388 | break things for you. | ||
389 | |||
390 | ===== Release notes for ftape-2.08, 14/03/96 ===== | ||
391 | |||
392 | If you correct a problem with ftape, please send your patch to | ||
393 | khp@dolphinics.no too. | ||
394 | |||
395 | - Updated to reflect that NR_MEM_LISTS is gone in 1.3.74 | ||
396 | - Teac 700 added to list of known drives. | ||
397 | - The registered device name is now "ft" rather than "ftape". | ||
398 | |||
399 | ===== Release notes for ftape-2.07a, 14/03/96 ===== | ||
400 | |||
401 | Bugfixes by Marcin Dalecki <dalecki@namu03.gwdg.de>: | ||
402 | - In the last release it just compiled against 1.3.70; | ||
403 | now the params to request_irq() and free_irq are() are fixed, so it also | ||
404 | works in 1.3.73 :-) | ||
405 | - Support for modules is now correct for newer kernels. | ||
406 | |||
407 | ===== Release notes for ftape-2.07, 04/03/96 ===== | ||
408 | |||
409 | |||
410 | - ftape updated to compile against 1.3.70. | ||
411 | - Iomega 700 and Wangtek 3200 recognised. | ||
412 | |||
413 | |||
414 | ===== Release notes for ftape-2.06b, 13/02/96 ===== | ||
415 | |||
416 | Another simple bugfix version. | ||
417 | |||
418 | - Jumbo 700 recognised. | ||
419 | - Typo in vendors.h fixed. | ||
420 | |||
421 | |||
422 | ===== Release notes for ftape-2.06a, 10/02/96 ===== | ||
423 | |||
424 | This release is a simple bugfix version. | ||
425 | |||
426 | - Linux/SMP: ftape *should* work. | ||
427 | - FC-10/20: Only accepts IRQs 3-7, or 9. If IRQ 9, properly tell the card | ||
428 | to use IRQ 2. Thanks to Greg Crider (gcrider@iclnet.org) for finding and | ||
429 | locating this bug and testing the patch. | ||
430 | - Insight drive recognised correctly again. | ||
431 | - Motor-on wakeup version of the Iomega 250 drive added | ||
432 | |||
433 | |||
434 | ===== Release notes for ftape-2.06, 28/01/96 ===== | ||
435 | |||
436 | Special thanks go to Neal Friedman and Steven Sorbom for their | ||
437 | help in producing and testing this release. | ||
438 | |||
439 | I have continued to clean up the code, with an eye towards inclusion | ||
440 | of ftape in Linus' official kernel (In fact, as I type this, I am | ||
441 | running on a kernel with ftape support statically linked). I have | ||
442 | test-compiled ftape against my 1.2.13 tree without problems. | ||
443 | Hopefully, everything should be OK for the v1.2.x people. | ||
444 | |||
445 | WARNING! Alan Cox has mailed me that ftape does *NOT* work with | ||
446 | Linux/SMP. If you try to run ftape under Linux/SMP, it will cause a | ||
447 | kernel deadlock (which is worse than a panic). | ||
448 | |||
449 | - QIC-3020/TR-3: 1Mbps support works. Neal is capable of reading and | ||
450 | writing data to a tape. ftape will automatically detect the type of | ||
451 | tape (e.g. TR-3 vs QIC-80) and move the fdc in and out of | ||
452 | "perpendicular mode" as necessary. | ||
453 | - 2Mbps support is disabled by default, since it is not fully | ||
454 | debugged. If you are adventurous, remove -DFDC_82078SL in the | ||
455 | Makefile and see what happens :-) | ||
456 | - fdc detection: silly bugs removed (Only 2Mbps fdcs were affected) | ||
457 | and added detection of the National Semiconductors PC8744 fdc chip | ||
458 | (used in the PC873xx "super-IO" chips). | ||
459 | - Removed warning about incompatible types when compiling with Linux | ||
460 | 1.2.x. | ||
461 | - README.PCI updated with info about the DELL Dimension XPS P90. | ||
462 | - Connor TST3200R added to detected drives. | ||
463 | - `swapout' utility added to distribution. It will dirty 5Meg of | ||
464 | memory, trying to swap out other programs. Just say `make swapout' | ||
465 | to build it. ftape will do this automatically Real Soon Now (ie: | ||
466 | when I have found out which kernel memory alloc function to call). | ||
467 | |||
468 | |||
469 | ===== Release notes for ftape-2.05, 08/01/96 ===== | ||
470 | |||
471 | - For v1.2.x Kernels, you must apply the patch linux-1.2/ksyms.patch to | ||
472 | the kernel and rebuild it (it adds the __get_dma_pages symbol to | ||
473 | ksyms.c). | ||
474 | - Included new asm-i386/io.h file from v1.3.x kernel series, to enable | ||
475 | gcc v.2.7.[12] to compile v1.2.x kernels (linux-1.2/io.h). | ||
476 | - Module versions: If you wish to compile ftape as a versioned module, | ||
477 | you must first compile your kernel with CONFIG_MODVERSIONS=y. | ||
478 | Otherwise, you will get complaints that <linux/modversions.h> does not | ||
479 | exist (if that happens, a `touch modversions.h' will help you out). | ||
480 | - CLK_48MHZ: new define in the Makefile (default: non-zero). If you have | ||
481 | a tape controller card that uses the i82078(-1) chip, but cannot get | ||
482 | it to work with ftape, try set it to 0 (and please report this). | ||
483 | - QIC-3010/3020: Complete support is still missing, but will hopefully | ||
484 | come soon. Steven Sorbom has kindly provided me with hints about | ||
485 | this. Writing of QIC-3020 tapes definitely does NOT work (do not try | ||
486 | it! - the drive will not be in "perpendicular mode" and this will ruin | ||
487 | the formatting info on the tape). | ||
488 | - ftape_num_buffers is out of fashion: use NR_BUFFERS instead (and | ||
489 | recompile if you want to change it :-). | ||
490 | |||
491 | |||
492 | ===== Release notes for ftape-2.04, 01/01/96 ===== | ||
493 | |||
494 | This version by Kai Harrekilde-Petersen <khp@dolphinics.no> | ||
495 | |||
496 | - ALERT! Support for Kernels earlier then v1.1.85 is about to go away. | ||
497 | I intend to clean up some of the code (getting rid of an annoyingly | ||
498 | large numbers of #ifdef mostly), which means that support for | ||
499 | pre-1.1.85 kernels must go as well. | ||
500 | - NR_FTAPE_BUFFERS is gone; You can instead select the number of dma | ||
501 | buffers by saying `insmod ftape.o ftape_num_buffer=<n>' instead. | ||
502 | - Configure script gone. ftape will now automagically determine your | ||
503 | kernel version by /usr/include/linux/version.h instead. | ||
504 | - CONFIG_MODVERSIONS now work. All combinations of versioned / | ||
505 | unversioned kernel and ftape module works (at least with my 1.3.52 | ||
506 | kernel). | ||
507 | - If you have problems with inserting ftape into an old (1.2.x) | ||
508 | kernel (e.g. insmod says "1.2.8 does not match 1.2.8), recompile | ||
509 | your modules utilities with your new compiler. | ||
510 | - Reveal TB1400 drive added to vendors.h | ||
511 | - Support for the i82078-1 (2Mbps) chip is coming along. The | ||
512 | biggest problem is that I don't have such a card, which makes | ||
513 | testing / debugging somewhat problematic. The second biggest | ||
514 | problem is that I do not have the QIC-3010/3020 standards either. | ||
515 | Status right now is that the chip is detected, and it should be | ||
516 | possible to put it into 2Mbps mode. However, I do not know what | ||
517 | "extras" are needed to complete the support. Although putting the | ||
518 | i82078 into 1Mbps mode ought to work out of the box, it doesn't | ||
519 | (right now, ftape complains about id am errors). | ||
520 | |||
521 | |||
522 | ===== Release notes for ftape-2.04beta5, 29/12/95 ===== | ||
523 | |||
524 | Bas offline linux-tape | ||
525 | ---------------------- | ||
526 | For reasons only known to the majordomo mail list processor, Bas was | ||
527 | kicked off the linux-tape list sometime during the summer. Being | ||
528 | overworked at his for-pay job, he didn't notice it much. Instead I | ||
529 | (Kai, khp@dolphinics.no) has worked on ftape to produce the 2.04(beta) | ||
530 | version. | ||
531 | |||
532 | zftape | ||
533 | ------ | ||
534 | Note that there exists a much improved version of ftape, written by | ||
535 | Claus-Justus Heine <claus@willi.math.rwth-aachen.de> which is named | ||
536 | zftape, which conforms to the QIC-80 specs on how to mark backups, and | ||
537 | is capable of doing automatic compression. However, zftape makes | ||
538 | substantial changes to ftape, and I (Kai) have therefore declined to | ||
539 | integrate zftape into ftape. Hopefully, this will happen soon. | ||
540 | |||
541 | CONFIG_QIC117 removed from the kernel | ||
542 | ------------------------------------- | ||
543 | The biggest change of all is that ftape now will allocate its dma | ||
544 | buffers when it is inserted. The means that the CONFIG_QIC117 option | ||
545 | has disappeared from the Linux kernel as of v1.3.34. If you have an | ||
546 | earlier kernel, simply answer 'no' to the question will do the trick | ||
547 | (if you get complains about __get_free_pages() missing, contact the | ||
548 | linux-tape mailing list). | ||
549 | |||
550 | Note that ftape-2.04beta will work equally well on kernels with and | ||
551 | without `ftape support'. The only catch is, that you will waste | ||
552 | around 96-128Kb of precious DMA'able memory on a box that has ftape | ||
553 | support compiled in. | ||
554 | |||
555 | Now for the real changes: | ||
556 | |||
557 | - FC-20 can now use DMA channels 1, 2, and 3. Thanks to Daniel | ||
558 | Cohen, catman@wpi.edu. | ||
559 | - ftape no longer requires a (gigantic) 96Kb buffer to be statically | ||
560 | allocated by the kernel. | ||
561 | - Added new Iomega drive (8882) to vendors.h | ||
562 | - -fno-strength-reduce added to Makefile, since GCC is broken. | ||
563 | - i82078-1 (2Mbps) FDC support started. | ||
564 | |||
565 | |||
566 | ===== Release notes for ftape-2.03b, 27/05/95 ===== | ||
567 | |||
568 | - Prevented verify_area to return error if called with zero length. | ||
569 | - Fixed a bug in flush_buffers that caused too much padding to be | ||
570 | written when a final segment had bad sectors. | ||
571 | - Increased maximum fast-seek overshoot value from 5 to 10 segments. | ||
572 | - Breaking loop after 5 retries when positioning fails. | ||
573 | - Fixed wrong calculation of tape length for QIC-3010 and QIC-3020 | ||
574 | tapes (densities were swapped). | ||
575 | - Fixed wrong calculation of overshoot on seek_forward: Wrong sign | ||
576 | of error. | ||
577 | - Suppress (false) error message due to new tape loaded. | ||
578 | - Added two new CMS drives (11c3 and 11c5) to vendors.h. | ||
579 | |||
580 | |||
581 | ===== Release notes for ftape-2.03a, 09/05/95 ===== | ||
582 | |||
583 | - Fixed display of old error (even if already cleared) in ftape_open. | ||
584 | - Improved tape length detection, ioctls would fail for 425 ft tapes. | ||
585 | Until the tape length is calculated with data from the header | ||
586 | segment, we'll use worst-case values. | ||
587 | - Clear eof_mark after rewinding ioctls. | ||
588 | - Fixed wrong version message (2.03 had 2.02g id). | ||
589 | - Fixed bug that caused the fdc to be reset very frequently. | ||
590 | This shouldn't affect normal operation but the timing of the | ||
591 | report routines has changed again and that may cause problems. | ||
592 | We'll just have to find out.... | ||
593 | - Implemented correct write precompensation setting for QIC-3010/3020. | ||
594 | - Cleaned up fdc_interrupt_wait routine. Hope it still works :-) | ||
595 | - Finally removed (already disabled) special eof mark handling for | ||
596 | gnu tar. | ||
597 | - Changed order of get_dma_residue and disable_dma in fdc-isr.c | ||
598 | because the current order would fail on at least one system. | ||
599 | We're back to the original order again, hope (and expect) this | ||
600 | doesn't break any other system. | ||
601 | |||
602 | |||
603 | ===== Release notes for ftape-2.03, 07/05/95 ===== | ||
604 | |||
605 | (Changes refer to the first ftape-2.02 release) | ||
606 | |||
607 | Support for wide and extended length tapes | ||
608 | ------------------------------------------ | ||
609 | The Conner TSM 420 and 850 drives are reported to be working. | ||
610 | I haven't received any reports about other brands; the TSM 420 | ||
611 | and 850 seem to be the most widely used wide drives. | ||
612 | Extended length tapes (425 ft) with normal QIC-80 drives | ||
613 | are operating too (At least I've had no reports stating otherwise). | ||
614 | _Not_ yet completely supported (although they may work) are | ||
615 | QIC-3020 drives and 2 Mbps floppy disk controllers won't work at | ||
616 | the highest speed. | ||
617 | If someone is kind enough to send me one of these, I'll include | ||
618 | support for it too ;-) | ||
619 | |||
620 | Easier configuration | ||
621 | -------------------- | ||
622 | Problems due to wrong settings in the Makefile are prevented | ||
623 | by using a configuration script that sets the necessary (kernel | ||
624 | version dependent) compile time options. | ||
625 | This kernel version is now determined from the sources found | ||
626 | at /usr/src/linux, or if not found, the old way using | ||
627 | /proc/version. | ||
628 | Versioned modules will be used automatically when supported | ||
629 | by- and configured in- the kernel. | ||
630 | Note that the current modules code (1.1.87) is still broken | ||
631 | and _needs_ the fix included in the insmod directory. | ||
632 | Please don't send me any more Oops reports caused by insmod :-( | ||
633 | |||
634 | Reduced module size | ||
635 | ------------------- | ||
636 | The standard module size is much reduced and some compile time | ||
637 | options can even reduce it further. (I don't recommend this | ||
638 | for normal use but it can be handy for rescue diskettes) | ||
639 | |||
640 | Option: Approx. module size: | ||
641 | |||
642 | <standard> 150 Kb | ||
643 | NO_TRACE 125 Kb | ||
644 | NO_TRACE_AT_ALL 67 Kb | ||
645 | |||
646 | |||
647 | Much improved driver interruption | ||
648 | --------------------------------- | ||
649 | Most possible loops have been broken and signal detection | ||
650 | has been improved. | ||
651 | In most cases the driver can be aborted by ^C (SIGINT) and | ||
652 | SIGKILL (kill -9) will generate be a sure kill. | ||
653 | (Note that aborting a tape operation may damage the last | ||
654 | data written to tape) | ||
655 | |||
656 | Improved error recovery | ||
657 | ----------------------- | ||
658 | Ftape now returns an error (ENODATA) to the application if | ||
659 | a segment proves to be unrecoverable and then skips the | ||
660 | bad segment. | ||
661 | This causes most applications to continue to work (tar | ||
662 | and afio) loosing only a small amount (up to 29 Kb) of data. | ||
663 | Retried read operations will now be done slightly off-track | ||
664 | to improve the chance of success. Serious head off-track | ||
665 | errors will be detected. | ||
666 | |||
667 | FC-10 and FC-20 controllers | ||
668 | --------------------------- | ||
669 | Ftape now supports both the old CMS FC-10 and the newer FC-20 | ||
670 | controllers. | ||
671 | Because the operation of these cards is still undocumented, | ||
672 | thus far they will only work with the default settings (See | ||
673 | Makefile). Any feed-back on how to use them with other settings | ||
674 | will be welcome ! | ||
675 | Compilation will fail if one changes the settings to illegal | ||
676 | values. | ||
677 | |||
678 | Kernels and compilers | ||
679 | --------------------- | ||
680 | Ftape is currently being developed using the 2.5.8 compiler. | ||
681 | The older 2.4.5 probably works too (Set option in Makefile!). | ||
682 | I have no experience with any later compilers nor Elf support. | ||
683 | Any information on this is welcome. | ||
684 | The latest kernel I have tested ftape with is 1.2.6. | ||
685 | |||
686 | Compression | ||
687 | ----------- | ||
688 | An impressive collection of changes for ftape including | ||
689 | on-the-fly compression is still lying on my desk. | ||
690 | If 2.03 proves to be reliable I might start integrating these | ||
691 | but as usual, I'm short in time :-( | ||
692 | |||
693 | Formatting | ||
694 | ---------- | ||
695 | There is still no way to format tapes under Linux. As far as | ||
696 | I know all attempts to write such a program have died now. | ||
697 | Since formatted tapes are rather common now, I think all we | ||
698 | need is a utility that writes a worst case pattern and verifies | ||
699 | that with the drive put in verify mode, reducing margins. | ||
700 | Any takers ? | ||
701 | |||
702 | Furthermore | ||
703 | ----------- | ||
704 | Cleaned up messages. | ||
705 | Prepared to support multiple tape drives on one fdc. | ||
706 | Thanks to all the people who sent bug reports and helped me | ||
707 | improve the driver. Without trying to be complete I'll mention | ||
708 | Gary Anderson (without his accurate reports and unreliable | ||
709 | hardware there wouldn't be a 2.03), Stefan Kneifel (FC-20), | ||
710 | Robert Broughton (FC-20, you were almost there ;-), Bjorn | ||
711 | Ekwall (for the versioned modules and buggy insmod ;-), Peter | ||
712 | Fox, Christopher Oliver, Ralph Whittaker and not the least | ||
713 | Linus Torvalds (for Linux and keeping me busy because of | ||
714 | changes to the kernel ;-) | ||
715 | Thanks to anyone I forgot, for the bug reports, the ftape | ||
716 | bashing and the mental support... | ||
717 | |||
718 | |||
719 | That's it for now. Have Fun, | ||
720 | |||
721 | Bas. | ||
722 | |||
723 | |||
724 | ===== Release notes for ftape-2.02g, 06/05/95 ===== | ||
725 | |||
726 | - Added extra test to break read-id loop with signal. | ||
727 | - Changed rewind code to handle negative overshoot for drives | ||
728 | that take very long to start or stop. | ||
729 | - Let use of get/set i/o-regions depend on kernel version. | ||
730 | - Changed code to use a more general test for conditional | ||
731 | compilations depending on kernel version. | ||
732 | - Improved micro-step functionality to go off-track only | ||
733 | while reading (id & data). | ||
734 | - Added failure on tape-not-referenced bit in ftape_command. | ||
735 | - Added FOREVER option to read-wait routine. | ||
736 | - Changed read-id to use shorter timeout causing smaller | ||
737 | rewinds on timeout. | ||
738 | - Made kernel-interface functions static. | ||
739 | |||
740 | |||
741 | ===== Release notes for ftape-2.02f, 03/05/95 ===== | ||
742 | |||
743 | - Added support for dual tape drives on my system, extended Configure | ||
744 | script to detect host 'dodo'. | ||
745 | - Log media defect in history if ecc failed and no data was returned. | ||
746 | - Fixed Configure script that was failing for kernel versions with | ||
747 | double digit version or revision numbers. | ||
748 | |||
749 | |||
750 | ===== Release notes for ftape-2.02e, 01/05/95 ===== | ||
751 | |||
752 | - Fixed reposition loop at logical eot (failing read_id). | ||
753 | - Fixed 34 segment offset when rewinding. | ||
754 | - Added fast seek capability for more than 255 segments. | ||
755 | - Fixed wrong busy result from ftape_command causing reverse | ||
756 | seek to fail. | ||
757 | - Added breakout from infinite rewind loop (if something fails). | ||
758 | |||
759 | |||
760 | ===== Release notes for ftape-2.02d, 30/04/95 ===== | ||
761 | |||
762 | - Improved abortion on signals: Interrupt will make a graceful | ||
763 | exit, Kill will be less nice and should be used if everything | ||
764 | else fails. | ||
765 | - Included check for tape-head off track. | ||
766 | - Implemented exit from tape-start loop. | ||
767 | - Added kernel io-port registration. | ||
768 | - Implemented skip of failing segment (ENODATA) on ecc failure. | ||
769 | This allows afio and tar to continue when the tape is damaged. | ||
770 | - Made distinction between drive names with different codes. | ||
771 | |||
772 | |||
773 | ===== Release notes for ftape-2.02c, 22/04/95 ===== | ||
774 | |||
775 | - Fixed too tight command queueing after tape stop/pause command | ||
776 | issued from within interrupt service routine (Showed as timeout | ||
777 | on Acknowledge errors during retries on some systems) | ||
778 | - Tried to fix timeouts when using 425 ft tape because the extended | ||
779 | length doesn't seem to be detected by the hardware. | ||
780 | We now use the format code from the header segment so adjust the | ||
781 | timing after reading the header segment. | ||
782 | - Fixed some messages stating 'unexpected something...' being not | ||
783 | unexpected anymore. | ||
784 | - Started preparations for merge of dynamic buffer allocation and | ||
785 | compression code. | ||
786 | - Changed some debug messages to include relevant segment information | ||
787 | at level 4. | ||
788 | - Included early bail-out when drive offline, preventing a lot of | ||
789 | false messages. | ||
790 | - Moved ftape_parameter_xxx() offsets into function instead of in calls. | ||
791 | - Removed 'weird, drive busy but no data' error when caused by | ||
792 | an error during a read-id. | ||
793 | - Improved 'timeout on acknowledge' diagnostics. | ||
794 | - Moved MODULE option into Configure. | ||
795 | - Reduced code size when no tracing at all was set (Claus Heine). | ||
796 | - No longer log error code 0 (no error) as an error. | ||
797 | |||
798 | |||
799 | ===== Release notes for ftape-2.02b, 09/04/95 ===== | ||
800 | |||
801 | - Relaxed timing for status operation and displaying | ||
802 | abnormal results. Hopefully this shows what's going | ||
803 | wrong with the Conner TSM850R drives. | ||
804 | - Created script for configuration, using version number | ||
805 | of kernel source if available, otherwise /proc/version. | ||
806 | - Fixed conditionals in kernel-interface.c. | ||
807 | - Removed unavoidable TRACE output. | ||
808 | |||
809 | |||
810 | ===== Release notes for ftape-2.02a, 01/04/95 ===== | ||
811 | |||
812 | - Implemented `new-style' (versioned) modules support for new | ||
813 | kernels. | ||
814 | - Reduced size of module by moving static data to bss. | ||
815 | - Now using version number of kernel source instead of running | ||
816 | kernel for kernel versions >= 1.1.82 | ||
817 | - Added feedback on drive speeds to vendor information. | ||
818 | - Included fixed insmod sources to distribution (Let's hope | ||
819 | the modules distribution get fixed soon :-/). | ||
820 | |||
821 | Note that I haven't yet implemented any of the code extension I | ||
822 | received. I hope to find some time to do this soon. | ||
823 | |||
824 | |||
825 | ===== Release notes for ftape-2.02, 15/01/95 ===== | ||
826 | |||
827 | |||
828 | - Fixed failing repositioning when overshoot was incremented. | ||
829 | - Fixed rate selection: Because of a deficiency in the QIC-117 | ||
830 | specification one cannot distinguish between a not implemented | ||
831 | and a failing command. Therefor we now try to find out if the | ||
832 | drive does support this command before usage. | ||
833 | - Fixed error retry using wrong offset in fdc-isr. | ||
834 | - Improved retry code to retry only once on a single no-data | ||
835 | error in a segment. | ||
836 | - Validate sector number extracted from eof mark because an | ||
837 | invalid file mark (due to ???) could cause kernel panic. | ||
838 | - Split ftape-io.c into ftape-io.c and ftape-ctl.c files. | ||
839 | - Corrected too high media error count after writing to | ||
840 | a bad tape. | ||
841 | - Added #include <asm/segment.h> again because old kernel versions | ||
842 | need it. | ||
843 | - Fixed fdc not being disabled when open failed because no tape | ||
844 | drive was found. | ||
845 | - Fixed problem with soft error in sector 32 (shift operator with | ||
846 | shiftcount 32 is not defined). | ||
847 | |||
848 | |||
849 | ===== Release notes for ftape-2.01, 08/01/95 ===== | ||
850 | |||
851 | |||
852 | - Removed TESTING setting from distributed Makefile. | ||
853 | - Fixed `mt asf' failure: Rewind was deferred to close which | ||
854 | overruled the fsf ioctl. | ||
855 | - Prevented non-interruptible commands being interrupted. | ||
856 | - Added missing timeout.pause setting. | ||
857 | - Maximum tape speed read from drive type information table. | ||
858 | If the information is not in the table (0) the drive will | ||
859 | determine the speed itself and put a message in the logfile. | ||
860 | This information should then be added to the table in the | ||
861 | vendors.h file (and reported to me). | ||
862 | - Added call to ftape_init_drive after soft reset for those | ||
863 | (antique) drives that don't do an implicit seek_load_point | ||
864 | after a reset or power up. | ||
865 | - Don't try to set data rate if reset failed. | ||
866 | - Prevent update of seek variables when starting from the | ||
867 | beginning or the end of the tape. | ||
868 | - Fixed wrong adjustment of overshoot in seek_forward(). | ||
869 | - Added sync to Makefile (again). | ||
870 | - Added code to diagnose timer problems (calibr.c). | ||
871 | - Replaced time differences by timediff calls. | ||
872 | - Removed reference to do_floppy from object for recent kernels. | ||
873 | - Fixed wrong display of 'failing dma controller' message. | ||
874 | - Removed various no longer used #include statements. | ||
875 | - Added max. tape speed value to vendor-struct. | ||
876 | - Changed ftape-command to check pre-conditions and wait | ||
877 | if needed. | ||
878 | - Further updated qic117.h to rev G. | ||
879 | - Combined command name table and restrictions table to one. | ||
880 | Extended this table with some new fields. | ||
881 | - Increased timeout on Ack timer value and included code to | ||
882 | report out of spec behaviour. | ||
883 | - Increased rewind timeout margin to calculated + 20%. | ||
884 | - Improved data rate selection so it won't fail on some | ||
885 | older (pre standard) drives. | ||
886 | - Changed initialisation code so drive will be rewound if the | ||
887 | driver is reloaded and the tape is not at bot. | ||
888 | - Moved some of the flush operations from close to the ioctls. | ||
889 | - Added exit code value to failing verify area message. | ||
890 | - Loop until tape halted in smart-stop. | ||
891 | - Fast seek handled specially if located at bot or eot. | ||
892 | - Being more conservative on overshoot value. | ||
893 | |||
894 | |||
895 | ===== Release notes for ftape-2.00, 31/12/94 ===== | ||
896 | |||
897 | The Install-guide is completely rewritten and now also includes | ||
898 | some information on how to use the driver. If you're either new | ||
899 | to ftape or new to Unix tape devices make sure to read it ! | ||
900 | |||
901 | If you own a pci system and experience problems with the | ||
902 | ftape driver make sure to read the README.PCI file. It contains | ||
903 | some hints on how to fix your hardware. | ||
904 | |||
905 | For anybody who hasn't noticed: The version number of the | ||
906 | driver has been incremented (The latest released version has | ||
907 | been version 1.14d). | ||
908 | This has been done for two major reasons: | ||
909 | |||
910 | o A new (better) error recovery scheme is implemented. | ||
911 | o Support for new drive types has been added. | ||
912 | |||
913 | All these improvements/changes will probably include a couple | ||
914 | of new (and old?) bugs. If you encounter any problems that you think | ||
915 | I'm not yet aware of, feel free to send a report to <bas@vimec.nl>. | ||
916 | I recommend keeping a version of ftape-1.14d available, just | ||
917 | in case ;-) | ||
918 | |||
919 | This version should work with all kernel versions from 1.0.9 up | ||
920 | to 1.1.72 (and probably earlier and later versions too). | ||
921 | |||
922 | |||
923 | Major new features: | ||
924 | |||
925 | - Better handling of tapes with defects: When a sector repeatedly | ||
926 | (SOFT_RETRIES in ftape.h) cannot be written to or read from it is | ||
927 | marked as an hard error and gets skipped. | ||
928 | The error correction code can handle up to three of these hard | ||
929 | errors provided there are no other errors in that segment (32 Kb). | ||
930 | |||
931 | - Allows writing to tapes with defects (although the risk of loosing | ||
932 | data increases !) | ||
933 | Look for the media-defects entry printed with the statistics when | ||
934 | the tape is closed. A non-zero value here shows a bad tape. | ||
935 | [the actual count is wrong (too high), this is a known bug]. | ||
936 | |||
937 | - Use of backup header segment if first one is failing. | ||
938 | |||
939 | - Support for extended length tapes with QIC-80: both 425 and 1100 ft. | ||
940 | 0.25 inch tapes are now recognized and handled. | ||
941 | |||
942 | - Support for new QIC-80 drives with 8 mm `wide' tapes (e.g. Conner | ||
943 | TSM 420). | ||
944 | |||
945 | - Support for new QIC-3010 and QIC-3020 drives (experimental) with | ||
946 | both 0.25 inch and 8 mm tapes. | ||
947 | |||
948 | Some minor features were added, a couple of small bugs were fixed and | ||
949 | probably some new ones introduced ;-). | ||
950 | |||
951 | [lseek() didn't make it into this version] | ||
952 | |||
953 | Have fun, | ||
954 | |||
955 | Bas. | ||
956 | ---- | ||
957 | LocalWords: ftape MCONFIG mt VFS zftape resp sftape proc subdir MTIOCVOLINFO | ||
958 | LocalWords: MTIOCGETSIZE BOT EOD MTBSF zft kerneld modprobe kdtime contrib TR | ||
959 | LocalWords: MTSETBLK afio uninstall texi www EIO QIC init sft eof aka dma GB | ||
960 | LocalWords: SIGKILL MTIOCFTCMD mmap Iomega FDC fdc io gnumt mtio fc asm inb | ||
961 | LocalWords: outb ft qic frontend TeXinfo irq mach MODVERSIONS CONFIG html dvi | ||
962 | LocalWords: usr doc SMP Mb Dunno FIXME vtblc perl listtape volinfo fsf MTWEOF | ||
963 | LocalWords: amanda degaussed ComByte DoublePlay whraven njackn com MTIOC vtbl | ||
964 | LocalWords: GETBLKSZ MAKEDEV zftape's linux dif CVS Revison cp MTREW MTOFFL | ||
965 | LocalWords: MTFSF BSF Marcin Dalecki GCC Config cpio swapout Kai Harrekilde | ||
966 | LocalWords: Pederson khp dolphinics Justus claus momo rwth aachen Laarhoven | ||
diff --git a/drivers/char/ftape/compressor/Makefile b/drivers/char/ftape/compressor/Makefile deleted file mode 100644 index 1fbd6c4019db..000000000000 --- a/drivers/char/ftape/compressor/Makefile +++ /dev/null | |||
@@ -1,31 +0,0 @@ | |||
1 | # | ||
2 | # Copyright (C) 1997 Claus-Justus Heine. | ||
3 | # | ||
4 | # This program is free software; you can redistribute it and/or modify | ||
5 | # it under the terms of the GNU General Public License as published by | ||
6 | # the Free Software Foundation; either version 2, or (at your option) | ||
7 | # any later version. | ||
8 | # | ||
9 | # This program is distributed in the hope that it will be useful, | ||
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | # GNU General Public License for more details. | ||
13 | # | ||
14 | # You should have received a copy of the GNU General Public License | ||
15 | # along with this program; see the file COPYING. If not, write to | ||
16 | # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | # | ||
18 | # $Source: /homes/cvs/ftape-stacked/ftape/compressor/Makefile,v $ | ||
19 | # $Revision: 1.1 $ | ||
20 | # $Date: 1997/10/05 19:12:28 $ | ||
21 | # | ||
22 | # Makefile for the optional compressor for th zftape VFS | ||
23 | # interface to the QIC-40/80/3010/3020 floppy-tape driver for | ||
24 | # Linux. | ||
25 | # | ||
26 | |||
27 | obj-$(CONFIG_ZFT_COMPRESSOR) += zft-compressor.o | ||
28 | |||
29 | zft-compressor-objs := zftape-compress.o lzrw3.o | ||
30 | |||
31 | CFLAGS_lzrw3.o := -O6 -funroll-all-loops | ||
diff --git a/drivers/char/ftape/compressor/lzrw3.c b/drivers/char/ftape/compressor/lzrw3.c deleted file mode 100644 index a032a0ee2a99..000000000000 --- a/drivers/char/ftape/compressor/lzrw3.c +++ /dev/null | |||
@@ -1,743 +0,0 @@ | |||
1 | /* | ||
2 | * $Source: /homes/cvs/ftape-stacked/ftape/compressor/lzrw3.c,v $ | ||
3 | * $Revision: 1.1 $ | ||
4 | * $Date: 1997/10/05 19:12:29 $ | ||
5 | * | ||
6 | * Implementation of Ross Williams lzrw3 algorithm. Adaption for zftape. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include "../compressor/lzrw3.h" /* Defines single exported function "compress". */ | ||
11 | |||
12 | /******************************************************************************/ | ||
13 | /* */ | ||
14 | /* LZRW3.C */ | ||
15 | /* */ | ||
16 | /******************************************************************************/ | ||
17 | /* */ | ||
18 | /* Author : Ross Williams. */ | ||
19 | /* Date : 30-Jun-1991. */ | ||
20 | /* Release : 1. */ | ||
21 | /* */ | ||
22 | /******************************************************************************/ | ||
23 | /* */ | ||
24 | /* This file contains an implementation of the LZRW3 data compression */ | ||
25 | /* algorithm in C. */ | ||
26 | /* */ | ||
27 | /* The algorithm is a general purpose compression algorithm that runs fast */ | ||
28 | /* and gives reasonable compression. The algorithm is a member of the Lempel */ | ||
29 | /* Ziv family of algorithms and bases its compression on the presence in the */ | ||
30 | /* data of repeated substrings. */ | ||
31 | /* */ | ||
32 | /* This algorithm is unpatented and the code is public domain. As the */ | ||
33 | /* algorithm is based on the LZ77 class of algorithms, it is unlikely to be */ | ||
34 | /* the subject of a patent challenge. */ | ||
35 | /* */ | ||
36 | /* Unlike the LZRW1 and LZRW1-A algorithms, the LZRW3 algorithm is */ | ||
37 | /* deterministic and is guaranteed to yield the same compressed */ | ||
38 | /* representation for a given file each time it is run. */ | ||
39 | /* */ | ||
40 | /* The LZRW3 algorithm was originally designed and implemented */ | ||
41 | /* by Ross Williams on 31-Dec-1990. */ | ||
42 | /* */ | ||
43 | /* Here are the results of applying this code, compiled under THINK C 4.0 */ | ||
44 | /* and running on a Mac-SE (8MHz 68000), to the standard calgary corpus. */ | ||
45 | /* */ | ||
46 | /* +----------------------------------------------------------------+ */ | ||
47 | /* | DATA COMPRESSION TEST | */ | ||
48 | /* | ===================== | */ | ||
49 | /* | Time of run : Sun 30-Jun-1991 09:31PM | */ | ||
50 | /* | Timing accuracy : One part in 100 | */ | ||
51 | /* | Context length : 262144 bytes (= 256.0000K) | */ | ||
52 | /* | Test suite : Calgary Corpus Suite | */ | ||
53 | /* | Files in suite : 14 | */ | ||
54 | /* | Algorithm : LZRW3 | */ | ||
55 | /* | Note: All averages are calculated from the un-rounded values. | */ | ||
56 | /* +----------------------------------------------------------------+ */ | ||
57 | /* | File Name Length CxB ComLen %Remn Bits Com K/s Dec K/s | */ | ||
58 | /* | ---------- ------ --- ------ ----- ---- ------- ------- | */ | ||
59 | /* | rpus:Bib.D 111261 1 55033 49.5 3.96 19.46 32.27 | */ | ||
60 | /* | us:Book1.D 768771 3 467962 60.9 4.87 17.03 31.07 | */ | ||
61 | /* | us:Book2.D 610856 3 317102 51.9 4.15 19.39 34.15 | */ | ||
62 | /* | rpus:Geo.D 102400 1 82424 80.5 6.44 11.65 18.18 | */ | ||
63 | /* | pus:News.D 377109 2 205670 54.5 4.36 17.14 27.47 | */ | ||
64 | /* | pus:Obj1.D 21504 1 13027 60.6 4.85 13.40 18.95 | */ | ||
65 | /* | pus:Obj2.D 246814 1 116286 47.1 3.77 19.31 30.10 | */ | ||
66 | /* | s:Paper1.D 53161 1 27522 51.8 4.14 18.60 31.15 | */ | ||
67 | /* | s:Paper2.D 82199 1 45160 54.9 4.40 18.45 32.84 | */ | ||
68 | /* | rpus:Pic.D 513216 2 122388 23.8 1.91 35.29 51.05 | */ | ||
69 | /* | us:Progc.D 39611 1 19669 49.7 3.97 18.87 30.64 | */ | ||
70 | /* | us:Progl.D 71646 1 28247 39.4 3.15 24.34 40.66 | */ | ||
71 | /* | us:Progp.D 49379 1 19377 39.2 3.14 23.91 39.23 | */ | ||
72 | /* | us:Trans.D 93695 1 33481 35.7 2.86 25.48 40.37 | */ | ||
73 | /* +----------------------------------------------------------------+ */ | ||
74 | /* | Average 224401 1 110953 50.0 4.00 20.17 32.72 | */ | ||
75 | /* +----------------------------------------------------------------+ */ | ||
76 | /* */ | ||
77 | /******************************************************************************/ | ||
78 | |||
79 | /******************************************************************************/ | ||
80 | |||
81 | /* The following structure is returned by the "compress" function below when */ | ||
82 | /* the user asks the function to return identifying information. */ | ||
83 | /* The most important field in the record is the working memory field which */ | ||
84 | /* tells the calling program how much working memory should be passed to */ | ||
85 | /* "compress" when it is called to perform a compression or decompression. */ | ||
86 | /* LZRW3 uses the same amount of memory during compression and decompression. */ | ||
87 | /* For more information on this structure see "compress.h". */ | ||
88 | |||
89 | #define U(X) ((ULONG) X) | ||
90 | #define SIZE_P_BYTE (U(sizeof(UBYTE *))) | ||
91 | #define SIZE_WORD (U(sizeof(UWORD ))) | ||
92 | #define ALIGNMENT_FUDGE (U(16)) | ||
93 | #define MEM_REQ ( U(4096)*(SIZE_P_BYTE) + ALIGNMENT_FUDGE ) | ||
94 | |||
95 | static struct compress_identity identity = | ||
96 | { | ||
97 | U(0x032DDEA8), /* Algorithm identification number. */ | ||
98 | MEM_REQ, /* Working memory (bytes) required. */ | ||
99 | "LZRW3", /* Name of algorithm. */ | ||
100 | "1.0", /* Version number of algorithm. */ | ||
101 | "31-Dec-1990", /* Date of algorithm. */ | ||
102 | "Public Domain", /* Copyright notice. */ | ||
103 | "Ross N. Williams", /* Author of algorithm. */ | ||
104 | "Renaissance Software", /* Affiliation of author. */ | ||
105 | "Public Domain" /* Vendor of algorithm. */ | ||
106 | }; | ||
107 | |||
108 | LOCAL void compress_compress (UBYTE *,UBYTE *,ULONG,UBYTE *, LONG *); | ||
109 | LOCAL void compress_decompress(UBYTE *,UBYTE *,LONG, UBYTE *, ULONG *); | ||
110 | |||
111 | /******************************************************************************/ | ||
112 | |||
113 | /* This function is the only function exported by this module. */ | ||
114 | /* Depending on its first parameter, the function can be requested to */ | ||
115 | /* compress a block of memory, decompress a block of memory, or to identify */ | ||
116 | /* itself. For more information, see the specification file "compress.h". */ | ||
117 | |||
118 | EXPORT void lzrw3_compress( | ||
119 | UWORD action, /* Action to be performed. */ | ||
120 | UBYTE *wrk_mem, /* Address of working memory we can use.*/ | ||
121 | UBYTE *src_adr, /* Address of input data. */ | ||
122 | LONG src_len, /* Length of input data. */ | ||
123 | UBYTE *dst_adr, /* Address to put output data. */ | ||
124 | void *p_dst_len /* Address of longword for length of output data.*/ | ||
125 | ) | ||
126 | { | ||
127 | switch (action) | ||
128 | { | ||
129 | case COMPRESS_ACTION_IDENTITY: | ||
130 | *((struct compress_identity **)p_dst_len)= &identity; | ||
131 | break; | ||
132 | case COMPRESS_ACTION_COMPRESS: | ||
133 | compress_compress(wrk_mem,src_adr,src_len,dst_adr,(LONG *)p_dst_len); | ||
134 | break; | ||
135 | case COMPRESS_ACTION_DECOMPRESS: | ||
136 | compress_decompress(wrk_mem,src_adr,src_len,dst_adr,(LONG *)p_dst_len); | ||
137 | break; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | /******************************************************************************/ | ||
142 | /* */ | ||
143 | /* BRIEF DESCRIPTION OF THE LZRW3 ALGORITHM */ | ||
144 | /* ======================================== */ | ||
145 | /* The LZRW3 algorithm is identical to the LZRW1-A algorithm except that */ | ||
146 | /* instead of transmitting history offsets, it transmits hash table indexes. */ | ||
147 | /* In order to decode the indexes, the decompressor must maintain an */ | ||
148 | /* identical hash table. Copy items are straightforward:when the decompressor */ | ||
149 | /* receives a copy item, it simply looks up the hash table to translate the */ | ||
150 | /* index into a pointer into the data already decompressed. To update the */ | ||
151 | /* hash table, it replaces the same table entry with a pointer to the start */ | ||
152 | /* of the newly decoded phrase. The tricky part is with literal items, for at */ | ||
153 | /* the time that the decompressor receives a literal item the decompressor */ | ||
154 | /* does not have the three bytes in the Ziv (that the compressor has) to */ | ||
155 | /* perform the three-byte hash. To solve this problem, in LZRW3, both the */ | ||
156 | /* compressor and decompressor are wired up so that they "buffer" these */ | ||
157 | /* literals and update their hash tables only when three bytes are available. */ | ||
158 | /* This makes the maximum buffering 2 bytes. */ | ||
159 | /* */ | ||
160 | /* Replacement of offsets by hash table indexes yields a few percent extra */ | ||
161 | /* compression at the cost of some speed. LZRW3 is slower than LZRW1, LZRW1-A */ | ||
162 | /* and LZRW2, but yields better compression. */ | ||
163 | /* */ | ||
164 | /* Extra compression could be obtained by using a hash table of depth two. */ | ||
165 | /* However, increasing the depth above one incurs a significant decrease in */ | ||
166 | /* compression speed which was not considered worthwhile. Another reason for */ | ||
167 | /* keeping the depth down to one was to allow easy comparison with the */ | ||
168 | /* LZRW1-A and LZRW2 algorithms so as to demonstrate the exact effect of the */ | ||
169 | /* use of direct hash indexes. */ | ||
170 | /* */ | ||
171 | /* +---+ */ | ||
172 | /* |___|4095 */ | ||
173 | /* |___| */ | ||
174 | /* +---------------------*_|<---+ /----+---\ */ | ||
175 | /* | |___| +---|Hash | */ | ||
176 | /* | |___| |Function| */ | ||
177 | /* | |___| \--------/ */ | ||
178 | /* | |___|0 ^ */ | ||
179 | /* | +---+ | */ | ||
180 | /* | Hash +-----+ */ | ||
181 | /* | Table | */ | ||
182 | /* | --- */ | ||
183 | /* v ^^^ */ | ||
184 | /* +-------------------------------------|----------------+ */ | ||
185 | /* |||||||||||||||||||||||||||||||||||||||||||||||||||||||| */ | ||
186 | /* +-------------------------------------|----------------+ */ | ||
187 | /* | |1......18| | */ | ||
188 | /* |<------- Lempel=History ------------>|<--Ziv-->| | */ | ||
189 | /* | (=bytes already processed) |<-Still to go-->| */ | ||
190 | /* |<-------------------- INPUT BLOCK ------------------->| */ | ||
191 | /* */ | ||
192 | /* The diagram above for LZRW3 looks almost identical to the diagram for */ | ||
193 | /* LZRW1. The difference is that in LZRW3, the compressor transmits hash */ | ||
194 | /* table indices instead of Lempel offsets. For this to work, the */ | ||
195 | /* decompressor must maintain a hash table as well as the compressor and both */ | ||
196 | /* compressor and decompressor must "buffer" literals, as the decompressor */ | ||
197 | /* cannot hash phrases commencing with a literal until another two bytes have */ | ||
198 | /* arrived. */ | ||
199 | /* */ | ||
200 | /* LZRW3 Algorithm Execution Summary */ | ||
201 | /* --------------------------------- */ | ||
202 | /* 1. Hash the first three bytes of the Ziv to yield a hash table index h. */ | ||
203 | /* 2. Look up the hash table yielding history pointer p. */ | ||
204 | /* 3. Match where p points with the Ziv. If there is a match of three or */ | ||
205 | /* more bytes, code those bytes (in the Ziv) as a copy item, otherwise */ | ||
206 | /* code the next byte in the Ziv as a literal item. */ | ||
207 | /* 4. Update the hash table as possible subject to the constraint that only */ | ||
208 | /* phrases commencing three bytes back from the Ziv can be hashed and */ | ||
209 | /* entered into the hash table. (This enables the decompressor to keep */ | ||
210 | /* pace). See the description and code for more details. */ | ||
211 | /* */ | ||
212 | /******************************************************************************/ | ||
213 | /* */ | ||
214 | /* DEFINITION OF COMPRESSED FILE FORMAT */ | ||
215 | /* ==================================== */ | ||
216 | /* * A compressed file consists of a COPY FLAG followed by a REMAINDER. */ | ||
217 | /* * The copy flag CF uses up four bytes with the first byte being the */ | ||
218 | /* least significant. */ | ||
219 | /* * If CF=1, then the compressed file represents the remainder of the file */ | ||
220 | /* exactly. Otherwise CF=0 and the remainder of the file consists of zero */ | ||
221 | /* or more GROUPS, each of which represents one or more bytes. */ | ||
222 | /* * Each group consists of two bytes of CONTROL information followed by */ | ||
223 | /* sixteen ITEMs except for the last group which can contain from one */ | ||
224 | /* to sixteen items. */ | ||
225 | /* * An item can be either a LITERAL item or a COPY item. */ | ||
226 | /* * Each item corresponds to a bit in the control bytes. */ | ||
227 | /* * The first control byte corresponds to the first 8 items in the group */ | ||
228 | /* with bit 0 corresponding to the first item in the group and bit 7 to */ | ||
229 | /* the eighth item in the group. */ | ||
230 | /* * The second control byte corresponds to the second 8 items in the group */ | ||
231 | /* with bit 0 corresponding to the ninth item in the group and bit 7 to */ | ||
232 | /* the sixteenth item in the group. */ | ||
233 | /* * A zero bit in a control word means that the corresponding item is a */ | ||
234 | /* literal item. A one bit corresponds to a copy item. */ | ||
235 | /* * A literal item consists of a single byte which represents itself. */ | ||
236 | /* * A copy item consists of two bytes that represent from 3 to 18 bytes. */ | ||
237 | /* * The first byte in a copy item will be denoted C1. */ | ||
238 | /* * The second byte in a copy item will be denoted C2. */ | ||
239 | /* * Bits will be selected using square brackets. */ | ||
240 | /* For example: C1[0..3] is the low nibble of the first control byte. */ | ||
241 | /* of copy item C1. */ | ||
242 | /* * The LENGTH of a copy item is defined to be C1[0..3]+3 which is a number */ | ||
243 | /* in the range [3,18]. */ | ||
244 | /* * The INDEX of a copy item is defined to be C1[4..7]*256+C2[0..8] which */ | ||
245 | /* is a number in the range [0,4095]. */ | ||
246 | /* * A copy item represents the sequence of bytes */ | ||
247 | /* text[POS-OFFSET..POS-OFFSET+LENGTH-1] where */ | ||
248 | /* text is the entire text of the uncompressed string. */ | ||
249 | /* POS is the index in the text of the character following the */ | ||
250 | /* string represented by all the items preceeding the item */ | ||
251 | /* being defined. */ | ||
252 | /* OFFSET is obtained from INDEX by looking up the hash table. */ | ||
253 | /* */ | ||
254 | /******************************************************************************/ | ||
255 | |||
256 | /* The following #define defines the length of the copy flag that appears at */ | ||
257 | /* the start of the compressed file. The value of four bytes was chosen */ | ||
258 | /* because the fast_copy routine on my Macintosh runs faster if the source */ | ||
259 | /* and destination blocks are relatively longword aligned. */ | ||
260 | /* The actual flag data appears in the first byte. The rest are zeroed so as */ | ||
261 | /* to normalize the compressed representation (i.e. not non-deterministic). */ | ||
262 | #define FLAG_BYTES 4 | ||
263 | |||
264 | /* The following #defines define the meaning of the values of the copy */ | ||
265 | /* flag at the start of the compressed file. */ | ||
266 | #define FLAG_COMPRESS 0 /* Signals that output was result of compression. */ | ||
267 | #define FLAG_COPY 1 /* Signals that output was simply copied over. */ | ||
268 | |||
269 | /* The 68000 microprocessor (on which this algorithm was originally developed */ | ||
270 | /* is fussy about non-aligned arrays of words. To avoid these problems the */ | ||
271 | /* following macro can be used to "waste" from 0 to 3 bytes so as to align */ | ||
272 | /* the argument pointer. */ | ||
273 | #define ULONG_ALIGN_UP(X) ((((ULONG)X)+sizeof(ULONG)-1)&~(sizeof(ULONG)-1)) | ||
274 | |||
275 | |||
276 | /* The following constant defines the maximum length of an uncompressed item. */ | ||
277 | /* This definition must not be changed; its value is hardwired into the code. */ | ||
278 | /* The longest number of bytes that can be spanned by a single item is 18 */ | ||
279 | /* for the longest copy item. */ | ||
280 | #define MAX_RAW_ITEM (18) | ||
281 | |||
282 | /* The following constant defines the maximum length of an uncompressed group.*/ | ||
283 | /* This definition must not be changed; its value is hardwired into the code. */ | ||
284 | /* A group contains at most 16 items which explains this definition. */ | ||
285 | #define MAX_RAW_GROUP (16*MAX_RAW_ITEM) | ||
286 | |||
287 | /* The following constant defines the maximum length of a compressed group. */ | ||
288 | /* This definition must not be changed; its value is hardwired into the code. */ | ||
289 | /* A compressed group consists of two control bytes followed by up to 16 */ | ||
290 | /* compressed items each of which can have a maximum length of two bytes. */ | ||
291 | #define MAX_CMP_GROUP (2+16*2) | ||
292 | |||
293 | /* The following constant defines the number of entries in the hash table. */ | ||
294 | /* This definition must not be changed; its value is hardwired into the code. */ | ||
295 | #define HASH_TABLE_LENGTH (4096) | ||
296 | |||
297 | /* LZRW3, unlike LZRW1(-A), must initialize its hash table so as to enable */ | ||
298 | /* the compressor and decompressor to stay in step maintaining identical hash */ | ||
299 | /* tables. In an early version of the algorithm, the tables were simply */ | ||
300 | /* initialized to zero and a check for zero was included just before the */ | ||
301 | /* matching code. However, this test costs time. A better solution is to */ | ||
302 | /* initialize all the entries in the hash table to point to a constant */ | ||
303 | /* string. The decompressor does the same. This solution requires no extra */ | ||
304 | /* test. The contents of the string do not matter so long as the string is */ | ||
305 | /* the same for the compressor and decompressor and contains at least */ | ||
306 | /* MAX_RAW_ITEM bytes. I chose consecutive decimal digits because they do not */ | ||
307 | /* have white space problems (e.g. there is no chance that the compiler will */ | ||
308 | /* replace more than one space by a TAB) and because they make the length of */ | ||
309 | /* the string obvious by inspection. */ | ||
310 | #define START_STRING_18 ((UBYTE *) "123456789012345678") | ||
311 | |||
312 | /* In this algorithm, hash values have to be calculated at more than one */ | ||
313 | /* point. The following macro neatens the code up for this. */ | ||
314 | #define HASH(PTR) \ | ||
315 | (((40543*(((*(PTR))<<8)^((*((PTR)+1))<<4)^(*((PTR)+2))))>>4) & 0xFFF) | ||
316 | |||
317 | /******************************************************************************/ | ||
318 | |||
319 | /* Input : Hand over the required amount of working memory in p_wrk_mem. */ | ||
320 | /* Input : Specify input block using p_src_first and src_len. */ | ||
321 | /* Input : Point p_dst_first to the start of the output zone (OZ). */ | ||
322 | /* Input : Point p_dst_len to a ULONG to receive the output length. */ | ||
323 | /* Input : Input block and output zone must not overlap. */ | ||
324 | /* Output : Length of output block written to *p_dst_len. */ | ||
325 | /* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. May */ | ||
326 | /* Output : write in OZ=Mem[p_dst_first..p_dst_first+src_len+MAX_CMP_GROUP-1].*/ | ||
327 | /* Output : Upon completion guaranteed *p_dst_len<=src_len+FLAG_BYTES. */ | ||
328 | LOCAL void compress_compress(UBYTE *p_wrk_mem, | ||
329 | UBYTE *p_src_first, ULONG src_len, | ||
330 | UBYTE *p_dst_first, LONG *p_dst_len) | ||
331 | { | ||
332 | /* p_src and p_dst step through the source and destination blocks. */ | ||
333 | register UBYTE *p_src = p_src_first; | ||
334 | register UBYTE *p_dst = p_dst_first; | ||
335 | |||
336 | /* The following variables are never modified and are used in the */ | ||
337 | /* calculations that determine when the main loop terminates. */ | ||
338 | UBYTE *p_src_post = p_src_first+src_len; | ||
339 | UBYTE *p_dst_post = p_dst_first+src_len; | ||
340 | UBYTE *p_src_max1 = p_src_first+src_len-MAX_RAW_ITEM; | ||
341 | UBYTE *p_src_max16 = p_src_first+src_len-MAX_RAW_ITEM*16; | ||
342 | |||
343 | /* The variables 'p_control' and 'control' are used to buffer control bits. */ | ||
344 | /* Before each group is processed, the next two bytes of the output block */ | ||
345 | /* are set aside for the control word for the group about to be processed. */ | ||
346 | /* 'p_control' is set to point to the first byte of that word. Meanwhile, */ | ||
347 | /* 'control' buffers the control bits being generated during the processing */ | ||
348 | /* of the group. Instead of having a counter to keep track of how many items */ | ||
349 | /* have been processed (=the number of bits in the control word), at the */ | ||
350 | /* start of each group, the top word of 'control' is filled with 1 bits. */ | ||
351 | /* As 'control' is shifted for each item, the 1 bits in the top word are */ | ||
352 | /* absorbed or destroyed. When they all run out (i.e. when the top word is */ | ||
353 | /* all zero bits, we know that we are at the end of a group. */ | ||
354 | # define TOPWORD 0xFFFF0000 | ||
355 | UBYTE *p_control; | ||
356 | register ULONG control=TOPWORD; | ||
357 | |||
358 | /* THe variable 'hash' always points to the first element of the hash table. */ | ||
359 | UBYTE **hash= (UBYTE **) ULONG_ALIGN_UP(p_wrk_mem); | ||
360 | |||
361 | /* The following two variables represent the literal buffer. p_h1 points to */ | ||
362 | /* the hash table entry corresponding to the youngest literal. p_h2 points */ | ||
363 | /* to the hash table entry corresponding to the second youngest literal. */ | ||
364 | /* Note: p_h1=0=>p_h2=0 because zero values denote absence of a pending */ | ||
365 | /* literal. The variables are initialized to zero meaning an empty "buffer". */ | ||
366 | UBYTE **p_h1=NULL; | ||
367 | UBYTE **p_h2=NULL; | ||
368 | |||
369 | /* To start, we write the flag bytes. Being optimistic, we set the flag to */ | ||
370 | /* FLAG_COMPRESS. The remaining flag bytes are zeroed so as to keep the */ | ||
371 | /* algorithm deterministic. */ | ||
372 | *p_dst++=FLAG_COMPRESS; | ||
373 | {UWORD i; for (i=2;i<=FLAG_BYTES;i++) *p_dst++=0;} | ||
374 | |||
375 | /* Reserve the first word of output as the control word for the first group. */ | ||
376 | /* Note: This is undone at the end if the input block is empty. */ | ||
377 | p_control=p_dst; p_dst+=2; | ||
378 | |||
379 | /* Initialize all elements of the hash table to point to a constant string. */ | ||
380 | /* Use of an unrolled loop speeds this up considerably. */ | ||
381 | {UWORD i; UBYTE **p_h=hash; | ||
382 | # define ZH *p_h++=START_STRING_18 | ||
383 | for (i=0;i<256;i++) /* 256=HASH_TABLE_LENGTH/16. */ | ||
384 | {ZH;ZH;ZH;ZH; | ||
385 | ZH;ZH;ZH;ZH; | ||
386 | ZH;ZH;ZH;ZH; | ||
387 | ZH;ZH;ZH;ZH;} | ||
388 | } | ||
389 | |||
390 | /* The main loop processes either 1 or 16 items per iteration. As its */ | ||
391 | /* termination logic is complicated, I have opted for an infinite loop */ | ||
392 | /* structure containing 'break' and 'goto' statements. */ | ||
393 | while (TRUE) | ||
394 | {/* Begin main processing loop. */ | ||
395 | |||
396 | /* Note: All the variables here except unroll should be defined within */ | ||
397 | /* the inner loop. Unfortunately the loop hasn't got a block. */ | ||
398 | register UBYTE *p; /* Scans through targ phrase during matching. */ | ||
399 | register UBYTE *p_ziv= NULL ; /* Points to first byte of current Ziv. */ | ||
400 | register UWORD unroll; /* Loop counter for unrolled inner loop. */ | ||
401 | register UWORD index; /* Index of current hash table entry. */ | ||
402 | register UBYTE **p_h0 = NULL ; /* Pointer to current hash table entry. */ | ||
403 | |||
404 | /* Test for overrun and jump to overrun code if necessary. */ | ||
405 | if (p_dst>p_dst_post) | ||
406 | goto overrun; | ||
407 | |||
408 | /* The following cascade of if statements efficiently catches and deals */ | ||
409 | /* with varying degrees of closeness to the end of the input block. */ | ||
410 | /* When we get very close to the end, we stop updating the table and */ | ||
411 | /* code the remaining bytes as literals. This makes the code simpler. */ | ||
412 | unroll=16; | ||
413 | if (p_src>p_src_max16) | ||
414 | { | ||
415 | unroll=1; | ||
416 | if (p_src>p_src_max1) | ||
417 | { | ||
418 | if (p_src==p_src_post) | ||
419 | break; | ||
420 | else | ||
421 | goto literal; | ||
422 | } | ||
423 | } | ||
424 | |||
425 | /* This inner unrolled loop processes 'unroll' (whose value is either 1 */ | ||
426 | /* or 16) items. I have chosen to implement this loop with labels and */ | ||
427 | /* gotos to heighten the ease with which the loop may be implemented with */ | ||
428 | /* a single decrement and branch instruction in assembly language and */ | ||
429 | /* also because the labels act as highly readable place markers. */ | ||
430 | /* (Also because we jump into the loop for endgame literals (see above)). */ | ||
431 | |||
432 | begin_unrolled_loop: | ||
433 | |||
434 | /* To process the next phrase, we hash the next three bytes and use */ | ||
435 | /* the resultant hash table index to look up the hash table. A pointer */ | ||
436 | /* to the entry is stored in p_h0 so as to avoid an array lookup. The */ | ||
437 | /* hash table entry *p_h0 is looked up yielding a pointer p to a */ | ||
438 | /* potential match of the Ziv in the history. */ | ||
439 | index=HASH(p_src); | ||
440 | p_h0=&hash[index]; | ||
441 | p=*p_h0; | ||
442 | |||
443 | /* Having looked up the candidate position, we are in a position to */ | ||
444 | /* attempt a match. The match loop has been unrolled using the PS */ | ||
445 | /* macro so that failure within the first three bytes automatically */ | ||
446 | /* results in the literal branch being taken. The coding is simple. */ | ||
447 | /* p_ziv saves p_src so we can let p_src wander. */ | ||
448 | # define PS *p++!=*p_src++ | ||
449 | p_ziv=p_src; | ||
450 | if (PS || PS || PS) | ||
451 | { | ||
452 | /* Literal. */ | ||
453 | |||
454 | /* Code the literal byte as itself and a zero control bit. */ | ||
455 | p_src=p_ziv; literal: *p_dst++=*p_src++; control&=0xFFFEFFFF; | ||
456 | |||
457 | /* We have just coded a literal. If we had two pending ones, that */ | ||
458 | /* makes three and we can update the hash table. */ | ||
459 | if (p_h2!=0) | ||
460 | {*p_h2=p_ziv-2;} | ||
461 | |||
462 | /* In any case, rotate the hash table pointers for next time. */ | ||
463 | p_h2=p_h1; p_h1=p_h0; | ||
464 | |||
465 | } | ||
466 | else | ||
467 | { | ||
468 | /* Copy */ | ||
469 | |||
470 | /* Match up to 15 remaining bytes using an unrolled loop and code. */ | ||
471 | #if 0 | ||
472 | PS || PS || PS || PS || PS || PS || PS || PS || | ||
473 | PS || PS || PS || PS || PS || PS || PS || p_src++; | ||
474 | #else | ||
475 | if ( | ||
476 | !( PS || PS || PS || PS || PS || PS || PS || PS || | ||
477 | PS || PS || PS || PS || PS || PS || PS ) | ||
478 | ) p_src++; | ||
479 | #endif | ||
480 | *p_dst++=((index&0xF00)>>4)|(--p_src-p_ziv-3); | ||
481 | *p_dst++=index&0xFF; | ||
482 | |||
483 | /* As we have just coded three bytes, we are now in a position to */ | ||
484 | /* update the hash table with the literal bytes that were pending */ | ||
485 | /* upon the arrival of extra context bytes. */ | ||
486 | if (p_h1!=0) | ||
487 | { | ||
488 | if (p_h2) | ||
489 | {*p_h2=p_ziv-2; p_h2=NULL;} | ||
490 | *p_h1=p_ziv-1; p_h1=NULL; | ||
491 | } | ||
492 | |||
493 | /* In any case, we can update the hash table based on the current */ | ||
494 | /* position as we just coded at least three bytes in a copy items. */ | ||
495 | *p_h0=p_ziv; | ||
496 | |||
497 | } | ||
498 | control>>=1; | ||
499 | |||
500 | /* This loop is all set up for a decrement and jump instruction! */ | ||
501 | #ifndef linux | ||
502 | ` end_unrolled_loop: if (--unroll) goto begin_unrolled_loop; | ||
503 | #else | ||
504 | /* end_unrolled_loop: */ if (--unroll) goto begin_unrolled_loop; | ||
505 | #endif | ||
506 | |||
507 | /* At this point it will nearly always be the end of a group in which */ | ||
508 | /* case, we have to do some control-word processing. However, near the */ | ||
509 | /* end of the input block, the inner unrolled loop is only executed once. */ | ||
510 | /* This necessitates the 'if' test. */ | ||
511 | if ((control&TOPWORD)==0) | ||
512 | { | ||
513 | /* Write the control word to the place we saved for it in the output. */ | ||
514 | *p_control++= control &0xFF; | ||
515 | *p_control = (control>>8) &0xFF; | ||
516 | |||
517 | /* Reserve the next word in the output block for the control word */ | ||
518 | /* for the group about to be processed. */ | ||
519 | p_control=p_dst; p_dst+=2; | ||
520 | |||
521 | /* Reset the control bits buffer. */ | ||
522 | control=TOPWORD; | ||
523 | } | ||
524 | |||
525 | } /* End main processing loop. */ | ||
526 | |||
527 | /* After the main processing loop has executed, all the input bytes have */ | ||
528 | /* been processed. However, the control word has still to be written to the */ | ||
529 | /* word reserved for it in the output at the start of the most recent group. */ | ||
530 | /* Before writing, the control word has to be shifted so that all the bits */ | ||
531 | /* are in the right place. The "empty" bit positions are filled with 1s */ | ||
532 | /* which partially fill the top word. */ | ||
533 | while(control&TOPWORD) control>>=1; | ||
534 | *p_control++= control &0xFF; | ||
535 | *p_control++=(control>>8) &0xFF; | ||
536 | |||
537 | /* If the last group contained no items, delete the control word too. */ | ||
538 | if (p_control==p_dst) p_dst-=2; | ||
539 | |||
540 | /* Write the length of the output block to the dst_len parameter and return. */ | ||
541 | *p_dst_len=p_dst-p_dst_first; | ||
542 | return; | ||
543 | |||
544 | /* Jump here as soon as an overrun is detected. An overrun is defined to */ | ||
545 | /* have occurred if p_dst>p_dst_first+src_len. That is, the moment the */ | ||
546 | /* length of the output written so far exceeds the length of the input block.*/ | ||
547 | /* The algorithm checks for overruns at least at the end of each group */ | ||
548 | /* which means that the maximum overrun is MAX_CMP_GROUP bytes. */ | ||
549 | /* Once an overrun occurs, the only thing to do is to set the copy flag and */ | ||
550 | /* copy the input over. */ | ||
551 | overrun: | ||
552 | #if 0 | ||
553 | *p_dst_first=FLAG_COPY; | ||
554 | fast_copy(p_src_first,p_dst_first+FLAG_BYTES,src_len); | ||
555 | *p_dst_len=src_len+FLAG_BYTES; | ||
556 | #else | ||
557 | fast_copy(p_src_first,p_dst_first,src_len); | ||
558 | *p_dst_len= -src_len; /* return a negative number to indicate uncompressed data */ | ||
559 | #endif | ||
560 | } | ||
561 | |||
562 | /******************************************************************************/ | ||
563 | |||
564 | /* Input : Hand over the required amount of working memory in p_wrk_mem. */ | ||
565 | /* Input : Specify input block using p_src_first and src_len. */ | ||
566 | /* Input : Point p_dst_first to the start of the output zone. */ | ||
567 | /* Input : Point p_dst_len to a ULONG to receive the output length. */ | ||
568 | /* Input : Input block and output zone must not overlap. User knows */ | ||
569 | /* Input : upperbound on output block length from earlier compression. */ | ||
570 | /* Input : In any case, maximum expansion possible is nine times. */ | ||
571 | /* Output : Length of output block written to *p_dst_len. */ | ||
572 | /* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */ | ||
573 | /* Output : Writes only in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */ | ||
574 | LOCAL void compress_decompress( UBYTE *p_wrk_mem, | ||
575 | UBYTE *p_src_first, LONG src_len, | ||
576 | UBYTE *p_dst_first, ULONG *p_dst_len) | ||
577 | { | ||
578 | /* Byte pointers p_src and p_dst scan through the input and output blocks. */ | ||
579 | register UBYTE *p_src = p_src_first+FLAG_BYTES; | ||
580 | register UBYTE *p_dst = p_dst_first; | ||
581 | /* we need to avoid a SEGV when trying to uncompress corrupt data */ | ||
582 | register UBYTE *p_dst_post = p_dst_first + *p_dst_len; | ||
583 | |||
584 | /* The following two variables are never modified and are used to control */ | ||
585 | /* the main loop. */ | ||
586 | UBYTE *p_src_post = p_src_first+src_len; | ||
587 | UBYTE *p_src_max16 = p_src_first+src_len-(MAX_CMP_GROUP-2); | ||
588 | |||
589 | /* The hash table is the only resident of the working memory. The hash table */ | ||
590 | /* contains HASH_TABLE_LENGTH=4096 pointers to positions in the history. To */ | ||
591 | /* keep Macintoshes happy, it is longword aligned. */ | ||
592 | UBYTE **hash = (UBYTE **) ULONG_ALIGN_UP(p_wrk_mem); | ||
593 | |||
594 | /* The variable 'control' is used to buffer the control bits which appear in */ | ||
595 | /* groups of 16 bits (control words) at the start of each compressed group. */ | ||
596 | /* When each group is read, bit 16 of the register is set to one. Whenever */ | ||
597 | /* a new bit is needed, the register is shifted right. When the value of the */ | ||
598 | /* register becomes 1, we know that we have reached the end of a group. */ | ||
599 | /* Initializing the register to 1 thus instructs the code to follow that it */ | ||
600 | /* should read a new control word immediately. */ | ||
601 | register ULONG control=1; | ||
602 | |||
603 | /* The value of 'literals' is always in the range 0..3. It is the number of */ | ||
604 | /* consecutive literal items just seen. We have to record this number so as */ | ||
605 | /* to know when to update the hash table. When literals gets to 3, there */ | ||
606 | /* have been three consecutive literals and we can update at the position of */ | ||
607 | /* the oldest of the three. */ | ||
608 | register UWORD literals=0; | ||
609 | |||
610 | /* Check the leading copy flag to see if the compressor chose to use a copy */ | ||
611 | /* operation instead of a compression operation. If a copy operation was */ | ||
612 | /* used, then all we need to do is copy the data over, set the output length */ | ||
613 | /* and return. */ | ||
614 | #if 0 | ||
615 | if (*p_src_first==FLAG_COPY) | ||
616 | { | ||
617 | fast_copy(p_src_first+FLAG_BYTES,p_dst_first,src_len-FLAG_BYTES); | ||
618 | *p_dst_len=src_len-FLAG_BYTES; | ||
619 | return; | ||
620 | } | ||
621 | #else | ||
622 | if ( src_len < 0 ) | ||
623 | { | ||
624 | fast_copy(p_src_first,p_dst_first,-src_len ); | ||
625 | *p_dst_len = (ULONG)-src_len; | ||
626 | return; | ||
627 | } | ||
628 | #endif | ||
629 | |||
630 | /* Initialize all elements of the hash table to point to a constant string. */ | ||
631 | /* Use of an unrolled loop speeds this up considerably. */ | ||
632 | {UWORD i; UBYTE **p_h=hash; | ||
633 | # define ZJ *p_h++=START_STRING_18 | ||
634 | for (i=0;i<256;i++) /* 256=HASH_TABLE_LENGTH/16. */ | ||
635 | {ZJ;ZJ;ZJ;ZJ; | ||
636 | ZJ;ZJ;ZJ;ZJ; | ||
637 | ZJ;ZJ;ZJ;ZJ; | ||
638 | ZJ;ZJ;ZJ;ZJ;} | ||
639 | } | ||
640 | |||
641 | /* The outer loop processes either 1 or 16 items per iteration depending on */ | ||
642 | /* how close p_src is to the end of the input block. */ | ||
643 | while (p_src!=p_src_post) | ||
644 | {/* Start of outer loop */ | ||
645 | |||
646 | register UWORD unroll; /* Counts unrolled loop executions. */ | ||
647 | |||
648 | /* When 'control' has the value 1, it means that the 16 buffered control */ | ||
649 | /* bits that were read in at the start of the current group have all been */ | ||
650 | /* shifted out and that all that is left is the 1 bit that was injected */ | ||
651 | /* into bit 16 at the start of the current group. When we reach the end */ | ||
652 | /* of a group, we have to load a new control word and inject a new 1 bit. */ | ||
653 | if (control==1) | ||
654 | { | ||
655 | control=0x10000|*p_src++; | ||
656 | control|=(*p_src++)<<8; | ||
657 | } | ||
658 | |||
659 | /* If it is possible that we are within 16 groups from the end of the */ | ||
660 | /* input, execute the unrolled loop only once, else process a whole group */ | ||
661 | /* of 16 items by looping 16 times. */ | ||
662 | unroll= p_src<=p_src_max16 ? 16 : 1; | ||
663 | |||
664 | /* This inner loop processes one phrase (item) per iteration. */ | ||
665 | while (unroll--) | ||
666 | { /* Begin unrolled inner loop. */ | ||
667 | |||
668 | /* Process a literal or copy item depending on the next control bit. */ | ||
669 | if (control&1) | ||
670 | { | ||
671 | /* Copy item. */ | ||
672 | |||
673 | register UBYTE *p; /* Points to place from which to copy. */ | ||
674 | register UWORD lenmt; /* Length of copy item minus three. */ | ||
675 | register UBYTE **p_hte; /* Pointer to current hash table entry.*/ | ||
676 | register UBYTE *p_ziv=p_dst; /* Pointer to start of current Ziv. */ | ||
677 | |||
678 | /* Read and dismantle the copy word. Work out from where to copy. */ | ||
679 | lenmt=*p_src++; | ||
680 | p_hte=&hash[((lenmt&0xF0)<<4)|*p_src++]; | ||
681 | p=*p_hte; | ||
682 | lenmt&=0xF; | ||
683 | |||
684 | /* Now perform the copy using a half unrolled loop. */ | ||
685 | *p_dst++=*p++; | ||
686 | *p_dst++=*p++; | ||
687 | *p_dst++=*p++; | ||
688 | while (lenmt--) | ||
689 | *p_dst++=*p++; | ||
690 | |||
691 | /* Because we have just received 3 or more bytes in a copy item */ | ||
692 | /* (whose bytes we have just installed in the output), we are now */ | ||
693 | /* in a position to flush all the pending literal hashings that had */ | ||
694 | /* been postponed for lack of bytes. */ | ||
695 | if (literals>0) | ||
696 | { | ||
697 | register UBYTE *r=p_ziv-literals; | ||
698 | hash[HASH(r)]=r; | ||
699 | if (literals==2) | ||
700 | {r++; hash[HASH(r)]=r;} | ||
701 | literals=0; | ||
702 | } | ||
703 | |||
704 | /* In any case, we can immediately update the hash table with the */ | ||
705 | /* current position. We don't need to do a HASH(...) to work out */ | ||
706 | /* where to put the pointer, as the compressor just told us!!! */ | ||
707 | *p_hte=p_ziv; | ||
708 | |||
709 | } | ||
710 | else | ||
711 | { | ||
712 | /* Literal item. */ | ||
713 | |||
714 | /* Copy over the literal byte. */ | ||
715 | *p_dst++=*p_src++; | ||
716 | |||
717 | /* If we now have three literals waiting to be hashed into the hash */ | ||
718 | /* table, we can do one of them now (because there are three). */ | ||
719 | if (++literals == 3) | ||
720 | {register UBYTE *p=p_dst-3; hash[HASH(p)]=p; literals=2;} | ||
721 | } | ||
722 | |||
723 | /* Shift the control buffer so the next control bit is in bit 0. */ | ||
724 | control>>=1; | ||
725 | #if 1 | ||
726 | if (p_dst > p_dst_post) | ||
727 | { | ||
728 | /* Shit: we tried to decompress corrupt data */ | ||
729 | *p_dst_len = 0; | ||
730 | return; | ||
731 | } | ||
732 | #endif | ||
733 | } /* End unrolled inner loop. */ | ||
734 | |||
735 | } /* End of outer loop */ | ||
736 | |||
737 | /* Write the length of the decompressed data before returning. */ | ||
738 | *p_dst_len=p_dst-p_dst_first; | ||
739 | } | ||
740 | |||
741 | /******************************************************************************/ | ||
742 | /* End of LZRW3.C */ | ||
743 | /******************************************************************************/ | ||
diff --git a/drivers/char/ftape/compressor/lzrw3.h b/drivers/char/ftape/compressor/lzrw3.h deleted file mode 100644 index 533feba47526..000000000000 --- a/drivers/char/ftape/compressor/lzrw3.h +++ /dev/null | |||
@@ -1,253 +0,0 @@ | |||
1 | #ifndef _LZRW3_H | ||
2 | #define _LZRW3_H | ||
3 | /* | ||
4 | * $Source: /homes/cvs/ftape-stacked/ftape/compressor/lzrw3.h,v $ | ||
5 | * $Revision: 1.1 $ | ||
6 | * $Date: 1997/10/05 19:12:30 $ | ||
7 | * | ||
8 | * include files for lzrw3. Only slighty modified from the original | ||
9 | * version. Assembles the three include files compress.h, port.h and | ||
10 | * fastcopy.h from the original lzrw3 package. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/types.h> | ||
15 | #include <linux/string.h> | ||
16 | |||
17 | /******************************************************************************/ | ||
18 | /* */ | ||
19 | /* COMPRESS.H */ | ||
20 | /* */ | ||
21 | /******************************************************************************/ | ||
22 | /* */ | ||
23 | /* Author : Ross Williams. */ | ||
24 | /* Date : December 1989. */ | ||
25 | /* */ | ||
26 | /* This header file defines the interface to a set of functions called */ | ||
27 | /* 'compress', each member of which implements a particular data compression */ | ||
28 | /* algorithm. */ | ||
29 | /* */ | ||
30 | /* Normally in C programming, for each .H file, there is a corresponding .C */ | ||
31 | /* file that implements the functions promised in the .H file. */ | ||
32 | /* Here, there are many .C files corresponding to this header file. */ | ||
33 | /* Each comforming implementation file contains a single function */ | ||
34 | /* called 'compress' that implements a single data compression */ | ||
35 | /* algorithm that conforms with the interface specified in this header file. */ | ||
36 | /* Only one algorithm can be linked in at a time in this organization. */ | ||
37 | /* */ | ||
38 | /******************************************************************************/ | ||
39 | /* */ | ||
40 | /* DEFINITION OF FUNCTION COMPRESS */ | ||
41 | /* =============================== */ | ||
42 | /* */ | ||
43 | /* Summary of Function Compress */ | ||
44 | /* ---------------------------- */ | ||
45 | /* The action that 'compress' takes depends on its first argument called */ | ||
46 | /* 'action'. The function provides three actions: */ | ||
47 | /* */ | ||
48 | /* - Return information about the algorithm. */ | ||
49 | /* - Compress a block of memory. */ | ||
50 | /* - Decompress a block of memory. */ | ||
51 | /* */ | ||
52 | /* Parameters */ | ||
53 | /* ---------- */ | ||
54 | /* See the formal C definition later for a description of the parameters. */ | ||
55 | /* */ | ||
56 | /* Constants */ | ||
57 | /* --------- */ | ||
58 | /* COMPRESS_OVERRUN: The constant COMPRESS_OVERRUN defines by how many bytes */ | ||
59 | /* an algorithm is allowed to expand a block during a compression operation. */ | ||
60 | /* */ | ||
61 | /* Although compression algorithms usually compress data, there will always */ | ||
62 | /* be data that a given compressor will expand (this can be proven). */ | ||
63 | /* Fortunately, the degree of expansion can be limited to a single bit, by */ | ||
64 | /* copying over the input data if the data gets bigger during compression. */ | ||
65 | /* To allow for this possibility, the first bit of a compressed */ | ||
66 | /* representation can be used as a flag indicating whether the */ | ||
67 | /* input data was copied over, or truly compressed. In practice, the first */ | ||
68 | /* byte would be used to store this bit so as to maintain byte alignment. */ | ||
69 | /* */ | ||
70 | /* Unfortunately, in general, the only way to tell if an algorithm will */ | ||
71 | /* expand a particular block of data is to run the algorithm on the data. */ | ||
72 | /* If the algorithm does not continuously monitor how many output bytes it */ | ||
73 | /* has written, it might write an output block far larger than the input */ | ||
74 | /* block before realizing that it has done so. */ | ||
75 | /* On the other hand, continuous checks on output length are inefficient. */ | ||
76 | /* */ | ||
77 | /* To cater for all these problems, this interface definition: */ | ||
78 | /* > Allows a compression algorithm to return an output block that is up to */ | ||
79 | /* COMPRESS_OVERRUN bytes longer than the input block. */ | ||
80 | /* > Allows a compression algorithm to write up to COMPRESS_OVERRUN bytes */ | ||
81 | /* more than the length of the input block to the memory of the output */ | ||
82 | /* block regardless of the length of the output block eventually returned. */ | ||
83 | /* This allows an algorithm to overrun the length of the input block in the */ | ||
84 | /* output block by up to COMPRESS_OVERRUN bytes between expansion checks. */ | ||
85 | /* */ | ||
86 | /* The problem does not arise for decompression. */ | ||
87 | /* */ | ||
88 | /* Identity Action */ | ||
89 | /* --------------- */ | ||
90 | /* > action must be COMPRESS_ACTION_IDENTITY. */ | ||
91 | /* > p_dst_len must point to a longword to receive a longword address. */ | ||
92 | /* > The value of the other parameters does not matter. */ | ||
93 | /* > After execution, the longword that p_dst_len points to will be a pointer */ | ||
94 | /* to a structure of type compress_identity. */ | ||
95 | /* Thus, for example, after the call, (*p_dst_len)->memory will return the */ | ||
96 | /* number of bytes of working memory that the algorithm requires to run. */ | ||
97 | /* > The values of the identity structure returned are fixed constant */ | ||
98 | /* attributes of the algorithm and must not vary from call to call. */ | ||
99 | /* */ | ||
100 | /* Common Requirements for Compression and Decompression Actions */ | ||
101 | /* ------------------------------------------------------------- */ | ||
102 | /* > wrk_mem must point to an unused block of memory of a length specified in */ | ||
103 | /* the algorithm's identity block. The identity block can be obtained by */ | ||
104 | /* making a separate call to compress, specifying the identity action. */ | ||
105 | /* > The INPUT BLOCK is defined to be Memory[src_addr,src_addr+src_len-1]. */ | ||
106 | /* > dst_len will be used to denote *p_dst_len. */ | ||
107 | /* > dst_len is not read by compress, only written. */ | ||
108 | /* > The value of dst_len is defined only upon termination. */ | ||
109 | /* > The OUTPUT BLOCK is defined to be Memory[dst_addr,dst_addr+dst_len-1]. */ | ||
110 | /* */ | ||
111 | /* Compression Action */ | ||
112 | /* ------------------ */ | ||
113 | /* > action must be COMPRESS_ACTION_COMPRESS. */ | ||
114 | /* > src_len must be in the range [0,COMPRESS_MAX_ORG]. */ | ||
115 | /* > The OUTPUT ZONE is defined to be */ | ||
116 | /* Memory[dst_addr,dst_addr+src_len-1+COMPRESS_OVERRUN]. */ | ||
117 | /* > The function can modify any part of the output zone regardless of the */ | ||
118 | /* final length of the output block. */ | ||
119 | /* > The input block and the output zone must not overlap. */ | ||
120 | /* > dst_len will be in the range [0,src_len+COMPRESS_OVERRUN]. */ | ||
121 | /* > dst_len will be in the range [0,COMPRESS_MAX_COM] (from prev fact). */ | ||
122 | /* > The output block will consist of a representation of the input block. */ | ||
123 | /* */ | ||
124 | /* Decompression Action */ | ||
125 | /* -------------------- */ | ||
126 | /* > action must be COMPRESS_ACTION_DECOMPRESS. */ | ||
127 | /* > The input block must be the result of an earlier compression operation. */ | ||
128 | /* > If the previous fact is true, the following facts must also be true: */ | ||
129 | /* > src_len will be in the range [0,COMPRESS_MAX_COM]. */ | ||
130 | /* > dst_len will be in the range [0,COMPRESS_MAX_ORG]. */ | ||
131 | /* > The input and output blocks must not overlap. */ | ||
132 | /* > Only the output block is modified. */ | ||
133 | /* > Upon termination, the output block will consist of the bytes contained */ | ||
134 | /* in the input block passed to the earlier compression operation. */ | ||
135 | /* */ | ||
136 | /******************************************************************************/ | ||
137 | |||
138 | /******************************************************************************/ | ||
139 | /* */ | ||
140 | /* PORT.H */ | ||
141 | /* */ | ||
142 | /******************************************************************************/ | ||
143 | /* */ | ||
144 | /* This module contains macro definitions and types that are likely to */ | ||
145 | /* change between computers. */ | ||
146 | /* */ | ||
147 | /******************************************************************************/ | ||
148 | |||
149 | #ifndef DONE_PORT /* Only do this if not previously done. */ | ||
150 | |||
151 | #ifdef THINK_C | ||
152 | #define UBYTE unsigned char /* Unsigned byte */ | ||
153 | #define UWORD unsigned int /* Unsigned word (2 bytes) */ | ||
154 | #define ULONG unsigned long /* Unsigned word (4 bytes) */ | ||
155 | #define BOOL unsigned char /* Boolean */ | ||
156 | #define FOPEN_BINARY_READ "rb" /* Mode string for binary reading. */ | ||
157 | #define FOPEN_BINARY_WRITE "wb" /* Mode string for binary writing. */ | ||
158 | #define FOPEN_TEXT_APPEND "a" /* Mode string for text appending. */ | ||
159 | #define REAL double /* USed for floating point stuff. */ | ||
160 | #endif | ||
161 | #if defined(LINUX) || defined(linux) | ||
162 | #define UBYTE __u8 /* Unsigned byte */ | ||
163 | #define UWORD __u16 /* Unsigned word (2 bytes) */ | ||
164 | #define ULONG __u32 /* Unsigned word (4 bytes) */ | ||
165 | #define LONG __s32 /* Signed word (4 bytes) */ | ||
166 | #define BOOL is not used here /* Boolean */ | ||
167 | #define FOPEN_BINARY_READ not used /* Mode string for binary reading. */ | ||
168 | #define FOPEN_BINARY_WRITE not used /* Mode string for binary writing. */ | ||
169 | #define FOPEN_TEXT_APPEND not used /* Mode string for text appending. */ | ||
170 | #define REAL not used /* USed for floating point stuff. */ | ||
171 | #ifndef TRUE | ||
172 | #define TRUE 1 | ||
173 | #endif | ||
174 | #endif | ||
175 | |||
176 | #define DONE_PORT /* Don't do all this again. */ | ||
177 | #define MALLOC_FAIL NULL /* Failure status from malloc() */ | ||
178 | #define LOCAL static /* For non-exported routines. */ | ||
179 | #define EXPORT /* Signals exported function. */ | ||
180 | #define then /* Useful for aligning ifs. */ | ||
181 | |||
182 | #endif | ||
183 | |||
184 | /******************************************************************************/ | ||
185 | /* End of PORT.H */ | ||
186 | /******************************************************************************/ | ||
187 | |||
188 | #define COMPRESS_ACTION_IDENTITY 0 | ||
189 | #define COMPRESS_ACTION_COMPRESS 1 | ||
190 | #define COMPRESS_ACTION_DECOMPRESS 2 | ||
191 | |||
192 | #define COMPRESS_OVERRUN 1024 | ||
193 | #define COMPRESS_MAX_COM 0x70000000 | ||
194 | #define COMPRESS_MAX_ORG (COMPRESS_MAX_COM-COMPRESS_OVERRUN) | ||
195 | |||
196 | #define COMPRESS_MAX_STRLEN 255 | ||
197 | |||
198 | /* The following structure provides information about the algorithm. */ | ||
199 | /* > The top bit of id must be zero. The remaining bits must be chosen by */ | ||
200 | /* the author of the algorithm by tossing a coin 31 times. */ | ||
201 | /* > The amount of memory requested by the algorithm is specified in bytes */ | ||
202 | /* and must be in the range [0,0x70000000]. */ | ||
203 | /* > All strings s must be such that strlen(s)<=COMPRESS_MAX_STRLEN. */ | ||
204 | struct compress_identity | ||
205 | { | ||
206 | ULONG id; /* Identifying number of algorithm. */ | ||
207 | ULONG memory; /* Number of bytes of working memory required. */ | ||
208 | |||
209 | char *name; /* Name of algorithm. */ | ||
210 | char *version; /* Version number. */ | ||
211 | char *date; /* Date of release of this version. */ | ||
212 | char *copyright; /* Copyright message. */ | ||
213 | |||
214 | char *author; /* Author of algorithm. */ | ||
215 | char *affiliation; /* Affiliation of author. */ | ||
216 | char *vendor; /* Where the algorithm can be obtained. */ | ||
217 | }; | ||
218 | |||
219 | void lzrw3_compress( /* Single function interface to compression algorithm. */ | ||
220 | UWORD action, /* Action to be performed. */ | ||
221 | UBYTE *wrk_mem, /* Working memory temporarily given to routine to use. */ | ||
222 | UBYTE *src_adr, /* Address of input data. */ | ||
223 | LONG src_len, /* Length of input data. */ | ||
224 | UBYTE *dst_adr, /* Address of output data. */ | ||
225 | void *p_dst_len /* Pointer to a longword where routine will write: */ | ||
226 | /* If action=..IDENTITY => Adr of id structure. */ | ||
227 | /* If action=..COMPRESS => Length of output data. */ | ||
228 | /* If action=..DECOMPRESS => Length of output data. */ | ||
229 | ); | ||
230 | |||
231 | /******************************************************************************/ | ||
232 | /* End of COMPRESS.H */ | ||
233 | /******************************************************************************/ | ||
234 | |||
235 | |||
236 | /******************************************************************************/ | ||
237 | /* fast_copy.h */ | ||
238 | /******************************************************************************/ | ||
239 | |||
240 | /* This function copies a block of memory very quickly. */ | ||
241 | /* The exact speed depends on the relative alignment of the blocks of memory. */ | ||
242 | /* PRE : 0<=src_len<=(2^32)-1 . */ | ||
243 | /* PRE : Source and destination blocks must not overlap. */ | ||
244 | /* POST : MEM[dst_adr,dst_adr+src_len-1]=MEM[src_adr,src_adr+src_len-1]. */ | ||
245 | /* POST : MEM[dst_adr,dst_adr+src_len-1] is the only memory changed. */ | ||
246 | |||
247 | #define fast_copy(src,dst,len) memcpy(dst,src,len) | ||
248 | |||
249 | /******************************************************************************/ | ||
250 | /* End of fast_copy.h */ | ||
251 | /******************************************************************************/ | ||
252 | |||
253 | #endif | ||
diff --git a/drivers/char/ftape/compressor/zftape-compress.c b/drivers/char/ftape/compressor/zftape-compress.c deleted file mode 100644 index 65ffc0be3df9..000000000000 --- a/drivers/char/ftape/compressor/zftape-compress.c +++ /dev/null | |||
@@ -1,1203 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1994-1997 Claus-Justus Heine | ||
3 | |||
4 | This program is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU General Public License as | ||
6 | published by the Free Software Foundation; either version 2, or (at | ||
7 | your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, but | ||
10 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; see the file COPYING. If not, write to | ||
16 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, | ||
17 | USA. | ||
18 | |||
19 | * | ||
20 | * This file implements a "generic" interface between the * | ||
21 | * zftape-driver and a compression-algorithm. The * | ||
22 | * compression-algorithm currently used is a LZ77. I use the * | ||
23 | * implementation lzrw3 by Ross N. Williams (Renaissance * | ||
24 | * Software). The compression program itself is in the file | ||
25 | * lzrw3.c * and lzrw3.h. To adopt another compression algorithm | ||
26 | * the functions * zft_compress() and zft_uncompress() must be | ||
27 | * changed * appropriately. See below. | ||
28 | */ | ||
29 | |||
30 | #include <linux/errno.h> | ||
31 | #include <linux/mm.h> | ||
32 | #include <linux/module.h> | ||
33 | |||
34 | #include <linux/zftape.h> | ||
35 | |||
36 | #include <asm/uaccess.h> | ||
37 | |||
38 | #include "../zftape/zftape-init.h" | ||
39 | #include "../zftape/zftape-eof.h" | ||
40 | #include "../zftape/zftape-ctl.h" | ||
41 | #include "../zftape/zftape-write.h" | ||
42 | #include "../zftape/zftape-read.h" | ||
43 | #include "../zftape/zftape-rw.h" | ||
44 | #include "../compressor/zftape-compress.h" | ||
45 | #include "../zftape/zftape-vtbl.h" | ||
46 | #include "../compressor/lzrw3.h" | ||
47 | |||
48 | /* | ||
49 | * global variables | ||
50 | */ | ||
51 | |||
52 | /* I handle the allocation of this buffer as a special case, because | ||
53 | * it's size varies depending on the tape length inserted. | ||
54 | */ | ||
55 | |||
56 | /* local variables | ||
57 | */ | ||
58 | static void *zftc_wrk_mem = NULL; | ||
59 | static __u8 *zftc_buf = NULL; | ||
60 | static void *zftc_scratch_buf = NULL; | ||
61 | |||
62 | /* compression statistics | ||
63 | */ | ||
64 | static unsigned int zftc_wr_uncompressed = 0; | ||
65 | static unsigned int zftc_wr_compressed = 0; | ||
66 | static unsigned int zftc_rd_uncompressed = 0; | ||
67 | static unsigned int zftc_rd_compressed = 0; | ||
68 | |||
69 | /* forward */ | ||
70 | static int zftc_write(int *write_cnt, | ||
71 | __u8 *dst_buf, const int seg_sz, | ||
72 | const __u8 __user *src_buf, const int req_len, | ||
73 | const zft_position *pos, const zft_volinfo *volume); | ||
74 | static int zftc_read(int *read_cnt, | ||
75 | __u8 __user *dst_buf, const int to_do, | ||
76 | const __u8 *src_buf, const int seg_sz, | ||
77 | const zft_position *pos, const zft_volinfo *volume); | ||
78 | static int zftc_seek(unsigned int new_block_pos, | ||
79 | zft_position *pos, const zft_volinfo *volume, | ||
80 | __u8 *buffer); | ||
81 | static void zftc_lock (void); | ||
82 | static void zftc_reset (void); | ||
83 | static void zftc_cleanup(void); | ||
84 | static void zftc_stats (void); | ||
85 | |||
86 | /* compressed segment. This conforms to QIC-80-MC, Revision K. | ||
87 | * | ||
88 | * Rev. K applies to tapes with `fixed length format' which is | ||
89 | * indicated by format code 2,3 and 5. See below for format code 4 and 6 | ||
90 | * | ||
91 | * 2 bytes: offset of compression segment structure | ||
92 | * 29k > offset >= 29k-18: data from previous segment ens in this | ||
93 | * segment and no compressed block starts | ||
94 | * in this segment | ||
95 | * offset == 0: data from previous segment occupies entire | ||
96 | * segment and continues in next segment | ||
97 | * n bytes: remainder from previous segment | ||
98 | * | ||
99 | * Rev. K: | ||
100 | * 4 bytes: 4 bytes: files set byte offset | ||
101 | * Post Rev. K and QIC-3020/3020: | ||
102 | * 8 bytes: 8 bytes: files set byte offset | ||
103 | * 2 bytes: byte count N (amount of data following) | ||
104 | * bit 15 is set if data is compressed, bit 15 is not | ||
105 | * set if data is uncompressed | ||
106 | * N bytes: data (as much as specified in the byte count) | ||
107 | * 2 bytes: byte count N_1 of next cluster | ||
108 | * N_1 bytes: data of next cluset | ||
109 | * 2 bytes: byte count N_2 of next cluster | ||
110 | * N_2 bytes: ... | ||
111 | * | ||
112 | * Note that the `N' byte count accounts only for the bytes that in the | ||
113 | * current segment if the cluster spans to the next segment. | ||
114 | */ | ||
115 | |||
116 | typedef struct | ||
117 | { | ||
118 | int cmpr_pos; /* actual position in compression buffer */ | ||
119 | int cmpr_sz; /* what is left in the compression buffer | ||
120 | * when copying the compressed data to the | ||
121 | * deblock buffer | ||
122 | */ | ||
123 | unsigned int first_block; /* location of header information in | ||
124 | * this segment | ||
125 | */ | ||
126 | unsigned int count; /* amount of data of current block | ||
127 | * contained in current segment | ||
128 | */ | ||
129 | unsigned int offset; /* offset in current segment */ | ||
130 | unsigned int spans:1; /* might continue in next segment */ | ||
131 | unsigned int uncmpr; /* 0x8000 if this block contains | ||
132 | * uncompressed data | ||
133 | */ | ||
134 | __s64 foffs; /* file set byte offset, same as in | ||
135 | * compression map segment | ||
136 | */ | ||
137 | } cmpr_info; | ||
138 | |||
139 | static cmpr_info cseg; /* static data. Must be kept uptodate and shared by | ||
140 | * read, write and seek functions | ||
141 | */ | ||
142 | |||
143 | #define DUMP_CMPR_INFO(level, msg, info) \ | ||
144 | TRACE(level, msg "\n" \ | ||
145 | KERN_INFO "cmpr_pos : %d\n" \ | ||
146 | KERN_INFO "cmpr_sz : %d\n" \ | ||
147 | KERN_INFO "first_block: %d\n" \ | ||
148 | KERN_INFO "count : %d\n" \ | ||
149 | KERN_INFO "offset : %d\n" \ | ||
150 | KERN_INFO "spans : %d\n" \ | ||
151 | KERN_INFO "uncmpr : 0x%04x\n" \ | ||
152 | KERN_INFO "foffs : " LL_X, \ | ||
153 | (info)->cmpr_pos, (info)->cmpr_sz, (info)->first_block, \ | ||
154 | (info)->count, (info)->offset, (info)->spans == 1, \ | ||
155 | (info)->uncmpr, LL((info)->foffs)) | ||
156 | |||
157 | /* dispatch compression segment info, return error code | ||
158 | * | ||
159 | * afterwards, cseg->offset points to start of data of the NEXT | ||
160 | * compressed block, and cseg->count contains the amount of data | ||
161 | * left in the actual compressed block. cseg->spans is set to 1 if | ||
162 | * the block is continued in the following segment. Otherwise it is | ||
163 | * set to 0. | ||
164 | */ | ||
165 | static int get_cseg (cmpr_info *cinfo, const __u8 *buff, | ||
166 | const unsigned int seg_sz, | ||
167 | const zft_volinfo *volume) | ||
168 | { | ||
169 | TRACE_FUN(ft_t_flow); | ||
170 | |||
171 | cinfo->first_block = GET2(buff, 0); | ||
172 | if (cinfo->first_block == 0) { /* data spans to next segment */ | ||
173 | cinfo->count = seg_sz - sizeof(__u16); | ||
174 | cinfo->offset = seg_sz; | ||
175 | cinfo->spans = 1; | ||
176 | } else { /* cluster definetely ends in this segment */ | ||
177 | if (cinfo->first_block > seg_sz) { | ||
178 | /* data corrupted */ | ||
179 | TRACE_ABORT(-EIO, ft_t_err, "corrupted data:\n" | ||
180 | KERN_INFO "segment size: %d\n" | ||
181 | KERN_INFO "first block : %d", | ||
182 | seg_sz, cinfo->first_block); | ||
183 | } | ||
184 | cinfo->count = cinfo->first_block - sizeof(__u16); | ||
185 | cinfo->offset = cinfo->first_block; | ||
186 | cinfo->spans = 0; | ||
187 | } | ||
188 | /* now get the offset the first block should have in the | ||
189 | * uncompressed data stream. | ||
190 | * | ||
191 | * For this magic `18' refer to CRF-3 standard or QIC-80MC, | ||
192 | * Rev. K. | ||
193 | */ | ||
194 | if ((seg_sz - cinfo->offset) > 18) { | ||
195 | if (volume->qic113) { /* > revision K */ | ||
196 | TRACE(ft_t_data_flow, "New QIC-113 compliance"); | ||
197 | cinfo->foffs = GET8(buff, cinfo->offset); | ||
198 | cinfo->offset += sizeof(__s64); | ||
199 | } else { | ||
200 | TRACE(/* ft_t_data_flow */ ft_t_noise, "pre QIC-113 version"); | ||
201 | cinfo->foffs = (__s64)GET4(buff, cinfo->offset); | ||
202 | cinfo->offset += sizeof(__u32); | ||
203 | } | ||
204 | } | ||
205 | if (cinfo->foffs > volume->size) { | ||
206 | TRACE_ABORT(-EIO, ft_t_err, "Inconsistency:\n" | ||
207 | KERN_INFO "offset in current volume: %d\n" | ||
208 | KERN_INFO "size of current volume : %d", | ||
209 | (int)(cinfo->foffs>>10), (int)(volume->size>>10)); | ||
210 | } | ||
211 | if (cinfo->cmpr_pos + cinfo->count > volume->blk_sz) { | ||
212 | TRACE_ABORT(-EIO, ft_t_err, "Inconsistency:\n" | ||
213 | KERN_INFO "block size : %d\n" | ||
214 | KERN_INFO "data record: %d", | ||
215 | volume->blk_sz, cinfo->cmpr_pos + cinfo->count); | ||
216 | } | ||
217 | DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */, "", cinfo); | ||
218 | TRACE_EXIT 0; | ||
219 | } | ||
220 | |||
221 | /* This one is called, when a new cluster starts in same segment. | ||
222 | * | ||
223 | * Note: if this is the first cluster in the current segment, we must | ||
224 | * not check whether there are more than 18 bytes available because | ||
225 | * this have already been done in get_cseg() and there may be less | ||
226 | * than 18 bytes available due to header information. | ||
227 | * | ||
228 | */ | ||
229 | static void get_next_cluster(cmpr_info *cluster, const __u8 *buff, | ||
230 | const int seg_sz, const int finish) | ||
231 | { | ||
232 | TRACE_FUN(ft_t_flow); | ||
233 | |||
234 | if (seg_sz - cluster->offset > 18 || cluster->foffs != 0) { | ||
235 | cluster->count = GET2(buff, cluster->offset); | ||
236 | cluster->uncmpr = cluster->count & 0x8000; | ||
237 | cluster->count -= cluster->uncmpr; | ||
238 | cluster->offset += sizeof(__u16); | ||
239 | cluster->foffs = 0; | ||
240 | if ((cluster->offset + cluster->count) < seg_sz) { | ||
241 | cluster->spans = 0; | ||
242 | } else if (cluster->offset + cluster->count == seg_sz) { | ||
243 | cluster->spans = !finish; | ||
244 | } else { | ||
245 | /* either an error or a volume written by an | ||
246 | * old version. If this is a data error, then we'll | ||
247 | * catch it later. | ||
248 | */ | ||
249 | TRACE(ft_t_data_flow, "Either error or old volume"); | ||
250 | cluster->spans = 1; | ||
251 | cluster->count = seg_sz - cluster->offset; | ||
252 | } | ||
253 | } else { | ||
254 | cluster->count = 0; | ||
255 | cluster->spans = 0; | ||
256 | cluster->foffs = 0; | ||
257 | } | ||
258 | DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */ , "", cluster); | ||
259 | TRACE_EXIT; | ||
260 | } | ||
261 | |||
262 | static void zftc_lock(void) | ||
263 | { | ||
264 | } | ||
265 | |||
266 | /* this function is needed for zftape_reset_position in zftape-io.c | ||
267 | */ | ||
268 | static void zftc_reset(void) | ||
269 | { | ||
270 | TRACE_FUN(ft_t_flow); | ||
271 | |||
272 | memset((void *)&cseg, '\0', sizeof(cseg)); | ||
273 | zftc_stats(); | ||
274 | TRACE_EXIT; | ||
275 | } | ||
276 | |||
277 | static int cmpr_mem_initialized = 0; | ||
278 | static unsigned int alloc_blksz = 0; | ||
279 | |||
280 | static int zft_allocate_cmpr_mem(unsigned int blksz) | ||
281 | { | ||
282 | TRACE_FUN(ft_t_flow); | ||
283 | |||
284 | if (cmpr_mem_initialized && blksz == alloc_blksz) { | ||
285 | TRACE_EXIT 0; | ||
286 | } | ||
287 | TRACE_CATCH(zft_vmalloc_once(&zftc_wrk_mem, CMPR_WRK_MEM_SIZE), | ||
288 | zftc_cleanup()); | ||
289 | TRACE_CATCH(zft_vmalloc_always(&zftc_buf, blksz + CMPR_OVERRUN), | ||
290 | zftc_cleanup()); | ||
291 | alloc_blksz = blksz; | ||
292 | TRACE_CATCH(zft_vmalloc_always(&zftc_scratch_buf, blksz+CMPR_OVERRUN), | ||
293 | zftc_cleanup()); | ||
294 | cmpr_mem_initialized = 1; | ||
295 | TRACE_EXIT 0; | ||
296 | } | ||
297 | |||
298 | static void zftc_cleanup(void) | ||
299 | { | ||
300 | TRACE_FUN(ft_t_flow); | ||
301 | |||
302 | zft_vfree(&zftc_wrk_mem, CMPR_WRK_MEM_SIZE); | ||
303 | zft_vfree(&zftc_buf, alloc_blksz + CMPR_OVERRUN); | ||
304 | zft_vfree(&zftc_scratch_buf, alloc_blksz + CMPR_OVERRUN); | ||
305 | cmpr_mem_initialized = alloc_blksz = 0; | ||
306 | TRACE_EXIT; | ||
307 | } | ||
308 | |||
309 | /***************************************************************************** | ||
310 | * * | ||
311 | * The following two functions "ftape_compress()" and * | ||
312 | * "ftape_uncompress()" are the interface to the actual compression * | ||
313 | * algorithm (i.e. they are calling the "compress()" function from * | ||
314 | * the lzrw3 package for now). These routines could quite easily be * | ||
315 | * changed to adopt another compression algorithm instead of lzrw3, * | ||
316 | * which currently is used. * | ||
317 | * * | ||
318 | *****************************************************************************/ | ||
319 | |||
320 | /* called by zft_compress_write() to perform the compression. Must | ||
321 | * return the size of the compressed data. | ||
322 | * | ||
323 | * NOTE: The size of the compressed data should not exceed the size of | ||
324 | * the uncompressed data. Most compression algorithms have means | ||
325 | * to store data unchanged if the "compressed" data amount would | ||
326 | * exceed the original one. Mostly this is done by storing some | ||
327 | * flag-bytes in front of the compressed data to indicate if it | ||
328 | * is compressed or not. Thus the worst compression result | ||
329 | * length is the original length plus those flag-bytes. | ||
330 | * | ||
331 | * We don't want that, as the QIC-80 standard provides a means | ||
332 | * of marking uncompressed blocks by simply setting bit 15 of | ||
333 | * the compressed block's length. Thus a compessed block can | ||
334 | * have at most a length of 2^15-1 bytes. The QIC-80 standard | ||
335 | * restricts the block-length even further, allowing only 29k - | ||
336 | * 6 bytes. | ||
337 | * | ||
338 | * Currently, the maximum blocksize used by zftape is 28k. | ||
339 | * | ||
340 | * In short: don't exceed the length of the input-package, set | ||
341 | * bit 15 of the compressed size to 1 if you have copied data | ||
342 | * instead of compressing it. | ||
343 | */ | ||
344 | static int zft_compress(__u8 *in_buffer, unsigned int in_sz, __u8 *out_buffer) | ||
345 | { | ||
346 | __s32 compressed_sz; | ||
347 | TRACE_FUN(ft_t_flow); | ||
348 | |||
349 | |||
350 | lzrw3_compress(COMPRESS_ACTION_COMPRESS, zftc_wrk_mem, | ||
351 | in_buffer, in_sz, out_buffer, &compressed_sz); | ||
352 | if (TRACE_LEVEL >= ft_t_info) { | ||
353 | /* the compiler will optimize this away when | ||
354 | * compiled with NO_TRACE_AT_ALL option | ||
355 | */ | ||
356 | TRACE(ft_t_data_flow, "\n" | ||
357 | KERN_INFO "before compression: %d bytes\n" | ||
358 | KERN_INFO "after compresison : %d bytes", | ||
359 | in_sz, | ||
360 | (int)(compressed_sz < 0 | ||
361 | ? -compressed_sz : compressed_sz)); | ||
362 | /* for statistical purposes | ||
363 | */ | ||
364 | zftc_wr_compressed += (compressed_sz < 0 | ||
365 | ? -compressed_sz : compressed_sz); | ||
366 | zftc_wr_uncompressed += in_sz; | ||
367 | } | ||
368 | TRACE_EXIT (int)compressed_sz; | ||
369 | } | ||
370 | |||
371 | /* called by zft_compress_read() to decompress the data. Must | ||
372 | * return the size of the decompressed data for sanity checks | ||
373 | * (compared with zft_blk_sz) | ||
374 | * | ||
375 | * NOTE: Read the note for zft_compress() above! If bit 15 of the | ||
376 | * parameter in_sz is set, then the data in in_buffer isn't | ||
377 | * compressed, which must be handled by the un-compression | ||
378 | * algorithm. (I changed lzrw3 to handle this.) | ||
379 | * | ||
380 | * The parameter max_out_sz is needed to prevent buffer overruns when | ||
381 | * uncompressing corrupt data. | ||
382 | */ | ||
383 | static unsigned int zft_uncompress(__u8 *in_buffer, | ||
384 | int in_sz, | ||
385 | __u8 *out_buffer, | ||
386 | unsigned int max_out_sz) | ||
387 | { | ||
388 | TRACE_FUN(ft_t_flow); | ||
389 | |||
390 | lzrw3_compress(COMPRESS_ACTION_DECOMPRESS, zftc_wrk_mem, | ||
391 | in_buffer, (__s32)in_sz, | ||
392 | out_buffer, (__u32 *)&max_out_sz); | ||
393 | |||
394 | if (TRACE_LEVEL >= ft_t_info) { | ||
395 | TRACE(ft_t_data_flow, "\n" | ||
396 | KERN_INFO "before decompression: %d bytes\n" | ||
397 | KERN_INFO "after decompression : %d bytes", | ||
398 | in_sz < 0 ? -in_sz : in_sz,(int)max_out_sz); | ||
399 | /* for statistical purposes | ||
400 | */ | ||
401 | zftc_rd_compressed += in_sz < 0 ? -in_sz : in_sz; | ||
402 | zftc_rd_uncompressed += max_out_sz; | ||
403 | } | ||
404 | TRACE_EXIT (unsigned int)max_out_sz; | ||
405 | } | ||
406 | |||
407 | /* print some statistics about the efficiency of the compression to | ||
408 | * the kernel log | ||
409 | */ | ||
410 | static void zftc_stats(void) | ||
411 | { | ||
412 | TRACE_FUN(ft_t_flow); | ||
413 | |||
414 | if (TRACE_LEVEL < ft_t_info) { | ||
415 | TRACE_EXIT; | ||
416 | } | ||
417 | if (zftc_wr_uncompressed != 0) { | ||
418 | if (zftc_wr_compressed > (1<<14)) { | ||
419 | TRACE(ft_t_info, "compression statistics (writing):\n" | ||
420 | KERN_INFO " compr./uncmpr. : %3d %%", | ||
421 | (((zftc_wr_compressed>>10) * 100) | ||
422 | / (zftc_wr_uncompressed>>10))); | ||
423 | } else { | ||
424 | TRACE(ft_t_info, "compression statistics (writing):\n" | ||
425 | KERN_INFO " compr./uncmpr. : %3d %%", | ||
426 | ((zftc_wr_compressed * 100) | ||
427 | / zftc_wr_uncompressed)); | ||
428 | } | ||
429 | } | ||
430 | if (zftc_rd_uncompressed != 0) { | ||
431 | if (zftc_rd_compressed > (1<<14)) { | ||
432 | TRACE(ft_t_info, "compression statistics (reading):\n" | ||
433 | KERN_INFO " compr./uncmpr. : %3d %%", | ||
434 | (((zftc_rd_compressed>>10) * 100) | ||
435 | / (zftc_rd_uncompressed>>10))); | ||
436 | } else { | ||
437 | TRACE(ft_t_info, "compression statistics (reading):\n" | ||
438 | KERN_INFO " compr./uncmpr. : %3d %%", | ||
439 | ((zftc_rd_compressed * 100) | ||
440 | / zftc_rd_uncompressed)); | ||
441 | } | ||
442 | } | ||
443 | /* only print it once: */ | ||
444 | zftc_wr_uncompressed = | ||
445 | zftc_wr_compressed = | ||
446 | zftc_rd_uncompressed = | ||
447 | zftc_rd_compressed = 0; | ||
448 | TRACE_EXIT; | ||
449 | } | ||
450 | |||
451 | /* start new compressed block | ||
452 | */ | ||
453 | static int start_new_cseg(cmpr_info *cluster, | ||
454 | char *dst_buf, | ||
455 | const zft_position *pos, | ||
456 | const unsigned int blk_sz, | ||
457 | const char *src_buf, | ||
458 | const int this_segs_sz, | ||
459 | const int qic113) | ||
460 | { | ||
461 | int size_left; | ||
462 | int cp_cnt; | ||
463 | int buf_pos; | ||
464 | TRACE_FUN(ft_t_flow); | ||
465 | |||
466 | size_left = this_segs_sz - sizeof(__u16) - cluster->cmpr_sz; | ||
467 | TRACE(ft_t_data_flow,"\n" | ||
468 | KERN_INFO "segment size : %d\n" | ||
469 | KERN_INFO "compressed_sz: %d\n" | ||
470 | KERN_INFO "size_left : %d", | ||
471 | this_segs_sz, cluster->cmpr_sz, size_left); | ||
472 | if (size_left > 18) { /* start a new cluseter */ | ||
473 | cp_cnt = cluster->cmpr_sz; | ||
474 | cluster->cmpr_sz = 0; | ||
475 | buf_pos = cp_cnt + sizeof(__u16); | ||
476 | PUT2(dst_buf, 0, buf_pos); | ||
477 | |||
478 | if (qic113) { | ||
479 | __s64 foffs = pos->volume_pos; | ||
480 | if (cp_cnt) foffs += (__s64)blk_sz; | ||
481 | |||
482 | TRACE(ft_t_data_flow, "new style QIC-113 header"); | ||
483 | PUT8(dst_buf, buf_pos, foffs); | ||
484 | buf_pos += sizeof(__s64); | ||
485 | } else { | ||
486 | __u32 foffs = (__u32)pos->volume_pos; | ||
487 | if (cp_cnt) foffs += (__u32)blk_sz; | ||
488 | |||
489 | TRACE(ft_t_data_flow, "old style QIC-80MC header"); | ||
490 | PUT4(dst_buf, buf_pos, foffs); | ||
491 | buf_pos += sizeof(__u32); | ||
492 | } | ||
493 | } else if (size_left >= 0) { | ||
494 | cp_cnt = cluster->cmpr_sz; | ||
495 | cluster->cmpr_sz = 0; | ||
496 | buf_pos = cp_cnt + sizeof(__u16); | ||
497 | PUT2(dst_buf, 0, buf_pos); | ||
498 | /* zero unused part of segment. */ | ||
499 | memset(dst_buf + buf_pos, '\0', size_left); | ||
500 | buf_pos = this_segs_sz; | ||
501 | } else { /* need entire segment and more space */ | ||
502 | PUT2(dst_buf, 0, 0); | ||
503 | cp_cnt = this_segs_sz - sizeof(__u16); | ||
504 | cluster->cmpr_sz -= cp_cnt; | ||
505 | buf_pos = this_segs_sz; | ||
506 | } | ||
507 | memcpy(dst_buf + sizeof(__u16), src_buf + cluster->cmpr_pos, cp_cnt); | ||
508 | cluster->cmpr_pos += cp_cnt; | ||
509 | TRACE_EXIT buf_pos; | ||
510 | } | ||
511 | |||
512 | /* return-value: the number of bytes removed from the user-buffer | ||
513 | * `src_buf' or error code | ||
514 | * | ||
515 | * int *write_cnt : how much actually has been moved to the | ||
516 | * dst_buf. Need not be initialized when | ||
517 | * function returns with an error code | ||
518 | * (negativ return value) | ||
519 | * __u8 *dst_buf : kernel space buffer where the has to be | ||
520 | * copied to. The contents of this buffers | ||
521 | * goes to a specific segment. | ||
522 | * const int seg_sz : the size of the segment dst_buf will be | ||
523 | * copied to. | ||
524 | * const zft_position *pos : struct containing the coordinates in | ||
525 | * the current volume (byte position, | ||
526 | * segment id of current segment etc) | ||
527 | * const zft_volinfo *volume: information about the current volume, | ||
528 | * size etc. | ||
529 | * const __u8 *src_buf : user space buffer that contains the | ||
530 | * data the user wants to be written to | ||
531 | * tape. | ||
532 | * const int req_len : the amount of data the user wants to be | ||
533 | * written to tape. | ||
534 | */ | ||
535 | static int zftc_write(int *write_cnt, | ||
536 | __u8 *dst_buf, const int seg_sz, | ||
537 | const __u8 __user *src_buf, const int req_len, | ||
538 | const zft_position *pos, const zft_volinfo *volume) | ||
539 | { | ||
540 | int req_len_left = req_len; | ||
541 | int result; | ||
542 | int len_left; | ||
543 | int buf_pos_write = pos->seg_byte_pos; | ||
544 | TRACE_FUN(ft_t_flow); | ||
545 | |||
546 | /* Note: we do not unlock the module because | ||
547 | * there are some values cached in that `cseg' variable. We | ||
548 | * don't don't want to use this information when being | ||
549 | * unloaded by kerneld even when the tape is full or when we | ||
550 | * cannot allocate enough memory. | ||
551 | */ | ||
552 | if (pos->tape_pos > (volume->size-volume->blk_sz-ZFT_CMPR_OVERHEAD)) { | ||
553 | TRACE_EXIT -ENOSPC; | ||
554 | } | ||
555 | if (zft_allocate_cmpr_mem(volume->blk_sz) < 0) { | ||
556 | /* should we unlock the module? But it shouldn't | ||
557 | * be locked anyway ... | ||
558 | */ | ||
559 | TRACE_EXIT -ENOMEM; | ||
560 | } | ||
561 | if (buf_pos_write == 0) { /* fill a new segment */ | ||
562 | *write_cnt = buf_pos_write = start_new_cseg(&cseg, | ||
563 | dst_buf, | ||
564 | pos, | ||
565 | volume->blk_sz, | ||
566 | zftc_buf, | ||
567 | seg_sz, | ||
568 | volume->qic113); | ||
569 | if (cseg.cmpr_sz == 0 && cseg.cmpr_pos != 0) { | ||
570 | req_len_left -= result = volume->blk_sz; | ||
571 | cseg.cmpr_pos = 0; | ||
572 | } else { | ||
573 | result = 0; | ||
574 | } | ||
575 | } else { | ||
576 | *write_cnt = result = 0; | ||
577 | } | ||
578 | |||
579 | len_left = seg_sz - buf_pos_write; | ||
580 | while ((req_len_left > 0) && (len_left > 18)) { | ||
581 | /* now we have some size left for a new compressed | ||
582 | * block. We know, that the compression buffer is | ||
583 | * empty (else there wouldn't be any space left). | ||
584 | */ | ||
585 | if (copy_from_user(zftc_scratch_buf, src_buf + result, | ||
586 | volume->blk_sz) != 0) { | ||
587 | TRACE_EXIT -EFAULT; | ||
588 | } | ||
589 | req_len_left -= volume->blk_sz; | ||
590 | cseg.cmpr_sz = zft_compress(zftc_scratch_buf, volume->blk_sz, | ||
591 | zftc_buf); | ||
592 | if (cseg.cmpr_sz < 0) { | ||
593 | cseg.uncmpr = 0x8000; | ||
594 | cseg.cmpr_sz = -cseg.cmpr_sz; | ||
595 | } else { | ||
596 | cseg.uncmpr = 0; | ||
597 | } | ||
598 | /* increment "result" iff we copied the entire | ||
599 | * compressed block to the zft_deblock_buf | ||
600 | */ | ||
601 | len_left -= sizeof(__u16); | ||
602 | if (len_left >= cseg.cmpr_sz) { | ||
603 | len_left -= cseg.count = cseg.cmpr_sz; | ||
604 | cseg.cmpr_pos = cseg.cmpr_sz = 0; | ||
605 | result += volume->blk_sz; | ||
606 | } else { | ||
607 | cseg.cmpr_sz -= | ||
608 | cseg.cmpr_pos = | ||
609 | cseg.count = len_left; | ||
610 | len_left = 0; | ||
611 | } | ||
612 | PUT2(dst_buf, buf_pos_write, cseg.uncmpr | cseg.count); | ||
613 | buf_pos_write += sizeof(__u16); | ||
614 | memcpy(dst_buf + buf_pos_write, zftc_buf, cseg.count); | ||
615 | buf_pos_write += cseg.count; | ||
616 | *write_cnt += cseg.count + sizeof(__u16); | ||
617 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
618 | } | ||
619 | /* erase the remainder of the segment if less than 18 bytes | ||
620 | * left (18 bytes is due to the QIC-80 standard) | ||
621 | */ | ||
622 | if (len_left <= 18) { | ||
623 | memset(dst_buf + buf_pos_write, '\0', len_left); | ||
624 | (*write_cnt) += len_left; | ||
625 | } | ||
626 | TRACE(ft_t_data_flow, "returning %d", result); | ||
627 | TRACE_EXIT result; | ||
628 | } | ||
629 | |||
630 | /* out: | ||
631 | * | ||
632 | * int *read_cnt: the number of bytes we removed from the zft_deblock_buf | ||
633 | * (result) | ||
634 | * int *to_do : the remaining size of the read-request. | ||
635 | * | ||
636 | * in: | ||
637 | * | ||
638 | * char *buff : buff is the address of the upper part of the user | ||
639 | * buffer, that hasn't been filled with data yet. | ||
640 | |||
641 | * int buf_pos_read : copy of from _ftape_read() | ||
642 | * int buf_len_read : copy of buf_len_rd from _ftape_read() | ||
643 | * char *zft_deblock_buf: zft_deblock_buf | ||
644 | * unsigned short blk_sz: the block size valid for this volume, may differ | ||
645 | * from zft_blk_sz. | ||
646 | * int finish: if != 0 means that this is the last segment belonging | ||
647 | * to this volume | ||
648 | * returns the amount of data actually copied to the user-buffer | ||
649 | * | ||
650 | * to_do MUST NOT SHRINK except to indicate an EOF. In this case *to_do has to | ||
651 | * be set to 0 | ||
652 | */ | ||
653 | static int zftc_read (int *read_cnt, | ||
654 | __u8 __user *dst_buf, const int to_do, | ||
655 | const __u8 *src_buf, const int seg_sz, | ||
656 | const zft_position *pos, const zft_volinfo *volume) | ||
657 | { | ||
658 | int uncompressed_sz; | ||
659 | int result = 0; | ||
660 | int remaining = to_do; | ||
661 | TRACE_FUN(ft_t_flow); | ||
662 | |||
663 | TRACE_CATCH(zft_allocate_cmpr_mem(volume->blk_sz),); | ||
664 | if (pos->seg_byte_pos == 0) { | ||
665 | /* new segment just read | ||
666 | */ | ||
667 | TRACE_CATCH(get_cseg(&cseg, src_buf, seg_sz, volume), | ||
668 | *read_cnt = 0); | ||
669 | memcpy(zftc_buf + cseg.cmpr_pos, src_buf + sizeof(__u16), | ||
670 | cseg.count); | ||
671 | cseg.cmpr_pos += cseg.count; | ||
672 | *read_cnt = cseg.offset; | ||
673 | DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */, "", &cseg); | ||
674 | } else { | ||
675 | *read_cnt = 0; | ||
676 | } | ||
677 | /* loop and uncompress until user buffer full or | ||
678 | * deblock-buffer empty | ||
679 | */ | ||
680 | TRACE(ft_t_data_flow, "compressed_sz: %d, compos : %d, *read_cnt: %d", | ||
681 | cseg.cmpr_sz, cseg.cmpr_pos, *read_cnt); | ||
682 | while ((cseg.spans == 0) && (remaining > 0)) { | ||
683 | if (cseg.cmpr_pos != 0) { /* cmpr buf is not empty */ | ||
684 | uncompressed_sz = | ||
685 | zft_uncompress(zftc_buf, | ||
686 | cseg.uncmpr == 0x8000 ? | ||
687 | -cseg.cmpr_pos : cseg.cmpr_pos, | ||
688 | zftc_scratch_buf, | ||
689 | volume->blk_sz); | ||
690 | if (uncompressed_sz != volume->blk_sz) { | ||
691 | *read_cnt = 0; | ||
692 | TRACE_ABORT(-EIO, ft_t_warn, | ||
693 | "Uncompressed blk (%d) != blk size (%d)", | ||
694 | uncompressed_sz, volume->blk_sz); | ||
695 | } | ||
696 | if (copy_to_user(dst_buf + result, | ||
697 | zftc_scratch_buf, | ||
698 | uncompressed_sz) != 0 ) { | ||
699 | TRACE_EXIT -EFAULT; | ||
700 | } | ||
701 | remaining -= uncompressed_sz; | ||
702 | result += uncompressed_sz; | ||
703 | cseg.cmpr_pos = 0; | ||
704 | } | ||
705 | if (remaining > 0) { | ||
706 | get_next_cluster(&cseg, src_buf, seg_sz, | ||
707 | volume->end_seg == pos->seg_pos); | ||
708 | if (cseg.count != 0) { | ||
709 | memcpy(zftc_buf, src_buf + cseg.offset, | ||
710 | cseg.count); | ||
711 | cseg.cmpr_pos = cseg.count; | ||
712 | cseg.offset += cseg.count; | ||
713 | *read_cnt += cseg.count + sizeof(__u16); | ||
714 | } else { | ||
715 | remaining = 0; | ||
716 | } | ||
717 | } | ||
718 | TRACE(ft_t_data_flow, "\n" | ||
719 | KERN_INFO "compressed_sz: %d\n" | ||
720 | KERN_INFO "compos : %d\n" | ||
721 | KERN_INFO "*read_cnt : %d", | ||
722 | cseg.cmpr_sz, cseg.cmpr_pos, *read_cnt); | ||
723 | } | ||
724 | if (seg_sz - cseg.offset <= 18) { | ||
725 | *read_cnt += seg_sz - cseg.offset; | ||
726 | TRACE(ft_t_data_flow, "expanding read cnt to: %d", *read_cnt); | ||
727 | } | ||
728 | TRACE(ft_t_data_flow, "\n" | ||
729 | KERN_INFO "segment size : %d\n" | ||
730 | KERN_INFO "read count : %d\n" | ||
731 | KERN_INFO "buf_pos_read : %d\n" | ||
732 | KERN_INFO "remaining : %d", | ||
733 | seg_sz, *read_cnt, pos->seg_byte_pos, | ||
734 | seg_sz - *read_cnt - pos->seg_byte_pos); | ||
735 | TRACE(ft_t_data_flow, "returning: %d", result); | ||
736 | TRACE_EXIT result; | ||
737 | } | ||
738 | |||
739 | /* seeks to the new data-position. Reads sometimes a segment. | ||
740 | * | ||
741 | * start_seg and end_seg give the boundaries of the current volume | ||
742 | * blk_sz is the blk_sz of the current volume as stored in the | ||
743 | * volume label | ||
744 | * | ||
745 | * We don't allow blocksizes less than 1024 bytes, therefore we don't need | ||
746 | * a 64 bit argument for new_block_pos. | ||
747 | */ | ||
748 | |||
749 | static int seek_in_segment(const unsigned int to_do, cmpr_info *c_info, | ||
750 | const char *src_buf, const int seg_sz, | ||
751 | const int seg_pos, const zft_volinfo *volume); | ||
752 | static int slow_seek_forward_until_error(const unsigned int distance, | ||
753 | cmpr_info *c_info, zft_position *pos, | ||
754 | const zft_volinfo *volume, __u8 *buf); | ||
755 | static int search_valid_segment(unsigned int segment, | ||
756 | const unsigned int end_seg, | ||
757 | const unsigned int max_foffs, | ||
758 | zft_position *pos, cmpr_info *c_info, | ||
759 | const zft_volinfo *volume, __u8 *buf); | ||
760 | static int slow_seek_forward(unsigned int dest, cmpr_info *c_info, | ||
761 | zft_position *pos, const zft_volinfo *volume, | ||
762 | __u8 *buf); | ||
763 | static int compute_seg_pos(unsigned int dest, zft_position *pos, | ||
764 | const zft_volinfo *volume); | ||
765 | |||
766 | #define ZFT_SLOW_SEEK_THRESHOLD 10 /* segments */ | ||
767 | #define ZFT_FAST_SEEK_MAX_TRIALS 10 /* times */ | ||
768 | #define ZFT_FAST_SEEK_BACKUP 10 /* segments */ | ||
769 | |||
770 | static int zftc_seek(unsigned int new_block_pos, | ||
771 | zft_position *pos, const zft_volinfo *volume, __u8 *buf) | ||
772 | { | ||
773 | unsigned int dest; | ||
774 | int limit; | ||
775 | int distance; | ||
776 | int result = 0; | ||
777 | int seg_dist; | ||
778 | int new_seg; | ||
779 | int old_seg = 0; | ||
780 | int fast_seek_trials = 0; | ||
781 | TRACE_FUN(ft_t_flow); | ||
782 | |||
783 | if (new_block_pos == 0) { | ||
784 | pos->seg_pos = volume->start_seg; | ||
785 | pos->seg_byte_pos = 0; | ||
786 | pos->volume_pos = 0; | ||
787 | zftc_reset(); | ||
788 | TRACE_EXIT 0; | ||
789 | } | ||
790 | dest = new_block_pos * (volume->blk_sz >> 10); | ||
791 | distance = dest - (pos->volume_pos >> 10); | ||
792 | while (distance != 0) { | ||
793 | seg_dist = compute_seg_pos(dest, pos, volume); | ||
794 | TRACE(ft_t_noise, "\n" | ||
795 | KERN_INFO "seg_dist: %d\n" | ||
796 | KERN_INFO "distance: %d\n" | ||
797 | KERN_INFO "dest : %d\n" | ||
798 | KERN_INFO "vpos : %d\n" | ||
799 | KERN_INFO "seg_pos : %d\n" | ||
800 | KERN_INFO "trials : %d", | ||
801 | seg_dist, distance, dest, | ||
802 | (unsigned int)(pos->volume_pos>>10), pos->seg_pos, | ||
803 | fast_seek_trials); | ||
804 | if (distance > 0) { | ||
805 | if (seg_dist < 0) { | ||
806 | TRACE(ft_t_bug, "BUG: distance %d > 0, " | ||
807 | "segment difference %d < 0", | ||
808 | distance, seg_dist); | ||
809 | result = -EIO; | ||
810 | break; | ||
811 | } | ||
812 | new_seg = pos->seg_pos + seg_dist; | ||
813 | if (new_seg > volume->end_seg) { | ||
814 | new_seg = volume->end_seg; | ||
815 | } | ||
816 | if (old_seg == new_seg || /* loop */ | ||
817 | seg_dist <= ZFT_SLOW_SEEK_THRESHOLD || | ||
818 | fast_seek_trials >= ZFT_FAST_SEEK_MAX_TRIALS) { | ||
819 | TRACE(ft_t_noise, "starting slow seek:\n" | ||
820 | KERN_INFO "fast seek failed too often: %s\n" | ||
821 | KERN_INFO "near target position : %s\n" | ||
822 | KERN_INFO "looping between two segs : %s", | ||
823 | (fast_seek_trials >= | ||
824 | ZFT_FAST_SEEK_MAX_TRIALS) | ||
825 | ? "yes" : "no", | ||
826 | (seg_dist <= ZFT_SLOW_SEEK_THRESHOLD) | ||
827 | ? "yes" : "no", | ||
828 | (old_seg == new_seg) | ||
829 | ? "yes" : "no"); | ||
830 | result = slow_seek_forward(dest, &cseg, | ||
831 | pos, volume, buf); | ||
832 | break; | ||
833 | } | ||
834 | old_seg = new_seg; | ||
835 | limit = volume->end_seg; | ||
836 | fast_seek_trials ++; | ||
837 | for (;;) { | ||
838 | result = search_valid_segment(new_seg, limit, | ||
839 | volume->size, | ||
840 | pos, &cseg, | ||
841 | volume, buf); | ||
842 | if (result == 0 || result == -EINTR) { | ||
843 | break; | ||
844 | } | ||
845 | if (new_seg == volume->start_seg) { | ||
846 | result = -EIO; /* set errror | ||
847 | * condition | ||
848 | */ | ||
849 | break; | ||
850 | } | ||
851 | limit = new_seg; | ||
852 | new_seg -= ZFT_FAST_SEEK_BACKUP; | ||
853 | if (new_seg < volume->start_seg) { | ||
854 | new_seg = volume->start_seg; | ||
855 | } | ||
856 | } | ||
857 | if (result < 0) { | ||
858 | TRACE(ft_t_warn, | ||
859 | "Couldn't find a readable segment"); | ||
860 | break; | ||
861 | } | ||
862 | } else /* if (distance < 0) */ { | ||
863 | if (seg_dist > 0) { | ||
864 | TRACE(ft_t_bug, "BUG: distance %d < 0, " | ||
865 | "segment difference %d >0", | ||
866 | distance, seg_dist); | ||
867 | result = -EIO; | ||
868 | break; | ||
869 | } | ||
870 | new_seg = pos->seg_pos + seg_dist; | ||
871 | if (fast_seek_trials > 0 && seg_dist == 0) { | ||
872 | /* this avoids sticking to the same | ||
873 | * segment all the time. On the other hand: | ||
874 | * if we got here for the first time, and the | ||
875 | * deblock_buffer still contains a valid | ||
876 | * segment, then there is no need to skip to | ||
877 | * the previous segment if the desired position | ||
878 | * is inside this segment. | ||
879 | */ | ||
880 | new_seg --; | ||
881 | } | ||
882 | if (new_seg < volume->start_seg) { | ||
883 | new_seg = volume->start_seg; | ||
884 | } | ||
885 | limit = pos->seg_pos; | ||
886 | fast_seek_trials ++; | ||
887 | for (;;) { | ||
888 | result = search_valid_segment(new_seg, limit, | ||
889 | pos->volume_pos, | ||
890 | pos, &cseg, | ||
891 | volume, buf); | ||
892 | if (result == 0 || result == -EINTR) { | ||
893 | break; | ||
894 | } | ||
895 | if (new_seg == volume->start_seg) { | ||
896 | result = -EIO; /* set errror | ||
897 | * condition | ||
898 | */ | ||
899 | break; | ||
900 | } | ||
901 | limit = new_seg; | ||
902 | new_seg -= ZFT_FAST_SEEK_BACKUP; | ||
903 | if (new_seg < volume->start_seg) { | ||
904 | new_seg = volume->start_seg; | ||
905 | } | ||
906 | } | ||
907 | if (result < 0) { | ||
908 | TRACE(ft_t_warn, | ||
909 | "Couldn't find a readable segment"); | ||
910 | break; | ||
911 | } | ||
912 | } | ||
913 | distance = dest - (pos->volume_pos >> 10); | ||
914 | } | ||
915 | TRACE_EXIT result; | ||
916 | } | ||
917 | |||
918 | |||
919 | /* advance inside the given segment at most to_do bytes. | ||
920 | * of kilobytes moved | ||
921 | */ | ||
922 | |||
923 | static int seek_in_segment(const unsigned int to_do, | ||
924 | cmpr_info *c_info, | ||
925 | const char *src_buf, | ||
926 | const int seg_sz, | ||
927 | const int seg_pos, | ||
928 | const zft_volinfo *volume) | ||
929 | { | ||
930 | int result = 0; | ||
931 | int blk_sz = volume->blk_sz >> 10; | ||
932 | int remaining = to_do; | ||
933 | TRACE_FUN(ft_t_flow); | ||
934 | |||
935 | if (c_info->offset == 0) { | ||
936 | /* new segment just read | ||
937 | */ | ||
938 | TRACE_CATCH(get_cseg(c_info, src_buf, seg_sz, volume),); | ||
939 | c_info->cmpr_pos += c_info->count; | ||
940 | DUMP_CMPR_INFO(ft_t_noise, "", c_info); | ||
941 | } | ||
942 | /* loop and uncompress until user buffer full or | ||
943 | * deblock-buffer empty | ||
944 | */ | ||
945 | TRACE(ft_t_noise, "compressed_sz: %d, compos : %d", | ||
946 | c_info->cmpr_sz, c_info->cmpr_pos); | ||
947 | while (c_info->spans == 0 && remaining > 0) { | ||
948 | if (c_info->cmpr_pos != 0) { /* cmpr buf is not empty */ | ||
949 | result += blk_sz; | ||
950 | remaining -= blk_sz; | ||
951 | c_info->cmpr_pos = 0; | ||
952 | } | ||
953 | if (remaining > 0) { | ||
954 | get_next_cluster(c_info, src_buf, seg_sz, | ||
955 | volume->end_seg == seg_pos); | ||
956 | if (c_info->count != 0) { | ||
957 | c_info->cmpr_pos = c_info->count; | ||
958 | c_info->offset += c_info->count; | ||
959 | } else { | ||
960 | break; | ||
961 | } | ||
962 | } | ||
963 | /* Allow escape from this loop on signal! | ||
964 | */ | ||
965 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
966 | DUMP_CMPR_INFO(ft_t_noise, "", c_info); | ||
967 | TRACE(ft_t_noise, "to_do: %d", remaining); | ||
968 | } | ||
969 | if (seg_sz - c_info->offset <= 18) { | ||
970 | c_info->offset = seg_sz; | ||
971 | } | ||
972 | TRACE(ft_t_noise, "\n" | ||
973 | KERN_INFO "segment size : %d\n" | ||
974 | KERN_INFO "buf_pos_read : %d\n" | ||
975 | KERN_INFO "remaining : %d", | ||
976 | seg_sz, c_info->offset, | ||
977 | seg_sz - c_info->offset); | ||
978 | TRACE_EXIT result; | ||
979 | } | ||
980 | |||
981 | static int slow_seek_forward_until_error(const unsigned int distance, | ||
982 | cmpr_info *c_info, | ||
983 | zft_position *pos, | ||
984 | const zft_volinfo *volume, | ||
985 | __u8 *buf) | ||
986 | { | ||
987 | unsigned int remaining = distance; | ||
988 | int seg_sz; | ||
989 | int seg_pos; | ||
990 | int result; | ||
991 | TRACE_FUN(ft_t_flow); | ||
992 | |||
993 | seg_pos = pos->seg_pos; | ||
994 | do { | ||
995 | TRACE_CATCH(seg_sz = zft_fetch_segment(seg_pos, buf, | ||
996 | FT_RD_AHEAD),); | ||
997 | /* now we have the contents of the actual segment in | ||
998 | * the deblock buffer | ||
999 | */ | ||
1000 | TRACE_CATCH(result = seek_in_segment(remaining, c_info, buf, | ||
1001 | seg_sz, seg_pos,volume),); | ||
1002 | remaining -= result; | ||
1003 | pos->volume_pos += result<<10; | ||
1004 | pos->seg_pos = seg_pos; | ||
1005 | pos->seg_byte_pos = c_info->offset; | ||
1006 | seg_pos ++; | ||
1007 | if (seg_pos <= volume->end_seg && c_info->offset == seg_sz) { | ||
1008 | pos->seg_pos ++; | ||
1009 | pos->seg_byte_pos = 0; | ||
1010 | c_info->offset = 0; | ||
1011 | } | ||
1012 | /* Allow escape from this loop on signal! | ||
1013 | */ | ||
1014 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
1015 | TRACE(ft_t_noise, "\n" | ||
1016 | KERN_INFO "remaining: %d\n" | ||
1017 | KERN_INFO "seg_pos: %d\n" | ||
1018 | KERN_INFO "end_seg: %d\n" | ||
1019 | KERN_INFO "result: %d", | ||
1020 | remaining, seg_pos, volume->end_seg, result); | ||
1021 | } while (remaining > 0 && seg_pos <= volume->end_seg); | ||
1022 | TRACE_EXIT 0; | ||
1023 | } | ||
1024 | |||
1025 | /* return segment id of next segment containing valid data, -EIO otherwise | ||
1026 | */ | ||
1027 | static int search_valid_segment(unsigned int segment, | ||
1028 | const unsigned int end_seg, | ||
1029 | const unsigned int max_foffs, | ||
1030 | zft_position *pos, | ||
1031 | cmpr_info *c_info, | ||
1032 | const zft_volinfo *volume, | ||
1033 | __u8 *buf) | ||
1034 | { | ||
1035 | cmpr_info tmp_info; | ||
1036 | int seg_sz; | ||
1037 | TRACE_FUN(ft_t_flow); | ||
1038 | |||
1039 | memset(&tmp_info, 0, sizeof(cmpr_info)); | ||
1040 | while (segment <= end_seg) { | ||
1041 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
1042 | TRACE(ft_t_noise, | ||
1043 | "Searching readable segment between %d and %d", | ||
1044 | segment, end_seg); | ||
1045 | seg_sz = zft_fetch_segment(segment, buf, FT_RD_AHEAD); | ||
1046 | if ((seg_sz > 0) && | ||
1047 | (get_cseg (&tmp_info, buf, seg_sz, volume) >= 0) && | ||
1048 | (tmp_info.foffs != 0 || segment == volume->start_seg)) { | ||
1049 | if ((tmp_info.foffs>>10) > max_foffs) { | ||
1050 | TRACE_ABORT(-EIO, ft_t_noise, "\n" | ||
1051 | KERN_INFO "cseg.foff: %d\n" | ||
1052 | KERN_INFO "dest : %d", | ||
1053 | (int)(tmp_info.foffs >> 10), | ||
1054 | max_foffs); | ||
1055 | } | ||
1056 | DUMP_CMPR_INFO(ft_t_noise, "", &tmp_info); | ||
1057 | *c_info = tmp_info; | ||
1058 | pos->seg_pos = segment; | ||
1059 | pos->volume_pos = c_info->foffs; | ||
1060 | pos->seg_byte_pos = c_info->offset; | ||
1061 | TRACE(ft_t_noise, "found segment at %d", segment); | ||
1062 | TRACE_EXIT 0; | ||
1063 | } | ||
1064 | segment++; | ||
1065 | } | ||
1066 | TRACE_EXIT -EIO; | ||
1067 | } | ||
1068 | |||
1069 | static int slow_seek_forward(unsigned int dest, | ||
1070 | cmpr_info *c_info, | ||
1071 | zft_position *pos, | ||
1072 | const zft_volinfo *volume, | ||
1073 | __u8 *buf) | ||
1074 | { | ||
1075 | unsigned int distance; | ||
1076 | int result = 0; | ||
1077 | TRACE_FUN(ft_t_flow); | ||
1078 | |||
1079 | distance = dest - (pos->volume_pos >> 10); | ||
1080 | while ((distance > 0) && | ||
1081 | (result = slow_seek_forward_until_error(distance, | ||
1082 | c_info, | ||
1083 | pos, | ||
1084 | volume, | ||
1085 | buf)) < 0) { | ||
1086 | if (result == -EINTR) { | ||
1087 | break; | ||
1088 | } | ||
1089 | TRACE(ft_t_noise, "seg_pos: %d", pos->seg_pos); | ||
1090 | /* the failing segment is either pos->seg_pos or | ||
1091 | * pos->seg_pos + 1. There is no need to further try | ||
1092 | * that segment, because ftape_read_segment() already | ||
1093 | * has tried very much to read it. So we start with | ||
1094 | * following segment, which is pos->seg_pos + 1 | ||
1095 | */ | ||
1096 | if(search_valid_segment(pos->seg_pos+1, volume->end_seg, dest, | ||
1097 | pos, c_info, | ||
1098 | volume, buf) < 0) { | ||
1099 | TRACE(ft_t_noise, "search_valid_segment() failed"); | ||
1100 | result = -EIO; | ||
1101 | break; | ||
1102 | } | ||
1103 | distance = dest - (pos->volume_pos >> 10); | ||
1104 | result = 0; | ||
1105 | TRACE(ft_t_noise, "segment: %d", pos->seg_pos); | ||
1106 | /* found valid segment, retry the seek */ | ||
1107 | } | ||
1108 | TRACE_EXIT result; | ||
1109 | } | ||
1110 | |||
1111 | static int compute_seg_pos(const unsigned int dest, | ||
1112 | zft_position *pos, | ||
1113 | const zft_volinfo *volume) | ||
1114 | { | ||
1115 | int segment; | ||
1116 | int distance = dest - (pos->volume_pos >> 10); | ||
1117 | unsigned int raw_size; | ||
1118 | unsigned int virt_size; | ||
1119 | unsigned int factor; | ||
1120 | TRACE_FUN(ft_t_flow); | ||
1121 | |||
1122 | if (distance >= 0) { | ||
1123 | raw_size = volume->end_seg - pos->seg_pos + 1; | ||
1124 | virt_size = ((unsigned int)(volume->size>>10) | ||
1125 | - (unsigned int)(pos->volume_pos>>10) | ||
1126 | + FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS - 1); | ||
1127 | virt_size /= FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS; | ||
1128 | if (virt_size == 0 || raw_size == 0) { | ||
1129 | TRACE_EXIT 0; | ||
1130 | } | ||
1131 | if (raw_size >= (1<<25)) { | ||
1132 | factor = raw_size/(virt_size>>7); | ||
1133 | } else { | ||
1134 | factor = (raw_size<<7)/virt_size; | ||
1135 | } | ||
1136 | segment = distance/(FT_SECTORS_PER_SEGMENT-FT_ECC_SECTORS); | ||
1137 | segment = (segment * factor)>>7; | ||
1138 | } else { | ||
1139 | raw_size = pos->seg_pos - volume->start_seg + 1; | ||
1140 | virt_size = ((unsigned int)(pos->volume_pos>>10) | ||
1141 | + FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS - 1); | ||
1142 | virt_size /= FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS; | ||
1143 | if (virt_size == 0 || raw_size == 0) { | ||
1144 | TRACE_EXIT 0; | ||
1145 | } | ||
1146 | if (raw_size >= (1<<25)) { | ||
1147 | factor = raw_size/(virt_size>>7); | ||
1148 | } else { | ||
1149 | factor = (raw_size<<7)/virt_size; | ||
1150 | } | ||
1151 | segment = distance/(FT_SECTORS_PER_SEGMENT-FT_ECC_SECTORS); | ||
1152 | } | ||
1153 | TRACE(ft_t_noise, "factor: %d/%d", factor, 1<<7); | ||
1154 | TRACE_EXIT segment; | ||
1155 | } | ||
1156 | |||
1157 | static struct zft_cmpr_ops cmpr_ops = { | ||
1158 | zftc_write, | ||
1159 | zftc_read, | ||
1160 | zftc_seek, | ||
1161 | zftc_lock, | ||
1162 | zftc_reset, | ||
1163 | zftc_cleanup | ||
1164 | }; | ||
1165 | |||
1166 | int zft_compressor_init(void) | ||
1167 | { | ||
1168 | TRACE_FUN(ft_t_flow); | ||
1169 | |||
1170 | #ifdef MODULE | ||
1171 | printk(KERN_INFO "zftape compressor v1.00a 970514 for " FTAPE_VERSION "\n"); | ||
1172 | if (TRACE_LEVEL >= ft_t_info) { | ||
1173 | printk( | ||
1174 | KERN_INFO "(c) 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n" | ||
1175 | KERN_INFO "Compressor for zftape (lzrw3 algorithm)\n"); | ||
1176 | } | ||
1177 | #else /* !MODULE */ | ||
1178 | /* print a short no-nonsense boot message */ | ||
1179 | printk(KERN_INFO "zftape compressor v1.00a 970514\n"); | ||
1180 | printk(KERN_INFO "For use with " FTAPE_VERSION "\n"); | ||
1181 | #endif /* MODULE */ | ||
1182 | TRACE(ft_t_info, "zft_compressor_init @ 0x%p", zft_compressor_init); | ||
1183 | TRACE(ft_t_info, "installing compressor for zftape ..."); | ||
1184 | TRACE_CATCH(zft_cmpr_register(&cmpr_ops),); | ||
1185 | TRACE_EXIT 0; | ||
1186 | } | ||
1187 | |||
1188 | #ifdef MODULE | ||
1189 | |||
1190 | MODULE_AUTHOR( | ||
1191 | "(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de"); | ||
1192 | MODULE_DESCRIPTION( | ||
1193 | "Compression routines for zftape. Uses the lzrw3 algorithm by Ross Williams"); | ||
1194 | MODULE_LICENSE("GPL"); | ||
1195 | |||
1196 | /* Called by modules package when installing the driver | ||
1197 | */ | ||
1198 | int init_module(void) | ||
1199 | { | ||
1200 | return zft_compressor_init(); | ||
1201 | } | ||
1202 | |||
1203 | #endif /* MODULE */ | ||
diff --git a/drivers/char/ftape/compressor/zftape-compress.h b/drivers/char/ftape/compressor/zftape-compress.h deleted file mode 100644 index f200741e33bf..000000000000 --- a/drivers/char/ftape/compressor/zftape-compress.h +++ /dev/null | |||
@@ -1,83 +0,0 @@ | |||
1 | #ifndef _ZFTAPE_COMPRESS_H | ||
2 | #define _ZFTAPE_COMPRESS_H | ||
3 | /* | ||
4 | * Copyright (c) 1994-1997 Claus-Justus Heine | ||
5 | |||
6 | This program is free software; you can redistribute it and/or | ||
7 | modify it under the terms of the GNU General Public License as | ||
8 | published by the Free Software Foundation; either version 2, or (at | ||
9 | your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, but | ||
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; see the file COPYING. If not, write to | ||
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, | ||
19 | USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/compressor/zftape-compress.h,v $ | ||
23 | * $Revision: 1.1 $ | ||
24 | * $Date: 1997/10/05 19:12:32 $ | ||
25 | * | ||
26 | * This file contains macros and definitions for zftape's | ||
27 | * builtin compression code. | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include "../zftape/zftape-buffers.h" | ||
32 | #include "../zftape/zftape-vtbl.h" | ||
33 | #include "../compressor/lzrw3.h" | ||
34 | |||
35 | /* CMPR_WRK_MEM_SIZE gives the size of the compression wrk_mem */ | ||
36 | /* I got these out of lzrw3.c */ | ||
37 | #define U(X) ((__u32) X) | ||
38 | #define SIZE_P_BYTE (U(sizeof(__u8 *))) | ||
39 | #define ALIGNMENT_FUDGE (U(16)) | ||
40 | |||
41 | #define CMPR_WRK_MEM_SIZE (U(4096)*(SIZE_P_BYTE) + ALIGNMENT_FUDGE) | ||
42 | |||
43 | /* the maximum number of bytes the size of the "compressed" data can | ||
44 | * exceed the uncompressed data. As it is quite useless to compress | ||
45 | * data twice it is sometimes the case that it is more efficient to | ||
46 | * copy a block of data but to feed it to the "compression" | ||
47 | * algorithm. In this case there are some flag bytes or the like | ||
48 | * proceding the "compressed" data. THAT MUST NOT BE THE CASE for the | ||
49 | * algorithm we use for this driver. Instead, the high bit 15 of | ||
50 | * compressed_size: | ||
51 | * | ||
52 | * compressed_size = ftape_compress() | ||
53 | * | ||
54 | * must be set in such a case. | ||
55 | * | ||
56 | * Nevertheless, it might also be as for lzrw3 that there is an | ||
57 | * "intermediate" overrun that exceeds the amount of the compressed | ||
58 | * data that is actually produced. During the algorithm we need in the | ||
59 | * worst case MAX_CMP_GROUP bytes more than the input-size. | ||
60 | */ | ||
61 | #define MAX_CMP_GROUP (2+16*2) /* from lzrw3.c */ | ||
62 | |||
63 | #define CMPR_OVERRUN MAX_CMP_GROUP /* during compression */ | ||
64 | |||
65 | /****************************************************/ | ||
66 | |||
67 | #define CMPR_BUFFER_SIZE (MAX_BLOCK_SIZE + CMPR_OVERRUN) | ||
68 | |||
69 | /* the compression map stores the byte offset compressed blocks within | ||
70 | * the current volume for catridges with format code 2,3 and 5 | ||
71 | * (and old versions of zftape) and the offset measured in kilobytes for | ||
72 | * format code 4 and 6. This gives us a possible max. size of a | ||
73 | * compressed volume of 1024*4GIG which should be enough. | ||
74 | */ | ||
75 | typedef __u32 CmprMap; | ||
76 | |||
77 | /* globals | ||
78 | */ | ||
79 | |||
80 | /* exported functions | ||
81 | */ | ||
82 | |||
83 | #endif /* _ZFTAPE_COMPRESS_H */ | ||
diff --git a/drivers/char/ftape/lowlevel/Makefile b/drivers/char/ftape/lowlevel/Makefile deleted file mode 100644 index febab07ba427..000000000000 --- a/drivers/char/ftape/lowlevel/Makefile +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | # | ||
2 | # Copyright (C) 1996, 1997 Clau-Justus Heine. | ||
3 | # | ||
4 | # This program is free software; you can redistribute it and/or modify | ||
5 | # it under the terms of the GNU General Public License as published by | ||
6 | # the Free Software Foundation; either version 2, or (at your option) | ||
7 | # any later version. | ||
8 | # | ||
9 | # This program is distributed in the hope that it will be useful, | ||
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | # GNU General Public License for more details. | ||
13 | # | ||
14 | # You should have received a copy of the GNU General Public License | ||
15 | # along with this program; see the file COPYING. If not, write to | ||
16 | # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | # | ||
18 | # $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/Makefile,v $ | ||
19 | # $Revision: 1.4 $ | ||
20 | # $Date: 1997/10/07 09:26:02 $ | ||
21 | # | ||
22 | # Makefile for the lowlevel part QIC-40/80/3010/3020 floppy-tape | ||
23 | # driver for Linux. | ||
24 | # | ||
25 | |||
26 | obj-$(CONFIG_FTAPE) += ftape.o | ||
27 | |||
28 | ftape-objs := ftape-init.o fdc-io.o fdc-isr.o \ | ||
29 | ftape-bsm.o ftape-ctl.o ftape-read.o ftape-rw.o \ | ||
30 | ftape-write.o ftape-io.o ftape-calibr.o ftape-ecc.o fc-10.o \ | ||
31 | ftape-buffer.o ftape-format.o ftape_syms.o | ||
32 | |||
33 | ifeq ($(CONFIG_FTAPE),y) | ||
34 | ftape-objs += ftape-setup.o | ||
35 | endif | ||
36 | |||
37 | ifndef CONFIG_FT_NO_TRACE_AT_ALL | ||
38 | ftape-objs += ftape-tracing.o | ||
39 | endif | ||
40 | |||
41 | ifeq ($(CONFIG_FT_PROC_FS),y) | ||
42 | ftape-objs += ftape-proc.o | ||
43 | endif | ||
diff --git a/drivers/char/ftape/lowlevel/fc-10.c b/drivers/char/ftape/lowlevel/fc-10.c deleted file mode 100644 index 9bc1cddade76..000000000000 --- a/drivers/char/ftape/lowlevel/fc-10.c +++ /dev/null | |||
@@ -1,175 +0,0 @@ | |||
1 | /* | ||
2 | * | ||
3 | |||
4 | Copyright (C) 1993,1994 Jon Tombs. | ||
5 | |||
6 | This program is distributed in the hope that it will be useful, | ||
7 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | GNU General Public License for more details. | ||
10 | |||
11 | The entire guts of this program was written by dosemu, modified to | ||
12 | record reads and writes to the ports in the 0x180-0x188 address space, | ||
13 | while running the CMS program TAPE.EXE V2.0.5 supplied with the drive. | ||
14 | |||
15 | Modified to use an array of addresses and generally cleaned up (made | ||
16 | much shorter) 4 June 94, dosemu isn't that good at writing short code it | ||
17 | would seem :-). Made independent of 0x180, but I doubt it will work | ||
18 | at any other address. | ||
19 | |||
20 | Modified for distribution with ftape source. 21 June 94, SJL. | ||
21 | |||
22 | Modifications on 20 October 95, by Daniel Cohen (catman@wpi.edu): | ||
23 | Modified to support different DMA, IRQ, and IO Ports. Borland's | ||
24 | Turbo Debugger in virtual 8086 mode (TD386.EXE with hardware breakpoints | ||
25 | provided by the TDH386.SYS Device Driver) was used on the CMS program | ||
26 | TAPE V4.0.5. I set breakpoints on I/O to ports 0x180-0x187. Note that | ||
27 | CMS's program will not successfully configure the tape drive if you set | ||
28 | breakpoints on IO Reads, but you can set them on IO Writes without problems. | ||
29 | Known problems: | ||
30 | - You can not use DMA Channels 5 or 7. | ||
31 | |||
32 | Modification on 29 January 96, by Daniel Cohen (catman@wpi.edu): | ||
33 | Modified to only accept IRQs 3 - 7, or 9. Since we can only send a 3 bit | ||
34 | number representing the IRQ to the card, special handling is required when | ||
35 | IRQ 9 is selected. IRQ 2 and 9 are the same, and we should request IRQ 9 | ||
36 | from the kernel while telling the card to use IRQ 2. Thanks to Greg | ||
37 | Crider (gcrider@iclnet.org) for finding and locating this bug, as well as | ||
38 | testing the patch. | ||
39 | |||
40 | Modification on 11 December 96, by Claus Heine (claus@momo.math.rwth-aachen.de): | ||
41 | Modified a little to use variahle ft_fdc_base, ft_fdc_irq, ft_fdc_dma | ||
42 | instead of preprocessor symbols. Thus we can compile this into the module | ||
43 | or kernel and let the user specify the options as command line arguments. | ||
44 | |||
45 | * | ||
46 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fc-10.c,v $ | ||
47 | * $Revision: 1.2 $ | ||
48 | * $Date: 1997/10/05 19:18:04 $ | ||
49 | * | ||
50 | * This file contains code for the CMS FC-10/FC-20 card. | ||
51 | */ | ||
52 | |||
53 | #include <asm/io.h> | ||
54 | #include <linux/ftape.h> | ||
55 | #include "../lowlevel/ftape-tracing.h" | ||
56 | #include "../lowlevel/fdc-io.h" | ||
57 | #include "../lowlevel/fc-10.h" | ||
58 | |||
59 | static __u16 inbs_magic[] = { | ||
60 | 0x3, 0x3, 0x0, 0x4, 0x7, 0x2, 0x5, 0x3, 0x1, 0x4, | ||
61 | 0x3, 0x5, 0x2, 0x0, 0x3, 0x7, 0x4, 0x2, | ||
62 | 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 | ||
63 | }; | ||
64 | |||
65 | static __u16 fc10_ports[] = { | ||
66 | 0x180, 0x210, 0x2A0, 0x300, 0x330, 0x340, 0x370 | ||
67 | }; | ||
68 | |||
69 | int fc10_enable(void) | ||
70 | { | ||
71 | int i; | ||
72 | __u8 cardConfig = 0x00; | ||
73 | __u8 x; | ||
74 | TRACE_FUN(ft_t_flow); | ||
75 | |||
76 | /* This code will only work if the FC-10 (or FC-20) is set to | ||
77 | * use DMA channels 1, 2, or 3. DMA channels 5 and 7 seem to be | ||
78 | * initialized by the same command as channels 1 and 3, respectively. | ||
79 | */ | ||
80 | if (ft_fdc_dma > 3) { | ||
81 | TRACE_ABORT(0, ft_t_err, | ||
82 | "Error: The FC-10/20 must be set to use DMA channels 1, 2, or 3!"); | ||
83 | } | ||
84 | /* Only allow the FC-10/20 to use IRQ 3-7, or 9. Note that CMS's program | ||
85 | * only accepts IRQ's 2-7, but in linux, IRQ 2 is the same as IRQ 9. | ||
86 | */ | ||
87 | if (ft_fdc_irq < 3 || ft_fdc_irq == 8 || ft_fdc_irq > 9) { | ||
88 | TRACE_ABORT(0, ft_t_err, | ||
89 | "Error: The FC-10/20 must be set to use IRQ levels 3 - 7, or 9!\n" | ||
90 | KERN_INFO "Note: IRQ 9 is the same as IRQ 2"); | ||
91 | } | ||
92 | /* Clear state machine ??? | ||
93 | */ | ||
94 | for (i = 0; i < NR_ITEMS(inbs_magic); i++) { | ||
95 | inb(ft_fdc_base + inbs_magic[i]); | ||
96 | } | ||
97 | outb(0x0, ft_fdc_base); | ||
98 | |||
99 | x = inb(ft_fdc_base); | ||
100 | if (x == 0x13 || x == 0x93) { | ||
101 | for (i = 1; i < 8; i++) { | ||
102 | if (inb(ft_fdc_base + i) != x) { | ||
103 | TRACE_EXIT 0; | ||
104 | } | ||
105 | } | ||
106 | } else { | ||
107 | TRACE_EXIT 0; | ||
108 | } | ||
109 | |||
110 | outb(0x8, ft_fdc_base); | ||
111 | |||
112 | for (i = 0; i < 8; i++) { | ||
113 | if (inb(ft_fdc_base + i) != 0x0) { | ||
114 | TRACE_EXIT 0; | ||
115 | } | ||
116 | } | ||
117 | outb(0x10, ft_fdc_base); | ||
118 | |||
119 | for (i = 0; i < 8; i++) { | ||
120 | if (inb(ft_fdc_base + i) != 0xff) { | ||
121 | TRACE_EXIT 0; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | /* Okay, we found a FC-10 card ! ??? | ||
126 | */ | ||
127 | outb(0x0, fdc.ccr); | ||
128 | |||
129 | /* Clear state machine again ??? | ||
130 | */ | ||
131 | for (i = 0; i < NR_ITEMS(inbs_magic); i++) { | ||
132 | inb(ft_fdc_base + inbs_magic[i]); | ||
133 | } | ||
134 | /* Send io port */ | ||
135 | for (i = 0; i < NR_ITEMS(fc10_ports); i++) | ||
136 | if (ft_fdc_base == fc10_ports[i]) | ||
137 | cardConfig = i + 1; | ||
138 | if (cardConfig == 0) { | ||
139 | TRACE_EXIT 0; /* Invalid I/O Port */ | ||
140 | } | ||
141 | /* and IRQ - If using IRQ 9, tell the FC card it is actually IRQ 2 */ | ||
142 | if (ft_fdc_irq != 9) | ||
143 | cardConfig |= ft_fdc_irq << 3; | ||
144 | else | ||
145 | cardConfig |= 2 << 3; | ||
146 | |||
147 | /* and finally DMA Channel */ | ||
148 | cardConfig |= ft_fdc_dma << 6; | ||
149 | outb(cardConfig, ft_fdc_base); /* DMA [2 bits]/IRQ [3 bits]/BASE [3 bits] */ | ||
150 | |||
151 | /* Enable FC-10 ??? | ||
152 | */ | ||
153 | outb(0, fdc.ccr); | ||
154 | outb(0, fdc.dor2); | ||
155 | outb(FDC_DMA_MODE /* 8 */, fdc.dor); | ||
156 | outb(FDC_DMA_MODE /* 8 */, fdc.dor); | ||
157 | outb(1, fdc.dor2); | ||
158 | |||
159 | /************************************* | ||
160 | * | ||
161 | * cH: why the hell should this be necessary? This is done | ||
162 | * by fdc_reset()!!! | ||
163 | * | ||
164 | *************************************/ | ||
165 | /* Initialize fdc, select drive B: | ||
166 | */ | ||
167 | outb(FDC_DMA_MODE, fdc.dor); /* assert reset, dma & irq enabled */ | ||
168 | /* 0x08 */ | ||
169 | outb(FDC_DMA_MODE|FDC_RESET_NOT, fdc.dor); /* release reset */ | ||
170 | /* 0x08 | 0x04 = 0x0c */ | ||
171 | outb(FDC_DMA_MODE|FDC_RESET_NOT|FDC_MOTOR_1|FTAPE_SEL_B, fdc.dor); | ||
172 | /* 0x08 | 0x04 | 0x20 | 0x01 = 0x2d */ | ||
173 | /* select drive 1 */ /* why not drive 0 ???? */ | ||
174 | TRACE_EXIT (x == 0x93) ? 2 : 1; | ||
175 | } | ||
diff --git a/drivers/char/ftape/lowlevel/fc-10.h b/drivers/char/ftape/lowlevel/fc-10.h deleted file mode 100644 index da7b88bca889..000000000000 --- a/drivers/char/ftape/lowlevel/fc-10.h +++ /dev/null | |||
@@ -1,39 +0,0 @@ | |||
1 | #ifndef _FC_10_H | ||
2 | #define _FC_10_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1994-1996 Bas Laarhoven. | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fc-10.h,v $ | ||
23 | * $Revision: 1.1 $ | ||
24 | * $Date: 1997/09/19 09:05:22 $ | ||
25 | * | ||
26 | * This file contains definitions for the FC-10 code | ||
27 | * of the QIC-40/80 floppy-tape driver for Linux. | ||
28 | */ | ||
29 | |||
30 | /* | ||
31 | * fc-10.c defined global vars. | ||
32 | */ | ||
33 | |||
34 | /* | ||
35 | * fc-10.c defined global functions. | ||
36 | */ | ||
37 | extern int fc10_enable(void); | ||
38 | |||
39 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c deleted file mode 100644 index bbcf918f056f..000000000000 --- a/drivers/char/ftape/lowlevel/fdc-io.c +++ /dev/null | |||
@@ -1,1349 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
3 | * (C) 1996-1997 Claus-Justus Heine. | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2, or (at your option) | ||
8 | any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; see the file COPYING. If not, write to | ||
17 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | |||
19 | * | ||
20 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-io.c,v $ | ||
21 | * $Revision: 1.7.4.2 $ | ||
22 | * $Date: 1997/11/16 14:48:17 $ | ||
23 | * | ||
24 | * This file contains the low-level floppy disk interface code | ||
25 | * for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for | ||
26 | * Linux. | ||
27 | */ | ||
28 | |||
29 | #include <linux/errno.h> | ||
30 | #include <linux/sched.h> | ||
31 | #include <linux/ioport.h> | ||
32 | #include <linux/interrupt.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <asm/system.h> | ||
35 | #include <asm/io.h> | ||
36 | #include <asm/dma.h> | ||
37 | #include <asm/irq.h> | ||
38 | |||
39 | #include <linux/ftape.h> | ||
40 | #include <linux/qic117.h> | ||
41 | #include "../lowlevel/ftape-tracing.h" | ||
42 | #include "../lowlevel/fdc-io.h" | ||
43 | #include "../lowlevel/fdc-isr.h" | ||
44 | #include "../lowlevel/ftape-io.h" | ||
45 | #include "../lowlevel/ftape-rw.h" | ||
46 | #include "../lowlevel/ftape-ctl.h" | ||
47 | #include "../lowlevel/ftape-calibr.h" | ||
48 | #include "../lowlevel/fc-10.h" | ||
49 | |||
50 | /* Global vars. | ||
51 | */ | ||
52 | static int ftape_motor; | ||
53 | volatile int ftape_current_cylinder = -1; | ||
54 | volatile fdc_mode_enum fdc_mode = fdc_idle; | ||
55 | fdc_config_info fdc; | ||
56 | DECLARE_WAIT_QUEUE_HEAD(ftape_wait_intr); | ||
57 | |||
58 | unsigned int ft_fdc_base = CONFIG_FT_FDC_BASE; | ||
59 | unsigned int ft_fdc_irq = CONFIG_FT_FDC_IRQ; | ||
60 | unsigned int ft_fdc_dma = CONFIG_FT_FDC_DMA; | ||
61 | unsigned int ft_fdc_threshold = CONFIG_FT_FDC_THR; /* bytes */ | ||
62 | unsigned int ft_fdc_rate_limit = CONFIG_FT_FDC_MAX_RATE; /* bits/sec */ | ||
63 | int ft_probe_fc10 = CONFIG_FT_PROBE_FC10; | ||
64 | int ft_mach2 = CONFIG_FT_MACH2; | ||
65 | |||
66 | /* Local vars. | ||
67 | */ | ||
68 | static spinlock_t fdc_io_lock; | ||
69 | static unsigned int fdc_calibr_count; | ||
70 | static unsigned int fdc_calibr_time; | ||
71 | static int fdc_status; | ||
72 | volatile __u8 fdc_head; /* FDC head from sector id */ | ||
73 | volatile __u8 fdc_cyl; /* FDC track from sector id */ | ||
74 | volatile __u8 fdc_sect; /* FDC sector from sector id */ | ||
75 | static int fdc_data_rate = 500; /* data rate (Kbps) */ | ||
76 | static int fdc_rate_code; /* data rate code (0 == 500 Kbps) */ | ||
77 | static int fdc_seek_rate = 2; /* step rate (msec) */ | ||
78 | static void (*do_ftape) (void); | ||
79 | static int fdc_fifo_state; /* original fifo setting - fifo enabled */ | ||
80 | static int fdc_fifo_thr; /* original fifo setting - threshold */ | ||
81 | static int fdc_lock_state; /* original lock setting - locked */ | ||
82 | static int fdc_fifo_locked; /* has fifo && lock set ? */ | ||
83 | static __u8 fdc_precomp; /* default precomp. value (nsec) */ | ||
84 | static __u8 fdc_prec_code; /* fdc precomp. select code */ | ||
85 | |||
86 | static char ftape_id[] = "ftape"; /* used by request irq and free irq */ | ||
87 | |||
88 | static int fdc_set_seek_rate(int seek_rate); | ||
89 | |||
90 | void fdc_catch_stray_interrupts(int count) | ||
91 | { | ||
92 | unsigned long flags; | ||
93 | |||
94 | spin_lock_irqsave(&fdc_io_lock, flags); | ||
95 | if (count == 0) { | ||
96 | ft_expected_stray_interrupts = 0; | ||
97 | } else { | ||
98 | ft_expected_stray_interrupts += count; | ||
99 | } | ||
100 | spin_unlock_irqrestore(&fdc_io_lock, flags); | ||
101 | } | ||
102 | |||
103 | /* Wait during a timeout period for a given FDC status. | ||
104 | * If usecs == 0 then just test status, else wait at least for usecs. | ||
105 | * Returns -ETIME on timeout. Function must be calibrated first ! | ||
106 | */ | ||
107 | static int fdc_wait(unsigned int usecs, __u8 mask, __u8 state) | ||
108 | { | ||
109 | int count_1 = (fdc_calibr_count * usecs + | ||
110 | fdc_calibr_count - 1) / fdc_calibr_time; | ||
111 | |||
112 | do { | ||
113 | fdc_status = inb_p(fdc.msr); | ||
114 | if ((fdc_status & mask) == state) { | ||
115 | return 0; | ||
116 | } | ||
117 | } while (count_1-- >= 0); | ||
118 | return -ETIME; | ||
119 | } | ||
120 | |||
121 | int fdc_ready_wait(unsigned int usecs) | ||
122 | { | ||
123 | return fdc_wait(usecs, FDC_DATA_READY | FDC_BUSY, FDC_DATA_READY); | ||
124 | } | ||
125 | |||
126 | /* Why can't we just use udelay()? | ||
127 | */ | ||
128 | static void fdc_usec_wait(unsigned int usecs) | ||
129 | { | ||
130 | fdc_wait(usecs, 0, 1); /* will always timeout ! */ | ||
131 | } | ||
132 | |||
133 | static int fdc_ready_out_wait(unsigned int usecs) | ||
134 | { | ||
135 | fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ | ||
136 | return fdc_wait(usecs, FDC_DATA_OUT_READY, FDC_DATA_OUT_READY); | ||
137 | } | ||
138 | |||
139 | void fdc_wait_calibrate(void) | ||
140 | { | ||
141 | ftape_calibrate("fdc_wait", | ||
142 | fdc_usec_wait, &fdc_calibr_count, &fdc_calibr_time); | ||
143 | } | ||
144 | |||
145 | /* Wait for a (short) while for the FDC to become ready | ||
146 | * and transfer the next command byte. | ||
147 | * Return -ETIME on timeout on getting ready (depends on hardware!). | ||
148 | */ | ||
149 | static int fdc_write(const __u8 data) | ||
150 | { | ||
151 | fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ | ||
152 | if (fdc_wait(150, FDC_DATA_READY_MASK, FDC_DATA_IN_READY) < 0) { | ||
153 | return -ETIME; | ||
154 | } else { | ||
155 | outb(data, fdc.fifo); | ||
156 | return 0; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | /* Wait for a (short) while for the FDC to become ready | ||
161 | * and transfer the next result byte. | ||
162 | * Return -ETIME if timeout on getting ready (depends on hardware!). | ||
163 | */ | ||
164 | static int fdc_read(__u8 * data) | ||
165 | { | ||
166 | fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ | ||
167 | if (fdc_wait(150, FDC_DATA_READY_MASK, FDC_DATA_OUT_READY) < 0) { | ||
168 | return -ETIME; | ||
169 | } else { | ||
170 | *data = inb(fdc.fifo); | ||
171 | return 0; | ||
172 | } | ||
173 | } | ||
174 | |||
175 | /* Output a cmd_len long command string to the FDC. | ||
176 | * The FDC should be ready to receive a new command or | ||
177 | * an error (EBUSY or ETIME) will occur. | ||
178 | */ | ||
179 | int fdc_command(const __u8 * cmd_data, int cmd_len) | ||
180 | { | ||
181 | int result = 0; | ||
182 | unsigned long flags; | ||
183 | int count = cmd_len; | ||
184 | int retry = 0; | ||
185 | #ifdef TESTING | ||
186 | static unsigned int last_time; | ||
187 | unsigned int time; | ||
188 | #endif | ||
189 | TRACE_FUN(ft_t_any); | ||
190 | |||
191 | fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ | ||
192 | spin_lock_irqsave(&fdc_io_lock, flags); | ||
193 | if (!in_interrupt()) | ||
194 | /* Yes, I know, too much comments inside this function | ||
195 | * ... | ||
196 | * | ||
197 | * Yet another bug in the original driver. All that | ||
198 | * havoc is caused by the fact that the isr() sends | ||
199 | * itself a command to the floppy tape driver (pause, | ||
200 | * micro step pause). Now, the problem is that | ||
201 | * commands are transmitted via the fdc_seek | ||
202 | * command. But: the fdc performs seeks in the | ||
203 | * background i.e. it doesn't signal busy while | ||
204 | * sending the step pulses to the drive. Therefore the | ||
205 | * non-interrupt level driver has no chance to tell | ||
206 | * whether the isr() just has issued a seek. Therefore | ||
207 | * we HAVE TO have a look at the ft_hide_interrupt | ||
208 | * flag: it signals the non-interrupt level part of | ||
209 | * the driver that it has to wait for the fdc until it | ||
210 | * has completet seeking. | ||
211 | * | ||
212 | * THIS WAS PRESUMABLY THE REASON FOR ALL THAT | ||
213 | * "fdc_read timeout" errors, I HOPE :-) | ||
214 | */ | ||
215 | if (ft_hide_interrupt) { | ||
216 | restore_flags(flags); | ||
217 | TRACE(ft_t_info, | ||
218 | "Waiting for the isr() completing fdc_seek()"); | ||
219 | if (fdc_interrupt_wait(2 * FT_SECOND) < 0) { | ||
220 | TRACE(ft_t_warn, | ||
221 | "Warning: timeout waiting for isr() seek to complete"); | ||
222 | } | ||
223 | if (ft_hide_interrupt || !ft_seek_completed) { | ||
224 | /* There cannot be another | ||
225 | * interrupt. The isr() only stops | ||
226 | * the tape and the next interrupt | ||
227 | * won't come until we have send our | ||
228 | * command to the drive. | ||
229 | */ | ||
230 | TRACE_ABORT(-EIO, ft_t_bug, | ||
231 | "BUG? isr() is still seeking?\n" | ||
232 | KERN_INFO "hide: %d\n" | ||
233 | KERN_INFO "seek: %d", | ||
234 | ft_hide_interrupt, | ||
235 | ft_seek_completed); | ||
236 | |||
237 | } | ||
238 | fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */ | ||
239 | spin_lock_irqsave(&fdc_io_lock, flags); | ||
240 | } | ||
241 | fdc_status = inb(fdc.msr); | ||
242 | if ((fdc_status & FDC_DATA_READY_MASK) != FDC_DATA_IN_READY) { | ||
243 | spin_unlock_irqrestore(&fdc_io_lock, flags); | ||
244 | TRACE_ABORT(-EBUSY, ft_t_err, "fdc not ready"); | ||
245 | } | ||
246 | fdc_mode = *cmd_data; /* used by isr */ | ||
247 | #ifdef TESTING | ||
248 | if (fdc_mode == FDC_SEEK) { | ||
249 | time = ftape_timediff(last_time, ftape_timestamp()); | ||
250 | if (time < 6000) { | ||
251 | TRACE(ft_t_bug,"Warning: short timeout between seek commands: %d", | ||
252 | time); | ||
253 | } | ||
254 | } | ||
255 | #endif | ||
256 | if (!in_interrupt()) { | ||
257 | /* shouldn't be cleared if called from isr | ||
258 | */ | ||
259 | ft_interrupt_seen = 0; | ||
260 | } | ||
261 | while (count) { | ||
262 | result = fdc_write(*cmd_data); | ||
263 | if (result < 0) { | ||
264 | TRACE(ft_t_fdc_dma, | ||
265 | "fdc_mode = %02x, status = %02x at index %d", | ||
266 | (int) fdc_mode, (int) fdc_status, | ||
267 | cmd_len - count); | ||
268 | if (++retry <= 3) { | ||
269 | TRACE(ft_t_warn, "fdc_write timeout, retry"); | ||
270 | } else { | ||
271 | TRACE(ft_t_err, "fdc_write timeout, fatal"); | ||
272 | /* recover ??? */ | ||
273 | break; | ||
274 | } | ||
275 | } else { | ||
276 | --count; | ||
277 | ++cmd_data; | ||
278 | } | ||
279 | } | ||
280 | #ifdef TESTING | ||
281 | if (fdc_mode == FDC_SEEK) { | ||
282 | last_time = ftape_timestamp(); | ||
283 | } | ||
284 | #endif | ||
285 | spin_unlock_irqrestore(&fdc_io_lock, flags); | ||
286 | TRACE_EXIT result; | ||
287 | } | ||
288 | |||
289 | /* Input a res_len long result string from the FDC. | ||
290 | * The FDC should be ready to send the result or an error | ||
291 | * (EBUSY or ETIME) will occur. | ||
292 | */ | ||
293 | int fdc_result(__u8 * res_data, int res_len) | ||
294 | { | ||
295 | int result = 0; | ||
296 | unsigned long flags; | ||
297 | int count = res_len; | ||
298 | int retry = 0; | ||
299 | TRACE_FUN(ft_t_any); | ||
300 | |||
301 | spin_lock_irqsave(&fdc_io_lock, flags); | ||
302 | fdc_status = inb(fdc.msr); | ||
303 | if ((fdc_status & FDC_DATA_READY_MASK) != FDC_DATA_OUT_READY) { | ||
304 | TRACE(ft_t_err, "fdc not ready"); | ||
305 | result = -EBUSY; | ||
306 | } else while (count) { | ||
307 | if (!(fdc_status & FDC_BUSY)) { | ||
308 | spin_unlock_irqrestore(&fdc_io_lock, flags); | ||
309 | TRACE_ABORT(-EIO, ft_t_err, "premature end of result phase"); | ||
310 | } | ||
311 | result = fdc_read(res_data); | ||
312 | if (result < 0) { | ||
313 | TRACE(ft_t_fdc_dma, | ||
314 | "fdc_mode = %02x, status = %02x at index %d", | ||
315 | (int) fdc_mode, | ||
316 | (int) fdc_status, | ||
317 | res_len - count); | ||
318 | if (++retry <= 3) { | ||
319 | TRACE(ft_t_warn, "fdc_read timeout, retry"); | ||
320 | } else { | ||
321 | TRACE(ft_t_err, "fdc_read timeout, fatal"); | ||
322 | /* recover ??? */ | ||
323 | break; | ||
324 | ++retry; | ||
325 | } | ||
326 | } else { | ||
327 | --count; | ||
328 | ++res_data; | ||
329 | } | ||
330 | } | ||
331 | spin_unlock_irqrestore(&fdc_io_lock, flags); | ||
332 | fdc_usec_wait(FT_RQM_DELAY); /* allow FDC to negate BSY */ | ||
333 | TRACE_EXIT result; | ||
334 | } | ||
335 | |||
336 | /* Handle command and result phases for | ||
337 | * commands without data phase. | ||
338 | */ | ||
339 | static int fdc_issue_command(const __u8 * out_data, int out_count, | ||
340 | __u8 * in_data, int in_count) | ||
341 | { | ||
342 | TRACE_FUN(ft_t_any); | ||
343 | |||
344 | if (out_count > 0) { | ||
345 | TRACE_CATCH(fdc_command(out_data, out_count),); | ||
346 | } | ||
347 | /* will take 24 - 30 usec for fdc_sense_drive_status and | ||
348 | * fdc_sense_interrupt_status commands. | ||
349 | * 35 fails sometimes (5/9/93 SJL) | ||
350 | * On a loaded system it incidentally takes longer than | ||
351 | * this for the fdc to get ready ! ?????? WHY ?????? | ||
352 | * So until we know what's going on use a very long timeout. | ||
353 | */ | ||
354 | TRACE_CATCH(fdc_ready_out_wait(500 /* usec */),); | ||
355 | if (in_count > 0) { | ||
356 | TRACE_CATCH(fdc_result(in_data, in_count), | ||
357 | TRACE(ft_t_err, "result phase aborted")); | ||
358 | } | ||
359 | TRACE_EXIT 0; | ||
360 | } | ||
361 | |||
362 | /* Wait for FDC interrupt with timeout (in milliseconds). | ||
363 | * Signals are blocked so the wait will not be aborted. | ||
364 | * Note: interrupts must be enabled ! (23/05/93 SJL) | ||
365 | */ | ||
366 | int fdc_interrupt_wait(unsigned int time) | ||
367 | { | ||
368 | DECLARE_WAITQUEUE(wait,current); | ||
369 | sigset_t old_sigmask; | ||
370 | static int resetting; | ||
371 | long timeout; | ||
372 | |||
373 | TRACE_FUN(ft_t_fdc_dma); | ||
374 | |||
375 | if (waitqueue_active(&ftape_wait_intr)) { | ||
376 | TRACE_ABORT(-EIO, ft_t_err, "error: nested call"); | ||
377 | } | ||
378 | /* timeout time will be up to USPT microseconds too long ! */ | ||
379 | timeout = (1000 * time + FT_USPT - 1) / FT_USPT; | ||
380 | |||
381 | spin_lock_irq(¤t->sighand->siglock); | ||
382 | old_sigmask = current->blocked; | ||
383 | sigfillset(¤t->blocked); | ||
384 | recalc_sigpending(); | ||
385 | spin_unlock_irq(¤t->sighand->siglock); | ||
386 | |||
387 | set_current_state(TASK_INTERRUPTIBLE); | ||
388 | add_wait_queue(&ftape_wait_intr, &wait); | ||
389 | while (!ft_interrupt_seen && timeout) | ||
390 | timeout = schedule_timeout_interruptible(timeout); | ||
391 | |||
392 | spin_lock_irq(¤t->sighand->siglock); | ||
393 | current->blocked = old_sigmask; | ||
394 | recalc_sigpending(); | ||
395 | spin_unlock_irq(¤t->sighand->siglock); | ||
396 | |||
397 | remove_wait_queue(&ftape_wait_intr, &wait); | ||
398 | /* the following IS necessary. True: as well | ||
399 | * wake_up_interruptible() as the schedule() set TASK_RUNNING | ||
400 | * when they wakeup a task, BUT: it may very well be that | ||
401 | * ft_interrupt_seen is already set to 1 when we enter here | ||
402 | * in which case schedule() gets never called, and | ||
403 | * TASK_RUNNING never set. This has the funny effect that we | ||
404 | * execute all the code until we leave kernel space, but then | ||
405 | * the task is stopped (a task CANNOT be preempted while in | ||
406 | * kernel mode. Sending a pair of SIGSTOP/SIGCONT to the | ||
407 | * tasks wakes it up again. Funny! :-) | ||
408 | */ | ||
409 | current->state = TASK_RUNNING; | ||
410 | if (ft_interrupt_seen) { /* woken up by interrupt */ | ||
411 | ft_interrupt_seen = 0; | ||
412 | TRACE_EXIT 0; | ||
413 | } | ||
414 | /* Original comment: | ||
415 | * In first instance, next statement seems unnecessary since | ||
416 | * it will be cleared in fdc_command. However, a small part of | ||
417 | * the software seems to rely on this being cleared here | ||
418 | * (ftape_close might fail) so stick to it until things get fixed ! | ||
419 | */ | ||
420 | /* My deeply sought of knowledge: | ||
421 | * Behold NO! It is obvious. fdc_reset() doesn't call fdc_command() | ||
422 | * but nevertheless uses fdc_interrupt_wait(). OF COURSE this needs to | ||
423 | * be reset here. | ||
424 | */ | ||
425 | ft_interrupt_seen = 0; /* clear for next call */ | ||
426 | if (!resetting) { | ||
427 | resetting = 1; /* break infinite recursion if reset fails */ | ||
428 | TRACE(ft_t_any, "cleanup reset"); | ||
429 | fdc_reset(); | ||
430 | resetting = 0; | ||
431 | } | ||
432 | TRACE_EXIT (signal_pending(current)) ? -EINTR : -ETIME; | ||
433 | } | ||
434 | |||
435 | /* Start/stop drive motor. Enable DMA mode. | ||
436 | */ | ||
437 | void fdc_motor(int motor) | ||
438 | { | ||
439 | int unit = ft_drive_sel; | ||
440 | int data = unit | FDC_RESET_NOT | FDC_DMA_MODE; | ||
441 | TRACE_FUN(ft_t_any); | ||
442 | |||
443 | ftape_motor = motor; | ||
444 | if (ftape_motor) { | ||
445 | data |= FDC_MOTOR_0 << unit; | ||
446 | TRACE(ft_t_noise, "turning motor %d on", unit); | ||
447 | } else { | ||
448 | TRACE(ft_t_noise, "turning motor %d off", unit); | ||
449 | } | ||
450 | if (ft_mach2) { | ||
451 | outb_p(data, fdc.dor2); | ||
452 | } else { | ||
453 | outb_p(data, fdc.dor); | ||
454 | } | ||
455 | ftape_sleep(10 * FT_MILLISECOND); | ||
456 | TRACE_EXIT; | ||
457 | } | ||
458 | |||
459 | static void fdc_update_dsr(void) | ||
460 | { | ||
461 | TRACE_FUN(ft_t_any); | ||
462 | |||
463 | TRACE(ft_t_flow, "rate = %d Kbps, precomp = %d ns", | ||
464 | fdc_data_rate, fdc_precomp); | ||
465 | if (fdc.type >= i82077) { | ||
466 | outb_p((fdc_rate_code & 0x03) | fdc_prec_code, fdc.dsr); | ||
467 | } else { | ||
468 | outb_p(fdc_rate_code & 0x03, fdc.ccr); | ||
469 | } | ||
470 | TRACE_EXIT; | ||
471 | } | ||
472 | |||
473 | void fdc_set_write_precomp(int precomp) | ||
474 | { | ||
475 | TRACE_FUN(ft_t_any); | ||
476 | |||
477 | TRACE(ft_t_noise, "New precomp: %d nsec", precomp); | ||
478 | fdc_precomp = precomp; | ||
479 | /* write precompensation can be set in multiples of 41.67 nsec. | ||
480 | * round the parameter to the nearest multiple and convert it | ||
481 | * into a fdc setting. Note that 0 means default to the fdc, | ||
482 | * 7 is used instead of that. | ||
483 | */ | ||
484 | fdc_prec_code = ((fdc_precomp + 21) / 42) << 2; | ||
485 | if (fdc_prec_code == 0 || fdc_prec_code > (6 << 2)) { | ||
486 | fdc_prec_code = 7 << 2; | ||
487 | } | ||
488 | fdc_update_dsr(); | ||
489 | TRACE_EXIT; | ||
490 | } | ||
491 | |||
492 | /* Reprogram the 82078 registers to use Data Rate Table 1 on all drives. | ||
493 | */ | ||
494 | static void fdc_set_drive_specs(void) | ||
495 | { | ||
496 | __u8 cmd[] = { FDC_DRIVE_SPEC, 0x00, 0x00, 0x00, 0x00, 0xc0}; | ||
497 | int result; | ||
498 | TRACE_FUN(ft_t_any); | ||
499 | |||
500 | TRACE(ft_t_flow, "Setting of drive specs called"); | ||
501 | if (fdc.type >= i82078_1) { | ||
502 | cmd[1] = (0 << 5) | (2 << 2); | ||
503 | cmd[2] = (1 << 5) | (2 << 2); | ||
504 | cmd[3] = (2 << 5) | (2 << 2); | ||
505 | cmd[4] = (3 << 5) | (2 << 2); | ||
506 | result = fdc_command(cmd, NR_ITEMS(cmd)); | ||
507 | if (result < 0) { | ||
508 | TRACE(ft_t_err, "Setting of drive specs failed"); | ||
509 | } | ||
510 | } | ||
511 | TRACE_EXIT; | ||
512 | } | ||
513 | |||
514 | /* Select clock for fdc, must correspond with tape drive setting ! | ||
515 | * This also influences the fdc timing so we must adjust some values. | ||
516 | */ | ||
517 | int fdc_set_data_rate(int rate) | ||
518 | { | ||
519 | int bad_rate = 0; | ||
520 | TRACE_FUN(ft_t_any); | ||
521 | |||
522 | /* Select clock for fdc, must correspond with tape drive setting ! | ||
523 | * This also influences the fdc timing so we must adjust some values. | ||
524 | */ | ||
525 | TRACE(ft_t_fdc_dma, "new rate = %d", rate); | ||
526 | switch (rate) { | ||
527 | case 250: | ||
528 | fdc_rate_code = fdc_data_rate_250; | ||
529 | break; | ||
530 | case 500: | ||
531 | fdc_rate_code = fdc_data_rate_500; | ||
532 | break; | ||
533 | case 1000: | ||
534 | if (fdc.type < i82077) { | ||
535 | bad_rate = 1; | ||
536 | } else { | ||
537 | fdc_rate_code = fdc_data_rate_1000; | ||
538 | } | ||
539 | break; | ||
540 | case 2000: | ||
541 | if (fdc.type < i82078_1) { | ||
542 | bad_rate = 1; | ||
543 | } else { | ||
544 | fdc_rate_code = fdc_data_rate_2000; | ||
545 | } | ||
546 | break; | ||
547 | default: | ||
548 | bad_rate = 1; | ||
549 | } | ||
550 | if (bad_rate) { | ||
551 | TRACE_ABORT(-EIO, | ||
552 | ft_t_fdc_dma, "%d is not a valid data rate", rate); | ||
553 | } | ||
554 | fdc_data_rate = rate; | ||
555 | fdc_update_dsr(); | ||
556 | fdc_set_seek_rate(fdc_seek_rate); /* clock changed! */ | ||
557 | ftape_udelay(1000); | ||
558 | TRACE_EXIT 0; | ||
559 | } | ||
560 | |||
561 | /* keep the unit select if keep_select is != 0, | ||
562 | */ | ||
563 | static void fdc_dor_reset(int keep_select) | ||
564 | { | ||
565 | __u8 fdc_ctl = ft_drive_sel; | ||
566 | |||
567 | if (keep_select != 0) { | ||
568 | fdc_ctl |= FDC_DMA_MODE; | ||
569 | if (ftape_motor) { | ||
570 | fdc_ctl |= FDC_MOTOR_0 << ft_drive_sel; | ||
571 | } | ||
572 | } | ||
573 | ftape_udelay(10); /* ??? but seems to be necessary */ | ||
574 | if (ft_mach2) { | ||
575 | outb_p(fdc_ctl & 0x0f, fdc.dor); | ||
576 | outb_p(fdc_ctl, fdc.dor2); | ||
577 | } else { | ||
578 | outb_p(fdc_ctl, fdc.dor); | ||
579 | } | ||
580 | fdc_usec_wait(10); /* delay >= 14 fdc clocks */ | ||
581 | if (keep_select == 0) { | ||
582 | fdc_ctl = 0; | ||
583 | } | ||
584 | fdc_ctl |= FDC_RESET_NOT; | ||
585 | if (ft_mach2) { | ||
586 | outb_p(fdc_ctl & 0x0f, fdc.dor); | ||
587 | outb_p(fdc_ctl, fdc.dor2); | ||
588 | } else { | ||
589 | outb_p(fdc_ctl, fdc.dor); | ||
590 | } | ||
591 | } | ||
592 | |||
593 | /* Reset the floppy disk controller. Leave the ftape_unit selected. | ||
594 | */ | ||
595 | void fdc_reset(void) | ||
596 | { | ||
597 | int st0; | ||
598 | int i; | ||
599 | int dummy; | ||
600 | unsigned long flags; | ||
601 | TRACE_FUN(ft_t_any); | ||
602 | |||
603 | spin_lock_irqsave(&fdc_io_lock, flags); | ||
604 | |||
605 | fdc_dor_reset(1); /* keep unit selected */ | ||
606 | |||
607 | fdc_mode = fdc_idle; | ||
608 | |||
609 | /* maybe the spin_lock_irq* pair is not necessary, BUT: | ||
610 | * the following line MUST be here. Otherwise fdc_interrupt_wait() | ||
611 | * won't wait. Note that fdc_reset() is called from | ||
612 | * ftape_dumb_stop() when the fdc is busy transferring data. In this | ||
613 | * case fdc_isr() MOST PROBABLY sets ft_interrupt_seen, and tries | ||
614 | * to get the result bytes from the fdc etc. CLASH. | ||
615 | */ | ||
616 | ft_interrupt_seen = 0; | ||
617 | |||
618 | /* Program data rate | ||
619 | */ | ||
620 | fdc_update_dsr(); /* restore data rate and precomp */ | ||
621 | |||
622 | spin_unlock_irqrestore(&fdc_io_lock, flags); | ||
623 | |||
624 | /* | ||
625 | * Wait for first polling cycle to complete | ||
626 | */ | ||
627 | if (fdc_interrupt_wait(1 * FT_SECOND) < 0) { | ||
628 | TRACE(ft_t_err, "no drive polling interrupt!"); | ||
629 | } else { /* clear all disk-changed statuses */ | ||
630 | for (i = 0; i < 4; ++i) { | ||
631 | if(fdc_sense_interrupt_status(&st0, &dummy) != 0) { | ||
632 | TRACE(ft_t_err, "sense failed for %d", i); | ||
633 | } | ||
634 | if (i == ft_drive_sel) { | ||
635 | ftape_current_cylinder = dummy; | ||
636 | } | ||
637 | } | ||
638 | TRACE(ft_t_noise, "drive polling completed"); | ||
639 | } | ||
640 | /* | ||
641 | * SPECIFY COMMAND | ||
642 | */ | ||
643 | fdc_set_seek_rate(fdc_seek_rate); | ||
644 | /* | ||
645 | * DRIVE SPECIFICATION COMMAND (if fdc type known) | ||
646 | */ | ||
647 | if (fdc.type >= i82078_1) { | ||
648 | fdc_set_drive_specs(); | ||
649 | } | ||
650 | TRACE_EXIT; | ||
651 | } | ||
652 | |||
653 | #if !defined(CLK_48MHZ) | ||
654 | # define CLK_48MHZ 1 | ||
655 | #endif | ||
656 | |||
657 | /* When we're done, put the fdc into reset mode so that the regular | ||
658 | * floppy disk driver will figure out that something is wrong and | ||
659 | * initialize the controller the way it wants. | ||
660 | */ | ||
661 | void fdc_disable(void) | ||
662 | { | ||
663 | __u8 cmd1[] = {FDC_CONFIGURE, 0x00, 0x00, 0x00}; | ||
664 | __u8 cmd2[] = {FDC_LOCK}; | ||
665 | __u8 cmd3[] = {FDC_UNLOCK}; | ||
666 | __u8 stat[1]; | ||
667 | TRACE_FUN(ft_t_flow); | ||
668 | |||
669 | if (!fdc_fifo_locked) { | ||
670 | fdc_reset(); | ||
671 | TRACE_EXIT; | ||
672 | } | ||
673 | if (fdc_issue_command(cmd3, 1, stat, 1) < 0 || stat[0] != 0x00) { | ||
674 | fdc_dor_reset(0); | ||
675 | TRACE_ABORT(/**/, ft_t_bug, | ||
676 | "couldn't unlock fifo, configuration remains changed"); | ||
677 | } | ||
678 | fdc_fifo_locked = 0; | ||
679 | if (CLK_48MHZ && fdc.type >= i82078) { | ||
680 | cmd1[0] |= FDC_CLK48_BIT; | ||
681 | } | ||
682 | cmd1[2] = ((fdc_fifo_state) ? 0 : 0x20) + (fdc_fifo_thr - 1); | ||
683 | if (fdc_command(cmd1, NR_ITEMS(cmd1)) < 0) { | ||
684 | fdc_dor_reset(0); | ||
685 | TRACE_ABORT(/**/, ft_t_bug, | ||
686 | "couldn't reconfigure fifo to old state"); | ||
687 | } | ||
688 | if (fdc_lock_state && | ||
689 | fdc_issue_command(cmd2, 1, stat, 1) < 0) { | ||
690 | fdc_dor_reset(0); | ||
691 | TRACE_ABORT(/**/, ft_t_bug, "couldn't lock old state again"); | ||
692 | } | ||
693 | TRACE(ft_t_noise, "fifo restored: %sabled, thr. %d, %slocked", | ||
694 | fdc_fifo_state ? "en" : "dis", | ||
695 | fdc_fifo_thr, (fdc_lock_state) ? "" : "not "); | ||
696 | fdc_dor_reset(0); | ||
697 | TRACE_EXIT; | ||
698 | } | ||
699 | |||
700 | /* Specify FDC seek-rate (milliseconds) | ||
701 | */ | ||
702 | static int fdc_set_seek_rate(int seek_rate) | ||
703 | { | ||
704 | /* set step rate, dma mode, and minimal head load and unload times | ||
705 | */ | ||
706 | __u8 in[3] = { FDC_SPECIFY, 1, (1 << 1)}; | ||
707 | |||
708 | fdc_seek_rate = seek_rate; | ||
709 | in[1] |= (16 - (fdc_data_rate * fdc_seek_rate) / 500) << 4; | ||
710 | |||
711 | return fdc_command(in, 3); | ||
712 | } | ||
713 | |||
714 | /* Sense drive status: get unit's drive status (ST3) | ||
715 | */ | ||
716 | int fdc_sense_drive_status(int *st3) | ||
717 | { | ||
718 | __u8 out[2]; | ||
719 | __u8 in[1]; | ||
720 | TRACE_FUN(ft_t_any); | ||
721 | |||
722 | out[0] = FDC_SENSED; | ||
723 | out[1] = ft_drive_sel; | ||
724 | TRACE_CATCH(fdc_issue_command(out, 2, in, 1),); | ||
725 | *st3 = in[0]; | ||
726 | TRACE_EXIT 0; | ||
727 | } | ||
728 | |||
729 | /* Sense Interrupt Status command: | ||
730 | * should be issued at the end of each seek. | ||
731 | * get ST0 and current cylinder. | ||
732 | */ | ||
733 | int fdc_sense_interrupt_status(int *st0, int *current_cylinder) | ||
734 | { | ||
735 | __u8 out[1]; | ||
736 | __u8 in[2]; | ||
737 | TRACE_FUN(ft_t_any); | ||
738 | |||
739 | out[0] = FDC_SENSEI; | ||
740 | TRACE_CATCH(fdc_issue_command(out, 1, in, 2),); | ||
741 | *st0 = in[0]; | ||
742 | *current_cylinder = in[1]; | ||
743 | TRACE_EXIT 0; | ||
744 | } | ||
745 | |||
746 | /* step to track | ||
747 | */ | ||
748 | int fdc_seek(int track) | ||
749 | { | ||
750 | __u8 out[3]; | ||
751 | int st0, pcn; | ||
752 | #ifdef TESTING | ||
753 | unsigned int time; | ||
754 | #endif | ||
755 | TRACE_FUN(ft_t_any); | ||
756 | |||
757 | out[0] = FDC_SEEK; | ||
758 | out[1] = ft_drive_sel; | ||
759 | out[2] = track; | ||
760 | #ifdef TESTING | ||
761 | time = ftape_timestamp(); | ||
762 | #endif | ||
763 | /* We really need this command to work ! | ||
764 | */ | ||
765 | ft_seek_completed = 0; | ||
766 | TRACE_CATCH(fdc_command(out, 3), | ||
767 | fdc_reset(); | ||
768 | TRACE(ft_t_noise, "destination was: %d, resetting FDC...", | ||
769 | track)); | ||
770 | /* Handle interrupts until ft_seek_completed or timeout. | ||
771 | */ | ||
772 | for (;;) { | ||
773 | TRACE_CATCH(fdc_interrupt_wait(2 * FT_SECOND),); | ||
774 | if (ft_seek_completed) { | ||
775 | TRACE_CATCH(fdc_sense_interrupt_status(&st0, &pcn),); | ||
776 | if ((st0 & ST0_SEEK_END) == 0) { | ||
777 | TRACE_ABORT(-EIO, ft_t_err, | ||
778 | "no seek-end after seek completion !??"); | ||
779 | } | ||
780 | break; | ||
781 | } | ||
782 | } | ||
783 | #ifdef TESTING | ||
784 | time = ftape_timediff(time, ftape_timestamp()) / abs(track - ftape_current_cylinder); | ||
785 | if ((time < 900 || time > 3100) && abs(track - ftape_current_cylinder) > 5) { | ||
786 | TRACE(ft_t_warn, "Wrong FDC STEP interval: %d usecs (%d)", | ||
787 | time, track - ftape_current_cylinder); | ||
788 | } | ||
789 | #endif | ||
790 | /* Verify whether we issued the right tape command. | ||
791 | */ | ||
792 | /* Verify that we seek to the proper track. */ | ||
793 | if (pcn != track) { | ||
794 | TRACE_ABORT(-EIO, ft_t_err, "bad seek.."); | ||
795 | } | ||
796 | ftape_current_cylinder = track; | ||
797 | TRACE_EXIT 0; | ||
798 | } | ||
799 | |||
800 | static int perpend_mode; /* set if fdc is in perpendicular mode */ | ||
801 | |||
802 | static int perpend_off(void) | ||
803 | { | ||
804 | __u8 perpend[] = {FDC_PERPEND, 0x00}; | ||
805 | TRACE_FUN(ft_t_any); | ||
806 | |||
807 | if (perpend_mode) { | ||
808 | /* Turn off perpendicular mode */ | ||
809 | perpend[1] = 0x80; | ||
810 | TRACE_CATCH(fdc_command(perpend, 2), | ||
811 | TRACE(ft_t_err,"Perpendicular mode exit failed!")); | ||
812 | perpend_mode = 0; | ||
813 | } | ||
814 | TRACE_EXIT 0; | ||
815 | } | ||
816 | |||
817 | static int handle_perpend(int segment_id) | ||
818 | { | ||
819 | __u8 perpend[] = {FDC_PERPEND, 0x00}; | ||
820 | TRACE_FUN(ft_t_any); | ||
821 | |||
822 | /* When writing QIC-3020 tapes, turn on perpendicular mode | ||
823 | * if tape is moving in forward direction (even tracks). | ||
824 | */ | ||
825 | if (ft_qic_std == QIC_TAPE_QIC3020 && | ||
826 | ((segment_id / ft_segments_per_track) & 1) == 0) { | ||
827 | /* FIXME: some i82077 seem to support perpendicular mode as | ||
828 | * well. | ||
829 | */ | ||
830 | #if 0 | ||
831 | if (fdc.type < i82077AA) {} | ||
832 | #else | ||
833 | if (fdc.type < i82077 && ft_data_rate < 1000) { | ||
834 | #endif | ||
835 | /* fdc does not support perpendicular mode: complain | ||
836 | */ | ||
837 | TRACE_ABORT(-EIO, ft_t_err, | ||
838 | "Your FDC does not support QIC-3020."); | ||
839 | } | ||
840 | perpend[1] = 0x03 /* 0x83 + (0x4 << ft_drive_sel) */ ; | ||
841 | TRACE_CATCH(fdc_command(perpend, 2), | ||
842 | TRACE(ft_t_err,"Perpendicular mode entry failed!")); | ||
843 | TRACE(ft_t_flow, "Perpendicular mode set"); | ||
844 | perpend_mode = 1; | ||
845 | TRACE_EXIT 0; | ||
846 | } | ||
847 | TRACE_EXIT perpend_off(); | ||
848 | } | ||
849 | |||
850 | static inline void fdc_setup_dma(char mode, | ||
851 | volatile void *addr, unsigned int count) | ||
852 | { | ||
853 | /* Program the DMA controller. | ||
854 | */ | ||
855 | disable_dma(fdc.dma); | ||
856 | clear_dma_ff(fdc.dma); | ||
857 | set_dma_mode(fdc.dma, mode); | ||
858 | set_dma_addr(fdc.dma, virt_to_bus((void*)addr)); | ||
859 | set_dma_count(fdc.dma, count); | ||
860 | enable_dma(fdc.dma); | ||
861 | } | ||
862 | |||
863 | /* Setup fdc and dma for formatting the next segment | ||
864 | */ | ||
865 | int fdc_setup_formatting(buffer_struct * buff) | ||
866 | { | ||
867 | unsigned long flags; | ||
868 | __u8 out[6] = { | ||
869 | FDC_FORMAT, 0x00, 3, 4 * FT_SECTORS_PER_SEGMENT, 0x00, 0x6b | ||
870 | }; | ||
871 | TRACE_FUN(ft_t_any); | ||
872 | |||
873 | TRACE_CATCH(handle_perpend(buff->segment_id),); | ||
874 | /* Program the DMA controller. | ||
875 | */ | ||
876 | TRACE(ft_t_fdc_dma, | ||
877 | "phys. addr. = %lx", virt_to_bus((void*) buff->ptr)); | ||
878 | spin_lock_irqsave(&fdc_io_lock, flags); | ||
879 | fdc_setup_dma(DMA_MODE_WRITE, buff->ptr, FT_SECTORS_PER_SEGMENT * 4); | ||
880 | /* Issue FDC command to start reading/writing. | ||
881 | */ | ||
882 | out[1] = ft_drive_sel; | ||
883 | out[4] = buff->gap3; | ||
884 | TRACE_CATCH(fdc_setup_error = fdc_command(out, sizeof(out)), | ||
885 | restore_flags(flags); fdc_mode = fdc_idle); | ||
886 | spin_unlock_irqrestore(&fdc_io_lock, flags); | ||
887 | TRACE_EXIT 0; | ||
888 | } | ||
889 | |||
890 | |||
891 | /* Setup Floppy Disk Controller and DMA to read or write the next cluster | ||
892 | * of good sectors from or to the current segment. | ||
893 | */ | ||
894 | int fdc_setup_read_write(buffer_struct * buff, __u8 operation) | ||
895 | { | ||
896 | unsigned long flags; | ||
897 | __u8 out[9]; | ||
898 | int dma_mode; | ||
899 | TRACE_FUN(ft_t_any); | ||
900 | |||
901 | switch(operation) { | ||
902 | case FDC_VERIFY: | ||
903 | if (fdc.type < i82077) { | ||
904 | operation = FDC_READ; | ||
905 | } | ||
906 | case FDC_READ: | ||
907 | case FDC_READ_DELETED: | ||
908 | dma_mode = DMA_MODE_READ; | ||
909 | TRACE(ft_t_fdc_dma, "xfer %d sectors to 0x%p", | ||
910 | buff->sector_count, buff->ptr); | ||
911 | TRACE_CATCH(perpend_off(),); | ||
912 | break; | ||
913 | case FDC_WRITE_DELETED: | ||
914 | TRACE(ft_t_noise, "deleting segment %d", buff->segment_id); | ||
915 | case FDC_WRITE: | ||
916 | dma_mode = DMA_MODE_WRITE; | ||
917 | /* When writing QIC-3020 tapes, turn on perpendicular mode | ||
918 | * if tape is moving in forward direction (even tracks). | ||
919 | */ | ||
920 | TRACE_CATCH(handle_perpend(buff->segment_id),); | ||
921 | TRACE(ft_t_fdc_dma, "xfer %d sectors from 0x%p", | ||
922 | buff->sector_count, buff->ptr); | ||
923 | break; | ||
924 | default: | ||
925 | TRACE_ABORT(-EIO, | ||
926 | ft_t_bug, "bug: invalid operation parameter"); | ||
927 | } | ||
928 | TRACE(ft_t_fdc_dma, "phys. addr. = %lx",virt_to_bus((void*)buff->ptr)); | ||
929 | spin_lock_irqsave(&fdc_io_lock, flags); | ||
930 | if (operation != FDC_VERIFY) { | ||
931 | fdc_setup_dma(dma_mode, buff->ptr, | ||
932 | FT_SECTOR_SIZE * buff->sector_count); | ||
933 | } | ||
934 | /* Issue FDC command to start reading/writing. | ||
935 | */ | ||
936 | out[0] = operation; | ||
937 | out[1] = ft_drive_sel; | ||
938 | out[2] = buff->cyl; | ||
939 | out[3] = buff->head; | ||
940 | out[4] = buff->sect + buff->sector_offset; | ||
941 | out[5] = 3; /* Sector size of 1K. */ | ||
942 | out[6] = out[4] + buff->sector_count - 1; /* last sector */ | ||
943 | out[7] = 109; /* Gap length. */ | ||
944 | out[8] = 0xff; /* No limit to transfer size. */ | ||
945 | TRACE(ft_t_fdc_dma, "C: 0x%02x, H: 0x%02x, R: 0x%02x, cnt: 0x%02x", | ||
946 | out[2], out[3], out[4], out[6] - out[4] + 1); | ||
947 | spin_unlock_irqrestore(&fdc_io_lock, flags); | ||
948 | TRACE_CATCH(fdc_setup_error = fdc_command(out, 9),fdc_mode = fdc_idle); | ||
949 | TRACE_EXIT 0; | ||
950 | } | ||
951 | |||
952 | int fdc_fifo_threshold(__u8 threshold, | ||
953 | int *fifo_state, int *lock_state, int *fifo_thr) | ||
954 | { | ||
955 | const __u8 cmd0[] = {FDC_DUMPREGS}; | ||
956 | __u8 cmd1[] = {FDC_CONFIGURE, 0, (0x0f & (threshold - 1)), 0}; | ||
957 | const __u8 cmd2[] = {FDC_LOCK}; | ||
958 | const __u8 cmd3[] = {FDC_UNLOCK}; | ||
959 | __u8 reg[10]; | ||
960 | __u8 stat; | ||
961 | int i; | ||
962 | int result; | ||
963 | TRACE_FUN(ft_t_any); | ||
964 | |||
965 | if (CLK_48MHZ && fdc.type >= i82078) { | ||
966 | cmd1[0] |= FDC_CLK48_BIT; | ||
967 | } | ||
968 | /* Dump fdc internal registers for examination | ||
969 | */ | ||
970 | TRACE_CATCH(fdc_command(cmd0, NR_ITEMS(cmd0)), | ||
971 | TRACE(ft_t_warn, "dumpreg cmd failed, fifo unchanged")); | ||
972 | /* Now read fdc internal registers from fifo | ||
973 | */ | ||
974 | for (i = 0; i < (int)NR_ITEMS(reg); ++i) { | ||
975 | fdc_read(®[i]); | ||
976 | TRACE(ft_t_fdc_dma, "Register %d = 0x%02x", i, reg[i]); | ||
977 | } | ||
978 | if (fifo_state && lock_state && fifo_thr) { | ||
979 | *fifo_state = (reg[8] & 0x20) == 0; | ||
980 | *lock_state = reg[7] & 0x80; | ||
981 | *fifo_thr = 1 + (reg[8] & 0x0f); | ||
982 | } | ||
983 | TRACE(ft_t_noise, | ||
984 | "original fifo state: %sabled, threshold %d, %slocked", | ||
985 | ((reg[8] & 0x20) == 0) ? "en" : "dis", | ||
986 | 1 + (reg[8] & 0x0f), (reg[7] & 0x80) ? "" : "not "); | ||
987 | /* If fdc is already locked, unlock it first ! */ | ||
988 | if (reg[7] & 0x80) { | ||
989 | fdc_ready_wait(100); | ||
990 | TRACE_CATCH(fdc_issue_command(cmd3, NR_ITEMS(cmd3), &stat, 1), | ||
991 | TRACE(ft_t_bug, "FDC unlock command failed, " | ||
992 | "configuration unchanged")); | ||
993 | } | ||
994 | fdc_fifo_locked = 0; | ||
995 | /* Enable fifo and set threshold at xx bytes to allow a | ||
996 | * reasonably large latency and reduce number of dma bursts. | ||
997 | */ | ||
998 | fdc_ready_wait(100); | ||
999 | if ((result = fdc_command(cmd1, NR_ITEMS(cmd1))) < 0) { | ||
1000 | TRACE(ft_t_bug, "configure cmd failed, fifo unchanged"); | ||
1001 | } | ||
1002 | /* Now lock configuration so reset will not change it | ||
1003 | */ | ||
1004 | if(fdc_issue_command(cmd2, NR_ITEMS(cmd2), &stat, 1) < 0 || | ||
1005 | stat != 0x10) { | ||
1006 | TRACE_ABORT(-EIO, ft_t_bug, | ||
1007 | "FDC lock command failed, stat = 0x%02x", stat); | ||
1008 | } | ||
1009 | fdc_fifo_locked = 1; | ||
1010 | TRACE_EXIT result; | ||
1011 | } | ||
1012 | |||
1013 | static int fdc_fifo_enable(void) | ||
1014 | { | ||
1015 | TRACE_FUN(ft_t_any); | ||
1016 | |||
1017 | if (fdc_fifo_locked) { | ||
1018 | TRACE_ABORT(0, ft_t_warn, "Fifo not enabled because locked"); | ||
1019 | } | ||
1020 | TRACE_CATCH(fdc_fifo_threshold(ft_fdc_threshold /* bytes */, | ||
1021 | &fdc_fifo_state, | ||
1022 | &fdc_lock_state, | ||
1023 | &fdc_fifo_thr),); | ||
1024 | TRACE_CATCH(fdc_fifo_threshold(ft_fdc_threshold /* bytes */, | ||
1025 | NULL, NULL, NULL),); | ||
1026 | TRACE_EXIT 0; | ||
1027 | } | ||
1028 | |||
1029 | /* Determine fd controller type | ||
1030 | */ | ||
1031 | static __u8 fdc_save_state[2]; | ||
1032 | |||
1033 | static int fdc_probe(void) | ||
1034 | { | ||
1035 | __u8 cmd[1]; | ||
1036 | __u8 stat[16]; /* must be able to hold dumpregs & save results */ | ||
1037 | int i; | ||
1038 | TRACE_FUN(ft_t_any); | ||
1039 | |||
1040 | /* Try to find out what kind of fd controller we have to deal with | ||
1041 | * Scheme borrowed from floppy driver: | ||
1042 | * first try if FDC_DUMPREGS command works | ||
1043 | * (this indicates that we have a 82072 or better) | ||
1044 | * then try the FDC_VERSION command (82072 doesn't support this) | ||
1045 | * then try the FDC_UNLOCK command (some older 82077's don't support this) | ||
1046 | * then try the FDC_PARTID command (82078's support this) | ||
1047 | */ | ||
1048 | cmd[0] = FDC_DUMPREGS; | ||
1049 | if (fdc_issue_command(cmd, 1, stat, 1) != 0) { | ||
1050 | TRACE_ABORT(no_fdc, ft_t_bug, "No FDC found"); | ||
1051 | } | ||
1052 | if (stat[0] == 0x80) { | ||
1053 | /* invalid command: must be pre 82072 */ | ||
1054 | TRACE_ABORT(i8272, | ||
1055 | ft_t_warn, "Type 8272A/765A compatible FDC found"); | ||
1056 | } | ||
1057 | fdc_result(&stat[1], 9); | ||
1058 | fdc_save_state[0] = stat[7]; | ||
1059 | fdc_save_state[1] = stat[8]; | ||
1060 | cmd[0] = FDC_VERSION; | ||
1061 | if (fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] == 0x80) { | ||
1062 | TRACE_ABORT(i8272, ft_t_warn, "Type 82072 FDC found"); | ||
1063 | } | ||
1064 | if (*stat != 0x90) { | ||
1065 | TRACE_ABORT(i8272, ft_t_warn, "Unknown FDC found"); | ||
1066 | } | ||
1067 | cmd[0] = FDC_UNLOCK; | ||
1068 | if(fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] != 0x00) { | ||
1069 | TRACE_ABORT(i8272, ft_t_warn, | ||
1070 | "Type pre-1991 82077 FDC found, " | ||
1071 | "treating it like a 82072"); | ||
1072 | } | ||
1073 | if (fdc_save_state[0] & 0x80) { /* was locked */ | ||
1074 | cmd[0] = FDC_LOCK; /* restore lock */ | ||
1075 | (void)fdc_issue_command(cmd, 1, stat, 1); | ||
1076 | TRACE(ft_t_warn, "FDC is already locked"); | ||
1077 | } | ||
1078 | /* Test for a i82078 FDC */ | ||
1079 | cmd[0] = FDC_PARTID; | ||
1080 | if (fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] == 0x80) { | ||
1081 | /* invalid command: not a i82078xx type FDC */ | ||
1082 | for (i = 0; i < 4; ++i) { | ||
1083 | outb_p(i, fdc.tdr); | ||
1084 | if ((inb_p(fdc.tdr) & 0x03) != i) { | ||
1085 | TRACE_ABORT(i82077, | ||
1086 | ft_t_warn, "Type 82077 FDC found"); | ||
1087 | } | ||
1088 | } | ||
1089 | TRACE_ABORT(i82077AA, ft_t_warn, "Type 82077AA FDC found"); | ||
1090 | } | ||
1091 | /* FDC_PARTID cmd succeeded */ | ||
1092 | switch (stat[0] >> 5) { | ||
1093 | case 0x0: | ||
1094 | /* i82078SL or i82078-1. The SL part cannot run at | ||
1095 | * 2Mbps (the SL and -1 dies are identical; they are | ||
1096 | * speed graded after production, according to Intel). | ||
1097 | * Some SL's can be detected by doing a SAVE cmd and | ||
1098 | * look at bit 7 of the first byte (the SEL3V# bit). | ||
1099 | * If it is 0, the part runs off 3Volts, and hence it | ||
1100 | * is a SL. | ||
1101 | */ | ||
1102 | cmd[0] = FDC_SAVE; | ||
1103 | if(fdc_issue_command(cmd, 1, stat, 16) < 0) { | ||
1104 | TRACE(ft_t_err, "FDC_SAVE failed. Dunno why"); | ||
1105 | /* guess we better claim the fdc to be a i82078 */ | ||
1106 | TRACE_ABORT(i82078, | ||
1107 | ft_t_warn, | ||
1108 | "Type i82078 FDC (i suppose) found"); | ||
1109 | } | ||
1110 | if ((stat[0] & FDC_SEL3V_BIT)) { | ||
1111 | /* fdc running off 5Volts; Pray that it's a i82078-1 | ||
1112 | */ | ||
1113 | TRACE_ABORT(i82078_1, ft_t_warn, | ||
1114 | "Type i82078-1 or 5Volt i82078SL FDC found"); | ||
1115 | } | ||
1116 | TRACE_ABORT(i82078, ft_t_warn, | ||
1117 | "Type 3Volt i82078SL FDC (1Mbps) found"); | ||
1118 | case 0x1: | ||
1119 | case 0x2: /* S82078B */ | ||
1120 | /* The '78B isn't '78 compatible. Detect it as a '77AA */ | ||
1121 | TRACE_ABORT(i82077AA, ft_t_warn, "Type i82077AA FDC found"); | ||
1122 | case 0x3: /* NSC PC8744 core; used in several super-IO chips */ | ||
1123 | TRACE_ABORT(i82077AA, | ||
1124 | ft_t_warn, "Type 82077AA compatible FDC found"); | ||
1125 | default: | ||
1126 | TRACE(ft_t_warn, "A previously undetected FDC found"); | ||
1127 | TRACE_ABORT(i82077AA, ft_t_warn, | ||
1128 | "Treating it as a 82077AA. Please report partid= %d", | ||
1129 | stat[0]); | ||
1130 | } /* switch(stat[ 0] >> 5) */ | ||
1131 | TRACE_EXIT no_fdc; | ||
1132 | } | ||
1133 | |||
1134 | static int fdc_request_regions(void) | ||
1135 | { | ||
1136 | TRACE_FUN(ft_t_flow); | ||
1137 | |||
1138 | if (ft_mach2 || ft_probe_fc10) { | ||
1139 | if (!request_region(fdc.sra, 8, "fdc (ft)")) { | ||
1140 | #ifndef BROKEN_FLOPPY_DRIVER | ||
1141 | TRACE_EXIT -EBUSY; | ||
1142 | #else | ||
1143 | TRACE(ft_t_warn, | ||
1144 | "address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); | ||
1145 | #endif | ||
1146 | } | ||
1147 | } else { | ||
1148 | if (!request_region(fdc.sra, 6, "fdc (ft)")) { | ||
1149 | #ifndef BROKEN_FLOPPY_DRIVER | ||
1150 | TRACE_EXIT -EBUSY; | ||
1151 | #else | ||
1152 | TRACE(ft_t_warn, | ||
1153 | "address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); | ||
1154 | #endif | ||
1155 | } | ||
1156 | if (!request_region(fdc.sra + 7, 1, "fdc (ft)")) { | ||
1157 | #ifndef BROKEN_FLOPPY_DRIVER | ||
1158 | release_region(fdc.sra, 6); | ||
1159 | TRACE_EXIT -EBUSY; | ||
1160 | #else | ||
1161 | TRACE(ft_t_warn, | ||
1162 | "address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra + 7); | ||
1163 | #endif | ||
1164 | } | ||
1165 | } | ||
1166 | TRACE_EXIT 0; | ||
1167 | } | ||
1168 | |||
1169 | void fdc_release_regions(void) | ||
1170 | { | ||
1171 | TRACE_FUN(ft_t_flow); | ||
1172 | |||
1173 | if (fdc.sra != 0) { | ||
1174 | if (fdc.dor2 != 0) { | ||
1175 | release_region(fdc.sra, 8); | ||
1176 | } else { | ||
1177 | release_region(fdc.sra, 6); | ||
1178 | release_region(fdc.dir, 1); | ||
1179 | } | ||
1180 | } | ||
1181 | TRACE_EXIT; | ||
1182 | } | ||
1183 | |||
1184 | static int fdc_config_regs(unsigned int fdc_base, | ||
1185 | unsigned int fdc_irq, | ||
1186 | unsigned int fdc_dma) | ||
1187 | { | ||
1188 | TRACE_FUN(ft_t_flow); | ||
1189 | |||
1190 | fdc.irq = fdc_irq; | ||
1191 | fdc.dma = fdc_dma; | ||
1192 | fdc.sra = fdc_base; | ||
1193 | fdc.srb = fdc_base + 1; | ||
1194 | fdc.dor = fdc_base + 2; | ||
1195 | fdc.tdr = fdc_base + 3; | ||
1196 | fdc.msr = fdc.dsr = fdc_base + 4; | ||
1197 | fdc.fifo = fdc_base + 5; | ||
1198 | fdc.dir = fdc.ccr = fdc_base + 7; | ||
1199 | fdc.dor2 = (ft_mach2 || ft_probe_fc10) ? fdc_base + 6 : 0; | ||
1200 | TRACE_CATCH(fdc_request_regions(), fdc.sra = 0); | ||
1201 | TRACE_EXIT 0; | ||
1202 | } | ||
1203 | |||
1204 | static int fdc_config(void) | ||
1205 | { | ||
1206 | static int already_done; | ||
1207 | TRACE_FUN(ft_t_any); | ||
1208 | |||
1209 | if (already_done) { | ||
1210 | TRACE_CATCH(fdc_request_regions(),); | ||
1211 | *(fdc.hook) = fdc_isr; /* hook our handler in */ | ||
1212 | TRACE_EXIT 0; | ||
1213 | } | ||
1214 | if (ft_probe_fc10) { | ||
1215 | int fc_type; | ||
1216 | |||
1217 | TRACE_CATCH(fdc_config_regs(ft_fdc_base, | ||
1218 | ft_fdc_irq, ft_fdc_dma),); | ||
1219 | fc_type = fc10_enable(); | ||
1220 | if (fc_type != 0) { | ||
1221 | TRACE(ft_t_warn, "FC-%c0 controller found", '0' + fc_type); | ||
1222 | fdc.type = fc10; | ||
1223 | fdc.hook = &do_ftape; | ||
1224 | *(fdc.hook) = fdc_isr; /* hook our handler in */ | ||
1225 | already_done = 1; | ||
1226 | TRACE_EXIT 0; | ||
1227 | } else { | ||
1228 | TRACE(ft_t_warn, "FC-10/20 controller not found"); | ||
1229 | fdc_release_regions(); | ||
1230 | fdc.type = no_fdc; | ||
1231 | ft_probe_fc10 = 0; | ||
1232 | ft_fdc_base = 0x3f0; | ||
1233 | ft_fdc_irq = 6; | ||
1234 | ft_fdc_dma = 2; | ||
1235 | } | ||
1236 | } | ||
1237 | TRACE(ft_t_warn, "fdc base: 0x%x, irq: %d, dma: %d", | ||
1238 | ft_fdc_base, ft_fdc_irq, ft_fdc_dma); | ||
1239 | TRACE_CATCH(fdc_config_regs(ft_fdc_base, ft_fdc_irq, ft_fdc_dma),); | ||
1240 | fdc.hook = &do_ftape; | ||
1241 | *(fdc.hook) = fdc_isr; /* hook our handler in */ | ||
1242 | already_done = 1; | ||
1243 | TRACE_EXIT 0; | ||
1244 | } | ||
1245 | |||
1246 | static irqreturn_t ftape_interrupt(int irq, void *dev_id) | ||
1247 | { | ||
1248 | void (*handler) (void) = *fdc.hook; | ||
1249 | int handled = 0; | ||
1250 | TRACE_FUN(ft_t_any); | ||
1251 | |||
1252 | *fdc.hook = NULL; | ||
1253 | if (handler) { | ||
1254 | handled = 1; | ||
1255 | handler(); | ||
1256 | } else { | ||
1257 | TRACE(ft_t_bug, "Unexpected ftape interrupt"); | ||
1258 | } | ||
1259 | TRACE_EXIT IRQ_RETVAL(handled); | ||
1260 | } | ||
1261 | |||
1262 | static int fdc_grab_irq_and_dma(void) | ||
1263 | { | ||
1264 | TRACE_FUN(ft_t_any); | ||
1265 | |||
1266 | if (fdc.hook == &do_ftape) { | ||
1267 | /* Get fast interrupt handler. | ||
1268 | */ | ||
1269 | if (request_irq(fdc.irq, ftape_interrupt, | ||
1270 | IRQF_DISABLED, "ft", ftape_id)) { | ||
1271 | TRACE_ABORT(-EIO, ft_t_bug, | ||
1272 | "Unable to grab IRQ%d for ftape driver", | ||
1273 | fdc.irq); | ||
1274 | } | ||
1275 | if (request_dma(fdc.dma, ftape_id)) { | ||
1276 | free_irq(fdc.irq, ftape_id); | ||
1277 | TRACE_ABORT(-EIO, ft_t_bug, | ||
1278 | "Unable to grab DMA%d for ftape driver", | ||
1279 | fdc.dma); | ||
1280 | } | ||
1281 | } | ||
1282 | if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) { | ||
1283 | /* Using same dma channel or irq as standard fdc, need | ||
1284 | * to disable the dma-gate on the std fdc. This | ||
1285 | * couldn't be done in the floppy driver as some | ||
1286 | * laptops are using the dma-gate to enter a low power | ||
1287 | * or even suspended state :-( | ||
1288 | */ | ||
1289 | outb_p(FDC_RESET_NOT, 0x3f2); | ||
1290 | TRACE(ft_t_noise, "DMA-gate on standard fdc disabled"); | ||
1291 | } | ||
1292 | TRACE_EXIT 0; | ||
1293 | } | ||
1294 | |||
1295 | int fdc_release_irq_and_dma(void) | ||
1296 | { | ||
1297 | TRACE_FUN(ft_t_any); | ||
1298 | |||
1299 | if (fdc.hook == &do_ftape) { | ||
1300 | disable_dma(fdc.dma); /* just in case... */ | ||
1301 | free_dma(fdc.dma); | ||
1302 | free_irq(fdc.irq, ftape_id); | ||
1303 | } | ||
1304 | if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) { | ||
1305 | /* Using same dma channel as standard fdc, need to | ||
1306 | * disable the dma-gate on the std fdc. This couldn't | ||
1307 | * be done in the floppy driver as some laptops are | ||
1308 | * using the dma-gate to enter a low power or even | ||
1309 | * suspended state :-( | ||
1310 | */ | ||
1311 | outb_p(FDC_RESET_NOT | FDC_DMA_MODE, 0x3f2); | ||
1312 | TRACE(ft_t_noise, "DMA-gate on standard fdc enabled again"); | ||
1313 | } | ||
1314 | TRACE_EXIT 0; | ||
1315 | } | ||
1316 | |||
1317 | int fdc_init(void) | ||
1318 | { | ||
1319 | TRACE_FUN(ft_t_any); | ||
1320 | |||
1321 | /* find a FDC to use */ | ||
1322 | TRACE_CATCH(fdc_config(),); | ||
1323 | TRACE_CATCH(fdc_grab_irq_and_dma(), fdc_release_regions()); | ||
1324 | ftape_motor = 0; | ||
1325 | fdc_catch_stray_interrupts(0); /* clear number of awainted | ||
1326 | * stray interrupte | ||
1327 | */ | ||
1328 | fdc_catch_stray_interrupts(1); /* one always comes (?) */ | ||
1329 | TRACE(ft_t_flow, "resetting fdc"); | ||
1330 | fdc_set_seek_rate(2); /* use nominal QIC step rate */ | ||
1331 | fdc_reset(); /* init fdc & clear track counters */ | ||
1332 | if (fdc.type == no_fdc) { /* no FC-10 or FC-20 found */ | ||
1333 | fdc.type = fdc_probe(); | ||
1334 | fdc_reset(); /* update with new knowledge */ | ||
1335 | } | ||
1336 | if (fdc.type == no_fdc) { | ||
1337 | fdc_release_irq_and_dma(); | ||
1338 | fdc_release_regions(); | ||
1339 | TRACE_EXIT -ENXIO; | ||
1340 | } | ||
1341 | if (fdc.type >= i82077) { | ||
1342 | if (fdc_fifo_enable() < 0) { | ||
1343 | TRACE(ft_t_warn, "couldn't enable fdc fifo !"); | ||
1344 | } else { | ||
1345 | TRACE(ft_t_flow, "fdc fifo enabled and locked"); | ||
1346 | } | ||
1347 | } | ||
1348 | TRACE_EXIT 0; | ||
1349 | } | ||
diff --git a/drivers/char/ftape/lowlevel/fdc-io.h b/drivers/char/ftape/lowlevel/fdc-io.h deleted file mode 100644 index 7ec3c72178bb..000000000000 --- a/drivers/char/ftape/lowlevel/fdc-io.h +++ /dev/null | |||
@@ -1,252 +0,0 @@ | |||
1 | #ifndef _FDC_IO_H | ||
2 | #define _FDC_IO_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
6 | * (C) 1996-1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-io.h,v $ | ||
24 | * $Revision: 1.3 $ | ||
25 | * $Date: 1997/10/05 19:18:06 $ | ||
26 | * | ||
27 | * This file contains the declarations for the low level | ||
28 | * functions that communicate with the floppy disk controller, | ||
29 | * for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for | ||
30 | * Linux. | ||
31 | */ | ||
32 | |||
33 | #include <linux/fdreg.h> | ||
34 | |||
35 | #include "../lowlevel/ftape-bsm.h" | ||
36 | |||
37 | #define FDC_SK_BIT (0x20) | ||
38 | #define FDC_MT_BIT (0x80) | ||
39 | |||
40 | #define FDC_READ (FD_READ & ~(FDC_SK_BIT | FDC_MT_BIT)) | ||
41 | #define FDC_WRITE (FD_WRITE & ~FDC_MT_BIT) | ||
42 | #define FDC_READ_DELETED (0x4c) | ||
43 | #define FDC_WRITE_DELETED (0x49) | ||
44 | #define FDC_VERIFY (0x56) | ||
45 | #define FDC_READID (0x4a) | ||
46 | #define FDC_SENSED (0x04) | ||
47 | #define FDC_SENSEI (FD_SENSEI) | ||
48 | #define FDC_FORMAT (FD_FORMAT) | ||
49 | #define FDC_RECAL (FD_RECALIBRATE) | ||
50 | #define FDC_SEEK (FD_SEEK) | ||
51 | #define FDC_SPECIFY (FD_SPECIFY) | ||
52 | #define FDC_RECALIBR (FD_RECALIBRATE) | ||
53 | #define FDC_VERSION (FD_VERSION) | ||
54 | #define FDC_PERPEND (FD_PERPENDICULAR) | ||
55 | #define FDC_DUMPREGS (FD_DUMPREGS) | ||
56 | #define FDC_LOCK (FD_LOCK) | ||
57 | #define FDC_UNLOCK (FD_UNLOCK) | ||
58 | #define FDC_CONFIGURE (FD_CONFIGURE) | ||
59 | #define FDC_DRIVE_SPEC (0x8e) /* i82078 has this (any others?) */ | ||
60 | #define FDC_PARTID (0x18) /* i82078 has this */ | ||
61 | #define FDC_SAVE (0x2e) /* i82078 has this (any others?) */ | ||
62 | #define FDC_RESTORE (0x4e) /* i82078 has this (any others?) */ | ||
63 | |||
64 | #define FDC_STATUS_MASK (STATUS_BUSY | STATUS_DMA | STATUS_DIR | STATUS_READY) | ||
65 | #define FDC_DATA_READY (STATUS_READY) | ||
66 | #define FDC_DATA_OUTPUT (STATUS_DIR) | ||
67 | #define FDC_DATA_READY_MASK (STATUS_READY | STATUS_DIR) | ||
68 | #define FDC_DATA_OUT_READY (STATUS_READY | STATUS_DIR) | ||
69 | #define FDC_DATA_IN_READY (STATUS_READY) | ||
70 | #define FDC_BUSY (STATUS_BUSY) | ||
71 | #define FDC_CLK48_BIT (0x80) | ||
72 | #define FDC_SEL3V_BIT (0x40) | ||
73 | |||
74 | #define ST0_INT_MASK (ST0_INTR) | ||
75 | #define FDC_INT_NORMAL (ST0_INTR & 0x00) | ||
76 | #define FDC_INT_ABNORMAL (ST0_INTR & 0x40) | ||
77 | #define FDC_INT_INVALID (ST0_INTR & 0x80) | ||
78 | #define FDC_INT_READYCH (ST0_INTR & 0xC0) | ||
79 | #define ST0_SEEK_END (ST0_SE) | ||
80 | #define ST3_TRACK_0 (ST3_TZ) | ||
81 | |||
82 | #define FDC_RESET_NOT (0x04) | ||
83 | #define FDC_DMA_MODE (0x08) | ||
84 | #define FDC_MOTOR_0 (0x10) | ||
85 | #define FDC_MOTOR_1 (0x20) | ||
86 | |||
87 | typedef struct { | ||
88 | void (**hook) (void); /* our wedge into the isr */ | ||
89 | enum { | ||
90 | no_fdc, i8272, i82077, i82077AA, fc10, | ||
91 | i82078, i82078_1 | ||
92 | } type; /* FDC type */ | ||
93 | unsigned int irq; /* FDC irq nr */ | ||
94 | unsigned int dma; /* FDC dma channel nr */ | ||
95 | __u16 sra; /* Status register A (PS/2 only) */ | ||
96 | __u16 srb; /* Status register B (PS/2 only) */ | ||
97 | __u16 dor; /* Digital output register */ | ||
98 | __u16 tdr; /* Tape Drive Register (82077SL-1 & | ||
99 | 82078 only) */ | ||
100 | __u16 msr; /* Main Status Register */ | ||
101 | __u16 dsr; /* Datarate Select Register (8207x only) */ | ||
102 | __u16 fifo; /* Data register / Fifo on 8207x */ | ||
103 | __u16 dir; /* Digital Input Register */ | ||
104 | __u16 ccr; /* Configuration Control Register */ | ||
105 | __u16 dor2; /* Alternate dor on MACH-2 controller, | ||
106 | also used with FC-10, meaning unknown */ | ||
107 | } fdc_config_info; | ||
108 | |||
109 | typedef enum { | ||
110 | fdc_data_rate_250 = 2, | ||
111 | fdc_data_rate_300 = 1, /* any fdc in default configuration */ | ||
112 | fdc_data_rate_500 = 0, | ||
113 | fdc_data_rate_1000 = 3, | ||
114 | fdc_data_rate_2000 = 1, /* i82078-1: when using Data Rate Table #2 */ | ||
115 | } fdc_data_rate_type; | ||
116 | |||
117 | typedef enum { | ||
118 | fdc_idle = 0, | ||
119 | fdc_reading_data = FDC_READ, | ||
120 | fdc_seeking = FDC_SEEK, | ||
121 | fdc_writing_data = FDC_WRITE, | ||
122 | fdc_deleting = FDC_WRITE_DELETED, | ||
123 | fdc_reading_id = FDC_READID, | ||
124 | fdc_recalibrating = FDC_RECAL, | ||
125 | fdc_formatting = FDC_FORMAT, | ||
126 | fdc_verifying = FDC_VERIFY | ||
127 | } fdc_mode_enum; | ||
128 | |||
129 | typedef enum { | ||
130 | waiting = 0, | ||
131 | reading, | ||
132 | writing, | ||
133 | formatting, | ||
134 | verifying, | ||
135 | deleting, | ||
136 | done, | ||
137 | error, | ||
138 | mmapped, | ||
139 | } buffer_state_enum; | ||
140 | |||
141 | typedef struct { | ||
142 | __u8 *address; | ||
143 | volatile buffer_state_enum status; | ||
144 | volatile __u8 *ptr; | ||
145 | volatile unsigned int bytes; | ||
146 | volatile unsigned int segment_id; | ||
147 | |||
148 | /* bitmap for remainder of segment not yet handled. | ||
149 | * one bit set for each bad sector that must be skipped. | ||
150 | */ | ||
151 | volatile SectorMap bad_sector_map; | ||
152 | |||
153 | /* bitmap with bad data blocks in data buffer. | ||
154 | * the errors in this map may be retried. | ||
155 | */ | ||
156 | volatile SectorMap soft_error_map; | ||
157 | |||
158 | /* bitmap with bad data blocks in data buffer | ||
159 | * the errors in this map may not be retried. | ||
160 | */ | ||
161 | volatile SectorMap hard_error_map; | ||
162 | |||
163 | /* retry counter for soft errors. | ||
164 | */ | ||
165 | volatile int retry; | ||
166 | |||
167 | /* sectors to skip on retry ??? | ||
168 | */ | ||
169 | volatile unsigned int skip; | ||
170 | |||
171 | /* nr of data blocks in data buffer | ||
172 | */ | ||
173 | volatile unsigned int data_offset; | ||
174 | |||
175 | /* offset in segment for first sector to be handled. | ||
176 | */ | ||
177 | volatile unsigned int sector_offset; | ||
178 | |||
179 | /* size of cluster of good sectors to be handled. | ||
180 | */ | ||
181 | volatile unsigned int sector_count; | ||
182 | |||
183 | /* size of remaining part of segment to be handled. | ||
184 | */ | ||
185 | volatile unsigned int remaining; | ||
186 | |||
187 | /* points to next segment (contiguous) to be handled, | ||
188 | * or is zero if no read-ahead is allowed. | ||
189 | */ | ||
190 | volatile unsigned int next_segment; | ||
191 | |||
192 | /* flag being set if deleted data was read. | ||
193 | */ | ||
194 | volatile int deleted; | ||
195 | |||
196 | /* floppy coordinates of first sector in segment */ | ||
197 | volatile __u8 head; | ||
198 | volatile __u8 cyl; | ||
199 | volatile __u8 sect; | ||
200 | |||
201 | /* gap to use when formatting */ | ||
202 | __u8 gap3; | ||
203 | /* flag set when buffer is mmaped */ | ||
204 | int mmapped; | ||
205 | } buffer_struct; | ||
206 | |||
207 | /* | ||
208 | * fdc-io.c defined public variables | ||
209 | */ | ||
210 | extern volatile fdc_mode_enum fdc_mode; | ||
211 | extern int fdc_setup_error; /* outdated ??? */ | ||
212 | extern wait_queue_head_t ftape_wait_intr; | ||
213 | extern volatile int ftape_current_cylinder; /* track nr FDC thinks we're on */ | ||
214 | extern volatile __u8 fdc_head; /* FDC head */ | ||
215 | extern volatile __u8 fdc_cyl; /* FDC track */ | ||
216 | extern volatile __u8 fdc_sect; /* FDC sector */ | ||
217 | extern fdc_config_info fdc; /* FDC hardware configuration */ | ||
218 | |||
219 | extern unsigned int ft_fdc_base; | ||
220 | extern unsigned int ft_fdc_irq; | ||
221 | extern unsigned int ft_fdc_dma; | ||
222 | extern unsigned int ft_fdc_threshold; | ||
223 | extern unsigned int ft_fdc_rate_limit; | ||
224 | extern int ft_probe_fc10; | ||
225 | extern int ft_mach2; | ||
226 | /* | ||
227 | * fdc-io.c defined public functions | ||
228 | */ | ||
229 | extern void fdc_catch_stray_interrupts(int count); | ||
230 | extern int fdc_ready_wait(unsigned int timeout); | ||
231 | extern int fdc_command(const __u8 * cmd_data, int cmd_len); | ||
232 | extern int fdc_result(__u8 * res_data, int res_len); | ||
233 | extern int fdc_interrupt_wait(unsigned int time); | ||
234 | extern int fdc_seek(int track); | ||
235 | extern int fdc_sense_drive_status(int *st3); | ||
236 | extern void fdc_motor(int motor); | ||
237 | extern void fdc_reset(void); | ||
238 | extern void fdc_disable(void); | ||
239 | extern int fdc_fifo_threshold(__u8 threshold, | ||
240 | int *fifo_state, int *lock_state, int *fifo_thr); | ||
241 | extern void fdc_wait_calibrate(void); | ||
242 | extern int fdc_sense_interrupt_status(int *st0, int *current_cylinder); | ||
243 | extern void fdc_save_drive_specs(void); | ||
244 | extern void fdc_restore_drive_specs(void); | ||
245 | extern int fdc_set_data_rate(int rate); | ||
246 | extern void fdc_set_write_precomp(int precomp); | ||
247 | extern int fdc_release_irq_and_dma(void); | ||
248 | extern void fdc_release_regions(void); | ||
249 | extern int fdc_init(void); | ||
250 | extern int fdc_setup_read_write(buffer_struct * buff, __u8 operation); | ||
251 | extern int fdc_setup_formatting(buffer_struct * buff); | ||
252 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/fdc-isr.c b/drivers/char/ftape/lowlevel/fdc-isr.c deleted file mode 100644 index ad2bc733ae1b..000000000000 --- a/drivers/char/ftape/lowlevel/fdc-isr.c +++ /dev/null | |||
@@ -1,1170 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1994-1996 Bas Laarhoven, | ||
3 | * (C) 1996-1997 Claus-Justus Heine. | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2, or (at your option) | ||
8 | any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; see the file COPYING. If not, write to | ||
17 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | |||
19 | * | ||
20 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-isr.c,v $ | ||
21 | * $Revision: 1.9 $ | ||
22 | * $Date: 1997/10/17 23:01:53 $ | ||
23 | * | ||
24 | * This file contains the interrupt service routine and | ||
25 | * associated code for the QIC-40/80/3010/3020 floppy-tape driver | ||
26 | * "ftape" for Linux. | ||
27 | */ | ||
28 | |||
29 | #include <asm/io.h> | ||
30 | #include <asm/dma.h> | ||
31 | |||
32 | #define volatile /* */ | ||
33 | |||
34 | #include <linux/ftape.h> | ||
35 | #include <linux/qic117.h> | ||
36 | #include "../lowlevel/ftape-tracing.h" | ||
37 | #include "../lowlevel/fdc-isr.h" | ||
38 | #include "../lowlevel/fdc-io.h" | ||
39 | #include "../lowlevel/ftape-ctl.h" | ||
40 | #include "../lowlevel/ftape-rw.h" | ||
41 | #include "../lowlevel/ftape-io.h" | ||
42 | #include "../lowlevel/ftape-calibr.h" | ||
43 | #include "../lowlevel/ftape-bsm.h" | ||
44 | |||
45 | /* Global vars. | ||
46 | */ | ||
47 | volatile int ft_expected_stray_interrupts; | ||
48 | volatile int ft_interrupt_seen; | ||
49 | volatile int ft_seek_completed; | ||
50 | volatile int ft_hide_interrupt; | ||
51 | /* Local vars. | ||
52 | */ | ||
53 | typedef enum { | ||
54 | no_error = 0, id_am_error = 0x01, id_crc_error = 0x02, | ||
55 | data_am_error = 0x04, data_crc_error = 0x08, | ||
56 | no_data_error = 0x10, overrun_error = 0x20, | ||
57 | } error_cause; | ||
58 | static int stop_read_ahead; | ||
59 | |||
60 | |||
61 | static void print_error_cause(int cause) | ||
62 | { | ||
63 | TRACE_FUN(ft_t_any); | ||
64 | |||
65 | switch (cause) { | ||
66 | case no_data_error: | ||
67 | TRACE(ft_t_noise, "no data error"); | ||
68 | break; | ||
69 | case id_am_error: | ||
70 | TRACE(ft_t_noise, "id am error"); | ||
71 | break; | ||
72 | case id_crc_error: | ||
73 | TRACE(ft_t_noise, "id crc error"); | ||
74 | break; | ||
75 | case data_am_error: | ||
76 | TRACE(ft_t_noise, "data am error"); | ||
77 | break; | ||
78 | case data_crc_error: | ||
79 | TRACE(ft_t_noise, "data crc error"); | ||
80 | break; | ||
81 | case overrun_error: | ||
82 | TRACE(ft_t_noise, "overrun error"); | ||
83 | break; | ||
84 | default:; | ||
85 | } | ||
86 | TRACE_EXIT; | ||
87 | } | ||
88 | |||
89 | static char *fdc_mode_txt(fdc_mode_enum mode) | ||
90 | { | ||
91 | switch (mode) { | ||
92 | case fdc_idle: | ||
93 | return "fdc_idle"; | ||
94 | case fdc_reading_data: | ||
95 | return "fdc_reading_data"; | ||
96 | case fdc_seeking: | ||
97 | return "fdc_seeking"; | ||
98 | case fdc_writing_data: | ||
99 | return "fdc_writing_data"; | ||
100 | case fdc_reading_id: | ||
101 | return "fdc_reading_id"; | ||
102 | case fdc_recalibrating: | ||
103 | return "fdc_recalibrating"; | ||
104 | case fdc_formatting: | ||
105 | return "fdc_formatting"; | ||
106 | case fdc_verifying: | ||
107 | return "fdc_verifying"; | ||
108 | default: | ||
109 | return "unknown"; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | static inline error_cause decode_irq_cause(fdc_mode_enum mode, __u8 st[]) | ||
114 | { | ||
115 | error_cause cause = no_error; | ||
116 | TRACE_FUN(ft_t_any); | ||
117 | |||
118 | /* Valid st[], decode cause of interrupt. | ||
119 | */ | ||
120 | switch (st[0] & ST0_INT_MASK) { | ||
121 | case FDC_INT_NORMAL: | ||
122 | TRACE(ft_t_fdc_dma,"normal completion: %s",fdc_mode_txt(mode)); | ||
123 | break; | ||
124 | case FDC_INT_ABNORMAL: | ||
125 | TRACE(ft_t_flow, "abnormal completion %s", fdc_mode_txt(mode)); | ||
126 | TRACE(ft_t_fdc_dma, "ST0: 0x%02x, ST1: 0x%02x, ST2: 0x%02x", | ||
127 | st[0], st[1], st[2]); | ||
128 | TRACE(ft_t_fdc_dma, | ||
129 | "C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x", | ||
130 | st[3], st[4], st[5], st[6]); | ||
131 | if (st[1] & 0x01) { | ||
132 | if (st[2] & 0x01) { | ||
133 | cause = data_am_error; | ||
134 | } else { | ||
135 | cause = id_am_error; | ||
136 | } | ||
137 | } else if (st[1] & 0x20) { | ||
138 | if (st[2] & 0x20) { | ||
139 | cause = data_crc_error; | ||
140 | } else { | ||
141 | cause = id_crc_error; | ||
142 | } | ||
143 | } else if (st[1] & 0x04) { | ||
144 | cause = no_data_error; | ||
145 | } else if (st[1] & 0x10) { | ||
146 | cause = overrun_error; | ||
147 | } | ||
148 | print_error_cause(cause); | ||
149 | break; | ||
150 | case FDC_INT_INVALID: | ||
151 | TRACE(ft_t_flow, "invalid completion %s", fdc_mode_txt(mode)); | ||
152 | break; | ||
153 | case FDC_INT_READYCH: | ||
154 | if (st[0] & ST0_SEEK_END) { | ||
155 | TRACE(ft_t_flow, "drive poll completed"); | ||
156 | } else { | ||
157 | TRACE(ft_t_flow, "ready change %s",fdc_mode_txt(mode)); | ||
158 | } | ||
159 | break; | ||
160 | default: | ||
161 | break; | ||
162 | } | ||
163 | TRACE_EXIT cause; | ||
164 | } | ||
165 | |||
166 | static void update_history(error_cause cause) | ||
167 | { | ||
168 | switch (cause) { | ||
169 | case id_am_error: | ||
170 | ft_history.id_am_errors++; | ||
171 | break; | ||
172 | case id_crc_error: | ||
173 | ft_history.id_crc_errors++; | ||
174 | break; | ||
175 | case data_am_error: | ||
176 | ft_history.data_am_errors++; | ||
177 | break; | ||
178 | case data_crc_error: | ||
179 | ft_history.data_crc_errors++; | ||
180 | break; | ||
181 | case overrun_error: | ||
182 | ft_history.overrun_errors++; | ||
183 | break; | ||
184 | case no_data_error: | ||
185 | ft_history.no_data_errors++; | ||
186 | break; | ||
187 | default:; | ||
188 | } | ||
189 | } | ||
190 | |||
191 | static void skip_bad_sector(buffer_struct * buff) | ||
192 | { | ||
193 | TRACE_FUN(ft_t_any); | ||
194 | |||
195 | /* Mark sector as soft error and skip it | ||
196 | */ | ||
197 | if (buff->remaining > 0) { | ||
198 | ++buff->sector_offset; | ||
199 | ++buff->data_offset; | ||
200 | --buff->remaining; | ||
201 | buff->ptr += FT_SECTOR_SIZE; | ||
202 | buff->bad_sector_map >>= 1; | ||
203 | } else { | ||
204 | /* Hey, what is this????????????? C code: if we shift | ||
205 | * more than 31 bits, we get no shift. That's bad!!!!!! | ||
206 | */ | ||
207 | ++buff->sector_offset; /* hack for error maps */ | ||
208 | TRACE(ft_t_warn, "skipping last sector in segment"); | ||
209 | } | ||
210 | TRACE_EXIT; | ||
211 | } | ||
212 | |||
213 | static void update_error_maps(buffer_struct * buff, unsigned int error_offset) | ||
214 | { | ||
215 | int hard = 0; | ||
216 | TRACE_FUN(ft_t_any); | ||
217 | |||
218 | if (buff->retry < FT_SOFT_RETRIES) { | ||
219 | buff->soft_error_map |= (1 << error_offset); | ||
220 | } else { | ||
221 | buff->hard_error_map |= (1 << error_offset); | ||
222 | buff->soft_error_map &= ~buff->hard_error_map; | ||
223 | buff->retry = -1; /* will be set to 0 in setup_segment */ | ||
224 | hard = 1; | ||
225 | } | ||
226 | TRACE(ft_t_noise, "sector %d : %s error\n" | ||
227 | KERN_INFO "hard map: 0x%08lx\n" | ||
228 | KERN_INFO "soft map: 0x%08lx", | ||
229 | FT_SECTOR(error_offset), hard ? "hard" : "soft", | ||
230 | (long) buff->hard_error_map, (long) buff->soft_error_map); | ||
231 | TRACE_EXIT; | ||
232 | } | ||
233 | |||
234 | static void print_progress(buffer_struct *buff, error_cause cause) | ||
235 | { | ||
236 | TRACE_FUN(ft_t_any); | ||
237 | |||
238 | switch (cause) { | ||
239 | case no_error: | ||
240 | TRACE(ft_t_flow,"%d Sector(s) transferred", buff->sector_count); | ||
241 | break; | ||
242 | case no_data_error: | ||
243 | TRACE(ft_t_flow, "Sector %d not found", | ||
244 | FT_SECTOR(buff->sector_offset)); | ||
245 | break; | ||
246 | case overrun_error: | ||
247 | /* got an overrun error on the first byte, must be a | ||
248 | * hardware problem | ||
249 | */ | ||
250 | TRACE(ft_t_bug, | ||
251 | "Unexpected error: failing DMA or FDC controller ?"); | ||
252 | break; | ||
253 | case data_crc_error: | ||
254 | TRACE(ft_t_flow, "Error in sector %d", | ||
255 | FT_SECTOR(buff->sector_offset - 1)); | ||
256 | break; | ||
257 | case id_crc_error: | ||
258 | case id_am_error: | ||
259 | case data_am_error: | ||
260 | TRACE(ft_t_flow, "Error in sector %d", | ||
261 | FT_SECTOR(buff->sector_offset)); | ||
262 | break; | ||
263 | default: | ||
264 | TRACE(ft_t_flow, "Unexpected error at sector %d", | ||
265 | FT_SECTOR(buff->sector_offset)); | ||
266 | break; | ||
267 | } | ||
268 | TRACE_EXIT; | ||
269 | } | ||
270 | |||
271 | /* | ||
272 | * Error cause: Amount xferred: Action: | ||
273 | * | ||
274 | * id_am_error 0 mark bad and skip | ||
275 | * id_crc_error 0 mark bad and skip | ||
276 | * data_am_error 0 mark bad and skip | ||
277 | * data_crc_error % 1024 mark bad and skip | ||
278 | * no_data_error 0 retry on write | ||
279 | * mark bad and skip on read | ||
280 | * overrun_error [ 0..all-1 ] mark bad and skip | ||
281 | * no_error all continue | ||
282 | */ | ||
283 | |||
284 | /* the arg `sector' is returned by the fdc and tells us at which sector we | ||
285 | * are positioned at (relative to starting sector of segment) | ||
286 | */ | ||
287 | static void determine_verify_progress(buffer_struct *buff, | ||
288 | error_cause cause, | ||
289 | __u8 sector) | ||
290 | { | ||
291 | TRACE_FUN(ft_t_any); | ||
292 | |||
293 | if (cause == no_error && sector == 1) { | ||
294 | buff->sector_offset = FT_SECTORS_PER_SEGMENT; | ||
295 | buff->remaining = 0; | ||
296 | if (TRACE_LEVEL >= ft_t_flow) { | ||
297 | print_progress(buff, cause); | ||
298 | } | ||
299 | } else { | ||
300 | buff->sector_offset = sector - buff->sect; | ||
301 | buff->remaining = FT_SECTORS_PER_SEGMENT - buff->sector_offset; | ||
302 | TRACE(ft_t_noise, "%ssector offset: 0x%04x", | ||
303 | (cause == no_error) ? "unexpected " : "", | ||
304 | buff->sector_offset); | ||
305 | switch (cause) { | ||
306 | case overrun_error: | ||
307 | break; | ||
308 | #if 0 | ||
309 | case no_data_error: | ||
310 | buff->retry = FT_SOFT_RETRIES; | ||
311 | if (buff->hard_error_map && | ||
312 | buff->sector_offset > 1 && | ||
313 | (buff->hard_error_map & | ||
314 | (1 << (buff->sector_offset-2)))) { | ||
315 | buff->retry --; | ||
316 | } | ||
317 | break; | ||
318 | #endif | ||
319 | default: | ||
320 | buff->retry = FT_SOFT_RETRIES; | ||
321 | break; | ||
322 | } | ||
323 | if (TRACE_LEVEL >= ft_t_flow) { | ||
324 | print_progress(buff, cause); | ||
325 | } | ||
326 | /* Sector_offset points to the problem area Now adjust | ||
327 | * sector_offset so it always points one past he failing | ||
328 | * sector. I.e. skip the bad sector. | ||
329 | */ | ||
330 | ++buff->sector_offset; | ||
331 | --buff->remaining; | ||
332 | update_error_maps(buff, buff->sector_offset - 1); | ||
333 | } | ||
334 | TRACE_EXIT; | ||
335 | } | ||
336 | |||
337 | static void determine_progress(buffer_struct *buff, | ||
338 | error_cause cause, | ||
339 | __u8 sector) | ||
340 | { | ||
341 | unsigned int dma_residue; | ||
342 | TRACE_FUN(ft_t_any); | ||
343 | |||
344 | /* Using less preferred order of disable_dma and | ||
345 | * get_dma_residue because this seems to fail on at least one | ||
346 | * system if reversed! | ||
347 | */ | ||
348 | dma_residue = get_dma_residue(fdc.dma); | ||
349 | disable_dma(fdc.dma); | ||
350 | if (cause != no_error || dma_residue != 0) { | ||
351 | TRACE(ft_t_noise, "%sDMA residue: 0x%04x", | ||
352 | (cause == no_error) ? "unexpected " : "", | ||
353 | dma_residue); | ||
354 | /* adjust to actual value: */ | ||
355 | if (dma_residue == 0) { | ||
356 | /* this happens sometimes with overrun errors. | ||
357 | * I don't know whether we could ignore the | ||
358 | * overrun error. Play save. | ||
359 | */ | ||
360 | buff->sector_count --; | ||
361 | } else { | ||
362 | buff->sector_count -= ((dma_residue + | ||
363 | (FT_SECTOR_SIZE - 1)) / | ||
364 | FT_SECTOR_SIZE); | ||
365 | } | ||
366 | } | ||
367 | /* Update var's influenced by the DMA operation. | ||
368 | */ | ||
369 | if (buff->sector_count > 0) { | ||
370 | buff->sector_offset += buff->sector_count; | ||
371 | buff->data_offset += buff->sector_count; | ||
372 | buff->ptr += (buff->sector_count * | ||
373 | FT_SECTOR_SIZE); | ||
374 | buff->remaining -= buff->sector_count; | ||
375 | buff->bad_sector_map >>= buff->sector_count; | ||
376 | } | ||
377 | if (TRACE_LEVEL >= ft_t_flow) { | ||
378 | print_progress(buff, cause); | ||
379 | } | ||
380 | if (cause != no_error) { | ||
381 | if (buff->remaining == 0) { | ||
382 | TRACE(ft_t_warn, "foo?\n" | ||
383 | KERN_INFO "count : %d\n" | ||
384 | KERN_INFO "offset: %d\n" | ||
385 | KERN_INFO "soft : %08x\n" | ||
386 | KERN_INFO "hard : %08x", | ||
387 | buff->sector_count, | ||
388 | buff->sector_offset, | ||
389 | buff->soft_error_map, | ||
390 | buff->hard_error_map); | ||
391 | } | ||
392 | /* Sector_offset points to the problem area, except if we got | ||
393 | * a data_crc_error. In that case it points one past the | ||
394 | * failing sector. | ||
395 | * | ||
396 | * Now adjust sector_offset so it always points one past he | ||
397 | * failing sector. I.e. skip the bad sector. | ||
398 | */ | ||
399 | if (cause != data_crc_error) { | ||
400 | skip_bad_sector(buff); | ||
401 | } | ||
402 | update_error_maps(buff, buff->sector_offset - 1); | ||
403 | } | ||
404 | TRACE_EXIT; | ||
405 | } | ||
406 | |||
407 | static int calc_steps(int cmd) | ||
408 | { | ||
409 | if (ftape_current_cylinder > cmd) { | ||
410 | return ftape_current_cylinder - cmd; | ||
411 | } else { | ||
412 | return ftape_current_cylinder + cmd; | ||
413 | } | ||
414 | } | ||
415 | |||
416 | static void pause_tape(int retry, int mode) | ||
417 | { | ||
418 | int result; | ||
419 | __u8 out[3] = {FDC_SEEK, ft_drive_sel, 0}; | ||
420 | TRACE_FUN(ft_t_any); | ||
421 | |||
422 | /* We'll use a raw seek command to get the tape to rewind and | ||
423 | * stop for a retry. | ||
424 | */ | ||
425 | ++ft_history.rewinds; | ||
426 | if (qic117_cmds[ftape_current_command].non_intr) { | ||
427 | TRACE(ft_t_warn, "motion command may be issued too soon"); | ||
428 | } | ||
429 | if (retry && (mode == fdc_reading_data || | ||
430 | mode == fdc_reading_id || | ||
431 | mode == fdc_verifying)) { | ||
432 | ftape_current_command = QIC_MICRO_STEP_PAUSE; | ||
433 | ftape_might_be_off_track = 1; | ||
434 | } else { | ||
435 | ftape_current_command = QIC_PAUSE; | ||
436 | } | ||
437 | out[2] = calc_steps(ftape_current_command); | ||
438 | result = fdc_command(out, 3); /* issue QIC_117 command */ | ||
439 | ftape_current_cylinder = out[ 2]; | ||
440 | if (result < 0) { | ||
441 | TRACE(ft_t_noise, "qic-pause failed, status = %d", result); | ||
442 | } else { | ||
443 | ft_location.known = 0; | ||
444 | ft_runner_status = idle; | ||
445 | ft_hide_interrupt = 1; | ||
446 | ftape_tape_running = 0; | ||
447 | } | ||
448 | TRACE_EXIT; | ||
449 | } | ||
450 | |||
451 | static void continue_xfer(buffer_struct *buff, | ||
452 | fdc_mode_enum mode, | ||
453 | unsigned int skip) | ||
454 | { | ||
455 | int write = 0; | ||
456 | TRACE_FUN(ft_t_any); | ||
457 | |||
458 | if (mode == fdc_writing_data || mode == fdc_deleting) { | ||
459 | write = 1; | ||
460 | } | ||
461 | /* This part can be removed if it never happens | ||
462 | */ | ||
463 | if (skip > 0 && | ||
464 | (ft_runner_status != running || | ||
465 | (write && (buff->status != writing)) || | ||
466 | (!write && (buff->status != reading && | ||
467 | buff->status != verifying)))) { | ||
468 | TRACE(ft_t_err, "unexpected runner/buffer state %d/%d", | ||
469 | ft_runner_status, buff->status); | ||
470 | buff->status = error; | ||
471 | /* finish this buffer: */ | ||
472 | (void)ftape_next_buffer(ft_queue_head); | ||
473 | ft_runner_status = aborting; | ||
474 | fdc_mode = fdc_idle; | ||
475 | } else if (buff->remaining > 0 && ftape_calc_next_cluster(buff) > 0) { | ||
476 | /* still sectors left in current segment, continue | ||
477 | * with this segment | ||
478 | */ | ||
479 | if (fdc_setup_read_write(buff, mode) < 0) { | ||
480 | /* failed, abort operation | ||
481 | */ | ||
482 | buff->bytes = buff->ptr - buff->address; | ||
483 | buff->status = error; | ||
484 | /* finish this buffer: */ | ||
485 | (void)ftape_next_buffer(ft_queue_head); | ||
486 | ft_runner_status = aborting; | ||
487 | fdc_mode = fdc_idle; | ||
488 | } | ||
489 | } else { | ||
490 | /* current segment completed | ||
491 | */ | ||
492 | unsigned int last_segment = buff->segment_id; | ||
493 | int eot = ((last_segment + 1) % ft_segments_per_track) == 0; | ||
494 | unsigned int next = buff->next_segment; /* 0 means stop ! */ | ||
495 | |||
496 | buff->bytes = buff->ptr - buff->address; | ||
497 | buff->status = done; | ||
498 | buff = ftape_next_buffer(ft_queue_head); | ||
499 | if (eot) { | ||
500 | /* finished last segment on current track, | ||
501 | * can't continue | ||
502 | */ | ||
503 | ft_runner_status = logical_eot; | ||
504 | fdc_mode = fdc_idle; | ||
505 | TRACE_EXIT; | ||
506 | } | ||
507 | if (next <= 0) { | ||
508 | /* don't continue with next segment | ||
509 | */ | ||
510 | TRACE(ft_t_noise, "no %s allowed, stopping tape", | ||
511 | (write) ? "write next" : "read ahead"); | ||
512 | pause_tape(0, mode); | ||
513 | ft_runner_status = idle; /* not quite true until | ||
514 | * next irq | ||
515 | */ | ||
516 | TRACE_EXIT; | ||
517 | } | ||
518 | /* continue with next segment | ||
519 | */ | ||
520 | if (buff->status != waiting) { | ||
521 | TRACE(ft_t_noise, "all input buffers %s, pausing tape", | ||
522 | (write) ? "empty" : "full"); | ||
523 | pause_tape(0, mode); | ||
524 | ft_runner_status = idle; /* not quite true until | ||
525 | * next irq | ||
526 | */ | ||
527 | TRACE_EXIT; | ||
528 | } | ||
529 | if (write && next != buff->segment_id) { | ||
530 | TRACE(ft_t_noise, | ||
531 | "segments out of order, aborting write"); | ||
532 | ft_runner_status = do_abort; | ||
533 | fdc_mode = fdc_idle; | ||
534 | TRACE_EXIT; | ||
535 | } | ||
536 | ftape_setup_new_segment(buff, next, 0); | ||
537 | if (stop_read_ahead) { | ||
538 | buff->next_segment = 0; | ||
539 | stop_read_ahead = 0; | ||
540 | } | ||
541 | if (ftape_calc_next_cluster(buff) == 0 || | ||
542 | fdc_setup_read_write(buff, mode) != 0) { | ||
543 | TRACE(ft_t_err, "couldn't start %s-ahead", | ||
544 | write ? "write" : "read"); | ||
545 | ft_runner_status = do_abort; | ||
546 | fdc_mode = fdc_idle; | ||
547 | } else { | ||
548 | /* keep on going */ | ||
549 | switch (ft_driver_state) { | ||
550 | case reading: buff->status = reading; break; | ||
551 | case verifying: buff->status = verifying; break; | ||
552 | case writing: buff->status = writing; break; | ||
553 | case deleting: buff->status = deleting; break; | ||
554 | default: | ||
555 | TRACE(ft_t_err, | ||
556 | "BUG: ft_driver_state %d should be one out of " | ||
557 | "{reading, writing, verifying, deleting}", | ||
558 | ft_driver_state); | ||
559 | buff->status = write ? writing : reading; | ||
560 | break; | ||
561 | } | ||
562 | } | ||
563 | } | ||
564 | TRACE_EXIT; | ||
565 | } | ||
566 | |||
567 | static void retry_sector(buffer_struct *buff, | ||
568 | int mode, | ||
569 | unsigned int skip) | ||
570 | { | ||
571 | TRACE_FUN(ft_t_any); | ||
572 | |||
573 | TRACE(ft_t_noise, "%s error, will retry", | ||
574 | (mode == fdc_writing_data || mode == fdc_deleting) ? "write" : "read"); | ||
575 | pause_tape(1, mode); | ||
576 | ft_runner_status = aborting; | ||
577 | buff->status = error; | ||
578 | buff->skip = skip; | ||
579 | TRACE_EXIT; | ||
580 | } | ||
581 | |||
582 | static unsigned int find_resume_point(buffer_struct *buff) | ||
583 | { | ||
584 | int i = 0; | ||
585 | SectorMap mask; | ||
586 | SectorMap map; | ||
587 | TRACE_FUN(ft_t_any); | ||
588 | |||
589 | /* This function is to be called after all variables have been | ||
590 | * updated to point past the failing sector. | ||
591 | * If there are any soft errors before the failing sector, | ||
592 | * find the first soft error and return the sector offset. | ||
593 | * Otherwise find the last hard error. | ||
594 | * Note: there should always be at least one hard or soft error ! | ||
595 | */ | ||
596 | if (buff->sector_offset < 1 || buff->sector_offset > 32) { | ||
597 | TRACE(ft_t_bug, "BUG: sector_offset = %d", | ||
598 | buff->sector_offset); | ||
599 | TRACE_EXIT 0; | ||
600 | } | ||
601 | if (buff->sector_offset >= 32) { /* C-limitation on shift ! */ | ||
602 | mask = 0xffffffff; | ||
603 | } else { | ||
604 | mask = (1 << buff->sector_offset) - 1; | ||
605 | } | ||
606 | map = buff->soft_error_map & mask; | ||
607 | if (map) { | ||
608 | while ((map & (1 << i)) == 0) { | ||
609 | ++i; | ||
610 | } | ||
611 | TRACE(ft_t_noise, "at sector %d", FT_SECTOR(i)); | ||
612 | } else { | ||
613 | map = buff->hard_error_map & mask; | ||
614 | i = buff->sector_offset - 1; | ||
615 | if (map) { | ||
616 | while ((map & (1 << i)) == 0) { | ||
617 | --i; | ||
618 | } | ||
619 | TRACE(ft_t_noise, "after sector %d", FT_SECTOR(i)); | ||
620 | ++i; /* first sector after last hard error */ | ||
621 | } else { | ||
622 | TRACE(ft_t_bug, "BUG: no soft or hard errors"); | ||
623 | } | ||
624 | } | ||
625 | TRACE_EXIT i; | ||
626 | } | ||
627 | |||
628 | /* check possible dma residue when formatting, update position record in | ||
629 | * buffer struct. This is, of course, modelled after determine_progress(), but | ||
630 | * we don't need to set up for retries because the format process cannot be | ||
631 | * interrupted (except at the end of the tape track). | ||
632 | */ | ||
633 | static int determine_fmt_progress(buffer_struct *buff, error_cause cause) | ||
634 | { | ||
635 | unsigned int dma_residue; | ||
636 | TRACE_FUN(ft_t_any); | ||
637 | |||
638 | /* Using less preferred order of disable_dma and | ||
639 | * get_dma_residue because this seems to fail on at least one | ||
640 | * system if reversed! | ||
641 | */ | ||
642 | dma_residue = get_dma_residue(fdc.dma); | ||
643 | disable_dma(fdc.dma); | ||
644 | if (cause != no_error || dma_residue != 0) { | ||
645 | TRACE(ft_t_info, "DMA residue = 0x%04x", dma_residue); | ||
646 | fdc_mode = fdc_idle; | ||
647 | switch(cause) { | ||
648 | case no_error: | ||
649 | ft_runner_status = aborting; | ||
650 | buff->status = idle; | ||
651 | break; | ||
652 | case overrun_error: | ||
653 | /* got an overrun error on the first byte, must be a | ||
654 | * hardware problem | ||
655 | */ | ||
656 | TRACE(ft_t_bug, | ||
657 | "Unexpected error: failing DMA controller ?"); | ||
658 | ft_runner_status = do_abort; | ||
659 | buff->status = error; | ||
660 | break; | ||
661 | default: | ||
662 | TRACE(ft_t_noise, "Unexpected error at segment %d", | ||
663 | buff->segment_id); | ||
664 | ft_runner_status = do_abort; | ||
665 | buff->status = error; | ||
666 | break; | ||
667 | } | ||
668 | TRACE_EXIT -EIO; /* can only retry entire track in format mode | ||
669 | */ | ||
670 | } | ||
671 | /* Update var's influenced by the DMA operation. | ||
672 | */ | ||
673 | buff->ptr += FT_SECTORS_PER_SEGMENT * 4; | ||
674 | buff->bytes -= FT_SECTORS_PER_SEGMENT * 4; | ||
675 | buff->remaining -= FT_SECTORS_PER_SEGMENT; | ||
676 | buff->segment_id ++; /* done with segment */ | ||
677 | TRACE_EXIT 0; | ||
678 | } | ||
679 | |||
680 | /* | ||
681 | * Continue formatting, switch buffers if there is no data left in | ||
682 | * current buffer. This is, of course, modelled after | ||
683 | * continue_xfer(), but we don't need to set up for retries because | ||
684 | * the format process cannot be interrupted (except at the end of the | ||
685 | * tape track). | ||
686 | */ | ||
687 | static void continue_formatting(buffer_struct *buff) | ||
688 | { | ||
689 | TRACE_FUN(ft_t_any); | ||
690 | |||
691 | if (buff->remaining <= 0) { /* no space left in dma buffer */ | ||
692 | unsigned int next = buff->next_segment; | ||
693 | |||
694 | if (next == 0) { /* end of tape track */ | ||
695 | buff->status = done; | ||
696 | ft_runner_status = logical_eot; | ||
697 | fdc_mode = fdc_idle; | ||
698 | TRACE(ft_t_noise, "Done formatting track %d", | ||
699 | ft_location.track); | ||
700 | TRACE_EXIT; | ||
701 | } | ||
702 | /* | ||
703 | * switch to next buffer! | ||
704 | */ | ||
705 | buff->status = done; | ||
706 | buff = ftape_next_buffer(ft_queue_head); | ||
707 | |||
708 | if (buff->status != waiting || next != buff->segment_id) { | ||
709 | goto format_setup_error; | ||
710 | } | ||
711 | } | ||
712 | if (fdc_setup_formatting(buff) < 0) { | ||
713 | goto format_setup_error; | ||
714 | } | ||
715 | buff->status = formatting; | ||
716 | TRACE(ft_t_fdc_dma, "Formatting segment %d on track %d", | ||
717 | buff->segment_id, ft_location.track); | ||
718 | TRACE_EXIT; | ||
719 | format_setup_error: | ||
720 | ft_runner_status = do_abort; | ||
721 | fdc_mode = fdc_idle; | ||
722 | buff->status = error; | ||
723 | TRACE(ft_t_err, "Error setting up for segment %d on track %d", | ||
724 | buff->segment_id, ft_location.track); | ||
725 | TRACE_EXIT; | ||
726 | |||
727 | } | ||
728 | |||
729 | /* this handles writing, read id, reading and formatting | ||
730 | */ | ||
731 | static void handle_fdc_busy(buffer_struct *buff) | ||
732 | { | ||
733 | static int no_data_error_count; | ||
734 | int retry = 0; | ||
735 | error_cause cause; | ||
736 | __u8 in[7]; | ||
737 | int skip; | ||
738 | fdc_mode_enum fmode = fdc_mode; | ||
739 | TRACE_FUN(ft_t_any); | ||
740 | |||
741 | if (fdc_result(in, 7) < 0) { /* better get it fast ! */ | ||
742 | TRACE(ft_t_err, | ||
743 | "Probably fatal error during FDC Result Phase\n" | ||
744 | KERN_INFO | ||
745 | "drive may hang until (power on) reset :-("); | ||
746 | /* what to do next ???? | ||
747 | */ | ||
748 | TRACE_EXIT; | ||
749 | } | ||
750 | cause = decode_irq_cause(fdc_mode, in); | ||
751 | #ifdef TESTING | ||
752 | { int i; | ||
753 | for (i = 0; i < (int)ft_nr_buffers; ++i) | ||
754 | TRACE(ft_t_any, "buffer[%d] status: %d, segment_id: %d", | ||
755 | i, ft_buffer[i]->status, ft_buffer[i]->segment_id); | ||
756 | } | ||
757 | #endif | ||
758 | if (fmode == fdc_reading_data && ft_driver_state == verifying) { | ||
759 | fmode = fdc_verifying; | ||
760 | } | ||
761 | switch (fmode) { | ||
762 | case fdc_verifying: | ||
763 | if (ft_runner_status == aborting || | ||
764 | ft_runner_status == do_abort) { | ||
765 | TRACE(ft_t_noise,"aborting %s",fdc_mode_txt(fdc_mode)); | ||
766 | break; | ||
767 | } | ||
768 | if (buff->retry > 0) { | ||
769 | TRACE(ft_t_flow, "this is retry nr %d", buff->retry); | ||
770 | } | ||
771 | switch (cause) { | ||
772 | case no_error: | ||
773 | no_data_error_count = 0; | ||
774 | determine_verify_progress(buff, cause, in[5]); | ||
775 | if (in[2] & 0x40) { | ||
776 | /* This should not happen when verifying | ||
777 | */ | ||
778 | TRACE(ft_t_warn, | ||
779 | "deleted data in segment %d/%d", | ||
780 | buff->segment_id, | ||
781 | FT_SECTOR(buff->sector_offset - 1)); | ||
782 | buff->remaining = 0; /* abort transfer */ | ||
783 | buff->hard_error_map = EMPTY_SEGMENT; | ||
784 | skip = 1; | ||
785 | } else { | ||
786 | skip = 0; | ||
787 | } | ||
788 | continue_xfer(buff, fdc_mode, skip); | ||
789 | break; | ||
790 | case no_data_error: | ||
791 | no_data_error_count ++; | ||
792 | case overrun_error: | ||
793 | retry ++; | ||
794 | case id_am_error: | ||
795 | case id_crc_error: | ||
796 | case data_am_error: | ||
797 | case data_crc_error: | ||
798 | determine_verify_progress(buff, cause, in[5]); | ||
799 | if (cause == no_data_error) { | ||
800 | if (no_data_error_count >= 2) { | ||
801 | TRACE(ft_t_warn, | ||
802 | "retrying because of successive " | ||
803 | "no data errors"); | ||
804 | no_data_error_count = 0; | ||
805 | } else { | ||
806 | retry --; | ||
807 | } | ||
808 | } else { | ||
809 | no_data_error_count = 0; | ||
810 | } | ||
811 | if (retry) { | ||
812 | skip = find_resume_point(buff); | ||
813 | } else { | ||
814 | skip = buff->sector_offset; | ||
815 | } | ||
816 | if (retry && skip < 32) { | ||
817 | retry_sector(buff, fdc_mode, skip); | ||
818 | } else { | ||
819 | continue_xfer(buff, fdc_mode, skip); | ||
820 | } | ||
821 | update_history(cause); | ||
822 | break; | ||
823 | default: | ||
824 | /* Don't know why this could happen | ||
825 | * but find out. | ||
826 | */ | ||
827 | determine_verify_progress(buff, cause, in[5]); | ||
828 | retry_sector(buff, fdc_mode, 0); | ||
829 | TRACE(ft_t_err, "Error: unexpected error"); | ||
830 | break; | ||
831 | } | ||
832 | break; | ||
833 | case fdc_reading_data: | ||
834 | #ifdef TESTING | ||
835 | /* I'm sorry, but: NOBODY ever used this trace | ||
836 | * messages for ages. I guess that Bas was the last person | ||
837 | * that ever really used this (thank you, between the lines) | ||
838 | */ | ||
839 | if (cause == no_error) { | ||
840 | TRACE(ft_t_flow,"reading segment %d",buff->segment_id); | ||
841 | } else { | ||
842 | TRACE(ft_t_noise, "error reading segment %d", | ||
843 | buff->segment_id); | ||
844 | TRACE(ft_t_noise, "\n" | ||
845 | KERN_INFO | ||
846 | "IRQ:C: 0x%02x, H: 0x%02x, R: 0x%02x, N: 0x%02x\n" | ||
847 | KERN_INFO | ||
848 | "BUF:C: 0x%02x, H: 0x%02x, R: 0x%02x", | ||
849 | in[3], in[4], in[5], in[6], | ||
850 | buff->cyl, buff->head, buff->sect); | ||
851 | } | ||
852 | #endif | ||
853 | if (ft_runner_status == aborting || | ||
854 | ft_runner_status == do_abort) { | ||
855 | TRACE(ft_t_noise,"aborting %s",fdc_mode_txt(fdc_mode)); | ||
856 | break; | ||
857 | } | ||
858 | if (buff->bad_sector_map == FAKE_SEGMENT) { | ||
859 | /* This condition occurs when reading a `fake' | ||
860 | * sector that's not accessible. Doesn't | ||
861 | * really matter as we would have ignored it | ||
862 | * anyway ! | ||
863 | * | ||
864 | * Chance is that we're past the next segment | ||
865 | * now, so the next operation may fail and | ||
866 | * result in a retry. | ||
867 | */ | ||
868 | buff->remaining = 0; /* skip failing sector */ | ||
869 | /* buff->ptr = buff->address; */ | ||
870 | /* fake success: */ | ||
871 | continue_xfer(buff, fdc_mode, 1); | ||
872 | /* trace calls are expensive: place them AFTER | ||
873 | * the real stuff has been done. | ||
874 | * | ||
875 | */ | ||
876 | TRACE(ft_t_noise, "skipping empty segment %d (read), size? %d", | ||
877 | buff->segment_id, buff->ptr - buff->address); | ||
878 | TRACE_EXIT; | ||
879 | } | ||
880 | if (buff->retry > 0) { | ||
881 | TRACE(ft_t_flow, "this is retry nr %d", buff->retry); | ||
882 | } | ||
883 | switch (cause) { | ||
884 | case no_error: | ||
885 | determine_progress(buff, cause, in[5]); | ||
886 | if (in[2] & 0x40) { | ||
887 | /* Handle deleted data in header segments. | ||
888 | * Skip segment and force read-ahead. | ||
889 | */ | ||
890 | TRACE(ft_t_warn, | ||
891 | "deleted data in segment %d/%d", | ||
892 | buff->segment_id, | ||
893 | FT_SECTOR(buff->sector_offset - 1)); | ||
894 | buff->deleted = 1; | ||
895 | buff->remaining = 0;/*abort transfer */ | ||
896 | buff->soft_error_map |= | ||
897 | (-1L << buff->sector_offset); | ||
898 | if (buff->segment_id == 0) { | ||
899 | /* stop on next segment */ | ||
900 | stop_read_ahead = 1; | ||
901 | } | ||
902 | /* force read-ahead: */ | ||
903 | buff->next_segment = | ||
904 | buff->segment_id + 1; | ||
905 | skip = (FT_SECTORS_PER_SEGMENT - | ||
906 | buff->sector_offset); | ||
907 | } else { | ||
908 | skip = 0; | ||
909 | } | ||
910 | continue_xfer(buff, fdc_mode, skip); | ||
911 | break; | ||
912 | case no_data_error: | ||
913 | /* Tape started too far ahead of or behind the | ||
914 | * right sector. This may also happen in the | ||
915 | * middle of a segment ! | ||
916 | * | ||
917 | * Handle no-data as soft error. If next | ||
918 | * sector fails too, a retry (with needed | ||
919 | * reposition) will follow. | ||
920 | */ | ||
921 | retry ++; | ||
922 | case id_am_error: | ||
923 | case id_crc_error: | ||
924 | case data_am_error: | ||
925 | case data_crc_error: | ||
926 | case overrun_error: | ||
927 | retry += (buff->soft_error_map != 0 || | ||
928 | buff->hard_error_map != 0); | ||
929 | determine_progress(buff, cause, in[5]); | ||
930 | #if 1 || defined(TESTING) | ||
931 | if (cause == overrun_error) retry ++; | ||
932 | #endif | ||
933 | if (retry) { | ||
934 | skip = find_resume_point(buff); | ||
935 | } else { | ||
936 | skip = buff->sector_offset; | ||
937 | } | ||
938 | /* Try to resume with next sector on single | ||
939 | * errors (let ecc correct it), but retry on | ||
940 | * no_data (we'll be past the target when we | ||
941 | * get here so we cannot retry) or on | ||
942 | * multiple errors (reduce chance on ecc | ||
943 | * failure). | ||
944 | */ | ||
945 | /* cH: 23/02/97: if the last sector in the | ||
946 | * segment was a hard error, then there is | ||
947 | * no sense in a retry. This occasion seldom | ||
948 | * occurs but ... @:³²¸`@%&§$ | ||
949 | */ | ||
950 | if (retry && skip < 32) { | ||
951 | retry_sector(buff, fdc_mode, skip); | ||
952 | } else { | ||
953 | continue_xfer(buff, fdc_mode, skip); | ||
954 | } | ||
955 | update_history(cause); | ||
956 | break; | ||
957 | default: | ||
958 | /* Don't know why this could happen | ||
959 | * but find out. | ||
960 | */ | ||
961 | determine_progress(buff, cause, in[5]); | ||
962 | retry_sector(buff, fdc_mode, 0); | ||
963 | TRACE(ft_t_err, "Error: unexpected error"); | ||
964 | break; | ||
965 | } | ||
966 | break; | ||
967 | case fdc_reading_id: | ||
968 | if (cause == no_error) { | ||
969 | fdc_cyl = in[3]; | ||
970 | fdc_head = in[4]; | ||
971 | fdc_sect = in[5]; | ||
972 | TRACE(ft_t_fdc_dma, | ||
973 | "id read: C: 0x%02x, H: 0x%02x, R: 0x%02x", | ||
974 | fdc_cyl, fdc_head, fdc_sect); | ||
975 | } else { /* no valid information, use invalid sector */ | ||
976 | fdc_cyl = fdc_head = fdc_sect = 0; | ||
977 | TRACE(ft_t_flow, "Didn't find valid sector Id"); | ||
978 | } | ||
979 | fdc_mode = fdc_idle; | ||
980 | break; | ||
981 | case fdc_deleting: | ||
982 | case fdc_writing_data: | ||
983 | #ifdef TESTING | ||
984 | if (cause == no_error) { | ||
985 | TRACE(ft_t_flow, "writing segment %d", buff->segment_id); | ||
986 | } else { | ||
987 | TRACE(ft_t_noise, "error writing segment %d", | ||
988 | buff->segment_id); | ||
989 | } | ||
990 | #endif | ||
991 | if (ft_runner_status == aborting || | ||
992 | ft_runner_status == do_abort) { | ||
993 | TRACE(ft_t_flow, "aborting %s",fdc_mode_txt(fdc_mode)); | ||
994 | break; | ||
995 | } | ||
996 | if (buff->retry > 0) { | ||
997 | TRACE(ft_t_flow, "this is retry nr %d", buff->retry); | ||
998 | } | ||
999 | if (buff->bad_sector_map == FAKE_SEGMENT) { | ||
1000 | /* This condition occurs when trying to write to a | ||
1001 | * `fake' sector that's not accessible. Doesn't really | ||
1002 | * matter as it isn't used anyway ! Might be located | ||
1003 | * at wrong segment, then we'll fail on the next | ||
1004 | * segment. | ||
1005 | */ | ||
1006 | TRACE(ft_t_noise, "skipping empty segment (write)"); | ||
1007 | buff->remaining = 0; /* skip failing sector */ | ||
1008 | /* fake success: */ | ||
1009 | continue_xfer(buff, fdc_mode, 1); | ||
1010 | break; | ||
1011 | } | ||
1012 | switch (cause) { | ||
1013 | case no_error: | ||
1014 | determine_progress(buff, cause, in[5]); | ||
1015 | continue_xfer(buff, fdc_mode, 0); | ||
1016 | break; | ||
1017 | case no_data_error: | ||
1018 | case id_am_error: | ||
1019 | case id_crc_error: | ||
1020 | case data_am_error: | ||
1021 | case overrun_error: | ||
1022 | update_history(cause); | ||
1023 | determine_progress(buff, cause, in[5]); | ||
1024 | skip = find_resume_point(buff); | ||
1025 | retry_sector(buff, fdc_mode, skip); | ||
1026 | break; | ||
1027 | default: | ||
1028 | if (in[1] & 0x02) { | ||
1029 | TRACE(ft_t_err, "media not writable"); | ||
1030 | } else { | ||
1031 | TRACE(ft_t_bug, "unforeseen write error"); | ||
1032 | } | ||
1033 | fdc_mode = fdc_idle; | ||
1034 | break; | ||
1035 | } | ||
1036 | break; /* fdc_deleting || fdc_writing_data */ | ||
1037 | case fdc_formatting: | ||
1038 | /* The interrupt comes after formatting a segment. We then | ||
1039 | * have to set up QUICKLY for the next segment. But | ||
1040 | * afterwards, there is plenty of time. | ||
1041 | */ | ||
1042 | switch (cause) { | ||
1043 | case no_error: | ||
1044 | /* would like to keep most of the formatting stuff | ||
1045 | * outside the isr code, but timing is too critical | ||
1046 | */ | ||
1047 | if (determine_fmt_progress(buff, cause) >= 0) { | ||
1048 | continue_formatting(buff); | ||
1049 | } | ||
1050 | break; | ||
1051 | case no_data_error: | ||
1052 | case id_am_error: | ||
1053 | case id_crc_error: | ||
1054 | case data_am_error: | ||
1055 | case overrun_error: | ||
1056 | default: | ||
1057 | determine_fmt_progress(buff, cause); | ||
1058 | update_history(cause); | ||
1059 | if (in[1] & 0x02) { | ||
1060 | TRACE(ft_t_err, "media not writable"); | ||
1061 | } else { | ||
1062 | TRACE(ft_t_bug, "unforeseen write error"); | ||
1063 | } | ||
1064 | break; | ||
1065 | } /* cause */ | ||
1066 | break; | ||
1067 | default: | ||
1068 | TRACE(ft_t_warn, "Warning: unexpected irq during: %s", | ||
1069 | fdc_mode_txt(fdc_mode)); | ||
1070 | fdc_mode = fdc_idle; | ||
1071 | break; | ||
1072 | } | ||
1073 | TRACE_EXIT; | ||
1074 | } | ||
1075 | |||
1076 | /* FDC interrupt service routine. | ||
1077 | */ | ||
1078 | void fdc_isr(void) | ||
1079 | { | ||
1080 | static int isr_active; | ||
1081 | #ifdef TESTING | ||
1082 | unsigned int t0 = ftape_timestamp(); | ||
1083 | #endif | ||
1084 | TRACE_FUN(ft_t_any); | ||
1085 | |||
1086 | if (isr_active++) { | ||
1087 | --isr_active; | ||
1088 | TRACE(ft_t_bug, "BUG: nested interrupt, not good !"); | ||
1089 | *fdc.hook = fdc_isr; /* hook our handler into the fdc | ||
1090 | * code again | ||
1091 | */ | ||
1092 | TRACE_EXIT; | ||
1093 | } | ||
1094 | sti(); | ||
1095 | if (inb_p(fdc.msr) & FDC_BUSY) { /* Entering Result Phase */ | ||
1096 | ft_hide_interrupt = 0; | ||
1097 | handle_fdc_busy(ftape_get_buffer(ft_queue_head)); | ||
1098 | if (ft_runner_status == do_abort) { | ||
1099 | /* cease operation, remember tape position | ||
1100 | */ | ||
1101 | TRACE(ft_t_flow, "runner aborting"); | ||
1102 | ft_runner_status = aborting; | ||
1103 | ++ft_expected_stray_interrupts; | ||
1104 | } | ||
1105 | } else { /* !FDC_BUSY */ | ||
1106 | /* clear interrupt, cause should be gotten by issuing | ||
1107 | * a Sense Interrupt Status command. | ||
1108 | */ | ||
1109 | if (fdc_mode == fdc_recalibrating || fdc_mode == fdc_seeking) { | ||
1110 | if (ft_hide_interrupt) { | ||
1111 | int st0; | ||
1112 | int pcn; | ||
1113 | |||
1114 | if (fdc_sense_interrupt_status(&st0, &pcn) < 0) | ||
1115 | TRACE(ft_t_err, | ||
1116 | "sense interrupt status failed"); | ||
1117 | ftape_current_cylinder = pcn; | ||
1118 | TRACE(ft_t_flow, "handled hidden interrupt"); | ||
1119 | } | ||
1120 | ft_seek_completed = 1; | ||
1121 | fdc_mode = fdc_idle; | ||
1122 | } else if (!waitqueue_active(&ftape_wait_intr)) { | ||
1123 | if (ft_expected_stray_interrupts == 0) { | ||
1124 | TRACE(ft_t_warn, "unexpected stray interrupt"); | ||
1125 | } else { | ||
1126 | TRACE(ft_t_flow, "expected stray interrupt"); | ||
1127 | --ft_expected_stray_interrupts; | ||
1128 | } | ||
1129 | } else { | ||
1130 | if (fdc_mode == fdc_reading_data || | ||
1131 | fdc_mode == fdc_verifying || | ||
1132 | fdc_mode == fdc_writing_data || | ||
1133 | fdc_mode == fdc_deleting || | ||
1134 | fdc_mode == fdc_formatting || | ||
1135 | fdc_mode == fdc_reading_id) { | ||
1136 | if (inb_p(fdc.msr) & FDC_BUSY) { | ||
1137 | TRACE(ft_t_bug, | ||
1138 | "***** FDC failure, busy too late"); | ||
1139 | } else { | ||
1140 | TRACE(ft_t_bug, | ||
1141 | "***** FDC failure, no busy"); | ||
1142 | } | ||
1143 | } else { | ||
1144 | TRACE(ft_t_fdc_dma, "awaited stray interrupt"); | ||
1145 | } | ||
1146 | } | ||
1147 | ft_hide_interrupt = 0; | ||
1148 | } | ||
1149 | /* Handle sleep code. | ||
1150 | */ | ||
1151 | if (!ft_hide_interrupt) { | ||
1152 | ft_interrupt_seen ++; | ||
1153 | if (waitqueue_active(&ftape_wait_intr)) { | ||
1154 | wake_up_interruptible(&ftape_wait_intr); | ||
1155 | } | ||
1156 | } else { | ||
1157 | TRACE(ft_t_flow, "hiding interrupt while %s", | ||
1158 | waitqueue_active(&ftape_wait_intr) ? "waiting":"active"); | ||
1159 | } | ||
1160 | #ifdef TESTING | ||
1161 | t0 = ftape_timediff(t0, ftape_timestamp()); | ||
1162 | if (t0 >= 1000) { | ||
1163 | /* only tell us about long calls */ | ||
1164 | TRACE(ft_t_noise, "isr() duration: %5d usec", t0); | ||
1165 | } | ||
1166 | #endif | ||
1167 | *fdc.hook = fdc_isr; /* hook our handler into the fdc code again */ | ||
1168 | --isr_active; | ||
1169 | TRACE_EXIT; | ||
1170 | } | ||
diff --git a/drivers/char/ftape/lowlevel/fdc-isr.h b/drivers/char/ftape/lowlevel/fdc-isr.h deleted file mode 100644 index 065aa978942d..000000000000 --- a/drivers/char/ftape/lowlevel/fdc-isr.h +++ /dev/null | |||
@@ -1,55 +0,0 @@ | |||
1 | #ifndef _FDC_ISR_H | ||
2 | #define _FDC_ISR_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
6 | * (C) 1996-1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-isr.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:18:07 $ | ||
26 | * | ||
27 | * This file declares the global variables necessary to | ||
28 | * synchronize the interrupt service routine (isr) with the | ||
29 | * remainder of the QIC-40/80/3010/3020 floppy-tape driver | ||
30 | * "ftape" for Linux. | ||
31 | */ | ||
32 | |||
33 | /* | ||
34 | * fdc-isr.c defined public variables | ||
35 | */ | ||
36 | extern volatile int ft_expected_stray_interrupts; /* masks stray interrupts */ | ||
37 | extern volatile int ft_seek_completed; /* flag set by isr */ | ||
38 | extern volatile int ft_interrupt_seen; /* flag set by isr */ | ||
39 | extern volatile int ft_hide_interrupt; /* flag set by isr */ | ||
40 | |||
41 | /* | ||
42 | * fdc-io.c defined public functions | ||
43 | */ | ||
44 | extern void fdc_isr(void); | ||
45 | |||
46 | /* | ||
47 | * A kernel hook that steals one interrupt from the floppy | ||
48 | * driver (Should be fixed when the new fdc driver gets ready) | ||
49 | * See the linux kernel source files: | ||
50 | * drivers/block/floppy.c & drivers/block/blk.h | ||
51 | * for the details. | ||
52 | */ | ||
53 | extern void (*do_floppy) (void); | ||
54 | |||
55 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-bsm.c b/drivers/char/ftape/lowlevel/ftape-bsm.c deleted file mode 100644 index d1a301cc344f..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-bsm.c +++ /dev/null | |||
@@ -1,491 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1994-1996 Bas Laarhoven, | ||
3 | * (C) 1996-1997 Claus Heine. | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2, or (at your option) | ||
8 | any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; see the file COPYING. If not, write to | ||
17 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | |||
19 | * | ||
20 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-bsm.c,v $ | ||
21 | * $Revision: 1.3 $ | ||
22 | * $Date: 1997/10/05 19:15:15 $ | ||
23 | * | ||
24 | * This file contains the bad-sector map handling code for | ||
25 | * the QIC-117 floppy tape driver for Linux. | ||
26 | * QIC-40, QIC-80, QIC-3010 and QIC-3020 maps are implemented. | ||
27 | */ | ||
28 | |||
29 | #include <linux/string.h> | ||
30 | |||
31 | #include <linux/ftape.h> | ||
32 | #include "../lowlevel/ftape-tracing.h" | ||
33 | #include "../lowlevel/ftape-bsm.h" | ||
34 | #include "../lowlevel/ftape-ctl.h" | ||
35 | #include "../lowlevel/ftape-rw.h" | ||
36 | |||
37 | /* Global vars. | ||
38 | */ | ||
39 | |||
40 | /* Local vars. | ||
41 | */ | ||
42 | static __u8 *bad_sector_map; | ||
43 | static SectorCount *bsm_hash_ptr; | ||
44 | |||
45 | typedef enum { | ||
46 | forward, backward | ||
47 | } mode_type; | ||
48 | |||
49 | #if 0 | ||
50 | static void ftape_put_bad_sector_entry(int segment_id, SectorMap new_map); | ||
51 | #endif | ||
52 | |||
53 | #if 0 | ||
54 | /* fix_tape converts a normal QIC-80 tape into a 'wide' tape. | ||
55 | * For testing purposes only ! | ||
56 | */ | ||
57 | void fix_tape(__u8 * buffer, ft_format_type new_code) | ||
58 | { | ||
59 | static __u8 list[BAD_SECTOR_MAP_SIZE]; | ||
60 | SectorMap *src_ptr = (SectorMap *) list; | ||
61 | __u8 *dst_ptr = bad_sector_map; | ||
62 | SectorMap map; | ||
63 | unsigned int sector = 1; | ||
64 | int i; | ||
65 | |||
66 | if (format_code != fmt_var && format_code != fmt_big) { | ||
67 | memcpy(list, bad_sector_map, sizeof(list)); | ||
68 | memset(bad_sector_map, 0, sizeof(bad_sector_map)); | ||
69 | while ((__u8 *) src_ptr - list < sizeof(list)) { | ||
70 | map = *src_ptr++; | ||
71 | if (map == EMPTY_SEGMENT) { | ||
72 | *(SectorMap *) dst_ptr = 0x800000 + sector; | ||
73 | dst_ptr += 3; | ||
74 | sector += SECTORS_PER_SEGMENT; | ||
75 | } else { | ||
76 | for (i = 0; i < SECTORS_PER_SEGMENT; ++i) { | ||
77 | if (map & 1) { | ||
78 | *(SewctorMap *) dst_ptr = sector; | ||
79 | dst_ptr += 3; | ||
80 | } | ||
81 | map >>= 1; | ||
82 | ++sector; | ||
83 | } | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | bad_sector_map_changed = 1; | ||
88 | *(buffer + 4) = new_code; /* put new format code */ | ||
89 | if (format_code != fmt_var && new_code == fmt_big) { | ||
90 | PUT4(buffer, FT_6_HSEG_1, (__u32)GET2(buffer, 6)); | ||
91 | PUT4(buffer, FT_6_HSEG_2, (__u32)GET2(buffer, 8)); | ||
92 | PUT4(buffer, FT_6_FRST_SEG, (__u32)GET2(buffer, 10)); | ||
93 | PUT4(buffer, FT_6_LAST_SEG, (__u32)GET2(buffer, 12)); | ||
94 | memset(buffer+6, '\0', 8); | ||
95 | } | ||
96 | format_code = new_code; | ||
97 | } | ||
98 | |||
99 | #endif | ||
100 | |||
101 | /* given buffer that contains a header segment, find the end of | ||
102 | * of the bsm list | ||
103 | */ | ||
104 | __u8 * ftape_find_end_of_bsm_list(__u8 * address) | ||
105 | { | ||
106 | __u8 *ptr = address + FT_HEADER_END; /* start of bsm list */ | ||
107 | __u8 *limit = address + FT_SEGMENT_SIZE; | ||
108 | while (ptr + 2 < limit) { | ||
109 | if (ptr[0] || ptr[1] || ptr[2]) { | ||
110 | ptr += 3; | ||
111 | } else { | ||
112 | return ptr; | ||
113 | } | ||
114 | } | ||
115 | return NULL; | ||
116 | } | ||
117 | |||
118 | static inline void put_sector(SectorCount *ptr, unsigned int sector) | ||
119 | { | ||
120 | ptr->bytes[0] = sector & 0xff; | ||
121 | sector >>= 8; | ||
122 | ptr->bytes[1] = sector & 0xff; | ||
123 | sector >>= 8; | ||
124 | ptr->bytes[2] = sector & 0xff; | ||
125 | } | ||
126 | |||
127 | static inline unsigned int get_sector(SectorCount *ptr) | ||
128 | { | ||
129 | #if 1 | ||
130 | unsigned int sector; | ||
131 | |||
132 | sector = ptr->bytes[0]; | ||
133 | sector += ptr->bytes[1] << 8; | ||
134 | sector += ptr->bytes[2] << 16; | ||
135 | |||
136 | return sector; | ||
137 | #else | ||
138 | /* GET4 gets the next four bytes in Intel little endian order | ||
139 | * and converts them to host byte order and handles unaligned | ||
140 | * access. | ||
141 | */ | ||
142 | return (GET4(ptr, 0) & 0x00ffffff); /* back to host byte order */ | ||
143 | #endif | ||
144 | } | ||
145 | |||
146 | static void bsm_debug_fake(void) | ||
147 | { | ||
148 | /* for testing of bad sector handling at end of tape | ||
149 | */ | ||
150 | #if 0 | ||
151 | ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 3, | ||
152 | 0x000003e0; | ||
153 | ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 2, | ||
154 | 0xff3fffff; | ||
155 | ftape_put_bad_sector_entry(segments_per_track * tracks_per_tape - 1, | ||
156 | 0xffffe000; | ||
157 | #endif | ||
158 | /* Enable to test bad sector handling | ||
159 | */ | ||
160 | #if 0 | ||
161 | ftape_put_bad_sector_entry(30, 0xfffffffe) | ||
162 | ftape_put_bad_sector_entry(32, 0x7fffffff); | ||
163 | ftape_put_bad_sector_entry(34, 0xfffeffff); | ||
164 | ftape_put_bad_sector_entry(36, 0x55555555); | ||
165 | ftape_put_bad_sector_entry(38, 0xffffffff); | ||
166 | ftape_put_bad_sector_entry(50, 0xffff0000); | ||
167 | ftape_put_bad_sector_entry(51, 0xffffffff); | ||
168 | ftape_put_bad_sector_entry(52, 0xffffffff); | ||
169 | ftape_put_bad_sector_entry(53, 0x0000ffff); | ||
170 | #endif | ||
171 | /* Enable when testing multiple volume tar dumps. | ||
172 | */ | ||
173 | #if 0 | ||
174 | { | ||
175 | int i; | ||
176 | |||
177 | for (i = ft_first_data_segment; | ||
178 | i <= ft_last_data_segment - 7; ++i) { | ||
179 | ftape_put_bad_sector_entry(i, EMPTY_SEGMENT); | ||
180 | } | ||
181 | } | ||
182 | #endif | ||
183 | /* Enable when testing bit positions in *_error_map | ||
184 | */ | ||
185 | #if 0 | ||
186 | { | ||
187 | int i; | ||
188 | |||
189 | for (i = first_data_segment; i <= last_data_segment; ++i) { | ||
190 | ftape_put_bad_sector_entry(i, | ||
191 | ftape_get_bad_sector_entry(i) | ||
192 | | 0x00ff00ff); | ||
193 | } | ||
194 | } | ||
195 | #endif | ||
196 | } | ||
197 | |||
198 | static void print_bad_sector_map(void) | ||
199 | { | ||
200 | unsigned int good_sectors; | ||
201 | unsigned int total_bad = 0; | ||
202 | int i; | ||
203 | TRACE_FUN(ft_t_flow); | ||
204 | |||
205 | if (ft_format_code == fmt_big || | ||
206 | ft_format_code == fmt_var || | ||
207 | ft_format_code == fmt_1100ft) { | ||
208 | SectorCount *ptr = (SectorCount *)bad_sector_map; | ||
209 | unsigned int sector; | ||
210 | __u16 *ptr16; | ||
211 | |||
212 | while((sector = get_sector(ptr++)) != 0) { | ||
213 | if ((ft_format_code == fmt_big || | ||
214 | ft_format_code == fmt_var) && | ||
215 | sector & 0x800000) { | ||
216 | total_bad += FT_SECTORS_PER_SEGMENT - 3; | ||
217 | TRACE(ft_t_noise, "bad segment at sector: %6d", | ||
218 | sector & 0x7fffff); | ||
219 | } else { | ||
220 | ++total_bad; | ||
221 | TRACE(ft_t_noise, "bad sector: %6d", sector); | ||
222 | } | ||
223 | } | ||
224 | /* Display old ftape's end-of-file marks | ||
225 | */ | ||
226 | ptr16 = (__u16*)ptr; | ||
227 | while ((sector = get_unaligned(ptr16++)) != 0) { | ||
228 | TRACE(ft_t_noise, "Old ftape eof mark: %4d/%2d", | ||
229 | sector, get_unaligned(ptr16++)); | ||
230 | } | ||
231 | } else { /* fixed size format */ | ||
232 | for (i = ft_first_data_segment; | ||
233 | i < (int)(ft_segments_per_track * ft_tracks_per_tape); ++i) { | ||
234 | SectorMap map = ((SectorMap *) bad_sector_map)[i]; | ||
235 | |||
236 | if (map) { | ||
237 | TRACE(ft_t_noise, | ||
238 | "bsm for segment %4d: 0x%08x", i, (unsigned int)map); | ||
239 | total_bad += ((map == EMPTY_SEGMENT) | ||
240 | ? FT_SECTORS_PER_SEGMENT - 3 | ||
241 | : count_ones(map)); | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | good_sectors = | ||
246 | ((ft_segments_per_track * ft_tracks_per_tape - ft_first_data_segment) | ||
247 | * (FT_SECTORS_PER_SEGMENT - 3)) - total_bad; | ||
248 | TRACE(ft_t_info, "%d Kb usable on this tape", good_sectors); | ||
249 | if (total_bad == 0) { | ||
250 | TRACE(ft_t_info, | ||
251 | "WARNING: this tape has no bad blocks registered !"); | ||
252 | } else { | ||
253 | TRACE(ft_t_info, "%d bad sectors", total_bad); | ||
254 | } | ||
255 | TRACE_EXIT; | ||
256 | } | ||
257 | |||
258 | |||
259 | void ftape_extract_bad_sector_map(__u8 * buffer) | ||
260 | { | ||
261 | TRACE_FUN(ft_t_any); | ||
262 | |||
263 | /* Fill the bad sector map with the contents of buffer. | ||
264 | */ | ||
265 | if (ft_format_code == fmt_var || ft_format_code == fmt_big) { | ||
266 | /* QIC-3010/3020 and wide QIC-80 tapes no longer have a failed | ||
267 | * sector log but use this area to extend the bad sector map. | ||
268 | */ | ||
269 | bad_sector_map = &buffer[FT_HEADER_END]; | ||
270 | } else { | ||
271 | /* non-wide QIC-80 tapes have a failed sector log area that | ||
272 | * mustn't be included in the bad sector map. | ||
273 | */ | ||
274 | bad_sector_map = &buffer[FT_FSL + FT_FSL_SIZE]; | ||
275 | } | ||
276 | if (ft_format_code == fmt_1100ft || | ||
277 | ft_format_code == fmt_var || | ||
278 | ft_format_code == fmt_big) { | ||
279 | bsm_hash_ptr = (SectorCount *)bad_sector_map; | ||
280 | } else { | ||
281 | bsm_hash_ptr = NULL; | ||
282 | } | ||
283 | bsm_debug_fake(); | ||
284 | if (TRACE_LEVEL >= ft_t_info) { | ||
285 | print_bad_sector_map(); | ||
286 | } | ||
287 | TRACE_EXIT; | ||
288 | } | ||
289 | |||
290 | static inline SectorMap cvt2map(unsigned int sector) | ||
291 | { | ||
292 | return 1 << (((sector & 0x7fffff) - 1) % FT_SECTORS_PER_SEGMENT); | ||
293 | } | ||
294 | |||
295 | static inline int cvt2segment(unsigned int sector) | ||
296 | { | ||
297 | return ((sector & 0x7fffff) - 1) / FT_SECTORS_PER_SEGMENT; | ||
298 | } | ||
299 | |||
300 | static int forward_seek_entry(int segment_id, | ||
301 | SectorCount **ptr, | ||
302 | SectorMap *map) | ||
303 | { | ||
304 | unsigned int sector; | ||
305 | int segment; | ||
306 | |||
307 | do { | ||
308 | sector = get_sector((*ptr)++); | ||
309 | segment = cvt2segment(sector); | ||
310 | } while (sector != 0 && segment < segment_id); | ||
311 | (*ptr) --; /* point to first sector >= segment_id */ | ||
312 | /* Get all sectors in segment_id | ||
313 | */ | ||
314 | if (sector == 0 || segment != segment_id) { | ||
315 | *map = 0; | ||
316 | return 0; | ||
317 | } else if ((sector & 0x800000) && | ||
318 | (ft_format_code == fmt_var || ft_format_code == fmt_big)) { | ||
319 | *map = EMPTY_SEGMENT; | ||
320 | return FT_SECTORS_PER_SEGMENT; | ||
321 | } else { | ||
322 | int count = 1; | ||
323 | SectorCount *tmp_ptr = (*ptr) + 1; | ||
324 | |||
325 | *map = cvt2map(sector); | ||
326 | while ((sector = get_sector(tmp_ptr++)) != 0 && | ||
327 | (segment = cvt2segment(sector)) == segment_id) { | ||
328 | *map |= cvt2map(sector); | ||
329 | ++count; | ||
330 | } | ||
331 | return count; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | static int backwards_seek_entry(int segment_id, | ||
336 | SectorCount **ptr, | ||
337 | SectorMap *map) | ||
338 | { | ||
339 | unsigned int sector; | ||
340 | int segment; /* max unsigned int */ | ||
341 | |||
342 | if (*ptr <= (SectorCount *)bad_sector_map) { | ||
343 | *map = 0; | ||
344 | return 0; | ||
345 | } | ||
346 | do { | ||
347 | sector = get_sector(--(*ptr)); | ||
348 | segment = cvt2segment(sector); | ||
349 | } while (*ptr > (SectorCount *)bad_sector_map && segment > segment_id); | ||
350 | if (segment > segment_id) { /* at start of list, no entry found */ | ||
351 | *map = 0; | ||
352 | return 0; | ||
353 | } else if (segment < segment_id) { | ||
354 | /* before smaller entry, adjust for overshoot */ | ||
355 | (*ptr) ++; | ||
356 | *map = 0; | ||
357 | return 0; | ||
358 | } else if ((sector & 0x800000) && | ||
359 | (ft_format_code == fmt_big || ft_format_code == fmt_var)) { | ||
360 | *map = EMPTY_SEGMENT; | ||
361 | return FT_SECTORS_PER_SEGMENT; | ||
362 | } else { /* get all sectors in segment_id */ | ||
363 | int count = 1; | ||
364 | |||
365 | *map = cvt2map(sector); | ||
366 | while(*ptr > (SectorCount *)bad_sector_map) { | ||
367 | sector = get_sector(--(*ptr)); | ||
368 | segment = cvt2segment(sector); | ||
369 | if (segment != segment_id) { | ||
370 | break; | ||
371 | } | ||
372 | *map |= cvt2map(sector); | ||
373 | ++count; | ||
374 | } | ||
375 | if (segment < segment_id) { | ||
376 | (*ptr) ++; | ||
377 | } | ||
378 | return count; | ||
379 | } | ||
380 | } | ||
381 | |||
382 | #if 0 | ||
383 | static void ftape_put_bad_sector_entry(int segment_id, SectorMap new_map) | ||
384 | { | ||
385 | SectorCount *ptr = (SectorCount *)bad_sector_map; | ||
386 | int count; | ||
387 | int new_count; | ||
388 | SectorMap map; | ||
389 | TRACE_FUN(ft_t_any); | ||
390 | |||
391 | if (ft_format_code == fmt_1100ft || | ||
392 | ft_format_code == fmt_var || | ||
393 | ft_format_code == fmt_big) { | ||
394 | count = forward_seek_entry(segment_id, &ptr, &map); | ||
395 | new_count = count_ones(new_map); | ||
396 | /* If format code == 4 put empty segment instead of 32 | ||
397 | * bad sectors. | ||
398 | */ | ||
399 | if (ft_format_code == fmt_var || ft_format_code == fmt_big) { | ||
400 | if (new_count == FT_SECTORS_PER_SEGMENT) { | ||
401 | new_count = 1; | ||
402 | } | ||
403 | if (count == FT_SECTORS_PER_SEGMENT) { | ||
404 | count = 1; | ||
405 | } | ||
406 | } | ||
407 | if (count != new_count) { | ||
408 | /* insert (or delete if < 0) new_count - count | ||
409 | * entries. Move trailing part of list | ||
410 | * including terminating 0. | ||
411 | */ | ||
412 | SectorCount *hi_ptr = ptr; | ||
413 | |||
414 | do { | ||
415 | } while (get_sector(hi_ptr++) != 0); | ||
416 | /* Note: ptr is of type byte *, and each bad sector | ||
417 | * consumes 3 bytes. | ||
418 | */ | ||
419 | memmove(ptr + new_count, ptr + count, | ||
420 | (size_t)(hi_ptr - (ptr + count))*sizeof(SectorCount)); | ||
421 | } | ||
422 | TRACE(ft_t_noise, "putting map 0x%08x at %p, segment %d", | ||
423 | (unsigned int)new_map, ptr, segment_id); | ||
424 | if (new_count == 1 && new_map == EMPTY_SEGMENT) { | ||
425 | put_sector(ptr++, (0x800001 + | ||
426 | segment_id * | ||
427 | FT_SECTORS_PER_SEGMENT)); | ||
428 | } else { | ||
429 | int i = 0; | ||
430 | |||
431 | while (new_map) { | ||
432 | if (new_map & 1) { | ||
433 | put_sector(ptr++, | ||
434 | 1 + segment_id * | ||
435 | FT_SECTORS_PER_SEGMENT + i); | ||
436 | } | ||
437 | ++i; | ||
438 | new_map >>= 1; | ||
439 | } | ||
440 | } | ||
441 | } else { | ||
442 | ((SectorMap *) bad_sector_map)[segment_id] = new_map; | ||
443 | } | ||
444 | TRACE_EXIT; | ||
445 | } | ||
446 | #endif /* 0 */ | ||
447 | |||
448 | SectorMap ftape_get_bad_sector_entry(int segment_id) | ||
449 | { | ||
450 | if (ft_used_header_segment == -1) { | ||
451 | /* When reading header segment we'll need a blank map. | ||
452 | */ | ||
453 | return 0; | ||
454 | } else if (bsm_hash_ptr != NULL) { | ||
455 | /* Invariants: | ||
456 | * map - mask value returned on last call. | ||
457 | * bsm_hash_ptr - points to first sector greater or equal to | ||
458 | * first sector in last_referenced segment. | ||
459 | * last_referenced - segment id used in the last call, | ||
460 | * sector and map belong to this id. | ||
461 | * This code is designed for sequential access and retries. | ||
462 | * For true random access it may have to be redesigned. | ||
463 | */ | ||
464 | static int last_reference = -1; | ||
465 | static SectorMap map; | ||
466 | |||
467 | if (segment_id > last_reference) { | ||
468 | /* Skip all sectors before segment_id | ||
469 | */ | ||
470 | forward_seek_entry(segment_id, &bsm_hash_ptr, &map); | ||
471 | } else if (segment_id < last_reference) { | ||
472 | /* Skip backwards until begin of buffer or | ||
473 | * first sector in segment_id | ||
474 | */ | ||
475 | backwards_seek_entry(segment_id, &bsm_hash_ptr, &map); | ||
476 | } /* segment_id == last_reference : keep map */ | ||
477 | last_reference = segment_id; | ||
478 | return map; | ||
479 | } else { | ||
480 | return ((SectorMap *) bad_sector_map)[segment_id]; | ||
481 | } | ||
482 | } | ||
483 | |||
484 | /* This is simply here to prevent us from overwriting other kernel | ||
485 | * data. Writes will result in NULL Pointer dereference. | ||
486 | */ | ||
487 | void ftape_init_bsm(void) | ||
488 | { | ||
489 | bad_sector_map = NULL; | ||
490 | bsm_hash_ptr = NULL; | ||
491 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-bsm.h b/drivers/char/ftape/lowlevel/ftape-bsm.h deleted file mode 100644 index ed45465af4d4..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-bsm.h +++ /dev/null | |||
@@ -1,66 +0,0 @@ | |||
1 | #ifndef _FTAPE_BSM_H | ||
2 | #define _FTAPE_BSM_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1994-1996 Bas Laarhoven, | ||
6 | * (C) 1996-1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-bsm.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:18:07 $ | ||
26 | * | ||
27 | * This file contains definitions for the bad sector map handling | ||
28 | * routines for the QIC-117 floppy-tape driver for Linux. | ||
29 | */ | ||
30 | |||
31 | #include <linux/ftape.h> | ||
32 | #include <linux/ftape-header-segment.h> | ||
33 | |||
34 | #define EMPTY_SEGMENT (0xffffffff) | ||
35 | #define FAKE_SEGMENT (0xfffffffe) | ||
36 | |||
37 | /* maximum (format code 4) bad sector map size (bytes). | ||
38 | */ | ||
39 | #define BAD_SECTOR_MAP_SIZE (29 * SECTOR_SIZE - 256) | ||
40 | |||
41 | /* format code 4 bad sector entry, ftape uses this | ||
42 | * internally for all format codes | ||
43 | */ | ||
44 | typedef __u32 SectorMap; | ||
45 | /* variable and 1100 ft bad sector map entry. These three bytes represent | ||
46 | * a single sector address measured from BOT. | ||
47 | */ | ||
48 | typedef struct NewSectorMap { | ||
49 | __u8 bytes[3]; | ||
50 | } SectorCount; | ||
51 | |||
52 | |||
53 | /* | ||
54 | * ftape-bsm.c defined global vars. | ||
55 | */ | ||
56 | |||
57 | /* | ||
58 | * ftape-bsm.c defined global functions. | ||
59 | */ | ||
60 | extern void update_bad_sector_map(__u8 * buffer); | ||
61 | extern void ftape_extract_bad_sector_map(__u8 * buffer); | ||
62 | extern SectorMap ftape_get_bad_sector_entry(int segment_id); | ||
63 | extern __u8 *ftape_find_end_of_bsm_list(__u8 * address); | ||
64 | extern void ftape_init_bsm(void); | ||
65 | |||
66 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-buffer.c b/drivers/char/ftape/lowlevel/ftape-buffer.c deleted file mode 100644 index c706ff162771..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-buffer.c +++ /dev/null | |||
@@ -1,130 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1997 Claus-Justus Heine | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; see the file COPYING. If not, write to | ||
16 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | |||
18 | * | ||
19 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-buffer.c,v $ | ||
20 | * $Revision: 1.3 $ | ||
21 | * $Date: 1997/10/16 23:33:11 $ | ||
22 | * | ||
23 | * This file contains the allocator/dealloctor for ftape's dynamic dma | ||
24 | * buffer. | ||
25 | */ | ||
26 | |||
27 | #include <linux/slab.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/mman.h> | ||
30 | #include <asm/dma.h> | ||
31 | |||
32 | #include <linux/ftape.h> | ||
33 | #include "../lowlevel/ftape-rw.h" | ||
34 | #include "../lowlevel/ftape-read.h" | ||
35 | #include "../lowlevel/ftape-tracing.h" | ||
36 | #include "../lowlevel/ftape-buffer.h" | ||
37 | |||
38 | /* DMA'able memory allocation stuff. | ||
39 | */ | ||
40 | |||
41 | static inline void *dmaalloc(size_t size) | ||
42 | { | ||
43 | unsigned long addr; | ||
44 | |||
45 | if (size == 0) { | ||
46 | return NULL; | ||
47 | } | ||
48 | addr = __get_dma_pages(GFP_KERNEL, get_order(size)); | ||
49 | if (addr) { | ||
50 | struct page *page; | ||
51 | |||
52 | for (page = virt_to_page(addr); page < virt_to_page(addr+size); page++) | ||
53 | SetPageReserved(page); | ||
54 | } | ||
55 | return (void *)addr; | ||
56 | } | ||
57 | |||
58 | static inline void dmafree(void *addr, size_t size) | ||
59 | { | ||
60 | if (size > 0) { | ||
61 | struct page *page; | ||
62 | |||
63 | for (page = virt_to_page((unsigned long)addr); | ||
64 | page < virt_to_page((unsigned long)addr+size); page++) | ||
65 | ClearPageReserved(page); | ||
66 | free_pages((unsigned long) addr, get_order(size)); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | static int add_one_buffer(void) | ||
71 | { | ||
72 | TRACE_FUN(ft_t_flow); | ||
73 | |||
74 | if (ft_nr_buffers >= FT_MAX_NR_BUFFERS) { | ||
75 | TRACE_EXIT -ENOMEM; | ||
76 | } | ||
77 | ft_buffer[ft_nr_buffers] = kmalloc(sizeof(buffer_struct), GFP_KERNEL); | ||
78 | if (ft_buffer[ft_nr_buffers] == NULL) { | ||
79 | TRACE_EXIT -ENOMEM; | ||
80 | } | ||
81 | memset(ft_buffer[ft_nr_buffers], 0, sizeof(buffer_struct)); | ||
82 | ft_buffer[ft_nr_buffers]->address = dmaalloc(FT_BUFF_SIZE); | ||
83 | if (ft_buffer[ft_nr_buffers]->address == NULL) { | ||
84 | kfree(ft_buffer[ft_nr_buffers]); | ||
85 | ft_buffer[ft_nr_buffers] = NULL; | ||
86 | TRACE_EXIT -ENOMEM; | ||
87 | } | ||
88 | ft_nr_buffers ++; | ||
89 | TRACE(ft_t_info, "buffer nr #%d @ %p, dma area @ %p", | ||
90 | ft_nr_buffers, | ||
91 | ft_buffer[ft_nr_buffers-1], | ||
92 | ft_buffer[ft_nr_buffers-1]->address); | ||
93 | TRACE_EXIT 0; | ||
94 | } | ||
95 | |||
96 | static void del_one_buffer(void) | ||
97 | { | ||
98 | TRACE_FUN(ft_t_flow); | ||
99 | if (ft_nr_buffers > 0) { | ||
100 | TRACE(ft_t_info, "releasing buffer nr #%d @ %p, dma area @ %p", | ||
101 | ft_nr_buffers, | ||
102 | ft_buffer[ft_nr_buffers-1], | ||
103 | ft_buffer[ft_nr_buffers-1]->address); | ||
104 | ft_nr_buffers --; | ||
105 | dmafree(ft_buffer[ft_nr_buffers]->address, FT_BUFF_SIZE); | ||
106 | kfree(ft_buffer[ft_nr_buffers]); | ||
107 | ft_buffer[ft_nr_buffers] = NULL; | ||
108 | } | ||
109 | TRACE_EXIT; | ||
110 | } | ||
111 | |||
112 | int ftape_set_nr_buffers(int cnt) | ||
113 | { | ||
114 | int delta = cnt - ft_nr_buffers; | ||
115 | TRACE_FUN(ft_t_flow); | ||
116 | |||
117 | if (delta > 0) { | ||
118 | while (delta--) { | ||
119 | if (add_one_buffer() < 0) { | ||
120 | TRACE_EXIT -ENOMEM; | ||
121 | } | ||
122 | } | ||
123 | } else if (delta < 0) { | ||
124 | while (delta++) { | ||
125 | del_one_buffer(); | ||
126 | } | ||
127 | } | ||
128 | ftape_zap_read_buffers(); | ||
129 | TRACE_EXIT 0; | ||
130 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-buffer.h b/drivers/char/ftape/lowlevel/ftape-buffer.h deleted file mode 100644 index eec99cee8f82..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-buffer.h +++ /dev/null | |||
@@ -1,32 +0,0 @@ | |||
1 | #ifndef _FTAPE_BUFFER_H | ||
2 | #define _FTAPE_BUFFER_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1997 Claus-Justus Heine. | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-buffer.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:18:08 $ | ||
25 | * | ||
26 | * This file contains the allocator/dealloctor for ftape's dynamic dma | ||
27 | * buffer. | ||
28 | */ | ||
29 | |||
30 | extern int ftape_set_nr_buffers(int cnt); | ||
31 | |||
32 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-calibr.c b/drivers/char/ftape/lowlevel/ftape-calibr.c deleted file mode 100644 index 8e50bfd35a52..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-calibr.c +++ /dev/null | |||
@@ -1,275 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1993-1996 Bas Laarhoven. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; see the file COPYING. If not, write to | ||
16 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | |||
18 | * | ||
19 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-calibr.c,v $ | ||
20 | * $Revision: 1.2 $ | ||
21 | * $Date: 1997/10/05 19:18:08 $ | ||
22 | * | ||
23 | * GP calibration routine for processor speed dependent | ||
24 | * functions. | ||
25 | */ | ||
26 | |||
27 | #include <linux/errno.h> | ||
28 | #include <linux/jiffies.h> | ||
29 | #include <asm/system.h> | ||
30 | #include <asm/io.h> | ||
31 | #if defined(__alpha__) | ||
32 | # include <asm/hwrpb.h> | ||
33 | #elif defined(__x86_64__) | ||
34 | # include <asm/msr.h> | ||
35 | # include <asm/timex.h> | ||
36 | #elif defined(__i386__) | ||
37 | # include <linux/timex.h> | ||
38 | #endif | ||
39 | #include <linux/ftape.h> | ||
40 | #include "../lowlevel/ftape-tracing.h" | ||
41 | #include "../lowlevel/ftape-calibr.h" | ||
42 | #include "../lowlevel/fdc-io.h" | ||
43 | |||
44 | #undef DEBUG | ||
45 | |||
46 | #if !defined(__alpha__) && !defined(__i386__) && !defined(__x86_64__) | ||
47 | # error Ftape is not implemented for this architecture! | ||
48 | #endif | ||
49 | |||
50 | #if defined(__alpha__) || defined(__x86_64__) | ||
51 | static unsigned long ps_per_cycle = 0; | ||
52 | #endif | ||
53 | |||
54 | static spinlock_t calibr_lock; | ||
55 | |||
56 | /* | ||
57 | * Note: On Intel PCs, the clock ticks at 100 Hz (HZ==100) which is | ||
58 | * too slow for certain timeouts (and that clock doesn't even tick | ||
59 | * when interrupts are disabled). For that reason, the 8254 timer is | ||
60 | * used directly to implement fine-grained timeouts. However, on | ||
61 | * Alpha PCs, the 8254 is *not* used to implement the clock tick | ||
62 | * (which is 1024 Hz, normally) and the 8254 timer runs at some | ||
63 | * "random" frequency (it seems to run at 18Hz, but it's not safe to | ||
64 | * rely on this value). Instead, we use the Alpha's "rpcc" | ||
65 | * instruction to read cycle counts. As this is a 32 bit counter, | ||
66 | * it will overflow only once per 30 seconds (on a 200MHz machine), | ||
67 | * which is plenty. | ||
68 | */ | ||
69 | |||
70 | unsigned int ftape_timestamp(void) | ||
71 | { | ||
72 | #if defined(__alpha__) | ||
73 | unsigned long r; | ||
74 | |||
75 | asm volatile ("rpcc %0" : "=r" (r)); | ||
76 | return r; | ||
77 | #elif defined(__x86_64__) | ||
78 | unsigned long r; | ||
79 | rdtscl(r); | ||
80 | return r; | ||
81 | #elif defined(__i386__) | ||
82 | |||
83 | /* | ||
84 | * Note that there is some time between counter underflowing and jiffies | ||
85 | * increasing, so the code below won't always give correct output. | ||
86 | * -Vojtech | ||
87 | */ | ||
88 | |||
89 | unsigned long flags; | ||
90 | __u16 lo; | ||
91 | __u16 hi; | ||
92 | |||
93 | spin_lock_irqsave(&calibr_lock, flags); | ||
94 | outb_p(0x00, 0x43); /* latch the count ASAP */ | ||
95 | lo = inb_p(0x40); /* read the latched count */ | ||
96 | lo |= inb(0x40) << 8; | ||
97 | hi = jiffies; | ||
98 | spin_unlock_irqrestore(&calibr_lock, flags); | ||
99 | return ((hi + 1) * (unsigned int) LATCH) - lo; /* downcounter ! */ | ||
100 | #endif | ||
101 | } | ||
102 | |||
103 | static unsigned int short_ftape_timestamp(void) | ||
104 | { | ||
105 | #if defined(__alpha__) || defined(__x86_64__) | ||
106 | return ftape_timestamp(); | ||
107 | #elif defined(__i386__) | ||
108 | unsigned int count; | ||
109 | unsigned long flags; | ||
110 | |||
111 | spin_lock_irqsave(&calibr_lock, flags); | ||
112 | outb_p(0x00, 0x43); /* latch the count ASAP */ | ||
113 | count = inb_p(0x40); /* read the latched count */ | ||
114 | count |= inb(0x40) << 8; | ||
115 | spin_unlock_irqrestore(&calibr_lock, flags); | ||
116 | return (LATCH - count); /* normal: downcounter */ | ||
117 | #endif | ||
118 | } | ||
119 | |||
120 | static unsigned int diff(unsigned int t0, unsigned int t1) | ||
121 | { | ||
122 | #if defined(__alpha__) || defined(__x86_64__) | ||
123 | return (t1 - t0); | ||
124 | #elif defined(__i386__) | ||
125 | /* | ||
126 | * This is tricky: to work for both short and full ftape_timestamps | ||
127 | * we'll have to discriminate between these. | ||
128 | * If it _looks_ like short stamps with wrapping around we'll | ||
129 | * asume it are. This will generate a small error if it really | ||
130 | * was a (very large) delta from full ftape_timestamps. | ||
131 | */ | ||
132 | return (t1 <= t0 && t0 <= LATCH) ? t1 + LATCH - t0 : t1 - t0; | ||
133 | #endif | ||
134 | } | ||
135 | |||
136 | static unsigned int usecs(unsigned int count) | ||
137 | { | ||
138 | #if defined(__alpha__) || defined(__x86_64__) | ||
139 | return (ps_per_cycle * count) / 1000000UL; | ||
140 | #elif defined(__i386__) | ||
141 | return (10000 * count) / ((CLOCK_TICK_RATE + 50) / 100); | ||
142 | #endif | ||
143 | } | ||
144 | |||
145 | unsigned int ftape_timediff(unsigned int t0, unsigned int t1) | ||
146 | { | ||
147 | /* | ||
148 | * Calculate difference in usec for ftape_timestamp results t0 & t1. | ||
149 | * Note that on the i386 platform with short time-stamps, the | ||
150 | * maximum allowed timespan is 1/HZ or we'll lose ticks! | ||
151 | */ | ||
152 | return usecs(diff(t0, t1)); | ||
153 | } | ||
154 | |||
155 | /* To get an indication of the I/O performance, | ||
156 | * measure the duration of the inb() function. | ||
157 | */ | ||
158 | static void time_inb(void) | ||
159 | { | ||
160 | int i; | ||
161 | int t0, t1; | ||
162 | unsigned long flags; | ||
163 | int status; | ||
164 | TRACE_FUN(ft_t_any); | ||
165 | |||
166 | spin_lock_irqsave(&calibr_lock, flags); | ||
167 | t0 = short_ftape_timestamp(); | ||
168 | for (i = 0; i < 1000; ++i) { | ||
169 | status = inb(fdc.msr); | ||
170 | } | ||
171 | t1 = short_ftape_timestamp(); | ||
172 | spin_unlock_irqrestore(&calibr_lock, flags); | ||
173 | TRACE(ft_t_info, "inb() duration: %d nsec", ftape_timediff(t0, t1)); | ||
174 | TRACE_EXIT; | ||
175 | } | ||
176 | |||
177 | static void init_clock(void) | ||
178 | { | ||
179 | TRACE_FUN(ft_t_any); | ||
180 | |||
181 | #if defined(__x86_64__) | ||
182 | ps_per_cycle = 1000000000UL / cpu_khz; | ||
183 | #elif defined(__alpha__) | ||
184 | extern struct hwrpb_struct *hwrpb; | ||
185 | ps_per_cycle = (1000*1000*1000*1000UL) / hwrpb->cycle_freq; | ||
186 | #endif | ||
187 | TRACE_EXIT; | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * Input: function taking int count as parameter. | ||
192 | * pointers to calculated calibration variables. | ||
193 | */ | ||
194 | void ftape_calibrate(char *name, | ||
195 | void (*fun) (unsigned int), | ||
196 | unsigned int *calibr_count, | ||
197 | unsigned int *calibr_time) | ||
198 | { | ||
199 | static int first_time = 1; | ||
200 | int i; | ||
201 | unsigned int tc = 0; | ||
202 | unsigned int count; | ||
203 | unsigned int time; | ||
204 | #if defined(__i386__) | ||
205 | unsigned int old_tc = 0; | ||
206 | unsigned int old_count = 1; | ||
207 | unsigned int old_time = 1; | ||
208 | #endif | ||
209 | TRACE_FUN(ft_t_flow); | ||
210 | |||
211 | if (first_time) { /* get idea of I/O performance */ | ||
212 | init_clock(); | ||
213 | time_inb(); | ||
214 | first_time = 0; | ||
215 | } | ||
216 | /* value of timeout must be set so that on very slow systems | ||
217 | * it will give a time less than one jiffy, and on | ||
218 | * very fast systems it'll give reasonable precision. | ||
219 | */ | ||
220 | |||
221 | count = 40; | ||
222 | for (i = 0; i < 15; ++i) { | ||
223 | unsigned int t0; | ||
224 | unsigned int t1; | ||
225 | unsigned int once; | ||
226 | unsigned int multiple; | ||
227 | unsigned long flags; | ||
228 | |||
229 | *calibr_count = | ||
230 | *calibr_time = count; /* set TC to 1 */ | ||
231 | spin_lock_irqsave(&calibr_lock, flags); | ||
232 | fun(0); /* dummy, get code into cache */ | ||
233 | t0 = short_ftape_timestamp(); | ||
234 | fun(0); /* overhead + one test */ | ||
235 | t1 = short_ftape_timestamp(); | ||
236 | once = diff(t0, t1); | ||
237 | t0 = short_ftape_timestamp(); | ||
238 | fun(count); /* overhead + count tests */ | ||
239 | t1 = short_ftape_timestamp(); | ||
240 | multiple = diff(t0, t1); | ||
241 | spin_unlock_irqrestore(&calibr_lock, flags); | ||
242 | time = ftape_timediff(0, multiple - once); | ||
243 | tc = (1000 * time) / (count - 1); | ||
244 | TRACE(ft_t_any, "once:%3d us,%6d times:%6d us, TC:%5d ns", | ||
245 | usecs(once), count - 1, usecs(multiple), tc); | ||
246 | #if defined(__alpha__) || defined(__x86_64__) | ||
247 | /* | ||
248 | * Increase the calibration count exponentially until the | ||
249 | * calibration time exceeds 100 ms. | ||
250 | */ | ||
251 | if (time >= 100*1000) { | ||
252 | break; | ||
253 | } | ||
254 | #elif defined(__i386__) | ||
255 | /* | ||
256 | * increase the count until the resulting time nears 2/HZ, | ||
257 | * then the tc will drop sharply because we lose LATCH counts. | ||
258 | */ | ||
259 | if (tc <= old_tc / 2) { | ||
260 | time = old_time; | ||
261 | count = old_count; | ||
262 | break; | ||
263 | } | ||
264 | old_tc = tc; | ||
265 | old_count = count; | ||
266 | old_time = time; | ||
267 | #endif | ||
268 | count *= 2; | ||
269 | } | ||
270 | *calibr_count = count - 1; | ||
271 | *calibr_time = time; | ||
272 | TRACE(ft_t_info, "TC for `%s()' = %d nsec (at %d counts)", | ||
273 | name, (1000 * *calibr_time) / *calibr_count, *calibr_count); | ||
274 | TRACE_EXIT; | ||
275 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-calibr.h b/drivers/char/ftape/lowlevel/ftape-calibr.h deleted file mode 100644 index 0c7e75246c7d..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-calibr.h +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | #ifndef _FTAPE_CALIBR_H | ||
2 | #define _FTAPE_CALIBR_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1993-1996 Bas Laarhoven. | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-calibr.h,v $ | ||
23 | * $Revision: 1.1 $ | ||
24 | * $Date: 1997/09/19 09:05:26 $ | ||
25 | * | ||
26 | * This file contains a gp calibration routine for | ||
27 | * hardware dependent timeout functions. | ||
28 | */ | ||
29 | |||
30 | extern void ftape_calibrate(char *name, | ||
31 | void (*fun) (unsigned int), | ||
32 | unsigned int *calibr_count, | ||
33 | unsigned int *calibr_time); | ||
34 | extern unsigned int ftape_timestamp(void); | ||
35 | extern unsigned int ftape_timediff(unsigned int t0, unsigned int t1); | ||
36 | |||
37 | #endif /* _FTAPE_CALIBR_H */ | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-ctl.c b/drivers/char/ftape/lowlevel/ftape-ctl.c deleted file mode 100644 index 5d7c1ce92d59..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-ctl.c +++ /dev/null | |||
@@ -1,896 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
3 | * 1996-1997 Claus-Justus Heine. | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2, or (at your option) | ||
8 | any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; see the file COPYING. If not, write to | ||
17 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | |||
19 | * | ||
20 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-ctl.c,v $ | ||
21 | * $Revision: 1.4 $ | ||
22 | * $Date: 1997/11/11 14:37:44 $ | ||
23 | * | ||
24 | * This file contains the non-read/write ftape functions for the | ||
25 | * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. | ||
26 | */ | ||
27 | |||
28 | #include <linux/errno.h> | ||
29 | #include <linux/mm.h> | ||
30 | #include <linux/mman.h> | ||
31 | |||
32 | #include <linux/ftape.h> | ||
33 | #include <linux/qic117.h> | ||
34 | #include <asm/uaccess.h> | ||
35 | #include <asm/io.h> | ||
36 | |||
37 | /* ease porting between pre-2.4.x and later kernels */ | ||
38 | #define vma_get_pgoff(v) ((v)->vm_pgoff) | ||
39 | |||
40 | #include "../lowlevel/ftape-tracing.h" | ||
41 | #include "../lowlevel/ftape-io.h" | ||
42 | #include "../lowlevel/ftape-ctl.h" | ||
43 | #include "../lowlevel/ftape-write.h" | ||
44 | #include "../lowlevel/ftape-read.h" | ||
45 | #include "../lowlevel/ftape-rw.h" | ||
46 | #include "../lowlevel/ftape-bsm.h" | ||
47 | |||
48 | /* Global vars. | ||
49 | */ | ||
50 | ftape_info ftape_status = { | ||
51 | /* vendor information */ | ||
52 | { 0, }, /* drive type */ | ||
53 | /* data rates */ | ||
54 | 500, /* used data rate */ | ||
55 | 500, /* drive max rate */ | ||
56 | 500, /* fdc max rate */ | ||
57 | /* drive selection, either FTAPE_SEL_A/B/C/D */ | ||
58 | -1, /* drive selection */ | ||
59 | /* flags set after decode the drive and tape status */ | ||
60 | 0, /* formatted */ | ||
61 | 1, /* no tape */ | ||
62 | 1, /* write protected */ | ||
63 | 1, /* new tape */ | ||
64 | /* values of last queried drive/tape status and error */ | ||
65 | {{0,}}, /* last error code */ | ||
66 | {{0,}}, /* drive status, configuration, tape status */ | ||
67 | /* cartridge geometry */ | ||
68 | 20, /* tracks_per_tape */ | ||
69 | 102, /* segments_per_track */ | ||
70 | /* location of header segments, etc. */ | ||
71 | -1, /* used_header_segment */ | ||
72 | -1, /* header_segment_1 */ | ||
73 | -1, /* header_segment_2 */ | ||
74 | -1, /* first_data_segment */ | ||
75 | -1, /* last_data_segment */ | ||
76 | /* the format code as stored in the header segment */ | ||
77 | fmt_normal, /* format code */ | ||
78 | /* the default for the qic std: unknown */ | ||
79 | -1, | ||
80 | /* is tape running? */ | ||
81 | idle, /* runner_state */ | ||
82 | /* is tape reading/writing/verifying/formatting/deleting */ | ||
83 | idle, /* driver state */ | ||
84 | /* flags fatal hardware error */ | ||
85 | 1, /* failure */ | ||
86 | /* history record */ | ||
87 | { 0, } /* history record */ | ||
88 | }; | ||
89 | |||
90 | int ftape_segments_per_head = 1020; | ||
91 | int ftape_segments_per_cylinder = 4; | ||
92 | int ftape_init_drive_needed = 1; /* need to be global for ftape_reset_drive() | ||
93 | * in ftape-io.c | ||
94 | */ | ||
95 | |||
96 | /* Local vars. | ||
97 | */ | ||
98 | static const vendor_struct vendors[] = QIC117_VENDORS; | ||
99 | static const wakeup_method methods[] = WAKEUP_METHODS; | ||
100 | |||
101 | const ftape_info *ftape_get_status(void) | ||
102 | { | ||
103 | #if defined(STATUS_PARANOYA) | ||
104 | static ftape_info get_status; | ||
105 | |||
106 | get_status = ftape_status; | ||
107 | return &get_status; | ||
108 | #else | ||
109 | return &ftape_status; /* maybe return only a copy of it to assure | ||
110 | * read only access | ||
111 | */ | ||
112 | #endif | ||
113 | } | ||
114 | |||
115 | static int ftape_not_operational(int status) | ||
116 | { | ||
117 | /* return true if status indicates tape can not be used. | ||
118 | */ | ||
119 | return ((status ^ QIC_STATUS_CARTRIDGE_PRESENT) & | ||
120 | (QIC_STATUS_ERROR | | ||
121 | QIC_STATUS_CARTRIDGE_PRESENT | | ||
122 | QIC_STATUS_NEW_CARTRIDGE)); | ||
123 | } | ||
124 | |||
125 | int ftape_seek_to_eot(void) | ||
126 | { | ||
127 | int status; | ||
128 | TRACE_FUN(ft_t_any); | ||
129 | |||
130 | TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),); | ||
131 | while ((status & QIC_STATUS_AT_EOT) == 0) { | ||
132 | if (ftape_not_operational(status)) { | ||
133 | TRACE_EXIT -EIO; | ||
134 | } | ||
135 | TRACE_CATCH(ftape_command_wait(QIC_PHYSICAL_FORWARD, | ||
136 | ftape_timeout.rewind,&status),); | ||
137 | } | ||
138 | TRACE_EXIT 0; | ||
139 | } | ||
140 | |||
141 | int ftape_seek_to_bot(void) | ||
142 | { | ||
143 | int status; | ||
144 | TRACE_FUN(ft_t_any); | ||
145 | |||
146 | TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),); | ||
147 | while ((status & QIC_STATUS_AT_BOT) == 0) { | ||
148 | if (ftape_not_operational(status)) { | ||
149 | TRACE_EXIT -EIO; | ||
150 | } | ||
151 | TRACE_CATCH(ftape_command_wait(QIC_PHYSICAL_REVERSE, | ||
152 | ftape_timeout.rewind,&status),); | ||
153 | } | ||
154 | TRACE_EXIT 0; | ||
155 | } | ||
156 | |||
157 | static int ftape_new_cartridge(void) | ||
158 | { | ||
159 | ft_location.track = -1; /* force seek on first access */ | ||
160 | ftape_zap_read_buffers(); | ||
161 | ftape_zap_write_buffers(); | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | int ftape_abort_operation(void) | ||
166 | { | ||
167 | int result = 0; | ||
168 | int status; | ||
169 | TRACE_FUN(ft_t_flow); | ||
170 | |||
171 | if (ft_runner_status == running) { | ||
172 | TRACE(ft_t_noise, "aborting runner, waiting"); | ||
173 | |||
174 | ft_runner_status = do_abort; | ||
175 | /* set timeout so that the tape will run to logical EOT | ||
176 | * if we missed the last sector and there are no queue pulses. | ||
177 | */ | ||
178 | result = ftape_dumb_stop(); | ||
179 | } | ||
180 | if (ft_runner_status != idle) { | ||
181 | if (ft_runner_status == do_abort) { | ||
182 | TRACE(ft_t_noise, "forcing runner abort"); | ||
183 | } | ||
184 | TRACE(ft_t_noise, "stopping tape"); | ||
185 | result = ftape_stop_tape(&status); | ||
186 | ft_location.known = 0; | ||
187 | ft_runner_status = idle; | ||
188 | } | ||
189 | ftape_reset_buffer(); | ||
190 | ftape_zap_read_buffers(); | ||
191 | ftape_set_state(idle); | ||
192 | TRACE_EXIT result; | ||
193 | } | ||
194 | |||
195 | static int lookup_vendor_id(unsigned int vendor_id) | ||
196 | { | ||
197 | int i = 0; | ||
198 | |||
199 | while (vendors[i].vendor_id != vendor_id) { | ||
200 | if (++i >= NR_ITEMS(vendors)) { | ||
201 | return -1; | ||
202 | } | ||
203 | } | ||
204 | return i; | ||
205 | } | ||
206 | |||
207 | static void ftape_detach_drive(void) | ||
208 | { | ||
209 | TRACE_FUN(ft_t_any); | ||
210 | |||
211 | TRACE(ft_t_flow, "disabling tape drive and fdc"); | ||
212 | ftape_put_drive_to_sleep(ft_drive_type.wake_up); | ||
213 | fdc_catch_stray_interrupts(1); /* one always comes */ | ||
214 | fdc_disable(); | ||
215 | fdc_release_irq_and_dma(); | ||
216 | fdc_release_regions(); | ||
217 | TRACE_EXIT; | ||
218 | } | ||
219 | |||
220 | static void clear_history(void) | ||
221 | { | ||
222 | ft_history.used = 0; | ||
223 | ft_history.id_am_errors = | ||
224 | ft_history.id_crc_errors = | ||
225 | ft_history.data_am_errors = | ||
226 | ft_history.data_crc_errors = | ||
227 | ft_history.overrun_errors = | ||
228 | ft_history.no_data_errors = | ||
229 | ft_history.retries = | ||
230 | ft_history.crc_errors = | ||
231 | ft_history.crc_failures = | ||
232 | ft_history.ecc_failures = | ||
233 | ft_history.corrected = | ||
234 | ft_history.defects = | ||
235 | ft_history.rewinds = 0; | ||
236 | } | ||
237 | |||
238 | static int ftape_activate_drive(vendor_struct * drive_type) | ||
239 | { | ||
240 | int result = 0; | ||
241 | TRACE_FUN(ft_t_flow); | ||
242 | |||
243 | /* If we already know the drive type, wake it up. | ||
244 | * Else try to find out what kind of drive is attached. | ||
245 | */ | ||
246 | if (drive_type->wake_up != unknown_wake_up) { | ||
247 | TRACE(ft_t_flow, "enabling tape drive and fdc"); | ||
248 | result = ftape_wakeup_drive(drive_type->wake_up); | ||
249 | if (result < 0) { | ||
250 | TRACE(ft_t_err, "known wakeup method failed"); | ||
251 | } | ||
252 | } else { | ||
253 | wake_up_types method; | ||
254 | const ft_trace_t old_tracing = TRACE_LEVEL; | ||
255 | if (TRACE_LEVEL < ft_t_flow) { | ||
256 | SET_TRACE_LEVEL(ft_t_bug); | ||
257 | } | ||
258 | |||
259 | /* Try to awaken the drive using all known methods. | ||
260 | * Lower tracing for a while. | ||
261 | */ | ||
262 | for (method=no_wake_up; method < NR_ITEMS(methods); ++method) { | ||
263 | drive_type->wake_up = method; | ||
264 | #ifdef CONFIG_FT_TWO_DRIVES | ||
265 | /* Test setup for dual drive configuration. | ||
266 | * /dev/rft2 uses mountain wakeup | ||
267 | * /dev/rft3 uses colorado wakeup | ||
268 | * Other systems will use the normal scheme. | ||
269 | */ | ||
270 | if ((ft_drive_sel < 2) || | ||
271 | (ft_drive_sel == 2 && method == FT_WAKE_UP_1) || | ||
272 | (ft_drive_sel == 3 && method == FT_WAKE_UP_2)) { | ||
273 | result=ftape_wakeup_drive(drive_type->wake_up); | ||
274 | } else { | ||
275 | result = -EIO; | ||
276 | } | ||
277 | #else | ||
278 | result = ftape_wakeup_drive(drive_type->wake_up); | ||
279 | #endif | ||
280 | if (result >= 0) { | ||
281 | TRACE(ft_t_warn, "drive wakeup method: %s", | ||
282 | methods[drive_type->wake_up].name); | ||
283 | break; | ||
284 | } | ||
285 | } | ||
286 | SET_TRACE_LEVEL(old_tracing); | ||
287 | |||
288 | if (method >= NR_ITEMS(methods)) { | ||
289 | /* no response at all, cannot open this drive */ | ||
290 | drive_type->wake_up = unknown_wake_up; | ||
291 | TRACE(ft_t_err, "no tape drive found !"); | ||
292 | result = -ENODEV; | ||
293 | } | ||
294 | } | ||
295 | TRACE_EXIT result; | ||
296 | } | ||
297 | |||
298 | static int ftape_get_drive_status(void) | ||
299 | { | ||
300 | int result; | ||
301 | int status; | ||
302 | TRACE_FUN(ft_t_flow); | ||
303 | |||
304 | ft_no_tape = ft_write_protected = 0; | ||
305 | /* Tape drive is activated now. | ||
306 | * First clear error status if present. | ||
307 | */ | ||
308 | do { | ||
309 | result = ftape_ready_wait(ftape_timeout.reset, &status); | ||
310 | if (result < 0) { | ||
311 | if (result == -ETIME) { | ||
312 | TRACE(ft_t_err, "ftape_ready_wait timeout"); | ||
313 | } else if (result == -EINTR) { | ||
314 | TRACE(ft_t_err, "ftape_ready_wait aborted"); | ||
315 | } else { | ||
316 | TRACE(ft_t_err, "ftape_ready_wait failed"); | ||
317 | } | ||
318 | TRACE_EXIT -EIO; | ||
319 | } | ||
320 | /* Clear error condition (drive is ready !) | ||
321 | */ | ||
322 | if (status & QIC_STATUS_ERROR) { | ||
323 | unsigned int error; | ||
324 | qic117_cmd_t command; | ||
325 | |||
326 | TRACE(ft_t_err, "error status set"); | ||
327 | result = ftape_report_error(&error, &command, 1); | ||
328 | if (result < 0) { | ||
329 | TRACE(ft_t_err, | ||
330 | "report_error_code failed: %d", result); | ||
331 | /* hope it's working next time */ | ||
332 | ftape_reset_drive(); | ||
333 | TRACE_EXIT -EIO; | ||
334 | } else if (error != 0) { | ||
335 | TRACE(ft_t_noise, "error code : %d", error); | ||
336 | TRACE(ft_t_noise, "error command: %d", command); | ||
337 | } | ||
338 | } | ||
339 | if (status & QIC_STATUS_NEW_CARTRIDGE) { | ||
340 | unsigned int error; | ||
341 | qic117_cmd_t command; | ||
342 | const ft_trace_t old_tracing = TRACE_LEVEL; | ||
343 | SET_TRACE_LEVEL(ft_t_bug); | ||
344 | |||
345 | /* Undocumented feature: Must clear (not present!) | ||
346 | * error here or we'll fail later. | ||
347 | */ | ||
348 | ftape_report_error(&error, &command, 1); | ||
349 | |||
350 | SET_TRACE_LEVEL(old_tracing); | ||
351 | TRACE(ft_t_info, "status: new cartridge"); | ||
352 | ft_new_tape = 1; | ||
353 | } else { | ||
354 | ft_new_tape = 0; | ||
355 | } | ||
356 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
357 | } while (status & QIC_STATUS_ERROR); | ||
358 | |||
359 | ft_no_tape = !(status & QIC_STATUS_CARTRIDGE_PRESENT); | ||
360 | ft_write_protected = (status & QIC_STATUS_WRITE_PROTECT) != 0; | ||
361 | if (ft_no_tape) { | ||
362 | TRACE(ft_t_warn, "no cartridge present"); | ||
363 | } else { | ||
364 | if (ft_write_protected) { | ||
365 | TRACE(ft_t_noise, "Write protected cartridge"); | ||
366 | } | ||
367 | } | ||
368 | TRACE_EXIT 0; | ||
369 | } | ||
370 | |||
371 | static void ftape_log_vendor_id(void) | ||
372 | { | ||
373 | int vendor_index; | ||
374 | TRACE_FUN(ft_t_flow); | ||
375 | |||
376 | ftape_report_vendor_id(&ft_drive_type.vendor_id); | ||
377 | vendor_index = lookup_vendor_id(ft_drive_type.vendor_id); | ||
378 | if (ft_drive_type.vendor_id == UNKNOWN_VENDOR && | ||
379 | ft_drive_type.wake_up == wake_up_colorado) { | ||
380 | vendor_index = 0; | ||
381 | /* hack to get rid of all this mail */ | ||
382 | ft_drive_type.vendor_id = 0; | ||
383 | } | ||
384 | if (vendor_index < 0) { | ||
385 | /* Unknown vendor id, first time opening device. The | ||
386 | * drive_type remains set to type found at wakeup | ||
387 | * time, this will probably keep the driver operating | ||
388 | * for this new vendor. | ||
389 | */ | ||
390 | TRACE(ft_t_warn, "\n" | ||
391 | KERN_INFO "============ unknown vendor id ===========\n" | ||
392 | KERN_INFO "A new, yet unsupported tape drive is found\n" | ||
393 | KERN_INFO "Please report the following values:\n" | ||
394 | KERN_INFO " Vendor id : 0x%04x\n" | ||
395 | KERN_INFO " Wakeup method : %s\n" | ||
396 | KERN_INFO "And a description of your tape drive\n" | ||
397 | KERN_INFO "to "THE_FTAPE_MAINTAINER"\n" | ||
398 | KERN_INFO "==========================================", | ||
399 | ft_drive_type.vendor_id, | ||
400 | methods[ft_drive_type.wake_up].name); | ||
401 | ft_drive_type.speed = 0; /* unknown */ | ||
402 | } else { | ||
403 | ft_drive_type.name = vendors[vendor_index].name; | ||
404 | ft_drive_type.speed = vendors[vendor_index].speed; | ||
405 | TRACE(ft_t_info, "tape drive type: %s", ft_drive_type.name); | ||
406 | /* scan all methods for this vendor_id in table */ | ||
407 | while(ft_drive_type.wake_up != vendors[vendor_index].wake_up) { | ||
408 | if (vendor_index < NR_ITEMS(vendors) - 1 && | ||
409 | vendors[vendor_index + 1].vendor_id | ||
410 | == | ||
411 | ft_drive_type.vendor_id) { | ||
412 | ++vendor_index; | ||
413 | } else { | ||
414 | break; | ||
415 | } | ||
416 | } | ||
417 | if (ft_drive_type.wake_up != vendors[vendor_index].wake_up) { | ||
418 | TRACE(ft_t_warn, "\n" | ||
419 | KERN_INFO "==========================================\n" | ||
420 | KERN_INFO "wakeup type mismatch:\n" | ||
421 | KERN_INFO "found: %s, expected: %s\n" | ||
422 | KERN_INFO "please report this to "THE_FTAPE_MAINTAINER"\n" | ||
423 | KERN_INFO "==========================================", | ||
424 | methods[ft_drive_type.wake_up].name, | ||
425 | methods[vendors[vendor_index].wake_up].name); | ||
426 | } | ||
427 | } | ||
428 | TRACE_EXIT; | ||
429 | } | ||
430 | |||
431 | void ftape_calc_timeouts(unsigned int qic_std, | ||
432 | unsigned int data_rate, | ||
433 | unsigned int tape_len) | ||
434 | { | ||
435 | int speed; /* deci-ips ! */ | ||
436 | int ff_speed; | ||
437 | int length; | ||
438 | TRACE_FUN(ft_t_any); | ||
439 | |||
440 | /* tape transport speed | ||
441 | * data rate: QIC-40 QIC-80 QIC-3010 QIC-3020 | ||
442 | * | ||
443 | * 250 Kbps 25 ips n/a n/a n/a | ||
444 | * 500 Kbps 50 ips 34 ips 22.6 ips n/a | ||
445 | * 1 Mbps n/a 68 ips 45.2 ips 22.6 ips | ||
446 | * 2 Mbps n/a n/a n/a 45.2 ips | ||
447 | * | ||
448 | * fast tape transport speed is at least 68 ips. | ||
449 | */ | ||
450 | switch (qic_std) { | ||
451 | case QIC_TAPE_QIC40: | ||
452 | speed = (data_rate == 250) ? 250 : 500; | ||
453 | break; | ||
454 | case QIC_TAPE_QIC80: | ||
455 | speed = (data_rate == 500) ? 340 : 680; | ||
456 | break; | ||
457 | case QIC_TAPE_QIC3010: | ||
458 | speed = (data_rate == 500) ? 226 : 452; | ||
459 | break; | ||
460 | case QIC_TAPE_QIC3020: | ||
461 | speed = (data_rate == 1000) ? 226 : 452; | ||
462 | break; | ||
463 | default: | ||
464 | TRACE(ft_t_bug, "Unknown qic_std (bug) ?"); | ||
465 | speed = 500; | ||
466 | break; | ||
467 | } | ||
468 | if (ft_drive_type.speed == 0) { | ||
469 | unsigned long t0; | ||
470 | static int dt = 0; /* keep gcc from complaining */ | ||
471 | static int first_time = 1; | ||
472 | |||
473 | /* Measure the time it takes to wind to EOT and back to BOT. | ||
474 | * If the tape length is known, calculate the rewind speed. | ||
475 | * Else keep the time value for calculation of the rewind | ||
476 | * speed later on, when the length _is_ known. | ||
477 | * Ask for a report only when length and speed are both known. | ||
478 | */ | ||
479 | if (first_time) { | ||
480 | ftape_seek_to_bot(); | ||
481 | t0 = jiffies; | ||
482 | ftape_seek_to_eot(); | ||
483 | ftape_seek_to_bot(); | ||
484 | dt = (int) (((jiffies - t0) * FT_USPT) / 1000); | ||
485 | if (dt < 1) { | ||
486 | dt = 1; /* prevent div by zero on failures */ | ||
487 | } | ||
488 | first_time = 0; | ||
489 | TRACE(ft_t_info, | ||
490 | "trying to determine seek timeout, got %d msec", | ||
491 | dt); | ||
492 | } | ||
493 | if (tape_len != 0) { | ||
494 | ft_drive_type.speed = | ||
495 | (2 * 12 * tape_len * 1000) / dt; | ||
496 | TRACE(ft_t_warn, "\n" | ||
497 | KERN_INFO "==========================================\n" | ||
498 | KERN_INFO "drive type: %s\n" | ||
499 | KERN_INFO "delta time = %d ms, length = %d ft\n" | ||
500 | KERN_INFO "has a maximum tape speed of %d ips\n" | ||
501 | KERN_INFO "please report this to "THE_FTAPE_MAINTAINER"\n" | ||
502 | KERN_INFO "==========================================", | ||
503 | ft_drive_type.name, dt, tape_len, | ||
504 | ft_drive_type.speed); | ||
505 | } | ||
506 | } | ||
507 | /* Handle unknown length tapes as very long ones. We'll | ||
508 | * determine the actual length from a header segment later. | ||
509 | * This is normal for all modern (Wide,TR1/2/3) formats. | ||
510 | */ | ||
511 | if (tape_len <= 0) { | ||
512 | TRACE(ft_t_noise, | ||
513 | "Unknown tape length, using maximal timeouts"); | ||
514 | length = QIC_TOP_TAPE_LEN; /* use worst case values */ | ||
515 | } else { | ||
516 | length = tape_len; /* use actual values */ | ||
517 | } | ||
518 | if (ft_drive_type.speed == 0) { | ||
519 | ff_speed = speed; | ||
520 | } else { | ||
521 | ff_speed = ft_drive_type.speed; | ||
522 | } | ||
523 | /* time to go from bot to eot at normal speed (data rate): | ||
524 | * time = (1+delta) * length (ft) * 12 (inch/ft) / speed (ips) | ||
525 | * delta = 10 % for seek speed, 20 % for rewind speed. | ||
526 | */ | ||
527 | ftape_timeout.seek = (length * 132 * FT_SECOND) / speed; | ||
528 | ftape_timeout.rewind = (length * 144 * FT_SECOND) / (10 * ff_speed); | ||
529 | ftape_timeout.reset = 20 * FT_SECOND + ftape_timeout.rewind; | ||
530 | TRACE(ft_t_noise, "timeouts for speed = %d, length = %d\n" | ||
531 | KERN_INFO "seek timeout : %d sec\n" | ||
532 | KERN_INFO "rewind timeout: %d sec\n" | ||
533 | KERN_INFO "reset timeout : %d sec", | ||
534 | speed, length, | ||
535 | (ftape_timeout.seek + 500) / 1000, | ||
536 | (ftape_timeout.rewind + 500) / 1000, | ||
537 | (ftape_timeout.reset + 500) / 1000); | ||
538 | TRACE_EXIT; | ||
539 | } | ||
540 | |||
541 | /* This function calibrates the datarate (i.e. determines the maximal | ||
542 | * usable data rate) and sets the global variable ft_qic_std to qic_std | ||
543 | * | ||
544 | */ | ||
545 | int ftape_calibrate_data_rate(unsigned int qic_std) | ||
546 | { | ||
547 | int rate = ft_fdc_rate_limit; | ||
548 | int result; | ||
549 | TRACE_FUN(ft_t_flow); | ||
550 | |||
551 | ft_qic_std = qic_std; | ||
552 | |||
553 | if (ft_qic_std == -1) { | ||
554 | TRACE_ABORT(-EIO, ft_t_err, | ||
555 | "Unable to determine data rate if QIC standard is unknown"); | ||
556 | } | ||
557 | |||
558 | /* Select highest rate supported by both fdc and drive. | ||
559 | * Start with highest rate supported by the fdc. | ||
560 | */ | ||
561 | while (fdc_set_data_rate(rate) < 0 && rate > 250) { | ||
562 | rate /= 2; | ||
563 | } | ||
564 | TRACE(ft_t_info, | ||
565 | "Highest FDC supported data rate: %d Kbps", rate); | ||
566 | ft_fdc_max_rate = rate; | ||
567 | do { | ||
568 | result = ftape_set_data_rate(rate, ft_qic_std); | ||
569 | } while (result == -EINVAL && (rate /= 2) > 250); | ||
570 | if (result < 0) { | ||
571 | TRACE_ABORT(-EIO, ft_t_err, "set datarate failed"); | ||
572 | } | ||
573 | ft_data_rate = rate; | ||
574 | TRACE_EXIT 0; | ||
575 | } | ||
576 | |||
577 | static int ftape_init_drive(void) | ||
578 | { | ||
579 | int status; | ||
580 | qic_model model; | ||
581 | unsigned int qic_std; | ||
582 | unsigned int data_rate; | ||
583 | TRACE_FUN(ft_t_flow); | ||
584 | |||
585 | ftape_init_drive_needed = 0; /* don't retry if this fails ? */ | ||
586 | TRACE_CATCH(ftape_report_raw_drive_status(&status),); | ||
587 | if (status & QIC_STATUS_CARTRIDGE_PRESENT) { | ||
588 | if (!(status & QIC_STATUS_AT_BOT)) { | ||
589 | /* Antique drives will get here after a soft reset, | ||
590 | * modern ones only if the driver is loaded when the | ||
591 | * tape wasn't rewound properly. | ||
592 | */ | ||
593 | /* Tape should be at bot if new cartridge ! */ | ||
594 | ftape_seek_to_bot(); | ||
595 | } | ||
596 | if (!(status & QIC_STATUS_REFERENCED)) { | ||
597 | TRACE(ft_t_flow, "starting seek_load_point"); | ||
598 | TRACE_CATCH(ftape_command_wait(QIC_SEEK_LOAD_POINT, | ||
599 | ftape_timeout.reset, | ||
600 | &status),); | ||
601 | } | ||
602 | } | ||
603 | ft_formatted = (status & QIC_STATUS_REFERENCED) != 0; | ||
604 | if (!ft_formatted) { | ||
605 | TRACE(ft_t_warn, "Warning: tape is not formatted !"); | ||
606 | } | ||
607 | |||
608 | /* report configuration aborts when ftape_tape_len == -1 | ||
609 | * unknown qic_std is okay if not formatted. | ||
610 | */ | ||
611 | TRACE_CATCH(ftape_report_configuration(&model, | ||
612 | &data_rate, | ||
613 | &qic_std, | ||
614 | &ftape_tape_len),); | ||
615 | |||
616 | /* Maybe add the following to the /proc entry | ||
617 | */ | ||
618 | TRACE(ft_t_info, "%s drive @ %d Kbps", | ||
619 | (model == prehistoric) ? "prehistoric" : | ||
620 | ((model == pre_qic117c) ? "pre QIC-117C" : | ||
621 | ((model == post_qic117b) ? "post QIC-117B" : | ||
622 | "post QIC-117D")), data_rate); | ||
623 | |||
624 | if (ft_formatted) { | ||
625 | /* initialize ft_used_data_rate to maximum value | ||
626 | * and set ft_qic_std | ||
627 | */ | ||
628 | TRACE_CATCH(ftape_calibrate_data_rate(qic_std),); | ||
629 | if (ftape_tape_len == 0) { | ||
630 | TRACE(ft_t_info, "unknown length QIC-%s tape", | ||
631 | (ft_qic_std == QIC_TAPE_QIC40) ? "40" : | ||
632 | ((ft_qic_std == QIC_TAPE_QIC80) ? "80" : | ||
633 | ((ft_qic_std == QIC_TAPE_QIC3010) | ||
634 | ? "3010" : "3020"))); | ||
635 | } else { | ||
636 | TRACE(ft_t_info, "%d ft. QIC-%s tape", ftape_tape_len, | ||
637 | (ft_qic_std == QIC_TAPE_QIC40) ? "40" : | ||
638 | ((ft_qic_std == QIC_TAPE_QIC80) ? "80" : | ||
639 | ((ft_qic_std == QIC_TAPE_QIC3010) | ||
640 | ? "3010" : "3020"))); | ||
641 | } | ||
642 | ftape_calc_timeouts(ft_qic_std, ft_data_rate, ftape_tape_len); | ||
643 | /* soft write-protect QIC-40/QIC-80 cartridges used with a | ||
644 | * Colorado T3000 drive. Buggy hardware! | ||
645 | */ | ||
646 | if ((ft_drive_type.vendor_id == 0x011c6) && | ||
647 | ((ft_qic_std == QIC_TAPE_QIC40 || | ||
648 | ft_qic_std == QIC_TAPE_QIC80) && | ||
649 | !ft_write_protected)) { | ||
650 | TRACE(ft_t_warn, "\n" | ||
651 | KERN_INFO "The famous Colorado T3000 bug:\n" | ||
652 | KERN_INFO "%s drives can't write QIC40 and QIC80\n" | ||
653 | KERN_INFO "cartridges but don't set the write-protect flag!", | ||
654 | ft_drive_type.name); | ||
655 | ft_write_protected = 1; | ||
656 | } | ||
657 | } else { | ||
658 | /* Doesn't make too much sense to set the data rate | ||
659 | * because we don't know what to use for the write | ||
660 | * precompensation. | ||
661 | * Need to do this again when formatting the cartridge. | ||
662 | */ | ||
663 | ft_data_rate = data_rate; | ||
664 | ftape_calc_timeouts(QIC_TAPE_QIC40, | ||
665 | data_rate, | ||
666 | ftape_tape_len); | ||
667 | } | ||
668 | ftape_new_cartridge(); | ||
669 | TRACE_EXIT 0; | ||
670 | } | ||
671 | |||
672 | static void ftape_munmap(void) | ||
673 | { | ||
674 | int i; | ||
675 | TRACE_FUN(ft_t_flow); | ||
676 | |||
677 | for (i = 0; i < ft_nr_buffers; i++) { | ||
678 | ft_buffer[i]->mmapped = 0; | ||
679 | } | ||
680 | TRACE_EXIT; | ||
681 | } | ||
682 | |||
683 | /* Map the dma buffers into the virtual address range given by vma. | ||
684 | * We only check the caller doesn't map non-existent buffers. We | ||
685 | * don't check for multiple mappings. | ||
686 | */ | ||
687 | int ftape_mmap(struct vm_area_struct *vma) | ||
688 | { | ||
689 | int num_buffers; | ||
690 | int i; | ||
691 | TRACE_FUN(ft_t_flow); | ||
692 | |||
693 | if (ft_failure) { | ||
694 | TRACE_EXIT -ENODEV; | ||
695 | } | ||
696 | if (!(vma->vm_flags & (VM_READ|VM_WRITE))) { | ||
697 | TRACE_ABORT(-EINVAL, ft_t_err, "Undefined mmap() access"); | ||
698 | } | ||
699 | if (vma_get_pgoff(vma) != 0) { | ||
700 | TRACE_ABORT(-EINVAL, ft_t_err, "page offset must be 0"); | ||
701 | } | ||
702 | if ((vma->vm_end - vma->vm_start) % FT_BUFF_SIZE != 0) { | ||
703 | TRACE_ABORT(-EINVAL, ft_t_err, | ||
704 | "size = %ld, should be a multiple of %d", | ||
705 | vma->vm_end - vma->vm_start, | ||
706 | FT_BUFF_SIZE); | ||
707 | } | ||
708 | num_buffers = (vma->vm_end - vma->vm_start) / FT_BUFF_SIZE; | ||
709 | if (num_buffers > ft_nr_buffers) { | ||
710 | TRACE_ABORT(-EINVAL, | ||
711 | ft_t_err, "size = %ld, should be less than %d", | ||
712 | vma->vm_end - vma->vm_start, | ||
713 | ft_nr_buffers * FT_BUFF_SIZE); | ||
714 | } | ||
715 | if (ft_driver_state != idle) { | ||
716 | /* this also clears the buffer states | ||
717 | */ | ||
718 | ftape_abort_operation(); | ||
719 | } else { | ||
720 | ftape_reset_buffer(); | ||
721 | } | ||
722 | for (i = 0; i < num_buffers; i++) { | ||
723 | unsigned long pfn; | ||
724 | |||
725 | pfn = virt_to_phys(ft_buffer[i]->address) >> PAGE_SHIFT; | ||
726 | TRACE_CATCH(remap_pfn_range(vma, vma->vm_start + | ||
727 | i * FT_BUFF_SIZE, | ||
728 | pfn, | ||
729 | FT_BUFF_SIZE, | ||
730 | vma->vm_page_prot), | ||
731 | _res = -EAGAIN); | ||
732 | TRACE(ft_t_noise, "remapped dma buffer @ %p to location @ %p", | ||
733 | ft_buffer[i]->address, | ||
734 | (void *)(vma->vm_start + i * FT_BUFF_SIZE)); | ||
735 | } | ||
736 | for (i = 0; i < num_buffers; i++) { | ||
737 | memset(ft_buffer[i]->address, 0xAA, FT_BUFF_SIZE); | ||
738 | ft_buffer[i]->mmapped++; | ||
739 | } | ||
740 | TRACE_EXIT 0; | ||
741 | } | ||
742 | |||
743 | static void ftape_init_driver(void); /* forward declaration */ | ||
744 | |||
745 | /* OPEN routine called by kernel-interface code | ||
746 | */ | ||
747 | int ftape_enable(int drive_selection) | ||
748 | { | ||
749 | TRACE_FUN(ft_t_any); | ||
750 | |||
751 | if (ft_drive_sel == -1 || ft_drive_sel != drive_selection) { | ||
752 | /* Other selection than last time | ||
753 | */ | ||
754 | ftape_init_driver(); | ||
755 | } | ||
756 | ft_drive_sel = FTAPE_SEL(drive_selection); | ||
757 | ft_failure = 0; | ||
758 | TRACE_CATCH(fdc_init(),); /* init & detect fdc */ | ||
759 | TRACE_CATCH(ftape_activate_drive(&ft_drive_type), | ||
760 | fdc_disable(); | ||
761 | fdc_release_irq_and_dma(); | ||
762 | fdc_release_regions()); | ||
763 | TRACE_CATCH(ftape_get_drive_status(), ftape_detach_drive()); | ||
764 | if (ft_drive_type.vendor_id == UNKNOWN_VENDOR) { | ||
765 | ftape_log_vendor_id(); | ||
766 | } | ||
767 | if (ft_new_tape) { | ||
768 | ftape_init_drive_needed = 1; | ||
769 | } | ||
770 | if (!ft_no_tape && ftape_init_drive_needed) { | ||
771 | TRACE_CATCH(ftape_init_drive(), ftape_detach_drive()); | ||
772 | } | ||
773 | ftape_munmap(); /* clear the mmap flag */ | ||
774 | clear_history(); | ||
775 | TRACE_EXIT 0; | ||
776 | } | ||
777 | |||
778 | /* release routine called by the high level interface modules | ||
779 | * zftape or sftape. | ||
780 | */ | ||
781 | void ftape_disable(void) | ||
782 | { | ||
783 | int i; | ||
784 | TRACE_FUN(ft_t_any); | ||
785 | |||
786 | for (i = 0; i < ft_nr_buffers; i++) { | ||
787 | if (ft_buffer[i]->mmapped) { | ||
788 | TRACE(ft_t_noise, "first byte of buffer %d: 0x%02x", | ||
789 | i, *ft_buffer[i]->address); | ||
790 | } | ||
791 | } | ||
792 | if (sigtestsetmask(¤t->pending.signal, _DONT_BLOCK) && | ||
793 | !(sigtestsetmask(¤t->pending.signal, _NEVER_BLOCK)) && | ||
794 | ftape_tape_running) { | ||
795 | TRACE(ft_t_warn, | ||
796 | "Interrupted by fatal signal and tape still running"); | ||
797 | ftape_dumb_stop(); | ||
798 | ftape_abort_operation(); /* it's annoying */ | ||
799 | } else { | ||
800 | ftape_set_state(idle); | ||
801 | } | ||
802 | ftape_detach_drive(); | ||
803 | if (ft_history.used) { | ||
804 | TRACE(ft_t_info, "== Non-fatal errors this run: =="); | ||
805 | TRACE(ft_t_info, "fdc isr statistics:\n" | ||
806 | KERN_INFO " id_am_errors : %3d\n" | ||
807 | KERN_INFO " id_crc_errors : %3d\n" | ||
808 | KERN_INFO " data_am_errors : %3d\n" | ||
809 | KERN_INFO " data_crc_errors : %3d\n" | ||
810 | KERN_INFO " overrun_errors : %3d\n" | ||
811 | KERN_INFO " no_data_errors : %3d\n" | ||
812 | KERN_INFO " retries : %3d", | ||
813 | ft_history.id_am_errors, ft_history.id_crc_errors, | ||
814 | ft_history.data_am_errors, ft_history.data_crc_errors, | ||
815 | ft_history.overrun_errors, ft_history.no_data_errors, | ||
816 | ft_history.retries); | ||
817 | if (ft_history.used & 1) { | ||
818 | TRACE(ft_t_info, "ecc statistics:\n" | ||
819 | KERN_INFO " crc_errors : %3d\n" | ||
820 | KERN_INFO " crc_failures : %3d\n" | ||
821 | KERN_INFO " ecc_failures : %3d\n" | ||
822 | KERN_INFO " sectors corrected: %3d", | ||
823 | ft_history.crc_errors, ft_history.crc_failures, | ||
824 | ft_history.ecc_failures, ft_history.corrected); | ||
825 | } | ||
826 | if (ft_history.defects > 0) { | ||
827 | TRACE(ft_t_warn, "Warning: %d media defects!", | ||
828 | ft_history.defects); | ||
829 | } | ||
830 | if (ft_history.rewinds > 0) { | ||
831 | TRACE(ft_t_info, "tape motion statistics:\n" | ||
832 | KERN_INFO "repositions : %3d", | ||
833 | ft_history.rewinds); | ||
834 | } | ||
835 | } | ||
836 | ft_failure = 1; | ||
837 | TRACE_EXIT; | ||
838 | } | ||
839 | |||
840 | static void ftape_init_driver(void) | ||
841 | { | ||
842 | TRACE_FUN(ft_t_flow); | ||
843 | |||
844 | ft_drive_type.vendor_id = UNKNOWN_VENDOR; | ||
845 | ft_drive_type.speed = 0; | ||
846 | ft_drive_type.wake_up = unknown_wake_up; | ||
847 | ft_drive_type.name = "Unknown"; | ||
848 | |||
849 | ftape_timeout.seek = 650 * FT_SECOND; | ||
850 | ftape_timeout.reset = 670 * FT_SECOND; | ||
851 | ftape_timeout.rewind = 650 * FT_SECOND; | ||
852 | ftape_timeout.head_seek = 15 * FT_SECOND; | ||
853 | ftape_timeout.stop = 5 * FT_SECOND; | ||
854 | ftape_timeout.pause = 16 * FT_SECOND; | ||
855 | |||
856 | ft_qic_std = -1; | ||
857 | ftape_tape_len = 0; /* unknown */ | ||
858 | ftape_current_command = 0; | ||
859 | ftape_current_cylinder = -1; | ||
860 | |||
861 | ft_segments_per_track = 102; | ||
862 | ftape_segments_per_head = 1020; | ||
863 | ftape_segments_per_cylinder = 4; | ||
864 | ft_tracks_per_tape = 20; | ||
865 | |||
866 | ft_failure = 1; | ||
867 | |||
868 | ft_formatted = 0; | ||
869 | ft_no_tape = 1; | ||
870 | ft_write_protected = 1; | ||
871 | ft_new_tape = 1; | ||
872 | |||
873 | ft_driver_state = idle; | ||
874 | |||
875 | ft_data_rate = | ||
876 | ft_fdc_max_rate = 500; | ||
877 | ft_drive_max_rate = 0; /* triggers set_rate_test() */ | ||
878 | |||
879 | ftape_init_drive_needed = 1; | ||
880 | |||
881 | ft_header_segment_1 = -1; | ||
882 | ft_header_segment_2 = -1; | ||
883 | ft_used_header_segment = -1; | ||
884 | ft_first_data_segment = -1; | ||
885 | ft_last_data_segment = -1; | ||
886 | |||
887 | ft_location.track = -1; | ||
888 | ft_location.known = 0; | ||
889 | |||
890 | ftape_tape_running = 0; | ||
891 | ftape_might_be_off_track = 1; | ||
892 | |||
893 | ftape_new_cartridge(); /* init some tape related variables */ | ||
894 | ftape_init_bsm(); | ||
895 | TRACE_EXIT; | ||
896 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-ctl.h b/drivers/char/ftape/lowlevel/ftape-ctl.h deleted file mode 100644 index 5f5e30bc3615..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-ctl.h +++ /dev/null | |||
@@ -1,162 +0,0 @@ | |||
1 | #ifndef _FTAPE_CTL_H | ||
2 | #define _FTAPE_CTL_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
6 | * (C) 1996-1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-ctl.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:18:09 $ | ||
26 | * | ||
27 | * This file contains the non-standard IOCTL related definitions | ||
28 | * for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for | ||
29 | * Linux. | ||
30 | */ | ||
31 | |||
32 | #include <linux/ioctl.h> | ||
33 | #include <linux/mtio.h> | ||
34 | #include <linux/ftape-vendors.h> | ||
35 | |||
36 | #include "../lowlevel/ftape-rw.h" | ||
37 | #include <linux/ftape-header-segment.h> | ||
38 | |||
39 | typedef struct { | ||
40 | int used; /* any reading or writing done */ | ||
41 | /* isr statistics */ | ||
42 | unsigned int id_am_errors; /* id address mark not found */ | ||
43 | unsigned int id_crc_errors; /* crc error in id address mark */ | ||
44 | unsigned int data_am_errors; /* data address mark not found */ | ||
45 | unsigned int data_crc_errors; /* crc error in data field */ | ||
46 | unsigned int overrun_errors; /* fdc access timing problem */ | ||
47 | unsigned int no_data_errors; /* sector not found */ | ||
48 | unsigned int retries; /* number of tape retries */ | ||
49 | /* ecc statistics */ | ||
50 | unsigned int crc_errors; /* crc error in data */ | ||
51 | unsigned int crc_failures; /* bad data without crc error */ | ||
52 | unsigned int ecc_failures; /* failed to correct */ | ||
53 | unsigned int corrected; /* total sectors corrected */ | ||
54 | /* general statistics */ | ||
55 | unsigned int rewinds; /* number of tape rewinds */ | ||
56 | unsigned int defects; /* bad sectors due to media defects */ | ||
57 | } history_record; | ||
58 | |||
59 | /* this structure contains * ALL * information that we want | ||
60 | * our child modules to know about, but don't want them to | ||
61 | * modify. | ||
62 | */ | ||
63 | typedef struct { | ||
64 | /* vendor information */ | ||
65 | vendor_struct fti_drive_type; | ||
66 | /* data rates */ | ||
67 | unsigned int fti_used_data_rate; | ||
68 | unsigned int fti_drive_max_rate; | ||
69 | unsigned int fti_fdc_max_rate; | ||
70 | /* drive selection, either FTAPE_SEL_A/B/C/D */ | ||
71 | int fti_drive_sel; | ||
72 | /* flags set after decode the drive and tape status */ | ||
73 | unsigned int fti_formatted :1; | ||
74 | unsigned int fti_no_tape :1; | ||
75 | unsigned int fti_write_protected:1; | ||
76 | unsigned int fti_new_tape :1; | ||
77 | /* values of last queried drive/tape status and error */ | ||
78 | ft_drive_error fti_last_error; | ||
79 | ft_drive_status fti_last_status; | ||
80 | /* cartridge geometry */ | ||
81 | unsigned int fti_tracks_per_tape; | ||
82 | unsigned int fti_segments_per_track; | ||
83 | /* location of header segments, etc. */ | ||
84 | int fti_used_header_segment; | ||
85 | int fti_header_segment_1; | ||
86 | int fti_header_segment_2; | ||
87 | int fti_first_data_segment; | ||
88 | int fti_last_data_segment; | ||
89 | /* the format code as stored in the header segment */ | ||
90 | ft_format_type fti_format_code; | ||
91 | /* the following is the sole reason for the ftape_set_status() call */ | ||
92 | unsigned int fti_qic_std; | ||
93 | /* is tape running? */ | ||
94 | volatile enum runner_status_enum fti_runner_status; | ||
95 | /* is tape reading/writing/verifying/formatting/deleting */ | ||
96 | buffer_state_enum fti_state; | ||
97 | /* flags fatal hardware error */ | ||
98 | unsigned int fti_failure:1; | ||
99 | /* history record */ | ||
100 | history_record fti_history; | ||
101 | } ftape_info; | ||
102 | |||
103 | /* vendor information */ | ||
104 | #define ft_drive_type ftape_status.fti_drive_type | ||
105 | /* data rates */ | ||
106 | #define ft_data_rate ftape_status.fti_used_data_rate | ||
107 | #define ft_drive_max_rate ftape_status.fti_drive_max_rate | ||
108 | #define ft_fdc_max_rate ftape_status.fti_fdc_max_rate | ||
109 | /* drive selection, either FTAPE_SEL_A/B/C/D */ | ||
110 | #define ft_drive_sel ftape_status.fti_drive_sel | ||
111 | /* flags set after decode the drive and tape status */ | ||
112 | #define ft_formatted ftape_status.fti_formatted | ||
113 | #define ft_no_tape ftape_status.fti_no_tape | ||
114 | #define ft_write_protected ftape_status.fti_write_protected | ||
115 | #define ft_new_tape ftape_status.fti_new_tape | ||
116 | /* values of last queried drive/tape status and error */ | ||
117 | #define ft_last_error ftape_status.fti_last_error | ||
118 | #define ft_last_status ftape_status.fti_last_status | ||
119 | /* cartridge geometry */ | ||
120 | #define ft_tracks_per_tape ftape_status.fti_tracks_per_tape | ||
121 | #define ft_segments_per_track ftape_status.fti_segments_per_track | ||
122 | /* the format code as stored in the header segment */ | ||
123 | #define ft_format_code ftape_status.fti_format_code | ||
124 | /* the qic status as returned by report drive configuration */ | ||
125 | #define ft_qic_std ftape_status.fti_qic_std | ||
126 | #define ft_used_header_segment ftape_status.fti_used_header_segment | ||
127 | #define ft_header_segment_1 ftape_status.fti_header_segment_1 | ||
128 | #define ft_header_segment_2 ftape_status.fti_header_segment_2 | ||
129 | #define ft_first_data_segment ftape_status.fti_first_data_segment | ||
130 | #define ft_last_data_segment ftape_status.fti_last_data_segment | ||
131 | /* is tape running? */ | ||
132 | #define ft_runner_status ftape_status.fti_runner_status | ||
133 | /* is tape reading/writing/verifying/formatting/deleting */ | ||
134 | #define ft_driver_state ftape_status.fti_state | ||
135 | /* flags fatal hardware error */ | ||
136 | #define ft_failure ftape_status.fti_failure | ||
137 | /* history record */ | ||
138 | #define ft_history ftape_status.fti_history | ||
139 | |||
140 | /* | ||
141 | * ftape-ctl.c defined global vars. | ||
142 | */ | ||
143 | extern ftape_info ftape_status; | ||
144 | extern int ftape_segments_per_head; | ||
145 | extern int ftape_segments_per_cylinder; | ||
146 | extern int ftape_init_drive_needed; | ||
147 | |||
148 | /* | ||
149 | * ftape-ctl.c defined global functions. | ||
150 | */ | ||
151 | extern int ftape_mmap(struct vm_area_struct *vma); | ||
152 | extern int ftape_enable(int drive_selection); | ||
153 | extern void ftape_disable(void); | ||
154 | extern int ftape_seek_to_bot(void); | ||
155 | extern int ftape_seek_to_eot(void); | ||
156 | extern int ftape_abort_operation(void); | ||
157 | extern void ftape_calc_timeouts(unsigned int qic_std, | ||
158 | unsigned int data_rate, | ||
159 | unsigned int tape_len); | ||
160 | extern int ftape_calibrate_data_rate(unsigned int qic_std); | ||
161 | extern const ftape_info *ftape_get_status(void); | ||
162 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-ecc.c b/drivers/char/ftape/lowlevel/ftape-ecc.c deleted file mode 100644 index e5632f674bc8..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-ecc.c +++ /dev/null | |||
@@ -1,853 +0,0 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 1993 Ning and David Mosberger. | ||
4 | |||
5 | This is based on code originally written by Bas Laarhoven (bas@vimec.nl) | ||
6 | and David L. Brown, Jr., and incorporates improvements suggested by | ||
7 | Kai Harrekilde-Petersen. | ||
8 | |||
9 | This program is free software; you can redistribute it and/or | ||
10 | modify it under the terms of the GNU General Public License as | ||
11 | published by the Free Software Foundation; either version 2, or (at | ||
12 | your option) any later version. | ||
13 | |||
14 | This program is distributed in the hope that it will be useful, but | ||
15 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | General Public License for more details. | ||
18 | |||
19 | You should have received a copy of the GNU General Public License | ||
20 | along with this program; see the file COPYING. If not, write to | ||
21 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, | ||
22 | USA. | ||
23 | |||
24 | * | ||
25 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-ecc.c,v $ | ||
26 | * $Revision: 1.3 $ | ||
27 | * $Date: 1997/10/05 19:18:10 $ | ||
28 | * | ||
29 | * This file contains the Reed-Solomon error correction code | ||
30 | * for the QIC-40/80 floppy-tape driver for Linux. | ||
31 | */ | ||
32 | |||
33 | #include <linux/ftape.h> | ||
34 | |||
35 | #include "../lowlevel/ftape-tracing.h" | ||
36 | #include "../lowlevel/ftape-ecc.h" | ||
37 | |||
38 | /* Machines that are big-endian should define macro BIG_ENDIAN. | ||
39 | * Unfortunately, there doesn't appear to be a standard include file | ||
40 | * that works for all OSs. | ||
41 | */ | ||
42 | |||
43 | #if defined(__sparc__) || defined(__hppa) | ||
44 | #define BIG_ENDIAN | ||
45 | #endif /* __sparc__ || __hppa */ | ||
46 | |||
47 | #if defined(__mips__) | ||
48 | #error Find a smart way to determine the Endianness of the MIPS CPU | ||
49 | #endif | ||
50 | |||
51 | /* Notice: to minimize the potential for confusion, we use r to | ||
52 | * denote the independent variable of the polynomials in the | ||
53 | * Galois Field GF(2^8). We reserve x for polynomials that | ||
54 | * that have coefficients in GF(2^8). | ||
55 | * | ||
56 | * The Galois Field in which coefficient arithmetic is performed are | ||
57 | * the polynomials over Z_2 (i.e., 0 and 1) modulo the irreducible | ||
58 | * polynomial f(r), where f(r)=r^8 + r^7 + r^2 + r + 1. A polynomial | ||
59 | * is represented as a byte with the MSB as the coefficient of r^7 and | ||
60 | * the LSB as the coefficient of r^0. For example, the binary | ||
61 | * representation of f(x) is 0x187 (of course, this doesn't fit into 8 | ||
62 | * bits). In this field, the polynomial r is a primitive element. | ||
63 | * That is, r^i with i in 0,...,255 enumerates all elements in the | ||
64 | * field. | ||
65 | * | ||
66 | * The generator polynomial for the QIC-80 ECC is | ||
67 | * | ||
68 | * g(x) = x^3 + r^105*x^2 + r^105*x + 1 | ||
69 | * | ||
70 | * which can be factored into: | ||
71 | * | ||
72 | * g(x) = (x-r^-1)(x-r^0)(x-r^1) | ||
73 | * | ||
74 | * the byte representation of the coefficients are: | ||
75 | * | ||
76 | * r^105 = 0xc0 | ||
77 | * r^-1 = 0xc3 | ||
78 | * r^0 = 0x01 | ||
79 | * r^1 = 0x02 | ||
80 | * | ||
81 | * Notice that r^-1 = r^254 as exponent arithmetic is performed | ||
82 | * modulo 2^8-1 = 255. | ||
83 | * | ||
84 | * For more information on Galois Fields and Reed-Solomon codes, refer | ||
85 | * to any good book. I found _An Introduction to Error Correcting | ||
86 | * Codes with Applications_ by S. A. Vanstone and P. C. van Oorschot | ||
87 | * to be a good introduction into the former. _CODING THEORY: The | ||
88 | * Essentials_ I found very useful for its concise description of | ||
89 | * Reed-Solomon encoding/decoding. | ||
90 | * | ||
91 | */ | ||
92 | |||
93 | typedef __u8 Matrix[3][3]; | ||
94 | |||
95 | /* | ||
96 | * gfpow[] is defined such that gfpow[i] returns r^i if | ||
97 | * i is in the range [0..255]. | ||
98 | */ | ||
99 | static const __u8 gfpow[] = | ||
100 | { | ||
101 | 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, | ||
102 | 0x87, 0x89, 0x95, 0xad, 0xdd, 0x3d, 0x7a, 0xf4, | ||
103 | 0x6f, 0xde, 0x3b, 0x76, 0xec, 0x5f, 0xbe, 0xfb, | ||
104 | 0x71, 0xe2, 0x43, 0x86, 0x8b, 0x91, 0xa5, 0xcd, | ||
105 | 0x1d, 0x3a, 0x74, 0xe8, 0x57, 0xae, 0xdb, 0x31, | ||
106 | 0x62, 0xc4, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, 0x67, | ||
107 | 0xce, 0x1b, 0x36, 0x6c, 0xd8, 0x37, 0x6e, 0xdc, | ||
108 | 0x3f, 0x7e, 0xfc, 0x7f, 0xfe, 0x7b, 0xf6, 0x6b, | ||
109 | 0xd6, 0x2b, 0x56, 0xac, 0xdf, 0x39, 0x72, 0xe4, | ||
110 | 0x4f, 0x9e, 0xbb, 0xf1, 0x65, 0xca, 0x13, 0x26, | ||
111 | 0x4c, 0x98, 0xb7, 0xe9, 0x55, 0xaa, 0xd3, 0x21, | ||
112 | 0x42, 0x84, 0x8f, 0x99, 0xb5, 0xed, 0x5d, 0xba, | ||
113 | 0xf3, 0x61, 0xc2, 0x03, 0x06, 0x0c, 0x18, 0x30, | ||
114 | 0x60, 0xc0, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, | ||
115 | 0x47, 0x8e, 0x9b, 0xb1, 0xe5, 0x4d, 0x9a, 0xb3, | ||
116 | 0xe1, 0x45, 0x8a, 0x93, 0xa1, 0xc5, 0x0d, 0x1a, | ||
117 | 0x34, 0x68, 0xd0, 0x27, 0x4e, 0x9c, 0xbf, 0xf9, | ||
118 | 0x75, 0xea, 0x53, 0xa6, 0xcb, 0x11, 0x22, 0x44, | ||
119 | 0x88, 0x97, 0xa9, 0xd5, 0x2d, 0x5a, 0xb4, 0xef, | ||
120 | 0x59, 0xb2, 0xe3, 0x41, 0x82, 0x83, 0x81, 0x85, | ||
121 | 0x8d, 0x9d, 0xbd, 0xfd, 0x7d, 0xfa, 0x73, 0xe6, | ||
122 | 0x4b, 0x96, 0xab, 0xd1, 0x25, 0x4a, 0x94, 0xaf, | ||
123 | 0xd9, 0x35, 0x6a, 0xd4, 0x2f, 0x5e, 0xbc, 0xff, | ||
124 | 0x79, 0xf2, 0x63, 0xc6, 0x0b, 0x16, 0x2c, 0x58, | ||
125 | 0xb0, 0xe7, 0x49, 0x92, 0xa3, 0xc1, 0x05, 0x0a, | ||
126 | 0x14, 0x28, 0x50, 0xa0, 0xc7, 0x09, 0x12, 0x24, | ||
127 | 0x48, 0x90, 0xa7, 0xc9, 0x15, 0x2a, 0x54, 0xa8, | ||
128 | 0xd7, 0x29, 0x52, 0xa4, 0xcf, 0x19, 0x32, 0x64, | ||
129 | 0xc8, 0x17, 0x2e, 0x5c, 0xb8, 0xf7, 0x69, 0xd2, | ||
130 | 0x23, 0x46, 0x8c, 0x9f, 0xb9, 0xf5, 0x6d, 0xda, | ||
131 | 0x33, 0x66, 0xcc, 0x1f, 0x3e, 0x7c, 0xf8, 0x77, | ||
132 | 0xee, 0x5b, 0xb6, 0xeb, 0x51, 0xa2, 0xc3, 0x01 | ||
133 | }; | ||
134 | |||
135 | /* | ||
136 | * This is a log table. That is, gflog[r^i] returns i (modulo f(r)). | ||
137 | * gflog[0] is undefined and the first element is therefore not valid. | ||
138 | */ | ||
139 | static const __u8 gflog[256] = | ||
140 | { | ||
141 | 0xff, 0x00, 0x01, 0x63, 0x02, 0xc6, 0x64, 0x6a, | ||
142 | 0x03, 0xcd, 0xc7, 0xbc, 0x65, 0x7e, 0x6b, 0x2a, | ||
143 | 0x04, 0x8d, 0xce, 0x4e, 0xc8, 0xd4, 0xbd, 0xe1, | ||
144 | 0x66, 0xdd, 0x7f, 0x31, 0x6c, 0x20, 0x2b, 0xf3, | ||
145 | 0x05, 0x57, 0x8e, 0xe8, 0xcf, 0xac, 0x4f, 0x83, | ||
146 | 0xc9, 0xd9, 0xd5, 0x41, 0xbe, 0x94, 0xe2, 0xb4, | ||
147 | 0x67, 0x27, 0xde, 0xf0, 0x80, 0xb1, 0x32, 0x35, | ||
148 | 0x6d, 0x45, 0x21, 0x12, 0x2c, 0x0d, 0xf4, 0x38, | ||
149 | 0x06, 0x9b, 0x58, 0x1a, 0x8f, 0x79, 0xe9, 0x70, | ||
150 | 0xd0, 0xc2, 0xad, 0xa8, 0x50, 0x75, 0x84, 0x48, | ||
151 | 0xca, 0xfc, 0xda, 0x8a, 0xd6, 0x54, 0x42, 0x24, | ||
152 | 0xbf, 0x98, 0x95, 0xf9, 0xe3, 0x5e, 0xb5, 0x15, | ||
153 | 0x68, 0x61, 0x28, 0xba, 0xdf, 0x4c, 0xf1, 0x2f, | ||
154 | 0x81, 0xe6, 0xb2, 0x3f, 0x33, 0xee, 0x36, 0x10, | ||
155 | 0x6e, 0x18, 0x46, 0xa6, 0x22, 0x88, 0x13, 0xf7, | ||
156 | 0x2d, 0xb8, 0x0e, 0x3d, 0xf5, 0xa4, 0x39, 0x3b, | ||
157 | 0x07, 0x9e, 0x9c, 0x9d, 0x59, 0x9f, 0x1b, 0x08, | ||
158 | 0x90, 0x09, 0x7a, 0x1c, 0xea, 0xa0, 0x71, 0x5a, | ||
159 | 0xd1, 0x1d, 0xc3, 0x7b, 0xae, 0x0a, 0xa9, 0x91, | ||
160 | 0x51, 0x5b, 0x76, 0x72, 0x85, 0xa1, 0x49, 0xeb, | ||
161 | 0xcb, 0x7c, 0xfd, 0xc4, 0xdb, 0x1e, 0x8b, 0xd2, | ||
162 | 0xd7, 0x92, 0x55, 0xaa, 0x43, 0x0b, 0x25, 0xaf, | ||
163 | 0xc0, 0x73, 0x99, 0x77, 0x96, 0x5c, 0xfa, 0x52, | ||
164 | 0xe4, 0xec, 0x5f, 0x4a, 0xb6, 0xa2, 0x16, 0x86, | ||
165 | 0x69, 0xc5, 0x62, 0xfe, 0x29, 0x7d, 0xbb, 0xcc, | ||
166 | 0xe0, 0xd3, 0x4d, 0x8c, 0xf2, 0x1f, 0x30, 0xdc, | ||
167 | 0x82, 0xab, 0xe7, 0x56, 0xb3, 0x93, 0x40, 0xd8, | ||
168 | 0x34, 0xb0, 0xef, 0x26, 0x37, 0x0c, 0x11, 0x44, | ||
169 | 0x6f, 0x78, 0x19, 0x9a, 0x47, 0x74, 0xa7, 0xc1, | ||
170 | 0x23, 0x53, 0x89, 0xfb, 0x14, 0x5d, 0xf8, 0x97, | ||
171 | 0x2e, 0x4b, 0xb9, 0x60, 0x0f, 0xed, 0x3e, 0xe5, | ||
172 | 0xf6, 0x87, 0xa5, 0x17, 0x3a, 0xa3, 0x3c, 0xb7 | ||
173 | }; | ||
174 | |||
175 | /* This is a multiplication table for the factor 0xc0 (i.e., r^105 (mod f(r)). | ||
176 | * gfmul_c0[f] returns r^105 * f(r) (modulo f(r)). | ||
177 | */ | ||
178 | static const __u8 gfmul_c0[256] = | ||
179 | { | ||
180 | 0x00, 0xc0, 0x07, 0xc7, 0x0e, 0xce, 0x09, 0xc9, | ||
181 | 0x1c, 0xdc, 0x1b, 0xdb, 0x12, 0xd2, 0x15, 0xd5, | ||
182 | 0x38, 0xf8, 0x3f, 0xff, 0x36, 0xf6, 0x31, 0xf1, | ||
183 | 0x24, 0xe4, 0x23, 0xe3, 0x2a, 0xea, 0x2d, 0xed, | ||
184 | 0x70, 0xb0, 0x77, 0xb7, 0x7e, 0xbe, 0x79, 0xb9, | ||
185 | 0x6c, 0xac, 0x6b, 0xab, 0x62, 0xa2, 0x65, 0xa5, | ||
186 | 0x48, 0x88, 0x4f, 0x8f, 0x46, 0x86, 0x41, 0x81, | ||
187 | 0x54, 0x94, 0x53, 0x93, 0x5a, 0x9a, 0x5d, 0x9d, | ||
188 | 0xe0, 0x20, 0xe7, 0x27, 0xee, 0x2e, 0xe9, 0x29, | ||
189 | 0xfc, 0x3c, 0xfb, 0x3b, 0xf2, 0x32, 0xf5, 0x35, | ||
190 | 0xd8, 0x18, 0xdf, 0x1f, 0xd6, 0x16, 0xd1, 0x11, | ||
191 | 0xc4, 0x04, 0xc3, 0x03, 0xca, 0x0a, 0xcd, 0x0d, | ||
192 | 0x90, 0x50, 0x97, 0x57, 0x9e, 0x5e, 0x99, 0x59, | ||
193 | 0x8c, 0x4c, 0x8b, 0x4b, 0x82, 0x42, 0x85, 0x45, | ||
194 | 0xa8, 0x68, 0xaf, 0x6f, 0xa6, 0x66, 0xa1, 0x61, | ||
195 | 0xb4, 0x74, 0xb3, 0x73, 0xba, 0x7a, 0xbd, 0x7d, | ||
196 | 0x47, 0x87, 0x40, 0x80, 0x49, 0x89, 0x4e, 0x8e, | ||
197 | 0x5b, 0x9b, 0x5c, 0x9c, 0x55, 0x95, 0x52, 0x92, | ||
198 | 0x7f, 0xbf, 0x78, 0xb8, 0x71, 0xb1, 0x76, 0xb6, | ||
199 | 0x63, 0xa3, 0x64, 0xa4, 0x6d, 0xad, 0x6a, 0xaa, | ||
200 | 0x37, 0xf7, 0x30, 0xf0, 0x39, 0xf9, 0x3e, 0xfe, | ||
201 | 0x2b, 0xeb, 0x2c, 0xec, 0x25, 0xe5, 0x22, 0xe2, | ||
202 | 0x0f, 0xcf, 0x08, 0xc8, 0x01, 0xc1, 0x06, 0xc6, | ||
203 | 0x13, 0xd3, 0x14, 0xd4, 0x1d, 0xdd, 0x1a, 0xda, | ||
204 | 0xa7, 0x67, 0xa0, 0x60, 0xa9, 0x69, 0xae, 0x6e, | ||
205 | 0xbb, 0x7b, 0xbc, 0x7c, 0xb5, 0x75, 0xb2, 0x72, | ||
206 | 0x9f, 0x5f, 0x98, 0x58, 0x91, 0x51, 0x96, 0x56, | ||
207 | 0x83, 0x43, 0x84, 0x44, 0x8d, 0x4d, 0x8a, 0x4a, | ||
208 | 0xd7, 0x17, 0xd0, 0x10, 0xd9, 0x19, 0xde, 0x1e, | ||
209 | 0xcb, 0x0b, 0xcc, 0x0c, 0xc5, 0x05, 0xc2, 0x02, | ||
210 | 0xef, 0x2f, 0xe8, 0x28, 0xe1, 0x21, 0xe6, 0x26, | ||
211 | 0xf3, 0x33, 0xf4, 0x34, 0xfd, 0x3d, 0xfa, 0x3a | ||
212 | }; | ||
213 | |||
214 | |||
215 | /* Returns V modulo 255 provided V is in the range -255,-254,...,509. | ||
216 | */ | ||
217 | static inline __u8 mod255(int v) | ||
218 | { | ||
219 | if (v > 0) { | ||
220 | if (v < 255) { | ||
221 | return v; | ||
222 | } else { | ||
223 | return v - 255; | ||
224 | } | ||
225 | } else { | ||
226 | return v + 255; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | |||
231 | /* Add two numbers in the field. Addition in this field is equivalent | ||
232 | * to a bit-wise exclusive OR operation---subtraction is therefore | ||
233 | * identical to addition. | ||
234 | */ | ||
235 | static inline __u8 gfadd(__u8 a, __u8 b) | ||
236 | { | ||
237 | return a ^ b; | ||
238 | } | ||
239 | |||
240 | |||
241 | /* Add two vectors of numbers in the field. Each byte in A and B gets | ||
242 | * added individually. | ||
243 | */ | ||
244 | static inline unsigned long gfadd_long(unsigned long a, unsigned long b) | ||
245 | { | ||
246 | return a ^ b; | ||
247 | } | ||
248 | |||
249 | |||
250 | /* Multiply two numbers in the field: | ||
251 | */ | ||
252 | static inline __u8 gfmul(__u8 a, __u8 b) | ||
253 | { | ||
254 | if (a && b) { | ||
255 | return gfpow[mod255(gflog[a] + gflog[b])]; | ||
256 | } else { | ||
257 | return 0; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | |||
262 | /* Just like gfmul, except we have already looked up the log of the | ||
263 | * second number. | ||
264 | */ | ||
265 | static inline __u8 gfmul_exp(__u8 a, int b) | ||
266 | { | ||
267 | if (a) { | ||
268 | return gfpow[mod255(gflog[a] + b)]; | ||
269 | } else { | ||
270 | return 0; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | |||
275 | /* Just like gfmul_exp, except that A is a vector of numbers. That | ||
276 | * is, each byte in A gets multiplied by gfpow[mod255(B)]. | ||
277 | */ | ||
278 | static inline unsigned long gfmul_exp_long(unsigned long a, int b) | ||
279 | { | ||
280 | __u8 t; | ||
281 | |||
282 | if (sizeof(long) == 4) { | ||
283 | return ( | ||
284 | ((t = (__u32)a >> 24 & 0xff) ? | ||
285 | (((__u32) gfpow[mod255(gflog[t] + b)]) << 24) : 0) | | ||
286 | ((t = (__u32)a >> 16 & 0xff) ? | ||
287 | (((__u32) gfpow[mod255(gflog[t] + b)]) << 16) : 0) | | ||
288 | ((t = (__u32)a >> 8 & 0xff) ? | ||
289 | (((__u32) gfpow[mod255(gflog[t] + b)]) << 8) : 0) | | ||
290 | ((t = (__u32)a >> 0 & 0xff) ? | ||
291 | (((__u32) gfpow[mod255(gflog[t] + b)]) << 0) : 0)); | ||
292 | } else if (sizeof(long) == 8) { | ||
293 | return ( | ||
294 | ((t = (__u64)a >> 56 & 0xff) ? | ||
295 | (((__u64) gfpow[mod255(gflog[t] + b)]) << 56) : 0) | | ||
296 | ((t = (__u64)a >> 48 & 0xff) ? | ||
297 | (((__u64) gfpow[mod255(gflog[t] + b)]) << 48) : 0) | | ||
298 | ((t = (__u64)a >> 40 & 0xff) ? | ||
299 | (((__u64) gfpow[mod255(gflog[t] + b)]) << 40) : 0) | | ||
300 | ((t = (__u64)a >> 32 & 0xff) ? | ||
301 | (((__u64) gfpow[mod255(gflog[t] + b)]) << 32) : 0) | | ||
302 | ((t = (__u64)a >> 24 & 0xff) ? | ||
303 | (((__u64) gfpow[mod255(gflog[t] + b)]) << 24) : 0) | | ||
304 | ((t = (__u64)a >> 16 & 0xff) ? | ||
305 | (((__u64) gfpow[mod255(gflog[t] + b)]) << 16) : 0) | | ||
306 | ((t = (__u64)a >> 8 & 0xff) ? | ||
307 | (((__u64) gfpow[mod255(gflog[t] + b)]) << 8) : 0) | | ||
308 | ((t = (__u64)a >> 0 & 0xff) ? | ||
309 | (((__u64) gfpow[mod255(gflog[t] + b)]) << 0) : 0)); | ||
310 | } else { | ||
311 | TRACE_FUN(ft_t_any); | ||
312 | TRACE_ABORT(-1, ft_t_err, "Error: size of long is %d bytes", | ||
313 | (int)sizeof(long)); | ||
314 | } | ||
315 | } | ||
316 | |||
317 | |||
318 | /* Divide two numbers in the field. Returns a/b (modulo f(x)). | ||
319 | */ | ||
320 | static inline __u8 gfdiv(__u8 a, __u8 b) | ||
321 | { | ||
322 | if (!b) { | ||
323 | TRACE_FUN(ft_t_any); | ||
324 | TRACE_ABORT(0xff, ft_t_bug, "Error: division by zero"); | ||
325 | } else if (a == 0) { | ||
326 | return 0; | ||
327 | } else { | ||
328 | return gfpow[mod255(gflog[a] - gflog[b])]; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | |||
333 | /* The following functions return the inverse of the matrix of the | ||
334 | * linear system that needs to be solved to determine the error | ||
335 | * magnitudes. The first deals with matrices of rank 3, while the | ||
336 | * second deals with matrices of rank 2. The error indices are passed | ||
337 | * in arguments L0,..,L2 (0=first sector, 31=last sector). The error | ||
338 | * indices must be sorted in ascending order, i.e., L0<L1<L2. | ||
339 | * | ||
340 | * The linear system that needs to be solved for the error magnitudes | ||
341 | * is A * b = s, where s is the known vector of syndromes, b is the | ||
342 | * vector of error magnitudes and A in the ORDER=3 case: | ||
343 | * | ||
344 | * A_3 = {{1/r^L[0], 1/r^L[1], 1/r^L[2]}, | ||
345 | * { 1, 1, 1}, | ||
346 | * { r^L[0], r^L[1], r^L[2]}} | ||
347 | */ | ||
348 | static inline int gfinv3(__u8 l0, | ||
349 | __u8 l1, | ||
350 | __u8 l2, | ||
351 | Matrix Ainv) | ||
352 | { | ||
353 | __u8 det; | ||
354 | __u8 t20, t10, t21, t12, t01, t02; | ||
355 | int log_det; | ||
356 | |||
357 | /* compute some intermediate results: */ | ||
358 | t20 = gfpow[l2 - l0]; /* t20 = r^l2/r^l0 */ | ||
359 | t10 = gfpow[l1 - l0]; /* t10 = r^l1/r^l0 */ | ||
360 | t21 = gfpow[l2 - l1]; /* t21 = r^l2/r^l1 */ | ||
361 | t12 = gfpow[l1 - l2 + 255]; /* t12 = r^l1/r^l2 */ | ||
362 | t01 = gfpow[l0 - l1 + 255]; /* t01 = r^l0/r^l1 */ | ||
363 | t02 = gfpow[l0 - l2 + 255]; /* t02 = r^l0/r^l2 */ | ||
364 | /* Calculate the determinant of matrix A_3^-1 (sometimes | ||
365 | * called the Vandermonde determinant): | ||
366 | */ | ||
367 | det = gfadd(t20, gfadd(t10, gfadd(t21, gfadd(t12, gfadd(t01, t02))))); | ||
368 | if (!det) { | ||
369 | TRACE_FUN(ft_t_any); | ||
370 | TRACE_ABORT(0, ft_t_err, | ||
371 | "Inversion failed (3 CRC errors, >0 CRC failures)"); | ||
372 | } | ||
373 | log_det = 255 - gflog[det]; | ||
374 | |||
375 | /* Now, calculate all of the coefficients: | ||
376 | */ | ||
377 | Ainv[0][0]= gfmul_exp(gfadd(gfpow[l1], gfpow[l2]), log_det); | ||
378 | Ainv[0][1]= gfmul_exp(gfadd(t21, t12), log_det); | ||
379 | Ainv[0][2]= gfmul_exp(gfadd(gfpow[255 - l1], gfpow[255 - l2]),log_det); | ||
380 | |||
381 | Ainv[1][0]= gfmul_exp(gfadd(gfpow[l0], gfpow[l2]), log_det); | ||
382 | Ainv[1][1]= gfmul_exp(gfadd(t20, t02), log_det); | ||
383 | Ainv[1][2]= gfmul_exp(gfadd(gfpow[255 - l0], gfpow[255 - l2]),log_det); | ||
384 | |||
385 | Ainv[2][0]= gfmul_exp(gfadd(gfpow[l0], gfpow[l1]), log_det); | ||
386 | Ainv[2][1]= gfmul_exp(gfadd(t10, t01), log_det); | ||
387 | Ainv[2][2]= gfmul_exp(gfadd(gfpow[255 - l0], gfpow[255 - l1]),log_det); | ||
388 | |||
389 | return 1; | ||
390 | } | ||
391 | |||
392 | |||
393 | static inline int gfinv2(__u8 l0, __u8 l1, Matrix Ainv) | ||
394 | { | ||
395 | __u8 det; | ||
396 | __u8 t1, t2; | ||
397 | int log_det; | ||
398 | |||
399 | t1 = gfpow[255 - l0]; | ||
400 | t2 = gfpow[255 - l1]; | ||
401 | det = gfadd(t1, t2); | ||
402 | if (!det) { | ||
403 | TRACE_FUN(ft_t_any); | ||
404 | TRACE_ABORT(0, ft_t_err, | ||
405 | "Inversion failed (2 CRC errors, >0 CRC failures)"); | ||
406 | } | ||
407 | log_det = 255 - gflog[det]; | ||
408 | |||
409 | /* Now, calculate all of the coefficients: | ||
410 | */ | ||
411 | Ainv[0][0] = Ainv[1][0] = gfpow[log_det]; | ||
412 | |||
413 | Ainv[0][1] = gfmul_exp(t2, log_det); | ||
414 | Ainv[1][1] = gfmul_exp(t1, log_det); | ||
415 | |||
416 | return 1; | ||
417 | } | ||
418 | |||
419 | |||
420 | /* Multiply matrix A by vector S and return result in vector B. M is | ||
421 | * assumed to be of order NxN, S and B of order Nx1. | ||
422 | */ | ||
423 | static inline void gfmat_mul(int n, Matrix A, | ||
424 | __u8 *s, __u8 *b) | ||
425 | { | ||
426 | int i, j; | ||
427 | __u8 dot_prod; | ||
428 | |||
429 | for (i = 0; i < n; ++i) { | ||
430 | dot_prod = 0; | ||
431 | for (j = 0; j < n; ++j) { | ||
432 | dot_prod = gfadd(dot_prod, gfmul(A[i][j], s[j])); | ||
433 | } | ||
434 | b[i] = dot_prod; | ||
435 | } | ||
436 | } | ||
437 | |||
438 | |||
439 | |||
440 | /* The Reed Solomon ECC codes are computed over the N-th byte of each | ||
441 | * block, where N=SECTOR_SIZE. There are up to 29 blocks of data, and | ||
442 | * 3 blocks of ECC. The blocks are stored contiguously in memory. A | ||
443 | * segment, consequently, is assumed to have at least 4 blocks: one or | ||
444 | * more data blocks plus three ECC blocks. | ||
445 | * | ||
446 | * Notice: In QIC-80 speak, a CRC error is a sector with an incorrect | ||
447 | * CRC. A CRC failure is a sector with incorrect data, but | ||
448 | * a valid CRC. In the error control literature, the former | ||
449 | * is usually called "erasure", the latter "error." | ||
450 | */ | ||
451 | /* Compute the parity bytes for C columns of data, where C is the | ||
452 | * number of bytes that fit into a long integer. We use a linear | ||
453 | * feed-back register to do this. The parity bytes P[0], P[STRIDE], | ||
454 | * P[2*STRIDE] are computed such that: | ||
455 | * | ||
456 | * x^k * p(x) + m(x) = 0 (modulo g(x)) | ||
457 | * | ||
458 | * where k = NBLOCKS, | ||
459 | * p(x) = P[0] + P[STRIDE]*x + P[2*STRIDE]*x^2, and | ||
460 | * m(x) = sum_{i=0}^k m_i*x^i. | ||
461 | * m_i = DATA[i*SECTOR_SIZE] | ||
462 | */ | ||
463 | static inline void set_parity(unsigned long *data, | ||
464 | int nblocks, | ||
465 | unsigned long *p, | ||
466 | int stride) | ||
467 | { | ||
468 | unsigned long p0, p1, p2, t1, t2, *end; | ||
469 | |||
470 | end = data + nblocks * (FT_SECTOR_SIZE / sizeof(long)); | ||
471 | p0 = p1 = p2 = 0; | ||
472 | while (data < end) { | ||
473 | /* The new parity bytes p0_i, p1_i, p2_i are computed | ||
474 | * from the old values p0_{i-1}, p1_{i-1}, p2_{i-1} | ||
475 | * recursively as: | ||
476 | * | ||
477 | * p0_i = p1_{i-1} + r^105 * (m_{i-1} - p0_{i-1}) | ||
478 | * p1_i = p2_{i-1} + r^105 * (m_{i-1} - p0_{i-1}) | ||
479 | * p2_i = (m_{i-1} - p0_{i-1}) | ||
480 | * | ||
481 | * With the initial condition: p0_0 = p1_0 = p2_0 = 0. | ||
482 | */ | ||
483 | t1 = gfadd_long(*data, p0); | ||
484 | /* | ||
485 | * Multiply each byte in t1 by 0xc0: | ||
486 | */ | ||
487 | if (sizeof(long) == 4) { | ||
488 | t2= (((__u32) gfmul_c0[(__u32)t1 >> 24 & 0xff]) << 24 | | ||
489 | ((__u32) gfmul_c0[(__u32)t1 >> 16 & 0xff]) << 16 | | ||
490 | ((__u32) gfmul_c0[(__u32)t1 >> 8 & 0xff]) << 8 | | ||
491 | ((__u32) gfmul_c0[(__u32)t1 >> 0 & 0xff]) << 0); | ||
492 | } else if (sizeof(long) == 8) { | ||
493 | t2= (((__u64) gfmul_c0[(__u64)t1 >> 56 & 0xff]) << 56 | | ||
494 | ((__u64) gfmul_c0[(__u64)t1 >> 48 & 0xff]) << 48 | | ||
495 | ((__u64) gfmul_c0[(__u64)t1 >> 40 & 0xff]) << 40 | | ||
496 | ((__u64) gfmul_c0[(__u64)t1 >> 32 & 0xff]) << 32 | | ||
497 | ((__u64) gfmul_c0[(__u64)t1 >> 24 & 0xff]) << 24 | | ||
498 | ((__u64) gfmul_c0[(__u64)t1 >> 16 & 0xff]) << 16 | | ||
499 | ((__u64) gfmul_c0[(__u64)t1 >> 8 & 0xff]) << 8 | | ||
500 | ((__u64) gfmul_c0[(__u64)t1 >> 0 & 0xff]) << 0); | ||
501 | } else { | ||
502 | TRACE_FUN(ft_t_any); | ||
503 | TRACE(ft_t_err, "Error: long is of size %d", | ||
504 | (int) sizeof(long)); | ||
505 | TRACE_EXIT; | ||
506 | } | ||
507 | p0 = gfadd_long(t2, p1); | ||
508 | p1 = gfadd_long(t2, p2); | ||
509 | p2 = t1; | ||
510 | data += FT_SECTOR_SIZE / sizeof(long); | ||
511 | } | ||
512 | *p = p0; | ||
513 | p += stride; | ||
514 | *p = p1; | ||
515 | p += stride; | ||
516 | *p = p2; | ||
517 | return; | ||
518 | } | ||
519 | |||
520 | |||
521 | /* Compute the 3 syndrome values. DATA should point to the first byte | ||
522 | * of the column for which the syndromes are desired. The syndromes | ||
523 | * are computed over the first NBLOCKS of rows. The three bytes will | ||
524 | * be placed in S[0], S[1], and S[2]. | ||
525 | * | ||
526 | * S[i] is the value of the "message" polynomial m(x) evaluated at the | ||
527 | * i-th root of the generator polynomial g(x). | ||
528 | * | ||
529 | * As g(x)=(x-r^-1)(x-1)(x-r^1) we evaluate the message polynomial at | ||
530 | * x=r^-1 to get S[0], at x=r^0=1 to get S[1], and at x=r to get S[2]. | ||
531 | * This could be done directly and efficiently via the Horner scheme. | ||
532 | * However, it would require multiplication tables for the factors | ||
533 | * r^-1 (0xc3) and r (0x02). The following scheme does not require | ||
534 | * any multiplication tables beyond what's needed for set_parity() | ||
535 | * anyway and is slightly faster if there are no errors and slightly | ||
536 | * slower if there are errors. The latter is hopefully the infrequent | ||
537 | * case. | ||
538 | * | ||
539 | * To understand the alternative algorithm, notice that set_parity(m, | ||
540 | * k, p) computes parity bytes such that: | ||
541 | * | ||
542 | * x^k * p(x) = m(x) (modulo g(x)). | ||
543 | * | ||
544 | * That is, to evaluate m(r^m), where r^m is a root of g(x), we can | ||
545 | * simply evaluate (r^m)^k*p(r^m). Also, notice that p is 0 if and | ||
546 | * only if s is zero. That is, if all parity bytes are 0, we know | ||
547 | * there is no error in the data and consequently there is no need to | ||
548 | * compute s(x) at all! In all other cases, we compute s(x) from p(x) | ||
549 | * by evaluating (r^m)^k*p(r^m) for m=-1, m=0, and m=1. The p(x) | ||
550 | * polynomial is evaluated via the Horner scheme. | ||
551 | */ | ||
552 | static int compute_syndromes(unsigned long *data, int nblocks, unsigned long *s) | ||
553 | { | ||
554 | unsigned long p[3]; | ||
555 | |||
556 | set_parity(data, nblocks, p, 1); | ||
557 | if (p[0] | p[1] | p[2]) { | ||
558 | /* Some of the checked columns do not have a zero | ||
559 | * syndrome. For simplicity, we compute the syndromes | ||
560 | * for all columns that we have computed the | ||
561 | * remainders for. | ||
562 | */ | ||
563 | s[0] = gfmul_exp_long( | ||
564 | gfadd_long(p[0], | ||
565 | gfmul_exp_long( | ||
566 | gfadd_long(p[1], | ||
567 | gfmul_exp_long(p[2], -1)), | ||
568 | -1)), | ||
569 | -nblocks); | ||
570 | s[1] = gfadd_long(gfadd_long(p[2], p[1]), p[0]); | ||
571 | s[2] = gfmul_exp_long( | ||
572 | gfadd_long(p[0], | ||
573 | gfmul_exp_long( | ||
574 | gfadd_long(p[1], | ||
575 | gfmul_exp_long(p[2], 1)), | ||
576 | 1)), | ||
577 | nblocks); | ||
578 | return 0; | ||
579 | } else { | ||
580 | return 1; | ||
581 | } | ||
582 | } | ||
583 | |||
584 | |||
585 | /* Correct the block in the column pointed to by DATA. There are NBAD | ||
586 | * CRC errors and their indices are in BAD_LOC[0], up to | ||
587 | * BAD_LOC[NBAD-1]. If NBAD>1, Ainv holds the inverse of the matrix | ||
588 | * of the linear system that needs to be solved to determine the error | ||
589 | * magnitudes. S[0], S[1], and S[2] are the syndrome values. If row | ||
590 | * j gets corrected, then bit j will be set in CORRECTION_MAP. | ||
591 | */ | ||
592 | static inline int correct_block(__u8 *data, int nblocks, | ||
593 | int nbad, int *bad_loc, Matrix Ainv, | ||
594 | __u8 *s, | ||
595 | SectorMap * correction_map) | ||
596 | { | ||
597 | int ncorrected = 0; | ||
598 | int i; | ||
599 | __u8 t1, t2; | ||
600 | __u8 c0, c1, c2; /* check bytes */ | ||
601 | __u8 error_mag[3], log_error_mag; | ||
602 | __u8 *dp, l, e; | ||
603 | TRACE_FUN(ft_t_any); | ||
604 | |||
605 | switch (nbad) { | ||
606 | case 0: | ||
607 | /* might have a CRC failure: */ | ||
608 | if (s[0] == 0) { | ||
609 | /* more than one error */ | ||
610 | TRACE_ABORT(-1, ft_t_err, | ||
611 | "ECC failed (0 CRC errors, >1 CRC failures)"); | ||
612 | } | ||
613 | t1 = gfdiv(s[1], s[0]); | ||
614 | if ((bad_loc[nbad++] = gflog[t1]) >= nblocks) { | ||
615 | TRACE(ft_t_err, | ||
616 | "ECC failed (0 CRC errors, >1 CRC failures)"); | ||
617 | TRACE_ABORT(-1, ft_t_err, | ||
618 | "attempt to correct data at %d", bad_loc[0]); | ||
619 | } | ||
620 | error_mag[0] = s[1]; | ||
621 | break; | ||
622 | case 1: | ||
623 | t1 = gfadd(gfmul_exp(s[1], bad_loc[0]), s[2]); | ||
624 | t2 = gfadd(gfmul_exp(s[0], bad_loc[0]), s[1]); | ||
625 | if (t1 == 0 && t2 == 0) { | ||
626 | /* one erasure, no error: */ | ||
627 | Ainv[0][0] = gfpow[bad_loc[0]]; | ||
628 | } else if (t1 == 0 || t2 == 0) { | ||
629 | /* one erasure and more than one error: */ | ||
630 | TRACE_ABORT(-1, ft_t_err, | ||
631 | "ECC failed (1 erasure, >1 error)"); | ||
632 | } else { | ||
633 | /* one erasure, one error: */ | ||
634 | if ((bad_loc[nbad++] = gflog[gfdiv(t1, t2)]) | ||
635 | >= nblocks) { | ||
636 | TRACE(ft_t_err, "ECC failed " | ||
637 | "(1 CRC errors, >1 CRC failures)"); | ||
638 | TRACE_ABORT(-1, ft_t_err, | ||
639 | "attempt to correct data at %d", | ||
640 | bad_loc[1]); | ||
641 | } | ||
642 | if (!gfinv2(bad_loc[0], bad_loc[1], Ainv)) { | ||
643 | /* inversion failed---must have more | ||
644 | * than one error | ||
645 | */ | ||
646 | TRACE_EXIT -1; | ||
647 | } | ||
648 | } | ||
649 | /* FALL THROUGH TO ERROR MAGNITUDE COMPUTATION: | ||
650 | */ | ||
651 | case 2: | ||
652 | case 3: | ||
653 | /* compute error magnitudes: */ | ||
654 | gfmat_mul(nbad, Ainv, s, error_mag); | ||
655 | break; | ||
656 | |||
657 | default: | ||
658 | TRACE_ABORT(-1, ft_t_err, | ||
659 | "Internal Error: number of CRC errors > 3"); | ||
660 | } | ||
661 | |||
662 | /* Perform correction by adding ERROR_MAG[i] to the byte at | ||
663 | * offset BAD_LOC[i]. Also add the value of the computed | ||
664 | * error polynomial to the syndrome values. If the correction | ||
665 | * was successful, the resulting check bytes should be zero | ||
666 | * (i.e., the corrected data is a valid code word). | ||
667 | */ | ||
668 | c0 = s[0]; | ||
669 | c1 = s[1]; | ||
670 | c2 = s[2]; | ||
671 | for (i = 0; i < nbad; ++i) { | ||
672 | e = error_mag[i]; | ||
673 | if (e) { | ||
674 | /* correct the byte at offset L by magnitude E: */ | ||
675 | l = bad_loc[i]; | ||
676 | dp = &data[l * FT_SECTOR_SIZE]; | ||
677 | *dp = gfadd(*dp, e); | ||
678 | *correction_map |= 1 << l; | ||
679 | ++ncorrected; | ||
680 | |||
681 | log_error_mag = gflog[e]; | ||
682 | c0 = gfadd(c0, gfpow[mod255(log_error_mag - l)]); | ||
683 | c1 = gfadd(c1, e); | ||
684 | c2 = gfadd(c2, gfpow[mod255(log_error_mag + l)]); | ||
685 | } | ||
686 | } | ||
687 | if (c0 || c1 || c2) { | ||
688 | TRACE_ABORT(-1, ft_t_err, | ||
689 | "ECC self-check failed, too many errors"); | ||
690 | } | ||
691 | TRACE_EXIT ncorrected; | ||
692 | } | ||
693 | |||
694 | |||
695 | #if defined(ECC_SANITY_CHECK) || defined(ECC_PARANOID) | ||
696 | |||
697 | /* Perform a sanity check on the computed parity bytes: | ||
698 | */ | ||
699 | static int sanity_check(unsigned long *data, int nblocks) | ||
700 | { | ||
701 | TRACE_FUN(ft_t_any); | ||
702 | unsigned long s[3]; | ||
703 | |||
704 | if (!compute_syndromes(data, nblocks, s)) { | ||
705 | TRACE_ABORT(0, ft_bug, | ||
706 | "Internal Error: syndrome self-check failed"); | ||
707 | } | ||
708 | TRACE_EXIT 1; | ||
709 | } | ||
710 | |||
711 | #endif /* defined(ECC_SANITY_CHECK) || defined(ECC_PARANOID) */ | ||
712 | |||
713 | /* Compute the parity for an entire segment of data. | ||
714 | */ | ||
715 | int ftape_ecc_set_segment_parity(struct memory_segment *mseg) | ||
716 | { | ||
717 | int i; | ||
718 | __u8 *parity_bytes; | ||
719 | |||
720 | parity_bytes = &mseg->data[(mseg->blocks - 3) * FT_SECTOR_SIZE]; | ||
721 | for (i = 0; i < FT_SECTOR_SIZE; i += sizeof(long)) { | ||
722 | set_parity((unsigned long *) &mseg->data[i], mseg->blocks - 3, | ||
723 | (unsigned long *) &parity_bytes[i], | ||
724 | FT_SECTOR_SIZE / sizeof(long)); | ||
725 | #ifdef ECC_PARANOID | ||
726 | if (!sanity_check((unsigned long *) &mseg->data[i], | ||
727 | mseg->blocks)) { | ||
728 | return -1; | ||
729 | } | ||
730 | #endif /* ECC_PARANOID */ | ||
731 | } | ||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | |||
736 | /* Checks and corrects (if possible) the segment MSEG. Returns one of | ||
737 | * ECC_OK, ECC_CORRECTED, and ECC_FAILED. | ||
738 | */ | ||
739 | int ftape_ecc_correct_data(struct memory_segment *mseg) | ||
740 | { | ||
741 | int col, i, result; | ||
742 | int ncorrected = 0; | ||
743 | int nerasures = 0; /* # of erasures (CRC errors) */ | ||
744 | int erasure_loc[3]; /* erasure locations */ | ||
745 | unsigned long ss[3]; | ||
746 | __u8 s[3]; | ||
747 | Matrix Ainv; | ||
748 | TRACE_FUN(ft_t_flow); | ||
749 | |||
750 | mseg->corrected = 0; | ||
751 | |||
752 | /* find first column that has non-zero syndromes: */ | ||
753 | for (col = 0; col < FT_SECTOR_SIZE; col += sizeof(long)) { | ||
754 | if (!compute_syndromes((unsigned long *) &mseg->data[col], | ||
755 | mseg->blocks, ss)) { | ||
756 | /* something is wrong---have to fix things */ | ||
757 | break; | ||
758 | } | ||
759 | } | ||
760 | if (col >= FT_SECTOR_SIZE) { | ||
761 | /* all syndromes are ok, therefore nothing to correct */ | ||
762 | TRACE_EXIT ECC_OK; | ||
763 | } | ||
764 | /* count the number of CRC errors if there were any: */ | ||
765 | if (mseg->read_bad) { | ||
766 | for (i = 0; i < mseg->blocks; i++) { | ||
767 | if (BAD_CHECK(mseg->read_bad, i)) { | ||
768 | if (nerasures >= 3) { | ||
769 | /* this is too much for ECC */ | ||
770 | TRACE_ABORT(ECC_FAILED, ft_t_err, | ||
771 | "ECC failed (>3 CRC errors)"); | ||
772 | } /* if */ | ||
773 | erasure_loc[nerasures++] = i; | ||
774 | } | ||
775 | } | ||
776 | } | ||
777 | /* | ||
778 | * If there are at least 2 CRC errors, determine inverse of matrix | ||
779 | * of linear system to be solved: | ||
780 | */ | ||
781 | switch (nerasures) { | ||
782 | case 2: | ||
783 | if (!gfinv2(erasure_loc[0], erasure_loc[1], Ainv)) { | ||
784 | TRACE_EXIT ECC_FAILED; | ||
785 | } | ||
786 | break; | ||
787 | case 3: | ||
788 | if (!gfinv3(erasure_loc[0], erasure_loc[1], | ||
789 | erasure_loc[2], Ainv)) { | ||
790 | TRACE_EXIT ECC_FAILED; | ||
791 | } | ||
792 | break; | ||
793 | default: | ||
794 | /* this is not an error condition... */ | ||
795 | break; | ||
796 | } | ||
797 | |||
798 | do { | ||
799 | for (i = 0; i < sizeof(long); ++i) { | ||
800 | s[0] = ss[0]; | ||
801 | s[1] = ss[1]; | ||
802 | s[2] = ss[2]; | ||
803 | if (s[0] | s[1] | s[2]) { | ||
804 | #ifdef BIG_ENDIAN | ||
805 | result = correct_block( | ||
806 | &mseg->data[col + sizeof(long) - 1 - i], | ||
807 | mseg->blocks, | ||
808 | nerasures, | ||
809 | erasure_loc, | ||
810 | Ainv, | ||
811 | s, | ||
812 | &mseg->corrected); | ||
813 | #else | ||
814 | result = correct_block(&mseg->data[col + i], | ||
815 | mseg->blocks, | ||
816 | nerasures, | ||
817 | erasure_loc, | ||
818 | Ainv, | ||
819 | s, | ||
820 | &mseg->corrected); | ||
821 | #endif | ||
822 | if (result < 0) { | ||
823 | TRACE_EXIT ECC_FAILED; | ||
824 | } | ||
825 | ncorrected += result; | ||
826 | } | ||
827 | ss[0] >>= 8; | ||
828 | ss[1] >>= 8; | ||
829 | ss[2] >>= 8; | ||
830 | } | ||
831 | |||
832 | #ifdef ECC_SANITY_CHECK | ||
833 | if (!sanity_check((unsigned long *) &mseg->data[col], | ||
834 | mseg->blocks)) { | ||
835 | TRACE_EXIT ECC_FAILED; | ||
836 | } | ||
837 | #endif /* ECC_SANITY_CHECK */ | ||
838 | |||
839 | /* find next column with non-zero syndromes: */ | ||
840 | while ((col += sizeof(long)) < FT_SECTOR_SIZE) { | ||
841 | if (!compute_syndromes((unsigned long *) | ||
842 | &mseg->data[col], mseg->blocks, ss)) { | ||
843 | /* something is wrong---have to fix things */ | ||
844 | break; | ||
845 | } | ||
846 | } | ||
847 | } while (col < FT_SECTOR_SIZE); | ||
848 | if (ncorrected && nerasures == 0) { | ||
849 | TRACE(ft_t_warn, "block contained error not caught by CRC"); | ||
850 | } | ||
851 | TRACE((ncorrected > 0) ? ft_t_noise : ft_t_any, "number of corrections: %d", ncorrected); | ||
852 | TRACE_EXIT ncorrected ? ECC_CORRECTED : ECC_OK; | ||
853 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-ecc.h b/drivers/char/ftape/lowlevel/ftape-ecc.h deleted file mode 100644 index 4829146fe9a0..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-ecc.h +++ /dev/null | |||
@@ -1,84 +0,0 @@ | |||
1 | #ifndef _FTAPE_ECC_H_ | ||
2 | #define _FTAPE_ECC_H_ | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1993 Ning and David Mosberger. | ||
6 | * Original: | ||
7 | * Copyright (C) 1993 Bas Laarhoven. | ||
8 | * Copyright (C) 1992 David L. Brown, Jr. | ||
9 | |||
10 | This program is free software; you can redistribute it and/or | ||
11 | modify it under the terms of the GNU General Public License as | ||
12 | published by the Free Software Foundation; either version 2, or (at | ||
13 | your option) any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, but | ||
16 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; see the file COPYING. If not, write to | ||
22 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, | ||
23 | USA. | ||
24 | |||
25 | * | ||
26 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-ecc.h,v $ | ||
27 | * $Revision: 1.2 $ | ||
28 | * $Date: 1997/10/05 19:18:11 $ | ||
29 | * | ||
30 | * This file contains the definitions for the | ||
31 | * Reed-Solomon error correction code | ||
32 | * for the QIC-40/80 tape streamer device driver. | ||
33 | */ | ||
34 | |||
35 | #include "../lowlevel/ftape-bsm.h" | ||
36 | |||
37 | #define BAD_CLEAR(entry) ((entry)=0) | ||
38 | #define BAD_SET(entry,sector) ((entry)|=(1<<(sector))) | ||
39 | #define BAD_CHECK(entry,sector) ((entry)&(1<<(sector))) | ||
40 | |||
41 | /* | ||
42 | * Return values for ecc_correct_data: | ||
43 | */ | ||
44 | enum { | ||
45 | ECC_OK, /* Data was correct. */ | ||
46 | ECC_CORRECTED, /* Correctable error in data. */ | ||
47 | ECC_FAILED, /* Could not correct data. */ | ||
48 | }; | ||
49 | |||
50 | /* | ||
51 | * Representation of an in memory segment. MARKED_BAD lists the | ||
52 | * sectors that were marked bad during formatting. If the N-th sector | ||
53 | * in a segment is marked bad, bit 1<<N will be set in MARKED_BAD. | ||
54 | * The sectors should be read in from the disk and packed, as if the | ||
55 | * bad sectors were not there, and the segment just contained fewer | ||
56 | * sectors. READ_SECTORS is a bitmap of errors encountered while | ||
57 | * reading the data. These offsets are relative to the packed data. | ||
58 | * BLOCKS is a count of the sectors not marked bad. This is just to | ||
59 | * prevent having to count the zero bits in MARKED_BAD each time this | ||
60 | * is needed. DATA is the actual sector packed data from (or to) the | ||
61 | * tape. | ||
62 | */ | ||
63 | struct memory_segment { | ||
64 | SectorMap marked_bad; | ||
65 | SectorMap read_bad; | ||
66 | int blocks; | ||
67 | __u8 *data; | ||
68 | SectorMap corrected; | ||
69 | }; | ||
70 | |||
71 | /* | ||
72 | * ecc.c defined global variables: | ||
73 | */ | ||
74 | #ifdef TEST | ||
75 | extern int ftape_ecc_tracing; | ||
76 | #endif | ||
77 | |||
78 | /* | ||
79 | * ecc.c defined global functions: | ||
80 | */ | ||
81 | extern int ftape_ecc_correct_data(struct memory_segment *data); | ||
82 | extern int ftape_ecc_set_segment_parity(struct memory_segment *data); | ||
83 | |||
84 | #endif /* _FTAPE_ECC_H_ */ | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-format.c b/drivers/char/ftape/lowlevel/ftape-format.c deleted file mode 100644 index 5dd4c59a3f34..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-format.c +++ /dev/null | |||
@@ -1,344 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1997 Claus-Justus Heine. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; see the file COPYING. If not, write to | ||
16 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | |||
18 | * | ||
19 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-format.c,v $ | ||
20 | * $Revision: 1.2.4.1 $ | ||
21 | * $Date: 1997/11/14 16:05:39 $ | ||
22 | * | ||
23 | * This file contains the code to support formatting of floppy | ||
24 | * tape cartridges with the QIC-40/80/3010/3020 floppy-tape | ||
25 | * driver "ftape" for Linux. | ||
26 | */ | ||
27 | |||
28 | #include <linux/string.h> | ||
29 | #include <linux/errno.h> | ||
30 | |||
31 | #include <linux/ftape.h> | ||
32 | #include <linux/qic117.h> | ||
33 | #include "../lowlevel/ftape-tracing.h" | ||
34 | #include "../lowlevel/ftape-io.h" | ||
35 | #include "../lowlevel/ftape-ctl.h" | ||
36 | #include "../lowlevel/ftape-rw.h" | ||
37 | #include "../lowlevel/ftape-ecc.h" | ||
38 | #include "../lowlevel/ftape-bsm.h" | ||
39 | #include "../lowlevel/ftape-format.h" | ||
40 | |||
41 | #if defined(TESTING) | ||
42 | #define FT_FMT_SEGS_PER_BUF 50 | ||
43 | #else | ||
44 | #define FT_FMT_SEGS_PER_BUF (FT_BUFF_SIZE/(4*FT_SECTORS_PER_SEGMENT)) | ||
45 | #endif | ||
46 | |||
47 | static spinlock_t ftape_format_lock; | ||
48 | |||
49 | /* | ||
50 | * first segment of the new buffer | ||
51 | */ | ||
52 | static int switch_segment; | ||
53 | |||
54 | /* | ||
55 | * at most 256 segments fit into one 32 kb buffer. Even TR-1 cartridges have | ||
56 | * more than this many segments per track, so better be careful. | ||
57 | * | ||
58 | * buffer_struct *buff: buffer to store the formatting coordinates in | ||
59 | * int start: starting segment for this buffer. | ||
60 | * int spt: segments per track | ||
61 | * | ||
62 | * Note: segment ids are relative to the start of the track here. | ||
63 | */ | ||
64 | static void setup_format_buffer(buffer_struct *buff, int start, int spt, | ||
65 | __u8 gap3) | ||
66 | { | ||
67 | int to_do = spt - start; | ||
68 | TRACE_FUN(ft_t_flow); | ||
69 | |||
70 | if (to_do > FT_FMT_SEGS_PER_BUF) { | ||
71 | to_do = FT_FMT_SEGS_PER_BUF; | ||
72 | } | ||
73 | buff->ptr = buff->address; | ||
74 | buff->remaining = to_do * FT_SECTORS_PER_SEGMENT; /* # sectors */ | ||
75 | buff->bytes = buff->remaining * 4; /* need 4 bytes per sector */ | ||
76 | buff->gap3 = gap3; | ||
77 | buff->segment_id = start; | ||
78 | buff->next_segment = start + to_do; | ||
79 | if (buff->next_segment >= spt) { | ||
80 | buff->next_segment = 0; /* 0 means: stop runner */ | ||
81 | } | ||
82 | buff->status = waiting; /* tells the isr that it can use | ||
83 | * this buffer | ||
84 | */ | ||
85 | TRACE_EXIT; | ||
86 | } | ||
87 | |||
88 | |||
89 | /* | ||
90 | * start formatting a new track. | ||
91 | */ | ||
92 | int ftape_format_track(const unsigned int track, const __u8 gap3) | ||
93 | { | ||
94 | unsigned long flags; | ||
95 | buffer_struct *tail, *head; | ||
96 | int status; | ||
97 | TRACE_FUN(ft_t_flow); | ||
98 | |||
99 | TRACE_CATCH(ftape_ready_wait(ftape_timeout.pause, &status),); | ||
100 | if (track & 1) { | ||
101 | if (!(status & QIC_STATUS_AT_EOT)) { | ||
102 | TRACE_CATCH(ftape_seek_to_eot(),); | ||
103 | } | ||
104 | } else { | ||
105 | if (!(status & QIC_STATUS_AT_BOT)) { | ||
106 | TRACE_CATCH(ftape_seek_to_bot(),); | ||
107 | } | ||
108 | } | ||
109 | ftape_abort_operation(); /* this sets ft_head = ft_tail = 0 */ | ||
110 | ftape_set_state(formatting); | ||
111 | |||
112 | TRACE(ft_t_noise, | ||
113 | "Formatting track %d, logical: from segment %d to %d", | ||
114 | track, track * ft_segments_per_track, | ||
115 | (track + 1) * ft_segments_per_track - 1); | ||
116 | |||
117 | /* | ||
118 | * initialize the buffer switching protocol for this track | ||
119 | */ | ||
120 | head = ftape_get_buffer(ft_queue_head); /* tape isn't running yet */ | ||
121 | tail = ftape_get_buffer(ft_queue_tail); /* tape isn't running yet */ | ||
122 | switch_segment = 0; | ||
123 | do { | ||
124 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
125 | setup_format_buffer(tail, switch_segment, | ||
126 | ft_segments_per_track, gap3); | ||
127 | switch_segment = tail->next_segment; | ||
128 | } while ((switch_segment != 0) && | ||
129 | ((tail = ftape_next_buffer(ft_queue_tail)) != head)); | ||
130 | /* go */ | ||
131 | head->status = formatting; | ||
132 | TRACE_CATCH(ftape_seek_head_to_track(track),); | ||
133 | TRACE_CATCH(ftape_command(QIC_LOGICAL_FORWARD),); | ||
134 | spin_lock_irqsave(&ftape_format_lock, flags); | ||
135 | TRACE_CATCH(fdc_setup_formatting(head), restore_flags(flags)); | ||
136 | spin_unlock_irqrestore(&ftape_format_lock, flags); | ||
137 | TRACE_EXIT 0; | ||
138 | } | ||
139 | |||
140 | /* return segment id of segment currently being formatted and do the | ||
141 | * buffer switching stuff. | ||
142 | */ | ||
143 | int ftape_format_status(unsigned int *segment_id) | ||
144 | { | ||
145 | buffer_struct *tail = ftape_get_buffer(ft_queue_tail); | ||
146 | int result; | ||
147 | TRACE_FUN(ft_t_flow); | ||
148 | |||
149 | while (switch_segment != 0 && | ||
150 | ftape_get_buffer(ft_queue_head) != tail) { | ||
151 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
152 | /* need more buffers, first wait for empty buffer | ||
153 | */ | ||
154 | TRACE_CATCH(ftape_wait_segment(formatting),); | ||
155 | /* don't worry for gap3. If we ever hit this piece of code, | ||
156 | * then all buffer already have the correct gap3 set! | ||
157 | */ | ||
158 | setup_format_buffer(tail, switch_segment, | ||
159 | ft_segments_per_track, tail->gap3); | ||
160 | switch_segment = tail->next_segment; | ||
161 | if (switch_segment != 0) { | ||
162 | tail = ftape_next_buffer(ft_queue_tail); | ||
163 | } | ||
164 | } | ||
165 | /* should runner stop ? | ||
166 | */ | ||
167 | if (ft_runner_status == aborting || ft_runner_status == do_abort) { | ||
168 | buffer_struct *head = ftape_get_buffer(ft_queue_head); | ||
169 | TRACE(ft_t_warn, "Error formatting segment %d", | ||
170 | ftape_get_buffer(ft_queue_head)->segment_id); | ||
171 | (void)ftape_abort_operation(); | ||
172 | TRACE_EXIT (head->status != error) ? -EAGAIN : -EIO; | ||
173 | } | ||
174 | /* | ||
175 | * don't care if the timer expires, this is just kind of a | ||
176 | * "select" operation that lets the calling process sleep | ||
177 | * until something has happened | ||
178 | */ | ||
179 | if (fdc_interrupt_wait(5 * FT_SECOND) < 0) { | ||
180 | TRACE(ft_t_noise, "End of track %d at segment %d", | ||
181 | ft_location.track, | ||
182 | ftape_get_buffer(ft_queue_head)->segment_id); | ||
183 | result = 1; /* end of track, unlock module */ | ||
184 | } else { | ||
185 | result = 0; | ||
186 | } | ||
187 | /* | ||
188 | * the calling process should use the seg id to determine | ||
189 | * which parts of the dma buffers can be safely overwritten | ||
190 | * with new data. | ||
191 | */ | ||
192 | *segment_id = ftape_get_buffer(ft_queue_head)->segment_id; | ||
193 | /* | ||
194 | * Internally we start counting segment ids from the start of | ||
195 | * each track when formatting, but externally we keep them | ||
196 | * relative to the start of the tape: | ||
197 | */ | ||
198 | *segment_id += ft_location.track * ft_segments_per_track; | ||
199 | TRACE_EXIT result; | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * The segment id is relative to the start of the tape | ||
204 | */ | ||
205 | int ftape_verify_segment(const unsigned int segment_id, SectorMap *bsm) | ||
206 | { | ||
207 | int result; | ||
208 | int verify_done = 0; | ||
209 | TRACE_FUN(ft_t_flow); | ||
210 | |||
211 | TRACE(ft_t_noise, "Verifying segment %d", segment_id); | ||
212 | |||
213 | if (ft_driver_state != verifying) { | ||
214 | TRACE(ft_t_noise, "calling ftape_abort_operation"); | ||
215 | if (ftape_abort_operation() < 0) { | ||
216 | TRACE(ft_t_err, "ftape_abort_operation failed"); | ||
217 | TRACE_EXIT -EIO; | ||
218 | } | ||
219 | } | ||
220 | *bsm = 0x00000000; | ||
221 | ftape_set_state(verifying); | ||
222 | for (;;) { | ||
223 | buffer_struct *tail; | ||
224 | /* | ||
225 | * Allow escape from this loop on signal | ||
226 | */ | ||
227 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
228 | /* | ||
229 | * Search all full buffers for the first matching the | ||
230 | * wanted segment. Clear other buffers on the fly. | ||
231 | */ | ||
232 | tail = ftape_get_buffer(ft_queue_tail); | ||
233 | while (!verify_done && tail->status == done) { | ||
234 | /* | ||
235 | * Allow escape from this loop on signal ! | ||
236 | */ | ||
237 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
238 | if (tail->segment_id == segment_id) { | ||
239 | /* If out buffer is already full, | ||
240 | * return its contents. | ||
241 | */ | ||
242 | TRACE(ft_t_flow, "found segment in cache: %d", | ||
243 | segment_id); | ||
244 | if ((tail->soft_error_map | | ||
245 | tail->hard_error_map) != 0) { | ||
246 | TRACE(ft_t_info,"bsm[%d] = 0x%08lx", | ||
247 | segment_id, | ||
248 | (unsigned long) | ||
249 | (tail->soft_error_map | | ||
250 | tail->hard_error_map)); | ||
251 | *bsm = (tail->soft_error_map | | ||
252 | tail->hard_error_map); | ||
253 | } | ||
254 | verify_done = 1; | ||
255 | } else { | ||
256 | TRACE(ft_t_flow,"zapping segment in cache: %d", | ||
257 | tail->segment_id); | ||
258 | } | ||
259 | tail->status = waiting; | ||
260 | tail = ftape_next_buffer(ft_queue_tail); | ||
261 | } | ||
262 | if (!verify_done && tail->status == verifying) { | ||
263 | if (tail->segment_id == segment_id) { | ||
264 | switch(ftape_wait_segment(verifying)) { | ||
265 | case 0: | ||
266 | break; | ||
267 | case -EINTR: | ||
268 | TRACE_ABORT(-EINTR, ft_t_warn, | ||
269 | "interrupted by " | ||
270 | "non-blockable signal"); | ||
271 | break; | ||
272 | default: | ||
273 | ftape_abort_operation(); | ||
274 | ftape_set_state(verifying); | ||
275 | /* be picky */ | ||
276 | TRACE_ABORT(-EIO, ft_t_warn, | ||
277 | "wait_segment failed"); | ||
278 | } | ||
279 | } else { | ||
280 | /* We're reading the wrong segment, | ||
281 | * stop runner. | ||
282 | */ | ||
283 | TRACE(ft_t_noise, "verifying wrong segment"); | ||
284 | ftape_abort_operation(); | ||
285 | ftape_set_state(verifying); | ||
286 | } | ||
287 | } | ||
288 | /* should runner stop ? | ||
289 | */ | ||
290 | if (ft_runner_status == aborting) { | ||
291 | buffer_struct *head = ftape_get_buffer(ft_queue_head); | ||
292 | if (head->status == error || | ||
293 | head->status == verifying) { | ||
294 | /* no data or overrun error */ | ||
295 | head->status = waiting; | ||
296 | } | ||
297 | TRACE_CATCH(ftape_dumb_stop(),); | ||
298 | } else { | ||
299 | /* If just passed last segment on tape: wait | ||
300 | * for BOT or EOT mark. Sets ft_runner_status to | ||
301 | * idle if at lEOT and successful | ||
302 | */ | ||
303 | TRACE_CATCH(ftape_handle_logical_eot(),); | ||
304 | } | ||
305 | if (verify_done) { | ||
306 | TRACE_EXIT 0; | ||
307 | } | ||
308 | /* Now at least one buffer is idle! | ||
309 | * Restart runner & tape if needed. | ||
310 | */ | ||
311 | /* We could optimize the following a little bit. We know that | ||
312 | * the bad sector map is empty. | ||
313 | */ | ||
314 | tail = ftape_get_buffer(ft_queue_tail); | ||
315 | if (tail->status == waiting) { | ||
316 | buffer_struct *head = ftape_get_buffer(ft_queue_head); | ||
317 | |||
318 | ftape_setup_new_segment(head, segment_id, -1); | ||
319 | ftape_calc_next_cluster(head); | ||
320 | if (ft_runner_status == idle) { | ||
321 | result = ftape_start_tape(segment_id, | ||
322 | head->sector_offset); | ||
323 | switch(result) { | ||
324 | case 0: | ||
325 | break; | ||
326 | case -ETIME: | ||
327 | case -EINTR: | ||
328 | TRACE_ABORT(result, ft_t_err, "Error: " | ||
329 | "segment %d unreachable", | ||
330 | segment_id); | ||
331 | break; | ||
332 | default: | ||
333 | *bsm = EMPTY_SEGMENT; | ||
334 | TRACE_EXIT 0; | ||
335 | break; | ||
336 | } | ||
337 | } | ||
338 | head->status = verifying; | ||
339 | fdc_setup_read_write(head, FDC_VERIFY); | ||
340 | } | ||
341 | } | ||
342 | /* not reached */ | ||
343 | TRACE_EXIT -EIO; | ||
344 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-format.h b/drivers/char/ftape/lowlevel/ftape-format.h deleted file mode 100644 index f15161566643..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-format.h +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | #ifndef _FTAPE_FORMAT_H | ||
2 | #define _FTAPE_FORMAT_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1996-1997 Claus-Justus Heine. | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-format.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:18:13 $ | ||
25 | * | ||
26 | * This file contains the low level definitions for the | ||
27 | * formatting support for the QIC-40/80/3010/3020 floppy-tape | ||
28 | * driver "ftape" for Linux. | ||
29 | */ | ||
30 | |||
31 | #ifdef __KERNEL__ | ||
32 | extern int ftape_format_track(const unsigned int track, const __u8 gap3); | ||
33 | extern int ftape_format_status(unsigned int *segment_id); | ||
34 | extern int ftape_verify_segment(const unsigned int segment_id, SectorMap *bsm); | ||
35 | #endif /* __KERNEL__ */ | ||
36 | |||
37 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-init.c b/drivers/char/ftape/lowlevel/ftape-init.c deleted file mode 100644 index 4998132a81d1..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-init.c +++ /dev/null | |||
@@ -1,160 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
3 | * (C) 1996-1997 Claus-Justus Heine. | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2, or (at your option) | ||
8 | any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; see the file COPYING. If not, write to | ||
17 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | |||
19 | * | ||
20 | * This file contains the code that interfaces the kernel | ||
21 | * for the QIC-40/80/3010/3020 floppy-tape driver for Linux. | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/errno.h> | ||
26 | #include <linux/fs.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/signal.h> | ||
29 | #include <linux/major.h> | ||
30 | |||
31 | #include <linux/ftape.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/qic117.h> | ||
34 | #ifdef CONFIG_ZFTAPE | ||
35 | #include <linux/zftape.h> | ||
36 | #endif | ||
37 | |||
38 | #include "../lowlevel/ftape-init.h" | ||
39 | #include "../lowlevel/ftape-io.h" | ||
40 | #include "../lowlevel/ftape-read.h" | ||
41 | #include "../lowlevel/ftape-write.h" | ||
42 | #include "../lowlevel/ftape-ctl.h" | ||
43 | #include "../lowlevel/ftape-rw.h" | ||
44 | #include "../lowlevel/fdc-io.h" | ||
45 | #include "../lowlevel/ftape-buffer.h" | ||
46 | #include "../lowlevel/ftape-proc.h" | ||
47 | #include "../lowlevel/ftape-tracing.h" | ||
48 | |||
49 | |||
50 | #if defined(MODULE) && !defined(CONFIG_FT_NO_TRACE_AT_ALL) | ||
51 | static int ft_tracing = -1; | ||
52 | #endif | ||
53 | |||
54 | |||
55 | /* Called by modules package when installing the driver | ||
56 | * or by kernel during the initialization phase | ||
57 | */ | ||
58 | static int __init ftape_init(void) | ||
59 | { | ||
60 | TRACE_FUN(ft_t_flow); | ||
61 | |||
62 | #ifdef MODULE | ||
63 | #ifndef CONFIG_FT_NO_TRACE_AT_ALL | ||
64 | if (ft_tracing != -1) { | ||
65 | ftape_tracing = ft_tracing; | ||
66 | } | ||
67 | #endif | ||
68 | printk(KERN_INFO FTAPE_VERSION "\n"); | ||
69 | if (TRACE_LEVEL >= ft_t_info) { | ||
70 | printk( | ||
71 | KERN_INFO "(c) 1993-1996 Bas Laarhoven (bas@vimec.nl)\n" | ||
72 | KERN_INFO "(c) 1995-1996 Kai Harrekilde-Petersen (khp@dolphinics.no)\n" | ||
73 | KERN_INFO "(c) 1996-1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n" | ||
74 | KERN_INFO "QIC-117 driver for QIC-40/80/3010/3020 floppy tape drives\n"); | ||
75 | } | ||
76 | #else /* !MODULE */ | ||
77 | /* print a short no-nonsense boot message */ | ||
78 | printk(KERN_INFO FTAPE_VERSION "\n"); | ||
79 | #endif /* MODULE */ | ||
80 | TRACE(ft_t_info, "installing QIC-117 floppy tape hardware drive ... "); | ||
81 | TRACE(ft_t_info, "ftape_init @ 0x%p", ftape_init); | ||
82 | /* Allocate the DMA buffers. They are deallocated at cleanup() time. | ||
83 | */ | ||
84 | #ifdef TESTING | ||
85 | #ifdef MODULE | ||
86 | while (ftape_set_nr_buffers(CONFIG_FT_NR_BUFFERS) < 0) { | ||
87 | ftape_sleep(FT_SECOND/20); | ||
88 | if (signal_pending(current)) { | ||
89 | (void)ftape_set_nr_buffers(0); | ||
90 | TRACE(ft_t_bug, | ||
91 | "Killed by signal while allocating buffers."); | ||
92 | TRACE_ABORT(-EINTR, | ||
93 | ft_t_bug, "Free up memory and retry"); | ||
94 | } | ||
95 | } | ||
96 | #else | ||
97 | TRACE_CATCH(ftape_set_nr_buffers(CONFIG_FT_NR_BUFFERS), | ||
98 | (void)ftape_set_nr_buffers(0)); | ||
99 | #endif | ||
100 | #else | ||
101 | TRACE_CATCH(ftape_set_nr_buffers(CONFIG_FT_NR_BUFFERS), | ||
102 | (void)ftape_set_nr_buffers(0)); | ||
103 | #endif | ||
104 | ft_drive_sel = -1; | ||
105 | ft_failure = 1; /* inhibit any operation but open */ | ||
106 | ftape_udelay_calibrate(); /* must be before fdc_wait_calibrate ! */ | ||
107 | fdc_wait_calibrate(); | ||
108 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) | ||
109 | (void)ftape_proc_init(); | ||
110 | #endif | ||
111 | #ifdef CONFIG_ZFTAPE | ||
112 | (void)zft_init(); | ||
113 | #endif | ||
114 | TRACE_EXIT 0; | ||
115 | } | ||
116 | |||
117 | module_param(ft_fdc_base, uint, 0); | ||
118 | MODULE_PARM_DESC(ft_fdc_base, "Base address of FDC controller."); | ||
119 | module_param(ft_fdc_irq, uint, 0); | ||
120 | MODULE_PARM_DESC(ft_fdc_irq, "IRQ (interrupt channel) to use."); | ||
121 | module_param(ft_fdc_dma, uint, 0); | ||
122 | MODULE_PARM_DESC(ft_fdc_dma, "DMA channel to use."); | ||
123 | module_param(ft_fdc_threshold, uint, 0); | ||
124 | MODULE_PARM_DESC(ft_fdc_threshold, "Threshold of the FDC Fifo."); | ||
125 | module_param(ft_fdc_rate_limit, uint, 0); | ||
126 | MODULE_PARM_DESC(ft_fdc_rate_limit, "Maximal data rate for FDC."); | ||
127 | module_param(ft_probe_fc10, bool, 0); | ||
128 | MODULE_PARM_DESC(ft_probe_fc10, | ||
129 | "If non-zero, probe for a Colorado FC-10/FC-20 controller."); | ||
130 | module_param(ft_mach2, bool, 0); | ||
131 | MODULE_PARM_DESC(ft_mach2, | ||
132 | "If non-zero, probe for a Mountain MACH-2 controller."); | ||
133 | #if defined(MODULE) && !defined(CONFIG_FT_NO_TRACE_AT_ALL) | ||
134 | module_param(ft_tracing, int, 0644); | ||
135 | MODULE_PARM_DESC(ft_tracing, | ||
136 | "Amount of debugging output, 0 <= tracing <= 8, default 3."); | ||
137 | #endif | ||
138 | |||
139 | MODULE_AUTHOR( | ||
140 | "(c) 1993-1996 Bas Laarhoven (bas@vimec.nl), " | ||
141 | "(c) 1995-1996 Kai Harrekilde-Petersen (khp@dolphinics.no), " | ||
142 | "(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)"); | ||
143 | MODULE_DESCRIPTION( | ||
144 | "QIC-117 driver for QIC-40/80/3010/3020 floppy tape drives."); | ||
145 | MODULE_LICENSE("GPL"); | ||
146 | |||
147 | static void __exit ftape_exit(void) | ||
148 | { | ||
149 | TRACE_FUN(ft_t_flow); | ||
150 | |||
151 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) | ||
152 | ftape_proc_destroy(); | ||
153 | #endif | ||
154 | (void)ftape_set_nr_buffers(0); | ||
155 | printk(KERN_INFO "ftape: unloaded.\n"); | ||
156 | TRACE_EXIT; | ||
157 | } | ||
158 | |||
159 | module_init(ftape_init); | ||
160 | module_exit(ftape_exit); | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-init.h b/drivers/char/ftape/lowlevel/ftape-init.h deleted file mode 100644 index 99a7b8ab086f..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-init.h +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | #ifndef _FTAPE_INIT_H | ||
2 | #define _FTAPE_INIT_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
6 | * (C) 1996-1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-init.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:18:16 $ | ||
26 | * | ||
27 | * This file contains the definitions for the interface to | ||
28 | * the Linux kernel for floppy tape driver ftape. | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #include <linux/linkage.h> | ||
33 | #include <linux/signal.h> | ||
34 | |||
35 | #define _NEVER_BLOCK (sigmask(SIGKILL) | sigmask(SIGSTOP)) | ||
36 | #define _DONT_BLOCK (_NEVER_BLOCK | sigmask(SIGINT)) | ||
37 | #define _DO_BLOCK (sigmask(SIGPIPE)) | ||
38 | |||
39 | #ifndef QIC117_TAPE_MAJOR | ||
40 | #define QIC117_TAPE_MAJOR 27 | ||
41 | #endif | ||
42 | |||
43 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-io.c b/drivers/char/ftape/lowlevel/ftape-io.c deleted file mode 100644 index 259015aeff55..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-io.c +++ /dev/null | |||
@@ -1,992 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
3 | * (C) 1996 Kai Harrekilde-Petersen, | ||
4 | * (C) 1997 Claus-Justus Heine. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; see the file COPYING. If not, write to | ||
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | |||
20 | * | ||
21 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-io.c,v $ | ||
22 | * $Revision: 1.4 $ | ||
23 | * $Date: 1997/11/11 14:02:36 $ | ||
24 | * | ||
25 | * This file contains the general control functions for the | ||
26 | * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. | ||
27 | */ | ||
28 | |||
29 | #include <linux/errno.h> | ||
30 | #include <linux/sched.h> | ||
31 | #include <linux/mm.h> | ||
32 | #include <asm/system.h> | ||
33 | #include <linux/ioctl.h> | ||
34 | #include <linux/mtio.h> | ||
35 | #include <linux/delay.h> | ||
36 | |||
37 | #include <linux/ftape.h> | ||
38 | #include <linux/qic117.h> | ||
39 | #include "../lowlevel/ftape-tracing.h" | ||
40 | #include "../lowlevel/fdc-io.h" | ||
41 | #include "../lowlevel/ftape-io.h" | ||
42 | #include "../lowlevel/ftape-ctl.h" | ||
43 | #include "../lowlevel/ftape-rw.h" | ||
44 | #include "../lowlevel/ftape-write.h" | ||
45 | #include "../lowlevel/ftape-read.h" | ||
46 | #include "../lowlevel/ftape-init.h" | ||
47 | #include "../lowlevel/ftape-calibr.h" | ||
48 | |||
49 | /* Global vars. | ||
50 | */ | ||
51 | /* NOTE: sectors start numbering at 1, all others at 0 ! */ | ||
52 | ft_timeout_table ftape_timeout; | ||
53 | unsigned int ftape_tape_len; | ||
54 | volatile qic117_cmd_t ftape_current_command; | ||
55 | const struct qic117_command_table qic117_cmds[] = QIC117_COMMANDS; | ||
56 | int ftape_might_be_off_track; | ||
57 | |||
58 | /* Local vars. | ||
59 | */ | ||
60 | static int diagnostic_mode; | ||
61 | static unsigned int ftape_udelay_count; | ||
62 | static unsigned int ftape_udelay_time; | ||
63 | |||
64 | void ftape_udelay(unsigned int usecs) | ||
65 | { | ||
66 | volatile int count = (ftape_udelay_count * usecs + | ||
67 | ftape_udelay_count - 1) / ftape_udelay_time; | ||
68 | volatile int i; | ||
69 | |||
70 | while (count-- > 0) { | ||
71 | for (i = 0; i < 20; ++i); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | void ftape_udelay_calibrate(void) | ||
76 | { | ||
77 | ftape_calibrate("ftape_udelay", | ||
78 | ftape_udelay, &ftape_udelay_count, &ftape_udelay_time); | ||
79 | } | ||
80 | |||
81 | /* Delay (msec) routine. | ||
82 | */ | ||
83 | void ftape_sleep(unsigned int time) | ||
84 | { | ||
85 | TRACE_FUN(ft_t_any); | ||
86 | |||
87 | time *= 1000; /* msecs -> usecs */ | ||
88 | if (time < FT_USPT) { | ||
89 | /* Time too small for scheduler, do a busy wait ! */ | ||
90 | ftape_udelay(time); | ||
91 | } else { | ||
92 | long timeout; | ||
93 | unsigned long flags; | ||
94 | unsigned int ticks = (time + FT_USPT - 1) / FT_USPT; | ||
95 | |||
96 | TRACE(ft_t_any, "%d msec, %d ticks", time/1000, ticks); | ||
97 | timeout = ticks; | ||
98 | save_flags(flags); | ||
99 | sti(); | ||
100 | msleep_interruptible(jiffies_to_msecs(timeout)); | ||
101 | /* Mmm. Isn't current->blocked == 0xffffffff ? | ||
102 | */ | ||
103 | if (signal_pending(current)) { | ||
104 | TRACE(ft_t_err, "awoken by non-blocked signal :-("); | ||
105 | } | ||
106 | restore_flags(flags); | ||
107 | } | ||
108 | TRACE_EXIT; | ||
109 | } | ||
110 | |||
111 | /* send a command or parameter to the drive | ||
112 | * Generates # of step pulses. | ||
113 | */ | ||
114 | static inline int ft_send_to_drive(int arg) | ||
115 | { | ||
116 | /* Always wait for a command_timeout period to separate | ||
117 | * individuals commands and/or parameters. | ||
118 | */ | ||
119 | ftape_sleep(3 * FT_MILLISECOND); | ||
120 | /* Keep cylinder nr within range, step towards home if possible. | ||
121 | */ | ||
122 | if (ftape_current_cylinder >= arg) { | ||
123 | return fdc_seek(ftape_current_cylinder - arg); | ||
124 | } else { | ||
125 | return fdc_seek(ftape_current_cylinder + arg); | ||
126 | } | ||
127 | } | ||
128 | |||
129 | /* forward */ int ftape_report_raw_drive_status(int *status); | ||
130 | |||
131 | static int ft_check_cmd_restrictions(qic117_cmd_t command) | ||
132 | { | ||
133 | int status = -1; | ||
134 | TRACE_FUN(ft_t_any); | ||
135 | |||
136 | TRACE(ft_t_flow, "%s", qic117_cmds[command].name); | ||
137 | /* A new motion command during an uninterruptible (motion) | ||
138 | * command requires a ready status before the new command can | ||
139 | * be issued. Otherwise a new motion command needs to be | ||
140 | * checked against required status. | ||
141 | */ | ||
142 | if (qic117_cmds[command].cmd_type == motion && | ||
143 | qic117_cmds[ftape_current_command].non_intr) { | ||
144 | ftape_report_raw_drive_status(&status); | ||
145 | if ((status & QIC_STATUS_READY) == 0) { | ||
146 | TRACE(ft_t_noise, | ||
147 | "motion cmd (%d) during non-intr cmd (%d)", | ||
148 | command, ftape_current_command); | ||
149 | TRACE(ft_t_noise, "waiting until drive gets ready"); | ||
150 | ftape_ready_wait(ftape_timeout.seek, | ||
151 | &status); | ||
152 | } | ||
153 | } | ||
154 | if (qic117_cmds[command].mask != 0) { | ||
155 | __u8 difference; | ||
156 | /* Some commands do require a certain status: | ||
157 | */ | ||
158 | if (status == -1) { /* not yet set */ | ||
159 | ftape_report_raw_drive_status(&status); | ||
160 | } | ||
161 | difference = ((status ^ qic117_cmds[command].state) & | ||
162 | qic117_cmds[command].mask); | ||
163 | /* Wait until the drive gets | ||
164 | * ready. This may last forever if | ||
165 | * the drive never gets ready... | ||
166 | */ | ||
167 | while ((difference & QIC_STATUS_READY) != 0) { | ||
168 | TRACE(ft_t_noise, "command %d issued while not ready", | ||
169 | command); | ||
170 | TRACE(ft_t_noise, "waiting until drive gets ready"); | ||
171 | if (ftape_ready_wait(ftape_timeout.seek, | ||
172 | &status) == -EINTR) { | ||
173 | /* Bail out on signal ! | ||
174 | */ | ||
175 | TRACE_ABORT(-EINTR, ft_t_warn, | ||
176 | "interrupted by non-blockable signal"); | ||
177 | } | ||
178 | difference = ((status ^ qic117_cmds[command].state) & | ||
179 | qic117_cmds[command].mask); | ||
180 | } | ||
181 | while ((difference & QIC_STATUS_ERROR) != 0) { | ||
182 | int err; | ||
183 | qic117_cmd_t cmd; | ||
184 | |||
185 | TRACE(ft_t_noise, | ||
186 | "command %d issued while error pending", | ||
187 | command); | ||
188 | TRACE(ft_t_noise, "clearing error status"); | ||
189 | ftape_report_error(&err, &cmd, 1); | ||
190 | ftape_report_raw_drive_status(&status); | ||
191 | difference = ((status ^ qic117_cmds[command].state) & | ||
192 | qic117_cmds[command].mask); | ||
193 | if ((difference & QIC_STATUS_ERROR) != 0) { | ||
194 | /* Bail out on fatal signal ! | ||
195 | */ | ||
196 | FT_SIGNAL_EXIT(_NEVER_BLOCK); | ||
197 | } | ||
198 | } | ||
199 | if (difference) { | ||
200 | /* Any remaining difference can't be solved | ||
201 | * here. | ||
202 | */ | ||
203 | if (difference & (QIC_STATUS_CARTRIDGE_PRESENT | | ||
204 | QIC_STATUS_NEW_CARTRIDGE | | ||
205 | QIC_STATUS_REFERENCED)) { | ||
206 | TRACE(ft_t_warn, | ||
207 | "Fatal: tape removed or reinserted !"); | ||
208 | ft_failure = 1; | ||
209 | } else { | ||
210 | TRACE(ft_t_err, "wrong state: 0x%02x should be: 0x%02x", | ||
211 | status & qic117_cmds[command].mask, | ||
212 | qic117_cmds[command].state); | ||
213 | } | ||
214 | TRACE_EXIT -EIO; | ||
215 | } | ||
216 | if (~status & QIC_STATUS_READY & qic117_cmds[command].mask) { | ||
217 | TRACE_ABORT(-EBUSY, ft_t_err, "Bad: still busy!"); | ||
218 | } | ||
219 | } | ||
220 | TRACE_EXIT 0; | ||
221 | } | ||
222 | |||
223 | /* Issue a tape command: | ||
224 | */ | ||
225 | int ftape_command(qic117_cmd_t command) | ||
226 | { | ||
227 | int result = 0; | ||
228 | static int level; | ||
229 | TRACE_FUN(ft_t_any); | ||
230 | |||
231 | if ((unsigned int)command > NR_ITEMS(qic117_cmds)) { | ||
232 | /* This is a bug we'll want to know about too. | ||
233 | */ | ||
234 | TRACE_ABORT(-EIO, ft_t_bug, "bug - bad command: %d", command); | ||
235 | } | ||
236 | if (++level > 5) { /* This is a bug we'll want to know about. */ | ||
237 | --level; | ||
238 | TRACE_ABORT(-EIO, ft_t_bug, "bug - recursion for command: %d", | ||
239 | command); | ||
240 | } | ||
241 | /* disable logging and restriction check for some commands, | ||
242 | * check all other commands that have a prescribed starting | ||
243 | * status. | ||
244 | */ | ||
245 | if (diagnostic_mode) { | ||
246 | TRACE(ft_t_flow, "diagnostic command %d", command); | ||
247 | } else if (command == QIC_REPORT_DRIVE_STATUS || | ||
248 | command == QIC_REPORT_NEXT_BIT) { | ||
249 | TRACE(ft_t_any, "%s", qic117_cmds[command].name); | ||
250 | } else { | ||
251 | TRACE_CATCH(ft_check_cmd_restrictions(command), --level); | ||
252 | } | ||
253 | /* Now all conditions are met or result was < 0. | ||
254 | */ | ||
255 | result = ft_send_to_drive((unsigned int)command); | ||
256 | if (qic117_cmds[command].cmd_type == motion && | ||
257 | command != QIC_LOGICAL_FORWARD && command != QIC_STOP_TAPE) { | ||
258 | ft_location.known = 0; | ||
259 | } | ||
260 | ftape_current_command = command; | ||
261 | --level; | ||
262 | TRACE_EXIT result; | ||
263 | } | ||
264 | |||
265 | /* Send a tape command parameter: | ||
266 | * Generates command # of step pulses. | ||
267 | * Skips tape-status call ! | ||
268 | */ | ||
269 | int ftape_parameter(unsigned int parameter) | ||
270 | { | ||
271 | TRACE_FUN(ft_t_any); | ||
272 | |||
273 | TRACE(ft_t_flow, "called with parameter = %d", parameter); | ||
274 | TRACE_EXIT ft_send_to_drive(parameter + 2); | ||
275 | } | ||
276 | |||
277 | /* Wait for the drive to get ready. | ||
278 | * timeout time in milli-seconds | ||
279 | * Returned status is valid if result != -EIO | ||
280 | * | ||
281 | * Should we allow to be killed by SIGINT? (^C) | ||
282 | * Would be nice at least for large timeouts. | ||
283 | */ | ||
284 | int ftape_ready_wait(unsigned int timeout, int *status) | ||
285 | { | ||
286 | unsigned long t0; | ||
287 | unsigned int poll_delay; | ||
288 | int signal_retries; | ||
289 | TRACE_FUN(ft_t_any); | ||
290 | |||
291 | /* the following ** REALLY ** reduces the system load when | ||
292 | * e.g. one simply rewinds or retensions. The tape is slow | ||
293 | * anyway. It is really not necessary to detect error | ||
294 | * conditions with 1/10 seconds granularity | ||
295 | * | ||
296 | * On my AMD 133MHZ 486: 100 ms: 23% system load | ||
297 | * 1 sec: 5% | ||
298 | * 5 sec: 0.6%, yeah | ||
299 | */ | ||
300 | if (timeout <= FT_SECOND) { | ||
301 | poll_delay = 100 * FT_MILLISECOND; | ||
302 | signal_retries = 20; /* two seconds */ | ||
303 | } else if (timeout < 20 * FT_SECOND) { | ||
304 | TRACE(ft_t_flow, "setting poll delay to 1 second"); | ||
305 | poll_delay = FT_SECOND; | ||
306 | signal_retries = 2; /* two seconds */ | ||
307 | } else { | ||
308 | TRACE(ft_t_flow, "setting poll delay to 5 seconds"); | ||
309 | poll_delay = 5 * FT_SECOND; | ||
310 | signal_retries = 1; /* five seconds */ | ||
311 | } | ||
312 | for (;;) { | ||
313 | t0 = jiffies; | ||
314 | TRACE_CATCH(ftape_report_raw_drive_status(status),); | ||
315 | if (*status & QIC_STATUS_READY) { | ||
316 | TRACE_EXIT 0; | ||
317 | } | ||
318 | if (!signal_retries--) { | ||
319 | FT_SIGNAL_EXIT(_NEVER_BLOCK); | ||
320 | } | ||
321 | if ((int)timeout >= 0) { | ||
322 | /* this will fail when jiffies wraps around about | ||
323 | * once every year :-) | ||
324 | */ | ||
325 | timeout -= ((jiffies - t0) * FT_SECOND) / HZ; | ||
326 | if (timeout <= 0) { | ||
327 | TRACE_ABORT(-ETIME, ft_t_err, "timeout"); | ||
328 | } | ||
329 | ftape_sleep(poll_delay); | ||
330 | timeout -= poll_delay; | ||
331 | } else { | ||
332 | ftape_sleep(poll_delay); | ||
333 | } | ||
334 | } | ||
335 | TRACE_EXIT -ETIME; | ||
336 | } | ||
337 | |||
338 | /* Issue command and wait up to timeout milli seconds for drive ready | ||
339 | */ | ||
340 | int ftape_command_wait(qic117_cmd_t command, unsigned int timeout, int *status) | ||
341 | { | ||
342 | int result; | ||
343 | |||
344 | /* Drive should be ready, issue command | ||
345 | */ | ||
346 | result = ftape_command(command); | ||
347 | if (result >= 0) { | ||
348 | result = ftape_ready_wait(timeout, status); | ||
349 | } | ||
350 | return result; | ||
351 | } | ||
352 | |||
353 | static int ftape_parameter_wait(unsigned int parm, unsigned int timeout, int *status) | ||
354 | { | ||
355 | int result; | ||
356 | |||
357 | /* Drive should be ready, issue command | ||
358 | */ | ||
359 | result = ftape_parameter(parm); | ||
360 | if (result >= 0) { | ||
361 | result = ftape_ready_wait(timeout, status); | ||
362 | } | ||
363 | return result; | ||
364 | } | ||
365 | |||
366 | /*-------------------------------------------------------------------------- | ||
367 | * Report operations | ||
368 | */ | ||
369 | |||
370 | /* Query the drive about its status. The command is sent and | ||
371 | result_length bits of status are returned (2 extra bits are read | ||
372 | for start and stop). */ | ||
373 | |||
374 | int ftape_report_operation(int *status, | ||
375 | qic117_cmd_t command, | ||
376 | int result_length) | ||
377 | { | ||
378 | int i, st3; | ||
379 | unsigned int t0; | ||
380 | unsigned int dt; | ||
381 | TRACE_FUN(ft_t_any); | ||
382 | |||
383 | TRACE_CATCH(ftape_command(command),); | ||
384 | t0 = ftape_timestamp(); | ||
385 | i = 0; | ||
386 | do { | ||
387 | ++i; | ||
388 | ftape_sleep(3 * FT_MILLISECOND); /* see remark below */ | ||
389 | TRACE_CATCH(fdc_sense_drive_status(&st3),); | ||
390 | dt = ftape_timediff(t0, ftape_timestamp()); | ||
391 | /* Ack should be asserted within Ttimout + Tack = 6 msec. | ||
392 | * Looks like some drives fail to do this so extend this | ||
393 | * period to 300 msec. | ||
394 | */ | ||
395 | } while (!(st3 & ST3_TRACK_0) && dt < 300000); | ||
396 | if (!(st3 & ST3_TRACK_0)) { | ||
397 | TRACE(ft_t_err, | ||
398 | "No acknowledge after %u msec. (%i iter)", dt / 1000, i); | ||
399 | TRACE_ABORT(-EIO, ft_t_err, "timeout on Acknowledge"); | ||
400 | } | ||
401 | /* dt may be larger than expected because of other tasks | ||
402 | * scheduled while we were sleeping. | ||
403 | */ | ||
404 | if (i > 1 && dt > 6000) { | ||
405 | TRACE(ft_t_err, "Acknowledge after %u msec. (%i iter)", | ||
406 | dt / 1000, i); | ||
407 | } | ||
408 | *status = 0; | ||
409 | for (i = 0; i < result_length + 1; i++) { | ||
410 | TRACE_CATCH(ftape_command(QIC_REPORT_NEXT_BIT),); | ||
411 | TRACE_CATCH(fdc_sense_drive_status(&st3),); | ||
412 | if (i < result_length) { | ||
413 | *status |= ((st3 & ST3_TRACK_0) ? 1 : 0) << i; | ||
414 | } else if ((st3 & ST3_TRACK_0) == 0) { | ||
415 | TRACE_ABORT(-EIO, ft_t_err, "missing status stop bit"); | ||
416 | } | ||
417 | } | ||
418 | /* this command will put track zero and index back into normal state */ | ||
419 | (void)ftape_command(QIC_REPORT_NEXT_BIT); | ||
420 | TRACE_EXIT 0; | ||
421 | } | ||
422 | |||
423 | /* Report the current drive status. */ | ||
424 | |||
425 | int ftape_report_raw_drive_status(int *status) | ||
426 | { | ||
427 | int result; | ||
428 | int count = 0; | ||
429 | TRACE_FUN(ft_t_any); | ||
430 | |||
431 | do { | ||
432 | result = ftape_report_operation(status, | ||
433 | QIC_REPORT_DRIVE_STATUS, 8); | ||
434 | } while (result < 0 && ++count <= 3); | ||
435 | if (result < 0) { | ||
436 | TRACE_ABORT(-EIO, ft_t_err, | ||
437 | "report_operation failed after %d trials", count); | ||
438 | } | ||
439 | if ((*status & 0xff) == 0xff) { | ||
440 | TRACE_ABORT(-EIO, ft_t_err, | ||
441 | "impossible drive status 0xff"); | ||
442 | } | ||
443 | if (*status & QIC_STATUS_READY) { | ||
444 | ftape_current_command = QIC_NO_COMMAND; /* completed */ | ||
445 | } | ||
446 | ft_last_status.status.drive_status = (__u8)(*status & 0xff); | ||
447 | TRACE_EXIT 0; | ||
448 | } | ||
449 | |||
450 | int ftape_report_drive_status(int *status) | ||
451 | { | ||
452 | TRACE_FUN(ft_t_any); | ||
453 | |||
454 | TRACE_CATCH(ftape_report_raw_drive_status(status),); | ||
455 | if (*status & QIC_STATUS_NEW_CARTRIDGE || | ||
456 | !(*status & QIC_STATUS_CARTRIDGE_PRESENT)) { | ||
457 | ft_failure = 1; /* will inhibit further operations */ | ||
458 | TRACE_EXIT -EIO; | ||
459 | } | ||
460 | if (*status & QIC_STATUS_READY && *status & QIC_STATUS_ERROR) { | ||
461 | /* Let caller handle all errors */ | ||
462 | TRACE_ABORT(1, ft_t_warn, "warning: error status set!"); | ||
463 | } | ||
464 | TRACE_EXIT 0; | ||
465 | } | ||
466 | |||
467 | int ftape_report_error(unsigned int *error, | ||
468 | qic117_cmd_t *command, int report) | ||
469 | { | ||
470 | static const ftape_error ftape_errors[] = QIC117_ERRORS; | ||
471 | int code; | ||
472 | TRACE_FUN(ft_t_any); | ||
473 | |||
474 | TRACE_CATCH(ftape_report_operation(&code, QIC_REPORT_ERROR_CODE, 16),); | ||
475 | *error = (unsigned int)(code & 0xff); | ||
476 | *command = (qic117_cmd_t)((code>>8)&0xff); | ||
477 | /* remember hardware status, maybe useful for status ioctls | ||
478 | */ | ||
479 | ft_last_error.error.command = (__u8)*command; | ||
480 | ft_last_error.error.error = (__u8)*error; | ||
481 | if (!report) { | ||
482 | TRACE_EXIT 0; | ||
483 | } | ||
484 | if (*error == 0) { | ||
485 | TRACE_ABORT(0, ft_t_info, "No error"); | ||
486 | } | ||
487 | TRACE(ft_t_info, "errorcode: %d", *error); | ||
488 | if (*error < NR_ITEMS(ftape_errors)) { | ||
489 | TRACE(ft_t_noise, "%sFatal ERROR:", | ||
490 | (ftape_errors[*error].fatal ? "" : "Non-")); | ||
491 | TRACE(ft_t_noise, "%s ...", ftape_errors[*error].message); | ||
492 | } else { | ||
493 | TRACE(ft_t_noise, "Unknown ERROR !"); | ||
494 | } | ||
495 | if ((unsigned int)*command < NR_ITEMS(qic117_cmds) && | ||
496 | qic117_cmds[*command].name != NULL) { | ||
497 | TRACE(ft_t_noise, "... caused by command \'%s\'", | ||
498 | qic117_cmds[*command].name); | ||
499 | } else { | ||
500 | TRACE(ft_t_noise, "... caused by unknown command %d", | ||
501 | *command); | ||
502 | } | ||
503 | TRACE_EXIT 0; | ||
504 | } | ||
505 | |||
506 | int ftape_report_configuration(qic_model *model, | ||
507 | unsigned int *rate, | ||
508 | int *qic_std, | ||
509 | int *tape_len) | ||
510 | { | ||
511 | int result; | ||
512 | int config; | ||
513 | int status; | ||
514 | static const unsigned int qic_rates[ 4] = { 250, 2000, 500, 1000 }; | ||
515 | TRACE_FUN(ft_t_any); | ||
516 | |||
517 | result = ftape_report_operation(&config, | ||
518 | QIC_REPORT_DRIVE_CONFIGURATION, 8); | ||
519 | if (result < 0) { | ||
520 | ft_last_status.status.drive_config = (__u8)0x00; | ||
521 | *model = prehistoric; | ||
522 | *rate = 500; | ||
523 | *qic_std = QIC_TAPE_QIC40; | ||
524 | *tape_len = 205; | ||
525 | TRACE_EXIT 0; | ||
526 | } else { | ||
527 | ft_last_status.status.drive_config = (__u8)(config & 0xff); | ||
528 | } | ||
529 | *rate = qic_rates[(config & QIC_CONFIG_RATE_MASK) >> QIC_CONFIG_RATE_SHIFT]; | ||
530 | result = ftape_report_operation(&status, QIC_REPORT_TAPE_STATUS, 8); | ||
531 | if (result < 0) { | ||
532 | ft_last_status.status.tape_status = (__u8)0x00; | ||
533 | /* pre- QIC117 rev C spec. drive, QIC_CONFIG_80 bit is valid. | ||
534 | */ | ||
535 | *qic_std = (config & QIC_CONFIG_80) ? | ||
536 | QIC_TAPE_QIC80 : QIC_TAPE_QIC40; | ||
537 | /* ?? how's about 425ft tapes? */ | ||
538 | *tape_len = (config & QIC_CONFIG_LONG) ? 307 : 0; | ||
539 | *model = pre_qic117c; | ||
540 | result = 0; | ||
541 | } else { | ||
542 | ft_last_status.status.tape_status = (__u8)(status & 0xff); | ||
543 | *model = post_qic117b; | ||
544 | TRACE(ft_t_any, "report tape status result = %02x", status); | ||
545 | /* post- QIC117 rev C spec. drive, QIC_CONFIG_80 bit is | ||
546 | * invalid. | ||
547 | */ | ||
548 | switch (status & QIC_TAPE_STD_MASK) { | ||
549 | case QIC_TAPE_QIC40: | ||
550 | case QIC_TAPE_QIC80: | ||
551 | case QIC_TAPE_QIC3020: | ||
552 | case QIC_TAPE_QIC3010: | ||
553 | *qic_std = status & QIC_TAPE_STD_MASK; | ||
554 | break; | ||
555 | default: | ||
556 | *qic_std = -1; | ||
557 | break; | ||
558 | } | ||
559 | switch (status & QIC_TAPE_LEN_MASK) { | ||
560 | case QIC_TAPE_205FT: | ||
561 | /* 205 or 425+ ft 550 Oe tape */ | ||
562 | *tape_len = 0; | ||
563 | break; | ||
564 | case QIC_TAPE_307FT: | ||
565 | /* 307.5 ft 550 Oe Extended Length (XL) tape */ | ||
566 | *tape_len = 307; | ||
567 | break; | ||
568 | case QIC_TAPE_VARIABLE: | ||
569 | /* Variable length 550 Oe tape */ | ||
570 | *tape_len = 0; | ||
571 | break; | ||
572 | case QIC_TAPE_1100FT: | ||
573 | /* 1100 ft 550 Oe tape */ | ||
574 | *tape_len = 1100; | ||
575 | break; | ||
576 | case QIC_TAPE_FLEX: | ||
577 | /* Variable length 900 Oe tape */ | ||
578 | *tape_len = 0; | ||
579 | break; | ||
580 | default: | ||
581 | *tape_len = -1; | ||
582 | break; | ||
583 | } | ||
584 | if (*qic_std == -1 || *tape_len == -1) { | ||
585 | TRACE(ft_t_any, | ||
586 | "post qic-117b spec drive with unknown tape"); | ||
587 | } | ||
588 | result = *tape_len == -1 ? -EIO : 0; | ||
589 | if (status & QIC_TAPE_WIDE) { | ||
590 | switch (*qic_std) { | ||
591 | case QIC_TAPE_QIC80: | ||
592 | TRACE(ft_t_info, "TR-1 tape detected"); | ||
593 | break; | ||
594 | case QIC_TAPE_QIC3010: | ||
595 | TRACE(ft_t_info, "TR-2 tape detected"); | ||
596 | break; | ||
597 | case QIC_TAPE_QIC3020: | ||
598 | TRACE(ft_t_info, "TR-3 tape detected"); | ||
599 | break; | ||
600 | default: | ||
601 | TRACE(ft_t_warn, | ||
602 | "Unknown Travan tape type detected"); | ||
603 | break; | ||
604 | } | ||
605 | } | ||
606 | } | ||
607 | TRACE_EXIT (result < 0) ? -EIO : 0; | ||
608 | } | ||
609 | |||
610 | static int ftape_report_rom_version(int *version) | ||
611 | { | ||
612 | |||
613 | if (ftape_report_operation(version, QIC_REPORT_ROM_VERSION, 8) < 0) { | ||
614 | return -EIO; | ||
615 | } else { | ||
616 | return 0; | ||
617 | } | ||
618 | } | ||
619 | |||
620 | void ftape_report_vendor_id(unsigned int *id) | ||
621 | { | ||
622 | int result; | ||
623 | TRACE_FUN(ft_t_any); | ||
624 | |||
625 | /* We'll try to get a vendor id from the drive. First | ||
626 | * according to the QIC-117 spec, a 16-bit id is requested. | ||
627 | * If that fails we'll try an 8-bit version, otherwise we'll | ||
628 | * try an undocumented query. | ||
629 | */ | ||
630 | result = ftape_report_operation((int *) id, QIC_REPORT_VENDOR_ID, 16); | ||
631 | if (result < 0) { | ||
632 | result = ftape_report_operation((int *) id, | ||
633 | QIC_REPORT_VENDOR_ID, 8); | ||
634 | if (result < 0) { | ||
635 | /* The following is an undocumented call found | ||
636 | * in the CMS code. | ||
637 | */ | ||
638 | result = ftape_report_operation((int *) id, 24, 8); | ||
639 | if (result < 0) { | ||
640 | *id = UNKNOWN_VENDOR; | ||
641 | } else { | ||
642 | TRACE(ft_t_noise, "got old 8 bit id: %04x", | ||
643 | *id); | ||
644 | *id |= 0x20000; | ||
645 | } | ||
646 | } else { | ||
647 | TRACE(ft_t_noise, "got 8 bit id: %04x", *id); | ||
648 | *id |= 0x10000; | ||
649 | } | ||
650 | } else { | ||
651 | TRACE(ft_t_noise, "got 16 bit id: %04x", *id); | ||
652 | } | ||
653 | if (*id == 0x0047) { | ||
654 | int version; | ||
655 | int sign; | ||
656 | |||
657 | if (ftape_report_rom_version(&version) < 0) { | ||
658 | TRACE(ft_t_bug, "report rom version failed"); | ||
659 | TRACE_EXIT; | ||
660 | } | ||
661 | TRACE(ft_t_noise, "CMS rom version: %d", version); | ||
662 | ftape_command(QIC_ENTER_DIAGNOSTIC_1); | ||
663 | ftape_command(QIC_ENTER_DIAGNOSTIC_1); | ||
664 | diagnostic_mode = 1; | ||
665 | if (ftape_report_operation(&sign, 9, 8) < 0) { | ||
666 | unsigned int error; | ||
667 | qic117_cmd_t command; | ||
668 | |||
669 | ftape_report_error(&error, &command, 1); | ||
670 | ftape_command(QIC_ENTER_PRIMARY_MODE); | ||
671 | diagnostic_mode = 0; | ||
672 | TRACE_EXIT; /* failure ! */ | ||
673 | } else { | ||
674 | TRACE(ft_t_noise, "CMS signature: %02x", sign); | ||
675 | } | ||
676 | if (sign == 0xa5) { | ||
677 | result = ftape_report_operation(&sign, 37, 8); | ||
678 | if (result < 0) { | ||
679 | if (version >= 63) { | ||
680 | *id = 0x8880; | ||
681 | TRACE(ft_t_noise, | ||
682 | "This is an Iomega drive !"); | ||
683 | } else { | ||
684 | *id = 0x0047; | ||
685 | TRACE(ft_t_noise, | ||
686 | "This is a real CMS drive !"); | ||
687 | } | ||
688 | } else { | ||
689 | *id = 0x0047; | ||
690 | TRACE(ft_t_noise, "CMS status: %d", sign); | ||
691 | } | ||
692 | } else { | ||
693 | *id = UNKNOWN_VENDOR; | ||
694 | } | ||
695 | ftape_command(QIC_ENTER_PRIMARY_MODE); | ||
696 | diagnostic_mode = 0; | ||
697 | } | ||
698 | TRACE_EXIT; | ||
699 | } | ||
700 | |||
701 | static int qic_rate_code(unsigned int rate) | ||
702 | { | ||
703 | switch (rate) { | ||
704 | case 250: | ||
705 | return QIC_CONFIG_RATE_250; | ||
706 | case 500: | ||
707 | return QIC_CONFIG_RATE_500; | ||
708 | case 1000: | ||
709 | return QIC_CONFIG_RATE_1000; | ||
710 | case 2000: | ||
711 | return QIC_CONFIG_RATE_2000; | ||
712 | default: | ||
713 | return QIC_CONFIG_RATE_500; | ||
714 | } | ||
715 | } | ||
716 | |||
717 | static int ftape_set_rate_test(unsigned int *max_rate) | ||
718 | { | ||
719 | unsigned int error; | ||
720 | qic117_cmd_t command; | ||
721 | int status; | ||
722 | int supported = 0; | ||
723 | TRACE_FUN(ft_t_any); | ||
724 | |||
725 | /* Check if the drive does support the select rate command | ||
726 | * by testing all different settings. If any one is accepted | ||
727 | * we assume the command is supported, else not. | ||
728 | */ | ||
729 | for (*max_rate = 2000; *max_rate >= 250; *max_rate /= 2) { | ||
730 | if (ftape_command(QIC_SELECT_RATE) < 0) { | ||
731 | continue; | ||
732 | } | ||
733 | if (ftape_parameter_wait(qic_rate_code(*max_rate), | ||
734 | 1 * FT_SECOND, &status) < 0) { | ||
735 | continue; | ||
736 | } | ||
737 | if (status & QIC_STATUS_ERROR) { | ||
738 | ftape_report_error(&error, &command, 0); | ||
739 | continue; | ||
740 | } | ||
741 | supported = 1; /* did accept a request */ | ||
742 | break; | ||
743 | } | ||
744 | TRACE(ft_t_noise, "Select Rate command is%s supported", | ||
745 | supported ? "" : " not"); | ||
746 | TRACE_EXIT supported; | ||
747 | } | ||
748 | |||
749 | int ftape_set_data_rate(unsigned int new_rate /* Kbps */, unsigned int qic_std) | ||
750 | { | ||
751 | int status; | ||
752 | int result = 0; | ||
753 | unsigned int data_rate = new_rate; | ||
754 | static int supported; | ||
755 | int rate_changed = 0; | ||
756 | qic_model dummy_model; | ||
757 | unsigned int dummy_qic_std, dummy_tape_len; | ||
758 | TRACE_FUN(ft_t_any); | ||
759 | |||
760 | if (ft_drive_max_rate == 0) { /* first time */ | ||
761 | supported = ftape_set_rate_test(&ft_drive_max_rate); | ||
762 | } | ||
763 | if (supported) { | ||
764 | ftape_command(QIC_SELECT_RATE); | ||
765 | result = ftape_parameter_wait(qic_rate_code(new_rate), | ||
766 | 1 * FT_SECOND, &status); | ||
767 | if (result >= 0 && !(status & QIC_STATUS_ERROR)) { | ||
768 | rate_changed = 1; | ||
769 | } | ||
770 | } | ||
771 | TRACE_CATCH(result = ftape_report_configuration(&dummy_model, | ||
772 | &data_rate, | ||
773 | &dummy_qic_std, | ||
774 | &dummy_tape_len),); | ||
775 | if (data_rate != new_rate) { | ||
776 | if (!supported) { | ||
777 | TRACE(ft_t_warn, "Rate change not supported!"); | ||
778 | } else if (rate_changed) { | ||
779 | TRACE(ft_t_warn, "Requested: %d, got %d", | ||
780 | new_rate, data_rate); | ||
781 | } else { | ||
782 | TRACE(ft_t_warn, "Rate change failed!"); | ||
783 | } | ||
784 | result = -EINVAL; | ||
785 | } | ||
786 | /* | ||
787 | * Set data rate and write precompensation as specified: | ||
788 | * | ||
789 | * | QIC-40/80 | QIC-3010/3020 | ||
790 | * rate | precomp | precomp | ||
791 | * ----------+-------------+-------------- | ||
792 | * 250 Kbps. | 250 ns. | 0 ns. | ||
793 | * 500 Kbps. | 125 ns. | 0 ns. | ||
794 | * 1 Mbps. | 42 ns. | 0 ns. | ||
795 | * 2 Mbps | N/A | 0 ns. | ||
796 | */ | ||
797 | if ((qic_std == QIC_TAPE_QIC40 && data_rate > 500) || | ||
798 | (qic_std == QIC_TAPE_QIC80 && data_rate > 1000)) { | ||
799 | TRACE_ABORT(-EINVAL, | ||
800 | ft_t_warn, "Datarate too high for QIC-mode"); | ||
801 | } | ||
802 | TRACE_CATCH(fdc_set_data_rate(data_rate),_res = -EINVAL); | ||
803 | ft_data_rate = data_rate; | ||
804 | if (qic_std == QIC_TAPE_QIC40 || qic_std == QIC_TAPE_QIC80) { | ||
805 | switch (data_rate) { | ||
806 | case 250: | ||
807 | fdc_set_write_precomp(250); | ||
808 | break; | ||
809 | default: | ||
810 | case 500: | ||
811 | fdc_set_write_precomp(125); | ||
812 | break; | ||
813 | case 1000: | ||
814 | fdc_set_write_precomp(42); | ||
815 | break; | ||
816 | } | ||
817 | } else { | ||
818 | fdc_set_write_precomp(0); | ||
819 | } | ||
820 | TRACE_EXIT result; | ||
821 | } | ||
822 | |||
823 | /* The next two functions are used to cope with excessive overrun errors | ||
824 | */ | ||
825 | int ftape_increase_threshold(void) | ||
826 | { | ||
827 | TRACE_FUN(ft_t_flow); | ||
828 | |||
829 | if (fdc.type < i82077 || ft_fdc_threshold >= 12) { | ||
830 | TRACE_ABORT(-EIO, ft_t_err, "cannot increase fifo threshold"); | ||
831 | } | ||
832 | if (fdc_fifo_threshold(++ft_fdc_threshold, NULL, NULL, NULL) < 0) { | ||
833 | TRACE(ft_t_err, "cannot increase fifo threshold"); | ||
834 | ft_fdc_threshold --; | ||
835 | fdc_reset(); | ||
836 | } | ||
837 | TRACE(ft_t_info, "New FIFO threshold: %d", ft_fdc_threshold); | ||
838 | TRACE_EXIT 0; | ||
839 | } | ||
840 | |||
841 | int ftape_half_data_rate(void) | ||
842 | { | ||
843 | if (ft_data_rate < 500) { | ||
844 | return -1; | ||
845 | } | ||
846 | if (ftape_set_data_rate(ft_data_rate / 2, ft_qic_std) < 0) { | ||
847 | return -EIO; | ||
848 | } | ||
849 | ftape_calc_timeouts(ft_qic_std, ft_data_rate, ftape_tape_len); | ||
850 | return 0; | ||
851 | } | ||
852 | |||
853 | /* Seek the head to the specified track. | ||
854 | */ | ||
855 | int ftape_seek_head_to_track(unsigned int track) | ||
856 | { | ||
857 | int status; | ||
858 | TRACE_FUN(ft_t_any); | ||
859 | |||
860 | ft_location.track = -1; /* remains set in case of error */ | ||
861 | if (track >= ft_tracks_per_tape) { | ||
862 | TRACE_ABORT(-EINVAL, ft_t_bug, "track out of bounds"); | ||
863 | } | ||
864 | TRACE(ft_t_flow, "seeking track %d", track); | ||
865 | TRACE_CATCH(ftape_command(QIC_SEEK_HEAD_TO_TRACK),); | ||
866 | TRACE_CATCH(ftape_parameter_wait(track, ftape_timeout.head_seek, | ||
867 | &status),); | ||
868 | ft_location.track = track; | ||
869 | ftape_might_be_off_track = 0; | ||
870 | TRACE_EXIT 0; | ||
871 | } | ||
872 | |||
873 | int ftape_wakeup_drive(wake_up_types method) | ||
874 | { | ||
875 | int status; | ||
876 | int motor_on = 0; | ||
877 | TRACE_FUN(ft_t_any); | ||
878 | |||
879 | switch (method) { | ||
880 | case wake_up_colorado: | ||
881 | TRACE_CATCH(ftape_command(QIC_PHANTOM_SELECT),); | ||
882 | TRACE_CATCH(ftape_parameter(0 /* ft_drive_sel ?? */),); | ||
883 | break; | ||
884 | case wake_up_mountain: | ||
885 | TRACE_CATCH(ftape_command(QIC_SOFT_SELECT),); | ||
886 | ftape_sleep(FT_MILLISECOND); /* NEEDED */ | ||
887 | TRACE_CATCH(ftape_parameter(18),); | ||
888 | break; | ||
889 | case wake_up_insight: | ||
890 | ftape_sleep(100 * FT_MILLISECOND); | ||
891 | motor_on = 1; | ||
892 | fdc_motor(motor_on); /* enable is done by motor-on */ | ||
893 | case no_wake_up: | ||
894 | break; | ||
895 | default: | ||
896 | TRACE_EXIT -ENODEV; /* unknown wakeup method */ | ||
897 | break; | ||
898 | } | ||
899 | /* If wakeup succeeded we shouldn't get an error here.. | ||
900 | */ | ||
901 | TRACE_CATCH(ftape_report_raw_drive_status(&status), | ||
902 | if (motor_on) { | ||
903 | fdc_motor(0); | ||
904 | }); | ||
905 | TRACE_EXIT 0; | ||
906 | } | ||
907 | |||
908 | int ftape_put_drive_to_sleep(wake_up_types method) | ||
909 | { | ||
910 | TRACE_FUN(ft_t_any); | ||
911 | |||
912 | switch (method) { | ||
913 | case wake_up_colorado: | ||
914 | TRACE_CATCH(ftape_command(QIC_PHANTOM_DESELECT),); | ||
915 | break; | ||
916 | case wake_up_mountain: | ||
917 | TRACE_CATCH(ftape_command(QIC_SOFT_DESELECT),); | ||
918 | break; | ||
919 | case wake_up_insight: | ||
920 | fdc_motor(0); /* enable is done by motor-on */ | ||
921 | case no_wake_up: /* no wakeup / no sleep ! */ | ||
922 | break; | ||
923 | default: | ||
924 | TRACE_EXIT -ENODEV; /* unknown wakeup method */ | ||
925 | } | ||
926 | TRACE_EXIT 0; | ||
927 | } | ||
928 | |||
929 | int ftape_reset_drive(void) | ||
930 | { | ||
931 | int result = 0; | ||
932 | int status; | ||
933 | unsigned int err_code; | ||
934 | qic117_cmd_t err_command; | ||
935 | int i; | ||
936 | TRACE_FUN(ft_t_any); | ||
937 | |||
938 | /* We want to re-establish contact with our drive. Fire a | ||
939 | * number of reset commands (single step pulses) and pray for | ||
940 | * success. | ||
941 | */ | ||
942 | for (i = 0; i < 2; ++i) { | ||
943 | TRACE(ft_t_flow, "Resetting fdc"); | ||
944 | fdc_reset(); | ||
945 | ftape_sleep(10 * FT_MILLISECOND); | ||
946 | TRACE(ft_t_flow, "Reset command to drive"); | ||
947 | result = ftape_command(QIC_RESET); | ||
948 | if (result == 0) { | ||
949 | ftape_sleep(1 * FT_SECOND); /* drive not | ||
950 | * accessible | ||
951 | * during 1 second | ||
952 | */ | ||
953 | TRACE(ft_t_flow, "Re-selecting drive"); | ||
954 | |||
955 | /* Strange, the QIC-117 specs don't mention | ||
956 | * this but the drive gets deselected after a | ||
957 | * soft reset ! So we need to enable it | ||
958 | * again. | ||
959 | */ | ||
960 | if (ftape_wakeup_drive(ft_drive_type.wake_up) < 0) { | ||
961 | TRACE(ft_t_err, "Wakeup failed !"); | ||
962 | } | ||
963 | TRACE(ft_t_flow, "Waiting until drive gets ready"); | ||
964 | result= ftape_ready_wait(ftape_timeout.reset, &status); | ||
965 | if (result == 0 && (status & QIC_STATUS_ERROR)) { | ||
966 | result = ftape_report_error(&err_code, | ||
967 | &err_command, 1); | ||
968 | if (result == 0 && err_code == 27) { | ||
969 | /* Okay, drive saw reset | ||
970 | * command and responded as it | ||
971 | * should | ||
972 | */ | ||
973 | break; | ||
974 | } else { | ||
975 | result = -EIO; | ||
976 | } | ||
977 | } else { | ||
978 | result = -EIO; | ||
979 | } | ||
980 | } | ||
981 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
982 | } | ||
983 | if (result != 0) { | ||
984 | TRACE(ft_t_err, "General failure to reset tape drive"); | ||
985 | } else { | ||
986 | /* Restore correct settings: keep original rate | ||
987 | */ | ||
988 | ftape_set_data_rate(ft_data_rate, ft_qic_std); | ||
989 | } | ||
990 | ftape_init_drive_needed = 1; | ||
991 | TRACE_EXIT result; | ||
992 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-io.h b/drivers/char/ftape/lowlevel/ftape-io.h deleted file mode 100644 index 26a7baad8717..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-io.h +++ /dev/null | |||
@@ -1,90 +0,0 @@ | |||
1 | #ifndef _FTAPE_IO_H | ||
2 | #define _FTAPE_IO_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
6 | * (C) 1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-io.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:18:18 $ | ||
26 | * | ||
27 | * This file contains definitions for the glue part of the | ||
28 | * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. | ||
29 | */ | ||
30 | |||
31 | #include <linux/qic117.h> | ||
32 | #include <linux/ftape-vendors.h> | ||
33 | |||
34 | typedef struct { | ||
35 | unsigned int seek; | ||
36 | unsigned int reset; | ||
37 | unsigned int rewind; | ||
38 | unsigned int head_seek; | ||
39 | unsigned int stop; | ||
40 | unsigned int pause; | ||
41 | } ft_timeout_table; | ||
42 | |||
43 | typedef enum { | ||
44 | prehistoric, pre_qic117c, post_qic117b, post_qic117d | ||
45 | } qic_model; | ||
46 | |||
47 | /* | ||
48 | * ftape-io.c defined global vars. | ||
49 | */ | ||
50 | extern ft_timeout_table ftape_timeout; | ||
51 | extern unsigned int ftape_tape_len; | ||
52 | extern volatile qic117_cmd_t ftape_current_command; | ||
53 | extern const struct qic117_command_table qic117_cmds[]; | ||
54 | extern int ftape_might_be_off_track; | ||
55 | |||
56 | /* | ||
57 | * ftape-io.c defined global functions. | ||
58 | */ | ||
59 | extern void ftape_udelay(unsigned int usecs); | ||
60 | extern void ftape_udelay_calibrate(void); | ||
61 | extern void ftape_sleep(unsigned int time); | ||
62 | extern void ftape_report_vendor_id(unsigned int *id); | ||
63 | extern int ftape_command(qic117_cmd_t command); | ||
64 | extern int ftape_command_wait(qic117_cmd_t command, | ||
65 | unsigned int timeout, | ||
66 | int *status); | ||
67 | extern int ftape_parameter(unsigned int parameter); | ||
68 | extern int ftape_report_operation(int *status, | ||
69 | qic117_cmd_t command, | ||
70 | int result_length); | ||
71 | extern int ftape_report_configuration(qic_model *model, | ||
72 | unsigned int *rate, | ||
73 | int *qic_std, | ||
74 | int *tape_len); | ||
75 | extern int ftape_report_drive_status(int *status); | ||
76 | extern int ftape_report_raw_drive_status(int *status); | ||
77 | extern int ftape_report_status(int *status); | ||
78 | extern int ftape_ready_wait(unsigned int timeout, int *status); | ||
79 | extern int ftape_seek_head_to_track(unsigned int track); | ||
80 | extern int ftape_set_data_rate(unsigned int new_rate, unsigned int qic_std); | ||
81 | extern int ftape_report_error(unsigned int *error, | ||
82 | qic117_cmd_t *command, | ||
83 | int report); | ||
84 | extern int ftape_reset_drive(void); | ||
85 | extern int ftape_put_drive_to_sleep(wake_up_types method); | ||
86 | extern int ftape_wakeup_drive(wake_up_types method); | ||
87 | extern int ftape_increase_threshold(void); | ||
88 | extern int ftape_half_data_rate(void); | ||
89 | |||
90 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-proc.c b/drivers/char/ftape/lowlevel/ftape-proc.c deleted file mode 100644 index e805b15e0a12..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-proc.c +++ /dev/null | |||
@@ -1,214 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1997 Claus-Justus Heine | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; see the file COPYING. If not, write to | ||
16 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | |||
18 | * | ||
19 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-proc.c,v $ | ||
20 | * $Revision: 1.11 $ | ||
21 | * $Date: 1997/10/24 14:47:37 $ | ||
22 | * | ||
23 | * This file contains the procfs interface for the | ||
24 | * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. | ||
25 | |||
26 | * Old code removed, switched to dynamic proc entry. | ||
27 | */ | ||
28 | |||
29 | |||
30 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) | ||
31 | |||
32 | #include <linux/proc_fs.h> | ||
33 | |||
34 | #include <linux/ftape.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/qic117.h> | ||
37 | |||
38 | #include "../lowlevel/ftape-io.h" | ||
39 | #include "../lowlevel/ftape-ctl.h" | ||
40 | #include "../lowlevel/ftape-proc.h" | ||
41 | #include "../lowlevel/ftape-tracing.h" | ||
42 | |||
43 | static size_t get_driver_info(char *buf) | ||
44 | { | ||
45 | const char *debug_level[] = { "bugs" , | ||
46 | "errors", | ||
47 | "warnings", | ||
48 | "informational", | ||
49 | "noisy", | ||
50 | "program flow", | ||
51 | "fdc and dma", | ||
52 | "data flow", | ||
53 | "anything" }; | ||
54 | |||
55 | return sprintf(buf, | ||
56 | "version : %s\n" | ||
57 | "used data rate: %d kbit/sec\n" | ||
58 | "dma memory : %d kb\n" | ||
59 | "debug messages: %s\n", | ||
60 | FTAPE_VERSION, | ||
61 | ft_data_rate, | ||
62 | FT_BUFF_SIZE * ft_nr_buffers >> 10, | ||
63 | debug_level[TRACE_LEVEL]); | ||
64 | } | ||
65 | |||
66 | static size_t get_tapedrive_info(char *buf) | ||
67 | { | ||
68 | return sprintf(buf, | ||
69 | "vendor id : 0x%04x\n" | ||
70 | "drive name: %s\n" | ||
71 | "wind speed: %d ips\n" | ||
72 | "wakeup : %s\n" | ||
73 | "max. rate : %d kbit/sec\n", | ||
74 | ft_drive_type.vendor_id, | ||
75 | ft_drive_type.name, | ||
76 | ft_drive_type.speed, | ||
77 | ((ft_drive_type.wake_up == no_wake_up) | ||
78 | ? "No wakeup needed" : | ||
79 | ((ft_drive_type.wake_up == wake_up_colorado) | ||
80 | ? "Colorado" : | ||
81 | ((ft_drive_type.wake_up == wake_up_mountain) | ||
82 | ? "Mountain" : | ||
83 | ((ft_drive_type.wake_up == wake_up_insight) | ||
84 | ? "Motor on" : | ||
85 | "Unknown")))), | ||
86 | ft_drive_max_rate); | ||
87 | } | ||
88 | |||
89 | static size_t get_cartridge_info(char *buf) | ||
90 | { | ||
91 | if (ftape_init_drive_needed) { | ||
92 | return sprintf(buf, "uninitialized\n"); | ||
93 | } | ||
94 | if (ft_no_tape) { | ||
95 | return sprintf(buf, "no cartridge inserted\n"); | ||
96 | } | ||
97 | return sprintf(buf, | ||
98 | "segments : %5d\n" | ||
99 | "tracks : %5d\n" | ||
100 | "length : %5dft\n" | ||
101 | "formatted : %3s\n" | ||
102 | "writable : %3s\n" | ||
103 | "QIC spec. : QIC-%s\n" | ||
104 | "fmt-code : %1d\n", | ||
105 | ft_segments_per_track, | ||
106 | ft_tracks_per_tape, | ||
107 | ftape_tape_len, | ||
108 | (ft_formatted == 1) ? "yes" : "no", | ||
109 | (ft_write_protected == 1) ? "no" : "yes", | ||
110 | ((ft_qic_std == QIC_TAPE_QIC40) ? "40" : | ||
111 | ((ft_qic_std == QIC_TAPE_QIC80) ? "80" : | ||
112 | ((ft_qic_std == QIC_TAPE_QIC3010) ? "3010" : | ||
113 | ((ft_qic_std == QIC_TAPE_QIC3020) ? "3020" : | ||
114 | "???")))), | ||
115 | ft_format_code); | ||
116 | } | ||
117 | |||
118 | static size_t get_controller_info(char *buf) | ||
119 | { | ||
120 | const char *fdc_name[] = { "no fdc", | ||
121 | "i8272", | ||
122 | "i82077", | ||
123 | "i82077AA", | ||
124 | "Colorado FC-10 or FC-20", | ||
125 | "i82078", | ||
126 | "i82078_1" }; | ||
127 | |||
128 | return sprintf(buf, | ||
129 | "FDC type : %s\n" | ||
130 | "FDC base : 0x%03x\n" | ||
131 | "FDC irq : %d\n" | ||
132 | "FDC dma : %d\n" | ||
133 | "FDC thr. : %d\n" | ||
134 | "max. rate : %d kbit/sec\n", | ||
135 | ft_mach2 ? "Mountain MACH-2" : fdc_name[fdc.type], | ||
136 | fdc.sra, fdc.irq, fdc.dma, | ||
137 | ft_fdc_threshold, ft_fdc_max_rate); | ||
138 | } | ||
139 | |||
140 | static size_t get_history_info(char *buf) | ||
141 | { | ||
142 | size_t len; | ||
143 | |||
144 | len = sprintf(buf, | ||
145 | "\nFDC isr statistics\n" | ||
146 | " id_am_errors : %3d\n" | ||
147 | " id_crc_errors : %3d\n" | ||
148 | " data_am_errors : %3d\n" | ||
149 | " data_crc_errors : %3d\n" | ||
150 | " overrun_errors : %3d\n" | ||
151 | " no_data_errors : %3d\n" | ||
152 | " retries : %3d\n", | ||
153 | ft_history.id_am_errors, ft_history.id_crc_errors, | ||
154 | ft_history.data_am_errors, ft_history.data_crc_errors, | ||
155 | ft_history.overrun_errors, ft_history.no_data_errors, | ||
156 | ft_history.retries); | ||
157 | len += sprintf(buf + len, | ||
158 | "\nECC statistics\n" | ||
159 | " crc_errors : %3d\n" | ||
160 | " crc_failures : %3d\n" | ||
161 | " ecc_failures : %3d\n" | ||
162 | " sectors corrected: %3d\n", | ||
163 | ft_history.crc_errors, ft_history.crc_failures, | ||
164 | ft_history.ecc_failures, ft_history.corrected); | ||
165 | len += sprintf(buf + len, | ||
166 | "\ntape quality statistics\n" | ||
167 | " media defects : %3d\n", | ||
168 | ft_history.defects); | ||
169 | len += sprintf(buf + len, | ||
170 | "\ntape motion statistics\n" | ||
171 | " repositions : %3d\n", | ||
172 | ft_history.rewinds); | ||
173 | return len; | ||
174 | } | ||
175 | |||
176 | static int ftape_read_proc(char *page, char **start, off_t off, | ||
177 | int count, int *eof, void *data) | ||
178 | { | ||
179 | char *ptr = page; | ||
180 | size_t len; | ||
181 | |||
182 | ptr += sprintf(ptr, "Kernel Driver\n\n"); | ||
183 | ptr += get_driver_info(ptr); | ||
184 | ptr += sprintf(ptr, "\nTape Drive\n\n"); | ||
185 | ptr += get_tapedrive_info(ptr); | ||
186 | ptr += sprintf(ptr, "\nFDC Controller\n\n"); | ||
187 | ptr += get_controller_info(ptr); | ||
188 | ptr += sprintf(ptr, "\nTape Cartridge\n\n"); | ||
189 | ptr += get_cartridge_info(ptr); | ||
190 | ptr += sprintf(ptr, "\nHistory Record\n\n"); | ||
191 | ptr += get_history_info(ptr); | ||
192 | |||
193 | len = strlen(page); | ||
194 | *start = NULL; | ||
195 | if (off+count >= len) { | ||
196 | *eof = 1; | ||
197 | } else { | ||
198 | *eof = 0; | ||
199 | } | ||
200 | return len; | ||
201 | } | ||
202 | |||
203 | int __init ftape_proc_init(void) | ||
204 | { | ||
205 | return create_proc_read_entry("ftape", 0, &proc_root, | ||
206 | ftape_read_proc, NULL) != NULL; | ||
207 | } | ||
208 | |||
209 | void ftape_proc_destroy(void) | ||
210 | { | ||
211 | remove_proc_entry("ftape", &proc_root); | ||
212 | } | ||
213 | |||
214 | #endif /* defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS) */ | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-proc.h b/drivers/char/ftape/lowlevel/ftape-proc.h deleted file mode 100644 index 264dfcc1d22d..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-proc.h +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | #ifndef _FTAPE_PROC_H | ||
2 | #define _FTAPE_PROC_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1997 Claus-Justus Heine | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-proc.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:18:20 $ | ||
25 | * | ||
26 | * This file contains definitions for the procfs interface of the | ||
27 | * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. | ||
28 | */ | ||
29 | |||
30 | #include <linux/proc_fs.h> | ||
31 | |||
32 | extern int ftape_proc_init(void); | ||
33 | extern void ftape_proc_destroy(void); | ||
34 | |||
35 | #endif | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-read.c b/drivers/char/ftape/lowlevel/ftape-read.c deleted file mode 100644 index d967d8cd86dc..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-read.c +++ /dev/null | |||
@@ -1,621 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
3 | * (C) 1996-1997 Claus-Justus Heine. | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2, or (at your option) | ||
8 | any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; see the file COPYING. If not, write to | ||
17 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | |||
19 | * | ||
20 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-read.c,v $ | ||
21 | * $Revision: 1.6 $ | ||
22 | * $Date: 1997/10/21 14:39:22 $ | ||
23 | * | ||
24 | * This file contains the reading code | ||
25 | * for the QIC-117 floppy-tape driver for Linux. | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | #include <linux/string.h> | ||
30 | #include <linux/errno.h> | ||
31 | #include <linux/mm.h> | ||
32 | |||
33 | #include <linux/ftape.h> | ||
34 | #include <linux/qic117.h> | ||
35 | #include "../lowlevel/ftape-tracing.h" | ||
36 | #include "../lowlevel/ftape-read.h" | ||
37 | #include "../lowlevel/ftape-io.h" | ||
38 | #include "../lowlevel/ftape-ctl.h" | ||
39 | #include "../lowlevel/ftape-rw.h" | ||
40 | #include "../lowlevel/ftape-write.h" | ||
41 | #include "../lowlevel/ftape-ecc.h" | ||
42 | #include "../lowlevel/ftape-bsm.h" | ||
43 | |||
44 | /* Global vars. | ||
45 | */ | ||
46 | |||
47 | /* Local vars. | ||
48 | */ | ||
49 | |||
50 | void ftape_zap_read_buffers(void) | ||
51 | { | ||
52 | int i; | ||
53 | |||
54 | for (i = 0; i < ft_nr_buffers; ++i) { | ||
55 | /* changed to "fit" with dynamic allocation of tape_buffer. --khp */ | ||
56 | ft_buffer[i]->status = waiting; | ||
57 | ft_buffer[i]->bytes = 0; | ||
58 | ft_buffer[i]->skip = 0; | ||
59 | ft_buffer[i]->retry = 0; | ||
60 | } | ||
61 | /* ftape_reset_buffer(); */ | ||
62 | } | ||
63 | |||
64 | static SectorMap convert_sector_map(buffer_struct * buff) | ||
65 | { | ||
66 | int i = 0; | ||
67 | SectorMap bad_map = ftape_get_bad_sector_entry(buff->segment_id); | ||
68 | SectorMap src_map = buff->soft_error_map | buff->hard_error_map; | ||
69 | SectorMap dst_map = 0; | ||
70 | TRACE_FUN(ft_t_any); | ||
71 | |||
72 | if (bad_map || src_map) { | ||
73 | TRACE(ft_t_flow, "bad_map = 0x%08lx", (long) bad_map); | ||
74 | TRACE(ft_t_flow, "src_map = 0x%08lx", (long) src_map); | ||
75 | } | ||
76 | while (bad_map) { | ||
77 | while ((bad_map & 1) == 0) { | ||
78 | if (src_map & 1) { | ||
79 | dst_map |= (1 << i); | ||
80 | } | ||
81 | src_map >>= 1; | ||
82 | bad_map >>= 1; | ||
83 | ++i; | ||
84 | } | ||
85 | /* (bad_map & 1) == 1 */ | ||
86 | src_map >>= 1; | ||
87 | bad_map >>= 1; | ||
88 | } | ||
89 | if (src_map) { | ||
90 | dst_map |= (src_map << i); | ||
91 | } | ||
92 | if (dst_map) { | ||
93 | TRACE(ft_t_flow, "dst_map = 0x%08lx", (long) dst_map); | ||
94 | } | ||
95 | TRACE_EXIT dst_map; | ||
96 | } | ||
97 | |||
98 | static int correct_and_copy_fraction(buffer_struct *buff, __u8 * destination, | ||
99 | int start, int size) | ||
100 | { | ||
101 | struct memory_segment mseg; | ||
102 | int result; | ||
103 | SectorMap read_bad; | ||
104 | TRACE_FUN(ft_t_any); | ||
105 | |||
106 | mseg.read_bad = convert_sector_map(buff); | ||
107 | mseg.marked_bad = 0; /* not used... */ | ||
108 | mseg.blocks = buff->bytes / FT_SECTOR_SIZE; | ||
109 | mseg.data = buff->address; | ||
110 | /* If there are no data sectors we can skip this segment. | ||
111 | */ | ||
112 | if (mseg.blocks <= 3) { | ||
113 | TRACE_ABORT(0, ft_t_noise, "empty segment"); | ||
114 | } | ||
115 | read_bad = mseg.read_bad; | ||
116 | ft_history.crc_errors += count_ones(read_bad); | ||
117 | result = ftape_ecc_correct_data(&mseg); | ||
118 | if (read_bad != 0 || mseg.corrected != 0) { | ||
119 | TRACE(ft_t_noise, "crc error map: 0x%08lx", (unsigned long)read_bad); | ||
120 | TRACE(ft_t_noise, "corrected map: 0x%08lx", (unsigned long)mseg.corrected); | ||
121 | ft_history.corrected += count_ones(mseg.corrected); | ||
122 | } | ||
123 | if (result == ECC_CORRECTED || result == ECC_OK) { | ||
124 | if (result == ECC_CORRECTED) { | ||
125 | TRACE(ft_t_info, "ecc corrected segment: %d", buff->segment_id); | ||
126 | } | ||
127 | if(start < 0) { | ||
128 | start= 0; | ||
129 | } | ||
130 | if((start+size) > ((mseg.blocks - 3) * FT_SECTOR_SIZE)) { | ||
131 | size = (mseg.blocks - 3) * FT_SECTOR_SIZE - start; | ||
132 | } | ||
133 | if (size < 0) { | ||
134 | size= 0; | ||
135 | } | ||
136 | if(size > 0) { | ||
137 | memcpy(destination + start, mseg.data + start, size); | ||
138 | } | ||
139 | if ((read_bad ^ mseg.corrected) & mseg.corrected) { | ||
140 | /* sectors corrected without crc errors set */ | ||
141 | ft_history.crc_failures++; | ||
142 | } | ||
143 | TRACE_EXIT size; /* (mseg.blocks - 3) * FT_SECTOR_SIZE; */ | ||
144 | } else { | ||
145 | ft_history.ecc_failures++; | ||
146 | TRACE_ABORT(-EAGAIN, | ||
147 | ft_t_err, "ecc failure on segment %d", | ||
148 | buff->segment_id); | ||
149 | } | ||
150 | TRACE_EXIT 0; | ||
151 | } | ||
152 | |||
153 | /* Read given segment into buffer at address. | ||
154 | */ | ||
155 | int ftape_read_segment_fraction(const int segment_id, | ||
156 | void *address, | ||
157 | const ft_read_mode_t read_mode, | ||
158 | const int start, | ||
159 | const int size) | ||
160 | { | ||
161 | int result = 0; | ||
162 | int retry = 0; | ||
163 | int bytes_read = 0; | ||
164 | int read_done = 0; | ||
165 | TRACE_FUN(ft_t_flow); | ||
166 | |||
167 | ft_history.used |= 1; | ||
168 | TRACE(ft_t_data_flow, "segment_id = %d", segment_id); | ||
169 | if (ft_driver_state != reading) { | ||
170 | TRACE(ft_t_noise, "calling ftape_abort_operation"); | ||
171 | TRACE_CATCH(ftape_abort_operation(),); | ||
172 | ftape_set_state(reading); | ||
173 | } | ||
174 | for(;;) { | ||
175 | buffer_struct *tail; | ||
176 | /* Allow escape from this loop on signal ! | ||
177 | */ | ||
178 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
179 | /* Search all full buffers for the first matching the | ||
180 | * wanted segment. Clear other buffers on the fly. | ||
181 | */ | ||
182 | tail = ftape_get_buffer(ft_queue_tail); | ||
183 | while (!read_done && tail->status == done) { | ||
184 | /* Allow escape from this loop on signal ! | ||
185 | */ | ||
186 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
187 | if (tail->segment_id == segment_id) { | ||
188 | /* If out buffer is already full, | ||
189 | * return its contents. | ||
190 | */ | ||
191 | TRACE(ft_t_flow, "found segment in cache: %d", | ||
192 | segment_id); | ||
193 | if (tail->deleted) { | ||
194 | /* Return a value that | ||
195 | * read_header_segment | ||
196 | * understands. As this | ||
197 | * should only occur when | ||
198 | * searching for the header | ||
199 | * segments it shouldn't be | ||
200 | * misinterpreted elsewhere. | ||
201 | */ | ||
202 | TRACE_EXIT 0; | ||
203 | } | ||
204 | result = correct_and_copy_fraction( | ||
205 | tail, | ||
206 | address, | ||
207 | start, | ||
208 | size); | ||
209 | TRACE(ft_t_flow, "segment contains (bytes): %d", | ||
210 | result); | ||
211 | if (result < 0) { | ||
212 | if (result != -EAGAIN) { | ||
213 | TRACE_EXIT result; | ||
214 | } | ||
215 | /* keep read_done == 0, will | ||
216 | * trigger | ||
217 | * ftape_abort_operation | ||
218 | * because reading wrong | ||
219 | * segment. | ||
220 | */ | ||
221 | TRACE(ft_t_err, "ecc failed, retry"); | ||
222 | ++retry; | ||
223 | } else { | ||
224 | read_done = 1; | ||
225 | bytes_read = result; | ||
226 | } | ||
227 | } else { | ||
228 | TRACE(ft_t_flow,"zapping segment in cache: %d", | ||
229 | tail->segment_id); | ||
230 | } | ||
231 | tail->status = waiting; | ||
232 | tail = ftape_next_buffer(ft_queue_tail); | ||
233 | } | ||
234 | if (!read_done && tail->status == reading) { | ||
235 | if (tail->segment_id == segment_id) { | ||
236 | switch(ftape_wait_segment(reading)) { | ||
237 | case 0: | ||
238 | break; | ||
239 | case -EINTR: | ||
240 | TRACE_ABORT(-EINTR, ft_t_warn, | ||
241 | "interrupted by " | ||
242 | "non-blockable signal"); | ||
243 | break; | ||
244 | default: | ||
245 | TRACE(ft_t_noise, | ||
246 | "wait_segment failed"); | ||
247 | ftape_abort_operation(); | ||
248 | ftape_set_state(reading); | ||
249 | break; | ||
250 | } | ||
251 | } else { | ||
252 | /* We're reading the wrong segment, | ||
253 | * stop runner. | ||
254 | */ | ||
255 | TRACE(ft_t_noise, "reading wrong segment"); | ||
256 | ftape_abort_operation(); | ||
257 | ftape_set_state(reading); | ||
258 | } | ||
259 | } | ||
260 | /* should runner stop ? | ||
261 | */ | ||
262 | if (ft_runner_status == aborting) { | ||
263 | buffer_struct *head = ftape_get_buffer(ft_queue_head); | ||
264 | switch(head->status) { | ||
265 | case error: | ||
266 | ft_history.defects += | ||
267 | count_ones(head->hard_error_map); | ||
268 | case reading: | ||
269 | head->status = waiting; | ||
270 | break; | ||
271 | default: | ||
272 | break; | ||
273 | } | ||
274 | TRACE_CATCH(ftape_dumb_stop(),); | ||
275 | } else { | ||
276 | /* If just passed last segment on tape: wait | ||
277 | * for BOT or EOT mark. Sets ft_runner_status to | ||
278 | * idle if at lEOT and successful | ||
279 | */ | ||
280 | TRACE_CATCH(ftape_handle_logical_eot(),); | ||
281 | } | ||
282 | /* If we got a segment: quit, or else retry up to limit. | ||
283 | * | ||
284 | * If segment to read is empty, do not start runner for it, | ||
285 | * but wait for next read call. | ||
286 | */ | ||
287 | if (read_done || | ||
288 | ftape_get_bad_sector_entry(segment_id) == EMPTY_SEGMENT ) { | ||
289 | /* bytes_read = 0; should still be zero */ | ||
290 | TRACE_EXIT bytes_read; | ||
291 | |||
292 | } | ||
293 | if (retry > FT_RETRIES_ON_ECC_ERROR) { | ||
294 | ft_history.defects++; | ||
295 | TRACE_ABORT(-ENODATA, ft_t_err, | ||
296 | "too many retries on ecc failure"); | ||
297 | } | ||
298 | /* Now at least one buffer is empty ! | ||
299 | * Restart runner & tape if needed. | ||
300 | */ | ||
301 | TRACE(ft_t_any, "head: %d, tail: %d, ft_runner_status: %d", | ||
302 | ftape_buffer_id(ft_queue_head), | ||
303 | ftape_buffer_id(ft_queue_tail), | ||
304 | ft_runner_status); | ||
305 | TRACE(ft_t_any, "buffer[].status, [head]: %d, [tail]: %d", | ||
306 | ftape_get_buffer(ft_queue_head)->status, | ||
307 | ftape_get_buffer(ft_queue_tail)->status); | ||
308 | tail = ftape_get_buffer(ft_queue_tail); | ||
309 | if (tail->status == waiting) { | ||
310 | buffer_struct *head = ftape_get_buffer(ft_queue_head); | ||
311 | |||
312 | ftape_setup_new_segment(head, segment_id, -1); | ||
313 | if (read_mode == FT_RD_SINGLE) { | ||
314 | /* disable read-ahead */ | ||
315 | head->next_segment = 0; | ||
316 | } | ||
317 | ftape_calc_next_cluster(head); | ||
318 | if (ft_runner_status == idle) { | ||
319 | result = ftape_start_tape(segment_id, | ||
320 | head->sector_offset); | ||
321 | if (result < 0) { | ||
322 | TRACE_ABORT(result, ft_t_err, "Error: " | ||
323 | "segment %d unreachable", | ||
324 | segment_id); | ||
325 | } | ||
326 | } | ||
327 | head->status = reading; | ||
328 | fdc_setup_read_write(head, FDC_READ); | ||
329 | } | ||
330 | } | ||
331 | /* not reached */ | ||
332 | TRACE_EXIT -EIO; | ||
333 | } | ||
334 | |||
335 | int ftape_read_header_segment(__u8 *address) | ||
336 | { | ||
337 | int result; | ||
338 | int header_segment; | ||
339 | int first_failed = 0; | ||
340 | int status; | ||
341 | TRACE_FUN(ft_t_flow); | ||
342 | |||
343 | ft_used_header_segment = -1; | ||
344 | TRACE_CATCH(ftape_report_drive_status(&status),); | ||
345 | TRACE(ft_t_flow, "reading..."); | ||
346 | /* We're looking for the first header segment. | ||
347 | * A header segment cannot contain bad sectors, therefor at the | ||
348 | * tape start, segments with bad sectors are (according to QIC-40/80) | ||
349 | * written with deleted data marks and must be skipped. | ||
350 | */ | ||
351 | memset(address, '\0', (FT_SECTORS_PER_SEGMENT - 3) * FT_SECTOR_SIZE); | ||
352 | result = 0; | ||
353 | #define HEADER_SEGMENT_BOUNDARY 68 /* why not 42? */ | ||
354 | for (header_segment = 0; | ||
355 | header_segment < HEADER_SEGMENT_BOUNDARY && result == 0; | ||
356 | ++header_segment) { | ||
357 | /* Set no read-ahead, the isr will force read-ahead whenever | ||
358 | * it encounters deleted data ! | ||
359 | */ | ||
360 | result = ftape_read_segment(header_segment, | ||
361 | address, | ||
362 | FT_RD_SINGLE); | ||
363 | if (result < 0 && !first_failed) { | ||
364 | TRACE(ft_t_err, "header segment damaged, trying backup"); | ||
365 | first_failed = 1; | ||
366 | result = 0; /* force read of next (backup) segment */ | ||
367 | } | ||
368 | } | ||
369 | if (result < 0 || header_segment >= HEADER_SEGMENT_BOUNDARY) { | ||
370 | TRACE_ABORT(-EIO, ft_t_err, | ||
371 | "no readable header segment found"); | ||
372 | } | ||
373 | TRACE_CATCH(ftape_abort_operation(),); | ||
374 | ft_used_header_segment = header_segment; | ||
375 | result = ftape_decode_header_segment(address); | ||
376 | TRACE_EXIT result; | ||
377 | } | ||
378 | |||
379 | int ftape_decode_header_segment(__u8 *address) | ||
380 | { | ||
381 | unsigned int max_floppy_side; | ||
382 | unsigned int max_floppy_track; | ||
383 | unsigned int max_floppy_sector; | ||
384 | unsigned int new_tape_len; | ||
385 | TRACE_FUN(ft_t_flow); | ||
386 | |||
387 | if (GET4(address, FT_SIGNATURE) == FT_D2G_MAGIC) { | ||
388 | /* Ditto 2GB header segment. They encrypt the bad sector map. | ||
389 | * We decrypt it and store them in normal format. | ||
390 | * I hope this is correct. | ||
391 | */ | ||
392 | int i; | ||
393 | TRACE(ft_t_warn, | ||
394 | "Found Ditto 2GB tape, " | ||
395 | "trying to decrypt bad sector map"); | ||
396 | for (i=256; i < 29 * FT_SECTOR_SIZE; i++) { | ||
397 | address[i] = ~(address[i] - (i&0xff)); | ||
398 | } | ||
399 | PUT4(address, 0,FT_HSEG_MAGIC); | ||
400 | } else if (GET4(address, FT_SIGNATURE) != FT_HSEG_MAGIC) { | ||
401 | TRACE_ABORT(-EIO, ft_t_err, | ||
402 | "wrong signature in header segment"); | ||
403 | } | ||
404 | ft_format_code = (ft_format_type) address[FT_FMT_CODE]; | ||
405 | if (ft_format_code != fmt_big) { | ||
406 | ft_header_segment_1 = GET2(address, FT_HSEG_1); | ||
407 | ft_header_segment_2 = GET2(address, FT_HSEG_2); | ||
408 | ft_first_data_segment = GET2(address, FT_FRST_SEG); | ||
409 | ft_last_data_segment = GET2(address, FT_LAST_SEG); | ||
410 | } else { | ||
411 | ft_header_segment_1 = GET4(address, FT_6_HSEG_1); | ||
412 | ft_header_segment_2 = GET4(address, FT_6_HSEG_2); | ||
413 | ft_first_data_segment = GET4(address, FT_6_FRST_SEG); | ||
414 | ft_last_data_segment = GET4(address, FT_6_LAST_SEG); | ||
415 | } | ||
416 | TRACE(ft_t_noise, "first data segment: %d", ft_first_data_segment); | ||
417 | TRACE(ft_t_noise, "last data segment: %d", ft_last_data_segment); | ||
418 | TRACE(ft_t_noise, "header segments are %d and %d", | ||
419 | ft_header_segment_1, ft_header_segment_2); | ||
420 | |||
421 | /* Verify tape parameters... | ||
422 | * QIC-40/80 spec: tape_parameters: | ||
423 | * | ||
424 | * segments-per-track segments_per_track | ||
425 | * tracks-per-cartridge tracks_per_tape | ||
426 | * max-floppy-side (segments_per_track * | ||
427 | * tracks_per_tape - 1) / | ||
428 | * ftape_segments_per_head | ||
429 | * max-floppy-track ftape_segments_per_head / | ||
430 | * ftape_segments_per_cylinder - 1 | ||
431 | * max-floppy-sector ftape_segments_per_cylinder * | ||
432 | * FT_SECTORS_PER_SEGMENT | ||
433 | */ | ||
434 | ft_segments_per_track = GET2(address, FT_SPT); | ||
435 | ft_tracks_per_tape = address[FT_TPC]; | ||
436 | max_floppy_side = address[FT_FHM]; | ||
437 | max_floppy_track = address[FT_FTM]; | ||
438 | max_floppy_sector = address[FT_FSM]; | ||
439 | TRACE(ft_t_noise, "(fmt/spt/tpc/fhm/ftm/fsm) = %d/%d/%d/%d/%d/%d", | ||
440 | ft_format_code, ft_segments_per_track, ft_tracks_per_tape, | ||
441 | max_floppy_side, max_floppy_track, max_floppy_sector); | ||
442 | new_tape_len = ftape_tape_len; | ||
443 | switch (ft_format_code) { | ||
444 | case fmt_425ft: | ||
445 | new_tape_len = 425; | ||
446 | break; | ||
447 | case fmt_normal: | ||
448 | if (ftape_tape_len == 0) { /* otherwise 307 ft */ | ||
449 | new_tape_len = 205; | ||
450 | } | ||
451 | break; | ||
452 | case fmt_1100ft: | ||
453 | new_tape_len = 1100; | ||
454 | break; | ||
455 | case fmt_var:{ | ||
456 | int segments_per_1000_inch = 1; /* non-zero default for switch */ | ||
457 | switch (ft_qic_std) { | ||
458 | case QIC_TAPE_QIC40: | ||
459 | segments_per_1000_inch = 332; | ||
460 | break; | ||
461 | case QIC_TAPE_QIC80: | ||
462 | segments_per_1000_inch = 488; | ||
463 | break; | ||
464 | case QIC_TAPE_QIC3010: | ||
465 | segments_per_1000_inch = 730; | ||
466 | break; | ||
467 | case QIC_TAPE_QIC3020: | ||
468 | segments_per_1000_inch = 1430; | ||
469 | break; | ||
470 | } | ||
471 | new_tape_len = (1000 * ft_segments_per_track + | ||
472 | (segments_per_1000_inch - 1)) / segments_per_1000_inch; | ||
473 | break; | ||
474 | } | ||
475 | case fmt_big:{ | ||
476 | int segments_per_1000_inch = 1; /* non-zero default for switch */ | ||
477 | switch (ft_qic_std) { | ||
478 | case QIC_TAPE_QIC40: | ||
479 | segments_per_1000_inch = 332; | ||
480 | break; | ||
481 | case QIC_TAPE_QIC80: | ||
482 | segments_per_1000_inch = 488; | ||
483 | break; | ||
484 | case QIC_TAPE_QIC3010: | ||
485 | segments_per_1000_inch = 730; | ||
486 | break; | ||
487 | case QIC_TAPE_QIC3020: | ||
488 | segments_per_1000_inch = 1430; | ||
489 | break; | ||
490 | default: | ||
491 | TRACE_ABORT(-EIO, ft_t_bug, | ||
492 | "%x QIC-standard with fmt-code %d, please report", | ||
493 | ft_qic_std, ft_format_code); | ||
494 | } | ||
495 | new_tape_len = ((1000 * ft_segments_per_track + | ||
496 | (segments_per_1000_inch - 1)) / | ||
497 | segments_per_1000_inch); | ||
498 | break; | ||
499 | } | ||
500 | default: | ||
501 | TRACE_ABORT(-EIO, ft_t_err, | ||
502 | "unknown tape format, please report !"); | ||
503 | } | ||
504 | if (new_tape_len != ftape_tape_len) { | ||
505 | ftape_tape_len = new_tape_len; | ||
506 | TRACE(ft_t_info, "calculated tape length is %d ft", | ||
507 | ftape_tape_len); | ||
508 | ftape_calc_timeouts(ft_qic_std, ft_data_rate, ftape_tape_len); | ||
509 | } | ||
510 | if (ft_segments_per_track == 0 && ft_tracks_per_tape == 0 && | ||
511 | max_floppy_side == 0 && max_floppy_track == 0 && | ||
512 | max_floppy_sector == 0) { | ||
513 | /* QIC-40 Rev E and earlier has no values in the header. | ||
514 | */ | ||
515 | ft_segments_per_track = 68; | ||
516 | ft_tracks_per_tape = 20; | ||
517 | max_floppy_side = 1; | ||
518 | max_floppy_track = 169; | ||
519 | max_floppy_sector = 128; | ||
520 | } | ||
521 | /* This test will compensate for the wrong parameter on tapes | ||
522 | * formatted by Conner software. | ||
523 | */ | ||
524 | if (ft_segments_per_track == 150 && | ||
525 | ft_tracks_per_tape == 28 && | ||
526 | max_floppy_side == 7 && | ||
527 | max_floppy_track == 149 && | ||
528 | max_floppy_sector == 128) { | ||
529 | TRACE(ft_t_info, "the famous CONNER bug: max_floppy_side off by one !"); | ||
530 | max_floppy_side = 6; | ||
531 | } | ||
532 | /* These tests will compensate for the wrong parameter on tapes | ||
533 | * formatted by ComByte Windows software. | ||
534 | * | ||
535 | * First, for 205 foot tapes | ||
536 | */ | ||
537 | if (ft_segments_per_track == 100 && | ||
538 | ft_tracks_per_tape == 28 && | ||
539 | max_floppy_side == 9 && | ||
540 | max_floppy_track == 149 && | ||
541 | max_floppy_sector == 128) { | ||
542 | TRACE(ft_t_info, "the ComByte bug: max_floppy_side incorrect!"); | ||
543 | max_floppy_side = 4; | ||
544 | } | ||
545 | /* Next, for 307 foot tapes. */ | ||
546 | if (ft_segments_per_track == 150 && | ||
547 | ft_tracks_per_tape == 28 && | ||
548 | max_floppy_side == 9 && | ||
549 | max_floppy_track == 149 && | ||
550 | max_floppy_sector == 128) { | ||
551 | TRACE(ft_t_info, "the ComByte bug: max_floppy_side incorrect!"); | ||
552 | max_floppy_side = 6; | ||
553 | } | ||
554 | /* This test will compensate for the wrong parameter on tapes | ||
555 | * formatted by Colorado Windows software. | ||
556 | */ | ||
557 | if (ft_segments_per_track == 150 && | ||
558 | ft_tracks_per_tape == 28 && | ||
559 | max_floppy_side == 6 && | ||
560 | max_floppy_track == 150 && | ||
561 | max_floppy_sector == 128) { | ||
562 | TRACE(ft_t_info, "the famous Colorado bug: max_floppy_track off by one !"); | ||
563 | max_floppy_track = 149; | ||
564 | } | ||
565 | ftape_segments_per_head = ((max_floppy_sector/FT_SECTORS_PER_SEGMENT) * | ||
566 | (max_floppy_track + 1)); | ||
567 | /* This test will compensate for some bug reported by Dima | ||
568 | * Brodsky. Seems to be a Colorado bug, either. (freebee | ||
569 | * Imation tape shipped together with Colorado T3000 | ||
570 | */ | ||
571 | if ((ft_format_code == fmt_var || ft_format_code == fmt_big) && | ||
572 | ft_tracks_per_tape == 50 && | ||
573 | max_floppy_side == 54 && | ||
574 | max_floppy_track == 255 && | ||
575 | max_floppy_sector == 128) { | ||
576 | TRACE(ft_t_info, "the famous ??? bug: max_floppy_track off by one !"); | ||
577 | max_floppy_track = 254; | ||
578 | } | ||
579 | /* | ||
580 | * Verify drive_configuration with tape parameters | ||
581 | */ | ||
582 | if (ftape_segments_per_head == 0 || ftape_segments_per_cylinder == 0 || | ||
583 | ((ft_segments_per_track * ft_tracks_per_tape - 1) / ftape_segments_per_head | ||
584 | != max_floppy_side) || | ||
585 | (ftape_segments_per_head / ftape_segments_per_cylinder - 1 != max_floppy_track) || | ||
586 | (ftape_segments_per_cylinder * FT_SECTORS_PER_SEGMENT != max_floppy_sector) | ||
587 | #ifdef TESTING | ||
588 | || ((ft_format_code == fmt_var || ft_format_code == fmt_big) && | ||
589 | (max_floppy_track != 254 || max_floppy_sector != 128)) | ||
590 | #endif | ||
591 | ) { | ||
592 | char segperheadz = ftape_segments_per_head ? ' ' : '?'; | ||
593 | char segpercylz = ftape_segments_per_cylinder ? ' ' : '?'; | ||
594 | TRACE(ft_t_err,"Tape parameters inconsistency, please report"); | ||
595 | TRACE(ft_t_err, "reported = %d/%d/%d/%d/%d/%d", | ||
596 | ft_format_code, | ||
597 | ft_segments_per_track, | ||
598 | ft_tracks_per_tape, | ||
599 | max_floppy_side, | ||
600 | max_floppy_track, | ||
601 | max_floppy_sector); | ||
602 | TRACE(ft_t_err, "required = %d/%d/%d/%d%c/%d%c/%d", | ||
603 | ft_format_code, | ||
604 | ft_segments_per_track, | ||
605 | ft_tracks_per_tape, | ||
606 | ftape_segments_per_head ? | ||
607 | ((ft_segments_per_track * ft_tracks_per_tape -1) / | ||
608 | ftape_segments_per_head ) : | ||
609 | (ft_segments_per_track * ft_tracks_per_tape -1), | ||
610 | segperheadz, | ||
611 | ftape_segments_per_cylinder ? | ||
612 | (ftape_segments_per_head / | ||
613 | ftape_segments_per_cylinder - 1 ) : | ||
614 | ftape_segments_per_head - 1, | ||
615 | segpercylz, | ||
616 | (ftape_segments_per_cylinder * FT_SECTORS_PER_SEGMENT)); | ||
617 | TRACE_EXIT -EIO; | ||
618 | } | ||
619 | ftape_extract_bad_sector_map(address); | ||
620 | TRACE_EXIT 0; | ||
621 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-read.h b/drivers/char/ftape/lowlevel/ftape-read.h deleted file mode 100644 index 069f99f2a984..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-read.h +++ /dev/null | |||
@@ -1,51 +0,0 @@ | |||
1 | #ifndef _FTAPE_READ_H | ||
2 | #define _FTAPE_READ_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1994-1996 Bas Laarhoven, | ||
6 | * (C) 1996-1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-read.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:18:22 $ | ||
26 | * | ||
27 | * This file contains the definitions for the read functions | ||
28 | * for the QIC-117 floppy-tape driver for Linux. | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | /* ftape-read.c defined global functions. | ||
33 | */ | ||
34 | typedef enum { | ||
35 | FT_RD_SINGLE = 0, | ||
36 | FT_RD_AHEAD = 1, | ||
37 | } ft_read_mode_t; | ||
38 | |||
39 | extern int ftape_read_header_segment(__u8 *address); | ||
40 | extern int ftape_decode_header_segment(__u8 *address); | ||
41 | extern int ftape_read_segment_fraction(const int segment, | ||
42 | void *address, | ||
43 | const ft_read_mode_t read_mode, | ||
44 | const int start, | ||
45 | const int size); | ||
46 | #define ftape_read_segment(segment, address, read_mode) \ | ||
47 | ftape_read_segment_fraction(segment, address, read_mode, \ | ||
48 | 0, FT_SEGMENT_SIZE) | ||
49 | extern void ftape_zap_read_buffers(void); | ||
50 | |||
51 | #endif /* _FTAPE_READ_H */ | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-rw.c b/drivers/char/ftape/lowlevel/ftape-rw.c deleted file mode 100644 index c0d6dc2cbfd3..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-rw.c +++ /dev/null | |||
@@ -1,1092 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
3 | * (C) 1996-1997 Claus-Justus Heine. | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2, or (at your option) | ||
8 | any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; see the file COPYING. If not, write to | ||
17 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | |||
19 | * | ||
20 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-rw.c,v $ | ||
21 | * $Revision: 1.7 $ | ||
22 | * $Date: 1997/10/28 14:26:49 $ | ||
23 | * | ||
24 | * This file contains some common code for the segment read and | ||
25 | * segment write routines for the QIC-117 floppy-tape driver for | ||
26 | * Linux. | ||
27 | */ | ||
28 | |||
29 | #include <linux/string.h> | ||
30 | #include <linux/errno.h> | ||
31 | |||
32 | #include <linux/ftape.h> | ||
33 | #include <linux/qic117.h> | ||
34 | #include "../lowlevel/ftape-tracing.h" | ||
35 | #include "../lowlevel/ftape-rw.h" | ||
36 | #include "../lowlevel/fdc-io.h" | ||
37 | #include "../lowlevel/ftape-init.h" | ||
38 | #include "../lowlevel/ftape-io.h" | ||
39 | #include "../lowlevel/ftape-ctl.h" | ||
40 | #include "../lowlevel/ftape-read.h" | ||
41 | #include "../lowlevel/ftape-ecc.h" | ||
42 | #include "../lowlevel/ftape-bsm.h" | ||
43 | |||
44 | /* Global vars. | ||
45 | */ | ||
46 | int ft_nr_buffers; | ||
47 | buffer_struct *ft_buffer[FT_MAX_NR_BUFFERS]; | ||
48 | static volatile int ft_head; | ||
49 | static volatile int ft_tail; /* not volatile but need same type as head */ | ||
50 | int fdc_setup_error; | ||
51 | location_record ft_location = {-1, 0}; | ||
52 | volatile int ftape_tape_running; | ||
53 | |||
54 | /* Local vars. | ||
55 | */ | ||
56 | static int overrun_count_offset; | ||
57 | static int inhibit_correction; | ||
58 | |||
59 | /* maxmimal allowed overshoot when fast seeking | ||
60 | */ | ||
61 | #define OVERSHOOT_LIMIT 10 | ||
62 | |||
63 | /* Increment cyclic buffer nr. | ||
64 | */ | ||
65 | buffer_struct *ftape_next_buffer(ft_buffer_queue_t pos) | ||
66 | { | ||
67 | switch (pos) { | ||
68 | case ft_queue_head: | ||
69 | if (++ft_head >= ft_nr_buffers) { | ||
70 | ft_head = 0; | ||
71 | } | ||
72 | return ft_buffer[ft_head]; | ||
73 | case ft_queue_tail: | ||
74 | if (++ft_tail >= ft_nr_buffers) { | ||
75 | ft_tail = 0; | ||
76 | } | ||
77 | return ft_buffer[ft_tail]; | ||
78 | default: | ||
79 | return NULL; | ||
80 | } | ||
81 | } | ||
82 | int ftape_buffer_id(ft_buffer_queue_t pos) | ||
83 | { | ||
84 | switch(pos) { | ||
85 | case ft_queue_head: return ft_head; | ||
86 | case ft_queue_tail: return ft_tail; | ||
87 | default: return -1; | ||
88 | } | ||
89 | } | ||
90 | buffer_struct *ftape_get_buffer(ft_buffer_queue_t pos) | ||
91 | { | ||
92 | switch(pos) { | ||
93 | case ft_queue_head: return ft_buffer[ft_head]; | ||
94 | case ft_queue_tail: return ft_buffer[ft_tail]; | ||
95 | default: return NULL; | ||
96 | } | ||
97 | } | ||
98 | void ftape_reset_buffer(void) | ||
99 | { | ||
100 | ft_head = ft_tail = 0; | ||
101 | } | ||
102 | |||
103 | buffer_state_enum ftape_set_state(buffer_state_enum new_state) | ||
104 | { | ||
105 | buffer_state_enum old_state = ft_driver_state; | ||
106 | |||
107 | ft_driver_state = new_state; | ||
108 | return old_state; | ||
109 | } | ||
110 | /* Calculate Floppy Disk Controller and DMA parameters for a segment. | ||
111 | * head: selects buffer struct in array. | ||
112 | * offset: number of physical sectors to skip (including bad ones). | ||
113 | * count: number of physical sectors to handle (including bad ones). | ||
114 | */ | ||
115 | static int setup_segment(buffer_struct * buff, | ||
116 | int segment_id, | ||
117 | unsigned int sector_offset, | ||
118 | unsigned int sector_count, | ||
119 | int retry) | ||
120 | { | ||
121 | SectorMap offset_mask; | ||
122 | SectorMap mask; | ||
123 | TRACE_FUN(ft_t_any); | ||
124 | |||
125 | buff->segment_id = segment_id; | ||
126 | buff->sector_offset = sector_offset; | ||
127 | buff->remaining = sector_count; | ||
128 | buff->head = segment_id / ftape_segments_per_head; | ||
129 | buff->cyl = (segment_id % ftape_segments_per_head) / ftape_segments_per_cylinder; | ||
130 | buff->sect = (segment_id % ftape_segments_per_cylinder) * FT_SECTORS_PER_SEGMENT + 1; | ||
131 | buff->deleted = 0; | ||
132 | offset_mask = (1 << buff->sector_offset) - 1; | ||
133 | mask = ftape_get_bad_sector_entry(segment_id) & offset_mask; | ||
134 | while (mask) { | ||
135 | if (mask & 1) { | ||
136 | offset_mask >>= 1; /* don't count bad sector */ | ||
137 | } | ||
138 | mask >>= 1; | ||
139 | } | ||
140 | buff->data_offset = count_ones(offset_mask); /* good sectors to skip */ | ||
141 | buff->ptr = buff->address + buff->data_offset * FT_SECTOR_SIZE; | ||
142 | TRACE(ft_t_flow, "data offset = %d sectors", buff->data_offset); | ||
143 | if (retry) { | ||
144 | buff->soft_error_map &= offset_mask; /* keep skipped part */ | ||
145 | } else { | ||
146 | buff->hard_error_map = buff->soft_error_map = 0; | ||
147 | } | ||
148 | buff->bad_sector_map = ftape_get_bad_sector_entry(buff->segment_id); | ||
149 | if (buff->bad_sector_map != 0) { | ||
150 | TRACE(ft_t_noise, "segment: %d, bad sector map: %08lx", | ||
151 | buff->segment_id, (long)buff->bad_sector_map); | ||
152 | } else { | ||
153 | TRACE(ft_t_flow, "segment: %d", buff->segment_id); | ||
154 | } | ||
155 | if (buff->sector_offset > 0) { | ||
156 | buff->bad_sector_map >>= buff->sector_offset; | ||
157 | } | ||
158 | if (buff->sector_offset != 0 || buff->remaining != FT_SECTORS_PER_SEGMENT) { | ||
159 | TRACE(ft_t_flow, "sector offset = %d, count = %d", | ||
160 | buff->sector_offset, buff->remaining); | ||
161 | } | ||
162 | /* Segments with 3 or less sectors are not written with valid | ||
163 | * data because there is no space left for the ecc. The | ||
164 | * data written is whatever happens to be in the buffer. | ||
165 | * Reading such a segment will return a zero byte-count. | ||
166 | * To allow us to read/write segments with all bad sectors | ||
167 | * we fake one readable sector in the segment. This | ||
168 | * prevents having to handle these segments in a very | ||
169 | * special way. It is not important if the reading of this | ||
170 | * bad sector fails or not (the data is ignored). It is | ||
171 | * only read to keep the driver running. | ||
172 | * | ||
173 | * The QIC-40/80 spec. has no information on how to handle | ||
174 | * this case, so this is my interpretation. | ||
175 | */ | ||
176 | if (buff->bad_sector_map == EMPTY_SEGMENT) { | ||
177 | TRACE(ft_t_flow, "empty segment %d, fake first sector good", | ||
178 | buff->segment_id); | ||
179 | if (buff->ptr != buff->address) { | ||
180 | TRACE(ft_t_bug, "This is a bug: %p/%p", | ||
181 | buff->ptr, buff->address); | ||
182 | } | ||
183 | buff->bad_sector_map = FAKE_SEGMENT; | ||
184 | } | ||
185 | fdc_setup_error = 0; | ||
186 | buff->next_segment = segment_id + 1; | ||
187 | TRACE_EXIT 0; | ||
188 | } | ||
189 | |||
190 | /* Calculate Floppy Disk Controller and DMA parameters for a new segment. | ||
191 | */ | ||
192 | int ftape_setup_new_segment(buffer_struct * buff, int segment_id, int skip) | ||
193 | { | ||
194 | int result = 0; | ||
195 | static int old_segment_id = -1; | ||
196 | static buffer_state_enum old_ft_driver_state = idle; | ||
197 | int retry = 0; | ||
198 | unsigned offset = 0; | ||
199 | int count = FT_SECTORS_PER_SEGMENT; | ||
200 | TRACE_FUN(ft_t_flow); | ||
201 | |||
202 | TRACE(ft_t_flow, "%s segment %d (old = %d)", | ||
203 | (ft_driver_state == reading || ft_driver_state == verifying) | ||
204 | ? "reading" : "writing", | ||
205 | segment_id, old_segment_id); | ||
206 | if (ft_driver_state != old_ft_driver_state) { /* when verifying */ | ||
207 | old_segment_id = -1; | ||
208 | old_ft_driver_state = ft_driver_state; | ||
209 | } | ||
210 | if (segment_id == old_segment_id) { | ||
211 | ++buff->retry; | ||
212 | ++ft_history.retries; | ||
213 | TRACE(ft_t_flow, "setting up for retry nr %d", buff->retry); | ||
214 | retry = 1; | ||
215 | if (skip && buff->skip > 0) { /* allow skip on retry */ | ||
216 | offset = buff->skip; | ||
217 | count -= offset; | ||
218 | TRACE(ft_t_flow, "skipping %d sectors", offset); | ||
219 | } | ||
220 | } else { | ||
221 | buff->retry = 0; | ||
222 | buff->skip = 0; | ||
223 | old_segment_id = segment_id; | ||
224 | } | ||
225 | result = setup_segment(buff, segment_id, offset, count, retry); | ||
226 | TRACE_EXIT result; | ||
227 | } | ||
228 | |||
229 | /* Determine size of next cluster of good sectors. | ||
230 | */ | ||
231 | int ftape_calc_next_cluster(buffer_struct * buff) | ||
232 | { | ||
233 | /* Skip bad sectors. | ||
234 | */ | ||
235 | while (buff->remaining > 0 && (buff->bad_sector_map & 1) != 0) { | ||
236 | buff->bad_sector_map >>= 1; | ||
237 | ++buff->sector_offset; | ||
238 | --buff->remaining; | ||
239 | } | ||
240 | /* Find next cluster of good sectors | ||
241 | */ | ||
242 | if (buff->bad_sector_map == 0) { /* speed up */ | ||
243 | buff->sector_count = buff->remaining; | ||
244 | } else { | ||
245 | SectorMap map = buff->bad_sector_map; | ||
246 | |||
247 | buff->sector_count = 0; | ||
248 | while (buff->sector_count < buff->remaining && (map & 1) == 0) { | ||
249 | ++buff->sector_count; | ||
250 | map >>= 1; | ||
251 | } | ||
252 | } | ||
253 | return buff->sector_count; | ||
254 | } | ||
255 | |||
256 | /* if just passed the last segment on a track, wait for BOT | ||
257 | * or EOT mark. | ||
258 | */ | ||
259 | int ftape_handle_logical_eot(void) | ||
260 | { | ||
261 | TRACE_FUN(ft_t_flow); | ||
262 | |||
263 | if (ft_runner_status == logical_eot) { | ||
264 | int status; | ||
265 | |||
266 | TRACE(ft_t_noise, "tape at logical EOT"); | ||
267 | TRACE_CATCH(ftape_ready_wait(ftape_timeout.seek, &status),); | ||
268 | if ((status & (QIC_STATUS_AT_BOT | QIC_STATUS_AT_EOT)) == 0) { | ||
269 | TRACE_ABORT(-EIO, ft_t_err, "eot/bot not reached"); | ||
270 | } | ||
271 | ft_runner_status = end_of_tape; | ||
272 | } | ||
273 | if (ft_runner_status == end_of_tape) { | ||
274 | TRACE(ft_t_noise, "runner stopped because of logical EOT"); | ||
275 | ft_runner_status = idle; | ||
276 | } | ||
277 | TRACE_EXIT 0; | ||
278 | } | ||
279 | |||
280 | static int check_bot_eot(int status) | ||
281 | { | ||
282 | TRACE_FUN(ft_t_flow); | ||
283 | |||
284 | if (status & (QIC_STATUS_AT_BOT | QIC_STATUS_AT_EOT)) { | ||
285 | ft_location.bot = ((ft_location.track & 1) == 0 ? | ||
286 | (status & QIC_STATUS_AT_BOT) != 0: | ||
287 | (status & QIC_STATUS_AT_EOT) != 0); | ||
288 | ft_location.eot = !ft_location.bot; | ||
289 | ft_location.segment = (ft_location.track + | ||
290 | (ft_location.bot ? 0 : 1)) * ft_segments_per_track - 1; | ||
291 | ft_location.sector = -1; | ||
292 | ft_location.known = 1; | ||
293 | TRACE(ft_t_flow, "tape at logical %s", | ||
294 | ft_location.bot ? "bot" : "eot"); | ||
295 | TRACE(ft_t_flow, "segment = %d", ft_location.segment); | ||
296 | } else { | ||
297 | ft_location.known = 0; | ||
298 | } | ||
299 | TRACE_EXIT ft_location.known; | ||
300 | } | ||
301 | |||
302 | /* Read Id of first sector passing tape head. | ||
303 | */ | ||
304 | static int ftape_read_id(void) | ||
305 | { | ||
306 | int status; | ||
307 | __u8 out[2]; | ||
308 | TRACE_FUN(ft_t_any); | ||
309 | |||
310 | /* Assume tape is running on entry, be able to handle | ||
311 | * situation where it stopped or is stopping. | ||
312 | */ | ||
313 | ft_location.known = 0; /* default is location not known */ | ||
314 | out[0] = FDC_READID; | ||
315 | out[1] = ft_drive_sel; | ||
316 | TRACE_CATCH(fdc_command(out, 2),); | ||
317 | switch (fdc_interrupt_wait(20 * FT_SECOND)) { | ||
318 | case 0: | ||
319 | if (fdc_sect == 0) { | ||
320 | if (ftape_report_drive_status(&status) >= 0 && | ||
321 | (status & QIC_STATUS_READY)) { | ||
322 | ftape_tape_running = 0; | ||
323 | TRACE(ft_t_flow, "tape has stopped"); | ||
324 | check_bot_eot(status); | ||
325 | } | ||
326 | } else { | ||
327 | ft_location.known = 1; | ||
328 | ft_location.segment = (ftape_segments_per_head | ||
329 | * fdc_head | ||
330 | + ftape_segments_per_cylinder | ||
331 | * fdc_cyl | ||
332 | + (fdc_sect - 1) | ||
333 | / FT_SECTORS_PER_SEGMENT); | ||
334 | ft_location.sector = ((fdc_sect - 1) | ||
335 | % FT_SECTORS_PER_SEGMENT); | ||
336 | ft_location.eot = ft_location.bot = 0; | ||
337 | } | ||
338 | break; | ||
339 | case -ETIME: | ||
340 | /* Didn't find id on tape, must be near end: Wait | ||
341 | * until stopped. | ||
342 | */ | ||
343 | if (ftape_ready_wait(FT_FOREVER, &status) >= 0) { | ||
344 | ftape_tape_running = 0; | ||
345 | TRACE(ft_t_flow, "tape has stopped"); | ||
346 | check_bot_eot(status); | ||
347 | } | ||
348 | break; | ||
349 | default: | ||
350 | /* Interrupted or otherwise failing | ||
351 | * fdc_interrupt_wait() | ||
352 | */ | ||
353 | TRACE(ft_t_err, "fdc_interrupt_wait failed"); | ||
354 | break; | ||
355 | } | ||
356 | if (!ft_location.known) { | ||
357 | TRACE_ABORT(-EIO, ft_t_flow, "no id found"); | ||
358 | } | ||
359 | if (ft_location.sector == 0) { | ||
360 | TRACE(ft_t_flow, "passing segment %d/%d", | ||
361 | ft_location.segment, ft_location.sector); | ||
362 | } else { | ||
363 | TRACE(ft_t_fdc_dma, "passing segment %d/%d", | ||
364 | ft_location.segment, ft_location.sector); | ||
365 | } | ||
366 | TRACE_EXIT 0; | ||
367 | } | ||
368 | |||
369 | static int logical_forward(void) | ||
370 | { | ||
371 | ftape_tape_running = 1; | ||
372 | return ftape_command(QIC_LOGICAL_FORWARD); | ||
373 | } | ||
374 | |||
375 | int ftape_stop_tape(int *pstatus) | ||
376 | { | ||
377 | int retry = 0; | ||
378 | int result; | ||
379 | TRACE_FUN(ft_t_flow); | ||
380 | |||
381 | do { | ||
382 | result = ftape_command_wait(QIC_STOP_TAPE, | ||
383 | ftape_timeout.stop, pstatus); | ||
384 | if (result == 0) { | ||
385 | if ((*pstatus & QIC_STATUS_READY) == 0) { | ||
386 | result = -EIO; | ||
387 | } else { | ||
388 | ftape_tape_running = 0; | ||
389 | } | ||
390 | } | ||
391 | } while (result < 0 && ++retry <= 3); | ||
392 | if (result < 0) { | ||
393 | TRACE(ft_t_err, "failed ! (fatal)"); | ||
394 | } | ||
395 | TRACE_EXIT result; | ||
396 | } | ||
397 | |||
398 | int ftape_dumb_stop(void) | ||
399 | { | ||
400 | int result; | ||
401 | int status; | ||
402 | TRACE_FUN(ft_t_flow); | ||
403 | |||
404 | /* Abort current fdc operation if it's busy (probably read | ||
405 | * or write operation pending) with a reset. | ||
406 | */ | ||
407 | if (fdc_ready_wait(100 /* usec */) < 0) { | ||
408 | TRACE(ft_t_noise, "aborting fdc operation"); | ||
409 | fdc_reset(); | ||
410 | } | ||
411 | /* Reading id's after the last segment on a track may fail | ||
412 | * but eventually the drive will become ready (logical eot). | ||
413 | */ | ||
414 | result = ftape_report_drive_status(&status); | ||
415 | ft_location.known = 0; | ||
416 | do { | ||
417 | if (result == 0 && status & QIC_STATUS_READY) { | ||
418 | /* Tape is not running any more. | ||
419 | */ | ||
420 | TRACE(ft_t_noise, "tape already halted"); | ||
421 | check_bot_eot(status); | ||
422 | ftape_tape_running = 0; | ||
423 | } else if (ftape_tape_running) { | ||
424 | /* Tape is (was) still moving. | ||
425 | */ | ||
426 | #ifdef TESTING | ||
427 | ftape_read_id(); | ||
428 | #endif | ||
429 | result = ftape_stop_tape(&status); | ||
430 | } else { | ||
431 | /* Tape not yet ready but stopped. | ||
432 | */ | ||
433 | result = ftape_ready_wait(ftape_timeout.pause,&status); | ||
434 | } | ||
435 | } while (ftape_tape_running | ||
436 | && !(sigtestsetmask(¤t->pending.signal, _NEVER_BLOCK))); | ||
437 | #ifndef TESTING | ||
438 | ft_location.known = 0; | ||
439 | #endif | ||
440 | if (ft_runner_status == aborting || ft_runner_status == do_abort) { | ||
441 | ft_runner_status = idle; | ||
442 | } | ||
443 | TRACE_EXIT result; | ||
444 | } | ||
445 | |||
446 | /* Wait until runner has finished tail buffer. | ||
447 | * | ||
448 | */ | ||
449 | int ftape_wait_segment(buffer_state_enum state) | ||
450 | { | ||
451 | int status; | ||
452 | int result = 0; | ||
453 | TRACE_FUN(ft_t_flow); | ||
454 | |||
455 | while (ft_buffer[ft_tail]->status == state) { | ||
456 | TRACE(ft_t_flow, "state: %d", ft_buffer[ft_tail]->status); | ||
457 | /* First buffer still being worked on, wait up to timeout. | ||
458 | * | ||
459 | * Note: we check two times for being killed. 50 | ||
460 | * seconds are quite long. Note that | ||
461 | * fdc_interrupt_wait() is not killable by any | ||
462 | * means. ftape_read_segment() wants us to return | ||
463 | * -EINTR in case of a signal. | ||
464 | */ | ||
465 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
466 | result = fdc_interrupt_wait(50 * FT_SECOND); | ||
467 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
468 | if (result < 0) { | ||
469 | TRACE_ABORT(result, | ||
470 | ft_t_err, "fdc_interrupt_wait failed"); | ||
471 | } | ||
472 | if (fdc_setup_error) { | ||
473 | /* recover... FIXME */ | ||
474 | TRACE_ABORT(-EIO, ft_t_err, "setup error"); | ||
475 | } | ||
476 | } | ||
477 | if (ft_buffer[ft_tail]->status != error) { | ||
478 | TRACE_EXIT 0; | ||
479 | } | ||
480 | TRACE_CATCH(ftape_report_drive_status(&status),); | ||
481 | TRACE(ft_t_noise, "ftape_report_drive_status: 0x%02x", status); | ||
482 | if ((status & QIC_STATUS_READY) && | ||
483 | (status & QIC_STATUS_ERROR)) { | ||
484 | unsigned int error; | ||
485 | qic117_cmd_t command; | ||
486 | |||
487 | /* Report and clear error state. | ||
488 | * In case the drive can't operate at the selected | ||
489 | * rate, select the next lower data rate. | ||
490 | */ | ||
491 | ftape_report_error(&error, &command, 1); | ||
492 | if (error == 31 && command == QIC_LOGICAL_FORWARD) { | ||
493 | /* drive does not accept this data rate */ | ||
494 | if (ft_data_rate > 250) { | ||
495 | TRACE(ft_t_info, | ||
496 | "Probable data rate conflict"); | ||
497 | TRACE(ft_t_info, | ||
498 | "Lowering data rate to %d Kbps", | ||
499 | ft_data_rate / 2); | ||
500 | ftape_half_data_rate(); | ||
501 | if (ft_buffer[ft_tail]->retry > 0) { | ||
502 | /* give it a chance */ | ||
503 | --ft_buffer[ft_tail]->retry; | ||
504 | } | ||
505 | } else { | ||
506 | /* no rate is accepted... */ | ||
507 | TRACE(ft_t_err, "We're dead :("); | ||
508 | } | ||
509 | } else { | ||
510 | TRACE(ft_t_err, "Unknown error"); | ||
511 | } | ||
512 | TRACE_EXIT -EIO; /* g.p. error */ | ||
513 | } | ||
514 | TRACE_EXIT 0; | ||
515 | } | ||
516 | |||
517 | /* forward */ static int seek_forward(int segment_id, int fast); | ||
518 | |||
519 | static int fast_seek(int count, int reverse) | ||
520 | { | ||
521 | int result = 0; | ||
522 | int status; | ||
523 | TRACE_FUN(ft_t_flow); | ||
524 | |||
525 | if (count > 0) { | ||
526 | /* If positioned at begin or end of tape, fast seeking needs | ||
527 | * special treatment. | ||
528 | * Starting from logical bot needs a (slow) seek to the first | ||
529 | * segment before the high speed seek. Most drives do this | ||
530 | * automatically but some older don't, so we treat them | ||
531 | * all the same. | ||
532 | * Starting from logical eot is even more difficult because | ||
533 | * we cannot (slow) reverse seek to the last segment. | ||
534 | * TO BE IMPLEMENTED. | ||
535 | */ | ||
536 | inhibit_correction = 0; | ||
537 | if (ft_location.known && | ||
538 | ((ft_location.bot && !reverse) || | ||
539 | (ft_location.eot && reverse))) { | ||
540 | if (!reverse) { | ||
541 | /* (slow) skip to first segment on a track | ||
542 | */ | ||
543 | seek_forward(ft_location.track * ft_segments_per_track, 0); | ||
544 | --count; | ||
545 | } else { | ||
546 | /* When seeking backwards from | ||
547 | * end-of-tape the number of erased | ||
548 | * gaps found seems to be higher than | ||
549 | * expected. Therefor the drive must | ||
550 | * skip some more segments than | ||
551 | * calculated, but we don't know how | ||
552 | * many. Thus we will prevent the | ||
553 | * re-calculation of offset and | ||
554 | * overshoot when seeking backwards. | ||
555 | */ | ||
556 | inhibit_correction = 1; | ||
557 | count += 3; /* best guess */ | ||
558 | } | ||
559 | } | ||
560 | } else { | ||
561 | TRACE(ft_t_flow, "warning: zero or negative count: %d", count); | ||
562 | } | ||
563 | if (count > 0) { | ||
564 | int i; | ||
565 | int nibbles = count > 255 ? 3 : 2; | ||
566 | |||
567 | if (count > 4095) { | ||
568 | TRACE(ft_t_noise, "skipping clipped at 4095 segment"); | ||
569 | count = 4095; | ||
570 | } | ||
571 | /* Issue this tape command first. */ | ||
572 | if (!reverse) { | ||
573 | TRACE(ft_t_noise, "skipping %d segment(s)", count); | ||
574 | result = ftape_command(nibbles == 3 ? | ||
575 | QIC_SKIP_EXTENDED_FORWARD : QIC_SKIP_FORWARD); | ||
576 | } else { | ||
577 | TRACE(ft_t_noise, "backing up %d segment(s)", count); | ||
578 | result = ftape_command(nibbles == 3 ? | ||
579 | QIC_SKIP_EXTENDED_REVERSE : QIC_SKIP_REVERSE); | ||
580 | } | ||
581 | if (result < 0) { | ||
582 | TRACE(ft_t_noise, "Skip command failed"); | ||
583 | } else { | ||
584 | --count; /* 0 means one gap etc. */ | ||
585 | for (i = 0; i < nibbles; ++i) { | ||
586 | if (result >= 0) { | ||
587 | result = ftape_parameter(count & 15); | ||
588 | count /= 16; | ||
589 | } | ||
590 | } | ||
591 | result = ftape_ready_wait(ftape_timeout.rewind, &status); | ||
592 | if (result >= 0) { | ||
593 | ftape_tape_running = 0; | ||
594 | } | ||
595 | } | ||
596 | } | ||
597 | TRACE_EXIT result; | ||
598 | } | ||
599 | |||
600 | static int validate(int id) | ||
601 | { | ||
602 | /* Check to see if position found is off-track as reported | ||
603 | * once. Because all tracks in one direction lie next to | ||
604 | * each other, if off-track the error will be approximately | ||
605 | * 2 * ft_segments_per_track. | ||
606 | */ | ||
607 | if (ft_location.track == -1) { | ||
608 | return 1; /* unforseen situation, don't generate error */ | ||
609 | } else { | ||
610 | /* Use margin of ft_segments_per_track on both sides | ||
611 | * because ftape needs some margin and the error we're | ||
612 | * looking for is much larger ! | ||
613 | */ | ||
614 | int lo = (ft_location.track - 1) * ft_segments_per_track; | ||
615 | int hi = (ft_location.track + 2) * ft_segments_per_track; | ||
616 | |||
617 | return (id >= lo && id < hi); | ||
618 | } | ||
619 | } | ||
620 | |||
621 | static int seek_forward(int segment_id, int fast) | ||
622 | { | ||
623 | int failures = 0; | ||
624 | int count; | ||
625 | static int margin = 1; /* fixed: stop this before target */ | ||
626 | static int overshoot = 1; | ||
627 | static int min_count = 8; | ||
628 | int expected = -1; | ||
629 | int target = segment_id - margin; | ||
630 | int fast_seeking; | ||
631 | int prev_segment = ft_location.segment; | ||
632 | TRACE_FUN(ft_t_flow); | ||
633 | |||
634 | if (!ft_location.known) { | ||
635 | TRACE_ABORT(-EIO, ft_t_err, | ||
636 | "fatal: cannot seek from unknown location"); | ||
637 | } | ||
638 | if (!validate(segment_id)) { | ||
639 | ftape_sleep(1 * FT_SECOND); | ||
640 | ft_failure = 1; | ||
641 | TRACE_ABORT(-EIO, ft_t_err, | ||
642 | "fatal: head off track (bad hardware?)"); | ||
643 | } | ||
644 | TRACE(ft_t_noise, "from %d/%d to %d/0 - %d", | ||
645 | ft_location.segment, ft_location.sector,segment_id,margin); | ||
646 | count = target - ft_location.segment - overshoot; | ||
647 | fast_seeking = (fast && | ||
648 | count > (min_count + (ft_location.bot ? 1 : 0))); | ||
649 | if (fast_seeking) { | ||
650 | TRACE(ft_t_noise, "fast skipping %d segments", count); | ||
651 | expected = segment_id - margin; | ||
652 | fast_seek(count, 0); | ||
653 | } | ||
654 | if (!ftape_tape_running) { | ||
655 | logical_forward(); | ||
656 | } | ||
657 | while (ft_location.segment < segment_id) { | ||
658 | /* This requires at least one sector in a (bad) segment to | ||
659 | * have a valid and readable sector id ! | ||
660 | * It looks like this is not guaranteed, so we must try | ||
661 | * to find a way to skip an EMPTY_SEGMENT. !!! FIXME !!! | ||
662 | */ | ||
663 | if (ftape_read_id() < 0 || !ft_location.known || | ||
664 | sigtestsetmask(¤t->pending.signal, _DONT_BLOCK)) { | ||
665 | ft_location.known = 0; | ||
666 | if (!ftape_tape_running || | ||
667 | ++failures > FT_SECTORS_PER_SEGMENT) { | ||
668 | TRACE_ABORT(-EIO, ft_t_err, | ||
669 | "read_id failed completely"); | ||
670 | } | ||
671 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
672 | TRACE(ft_t_flow, "read_id failed, retry (%d)", | ||
673 | failures); | ||
674 | continue; | ||
675 | } | ||
676 | if (fast_seeking) { | ||
677 | TRACE(ft_t_noise, "ended at %d/%d (%d,%d)", | ||
678 | ft_location.segment, ft_location.sector, | ||
679 | overshoot, inhibit_correction); | ||
680 | if (!inhibit_correction && | ||
681 | (ft_location.segment < expected || | ||
682 | ft_location.segment > expected + margin)) { | ||
683 | int error = ft_location.segment - expected; | ||
684 | TRACE(ft_t_noise, | ||
685 | "adjusting overshoot from %d to %d", | ||
686 | overshoot, overshoot + error); | ||
687 | overshoot += error; | ||
688 | /* All overshoots have the same | ||
689 | * direction, so it should never | ||
690 | * become negative, but who knows. | ||
691 | */ | ||
692 | if (overshoot < -5 || | ||
693 | overshoot > OVERSHOOT_LIMIT) { | ||
694 | if (overshoot < 0) { | ||
695 | /* keep sane value */ | ||
696 | overshoot = -5; | ||
697 | } else { | ||
698 | /* keep sane value */ | ||
699 | overshoot = OVERSHOOT_LIMIT; | ||
700 | } | ||
701 | TRACE(ft_t_noise, | ||
702 | "clipped overshoot to %d", | ||
703 | overshoot); | ||
704 | } | ||
705 | } | ||
706 | fast_seeking = 0; | ||
707 | } | ||
708 | if (ft_location.known) { | ||
709 | if (ft_location.segment > prev_segment + 1) { | ||
710 | TRACE(ft_t_noise, | ||
711 | "missed segment %d while skipping", | ||
712 | prev_segment + 1); | ||
713 | } | ||
714 | prev_segment = ft_location.segment; | ||
715 | } | ||
716 | } | ||
717 | if (ft_location.segment > segment_id) { | ||
718 | TRACE_ABORT(-EIO, | ||
719 | ft_t_noise, "failed: skip ended at segment %d/%d", | ||
720 | ft_location.segment, ft_location.sector); | ||
721 | } | ||
722 | TRACE_EXIT 0; | ||
723 | } | ||
724 | |||
725 | static int skip_reverse(int segment_id, int *pstatus) | ||
726 | { | ||
727 | int failures = 0; | ||
728 | static int overshoot = 1; | ||
729 | static int min_rewind = 2; /* 1 + overshoot */ | ||
730 | static const int margin = 1; /* stop this before target */ | ||
731 | int expected = 0; | ||
732 | int count = 1; | ||
733 | int short_seek; | ||
734 | int target = segment_id - margin; | ||
735 | TRACE_FUN(ft_t_flow); | ||
736 | |||
737 | if (ft_location.known && !validate(segment_id)) { | ||
738 | ftape_sleep(1 * FT_SECOND); | ||
739 | ft_failure = 1; | ||
740 | TRACE_ABORT(-EIO, ft_t_err, | ||
741 | "fatal: head off track (bad hardware?)"); | ||
742 | } | ||
743 | do { | ||
744 | if (!ft_location.known) { | ||
745 | TRACE(ft_t_warn, "warning: location not known"); | ||
746 | } | ||
747 | TRACE(ft_t_noise, "from %d/%d to %d/0 - %d", | ||
748 | ft_location.segment, ft_location.sector, | ||
749 | segment_id, margin); | ||
750 | /* min_rewind == 1 + overshoot_when_doing_minimum_rewind | ||
751 | * overshoot == overshoot_when_doing_larger_rewind | ||
752 | * Initially min_rewind == 1 + overshoot, optimization | ||
753 | * of both values will be done separately. | ||
754 | * overshoot and min_rewind can be negative as both are | ||
755 | * sums of three components: | ||
756 | * any_overshoot == rewind_overshoot - | ||
757 | * stop_overshoot - | ||
758 | * start_overshoot | ||
759 | */ | ||
760 | if (ft_location.segment - target - (min_rewind - 1) < 1) { | ||
761 | short_seek = 1; | ||
762 | } else { | ||
763 | count = ft_location.segment - target - overshoot; | ||
764 | short_seek = (count < 1); | ||
765 | } | ||
766 | if (short_seek) { | ||
767 | count = 1; /* do shortest rewind */ | ||
768 | expected = ft_location.segment - min_rewind; | ||
769 | if (expected/ft_segments_per_track != ft_location.track) { | ||
770 | expected = (ft_location.track * | ||
771 | ft_segments_per_track); | ||
772 | } | ||
773 | } else { | ||
774 | expected = target; | ||
775 | } | ||
776 | fast_seek(count, 1); | ||
777 | logical_forward(); | ||
778 | if (ftape_read_id() < 0 || !ft_location.known || | ||
779 | (sigtestsetmask(¤t->pending.signal, _DONT_BLOCK))) { | ||
780 | if ((!ftape_tape_running && !ft_location.known) || | ||
781 | ++failures > FT_SECTORS_PER_SEGMENT) { | ||
782 | TRACE_ABORT(-EIO, ft_t_err, | ||
783 | "read_id failed completely"); | ||
784 | } | ||
785 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
786 | TRACE_CATCH(ftape_report_drive_status(pstatus),); | ||
787 | TRACE(ft_t_noise, "ftape_read_id failed, retry (%d)", | ||
788 | failures); | ||
789 | continue; | ||
790 | } | ||
791 | TRACE(ft_t_noise, "ended at %d/%d (%d,%d,%d)", | ||
792 | ft_location.segment, ft_location.sector, | ||
793 | min_rewind, overshoot, inhibit_correction); | ||
794 | if (!inhibit_correction && | ||
795 | (ft_location.segment < expected || | ||
796 | ft_location.segment > expected + margin)) { | ||
797 | int error = expected - ft_location.segment; | ||
798 | if (short_seek) { | ||
799 | TRACE(ft_t_noise, | ||
800 | "adjusting min_rewind from %d to %d", | ||
801 | min_rewind, min_rewind + error); | ||
802 | min_rewind += error; | ||
803 | if (min_rewind < -5) { | ||
804 | /* is this right ? FIXME ! */ | ||
805 | /* keep sane value */ | ||
806 | min_rewind = -5; | ||
807 | TRACE(ft_t_noise, | ||
808 | "clipped min_rewind to %d", | ||
809 | min_rewind); | ||
810 | } | ||
811 | } else { | ||
812 | TRACE(ft_t_noise, | ||
813 | "adjusting overshoot from %d to %d", | ||
814 | overshoot, overshoot + error); | ||
815 | overshoot += error; | ||
816 | if (overshoot < -5 || | ||
817 | overshoot > OVERSHOOT_LIMIT) { | ||
818 | if (overshoot < 0) { | ||
819 | /* keep sane value */ | ||
820 | overshoot = -5; | ||
821 | } else { | ||
822 | /* keep sane value */ | ||
823 | overshoot = OVERSHOOT_LIMIT; | ||
824 | } | ||
825 | TRACE(ft_t_noise, | ||
826 | "clipped overshoot to %d", | ||
827 | overshoot); | ||
828 | } | ||
829 | } | ||
830 | } | ||
831 | } while (ft_location.segment > segment_id); | ||
832 | if (ft_location.known) { | ||
833 | TRACE(ft_t_noise, "current location: %d/%d", | ||
834 | ft_location.segment, ft_location.sector); | ||
835 | } | ||
836 | TRACE_EXIT 0; | ||
837 | } | ||
838 | |||
839 | static int determine_position(void) | ||
840 | { | ||
841 | int retry = 0; | ||
842 | int status; | ||
843 | int result; | ||
844 | TRACE_FUN(ft_t_flow); | ||
845 | |||
846 | if (!ftape_tape_running) { | ||
847 | /* This should only happen if tape is stopped by isr. | ||
848 | */ | ||
849 | TRACE(ft_t_flow, "waiting for tape stop"); | ||
850 | if (ftape_ready_wait(ftape_timeout.pause, &status) < 0) { | ||
851 | TRACE(ft_t_flow, "drive still running (fatal)"); | ||
852 | ftape_tape_running = 1; /* ? */ | ||
853 | } | ||
854 | } else { | ||
855 | ftape_report_drive_status(&status); | ||
856 | } | ||
857 | if (status & QIC_STATUS_READY) { | ||
858 | /* Drive must be ready to check error state ! | ||
859 | */ | ||
860 | TRACE(ft_t_flow, "drive is ready"); | ||
861 | if (status & QIC_STATUS_ERROR) { | ||
862 | unsigned int error; | ||
863 | qic117_cmd_t command; | ||
864 | |||
865 | /* Report and clear error state, try to continue. | ||
866 | */ | ||
867 | TRACE(ft_t_flow, "error status set"); | ||
868 | ftape_report_error(&error, &command, 1); | ||
869 | ftape_ready_wait(ftape_timeout.reset, &status); | ||
870 | ftape_tape_running = 0; /* ? */ | ||
871 | } | ||
872 | if (check_bot_eot(status)) { | ||
873 | if (ft_location.bot) { | ||
874 | if ((status & QIC_STATUS_READY) == 0) { | ||
875 | /* tape moving away from | ||
876 | * bot/eot, let's see if we | ||
877 | * can catch up with the first | ||
878 | * segment on this track. | ||
879 | */ | ||
880 | } else { | ||
881 | TRACE(ft_t_flow, | ||
882 | "start tape from logical bot"); | ||
883 | logical_forward(); /* start moving */ | ||
884 | } | ||
885 | } else { | ||
886 | if ((status & QIC_STATUS_READY) == 0) { | ||
887 | TRACE(ft_t_noise, "waiting for logical end of track"); | ||
888 | result = ftape_ready_wait(ftape_timeout.reset, &status); | ||
889 | /* error handling needed ? */ | ||
890 | } else { | ||
891 | TRACE(ft_t_noise, | ||
892 | "tape at logical end of track"); | ||
893 | } | ||
894 | } | ||
895 | } else { | ||
896 | TRACE(ft_t_flow, "start tape"); | ||
897 | logical_forward(); /* start moving */ | ||
898 | ft_location.known = 0; /* not cleared by logical forward ! */ | ||
899 | } | ||
900 | } | ||
901 | /* tape should be moving now, start reading id's | ||
902 | */ | ||
903 | while (!ft_location.known && | ||
904 | retry++ < FT_SECTORS_PER_SEGMENT && | ||
905 | (result = ftape_read_id()) < 0) { | ||
906 | |||
907 | TRACE(ft_t_flow, "location unknown"); | ||
908 | |||
909 | /* exit on signal | ||
910 | */ | ||
911 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
912 | |||
913 | /* read-id somehow failed, tape may | ||
914 | * have reached end or some other | ||
915 | * error happened. | ||
916 | */ | ||
917 | TRACE(ft_t_flow, "read-id failed"); | ||
918 | TRACE_CATCH(ftape_report_drive_status(&status),); | ||
919 | TRACE(ft_t_err, "ftape_report_drive_status: 0x%02x", status); | ||
920 | if (status & QIC_STATUS_READY) { | ||
921 | ftape_tape_running = 0; | ||
922 | TRACE(ft_t_noise, "tape stopped for unknown reason! " | ||
923 | "status = 0x%02x", status); | ||
924 | if (status & QIC_STATUS_ERROR || | ||
925 | !check_bot_eot(status)) { | ||
926 | /* oops, tape stopped but not at end! | ||
927 | */ | ||
928 | TRACE_EXIT -EIO; | ||
929 | } | ||
930 | } | ||
931 | } | ||
932 | TRACE(ft_t_flow, | ||
933 | "tape is positioned at segment %d", ft_location.segment); | ||
934 | TRACE_EXIT ft_location.known ? 0 : -EIO; | ||
935 | } | ||
936 | |||
937 | /* Get the tape running and position it just before the | ||
938 | * requested segment. | ||
939 | * Seek tape-track and reposition as needed. | ||
940 | */ | ||
941 | int ftape_start_tape(int segment_id, int sector_offset) | ||
942 | { | ||
943 | int track = segment_id / ft_segments_per_track; | ||
944 | int result = -EIO; | ||
945 | int status; | ||
946 | static int last_segment = -1; | ||
947 | static int bad_bus_timing = 0; | ||
948 | /* number of segments passing the head between starting the tape | ||
949 | * and being able to access the first sector. | ||
950 | */ | ||
951 | static int start_offset = 1; | ||
952 | int retry; | ||
953 | TRACE_FUN(ft_t_flow); | ||
954 | |||
955 | /* If sector_offset > 0, seek into wanted segment instead of | ||
956 | * into previous. | ||
957 | * This allows error recovery if a part of the segment is bad | ||
958 | * (erased) causing the tape drive to generate an index pulse | ||
959 | * thus causing a no-data error before the requested sector | ||
960 | * is reached. | ||
961 | */ | ||
962 | ftape_tape_running = 0; | ||
963 | TRACE(ft_t_noise, "target segment: %d/%d%s", segment_id, sector_offset, | ||
964 | ft_buffer[ft_head]->retry > 0 ? " retry" : ""); | ||
965 | if (ft_buffer[ft_head]->retry > 0) { /* this is a retry */ | ||
966 | int dist = segment_id - last_segment; | ||
967 | |||
968 | if ((int)ft_history.overrun_errors < overrun_count_offset) { | ||
969 | overrun_count_offset = ft_history.overrun_errors; | ||
970 | } else if (dist < 0 || dist > 50) { | ||
971 | overrun_count_offset = ft_history.overrun_errors; | ||
972 | } else if ((ft_history.overrun_errors - | ||
973 | overrun_count_offset) >= 8) { | ||
974 | if (ftape_increase_threshold() >= 0) { | ||
975 | --ft_buffer[ft_head]->retry; | ||
976 | overrun_count_offset = | ||
977 | ft_history.overrun_errors; | ||
978 | TRACE(ft_t_warn, "increased threshold because " | ||
979 | "of excessive overrun errors"); | ||
980 | } else if (!bad_bus_timing && ft_data_rate >= 1000) { | ||
981 | ftape_half_data_rate(); | ||
982 | --ft_buffer[ft_head]->retry; | ||
983 | bad_bus_timing = 1; | ||
984 | overrun_count_offset = | ||
985 | ft_history.overrun_errors; | ||
986 | TRACE(ft_t_warn, "reduced datarate because " | ||
987 | "of excessive overrun errors"); | ||
988 | } | ||
989 | } | ||
990 | } | ||
991 | last_segment = segment_id; | ||
992 | if (ft_location.track != track || | ||
993 | (ftape_might_be_off_track && ft_buffer[ft_head]->retry== 0)) { | ||
994 | /* current track unknown or not equal to destination | ||
995 | */ | ||
996 | ftape_ready_wait(ftape_timeout.seek, &status); | ||
997 | ftape_seek_head_to_track(track); | ||
998 | /* overrun_count_offset = ft_history.overrun_errors; */ | ||
999 | } | ||
1000 | result = -EIO; | ||
1001 | retry = 0; | ||
1002 | while (result < 0 && | ||
1003 | retry++ <= 5 && | ||
1004 | !ft_failure && | ||
1005 | !(sigtestsetmask(¤t->pending.signal, _DONT_BLOCK))) { | ||
1006 | |||
1007 | if (retry && start_offset < 5) { | ||
1008 | start_offset ++; | ||
1009 | } | ||
1010 | /* Check if we are able to catch the requested | ||
1011 | * segment in time. | ||
1012 | */ | ||
1013 | if ((ft_location.known || (determine_position() == 0)) && | ||
1014 | ft_location.segment >= | ||
1015 | (segment_id - | ||
1016 | ((ftape_tape_running || ft_location.bot) | ||
1017 | ? 0 : start_offset))) { | ||
1018 | /* Too far ahead (in or past target segment). | ||
1019 | */ | ||
1020 | if (ftape_tape_running) { | ||
1021 | if ((result = ftape_stop_tape(&status)) < 0) { | ||
1022 | TRACE(ft_t_err, | ||
1023 | "stop tape failed with code %d", | ||
1024 | result); | ||
1025 | break; | ||
1026 | } | ||
1027 | TRACE(ft_t_noise, "tape stopped"); | ||
1028 | ftape_tape_running = 0; | ||
1029 | } | ||
1030 | TRACE(ft_t_noise, "repositioning"); | ||
1031 | ++ft_history.rewinds; | ||
1032 | if (segment_id % ft_segments_per_track < start_offset){ | ||
1033 | TRACE(ft_t_noise, "end of track condition\n" | ||
1034 | KERN_INFO "segment_id : %d\n" | ||
1035 | KERN_INFO "ft_segments_per_track: %d\n" | ||
1036 | KERN_INFO "start_offset : %d", | ||
1037 | segment_id, ft_segments_per_track, | ||
1038 | start_offset); | ||
1039 | |||
1040 | /* If seeking to first segments on | ||
1041 | * track better do a complete rewind | ||
1042 | * to logical begin of track to get a | ||
1043 | * more steady tape motion. | ||
1044 | */ | ||
1045 | result = ftape_command_wait( | ||
1046 | (ft_location.track & 1) | ||
1047 | ? QIC_PHYSICAL_FORWARD | ||
1048 | : QIC_PHYSICAL_REVERSE, | ||
1049 | ftape_timeout.rewind, &status); | ||
1050 | check_bot_eot(status); /* update location */ | ||
1051 | } else { | ||
1052 | result= skip_reverse(segment_id - start_offset, | ||
1053 | &status); | ||
1054 | } | ||
1055 | } | ||
1056 | if (!ft_location.known) { | ||
1057 | TRACE(ft_t_bug, "panic: location not known"); | ||
1058 | result = -EIO; | ||
1059 | continue; /* while() will check for failure */ | ||
1060 | } | ||
1061 | TRACE(ft_t_noise, "current segment: %d/%d", | ||
1062 | ft_location.segment, ft_location.sector); | ||
1063 | /* We're on the right track somewhere before the | ||
1064 | * wanted segment. Start tape movement if needed and | ||
1065 | * skip to just before or inside the requested | ||
1066 | * segment. Keep tape running. | ||
1067 | */ | ||
1068 | result = 0; | ||
1069 | if (ft_location.segment < | ||
1070 | (segment_id - ((ftape_tape_running || ft_location.bot) | ||
1071 | ? 0 : start_offset))) { | ||
1072 | if (sector_offset > 0) { | ||
1073 | result = seek_forward(segment_id, | ||
1074 | retry <= 3); | ||
1075 | } else { | ||
1076 | result = seek_forward(segment_id - 1, | ||
1077 | retry <= 3); | ||
1078 | } | ||
1079 | } | ||
1080 | if (result == 0 && | ||
1081 | ft_location.segment != | ||
1082 | (segment_id - (sector_offset > 0 ? 0 : 1))) { | ||
1083 | result = -EIO; | ||
1084 | } | ||
1085 | } | ||
1086 | if (result < 0) { | ||
1087 | TRACE(ft_t_err, "failed to reposition"); | ||
1088 | } else { | ||
1089 | ft_runner_status = running; | ||
1090 | } | ||
1091 | TRACE_EXIT result; | ||
1092 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-rw.h b/drivers/char/ftape/lowlevel/ftape-rw.h deleted file mode 100644 index 32f4feeb887c..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-rw.h +++ /dev/null | |||
@@ -1,111 +0,0 @@ | |||
1 | #ifndef _FTAPE_RW_H | ||
2 | #define _FTAPE_RW_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
6 | * (C) 1996-1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-rw.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:18:25 $ | ||
26 | * | ||
27 | * This file contains the definitions for the read and write | ||
28 | * functions for the QIC-117 floppy-tape driver for Linux. | ||
29 | * | ||
30 | * Claus-Justus Heine (1996/09/20): Add definition of format code 6 | ||
31 | * Claus-Justus Heine (1996/10/04): Changed GET/PUT macros to cast to (__u8 *) | ||
32 | * | ||
33 | */ | ||
34 | |||
35 | #include "../lowlevel/fdc-io.h" | ||
36 | #include "../lowlevel/ftape-init.h" | ||
37 | #include "../lowlevel/ftape-bsm.h" | ||
38 | |||
39 | #include <asm/unaligned.h> | ||
40 | |||
41 | #define GET2(address, offset) get_unaligned((__u16*)((__u8 *)address + offset)) | ||
42 | #define GET4(address, offset) get_unaligned((__u32*)((__u8 *)address + offset)) | ||
43 | #define GET8(address, offset) get_unaligned((__u64*)((__u8 *)address + offset)) | ||
44 | #define PUT2(address, offset , value) put_unaligned((value), (__u16*)((__u8 *)address + offset)) | ||
45 | #define PUT4(address, offset , value) put_unaligned((value), (__u32*)((__u8 *)address + offset)) | ||
46 | #define PUT8(address, offset , value) put_unaligned((value), (__u64*)((__u8 *)address + offset)) | ||
47 | |||
48 | enum runner_status_enum { | ||
49 | idle = 0, | ||
50 | running, | ||
51 | do_abort, | ||
52 | aborting, | ||
53 | logical_eot, | ||
54 | end_of_tape, | ||
55 | }; | ||
56 | |||
57 | typedef enum ft_buffer_queue { | ||
58 | ft_queue_head = 0, | ||
59 | ft_queue_tail = 1 | ||
60 | } ft_buffer_queue_t; | ||
61 | |||
62 | |||
63 | typedef struct { | ||
64 | int track; /* tape head position */ | ||
65 | volatile int segment; /* current segment */ | ||
66 | volatile int sector; /* sector offset within current segment */ | ||
67 | volatile unsigned int bot; /* logical begin of track */ | ||
68 | volatile unsigned int eot; /* logical end of track */ | ||
69 | volatile unsigned int known; /* validates bot, segment, sector */ | ||
70 | } location_record; | ||
71 | |||
72 | /* Count nr of 1's in pattern. | ||
73 | */ | ||
74 | static inline int count_ones(unsigned long mask) | ||
75 | { | ||
76 | int bits; | ||
77 | |||
78 | for (bits = 0; mask != 0; mask >>= 1) { | ||
79 | if (mask & 1) { | ||
80 | ++bits; | ||
81 | } | ||
82 | } | ||
83 | return bits; | ||
84 | } | ||
85 | |||
86 | #define FT_MAX_NR_BUFFERS 16 /* arbitrary value */ | ||
87 | /* ftape-rw.c defined global vars. | ||
88 | */ | ||
89 | extern buffer_struct *ft_buffer[FT_MAX_NR_BUFFERS]; | ||
90 | extern int ft_nr_buffers; | ||
91 | extern location_record ft_location; | ||
92 | extern volatile int ftape_tape_running; | ||
93 | |||
94 | /* ftape-rw.c defined global functions. | ||
95 | */ | ||
96 | extern int ftape_setup_new_segment(buffer_struct * buff, | ||
97 | int segment_id, | ||
98 | int offset); | ||
99 | extern int ftape_calc_next_cluster(buffer_struct * buff); | ||
100 | extern buffer_struct *ftape_next_buffer (ft_buffer_queue_t pos); | ||
101 | extern buffer_struct *ftape_get_buffer (ft_buffer_queue_t pos); | ||
102 | extern int ftape_buffer_id (ft_buffer_queue_t pos); | ||
103 | extern void ftape_reset_buffer(void); | ||
104 | extern void ftape_tape_parameters(__u8 drive_configuration); | ||
105 | extern int ftape_wait_segment(buffer_state_enum state); | ||
106 | extern int ftape_dumb_stop(void); | ||
107 | extern int ftape_start_tape(int segment_id, int offset); | ||
108 | extern int ftape_stop_tape(int *pstatus); | ||
109 | extern int ftape_handle_logical_eot(void); | ||
110 | extern buffer_state_enum ftape_set_state(buffer_state_enum new_state); | ||
111 | #endif /* _FTAPE_RW_H */ | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-setup.c b/drivers/char/ftape/lowlevel/ftape-setup.c deleted file mode 100644 index 678340acd0b7..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-setup.c +++ /dev/null | |||
@@ -1,104 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1996, 1997 Claus-Justus Heine. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; see the file COPYING. If not, write to | ||
16 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | |||
18 | * | ||
19 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-setup.c,v $ | ||
20 | * $Revision: 1.7 $ | ||
21 | * $Date: 1997/10/10 09:57:06 $ | ||
22 | * | ||
23 | * This file contains the code for processing the kernel command | ||
24 | * line options for the QIC-40/80/3010/3020 floppy-tape driver | ||
25 | * "ftape" for Linux. | ||
26 | */ | ||
27 | |||
28 | #include <linux/string.h> | ||
29 | #include <linux/errno.h> | ||
30 | #include <linux/mm.h> | ||
31 | |||
32 | #include <linux/ftape.h> | ||
33 | #include <linux/init.h> | ||
34 | #include "../lowlevel/ftape-tracing.h" | ||
35 | #include "../lowlevel/fdc-io.h" | ||
36 | |||
37 | static struct param_table { | ||
38 | const char *name; | ||
39 | int *var; | ||
40 | int def_param; | ||
41 | int min; | ||
42 | int max; | ||
43 | } config_params[] __initdata = { | ||
44 | #ifndef CONFIG_FT_NO_TRACE_AT_ALL | ||
45 | { "tracing", &ftape_tracing, 3, ft_t_bug, ft_t_any}, | ||
46 | #endif | ||
47 | { "ioport", &ft_fdc_base, CONFIG_FT_FDC_BASE, 0x0, 0xfff}, | ||
48 | { "irq", &ft_fdc_irq, CONFIG_FT_FDC_IRQ, 2, 15}, | ||
49 | { "dma", &ft_fdc_dma, CONFIG_FT_FDC_DMA, 0, 3}, | ||
50 | { "threshold", &ft_fdc_threshold, CONFIG_FT_FDC_THR, 1, 16}, | ||
51 | { "datarate", &ft_fdc_rate_limit, CONFIG_FT_FDC_MAX_RATE, 500, 2000}, | ||
52 | { "fc10", &ft_probe_fc10, CONFIG_FT_PROBE_FC10, 0, 1}, | ||
53 | { "mach2", &ft_mach2, CONFIG_FT_MACH2, 0, 1} | ||
54 | }; | ||
55 | |||
56 | static int __init ftape_setup(char *str) | ||
57 | { | ||
58 | int i; | ||
59 | int param; | ||
60 | int ints[2]; | ||
61 | |||
62 | TRACE_FUN(ft_t_flow); | ||
63 | |||
64 | str = get_options(str, ARRAY_SIZE(ints), ints); | ||
65 | if (str) { | ||
66 | for (i=0; i < NR_ITEMS(config_params); i++) { | ||
67 | if (strcmp(str,config_params[i].name) == 0){ | ||
68 | if (ints[0]) { | ||
69 | param = ints[1]; | ||
70 | } else { | ||
71 | param = config_params[i].def_param; | ||
72 | } | ||
73 | if (param < config_params[i].min || | ||
74 | param > config_params[i].max) { | ||
75 | TRACE(ft_t_err, | ||
76 | "parameter %s out of range %d ... %d", | ||
77 | config_params[i].name, | ||
78 | config_params[i].min, | ||
79 | config_params[i].max); | ||
80 | goto out; | ||
81 | } | ||
82 | if(config_params[i].var) { | ||
83 | TRACE(ft_t_info, "%s=%d", str, param); | ||
84 | *config_params[i].var = param; | ||
85 | } | ||
86 | goto out; | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | if (str) { | ||
91 | TRACE(ft_t_err, "unknown ftape option [%s]", str); | ||
92 | |||
93 | TRACE(ft_t_err, "allowed options are:"); | ||
94 | for (i=0; i < NR_ITEMS(config_params); i++) { | ||
95 | TRACE(ft_t_err, " %s",config_params[i].name); | ||
96 | } | ||
97 | } else { | ||
98 | TRACE(ft_t_err, "botched ftape option"); | ||
99 | } | ||
100 | out: | ||
101 | TRACE_EXIT 1; | ||
102 | } | ||
103 | |||
104 | __setup("ftape=", ftape_setup); | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-tracing.c b/drivers/char/ftape/lowlevel/ftape-tracing.c deleted file mode 100644 index 7fdc6567440b..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-tracing.c +++ /dev/null | |||
@@ -1,118 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1993-1996 Bas Laarhoven, | ||
3 | * (C) 1996-1997 Claus-Justus Heine. | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2, or (at your option) | ||
8 | any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; see the file COPYING. If not, write to | ||
17 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | |||
19 | * | ||
20 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-tracing.c,v $ | ||
21 | * $Revision: 1.2 $ | ||
22 | * $Date: 1997/10/05 19:18:27 $ | ||
23 | * | ||
24 | * This file contains the reading code | ||
25 | * for the QIC-117 floppy-tape driver for Linux. | ||
26 | */ | ||
27 | |||
28 | #include <linux/ftape.h> | ||
29 | #include "../lowlevel/ftape-tracing.h" | ||
30 | |||
31 | /* Global vars. | ||
32 | */ | ||
33 | /* tracing | ||
34 | * set it to: to log : | ||
35 | * 0 bugs | ||
36 | * 1 + errors | ||
37 | * 2 + warnings | ||
38 | * 3 + information | ||
39 | * 4 + more information | ||
40 | * 5 + program flow | ||
41 | * 6 + fdc/dma info | ||
42 | * 7 + data flow | ||
43 | * 8 + everything else | ||
44 | */ | ||
45 | ft_trace_t ftape_tracing = ft_t_info; /* Default level: information and up */ | ||
46 | int ftape_function_nest_level; | ||
47 | |||
48 | /* Local vars. | ||
49 | */ | ||
50 | static __u8 trace_id; | ||
51 | static char spacing[] = "* "; | ||
52 | |||
53 | void ftape_trace_call(const char *file, const char *name) | ||
54 | { | ||
55 | char *indent; | ||
56 | |||
57 | /* Since printk seems not to work with "%*s" format | ||
58 | * we'll use this work-around. | ||
59 | */ | ||
60 | if (ftape_function_nest_level < 0) { | ||
61 | printk(KERN_INFO "function nest level (%d) < 0\n", | ||
62 | ftape_function_nest_level); | ||
63 | ftape_function_nest_level = 0; | ||
64 | } | ||
65 | if (ftape_function_nest_level < sizeof(spacing)) { | ||
66 | indent = (spacing + | ||
67 | sizeof(spacing) - 1 - | ||
68 | ftape_function_nest_level); | ||
69 | } else { | ||
70 | indent = spacing; | ||
71 | } | ||
72 | printk(KERN_INFO "[%03d]%s+%s (%s)\n", | ||
73 | (int) trace_id++, indent, file, name); | ||
74 | } | ||
75 | |||
76 | void ftape_trace_exit(const char *file, const char *name) | ||
77 | { | ||
78 | char *indent; | ||
79 | |||
80 | /* Since printk seems not to work with "%*s" format | ||
81 | * we'll use this work-around. | ||
82 | */ | ||
83 | if (ftape_function_nest_level < 0) { | ||
84 | printk(KERN_INFO "function nest level (%d) < 0\n", ftape_function_nest_level); | ||
85 | ftape_function_nest_level = 0; | ||
86 | } | ||
87 | if (ftape_function_nest_level < sizeof(spacing)) { | ||
88 | indent = (spacing + | ||
89 | sizeof(spacing) - 1 - | ||
90 | ftape_function_nest_level); | ||
91 | } else { | ||
92 | indent = spacing; | ||
93 | } | ||
94 | printk(KERN_INFO "[%03d]%s-%s (%s)\n", | ||
95 | (int) trace_id++, indent, file, name); | ||
96 | } | ||
97 | |||
98 | void ftape_trace_log(const char *file, const char *function) | ||
99 | { | ||
100 | char *indent; | ||
101 | |||
102 | /* Since printk seems not to work with "%*s" format | ||
103 | * we'll use this work-around. | ||
104 | */ | ||
105 | if (ftape_function_nest_level < 0) { | ||
106 | printk(KERN_INFO "function nest level (%d) < 0\n", ftape_function_nest_level); | ||
107 | ftape_function_nest_level = 0; | ||
108 | } | ||
109 | if (ftape_function_nest_level < sizeof(spacing)) { | ||
110 | indent = (spacing + | ||
111 | sizeof(spacing) - 1 - | ||
112 | ftape_function_nest_level); | ||
113 | } else { | ||
114 | indent = spacing; | ||
115 | } | ||
116 | printk(KERN_INFO "[%03d]%s%s (%s) - ", | ||
117 | (int) trace_id++, indent, file, function); | ||
118 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-tracing.h b/drivers/char/ftape/lowlevel/ftape-tracing.h deleted file mode 100644 index 2950810c7085..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-tracing.h +++ /dev/null | |||
@@ -1,179 +0,0 @@ | |||
1 | #ifndef _FTAPE_TRACING_H | ||
2 | #define _FTAPE_TRACING_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1994-1996 Bas Laarhoven, | ||
6 | * (C) 1996-1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-tracing.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:18:28 $ | ||
26 | * | ||
27 | * This file contains definitions that eases the debugging of the | ||
28 | * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux. | ||
29 | */ | ||
30 | |||
31 | #include <linux/kernel.h> | ||
32 | |||
33 | /* | ||
34 | * Be very careful with TRACE_EXIT and TRACE_ABORT. | ||
35 | * | ||
36 | * if (something) TRACE_EXIT error; | ||
37 | * | ||
38 | * will NOT work. Use | ||
39 | * | ||
40 | * if (something) { | ||
41 | * TRACE_EXIT error; | ||
42 | * } | ||
43 | * | ||
44 | * instead. Maybe a bit dangerous, but save lots of lines of code. | ||
45 | */ | ||
46 | |||
47 | #define LL_X "%d/%d KB" | ||
48 | #define LL(x) (unsigned int)((__u64)(x)>>10), (unsigned int)((x)&1023) | ||
49 | |||
50 | typedef enum { | ||
51 | ft_t_nil = -1, | ||
52 | ft_t_bug, | ||
53 | ft_t_err, | ||
54 | ft_t_warn, | ||
55 | ft_t_info, | ||
56 | ft_t_noise, | ||
57 | ft_t_flow, | ||
58 | ft_t_fdc_dma, | ||
59 | ft_t_data_flow, | ||
60 | ft_t_any | ||
61 | } ft_trace_t; | ||
62 | |||
63 | #ifdef CONFIG_FT_NO_TRACE_AT_ALL | ||
64 | /* the compiler will optimize away most TRACE() macros | ||
65 | */ | ||
66 | #define FT_TRACE_TOP_LEVEL ft_t_bug | ||
67 | #define TRACE_FUN(level) do {} while(0) | ||
68 | #define TRACE_EXIT return | ||
69 | #define TRACE(l, m, i...) \ | ||
70 | { \ | ||
71 | if ((ft_trace_t)(l) == FT_TRACE_TOP_LEVEL) { \ | ||
72 | printk(KERN_INFO"ftape%s(%s):\n" \ | ||
73 | KERN_INFO m".\n" ,__FILE__, __FUNCTION__ , ##i); \ | ||
74 | } \ | ||
75 | } | ||
76 | #define SET_TRACE_LEVEL(l) if ((l) == (l)) do {} while(0) | ||
77 | #define TRACE_LEVEL FT_TRACE_TOP_LEVEL | ||
78 | |||
79 | #else | ||
80 | |||
81 | #ifdef CONFIG_FT_NO_TRACE | ||
82 | /* the compiler will optimize away many TRACE() macros | ||
83 | * the ftape_simple_trace_call() function simply increments | ||
84 | * the function nest level. | ||
85 | */ | ||
86 | #define FT_TRACE_TOP_LEVEL ft_t_warn | ||
87 | #define TRACE_FUN(level) ftape_function_nest_level++ | ||
88 | #define TRACE_EXIT ftape_function_nest_level--; return | ||
89 | |||
90 | #else | ||
91 | #ifdef CONFIG_FT_FULL_DEBUG | ||
92 | #define FT_TRACE_TOP_LEVEL ft_t_any | ||
93 | #else | ||
94 | #define FT_TRACE_TOP_LEVEL ft_t_flow | ||
95 | #endif | ||
96 | #define TRACE_FUN(level) \ | ||
97 | const ft_trace_t _tracing = level; \ | ||
98 | if (ftape_tracing >= (ft_trace_t)(level) && \ | ||
99 | (ft_trace_t)(level) <= FT_TRACE_TOP_LEVEL) \ | ||
100 | ftape_trace_call(__FILE__, __FUNCTION__); \ | ||
101 | ftape_function_nest_level ++; | ||
102 | |||
103 | #define TRACE_EXIT \ | ||
104 | --ftape_function_nest_level; \ | ||
105 | if (ftape_tracing >= (ft_trace_t)(_tracing) && \ | ||
106 | (ft_trace_t)(_tracing) <= FT_TRACE_TOP_LEVEL) \ | ||
107 | ftape_trace_exit(__FILE__, __FUNCTION__); \ | ||
108 | return | ||
109 | |||
110 | #endif | ||
111 | |||
112 | #define TRACE(l, m, i...) \ | ||
113 | { \ | ||
114 | if (ftape_tracing >= (ft_trace_t)(l) && \ | ||
115 | (ft_trace_t)(l) <= FT_TRACE_TOP_LEVEL) { \ | ||
116 | ftape_trace_log(__FILE__, __FUNCTION__); \ | ||
117 | printk(m".\n" ,##i); \ | ||
118 | } \ | ||
119 | } | ||
120 | |||
121 | #define SET_TRACE_LEVEL(l) \ | ||
122 | { \ | ||
123 | if ((ft_trace_t)(l) <= FT_TRACE_TOP_LEVEL) { \ | ||
124 | ftape_tracing = (ft_trace_t)(l); \ | ||
125 | } else { \ | ||
126 | ftape_tracing = FT_TRACE_TOP_LEVEL; \ | ||
127 | } \ | ||
128 | } | ||
129 | #define TRACE_LEVEL \ | ||
130 | ((ftape_tracing <= FT_TRACE_TOP_LEVEL) ? ftape_tracing : FT_TRACE_TOP_LEVEL) | ||
131 | |||
132 | |||
133 | /* Global variables declared in tracing.c | ||
134 | */ | ||
135 | extern ft_trace_t ftape_tracing; /* sets default level */ | ||
136 | extern int ftape_function_nest_level; | ||
137 | |||
138 | /* Global functions declared in tracing.c | ||
139 | */ | ||
140 | extern void ftape_trace_call(const char *file, const char *name); | ||
141 | extern void ftape_trace_exit(const char *file, const char *name); | ||
142 | extern void ftape_trace_log (const char *file, const char *name); | ||
143 | |||
144 | #endif /* !defined(CONFIG_FT_NO_TRACE_AT_ALL) */ | ||
145 | |||
146 | /* | ||
147 | * Abort with a message. | ||
148 | */ | ||
149 | #define TRACE_ABORT(res, i...) \ | ||
150 | { \ | ||
151 | TRACE(i); \ | ||
152 | TRACE_EXIT res; \ | ||
153 | } | ||
154 | |||
155 | /* The following transforms the common "if(result < 0) ... " into a | ||
156 | * one-liner. | ||
157 | */ | ||
158 | #define _TRACE_CATCH(level, fun, action) \ | ||
159 | { \ | ||
160 | int _res = (fun); \ | ||
161 | if (_res < 0) { \ | ||
162 | do { action /* */ ; } while(0); \ | ||
163 | TRACE_ABORT(_res, level, "%s failed: %d", #fun, _res); \ | ||
164 | } \ | ||
165 | } | ||
166 | |||
167 | #define TRACE_CATCH(fun, fail) _TRACE_CATCH(ft_t_err, fun, fail) | ||
168 | |||
169 | /* Abort the current function when signalled. This doesn't belong here, | ||
170 | * but rather into ftape-rw.h (maybe) | ||
171 | */ | ||
172 | #define FT_SIGNAL_EXIT(sig_mask) \ | ||
173 | if (sigtestsetmask(¤t->pending.signal, sig_mask)) { \ | ||
174 | TRACE_ABORT(-EINTR, \ | ||
175 | ft_t_warn, \ | ||
176 | "interrupted by non-blockable signal"); \ | ||
177 | } | ||
178 | |||
179 | #endif /* _FTAPE_TRACING_H */ | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-write.c b/drivers/char/ftape/lowlevel/ftape-write.c deleted file mode 100644 index 45601ec801ee..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-write.c +++ /dev/null | |||
@@ -1,336 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1993-1995 Bas Laarhoven, | ||
3 | * (C) 1996-1997 Claus-Justus Heine. | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2, or (at your option) | ||
8 | any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; see the file COPYING. If not, write to | ||
17 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | |||
19 | * | ||
20 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-write.c,v $ | ||
21 | * $Revision: 1.3.4.1 $ | ||
22 | * $Date: 1997/11/14 18:07:04 $ | ||
23 | * | ||
24 | * This file contains the writing code | ||
25 | * for the QIC-117 floppy-tape driver for Linux. | ||
26 | */ | ||
27 | |||
28 | #include <linux/string.h> | ||
29 | #include <linux/errno.h> | ||
30 | #include <linux/mm.h> | ||
31 | |||
32 | #include <linux/ftape.h> | ||
33 | #include <linux/qic117.h> | ||
34 | #include "../lowlevel/ftape-tracing.h" | ||
35 | #include "../lowlevel/ftape-write.h" | ||
36 | #include "../lowlevel/ftape-read.h" | ||
37 | #include "../lowlevel/ftape-io.h" | ||
38 | #include "../lowlevel/ftape-ctl.h" | ||
39 | #include "../lowlevel/ftape-rw.h" | ||
40 | #include "../lowlevel/ftape-ecc.h" | ||
41 | #include "../lowlevel/ftape-bsm.h" | ||
42 | #include "../lowlevel/fdc-isr.h" | ||
43 | |||
44 | /* Global vars. | ||
45 | */ | ||
46 | |||
47 | /* Local vars. | ||
48 | */ | ||
49 | static int last_write_failed; | ||
50 | |||
51 | void ftape_zap_write_buffers(void) | ||
52 | { | ||
53 | int i; | ||
54 | |||
55 | for (i = 0; i < ft_nr_buffers; ++i) { | ||
56 | ft_buffer[i]->status = done; | ||
57 | } | ||
58 | ftape_reset_buffer(); | ||
59 | } | ||
60 | |||
61 | static int copy_and_gen_ecc(void *destination, | ||
62 | const void *source, | ||
63 | const SectorMap bad_sector_map) | ||
64 | { | ||
65 | int result; | ||
66 | struct memory_segment mseg; | ||
67 | int bads = count_ones(bad_sector_map); | ||
68 | TRACE_FUN(ft_t_any); | ||
69 | |||
70 | if (bads > 0) { | ||
71 | TRACE(ft_t_noise, "bad sectors in map: %d", bads); | ||
72 | } | ||
73 | if (bads + 3 >= FT_SECTORS_PER_SEGMENT) { | ||
74 | TRACE(ft_t_noise, "empty segment"); | ||
75 | mseg.blocks = 0; /* skip entire segment */ | ||
76 | result = 0; /* nothing written */ | ||
77 | } else { | ||
78 | mseg.blocks = FT_SECTORS_PER_SEGMENT - bads; | ||
79 | mseg.data = destination; | ||
80 | memcpy(mseg.data, source, (mseg.blocks - 3) * FT_SECTOR_SIZE); | ||
81 | result = ftape_ecc_set_segment_parity(&mseg); | ||
82 | if (result < 0) { | ||
83 | TRACE(ft_t_err, "ecc_set_segment_parity failed"); | ||
84 | } else { | ||
85 | result = (mseg.blocks - 3) * FT_SECTOR_SIZE; | ||
86 | } | ||
87 | } | ||
88 | TRACE_EXIT result; | ||
89 | } | ||
90 | |||
91 | |||
92 | int ftape_start_writing(const ft_write_mode_t mode) | ||
93 | { | ||
94 | buffer_struct *head = ftape_get_buffer(ft_queue_head); | ||
95 | int segment_id = head->segment_id; | ||
96 | int result; | ||
97 | buffer_state_enum wanted_state = (mode == FT_WR_DELETE | ||
98 | ? deleting | ||
99 | : writing); | ||
100 | TRACE_FUN(ft_t_flow); | ||
101 | |||
102 | if ((ft_driver_state != wanted_state) || head->status != waiting) { | ||
103 | TRACE_EXIT 0; | ||
104 | } | ||
105 | ftape_setup_new_segment(head, segment_id, 1); | ||
106 | if (mode == FT_WR_SINGLE) { | ||
107 | /* stop tape instead of pause */ | ||
108 | head->next_segment = 0; | ||
109 | } | ||
110 | ftape_calc_next_cluster(head); /* prepare */ | ||
111 | head->status = ft_driver_state; /* either writing or deleting */ | ||
112 | if (ft_runner_status == idle) { | ||
113 | TRACE(ft_t_noise, | ||
114 | "starting runner for segment %d", segment_id); | ||
115 | TRACE_CATCH(ftape_start_tape(segment_id,head->sector_offset),); | ||
116 | } else { | ||
117 | TRACE(ft_t_noise, "runner not idle, not starting tape"); | ||
118 | } | ||
119 | /* go */ | ||
120 | result = fdc_setup_read_write(head, (mode == FT_WR_DELETE | ||
121 | ? FDC_WRITE_DELETED : FDC_WRITE)); | ||
122 | ftape_set_state(wanted_state); /* should not be necessary */ | ||
123 | TRACE_EXIT result; | ||
124 | } | ||
125 | |||
126 | /* Wait until all data is actually written to tape. | ||
127 | * | ||
128 | * There is a problem: when the tape runs into logical EOT, then this | ||
129 | * failes. We need to restart the runner in this case. | ||
130 | */ | ||
131 | int ftape_loop_until_writes_done(void) | ||
132 | { | ||
133 | buffer_struct *head; | ||
134 | TRACE_FUN(ft_t_flow); | ||
135 | |||
136 | while ((ft_driver_state == writing || ft_driver_state == deleting) && | ||
137 | ftape_get_buffer(ft_queue_head)->status != done) { | ||
138 | /* set the runner status to idle if at lEOT */ | ||
139 | TRACE_CATCH(ftape_handle_logical_eot(), last_write_failed = 1); | ||
140 | /* restart the tape if necessary */ | ||
141 | if (ft_runner_status == idle) { | ||
142 | TRACE(ft_t_noise, "runner is idle, restarting"); | ||
143 | if (ft_driver_state == deleting) { | ||
144 | TRACE_CATCH(ftape_start_writing(FT_WR_DELETE), | ||
145 | last_write_failed = 1); | ||
146 | } else { | ||
147 | TRACE_CATCH(ftape_start_writing(FT_WR_MULTI), | ||
148 | last_write_failed = 1); | ||
149 | } | ||
150 | } | ||
151 | TRACE(ft_t_noise, "tail: %d, head: %d", | ||
152 | ftape_buffer_id(ft_queue_tail), | ||
153 | ftape_buffer_id(ft_queue_head)); | ||
154 | TRACE_CATCH(fdc_interrupt_wait(5 * FT_SECOND), | ||
155 | last_write_failed = 1); | ||
156 | head = ftape_get_buffer(ft_queue_head); | ||
157 | if (head->status == error) { | ||
158 | /* Allow escape from loop when signaled ! | ||
159 | */ | ||
160 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
161 | if (head->hard_error_map != 0) { | ||
162 | /* Implement hard write error recovery here | ||
163 | */ | ||
164 | } | ||
165 | /* retry this one */ | ||
166 | head->status = waiting; | ||
167 | if (ft_runner_status == aborting) { | ||
168 | ftape_dumb_stop(); | ||
169 | } | ||
170 | if (ft_runner_status != idle) { | ||
171 | TRACE_ABORT(-EIO, ft_t_err, | ||
172 | "unexpected state: " | ||
173 | "ft_runner_status != idle"); | ||
174 | } | ||
175 | ftape_start_writing(ft_driver_state == deleting | ||
176 | ? FT_WR_MULTI : FT_WR_DELETE); | ||
177 | } | ||
178 | TRACE(ft_t_noise, "looping until writes done"); | ||
179 | } | ||
180 | ftape_set_state(idle); | ||
181 | TRACE_EXIT 0; | ||
182 | } | ||
183 | |||
184 | /* Write given segment from buffer at address to tape. | ||
185 | */ | ||
186 | static int write_segment(const int segment_id, | ||
187 | const void *address, | ||
188 | const ft_write_mode_t write_mode) | ||
189 | { | ||
190 | int bytes_written = 0; | ||
191 | buffer_struct *tail; | ||
192 | buffer_state_enum wanted_state = (write_mode == FT_WR_DELETE | ||
193 | ? deleting : writing); | ||
194 | TRACE_FUN(ft_t_flow); | ||
195 | |||
196 | TRACE(ft_t_noise, "segment_id = %d", segment_id); | ||
197 | if (ft_driver_state != wanted_state) { | ||
198 | if (ft_driver_state == deleting || | ||
199 | wanted_state == deleting) { | ||
200 | TRACE_CATCH(ftape_loop_until_writes_done(),); | ||
201 | } | ||
202 | TRACE(ft_t_noise, "calling ftape_abort_operation"); | ||
203 | TRACE_CATCH(ftape_abort_operation(),); | ||
204 | ftape_zap_write_buffers(); | ||
205 | ftape_set_state(wanted_state); | ||
206 | } | ||
207 | /* if all buffers full we'll have to wait... | ||
208 | */ | ||
209 | ftape_wait_segment(wanted_state); | ||
210 | tail = ftape_get_buffer(ft_queue_tail); | ||
211 | switch(tail->status) { | ||
212 | case done: | ||
213 | ft_history.defects += count_ones(tail->hard_error_map); | ||
214 | break; | ||
215 | case waiting: | ||
216 | /* this could happen with multiple EMPTY_SEGMENTs, but | ||
217 | * shouldn't happen any more as we re-start the runner even | ||
218 | * with an empty segment. | ||
219 | */ | ||
220 | bytes_written = -EAGAIN; | ||
221 | break; | ||
222 | case error: | ||
223 | /* setup for a retry | ||
224 | */ | ||
225 | tail->status = waiting; | ||
226 | bytes_written = -EAGAIN; /* force retry */ | ||
227 | if (tail->hard_error_map != 0) { | ||
228 | TRACE(ft_t_warn, | ||
229 | "warning: %d hard error(s) in written segment", | ||
230 | count_ones(tail->hard_error_map)); | ||
231 | TRACE(ft_t_noise, "hard_error_map = 0x%08lx", | ||
232 | (long)tail->hard_error_map); | ||
233 | /* Implement hard write error recovery here | ||
234 | */ | ||
235 | } | ||
236 | break; | ||
237 | default: | ||
238 | TRACE_ABORT(-EIO, ft_t_err, | ||
239 | "wait for empty segment failed, tail status: %d", | ||
240 | tail->status); | ||
241 | } | ||
242 | /* should runner stop ? | ||
243 | */ | ||
244 | if (ft_runner_status == aborting) { | ||
245 | buffer_struct *head = ftape_get_buffer(ft_queue_head); | ||
246 | if (head->status == wanted_state) { | ||
247 | head->status = done; /* ???? */ | ||
248 | } | ||
249 | /* don't call abort_operation(), we don't want to zap | ||
250 | * the dma buffers | ||
251 | */ | ||
252 | TRACE_CATCH(ftape_dumb_stop(),); | ||
253 | } else { | ||
254 | /* If just passed last segment on tape: wait for BOT | ||
255 | * or EOT mark. Sets ft_runner_status to idle if at lEOT | ||
256 | * and successful | ||
257 | */ | ||
258 | TRACE_CATCH(ftape_handle_logical_eot(),); | ||
259 | } | ||
260 | if (tail->status == done) { | ||
261 | /* now at least one buffer is empty, fill it with our | ||
262 | * data. skip bad sectors and generate ecc. | ||
263 | * copy_and_gen_ecc return nr of bytes written, range | ||
264 | * 0..29 Kb inclusive! | ||
265 | * | ||
266 | * Empty segments are handled inside coyp_and_gen_ecc() | ||
267 | */ | ||
268 | if (write_mode != FT_WR_DELETE) { | ||
269 | TRACE_CATCH(bytes_written = copy_and_gen_ecc( | ||
270 | tail->address, address, | ||
271 | ftape_get_bad_sector_entry(segment_id)),); | ||
272 | } | ||
273 | tail->segment_id = segment_id; | ||
274 | tail->status = waiting; | ||
275 | tail = ftape_next_buffer(ft_queue_tail); | ||
276 | } | ||
277 | /* Start tape only if all buffers full or flush mode. | ||
278 | * This will give higher probability of streaming. | ||
279 | */ | ||
280 | if (ft_runner_status != running && | ||
281 | ((tail->status == waiting && | ||
282 | ftape_get_buffer(ft_queue_head) == tail) || | ||
283 | write_mode != FT_WR_ASYNC)) { | ||
284 | TRACE_CATCH(ftape_start_writing(write_mode),); | ||
285 | } | ||
286 | TRACE_EXIT bytes_written; | ||
287 | } | ||
288 | |||
289 | /* Write as much as fits from buffer to the given segment on tape | ||
290 | * and handle retries. | ||
291 | * Return the number of bytes written (>= 0), or: | ||
292 | * -EIO write failed | ||
293 | * -EINTR interrupted by signal | ||
294 | * -ENOSPC device full | ||
295 | */ | ||
296 | int ftape_write_segment(const int segment_id, | ||
297 | const void *buffer, | ||
298 | const ft_write_mode_t flush) | ||
299 | { | ||
300 | int retry = 0; | ||
301 | int result; | ||
302 | TRACE_FUN(ft_t_flow); | ||
303 | |||
304 | ft_history.used |= 2; | ||
305 | if (segment_id >= ft_tracks_per_tape*ft_segments_per_track) { | ||
306 | /* tape full */ | ||
307 | TRACE_ABORT(-ENOSPC, ft_t_err, | ||
308 | "invalid segment id: %d (max %d)", | ||
309 | segment_id, | ||
310 | ft_tracks_per_tape * ft_segments_per_track -1); | ||
311 | } | ||
312 | for (;;) { | ||
313 | if ((result = write_segment(segment_id, buffer, flush)) >= 0) { | ||
314 | if (result == 0) { /* empty segment */ | ||
315 | TRACE(ft_t_noise, | ||
316 | "empty segment, nothing written"); | ||
317 | } | ||
318 | TRACE_EXIT result; | ||
319 | } | ||
320 | if (result == -EAGAIN) { | ||
321 | if (++retry > 100) { /* give up */ | ||
322 | TRACE_ABORT(-EIO, ft_t_err, | ||
323 | "write failed, >100 retries in segment"); | ||
324 | } | ||
325 | TRACE(ft_t_warn, "write error, retry %d (%d)", | ||
326 | retry, | ||
327 | ftape_get_buffer(ft_queue_tail)->segment_id); | ||
328 | } else { | ||
329 | TRACE_ABORT(result, ft_t_err, | ||
330 | "write_segment failed, error: %d", result); | ||
331 | } | ||
332 | /* Allow escape from loop when signaled ! | ||
333 | */ | ||
334 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
335 | } | ||
336 | } | ||
diff --git a/drivers/char/ftape/lowlevel/ftape-write.h b/drivers/char/ftape/lowlevel/ftape-write.h deleted file mode 100644 index 0e7f898b7af9..000000000000 --- a/drivers/char/ftape/lowlevel/ftape-write.h +++ /dev/null | |||
@@ -1,53 +0,0 @@ | |||
1 | #ifndef _FTAPE_WRITE_H | ||
2 | #define _FTAPE_WRITE_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1994-1995 Bas Laarhoven, | ||
6 | * (C) 1996-1997 Claus-Justus Heine. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape-write.h,v $ | ||
24 | $Author: claus $ | ||
25 | * | ||
26 | $Revision: 1.2 $ | ||
27 | $Date: 1997/10/05 19:18:30 $ | ||
28 | $State: Exp $ | ||
29 | * | ||
30 | * This file contains the definitions for the write functions | ||
31 | * for the QIC-117 floppy-tape driver for Linux. | ||
32 | * | ||
33 | */ | ||
34 | |||
35 | |||
36 | /* ftape-write.c defined global functions. | ||
37 | */ | ||
38 | typedef enum { | ||
39 | FT_WR_ASYNC = 0, /* start tape only when all buffers are full */ | ||
40 | FT_WR_MULTI = 1, /* start tape, but don't necessarily stop */ | ||
41 | FT_WR_SINGLE = 2, /* write a single segment and stop afterwards */ | ||
42 | FT_WR_DELETE = 3 /* write deleted data marks */ | ||
43 | } ft_write_mode_t; | ||
44 | |||
45 | extern int ftape_start_writing(const ft_write_mode_t mode); | ||
46 | extern int ftape_write_segment(const int segment, | ||
47 | const void *address, | ||
48 | const ft_write_mode_t flushing); | ||
49 | extern void ftape_zap_write_buffers(void); | ||
50 | extern int ftape_loop_until_writes_done(void); | ||
51 | |||
52 | #endif /* _FTAPE_WRITE_H */ | ||
53 | |||
diff --git a/drivers/char/ftape/lowlevel/ftape_syms.c b/drivers/char/ftape/lowlevel/ftape_syms.c deleted file mode 100644 index 8e0dc4a07ca6..000000000000 --- a/drivers/char/ftape/lowlevel/ftape_syms.c +++ /dev/null | |||
@@ -1,87 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1996-1997 Claus-Justus Heine | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; see the file COPYING. If not, write to | ||
16 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | |||
18 | * | ||
19 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/ftape_syms.c,v $ | ||
20 | * $Revision: 1.4 $ | ||
21 | * $Date: 1997/10/17 00:03:51 $ | ||
22 | * | ||
23 | * This file contains the symbols that the ftape low level | ||
24 | * part of the QIC-40/80/3010/3020 floppy-tape driver "ftape" | ||
25 | * exports to its high level clients | ||
26 | */ | ||
27 | |||
28 | #include <linux/module.h> | ||
29 | |||
30 | #include <linux/ftape.h> | ||
31 | #include "../lowlevel/ftape-tracing.h" | ||
32 | #include "../lowlevel/ftape-init.h" | ||
33 | #include "../lowlevel/fdc-io.h" | ||
34 | #include "../lowlevel/ftape-read.h" | ||
35 | #include "../lowlevel/ftape-write.h" | ||
36 | #include "../lowlevel/ftape-io.h" | ||
37 | #include "../lowlevel/ftape-ctl.h" | ||
38 | #include "../lowlevel/ftape-rw.h" | ||
39 | #include "../lowlevel/ftape-bsm.h" | ||
40 | #include "../lowlevel/ftape-buffer.h" | ||
41 | #include "../lowlevel/ftape-format.h" | ||
42 | |||
43 | /* bad sector handling from ftape-bsm.c */ | ||
44 | EXPORT_SYMBOL(ftape_get_bad_sector_entry); | ||
45 | EXPORT_SYMBOL(ftape_find_end_of_bsm_list); | ||
46 | /* from ftape-rw.c */ | ||
47 | EXPORT_SYMBOL(ftape_set_state); | ||
48 | /* from ftape-ctl.c */ | ||
49 | EXPORT_SYMBOL(ftape_seek_to_bot); | ||
50 | EXPORT_SYMBOL(ftape_seek_to_eot); | ||
51 | EXPORT_SYMBOL(ftape_abort_operation); | ||
52 | EXPORT_SYMBOL(ftape_get_status); | ||
53 | EXPORT_SYMBOL(ftape_enable); | ||
54 | EXPORT_SYMBOL(ftape_disable); | ||
55 | EXPORT_SYMBOL(ftape_mmap); | ||
56 | EXPORT_SYMBOL(ftape_calibrate_data_rate); | ||
57 | /* from ftape-io.c */ | ||
58 | EXPORT_SYMBOL(ftape_reset_drive); | ||
59 | EXPORT_SYMBOL(ftape_command); | ||
60 | EXPORT_SYMBOL(ftape_parameter); | ||
61 | EXPORT_SYMBOL(ftape_ready_wait); | ||
62 | EXPORT_SYMBOL(ftape_report_operation); | ||
63 | EXPORT_SYMBOL(ftape_report_error); | ||
64 | /* from ftape-read.c */ | ||
65 | EXPORT_SYMBOL(ftape_read_segment_fraction); | ||
66 | EXPORT_SYMBOL(ftape_zap_read_buffers); | ||
67 | EXPORT_SYMBOL(ftape_read_header_segment); | ||
68 | EXPORT_SYMBOL(ftape_decode_header_segment); | ||
69 | /* from ftape-write.c */ | ||
70 | EXPORT_SYMBOL(ftape_write_segment); | ||
71 | EXPORT_SYMBOL(ftape_start_writing); | ||
72 | EXPORT_SYMBOL(ftape_loop_until_writes_done); | ||
73 | /* from ftape-buffer.h */ | ||
74 | EXPORT_SYMBOL(ftape_set_nr_buffers); | ||
75 | /* from ftape-format.h */ | ||
76 | EXPORT_SYMBOL(ftape_format_track); | ||
77 | EXPORT_SYMBOL(ftape_format_status); | ||
78 | EXPORT_SYMBOL(ftape_verify_segment); | ||
79 | /* from tracing.c */ | ||
80 | #ifndef CONFIG_FT_NO_TRACE_AT_ALL | ||
81 | EXPORT_SYMBOL(ftape_tracing); | ||
82 | EXPORT_SYMBOL(ftape_function_nest_level); | ||
83 | EXPORT_SYMBOL(ftape_trace_call); | ||
84 | EXPORT_SYMBOL(ftape_trace_exit); | ||
85 | EXPORT_SYMBOL(ftape_trace_log); | ||
86 | #endif | ||
87 | |||
diff --git a/drivers/char/ftape/zftape/Makefile b/drivers/char/ftape/zftape/Makefile deleted file mode 100644 index 6d91c1f77c05..000000000000 --- a/drivers/char/ftape/zftape/Makefile +++ /dev/null | |||
@@ -1,36 +0,0 @@ | |||
1 | # | ||
2 | # Copyright (C) 1996, 1997 Claus-Justus Heine. | ||
3 | # | ||
4 | # This program is free software; you can redistribute it and/or modify | ||
5 | # it under the terms of the GNU General Public License as published by | ||
6 | # the Free Software Foundation; either version 2, or (at your option) | ||
7 | # any later version. | ||
8 | # | ||
9 | # This program is distributed in the hope that it will be useful, | ||
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | # GNU General Public License for more details. | ||
13 | # | ||
14 | # You should have received a copy of the GNU General Public License | ||
15 | # along with this program; see the file COPYING. If not, write to | ||
16 | # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | # | ||
18 | # $Source: /homes/cvs/ftape-stacked/ftape/zftape/Makefile,v $ | ||
19 | # $Revision: 1.4 $ | ||
20 | # $Date: 1997/10/05 19:18:58 $ | ||
21 | # | ||
22 | # Makefile for the QIC-40/80/3010/3020 zftape interface VFS to | ||
23 | # ftape | ||
24 | # | ||
25 | |||
26 | |||
27 | # ZFT_OBSOLETE - enable the MTIOC_ZFTAPE_GETBLKSZ ioctl. You should | ||
28 | # leave this enabled for compatibility with taper. | ||
29 | |||
30 | obj-$(CONFIG_ZFTAPE) += zftape.o | ||
31 | |||
32 | zftape-objs := zftape-rw.o zftape-ctl.o zftape-read.o \ | ||
33 | zftape-write.o zftape-vtbl.o zftape-eof.o \ | ||
34 | zftape-init.o zftape-buffers.o zftape_syms.o | ||
35 | |||
36 | 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 da06f138334e..000000000000 --- a/drivers/char/ftape/zftape/zftape-buffers.c +++ /dev/null | |||
@@ -1,149 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1995-1997 Claus-Justus Heine. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; see the file COPYING. If not, write to | ||
16 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | |||
18 | * | ||
19 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-buffers.c,v $ | ||
20 | * $Revision: 1.2 $ | ||
21 | * $Date: 1997/10/05 19:18:59 $ | ||
22 | * | ||
23 | * This file contains the dynamic buffer allocation routines | ||
24 | * of zftape | ||
25 | */ | ||
26 | |||
27 | #include <linux/errno.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/delay.h> | ||
31 | |||
32 | #include <linux/zftape.h> | ||
33 | |||
34 | #include <linux/vmalloc.h> | ||
35 | |||
36 | #include "../zftape/zftape-init.h" | ||
37 | #include "../zftape/zftape-eof.h" | ||
38 | #include "../zftape/zftape-ctl.h" | ||
39 | #include "../zftape/zftape-write.h" | ||
40 | #include "../zftape/zftape-read.h" | ||
41 | #include "../zftape/zftape-rw.h" | ||
42 | #include "../zftape/zftape-vtbl.h" | ||
43 | |||
44 | /* global variables | ||
45 | */ | ||
46 | |||
47 | /* local varibales | ||
48 | */ | ||
49 | static unsigned int used_memory; | ||
50 | static unsigned int peak_memory; | ||
51 | |||
52 | void zft_memory_stats(void) | ||
53 | { | ||
54 | TRACE_FUN(ft_t_flow); | ||
55 | |||
56 | TRACE(ft_t_noise, "Memory usage (vmalloc allocations):\n" | ||
57 | KERN_INFO "total allocated: %d\n" | ||
58 | KERN_INFO "peak allocation: %d", | ||
59 | used_memory, peak_memory); | ||
60 | peak_memory = used_memory; | ||
61 | TRACE_EXIT; | ||
62 | } | ||
63 | |||
64 | int zft_vcalloc_once(void *new, size_t size) | ||
65 | { | ||
66 | TRACE_FUN(ft_t_flow); | ||
67 | if (zft_vmalloc_once(new, size) < 0) { | ||
68 | TRACE_EXIT -ENOMEM; | ||
69 | } | ||
70 | memset(*(void **)new, '\0', size); | ||
71 | TRACE_EXIT 0; | ||
72 | } | ||
73 | int zft_vmalloc_once(void *new, size_t size) | ||
74 | { | ||
75 | TRACE_FUN(ft_t_flow); | ||
76 | |||
77 | if (*(void **)new != NULL || size == 0) { | ||
78 | TRACE_EXIT 0; | ||
79 | } | ||
80 | if ((*(void **)new = vmalloc(size)) == NULL) { | ||
81 | TRACE_EXIT -ENOMEM; | ||
82 | } | ||
83 | used_memory += size; | ||
84 | if (peak_memory < used_memory) { | ||
85 | peak_memory = used_memory; | ||
86 | } | ||
87 | TRACE_ABORT(0, ft_t_noise, | ||
88 | "allocated buffer @ %p, %d bytes", *(void **)new, size); | ||
89 | } | ||
90 | int zft_vmalloc_always(void *new, size_t size) | ||
91 | { | ||
92 | TRACE_FUN(ft_t_flow); | ||
93 | |||
94 | zft_vfree(new, size); | ||
95 | TRACE_EXIT zft_vmalloc_once(new, size); | ||
96 | } | ||
97 | void zft_vfree(void *old, size_t size) | ||
98 | { | ||
99 | TRACE_FUN(ft_t_flow); | ||
100 | |||
101 | if (*(void **)old) { | ||
102 | vfree(*(void **)old); | ||
103 | used_memory -= size; | ||
104 | TRACE(ft_t_noise, "released buffer @ %p, %d bytes", | ||
105 | *(void **)old, size); | ||
106 | *(void **)old = NULL; | ||
107 | } | ||
108 | TRACE_EXIT; | ||
109 | } | ||
110 | |||
111 | void *zft_kmalloc(size_t size) | ||
112 | { | ||
113 | void *new; | ||
114 | |||
115 | while ((new = kmalloc(size, GFP_KERNEL)) == NULL) { | ||
116 | msleep_interruptible(100); | ||
117 | } | ||
118 | memset(new, 0, size); | ||
119 | used_memory += size; | ||
120 | if (peak_memory < used_memory) { | ||
121 | peak_memory = used_memory; | ||
122 | } | ||
123 | return new; | ||
124 | } | ||
125 | |||
126 | void zft_kfree(void *old, size_t size) | ||
127 | { | ||
128 | kfree(old); | ||
129 | used_memory -= size; | ||
130 | } | ||
131 | |||
132 | /* there are some more buffers that are allocated on demand. | ||
133 | * cleanup_module() calles this function to be sure to have released | ||
134 | * them | ||
135 | */ | ||
136 | void zft_uninit_mem(void) | ||
137 | { | ||
138 | TRACE_FUN(ft_t_flow); | ||
139 | |||
140 | zft_vfree(&zft_hseg_buf, FT_SEGMENT_SIZE); | ||
141 | zft_vfree(&zft_deblock_buf, FT_SEGMENT_SIZE); zft_deblock_segment = -1; | ||
142 | zft_free_vtbl(); | ||
143 | if (zft_cmpr_lock(0 /* don't load */) == 0) { | ||
144 | (*zft_cmpr_ops->cleanup)(); | ||
145 | (*zft_cmpr_ops->reset)(); /* unlock it again */ | ||
146 | } | ||
147 | zft_memory_stats(); | ||
148 | TRACE_EXIT; | ||
149 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-buffers.h b/drivers/char/ftape/zftape/zftape-buffers.h deleted file mode 100644 index 798e3128c682..000000000000 --- a/drivers/char/ftape/zftape/zftape-buffers.h +++ /dev/null | |||
@@ -1,55 +0,0 @@ | |||
1 | #ifndef _FTAPE_DYNMEM_H | ||
2 | #define _FTAPE_DYNMEM_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1995-1997 Claus-Justus Heine. | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-buffers.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:18:59 $ | ||
25 | * | ||
26 | * memory allocation routines. | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | /* we do not allocate all of the really large buffer memory before | ||
31 | * someone tries to open the drive. ftape_open() may fail with | ||
32 | * -ENOMEM, but that's better having 200k of vmalloced memory which | ||
33 | * cannot be swapped out. | ||
34 | */ | ||
35 | |||
36 | extern void zft_memory_stats(void); | ||
37 | extern int zft_vmalloc_once(void *new, size_t size); | ||
38 | extern int zft_vcalloc_once(void *new, size_t size); | ||
39 | extern int zft_vmalloc_always(void *new, size_t size); | ||
40 | extern void zft_vfree(void *old, size_t size); | ||
41 | extern void *zft_kmalloc(size_t size); | ||
42 | extern void zft_kfree(void *old, size_t size); | ||
43 | |||
44 | /* called by cleanup_module() | ||
45 | */ | ||
46 | extern void zft_uninit_mem(void); | ||
47 | |||
48 | #endif | ||
49 | |||
50 | |||
51 | |||
52 | |||
53 | |||
54 | |||
55 | |||
diff --git a/drivers/char/ftape/zftape/zftape-ctl.c b/drivers/char/ftape/zftape/zftape-ctl.c deleted file mode 100644 index 22ba0f5d00cf..000000000000 --- a/drivers/char/ftape/zftape/zftape-ctl.c +++ /dev/null | |||
@@ -1,1417 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1996, 1997 Claus-Justus Heine | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; see the file COPYING. If not, write to | ||
16 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | |||
18 | * | ||
19 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-ctl.c,v $ | ||
20 | * $Revision: 1.2.6.2 $ | ||
21 | * $Date: 1997/11/14 18:07:33 $ | ||
22 | * | ||
23 | * This file contains the non-read/write zftape functions | ||
24 | * for the QIC-40/80/3010/3020 floppy-tape driver for Linux. | ||
25 | */ | ||
26 | |||
27 | #include <linux/errno.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/fcntl.h> | ||
31 | |||
32 | #include <linux/zftape.h> | ||
33 | |||
34 | #include <asm/uaccess.h> | ||
35 | |||
36 | #include "../zftape/zftape-init.h" | ||
37 | #include "../zftape/zftape-eof.h" | ||
38 | #include "../zftape/zftape-ctl.h" | ||
39 | #include "../zftape/zftape-write.h" | ||
40 | #include "../zftape/zftape-read.h" | ||
41 | #include "../zftape/zftape-rw.h" | ||
42 | #include "../zftape/zftape-vtbl.h" | ||
43 | |||
44 | /* Global vars. | ||
45 | */ | ||
46 | int zft_write_protected; /* this is when cartridge rdonly or O_RDONLY */ | ||
47 | int zft_header_read; | ||
48 | int zft_offline; | ||
49 | unsigned int zft_unit; | ||
50 | int zft_resid; | ||
51 | int zft_mt_compression; | ||
52 | |||
53 | /* Local vars. | ||
54 | */ | ||
55 | static int going_offline; | ||
56 | |||
57 | typedef int (mt_fun)(int *argptr); | ||
58 | typedef int (*mt_funp)(int *argptr); | ||
59 | typedef struct | ||
60 | { | ||
61 | mt_funp function; | ||
62 | unsigned offline : 1; /* op permitted if offline or no_tape */ | ||
63 | unsigned write_protected : 1; /* op permitted if write-protected */ | ||
64 | unsigned not_formatted : 1; /* op permitted if tape not formatted */ | ||
65 | unsigned raw_mode : 1; /* op permitted if zft_mode == 0 */ | ||
66 | unsigned need_idle_state : 1; /* need to call def_idle_state */ | ||
67 | char *name; | ||
68 | } fun_entry; | ||
69 | |||
70 | static mt_fun mt_dummy, mt_reset, mt_fsr, mt_bsr, mt_rew, mt_offl, mt_nop, | ||
71 | mt_weof, mt_erase, mt_ras2, mt_setblk, mt_setdensity, | ||
72 | mt_seek, mt_tell, mt_reten, mt_eom, mt_fsf, mt_bsf, | ||
73 | mt_fsfm, mt_bsfm, mt_setdrvbuffer, mt_compression; | ||
74 | |||
75 | static fun_entry mt_funs[]= | ||
76 | { | ||
77 | {mt_reset , 1, 1, 1, 1, 0, "MT_RESET" }, /* 0 */ | ||
78 | {mt_fsf , 0, 1, 0, 0, 1, "MT_FSF" }, | ||
79 | {mt_bsf , 0, 1, 0, 0, 1, "MT_BSF" }, | ||
80 | {mt_fsr , 0, 1, 0, 1, 1, "MT_FSR" }, | ||
81 | {mt_bsr , 0, 1, 0, 1, 1, "MT_BSR" }, | ||
82 | {mt_weof , 0, 0, 0, 0, 0, "MT_WEOF" }, /* 5 */ | ||
83 | {mt_rew , 0, 1, 1, 1, 0, "MT_REW" }, | ||
84 | {mt_offl , 0, 1, 1, 1, 0, "MT_OFFL" }, | ||
85 | {mt_nop , 1, 1, 1, 1, 0, "MT_NOP" }, | ||
86 | {mt_reten , 0, 1, 1, 1, 0, "MT_RETEN" }, | ||
87 | {mt_bsfm , 0, 1, 0, 0, 1, "MT_BSFM" }, /* 10 */ | ||
88 | {mt_fsfm , 0, 1, 0, 0, 1, "MT_FSFM" }, | ||
89 | {mt_eom , 0, 1, 0, 0, 1, "MT_EOM" }, | ||
90 | {mt_erase , 0, 0, 0, 1, 0, "MT_ERASE" }, | ||
91 | {mt_dummy , 1, 1, 1, 1, 0, "MT_RAS1" }, | ||
92 | {mt_ras2 , 0, 0, 0, 1, 0, "MT_RAS2" }, | ||
93 | {mt_dummy , 1, 1, 1, 1, 0, "MT_RAS3" }, | ||
94 | {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, | ||
95 | {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, | ||
96 | {mt_dummy , 1, 1, 1, 1, 0, "UNKNOWN" }, | ||
97 | {mt_setblk , 1, 1, 1, 1, 1, "MT_SETBLK"}, /* 20 */ | ||
98 | {mt_setdensity , 1, 1, 1, 1, 0, "MT_SETDENSITY"}, | ||
99 | {mt_seek , 0, 1, 0, 1, 1, "MT_SEEK" }, | ||
100 | {mt_dummy , 0, 1, 0, 1, 1, "MT_TELL" }, /* wr-only ?! */ | ||
101 | {mt_setdrvbuffer, 1, 1, 1, 1, 0, "MT_SETDRVBUFFER" }, | ||
102 | {mt_dummy , 1, 1, 1, 1, 0, "MT_FSS" }, /* 25 */ | ||
103 | {mt_dummy , 1, 1, 1, 1, 0, "MT_BSS" }, | ||
104 | {mt_dummy , 1, 1, 1, 1, 0, "MT_WSM" }, | ||
105 | {mt_dummy , 1, 1, 1, 1, 0, "MT_LOCK" }, | ||
106 | {mt_dummy , 1, 1, 1, 1, 0, "MT_UNLOCK"}, | ||
107 | {mt_dummy , 1, 1, 1, 1, 0, "MT_LOAD" }, /* 30 */ | ||
108 | {mt_dummy , 1, 1, 1, 1, 0, "MT_UNLOAD"}, | ||
109 | {mt_compression , 1, 1, 1, 0, 1, "MT_COMPRESSION"}, | ||
110 | {mt_dummy , 1, 1, 1, 1, 0, "MT_SETPART"}, | ||
111 | {mt_dummy , 1, 1, 1, 1, 0, "MT_MKPART"} | ||
112 | }; | ||
113 | |||
114 | #define NR_MT_CMDS NR_ITEMS(mt_funs) | ||
115 | |||
116 | void zft_reset_position(zft_position *pos) | ||
117 | { | ||
118 | TRACE_FUN(ft_t_flow); | ||
119 | |||
120 | pos->seg_byte_pos = | ||
121 | pos->volume_pos = 0; | ||
122 | if (zft_header_read) { | ||
123 | /* need to keep track of the volume table and | ||
124 | * compression map. We therefor simply | ||
125 | * position at the beginning of the first | ||
126 | * volume. This covers old ftape archives as | ||
127 | * well has various flavours of the | ||
128 | * compression map segments. The worst case is | ||
129 | * that the compression map shows up as a | ||
130 | * additional volume in front of all others. | ||
131 | */ | ||
132 | pos->seg_pos = zft_find_volume(0)->start_seg; | ||
133 | pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); | ||
134 | } else { | ||
135 | pos->tape_pos = 0; | ||
136 | pos->seg_pos = -1; | ||
137 | } | ||
138 | zft_just_before_eof = 0; | ||
139 | zft_deblock_segment = -1; | ||
140 | zft_io_state = zft_idle; | ||
141 | zft_zap_read_buffers(); | ||
142 | zft_prevent_flush(); | ||
143 | /* unlock the compresison module if it is loaded. | ||
144 | * The zero arg means not to try to load the module. | ||
145 | */ | ||
146 | if (zft_cmpr_lock(0) == 0) { | ||
147 | (*zft_cmpr_ops->reset)(); /* unlock */ | ||
148 | } | ||
149 | TRACE_EXIT; | ||
150 | } | ||
151 | |||
152 | static void zft_init_driver(void) | ||
153 | { | ||
154 | TRACE_FUN(ft_t_flow); | ||
155 | |||
156 | zft_resid = | ||
157 | zft_header_read = | ||
158 | zft_old_ftape = | ||
159 | zft_offline = | ||
160 | zft_write_protected = | ||
161 | going_offline = | ||
162 | zft_mt_compression = | ||
163 | zft_header_changed = | ||
164 | zft_volume_table_changed = | ||
165 | zft_written_segments = 0; | ||
166 | zft_blk_sz = CONFIG_ZFT_DFLT_BLK_SZ; | ||
167 | zft_reset_position(&zft_pos); /* does most of the stuff */ | ||
168 | ftape_zap_read_buffers(); | ||
169 | ftape_set_state(idle); | ||
170 | TRACE_EXIT; | ||
171 | } | ||
172 | |||
173 | int zft_def_idle_state(void) | ||
174 | { | ||
175 | int result = 0; | ||
176 | TRACE_FUN(ft_t_flow); | ||
177 | |||
178 | if (!zft_header_read) { | ||
179 | result = zft_read_header_segments(); | ||
180 | } else if ((result = zft_flush_buffers()) >= 0 && zft_qic_mode) { | ||
181 | /* don't move past eof | ||
182 | */ | ||
183 | (void)zft_close_volume(&zft_pos); | ||
184 | } | ||
185 | if (ftape_abort_operation() < 0) { | ||
186 | TRACE(ft_t_warn, "ftape_abort_operation() failed"); | ||
187 | result = -EIO; | ||
188 | } | ||
189 | /* clear remaining read buffers */ | ||
190 | zft_zap_read_buffers(); | ||
191 | zft_io_state = zft_idle; | ||
192 | TRACE_EXIT result; | ||
193 | } | ||
194 | |||
195 | /***************************************************************************** | ||
196 | * * | ||
197 | * functions for the MTIOCTOP commands * | ||
198 | * * | ||
199 | *****************************************************************************/ | ||
200 | |||
201 | static int mt_dummy(int *dummy) | ||
202 | { | ||
203 | TRACE_FUN(ft_t_flow); | ||
204 | |||
205 | TRACE_EXIT -ENOSYS; | ||
206 | } | ||
207 | |||
208 | static int mt_reset(int *dummy) | ||
209 | { | ||
210 | TRACE_FUN(ft_t_flow); | ||
211 | |||
212 | (void)ftape_seek_to_bot(); | ||
213 | TRACE_CATCH(ftape_reset_drive(), | ||
214 | zft_init_driver(); zft_uninit_mem(); zft_offline = 1); | ||
215 | /* fake a re-open of the device. This will set all flage and | ||
216 | * allocate buffers as appropriate. The new tape condition will | ||
217 | * force the open routine to do anything we need. | ||
218 | */ | ||
219 | TRACE_CATCH(_zft_open(-1 /* fake reopen */, 0 /* dummy */),); | ||
220 | TRACE_EXIT 0; | ||
221 | } | ||
222 | |||
223 | static int mt_fsf(int *arg) | ||
224 | { | ||
225 | int result; | ||
226 | TRACE_FUN(ft_t_flow); | ||
227 | |||
228 | result = zft_skip_volumes(*arg, &zft_pos); | ||
229 | zft_just_before_eof = 0; | ||
230 | TRACE_EXIT result; | ||
231 | } | ||
232 | |||
233 | static int mt_bsf(int *arg) | ||
234 | { | ||
235 | int result = 0; | ||
236 | TRACE_FUN(ft_t_flow); | ||
237 | |||
238 | if (*arg != 0) { | ||
239 | result = zft_skip_volumes(-*arg + 1, &zft_pos); | ||
240 | } | ||
241 | TRACE_EXIT result; | ||
242 | } | ||
243 | |||
244 | static int seek_block(__s64 data_offset, | ||
245 | __s64 block_increment, | ||
246 | zft_position *pos) | ||
247 | { | ||
248 | int result = 0; | ||
249 | __s64 new_block_pos; | ||
250 | __s64 vol_block_count; | ||
251 | const zft_volinfo *volume; | ||
252 | int exceed; | ||
253 | TRACE_FUN(ft_t_flow); | ||
254 | |||
255 | volume = zft_find_volume(pos->seg_pos); | ||
256 | if (volume->start_seg == 0 || volume->end_seg == 0) { | ||
257 | TRACE_EXIT -EIO; | ||
258 | } | ||
259 | new_block_pos = (zft_div_blksz(data_offset, volume->blk_sz) | ||
260 | + block_increment); | ||
261 | vol_block_count = zft_div_blksz(volume->size, volume->blk_sz); | ||
262 | if (new_block_pos < 0) { | ||
263 | TRACE(ft_t_noise, | ||
264 | "new_block_pos " LL_X " < 0", LL(new_block_pos)); | ||
265 | zft_resid = (int)new_block_pos; | ||
266 | new_block_pos = 0; | ||
267 | exceed = 1; | ||
268 | } else if (new_block_pos > vol_block_count) { | ||
269 | TRACE(ft_t_noise, | ||
270 | "new_block_pos " LL_X " exceeds size of volume " LL_X, | ||
271 | LL(new_block_pos), LL(vol_block_count)); | ||
272 | zft_resid = (int)(vol_block_count - new_block_pos); | ||
273 | new_block_pos = vol_block_count; | ||
274 | exceed = 1; | ||
275 | } else { | ||
276 | exceed = 0; | ||
277 | } | ||
278 | if (zft_use_compression && volume->use_compression) { | ||
279 | TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),); | ||
280 | result = (*zft_cmpr_ops->seek)(new_block_pos, pos, volume, | ||
281 | zft_deblock_buf); | ||
282 | pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); | ||
283 | pos->tape_pos += pos->seg_byte_pos; | ||
284 | } else { | ||
285 | pos->volume_pos = zft_mul_blksz(new_block_pos, volume->blk_sz); | ||
286 | pos->tape_pos = zft_calc_tape_pos(volume->start_seg); | ||
287 | pos->tape_pos += pos->volume_pos; | ||
288 | pos->seg_pos = zft_calc_seg_byte_coord(&pos->seg_byte_pos, | ||
289 | pos->tape_pos); | ||
290 | } | ||
291 | zft_just_before_eof = volume->size == pos->volume_pos; | ||
292 | if (zft_just_before_eof) { | ||
293 | /* why this? because zft_file_no checks agains start | ||
294 | * and end segment of a volume. We do not want to | ||
295 | * advance to the next volume with this function. | ||
296 | */ | ||
297 | TRACE(ft_t_noise, "set zft_just_before_eof"); | ||
298 | zft_position_before_eof(pos, volume); | ||
299 | } | ||
300 | TRACE(ft_t_noise, "\n" | ||
301 | KERN_INFO "new_seg_pos : %d\n" | ||
302 | KERN_INFO "new_tape_pos: " LL_X "\n" | ||
303 | KERN_INFO "vol_size : " LL_X "\n" | ||
304 | KERN_INFO "seg_byte_pos: %d\n" | ||
305 | KERN_INFO "blk_sz : %d", | ||
306 | pos->seg_pos, LL(pos->tape_pos), | ||
307 | LL(volume->size), pos->seg_byte_pos, | ||
308 | volume->blk_sz); | ||
309 | if (!exceed) { | ||
310 | zft_resid = new_block_pos - zft_div_blksz(pos->volume_pos, | ||
311 | volume->blk_sz); | ||
312 | } | ||
313 | if (zft_resid < 0) { | ||
314 | zft_resid = -zft_resid; | ||
315 | } | ||
316 | TRACE_EXIT ((exceed || zft_resid != 0) && result >= 0) ? -EINVAL : result; | ||
317 | } | ||
318 | |||
319 | static int mt_fsr(int *arg) | ||
320 | { | ||
321 | int result; | ||
322 | TRACE_FUN(ft_t_flow); | ||
323 | |||
324 | result = seek_block(zft_pos.volume_pos, *arg, &zft_pos); | ||
325 | TRACE_EXIT result; | ||
326 | } | ||
327 | |||
328 | static int mt_bsr(int *arg) | ||
329 | { | ||
330 | int result; | ||
331 | TRACE_FUN(ft_t_flow); | ||
332 | |||
333 | result = seek_block(zft_pos.volume_pos, -*arg, &zft_pos); | ||
334 | TRACE_EXIT result; | ||
335 | } | ||
336 | |||
337 | static int mt_weof(int *arg) | ||
338 | { | ||
339 | int result; | ||
340 | TRACE_FUN(ft_t_flow); | ||
341 | |||
342 | TRACE_CATCH(zft_flush_buffers(),); | ||
343 | result = zft_weof(*arg, &zft_pos); | ||
344 | TRACE_EXIT result; | ||
345 | } | ||
346 | |||
347 | static int mt_rew(int *dummy) | ||
348 | { | ||
349 | int result; | ||
350 | TRACE_FUN(ft_t_flow); | ||
351 | |||
352 | if(zft_header_read) { | ||
353 | (void)zft_def_idle_state(); | ||
354 | } | ||
355 | result = ftape_seek_to_bot(); | ||
356 | zft_reset_position(&zft_pos); | ||
357 | TRACE_EXIT result; | ||
358 | } | ||
359 | |||
360 | static int mt_offl(int *dummy) | ||
361 | { | ||
362 | int result; | ||
363 | TRACE_FUN(ft_t_flow); | ||
364 | |||
365 | going_offline= 1; | ||
366 | result = mt_rew(NULL); | ||
367 | TRACE_EXIT result; | ||
368 | } | ||
369 | |||
370 | static int mt_nop(int *dummy) | ||
371 | { | ||
372 | TRACE_FUN(ft_t_flow); | ||
373 | /* should we set tape status? | ||
374 | */ | ||
375 | if (!zft_offline) { /* offline includes no_tape */ | ||
376 | (void)zft_def_idle_state(); | ||
377 | } | ||
378 | TRACE_EXIT 0; | ||
379 | } | ||
380 | |||
381 | static int mt_reten(int *dummy) | ||
382 | { | ||
383 | int result; | ||
384 | TRACE_FUN(ft_t_flow); | ||
385 | |||
386 | if(zft_header_read) { | ||
387 | (void)zft_def_idle_state(); | ||
388 | } | ||
389 | result = ftape_seek_to_eot(); | ||
390 | if (result >= 0) { | ||
391 | result = ftape_seek_to_bot(); | ||
392 | } | ||
393 | TRACE_EXIT(result); | ||
394 | } | ||
395 | |||
396 | static int fsfbsfm(int arg, zft_position *pos) | ||
397 | { | ||
398 | const zft_volinfo *vtbl; | ||
399 | __s64 block_pos; | ||
400 | TRACE_FUN(ft_t_flow); | ||
401 | |||
402 | /* What to do? This should seek to the next file-mark and | ||
403 | * position BEFORE. That is, a next write would just extend | ||
404 | * the current file. Well. Let's just seek to the end of the | ||
405 | * current file, if count == 1. If count > 1, then do a | ||
406 | * "mt_fsf(count - 1)", and then seek to the end of that file. | ||
407 | * If count == 0, do nothing | ||
408 | */ | ||
409 | if (arg == 0) { | ||
410 | TRACE_EXIT 0; | ||
411 | } | ||
412 | zft_just_before_eof = 0; | ||
413 | TRACE_CATCH(zft_skip_volumes(arg < 0 ? arg : arg-1, pos), | ||
414 | if (arg > 0) { | ||
415 | zft_resid ++; | ||
416 | }); | ||
417 | vtbl = zft_find_volume(pos->seg_pos); | ||
418 | block_pos = zft_div_blksz(vtbl->size, vtbl->blk_sz); | ||
419 | (void)seek_block(0, block_pos, pos); | ||
420 | if (pos->volume_pos != vtbl->size) { | ||
421 | zft_just_before_eof = 0; | ||
422 | zft_resid = 1; | ||
423 | /* we didn't managed to go there */ | ||
424 | TRACE_ABORT(-EIO, ft_t_err, | ||
425 | "wanted file position " LL_X ", arrived at " LL_X, | ||
426 | LL(vtbl->size), LL(pos->volume_pos)); | ||
427 | } | ||
428 | zft_just_before_eof = 1; | ||
429 | TRACE_EXIT 0; | ||
430 | } | ||
431 | |||
432 | static int mt_bsfm(int *arg) | ||
433 | { | ||
434 | int result; | ||
435 | TRACE_FUN(ft_t_flow); | ||
436 | |||
437 | result = fsfbsfm(-*arg, &zft_pos); | ||
438 | TRACE_EXIT result; | ||
439 | } | ||
440 | |||
441 | static int mt_fsfm(int *arg) | ||
442 | { | ||
443 | int result; | ||
444 | TRACE_FUN(ft_t_flow); | ||
445 | |||
446 | result = fsfbsfm(*arg, &zft_pos); | ||
447 | TRACE_EXIT result; | ||
448 | } | ||
449 | |||
450 | static int mt_eom(int *dummy) | ||
451 | { | ||
452 | TRACE_FUN(ft_t_flow); | ||
453 | |||
454 | zft_skip_to_eom(&zft_pos); | ||
455 | TRACE_EXIT 0; | ||
456 | } | ||
457 | |||
458 | static int mt_erase(int *dummy) | ||
459 | { | ||
460 | int result; | ||
461 | TRACE_FUN(ft_t_flow); | ||
462 | |||
463 | result = zft_erase(); | ||
464 | TRACE_EXIT result; | ||
465 | } | ||
466 | |||
467 | static int mt_ras2(int *dummy) | ||
468 | { | ||
469 | int result; | ||
470 | TRACE_FUN(ft_t_flow); | ||
471 | |||
472 | result = -ENOSYS; | ||
473 | TRACE_EXIT result; | ||
474 | } | ||
475 | |||
476 | /* Sets the new blocksize in BYTES | ||
477 | * | ||
478 | */ | ||
479 | static int mt_setblk(int *new_size) | ||
480 | { | ||
481 | TRACE_FUN(ft_t_flow); | ||
482 | |||
483 | if((unsigned int)(*new_size) > ZFT_MAX_BLK_SZ) { | ||
484 | TRACE_ABORT(-EINVAL, ft_t_info, | ||
485 | "desired blk_sz (%d) should be <= %d bytes", | ||
486 | *new_size, ZFT_MAX_BLK_SZ); | ||
487 | } | ||
488 | if ((*new_size & (FT_SECTOR_SIZE-1)) != 0) { | ||
489 | TRACE_ABORT(-EINVAL, ft_t_info, | ||
490 | "desired blk_sz (%d) must be a multiple of %d bytes", | ||
491 | *new_size, FT_SECTOR_SIZE); | ||
492 | } | ||
493 | if (*new_size == 0) { | ||
494 | if (zft_use_compression) { | ||
495 | TRACE_ABORT(-EINVAL, ft_t_info, | ||
496 | "Variable block size not yet " | ||
497 | "supported with compression"); | ||
498 | } | ||
499 | *new_size = 1; | ||
500 | } | ||
501 | zft_blk_sz = *new_size; | ||
502 | TRACE_EXIT 0; | ||
503 | } | ||
504 | |||
505 | static int mt_setdensity(int *arg) | ||
506 | { | ||
507 | TRACE_FUN(ft_t_flow); | ||
508 | |||
509 | SET_TRACE_LEVEL(*arg); | ||
510 | TRACE(TRACE_LEVEL, "tracing set to %d", TRACE_LEVEL); | ||
511 | if ((int)TRACE_LEVEL != *arg) { | ||
512 | TRACE_EXIT -EINVAL; | ||
513 | } | ||
514 | TRACE_EXIT 0; | ||
515 | } | ||
516 | |||
517 | static int mt_seek(int *new_block_pos) | ||
518 | { | ||
519 | int result= 0; | ||
520 | TRACE_FUN(ft_t_any); | ||
521 | |||
522 | result = seek_block(0, (__s64)*new_block_pos, &zft_pos); | ||
523 | TRACE_EXIT result; | ||
524 | } | ||
525 | |||
526 | /* OK, this is totally different from SCSI, but the worst thing that can | ||
527 | * happen is that there is not enough defragmentated memory that can be | ||
528 | * allocated. Also, there is a hardwired limit of 16 dma buffers in the | ||
529 | * stock ftape module. This shouldn't bring the system down. | ||
530 | * | ||
531 | * NOTE: the argument specifies the total number of dma buffers to use. | ||
532 | * The driver needs at least 3 buffers to function at all. | ||
533 | * | ||
534 | */ | ||
535 | static int mt_setdrvbuffer(int *cnt) | ||
536 | { | ||
537 | TRACE_FUN(ft_t_flow); | ||
538 | |||
539 | if (*cnt < 3) { | ||
540 | TRACE_EXIT -EINVAL; | ||
541 | } | ||
542 | TRACE_CATCH(ftape_set_nr_buffers(*cnt),); | ||
543 | TRACE_EXIT 0; | ||
544 | } | ||
545 | /* return the block position from start of volume | ||
546 | */ | ||
547 | static int mt_tell(int *arg) | ||
548 | { | ||
549 | TRACE_FUN(ft_t_flow); | ||
550 | |||
551 | *arg = zft_div_blksz(zft_pos.volume_pos, | ||
552 | zft_find_volume(zft_pos.seg_pos)->blk_sz); | ||
553 | TRACE_EXIT 0; | ||
554 | } | ||
555 | |||
556 | static int mt_compression(int *arg) | ||
557 | { | ||
558 | TRACE_FUN(ft_t_flow); | ||
559 | |||
560 | /* Ok. We could also check whether compression is available at | ||
561 | * all by trying to load the compression module. We could | ||
562 | * also check for a block size of 1 byte which is illegal | ||
563 | * with compression. Instead of doing it here we rely on | ||
564 | * zftape_write() to do the proper checks. | ||
565 | */ | ||
566 | if ((unsigned int)*arg > 1) { | ||
567 | TRACE_EXIT -EINVAL; | ||
568 | } | ||
569 | if (*arg != 0 && zft_blk_sz == 1) { /* variable block size */ | ||
570 | TRACE_ABORT(-EINVAL, ft_t_info, | ||
571 | "Compression not yet supported " | ||
572 | "with variable block size"); | ||
573 | } | ||
574 | zft_mt_compression = *arg; | ||
575 | if ((zft_unit & ZFT_ZIP_MODE) == 0) { | ||
576 | zft_use_compression = zft_mt_compression; | ||
577 | } | ||
578 | TRACE_EXIT 0; | ||
579 | } | ||
580 | |||
581 | /* check whether write access is allowed. Write access is denied when | ||
582 | * + zft_write_protected == 1 -- this accounts for either hard write | ||
583 | * protection of the cartridge or for | ||
584 | * O_RDONLY access mode of the tape device | ||
585 | * + zft_offline == 1 -- this meany that there is either no tape | ||
586 | * or that the MTOFFLINE ioctl has been | ||
587 | * previously issued (`soft eject') | ||
588 | * + ft_formatted == 0 -- this means that the cartridge is not | ||
589 | * formatted | ||
590 | * Then we distinuguish two cases. When zft_qic_mode is TRUE, then we try | ||
591 | * to emulate a `traditional' (aka SCSI like) UN*X tape device. Therefore we | ||
592 | * deny writes when | ||
593 | * + zft_qic_mode ==1 && | ||
594 | * (!zft_tape_at_lbot() && -- tape no at logical BOT | ||
595 | * !(zft_tape_at_eom() || -- tape not at logical EOM (or EOD) | ||
596 | * (zft_tape_at_eom() && | ||
597 | * zft_old_ftape()))) -- we can't add new volume to tapes | ||
598 | * written by old ftape because ftape | ||
599 | * don't use the volume table | ||
600 | * | ||
601 | * when the drive is in true raw mode (aka /dev/rawft0) then we don't | ||
602 | * care about LBOT and EOM conditions. This device is intended for a | ||
603 | * user level program that wants to truly implement the QIC-80 compliance | ||
604 | * at the logical data layout level of the cartridge, i.e. implement all | ||
605 | * that volume table and volume directory stuff etc.< | ||
606 | */ | ||
607 | int zft_check_write_access(zft_position *pos) | ||
608 | { | ||
609 | TRACE_FUN(ft_t_flow); | ||
610 | |||
611 | if (zft_offline) { /* offline includes no_tape */ | ||
612 | TRACE_ABORT(-ENXIO, | ||
613 | ft_t_info, "tape is offline or no cartridge"); | ||
614 | } | ||
615 | if (!ft_formatted) { | ||
616 | TRACE_ABORT(-EACCES, ft_t_info, "tape is not formatted"); | ||
617 | } | ||
618 | if (zft_write_protected) { | ||
619 | TRACE_ABORT(-EACCES, ft_t_info, "cartridge write protected"); | ||
620 | } | ||
621 | if (zft_qic_mode) { | ||
622 | /* check BOT condition */ | ||
623 | if (!zft_tape_at_lbot(pos)) { | ||
624 | /* protect cartridges written by old ftape if | ||
625 | * not at BOT because they use the vtbl | ||
626 | * segment for storing data | ||
627 | */ | ||
628 | if (zft_old_ftape) { | ||
629 | TRACE_ABORT(-EACCES, ft_t_warn, | ||
630 | "Cannot write to cartridges written by old ftape when not at BOT"); | ||
631 | } | ||
632 | /* not at BOT, but allow writes at EOD, of course | ||
633 | */ | ||
634 | if (!zft_tape_at_eod(pos)) { | ||
635 | TRACE_ABORT(-EACCES, ft_t_info, | ||
636 | "tape not at BOT and not at EOD"); | ||
637 | } | ||
638 | } | ||
639 | /* fine. Now the tape is either at BOT or at EOD. */ | ||
640 | } | ||
641 | /* or in raw mode in which case we don't care about BOT and EOD */ | ||
642 | TRACE_EXIT 0; | ||
643 | } | ||
644 | |||
645 | /* OPEN routine called by kernel-interface code | ||
646 | * | ||
647 | * NOTE: this is also called by mt_reset() with dev_minor == -1 | ||
648 | * to fake a reopen after a reset. | ||
649 | */ | ||
650 | int _zft_open(unsigned int dev_minor, unsigned int access_mode) | ||
651 | { | ||
652 | static unsigned int tape_unit; | ||
653 | static unsigned int file_access_mode; | ||
654 | int result; | ||
655 | TRACE_FUN(ft_t_flow); | ||
656 | |||
657 | if ((int)dev_minor == -1) { | ||
658 | /* fake reopen */ | ||
659 | zft_unit = tape_unit; | ||
660 | access_mode = file_access_mode; | ||
661 | zft_init_driver(); /* reset all static data to defaults */ | ||
662 | } else { | ||
663 | tape_unit = dev_minor; | ||
664 | file_access_mode = access_mode; | ||
665 | if ((result = ftape_enable(FTAPE_SEL(dev_minor))) < 0) { | ||
666 | TRACE_ABORT(-ENXIO, ft_t_err, | ||
667 | "ftape_enable failed: %d", result); | ||
668 | } | ||
669 | if (ft_new_tape || ft_no_tape || !ft_formatted || | ||
670 | (FTAPE_SEL(zft_unit) != FTAPE_SEL(dev_minor)) || | ||
671 | (zft_unit & ZFT_RAW_MODE) != (dev_minor & ZFT_RAW_MODE)) { | ||
672 | /* reset all static data to defaults, | ||
673 | */ | ||
674 | zft_init_driver(); | ||
675 | } | ||
676 | zft_unit = dev_minor; | ||
677 | } | ||
678 | zft_set_flags(zft_unit); /* decode the minor bits */ | ||
679 | if (zft_blk_sz == 1 && zft_use_compression) { | ||
680 | ftape_disable(); /* resets ft_no_tape */ | ||
681 | TRACE_ABORT(-ENODEV, ft_t_warn, "Variable block size not yet " | ||
682 | "supported with compression"); | ||
683 | } | ||
684 | /* no need for most of the buffers when no tape or not | ||
685 | * formatted. for the read/write operations, it is the | ||
686 | * regardless whether there is no tape, a not-formatted tape | ||
687 | * or the whether the driver is soft offline. | ||
688 | * Nevertheless we allow some ioctls with non-formatted tapes, | ||
689 | * like rewind and reset. | ||
690 | */ | ||
691 | if (ft_no_tape || !ft_formatted) { | ||
692 | zft_uninit_mem(); | ||
693 | } | ||
694 | if (ft_no_tape) { | ||
695 | zft_offline = 1; /* so we need not test two variables */ | ||
696 | } | ||
697 | if ((access_mode == O_WRONLY || access_mode == O_RDWR) && | ||
698 | (ft_write_protected || ft_no_tape)) { | ||
699 | ftape_disable(); /* resets ft_no_tape */ | ||
700 | TRACE_ABORT(ft_no_tape ? -ENXIO : -EROFS, | ||
701 | ft_t_warn, "wrong access mode %s cartridge", | ||
702 | ft_no_tape ? "without a" : "with write protected"); | ||
703 | } | ||
704 | zft_write_protected = (access_mode == O_RDONLY || | ||
705 | ft_write_protected != 0); | ||
706 | if (zft_write_protected) { | ||
707 | TRACE(ft_t_noise, | ||
708 | "read only access mode: %d, " | ||
709 | "drive write protected: %d", | ||
710 | access_mode == O_RDONLY, | ||
711 | ft_write_protected != 0); | ||
712 | } | ||
713 | if (!zft_offline) { | ||
714 | TRACE_CATCH(zft_vmalloc_once(&zft_deblock_buf,FT_SEGMENT_SIZE), | ||
715 | ftape_disable()); | ||
716 | } | ||
717 | /* zft_seg_pos should be greater than the vtbl segpos but not | ||
718 | * if in compatibility mode and only after we read in the | ||
719 | * header segments | ||
720 | * | ||
721 | * might also be a problem if the user makes a backup with a | ||
722 | * *qft* device and rewinds it with a raw device. | ||
723 | */ | ||
724 | if (zft_qic_mode && | ||
725 | !zft_old_ftape && | ||
726 | zft_pos.seg_pos >= 0 && | ||
727 | zft_header_read && | ||
728 | zft_pos.seg_pos <= ft_first_data_segment) { | ||
729 | TRACE(ft_t_noise, "you probably mixed up the zftape devices!"); | ||
730 | zft_reset_position(&zft_pos); | ||
731 | } | ||
732 | TRACE_EXIT 0; | ||
733 | } | ||
734 | |||
735 | /* RELEASE routine called by kernel-interface code | ||
736 | */ | ||
737 | int _zft_close(void) | ||
738 | { | ||
739 | int result = 0; | ||
740 | TRACE_FUN(ft_t_flow); | ||
741 | |||
742 | if (zft_offline) { | ||
743 | /* call the hardware release routine. Puts the drive offline */ | ||
744 | ftape_disable(); | ||
745 | TRACE_EXIT 0; | ||
746 | } | ||
747 | if (!(ft_write_protected || zft_old_ftape)) { | ||
748 | result = zft_flush_buffers(); | ||
749 | TRACE(ft_t_noise, "writing file mark at current position"); | ||
750 | if (zft_qic_mode && zft_close_volume(&zft_pos) == 0) { | ||
751 | zft_move_past_eof(&zft_pos); | ||
752 | } | ||
753 | if ((zft_tape_at_lbot(&zft_pos) || | ||
754 | !(zft_unit & FTAPE_NO_REWIND))) { | ||
755 | if (result >= 0) { | ||
756 | result = zft_update_header_segments(); | ||
757 | } else { | ||
758 | TRACE(ft_t_err, | ||
759 | "Error: unable to update header segments"); | ||
760 | } | ||
761 | } | ||
762 | } | ||
763 | ftape_abort_operation(); | ||
764 | if (!(zft_unit & FTAPE_NO_REWIND)) { | ||
765 | TRACE(ft_t_noise, "rewinding tape"); | ||
766 | if (ftape_seek_to_bot() < 0 && result >= 0) { | ||
767 | result = -EIO; /* keep old value */ | ||
768 | } | ||
769 | zft_reset_position(&zft_pos); | ||
770 | } | ||
771 | zft_zap_read_buffers(); | ||
772 | /* now free up memory as much as possible. We don't destroy | ||
773 | * the deblock buffer if it containes a valid segment. | ||
774 | */ | ||
775 | if (zft_deblock_segment == -1) { | ||
776 | zft_vfree(&zft_deblock_buf, FT_SEGMENT_SIZE); | ||
777 | } | ||
778 | /* high level driver status, forces creation of a new volume | ||
779 | * when calling ftape_write again and not zft_just_before_eof | ||
780 | */ | ||
781 | zft_io_state = zft_idle; | ||
782 | if (going_offline) { | ||
783 | zft_init_driver(); | ||
784 | zft_uninit_mem(); | ||
785 | going_offline = 0; | ||
786 | zft_offline = 1; | ||
787 | } else if (zft_cmpr_lock(0 /* don't load */) == 0) { | ||
788 | (*zft_cmpr_ops->reset)(); /* unlock it again */ | ||
789 | } | ||
790 | zft_memory_stats(); | ||
791 | /* call the hardware release routine. Puts the drive offline */ | ||
792 | ftape_disable(); | ||
793 | TRACE_EXIT result; | ||
794 | } | ||
795 | |||
796 | /* | ||
797 | * the wrapper function around the wrapper MTIOCTOP ioctl | ||
798 | */ | ||
799 | static int mtioctop(struct mtop *mtop, int arg_size) | ||
800 | { | ||
801 | int result = 0; | ||
802 | fun_entry *mt_fun_entry; | ||
803 | TRACE_FUN(ft_t_flow); | ||
804 | |||
805 | if (arg_size != sizeof(struct mtop) || mtop->mt_op >= NR_MT_CMDS) { | ||
806 | TRACE_EXIT -EINVAL; | ||
807 | } | ||
808 | TRACE(ft_t_noise, "calling MTIOCTOP command: %s", | ||
809 | mt_funs[mtop->mt_op].name); | ||
810 | mt_fun_entry= &mt_funs[mtop->mt_op]; | ||
811 | zft_resid = mtop->mt_count; | ||
812 | if (!mt_fun_entry->offline && zft_offline) { | ||
813 | if (ft_no_tape) { | ||
814 | TRACE_ABORT(-ENXIO, ft_t_info, "no tape present"); | ||
815 | } else { | ||
816 | TRACE_ABORT(-ENXIO, ft_t_info, "drive is offline"); | ||
817 | } | ||
818 | } | ||
819 | if (!mt_fun_entry->not_formatted && !ft_formatted) { | ||
820 | TRACE_ABORT(-EACCES, ft_t_info, "tape is not formatted"); | ||
821 | } | ||
822 | if (!mt_fun_entry->write_protected) { | ||
823 | TRACE_CATCH(zft_check_write_access(&zft_pos),); | ||
824 | } | ||
825 | if (mt_fun_entry->need_idle_state && !(zft_offline || !ft_formatted)) { | ||
826 | TRACE_CATCH(zft_def_idle_state(),); | ||
827 | } | ||
828 | if (!zft_qic_mode && !mt_fun_entry->raw_mode) { | ||
829 | TRACE_ABORT(-EACCES, ft_t_info, | ||
830 | "Drive needs to be in QIC-80 compatibility mode for this command"); | ||
831 | } | ||
832 | result = (mt_fun_entry->function)(&mtop->mt_count); | ||
833 | if (zft_tape_at_lbot(&zft_pos)) { | ||
834 | TRACE_CATCH(zft_update_header_segments(),); | ||
835 | } | ||
836 | if (result >= 0) { | ||
837 | zft_resid = 0; | ||
838 | } | ||
839 | TRACE_EXIT result; | ||
840 | } | ||
841 | |||
842 | /* | ||
843 | * standard MTIOCGET ioctl | ||
844 | */ | ||
845 | static int mtiocget(struct mtget *mtget, int arg_size) | ||
846 | { | ||
847 | const zft_volinfo *volume; | ||
848 | __s64 max_tape_pos; | ||
849 | TRACE_FUN(ft_t_flow); | ||
850 | |||
851 | if (arg_size != sizeof(struct mtget)) { | ||
852 | TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", | ||
853 | arg_size); | ||
854 | } | ||
855 | mtget->mt_type = ft_drive_type.vendor_id + 0x800000; | ||
856 | mtget->mt_dsreg = ft_last_status.space; | ||
857 | mtget->mt_erreg = ft_last_error.space; /* error register */ | ||
858 | mtget->mt_resid = zft_resid; /* residuum of writes, reads and | ||
859 | * MTIOCTOP commands | ||
860 | */ | ||
861 | if (!zft_offline) { /* neither no_tape nor soft offline */ | ||
862 | mtget->mt_gstat = GMT_ONLINE(~0UL); | ||
863 | /* should rather return the status of the cartridge | ||
864 | * than the access mode of the file, therefor use | ||
865 | * ft_write_protected, not zft_write_protected | ||
866 | */ | ||
867 | if (ft_write_protected) { | ||
868 | mtget->mt_gstat |= GMT_WR_PROT(~0UL); | ||
869 | } | ||
870 | if(zft_header_read) { /* this catches non-formatted */ | ||
871 | volume = zft_find_volume(zft_pos.seg_pos); | ||
872 | mtget->mt_fileno = volume->count; | ||
873 | max_tape_pos = zft_capacity - zft_blk_sz; | ||
874 | if (zft_use_compression) { | ||
875 | max_tape_pos -= ZFT_CMPR_OVERHEAD; | ||
876 | } | ||
877 | if (zft_tape_at_eod(&zft_pos)) { | ||
878 | mtget->mt_gstat |= GMT_EOD(~0UL); | ||
879 | } | ||
880 | if (zft_pos.tape_pos > max_tape_pos) { | ||
881 | mtget->mt_gstat |= GMT_EOT(~0UL); | ||
882 | } | ||
883 | mtget->mt_blkno = zft_div_blksz(zft_pos.volume_pos, | ||
884 | volume->blk_sz); | ||
885 | if (zft_just_before_eof) { | ||
886 | mtget->mt_gstat |= GMT_EOF(~0UL); | ||
887 | } | ||
888 | if (zft_tape_at_lbot(&zft_pos)) { | ||
889 | mtget->mt_gstat |= GMT_BOT(~0UL); | ||
890 | } | ||
891 | } else { | ||
892 | mtget->mt_fileno = mtget->mt_blkno = -1; | ||
893 | if (mtget->mt_dsreg & QIC_STATUS_AT_BOT) { | ||
894 | mtget->mt_gstat |= GMT_BOT(~0UL); | ||
895 | } | ||
896 | } | ||
897 | } else { | ||
898 | if (ft_no_tape) { | ||
899 | mtget->mt_gstat = GMT_DR_OPEN(~0UL); | ||
900 | } else { | ||
901 | mtget->mt_gstat = 0UL; | ||
902 | } | ||
903 | mtget->mt_fileno = mtget->mt_blkno = -1; | ||
904 | } | ||
905 | TRACE_EXIT 0; | ||
906 | } | ||
907 | |||
908 | #ifdef MTIOCRDFTSEG | ||
909 | /* | ||
910 | * Read a floppy tape segment. This is useful for manipulating the | ||
911 | * volume table, and read the old header segment before re-formatting | ||
912 | * the cartridge. | ||
913 | */ | ||
914 | static int mtiocrdftseg(struct mtftseg * mtftseg, int arg_size) | ||
915 | { | ||
916 | TRACE_FUN(ft_t_flow); | ||
917 | |||
918 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCRDFTSEG"); | ||
919 | if (zft_qic_mode) { | ||
920 | TRACE_ABORT(-EACCES, ft_t_info, | ||
921 | "driver needs to be in raw mode for this ioctl"); | ||
922 | } | ||
923 | if (arg_size != sizeof(struct mtftseg)) { | ||
924 | TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", | ||
925 | arg_size); | ||
926 | } | ||
927 | if (zft_offline) { | ||
928 | TRACE_EXIT -ENXIO; | ||
929 | } | ||
930 | if (mtftseg->mt_mode != FT_RD_SINGLE && | ||
931 | mtftseg->mt_mode != FT_RD_AHEAD) { | ||
932 | TRACE_ABORT(-EINVAL, ft_t_info, "invalid read mode"); | ||
933 | } | ||
934 | if (!ft_formatted) { | ||
935 | TRACE_EXIT -EACCES; /* -ENXIO ? */ | ||
936 | |||
937 | } | ||
938 | if (!zft_header_read) { | ||
939 | TRACE_CATCH(zft_def_idle_state(),); | ||
940 | } | ||
941 | if (mtftseg->mt_segno > ft_last_data_segment) { | ||
942 | TRACE_ABORT(-EINVAL, ft_t_info, "segment number is too large"); | ||
943 | } | ||
944 | mtftseg->mt_result = ftape_read_segment(mtftseg->mt_segno, | ||
945 | zft_deblock_buf, | ||
946 | mtftseg->mt_mode); | ||
947 | if (mtftseg->mt_result < 0) { | ||
948 | /* a negativ result is not an ioctl error. if | ||
949 | * the user wants to read damaged tapes, | ||
950 | * it's up to her/him | ||
951 | */ | ||
952 | TRACE_EXIT 0; | ||
953 | } | ||
954 | if (copy_to_user(mtftseg->mt_data, | ||
955 | zft_deblock_buf, | ||
956 | mtftseg->mt_result) != 0) { | ||
957 | TRACE_EXIT -EFAULT; | ||
958 | } | ||
959 | TRACE_EXIT 0; | ||
960 | } | ||
961 | #endif | ||
962 | |||
963 | #ifdef MTIOCWRFTSEG | ||
964 | /* | ||
965 | * write a floppy tape segment. This version features writing of | ||
966 | * deleted address marks, and gracefully ignores the (software) | ||
967 | * ft_formatted flag to support writing of header segments after | ||
968 | * formatting. | ||
969 | */ | ||
970 | static int mtiocwrftseg(struct mtftseg * mtftseg, int arg_size) | ||
971 | { | ||
972 | int result; | ||
973 | TRACE_FUN(ft_t_flow); | ||
974 | |||
975 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCWRFTSEG"); | ||
976 | if (zft_write_protected || zft_qic_mode) { | ||
977 | TRACE_EXIT -EACCES; | ||
978 | } | ||
979 | if (arg_size != sizeof(struct mtftseg)) { | ||
980 | TRACE_ABORT(-EINVAL, ft_t_info, "bad argument size: %d", | ||
981 | arg_size); | ||
982 | } | ||
983 | if (zft_offline) { | ||
984 | TRACE_EXIT -ENXIO; | ||
985 | } | ||
986 | if (mtftseg->mt_mode != FT_WR_ASYNC && | ||
987 | mtftseg->mt_mode != FT_WR_MULTI && | ||
988 | mtftseg->mt_mode != FT_WR_SINGLE && | ||
989 | mtftseg->mt_mode != FT_WR_DELETE) { | ||
990 | TRACE_ABORT(-EINVAL, ft_t_info, "invalid write mode"); | ||
991 | } | ||
992 | /* | ||
993 | * We don't check for ft_formatted, because this gives | ||
994 | * only the software status of the driver. | ||
995 | * | ||
996 | * We assume that the user knows what it is | ||
997 | * doing. And rely on the low level stuff to fail | ||
998 | * when the tape isn't formatted. We only make sure | ||
999 | * that The header segment buffer is allocated, | ||
1000 | * because it holds the bad sector map. | ||
1001 | */ | ||
1002 | if (zft_hseg_buf == NULL) { | ||
1003 | TRACE_EXIT -ENXIO; | ||
1004 | } | ||
1005 | if (mtftseg->mt_mode != FT_WR_DELETE) { | ||
1006 | if (copy_from_user(zft_deblock_buf, | ||
1007 | mtftseg->mt_data, | ||
1008 | FT_SEGMENT_SIZE) != 0) { | ||
1009 | TRACE_EXIT -EFAULT; | ||
1010 | } | ||
1011 | } | ||
1012 | mtftseg->mt_result = ftape_write_segment(mtftseg->mt_segno, | ||
1013 | zft_deblock_buf, | ||
1014 | mtftseg->mt_mode); | ||
1015 | if (mtftseg->mt_result >= 0 && mtftseg->mt_mode == FT_WR_SINGLE) { | ||
1016 | /* | ||
1017 | * a negativ result is not an ioctl error. if | ||
1018 | * the user wants to write damaged tapes, | ||
1019 | * it's up to her/him | ||
1020 | */ | ||
1021 | if ((result = ftape_loop_until_writes_done()) < 0) { | ||
1022 | mtftseg->mt_result = result; | ||
1023 | } | ||
1024 | } | ||
1025 | TRACE_EXIT 0; | ||
1026 | } | ||
1027 | #endif | ||
1028 | |||
1029 | #ifdef MTIOCVOLINFO | ||
1030 | /* | ||
1031 | * get information about volume positioned at. | ||
1032 | */ | ||
1033 | static int mtiocvolinfo(struct mtvolinfo *volinfo, int arg_size) | ||
1034 | { | ||
1035 | const zft_volinfo *volume; | ||
1036 | TRACE_FUN(ft_t_flow); | ||
1037 | |||
1038 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCVOLINFO"); | ||
1039 | if (arg_size != sizeof(struct mtvolinfo)) { | ||
1040 | TRACE_ABORT(-EINVAL, | ||
1041 | ft_t_info, "bad argument size: %d", arg_size); | ||
1042 | } | ||
1043 | if (zft_offline) { | ||
1044 | TRACE_EXIT -ENXIO; | ||
1045 | } | ||
1046 | if (!ft_formatted) { | ||
1047 | TRACE_EXIT -EACCES; | ||
1048 | } | ||
1049 | TRACE_CATCH(zft_def_idle_state(),); | ||
1050 | volume = zft_find_volume(zft_pos.seg_pos); | ||
1051 | volinfo->mt_volno = volume->count; | ||
1052 | volinfo->mt_blksz = volume->blk_sz == 1 ? 0 : volume->blk_sz; | ||
1053 | volinfo->mt_size = volume->size >> 10; | ||
1054 | volinfo->mt_rawsize = ((zft_calc_tape_pos(volume->end_seg + 1) >> 10) - | ||
1055 | (zft_calc_tape_pos(volume->start_seg) >> 10)); | ||
1056 | volinfo->mt_cmpr = volume->use_compression; | ||
1057 | TRACE_EXIT 0; | ||
1058 | } | ||
1059 | #endif | ||
1060 | |||
1061 | #ifdef ZFT_OBSOLETE | ||
1062 | static int mtioc_zftape_getblksz(struct mtblksz *blksz, int arg_size) | ||
1063 | { | ||
1064 | TRACE_FUN(ft_t_flow); | ||
1065 | |||
1066 | TRACE(ft_t_noise, "\n" | ||
1067 | KERN_INFO "Mag tape ioctl command: MTIOC_ZTAPE_GETBLKSZ\n" | ||
1068 | KERN_INFO "This ioctl is here merely for compatibility.\n" | ||
1069 | KERN_INFO "Please use MTIOCVOLINFO instead"); | ||
1070 | if (arg_size != sizeof(struct mtblksz)) { | ||
1071 | TRACE_ABORT(-EINVAL, | ||
1072 | ft_t_info, "bad argument size: %d", arg_size); | ||
1073 | } | ||
1074 | if (zft_offline) { | ||
1075 | TRACE_EXIT -ENXIO; | ||
1076 | } | ||
1077 | if (!ft_formatted) { | ||
1078 | TRACE_EXIT -EACCES; | ||
1079 | } | ||
1080 | TRACE_CATCH(zft_def_idle_state(),); | ||
1081 | blksz->mt_blksz = zft_find_volume(zft_pos.seg_pos)->blk_sz; | ||
1082 | TRACE_EXIT 0; | ||
1083 | } | ||
1084 | #endif | ||
1085 | |||
1086 | #ifdef MTIOCGETSIZE | ||
1087 | /* | ||
1088 | * get the capacity of the tape cartridge. | ||
1089 | */ | ||
1090 | static int mtiocgetsize(struct mttapesize *size, int arg_size) | ||
1091 | { | ||
1092 | TRACE_FUN(ft_t_flow); | ||
1093 | |||
1094 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOC_ZFTAPE_GETSIZE"); | ||
1095 | if (arg_size != sizeof(struct mttapesize)) { | ||
1096 | TRACE_ABORT(-EINVAL, | ||
1097 | ft_t_info, "bad argument size: %d", arg_size); | ||
1098 | } | ||
1099 | if (zft_offline) { | ||
1100 | TRACE_EXIT -ENXIO; | ||
1101 | } | ||
1102 | if (!ft_formatted) { | ||
1103 | TRACE_EXIT -EACCES; | ||
1104 | } | ||
1105 | TRACE_CATCH(zft_def_idle_state(),); | ||
1106 | size->mt_capacity = (unsigned int)(zft_capacity>>10); | ||
1107 | size->mt_used = (unsigned int)(zft_get_eom_pos()>>10); | ||
1108 | TRACE_EXIT 0; | ||
1109 | } | ||
1110 | #endif | ||
1111 | |||
1112 | static int mtiocpos(struct mtpos *mtpos, int arg_size) | ||
1113 | { | ||
1114 | int result; | ||
1115 | TRACE_FUN(ft_t_flow); | ||
1116 | |||
1117 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCPOS"); | ||
1118 | if (arg_size != sizeof(struct mtpos)) { | ||
1119 | TRACE_ABORT(-EINVAL, | ||
1120 | ft_t_info, "bad argument size: %d", arg_size); | ||
1121 | } | ||
1122 | result = mt_tell((int *)&mtpos->mt_blkno); | ||
1123 | TRACE_EXIT result; | ||
1124 | } | ||
1125 | |||
1126 | #ifdef MTIOCFTFORMAT | ||
1127 | /* | ||
1128 | * formatting of floppy tape cartridges. This is intended to be used | ||
1129 | * together with the MTIOCFTCMD ioctl and the new mmap feature | ||
1130 | */ | ||
1131 | |||
1132 | /* | ||
1133 | * This function uses ftape_decode_header_segment() to inform the low | ||
1134 | * level ftape module about the new parameters. | ||
1135 | * | ||
1136 | * It erases the hseg_buf. The calling process must specify all | ||
1137 | * parameters to assure proper operation. | ||
1138 | * | ||
1139 | * return values: -EINVAL - wrong argument size | ||
1140 | * -EINVAL - if ftape_decode_header_segment() failed. | ||
1141 | */ | ||
1142 | static int set_format_parms(struct ftfmtparms *p, __u8 *hseg_buf) | ||
1143 | { | ||
1144 | ft_trace_t old_level = TRACE_LEVEL; | ||
1145 | TRACE_FUN(ft_t_flow); | ||
1146 | |||
1147 | TRACE(ft_t_noise, "MTIOCFTFORMAT operation FTFMT_SETPARMS"); | ||
1148 | memset(hseg_buf, 0, FT_SEGMENT_SIZE); | ||
1149 | PUT4(hseg_buf, FT_SIGNATURE, FT_HSEG_MAGIC); | ||
1150 | |||
1151 | /* fill in user specified parameters | ||
1152 | */ | ||
1153 | hseg_buf[FT_FMT_CODE] = (__u8)p->ft_fmtcode; | ||
1154 | PUT2(hseg_buf, FT_SPT, p->ft_spt); | ||
1155 | hseg_buf[FT_TPC] = (__u8)p->ft_tpc; | ||
1156 | hseg_buf[FT_FHM] = (__u8)p->ft_fhm; | ||
1157 | hseg_buf[FT_FTM] = (__u8)p->ft_ftm; | ||
1158 | |||
1159 | /* fill in sane defaults to make ftape happy. | ||
1160 | */ | ||
1161 | hseg_buf[FT_FSM] = (__u8)128; /* 128 is hard wired all over ftape */ | ||
1162 | if (p->ft_fmtcode == fmt_big) { | ||
1163 | PUT4(hseg_buf, FT_6_HSEG_1, 0); | ||
1164 | PUT4(hseg_buf, FT_6_HSEG_2, 1); | ||
1165 | PUT4(hseg_buf, FT_6_FRST_SEG, 2); | ||
1166 | PUT4(hseg_buf, FT_6_LAST_SEG, p->ft_spt * p->ft_tpc - 1); | ||
1167 | } else { | ||
1168 | PUT2(hseg_buf, FT_HSEG_1, 0); | ||
1169 | PUT2(hseg_buf, FT_HSEG_2, 1); | ||
1170 | PUT2(hseg_buf, FT_FRST_SEG, 2); | ||
1171 | PUT2(hseg_buf, FT_LAST_SEG, p->ft_spt * p->ft_tpc - 1); | ||
1172 | } | ||
1173 | |||
1174 | /* Synchronize with the low level module. This is particularly | ||
1175 | * needed for unformatted cartridges as the QIC std was previously | ||
1176 | * unknown BUT is needed to set data rate and to calculate timeouts. | ||
1177 | */ | ||
1178 | TRACE_CATCH(ftape_calibrate_data_rate(p->ft_qicstd&QIC_TAPE_STD_MASK), | ||
1179 | _res = -EINVAL); | ||
1180 | |||
1181 | /* The following will also recalcualte the timeouts for the tape | ||
1182 | * length and QIC std we want to format to. | ||
1183 | * abort with -EINVAL rather than -EIO | ||
1184 | */ | ||
1185 | SET_TRACE_LEVEL(ft_t_warn); | ||
1186 | TRACE_CATCH(ftape_decode_header_segment(hseg_buf), | ||
1187 | SET_TRACE_LEVEL(old_level); _res = -EINVAL); | ||
1188 | SET_TRACE_LEVEL(old_level); | ||
1189 | TRACE_EXIT 0; | ||
1190 | } | ||
1191 | |||
1192 | /* | ||
1193 | * Return the internal SOFTWARE status of the kernel driver. This does | ||
1194 | * NOT query the tape drive about its status. | ||
1195 | */ | ||
1196 | static int get_format_parms(struct ftfmtparms *p, __u8 *hseg_buffer) | ||
1197 | { | ||
1198 | TRACE_FUN(ft_t_flow); | ||
1199 | |||
1200 | TRACE(ft_t_noise, "MTIOCFTFORMAT operation FTFMT_GETPARMS"); | ||
1201 | p->ft_qicstd = ft_qic_std; | ||
1202 | p->ft_fmtcode = ft_format_code; | ||
1203 | p->ft_fhm = hseg_buffer[FT_FHM]; | ||
1204 | p->ft_ftm = hseg_buffer[FT_FTM]; | ||
1205 | p->ft_spt = ft_segments_per_track; | ||
1206 | p->ft_tpc = ft_tracks_per_tape; | ||
1207 | TRACE_EXIT 0; | ||
1208 | } | ||
1209 | |||
1210 | static int mtiocftformat(struct mtftformat *mtftformat, int arg_size) | ||
1211 | { | ||
1212 | int result; | ||
1213 | union fmt_arg *arg = &mtftformat->fmt_arg; | ||
1214 | TRACE_FUN(ft_t_flow); | ||
1215 | |||
1216 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCFTFORMAT"); | ||
1217 | if (zft_offline) { | ||
1218 | if (ft_no_tape) { | ||
1219 | TRACE_ABORT(-ENXIO, ft_t_info, "no tape present"); | ||
1220 | } else { | ||
1221 | TRACE_ABORT(-ENXIO, ft_t_info, "drive is offline"); | ||
1222 | } | ||
1223 | } | ||
1224 | if (zft_qic_mode) { | ||
1225 | TRACE_ABORT(-EACCES, ft_t_info, | ||
1226 | "driver needs to be in raw mode for this ioctl"); | ||
1227 | } | ||
1228 | if (zft_hseg_buf == NULL) { | ||
1229 | TRACE_CATCH(zft_vcalloc_once(&zft_hseg_buf, FT_SEGMENT_SIZE),); | ||
1230 | } | ||
1231 | zft_header_read = 0; | ||
1232 | switch(mtftformat->fmt_op) { | ||
1233 | case FTFMT_SET_PARMS: | ||
1234 | TRACE_CATCH(set_format_parms(&arg->fmt_parms, zft_hseg_buf),); | ||
1235 | TRACE_EXIT 0; | ||
1236 | case FTFMT_GET_PARMS: | ||
1237 | TRACE_CATCH(get_format_parms(&arg->fmt_parms, zft_hseg_buf),); | ||
1238 | TRACE_EXIT 0; | ||
1239 | case FTFMT_FORMAT_TRACK: | ||
1240 | if ((ft_formatted && zft_check_write_access(&zft_pos) < 0) || | ||
1241 | (!ft_formatted && zft_write_protected)) { | ||
1242 | TRACE_ABORT(-EACCES, ft_t_info, "Write access denied"); | ||
1243 | } | ||
1244 | TRACE_CATCH(ftape_format_track(arg->fmt_track.ft_track, | ||
1245 | arg->fmt_track.ft_gap3),); | ||
1246 | TRACE_EXIT 0; | ||
1247 | case FTFMT_STATUS: | ||
1248 | TRACE_CATCH(ftape_format_status(&arg->fmt_status.ft_segment),); | ||
1249 | TRACE_EXIT 0; | ||
1250 | case FTFMT_VERIFY: | ||
1251 | TRACE_CATCH(ftape_verify_segment(arg->fmt_verify.ft_segment, | ||
1252 | (SectorMap *)&arg->fmt_verify.ft_bsm),); | ||
1253 | TRACE_EXIT 0; | ||
1254 | default: | ||
1255 | TRACE_ABORT(-EINVAL, ft_t_err, "Invalid format operation"); | ||
1256 | } | ||
1257 | TRACE_EXIT result; | ||
1258 | } | ||
1259 | #endif | ||
1260 | |||
1261 | #ifdef MTIOCFTCMD | ||
1262 | /* | ||
1263 | * send a QIC-117 command to the drive, with optional timeouts, | ||
1264 | * parameter and result bits. This is intended to be used together | ||
1265 | * with the formatting ioctl. | ||
1266 | */ | ||
1267 | static int mtiocftcmd(struct mtftcmd *ftcmd, int arg_size) | ||
1268 | { | ||
1269 | int i; | ||
1270 | TRACE_FUN(ft_t_flow); | ||
1271 | |||
1272 | TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCFTCMD"); | ||
1273 | if (!capable(CAP_SYS_ADMIN)) { | ||
1274 | TRACE_ABORT(-EPERM, ft_t_info, | ||
1275 | "need CAP_SYS_ADMIN capability to send raw qic-117 commands"); | ||
1276 | } | ||
1277 | if (zft_qic_mode) { | ||
1278 | TRACE_ABORT(-EACCES, ft_t_info, | ||
1279 | "driver needs to be in raw mode for this ioctl"); | ||
1280 | } | ||
1281 | if (arg_size != sizeof(struct mtftcmd)) { | ||
1282 | TRACE_ABORT(-EINVAL, | ||
1283 | ft_t_info, "bad argument size: %d", arg_size); | ||
1284 | } | ||
1285 | if (ftcmd->ft_wait_before) { | ||
1286 | TRACE_CATCH(ftape_ready_wait(ftcmd->ft_wait_before, | ||
1287 | &ftcmd->ft_status),); | ||
1288 | } | ||
1289 | if (ftcmd->ft_status & QIC_STATUS_ERROR) | ||
1290 | goto ftmtcmd_error; | ||
1291 | if (ftcmd->ft_result_bits != 0) { | ||
1292 | TRACE_CATCH(ftape_report_operation(&ftcmd->ft_result, | ||
1293 | ftcmd->ft_cmd, | ||
1294 | ftcmd->ft_result_bits),); | ||
1295 | } else { | ||
1296 | TRACE_CATCH(ftape_command(ftcmd->ft_cmd),); | ||
1297 | if (ftcmd->ft_status & QIC_STATUS_ERROR) | ||
1298 | goto ftmtcmd_error; | ||
1299 | for (i = 0; i < ftcmd->ft_parm_cnt; i++) { | ||
1300 | TRACE_CATCH(ftape_parameter(ftcmd->ft_parms[i]&0x0f),); | ||
1301 | if (ftcmd->ft_status & QIC_STATUS_ERROR) | ||
1302 | goto ftmtcmd_error; | ||
1303 | } | ||
1304 | } | ||
1305 | if (ftcmd->ft_wait_after != 0) { | ||
1306 | TRACE_CATCH(ftape_ready_wait(ftcmd->ft_wait_after, | ||
1307 | &ftcmd->ft_status),); | ||
1308 | } | ||
1309 | ftmtcmd_error: | ||
1310 | if (ftcmd->ft_status & QIC_STATUS_ERROR) { | ||
1311 | TRACE(ft_t_noise, "error status set"); | ||
1312 | TRACE_CATCH(ftape_report_error(&ftcmd->ft_error, | ||
1313 | &ftcmd->ft_cmd, 1),); | ||
1314 | } | ||
1315 | TRACE_EXIT 0; /* this is not an i/o error */ | ||
1316 | } | ||
1317 | #endif | ||
1318 | |||
1319 | /* IOCTL routine called by kernel-interface code | ||
1320 | */ | ||
1321 | int _zft_ioctl(unsigned int command, void __user * arg) | ||
1322 | { | ||
1323 | int result; | ||
1324 | union { struct mtop mtop; | ||
1325 | struct mtget mtget; | ||
1326 | struct mtpos mtpos; | ||
1327 | #ifdef MTIOCRDFTSEG | ||
1328 | struct mtftseg mtftseg; | ||
1329 | #endif | ||
1330 | #ifdef MTIOCVOLINFO | ||
1331 | struct mtvolinfo mtvolinfo; | ||
1332 | #endif | ||
1333 | #ifdef MTIOCGETSIZE | ||
1334 | struct mttapesize mttapesize; | ||
1335 | #endif | ||
1336 | #ifdef MTIOCFTFORMAT | ||
1337 | struct mtftformat mtftformat; | ||
1338 | #endif | ||
1339 | #ifdef ZFT_OBSOLETE | ||
1340 | struct mtblksz mtblksz; | ||
1341 | #endif | ||
1342 | #ifdef MTIOCFTCMD | ||
1343 | struct mtftcmd mtftcmd; | ||
1344 | #endif | ||
1345 | } krnl_arg; | ||
1346 | int arg_size = _IOC_SIZE(command); | ||
1347 | int dir = _IOC_DIR(command); | ||
1348 | TRACE_FUN(ft_t_flow); | ||
1349 | |||
1350 | /* This check will only catch arguments that are too large ! | ||
1351 | */ | ||
1352 | if (dir & (_IOC_READ | _IOC_WRITE) && arg_size > sizeof(krnl_arg)) { | ||
1353 | TRACE_ABORT(-EINVAL, | ||
1354 | ft_t_info, "bad argument size: %d", arg_size); | ||
1355 | } | ||
1356 | if (dir & _IOC_WRITE) { | ||
1357 | if (copy_from_user(&krnl_arg, arg, arg_size) != 0) { | ||
1358 | TRACE_EXIT -EFAULT; | ||
1359 | } | ||
1360 | } | ||
1361 | TRACE(ft_t_flow, "called with ioctl command: 0x%08x", command); | ||
1362 | switch (command) { | ||
1363 | case MTIOCTOP: | ||
1364 | result = mtioctop(&krnl_arg.mtop, arg_size); | ||
1365 | break; | ||
1366 | case MTIOCGET: | ||
1367 | result = mtiocget(&krnl_arg.mtget, arg_size); | ||
1368 | break; | ||
1369 | case MTIOCPOS: | ||
1370 | result = mtiocpos(&krnl_arg.mtpos, arg_size); | ||
1371 | break; | ||
1372 | #ifdef MTIOCVOLINFO | ||
1373 | case MTIOCVOLINFO: | ||
1374 | result = mtiocvolinfo(&krnl_arg.mtvolinfo, arg_size); | ||
1375 | break; | ||
1376 | #endif | ||
1377 | #ifdef ZFT_OBSOLETE | ||
1378 | case MTIOC_ZFTAPE_GETBLKSZ: | ||
1379 | result = mtioc_zftape_getblksz(&krnl_arg.mtblksz, arg_size); | ||
1380 | break; | ||
1381 | #endif | ||
1382 | #ifdef MTIOCRDFTSEG | ||
1383 | case MTIOCRDFTSEG: /* read a segment via ioctl */ | ||
1384 | result = mtiocrdftseg(&krnl_arg.mtftseg, arg_size); | ||
1385 | break; | ||
1386 | #endif | ||
1387 | #ifdef MTIOCWRFTSEG | ||
1388 | case MTIOCWRFTSEG: /* write a segment via ioctl */ | ||
1389 | result = mtiocwrftseg(&krnl_arg.mtftseg, arg_size); | ||
1390 | break; | ||
1391 | #endif | ||
1392 | #ifdef MTIOCGETSIZE | ||
1393 | case MTIOCGETSIZE: | ||
1394 | result = mtiocgetsize(&krnl_arg.mttapesize, arg_size); | ||
1395 | break; | ||
1396 | #endif | ||
1397 | #ifdef MTIOCFTFORMAT | ||
1398 | case MTIOCFTFORMAT: | ||
1399 | result = mtiocftformat(&krnl_arg.mtftformat, arg_size); | ||
1400 | break; | ||
1401 | #endif | ||
1402 | #ifdef MTIOCFTCMD | ||
1403 | case MTIOCFTCMD: | ||
1404 | result = mtiocftcmd(&krnl_arg.mtftcmd, arg_size); | ||
1405 | break; | ||
1406 | #endif | ||
1407 | default: | ||
1408 | result = -EINVAL; | ||
1409 | break; | ||
1410 | } | ||
1411 | if ((result >= 0) && (dir & _IOC_READ)) { | ||
1412 | if (copy_to_user(arg, &krnl_arg, arg_size) != 0) { | ||
1413 | TRACE_EXIT -EFAULT; | ||
1414 | } | ||
1415 | } | ||
1416 | TRACE_EXIT result; | ||
1417 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-ctl.h b/drivers/char/ftape/zftape/zftape-ctl.h deleted file mode 100644 index 8e6f2d7ac74e..000000000000 --- a/drivers/char/ftape/zftape/zftape-ctl.h +++ /dev/null | |||
@@ -1,58 +0,0 @@ | |||
1 | #ifndef _ZFTAPE_CTL_H | ||
2 | #define _ZFTAPE_CTL_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1996, 1997 Claus-Justus Heine. | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-ctl.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:19:02 $ | ||
25 | * | ||
26 | * This file contains the non-standard IOCTL related definitions | ||
27 | * for the QIC-40/80 floppy-tape driver for Linux. | ||
28 | */ | ||
29 | |||
30 | #include <linux/ioctl.h> | ||
31 | #include <linux/mtio.h> | ||
32 | |||
33 | #include "../zftape/zftape-rw.h" | ||
34 | |||
35 | #ifdef CONFIG_ZFTAPE_MODULE | ||
36 | #define ftape_status (*zft_status) | ||
37 | #endif | ||
38 | |||
39 | extern int zft_offline; | ||
40 | extern int zft_mt_compression; | ||
41 | extern int zft_write_protected; | ||
42 | extern int zft_header_read; | ||
43 | extern unsigned int zft_unit; | ||
44 | extern int zft_resid; | ||
45 | |||
46 | extern void zft_reset_position(zft_position *pos); | ||
47 | extern int zft_check_write_access(zft_position *pos); | ||
48 | extern int zft_def_idle_state(void); | ||
49 | |||
50 | /* hooks for the VFS interface | ||
51 | */ | ||
52 | extern int _zft_open(unsigned int dev_minor, unsigned int access_mode); | ||
53 | extern int _zft_close(void); | ||
54 | extern int _zft_ioctl(unsigned int command, void __user *arg); | ||
55 | #endif | ||
56 | |||
57 | |||
58 | |||
diff --git a/drivers/char/ftape/zftape/zftape-eof.c b/drivers/char/ftape/zftape/zftape-eof.c deleted file mode 100644 index dcadcaee9ac1..000000000000 --- a/drivers/char/ftape/zftape/zftape-eof.c +++ /dev/null | |||
@@ -1,199 +0,0 @@ | |||
1 | /* | ||
2 | * I use these routines just to decide when I have to fake a | ||
3 | * volume-table to preserve compatibility to original ftape. | ||
4 | */ | ||
5 | /* | ||
6 | * Copyright (C) 1994-1995 Bas Laarhoven. | ||
7 | * | ||
8 | * Modified for zftape 1996, 1997 Claus Heine. | ||
9 | |||
10 | This program is free software; you can redistribute it and/or modify | ||
11 | it under the terms of the GNU General Public License as published by | ||
12 | the Free Software Foundation; either version 2, or (at your option) | ||
13 | any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; see the file COPYING. If not, write to | ||
22 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | |||
24 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-eof.c,v $ | ||
25 | * $Revision: 1.2 $ | ||
26 | * $Date: 1997/10/05 19:19:02 $ | ||
27 | * | ||
28 | * This file contains the eof mark handling code | ||
29 | * for the QIC-40/80 floppy-tape driver for Linux. | ||
30 | */ | ||
31 | |||
32 | #include <linux/string.h> | ||
33 | #include <linux/errno.h> | ||
34 | |||
35 | #include <linux/zftape.h> | ||
36 | |||
37 | #include "../zftape/zftape-init.h" | ||
38 | #include "../zftape/zftape-rw.h" | ||
39 | #include "../zftape/zftape-eof.h" | ||
40 | |||
41 | /* Global vars. | ||
42 | */ | ||
43 | |||
44 | /* a copy of the failed sector log from the header segment. | ||
45 | */ | ||
46 | eof_mark_union *zft_eof_map; | ||
47 | |||
48 | /* number of eof marks (entries in bad sector log) on tape. | ||
49 | */ | ||
50 | int zft_nr_eof_marks = -1; | ||
51 | |||
52 | |||
53 | /* Local vars. | ||
54 | */ | ||
55 | |||
56 | static char linux_tape_label[] = "Linux raw format V"; | ||
57 | enum { | ||
58 | min_fmt_version = 1, max_fmt_version = 2 | ||
59 | }; | ||
60 | static unsigned ftape_fmt_version = 0; | ||
61 | |||
62 | |||
63 | /* Ftape (mis)uses the bad sector log to record end-of-file marks. | ||
64 | * Initially (when the tape is erased) all entries in the bad sector | ||
65 | * log are added to the tape's bad sector map. The bad sector log then | ||
66 | * is cleared. | ||
67 | * | ||
68 | * The bad sector log normally contains entries of the form: | ||
69 | * even 16-bit word: segment number of bad sector | ||
70 | * odd 16-bit word: encoded date | ||
71 | * There can be a total of 448 entries (1792 bytes). | ||
72 | * | ||
73 | * My guess is that no program is using this bad sector log (the * | ||
74 | * format seems useless as there is no indication of the bad sector | ||
75 | * itself, only the segment) However, if any program does use the bad | ||
76 | * sector log, the format used by ftape will let the program think | ||
77 | * there are some bad sectors and no harm is done. | ||
78 | * | ||
79 | * The eof mark entries that ftape stores in the bad sector log: even | ||
80 | * 16-bit word: segment number of eof mark odd 16-bit word: sector | ||
81 | * number of eof mark [1..32] | ||
82 | * | ||
83 | * The zft_eof_map as maintained is a sorted list of eof mark entries. | ||
84 | * | ||
85 | * | ||
86 | * The tape name field in the header segments is used to store a linux | ||
87 | * tape identification string and a version number. This way the tape | ||
88 | * can be recognized as a Linux raw format tape when using tools under | ||
89 | * other OS's. | ||
90 | * | ||
91 | * 'Wide' QIC tapes (format code 4) don't have a failed sector list | ||
92 | * anymore. That space is used for the (longer) bad sector map that | ||
93 | * now is a variable length list too. We now store our end-of-file | ||
94 | * marker list after the bad-sector-map on tape. The list is delimited | ||
95 | * by a (__u32) 0 entry. | ||
96 | */ | ||
97 | |||
98 | int zft_ftape_validate_label(char *label) | ||
99 | { | ||
100 | static char tmp_label[45]; | ||
101 | int result = 0; | ||
102 | TRACE_FUN(ft_t_any); | ||
103 | |||
104 | memcpy(tmp_label, label, FT_LABEL_SZ); | ||
105 | tmp_label[FT_LABEL_SZ] = '\0'; | ||
106 | TRACE(ft_t_noise, "tape label = `%s'", tmp_label); | ||
107 | ftape_fmt_version = 0; | ||
108 | if (memcmp(label, linux_tape_label, strlen(linux_tape_label)) == 0) { | ||
109 | int pos = strlen(linux_tape_label); | ||
110 | while (label[pos] >= '0' && label[pos] <= '9') { | ||
111 | ftape_fmt_version *= 10; | ||
112 | ftape_fmt_version = label[ pos++] - '0'; | ||
113 | } | ||
114 | result = (ftape_fmt_version >= min_fmt_version && | ||
115 | ftape_fmt_version <= max_fmt_version); | ||
116 | } | ||
117 | TRACE(ft_t_noise, "format version = %d", ftape_fmt_version); | ||
118 | TRACE_EXIT result; | ||
119 | } | ||
120 | |||
121 | static __u8 * find_end_of_eof_list(__u8 * ptr, __u8 * limit) | ||
122 | { | ||
123 | while (ptr + 3 < limit) { | ||
124 | |||
125 | if (get_unaligned((__u32*)ptr)) { | ||
126 | ptr += sizeof(__u32); | ||
127 | } else { | ||
128 | return ptr; | ||
129 | } | ||
130 | } | ||
131 | return NULL; | ||
132 | } | ||
133 | |||
134 | void zft_ftape_extract_file_marks(__u8* address) | ||
135 | { | ||
136 | int i; | ||
137 | TRACE_FUN(ft_t_any); | ||
138 | |||
139 | zft_eof_map = NULL; | ||
140 | if (ft_format_code == fmt_var || ft_format_code == fmt_big) { | ||
141 | __u8* end; | ||
142 | __u8* start = ftape_find_end_of_bsm_list(address); | ||
143 | |||
144 | zft_nr_eof_marks = 0; | ||
145 | if (start) { | ||
146 | start += 3; /* skip end of list mark */ | ||
147 | end = find_end_of_eof_list(start, | ||
148 | address + FT_SEGMENT_SIZE); | ||
149 | if (end && end - start <= FT_FSL_SIZE) { | ||
150 | zft_nr_eof_marks = ((end - start) / | ||
151 | sizeof(eof_mark_union)); | ||
152 | zft_eof_map = (eof_mark_union *)start; | ||
153 | } else { | ||
154 | TRACE(ft_t_err, | ||
155 | "EOF Mark List is too long or damaged!"); | ||
156 | } | ||
157 | } else { | ||
158 | TRACE(ft_t_err, | ||
159 | "Bad Sector List is too long or damaged !"); | ||
160 | } | ||
161 | } else { | ||
162 | zft_eof_map = (eof_mark_union *)&address[FT_FSL]; | ||
163 | zft_nr_eof_marks = GET2(address, FT_FSL_CNT); | ||
164 | } | ||
165 | TRACE(ft_t_noise, "number of file marks: %d", zft_nr_eof_marks); | ||
166 | if (ftape_fmt_version == 1) { | ||
167 | TRACE(ft_t_info, "swapping version 1 fields"); | ||
168 | /* version 1 format uses swapped sector and segment | ||
169 | * fields, correct that ! | ||
170 | */ | ||
171 | for (i = 0; i < zft_nr_eof_marks; ++i) { | ||
172 | __u16 tmp = GET2(&zft_eof_map[i].mark.segment,0); | ||
173 | PUT2(&zft_eof_map[i].mark.segment, 0, | ||
174 | GET2(&zft_eof_map[i].mark.date,0)); | ||
175 | PUT2(&zft_eof_map[i].mark.date, 0, tmp); | ||
176 | } | ||
177 | } | ||
178 | for (i = 0; i < zft_nr_eof_marks; ++i) { | ||
179 | TRACE(ft_t_noise, "eof mark: %5d/%2d", | ||
180 | GET2(&zft_eof_map[i].mark.segment, 0), | ||
181 | GET2(&zft_eof_map[i].mark.date,0)); | ||
182 | } | ||
183 | TRACE_EXIT; | ||
184 | } | ||
185 | |||
186 | void zft_clear_ftape_file_marks(void) | ||
187 | { | ||
188 | TRACE_FUN(ft_t_flow); | ||
189 | /* Clear failed sector log: remove all tape marks. We | ||
190 | * don't use old ftape-style EOF-marks. | ||
191 | */ | ||
192 | TRACE(ft_t_info, "Clearing old ftape's eof map"); | ||
193 | memset(zft_eof_map, 0, zft_nr_eof_marks * sizeof(__u32)); | ||
194 | zft_nr_eof_marks = 0; | ||
195 | PUT2(zft_hseg_buf, FT_FSL_CNT, 0); /* nr of eof-marks */ | ||
196 | zft_header_changed = 1; | ||
197 | zft_update_label(zft_hseg_buf); | ||
198 | TRACE_EXIT; | ||
199 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-eof.h b/drivers/char/ftape/zftape/zftape-eof.h deleted file mode 100644 index 26568c26c518..000000000000 --- a/drivers/char/ftape/zftape/zftape-eof.h +++ /dev/null | |||
@@ -1,52 +0,0 @@ | |||
1 | #ifndef _ZFTAPE_EOF_H | ||
2 | #define _ZFTAPE_EOF_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1994-1995 Bas Laarhoven. | ||
6 | * adaptaed for zftape 1996, 1997 by Claus Heine | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; see the file COPYING. If not, write to | ||
20 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-eof.h,v $ | ||
24 | * $Revision: 1.2 $ | ||
25 | * $Date: 1997/10/05 19:19:03 $ | ||
26 | * | ||
27 | * Definitions and declarations for the end of file markers | ||
28 | * for the QIC-40/80 floppy-tape driver for Linux. | ||
29 | */ | ||
30 | |||
31 | #include <linux/ftape-header-segment.h> | ||
32 | #include "../zftape/zftape-buffers.h" | ||
33 | /* failed sector log size (only used if format code != 4). | ||
34 | */ | ||
35 | |||
36 | typedef union { | ||
37 | ft_fsl_entry mark; | ||
38 | __u32 entry; | ||
39 | } eof_mark_union; | ||
40 | |||
41 | /* ftape-eof.c defined global vars. | ||
42 | */ | ||
43 | extern int zft_nr_eof_marks; | ||
44 | extern eof_mark_union *zft_eof_map; | ||
45 | |||
46 | /* ftape-eof.c defined global functions. | ||
47 | */ | ||
48 | extern void zft_ftape_extract_file_marks(__u8* address); | ||
49 | extern int zft_ftape_validate_label(char* label); | ||
50 | extern void zft_clear_ftape_file_marks(void); | ||
51 | |||
52 | #endif | ||
diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c deleted file mode 100644 index 164a1aa77a2f..000000000000 --- a/drivers/char/ftape/zftape/zftape-init.c +++ /dev/null | |||
@@ -1,377 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1996, 1997 Claus-Justus Heine. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; see the file COPYING. If not, write to | ||
16 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | |||
18 | * | ||
19 | * This file contains the code that registers the zftape frontend | ||
20 | * to the ftape floppy tape driver for Linux | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/fs.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/signal.h> | ||
28 | #include <linux/major.h> | ||
29 | #include <linux/slab.h> | ||
30 | #ifdef CONFIG_KMOD | ||
31 | #include <linux/kmod.h> | ||
32 | #endif | ||
33 | #include <linux/fcntl.h> | ||
34 | #include <linux/smp_lock.h> | ||
35 | |||
36 | #include <linux/zftape.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/device.h> | ||
39 | |||
40 | #include "../zftape/zftape-init.h" | ||
41 | #include "../zftape/zftape-read.h" | ||
42 | #include "../zftape/zftape-write.h" | ||
43 | #include "../zftape/zftape-ctl.h" | ||
44 | #include "../zftape/zftape-buffers.h" | ||
45 | |||
46 | MODULE_AUTHOR("(c) 1996, 1997 Claus-Justus Heine " | ||
47 | "(claus@momo.math.rwth-aachen.de)"); | ||
48 | MODULE_DESCRIPTION(ZFTAPE_VERSION " - " | ||
49 | "VFS interface for the Linux floppy tape driver. " | ||
50 | "Support for QIC-113 compatible volume table " | ||
51 | "and builtin compression (lzrw3 algorithm)"); | ||
52 | MODULE_SUPPORTED_DEVICE("char-major-27"); | ||
53 | MODULE_LICENSE("GPL"); | ||
54 | |||
55 | /* Global vars. | ||
56 | */ | ||
57 | struct zft_cmpr_ops *zft_cmpr_ops = NULL; | ||
58 | const ftape_info *zft_status; | ||
59 | |||
60 | /* Local vars. | ||
61 | */ | ||
62 | static unsigned long busy_flag; | ||
63 | |||
64 | static sigset_t orig_sigmask; | ||
65 | |||
66 | /* the interface to the kernel vfs layer | ||
67 | */ | ||
68 | |||
69 | /* Note about llseek(): | ||
70 | * | ||
71 | * st.c and tpqic.c update fp->f_pos but don't implment llseek() and | ||
72 | * initialize the llseek component of the file_ops struct with NULL. | ||
73 | * This means that the user will get the default seek, but the tape | ||
74 | * device will not respect the new position, but happily read from the | ||
75 | * old position. Think a zftape specific llseek() function would be | ||
76 | * better, returning -ESPIPE. TODO. | ||
77 | */ | ||
78 | |||
79 | static int zft_open (struct inode *ino, struct file *filep); | ||
80 | static int zft_close(struct inode *ino, struct file *filep); | ||
81 | static int zft_ioctl(struct inode *ino, struct file *filep, | ||
82 | unsigned int command, unsigned long arg); | ||
83 | static int zft_mmap(struct file *filep, struct vm_area_struct *vma); | ||
84 | static ssize_t zft_read (struct file *fp, char __user *buff, | ||
85 | size_t req_len, loff_t *ppos); | ||
86 | static ssize_t zft_write(struct file *fp, const char __user *buff, | ||
87 | size_t req_len, loff_t *ppos); | ||
88 | |||
89 | static const struct file_operations zft_cdev = | ||
90 | { | ||
91 | .owner = THIS_MODULE, | ||
92 | .read = zft_read, | ||
93 | .write = zft_write, | ||
94 | .ioctl = zft_ioctl, | ||
95 | .mmap = zft_mmap, | ||
96 | .open = zft_open, | ||
97 | .release = zft_close, | ||
98 | }; | ||
99 | |||
100 | static struct class *zft_class; | ||
101 | |||
102 | /* Open floppy tape device | ||
103 | */ | ||
104 | static int zft_open(struct inode *ino, struct file *filep) | ||
105 | { | ||
106 | int result; | ||
107 | TRACE_FUN(ft_t_flow); | ||
108 | |||
109 | nonseekable_open(ino, filep); | ||
110 | TRACE(ft_t_flow, "called for minor %d", iminor(ino)); | ||
111 | if ( test_and_set_bit(0,&busy_flag) ) { | ||
112 | TRACE_ABORT(-EBUSY, ft_t_warn, "failed: already busy"); | ||
113 | } | ||
114 | if ((iminor(ino) & ~(ZFT_MINOR_OP_MASK | FTAPE_NO_REWIND)) | ||
115 | > | ||
116 | FTAPE_SEL_D) { | ||
117 | clear_bit(0,&busy_flag); | ||
118 | TRACE_ABORT(-ENXIO, ft_t_err, "failed: invalid unit nr"); | ||
119 | } | ||
120 | orig_sigmask = current->blocked; | ||
121 | sigfillset(¤t->blocked); | ||
122 | result = _zft_open(iminor(ino), filep->f_flags & O_ACCMODE); | ||
123 | if (result < 0) { | ||
124 | current->blocked = orig_sigmask; /* restore mask */ | ||
125 | clear_bit(0,&busy_flag); | ||
126 | TRACE_ABORT(result, ft_t_err, "_ftape_open failed"); | ||
127 | } else { | ||
128 | /* Mask signals that will disturb proper operation of the | ||
129 | * program that is calling. | ||
130 | */ | ||
131 | current->blocked = orig_sigmask; | ||
132 | sigaddsetmask (¤t->blocked, _DO_BLOCK); | ||
133 | TRACE_EXIT 0; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | /* Close floppy tape device | ||
138 | */ | ||
139 | static int zft_close(struct inode *ino, struct file *filep) | ||
140 | { | ||
141 | int result; | ||
142 | TRACE_FUN(ft_t_flow); | ||
143 | |||
144 | if ( !test_bit(0,&busy_flag) || iminor(ino) != zft_unit) { | ||
145 | TRACE(ft_t_err, "failed: not busy or wrong unit"); | ||
146 | TRACE_EXIT 0; | ||
147 | } | ||
148 | sigfillset(¤t->blocked); | ||
149 | result = _zft_close(); | ||
150 | if (result < 0) { | ||
151 | TRACE(ft_t_err, "_zft_close failed"); | ||
152 | } | ||
153 | current->blocked = orig_sigmask; /* restore before open state */ | ||
154 | clear_bit(0,&busy_flag); | ||
155 | TRACE_EXIT 0; | ||
156 | } | ||
157 | |||
158 | /* Ioctl for floppy tape device | ||
159 | */ | ||
160 | static int zft_ioctl(struct inode *ino, struct file *filep, | ||
161 | unsigned int command, unsigned long arg) | ||
162 | { | ||
163 | int result = -EIO; | ||
164 | sigset_t old_sigmask; | ||
165 | TRACE_FUN(ft_t_flow); | ||
166 | |||
167 | if ( !test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) { | ||
168 | TRACE_ABORT(-EIO, ft_t_err, | ||
169 | "failed: not busy, failure or wrong unit"); | ||
170 | } | ||
171 | old_sigmask = current->blocked; /* save mask */ | ||
172 | sigfillset(¤t->blocked); | ||
173 | /* This will work as long as sizeof(void *) == sizeof(long) */ | ||
174 | result = _zft_ioctl(command, (void __user *) arg); | ||
175 | current->blocked = old_sigmask; /* restore mask */ | ||
176 | TRACE_EXIT result; | ||
177 | } | ||
178 | |||
179 | /* Ioctl for floppy tape device | ||
180 | */ | ||
181 | static int zft_mmap(struct file *filep, struct vm_area_struct *vma) | ||
182 | { | ||
183 | int result = -EIO; | ||
184 | sigset_t old_sigmask; | ||
185 | TRACE_FUN(ft_t_flow); | ||
186 | |||
187 | if ( !test_bit(0,&busy_flag) || | ||
188 | iminor(filep->f_dentry->d_inode) != zft_unit || | ||
189 | ft_failure) | ||
190 | { | ||
191 | TRACE_ABORT(-EIO, ft_t_err, | ||
192 | "failed: not busy, failure or wrong unit"); | ||
193 | } | ||
194 | old_sigmask = current->blocked; /* save mask */ | ||
195 | sigfillset(¤t->blocked); | ||
196 | if ((result = ftape_mmap(vma)) >= 0) { | ||
197 | #ifndef MSYNC_BUG_WAS_FIXED | ||
198 | static struct vm_operations_struct dummy = { NULL, }; | ||
199 | vma->vm_ops = &dummy; | ||
200 | #endif | ||
201 | } | ||
202 | current->blocked = old_sigmask; /* restore mask */ | ||
203 | TRACE_EXIT result; | ||
204 | } | ||
205 | |||
206 | /* Read from floppy tape device | ||
207 | */ | ||
208 | static ssize_t zft_read(struct file *fp, char __user *buff, | ||
209 | size_t req_len, loff_t *ppos) | ||
210 | { | ||
211 | int result = -EIO; | ||
212 | sigset_t old_sigmask; | ||
213 | struct inode *ino = fp->f_dentry->d_inode; | ||
214 | TRACE_FUN(ft_t_flow); | ||
215 | |||
216 | TRACE(ft_t_data_flow, "called with count: %ld", (unsigned long)req_len); | ||
217 | if (!test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) { | ||
218 | TRACE_ABORT(-EIO, ft_t_err, | ||
219 | "failed: not busy, failure or wrong unit"); | ||
220 | } | ||
221 | old_sigmask = current->blocked; /* save mask */ | ||
222 | sigfillset(¤t->blocked); | ||
223 | result = _zft_read(buff, req_len); | ||
224 | current->blocked = old_sigmask; /* restore mask */ | ||
225 | TRACE(ft_t_data_flow, "return with count: %d", result); | ||
226 | TRACE_EXIT result; | ||
227 | } | ||
228 | |||
229 | /* Write to tape device | ||
230 | */ | ||
231 | static ssize_t zft_write(struct file *fp, const char __user *buff, | ||
232 | size_t req_len, loff_t *ppos) | ||
233 | { | ||
234 | int result = -EIO; | ||
235 | sigset_t old_sigmask; | ||
236 | struct inode *ino = fp->f_dentry->d_inode; | ||
237 | TRACE_FUN(ft_t_flow); | ||
238 | |||
239 | TRACE(ft_t_flow, "called with count: %ld", (unsigned long)req_len); | ||
240 | if (!test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) { | ||
241 | TRACE_ABORT(-EIO, ft_t_err, | ||
242 | "failed: not busy, failure or wrong unit"); | ||
243 | } | ||
244 | old_sigmask = current->blocked; /* save mask */ | ||
245 | sigfillset(¤t->blocked); | ||
246 | result = _zft_write(buff, req_len); | ||
247 | current->blocked = old_sigmask; /* restore mask */ | ||
248 | TRACE(ft_t_data_flow, "return with count: %d", result); | ||
249 | TRACE_EXIT result; | ||
250 | } | ||
251 | |||
252 | /* END OF VFS INTERFACE | ||
253 | * | ||
254 | *****************************************************************************/ | ||
255 | |||
256 | /* driver/module initialization | ||
257 | */ | ||
258 | |||
259 | /* the compression module has to call this function to hook into the zftape | ||
260 | * code | ||
261 | */ | ||
262 | int zft_cmpr_register(struct zft_cmpr_ops *new_ops) | ||
263 | { | ||
264 | TRACE_FUN(ft_t_flow); | ||
265 | |||
266 | if (zft_cmpr_ops != NULL) { | ||
267 | TRACE_EXIT -EBUSY; | ||
268 | } else { | ||
269 | zft_cmpr_ops = new_ops; | ||
270 | TRACE_EXIT 0; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | /* lock the zft-compressor() module. | ||
275 | */ | ||
276 | int zft_cmpr_lock(int try_to_load) | ||
277 | { | ||
278 | if (zft_cmpr_ops == NULL) { | ||
279 | #ifdef CONFIG_KMOD | ||
280 | if (try_to_load) { | ||
281 | request_module("zft-compressor"); | ||
282 | if (zft_cmpr_ops == NULL) { | ||
283 | return -ENOSYS; | ||
284 | } | ||
285 | } else { | ||
286 | return -ENOSYS; | ||
287 | } | ||
288 | #else | ||
289 | return -ENOSYS; | ||
290 | #endif | ||
291 | } | ||
292 | (*zft_cmpr_ops->lock)(); | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | #ifdef CONFIG_ZFT_COMPRESSOR | ||
297 | extern int zft_compressor_init(void); | ||
298 | #endif | ||
299 | |||
300 | /* Called by modules package when installing the driver or by kernel | ||
301 | * during the initialization phase | ||
302 | */ | ||
303 | int __init zft_init(void) | ||
304 | { | ||
305 | int i; | ||
306 | TRACE_FUN(ft_t_flow); | ||
307 | |||
308 | #ifdef MODULE | ||
309 | printk(KERN_INFO ZFTAPE_VERSION "\n"); | ||
310 | if (TRACE_LEVEL >= ft_t_info) { | ||
311 | printk( | ||
312 | KERN_INFO | ||
313 | "(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n" | ||
314 | KERN_INFO | ||
315 | "vfs interface for ftape floppy tape driver.\n" | ||
316 | KERN_INFO | ||
317 | "Support for QIC-113 compatible volume table, dynamic memory allocation\n" | ||
318 | KERN_INFO | ||
319 | "and builtin compression (lzrw3 algorithm).\n"); | ||
320 | } | ||
321 | #else /* !MODULE */ | ||
322 | /* print a short no-nonsense boot message */ | ||
323 | printk(KERN_INFO ZFTAPE_VERSION "\n"); | ||
324 | #endif /* MODULE */ | ||
325 | TRACE(ft_t_info, "zft_init @ 0x%p", zft_init); | ||
326 | TRACE(ft_t_info, | ||
327 | "installing zftape VFS interface for ftape driver ..."); | ||
328 | TRACE_CATCH(register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),); | ||
329 | |||
330 | zft_class = class_create(THIS_MODULE, "zft"); | ||
331 | for (i = 0; i < 4; i++) { | ||
332 | class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i); | ||
333 | class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i); | ||
334 | class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i); | ||
335 | class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i); | ||
336 | class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i); | ||
337 | class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i); | ||
338 | } | ||
339 | |||
340 | #ifdef CONFIG_ZFT_COMPRESSOR | ||
341 | (void)zft_compressor_init(); | ||
342 | #endif | ||
343 | zft_status = ftape_get_status(); /* fetch global data of ftape | ||
344 | * hardware driver | ||
345 | */ | ||
346 | TRACE_EXIT 0; | ||
347 | } | ||
348 | |||
349 | |||
350 | /* Called by modules package when removing the driver | ||
351 | */ | ||
352 | static void zft_exit(void) | ||
353 | { | ||
354 | int i; | ||
355 | TRACE_FUN(ft_t_flow); | ||
356 | |||
357 | if (unregister_chrdev(QIC117_TAPE_MAJOR, "zft") != 0) { | ||
358 | TRACE(ft_t_warn, "failed"); | ||
359 | } else { | ||
360 | TRACE(ft_t_info, "successful"); | ||
361 | } | ||
362 | for (i = 0; i < 4; i++) { | ||
363 | class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i)); | ||
364 | class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4)); | ||
365 | class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16)); | ||
366 | class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20)); | ||
367 | class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32)); | ||
368 | class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36)); | ||
369 | } | ||
370 | class_destroy(zft_class); | ||
371 | zft_uninit_mem(); /* release remaining memory, if any */ | ||
372 | printk(KERN_INFO "zftape successfully unloaded.\n"); | ||
373 | TRACE_EXIT; | ||
374 | } | ||
375 | |||
376 | module_init(zft_init); | ||
377 | module_exit(zft_exit); | ||
diff --git a/drivers/char/ftape/zftape/zftape-init.h b/drivers/char/ftape/zftape/zftape-init.h deleted file mode 100644 index 937e5d48c20e..000000000000 --- a/drivers/char/ftape/zftape/zftape-init.h +++ /dev/null | |||
@@ -1,77 +0,0 @@ | |||
1 | #ifndef _ZFTAPE_INIT_H | ||
2 | #define _ZFTAPE_INIT_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1996, 1997 Claus Heine. | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-init.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:19:05 $ | ||
25 | * | ||
26 | * This file contains definitions and macro for the vfs | ||
27 | * interface defined by zftape | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <linux/ftape-header-segment.h> | ||
32 | |||
33 | #include "../lowlevel/ftape-tracing.h" | ||
34 | #include "../lowlevel/ftape-ctl.h" | ||
35 | #include "../lowlevel/ftape-read.h" | ||
36 | #include "../lowlevel/ftape-write.h" | ||
37 | #include "../lowlevel/ftape-bsm.h" | ||
38 | #include "../lowlevel/ftape-io.h" | ||
39 | #include "../lowlevel/ftape-buffer.h" | ||
40 | #include "../lowlevel/ftape-format.h" | ||
41 | |||
42 | #include "../zftape/zftape-rw.h" | ||
43 | |||
44 | #ifdef MODULE | ||
45 | #define ftape_status (*zft_status) | ||
46 | #endif | ||
47 | |||
48 | extern const ftape_info *zft_status; /* needed for zftape-vtbl.h */ | ||
49 | |||
50 | #include "../zftape/zftape-vtbl.h" | ||
51 | |||
52 | struct zft_cmpr_ops { | ||
53 | int (*write)(int *write_cnt, | ||
54 | __u8 *dst_buf, const int seg_sz, | ||
55 | const __u8 __user *src_buf, const int req_len, | ||
56 | const zft_position *pos, const zft_volinfo *volume); | ||
57 | int (*read)(int *read_cnt, | ||
58 | __u8 __user *dst_buf, const int req_len, | ||
59 | const __u8 *src_buf, const int seg_sz, | ||
60 | const zft_position *pos, const zft_volinfo *volume); | ||
61 | int (*seek)(unsigned int new_block_pos, | ||
62 | zft_position *pos, const zft_volinfo *volume, | ||
63 | __u8 *buffer); | ||
64 | void (*lock) (void); | ||
65 | void (*reset) (void); | ||
66 | void (*cleanup)(void); | ||
67 | }; | ||
68 | |||
69 | extern struct zft_cmpr_ops *zft_cmpr_ops; | ||
70 | /* zftape-init.c defined global functions. | ||
71 | */ | ||
72 | extern int zft_cmpr_register(struct zft_cmpr_ops *new_ops); | ||
73 | extern int zft_cmpr_lock(int try_to_load); | ||
74 | |||
75 | #endif | ||
76 | |||
77 | |||
diff --git a/drivers/char/ftape/zftape/zftape-read.c b/drivers/char/ftape/zftape/zftape-read.c deleted file mode 100644 index 214bf03dce68..000000000000 --- a/drivers/char/ftape/zftape/zftape-read.c +++ /dev/null | |||
@@ -1,377 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1996, 1997 Claus-Justus Heine | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; see the file COPYING. If not, write to | ||
16 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | |||
18 | * | ||
19 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-read.c,v $ | ||
20 | * $Revision: 1.2 $ | ||
21 | * $Date: 1997/10/05 19:19:06 $ | ||
22 | * | ||
23 | * This file contains the high level reading code | ||
24 | * for the QIC-117 floppy-tape driver for Linux. | ||
25 | */ | ||
26 | |||
27 | #include <linux/errno.h> | ||
28 | #include <linux/mm.h> | ||
29 | |||
30 | #include <linux/zftape.h> | ||
31 | |||
32 | #include <asm/uaccess.h> | ||
33 | |||
34 | #include "../zftape/zftape-init.h" | ||
35 | #include "../zftape/zftape-eof.h" | ||
36 | #include "../zftape/zftape-ctl.h" | ||
37 | #include "../zftape/zftape-write.h" | ||
38 | #include "../zftape/zftape-read.h" | ||
39 | #include "../zftape/zftape-rw.h" | ||
40 | #include "../zftape/zftape-vtbl.h" | ||
41 | |||
42 | /* Global vars. | ||
43 | */ | ||
44 | int zft_just_before_eof; | ||
45 | |||
46 | /* Local vars. | ||
47 | */ | ||
48 | static int buf_len_rd; | ||
49 | |||
50 | void zft_zap_read_buffers(void) | ||
51 | { | ||
52 | buf_len_rd = 0; | ||
53 | } | ||
54 | |||
55 | int zft_read_header_segments(void) | ||
56 | { | ||
57 | TRACE_FUN(ft_t_flow); | ||
58 | |||
59 | zft_header_read = 0; | ||
60 | TRACE_CATCH(zft_vmalloc_once(&zft_hseg_buf, FT_SEGMENT_SIZE),); | ||
61 | TRACE_CATCH(ftape_read_header_segment(zft_hseg_buf),); | ||
62 | TRACE(ft_t_info, "Segments written since first format: %d", | ||
63 | (int)GET4(zft_hseg_buf, FT_SEG_CNT)); | ||
64 | zft_qic113 = (ft_format_code != fmt_normal && | ||
65 | ft_format_code != fmt_1100ft && | ||
66 | ft_format_code != fmt_425ft); | ||
67 | TRACE(ft_t_info, "ft_first_data_segment: %d, ft_last_data_segment: %d", | ||
68 | ft_first_data_segment, ft_last_data_segment); | ||
69 | zft_capacity = zft_get_capacity(); | ||
70 | zft_old_ftape = zft_ftape_validate_label(&zft_hseg_buf[FT_LABEL]); | ||
71 | if (zft_old_ftape) { | ||
72 | TRACE(ft_t_info, | ||
73 | "Found old ftaped tape, emulating eof marks, entering read-only mode"); | ||
74 | zft_ftape_extract_file_marks(zft_hseg_buf); | ||
75 | TRACE_CATCH(zft_fake_volume_headers(zft_eof_map, | ||
76 | zft_nr_eof_marks),); | ||
77 | } else { | ||
78 | /* the specs say that the volume table must be | ||
79 | * initialized with zeroes during formatting, so it | ||
80 | * MUST be readable, i.e. contain vaid ECC | ||
81 | * information. | ||
82 | */ | ||
83 | TRACE_CATCH(ftape_read_segment(ft_first_data_segment, | ||
84 | zft_deblock_buf, | ||
85 | FT_RD_SINGLE),); | ||
86 | TRACE_CATCH(zft_extract_volume_headers(zft_deblock_buf),); | ||
87 | } | ||
88 | zft_header_read = 1; | ||
89 | zft_set_flags(zft_unit); | ||
90 | zft_reset_position(&zft_pos); | ||
91 | TRACE_EXIT 0; | ||
92 | } | ||
93 | |||
94 | int zft_fetch_segment_fraction(const unsigned int segment, void *buffer, | ||
95 | const ft_read_mode_t read_mode, | ||
96 | const unsigned int start, | ||
97 | const unsigned int size) | ||
98 | { | ||
99 | int seg_sz; | ||
100 | TRACE_FUN(ft_t_flow); | ||
101 | |||
102 | if (segment == zft_deblock_segment) { | ||
103 | TRACE(ft_t_data_flow, | ||
104 | "re-using segment %d already in deblock buffer", | ||
105 | segment); | ||
106 | seg_sz = zft_get_seg_sz(segment); | ||
107 | if (start > seg_sz) { | ||
108 | TRACE_ABORT(-EINVAL, ft_t_bug, | ||
109 | "trying to read beyond end of segment:\n" | ||
110 | KERN_INFO "seg_sz : %d\n" | ||
111 | KERN_INFO "start : %d\n" | ||
112 | KERN_INFO "segment: %d", | ||
113 | seg_sz, start, segment); | ||
114 | } | ||
115 | if ((start + size) > seg_sz) { | ||
116 | TRACE_EXIT seg_sz - start; | ||
117 | } | ||
118 | TRACE_EXIT size; | ||
119 | } | ||
120 | seg_sz = ftape_read_segment_fraction(segment, buffer, read_mode, | ||
121 | start, size); | ||
122 | TRACE(ft_t_data_flow, "segment %d, result %d", segment, seg_sz); | ||
123 | if ((int)seg_sz >= 0 && start == 0 && size == FT_SEGMENT_SIZE) { | ||
124 | /* this implicitly assumes that we are always called with | ||
125 | * buffer == zft_deblock_buf | ||
126 | */ | ||
127 | zft_deblock_segment = segment; | ||
128 | } else { | ||
129 | zft_deblock_segment = -1; | ||
130 | } | ||
131 | TRACE_EXIT seg_sz; | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | * out: | ||
136 | * | ||
137 | * int *read_cnt: the number of bytes we removed from the | ||
138 | * zft_deblock_buf (result) | ||
139 | * | ||
140 | * int *to_do : the remaining size of the read-request. Is changed. | ||
141 | * | ||
142 | * in: | ||
143 | * | ||
144 | * char *buff : buff is the address of the upper part of the user | ||
145 | * buffer, that hasn't been filled with data yet. | ||
146 | * int buf_pos_read: copy of buf_pos_rd | ||
147 | * int buf_len_read: copy of buf_len_rd | ||
148 | * char *zft_deblock_buf: ftape_zft_deblock_buf | ||
149 | * | ||
150 | * returns the amount of data actually copied to the user-buffer | ||
151 | * | ||
152 | * to_do MUST NOT SHRINK except to indicate an EOT. In this case to_do | ||
153 | * has to be set to 0. We cannot return -ENOSPC, because we return the | ||
154 | * amount of data actually * copied to the user-buffer | ||
155 | */ | ||
156 | static int zft_simple_read (int *read_cnt, | ||
157 | __u8 __user *dst_buf, | ||
158 | const int to_do, | ||
159 | const __u8 *src_buf, | ||
160 | const int seg_sz, | ||
161 | const zft_position *pos, | ||
162 | const zft_volinfo *volume) | ||
163 | { | ||
164 | TRACE_FUN(ft_t_flow); | ||
165 | |||
166 | if (seg_sz - pos->seg_byte_pos < to_do) { | ||
167 | *read_cnt = seg_sz - pos->seg_byte_pos; | ||
168 | } else { | ||
169 | *read_cnt = to_do; | ||
170 | } | ||
171 | if (copy_to_user(dst_buf, | ||
172 | src_buf + pos->seg_byte_pos, *read_cnt) != 0) { | ||
173 | TRACE_EXIT -EFAULT; | ||
174 | } | ||
175 | TRACE(ft_t_noise, "nr bytes just read: %d", *read_cnt); | ||
176 | TRACE_EXIT *read_cnt; | ||
177 | } | ||
178 | |||
179 | /* req_len: gets clipped due to EOT of EOF. | ||
180 | * req_clipped: is a flag indicating whether req_len was clipped or not | ||
181 | * volume: contains information on current volume (blk_sz etc.) | ||
182 | */ | ||
183 | static int check_read_access(int *req_len, | ||
184 | const zft_volinfo **volume, | ||
185 | int *req_clipped, | ||
186 | const zft_position *pos) | ||
187 | { | ||
188 | static __s64 remaining; | ||
189 | static int eod; | ||
190 | TRACE_FUN(ft_t_flow); | ||
191 | |||
192 | if (zft_io_state != zft_reading) { | ||
193 | if (zft_offline) { /* offline includes no_tape */ | ||
194 | TRACE_ABORT(-ENXIO, ft_t_warn, | ||
195 | "tape is offline or no cartridge"); | ||
196 | } | ||
197 | if (!ft_formatted) { | ||
198 | TRACE_ABORT(-EACCES, | ||
199 | ft_t_warn, "tape is not formatted"); | ||
200 | } | ||
201 | /* now enter defined state, read header segment if not | ||
202 | * already done and flush write buffers | ||
203 | */ | ||
204 | TRACE_CATCH(zft_def_idle_state(),); | ||
205 | zft_io_state = zft_reading; | ||
206 | if (zft_tape_at_eod(pos)) { | ||
207 | eod = 1; | ||
208 | TRACE_EXIT 1; | ||
209 | } | ||
210 | eod = 0; | ||
211 | *volume = zft_find_volume(pos->seg_pos); | ||
212 | /* get the space left until EOF */ | ||
213 | remaining = zft_check_for_eof(*volume, pos); | ||
214 | buf_len_rd = 0; | ||
215 | TRACE(ft_t_noise, "remaining: " LL_X ", vol_no: %d", | ||
216 | LL(remaining), (*volume)->count); | ||
217 | } else if (zft_tape_at_eod(pos)) { | ||
218 | if (++eod > 2) { | ||
219 | TRACE_EXIT -EIO; /* st.c also returns -EIO */ | ||
220 | } else { | ||
221 | TRACE_EXIT 1; | ||
222 | } | ||
223 | } | ||
224 | if ((*req_len % (*volume)->blk_sz) != 0) { | ||
225 | /* this message is informational only. The user gets the | ||
226 | * proper return value | ||
227 | */ | ||
228 | TRACE_ABORT(-EINVAL, ft_t_info, | ||
229 | "req_len %d not a multiple of block size %d", | ||
230 | *req_len, (*volume)->blk_sz); | ||
231 | } | ||
232 | /* As GNU tar doesn't accept partial read counts when the | ||
233 | * multiple volume flag is set, we make sure to return the | ||
234 | * requested amount of data. Except, of course, at the end of | ||
235 | * the tape or file mark. | ||
236 | */ | ||
237 | remaining -= *req_len; | ||
238 | if (remaining <= 0) { | ||
239 | TRACE(ft_t_noise, | ||
240 | "clipped request from %d to %d.", | ||
241 | *req_len, (int)(*req_len + remaining)); | ||
242 | *req_len += remaining; | ||
243 | *req_clipped = 1; | ||
244 | } else { | ||
245 | *req_clipped = 0; | ||
246 | } | ||
247 | TRACE_EXIT 0; | ||
248 | } | ||
249 | |||
250 | /* this_segs_size: the current segment's size. | ||
251 | * buff: the USER-SPACE buffer provided by the calling function. | ||
252 | * req_len: how much data should be read at most. | ||
253 | * volume: contains information on current volume (blk_sz etc.) | ||
254 | */ | ||
255 | static int empty_deblock_buf(__u8 __user *usr_buf, const int req_len, | ||
256 | const __u8 *src_buf, const int seg_sz, | ||
257 | zft_position *pos, | ||
258 | const zft_volinfo *volume) | ||
259 | { | ||
260 | int cnt; | ||
261 | int result = 0; | ||
262 | TRACE_FUN(ft_t_flow); | ||
263 | |||
264 | TRACE(ft_t_data_flow, "this_segs_size: %d", seg_sz); | ||
265 | if (zft_use_compression && volume->use_compression) { | ||
266 | TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),); | ||
267 | TRACE_CATCH(result= (*zft_cmpr_ops->read)(&cnt, | ||
268 | usr_buf, req_len, | ||
269 | src_buf, seg_sz, | ||
270 | pos, volume),); | ||
271 | } else { | ||
272 | TRACE_CATCH(result= zft_simple_read (&cnt, | ||
273 | usr_buf, req_len, | ||
274 | src_buf, seg_sz, | ||
275 | pos, volume),); | ||
276 | } | ||
277 | pos->volume_pos += result; | ||
278 | pos->tape_pos += cnt; | ||
279 | pos->seg_byte_pos += cnt; | ||
280 | buf_len_rd -= cnt; /* remaining bytes in buffer */ | ||
281 | TRACE(ft_t_data_flow, "buf_len_rd: %d, cnt: %d", buf_len_rd, cnt); | ||
282 | if(pos->seg_byte_pos >= seg_sz) { | ||
283 | pos->seg_pos++; | ||
284 | pos->seg_byte_pos = 0; | ||
285 | } | ||
286 | TRACE(ft_t_data_flow, "bytes moved out of deblock-buffer: %d", cnt); | ||
287 | TRACE_EXIT result; | ||
288 | } | ||
289 | |||
290 | |||
291 | /* note: we store the segment id of the segment that is inside the | ||
292 | * deblock buffer. This spares a lot of ftape_read_segment()s when we | ||
293 | * use small block-sizes. The block-size may be 1kb (SECTOR_SIZE). In | ||
294 | * this case a MTFSR 28 maybe still inside the same segment. | ||
295 | */ | ||
296 | int _zft_read(char __user *buff, int req_len) | ||
297 | { | ||
298 | int req_clipped; | ||
299 | int result = 0; | ||
300 | int bytes_read = 0; | ||
301 | static unsigned int seg_sz = 0; | ||
302 | static const zft_volinfo *volume = NULL; | ||
303 | TRACE_FUN(ft_t_flow); | ||
304 | |||
305 | zft_resid = req_len; | ||
306 | result = check_read_access(&req_len, &volume, | ||
307 | &req_clipped, &zft_pos); | ||
308 | switch(result) { | ||
309 | case 0: | ||
310 | break; /* nothing special */ | ||
311 | case 1: | ||
312 | TRACE(ft_t_noise, "EOD reached"); | ||
313 | TRACE_EXIT 0; /* EOD */ | ||
314 | default: | ||
315 | TRACE_ABORT(result, ft_t_noise, | ||
316 | "check_read_access() failed with result %d", | ||
317 | result); | ||
318 | TRACE_EXIT result; | ||
319 | } | ||
320 | while (req_len > 0) { | ||
321 | /* Allow escape from this loop on signal ! | ||
322 | */ | ||
323 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
324 | /* buf_len_rd == 0 means that we need to read a new | ||
325 | * segment. | ||
326 | */ | ||
327 | if (buf_len_rd == 0) { | ||
328 | while((result = zft_fetch_segment(zft_pos.seg_pos, | ||
329 | zft_deblock_buf, | ||
330 | FT_RD_AHEAD)) == 0) { | ||
331 | zft_pos.seg_pos ++; | ||
332 | zft_pos.seg_byte_pos = 0; | ||
333 | } | ||
334 | if (result < 0) { | ||
335 | zft_resid -= bytes_read; | ||
336 | TRACE_ABORT(result, ft_t_noise, | ||
337 | "zft_fetch_segment(): %d", | ||
338 | result); | ||
339 | } | ||
340 | seg_sz = result; | ||
341 | buf_len_rd = seg_sz - zft_pos.seg_byte_pos; | ||
342 | } | ||
343 | TRACE_CATCH(result = empty_deblock_buf(buff, | ||
344 | req_len, | ||
345 | zft_deblock_buf, | ||
346 | seg_sz, | ||
347 | &zft_pos, | ||
348 | volume), | ||
349 | zft_resid -= bytes_read); | ||
350 | TRACE(ft_t_data_flow, "bytes just read: %d", result); | ||
351 | bytes_read += result; /* what we got so far */ | ||
352 | buff += result; /* index in user-buffer */ | ||
353 | req_len -= result; /* what's left from req_len */ | ||
354 | } /* while (req_len > 0) */ | ||
355 | if (req_clipped) { | ||
356 | TRACE(ft_t_data_flow, | ||
357 | "maybe partial count because of eof mark"); | ||
358 | if (zft_just_before_eof && bytes_read == 0) { | ||
359 | /* req_len was > 0, but user didn't get | ||
360 | * anything the user has read in the eof-mark | ||
361 | */ | ||
362 | zft_move_past_eof(&zft_pos); | ||
363 | ftape_abort_operation(); | ||
364 | } else { | ||
365 | /* don't skip to the next file before the user | ||
366 | * tried to read a second time past EOF Just | ||
367 | * mark that we are at EOF and maybe decrement | ||
368 | * zft_seg_pos to stay in the same volume; | ||
369 | */ | ||
370 | zft_just_before_eof = 1; | ||
371 | zft_position_before_eof(&zft_pos, volume); | ||
372 | TRACE(ft_t_noise, "just before eof"); | ||
373 | } | ||
374 | } | ||
375 | zft_resid -= result; /* for MTSTATUS */ | ||
376 | TRACE_EXIT bytes_read; | ||
377 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-read.h b/drivers/char/ftape/zftape/zftape-read.h deleted file mode 100644 index 42941de0c23a..000000000000 --- a/drivers/char/ftape/zftape/zftape-read.h +++ /dev/null | |||
@@ -1,53 +0,0 @@ | |||
1 | #ifndef _ZFTAPE_READ_H | ||
2 | #define _ZFTAPE_READ_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1996, 1997 Claus-Justus Heine | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-read.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:19:07 $ | ||
25 | * | ||
26 | * This file contains the definitions for the read functions | ||
27 | * for the zftape driver for Linux. | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include "../lowlevel/ftape-read.h" | ||
32 | |||
33 | /* ftape-read.c defined global vars. | ||
34 | */ | ||
35 | extern int zft_just_before_eof; | ||
36 | |||
37 | /* ftape-read.c defined global functions. | ||
38 | */ | ||
39 | extern void zft_zap_read_buffers(void); | ||
40 | extern int zft_read_header_segments(void); | ||
41 | extern int zft_fetch_segment_fraction(const unsigned int segment, | ||
42 | void *buffer, | ||
43 | const ft_read_mode_t read_mode, | ||
44 | const unsigned int start, | ||
45 | const unsigned int size); | ||
46 | #define zft_fetch_segment(segment, address, read_mode) \ | ||
47 | zft_fetch_segment_fraction(segment, address, read_mode, \ | ||
48 | 0, FT_SEGMENT_SIZE) | ||
49 | /* hook for the VFS interface | ||
50 | */ | ||
51 | extern int _zft_read(char __user *buff, int req_len); | ||
52 | |||
53 | #endif /* _ZFTAPE_READ_H */ | ||
diff --git a/drivers/char/ftape/zftape/zftape-rw.c b/drivers/char/ftape/zftape/zftape-rw.c deleted file mode 100644 index dab634686885..000000000000 --- a/drivers/char/ftape/zftape/zftape-rw.c +++ /dev/null | |||
@@ -1,375 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1996, 1997 Claus-Justus Heine | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; see the file COPYING. If not, write to | ||
16 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | |||
18 | * | ||
19 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-rw.c,v $ | ||
20 | * $Revision: 1.2 $ | ||
21 | * $Date: 1997/10/05 19:19:08 $ | ||
22 | * | ||
23 | * This file contains some common code for the r/w code for | ||
24 | * zftape. | ||
25 | */ | ||
26 | |||
27 | #include <linux/errno.h> | ||
28 | #include <linux/mm.h> | ||
29 | |||
30 | #include <linux/zftape.h> | ||
31 | #include "../zftape/zftape-init.h" | ||
32 | #include "../zftape/zftape-eof.h" | ||
33 | #include "../zftape/zftape-ctl.h" | ||
34 | #include "../zftape/zftape-write.h" | ||
35 | #include "../zftape/zftape-read.h" | ||
36 | #include "../zftape/zftape-rw.h" | ||
37 | #include "../zftape/zftape-vtbl.h" | ||
38 | |||
39 | /* Global vars. | ||
40 | */ | ||
41 | |||
42 | __u8 *zft_deblock_buf; | ||
43 | __u8 *zft_hseg_buf; | ||
44 | int zft_deblock_segment = -1; | ||
45 | zft_status_enum zft_io_state = zft_idle; | ||
46 | int zft_header_changed; | ||
47 | int zft_qic113; /* conform to old specs. and old zftape */ | ||
48 | int zft_use_compression; | ||
49 | zft_position zft_pos = { | ||
50 | -1, /* seg_pos */ | ||
51 | 0, /* seg_byte_pos */ | ||
52 | 0, /* tape_pos */ | ||
53 | 0 /* volume_pos */ | ||
54 | }; | ||
55 | unsigned int zft_blk_sz = CONFIG_ZFT_DFLT_BLK_SZ; | ||
56 | __s64 zft_capacity; | ||
57 | |||
58 | unsigned int zft_written_segments; | ||
59 | int zft_label_changed; | ||
60 | |||
61 | /* Local vars. | ||
62 | */ | ||
63 | |||
64 | unsigned int zft_get_seg_sz(unsigned int segment) | ||
65 | { | ||
66 | int size; | ||
67 | TRACE_FUN(ft_t_any); | ||
68 | |||
69 | size = FT_SEGMENT_SIZE - | ||
70 | count_ones(ftape_get_bad_sector_entry(segment))*FT_SECTOR_SIZE; | ||
71 | if (size > 0) { | ||
72 | TRACE_EXIT (unsigned)size; | ||
73 | } else { | ||
74 | TRACE_EXIT 0; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | /* ftape_set_flags(). Claus-Justus Heine, 1994/1995 | ||
79 | */ | ||
80 | void zft_set_flags(unsigned minor_unit) | ||
81 | { | ||
82 | TRACE_FUN(ft_t_flow); | ||
83 | |||
84 | zft_use_compression = zft_qic_mode = 0; | ||
85 | switch (minor_unit & ZFT_MINOR_OP_MASK) { | ||
86 | case (ZFT_Q80_MODE | ZFT_ZIP_MODE): | ||
87 | case ZFT_ZIP_MODE: | ||
88 | zft_use_compression = 1; | ||
89 | case 0: | ||
90 | case ZFT_Q80_MODE: | ||
91 | zft_qic_mode = 1; | ||
92 | if (zft_mt_compression) { /* override the default */ | ||
93 | zft_use_compression = 1; | ||
94 | } | ||
95 | break; | ||
96 | case ZFT_RAW_MODE: | ||
97 | TRACE(ft_t_noise, "switching to raw mode"); | ||
98 | break; | ||
99 | default: | ||
100 | TRACE(ft_t_warn, "Warning:\n" | ||
101 | KERN_INFO "Wrong combination of minor device bits.\n" | ||
102 | KERN_INFO "Switching to raw read-only mode."); | ||
103 | zft_write_protected = 1; | ||
104 | break; | ||
105 | } | ||
106 | TRACE_EXIT; | ||
107 | } | ||
108 | |||
109 | /* computes the segment and byte offset inside the segment | ||
110 | * corresponding to tape_pos. | ||
111 | * | ||
112 | * tape_pos gives the offset in bytes from the beginning of the | ||
113 | * ft_first_data_segment *seg_byte_pos is the offset in the current | ||
114 | * segment in bytes | ||
115 | * | ||
116 | * Of, if this routine was called often one should cache the last data | ||
117 | * pos it was called with, but actually this is only needed in | ||
118 | * ftape_seek_block(), that is, almost never. | ||
119 | */ | ||
120 | int zft_calc_seg_byte_coord(int *seg_byte_pos, __s64 tape_pos) | ||
121 | { | ||
122 | int segment; | ||
123 | int seg_sz; | ||
124 | TRACE_FUN(ft_t_flow); | ||
125 | |||
126 | if (tape_pos == 0) { | ||
127 | *seg_byte_pos = 0; | ||
128 | segment = ft_first_data_segment; | ||
129 | } else { | ||
130 | seg_sz = 0; | ||
131 | |||
132 | for (segment = ft_first_data_segment; | ||
133 | ((tape_pos > 0) && (segment <= ft_last_data_segment)); | ||
134 | segment++) { | ||
135 | seg_sz = zft_get_seg_sz(segment); | ||
136 | tape_pos -= seg_sz; | ||
137 | } | ||
138 | if(tape_pos >= 0) { | ||
139 | /* the case tape_pos > != 0 means that the | ||
140 | * argument tape_pos lies beyond the EOT. | ||
141 | */ | ||
142 | *seg_byte_pos= 0; | ||
143 | } else { /* tape_pos < 0 */ | ||
144 | segment--; | ||
145 | *seg_byte_pos= tape_pos + seg_sz; | ||
146 | } | ||
147 | } | ||
148 | TRACE_EXIT(segment); | ||
149 | } | ||
150 | |||
151 | /* ftape_calc_tape_pos(). | ||
152 | * | ||
153 | * computes the offset in bytes from the beginning of the | ||
154 | * ft_first_data_segment inverse to ftape_calc_seg_byte_coord | ||
155 | * | ||
156 | * We should do some caching. But how: | ||
157 | * | ||
158 | * Each time the header segments are read in, this routine is called | ||
159 | * with ft_tracks_per_tape*segments_per_track argumnet. So this should be | ||
160 | * the time to reset the cache. | ||
161 | * | ||
162 | * Also, it might be in the future that the bad sector map gets | ||
163 | * changed. -> reset the cache | ||
164 | */ | ||
165 | static int seg_pos; | ||
166 | static __s64 tape_pos; | ||
167 | |||
168 | __s64 zft_get_capacity(void) | ||
169 | { | ||
170 | seg_pos = ft_first_data_segment; | ||
171 | tape_pos = 0; | ||
172 | |||
173 | while (seg_pos <= ft_last_data_segment) { | ||
174 | tape_pos += zft_get_seg_sz(seg_pos ++); | ||
175 | } | ||
176 | return tape_pos; | ||
177 | } | ||
178 | |||
179 | __s64 zft_calc_tape_pos(int segment) | ||
180 | { | ||
181 | int d1, d2, d3; | ||
182 | TRACE_FUN(ft_t_any); | ||
183 | |||
184 | if (segment > ft_last_data_segment) { | ||
185 | TRACE_EXIT zft_capacity; | ||
186 | } | ||
187 | if (segment < ft_first_data_segment) { | ||
188 | TRACE_EXIT 0; | ||
189 | } | ||
190 | d2 = segment - seg_pos; | ||
191 | if (-d2 > 10) { | ||
192 | d1 = segment - ft_first_data_segment; | ||
193 | if (-d2 > d1) { | ||
194 | tape_pos = 0; | ||
195 | seg_pos = ft_first_data_segment; | ||
196 | d2 = d1; | ||
197 | } | ||
198 | } | ||
199 | if (d2 > 10) { | ||
200 | d3 = ft_last_data_segment - segment; | ||
201 | if (d2 > d3) { | ||
202 | tape_pos = zft_capacity; | ||
203 | seg_pos = ft_last_data_segment + 1; | ||
204 | d2 = -d3; | ||
205 | } | ||
206 | } | ||
207 | if (d2 > 0) { | ||
208 | while (seg_pos < segment) { | ||
209 | tape_pos += zft_get_seg_sz(seg_pos++); | ||
210 | } | ||
211 | } else { | ||
212 | while (seg_pos > segment) { | ||
213 | tape_pos -= zft_get_seg_sz(--seg_pos); | ||
214 | } | ||
215 | } | ||
216 | TRACE(ft_t_noise, "new cached pos: %d", seg_pos); | ||
217 | |||
218 | TRACE_EXIT tape_pos; | ||
219 | } | ||
220 | |||
221 | /* copy Z-label string to buffer, keeps track of the correct offset in | ||
222 | * `buffer' | ||
223 | */ | ||
224 | void zft_update_label(__u8 *buffer) | ||
225 | { | ||
226 | TRACE_FUN(ft_t_flow); | ||
227 | |||
228 | if (strncmp(&buffer[FT_LABEL], ZFTAPE_LABEL, | ||
229 | sizeof(ZFTAPE_LABEL)-1) != 0) { | ||
230 | TRACE(ft_t_info, "updating label from \"%s\" to \"%s\"", | ||
231 | &buffer[FT_LABEL], ZFTAPE_LABEL); | ||
232 | strcpy(&buffer[FT_LABEL], ZFTAPE_LABEL); | ||
233 | memset(&buffer[FT_LABEL] + sizeof(ZFTAPE_LABEL) - 1, ' ', | ||
234 | FT_LABEL_SZ - sizeof(ZFTAPE_LABEL + 1)); | ||
235 | PUT4(buffer, FT_LABEL_DATE, 0); | ||
236 | zft_label_changed = zft_header_changed = 1; /* changed */ | ||
237 | } | ||
238 | TRACE_EXIT; | ||
239 | } | ||
240 | |||
241 | int zft_verify_write_segments(unsigned int segment, | ||
242 | __u8 *data, size_t size, | ||
243 | __u8 *buffer) | ||
244 | { | ||
245 | int result; | ||
246 | __u8 *write_buf; | ||
247 | __u8 *src_buf; | ||
248 | int single; | ||
249 | int seg_pos; | ||
250 | int seg_sz; | ||
251 | int remaining; | ||
252 | ft_write_mode_t write_mode; | ||
253 | TRACE_FUN(ft_t_flow); | ||
254 | |||
255 | seg_pos = segment; | ||
256 | seg_sz = zft_get_seg_sz(seg_pos); | ||
257 | src_buf = data; | ||
258 | single = size <= seg_sz; | ||
259 | remaining = size; | ||
260 | do { | ||
261 | TRACE(ft_t_noise, "\n" | ||
262 | KERN_INFO "remaining: %d\n" | ||
263 | KERN_INFO "seg_sz : %d\n" | ||
264 | KERN_INFO "segment : %d", | ||
265 | remaining, seg_sz, seg_pos); | ||
266 | if (remaining == seg_sz) { | ||
267 | write_buf = src_buf; | ||
268 | write_mode = single ? FT_WR_SINGLE : FT_WR_MULTI; | ||
269 | remaining = 0; | ||
270 | } else if (remaining > seg_sz) { | ||
271 | write_buf = src_buf; | ||
272 | write_mode = FT_WR_ASYNC; /* don't start tape */ | ||
273 | remaining -= seg_sz; | ||
274 | } else { /* remaining < seg_sz */ | ||
275 | write_buf = buffer; | ||
276 | memcpy(write_buf, src_buf, remaining); | ||
277 | memset(&write_buf[remaining],'\0',seg_sz-remaining); | ||
278 | write_mode = single ? FT_WR_SINGLE : FT_WR_MULTI; | ||
279 | remaining = 0; | ||
280 | } | ||
281 | if ((result = ftape_write_segment(seg_pos, | ||
282 | write_buf, | ||
283 | write_mode)) != seg_sz) { | ||
284 | TRACE(ft_t_err, "Error: " | ||
285 | "Couldn't write segment %d", seg_pos); | ||
286 | TRACE_EXIT result < 0 ? result : -EIO; /* bail out */ | ||
287 | } | ||
288 | zft_written_segments ++; | ||
289 | seg_sz = zft_get_seg_sz(++seg_pos); | ||
290 | src_buf += result; | ||
291 | } while (remaining > 0); | ||
292 | if (ftape_get_status()->fti_state == writing) { | ||
293 | TRACE_CATCH(ftape_loop_until_writes_done(),); | ||
294 | TRACE_CATCH(ftape_abort_operation(),); | ||
295 | zft_prevent_flush(); | ||
296 | } | ||
297 | seg_pos = segment; | ||
298 | src_buf = data; | ||
299 | remaining = size; | ||
300 | do { | ||
301 | TRACE_CATCH(result = ftape_read_segment(seg_pos, buffer, | ||
302 | single ? FT_RD_SINGLE | ||
303 | : FT_RD_AHEAD),); | ||
304 | if (memcmp(src_buf, buffer, | ||
305 | remaining > result ? result : remaining) != 0) { | ||
306 | TRACE_ABORT(-EIO, ft_t_err, | ||
307 | "Failed to verify written segment %d", | ||
308 | seg_pos); | ||
309 | } | ||
310 | remaining -= result; | ||
311 | TRACE(ft_t_noise, "verify successful:\n" | ||
312 | KERN_INFO "segment : %d\n" | ||
313 | KERN_INFO "segsize : %d\n" | ||
314 | KERN_INFO "remaining: %d", | ||
315 | seg_pos, result, remaining); | ||
316 | src_buf += seg_sz; | ||
317 | seg_pos++; | ||
318 | } while (remaining > 0); | ||
319 | TRACE_EXIT size; | ||
320 | } | ||
321 | |||
322 | |||
323 | /* zft_erase(). implemented compression-handling | ||
324 | * | ||
325 | * calculate the first data-segment when using/not using compression. | ||
326 | * | ||
327 | * update header-segment and compression-map-segment. | ||
328 | */ | ||
329 | int zft_erase(void) | ||
330 | { | ||
331 | int result = 0; | ||
332 | TRACE_FUN(ft_t_flow); | ||
333 | |||
334 | if (!zft_header_read) { | ||
335 | TRACE_CATCH(zft_vmalloc_once((void **)&zft_hseg_buf, | ||
336 | FT_SEGMENT_SIZE),); | ||
337 | /* no need to read the vtbl and compression map */ | ||
338 | TRACE_CATCH(ftape_read_header_segment(zft_hseg_buf),); | ||
339 | if ((zft_old_ftape = | ||
340 | zft_ftape_validate_label(&zft_hseg_buf[FT_LABEL]))) { | ||
341 | zft_ftape_extract_file_marks(zft_hseg_buf); | ||
342 | } | ||
343 | TRACE(ft_t_noise, | ||
344 | "ft_first_data_segment: %d, ft_last_data_segment: %d", | ||
345 | ft_first_data_segment, ft_last_data_segment); | ||
346 | zft_qic113 = (ft_format_code != fmt_normal && | ||
347 | ft_format_code != fmt_1100ft && | ||
348 | ft_format_code != fmt_425ft); | ||
349 | } | ||
350 | if (zft_old_ftape) { | ||
351 | zft_clear_ftape_file_marks(); | ||
352 | zft_old_ftape = 0; /* no longer old ftape */ | ||
353 | } | ||
354 | PUT2(zft_hseg_buf, FT_CMAP_START, 0); | ||
355 | zft_volume_table_changed = 1; | ||
356 | zft_capacity = zft_get_capacity(); | ||
357 | zft_init_vtbl(); | ||
358 | /* the rest must be done in ftape_update_header_segments | ||
359 | */ | ||
360 | zft_header_read = 1; | ||
361 | zft_header_changed = 1; /* force update of timestamp */ | ||
362 | result = zft_update_header_segments(); | ||
363 | |||
364 | ftape_abort_operation(); | ||
365 | |||
366 | zft_reset_position(&zft_pos); | ||
367 | zft_set_flags (zft_unit); | ||
368 | TRACE_EXIT result; | ||
369 | } | ||
370 | |||
371 | unsigned int zft_get_time(void) | ||
372 | { | ||
373 | unsigned int date = FT_TIME_STAMP(2097, 11, 30, 23, 59, 59); /* fun */ | ||
374 | return date; | ||
375 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-rw.h b/drivers/char/ftape/zftape/zftape-rw.h deleted file mode 100644 index 1ceec22b60bd..000000000000 --- a/drivers/char/ftape/zftape/zftape-rw.h +++ /dev/null | |||
@@ -1,101 +0,0 @@ | |||
1 | #ifndef _ZFTAPE_RW_H | ||
2 | #define _ZFTAPE_RW_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1996, 1997 Claus-Justus Heine. | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-rw.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:19:09 $ | ||
25 | * | ||
26 | * This file contains the definitions for the read and write | ||
27 | * functions for the QIC-117 floppy-tape driver for Linux. | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include "../zftape/zftape-buffers.h" | ||
32 | |||
33 | #define SEGMENTS_PER_TAPE (ft_segments_per_track * ft_tracks_per_tape) | ||
34 | |||
35 | /* QIC-113 Rev. G says that `a maximum of 63488 raw bytes may be | ||
36 | * compressed into a single frame'. | ||
37 | * Maybe we should stick to 32kb to make it more `beautiful' | ||
38 | */ | ||
39 | #define ZFT_MAX_BLK_SZ (62*1024) /* bytes */ | ||
40 | #if !defined(CONFIG_ZFT_DFLT_BLK_SZ) | ||
41 | # define CONFIG_ZFT_DFLT_BLK_SZ (10*1024) /* bytes, default of gnu tar */ | ||
42 | #elif CONFIG_ZFT_DFLT_BLK_SZ == 0 | ||
43 | # undef CONFIG_ZFT_DFLT_BLK_SZ | ||
44 | # define CONFIG_ZFT_DFLT_BLK_SZ 1 | ||
45 | #elif (CONFIG_ZFT_DFLT_BLK_SZ % 1024) != 0 | ||
46 | # error CONFIG_ZFT_DFLT_BLK_SZ must be 1 or a multiple of 1024 | ||
47 | #endif | ||
48 | /* The *optional* compression routines need some overhead per tape | ||
49 | * block for their purposes. Instead of asking the actual compression | ||
50 | * implementation how much it needs, we restrict this overhead to be | ||
51 | * maximal of ZFT_CMPT_OVERHEAD size. We need this for EOT | ||
52 | * conditions. The tape is assumed to be logical at EOT when the | ||
53 | * distance from the physical EOT is less than | ||
54 | * one tape block + ZFT_CMPR_OVERHEAD | ||
55 | */ | ||
56 | #define ZFT_CMPR_OVERHEAD 16 /* bytes */ | ||
57 | |||
58 | typedef enum | ||
59 | { | ||
60 | zft_idle = 0, | ||
61 | zft_reading, | ||
62 | zft_writing, | ||
63 | } zft_status_enum; | ||
64 | |||
65 | typedef struct /* all values measured in bytes */ | ||
66 | { | ||
67 | int seg_pos; /* segment currently positioned at */ | ||
68 | int seg_byte_pos; /* offset in current segment */ | ||
69 | __s64 tape_pos; /* real offset from BOT */ | ||
70 | __s64 volume_pos; /* pos. in uncompressed data stream in | ||
71 | * current volume | ||
72 | */ | ||
73 | } zft_position; | ||
74 | |||
75 | extern zft_position zft_pos; | ||
76 | extern __u8 *zft_deblock_buf; | ||
77 | extern __u8 *zft_hseg_buf; | ||
78 | extern int zft_deblock_segment; | ||
79 | extern zft_status_enum zft_io_state; | ||
80 | extern int zft_header_changed; | ||
81 | extern int zft_qic113; /* conform to old specs. and old zftape */ | ||
82 | extern int zft_use_compression; | ||
83 | extern unsigned int zft_blk_sz; | ||
84 | extern __s64 zft_capacity; | ||
85 | extern unsigned int zft_written_segments; | ||
86 | extern int zft_label_changed; | ||
87 | |||
88 | /* zftape-rw.c exported functions | ||
89 | */ | ||
90 | extern unsigned int zft_get_seg_sz(unsigned int segment); | ||
91 | extern void zft_set_flags(unsigned int minor_unit); | ||
92 | extern int zft_calc_seg_byte_coord(int *seg_byte_pos, __s64 tape_pos); | ||
93 | extern __s64 zft_calc_tape_pos(int segment); | ||
94 | extern __s64 zft_get_capacity(void); | ||
95 | extern void zft_update_label(__u8 *buffer); | ||
96 | extern int zft_erase(void); | ||
97 | extern int zft_verify_write_segments(unsigned int segment, | ||
98 | __u8 *data, size_t size, __u8 *buffer); | ||
99 | extern unsigned int zft_get_time(void); | ||
100 | #endif /* _ZFTAPE_RW_H */ | ||
101 | |||
diff --git a/drivers/char/ftape/zftape/zftape-vtbl.c b/drivers/char/ftape/zftape/zftape-vtbl.c deleted file mode 100644 index ad7f8be6340b..000000000000 --- a/drivers/char/ftape/zftape/zftape-vtbl.c +++ /dev/null | |||
@@ -1,757 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 1995-1997 Claus-Justus Heine | ||
3 | |||
4 | This program is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU General Public License as | ||
6 | published by the Free Software Foundation; either version 2, or (at | ||
7 | your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, but | ||
10 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; see the file COPYING. If not, write to | ||
16 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, | ||
17 | USA. | ||
18 | |||
19 | * | ||
20 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-vtbl.c,v $ | ||
21 | * $Revision: 1.7.6.1 $ | ||
22 | * $Date: 1997/11/24 13:48:31 $ | ||
23 | * | ||
24 | * This file defines a volume table as defined in various QIC | ||
25 | * standards. | ||
26 | * | ||
27 | * This is a minimal implementation, just allowing ordinary DOS | ||
28 | * :( prgrams to identify the cartridge as used. | ||
29 | */ | ||
30 | |||
31 | #include <linux/errno.h> | ||
32 | #include <linux/mm.h> | ||
33 | #include <linux/slab.h> | ||
34 | |||
35 | #include <linux/zftape.h> | ||
36 | #include "../zftape/zftape-init.h" | ||
37 | #include "../zftape/zftape-eof.h" | ||
38 | #include "../zftape/zftape-ctl.h" | ||
39 | #include "../zftape/zftape-write.h" | ||
40 | #include "../zftape/zftape-read.h" | ||
41 | #include "../zftape/zftape-rw.h" | ||
42 | #include "../zftape/zftape-vtbl.h" | ||
43 | |||
44 | #define ZFT_CMAP_HACK /* leave this defined to hide the compression map */ | ||
45 | |||
46 | /* | ||
47 | * global variables | ||
48 | */ | ||
49 | int zft_qic_mode = 1; /* use the vtbl */ | ||
50 | int zft_old_ftape; /* prevents old ftaped tapes to be overwritten */ | ||
51 | int zft_volume_table_changed; /* for write_header_segments() */ | ||
52 | |||
53 | /* | ||
54 | * private variables (only exported for inline functions) | ||
55 | */ | ||
56 | LIST_HEAD(zft_vtbl); | ||
57 | |||
58 | /* We could also allocate these dynamically when extracting the volume table | ||
59 | * sizeof(zft_volinfo) is about 32 or something close to that | ||
60 | */ | ||
61 | static zft_volinfo tape_vtbl; | ||
62 | static zft_volinfo eot_vtbl; | ||
63 | static zft_volinfo *cur_vtbl; | ||
64 | |||
65 | static inline void zft_new_vtbl_entry(void) | ||
66 | { | ||
67 | struct list_head *tmp = &zft_last_vtbl->node; | ||
68 | zft_volinfo *new = zft_kmalloc(sizeof(zft_volinfo)); | ||
69 | |||
70 | list_add(&new->node, tmp); | ||
71 | new->count = zft_eom_vtbl->count ++; | ||
72 | } | ||
73 | |||
74 | void zft_free_vtbl(void) | ||
75 | { | ||
76 | for (;;) { | ||
77 | struct list_head *tmp = zft_vtbl.prev; | ||
78 | zft_volinfo *vtbl; | ||
79 | |||
80 | if (tmp == &zft_vtbl) | ||
81 | break; | ||
82 | list_del(tmp); | ||
83 | vtbl = list_entry(tmp, zft_volinfo, node); | ||
84 | zft_kfree(vtbl, sizeof(zft_volinfo)); | ||
85 | } | ||
86 | INIT_LIST_HEAD(&zft_vtbl); | ||
87 | cur_vtbl = NULL; | ||
88 | } | ||
89 | |||
90 | /* initialize vtbl, called by ftape_new_cartridge() | ||
91 | */ | ||
92 | void zft_init_vtbl(void) | ||
93 | { | ||
94 | zft_volinfo *new; | ||
95 | |||
96 | zft_free_vtbl(); | ||
97 | |||
98 | /* Create the two dummy vtbl entries | ||
99 | */ | ||
100 | new = zft_kmalloc(sizeof(zft_volinfo)); | ||
101 | list_add(&new->node, &zft_vtbl); | ||
102 | new = zft_kmalloc(sizeof(zft_volinfo)); | ||
103 | list_add(&new->node, &zft_vtbl); | ||
104 | zft_head_vtbl->end_seg = ft_first_data_segment; | ||
105 | zft_head_vtbl->blk_sz = zft_blk_sz; | ||
106 | zft_head_vtbl->count = -1; | ||
107 | zft_eom_vtbl->start_seg = ft_first_data_segment + 1; | ||
108 | zft_eom_vtbl->end_seg = ft_last_data_segment + 1; | ||
109 | zft_eom_vtbl->blk_sz = zft_blk_sz; | ||
110 | zft_eom_vtbl->count = 0; | ||
111 | |||
112 | /* Reset the pointer for zft_find_volume() | ||
113 | */ | ||
114 | cur_vtbl = zft_eom_vtbl; | ||
115 | |||
116 | /* initialize the dummy vtbl entries for zft_qic_mode == 0 | ||
117 | */ | ||
118 | eot_vtbl.start_seg = ft_last_data_segment + 1; | ||
119 | eot_vtbl.end_seg = ft_last_data_segment + 1; | ||
120 | eot_vtbl.blk_sz = zft_blk_sz; | ||
121 | eot_vtbl.count = -1; | ||
122 | tape_vtbl.start_seg = ft_first_data_segment; | ||
123 | tape_vtbl.end_seg = ft_last_data_segment; | ||
124 | tape_vtbl.blk_sz = zft_blk_sz; | ||
125 | tape_vtbl.size = zft_capacity; | ||
126 | tape_vtbl.count = 0; | ||
127 | } | ||
128 | |||
129 | /* check for a valid VTBL signature. | ||
130 | */ | ||
131 | static int vtbl_signature_valid(__u8 signature[4]) | ||
132 | { | ||
133 | const char *vtbl_ids[] = VTBL_IDS; /* valid signatures */ | ||
134 | int j; | ||
135 | |||
136 | for (j = 0; | ||
137 | (j < NR_ITEMS(vtbl_ids)) && (memcmp(signature, vtbl_ids[j], 4) != 0); | ||
138 | j++); | ||
139 | return j < NR_ITEMS(vtbl_ids); | ||
140 | } | ||
141 | |||
142 | /* We used to store the block-size of the volume in the volume-label, | ||
143 | * using the keyword "blocksize". The blocksize written to the | ||
144 | * volume-label is in bytes. | ||
145 | * | ||
146 | * We use this now only for compatibility with old zftape version. We | ||
147 | * store the blocksize directly as binary number in the vendor | ||
148 | * extension part of the volume entry. | ||
149 | */ | ||
150 | static int check_volume_label(const char *label, int *blk_sz) | ||
151 | { | ||
152 | int valid_format; | ||
153 | char *blocksize; | ||
154 | TRACE_FUN(ft_t_flow); | ||
155 | |||
156 | TRACE(ft_t_noise, "called with \"%s\" / \"%s\"", label, ZFT_VOL_NAME); | ||
157 | if (strncmp(label, ZFT_VOL_NAME, strlen(ZFT_VOL_NAME)) != 0) { | ||
158 | *blk_sz = 1; /* smallest block size that we allow */ | ||
159 | valid_format = 0; | ||
160 | } else { | ||
161 | TRACE(ft_t_noise, "got old style zftape vtbl entry"); | ||
162 | /* get the default blocksize */ | ||
163 | /* use the kernel strstr() */ | ||
164 | blocksize= strstr(label, " blocksize "); | ||
165 | if (blocksize) { | ||
166 | blocksize += strlen(" blocksize "); | ||
167 | for(*blk_sz= 0; | ||
168 | *blocksize >= '0' && *blocksize <= '9'; | ||
169 | blocksize++) { | ||
170 | *blk_sz *= 10; | ||
171 | *blk_sz += *blocksize - '0'; | ||
172 | } | ||
173 | if (*blk_sz > ZFT_MAX_BLK_SZ) { | ||
174 | *blk_sz= 1; | ||
175 | valid_format= 0; | ||
176 | } else { | ||
177 | valid_format = 1; | ||
178 | } | ||
179 | } else { | ||
180 | *blk_sz= 1; | ||
181 | valid_format= 0; | ||
182 | } | ||
183 | } | ||
184 | TRACE_EXIT valid_format; | ||
185 | } | ||
186 | |||
187 | /* check for a zftape volume | ||
188 | */ | ||
189 | static int check_volume(__u8 *entry, zft_volinfo *volume) | ||
190 | { | ||
191 | TRACE_FUN(ft_t_flow); | ||
192 | |||
193 | if(strncmp(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG, | ||
194 | strlen(ZFTAPE_SIG)) == 0) { | ||
195 | TRACE(ft_t_noise, "got new style zftape vtbl entry"); | ||
196 | volume->blk_sz = GET2(entry, VTBL_EXT+EXT_ZFTAPE_BLKSZ); | ||
197 | volume->qic113 = entry[VTBL_EXT+EXT_ZFTAPE_QIC113]; | ||
198 | TRACE_EXIT 1; | ||
199 | } else { | ||
200 | TRACE_EXIT check_volume_label(&entry[VTBL_DESC], &volume->blk_sz); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | |||
205 | /* create zftape specific vtbl entry, the volume bounds are inserted | ||
206 | * in the calling function, zft_create_volume_headers() | ||
207 | */ | ||
208 | static void create_zft_volume(__u8 *entry, zft_volinfo *vtbl) | ||
209 | { | ||
210 | TRACE_FUN(ft_t_flow); | ||
211 | |||
212 | memset(entry, 0, VTBL_SIZE); | ||
213 | memcpy(&entry[VTBL_SIG], VTBL_ID, 4); | ||
214 | sprintf(&entry[VTBL_DESC], ZFT_VOL_NAME" %03d", vtbl->count); | ||
215 | entry[VTBL_FLAGS] = (VTBL_FL_NOT_VERIFIED | VTBL_FL_SEG_SPANNING); | ||
216 | entry[VTBL_M_NO] = 1; /* multi_cartridge_count */ | ||
217 | strcpy(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG); | ||
218 | PUT2(entry, VTBL_EXT+EXT_ZFTAPE_BLKSZ, vtbl->blk_sz); | ||
219 | if (zft_qic113) { | ||
220 | PUT8(entry, VTBL_DATA_SIZE, vtbl->size); | ||
221 | entry[VTBL_CMPR] = VTBL_CMPR_UNREG; | ||
222 | if (vtbl->use_compression) { /* use compression: */ | ||
223 | entry[VTBL_CMPR] |= VTBL_CMPR_USED; | ||
224 | } | ||
225 | entry[VTBL_EXT+EXT_ZFTAPE_QIC113] = 1; | ||
226 | } else { | ||
227 | PUT4(entry, VTBL_DATA_SIZE, vtbl->size); | ||
228 | entry[VTBL_K_CMPR] = VTBL_CMPR_UNREG; | ||
229 | if (vtbl->use_compression) { /* use compression: */ | ||
230 | entry[VTBL_K_CMPR] |= VTBL_CMPR_USED; | ||
231 | } | ||
232 | } | ||
233 | if (ft_format_code == fmt_big) { | ||
234 | /* SCSI like vtbl, store the number of used | ||
235 | * segments as 4 byte value | ||
236 | */ | ||
237 | PUT4(entry, VTBL_SCSI_SEGS, vtbl->end_seg-vtbl->start_seg + 1); | ||
238 | } else { | ||
239 | /* normal, QIC-80MC like vtbl | ||
240 | */ | ||
241 | PUT2(entry, VTBL_START, vtbl->start_seg); | ||
242 | PUT2(entry, VTBL_END, vtbl->end_seg); | ||
243 | } | ||
244 | TRACE_EXIT; | ||
245 | } | ||
246 | |||
247 | /* this one creates the volume headers for each volume. It is assumed | ||
248 | * that buffer already contains the old volume-table, so that vtbl | ||
249 | * entries without the zft_volume flag set can savely be ignored. | ||
250 | */ | ||
251 | static void zft_create_volume_headers(__u8 *buffer) | ||
252 | { | ||
253 | __u8 *entry; | ||
254 | struct list_head *tmp; | ||
255 | zft_volinfo *vtbl; | ||
256 | TRACE_FUN(ft_t_flow); | ||
257 | |||
258 | #ifdef ZFT_CMAP_HACK | ||
259 | if((strncmp(&buffer[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG, | ||
260 | strlen(ZFTAPE_SIG)) == 0) && | ||
261 | buffer[VTBL_EXT+EXT_ZFTAPE_CMAP] != 0) { | ||
262 | TRACE(ft_t_noise, "deleting cmap volume"); | ||
263 | memmove(buffer, buffer + VTBL_SIZE, | ||
264 | FT_SEGMENT_SIZE - VTBL_SIZE); | ||
265 | } | ||
266 | #endif | ||
267 | entry = buffer; | ||
268 | for (tmp = zft_head_vtbl->node.next; | ||
269 | tmp != &zft_eom_vtbl->node; | ||
270 | tmp = tmp->next) { | ||
271 | vtbl = list_entry(tmp, zft_volinfo, node); | ||
272 | /* we now fill in the values only for newly created volumes. | ||
273 | */ | ||
274 | if (vtbl->new_volume) { | ||
275 | create_zft_volume(entry, vtbl); | ||
276 | vtbl->new_volume = 0; /* clear the flag */ | ||
277 | } | ||
278 | |||
279 | DUMP_VOLINFO(ft_t_noise, &entry[VTBL_DESC], vtbl); | ||
280 | entry += VTBL_SIZE; | ||
281 | } | ||
282 | memset(entry, 0, FT_SEGMENT_SIZE - zft_eom_vtbl->count * VTBL_SIZE); | ||
283 | TRACE_EXIT; | ||
284 | } | ||
285 | |||
286 | /* write volume table to tape. Calls zft_create_volume_headers() | ||
287 | */ | ||
288 | int zft_update_volume_table(unsigned int segment) | ||
289 | { | ||
290 | int result = 0; | ||
291 | __u8 *verify_buf = NULL; | ||
292 | TRACE_FUN(ft_t_flow); | ||
293 | |||
294 | TRACE_CATCH(result = ftape_read_segment(ft_first_data_segment, | ||
295 | zft_deblock_buf, | ||
296 | FT_RD_SINGLE),); | ||
297 | zft_create_volume_headers(zft_deblock_buf); | ||
298 | TRACE(ft_t_noise, "writing volume table segment %d", segment); | ||
299 | if (zft_vmalloc_once(&verify_buf, FT_SEGMENT_SIZE) == 0) { | ||
300 | TRACE_CATCH(zft_verify_write_segments(segment, | ||
301 | zft_deblock_buf, result, | ||
302 | verify_buf), | ||
303 | zft_vfree(&verify_buf, FT_SEGMENT_SIZE)); | ||
304 | zft_vfree(&verify_buf, FT_SEGMENT_SIZE); | ||
305 | } else { | ||
306 | TRACE_CATCH(ftape_write_segment(segment, zft_deblock_buf, | ||
307 | FT_WR_SINGLE),); | ||
308 | } | ||
309 | TRACE_EXIT 0; | ||
310 | } | ||
311 | |||
312 | /* non zftape volumes are handled in raw mode. Thus we need to | ||
313 | * calculate the raw amount of data contained in those segments. | ||
314 | */ | ||
315 | static void extract_alien_volume(__u8 *entry, zft_volinfo *vtbl) | ||
316 | { | ||
317 | TRACE_FUN(ft_t_flow); | ||
318 | |||
319 | vtbl->size = (zft_calc_tape_pos(zft_last_vtbl->end_seg+1) - | ||
320 | zft_calc_tape_pos(zft_last_vtbl->start_seg)); | ||
321 | vtbl->use_compression = 0; | ||
322 | vtbl->qic113 = zft_qic113; | ||
323 | if (vtbl->qic113) { | ||
324 | TRACE(ft_t_noise, | ||
325 | "Fake alien volume's size from " LL_X " to " LL_X, | ||
326 | LL(GET8(entry, VTBL_DATA_SIZE)), LL(vtbl->size)); | ||
327 | } else { | ||
328 | TRACE(ft_t_noise, | ||
329 | "Fake alien volume's size from %d to " LL_X, | ||
330 | (int)GET4(entry, VTBL_DATA_SIZE), LL(vtbl->size)); | ||
331 | } | ||
332 | TRACE_EXIT; | ||
333 | } | ||
334 | |||
335 | |||
336 | /* extract an zftape specific volume | ||
337 | */ | ||
338 | static void extract_zft_volume(__u8 *entry, zft_volinfo *vtbl) | ||
339 | { | ||
340 | TRACE_FUN(ft_t_flow); | ||
341 | |||
342 | if (vtbl->qic113) { | ||
343 | vtbl->size = GET8(entry, VTBL_DATA_SIZE); | ||
344 | vtbl->use_compression = | ||
345 | (entry[VTBL_CMPR] & VTBL_CMPR_USED) != 0; | ||
346 | } else { | ||
347 | vtbl->size = GET4(entry, VTBL_DATA_SIZE); | ||
348 | if (entry[VTBL_K_CMPR] & VTBL_CMPR_UNREG) { | ||
349 | vtbl->use_compression = | ||
350 | (entry[VTBL_K_CMPR] & VTBL_CMPR_USED) != 0; | ||
351 | } else if (entry[VTBL_CMPR] & VTBL_CMPR_UNREG) { | ||
352 | vtbl->use_compression = | ||
353 | (entry[VTBL_CMPR] & VTBL_CMPR_USED) != 0; | ||
354 | } else { | ||
355 | TRACE(ft_t_warn, "Geeh! There is something wrong:\n" | ||
356 | KERN_INFO "QIC compression (Rev = K): %x\n" | ||
357 | KERN_INFO "QIC compression (Rev > K): %x", | ||
358 | entry[VTBL_K_CMPR], entry[VTBL_CMPR]); | ||
359 | } | ||
360 | } | ||
361 | TRACE_EXIT; | ||
362 | } | ||
363 | |||
364 | /* extract the volume table from buffer. "buffer" must already contain | ||
365 | * the vtbl-segment | ||
366 | */ | ||
367 | int zft_extract_volume_headers(__u8 *buffer) | ||
368 | { | ||
369 | __u8 *entry; | ||
370 | TRACE_FUN(ft_t_flow); | ||
371 | |||
372 | zft_init_vtbl(); | ||
373 | entry = buffer; | ||
374 | #ifdef ZFT_CMAP_HACK | ||
375 | if ((strncmp(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG, | ||
376 | strlen(ZFTAPE_SIG)) == 0) && | ||
377 | entry[VTBL_EXT+EXT_ZFTAPE_CMAP] != 0) { | ||
378 | TRACE(ft_t_noise, "ignoring cmap volume"); | ||
379 | entry += VTBL_SIZE; | ||
380 | } | ||
381 | #endif | ||
382 | /* the end of the vtbl is indicated by an invalid signature | ||
383 | */ | ||
384 | while (vtbl_signature_valid(&entry[VTBL_SIG]) && | ||
385 | (entry - buffer) < FT_SEGMENT_SIZE) { | ||
386 | zft_new_vtbl_entry(); | ||
387 | if (ft_format_code == fmt_big) { | ||
388 | /* SCSI like vtbl, stores only the number of | ||
389 | * segments used | ||
390 | */ | ||
391 | unsigned int num_segments= GET4(entry, VTBL_SCSI_SEGS); | ||
392 | zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; | ||
393 | zft_last_vtbl->end_seg = | ||
394 | zft_last_vtbl->start_seg + num_segments - 1; | ||
395 | } else { | ||
396 | /* `normal', QIC-80 like vtbl | ||
397 | */ | ||
398 | zft_last_vtbl->start_seg = GET2(entry, VTBL_START); | ||
399 | zft_last_vtbl->end_seg = GET2(entry, VTBL_END); | ||
400 | } | ||
401 | zft_eom_vtbl->start_seg = zft_last_vtbl->end_seg + 1; | ||
402 | /* check if we created this volume and get the | ||
403 | * blk_sz | ||
404 | */ | ||
405 | zft_last_vtbl->zft_volume = check_volume(entry, zft_last_vtbl); | ||
406 | if (zft_last_vtbl->zft_volume == 0) { | ||
407 | extract_alien_volume(entry, zft_last_vtbl); | ||
408 | } else { | ||
409 | extract_zft_volume(entry, zft_last_vtbl); | ||
410 | } | ||
411 | DUMP_VOLINFO(ft_t_noise, &entry[VTBL_DESC], zft_last_vtbl); | ||
412 | entry +=VTBL_SIZE; | ||
413 | } | ||
414 | #if 0 | ||
415 | /* | ||
416 | * undefine to test end of tape handling | ||
417 | */ | ||
418 | zft_new_vtbl_entry(); | ||
419 | zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; | ||
420 | zft_last_vtbl->end_seg = ft_last_data_segment - 10; | ||
421 | zft_last_vtbl->blk_sz = zft_blk_sz; | ||
422 | zft_last_vtbl->zft_volume = 1; | ||
423 | zft_last_vtbl->qic113 = zft_qic113; | ||
424 | zft_last_vtbl->size = (zft_calc_tape_pos(zft_last_vtbl->end_seg+1) | ||
425 | - zft_calc_tape_pos(zft_last_vtbl->start_seg)); | ||
426 | #endif | ||
427 | TRACE_EXIT 0; | ||
428 | } | ||
429 | |||
430 | /* this functions translates the failed_sector_log, misused as | ||
431 | * EOF-marker list, into a virtual volume table. The table mustn't be | ||
432 | * written to tape, because this would occupy the first data segment, | ||
433 | * which should be the volume table, but is actually the first segment | ||
434 | * that is filled with data (when using standard ftape). We assume, | ||
435 | * that we get a non-empty failed_sector_log. | ||
436 | */ | ||
437 | int zft_fake_volume_headers (eof_mark_union *eof_map, int num_failed_sectors) | ||
438 | { | ||
439 | unsigned int segment, sector; | ||
440 | int have_eom = 0; | ||
441 | int vol_no; | ||
442 | TRACE_FUN(ft_t_flow); | ||
443 | |||
444 | if ((num_failed_sectors >= 2) && | ||
445 | (GET2(&eof_map[num_failed_sectors - 1].mark.segment, 0) | ||
446 | == | ||
447 | GET2(&eof_map[num_failed_sectors - 2].mark.segment, 0) + 1) && | ||
448 | (GET2(&eof_map[num_failed_sectors - 1].mark.date, 0) == 1)) { | ||
449 | /* this should be eom. We keep the remainder of the | ||
450 | * tape as another volume. | ||
451 | */ | ||
452 | have_eom = 1; | ||
453 | } | ||
454 | zft_init_vtbl(); | ||
455 | zft_eom_vtbl->start_seg = ft_first_data_segment; | ||
456 | for(vol_no = 0; vol_no < num_failed_sectors - have_eom; vol_no ++) { | ||
457 | zft_new_vtbl_entry(); | ||
458 | |||
459 | segment = GET2(&eof_map[vol_no].mark.segment, 0); | ||
460 | sector = GET2(&eof_map[vol_no].mark.date, 0); | ||
461 | |||
462 | zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; | ||
463 | zft_last_vtbl->end_seg = segment; | ||
464 | zft_eom_vtbl->start_seg = segment + 1; | ||
465 | zft_last_vtbl->blk_sz = 1; | ||
466 | zft_last_vtbl->size = | ||
467 | (zft_calc_tape_pos(zft_last_vtbl->end_seg) | ||
468 | - zft_calc_tape_pos(zft_last_vtbl->start_seg) | ||
469 | + (sector-1) * FT_SECTOR_SIZE); | ||
470 | TRACE(ft_t_noise, | ||
471 | "failed sector log: segment: %d, sector: %d", | ||
472 | segment, sector); | ||
473 | DUMP_VOLINFO(ft_t_noise, "Faked volume", zft_last_vtbl); | ||
474 | } | ||
475 | if (!have_eom) { | ||
476 | zft_new_vtbl_entry(); | ||
477 | zft_last_vtbl->start_seg = zft_eom_vtbl->start_seg; | ||
478 | zft_last_vtbl->end_seg = ft_last_data_segment; | ||
479 | zft_eom_vtbl->start_seg = ft_last_data_segment + 1; | ||
480 | zft_last_vtbl->size = zft_capacity; | ||
481 | zft_last_vtbl->size -= zft_calc_tape_pos(zft_last_vtbl->start_seg); | ||
482 | zft_last_vtbl->blk_sz = 1; | ||
483 | DUMP_VOLINFO(ft_t_noise, "Faked volume",zft_last_vtbl); | ||
484 | } | ||
485 | TRACE_EXIT 0; | ||
486 | } | ||
487 | |||
488 | /* update the internal volume table | ||
489 | * | ||
490 | * if before start of last volume: erase all following volumes if | ||
491 | * inside a volume: set end of volume to infinity | ||
492 | * | ||
493 | * this function is intended to be called every time _ftape_write() is | ||
494 | * called | ||
495 | * | ||
496 | * return: 0 if no new volume was created, 1 if a new volume was | ||
497 | * created | ||
498 | * | ||
499 | * NOTE: we don't need to check for zft_mode as ftape_write() does | ||
500 | * that already. This function gets never called without accessing | ||
501 | * zftape via the *qft* devices | ||
502 | */ | ||
503 | |||
504 | int zft_open_volume(zft_position *pos, int blk_sz, int use_compression) | ||
505 | { | ||
506 | TRACE_FUN(ft_t_flow); | ||
507 | |||
508 | if (!zft_qic_mode) { | ||
509 | TRACE_EXIT 0; | ||
510 | } | ||
511 | if (zft_tape_at_lbot(pos)) { | ||
512 | zft_init_vtbl(); | ||
513 | if(zft_old_ftape) { | ||
514 | /* clear old ftape's eof marks */ | ||
515 | zft_clear_ftape_file_marks(); | ||
516 | zft_old_ftape = 0; /* no longer old ftape */ | ||
517 | } | ||
518 | zft_reset_position(pos); | ||
519 | } | ||
520 | if (pos->seg_pos != zft_last_vtbl->end_seg + 1) { | ||
521 | TRACE_ABORT(-EIO, ft_t_bug, | ||
522 | "BUG: seg_pos: %d, zft_last_vtbl->end_seg: %d", | ||
523 | pos->seg_pos, zft_last_vtbl->end_seg); | ||
524 | } | ||
525 | TRACE(ft_t_noise, "create new volume"); | ||
526 | if (zft_eom_vtbl->count >= ZFT_MAX_VOLUMES) { | ||
527 | TRACE_ABORT(-ENOSPC, ft_t_err, | ||
528 | "Error: maxmimal number of volumes exhausted " | ||
529 | "(maxmimum is %d)", ZFT_MAX_VOLUMES); | ||
530 | } | ||
531 | zft_new_vtbl_entry(); | ||
532 | pos->volume_pos = pos->seg_byte_pos = 0; | ||
533 | zft_last_vtbl->start_seg = pos->seg_pos; | ||
534 | zft_last_vtbl->end_seg = ft_last_data_segment; /* infinity */ | ||
535 | zft_last_vtbl->blk_sz = blk_sz; | ||
536 | zft_last_vtbl->size = zft_capacity; | ||
537 | zft_last_vtbl->zft_volume = 1; | ||
538 | zft_last_vtbl->use_compression = use_compression; | ||
539 | zft_last_vtbl->qic113 = zft_qic113; | ||
540 | zft_last_vtbl->new_volume = 1; | ||
541 | zft_last_vtbl->open = 1; | ||
542 | zft_volume_table_changed = 1; | ||
543 | zft_eom_vtbl->start_seg = ft_last_data_segment + 1; | ||
544 | TRACE_EXIT 0; | ||
545 | } | ||
546 | |||
547 | /* perform mtfsf, mtbsf, not allowed without zft_qic_mode | ||
548 | */ | ||
549 | int zft_skip_volumes(int count, zft_position *pos) | ||
550 | { | ||
551 | const zft_volinfo *vtbl; | ||
552 | TRACE_FUN(ft_t_flow); | ||
553 | |||
554 | TRACE(ft_t_noise, "count: %d", count); | ||
555 | |||
556 | vtbl= zft_find_volume(pos->seg_pos); | ||
557 | while (count > 0 && vtbl != zft_eom_vtbl) { | ||
558 | vtbl = list_entry(vtbl->node.next, zft_volinfo, node); | ||
559 | count --; | ||
560 | } | ||
561 | while (count < 0 && vtbl != zft_first_vtbl) { | ||
562 | vtbl = list_entry(vtbl->node.prev, zft_volinfo, node); | ||
563 | count ++; | ||
564 | } | ||
565 | pos->seg_pos = vtbl->start_seg; | ||
566 | pos->seg_byte_pos = 0; | ||
567 | pos->volume_pos = 0; | ||
568 | pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); | ||
569 | zft_just_before_eof = vtbl->size == 0; | ||
570 | if (zft_cmpr_ops) { | ||
571 | (*zft_cmpr_ops->reset)(); | ||
572 | } | ||
573 | zft_deblock_segment = -1; /* no need to keep cache */ | ||
574 | TRACE(ft_t_noise, "repositioning to:\n" | ||
575 | KERN_INFO "zft_seg_pos : %d\n" | ||
576 | KERN_INFO "zft_seg_byte_pos : %d\n" | ||
577 | KERN_INFO "zft_tape_pos : " LL_X "\n" | ||
578 | KERN_INFO "zft_volume_pos : " LL_X "\n" | ||
579 | KERN_INFO "file number : %d", | ||
580 | pos->seg_pos, pos->seg_byte_pos, | ||
581 | LL(pos->tape_pos), LL(pos->volume_pos), vtbl->count); | ||
582 | zft_resid = count < 0 ? -count : count; | ||
583 | TRACE_EXIT zft_resid ? -EINVAL : 0; | ||
584 | } | ||
585 | |||
586 | /* the following simply returns the raw data position of the EOM | ||
587 | * marker, MTIOCSIZE ioctl | ||
588 | */ | ||
589 | __s64 zft_get_eom_pos(void) | ||
590 | { | ||
591 | if (zft_qic_mode) { | ||
592 | return zft_calc_tape_pos(zft_eom_vtbl->start_seg); | ||
593 | } else { | ||
594 | /* there is only one volume in raw mode */ | ||
595 | return zft_capacity; | ||
596 | } | ||
597 | } | ||
598 | |||
599 | /* skip to eom, used for MTEOM | ||
600 | */ | ||
601 | void zft_skip_to_eom(zft_position *pos) | ||
602 | { | ||
603 | TRACE_FUN(ft_t_flow); | ||
604 | pos->seg_pos = zft_eom_vtbl->start_seg; | ||
605 | pos->seg_byte_pos = | ||
606 | pos->volume_pos = | ||
607 | zft_just_before_eof = 0; | ||
608 | pos->tape_pos = zft_calc_tape_pos(pos->seg_pos); | ||
609 | TRACE(ft_t_noise, "ftape positioned to segment %d, data pos " LL_X, | ||
610 | pos->seg_pos, LL(pos->tape_pos)); | ||
611 | TRACE_EXIT; | ||
612 | } | ||
613 | |||
614 | /* write an EOF-marker by setting zft_last_vtbl->end_seg to seg_pos. | ||
615 | * NOTE: this function assumes that zft_last_vtbl points to a valid | ||
616 | * vtbl entry | ||
617 | * | ||
618 | * NOTE: this routine always positions before the EOF marker | ||
619 | */ | ||
620 | int zft_close_volume(zft_position *pos) | ||
621 | { | ||
622 | TRACE_FUN(ft_t_any); | ||
623 | |||
624 | if (zft_vtbl_empty || !zft_last_vtbl->open) { /* should not happen */ | ||
625 | TRACE(ft_t_noise, "There are no volumes to finish"); | ||
626 | TRACE_EXIT -EIO; | ||
627 | } | ||
628 | if (pos->seg_byte_pos == 0 && | ||
629 | pos->seg_pos != zft_last_vtbl->start_seg) { | ||
630 | pos->seg_pos --; | ||
631 | pos->seg_byte_pos = zft_get_seg_sz(pos->seg_pos); | ||
632 | } | ||
633 | zft_last_vtbl->end_seg = pos->seg_pos; | ||
634 | zft_last_vtbl->size = pos->volume_pos; | ||
635 | zft_volume_table_changed = 1; | ||
636 | zft_just_before_eof = 1; | ||
637 | zft_eom_vtbl->start_seg = zft_last_vtbl->end_seg + 1; | ||
638 | zft_last_vtbl->open = 0; /* closed */ | ||
639 | TRACE_EXIT 0; | ||
640 | } | ||
641 | |||
642 | /* write count file-marks at current position. | ||
643 | * | ||
644 | * The tape is positioned after the eof-marker, that is at byte 0 of | ||
645 | * the segment following the eof-marker | ||
646 | * | ||
647 | * this function is only allowed in zft_qic_mode | ||
648 | * | ||
649 | * Only allowed when tape is at BOT or EOD. | ||
650 | */ | ||
651 | int zft_weof(unsigned int count, zft_position *pos) | ||
652 | { | ||
653 | |||
654 | TRACE_FUN(ft_t_flow); | ||
655 | |||
656 | if (!count) { /* write zero EOF marks should be a real no-op */ | ||
657 | TRACE_EXIT 0; | ||
658 | } | ||
659 | zft_volume_table_changed = 1; | ||
660 | if (zft_tape_at_lbot(pos)) { | ||
661 | zft_init_vtbl(); | ||
662 | if(zft_old_ftape) { | ||
663 | /* clear old ftape's eof marks */ | ||
664 | zft_clear_ftape_file_marks(); | ||
665 | zft_old_ftape = 0; /* no longer old ftape */ | ||
666 | } | ||
667 | } | ||
668 | if (zft_last_vtbl->open) { | ||
669 | zft_close_volume(pos); | ||
670 | zft_move_past_eof(pos); | ||
671 | count --; | ||
672 | } | ||
673 | /* now it's easy, just append eof-marks, that is empty | ||
674 | * volumes, to the end of the already recorded media. | ||
675 | */ | ||
676 | while (count > 0 && | ||
677 | pos->seg_pos <= ft_last_data_segment && | ||
678 | zft_eom_vtbl->count < ZFT_MAX_VOLUMES) { | ||
679 | TRACE(ft_t_noise, | ||
680 | "Writing zero sized file at segment %d", pos->seg_pos); | ||
681 | zft_new_vtbl_entry(); | ||
682 | zft_last_vtbl->start_seg = pos->seg_pos; | ||
683 | zft_last_vtbl->end_seg = pos->seg_pos; | ||
684 | zft_last_vtbl->size = 0; | ||
685 | zft_last_vtbl->blk_sz = zft_blk_sz; | ||
686 | zft_last_vtbl->zft_volume = 1; | ||
687 | zft_last_vtbl->use_compression = 0; | ||
688 | pos->tape_pos += zft_get_seg_sz(pos->seg_pos); | ||
689 | zft_eom_vtbl->start_seg = ++ pos->seg_pos; | ||
690 | count --; | ||
691 | } | ||
692 | if (count > 0) { | ||
693 | /* there are two possibilities: end of tape, or the | ||
694 | * maximum number of files is exhausted. | ||
695 | */ | ||
696 | zft_resid = count; | ||
697 | TRACE(ft_t_noise,"Number of marks NOT written: %d", zft_resid); | ||
698 | if (zft_eom_vtbl->count == ZFT_MAX_VOLUMES) { | ||
699 | TRACE_ABORT(-EINVAL, ft_t_warn, | ||
700 | "maximum allowed number of files " | ||
701 | "exhausted: %d", ZFT_MAX_VOLUMES); | ||
702 | } else { | ||
703 | TRACE_ABORT(-ENOSPC, | ||
704 | ft_t_noise, "reached end of tape"); | ||
705 | } | ||
706 | } | ||
707 | TRACE_EXIT 0; | ||
708 | } | ||
709 | |||
710 | const zft_volinfo *zft_find_volume(unsigned int seg_pos) | ||
711 | { | ||
712 | TRACE_FUN(ft_t_flow); | ||
713 | |||
714 | TRACE(ft_t_any, "called with seg_pos %d",seg_pos); | ||
715 | if (!zft_qic_mode) { | ||
716 | if (seg_pos > ft_last_data_segment) { | ||
717 | TRACE_EXIT &eot_vtbl; | ||
718 | } | ||
719 | tape_vtbl.blk_sz = zft_blk_sz; | ||
720 | TRACE_EXIT &tape_vtbl; | ||
721 | } | ||
722 | if (seg_pos < zft_first_vtbl->start_seg) { | ||
723 | TRACE_EXIT (cur_vtbl = zft_first_vtbl); | ||
724 | } | ||
725 | while (seg_pos > cur_vtbl->end_seg) { | ||
726 | cur_vtbl = list_entry(cur_vtbl->node.next, zft_volinfo, node); | ||
727 | TRACE(ft_t_noise, "%d - %d", cur_vtbl->start_seg, cur_vtbl->end_seg); | ||
728 | } | ||
729 | while (seg_pos < cur_vtbl->start_seg) { | ||
730 | cur_vtbl = list_entry(cur_vtbl->node.prev, zft_volinfo, node); | ||
731 | TRACE(ft_t_noise, "%d - %d", cur_vtbl->start_seg, cur_vtbl->end_seg); | ||
732 | } | ||
733 | if (seg_pos > cur_vtbl->end_seg || seg_pos < cur_vtbl->start_seg) { | ||
734 | TRACE(ft_t_bug, "This cannot happen"); | ||
735 | } | ||
736 | DUMP_VOLINFO(ft_t_noise, "", cur_vtbl); | ||
737 | TRACE_EXIT cur_vtbl; | ||
738 | } | ||
739 | |||
740 | /* this function really assumes that we are just before eof | ||
741 | */ | ||
742 | void zft_move_past_eof(zft_position *pos) | ||
743 | { | ||
744 | TRACE_FUN(ft_t_flow); | ||
745 | |||
746 | TRACE(ft_t_noise, "old seg. pos: %d", pos->seg_pos); | ||
747 | pos->tape_pos += zft_get_seg_sz(pos->seg_pos++) - pos->seg_byte_pos; | ||
748 | pos->seg_byte_pos = 0; | ||
749 | pos->volume_pos = 0; | ||
750 | if (zft_cmpr_ops) { | ||
751 | (*zft_cmpr_ops->reset)(); | ||
752 | } | ||
753 | zft_just_before_eof = 0; | ||
754 | zft_deblock_segment = -1; /* no need to cache it anymore */ | ||
755 | TRACE(ft_t_noise, "new seg. pos: %d", pos->seg_pos); | ||
756 | TRACE_EXIT; | ||
757 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-vtbl.h b/drivers/char/ftape/zftape/zftape-vtbl.h deleted file mode 100644 index f31d196d1759..000000000000 --- a/drivers/char/ftape/zftape/zftape-vtbl.h +++ /dev/null | |||
@@ -1,227 +0,0 @@ | |||
1 | #ifndef _ZFTAPE_VTBL_H | ||
2 | #define _ZFTAPE_VTBL_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (c) 1995-1997 Claus-Justus Heine | ||
6 | |||
7 | This program is free software; you can redistribute it and/or | ||
8 | modify it under the terms of the GNU General Public License as | ||
9 | published by the Free Software Foundation; either version 2, or (at | ||
10 | your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, but | ||
13 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, | ||
20 | USA. | ||
21 | |||
22 | * | ||
23 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-vtbl.h,v $ | ||
24 | * $Revision: 1.3 $ | ||
25 | * $Date: 1997/10/28 14:30:09 $ | ||
26 | * | ||
27 | * This file defines a volume table as defined in the QIC-80 | ||
28 | * development standards. | ||
29 | */ | ||
30 | |||
31 | #include <linux/list.h> | ||
32 | |||
33 | #include "../lowlevel/ftape-tracing.h" | ||
34 | |||
35 | #include "../zftape/zftape-eof.h" | ||
36 | #include "../zftape/zftape-ctl.h" | ||
37 | #include "../zftape/zftape-rw.h" | ||
38 | |||
39 | #define VTBL_SIZE 128 /* bytes */ | ||
40 | |||
41 | /* The following are offsets in the vtbl. */ | ||
42 | #define VTBL_SIG 0 | ||
43 | #define VTBL_START 4 | ||
44 | #define VTBL_END 6 | ||
45 | #define VTBL_DESC 8 | ||
46 | #define VTBL_DATE 52 | ||
47 | #define VTBL_FLAGS 56 | ||
48 | #define VTBL_FL_VENDOR_SPECIFIC (1<<0) | ||
49 | #define VTBL_FL_MUTLI_CARTRIDGE (1<<1) | ||
50 | #define VTBL_FL_NOT_VERIFIED (1<<2) | ||
51 | #define VTBL_FL_REDIR_INHIBIT (1<<3) | ||
52 | #define VTBL_FL_SEG_SPANNING (1<<4) | ||
53 | #define VTBL_FL_DIRECTORY_LAST (1<<5) | ||
54 | #define VTBL_FL_RESERVED_6 (1<<6) | ||
55 | #define VTBL_FL_RESERVED_7 (1<<7) | ||
56 | #define VTBL_M_NO 57 | ||
57 | #define VTBL_EXT 58 | ||
58 | #define EXT_ZFTAPE_SIG 0 | ||
59 | #define EXT_ZFTAPE_BLKSZ 10 | ||
60 | #define EXT_ZFTAPE_CMAP 12 | ||
61 | #define EXT_ZFTAPE_QIC113 13 | ||
62 | #define VTBL_PWD 84 | ||
63 | #define VTBL_DIR_SIZE 92 | ||
64 | #define VTBL_DATA_SIZE 96 | ||
65 | #define VTBL_OS_VERSION 104 | ||
66 | #define VTBL_SRC_DRIVE 106 | ||
67 | #define VTBL_DEV 122 | ||
68 | #define VTBL_RESERVED_1 123 | ||
69 | #define VTBL_CMPR 124 | ||
70 | #define VTBL_CMPR_UNREG 0x3f | ||
71 | #define VTBL_CMPR_USED 0x80 | ||
72 | #define VTBL_FMT 125 | ||
73 | #define VTBL_RESERVED_2 126 | ||
74 | #define VTBL_RESERVED_3 127 | ||
75 | /* compatibility with pre revision K */ | ||
76 | #define VTBL_K_CMPR 120 | ||
77 | |||
78 | /* the next is used by QIC-3020 tapes with format code 6 (>2^16 | ||
79 | * segments) It is specified in QIC-113, Rev. G, Section 5 (SCSI | ||
80 | * volume table). The difference is simply, that we only store the | ||
81 | * number of segments used, not the starting segment. | ||
82 | */ | ||
83 | #define VTBL_SCSI_SEGS 4 /* is a 4 byte value */ | ||
84 | |||
85 | /* one vtbl is 128 bytes, that results in a maximum number of | ||
86 | * 29*1024/128 = 232 volumes. | ||
87 | */ | ||
88 | #define ZFT_MAX_VOLUMES (FT_SEGMENT_SIZE/VTBL_SIZE) | ||
89 | #define VTBL_ID "VTBL" | ||
90 | #define VTBL_IDS { VTBL_ID, "XTBL", "UTID", "EXVT" } /* other valid ids */ | ||
91 | #define ZFT_VOL_NAME "zftape volume" /* volume label used by me */ | ||
92 | #define ZFTAPE_SIG "LINUX ZFT" | ||
93 | |||
94 | /* global variables | ||
95 | */ | ||
96 | typedef struct zft_internal_vtbl | ||
97 | { | ||
98 | struct list_head node; | ||
99 | int count; | ||
100 | unsigned int start_seg; /* 32 bits are enough for now */ | ||
101 | unsigned int end_seg; /* 32 bits are enough for now */ | ||
102 | __s64 size; /* uncompressed size */ | ||
103 | unsigned int blk_sz; /* block size for this volume */ | ||
104 | unsigned int zft_volume :1; /* zftape created this volume */ | ||
105 | unsigned int use_compression:1; /* compressed volume */ | ||
106 | unsigned int qic113 :1; /* layout of compressed block | ||
107 | * info and vtbl conforms to | ||
108 | * QIC-113, Rev. G | ||
109 | */ | ||
110 | unsigned int new_volume :1; /* it was created by us, this | ||
111 | * run. this allows the | ||
112 | * fields that aren't really | ||
113 | * used by zftape to be filled | ||
114 | * in by some user level | ||
115 | * program. | ||
116 | */ | ||
117 | unsigned int open :1; /* just in progress of being | ||
118 | * written | ||
119 | */ | ||
120 | } zft_volinfo; | ||
121 | |||
122 | extern struct list_head zft_vtbl; | ||
123 | #define zft_head_vtbl list_entry(zft_vtbl.next, zft_volinfo, node) | ||
124 | #define zft_eom_vtbl list_entry(zft_vtbl.prev, zft_volinfo, node) | ||
125 | #define zft_last_vtbl list_entry(zft_eom_vtbl->node.prev, zft_volinfo, node) | ||
126 | #define zft_first_vtbl list_entry(zft_head_vtbl->node.next, zft_volinfo, node) | ||
127 | #define zft_vtbl_empty (zft_eom_vtbl->node.prev == &zft_head_vtbl->node) | ||
128 | |||
129 | #define DUMP_VOLINFO(level, desc, info) \ | ||
130 | { \ | ||
131 | char tmp[21]; \ | ||
132 | strlcpy(tmp, desc, sizeof(tmp)); \ | ||
133 | TRACE(level, "Volume %d:\n" \ | ||
134 | KERN_INFO "description : %s\n" \ | ||
135 | KERN_INFO "first segment: %d\n" \ | ||
136 | KERN_INFO "last segment: %d\n" \ | ||
137 | KERN_INFO "size : " LL_X "\n" \ | ||
138 | KERN_INFO "block size : %d\n" \ | ||
139 | KERN_INFO "compression : %d\n" \ | ||
140 | KERN_INFO "zftape volume: %d\n" \ | ||
141 | KERN_INFO "QIC-113 conf.: %d", \ | ||
142 | (info)->count, tmp, (info)->start_seg, (info)->end_seg, \ | ||
143 | LL((info)->size), (info)->blk_sz, \ | ||
144 | (info)->use_compression != 0, (info)->zft_volume != 0, \ | ||
145 | (info)->qic113 != 0); \ | ||
146 | } | ||
147 | |||
148 | extern int zft_qic_mode; | ||
149 | extern int zft_old_ftape; | ||
150 | extern int zft_volume_table_changed; | ||
151 | |||
152 | /* exported functions */ | ||
153 | extern void zft_init_vtbl (void); | ||
154 | extern void zft_free_vtbl (void); | ||
155 | extern int zft_extract_volume_headers(__u8 *buffer); | ||
156 | extern int zft_update_volume_table (unsigned int segment); | ||
157 | extern int zft_open_volume (zft_position *pos, | ||
158 | int blk_sz, int use_compression); | ||
159 | extern int zft_close_volume (zft_position *pos); | ||
160 | extern const zft_volinfo *zft_find_volume(unsigned int seg_pos); | ||
161 | extern int zft_skip_volumes (int count, zft_position *pos); | ||
162 | extern __s64 zft_get_eom_pos (void); | ||
163 | extern void zft_skip_to_eom (zft_position *pos); | ||
164 | extern int zft_fake_volume_headers (eof_mark_union *eof_map, | ||
165 | int num_failed_sectors); | ||
166 | extern int zft_weof (unsigned int count, zft_position *pos); | ||
167 | extern void zft_move_past_eof (zft_position *pos); | ||
168 | |||
169 | static inline int zft_tape_at_eod (const zft_position *pos); | ||
170 | static inline int zft_tape_at_lbot (const zft_position *pos); | ||
171 | static inline void zft_position_before_eof (zft_position *pos, | ||
172 | const zft_volinfo *volume); | ||
173 | static inline __s64 zft_check_for_eof(const zft_volinfo *vtbl, | ||
174 | const zft_position *pos); | ||
175 | |||
176 | /* this function decrements the zft_seg_pos counter if we are right | ||
177 | * at the beginning of a segment. This is to handle fsfm/bsfm -- we | ||
178 | * need to position before the eof mark. NOTE: zft_tape_pos is not | ||
179 | * changed | ||
180 | */ | ||
181 | static inline void zft_position_before_eof(zft_position *pos, | ||
182 | const zft_volinfo *volume) | ||
183 | { | ||
184 | TRACE_FUN(ft_t_flow); | ||
185 | |||
186 | if (pos->seg_pos == volume->end_seg + 1 && pos->seg_byte_pos == 0) { | ||
187 | pos->seg_pos --; | ||
188 | pos->seg_byte_pos = zft_get_seg_sz(pos->seg_pos); | ||
189 | } | ||
190 | TRACE_EXIT; | ||
191 | } | ||
192 | |||
193 | /* Mmmh. Is the position at the end of the last volume, that is right | ||
194 | * before the last EOF mark also logical an EOD condition? | ||
195 | */ | ||
196 | static inline int zft_tape_at_eod(const zft_position *pos) | ||
197 | { | ||
198 | TRACE_FUN(ft_t_any); | ||
199 | |||
200 | if (zft_qic_mode) { | ||
201 | TRACE_EXIT (pos->seg_pos >= zft_eom_vtbl->start_seg || | ||
202 | zft_last_vtbl->open); | ||
203 | } else { | ||
204 | TRACE_EXIT pos->seg_pos > ft_last_data_segment; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | static inline int zft_tape_at_lbot(const zft_position *pos) | ||
209 | { | ||
210 | if (zft_qic_mode) { | ||
211 | return (pos->seg_pos <= zft_first_vtbl->start_seg && | ||
212 | pos->volume_pos == 0); | ||
213 | } else { | ||
214 | return (pos->seg_pos <= ft_first_data_segment && | ||
215 | pos->volume_pos == 0); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | /* This one checks for EOF. return remaing space (may be negative) | ||
220 | */ | ||
221 | static inline __s64 zft_check_for_eof(const zft_volinfo *vtbl, | ||
222 | const zft_position *pos) | ||
223 | { | ||
224 | return (__s64)(vtbl->size - pos->volume_pos); | ||
225 | } | ||
226 | |||
227 | #endif /* _ZFTAPE_VTBL_H */ | ||
diff --git a/drivers/char/ftape/zftape/zftape-write.c b/drivers/char/ftape/zftape/zftape-write.c deleted file mode 100644 index 94327b8c97b9..000000000000 --- a/drivers/char/ftape/zftape/zftape-write.c +++ /dev/null | |||
@@ -1,483 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1996, 1997 Claus Heine | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; see the file COPYING. If not, write to | ||
16 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | |||
18 | * | ||
19 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-write.c,v $ | ||
20 | * $Revision: 1.3 $ | ||
21 | * $Date: 1997/11/06 00:50:29 $ | ||
22 | * | ||
23 | * This file contains the writing code | ||
24 | * for the QIC-117 floppy-tape driver for Linux. | ||
25 | */ | ||
26 | |||
27 | #include <linux/errno.h> | ||
28 | #include <linux/mm.h> | ||
29 | |||
30 | #include <linux/zftape.h> | ||
31 | |||
32 | #include <asm/uaccess.h> | ||
33 | |||
34 | #include "../zftape/zftape-init.h" | ||
35 | #include "../zftape/zftape-eof.h" | ||
36 | #include "../zftape/zftape-ctl.h" | ||
37 | #include "../zftape/zftape-write.h" | ||
38 | #include "../zftape/zftape-read.h" | ||
39 | #include "../zftape/zftape-rw.h" | ||
40 | #include "../zftape/zftape-vtbl.h" | ||
41 | |||
42 | /* Global vars. | ||
43 | */ | ||
44 | |||
45 | /* Local vars. | ||
46 | */ | ||
47 | static int last_write_failed; | ||
48 | static int need_flush; | ||
49 | |||
50 | void zft_prevent_flush(void) | ||
51 | { | ||
52 | need_flush = 0; | ||
53 | } | ||
54 | |||
55 | static int zft_write_header_segments(__u8* buffer) | ||
56 | { | ||
57 | int header_1_ok = 0; | ||
58 | int header_2_ok = 0; | ||
59 | unsigned int time_stamp; | ||
60 | TRACE_FUN(ft_t_noise); | ||
61 | |||
62 | TRACE_CATCH(ftape_abort_operation(),); | ||
63 | ftape_seek_to_bot(); /* prevents extra rewind */ | ||
64 | if (GET4(buffer, 0) != FT_HSEG_MAGIC) { | ||
65 | TRACE_ABORT(-EIO, ft_t_err, | ||
66 | "wrong header signature found, aborting"); | ||
67 | } | ||
68 | /* Be optimistic: */ | ||
69 | PUT4(buffer, FT_SEG_CNT, | ||
70 | zft_written_segments + GET4(buffer, FT_SEG_CNT) + 2); | ||
71 | if ((time_stamp = zft_get_time()) != 0) { | ||
72 | PUT4(buffer, FT_WR_DATE, time_stamp); | ||
73 | if (zft_label_changed) { | ||
74 | PUT4(buffer, FT_LABEL_DATE, time_stamp); | ||
75 | } | ||
76 | } | ||
77 | TRACE(ft_t_noise, | ||
78 | "writing first header segment %d", ft_header_segment_1); | ||
79 | header_1_ok = zft_verify_write_segments(ft_header_segment_1, | ||
80 | buffer, FT_SEGMENT_SIZE, | ||
81 | zft_deblock_buf) >= 0; | ||
82 | TRACE(ft_t_noise, | ||
83 | "writing second header segment %d", ft_header_segment_2); | ||
84 | header_2_ok = zft_verify_write_segments(ft_header_segment_2, | ||
85 | buffer, FT_SEGMENT_SIZE, | ||
86 | zft_deblock_buf) >= 0; | ||
87 | if (!header_1_ok) { | ||
88 | TRACE(ft_t_warn, "Warning: " | ||
89 | "update of first header segment failed"); | ||
90 | } | ||
91 | if (!header_2_ok) { | ||
92 | TRACE(ft_t_warn, "Warning: " | ||
93 | "update of second header segment failed"); | ||
94 | } | ||
95 | if (!header_1_ok && !header_2_ok) { | ||
96 | TRACE_ABORT(-EIO, ft_t_err, "Error: " | ||
97 | "update of both header segments failed."); | ||
98 | } | ||
99 | TRACE_EXIT 0; | ||
100 | } | ||
101 | |||
102 | int zft_update_header_segments(void) | ||
103 | { | ||
104 | TRACE_FUN(ft_t_noise); | ||
105 | |||
106 | /* must NOT use zft_write_protected, as it also includes the | ||
107 | * file access mode. But we also want to update when soft | ||
108 | * write protection is enabled (O_RDONLY) | ||
109 | */ | ||
110 | if (ft_write_protected || zft_old_ftape) { | ||
111 | TRACE_ABORT(0, ft_t_noise, "Tape set read-only: no update"); | ||
112 | } | ||
113 | if (!zft_header_read) { | ||
114 | TRACE_ABORT(0, ft_t_noise, "Nothing to update"); | ||
115 | } | ||
116 | if (!zft_header_changed) { | ||
117 | zft_header_changed = zft_written_segments > 0; | ||
118 | } | ||
119 | if (!zft_header_changed && !zft_volume_table_changed) { | ||
120 | TRACE_ABORT(0, ft_t_noise, "Nothing to update"); | ||
121 | } | ||
122 | TRACE(ft_t_noise, "Updating header segments"); | ||
123 | if (ftape_get_status()->fti_state == writing) { | ||
124 | TRACE_CATCH(ftape_loop_until_writes_done(),); | ||
125 | } | ||
126 | TRACE_CATCH(ftape_abort_operation(),); | ||
127 | |||
128 | zft_deblock_segment = -1; /* invalidate the cache */ | ||
129 | if (zft_header_changed) { | ||
130 | TRACE_CATCH(zft_write_header_segments(zft_hseg_buf),); | ||
131 | } | ||
132 | if (zft_volume_table_changed) { | ||
133 | TRACE_CATCH(zft_update_volume_table(ft_first_data_segment),); | ||
134 | } | ||
135 | zft_header_changed = | ||
136 | zft_volume_table_changed = | ||
137 | zft_label_changed = | ||
138 | zft_written_segments = 0; | ||
139 | TRACE_CATCH(ftape_abort_operation(),); | ||
140 | ftape_seek_to_bot(); | ||
141 | TRACE_EXIT 0; | ||
142 | } | ||
143 | |||
144 | static int read_merge_buffer(int seg_pos, __u8 *buffer, int offset, int seg_sz) | ||
145 | { | ||
146 | int result = 0; | ||
147 | const ft_trace_t old_tracing = TRACE_LEVEL; | ||
148 | TRACE_FUN(ft_t_flow); | ||
149 | |||
150 | if (zft_qic_mode) { | ||
151 | /* writing in the middle of a volume is NOT allowed | ||
152 | * | ||
153 | */ | ||
154 | TRACE(ft_t_noise, "No need to read a segment"); | ||
155 | memset(buffer + offset, 0, seg_sz - offset); | ||
156 | TRACE_EXIT 0; | ||
157 | } | ||
158 | TRACE(ft_t_any, "waiting"); | ||
159 | ftape_start_writing(FT_WR_MULTI); | ||
160 | TRACE_CATCH(ftape_loop_until_writes_done(),); | ||
161 | |||
162 | TRACE(ft_t_noise, "trying to read segment %d from offset %d", | ||
163 | seg_pos, offset); | ||
164 | SET_TRACE_LEVEL(ft_t_bug); | ||
165 | result = zft_fetch_segment_fraction(seg_pos, buffer, | ||
166 | FT_RD_SINGLE, | ||
167 | offset, seg_sz - offset); | ||
168 | SET_TRACE_LEVEL(old_tracing); | ||
169 | if (result != (seg_sz - offset)) { | ||
170 | TRACE(ft_t_noise, "Ignore error: read_segment() result: %d", | ||
171 | result); | ||
172 | memset(buffer + offset, 0, seg_sz - offset); | ||
173 | } | ||
174 | TRACE_EXIT 0; | ||
175 | } | ||
176 | |||
177 | /* flush the write buffer to tape and write an eof-marker at the | ||
178 | * current position if not in raw mode. This function always | ||
179 | * positions the tape before the eof-marker. _ftape_close() should | ||
180 | * then advance to the next segment. | ||
181 | * | ||
182 | * the parameter "finish_volume" describes whether to position before | ||
183 | * or after the possibly created file-mark. We always position after | ||
184 | * the file-mark when called from ftape_close() and a flush was needed | ||
185 | * (that is ftape_write() was the last tape operation before calling | ||
186 | * ftape_flush) But we always position before the file-mark when this | ||
187 | * function get's called from outside ftape_close() | ||
188 | */ | ||
189 | int zft_flush_buffers(void) | ||
190 | { | ||
191 | int result; | ||
192 | int data_remaining; | ||
193 | int this_segs_size; | ||
194 | TRACE_FUN(ft_t_flow); | ||
195 | |||
196 | TRACE(ft_t_data_flow, | ||
197 | "entered, ftape_state = %d", ftape_get_status()->fti_state); | ||
198 | if (ftape_get_status()->fti_state != writing && !need_flush) { | ||
199 | TRACE_ABORT(0, ft_t_noise, "no need for flush"); | ||
200 | } | ||
201 | zft_io_state = zft_idle; /* triggers some initializations for the | ||
202 | * read and write routines | ||
203 | */ | ||
204 | if (last_write_failed) { | ||
205 | ftape_abort_operation(); | ||
206 | TRACE_EXIT -EIO; | ||
207 | } | ||
208 | TRACE(ft_t_noise, "flushing write buffers"); | ||
209 | this_segs_size = zft_get_seg_sz(zft_pos.seg_pos); | ||
210 | if (this_segs_size == zft_pos.seg_byte_pos) { | ||
211 | zft_pos.seg_pos ++; | ||
212 | data_remaining = zft_pos.seg_byte_pos = 0; | ||
213 | } else { | ||
214 | data_remaining = zft_pos.seg_byte_pos; | ||
215 | } | ||
216 | /* If there is any data not written to tape yet, append zero's | ||
217 | * up to the end of the sector (if using compression) or merge | ||
218 | * it with the data existing on the tape Then write the | ||
219 | * segment(s) to tape. | ||
220 | */ | ||
221 | TRACE(ft_t_noise, "Position:\n" | ||
222 | KERN_INFO "seg_pos : %d\n" | ||
223 | KERN_INFO "byte pos : %d\n" | ||
224 | KERN_INFO "remaining: %d", | ||
225 | zft_pos.seg_pos, zft_pos.seg_byte_pos, data_remaining); | ||
226 | if (data_remaining > 0) { | ||
227 | do { | ||
228 | this_segs_size = zft_get_seg_sz(zft_pos.seg_pos); | ||
229 | if (this_segs_size > data_remaining) { | ||
230 | TRACE_CATCH(read_merge_buffer(zft_pos.seg_pos, | ||
231 | zft_deblock_buf, | ||
232 | data_remaining, | ||
233 | this_segs_size), | ||
234 | last_write_failed = 1); | ||
235 | } | ||
236 | result = ftape_write_segment(zft_pos.seg_pos, | ||
237 | zft_deblock_buf, | ||
238 | FT_WR_MULTI); | ||
239 | if (result != this_segs_size) { | ||
240 | TRACE(ft_t_err, "flush buffers failed"); | ||
241 | zft_pos.tape_pos -= zft_pos.seg_byte_pos; | ||
242 | zft_pos.seg_byte_pos = 0; | ||
243 | |||
244 | last_write_failed = 1; | ||
245 | TRACE_EXIT result; | ||
246 | } | ||
247 | zft_written_segments ++; | ||
248 | TRACE(ft_t_data_flow, | ||
249 | "flush, moved out buffer: %d", result); | ||
250 | /* need next segment for more data (empty segments?) | ||
251 | */ | ||
252 | if (result < data_remaining) { | ||
253 | if (result > 0) { | ||
254 | /* move remainder to buffer beginning | ||
255 | */ | ||
256 | memmove(zft_deblock_buf, | ||
257 | zft_deblock_buf + result, | ||
258 | FT_SEGMENT_SIZE - result); | ||
259 | } | ||
260 | } | ||
261 | data_remaining -= result; | ||
262 | zft_pos.seg_pos ++; | ||
263 | } while (data_remaining > 0); | ||
264 | TRACE(ft_t_any, "result: %d", result); | ||
265 | zft_deblock_segment = --zft_pos.seg_pos; | ||
266 | if (data_remaining == 0) { /* first byte next segment */ | ||
267 | zft_pos.seg_byte_pos = this_segs_size; | ||
268 | } else { /* after data previous segment, data_remaining < 0 */ | ||
269 | zft_pos.seg_byte_pos = data_remaining + result; | ||
270 | } | ||
271 | } else { | ||
272 | TRACE(ft_t_noise, "zft_deblock_buf empty"); | ||
273 | zft_pos.seg_pos --; | ||
274 | zft_pos.seg_byte_pos = zft_get_seg_sz (zft_pos.seg_pos); | ||
275 | ftape_start_writing(FT_WR_MULTI); | ||
276 | } | ||
277 | TRACE(ft_t_any, "waiting"); | ||
278 | if ((result = ftape_loop_until_writes_done()) < 0) { | ||
279 | /* that's really bad. What to to with zft_tape_pos? | ||
280 | */ | ||
281 | TRACE(ft_t_err, "flush buffers failed"); | ||
282 | } | ||
283 | TRACE(ft_t_any, "zft_seg_pos: %d, zft_seg_byte_pos: %d", | ||
284 | zft_pos.seg_pos, zft_pos.seg_byte_pos); | ||
285 | last_write_failed = | ||
286 | need_flush = 0; | ||
287 | TRACE_EXIT result; | ||
288 | } | ||
289 | |||
290 | /* return-value: the number of bytes removed from the user-buffer | ||
291 | * | ||
292 | * out: | ||
293 | * int *write_cnt: how much actually has been moved to the | ||
294 | * zft_deblock_buf | ||
295 | * int req_len : MUST NOT BE CHANGED, except at EOT, in | ||
296 | * which case it may be adjusted | ||
297 | * in : | ||
298 | * char *buff : the user buffer | ||
299 | * int buf_pos_write : copy of buf_len_wr int | ||
300 | * this_segs_size : the size in bytes of the actual segment | ||
301 | * char | ||
302 | * *zft_deblock_buf : zft_deblock_buf | ||
303 | */ | ||
304 | static int zft_simple_write(int *cnt, | ||
305 | __u8 *dst_buf, const int seg_sz, | ||
306 | const __u8 __user *src_buf, const int req_len, | ||
307 | const zft_position *pos,const zft_volinfo *volume) | ||
308 | { | ||
309 | int space_left; | ||
310 | TRACE_FUN(ft_t_flow); | ||
311 | |||
312 | /* volume->size holds the tape capacity while volume is open */ | ||
313 | if (pos->tape_pos + volume->blk_sz > volume->size) { | ||
314 | TRACE_EXIT -ENOSPC; | ||
315 | } | ||
316 | /* remaining space in this segment, NOT zft_deblock_buf | ||
317 | */ | ||
318 | space_left = seg_sz - pos->seg_byte_pos; | ||
319 | *cnt = req_len < space_left ? req_len : space_left; | ||
320 | if (copy_from_user(dst_buf + pos->seg_byte_pos, src_buf, *cnt) != 0) { | ||
321 | TRACE_EXIT -EFAULT; | ||
322 | } | ||
323 | TRACE_EXIT *cnt; | ||
324 | } | ||
325 | |||
326 | static int check_write_access(int req_len, | ||
327 | const zft_volinfo **volume, | ||
328 | zft_position *pos, | ||
329 | const unsigned int blk_sz) | ||
330 | { | ||
331 | int result; | ||
332 | TRACE_FUN(ft_t_flow); | ||
333 | |||
334 | if ((req_len % zft_blk_sz) != 0) { | ||
335 | TRACE_ABORT(-EINVAL, ft_t_info, | ||
336 | "write-count %d must be multiple of block-size %d", | ||
337 | req_len, blk_sz); | ||
338 | } | ||
339 | if (zft_io_state == zft_writing) { | ||
340 | /* all other error conditions have been checked earlier | ||
341 | */ | ||
342 | TRACE_EXIT 0; | ||
343 | } | ||
344 | zft_io_state = zft_idle; | ||
345 | TRACE_CATCH(zft_check_write_access(pos),); | ||
346 | /* If we haven't read the header segment yet, do it now. | ||
347 | * This will verify the configuration, get the bad sector | ||
348 | * table and read the volume table segment | ||
349 | */ | ||
350 | if (!zft_header_read) { | ||
351 | TRACE_CATCH(zft_read_header_segments(),); | ||
352 | } | ||
353 | /* fine. Now the tape is either at BOT or at EOD, | ||
354 | * Write start of volume now | ||
355 | */ | ||
356 | TRACE_CATCH(zft_open_volume(pos, blk_sz, zft_use_compression),); | ||
357 | *volume = zft_find_volume(pos->seg_pos); | ||
358 | DUMP_VOLINFO(ft_t_noise, "", *volume); | ||
359 | zft_just_before_eof = 0; | ||
360 | /* now merge with old data if necessary */ | ||
361 | if (!zft_qic_mode && pos->seg_byte_pos != 0){ | ||
362 | result = zft_fetch_segment(pos->seg_pos, | ||
363 | zft_deblock_buf, | ||
364 | FT_RD_SINGLE); | ||
365 | if (result < 0) { | ||
366 | if (result == -EINTR || result == -ENOSPC) { | ||
367 | TRACE_EXIT result; | ||
368 | } | ||
369 | TRACE(ft_t_noise, | ||
370 | "ftape_read_segment() result: %d. " | ||
371 | "This might be normal when using " | ||
372 | "a newly\nformatted tape", result); | ||
373 | memset(zft_deblock_buf, '\0', pos->seg_byte_pos); | ||
374 | } | ||
375 | } | ||
376 | zft_io_state = zft_writing; | ||
377 | TRACE_EXIT 0; | ||
378 | } | ||
379 | |||
380 | static int fill_deblock_buf(__u8 *dst_buf, const int seg_sz, | ||
381 | zft_position *pos, const zft_volinfo *volume, | ||
382 | const char __user *usr_buf, const int req_len) | ||
383 | { | ||
384 | int cnt = 0; | ||
385 | int result = 0; | ||
386 | TRACE_FUN(ft_t_flow); | ||
387 | |||
388 | if (seg_sz == 0) { | ||
389 | TRACE_ABORT(0, ft_t_data_flow, "empty segment"); | ||
390 | } | ||
391 | TRACE(ft_t_data_flow, "\n" | ||
392 | KERN_INFO "remaining req_len: %d\n" | ||
393 | KERN_INFO " buf_pos: %d", | ||
394 | req_len, pos->seg_byte_pos); | ||
395 | /* zft_deblock_buf will not contain a valid segment any longer */ | ||
396 | zft_deblock_segment = -1; | ||
397 | if (zft_use_compression) { | ||
398 | TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),); | ||
399 | TRACE_CATCH(result= (*zft_cmpr_ops->write)(&cnt, | ||
400 | dst_buf, seg_sz, | ||
401 | usr_buf, req_len, | ||
402 | pos, volume),); | ||
403 | } else { | ||
404 | TRACE_CATCH(result= zft_simple_write(&cnt, | ||
405 | dst_buf, seg_sz, | ||
406 | usr_buf, req_len, | ||
407 | pos, volume),); | ||
408 | } | ||
409 | pos->volume_pos += result; | ||
410 | pos->seg_byte_pos += cnt; | ||
411 | pos->tape_pos += cnt; | ||
412 | TRACE(ft_t_data_flow, "\n" | ||
413 | KERN_INFO "removed from user-buffer : %d bytes.\n" | ||
414 | KERN_INFO "copied to zft_deblock_buf: %d bytes.\n" | ||
415 | KERN_INFO "zft_tape_pos : " LL_X " bytes.", | ||
416 | result, cnt, LL(pos->tape_pos)); | ||
417 | TRACE_EXIT result; | ||
418 | } | ||
419 | |||
420 | |||
421 | /* called by the kernel-interface routine "zft_write()" | ||
422 | */ | ||
423 | int _zft_write(const char __user *buff, int req_len) | ||
424 | { | ||
425 | int result = 0; | ||
426 | int written = 0; | ||
427 | int write_cnt; | ||
428 | int seg_sz; | ||
429 | static const zft_volinfo *volume = NULL; | ||
430 | TRACE_FUN(ft_t_flow); | ||
431 | |||
432 | zft_resid = req_len; | ||
433 | last_write_failed = 1; /* reset to 0 when successful */ | ||
434 | /* check if write is allowed | ||
435 | */ | ||
436 | TRACE_CATCH(check_write_access(req_len, &volume,&zft_pos,zft_blk_sz),); | ||
437 | while (req_len > 0) { | ||
438 | /* Allow us to escape from this loop with a signal ! | ||
439 | */ | ||
440 | FT_SIGNAL_EXIT(_DONT_BLOCK); | ||
441 | seg_sz = zft_get_seg_sz(zft_pos.seg_pos); | ||
442 | if ((write_cnt = fill_deblock_buf(zft_deblock_buf, | ||
443 | seg_sz, | ||
444 | &zft_pos, | ||
445 | volume, | ||
446 | buff, | ||
447 | req_len)) < 0) { | ||
448 | zft_resid -= written; | ||
449 | if (write_cnt == -ENOSPC) { | ||
450 | /* leave the remainder to flush_buffers() | ||
451 | */ | ||
452 | TRACE(ft_t_info, "No space left on device"); | ||
453 | last_write_failed = 0; | ||
454 | if (!need_flush) { | ||
455 | need_flush = written > 0; | ||
456 | } | ||
457 | TRACE_EXIT written > 0 ? written : -ENOSPC; | ||
458 | } else { | ||
459 | TRACE_EXIT result; | ||
460 | } | ||
461 | } | ||
462 | if (zft_pos.seg_byte_pos == seg_sz) { | ||
463 | TRACE_CATCH(ftape_write_segment(zft_pos.seg_pos, | ||
464 | zft_deblock_buf, | ||
465 | FT_WR_ASYNC), | ||
466 | zft_resid -= written); | ||
467 | zft_written_segments ++; | ||
468 | zft_pos.seg_byte_pos = 0; | ||
469 | zft_deblock_segment = zft_pos.seg_pos; | ||
470 | ++zft_pos.seg_pos; | ||
471 | } | ||
472 | written += write_cnt; | ||
473 | buff += write_cnt; | ||
474 | req_len -= write_cnt; | ||
475 | } /* while (req_len > 0) */ | ||
476 | TRACE(ft_t_data_flow, "remaining in blocking buffer: %d", | ||
477 | zft_pos.seg_byte_pos); | ||
478 | TRACE(ft_t_data_flow, "just written bytes: %d", written); | ||
479 | last_write_failed = 0; | ||
480 | zft_resid -= written; | ||
481 | need_flush = need_flush || written > 0; | ||
482 | TRACE_EXIT written; /* bytes written */ | ||
483 | } | ||
diff --git a/drivers/char/ftape/zftape/zftape-write.h b/drivers/char/ftape/zftape/zftape-write.h deleted file mode 100644 index ea887015b493..000000000000 --- a/drivers/char/ftape/zftape/zftape-write.h +++ /dev/null | |||
@@ -1,38 +0,0 @@ | |||
1 | #ifndef _ZFTAPE_WRITE_H | ||
2 | #define _ZFTAPE_WRITE_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 1996, 1997 Claus-Justus Heine | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | * | ||
22 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-write.h,v $ | ||
23 | * $Revision: 1.2 $ | ||
24 | * $Date: 1997/10/05 19:19:13 $ | ||
25 | * | ||
26 | * This file contains the definitions for the write functions | ||
27 | * for the zftape driver for Linux. | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | extern int zft_flush_buffers(void); | ||
32 | extern int zft_update_header_segments(void); | ||
33 | extern void zft_prevent_flush(void); | ||
34 | |||
35 | /* hook for the VFS interface | ||
36 | */ | ||
37 | extern int _zft_write(const char __user *buff, int req_len); | ||
38 | #endif /* _ZFTAPE_WRITE_H */ | ||
diff --git a/drivers/char/ftape/zftape/zftape_syms.c b/drivers/char/ftape/zftape/zftape_syms.c deleted file mode 100644 index 2db1401682df..000000000000 --- a/drivers/char/ftape/zftape/zftape_syms.c +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1997 Claus-Justus Heine | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; see the file COPYING. If not, write to | ||
16 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | |||
18 | * | ||
19 | * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape_syms.c,v $ | ||
20 | * $Revision: 1.3 $ | ||
21 | * $Date: 1997/10/05 19:19:14 $ | ||
22 | * | ||
23 | * This file contains the symbols that the zftape frontend to | ||
24 | * the ftape floppy tape driver exports | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | |||
29 | #include <linux/zftape.h> | ||
30 | |||
31 | #include "../zftape/zftape-init.h" | ||
32 | #include "../zftape/zftape-read.h" | ||
33 | #include "../zftape/zftape-buffers.h" | ||
34 | #include "../zftape/zftape-ctl.h" | ||
35 | |||
36 | /* zftape-init.c */ | ||
37 | EXPORT_SYMBOL(zft_cmpr_register); | ||
38 | /* zftape-read.c */ | ||
39 | EXPORT_SYMBOL(zft_fetch_segment_fraction); | ||
40 | /* zftape-buffers.c */ | ||
41 | EXPORT_SYMBOL(zft_vmalloc_once); | ||
42 | EXPORT_SYMBOL(zft_vmalloc_always); | ||
43 | EXPORT_SYMBOL(zft_vfree); | ||
diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c index 817dc409ac20..23b25ada65ea 100644 --- a/drivers/char/genrtc.c +++ b/drivers/char/genrtc.c | |||
@@ -102,7 +102,7 @@ static void gen_rtc_interrupt(unsigned long arg); | |||
102 | * Routine to poll RTC seconds field for change as often as possible, | 102 | * Routine to poll RTC seconds field for change as often as possible, |
103 | * after first RTC_UIE use timer to reduce polling | 103 | * after first RTC_UIE use timer to reduce polling |
104 | */ | 104 | */ |
105 | static void genrtc_troutine(void *data) | 105 | static void genrtc_troutine(struct work_struct *work) |
106 | { | 106 | { |
107 | unsigned int tmp = get_rtc_ss(); | 107 | unsigned int tmp = get_rtc_ss(); |
108 | 108 | ||
@@ -255,7 +255,7 @@ static inline int gen_set_rtc_irq_bit(unsigned char bit) | |||
255 | irq_active = 1; | 255 | irq_active = 1; |
256 | stop_rtc_timers = 0; | 256 | stop_rtc_timers = 0; |
257 | lostint = 0; | 257 | lostint = 0; |
258 | INIT_WORK(&genrtc_task, genrtc_troutine, NULL); | 258 | INIT_WORK(&genrtc_task, genrtc_troutine); |
259 | oldsecs = get_rtc_ss(); | 259 | oldsecs = get_rtc_ss(); |
260 | init_timer(&timer_task); | 260 | init_timer(&timer_task); |
261 | 261 | ||
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 091a11cd878c..20dc3be5ecfc 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/fcntl.h> | 21 | #include <linux/fcntl.h> |
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/poll.h> | 23 | #include <linux/poll.h> |
24 | #include <linux/mm.h> | ||
24 | #include <linux/proc_fs.h> | 25 | #include <linux/proc_fs.h> |
25 | #include <linux/spinlock.h> | 26 | #include <linux/spinlock.h> |
26 | #include <linux/sysctl.h> | 27 | #include <linux/sysctl.h> |
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 9902ffad3b12..cc2cd46bedc6 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/sched.h> | 38 | #include <linux/sched.h> |
39 | #include <linux/spinlock.h> | 39 | #include <linux/spinlock.h> |
40 | #include <linux/delay.h> | 40 | #include <linux/delay.h> |
41 | #include <linux/freezer.h> | ||
41 | 42 | ||
42 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
43 | 44 | ||
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 8728255c9463..d090622f1dea 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c | |||
@@ -337,11 +337,6 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp); | |||
337 | static void hvcs_close(struct tty_struct *tty, struct file *filp); | 337 | static void hvcs_close(struct tty_struct *tty, struct file *filp); |
338 | static void hvcs_hangup(struct tty_struct * tty); | 338 | static void hvcs_hangup(struct tty_struct * tty); |
339 | 339 | ||
340 | static void hvcs_create_device_attrs(struct hvcs_struct *hvcsd); | ||
341 | static void hvcs_remove_device_attrs(struct vio_dev *vdev); | ||
342 | static void hvcs_create_driver_attrs(void); | ||
343 | static void hvcs_remove_driver_attrs(void); | ||
344 | |||
345 | static int __devinit hvcs_probe(struct vio_dev *dev, | 340 | static int __devinit hvcs_probe(struct vio_dev *dev, |
346 | const struct vio_device_id *id); | 341 | const struct vio_device_id *id); |
347 | static int __devexit hvcs_remove(struct vio_dev *dev); | 342 | static int __devexit hvcs_remove(struct vio_dev *dev); |
@@ -353,6 +348,172 @@ static void __exit hvcs_module_exit(void); | |||
353 | #define HVCS_TRY_WRITE 0x00000004 | 348 | #define HVCS_TRY_WRITE 0x00000004 |
354 | #define HVCS_READ_MASK (HVCS_SCHED_READ | HVCS_QUICK_READ) | 349 | #define HVCS_READ_MASK (HVCS_SCHED_READ | HVCS_QUICK_READ) |
355 | 350 | ||
351 | static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod) | ||
352 | { | ||
353 | return viod->dev.driver_data; | ||
354 | } | ||
355 | /* The sysfs interface for the driver and devices */ | ||
356 | |||
357 | static ssize_t hvcs_partner_vtys_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
358 | { | ||
359 | struct vio_dev *viod = to_vio_dev(dev); | ||
360 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
361 | unsigned long flags; | ||
362 | int retval; | ||
363 | |||
364 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
365 | retval = sprintf(buf, "%X\n", hvcsd->p_unit_address); | ||
366 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
367 | return retval; | ||
368 | } | ||
369 | static DEVICE_ATTR(partner_vtys, S_IRUGO, hvcs_partner_vtys_show, NULL); | ||
370 | |||
371 | static ssize_t hvcs_partner_clcs_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
372 | { | ||
373 | struct vio_dev *viod = to_vio_dev(dev); | ||
374 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
375 | unsigned long flags; | ||
376 | int retval; | ||
377 | |||
378 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
379 | retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]); | ||
380 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
381 | return retval; | ||
382 | } | ||
383 | static DEVICE_ATTR(partner_clcs, S_IRUGO, hvcs_partner_clcs_show, NULL); | ||
384 | |||
385 | static ssize_t hvcs_current_vty_store(struct device *dev, struct device_attribute *attr, const char * buf, | ||
386 | size_t count) | ||
387 | { | ||
388 | /* | ||
389 | * Don't need this feature at the present time because firmware doesn't | ||
390 | * yet support multiple partners. | ||
391 | */ | ||
392 | printk(KERN_INFO "HVCS: Denied current_vty change: -EPERM.\n"); | ||
393 | return -EPERM; | ||
394 | } | ||
395 | |||
396 | static ssize_t hvcs_current_vty_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
397 | { | ||
398 | struct vio_dev *viod = to_vio_dev(dev); | ||
399 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
400 | unsigned long flags; | ||
401 | int retval; | ||
402 | |||
403 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
404 | retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]); | ||
405 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
406 | return retval; | ||
407 | } | ||
408 | |||
409 | static DEVICE_ATTR(current_vty, | ||
410 | S_IRUGO | S_IWUSR, hvcs_current_vty_show, hvcs_current_vty_store); | ||
411 | |||
412 | static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribute *attr, const char *buf, | ||
413 | size_t count) | ||
414 | { | ||
415 | struct vio_dev *viod = to_vio_dev(dev); | ||
416 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
417 | unsigned long flags; | ||
418 | |||
419 | /* writing a '0' to this sysfs entry will result in the disconnect. */ | ||
420 | if (simple_strtol(buf, NULL, 0) != 0) | ||
421 | return -EINVAL; | ||
422 | |||
423 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
424 | |||
425 | if (hvcsd->open_count > 0) { | ||
426 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
427 | printk(KERN_INFO "HVCS: vterm state unchanged. " | ||
428 | "The hvcs device node is still in use.\n"); | ||
429 | return -EPERM; | ||
430 | } | ||
431 | |||
432 | if (hvcsd->connected == 0) { | ||
433 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
434 | printk(KERN_INFO "HVCS: vterm state unchanged. The" | ||
435 | " vty-server is not connected to a vty.\n"); | ||
436 | return -EPERM; | ||
437 | } | ||
438 | |||
439 | hvcs_partner_free(hvcsd); | ||
440 | printk(KERN_INFO "HVCS: Closed vty-server@%X and" | ||
441 | " partner vty@%X:%d connection.\n", | ||
442 | hvcsd->vdev->unit_address, | ||
443 | hvcsd->p_unit_address, | ||
444 | (uint32_t)hvcsd->p_partition_ID); | ||
445 | |||
446 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
447 | return count; | ||
448 | } | ||
449 | |||
450 | static ssize_t hvcs_vterm_state_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
451 | { | ||
452 | struct vio_dev *viod = to_vio_dev(dev); | ||
453 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
454 | unsigned long flags; | ||
455 | int retval; | ||
456 | |||
457 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
458 | retval = sprintf(buf, "%d\n", hvcsd->connected); | ||
459 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
460 | return retval; | ||
461 | } | ||
462 | static DEVICE_ATTR(vterm_state, S_IRUGO | S_IWUSR, | ||
463 | hvcs_vterm_state_show, hvcs_vterm_state_store); | ||
464 | |||
465 | static ssize_t hvcs_index_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
466 | { | ||
467 | struct vio_dev *viod = to_vio_dev(dev); | ||
468 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
469 | unsigned long flags; | ||
470 | int retval; | ||
471 | |||
472 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
473 | retval = sprintf(buf, "%d\n", hvcsd->index); | ||
474 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
475 | return retval; | ||
476 | } | ||
477 | |||
478 | static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL); | ||
479 | |||
480 | static struct attribute *hvcs_attrs[] = { | ||
481 | &dev_attr_partner_vtys.attr, | ||
482 | &dev_attr_partner_clcs.attr, | ||
483 | &dev_attr_current_vty.attr, | ||
484 | &dev_attr_vterm_state.attr, | ||
485 | &dev_attr_index.attr, | ||
486 | NULL, | ||
487 | }; | ||
488 | |||
489 | static struct attribute_group hvcs_attr_group = { | ||
490 | .attrs = hvcs_attrs, | ||
491 | }; | ||
492 | |||
493 | static ssize_t hvcs_rescan_show(struct device_driver *ddp, char *buf) | ||
494 | { | ||
495 | /* A 1 means it is updating, a 0 means it is done updating */ | ||
496 | return snprintf(buf, PAGE_SIZE, "%d\n", hvcs_rescan_status); | ||
497 | } | ||
498 | |||
499 | static ssize_t hvcs_rescan_store(struct device_driver *ddp, const char * buf, | ||
500 | size_t count) | ||
501 | { | ||
502 | if ((simple_strtol(buf, NULL, 0) != 1) | ||
503 | && (hvcs_rescan_status != 0)) | ||
504 | return -EINVAL; | ||
505 | |||
506 | hvcs_rescan_status = 1; | ||
507 | printk(KERN_INFO "HVCS: rescanning partner info for all" | ||
508 | " vty-servers.\n"); | ||
509 | hvcs_rescan_devices_list(); | ||
510 | hvcs_rescan_status = 0; | ||
511 | return count; | ||
512 | } | ||
513 | |||
514 | static DRIVER_ATTR(rescan, | ||
515 | S_IRUGO | S_IWUSR, hvcs_rescan_show, hvcs_rescan_store); | ||
516 | |||
356 | static void hvcs_kick(void) | 517 | static void hvcs_kick(void) |
357 | { | 518 | { |
358 | hvcs_kicked = 1; | 519 | hvcs_kicked = 1; |
@@ -575,7 +736,7 @@ static void destroy_hvcs_struct(struct kobject *kobj) | |||
575 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 736 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
576 | spin_unlock(&hvcs_structs_lock); | 737 | spin_unlock(&hvcs_structs_lock); |
577 | 738 | ||
578 | hvcs_remove_device_attrs(vdev); | 739 | sysfs_remove_group(&vdev->dev.kobj, &hvcs_attr_group); |
579 | 740 | ||
580 | kfree(hvcsd); | 741 | kfree(hvcsd); |
581 | } | 742 | } |
@@ -608,6 +769,7 @@ static int __devinit hvcs_probe( | |||
608 | { | 769 | { |
609 | struct hvcs_struct *hvcsd; | 770 | struct hvcs_struct *hvcsd; |
610 | int index; | 771 | int index; |
772 | int retval; | ||
611 | 773 | ||
612 | if (!dev || !id) { | 774 | if (!dev || !id) { |
613 | printk(KERN_ERR "HVCS: probed with invalid parameter.\n"); | 775 | printk(KERN_ERR "HVCS: probed with invalid parameter.\n"); |
@@ -658,14 +820,16 @@ static int __devinit hvcs_probe( | |||
658 | * the hvcs_struct has been added to the devices list then the user app | 820 | * the hvcs_struct has been added to the devices list then the user app |
659 | * will get -ENODEV. | 821 | * will get -ENODEV. |
660 | */ | 822 | */ |
661 | |||
662 | spin_lock(&hvcs_structs_lock); | 823 | spin_lock(&hvcs_structs_lock); |
663 | |||
664 | list_add_tail(&(hvcsd->next), &hvcs_structs); | 824 | list_add_tail(&(hvcsd->next), &hvcs_structs); |
665 | |||
666 | spin_unlock(&hvcs_structs_lock); | 825 | spin_unlock(&hvcs_structs_lock); |
667 | 826 | ||
668 | hvcs_create_device_attrs(hvcsd); | 827 | retval = sysfs_create_group(&dev->dev.kobj, &hvcs_attr_group); |
828 | if (retval) { | ||
829 | printk(KERN_ERR "HVCS: Can't create sysfs attrs for vty-server@%X\n", | ||
830 | hvcsd->vdev->unit_address); | ||
831 | return retval; | ||
832 | } | ||
669 | 833 | ||
670 | printk(KERN_INFO "HVCS: vty-server@%X added to the vio bus.\n", dev->unit_address); | 834 | printk(KERN_INFO "HVCS: vty-server@%X added to the vio bus.\n", dev->unit_address); |
671 | 835 | ||
@@ -1354,8 +1518,10 @@ static int __init hvcs_module_init(void) | |||
1354 | if (!hvcs_tty_driver) | 1518 | if (!hvcs_tty_driver) |
1355 | return -ENOMEM; | 1519 | return -ENOMEM; |
1356 | 1520 | ||
1357 | if (hvcs_alloc_index_list(num_ttys_to_alloc)) | 1521 | if (hvcs_alloc_index_list(num_ttys_to_alloc)) { |
1358 | return -ENOMEM; | 1522 | rc = -ENOMEM; |
1523 | goto index_fail; | ||
1524 | } | ||
1359 | 1525 | ||
1360 | hvcs_tty_driver->owner = THIS_MODULE; | 1526 | hvcs_tty_driver->owner = THIS_MODULE; |
1361 | 1527 | ||
@@ -1385,41 +1551,57 @@ static int __init hvcs_module_init(void) | |||
1385 | * dynamically assigned major and minor numbers for our devices. | 1551 | * dynamically assigned major and minor numbers for our devices. |
1386 | */ | 1552 | */ |
1387 | if (tty_register_driver(hvcs_tty_driver)) { | 1553 | if (tty_register_driver(hvcs_tty_driver)) { |
1388 | printk(KERN_ERR "HVCS: registration " | 1554 | printk(KERN_ERR "HVCS: registration as a tty driver failed.\n"); |
1389 | " as a tty driver failed.\n"); | 1555 | rc = -EIO; |
1390 | hvcs_free_index_list(); | 1556 | goto register_fail; |
1391 | put_tty_driver(hvcs_tty_driver); | ||
1392 | return -EIO; | ||
1393 | } | 1557 | } |
1394 | 1558 | ||
1395 | hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL); | 1559 | hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL); |
1396 | if (!hvcs_pi_buff) { | 1560 | if (!hvcs_pi_buff) { |
1397 | tty_unregister_driver(hvcs_tty_driver); | 1561 | rc = -ENOMEM; |
1398 | hvcs_free_index_list(); | 1562 | goto buff_alloc_fail; |
1399 | put_tty_driver(hvcs_tty_driver); | ||
1400 | return -ENOMEM; | ||
1401 | } | 1563 | } |
1402 | 1564 | ||
1403 | hvcs_task = kthread_run(khvcsd, NULL, "khvcsd"); | 1565 | hvcs_task = kthread_run(khvcsd, NULL, "khvcsd"); |
1404 | if (IS_ERR(hvcs_task)) { | 1566 | if (IS_ERR(hvcs_task)) { |
1405 | printk(KERN_ERR "HVCS: khvcsd creation failed. Driver not loaded.\n"); | 1567 | printk(KERN_ERR "HVCS: khvcsd creation failed. Driver not loaded.\n"); |
1406 | kfree(hvcs_pi_buff); | 1568 | rc = -EIO; |
1407 | tty_unregister_driver(hvcs_tty_driver); | 1569 | goto kthread_fail; |
1408 | hvcs_free_index_list(); | ||
1409 | put_tty_driver(hvcs_tty_driver); | ||
1410 | return -EIO; | ||
1411 | } | 1570 | } |
1412 | 1571 | ||
1413 | rc = vio_register_driver(&hvcs_vio_driver); | 1572 | rc = vio_register_driver(&hvcs_vio_driver); |
1573 | if (rc) { | ||
1574 | printk(KERN_ERR "HVCS: can't register vio driver\n"); | ||
1575 | goto vio_fail; | ||
1576 | } | ||
1414 | 1577 | ||
1415 | /* | 1578 | /* |
1416 | * This needs to be done AFTER the vio_register_driver() call or else | 1579 | * This needs to be done AFTER the vio_register_driver() call or else |
1417 | * the kobjects won't be initialized properly. | 1580 | * the kobjects won't be initialized properly. |
1418 | */ | 1581 | */ |
1419 | hvcs_create_driver_attrs(); | 1582 | rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan); |
1583 | if (rc) { | ||
1584 | printk(KERN_ERR "HVCS: sysfs attr create failed\n"); | ||
1585 | goto attr_fail; | ||
1586 | } | ||
1420 | 1587 | ||
1421 | printk(KERN_INFO "HVCS: driver module inserted.\n"); | 1588 | printk(KERN_INFO "HVCS: driver module inserted.\n"); |
1422 | 1589 | ||
1590 | return 0; | ||
1591 | |||
1592 | attr_fail: | ||
1593 | vio_unregister_driver(&hvcs_vio_driver); | ||
1594 | vio_fail: | ||
1595 | kthread_stop(hvcs_task); | ||
1596 | kthread_fail: | ||
1597 | kfree(hvcs_pi_buff); | ||
1598 | buff_alloc_fail: | ||
1599 | tty_unregister_driver(hvcs_tty_driver); | ||
1600 | register_fail: | ||
1601 | hvcs_free_index_list(); | ||
1602 | index_fail: | ||
1603 | put_tty_driver(hvcs_tty_driver); | ||
1604 | hvcs_tty_driver = NULL; | ||
1423 | return rc; | 1605 | return rc; |
1424 | } | 1606 | } |
1425 | 1607 | ||
@@ -1441,7 +1623,7 @@ static void __exit hvcs_module_exit(void) | |||
1441 | hvcs_pi_buff = NULL; | 1623 | hvcs_pi_buff = NULL; |
1442 | spin_unlock(&hvcs_pi_lock); | 1624 | spin_unlock(&hvcs_pi_lock); |
1443 | 1625 | ||
1444 | hvcs_remove_driver_attrs(); | 1626 | driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan); |
1445 | 1627 | ||
1446 | vio_unregister_driver(&hvcs_vio_driver); | 1628 | vio_unregister_driver(&hvcs_vio_driver); |
1447 | 1629 | ||
@@ -1456,191 +1638,3 @@ static void __exit hvcs_module_exit(void) | |||
1456 | 1638 | ||
1457 | module_init(hvcs_module_init); | 1639 | module_init(hvcs_module_init); |
1458 | module_exit(hvcs_module_exit); | 1640 | module_exit(hvcs_module_exit); |
1459 | |||
1460 | static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod) | ||
1461 | { | ||
1462 | return viod->dev.driver_data; | ||
1463 | } | ||
1464 | /* The sysfs interface for the driver and devices */ | ||
1465 | |||
1466 | static ssize_t hvcs_partner_vtys_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
1467 | { | ||
1468 | struct vio_dev *viod = to_vio_dev(dev); | ||
1469 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
1470 | unsigned long flags; | ||
1471 | int retval; | ||
1472 | |||
1473 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
1474 | retval = sprintf(buf, "%X\n", hvcsd->p_unit_address); | ||
1475 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1476 | return retval; | ||
1477 | } | ||
1478 | static DEVICE_ATTR(partner_vtys, S_IRUGO, hvcs_partner_vtys_show, NULL); | ||
1479 | |||
1480 | static ssize_t hvcs_partner_clcs_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
1481 | { | ||
1482 | struct vio_dev *viod = to_vio_dev(dev); | ||
1483 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
1484 | unsigned long flags; | ||
1485 | int retval; | ||
1486 | |||
1487 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
1488 | retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]); | ||
1489 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1490 | return retval; | ||
1491 | } | ||
1492 | static DEVICE_ATTR(partner_clcs, S_IRUGO, hvcs_partner_clcs_show, NULL); | ||
1493 | |||
1494 | static ssize_t hvcs_current_vty_store(struct device *dev, struct device_attribute *attr, const char * buf, | ||
1495 | size_t count) | ||
1496 | { | ||
1497 | /* | ||
1498 | * Don't need this feature at the present time because firmware doesn't | ||
1499 | * yet support multiple partners. | ||
1500 | */ | ||
1501 | printk(KERN_INFO "HVCS: Denied current_vty change: -EPERM.\n"); | ||
1502 | return -EPERM; | ||
1503 | } | ||
1504 | |||
1505 | static ssize_t hvcs_current_vty_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
1506 | { | ||
1507 | struct vio_dev *viod = to_vio_dev(dev); | ||
1508 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
1509 | unsigned long flags; | ||
1510 | int retval; | ||
1511 | |||
1512 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
1513 | retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]); | ||
1514 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1515 | return retval; | ||
1516 | } | ||
1517 | |||
1518 | static DEVICE_ATTR(current_vty, | ||
1519 | S_IRUGO | S_IWUSR, hvcs_current_vty_show, hvcs_current_vty_store); | ||
1520 | |||
1521 | static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribute *attr, const char *buf, | ||
1522 | size_t count) | ||
1523 | { | ||
1524 | struct vio_dev *viod = to_vio_dev(dev); | ||
1525 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
1526 | unsigned long flags; | ||
1527 | |||
1528 | /* writing a '0' to this sysfs entry will result in the disconnect. */ | ||
1529 | if (simple_strtol(buf, NULL, 0) != 0) | ||
1530 | return -EINVAL; | ||
1531 | |||
1532 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
1533 | |||
1534 | if (hvcsd->open_count > 0) { | ||
1535 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1536 | printk(KERN_INFO "HVCS: vterm state unchanged. " | ||
1537 | "The hvcs device node is still in use.\n"); | ||
1538 | return -EPERM; | ||
1539 | } | ||
1540 | |||
1541 | if (hvcsd->connected == 0) { | ||
1542 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1543 | printk(KERN_INFO "HVCS: vterm state unchanged. The" | ||
1544 | " vty-server is not connected to a vty.\n"); | ||
1545 | return -EPERM; | ||
1546 | } | ||
1547 | |||
1548 | hvcs_partner_free(hvcsd); | ||
1549 | printk(KERN_INFO "HVCS: Closed vty-server@%X and" | ||
1550 | " partner vty@%X:%d connection.\n", | ||
1551 | hvcsd->vdev->unit_address, | ||
1552 | hvcsd->p_unit_address, | ||
1553 | (uint32_t)hvcsd->p_partition_ID); | ||
1554 | |||
1555 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1556 | return count; | ||
1557 | } | ||
1558 | |||
1559 | static ssize_t hvcs_vterm_state_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
1560 | { | ||
1561 | struct vio_dev *viod = to_vio_dev(dev); | ||
1562 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
1563 | unsigned long flags; | ||
1564 | int retval; | ||
1565 | |||
1566 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
1567 | retval = sprintf(buf, "%d\n", hvcsd->connected); | ||
1568 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1569 | return retval; | ||
1570 | } | ||
1571 | static DEVICE_ATTR(vterm_state, S_IRUGO | S_IWUSR, | ||
1572 | hvcs_vterm_state_show, hvcs_vterm_state_store); | ||
1573 | |||
1574 | static ssize_t hvcs_index_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
1575 | { | ||
1576 | struct vio_dev *viod = to_vio_dev(dev); | ||
1577 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
1578 | unsigned long flags; | ||
1579 | int retval; | ||
1580 | |||
1581 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
1582 | retval = sprintf(buf, "%d\n", hvcsd->index); | ||
1583 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1584 | return retval; | ||
1585 | } | ||
1586 | |||
1587 | static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL); | ||
1588 | |||
1589 | static struct attribute *hvcs_attrs[] = { | ||
1590 | &dev_attr_partner_vtys.attr, | ||
1591 | &dev_attr_partner_clcs.attr, | ||
1592 | &dev_attr_current_vty.attr, | ||
1593 | &dev_attr_vterm_state.attr, | ||
1594 | &dev_attr_index.attr, | ||
1595 | NULL, | ||
1596 | }; | ||
1597 | |||
1598 | static struct attribute_group hvcs_attr_group = { | ||
1599 | .attrs = hvcs_attrs, | ||
1600 | }; | ||
1601 | |||
1602 | static void hvcs_create_device_attrs(struct hvcs_struct *hvcsd) | ||
1603 | { | ||
1604 | struct vio_dev *vdev = hvcsd->vdev; | ||
1605 | sysfs_create_group(&vdev->dev.kobj, &hvcs_attr_group); | ||
1606 | } | ||
1607 | |||
1608 | static void hvcs_remove_device_attrs(struct vio_dev *vdev) | ||
1609 | { | ||
1610 | sysfs_remove_group(&vdev->dev.kobj, &hvcs_attr_group); | ||
1611 | } | ||
1612 | |||
1613 | static ssize_t hvcs_rescan_show(struct device_driver *ddp, char *buf) | ||
1614 | { | ||
1615 | /* A 1 means it is updating, a 0 means it is done updating */ | ||
1616 | return snprintf(buf, PAGE_SIZE, "%d\n", hvcs_rescan_status); | ||
1617 | } | ||
1618 | |||
1619 | static ssize_t hvcs_rescan_store(struct device_driver *ddp, const char * buf, | ||
1620 | size_t count) | ||
1621 | { | ||
1622 | if ((simple_strtol(buf, NULL, 0) != 1) | ||
1623 | && (hvcs_rescan_status != 0)) | ||
1624 | return -EINVAL; | ||
1625 | |||
1626 | hvcs_rescan_status = 1; | ||
1627 | printk(KERN_INFO "HVCS: rescanning partner info for all" | ||
1628 | " vty-servers.\n"); | ||
1629 | hvcs_rescan_devices_list(); | ||
1630 | hvcs_rescan_status = 0; | ||
1631 | return count; | ||
1632 | } | ||
1633 | static DRIVER_ATTR(rescan, | ||
1634 | S_IRUGO | S_IWUSR, hvcs_rescan_show, hvcs_rescan_store); | ||
1635 | |||
1636 | static void hvcs_create_driver_attrs(void) | ||
1637 | { | ||
1638 | struct device_driver *driverfs = &(hvcs_vio_driver.driver); | ||
1639 | driver_create_file(driverfs, &driver_attr_rescan); | ||
1640 | } | ||
1641 | |||
1642 | static void hvcs_remove_driver_attrs(void) | ||
1643 | { | ||
1644 | struct device_driver *driverfs = &(hvcs_vio_driver.driver); | ||
1645 | driver_remove_file(driverfs, &driver_attr_rescan); | ||
1646 | } | ||
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index 2cf63e7305a3..82a41d5b4ed0 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c | |||
@@ -69,7 +69,7 @@ | |||
69 | #define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) | 69 | #define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) |
70 | 70 | ||
71 | struct hvsi_struct { | 71 | struct hvsi_struct { |
72 | struct work_struct writer; | 72 | struct delayed_work writer; |
73 | struct work_struct handshaker; | 73 | struct work_struct handshaker; |
74 | wait_queue_head_t emptyq; /* woken when outbuf is emptied */ | 74 | wait_queue_head_t emptyq; /* woken when outbuf is emptied */ |
75 | wait_queue_head_t stateq; /* woken when HVSI state changes */ | 75 | wait_queue_head_t stateq; /* woken when HVSI state changes */ |
@@ -744,9 +744,10 @@ static int hvsi_handshake(struct hvsi_struct *hp) | |||
744 | return 0; | 744 | return 0; |
745 | } | 745 | } |
746 | 746 | ||
747 | static void hvsi_handshaker(void *arg) | 747 | static void hvsi_handshaker(struct work_struct *work) |
748 | { | 748 | { |
749 | struct hvsi_struct *hp = (struct hvsi_struct *)arg; | 749 | struct hvsi_struct *hp = |
750 | container_of(work, struct hvsi_struct, handshaker); | ||
750 | 751 | ||
751 | if (hvsi_handshake(hp) >= 0) | 752 | if (hvsi_handshake(hp) >= 0) |
752 | return; | 753 | return; |
@@ -951,9 +952,10 @@ static void hvsi_push(struct hvsi_struct *hp) | |||
951 | } | 952 | } |
952 | 953 | ||
953 | /* hvsi_write_worker will keep rescheduling itself until outbuf is empty */ | 954 | /* hvsi_write_worker will keep rescheduling itself until outbuf is empty */ |
954 | static void hvsi_write_worker(void *arg) | 955 | static void hvsi_write_worker(struct work_struct *work) |
955 | { | 956 | { |
956 | struct hvsi_struct *hp = (struct hvsi_struct *)arg; | 957 | struct hvsi_struct *hp = |
958 | container_of(work, struct hvsi_struct, writer.work); | ||
957 | unsigned long flags; | 959 | unsigned long flags; |
958 | #ifdef DEBUG | 960 | #ifdef DEBUG |
959 | static long start_j = 0; | 961 | static long start_j = 0; |
@@ -1287,8 +1289,8 @@ static int __init hvsi_console_init(void) | |||
1287 | } | 1289 | } |
1288 | 1290 | ||
1289 | hp = &hvsi_ports[hvsi_count]; | 1291 | hp = &hvsi_ports[hvsi_count]; |
1290 | INIT_WORK(&hp->writer, hvsi_write_worker, hp); | 1292 | INIT_DELAYED_WORK(&hp->writer, hvsi_write_worker); |
1291 | INIT_WORK(&hp->handshaker, hvsi_handshaker, hp); | 1293 | INIT_WORK(&hp->handshaker, hvsi_handshaker); |
1292 | init_waitqueue_head(&hp->emptyq); | 1294 | init_waitqueue_head(&hp->emptyq); |
1293 | init_waitqueue_head(&hp->stateq); | 1295 | init_waitqueue_head(&hp->stateq); |
1294 | spin_lock_init(&hp->lock); | 1296 | spin_lock_init(&hp->lock); |
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 9f7635f75178..5f3acd8e64b8 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig | |||
@@ -3,17 +3,20 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | config HW_RANDOM | 5 | config HW_RANDOM |
6 | bool "Hardware Random Number Generator Core support" | 6 | tristate "Hardware Random Number Generator Core support" |
7 | default y | 7 | default m |
8 | ---help--- | 8 | ---help--- |
9 | Hardware Random Number Generator Core infrastructure. | 9 | Hardware Random Number Generator Core infrastructure. |
10 | 10 | ||
11 | To compile this driver as a module, choose M here: the | ||
12 | module will be called rng-core. | ||
13 | |||
11 | If unsure, say Y. | 14 | If unsure, say Y. |
12 | 15 | ||
13 | config HW_RANDOM_INTEL | 16 | config HW_RANDOM_INTEL |
14 | tristate "Intel HW Random Number Generator support" | 17 | tristate "Intel HW Random Number Generator support" |
15 | depends on HW_RANDOM && (X86 || IA64) && PCI | 18 | depends on HW_RANDOM && (X86 || IA64) && PCI |
16 | default y | 19 | default HW_RANDOM |
17 | ---help--- | 20 | ---help--- |
18 | This driver provides kernel-side support for the Random Number | 21 | This driver provides kernel-side support for the Random Number |
19 | Generator hardware found on Intel i8xx-based motherboards. | 22 | Generator hardware found on Intel i8xx-based motherboards. |
@@ -26,7 +29,7 @@ config HW_RANDOM_INTEL | |||
26 | config HW_RANDOM_AMD | 29 | config HW_RANDOM_AMD |
27 | tristate "AMD HW Random Number Generator support" | 30 | tristate "AMD HW Random Number Generator support" |
28 | depends on HW_RANDOM && X86 && PCI | 31 | depends on HW_RANDOM && X86 && PCI |
29 | default y | 32 | default HW_RANDOM |
30 | ---help--- | 33 | ---help--- |
31 | This driver provides kernel-side support for the Random Number | 34 | This driver provides kernel-side support for the Random Number |
32 | Generator hardware found on AMD 76x-based motherboards. | 35 | Generator hardware found on AMD 76x-based motherboards. |
@@ -39,7 +42,7 @@ config HW_RANDOM_AMD | |||
39 | config HW_RANDOM_GEODE | 42 | config HW_RANDOM_GEODE |
40 | tristate "AMD Geode HW Random Number Generator support" | 43 | tristate "AMD Geode HW Random Number Generator support" |
41 | depends on HW_RANDOM && X86 && PCI | 44 | depends on HW_RANDOM && X86 && PCI |
42 | default y | 45 | default HW_RANDOM |
43 | ---help--- | 46 | ---help--- |
44 | This driver provides kernel-side support for the Random Number | 47 | This driver provides kernel-side support for the Random Number |
45 | Generator hardware found on the AMD Geode LX. | 48 | Generator hardware found on the AMD Geode LX. |
@@ -52,7 +55,7 @@ config HW_RANDOM_GEODE | |||
52 | config HW_RANDOM_VIA | 55 | config HW_RANDOM_VIA |
53 | tristate "VIA HW Random Number Generator support" | 56 | tristate "VIA HW Random Number Generator support" |
54 | depends on HW_RANDOM && X86_32 | 57 | depends on HW_RANDOM && X86_32 |
55 | default y | 58 | default HW_RANDOM |
56 | ---help--- | 59 | ---help--- |
57 | This driver provides kernel-side support for the Random Number | 60 | This driver provides kernel-side support for the Random Number |
58 | Generator hardware found on VIA based motherboards. | 61 | Generator hardware found on VIA based motherboards. |
@@ -65,7 +68,7 @@ config HW_RANDOM_VIA | |||
65 | config HW_RANDOM_IXP4XX | 68 | config HW_RANDOM_IXP4XX |
66 | tristate "Intel IXP4xx NPU HW Random Number Generator support" | 69 | tristate "Intel IXP4xx NPU HW Random Number Generator support" |
67 | depends on HW_RANDOM && ARCH_IXP4XX | 70 | depends on HW_RANDOM && ARCH_IXP4XX |
68 | default y | 71 | default HW_RANDOM |
69 | ---help--- | 72 | ---help--- |
70 | This driver provides kernel-side support for the Random | 73 | This driver provides kernel-side support for the Random |
71 | Number Generator hardware found on the Intel IXP4xx NPU. | 74 | Number Generator hardware found on the Intel IXP4xx NPU. |
@@ -78,7 +81,7 @@ config HW_RANDOM_IXP4XX | |||
78 | config HW_RANDOM_OMAP | 81 | config HW_RANDOM_OMAP |
79 | tristate "OMAP Random Number Generator support" | 82 | tristate "OMAP Random Number Generator support" |
80 | depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP24XX) | 83 | depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP24XX) |
81 | default y | 84 | default HW_RANDOM |
82 | ---help--- | 85 | ---help--- |
83 | This driver provides kernel-side support for the Random Number | 86 | This driver provides kernel-side support for the Random Number |
84 | Generator hardware found on OMAP16xx and OMAP24xx multimedia | 87 | Generator hardware found on OMAP16xx and OMAP24xx multimedia |
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index e263ae96f940..c41fa19454e3 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile | |||
@@ -2,7 +2,8 @@ | |||
2 | # Makefile for HW Random Number Generator (RNG) device drivers. | 2 | # Makefile for HW Random Number Generator (RNG) device drivers. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_HW_RANDOM) += core.o | 5 | obj-$(CONFIG_HW_RANDOM) += rng-core.o |
6 | rng-core-y := core.o | ||
6 | obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o | 7 | obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o |
7 | obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o | 8 | obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o |
8 | obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o | 9 | obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o |
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 154a81d328c1..26a860adcb38 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/module.h> | 36 | #include <linux/module.h> |
37 | #include <linux/kernel.h> | 37 | #include <linux/kernel.h> |
38 | #include <linux/fs.h> | 38 | #include <linux/fs.h> |
39 | #include <linux/sched.h> | ||
39 | #include <linux/init.h> | 40 | #include <linux/init.h> |
40 | #include <linux/miscdevice.h> | 41 | #include <linux/miscdevice.h> |
41 | #include <linux/delay.h> | 42 | #include <linux/delay.h> |
@@ -162,7 +163,8 @@ static struct miscdevice rng_miscdev = { | |||
162 | }; | 163 | }; |
163 | 164 | ||
164 | 165 | ||
165 | static ssize_t hwrng_attr_current_store(struct class_device *class, | 166 | static ssize_t hwrng_attr_current_store(struct device *dev, |
167 | struct device_attribute *attr, | ||
166 | const char *buf, size_t len) | 168 | const char *buf, size_t len) |
167 | { | 169 | { |
168 | int err; | 170 | int err; |
@@ -192,7 +194,8 @@ static ssize_t hwrng_attr_current_store(struct class_device *class, | |||
192 | return err ? : len; | 194 | return err ? : len; |
193 | } | 195 | } |
194 | 196 | ||
195 | static ssize_t hwrng_attr_current_show(struct class_device *class, | 197 | static ssize_t hwrng_attr_current_show(struct device *dev, |
198 | struct device_attribute *attr, | ||
196 | char *buf) | 199 | char *buf) |
197 | { | 200 | { |
198 | int err; | 201 | int err; |
@@ -210,7 +213,8 @@ static ssize_t hwrng_attr_current_show(struct class_device *class, | |||
210 | return ret; | 213 | return ret; |
211 | } | 214 | } |
212 | 215 | ||
213 | static ssize_t hwrng_attr_available_show(struct class_device *class, | 216 | static ssize_t hwrng_attr_available_show(struct device *dev, |
217 | struct device_attribute *attr, | ||
214 | char *buf) | 218 | char *buf) |
215 | { | 219 | { |
216 | int err; | 220 | int err; |
@@ -234,20 +238,18 @@ static ssize_t hwrng_attr_available_show(struct class_device *class, | |||
234 | return ret; | 238 | return ret; |
235 | } | 239 | } |
236 | 240 | ||
237 | static CLASS_DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR, | 241 | static DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR, |
238 | hwrng_attr_current_show, | 242 | hwrng_attr_current_show, |
239 | hwrng_attr_current_store); | 243 | hwrng_attr_current_store); |
240 | static CLASS_DEVICE_ATTR(rng_available, S_IRUGO, | 244 | static DEVICE_ATTR(rng_available, S_IRUGO, |
241 | hwrng_attr_available_show, | 245 | hwrng_attr_available_show, |
242 | NULL); | 246 | NULL); |
243 | 247 | ||
244 | 248 | ||
245 | static void unregister_miscdev(void) | 249 | static void unregister_miscdev(void) |
246 | { | 250 | { |
247 | class_device_remove_file(rng_miscdev.class, | 251 | device_remove_file(rng_miscdev.this_device, &dev_attr_rng_available); |
248 | &class_device_attr_rng_available); | 252 | device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current); |
249 | class_device_remove_file(rng_miscdev.class, | ||
250 | &class_device_attr_rng_current); | ||
251 | misc_deregister(&rng_miscdev); | 253 | misc_deregister(&rng_miscdev); |
252 | } | 254 | } |
253 | 255 | ||
@@ -258,20 +260,19 @@ static int register_miscdev(void) | |||
258 | err = misc_register(&rng_miscdev); | 260 | err = misc_register(&rng_miscdev); |
259 | if (err) | 261 | if (err) |
260 | goto out; | 262 | goto out; |
261 | err = class_device_create_file(rng_miscdev.class, | 263 | err = device_create_file(rng_miscdev.this_device, |
262 | &class_device_attr_rng_current); | 264 | &dev_attr_rng_current); |
263 | if (err) | 265 | if (err) |
264 | goto err_misc_dereg; | 266 | goto err_misc_dereg; |
265 | err = class_device_create_file(rng_miscdev.class, | 267 | err = device_create_file(rng_miscdev.this_device, |
266 | &class_device_attr_rng_available); | 268 | &dev_attr_rng_available); |
267 | if (err) | 269 | if (err) |
268 | goto err_remove_current; | 270 | goto err_remove_current; |
269 | out: | 271 | out: |
270 | return err; | 272 | return err; |
271 | 273 | ||
272 | err_remove_current: | 274 | err_remove_current: |
273 | class_device_remove_file(rng_miscdev.class, | 275 | device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current); |
274 | &class_device_attr_rng_current); | ||
275 | err_misc_dereg: | 276 | err_misc_dereg: |
276 | misc_deregister(&rng_miscdev); | 277 | misc_deregister(&rng_miscdev); |
277 | goto out; | 278 | goto out; |
diff --git a/drivers/char/ip2/i2cmd.h b/drivers/char/ip2/i2cmd.h index baa4e721b758..29277ec6b8ed 100644 --- a/drivers/char/ip2/i2cmd.h +++ b/drivers/char/ip2/i2cmd.h | |||
@@ -367,11 +367,6 @@ static UCHAR cc02[]; | |||
367 | #define CSE_NULL 3 // Replace with a null | 367 | #define CSE_NULL 3 // Replace with a null |
368 | #define CSE_MARK 4 // Replace with a 3-character sequence (as Unix) | 368 | #define CSE_MARK 4 // Replace with a 3-character sequence (as Unix) |
369 | 369 | ||
370 | #define CMD_SET_REPLACEMENT(arg,ch) \ | ||
371 | (((cmdSyntaxPtr)(ct36a))->cmd[1] = (arg), \ | ||
372 | (((cmdSyntaxPtr)(ct36a))->cmd[2] = (ch), \ | ||
373 | (cmdSyntaxPtr)(ct36a)) | ||
374 | |||
375 | #define CSE_REPLACE 0x8 // Replace the errored character with the | 370 | #define CSE_REPLACE 0x8 // Replace the errored character with the |
376 | // replacement character defined here | 371 | // replacement character defined here |
377 | 372 | ||
diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c index 54d93f0345e8..78045767ec33 100644 --- a/drivers/char/ip2/i2lib.c +++ b/drivers/char/ip2/i2lib.c | |||
@@ -84,8 +84,8 @@ static void iiSendPendingMail(i2eBordStrPtr); | |||
84 | static void serviceOutgoingFifo(i2eBordStrPtr); | 84 | static void serviceOutgoingFifo(i2eBordStrPtr); |
85 | 85 | ||
86 | // Functions defined in ip2.c as part of interrupt handling | 86 | // Functions defined in ip2.c as part of interrupt handling |
87 | static void do_input(void *); | 87 | static void do_input(struct work_struct *); |
88 | static void do_status(void *); | 88 | static void do_status(struct work_struct *); |
89 | 89 | ||
90 | //*************** | 90 | //*************** |
91 | //* Debug Data * | 91 | //* Debug Data * |
@@ -331,8 +331,8 @@ i2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh) | |||
331 | pCh->ClosingWaitTime = 30*HZ; | 331 | pCh->ClosingWaitTime = 30*HZ; |
332 | 332 | ||
333 | // Initialize task queue objects | 333 | // Initialize task queue objects |
334 | INIT_WORK(&pCh->tqueue_input, do_input, pCh); | 334 | INIT_WORK(&pCh->tqueue_input, do_input); |
335 | INIT_WORK(&pCh->tqueue_status, do_status, pCh); | 335 | INIT_WORK(&pCh->tqueue_status, do_status); |
336 | 336 | ||
337 | #ifdef IP2DEBUG_TRACE | 337 | #ifdef IP2DEBUG_TRACE |
338 | pCh->trace = ip2trace; | 338 | pCh->trace = ip2trace; |
@@ -1016,7 +1016,6 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count) | |||
1016 | unsigned short channel; | 1016 | unsigned short channel; |
1017 | unsigned short stuffIndex; | 1017 | unsigned short stuffIndex; |
1018 | unsigned long flags; | 1018 | unsigned long flags; |
1019 | int rc = 0; | ||
1020 | 1019 | ||
1021 | int bailout = 10; | 1020 | int bailout = 10; |
1022 | 1021 | ||
@@ -1573,7 +1572,7 @@ i2StripFifo(i2eBordStrPtr pB) | |||
1573 | #ifdef USE_IQ | 1572 | #ifdef USE_IQ |
1574 | schedule_work(&pCh->tqueue_input); | 1573 | schedule_work(&pCh->tqueue_input); |
1575 | #else | 1574 | #else |
1576 | do_input(pCh); | 1575 | do_input(&pCh->tqueue_input); |
1577 | #endif | 1576 | #endif |
1578 | 1577 | ||
1579 | // Note we do not need to maintain any flow-control credits at this | 1578 | // Note we do not need to maintain any flow-control credits at this |
@@ -1810,7 +1809,7 @@ i2StripFifo(i2eBordStrPtr pB) | |||
1810 | #ifdef USE_IQ | 1809 | #ifdef USE_IQ |
1811 | schedule_work(&pCh->tqueue_status); | 1810 | schedule_work(&pCh->tqueue_status); |
1812 | #else | 1811 | #else |
1813 | do_status(pCh); | 1812 | do_status(&pCh->tqueue_status); |
1814 | #endif | 1813 | #endif |
1815 | } | 1814 | } |
1816 | } | 1815 | } |
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index a3f32d46d2f8..cda2459c1d60 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c | |||
@@ -189,12 +189,12 @@ static int ip2_tiocmset(struct tty_struct *tty, struct file *file, | |||
189 | unsigned int set, unsigned int clear); | 189 | unsigned int set, unsigned int clear); |
190 | 190 | ||
191 | static void set_irq(int, int); | 191 | static void set_irq(int, int); |
192 | static void ip2_interrupt_bh(i2eBordStrPtr pB); | 192 | static void ip2_interrupt_bh(struct work_struct *work); |
193 | static irqreturn_t ip2_interrupt(int irq, void *dev_id); | 193 | static irqreturn_t ip2_interrupt(int irq, void *dev_id); |
194 | static void ip2_poll(unsigned long arg); | 194 | static void ip2_poll(unsigned long arg); |
195 | static inline void service_all_boards(void); | 195 | static inline void service_all_boards(void); |
196 | static void do_input(void *p); | 196 | static void do_input(struct work_struct *); |
197 | static void do_status(void *p); | 197 | static void do_status(struct work_struct *); |
198 | 198 | ||
199 | static void ip2_wait_until_sent(PTTY,int); | 199 | static void ip2_wait_until_sent(PTTY,int); |
200 | 200 | ||
@@ -918,7 +918,7 @@ ip2_init_board( int boardnum ) | |||
918 | pCh++; | 918 | pCh++; |
919 | } | 919 | } |
920 | ex_exit: | 920 | ex_exit: |
921 | INIT_WORK(&pB->tqueue_interrupt, (void(*)(void*)) ip2_interrupt_bh, pB); | 921 | INIT_WORK(&pB->tqueue_interrupt, ip2_interrupt_bh); |
922 | return; | 922 | return; |
923 | 923 | ||
924 | err_release_region: | 924 | err_release_region: |
@@ -1125,8 +1125,8 @@ service_all_boards(void) | |||
1125 | 1125 | ||
1126 | 1126 | ||
1127 | /******************************************************************************/ | 1127 | /******************************************************************************/ |
1128 | /* Function: ip2_interrupt_bh(pB) */ | 1128 | /* Function: ip2_interrupt_bh(work) */ |
1129 | /* Parameters: pB - pointer to the board structure */ | 1129 | /* Parameters: work - pointer to the board structure */ |
1130 | /* Returns: Nothing */ | 1130 | /* Returns: Nothing */ |
1131 | /* */ | 1131 | /* */ |
1132 | /* Description: */ | 1132 | /* Description: */ |
@@ -1135,8 +1135,9 @@ service_all_boards(void) | |||
1135 | /* */ | 1135 | /* */ |
1136 | /******************************************************************************/ | 1136 | /******************************************************************************/ |
1137 | static void | 1137 | static void |
1138 | ip2_interrupt_bh(i2eBordStrPtr pB) | 1138 | ip2_interrupt_bh(struct work_struct *work) |
1139 | { | 1139 | { |
1140 | i2eBordStrPtr pB = container_of(work, i2eBordStr, tqueue_interrupt); | ||
1140 | // pB better well be set or we have a problem! We can only get | 1141 | // pB better well be set or we have a problem! We can only get |
1141 | // here from the IMMEDIATE queue. Here, we process the boards. | 1142 | // here from the IMMEDIATE queue. Here, we process the boards. |
1142 | // Checking pB doesn't cost much and it saves us from the sanity checkers. | 1143 | // Checking pB doesn't cost much and it saves us from the sanity checkers. |
@@ -1245,9 +1246,9 @@ ip2_poll(unsigned long arg) | |||
1245 | ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 ); | 1246 | ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 ); |
1246 | } | 1247 | } |
1247 | 1248 | ||
1248 | static void do_input(void *p) | 1249 | static void do_input(struct work_struct *work) |
1249 | { | 1250 | { |
1250 | i2ChanStrPtr pCh = p; | 1251 | i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_input); |
1251 | unsigned long flags; | 1252 | unsigned long flags; |
1252 | 1253 | ||
1253 | ip2trace(CHANN, ITRC_INPUT, 21, 0 ); | 1254 | ip2trace(CHANN, ITRC_INPUT, 21, 0 ); |
@@ -1279,9 +1280,9 @@ static inline void isig(int sig, struct tty_struct *tty, int flush) | |||
1279 | } | 1280 | } |
1280 | } | 1281 | } |
1281 | 1282 | ||
1282 | static void do_status(void *p) | 1283 | static void do_status(struct work_struct *work) |
1283 | { | 1284 | { |
1284 | i2ChanStrPtr pCh = p; | 1285 | i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_status); |
1285 | int status; | 1286 | int status; |
1286 | 1287 | ||
1287 | status = i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) ); | 1288 | status = i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) ); |
diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index 0030cd8e2e95..6c59baa887a8 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c | |||
@@ -33,11 +33,13 @@ | |||
33 | #include <linux/ipmi_msgdefs.h> /* for completion codes */ | 33 | #include <linux/ipmi_msgdefs.h> /* for completion codes */ |
34 | #include "ipmi_si_sm.h" | 34 | #include "ipmi_si_sm.h" |
35 | 35 | ||
36 | static int bt_debug = 0x00; /* Production value 0, see following flags */ | 36 | #define BT_DEBUG_OFF 0 /* Used in production */ |
37 | #define BT_DEBUG_ENABLE 1 /* Generic messages */ | ||
38 | #define BT_DEBUG_MSG 2 /* Prints all request/response buffers */ | ||
39 | #define BT_DEBUG_STATES 4 /* Verbose look at state changes */ | ||
40 | |||
41 | static int bt_debug = BT_DEBUG_OFF; | ||
37 | 42 | ||
38 | #define BT_DEBUG_ENABLE 1 | ||
39 | #define BT_DEBUG_MSG 2 | ||
40 | #define BT_DEBUG_STATES 4 | ||
41 | module_param(bt_debug, int, 0644); | 43 | module_param(bt_debug, int, 0644); |
42 | MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); | 44 | MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); |
43 | 45 | ||
@@ -47,38 +49,54 @@ MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); | |||
47 | Since the Open IPMI architecture is single-message oriented at this | 49 | Since the Open IPMI architecture is single-message oriented at this |
48 | stage, the queue depth of BT is of no concern. */ | 50 | stage, the queue depth of BT is of no concern. */ |
49 | 51 | ||
50 | #define BT_NORMAL_TIMEOUT 5000000 /* seconds in microseconds */ | 52 | #define BT_NORMAL_TIMEOUT 5 /* seconds */ |
51 | #define BT_RETRY_LIMIT 2 | 53 | #define BT_NORMAL_RETRY_LIMIT 2 |
52 | #define BT_RESET_DELAY 6000000 /* 6 seconds after warm reset */ | 54 | #define BT_RESET_DELAY 6 /* seconds after warm reset */ |
55 | |||
56 | /* States are written in chronological order and usually cover | ||
57 | multiple rows of the state table discussion in the IPMI spec. */ | ||
53 | 58 | ||
54 | enum bt_states { | 59 | enum bt_states { |
55 | BT_STATE_IDLE, | 60 | BT_STATE_IDLE = 0, /* Order is critical in this list */ |
56 | BT_STATE_XACTION_START, | 61 | BT_STATE_XACTION_START, |
57 | BT_STATE_WRITE_BYTES, | 62 | BT_STATE_WRITE_BYTES, |
58 | BT_STATE_WRITE_END, | ||
59 | BT_STATE_WRITE_CONSUME, | 63 | BT_STATE_WRITE_CONSUME, |
60 | BT_STATE_B2H_WAIT, | 64 | BT_STATE_READ_WAIT, |
61 | BT_STATE_READ_END, | 65 | BT_STATE_CLEAR_B2H, |
62 | BT_STATE_RESET1, /* These must come last */ | 66 | BT_STATE_READ_BYTES, |
67 | BT_STATE_RESET1, /* These must come last */ | ||
63 | BT_STATE_RESET2, | 68 | BT_STATE_RESET2, |
64 | BT_STATE_RESET3, | 69 | BT_STATE_RESET3, |
65 | BT_STATE_RESTART, | 70 | BT_STATE_RESTART, |
66 | BT_STATE_HOSED | 71 | BT_STATE_PRINTME, |
72 | BT_STATE_CAPABILITIES_BEGIN, | ||
73 | BT_STATE_CAPABILITIES_END, | ||
74 | BT_STATE_LONG_BUSY /* BT doesn't get hosed :-) */ | ||
67 | }; | 75 | }; |
68 | 76 | ||
77 | /* Macros seen at the end of state "case" blocks. They help with legibility | ||
78 | and debugging. */ | ||
79 | |||
80 | #define BT_STATE_CHANGE(X,Y) { bt->state = X; return Y; } | ||
81 | |||
82 | #define BT_SI_SM_RETURN(Y) { last_printed = BT_STATE_PRINTME; return Y; } | ||
83 | |||
69 | struct si_sm_data { | 84 | struct si_sm_data { |
70 | enum bt_states state; | 85 | enum bt_states state; |
71 | enum bt_states last_state; /* assist printing and resets */ | ||
72 | unsigned char seq; /* BT sequence number */ | 86 | unsigned char seq; /* BT sequence number */ |
73 | struct si_sm_io *io; | 87 | struct si_sm_io *io; |
74 | unsigned char write_data[IPMI_MAX_MSG_LENGTH]; | 88 | unsigned char write_data[IPMI_MAX_MSG_LENGTH]; |
75 | int write_count; | 89 | int write_count; |
76 | unsigned char read_data[IPMI_MAX_MSG_LENGTH]; | 90 | unsigned char read_data[IPMI_MAX_MSG_LENGTH]; |
77 | int read_count; | 91 | int read_count; |
78 | int truncated; | 92 | int truncated; |
79 | long timeout; | 93 | long timeout; /* microseconds countdown */ |
80 | unsigned int error_retries; /* end of "common" fields */ | 94 | int error_retries; /* end of "common" fields */ |
81 | int nonzero_status; /* hung BMCs stay all 0 */ | 95 | int nonzero_status; /* hung BMCs stay all 0 */ |
96 | enum bt_states complete; /* to divert the state machine */ | ||
97 | int BT_CAP_outreqs; | ||
98 | long BT_CAP_req2rsp; | ||
99 | int BT_CAP_retries; /* Recommended retries */ | ||
82 | }; | 100 | }; |
83 | 101 | ||
84 | #define BT_CLR_WR_PTR 0x01 /* See IPMI 1.5 table 11.6.4 */ | 102 | #define BT_CLR_WR_PTR 0x01 /* See IPMI 1.5 table 11.6.4 */ |
@@ -111,86 +129,118 @@ struct si_sm_data { | |||
111 | static char *state2txt(unsigned char state) | 129 | static char *state2txt(unsigned char state) |
112 | { | 130 | { |
113 | switch (state) { | 131 | switch (state) { |
114 | case BT_STATE_IDLE: return("IDLE"); | 132 | case BT_STATE_IDLE: return("IDLE"); |
115 | case BT_STATE_XACTION_START: return("XACTION"); | 133 | case BT_STATE_XACTION_START: return("XACTION"); |
116 | case BT_STATE_WRITE_BYTES: return("WR_BYTES"); | 134 | case BT_STATE_WRITE_BYTES: return("WR_BYTES"); |
117 | case BT_STATE_WRITE_END: return("WR_END"); | 135 | case BT_STATE_WRITE_CONSUME: return("WR_CONSUME"); |
118 | case BT_STATE_WRITE_CONSUME: return("WR_CONSUME"); | 136 | case BT_STATE_READ_WAIT: return("RD_WAIT"); |
119 | case BT_STATE_B2H_WAIT: return("B2H_WAIT"); | 137 | case BT_STATE_CLEAR_B2H: return("CLEAR_B2H"); |
120 | case BT_STATE_READ_END: return("RD_END"); | 138 | case BT_STATE_READ_BYTES: return("RD_BYTES"); |
121 | case BT_STATE_RESET1: return("RESET1"); | 139 | case BT_STATE_RESET1: return("RESET1"); |
122 | case BT_STATE_RESET2: return("RESET2"); | 140 | case BT_STATE_RESET2: return("RESET2"); |
123 | case BT_STATE_RESET3: return("RESET3"); | 141 | case BT_STATE_RESET3: return("RESET3"); |
124 | case BT_STATE_RESTART: return("RESTART"); | 142 | case BT_STATE_RESTART: return("RESTART"); |
125 | case BT_STATE_HOSED: return("HOSED"); | 143 | case BT_STATE_LONG_BUSY: return("LONG_BUSY"); |
144 | case BT_STATE_CAPABILITIES_BEGIN: return("CAP_BEGIN"); | ||
145 | case BT_STATE_CAPABILITIES_END: return("CAP_END"); | ||
126 | } | 146 | } |
127 | return("BAD STATE"); | 147 | return("BAD STATE"); |
128 | } | 148 | } |
129 | #define STATE2TXT state2txt(bt->state) | 149 | #define STATE2TXT state2txt(bt->state) |
130 | 150 | ||
131 | static char *status2txt(unsigned char status, char *buf) | 151 | static char *status2txt(unsigned char status) |
132 | { | 152 | { |
153 | /* | ||
154 | * This cannot be called by two threads at the same time and | ||
155 | * the buffer is always consumed immediately, so the static is | ||
156 | * safe to use. | ||
157 | */ | ||
158 | static char buf[40]; | ||
159 | |||
133 | strcpy(buf, "[ "); | 160 | strcpy(buf, "[ "); |
134 | if (status & BT_B_BUSY) strcat(buf, "B_BUSY "); | 161 | if (status & BT_B_BUSY) |
135 | if (status & BT_H_BUSY) strcat(buf, "H_BUSY "); | 162 | strcat(buf, "B_BUSY "); |
136 | if (status & BT_OEM0) strcat(buf, "OEM0 "); | 163 | if (status & BT_H_BUSY) |
137 | if (status & BT_SMS_ATN) strcat(buf, "SMS "); | 164 | strcat(buf, "H_BUSY "); |
138 | if (status & BT_B2H_ATN) strcat(buf, "B2H "); | 165 | if (status & BT_OEM0) |
139 | if (status & BT_H2B_ATN) strcat(buf, "H2B "); | 166 | strcat(buf, "OEM0 "); |
167 | if (status & BT_SMS_ATN) | ||
168 | strcat(buf, "SMS "); | ||
169 | if (status & BT_B2H_ATN) | ||
170 | strcat(buf, "B2H "); | ||
171 | if (status & BT_H2B_ATN) | ||
172 | strcat(buf, "H2B "); | ||
140 | strcat(buf, "]"); | 173 | strcat(buf, "]"); |
141 | return buf; | 174 | return buf; |
142 | } | 175 | } |
143 | #define STATUS2TXT(buf) status2txt(status, buf) | 176 | #define STATUS2TXT status2txt(status) |
177 | |||
178 | /* called externally at insmod time, and internally on cleanup */ | ||
144 | 179 | ||
145 | /* This will be called from within this module on a hosed condition */ | ||
146 | #define FIRST_SEQ 0 | ||
147 | static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io) | 180 | static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io) |
148 | { | 181 | { |
149 | bt->state = BT_STATE_IDLE; | 182 | memset(bt, 0, sizeof(struct si_sm_data)); |
150 | bt->last_state = BT_STATE_IDLE; | 183 | if (bt->io != io) { /* external: one-time only things */ |
151 | bt->seq = FIRST_SEQ; | 184 | bt->io = io; |
152 | bt->io = io; | 185 | bt->seq = 0; |
153 | bt->write_count = 0; | 186 | } |
154 | bt->read_count = 0; | 187 | bt->state = BT_STATE_IDLE; /* start here */ |
155 | bt->error_retries = 0; | 188 | bt->complete = BT_STATE_IDLE; /* end here */ |
156 | bt->nonzero_status = 0; | 189 | bt->BT_CAP_req2rsp = BT_NORMAL_TIMEOUT * 1000000; |
157 | bt->truncated = 0; | 190 | bt->BT_CAP_retries = BT_NORMAL_RETRY_LIMIT; |
158 | bt->timeout = BT_NORMAL_TIMEOUT; | 191 | /* BT_CAP_outreqs == zero is a flag to read BT Capabilities */ |
159 | return 3; /* We claim 3 bytes of space; ought to check SPMI table */ | 192 | return 3; /* We claim 3 bytes of space; ought to check SPMI table */ |
160 | } | 193 | } |
161 | 194 | ||
195 | /* Jam a completion code (probably an error) into a response */ | ||
196 | |||
197 | static void force_result(struct si_sm_data *bt, unsigned char completion_code) | ||
198 | { | ||
199 | bt->read_data[0] = 4; /* # following bytes */ | ||
200 | bt->read_data[1] = bt->write_data[1] | 4; /* Odd NetFn/LUN */ | ||
201 | bt->read_data[2] = bt->write_data[2]; /* seq (ignored) */ | ||
202 | bt->read_data[3] = bt->write_data[3]; /* Command */ | ||
203 | bt->read_data[4] = completion_code; | ||
204 | bt->read_count = 5; | ||
205 | } | ||
206 | |||
207 | /* The upper state machine starts here */ | ||
208 | |||
162 | static int bt_start_transaction(struct si_sm_data *bt, | 209 | static int bt_start_transaction(struct si_sm_data *bt, |
163 | unsigned char *data, | 210 | unsigned char *data, |
164 | unsigned int size) | 211 | unsigned int size) |
165 | { | 212 | { |
166 | unsigned int i; | 213 | unsigned int i; |
167 | 214 | ||
168 | if ((size < 2) || (size > (IPMI_MAX_MSG_LENGTH - 2))) | 215 | if (size < 2) |
169 | return -1; | 216 | return IPMI_REQ_LEN_INVALID_ERR; |
217 | if (size > IPMI_MAX_MSG_LENGTH) | ||
218 | return IPMI_REQ_LEN_EXCEEDED_ERR; | ||
170 | 219 | ||
171 | if ((bt->state != BT_STATE_IDLE) && (bt->state != BT_STATE_HOSED)) | 220 | if (bt->state == BT_STATE_LONG_BUSY) |
172 | return -2; | 221 | return IPMI_NODE_BUSY_ERR; |
222 | |||
223 | if (bt->state != BT_STATE_IDLE) | ||
224 | return IPMI_NOT_IN_MY_STATE_ERR; | ||
173 | 225 | ||
174 | if (bt_debug & BT_DEBUG_MSG) { | 226 | if (bt_debug & BT_DEBUG_MSG) { |
175 | printk(KERN_WARNING "+++++++++++++++++++++++++++++++++++++\n"); | 227 | printk(KERN_WARNING "BT: +++++++++++++++++ New command\n"); |
176 | printk(KERN_WARNING "BT: write seq=0x%02X:", bt->seq); | 228 | printk(KERN_WARNING "BT: NetFn/LUN CMD [%d data]:", size - 2); |
177 | for (i = 0; i < size; i ++) | 229 | for (i = 0; i < size; i ++) |
178 | printk (" %02x", data[i]); | 230 | printk (" %02x", data[i]); |
179 | printk("\n"); | 231 | printk("\n"); |
180 | } | 232 | } |
181 | bt->write_data[0] = size + 1; /* all data plus seq byte */ | 233 | bt->write_data[0] = size + 1; /* all data plus seq byte */ |
182 | bt->write_data[1] = *data; /* NetFn/LUN */ | 234 | bt->write_data[1] = *data; /* NetFn/LUN */ |
183 | bt->write_data[2] = bt->seq; | 235 | bt->write_data[2] = bt->seq++; |
184 | memcpy(bt->write_data + 3, data + 1, size - 1); | 236 | memcpy(bt->write_data + 3, data + 1, size - 1); |
185 | bt->write_count = size + 2; | 237 | bt->write_count = size + 2; |
186 | |||
187 | bt->error_retries = 0; | 238 | bt->error_retries = 0; |
188 | bt->nonzero_status = 0; | 239 | bt->nonzero_status = 0; |
189 | bt->read_count = 0; | ||
190 | bt->truncated = 0; | 240 | bt->truncated = 0; |
191 | bt->state = BT_STATE_XACTION_START; | 241 | bt->state = BT_STATE_XACTION_START; |
192 | bt->last_state = BT_STATE_IDLE; | 242 | bt->timeout = bt->BT_CAP_req2rsp; |
193 | bt->timeout = BT_NORMAL_TIMEOUT; | 243 | force_result(bt, IPMI_ERR_UNSPECIFIED); |
194 | return 0; | 244 | return 0; |
195 | } | 245 | } |
196 | 246 | ||
@@ -198,38 +248,30 @@ static int bt_start_transaction(struct si_sm_data *bt, | |||
198 | it calls this. Strip out the length and seq bytes. */ | 248 | it calls this. Strip out the length and seq bytes. */ |
199 | 249 | ||
200 | static int bt_get_result(struct si_sm_data *bt, | 250 | static int bt_get_result(struct si_sm_data *bt, |
201 | unsigned char *data, | 251 | unsigned char *data, |
202 | unsigned int length) | 252 | unsigned int length) |
203 | { | 253 | { |
204 | int i, msg_len; | 254 | int i, msg_len; |
205 | 255 | ||
206 | msg_len = bt->read_count - 2; /* account for length & seq */ | 256 | msg_len = bt->read_count - 2; /* account for length & seq */ |
207 | /* Always NetFn, Cmd, cCode */ | ||
208 | if (msg_len < 3 || msg_len > IPMI_MAX_MSG_LENGTH) { | 257 | if (msg_len < 3 || msg_len > IPMI_MAX_MSG_LENGTH) { |
209 | printk(KERN_DEBUG "BT results: bad msg_len = %d\n", msg_len); | 258 | force_result(bt, IPMI_ERR_UNSPECIFIED); |
210 | data[0] = bt->write_data[1] | 0x4; /* Kludge a response */ | ||
211 | data[1] = bt->write_data[3]; | ||
212 | data[2] = IPMI_ERR_UNSPECIFIED; | ||
213 | msg_len = 3; | 259 | msg_len = 3; |
214 | } else { | 260 | } |
215 | data[0] = bt->read_data[1]; | 261 | data[0] = bt->read_data[1]; |
216 | data[1] = bt->read_data[3]; | 262 | data[1] = bt->read_data[3]; |
217 | if (length < msg_len) | 263 | if (length < msg_len || bt->truncated) { |
218 | bt->truncated = 1; | 264 | data[2] = IPMI_ERR_MSG_TRUNCATED; |
219 | if (bt->truncated) { /* can be set in read_all_bytes() */ | 265 | msg_len = 3; |
220 | data[2] = IPMI_ERR_MSG_TRUNCATED; | 266 | } else |
221 | msg_len = 3; | 267 | memcpy(data + 2, bt->read_data + 4, msg_len - 2); |
222 | } else | ||
223 | memcpy(data + 2, bt->read_data + 4, msg_len - 2); | ||
224 | 268 | ||
225 | if (bt_debug & BT_DEBUG_MSG) { | 269 | if (bt_debug & BT_DEBUG_MSG) { |
226 | printk (KERN_WARNING "BT: res (raw)"); | 270 | printk (KERN_WARNING "BT: result %d bytes:", msg_len); |
227 | for (i = 0; i < msg_len; i++) | 271 | for (i = 0; i < msg_len; i++) |
228 | printk(" %02x", data[i]); | 272 | printk(" %02x", data[i]); |
229 | printk ("\n"); | 273 | printk ("\n"); |
230 | } | ||
231 | } | 274 | } |
232 | bt->read_count = 0; /* paranoia */ | ||
233 | return msg_len; | 275 | return msg_len; |
234 | } | 276 | } |
235 | 277 | ||
@@ -238,22 +280,40 @@ static int bt_get_result(struct si_sm_data *bt, | |||
238 | 280 | ||
239 | static void reset_flags(struct si_sm_data *bt) | 281 | static void reset_flags(struct si_sm_data *bt) |
240 | { | 282 | { |
283 | if (bt_debug) | ||
284 | printk(KERN_WARNING "IPMI BT: flag reset %s\n", | ||
285 | status2txt(BT_STATUS)); | ||
241 | if (BT_STATUS & BT_H_BUSY) | 286 | if (BT_STATUS & BT_H_BUSY) |
242 | BT_CONTROL(BT_H_BUSY); | 287 | BT_CONTROL(BT_H_BUSY); /* force clear */ |
243 | if (BT_STATUS & BT_B_BUSY) | 288 | BT_CONTROL(BT_CLR_WR_PTR); /* always reset */ |
244 | BT_CONTROL(BT_B_BUSY); | 289 | BT_CONTROL(BT_SMS_ATN); /* always clear */ |
245 | BT_CONTROL(BT_CLR_WR_PTR); | 290 | BT_INTMASK_W(BT_BMC_HWRST); |
246 | BT_CONTROL(BT_SMS_ATN); | 291 | } |
247 | 292 | ||
248 | if (BT_STATUS & BT_B2H_ATN) { | 293 | /* Get rid of an unwanted/stale response. This should only be needed for |
249 | int i; | 294 | BMCs that support multiple outstanding requests. */ |
250 | BT_CONTROL(BT_H_BUSY); | 295 | |
251 | BT_CONTROL(BT_B2H_ATN); | 296 | static void drain_BMC2HOST(struct si_sm_data *bt) |
252 | BT_CONTROL(BT_CLR_RD_PTR); | 297 | { |
253 | for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++) | 298 | int i, size; |
254 | BMC2HOST; | 299 | |
255 | BT_CONTROL(BT_H_BUSY); | 300 | if (!(BT_STATUS & BT_B2H_ATN)) /* Not signalling a response */ |
256 | } | 301 | return; |
302 | |||
303 | BT_CONTROL(BT_H_BUSY); /* now set */ | ||
304 | BT_CONTROL(BT_B2H_ATN); /* always clear */ | ||
305 | BT_STATUS; /* pause */ | ||
306 | BT_CONTROL(BT_B2H_ATN); /* some BMCs are stubborn */ | ||
307 | BT_CONTROL(BT_CLR_RD_PTR); /* always reset */ | ||
308 | if (bt_debug) | ||
309 | printk(KERN_WARNING "IPMI BT: stale response %s; ", | ||
310 | status2txt(BT_STATUS)); | ||
311 | size = BMC2HOST; | ||
312 | for (i = 0; i < size ; i++) | ||
313 | BMC2HOST; | ||
314 | BT_CONTROL(BT_H_BUSY); /* now clear */ | ||
315 | if (bt_debug) | ||
316 | printk("drained %d bytes\n", size + 1); | ||
257 | } | 317 | } |
258 | 318 | ||
259 | static inline void write_all_bytes(struct si_sm_data *bt) | 319 | 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) | |||
261 | int i; | 321 | int i; |
262 | 322 | ||
263 | if (bt_debug & BT_DEBUG_MSG) { | 323 | if (bt_debug & BT_DEBUG_MSG) { |
264 | printk(KERN_WARNING "BT: write %d bytes seq=0x%02X", | 324 | printk(KERN_WARNING "BT: write %d bytes seq=0x%02X", |
265 | bt->write_count, bt->seq); | 325 | bt->write_count, bt->seq); |
266 | for (i = 0; i < bt->write_count; i++) | 326 | for (i = 0; i < bt->write_count; i++) |
267 | printk (" %02x", bt->write_data[i]); | 327 | printk (" %02x", bt->write_data[i]); |
268 | printk ("\n"); | 328 | printk ("\n"); |
269 | } | 329 | } |
270 | for (i = 0; i < bt->write_count; i++) | 330 | for (i = 0; i < bt->write_count; i++) |
271 | HOST2BMC(bt->write_data[i]); | 331 | HOST2BMC(bt->write_data[i]); |
272 | } | 332 | } |
273 | 333 | ||
274 | static inline int read_all_bytes(struct si_sm_data *bt) | 334 | static inline int read_all_bytes(struct si_sm_data *bt) |
275 | { | 335 | { |
276 | unsigned char i; | 336 | unsigned char i; |
277 | 337 | ||
338 | /* length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode. | ||
339 | Keep layout of first four bytes aligned with write_data[] */ | ||
340 | |||
278 | bt->read_data[0] = BMC2HOST; | 341 | bt->read_data[0] = BMC2HOST; |
279 | bt->read_count = bt->read_data[0]; | 342 | bt->read_count = bt->read_data[0]; |
280 | if (bt_debug & BT_DEBUG_MSG) | ||
281 | printk(KERN_WARNING "BT: read %d bytes:", bt->read_count); | ||
282 | 343 | ||
283 | /* minimum: length, NetFn, Seq, Cmd, cCode == 5 total, or 4 more | ||
284 | following the length byte. */ | ||
285 | if (bt->read_count < 4 || bt->read_count >= IPMI_MAX_MSG_LENGTH) { | 344 | if (bt->read_count < 4 || bt->read_count >= IPMI_MAX_MSG_LENGTH) { |
286 | if (bt_debug & BT_DEBUG_MSG) | 345 | if (bt_debug & BT_DEBUG_MSG) |
287 | printk("bad length %d\n", bt->read_count); | 346 | printk(KERN_WARNING "BT: bad raw rsp len=%d\n", |
347 | bt->read_count); | ||
288 | bt->truncated = 1; | 348 | bt->truncated = 1; |
289 | return 1; /* let next XACTION START clean it up */ | 349 | return 1; /* let next XACTION START clean it up */ |
290 | } | 350 | } |
291 | for (i = 1; i <= bt->read_count; i++) | 351 | for (i = 1; i <= bt->read_count; i++) |
292 | bt->read_data[i] = BMC2HOST; | 352 | bt->read_data[i] = BMC2HOST; |
293 | bt->read_count++; /* account for the length byte */ | 353 | bt->read_count++; /* Account internally for length byte */ |
294 | 354 | ||
295 | if (bt_debug & BT_DEBUG_MSG) { | 355 | if (bt_debug & BT_DEBUG_MSG) { |
296 | for (i = 0; i < bt->read_count; i++) | 356 | int max = bt->read_count; |
357 | |||
358 | printk(KERN_WARNING "BT: got %d bytes seq=0x%02X", | ||
359 | max, bt->read_data[2]); | ||
360 | if (max > 16) | ||
361 | max = 16; | ||
362 | for (i = 0; i < max; i++) | ||
297 | printk (" %02x", bt->read_data[i]); | 363 | printk (" %02x", bt->read_data[i]); |
298 | printk ("\n"); | 364 | printk ("%s\n", bt->read_count == max ? "" : " ..."); |
299 | } | 365 | } |
300 | if (bt->seq != bt->write_data[2]) /* idiot check */ | ||
301 | printk(KERN_DEBUG "BT: internal error: sequence mismatch\n"); | ||
302 | 366 | ||
303 | /* per the spec, the (NetFn, Seq, Cmd) tuples should match */ | 367 | /* per the spec, the (NetFn[1], Seq[2], Cmd[3]) tuples must match */ |
304 | if ((bt->read_data[3] == bt->write_data[3]) && /* Cmd */ | 368 | if ((bt->read_data[3] == bt->write_data[3]) && |
305 | (bt->read_data[2] == bt->write_data[2]) && /* Sequence */ | 369 | (bt->read_data[2] == bt->write_data[2]) && |
306 | ((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8))) | 370 | ((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8))) |
307 | return 1; | 371 | return 1; |
308 | 372 | ||
309 | if (bt_debug & BT_DEBUG_MSG) | 373 | if (bt_debug & BT_DEBUG_MSG) |
310 | printk(KERN_WARNING "BT: bad packet: " | 374 | printk(KERN_WARNING "IPMI BT: bad packet: " |
311 | "want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n", | 375 | "want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n", |
312 | bt->write_data[1], bt->write_data[2], bt->write_data[3], | 376 | bt->write_data[1] | 0x04, bt->write_data[2], bt->write_data[3], |
313 | bt->read_data[1], bt->read_data[2], bt->read_data[3]); | 377 | bt->read_data[1], bt->read_data[2], bt->read_data[3]); |
314 | return 0; | 378 | return 0; |
315 | } | 379 | } |
316 | 380 | ||
317 | /* Modifies bt->state appropriately, need to get into the bt_event() switch */ | 381 | /* Restart if retries are left, or return an error completion code */ |
318 | 382 | ||
319 | static void error_recovery(struct si_sm_data *bt, char *reason) | 383 | static enum si_sm_result error_recovery(struct si_sm_data *bt, |
384 | unsigned char status, | ||
385 | unsigned char cCode) | ||
320 | { | 386 | { |
321 | unsigned char status; | 387 | char *reason; |
322 | char buf[40]; /* For getting status */ | ||
323 | 388 | ||
324 | bt->timeout = BT_NORMAL_TIMEOUT; /* various places want to retry */ | 389 | bt->timeout = bt->BT_CAP_req2rsp; |
325 | 390 | ||
326 | status = BT_STATUS; | 391 | switch (cCode) { |
327 | printk(KERN_DEBUG "BT: %s in %s %s\n", reason, STATE2TXT, | 392 | case IPMI_TIMEOUT_ERR: |
328 | STATUS2TXT(buf)); | 393 | reason = "timeout"; |
394 | break; | ||
395 | default: | ||
396 | reason = "internal error"; | ||
397 | break; | ||
398 | } | ||
399 | |||
400 | printk(KERN_WARNING "IPMI BT: %s in %s %s ", /* open-ended line */ | ||
401 | reason, STATE2TXT, STATUS2TXT); | ||
329 | 402 | ||
403 | /* Per the IPMI spec, retries are based on the sequence number | ||
404 | known only to this module, so manage a restart here. */ | ||
330 | (bt->error_retries)++; | 405 | (bt->error_retries)++; |
331 | if (bt->error_retries > BT_RETRY_LIMIT) { | 406 | if (bt->error_retries < bt->BT_CAP_retries) { |
332 | printk(KERN_DEBUG "retry limit (%d) exceeded\n", BT_RETRY_LIMIT); | 407 | printk("%d retries left\n", |
333 | bt->state = BT_STATE_HOSED; | 408 | bt->BT_CAP_retries - bt->error_retries); |
334 | if (!bt->nonzero_status) | 409 | bt->state = BT_STATE_RESTART; |
335 | printk(KERN_ERR "IPMI: BT stuck, try power cycle\n"); | 410 | return SI_SM_CALL_WITHOUT_DELAY; |
336 | else if (bt->error_retries <= BT_RETRY_LIMIT + 1) { | ||
337 | printk(KERN_DEBUG "IPMI: BT reset (takes 5 secs)\n"); | ||
338 | bt->state = BT_STATE_RESET1; | ||
339 | } | ||
340 | return; | ||
341 | } | 411 | } |
342 | 412 | ||
343 | /* Sometimes the BMC queues get in an "off-by-one" state...*/ | 413 | printk("failed %d retries, sending error response\n", |
344 | if ((bt->state == BT_STATE_B2H_WAIT) && (status & BT_B2H_ATN)) { | 414 | bt->BT_CAP_retries); |
345 | printk(KERN_DEBUG "retry B2H_WAIT\n"); | 415 | if (!bt->nonzero_status) |
346 | return; | 416 | printk(KERN_ERR "IPMI BT: stuck, try power cycle\n"); |
417 | |||
418 | /* this is most likely during insmod */ | ||
419 | else if (bt->seq <= (unsigned char)(bt->BT_CAP_retries & 0xFF)) { | ||
420 | printk(KERN_WARNING "IPMI: BT reset (takes 5 secs)\n"); | ||
421 | bt->state = BT_STATE_RESET1; | ||
422 | return SI_SM_CALL_WITHOUT_DELAY; | ||
347 | } | 423 | } |
348 | 424 | ||
349 | printk(KERN_DEBUG "restart command\n"); | 425 | /* Concoct a useful error message, set up the next state, and |
350 | bt->state = BT_STATE_RESTART; | 426 | be done with this sequence. */ |
427 | |||
428 | bt->state = BT_STATE_IDLE; | ||
429 | switch (cCode) { | ||
430 | case IPMI_TIMEOUT_ERR: | ||
431 | if (status & BT_B_BUSY) { | ||
432 | cCode = IPMI_NODE_BUSY_ERR; | ||
433 | bt->state = BT_STATE_LONG_BUSY; | ||
434 | } | ||
435 | break; | ||
436 | default: | ||
437 | break; | ||
438 | } | ||
439 | force_result(bt, cCode); | ||
440 | return SI_SM_TRANSACTION_COMPLETE; | ||
351 | } | 441 | } |
352 | 442 | ||
353 | /* Check the status and (possibly) advance the BT state machine. The | 443 | /* Check status and (usually) take action and change this state machine. */ |
354 | default return is SI_SM_CALL_WITH_DELAY. */ | ||
355 | 444 | ||
356 | static enum si_sm_result bt_event(struct si_sm_data *bt, long time) | 445 | static enum si_sm_result bt_event(struct si_sm_data *bt, long time) |
357 | { | 446 | { |
358 | unsigned char status; | 447 | unsigned char status, BT_CAP[8]; |
359 | char buf[40]; /* For getting status */ | 448 | static enum bt_states last_printed = BT_STATE_PRINTME; |
360 | int i; | 449 | int i; |
361 | 450 | ||
362 | status = BT_STATUS; | 451 | status = BT_STATUS; |
363 | bt->nonzero_status |= status; | 452 | bt->nonzero_status |= status; |
364 | 453 | if ((bt_debug & BT_DEBUG_STATES) && (bt->state != last_printed)) { | |
365 | if ((bt_debug & BT_DEBUG_STATES) && (bt->state != bt->last_state)) | ||
366 | printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n", | 454 | printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n", |
367 | STATE2TXT, | 455 | STATE2TXT, |
368 | STATUS2TXT(buf), | 456 | STATUS2TXT, |
369 | bt->timeout, | 457 | bt->timeout, |
370 | time); | 458 | time); |
371 | bt->last_state = bt->state; | 459 | last_printed = bt->state; |
460 | } | ||
372 | 461 | ||
373 | if (bt->state == BT_STATE_HOSED) | 462 | /* Commands that time out may still (eventually) provide a response. |
374 | return SI_SM_HOSED; | 463 | This stale response will get in the way of a new response so remove |
464 | it if possible (hopefully during IDLE). Even if it comes up later | ||
465 | it will be rejected by its (now-forgotten) seq number. */ | ||
466 | |||
467 | if ((bt->state < BT_STATE_WRITE_BYTES) && (status & BT_B2H_ATN)) { | ||
468 | drain_BMC2HOST(bt); | ||
469 | BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); | ||
470 | } | ||
375 | 471 | ||
376 | if (bt->state != BT_STATE_IDLE) { /* do timeout test */ | 472 | if ((bt->state != BT_STATE_IDLE) && |
473 | (bt->state < BT_STATE_PRINTME)) { /* check timeout */ | ||
377 | bt->timeout -= time; | 474 | bt->timeout -= time; |
378 | if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) { | 475 | if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) |
379 | error_recovery(bt, "timed out"); | 476 | return error_recovery(bt, |
380 | return SI_SM_CALL_WITHOUT_DELAY; | 477 | status, |
381 | } | 478 | IPMI_TIMEOUT_ERR); |
382 | } | 479 | } |
383 | 480 | ||
384 | switch (bt->state) { | 481 | switch (bt->state) { |
385 | 482 | ||
386 | case BT_STATE_IDLE: /* check for asynchronous messages */ | 483 | /* Idle state first checks for asynchronous messages from another |
484 | channel, then does some opportunistic housekeeping. */ | ||
485 | |||
486 | case BT_STATE_IDLE: | ||
387 | if (status & BT_SMS_ATN) { | 487 | if (status & BT_SMS_ATN) { |
388 | BT_CONTROL(BT_SMS_ATN); /* clear it */ | 488 | BT_CONTROL(BT_SMS_ATN); /* clear it */ |
389 | return SI_SM_ATTN; | 489 | return SI_SM_ATTN; |
390 | } | 490 | } |
391 | return SI_SM_IDLE; | ||
392 | 491 | ||
393 | case BT_STATE_XACTION_START: | 492 | if (status & BT_H_BUSY) /* clear a leftover H_BUSY */ |
394 | if (status & BT_H_BUSY) { | ||
395 | BT_CONTROL(BT_H_BUSY); | 493 | BT_CONTROL(BT_H_BUSY); |
396 | break; | ||
397 | } | ||
398 | if (status & BT_B2H_ATN) | ||
399 | break; | ||
400 | bt->state = BT_STATE_WRITE_BYTES; | ||
401 | return SI_SM_CALL_WITHOUT_DELAY; /* for logging */ | ||
402 | 494 | ||
403 | case BT_STATE_WRITE_BYTES: | 495 | /* Read BT capabilities if it hasn't been done yet */ |
496 | if (!bt->BT_CAP_outreqs) | ||
497 | BT_STATE_CHANGE(BT_STATE_CAPABILITIES_BEGIN, | ||
498 | SI_SM_CALL_WITHOUT_DELAY); | ||
499 | bt->timeout = bt->BT_CAP_req2rsp; | ||
500 | BT_SI_SM_RETURN(SI_SM_IDLE); | ||
501 | |||
502 | case BT_STATE_XACTION_START: | ||
404 | if (status & (BT_B_BUSY | BT_H2B_ATN)) | 503 | if (status & (BT_B_BUSY | BT_H2B_ATN)) |
405 | break; | 504 | BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); |
505 | if (BT_STATUS & BT_H_BUSY) | ||
506 | BT_CONTROL(BT_H_BUSY); /* force clear */ | ||
507 | BT_STATE_CHANGE(BT_STATE_WRITE_BYTES, | ||
508 | SI_SM_CALL_WITHOUT_DELAY); | ||
509 | |||
510 | case BT_STATE_WRITE_BYTES: | ||
511 | if (status & BT_H_BUSY) | ||
512 | BT_CONTROL(BT_H_BUSY); /* clear */ | ||
406 | BT_CONTROL(BT_CLR_WR_PTR); | 513 | BT_CONTROL(BT_CLR_WR_PTR); |
407 | write_all_bytes(bt); | 514 | write_all_bytes(bt); |
408 | BT_CONTROL(BT_H2B_ATN); /* clears too fast to catch? */ | 515 | BT_CONTROL(BT_H2B_ATN); /* can clear too fast to catch */ |
409 | bt->state = BT_STATE_WRITE_CONSUME; | 516 | BT_STATE_CHANGE(BT_STATE_WRITE_CONSUME, |
410 | return SI_SM_CALL_WITHOUT_DELAY; /* it MIGHT sail through */ | 517 | SI_SM_CALL_WITHOUT_DELAY); |
411 | |||
412 | case BT_STATE_WRITE_CONSUME: /* BMCs usually blow right thru here */ | ||
413 | if (status & (BT_H2B_ATN | BT_B_BUSY)) | ||
414 | break; | ||
415 | bt->state = BT_STATE_B2H_WAIT; | ||
416 | /* fall through with status */ | ||
417 | |||
418 | /* Stay in BT_STATE_B2H_WAIT until a packet matches. However, spinning | ||
419 | hard here, constantly reading status, seems to hold off the | ||
420 | generation of B2H_ATN so ALWAYS return CALL_WITH_DELAY. */ | ||
421 | |||
422 | case BT_STATE_B2H_WAIT: | ||
423 | if (!(status & BT_B2H_ATN)) | ||
424 | break; | ||
425 | |||
426 | /* Assume ordered, uncached writes: no need to wait */ | ||
427 | if (!(status & BT_H_BUSY)) | ||
428 | BT_CONTROL(BT_H_BUSY); /* set */ | ||
429 | BT_CONTROL(BT_B2H_ATN); /* clear it, ACK to the BMC */ | ||
430 | BT_CONTROL(BT_CLR_RD_PTR); /* reset the queue */ | ||
431 | i = read_all_bytes(bt); | ||
432 | BT_CONTROL(BT_H_BUSY); /* clear */ | ||
433 | if (!i) /* Try this state again */ | ||
434 | break; | ||
435 | bt->state = BT_STATE_READ_END; | ||
436 | return SI_SM_CALL_WITHOUT_DELAY; /* for logging */ | ||
437 | |||
438 | case BT_STATE_READ_END: | ||
439 | |||
440 | /* I could wait on BT_H_BUSY to go clear for a truly clean | ||
441 | exit. However, this is already done in XACTION_START | ||
442 | and the (possible) extra loop/status/possible wait affects | ||
443 | performance. So, as long as it works, just ignore H_BUSY */ | ||
444 | |||
445 | #ifdef MAKE_THIS_TRUE_IF_NECESSARY | ||
446 | 518 | ||
447 | if (status & BT_H_BUSY) | 519 | case BT_STATE_WRITE_CONSUME: |
448 | break; | 520 | if (status & (BT_B_BUSY | BT_H2B_ATN)) |
449 | #endif | 521 | BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); |
450 | bt->seq++; | 522 | BT_STATE_CHANGE(BT_STATE_READ_WAIT, |
451 | bt->state = BT_STATE_IDLE; | 523 | SI_SM_CALL_WITHOUT_DELAY); |
452 | return SI_SM_TRANSACTION_COMPLETE; | 524 | |
525 | /* Spinning hard can suppress B2H_ATN and force a timeout */ | ||
526 | |||
527 | case BT_STATE_READ_WAIT: | ||
528 | if (!(status & BT_B2H_ATN)) | ||
529 | BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); | ||
530 | BT_CONTROL(BT_H_BUSY); /* set */ | ||
531 | |||
532 | /* Uncached, ordered writes should just proceeed serially but | ||
533 | some BMCs don't clear B2H_ATN with one hit. Fast-path a | ||
534 | workaround without too much penalty to the general case. */ | ||
535 | |||
536 | BT_CONTROL(BT_B2H_ATN); /* clear it to ACK the BMC */ | ||
537 | BT_STATE_CHANGE(BT_STATE_CLEAR_B2H, | ||
538 | SI_SM_CALL_WITHOUT_DELAY); | ||
539 | |||
540 | case BT_STATE_CLEAR_B2H: | ||
541 | if (status & BT_B2H_ATN) { /* keep hitting it */ | ||
542 | BT_CONTROL(BT_B2H_ATN); | ||
543 | BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); | ||
544 | } | ||
545 | BT_STATE_CHANGE(BT_STATE_READ_BYTES, | ||
546 | SI_SM_CALL_WITHOUT_DELAY); | ||
547 | |||
548 | case BT_STATE_READ_BYTES: | ||
549 | if (!(status & BT_H_BUSY)) /* check in case of retry */ | ||
550 | BT_CONTROL(BT_H_BUSY); | ||
551 | BT_CONTROL(BT_CLR_RD_PTR); /* start of BMC2HOST buffer */ | ||
552 | i = read_all_bytes(bt); /* true == packet seq match */ | ||
553 | BT_CONTROL(BT_H_BUSY); /* NOW clear */ | ||
554 | if (!i) /* Not my message */ | ||
555 | BT_STATE_CHANGE(BT_STATE_READ_WAIT, | ||
556 | SI_SM_CALL_WITHOUT_DELAY); | ||
557 | bt->state = bt->complete; | ||
558 | return bt->state == BT_STATE_IDLE ? /* where to next? */ | ||
559 | SI_SM_TRANSACTION_COMPLETE : /* normal */ | ||
560 | SI_SM_CALL_WITHOUT_DELAY; /* Startup magic */ | ||
561 | |||
562 | case BT_STATE_LONG_BUSY: /* For example: after FW update */ | ||
563 | if (!(status & BT_B_BUSY)) { | ||
564 | reset_flags(bt); /* next state is now IDLE */ | ||
565 | bt_init_data(bt, bt->io); | ||
566 | } | ||
567 | return SI_SM_CALL_WITH_DELAY; /* No repeat printing */ | ||
453 | 568 | ||
454 | case BT_STATE_RESET1: | 569 | case BT_STATE_RESET1: |
455 | reset_flags(bt); | 570 | reset_flags(bt); |
456 | bt->timeout = BT_RESET_DELAY; | 571 | drain_BMC2HOST(bt); |
457 | bt->state = BT_STATE_RESET2; | 572 | BT_STATE_CHANGE(BT_STATE_RESET2, |
458 | break; | 573 | SI_SM_CALL_WITH_DELAY); |
459 | 574 | ||
460 | case BT_STATE_RESET2: /* Send a soft reset */ | 575 | case BT_STATE_RESET2: /* Send a soft reset */ |
461 | BT_CONTROL(BT_CLR_WR_PTR); | 576 | BT_CONTROL(BT_CLR_WR_PTR); |
@@ -464,29 +579,59 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) | |||
464 | HOST2BMC(42); /* Sequence number */ | 579 | HOST2BMC(42); /* Sequence number */ |
465 | HOST2BMC(3); /* Cmd == Soft reset */ | 580 | HOST2BMC(3); /* Cmd == Soft reset */ |
466 | BT_CONTROL(BT_H2B_ATN); | 581 | BT_CONTROL(BT_H2B_ATN); |
467 | bt->state = BT_STATE_RESET3; | 582 | bt->timeout = BT_RESET_DELAY * 1000000; |
468 | break; | 583 | BT_STATE_CHANGE(BT_STATE_RESET3, |
584 | SI_SM_CALL_WITH_DELAY); | ||
469 | 585 | ||
470 | case BT_STATE_RESET3: | 586 | case BT_STATE_RESET3: /* Hold off everything for a bit */ |
471 | if (bt->timeout > 0) | 587 | if (bt->timeout > 0) |
472 | return SI_SM_CALL_WITH_DELAY; | 588 | return SI_SM_CALL_WITH_DELAY; |
473 | bt->state = BT_STATE_RESTART; /* printk in debug modes */ | 589 | drain_BMC2HOST(bt); |
474 | break; | 590 | BT_STATE_CHANGE(BT_STATE_RESTART, |
591 | SI_SM_CALL_WITH_DELAY); | ||
475 | 592 | ||
476 | case BT_STATE_RESTART: /* don't reset retries! */ | 593 | case BT_STATE_RESTART: /* don't reset retries or seq! */ |
477 | reset_flags(bt); | ||
478 | bt->write_data[2] = ++bt->seq; | ||
479 | bt->read_count = 0; | 594 | bt->read_count = 0; |
480 | bt->nonzero_status = 0; | 595 | bt->nonzero_status = 0; |
481 | bt->timeout = BT_NORMAL_TIMEOUT; | 596 | bt->timeout = bt->BT_CAP_req2rsp; |
482 | bt->state = BT_STATE_XACTION_START; | 597 | BT_STATE_CHANGE(BT_STATE_XACTION_START, |
483 | break; | 598 | SI_SM_CALL_WITH_DELAY); |
484 | 599 | ||
485 | default: /* HOSED is supposed to be caught much earlier */ | 600 | /* Get BT Capabilities, using timing of upper level state machine. |
486 | error_recovery(bt, "internal logic error"); | 601 | Set outreqs to prevent infinite loop on timeout. */ |
487 | break; | 602 | case BT_STATE_CAPABILITIES_BEGIN: |
488 | } | 603 | bt->BT_CAP_outreqs = 1; |
489 | return SI_SM_CALL_WITH_DELAY; | 604 | { |
605 | unsigned char GetBT_CAP[] = { 0x18, 0x36 }; | ||
606 | bt->state = BT_STATE_IDLE; | ||
607 | bt_start_transaction(bt, GetBT_CAP, sizeof(GetBT_CAP)); | ||
608 | } | ||
609 | bt->complete = BT_STATE_CAPABILITIES_END; | ||
610 | BT_STATE_CHANGE(BT_STATE_XACTION_START, | ||
611 | SI_SM_CALL_WITH_DELAY); | ||
612 | |||
613 | case BT_STATE_CAPABILITIES_END: | ||
614 | i = bt_get_result(bt, BT_CAP, sizeof(BT_CAP)); | ||
615 | bt_init_data(bt, bt->io); | ||
616 | if ((i == 8) && !BT_CAP[2]) { | ||
617 | bt->BT_CAP_outreqs = BT_CAP[3]; | ||
618 | bt->BT_CAP_req2rsp = BT_CAP[6] * 1000000; | ||
619 | bt->BT_CAP_retries = BT_CAP[7]; | ||
620 | } else | ||
621 | printk(KERN_WARNING "IPMI BT: using default values\n"); | ||
622 | if (!bt->BT_CAP_outreqs) | ||
623 | bt->BT_CAP_outreqs = 1; | ||
624 | printk(KERN_WARNING "IPMI BT: req2rsp=%ld secs retries=%d\n", | ||
625 | bt->BT_CAP_req2rsp / 1000000L, bt->BT_CAP_retries); | ||
626 | bt->timeout = bt->BT_CAP_req2rsp; | ||
627 | return SI_SM_CALL_WITHOUT_DELAY; | ||
628 | |||
629 | default: /* should never occur */ | ||
630 | return error_recovery(bt, | ||
631 | status, | ||
632 | IPMI_ERR_UNSPECIFIED); | ||
633 | } | ||
634 | return SI_SM_CALL_WITH_DELAY; | ||
490 | } | 635 | } |
491 | 636 | ||
492 | static int bt_detect(struct si_sm_data *bt) | 637 | static int bt_detect(struct si_sm_data *bt) |
@@ -497,7 +642,7 @@ static int bt_detect(struct si_sm_data *bt) | |||
497 | test that first. The calling routine uses negative logic. */ | 642 | test that first. The calling routine uses negative logic. */ |
498 | 643 | ||
499 | if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) | 644 | if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) |
500 | return 1; | 645 | return 1; |
501 | reset_flags(bt); | 646 | reset_flags(bt); |
502 | return 0; | 647 | return 0; |
503 | } | 648 | } |
@@ -513,11 +658,11 @@ static int bt_size(void) | |||
513 | 658 | ||
514 | struct si_sm_handlers bt_smi_handlers = | 659 | struct si_sm_handlers bt_smi_handlers = |
515 | { | 660 | { |
516 | .init_data = bt_init_data, | 661 | .init_data = bt_init_data, |
517 | .start_transaction = bt_start_transaction, | 662 | .start_transaction = bt_start_transaction, |
518 | .get_result = bt_get_result, | 663 | .get_result = bt_get_result, |
519 | .event = bt_event, | 664 | .event = bt_event, |
520 | .detect = bt_detect, | 665 | .detect = bt_detect, |
521 | .cleanup = bt_cleanup, | 666 | .cleanup = bt_cleanup, |
522 | .size = bt_size, | 667 | .size = bt_size, |
523 | }; | 668 | }; |
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 81fcf0ce21d1..375d3378eecd 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c | |||
@@ -596,6 +596,31 @@ static int ipmi_ioctl(struct inode *inode, | |||
596 | rv = 0; | 596 | rv = 0; |
597 | break; | 597 | break; |
598 | } | 598 | } |
599 | |||
600 | case IPMICTL_GET_MAINTENANCE_MODE_CMD: | ||
601 | { | ||
602 | int mode; | ||
603 | |||
604 | mode = ipmi_get_maintenance_mode(priv->user); | ||
605 | if (copy_to_user(arg, &mode, sizeof(mode))) { | ||
606 | rv = -EFAULT; | ||
607 | break; | ||
608 | } | ||
609 | rv = 0; | ||
610 | break; | ||
611 | } | ||
612 | |||
613 | case IPMICTL_SET_MAINTENANCE_MODE_CMD: | ||
614 | { | ||
615 | int mode; | ||
616 | |||
617 | if (copy_from_user(&mode, arg, sizeof(mode))) { | ||
618 | rv = -EFAULT; | ||
619 | break; | ||
620 | } | ||
621 | rv = ipmi_set_maintenance_mode(priv->user, mode); | ||
622 | break; | ||
623 | } | ||
599 | } | 624 | } |
600 | 625 | ||
601 | return rv; | 626 | return rv; |
diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c index 2062675f9e99..c1b8228cb7b6 100644 --- a/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/drivers/char/ipmi/ipmi_kcs_sm.c | |||
@@ -93,8 +93,8 @@ enum kcs_states { | |||
93 | state machine. */ | 93 | state machine. */ |
94 | }; | 94 | }; |
95 | 95 | ||
96 | #define MAX_KCS_READ_SIZE 80 | 96 | #define MAX_KCS_READ_SIZE IPMI_MAX_MSG_LENGTH |
97 | #define MAX_KCS_WRITE_SIZE 80 | 97 | #define MAX_KCS_WRITE_SIZE IPMI_MAX_MSG_LENGTH |
98 | 98 | ||
99 | /* Timeouts in microseconds. */ | 99 | /* Timeouts in microseconds. */ |
100 | #define IBF_RETRY_TIMEOUT 1000000 | 100 | #define IBF_RETRY_TIMEOUT 1000000 |
@@ -261,12 +261,14 @@ static int start_kcs_transaction(struct si_sm_data *kcs, unsigned char *data, | |||
261 | { | 261 | { |
262 | unsigned int i; | 262 | unsigned int i; |
263 | 263 | ||
264 | if ((size < 2) || (size > MAX_KCS_WRITE_SIZE)) { | 264 | if (size < 2) |
265 | return -1; | 265 | return IPMI_REQ_LEN_INVALID_ERR; |
266 | } | 266 | if (size > MAX_KCS_WRITE_SIZE) |
267 | if ((kcs->state != KCS_IDLE) && (kcs->state != KCS_HOSED)) { | 267 | return IPMI_REQ_LEN_EXCEEDED_ERR; |
268 | return -2; | 268 | |
269 | } | 269 | if ((kcs->state != KCS_IDLE) && (kcs->state != KCS_HOSED)) |
270 | return IPMI_NOT_IN_MY_STATE_ERR; | ||
271 | |||
270 | if (kcs_debug & KCS_DEBUG_MSG) { | 272 | if (kcs_debug & KCS_DEBUG_MSG) { |
271 | printk(KERN_DEBUG "start_kcs_transaction -"); | 273 | printk(KERN_DEBUG "start_kcs_transaction -"); |
272 | for (i = 0; i < size; i ++) { | 274 | for (i = 0; i < size; i ++) { |
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 34a4fd13fa81..5703ee28e1cc 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c | |||
@@ -48,7 +48,7 @@ | |||
48 | 48 | ||
49 | #define PFX "IPMI message handler: " | 49 | #define PFX "IPMI message handler: " |
50 | 50 | ||
51 | #define IPMI_DRIVER_VERSION "39.0" | 51 | #define IPMI_DRIVER_VERSION "39.1" |
52 | 52 | ||
53 | static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); | 53 | static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); |
54 | static int ipmi_init_msghandler(void); | 54 | static int ipmi_init_msghandler(void); |
@@ -59,6 +59,9 @@ static int initialized = 0; | |||
59 | static struct proc_dir_entry *proc_ipmi_root = NULL; | 59 | static struct proc_dir_entry *proc_ipmi_root = NULL; |
60 | #endif /* CONFIG_PROC_FS */ | 60 | #endif /* CONFIG_PROC_FS */ |
61 | 61 | ||
62 | /* Remain in auto-maintenance mode for this amount of time (in ms). */ | ||
63 | #define IPMI_MAINTENANCE_MODE_TIMEOUT 30000 | ||
64 | |||
62 | #define MAX_EVENTS_IN_QUEUE 25 | 65 | #define MAX_EVENTS_IN_QUEUE 25 |
63 | 66 | ||
64 | /* Don't let a message sit in a queue forever, always time it with at lest | 67 | /* Don't let a message sit in a queue forever, always time it with at lest |
@@ -193,17 +196,28 @@ struct ipmi_smi | |||
193 | 196 | ||
194 | struct kref refcount; | 197 | struct kref refcount; |
195 | 198 | ||
199 | /* Used for a list of interfaces. */ | ||
200 | struct list_head link; | ||
201 | |||
196 | /* The list of upper layers that are using me. seq_lock | 202 | /* The list of upper layers that are using me. seq_lock |
197 | * protects this. */ | 203 | * protects this. */ |
198 | struct list_head users; | 204 | struct list_head users; |
199 | 205 | ||
206 | /* Information to supply to users. */ | ||
207 | unsigned char ipmi_version_major; | ||
208 | unsigned char ipmi_version_minor; | ||
209 | |||
200 | /* Used for wake ups at startup. */ | 210 | /* Used for wake ups at startup. */ |
201 | wait_queue_head_t waitq; | 211 | wait_queue_head_t waitq; |
202 | 212 | ||
203 | struct bmc_device *bmc; | 213 | struct bmc_device *bmc; |
204 | char *my_dev_name; | 214 | char *my_dev_name; |
215 | char *sysfs_name; | ||
205 | 216 | ||
206 | /* This is the lower-layer's sender routine. */ | 217 | /* This is the lower-layer's sender routine. Note that you |
218 | * must either be holding the ipmi_interfaces_mutex or be in | ||
219 | * an umpreemptible region to use this. You must fetch the | ||
220 | * value into a local variable and make sure it is not NULL. */ | ||
207 | struct ipmi_smi_handlers *handlers; | 221 | struct ipmi_smi_handlers *handlers; |
208 | void *send_info; | 222 | void *send_info; |
209 | 223 | ||
@@ -242,6 +256,7 @@ struct ipmi_smi | |||
242 | spinlock_t events_lock; /* For dealing with event stuff. */ | 256 | spinlock_t events_lock; /* For dealing with event stuff. */ |
243 | struct list_head waiting_events; | 257 | struct list_head waiting_events; |
244 | unsigned int waiting_events_count; /* How many events in queue? */ | 258 | unsigned int waiting_events_count; /* How many events in queue? */ |
259 | int delivering_events; | ||
245 | 260 | ||
246 | /* The event receiver for my BMC, only really used at panic | 261 | /* The event receiver for my BMC, only really used at panic |
247 | shutdown as a place to store this. */ | 262 | shutdown as a place to store this. */ |
@@ -250,6 +265,12 @@ struct ipmi_smi | |||
250 | unsigned char local_sel_device; | 265 | unsigned char local_sel_device; |
251 | unsigned char local_event_generator; | 266 | unsigned char local_event_generator; |
252 | 267 | ||
268 | /* For handling of maintenance mode. */ | ||
269 | int maintenance_mode; | ||
270 | int maintenance_mode_enable; | ||
271 | int auto_maintenance_timeout; | ||
272 | spinlock_t maintenance_mode_lock; /* Used in a timer... */ | ||
273 | |||
253 | /* A cheap hack, if this is non-null and a message to an | 274 | /* A cheap hack, if this is non-null and a message to an |
254 | interface comes in with a NULL user, call this routine with | 275 | interface comes in with a NULL user, call this routine with |
255 | it. Note that the message will still be freed by the | 276 | it. Note that the message will still be freed by the |
@@ -338,13 +359,6 @@ struct ipmi_smi | |||
338 | }; | 359 | }; |
339 | #define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev) | 360 | #define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev) |
340 | 361 | ||
341 | /* Used to mark an interface entry that cannot be used but is not a | ||
342 | * free entry, either, primarily used at creation and deletion time so | ||
343 | * a slot doesn't get reused too quickly. */ | ||
344 | #define IPMI_INVALID_INTERFACE_ENTRY ((ipmi_smi_t) ((long) 1)) | ||
345 | #define IPMI_INVALID_INTERFACE(i) (((i) == NULL) \ | ||
346 | || (i == IPMI_INVALID_INTERFACE_ENTRY)) | ||
347 | |||
348 | /** | 362 | /** |
349 | * The driver model view of the IPMI messaging driver. | 363 | * The driver model view of the IPMI messaging driver. |
350 | */ | 364 | */ |
@@ -354,16 +368,13 @@ static struct device_driver ipmidriver = { | |||
354 | }; | 368 | }; |
355 | static DEFINE_MUTEX(ipmidriver_mutex); | 369 | static DEFINE_MUTEX(ipmidriver_mutex); |
356 | 370 | ||
357 | #define MAX_IPMI_INTERFACES 4 | 371 | static struct list_head ipmi_interfaces = LIST_HEAD_INIT(ipmi_interfaces); |
358 | static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES]; | 372 | static DEFINE_MUTEX(ipmi_interfaces_mutex); |
359 | |||
360 | /* Directly protects the ipmi_interfaces data structure. */ | ||
361 | static DEFINE_SPINLOCK(interfaces_lock); | ||
362 | 373 | ||
363 | /* List of watchers that want to know when smi's are added and | 374 | /* List of watchers that want to know when smi's are added and |
364 | deleted. */ | 375 | deleted. */ |
365 | static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers); | 376 | static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers); |
366 | static DECLARE_RWSEM(smi_watchers_sem); | 377 | static DEFINE_MUTEX(smi_watchers_mutex); |
367 | 378 | ||
368 | 379 | ||
369 | static void free_recv_msg_list(struct list_head *q) | 380 | static void free_recv_msg_list(struct list_head *q) |
@@ -376,13 +387,23 @@ static void free_recv_msg_list(struct list_head *q) | |||
376 | } | 387 | } |
377 | } | 388 | } |
378 | 389 | ||
390 | static void free_smi_msg_list(struct list_head *q) | ||
391 | { | ||
392 | struct ipmi_smi_msg *msg, *msg2; | ||
393 | |||
394 | list_for_each_entry_safe(msg, msg2, q, link) { | ||
395 | list_del(&msg->link); | ||
396 | ipmi_free_smi_msg(msg); | ||
397 | } | ||
398 | } | ||
399 | |||
379 | static void clean_up_interface_data(ipmi_smi_t intf) | 400 | static void clean_up_interface_data(ipmi_smi_t intf) |
380 | { | 401 | { |
381 | int i; | 402 | int i; |
382 | struct cmd_rcvr *rcvr, *rcvr2; | 403 | struct cmd_rcvr *rcvr, *rcvr2; |
383 | struct list_head list; | 404 | struct list_head list; |
384 | 405 | ||
385 | free_recv_msg_list(&intf->waiting_msgs); | 406 | free_smi_msg_list(&intf->waiting_msgs); |
386 | free_recv_msg_list(&intf->waiting_events); | 407 | free_recv_msg_list(&intf->waiting_events); |
387 | 408 | ||
388 | /* Wholesale remove all the entries from the list in the | 409 | /* Wholesale remove all the entries from the list in the |
@@ -413,48 +434,84 @@ static void intf_free(struct kref *ref) | |||
413 | kfree(intf); | 434 | kfree(intf); |
414 | } | 435 | } |
415 | 436 | ||
437 | struct watcher_entry { | ||
438 | int intf_num; | ||
439 | ipmi_smi_t intf; | ||
440 | struct list_head link; | ||
441 | }; | ||
442 | |||
416 | int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher) | 443 | int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher) |
417 | { | 444 | { |
418 | int i; | 445 | ipmi_smi_t intf; |
419 | unsigned long flags; | 446 | struct list_head to_deliver = LIST_HEAD_INIT(to_deliver); |
447 | struct watcher_entry *e, *e2; | ||
420 | 448 | ||
421 | down_write(&smi_watchers_sem); | 449 | mutex_lock(&smi_watchers_mutex); |
422 | list_add(&(watcher->link), &smi_watchers); | 450 | |
423 | up_write(&smi_watchers_sem); | 451 | mutex_lock(&ipmi_interfaces_mutex); |
424 | spin_lock_irqsave(&interfaces_lock, flags); | 452 | |
425 | for (i = 0; i < MAX_IPMI_INTERFACES; i++) { | 453 | /* Build a list of things to deliver. */ |
426 | ipmi_smi_t intf = ipmi_interfaces[i]; | 454 | list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { |
427 | if (IPMI_INVALID_INTERFACE(intf)) | 455 | if (intf->intf_num == -1) |
428 | continue; | 456 | continue; |
429 | spin_unlock_irqrestore(&interfaces_lock, flags); | 457 | e = kmalloc(sizeof(*e), GFP_KERNEL); |
430 | watcher->new_smi(i, intf->si_dev); | 458 | if (!e) |
431 | spin_lock_irqsave(&interfaces_lock, flags); | 459 | goto out_err; |
460 | kref_get(&intf->refcount); | ||
461 | e->intf = intf; | ||
462 | e->intf_num = intf->intf_num; | ||
463 | list_add_tail(&e->link, &to_deliver); | ||
464 | } | ||
465 | |||
466 | /* We will succeed, so add it to the list. */ | ||
467 | list_add(&watcher->link, &smi_watchers); | ||
468 | |||
469 | mutex_unlock(&ipmi_interfaces_mutex); | ||
470 | |||
471 | list_for_each_entry_safe(e, e2, &to_deliver, link) { | ||
472 | list_del(&e->link); | ||
473 | watcher->new_smi(e->intf_num, e->intf->si_dev); | ||
474 | kref_put(&e->intf->refcount, intf_free); | ||
475 | kfree(e); | ||
432 | } | 476 | } |
433 | spin_unlock_irqrestore(&interfaces_lock, flags); | 477 | |
478 | mutex_unlock(&smi_watchers_mutex); | ||
479 | |||
434 | return 0; | 480 | return 0; |
481 | |||
482 | out_err: | ||
483 | mutex_unlock(&ipmi_interfaces_mutex); | ||
484 | mutex_unlock(&smi_watchers_mutex); | ||
485 | list_for_each_entry_safe(e, e2, &to_deliver, link) { | ||
486 | list_del(&e->link); | ||
487 | kref_put(&e->intf->refcount, intf_free); | ||
488 | kfree(e); | ||
489 | } | ||
490 | return -ENOMEM; | ||
435 | } | 491 | } |
436 | 492 | ||
437 | int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher) | 493 | int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher) |
438 | { | 494 | { |
439 | down_write(&smi_watchers_sem); | 495 | mutex_lock(&smi_watchers_mutex); |
440 | list_del(&(watcher->link)); | 496 | list_del(&(watcher->link)); |
441 | up_write(&smi_watchers_sem); | 497 | mutex_unlock(&smi_watchers_mutex); |
442 | return 0; | 498 | return 0; |
443 | } | 499 | } |
444 | 500 | ||
501 | /* | ||
502 | * Must be called with smi_watchers_mutex held. | ||
503 | */ | ||
445 | static void | 504 | static void |
446 | call_smi_watchers(int i, struct device *dev) | 505 | call_smi_watchers(int i, struct device *dev) |
447 | { | 506 | { |
448 | struct ipmi_smi_watcher *w; | 507 | struct ipmi_smi_watcher *w; |
449 | 508 | ||
450 | down_read(&smi_watchers_sem); | ||
451 | list_for_each_entry(w, &smi_watchers, link) { | 509 | list_for_each_entry(w, &smi_watchers, link) { |
452 | if (try_module_get(w->owner)) { | 510 | if (try_module_get(w->owner)) { |
453 | w->new_smi(i, dev); | 511 | w->new_smi(i, dev); |
454 | module_put(w->owner); | 512 | module_put(w->owner); |
455 | } | 513 | } |
456 | } | 514 | } |
457 | up_read(&smi_watchers_sem); | ||
458 | } | 515 | } |
459 | 516 | ||
460 | static int | 517 | static int |
@@ -580,6 +637,17 @@ static void deliver_response(struct ipmi_recv_msg *msg) | |||
580 | } | 637 | } |
581 | } | 638 | } |
582 | 639 | ||
640 | static void | ||
641 | deliver_err_response(struct ipmi_recv_msg *msg, int err) | ||
642 | { | ||
643 | msg->recv_type = IPMI_RESPONSE_RECV_TYPE; | ||
644 | msg->msg_data[0] = err; | ||
645 | msg->msg.netfn |= 1; /* Convert to a response. */ | ||
646 | msg->msg.data_len = 1; | ||
647 | msg->msg.data = msg->msg_data; | ||
648 | deliver_response(msg); | ||
649 | } | ||
650 | |||
583 | /* Find the next sequence number not being used and add the given | 651 | /* Find the next sequence number not being used and add the given |
584 | message with the given timeout to the sequence table. This must be | 652 | message with the given timeout to the sequence table. This must be |
585 | called with the interface's seq_lock held. */ | 653 | called with the interface's seq_lock held. */ |
@@ -717,14 +785,8 @@ static int intf_err_seq(ipmi_smi_t intf, | |||
717 | } | 785 | } |
718 | spin_unlock_irqrestore(&(intf->seq_lock), flags); | 786 | spin_unlock_irqrestore(&(intf->seq_lock), flags); |
719 | 787 | ||
720 | if (msg) { | 788 | if (msg) |
721 | msg->recv_type = IPMI_RESPONSE_RECV_TYPE; | 789 | deliver_err_response(msg, err); |
722 | msg->msg_data[0] = err; | ||
723 | msg->msg.netfn |= 1; /* Convert to a response. */ | ||
724 | msg->msg.data_len = 1; | ||
725 | msg->msg.data = msg->msg_data; | ||
726 | deliver_response(msg); | ||
727 | } | ||
728 | 790 | ||
729 | return rv; | 791 | return rv; |
730 | } | 792 | } |
@@ -766,17 +828,18 @@ int ipmi_create_user(unsigned int if_num, | |||
766 | if (!new_user) | 828 | if (!new_user) |
767 | return -ENOMEM; | 829 | return -ENOMEM; |
768 | 830 | ||
769 | spin_lock_irqsave(&interfaces_lock, flags); | 831 | mutex_lock(&ipmi_interfaces_mutex); |
770 | intf = ipmi_interfaces[if_num]; | 832 | list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { |
771 | if ((if_num >= MAX_IPMI_INTERFACES) || IPMI_INVALID_INTERFACE(intf)) { | 833 | if (intf->intf_num == if_num) |
772 | spin_unlock_irqrestore(&interfaces_lock, flags); | 834 | goto found; |
773 | rv = -EINVAL; | ||
774 | goto out_kfree; | ||
775 | } | 835 | } |
836 | /* Not found, return an error */ | ||
837 | rv = -EINVAL; | ||
838 | goto out_kfree; | ||
776 | 839 | ||
840 | found: | ||
777 | /* Note that each existing user holds a refcount to the interface. */ | 841 | /* Note that each existing user holds a refcount to the interface. */ |
778 | kref_get(&intf->refcount); | 842 | kref_get(&intf->refcount); |
779 | spin_unlock_irqrestore(&interfaces_lock, flags); | ||
780 | 843 | ||
781 | kref_init(&new_user->refcount); | 844 | kref_init(&new_user->refcount); |
782 | new_user->handler = handler; | 845 | new_user->handler = handler; |
@@ -797,6 +860,10 @@ int ipmi_create_user(unsigned int if_num, | |||
797 | } | 860 | } |
798 | } | 861 | } |
799 | 862 | ||
863 | /* Hold the lock so intf->handlers is guaranteed to be good | ||
864 | * until now */ | ||
865 | mutex_unlock(&ipmi_interfaces_mutex); | ||
866 | |||
800 | new_user->valid = 1; | 867 | new_user->valid = 1; |
801 | spin_lock_irqsave(&intf->seq_lock, flags); | 868 | spin_lock_irqsave(&intf->seq_lock, flags); |
802 | list_add_rcu(&new_user->link, &intf->users); | 869 | list_add_rcu(&new_user->link, &intf->users); |
@@ -807,6 +874,7 @@ int ipmi_create_user(unsigned int if_num, | |||
807 | out_kref: | 874 | out_kref: |
808 | kref_put(&intf->refcount, intf_free); | 875 | kref_put(&intf->refcount, intf_free); |
809 | out_kfree: | 876 | out_kfree: |
877 | mutex_unlock(&ipmi_interfaces_mutex); | ||
810 | kfree(new_user); | 878 | kfree(new_user); |
811 | return rv; | 879 | return rv; |
812 | } | 880 | } |
@@ -836,6 +904,7 @@ int ipmi_destroy_user(ipmi_user_t user) | |||
836 | && (intf->seq_table[i].recv_msg->user == user)) | 904 | && (intf->seq_table[i].recv_msg->user == user)) |
837 | { | 905 | { |
838 | intf->seq_table[i].inuse = 0; | 906 | intf->seq_table[i].inuse = 0; |
907 | ipmi_free_recv_msg(intf->seq_table[i].recv_msg); | ||
839 | } | 908 | } |
840 | } | 909 | } |
841 | spin_unlock_irqrestore(&intf->seq_lock, flags); | 910 | spin_unlock_irqrestore(&intf->seq_lock, flags); |
@@ -862,9 +931,13 @@ int ipmi_destroy_user(ipmi_user_t user) | |||
862 | kfree(rcvr); | 931 | kfree(rcvr); |
863 | } | 932 | } |
864 | 933 | ||
865 | module_put(intf->handlers->owner); | 934 | mutex_lock(&ipmi_interfaces_mutex); |
866 | if (intf->handlers->dec_usecount) | 935 | if (intf->handlers) { |
867 | intf->handlers->dec_usecount(intf->send_info); | 936 | module_put(intf->handlers->owner); |
937 | if (intf->handlers->dec_usecount) | ||
938 | intf->handlers->dec_usecount(intf->send_info); | ||
939 | } | ||
940 | mutex_unlock(&ipmi_interfaces_mutex); | ||
868 | 941 | ||
869 | kref_put(&intf->refcount, intf_free); | 942 | kref_put(&intf->refcount, intf_free); |
870 | 943 | ||
@@ -877,8 +950,8 @@ void ipmi_get_version(ipmi_user_t user, | |||
877 | unsigned char *major, | 950 | unsigned char *major, |
878 | unsigned char *minor) | 951 | unsigned char *minor) |
879 | { | 952 | { |
880 | *major = ipmi_version_major(&user->intf->bmc->id); | 953 | *major = user->intf->ipmi_version_major; |
881 | *minor = ipmi_version_minor(&user->intf->bmc->id); | 954 | *minor = user->intf->ipmi_version_minor; |
882 | } | 955 | } |
883 | 956 | ||
884 | int ipmi_set_my_address(ipmi_user_t user, | 957 | int ipmi_set_my_address(ipmi_user_t user, |
@@ -921,6 +994,65 @@ int ipmi_get_my_LUN(ipmi_user_t user, | |||
921 | return 0; | 994 | return 0; |
922 | } | 995 | } |
923 | 996 | ||
997 | int ipmi_get_maintenance_mode(ipmi_user_t user) | ||
998 | { | ||
999 | int mode; | ||
1000 | unsigned long flags; | ||
1001 | |||
1002 | spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags); | ||
1003 | mode = user->intf->maintenance_mode; | ||
1004 | spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags); | ||
1005 | |||
1006 | return mode; | ||
1007 | } | ||
1008 | EXPORT_SYMBOL(ipmi_get_maintenance_mode); | ||
1009 | |||
1010 | static void maintenance_mode_update(ipmi_smi_t intf) | ||
1011 | { | ||
1012 | if (intf->handlers->set_maintenance_mode) | ||
1013 | intf->handlers->set_maintenance_mode( | ||
1014 | intf->send_info, intf->maintenance_mode_enable); | ||
1015 | } | ||
1016 | |||
1017 | int ipmi_set_maintenance_mode(ipmi_user_t user, int mode) | ||
1018 | { | ||
1019 | int rv = 0; | ||
1020 | unsigned long flags; | ||
1021 | ipmi_smi_t intf = user->intf; | ||
1022 | |||
1023 | spin_lock_irqsave(&intf->maintenance_mode_lock, flags); | ||
1024 | if (intf->maintenance_mode != mode) { | ||
1025 | switch (mode) { | ||
1026 | case IPMI_MAINTENANCE_MODE_AUTO: | ||
1027 | intf->maintenance_mode = mode; | ||
1028 | intf->maintenance_mode_enable | ||
1029 | = (intf->auto_maintenance_timeout > 0); | ||
1030 | break; | ||
1031 | |||
1032 | case IPMI_MAINTENANCE_MODE_OFF: | ||
1033 | intf->maintenance_mode = mode; | ||
1034 | intf->maintenance_mode_enable = 0; | ||
1035 | break; | ||
1036 | |||
1037 | case IPMI_MAINTENANCE_MODE_ON: | ||
1038 | intf->maintenance_mode = mode; | ||
1039 | intf->maintenance_mode_enable = 1; | ||
1040 | break; | ||
1041 | |||
1042 | default: | ||
1043 | rv = -EINVAL; | ||
1044 | goto out_unlock; | ||
1045 | } | ||
1046 | |||
1047 | maintenance_mode_update(intf); | ||
1048 | } | ||
1049 | out_unlock: | ||
1050 | spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags); | ||
1051 | |||
1052 | return rv; | ||
1053 | } | ||
1054 | EXPORT_SYMBOL(ipmi_set_maintenance_mode); | ||
1055 | |||
924 | int ipmi_set_gets_events(ipmi_user_t user, int val) | 1056 | int ipmi_set_gets_events(ipmi_user_t user, int val) |
925 | { | 1057 | { |
926 | unsigned long flags; | 1058 | unsigned long flags; |
@@ -933,20 +1065,33 @@ int ipmi_set_gets_events(ipmi_user_t user, int val) | |||
933 | spin_lock_irqsave(&intf->events_lock, flags); | 1065 | spin_lock_irqsave(&intf->events_lock, flags); |
934 | user->gets_events = val; | 1066 | user->gets_events = val; |
935 | 1067 | ||
936 | if (val) { | 1068 | if (intf->delivering_events) |
937 | /* Deliver any queued events. */ | 1069 | /* |
1070 | * Another thread is delivering events for this, so | ||
1071 | * let it handle any new events. | ||
1072 | */ | ||
1073 | goto out; | ||
1074 | |||
1075 | /* Deliver any queued events. */ | ||
1076 | while (user->gets_events && !list_empty(&intf->waiting_events)) { | ||
938 | list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link) | 1077 | list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link) |
939 | list_move_tail(&msg->link, &msgs); | 1078 | list_move_tail(&msg->link, &msgs); |
940 | intf->waiting_events_count = 0; | 1079 | intf->waiting_events_count = 0; |
941 | } | ||
942 | 1080 | ||
943 | /* Hold the events lock while doing this to preserve order. */ | 1081 | intf->delivering_events = 1; |
944 | list_for_each_entry_safe(msg, msg2, &msgs, link) { | 1082 | spin_unlock_irqrestore(&intf->events_lock, flags); |
945 | msg->user = user; | 1083 | |
946 | kref_get(&user->refcount); | 1084 | list_for_each_entry_safe(msg, msg2, &msgs, link) { |
947 | deliver_response(msg); | 1085 | msg->user = user; |
1086 | kref_get(&user->refcount); | ||
1087 | deliver_response(msg); | ||
1088 | } | ||
1089 | |||
1090 | spin_lock_irqsave(&intf->events_lock, flags); | ||
1091 | intf->delivering_events = 0; | ||
948 | } | 1092 | } |
949 | 1093 | ||
1094 | out: | ||
950 | spin_unlock_irqrestore(&intf->events_lock, flags); | 1095 | spin_unlock_irqrestore(&intf->events_lock, flags); |
951 | 1096 | ||
952 | return 0; | 1097 | return 0; |
@@ -1057,7 +1202,8 @@ int ipmi_unregister_for_cmd(ipmi_user_t user, | |||
1057 | void ipmi_user_set_run_to_completion(ipmi_user_t user, int val) | 1202 | void ipmi_user_set_run_to_completion(ipmi_user_t user, int val) |
1058 | { | 1203 | { |
1059 | ipmi_smi_t intf = user->intf; | 1204 | ipmi_smi_t intf = user->intf; |
1060 | intf->handlers->set_run_to_completion(intf->send_info, val); | 1205 | if (intf->handlers) |
1206 | intf->handlers->set_run_to_completion(intf->send_info, val); | ||
1061 | } | 1207 | } |
1062 | 1208 | ||
1063 | static unsigned char | 1209 | static unsigned char |
@@ -1168,10 +1314,11 @@ static int i_ipmi_request(ipmi_user_t user, | |||
1168 | int retries, | 1314 | int retries, |
1169 | unsigned int retry_time_ms) | 1315 | unsigned int retry_time_ms) |
1170 | { | 1316 | { |
1171 | int rv = 0; | 1317 | int rv = 0; |
1172 | struct ipmi_smi_msg *smi_msg; | 1318 | struct ipmi_smi_msg *smi_msg; |
1173 | struct ipmi_recv_msg *recv_msg; | 1319 | struct ipmi_recv_msg *recv_msg; |
1174 | unsigned long flags; | 1320 | unsigned long flags; |
1321 | struct ipmi_smi_handlers *handlers; | ||
1175 | 1322 | ||
1176 | 1323 | ||
1177 | if (supplied_recv) { | 1324 | if (supplied_recv) { |
@@ -1194,6 +1341,13 @@ static int i_ipmi_request(ipmi_user_t user, | |||
1194 | } | 1341 | } |
1195 | } | 1342 | } |
1196 | 1343 | ||
1344 | rcu_read_lock(); | ||
1345 | handlers = intf->handlers; | ||
1346 | if (!handlers) { | ||
1347 | rv = -ENODEV; | ||
1348 | goto out_err; | ||
1349 | } | ||
1350 | |||
1197 | recv_msg->user = user; | 1351 | recv_msg->user = user; |
1198 | if (user) | 1352 | if (user) |
1199 | kref_get(&user->refcount); | 1353 | kref_get(&user->refcount); |
@@ -1236,6 +1390,24 @@ static int i_ipmi_request(ipmi_user_t user, | |||
1236 | goto out_err; | 1390 | goto out_err; |
1237 | } | 1391 | } |
1238 | 1392 | ||
1393 | if (((msg->netfn == IPMI_NETFN_APP_REQUEST) | ||
1394 | && ((msg->cmd == IPMI_COLD_RESET_CMD) | ||
1395 | || (msg->cmd == IPMI_WARM_RESET_CMD))) | ||
1396 | || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST)) | ||
1397 | { | ||
1398 | spin_lock_irqsave(&intf->maintenance_mode_lock, flags); | ||
1399 | intf->auto_maintenance_timeout | ||
1400 | = IPMI_MAINTENANCE_MODE_TIMEOUT; | ||
1401 | if (!intf->maintenance_mode | ||
1402 | && !intf->maintenance_mode_enable) | ||
1403 | { | ||
1404 | intf->maintenance_mode_enable = 1; | ||
1405 | maintenance_mode_update(intf); | ||
1406 | } | ||
1407 | spin_unlock_irqrestore(&intf->maintenance_mode_lock, | ||
1408 | flags); | ||
1409 | } | ||
1410 | |||
1239 | if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) { | 1411 | if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) { |
1240 | spin_lock_irqsave(&intf->counter_lock, flags); | 1412 | spin_lock_irqsave(&intf->counter_lock, flags); |
1241 | intf->sent_invalid_commands++; | 1413 | intf->sent_invalid_commands++; |
@@ -1510,11 +1682,14 @@ static int i_ipmi_request(ipmi_user_t user, | |||
1510 | printk("\n"); | 1682 | printk("\n"); |
1511 | } | 1683 | } |
1512 | #endif | 1684 | #endif |
1513 | intf->handlers->sender(intf->send_info, smi_msg, priority); | 1685 | |
1686 | handlers->sender(intf->send_info, smi_msg, priority); | ||
1687 | rcu_read_unlock(); | ||
1514 | 1688 | ||
1515 | return 0; | 1689 | return 0; |
1516 | 1690 | ||
1517 | out_err: | 1691 | out_err: |
1692 | rcu_read_unlock(); | ||
1518 | ipmi_free_smi_msg(smi_msg); | 1693 | ipmi_free_smi_msg(smi_msg); |
1519 | ipmi_free_recv_msg(recv_msg); | 1694 | ipmi_free_recv_msg(recv_msg); |
1520 | return rv; | 1695 | return rv; |
@@ -1594,6 +1769,7 @@ int ipmi_request_supply_msgs(ipmi_user_t user, | |||
1594 | -1, 0); | 1769 | -1, 0); |
1595 | } | 1770 | } |
1596 | 1771 | ||
1772 | #ifdef CONFIG_PROC_FS | ||
1597 | static int ipmb_file_read_proc(char *page, char **start, off_t off, | 1773 | static int ipmb_file_read_proc(char *page, char **start, off_t off, |
1598 | int count, int *eof, void *data) | 1774 | int count, int *eof, void *data) |
1599 | { | 1775 | { |
@@ -1682,6 +1858,7 @@ static int stat_file_read_proc(char *page, char **start, off_t off, | |||
1682 | 1858 | ||
1683 | return (out - ((char *) page)); | 1859 | return (out - ((char *) page)); |
1684 | } | 1860 | } |
1861 | #endif /* CONFIG_PROC_FS */ | ||
1685 | 1862 | ||
1686 | int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, | 1863 | int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, |
1687 | read_proc_t *read_proc, write_proc_t *write_proc, | 1864 | 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) | |||
1807 | struct bmc_device *bmc = dev_get_drvdata(dev); | 1984 | struct bmc_device *bmc = dev_get_drvdata(dev); |
1808 | 1985 | ||
1809 | return (bmc->id.product_id == id->product_id | 1986 | return (bmc->id.product_id == id->product_id |
1810 | && bmc->id.product_id == id->product_id | ||
1811 | && bmc->id.device_id == id->device_id); | 1987 | && bmc->id.device_id == id->device_id); |
1812 | } | 1988 | } |
1813 | 1989 | ||
1814 | static struct bmc_device *ipmi_find_bmc_prod_dev_id( | 1990 | static struct bmc_device *ipmi_find_bmc_prod_dev_id( |
1815 | struct device_driver *drv, | 1991 | struct device_driver *drv, |
1816 | unsigned char product_id, unsigned char device_id) | 1992 | unsigned int product_id, unsigned char device_id) |
1817 | { | 1993 | { |
1818 | struct prod_dev_id id = { | 1994 | struct prod_dev_id id = { |
1819 | .product_id = product_id, | 1995 | .product_id = product_id, |
@@ -1844,7 +2020,7 @@ static ssize_t provides_dev_sdrs_show(struct device *dev, | |||
1844 | struct bmc_device *bmc = dev_get_drvdata(dev); | 2020 | struct bmc_device *bmc = dev_get_drvdata(dev); |
1845 | 2021 | ||
1846 | return snprintf(buf, 10, "%u\n", | 2022 | return snprintf(buf, 10, "%u\n", |
1847 | bmc->id.device_revision && 0x80 >> 7); | 2023 | (bmc->id.device_revision & 0x80) >> 7); |
1848 | } | 2024 | } |
1849 | 2025 | ||
1850 | static ssize_t revision_show(struct device *dev, struct device_attribute *attr, | 2026 | 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, | |||
1853 | struct bmc_device *bmc = dev_get_drvdata(dev); | 2029 | struct bmc_device *bmc = dev_get_drvdata(dev); |
1854 | 2030 | ||
1855 | return snprintf(buf, 20, "%u\n", | 2031 | return snprintf(buf, 20, "%u\n", |
1856 | bmc->id.device_revision && 0x0F); | 2032 | bmc->id.device_revision & 0x0F); |
1857 | } | 2033 | } |
1858 | 2034 | ||
1859 | static ssize_t firmware_rev_show(struct device *dev, | 2035 | 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, | |||
1930 | 2106 | ||
1931 | static void remove_files(struct bmc_device *bmc) | 2107 | static void remove_files(struct bmc_device *bmc) |
1932 | { | 2108 | { |
2109 | if (!bmc->dev) | ||
2110 | return; | ||
2111 | |||
1933 | device_remove_file(&bmc->dev->dev, | 2112 | device_remove_file(&bmc->dev->dev, |
1934 | &bmc->device_id_attr); | 2113 | &bmc->device_id_attr); |
1935 | device_remove_file(&bmc->dev->dev, | 2114 | device_remove_file(&bmc->dev->dev, |
@@ -1963,7 +2142,8 @@ cleanup_bmc_device(struct kref *ref) | |||
1963 | bmc = container_of(ref, struct bmc_device, refcount); | 2142 | bmc = container_of(ref, struct bmc_device, refcount); |
1964 | 2143 | ||
1965 | remove_files(bmc); | 2144 | remove_files(bmc); |
1966 | platform_device_unregister(bmc->dev); | 2145 | if (bmc->dev) |
2146 | platform_device_unregister(bmc->dev); | ||
1967 | kfree(bmc); | 2147 | kfree(bmc); |
1968 | } | 2148 | } |
1969 | 2149 | ||
@@ -1971,7 +2151,11 @@ static void ipmi_bmc_unregister(ipmi_smi_t intf) | |||
1971 | { | 2151 | { |
1972 | struct bmc_device *bmc = intf->bmc; | 2152 | struct bmc_device *bmc = intf->bmc; |
1973 | 2153 | ||
1974 | sysfs_remove_link(&intf->si_dev->kobj, "bmc"); | 2154 | if (intf->sysfs_name) { |
2155 | sysfs_remove_link(&intf->si_dev->kobj, intf->sysfs_name); | ||
2156 | kfree(intf->sysfs_name); | ||
2157 | intf->sysfs_name = NULL; | ||
2158 | } | ||
1975 | if (intf->my_dev_name) { | 2159 | if (intf->my_dev_name) { |
1976 | sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name); | 2160 | sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name); |
1977 | kfree(intf->my_dev_name); | 2161 | kfree(intf->my_dev_name); |
@@ -1980,6 +2164,7 @@ static void ipmi_bmc_unregister(ipmi_smi_t intf) | |||
1980 | 2164 | ||
1981 | mutex_lock(&ipmidriver_mutex); | 2165 | mutex_lock(&ipmidriver_mutex); |
1982 | kref_put(&bmc->refcount, cleanup_bmc_device); | 2166 | kref_put(&bmc->refcount, cleanup_bmc_device); |
2167 | intf->bmc = NULL; | ||
1983 | mutex_unlock(&ipmidriver_mutex); | 2168 | mutex_unlock(&ipmidriver_mutex); |
1984 | } | 2169 | } |
1985 | 2170 | ||
@@ -1987,6 +2172,56 @@ static int create_files(struct bmc_device *bmc) | |||
1987 | { | 2172 | { |
1988 | int err; | 2173 | int err; |
1989 | 2174 | ||
2175 | bmc->device_id_attr.attr.name = "device_id"; | ||
2176 | bmc->device_id_attr.attr.owner = THIS_MODULE; | ||
2177 | bmc->device_id_attr.attr.mode = S_IRUGO; | ||
2178 | bmc->device_id_attr.show = device_id_show; | ||
2179 | |||
2180 | bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs"; | ||
2181 | bmc->provides_dev_sdrs_attr.attr.owner = THIS_MODULE; | ||
2182 | bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO; | ||
2183 | bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show; | ||
2184 | |||
2185 | bmc->revision_attr.attr.name = "revision"; | ||
2186 | bmc->revision_attr.attr.owner = THIS_MODULE; | ||
2187 | bmc->revision_attr.attr.mode = S_IRUGO; | ||
2188 | bmc->revision_attr.show = revision_show; | ||
2189 | |||
2190 | bmc->firmware_rev_attr.attr.name = "firmware_revision"; | ||
2191 | bmc->firmware_rev_attr.attr.owner = THIS_MODULE; | ||
2192 | bmc->firmware_rev_attr.attr.mode = S_IRUGO; | ||
2193 | bmc->firmware_rev_attr.show = firmware_rev_show; | ||
2194 | |||
2195 | bmc->version_attr.attr.name = "ipmi_version"; | ||
2196 | bmc->version_attr.attr.owner = THIS_MODULE; | ||
2197 | bmc->version_attr.attr.mode = S_IRUGO; | ||
2198 | bmc->version_attr.show = ipmi_version_show; | ||
2199 | |||
2200 | bmc->add_dev_support_attr.attr.name = "additional_device_support"; | ||
2201 | bmc->add_dev_support_attr.attr.owner = THIS_MODULE; | ||
2202 | bmc->add_dev_support_attr.attr.mode = S_IRUGO; | ||
2203 | bmc->add_dev_support_attr.show = add_dev_support_show; | ||
2204 | |||
2205 | bmc->manufacturer_id_attr.attr.name = "manufacturer_id"; | ||
2206 | bmc->manufacturer_id_attr.attr.owner = THIS_MODULE; | ||
2207 | bmc->manufacturer_id_attr.attr.mode = S_IRUGO; | ||
2208 | bmc->manufacturer_id_attr.show = manufacturer_id_show; | ||
2209 | |||
2210 | bmc->product_id_attr.attr.name = "product_id"; | ||
2211 | bmc->product_id_attr.attr.owner = THIS_MODULE; | ||
2212 | bmc->product_id_attr.attr.mode = S_IRUGO; | ||
2213 | bmc->product_id_attr.show = product_id_show; | ||
2214 | |||
2215 | bmc->guid_attr.attr.name = "guid"; | ||
2216 | bmc->guid_attr.attr.owner = THIS_MODULE; | ||
2217 | bmc->guid_attr.attr.mode = S_IRUGO; | ||
2218 | bmc->guid_attr.show = guid_show; | ||
2219 | |||
2220 | bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision"; | ||
2221 | bmc->aux_firmware_rev_attr.attr.owner = THIS_MODULE; | ||
2222 | bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO; | ||
2223 | bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show; | ||
2224 | |||
1990 | err = device_create_file(&bmc->dev->dev, | 2225 | err = device_create_file(&bmc->dev->dev, |
1991 | &bmc->device_id_attr); | 2226 | &bmc->device_id_attr); |
1992 | if (err) goto out; | 2227 | if (err) goto out; |
@@ -2056,7 +2291,8 @@ out: | |||
2056 | return err; | 2291 | return err; |
2057 | } | 2292 | } |
2058 | 2293 | ||
2059 | static int ipmi_bmc_register(ipmi_smi_t intf) | 2294 | static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum, |
2295 | const char *sysfs_name) | ||
2060 | { | 2296 | { |
2061 | int rv; | 2297 | int rv; |
2062 | struct bmc_device *bmc = intf->bmc; | 2298 | struct bmc_device *bmc = intf->bmc; |
@@ -2096,9 +2332,39 @@ static int ipmi_bmc_register(ipmi_smi_t intf) | |||
2096 | bmc->id.product_id, | 2332 | bmc->id.product_id, |
2097 | bmc->id.device_id); | 2333 | bmc->id.device_id); |
2098 | } else { | 2334 | } else { |
2099 | bmc->dev = platform_device_alloc("ipmi_bmc", | 2335 | char name[14]; |
2100 | bmc->id.device_id); | 2336 | unsigned char orig_dev_id = bmc->id.device_id; |
2337 | int warn_printed = 0; | ||
2338 | |||
2339 | snprintf(name, sizeof(name), | ||
2340 | "ipmi_bmc.%4.4x", bmc->id.product_id); | ||
2341 | |||
2342 | while (ipmi_find_bmc_prod_dev_id(&ipmidriver, | ||
2343 | bmc->id.product_id, | ||
2344 | bmc->id.device_id)) | ||
2345 | { | ||
2346 | if (!warn_printed) { | ||
2347 | printk(KERN_WARNING PFX | ||
2348 | "This machine has two different BMCs" | ||
2349 | " with the same product id and device" | ||
2350 | " id. This is an error in the" | ||
2351 | " firmware, but incrementing the" | ||
2352 | " device id to work around the problem." | ||
2353 | " Prod ID = 0x%x, Dev ID = 0x%x\n", | ||
2354 | bmc->id.product_id, bmc->id.device_id); | ||
2355 | warn_printed = 1; | ||
2356 | } | ||
2357 | bmc->id.device_id++; /* Wraps at 255 */ | ||
2358 | if (bmc->id.device_id == orig_dev_id) { | ||
2359 | printk(KERN_ERR PFX | ||
2360 | "Out of device ids!\n"); | ||
2361 | break; | ||
2362 | } | ||
2363 | } | ||
2364 | |||
2365 | bmc->dev = platform_device_alloc(name, bmc->id.device_id); | ||
2101 | if (!bmc->dev) { | 2366 | if (!bmc->dev) { |
2367 | mutex_unlock(&ipmidriver_mutex); | ||
2102 | printk(KERN_ERR | 2368 | printk(KERN_ERR |
2103 | "ipmi_msghandler:" | 2369 | "ipmi_msghandler:" |
2104 | " Unable to allocate platform device\n"); | 2370 | " Unable to allocate platform device\n"); |
@@ -2108,9 +2374,11 @@ static int ipmi_bmc_register(ipmi_smi_t intf) | |||
2108 | dev_set_drvdata(&bmc->dev->dev, bmc); | 2374 | dev_set_drvdata(&bmc->dev->dev, bmc); |
2109 | kref_init(&bmc->refcount); | 2375 | kref_init(&bmc->refcount); |
2110 | 2376 | ||
2111 | rv = platform_device_register(bmc->dev); | 2377 | rv = platform_device_add(bmc->dev); |
2112 | mutex_unlock(&ipmidriver_mutex); | 2378 | mutex_unlock(&ipmidriver_mutex); |
2113 | if (rv) { | 2379 | if (rv) { |
2380 | platform_device_put(bmc->dev); | ||
2381 | bmc->dev = NULL; | ||
2114 | printk(KERN_ERR | 2382 | printk(KERN_ERR |
2115 | "ipmi_msghandler:" | 2383 | "ipmi_msghandler:" |
2116 | " Unable to register bmc device: %d\n", | 2384 | " Unable to register bmc device: %d\n", |
@@ -2120,57 +2388,6 @@ static int ipmi_bmc_register(ipmi_smi_t intf) | |||
2120 | return rv; | 2388 | return rv; |
2121 | } | 2389 | } |
2122 | 2390 | ||
2123 | bmc->device_id_attr.attr.name = "device_id"; | ||
2124 | bmc->device_id_attr.attr.owner = THIS_MODULE; | ||
2125 | bmc->device_id_attr.attr.mode = S_IRUGO; | ||
2126 | bmc->device_id_attr.show = device_id_show; | ||
2127 | |||
2128 | bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs"; | ||
2129 | bmc->provides_dev_sdrs_attr.attr.owner = THIS_MODULE; | ||
2130 | bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO; | ||
2131 | bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show; | ||
2132 | |||
2133 | bmc->revision_attr.attr.name = "revision"; | ||
2134 | bmc->revision_attr.attr.owner = THIS_MODULE; | ||
2135 | bmc->revision_attr.attr.mode = S_IRUGO; | ||
2136 | bmc->revision_attr.show = revision_show; | ||
2137 | |||
2138 | bmc->firmware_rev_attr.attr.name = "firmware_revision"; | ||
2139 | bmc->firmware_rev_attr.attr.owner = THIS_MODULE; | ||
2140 | bmc->firmware_rev_attr.attr.mode = S_IRUGO; | ||
2141 | bmc->firmware_rev_attr.show = firmware_rev_show; | ||
2142 | |||
2143 | bmc->version_attr.attr.name = "ipmi_version"; | ||
2144 | bmc->version_attr.attr.owner = THIS_MODULE; | ||
2145 | bmc->version_attr.attr.mode = S_IRUGO; | ||
2146 | bmc->version_attr.show = ipmi_version_show; | ||
2147 | |||
2148 | bmc->add_dev_support_attr.attr.name | ||
2149 | = "additional_device_support"; | ||
2150 | bmc->add_dev_support_attr.attr.owner = THIS_MODULE; | ||
2151 | bmc->add_dev_support_attr.attr.mode = S_IRUGO; | ||
2152 | bmc->add_dev_support_attr.show = add_dev_support_show; | ||
2153 | |||
2154 | bmc->manufacturer_id_attr.attr.name = "manufacturer_id"; | ||
2155 | bmc->manufacturer_id_attr.attr.owner = THIS_MODULE; | ||
2156 | bmc->manufacturer_id_attr.attr.mode = S_IRUGO; | ||
2157 | bmc->manufacturer_id_attr.show = manufacturer_id_show; | ||
2158 | |||
2159 | bmc->product_id_attr.attr.name = "product_id"; | ||
2160 | bmc->product_id_attr.attr.owner = THIS_MODULE; | ||
2161 | bmc->product_id_attr.attr.mode = S_IRUGO; | ||
2162 | bmc->product_id_attr.show = product_id_show; | ||
2163 | |||
2164 | bmc->guid_attr.attr.name = "guid"; | ||
2165 | bmc->guid_attr.attr.owner = THIS_MODULE; | ||
2166 | bmc->guid_attr.attr.mode = S_IRUGO; | ||
2167 | bmc->guid_attr.show = guid_show; | ||
2168 | |||
2169 | bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision"; | ||
2170 | bmc->aux_firmware_rev_attr.attr.owner = THIS_MODULE; | ||
2171 | bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO; | ||
2172 | bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show; | ||
2173 | |||
2174 | rv = create_files(bmc); | 2391 | rv = create_files(bmc); |
2175 | if (rv) { | 2392 | if (rv) { |
2176 | mutex_lock(&ipmidriver_mutex); | 2393 | mutex_lock(&ipmidriver_mutex); |
@@ -2192,29 +2409,44 @@ static int ipmi_bmc_register(ipmi_smi_t intf) | |||
2192 | * create symlink from system interface device to bmc device | 2409 | * create symlink from system interface device to bmc device |
2193 | * and back. | 2410 | * and back. |
2194 | */ | 2411 | */ |
2412 | intf->sysfs_name = kstrdup(sysfs_name, GFP_KERNEL); | ||
2413 | if (!intf->sysfs_name) { | ||
2414 | rv = -ENOMEM; | ||
2415 | printk(KERN_ERR | ||
2416 | "ipmi_msghandler: allocate link to BMC: %d\n", | ||
2417 | rv); | ||
2418 | goto out_err; | ||
2419 | } | ||
2420 | |||
2195 | rv = sysfs_create_link(&intf->si_dev->kobj, | 2421 | rv = sysfs_create_link(&intf->si_dev->kobj, |
2196 | &bmc->dev->dev.kobj, "bmc"); | 2422 | &bmc->dev->dev.kobj, intf->sysfs_name); |
2197 | if (rv) { | 2423 | if (rv) { |
2424 | kfree(intf->sysfs_name); | ||
2425 | intf->sysfs_name = NULL; | ||
2198 | printk(KERN_ERR | 2426 | printk(KERN_ERR |
2199 | "ipmi_msghandler: Unable to create bmc symlink: %d\n", | 2427 | "ipmi_msghandler: Unable to create bmc symlink: %d\n", |
2200 | rv); | 2428 | rv); |
2201 | goto out_err; | 2429 | goto out_err; |
2202 | } | 2430 | } |
2203 | 2431 | ||
2204 | size = snprintf(dummy, 0, "ipmi%d", intf->intf_num); | 2432 | size = snprintf(dummy, 0, "ipmi%d", ifnum); |
2205 | intf->my_dev_name = kmalloc(size+1, GFP_KERNEL); | 2433 | intf->my_dev_name = kmalloc(size+1, GFP_KERNEL); |
2206 | if (!intf->my_dev_name) { | 2434 | if (!intf->my_dev_name) { |
2435 | kfree(intf->sysfs_name); | ||
2436 | intf->sysfs_name = NULL; | ||
2207 | rv = -ENOMEM; | 2437 | rv = -ENOMEM; |
2208 | printk(KERN_ERR | 2438 | printk(KERN_ERR |
2209 | "ipmi_msghandler: allocate link from BMC: %d\n", | 2439 | "ipmi_msghandler: allocate link from BMC: %d\n", |
2210 | rv); | 2440 | rv); |
2211 | goto out_err; | 2441 | goto out_err; |
2212 | } | 2442 | } |
2213 | snprintf(intf->my_dev_name, size+1, "ipmi%d", intf->intf_num); | 2443 | snprintf(intf->my_dev_name, size+1, "ipmi%d", ifnum); |
2214 | 2444 | ||
2215 | rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj, | 2445 | rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj, |
2216 | intf->my_dev_name); | 2446 | intf->my_dev_name); |
2217 | if (rv) { | 2447 | if (rv) { |
2448 | kfree(intf->sysfs_name); | ||
2449 | intf->sysfs_name = NULL; | ||
2218 | kfree(intf->my_dev_name); | 2450 | kfree(intf->my_dev_name); |
2219 | intf->my_dev_name = NULL; | 2451 | intf->my_dev_name = NULL; |
2220 | printk(KERN_ERR | 2452 | printk(KERN_ERR |
@@ -2399,17 +2631,14 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, | |||
2399 | void *send_info, | 2631 | void *send_info, |
2400 | struct ipmi_device_id *device_id, | 2632 | struct ipmi_device_id *device_id, |
2401 | struct device *si_dev, | 2633 | struct device *si_dev, |
2634 | const char *sysfs_name, | ||
2402 | unsigned char slave_addr) | 2635 | unsigned char slave_addr) |
2403 | { | 2636 | { |
2404 | int i, j; | 2637 | int i, j; |
2405 | int rv; | 2638 | int rv; |
2406 | ipmi_smi_t intf; | 2639 | ipmi_smi_t intf; |
2407 | unsigned long flags; | 2640 | ipmi_smi_t tintf; |
2408 | int version_major; | 2641 | struct list_head *link; |
2409 | int version_minor; | ||
2410 | |||
2411 | version_major = ipmi_version_major(device_id); | ||
2412 | version_minor = ipmi_version_minor(device_id); | ||
2413 | 2642 | ||
2414 | /* Make sure the driver is actually initialized, this handles | 2643 | /* Make sure the driver is actually initialized, this handles |
2415 | problems with initialization order. */ | 2644 | problems with initialization order. */ |
@@ -2427,12 +2656,16 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, | |||
2427 | if (!intf) | 2656 | if (!intf) |
2428 | return -ENOMEM; | 2657 | return -ENOMEM; |
2429 | memset(intf, 0, sizeof(*intf)); | 2658 | memset(intf, 0, sizeof(*intf)); |
2659 | |||
2660 | intf->ipmi_version_major = ipmi_version_major(device_id); | ||
2661 | intf->ipmi_version_minor = ipmi_version_minor(device_id); | ||
2662 | |||
2430 | intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL); | 2663 | intf->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL); |
2431 | if (!intf->bmc) { | 2664 | if (!intf->bmc) { |
2432 | kfree(intf); | 2665 | kfree(intf); |
2433 | return -ENOMEM; | 2666 | return -ENOMEM; |
2434 | } | 2667 | } |
2435 | intf->intf_num = -1; | 2668 | intf->intf_num = -1; /* Mark it invalid for now. */ |
2436 | kref_init(&intf->refcount); | 2669 | kref_init(&intf->refcount); |
2437 | intf->bmc->id = *device_id; | 2670 | intf->bmc->id = *device_id; |
2438 | intf->si_dev = si_dev; | 2671 | intf->si_dev = si_dev; |
@@ -2460,26 +2693,30 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, | |||
2460 | INIT_LIST_HEAD(&intf->waiting_events); | 2693 | INIT_LIST_HEAD(&intf->waiting_events); |
2461 | intf->waiting_events_count = 0; | 2694 | intf->waiting_events_count = 0; |
2462 | mutex_init(&intf->cmd_rcvrs_mutex); | 2695 | mutex_init(&intf->cmd_rcvrs_mutex); |
2696 | spin_lock_init(&intf->maintenance_mode_lock); | ||
2463 | INIT_LIST_HEAD(&intf->cmd_rcvrs); | 2697 | INIT_LIST_HEAD(&intf->cmd_rcvrs); |
2464 | init_waitqueue_head(&intf->waitq); | 2698 | init_waitqueue_head(&intf->waitq); |
2465 | 2699 | ||
2466 | spin_lock_init(&intf->counter_lock); | 2700 | spin_lock_init(&intf->counter_lock); |
2467 | intf->proc_dir = NULL; | 2701 | intf->proc_dir = NULL; |
2468 | 2702 | ||
2469 | rv = -ENOMEM; | 2703 | mutex_lock(&smi_watchers_mutex); |
2470 | spin_lock_irqsave(&interfaces_lock, flags); | 2704 | mutex_lock(&ipmi_interfaces_mutex); |
2471 | for (i = 0; i < MAX_IPMI_INTERFACES; i++) { | 2705 | /* Look for a hole in the numbers. */ |
2472 | if (ipmi_interfaces[i] == NULL) { | 2706 | i = 0; |
2473 | intf->intf_num = i; | 2707 | link = &ipmi_interfaces; |
2474 | /* Reserve the entry till we are done. */ | 2708 | list_for_each_entry_rcu(tintf, &ipmi_interfaces, link) { |
2475 | ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY; | 2709 | if (tintf->intf_num != i) { |
2476 | rv = 0; | 2710 | link = &tintf->link; |
2477 | break; | 2711 | break; |
2478 | } | 2712 | } |
2713 | i++; | ||
2479 | } | 2714 | } |
2480 | spin_unlock_irqrestore(&interfaces_lock, flags); | 2715 | /* Add the new interface in numeric order. */ |
2481 | if (rv) | 2716 | if (i == 0) |
2482 | goto out; | 2717 | list_add_rcu(&intf->link, &ipmi_interfaces); |
2718 | else | ||
2719 | list_add_tail_rcu(&intf->link, link); | ||
2483 | 2720 | ||
2484 | rv = handlers->start_processing(send_info, intf); | 2721 | rv = handlers->start_processing(send_info, intf); |
2485 | if (rv) | 2722 | if (rv) |
@@ -2487,8 +2724,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, | |||
2487 | 2724 | ||
2488 | get_guid(intf); | 2725 | get_guid(intf); |
2489 | 2726 | ||
2490 | if ((version_major > 1) | 2727 | if ((intf->ipmi_version_major > 1) |
2491 | || ((version_major == 1) && (version_minor >= 5))) | 2728 | || ((intf->ipmi_version_major == 1) |
2729 | && (intf->ipmi_version_minor >= 5))) | ||
2492 | { | 2730 | { |
2493 | /* Start scanning the channels to see what is | 2731 | /* Start scanning the channels to see what is |
2494 | available. */ | 2732 | available. */ |
@@ -2511,64 +2749,67 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, | |||
2511 | if (rv == 0) | 2749 | if (rv == 0) |
2512 | rv = add_proc_entries(intf, i); | 2750 | rv = add_proc_entries(intf, i); |
2513 | 2751 | ||
2514 | rv = ipmi_bmc_register(intf); | 2752 | rv = ipmi_bmc_register(intf, i, sysfs_name); |
2515 | 2753 | ||
2516 | out: | 2754 | out: |
2517 | if (rv) { | 2755 | if (rv) { |
2518 | if (intf->proc_dir) | 2756 | if (intf->proc_dir) |
2519 | remove_proc_entries(intf); | 2757 | remove_proc_entries(intf); |
2758 | intf->handlers = NULL; | ||
2759 | list_del_rcu(&intf->link); | ||
2760 | mutex_unlock(&ipmi_interfaces_mutex); | ||
2761 | mutex_unlock(&smi_watchers_mutex); | ||
2762 | synchronize_rcu(); | ||
2520 | kref_put(&intf->refcount, intf_free); | 2763 | kref_put(&intf->refcount, intf_free); |
2521 | if (i < MAX_IPMI_INTERFACES) { | ||
2522 | spin_lock_irqsave(&interfaces_lock, flags); | ||
2523 | ipmi_interfaces[i] = NULL; | ||
2524 | spin_unlock_irqrestore(&interfaces_lock, flags); | ||
2525 | } | ||
2526 | } else { | 2764 | } else { |
2527 | spin_lock_irqsave(&interfaces_lock, flags); | 2765 | /* After this point the interface is legal to use. */ |
2528 | ipmi_interfaces[i] = intf; | 2766 | intf->intf_num = i; |
2529 | spin_unlock_irqrestore(&interfaces_lock, flags); | 2767 | mutex_unlock(&ipmi_interfaces_mutex); |
2530 | call_smi_watchers(i, intf->si_dev); | 2768 | call_smi_watchers(i, intf->si_dev); |
2769 | mutex_unlock(&smi_watchers_mutex); | ||
2531 | } | 2770 | } |
2532 | 2771 | ||
2533 | return rv; | 2772 | return rv; |
2534 | } | 2773 | } |
2535 | 2774 | ||
2775 | static void cleanup_smi_msgs(ipmi_smi_t intf) | ||
2776 | { | ||
2777 | int i; | ||
2778 | struct seq_table *ent; | ||
2779 | |||
2780 | /* No need for locks, the interface is down. */ | ||
2781 | for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) { | ||
2782 | ent = &(intf->seq_table[i]); | ||
2783 | if (!ent->inuse) | ||
2784 | continue; | ||
2785 | deliver_err_response(ent->recv_msg, IPMI_ERR_UNSPECIFIED); | ||
2786 | } | ||
2787 | } | ||
2788 | |||
2536 | int ipmi_unregister_smi(ipmi_smi_t intf) | 2789 | int ipmi_unregister_smi(ipmi_smi_t intf) |
2537 | { | 2790 | { |
2538 | int i; | ||
2539 | struct ipmi_smi_watcher *w; | 2791 | struct ipmi_smi_watcher *w; |
2540 | unsigned long flags; | 2792 | int intf_num = intf->intf_num; |
2541 | 2793 | ||
2542 | ipmi_bmc_unregister(intf); | 2794 | ipmi_bmc_unregister(intf); |
2543 | 2795 | ||
2544 | spin_lock_irqsave(&interfaces_lock, flags); | 2796 | mutex_lock(&smi_watchers_mutex); |
2545 | for (i = 0; i < MAX_IPMI_INTERFACES; i++) { | 2797 | mutex_lock(&ipmi_interfaces_mutex); |
2546 | if (ipmi_interfaces[i] == intf) { | 2798 | intf->intf_num = -1; |
2547 | /* Set the interface number reserved until we | 2799 | intf->handlers = NULL; |
2548 | * are done. */ | 2800 | list_del_rcu(&intf->link); |
2549 | ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY; | 2801 | mutex_unlock(&ipmi_interfaces_mutex); |
2550 | intf->intf_num = -1; | 2802 | synchronize_rcu(); |
2551 | break; | ||
2552 | } | ||
2553 | } | ||
2554 | spin_unlock_irqrestore(&interfaces_lock,flags); | ||
2555 | 2803 | ||
2556 | if (i == MAX_IPMI_INTERFACES) | 2804 | cleanup_smi_msgs(intf); |
2557 | return -ENODEV; | ||
2558 | 2805 | ||
2559 | remove_proc_entries(intf); | 2806 | remove_proc_entries(intf); |
2560 | 2807 | ||
2561 | /* Call all the watcher interfaces to tell them that | 2808 | /* Call all the watcher interfaces to tell them that |
2562 | an interface is gone. */ | 2809 | an interface is gone. */ |
2563 | down_read(&smi_watchers_sem); | ||
2564 | list_for_each_entry(w, &smi_watchers, link) | 2810 | list_for_each_entry(w, &smi_watchers, link) |
2565 | w->smi_gone(i); | 2811 | w->smi_gone(intf_num); |
2566 | up_read(&smi_watchers_sem); | 2812 | mutex_unlock(&smi_watchers_mutex); |
2567 | |||
2568 | /* Allow the entry to be reused now. */ | ||
2569 | spin_lock_irqsave(&interfaces_lock, flags); | ||
2570 | ipmi_interfaces[i] = NULL; | ||
2571 | spin_unlock_irqrestore(&interfaces_lock,flags); | ||
2572 | 2813 | ||
2573 | kref_put(&intf->refcount, intf_free); | 2814 | kref_put(&intf->refcount, intf_free); |
2574 | return 0; | 2815 | return 0; |
@@ -2650,6 +2891,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, | |||
2650 | struct ipmi_ipmb_addr *ipmb_addr; | 2891 | struct ipmi_ipmb_addr *ipmb_addr; |
2651 | struct ipmi_recv_msg *recv_msg; | 2892 | struct ipmi_recv_msg *recv_msg; |
2652 | unsigned long flags; | 2893 | unsigned long flags; |
2894 | struct ipmi_smi_handlers *handlers; | ||
2653 | 2895 | ||
2654 | if (msg->rsp_size < 10) { | 2896 | if (msg->rsp_size < 10) { |
2655 | /* Message not big enough, just ignore it. */ | 2897 | /* Message not big enough, just ignore it. */ |
@@ -2706,10 +2948,16 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, | |||
2706 | printk("\n"); | 2948 | printk("\n"); |
2707 | } | 2949 | } |
2708 | #endif | 2950 | #endif |
2709 | intf->handlers->sender(intf->send_info, msg, 0); | 2951 | rcu_read_lock(); |
2710 | 2952 | handlers = intf->handlers; | |
2711 | rv = -1; /* We used the message, so return the value that | 2953 | if (handlers) { |
2712 | causes it to not be freed or queued. */ | 2954 | handlers->sender(intf->send_info, msg, 0); |
2955 | /* We used the message, so return the value | ||
2956 | that causes it to not be freed or | ||
2957 | queued. */ | ||
2958 | rv = -1; | ||
2959 | } | ||
2960 | rcu_read_unlock(); | ||
2713 | } else { | 2961 | } else { |
2714 | /* Deliver the message to the user. */ | 2962 | /* Deliver the message to the user. */ |
2715 | spin_lock_irqsave(&intf->counter_lock, flags); | 2963 | spin_lock_irqsave(&intf->counter_lock, flags); |
@@ -3232,7 +3480,9 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, | |||
3232 | report the error immediately. */ | 3480 | report the error immediately. */ |
3233 | if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0) | 3481 | if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0) |
3234 | && (msg->rsp[2] != IPMI_NODE_BUSY_ERR) | 3482 | && (msg->rsp[2] != IPMI_NODE_BUSY_ERR) |
3235 | && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)) | 3483 | && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR) |
3484 | && (msg->rsp[2] != IPMI_BUS_ERR) | ||
3485 | && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) | ||
3236 | { | 3486 | { |
3237 | int chan = msg->rsp[3] & 0xf; | 3487 | int chan = msg->rsp[3] & 0xf; |
3238 | 3488 | ||
@@ -3297,16 +3547,6 @@ void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf) | |||
3297 | rcu_read_unlock(); | 3547 | rcu_read_unlock(); |
3298 | } | 3548 | } |
3299 | 3549 | ||
3300 | static void | ||
3301 | handle_msg_timeout(struct ipmi_recv_msg *msg) | ||
3302 | { | ||
3303 | msg->recv_type = IPMI_RESPONSE_RECV_TYPE; | ||
3304 | msg->msg_data[0] = IPMI_TIMEOUT_COMPLETION_CODE; | ||
3305 | msg->msg.netfn |= 1; /* Convert to a response. */ | ||
3306 | msg->msg.data_len = 1; | ||
3307 | msg->msg.data = msg->msg_data; | ||
3308 | deliver_response(msg); | ||
3309 | } | ||
3310 | 3550 | ||
3311 | static struct ipmi_smi_msg * | 3551 | static struct ipmi_smi_msg * |
3312 | smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, | 3552 | 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, | |||
3338 | struct list_head *timeouts, long timeout_period, | 3578 | struct list_head *timeouts, long timeout_period, |
3339 | int slot, unsigned long *flags) | 3579 | int slot, unsigned long *flags) |
3340 | { | 3580 | { |
3341 | struct ipmi_recv_msg *msg; | 3581 | struct ipmi_recv_msg *msg; |
3582 | struct ipmi_smi_handlers *handlers; | ||
3583 | |||
3584 | if (intf->intf_num == -1) | ||
3585 | return; | ||
3342 | 3586 | ||
3343 | if (!ent->inuse) | 3587 | if (!ent->inuse) |
3344 | return; | 3588 | return; |
@@ -3381,13 +3625,19 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, | |||
3381 | return; | 3625 | return; |
3382 | 3626 | ||
3383 | spin_unlock_irqrestore(&intf->seq_lock, *flags); | 3627 | spin_unlock_irqrestore(&intf->seq_lock, *flags); |
3628 | |||
3384 | /* Send the new message. We send with a zero | 3629 | /* Send the new message. We send with a zero |
3385 | * priority. It timed out, I doubt time is | 3630 | * priority. It timed out, I doubt time is |
3386 | * that critical now, and high priority | 3631 | * that critical now, and high priority |
3387 | * messages are really only for messages to the | 3632 | * messages are really only for messages to the |
3388 | * local MC, which don't get resent. */ | 3633 | * local MC, which don't get resent. */ |
3389 | intf->handlers->sender(intf->send_info, | 3634 | handlers = intf->handlers; |
3390 | smi_msg, 0); | 3635 | if (handlers) |
3636 | intf->handlers->sender(intf->send_info, | ||
3637 | smi_msg, 0); | ||
3638 | else | ||
3639 | ipmi_free_smi_msg(smi_msg); | ||
3640 | |||
3391 | spin_lock_irqsave(&intf->seq_lock, *flags); | 3641 | spin_lock_irqsave(&intf->seq_lock, *flags); |
3392 | } | 3642 | } |
3393 | } | 3643 | } |
@@ -3399,18 +3649,12 @@ static void ipmi_timeout_handler(long timeout_period) | |||
3399 | struct ipmi_recv_msg *msg, *msg2; | 3649 | struct ipmi_recv_msg *msg, *msg2; |
3400 | struct ipmi_smi_msg *smi_msg, *smi_msg2; | 3650 | struct ipmi_smi_msg *smi_msg, *smi_msg2; |
3401 | unsigned long flags; | 3651 | unsigned long flags; |
3402 | int i, j; | 3652 | int i; |
3403 | 3653 | ||
3404 | INIT_LIST_HEAD(&timeouts); | 3654 | INIT_LIST_HEAD(&timeouts); |
3405 | 3655 | ||
3406 | spin_lock(&interfaces_lock); | 3656 | rcu_read_lock(); |
3407 | for (i = 0; i < MAX_IPMI_INTERFACES; i++) { | 3657 | list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { |
3408 | intf = ipmi_interfaces[i]; | ||
3409 | if (IPMI_INVALID_INTERFACE(intf)) | ||
3410 | continue; | ||
3411 | kref_get(&intf->refcount); | ||
3412 | spin_unlock(&interfaces_lock); | ||
3413 | |||
3414 | /* See if any waiting messages need to be processed. */ | 3658 | /* See if any waiting messages need to be processed. */ |
3415 | spin_lock_irqsave(&intf->waiting_msgs_lock, flags); | 3659 | spin_lock_irqsave(&intf->waiting_msgs_lock, flags); |
3416 | list_for_each_entry_safe(smi_msg, smi_msg2, | 3660 | list_for_each_entry_safe(smi_msg, smi_msg2, |
@@ -3430,35 +3674,60 @@ static void ipmi_timeout_handler(long timeout_period) | |||
3430 | have timed out, putting them in the timeouts | 3674 | have timed out, putting them in the timeouts |
3431 | list. */ | 3675 | list. */ |
3432 | spin_lock_irqsave(&intf->seq_lock, flags); | 3676 | spin_lock_irqsave(&intf->seq_lock, flags); |
3433 | for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) | 3677 | for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) |
3434 | check_msg_timeout(intf, &(intf->seq_table[j]), | 3678 | check_msg_timeout(intf, &(intf->seq_table[i]), |
3435 | &timeouts, timeout_period, j, | 3679 | &timeouts, timeout_period, i, |
3436 | &flags); | 3680 | &flags); |
3437 | spin_unlock_irqrestore(&intf->seq_lock, flags); | 3681 | spin_unlock_irqrestore(&intf->seq_lock, flags); |
3438 | 3682 | ||
3439 | list_for_each_entry_safe(msg, msg2, &timeouts, link) | 3683 | list_for_each_entry_safe(msg, msg2, &timeouts, link) |
3440 | handle_msg_timeout(msg); | 3684 | deliver_err_response(msg, IPMI_TIMEOUT_COMPLETION_CODE); |
3441 | 3685 | ||
3442 | kref_put(&intf->refcount, intf_free); | 3686 | /* |
3443 | spin_lock(&interfaces_lock); | 3687 | * Maintenance mode handling. Check the timeout |
3688 | * optimistically before we claim the lock. It may | ||
3689 | * mean a timeout gets missed occasionally, but that | ||
3690 | * only means the timeout gets extended by one period | ||
3691 | * in that case. No big deal, and it avoids the lock | ||
3692 | * most of the time. | ||
3693 | */ | ||
3694 | if (intf->auto_maintenance_timeout > 0) { | ||
3695 | spin_lock_irqsave(&intf->maintenance_mode_lock, flags); | ||
3696 | if (intf->auto_maintenance_timeout > 0) { | ||
3697 | intf->auto_maintenance_timeout | ||
3698 | -= timeout_period; | ||
3699 | if (!intf->maintenance_mode | ||
3700 | && (intf->auto_maintenance_timeout <= 0)) | ||
3701 | { | ||
3702 | intf->maintenance_mode_enable = 0; | ||
3703 | maintenance_mode_update(intf); | ||
3704 | } | ||
3705 | } | ||
3706 | spin_unlock_irqrestore(&intf->maintenance_mode_lock, | ||
3707 | flags); | ||
3708 | } | ||
3444 | } | 3709 | } |
3445 | spin_unlock(&interfaces_lock); | 3710 | rcu_read_unlock(); |
3446 | } | 3711 | } |
3447 | 3712 | ||
3448 | static void ipmi_request_event(void) | 3713 | static void ipmi_request_event(void) |
3449 | { | 3714 | { |
3450 | ipmi_smi_t intf; | 3715 | ipmi_smi_t intf; |
3451 | int i; | 3716 | struct ipmi_smi_handlers *handlers; |
3452 | 3717 | ||
3453 | spin_lock(&interfaces_lock); | 3718 | rcu_read_lock(); |
3454 | for (i = 0; i < MAX_IPMI_INTERFACES; i++) { | 3719 | /* Called from the timer, no need to check if handlers is |
3455 | intf = ipmi_interfaces[i]; | 3720 | * valid. */ |
3456 | if (IPMI_INVALID_INTERFACE(intf)) | 3721 | list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { |
3722 | /* No event requests when in maintenance mode. */ | ||
3723 | if (intf->maintenance_mode_enable) | ||
3457 | continue; | 3724 | continue; |
3458 | 3725 | ||
3459 | intf->handlers->request_events(intf->send_info); | 3726 | handlers = intf->handlers; |
3727 | if (handlers) | ||
3728 | handlers->request_events(intf->send_info); | ||
3460 | } | 3729 | } |
3461 | spin_unlock(&interfaces_lock); | 3730 | rcu_read_unlock(); |
3462 | } | 3731 | } |
3463 | 3732 | ||
3464 | static struct timer_list ipmi_timer; | 3733 | static struct timer_list ipmi_timer; |
@@ -3587,7 +3856,6 @@ static void send_panic_events(char *str) | |||
3587 | struct kernel_ipmi_msg msg; | 3856 | struct kernel_ipmi_msg msg; |
3588 | ipmi_smi_t intf; | 3857 | ipmi_smi_t intf; |
3589 | unsigned char data[16]; | 3858 | unsigned char data[16]; |
3590 | int i; | ||
3591 | struct ipmi_system_interface_addr *si; | 3859 | struct ipmi_system_interface_addr *si; |
3592 | struct ipmi_addr addr; | 3860 | struct ipmi_addr addr; |
3593 | struct ipmi_smi_msg smi_msg; | 3861 | struct ipmi_smi_msg smi_msg; |
@@ -3621,9 +3889,9 @@ static void send_panic_events(char *str) | |||
3621 | recv_msg.done = dummy_recv_done_handler; | 3889 | recv_msg.done = dummy_recv_done_handler; |
3622 | 3890 | ||
3623 | /* For every registered interface, send the event. */ | 3891 | /* For every registered interface, send the event. */ |
3624 | for (i = 0; i < MAX_IPMI_INTERFACES; i++) { | 3892 | list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { |
3625 | intf = ipmi_interfaces[i]; | 3893 | if (!intf->handlers) |
3626 | if (IPMI_INVALID_INTERFACE(intf)) | 3894 | /* Interface is not ready. */ |
3627 | continue; | 3895 | continue; |
3628 | 3896 | ||
3629 | /* Send the event announcing the panic. */ | 3897 | /* Send the event announcing the panic. */ |
@@ -3648,13 +3916,14 @@ static void send_panic_events(char *str) | |||
3648 | if (!str) | 3916 | if (!str) |
3649 | return; | 3917 | return; |
3650 | 3918 | ||
3651 | for (i = 0; i < MAX_IPMI_INTERFACES; i++) { | 3919 | /* For every registered interface, send the event. */ |
3920 | list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { | ||
3652 | char *p = str; | 3921 | char *p = str; |
3653 | struct ipmi_ipmb_addr *ipmb; | 3922 | struct ipmi_ipmb_addr *ipmb; |
3654 | int j; | 3923 | int j; |
3655 | 3924 | ||
3656 | intf = ipmi_interfaces[i]; | 3925 | if (intf->intf_num == -1) |
3657 | if (IPMI_INVALID_INTERFACE(intf)) | 3926 | /* Interface was not ready yet. */ |
3658 | continue; | 3927 | continue; |
3659 | 3928 | ||
3660 | /* First job here is to figure out where to send the | 3929 | /* First job here is to figure out where to send the |
@@ -3780,7 +4049,6 @@ static int panic_event(struct notifier_block *this, | |||
3780 | unsigned long event, | 4049 | unsigned long event, |
3781 | void *ptr) | 4050 | void *ptr) |
3782 | { | 4051 | { |
3783 | int i; | ||
3784 | ipmi_smi_t intf; | 4052 | ipmi_smi_t intf; |
3785 | 4053 | ||
3786 | if (has_panicked) | 4054 | if (has_panicked) |
@@ -3788,9 +4056,9 @@ static int panic_event(struct notifier_block *this, | |||
3788 | has_panicked = 1; | 4056 | has_panicked = 1; |
3789 | 4057 | ||
3790 | /* For every registered interface, set it to run to completion. */ | 4058 | /* For every registered interface, set it to run to completion. */ |
3791 | for (i = 0; i < MAX_IPMI_INTERFACES; i++) { | 4059 | list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { |
3792 | intf = ipmi_interfaces[i]; | 4060 | if (!intf->handlers) |
3793 | if (IPMI_INVALID_INTERFACE(intf)) | 4061 | /* Interface is not ready. */ |
3794 | continue; | 4062 | continue; |
3795 | 4063 | ||
3796 | intf->handlers->set_run_to_completion(intf->send_info, 1); | 4064 | intf->handlers->set_run_to_completion(intf->send_info, 1); |
@@ -3811,7 +4079,6 @@ static struct notifier_block panic_block = { | |||
3811 | 4079 | ||
3812 | static int ipmi_init_msghandler(void) | 4080 | static int ipmi_init_msghandler(void) |
3813 | { | 4081 | { |
3814 | int i; | ||
3815 | int rv; | 4082 | int rv; |
3816 | 4083 | ||
3817 | if (initialized) | 4084 | if (initialized) |
@@ -3826,9 +4093,6 @@ static int ipmi_init_msghandler(void) | |||
3826 | printk(KERN_INFO "ipmi message handler version " | 4093 | printk(KERN_INFO "ipmi message handler version " |
3827 | IPMI_DRIVER_VERSION "\n"); | 4094 | IPMI_DRIVER_VERSION "\n"); |
3828 | 4095 | ||
3829 | for (i = 0; i < MAX_IPMI_INTERFACES; i++) | ||
3830 | ipmi_interfaces[i] = NULL; | ||
3831 | |||
3832 | #ifdef CONFIG_PROC_FS | 4096 | #ifdef CONFIG_PROC_FS |
3833 | proc_ipmi_root = proc_mkdir("ipmi", NULL); | 4097 | proc_ipmi_root = proc_mkdir("ipmi", NULL); |
3834 | if (!proc_ipmi_root) { | 4098 | if (!proc_ipmi_root) { |
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index 8d941db83457..597eb4f88b84 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c | |||
@@ -43,6 +43,9 @@ | |||
43 | 43 | ||
44 | #define PFX "IPMI poweroff: " | 44 | #define PFX "IPMI poweroff: " |
45 | 45 | ||
46 | static void ipmi_po_smi_gone(int if_num); | ||
47 | static void ipmi_po_new_smi(int if_num, struct device *device); | ||
48 | |||
46 | /* Definitions for controlling power off (if the system supports it). It | 49 | /* Definitions for controlling power off (if the system supports it). It |
47 | * conveniently matches the IPMI chassis control values. */ | 50 | * conveniently matches the IPMI chassis control values. */ |
48 | #define IPMI_CHASSIS_POWER_DOWN 0 /* power down, the default. */ | 51 | #define IPMI_CHASSIS_POWER_DOWN 0 /* power down, the default. */ |
@@ -51,6 +54,37 @@ | |||
51 | /* the IPMI data command */ | 54 | /* the IPMI data command */ |
52 | static int poweroff_powercycle; | 55 | static int poweroff_powercycle; |
53 | 56 | ||
57 | /* Which interface to use, -1 means the first we see. */ | ||
58 | static int ifnum_to_use = -1; | ||
59 | |||
60 | /* Our local state. */ | ||
61 | static int ready = 0; | ||
62 | static ipmi_user_t ipmi_user; | ||
63 | static int ipmi_ifnum; | ||
64 | static void (*specific_poweroff_func)(ipmi_user_t user) = NULL; | ||
65 | |||
66 | /* Holds the old poweroff function so we can restore it on removal. */ | ||
67 | static void (*old_poweroff_func)(void); | ||
68 | |||
69 | static int set_param_ifnum(const char *val, struct kernel_param *kp) | ||
70 | { | ||
71 | int rv = param_set_int(val, kp); | ||
72 | if (rv) | ||
73 | return rv; | ||
74 | if ((ifnum_to_use < 0) || (ifnum_to_use == ipmi_ifnum)) | ||
75 | return 0; | ||
76 | |||
77 | ipmi_po_smi_gone(ipmi_ifnum); | ||
78 | ipmi_po_new_smi(ifnum_to_use, NULL); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | module_param_call(ifnum_to_use, set_param_ifnum, param_get_int, | ||
83 | &ifnum_to_use, 0644); | ||
84 | MODULE_PARM_DESC(ifnum_to_use, "The interface number to use for the watchdog " | ||
85 | "timer. Setting to -1 defaults to the first registered " | ||
86 | "interface"); | ||
87 | |||
54 | /* parameter definition to allow user to flag power cycle */ | 88 | /* parameter definition to allow user to flag power cycle */ |
55 | module_param(poweroff_powercycle, int, 0644); | 89 | module_param(poweroff_powercycle, int, 0644); |
56 | 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."); | 90 | 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, | |||
142 | #define IPMI_ATCA_GET_ADDR_INFO_CMD 0x01 | 176 | #define IPMI_ATCA_GET_ADDR_INFO_CMD 0x01 |
143 | #define IPMI_PICMG_ID 0 | 177 | #define IPMI_PICMG_ID 0 |
144 | 178 | ||
179 | #define IPMI_NETFN_OEM 0x2e | ||
180 | #define IPMI_ATCA_PPS_GRACEFUL_RESTART 0x11 | ||
181 | #define IPMI_ATCA_PPS_IANA "\x00\x40\x0A" | ||
182 | #define IPMI_MOTOROLA_MANUFACTURER_ID 0x0000A1 | ||
183 | #define IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID 0x0051 | ||
184 | |||
185 | static void (*atca_oem_poweroff_hook)(ipmi_user_t user) = NULL; | ||
186 | |||
187 | static void pps_poweroff_atca (ipmi_user_t user) | ||
188 | { | ||
189 | struct ipmi_system_interface_addr smi_addr; | ||
190 | struct kernel_ipmi_msg send_msg; | ||
191 | int rv; | ||
192 | /* | ||
193 | * Configure IPMI address for local access | ||
194 | */ | ||
195 | smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; | ||
196 | smi_addr.channel = IPMI_BMC_CHANNEL; | ||
197 | smi_addr.lun = 0; | ||
198 | |||
199 | printk(KERN_INFO PFX "PPS powerdown hook used"); | ||
200 | |||
201 | send_msg.netfn = IPMI_NETFN_OEM; | ||
202 | send_msg.cmd = IPMI_ATCA_PPS_GRACEFUL_RESTART; | ||
203 | send_msg.data = IPMI_ATCA_PPS_IANA; | ||
204 | send_msg.data_len = 3; | ||
205 | rv = ipmi_request_in_rc_mode(user, | ||
206 | (struct ipmi_addr *) &smi_addr, | ||
207 | &send_msg); | ||
208 | if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) { | ||
209 | printk(KERN_ERR PFX "Unable to send ATCA ," | ||
210 | " IPMI error 0x%x\n", rv); | ||
211 | } | ||
212 | return; | ||
213 | } | ||
214 | |||
145 | static int ipmi_atca_detect (ipmi_user_t user) | 215 | static int ipmi_atca_detect (ipmi_user_t user) |
146 | { | 216 | { |
147 | struct ipmi_system_interface_addr smi_addr; | 217 | struct ipmi_system_interface_addr smi_addr; |
@@ -167,6 +237,13 @@ static int ipmi_atca_detect (ipmi_user_t user) | |||
167 | rv = ipmi_request_wait_for_response(user, | 237 | rv = ipmi_request_wait_for_response(user, |
168 | (struct ipmi_addr *) &smi_addr, | 238 | (struct ipmi_addr *) &smi_addr, |
169 | &send_msg); | 239 | &send_msg); |
240 | |||
241 | printk(KERN_INFO PFX "ATCA Detect mfg 0x%X prod 0x%X\n", mfg_id, prod_id); | ||
242 | if((mfg_id == IPMI_MOTOROLA_MANUFACTURER_ID) | ||
243 | && (prod_id == IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID)) { | ||
244 | printk(KERN_INFO PFX "Installing Pigeon Point Systems Poweroff Hook\n"); | ||
245 | atca_oem_poweroff_hook = pps_poweroff_atca; | ||
246 | } | ||
170 | return !rv; | 247 | return !rv; |
171 | } | 248 | } |
172 | 249 | ||
@@ -200,12 +277,19 @@ static void ipmi_poweroff_atca (ipmi_user_t user) | |||
200 | rv = ipmi_request_in_rc_mode(user, | 277 | rv = ipmi_request_in_rc_mode(user, |
201 | (struct ipmi_addr *) &smi_addr, | 278 | (struct ipmi_addr *) &smi_addr, |
202 | &send_msg); | 279 | &send_msg); |
203 | if (rv) { | 280 | /** At this point, the system may be shutting down, and most |
281 | ** serial drivers (if used) will have interrupts turned off | ||
282 | ** it may be better to ignore IPMI_UNKNOWN_ERR_COMPLETION_CODE | ||
283 | ** return code | ||
284 | **/ | ||
285 | if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) { | ||
204 | printk(KERN_ERR PFX "Unable to send ATCA powerdown message," | 286 | printk(KERN_ERR PFX "Unable to send ATCA powerdown message," |
205 | " IPMI error 0x%x\n", rv); | 287 | " IPMI error 0x%x\n", rv); |
206 | goto out; | 288 | goto out; |
207 | } | 289 | } |
208 | 290 | ||
291 | if(atca_oem_poweroff_hook) | ||
292 | return atca_oem_poweroff_hook(user); | ||
209 | out: | 293 | out: |
210 | return; | 294 | return; |
211 | } | 295 | } |
@@ -440,15 +524,6 @@ static struct poweroff_function poweroff_functions[] = { | |||
440 | / sizeof(struct poweroff_function)) | 524 | / sizeof(struct poweroff_function)) |
441 | 525 | ||
442 | 526 | ||
443 | /* Our local state. */ | ||
444 | static int ready = 0; | ||
445 | static ipmi_user_t ipmi_user; | ||
446 | static void (*specific_poweroff_func)(ipmi_user_t user) = NULL; | ||
447 | |||
448 | /* Holds the old poweroff function so we can restore it on removal. */ | ||
449 | static void (*old_poweroff_func)(void); | ||
450 | |||
451 | |||
452 | /* Called on a powerdown request. */ | 527 | /* Called on a powerdown request. */ |
453 | static void ipmi_poweroff_function (void) | 528 | static void ipmi_poweroff_function (void) |
454 | { | 529 | { |
@@ -473,6 +548,9 @@ static void ipmi_po_new_smi(int if_num, struct device *device) | |||
473 | if (ready) | 548 | if (ready) |
474 | return; | 549 | return; |
475 | 550 | ||
551 | if ((ifnum_to_use >= 0) && (ifnum_to_use != if_num)) | ||
552 | return; | ||
553 | |||
476 | rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, | 554 | rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, |
477 | &ipmi_user); | 555 | &ipmi_user); |
478 | if (rv) { | 556 | if (rv) { |
@@ -481,6 +559,8 @@ static void ipmi_po_new_smi(int if_num, struct device *device) | |||
481 | return; | 559 | return; |
482 | } | 560 | } |
483 | 561 | ||
562 | ipmi_ifnum = if_num; | ||
563 | |||
484 | /* | 564 | /* |
485 | * Do a get device ide and store some results, since this is | 565 | * Do a get device ide and store some results, since this is |
486 | * used by several functions. | 566 | * used by several functions. |
@@ -541,9 +621,15 @@ static void ipmi_po_new_smi(int if_num, struct device *device) | |||
541 | 621 | ||
542 | static void ipmi_po_smi_gone(int if_num) | 622 | static void ipmi_po_smi_gone(int if_num) |
543 | { | 623 | { |
544 | /* This can never be called, because once poweroff driver is | 624 | if (!ready) |
545 | registered, the interface can't go away until the power | 625 | return; |
546 | driver is unregistered. */ | 626 | |
627 | if (ipmi_ifnum != if_num) | ||
628 | return; | ||
629 | |||
630 | ready = 0; | ||
631 | ipmi_destroy_user(ipmi_user); | ||
632 | pm_power_off = old_poweroff_func; | ||
547 | } | 633 | } |
548 | 634 | ||
549 | static struct ipmi_smi_watcher smi_watcher = | 635 | static struct ipmi_smi_watcher smi_watcher = |
@@ -616,9 +702,9 @@ static int ipmi_poweroff_init (void) | |||
616 | printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); | 702 | printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); |
617 | goto out_err; | 703 | goto out_err; |
618 | } | 704 | } |
619 | #endif | ||
620 | 705 | ||
621 | out_err: | 706 | out_err: |
707 | #endif | ||
622 | return rv; | 708 | return rv; |
623 | } | 709 | } |
624 | 710 | ||
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 157fa81a264f..81a0c89598e7 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
@@ -61,6 +61,10 @@ | |||
61 | #include "ipmi_si_sm.h" | 61 | #include "ipmi_si_sm.h" |
62 | #include <linux/init.h> | 62 | #include <linux/init.h> |
63 | #include <linux/dmi.h> | 63 | #include <linux/dmi.h> |
64 | #include <linux/string.h> | ||
65 | #include <linux/ctype.h> | ||
66 | |||
67 | #define PFX "ipmi_si: " | ||
64 | 68 | ||
65 | /* Measure times between events in the driver. */ | 69 | /* Measure times between events in the driver. */ |
66 | #undef DEBUG_TIMING | 70 | #undef DEBUG_TIMING |
@@ -92,7 +96,7 @@ enum si_intf_state { | |||
92 | enum si_type { | 96 | enum si_type { |
93 | SI_KCS, SI_SMIC, SI_BT | 97 | SI_KCS, SI_SMIC, SI_BT |
94 | }; | 98 | }; |
95 | static char *si_to_str[] = { "KCS", "SMIC", "BT" }; | 99 | static char *si_to_str[] = { "kcs", "smic", "bt" }; |
96 | 100 | ||
97 | #define DEVICE_NAME "ipmi_si" | 101 | #define DEVICE_NAME "ipmi_si" |
98 | 102 | ||
@@ -222,7 +226,10 @@ struct smi_info | |||
222 | static int force_kipmid[SI_MAX_PARMS]; | 226 | static int force_kipmid[SI_MAX_PARMS]; |
223 | static int num_force_kipmid; | 227 | static int num_force_kipmid; |
224 | 228 | ||
229 | static int unload_when_empty = 1; | ||
230 | |||
225 | static int try_smi_init(struct smi_info *smi); | 231 | static int try_smi_init(struct smi_info *smi); |
232 | static void cleanup_one_si(struct smi_info *to_clean); | ||
226 | 233 | ||
227 | static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list); | 234 | static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list); |
228 | static int register_xaction_notifier(struct notifier_block * nb) | 235 | static int register_xaction_notifier(struct notifier_block * nb) |
@@ -240,14 +247,18 @@ static void deliver_recv_msg(struct smi_info *smi_info, | |||
240 | spin_lock(&(smi_info->si_lock)); | 247 | spin_lock(&(smi_info->si_lock)); |
241 | } | 248 | } |
242 | 249 | ||
243 | static void return_hosed_msg(struct smi_info *smi_info) | 250 | static void return_hosed_msg(struct smi_info *smi_info, int cCode) |
244 | { | 251 | { |
245 | struct ipmi_smi_msg *msg = smi_info->curr_msg; | 252 | struct ipmi_smi_msg *msg = smi_info->curr_msg; |
246 | 253 | ||
254 | if (cCode < 0 || cCode > IPMI_ERR_UNSPECIFIED) | ||
255 | cCode = IPMI_ERR_UNSPECIFIED; | ||
256 | /* else use it as is */ | ||
257 | |||
247 | /* Make it a reponse */ | 258 | /* Make it a reponse */ |
248 | msg->rsp[0] = msg->data[0] | 4; | 259 | msg->rsp[0] = msg->data[0] | 4; |
249 | msg->rsp[1] = msg->data[1]; | 260 | msg->rsp[1] = msg->data[1]; |
250 | msg->rsp[2] = 0xFF; /* Unknown error. */ | 261 | msg->rsp[2] = cCode; |
251 | msg->rsp_size = 3; | 262 | msg->rsp_size = 3; |
252 | 263 | ||
253 | smi_info->curr_msg = NULL; | 264 | smi_info->curr_msg = NULL; |
@@ -298,7 +309,7 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) | |||
298 | smi_info->curr_msg->data, | 309 | smi_info->curr_msg->data, |
299 | smi_info->curr_msg->data_size); | 310 | smi_info->curr_msg->data_size); |
300 | if (err) { | 311 | if (err) { |
301 | return_hosed_msg(smi_info); | 312 | return_hosed_msg(smi_info, err); |
302 | } | 313 | } |
303 | 314 | ||
304 | rv = SI_SM_CALL_WITHOUT_DELAY; | 315 | rv = SI_SM_CALL_WITHOUT_DELAY; |
@@ -640,7 +651,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, | |||
640 | /* If we were handling a user message, format | 651 | /* If we were handling a user message, format |
641 | a response to send to the upper layer to | 652 | a response to send to the upper layer to |
642 | tell it about the error. */ | 653 | tell it about the error. */ |
643 | return_hosed_msg(smi_info); | 654 | return_hosed_msg(smi_info, IPMI_ERR_UNSPECIFIED); |
644 | } | 655 | } |
645 | si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0); | 656 | si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0); |
646 | } | 657 | } |
@@ -684,22 +695,24 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, | |||
684 | { | 695 | { |
685 | /* We are idle and the upper layer requested that I fetch | 696 | /* We are idle and the upper layer requested that I fetch |
686 | events, so do so. */ | 697 | events, so do so. */ |
687 | unsigned char msg[2]; | 698 | atomic_set(&smi_info->req_events, 0); |
688 | 699 | ||
689 | spin_lock(&smi_info->count_lock); | 700 | smi_info->curr_msg = ipmi_alloc_smi_msg(); |
690 | smi_info->flag_fetches++; | 701 | if (!smi_info->curr_msg) |
691 | spin_unlock(&smi_info->count_lock); | 702 | goto out; |
692 | 703 | ||
693 | atomic_set(&smi_info->req_events, 0); | 704 | smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2); |
694 | msg[0] = (IPMI_NETFN_APP_REQUEST << 2); | 705 | smi_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD; |
695 | msg[1] = IPMI_GET_MSG_FLAGS_CMD; | 706 | smi_info->curr_msg->data_size = 2; |
696 | 707 | ||
697 | smi_info->handlers->start_transaction( | 708 | smi_info->handlers->start_transaction( |
698 | smi_info->si_sm, msg, 2); | 709 | smi_info->si_sm, |
699 | smi_info->si_state = SI_GETTING_FLAGS; | 710 | smi_info->curr_msg->data, |
711 | smi_info->curr_msg->data_size); | ||
712 | smi_info->si_state = SI_GETTING_EVENTS; | ||
700 | goto restart; | 713 | goto restart; |
701 | } | 714 | } |
702 | 715 | out: | |
703 | return si_sm_result; | 716 | return si_sm_result; |
704 | } | 717 | } |
705 | 718 | ||
@@ -714,6 +727,15 @@ static void sender(void *send_info, | |||
714 | struct timeval t; | 727 | struct timeval t; |
715 | #endif | 728 | #endif |
716 | 729 | ||
730 | if (atomic_read(&smi_info->stop_operation)) { | ||
731 | msg->rsp[0] = msg->data[0] | 4; | ||
732 | msg->rsp[1] = msg->data[1]; | ||
733 | msg->rsp[2] = IPMI_ERR_UNSPECIFIED; | ||
734 | msg->rsp_size = 3; | ||
735 | deliver_recv_msg(smi_info, msg); | ||
736 | return; | ||
737 | } | ||
738 | |||
717 | spin_lock_irqsave(&(smi_info->msg_lock), flags); | 739 | spin_lock_irqsave(&(smi_info->msg_lock), flags); |
718 | #ifdef DEBUG_TIMING | 740 | #ifdef DEBUG_TIMING |
719 | do_gettimeofday(&t); | 741 | do_gettimeofday(&t); |
@@ -805,13 +827,21 @@ static void poll(void *send_info) | |||
805 | { | 827 | { |
806 | struct smi_info *smi_info = send_info; | 828 | struct smi_info *smi_info = send_info; |
807 | 829 | ||
808 | smi_event_handler(smi_info, 0); | 830 | /* |
831 | * Make sure there is some delay in the poll loop so we can | ||
832 | * drive time forward and timeout things. | ||
833 | */ | ||
834 | udelay(10); | ||
835 | smi_event_handler(smi_info, 10); | ||
809 | } | 836 | } |
810 | 837 | ||
811 | static void request_events(void *send_info) | 838 | static void request_events(void *send_info) |
812 | { | 839 | { |
813 | struct smi_info *smi_info = send_info; | 840 | struct smi_info *smi_info = send_info; |
814 | 841 | ||
842 | if (atomic_read(&smi_info->stop_operation)) | ||
843 | return; | ||
844 | |||
815 | atomic_set(&smi_info->req_events, 1); | 845 | atomic_set(&smi_info->req_events, 1); |
816 | } | 846 | } |
817 | 847 | ||
@@ -949,12 +979,21 @@ static int smi_start_processing(void *send_info, | |||
949 | return 0; | 979 | return 0; |
950 | } | 980 | } |
951 | 981 | ||
982 | static void set_maintenance_mode(void *send_info, int enable) | ||
983 | { | ||
984 | struct smi_info *smi_info = send_info; | ||
985 | |||
986 | if (!enable) | ||
987 | atomic_set(&smi_info->req_events, 0); | ||
988 | } | ||
989 | |||
952 | static struct ipmi_smi_handlers handlers = | 990 | static struct ipmi_smi_handlers handlers = |
953 | { | 991 | { |
954 | .owner = THIS_MODULE, | 992 | .owner = THIS_MODULE, |
955 | .start_processing = smi_start_processing, | 993 | .start_processing = smi_start_processing, |
956 | .sender = sender, | 994 | .sender = sender, |
957 | .request_events = request_events, | 995 | .request_events = request_events, |
996 | .set_maintenance_mode = set_maintenance_mode, | ||
958 | .set_run_to_completion = set_run_to_completion, | 997 | .set_run_to_completion = set_run_to_completion, |
959 | .poll = poll, | 998 | .poll = poll, |
960 | }; | 999 | }; |
@@ -987,6 +1026,16 @@ static int num_regshifts = 0; | |||
987 | static int slave_addrs[SI_MAX_PARMS]; | 1026 | static int slave_addrs[SI_MAX_PARMS]; |
988 | static int num_slave_addrs = 0; | 1027 | static int num_slave_addrs = 0; |
989 | 1028 | ||
1029 | #define IPMI_IO_ADDR_SPACE 0 | ||
1030 | #define IPMI_MEM_ADDR_SPACE 1 | ||
1031 | static char *addr_space_to_str[] = { "I/O", "mem" }; | ||
1032 | |||
1033 | static int hotmod_handler(const char *val, struct kernel_param *kp); | ||
1034 | |||
1035 | module_param_call(hotmod, hotmod_handler, NULL, NULL, 0200); | ||
1036 | MODULE_PARM_DESC(hotmod, "Add and remove interfaces. See" | ||
1037 | " Documentation/IPMI.txt in the kernel sources for the" | ||
1038 | " gory details."); | ||
990 | 1039 | ||
991 | module_param_named(trydefaults, si_trydefaults, bool, 0); | 1040 | module_param_named(trydefaults, si_trydefaults, bool, 0); |
992 | MODULE_PARM_DESC(trydefaults, "Setting this to 'false' will disable the" | 1041 | 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); | |||
1038 | MODULE_PARM_DESC(force_kipmid, "Force the kipmi daemon to be enabled (1) or" | 1087 | MODULE_PARM_DESC(force_kipmid, "Force the kipmi daemon to be enabled (1) or" |
1039 | " disabled(0). Normally the IPMI driver auto-detects" | 1088 | " disabled(0). Normally the IPMI driver auto-detects" |
1040 | " this, but the value may be overridden by this parm."); | 1089 | " this, but the value may be overridden by this parm."); |
1090 | module_param(unload_when_empty, int, 0); | ||
1091 | MODULE_PARM_DESC(unload_when_empty, "Unload the module if no interfaces are" | ||
1092 | " specified or found, default is 1. Setting to 0" | ||
1093 | " is useful for hot add of devices using hotmod."); | ||
1041 | 1094 | ||
1042 | 1095 | ||
1043 | #define IPMI_IO_ADDR_SPACE 0 | ||
1044 | #define IPMI_MEM_ADDR_SPACE 1 | ||
1045 | static char *addr_space_to_str[] = { "I/O", "memory" }; | ||
1046 | |||
1047 | static void std_irq_cleanup(struct smi_info *info) | 1096 | static void std_irq_cleanup(struct smi_info *info) |
1048 | { | 1097 | { |
1049 | if (info->si_type == SI_BT) | 1098 | if (info->si_type == SI_BT) |
@@ -1211,7 +1260,7 @@ static void intf_mem_outb(struct si_sm_io *io, unsigned int offset, | |||
1211 | static unsigned char intf_mem_inw(struct si_sm_io *io, unsigned int offset) | 1260 | static unsigned char intf_mem_inw(struct si_sm_io *io, unsigned int offset) |
1212 | { | 1261 | { |
1213 | return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift) | 1262 | return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift) |
1214 | && 0xff; | 1263 | & 0xff; |
1215 | } | 1264 | } |
1216 | 1265 | ||
1217 | static void intf_mem_outw(struct si_sm_io *io, unsigned int offset, | 1266 | 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, | |||
1223 | static unsigned char intf_mem_inl(struct si_sm_io *io, unsigned int offset) | 1272 | static unsigned char intf_mem_inl(struct si_sm_io *io, unsigned int offset) |
1224 | { | 1273 | { |
1225 | return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift) | 1274 | return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift) |
1226 | && 0xff; | 1275 | & 0xff; |
1227 | } | 1276 | } |
1228 | 1277 | ||
1229 | static void intf_mem_outl(struct si_sm_io *io, unsigned int offset, | 1278 | 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, | |||
1236 | static unsigned char mem_inq(struct si_sm_io *io, unsigned int offset) | 1285 | static unsigned char mem_inq(struct si_sm_io *io, unsigned int offset) |
1237 | { | 1286 | { |
1238 | return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift) | 1287 | return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift) |
1239 | && 0xff; | 1288 | & 0xff; |
1240 | } | 1289 | } |
1241 | 1290 | ||
1242 | static void mem_outq(struct si_sm_io *io, unsigned int offset, | 1291 | static void mem_outq(struct si_sm_io *io, unsigned int offset, |
@@ -1317,6 +1366,234 @@ static int mem_setup(struct smi_info *info) | |||
1317 | return 0; | 1366 | return 0; |
1318 | } | 1367 | } |
1319 | 1368 | ||
1369 | /* | ||
1370 | * Parms come in as <op1>[:op2[:op3...]]. ops are: | ||
1371 | * add|remove,kcs|bt|smic,mem|i/o,<address>[,<opt1>[,<opt2>[,...]]] | ||
1372 | * Options are: | ||
1373 | * rsp=<regspacing> | ||
1374 | * rsi=<regsize> | ||
1375 | * rsh=<regshift> | ||
1376 | * irq=<irq> | ||
1377 | * ipmb=<ipmb addr> | ||
1378 | */ | ||
1379 | enum hotmod_op { HM_ADD, HM_REMOVE }; | ||
1380 | struct hotmod_vals { | ||
1381 | char *name; | ||
1382 | int val; | ||
1383 | }; | ||
1384 | static struct hotmod_vals hotmod_ops[] = { | ||
1385 | { "add", HM_ADD }, | ||
1386 | { "remove", HM_REMOVE }, | ||
1387 | { NULL } | ||
1388 | }; | ||
1389 | static struct hotmod_vals hotmod_si[] = { | ||
1390 | { "kcs", SI_KCS }, | ||
1391 | { "smic", SI_SMIC }, | ||
1392 | { "bt", SI_BT }, | ||
1393 | { NULL } | ||
1394 | }; | ||
1395 | static struct hotmod_vals hotmod_as[] = { | ||
1396 | { "mem", IPMI_MEM_ADDR_SPACE }, | ||
1397 | { "i/o", IPMI_IO_ADDR_SPACE }, | ||
1398 | { NULL } | ||
1399 | }; | ||
1400 | static int ipmi_strcasecmp(const char *s1, const char *s2) | ||
1401 | { | ||
1402 | while (*s1 || *s2) { | ||
1403 | if (!*s1) | ||
1404 | return -1; | ||
1405 | if (!*s2) | ||
1406 | return 1; | ||
1407 | if (*s1 != *s2) | ||
1408 | return *s1 - *s2; | ||
1409 | s1++; | ||
1410 | s2++; | ||
1411 | } | ||
1412 | return 0; | ||
1413 | } | ||
1414 | static int parse_str(struct hotmod_vals *v, int *val, char *name, char **curr) | ||
1415 | { | ||
1416 | char *s; | ||
1417 | int i; | ||
1418 | |||
1419 | s = strchr(*curr, ','); | ||
1420 | if (!s) { | ||
1421 | printk(KERN_WARNING PFX "No hotmod %s given.\n", name); | ||
1422 | return -EINVAL; | ||
1423 | } | ||
1424 | *s = '\0'; | ||
1425 | s++; | ||
1426 | for (i = 0; hotmod_ops[i].name; i++) { | ||
1427 | if (ipmi_strcasecmp(*curr, v[i].name) == 0) { | ||
1428 | *val = v[i].val; | ||
1429 | *curr = s; | ||
1430 | return 0; | ||
1431 | } | ||
1432 | } | ||
1433 | |||
1434 | printk(KERN_WARNING PFX "Invalid hotmod %s '%s'\n", name, *curr); | ||
1435 | return -EINVAL; | ||
1436 | } | ||
1437 | |||
1438 | static int hotmod_handler(const char *val, struct kernel_param *kp) | ||
1439 | { | ||
1440 | char *str = kstrdup(val, GFP_KERNEL); | ||
1441 | int rv = -EINVAL; | ||
1442 | char *next, *curr, *s, *n, *o; | ||
1443 | enum hotmod_op op; | ||
1444 | enum si_type si_type; | ||
1445 | int addr_space; | ||
1446 | unsigned long addr; | ||
1447 | int regspacing; | ||
1448 | int regsize; | ||
1449 | int regshift; | ||
1450 | int irq; | ||
1451 | int ipmb; | ||
1452 | int ival; | ||
1453 | struct smi_info *info; | ||
1454 | |||
1455 | if (!str) | ||
1456 | return -ENOMEM; | ||
1457 | |||
1458 | /* Kill any trailing spaces, as we can get a "\n" from echo. */ | ||
1459 | ival = strlen(str) - 1; | ||
1460 | while ((ival >= 0) && isspace(str[ival])) { | ||
1461 | str[ival] = '\0'; | ||
1462 | ival--; | ||
1463 | } | ||
1464 | |||
1465 | for (curr = str; curr; curr = next) { | ||
1466 | regspacing = 1; | ||
1467 | regsize = 1; | ||
1468 | regshift = 0; | ||
1469 | irq = 0; | ||
1470 | ipmb = 0x20; | ||
1471 | |||
1472 | next = strchr(curr, ':'); | ||
1473 | if (next) { | ||
1474 | *next = '\0'; | ||
1475 | next++; | ||
1476 | } | ||
1477 | |||
1478 | rv = parse_str(hotmod_ops, &ival, "operation", &curr); | ||
1479 | if (rv) | ||
1480 | break; | ||
1481 | op = ival; | ||
1482 | |||
1483 | rv = parse_str(hotmod_si, &ival, "interface type", &curr); | ||
1484 | if (rv) | ||
1485 | break; | ||
1486 | si_type = ival; | ||
1487 | |||
1488 | rv = parse_str(hotmod_as, &addr_space, "address space", &curr); | ||
1489 | if (rv) | ||
1490 | break; | ||
1491 | |||
1492 | s = strchr(curr, ','); | ||
1493 | if (s) { | ||
1494 | *s = '\0'; | ||
1495 | s++; | ||
1496 | } | ||
1497 | addr = simple_strtoul(curr, &n, 0); | ||
1498 | if ((*n != '\0') || (*curr == '\0')) { | ||
1499 | printk(KERN_WARNING PFX "Invalid hotmod address" | ||
1500 | " '%s'\n", curr); | ||
1501 | break; | ||
1502 | } | ||
1503 | |||
1504 | while (s) { | ||
1505 | curr = s; | ||
1506 | s = strchr(curr, ','); | ||
1507 | if (s) { | ||
1508 | *s = '\0'; | ||
1509 | s++; | ||
1510 | } | ||
1511 | o = strchr(curr, '='); | ||
1512 | if (o) { | ||
1513 | *o = '\0'; | ||
1514 | o++; | ||
1515 | } | ||
1516 | #define HOTMOD_INT_OPT(name, val) \ | ||
1517 | if (ipmi_strcasecmp(curr, name) == 0) { \ | ||
1518 | if (!o) { \ | ||
1519 | printk(KERN_WARNING PFX \ | ||
1520 | "No option given for '%s'\n", \ | ||
1521 | curr); \ | ||
1522 | goto out; \ | ||
1523 | } \ | ||
1524 | val = simple_strtoul(o, &n, 0); \ | ||
1525 | if ((*n != '\0') || (*o == '\0')) { \ | ||
1526 | printk(KERN_WARNING PFX \ | ||
1527 | "Bad option given for '%s'\n", \ | ||
1528 | curr); \ | ||
1529 | goto out; \ | ||
1530 | } \ | ||
1531 | } | ||
1532 | |||
1533 | HOTMOD_INT_OPT("rsp", regspacing) | ||
1534 | else HOTMOD_INT_OPT("rsi", regsize) | ||
1535 | else HOTMOD_INT_OPT("rsh", regshift) | ||
1536 | else HOTMOD_INT_OPT("irq", irq) | ||
1537 | else HOTMOD_INT_OPT("ipmb", ipmb) | ||
1538 | else { | ||
1539 | printk(KERN_WARNING PFX | ||
1540 | "Invalid hotmod option '%s'\n", | ||
1541 | curr); | ||
1542 | goto out; | ||
1543 | } | ||
1544 | #undef HOTMOD_INT_OPT | ||
1545 | } | ||
1546 | |||
1547 | if (op == HM_ADD) { | ||
1548 | info = kzalloc(sizeof(*info), GFP_KERNEL); | ||
1549 | if (!info) { | ||
1550 | rv = -ENOMEM; | ||
1551 | goto out; | ||
1552 | } | ||
1553 | |||
1554 | info->addr_source = "hotmod"; | ||
1555 | info->si_type = si_type; | ||
1556 | info->io.addr_data = addr; | ||
1557 | info->io.addr_type = addr_space; | ||
1558 | if (addr_space == IPMI_MEM_ADDR_SPACE) | ||
1559 | info->io_setup = mem_setup; | ||
1560 | else | ||
1561 | info->io_setup = port_setup; | ||
1562 | |||
1563 | info->io.addr = NULL; | ||
1564 | info->io.regspacing = regspacing; | ||
1565 | if (!info->io.regspacing) | ||
1566 | info->io.regspacing = DEFAULT_REGSPACING; | ||
1567 | info->io.regsize = regsize; | ||
1568 | if (!info->io.regsize) | ||
1569 | info->io.regsize = DEFAULT_REGSPACING; | ||
1570 | info->io.regshift = regshift; | ||
1571 | info->irq = irq; | ||
1572 | if (info->irq) | ||
1573 | info->irq_setup = std_irq_setup; | ||
1574 | info->slave_addr = ipmb; | ||
1575 | |||
1576 | try_smi_init(info); | ||
1577 | } else { | ||
1578 | /* remove */ | ||
1579 | struct smi_info *e, *tmp_e; | ||
1580 | |||
1581 | mutex_lock(&smi_infos_lock); | ||
1582 | list_for_each_entry_safe(e, tmp_e, &smi_infos, link) { | ||
1583 | if (e->io.addr_type != addr_space) | ||
1584 | continue; | ||
1585 | if (e->si_type != si_type) | ||
1586 | continue; | ||
1587 | if (e->io.addr_data == addr) | ||
1588 | cleanup_one_si(e); | ||
1589 | } | ||
1590 | mutex_unlock(&smi_infos_lock); | ||
1591 | } | ||
1592 | } | ||
1593 | out: | ||
1594 | kfree(str); | ||
1595 | return rv; | ||
1596 | } | ||
1320 | 1597 | ||
1321 | static __devinit void hardcode_find_bmc(void) | 1598 | static __devinit void hardcode_find_bmc(void) |
1322 | { | 1599 | { |
@@ -1333,11 +1610,11 @@ static __devinit void hardcode_find_bmc(void) | |||
1333 | 1610 | ||
1334 | info->addr_source = "hardcoded"; | 1611 | info->addr_source = "hardcoded"; |
1335 | 1612 | ||
1336 | if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) { | 1613 | if (!si_type[i] || ipmi_strcasecmp(si_type[i], "kcs") == 0) { |
1337 | info->si_type = SI_KCS; | 1614 | info->si_type = SI_KCS; |
1338 | } else if (strcmp(si_type[i], "smic") == 0) { | 1615 | } else if (ipmi_strcasecmp(si_type[i], "smic") == 0) { |
1339 | info->si_type = SI_SMIC; | 1616 | info->si_type = SI_SMIC; |
1340 | } else if (strcmp(si_type[i], "bt") == 0) { | 1617 | } else if (ipmi_strcasecmp(si_type[i], "bt") == 0) { |
1341 | info->si_type = SI_BT; | 1618 | info->si_type = SI_BT; |
1342 | } else { | 1619 | } else { |
1343 | printk(KERN_WARNING | 1620 | printk(KERN_WARNING |
@@ -1952,19 +2229,9 @@ static int try_get_dev_id(struct smi_info *smi_info) | |||
1952 | static int type_file_read_proc(char *page, char **start, off_t off, | 2229 | static int type_file_read_proc(char *page, char **start, off_t off, |
1953 | int count, int *eof, void *data) | 2230 | int count, int *eof, void *data) |
1954 | { | 2231 | { |
1955 | char *out = (char *) page; | ||
1956 | struct smi_info *smi = data; | 2232 | struct smi_info *smi = data; |
1957 | 2233 | ||
1958 | switch (smi->si_type) { | 2234 | return sprintf(page, "%s\n", si_to_str[smi->si_type]); |
1959 | case SI_KCS: | ||
1960 | return sprintf(out, "kcs\n"); | ||
1961 | case SI_SMIC: | ||
1962 | return sprintf(out, "smic\n"); | ||
1963 | case SI_BT: | ||
1964 | return sprintf(out, "bt\n"); | ||
1965 | default: | ||
1966 | return 0; | ||
1967 | } | ||
1968 | } | 2235 | } |
1969 | 2236 | ||
1970 | static int stat_file_read_proc(char *page, char **start, off_t off, | 2237 | 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, | |||
2000 | out += sprintf(out, "incoming_messages: %ld\n", | 2267 | out += sprintf(out, "incoming_messages: %ld\n", |
2001 | smi->incoming_messages); | 2268 | smi->incoming_messages); |
2002 | 2269 | ||
2003 | return (out - ((char *) page)); | 2270 | return out - page; |
2271 | } | ||
2272 | |||
2273 | static int param_read_proc(char *page, char **start, off_t off, | ||
2274 | int count, int *eof, void *data) | ||
2275 | { | ||
2276 | struct smi_info *smi = data; | ||
2277 | |||
2278 | return sprintf(page, | ||
2279 | "%s,%s,0x%lx,rsp=%d,rsi=%d,rsh=%d,irq=%d,ipmb=%d\n", | ||
2280 | si_to_str[smi->si_type], | ||
2281 | addr_space_to_str[smi->io.addr_type], | ||
2282 | smi->io.addr_data, | ||
2283 | smi->io.regspacing, | ||
2284 | smi->io.regsize, | ||
2285 | smi->io.regshift, | ||
2286 | smi->irq, | ||
2287 | smi->slave_addr); | ||
2004 | } | 2288 | } |
2005 | 2289 | ||
2006 | /* | 2290 | /* |
@@ -2346,7 +2630,7 @@ static int try_smi_init(struct smi_info *new_smi) | |||
2346 | new_smi->dev = &new_smi->pdev->dev; | 2630 | new_smi->dev = &new_smi->pdev->dev; |
2347 | new_smi->dev->driver = &ipmi_driver; | 2631 | new_smi->dev->driver = &ipmi_driver; |
2348 | 2632 | ||
2349 | rv = platform_device_register(new_smi->pdev); | 2633 | rv = platform_device_add(new_smi->pdev); |
2350 | if (rv) { | 2634 | if (rv) { |
2351 | printk(KERN_ERR | 2635 | printk(KERN_ERR |
2352 | "ipmi_si_intf:" | 2636 | "ipmi_si_intf:" |
@@ -2362,6 +2646,7 @@ static int try_smi_init(struct smi_info *new_smi) | |||
2362 | new_smi, | 2646 | new_smi, |
2363 | &new_smi->device_id, | 2647 | &new_smi->device_id, |
2364 | new_smi->dev, | 2648 | new_smi->dev, |
2649 | "bmc", | ||
2365 | new_smi->slave_addr); | 2650 | new_smi->slave_addr); |
2366 | if (rv) { | 2651 | if (rv) { |
2367 | printk(KERN_ERR | 2652 | printk(KERN_ERR |
@@ -2390,6 +2675,16 @@ static int try_smi_init(struct smi_info *new_smi) | |||
2390 | goto out_err_stop_timer; | 2675 | goto out_err_stop_timer; |
2391 | } | 2676 | } |
2392 | 2677 | ||
2678 | rv = ipmi_smi_add_proc_entry(new_smi->intf, "params", | ||
2679 | param_read_proc, NULL, | ||
2680 | new_smi, THIS_MODULE); | ||
2681 | if (rv) { | ||
2682 | printk(KERN_ERR | ||
2683 | "ipmi_si: Unable to create proc entry: %d\n", | ||
2684 | rv); | ||
2685 | goto out_err_stop_timer; | ||
2686 | } | ||
2687 | |||
2393 | list_add_tail(&new_smi->link, &smi_infos); | 2688 | list_add_tail(&new_smi->link, &smi_infos); |
2394 | 2689 | ||
2395 | mutex_unlock(&smi_infos_lock); | 2690 | mutex_unlock(&smi_infos_lock); |
@@ -2483,7 +2778,12 @@ static __devinit int init_ipmi_si(void) | |||
2483 | #endif | 2778 | #endif |
2484 | 2779 | ||
2485 | #ifdef CONFIG_PCI | 2780 | #ifdef CONFIG_PCI |
2486 | pci_module_init(&ipmi_pci_driver); | 2781 | rv = pci_register_driver(&ipmi_pci_driver); |
2782 | if (rv){ | ||
2783 | printk(KERN_ERR | ||
2784 | "init_ipmi_si: Unable to register PCI driver: %d\n", | ||
2785 | rv); | ||
2786 | } | ||
2487 | #endif | 2787 | #endif |
2488 | 2788 | ||
2489 | if (si_trydefaults) { | 2789 | if (si_trydefaults) { |
@@ -2498,7 +2798,7 @@ static __devinit int init_ipmi_si(void) | |||
2498 | } | 2798 | } |
2499 | 2799 | ||
2500 | mutex_lock(&smi_infos_lock); | 2800 | mutex_lock(&smi_infos_lock); |
2501 | if (list_empty(&smi_infos)) { | 2801 | if (unload_when_empty && list_empty(&smi_infos)) { |
2502 | mutex_unlock(&smi_infos_lock); | 2802 | mutex_unlock(&smi_infos_lock); |
2503 | #ifdef CONFIG_PCI | 2803 | #ifdef CONFIG_PCI |
2504 | pci_unregister_driver(&ipmi_pci_driver); | 2804 | pci_unregister_driver(&ipmi_pci_driver); |
@@ -2513,7 +2813,7 @@ static __devinit int init_ipmi_si(void) | |||
2513 | } | 2813 | } |
2514 | module_init(init_ipmi_si); | 2814 | module_init(init_ipmi_si); |
2515 | 2815 | ||
2516 | static void __devexit cleanup_one_si(struct smi_info *to_clean) | 2816 | static void cleanup_one_si(struct smi_info *to_clean) |
2517 | { | 2817 | { |
2518 | int rv; | 2818 | int rv; |
2519 | unsigned long flags; | 2819 | unsigned long flags; |
diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c index 39d7e5ef1a2b..e64ea7d25d24 100644 --- a/drivers/char/ipmi/ipmi_smic_sm.c +++ b/drivers/char/ipmi/ipmi_smic_sm.c | |||
@@ -141,12 +141,14 @@ static int start_smic_transaction(struct si_sm_data *smic, | |||
141 | { | 141 | { |
142 | unsigned int i; | 142 | unsigned int i; |
143 | 143 | ||
144 | if ((size < 2) || (size > MAX_SMIC_WRITE_SIZE)) { | 144 | if (size < 2) |
145 | return -1; | 145 | return IPMI_REQ_LEN_INVALID_ERR; |
146 | } | 146 | if (size > MAX_SMIC_WRITE_SIZE) |
147 | if ((smic->state != SMIC_IDLE) && (smic->state != SMIC_HOSED)) { | 147 | return IPMI_REQ_LEN_EXCEEDED_ERR; |
148 | return -2; | 148 | |
149 | } | 149 | if ((smic->state != SMIC_IDLE) && (smic->state != SMIC_HOSED)) |
150 | return IPMI_NOT_IN_MY_STATE_ERR; | ||
151 | |||
150 | if (smic_debug & SMIC_DEBUG_MSG) { | 152 | if (smic_debug & SMIC_DEBUG_MSG) { |
151 | printk(KERN_INFO "start_smic_transaction -"); | 153 | printk(KERN_INFO "start_smic_transaction -"); |
152 | for (i = 0; i < size; i ++) { | 154 | for (i = 0; i < size; i ++) { |
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 73f759eaa5a6..90fb2a541916 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c | |||
@@ -135,6 +135,7 @@ | |||
135 | static int nowayout = WATCHDOG_NOWAYOUT; | 135 | static int nowayout = WATCHDOG_NOWAYOUT; |
136 | 136 | ||
137 | static ipmi_user_t watchdog_user = NULL; | 137 | static ipmi_user_t watchdog_user = NULL; |
138 | static int watchdog_ifnum; | ||
138 | 139 | ||
139 | /* Default the timeout to 10 seconds. */ | 140 | /* Default the timeout to 10 seconds. */ |
140 | static int timeout = 10; | 141 | static int timeout = 10; |
@@ -161,6 +162,8 @@ static struct fasync_struct *fasync_q = NULL; | |||
161 | static char pretimeout_since_last_heartbeat = 0; | 162 | static char pretimeout_since_last_heartbeat = 0; |
162 | static char expect_close; | 163 | static char expect_close; |
163 | 164 | ||
165 | static int ifnum_to_use = -1; | ||
166 | |||
164 | static DECLARE_RWSEM(register_sem); | 167 | static DECLARE_RWSEM(register_sem); |
165 | 168 | ||
166 | /* Parameters to ipmi_set_timeout */ | 169 | /* Parameters to ipmi_set_timeout */ |
@@ -169,6 +172,8 @@ static DECLARE_RWSEM(register_sem); | |||
169 | #define IPMI_SET_TIMEOUT_FORCE_HB 2 | 172 | #define IPMI_SET_TIMEOUT_FORCE_HB 2 |
170 | 173 | ||
171 | static int ipmi_set_timeout(int do_heartbeat); | 174 | static int ipmi_set_timeout(int do_heartbeat); |
175 | static void ipmi_register_watchdog(int ipmi_intf); | ||
176 | static void ipmi_unregister_watchdog(int ipmi_intf); | ||
172 | 177 | ||
173 | /* If true, the driver will start running as soon as it is configured | 178 | /* If true, the driver will start running as soon as it is configured |
174 | and ready. */ | 179 | and ready. */ |
@@ -245,6 +250,26 @@ static int get_param_str(char *buffer, struct kernel_param *kp) | |||
245 | return strlen(buffer); | 250 | return strlen(buffer); |
246 | } | 251 | } |
247 | 252 | ||
253 | |||
254 | static int set_param_wdog_ifnum(const char *val, struct kernel_param *kp) | ||
255 | { | ||
256 | int rv = param_set_int(val, kp); | ||
257 | if (rv) | ||
258 | return rv; | ||
259 | if ((ifnum_to_use < 0) || (ifnum_to_use == watchdog_ifnum)) | ||
260 | return 0; | ||
261 | |||
262 | ipmi_unregister_watchdog(watchdog_ifnum); | ||
263 | ipmi_register_watchdog(ifnum_to_use); | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | module_param_call(ifnum_to_use, set_param_wdog_ifnum, get_param_int, | ||
268 | &ifnum_to_use, 0644); | ||
269 | MODULE_PARM_DESC(ifnum_to_use, "The interface number to use for the watchdog " | ||
270 | "timer. Setting to -1 defaults to the first registered " | ||
271 | "interface"); | ||
272 | |||
248 | module_param_call(timeout, set_param_int, get_param_int, &timeout, 0644); | 273 | module_param_call(timeout, set_param_int, get_param_int, &timeout, 0644); |
249 | MODULE_PARM_DESC(timeout, "Timeout value in seconds."); | 274 | MODULE_PARM_DESC(timeout, "Timeout value in seconds."); |
250 | 275 | ||
@@ -263,12 +288,13 @@ module_param_call(preop, set_param_str, get_param_str, preop_op, 0644); | |||
263 | MODULE_PARM_DESC(preop, "Pretimeout driver operation. One of: " | 288 | MODULE_PARM_DESC(preop, "Pretimeout driver operation. One of: " |
264 | "preop_none, preop_panic, preop_give_data."); | 289 | "preop_none, preop_panic, preop_give_data."); |
265 | 290 | ||
266 | module_param(start_now, int, 0); | 291 | module_param(start_now, int, 0444); |
267 | MODULE_PARM_DESC(start_now, "Set to 1 to start the watchdog as" | 292 | MODULE_PARM_DESC(start_now, "Set to 1 to start the watchdog as" |
268 | "soon as the driver is loaded."); | 293 | "soon as the driver is loaded."); |
269 | 294 | ||
270 | module_param(nowayout, int, 0644); | 295 | module_param(nowayout, int, 0644); |
271 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | 296 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " |
297 | "(default=CONFIG_WATCHDOG_NOWAYOUT)"); | ||
272 | 298 | ||
273 | /* Default state of the timer. */ | 299 | /* Default state of the timer. */ |
274 | static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE; | 300 | static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE; |
@@ -872,6 +898,11 @@ static void ipmi_register_watchdog(int ipmi_intf) | |||
872 | if (watchdog_user) | 898 | if (watchdog_user) |
873 | goto out; | 899 | goto out; |
874 | 900 | ||
901 | if ((ifnum_to_use >= 0) && (ifnum_to_use != ipmi_intf)) | ||
902 | goto out; | ||
903 | |||
904 | watchdog_ifnum = ipmi_intf; | ||
905 | |||
875 | rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &watchdog_user); | 906 | rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &watchdog_user); |
876 | if (rv < 0) { | 907 | if (rv < 0) { |
877 | printk(KERN_CRIT PFX "Unable to register with ipmi\n"); | 908 | printk(KERN_CRIT PFX "Unable to register with ipmi\n"); |
@@ -901,6 +932,39 @@ static void ipmi_register_watchdog(int ipmi_intf) | |||
901 | } | 932 | } |
902 | } | 933 | } |
903 | 934 | ||
935 | static void ipmi_unregister_watchdog(int ipmi_intf) | ||
936 | { | ||
937 | int rv; | ||
938 | |||
939 | down_write(®ister_sem); | ||
940 | |||
941 | if (!watchdog_user) | ||
942 | goto out; | ||
943 | |||
944 | if (watchdog_ifnum != ipmi_intf) | ||
945 | goto out; | ||
946 | |||
947 | /* Make sure no one can call us any more. */ | ||
948 | misc_deregister(&ipmi_wdog_miscdev); | ||
949 | |||
950 | /* Wait to make sure the message makes it out. The lower layer has | ||
951 | pointers to our buffers, we want to make sure they are done before | ||
952 | we release our memory. */ | ||
953 | while (atomic_read(&set_timeout_tofree)) | ||
954 | schedule_timeout_uninterruptible(1); | ||
955 | |||
956 | /* Disconnect from IPMI. */ | ||
957 | rv = ipmi_destroy_user(watchdog_user); | ||
958 | if (rv) { | ||
959 | printk(KERN_WARNING PFX "error unlinking from IPMI: %d\n", | ||
960 | rv); | ||
961 | } | ||
962 | watchdog_user = NULL; | ||
963 | |||
964 | out: | ||
965 | up_write(®ister_sem); | ||
966 | } | ||
967 | |||
904 | #ifdef HAVE_NMI_HANDLER | 968 | #ifdef HAVE_NMI_HANDLER |
905 | static int | 969 | static int |
906 | ipmi_nmi(void *dev_id, int cpu, int handled) | 970 | ipmi_nmi(void *dev_id, int cpu, int handled) |
@@ -1004,9 +1068,7 @@ static void ipmi_new_smi(int if_num, struct device *device) | |||
1004 | 1068 | ||
1005 | static void ipmi_smi_gone(int if_num) | 1069 | static void ipmi_smi_gone(int if_num) |
1006 | { | 1070 | { |
1007 | /* This can never be called, because once the watchdog is | 1071 | ipmi_unregister_watchdog(if_num); |
1008 | registered, the interface can't go away until the watchdog | ||
1009 | is unregistered. */ | ||
1010 | } | 1072 | } |
1011 | 1073 | ||
1012 | static struct ipmi_smi_watcher smi_watcher = | 1074 | static struct ipmi_smi_watcher smi_watcher = |
@@ -1148,30 +1210,32 @@ static int __init ipmi_wdog_init(void) | |||
1148 | 1210 | ||
1149 | check_parms(); | 1211 | check_parms(); |
1150 | 1212 | ||
1213 | register_reboot_notifier(&wdog_reboot_notifier); | ||
1214 | atomic_notifier_chain_register(&panic_notifier_list, | ||
1215 | &wdog_panic_notifier); | ||
1216 | |||
1151 | rv = ipmi_smi_watcher_register(&smi_watcher); | 1217 | rv = ipmi_smi_watcher_register(&smi_watcher); |
1152 | if (rv) { | 1218 | if (rv) { |
1153 | #ifdef HAVE_NMI_HANDLER | 1219 | #ifdef HAVE_NMI_HANDLER |
1154 | if (preaction_val == WDOG_PRETIMEOUT_NMI) | 1220 | if (preaction_val == WDOG_PRETIMEOUT_NMI) |
1155 | release_nmi(&ipmi_nmi_handler); | 1221 | release_nmi(&ipmi_nmi_handler); |
1156 | #endif | 1222 | #endif |
1223 | atomic_notifier_chain_unregister(&panic_notifier_list, | ||
1224 | &wdog_panic_notifier); | ||
1225 | unregister_reboot_notifier(&wdog_reboot_notifier); | ||
1157 | printk(KERN_WARNING PFX "can't register smi watcher\n"); | 1226 | printk(KERN_WARNING PFX "can't register smi watcher\n"); |
1158 | return rv; | 1227 | return rv; |
1159 | } | 1228 | } |
1160 | 1229 | ||
1161 | register_reboot_notifier(&wdog_reboot_notifier); | ||
1162 | atomic_notifier_chain_register(&panic_notifier_list, | ||
1163 | &wdog_panic_notifier); | ||
1164 | |||
1165 | printk(KERN_INFO PFX "driver initialized\n"); | 1230 | printk(KERN_INFO PFX "driver initialized\n"); |
1166 | 1231 | ||
1167 | return 0; | 1232 | return 0; |
1168 | } | 1233 | } |
1169 | 1234 | ||
1170 | static __exit void ipmi_unregister_watchdog(void) | 1235 | static void __exit ipmi_wdog_exit(void) |
1171 | { | 1236 | { |
1172 | int rv; | 1237 | ipmi_smi_watcher_unregister(&smi_watcher); |
1173 | 1238 | ipmi_unregister_watchdog(watchdog_ifnum); | |
1174 | down_write(®ister_sem); | ||
1175 | 1239 | ||
1176 | #ifdef HAVE_NMI_HANDLER | 1240 | #ifdef HAVE_NMI_HANDLER |
1177 | if (nmi_handler_registered) | 1241 | if (nmi_handler_registered) |
@@ -1179,37 +1243,8 @@ static __exit void ipmi_unregister_watchdog(void) | |||
1179 | #endif | 1243 | #endif |
1180 | 1244 | ||
1181 | atomic_notifier_chain_unregister(&panic_notifier_list, | 1245 | atomic_notifier_chain_unregister(&panic_notifier_list, |
1182 | &wdog_panic_notifier); | 1246 | &wdog_panic_notifier); |
1183 | unregister_reboot_notifier(&wdog_reboot_notifier); | 1247 | unregister_reboot_notifier(&wdog_reboot_notifier); |
1184 | |||
1185 | if (! watchdog_user) | ||
1186 | goto out; | ||
1187 | |||
1188 | /* Make sure no one can call us any more. */ | ||
1189 | misc_deregister(&ipmi_wdog_miscdev); | ||
1190 | |||
1191 | /* Wait to make sure the message makes it out. The lower layer has | ||
1192 | pointers to our buffers, we want to make sure they are done before | ||
1193 | we release our memory. */ | ||
1194 | while (atomic_read(&set_timeout_tofree)) | ||
1195 | schedule_timeout_uninterruptible(1); | ||
1196 | |||
1197 | /* Disconnect from IPMI. */ | ||
1198 | rv = ipmi_destroy_user(watchdog_user); | ||
1199 | if (rv) { | ||
1200 | printk(KERN_WARNING PFX "error unlinking from IPMI: %d\n", | ||
1201 | rv); | ||
1202 | } | ||
1203 | watchdog_user = NULL; | ||
1204 | |||
1205 | out: | ||
1206 | up_write(®ister_sem); | ||
1207 | } | ||
1208 | |||
1209 | static void __exit ipmi_wdog_exit(void) | ||
1210 | { | ||
1211 | ipmi_smi_watcher_unregister(&smi_watcher); | ||
1212 | ipmi_unregister_watchdog(); | ||
1213 | } | 1248 | } |
1214 | module_exit(ipmi_wdog_exit); | 1249 | module_exit(ipmi_wdog_exit); |
1215 | module_init(ipmi_wdog_init); | 1250 | module_init(ipmi_wdog_init); |
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index e9e9bf31c369..1637c1d9a4ba 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c | |||
@@ -530,9 +530,9 @@ sched_again: | |||
530 | /* Interrupt handlers */ | 530 | /* Interrupt handlers */ |
531 | 531 | ||
532 | 532 | ||
533 | static void isicom_bottomhalf(void *data) | 533 | static void isicom_bottomhalf(struct work_struct *work) |
534 | { | 534 | { |
535 | struct isi_port *port = (struct isi_port *) data; | 535 | struct isi_port *port = container_of(work, struct isi_port, bh_tqueue); |
536 | struct tty_struct *tty = port->tty; | 536 | struct tty_struct *tty = port->tty; |
537 | 537 | ||
538 | if (!tty) | 538 | if (!tty) |
@@ -1062,11 +1062,12 @@ static void isicom_shutdown_port(struct isi_port *port) | |||
1062 | static void isicom_close(struct tty_struct *tty, struct file *filp) | 1062 | static void isicom_close(struct tty_struct *tty, struct file *filp) |
1063 | { | 1063 | { |
1064 | struct isi_port *port = tty->driver_data; | 1064 | struct isi_port *port = tty->driver_data; |
1065 | struct isi_board *card = port->card; | 1065 | struct isi_board *card; |
1066 | unsigned long flags; | 1066 | unsigned long flags; |
1067 | 1067 | ||
1068 | if (!port) | 1068 | if (!port) |
1069 | return; | 1069 | return; |
1070 | card = port->card; | ||
1070 | if (isicom_paranoia_check(port, tty->name, "isicom_close")) | 1071 | if (isicom_paranoia_check(port, tty->name, "isicom_close")) |
1071 | return; | 1072 | return; |
1072 | 1073 | ||
@@ -1473,9 +1474,9 @@ static void isicom_start(struct tty_struct *tty) | |||
1473 | } | 1474 | } |
1474 | 1475 | ||
1475 | /* hangup et all */ | 1476 | /* hangup et all */ |
1476 | static void do_isicom_hangup(void *data) | 1477 | static void do_isicom_hangup(struct work_struct *work) |
1477 | { | 1478 | { |
1478 | struct isi_port *port = data; | 1479 | struct isi_port *port = container_of(work, struct isi_port, hangup_tq); |
1479 | struct tty_struct *tty; | 1480 | struct tty_struct *tty; |
1480 | 1481 | ||
1481 | tty = port->tty; | 1482 | tty = port->tty; |
@@ -1965,8 +1966,8 @@ static int __devinit isicom_setup(void) | |||
1965 | port->channel = channel; | 1966 | port->channel = channel; |
1966 | port->close_delay = 50 * HZ/100; | 1967 | port->close_delay = 50 * HZ/100; |
1967 | port->closing_wait = 3000 * HZ/100; | 1968 | port->closing_wait = 3000 * HZ/100; |
1968 | INIT_WORK(&port->hangup_tq, do_isicom_hangup, port); | 1969 | INIT_WORK(&port->hangup_tq, do_isicom_hangup); |
1969 | INIT_WORK(&port->bh_tqueue, isicom_bottomhalf, port); | 1970 | INIT_WORK(&port->bh_tqueue, isicom_bottomhalf); |
1970 | port->status = 0; | 1971 | port->status = 0; |
1971 | init_waitqueue_head(&port->open_wait); | 1972 | init_waitqueue_head(&port->open_wait); |
1972 | init_waitqueue_head(&port->close_wait); | 1973 | init_waitqueue_head(&port->close_wait); |
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index ffdf9df1a67a..8f591945ebd9 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c | |||
@@ -663,7 +663,7 @@ static int stli_initopen(stlibrd_t *brdp, stliport_t *portp); | |||
663 | static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait); | 663 | static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait); |
664 | static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait); | 664 | static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait); |
665 | static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *filp); | 665 | static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *filp); |
666 | static void stli_dohangup(void *arg); | 666 | static void stli_dohangup(struct work_struct *); |
667 | static int stli_setport(stliport_t *portp); | 667 | static int stli_setport(stliport_t *portp); |
668 | static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback); | 668 | static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback); |
669 | static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback); | 669 | 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) | |||
1990 | * aren't that time critical). | 1990 | * aren't that time critical). |
1991 | */ | 1991 | */ |
1992 | 1992 | ||
1993 | static void stli_dohangup(void *arg) | 1993 | static void stli_dohangup(struct work_struct *ugly_api) |
1994 | { | 1994 | { |
1995 | stliport_t *portp = (stliport_t *) arg; | 1995 | stliport_t *portp = container_of(ugly_api, stliport_t, tqhangup); |
1996 | if (portp->tty != NULL) { | 1996 | if (portp->tty != NULL) { |
1997 | tty_hangup(portp->tty); | 1997 | tty_hangup(portp->tty); |
1998 | } | 1998 | } |
@@ -2898,7 +2898,7 @@ static int stli_initports(stlibrd_t *brdp) | |||
2898 | portp->baud_base = STL_BAUDBASE; | 2898 | portp->baud_base = STL_BAUDBASE; |
2899 | portp->close_delay = STL_CLOSEDELAY; | 2899 | portp->close_delay = STL_CLOSEDELAY; |
2900 | portp->closing_wait = 30 * HZ; | 2900 | portp->closing_wait = 30 * HZ; |
2901 | INIT_WORK(&portp->tqhangup, stli_dohangup, portp); | 2901 | INIT_WORK(&portp->tqhangup, stli_dohangup); |
2902 | init_waitqueue_head(&portp->open_wait); | 2902 | init_waitqueue_head(&portp->open_wait); |
2903 | init_waitqueue_head(&portp->close_wait); | 2903 | init_waitqueue_head(&portp->close_wait); |
2904 | init_waitqueue_head(&portp->raw_wait); | 2904 | init_waitqueue_head(&portp->raw_wait); |
@@ -3476,6 +3476,8 @@ static int stli_initecp(stlibrd_t *brdp) | |||
3476 | if (sig.magic != cpu_to_le32(ECP_MAGIC)) | 3476 | if (sig.magic != cpu_to_le32(ECP_MAGIC)) |
3477 | { | 3477 | { |
3478 | release_region(brdp->iobase, brdp->iosize); | 3478 | release_region(brdp->iobase, brdp->iosize); |
3479 | iounmap(brdp->membase); | ||
3480 | brdp->membase = NULL; | ||
3479 | return -ENODEV; | 3481 | return -ENODEV; |
3480 | } | 3482 | } |
3481 | 3483 | ||
@@ -3632,6 +3634,8 @@ static int stli_initonb(stlibrd_t *brdp) | |||
3632 | sig.magic3 != cpu_to_le16(ONB_MAGIC3)) | 3634 | sig.magic3 != cpu_to_le16(ONB_MAGIC3)) |
3633 | { | 3635 | { |
3634 | release_region(brdp->iobase, brdp->iosize); | 3636 | release_region(brdp->iobase, brdp->iosize); |
3637 | iounmap(brdp->membase); | ||
3638 | brdp->membase = NULL; | ||
3635 | return -ENODEV; | 3639 | return -ENODEV; |
3636 | } | 3640 | } |
3637 | 3641 | ||
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 55473371b7c6..e67eef4867ba 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
@@ -980,10 +980,10 @@ static int __init chr_dev_init(void) | |||
980 | 980 | ||
981 | mem_class = class_create(THIS_MODULE, "mem"); | 981 | mem_class = class_create(THIS_MODULE, "mem"); |
982 | for (i = 0; i < ARRAY_SIZE(devlist); i++) | 982 | for (i = 0; i < ARRAY_SIZE(devlist); i++) |
983 | class_device_create(mem_class, NULL, | 983 | device_create(mem_class, NULL, |
984 | MKDEV(MEM_MAJOR, devlist[i].minor), | 984 | MKDEV(MEM_MAJOR, devlist[i].minor), |
985 | NULL, devlist[i].name); | 985 | devlist[i].name); |
986 | 986 | ||
987 | return 0; | 987 | return 0; |
988 | } | 988 | } |
989 | 989 | ||
diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 62ebe09656e3..7e975f606924 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c | |||
@@ -169,11 +169,6 @@ fail: | |||
169 | return err; | 169 | return err; |
170 | } | 170 | } |
171 | 171 | ||
172 | /* | ||
173 | * TODO for 2.7: | ||
174 | * - add a struct kref to struct miscdevice and make all usages of | ||
175 | * them dynamic. | ||
176 | */ | ||
177 | static struct class *misc_class; | 172 | static struct class *misc_class; |
178 | 173 | ||
179 | static const struct file_operations misc_fops = { | 174 | static const struct file_operations misc_fops = { |
@@ -204,6 +199,8 @@ int misc_register(struct miscdevice * misc) | |||
204 | dev_t dev; | 199 | dev_t dev; |
205 | int err = 0; | 200 | int err = 0; |
206 | 201 | ||
202 | INIT_LIST_HEAD(&misc->list); | ||
203 | |||
207 | down(&misc_sem); | 204 | down(&misc_sem); |
208 | list_for_each_entry(c, &misc_list, list) { | 205 | list_for_each_entry(c, &misc_list, list) { |
209 | if (c->minor == misc->minor) { | 206 | if (c->minor == misc->minor) { |
@@ -228,10 +225,10 @@ int misc_register(struct miscdevice * misc) | |||
228 | misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7); | 225 | misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7); |
229 | dev = MKDEV(MISC_MAJOR, misc->minor); | 226 | dev = MKDEV(MISC_MAJOR, misc->minor); |
230 | 227 | ||
231 | misc->class = class_device_create(misc_class, NULL, dev, misc->dev, | 228 | misc->this_device = device_create(misc_class, misc->parent, dev, |
232 | "%s", misc->name); | 229 | "%s", misc->name); |
233 | if (IS_ERR(misc->class)) { | 230 | if (IS_ERR(misc->this_device)) { |
234 | err = PTR_ERR(misc->class); | 231 | err = PTR_ERR(misc->this_device); |
235 | goto out; | 232 | goto out; |
236 | } | 233 | } |
237 | 234 | ||
@@ -264,7 +261,7 @@ int misc_deregister(struct miscdevice * misc) | |||
264 | 261 | ||
265 | down(&misc_sem); | 262 | down(&misc_sem); |
266 | list_del(&misc->list); | 263 | list_del(&misc->list); |
267 | class_device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); | 264 | device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); |
268 | if (i < DYNAMIC_MINORS && i>0) { | 265 | if (i < DYNAMIC_MINORS && i>0) { |
269 | misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); | 266 | misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); |
270 | } | 267 | } |
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c index 22b9905c1e52..c09160383a53 100644 --- a/drivers/char/mmtimer.c +++ b/drivers/char/mmtimer.c | |||
@@ -680,7 +680,7 @@ static int __init mmtimer_init(void) | |||
680 | if (sn_rtc_cycles_per_second < 100000) { | 680 | if (sn_rtc_cycles_per_second < 100000) { |
681 | printk(KERN_ERR "%s: unable to determine clock frequency\n", | 681 | printk(KERN_ERR "%s: unable to determine clock frequency\n", |
682 | MMTIMER_NAME); | 682 | MMTIMER_NAME); |
683 | return -1; | 683 | goto out1; |
684 | } | 684 | } |
685 | 685 | ||
686 | mmtimer_femtoperiod = ((unsigned long)1E15 + sn_rtc_cycles_per_second / | 686 | mmtimer_femtoperiod = ((unsigned long)1E15 + sn_rtc_cycles_per_second / |
@@ -689,13 +689,13 @@ static int __init mmtimer_init(void) | |||
689 | if (request_irq(SGI_MMTIMER_VECTOR, mmtimer_interrupt, IRQF_PERCPU, MMTIMER_NAME, NULL)) { | 689 | if (request_irq(SGI_MMTIMER_VECTOR, mmtimer_interrupt, IRQF_PERCPU, MMTIMER_NAME, NULL)) { |
690 | printk(KERN_WARNING "%s: unable to allocate interrupt.", | 690 | printk(KERN_WARNING "%s: unable to allocate interrupt.", |
691 | MMTIMER_NAME); | 691 | MMTIMER_NAME); |
692 | return -1; | 692 | goto out1; |
693 | } | 693 | } |
694 | 694 | ||
695 | if (misc_register(&mmtimer_miscdev)) { | 695 | if (misc_register(&mmtimer_miscdev)) { |
696 | printk(KERN_ERR "%s: failed to register device\n", | 696 | printk(KERN_ERR "%s: failed to register device\n", |
697 | MMTIMER_NAME); | 697 | MMTIMER_NAME); |
698 | return -1; | 698 | goto out2; |
699 | } | 699 | } |
700 | 700 | ||
701 | /* Get max numbered node, calculate slots needed */ | 701 | /* Get max numbered node, calculate slots needed */ |
@@ -709,16 +709,18 @@ static int __init mmtimer_init(void) | |||
709 | if (timers == NULL) { | 709 | if (timers == NULL) { |
710 | printk(KERN_ERR "%s: failed to allocate memory for device\n", | 710 | printk(KERN_ERR "%s: failed to allocate memory for device\n", |
711 | MMTIMER_NAME); | 711 | MMTIMER_NAME); |
712 | return -1; | 712 | goto out3; |
713 | } | 713 | } |
714 | 714 | ||
715 | memset(timers,0,(sizeof(mmtimer_t *)*maxn)); | ||
716 | |||
715 | /* Allocate mmtimer_t's for each online node */ | 717 | /* Allocate mmtimer_t's for each online node */ |
716 | for_each_online_node(node) { | 718 | for_each_online_node(node) { |
717 | timers[node] = kmalloc_node(sizeof(mmtimer_t)*NUM_COMPARATORS, GFP_KERNEL, node); | 719 | timers[node] = kmalloc_node(sizeof(mmtimer_t)*NUM_COMPARATORS, GFP_KERNEL, node); |
718 | if (timers[node] == NULL) { | 720 | if (timers[node] == NULL) { |
719 | printk(KERN_ERR "%s: failed to allocate memory for device\n", | 721 | printk(KERN_ERR "%s: failed to allocate memory for device\n", |
720 | MMTIMER_NAME); | 722 | MMTIMER_NAME); |
721 | return -1; | 723 | goto out4; |
722 | } | 724 | } |
723 | for (i=0; i< NUM_COMPARATORS; i++) { | 725 | for (i=0; i< NUM_COMPARATORS; i++) { |
724 | mmtimer_t * base = timers[node] + i; | 726 | mmtimer_t * base = timers[node] + i; |
@@ -739,6 +741,17 @@ static int __init mmtimer_init(void) | |||
739 | sn_rtc_cycles_per_second/(unsigned long)1E6); | 741 | sn_rtc_cycles_per_second/(unsigned long)1E6); |
740 | 742 | ||
741 | return 0; | 743 | return 0; |
744 | |||
745 | out4: | ||
746 | for_each_online_node(node) { | ||
747 | kfree(timers[node]); | ||
748 | } | ||
749 | out3: | ||
750 | misc_deregister(&mmtimer_miscdev); | ||
751 | out2: | ||
752 | free_irq(SGI_MMTIMER_VECTOR, NULL); | ||
753 | out1: | ||
754 | return -1; | ||
742 | } | 755 | } |
743 | 756 | ||
744 | module_init(mmtimer_init); | 757 | module_init(mmtimer_init); |
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 96cb1f07332b..8b316953173d 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c | |||
@@ -222,7 +222,7 @@ static struct semaphore moxaBuffSem; | |||
222 | /* | 222 | /* |
223 | * static functions: | 223 | * static functions: |
224 | */ | 224 | */ |
225 | static void do_moxa_softint(void *); | 225 | static void do_moxa_softint(struct work_struct *); |
226 | static int moxa_open(struct tty_struct *, struct file *); | 226 | static int moxa_open(struct tty_struct *, struct file *); |
227 | static void moxa_close(struct tty_struct *, struct file *); | 227 | static void moxa_close(struct tty_struct *, struct file *); |
228 | static int moxa_write(struct tty_struct *, const unsigned char *, int); | 228 | static int moxa_write(struct tty_struct *, const unsigned char *, int); |
@@ -363,7 +363,7 @@ static int __init moxa_init(void) | |||
363 | for (i = 0, ch = moxaChannels; i < MAX_PORTS; i++, ch++) { | 363 | for (i = 0, ch = moxaChannels; i < MAX_PORTS; i++, ch++) { |
364 | ch->type = PORT_16550A; | 364 | ch->type = PORT_16550A; |
365 | ch->port = i; | 365 | ch->port = i; |
366 | INIT_WORK(&ch->tqueue, do_moxa_softint, ch); | 366 | INIT_WORK(&ch->tqueue, do_moxa_softint); |
367 | ch->tty = NULL; | 367 | ch->tty = NULL; |
368 | ch->close_delay = 5 * HZ / 10; | 368 | ch->close_delay = 5 * HZ / 10; |
369 | ch->closing_wait = 30 * HZ; | 369 | ch->closing_wait = 30 * HZ; |
@@ -498,9 +498,12 @@ static void __exit moxa_exit(void) | |||
498 | printk("Couldn't unregister MOXA Intellio family serial driver\n"); | 498 | printk("Couldn't unregister MOXA Intellio family serial driver\n"); |
499 | put_tty_driver(moxaDriver); | 499 | put_tty_driver(moxaDriver); |
500 | 500 | ||
501 | for (i = 0; i < MAX_BOARDS; i++) | 501 | for (i = 0; i < MAX_BOARDS; i++) { |
502 | if (moxaBaseAddr[i]) | ||
503 | iounmap(moxaBaseAddr[i]); | ||
502 | if (moxa_boards[i].busType == MOXA_BUS_TYPE_PCI) | 504 | if (moxa_boards[i].busType == MOXA_BUS_TYPE_PCI) |
503 | pci_dev_put(moxa_boards[i].pciInfo.pdev); | 505 | pci_dev_put(moxa_boards[i].pciInfo.pdev); |
506 | } | ||
504 | 507 | ||
505 | if (verbose) | 508 | if (verbose) |
506 | printk("Done\n"); | 509 | printk("Done\n"); |
@@ -509,9 +512,9 @@ static void __exit moxa_exit(void) | |||
509 | module_init(moxa_init); | 512 | module_init(moxa_init); |
510 | module_exit(moxa_exit); | 513 | module_exit(moxa_exit); |
511 | 514 | ||
512 | static void do_moxa_softint(void *private_) | 515 | static void do_moxa_softint(struct work_struct *work) |
513 | { | 516 | { |
514 | struct moxa_str *ch = (struct moxa_str *) private_; | 517 | struct moxa_str *ch = container_of(work, struct moxa_str, tqueue); |
515 | struct tty_struct *tty; | 518 | struct tty_struct *tty; |
516 | 519 | ||
517 | if (ch && (tty = ch->tty)) { | 520 | if (ch && (tty = ch->tty)) { |
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index 5c0dec39cf6c..235e89226112 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c | |||
@@ -72,7 +72,11 @@ enum { | |||
72 | MSPEC_UNCACHED | 72 | MSPEC_UNCACHED |
73 | }; | 73 | }; |
74 | 74 | ||
75 | #ifdef CONFIG_SGI_SN | ||
75 | static int is_sn2; | 76 | static int is_sn2; |
77 | #else | ||
78 | #define is_sn2 0 | ||
79 | #endif | ||
76 | 80 | ||
77 | /* | 81 | /* |
78 | * One of these structures is allocated when an mspec region is mmaped. The | 82 | * 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) | |||
211 | if (vdata->type == MSPEC_FETCHOP) | 215 | if (vdata->type == MSPEC_FETCHOP) |
212 | paddr = TO_AMO(maddr); | 216 | paddr = TO_AMO(maddr); |
213 | else | 217 | else |
214 | paddr = __pa(TO_CAC(maddr)); | 218 | paddr = maddr & ~__IA64_UNCACHED_OFFSET; |
215 | 219 | ||
216 | pfn = paddr >> PAGE_SHIFT; | 220 | pfn = paddr >> PAGE_SHIFT; |
217 | 221 | ||
@@ -335,6 +339,7 @@ mspec_init(void) | |||
335 | * The fetchop device only works on SN2 hardware, uncached and cached | 339 | * The fetchop device only works on SN2 hardware, uncached and cached |
336 | * memory drivers should both be valid on all ia64 hardware | 340 | * memory drivers should both be valid on all ia64 hardware |
337 | */ | 341 | */ |
342 | #ifdef CONFIG_SGI_SN | ||
338 | if (ia64_platform_is("sn2")) { | 343 | if (ia64_platform_is("sn2")) { |
339 | is_sn2 = 1; | 344 | is_sn2 = 1; |
340 | if (is_shub2()) { | 345 | if (is_shub2()) { |
@@ -363,6 +368,7 @@ mspec_init(void) | |||
363 | goto free_scratch_pages; | 368 | goto free_scratch_pages; |
364 | } | 369 | } |
365 | } | 370 | } |
371 | #endif | ||
366 | ret = misc_register(&cached_miscdev); | 372 | ret = misc_register(&cached_miscdev); |
367 | if (ret) { | 373 | if (ret) { |
368 | printk(KERN_ERR "%s: failed to register device %i\n", | 374 | printk(KERN_ERR "%s: failed to register device %i\n", |
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 048d91142c17..5ed2486b7581 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c | |||
@@ -389,7 +389,7 @@ static int mxser_init(void); | |||
389 | /* static void mxser_poll(unsigned long); */ | 389 | /* static void mxser_poll(unsigned long); */ |
390 | static int mxser_get_ISA_conf(int, struct mxser_hwconf *); | 390 | static int mxser_get_ISA_conf(int, struct mxser_hwconf *); |
391 | static int mxser_get_PCI_conf(int, int, int, struct mxser_hwconf *); | 391 | static int mxser_get_PCI_conf(int, int, int, struct mxser_hwconf *); |
392 | static void mxser_do_softint(void *); | 392 | static void mxser_do_softint(struct work_struct *); |
393 | static int mxser_open(struct tty_struct *, struct file *); | 393 | static int mxser_open(struct tty_struct *, struct file *); |
394 | static void mxser_close(struct tty_struct *, struct file *); | 394 | static void mxser_close(struct tty_struct *, struct file *); |
395 | static int mxser_write(struct tty_struct *, const unsigned char *, int); | 395 | 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) | |||
590 | info->custom_divisor = hwconf->baud_base[i] * 16; | 590 | info->custom_divisor = hwconf->baud_base[i] * 16; |
591 | info->close_delay = 5 * HZ / 10; | 591 | info->close_delay = 5 * HZ / 10; |
592 | info->closing_wait = 30 * HZ; | 592 | info->closing_wait = 30 * HZ; |
593 | INIT_WORK(&info->tqueue, mxser_do_softint, info); | 593 | INIT_WORK(&info->tqueue, mxser_do_softint); |
594 | info->normal_termios = mxvar_sdriver->init_termios; | 594 | info->normal_termios = mxvar_sdriver->init_termios; |
595 | init_waitqueue_head(&info->open_wait); | 595 | init_waitqueue_head(&info->open_wait); |
596 | init_waitqueue_head(&info->close_wait); | 596 | init_waitqueue_head(&info->close_wait); |
@@ -917,9 +917,10 @@ static int mxser_init(void) | |||
917 | return 0; | 917 | return 0; |
918 | } | 918 | } |
919 | 919 | ||
920 | static void mxser_do_softint(void *private_) | 920 | static void mxser_do_softint(struct work_struct *work) |
921 | { | 921 | { |
922 | struct mxser_struct *info = private_; | 922 | struct mxser_struct *info = |
923 | container_of(work, struct mxser_struct, tqueue); | ||
923 | struct tty_struct *tty; | 924 | struct tty_struct *tty; |
924 | 925 | ||
925 | tty = info->tty; | 926 | tty = info->tty; |
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 50d20aafeb18..211c93fda6fc 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c | |||
@@ -1764,29 +1764,11 @@ static int cm4000_config(struct pcmcia_device * link, int devno) | |||
1764 | int rc; | 1764 | int rc; |
1765 | 1765 | ||
1766 | /* read the config-tuples */ | 1766 | /* read the config-tuples */ |
1767 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
1768 | tuple.Attributes = 0; | 1767 | tuple.Attributes = 0; |
1769 | tuple.TupleData = buf; | 1768 | tuple.TupleData = buf; |
1770 | tuple.TupleDataMax = sizeof(buf); | 1769 | tuple.TupleDataMax = sizeof(buf); |
1771 | tuple.TupleOffset = 0; | 1770 | tuple.TupleOffset = 0; |
1772 | 1771 | ||
1773 | if ((fail_rc = pcmcia_get_first_tuple(link, &tuple)) != CS_SUCCESS) { | ||
1774 | fail_fn = GetFirstTuple; | ||
1775 | goto cs_failed; | ||
1776 | } | ||
1777 | if ((fail_rc = pcmcia_get_tuple_data(link, &tuple)) != CS_SUCCESS) { | ||
1778 | fail_fn = GetTupleData; | ||
1779 | goto cs_failed; | ||
1780 | } | ||
1781 | if ((fail_rc = | ||
1782 | pcmcia_parse_tuple(link, &tuple, &parse)) != CS_SUCCESS) { | ||
1783 | fail_fn = ParseTuple; | ||
1784 | goto cs_failed; | ||
1785 | } | ||
1786 | |||
1787 | link->conf.ConfigBase = parse.config.base; | ||
1788 | link->conf.Present = parse.config.rmask[0]; | ||
1789 | |||
1790 | link->io.BasePort2 = 0; | 1772 | link->io.BasePort2 = 0; |
1791 | link->io.NumPorts2 = 0; | 1773 | link->io.NumPorts2 = 0; |
1792 | link->io.Attributes2 = 0; | 1774 | link->io.Attributes2 = 0; |
@@ -1841,8 +1823,6 @@ static int cm4000_config(struct pcmcia_device * link, int devno) | |||
1841 | 1823 | ||
1842 | return 0; | 1824 | return 0; |
1843 | 1825 | ||
1844 | cs_failed: | ||
1845 | cs_error(link, fail_fn, fail_rc); | ||
1846 | cs_release: | 1826 | cs_release: |
1847 | cm4000_release(link); | 1827 | cm4000_release(link); |
1848 | return -ENODEV; | 1828 | return -ENODEV; |
@@ -1973,14 +1953,14 @@ static int __init cmm_init(void) | |||
1973 | printk(KERN_INFO "%s\n", version); | 1953 | printk(KERN_INFO "%s\n", version); |
1974 | 1954 | ||
1975 | cmm_class = class_create(THIS_MODULE, "cardman_4000"); | 1955 | cmm_class = class_create(THIS_MODULE, "cardman_4000"); |
1976 | if (!cmm_class) | 1956 | if (IS_ERR(cmm_class)) |
1977 | return -1; | 1957 | return PTR_ERR(cmm_class); |
1978 | 1958 | ||
1979 | major = register_chrdev(0, DEVICE_NAME, &cm4000_fops); | 1959 | major = register_chrdev(0, DEVICE_NAME, &cm4000_fops); |
1980 | if (major < 0) { | 1960 | if (major < 0) { |
1981 | printk(KERN_WARNING MODULE_NAME | 1961 | printk(KERN_WARNING MODULE_NAME |
1982 | ": could not get major number\n"); | 1962 | ": could not get major number\n"); |
1983 | return -1; | 1963 | return major; |
1984 | } | 1964 | } |
1985 | 1965 | ||
1986 | rc = pcmcia_register_driver(&cm4000_driver); | 1966 | rc = pcmcia_register_driver(&cm4000_driver); |
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 55cf4be42976..9b1ff7e8f896 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c | |||
@@ -523,29 +523,11 @@ static int reader_config(struct pcmcia_device *link, int devno) | |||
523 | int fail_fn, fail_rc; | 523 | int fail_fn, fail_rc; |
524 | int rc; | 524 | int rc; |
525 | 525 | ||
526 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
527 | tuple.Attributes = 0; | 526 | tuple.Attributes = 0; |
528 | tuple.TupleData = buf; | 527 | tuple.TupleData = buf; |
529 | tuple.TupleDataMax = sizeof(buf); | 528 | tuple.TupleDataMax = sizeof(buf); |
530 | tuple.TupleOffset = 0; | 529 | tuple.TupleOffset = 0; |
531 | 530 | ||
532 | if ((fail_rc = pcmcia_get_first_tuple(link, &tuple)) != CS_SUCCESS) { | ||
533 | fail_fn = GetFirstTuple; | ||
534 | goto cs_failed; | ||
535 | } | ||
536 | if ((fail_rc = pcmcia_get_tuple_data(link, &tuple)) != CS_SUCCESS) { | ||
537 | fail_fn = GetTupleData; | ||
538 | goto cs_failed; | ||
539 | } | ||
540 | if ((fail_rc = pcmcia_parse_tuple(link, &tuple, &parse)) | ||
541 | != CS_SUCCESS) { | ||
542 | fail_fn = ParseTuple; | ||
543 | goto cs_failed; | ||
544 | } | ||
545 | |||
546 | link->conf.ConfigBase = parse.config.base; | ||
547 | link->conf.Present = parse.config.rmask[0]; | ||
548 | |||
549 | link->io.BasePort2 = 0; | 531 | link->io.BasePort2 = 0; |
550 | link->io.NumPorts2 = 0; | 532 | link->io.NumPorts2 = 0; |
551 | link->io.Attributes2 = 0; | 533 | link->io.Attributes2 = 0; |
@@ -609,8 +591,6 @@ static int reader_config(struct pcmcia_device *link, int devno) | |||
609 | 591 | ||
610 | return 0; | 592 | return 0; |
611 | 593 | ||
612 | cs_failed: | ||
613 | cs_error(link, fail_fn, fail_rc); | ||
614 | cs_release: | 594 | cs_release: |
615 | reader_release(link); | 595 | reader_release(link); |
616 | return -ENODEV; | 596 | return -ENODEV; |
@@ -721,14 +701,14 @@ static int __init cm4040_init(void) | |||
721 | 701 | ||
722 | printk(KERN_INFO "%s\n", version); | 702 | printk(KERN_INFO "%s\n", version); |
723 | cmx_class = class_create(THIS_MODULE, "cardman_4040"); | 703 | cmx_class = class_create(THIS_MODULE, "cardman_4040"); |
724 | if (!cmx_class) | 704 | if (IS_ERR(cmx_class)) |
725 | return -1; | 705 | return PTR_ERR(cmx_class); |
726 | 706 | ||
727 | major = register_chrdev(0, DEVICE_NAME, &reader_fops); | 707 | major = register_chrdev(0, DEVICE_NAME, &reader_fops); |
728 | if (major < 0) { | 708 | if (major < 0) { |
729 | printk(KERN_WARNING MODULE_NAME | 709 | printk(KERN_WARNING MODULE_NAME |
730 | ": could not get major number\n"); | 710 | ": could not get major number\n"); |
731 | return -1; | 711 | return major; |
732 | } | 712 | } |
733 | 713 | ||
734 | rc = pcmcia_register_driver(&reader_driver); | 714 | rc = pcmcia_register_driver(&reader_driver); |
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 1a0bc30b79d1..74d21c1c104f 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c | |||
@@ -75,8 +75,10 @@ | |||
75 | #include <pcmcia/cisreg.h> | 75 | #include <pcmcia/cisreg.h> |
76 | #include <pcmcia/ds.h> | 76 | #include <pcmcia/ds.h> |
77 | 77 | ||
78 | #ifdef CONFIG_HDLC_MODULE | 78 | #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_CS_MODULE)) |
79 | #define CONFIG_HDLC 1 | 79 | #define SYNCLINK_GENERIC_HDLC 1 |
80 | #else | ||
81 | #define SYNCLINK_GENERIC_HDLC 0 | ||
80 | #endif | 82 | #endif |
81 | 83 | ||
82 | #define GET_USER(error,value,addr) error = get_user(value,addr) | 84 | #define GET_USER(error,value,addr) error = get_user(value,addr) |
@@ -235,7 +237,7 @@ typedef struct _mgslpc_info { | |||
235 | int dosyncppp; | 237 | int dosyncppp; |
236 | spinlock_t netlock; | 238 | spinlock_t netlock; |
237 | 239 | ||
238 | #ifdef CONFIG_HDLC | 240 | #if SYNCLINK_GENERIC_HDLC |
239 | struct net_device *netdev; | 241 | struct net_device *netdev; |
240 | #endif | 242 | #endif |
241 | 243 | ||
@@ -392,7 +394,7 @@ static void tx_timeout(unsigned long context); | |||
392 | 394 | ||
393 | static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg); | 395 | static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg); |
394 | 396 | ||
395 | #ifdef CONFIG_HDLC | 397 | #if SYNCLINK_GENERIC_HDLC |
396 | #define dev_to_port(D) (dev_to_hdlc(D)->priv) | 398 | #define dev_to_port(D) (dev_to_hdlc(D)->priv) |
397 | static void hdlcdev_tx_done(MGSLPC_INFO *info); | 399 | static void hdlcdev_tx_done(MGSLPC_INFO *info); |
398 | static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size); | 400 | 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); | |||
421 | /* | 423 | /* |
422 | * Bottom half interrupt handlers | 424 | * Bottom half interrupt handlers |
423 | */ | 425 | */ |
424 | static void bh_handler(void* Context); | 426 | static void bh_handler(struct work_struct *work); |
425 | static void bh_transmit(MGSLPC_INFO *info); | 427 | static void bh_transmit(MGSLPC_INFO *info); |
426 | static void bh_status(MGSLPC_INFO *info); | 428 | static void bh_status(MGSLPC_INFO *info); |
427 | 429 | ||
@@ -547,7 +549,7 @@ static int mgslpc_probe(struct pcmcia_device *link) | |||
547 | 549 | ||
548 | memset(info, 0, sizeof(MGSLPC_INFO)); | 550 | memset(info, 0, sizeof(MGSLPC_INFO)); |
549 | info->magic = MGSLPC_MAGIC; | 551 | info->magic = MGSLPC_MAGIC; |
550 | INIT_WORK(&info->task, bh_handler, info); | 552 | INIT_WORK(&info->task, bh_handler); |
551 | info->max_frame_size = 4096; | 553 | info->max_frame_size = 4096; |
552 | info->close_delay = 5*HZ/10; | 554 | info->close_delay = 5*HZ/10; |
553 | info->closing_wait = 30*HZ; | 555 | info->closing_wait = 30*HZ; |
@@ -604,17 +606,10 @@ static int mgslpc_config(struct pcmcia_device *link) | |||
604 | if (debug_level >= DEBUG_LEVEL_INFO) | 606 | if (debug_level >= DEBUG_LEVEL_INFO) |
605 | printk("mgslpc_config(0x%p)\n", link); | 607 | printk("mgslpc_config(0x%p)\n", link); |
606 | 608 | ||
607 | /* read CONFIG tuple to find its configuration registers */ | ||
608 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
609 | tuple.Attributes = 0; | 609 | tuple.Attributes = 0; |
610 | tuple.TupleData = buf; | 610 | tuple.TupleData = buf; |
611 | tuple.TupleDataMax = sizeof(buf); | 611 | tuple.TupleDataMax = sizeof(buf); |
612 | tuple.TupleOffset = 0; | 612 | tuple.TupleOffset = 0; |
613 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); | ||
614 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); | ||
615 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); | ||
616 | link->conf.ConfigBase = parse.config.base; | ||
617 | link->conf.Present = parse.config.rmask[0]; | ||
618 | 613 | ||
619 | /* get CIS configuration entry */ | 614 | /* get CIS configuration entry */ |
620 | 615 | ||
@@ -842,9 +837,9 @@ static int bh_action(MGSLPC_INFO *info) | |||
842 | return rc; | 837 | return rc; |
843 | } | 838 | } |
844 | 839 | ||
845 | static void bh_handler(void* Context) | 840 | static void bh_handler(struct work_struct *work) |
846 | { | 841 | { |
847 | MGSLPC_INFO *info = (MGSLPC_INFO*)Context; | 842 | MGSLPC_INFO *info = container_of(work, MGSLPC_INFO, task); |
848 | int action; | 843 | int action; |
849 | 844 | ||
850 | if (!info) | 845 | if (!info) |
@@ -1060,7 +1055,7 @@ static void tx_done(MGSLPC_INFO *info) | |||
1060 | info->drop_rts_on_tx_done = 0; | 1055 | info->drop_rts_on_tx_done = 0; |
1061 | } | 1056 | } |
1062 | 1057 | ||
1063 | #ifdef CONFIG_HDLC | 1058 | #if SYNCLINK_GENERIC_HDLC |
1064 | if (info->netcount) | 1059 | if (info->netcount) |
1065 | hdlcdev_tx_done(info); | 1060 | hdlcdev_tx_done(info); |
1066 | else | 1061 | else |
@@ -1171,7 +1166,7 @@ static void dcd_change(MGSLPC_INFO *info) | |||
1171 | } | 1166 | } |
1172 | else | 1167 | else |
1173 | info->input_signal_events.dcd_down++; | 1168 | info->input_signal_events.dcd_down++; |
1174 | #ifdef CONFIG_HDLC | 1169 | #if SYNCLINK_GENERIC_HDLC |
1175 | if (info->netcount) { | 1170 | if (info->netcount) { |
1176 | if (info->serial_signals & SerialSignal_DCD) | 1171 | if (info->serial_signals & SerialSignal_DCD) |
1177 | netif_carrier_on(info->netdev); | 1172 | netif_carrier_on(info->netdev); |
@@ -2960,7 +2955,7 @@ static void mgslpc_add_device(MGSLPC_INFO *info) | |||
2960 | printk( "SyncLink PC Card %s:IO=%04X IRQ=%d\n", | 2955 | printk( "SyncLink PC Card %s:IO=%04X IRQ=%d\n", |
2961 | info->device_name, info->io_base, info->irq_level); | 2956 | info->device_name, info->io_base, info->irq_level); |
2962 | 2957 | ||
2963 | #ifdef CONFIG_HDLC | 2958 | #if SYNCLINK_GENERIC_HDLC |
2964 | hdlcdev_init(info); | 2959 | hdlcdev_init(info); |
2965 | #endif | 2960 | #endif |
2966 | } | 2961 | } |
@@ -2976,7 +2971,7 @@ static void mgslpc_remove_device(MGSLPC_INFO *remove_info) | |||
2976 | last->next_device = info->next_device; | 2971 | last->next_device = info->next_device; |
2977 | else | 2972 | else |
2978 | mgslpc_device_list = info->next_device; | 2973 | mgslpc_device_list = info->next_device; |
2979 | #ifdef CONFIG_HDLC | 2974 | #if SYNCLINK_GENERIC_HDLC |
2980 | hdlcdev_exit(info); | 2975 | hdlcdev_exit(info); |
2981 | #endif | 2976 | #endif |
2982 | release_resources(info); | 2977 | release_resources(info); |
@@ -3908,7 +3903,7 @@ static int rx_get_frame(MGSLPC_INFO *info) | |||
3908 | return_frame = 1; | 3903 | return_frame = 1; |
3909 | } | 3904 | } |
3910 | framesize = 0; | 3905 | framesize = 0; |
3911 | #ifdef CONFIG_HDLC | 3906 | #if SYNCLINK_GENERIC_HDLC |
3912 | { | 3907 | { |
3913 | struct net_device_stats *stats = hdlc_stats(info->netdev); | 3908 | struct net_device_stats *stats = hdlc_stats(info->netdev); |
3914 | stats->rx_errors++; | 3909 | stats->rx_errors++; |
@@ -3942,7 +3937,7 @@ static int rx_get_frame(MGSLPC_INFO *info) | |||
3942 | ++framesize; | 3937 | ++framesize; |
3943 | } | 3938 | } |
3944 | 3939 | ||
3945 | #ifdef CONFIG_HDLC | 3940 | #if SYNCLINK_GENERIC_HDLC |
3946 | if (info->netcount) | 3941 | if (info->netcount) |
3947 | hdlcdev_rx(info, buf->data, framesize); | 3942 | hdlcdev_rx(info, buf->data, framesize); |
3948 | else | 3943 | else |
@@ -4098,7 +4093,7 @@ static void tx_timeout(unsigned long context) | |||
4098 | 4093 | ||
4099 | spin_unlock_irqrestore(&info->lock,flags); | 4094 | spin_unlock_irqrestore(&info->lock,flags); |
4100 | 4095 | ||
4101 | #ifdef CONFIG_HDLC | 4096 | #if SYNCLINK_GENERIC_HDLC |
4102 | if (info->netcount) | 4097 | if (info->netcount) |
4103 | hdlcdev_tx_done(info); | 4098 | hdlcdev_tx_done(info); |
4104 | else | 4099 | else |
@@ -4106,7 +4101,7 @@ static void tx_timeout(unsigned long context) | |||
4106 | bh_transmit(info); | 4101 | bh_transmit(info); |
4107 | } | 4102 | } |
4108 | 4103 | ||
4109 | #ifdef CONFIG_HDLC | 4104 | #if SYNCLINK_GENERIC_HDLC |
4110 | 4105 | ||
4111 | /** | 4106 | /** |
4112 | * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) | 4107 | * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) |
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index efc485edad1c..c1e3dd837fc8 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c | |||
@@ -752,13 +752,13 @@ static const struct file_operations pp_fops = { | |||
752 | 752 | ||
753 | static void pp_attach(struct parport *port) | 753 | static void pp_attach(struct parport *port) |
754 | { | 754 | { |
755 | class_device_create(ppdev_class, NULL, MKDEV(PP_MAJOR, port->number), | 755 | device_create(ppdev_class, NULL, MKDEV(PP_MAJOR, port->number), |
756 | NULL, "parport%d", port->number); | 756 | "parport%d", port->number); |
757 | } | 757 | } |
758 | 758 | ||
759 | static void pp_detach(struct parport *port) | 759 | static void pp_detach(struct parport *port) |
760 | { | 760 | { |
761 | class_device_destroy(ppdev_class, MKDEV(PP_MAJOR, port->number)); | 761 | device_destroy(ppdev_class, MKDEV(PP_MAJOR, port->number)); |
762 | } | 762 | } |
763 | 763 | ||
764 | static struct parport_driver pp_driver = { | 764 | static struct parport_driver pp_driver = { |
diff --git a/drivers/char/random.c b/drivers/char/random.c index eb6b13f4211a..4c6782a1ecdb 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c | |||
@@ -1422,9 +1422,9 @@ static struct keydata { | |||
1422 | 1422 | ||
1423 | static unsigned int ip_cnt; | 1423 | static unsigned int ip_cnt; |
1424 | 1424 | ||
1425 | static void rekey_seq_generator(void *private_); | 1425 | static void rekey_seq_generator(struct work_struct *work); |
1426 | 1426 | ||
1427 | static DECLARE_WORK(rekey_work, rekey_seq_generator, NULL); | 1427 | static DECLARE_DELAYED_WORK(rekey_work, rekey_seq_generator); |
1428 | 1428 | ||
1429 | /* | 1429 | /* |
1430 | * Lock avoidance: | 1430 | * Lock avoidance: |
@@ -1438,7 +1438,7 @@ static DECLARE_WORK(rekey_work, rekey_seq_generator, NULL); | |||
1438 | * happen, and even if that happens only a not perfectly compliant | 1438 | * happen, and even if that happens only a not perfectly compliant |
1439 | * ISN is generated, nothing fatal. | 1439 | * ISN is generated, nothing fatal. |
1440 | */ | 1440 | */ |
1441 | static void rekey_seq_generator(void *private_) | 1441 | static void rekey_seq_generator(struct work_struct *work) |
1442 | { | 1442 | { |
1443 | struct keydata *keyptr = &ip_keydata[1 ^ (ip_cnt & 1)]; | 1443 | struct keydata *keyptr = &ip_keydata[1 ^ (ip_cnt & 1)]; |
1444 | 1444 | ||
@@ -1466,8 +1466,8 @@ static __init int seqgen_init(void) | |||
1466 | late_initcall(seqgen_init); | 1466 | late_initcall(seqgen_init); |
1467 | 1467 | ||
1468 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 1468 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
1469 | __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, | 1469 | __u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr, |
1470 | __u16 sport, __u16 dport) | 1470 | __be16 sport, __be16 dport) |
1471 | { | 1471 | { |
1472 | struct timeval tv; | 1472 | struct timeval tv; |
1473 | __u32 seq; | 1473 | __u32 seq; |
@@ -1479,10 +1479,10 @@ __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, | |||
1479 | */ | 1479 | */ |
1480 | 1480 | ||
1481 | memcpy(hash, saddr, 16); | 1481 | memcpy(hash, saddr, 16); |
1482 | hash[4]=(sport << 16) + dport; | 1482 | hash[4]=((__force u16)sport << 16) + (__force u16)dport; |
1483 | memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7); | 1483 | memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7); |
1484 | 1484 | ||
1485 | seq = twothirdsMD4Transform(daddr, hash) & HASH_MASK; | 1485 | seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK; |
1486 | seq += keyptr->count; | 1486 | seq += keyptr->count; |
1487 | 1487 | ||
1488 | do_gettimeofday(&tv); | 1488 | do_gettimeofday(&tv); |
@@ -1496,7 +1496,7 @@ EXPORT_SYMBOL(secure_tcpv6_sequence_number); | |||
1496 | /* The code below is shamelessly stolen from secure_tcp_sequence_number(). | 1496 | /* The code below is shamelessly stolen from secure_tcp_sequence_number(). |
1497 | * All blames to Andrey V. Savochkin <saw@msu.ru>. | 1497 | * All blames to Andrey V. Savochkin <saw@msu.ru>. |
1498 | */ | 1498 | */ |
1499 | __u32 secure_ip_id(__u32 daddr) | 1499 | __u32 secure_ip_id(__be32 daddr) |
1500 | { | 1500 | { |
1501 | struct keydata *keyptr; | 1501 | struct keydata *keyptr; |
1502 | __u32 hash[4]; | 1502 | __u32 hash[4]; |
@@ -1508,7 +1508,7 @@ __u32 secure_ip_id(__u32 daddr) | |||
1508 | * The dest ip address is placed in the starting vector, | 1508 | * The dest ip address is placed in the starting vector, |
1509 | * which is then hashed with random data. | 1509 | * which is then hashed with random data. |
1510 | */ | 1510 | */ |
1511 | hash[0] = daddr; | 1511 | hash[0] = (__force __u32)daddr; |
1512 | hash[1] = keyptr->secret[9]; | 1512 | hash[1] = keyptr->secret[9]; |
1513 | hash[2] = keyptr->secret[10]; | 1513 | hash[2] = keyptr->secret[10]; |
1514 | hash[3] = keyptr->secret[11]; | 1514 | hash[3] = keyptr->secret[11]; |
@@ -1518,8 +1518,8 @@ __u32 secure_ip_id(__u32 daddr) | |||
1518 | 1518 | ||
1519 | #ifdef CONFIG_INET | 1519 | #ifdef CONFIG_INET |
1520 | 1520 | ||
1521 | __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, | 1521 | __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, |
1522 | __u16 sport, __u16 dport) | 1522 | __be16 sport, __be16 dport) |
1523 | { | 1523 | { |
1524 | struct timeval tv; | 1524 | struct timeval tv; |
1525 | __u32 seq; | 1525 | __u32 seq; |
@@ -1532,9 +1532,9 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, | |||
1532 | * Note that the words are placed into the starting vector, which is | 1532 | * Note that the words are placed into the starting vector, which is |
1533 | * then mixed with a partial MD4 over random data. | 1533 | * then mixed with a partial MD4 over random data. |
1534 | */ | 1534 | */ |
1535 | hash[0]=saddr; | 1535 | hash[0]=(__force u32)saddr; |
1536 | hash[1]=daddr; | 1536 | hash[1]=(__force u32)daddr; |
1537 | hash[2]=(sport << 16) + dport; | 1537 | hash[2]=((__force u16)sport << 16) + (__force u16)dport; |
1538 | hash[3]=keyptr->secret[11]; | 1538 | hash[3]=keyptr->secret[11]; |
1539 | 1539 | ||
1540 | seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK; | 1540 | seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK; |
@@ -1559,7 +1559,7 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, | |||
1559 | EXPORT_SYMBOL(secure_tcp_sequence_number); | 1559 | EXPORT_SYMBOL(secure_tcp_sequence_number); |
1560 | 1560 | ||
1561 | /* Generate secure starting point for ephemeral IPV4 transport port search */ | 1561 | /* Generate secure starting point for ephemeral IPV4 transport port search */ |
1562 | u32 secure_ipv4_port_ephemeral(__u32 saddr, __u32 daddr, __u16 dport) | 1562 | u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) |
1563 | { | 1563 | { |
1564 | struct keydata *keyptr = get_keyptr(); | 1564 | struct keydata *keyptr = get_keyptr(); |
1565 | u32 hash[4]; | 1565 | u32 hash[4]; |
@@ -1568,25 +1568,25 @@ u32 secure_ipv4_port_ephemeral(__u32 saddr, __u32 daddr, __u16 dport) | |||
1568 | * Pick a unique starting offset for each ephemeral port search | 1568 | * Pick a unique starting offset for each ephemeral port search |
1569 | * (saddr, daddr, dport) and 48bits of random data. | 1569 | * (saddr, daddr, dport) and 48bits of random data. |
1570 | */ | 1570 | */ |
1571 | hash[0] = saddr; | 1571 | hash[0] = (__force u32)saddr; |
1572 | hash[1] = daddr; | 1572 | hash[1] = (__force u32)daddr; |
1573 | hash[2] = dport ^ keyptr->secret[10]; | 1573 | hash[2] = (__force u32)dport ^ keyptr->secret[10]; |
1574 | hash[3] = keyptr->secret[11]; | 1574 | hash[3] = keyptr->secret[11]; |
1575 | 1575 | ||
1576 | return half_md4_transform(hash, keyptr->secret); | 1576 | return half_md4_transform(hash, keyptr->secret); |
1577 | } | 1577 | } |
1578 | 1578 | ||
1579 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 1579 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
1580 | u32 secure_ipv6_port_ephemeral(const __u32 *saddr, const __u32 *daddr, __u16 dport) | 1580 | u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, __be16 dport) |
1581 | { | 1581 | { |
1582 | struct keydata *keyptr = get_keyptr(); | 1582 | struct keydata *keyptr = get_keyptr(); |
1583 | u32 hash[12]; | 1583 | u32 hash[12]; |
1584 | 1584 | ||
1585 | memcpy(hash, saddr, 16); | 1585 | memcpy(hash, saddr, 16); |
1586 | hash[4] = dport; | 1586 | hash[4] = (__force u32)dport; |
1587 | memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7); | 1587 | memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7); |
1588 | 1588 | ||
1589 | return twothirdsMD4Transform(daddr, hash); | 1589 | return twothirdsMD4Transform((const __u32 *)daddr, hash); |
1590 | } | 1590 | } |
1591 | #endif | 1591 | #endif |
1592 | 1592 | ||
@@ -1595,17 +1595,17 @@ u32 secure_ipv6_port_ephemeral(const __u32 *saddr, const __u32 *daddr, __u16 dpo | |||
1595 | * bit's 32-47 increase every key exchange | 1595 | * bit's 32-47 increase every key exchange |
1596 | * 0-31 hash(source, dest) | 1596 | * 0-31 hash(source, dest) |
1597 | */ | 1597 | */ |
1598 | u64 secure_dccp_sequence_number(__u32 saddr, __u32 daddr, | 1598 | u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, |
1599 | __u16 sport, __u16 dport) | 1599 | __be16 sport, __be16 dport) |
1600 | { | 1600 | { |
1601 | struct timeval tv; | 1601 | struct timeval tv; |
1602 | u64 seq; | 1602 | u64 seq; |
1603 | __u32 hash[4]; | 1603 | __u32 hash[4]; |
1604 | struct keydata *keyptr = get_keyptr(); | 1604 | struct keydata *keyptr = get_keyptr(); |
1605 | 1605 | ||
1606 | hash[0] = saddr; | 1606 | hash[0] = (__force u32)saddr; |
1607 | hash[1] = daddr; | 1607 | hash[1] = (__force u32)daddr; |
1608 | hash[2] = (sport << 16) + dport; | 1608 | hash[2] = ((__force u16)sport << 16) + (__force u16)dport; |
1609 | hash[3] = keyptr->secret[11]; | 1609 | hash[3] = keyptr->secret[11]; |
1610 | 1610 | ||
1611 | seq = half_md4_transform(hash, keyptr->secret); | 1611 | seq = half_md4_transform(hash, keyptr->secret); |
@@ -1641,7 +1641,7 @@ unsigned int get_random_int(void) | |||
1641 | * drain on it), and uses halfMD4Transform within the second. We | 1641 | * drain on it), and uses halfMD4Transform within the second. We |
1642 | * also mix it with jiffies and the PID: | 1642 | * also mix it with jiffies and the PID: |
1643 | */ | 1643 | */ |
1644 | return secure_ip_id(current->pid + jiffies); | 1644 | return secure_ip_id((__force __be32)(current->pid + jiffies)); |
1645 | } | 1645 | } |
1646 | 1646 | ||
1647 | /* | 1647 | /* |
diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 89b718e326e5..3b32313f6eb4 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c | |||
@@ -127,9 +127,9 @@ raw_ioctl(struct inode *inode, struct file *filp, | |||
127 | 127 | ||
128 | static void bind_device(struct raw_config_request *rq) | 128 | static void bind_device(struct raw_config_request *rq) |
129 | { | 129 | { |
130 | class_device_destroy(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor)); | 130 | device_destroy(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor)); |
131 | class_device_create(raw_class, NULL, MKDEV(RAW_MAJOR, rq->raw_minor), | 131 | device_create(raw_class, NULL, MKDEV(RAW_MAJOR, rq->raw_minor), |
132 | NULL, "raw%d", rq->raw_minor); | 132 | "raw%d", rq->raw_minor); |
133 | } | 133 | } |
134 | 134 | ||
135 | /* | 135 | /* |
@@ -200,7 +200,7 @@ static int raw_ctl_ioctl(struct inode *inode, struct file *filp, | |||
200 | if (rq.block_major == 0 && rq.block_minor == 0) { | 200 | if (rq.block_major == 0 && rq.block_minor == 0) { |
201 | /* unbind */ | 201 | /* unbind */ |
202 | rawdev->binding = NULL; | 202 | rawdev->binding = NULL; |
203 | class_device_destroy(raw_class, | 203 | device_destroy(raw_class, |
204 | MKDEV(RAW_MAJOR, rq.raw_minor)); | 204 | MKDEV(RAW_MAJOR, rq.raw_minor)); |
205 | } else { | 205 | } else { |
206 | rawdev->binding = bdget(dev); | 206 | rawdev->binding = bdget(dev); |
@@ -283,7 +283,7 @@ static int __init raw_init(void) | |||
283 | ret = PTR_ERR(raw_class); | 283 | ret = PTR_ERR(raw_class); |
284 | goto error_region; | 284 | goto error_region; |
285 | } | 285 | } |
286 | class_device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); | 286 | device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), "rawctl"); |
287 | 287 | ||
288 | return 0; | 288 | return 0; |
289 | 289 | ||
@@ -295,7 +295,7 @@ error: | |||
295 | 295 | ||
296 | static void __exit raw_exit(void) | 296 | static void __exit raw_exit(void) |
297 | { | 297 | { |
298 | class_device_destroy(raw_class, MKDEV(RAW_MAJOR, 0)); | 298 | device_destroy(raw_class, MKDEV(RAW_MAJOR, 0)); |
299 | class_destroy(raw_class); | 299 | class_destroy(raw_class); |
300 | cdev_del(&raw_cdev); | 300 | cdev_del(&raw_cdev); |
301 | unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), MAX_RAW_MINORS); | 301 | unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), MAX_RAW_MINORS); |
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 7ac68cb3bedd..e79b2ede8510 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c | |||
@@ -1026,6 +1026,7 @@ static int __init rio_init(void) | |||
1026 | found++; | 1026 | found++; |
1027 | } else { | 1027 | } else { |
1028 | iounmap(p->RIOHosts[p->RIONumHosts].Caddr); | 1028 | iounmap(p->RIOHosts[p->RIONumHosts].Caddr); |
1029 | p->RIOHosts[p->RIONumHosts].Caddr = NULL; | ||
1029 | } | 1030 | } |
1030 | } | 1031 | } |
1031 | 1032 | ||
@@ -1078,6 +1079,7 @@ static int __init rio_init(void) | |||
1078 | found++; | 1079 | found++; |
1079 | } else { | 1080 | } else { |
1080 | iounmap(p->RIOHosts[p->RIONumHosts].Caddr); | 1081 | iounmap(p->RIOHosts[p->RIONumHosts].Caddr); |
1082 | p->RIOHosts[p->RIONumHosts].Caddr = NULL; | ||
1081 | } | 1083 | } |
1082 | #else | 1084 | #else |
1083 | printk(KERN_ERR "Found an older RIO PCI card, but the driver is not " "compiled to support it.\n"); | 1085 | 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) | |||
1117 | } | 1119 | } |
1118 | } | 1120 | } |
1119 | 1121 | ||
1120 | if (!okboard) | 1122 | if (!okboard) { |
1121 | iounmap(hp->Caddr); | 1123 | iounmap(hp->Caddr); |
1124 | hp->Caddr = NULL; | ||
1125 | } | ||
1122 | } | 1126 | } |
1123 | } | 1127 | } |
1124 | 1128 | ||
@@ -1188,6 +1192,8 @@ static void __exit rio_exit(void) | |||
1188 | } | 1192 | } |
1189 | /* It is safe/allowed to del_timer a non-active timer */ | 1193 | /* It is safe/allowed to del_timer a non-active timer */ |
1190 | del_timer(&hp->timer); | 1194 | del_timer(&hp->timer); |
1195 | if (hp->Caddr) | ||
1196 | iounmap(hp->Caddr); | ||
1191 | if (hp->Type == RIO_PCI) | 1197 | if (hp->Type == RIO_PCI) |
1192 | pci_dev_put(hp->pdev); | 1198 | pci_dev_put(hp->pdev); |
1193 | } | 1199 | } |
diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c index 4df6ab2206a1..167ebc84e8d7 100644 --- a/drivers/char/rio/riocmd.c +++ b/drivers/char/rio/riocmd.c | |||
@@ -922,7 +922,7 @@ int RIOUnUse(unsigned long iPortP, struct CmdBlk *CmdBlkP) | |||
922 | ** | 922 | ** |
923 | ** Packet is an actual packet structure to be filled in with the packet | 923 | ** Packet is an actual packet structure to be filled in with the packet |
924 | ** information associated with the command. You need to fill in everything, | 924 | ** information associated with the command. You need to fill in everything, |
925 | ** as the command processore doesn't process the command packet in any way. | 925 | ** as the command processor doesn't process the command packet in any way. |
926 | ** | 926 | ** |
927 | ** The PreFuncP is called before the packet is enqueued on the host rup. | 927 | ** The PreFuncP is called before the packet is enqueued on the host rup. |
928 | ** PreFuncP is called as (*PreFuncP)(PreArg, CmdBlkP);. PreFuncP must | 928 | ** PreFuncP is called as (*PreFuncP)(PreArg, CmdBlkP);. PreFuncP must |
diff --git a/drivers/char/rio/rioinit.c b/drivers/char/rio/rioinit.c index 99f3df02b61c..0794844369d6 100644 --- a/drivers/char/rio/rioinit.c +++ b/drivers/char/rio/rioinit.c | |||
@@ -222,7 +222,7 @@ int RIOBoardTest(unsigned long paddr, void __iomem *caddr, unsigned char type, i | |||
222 | ** which value will be written into memory. | 222 | ** which value will be written into memory. |
223 | ** Call with op set to zero means that the RAM will not be read and checked | 223 | ** Call with op set to zero means that the RAM will not be read and checked |
224 | ** before it is written. | 224 | ** before it is written. |
225 | ** Call with op not zero, and the RAM will be read and compated with val[op-1] | 225 | ** Call with op not zero and the RAM will be read and compared with val[op-1] |
226 | ** to check that the data from the previous phase was retained. | 226 | ** to check that the data from the previous phase was retained. |
227 | */ | 227 | */ |
228 | 228 | ||
diff --git a/drivers/char/rio/rioparam.c b/drivers/char/rio/rioparam.c index 1066d9760704..bb498d24adcc 100644 --- a/drivers/char/rio/rioparam.c +++ b/drivers/char/rio/rioparam.c | |||
@@ -87,8 +87,8 @@ static char *_rioparam_c_sccs_ = "@(#)rioparam.c 1.3"; | |||
87 | ** command bit set onto the port. The command bit is in the len field, | 87 | ** command bit set onto the port. The command bit is in the len field, |
88 | ** and gets ORed in with the actual byte count. | 88 | ** and gets ORed in with the actual byte count. |
89 | ** | 89 | ** |
90 | ** When you send a packet with the command bit set, then the first | 90 | ** When you send a packet with the command bit set the first |
91 | ** data byte ( data[0] ) is interpretted as the command to execute. | 91 | ** data byte (data[0]) is interpreted as the command to execute. |
92 | ** It also governs what data structure overlay should accompany the packet. | 92 | ** It also governs what data structure overlay should accompany the packet. |
93 | ** Commands are defined in cirrus/cirrus.h | 93 | ** Commands are defined in cirrus/cirrus.h |
94 | ** | 94 | ** |
@@ -103,7 +103,7 @@ static char *_rioparam_c_sccs_ = "@(#)rioparam.c 1.3"; | |||
103 | ** | 103 | ** |
104 | ** Most commands do not use the remaining bytes in the data array. The | 104 | ** Most commands do not use the remaining bytes in the data array. The |
105 | ** exceptions are OPEN MOPEN and CONFIG. (NB. As with the SI CONFIG and | 105 | ** exceptions are OPEN MOPEN and CONFIG. (NB. As with the SI CONFIG and |
106 | ** OPEN are currently analagous). With these three commands the following | 106 | ** OPEN are currently analogous). With these three commands the following |
107 | ** 11 data bytes are all used to pass config information such as baud rate etc. | 107 | ** 11 data bytes are all used to pass config information such as baud rate etc. |
108 | ** The fields are also defined in cirrus.h. Some contain straightforward | 108 | ** The fields are also defined in cirrus.h. Some contain straightforward |
109 | ** information such as the transmit XON character. Two contain the transmit and | 109 | ** information such as the transmit XON character. Two contain the transmit and |
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 5ab32b38f45a..0a77bfcd5b5e 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c | |||
@@ -82,11 +82,6 @@ | |||
82 | static struct riscom_board * IRQ_to_board[16]; | 82 | static struct riscom_board * IRQ_to_board[16]; |
83 | static struct tty_driver *riscom_driver; | 83 | static struct tty_driver *riscom_driver; |
84 | 84 | ||
85 | static unsigned long baud_table[] = { | ||
86 | 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, | ||
87 | 9600, 19200, 38400, 57600, 76800, 0, | ||
88 | }; | ||
89 | |||
90 | static struct riscom_board rc_board[RC_NBOARD] = { | 85 | static struct riscom_board rc_board[RC_NBOARD] = { |
91 | { | 86 | { |
92 | .base = RC_IOBASE1, | 87 | .base = RC_IOBASE1, |
@@ -1516,9 +1511,9 @@ static void rc_start(struct tty_struct * tty) | |||
1516 | * do_rc_hangup() -> tty->hangup() -> rc_hangup() | 1511 | * do_rc_hangup() -> tty->hangup() -> rc_hangup() |
1517 | * | 1512 | * |
1518 | */ | 1513 | */ |
1519 | static void do_rc_hangup(void *private_) | 1514 | static void do_rc_hangup(struct work_struct *ugly_api) |
1520 | { | 1515 | { |
1521 | struct riscom_port *port = (struct riscom_port *) private_; | 1516 | struct riscom_port *port = container_of(ugly_api, struct riscom_port, tqueue_hangup); |
1522 | struct tty_struct *tty; | 1517 | struct tty_struct *tty; |
1523 | 1518 | ||
1524 | tty = port->tty; | 1519 | tty = port->tty; |
@@ -1567,9 +1562,9 @@ static void rc_set_termios(struct tty_struct * tty, struct termios * old_termios | |||
1567 | } | 1562 | } |
1568 | } | 1563 | } |
1569 | 1564 | ||
1570 | static void do_softint(void *private_) | 1565 | static void do_softint(struct work_struct *ugly_api) |
1571 | { | 1566 | { |
1572 | struct riscom_port *port = (struct riscom_port *) private_; | 1567 | struct riscom_port *port = container_of(ugly_api, struct riscom_port, tqueue); |
1573 | struct tty_struct *tty; | 1568 | struct tty_struct *tty; |
1574 | 1569 | ||
1575 | if(!(tty = port->tty)) | 1570 | if(!(tty = port->tty)) |
@@ -1632,8 +1627,8 @@ static inline int rc_init_drivers(void) | |||
1632 | memset(rc_port, 0, sizeof(rc_port)); | 1627 | memset(rc_port, 0, sizeof(rc_port)); |
1633 | for (i = 0; i < RC_NPORT * RC_NBOARD; i++) { | 1628 | for (i = 0; i < RC_NPORT * RC_NBOARD; i++) { |
1634 | rc_port[i].magic = RISCOM8_MAGIC; | 1629 | rc_port[i].magic = RISCOM8_MAGIC; |
1635 | INIT_WORK(&rc_port[i].tqueue, do_softint, &rc_port[i]); | 1630 | INIT_WORK(&rc_port[i].tqueue, do_softint); |
1636 | INIT_WORK(&rc_port[i].tqueue_hangup, do_rc_hangup, &rc_port[i]); | 1631 | INIT_WORK(&rc_port[i].tqueue_hangup, do_rc_hangup); |
1637 | rc_port[i].close_delay = 50 * HZ/100; | 1632 | rc_port[i].close_delay = 50 * HZ/100; |
1638 | rc_port[i].closing_wait = 3000 * HZ/100; | 1633 | rc_port[i].closing_wait = 3000 * HZ/100; |
1639 | init_waitqueue_head(&rc_port[i].open_wait); | 1634 | init_waitqueue_head(&rc_port[i].open_wait); |
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index 3af7f0958c5d..9ba13af234be 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c | |||
@@ -706,9 +706,9 @@ cd2401_rx_interrupt(int irq, void *dev_id) | |||
706 | * had to poll every port to see if that port needed servicing. | 706 | * had to poll every port to see if that port needed servicing. |
707 | */ | 707 | */ |
708 | static void | 708 | static void |
709 | do_softint(void *private_) | 709 | do_softint(struct work_struct *ugly_api) |
710 | { | 710 | { |
711 | struct cyclades_port *info = (struct cyclades_port *) private_; | 711 | struct cyclades_port *info = container_of(ugly_api, struct cyclades_port, tqueue); |
712 | struct tty_struct *tty; | 712 | struct tty_struct *tty; |
713 | 713 | ||
714 | tty = info->tty; | 714 | tty = info->tty; |
@@ -2273,7 +2273,7 @@ scrn[1] = '\0'; | |||
2273 | info->blocked_open = 0; | 2273 | info->blocked_open = 0; |
2274 | info->default_threshold = 0; | 2274 | info->default_threshold = 0; |
2275 | info->default_timeout = 0; | 2275 | info->default_timeout = 0; |
2276 | INIT_WORK(&info->tqueue, do_softint, info); | 2276 | INIT_WORK(&info->tqueue, do_softint); |
2277 | init_waitqueue_head(&info->open_wait); | 2277 | init_waitqueue_head(&info->open_wait); |
2278 | init_waitqueue_head(&info->close_wait); | 2278 | init_waitqueue_head(&info->close_wait); |
2279 | /* info->session */ | 2279 | /* info->session */ |
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index c084149153de..fc87070f1866 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c | |||
@@ -765,7 +765,7 @@ static void sonypi_setbluetoothpower(u8 state) | |||
765 | sonypi_device.bluetooth_power = state; | 765 | sonypi_device.bluetooth_power = state; |
766 | } | 766 | } |
767 | 767 | ||
768 | static void input_keyrelease(void *data) | 768 | static void input_keyrelease(struct work_struct *work) |
769 | { | 769 | { |
770 | struct sonypi_keypress kp; | 770 | struct sonypi_keypress kp; |
771 | 771 | ||
@@ -1412,7 +1412,7 @@ static int __devinit sonypi_probe(struct platform_device *dev) | |||
1412 | goto err_inpdev_unregister; | 1412 | goto err_inpdev_unregister; |
1413 | } | 1413 | } |
1414 | 1414 | ||
1415 | INIT_WORK(&sonypi_device.input_work, input_keyrelease, NULL); | 1415 | INIT_WORK(&sonypi_device.input_work, input_keyrelease); |
1416 | } | 1416 | } |
1417 | 1417 | ||
1418 | sonypi_enable(0); | 1418 | sonypi_enable(0); |
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index 7e1bd9562c2a..99137ab66b62 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c | |||
@@ -2261,9 +2261,10 @@ static void sx_start(struct tty_struct * tty) | |||
2261 | * do_sx_hangup() -> tty->hangup() -> sx_hangup() | 2261 | * do_sx_hangup() -> tty->hangup() -> sx_hangup() |
2262 | * | 2262 | * |
2263 | */ | 2263 | */ |
2264 | static void do_sx_hangup(void *private_) | 2264 | static void do_sx_hangup(struct work_struct *work) |
2265 | { | 2265 | { |
2266 | struct specialix_port *port = (struct specialix_port *) private_; | 2266 | struct specialix_port *port = |
2267 | container_of(work, struct specialix_port, tqueue_hangup); | ||
2267 | struct tty_struct *tty; | 2268 | struct tty_struct *tty; |
2268 | 2269 | ||
2269 | func_enter(); | 2270 | func_enter(); |
@@ -2336,9 +2337,10 @@ static void sx_set_termios(struct tty_struct * tty, struct termios * old_termios | |||
2336 | } | 2337 | } |
2337 | 2338 | ||
2338 | 2339 | ||
2339 | static void do_softint(void *private_) | 2340 | static void do_softint(struct work_struct *work) |
2340 | { | 2341 | { |
2341 | struct specialix_port *port = (struct specialix_port *) private_; | 2342 | struct specialix_port *port = |
2343 | container_of(work, struct specialix_port, tqueue); | ||
2342 | struct tty_struct *tty; | 2344 | struct tty_struct *tty; |
2343 | 2345 | ||
2344 | func_enter(); | 2346 | func_enter(); |
@@ -2411,8 +2413,8 @@ static int sx_init_drivers(void) | |||
2411 | memset(sx_port, 0, sizeof(sx_port)); | 2413 | memset(sx_port, 0, sizeof(sx_port)); |
2412 | for (i = 0; i < SX_NPORT * SX_NBOARD; i++) { | 2414 | for (i = 0; i < SX_NPORT * SX_NBOARD; i++) { |
2413 | sx_port[i].magic = SPECIALIX_MAGIC; | 2415 | sx_port[i].magic = SPECIALIX_MAGIC; |
2414 | INIT_WORK(&sx_port[i].tqueue, do_softint, &sx_port[i]); | 2416 | INIT_WORK(&sx_port[i].tqueue, do_softint); |
2415 | INIT_WORK(&sx_port[i].tqueue_hangup, do_sx_hangup, &sx_port[i]); | 2417 | INIT_WORK(&sx_port[i].tqueue_hangup, do_sx_hangup); |
2416 | sx_port[i].close_delay = 50 * HZ/100; | 2418 | sx_port[i].close_delay = 50 * HZ/100; |
2417 | sx_port[i].closing_wait = 3000 * HZ/100; | 2419 | sx_port[i].closing_wait = 3000 * HZ/100; |
2418 | init_waitqueue_head(&sx_port[i].open_wait); | 2420 | init_waitqueue_head(&sx_port[i].open_wait); |
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 522e88e395cc..5e2de62bce70 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c | |||
@@ -500,7 +500,7 @@ static int stl_echatintr(stlbrd_t *brdp); | |||
500 | static int stl_echmcaintr(stlbrd_t *brdp); | 500 | static int stl_echmcaintr(stlbrd_t *brdp); |
501 | static int stl_echpciintr(stlbrd_t *brdp); | 501 | static int stl_echpciintr(stlbrd_t *brdp); |
502 | static int stl_echpci64intr(stlbrd_t *brdp); | 502 | static int stl_echpci64intr(stlbrd_t *brdp); |
503 | static void stl_offintr(void *private); | 503 | static void stl_offintr(struct work_struct *); |
504 | static stlbrd_t *stl_allocbrd(void); | 504 | static stlbrd_t *stl_allocbrd(void); |
505 | static stlport_t *stl_getport(int brdnr, int panelnr, int portnr); | 505 | static stlport_t *stl_getport(int brdnr, int panelnr, int portnr); |
506 | 506 | ||
@@ -2081,14 +2081,12 @@ static int stl_echpci64intr(stlbrd_t *brdp) | |||
2081 | /* | 2081 | /* |
2082 | * Service an off-level request for some channel. | 2082 | * Service an off-level request for some channel. |
2083 | */ | 2083 | */ |
2084 | static void stl_offintr(void *private) | 2084 | static void stl_offintr(struct work_struct *work) |
2085 | { | 2085 | { |
2086 | stlport_t *portp; | 2086 | stlport_t *portp = container_of(work, stlport_t, tqueue); |
2087 | struct tty_struct *tty; | 2087 | struct tty_struct *tty; |
2088 | unsigned int oldsigs; | 2088 | unsigned int oldsigs; |
2089 | 2089 | ||
2090 | portp = private; | ||
2091 | |||
2092 | #ifdef DEBUG | 2090 | #ifdef DEBUG |
2093 | printk("stl_offintr(portp=%x)\n", (int) portp); | 2091 | printk("stl_offintr(portp=%x)\n", (int) portp); |
2094 | #endif | 2092 | #endif |
@@ -2156,7 +2154,7 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) | |||
2156 | portp->baud_base = STL_BAUDBASE; | 2154 | portp->baud_base = STL_BAUDBASE; |
2157 | portp->close_delay = STL_CLOSEDELAY; | 2155 | portp->close_delay = STL_CLOSEDELAY; |
2158 | portp->closing_wait = 30 * HZ; | 2156 | portp->closing_wait = 30 * HZ; |
2159 | INIT_WORK(&portp->tqueue, stl_offintr, portp); | 2157 | INIT_WORK(&portp->tqueue, stl_offintr); |
2160 | init_waitqueue_head(&portp->open_wait); | 2158 | init_waitqueue_head(&portp->open_wait); |
2161 | init_waitqueue_head(&portp->close_wait); | 2159 | init_waitqueue_head(&portp->close_wait); |
2162 | portp->stats.brd = portp->brdnr; | 2160 | portp->stats.brd = portp->brdnr; |
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 06784adcc35c..645187b9141e 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c | |||
@@ -101,8 +101,10 @@ | |||
101 | #include <linux/hdlc.h> | 101 | #include <linux/hdlc.h> |
102 | #include <linux/dma-mapping.h> | 102 | #include <linux/dma-mapping.h> |
103 | 103 | ||
104 | #ifdef CONFIG_HDLC_MODULE | 104 | #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_MODULE)) |
105 | #define CONFIG_HDLC 1 | 105 | #define SYNCLINK_GENERIC_HDLC 1 |
106 | #else | ||
107 | #define SYNCLINK_GENERIC_HDLC 0 | ||
106 | #endif | 108 | #endif |
107 | 109 | ||
108 | #define GET_USER(error,value,addr) error = get_user(value,addr) | 110 | #define GET_USER(error,value,addr) error = get_user(value,addr) |
@@ -320,7 +322,7 @@ struct mgsl_struct { | |||
320 | int dosyncppp; | 322 | int dosyncppp; |
321 | spinlock_t netlock; | 323 | spinlock_t netlock; |
322 | 324 | ||
323 | #ifdef CONFIG_HDLC | 325 | #if SYNCLINK_GENERIC_HDLC |
324 | struct net_device *netdev; | 326 | struct net_device *netdev; |
325 | #endif | 327 | #endif |
326 | }; | 328 | }; |
@@ -728,7 +730,7 @@ static void usc_loopmode_send_done( struct mgsl_struct * info ); | |||
728 | 730 | ||
729 | static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg); | 731 | static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg); |
730 | 732 | ||
731 | #ifdef CONFIG_HDLC | 733 | #if SYNCLINK_GENERIC_HDLC |
732 | #define dev_to_port(D) (dev_to_hdlc(D)->priv) | 734 | #define dev_to_port(D) (dev_to_hdlc(D)->priv) |
733 | static void hdlcdev_tx_done(struct mgsl_struct *info); | 735 | static void hdlcdev_tx_done(struct mgsl_struct *info); |
734 | static void hdlcdev_rx(struct mgsl_struct *info, char *buf, int size); | 736 | 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 | |||
802 | /* | 804 | /* |
803 | * Bottom half interrupt handlers | 805 | * Bottom half interrupt handlers |
804 | */ | 806 | */ |
805 | static void mgsl_bh_handler(void* Context); | 807 | static void mgsl_bh_handler(struct work_struct *work); |
806 | static void mgsl_bh_receive(struct mgsl_struct *info); | 808 | static void mgsl_bh_receive(struct mgsl_struct *info); |
807 | static void mgsl_bh_transmit(struct mgsl_struct *info); | 809 | static void mgsl_bh_transmit(struct mgsl_struct *info); |
808 | static void mgsl_bh_status(struct mgsl_struct *info); | 810 | static void mgsl_bh_status(struct mgsl_struct *info); |
@@ -1071,9 +1073,10 @@ static int mgsl_bh_action(struct mgsl_struct *info) | |||
1071 | /* | 1073 | /* |
1072 | * Perform bottom half processing of work items queued by ISR. | 1074 | * Perform bottom half processing of work items queued by ISR. |
1073 | */ | 1075 | */ |
1074 | static void mgsl_bh_handler(void* Context) | 1076 | static void mgsl_bh_handler(struct work_struct *work) |
1075 | { | 1077 | { |
1076 | struct mgsl_struct *info = (struct mgsl_struct*)Context; | 1078 | struct mgsl_struct *info = |
1079 | container_of(work, struct mgsl_struct, task); | ||
1077 | int action; | 1080 | int action; |
1078 | 1081 | ||
1079 | if (!info) | 1082 | if (!info) |
@@ -1276,7 +1279,7 @@ static void mgsl_isr_transmit_status( struct mgsl_struct *info ) | |||
1276 | info->drop_rts_on_tx_done = 0; | 1279 | info->drop_rts_on_tx_done = 0; |
1277 | } | 1280 | } |
1278 | 1281 | ||
1279 | #ifdef CONFIG_HDLC | 1282 | #if SYNCLINK_GENERIC_HDLC |
1280 | if (info->netcount) | 1283 | if (info->netcount) |
1281 | hdlcdev_tx_done(info); | 1284 | hdlcdev_tx_done(info); |
1282 | else | 1285 | else |
@@ -1341,7 +1344,7 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info ) | |||
1341 | info->input_signal_events.dcd_up++; | 1344 | info->input_signal_events.dcd_up++; |
1342 | } else | 1345 | } else |
1343 | info->input_signal_events.dcd_down++; | 1346 | info->input_signal_events.dcd_down++; |
1344 | #ifdef CONFIG_HDLC | 1347 | #if SYNCLINK_GENERIC_HDLC |
1345 | if (info->netcount) { | 1348 | if (info->netcount) { |
1346 | if (status & MISCSTATUS_DCD) | 1349 | if (status & MISCSTATUS_DCD) |
1347 | netif_carrier_on(info->netdev); | 1350 | netif_carrier_on(info->netdev); |
@@ -4312,7 +4315,7 @@ static void mgsl_add_device( struct mgsl_struct *info ) | |||
4312 | info->max_frame_size ); | 4315 | info->max_frame_size ); |
4313 | } | 4316 | } |
4314 | 4317 | ||
4315 | #ifdef CONFIG_HDLC | 4318 | #if SYNCLINK_GENERIC_HDLC |
4316 | hdlcdev_init(info); | 4319 | hdlcdev_init(info); |
4317 | #endif | 4320 | #endif |
4318 | 4321 | ||
@@ -4337,7 +4340,7 @@ static struct mgsl_struct* mgsl_allocate_device(void) | |||
4337 | } else { | 4340 | } else { |
4338 | memset(info, 0, sizeof(struct mgsl_struct)); | 4341 | memset(info, 0, sizeof(struct mgsl_struct)); |
4339 | info->magic = MGSL_MAGIC; | 4342 | info->magic = MGSL_MAGIC; |
4340 | INIT_WORK(&info->task, mgsl_bh_handler, info); | 4343 | INIT_WORK(&info->task, mgsl_bh_handler); |
4341 | info->max_frame_size = 4096; | 4344 | info->max_frame_size = 4096; |
4342 | info->close_delay = 5*HZ/10; | 4345 | info->close_delay = 5*HZ/10; |
4343 | info->closing_wait = 30*HZ; | 4346 | info->closing_wait = 30*HZ; |
@@ -4470,7 +4473,7 @@ static void synclink_cleanup(void) | |||
4470 | 4473 | ||
4471 | info = mgsl_device_list; | 4474 | info = mgsl_device_list; |
4472 | while(info) { | 4475 | while(info) { |
4473 | #ifdef CONFIG_HDLC | 4476 | #if SYNCLINK_GENERIC_HDLC |
4474 | hdlcdev_exit(info); | 4477 | hdlcdev_exit(info); |
4475 | #endif | 4478 | #endif |
4476 | mgsl_release_resources(info); | 4479 | mgsl_release_resources(info); |
@@ -6644,7 +6647,7 @@ static int mgsl_get_rx_frame(struct mgsl_struct *info) | |||
6644 | return_frame = 1; | 6647 | return_frame = 1; |
6645 | } | 6648 | } |
6646 | framesize = 0; | 6649 | framesize = 0; |
6647 | #ifdef CONFIG_HDLC | 6650 | #if SYNCLINK_GENERIC_HDLC |
6648 | { | 6651 | { |
6649 | struct net_device_stats *stats = hdlc_stats(info->netdev); | 6652 | struct net_device_stats *stats = hdlc_stats(info->netdev); |
6650 | stats->rx_errors++; | 6653 | stats->rx_errors++; |
@@ -6720,7 +6723,7 @@ static int mgsl_get_rx_frame(struct mgsl_struct *info) | |||
6720 | *ptmp); | 6723 | *ptmp); |
6721 | } | 6724 | } |
6722 | 6725 | ||
6723 | #ifdef CONFIG_HDLC | 6726 | #if SYNCLINK_GENERIC_HDLC |
6724 | if (info->netcount) | 6727 | if (info->netcount) |
6725 | hdlcdev_rx(info,info->intermediate_rxbuffer,framesize); | 6728 | hdlcdev_rx(info,info->intermediate_rxbuffer,framesize); |
6726 | else | 6729 | else |
@@ -7624,7 +7627,7 @@ static void mgsl_tx_timeout(unsigned long context) | |||
7624 | 7627 | ||
7625 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | 7628 | spin_unlock_irqrestore(&info->irq_spinlock,flags); |
7626 | 7629 | ||
7627 | #ifdef CONFIG_HDLC | 7630 | #if SYNCLINK_GENERIC_HDLC |
7628 | if (info->netcount) | 7631 | if (info->netcount) |
7629 | hdlcdev_tx_done(info); | 7632 | hdlcdev_tx_done(info); |
7630 | else | 7633 | else |
@@ -7700,7 +7703,7 @@ static int usc_loopmode_active( struct mgsl_struct * info) | |||
7700 | return usc_InReg( info, CCSR ) & BIT7 ? 1 : 0 ; | 7703 | return usc_InReg( info, CCSR ) & BIT7 ? 1 : 0 ; |
7701 | } | 7704 | } |
7702 | 7705 | ||
7703 | #ifdef CONFIG_HDLC | 7706 | #if SYNCLINK_GENERIC_HDLC |
7704 | 7707 | ||
7705 | /** | 7708 | /** |
7706 | * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) | 7709 | * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) |
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index d4334c79f8d4..e4730a7312b5 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c | |||
@@ -83,8 +83,10 @@ | |||
83 | 83 | ||
84 | #include "linux/synclink.h" | 84 | #include "linux/synclink.h" |
85 | 85 | ||
86 | #ifdef CONFIG_HDLC_MODULE | 86 | #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_GT_MODULE)) |
87 | #define CONFIG_HDLC 1 | 87 | #define SYNCLINK_GENERIC_HDLC 1 |
88 | #else | ||
89 | #define SYNCLINK_GENERIC_HDLC 0 | ||
88 | #endif | 90 | #endif |
89 | 91 | ||
90 | /* | 92 | /* |
@@ -171,7 +173,7 @@ static void set_break(struct tty_struct *tty, int break_state); | |||
171 | /* | 173 | /* |
172 | * generic HDLC support and callbacks | 174 | * generic HDLC support and callbacks |
173 | */ | 175 | */ |
174 | #ifdef CONFIG_HDLC | 176 | #if SYNCLINK_GENERIC_HDLC |
175 | #define dev_to_port(D) (dev_to_hdlc(D)->priv) | 177 | #define dev_to_port(D) (dev_to_hdlc(D)->priv) |
176 | static void hdlcdev_tx_done(struct slgt_info *info); | 178 | static void hdlcdev_tx_done(struct slgt_info *info); |
177 | static void hdlcdev_rx(struct slgt_info *info, char *buf, int size); | 179 | static void hdlcdev_rx(struct slgt_info *info, char *buf, int size); |
@@ -359,7 +361,7 @@ struct slgt_info { | |||
359 | int netcount; | 361 | int netcount; |
360 | int dosyncppp; | 362 | int dosyncppp; |
361 | spinlock_t netlock; | 363 | spinlock_t netlock; |
362 | #ifdef CONFIG_HDLC | 364 | #if SYNCLINK_GENERIC_HDLC |
363 | struct net_device *netdev; | 365 | struct net_device *netdev; |
364 | #endif | 366 | #endif |
365 | 367 | ||
@@ -485,7 +487,7 @@ static void enable_loopback(struct slgt_info *info); | |||
485 | static void set_rate(struct slgt_info *info, u32 data_rate); | 487 | static void set_rate(struct slgt_info *info, u32 data_rate); |
486 | 488 | ||
487 | static int bh_action(struct slgt_info *info); | 489 | static int bh_action(struct slgt_info *info); |
488 | static void bh_handler(void* context); | 490 | static void bh_handler(struct work_struct *work); |
489 | static void bh_transmit(struct slgt_info *info); | 491 | static void bh_transmit(struct slgt_info *info); |
490 | static void isr_serial(struct slgt_info *info); | 492 | static void isr_serial(struct slgt_info *info); |
491 | static void isr_rdma(struct slgt_info *info); | 493 | static void isr_rdma(struct slgt_info *info); |
@@ -1354,7 +1356,7 @@ static void set_break(struct tty_struct *tty, int break_state) | |||
1354 | spin_unlock_irqrestore(&info->lock,flags); | 1356 | spin_unlock_irqrestore(&info->lock,flags); |
1355 | } | 1357 | } |
1356 | 1358 | ||
1357 | #ifdef CONFIG_HDLC | 1359 | #if SYNCLINK_GENERIC_HDLC |
1358 | 1360 | ||
1359 | /** | 1361 | /** |
1360 | * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) | 1362 | * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) |
@@ -1878,9 +1880,9 @@ static int bh_action(struct slgt_info *info) | |||
1878 | /* | 1880 | /* |
1879 | * perform bottom half processing | 1881 | * perform bottom half processing |
1880 | */ | 1882 | */ |
1881 | static void bh_handler(void* context) | 1883 | static void bh_handler(struct work_struct *work) |
1882 | { | 1884 | { |
1883 | struct slgt_info *info = context; | 1885 | struct slgt_info *info = container_of(work, struct slgt_info, task); |
1884 | int action; | 1886 | int action; |
1885 | 1887 | ||
1886 | if (!info) | 1888 | if (!info) |
@@ -2002,7 +2004,7 @@ static void dcd_change(struct slgt_info *info) | |||
2002 | } else { | 2004 | } else { |
2003 | info->input_signal_events.dcd_down++; | 2005 | info->input_signal_events.dcd_down++; |
2004 | } | 2006 | } |
2005 | #ifdef CONFIG_HDLC | 2007 | #if SYNCLINK_GENERIC_HDLC |
2006 | if (info->netcount) { | 2008 | if (info->netcount) { |
2007 | if (info->signals & SerialSignal_DCD) | 2009 | if (info->signals & SerialSignal_DCD) |
2008 | netif_carrier_on(info->netdev); | 2010 | netif_carrier_on(info->netdev); |
@@ -2180,7 +2182,7 @@ static void isr_txeom(struct slgt_info *info, unsigned short status) | |||
2180 | set_signals(info); | 2182 | set_signals(info); |
2181 | } | 2183 | } |
2182 | 2184 | ||
2183 | #ifdef CONFIG_HDLC | 2185 | #if SYNCLINK_GENERIC_HDLC |
2184 | if (info->netcount) | 2186 | if (info->netcount) |
2185 | hdlcdev_tx_done(info); | 2187 | hdlcdev_tx_done(info); |
2186 | else | 2188 | else |
@@ -3306,7 +3308,7 @@ static void add_device(struct slgt_info *info) | |||
3306 | devstr, info->device_name, info->phys_reg_addr, | 3308 | devstr, info->device_name, info->phys_reg_addr, |
3307 | info->irq_level, info->max_frame_size); | 3309 | info->irq_level, info->max_frame_size); |
3308 | 3310 | ||
3309 | #ifdef CONFIG_HDLC | 3311 | #if SYNCLINK_GENERIC_HDLC |
3310 | hdlcdev_init(info); | 3312 | hdlcdev_init(info); |
3311 | #endif | 3313 | #endif |
3312 | } | 3314 | } |
@@ -3326,7 +3328,7 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev | |||
3326 | } else { | 3328 | } else { |
3327 | memset(info, 0, sizeof(struct slgt_info)); | 3329 | memset(info, 0, sizeof(struct slgt_info)); |
3328 | info->magic = MGSL_MAGIC; | 3330 | info->magic = MGSL_MAGIC; |
3329 | INIT_WORK(&info->task, bh_handler, info); | 3331 | INIT_WORK(&info->task, bh_handler); |
3330 | info->max_frame_size = 4096; | 3332 | info->max_frame_size = 4096; |
3331 | info->raw_rx_size = DMABUFSIZE; | 3333 | info->raw_rx_size = DMABUFSIZE; |
3332 | info->close_delay = 5*HZ/10; | 3334 | info->close_delay = 5*HZ/10; |
@@ -3488,7 +3490,7 @@ static void slgt_cleanup(void) | |||
3488 | /* release devices */ | 3490 | /* release devices */ |
3489 | info = slgt_device_list; | 3491 | info = slgt_device_list; |
3490 | while(info) { | 3492 | while(info) { |
3491 | #ifdef CONFIG_HDLC | 3493 | #if SYNCLINK_GENERIC_HDLC |
3492 | hdlcdev_exit(info); | 3494 | hdlcdev_exit(info); |
3493 | #endif | 3495 | #endif |
3494 | free_dma_bufs(info); | 3496 | free_dma_bufs(info); |
@@ -3522,6 +3524,7 @@ static int __init slgt_init(void) | |||
3522 | 3524 | ||
3523 | if (!slgt_device_list) { | 3525 | if (!slgt_device_list) { |
3524 | printk("%s no devices found\n",driver_name); | 3526 | printk("%s no devices found\n",driver_name); |
3527 | pci_unregister_driver(&pci_driver); | ||
3525 | return -ENODEV; | 3528 | return -ENODEV; |
3526 | } | 3529 | } |
3527 | 3530 | ||
@@ -4433,7 +4436,7 @@ check_again: | |||
4433 | framesize = 0; | 4436 | framesize = 0; |
4434 | } | 4437 | } |
4435 | 4438 | ||
4436 | #ifdef CONFIG_HDLC | 4439 | #if SYNCLINK_GENERIC_HDLC |
4437 | if (framesize == 0) { | 4440 | if (framesize == 0) { |
4438 | struct net_device_stats *stats = hdlc_stats(info->netdev); | 4441 | struct net_device_stats *stats = hdlc_stats(info->netdev); |
4439 | stats->rx_errors++; | 4442 | stats->rx_errors++; |
@@ -4476,7 +4479,7 @@ check_again: | |||
4476 | framesize++; | 4479 | framesize++; |
4477 | } | 4480 | } |
4478 | 4481 | ||
4479 | #ifdef CONFIG_HDLC | 4482 | #if SYNCLINK_GENERIC_HDLC |
4480 | if (info->netcount) | 4483 | if (info->netcount) |
4481 | hdlcdev_rx(info,info->tmp_rbuf, framesize); | 4484 | hdlcdev_rx(info,info->tmp_rbuf, framesize); |
4482 | else | 4485 | else |
@@ -4779,7 +4782,7 @@ static void tx_timeout(unsigned long context) | |||
4779 | info->tx_count = 0; | 4782 | info->tx_count = 0; |
4780 | spin_unlock_irqrestore(&info->lock,flags); | 4783 | spin_unlock_irqrestore(&info->lock,flags); |
4781 | 4784 | ||
4782 | #ifdef CONFIG_HDLC | 4785 | #if SYNCLINK_GENERIC_HDLC |
4783 | if (info->netcount) | 4786 | if (info->netcount) |
4784 | hdlcdev_tx_done(info); | 4787 | hdlcdev_tx_done(info); |
4785 | else | 4788 | else |
@@ -4799,6 +4802,6 @@ static void rx_timeout(unsigned long context) | |||
4799 | spin_lock_irqsave(&info->lock, flags); | 4802 | spin_lock_irqsave(&info->lock, flags); |
4800 | info->pending_bh |= BH_RECEIVE; | 4803 | info->pending_bh |= BH_RECEIVE; |
4801 | spin_unlock_irqrestore(&info->lock, flags); | 4804 | spin_unlock_irqrestore(&info->lock, flags); |
4802 | bh_handler(info); | 4805 | bh_handler(&info->task); |
4803 | } | 4806 | } |
4804 | 4807 | ||
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 3e932b681371..20a96ef250be 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c | |||
@@ -67,8 +67,10 @@ | |||
67 | #include <linux/workqueue.h> | 67 | #include <linux/workqueue.h> |
68 | #include <linux/hdlc.h> | 68 | #include <linux/hdlc.h> |
69 | 69 | ||
70 | #ifdef CONFIG_HDLC_MODULE | 70 | #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINKMP_MODULE)) |
71 | #define CONFIG_HDLC 1 | 71 | #define SYNCLINK_GENERIC_HDLC 1 |
72 | #else | ||
73 | #define SYNCLINK_GENERIC_HDLC 0 | ||
72 | #endif | 74 | #endif |
73 | 75 | ||
74 | #define GET_USER(error,value,addr) error = get_user(value,addr) | 76 | #define GET_USER(error,value,addr) error = get_user(value,addr) |
@@ -280,7 +282,7 @@ typedef struct _synclinkmp_info { | |||
280 | int dosyncppp; | 282 | int dosyncppp; |
281 | spinlock_t netlock; | 283 | spinlock_t netlock; |
282 | 284 | ||
283 | #ifdef CONFIG_HDLC | 285 | #if SYNCLINK_GENERIC_HDLC |
284 | struct net_device *netdev; | 286 | struct net_device *netdev; |
285 | #endif | 287 | #endif |
286 | 288 | ||
@@ -536,7 +538,7 @@ static void throttle(struct tty_struct * tty); | |||
536 | static void unthrottle(struct tty_struct * tty); | 538 | static void unthrottle(struct tty_struct * tty); |
537 | static void set_break(struct tty_struct *tty, int break_state); | 539 | static void set_break(struct tty_struct *tty, int break_state); |
538 | 540 | ||
539 | #ifdef CONFIG_HDLC | 541 | #if SYNCLINK_GENERIC_HDLC |
540 | #define dev_to_port(D) (dev_to_hdlc(D)->priv) | 542 | #define dev_to_port(D) (dev_to_hdlc(D)->priv) |
541 | static void hdlcdev_tx_done(SLMP_INFO *info); | 543 | static void hdlcdev_tx_done(SLMP_INFO *info); |
542 | static void hdlcdev_rx(SLMP_INFO *info, char *buf, int size); | 544 | static void hdlcdev_rx(SLMP_INFO *info, char *buf, int size); |
@@ -602,7 +604,7 @@ static void enable_loopback(SLMP_INFO *info, int enable); | |||
602 | static void set_rate(SLMP_INFO *info, u32 data_rate); | 604 | static void set_rate(SLMP_INFO *info, u32 data_rate); |
603 | 605 | ||
604 | static int bh_action(SLMP_INFO *info); | 606 | static int bh_action(SLMP_INFO *info); |
605 | static void bh_handler(void* Context); | 607 | static void bh_handler(struct work_struct *work); |
606 | static void bh_receive(SLMP_INFO *info); | 608 | static void bh_receive(SLMP_INFO *info); |
607 | static void bh_transmit(SLMP_INFO *info); | 609 | static void bh_transmit(SLMP_INFO *info); |
608 | static void bh_status(SLMP_INFO *info); | 610 | static void bh_status(SLMP_INFO *info); |
@@ -1607,7 +1609,7 @@ static void set_break(struct tty_struct *tty, int break_state) | |||
1607 | spin_unlock_irqrestore(&info->lock,flags); | 1609 | spin_unlock_irqrestore(&info->lock,flags); |
1608 | } | 1610 | } |
1609 | 1611 | ||
1610 | #ifdef CONFIG_HDLC | 1612 | #if SYNCLINK_GENERIC_HDLC |
1611 | 1613 | ||
1612 | /** | 1614 | /** |
1613 | * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) | 1615 | * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) |
@@ -2063,9 +2065,9 @@ int bh_action(SLMP_INFO *info) | |||
2063 | 2065 | ||
2064 | /* Perform bottom half processing of work items queued by ISR. | 2066 | /* Perform bottom half processing of work items queued by ISR. |
2065 | */ | 2067 | */ |
2066 | void bh_handler(void* Context) | 2068 | void bh_handler(struct work_struct *work) |
2067 | { | 2069 | { |
2068 | SLMP_INFO *info = (SLMP_INFO*)Context; | 2070 | SLMP_INFO *info = container_of(work, SLMP_INFO, task); |
2069 | int action; | 2071 | int action; |
2070 | 2072 | ||
2071 | if (!info) | 2073 | if (!info) |
@@ -2339,7 +2341,7 @@ static void isr_txeom(SLMP_INFO * info, unsigned char status) | |||
2339 | set_signals(info); | 2341 | set_signals(info); |
2340 | } | 2342 | } |
2341 | 2343 | ||
2342 | #ifdef CONFIG_HDLC | 2344 | #if SYNCLINK_GENERIC_HDLC |
2343 | if (info->netcount) | 2345 | if (info->netcount) |
2344 | hdlcdev_tx_done(info); | 2346 | hdlcdev_tx_done(info); |
2345 | else | 2347 | else |
@@ -2523,7 +2525,7 @@ void isr_io_pin( SLMP_INFO *info, u16 status ) | |||
2523 | info->input_signal_events.dcd_up++; | 2525 | info->input_signal_events.dcd_up++; |
2524 | } else | 2526 | } else |
2525 | info->input_signal_events.dcd_down++; | 2527 | info->input_signal_events.dcd_down++; |
2526 | #ifdef CONFIG_HDLC | 2528 | #if SYNCLINK_GENERIC_HDLC |
2527 | if (info->netcount) { | 2529 | if (info->netcount) { |
2528 | if (status & SerialSignal_DCD) | 2530 | if (status & SerialSignal_DCD) |
2529 | netif_carrier_on(info->netdev); | 2531 | netif_carrier_on(info->netdev); |
@@ -3783,7 +3785,7 @@ void add_device(SLMP_INFO *info) | |||
3783 | info->irq_level, | 3785 | info->irq_level, |
3784 | info->max_frame_size ); | 3786 | info->max_frame_size ); |
3785 | 3787 | ||
3786 | #ifdef CONFIG_HDLC | 3788 | #if SYNCLINK_GENERIC_HDLC |
3787 | hdlcdev_init(info); | 3789 | hdlcdev_init(info); |
3788 | #endif | 3790 | #endif |
3789 | } | 3791 | } |
@@ -3805,7 +3807,7 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev) | |||
3805 | } else { | 3807 | } else { |
3806 | memset(info, 0, sizeof(SLMP_INFO)); | 3808 | memset(info, 0, sizeof(SLMP_INFO)); |
3807 | info->magic = MGSL_MAGIC; | 3809 | info->magic = MGSL_MAGIC; |
3808 | INIT_WORK(&info->task, bh_handler, info); | 3810 | INIT_WORK(&info->task, bh_handler); |
3809 | info->max_frame_size = 4096; | 3811 | info->max_frame_size = 4096; |
3810 | info->close_delay = 5*HZ/10; | 3812 | info->close_delay = 5*HZ/10; |
3811 | info->closing_wait = 30*HZ; | 3813 | info->closing_wait = 30*HZ; |
@@ -3977,7 +3979,7 @@ static void synclinkmp_cleanup(void) | |||
3977 | /* release devices */ | 3979 | /* release devices */ |
3978 | info = synclinkmp_device_list; | 3980 | info = synclinkmp_device_list; |
3979 | while(info) { | 3981 | while(info) { |
3980 | #ifdef CONFIG_HDLC | 3982 | #if SYNCLINK_GENERIC_HDLC |
3981 | hdlcdev_exit(info); | 3983 | hdlcdev_exit(info); |
3982 | #endif | 3984 | #endif |
3983 | free_dma_bufs(info); | 3985 | free_dma_bufs(info); |
@@ -4979,7 +4981,7 @@ CheckAgain: | |||
4979 | info->icount.rxcrc++; | 4981 | info->icount.rxcrc++; |
4980 | 4982 | ||
4981 | framesize = 0; | 4983 | framesize = 0; |
4982 | #ifdef CONFIG_HDLC | 4984 | #if SYNCLINK_GENERIC_HDLC |
4983 | { | 4985 | { |
4984 | struct net_device_stats *stats = hdlc_stats(info->netdev); | 4986 | struct net_device_stats *stats = hdlc_stats(info->netdev); |
4985 | stats->rx_errors++; | 4987 | stats->rx_errors++; |
@@ -5020,7 +5022,7 @@ CheckAgain: | |||
5020 | index = 0; | 5022 | index = 0; |
5021 | } | 5023 | } |
5022 | 5024 | ||
5023 | #ifdef CONFIG_HDLC | 5025 | #if SYNCLINK_GENERIC_HDLC |
5024 | if (info->netcount) | 5026 | if (info->netcount) |
5025 | hdlcdev_rx(info,info->tmp_rx_buf,framesize); | 5027 | hdlcdev_rx(info,info->tmp_rx_buf,framesize); |
5026 | else | 5028 | else |
@@ -5531,7 +5533,7 @@ void tx_timeout(unsigned long context) | |||
5531 | 5533 | ||
5532 | spin_unlock_irqrestore(&info->lock,flags); | 5534 | spin_unlock_irqrestore(&info->lock,flags); |
5533 | 5535 | ||
5534 | #ifdef CONFIG_HDLC | 5536 | #if SYNCLINK_GENERIC_HDLC |
5535 | if (info->netcount) | 5537 | if (info->netcount) |
5536 | hdlcdev_tx_done(info); | 5538 | hdlcdev_tx_done(info); |
5537 | else | 5539 | else |
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 5f49280779fb..05810c8d20bc 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c | |||
@@ -182,6 +182,18 @@ static struct sysrq_key_op sysrq_showstate_op = { | |||
182 | .enable_mask = SYSRQ_ENABLE_DUMP, | 182 | .enable_mask = SYSRQ_ENABLE_DUMP, |
183 | }; | 183 | }; |
184 | 184 | ||
185 | static void sysrq_handle_showstate_blocked(int key, struct tty_struct *tty) | ||
186 | { | ||
187 | show_state_filter(TASK_UNINTERRUPTIBLE); | ||
188 | } | ||
189 | static struct sysrq_key_op sysrq_showstate_blocked_op = { | ||
190 | .handler = sysrq_handle_showstate_blocked, | ||
191 | .help_msg = "showBlockedTasks", | ||
192 | .action_msg = "Show Blocked State", | ||
193 | .enable_mask = SYSRQ_ENABLE_DUMP, | ||
194 | }; | ||
195 | |||
196 | |||
185 | static void sysrq_handle_showmem(int key, struct tty_struct *tty) | 197 | static void sysrq_handle_showmem(int key, struct tty_struct *tty) |
186 | { | 198 | { |
187 | show_mem(); | 199 | show_mem(); |
@@ -219,13 +231,13 @@ static struct sysrq_key_op sysrq_term_op = { | |||
219 | .enable_mask = SYSRQ_ENABLE_SIGNAL, | 231 | .enable_mask = SYSRQ_ENABLE_SIGNAL, |
220 | }; | 232 | }; |
221 | 233 | ||
222 | static void moom_callback(void *ignored) | 234 | static void moom_callback(struct work_struct *ignored) |
223 | { | 235 | { |
224 | out_of_memory(&NODE_DATA(0)->node_zonelists[ZONE_NORMAL], | 236 | out_of_memory(&NODE_DATA(0)->node_zonelists[ZONE_NORMAL], |
225 | GFP_KERNEL, 0); | 237 | GFP_KERNEL, 0); |
226 | } | 238 | } |
227 | 239 | ||
228 | static DECLARE_WORK(moom_work, moom_callback, NULL); | 240 | static DECLARE_WORK(moom_work, moom_callback); |
229 | 241 | ||
230 | static void sysrq_handle_moom(int key, struct tty_struct *tty) | 242 | static void sysrq_handle_moom(int key, struct tty_struct *tty) |
231 | { | 243 | { |
@@ -304,7 +316,7 @@ static struct sysrq_key_op *sysrq_key_table[36] = { | |||
304 | /* May be assigned at init time by SMP VOYAGER */ | 316 | /* May be assigned at init time by SMP VOYAGER */ |
305 | NULL, /* v */ | 317 | NULL, /* v */ |
306 | NULL, /* w */ | 318 | NULL, /* w */ |
307 | NULL, /* x */ | 319 | &sysrq_showstate_blocked_op, /* x */ |
308 | NULL, /* y */ | 320 | NULL, /* y */ |
309 | NULL /* z */ | 321 | NULL /* z */ |
310 | }; | 322 | }; |
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c index 2444a0e24b31..244d30a03fef 100644 --- a/drivers/char/tlclk.c +++ b/drivers/char/tlclk.c | |||
@@ -792,15 +792,14 @@ static int __init tlclk_init(void) | |||
792 | ret = misc_register(&tlclk_miscdev); | 792 | ret = misc_register(&tlclk_miscdev); |
793 | if (ret < 0) { | 793 | if (ret < 0) { |
794 | printk(KERN_ERR "tlclk: misc_register returns %d.\n", ret); | 794 | printk(KERN_ERR "tlclk: misc_register returns %d.\n", ret); |
795 | ret = -EBUSY; | ||
796 | goto out3; | 795 | goto out3; |
797 | } | 796 | } |
798 | 797 | ||
799 | tlclk_device = platform_device_register_simple("telco_clock", | 798 | tlclk_device = platform_device_register_simple("telco_clock", |
800 | -1, NULL, 0); | 799 | -1, NULL, 0); |
801 | if (!tlclk_device) { | 800 | if (IS_ERR(tlclk_device)) { |
802 | printk(KERN_ERR "tlclk: platform_device_register failed.\n"); | 801 | printk(KERN_ERR "tlclk: platform_device_register failed.\n"); |
803 | ret = -EBUSY; | 802 | ret = PTR_ERR(tlclk_device); |
804 | goto out4; | 803 | goto out4; |
805 | } | 804 | } |
806 | 805 | ||
diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index dd36fd04a842..07067c31c4ec 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c | |||
@@ -249,6 +249,7 @@ int tosh_smm(SMMRegisters *regs) | |||
249 | 249 | ||
250 | return eax; | 250 | return eax; |
251 | } | 251 | } |
252 | EXPORT_SYMBOL(tosh_smm); | ||
252 | 253 | ||
253 | 254 | ||
254 | static int tosh_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, | 255 | static int tosh_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, |
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 6ad2d3bb945c..33e1f66e39cb 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -325,9 +325,9 @@ static void user_reader_timeout(unsigned long ptr) | |||
325 | schedule_work(&chip->work); | 325 | schedule_work(&chip->work); |
326 | } | 326 | } |
327 | 327 | ||
328 | static void timeout_work(void *ptr) | 328 | static void timeout_work(struct work_struct *work) |
329 | { | 329 | { |
330 | struct tpm_chip *chip = ptr; | 330 | struct tpm_chip *chip = container_of(work, struct tpm_chip, work); |
331 | 331 | ||
332 | down(&chip->buffer_mutex); | 332 | down(&chip->buffer_mutex); |
333 | atomic_set(&chip->data_pending, 0); | 333 | atomic_set(&chip->data_pending, 0); |
@@ -1105,7 +1105,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend | |||
1105 | init_MUTEX(&chip->tpm_mutex); | 1105 | init_MUTEX(&chip->tpm_mutex); |
1106 | INIT_LIST_HEAD(&chip->list); | 1106 | INIT_LIST_HEAD(&chip->list); |
1107 | 1107 | ||
1108 | INIT_WORK(&chip->work, timeout_work, chip); | 1108 | INIT_WORK(&chip->work, timeout_work); |
1109 | 1109 | ||
1110 | init_timer(&chip->user_read_timer); | 1110 | init_timer(&chip->user_read_timer); |
1111 | chip->user_read_timer.function = user_reader_timeout; | 1111 | 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 | |||
1130 | scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); | 1130 | scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); |
1131 | chip->vendor.miscdev.name = devname; | 1131 | chip->vendor.miscdev.name = devname; |
1132 | 1132 | ||
1133 | chip->vendor.miscdev.dev = dev; | 1133 | chip->vendor.miscdev.parent = dev; |
1134 | chip->dev = get_device(dev); | 1134 | chip->dev = get_device(dev); |
1135 | 1135 | ||
1136 | if (misc_register(&chip->vendor.miscdev)) { | 1136 | if (misc_register(&chip->vendor.miscdev)) { |
@@ -1155,6 +1155,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend | |||
1155 | 1155 | ||
1156 | if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { | 1156 | if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { |
1157 | list_del(&chip->list); | 1157 | list_del(&chip->list); |
1158 | misc_deregister(&chip->vendor.miscdev); | ||
1158 | put_device(dev); | 1159 | put_device(dev); |
1159 | clear_bit(chip->dev_num, dev_mask); | 1160 | clear_bit(chip->dev_num, dev_mask); |
1160 | kfree(chip); | 1161 | kfree(chip); |
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 050ced247f68..bb9a43c6cf3d 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/pci.h> | 22 | #include <linux/pci.h> |
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/fs.h> | 24 | #include <linux/fs.h> |
25 | #include <linux/sched.h> | ||
25 | #include <linux/miscdevice.h> | 26 | #include <linux/miscdevice.h> |
26 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
27 | #include <linux/io.h> | 28 | #include <linux/io.h> |
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index e90ea39c7c4b..b3cfc8bc613c 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
@@ -1254,7 +1254,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); | |||
1254 | 1254 | ||
1255 | /** | 1255 | /** |
1256 | * do_tty_hangup - actual handler for hangup events | 1256 | * do_tty_hangup - actual handler for hangup events |
1257 | * @data: tty device | 1257 | * @work: tty device |
1258 | * | 1258 | * |
1259 | * This can be called by the "eventd" kernel thread. That is process | 1259 | * This can be called by the "eventd" kernel thread. That is process |
1260 | * synchronous but doesn't hold any locks, so we need to make sure we | 1260 | * synchronous but doesn't hold any locks, so we need to make sure we |
@@ -1274,9 +1274,10 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); | |||
1274 | * tasklist_lock to walk task list for hangup event | 1274 | * tasklist_lock to walk task list for hangup event |
1275 | * | 1275 | * |
1276 | */ | 1276 | */ |
1277 | static void do_tty_hangup(void *data) | 1277 | static void do_tty_hangup(struct work_struct *work) |
1278 | { | 1278 | { |
1279 | struct tty_struct *tty = (struct tty_struct *) data; | 1279 | struct tty_struct *tty = |
1280 | container_of(work, struct tty_struct, hangup_work); | ||
1280 | struct file * cons_filp = NULL; | 1281 | struct file * cons_filp = NULL; |
1281 | struct file *filp, *f = NULL; | 1282 | struct file *filp, *f = NULL; |
1282 | struct task_struct *p; | 1283 | struct task_struct *p; |
@@ -1433,7 +1434,7 @@ void tty_vhangup(struct tty_struct * tty) | |||
1433 | 1434 | ||
1434 | printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf)); | 1435 | printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf)); |
1435 | #endif | 1436 | #endif |
1436 | do_tty_hangup((void *) tty); | 1437 | do_tty_hangup(&tty->hangup_work); |
1437 | } | 1438 | } |
1438 | EXPORT_SYMBOL(tty_vhangup); | 1439 | EXPORT_SYMBOL(tty_vhangup); |
1439 | 1440 | ||
@@ -3304,12 +3305,13 @@ int tty_ioctl(struct inode * inode, struct file * file, | |||
3304 | * Nasty bug: do_SAK is being called in interrupt context. This can | 3305 | * Nasty bug: do_SAK is being called in interrupt context. This can |
3305 | * deadlock. We punt it up to process context. AKPM - 16Mar2001 | 3306 | * deadlock. We punt it up to process context. AKPM - 16Mar2001 |
3306 | */ | 3307 | */ |
3307 | static void __do_SAK(void *arg) | 3308 | static void __do_SAK(struct work_struct *work) |
3308 | { | 3309 | { |
3310 | struct tty_struct *tty = | ||
3311 | container_of(work, struct tty_struct, SAK_work); | ||
3309 | #ifdef TTY_SOFT_SAK | 3312 | #ifdef TTY_SOFT_SAK |
3310 | tty_hangup(tty); | 3313 | tty_hangup(tty); |
3311 | #else | 3314 | #else |
3312 | struct tty_struct *tty = arg; | ||
3313 | struct task_struct *g, *p; | 3315 | struct task_struct *g, *p; |
3314 | int session; | 3316 | int session; |
3315 | int i; | 3317 | int i; |
@@ -3388,7 +3390,7 @@ void do_SAK(struct tty_struct *tty) | |||
3388 | { | 3390 | { |
3389 | if (!tty) | 3391 | if (!tty) |
3390 | return; | 3392 | return; |
3391 | PREPARE_WORK(&tty->SAK_work, __do_SAK, tty); | 3393 | PREPARE_WORK(&tty->SAK_work, __do_SAK); |
3392 | schedule_work(&tty->SAK_work); | 3394 | schedule_work(&tty->SAK_work); |
3393 | } | 3395 | } |
3394 | 3396 | ||
@@ -3396,7 +3398,7 @@ EXPORT_SYMBOL(do_SAK); | |||
3396 | 3398 | ||
3397 | /** | 3399 | /** |
3398 | * flush_to_ldisc | 3400 | * flush_to_ldisc |
3399 | * @private_: tty structure passed from work queue. | 3401 | * @work: tty structure passed from work queue. |
3400 | * | 3402 | * |
3401 | * This routine is called out of the software interrupt to flush data | 3403 | * This routine is called out of the software interrupt to flush data |
3402 | * from the buffer chain to the line discipline. | 3404 | * from the buffer chain to the line discipline. |
@@ -3406,9 +3408,10 @@ EXPORT_SYMBOL(do_SAK); | |||
3406 | * receive_buf method is single threaded for each tty instance. | 3408 | * receive_buf method is single threaded for each tty instance. |
3407 | */ | 3409 | */ |
3408 | 3410 | ||
3409 | static void flush_to_ldisc(void *private_) | 3411 | static void flush_to_ldisc(struct work_struct *work) |
3410 | { | 3412 | { |
3411 | struct tty_struct *tty = (struct tty_struct *) private_; | 3413 | struct tty_struct *tty = |
3414 | container_of(work, struct tty_struct, buf.work.work); | ||
3412 | unsigned long flags; | 3415 | unsigned long flags; |
3413 | struct tty_ldisc *disc; | 3416 | struct tty_ldisc *disc; |
3414 | struct tty_buffer *tbuf, *head; | 3417 | struct tty_buffer *tbuf, *head; |
@@ -3553,7 +3556,7 @@ void tty_flip_buffer_push(struct tty_struct *tty) | |||
3553 | spin_unlock_irqrestore(&tty->buf.lock, flags); | 3556 | spin_unlock_irqrestore(&tty->buf.lock, flags); |
3554 | 3557 | ||
3555 | if (tty->low_latency) | 3558 | if (tty->low_latency) |
3556 | flush_to_ldisc((void *) tty); | 3559 | flush_to_ldisc(&tty->buf.work.work); |
3557 | else | 3560 | else |
3558 | schedule_delayed_work(&tty->buf.work, 1); | 3561 | schedule_delayed_work(&tty->buf.work, 1); |
3559 | } | 3562 | } |
@@ -3580,17 +3583,17 @@ static void initialize_tty_struct(struct tty_struct *tty) | |||
3580 | tty->overrun_time = jiffies; | 3583 | tty->overrun_time = jiffies; |
3581 | tty->buf.head = tty->buf.tail = NULL; | 3584 | tty->buf.head = tty->buf.tail = NULL; |
3582 | tty_buffer_init(tty); | 3585 | tty_buffer_init(tty); |
3583 | INIT_WORK(&tty->buf.work, flush_to_ldisc, tty); | 3586 | INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc); |
3584 | init_MUTEX(&tty->buf.pty_sem); | 3587 | init_MUTEX(&tty->buf.pty_sem); |
3585 | mutex_init(&tty->termios_mutex); | 3588 | mutex_init(&tty->termios_mutex); |
3586 | init_waitqueue_head(&tty->write_wait); | 3589 | init_waitqueue_head(&tty->write_wait); |
3587 | init_waitqueue_head(&tty->read_wait); | 3590 | init_waitqueue_head(&tty->read_wait); |
3588 | INIT_WORK(&tty->hangup_work, do_tty_hangup, tty); | 3591 | INIT_WORK(&tty->hangup_work, do_tty_hangup); |
3589 | mutex_init(&tty->atomic_read_lock); | 3592 | mutex_init(&tty->atomic_read_lock); |
3590 | mutex_init(&tty->atomic_write_lock); | 3593 | mutex_init(&tty->atomic_write_lock); |
3591 | spin_lock_init(&tty->read_lock); | 3594 | spin_lock_init(&tty->read_lock); |
3592 | INIT_LIST_HEAD(&tty->tty_files); | 3595 | INIT_LIST_HEAD(&tty->tty_files); |
3593 | INIT_WORK(&tty->SAK_work, NULL, NULL); | 3596 | INIT_WORK(&tty->SAK_work, NULL); |
3594 | } | 3597 | } |
3595 | 3598 | ||
3596 | /* | 3599 | /* |
@@ -3612,7 +3615,8 @@ static struct class *tty_class; | |||
3612 | * This field is optional, if there is no known struct device | 3615 | * This field is optional, if there is no known struct device |
3613 | * for this tty device it can be set to NULL safely. | 3616 | * for this tty device it can be set to NULL safely. |
3614 | * | 3617 | * |
3615 | * Returns a pointer to the class device (or ERR_PTR(-EFOO) on error). | 3618 | * Returns a pointer to the struct device for this tty device |
3619 | * (or ERR_PTR(-EFOO) on error). | ||
3616 | * | 3620 | * |
3617 | * This call is required to be made to register an individual tty device | 3621 | * This call is required to be made to register an individual tty device |
3618 | * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If | 3622 | * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If |
@@ -3622,8 +3626,8 @@ static struct class *tty_class; | |||
3622 | * Locking: ?? | 3626 | * Locking: ?? |
3623 | */ | 3627 | */ |
3624 | 3628 | ||
3625 | struct class_device *tty_register_device(struct tty_driver *driver, | 3629 | struct device *tty_register_device(struct tty_driver *driver, unsigned index, |
3626 | unsigned index, struct device *device) | 3630 | struct device *device) |
3627 | { | 3631 | { |
3628 | char name[64]; | 3632 | char name[64]; |
3629 | dev_t dev = MKDEV(driver->major, driver->minor_start) + index; | 3633 | dev_t dev = MKDEV(driver->major, driver->minor_start) + index; |
@@ -3639,7 +3643,7 @@ struct class_device *tty_register_device(struct tty_driver *driver, | |||
3639 | else | 3643 | else |
3640 | tty_line_name(driver, index, name); | 3644 | tty_line_name(driver, index, name); |
3641 | 3645 | ||
3642 | return class_device_create(tty_class, NULL, dev, device, "%s", name); | 3646 | return device_create(tty_class, device, dev, name); |
3643 | } | 3647 | } |
3644 | 3648 | ||
3645 | /** | 3649 | /** |
@@ -3655,7 +3659,7 @@ struct class_device *tty_register_device(struct tty_driver *driver, | |||
3655 | 3659 | ||
3656 | void tty_unregister_device(struct tty_driver *driver, unsigned index) | 3660 | void tty_unregister_device(struct tty_driver *driver, unsigned index) |
3657 | { | 3661 | { |
3658 | class_device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); | 3662 | device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); |
3659 | } | 3663 | } |
3660 | 3664 | ||
3661 | EXPORT_SYMBOL(tty_register_device); | 3665 | EXPORT_SYMBOL(tty_register_device); |
@@ -3895,20 +3899,20 @@ static int __init tty_init(void) | |||
3895 | if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || | 3899 | if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || |
3896 | register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) | 3900 | register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) |
3897 | panic("Couldn't register /dev/tty driver\n"); | 3901 | panic("Couldn't register /dev/tty driver\n"); |
3898 | class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); | 3902 | device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), "tty"); |
3899 | 3903 | ||
3900 | cdev_init(&console_cdev, &console_fops); | 3904 | cdev_init(&console_cdev, &console_fops); |
3901 | if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || | 3905 | if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || |
3902 | register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) | 3906 | register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) |
3903 | panic("Couldn't register /dev/console driver\n"); | 3907 | panic("Couldn't register /dev/console driver\n"); |
3904 | class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); | 3908 | device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), "console"); |
3905 | 3909 | ||
3906 | #ifdef CONFIG_UNIX98_PTYS | 3910 | #ifdef CONFIG_UNIX98_PTYS |
3907 | cdev_init(&ptmx_cdev, &ptmx_fops); | 3911 | cdev_init(&ptmx_cdev, &ptmx_fops); |
3908 | if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || | 3912 | if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || |
3909 | register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) | 3913 | register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) |
3910 | panic("Couldn't register /dev/ptmx driver\n"); | 3914 | panic("Couldn't register /dev/ptmx driver\n"); |
3911 | class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); | 3915 | device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), "ptmx"); |
3912 | #endif | 3916 | #endif |
3913 | 3917 | ||
3914 | #ifdef CONFIG_VT | 3918 | #ifdef CONFIG_VT |
@@ -3916,7 +3920,7 @@ static int __init tty_init(void) | |||
3916 | if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || | 3920 | if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || |
3917 | register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) | 3921 | register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) |
3918 | panic("Couldn't register /dev/tty0 driver\n"); | 3922 | panic("Couldn't register /dev/tty0 driver\n"); |
3919 | class_device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); | 3923 | device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), "tty0"); |
3920 | 3924 | ||
3921 | vty_init(); | 3925 | vty_init(); |
3922 | #endif | 3926 | #endif |
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index bd7a98c6ea7a..f442b574b44a 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c | |||
@@ -476,16 +476,16 @@ static struct class *vc_class; | |||
476 | 476 | ||
477 | void vcs_make_sysfs(struct tty_struct *tty) | 477 | void vcs_make_sysfs(struct tty_struct *tty) |
478 | { | 478 | { |
479 | class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1), | 479 | device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1), |
480 | NULL, "vcs%u", tty->index + 1); | 480 | "vcs%u", tty->index + 1); |
481 | class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129), | 481 | device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129), |
482 | NULL, "vcsa%u", tty->index + 1); | 482 | "vcsa%u", tty->index + 1); |
483 | } | 483 | } |
484 | 484 | ||
485 | void vcs_remove_sysfs(struct tty_struct *tty) | 485 | void vcs_remove_sysfs(struct tty_struct *tty) |
486 | { | 486 | { |
487 | class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1)); | 487 | device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1)); |
488 | class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129)); | 488 | device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129)); |
489 | } | 489 | } |
490 | 490 | ||
491 | int __init vcs_init(void) | 491 | int __init vcs_init(void) |
@@ -494,7 +494,7 @@ int __init vcs_init(void) | |||
494 | panic("unable to get major %d for vcs device", VCS_MAJOR); | 494 | panic("unable to get major %d for vcs device", VCS_MAJOR); |
495 | vc_class = class_create(THIS_MODULE, "vc"); | 495 | vc_class = class_create(THIS_MODULE, "vc"); |
496 | 496 | ||
497 | class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); | 497 | device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), "vcs"); |
498 | class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); | 498 | device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), "vcsa"); |
499 | return 0; | 499 | return 0; |
500 | } | 500 | } |
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 8e4413f6fbaf..a8239dac994f 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c | |||
@@ -112,7 +112,7 @@ | |||
112 | struct con_driver { | 112 | struct con_driver { |
113 | const struct consw *con; | 113 | const struct consw *con; |
114 | const char *desc; | 114 | const char *desc; |
115 | struct class_device *class_dev; | 115 | struct device *dev; |
116 | int node; | 116 | int node; |
117 | int first; | 117 | int first; |
118 | int last; | 118 | int last; |
@@ -152,10 +152,10 @@ static void gotoxy(struct vc_data *vc, int new_x, int new_y); | |||
152 | static void save_cur(struct vc_data *vc); | 152 | static void save_cur(struct vc_data *vc); |
153 | static void reset_terminal(struct vc_data *vc, int do_clear); | 153 | static void reset_terminal(struct vc_data *vc, int do_clear); |
154 | static void con_flush_chars(struct tty_struct *tty); | 154 | static void con_flush_chars(struct tty_struct *tty); |
155 | static void set_vesa_blanking(char __user *p); | 155 | static int set_vesa_blanking(char __user *p); |
156 | static void set_cursor(struct vc_data *vc); | 156 | static void set_cursor(struct vc_data *vc); |
157 | static void hide_cursor(struct vc_data *vc); | 157 | static void hide_cursor(struct vc_data *vc); |
158 | static void console_callback(void *ignored); | 158 | static void console_callback(struct work_struct *ignored); |
159 | static void blank_screen_t(unsigned long dummy); | 159 | static void blank_screen_t(unsigned long dummy); |
160 | static void set_palette(struct vc_data *vc); | 160 | static void set_palette(struct vc_data *vc); |
161 | 161 | ||
@@ -174,7 +174,7 @@ static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ | |||
174 | static int blankinterval = 10*60*HZ; | 174 | static int blankinterval = 10*60*HZ; |
175 | static int vesa_off_interval; | 175 | static int vesa_off_interval; |
176 | 176 | ||
177 | static DECLARE_WORK(console_work, console_callback, NULL); | 177 | static DECLARE_WORK(console_work, console_callback); |
178 | 178 | ||
179 | /* | 179 | /* |
180 | * fg_console is the current virtual console, | 180 | * fg_console is the current virtual console, |
@@ -2154,7 +2154,7 @@ out: | |||
2154 | * with other console code and prevention of re-entrancy is | 2154 | * with other console code and prevention of re-entrancy is |
2155 | * ensured with console_sem. | 2155 | * ensured with console_sem. |
2156 | */ | 2156 | */ |
2157 | static void console_callback(void *ignored) | 2157 | static void console_callback(struct work_struct *ignored) |
2158 | { | 2158 | { |
2159 | acquire_console_sem(); | 2159 | acquire_console_sem(); |
2160 | 2160 | ||
@@ -2369,7 +2369,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) | |||
2369 | ret = __put_user(data, p); | 2369 | ret = __put_user(data, p); |
2370 | break; | 2370 | break; |
2371 | case TIOCL_SETVESABLANK: | 2371 | case TIOCL_SETVESABLANK: |
2372 | set_vesa_blanking(p); | 2372 | ret = set_vesa_blanking(p); |
2373 | break; | 2373 | break; |
2374 | case TIOCL_GETKMSGREDIRECT: | 2374 | case TIOCL_GETKMSGREDIRECT: |
2375 | data = kmsg_redirect; | 2375 | data = kmsg_redirect; |
@@ -3023,10 +3023,10 @@ static inline int vt_unbind(struct con_driver *con) | |||
3023 | } | 3023 | } |
3024 | #endif /* CONFIG_VT_HW_CONSOLE_BINDING */ | 3024 | #endif /* CONFIG_VT_HW_CONSOLE_BINDING */ |
3025 | 3025 | ||
3026 | static ssize_t store_bind(struct class_device *class_device, | 3026 | static ssize_t store_bind(struct device *dev, struct device_attribute *attr, |
3027 | const char *buf, size_t count) | 3027 | const char *buf, size_t count) |
3028 | { | 3028 | { |
3029 | struct con_driver *con = class_get_devdata(class_device); | 3029 | struct con_driver *con = dev_get_drvdata(dev); |
3030 | int bind = simple_strtoul(buf, NULL, 0); | 3030 | int bind = simple_strtoul(buf, NULL, 0); |
3031 | 3031 | ||
3032 | if (bind) | 3032 | if (bind) |
@@ -3037,17 +3037,19 @@ static ssize_t store_bind(struct class_device *class_device, | |||
3037 | return count; | 3037 | return count; |
3038 | } | 3038 | } |
3039 | 3039 | ||
3040 | static ssize_t show_bind(struct class_device *class_device, char *buf) | 3040 | static ssize_t show_bind(struct device *dev, struct device_attribute *attr, |
3041 | char *buf) | ||
3041 | { | 3042 | { |
3042 | struct con_driver *con = class_get_devdata(class_device); | 3043 | struct con_driver *con = dev_get_drvdata(dev); |
3043 | int bind = con_is_bound(con->con); | 3044 | int bind = con_is_bound(con->con); |
3044 | 3045 | ||
3045 | return snprintf(buf, PAGE_SIZE, "%i\n", bind); | 3046 | return snprintf(buf, PAGE_SIZE, "%i\n", bind); |
3046 | } | 3047 | } |
3047 | 3048 | ||
3048 | static ssize_t show_name(struct class_device *class_device, char *buf) | 3049 | static ssize_t show_name(struct device *dev, struct device_attribute *attr, |
3050 | char *buf) | ||
3049 | { | 3051 | { |
3050 | struct con_driver *con = class_get_devdata(class_device); | 3052 | struct con_driver *con = dev_get_drvdata(dev); |
3051 | 3053 | ||
3052 | return snprintf(buf, PAGE_SIZE, "%s %s\n", | 3054 | return snprintf(buf, PAGE_SIZE, "%s %s\n", |
3053 | (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)", | 3055 | (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)", |
@@ -3055,43 +3057,40 @@ static ssize_t show_name(struct class_device *class_device, char *buf) | |||
3055 | 3057 | ||
3056 | } | 3058 | } |
3057 | 3059 | ||
3058 | static struct class_device_attribute class_device_attrs[] = { | 3060 | static struct device_attribute device_attrs[] = { |
3059 | __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind), | 3061 | __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind), |
3060 | __ATTR(name, S_IRUGO, show_name, NULL), | 3062 | __ATTR(name, S_IRUGO, show_name, NULL), |
3061 | }; | 3063 | }; |
3062 | 3064 | ||
3063 | static int vtconsole_init_class_device(struct con_driver *con) | 3065 | static int vtconsole_init_device(struct con_driver *con) |
3064 | { | 3066 | { |
3065 | int i; | 3067 | int i; |
3066 | int error = 0; | 3068 | int error = 0; |
3067 | 3069 | ||
3068 | con->flag |= CON_DRIVER_FLAG_ATTR; | 3070 | con->flag |= CON_DRIVER_FLAG_ATTR; |
3069 | class_set_devdata(con->class_dev, con); | 3071 | dev_set_drvdata(con->dev, con); |
3070 | for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) { | 3072 | for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { |
3071 | error = class_device_create_file(con->class_dev, | 3073 | error = device_create_file(con->dev, &device_attrs[i]); |
3072 | &class_device_attrs[i]); | ||
3073 | if (error) | 3074 | if (error) |
3074 | break; | 3075 | break; |
3075 | } | 3076 | } |
3076 | 3077 | ||
3077 | if (error) { | 3078 | if (error) { |
3078 | while (--i >= 0) | 3079 | while (--i >= 0) |
3079 | class_device_remove_file(con->class_dev, | 3080 | device_remove_file(con->dev, &device_attrs[i]); |
3080 | &class_device_attrs[i]); | ||
3081 | con->flag &= ~CON_DRIVER_FLAG_ATTR; | 3081 | con->flag &= ~CON_DRIVER_FLAG_ATTR; |
3082 | } | 3082 | } |
3083 | 3083 | ||
3084 | return error; | 3084 | return error; |
3085 | } | 3085 | } |
3086 | 3086 | ||
3087 | static void vtconsole_deinit_class_device(struct con_driver *con) | 3087 | static void vtconsole_deinit_device(struct con_driver *con) |
3088 | { | 3088 | { |
3089 | int i; | 3089 | int i; |
3090 | 3090 | ||
3091 | if (con->flag & CON_DRIVER_FLAG_ATTR) { | 3091 | if (con->flag & CON_DRIVER_FLAG_ATTR) { |
3092 | for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) | 3092 | for (i = 0; i < ARRAY_SIZE(device_attrs); i++) |
3093 | class_device_remove_file(con->class_dev, | 3093 | device_remove_file(con->dev, &device_attrs[i]); |
3094 | &class_device_attrs[i]); | ||
3095 | con->flag &= ~CON_DRIVER_FLAG_ATTR; | 3094 | con->flag &= ~CON_DRIVER_FLAG_ATTR; |
3096 | } | 3095 | } |
3097 | } | 3096 | } |
@@ -3179,18 +3178,17 @@ int register_con_driver(const struct consw *csw, int first, int last) | |||
3179 | if (retval) | 3178 | if (retval) |
3180 | goto err; | 3179 | goto err; |
3181 | 3180 | ||
3182 | con_driver->class_dev = class_device_create(vtconsole_class, NULL, | 3181 | con_driver->dev = device_create(vtconsole_class, NULL, |
3183 | MKDEV(0, con_driver->node), | 3182 | MKDEV(0, con_driver->node), |
3184 | NULL, "vtcon%i", | 3183 | "vtcon%i", con_driver->node); |
3185 | con_driver->node); | ||
3186 | 3184 | ||
3187 | if (IS_ERR(con_driver->class_dev)) { | 3185 | if (IS_ERR(con_driver->dev)) { |
3188 | printk(KERN_WARNING "Unable to create class_device for %s; " | 3186 | printk(KERN_WARNING "Unable to create device for %s; " |
3189 | "errno = %ld\n", con_driver->desc, | 3187 | "errno = %ld\n", con_driver->desc, |
3190 | PTR_ERR(con_driver->class_dev)); | 3188 | PTR_ERR(con_driver->dev)); |
3191 | con_driver->class_dev = NULL; | 3189 | con_driver->dev = NULL; |
3192 | } else { | 3190 | } else { |
3193 | vtconsole_init_class_device(con_driver); | 3191 | vtconsole_init_device(con_driver); |
3194 | } | 3192 | } |
3195 | 3193 | ||
3196 | err: | 3194 | err: |
@@ -3226,12 +3224,12 @@ int unregister_con_driver(const struct consw *csw) | |||
3226 | 3224 | ||
3227 | if (con_driver->con == csw && | 3225 | if (con_driver->con == csw && |
3228 | con_driver->flag & CON_DRIVER_FLAG_MODULE) { | 3226 | con_driver->flag & CON_DRIVER_FLAG_MODULE) { |
3229 | vtconsole_deinit_class_device(con_driver); | 3227 | vtconsole_deinit_device(con_driver); |
3230 | class_device_destroy(vtconsole_class, | 3228 | device_destroy(vtconsole_class, |
3231 | MKDEV(0, con_driver->node)); | 3229 | MKDEV(0, con_driver->node)); |
3232 | con_driver->con = NULL; | 3230 | con_driver->con = NULL; |
3233 | con_driver->desc = NULL; | 3231 | con_driver->desc = NULL; |
3234 | con_driver->class_dev = NULL; | 3232 | con_driver->dev = NULL; |
3235 | con_driver->node = 0; | 3233 | con_driver->node = 0; |
3236 | con_driver->flag = 0; | 3234 | con_driver->flag = 0; |
3237 | con_driver->first = 0; | 3235 | con_driver->first = 0; |
@@ -3289,19 +3287,18 @@ static int __init vtconsole_class_init(void) | |||
3289 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | 3287 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { |
3290 | struct con_driver *con = ®istered_con_driver[i]; | 3288 | struct con_driver *con = ®istered_con_driver[i]; |
3291 | 3289 | ||
3292 | if (con->con && !con->class_dev) { | 3290 | if (con->con && !con->dev) { |
3293 | con->class_dev = | 3291 | con->dev = device_create(vtconsole_class, NULL, |
3294 | class_device_create(vtconsole_class, NULL, | 3292 | MKDEV(0, con->node), |
3295 | MKDEV(0, con->node), NULL, | 3293 | "vtcon%i", con->node); |
3296 | "vtcon%i", con->node); | ||
3297 | 3294 | ||
3298 | if (IS_ERR(con->class_dev)) { | 3295 | if (IS_ERR(con->dev)) { |
3299 | printk(KERN_WARNING "Unable to create " | 3296 | printk(KERN_WARNING "Unable to create " |
3300 | "class_device for %s; errno = %ld\n", | 3297 | "device for %s; errno = %ld\n", |
3301 | con->desc, PTR_ERR(con->class_dev)); | 3298 | con->desc, PTR_ERR(con->dev)); |
3302 | con->class_dev = NULL; | 3299 | con->dev = NULL; |
3303 | } else { | 3300 | } else { |
3304 | vtconsole_init_class_device(con); | 3301 | vtconsole_init_device(con); |
3305 | } | 3302 | } |
3306 | } | 3303 | } |
3307 | } | 3304 | } |
@@ -3316,11 +3313,15 @@ postcore_initcall(vtconsole_class_init); | |||
3316 | * Screen blanking | 3313 | * Screen blanking |
3317 | */ | 3314 | */ |
3318 | 3315 | ||
3319 | static void set_vesa_blanking(char __user *p) | 3316 | static int set_vesa_blanking(char __user *p) |
3320 | { | 3317 | { |
3321 | unsigned int mode; | 3318 | unsigned int mode; |
3322 | get_user(mode, p + 1); | 3319 | |
3323 | vesa_blank_mode = (mode < 4) ? mode : 0; | 3320 | if (get_user(mode, p + 1)) |
3321 | return -EFAULT; | ||
3322 | |||
3323 | vesa_blank_mode = (mode < 4) ? mode : 0; | ||
3324 | return 0; | ||
3324 | } | 3325 | } |
3325 | 3326 | ||
3326 | void do_blank_screen(int entering_gfx) | 3327 | void do_blank_screen(int entering_gfx) |
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 0187b1185323..ea09d0c974ea 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig | |||
@@ -340,6 +340,14 @@ config ITCO_WDT | |||
340 | To compile this driver as a module, choose M here: the | 340 | To compile this driver as a module, choose M here: the |
341 | module will be called iTCO_wdt. | 341 | module will be called iTCO_wdt. |
342 | 342 | ||
343 | config ITCO_VENDOR_SUPPORT | ||
344 | bool "Intel TCO Timer/Watchdog Specific Vendor Support" | ||
345 | depends on ITCO_WDT | ||
346 | ---help--- | ||
347 | Add vendor specific support to the intel TCO timer based watchdog | ||
348 | devices. At this moment we only have additional support for some | ||
349 | SuperMicro Inc. motherboards. | ||
350 | |||
343 | config SC1200_WDT | 351 | config SC1200_WDT |
344 | tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog" | 352 | tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog" |
345 | depends on WATCHDOG && X86 | 353 | depends on WATCHDOG && X86 |
@@ -363,6 +371,20 @@ config SCx200_WDT | |||
363 | 371 | ||
364 | If compiled as a module, it will be called scx200_wdt. | 372 | If compiled as a module, it will be called scx200_wdt. |
365 | 373 | ||
374 | config PC87413_WDT | ||
375 | tristate "NS PC87413 watchdog" | ||
376 | depends on WATCHDOG && X86 | ||
377 | ---help--- | ||
378 | This is the driver for the hardware watchdog on the PC87413 chipset | ||
379 | This watchdog simply watches your kernel to make sure it doesn't | ||
380 | freeze, and if it does, it reboots your computer after a certain | ||
381 | amount of time. | ||
382 | |||
383 | To compile this driver as a module, choose M here: the | ||
384 | module will be called pc87413_wdt. | ||
385 | |||
386 | Most people will say N. | ||
387 | |||
366 | config 60XX_WDT | 388 | config 60XX_WDT |
367 | tristate "SBC-60XX Watchdog Timer" | 389 | tristate "SBC-60XX Watchdog Timer" |
368 | depends on WATCHDOG && X86 | 390 | depends on WATCHDOG && X86 |
@@ -553,6 +575,16 @@ config INDYDOG | |||
553 | timer expired and no process has written to /dev/watchdog during | 575 | timer expired and no process has written to /dev/watchdog during |
554 | that time. | 576 | that time. |
555 | 577 | ||
578 | config WDT_RM9K_GPI | ||
579 | tristate "RM9000/GPI hardware watchdog" | ||
580 | depends on WATCHDOG && CPU_RM9000 | ||
581 | help | ||
582 | Watchdog implementation using the GPI hardware found on | ||
583 | PMC-Sierra RM9xxx CPUs. | ||
584 | |||
585 | To compile this driver as a module, choose M here: the | ||
586 | module will be called rm9k_wdt. | ||
587 | |||
556 | # S390 Architecture | 588 | # S390 Architecture |
557 | 589 | ||
558 | config ZVM_WATCHDOG | 590 | config ZVM_WATCHDOG |
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index 36440497047c..2cd8ff8d10ac 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile | |||
@@ -47,9 +47,10 @@ obj-$(CONFIG_IBMASR) += ibmasr.o | |||
47 | obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o | 47 | obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o |
48 | obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o | 48 | obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o |
49 | obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o | 49 | obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o |
50 | obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o | 50 | obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o |
51 | obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o | 51 | obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o |
52 | obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o | 52 | obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o |
53 | obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o | ||
53 | obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o | 54 | obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o |
54 | obj-$(CONFIG_SBC8360_WDT) += sbc8360.o | 55 | obj-$(CONFIG_SBC8360_WDT) += sbc8360.o |
55 | obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o | 56 | obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o |
@@ -72,6 +73,7 @@ obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o | |||
72 | 73 | ||
73 | # MIPS Architecture | 74 | # MIPS Architecture |
74 | obj-$(CONFIG_INDYDOG) += indydog.o | 75 | obj-$(CONFIG_INDYDOG) += indydog.o |
76 | obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o | ||
75 | 77 | ||
76 | # S390 Architecture | 78 | # S390 Architecture |
77 | 79 | ||
diff --git a/drivers/char/watchdog/at91rm9200_wdt.c b/drivers/char/watchdog/at91rm9200_wdt.c index 4e7a1145e78f..cb86967e2c5f 100644 --- a/drivers/char/watchdog/at91rm9200_wdt.c +++ b/drivers/char/watchdog/at91rm9200_wdt.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/watchdog.h> | 21 | #include <linux/watchdog.h> |
22 | #include <asm/bitops.h> | 22 | #include <asm/bitops.h> |
23 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
24 | #include <asm/arch/at91_st.h> | ||
24 | 25 | ||
25 | 26 | ||
26 | #define WDT_DEFAULT_TIME 5 /* seconds */ | 27 | #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 000000000000..415083990097 --- /dev/null +++ b/drivers/char/watchdog/iTCO_vendor_support.c | |||
@@ -0,0 +1,307 @@ | |||
1 | /* | ||
2 | * intel TCO vendor specific watchdog driver support | ||
3 | * | ||
4 | * (c) Copyright 2006 Wim Van Sebroeck <wim@iguana.be>. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor | ||
12 | * provide warranty for any of this software. This material is | ||
13 | * provided "AS-IS" and at no charge. | ||
14 | */ | ||
15 | |||
16 | /* | ||
17 | * Includes, defines, variables, module parameters, ... | ||
18 | */ | ||
19 | |||
20 | /* Module and version information */ | ||
21 | #define DRV_NAME "iTCO_vendor_support" | ||
22 | #define DRV_VERSION "1.01" | ||
23 | #define DRV_RELDATE "11-Nov-2006" | ||
24 | #define PFX DRV_NAME ": " | ||
25 | |||
26 | /* Includes */ | ||
27 | #include <linux/module.h> /* For module specific items */ | ||
28 | #include <linux/moduleparam.h> /* For new moduleparam's */ | ||
29 | #include <linux/types.h> /* For standard types (like size_t) */ | ||
30 | #include <linux/errno.h> /* For the -ENODEV/... values */ | ||
31 | #include <linux/kernel.h> /* For printk/panic/... */ | ||
32 | #include <linux/init.h> /* For __init/__exit/... */ | ||
33 | #include <linux/ioport.h> /* For io-port access */ | ||
34 | |||
35 | #include <asm/io.h> /* For inb/outb/... */ | ||
36 | |||
37 | /* iTCO defines */ | ||
38 | #define SMI_EN acpibase + 0x30 /* SMI Control and Enable Register */ | ||
39 | #define TCOBASE acpibase + 0x60 /* TCO base address */ | ||
40 | #define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */ | ||
41 | |||
42 | /* List of vendor support modes */ | ||
43 | #define SUPERMICRO_OLD_BOARD 1 /* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */ | ||
44 | #define SUPERMICRO_NEW_BOARD 2 /* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems */ | ||
45 | |||
46 | static int vendorsupport = 0; | ||
47 | module_param(vendorsupport, int, 0); | ||
48 | MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+"); | ||
49 | |||
50 | /* | ||
51 | * Vendor Specific Support | ||
52 | */ | ||
53 | |||
54 | /* | ||
55 | * Vendor Support: 1 | ||
56 | * Board: Super Micro Computer Inc. 370SSE+-OEM1/P3TSSE | ||
57 | * iTCO chipset: ICH2 | ||
58 | * | ||
59 | * Code contributed by: R. Seretny <lkpatches@paypc.com> | ||
60 | * Documentation obtained by R. Seretny from SuperMicro Technical Support | ||
61 | * | ||
62 | * To enable Watchdog function: | ||
63 | * BIOS setup -> Power -> TCO Logic SMI Enable -> Within5Minutes | ||
64 | * This setting enables SMI to clear the watchdog expired flag. | ||
65 | * If BIOS or CPU fail which may cause SMI hang, then system will | ||
66 | * reboot. When application starts to use watchdog function, | ||
67 | * application has to take over the control from SMI. | ||
68 | * | ||
69 | * For P3TSSE, J36 jumper needs to be removed to enable the Watchdog | ||
70 | * function. | ||
71 | * | ||
72 | * Note: The system will reboot when Expire Flag is set TWICE. | ||
73 | * So, if the watchdog timer is 20 seconds, then the maximum hang | ||
74 | * time is about 40 seconds, and the minimum hang time is about | ||
75 | * 20.6 seconds. | ||
76 | */ | ||
77 | |||
78 | static void supermicro_old_pre_start(unsigned long acpibase) | ||
79 | { | ||
80 | unsigned long val32; | ||
81 | |||
82 | val32 = inl(SMI_EN); | ||
83 | val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ | ||
84 | outl(val32, SMI_EN); /* Needed to activate watchdog */ | ||
85 | } | ||
86 | |||
87 | static void supermicro_old_pre_stop(unsigned long acpibase) | ||
88 | { | ||
89 | unsigned long val32; | ||
90 | |||
91 | val32 = inl(SMI_EN); | ||
92 | val32 &= 0x00002000; /* Turn on SMI clearing watchdog */ | ||
93 | outl(val32, SMI_EN); /* Needed to deactivate watchdog */ | ||
94 | } | ||
95 | |||
96 | static void supermicro_old_pre_keepalive(unsigned long acpibase) | ||
97 | { | ||
98 | /* Reload TCO Timer (done in iTCO_wdt_keepalive) + */ | ||
99 | /* Clear "Expire Flag" (Bit 3 of TC01_STS register) */ | ||
100 | outb(0x08, TCO1_STS); | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | * Vendor Support: 2 | ||
105 | * Board: Super Micro Computer Inc. P4SBx, P4DPx | ||
106 | * iTCO chipset: ICH4 | ||
107 | * | ||
108 | * Code contributed by: R. Seretny <lkpatches@paypc.com> | ||
109 | * Documentation obtained by R. Seretny from SuperMicro Technical Support | ||
110 | * | ||
111 | * To enable Watchdog function: | ||
112 | * 1. BIOS | ||
113 | * For P4SBx: | ||
114 | * BIOS setup -> Advanced -> Integrated Peripherals -> Watch Dog Feature | ||
115 | * For P4DPx: | ||
116 | * BIOS setup -> Advanced -> I/O Device Configuration -> Watch Dog | ||
117 | * This setting enables or disables Watchdog function. When enabled, the | ||
118 | * default watchdog timer is set to be 5 minutes (about 4’35â€). It is | ||
119 | * enough to load and run the OS. The application (service or driver) has | ||
120 | * to take over the control once OS is running up and before watchdog | ||
121 | * expires. | ||
122 | * | ||
123 | * 2. JUMPER | ||
124 | * For P4SBx: JP39 | ||
125 | * For P4DPx: JP37 | ||
126 | * This jumper is used for safety. Closed is enabled. This jumper | ||
127 | * prevents user enables watchdog in BIOS by accident. | ||
128 | * | ||
129 | * To enable Watch Dog function, both BIOS and JUMPER must be enabled. | ||
130 | * | ||
131 | * The documentation lists motherboards P4SBx and P4DPx series as of | ||
132 | * 20-March-2002. However, this code works flawlessly with much newer | ||
133 | * motherboards, such as my X6DHR-8G2 (SuperServer 6014H-82). | ||
134 | * | ||
135 | * The original iTCO driver as written does not actually reset the | ||
136 | * watchdog timer on these machines, as a result they reboot after five | ||
137 | * minutes. | ||
138 | * | ||
139 | * NOTE: You may leave the Watchdog function disabled in the SuperMicro | ||
140 | * BIOS to avoid a "boot-race"... This driver will enable watchdog | ||
141 | * functionality even if it's disabled in the BIOS once the /dev/watchdog | ||
142 | * file is opened. | ||
143 | */ | ||
144 | |||
145 | /* I/O Port's */ | ||
146 | #define SM_REGINDEX 0x2e /* SuperMicro ICH4+ Register Index */ | ||
147 | #define SM_DATAIO 0x2f /* SuperMicro ICH4+ Register Data I/O */ | ||
148 | |||
149 | /* Control Register's */ | ||
150 | #define SM_CTLPAGESW 0x07 /* SuperMicro ICH4+ Control Page Switch */ | ||
151 | #define SM_CTLPAGE 0x08 /* SuperMicro ICH4+ Control Page Num */ | ||
152 | |||
153 | #define SM_WATCHENABLE 0x30 /* Watchdog enable: Bit 0: 0=off, 1=on */ | ||
154 | |||
155 | #define SM_WATCHPAGE 0x87 /* Watchdog unlock control page */ | ||
156 | |||
157 | #define SM_ENDWATCH 0xAA /* Watchdog lock control page */ | ||
158 | |||
159 | #define SM_COUNTMODE 0xf5 /* Watchdog count mode select */ | ||
160 | /* (Bit 3: 0 = seconds, 1 = minutes */ | ||
161 | |||
162 | #define SM_WATCHTIMER 0xf6 /* 8-bits, Watchdog timer counter (RW) */ | ||
163 | |||
164 | #define SM_RESETCONTROL 0xf7 /* Watchdog reset control */ | ||
165 | /* Bit 6: timer is reset by kbd interrupt */ | ||
166 | /* Bit 7: timer is reset by mouse interrupt */ | ||
167 | |||
168 | static void supermicro_new_unlock_watchdog(void) | ||
169 | { | ||
170 | outb(SM_WATCHPAGE, SM_REGINDEX); /* Write 0x87 to port 0x2e twice */ | ||
171 | outb(SM_WATCHPAGE, SM_REGINDEX); | ||
172 | |||
173 | outb(SM_CTLPAGESW, SM_REGINDEX); /* Switch to watchdog control page */ | ||
174 | outb(SM_CTLPAGE, SM_DATAIO); | ||
175 | } | ||
176 | |||
177 | static void supermicro_new_lock_watchdog(void) | ||
178 | { | ||
179 | outb(SM_ENDWATCH, SM_REGINDEX); | ||
180 | } | ||
181 | |||
182 | static void supermicro_new_pre_start(unsigned int heartbeat) | ||
183 | { | ||
184 | unsigned int val; | ||
185 | |||
186 | supermicro_new_unlock_watchdog(); | ||
187 | |||
188 | /* Watchdog timer setting needs to be in seconds*/ | ||
189 | outb(SM_COUNTMODE, SM_REGINDEX); | ||
190 | val = inb(SM_DATAIO); | ||
191 | val &= 0xF7; | ||
192 | outb(val, SM_DATAIO); | ||
193 | |||
194 | /* Write heartbeat interval to WDOG */ | ||
195 | outb (SM_WATCHTIMER, SM_REGINDEX); | ||
196 | outb((heartbeat & 255), SM_DATAIO); | ||
197 | |||
198 | /* Make sure keyboard/mouse interrupts don't interfere */ | ||
199 | outb(SM_RESETCONTROL, SM_REGINDEX); | ||
200 | val = inb(SM_DATAIO); | ||
201 | val &= 0x3f; | ||
202 | outb(val, SM_DATAIO); | ||
203 | |||
204 | /* enable watchdog by setting bit 0 of Watchdog Enable to 1 */ | ||
205 | outb(SM_WATCHENABLE, SM_REGINDEX); | ||
206 | val = inb(SM_DATAIO); | ||
207 | val |= 0x01; | ||
208 | outb(val, SM_DATAIO); | ||
209 | |||
210 | supermicro_new_lock_watchdog(); | ||
211 | } | ||
212 | |||
213 | static void supermicro_new_pre_stop(void) | ||
214 | { | ||
215 | unsigned int val; | ||
216 | |||
217 | supermicro_new_unlock_watchdog(); | ||
218 | |||
219 | /* disable watchdog by setting bit 0 of Watchdog Enable to 0 */ | ||
220 | outb(SM_WATCHENABLE, SM_REGINDEX); | ||
221 | val = inb(SM_DATAIO); | ||
222 | val &= 0xFE; | ||
223 | outb(val, SM_DATAIO); | ||
224 | |||
225 | supermicro_new_lock_watchdog(); | ||
226 | } | ||
227 | |||
228 | static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat) | ||
229 | { | ||
230 | supermicro_new_unlock_watchdog(); | ||
231 | |||
232 | /* reset watchdog timeout to heartveat value */ | ||
233 | outb(SM_WATCHTIMER, SM_REGINDEX); | ||
234 | outb((heartbeat & 255), SM_DATAIO); | ||
235 | |||
236 | supermicro_new_lock_watchdog(); | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * Generic Support Functions | ||
241 | */ | ||
242 | |||
243 | void iTCO_vendor_pre_start(unsigned long acpibase, | ||
244 | unsigned int heartbeat) | ||
245 | { | ||
246 | if (vendorsupport == SUPERMICRO_OLD_BOARD) | ||
247 | supermicro_old_pre_start(acpibase); | ||
248 | else if (vendorsupport == SUPERMICRO_NEW_BOARD) | ||
249 | supermicro_new_pre_start(heartbeat); | ||
250 | } | ||
251 | EXPORT_SYMBOL(iTCO_vendor_pre_start); | ||
252 | |||
253 | void iTCO_vendor_pre_stop(unsigned long acpibase) | ||
254 | { | ||
255 | if (vendorsupport == SUPERMICRO_OLD_BOARD) | ||
256 | supermicro_old_pre_stop(acpibase); | ||
257 | else if (vendorsupport == SUPERMICRO_NEW_BOARD) | ||
258 | supermicro_new_pre_stop(); | ||
259 | } | ||
260 | EXPORT_SYMBOL(iTCO_vendor_pre_stop); | ||
261 | |||
262 | void iTCO_vendor_pre_keepalive(unsigned long acpibase, unsigned int heartbeat) | ||
263 | { | ||
264 | if (vendorsupport == SUPERMICRO_OLD_BOARD) | ||
265 | supermicro_old_pre_keepalive(acpibase); | ||
266 | else if (vendorsupport == SUPERMICRO_NEW_BOARD) | ||
267 | supermicro_new_pre_set_heartbeat(heartbeat); | ||
268 | } | ||
269 | EXPORT_SYMBOL(iTCO_vendor_pre_keepalive); | ||
270 | |||
271 | void iTCO_vendor_pre_set_heartbeat(unsigned int heartbeat) | ||
272 | { | ||
273 | if (vendorsupport == SUPERMICRO_NEW_BOARD) | ||
274 | supermicro_new_pre_set_heartbeat(heartbeat); | ||
275 | } | ||
276 | EXPORT_SYMBOL(iTCO_vendor_pre_set_heartbeat); | ||
277 | |||
278 | int iTCO_vendor_check_noreboot_on(void) | ||
279 | { | ||
280 | switch(vendorsupport) { | ||
281 | case SUPERMICRO_OLD_BOARD: | ||
282 | return 0; | ||
283 | default: | ||
284 | return 1; | ||
285 | } | ||
286 | } | ||
287 | EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on); | ||
288 | |||
289 | static int __init iTCO_vendor_init_module(void) | ||
290 | { | ||
291 | printk (KERN_INFO PFX "vendor-support=%d\n", vendorsupport); | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static void __exit iTCO_vendor_exit_module(void) | ||
296 | { | ||
297 | printk (KERN_INFO PFX "Module Unloaded\n"); | ||
298 | } | ||
299 | |||
300 | module_init(iTCO_vendor_init_module); | ||
301 | module_exit(iTCO_vendor_exit_module); | ||
302 | |||
303 | MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>, R. Seretny <lkpatches@paypc.com>"); | ||
304 | MODULE_DESCRIPTION("Intel TCO Vendor Specific WatchDog Timer Driver Support"); | ||
305 | MODULE_VERSION(DRV_VERSION); | ||
306 | MODULE_LICENSE("GPL"); | ||
307 | |||
diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c index b6f29cb8bd39..7eac922df867 100644 --- a/drivers/char/watchdog/iTCO_wdt.c +++ b/drivers/char/watchdog/iTCO_wdt.c | |||
@@ -48,8 +48,8 @@ | |||
48 | 48 | ||
49 | /* Module and version information */ | 49 | /* Module and version information */ |
50 | #define DRV_NAME "iTCO_wdt" | 50 | #define DRV_NAME "iTCO_wdt" |
51 | #define DRV_VERSION "1.00" | 51 | #define DRV_VERSION "1.01" |
52 | #define DRV_RELDATE "08-Oct-2006" | 52 | #define DRV_RELDATE "11-Nov-2006" |
53 | #define PFX DRV_NAME ": " | 53 | #define PFX DRV_NAME ": " |
54 | 54 | ||
55 | /* Includes */ | 55 | /* Includes */ |
@@ -189,6 +189,21 @@ static int nowayout = WATCHDOG_NOWAYOUT; | |||
189 | module_param(nowayout, int, 0); | 189 | module_param(nowayout, int, 0); |
190 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | 190 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); |
191 | 191 | ||
192 | /* iTCO Vendor Specific Support hooks */ | ||
193 | #ifdef CONFIG_ITCO_VENDOR_SUPPORT | ||
194 | extern void iTCO_vendor_pre_start(unsigned long, unsigned int); | ||
195 | extern void iTCO_vendor_pre_stop(unsigned long); | ||
196 | extern void iTCO_vendor_pre_keepalive(unsigned long, unsigned int); | ||
197 | extern void iTCO_vendor_pre_set_heartbeat(unsigned int); | ||
198 | extern int iTCO_vendor_check_noreboot_on(void); | ||
199 | #else | ||
200 | #define iTCO_vendor_pre_start(acpibase, heartbeat) {} | ||
201 | #define iTCO_vendor_pre_stop(acpibase) {} | ||
202 | #define iTCO_vendor_pre_keepalive(acpibase,heartbeat) {} | ||
203 | #define iTCO_vendor_pre_set_heartbeat(heartbeat) {} | ||
204 | #define iTCO_vendor_check_noreboot_on() 1 /* 1=check noreboot; 0=don't check */ | ||
205 | #endif | ||
206 | |||
192 | /* | 207 | /* |
193 | * Some TCO specific functions | 208 | * Some TCO specific functions |
194 | */ | 209 | */ |
@@ -249,6 +264,8 @@ static int iTCO_wdt_start(void) | |||
249 | 264 | ||
250 | spin_lock(&iTCO_wdt_private.io_lock); | 265 | spin_lock(&iTCO_wdt_private.io_lock); |
251 | 266 | ||
267 | iTCO_vendor_pre_start(iTCO_wdt_private.ACPIBASE, heartbeat); | ||
268 | |||
252 | /* disable chipset's NO_REBOOT bit */ | 269 | /* disable chipset's NO_REBOOT bit */ |
253 | if (iTCO_wdt_unset_NO_REBOOT_bit()) { | 270 | if (iTCO_wdt_unset_NO_REBOOT_bit()) { |
254 | printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); | 271 | 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) | |||
273 | 290 | ||
274 | spin_lock(&iTCO_wdt_private.io_lock); | 291 | spin_lock(&iTCO_wdt_private.io_lock); |
275 | 292 | ||
293 | iTCO_vendor_pre_stop(iTCO_wdt_private.ACPIBASE); | ||
294 | |||
276 | /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ | 295 | /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ |
277 | val = inw(TCO1_CNT); | 296 | val = inw(TCO1_CNT); |
278 | val |= 0x0800; | 297 | val |= 0x0800; |
@@ -293,6 +312,8 @@ static int iTCO_wdt_keepalive(void) | |||
293 | { | 312 | { |
294 | spin_lock(&iTCO_wdt_private.io_lock); | 313 | spin_lock(&iTCO_wdt_private.io_lock); |
295 | 314 | ||
315 | iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat); | ||
316 | |||
296 | /* Reload the timer by writing to the TCO Timer Counter register */ | 317 | /* Reload the timer by writing to the TCO Timer Counter register */ |
297 | if (iTCO_wdt_private.iTCO_version == 2) { | 318 | if (iTCO_wdt_private.iTCO_version == 2) { |
298 | outw(0x01, TCO_RLD); | 319 | outw(0x01, TCO_RLD); |
@@ -319,6 +340,8 @@ static int iTCO_wdt_set_heartbeat(int t) | |||
319 | ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f))) | 340 | ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f))) |
320 | return -EINVAL; | 341 | return -EINVAL; |
321 | 342 | ||
343 | iTCO_vendor_pre_set_heartbeat(tmrval); | ||
344 | |||
322 | /* Write new heartbeat to watchdog */ | 345 | /* Write new heartbeat to watchdog */ |
323 | if (iTCO_wdt_private.iTCO_version == 2) { | 346 | if (iTCO_wdt_private.iTCO_version == 2) { |
324 | spin_lock(&iTCO_wdt_private.io_lock); | 347 | 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, | |||
569 | } | 592 | } |
570 | 593 | ||
571 | /* Check chipset's NO_REBOOT bit */ | 594 | /* Check chipset's NO_REBOOT bit */ |
572 | if (iTCO_wdt_unset_NO_REBOOT_bit()) { | 595 | if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) { |
573 | printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); | 596 | printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); |
574 | ret = -ENODEV; /* Cannot reset NO_REBOOT bit */ | 597 | ret = -ENODEV; /* Cannot reset NO_REBOOT bit */ |
575 | goto out; | 598 | goto out; |
diff --git a/drivers/char/watchdog/pc87413_wdt.c b/drivers/char/watchdog/pc87413_wdt.c new file mode 100644 index 000000000000..1d447e32af41 --- /dev/null +++ b/drivers/char/watchdog/pc87413_wdt.c | |||
@@ -0,0 +1,635 @@ | |||
1 | /* | ||
2 | * NS pc87413-wdt Watchdog Timer driver for Linux 2.6.x.x | ||
3 | * | ||
4 | * This code is based on wdt.c with original copyright. | ||
5 | * | ||
6 | * (C) Copyright 2006 Sven Anders, <anders@anduras.de> | ||
7 | * and Marcus Junker, <junker@anduras.de> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version | ||
12 | * 2 of the License, or (at your option) any later version. | ||
13 | * | ||
14 | * Neither Sven Anders, Marcus Junker nor ANDURAS AG | ||
15 | * admit liability nor provide warranty for any of this software. | ||
16 | * This material is provided "AS-IS" and at no charge. | ||
17 | * | ||
18 | * Release 1.1 | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/types.h> | ||
23 | #include <linux/miscdevice.h> | ||
24 | #include <linux/watchdog.h> | ||
25 | #include <linux/ioport.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/notifier.h> | ||
28 | #include <linux/fs.h> | ||
29 | #include <linux/reboot.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | #include <linux/moduleparam.h> | ||
33 | #include <linux/version.h> | ||
34 | |||
35 | #include <asm/io.h> | ||
36 | #include <asm/uaccess.h> | ||
37 | #include <asm/system.h> | ||
38 | |||
39 | /* #define DEBUG 1 */ | ||
40 | |||
41 | #define DEFAULT_TIMEOUT 1 /* 1 minute */ | ||
42 | #define MAX_TIMEOUT 255 | ||
43 | |||
44 | #define VERSION "1.1" | ||
45 | #define MODNAME "pc87413 WDT" | ||
46 | #define PFX MODNAME ": " | ||
47 | #define DPFX MODNAME " - DEBUG: " | ||
48 | |||
49 | #define WDT_INDEX_IO_PORT (io+0) /* I/O port base (index register) */ | ||
50 | #define WDT_DATA_IO_PORT (WDT_INDEX_IO_PORT+1) | ||
51 | #define SWC_LDN 0x04 | ||
52 | #define SIOCFG2 0x22 /* Serial IO register */ | ||
53 | #define WDCTL 0x10 /* Watchdog-Timer-Controll-Register */ | ||
54 | #define WDTO 0x11 /* Watchdog timeout register */ | ||
55 | #define WDCFG 0x12 /* Watchdog config register */ | ||
56 | |||
57 | static int io = 0x2E; /* Address used on Portwell Boards */ | ||
58 | |||
59 | static int timeout = DEFAULT_TIMEOUT; /* timeout value */ | ||
60 | static unsigned long timer_enabled = 0; /* is the timer enabled? */ | ||
61 | |||
62 | static char expect_close; /* is the close expected? */ | ||
63 | |||
64 | static spinlock_t io_lock; /* to guard the watchdog from io races */ | ||
65 | |||
66 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
67 | |||
68 | /* -- Low level function ----------------------------------------*/ | ||
69 | |||
70 | /* Select pins for Watchdog output */ | ||
71 | |||
72 | static inline void pc87413_select_wdt_out (void) | ||
73 | { | ||
74 | unsigned int cr_data = 0; | ||
75 | |||
76 | /* Step 1: Select multiple pin,pin55,as WDT output */ | ||
77 | |||
78 | outb_p(SIOCFG2, WDT_INDEX_IO_PORT); | ||
79 | |||
80 | cr_data = inb (WDT_DATA_IO_PORT); | ||
81 | |||
82 | cr_data |= 0x80; /* Set Bit7 to 1*/ | ||
83 | outb_p(SIOCFG2, WDT_INDEX_IO_PORT); | ||
84 | |||
85 | outb_p(cr_data, WDT_DATA_IO_PORT); | ||
86 | |||
87 | #ifdef DEBUG | ||
88 | printk(KERN_INFO DPFX "Select multiple pin,pin55,as WDT output:" | ||
89 | " Bit7 to 1: %d\n", cr_data); | ||
90 | #endif | ||
91 | } | ||
92 | |||
93 | /* Enable SWC functions */ | ||
94 | |||
95 | static inline void pc87413_enable_swc(void) | ||
96 | { | ||
97 | unsigned int cr_data=0; | ||
98 | |||
99 | /* Step 2: Enable SWC functions */ | ||
100 | |||
101 | outb_p(0x07, WDT_INDEX_IO_PORT); /* Point SWC_LDN (LDN=4) */ | ||
102 | outb_p(SWC_LDN, WDT_DATA_IO_PORT); | ||
103 | |||
104 | outb_p(0x30, WDT_INDEX_IO_PORT); /* Read Index 0x30 First */ | ||
105 | cr_data = inb(WDT_DATA_IO_PORT); | ||
106 | cr_data |= 0x01; /* Set Bit0 to 1 */ | ||
107 | outb_p(0x30, WDT_INDEX_IO_PORT); | ||
108 | outb_p(cr_data, WDT_DATA_IO_PORT); /* Index0x30_bit0P1 */ | ||
109 | |||
110 | #ifdef DEBUG | ||
111 | printk(KERN_INFO DPFX "pc87413 - Enable SWC functions\n"); | ||
112 | #endif | ||
113 | } | ||
114 | |||
115 | /* Read SWC I/O base address */ | ||
116 | |||
117 | static inline unsigned int pc87413_get_swc_base(void) | ||
118 | { | ||
119 | unsigned int swc_base_addr = 0; | ||
120 | unsigned char addr_l, addr_h = 0; | ||
121 | |||
122 | /* Step 3: Read SWC I/O Base Address */ | ||
123 | |||
124 | outb_p(0x60, WDT_INDEX_IO_PORT); /* Read Index 0x60 */ | ||
125 | addr_h = inb(WDT_DATA_IO_PORT); | ||
126 | |||
127 | outb_p(0x61, WDT_INDEX_IO_PORT); /* Read Index 0x61 */ | ||
128 | |||
129 | addr_l = inb(WDT_DATA_IO_PORT); | ||
130 | |||
131 | swc_base_addr = (addr_h << 8) + addr_l; | ||
132 | |||
133 | #ifdef DEBUG | ||
134 | printk(KERN_INFO DPFX "Read SWC I/O Base Address: low %d, high %d," | ||
135 | " res %d\n", addr_l, addr_h, swc_base_addr); | ||
136 | #endif | ||
137 | |||
138 | return swc_base_addr; | ||
139 | } | ||
140 | |||
141 | /* Select Bank 3 of SWC */ | ||
142 | |||
143 | static inline void pc87413_swc_bank3(unsigned int swc_base_addr) | ||
144 | { | ||
145 | /* Step 4: Select Bank3 of SWC */ | ||
146 | |||
147 | outb_p(inb(swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f); | ||
148 | |||
149 | #ifdef DEBUG | ||
150 | printk(KERN_INFO DPFX "Select Bank3 of SWC\n"); | ||
151 | #endif | ||
152 | } | ||
153 | |||
154 | /* Set watchdog timeout to x minutes */ | ||
155 | |||
156 | static inline void pc87413_programm_wdto(unsigned int swc_base_addr, | ||
157 | char pc87413_time) | ||
158 | { | ||
159 | /* Step 5: Programm WDTO, Twd. */ | ||
160 | |||
161 | outb_p(pc87413_time, swc_base_addr + WDTO); | ||
162 | |||
163 | #ifdef DEBUG | ||
164 | printk(KERN_INFO DPFX "Set WDTO to %d minutes\n", pc87413_time); | ||
165 | #endif | ||
166 | } | ||
167 | |||
168 | /* Enable WDEN */ | ||
169 | |||
170 | static inline void pc87413_enable_wden(unsigned int swc_base_addr) | ||
171 | { | ||
172 | /* Step 6: Enable WDEN */ | ||
173 | |||
174 | outb_p(inb (swc_base_addr + WDCTL) | 0x01, swc_base_addr + WDCTL); | ||
175 | |||
176 | #ifdef DEBUG | ||
177 | printk(KERN_INFO DPFX "Enable WDEN\n"); | ||
178 | #endif | ||
179 | } | ||
180 | |||
181 | /* Enable SW_WD_TREN */ | ||
182 | static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr) | ||
183 | { | ||
184 | /* Enable SW_WD_TREN */ | ||
185 | |||
186 | outb_p(inb (swc_base_addr + WDCFG) | 0x80, swc_base_addr + WDCFG); | ||
187 | |||
188 | #ifdef DEBUG | ||
189 | printk(KERN_INFO DPFX "Enable SW_WD_TREN\n"); | ||
190 | #endif | ||
191 | } | ||
192 | |||
193 | /* Disable SW_WD_TREN */ | ||
194 | |||
195 | static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr) | ||
196 | { | ||
197 | /* Disable SW_WD_TREN */ | ||
198 | |||
199 | outb_p(inb (swc_base_addr + WDCFG) & 0x7f, swc_base_addr + WDCFG); | ||
200 | |||
201 | #ifdef DEBUG | ||
202 | printk(KERN_INFO DPFX "pc87413 - Disable SW_WD_TREN\n"); | ||
203 | #endif | ||
204 | } | ||
205 | |||
206 | /* Enable SW_WD_TRG */ | ||
207 | |||
208 | static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr) | ||
209 | { | ||
210 | /* Enable SW_WD_TRG */ | ||
211 | |||
212 | outb_p(inb (swc_base_addr + WDCTL) | 0x80, swc_base_addr + WDCTL); | ||
213 | |||
214 | #ifdef DEBUG | ||
215 | printk(KERN_INFO DPFX "pc87413 - Enable SW_WD_TRG\n"); | ||
216 | #endif | ||
217 | } | ||
218 | |||
219 | /* Disable SW_WD_TRG */ | ||
220 | |||
221 | static inline void pc87413_disable_sw_wd_trg(unsigned int swc_base_addr) | ||
222 | { | ||
223 | /* Disable SW_WD_TRG */ | ||
224 | |||
225 | outb_p(inb (swc_base_addr + WDCTL) & 0x7f, swc_base_addr + WDCTL); | ||
226 | |||
227 | #ifdef DEBUG | ||
228 | printk(KERN_INFO DPFX "Disable SW_WD_TRG\n"); | ||
229 | #endif | ||
230 | } | ||
231 | |||
232 | /* -- Higher level functions ------------------------------------*/ | ||
233 | |||
234 | /* Enable the watchdog */ | ||
235 | |||
236 | static void pc87413_enable(void) | ||
237 | { | ||
238 | unsigned int swc_base_addr; | ||
239 | |||
240 | spin_lock(&io_lock); | ||
241 | |||
242 | pc87413_select_wdt_out(); | ||
243 | pc87413_enable_swc(); | ||
244 | swc_base_addr = pc87413_get_swc_base(); | ||
245 | pc87413_swc_bank3(swc_base_addr); | ||
246 | pc87413_programm_wdto(swc_base_addr, timeout); | ||
247 | pc87413_enable_wden(swc_base_addr); | ||
248 | pc87413_enable_sw_wd_tren(swc_base_addr); | ||
249 | pc87413_enable_sw_wd_trg(swc_base_addr); | ||
250 | |||
251 | spin_unlock(&io_lock); | ||
252 | } | ||
253 | |||
254 | /* Disable the watchdog */ | ||
255 | |||
256 | static void pc87413_disable(void) | ||
257 | { | ||
258 | unsigned int swc_base_addr; | ||
259 | |||
260 | spin_lock(&io_lock); | ||
261 | |||
262 | pc87413_select_wdt_out(); | ||
263 | pc87413_enable_swc(); | ||
264 | swc_base_addr = pc87413_get_swc_base(); | ||
265 | pc87413_swc_bank3(swc_base_addr); | ||
266 | pc87413_disable_sw_wd_tren(swc_base_addr); | ||
267 | pc87413_disable_sw_wd_trg(swc_base_addr); | ||
268 | pc87413_programm_wdto(swc_base_addr, 0); | ||
269 | |||
270 | spin_unlock(&io_lock); | ||
271 | } | ||
272 | |||
273 | /* Refresh the watchdog */ | ||
274 | |||
275 | static void pc87413_refresh(void) | ||
276 | { | ||
277 | unsigned int swc_base_addr; | ||
278 | |||
279 | spin_lock(&io_lock); | ||
280 | |||
281 | pc87413_select_wdt_out(); | ||
282 | pc87413_enable_swc(); | ||
283 | swc_base_addr = pc87413_get_swc_base(); | ||
284 | pc87413_swc_bank3(swc_base_addr); | ||
285 | pc87413_disable_sw_wd_tren(swc_base_addr); | ||
286 | pc87413_disable_sw_wd_trg(swc_base_addr); | ||
287 | pc87413_programm_wdto(swc_base_addr, timeout); | ||
288 | pc87413_enable_wden(swc_base_addr); | ||
289 | pc87413_enable_sw_wd_tren(swc_base_addr); | ||
290 | pc87413_enable_sw_wd_trg(swc_base_addr); | ||
291 | |||
292 | spin_unlock(&io_lock); | ||
293 | } | ||
294 | |||
295 | /* -- File operations -------------------------------------------*/ | ||
296 | |||
297 | /** | ||
298 | * pc87413_open: | ||
299 | * @inode: inode of device | ||
300 | * @file: file handle to device | ||
301 | * | ||
302 | */ | ||
303 | |||
304 | static int pc87413_open(struct inode *inode, struct file *file) | ||
305 | { | ||
306 | /* /dev/watchdog can only be opened once */ | ||
307 | |||
308 | if (test_and_set_bit(0, &timer_enabled)) | ||
309 | return -EBUSY; | ||
310 | |||
311 | if (nowayout) | ||
312 | __module_get(THIS_MODULE); | ||
313 | |||
314 | /* Reload and activate timer */ | ||
315 | pc87413_refresh(); | ||
316 | |||
317 | printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to" | ||
318 | " %d minute(s).\n", timeout); | ||
319 | |||
320 | return nonseekable_open(inode, file); | ||
321 | } | ||
322 | |||
323 | /** | ||
324 | * pc87413_release: | ||
325 | * @inode: inode to board | ||
326 | * @file: file handle to board | ||
327 | * | ||
328 | * The watchdog has a configurable API. There is a religious dispute | ||
329 | * between people who want their watchdog to be able to shut down and | ||
330 | * those who want to be sure if the watchdog manager dies the machine | ||
331 | * reboots. In the former case we disable the counters, in the latter | ||
332 | * case you have to open it again very soon. | ||
333 | */ | ||
334 | |||
335 | static int pc87413_release(struct inode *inode, struct file *file) | ||
336 | { | ||
337 | /* Shut off the timer. */ | ||
338 | |||
339 | if (expect_close == 42) { | ||
340 | pc87413_disable(); | ||
341 | printk(KERN_INFO MODNAME "Watchdog disabled," | ||
342 | " sleeping again...\n"); | ||
343 | } else { | ||
344 | printk(KERN_CRIT MODNAME "Unexpected close, not stopping" | ||
345 | " watchdog!\n"); | ||
346 | pc87413_refresh(); | ||
347 | } | ||
348 | |||
349 | clear_bit(0, &timer_enabled); | ||
350 | expect_close = 0; | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | /** | ||
356 | * pc87413_status: | ||
357 | * | ||
358 | * return, if the watchdog is enabled (timeout is set...) | ||
359 | */ | ||
360 | |||
361 | |||
362 | static int pc87413_status(void) | ||
363 | { | ||
364 | return 0; /* currently not supported */ | ||
365 | } | ||
366 | |||
367 | /** | ||
368 | * pc87413_write: | ||
369 | * @file: file handle to the watchdog | ||
370 | * @data: data buffer to write | ||
371 | * @len: length in bytes | ||
372 | * @ppos: pointer to the position to write. No seeks allowed | ||
373 | * | ||
374 | * A write to a watchdog device is defined as a keepalive signal. Any | ||
375 | * write of data will do, as we we don't define content meaning. | ||
376 | */ | ||
377 | |||
378 | static ssize_t pc87413_write(struct file *file, const char __user *data, | ||
379 | size_t len, loff_t *ppos) | ||
380 | { | ||
381 | /* See if we got the magic character 'V' and reload the timer */ | ||
382 | if (len) { | ||
383 | if (!nowayout) { | ||
384 | size_t i; | ||
385 | |||
386 | /* reset expect flag */ | ||
387 | expect_close = 0; | ||
388 | |||
389 | /* scan to see whether or not we got the magic character */ | ||
390 | for (i = 0; i != len; i++) { | ||
391 | char c; | ||
392 | if (get_user(c, data+i)) | ||
393 | return -EFAULT; | ||
394 | if (c == 'V') | ||
395 | expect_close = 42; | ||
396 | } | ||
397 | } | ||
398 | |||
399 | /* someone wrote to us, we should reload the timer */ | ||
400 | pc87413_refresh(); | ||
401 | } | ||
402 | return len; | ||
403 | } | ||
404 | |||
405 | /** | ||
406 | * pc87413_ioctl: | ||
407 | * @inode: inode of the device | ||
408 | * @file: file handle to the device | ||
409 | * @cmd: watchdog command | ||
410 | * @arg: argument pointer | ||
411 | * | ||
412 | * The watchdog API defines a common set of functions for all watchdogs | ||
413 | * according to their available features. We only actually usefully support | ||
414 | * querying capabilities and current status. | ||
415 | */ | ||
416 | |||
417 | static int pc87413_ioctl(struct inode *inode, struct file *file, | ||
418 | unsigned int cmd, unsigned long arg) | ||
419 | { | ||
420 | int new_timeout; | ||
421 | |||
422 | union { | ||
423 | struct watchdog_info __user *ident; | ||
424 | int __user *i; | ||
425 | } uarg; | ||
426 | |||
427 | static struct watchdog_info ident = { | ||
428 | .options = WDIOF_KEEPALIVEPING | | ||
429 | WDIOF_SETTIMEOUT | | ||
430 | WDIOF_MAGICCLOSE, | ||
431 | .firmware_version = 1, | ||
432 | .identity = "PC87413(HF/F) watchdog" | ||
433 | }; | ||
434 | |||
435 | uarg.i = (int __user *)arg; | ||
436 | |||
437 | switch(cmd) { | ||
438 | default: | ||
439 | return -ENOTTY; | ||
440 | |||
441 | case WDIOC_GETSUPPORT: | ||
442 | return copy_to_user(uarg.ident, &ident, | ||
443 | sizeof(ident)) ? -EFAULT : 0; | ||
444 | |||
445 | case WDIOC_GETSTATUS: | ||
446 | return put_user(pc87413_status(), uarg.i); | ||
447 | |||
448 | case WDIOC_GETBOOTSTATUS: | ||
449 | return put_user(0, uarg.i); | ||
450 | |||
451 | case WDIOC_KEEPALIVE: | ||
452 | pc87413_refresh(); | ||
453 | #ifdef DEBUG | ||
454 | printk(KERN_INFO DPFX "keepalive\n"); | ||
455 | #endif | ||
456 | return 0; | ||
457 | |||
458 | case WDIOC_SETTIMEOUT: | ||
459 | if (get_user(new_timeout, uarg.i)) | ||
460 | return -EFAULT; | ||
461 | |||
462 | // the API states this is given in secs | ||
463 | new_timeout /= 60; | ||
464 | |||
465 | if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) | ||
466 | return -EINVAL; | ||
467 | |||
468 | timeout = new_timeout; | ||
469 | pc87413_refresh(); | ||
470 | |||
471 | // fall through and return the new timeout... | ||
472 | |||
473 | case WDIOC_GETTIMEOUT: | ||
474 | |||
475 | new_timeout = timeout * 60; | ||
476 | |||
477 | return put_user(new_timeout, uarg.i); | ||
478 | |||
479 | case WDIOC_SETOPTIONS: | ||
480 | { | ||
481 | int options, retval = -EINVAL; | ||
482 | |||
483 | if (get_user(options, uarg.i)) | ||
484 | return -EFAULT; | ||
485 | |||
486 | if (options & WDIOS_DISABLECARD) { | ||
487 | pc87413_disable(); | ||
488 | retval = 0; | ||
489 | } | ||
490 | |||
491 | if (options & WDIOS_ENABLECARD) { | ||
492 | pc87413_enable(); | ||
493 | retval = 0; | ||
494 | } | ||
495 | |||
496 | return retval; | ||
497 | } | ||
498 | } | ||
499 | } | ||
500 | |||
501 | /* -- Notifier funtions -----------------------------------------*/ | ||
502 | |||
503 | /** | ||
504 | * notify_sys: | ||
505 | * @this: our notifier block | ||
506 | * @code: the event being reported | ||
507 | * @unused: unused | ||
508 | * | ||
509 | * Our notifier is called on system shutdowns. We want to turn the card | ||
510 | * off at reboot otherwise the machine will reboot again during memory | ||
511 | * test or worse yet during the following fsck. This would suck, in fact | ||
512 | * trust me - if it happens it does suck. | ||
513 | */ | ||
514 | |||
515 | static int pc87413_notify_sys(struct notifier_block *this, | ||
516 | unsigned long code, | ||
517 | void *unused) | ||
518 | { | ||
519 | if (code == SYS_DOWN || code == SYS_HALT) | ||
520 | { | ||
521 | /* Turn the card off */ | ||
522 | pc87413_disable(); | ||
523 | } | ||
524 | return NOTIFY_DONE; | ||
525 | } | ||
526 | |||
527 | /* -- Module's structures ---------------------------------------*/ | ||
528 | |||
529 | static struct file_operations pc87413_fops = { | ||
530 | .owner = THIS_MODULE, | ||
531 | .llseek = no_llseek, | ||
532 | .write = pc87413_write, | ||
533 | .ioctl = pc87413_ioctl, | ||
534 | .open = pc87413_open, | ||
535 | .release = pc87413_release, | ||
536 | }; | ||
537 | |||
538 | static struct notifier_block pc87413_notifier = | ||
539 | { | ||
540 | .notifier_call = pc87413_notify_sys, | ||
541 | }; | ||
542 | |||
543 | static struct miscdevice pc87413_miscdev= | ||
544 | { | ||
545 | .minor = WATCHDOG_MINOR, | ||
546 | .name = "watchdog", | ||
547 | .fops = &pc87413_fops | ||
548 | }; | ||
549 | |||
550 | /* -- Module init functions -------------------------------------*/ | ||
551 | |||
552 | /** | ||
553 | * pc87413_init: module's "constructor" | ||
554 | * | ||
555 | * Set up the WDT watchdog board. All we have to do is grab the | ||
556 | * resources we require and bitch if anyone beat us to them. | ||
557 | * The open() function will actually kick the board off. | ||
558 | */ | ||
559 | |||
560 | static int __init pc87413_init(void) | ||
561 | { | ||
562 | int ret; | ||
563 | |||
564 | spin_lock_init(&io_lock); | ||
565 | |||
566 | printk(KERN_INFO PFX "Version " VERSION " at io 0x%X\n", WDT_INDEX_IO_PORT); | ||
567 | |||
568 | /* request_region(io, 2, "pc87413"); */ | ||
569 | |||
570 | ret = register_reboot_notifier(&pc87413_notifier); | ||
571 | if (ret != 0) { | ||
572 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | ||
573 | ret); | ||
574 | } | ||
575 | |||
576 | ret = misc_register(&pc87413_miscdev); | ||
577 | |||
578 | if (ret != 0) { | ||
579 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | ||
580 | WATCHDOG_MINOR, ret); | ||
581 | unregister_reboot_notifier(&pc87413_notifier); | ||
582 | return ret; | ||
583 | } | ||
584 | |||
585 | printk(KERN_INFO PFX "initialized. timeout=%d min \n", timeout); | ||
586 | |||
587 | pc87413_enable(); | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | /** | ||
593 | * pc87413_exit: module's "destructor" | ||
594 | * | ||
595 | * Unload the watchdog. You cannot do this with any file handles open. | ||
596 | * If your watchdog is set to continue ticking on close and you unload | ||
597 | * it, well it keeps ticking. We won't get the interrupt but the board | ||
598 | * will not touch PC memory so all is fine. You just have to load a new | ||
599 | * module in 60 seconds or reboot. | ||
600 | */ | ||
601 | |||
602 | static void __exit pc87413_exit(void) | ||
603 | { | ||
604 | /* Stop the timer before we leave */ | ||
605 | if (!nowayout) | ||
606 | { | ||
607 | pc87413_disable(); | ||
608 | printk(KERN_INFO MODNAME "Watchdog disabled.\n"); | ||
609 | } | ||
610 | |||
611 | misc_deregister(&pc87413_miscdev); | ||
612 | unregister_reboot_notifier(&pc87413_notifier); | ||
613 | /* release_region(io,2); */ | ||
614 | |||
615 | printk(MODNAME " watchdog component driver removed.\n"); | ||
616 | } | ||
617 | |||
618 | module_init(pc87413_init); | ||
619 | module_exit(pc87413_exit); | ||
620 | |||
621 | MODULE_AUTHOR("Sven Anders <anders@anduras.de>, Marcus Junker <junker@anduras.de>,"); | ||
622 | MODULE_DESCRIPTION("PC87413 WDT driver"); | ||
623 | MODULE_LICENSE("GPL"); | ||
624 | |||
625 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
626 | |||
627 | module_param(io, int, 0); | ||
628 | MODULE_PARM_DESC(io, MODNAME " I/O port (default: " __MODULE_STRING(io) ")."); | ||
629 | |||
630 | module_param(timeout, int, 0); | ||
631 | MODULE_PARM_DESC(timeout, "Watchdog timeout in minutes (default=" __MODULE_STRING(timeout) ")."); | ||
632 | |||
633 | module_param(nowayout, int, 0); | ||
634 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | ||
635 | |||
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c index bda45334d802..61138726b501 100644 --- a/drivers/char/watchdog/pcwd_usb.c +++ b/drivers/char/watchdog/pcwd_usb.c | |||
@@ -561,8 +561,7 @@ static struct notifier_block usb_pcwd_notifier = { | |||
561 | */ | 561 | */ |
562 | static inline void usb_pcwd_delete (struct usb_pcwd_private *usb_pcwd) | 562 | static inline void usb_pcwd_delete (struct usb_pcwd_private *usb_pcwd) |
563 | { | 563 | { |
564 | if (usb_pcwd->intr_urb != NULL) | 564 | usb_free_urb(usb_pcwd->intr_urb); |
565 | usb_free_urb (usb_pcwd->intr_urb); | ||
566 | if (usb_pcwd->intr_buffer != NULL) | 565 | if (usb_pcwd->intr_buffer != NULL) |
567 | usb_buffer_free(usb_pcwd->udev, usb_pcwd->intr_size, | 566 | usb_buffer_free(usb_pcwd->udev, usb_pcwd->intr_size, |
568 | usb_pcwd->intr_buffer, usb_pcwd->intr_dma); | 567 | 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 | |||
635 | usb_pcwd->intr_size = (le16_to_cpu(endpoint->wMaxPacketSize) > 8 ? le16_to_cpu(endpoint->wMaxPacketSize) : 8); | 634 | usb_pcwd->intr_size = (le16_to_cpu(endpoint->wMaxPacketSize) > 8 ? le16_to_cpu(endpoint->wMaxPacketSize) : 8); |
636 | 635 | ||
637 | /* set up the memory buffer's */ | 636 | /* set up the memory buffer's */ |
638 | if (!(usb_pcwd->intr_buffer = usb_buffer_alloc(udev, usb_pcwd->intr_size, SLAB_ATOMIC, &usb_pcwd->intr_dma))) { | 637 | if (!(usb_pcwd->intr_buffer = usb_buffer_alloc(udev, usb_pcwd->intr_size, GFP_ATOMIC, &usb_pcwd->intr_dma))) { |
639 | printk(KERN_ERR PFX "Out of memory\n"); | 638 | printk(KERN_ERR PFX "Out of memory\n"); |
640 | goto error; | 639 | goto error; |
641 | } | 640 | } |
diff --git a/drivers/char/watchdog/rm9k_wdt.c b/drivers/char/watchdog/rm9k_wdt.c new file mode 100644 index 000000000000..ec3909371c21 --- /dev/null +++ b/drivers/char/watchdog/rm9k_wdt.c | |||
@@ -0,0 +1,420 @@ | |||
1 | /* | ||
2 | * Watchdog implementation for GPI h/w found on PMC-Sierra RM9xxx | ||
3 | * chips. | ||
4 | * | ||
5 | * Copyright (C) 2004 by Basler Vision Technologies AG | ||
6 | * Author: Thomas Koeller <thomas.koeller@baslerweb.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/moduleparam.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/fs.h> | ||
28 | #include <linux/reboot.h> | ||
29 | #include <linux/notifier.h> | ||
30 | #include <linux/miscdevice.h> | ||
31 | #include <linux/watchdog.h> | ||
32 | #include <asm/io.h> | ||
33 | #include <asm/atomic.h> | ||
34 | #include <asm/processor.h> | ||
35 | #include <asm/uaccess.h> | ||
36 | #include <asm/system.h> | ||
37 | #include <asm/rm9k-ocd.h> | ||
38 | |||
39 | #include <rm9k_wdt.h> | ||
40 | |||
41 | |||
42 | #define CLOCK 125000000 | ||
43 | #define MAX_TIMEOUT_SECONDS 32 | ||
44 | #define CPCCR 0x0080 | ||
45 | #define CPGIG1SR 0x0044 | ||
46 | #define CPGIG1ER 0x0054 | ||
47 | |||
48 | |||
49 | /* Function prototypes */ | ||
50 | static irqreturn_t wdt_gpi_irqhdl(int, void *, struct pt_regs *); | ||
51 | static void wdt_gpi_start(void); | ||
52 | static void wdt_gpi_stop(void); | ||
53 | static void wdt_gpi_set_timeout(unsigned int); | ||
54 | static int wdt_gpi_open(struct inode *, struct file *); | ||
55 | static int wdt_gpi_release(struct inode *, struct file *); | ||
56 | static ssize_t wdt_gpi_write(struct file *, const char __user *, size_t, loff_t *); | ||
57 | static long wdt_gpi_ioctl(struct file *, unsigned int, unsigned long); | ||
58 | static int wdt_gpi_notify(struct notifier_block *, unsigned long, void *); | ||
59 | static const struct resource *wdt_gpi_get_resource(struct platform_device *, const char *, unsigned int); | ||
60 | static int __init wdt_gpi_probe(struct device *); | ||
61 | static int __exit wdt_gpi_remove(struct device *); | ||
62 | |||
63 | |||
64 | static const char wdt_gpi_name[] = "wdt_gpi"; | ||
65 | static atomic_t opencnt; | ||
66 | static int expect_close; | ||
67 | static int locked; | ||
68 | |||
69 | |||
70 | /* These are set from device resources */ | ||
71 | static void __iomem * wd_regs; | ||
72 | static unsigned int wd_irq, wd_ctr; | ||
73 | |||
74 | |||
75 | /* Module arguments */ | ||
76 | static int timeout = MAX_TIMEOUT_SECONDS; | ||
77 | module_param(timeout, int, 0444); | ||
78 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds"); | ||
79 | |||
80 | static unsigned long resetaddr = 0xbffdc200; | ||
81 | module_param(resetaddr, ulong, 0444); | ||
82 | MODULE_PARM_DESC(resetaddr, "Address to write to to force a reset"); | ||
83 | |||
84 | static unsigned long flagaddr = 0xbffdc104; | ||
85 | module_param(flagaddr, ulong, 0444); | ||
86 | MODULE_PARM_DESC(flagaddr, "Address to write to boot flags to"); | ||
87 | |||
88 | static int powercycle; | ||
89 | module_param(powercycle, bool, 0444); | ||
90 | MODULE_PARM_DESC(powercycle, "Cycle power if watchdog expires"); | ||
91 | |||
92 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
93 | module_param(nowayout, bool, 0444); | ||
94 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be disabled once started"); | ||
95 | |||
96 | |||
97 | /* Interrupt handler */ | ||
98 | static irqreturn_t wdt_gpi_irqhdl(int irq, void *ctxt, struct pt_regs *regs) | ||
99 | { | ||
100 | if (!unlikely(__raw_readl(wd_regs + 0x0008) & 0x1)) | ||
101 | return IRQ_NONE; | ||
102 | __raw_writel(0x1, wd_regs + 0x0008); | ||
103 | |||
104 | |||
105 | printk(KERN_CRIT "%s: watchdog expired - resetting system\n", | ||
106 | wdt_gpi_name); | ||
107 | |||
108 | *(volatile char *) flagaddr |= 0x01; | ||
109 | *(volatile char *) resetaddr = powercycle ? 0x01 : 0x2; | ||
110 | iob(); | ||
111 | while (1) | ||
112 | cpu_relax(); | ||
113 | } | ||
114 | |||
115 | |||
116 | /* Watchdog functions */ | ||
117 | static void wdt_gpi_start(void) | ||
118 | { | ||
119 | u32 reg; | ||
120 | |||
121 | lock_titan_regs(); | ||
122 | reg = titan_readl(CPGIG1ER); | ||
123 | titan_writel(reg | (0x100 << wd_ctr), CPGIG1ER); | ||
124 | iob(); | ||
125 | unlock_titan_regs(); | ||
126 | } | ||
127 | |||
128 | static void wdt_gpi_stop(void) | ||
129 | { | ||
130 | u32 reg; | ||
131 | |||
132 | lock_titan_regs(); | ||
133 | reg = titan_readl(CPCCR) & ~(0xf << (wd_ctr * 4)); | ||
134 | titan_writel(reg, CPCCR); | ||
135 | reg = titan_readl(CPGIG1ER); | ||
136 | titan_writel(reg & ~(0x100 << wd_ctr), CPGIG1ER); | ||
137 | iob(); | ||
138 | unlock_titan_regs(); | ||
139 | } | ||
140 | |||
141 | static void wdt_gpi_set_timeout(unsigned int to) | ||
142 | { | ||
143 | u32 reg; | ||
144 | const u32 wdval = (to * CLOCK) & ~0x0000000f; | ||
145 | |||
146 | lock_titan_regs(); | ||
147 | reg = titan_readl(CPCCR) & ~(0xf << (wd_ctr * 4)); | ||
148 | titan_writel(reg, CPCCR); | ||
149 | wmb(); | ||
150 | __raw_writel(wdval, wd_regs + 0x0000); | ||
151 | wmb(); | ||
152 | titan_writel(reg | (0x2 << (wd_ctr * 4)), CPCCR); | ||
153 | wmb(); | ||
154 | titan_writel(reg | (0x5 << (wd_ctr * 4)), CPCCR); | ||
155 | iob(); | ||
156 | unlock_titan_regs(); | ||
157 | } | ||
158 | |||
159 | |||
160 | /* /dev/watchdog operations */ | ||
161 | static int wdt_gpi_open(struct inode *inode, struct file *file) | ||
162 | { | ||
163 | int res; | ||
164 | |||
165 | if (unlikely(atomic_dec_if_positive(&opencnt) < 0)) | ||
166 | return -EBUSY; | ||
167 | |||
168 | expect_close = 0; | ||
169 | if (locked) { | ||
170 | module_put(THIS_MODULE); | ||
171 | free_irq(wd_irq, &miscdev); | ||
172 | locked = 0; | ||
173 | } | ||
174 | |||
175 | res = request_irq(wd_irq, wdt_gpi_irqhdl, SA_SHIRQ | SA_INTERRUPT, | ||
176 | wdt_gpi_name, &miscdev); | ||
177 | if (unlikely(res)) | ||
178 | return res; | ||
179 | |||
180 | wdt_gpi_set_timeout(timeout); | ||
181 | wdt_gpi_start(); | ||
182 | |||
183 | printk(KERN_INFO "%s: watchdog started, timeout = %u seconds\n", | ||
184 | wdt_gpi_name, timeout); | ||
185 | return nonseekable_open(inode, file); | ||
186 | } | ||
187 | |||
188 | static int wdt_gpi_release(struct inode *inode, struct file *file) | ||
189 | { | ||
190 | if (nowayout) { | ||
191 | printk(KERN_INFO "%s: no way out - watchdog left running\n", | ||
192 | wdt_gpi_name); | ||
193 | __module_get(THIS_MODULE); | ||
194 | locked = 1; | ||
195 | } else { | ||
196 | if (expect_close) { | ||
197 | wdt_gpi_stop(); | ||
198 | free_irq(wd_irq, &miscdev); | ||
199 | printk(KERN_INFO "%s: watchdog stopped\n", wdt_gpi_name); | ||
200 | } else { | ||
201 | printk(KERN_CRIT "%s: unexpected close() -" | ||
202 | " watchdog left running\n", | ||
203 | wdt_gpi_name); | ||
204 | wdt_gpi_set_timeout(timeout); | ||
205 | __module_get(THIS_MODULE); | ||
206 | locked = 1; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | atomic_inc(&opencnt); | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static ssize_t | ||
215 | wdt_gpi_write(struct file *f, const char __user *d, size_t s, loff_t *o) | ||
216 | { | ||
217 | char val; | ||
218 | |||
219 | wdt_gpi_set_timeout(timeout); | ||
220 | expect_close = (s > 0) && !get_user(val, d) && (val == 'V'); | ||
221 | return s ? 1 : 0; | ||
222 | } | ||
223 | |||
224 | static long | ||
225 | wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | ||
226 | { | ||
227 | long res = -ENOTTY; | ||
228 | const long size = _IOC_SIZE(cmd); | ||
229 | int stat; | ||
230 | void __user *argp = (void __user *)arg; | ||
231 | static struct watchdog_info wdinfo = { | ||
232 | .identity = "RM9xxx/GPI watchdog", | ||
233 | .firmware_version = 0, | ||
234 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | ||
235 | }; | ||
236 | |||
237 | if (unlikely(_IOC_TYPE(cmd) != WATCHDOG_IOCTL_BASE)) | ||
238 | return -ENOTTY; | ||
239 | |||
240 | if ((_IOC_DIR(cmd) & _IOC_READ) | ||
241 | && !access_ok(VERIFY_WRITE, arg, size)) | ||
242 | return -EFAULT; | ||
243 | |||
244 | if ((_IOC_DIR(cmd) & _IOC_WRITE) | ||
245 | && !access_ok(VERIFY_READ, arg, size)) | ||
246 | return -EFAULT; | ||
247 | |||
248 | expect_close = 0; | ||
249 | |||
250 | switch (cmd) { | ||
251 | case WDIOC_GETSUPPORT: | ||
252 | wdinfo.options = nowayout ? | ||
253 | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING : | ||
254 | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE; | ||
255 | res = __copy_to_user(argp, &wdinfo, size) ? -EFAULT : size; | ||
256 | break; | ||
257 | |||
258 | case WDIOC_GETSTATUS: | ||
259 | break; | ||
260 | |||
261 | case WDIOC_GETBOOTSTATUS: | ||
262 | stat = (*(volatile char *) flagaddr & 0x01) | ||
263 | ? WDIOF_CARDRESET : 0; | ||
264 | res = __copy_to_user(argp, &stat, size) ? | ||
265 | -EFAULT : size; | ||
266 | break; | ||
267 | |||
268 | case WDIOC_SETOPTIONS: | ||
269 | break; | ||
270 | |||
271 | case WDIOC_KEEPALIVE: | ||
272 | wdt_gpi_set_timeout(timeout); | ||
273 | res = size; | ||
274 | break; | ||
275 | |||
276 | case WDIOC_SETTIMEOUT: | ||
277 | { | ||
278 | int val; | ||
279 | if (unlikely(__copy_from_user(&val, argp, size))) { | ||
280 | res = -EFAULT; | ||
281 | break; | ||
282 | } | ||
283 | |||
284 | if (val > MAX_TIMEOUT_SECONDS) | ||
285 | val = MAX_TIMEOUT_SECONDS; | ||
286 | timeout = val; | ||
287 | wdt_gpi_set_timeout(val); | ||
288 | res = size; | ||
289 | printk(KERN_INFO "%s: timeout set to %u seconds\n", | ||
290 | wdt_gpi_name, timeout); | ||
291 | } | ||
292 | break; | ||
293 | |||
294 | case WDIOC_GETTIMEOUT: | ||
295 | res = __copy_to_user(argp, &timeout, size) ? | ||
296 | -EFAULT : size; | ||
297 | break; | ||
298 | } | ||
299 | |||
300 | return res; | ||
301 | } | ||
302 | |||
303 | |||
304 | /* Shutdown notifier */ | ||
305 | static int | ||
306 | wdt_gpi_notify(struct notifier_block *this, unsigned long code, void *unused) | ||
307 | { | ||
308 | if (code == SYS_DOWN || code == SYS_HALT) | ||
309 | wdt_gpi_stop(); | ||
310 | |||
311 | return NOTIFY_DONE; | ||
312 | } | ||
313 | |||
314 | |||
315 | /* Kernel interfaces */ | ||
316 | static struct file_operations fops = { | ||
317 | .owner = THIS_MODULE, | ||
318 | .open = wdt_gpi_open, | ||
319 | .release = wdt_gpi_release, | ||
320 | .write = wdt_gpi_write, | ||
321 | .unlocked_ioctl = wdt_gpi_ioctl, | ||
322 | }; | ||
323 | |||
324 | static struct miscdevice miscdev = { | ||
325 | .minor = WATCHDOG_MINOR, | ||
326 | .name = wdt_gpi_name, | ||
327 | .fops = &fops, | ||
328 | }; | ||
329 | |||
330 | static struct notifier_block wdt_gpi_shutdown = { | ||
331 | .notifier_call = wdt_gpi_notify, | ||
332 | }; | ||
333 | |||
334 | |||
335 | /* Init & exit procedures */ | ||
336 | static const struct resource * | ||
337 | wdt_gpi_get_resource(struct platform_device *pdv, const char *name, | ||
338 | unsigned int type) | ||
339 | { | ||
340 | char buf[80]; | ||
341 | if (snprintf(buf, sizeof buf, "%s_0", name) >= sizeof buf) | ||
342 | return NULL; | ||
343 | return platform_get_resource_byname(pdv, type, buf); | ||
344 | } | ||
345 | |||
346 | /* No hotplugging on the platform bus - use __init */ | ||
347 | static int __init wdt_gpi_probe(struct device *dev) | ||
348 | { | ||
349 | int res; | ||
350 | struct platform_device * const pdv = to_platform_device(dev); | ||
351 | const struct resource | ||
352 | * const rr = wdt_gpi_get_resource(pdv, WDT_RESOURCE_REGS, | ||
353 | IORESOURCE_MEM), | ||
354 | * const ri = wdt_gpi_get_resource(pdv, WDT_RESOURCE_IRQ, | ||
355 | IORESOURCE_IRQ), | ||
356 | * const rc = wdt_gpi_get_resource(pdv, WDT_RESOURCE_COUNTER, | ||
357 | 0); | ||
358 | |||
359 | if (unlikely(!rr || !ri || !rc)) | ||
360 | return -ENXIO; | ||
361 | |||
362 | wd_regs = ioremap_nocache(rr->start, rr->end + 1 - rr->start); | ||
363 | if (unlikely(!wd_regs)) | ||
364 | return -ENOMEM; | ||
365 | wd_irq = ri->start; | ||
366 | wd_ctr = rc->start; | ||
367 | res = misc_register(&miscdev); | ||
368 | if (res) | ||
369 | iounmap(wd_regs); | ||
370 | else | ||
371 | register_reboot_notifier(&wdt_gpi_shutdown); | ||
372 | return res; | ||
373 | } | ||
374 | |||
375 | static int __exit wdt_gpi_remove(struct device *dev) | ||
376 | { | ||
377 | int res; | ||
378 | |||
379 | unregister_reboot_notifier(&wdt_gpi_shutdown); | ||
380 | res = misc_deregister(&miscdev); | ||
381 | iounmap(wd_regs); | ||
382 | wd_regs = NULL; | ||
383 | return res; | ||
384 | } | ||
385 | |||
386 | |||
387 | /* Device driver init & exit */ | ||
388 | static struct device_driver wdt_gpi_driver = { | ||
389 | .name = (char *) wdt_gpi_name, | ||
390 | .bus = &platform_bus_type, | ||
391 | .owner = THIS_MODULE, | ||
392 | .probe = wdt_gpi_probe, | ||
393 | .remove = __exit_p(wdt_gpi_remove), | ||
394 | .shutdown = NULL, | ||
395 | .suspend = NULL, | ||
396 | .resume = NULL, | ||
397 | }; | ||
398 | |||
399 | static int __init wdt_gpi_init_module(void) | ||
400 | { | ||
401 | atomic_set(&opencnt, 1); | ||
402 | if (timeout > MAX_TIMEOUT_SECONDS) | ||
403 | timeout = MAX_TIMEOUT_SECONDS; | ||
404 | return driver_register(&wdt_gpi_driver); | ||
405 | } | ||
406 | |||
407 | static void __exit wdt_gpi_cleanup_module(void) | ||
408 | { | ||
409 | driver_unregister(&wdt_gpi_driver); | ||
410 | } | ||
411 | |||
412 | module_init(wdt_gpi_init_module); | ||
413 | module_exit(wdt_gpi_cleanup_module); | ||
414 | |||
415 | MODULE_AUTHOR("Thomas Koeller <thomas.koeller@baslerweb.com>"); | ||
416 | MODULE_DESCRIPTION("Basler eXcite watchdog driver for gpi devices"); | ||
417 | MODULE_VERSION("0.1"); | ||
418 | MODULE_LICENSE("GPL"); | ||
419 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
420 | |||