aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavem <davem>2002-01-16 20:58:38 +0000
committerdavem <davem>2002-01-16 20:58:38 +0000
commit4dd458db8fe96cf9c4de7127d121fc4881b52249 (patch)
treec53be8f19235e197a1ee1b2d9b3c8498894c0230
parent6f03c869e708f289a69077d7dbea133cfaa98773 (diff)
downloadnetdev-vger-cvs-4dd458db8fe96cf9c4de7127d121fc4881b52249.tar.gz
Merge mainline to 2.5.3-pre1
-rw-r--r--CREDITS22
-rw-r--r--MAINTAINERS6
-rw-r--r--Makefile4
-rw-r--r--arch/arm/kernel/init_task.c1
-rw-r--r--arch/i386/defconfig10
-rw-r--r--arch/i386/kernel/init_task.c1
-rw-r--r--arch/ia64/kernel/init_task.c1
-rw-r--r--arch/mips/kernel/init_task.c1
-rw-r--r--arch/mips64/kernel/init_task.c1
-rw-r--r--arch/parisc/kernel/init_task.c1
-rw-r--r--arch/ppc/kernel/setup.c18
-rw-r--r--arch/s390/kernel/init_task.c1
-rw-r--r--arch/s390x/kernel/init_task.c1
-rw-r--r--arch/sh/kernel/init_task.c1
-rw-r--r--arch/sparc/kernel/init_task.c1
-rw-r--r--arch/sparc64/defconfig8
-rw-r--r--arch/sparc64/kernel/init_task.c1
-rw-r--r--drivers/block/loop.c1
-rw-r--r--drivers/block/paride/pf.c3
-rw-r--r--drivers/block/paride/pg.c3
-rw-r--r--drivers/block/paride/pseudo.h4
-rw-r--r--drivers/block/paride/pt.c3
-rw-r--r--drivers/ide/Config.in18
-rw-r--r--drivers/ide/Makefile7
-rw-r--r--drivers/ide/alim15x3.c2
-rw-r--r--drivers/ide/cmd64x.c408
-rw-r--r--drivers/ide/hpt366.c794
-rw-r--r--drivers/ide/ide-cd.c41
-rw-r--r--drivers/ide/ide-cd.h2
-rw-r--r--drivers/ide/ide-cs.c15
-rw-r--r--drivers/ide/ide-disk.c981
-rw-r--r--drivers/ide/ide-dma.c90
-rw-r--r--drivers/ide/ide-features.c49
-rw-r--r--drivers/ide/ide-floppy.c122
-rw-r--r--drivers/ide/ide-geometry.c11
-rw-r--r--drivers/ide/ide-pci.c119
-rw-r--r--drivers/ide/ide-pmac.c8
-rw-r--r--drivers/ide/ide-probe.c92
-rw-r--r--drivers/ide/ide-proc.c64
-rw-r--r--drivers/ide/ide-tape.c95
-rw-r--r--drivers/ide/ide-taskfile.c1824
-rw-r--r--drivers/ide/ide.c583
-rw-r--r--drivers/ide/pdc202xx.c630
-rw-r--r--drivers/ide/pdc4030.c123
-rw-r--r--drivers/ide/pdcadma.c109
-rw-r--r--drivers/ide/piix.c2
-rw-r--r--drivers/ide/qd65xx.c25
-rw-r--r--drivers/ide/qd65xx.h3
-rw-r--r--drivers/ide/serverworks.c217
-rw-r--r--drivers/ide/slc90e66.c14
-rw-r--r--drivers/mtd/devices/blkmtd.c1
-rw-r--r--drivers/mtd/mtdblock.c8
-rw-r--r--drivers/parport/ChangeLog6
-rw-r--r--drivers/parport/Config.in10
-rw-r--r--drivers/parport/ieee1284_ops.c3
-rw-r--r--drivers/scsi/ide-scsi.c80
-rw-r--r--drivers/usb/storage/usb.c3
-rw-r--r--fs/fat/dir.c14
-rw-r--r--fs/fat/inode.c329
-rw-r--r--fs/fat/misc.c42
-rw-r--r--fs/fcntl.c22
-rw-r--r--fs/file.c1
-rw-r--r--fs/open.c38
-rw-r--r--fs/partitions/Makefile2
-rw-r--r--fs/partitions/msdos.c16
-rw-r--r--fs/proc/array.c1
-rw-r--r--fs/vfat/namei.c2
-rw-r--r--include/asm-alpha/ide.h14
-rw-r--r--include/asm-arm/ide.h14
-rw-r--r--include/asm-cris/ide.h14
-rw-r--r--include/asm-i386/ide.h14
-rw-r--r--include/asm-ia64/ide.h14
-rw-r--r--include/asm-m68k/ide.h14
-rw-r--r--include/asm-mips/ide.h20
-rw-r--r--include/asm-mips64/ide.h14
-rw-r--r--include/asm-parisc/ide.h14
-rw-r--r--include/asm-ppc/ide.h12
-rw-r--r--include/asm-s390/ide.h14
-rw-r--r--include/asm-s390x/ide.h14
-rw-r--r--include/asm-sh/ide.h14
-rw-r--r--include/asm-sparc/ide.h14
-rw-r--r--include/asm-sparc64/ide.h14
-rw-r--r--include/linux/blkdev.h4
-rw-r--r--include/linux/file.h111
-rw-r--r--include/linux/hdreg.h643
-rw-r--r--include/linux/ide.h184
-rw-r--r--include/linux/init_task.h88
-rw-r--r--include/linux/msdos_fs.h22
-rw-r--r--include/linux/sched.h170
-rw-r--r--kernel/exit.c1
-rw-r--r--kernel/fork.c8
-rw-r--r--kernel/kmod.c1
-rw-r--r--kernel/ksyms.c5
-rw-r--r--kernel/sched.c446
-rw-r--r--kernel/timer.c3
-rw-r--r--lib/vsprintf.c9
-rw-r--r--mm/swapfile.c1
97 files changed, 6767 insertions, 2262 deletions
diff --git a/CREDITS b/CREDITS
index d73f905e9..5bdaddc54 100644
--- a/CREDITS
+++ b/CREDITS
@@ -588,6 +588,13 @@ D: USB Bluetooth Driver
S: University of Michigan
S: Ann Arbor, MI
+N: Michael Cornwell
+E: cornwell@acm.org
+D: Original designer and co-author of ATA Taskfile
+D: Kernel module SMART utilities
+S: Santa Cruz, California
+S: USA
+
N: Kees Cook
E: cook@cpoint.net
W: http://outflux.net/
@@ -1186,22 +1193,19 @@ D: Selection mechanism
N: Andre Hedrick
E: andre@linux-ide.org
-E: andre@aslab.com
-E: andre@suse.com
+E: andre@linuxdiskcert.org
W: http://www.linux-ide.org/
+W: http://www.linuxdiskcert.org/
D: Random SMP kernel hacker...
D: Uniform Multi-Platform E-IDE driver
D: Active-ATA-Chipset maddness..........
-D: Ultra DMA 100/66/33
-D: ATA-Disconnect
+D: Ultra DMA 133/100/66/33 w/48-bit Addressing
+D: ATA-Disconnect, ATA-TCQ
D: ATA-Smart Kernel Daemon
+D: Serial ATA
+D: ATA Command Block and Taskfile
S: Linux ATA Development (LAD)
S: Concord, CA
-S: ASL, Inc. 1-877-ASL-3535
-S: 1757 Houret Court, Milpitas, CA 95035
-S: SuSE Linux, Inc.
-S: 580 Second Street, Suite 210 Oakland, CA 94607
-S: USA
N: Jochen Hein
E: jochen@jochen.org
diff --git a/MAINTAINERS b/MAINTAINERS
index bbace6caf..2ebeced0b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -700,12 +700,12 @@ S: Supported
IDE DRIVER [GENERAL]
P: Andre Hedrick
M: andre@linux-ide.org
-M: andre@aslab.com
-M: andre@suse.com
+M: andre@linuxdiskcert.org
L: linux-kernel@vger.kernel.org
W: http://www.kernel.org/pub/linux/kernel/people/hedrick/
W: http://www.linux-ide.org/
-S: Supported
+W: http://www.linuxdiskcert.org/
+S: Maintained
IDE/ATAPI CDROM DRIVER
P: Jens Axboe
diff --git a/Makefile b/Makefile
index 5c2a8e1c6..dc774375b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 5
-SUBLEVEL = 2
-EXTRAVERSION =
+SUBLEVEL = 3
+EXTRAVERSION =-pre1
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
diff --git a/arch/arm/kernel/init_task.c b/arch/arm/kernel/init_task.c
index 7245a45b0..2e3ce17b0 100644
--- a/arch/arm/kernel/init_task.c
+++ b/arch/arm/kernel/init_task.c
@@ -5,6 +5,7 @@
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/init.h>
+#include <linux/init_task.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 11ce0b503..dc4850353 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -154,7 +154,7 @@ CONFIG_BLK_DEV_FD=y
#
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK is not set
+# CONFIG_NETLINK_DEV is not set
# CONFIG_NETFILTER is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
@@ -205,6 +205,7 @@ CONFIG_BLK_DEV_IDE=y
# CONFIG_BLK_DEV_HD is not set
CONFIG_BLK_DEV_IDEDISK=y
CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_IDEDISK_STROKE is not set
# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
# CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -219,6 +220,7 @@ CONFIG_BLK_DEV_IDECD=y
# CONFIG_BLK_DEV_IDETAPE is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
# CONFIG_BLK_DEV_IDESCSI is not set
+CONFIG_IDE_TASK_IOCTL=y
#
# IDE chipset support/bugfixes
@@ -230,12 +232,15 @@ CONFIG_BLK_DEV_RZ1000=y
CONFIG_BLK_DEV_IDEPCI=y
CONFIG_IDEPCI_SHARE_IRQ=y
CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
# CONFIG_BLK_DEV_AEC62XX is not set
# CONFIG_AEC62XX_TUNING is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
@@ -252,6 +257,7 @@ CONFIG_BLK_DEV_PIIX=y
CONFIG_PIIX_TUNING=y
# CONFIG_BLK_DEV_NS87415 is not set
# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC_ADMA is not set
# CONFIG_BLK_DEV_PDC202XX is not set
# CONFIG_PDC202XX_BURST is not set
# CONFIG_PDC202XX_FORCE is not set
diff --git a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c
index 7779809ef..c7ace3bbe 100644
--- a/arch/i386/kernel/init_task.c
+++ b/arch/i386/kernel/init_task.c
@@ -1,6 +1,7 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
+#include <linux/init_task.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
diff --git a/arch/ia64/kernel/init_task.c b/arch/ia64/kernel/init_task.c
index 341e32e14..3027ada1a 100644
--- a/arch/ia64/kernel/init_task.c
+++ b/arch/ia64/kernel/init_task.c
@@ -9,6 +9,7 @@
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/sched.h>
+#include <linux/init_task.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
diff --git a/arch/mips/kernel/init_task.c b/arch/mips/kernel/init_task.c
index ccef3ba6b..0cba234e7 100644
--- a/arch/mips/kernel/init_task.c
+++ b/arch/mips/kernel/init_task.c
@@ -1,5 +1,6 @@
#include <linux/mm.h>
#include <linux/sched.h>
+#include <linux/init_task.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
diff --git a/arch/mips64/kernel/init_task.c b/arch/mips64/kernel/init_task.c
index 879214ff5..3338ff278 100644
--- a/arch/mips64/kernel/init_task.c
+++ b/arch/mips64/kernel/init_task.c
@@ -1,5 +1,6 @@
#include <linux/mm.h>
#include <linux/sched.h>
+#include <linux/init_task.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
diff --git a/arch/parisc/kernel/init_task.c b/arch/parisc/kernel/init_task.c
index 45ed70c9c..602d85a53 100644
--- a/arch/parisc/kernel/init_task.c
+++ b/arch/parisc/kernel/init_task.c
@@ -1,6 +1,7 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
+#include <linux/init_task.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index fe503e74a..7d0fd4246 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -689,8 +689,12 @@ void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
id->CurAPMvalues = __le16_to_cpu(id->CurAPMvalues);
id->word92 = __le16_to_cpu(id->word92);
id->hw_config = __le16_to_cpu(id->hw_config);
- for (i = 0; i < 32; i++)
- id->words94_125[i] = __le16_to_cpu(id->words94_125[i]);
+ id->acoustic = __le16_to_cpu(id->acoustic);
+ for (i = 0; i < 5; i++)
+ id->words95_99[i] = __le16_to_cpu(id->words95_99[i]);
+ id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
+ for (i = 0; i < 22; i++)
+ id->words104_125[i] = __le16_to_cpu(id->words104_125[i]);
id->last_lun = __le16_to_cpu(id->last_lun);
id->word127 = __le16_to_cpu(id->word127);
id->dlf = __le16_to_cpu(id->dlf);
@@ -700,6 +704,12 @@ void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
id->word156 = __le16_to_cpu(id->word156);
for (i = 0; i < 3; i++)
id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
- for (i = 0; i < 96; i++)
- id->words160_255[i] = __le16_to_cpu(id->words160_255[i]);
+ id->cfa_power = __le16_to_cpu(id->cfa_power);
+ for (i = 0; i < 14; i++)
+ id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
+ for (i = 0; i < 31; i++)
+ id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
+ for (i = 0; i < 48; i++)
+ id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
+ id->integrity_word = __le16_to_cpu(id->integrity_word);
}
diff --git a/arch/s390/kernel/init_task.c b/arch/s390/kernel/init_task.c
index 3e2600776..fdbfc012a 100644
--- a/arch/s390/kernel/init_task.c
+++ b/arch/s390/kernel/init_task.c
@@ -8,6 +8,7 @@
#include <linux/mm.h>
#include <linux/sched.h>
+#include <linux/init_task.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
diff --git a/arch/s390x/kernel/init_task.c b/arch/s390x/kernel/init_task.c
index 74cf730b0..1f7fa9611 100644
--- a/arch/s390x/kernel/init_task.c
+++ b/arch/s390x/kernel/init_task.c
@@ -8,6 +8,7 @@
#include <linux/mm.h>
#include <linux/sched.h>
+#include <linux/init_task.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
diff --git a/arch/sh/kernel/init_task.c b/arch/sh/kernel/init_task.c
index 6f92b9ef5..648cc7543 100644
--- a/arch/sh/kernel/init_task.c
+++ b/arch/sh/kernel/init_task.c
@@ -1,6 +1,7 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
+#include <linux/init_task.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
diff --git a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c
index d6d5e35e5..e43bbc5dc 100644
--- a/arch/sparc/kernel/init_task.c
+++ b/arch/sparc/kernel/init_task.c
@@ -1,5 +1,6 @@
#include <linux/mm.h>
#include <linux/sched.h>
+#include <linux/init_task.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 2d80c59f8..728c010c8 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -253,6 +253,7 @@ CONFIG_BLK_DEV_IDE=y
# CONFIG_BLK_DEV_HD is not set
CONFIG_BLK_DEV_IDEDISK=y
# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
# CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -267,6 +268,7 @@ CONFIG_BLK_DEV_IDECD=y
# CONFIG_BLK_DEV_IDETAPE is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
#
# IDE chipset support/bugfixes
@@ -278,12 +280,15 @@ CONFIG_BLK_DEV_IDECD=y
CONFIG_BLK_DEV_IDEPCI=y
# CONFIG_IDEPCI_SHARE_IRQ is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
CONFIG_IDEDMA_PCI_AUTO=y
+CONFIG_IDEDMA_ONLYDISK=y
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
# CONFIG_BLK_DEV_AEC62XX is not set
# CONFIG_AEC62XX_TUNING is not set
CONFIG_BLK_DEV_ALI15X3=y
@@ -298,6 +303,7 @@ CONFIG_BLK_DEV_CMD64X=y
# CONFIG_BLK_DEV_HPT366 is not set
CONFIG_BLK_DEV_NS87415=y
# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC_ADMA is not set
# CONFIG_BLK_DEV_PDC202XX is not set
# CONFIG_PDC202XX_BURST is not set
# CONFIG_PDC202XX_FORCE is not set
diff --git a/arch/sparc64/kernel/init_task.c b/arch/sparc64/kernel/init_task.c
index 9cbcc9cb3..ae8150a32 100644
--- a/arch/sparc64/kernel/init_task.c
+++ b/arch/sparc64/kernel/init_task.c
@@ -1,5 +1,6 @@
#include <linux/mm.h>
#include <linux/sched.h>
+#include <linux/init_task.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index c69633139..722b9a947 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -534,7 +534,6 @@ static int loop_thread(void *data)
struct bio *bio;
daemonize();
- exit_files(current);
sprintf(current->comm, "loop%d", lo->lo_number);
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
index 0088d7938..4cc25c0fd 100644
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -684,7 +684,8 @@ static void xs( char *buf, char *targ, int offs, int len )
for (k=0;k<len;k++)
if((buf[k+offs]!=0x20)||(buf[k+offs]!=l))
l=targ[j++]=buf[k+offs];
- if (l==0x20) j--; targ[j]=0;
+ if (l==0x20) j--;
+ targ[j]=0;
}
static int xl( char *buf, int offs )
diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
index bf98ec1de..8592e4039 100644
--- a/drivers/block/paride/pg.c
+++ b/drivers/block/paride/pg.c
@@ -491,7 +491,8 @@ static void xs( char *buf, char *targ, int offs, int len )
for (k=0;k<len;k++)
if((buf[k+offs]!=0x20)||(buf[k+offs]!=l))
l=targ[j++]=buf[k+offs];
- if (l==0x20) j--; targ[j]=0;
+ if (l==0x20) j--;
+ targ[j]=0;
}
static int pg_identify( int unit, int log )
diff --git a/drivers/block/paride/pseudo.h b/drivers/block/paride/pseudo.h
index 31cf68d5c..25cde3063 100644
--- a/drivers/block/paride/pseudo.h
+++ b/drivers/block/paride/pseudo.h
@@ -102,7 +102,7 @@ static void ps_tq_int( void *data )
spin_unlock_irqrestore(&ps_spinlock,flags);
return;
}
- if (!ps_ready || ps_ready() || (jiffies >= ps_timeout)) {
+ if (!ps_ready || ps_ready() || time_after_eq(jiffies, ps_timeout)) {
ps_continuation = NULL;
spin_unlock_irqrestore(&ps_spinlock,flags);
con();
@@ -131,7 +131,7 @@ static void ps_timer_int( unsigned long data)
spin_unlock_irqrestore(&ps_spinlock,flags);
return;
}
- if (!ps_ready || ps_ready() || (jiffies >= ps_timeout)) {
+ if (!ps_ready || ps_ready() || time_after_eq(jiffies, ps_timeout)) {
ps_continuation = NULL;
spin_unlock_irqrestore(&ps_spinlock,flags);
con();
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
index 9e9e59238..fab199e16 100644
--- a/drivers/block/paride/pt.c
+++ b/drivers/block/paride/pt.c
@@ -577,7 +577,8 @@ static void xs( char *buf, char *targ, int offs, int len )
for (k=0;k<len;k++)
if((buf[k+offs]!=0x20)||(buf[k+offs]!=l))
l=targ[j++]=buf[k+offs];
- if (l==0x20) j--; targ[j]=0;
+ if (l==0x20) j--;
+ targ[j]=0;
}
static int xn( char *buf, int offs, int size )
diff --git a/drivers/ide/Config.in b/drivers/ide/Config.in
index b17e8b01f..ac177c4cd 100644
--- a/drivers/ide/Config.in
+++ b/drivers/ide/Config.in
@@ -14,6 +14,7 @@ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
dep_tristate ' Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
dep_mbool ' Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK
+ dep_mbool ' Auto-Geometry Resizing support' CONFIG_IDEDISK_STROKE $CONFIG_BLK_DEV_IDEDISK
define_bool CONFIG_BLK_DEV_IDEDISK_VENDOR n
dep_mbool ' Fujitsu Vendor Specific' CONFIG_BLK_DEV_IDEDISK_FUJITSU $CONFIG_BLK_DEV_IDEDISK_VENDOR
@@ -32,6 +33,8 @@ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI
+ bool ' IDE Taskfile Access' CONFIG_IDE_TASK_IOCTL
+
comment 'IDE chipset support/bugfixes'
if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
dep_bool ' CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640 $CONFIG_X86
@@ -43,14 +46,17 @@ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
bool ' Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ
bool ' Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
-# bool ' Asynchronous DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
- define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
+ dep_bool ' Force enable legacy 2.0.X HOSTS to use DMA' CONFIG_BLK_DEV_IDEDMA_FORCED $CONFIG_BLK_DEV_IDEDMA_PCI
dep_bool ' Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO $CONFIG_BLK_DEV_IDEDMA_PCI
+ dep_bool ' Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO
define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI
dep_bool ' ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
-# dep_bool ' Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP
+ dep_bool ' Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP
dep_bool ' Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP
+# dep_bool ' Asynchronous DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP
+ define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
+# dep_bool ' Tag Command Queue DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDMA_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP
dep_bool ' AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
dep_mbool ' AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX
@@ -74,7 +80,8 @@ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
fi
dep_bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI
dep_bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
- dep_bool ' PROMISE PDC202{46|62|65|67|68} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
+ dep_mbool ' Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP
+ dep_bool ' PROMISE PDC202{46|62|65|67|68|69|70} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
dep_bool ' Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX
dep_bool ' Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX
dep_bool ' ServerWorks OSB4/CSB5 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
@@ -84,8 +91,6 @@ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
dep_bool ' VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
fi
-# dep_mbool ' Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP
-
if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
fi
@@ -173,6 +178,7 @@ if [ "$CONFIG_BLK_DEV_TIVO" = "y" ]; then
else
define_bool CONFIG_DMA_NONPCI n
fi
+
if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
"$CONFIG_BLK_DEV_AEC62XX" = "y" -o \
"$CONFIG_BLK_DEV_ALI15X3" = "y" -o \
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index 0a3e8eca6..3955be750 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -10,7 +10,7 @@
O_TARGET := idedriver.o
-export-objs := ide.o ide-features.o ataraid.o
+export-objs := ide-taskfile.o ide.o ide-features.o ide-probe.o ataraid.o
list-multi := ide-mod.o ide-probe-mod.o
obj-y :=
@@ -24,6 +24,7 @@ obj-$(CONFIG_BLK_DEV_IDEDISK) += ide-disk.o
obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd.o
obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o
obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o
+
obj-$(CONFIG_BLK_DEV_IT8172) += it8172.o
ide-obj-$(CONFIG_BLK_DEV_AEC62XX) += aec62xx.o
@@ -69,13 +70,13 @@ ide-obj-$(CONFIG_BLK_DEV_MPC8xx_IDE) += ide-m8xx.o
# The virtualised raid layers MUST come after the ide itself or bad stuff
# will happen.
-obj-$(CONFIG_BLK_DEV_ATARAID) += ataraid.o
+obj-$(CONFIG_BLK_DEV_ATARAID) += ataraid.o
obj-$(CONFIG_BLK_DEV_ATARAID_PDC) += pdcraid.o
obj-$(CONFIG_BLK_DEV_ATARAID_HPT) += hptraid.o
ide-obj-$(CONFIG_PROC_FS) += ide-proc.o
-ide-mod-objs := ide.o ide-features.o $(ide-obj-y)
+ide-mod-objs := ide-taskfile.o ide.o ide-features.o $(ide-obj-y)
ide-probe-mod-objs := ide-probe.o ide-geometry.o
include $(TOPDIR)/Rules.make
diff --git a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c
index 88d60d122..ccdeb80c9 100644
--- a/drivers/ide/alim15x3.c
+++ b/drivers/ide/alim15x3.c
@@ -453,7 +453,7 @@ static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
}
dma_func = ide_dma_off_quietly;
if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) {
- if (id->dma_ultra & 0x002F) {
+ if (id->dma_ultra & 0x003F) {
/* Force if Capable UltraDMA */
dma_func = config_chipset_for_dma(drive, can_ultra_dma);
if ((id->field_valid & 2) &&
diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c
index 85f985487..64004b418 100644
--- a/drivers/ide/cmd64x.c
+++ b/drivers/ide/cmd64x.c
@@ -86,6 +86,7 @@
#include <linux/proc_fs.h>
static int cmd64x_get_info(char *, char **, off_t, int);
+static int cmd680_get_info(char *, char **, off_t, int);
extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
extern char *ide_media_verbose(ide_drive_t *);
static struct pci_dev *bmide_dev;
@@ -180,24 +181,21 @@ static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
return p-buffer; /* => must be less than 4k! */
}
-#if 0
-static char * cmd64x_chipset_data (char *buf, struct pci_dev *dev)
-{
- char *p = buf;
- p += sprintf(p, "thingy stuff\n");
- return (char *)p;
-}
-static int __init cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
+static int cmd680_get_info (char *buffer, char **addr, off_t offset, int count)
{
char *p = buffer;
- p = cmd64x_chipset_data(buffer, bmide_dev);
- return p-buffer; /* hoping it is less than 4K... */
+ p += sprintf(p, "\n CMD680 Chipset.\n");
+ p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+ p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+ p += sprintf(p, "PIO Mode: %s %s %s %s\n",
+ "?", "?", "?", "?");
+ return p-buffer; /* => must be less than 4k! */
}
-#endif
#endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
byte cmd64x_proc = 0;
+byte cmd680_proc = 0;
/*
* Registers and masks for easy access by drive index:
@@ -345,10 +343,58 @@ static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted)
setup_count, active_count, recovery_count);
}
-static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+static byte cmd680_taskfile_timing (ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+ byte addr_mask = (hwif->channel) ? 0xB2 : 0xA2;
+ unsigned short timing;
+
+ pci_read_config_word(dev, addr_mask, &timing);
+
+ switch (timing) {
+ case 0x10c1: return 4;
+ case 0x10c3: return 3;
+ case 0x1281: return 2;
+ case 0x2283: return 1;
+ case 0x328a:
+ default: return 0;
+ }
+}
+
+static void cmd680_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ byte drive_pci;
+ unsigned short speedt;
+
+ switch (drive->dn) {
+ case 0: drive_pci = 0xA4; break;
+ case 1: drive_pci = 0xA6; break;
+ case 2: drive_pci = 0xB4; break;
+ case 3: drive_pci = 0xB6; break;
+ default: return;
+ }
+
+ pci_read_config_word(dev, drive_pci, &speedt);
+
+ /* cheat for now and use the docs */
+// switch(cmd680_taskfile_timing(hwif)) {
+ switch(mode_wanted) {
+ case 4: speedt = 0x10c1; break;
+ case 3: speedt = 0x10C3; break;
+ case 2: speedt = 0x1104; break;
+ case 1: speedt = 0x2283; break;
+ case 0:
+ default: speedt = 0x328A; break;
+ }
+ pci_write_config_word(dev, drive_pci, speedt);
+}
+
+static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
{
- byte speed= 0x00;
- byte set_pio= ide_get_best_pio_mode(drive, 4, 5, NULL);
+ byte speed = 0x00;
+ byte set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL);
cmd64x_tuneproc(drive, set_pio);
speed = XFER_PIO_0 + set_pio;
@@ -356,6 +402,41 @@ static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
(void) ide_config_drive_speed(drive, speed);
}
+static void config_cmd680_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 unit = (drive->select.b.unit & 0x01);
+ u8 addr_mask = (hwif->channel) ? 0x84 : 0x80;
+ u8 speed = 0x00;
+ u8 mode_pci = 0x00;
+ u8 channel_timings = cmd680_taskfile_timing(hwif);
+ u8 set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+ pci_read_config_byte(dev, addr_mask, &mode_pci);
+ mode_pci &= ~((unit) ? 0x30 : 0x03);
+
+ /* WARNING PIO timing mess is going to happen b/w devices, argh */
+ if ((channel_timings != set_pio) && (set_pio > channel_timings))
+ set_pio = channel_timings;
+
+ cmd680_tuneproc(drive, set_pio);
+ speed = XFER_PIO_0 + set_pio;
+ if (set_speed) {
+ (void) ide_config_drive_speed(drive, speed);
+ drive->current_speed = speed;
+ }
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+ if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680) {
+ config_cmd680_chipset_for_pio(drive, set_speed);
+ } else {
+ config_cmd64x_chipset_for_pio(drive, set_speed);
+ }
+}
+
static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed)
{
#ifdef CONFIG_BLK_DEV_IDEDMA
@@ -363,7 +444,7 @@ static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed)
struct pci_dev *dev = hwif->pci_dev;
int err = 0;
- byte unit = (drive->select.b.unit & 0x01);
+ u8 unit = (drive->select.b.unit & 0x01);
u8 pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
u8 pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0;
u8 regU = 0;
@@ -424,8 +505,123 @@ static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed)
return err;
}
+static int cmd680_tune_chipset (ide_drive_t *drive, byte speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 addr_mask = (hwif->channel) ? 0x84 : 0x80;
+ u8 unit = (drive->select.b.unit & 0x01);
+ u8 dma_pci = 0;
+ u8 udma_pci = 0;
+ u8 mode_pci = 0;
+ u8 scsc = 0;
+ u16 ultra = 0;
+ u16 multi = 0;
+ int err = 0;
+
+ pci_read_config_byte(dev, addr_mask, &mode_pci);
+ pci_read_config_byte(dev, 0x8A, &scsc);
+
+ switch (drive->dn) {
+ case 0: dma_pci = 0xA8; udma_pci = 0xAC; break;
+ case 1: dma_pci = 0xAA; udma_pci = 0xAE; break;
+ case 2: dma_pci = 0xB8; udma_pci = 0xBC; break;
+ case 3: dma_pci = 0xBA; udma_pci = 0xBE; break;
+ default: return 1;
+ }
+
+ pci_read_config_byte(dev, addr_mask, &mode_pci);
+ mode_pci &= ~((unit) ? 0x30 : 0x03);
+ pci_read_config_word(dev, dma_pci, &multi);
+ pci_read_config_word(dev, udma_pci, &ultra);
+
+ if ((speed == XFER_UDMA_6) && (scsc & 0x30) == 0x00) {
+ pci_write_config_byte(dev, 0x8A, scsc|0x01);
+ pci_read_config_byte(dev, 0x8A, &scsc);
+ }
+
+ switch(speed) {
#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
+ case XFER_UDMA_6:
+ if ((scsc & 0x30) == 0x00)
+ goto speed_break;
+ multi = 0x10C1;
+ ultra &= ~0x3F;
+ ultra |= 0x01;
+ break;
+speed_break :
+ speed = XFER_UDMA_5;
+ case XFER_UDMA_5:
+ multi = 0x10C1;
+ ultra &= ~0x3F;
+ ultra |= (((scsc & 0x30) == 0x00) ? 0x01 : 0x02);
+ break;
+ case XFER_UDMA_4:
+ multi = 0x10C1;
+ ultra &= ~0x3F;
+ ultra |= (((scsc & 0x30) == 0x00) ? 0x02 : 0x03);
+ break;
+ case XFER_UDMA_3:
+ multi = 0x10C1;
+ ultra &= ~0x3F;
+ ultra |= (((scsc & 0x30) == 0x00) ? 0x04 : 0x05);
+ break;
+ case XFER_UDMA_2:
+ multi = 0x10C1;
+ ultra &= ~0x3F;
+ ultra |= (((scsc & 0x30) == 0x00) ? 0x05 : 0x07);
+ break;
+ case XFER_UDMA_1:
+ multi = 0x10C1;
+ ultra &= ~0x3F;
+ ultra |= (((scsc & 0x30) == 0x00) ? 0x07 : 0x0B);
+ break;
+ case XFER_UDMA_0:
+ multi = 0x10C1;
+ ultra &= ~0x3F;
+ ultra |= (((scsc & 0x30) == 0x00) ? 0x0C : 0x0F);
+ break;
+ case XFER_MW_DMA_2:
+ multi = 0x10C1;
+ break;
+ case XFER_MW_DMA_1:
+ multi = 0x10C2;
+ break;
+ case XFER_MW_DMA_0:
+ multi = 0x2208;
+ break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+ case XFER_PIO_4: cmd680_tuneproc(drive, 4); break;
+ case XFER_PIO_3: cmd680_tuneproc(drive, 3); break;
+ case XFER_PIO_2: cmd680_tuneproc(drive, 2); break;
+ case XFER_PIO_1: cmd680_tuneproc(drive, 1); break;
+ case XFER_PIO_0: cmd680_tuneproc(drive, 0); break;
+ default:
+ return 1;
+ }
+
+
+ if (speed >= XFER_MW_DMA_0)
+ config_cmd680_chipset_for_pio(drive, 0);
+
+ if (speed >= XFER_UDMA_0)
+ mode_pci |= ((unit) ? 0x30 : 0x03);
+ else if (speed >= XFER_MW_DMA_0)
+ mode_pci |= ((unit) ? 0x20 : 0x02);
+ else
+ mode_pci |= ((unit) ? 0x10 : 0x01);
+
+ pci_write_config_byte(dev, addr_mask, mode_pci);
+ pci_write_config_word(dev, dma_pci, multi);
+ pci_write_config_word(dev, udma_pci, ultra);
+
+ err = ide_config_drive_speed(drive, speed);
+ drive->current_speed = speed;
+ return err;
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int config_cmd64x_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
{
struct hd_driveid *id = drive->id;
ide_hwif_t *hwif = HWIF(drive);
@@ -510,6 +706,55 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
return rval;
}
+static int config_cmd680_chipset_for_dma (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ byte udma_66 = eighty_ninty_three(drive);
+ byte speed = 0x00;
+ byte set_pio = 0x00;
+ int rval;
+
+ if ((id->dma_ultra & 0x0040) && (udma_66)) speed = XFER_UDMA_6;
+ else if ((id->dma_ultra & 0x0020) && (udma_66)) speed = XFER_UDMA_5;
+ else if ((id->dma_ultra & 0x0010) && (udma_66)) speed = XFER_UDMA_4;
+ else if ((id->dma_ultra & 0x0008) && (udma_66)) speed = XFER_UDMA_3;
+ else if (id->dma_ultra & 0x0004) speed = XFER_UDMA_2;
+ else if (id->dma_ultra & 0x0002) speed = XFER_UDMA_1;
+ else if (id->dma_ultra & 0x0001) speed = XFER_UDMA_0;
+ else if (id->dma_mword & 0x0004) speed = XFER_MW_DMA_2;
+ else if (id->dma_mword & 0x0002) speed = XFER_MW_DMA_1;
+ else if (id->dma_mword & 0x0001) speed = XFER_MW_DMA_0;
+ else {
+ set_pio = 1;
+ }
+
+ if (!drive->init_speed)
+ drive->init_speed = speed;
+
+ config_chipset_for_pio(drive, set_pio);
+
+ if (set_pio)
+ return ((int) ide_dma_off_quietly);
+
+ if (cmd680_tune_chipset(drive, speed))
+ return ((int) ide_dma_off);
+
+ rval = (int)( ((id->dma_ultra >> 14) & 3) ? ide_dma_on :
+ ((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+ ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+ ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+ ((id->dma_1word >> 8) & 7) ? ide_dma_on :
+ ide_dma_off_quietly);
+ return rval;
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
+{
+ if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680)
+ return (config_cmd680_chipset_for_dma(drive));
+ return (config_cmd64x_chipset_for_dma(drive, rev, ultra_66));
+}
+
static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -519,12 +764,15 @@ static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
byte can_ultra_33 = 0;
byte can_ultra_66 = 0;
byte can_ultra_100 = 0;
+ byte can_ultra_133 = 0;
ide_dma_action_t dma_func = ide_dma_on;
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
class_rev &= 0xff;
switch(dev->device) {
+ case PCI_DEVICE_ID_CMD_680:
+ can_ultra_133 = 1;
case PCI_DEVICE_ID_CMD_649:
can_ultra_100 = 1;
case PCI_DEVICE_ID_CMD_648:
@@ -550,7 +798,7 @@ static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
}
dma_func = ide_dma_off_quietly;
if ((id->field_valid & 4) && (can_ultra_33)) {
- if (id->dma_ultra & 0x002F) {
+ if (id->dma_ultra & 0x007F) {
/* Force if Capable UltraDMA */
dma_func = config_chipset_for_dma(drive, class_rev, can_ultra_66);
if ((id->field_valid & 2) &&
@@ -586,6 +834,18 @@ no_dma_set:
return HWIF(drive)->dmaproc(dma_func, drive);
}
+static int cmd680_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+ switch (func) {
+ case ide_dma_check:
+ return cmd64x_config_drive_for_dma(drive);
+ default:
+ break;
+ }
+ /* Other cases are done by generic IDE-DMA code. */
+ return ide_dmaproc(func, drive);
+}
+
static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
byte dma_stat = 0;
@@ -663,7 +923,78 @@ static int cmd646_1_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
-unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
+static int cmd680_busproc (ide_drive_t * drive, int state)
+{
+#if 0
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 addr_mask = (hwif->channel) ? 0xB0 : 0xA0;
+ u32 stat_config = 0;
+
+ pci_read_config_dword(hwif->pci_dev, addr_mask, &stat_config);
+
+ if (!hwif)
+ return -EINVAL;
+
+ switch (state) {
+ case BUSSTATE_ON:
+ hwif->drives[0].failures = 0;
+ hwif->drives[1].failures = 0;
+ break;
+ case BUSSTATE_OFF:
+ hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+ hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+ break;
+ case BUSSTATE_TRISTATE:
+ hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+ hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+ break;
+ default:
+ return 0;
+ }
+ hwif->bus_state = state;
+#endif
+ return 0;
+}
+
+void cmd680_reset (ide_drive_t *drive)
+{
+#if 0
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 addr_mask = (hwif->channel) ? 0xB0 : 0xA0;
+ byte reset = 0;
+
+ pci_read_config_byte(hwif->pci_dev, addr_mask, &reset);
+ pci_write_config_byte(hwif->pci_dev, addr_mask, reset|0x03);
+#endif
+}
+
+unsigned int cmd680_pci_init (struct pci_dev *dev, const char *name)
+{
+ u8 tmpbyte = 0;
+ pci_write_config_byte(dev, 0x80, 0x00);
+ pci_write_config_byte(dev, 0x84, 0x00);
+ pci_read_config_byte(dev, 0x8A, &tmpbyte);
+ pci_write_config_byte(dev, 0x8A, tmpbyte|0x01);
+ pci_write_config_word(dev, 0xA2, 0x328A);
+ pci_write_config_dword(dev, 0xA4, 0x328A);
+ pci_write_config_dword(dev, 0xA8, 0x4392);
+ pci_write_config_dword(dev, 0xAC, 0x4009);
+ pci_write_config_word(dev, 0xB2, 0x328A);
+ pci_write_config_dword(dev, 0xB4, 0x328A);
+ pci_write_config_dword(dev, 0xB8, 0x4392);
+ pci_write_config_dword(dev, 0xBC, 0x4009);
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+ if (!cmd64x_proc) {
+ cmd64x_proc = 1;
+ bmide_dev = dev;
+ cmd64x_display_info = &cmd680_get_info;
+ }
+#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
+ return 0;
+}
+
+unsigned int cmd64x_pci_init (struct pci_dev *dev, const char *name)
{
unsigned char mrdmode;
unsigned int class_rev;
@@ -752,7 +1083,23 @@ unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
return 0;
}
-unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
+{
+ if (dev->device == PCI_DEVICE_ID_CMD_680)
+ return cmd680_pci_init (dev, name);
+ return cmd64x_pci_init (dev, name);
+}
+
+unsigned int cmd680_ata66 (ide_hwif_t *hwif)
+{
+ byte ata66 = 0;
+ byte addr_mask = (hwif->channel) ? 0xB0 : 0xA0;
+
+ pci_read_config_byte(hwif->pci_dev, addr_mask, &ata66);
+ return (ata66 & 0x01) ? 1 : 0;
+}
+
+unsigned int cmd64x_ata66 (ide_hwif_t *hwif)
{
byte ata66 = 0;
byte mask = (hwif->channel) ? 0x02 : 0x01;
@@ -761,6 +1108,14 @@ unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
return (ata66 & mask) ? 1 : 0;
}
+unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+ if (dev->device == PCI_DEVICE_ID_CMD_680)
+ return cmd680_ata66(hwif);
+ return cmd64x_ata66(hwif);
+}
+
void __init ide_init_cmd64x (ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
@@ -769,8 +1124,6 @@ void __init ide_init_cmd64x (ide_hwif_t *hwif)
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
class_rev &= 0xff;
- hwif->tuneproc = &cmd64x_tuneproc;
- hwif->speedproc = &cmd64x_tune_chipset;
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
@@ -779,10 +1132,19 @@ void __init ide_init_cmd64x (ide_hwif_t *hwif)
#ifdef CONFIG_BLK_DEV_IDEDMA
switch(dev->device) {
+ case PCI_DEVICE_ID_CMD_680:
+ hwif->busproc = &cmd680_busproc;
+ hwif->dmaproc = &cmd680_dmaproc;
+ hwif->resetproc = &cmd680_reset;
+ hwif->speedproc = &cmd680_tune_chipset;
+ hwif->tuneproc = &cmd680_tuneproc;
+ break;
case PCI_DEVICE_ID_CMD_649:
case PCI_DEVICE_ID_CMD_648:
case PCI_DEVICE_ID_CMD_643:
- hwif->dmaproc = &cmd64x_dmaproc;
+ hwif->dmaproc = &cmd64x_dmaproc;
+ hwif->tuneproc = &cmd64x_tuneproc;
+ hwif->speedproc = &cmd64x_tune_chipset;
break;
case PCI_DEVICE_ID_CMD_646:
hwif->chipset = ide_cmd646;
@@ -791,6 +1153,8 @@ void __init ide_init_cmd64x (ide_hwif_t *hwif)
} else {
hwif->dmaproc = &cmd64x_dmaproc;
}
+ hwif->tuneproc = &cmd64x_tuneproc;
+ hwif->speedproc = &cmd64x_tune_chipset;
break;
default:
break;
diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
index f216dfeb3..8c98bad76 100644
--- a/drivers/ide/hpt366.c
+++ b/drivers/ide/hpt366.c
@@ -1,7 +1,8 @@
/*
- * linux/drivers/ide/hpt366.c Version 0.18 June. 9, 2000
+ * linux/drivers/ide/hpt366.c Version 0.22 20 Sep 2001
*
* Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 2001 Sun Microsystems, Inc.
* May be copied or modified under the terms of the GNU General Public License
*
* Thanks to HighPoint Technologies for their assistance, and hardware.
@@ -11,6 +12,34 @@
*
* Note that final HPT370 support was done by force extraction of GPL.
*
+ * - add function for getting/setting power status of drive
+ * - the HPT370's state machine can get confused. reset it before each dma
+ * xfer to prevent that from happening.
+ * - reset state engine whenever we get an error.
+ * - check for busmaster state at end of dma.
+ * - use new highpoint timings.
+ * - detect bus speed using highpoint register.
+ * - use pll if we don't have a clock table. added a 66MHz table that's
+ * just 2x the 33MHz table.
+ * - removed turnaround. NOTE: we never want to switch between pll and
+ * pci clocks as the chip can glitch in those cases. the highpoint
+ * approved workaround slows everything down too much to be useful. in
+ * addition, we would have to serialize access to each chip.
+ * Adrian Sun <a.sun@sun.com>
+ *
+ * add drive timings for 66MHz PCI bus,
+ * fix ATA Cable signal detection, fix incorrect /proc info
+ * add /proc display for per-drive PIO/DMA/UDMA mode and
+ * per-channel ATA-33/66 Cable detect.
+ * Duncan Laurie <void@sun.com>
+ *
+ * fixup /proc output for multiple controllers
+ * Tim Hockin <thockin@sun.com>
+ *
+ * On hpt366:
+ * Reset the hpt366 on error, reset on dma
+ * Fix disabling Fast Interrupt hpt366.
+ * Mike Waychison <crlf@sun.com>
*/
#include <linux/config.h>
@@ -28,6 +57,7 @@
#include <linux/init.h>
#include <linux/ide.h>
+#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -35,6 +65,11 @@
#define DISPLAY_HPT366_TIMINGS
+/* various tuning parameters */
+#define HPT_RESET_STATE_ENGINE
+/*#define HPT_DELAY_INTERRUPT*/
+/*#define HPT_SERIALIZE_IO*/
+
#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
#include <linux/stat.h>
#include <linux/proc_fs.h>
@@ -106,146 +141,302 @@ const char *bad_ata33[] = {
struct chipset_bus_clock_list_entry {
byte xfer_speed;
- unsigned int chipset_settings_write;
- unsigned int chipset_settings_read;
+ unsigned int chipset_settings;
};
+/* key for bus clock timings
+ * bit
+ * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ * register access.
+ * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
+ * register access.
+ * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
+ * during task file register access.
+ * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
+ * xfer.
+ * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ * register access.
+ * 28 UDMA enable
+ * 29 DMA enable
+ * 30 PIO_MST enable. if set, the chip is in bus master mode during
+ * PIO.
+ * 31 FIFO enable.
+ */
struct chipset_bus_clock_list_entry forty_base [] = {
- { XFER_UDMA_4, 0x900fd943, 0x900fd943 },
- { XFER_UDMA_3, 0x900ad943, 0x900ad943 },
- { XFER_UDMA_2, 0x900bd943, 0x900bd943 },
- { XFER_UDMA_1, 0x9008d943, 0x9008d943 },
- { XFER_UDMA_0, 0x9008d943, 0x9008d943 },
-
- { XFER_MW_DMA_2, 0xa008d943, 0xa008d943 },
- { XFER_MW_DMA_1, 0xa010d955, 0xa010d955 },
- { XFER_MW_DMA_0, 0xa010d9fc, 0xa010d9fc },
-
- { XFER_PIO_4, 0xc008d963, 0xc008d963 },
- { XFER_PIO_3, 0xc010d974, 0xc010d974 },
- { XFER_PIO_2, 0xc010d997, 0xc010d997 },
- { XFER_PIO_1, 0xc010d9c7, 0xc010d9c7 },
- { XFER_PIO_0, 0xc018d9d9, 0xc018d9d9 },
- { 0, 0x0120d9d9, 0x0120d9d9 }
+ { XFER_UDMA_4, 0x900fd943 },
+ { XFER_UDMA_3, 0x900ad943 },
+ { XFER_UDMA_2, 0x900bd943 },
+ { XFER_UDMA_1, 0x9008d943 },
+ { XFER_UDMA_0, 0x9008d943 },
+
+ { XFER_MW_DMA_2, 0xa008d943 },
+ { XFER_MW_DMA_1, 0xa010d955 },
+ { XFER_MW_DMA_0, 0xa010d9fc },
+
+ { XFER_PIO_4, 0xc008d963 },
+ { XFER_PIO_3, 0xc010d974 },
+ { XFER_PIO_2, 0xc010d997 },
+ { XFER_PIO_1, 0xc010d9c7 },
+ { XFER_PIO_0, 0xc018d9d9 },
+ { 0, 0x0120d9d9 }
};
struct chipset_bus_clock_list_entry thirty_three_base [] = {
- { XFER_UDMA_4, 0x90c9a731, 0x90c9a731 },
- { XFER_UDMA_3, 0x90cfa731, 0x90cfa731 },
- { XFER_UDMA_2, 0x90caa731, 0x90caa731 },
- { XFER_UDMA_1, 0x90cba731, 0x90cba731 },
- { XFER_UDMA_0, 0x90c8a731, 0x90c8a731 },
-
- { XFER_MW_DMA_2, 0xa0c8a731, 0xa0c8a731 },
- { XFER_MW_DMA_1, 0xa0c8a732, 0xa0c8a732 }, /* 0xa0c8a733 */
- { XFER_MW_DMA_0, 0xa0c8a797, 0xa0c8a797 },
-
- { XFER_PIO_4, 0xc0c8a731, 0xc0c8a731 },
- { XFER_PIO_3, 0xc0c8a742, 0xc0c8a742 },
- { XFER_PIO_2, 0xc0d0a753, 0xc0d0a753 },
- { XFER_PIO_1, 0xc0d0a7a3, 0xc0d0a7a3 }, /* 0xc0d0a793 */
- { XFER_PIO_0, 0xc0d0a7aa, 0xc0d0a7aa }, /* 0xc0d0a7a7 */
- { 0, 0x0120a7a7, 0x0120a7a7 }
+ { XFER_UDMA_4, 0x90c9a731 },
+ { XFER_UDMA_3, 0x90cfa731 },
+ { XFER_UDMA_2, 0x90caa731 },
+ { XFER_UDMA_1, 0x90cba731 },
+ { XFER_UDMA_0, 0x90c8a731 },
+
+ { XFER_MW_DMA_2, 0xa0c8a731 },
+ { XFER_MW_DMA_1, 0xa0c8a732 }, /* 0xa0c8a733 */
+ { XFER_MW_DMA_0, 0xa0c8a797 },
+
+ { XFER_PIO_4, 0xc0c8a731 },
+ { XFER_PIO_3, 0xc0c8a742 },
+ { XFER_PIO_2, 0xc0d0a753 },
+ { XFER_PIO_1, 0xc0d0a7a3 }, /* 0xc0d0a793 */
+ { XFER_PIO_0, 0xc0d0a7aa }, /* 0xc0d0a7a7 */
+ { 0, 0x0120a7a7 }
};
struct chipset_bus_clock_list_entry twenty_five_base [] = {
- { XFER_UDMA_4, 0x90c98521, 0x90c98521 },
- { XFER_UDMA_3, 0x90cf8521, 0x90cf8521 },
- { XFER_UDMA_2, 0x90cf8521, 0x90cf8521 },
- { XFER_UDMA_1, 0x90cb8521, 0x90cb8521 },
- { XFER_UDMA_0, 0x90cb8521, 0x90cb8521 },
-
- { XFER_MW_DMA_2, 0xa0ca8521, 0xa0ca8521 },
- { XFER_MW_DMA_1, 0xa0ca8532, 0xa0ca8532 },
- { XFER_MW_DMA_0, 0xa0ca8575, 0xa0ca8575 },
-
- { XFER_PIO_4, 0xc0ca8521, 0xc0ca8521 },
- { XFER_PIO_3, 0xc0ca8532, 0xc0ca8532 },
- { XFER_PIO_2, 0xc0ca8542, 0xc0ca8542 },
- { XFER_PIO_1, 0xc0d08572, 0xc0d08572 },
- { XFER_PIO_0, 0xc0d08585, 0xc0d08585 },
- { 0, 0x01208585, 0x01208585 }
+ { XFER_UDMA_4, 0x90c98521 },
+ { XFER_UDMA_3, 0x90cf8521 },
+ { XFER_UDMA_2, 0x90cf8521 },
+ { XFER_UDMA_1, 0x90cb8521 },
+ { XFER_UDMA_0, 0x90cb8521 },
+
+ { XFER_MW_DMA_2, 0xa0ca8521 },
+ { XFER_MW_DMA_1, 0xa0ca8532 },
+ { XFER_MW_DMA_0, 0xa0ca8575 },
+
+ { XFER_PIO_4, 0xc0ca8521 },
+ { XFER_PIO_3, 0xc0ca8532 },
+ { XFER_PIO_2, 0xc0ca8542 },
+ { XFER_PIO_1, 0xc0d08572 },
+ { XFER_PIO_0, 0xc0d08585 },
+ { 0, 0x01208585 }
+};
+
+#if 1
+/* these are the current (4 sep 2001) timings from highpoint */
+struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
+ { XFER_UDMA_5, 0x12446231 },
+ { XFER_UDMA_4, 0x12446231 },
+ { XFER_UDMA_3, 0x126c6231 },
+ { XFER_UDMA_2, 0x12486231 },
+ { XFER_UDMA_1, 0x124c6233 },
+ { XFER_UDMA_0, 0x12506297 },
+
+ { XFER_MW_DMA_2, 0x22406c31 },
+ { XFER_MW_DMA_1, 0x22406c33 },
+ { XFER_MW_DMA_0, 0x22406c97 },
+
+ { XFER_PIO_4, 0x06414e31 },
+ { XFER_PIO_3, 0x06414e42 },
+ { XFER_PIO_2, 0x06414e53 },
+ { XFER_PIO_1, 0x06814e93 },
+ { XFER_PIO_0, 0x06814ea7 },
+ { 0, 0x06814ea7 }
};
+/* 2x 33MHz timings */
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+ { XFER_UDMA_5, 0x1488e673 },
+ { XFER_UDMA_4, 0x1488e673 },
+ { XFER_UDMA_3, 0x1498e673 },
+ { XFER_UDMA_2, 0x1490e673 },
+ { XFER_UDMA_1, 0x1498e677 },
+ { XFER_UDMA_0, 0x14a0e73f },
+
+ { XFER_MW_DMA_2, 0x2480fa73 },
+ { XFER_MW_DMA_1, 0x2480fa77 },
+ { XFER_MW_DMA_0, 0x2480fb3f },
+
+ { XFER_PIO_4, 0x0c82be73 },
+ { XFER_PIO_3, 0x0c82be95 },
+ { XFER_PIO_2, 0x0c82beb7 },
+ { XFER_PIO_1, 0x0d02bf37 },
+ { XFER_PIO_0, 0x0d02bf5f },
+ { 0, 0x0d02bf5f }
+};
+#else
+/* from highpoint documentation. these are old values */
struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
- { XFER_UDMA_5, 0x1A85F442, 0x16454e31 },
- { XFER_UDMA_4, 0x16454e31, 0x16454e31 },
- { XFER_UDMA_3, 0x166d4e31, 0x166d4e31 },
- { XFER_UDMA_2, 0x16494e31, 0x16494e31 },
- { XFER_UDMA_1, 0x164d4e31, 0x164d4e31 },
- { XFER_UDMA_0, 0x16514e31, 0x16514e31 },
-
- { XFER_MW_DMA_2, 0x26514e21, 0x26514e21 },
- { XFER_MW_DMA_1, 0x26514e33, 0x26514e33 },
- { XFER_MW_DMA_0, 0x26514e97, 0x26514e97 },
-
- { XFER_PIO_4, 0x06514e21, 0x06514e21 },
- { XFER_PIO_3, 0x06514e22, 0x06514e22 },
- { XFER_PIO_2, 0x06514e33, 0x06514e33 },
- { XFER_PIO_1, 0x06914e43, 0x06914e43 },
- { XFER_PIO_0, 0x06914e57, 0x06914e57 },
- { 0, 0x06514e57, 0x06514e57 }
+ { XFER_UDMA_5, 0x16454e31 },
+ { XFER_UDMA_4, 0x16454e31 },
+ { XFER_UDMA_3, 0x166d4e31 },
+ { XFER_UDMA_2, 0x16494e31 },
+ { XFER_UDMA_1, 0x164d4e31 },
+ { XFER_UDMA_0, 0x16514e31 },
+
+ { XFER_MW_DMA_2, 0x26514e21 },
+ { XFER_MW_DMA_1, 0x26514e33 },
+ { XFER_MW_DMA_0, 0x26514e97 },
+
+ { XFER_PIO_4, 0x06514e21 },
+ { XFER_PIO_3, 0x06514e22 },
+ { XFER_PIO_2, 0x06514e33 },
+ { XFER_PIO_1, 0x06914e43 },
+ { XFER_PIO_0, 0x06914e57 },
+ { 0, 0x06514e57 }
+};
+
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+ { XFER_UDMA_5, 0x14846231 },
+ { XFER_UDMA_4, 0x14886231 },
+ { XFER_UDMA_3, 0x148c6231 },
+ { XFER_UDMA_2, 0x148c6231 },
+ { XFER_UDMA_1, 0x14906231 },
+ { XFER_UDMA_0, 0x14986231 },
+
+ { XFER_MW_DMA_2, 0x26514e21 },
+ { XFER_MW_DMA_1, 0x26514e33 },
+ { XFER_MW_DMA_0, 0x26514e97 },
+
+ { XFER_PIO_4, 0x06514e21 },
+ { XFER_PIO_3, 0x06514e22 },
+ { XFER_PIO_2, 0x06514e33 },
+ { XFER_PIO_1, 0x06914e43 },
+ { XFER_PIO_0, 0x06914e57 },
+ { 0, 0x06514e57 }
+};
+#endif
+
+struct chipset_bus_clock_list_entry fifty_base_hpt370[] = {
+ { XFER_UDMA_5, 0x12848242 },
+ { XFER_UDMA_4, 0x12ac8242 },
+ { XFER_UDMA_3, 0x128c8242 },
+ { XFER_UDMA_2, 0x120c8242 },
+ { XFER_UDMA_1, 0x12148254 },
+ { XFER_UDMA_0, 0x121882ea },
+
+ { XFER_MW_DMA_2, 0x22808242 },
+ { XFER_MW_DMA_1, 0x22808254 },
+ { XFER_MW_DMA_0, 0x228082ea },
+
+ { XFER_PIO_4, 0x0a81f442 },
+ { XFER_PIO_3, 0x0a81f443 },
+ { XFER_PIO_2, 0x0a81f454 },
+ { XFER_PIO_1, 0x0ac1f465 },
+ { XFER_PIO_0, 0x0ac1f48a },
+ { 0, 0x0ac1f48a }
};
#define HPT366_DEBUG_DRIVE_INFO 0
#define HPT370_ALLOW_ATA100_5 1
#define HPT366_ALLOW_ATA66_4 1
#define HPT366_ALLOW_ATA66_3 1
+#define HPT366_MAX_DEVS 8
+
+#define F_LOW_PCI_33 0x23
+#define F_LOW_PCI_40 0x29
+#define F_LOW_PCI_50 0x2d
+#define F_LOW_PCI_66 0x42
+
+static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];
+static int n_hpt_devs;
+
+static unsigned int pci_rev_check_hpt3xx(struct pci_dev *dev);
+static unsigned int pci_rev2_check_hpt3xx(struct pci_dev *dev);
+byte hpt366_proc = 0;
+byte hpt363_shared_irq;
+byte hpt363_shared_pin;
+extern char *ide_xfer_verbose (byte xfer_rate);
#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
static int hpt366_get_info(char *, char **, off_t, int);
extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */
extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-static struct pci_dev *bmide2_dev;
static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
{
- char *p = buffer;
- u32 bibma = bmide_dev->resource[4].start;
- u32 bibma2 = bmide2_dev->resource[4].start;
- char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A"};
- u8 c0 = 0, c1 = 0;
- u32 class_rev;
-
- pci_read_config_dword(bmide_dev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xff;
-
- /*
- * at that point bibma+0x2 et bibma+0xa are byte registers
- * to investigate:
- */
- c0 = inb_p((unsigned short)bibma + 0x02);
- if (bmide2_dev)
- c1 = inb_p((unsigned short)bibma2 + 0x02);
-
- p += sprintf(p, "\n %s Chipset.\n", chipset_names[class_rev]);
- p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
- p += sprintf(p, " %sabled %sabled\n",
- (c0&0x80) ? "dis" : " en",
- (c1&0x80) ? "dis" : " en");
- p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
- p += sprintf(p, "DMA enabled: %s %s %s %s\n",
- (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
- (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
-
- p += sprintf(p, "UDMA\n");
- p += sprintf(p, "DMA\n");
- p += sprintf(p, "PIO\n");
+ char *p = buffer;
+ char *chipset_nums[] = {"366", "366", "368", "370", "370A"};
+ int i;
+
+ p += sprintf(p, "\n "
+ "HighPoint HPT366/368/370\n");
+ for (i = 0; i < n_hpt_devs; i++) {
+ struct pci_dev *dev = hpt_devs[i];
+ unsigned short iobase = dev->resource[4].start;
+ u32 class_rev;
+ u8 c0, c1;
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xff;
+
+ p += sprintf(p, "\nController: %d\n", i);
+ p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]);
+ p += sprintf(p, "--------------- Primary Channel "
+ "--------------- Secondary Channel "
+ "--------------\n");
+
+ /* get the bus master status registers */
+ c0 = inb_p(iobase + 0x2);
+ c1 = inb_p(iobase + 0xa);
+ p += sprintf(p, "Enabled: %s"
+ " %s\n",
+ (c0 & 0x80) ? "no" : "yes",
+ (c1 & 0x80) ? "no" : "yes");
+
+ if (pci_rev_check_hpt3xx(dev)) {
+ u8 cbl;
+ cbl = inb_p(iobase + 0x7b);
+ outb_p(cbl | 1, iobase + 0x7b);
+ outb_p(cbl & ~1, iobase + 0x7b);
+ cbl = inb_p(iobase + 0x7a);
+ p += sprintf(p, "Cable: ATA-%d"
+ " ATA-%d\n",
+ (cbl & 0x02) ? 33 : 66,
+ (cbl & 0x01) ? 33 : 66);
+ p += sprintf(p, "\n");
+ }
+ p += sprintf(p, "--------------- drive0 --------- drive1 "
+ "------- drive0 ---------- drive1 -------\n");
+ p += sprintf(p, "DMA capable: %s %s"
+ " %s %s\n",
+ (c0 & 0x20) ? "yes" : "no ",
+ (c0 & 0x40) ? "yes" : "no ",
+ (c1 & 0x20) ? "yes" : "no ",
+ (c1 & 0x40) ? "yes" : "no ");
+
+ {
+ u8 c2, c3;
+ /* older revs don't have these registers mapped
+ * into io space */
+ pci_read_config_byte(dev, 0x43, &c0);
+ pci_read_config_byte(dev, 0x47, &c1);
+ pci_read_config_byte(dev, 0x4b, &c2);
+ pci_read_config_byte(dev, 0x4f, &c3);
+
+ p += sprintf(p, "Mode: %s %s"
+ " %s %s\n",
+ (c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " :
+ (c0 & 0x80) ? "PIO " : "off ",
+ (c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
+ (c1 & 0x80) ? "PIO " : "off ",
+ (c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
+ (c2 & 0x80) ? "PIO " : "off ",
+ (c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
+ (c3 & 0x80) ? "PIO " : "off ");
+ }
+ }
+ p += sprintf(p, "\n");
+
return p-buffer;/* => must be less than 4k! */
}
#endif /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
-byte hpt366_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-byte hpt363_shared_irq;
-byte hpt363_shared_pin;
-
static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev)
{
unsigned int class_rev;
@@ -282,16 +473,16 @@ static int check_in_drive_lists (ide_drive_t *drive, const char **list)
return 0;
}
-static unsigned int pci_bus_clock_list (byte speed, int direction, struct chipset_bus_clock_list_entry * chipset_table)
+static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
{
for ( ; chipset_table->xfer_speed ; chipset_table++)
if (chipset_table->xfer_speed == speed) {
- return (direction) ? chipset_table->chipset_settings_write : chipset_table->chipset_settings_read;
+ return chipset_table->chipset_settings;
}
- return (direction) ? chipset_table->chipset_settings_write : chipset_table->chipset_settings_read;
+ return chipset_table->chipset_settings;
}
-static void hpt366_tune_chipset (ide_drive_t *drive, byte speed, int direction)
+static void hpt366_tune_chipset (ide_drive_t *drive, byte speed)
{
byte regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
byte regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
@@ -304,7 +495,7 @@ static void hpt366_tune_chipset (ide_drive_t *drive, byte speed, int direction)
byte drive_fast = 0;
/*
- * Disable the "fast interrupt" prediction.
+ * Disable the "fast interrupt" prediction.
*/
pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
if (drive_fast & 0x02)
@@ -314,16 +505,22 @@ static void hpt366_tune_chipset (ide_drive_t *drive, byte speed, int direction)
/* detect bus speed by looking at control reg timing: */
switch((reg1 >> 8) & 7) {
case 5:
- reg2 = pci_bus_clock_list(speed, direction, forty_base);
+ reg2 = pci_bus_clock_list(speed, forty_base);
break;
case 9:
- reg2 = pci_bus_clock_list(speed, direction, twenty_five_base);
+ reg2 = pci_bus_clock_list(speed, twenty_five_base);
break;
default:
case 7:
- reg2 = pci_bus_clock_list(speed, direction, thirty_three_base);
+ reg2 = pci_bus_clock_list(speed, thirty_three_base);
break;
}
+#if 0
+ /* this is a nice idea ... */
+ list_conf = pci_bus_clock_list(speed,
+ (struct chipset_bus_clock_list_entry *)
+ dev->sysdata);
+#endif
/*
* Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
*/
@@ -337,40 +534,47 @@ static void hpt366_tune_chipset (ide_drive_t *drive, byte speed, int direction)
pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
}
-static void hpt370_tune_chipset (ide_drive_t *drive, byte speed, int direction)
+static void hpt370_tune_chipset (ide_drive_t *drive, byte speed)
{
byte regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
- byte reg5bh = (speed != XFER_UDMA_5) ? 0x22 : (direction) ? 0x20 : 0x22;
- unsigned int list_conf = pci_bus_clock_list(speed, direction, thirty_three_base_hpt370);
+ unsigned int list_conf = 0;
unsigned int drive_conf = 0;
unsigned int conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
- byte drive_pci = 0;
- byte drive_fast = 0;
+ byte drive_pci = 0x40 + (drive->dn * 4);
+ byte new_fast, drive_fast = 0;
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
- switch (drive->dn) {
- case 0: drive_pci = 0x40; break;
- case 1: drive_pci = 0x44; break;
- case 2: drive_pci = 0x48; break;
- case 3: drive_pci = 0x4c; break;
- default: return;
- }
/*
* Disable the "fast interrupt" prediction.
+ * don't holdoff on interrupts. (== 0x01 despite what the docs say)
*/
- pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
- if (drive_fast & 0x80)
- pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x80);
+ pci_read_config_byte(dev, regfast, &drive_fast);
+ new_fast = drive_fast;
+ if (new_fast & 0x02)
+ new_fast &= ~0x02;
+
+#ifdef HPT_DELAY_INTERRUPT
+ if (new_fast & 0x01)
+ new_fast &= ~0x01;
+#else
+ if ((new_fast & 0x01) == 0)
+ new_fast |= 0x01;
+#endif
+ if (new_fast != drive_fast)
+ pci_write_config_byte(HWIF(drive)->pci_dev, regfast, new_fast);
- pci_read_config_dword(HWIF(drive)->pci_dev, drive_pci, &drive_conf);
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x5b, reg5bh);
+ list_conf = pci_bus_clock_list(speed,
+ (struct chipset_bus_clock_list_entry *)
+ dev->sysdata);
+ pci_read_config_dword(dev, drive_pci, &drive_conf);
list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
- /*
- * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
- */
- list_conf &= ~0x80000000;
+
+ if (speed < XFER_MW_DMA_0) {
+ list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+ }
- pci_write_config_dword(HWIF(drive)->pci_dev, drive_pci, list_conf);
+ pci_write_config_dword(dev, drive_pci, list_conf);
}
static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
@@ -382,9 +586,9 @@ static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
drive->init_speed = speed;
if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
- hpt370_tune_chipset(drive, speed, 0);
+ hpt370_tune_chipset(drive, speed);
} else {
- hpt366_tune_chipset(drive, speed, 0);
+ hpt366_tune_chipset(drive, speed);
}
drive->current_speed = speed;
return ((int) ide_config_drive_speed(drive, speed));
@@ -541,13 +745,6 @@ void hpt3xx_maskproc (ide_drive_t *drive, int mask)
}
}
-void hpt370_rw_proc (ide_drive_t *drive, ide_dma_action_t func)
-{
- if ((func != ide_dma_write) || (func != ide_dma_read))
- return;
- hpt370_tune_chipset(drive, drive->current_speed, (func == ide_dma_write));
-}
-
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -624,6 +821,13 @@ int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
reg50h, reg52h, reg5ah);
if (reg5ah & 0x10)
pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, reg5ah & ~0x10);
+ /* fall through to a reset */
+#if 0
+ case ide_dma_begin:
+ case ide_dma_end:
+ /* reset the chips state over and over.. */
+ pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x13);
+#endif
break;
case ide_dma_timeout:
default:
@@ -634,9 +838,52 @@ int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long dma_base = hwif->dma_base;
+ byte regstate = hwif->channel ? 0x54 : 0x50;
+ byte reginfo = hwif->channel ? 0x56 : 0x52;
+ byte dma_stat;
+
switch (func) {
case ide_dma_check:
return config_drive_xfer_rate(drive);
+ case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
+ dma_stat = inb(dma_base+2);
+ return (dma_stat & 4) == 4; /* return 1 if INTR asserted */
+
+ case ide_dma_end:
+ dma_stat = inb(dma_base + 2);
+ if (dma_stat & 0x01) {
+ udelay(20); /* wait a little */
+ dma_stat = inb(dma_base + 2);
+ }
+ if ((dma_stat & 0x01) == 0)
+ break;
+
+ func = ide_dma_timeout;
+ /* fallthrough */
+
+ case ide_dma_timeout:
+ case ide_dma_lostirq:
+ pci_read_config_byte(hwif->pci_dev, reginfo,
+ &dma_stat);
+ printk("%s: %d bytes in FIFO\n", drive->name,
+ dma_stat);
+ pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
+ udelay(10);
+ dma_stat = inb(dma_base);
+ outb(dma_stat & ~0x1, dma_base); /* stop dma */
+ dma_stat = inb(dma_base + 2);
+ outb(dma_stat | 0x6, dma_base+2); /* clear errors */
+ /* fallthrough */
+
+#ifdef HPT_RESET_STATE_ENGINE
+ case ide_dma_begin:
+#endif
+ pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
+ udelay(10);
+ break;
+
default:
break;
}
@@ -644,6 +891,212 @@ int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+void hpt3xx_reset (ide_drive_t *drive)
+{
+#if 0
+ unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4);
+ byte reset = (HWIF(drive)->channel) ? 0x80 : 0x40;
+ byte reg59h = 0;
+
+ pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
+ pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
+ pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
+#endif
+}
+
+#if 0
+static int hpt3xx_tristate (ide_drive_t * drive, int state)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ byte reset = (hwif->channel) ? 0x80 : 0x40;
+ byte state_reg = (hwif->channel) ? 0x57 : 0x53;
+ byte reg59h = 0;
+ byte regXXh = 0;
+
+ if (!hwif)
+ return -EINVAL;
+
+// hwif->bus_state = state;
+
+ pci_read_config_byte(dev, 0x59, &reg59h);
+ pci_read_config_byte(dev, state_reg, &regXXh);
+
+ if (state) {
+ (void) ide_do_reset(drive);
+ pci_write_config_byte(dev, state_reg, regXXh|0x80);
+ pci_write_config_byte(dev, 0x59, reg59h|reset);
+ } else {
+ pci_write_config_byte(dev, 0x59, reg59h & ~(reset));
+ pci_write_config_byte(dev, state_reg, regXXh & ~(0x80));
+ (void) ide_do_reset(drive);
+ }
+ return 0;
+}
+#endif
+
+/*
+ * set/get power state for a drive.
+ * turning the power off does the following things:
+ * 1) soft-reset the drive
+ * 2) tri-states the ide bus
+ *
+ * when we turn things back on, we need to re-initialize things.
+ */
+#define TRISTATE_BIT 0x8000
+static int hpt370_busproc(ide_drive_t * drive, int state)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ byte tristate, resetmask, bus_reg;
+ u16 tri_reg;
+
+ if (!hwif)
+ return -EINVAL;
+
+ hwif->bus_state = state;
+
+ if (hwif->channel) {
+ /* secondary channel */
+ tristate = 0x56;
+ resetmask = 0x80;
+ } else {
+ /* primary channel */
+ tristate = 0x52;
+ resetmask = 0x40;
+ }
+
+ /* grab status */
+ pci_read_config_word(hwif->pci_dev, tristate, &tri_reg);
+ pci_read_config_byte(hwif->pci_dev, 0x59, &bus_reg);
+
+ /* set the state. we don't set it if we don't need to do so.
+ * make sure that the drive knows that it has failed if it's off */
+ switch (state) {
+ case BUSSTATE_ON:
+ hwif->drives[0].failures = 0;
+ hwif->drives[1].failures = 0;
+ if ((bus_reg & resetmask) == 0)
+ return 0;
+ tri_reg &= ~TRISTATE_BIT;
+ bus_reg &= ~resetmask;
+ break;
+ case BUSSTATE_OFF:
+ hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+ hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+ if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask))
+ return 0;
+ tri_reg &= ~TRISTATE_BIT;
+ bus_reg |= resetmask;
+ break;
+ case BUSSTATE_TRISTATE:
+ hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+ hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+ if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask))
+ return 0;
+ tri_reg |= TRISTATE_BIT;
+ bus_reg |= resetmask;
+ break;
+ }
+ pci_write_config_byte(hwif->pci_dev, 0x59, bus_reg);
+ pci_write_config_word(hwif->pci_dev, tristate, tri_reg);
+
+ return 0;
+}
+
+static void __init init_hpt370(struct pci_dev *dev)
+{
+ int adjust, i;
+ u16 freq;
+ u32 pll;
+ byte reg5bh;
+
+ /*
+ * default to pci clock. make sure MA15/16 are set to output
+ * to prevent drives having problems with 40-pin cables.
+ */
+ pci_write_config_byte(dev, 0x5b, 0x23);
+
+ /*
+ * set up the PLL. we need to adjust it so that it's stable.
+ * freq = Tpll * 192 / Tpci
+ */
+ pci_read_config_word(dev, 0x78, &freq);
+ freq &= 0x1FF;
+ if (freq < 0x9c) {
+ pll = F_LOW_PCI_33;
+ dev->sysdata = (void *) thirty_three_base_hpt370;
+ printk("HPT370: using 33MHz PCI clock\n");
+ } else if (freq < 0xb0) {
+ pll = F_LOW_PCI_40;
+ } else if (freq < 0xc8) {
+ pll = F_LOW_PCI_50;
+ dev->sysdata = (void *) fifty_base_hpt370;
+ printk("HPT370: using 50MHz PCI clock\n");
+ } else {
+ pll = F_LOW_PCI_66;
+ dev->sysdata = (void *) sixty_six_base_hpt370;
+ printk("HPT370: using 66MHz PCI clock\n");
+ }
+
+ /*
+ * only try the pll if we don't have a table for the clock
+ * speed that we're running at. NOTE: the internal PLL will
+ * result in slow reads when using a 33MHz PCI clock. we also
+ * don't like to use the PLL because it will cause glitches
+ * on PRST/SRST when the HPT state engine gets reset.
+ */
+ if (dev->sysdata)
+ goto init_hpt370_done;
+
+ /*
+ * adjust PLL based upon PCI clock, enable it, and wait for
+ * stabilization.
+ */
+ adjust = 0;
+ freq = (pll < F_LOW_PCI_50) ? 2 : 4;
+ while (adjust++ < 6) {
+ pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
+ pll | 0x100);
+
+ /* wait for clock stabilization */
+ for (i = 0; i < 0x50000; i++) {
+ pci_read_config_byte(dev, 0x5b, &reg5bh);
+ if (reg5bh & 0x80) {
+ /* spin looking for the clock to destabilize */
+ for (i = 0; i < 0x1000; ++i) {
+ pci_read_config_byte(dev, 0x5b,
+ &reg5bh);
+ if ((reg5bh & 0x80) == 0)
+ goto pll_recal;
+ }
+ pci_read_config_dword(dev, 0x5c, &pll);
+ pci_write_config_dword(dev, 0x5c,
+ pll & ~0x100);
+ pci_write_config_byte(dev, 0x5b, 0x21);
+ dev->sysdata = (void *) fifty_base_hpt370;
+ printk("HPT370: using 50MHz internal PLL\n");
+ goto init_hpt370_done;
+ }
+ }
+pll_recal:
+ if (adjust & 1)
+ pll -= (adjust >> 1);
+ else
+ pll += (adjust >> 1);
+ }
+
+init_hpt370_done:
+ /* reset state engine */
+ pci_write_config_byte(dev, 0x50, 0x37);
+ pci_write_config_byte(dev, 0x54, 0x37);
+ udelay(100);
+}
+
unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
{
byte test = 0;
@@ -652,14 +1105,8 @@ unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
-
-#if 0
- if (test != 0x08)
- pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x08);
-#else
if (test != (L1_CACHE_BYTES / 4))
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
-#endif
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
if (test != 0x78)
@@ -673,17 +1120,18 @@ unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
if (test != 0x08)
pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+ if (pci_rev_check_hpt3xx(dev)) {
+ init_hpt370(dev);
+ hpt_devs[n_hpt_devs++] = dev;
+ } else {
+ hpt_devs[n_hpt_devs++] = dev;
+ }
+
#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
if (!hpt366_proc) {
hpt366_proc = 1;
- bmide_dev = dev;
- if (pci_rev_check_hpt3xx(dev))
- bmide2_dev = dev;
hpt366_display_info = &hpt366_get_info;
}
- if ((hpt366_proc) && ((dev->devfn - bmide_dev->devfn) == 1)) {
- bmide2_dev = dev;
- }
#endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */
return dev->irq;
@@ -691,38 +1139,58 @@ unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
{
- byte ata66 = 0;
+ byte ata66 = 0;
+ byte regmask = (hwif->channel) ? 0x01 : 0x02;
pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
#ifdef DEBUG
printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
- ata66, (ata66 & 0x02) ? "33" : "66",
+ ata66, (ata66 & regmask) ? "33" : "66",
PCI_FUNC(hwif->pci_dev->devfn));
#endif /* DEBUG */
- return ((ata66 & 0x02) ? 0 : 1);
+ return ((ata66 & regmask) ? 0 : 1);
}
void __init ide_init_hpt366 (ide_hwif_t *hwif)
{
+ int hpt_rev;
+
hwif->tuneproc = &hpt3xx_tune_drive;
hwif->speedproc = &hpt3xx_tune_chipset;
hwif->quirkproc = &hpt3xx_quirkproc;
hwif->intrproc = &hpt3xx_intrproc;
hwif->maskproc = &hpt3xx_maskproc;
+#ifdef HPT_SERIALIZE_IO
+ /* serialize access to this device */
+ if (hwif->mate)
+ hwif->serialized = hwif->mate->serialized = 1;
+#endif
+
+ hpt_rev = pci_rev_check_hpt3xx(hwif->pci_dev);
+ if (hpt_rev) {
+ /* set up ioctl for power status. note: power affects both
+ * drives on each channel */
+ hwif->busproc = &hpt370_busproc;
+ }
+
if (pci_rev2_check_hpt3xx(hwif->pci_dev)) {
/* do nothing now but will split device types */
+ hwif->resetproc = &hpt3xx_reset;
+/*
+ * don't do until we can parse out the cobalt box argh ...
+ * hwif->busproc = &hpt3xx_tristate;
+ */
}
#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->dma_base) {
- if (pci_rev_check_hpt3xx(hwif->pci_dev)) {
+ if (hpt_rev) {
byte reg5ah = 0;
pci_read_config_byte(hwif->pci_dev, 0x5a, &reg5ah);
if (reg5ah & 0x10) /* interrupt force enable */
pci_write_config_byte(hwif->pci_dev, 0x5a, reg5ah & ~0x10);
hwif->dmaproc = &hpt370_dmaproc;
- hwif->rwproc = &hpt370_rw_proc;
} else {
hwif->dmaproc = &hpt366_dmaproc;
}
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index daf317775..309285bad 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -2911,11 +2911,7 @@ int ide_cdrom_cleanup(ide_drive_t *drive)
return 0;
}
-static
-int ide_cdrom_reinit (ide_drive_t *drive)
-{
- return 0;
-}
+int ide_cdrom_reinit (ide_drive_t *drive);
static ide_driver_t ide_cdrom_driver = {
name: "ide-cdrom",
@@ -2925,6 +2921,8 @@ static ide_driver_t ide_cdrom_driver = {
supports_dma: 1,
supports_dsc_overlap: 1,
cleanup: ide_cdrom_cleanup,
+ standby: NULL,
+ flushcache: NULL,
do_request: ide_do_rw_cdrom,
end_request: NULL,
ioctl: ide_cdrom_ioctl,
@@ -2953,6 +2951,39 @@ char *ignore = NULL;
MODULE_PARM(ignore, "s");
MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
+int ide_cdrom_reinit (ide_drive_t *drive)
+{
+ struct cdrom_info *info;
+ int failed = 0;
+
+ MOD_INC_USE_COUNT;
+ info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL);
+ if (info == NULL) {
+ printk ("%s: Can't allocate a cdrom structure\n", drive->name);
+ return 1;
+ }
+ if (ide_register_subdriver (drive, &ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
+ printk ("%s: Failed to register the driver with ide.c\n", drive->name);
+ kfree (info);
+ return 1;
+ }
+ memset (info, 0, sizeof (struct cdrom_info));
+ drive->driver_data = info;
+ DRIVER(drive)->busy++;
+ if (ide_cdrom_setup (drive)) {
+ DRIVER(drive)->busy--;
+ if (ide_cdrom_cleanup (drive))
+ printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
+ return 1;
+ }
+ DRIVER(drive)->busy--;
+ failed--;
+
+ ide_register_module(&ide_cdrom_module);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
static void __exit ide_cdrom_exit(void)
{
ide_drive_t *drive;
diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h
index 9a5de53a6..d107fab12 100644
--- a/drivers/ide/ide-cd.h
+++ b/drivers/ide/ide-cd.h
@@ -38,7 +38,9 @@
/************************************************************************/
#define SECTOR_BITS 9
+#ifndef SECTOR_SIZE
#define SECTOR_SIZE (1 << SECTOR_BITS)
+#endif
#define SECTORS_PER_FRAME (CD_FRAMESIZE >> SECTOR_BITS)
#define SECTOR_BUFFER_SIZE (CD_FRAMESIZE * 32)
#define SECTORS_BUFFER (SECTOR_BUFFER_SIZE >> SECTOR_BITS)
diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c
index 62a719ad8..c23b86b56 100644
--- a/drivers/ide/ide-cs.c
+++ b/drivers/ide/ide-cs.c
@@ -227,16 +227,15 @@ while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
#define CFG_CHECK(fn, args...) \
if (CardServices(fn, args) != 0) goto next_entry
-int idecs_register (int io_base, int ctl_base, int irq)
+int idecs_register (int arg1, int arg2, int irq)
{
hw_regs_t hw;
- ide_init_hwif_ports(&hw, (ide_ioreg_t) io_base, (ide_ioreg_t) ctl_base, NULL);
+ ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
hw.irq = irq;
- hw.chipset = ide_pci; // this enables IRQ sharing w/ PCI irqs
+ hw.chipset = ide_pci; /* this enables IRQ sharing w/ PCI irqs */
return ide_register_hw(&hw, NULL);
}
-
void ide_config(dev_link_t *link)
{
client_handle_t handle = link->handle;
@@ -338,15 +337,15 @@ void ide_config(dev_link_t *link)
if (link->io.NumPorts2)
release_region(link->io.BasePort2, link->io.NumPorts2);
- /* disable drive interrupts during IDE probe */
- if(ctl_base)
- outb(0x02, ctl_base);
-
/* retry registration in case device is still spinning up */
for (i = 0; i < 10; i++) {
+ if (ctl_base)
+ outb(0x02, ctl_base); /* Set nIEN = disable device interrupts */
hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
if (hd >= 0) break;
if (link->io.NumPorts1 == 0x20) {
+ if (ctl_base)
+ outb(0x02, ctl_base+0x10);
hd = idecs_register(io_base+0x10, ctl_base+0x10,
link->irq.AssignedIRQ);
if (hd >= 0) {
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 000fe8a45..cbc80707b 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/ide-disk.c Version 1.10 June 9, 2000
+ * linux/drivers/ide/ide-disk.c Version 1.13 Nov 28, 2001
*
* Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
*/
@@ -28,9 +28,11 @@
* added UDMA 3/4 reporting
* Version 1.10 request queue changes, Ultra DMA 100
* Version 1.11 Highmem I/O support, Jens Axboe <axboe@suse.de>
+ * Version 1.12 added 48-bit lba
+ * Version 1.13 adding taskfile io access method
*/
-#define IDEDISK_VERSION "1.11"
+#define IDEDISK_VERSION "1.13"
#undef REALLY_SLOW_IO /* most systems can safely undef this */
@@ -60,33 +62,6 @@
#define IS_PDC4030_DRIVE (0) /* auto-NULLs out pdc4030 code */
#endif
-static void idedisk_bswap_data (void *buffer, int wcount)
-{
- u16 *p = buffer;
-
- while (wcount--) {
- *p = *p << 8 | *p >> 8; p++;
- *p = *p << 8 | *p >> 8; p++;
- }
-}
-
-inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
- ide_input_data(drive, buffer, wcount);
- if (drive->bswap)
- idedisk_bswap_data(buffer, wcount);
-}
-
-static inline void idedisk_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
- if (drive->bswap) {
- idedisk_bswap_data(buffer, wcount);
- ide_output_data(drive, buffer, wcount);
- idedisk_bswap_data(buffer, wcount);
- } else
- ide_output_data(drive, buffer, wcount);
-}
-
/*
* lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
* value for this drive (from its reported identification information).
@@ -100,6 +75,11 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
{
unsigned long lba_sects, chs_sects, head, tail;
+ if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
+ printk("48-bit Drive: %llu \n", id->lba_capacity_2);
+ return 1;
+ }
+
/*
* The ATA spec tells large drives to return
* C/H/S = 16383/16/63 independent of their size.
@@ -132,367 +112,256 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
return 0; /* lba_capacity value may be bad */
}
+static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
+static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
+static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block);
+
/*
- * read_intr() is the handler for disk read/multread interrupts
+ * do_rw_disk() issues READ and WRITE commands to a disk,
+ * using LBA if supported, or CHS otherwise, to address sectors.
+ * It also takes care of issuing special DRIVE_CMDs.
*/
-static ide_startstop_t read_intr (ide_drive_t *drive)
+static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
{
- byte stat;
- int i;
- unsigned int msect, nsect;
- unsigned long flags;
- struct request *rq;
- char *to;
-
- /* new way for dealing with premature shared PCI interrupts */
- if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
- if (stat & (ERR_STAT|DRQ_STAT)) {
- return ide_error(drive, "read_intr", stat);
- }
- /* no data yet, so wait for another interrupt */
- ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
- return ide_started;
- }
+ if (rq_data_dir(rq) == READ)
+ goto good_command;
+ if (rq_data_dir(rq) == WRITE)
+ goto good_command;
- msect = drive->mult_count;
-read_next:
- rq = HWGROUP(drive)->rq;
- if (msect) {
- if ((nsect = rq->current_nr_sectors) > msect)
- nsect = msect;
- msect -= nsect;
- } else
- nsect = 1;
- to = ide_map_buffer(rq, &flags);
- idedisk_input_data(drive, to, nsect * SECTOR_WORDS);
-#ifdef DEBUG
- printk("%s: read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n",
- drive->name, rq->sector, rq->sector+nsect-1,
- (unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect);
-#endif
- ide_unmap_buffer(to, &flags);
- rq->sector += nsect;
- rq->errors = 0;
- i = (rq->nr_sectors -= nsect);
- if (((long)(rq->current_nr_sectors -= nsect)) <= 0)
- ide_end_request(1, HWGROUP(drive));
- if (i > 0) {
- if (msect)
- goto read_next;
- ide_set_handler (drive, &read_intr, WAIT_CMD, NULL);
- return ide_started;
+ printk(KERN_ERR "%s: bad command: %lx\n", drive->name, rq->flags);
+ ide_end_request(0, HWGROUP(drive));
+ return ide_stopped;
+
+good_command:
+
+#ifdef CONFIG_BLK_DEV_PDC4030
+ if (IS_PDC4030_DRIVE) {
+ extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+ return promise_rw_disk(drive, rq, block);
}
- return ide_stopped;
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+
+ if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) /* 48-bit LBA */
+ return lba_48_rw_disk(drive, rq, (unsigned long long) block);
+ if (drive->select.b.lba) /* 28-bit LBA */
+ return lba_28_rw_disk(drive, rq, (unsigned long) block);
+
+ /* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */
+ return chs_rw_disk(drive, rq, (unsigned long) block);
}
-/*
- * write_intr() is the handler for disk write interrupts
- */
-static ide_startstop_t write_intr (ide_drive_t *drive)
+static task_ioreg_t get_command (ide_drive_t *drive, int cmd)
{
- byte stat;
- int i;
- ide_hwgroup_t *hwgroup = HWGROUP(drive);
- struct request *rq = hwgroup->rq;
+ int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
- if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
- printk("%s: write_intr error1: nr_sectors=%ld, stat=0x%02x\n", drive->name, rq->nr_sectors, stat);
- } else {
-#ifdef DEBUG
- printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n",
- drive->name, rq->sector, (unsigned long) rq->buffer,
- rq->nr_sectors-1);
+#if 1
+ lba48bit = drive->addressing;
#endif
- if ((rq->nr_sectors == 1) ^ ((stat & DRQ_STAT) != 0)) {
- rq->sector++;
- rq->errors = 0;
- i = --rq->nr_sectors;
- --rq->current_nr_sectors;
- if (((long)rq->current_nr_sectors) <= 0)
- ide_end_request(1, hwgroup);
- if (i > 0) {
- unsigned long flags;
- char *to = ide_map_buffer(rq, &flags);
- idedisk_output_data (drive, to, SECTOR_WORDS);
- ide_unmap_buffer(to, &flags);
- ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
- return ide_started;
- }
- return ide_stopped;
- }
- return ide_stopped; /* the original code did this here (?) */
- }
- return ide_error(drive, "write_intr", stat);
-}
-/*
- * ide_multwrite() transfers a block of up to mcount sectors of data
- * to a drive as part of a disk multiple-sector write operation.
- *
- * Returns 0 on success.
- *
- * Note that we may be called from two contexts - the do_rw_disk context
- * and IRQ context. The IRQ can happen any time after we've output the
- * full "mcount" number of sectors, so we must make sure we update the
- * state _before_ we output the final part of the data!
- */
-int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
-{
- ide_hwgroup_t *hwgroup= HWGROUP(drive);
- struct request *rq = &hwgroup->wrq;
-
- do {
- char *buffer;
- int nsect = rq->current_nr_sectors;
- unsigned long flags;
-
- if (nsect > mcount)
- nsect = mcount;
- mcount -= nsect;
-
- buffer = ide_map_buffer(rq, &flags);
- rq->sector += nsect;
- rq->nr_sectors -= nsect;
- rq->current_nr_sectors -= nsect;
-
- /* Do we move to the next bh after this? */
- if (!rq->current_nr_sectors) {
- struct bio *bio = rq->bio->bi_next;
-
- /* end early early we ran out of requests */
- if (!bio) {
- mcount = 0;
- } else {
- rq->bio = bio;
- rq->current_nr_sectors = bio_sectors(bio);
- rq->hard_cur_sectors = rq->current_nr_sectors;
- }
- }
+ if ((cmd == READ) && (drive->using_dma))
+ return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA;
+ else if ((cmd == READ) && (drive->mult_count))
+ return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD;
+ else if (cmd == READ)
+ return (lba48bit) ? WIN_READ_EXT : WIN_READ;
+ else if ((cmd == WRITE) && (drive->using_dma))
+ return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+ else if ((cmd == WRITE) && (drive->mult_count))
+ return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
+ else if (cmd == WRITE)
+ return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE;
+ else
+ return WIN_NOP;
+}
- /*
- * Ok, we're all setup for the interrupt
- * re-entering us on the last transfer.
- */
- idedisk_output_data(drive, buffer, nsect<<7);
- ide_unmap_buffer(buffer, &flags);
- } while (mcount);
+static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+ struct hd_drive_task_hdr taskfile;
+ struct hd_drive_hob_hdr hobfile;
+ ide_task_t args;
+
+ task_ioreg_t command = get_command(drive, rq_data_dir(rq));
+ unsigned int track = (block / drive->sect);
+ unsigned int sect = (block % drive->sect) + 1;
+ unsigned int head = (track % drive->head);
+ unsigned int cyl = (track / drive->head);
+
+ memset(&taskfile, 0, sizeof(task_struct_t));
+ memset(&hobfile, 0, sizeof(hob_struct_t));
+
+ taskfile.sector_count = (rq->nr_sectors==256)?0x00:rq->nr_sectors;
+ taskfile.sector_number = sect;
+ taskfile.low_cylinder = cyl;
+ taskfile.high_cylinder = (cyl>>8);
+ taskfile.device_head = head;
+ taskfile.device_head |= drive->select.all;
+ taskfile.command = command;
- return 0;
-}
+#ifdef DEBUG
+ printk("%s: %sing: ", drive->name,
+ (rq_data_dir(rq)==READ) ? "read" : "writ");
+ if (lba) printk("LBAsect=%lld, ", block);
+ else printk("CHS=%d/%d/%d, ", cyl, head, sect);
+ printk("sectors=%ld, ", rq->nr_sectors);
+ printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
-/*
- * multwrite_intr() is the handler for disk multwrite interrupts
- */
-static ide_startstop_t multwrite_intr (ide_drive_t *drive)
-{
- byte stat;
- ide_hwgroup_t *hwgroup = HWGROUP(drive);
- struct request *rq = &hwgroup->wrq;
-
- if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
- if (stat & DRQ_STAT) {
- /*
- * The drive wants data. Remember rq is the copy
- * of the request
- */
- if (rq->nr_sectors) {
- if (ide_multwrite(drive, drive->mult_count))
- return ide_stopped;
- ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
- return ide_started;
- }
- } else {
- /*
- * If the copy has all the blocks completed then
- * we can end the original request.
- */
- if (!rq->nr_sectors) { /* all done? */
- rq = hwgroup->rq;
-
- __ide_end_request(hwgroup, 1, rq->nr_sectors);
- return ide_stopped;
- }
- }
- return ide_stopped; /* the original code did this here (?) */
- }
- return ide_error(drive, "multwrite_intr", stat);
+ memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+ memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+ args.command_type = ide_cmd_type_parser(&args);
+ args.prehandler = ide_pre_handler_parser(&taskfile, &hobfile);
+ args.handler = ide_handler_parser(&taskfile, &hobfile);
+ args.posthandler = NULL;
+ args.rq = (struct request *) rq;
+ args.block = block;
+ rq->special = NULL;
+ rq->special = (ide_task_t *)&args;
+
+ return do_rw_taskfile(drive, &args);
}
-/*
- * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
- */
-static ide_startstop_t set_multmode_intr (ide_drive_t *drive)
+static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
{
- byte stat;
+ struct hd_drive_task_hdr taskfile;
+ struct hd_drive_hob_hdr hobfile;
+ ide_task_t args;
- if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) {
- drive->mult_count = drive->mult_req;
- } else {
- drive->mult_req = drive->mult_count = 0;
- drive->special.b.recalibrate = 1;
- (void) ide_dump_status(drive, "set_multmode", stat);
- }
- return ide_stopped;
-}
+ task_ioreg_t command = get_command(drive, rq_data_dir(rq));
-/*
- * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
- */
-static ide_startstop_t set_geometry_intr (ide_drive_t *drive)
-{
- byte stat;
+ memset(&taskfile, 0, sizeof(task_struct_t));
+ memset(&hobfile, 0, sizeof(hob_struct_t));
- if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
- return ide_stopped;
+ taskfile.sector_count = (rq->nr_sectors==256)?0x00:rq->nr_sectors;
+ taskfile.sector_number = block;
+ taskfile.low_cylinder = (block>>=8);
+ taskfile.high_cylinder = (block>>=8);
+ taskfile.device_head = ((block>>8)&0x0f);
+ taskfile.device_head |= drive->select.all;
+ taskfile.command = command;
- if (stat & (ERR_STAT|DRQ_STAT))
- return ide_error(drive, "set_geometry_intr", stat);
+#ifdef DEBUG
+ printk("%s: %sing: ", drive->name,
+ (rq_data_dir(rq)==READ) ? "read" : "writ");
+ if (lba) printk("LBAsect=%lld, ", block);
+ else printk("CHS=%d/%d/%d, ", cyl, head, sect);
+ printk("sectors=%ld, ", rq->nr_sectors);
+ printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
- ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
- return ide_started;
+ memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+ memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+ args.command_type = ide_cmd_type_parser(&args);
+ args.prehandler = ide_pre_handler_parser(&taskfile, &hobfile);
+ args.handler = ide_handler_parser(&taskfile, &hobfile);
+ args.posthandler = NULL;
+ args.rq = (struct request *) rq;
+ args.block = block;
+ rq->special = NULL;
+ rq->special = (ide_task_t *)&args;
+
+ return do_rw_taskfile(drive, &args);
}
/*
- * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
+ * 268435455 == 137439 MB or 28bit limit
+ * 320173056 == 163929 MB or 48bit addressing
+ * 1073741822 == 549756 MB or 48bit addressing fake drive
*/
-static ide_startstop_t recal_intr (ide_drive_t *drive)
+
+static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block)
{
- byte stat = GET_STAT();
+ struct hd_drive_task_hdr taskfile;
+ struct hd_drive_hob_hdr hobfile;
+ ide_task_t args;
- if (!OK_STAT(stat,READY_STAT,BAD_STAT))
- return ide_error(drive, "recal_intr", stat);
- return ide_stopped;
-}
+ task_ioreg_t command = get_command(drive, rq_data_dir(rq));
-/*
- * do_rw_disk() issues READ and WRITE commands to a disk,
- * using LBA if supported, or CHS otherwise, to address sectors.
- * It also takes care of issuing special DRIVE_CMDs.
- */
-static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
-{
- unsigned long flags;
+ memset(&taskfile, 0, sizeof(task_struct_t));
+ memset(&hobfile, 0, sizeof(hob_struct_t));
+
+ taskfile.sector_count = rq->nr_sectors;
+ hobfile.sector_count = (rq->nr_sectors>>8);
+
+ if (rq->nr_sectors == 65536) {
+ taskfile.sector_count = 0x00;
+ hobfile.sector_count = 0x00;
+ }
+
+ taskfile.sector_number = block; /* low lba */
+ taskfile.low_cylinder = (block>>=8); /* mid lba */
+ taskfile.high_cylinder = (block>>=8); /* hi lba */
+ hobfile.sector_number = (block>>=8); /* low lba */
+ hobfile.low_cylinder = (block>>=8); /* mid lba */
+ hobfile.high_cylinder = (block>>=8); /* hi lba */
+ taskfile.device_head = drive->select.all;
+ hobfile.device_head = taskfile.device_head;
+ hobfile.control = (drive->ctl|0x80);
+ taskfile.command = command;
- if (IDE_CONTROL_REG)
- OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
- OUT_BYTE(0x00, IDE_FEATURE_REG);
- OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG);
-#ifdef CONFIG_BLK_DEV_PDC4030
- if (drive->select.b.lba || IS_PDC4030_DRIVE) {
-#else /* !CONFIG_BLK_DEV_PDC4030 */
- if (drive->select.b.lba) {
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-#ifdef DEBUG
- printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n",
- drive->name, (rq_data_dir(rq)==READ)?"read":"writ",
- block, rq->nr_sectors, (unsigned long) rq->buffer);
-#endif
- OUT_BYTE(block,IDE_SECTOR_REG);
- OUT_BYTE(block>>=8,IDE_LCYL_REG);
- OUT_BYTE(block>>=8,IDE_HCYL_REG);
- OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
- } else {
- unsigned int sect,head,cyl,track;
- track = block / drive->sect;
- sect = block % drive->sect + 1;
- OUT_BYTE(sect,IDE_SECTOR_REG);
- head = track % drive->head;
- cyl = track / drive->head;
- OUT_BYTE(cyl,IDE_LCYL_REG);
- OUT_BYTE(cyl>>8,IDE_HCYL_REG);
- OUT_BYTE(head|drive->select.all,IDE_SELECT_REG);
#ifdef DEBUG
- printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n",
- drive->name, (rq_data_dir(rq)==READ)?"read":"writ", cyl,
- head, sect, rq->nr_sectors, (unsigned long) rq->buffer);
+ printk("%s: %sing: ", drive->name,
+ (rq_data_dir(rq)==READ) ? "read" : "writ");
+ if (lba) printk("LBAsect=%lld, ", block);
+ else printk("CHS=%d/%d/%d, ", cyl, head, sect);
+ printk("sectors=%ld, ", rq->nr_sectors);
+ printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
#endif
- }
-#ifdef CONFIG_BLK_DEV_PDC4030
- if (IS_PDC4030_DRIVE) {
- extern ide_startstop_t do_pdc4030_io(ide_drive_t *, struct request *);
- return do_pdc4030_io (drive, rq);
- }
-#endif /* CONFIG_BLK_DEV_PDC4030 */
- if (rq_data_dir(rq) == READ) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
- if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
- return ide_started;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
- ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
- OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
- return ide_started;
- }
- if (rq_data_dir(rq) == WRITE) {
- ide_startstop_t startstop;
-#ifdef CONFIG_BLK_DEV_IDEDMA
- if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))
- return ide_started;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
- OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
- if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
- printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name,
- drive->mult_count ? "MULTWRITE" : "WRITE");
- return startstop;
- }
- if (!drive->unmask)
- __cli(); /* local CPU only */
- if (drive->mult_count) {
- ide_hwgroup_t *hwgroup = HWGROUP(drive);
- /*
- * Ugh.. this part looks ugly because we MUST set up
- * the interrupt handler before outputting the first block
- * of data to be written. If we hit an error (corrupted buffer list)
- * in ide_multwrite(), then we need to remove the handler/timer
- * before returning. Fortunately, this NEVER happens (right?).
- *
- * Except when you get an error it seems...
- */
- hwgroup->wrq = *rq; /* scratchpad */
- ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
- if (ide_multwrite(drive, drive->mult_count)) {
- spin_lock_irqsave(&ide_lock, flags);
- hwgroup->handler = NULL;
- del_timer(&hwgroup->timer);
- spin_unlock_irqrestore(&ide_lock, flags);
- return ide_stopped;
- }
- } else {
- char *buffer = ide_map_buffer(rq, &flags);
- ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
- idedisk_output_data(drive, buffer, SECTOR_WORDS);
- ide_unmap_buffer(buffer, &flags);
- }
- return ide_started;
- }
- printk(KERN_ERR "%s: bad command: %lx\n", drive->name, rq->flags);
- ide_end_request(0, HWGROUP(drive));
- return ide_stopped;
+
+ memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+ memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+ args.command_type = ide_cmd_type_parser(&args);
+ args.prehandler = ide_pre_handler_parser(&taskfile, &hobfile);
+ args.handler = ide_handler_parser(&taskfile, &hobfile);
+ args.posthandler = NULL;
+ args.rq = (struct request *) rq;
+ args.block = block;
+ rq->special = NULL;
+ rq->special = (ide_task_t *)&args;
+
+ return do_rw_taskfile(drive, &args);
}
static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
{
MOD_INC_USE_COUNT;
if (drive->removable && drive->usage == 1) {
+ struct hd_drive_task_hdr taskfile;
+ struct hd_drive_hob_hdr hobfile;
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
check_disk_change(inode->i_rdev);
+ taskfile.command = WIN_DOORLOCK;
/*
* Ignore the return code from door_lock,
* since the open() has already succeeded,
* and the door_lock is irrelevant at this point.
*/
- if (drive->doorlocking && ide_wait_cmd(drive, WIN_DOORLOCK, 0, 0, 0, NULL))
+ if (drive->doorlocking &&
+ ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
drive->doorlocking = 0;
}
return 0;
}
+static int do_idedisk_flushcache(ide_drive_t *drive);
+
static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
{
if (drive->removable && !drive->usage) {
+ struct hd_drive_task_hdr taskfile;
+ struct hd_drive_hob_hdr hobfile;
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
invalidate_bdev(inode->i_bdev, 0);
+ taskfile.command = WIN_DOORUNLOCK;
if (drive->doorlocking &&
- ide_wait_cmd(drive, WIN_DOORUNLOCK, 0, 0, 0, NULL))
+ ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
drive->doorlocking = 0;
}
+ if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
+ if (do_idedisk_flushcache(drive))
+ printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
+ drive->name);
MOD_DEC_USE_COUNT;
}
@@ -507,27 +376,234 @@ static void idedisk_revalidate (ide_drive_t *drive)
}
/*
+ * Queries for true maximum capacity of the drive.
+ * Returns maximum LBA address (> 0) of the drive, 0 if failed.
+ */
+static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
+{
+ ide_task_t args;
+ unsigned long addr = 0;
+
+ if (!(drive->id->command_set_1 & 0x0400) &&
+ !(drive->id->cfs_enable_2 & 0x0100))
+ return addr;
+
+ /* Create IDE/ATA command request structure */
+ memset(&args, 0, sizeof(ide_task_t));
+ args.tfRegister[IDE_SELECT_OFFSET] = 0x40;
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX;
+ args.handler = task_no_data_intr;
+
+ /* submit command request */
+ ide_raw_taskfile(drive, &args, NULL);
+
+ /* if OK, compute maximum address value */
+ if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+ addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
+ | ((args.tfRegister[ IDE_HCYL_OFFSET] ) << 16)
+ | ((args.tfRegister[ IDE_LCYL_OFFSET] ) << 8)
+ | ((args.tfRegister[IDE_SECTOR_OFFSET] ));
+ }
+ addr++; /* since the return value is (maxlba - 1), we add 1 */
+ return addr;
+}
+
+static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive)
+{
+ ide_task_t args;
+ unsigned long long addr = 0;
+
+ /* Create IDE/ATA command request structure */
+ memset(&args, 0, sizeof(ide_task_t));
+
+ args.tfRegister[IDE_SELECT_OFFSET] = 0x40;
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX_EXT;
+ args.handler = task_no_data_intr;
+
+ /* submit command request */
+ ide_raw_taskfile(drive, &args, NULL);
+
+ /* if OK, compute maximum address value */
+ if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+ u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
+ ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
+ (args.hobRegister[IDE_SECTOR_OFFSET_HOB]);
+ u32 low = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
+ ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
+ (args.tfRegister[IDE_SECTOR_OFFSET]);
+ addr = ((__u64)high << 24) | low;
+ }
+ addr++; /* since the return value is (maxlba - 1), we add 1 */
+ return addr;
+}
+
+#ifdef CONFIG_IDEDISK_STROKE
+/*
+ * Sets maximum virtual LBA address of the drive.
+ * Returns new maximum virtual LBA address (> 0) or 0 on failure.
+ */
+static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req)
+{
+ ide_task_t args;
+ unsigned long addr_set = 0;
+
+ addr_req--;
+ /* Create IDE/ATA command request structure */
+ memset(&args, 0, sizeof(ide_task_t));
+ args.tfRegister[IDE_SECTOR_OFFSET] = ((addr_req >> 0) & 0xff);
+ args.tfRegister[IDE_LCYL_OFFSET] = ((addr_req >> 8) & 0xff);
+ args.tfRegister[IDE_HCYL_OFFSET] = ((addr_req >> 16) & 0xff);
+ args.tfRegister[IDE_SELECT_OFFSET] = ((addr_req >> 24) & 0x0f) | 0x40;
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SET_MAX;
+ args.handler = task_no_data_intr;
+ /* submit command request */
+ ide_raw_taskfile(drive, &args, NULL);
+ /* if OK, read new maximum address value */
+ if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+ addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
+ | ((args.tfRegister[ IDE_HCYL_OFFSET] ) << 16)
+ | ((args.tfRegister[ IDE_LCYL_OFFSET] ) << 8)
+ | ((args.tfRegister[IDE_SECTOR_OFFSET] ));
+ }
+ addr_set++;
+ return addr_set;
+}
+
+static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req)
+{
+ ide_task_t args;
+ unsigned long long addr_set = 0;
+
+ addr_req--;
+ /* Create IDE/ATA command request structure */
+ memset(&args, 0, sizeof(ide_task_t));
+ args.tfRegister[IDE_SECTOR_OFFSET] = ((addr_req >> 0) & 0xff);
+ args.tfRegister[IDE_LCYL_OFFSET] = ((addr_req >>= 8) & 0xff);
+ args.tfRegister[IDE_HCYL_OFFSET] = ((addr_req >>= 8) & 0xff);
+ args.tfRegister[IDE_SELECT_OFFSET] = 0x40;
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SET_MAX_EXT;
+ args.hobRegister[IDE_SECTOR_OFFSET_HOB] = ((addr_req >>= 8) & 0xff);
+ args.hobRegister[IDE_LCYL_OFFSET_HOB] = ((addr_req >>= 8) & 0xff);
+ args.hobRegister[IDE_HCYL_OFFSET_HOB] = ((addr_req >>= 8) & 0xff);
+ args.hobRegister[IDE_SELECT_OFFSET_HOB] = 0x40;
+ args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
+ args.handler = task_no_data_intr;
+ /* submit command request */
+ ide_raw_taskfile(drive, &args, NULL);
+ /* if OK, compute maximum address value */
+ if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+ u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
+ ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
+ (args.hobRegister[IDE_SECTOR_OFFSET_HOB]);
+ u32 low = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
+ ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
+ (args.tfRegister[IDE_SECTOR_OFFSET]);
+ addr_set = ((__u64)high << 24) | low;
+ }
+ return addr_set;
+}
+
+/*
+ * Tests if the drive supports Host Protected Area feature.
+ * Returns true if supported, false otherwise.
+ */
+static inline int idedisk_supports_host_protected_area(ide_drive_t *drive)
+{
+ int flag = (drive->id->cfs_enable_1 & 0x0400) ? 1 : 0;
+ printk("%s: host protected area => %d\n", drive->name, flag);
+ return flag;
+}
+
+#endif /* CONFIG_IDEDISK_STROKE */
+
+/*
* Compute drive->capacity, the full capacity of the drive
* Called with drive->id != NULL.
+ *
+ * To compute capacity, this uses either of
+ *
+ * 1. CHS value set by user (whatever user sets will be trusted)
+ * 2. LBA value from target drive (require new ATA feature)
+ * 3. LBA value from system BIOS (new one is OK, old one may break)
+ * 4. CHS value from system BIOS (traditional style)
+ *
+ * in above order (i.e., if value of higher priority is available,
+ * reset will be ignored).
*/
static void init_idedisk_capacity (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
unsigned long capacity = drive->cyl * drive->head * drive->sect;
+ unsigned long set_max = idedisk_read_native_max_address(drive);
+ unsigned long long capacity_2 = capacity;
+ unsigned long long set_max_ext;
+ drive->capacity48 = 0;
drive->select.b.lba = 0;
+ if (id->cfs_enable_2 & 0x0400) {
+ capacity_2 = id->lba_capacity_2;
+ drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
+ drive->head = drive->bios_head = 255;
+ drive->sect = drive->bios_sect = 63;
+ drive->select.b.lba = 1;
+ set_max_ext = idedisk_read_native_max_address_ext(drive);
+ if (set_max_ext > capacity_2) {
+#ifdef CONFIG_IDEDISK_STROKE
+ set_max_ext = idedisk_read_native_max_address_ext(drive);
+ set_max_ext = idedisk_set_max_address_ext(drive, set_max_ext);
+ if (set_max_ext) {
+ drive->capacity48 = capacity_2 = set_max_ext;
+ drive->cyl = (unsigned int) set_max_ext / (drive->head * drive->sect);
+ drive->select.b.lba = 1;
+ drive->id->lba_capacity_2 = capacity_2;
+ }
+#else /* !CONFIG_IDEDISK_STROKE */
+ printk("%s: setmax_ext LBA %llu, native %llu\n",
+ drive->name, set_max_ext, capacity_2);
+#endif /* CONFIG_IDEDISK_STROKE */
+ }
+ drive->bios_cyl = drive->cyl;
+ drive->capacity48 = capacity_2;
+ drive->capacity = (unsigned long) capacity_2;
+ return;
/* Determine capacity, and use LBA if the drive properly supports it */
- if ((id->capability & 2) && lba_capacity_is_ok(id)) {
+ } else if ((id->capability & 2) && lba_capacity_is_ok(id)) {
capacity = id->lba_capacity;
drive->cyl = capacity / (drive->head * drive->sect);
drive->select.b.lba = 1;
}
+
+ if (set_max > capacity) {
+#ifdef CONFIG_IDEDISK_STROKE
+ set_max = idedisk_read_native_max_address(drive);
+ set_max = idedisk_set_max_address(drive, set_max);
+ if (set_max) {
+ drive->capacity = capacity = set_max;
+ drive->cyl = set_max / (drive->head * drive->sect);
+ drive->select.b.lba = 1;
+ drive->id->lba_capacity = capacity;
+ }
+#else /* !CONFIG_IDEDISK_STROKE */
+ printk("%s: setmax LBA %lu, native %lu\n",
+ drive->name, set_max, capacity);
+#endif /* CONFIG_IDEDISK_STROKE */
+ }
+
drive->capacity = capacity;
+
+ if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
+ drive->capacity48 = id->lba_capacity_2;
+ drive->head = 255;
+ drive->sect = 63;
+ drive->cyl = (unsigned long)(drive->capacity48) / (drive->head * drive->sect);
+ }
}
-static unsigned long idedisk_capacity (ide_drive_t *drive)
+static unsigned long idedisk_capacity (ide_drive_t *drive)
{
+ if (drive->id->cfs_enable_2 & 0x0400)
+ return (drive->capacity48 - drive->sect0);
return (drive->capacity - drive->sect0);
}
@@ -536,23 +612,48 @@ static ide_startstop_t idedisk_special (ide_drive_t *drive)
special_t *s = &drive->special;
if (s->b.set_geometry) {
- s->b.set_geometry = 0;
- OUT_BYTE(drive->sect,IDE_SECTOR_REG);
- OUT_BYTE(drive->cyl,IDE_LCYL_REG);
- OUT_BYTE(drive->cyl>>8,IDE_HCYL_REG);
- OUT_BYTE(((drive->head-1)|drive->select.all)&0xBF,IDE_SELECT_REG);
- if (!IS_PDC4030_DRIVE)
- ide_cmd(drive, WIN_SPECIFY, drive->sect, &set_geometry_intr);
+ struct hd_drive_task_hdr taskfile;
+ struct hd_drive_hob_hdr hobfile;
+ ide_handler_t *handler = NULL;
+
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
+ s->b.set_geometry = 0;
+ taskfile.sector_number = drive->sect;
+ taskfile.low_cylinder = drive->cyl;
+ taskfile.high_cylinder = drive->cyl>>8;
+ taskfile.device_head = ((drive->head-1)|drive->select.all)&0xBF;
+ if (!IS_PDC4030_DRIVE) {
+ taskfile.sector_count = drive->sect;
+ taskfile.command = WIN_SPECIFY;
+ handler = ide_handler_parser(&taskfile, &hobfile);
+ }
+ do_taskfile(drive, &taskfile, &hobfile, handler);
} else if (s->b.recalibrate) {
s->b.recalibrate = 0;
- if (!IS_PDC4030_DRIVE)
- ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr);
+ if (!IS_PDC4030_DRIVE) {
+ struct hd_drive_task_hdr taskfile;
+ struct hd_drive_hob_hdr hobfile;
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+ taskfile.sector_count = drive->sect;
+ taskfile.command = WIN_RESTORE;
+ do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+ }
} else if (s->b.set_multmode) {
s->b.set_multmode = 0;
if (drive->id && drive->mult_req > drive->id->max_multsect)
drive->mult_req = drive->id->max_multsect;
- if (!IS_PDC4030_DRIVE)
- ide_cmd(drive, WIN_SETMULT, drive->mult_req, &set_multmode_intr);
+ if (!IS_PDC4030_DRIVE) {
+ struct hd_drive_task_hdr taskfile;
+ struct hd_drive_hob_hdr hobfile;
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+ taskfile.sector_count = drive->mult_req;
+ taskfile.command = WIN_SETMULT;
+ do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+ }
} else if (s->all) {
int special = s->all;
s->all = 0;
@@ -564,9 +665,11 @@ static ide_startstop_t idedisk_special (ide_drive_t *drive)
static void idedisk_pre_reset (ide_drive_t *drive)
{
+ int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1;
+
drive->special.all = 0;
- drive->special.b.set_geometry = 1;
- drive->special.b.recalibrate = 1;
+ drive->special.b.set_geometry = legacy;
+ drive->special.b.recalibrate = legacy;
if (OK_TO_RESET_CONTROLLER)
drive->mult_count = 0;
if (!drive->keep_settings && !drive->using_dma)
@@ -579,19 +682,45 @@ static void idedisk_pre_reset (ide_drive_t *drive)
static int smart_enable(ide_drive_t *drive)
{
- return ide_wait_cmd(drive, WIN_SMART, 0, SMART_ENABLE, 0, NULL);
+ struct hd_drive_task_hdr taskfile;
+ struct hd_drive_hob_hdr hobfile;
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+ taskfile.feature = SMART_ENABLE;
+ taskfile.low_cylinder = SMART_LCYL_PASS;
+ taskfile.high_cylinder = SMART_HCYL_PASS;
+ taskfile.command = WIN_SMART;
+ return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
}
static int get_smart_values(ide_drive_t *drive, byte *buf)
{
+ struct hd_drive_task_hdr taskfile;
+ struct hd_drive_hob_hdr hobfile;
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+ taskfile.feature = SMART_READ_VALUES;
+ taskfile.sector_count = 0x01;
+ taskfile.low_cylinder = SMART_LCYL_PASS;
+ taskfile.high_cylinder = SMART_HCYL_PASS;
+ taskfile.command = WIN_SMART;
(void) smart_enable(drive);
- return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_VALUES, 1, buf);
+ return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
}
static int get_smart_thresholds(ide_drive_t *drive, byte *buf)
{
+ struct hd_drive_task_hdr taskfile;
+ struct hd_drive_hob_hdr hobfile;
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+ taskfile.feature = SMART_READ_THRESHOLDS;
+ taskfile.sector_count = 0x01;
+ taskfile.low_cylinder = SMART_LCYL_PASS;
+ taskfile.high_cylinder = SMART_HCYL_PASS;
+ taskfile.command = WIN_SMART;
(void) smart_enable(drive);
- return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_THRESHOLDS, 1, buf);
+ return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
}
static int proc_idedisk_read_cache
@@ -615,7 +744,7 @@ static int proc_idedisk_read_smart_thresholds
int len = 0, i = 0;
if (!get_smart_thresholds(drive, page)) {
- unsigned short *val = ((unsigned short *)page) + 2;
+ unsigned short *val = (unsigned short *) page;
char *out = ((char *)val) + (SECTOR_WORDS * 4);
page = out;
do {
@@ -634,7 +763,7 @@ static int proc_idedisk_read_smart_values
int len = 0, i = 0;
if (!get_smart_values(drive, page)) {
- unsigned short *val = ((unsigned short *)page) + 2;
+ unsigned short *val = (unsigned short *) page;
char *out = ((char *)val) + (SECTOR_WORDS * 4);
page = out;
do {
@@ -662,6 +791,21 @@ static ide_proc_entry_t idedisk_proc[] = {
static int set_multcount(ide_drive_t *drive, int arg)
{
+#if 1
+ struct hd_drive_task_hdr taskfile;
+ struct hd_drive_hob_hdr hobfile;
+
+ if (drive->special.b.set_multmode)
+ return -EBUSY;
+
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+ taskfile.sector_count = drive->mult_req;
+ taskfile.command = WIN_SETMULT;
+ drive->mult_req = arg;
+ drive->special.b.set_multmode = 1;
+ ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+#else
struct request rq;
if (drive->special.b.set_multmode)
@@ -670,6 +814,7 @@ static int set_multcount(ide_drive_t *drive, int arg)
drive->mult_req = arg;
drive->special.b.set_multmode = 1;
(void) ide_do_drive_cmd (drive, &rq, ide_wait);
+#endif
return (drive->mult_count == arg) ? 0 : -EIO;
}
@@ -683,6 +828,79 @@ static int set_nowerr(ide_drive_t *drive, int arg)
return 0;
}
+static int write_cache (ide_drive_t *drive, int arg)
+{
+ struct hd_drive_task_hdr taskfile;
+ struct hd_drive_hob_hdr hobfile;
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+ taskfile.feature = (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
+ taskfile.command = WIN_SETFEATURES;
+
+ if (!(drive->id->cfs_enable_2 & 0x3000))
+ return 1;
+
+ (void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+ drive->wcache = arg;
+ return 0;
+}
+
+static int do_idedisk_standby (ide_drive_t *drive)
+{
+ struct hd_drive_task_hdr taskfile;
+ struct hd_drive_hob_hdr hobfile;
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+ taskfile.command = WIN_STANDBYNOW1;
+ return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+}
+
+static int do_idedisk_flushcache (ide_drive_t *drive)
+{
+ struct hd_drive_task_hdr taskfile;
+ struct hd_drive_hob_hdr hobfile;
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+ if (drive->id->cfs_enable_2 & 0x2400) {
+ taskfile.command = WIN_FLUSH_CACHE_EXT;
+ } else {
+ taskfile.command = WIN_FLUSH_CACHE;
+ }
+ return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+}
+
+static int set_acoustic (ide_drive_t *drive, int arg)
+{
+ struct hd_drive_task_hdr taskfile;
+ struct hd_drive_hob_hdr hobfile;
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
+ taskfile.feature = (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM;
+ taskfile.sector_count = arg;
+
+ taskfile.command = WIN_SETFEATURES;
+ (void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+ drive->acoustic = arg;
+ return 0;
+}
+
+static int probe_lba_addressing (ide_drive_t *drive, int arg)
+{
+ drive->addressing = 0;
+
+ if (!(drive->id->cfs_enable_2 & 0x0400))
+ return -EIO;
+
+ drive->addressing = arg;
+ return 0;
+}
+
+static int set_lba_addressing (ide_drive_t *drive, int arg)
+{
+ return (probe_lba_addressing(drive, arg));
+}
+
static void idedisk_add_settings(ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -692,12 +910,15 @@ static void idedisk_add_settings(ide_drive_t *drive)
ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->bios_cyl, NULL);
ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL);
ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL);
+ ide_add_setting(drive, "address", SETTING_RW, HDIO_GET_ADDRESS, HDIO_SET_ADDRESS, TYPE_INTA, 0, 2, 1, 1, &drive->addressing, set_lba_addressing);
ide_add_setting(drive, "bswap", SETTING_READ, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->bswap, NULL);
- ide_add_setting(drive, "multcount", id ? SETTING_RW : SETTING_READ, HDIO_GET_MULTCOUNT, HDIO_SET_MULTCOUNT, TYPE_BYTE, 0, id ? id->max_multsect : 0, 1, 2, &drive->mult_count, set_multcount);
+ ide_add_setting(drive, "multcount", id ? SETTING_RW : SETTING_READ, HDIO_GET_MULTCOUNT, HDIO_SET_MULTCOUNT, TYPE_BYTE, 0, id ? id->max_multsect : 0, 1, 1, &drive->mult_count, set_multcount);
ide_add_setting(drive, "nowerr", SETTING_RW, HDIO_GET_NOWERR, HDIO_SET_NOWERR, TYPE_BYTE, 0, 1, 1, 1, &drive->nowerr, set_nowerr);
- ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL);
+ ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 1, &read_ahead[major], NULL);
ide_add_setting(drive, "file_readahead", SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, 4096, PAGE_SIZE, 1024, &max_readahead[major][minor], NULL);
ide_add_setting(drive, "lun", SETTING_RW, -1, -1, TYPE_INT, 0, 7, 1, 1, &drive->lun, NULL);
+ ide_add_setting(drive, "wcache", SETTING_RW, HDIO_GET_WCACHE, HDIO_SET_WCACHE, TYPE_BYTE, 0, 1, 1, 1, &drive->wcache, write_cache);
+ ide_add_setting(drive, "acoustic", SETTING_RW, HDIO_GET_ACOUSTIC, HDIO_SET_ACOUSTIC, TYPE_BYTE, 0, 254, 1, 1, &drive->acoustic, set_acoustic);
ide_add_setting(drive, "failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->failures, NULL);
ide_add_setting(drive, "max_failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->max_failures, NULL);
}
@@ -769,7 +990,6 @@ static void idedisk_setup (ide_drive_t *drive)
if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) &&
(!drive->forced_geom) && drive->bios_sect && drive->bios_head)
drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
-
printk (KERN_INFO "%s: %ld sectors", drive->name, capacity);
/* Give size in megabytes (MB), not mebibytes (MiB). */
@@ -801,21 +1021,25 @@ static void idedisk_setup (ide_drive_t *drive)
drive->mult_req = id->max_multsect;
if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
drive->special.b.set_multmode = 1;
-#endif
+#endif /* CONFIG_IDEDISK_MULTI_MODE */
}
drive->no_io_32bit = id->dword_io ? 1 : 0;
-}
-
-static int idedisk_reinit (ide_drive_t *drive)
-{
- return 0;
+ if (drive->id->cfs_enable_2 & 0x3000)
+ write_cache(drive, (id->cfs_enable_2 & 0x3000));
+ (void) probe_lba_addressing(drive, 1);
}
static int idedisk_cleanup (ide_drive_t *drive)
{
+ if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
+ if (do_idedisk_flushcache(drive))
+ printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
+ drive->name);
return ide_unregister_subdriver(drive);
}
+int idedisk_reinit(ide_drive_t *drive);
+
/*
* IDE subdriver functions, registered with ide.c
*/
@@ -827,6 +1051,8 @@ static ide_driver_t idedisk_driver = {
supports_dma: 1,
supports_dsc_overlap: 0,
cleanup: idedisk_cleanup,
+ standby: do_idedisk_standby,
+ flushcache: do_idedisk_flushcache,
do_request: do_rw_disk,
end_request: NULL,
ioctl: NULL,
@@ -851,6 +1077,32 @@ static ide_module_t idedisk_module = {
MODULE_DESCRIPTION("ATA DISK Driver");
+int idedisk_reinit (ide_drive_t *drive)
+{
+ int failed = 0;
+
+ MOD_INC_USE_COUNT;
+
+ if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
+ printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
+ return 1;
+ }
+ DRIVER(drive)->busy++;
+ idedisk_setup(drive);
+ if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
+ printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
+ (void) idedisk_cleanup(drive);
+ DRIVER(drive)->busy--;
+ return 1;
+ }
+ DRIVER(drive)->busy--;
+ failed--;
+
+ ide_register_module(&idedisk_module);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
static void __exit idedisk_exit (void)
{
ide_drive_t *drive;
@@ -882,12 +1134,15 @@ int idedisk_init (void)
printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
continue;
}
+ DRIVER(drive)->busy++;
idedisk_setup(drive);
if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
(void) idedisk_cleanup(drive);
+ DRIVER(drive)->busy--;
continue;
}
+ DRIVER(drive)->busy--;
failed--;
}
ide_register_module(&idedisk_module);
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index fb638ca30..3f4d4e627 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -243,6 +243,46 @@ static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq)
return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
}
+static int ide_raw_build_sglist (ide_hwif_t *hwif, struct request *rq)
+{
+ struct scatterlist *sg = hwif->sg_table;
+ int nents = 0;
+ ide_task_t *args = rq->special;
+#if 1
+ unsigned char *virt_addr = rq->buffer;
+ int sector_count = rq->nr_sectors;
+#else
+ nents = blk_rq_map_sg(rq->q, rq, hwif->sg_table);
+
+ if (nents > rq->nr_segments)
+ printk("ide-dma: received %d segments, build %d\n", rq->nr_segments, nents);
+#endif
+
+ if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
+ hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+ else
+ hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+
+#if 1
+ if (sector_count > 128) {
+ memset(&sg[nents], 0, sizeof(*sg));
+ sg[nents].page = virt_to_page(virt_addr);
+ sg[nents].offset = ((unsigned long) virt_addr & ~PAGE_MASK);
+ sg[nents].length = 128 * SECTOR_SIZE;
+ nents++;
+ virt_addr = virt_addr + (128 * SECTOR_SIZE);
+ sector_count -= 128;
+ }
+ memset(&sg[nents], 0, sizeof(*sg));
+ sg[nents].page = virt_to_page(virt_addr);
+ sg[nents].offset = ((unsigned long) virt_addr & ~PAGE_MASK);
+ sg[nents].length = sector_count * SECTOR_SIZE;
+ nents++;
+ #endif
+
+ return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
+}
+
/*
* ide_build_dmatable() prepares a dma request.
* Returns 0 if all went okay, returns 1 otherwise.
@@ -261,7 +301,11 @@ int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func)
int i;
struct scatterlist *sg;
- hwif->sg_nents = i = ide_build_sglist(hwif, HWGROUP(drive)->rq);
+ if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
+ hwif->sg_nents = i = ide_raw_build_sglist(hwif, HWGROUP(drive)->rq);
+ } else {
+ hwif->sg_nents = i = ide_build_sglist(hwif, HWGROUP(drive)->rq);
+ }
if (!i)
return 0;
@@ -387,7 +431,14 @@ int report_drive_dmaing (ide_drive_t *drive)
struct hd_driveid *id = drive->id;
if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
- (id->dma_ultra & (id->dma_ultra >> 11) & 7)) {
+ (id->dma_ultra & (id->dma_ultra >> 14) & 3)) {
+ if ((id->dma_ultra >> 15) & 1) {
+ printk(", UDMA(mode 7)"); /* UDMA BIOS-enabled! */
+ } else {
+ printk(", UDMA(133)"); /* UDMA BIOS-enabled! */
+ }
+ } else if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
+ (id->dma_ultra & (id->dma_ultra >> 11) & 7)) {
if ((id->dma_ultra >> 13) & 1) {
printk(", UDMA(100)"); /* UDMA BIOS-enabled! */
} else if ((id->dma_ultra >> 12) & 1) {
@@ -414,14 +465,24 @@ int report_drive_dmaing (ide_drive_t *drive)
static int config_drive_for_dma (ide_drive_t *drive)
{
+ int config_allows_dma = 1;
struct hd_driveid *id = drive->id;
ide_hwif_t *hwif = HWIF(drive);
- if (id && (id->capability & 1) && hwif->autodma) {
+#ifdef CONFIG_IDEDMA_ONLYDISK
+ if (drive->media != ide_disk)
+ config_allows_dma = 0;
+#endif
+
+ if (id && (id->capability & 1) && hwif->autodma && config_allows_dma) {
/* Consult the list of known "bad" drives */
if (ide_dmaproc(ide_dma_bad_drive, drive))
return hwif->dmaproc(ide_dma_off, drive);
+ /* Enable DMA on any drive that has UltraDMA (mode 6/7/?) enabled */
+ if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
+ if ((id->dma_ultra & (id->dma_ultra >> 14) & 2))
+ return hwif->dmaproc(ide_dma_on, drive);
/* Enable DMA on any drive that has UltraDMA (mode 3/4/5) enabled */
if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
if ((id->dma_ultra & (id->dma_ultra >> 11) & 7))
@@ -453,7 +514,7 @@ static int dma_timer_expiry (ide_drive_t *drive)
printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat);
#endif /* DEBUG */
-#if 1
+#if 0
HWGROUP(drive)->expiry = NULL; /* one free ride for now */
#endif
@@ -474,10 +535,10 @@ static ide_startstop_t ide_dma_timeout_revovery (ide_drive_t *drive)
unsigned long flags;
ide_startstop_t startstop;
- spin_lock_irqsave(&io_request_lock, flags);
+ spin_lock_irqsave(&ide_lock, flags);
hwgroup->handler = NULL;
del_timer(&hwgroup->timer);
- spin_unlock_irqrestore(&io_request_lock, flags);
+ spin_unlock_irqrestore(&ide_lock, flags);
drive->waiting_for_dma = 0;
@@ -555,11 +616,20 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
if (drive->media != ide_disk)
return 0;
#ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
- ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); /* issue cmd to drive */
+ ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL); /* issue cmd to drive */
#else /* !CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry); /* issue cmd to drive */
#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
- OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+ if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) &&
+ (drive->addressing == 1)) {
+ ide_task_t *args = HWGROUP(drive)->rq->special;
+ OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+ } else if (drive->addressing) {
+ OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
+ } else {
+ OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+ }
+ return HWIF(drive)->dmaproc(ide_dma_begin, drive);
case ide_dma_begin:
/* Note that this is done *after* the cmd has
* been issued to the drive, as per the BM-IDE spec.
@@ -577,7 +647,7 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0; /* verify good DMA status */
case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
dma_stat = inb(dma_base+2);
-#if 0 /* do not set unless you know what you are doing */
+#if 0 /* do not set unless you know what you are doing */
if (dma_stat & 4) {
byte stat = GET_STAT();
outb(dma_base+2, dma_stat & 0xE4);
@@ -622,6 +692,8 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
GET_STAT(), dma_stat);
return restart_request(drive); // BUG: return types do not match!!
+//#else
+// return HWGROUP(drive)->handler(drive);
#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
case ide_dma_retune:
case ide_dma_lostirq:
diff --git a/drivers/ide/ide-features.c b/drivers/ide/ide-features.c
index 80a28c963..8510e66c1 100644
--- a/drivers/ide/ide-features.c
+++ b/drivers/ide/ide-features.c
@@ -127,30 +127,14 @@ byte ide_auto_reduce_xfer (ide_drive_t *drive)
case XFER_UDMA_3: return XFER_UDMA_2;
case XFER_UDMA_2: return XFER_UDMA_1;
case XFER_UDMA_1: return XFER_UDMA_0;
+ /*
+ * OOPS we do not goto non Ultra DMA modes
+ * without iCRC's available we force
+ * the system to PIO and make the user
+ * invoke the ATA-1 ATA-2 DMA modes.
+ */
case XFER_UDMA_0:
- if (drive->id->dma_mword & 0x0004) return XFER_MW_DMA_2;
- else if (drive->id->dma_mword & 0x0002) return XFER_MW_DMA_1;
- else if (drive->id->dma_mword & 0x0001) return XFER_MW_DMA_0;
- else return XFER_PIO_4;
- case XFER_MW_DMA_2: return XFER_MW_DMA_1;
- case XFER_MW_DMA_1: return XFER_MW_DMA_0;
- case XFER_MW_DMA_0:
- if (drive->id->dma_1word & 0x0004) return XFER_SW_DMA_2;
- else if (drive->id->dma_1word & 0x0002) return XFER_SW_DMA_1;
- else if (drive->id->dma_1word & 0x0001) return XFER_SW_DMA_0;
- else return XFER_PIO_4;
- case XFER_SW_DMA_2: return XFER_SW_DMA_1;
- case XFER_SW_DMA_1: return XFER_SW_DMA_0;
- case XFER_SW_DMA_0:
- {
- return XFER_PIO_4;
- }
- case XFER_PIO_4: return XFER_PIO_3;
- case XFER_PIO_3: return XFER_PIO_2;
- case XFER_PIO_2: return XFER_PIO_1;
- case XFER_PIO_1: return XFER_PIO_0;
- case XFER_PIO_0:
- default: return XFER_PIO_SLOW;
+ default: return XFER_PIO_4;
}
}
@@ -193,7 +177,7 @@ int ide_driveid_update (ide_drive_t *drive)
__restore_flags(flags); /* local CPU only */
return 0;
}
- ide_input_data(drive, id, SECTOR_WORDS);
+ ata_input_data(drive, id, SECTOR_WORDS);
(void) GET_STAT(); /* clear drive IRQ */
ide__sti(); /* local CPU only */
__restore_flags(flags); /* local CPU only */
@@ -216,11 +200,11 @@ int ide_driveid_update (ide_drive_t *drive)
* in combination with the device (usually a disk) properly detect
* and acknowledge each end of the ribbon.
*/
-int ide_ata66_check (ide_drive_t *drive, byte cmd, byte nsect, byte feature)
+int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
{
- if ((cmd == WIN_SETFEATURES) &&
- (nsect > XFER_UDMA_2) &&
- (feature == SETFEATURES_XFER)) {
+ if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+ (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
+ (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
if (!HWIF(drive)->udma_four) {
printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", HWIF(drive)->name);
return 1;
@@ -243,11 +227,11 @@ int ide_ata66_check (ide_drive_t *drive, byte cmd, byte nsect, byte feature)
* 1 : Safe to update drive->id DMA registers.
* 0 : OOPs not allowed.
*/
-int set_transfer (ide_drive_t *drive, byte cmd, byte nsect, byte feature)
+int set_transfer (ide_drive_t *drive, ide_task_t *args)
{
- if ((cmd == WIN_SETFEATURES) &&
- (nsect >= XFER_SW_DMA_0) &&
- (feature == SETFEATURES_XFER) &&
+ if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+ (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
+ (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
(drive->id->dma_ultra ||
drive->id->dma_mword ||
drive->id->dma_1word))
@@ -389,3 +373,4 @@ EXPORT_SYMBOL(ide_ata66_check);
EXPORT_SYMBOL(set_transfer);
EXPORT_SYMBOL(eighty_ninty_three);
EXPORT_SYMBOL(ide_config_drive_speed);
+
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index ca55f3b18..07e5e8260 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -71,9 +71,14 @@
* including set_bit patch from Rusty Russel
* Ver 0.97 Jul 22 01 Merge 0.91-0.96 onto 0.9.sv for ac series
* Ver 0.97.sv Aug 3 01 Backported from 2.4.7-ac3
+ * Ver 0.98 Oct 26 01 Split idefloppy_transfer_pc into two pieces to
+ * fix a lost interrupt problem. It appears the busy
+ * bit was being deasserted by my IOMEGA ATAPI ZIP 100
+ * drive before the drive was actually ready.
+ * Ver 0.98a Oct 29 01 Expose delay value so we can play.
*/
-#define IDEFLOPPY_VERSION "0.97.sv"
+#define IDEFLOPPY_VERSION "0.98a"
#include <linux/config.h>
#include <linux/module.h>
@@ -276,6 +281,7 @@ typedef struct {
* Last error information
*/
byte sense_key, asc, ascq;
+ byte ticks; /* delay this long before sending packet command */
int progress_indication;
/*
@@ -289,6 +295,8 @@ typedef struct {
unsigned long flags; /* Status/Action flags */
} idefloppy_floppy_t;
+#define IDEFLOPPY_TICKS_DELAY 3 /* default delay for ZIP 100 */
+
/*
* Floppy flag bits values.
*/
@@ -297,7 +305,7 @@ typedef struct {
#define IDEFLOPPY_USE_READ12 2 /* Use READ12/WRITE12 or READ10/WRITE10 */
#define IDEFLOPPY_FORMAT_IN_PROGRESS 3 /* Format in progress */
#define IDEFLOPPY_CLIK_DRIVE 4 /* Avoid commands not supported in Clik drive */
-
+#define IDEFLOPPY_ZIP_DRIVE 5 /* Requires BH algorithm for packets */
/*
* ATAPI floppy drive packet commands
@@ -985,6 +993,11 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
return ide_started;
}
+/*
+ * This is the original routine that did the packet transfer.
+ * It fails at high speeds on the Iomega ZIP drive, so there's a slower version
+ * for that drive below. The algorithm is chosen based on drive type
+ */
static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
{
ide_startstop_t startstop;
@@ -1005,6 +1018,56 @@ static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
return ide_started;
}
+
+/*
+ * What we have here is a classic case of a top half / bottom half
+ * interrupt service routine. In interrupt mode, the device sends
+ * an interrupt to signal it's ready to receive a packet. However,
+ * we need to delay about 2-3 ticks before issuing the packet or we
+ * gets in trouble.
+ *
+ * So, follow carefully. transfer_pc1 is called as an interrupt (or
+ * directly). In either case, when the device says it's ready for a
+ * packet, we schedule the packet transfer to occur about 2-3 ticks
+ * later in transfer_pc2.
+ */
+static int idefloppy_transfer_pc2 (ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+
+ atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
+ return IDEFLOPPY_WAIT_CMD; /* Timeout for the packet command */
+}
+
+static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+ ide_startstop_t startstop;
+ idefloppy_ireason_reg_t ireason;
+
+ if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+ printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n");
+ return startstop;
+ }
+ ireason.all=IN_BYTE (IDE_IREASON_REG);
+ if (!ireason.b.cod || ireason.b.io) {
+ printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
+ return ide_do_reset (drive);
+ }
+ /*
+ * The following delay solves a problem with ATAPI Zip 100 drives where the
+ * Busy flag was apparently being deasserted before the unit was ready to
+ * receive data. This was happening on a 1200 MHz Athlon system. 10/26/01
+ * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will
+ * not be actually used until after the packet is moved in about 50 msec.
+ */
+ ide_set_handler (drive,
+ &idefloppy_pc_intr, /* service routine for packet command */
+ floppy->ticks, /* wait this long before "failing" */
+ &idefloppy_transfer_pc2); /* fail == transfer_pc2 */
+ return ide_started;
+}
+
/*
* Issue a packet command
*/
@@ -1013,6 +1076,7 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
idefloppy_floppy_t *floppy = drive->driver_data;
idefloppy_bcount_reg_t bcount;
int dma_ok = 0;
+ ide_handler_t *pkt_xfer_routine;
#if IDEFLOPPY_DEBUG_BUGS
if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD && pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
@@ -1072,13 +1136,20 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
+ /* Can we transfer the packet when we get the interrupt or wait? */
+ if (test_bit (IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) {
+ pkt_xfer_routine = &idefloppy_transfer_pc1; /* wait */
+ } else {
+ pkt_xfer_routine = &idefloppy_transfer_pc; /* immediate */
+ }
+
if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
- ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD, NULL);
+ ide_set_handler (drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */
return ide_started;
} else {
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
- return idefloppy_transfer_pc (drive);
+ return (*pkt_xfer_routine) (drive);
}
}
@@ -1979,10 +2050,7 @@ static ide_proc_entry_t idefloppy_proc[] = {
#endif /* CONFIG_PROC_FS */
-static int idefloppy_reinit (ide_drive_t *drive)
-{
- return 0;
-}
+int idefloppy_reinit(ide_drive_t *drive);
/*
* IDE subdriver functions, registered with ide.c
@@ -1995,6 +2063,8 @@ static ide_driver_t idefloppy_driver = {
supports_dma: 1,
supports_dsc_overlap: 0,
cleanup: idefloppy_cleanup,
+ standby: NULL,
+ flushcache: NULL,
do_request: idefloppy_do_request,
end_request: idefloppy_end_request,
ioctl: idefloppy_ioctl,
@@ -2017,6 +2087,40 @@ static ide_module_t idefloppy_module = {
NULL
};
+int idefloppy_reinit (ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy;
+ int failed = 0;
+
+ MOD_INC_USE_COUNT;
+ while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) {
+ if (!idefloppy_identify_device (drive, drive->id)) {
+ printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
+ continue;
+ }
+ if (drive->scsi) {
+ printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
+ continue;
+ }
+ if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
+ printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
+ continue;
+ }
+ if (ide_register_subdriver (drive, &idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
+ printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
+ kfree (floppy);
+ continue;
+ }
+ DRIVER(drive)->busy++;
+ idefloppy_setup (drive, floppy);
+ DRIVER(drive)->busy--;
+ failed--;
+ }
+ ide_register_module(&idefloppy_module);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
static void __exit idefloppy_exit (void)
@@ -2069,7 +2173,9 @@ int idefloppy_init (void)
kfree (floppy);
continue;
}
+ DRIVER(drive)->busy++;
idefloppy_setup (drive, floppy);
+ DRIVER(drive)->busy--;
failed--;
}
ide_register_module(&idefloppy_module);
diff --git a/drivers/ide/ide-geometry.c b/drivers/ide/ide-geometry.c
index ce26d65f0..5f21651c1 100644
--- a/drivers/ide/ide-geometry.c
+++ b/drivers/ide/ide-geometry.c
@@ -6,6 +6,8 @@
#include <linux/mc146818rtc.h>
#include <asm/io.h>
+#ifdef CONFIG_BLK_DEV_IDE
+
/*
* We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
* controller that is BIOS compatible with ST-506, and thus showing up in our
@@ -40,7 +42,11 @@
* Consequently, also the former "drive->present = 1" below was a mistake.
*
* Eventually the entire routine below should be removed.
+ *
+ * 17-OCT-2000 rjohnson@analogic.com Added spin-locks for reading CMOS
+ * chip.
*/
+
void probe_cmos_for_drives (ide_hwif_t *hwif)
{
#ifdef __i386__
@@ -80,9 +86,10 @@ void probe_cmos_for_drives (ide_hwif_t *hwif)
}
#endif
}
+#endif /* CONFIG_BLK_DEV_IDE */
-#ifdef CONFIG_BLK_DEV_IDE
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
extern ide_drive_t * get_info_ptr(kdev_t);
extern unsigned long current_capacity (ide_drive_t *);
@@ -214,4 +221,4 @@ int ide_xlate_1024 (kdev_t i_rdev, int xparm, int ptheads, const char *msg)
drive->bios_cyl, drive->bios_head, drive->bios_sect);
return ret;
}
-#endif /* CONFIG_BLK_DEV_IDE */
+#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
diff --git a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c
index e75d36b28..d6cae3ffb 100644
--- a/drivers/ide/ide-pci.c
+++ b/drivers/ide/ide-pci.c
@@ -12,6 +12,13 @@
* configuration of all PCI IDE interfaces present in a system.
*/
+/*
+ * Chipsets that are on the IDE_IGNORE list because of problems of not being
+ * set at compile time.
+ *
+ * CONFIG_BLK_DEV_PDC202XX
+ */
+
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -47,6 +54,8 @@
#define DEVID_PDC20267 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267})
#define DEVID_PDC20268 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268})
#define DEVID_PDC20268R ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268R})
+#define DEVID_PDC20269 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269})
+#define DEVID_PDC20275 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275})
#define DEVID_RZ1000 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000})
#define DEVID_RZ1001 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001})
#define DEVID_SAMURAI ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE})
@@ -55,6 +64,7 @@
#define DEVID_CMD646 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646})
#define DEVID_CMD648 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648})
#define DEVID_CMD649 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649})
+#define DEVID_CMD680 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_680})
#define DEVID_SIS5513 ((ide_pci_devid_t){PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513})
#define DEVID_OPTI621 ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621})
#define DEVID_OPTI621V ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558})
@@ -87,6 +97,7 @@
#define DEVID_ITE8172G ((ide_pci_devid_t){PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G})
#define IDE_IGNORE ((void *)-1)
+#define IDE_NO_DRIVER ((void *)-2)
#ifdef CONFIG_BLK_DEV_AEC62XX
extern unsigned int pci_init_aec62xx(struct pci_dev *, const char *);
@@ -100,7 +111,7 @@ extern void ide_dmacapable_aec62xx(ide_hwif_t *, unsigned long);
#else
#define PCI_AEC62XX NULL
#define ATA66_AEC62XX NULL
-#define INIT_AEC62XX NULL
+#define INIT_AEC62XX IDE_NO_DRIVER
#define DMA_AEC62XX NULL
#endif
@@ -116,7 +127,7 @@ extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long);
#else
#define PCI_ALI15X3 NULL
#define ATA66_ALI15X3 NULL
-#define INIT_ALI15X3 NULL
+#define INIT_ALI15X3 IDE_NO_DRIVER
#define DMA_ALI15X3 NULL
#endif
@@ -132,7 +143,7 @@ extern void ide_dmacapable_amd74xx(ide_hwif_t *, unsigned long);
#else
#define PCI_AMD74XX NULL
#define ATA66_AMD74XX NULL
-#define INIT_AMD74XX NULL
+#define INIT_AMD74XX IDE_NO_DRIVER
#define DMA_AMD74XX NULL
#endif
@@ -150,7 +161,7 @@ extern void ide_dmacapable_cmd64x(ide_hwif_t *, unsigned long);
#ifdef __sparc_v9__
#define INIT_CMD64X IDE_IGNORE
#else
-#define INIT_CMD64X NULL
+#define INIT_CMD64X IDE_NO_DRIVER
#endif
#endif
@@ -161,7 +172,7 @@ extern void ide_init_cy82c693(ide_hwif_t *);
#define INIT_CY82C693 &ide_init_cy82c693
#else
#define PCI_CY82C693 NULL
-#define INIT_CY82C693 NULL
+#define INIT_CY82C693 IDE_NO_DRIVER
#endif
#ifdef CONFIG_BLK_DEV_CS5530
@@ -171,7 +182,7 @@ extern void ide_init_cs5530(ide_hwif_t *);
#define INIT_CS5530 &ide_init_cs5530
#else
#define PCI_CS5530 NULL
-#define INIT_CS5530 NULL
+#define INIT_CS5530 IDE_NO_DRIVER
#endif
#ifdef CONFIG_BLK_DEV_HPT34X
@@ -200,7 +211,7 @@ static byte hpt363_shared_irq;
static byte hpt363_shared_pin;
#define PCI_HPT366 NULL
#define ATA66_HPT366 NULL
-#define INIT_HPT366 NULL
+#define INIT_HPT366 IDE_NO_DRIVER
#define DMA_HPT366 NULL
#endif
@@ -215,7 +226,7 @@ extern void ide_init_ns87415(ide_hwif_t *);
extern void ide_init_opti621(ide_hwif_t *);
#define INIT_OPTI621 &ide_init_opti621
#else
-#define INIT_OPTI621 NULL
+#define INIT_OPTI621 IDE_NO_DRIVER
#endif
#ifdef CONFIG_BLK_DEV_PDC_ADMA
@@ -242,9 +253,9 @@ extern void ide_init_pdc202xx(ide_hwif_t *);
#define ATA66_PDC202XX &ata66_pdc202xx
#define INIT_PDC202XX &ide_init_pdc202xx
#else
-#define PCI_PDC202XX NULL
-#define ATA66_PDC202XX NULL
-#define INIT_PDC202XX NULL
+#define PCI_PDC202XX IDE_IGNORE
+#define ATA66_PDC202XX IDE_IGNORE
+#define INIT_PDC202XX IDE_IGNORE
#endif
#ifdef CONFIG_BLK_DEV_PIIX
@@ -257,7 +268,7 @@ extern void ide_init_piix(ide_hwif_t *);
#else
#define PCI_PIIX NULL
#define ATA66_PIIX NULL
-#define INIT_PIIX NULL
+#define INIT_PIIX IDE_NO_DRIVER
#endif
#ifdef CONFIG_BLK_DEV_IT8172
@@ -269,7 +280,7 @@ extern void ide_init_it8172(ide_hwif_t *);
#else
#define PCI_IT8172 NULL
#define ATA66_IT8172 NULL
-#define INIT_IT8172 NULL
+#define INIT_IT8172 IDE_NO_DRIVER
#endif
#ifdef CONFIG_BLK_DEV_RZ1000
@@ -291,7 +302,7 @@ extern void ide_init_svwks(ide_hwif_t *);
#else
#define PCI_SVWKS NULL
#define ATA66_SVWKS NULL
-#define INIT_SVWKS NULL
+#define INIT_SVWKS IDE_NO_DRIVER
#endif
#ifdef CONFIG_BLK_DEV_SIS5513
@@ -304,7 +315,7 @@ extern void ide_init_sis5513(ide_hwif_t *);
#else
#define PCI_SIS5513 NULL
#define ATA66_SIS5513 NULL
-#define INIT_SIS5513 NULL
+#define INIT_SIS5513 IDE_NO_DRIVER
#endif
#ifdef CONFIG_BLK_DEV_SLC90E66
@@ -317,7 +328,7 @@ extern void ide_init_slc90e66(ide_hwif_t *);
#else
#define PCI_SLC90E66 NULL
#define ATA66_SLC90E66 NULL
-#define INIT_SLC90E66 NULL
+#define INIT_SLC90E66 IDE_NO_DRIVER
#endif
#ifdef CONFIG_BLK_DEV_SL82C105
@@ -352,7 +363,7 @@ extern void ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long);
#else
#define PCI_VIA82CXXX NULL
#define ATA66_VIA82CXXX NULL
-#define INIT_VIA82CXXX NULL
+#define INIT_VIA82CXXX IDE_NO_DRIVER
#define DMA_VIA82CXXX NULL
#endif
@@ -394,7 +405,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
#ifdef CONFIG_PDC202XX_FORCE
{DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 16 },
{DEVID_PDC20262,"PDC20262", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48 },
- {DEVID_PDC20265,"PDC20265", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48 },
+ {DEVID_PDC20265,"PDC20265", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 48 },
{DEVID_PDC20267,"PDC20267", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48 },
#else /* !CONFIG_PDC202XX_FORCE */
{DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 },
@@ -402,11 +413,13 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
{DEVID_PDC20265,"PDC20265", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 },
{DEVID_PDC20267,"PDC20267", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 },
#endif
- {DEVID_PDC20268,"PDC20268", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 16 },
+ {DEVID_PDC20268,"PDC20268", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 },
/* Promise used a different PCI ident for the raid card apparently to try and
prevent Linux detecting it and using our own raid code. We want to detect
it for the ataraid drivers, so we have to list both here.. */
- {DEVID_PDC20268R,"PDC20268", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 16 },
+ {DEVID_PDC20268R,"PDC20270", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 },
+ {DEVID_PDC20269,"PDC20269", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 },
+ {DEVID_PDC20275,"PDC20275", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 },
{DEVID_RZ1000, "RZ1000", NULL, NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
{DEVID_RZ1001, "RZ1001", NULL, NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
{DEVID_SAMURAI, "SAMURAI", NULL, NULL, INIT_SAMURAI, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
@@ -417,6 +430,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
{DEVID_CMD646, "CMD646", PCI_CMD64X, NULL, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0 },
{DEVID_CMD648, "CMD648", PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
{DEVID_CMD649, "CMD649", PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_CMD680, "CMD680", PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
{DEVID_HT6565, "HT6565", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
{DEVID_OPTI621, "OPTI621", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 },
{DEVID_OPTI621X,"OPTI621X", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 },
@@ -435,10 +449,10 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
{DEVID_CY82C693,"CY82C693", PCI_CY82C693, NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
{DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
{DEVID_CS5530, "CS5530", PCI_CS5530, NULL, INIT_CS5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
- {DEVID_AMD7401, "AMD7401", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_AMD7401, "AMD7401", NULL, NULL, NULL, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 },
{DEVID_AMD7409, "AMD7409", PCI_AMD74XX, ATA66_AMD74XX, INIT_AMD74XX, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 },
{DEVID_AMD7411, "AMD7411", PCI_AMD74XX, ATA66_AMD74XX, INIT_AMD74XX, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 },
- {DEVID_AMD7441, "AMD7441", PCI_AMD74XX, ATA66_AMD74XX, INIT_AMD74XX, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 },
+ {DEVID_AMD7441, "AMD7441", PCI_AMD74XX, ATA66_AMD74XX, INIT_AMD74XX, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 },
{DEVID_PDCADMA, "PDCADMA", PCI_PDCADMA, ATA66_PDCADMA, INIT_PDCADMA, DMA_PDCADMA, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 },
{DEVID_SLC90E66,"SLC90E66", PCI_SLC90E66, ATA66_SLC90E66, INIT_SLC90E66, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 },
{DEVID_OSB4, "ServerWorks OSB4", PCI_SVWKS, ATA66_SVWKS, INIT_SVWKS, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
@@ -460,6 +474,9 @@ static unsigned int __init ide_special_settings (struct pci_dev *dev, const char
case PCI_DEVICE_ID_PROMISE_20265:
case PCI_DEVICE_ID_PROMISE_20267:
case PCI_DEVICE_ID_PROMISE_20268:
+ case PCI_DEVICE_ID_PROMISE_20268R:
+ case PCI_DEVICE_ID_PROMISE_20269:
+ case PCI_DEVICE_ID_PROMISE_20275:
case PCI_DEVICE_ID_ARTOP_ATP850UF:
case PCI_DEVICE_ID_ARTOP_ATP860:
case PCI_DEVICE_ID_ARTOP_ATP860R:
@@ -594,7 +611,15 @@ static void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *
autodma = 1;
#endif
- pci_enable_device(dev);
+ if (d->init_hwif == IDE_NO_DRIVER) {
+ printk(KERN_WARNING "%s: detected chipset, but driver not compiled in!\n", d->name);
+ d->init_hwif = NULL;
+ }
+
+ if (pci_enable_device(dev)) {
+ printk(KERN_WARNING "%s: (ide_setup_pci_device:) Could not enable device.\n", d->name);
+ return;
+ }
check_if_enabled:
if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
@@ -754,7 +779,8 @@ controller_ok:
}
if (IDE_PCI_DEVID_EQ(d->devid, DEVID_MPIIX))
goto bypass_piix_dma;
-
+ if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDCADMA))
+ goto bypass_legacy_dma;
if (hwif->udma_four) {
printk("%s: ATA-66/100 forced bit set (WARNING)!!\n", d->name);
} else {
@@ -771,12 +797,15 @@ controller_ok:
autodma = 0;
if (autodma)
hwif->autodma = 1;
+
if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20267) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R) ||
+ IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20269) ||
+ IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20275) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) ||
@@ -787,6 +816,7 @@ controller_ok:
IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD646) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD648) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD649) ||
+ IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD680) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_OSB4) ||
((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) {
unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name);
@@ -813,6 +843,7 @@ controller_ok:
}
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
+bypass_legacy_dma:
bypass_piix_dma:
bypass_umc_dma:
if (d->init_hwif) /* Call chipset-specific routine for each enabled hwif */
@@ -824,6 +855,44 @@ bypass_umc_dma:
printk("%s: neither IDE port enabled (BIOS)\n", d->name);
}
+static void __init pdc20270_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
+{
+ struct pci_dev *dev2 = NULL, *findev;
+ ide_pci_device_t *d2;
+
+ if ((dev->bus->self &&
+ dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
+ (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
+ if (PCI_SLOT(dev->devfn) & 2) {
+ return;
+ }
+ d->extra = 0;
+ pci_for_each_dev(findev) {
+ if ((findev->vendor == dev->vendor) &&
+ (findev->device == dev->device) &&
+ (PCI_SLOT(findev->devfn) & 2)) {
+ byte irq = 0, irq2 = 0;
+ dev2 = findev;
+ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+ pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2);
+ if (irq != irq2) {
+ dev2->irq = dev->irq;
+ pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq);
+ }
+
+ }
+ }
+ }
+
+ printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
+ ide_setup_pci_device(dev, d);
+ if (!dev2)
+ return;
+ d2 = d;
+ printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn);
+ ide_setup_pci_device(dev2, d2);
+}
+
static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
{
struct pci_dev *dev2 = NULL, *findev;
@@ -904,6 +973,8 @@ void __init ide_scan_pcidev (struct pci_dev *dev)
return; /* UM8886A/BF pair */
else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366))
hpt366_device_order_fixup(dev, d);
+ else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R))
+ pdc20270_device_order_fixup(dev, d);
else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL))
printk("%s: unknown IDE controller on PCI slot %s, VID=%04x, DID=%04x\n",
diff --git a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c
index af7603af9..25987c77e 100644
--- a/drivers/ide/ide-pmac.c
+++ b/drivers/ide/ide-pmac.c
@@ -1101,7 +1101,7 @@ static void idepmac_wake_device(ide_drive_t *drive, int used_dma)
HWGROUP(drive)->busy = 1;
pmac_ide_check_dma(drive);
HWGROUP(drive)->busy = 0;
- spin_unlock_irq(&io_request_lock);
+ spin_unlock_irq(&ide_lock);
}
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
}
@@ -1220,7 +1220,7 @@ static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
/* Disable irq during sleep */
disable_irq(pmac_ide[i].irq);
if (unlock)
- spin_unlock_irq(&io_request_lock);
+ spin_unlock_irq(&ide_lock);
/* Check if this is a media bay with an IDE device or not
* a media bay.
@@ -1279,11 +1279,11 @@ static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
drive->using_dma = 0;
/* We resume processing on the HW group */
- spin_lock_irqsave(&io_request_lock, flags);
+ spin_lock_irqsave(&ide_lock, flags);
enable_irq(pmac_ide[i].irq);
if (drive->present)
HWGROUP(drive)->busy = 0;
- spin_unlock_irqrestore(&io_request_lock, flags);
+ spin_unlock_irqrestore(&ide_lock, flags);
/* Wake the device
* We could handle the slave here
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index abdfccd98..7a8141b7c 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -58,7 +58,22 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
struct hd_driveid *id;
id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_ATOMIC); /* called with interrupts disabled! */
- ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */
+ if (!id) {
+ printk(KERN_WARNING "(ide-probe::do_identify) Out of memory.\n");
+ goto err_kmalloc;
+ }
+ /* read 512 bytes of id info */
+#if 1
+ ata_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */
+#else
+ {
+ unsigned long *ptr = (unsigned long *)id ;
+ unsigned long lcount = 256/2 ;
+ // printk("IDE_DATA_REG = %#lx",IDE_DATA_REG);
+ while( lcount-- )
+ *ptr++ = inl(IDE_DATA_REG);
+ }
+#endif
ide__sti(); /* local CPU only */
ide_fix_driveid(id);
@@ -76,8 +91,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
if ((id->model[0] == 'P' && id->model[1] == 'M')
|| (id->model[0] == 'S' && id->model[1] == 'K')) {
printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);
- drive->present = 0;
- return;
+ goto err_misc;
}
#endif /* CONFIG_SCSI_EATA_DMA || CONFIG_SCSI_EATA_PIO */
@@ -96,7 +110,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
if (strstr(id->model, "E X A B Y T E N E S T"))
- return;
+ goto err_misc;
id->model[sizeof(id->model)-1] = '\0'; /* we depend on this a lot! */
printk("%s: %s, ", drive->name, id->model);
@@ -111,8 +125,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
#ifdef CONFIG_BLK_DEV_PDC4030
if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) {
printk(" -- not supported on 2nd Promise port\n");
- drive->present = 0;
- return;
+ goto err_misc;
}
#endif /* CONFIG_BLK_DEV_PDC4030 */
switch (type) {
@@ -174,6 +187,12 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
printk("ATA DISK drive\n");
QUIRK_LIST(HWIF(drive),drive);
return;
+
+err_misc:
+ kfree(id);
+err_kmalloc:
+ drive->present = 0;
+ return;
}
/*
@@ -702,6 +721,10 @@ static int init_irq (ide_hwif_t *hwif)
#else /* !CONFIG_IDEPCI_SHARE_IRQ */
int sa = IDE_CHIPSET_IS_PCI(hwif->chipset) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT;
#endif /* CONFIG_IDEPCI_SHARE_IRQ */
+
+ if (hwif->io_ports[IDE_CONTROL_OFFSET])
+ OUT_BYTE(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]); /* clear nIEN */
+
if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) {
if (!match)
kfree(hwgroup);
@@ -769,17 +792,32 @@ static void init_gendisk (ide_hwif_t *hwif)
int *bs, *max_ra;
extern devfs_handle_t ide_devfs_handle;
+#if 1
+ units = MAX_DRIVES;
+#else
/* figure out maximum drive number on the interface */
for (units = MAX_DRIVES; units > 0; --units) {
if (hwif->drives[units-1].present)
break;
}
+#endif
+
minors = units * (1<<PARTN_BITS);
gd = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
+ if (!gd)
+ goto err_kmalloc_gd;
gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
+ if (!gd->sizes)
+ goto err_kmalloc_gd_sizes;
gd->part = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
+ if (!gd->part)
+ goto err_kmalloc_gd_part;
bs = kmalloc (minors*sizeof(int), GFP_KERNEL);
+ if (!bs)
+ goto err_kmalloc_bs;
max_ra = kmalloc (minors*sizeof(int), GFP_KERNEL);
+ if (!max_ra)
+ goto err_kmalloc_max_ra;
memset(gd->part, 0, minors * sizeof(struct hd_struct));
@@ -811,6 +849,17 @@ static void init_gendisk (ide_hwif_t *hwif)
add_gendisk(gd);
for (unit = 0; unit < units; ++unit) {
+#if 1
+ char name[64];
+ ide_add_generic_settings(hwif->drives + unit);
+ hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
+ sprintf (name, "host%d/bus%d/target%d/lun%d",
+ (hwif->channel && hwif->mate) ?
+ hwif->mate->index : hwif->index,
+ hwif->channel, unit, hwif->drives[unit].lun);
+ if (hwif->drives[unit].present)
+ hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
+#else
if (hwif->drives[unit].present) {
char name[64];
@@ -822,7 +871,21 @@ static void init_gendisk (ide_hwif_t *hwif)
hwif->drives[unit].de =
devfs_mk_dir (ide_devfs_handle, name, NULL);
}
+#endif
}
+ return;
+
+err_kmalloc_max_ra:
+ kfree(bs);
+err_kmalloc_bs:
+ kfree(gd->part);
+err_kmalloc_gd_part:
+ kfree(gd->sizes);
+err_kmalloc_gd_sizes:
+ kfree(gd);
+err_kmalloc_gd:
+ printk(KERN_WARNING "(ide::init_gendisk) Out of memory\n");
+ return;
}
static int hwif_init (ide_hwif_t *hwif)
@@ -880,6 +943,19 @@ static int hwif_init (ide_hwif_t *hwif)
return hwif->present;
}
+void export_ide_init_queue (ide_drive_t *drive)
+{
+ ide_init_queue(drive);
+}
+
+byte export_probe_for_drive (ide_drive_t *drive)
+{
+ return probe_for_drive(drive);
+}
+
+EXPORT_SYMBOL(export_ide_init_queue);
+EXPORT_SYMBOL(export_probe_for_drive);
+
int ideprobe_init (void);
static ide_module_t ideprobe_module = {
IDE_PROBE_MODULE,
@@ -913,6 +989,8 @@ int ideprobe_init (void)
}
#ifdef MODULE
+extern int (*ide_xlate_1024_hook)(kdev_t, int, int, const char *);
+
int init_module (void)
{
unsigned int index;
@@ -921,12 +999,14 @@ int init_module (void)
ide_unregister(index);
ideprobe_init();
create_proc_ide_interfaces();
+ ide_xlate_1024_hook = ide_xlate_1024;
return 0;
}
void cleanup_module (void)
{
ide_probe = NULL;
+ ide_xlate_1024_hook = 0;
}
MODULE_LICENSE("GPL");
#endif /* MODULE */
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index 4c905cf0f..82dd2704b 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -65,6 +65,7 @@
#include <linux/mm.h>
#include <linux/pci.h>
#include <linux/ctype.h>
+#include <linux/hdreg.h>
#include <linux/ide.h>
#include <asm/io.h>
@@ -447,7 +448,15 @@ static int proc_ide_read_channel
static int proc_ide_get_identify(ide_drive_t *drive, byte *buf)
{
- return ide_wait_cmd(drive, (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY, 0, 0, 1, buf);
+ struct hd_drive_task_hdr taskfile;
+ struct hd_drive_hob_hdr hobfile;
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
+ taskfile.sector_count = 0x01;
+ taskfile.command = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY ;
+
+ return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
}
static int proc_ide_read_identify
@@ -457,7 +466,7 @@ static int proc_ide_read_identify
int len = 0, i = 0;
if (drive && !proc_ide_get_identify(drive, page)) {
- unsigned short *val = ((unsigned short *)page) + 2;
+ unsigned short *val = (unsigned short *) page;
char *out = ((char *)val) + (SECTOR_WORDS * 4);
page = out;
do {
@@ -588,7 +597,7 @@ int proc_ide_read_capacity
if (!driver)
len = sprintf(page, "(none)\n");
else
- len = sprintf(page,"%li\n", ((ide_driver_t *)drive->driver)->capacity(drive));
+ len = sprintf(page,"%llu\n", (unsigned long long) ((ide_driver_t *)drive->driver)->capacity(drive));
PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
}
@@ -732,16 +741,38 @@ static void create_proc_ide_drives(ide_hwif_t *hwif)
}
}
-void destroy_proc_ide_drives(ide_hwif_t *hwif)
+void recreate_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
{
- int d;
+ struct proc_dir_entry *ent;
+ struct proc_dir_entry *parent = hwif->proc;
+ char name[64];
+// ide_driver_t *driver = drive->driver;
- for (d = 0; d < MAX_DRIVES; d++) {
- ide_drive_t *drive = &hwif->drives[d];
- ide_driver_t *driver = drive->driver;
+ if (drive->present && !drive->proc) {
+ drive->proc = proc_mkdir(drive->name, parent);
+ if (drive->proc)
+ ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
- if (!drive->proc)
- continue;
+/*
+ * assume that we have these already, however, should test FIXME!
+ * if (driver) {
+ * ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
+ * ide_add_proc_entries(drive->proc, driver->proc, drive);
+ * }
+ *
+ */
+ sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name);
+ ent = proc_symlink(drive->name, proc_ide_root, name);
+ if (!ent)
+ return;
+ }
+}
+
+void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
+{
+ ide_driver_t *driver = drive->driver;
+
+ if (drive->proc) {
if (driver)
ide_remove_proc_entries(drive->proc, driver->proc);
ide_remove_proc_entries(drive->proc, generic_drive_entries);
@@ -751,6 +782,19 @@ void destroy_proc_ide_drives(ide_hwif_t *hwif)
}
}
+void destroy_proc_ide_drives(ide_hwif_t *hwif)
+{
+ int d;
+
+ for (d = 0; d < MAX_DRIVES; d++) {
+ ide_drive_t *drive = &hwif->drives[d];
+// ide_driver_t *driver = drive->driver;
+
+ if (drive->proc)
+ destroy_proc_ide_device(hwif, drive);
+ }
+}
+
static ide_proc_entry_t hwif_entries[] = {
{ "channel", S_IFREG|S_IRUGO, proc_ide_read_channel, NULL },
{ "config", S_IFREG|S_IRUGO|S_IWUSR,proc_ide_read_config, proc_ide_write_config },
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 6460e3387..4828e49f9 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -6130,10 +6130,7 @@ static ide_proc_entry_t idetape_proc[] = {
#endif
-static int idetape_reinit (ide_drive_t *drive)
-{
- return 0;
-}
+int idetape_reinit(ide_drive_t *drive);
/*
* IDE subdriver functions, registered with ide.c
@@ -6146,6 +6143,8 @@ static ide_driver_t idetape_driver = {
supports_dma: 1,
supports_dsc_overlap: 1,
cleanup: idetape_cleanup,
+ standby: NULL,
+ flushcache: NULL,
do_request: idetape_do_request,
end_request: idetape_end_request,
ioctl: idetape_blkdev_ioctl,
@@ -6179,6 +6178,92 @@ static struct file_operations idetape_fops = {
release: idetape_chrdev_release,
};
+int idetape_reinit (ide_drive_t *drive)
+{
+#if 0
+ idetape_tape_t *tape;
+ int minor, failed = 0, supported = 0;
+/* DRIVER(drive)->busy++; */
+ MOD_INC_USE_COUNT;
+#if ONSTREAM_DEBUG
+ printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
+#endif
+ if (!idetape_chrdev_present)
+ for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
+ idetape_chrdevs[minor].drive = NULL;
+
+ if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) {
+ ide_register_module (&idetape_module);
+ MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+ printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
+ return 0;
+ }
+ if (!idetape_chrdev_present &&
+ devfs_register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
+ printk (KERN_ERR "ide-tape: Failed to register character device interface\n");
+ MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+ printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
+ return -EBUSY;
+ }
+ do {
+ if (!idetape_identify_device (drive, drive->id)) {
+ printk (KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
+ continue;
+ }
+ if (drive->scsi) {
+ if (strstr(drive->id->model, "OnStream DI-30")) {
+ printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model);
+ } else {
+ printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
+ continue;
+ }
+ }
+ tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
+ if (tape == NULL) {
+ printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
+ continue;
+ }
+ if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) {
+ printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
+ kfree (tape);
+ continue;
+ }
+ for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
+ idetape_setup (drive, tape, minor);
+ idetape_chrdevs[minor].drive = drive;
+ tape->de_r =
+ devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
+ HWIF(drive)->major, minor,
+ S_IFCHR | S_IRUGO | S_IWUGO,
+ &idetape_fops, NULL);
+ tape->de_n =
+ devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
+ HWIF(drive)->major, minor + 128,
+ S_IFCHR | S_IRUGO | S_IWUGO,
+ &idetape_fops, NULL);
+ devfs_register_tape (tape->de_r);
+ supported++; failed--;
+ } while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL);
+ if (!idetape_chrdev_present && !supported) {
+ devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
+ } else
+ idetape_chrdev_present = 1;
+ ide_register_module (&idetape_module);
+ MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+ printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
+
+ return 0;
+#else
+ return 1;
+#endif
+}
+
MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
MODULE_LICENSE("GPL");
@@ -6203,7 +6288,7 @@ int idetape_init (void)
ide_drive_t *drive;
idetape_tape_t *tape;
int minor, failed = 0, supported = 0;
-
+/* DRIVER(drive)->busy++; */
MOD_INC_USE_COUNT;
#if ONSTREAM_DEBUG
printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
new file mode 100644
index 000000000..b47951259
--- /dev/null
+++ b/drivers/ide/ide-taskfile.c
@@ -0,0 +1,1824 @@
+/*
+ * linux/drivers/ide/ide-taskfile.c Version 0.20 Oct 11, 2000
+ *
+ * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
+ * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * IDE_DEBUG(__LINE__);
+ */
+
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+#define DEBUG_TASKFILE 0 /* unset when fixed */
+
+#if DEBUG_TASKFILE
+#define DTF(x...) printk(##x)
+#else
+#define DTF(x...)
+#endif
+
+inline u32 task_read_24 (ide_drive_t *drive)
+{
+ return (IN_BYTE(IDE_HCYL_REG)<<16) |
+ (IN_BYTE(IDE_LCYL_REG)<<8) |
+ IN_BYTE(IDE_SECTOR_REG);
+}
+
+static void ata_bswap_data (void *buffer, int wcount)
+{
+ u16 *p = buffer;
+
+ while (wcount--) {
+ *p = *p << 8 | *p >> 8; p++;
+ *p = *p << 8 | *p >> 8; p++;
+ }
+}
+
+#if SUPPORT_VLB_SYNC
+/*
+ * Some localbus EIDE interfaces require a special access sequence
+ * when using 32-bit I/O instructions to transfer data. We call this
+ * the "vlb_sync" sequence, which consists of three successive reads
+ * of the sector count register location, with interrupts disabled
+ * to ensure that the reads all happen together.
+ */
+static inline void task_vlb_sync (ide_ioreg_t port) {
+ (void) IN_BYTE (port);
+ (void) IN_BYTE (port);
+ (void) IN_BYTE (port);
+}
+#endif /* SUPPORT_VLB_SYNC */
+
+/*
+ * This is used for most PIO data transfers *from* the IDE interface
+ */
+void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+ byte io_32bit;
+
+ /*
+ * first check if this controller has defined a special function
+ * for handling polled ide transfers
+ */
+
+ if (HWIF(drive)->ideproc) {
+ HWIF(drive)->ideproc(ideproc_ide_input_data, drive, buffer, wcount);
+ return;
+ }
+
+ io_32bit = drive->io_32bit;
+
+ if (io_32bit) {
+#if SUPPORT_VLB_SYNC
+ if (io_32bit & 2) {
+ unsigned long flags;
+ __save_flags(flags); /* local CPU only */
+ __cli(); /* local CPU only */
+ task_vlb_sync(IDE_NSECTOR_REG);
+ insl(IDE_DATA_REG, buffer, wcount);
+ __restore_flags(flags); /* local CPU only */
+ } else
+#endif /* SUPPORT_VLB_SYNC */
+ insl(IDE_DATA_REG, buffer, wcount);
+ } else {
+#if SUPPORT_SLOW_DATA_PORTS
+ if (drive->slow) {
+ unsigned short *ptr = (unsigned short *) buffer;
+ while (wcount--) {
+ *ptr++ = inw_p(IDE_DATA_REG);
+ *ptr++ = inw_p(IDE_DATA_REG);
+ }
+ } else
+#endif /* SUPPORT_SLOW_DATA_PORTS */
+ insw(IDE_DATA_REG, buffer, wcount<<1);
+ }
+}
+
+/*
+ * This is used for most PIO data transfers *to* the IDE interface
+ */
+void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+ byte io_32bit;
+
+ if (HWIF(drive)->ideproc) {
+ HWIF(drive)->ideproc(ideproc_ide_output_data, drive, buffer, wcount);
+ return;
+ }
+
+ io_32bit = drive->io_32bit;
+
+ if (io_32bit) {
+#if SUPPORT_VLB_SYNC
+ if (io_32bit & 2) {
+ unsigned long flags;
+ __save_flags(flags); /* local CPU only */
+ __cli(); /* local CPU only */
+ task_vlb_sync(IDE_NSECTOR_REG);
+ outsl(IDE_DATA_REG, buffer, wcount);
+ __restore_flags(flags); /* local CPU only */
+ } else
+#endif /* SUPPORT_VLB_SYNC */
+ outsl(IDE_DATA_REG, buffer, wcount);
+ } else {
+#if SUPPORT_SLOW_DATA_PORTS
+ if (drive->slow) {
+ unsigned short *ptr = (unsigned short *) buffer;
+ while (wcount--) {
+ outw_p(*ptr++, IDE_DATA_REG);
+ outw_p(*ptr++, IDE_DATA_REG);
+ }
+ } else
+#endif /* SUPPORT_SLOW_DATA_PORTS */
+ outsw(IDE_DATA_REG, buffer, wcount<<1);
+ }
+}
+
+/*
+ * The following routines are mainly used by the ATAPI drivers.
+ *
+ * These routines will round up any request for an odd number of bytes,
+ * so if an odd bytecount is specified, be sure that there's at least one
+ * extra byte allocated for the buffer.
+ */
+void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+{
+ if (HWIF(drive)->ideproc) {
+ HWIF(drive)->ideproc(ideproc_atapi_input_bytes, drive, buffer, bytecount);
+ return;
+ }
+
+ ++bytecount;
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+ if (MACH_IS_ATARI || MACH_IS_Q40) {
+ /* Atari has a byte-swapped IDE interface */
+ insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
+ return;
+ }
+#endif /* CONFIG_ATARI */
+ ata_input_data (drive, buffer, bytecount / 4);
+ if ((bytecount & 0x03) >= 2)
+ insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
+}
+
+void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+{
+ if (HWIF(drive)->ideproc) {
+ HWIF(drive)->ideproc(ideproc_atapi_output_bytes, drive, buffer, bytecount);
+ return;
+ }
+
+ ++bytecount;
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+ if (MACH_IS_ATARI || MACH_IS_Q40) {
+ /* Atari has a byte-swapped IDE interface */
+ outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
+ return;
+ }
+#endif /* CONFIG_ATARI */
+ ata_output_data (drive, buffer, bytecount / 4);
+ if ((bytecount & 0x03) >= 2)
+ outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
+}
+
+void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+ ata_input_data(drive, buffer, wcount);
+ if (drive->bswap)
+ ata_bswap_data(buffer, wcount);
+}
+
+void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+ if (drive->bswap) {
+ ata_bswap_data(buffer, wcount);
+ ata_output_data(drive, buffer, wcount);
+ ata_bswap_data(buffer, wcount);
+ } else {
+ ata_output_data(drive, buffer, wcount);
+ }
+}
+
+/*
+ * Needed for PCI irq sharing
+ */
+int drive_is_ready (ide_drive_t *drive)
+{
+ byte stat = 0;
+ if (drive->waiting_for_dma)
+ return HWIF(drive)->dmaproc(ide_dma_test_irq, drive);
+#if 0
+ /* need to guarantee 400ns since last command was issued */
+ udelay(1);
+#endif
+
+#ifdef CONFIG_IDEPCI_SHARE_IRQ
+ /*
+ * We do a passive status test under shared PCI interrupts on
+ * cards that truly share the ATA side interrupt, but may also share
+ * an interrupt with another pci card/device. We make no assumptions
+ * about possible isa-pnp and pci-pnp issues yet.
+ */
+ if (IDE_CONTROL_REG)
+ stat = GET_ALTSTAT();
+ else
+#endif /* CONFIG_IDEPCI_SHARE_IRQ */
+ stat = GET_STAT(); /* Note: this may clear a pending IRQ!! */
+
+ if (stat & BUSY_STAT)
+ return 0; /* drive busy: definitely not interrupting */
+ return 1; /* drive ready: *might* be interrupting */
+}
+
+ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+ task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+ hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
+ struct hd_driveid *id = drive->id;
+ byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
+
+ /* (ks/hs): Moved to start, do not use for multiple out commands */
+ if (task->handler != task_mulout_intr) {
+ if (IDE_CONTROL_REG)
+ OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */
+ SELECT_MASK(HWIF(drive), drive, 0);
+ }
+
+ if ((id->command_set_2 & 0x0400) &&
+ (id->cfs_enable_2 & 0x0400) &&
+ (drive->addressing == 1)) {
+ OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);
+ OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
+ OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
+ OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
+ OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
+ }
+
+ OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
+ OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+ /* refers to number of sectors to transfer */
+ OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+ /* refers to sector offset or start sector */
+ OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
+ OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+
+ OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
+ if (task->handler != NULL) {
+ ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
+ OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+ /*
+ * warning check for race between handler and prehandler for
+ * writing first block of data. however since we are well
+ * inside the boundaries of the seek, we should be okay.
+ */
+ if (task->prehandler != NULL) {
+ return task->prehandler(drive, task->rq);
+ }
+ } else {
+ /* for dma commands we down set the handler */
+ if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
+ }
+
+ return ide_started;
+}
+
+void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler)
+{
+ struct hd_driveid *id = drive->id;
+ byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
+
+ /* (ks/hs): Moved to start, do not use for multiple out commands */
+ if (*handler != task_mulout_intr) {
+ if (IDE_CONTROL_REG)
+ OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */
+ SELECT_MASK(HWIF(drive), drive, 0);
+ }
+
+ if ((id->command_set_2 & 0x0400) &&
+ (id->cfs_enable_2 & 0x0400) &&
+ (drive->addressing == 1)) {
+ OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);
+ OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
+ OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
+ OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
+ OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
+ }
+
+ OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
+ OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+ /* refers to number of sectors to transfer */
+ OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+ /* refers to sector offset or start sector */
+ OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
+ OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+
+ OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
+ if (handler != NULL) {
+ ide_set_handler (drive, handler, WAIT_CMD, NULL);
+ OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+ } else {
+ /* for dma commands we down set the handler */
+ if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
+ }
+}
+
+#if 0
+ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+ task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+ hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
+ struct hd_driveid *id = drive->id;
+
+ /*
+ * (KS) Check taskfile in/out flags.
+ * If set, then execute as it is defined.
+ * If not set, then define default settings.
+ * The default values are:
+ * write and read all taskfile registers (except data)
+ * write and read the hob registers (sector,nsector,lcyl,hcyl)
+ */
+ if (task->tf_out_flags.all == 0) {
+ task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS;
+ if ((id->command_set_2 & 0x0400) &&
+ (id->cfs_enable_2 & 0x0400) &&
+ (drive->addressing == 1)) {
+ task->tf_out_flags.all != (IDE_HOB_STD_OUT_FLAGS << 8);
+ }
+ }
+
+ if (task->tf_in_flags.all == 0) {
+ task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
+ if ((id->command_set_2 & 0x0400) &&
+ (id->cfs_enable_2 & 0x0400) &&
+ (drive->addressing == 1)) {
+ task->tf_in_flags.all != (IDE_HOB_STD_IN_FLAGS << 8);
+ }
+ }
+
+ if (IDE_CONTROL_REG)
+ OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */
+ SELECT_MASK(HWIF(drive), drive, 0);
+
+ if (task->tf_out_flags.b.data) {
+ unsigned short data = taskfile->data + (hobfile->data << 8);
+ OUT_WORD (data, IDE_DATA_REG);
+ }
+
+ /* (KS) send hob registers first */
+ if (task->tf_out_flags.b.nsector_hob)
+ OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
+ if (task->tf_out_flags.b.sector_hob)
+ OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
+ if (task->tf_out_flags.b.lcyl_hob)
+ OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
+ if (task->tf_out_flags.b.hcyl_hob)
+ OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
+
+
+ /* (KS) Send now the standard registers */
+ if (task->tf_out_flags.b.error_feature)
+ OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
+ /* refers to number of sectors to transfer */
+ if (task->tf_out_flags.b.nsector)
+ OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+ /* refers to sector offset or start sector */
+ if (task->tf_out_flags.b.sector)
+ OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+ if (task->tf_out_flags.b.lcyl)
+ OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
+ if (task->tf_out_flags.b.hcyl)
+ OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+
+ /*
+ * (KS) Do not modify the specified taskfile. We want to have a
+ * universal pass through, so we must execute ALL specified values.
+ *
+ * (KS) The drive head register is mandatory.
+ * Don't care about the out flags !
+ */
+ OUT_BYTE(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
+ if (task->handler != NULL) {
+ ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
+ OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+ /*
+ * warning check for race between handler and prehandler for
+ * writing first block of data. however since we are well
+ * inside the boundaries of the seek, we should be okay.
+ */
+ if (task->prehandler != NULL) {
+ return task->prehandler(drive, task->rq);
+ }
+ } else {
+ /* for dma commands we down set the handler */
+ if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
+ }
+
+ return ide_started;
+}
+#endif
+
+#if 0
+/*
+ * Error reporting, in human readable form (luxurious, but a memory hog).
+ */
+byte taskfile_dump_status (ide_drive_t *drive, const char *msg, byte stat)
+{
+ unsigned long flags;
+ byte err = 0;
+
+ __save_flags (flags); /* local CPU only */
+ ide__sti(); /* local CPU only */
+ printk("%s: %s: status=0x%02x", drive->name, msg, stat);
+#if FANCY_STATUS_DUMPS
+ printk(" { ");
+ if (stat & BUSY_STAT)
+ printk("Busy ");
+ else {
+ if (stat & READY_STAT) printk("DriveReady ");
+ if (stat & WRERR_STAT) printk("DeviceFault ");
+ if (stat & SEEK_STAT) printk("SeekComplete ");
+ if (stat & DRQ_STAT) printk("DataRequest ");
+ if (stat & ECC_STAT) printk("CorrectedError ");
+ if (stat & INDEX_STAT) printk("Index ");
+ if (stat & ERR_STAT) printk("Error ");
+ }
+ printk("}");
+#endif /* FANCY_STATUS_DUMPS */
+ printk("\n");
+ if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+ err = GET_ERR();
+ printk("%s: %s: error=0x%02x", drive->name, msg, err);
+#if FANCY_STATUS_DUMPS
+ if (drive->media == ide_disk) {
+ printk(" { ");
+ if (err & ABRT_ERR) printk("DriveStatusError ");
+ if (err & ICRC_ERR) printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector ");
+ if (err & ECC_ERR) printk("UncorrectableError ");
+ if (err & ID_ERR) printk("SectorIdNotFound ");
+ if (err & TRK0_ERR) printk("TrackZeroNotFound ");
+ if (err & MARK_ERR) printk("AddrMarkNotFound ");
+ printk("}");
+ if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+ if ((drive->id->command_set_2 & 0x0400) &&
+ (drive->id->cfs_enable_2 & 0x0400) &&
+ (drive->addressing == 1)) {
+ __u64 sectors = 0;
+ u32 low = 0, high = 0;
+ low = task_read_24(drive);
+ OUT_BYTE(0x80, IDE_CONTROL_REG);
+ high = task_read_24(drive);
+ sectors = ((__u64)high << 24) | low;
+ printk(", LBAsect=%lld", sectors);
+ } else {
+ byte cur = IN_BYTE(IDE_SELECT_REG);
+ if (cur & 0x40) { /* using LBA? */
+ printk(", LBAsect=%ld", (unsigned long)
+ ((cur&0xf)<<24)
+ |(IN_BYTE(IDE_HCYL_REG)<<16)
+ |(IN_BYTE(IDE_LCYL_REG)<<8)
+ | IN_BYTE(IDE_SECTOR_REG));
+ } else {
+ printk(", CHS=%d/%d/%d",
+ (IN_BYTE(IDE_HCYL_REG)<<8) +
+ IN_BYTE(IDE_LCYL_REG),
+ cur & 0xf,
+ IN_BYTE(IDE_SECTOR_REG));
+ }
+ }
+ if (HWGROUP(drive)->rq)
+ printk(", sector=%llu", (__u64) HWGROUP(drive)->rq->sector);
+ }
+ }
+#endif /* FANCY_STATUS_DUMPS */
+ printk("\n");
+ }
+ __restore_flags (flags); /* local CPU only */
+ return err;
+}
+
+/*
+ * Clean up after success/failure of an explicit taskfile operation.
+ */
+void ide_end_taskfile (ide_drive_t *drive, byte stat, byte err)
+{
+ unsigned long flags;
+ struct request *rq;
+ ide_task_t *args;
+ task_ioreg_t command;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ rq = HWGROUP(drive)->rq;
+ spin_unlock_irqrestore(&ide_lock, flags);
+ args = (ide_task_t *) rq->special;
+
+ command = args->tfRegister[IDE_COMMAND_OFFSET];
+
+ rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+
+ args->tfRegister[IDE_ERROR_OFFSET] = err;
+ args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
+ args->tfRegister[IDE_SECTOR_OFFSET] = IN_BYTE(IDE_SECTOR_REG);
+ args->tfRegister[IDE_LCYL_OFFSET] = IN_BYTE(IDE_LCYL_REG);
+ args->tfRegister[IDE_HCYL_OFFSET] = IN_BYTE(IDE_HCYL_REG);
+ args->tfRegister[IDE_SELECT_OFFSET] = IN_BYTE(IDE_SELECT_REG);
+ args->tfRegister[IDE_STATUS_OFFSET] = stat;
+ if ((drive->id->command_set_2 & 0x0400) &&
+ (drive->id->cfs_enable_2 & 0x0400) &&
+ (drive->addressing == 1)) {
+ OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
+ args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
+ args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
+ args->hobRegister[IDE_SECTOR_OFFSET_HOB] = IN_BYTE(IDE_SECTOR_REG);
+ args->hobRegister[IDE_LCYL_OFFSET_HOB] = IN_BYTE(IDE_LCYL_REG);
+ args->hobRegister[IDE_HCYL_OFFSET_HOB] = IN_BYTE(IDE_HCYL_REG);
+ }
+
+/* taskfile_settings_update(drive, args, command); */
+
+ spin_lock_irqsave(&ide_lock, flags);
+ blkdev_dequeue_request(rq);
+ HWGROUP(drive)->rq = NULL;
+ end_that_request_last(rq);
+ spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * try_to_flush_leftover_data() is invoked in response to a drive
+ * unexpectedly having its DRQ_STAT bit set. As an alternative to
+ * resetting the drive, this routine tries to clear the condition
+ * by read a sector's worth of data from the drive. Of course,
+ * this may not help if the drive is *waiting* for data from *us*.
+ */
+void task_try_to_flush_leftover_data (ide_drive_t *drive)
+{
+ int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
+
+ if (drive->media != ide_disk)
+ return;
+ while (i > 0) {
+ u32 buffer[16];
+ unsigned int wcount = (i > 16) ? 16 : i;
+ i -= wcount;
+ taskfile_input_data (drive, buffer, wcount);
+ }
+}
+
+/*
+ * taskfile_error() takes action based on the error returned by the drive.
+ */
+ide_startstop_t taskfile_error (ide_drive_t *drive, const char *msg, byte stat)
+{
+ struct request *rq;
+ byte err;
+
+ err = taskfile_dump_status(drive, msg, stat);
+ if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+ return ide_stopped;
+ /* retry only "normal" I/O: */
+ if (rq->flags & REQ_DRIVE_TASKFILE) {
+ rq->errors = 1;
+ ide_end_taskfile(drive, stat, err);
+ return ide_stopped;
+ }
+ if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
+ rq->errors |= ERROR_RESET;
+ } else {
+ if (drive->media == ide_disk && (stat & ERR_STAT)) {
+ /* err has different meaning on cdrom and tape */
+ if (err == ABRT_ERR) {
+ if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
+ return ide_stopped; /* some newer drives don't support WIN_SPECIFY */
+ } else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) {
+ drive->crc_count++; /* UDMA crc error -- just retry the operation */
+ } else if (err & (BBD_ERR | ECC_ERR)) /* retries won't help these */
+ rq->errors = ERROR_MAX;
+ else if (err & TRK0_ERR) /* help it find track zero */
+ rq->errors |= ERROR_RECAL;
+ }
+ /* pre bio (rq->cmd != WRITE) */
+ if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ)
+ task_try_to_flush_leftover_data(drive);
+ }
+ if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
+ OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); /* force an abort */
+
+ if (rq->errors >= ERROR_MAX) {
+ if (drive->driver != NULL)
+ DRIVER(drive)->end_request(0, HWGROUP(drive));
+ else
+ ide_end_request(0, HWGROUP(drive));
+ } else {
+ if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+ ++rq->errors;
+ return ide_do_reset(drive);
+ }
+ if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+ drive->special.b.recalibrate = 1;
+ ++rq->errors;
+ }
+ return ide_stopped;
+}
+#endif
+
+/*
+ * Handler for special commands without a data phase from ide-disk
+ */
+
+/*
+ * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
+ */
+ide_startstop_t set_multmode_intr (ide_drive_t *drive)
+{
+ byte stat;
+
+ if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) {
+ drive->mult_count = drive->mult_req;
+ } else {
+ drive->mult_req = drive->mult_count = 0;
+ drive->special.b.recalibrate = 1;
+ (void) ide_dump_status(drive, "set_multmode", stat);
+ }
+ return ide_stopped;
+}
+
+/*
+ * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
+ */
+ide_startstop_t set_geometry_intr (ide_drive_t *drive)
+{
+ byte stat;
+
+ if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
+ return ide_stopped;
+
+ if (stat & (ERR_STAT|DRQ_STAT))
+ return ide_error(drive, "set_geometry_intr", stat);
+
+ ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
+ return ide_started;
+}
+
+/*
+ * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
+ */
+ide_startstop_t recal_intr (ide_drive_t *drive)
+{
+ byte stat = GET_STAT();
+
+ if (!OK_STAT(stat,READY_STAT,BAD_STAT))
+ return ide_error(drive, "recal_intr", stat);
+ return ide_stopped;
+}
+
+/*
+ * Handler for commands without a data phase
+ */
+ide_startstop_t task_no_data_intr (ide_drive_t *drive)
+{
+ ide_task_t *args = HWGROUP(drive)->rq->special;
+ byte stat = GET_STAT();
+
+ ide__sti(); /* local CPU only */
+
+ if (!OK_STAT(stat, READY_STAT, BAD_STAT))
+ return ide_error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */
+
+ if (args)
+ ide_end_drive_cmd (drive, stat, GET_ERR());
+
+ return ide_stopped;
+}
+
+/*
+ * Handler for command with PIO data-in phase
+ */
+ide_startstop_t task_in_intr (ide_drive_t *drive)
+{
+ byte stat = GET_STAT();
+ byte io_32bit = drive->io_32bit;
+ struct request *rq = HWGROUP(drive)->rq;
+ char *pBuf = NULL;
+
+ if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+ if (stat & (ERR_STAT|DRQ_STAT)) {
+ return ide_error(drive, "task_in_intr", stat);
+ }
+ if (!(stat & BUSY_STAT)) {
+ DTF("task_in_intr to Soon wait for next interrupt\n");
+ ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
+ return ide_started;
+ }
+ }
+ DTF("stat: %02x\n", stat);
+ pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+ DTF("Read: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
+
+ drive->io_32bit = 0;
+ taskfile_input_data(drive, pBuf, SECTOR_WORDS);
+ drive->io_32bit = io_32bit;
+
+ if (--rq->current_nr_sectors <= 0) {
+ /* (hs): swapped next 2 lines */
+ DTF("Request Ended stat: %02x\n", GET_STAT());
+ ide_end_request(1, HWGROUP(drive));
+ } else {
+ ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
+ return ide_started;
+ }
+ return ide_stopped;
+}
+
+#undef ALTSTAT_SCREW_UP
+
+#ifdef ALTSTAT_SCREW_UP
+/*
+ * (ks/hs): Poll Alternate Status Register to ensure
+ * that drive is not busy.
+ */
+byte altstat_multi_busy (ide_drive_t *drive, byte stat, const char *msg)
+{
+ int i;
+
+ DTF("multi%s: ASR = %x\n", msg, stat);
+ if (stat & BUSY_STAT) {
+ /* (ks/hs): FIXME: Replace hard-coded 100, error handling? */
+ for (i=0; i<100; i++) {
+ stat = GET_ALTSTAT();
+ if ((stat & BUSY_STAT) == 0)
+ break;
+ }
+ }
+ /*
+ * (ks/hs): Read Status AFTER Alternate Status Register
+ */
+ return(GET_STAT());
+}
+
+/*
+ * (ks/hs): Poll Alternate status register to wait for drive
+ * to become ready for next transfer
+ */
+byte altstat_multi_poll (ide_drive_t *drive, byte stat, const char *msg)
+{
+ /* (ks/hs): FIXME: Error handling, time-out? */
+ while (stat & BUSY_STAT)
+ stat = GET_ALTSTAT();
+ DTF("multi%s: nsect=1, ASR = %x\n", msg, stat);
+ return(GET_STAT()); /* (ks/hs): Clear pending IRQ */
+}
+#endif /* ALTSTAT_SCREW_UP */
+
+/*
+ * Handler for command with Read Multiple
+ */
+ide_startstop_t task_mulin_intr (ide_drive_t *drive)
+{
+ unsigned int msect, nsect;
+
+#ifdef ALTSTAT_SCREW_UP
+ byte stat = altstat_multi_busy(drive, GET_ALTSTAT(), "read");
+#else
+ byte stat = GET_STAT();
+#endif /* ALTSTAT_SCREW_UP */
+
+ byte io_32bit = drive->io_32bit;
+ struct request *rq = HWGROUP(drive)->rq;
+ char *pBuf = NULL;
+
+ if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+ if (stat & (ERR_STAT|DRQ_STAT)) {
+ return ide_error(drive, "task_mulin_intr", stat);
+ }
+ /* no data yet, so wait for another interrupt */
+ ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
+ return ide_started;
+ }
+
+ /* (ks/hs): Fixed Multi-Sector transfer */
+ msect = drive->mult_count;
+
+#ifdef ALTSTAT_SCREW_UP
+ /*
+ * Screw the request we do not support bad data-phase setups!
+ * Either read and learn the ATA standard or crash yourself!
+ */
+ if (!msect) {
+ /*
+ * (ks/hs): Drive supports multi-sector transfer,
+ * drive->mult_count was not set
+ */
+ nsect = 1;
+ while (rq->current_nr_sectors) {
+ pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+ DTF("Multiread: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
+ drive->io_32bit = 0;
+ taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+ drive->io_32bit = io_32bit;
+ rq->errors = 0;
+ rq->current_nr_sectors -= nsect;
+ stat = altstat_multi_poll(drive, GET_ALTSTAT(), "read");
+ }
+ ide_end_request(1, HWGROUP(drive));
+ return ide_stopped;
+ }
+#endif /* ALTSTAT_SCREW_UP */
+
+ nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+ pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+
+ DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+ pBuf, nsect, rq->current_nr_sectors);
+ drive->io_32bit = 0;
+ taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+ drive->io_32bit = io_32bit;
+ rq->errors = 0;
+ rq->current_nr_sectors -= nsect;
+ if (rq->current_nr_sectors != 0) {
+ ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
+ return ide_started;
+ }
+ ide_end_request(1, HWGROUP(drive));
+ return ide_stopped;
+}
+
+ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
+{
+ ide_task_t *args = rq->special;
+ ide_startstop_t startstop;
+
+ if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
+ printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name, drive->mult_count ? "MULTWRITE" : "WRITE");
+ return startstop;
+ }
+
+ /* (ks/hs): Fixed Multi Write */
+ if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) &&
+ (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) {
+ /* For Write_sectors we need to stuff the first sector */
+ taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
+ rq->current_nr_sectors--;
+ return ide_started;
+ } else {
+ /*
+ * (ks/hs): Stuff the first sector(s)
+ * by implicitly calling the handler
+ */
+ if (!(drive_is_ready(drive))) {
+ int i;
+ /*
+ * (ks/hs): FIXME: Replace hard-coded
+ * 100, error handling?
+ */
+ for (i=0; i<100; i++) {
+ if (drive_is_ready(drive))
+ break;
+ }
+ }
+ return args->handler(drive);
+ }
+ return ide_started;
+}
+
+/*
+ * Handler for command with PIO data-out phase
+ */
+ide_startstop_t task_out_intr (ide_drive_t *drive)
+{
+ byte stat = GET_STAT();
+ byte io_32bit = drive->io_32bit;
+ struct request *rq = HWGROUP(drive)->rq;
+ char *pBuf = NULL;
+
+ if (!rq->current_nr_sectors) {
+ ide_end_request(1, HWGROUP(drive));
+ return ide_stopped;
+ }
+
+ if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
+ return ide_error(drive, "task_out_intr", stat);
+ }
+ if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
+ rq = HWGROUP(drive)->rq;
+ pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+ DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
+ drive->io_32bit = 0;
+ taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+ drive->io_32bit = io_32bit;
+ rq->errors = 0;
+ rq->current_nr_sectors--;
+ }
+
+ if (rq->current_nr_sectors <= 0) {
+ ide_end_request(1, HWGROUP(drive));
+ } else {
+ ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
+ return ide_started;
+ }
+ return ide_stopped;
+}
+
+/*
+ * Handler for command write multiple
+ * Called directly from execute_drive_cmd for the first bunch of sectors,
+ * afterwards only by the ISR
+ */
+ide_startstop_t task_mulout_intr (ide_drive_t *drive)
+{
+ unsigned int msect, nsect;
+
+#ifdef ALTSTAT_SCREW_UP
+ byte stat = altstat_multi_busy(drive, GET_ALTSTAT(), "write");
+#else
+ byte stat = GET_STAT();
+#endif /* ALTSTAT_SCREW_UP */
+
+ byte io_32bit = drive->io_32bit;
+ struct request *rq = HWGROUP(drive)->rq;
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ char *pBuf = NULL;
+
+ /*
+ * (ks/hs): Handle last IRQ on multi-sector transfer,
+ * occurs after all data was sent
+ */
+ if (rq->current_nr_sectors == 0) {
+ if (stat & (ERR_STAT|DRQ_STAT))
+ return ide_error(drive, "task_mulout_intr", stat);
+ ide_end_request(1, HWGROUP(drive));
+ return ide_stopped;
+ }
+
+ if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+ if (stat & (ERR_STAT|DRQ_STAT)) {
+ return ide_error(drive, "task_mulout_intr", stat);
+ }
+ /* no data yet, so wait for another interrupt */
+ if (hwgroup->handler == NULL)
+ ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+ return ide_started;
+ }
+
+ /* (ks/hs): See task_mulin_intr */
+ msect = drive->mult_count;
+
+#ifdef ALTSTAT_SCREW_UP
+ /*
+ * Screw the request we do not support bad data-phase setups!
+ * Either read and learn the ATA standard or crash yourself!
+ */
+ if (!msect) {
+ nsect = 1;
+ while (rq->current_nr_sectors) {
+ pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+ DTF("Multiwrite: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
+ drive->io_32bit = 0;
+ taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+ drive->io_32bit = io_32bit;
+ rq->errors = 0;
+ rq->current_nr_sectors -= nsect;
+ stat = altstat_multi_poll(drive, GET_ALTSTAT(), "write");
+ }
+ ide_end_request(1, HWGROUP(drive));
+ return ide_stopped;
+ }
+#endif /* ALTSTAT_SCREW_UP */
+
+ nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+ pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+ DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+ pBuf, nsect, rq->current_nr_sectors);
+ drive->io_32bit = 0;
+ taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+ drive->io_32bit = io_32bit;
+ rq->errors = 0;
+ rq->current_nr_sectors -= nsect;
+ if (hwgroup->handler == NULL)
+ ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+ return ide_started;
+}
+
+/* Called by internal to feature out type of command being called */
+ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
+{
+ switch(taskfile->command) {
+ /* IDE_DRIVE_TASK_RAW_WRITE */
+ case CFA_WRITE_MULTI_WO_ERASE:
+ case WIN_MULTWRITE:
+ case WIN_MULTWRITE_EXT:
+ /* IDE_DRIVE_TASK_OUT */
+ case WIN_WRITE:
+ case WIN_WRITE_EXT:
+ case WIN_WRITE_VERIFY:
+ case WIN_WRITE_BUFFER:
+ case CFA_WRITE_SECT_WO_ERASE:
+ case WIN_DOWNLOAD_MICROCODE:
+ return &pre_task_out_intr;
+ /* IDE_DRIVE_TASK_OUT */
+ case WIN_SMART:
+ if (taskfile->feature == SMART_WRITE_LOG_SECTOR)
+ return &pre_task_out_intr;
+ case WIN_WRITEDMA:
+ case WIN_WRITEDMA_QUEUED:
+ case WIN_WRITEDMA_EXT:
+ case WIN_WRITEDMA_QUEUED_EXT:
+ /* IDE_DRIVE_TASK_OUT */
+ default:
+ break;
+ }
+ return(NULL);
+}
+
+/* Called by internal to feature out type of command being called */
+ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
+{
+ switch(taskfile->command) {
+ case WIN_IDENTIFY:
+ case WIN_PIDENTIFY:
+ case CFA_TRANSLATE_SECTOR:
+ case WIN_READ_BUFFER:
+ case WIN_READ:
+ case WIN_READ_EXT:
+ return &task_in_intr;
+ case WIN_SECURITY_DISABLE:
+ case WIN_SECURITY_ERASE_UNIT:
+ case WIN_SECURITY_SET_PASS:
+ case WIN_SECURITY_UNLOCK:
+ case WIN_DOWNLOAD_MICROCODE:
+ case CFA_WRITE_SECT_WO_ERASE:
+ case WIN_WRITE_BUFFER:
+ case WIN_WRITE_VERIFY:
+ case WIN_WRITE:
+ case WIN_WRITE_EXT:
+ return &task_out_intr;
+ case WIN_MULTREAD:
+ case WIN_MULTREAD_EXT:
+ return &task_mulin_intr;
+ case CFA_WRITE_MULTI_WO_ERASE:
+ case WIN_MULTWRITE:
+ case WIN_MULTWRITE_EXT:
+ return &task_mulout_intr;
+ case WIN_SMART:
+ switch(taskfile->feature) {
+ case SMART_READ_VALUES:
+ case SMART_READ_THRESHOLDS:
+ case SMART_READ_LOG_SECTOR:
+ return &task_in_intr;
+ case SMART_WRITE_LOG_SECTOR:
+ return &task_out_intr;
+ default:
+ return &task_no_data_intr;
+ }
+ case CFA_REQ_EXT_ERROR_CODE:
+ case CFA_ERASE_SECTORS:
+ case WIN_VERIFY:
+ case WIN_VERIFY_EXT:
+ case WIN_SEEK:
+ return &task_no_data_intr;
+ case WIN_SPECIFY:
+ return &set_geometry_intr;
+ case WIN_RESTORE:
+ return &recal_intr;
+ case WIN_DIAGNOSE:
+ case WIN_FLUSH_CACHE:
+ case WIN_FLUSH_CACHE_EXT:
+ case WIN_STANDBYNOW1:
+ case WIN_STANDBYNOW2:
+ case WIN_SLEEPNOW1:
+ case WIN_SLEEPNOW2:
+ case WIN_SETIDLE1:
+ case WIN_CHECKPOWERMODE1:
+ case WIN_CHECKPOWERMODE2:
+ case WIN_GETMEDIASTATUS:
+ case WIN_MEDIAEJECT:
+ return &task_no_data_intr;
+ case WIN_SETMULT:
+ return &set_multmode_intr;
+ case WIN_READ_NATIVE_MAX:
+ case WIN_SET_MAX:
+ case WIN_READ_NATIVE_MAX_EXT:
+ case WIN_SET_MAX_EXT:
+ case WIN_SECURITY_ERASE_PREPARE:
+ case WIN_SECURITY_FREEZE_LOCK:
+ case WIN_DOORLOCK:
+ case WIN_DOORUNLOCK:
+ case WIN_SETFEATURES:
+ return &task_no_data_intr;
+ case DISABLE_SEAGATE:
+ case EXABYTE_ENABLE_NEST:
+ return &task_no_data_intr;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ case WIN_READDMA:
+ case WIN_IDENTIFY_DMA:
+ case WIN_READDMA_QUEUED:
+ case WIN_READDMA_EXT:
+ case WIN_READDMA_QUEUED_EXT:
+ case WIN_WRITEDMA:
+ case WIN_WRITEDMA_QUEUED:
+ case WIN_WRITEDMA_EXT:
+ case WIN_WRITEDMA_QUEUED_EXT:
+#endif
+ case WIN_FORMAT:
+ case WIN_INIT:
+ case WIN_DEVICE_RESET:
+ case WIN_QUEUED_SERVICE:
+ case WIN_PACKETCMD:
+ default:
+ return(NULL);
+ }
+}
+
+/* Called by ioctl to feature out type of command being called */
+int ide_cmd_type_parser (ide_task_t *args)
+{
+ struct hd_drive_task_hdr *taskfile = (struct hd_drive_task_hdr *) args->tfRegister;
+ struct hd_drive_hob_hdr *hobfile = (struct hd_drive_hob_hdr *) args->hobRegister;
+
+ args->prehandler = ide_pre_handler_parser(taskfile, hobfile);
+ args->handler = ide_handler_parser(taskfile, hobfile);
+
+ switch(args->tfRegister[IDE_COMMAND_OFFSET]) {
+ case WIN_IDENTIFY:
+ case WIN_PIDENTIFY:
+ return IDE_DRIVE_TASK_IN;
+ case CFA_TRANSLATE_SECTOR:
+ case WIN_READ:
+ case WIN_READ_EXT:
+ case WIN_READ_BUFFER:
+ return IDE_DRIVE_TASK_IN;
+ case WIN_WRITE:
+ case WIN_WRITE_EXT:
+ case WIN_WRITE_VERIFY:
+ case WIN_WRITE_BUFFER:
+ case CFA_WRITE_SECT_WO_ERASE:
+ case WIN_DOWNLOAD_MICROCODE:
+ return IDE_DRIVE_TASK_RAW_WRITE;
+ case WIN_MULTREAD:
+ case WIN_MULTREAD_EXT:
+ return IDE_DRIVE_TASK_IN;
+ case CFA_WRITE_MULTI_WO_ERASE:
+ case WIN_MULTWRITE:
+ case WIN_MULTWRITE_EXT:
+ return IDE_DRIVE_TASK_RAW_WRITE;
+ case WIN_SECURITY_DISABLE:
+ case WIN_SECURITY_ERASE_UNIT:
+ case WIN_SECURITY_SET_PASS:
+ case WIN_SECURITY_UNLOCK:
+ return IDE_DRIVE_TASK_OUT;
+ case WIN_SMART:
+ args->tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS;
+ args->tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS;
+ switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+ case SMART_READ_VALUES:
+ case SMART_READ_THRESHOLDS:
+ case SMART_READ_LOG_SECTOR:
+ return IDE_DRIVE_TASK_IN;
+ case SMART_WRITE_LOG_SECTOR:
+ return IDE_DRIVE_TASK_OUT;
+ default:
+ return IDE_DRIVE_TASK_NO_DATA;
+ }
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ case WIN_READDMA:
+ case WIN_IDENTIFY_DMA:
+ case WIN_READDMA_QUEUED:
+ case WIN_READDMA_EXT:
+ case WIN_READDMA_QUEUED_EXT:
+ return IDE_DRIVE_TASK_IN;
+ case WIN_WRITEDMA:
+ case WIN_WRITEDMA_QUEUED:
+ case WIN_WRITEDMA_EXT:
+ case WIN_WRITEDMA_QUEUED_EXT:
+ return IDE_DRIVE_TASK_RAW_WRITE;
+#endif
+ case WIN_SETFEATURES:
+ switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+ case SETFEATURES_XFER:
+ return IDE_DRIVE_TASK_SET_XFER;
+ case SETFEATURES_DIS_DEFECT:
+ case SETFEATURES_EN_APM:
+ case SETFEATURES_DIS_MSN:
+ case SETFEATURES_EN_RI:
+ case SETFEATURES_EN_SI:
+ case SETFEATURES_DIS_RPOD:
+ case SETFEATURES_DIS_WCACHE:
+ case SETFEATURES_EN_DEFECT:
+ case SETFEATURES_DIS_APM:
+ case SETFEATURES_EN_MSN:
+ case SETFEATURES_EN_RLA:
+ case SETFEATURES_PREFETCH:
+ case SETFEATURES_EN_RPOD:
+ case SETFEATURES_DIS_RI:
+ case SETFEATURES_DIS_SI:
+ default:
+ return IDE_DRIVE_TASK_NO_DATA;
+ }
+ case WIN_NOP:
+ case CFA_REQ_EXT_ERROR_CODE:
+ case CFA_ERASE_SECTORS:
+ case WIN_VERIFY:
+ case WIN_VERIFY_EXT:
+ case WIN_SEEK:
+ case WIN_SPECIFY:
+ case WIN_RESTORE:
+ case WIN_DIAGNOSE:
+ case WIN_FLUSH_CACHE:
+ case WIN_FLUSH_CACHE_EXT:
+ case WIN_STANDBYNOW1:
+ case WIN_STANDBYNOW2:
+ case WIN_SLEEPNOW1:
+ case WIN_SLEEPNOW2:
+ case WIN_SETIDLE1:
+ case DISABLE_SEAGATE:
+ case WIN_CHECKPOWERMODE1:
+ case WIN_CHECKPOWERMODE2:
+ case WIN_GETMEDIASTATUS:
+ case WIN_MEDIAEJECT:
+ case WIN_SETMULT:
+ case WIN_READ_NATIVE_MAX:
+ case WIN_SET_MAX:
+ case WIN_READ_NATIVE_MAX_EXT:
+ case WIN_SET_MAX_EXT:
+ case WIN_SECURITY_ERASE_PREPARE:
+ case WIN_SECURITY_FREEZE_LOCK:
+ case EXABYTE_ENABLE_NEST:
+ case WIN_DOORLOCK:
+ case WIN_DOORUNLOCK:
+ return IDE_DRIVE_TASK_NO_DATA;
+ case WIN_FORMAT:
+ case WIN_INIT:
+ case WIN_DEVICE_RESET:
+ case WIN_QUEUED_SERVICE:
+ case WIN_PACKETCMD:
+ default:
+ return IDE_DRIVE_TASK_INVALID;
+ }
+}
+
+/*
+ * This function is intended to be used prior to invoking ide_do_drive_cmd().
+ */
+void ide_init_drive_taskfile (struct request *rq)
+{
+ memset(rq, 0, sizeof(*rq));
+ rq->flags = REQ_DRIVE_TASKFILE;
+}
+
+/*
+ * This is kept for internal use only !!!
+ * This is an internal call and nobody in user-space has a damn
+ * reason to call this taskfile.
+ *
+ * ide_raw_taskfile is the one that user-space executes.
+ */
+int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf)
+{
+ struct request rq;
+ ide_task_t args;
+
+ memset(&args, 0, sizeof(ide_task_t));
+
+ args.tfRegister[IDE_DATA_OFFSET] = taskfile->data;
+ args.tfRegister[IDE_FEATURE_OFFSET] = taskfile->feature;
+ args.tfRegister[IDE_NSECTOR_OFFSET] = taskfile->sector_count;
+ args.tfRegister[IDE_SECTOR_OFFSET] = taskfile->sector_number;
+ args.tfRegister[IDE_LCYL_OFFSET] = taskfile->low_cylinder;
+ args.tfRegister[IDE_HCYL_OFFSET] = taskfile->high_cylinder;
+ args.tfRegister[IDE_SELECT_OFFSET] = taskfile->device_head;
+ args.tfRegister[IDE_COMMAND_OFFSET] = taskfile->command;
+
+ args.hobRegister[IDE_DATA_OFFSET_HOB] = hobfile->data;
+ args.hobRegister[IDE_FEATURE_OFFSET_HOB] = hobfile->feature;
+ args.hobRegister[IDE_NSECTOR_OFFSET_HOB] = hobfile->sector_count;
+ args.hobRegister[IDE_SECTOR_OFFSET_HOB] = hobfile->sector_number;
+ args.hobRegister[IDE_LCYL_OFFSET_HOB] = hobfile->low_cylinder;
+ args.hobRegister[IDE_HCYL_OFFSET_HOB] = hobfile->high_cylinder;
+ args.hobRegister[IDE_SELECT_OFFSET_HOB] = hobfile->device_head;
+ args.hobRegister[IDE_CONTROL_OFFSET_HOB] = hobfile->control;
+
+ ide_init_drive_taskfile(&rq);
+ /* This is kept for internal use only !!! */
+ args.command_type = ide_cmd_type_parser (&args);
+ if (args.command_type != IDE_DRIVE_TASK_NO_DATA)
+ rq.current_nr_sectors = rq.nr_sectors = (hobfile->sector_count << 8) | taskfile->sector_count;
+
+ rq.buffer = buf;
+ rq.special = &args;
+ return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
+int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, byte *buf)
+{
+ struct request rq;
+ ide_init_drive_taskfile(&rq);
+ rq.buffer = buf;
+
+ if (args->command_type != IDE_DRIVE_TASK_NO_DATA)
+ rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
+
+ rq.special = args;
+ return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
+
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+char * ide_ioctl_verbose (unsigned int cmd)
+{
+ return("unknown");
+}
+
+char * ide_task_cmd_verbose (byte task)
+{
+ return("unknown");
+}
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+
+/*
+ * The taskfile glue table
+ *
+ * reqtask.data_phase reqtask.req_cmd
+ * args.command_type args.handler
+ *
+ * TASKFILE_P_OUT_DMAQ ?? ??
+ * TASKFILE_P_IN_DMAQ ?? ??
+ * TASKFILE_P_OUT_DMA ?? ??
+ * TASKFILE_P_IN_DMA ?? ??
+ * TASKFILE_P_OUT ?? ??
+ * TASKFILE_P_IN ?? ??
+ *
+ * TASKFILE_OUT_DMAQ IDE_DRIVE_TASK_RAW_WRITE NULL
+ * TASKFILE_IN_DMAQ IDE_DRIVE_TASK_IN NULL
+ *
+ * TASKFILE_OUT_DMA IDE_DRIVE_TASK_RAW_WRITE NULL
+ * TASKFILE_IN_DMA IDE_DRIVE_TASK_IN NULL
+ *
+ * TASKFILE_IN_OUT ?? ??
+ *
+ * TASKFILE_MULTI_OUT IDE_DRIVE_TASK_RAW_WRITE task_mulout_intr
+ * TASKFILE_MULTI_IN IDE_DRIVE_TASK_IN task_mulin_intr
+ *
+ * TASKFILE_OUT IDE_DRIVE_TASK_RAW_WRITE task_out_intr
+ * TASKFILE_OUT IDE_DRIVE_TASK_OUT task_out_intr
+ *
+ * TASKFILE_IN IDE_DRIVE_TASK_IN task_in_intr
+ * TASKFILE_NO_DATA IDE_DRIVE_TASK_NO_DATA task_no_data_intr
+ *
+ * IDE_DRIVE_TASK_SET_XFER task_no_data_intr
+ * IDE_DRIVE_TASK_INVALID
+ *
+ */
+
+#define MAX_DMA (256*SECTOR_WORDS)
+
+int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ ide_task_request_t *req_task;
+ ide_task_t args;
+
+ byte *outbuf = NULL;
+ byte *inbuf = NULL;
+ task_ioreg_t *argsptr = args.tfRegister;
+ task_ioreg_t *hobsptr = args.hobRegister;
+ int err = 0;
+ int tasksize = sizeof(struct ide_task_request_s);
+ int taskin = 0;
+ int taskout = 0;
+
+ req_task = kmalloc(tasksize, GFP_KERNEL);
+ if (req_task == NULL) return -ENOMEM;
+ memset(req_task, 0, tasksize);
+ if (copy_from_user(req_task, (void *) arg, tasksize)) {
+ kfree(req_task);
+ return -EFAULT;
+ }
+
+ taskout = (int) req_task->out_size;
+ taskin = (int) req_task->in_size;
+
+ if (taskout) {
+ int outtotal = tasksize;
+ outbuf = kmalloc(taskout, GFP_KERNEL);
+ if (outbuf == NULL) {
+ err = -ENOMEM;
+ goto abort;
+ }
+ memset(outbuf, 0, taskout);
+ if (copy_from_user(outbuf, (void *)arg + outtotal, taskout)) {
+ err = -EFAULT;
+ goto abort;
+ }
+ }
+
+ if (taskin) {
+ int intotal = tasksize + taskout;
+ inbuf = kmalloc(taskin, GFP_KERNEL);
+ if (inbuf == NULL) {
+ err = -ENOMEM;
+ goto abort;
+ }
+ memset(inbuf, 0, taskin);
+ if (copy_from_user(inbuf, (void *)arg + intotal , taskin)) {
+ err = -EFAULT;
+ goto abort;
+ }
+ }
+
+ memset(argsptr, 0, HDIO_DRIVE_TASK_HDR_SIZE);
+ memset(hobsptr, 0, HDIO_DRIVE_HOB_HDR_SIZE);
+ memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
+ memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE);
+
+ args.tf_in_flags = req_task->in_flags;
+ args.tf_out_flags = req_task->out_flags;
+ args.data_phase = req_task->data_phase;
+ args.command_type = req_task->req_cmd;
+
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+ DTF("%s: ide_ioctl_cmd %s: ide_task_cmd %s\n",
+ drive->name,
+ ide_ioctl_verbose(cmd),
+ ide_task_cmd_verbose(args.tfRegister[IDE_COMMAND_OFFSET]));
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+
+ switch(req_task->data_phase) {
+ case TASKFILE_OUT_DMAQ:
+ case TASKFILE_OUT_DMA:
+ args.prehandler = NULL;
+ args.handler = NULL;
+ args.posthandler = NULL;
+ err = ide_raw_taskfile(drive, &args, outbuf);
+ break;
+ case TASKFILE_IN_DMAQ:
+ case TASKFILE_IN_DMA:
+ args.prehandler = NULL;
+ args.handler = NULL;
+ args.posthandler = NULL;
+ err = ide_raw_taskfile(drive, &args, inbuf);
+ break;
+ case TASKFILE_IN_OUT:
+#if 0
+ args.prehandler = &pre_task_out_intr;
+ args.handler = &task_out_intr;
+ args.posthandler = NULL;
+ err = ide_raw_taskfile(drive, &args, outbuf);
+ args.prehandler = NULL;
+ args.handler = &task_in_intr;
+ args.posthandler = NULL;
+ err = ide_raw_taskfile(drive, &args, inbuf);
+ break;
+#else
+ err = -EFAULT;
+ goto abort;
+#endif
+ case TASKFILE_MULTI_OUT:
+ if (drive->mult_count) {
+ args.prehandler = &pre_task_out_intr;
+ args.handler = &task_mulout_intr;
+ args.posthandler = NULL;
+ err = ide_raw_taskfile(drive, &args, outbuf);
+ } else {
+ /* (hs): give up if multcount is not set */
+ printk("%s: %s Multimode Write " \
+ "multcount is not set\n",
+ drive->name, __FUNCTION__);
+ err = -EPERM;
+ goto abort;
+ }
+ break;
+ case TASKFILE_OUT:
+ args.prehandler = &pre_task_out_intr;
+ args.handler = &task_out_intr;
+ args.posthandler = NULL;
+ err = ide_raw_taskfile(drive, &args, outbuf);
+ break;
+ case TASKFILE_MULTI_IN:
+ if (drive->mult_count) {
+ args.prehandler = NULL;
+ args.handler = &task_mulin_intr;
+ args.posthandler = NULL;
+ err = ide_raw_taskfile(drive, &args, inbuf);
+ } else {
+ /* (hs): give up if multcount is not set */
+ printk("%s: %s Multimode Read failure " \
+ "multcount is not set\n",
+ drive->name, __FUNCTION__);
+ err = -EPERM;
+ goto abort;
+ }
+ break;
+ case TASKFILE_IN:
+ args.prehandler = NULL;
+ args.handler = &task_in_intr;
+ args.posthandler = NULL;
+ err = ide_raw_taskfile(drive, &args, inbuf);
+ break;
+ case TASKFILE_NO_DATA:
+ args.prehandler = NULL;
+ args.handler = &task_no_data_intr;
+ args.posthandler = NULL;
+ err = ide_raw_taskfile(drive, &args, NULL);
+ break;
+ default:
+ args.prehandler = NULL;
+ args.handler = NULL;
+ args.posthandler = NULL;
+ err = -EFAULT;
+ goto abort;
+ }
+
+ memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE);
+ memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE);
+ req_task->in_flags = args.tf_in_flags;
+ req_task->out_flags = args.tf_out_flags;
+
+ if (copy_to_user((void *)arg, req_task, tasksize)) {
+ err = -EFAULT;
+ goto abort;
+ }
+ if (taskout) {
+ int outtotal = tasksize;
+ if (copy_to_user((void *)arg+outtotal, outbuf, taskout)) {
+ err = -EFAULT;
+ goto abort;
+ }
+ }
+ if (taskin) {
+ int intotal = tasksize + taskout;
+ if (copy_to_user((void *)arg+intotal, inbuf, taskin)) {
+ err = -EFAULT;
+ goto abort;
+ }
+ }
+abort:
+ kfree(req_task);
+ if (outbuf != NULL)
+ kfree(outbuf);
+ if (inbuf != NULL)
+ kfree(inbuf);
+ return err;
+}
+
+int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int err = 0;
+ byte args[4], *argbuf = args;
+ byte xfer_rate = 0;
+ int argsize = 4;
+ ide_task_t tfargs;
+
+ if (NULL == (void *) arg) {
+ struct request rq;
+ ide_init_drive_cmd(&rq);
+ return ide_do_drive_cmd(drive, &rq, ide_wait);
+ }
+ if (copy_from_user(args, (void *)arg, 4))
+ return -EFAULT;
+
+ tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
+ tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
+ tfargs.tfRegister[IDE_SECTOR_OFFSET] = args[1];
+ tfargs.tfRegister[IDE_LCYL_OFFSET] = 0x00;
+ tfargs.tfRegister[IDE_HCYL_OFFSET] = 0x00;
+ tfargs.tfRegister[IDE_SELECT_OFFSET] = 0x00;
+ tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
+
+ if (args[3]) {
+ argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
+ argbuf = kmalloc(argsize, GFP_KERNEL);
+ if (argbuf == NULL)
+ return -ENOMEM;
+ memcpy(argbuf, args, 4);
+ }
+ if (set_transfer(drive, &tfargs)) {
+ xfer_rate = args[1];
+ if (ide_ata66_check(drive, &tfargs))
+ goto abort;
+ }
+
+ err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
+
+ if (!err && xfer_rate) {
+ /* active-retuning-calls future */
+ if ((HWIF(drive)->speedproc) != NULL)
+ HWIF(drive)->speedproc(drive, xfer_rate);
+ ide_driveid_update(drive);
+ }
+abort:
+ if (copy_to_user((void *)arg, argbuf, argsize))
+ err = -EFAULT;
+ if (argsize > 4)
+ kfree(argbuf);
+ return err;
+}
+
+int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int err = 0;
+ byte args[7], *argbuf = args;
+ int argsize = 7;
+
+ if (copy_from_user(args, (void *)arg, 7))
+ return -EFAULT;
+ err = ide_wait_cmd_task(drive, argbuf);
+ if (copy_to_user((void *)arg, argbuf, argsize))
+ err = -EFAULT;
+ return err;
+}
+
+EXPORT_SYMBOL(drive_is_ready);
+EXPORT_SYMBOL(task_read_24);
+EXPORT_SYMBOL(ata_input_data);
+EXPORT_SYMBOL(ata_output_data);
+EXPORT_SYMBOL(atapi_input_bytes);
+EXPORT_SYMBOL(atapi_output_bytes);
+EXPORT_SYMBOL(taskfile_input_data);
+EXPORT_SYMBOL(taskfile_output_data);
+EXPORT_SYMBOL(do_rw_taskfile);
+EXPORT_SYMBOL(do_taskfile);
+// EXPORT_SYMBOL(flagged_taskfile);
+
+//EXPORT_SYMBOL(ide_end_taskfile);
+
+EXPORT_SYMBOL(set_multmode_intr);
+EXPORT_SYMBOL(set_geometry_intr);
+EXPORT_SYMBOL(recal_intr);
+
+EXPORT_SYMBOL(task_no_data_intr);
+EXPORT_SYMBOL(task_in_intr);
+EXPORT_SYMBOL(task_mulin_intr);
+EXPORT_SYMBOL(pre_task_out_intr);
+EXPORT_SYMBOL(task_out_intr);
+EXPORT_SYMBOL(task_mulout_intr);
+
+EXPORT_SYMBOL(ide_init_drive_taskfile);
+EXPORT_SYMBOL(ide_wait_taskfile);
+EXPORT_SYMBOL(ide_raw_taskfile);
+EXPORT_SYMBOL(ide_pre_handler_parser);
+EXPORT_SYMBOL(ide_handler_parser);
+EXPORT_SYMBOL(ide_cmd_type_parser);
+EXPORT_SYMBOL(ide_taskfile_ioctl);
+EXPORT_SYMBOL(ide_cmd_ioctl);
+EXPORT_SYMBOL(ide_task_ioctl);
+
+
+#ifdef CONFIG_PKT_TASK_IOCTL
+
+#if 0
+{
+
+{ /* start cdrom */
+
+ struct cdrom_info *info = drive->driver_data;
+
+ if (info->dma) {
+ if (info->cmd == READ) {
+ info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
+ } else if (info->cmd == WRITE) {
+ info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
+ } else {
+ printk("ide-cd: DMA set, but not allowed\n");
+ }
+ }
+
+ /* Set up the controller registers. */
+ OUT_BYTE (info->dma, IDE_FEATURE_REG);
+ OUT_BYTE (0, IDE_NSECTOR_REG);
+ OUT_BYTE (0, IDE_SECTOR_REG);
+
+ OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
+ OUT_BYTE (xferlen >> 8 , IDE_HCYL_REG);
+ if (IDE_CONTROL_REG)
+ OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
+
+ if (info->dma)
+ (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+
+ if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+ ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
+ OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+ return ide_started;
+ } else {
+ OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+ return (*handler) (drive);
+ }
+
+} /* end cdrom */
+
+{ /* start floppy */
+
+ idefloppy_floppy_t *floppy = drive->driver_data;
+ idefloppy_bcount_reg_t bcount;
+ int dma_ok = 0;
+
+ floppy->pc=pc; /* Set the current packet command */
+
+ pc->retries++;
+ pc->actually_transferred=0; /* We haven't transferred any data yet */
+ pc->current_position=pc->buffer;
+ bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
+ (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+ }
+ if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+ dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+ if (IDE_CONTROL_REG)
+ OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
+ OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG); /* Use PIO/DMA */
+ OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
+ OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
+ OUT_BYTE (drive->select.all,IDE_SELECT_REG);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (dma_ok) { /* Begin DMA, if necessary */
+ set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+ (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+ }
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+} /* end floppy */
+
+{ /* start tape */
+
+ idetape_tape_t *tape = drive->driver_data;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
+ printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
+ (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+ }
+ if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+ dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+ if (IDE_CONTROL_REG)
+ OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
+ OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG); /* Use PIO/DMA */
+ OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
+ OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
+ OUT_BYTE (drive->select.all,IDE_SELECT_REG);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (dma_ok) { /* Begin DMA, if necessary */
+ set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+ (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+ }
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+ if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
+ ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
+ OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+ return ide_started;
+ } else {
+ OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+ return idetape_transfer_pc(drive);
+ }
+
+} /* end tape */
+
+}
+#endif
+
+int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+#if 0
+ switch(req_task->data_phase) {
+ case TASKFILE_P_OUT_DMAQ:
+ case TASKFILE_P_IN_DMAQ:
+ case TASKFILE_P_OUT_DMA:
+ case TASKFILE_P_IN_DMA:
+ case TASKFILE_P_OUT:
+ case TASKFILE_P_IN:
+ }
+#endif
+ return -ENOMSG;
+}
+
+EXPORT_SYMBOL(pkt_taskfile_ioctl);
+
+#endif /* CONFIG_PKT_TASK_IOCTL */
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 344dddac2..00f8d9b4c 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -151,6 +151,7 @@
#include <linux/ide.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/completion.h>
+#include <linux/reboot.h>
#include <linux/cdrom.h>
#include <asm/byteorder.h>
@@ -371,186 +372,6 @@ int ide_system_bus_speed (void)
return system_bus_speed;
}
-#if SUPPORT_VLB_SYNC
-/*
- * Some localbus EIDE interfaces require a special access sequence
- * when using 32-bit I/O instructions to transfer data. We call this
- * the "vlb_sync" sequence, which consists of three successive reads
- * of the sector count register location, with interrupts disabled
- * to ensure that the reads all happen together.
- */
-static inline void do_vlb_sync (ide_ioreg_t port) {
- (void) inb (port);
- (void) inb (port);
- (void) inb (port);
-}
-#endif /* SUPPORT_VLB_SYNC */
-
-/*
- * This is used for most PIO data transfers *from* the IDE interface
- */
-void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
- byte io_32bit;
-
- /* first check if this controller has defined a special function
- * for handling polled ide transfers
- */
-
- if(HWIF(drive)->ideproc) {
- HWIF(drive)->ideproc(ideproc_ide_input_data,
- drive, buffer, wcount);
- return;
- }
-
- io_32bit = drive->io_32bit;
-
- if (io_32bit) {
-#if SUPPORT_VLB_SYNC
- if (io_32bit & 2) {
- unsigned long flags;
- __save_flags(flags); /* local CPU only */
- __cli(); /* local CPU only */
- do_vlb_sync(IDE_NSECTOR_REG);
- insl(IDE_DATA_REG, buffer, wcount);
- __restore_flags(flags); /* local CPU only */
- } else
-#endif /* SUPPORT_VLB_SYNC */
- insl(IDE_DATA_REG, buffer, wcount);
- } else {
-#if SUPPORT_SLOW_DATA_PORTS
- if (drive->slow) {
- unsigned short *ptr = (unsigned short *) buffer;
- while (wcount--) {
- *ptr++ = inw_p(IDE_DATA_REG);
- *ptr++ = inw_p(IDE_DATA_REG);
- }
- } else
-#endif /* SUPPORT_SLOW_DATA_PORTS */
- insw(IDE_DATA_REG, buffer, wcount<<1);
- }
-}
-
-/*
- * This is used for most PIO data transfers *to* the IDE interface
- */
-void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
- byte io_32bit;
-
- if(HWIF(drive)->ideproc) {
- HWIF(drive)->ideproc(ideproc_ide_output_data,
- drive, buffer, wcount);
- return;
- }
-
- io_32bit = drive->io_32bit;
-
- if (io_32bit) {
-#if SUPPORT_VLB_SYNC
- if (io_32bit & 2) {
- unsigned long flags;
- __save_flags(flags); /* local CPU only */
- __cli(); /* local CPU only */
- do_vlb_sync(IDE_NSECTOR_REG);
- outsl(IDE_DATA_REG, buffer, wcount);
- __restore_flags(flags); /* local CPU only */
- } else
-#endif /* SUPPORT_VLB_SYNC */
- outsl(IDE_DATA_REG, buffer, wcount);
- } else {
-#if SUPPORT_SLOW_DATA_PORTS
- if (drive->slow) {
- unsigned short *ptr = (unsigned short *) buffer;
- while (wcount--) {
- outw_p(*ptr++, IDE_DATA_REG);
- outw_p(*ptr++, IDE_DATA_REG);
- }
- } else
-#endif /* SUPPORT_SLOW_DATA_PORTS */
- outsw(IDE_DATA_REG, buffer, wcount<<1);
- }
-}
-
-/*
- * The following routines are mainly used by the ATAPI drivers.
- *
- * These routines will round up any request for an odd number of bytes,
- * so if an odd bytecount is specified, be sure that there's at least one
- * extra byte allocated for the buffer.
- */
-void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
-{
- if(HWIF(drive)->ideproc) {
- HWIF(drive)->ideproc(ideproc_atapi_input_bytes,
- drive, buffer, bytecount);
- return;
- }
-
- ++bytecount;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
- if (MACH_IS_ATARI || MACH_IS_Q40) {
- /* Atari has a byte-swapped IDE interface */
- insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
- return;
- }
-#endif /* CONFIG_ATARI */
- ide_input_data (drive, buffer, bytecount / 4);
- if ((bytecount & 0x03) >= 2)
- insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
-}
-
-void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
-{
- if(HWIF(drive)->ideproc) {
- HWIF(drive)->ideproc(ideproc_atapi_output_bytes,
- drive, buffer, bytecount);
- return;
- }
-
- ++bytecount;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
- if (MACH_IS_ATARI || MACH_IS_Q40) {
- /* Atari has a byte-swapped IDE interface */
- outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
- return;
- }
-#endif /* CONFIG_ATARI */
- ide_output_data (drive, buffer, bytecount / 4);
- if ((bytecount & 0x03) >= 2)
- outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
-}
-
-/*
- * Needed for PCI irq sharing
- */
-static inline int drive_is_ready (ide_drive_t *drive)
-{
- byte stat = 0;
- if (drive->waiting_for_dma)
- return HWIF(drive)->dmaproc(ide_dma_test_irq, drive);
-#if 0
- udelay(1); /* need to guarantee 400ns since last command was issued */
-#endif
-
-#ifdef CONFIG_IDEPCI_SHARE_IRQ
- /*
- * We do a passive status test under shared PCI interrupts on
- * cards that truly share the ATA side interrupt, but may also share
- * an interrupt with another pci card/device. We make no assumptions
- * about possible isa-pnp and pci-pnp issues yet.
- */
- if (IDE_CONTROL_REG)
- stat = GET_ALTSTAT();
- else
-#endif /* CONFIG_IDEPCI_SHARE_IRQ */
- stat = GET_STAT(); /* Note: this may clear a pending IRQ!! */
-
- if (stat & BUSY_STAT)
- return 0; /* drive busy: definitely not interrupting */
- return 1; /* drive ready: *might* be interrupting */
-}
-
inline int __ide_end_request(ide_hwgroup_t *hwgroup, int uptodate, int nr_secs)
{
ide_drive_t *drive = hwgroup->drive;
@@ -836,7 +657,11 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
*/
OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG); /* set SRST and nIEN */
udelay(10); /* more than enough time */
- OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */
+ if (drive->quirk_list == 2) {
+ OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear SRST and nIEN */
+ } else {
+ OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */
+ }
udelay(10); /* more than enough time */
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
@@ -863,6 +688,13 @@ ide_startstop_t ide_do_reset (ide_drive_t *drive)
return do_reset1 (drive, 0);
}
+static inline u32 read_24 (ide_drive_t *drive)
+{
+ return (IN_BYTE(IDE_HCYL_REG)<<16) |
+ (IN_BYTE(IDE_LCYL_REG)<<8) |
+ IN_BYTE(IDE_SECTOR_REG);
+}
+
/*
* Clean up after success/failure of an explicit drive cmd
*/
@@ -894,6 +726,33 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
args[5] = IN_BYTE(IDE_HCYL_REG);
args[6] = IN_BYTE(IDE_SELECT_REG);
}
+ } else if (rq->flags & REQ_DRIVE_TASKFILE) {
+ ide_task_t *args = (ide_task_t *) rq->special;
+ rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+ if (args) {
+ if (args->tf_in_flags.b.data) {
+ unsigned short data = IN_WORD(IDE_DATA_REG);
+ args->tfRegister[IDE_DATA_OFFSET] = (data) & 0xFF;
+ args->hobRegister[IDE_DATA_OFFSET_HOB] = (data >> 8) & 0xFF;
+ }
+ args->tfRegister[IDE_ERROR_OFFSET] = err;
+ args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
+ args->tfRegister[IDE_SECTOR_OFFSET] = IN_BYTE(IDE_SECTOR_REG);
+ args->tfRegister[IDE_LCYL_OFFSET] = IN_BYTE(IDE_LCYL_REG);
+ args->tfRegister[IDE_HCYL_OFFSET] = IN_BYTE(IDE_HCYL_REG);
+ args->tfRegister[IDE_SELECT_OFFSET] = IN_BYTE(IDE_SELECT_REG);
+ args->tfRegister[IDE_STATUS_OFFSET] = stat;
+ if ((drive->id->command_set_2 & 0x0400) &&
+ (drive->id->cfs_enable_2 & 0x0400) &&
+ (drive->addressing == 1)) {
+ OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
+ args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
+ args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
+ args->hobRegister[IDE_SECTOR_OFFSET_HOB] = IN_BYTE(IDE_SECTOR_REG);
+ args->hobRegister[IDE_LCYL_OFFSET_HOB] = IN_BYTE(IDE_LCYL_REG);
+ args->hobRegister[IDE_HCYL_OFFSET_HOB] = IN_BYTE(IDE_HCYL_REG);
+ }
+ }
}
blkdev_dequeue_request(rq);
@@ -944,19 +803,32 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat)
if (err & MARK_ERR) printk("AddrMarkNotFound ");
printk("}");
if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
- byte cur = IN_BYTE(IDE_SELECT_REG);
- if (cur & 0x40) { /* using LBA? */
- printk(", LBAsect=%ld", (unsigned long)
- ((cur&0xf)<<24)
- |(IN_BYTE(IDE_HCYL_REG)<<16)
- |(IN_BYTE(IDE_LCYL_REG)<<8)
- | IN_BYTE(IDE_SECTOR_REG));
+ if ((drive->id->command_set_2 & 0x0400) &&
+ (drive->id->cfs_enable_2 & 0x0400) &&
+ (drive->addressing == 1)) {
+ __u64 sectors = 0;
+ u32 low = 0, high = 0;
+ low = read_24(drive);
+ OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG);
+ high = read_24(drive);
+
+ sectors = ((__u64)high << 24) | low;
+ printk(", LBAsect=%lld, high=%d, low=%d", (long long) sectors, high, low);
} else {
- printk(", CHS=%d/%d/%d",
- (IN_BYTE(IDE_HCYL_REG)<<8) +
- IN_BYTE(IDE_LCYL_REG),
- cur & 0xf,
- IN_BYTE(IDE_SECTOR_REG));
+ byte cur = IN_BYTE(IDE_SELECT_REG);
+ if (cur & 0x40) { /* using LBA? */
+ printk(", LBAsect=%ld", (unsigned long)
+ ((cur&0xf)<<24)
+ |(IN_BYTE(IDE_HCYL_REG)<<16)
+ |(IN_BYTE(IDE_LCYL_REG)<<8)
+ | IN_BYTE(IDE_SECTOR_REG));
+ } else {
+ printk(", CHS=%d/%d/%d",
+ (IN_BYTE(IDE_HCYL_REG)<<8) +
+ IN_BYTE(IDE_LCYL_REG),
+ cur & 0xf,
+ IN_BYTE(IDE_SECTOR_REG));
+ }
}
if (HWGROUP(drive) && HWGROUP(drive)->rq)
printk(", sector=%ld", HWGROUP(drive)->rq->sector);
@@ -986,7 +858,7 @@ static void try_to_flush_leftover_data (ide_drive_t *drive)
u32 buffer[16];
unsigned int wcount = (i > 16) ? 16 : i;
i -= wcount;
- ide_input_data (drive, buffer, wcount);
+ ata_input_data (drive, buffer, wcount);
}
}
@@ -1004,9 +876,15 @@ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat)
/* retry only "normal" I/O: */
if (!(rq->flags & REQ_CMD)) {
rq->errors = 1;
+#if 0
+ if (rq->flags & REQ_DRIVE_TASKFILE)
+ ide_end_taskfile(drive, stat, err);
+ else
+#endif
ide_end_drive_cmd(drive, stat, err);
return ide_stopped;
}
+
if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
rq->errors |= ERROR_RESET;
} else {
@@ -1022,6 +900,7 @@ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat)
else if (err & TRK0_ERR) /* help it find track zero */
rq->errors |= ERROR_RECAL;
}
+ /* pre bio (rq->cmd != WRITE) */
if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ)
try_to_flush_leftover_data(drive);
}
@@ -1073,7 +952,7 @@ static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
if ((stat & DRQ_STAT) && args && args[3]) {
byte io_32bit = drive->io_32bit;
drive->io_32bit = 0;
- ide_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
+ ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
drive->io_32bit = io_32bit;
while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
udelay(100);
@@ -1168,14 +1047,63 @@ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, by
*/
static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
{
- byte *args = rq->buffer;
- if (args && (rq->flags & REQ_DRIVE_TASK)) {
+ if (rq->flags & REQ_DRIVE_TASKFILE) {
+ ide_task_t *args = rq->special;
+
+ if (!(args)) goto args_error;
+
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+ {
+ printk(KERN_INFO "%s: ", drive->name);
+// printk("TF.0=x%02x ", args->tfRegister[IDE_DATA_OFFSET]);
+ printk("TF.1=x%02x ", args->tfRegister[IDE_FEATURE_OFFSET]);
+ printk("TF.2=x%02x ", args->tfRegister[IDE_NSECTOR_OFFSET]);
+ printk("TF.3=x%02x ", args->tfRegister[IDE_SECTOR_OFFSET]);
+ printk("TF.4=x%02x ", args->tfRegister[IDE_LCYL_OFFSET]);
+ printk("TF.5=x%02x ", args->tfRegister[IDE_HCYL_OFFSET]);
+ printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]);
+ printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]);
+ printk(KERN_INFO "%s: ", drive->name);
+// printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET_HOB]);
+ printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET_HOB]);
+ printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET_HOB]);
+ printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET_HOB]);
+ printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET_HOB]);
+ printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET_HOB]);
+ printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET_HOB]);
+ printk("HTF.7=x%02x\n", args->hobRegister[IDE_CONTROL_OFFSET_HOB]);
+ }
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+
+// if (args->tf_out_flags.all == 0) {
+ do_taskfile(drive,
+ (struct hd_drive_task_hdr *)&args->tfRegister,
+ (struct hd_drive_hob_hdr *)&args->hobRegister,
+ args->handler);
+// } else {
+// return flagged_taskfile(drive, args);
+// }
+
+ if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) ||
+ (args->command_type == IDE_DRIVE_TASK_OUT)) &&
+ args->prehandler && args->handler)
+ return args->prehandler(drive, rq);
+ return ide_started;
+
+ } else if (rq->flags & REQ_DRIVE_TASK) {
+ byte *args = rq->buffer;
byte sel;
+
+ if (!(args)) goto args_error;
#ifdef DEBUG
- printk("%s: DRIVE_TASK_CMD data=x%02x cmd=0x%02x fr=0x%02x ns=0x%02x sc=0x%02x lcyl=0x%02x hcyl=0x%02x sel=0x%02x\n",
- drive->name,
- args[0], args[1], args[2], args[3],
- args[4], args[5], args[6], args[7]);
+ printk("%s: DRIVE_TASK_CMD ", drive->name);
+ printk("cmd=0x%02x ", args[0]);
+ printk("fr=0x%02x ", args[1]);
+ printk("ns=0x%02x ", args[2]);
+ printk("sc=0x%02x ", args[3]);
+ printk("lcyl=0x%02x ", args[4]);
+ printk("hcyl=0x%02x ", args[5]);
+ printk("sel=0x%02x\n", args[6]);
#endif
OUT_BYTE(args[1], IDE_FEATURE_REG);
OUT_BYTE(args[3], IDE_SECTOR_REG);
@@ -1187,10 +1115,16 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq
OUT_BYTE(sel, IDE_SELECT_REG);
ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
return ide_started;
- } else if (args) {
+ } else if (rq->flags & REQ_DRIVE_CMD) {
+
+ byte *args = rq->buffer;
+ if (!(args)) goto args_error;
#ifdef DEBUG
- printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x xx=0x%02x\n",
- drive->name, args[0], args[1], args[2], args[3]);
+ printk("%s: DRIVE_CMD ", drive->name);
+ printk("cmd=0x%02x ", args[0]);
+ printk("sc=0x%02x ", args[1]);
+ printk("fr=0x%02x ", args[2]);
+ printk("xx=0x%02x\n", args[3]);
#endif
if (args[0] == WIN_SMART) {
OUT_BYTE(0x4f, IDE_LCYL_REG);
@@ -1203,17 +1137,18 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq
OUT_BYTE(args[2],IDE_FEATURE_REG);
ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
return ide_started;
- } else {
- /*
- * NULL is actually a valid way of waiting for
- * all current requests to be flushed from the queue.
- */
+ }
+
+args_error:
+ /*
+ * NULL is actually a valid way of waiting for
+ * all current requests to be flushed from the queue.
+ */
#ifdef DEBUG
- printk("%s: DRIVE_CMD (null)\n", drive->name);
+ printk("%s: DRIVE_CMD (null)\n", drive->name);
#endif
- ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
- return ide_stopped;
- }
+ ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
+ return ide_stopped;
}
/*
@@ -1264,7 +1199,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
return startstop;
}
if (!drive->special.all) {
- if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK))
+ if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE))
return execute_drive_cmd(drive, rq);
if (drive->driver != NULL) {
@@ -1384,7 +1319,7 @@ repeat:
* will start the next request from the queue. If no more work remains,
* the driver will clear the hwgroup->flags IDE_BUSY flag and exit.
*/
-static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
+static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
{
ide_drive_t *drive;
ide_hwif_t *hwif;
@@ -1986,6 +1921,10 @@ static int ide_open (struct inode * inode, struct file * filp)
(void) request_module("ide-tape");
if (drive->media == ide_floppy)
(void) request_module("ide-floppy");
+#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI)
+ if (drive->media == ide_scsi)
+ (void) request_module("ide-scsi");
+#endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */
}
#endif /* CONFIG_KMOD */
while (drive->busy)
@@ -2609,6 +2548,61 @@ int system_bus_clock (void)
return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
}
+int ide_reinit_drive (ide_drive_t *drive)
+{
+ switch (drive->media) {
+#ifdef CONFIG_BLK_DEV_IDECD
+ case ide_cdrom:
+ {
+ extern int ide_cdrom_reinit(ide_drive_t *drive);
+ if (ide_cdrom_reinit(drive))
+ return 1;
+ break;
+ }
+#endif /* CONFIG_BLK_DEV_IDECD */
+#ifdef CONFIG_BLK_DEV_IDEDISK
+ case ide_disk:
+ {
+ extern int idedisk_reinit(ide_drive_t *drive);
+ if (idedisk_reinit(drive))
+ return 1;
+ break;
+ }
+#endif /* CONFIG_BLK_DEV_IDEDISK */
+#ifdef CONFIG_BLK_DEV_IDEFLOPPY
+ case ide_floppy:
+ {
+ extern int idefloppy_reinit(ide_drive_t *drive);
+ if (idefloppy_reinit(drive))
+ return 1;
+ break;
+ }
+#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
+#ifdef CONFIG_BLK_DEV_IDETAPE
+ case ide_tape:
+ {
+ extern int idetape_reinit(ide_drive_t *drive);
+ if (idetape_reinit(drive))
+ return 1;
+ break;
+ }
+#endif /* CONFIG_BLK_DEV_IDETAPE */
+#ifdef CONFIG_BLK_DEV_IDESCSI
+/*
+ * {
+ * extern int idescsi_reinit(ide_drive_t *drive);
+ * if (idescsi_reinit(drive))
+ * return 1;
+ * break;
+ * }
+ */
+#endif /* CONFIG_BLK_DEV_IDESCSI */
+ default:
+ return 1;
+ }
+ return 0;
+}
+
static int ide_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -2695,57 +2689,35 @@ static int ide_ioctl (struct inode *inode, struct file *file,
drive->nice1 << IDE_NICE_1 |
drive->nice2 << IDE_NICE_2,
(long *) arg);
- case HDIO_DRIVE_CMD:
- {
- byte args[4], *argbuf = args;
- byte xfer_rate = 0;
- int argsize = 4;
- if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES;
- if (NULL == (void *) arg)
- return ide_do_drive_cmd(drive, &rq, ide_wait);
- if (copy_from_user(args, (void *)arg, 4))
- return -EFAULT;
- if (args[3]) {
- argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
- argbuf = kmalloc(argsize, GFP_KERNEL);
- if (argbuf == NULL)
- return -ENOMEM;
- memcpy(argbuf, args, 4);
- }
- if (set_transfer(drive, args[0], args[1], args[2])) {
- xfer_rate = args[1];
- if (ide_ata66_check(drive, args[0], args[1], args[2]))
- goto abort;
+#ifdef CONFIG_IDE_TASK_IOCTL
+ case HDIO_DRIVE_TASKFILE:
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+ return -EACCES;
+ switch(drive->media) {
+ case ide_disk:
+ return ide_taskfile_ioctl(drive, inode, file, cmd, arg);
+#ifdef CONFIG_PKT_TASK_IOCTL
+ case ide_cdrom:
+ case ide_tape:
+ case ide_floppy:
+ return pkt_taskfile_ioctl(drive, inode, file, cmd, arg);
+#endif /* CONFIG_PKT_TASK_IOCTL */
+ default:
+ return -ENOMSG;
}
+#endif /* CONFIG_IDE_TASK_IOCTL */
- err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
+ case HDIO_DRIVE_CMD:
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+ return -EACCES;
+ return ide_cmd_ioctl(drive, inode, file, cmd, arg);
- if (!err && xfer_rate) {
- /* active-retuning-calls future */
- if ((HWIF(drive)->speedproc) != NULL)
- HWIF(drive)->speedproc(drive, xfer_rate);
- ide_driveid_update(drive);
- }
- abort:
- if (copy_to_user((void *)arg, argbuf, argsize))
- err = -EFAULT;
- if (argsize > 4)
- kfree(argbuf);
- return err;
- }
case HDIO_DRIVE_TASK:
- {
- byte args[7], *argbuf = args;
- int argsize = 7;
- if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES;
- if (copy_from_user(args, (void *)arg, 7))
- return -EFAULT;
- err = ide_wait_cmd_task(drive, argbuf);
- if (copy_to_user((void *)arg, argbuf, argsize))
- err = -EFAULT;
- return err;
- }
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+ return -EACCES;
+ return ide_task_ioctl(drive, inode, file, cmd, arg);
+
case HDIO_SCAN_HWIF:
{
int args[3];
@@ -2775,7 +2747,24 @@ static int ide_ioctl (struct inode *inode, struct file *file,
drive->nice1 = (arg >> IDE_NICE_1) & 1;
return 0;
case HDIO_DRIVE_RESET:
+ {
+ unsigned long flags;
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+#if 1
+ spin_lock_irqsave(&ide_lock, flags);
+ if (hwgroup->handler != NULL) {
+ printk("%s: ide_set_handler: handler not null; %p\n", drive->name, hwgroup->handler);
+ (void) hwgroup->handler(drive);
+// hwgroup->handler = NULL;
+// hwgroup->expiry = NULL;
+ hwgroup->timer.expires = jiffies + 0;;
+ del_timer(&hwgroup->timer);
+ }
+ spin_unlock_irqrestore(&ide_lock, flags);
+
+#endif
(void) ide_do_reset(drive);
if (drive->suspend_reset) {
/*
@@ -2790,7 +2779,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
return ide_revalidate_disk(inode->i_rdev);
}
return 0;
-
+ }
case BLKGETSIZE:
case BLKGETSIZE64:
case BLKROSET:
@@ -2822,7 +2811,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (HWIF(drive)->busproc)
- HWIF(drive)->busproc(HWIF(drive), arg);
+ HWIF(drive)->busproc(drive, (int)arg);
return 0;
default:
@@ -3483,6 +3472,16 @@ static int default_cleanup (ide_drive_t *drive)
return ide_unregister_subdriver(drive);
}
+static int default_standby (ide_drive_t *drive)
+{
+ return 0;
+}
+
+static int default_flushcache (ide_drive_t *drive)
+{
+ return 0;
+}
+
static ide_startstop_t default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
{
ide_end_request(0, HWGROUP(drive));
@@ -3545,6 +3544,8 @@ static void setup_driver_defaults (ide_drive_t *drive)
ide_driver_t *d = drive->driver;
if (d->cleanup == NULL) d->cleanup = default_cleanup;
+ if (d->standby == NULL) d->standby = default_standby;
+ if (d->flushcache == NULL) d->flushcache = default_flushcache;
if (d->do_request == NULL) d->do_request = default_do_request;
if (d->end_request == NULL) d->end_request = default_end_request;
if (d->ioctl == NULL) d->ioctl = default_ioctl;
@@ -3696,10 +3697,6 @@ EXPORT_SYMBOL(ide_scan_devices);
EXPORT_SYMBOL(ide_register_subdriver);
EXPORT_SYMBOL(ide_unregister_subdriver);
EXPORT_SYMBOL(ide_replace_subdriver);
-EXPORT_SYMBOL(ide_input_data);
-EXPORT_SYMBOL(ide_output_data);
-EXPORT_SYMBOL(atapi_input_bytes);
-EXPORT_SYMBOL(atapi_output_bytes);
EXPORT_SYMBOL(ide_set_handler);
EXPORT_SYMBOL(ide_dump_status);
EXPORT_SYMBOL(ide_error);
@@ -3724,6 +3721,8 @@ EXPORT_SYMBOL(ide_add_proc_entries);
EXPORT_SYMBOL(ide_remove_proc_entries);
EXPORT_SYMBOL(proc_ide_read_geometry);
EXPORT_SYMBOL(create_proc_ide_interfaces);
+EXPORT_SYMBOL(recreate_proc_ide_device);
+EXPORT_SYMBOL(destroy_proc_ide_device);
#endif
EXPORT_SYMBOL(ide_add_setting);
EXPORT_SYMBOL(ide_remove_setting);
@@ -3738,6 +3737,54 @@ EXPORT_SYMBOL(current_capacity);
EXPORT_SYMBOL(system_bus_clock);
+EXPORT_SYMBOL(ide_reinit_drive);
+
+static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
+{
+ ide_hwif_t *hwif;
+ ide_drive_t *drive;
+ int i, unit;
+
+ switch (event) {
+ case SYS_HALT:
+ case SYS_POWER_OFF:
+ case SYS_RESTART:
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+
+ printk("flushing ide devices: ");
+
+ for (i = 0; i < MAX_HWIFS; i++) {
+ hwif = &ide_hwifs[i];
+ if (!hwif->present)
+ continue;
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ drive = &hwif->drives[unit];
+ if (!drive->present)
+ continue;
+
+ /* set the drive to standby */
+ printk("%s ", drive->name);
+ if (event != SYS_RESTART)
+ if (drive->driver != NULL && DRIVER(drive)->standby(drive))
+ continue;
+
+ if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+ continue;
+ }
+ }
+ printk("\n");
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block ide_notifier = {
+ ide_notify_reboot,
+ NULL,
+ 5
+};
+
/*
* This is gets invoked once during initialization, to set *everything* up
*/
@@ -3765,6 +3812,7 @@ int __init ide_init (void)
ide_geninit(hwif);
}
+ register_reboot_notifier(&ide_notifier);
return 0;
}
@@ -3797,6 +3845,7 @@ void cleanup_module (void)
{
int index;
+ unregister_reboot_notifier(&ide_notifier);
for (index = 0; index < MAX_HWIFS; ++index) {
ide_unregister(index);
#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
diff --git a/drivers/ide/pdc202xx.c b/drivers/ide/pdc202xx.c
index eedad0daa..b614fd319 100644
--- a/drivers/ide/pdc202xx.c
+++ b/drivers/ide/pdc202xx.c
@@ -108,7 +108,7 @@ static char * pdc202xx_info (char *buf, struct pci_dev *dev)
u32 bibma = pci_resource_start(dev, 4);
u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
u16 reg50h = 0, pmask = (1<<10), smask = (1<<11);
- u8 hi = 0, lo = 0, invalid_data_set = 0;
+ u8 hi = 0, lo = 0;
/*
* at that point bibma+0x2 et bibma+0xa are byte registers
@@ -132,11 +132,6 @@ static char * pdc202xx_info (char *buf, struct pci_dev *dev)
pci_read_config_dword(dev, 0x6c, &reg6ch);
switch(dev->device) {
- case PCI_DEVICE_ID_PROMISE_20268:
- case PCI_DEVICE_ID_PROMISE_20268R:
- p += sprintf(p, "\n PDC20268 TX2 Chipset.\n");
- invalid_data_set = 1;
- break;
case PCI_DEVICE_ID_PROMISE_20267:
p += sprintf(p, "\n PDC20267 Chipset.\n");
break;
@@ -180,45 +175,77 @@ static char * pdc202xx_info (char *buf, struct pci_dev *dev)
p += sprintf(p, " Mode %s Mode %s\n",
(sc1a & 0x01) ? "MASTER" : "PCI ",
(sc1b & 0x01) ? "MASTER" : "PCI ");
- if (!(invalid_data_set))
- p += sprintf(p, " %s %s\n",
- (sc1d & 0x08) ? "Error " :
- ((sc1d & 0x05) == 0x05) ? "Not My INTR " :
- (sc1d & 0x04) ? "Interrupting" :
- (sc1d & 0x02) ? "FIFO Full " :
- (sc1d & 0x01) ? "FIFO Empty " : "????????????",
- (sc1d & 0x80) ? "Error " :
- ((sc1d & 0x50) == 0x50) ? "Not My INTR " :
- (sc1d & 0x40) ? "Interrupting" :
- (sc1d & 0x20) ? "FIFO Full " :
- (sc1d & 0x10) ? "FIFO Empty " : "????????????");
+ p += sprintf(p, " %s %s\n",
+ (sc1d & 0x08) ? "Error " :
+ ((sc1d & 0x05) == 0x05) ? "Not My INTR " :
+ (sc1d & 0x04) ? "Interrupting" :
+ (sc1d & 0x02) ? "FIFO Full " :
+ (sc1d & 0x01) ? "FIFO Empty " : "????????????",
+ (sc1d & 0x80) ? "Error " :
+ ((sc1d & 0x50) == 0x50) ? "Not My INTR " :
+ (sc1d & 0x40) ? "Interrupting" :
+ (sc1d & 0x20) ? "FIFO Full " :
+ (sc1d & 0x10) ? "FIFO Empty " : "????????????");
p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
p += sprintf(p, "DMA enabled: %s %s %s %s\n",
(c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ",(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
- if (!(invalid_data_set))
- p += sprintf(p, "DMA Mode: %s %s %s %s\n",
- pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
- pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
- pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
- pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
- if (!(invalid_data_set))
- p += sprintf(p, "PIO Mode: %s %s %s %s\n",
- pdc202xx_pio_verbose(reg60h),
- pdc202xx_pio_verbose(reg64h),
- pdc202xx_pio_verbose(reg68h),
- pdc202xx_pio_verbose(reg6ch));
+ p += sprintf(p, "DMA Mode: %s %s %s %s\n",
+ pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
+ pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
+ pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
+ pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
+ p += sprintf(p, "PIO Mode: %s %s %s %s\n",
+ pdc202xx_pio_verbose(reg60h),
+ pdc202xx_pio_verbose(reg64h),
+ pdc202xx_pio_verbose(reg68h),
+ pdc202xx_pio_verbose(reg6ch));
#if 0
p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n");
#endif
- if (invalid_data_set)
- p += sprintf(p, "--------------- Cannot Decode HOST ---------------\n");
+ return (char *)p;
+}
+
+static char * pdc202xx_info_new (char *buf, struct pci_dev *dev)
+{
+ char *p = buf;
+// u32 bibma = pci_resource_start(dev, 4);
+
+// u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
+// u16 reg50h = 0, word88 = 0;
+// int udmasel[4]={0,0,0,0}, piosel[4]={0,0,0,0}, i=0, hd=0;
+
+ switch(dev->device) {
+ case PCI_DEVICE_ID_PROMISE_20275:
+ p += sprintf(p, "\n PDC20275 Chipset.\n");
+ break;
+ case PCI_DEVICE_ID_PROMISE_20269:
+ p += sprintf(p, "\n PDC20269 TX2 Chipset.\n");
+ break;
+ case PCI_DEVICE_ID_PROMISE_20268:
+ case PCI_DEVICE_ID_PROMISE_20268R:
+ p += sprintf(p, "\n PDC20268 TX2 Chipset.\n");
+ break;
+default:
+ p += sprintf(p, "\n PDC202XX Chipset.\n");
+ break;
+ }
return (char *)p;
}
static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count)
{
char *p = buffer;
- p = pdc202xx_info(buffer, bmide_dev);
+ switch(bmide_dev->device) {
+ case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20269:
+ case PCI_DEVICE_ID_PROMISE_20268:
+ case PCI_DEVICE_ID_PROMISE_20268R:
+ p = pdc202xx_info_new(buffer, bmide_dev);
+ break;
+ default:
+ p = pdc202xx_info(buffer, bmide_dev);
+ break;
+ }
return p-buffer; /* => must be less than 4k! */
}
#endif /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
@@ -387,9 +414,6 @@ static int pdc202xx_tune_chipset (ide_drive_t *drive, byte speed)
if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0)) return -1;
- if (dev->device == PCI_DEVICE_ID_PROMISE_20268)
- goto skip_register_hell;
-
pci_read_config_dword(dev, drive_pci, &drive_conf);
pci_read_config_byte(dev, (drive_pci), &AP);
pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
@@ -432,6 +456,7 @@ static int pdc202xx_tune_chipset (ide_drive_t *drive, byte speed)
switch(speed) {
#ifdef CONFIG_BLK_DEV_IDEDMA
+ /* case XFER_UDMA_6: */
case XFER_UDMA_5:
case XFER_UDMA_4: TB = 0x20; TC = 0x01; break; /* speed 8 == UDMA mode 4 */
case XFER_UDMA_3: TB = 0x40; TC = 0x02; break; /* speed 7 == UDMA mode 3 */
@@ -477,8 +502,6 @@ static int pdc202xx_tune_chipset (ide_drive_t *drive, byte speed)
decode_registers(REG_D, DP);
#endif /* PDC202XX_DECODE_REGISTER_INFO */
-skip_register_hell:
-
if (!drive->init_speed)
drive->init_speed = speed;
err = ide_config_drive_speed(drive, speed);
@@ -494,6 +517,159 @@ skip_register_hell:
return err;
}
+static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ unsigned long indexreg = (hwif->dma_base + 1);
+ unsigned long datareg = (hwif->dma_base + 3);
+#else
+ struct pci_dev *dev = hwif->pci_dev;
+ unsigned long high_16 = pci_resource_start(dev, 4);
+ unsigned long indexreg = high_16 + (hwif->channel ? 0x09 : 0x01);
+ unsigned long datareg = (indexreg + 2);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+ byte thold = 0x10;
+ byte adj = (drive->dn%2) ? 0x08 : 0x00;
+
+ int err;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (speed == XFER_UDMA_2) {
+ OUT_BYTE((thold + adj), indexreg);
+ OUT_BYTE((IN_BYTE(datareg) & 0x7f), datareg);
+ }
+ switch (speed) {
+ case XFER_UDMA_7:
+ speed = XFER_UDMA_6;
+ case XFER_UDMA_6:
+ OUT_BYTE((0x10 + adj), indexreg);
+ OUT_BYTE(0x1a, datareg);
+ OUT_BYTE((0x11 + adj), indexreg);
+ OUT_BYTE(0x01, datareg);
+ OUT_BYTE((0x12 + adj), indexreg);
+ OUT_BYTE(0xcb, datareg);
+ break;
+ case XFER_UDMA_5:
+ OUT_BYTE((0x10 + adj), indexreg);
+ OUT_BYTE(0x1a, datareg);
+ OUT_BYTE((0x11 + adj), indexreg);
+ OUT_BYTE(0x02, datareg);
+ OUT_BYTE((0x12 + adj), indexreg);
+ OUT_BYTE(0xcb, datareg);
+ break;
+ case XFER_UDMA_4:
+ OUT_BYTE((0x10 + adj), indexreg);
+ OUT_BYTE(0x1a, datareg);
+ OUT_BYTE((0x11 + adj), indexreg);
+ OUT_BYTE(0x03, datareg);
+ OUT_BYTE((0x12 + adj), indexreg);
+ OUT_BYTE(0xcd, datareg);
+ break;
+ case XFER_UDMA_3:
+ OUT_BYTE((0x10 + adj), indexreg);
+ OUT_BYTE(0x1a, datareg);
+ OUT_BYTE((0x11 + adj), indexreg);
+ OUT_BYTE(0x05, datareg);
+ OUT_BYTE((0x12 + adj), indexreg);
+ OUT_BYTE(0xcd, datareg);
+ break;
+ case XFER_UDMA_2:
+ OUT_BYTE((0x10 + adj), indexreg);
+ OUT_BYTE(0x2a, datareg);
+ OUT_BYTE((0x11 + adj), indexreg);
+ OUT_BYTE(0x07, datareg);
+ OUT_BYTE((0x12 + adj), indexreg);
+ OUT_BYTE(0xcd, datareg);
+ break;
+ case XFER_UDMA_1:
+ OUT_BYTE((0x10 + adj), indexreg);
+ OUT_BYTE(0x3a, datareg);
+ OUT_BYTE((0x11 + adj), indexreg);
+ OUT_BYTE(0x0a, datareg);
+ OUT_BYTE((0x12 + adj), indexreg);
+ OUT_BYTE(0xd0, datareg);
+ break;
+ case XFER_UDMA_0:
+ OUT_BYTE((0x10 + adj), indexreg);
+ OUT_BYTE(0x4a, datareg);
+ OUT_BYTE((0x11 + adj), indexreg);
+ OUT_BYTE(0x0f, datareg);
+ OUT_BYTE((0x12 + adj), indexreg);
+ OUT_BYTE(0xd5, datareg);
+ break;
+ case XFER_MW_DMA_2:
+ OUT_BYTE((0x0e + adj), indexreg);
+ OUT_BYTE(0x69, datareg);
+ OUT_BYTE((0x0f + adj), indexreg);
+ OUT_BYTE(0x25, datareg);
+ break;
+ case XFER_MW_DMA_1:
+ OUT_BYTE((0x0e + adj), indexreg);
+ OUT_BYTE(0x6b, datareg);
+ OUT_BYTE((0x0f+ adj), indexreg);
+ OUT_BYTE(0x27, datareg);
+ break;
+ case XFER_MW_DMA_0:
+ OUT_BYTE((0x0e + adj), indexreg);
+ OUT_BYTE(0xdf, datareg);
+ OUT_BYTE((0x0f + adj), indexreg);
+ OUT_BYTE(0x5f, datareg);
+ break;
+#else
+ switch (speed) {
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+ case XFER_PIO_4:
+ OUT_BYTE((0x0c + adj), indexreg);
+ OUT_BYTE(0x23, datareg);
+ OUT_BYTE((0x0d + adj), indexreg);
+ OUT_BYTE(0x09, datareg);
+ OUT_BYTE((0x13 + adj), indexreg);
+ OUT_BYTE(0x25, datareg);
+ break;
+ case XFER_PIO_3:
+ OUT_BYTE((0x0c + adj), indexreg);
+ OUT_BYTE(0x27, datareg);
+ OUT_BYTE((0x0d + adj), indexreg);
+ OUT_BYTE(0x0d, datareg);
+ OUT_BYTE((0x13 + adj), indexreg);
+ OUT_BYTE(0x35, datareg);
+ break;
+ case XFER_PIO_2:
+ OUT_BYTE((0x0c + adj), indexreg);
+ OUT_BYTE(0x23, datareg);
+ OUT_BYTE((0x0d + adj), indexreg);
+ OUT_BYTE(0x26, datareg);
+ OUT_BYTE((0x13 + adj), indexreg);
+ OUT_BYTE(0x64, datareg);
+ break;
+ case XFER_PIO_1:
+ OUT_BYTE((0x0c + adj), indexreg);
+ OUT_BYTE(0x46, datareg);
+ OUT_BYTE((0x0d + adj), indexreg);
+ OUT_BYTE(0x29, datareg);
+ OUT_BYTE((0x13 + adj), indexreg);
+ OUT_BYTE(0xa4, datareg);
+ break;
+ case XFER_PIO_0:
+ OUT_BYTE((0x0c + adj), indexreg);
+ OUT_BYTE(0xfb, datareg);
+ OUT_BYTE((0x0d + adj), indexreg);
+ OUT_BYTE(0x2b, datareg);
+ OUT_BYTE((0x13 + adj), indexreg);
+ OUT_BYTE(0xac, datareg);
+ break;
+ default:
+ }
+
+ if (!drive->init_speed)
+ drive->init_speed = speed;
+ err = ide_config_drive_speed(drive, speed);
+ drive->current_speed = speed;
+
+ return err;
+}
+
/* 0 1 2 3 4 5 6 7 8
* 960, 480, 390, 300, 240, 180, 120, 90, 60
* 180, 150, 120, 90, 60
@@ -524,18 +700,75 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
struct pci_dev *dev = hwif->pci_dev;
unsigned long high_16 = pci_resource_start(dev, 4);
unsigned long dma_base = hwif->dma_base;
+ unsigned long indexreg = dma_base + 1;
+ unsigned long datareg = dma_base + 3;
+ byte iordy = 0x13;
+ byte adj = (drive->dn%2) ? 0x08 : 0x00;
+ byte cable = 0;
+ byte jumpbit = 0;
byte unit = (drive->select.b.unit & 0x01);
-
unsigned int drive_conf;
- byte drive_pci;
+ byte drive_pci = 0;
byte test1, test2, speed = -1;
byte AP;
unsigned short EP;
- byte CLKSPD = IN_BYTE(high_16 + 0x11);
- byte udma_33 = ultra ? (inb(high_16 + 0x001f) & 1) : 0;
+ byte CLKSPD = 0;
+ byte udma_33 = ultra;
+// byte udma_33 = ultra ? (IN_BYTE(high_16 + 0x001f) & 1) : 0;
byte udma_66 = ((eighty_ninty_three(drive)) && udma_33) ? 1 : 0;
- byte udma_100 = (((dev->device == PCI_DEVICE_ID_PROMISE_20265) || (dev->device == PCI_DEVICE_ID_PROMISE_20267) || (dev->device == PCI_DEVICE_ID_PROMISE_20268)) && udma_66) ? 1 : 0;
+ byte udma_100 = 0;
+ byte udma_133 = 0;
+ byte mask = hwif->channel ? 0x08 : 0x02;
+ unsigned short c_mask = hwif->channel ? (1<<11) : (1<<10);
+
+ byte ultra_66 = ((id->dma_ultra & 0x0010) ||
+ (id->dma_ultra & 0x0008)) ? 1 : 0;
+ byte ultra_100 = ((id->dma_ultra & 0x0020) ||
+ (ultra_66)) ? 1 : 0;
+ byte ultra_133 = ((id->dma_ultra & 0x0040) ||
+ (ultra_100)) ? 1 : 0;
+
+ switch(dev->device) {
+ case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20269:
+ udma_133 = (udma_66) ? 1 : 0;
+ udma_100 = (udma_66) ? 1 : 0;
+ OUT_BYTE(0x0b, (hwif->dma_base + 1));
+ cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
+ jumpbit = 1;
+ break;
+ case PCI_DEVICE_ID_PROMISE_20268R:
+ udma_100 = 1;
+ udma_66 = 1;
+ OUT_BYTE(0x0b, (hwif->dma_base + 1));
+ cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
+ jumpbit = 1;
+ break;
+ case PCI_DEVICE_ID_PROMISE_20268:
+ udma_100 = (udma_66) ? 1 : 0;
+ OUT_BYTE(0x0b, (hwif->dma_base + 1));
+ cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
+ jumpbit = 1;
+ break;
+ case PCI_DEVICE_ID_PROMISE_20267:
+ case PCI_DEVICE_ID_PROMISE_20265:
+ udma_100 = (udma_66) ? 1 : 0;
+ pci_read_config_word(dev, 0x50, &EP);
+ cable = (EP & c_mask);
+ jumpbit = 0;
+ break;
+ case PCI_DEVICE_ID_PROMISE_20262:
+ pci_read_config_word(dev, 0x50, &EP);
+ cable = (EP & c_mask);
+ jumpbit = 0;
+ break;
+ default:
+ udma_100 = 0; udma_133 = 0; cable = 1; jumpbit = 0;
+ break;
+ }
+ if (!jumpbit)
+ CLKSPD = IN_BYTE(high_16 + 0x11);
/*
* Set the control register to use the 66Mhz system
* clock for UDMA 3/4 mode operation. If one drive on
@@ -549,47 +782,52 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
* parameters.
*/
- byte mask = hwif->channel ? 0x08 : 0x02;
- unsigned short c_mask = hwif->channel ? (1<<11) : (1<<10);
- byte ultra_66 = ((id->dma_ultra & 0x0010) ||
- (id->dma_ultra & 0x0008)) ? 1 : 0;
- byte ultra_100 = ((id->dma_ultra & 0x0020) ||
- (id->dma_ultra & 0x0010) ||
- (id->dma_ultra & 0x0008)) ? 1 : 0;
-
- if (dev->device == PCI_DEVICE_ID_PROMISE_20268)
- goto jump_pci_mucking;
-
- pci_read_config_word(dev, 0x50, &EP);
-
- if (((ultra_66) || (ultra_100)) && (EP & c_mask)) {
+ if (((ultra_66) || (ultra_100) || (ultra_133)) && (cable)) {
#ifdef DEBUG
printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->channel ? "Secondary" : "Primary");
printk(" Switching to Ultra33 mode.\n");
#endif /* DEBUG */
/* Primary : zero out second bit */
/* Secondary : zero out fourth bit */
- OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+ if (!jumpbit)
+ OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+ printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+ printk("%s reduced to Ultra33 mode.\n", drive->name);
+ udma_66 = 0; udma_100 = 0; udma_133 = 0;
} else {
- if ((ultra_66) || (ultra_100)) {
+ if ((ultra_66) || (ultra_100) || (ultra_133)) {
/*
* check to make sure drive on same channel
* is u66 capable
*/
if (hwif->drives[!(drive->dn%2)].id) {
- if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0020) ||
+ if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0040) ||
+ (hwif->drives[!(drive->dn%2)].id->dma_ultra
+& 0x0020) ||
(hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0010) ||
(hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0008)) {
- OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
+ if (!jumpbit)
+ OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
} else {
- OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+ if (!jumpbit)
+ OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
}
} else { /* udma4 drive by itself */
- OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
+ if (!jumpbit)
+ OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
}
}
}
+ if (jumpbit) {
+ if (drive->media != ide_disk) return ide_dma_off_quietly;
+ if (id->capability & 4) { /* IORDY_EN & PREFETCH_EN */
+ OUT_BYTE((iordy + adj), indexreg);
+ OUT_BYTE((IN_BYTE(datareg)|0x03), datareg);
+ }
+ goto jumpbit_is_set;
+ }
+
switch(drive->dn) {
case 0: drive_pci = 0x60;
pci_read_config_dword(dev, drive_pci, &drive_conf);
@@ -640,31 +878,33 @@ chipset_is_set:
if (drive->media == ide_disk) /* PREFETCH_EN */
pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
-jump_pci_mucking:
+jumpbit_is_set:
- if ((id->dma_ultra & 0x0020) && (udma_100)) speed = XFER_UDMA_5;
- else if ((id->dma_ultra & 0x0010) && (udma_66)) speed = XFER_UDMA_4;
- else if ((id->dma_ultra & 0x0008) && (udma_66)) speed = XFER_UDMA_3;
- else if ((id->dma_ultra & 0x0004) && (udma_33)) speed = XFER_UDMA_2;
- else if ((id->dma_ultra & 0x0002) && (udma_33)) speed = XFER_UDMA_1;
- else if ((id->dma_ultra & 0x0001) && (udma_33)) speed = XFER_UDMA_0;
+ if ((id->dma_ultra & 0x0040)&&(udma_133)) speed = XFER_UDMA_6;
+ else if ((id->dma_ultra & 0x0020)&&(udma_100)) speed = XFER_UDMA_5;
+ else if ((id->dma_ultra & 0x0010)&&(udma_66)) speed = XFER_UDMA_4;
+ else if ((id->dma_ultra & 0x0008)&&(udma_66)) speed = XFER_UDMA_3;
+ else if ((id->dma_ultra & 0x0004)&&(udma_33)) speed = XFER_UDMA_2;
+ else if ((id->dma_ultra & 0x0002)&&(udma_33)) speed = XFER_UDMA_1;
+ else if ((id->dma_ultra & 0x0001)&&(udma_33)) speed = XFER_UDMA_0;
else if (id->dma_mword & 0x0004) speed = XFER_MW_DMA_2;
else if (id->dma_mword & 0x0002) speed = XFER_MW_DMA_1;
else if (id->dma_mword & 0x0001) speed = XFER_MW_DMA_0;
- else if (id->dma_1word & 0x0004) speed = XFER_SW_DMA_2;
- else if (id->dma_1word & 0x0002) speed = XFER_SW_DMA_1;
- else if (id->dma_1word & 0x0001) speed = XFER_SW_DMA_0;
+ else if ((id->dma_1word & 0x0004)&&(!jumpbit)) speed = XFER_SW_DMA_2;
+ else if ((id->dma_1word & 0x0002)&&(!jumpbit)) speed = XFER_SW_DMA_1;
+ else if ((id->dma_1word & 0x0001)&&(!jumpbit)) speed = XFER_SW_DMA_0;
else {
/* restore original pci-config space */
- if (dev->device != PCI_DEVICE_ID_PROMISE_20268)
+ if (!jumpbit)
pci_write_config_dword(dev, drive_pci, drive_conf);
return ide_dma_off_quietly;
}
outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
- (void) pdc202xx_tune_chipset(drive, speed);
+ (void) hwif->speedproc(drive, speed);
- return ((int) ((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+ return ((int) ((id->dma_ultra >> 14) & 3) ? ide_dma_on :
+ ((id->dma_ultra >> 11) & 7) ? ide_dma_on :
((id->dma_ultra >> 8) & 7) ? ide_dma_on :
((id->dma_mword >> 8) & 7) ? ide_dma_on :
((id->dma_1word >> 8) & 7) ? ide_dma_on :
@@ -685,7 +925,7 @@ static int config_drive_xfer_rate (ide_drive_t *drive)
}
dma_func = ide_dma_off_quietly;
if (id->field_valid & 4) {
- if (id->dma_ultra & 0x002F) {
+ if (id->dma_ultra & 0x007F) {
/* Force if Capable UltraDMA */
dma_func = config_chipset_for_dma(drive, 1);
if ((id->field_valid & 2) &&
@@ -732,16 +972,65 @@ int pdc202xx_quirkproc (ide_drive_t *drive)
*/
int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
- byte dma_stat = 0, sc1d = 0;
- unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4);
- unsigned long dma_base = HWIF(drive)->dma_base;
+ byte dma_stat = 0;
+ byte sc1d = 0;
+ byte newchip = 0;
+ byte clock = 0;
+ byte hardware48hack = 0;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ unsigned long high_16 = pci_resource_start(dev, 4);
+ unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x00);
+ unsigned long dma_base = hwif->dma_base;
+
+ switch (dev->device) {
+ case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20269:
+ case PCI_DEVICE_ID_PROMISE_20268R:
+ case PCI_DEVICE_ID_PROMISE_20268:
+ newchip = 1;
+ break;
+ case PCI_DEVICE_ID_PROMISE_20267:
+ case PCI_DEVICE_ID_PROMISE_20265:
+ case PCI_DEVICE_ID_PROMISE_20262:
+ hardware48hack = 1;
+ clock = IN_BYTE(high_16 + 0x11);
+ default:
+ break;
+ }
switch (func) {
case ide_dma_check:
return config_drive_xfer_rate(drive);
+ case ide_dma_begin:
+ /* Note that this is done *after* the cmd has
+ * been issued to the drive, as per the BM-IDE spec.
+ * The Promise Ultra33 doesn't work correctly when
+ * we do this part before issuing the drive cmd.
+ */
+ if ((drive->addressing) && (hardware48hack)) {
+ struct request *rq = HWGROUP(drive)->rq;
+ unsigned long word_count = 0;
+
+ outb(clock|(hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
+ word_count = (rq->nr_sectors << 8);
+ word_count = (rq_data_dir(rq) == READ) ? word_count | 0x05000000 : word_count | 0x06000000;
+ outl(word_count, atapi_reg);
+ }
+ break;
+ case ide_dma_end:
+ if ((drive->addressing) && (hardware48hack)) {
+ outl(0, atapi_reg); /* zero out extra */
+ clock = IN_BYTE(high_16 + 0x11);
+ OUT_BYTE(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
+ }
+ break;
case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
- dma_stat = inb(dma_base+2);
- sc1d = inb(high_16 + 0x001d);
+ dma_stat = IN_BYTE(dma_base+2);
+ if (newchip)
+ return (dma_stat & 4) == 4;
+
+ sc1d = IN_BYTE(high_16 + 0x001d);
if (HWIF(drive)->channel) {
if ((sc1d & 0x50) == 0x50) goto somebody_else;
else if ((sc1d & 0x40) == 0x40)
@@ -764,61 +1053,113 @@ somebody_else:
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
+void pdc202xx_new_reset (ide_drive_t *drive)
+{
+ OUT_BYTE(0x04,IDE_CONTROL_REG);
+ mdelay(1000);
+ OUT_BYTE(0x00,IDE_CONTROL_REG);
+ mdelay(1000);
+ printk("PDC202XX: %s channel reset.\n",
+ HWIF(drive)->channel ? "Secondary" : "Primary");
+}
+
void pdc202xx_reset (ide_drive_t *drive)
{
unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4);
- byte udma_speed_flag = inb(high_16 + 0x001f);
+ byte udma_speed_flag = IN_BYTE(high_16 + 0x001f);
OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
mdelay(100);
OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
mdelay(2000); /* 2 seconds ?! */
+ printk("PDC202XX: %s channel reset.\n",
+ HWIF(drive)->channel ? "Secondary" : "Primary");
}
-unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+static int pdc202xx_tristate (ide_drive_t * drive, int state)
{
- unsigned long high_16 = pci_resource_start(dev, 4);
- byte udma_speed_flag = inb(high_16 + 0x001f);
- byte primary_mode = inb(high_16 + 0x001a);
- byte secondary_mode = inb(high_16 + 0x001b);
-
- if ((dev->device == PCI_DEVICE_ID_PROMISE_20262) ||
- (dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
- (dev->device == PCI_DEVICE_ID_PROMISE_20267)) {
- /*
- * software reset - this is required because the bios
- * will set UDMA timing on if the hdd supports it. The
- * user may want to turn udma off. A bug in the pdc20262
- * is that it cannot handle a downgrade in timing from UDMA
- * to DMA. Disk accesses after issuing a set feature command
- * will result in errors. A software reset leaves the timing
- * registers intact, but resets the drives.
- */
-
- OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
- mdelay(100);
- OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
- mdelay(2000); /* 2 seconds ?! */
+#if 0
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long high_16 = pci_resource_start(hwif->pci_dev, 4);
+ byte sc1f = inb(high_16 + 0x001f);
+
+ if (!hwif)
+ return -EINVAL;
+
+// hwif->bus_state = state;
+
+ if (state) {
+ outb(sc1f | 0x08, high_16 + 0x001f);
+ } else {
+ outb(sc1f & ~0x08, high_16 + 0x001f);
}
+#endif
+ return 0;
+}
+
+unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
+{
+ unsigned long high_16 = pci_resource_start(dev, 4);
+ byte udma_speed_flag = IN_BYTE(high_16 + 0x001f);
+ byte primary_mode = IN_BYTE(high_16 + 0x001a);
+ byte secondary_mode = IN_BYTE(high_16 + 0x001b);
+ byte newchip = 0;
if (dev->resource[PCI_ROM_RESOURCE].start) {
pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
}
- if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
- byte irq = 0, irq2 = 0;
- pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
- pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2); /* 0xbc */
- if ((irq != irq2) &&
- (dev->device != PCI_DEVICE_ID_PROMISE_20265) &&
- (dev->device != PCI_DEVICE_ID_PROMISE_20267) &&
- (dev->device != PCI_DEVICE_ID_PROMISE_20268)) {
- pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */
- printk("%s: pci-config space interrupt mirror fixed.\n", name);
- }
+ switch (dev->device) {
+ case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20269:
+ case PCI_DEVICE_ID_PROMISE_20268R:
+ case PCI_DEVICE_ID_PROMISE_20268:
+ newchip = 1;
+ break;
+ case PCI_DEVICE_ID_PROMISE_20267:
+ case PCI_DEVICE_ID_PROMISE_20265:
+ OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
+ mdelay(100);
+ OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
+ mdelay(2000); /* 2 seconds ?! */
+ break;
+ case PCI_DEVICE_ID_PROMISE_20262:
+ /*
+ * software reset - this is required because the bios
+ * will set UDMA timing on if the hdd supports it. The
+ * user may want to turn udma off. A bug in the pdc20262
+ * is that it cannot handle a downgrade in timing from
+ * UDMA to DMA. Disk accesses after issuing a set
+ * feature command will result in errors. A software
+ * reset leaves the timing registers intact,
+ * but resets the drives.
+ */
+ OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
+ mdelay(100);
+ OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
+ mdelay(2000); /* 2 seconds ?! */
+ default:
+ if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
+ byte irq = 0, irq2 = 0;
+ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+ pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2); /* 0xbc */
+ if (irq != irq2) {
+ pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */
+ printk("%s: pci-config space interrupt mirror fixed.\n", name);
+ }
+ }
+ break;
}
+ if (newchip)
+ goto fttk_tx_series;
+
printk("%s: (U)DMA Burst Bit %sABLED " \
"Primary %s Mode " \
"Secondary %s Mode.\n",
@@ -830,8 +1171,8 @@ unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
#ifdef CONFIG_PDC202XX_BURST
if (!(udma_speed_flag & 1)) {
printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1));
- outb(udma_speed_flag|1, high_16 + 0x001f);
- printk("%sCTIVE\n", (inb(high_16 + 0x001f) & 1) ? "A" : "INA");
+ OUT_BYTE(udma_speed_flag|1, high_16 + 0x001f);
+ printk("%sCTIVE\n", (IN_BYTE(high_16 + 0x001f) & 1) ? "A" : "INA");
}
#endif /* CONFIG_PDC202XX_BURST */
@@ -839,18 +1180,20 @@ unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
if (!(primary_mode & 1)) {
printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ",
name, primary_mode, (primary_mode|1));
- outb(primary_mode|1, high_16 + 0x001a);
- printk("%s\n", (inb(high_16 + 0x001a) & 1) ? "MASTER" : "PCI");
+ OUT_BYTE(primary_mode|1, high_16 + 0x001a);
+ printk("%s\n", (IN_BYTE(high_16 + 0x001a) & 1) ? "MASTER" : "PCI");
}
if (!(secondary_mode & 1)) {
printk("%s: FORCING SECONDARY MODE BIT 0x%02x -> 0x%02x ",
name, secondary_mode, (secondary_mode|1));
- outb(secondary_mode|1, high_16 + 0x001b);
- printk("%s\n", (inb(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
+ OUT_BYTE(secondary_mode|1, high_16 + 0x001b);
+ printk("%s\n", (IN_BYTE(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
}
#endif /* CONFIG_PDC202XX_MASTER */
+fttk_tx_series:
+
#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
if (!pdc202xx_proc) {
pdc202xx_proc = 1;
@@ -866,20 +1209,41 @@ unsigned int __init ata66_pdc202xx (ide_hwif_t *hwif)
unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10);
unsigned short CIS;
- pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
- return ((CIS & mask) ? 0 : 1);
+ switch(hwif->pci_dev->device) {
+ case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20269:
+ case PCI_DEVICE_ID_PROMISE_20268:
+ case PCI_DEVICE_ID_PROMISE_20268R:
+ OUT_BYTE(0x0b, (hwif->dma_base + 1));
+ return (!(IN_BYTE((hwif->dma_base + 3)) & 0x04));
+ default:
+ pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
+ return (!(CIS & mask));
+ }
}
void __init ide_init_pdc202xx (ide_hwif_t *hwif)
{
- hwif->tuneproc = &pdc202xx_tune_drive;
- hwif->speedproc = &pdc202xx_tune_chipset;
- hwif->quirkproc = &pdc202xx_quirkproc;
-
- if ((hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20262) ||
- (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
- (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20267)) {
- hwif->resetproc = &pdc202xx_reset;
+ hwif->tuneproc = &pdc202xx_tune_drive;
+ hwif->quirkproc = &pdc202xx_quirkproc;
+
+ switch(hwif->pci_dev->device) {
+ case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20269:
+ case PCI_DEVICE_ID_PROMISE_20268:
+ case PCI_DEVICE_ID_PROMISE_20268R:
+ hwif->speedproc = &pdc202xx_new_tune_chipset;
+ hwif->resetproc = &pdc202xx_new_reset;
+ break;
+ case PCI_DEVICE_ID_PROMISE_20267:
+ case PCI_DEVICE_ID_PROMISE_20265:
+ case PCI_DEVICE_ID_PROMISE_20262:
+ hwif->busproc = &pdc202xx_tristate;
+ hwif->resetproc = &pdc202xx_reset;
+ case PCI_DEVICE_ID_PROMISE_20246:
+ hwif->speedproc = &pdc202xx_tune_chipset;
+ default:
+ break;
}
#undef CONFIG_PDC202XX_32_UNMASK
diff --git a/drivers/ide/pdc4030.c b/drivers/ide/pdc4030.c
index abafb7afa..4cde788ca 100644
--- a/drivers/ide/pdc4030.c
+++ b/drivers/ide/pdc4030.c
@@ -183,7 +183,7 @@ int __init setup_pdc4030 (ide_hwif_t *hwif)
"%s: Failed Promise read config!\n",hwif->name);
return 0;
}
- ide_input_data(drive,&ident,SECTOR_WORDS);
+ ata_input_data(drive, &ident, SECTOR_WORDS);
if (ident.id[1] != 'P' || ident.id[0] != 'T') {
return 0;
}
@@ -300,8 +300,6 @@ void __init ide_probe_for_pdc4030(void)
}
}
-
-
/*
* promise_read_intr() is the handler for disk read/multread interrupts
*/
@@ -335,7 +333,7 @@ read_next:
nsect = sectors_avail;
sectors_avail -= nsect;
to = ide_map_buffer(rq, &flags);
- idedisk_input_data(drive, to, nsect * SECTOR_WORDS);
+ ata_input_data(drive, to, nsect * SECTOR_WORDS);
#ifdef DEBUG_READ
printk(KERN_DEBUG "%s: promise_read: sectors(%ld-%ld), "
"buf=0x%08lx, rem=%ld\n", drive->name, rq->sector,
@@ -393,7 +391,6 @@ static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive)
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
struct request *rq = hwgroup->rq;
- int i;
if (GET_STAT() & BUSY_STAT) {
if (time_before(jiffies, hwgroup->poll_timeout)) {
@@ -415,6 +412,61 @@ static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive)
}
/*
+ * promise_multwrite() transfers a block of up to mcount sectors of data
+ * to a drive as part of a disk multiple-sector write operation.
+ *
+ * Returns 0 on success.
+ *
+ * Note that we may be called from two contexts - the do_rw_disk context
+ * and IRQ context. The IRQ can happen any time after we've output the
+ * full "mcount" number of sectors, so we must make sure we update the
+ * state _before_ we output the final part of the data!
+ */
+int promise_multwrite (ide_drive_t *drive, unsigned int mcount)
+{
+ ide_hwgroup_t *hwgroup= HWGROUP(drive);
+ struct request *rq = &hwgroup->wrq;
+
+ do {
+ char *buffer;
+ int nsect = rq->current_nr_sectors;
+ unsigned long flags;
+
+ if (nsect > mcount)
+ nsect = mcount;
+ mcount -= nsect;
+
+ buffer = ide_map_buffer(rq, &flags);
+ rq->sector += nsect;
+ rq->nr_sectors -= nsect;
+ rq->current_nr_sectors -= nsect;
+
+ /* Do we move to the next bh after this? */
+ if (!rq->current_nr_sectors) {
+ struct bio *bio = rq->bio->bi_next;
+
+ /* end early early we ran out of requests */
+ if (!bio) {
+ mcount = 0;
+ } else {
+ rq->bio = bio;
+ rq->current_nr_sectors = bio_sectors(bio);
+ rq->hard_cur_sectors = rq->current_nr_sectors;
+ }
+ }
+
+ /*
+ * Ok, we're all setup for the interrupt
+ * re-entering us on the last transfer.
+ */
+ taskfile_output_data(drive, buffer, nsect<<7);
+ ide_unmap_buffer(buffer, &flags);
+ } while (mcount);
+
+ return 0;
+}
+
+/*
* promise_write_pollfunc() is the handler for disk write completion polling.
*/
static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
@@ -434,7 +486,7 @@ static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
/*
* Now write out last 4 sectors and poll for not BUSY
*/
- ide_multwrite(drive, 4);
+ promise_multwrite(drive, 4);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
#ifdef DEBUG_WRITE
@@ -467,7 +519,7 @@ static ide_startstop_t promise_write (ide_drive_t *drive)
* the polling strategy as defined above.
*/
if (rq->nr_sectors > 4) {
- if (ide_multwrite(drive, rq->nr_sectors - 4))
+ if (promise_multwrite(drive, rq->nr_sectors - 4))
return ide_stopped;
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
@@ -477,7 +529,7 @@ static ide_startstop_t promise_write (ide_drive_t *drive)
* There are 4 or fewer sectors to transfer, do them all in one go
* and wait for NOT BUSY.
*/
- if (ide_multwrite(drive, rq->nr_sectors))
+ if (promise_multwrite(drive, rq->nr_sectors))
return ide_stopped;
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
@@ -494,11 +546,28 @@ static ide_startstop_t promise_write (ide_drive_t *drive)
* already set up. It issues a READ or WRITE command to the Promise
* controller, assuming LBA has been used to set up the block number.
*/
-ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq)
+ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
{
+ struct request *rq = HWGROUP(drive)->rq;
+ task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+ ide_startstop_t startstop;
unsigned long timeout;
byte stat;
+ if (IDE_CONTROL_REG)
+ OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */
+ SELECT_MASK(HWIF(drive), drive, 0);
+
+ OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
+ OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+ /* refers to number of sectors to transfer */
+ OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+ /* refers to sector offset or start sector */
+ OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
+ OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+ OUT_BYTE(taskfile->device_head, IDE_SELECT_REG);
+ OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+
/* Check that it's a regular command. If not, bomb out early. */
if (!(rq->flags & REQ_CMD)) {
blk_dump_rq_flags(rq, "pdc4030 bad flags");
@@ -540,9 +609,8 @@ ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq)
printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n",
drive->name);
return ide_stopped;
- break;
- case WRITE:
+ case WRITE: {
ide_startstop_t startstop;
OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
/*
@@ -561,11 +629,40 @@ ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq)
__cli(); /* local CPU only */
HWGROUP(drive)->wrq = *rq; /* scratchpad */
return promise_write(drive);
- break;
+ }
default:
printk(KERN_ERR "pdc4030: command not READ or WRITE! Huh?\n");
ide_end_request(0, HWGROUP(drive));
- break;
+ return ide_stopped;
}
}
+
+ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+ struct hd_drive_task_hdr taskfile;
+ ide_task_t args;
+
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+
+ taskfile.sector_count = rq->nr_sectors;
+ taskfile.sector_number = block;
+ taskfile.low_cylinder = (block>>=8);
+ taskfile.high_cylinder = (block>>=8);
+ taskfile.device_head = ((block>>8)&0x0f)|drive->select.all;
+ taskfile.command = (rq_data_dir(rq)==READ)?PROMISE_READ:PROMISE_WRITE;
+
+ memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+ memcpy(args.hobRegister, NULL, sizeof(struct hd_drive_hob_hdr));
+ args.command_type = ide_cmd_type_parser(&args);
+ args.prehandler = NULL;
+ args.handler = NULL;
+ args.posthandler = NULL;
+ args.rq = (struct request *) rq;
+ args.block = block;
+ rq->special = NULL;
+ rq->special = (ide_task_t *)&args;
+
+ return do_pdc4030_io(drive, &args);
+}
+
diff --git a/drivers/ide/pdcadma.c b/drivers/ide/pdcadma.c
new file mode 100644
index 000000000..c699f714e
--- /dev/null
+++ b/drivers/ide/pdcadma.c
@@ -0,0 +1,109 @@
+/*
+ * linux/drivers/ide/pdcadma.c Version 0.01 June 21, 2001
+ *
+ * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+
+#undef DISPLAY_PDCADMA_TIMINGS
+
+#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int pdcadma_get_info(char *, char **, off_t, int);
+extern int (*pdcadma_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static struct pci_dev *bmide_dev;
+
+static int pdcadma_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+ char *p = buffer;
+ u32 bibma = pci_resource_start(bmide_dev, 4);
+
+ p += sprintf(p, "\n PDC ADMA %04X Chipset.\n", bmide_dev->device);
+ p += sprintf(p, "UDMA\n");
+ p += sprintf(p, "PIO\n");
+
+ return p-buffer; /* => must be less than 4k! */
+}
+#endif /* defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+byte pdcadma_proc = 0;
+
+extern char *ide_xfer_verbose (byte xfer_rate);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+/*
+ * pdcadma_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
+ */
+
+int pdcadma_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+ switch (func) {
+ case ide_dma_check:
+ func = ide_dma_off_quietly;
+ default:
+ break;
+ }
+ return ide_dmaproc(func, drive); /* use standard DMA stuff */
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+unsigned int __init pci_init_pdcadma (struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+ if (!pdcadma_proc) {
+ pdcadma_proc = 1;
+ bmide_dev = dev;
+ pdcadma_display_info = &pdcadma_get_info;
+ }
+#endif /* DISPLAY_PDCADMA_TIMINGS && CONFIG_PROC_FS */
+ return 0;
+}
+
+unsigned int __init ata66_pdcadma (ide_hwif_t *hwif)
+{
+ return 1;
+}
+
+void __init ide_init_pdcadma (ide_hwif_t *hwif)
+{
+ hwif->autodma = 0;
+ hwif->dma_base = 0;
+
+// hwif->tuneproc = &pdcadma_tune_drive;
+// hwif->speedproc = &pdcadma_tune_chipset;
+
+// if (hwif->dma_base) {
+// hwif->dmaproc = &pdcadma_dmaproc;
+// hwif->autodma = 1;
+// }
+}
+
+void __init ide_dmacapable_pdcadma (ide_hwif_t *hwif, unsigned long dmabase)
+{
+// ide_setup_dma(hwif, dmabase, 8);
+}
+
diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c
index 0f64f4ed1..631cef9e6 100644
--- a/drivers/ide/piix.c
+++ b/drivers/ide/piix.c
@@ -402,7 +402,7 @@ static int config_drive_xfer_rate (ide_drive_t *drive)
}
dma_func = ide_dma_off_quietly;
if (id->field_valid & 4) {
- if (id->dma_ultra & 0x002F) {
+ if (id->dma_ultra & 0x003F) {
/* Force if Capable UltraDMA */
dma_func = piix_config_drive_for_dma(drive);
if ((id->field_valid & 2) &&
diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c
index b0ab4ebfd..7f1a10be1 100644
--- a/drivers/ide/qd65xx.c
+++ b/drivers/ide/qd65xx.c
@@ -1,14 +1,15 @@
/*
- * linux/drivers/ide/qd65xx.c Version 0.06 Aug 3, 2000
+ * linux/drivers/ide/qd65xx.c Version 0.07 Sep 30, 2001
*
- * Copyright (C) 1996-2000 Linus Torvalds & author (see below)
+ * Copyright (C) 1996-2001 Linus Torvalds & author (see below)
*/
/*
* Version 0.03 Cleaned auto-tune, added probe
* Version 0.04 Added second channel tuning
* Version 0.05 Enhanced tuning ; added qd6500 support
- * Version 0.06 added dos driver's list
+ * Version 0.06 Added dos driver's list
+ * Version 0.07 Second channel bug fix
*
* QDI QD6500/QD6580 EIDE controller fast support
*
@@ -67,6 +68,7 @@
* qd6500: 1100
* qd6580: either 1010 or 0101
*
+ *
* base+0x02: Timer2 (qd6580 only)
*
*
@@ -137,12 +139,12 @@ static byte qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recove
{
byte active_cycle,recovery_cycle;
- if (system_bus_clock()<=33) {
- active_cycle = 9 - IDE_IN(active_time * system_bus_clock() / 1000 + 1, 2, 9);
- recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 0, 15);
+ if (ide_system_bus_speed()<=33) {
+ active_cycle = 9 - IDE_IN(active_time * ide_system_bus_speed() / 1000 + 1, 2, 9);
+ recovery_cycle = 15 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 0, 15);
} else {
- active_cycle = 8 - IDE_IN(active_time * system_bus_clock() / 1000 + 1, 1, 8);
- recovery_cycle = 18 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 3, 18);
+ active_cycle = 8 - IDE_IN(active_time * ide_system_bus_speed() / 1000 + 1, 1, 8);
+ recovery_cycle = 18 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 3, 18);
}
return((recovery_cycle<<4) | 0x08 | active_cycle);
@@ -156,8 +158,8 @@ static byte qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recove
static byte qd6580_compute_timing (int active_time, int recovery_time)
{
- byte active_cycle = 17-IDE_IN(active_time * system_bus_clock() / 1000 + 1, 2, 17);
- byte recovery_cycle = 15-IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 2, 15);
+ byte active_cycle = 17-IDE_IN(active_time * ide_system_bus_speed() / 1000 + 1, 2, 17);
+ byte recovery_cycle = 15-IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 2, 15);
return((recovery_cycle<<4) | active_cycle);
}
@@ -427,7 +429,8 @@ int __init probe (int base)
ide_hwifs[i].tuneproc = &qd6580_tune_drive;
for (j=0;j<2;j++) {
- ide_hwifs[i].drives[j].drive_data = QD6580_DEF_DATA;
+ ide_hwifs[i].drives[j].drive_data =
+ i?QD6580_DEF_DATA2:QD6580_DEF_DATA;
ide_hwifs[i].drives[j].io_32bit = 1;
}
}
diff --git a/drivers/ide/qd65xx.h b/drivers/ide/qd65xx.h
index 8a3d9b60d..73a7d76bb 100644
--- a/drivers/ide/qd65xx.h
+++ b/drivers/ide/qd65xx.h
@@ -29,7 +29,7 @@
#define QD_CONTR_SEC_DISABLED 0x01
-#define QD_ID3 (config & QD_CONFIG_ID3)
+#define QD_ID3 ((config & QD_CONFIG_ID3)!=0)
#define QD_CONFIG(hwif) ((hwif)->config_data & 0x00ff)
#define QD_CONTROL(hwif) (((hwif)->config_data & 0xff00) >> 8)
@@ -39,6 +39,7 @@
#define QD6500_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08))
#define QD6580_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
+#define QD6580_DEF_DATA2 ((QD_TIM2_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
#define QD_DEF_CONTR (0x40 | ((control & 0x02) ? 0x9f : 0x1f))
#define QD_TESTVAL 0x19 /* safe value */
diff --git a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c
index 60bccdab6..8776d20c6 100644
--- a/drivers/ide/serverworks.c
+++ b/drivers/ide/serverworks.c
@@ -1,16 +1,26 @@
/*
- * linux/drivers/ide/serverworks.c Version 0.2 17 Oct 2000
+ * linux/drivers/ide/serverworks.c Version 0.3 26 Oct 2001
*
- * Copyright (C) 2000 Cobalt Networks, Inc. <asun@cobalt.com>
- * May be copied or modified under the terms of the GNU General Public License
+ * May be copied or modified under the terms of the GNU General Public License
*
- * interface borrowed from alim15x3.c:
- * Copyright (C) 1998-2000 Michel Aubry, Maintainer
- * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
+ * Copyright (C) 1998-2000 Michel Aubry
+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * Portions copyright (c) 2001 Sun Microsystems
*
- * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
*
- * IDE support for the ServerWorks OSB4 IDE chipset
+ * RCC/ServerWorks IDE driver for Linux
+ *
+ * OSB4: `Open South Bridge' IDE Interface (fn 1)
+ * supports UDMA mode 2 (33 MB/s)
+ *
+ * CSB5: `Champion South Bridge' IDE Interface (fn 1)
+ * all revisions support UDMA mode 4 (66 MB/s)
+ * revision A2.0 and up support UDMA mode 5 (100 MB/s)
+ *
+ * *** The CSB5 does not provide ANY register ***
+ * *** to detect 80-conductor cable presence. ***
+ *
*
* here's the default lspci:
*
@@ -83,15 +93,15 @@
#include "ide_modes.h"
-#define SVWKS_DEBUG_DRIVE_INFO 0
-
-#define DISPLAY_SVWKS_TIMINGS
+#define DISPLAY_SVWKS_TIMINGS 1
+#undef SVWKS_DEBUG_DRIVE_INFO
#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
#include <linux/stat.h>
#include <linux/proc_fs.h>
static struct pci_dev *bmide_dev;
+static byte svwks_revision = 0;
static int svwks_get_info(char *, char **, off_t, int);
extern int (*svwks_display_info)(char *, char **, off_t, int); /* ide-proc.c */
@@ -103,7 +113,7 @@ static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
u32 bibma = pci_resource_start(bmide_dev, 4);
u32 reg40, reg44;
u16 reg48, reg56;
- u8 c0 = 0, c1 = 0, reg54;
+ u8 reg54, c0=0, c1=0;
pci_read_config_dword(bmide_dev, 0x40, &reg40);
pci_read_config_dword(bmide_dev, 0x44, &reg44);
@@ -120,20 +130,23 @@ static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
switch(bmide_dev->device) {
case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
- p += sprintf(p, "\n ServerWorks CSB5 Chipset.\n");
+ p += sprintf(p, "\n "
+ "ServerWorks CSB5 Chipset (rev %02x)\n",
+ svwks_revision);
break;
- case PCI_DEVICE_ID_SERVERWORKS_OSB4:
- p += sprintf(p, "\n ServerWorks OSB4 Chipset.\n");
+ case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
+ p += sprintf(p, "\n "
+ "ServerWorks OSB4 Chipset (rev %02x)\n",
+ svwks_revision);
break;
default:
- p += sprintf(p, "\n ServerWorks 0x%04x Chipset.\n", bmide_dev->device);
+ p += sprintf(p, "\n "
+ "ServerWorks %04x Chipset (rev %02x)\n",
+ bmide_dev->device, svwks_revision);
break;
}
p += sprintf(p, "------------------------------- General Status ---------------------------------\n");
-#if 0
- p += sprintf(p, " : %s\n", "str");
-#endif
p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
p += sprintf(p, " %sabled %sabled\n",
(c0&0x80) ? "dis" : " en",
@@ -191,11 +204,7 @@ static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
((reg44&0x00210000)==0x00210000)?"1":
((reg44&0x00770000)==0x00770000)?"0":
((reg44&0x00FF0000)==0x00FF0000)?"X":"?");
-#if 0
- if (bmide_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
- p += sprintf(p, "PIO enabled: %s %s %s %s\n",
- if (bmide_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4)
-#endif
+
p += sprintf(p, "PIO enabled: %s %s %s %s\n",
((reg40&0x00002000)==0x00002000)?"4":
((reg40&0x00002200)==0x00002200)?"3":
@@ -221,7 +230,7 @@ static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
}
#endif /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
-static byte svwks_revision = 0;
+#define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
byte svwks_proc = 0;
@@ -292,6 +301,7 @@ static int svwks_tune_chipset (ide_drive_t *drive, byte speed)
pio_timing |= pio_modes[speed - XFER_PIO_0];
csb5_pio |= ((speed - XFER_PIO_0) << (4*drive->dn));
break;
+
#ifdef CONFIG_BLK_DEV_IDEDMA
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
@@ -307,9 +317,9 @@ static int svwks_tune_chipset (ide_drive_t *drive, byte speed)
case XFER_UDMA_2:
case XFER_UDMA_1:
case XFER_UDMA_0:
- pio_timing |= pio_modes[pio];
- csb5_pio |= (pio << (4*drive->dn));
- dma_timing |= dma_modes[2];
+ pio_timing |= pio_modes[pio];
+ csb5_pio |= (pio << (4*drive->dn));
+ dma_timing |= dma_modes[2];
ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
ultra_enable |= (0x01 << drive->dn);
#endif
@@ -322,9 +332,9 @@ static int svwks_tune_chipset (ide_drive_t *drive, byte speed)
drive->name, ultra_timing, dma_timing, pio_timing);
#endif
-#if OSB4_DEBUG_DRIVE_INFO
+#if SVWKS_DEBUG_DRIVE_INFO
printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* OSB4_DEBUG_DRIVE_INFO */
+#endif /* SVWKS_DEBUG_DRIVE_INFO */
if (!drive->init_speed)
drive->init_speed = speed;
@@ -338,11 +348,10 @@ static int svwks_tune_chipset (ide_drive_t *drive, byte speed)
pci_write_config_byte(dev, drive_pci3, ultra_timing);
pci_write_config_byte(dev, 0x54, ultra_enable);
- if (speed > XFER_PIO_4) {
+ if (speed > XFER_PIO_4)
outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
- } else {
+ else
outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
- }
#endif /* CONFIG_BLK_DEV_IDEDMA */
err = ide_config_drive_speed(drive, speed);
@@ -354,25 +363,24 @@ static void config_chipset_for_pio (ide_drive_t *drive)
{
unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
unsigned short xfer_pio = drive->id->eide_pio_modes;
- byte timing, speed, pio;
+ byte timing, speed, pio;
pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
if (xfer_pio> 4)
xfer_pio = 0;
- if (drive->id->eide_pio_iordy > 0) {
+ if (drive->id->eide_pio_iordy > 0)
for (xfer_pio = 5;
xfer_pio>0 &&
drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
xfer_pio--);
- } else {
+ else
xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
(drive->id->eide_pio_modes & 2) ? 0x04 :
(drive->id->eide_pio_modes & 1) ? 0x03 :
(drive->id->tPIO & 2) ? 0x02 :
(drive->id->tPIO & 1) ? 0x01 : xfer_pio;
- }
timing = (xfer_pio >= pio) ? xfer_pio : pio;
@@ -407,12 +415,10 @@ static int config_chipset_for_dma (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
struct pci_dev *dev = HWIF(drive)->pci_dev;
- byte udma_66 = eighty_ninty_three(drive);
- byte speed;
-
- int ultra66 = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
- /* need specs to figure out if osb4 is capable of ata/66/100 */
- int ultra100 = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
+ byte udma_66 = eighty_ninty_three(drive);
+ int ultra66 = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
+ int ultra100 = (ultra66 && svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 1 : 0;
+ byte speed;
if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) {
speed = XFER_UDMA_5;
@@ -458,7 +464,7 @@ static int config_drive_xfer_rate (ide_drive_t *drive)
}
dma_func = ide_dma_off_quietly;
if (id->field_valid & 4) {
- if (id->dma_ultra & 0x002F) {
+ if (id->dma_ultra & 0x003F) {
/* Force if Capable UltraDMA */
dma_func = config_chipset_for_dma(drive);
if ((id->field_valid & 2) &&
@@ -499,7 +505,41 @@ static int svwks_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
switch (func) {
case ide_dma_check:
return config_drive_xfer_rate(drive);
- default :
+ case ide_dma_end:
+ {
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long dma_base = hwif->dma_base;
+
+ if(inb(dma_base+0x02)&1)
+ {
+#if 0
+ int i;
+ printk(KERN_ERR "Curious - OSB4 thinks the DMA is still running.\n");
+ for(i=0;i<10;i++)
+ {
+ if(!(inb(dma_base+0x02)&1))
+ {
+ printk(KERN_ERR "OSB4 now finished.\n");
+ break;
+ }
+ udelay(5);
+ }
+#endif
+ printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n");
+ printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n");
+ printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n");
+#if 0
+ /* Panic might sys_sync -> death by corrupt disk */
+ panic("OSB4: continuing might cause disk corruption.\n");
+#else
+ printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n");
+ while(1)
+ cpu_relax();
+#endif
+ }
+ /* and drop through */
+ }
+ default:
break;
}
/* Other cases are done by generic IDE-DMA code. */
@@ -509,30 +549,43 @@ static int svwks_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
{
- unsigned int reg64;
+ unsigned int reg;
+ byte btr;
+ /* save revision id to determine DMA capability */
pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
- if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
- isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+ /* force Master Latency Timer value to 64 PCICLKs */
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
- pci_read_config_dword(isa_dev, 0x64, &reg64);
-#ifdef DEBUG
- printk("%s: reg64 == 0x%08x\n", name, reg64);
-#endif
+ /* OSB4 : South Bridge and IDE */
+ if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+ isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+ if (isa_dev) {
+ pci_read_config_dword(isa_dev, 0x64, &reg);
+ reg &= ~0x00002000; /* disable 600ns interrupt mask */
+ reg |= 0x00004000; /* enable UDMA/33 support */
+ pci_write_config_dword(isa_dev, 0x64, reg);
+ }
+ }
-// reg64 &= ~0x0000A000;
-//#ifdef CONFIG_SMP
-// reg64 |= 0x00008000;
-//#endif
- /* Assume the APIC was set up properly by the BIOS for now . If it
- wasnt we need to do a fix up _way_ earlier. Bits 15,10,3 control
- APIC enable, routing and decode */
-
- reg64 &= ~0x00002000;
- pci_write_config_dword(isa_dev, 0x64, reg64);
+ /* setup CSB5 : South Bridge and IDE */
+ else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) {
+ /* setup the UDMA Control register
+ *
+ * 1. clear bit 6 to enable DMA
+ * 2. enable DMA modes with bits 0-1
+ * 00 : legacy
+ * 01 : udma2
+ * 10 : udma2/udma4
+ * 11 : udma2/udma4/udma5
+ */
+ pci_read_config_byte(dev, 0x5A, &btr);
+ btr &= ~0x40;
+ btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
+ pci_write_config_byte(dev, 0x5A, btr);
}
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
if (!svwks_proc) {
@@ -551,26 +604,46 @@ unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
* Bit 14 clear = primary IDE channel does not have 80-pin cable.
* Bit 14 set = primary IDE channel has 80-pin cable.
*/
-
static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
{
- struct pci_dev *dev = hwif->pci_dev;
- if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
- dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
- dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+ struct pci_dev *dev = hwif->pci_dev;
+ if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+ dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
+ dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
return ((1 << (hwif->channel + 14)) &
dev->subsystem_device) ? 1 : 0;
-
return 0;
+}
+/* Sun Cobalt Alpine hardware avoids the 80-pin cable
+ * detect issue by attaching the drives directly to the board.
+ * This check follows the Dell precedent (how scary is that?!)
+ *
+ * WARNING: this only works on Alpine hardware!
+ */
+static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+ if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
+ dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
+ dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+ return ((1 << (hwif->channel + 14)) &
+ dev->subsystem_device) ? 1 : 0;
+ return 0;
}
unsigned int __init ata66_svwks (ide_hwif_t *hwif)
{
- struct pci_dev *dev = hwif->pci_dev;
+ struct pci_dev *dev = hwif->pci_dev;
+
+ /* Dell PowerEdge */
if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL)
return ata66_svwks_dell (hwif);
-
+
+ /* Cobalt Alpine */
+ if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
+ return ata66_svwks_cobalt (hwif);
+
return 0;
}
@@ -586,9 +659,7 @@ void __init ide_init_svwks (ide_hwif_t *hwif)
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
hwif->autodma = 0;
- return;
#else /* CONFIG_BLK_DEV_IDEDMA */
-
if (hwif->dma_base) {
if (!noautodma)
hwif->autodma = 1;
diff --git a/drivers/ide/slc90e66.c b/drivers/ide/slc90e66.c
index df824d20d..75a15e48d 100644
--- a/drivers/ide/slc90e66.c
+++ b/drivers/ide/slc90e66.c
@@ -86,8 +86,13 @@ static int slc90e66_get_info (char *buffer, char **addr, off_t offset, int count
* at that point bibma+0x2 et bibma+0xa are byte registers
* to investigate:
*/
+#ifdef __mips__ /* only for mips? */
+ c0 = inb_p(bibma + 0x02);
+ c1 = inb_p(bibma + 0x0a);
+#else
c0 = inb_p((unsigned short)bibma + 0x02);
c1 = inb_p((unsigned short)bibma + 0x0a);
+#endif
p += sprintf(p, " SLC90E66 Chipset.\n");
p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
@@ -253,7 +258,9 @@ static int slc90e66_tune_chipset (ide_drive_t *drive, byte speed)
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
case XFER_SW_DMA_2: break;
+#if 0 /* allow PIO modes */
default: return -1;
+#endif
}
if (speed >= XFER_UDMA_0) {
@@ -291,6 +298,13 @@ static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
byte speed = 0;
byte udma_66 = eighty_ninty_three(drive);
+#if 1 /* allow PIO modes */
+ if (!HWIF(drive)->autodma) {
+ speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+ (void) slc90e66_tune_chipset(drive, speed);
+ return ((int) ide_dma_off_quietly);
+ }
+#endif
if ((id->dma_ultra & 0x0010) && (ultra)) {
speed = (udma_66) ? XFER_UDMA_4 : XFER_UDMA_2;
} else if ((id->dma_ultra & 0x0008) && (ultra)) {
diff --git a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c
index a1fd4888b..588084dff 100644
--- a/drivers/mtd/devices/blkmtd.c
+++ b/drivers/mtd/devices/blkmtd.c
@@ -265,7 +265,6 @@ static int write_queue_task(void *data)
sigfillset(&tsk->blocked);
recalc_sigpending(tsk);
spin_unlock_irq(&tsk->sigmask_lock);
- exit_sighand(tsk);
if(alloc_kiovec(1, &iobuf))
return 0;
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
index 21dc6c106..3600cef86 100644
--- a/drivers/mtd/mtdblock.c
+++ b/drivers/mtd/mtdblock.c
@@ -472,20 +472,14 @@ int mtdblock_thread(void *dummy)
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
- tsk->session = 1;
- tsk->pgrp = 1;
/* we might get involved when memory gets low, so use PF_MEMALLOC */
tsk->flags |= PF_MEMALLOC;
strcpy(tsk->comm, "mtdblockd");
- tsk->tty = NULL;
spin_lock_irq(&tsk->sigmask_lock);
sigfillset(&tsk->blocked);
recalc_sigpending(tsk);
spin_unlock_irq(&tsk->sigmask_lock);
- exit_mm(tsk);
- exit_files(tsk);
- exit_sighand(tsk);
- exit_fs(tsk);
+ daemonize();
while (!leaving) {
add_wait_queue(&thr_wq, &wait);
diff --git a/drivers/parport/ChangeLog b/drivers/parport/ChangeLog
index 39ef2e14d..129450bf6 100644
--- a/drivers/parport/ChangeLog
+++ b/drivers/parport/ChangeLog
@@ -1,3 +1,9 @@
+2001-12-06 Tim Waugh <twaugh@redhat.com>
+
+ * ieee1284_ops.c (parport_ieee1284_ecp_read_data): Mask off
+ PARPORT_CONTROL_AUTOFD as well. Bug spotted by Joe
+ <joeja@mindspring.com>.
+
2001-11-12 Tim Waugh <twaugh@redhat.com>
* parport_pc.c (init_module): Warn when parameters are ignored.
diff --git a/drivers/parport/Config.in b/drivers/parport/Config.in
index b4d643315..eb13f0748 100644
--- a/drivers/parport/Config.in
+++ b/drivers/parport/Config.in
@@ -24,9 +24,13 @@ if [ "$CONFIG_PARPORT" != "n" ]; then
bool ' Use FIFO/DMA if available (EXPERIMENTAL)' CONFIG_PARPORT_PC_FIFO
bool ' SuperIO chipset support (EXPERIMENTAL)' CONFIG_PARPORT_PC_SUPERIO
fi
- fi
- if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
- dep_tristate ' Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA $CONFIG_PCMCIA
+ if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
+ if [ "$CONFIG_PARPORT_PC" = "y" ]; then
+ dep_tristate ' Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA $CONFIG_PCMCIA
+ else
+ dep_tristate ' Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA $CONFIG_PARPORT_PC
+ fi
+ fi
fi
if [ "$CONFIG_ARM" = "y" ]; then
dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
diff --git a/drivers/parport/ieee1284_ops.c b/drivers/parport/ieee1284_ops.c
index 51f771a62..8fcd6f2f1 100644
--- a/drivers/parport/ieee1284_ops.c
+++ b/drivers/parport/ieee1284_ops.c
@@ -514,7 +514,8 @@ size_t parport_ieee1284_ecp_read_data (struct parport *port,
/* Set HostAck low to start accepting data. */
ctl = parport_read_control (port);
- ctl &= ~(PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT);
+ ctl &= ~(PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT |
+ PARPORT_CONTROL_AUTOFD);
parport_write_control (port,
ctl | PARPORT_CONTROL_AUTOFD);
while (count < len) {
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 1c47f9cc0..1590354e8 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -530,28 +530,33 @@ static int idescsi_cleanup (ide_drive_t *drive)
return 0;
}
+int idescsi_reinit(ide_drive_t *drive);
+
/*
* IDE subdriver functions, registered with ide.c
*/
static ide_driver_t idescsi_driver = {
- "ide-scsi", /* name */
- IDESCSI_VERSION, /* version */
- ide_scsi, /* media */
- 0, /* busy */
- 1, /* supports_dma */
- 0, /* supports_dsc_overlap */
- idescsi_cleanup, /* cleanup */
- idescsi_do_request, /* do_request */
- idescsi_end_request, /* end_request */
- NULL, /* ioctl */
- idescsi_open, /* open */
- idescsi_ide_release, /* release */
- NULL, /* media_change */
- NULL, /* revalidate */
- NULL, /* pre_reset */
- NULL, /* capacity */
- NULL, /* special */
- NULL /* proc */
+ name: "ide-scsi",
+ version: IDESCSI_VERSION,
+ media: ide_scsi,
+ busy: 0,
+ supports_dma: 1,
+ supports_dsc_overlap: 0,
+ cleanup: idescsi_cleanup,
+ standby: NULL,
+ flushcache: NULL,
+ do_request: idescsi_do_request,
+ end_request: idescsi_end_request,
+ ioctl: NULL,
+ open: idescsi_open,
+ release: idescsi_ide_release,
+ media_change: NULL,
+ revalidate: NULL,
+ pre_reset: NULL,
+ capacity: NULL,
+ special: NULL,
+ proc: NULL,
+ driver_reinit: idescsi_reinit,
};
int idescsi_init (void);
@@ -562,6 +567,43 @@ static ide_module_t idescsi_module = {
NULL
};
+int idescsi_reinit (ide_drive_t *drive)
+{
+#if 0
+ idescsi_scsi_t *scsi;
+ byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
+ int i, failed, id;
+
+ if (!idescsi_initialized)
+ return 0;
+ for (i = 0; i < MAX_HWIFS * MAX_DRIVES; i++)
+ idescsi_drives[i] = NULL;
+
+ MOD_INC_USE_COUNT;
+ for (i = 0; media[i] != 255; i++) {
+ failed = 0;
+ while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) {
+
+ if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) {
+ printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name);
+ continue;
+ }
+ if (ide_register_subdriver (drive, &idescsi_driver, IDE_SUBDRIVER_VERSION)) {
+ printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name);
+ kfree (scsi);
+ continue;
+ }
+ for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++);
+ idescsi_setup (drive, scsi, id);
+ failed--;
+ }
+ }
+ ide_register_module(&idescsi_module);
+ MOD_DEC_USE_COUNT;
+#endif
+ return 0;
+}
+
/*
* idescsi_init will register the driver for each scsi.
*/
@@ -592,7 +634,7 @@ int idescsi_init (void)
continue;
}
for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++);
- idescsi_setup (drive, scsi, id);
+ idescsi_setup (drive, scsi, id);
failed--;
}
}
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 1d11dfb67..db9ecdad8 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -314,9 +314,6 @@ static int usb_stor_control_thread(void * __us)
* This thread doesn't need any user-level access,
* so get rid of all our resources..
*/
- exit_files(current);
- current->files = init_task.files;
- atomic_inc(&current->files->count);
daemonize();
/* set our name for identification purposes */
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 76b379ad9..2b474f297 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -538,7 +538,6 @@ ParseLong:
if (!memcmp(de->name,MSDOS_DOT,11))
inum = inode->i_ino;
else if (!memcmp(de->name,MSDOS_DOTDOT,11)) {
-/* inum = fat_parent_ino(inode,0); */
inum = filp->f_dentry->d_parent->d_inode->i_ino;
} else {
struct inode *tmp = fat_iget(sb, ino);
@@ -727,7 +726,13 @@ int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
offset = curr = 0;
*bh = NULL;
row = 0;
- while (fat_get_entry(dir,&curr,bh,de,ino) > -1) {
+ while (fat_get_entry(dir, &curr, bh, de, ino) > -1) {
+ /* check the maximum size of directory */
+ if (curr >= FAT_MAX_DIR_SIZE) {
+ fat_brelse(sb, *bh);
+ return -ENOSPC;
+ }
+
if (IS_FREE((*de)->name)) {
if (++row == slots)
return offset;
@@ -742,7 +747,10 @@ int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
if (!new_bh)
return -ENOSPC;
fat_brelse(sb, new_bh);
- do fat_get_entry(dir,&curr,bh,de,ino); while (++row<slots);
+ do {
+ fat_get_entry(dir, &curr, bh, de, ino);
+ } while (++row < slots);
+
return offset;
}
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 904a5b277..524f18d05 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -208,7 +208,7 @@ void fat_put_super(struct super_block *sb)
}
-static int parse_options(char *options,int *fat, int *debug,
+static int parse_options(char *options, int *debug,
struct fat_mount_options *opts,
char *cvf_format, char *cvf_options)
{
@@ -227,7 +227,7 @@ static int parse_options(char *options,int *fat, int *debug,
opts->shortname = 0;
opts->utf8 = 0;
opts->iocharset = NULL;
- *debug = *fat = 0;
+ *debug = 0;
if (!options)
goto out;
@@ -305,13 +305,8 @@ static int parse_options(char *options,int *fat, int *debug,
else *debug = 1;
}
else if (!strcmp(this_char,"fat")) {
- if (!value || !*value) ret = 0;
- else {
- *fat = simple_strtoul(value,&value,0);
- if (*value || (*fat != 12 && *fat != 16 &&
- *fat != 32))
- ret = 0;
- }
+ printk("FAT: fat option is obsolete, "
+ "not supported now\n");
}
else if (!strcmp(this_char,"quiet")) {
if (value) ret = 0;
@@ -328,8 +323,6 @@ static int parse_options(char *options,int *fat, int *debug,
else if (!strcmp(this_char,"codepage") && value) {
opts->codepage = simple_strtoul(value,&value,0);
if (*value) ret = 0;
- else printk ("MSDOS FS: Using codepage %d\n",
- opts->codepage);
}
else if (!strcmp(this_char,"iocharset") && value) {
p = value;
@@ -348,7 +341,6 @@ static int parse_options(char *options,int *fat, int *debug,
opts->iocharset = buffer;
memcpy(buffer, p, len);
buffer[len] = 0;
- printk("MSDOS FS: IO charset %s\n", buffer);
} else
ret = 0;
}
@@ -373,11 +365,37 @@ out:
return ret;
}
+static void fat_calc_dir_size(struct inode *inode)
+{
+ struct super_block *sb = inode->i_sb;
+ int nr;
+
+ inode->i_size = 0;
+ if (MSDOS_I(inode)->i_start == 0)
+ return;
+
+ nr = MSDOS_I(inode)->i_start;
+ do {
+ inode->i_size += 1 << MSDOS_SB(sb)->cluster_bits;
+ if (!(nr = fat_access(sb, nr, -1))) {
+ printk("FAT: Directory %ld: bad FAT\n",
+ inode->i_ino);
+ break;
+ }
+ if (inode->i_size > FAT_MAX_DIR_SIZE) {
+ fat_fs_panic(sb, "Directory %ld: "
+ "exceeded the maximum size of directory",
+ inode->i_ino);
+ inode->i_size = FAT_MAX_DIR_SIZE;
+ break;
+ }
+ } while (nr != -1);
+}
+
static void fat_read_root(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
struct msdos_sb_info *sbi = MSDOS_SB(sb);
- int nr;
INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
MSDOS_I(inode)->i_location = 0;
@@ -391,16 +409,7 @@ static void fat_read_root(struct inode *inode)
inode->i_fop = &fat_dir_operations;
if (sbi->fat_bits == 32) {
MSDOS_I(inode)->i_start = sbi->root_cluster;
- if ((nr = MSDOS_I(inode)->i_start) != 0) {
- while (nr != -1) {
- inode->i_size += 1 << sbi->cluster_bits;
- if (!(nr = fat_access(sb, nr, -1))) {
- printk("Directory %ld: bad FAT\n",
- inode->i_ino);
- break;
- }
- }
- }
+ fat_calc_dir_size(inode);
} else {
MSDOS_I(inode)->i_start = 0;
inode->i_size = sbi->dir_entries * sizeof(struct msdos_dir_entry);
@@ -550,11 +559,9 @@ fat_read_super(struct super_block *sb, void *data, int silent,
struct buffer_head *bh;
struct fat_boot_sector *b;
struct msdos_sb_info *sbi = MSDOS_SB(sb);
- char *p;
- int logical_sector_size, hard_blksize, fat_clusters = 0;
+ int logical_sector_size, fat_clusters;
unsigned int total_sectors, rootdir_sectors;
- int fat32, debug, error, fat, cp;
- struct fat_mount_options opts;
+ int debug, cp;
char buf[50];
int i;
char cvf_format[21];
@@ -562,22 +569,20 @@ fat_read_super(struct super_block *sb, void *data, int silent,
cvf_format[0] = '\0';
cvf_options[0] = '\0';
- sbi->cvf_format = NULL;
sbi->private_data = NULL;
- sbi->dir_ops = fs_dir_inode_ops;
-
- sb->s_maxbytes = MAX_NON_LFS;
+ sb->s_magic = MSDOS_SUPER_MAGIC;
sb->s_op = &fat_sops;
+ sbi->dir_ops = fs_dir_inode_ops;
+ sbi->cvf_format = &default_cvf;
- opts.isvfat = sbi->options.isvfat;
- if (!parse_options((char *) data, &fat, &debug, &opts,
+ if (!parse_options((char *)data, &debug, &sbi->options,
cvf_format, cvf_options))
goto out_fail;
- /* N.B. we should parse directly into the sb structure */
- memcpy(&(sbi->options), &opts, sizeof(struct fat_mount_options));
fat_cache_init();
+ /* set up enough so that it can read an inode */
+ init_MUTEX(&sbi->fat_lock);
sb_min_blocksize(sb, 512);
bh = sb_bread(sb, 0);
@@ -586,37 +591,37 @@ fat_read_super(struct super_block *sb, void *data, int silent,
goto out_fail;
}
-/*
- * The DOS3 partition size limit is *not* 32M as many people think.
- * Instead, it is 64K sectors (with the usual sector size being
- * 512 bytes, leading to a 32M limit).
- *
- * DOS 3 partition managers got around this problem by faking a
- * larger sector size, ie treating multiple physical sectors as
- * a single logical sector.
- *
- * We can accommodate this scheme by adjusting our cluster size,
- * fat_start, and data_start by an appropriate value.
- *
- * (by Drew Eckhardt)
- */
-
-
b = (struct fat_boot_sector *) bh->b_data;
+ if (!b->secs_track) {
+ if (!silent)
+ printk("FAT: bogus sectors-per-track value\n");
+ brelse(bh);
+ goto out_invalid;
+ }
+ if (!b->heads) {
+ if (!silent)
+ printk("FAT: bogus number-of-heads value\n");
+ brelse(bh);
+ goto out_invalid;
+ }
logical_sector_size =
CF_LE_W(get_unaligned((unsigned short *) &b->sector_size));
if (!logical_sector_size
- || (logical_sector_size & (logical_sector_size - 1))) {
- printk("FAT: bogus logical sector size %d\n",
- logical_sector_size);
+ || (logical_sector_size & (logical_sector_size - 1))
+ || (logical_sector_size < 512)
+ || (PAGE_CACHE_SIZE < logical_sector_size)) {
+ if (!silent)
+ printk("FAT: bogus logical sector size %d\n",
+ logical_sector_size);
brelse(bh);
goto out_invalid;
}
-
sbi->cluster_size = b->cluster_size;
if (!sbi->cluster_size
|| (sbi->cluster_size & (sbi->cluster_size - 1))) {
- printk("FAT: bogus cluster size %d\n", sbi->cluster_size);
+ if (!silent)
+ printk("FAT: bogus cluster size %d\n",
+ sbi->cluster_size);
brelse(bh);
goto out_invalid;
}
@@ -625,47 +630,62 @@ fat_read_super(struct super_block *sb, void *data, int silent,
printk("FAT: logical sector size too small for device"
" (logical sector size = %d)\n", logical_sector_size);
brelse(bh);
- goto out_invalid;
+ goto out_fail;
}
+ if (logical_sector_size > sb->s_blocksize) {
+ brelse(bh);
- hard_blksize = sb->s_blocksize;
+ if (!sb_set_blocksize(sb, logical_sector_size)) {
+ printk("FAT: unable to set blocksize %d\n",
+ logical_sector_size);
+ goto out_fail;
+ }
+ bh = sb_bread(sb, 0);
+ if (bh == NULL) {
+ printk("FAT: unable to read boot sector"
+ " (logical sector size = %lu)\n",
+ sb->s_blocksize);
+ goto out_fail;
+ }
+ b = (struct fat_boot_sector *) bh->b_data;
+ }
- sbi->cluster_bits = ffs(logical_sector_size * sbi->cluster_size) - 1;
+ sbi->cluster_bits = ffs(sb->s_blocksize * sbi->cluster_size) - 1;
sbi->fats = b->fats;
+ sbi->fat_bits = 0; /* Don't know yet */
sbi->fat_start = CF_LE_W(b->reserved);
- if (!b->fat_length && b->fat32_length) {
+ sbi->fat_length = CF_LE_W(b->fat_length);
+ sbi->root_cluster = 0;
+ sbi->free_clusters = -1; /* Don't know yet */
+ sbi->prev_free = 0;
+
+ if (!sbi->fat_length && b->fat32_length) {
struct fat_boot_fsinfo *fsinfo;
struct buffer_head *fsinfo_bh;
- int fsinfo_block, fsinfo_offset;
/* Must be FAT32 */
- fat32 = 1;
+ sbi->fat_bits = 32;
sbi->fat_length = CF_LE_L(b->fat32_length);
sbi->root_cluster = CF_LE_L(b->root_cluster);
- sbi->fsinfo_sector = CF_LE_W(b->info_sector);
/* MC - if info_sector is 0, don't multiply by 0 */
+ sbi->fsinfo_sector = CF_LE_W(b->info_sector);
if (sbi->fsinfo_sector == 0)
sbi->fsinfo_sector = 1;
- fsinfo_block =
- (sbi->fsinfo_sector * logical_sector_size) / hard_blksize;
- fsinfo_offset =
- (sbi->fsinfo_sector * logical_sector_size) % hard_blksize;
- fsinfo_bh = bh;
- if (fsinfo_block != 0) {
- fsinfo_bh = sb_bread(sb, fsinfo_block);
- if (fsinfo_bh == NULL) {
- printk("FAT: bread failed, FSINFO block"
- " (blocknr = %d)\n", fsinfo_block);
- brelse(bh);
- goto out_invalid;
- }
+ fsinfo_bh = sb_bread(sb, sbi->fsinfo_sector);
+ if (fsinfo_bh == NULL) {
+ printk("FAT: bread failed, FSINFO block"
+ " (sector = %lu)\n", sbi->fsinfo_sector);
+ brelse(bh);
+ goto out_fail;
}
- fsinfo = (struct fat_boot_fsinfo *)&fsinfo_bh->b_data[fsinfo_offset];
+
+ fsinfo = (struct fat_boot_fsinfo *)fsinfo_bh->b_data;
if (!IS_FSINFO(fsinfo)) {
printk("FAT: Did not find valid FSINFO signature.\n"
- "Found signature1 0x%x signature2 0x%x sector=%ld.\n",
+ " Found signature1 0x%08x signature2 0x%08x"
+ " (sector = %lu)\n",
CF_LE_L(fsinfo->signature1),
CF_LE_L(fsinfo->signature2),
sbi->fsinfo_sector);
@@ -673,140 +693,110 @@ fat_read_super(struct super_block *sb, void *data, int silent,
sbi->free_clusters = CF_LE_L(fsinfo->free_clusters);
}
- if (fsinfo_block != 0)
- brelse(fsinfo_bh);
- } else {
- fat32 = 0;
- sbi->fat_length = CF_LE_W(b->fat_length);
- sbi->root_cluster = 0;
- sbi->free_clusters = -1; /* Don't know yet */
+ brelse(fsinfo_bh);
}
- sbi->dir_per_block = logical_sector_size / sizeof(struct msdos_dir_entry);
+ sbi->dir_per_block = sb->s_blocksize / sizeof(struct msdos_dir_entry);
sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1;
sbi->dir_start = sbi->fat_start + sbi->fats * sbi->fat_length;
sbi->dir_entries =
CF_LE_W(get_unaligned((unsigned short *)&b->dir_entries));
+ if (sbi->dir_entries & (sbi->dir_per_block - 1)) {
+ printk("FAT: bogus directroy-entries per block\n");
+ brelse(bh);
+ goto out_invalid;
+ }
+
rootdir_sectors = sbi->dir_entries
- * sizeof(struct msdos_dir_entry) / logical_sector_size;
+ * sizeof(struct msdos_dir_entry) / sb->s_blocksize;
sbi->data_start = sbi->dir_start + rootdir_sectors;
total_sectors = CF_LE_W(get_unaligned((unsigned short *)&b->sectors));
if (total_sectors == 0)
total_sectors = CF_LE_L(b->total_sect);
sbi->clusters = (total_sectors - sbi->data_start) / sbi->cluster_size;
- error = 0;
- if (!error) {
- sbi->fat_bits = fat32 ? 32 :
- (fat ? fat :
- (sbi->clusters > MSDOS_FAT12 ? 16 : 12));
- fat_clusters =
- sbi->fat_length * logical_sector_size * 8 / sbi->fat_bits;
- error = !sbi->fats || (sbi->dir_entries & (sbi->dir_per_block - 1))
- || sbi->clusters + 2 > fat_clusters + MSDOS_MAX_EXTRA
- || logical_sector_size < 512
- || PAGE_CACHE_SIZE < logical_sector_size
- || !b->secs_track || !b->heads;
- }
- brelse(bh);
+ if (sbi->fat_bits != 32)
+ sbi->fat_bits = (sbi->clusters > MSDOS_FAT12) ? 16 : 12;
- if (error)
- goto out_invalid;
+ /* check that FAT table does not overflow */
+ fat_clusters = sbi->fat_length * sb->s_blocksize * 8 / sbi->fat_bits;
+ if (sbi->clusters > fat_clusters - 2)
+ sbi->clusters = fat_clusters - 2;
+
+ brelse(bh);
- sb_set_blocksize(sb, logical_sector_size);
- sbi->cvf_format = &default_cvf;
if (!strcmp(cvf_format, "none"))
i = -1;
else
- i = detect_cvf(sb,cvf_format);
- if (i >= 0)
- error = cvf_formats[i]->mount_cvf(sb, cvf_options);
- if (error || debug) {
- /* The MSDOS_CAN_BMAP is obsolete, but left just to remember */
- printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
- "uid=%d,gid=%d,umask=%03o%s]\n",
- sbi->fat_bits,opts.name_check,
- opts.conversion,opts.fs_uid,opts.fs_gid,opts.fs_umask,
- MSDOS_CAN_BMAP(sbi) ? ",bmap" : "");
- printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%ld,ds=%ld,de=%d,data=%ld,"
- "se=%u,ts=%u,ls=%d,rc=%ld,fc=%u]\n",
- b->media, sbi->cluster_size, sbi->fats,
- sbi->fat_start, sbi->fat_length, sbi->dir_start,
- sbi->dir_entries, sbi->data_start,
- CF_LE_W(get_unaligned((unsigned short *)&b->sectors)),
- CF_LE_L(b->total_sect), logical_sector_size,
- sbi->root_cluster, sbi->free_clusters);
- printk ("hard sector size = %d\n", hard_blksize);
+ i = detect_cvf(sb, cvf_format);
+ if (i >= 0) {
+ if (cvf_formats[i]->mount_cvf(sb, cvf_options))
+ goto out_invalid;
}
- if (i < 0)
- if (sbi->clusters + 2 > fat_clusters)
- sbi->clusters = fat_clusters - 2;
- if (error)
- goto out_invalid;
- sb->s_magic = MSDOS_SUPER_MAGIC;
- /* set up enough so that it can read an inode */
- init_MUTEX(&sbi->fat_lock);
- sbi->prev_free = 0;
-
- cp = opts.codepage ? opts.codepage : 437;
+ cp = sbi->options.codepage ? sbi->options.codepage : 437;
sprintf(buf, "cp%d", cp);
sbi->nls_disk = load_nls(buf);
if (! sbi->nls_disk) {
/* Fail only if explicit charset specified */
- if (opts.codepage != 0)
+ if (sbi->options.codepage != 0) {
+ printk("FAT: codepage %s not found\n", buf);
goto out_fail;
+ }
sbi->options.codepage = 0; /* already 0?? */
sbi->nls_disk = load_nls_default();
}
-
- sbi->nls_io = NULL;
- if (sbi->options.isvfat && !opts.utf8) {
- p = opts.iocharset ? opts.iocharset : CONFIG_NLS_DEFAULT;
- sbi->nls_io = load_nls(p);
- if (! sbi->nls_io)
- /* Fail only if explicit charset specified */
- if (opts.iocharset)
- goto out_unload_nls;
+ if (!silent)
+ printk("FAT: Using codepage %s\n", sbi->nls_disk->charset);
+
+ if (sbi->options.isvfat && !sbi->options.utf8) {
+ if (sbi->options.iocharset != NULL) {
+ sbi->nls_io = load_nls(sbi->options.iocharset);
+ if (!sbi->nls_io) {
+ printk("FAT: IO charset %s not found\n",
+ sbi->options.iocharset);
+ goto out_fail;
+ }
+ } else
+ sbi->nls_io = load_nls_default();
+ if (!silent)
+ printk("FAT: Using IO charset %s\n",
+ sbi->nls_io->charset);
}
- if (! sbi->nls_io)
- sbi->nls_io = load_nls_default();
root_inode = new_inode(sb);
if (!root_inode)
- goto out_unload_nls;
+ goto out_fail;
+
root_inode->i_ino = MSDOS_ROOT_INO;
root_inode->i_version = 0;
fat_read_root(root_inode);
insert_inode_hash(root_inode);
sb->s_root = d_alloc_root(root_inode);
- if (!sb->s_root)
- goto out_no_root;
+ if (!sb->s_root) {
+ printk("FAT: get root inode failed\n");
+ iput(root_inode);
+ goto out_fail;
+ }
if(i >= 0) {
sbi->cvf_format = cvf_formats[i];
++cvf_format_use_count[i];
}
return sb;
-out_no_root:
- printk("FAT: get root inode failed\n");
- iput(root_inode);
- unload_nls(sbi->nls_io);
-out_unload_nls:
- unload_nls(sbi->nls_disk);
- goto out_fail;
out_invalid:
- if (!silent) {
+ if (!silent)
printk("VFS: Can't find a valid FAT filesystem on dev %s.\n",
sb->s_id);
- }
out_fail:
- if (opts.iocharset) {
- printk("FAT: freeing iocharset=%s\n", opts.iocharset);
- kfree(opts.iocharset);
- }
- if(sbi->private_data)
+ if (sbi->nls_io)
+ unload_nls(sbi->nls_io);
+ if (sbi->nls_disk)
+ unload_nls(sbi->nls_disk);
+ if (sbi->options.iocharset)
+ kfree(sbi->options.iocharset);
+ if (sbi->private_data)
kfree(sbi->private_data);
sbi->private_data = NULL;
@@ -882,7 +872,6 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
{
struct super_block *sb = inode->i_sb;
struct msdos_sb_info *sbi = MSDOS_SB(sb);
- int nr;
INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
MSDOS_I(inode)->i_location = 0;
@@ -913,15 +902,7 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
inode->i_nlink = 1;
}
#endif
- if ((nr = MSDOS_I(inode)->i_start) != 0)
- while (nr != -1) {
- inode->i_size += 1 << sbi->cluster_bits;
- if (!(nr = fat_access(sb, nr, -1))) {
- printk("Directory %ld: bad FAT\n",
- inode->i_ino);
- break;
- }
- }
+ fat_calc_dir_size(inode);
MSDOS_I(inode)->mmu_private = inode->i_size;
} else { /* not a directory */
inode->i_generation |= 1;
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 6f175afac..2f34195b5 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -38,15 +38,25 @@ static char ascii_extensions[] =
* read-only. The file system can be made writable again by remounting it.
*/
-void fat_fs_panic(struct super_block *s,const char *msg)
+static char panic_msg[512];
+
+void fat_fs_panic(struct super_block *s, const char *fmt, ...)
{
int not_ro;
+ va_list args;
+
+ va_start (args, fmt);
+ vsnprintf (panic_msg, sizeof(panic_msg), fmt, args);
+ va_end (args);
not_ro = !(s->s_flags & MS_RDONLY);
- if (not_ro) s->s_flags |= MS_RDONLY;
- printk("Filesystem panic (dev %s).\n %s\n", s->s_id, msg);
if (not_ro)
- printk(" File system has been set read-only\n");
+ s->s_flags |= MS_RDONLY;
+
+ printk("FAT: Filesystem panic (dev %s)\n"
+ " %s\n", s->s_id, panic_msg);
+ if (not_ro)
+ printk(" File system has been set read-only\n");
}
@@ -102,13 +112,14 @@ void fat_clusters_flush(struct super_block *sb)
/* Sanity check */
if (!IS_FSINFO(fsinfo)) {
printk("FAT: Did not find valid FSINFO signature.\n"
- "Found signature1 0x%x signature2 0x%x sector=%ld.\n",
+ " Found signature1 0x%08x signature2 0x%08x"
+ " (sector = %lu)\n",
CF_LE_L(fsinfo->signature1), CF_LE_L(fsinfo->signature2),
MSDOS_SB(sb)->fsinfo_sector);
- return;
+ } else {
+ fsinfo->free_clusters = CF_LE_L(MSDOS_SB(sb)->free_clusters);
+ fat_mark_buffer_dirty(sb, bh);
}
- fsinfo->free_clusters = CF_LE_L(MSDOS_SB(sb)->free_clusters);
- fat_mark_buffer_dirty(sb, bh);
fat_brelse(sb, bh);
}
@@ -472,11 +483,13 @@ static int raw_scan_nonroot(struct super_block *sb,int start,const char *name,
int *number,int *ino,struct buffer_head **res_bh,struct msdos_dir_entry
**res_de)
{
- int count,cluster;
+ int count, cluster;
+ unsigned long dir_size;
#ifdef DEBUG
printk("raw_scan_nonroot: start=%d\n",start);
#endif
+ dir_size = 0;
do {
for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) {
if ((cluster = raw_scan_sector(sb,(start-2)*
@@ -484,6 +497,13 @@ static int raw_scan_nonroot(struct super_block *sb,int start,const char *name,
count,name,number,ino,res_bh,res_de)) >= 0)
return cluster;
}
+ dir_size += 1 << MSDOS_SB(sb)->cluster_bits;
+ if (dir_size > FAT_MAX_DIR_SIZE) {
+ fat_fs_panic(sb, "Directory %d: "
+ "exceeded the maximum size of directory",
+ start);
+ break;
+ }
if (!(start = fat_access(sb,start,-1))) {
fat_fs_panic(sb,"FAT error");
break;
@@ -491,8 +511,8 @@ static int raw_scan_nonroot(struct super_block *sb,int start,const char *name,
#ifdef DEBUG
printk("next start: %d\n",start);
#endif
- }
- while (start != -1);
+ } while (start != -1);
+
return -ENOENT;
}
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 9f5171ecc..48d64f48f 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -20,6 +20,28 @@ extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg);
extern int fcntl_getlease(struct file *filp);
+void set_close_on_exec(unsigned int fd, int flag)
+{
+ struct files_struct *files = current->files;
+ write_lock(&files->file_lock);
+ if (flag)
+ FD_SET(fd, files->close_on_exec);
+ else
+ FD_CLR(fd, files->close_on_exec);
+ write_unlock(&files->file_lock);
+}
+
+static inline int get_close_on_exec(unsigned int fd)
+{
+ struct files_struct *files = current->files;
+ int res;
+ read_lock(&files->file_lock);
+ res = FD_ISSET(fd, files->close_on_exec);
+ read_unlock(&files->file_lock);
+ return res;
+}
+
+
/* Expand files. Return <0 on error; 0 nothing done; 1 files expanded,
* we may have blocked.
*
diff --git a/fs/file.c b/fs/file.c
index 51d9f7a25..200d7b1bf 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -11,6 +11,7 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
+#include <linux/file.h>
#include <asm/bitops.h>
diff --git a/fs/open.c b/fs/open.c
index f1e58fc98..aba53ed8d 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -772,6 +772,44 @@ out:
return error;
}
+static inline void __put_unused_fd(struct files_struct *files, unsigned int fd)
+{
+ __FD_CLR(fd, files->open_fds);
+ if (fd < files->next_fd)
+ files->next_fd = fd;
+}
+
+void put_unused_fd(unsigned int fd)
+{
+ struct files_struct *files = current->files;
+ write_lock(&files->file_lock);
+ __put_unused_fd(files, fd);
+ write_unlock(&files->file_lock);
+}
+
+/*
+ * Install a file pointer in the fd array.
+ *
+ * The VFS is full of places where we drop the files lock between
+ * setting the open_fds bitmap and installing the file in the file
+ * array. At any such point, we are vulnerable to a dup2() race
+ * installing a file in the array before us. We need to detect this and
+ * fput() the struct file we are about to overwrite in this case.
+ *
+ * It should never happen - if we allow dup2() do it, _really_ bad things
+ * will follow.
+ */
+
+void fd_install(unsigned int fd, struct file * file)
+{
+ struct files_struct *files = current->files;
+ write_lock(&files->file_lock);
+ if (unlikely(files->fd[fd] != NULL))
+ BUG();
+ files->fd[fd] = file;
+ write_unlock(&files->file_lock);
+}
+
asmlinkage long sys_open(const char * filename, int flags, int mode)
{
char * tmp;
diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile
index 2a7a0d642..e4cda5053 100644
--- a/fs/partitions/Makefile
+++ b/fs/partitions/Makefile
@@ -9,7 +9,7 @@
O_TARGET := partitions.o
-export-objs := check.o ibm.o
+export-objs := check.o ibm.o msdos.o
obj-y := check.o
diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c
index 870f9c112..fdf9a8271 100644
--- a/fs/partitions/msdos.c
+++ b/fs/partitions/msdos.c
@@ -29,7 +29,13 @@
#ifdef CONFIG_BLK_DEV_IDE
#include <linux/ide.h> /* IDE xlate */
-#endif /* CONFIG_BLK_DEV_IDE */
+#elif defined(CONFIG_BLK_DEV_IDE_MODULE)
+#include <linux/module.h>
+
+int (*ide_xlate_1024_hook)(kdev_t, int, int, const char *);
+EXPORT_SYMBOL(ide_xlate_1024_hook);
+#define ide_xlate_1024 ide_xlate_1024_hook
+#endif
#include <asm/system.h>
@@ -468,7 +474,7 @@ static struct {
*/
static int handle_ide_mess(struct block_device *bdev)
{
-#ifdef CONFIG_BLK_DEV_IDE
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
Sector sect;
unsigned char *data;
kdev_t dev = to_kdev_t(bdev->bd_dev);
@@ -476,6 +482,10 @@ static int handle_ide_mess(struct block_device *bdev)
int heads = 0;
struct partition *p;
int i;
+#ifdef CONFIG_BLK_DEV_IDE_MODULE
+ if (!ide_xlate_1024)
+ return 1;
+#endif
/*
* The i386 partition handling programs very often
* make partitions end on cylinder boundaries.
@@ -537,7 +547,7 @@ reread:
/* Flush the cache */
invalidate_bdev(bdev, 1);
truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
-#endif /* CONFIG_BLK_DEV_IDE */
+#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
return 1;
}
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 4ebf80ca1..d0fbb66a1 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -70,6 +70,7 @@
#include <linux/smp.h>
#include <linux/signal.h>
#include <linux/highmem.h>
+#include <linux/file.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index 30afba540..656b58f1b 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -446,7 +446,7 @@ struct shortname_info {
(x)->lower = 1; \
(x)->upper = 1; \
(x)->valid = 1; \
-} while (0);
+} while (0)
static inline unsigned char
shortname_info_to_lcase(struct shortname_info *base,
diff --git a/include/asm-alpha/ide.h b/include/asm-alpha/ide.h
index da698627e..5f6f9f576 100644
--- a/include/asm-alpha/ide.h
+++ b/include/asm-alpha/ide.h
@@ -91,7 +91,19 @@ typedef union {
unsigned lba : 1; /* using LBA instead of CHS */
unsigned bit7 : 1; /* always 1 */
} b;
- } select_t;
+} select_t;
+
+typedef union {
+ unsigned all : 8; /* all of the bits together */
+ struct {
+ unsigned bit0 : 1;
+ unsigned nIEN : 1; /* device INTRQ to host */
+ unsigned SRST : 1; /* host soft reset bit */
+ unsigned bit3 : 1; /* ATA-2 thingy */
+ unsigned reserved456 : 3;
+ unsigned HOB : 1; /* 48-bit address ordering */
+ } b;
+} control_t;
#define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id))
#define ide_free_irq(irq,dev_id) free_irq((irq), (dev_id))
diff --git a/include/asm-arm/ide.h b/include/asm-arm/ide.h
index 5b898dfee..05161e3e0 100644
--- a/include/asm-arm/ide.h
+++ b/include/asm-arm/ide.h
@@ -30,7 +30,19 @@ typedef union {
unsigned lba : 1; /* using LBA instead of CHS */
unsigned bit7 : 1; /* always 1 */
} b;
- } select_t;
+} select_t;
+
+typedef union {
+ unsigned all : 8; /* all of the bits together */
+ struct {
+ unsigned bit0 : 1;
+ unsigned nIEN : 1; /* device INTRQ to host */
+ unsigned SRST : 1; /* host soft reset bit */
+ unsigned bit3 : 1; /* ATA-2 thingy */
+ unsigned reserved456 : 3;
+ unsigned HOB : 1; /* 48-bit address ordering */
+ } b;
+} control_t;
#define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id))
#define ide_free_irq(irq,dev_id) free_irq((irq), (dev_id))
diff --git a/include/asm-cris/ide.h b/include/asm-cris/ide.h
index 39f402021..4ba84983c 100644
--- a/include/asm-cris/ide.h
+++ b/include/asm-cris/ide.h
@@ -97,7 +97,19 @@ typedef union {
unsigned lba : 1; /* using LBA instead of CHS */
unsigned bit7 : 1; /* always 1 */
} b;
- } select_t;
+} select_t;
+
+typedef union {
+ unsigned all : 8; /* all of the bits together */
+ struct {
+ unsigned bit0 : 1;
+ unsigned nIEN : 1; /* device INTRQ to host */
+ unsigned SRST : 1; /* host soft reset bit */
+ unsigned bit3 : 1; /* ATA-2 thingy */
+ unsigned reserved456 : 3;
+ unsigned HOB : 1; /* 48-bit address ordering */
+ } b;
+} control_t;
/* some configuration options we don't need */
diff --git a/include/asm-i386/ide.h b/include/asm-i386/ide.h
index 6ac787665..6642abf46 100644
--- a/include/asm-i386/ide.h
+++ b/include/asm-i386/ide.h
@@ -95,7 +95,19 @@ typedef union {
unsigned lba : 1; /* using LBA instead of CHS */
unsigned bit7 : 1; /* always 1 */
} b;
- } select_t;
+} select_t;
+
+typedef union {
+ unsigned all : 8; /* all of the bits together */
+ struct {
+ unsigned bit0 : 1;
+ unsigned nIEN : 1; /* device INTRQ to host */
+ unsigned SRST : 1; /* host soft reset bit */
+ unsigned bit3 : 1; /* ATA-2 thingy */
+ unsigned reserved456 : 3;
+ unsigned HOB : 1; /* 48-bit address ordering */
+ } b;
+} control_t;
#define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id))
#define ide_free_irq(irq,dev_id) free_irq((irq), (dev_id))
diff --git a/include/asm-ia64/ide.h b/include/asm-ia64/ide.h
index c0fe76856..697c2c51b 100644
--- a/include/asm-ia64/ide.h
+++ b/include/asm-ia64/ide.h
@@ -101,7 +101,19 @@ typedef union {
unsigned lba : 1; /* using LBA instead of CHS */
unsigned bit7 : 1; /* always 1 */
} b;
- } select_t;
+} select_t;
+
+typedef union {
+ unsigned all : 8; /* all of the bits together */
+ struct {
+ unsigned bit0 : 1;
+ unsigned nIEN : 1; /* device INTRQ to host */
+ unsigned SRST : 1; /* host soft reset bit */
+ unsigned bit3 : 1; /* ATA-2 thingy */
+ unsigned reserved456 : 3;
+ unsigned HOB : 1; /* 48-bit address ordering */
+ } b;
+} control_t;
#define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id))
#define ide_free_irq(irq,dev_id) free_irq((irq), (dev_id))
diff --git a/include/asm-m68k/ide.h b/include/asm-m68k/ide.h
index 10d8ac2d0..b44b8ccab 100644
--- a/include/asm-m68k/ide.h
+++ b/include/asm-m68k/ide.h
@@ -89,7 +89,19 @@ typedef union {
unsigned unit : 1; /* drive select number, 0 or 1 */
unsigned head : 4; /* always zeros here */
} b;
- } select_t;
+} select_t;
+
+typedef union {
+ unsigned all : 8; /* all of the bits together */
+ struct {
+ unsigned HOB : 1; /* 48-bit address ordering */
+ unsigned reserved456 : 3;
+ unsigned bit3 : 1; /* ATA-2 thingy */
+ unsigned SRST : 1; /* host soft reset bit */
+ unsigned nIEN : 1; /* device INTRQ to host */
+ unsigned bit0 : 1;
+ } b;
+} control_t;
static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
unsigned long flags, const char *device, void *dev_id)
diff --git a/include/asm-mips/ide.h b/include/asm-mips/ide.h
index f55d96601..26de4e40f 100644
--- a/include/asm-mips/ide.h
+++ b/include/asm-mips/ide.h
@@ -92,6 +92,26 @@ typedef union {
} b;
} select_t;
+typedef union {
+ unsigned all : 8; /* all of the bits together */
+ struct {
+#ifdef __MIPSEB__
+ unsigned HOB : 1; /* 48-bit address ordering */
+ unsigned reserved456 : 3;
+ unsigned SRST : 1; /* host soft reset bit */
+ unsigned nIEN : 1; /* device INTRQ to host */
+ unsigned bit0 : 1;
+#else
+ unsigned bit0 : 1;
+ unsigned nIEN : 1; /* device INTRQ to host */
+ unsigned SRST : 1; /* host soft reset bit */
+ unsigned bit3 : 1; /* ATA-2 thingy */
+ unsigned reserved456 : 3;
+ unsigned HOB : 1; /* 48-bit address ordering */
+#endif
+ } b;
+} control_t;
+
static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int,void *, struct pt_regs *),
unsigned long flags, const char *device, void *dev_id)
{
diff --git a/include/asm-mips64/ide.h b/include/asm-mips64/ide.h
index 8b37e1544..2221ccc4c 100644
--- a/include/asm-mips64/ide.h
+++ b/include/asm-mips64/ide.h
@@ -85,7 +85,19 @@ typedef union {
unsigned lba : 1; /* using LBA instead of CHS */
unsigned bit7 : 1; /* always 1 */
} b;
- } select_t;
+} select_t;
+
+typedef union {
+ unsigned all : 8; /* all of the bits together */
+ struct {
+ unsigned bit0 : 1;
+ unsigned nIEN : 1; /* device INTRQ to host */
+ unsigned SRST : 1; /* host soft reset bit */
+ unsigned bit3 : 1; /* ATA-2 thingy */
+ unsigned reserved456 : 3;
+ unsigned HOB : 1; /* 48-bit address ordering */
+ } b;
+} control_t;
static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int,void *, struct pt_regs *),
unsigned long flags, const char *device, void *dev_id)
diff --git a/include/asm-parisc/ide.h b/include/asm-parisc/ide.h
index 08d1c9408..bff2c7b34 100644
--- a/include/asm-parisc/ide.h
+++ b/include/asm-parisc/ide.h
@@ -90,7 +90,19 @@ typedef union {
unsigned lba : 1; /* using LBA instead of CHS */
unsigned bit7 : 1; /* always 1 */
} b;
- } select_t;
+} select_t;
+
+typedef union {
+ unsigned all : 8; /* all of the bits together */
+ struct {
+ unsigned bit0 : 1;
+ unsigned nIEN : 1; /* device INTRQ to host */
+ unsigned SRST : 1; /* host soft reset bit */
+ unsigned bit3 : 1; /* ATA-2 thingy */
+ unsigned reserved456 : 3;
+ unsigned HOB : 1; /* 48-bit address ordering */
+ } b;
+} control_t;
#define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id))
#define ide_free_irq(irq,dev_id) free_irq((irq), (dev_id))
diff --git a/include/asm-ppc/ide.h b/include/asm-ppc/ide.h
index bff070ea2..4906bffc8 100644
--- a/include/asm-ppc/ide.h
+++ b/include/asm-ppc/ide.h
@@ -129,6 +129,18 @@ typedef union {
} b;
} select_t;
+typedef union {
+ unsigned all : 8; /* all of the bits together */
+ struct {
+ unsigned HOB : 1; /* 48-bit address ordering */
+ unsigned reserved456 : 3;
+ unsigned bit3 : 1; /* ATA-2 thingy */
+ unsigned SRST : 1; /* host soft reset bit */
+ unsigned nIEN : 1; /* device INTRQ to host */
+ unsigned bit0 : 1;
+ } b;
+} control_t;
+
#if !defined(ide_request_irq)
#define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id))
#endif
diff --git a/include/asm-s390/ide.h b/include/asm-s390/ide.h
index eb47027ff..528d4faef 100644
--- a/include/asm-s390/ide.h
+++ b/include/asm-s390/ide.h
@@ -26,7 +26,19 @@ typedef union {
unsigned lba : 1; /* using LBA instead of CHS */
unsigned bit7 : 1; /* always 1 */
} b;
- } select_t;
+} select_t;
+
+typedef union {
+ unsigned all : 8; /* all of the bits together */
+ struct {
+ unsigned bit0 : 1;
+ unsigned nIEN : 1; /* device INTRQ to host */
+ unsigned SRST : 1; /* host soft reset bit */
+ unsigned bit3 : 1; /* ATA-2 thingy */
+ unsigned reserved456 : 3;
+ unsigned HOB : 1; /* 48-bit address ordering */
+ } b;
+} control_t;
#define ide_request_irq(irq,hand,flg,dev,id) do {} while (0)
#define ide_free_irq(irq,dev_id) do {} while (0)
diff --git a/include/asm-s390x/ide.h b/include/asm-s390x/ide.h
index eb47027ff..528d4faef 100644
--- a/include/asm-s390x/ide.h
+++ b/include/asm-s390x/ide.h
@@ -26,7 +26,19 @@ typedef union {
unsigned lba : 1; /* using LBA instead of CHS */
unsigned bit7 : 1; /* always 1 */
} b;
- } select_t;
+} select_t;
+
+typedef union {
+ unsigned all : 8; /* all of the bits together */
+ struct {
+ unsigned bit0 : 1;
+ unsigned nIEN : 1; /* device INTRQ to host */
+ unsigned SRST : 1; /* host soft reset bit */
+ unsigned bit3 : 1; /* ATA-2 thingy */
+ unsigned reserved456 : 3;
+ unsigned HOB : 1; /* 48-bit address ordering */
+ } b;
+} control_t;
#define ide_request_irq(irq,hand,flg,dev,id) do {} while (0)
#define ide_free_irq(irq,dev_id) do {} while (0)
diff --git a/include/asm-sh/ide.h b/include/asm-sh/ide.h
index 52375f498..3575578b3 100644
--- a/include/asm-sh/ide.h
+++ b/include/asm-sh/ide.h
@@ -116,7 +116,19 @@ typedef union {
unsigned lba : 1; /* using LBA instead of CHS */
unsigned bit7 : 1; /* always 1 */
} b;
- } select_t;
+} select_t;
+
+typedef union {
+ unsigned all : 8; /* all of the bits together */
+ struct {
+ unsigned bit0 : 1;
+ unsigned nIEN : 1; /* device INTRQ to host */
+ unsigned SRST : 1; /* host soft reset bit */
+ unsigned bit3 : 1; /* ATA-2 thingy */
+ unsigned reserved456 : 3;
+ unsigned HOB : 1; /* 48-bit address ordering */
+ } b;
+} control_t;
#define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id))
#define ide_free_irq(irq,dev_id) free_irq((irq), (dev_id))
diff --git a/include/asm-sparc/ide.h b/include/asm-sparc/ide.h
index 36416d692..f1f78679b 100644
--- a/include/asm-sparc/ide.h
+++ b/include/asm-sparc/ide.h
@@ -1,4 +1,4 @@
-/* $Id: ide.h,v 1.6 2000-05-27 00:49:37 davem Exp $
+/* $Id: ide.h,v 1.7 2002-01-16 20:58:40 davem Exp $
* ide.h: SPARC PCI specific IDE glue.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -84,6 +84,18 @@ typedef union {
} b;
} select_t;
+typedef union {
+ unsigned int all : 8; /* all of the bits together */
+ struct {
+ unsigned int HOB : 1; /* 48-bit address ordering */
+ unsigned int reserved456: 3;
+ unsigned bit3 : 1; /* ATA-2 thingy */
+ unsigned int SRST : 1; /* host soft reset bit */
+ unsigned int nIEN : 1; /* device INTRQ to host */
+ unsigned int bit0 : 1;
+ } b;
+} control_t;
+
static __inline__ int ide_request_irq(unsigned int irq,
void (*handler)(int, void *, struct pt_regs *),
unsigned long flags, const char *name, void *devid)
diff --git a/include/asm-sparc64/ide.h b/include/asm-sparc64/ide.h
index 06a25ca2d..5f4053cf8 100644
--- a/include/asm-sparc64/ide.h
+++ b/include/asm-sparc64/ide.h
@@ -1,4 +1,4 @@
-/* $Id: ide.h,v 1.21 2001-09-25 20:21:48 kanoj Exp $
+/* $Id: ide.h,v 1.22 2002-01-16 20:58:40 davem Exp $
* ide.h: Ultra/PCI specific IDE glue.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -80,6 +80,18 @@ typedef union {
} b;
} select_t;
+typedef union {
+ unsigned int all : 8; /* all of the bits together */
+ struct {
+ unsigned int HOB : 1; /* 48-bit address ordering */
+ unsigned int reserved456: 3;
+ unsigned bit3 : 1; /* ATA-2 thingy */
+ unsigned int SRST : 1; /* host soft reset bit */
+ unsigned int nIEN : 1; /* device INTRQ to host */
+ unsigned int bit0 : 1;
+ } b;
+} control_t;
+
static __inline__ int ide_request_irq(unsigned int irq,
void (*handler)(int, void *, struct pt_regs *),
unsigned long flags, const char *name, void *devid)
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 0cbe78286..ad5250710 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -80,6 +80,7 @@ enum rq_flag_bits {
*/
__REQ_DRIVE_CMD,
__REQ_DRIVE_TASK,
+ __REQ_DRIVE_ACB,
__REQ_PC, /* packet command (special) */
__REQ_BLOCK_PC, /* queued down pc from block layer */
@@ -99,11 +100,14 @@ enum rq_flag_bits {
#define REQ_DONTPREP (1 << __REQ_DONTPREP)
#define REQ_DRIVE_CMD (1 << __REQ_DRIVE_CMD)
#define REQ_DRIVE_TASK (1 << __REQ_DRIVE_TASK)
+#define REQ_DRIVE_ACB (1 << __REQ_DRIVE_ACB)
#define REQ_PC (1 << __REQ_PC)
#define REQ_SENSE (1 << __REQ_SENSE)
#define REQ_BLOCK_PC (1 << __REQ_BLOCK_PC)
#define REQ_SPECIAL (1 << __REQ_SPECIAL)
+#define REQ_DRIVE_TASKFILE REQ_DRIVE_ACB
+
#include <linux/elevator.h>
typedef int (merge_request_fn) (request_queue_t *, struct request *,
diff --git a/include/linux/file.h b/include/linux/file.h
index 0994be612..bac312507 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -5,31 +5,43 @@
#ifndef __LINUX_FILE_H
#define __LINUX_FILE_H
-#include <linux/sched.h>
+#ifndef _LINUX_POSIX_TYPES_H /* __FD_CLR */
+#include <linux/posix_types.h>
+#endif
+#ifndef __LINUX_COMPILER_H /* unlikely */
+#include <linux/compiler.h>
+#endif
+
+/*
+ * The default fd array needs to be at least BITS_PER_LONG,
+ * as this is the granularity returned by copy_fdset().
+ */
+#define NR_OPEN_DEFAULT BITS_PER_LONG
+
+/*
+ * Open file table structure
+ */
+struct files_struct {
+ atomic_t count;
+ rwlock_t file_lock; /* Protects all the below members. Nests inside tsk->alloc_lock */
+ int max_fds;
+ int max_fdset;
+ int next_fd;
+ struct file ** fd; /* current fd array */
+ fd_set *close_on_exec;
+ fd_set *open_fds;
+ fd_set close_on_exec_init;
+ fd_set open_fds_init;
+ struct file * fd_array[NR_OPEN_DEFAULT];
+};
extern void FASTCALL(fput(struct file *));
extern struct file * FASTCALL(fget(unsigned int fd));
-
-static inline int get_close_on_exec(unsigned int fd)
-{
- struct files_struct *files = current->files;
- int res;
- read_lock(&files->file_lock);
- res = FD_ISSET(fd, files->close_on_exec);
- read_unlock(&files->file_lock);
- return res;
-}
+extern void FASTCALL(set_close_on_exec(unsigned int fd, int flag));
+extern void put_filp(struct file *);
+extern int get_unused_fd(void);
+extern void FASTCALL(put_unused_fd(unsigned int fd));
-static inline void set_close_on_exec(unsigned int fd, int flag)
-{
- struct files_struct *files = current->files;
- write_lock(&files->file_lock);
- if (flag)
- FD_SET(fd, files->close_on_exec);
- else
- FD_CLR(fd, files->close_on_exec);
- write_unlock(&files->file_lock);
-}
static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
{
@@ -43,60 +55,9 @@ static inline struct file * fcheck_files(struct files_struct *files, unsigned in
/*
* Check whether the specified fd has an open file.
*/
-static inline struct file * fcheck(unsigned int fd)
-{
- struct file * file = NULL;
- struct files_struct *files = current->files;
-
- if (fd < files->max_fds)
- file = files->fd[fd];
- return file;
-}
-
-extern void put_filp(struct file *);
-
-extern int get_unused_fd(void);
-
-static inline void __put_unused_fd(struct files_struct *files, unsigned int fd)
-{
- FD_CLR(fd, files->open_fds);
- if (fd < files->next_fd)
- files->next_fd = fd;
-}
-
-static inline void put_unused_fd(unsigned int fd)
-{
- struct files_struct *files = current->files;
-
- write_lock(&files->file_lock);
- __put_unused_fd(files, fd);
- write_unlock(&files->file_lock);
-}
-
-/*
- * Install a file pointer in the fd array.
- *
- * The VFS is full of places where we drop the files lock between
- * setting the open_fds bitmap and installing the file in the file
- * array. At any such point, we are vulnerable to a dup2() race
- * installing a file in the array before us. We need to detect this and
- * fput() the struct file we are about to overwrite in this case.
- *
- * It should never happen - if we allow dup2() do it, _really_ bad things
- * will follow.
- */
-
-static inline void fd_install(unsigned int fd, struct file * file)
-{
- struct files_struct *files = current->files;
-
- write_lock(&files->file_lock);
- if (files->fd[fd])
- BUG();
- files->fd[fd] = file;
- write_unlock(&files->file_lock);
-}
+#define fcheck(fd) fcheck_files(current->files, fd)
-void put_files_struct(struct files_struct *fs);
+extern void FASTCALL(fd_install(unsigned int fd, struct file * file));
+void FASTCALL(put_files_struct(struct files_struct *fs));
#endif /* __LINUX_FILE_H */
diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h
index 97289e19f..703b75011 100644
--- a/include/linux/hdreg.h
+++ b/include/linux/hdreg.h
@@ -6,104 +6,269 @@
* Various sources.
*/
-#define HD_IRQ 14 /* the standard disk interrupt */
+#define HD_IRQ 14 /* the standard disk interrupt */
/* ide.c has its own port definitions in "ide.h" */
/* Hd controller regs. Ref: IBM AT Bios-listing */
-#define HD_DATA 0x1f0 /* _CTL when writing */
-#define HD_ERROR 0x1f1 /* see err-bits */
-#define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */
-#define HD_SECTOR 0x1f3 /* starting sector */
-#define HD_LCYL 0x1f4 /* starting cylinder */
-#define HD_HCYL 0x1f5 /* high byte of starting cyl */
-#define HD_CURRENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */
-#define HD_STATUS 0x1f7 /* see status-bits */
-#define HD_FEATURE HD_ERROR /* same io address, read=error, write=feature */
-#define HD_PRECOMP HD_FEATURE /* obsolete use of this port - predates IDE */
-#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */
-
-#define HD_CMD 0x3f6 /* used for resets */
-#define HD_ALTSTATUS 0x3f6 /* same as HD_STATUS but doesn't clear irq */
+#define HD_DATA 0x1f0 /* _CTL when writing */
+#define HD_ERROR 0x1f1 /* see err-bits */
+#define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */
+#define HD_SECTOR 0x1f3 /* starting sector */
+#define HD_LCYL 0x1f4 /* starting cylinder */
+#define HD_HCYL 0x1f5 /* high byte of starting cyl */
+#define HD_CURRENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */
+#define HD_STATUS 0x1f7 /* see status-bits */
+#define HD_FEATURE HD_ERROR /* same io address, read=error, write=feature */
+#define HD_PRECOMP HD_FEATURE /* obsolete use of this port - predates IDE */
+#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */
+
+#define HD_CMD 0x3f6 /* used for resets */
+#define HD_ALTSTATUS 0x3f6 /* same as HD_STATUS but doesn't clear irq */
/* remainder is shared between hd.c, ide.c, ide-cd.c, and the hdparm utility */
/* Bits of HD_STATUS */
-#define ERR_STAT 0x01
-#define INDEX_STAT 0x02
-#define ECC_STAT 0x04 /* Corrected error */
-#define DRQ_STAT 0x08
-#define SEEK_STAT 0x10
-#define WRERR_STAT 0x20
-#define READY_STAT 0x40
-#define BUSY_STAT 0x80
-
-/* Values for HD_COMMAND */
-#define WIN_RESTORE 0x10
-#define WIN_READ 0x20
-#define WIN_WRITE 0x30
-#define WIN_WRITE_VERIFY 0x3C
-#define WIN_VERIFY 0x40
-#define WIN_FORMAT 0x50
-#define WIN_INIT 0x60
-#define WIN_SEEK 0x70
-#define WIN_DIAGNOSE 0x90
-#define WIN_SPECIFY 0x91 /* set drive geometry translation */
-#define WIN_IDLEIMMEDIATE 0xE1 /* force drive to become "ready" */
-#define WIN_SETIDLE1 0xE3
-#define WIN_SETIDLE2 0x97
-
-#define WIN_STANDBYNOW1 0xE0
-#define WIN_STANDBYNOW2 0x94
-#define WIN_SLEEPNOW1 0xE6
-#define WIN_SLEEPNOW2 0x99
-#define WIN_CHECKPOWERMODE1 0xE5
-#define WIN_CHECKPOWERMODE2 0x98
-
-#define WIN_DOORLOCK 0xDE /* lock door on removable drives */
-#define WIN_DOORUNLOCK 0xDF /* unlock door on removable drives */
-
-#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode */
-#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */
-#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */
-#define WIN_IDENTIFY 0xEC /* ask drive to identify itself */
-#define WIN_IDENTIFY_DMA 0xEE /* same as WIN_IDENTIFY, but DMA */
-#define WIN_SETFEATURES 0xEF /* set special drive features */
-#define WIN_READDMA 0xC8 /* read sectors using DMA transfers */
-#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */
-
-#define WIN_QUEUED_SERVICE 0xA2 /* */
-#define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers */
-#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */
-
-#define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */
-#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */
-
-#define WIN_SMART 0xB0 /* self-monitoring and reporting */
-
-/* Additional drive command codes used by ATAPI devices. */
-#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */
-#define WIN_SRST 0x08 /* ATAPI soft reset command */
-#define WIN_PACKETCMD 0xA0 /* Send a packet command. */
-
-#define DISABLE_SEAGATE 0xFB
-#define EXABYTE_ENABLE_NEST 0xF0
+#define ERR_STAT 0x01
+#define INDEX_STAT 0x02
+#define ECC_STAT 0x04 /* Corrected error */
+#define DRQ_STAT 0x08
+#define SEEK_STAT 0x10
+#define WRERR_STAT 0x20
+#define READY_STAT 0x40
+#define BUSY_STAT 0x80
-/* WIN_SMART sub-commands */
+/* Bits for HD_ERROR */
+#define MARK_ERR 0x01 /* Bad address mark */
+#define TRK0_ERR 0x02 /* couldn't find track 0 */
+#define ABRT_ERR 0x04 /* Command aborted */
+#define MCR_ERR 0x08 /* media change request */
+#define ID_ERR 0x10 /* ID field not found */
+#define MC_ERR 0x20 /* media changed */
+#define ECC_ERR 0x40 /* Uncorrectable ECC error */
+#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */
+#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */
+
+/*
+ * Command Header sizes for IOCTL commands
+ * HDIO_DRIVE_CMD, HDIO_DRIVE_TASK, and HDIO_DRIVE_TASKFILE
+ */
+
+#if 0
+#include <asm/hdreg.h>
+typedef ide_ioreg_t task_ioreg_t;
+#else
+typedef unsigned char task_ioreg_t;
+#endif
+
+#define HDIO_DRIVE_CMD_HDR_SIZE 4*sizeof(task_ioreg_t)
+#define HDIO_DRIVE_TASK_HDR_SIZE 8*sizeof(task_ioreg_t)
+#define HDIO_DRIVE_HOB_HDR_SIZE 8*sizeof(task_ioreg_t)
-#define SMART_READ_VALUES 0xd0
-#define SMART_READ_THRESHOLDS 0xd1
-#define SMART_AUTOSAVE 0xd2
-#define SMART_SAVE 0xd3
-#define SMART_IMMEDIATE_OFFLINE 0xd4
-#define SMART_READ_LOG_SECTOR 0xd5
-#define SMART_WRITE_LOG_SECTOR 0xd6
-#define SMART_WRITE_THRESHOLDS 0xd7
-#define SMART_ENABLE 0xd8
-#define SMART_DISABLE 0xd9
-#define SMART_STATUS 0xda
-#define SMART_AUTO_OFFLINE 0xdb
+#define IDE_DRIVE_TASK_INVALID -1
+#define IDE_DRIVE_TASK_NO_DATA 0
+#define IDE_DRIVE_TASK_SET_XFER 1
+#define IDE_DRIVE_TASK_IN 2
+
+#define IDE_DRIVE_TASK_OUT 3
+#define IDE_DRIVE_TASK_RAW_WRITE 4
+
+struct hd_drive_cmd_hdr {
+ task_ioreg_t command;
+ task_ioreg_t sector_number;
+ task_ioreg_t feature;
+ task_ioreg_t sector_count;
+};
+
+typedef struct hd_drive_task_hdr {
+ task_ioreg_t data;
+ task_ioreg_t feature;
+ task_ioreg_t sector_count;
+ task_ioreg_t sector_number;
+ task_ioreg_t low_cylinder;
+ task_ioreg_t high_cylinder;
+ task_ioreg_t device_head;
+ task_ioreg_t command;
+} task_struct_t;
+
+typedef struct hd_drive_hob_hdr {
+ task_ioreg_t data;
+ task_ioreg_t feature;
+ task_ioreg_t sector_count;
+ task_ioreg_t sector_number;
+ task_ioreg_t low_cylinder;
+ task_ioreg_t high_cylinder;
+ task_ioreg_t device_head;
+ task_ioreg_t control;
+} hob_struct_t;
+
+typedef union ide_reg_valid_s {
+ unsigned all : 16;
+ struct {
+ unsigned data : 1;
+ unsigned error_feature : 1;
+ unsigned sector : 1;
+ unsigned nsector : 1;
+ unsigned lcyl : 1;
+ unsigned hcyl : 1;
+ unsigned select : 1;
+ unsigned status_command : 1;
+
+ unsigned data_hob : 1;
+ unsigned error_feature_hob : 1;
+ unsigned sector_hob : 1;
+ unsigned nsector_hob : 1;
+ unsigned lcyl_hob : 1;
+ unsigned hcyl_hob : 1;
+ unsigned select_hob : 1;
+ unsigned control_hob : 1;
+ } b;
+} ide_reg_valid_t;
+
+/*
+ * Define standard taskfile in/out register
+ */
+#define IDE_TASKFILE_STD_OUT_FLAGS 0xFE
+#define IDE_TASKFILE_STD_IN_FLAGS 0xFE
+#define IDE_HOB_STD_OUT_FLAGS 0xC0
+#define IDE_HOB_STD_IN_FLAGS 0xC0
+
+typedef struct ide_task_request_s {
+ task_ioreg_t io_ports[8];
+ task_ioreg_t hob_ports[8];
+ ide_reg_valid_t out_flags;
+ ide_reg_valid_t in_flags;
+ int data_phase;
+ int req_cmd;
+ unsigned long out_size;
+ unsigned long in_size;
+} ide_task_request_t;
+
+typedef struct ide_ioctl_request_s {
+ ide_task_request_t *task_request;
+ unsigned char *out_buffer;
+ unsigned char *in_buffer;
+} ide_ioctl_request_t;
+
+#define TASKFILE_INVALID 0x7fff
+#define TASKFILE_48 0x8000
+
+#define TASKFILE_NO_DATA 0x0000
+
+#define TASKFILE_IN 0x0001
+#define TASKFILE_MULTI_IN 0x0002
+
+#define TASKFILE_OUT 0x0004
+#define TASKFILE_MULTI_OUT 0x0008
+#define TASKFILE_IN_OUT 0x0010
+
+#define TASKFILE_IN_DMA 0x0020
+#define TASKFILE_OUT_DMA 0x0040
+#define TASKFILE_IN_DMAQ 0x0080
+#define TASKFILE_OUT_DMAQ 0x0100
+
+#define TASKFILE_P_IN 0x0200
+#define TASKFILE_P_OUT 0x0400
+#define TASKFILE_P_IN_DMA 0x0800
+#define TASKFILE_P_OUT_DMA 0x1000
+#define TASKFILE_P_IN_DMAQ 0x2000
+#define TASKFILE_P_OUT_DMAQ 0x4000
+
+/* ATA/ATAPI Commands pre T13 Spec */
+#define WIN_NOP 0x00
+#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */
+#define WIN_SRST 0x08 /* ATAPI soft reset command */
+#define WIN_DEVICE_RESET 0x08
+#define WIN_RESTORE 0x10
+#define WIN_READ 0x20 /* 28-Bit */
+#define WIN_READ_EXT 0x24 /* 48-Bit */
+#define WIN_READDMA_EXT 0x25 /* 48-Bit */
+#define WIN_READDMA_QUEUED_EXT 0x26 /* 48-Bit */
+#define WIN_READ_NATIVE_MAX_EXT 0x27 /* 48-Bit */
+#define WIN_MULTREAD_EXT 0x29 /* 48-Bit */
+#define WIN_WRITE 0x30 /* 28-Bit */
+#define WIN_WRITE_EXT 0x34 /* 48-Bit */
+#define WIN_WRITEDMA_EXT 0x35 /* 48-Bit */
+#define WIN_WRITEDMA_QUEUED_EXT 0x36 /* 48-Bit */
+#define WIN_SET_MAX_EXT 0x37 /* 48-Bit */
+#define CFA_WRITE_SECT_WO_ERASE 0x38 /* CFA Write Sectors without erase */
+#define WIN_MULTWRITE_EXT 0x39 /* 48-Bit */
+#define WIN_WRITE_VERIFY 0x3C /* 28-Bit */
+#define WIN_VERIFY 0x40 /* 28-Bit - Read Verify Sectors */
+#define WIN_VERIFY_EXT 0x42 /* 48-Bit */
+#define WIN_FORMAT 0x50
+#define WIN_INIT 0x60
+#define WIN_SEEK 0x70
+#define CFA_TRANSLATE_SECTOR 0x87 /* CFA Translate Sector */
+#define WIN_DIAGNOSE 0x90
+#define WIN_SPECIFY 0x91 /* set drive geometry translation */
+#define WIN_DOWNLOAD_MICROCODE 0x92
+#define WIN_STANDBYNOW2 0x94
+#define WIN_SETIDLE2 0x97
+#define WIN_CHECKPOWERMODE2 0x98
+#define WIN_SLEEPNOW2 0x99
+#define WIN_PACKETCMD 0xA0 /* Send a packet command. */
+#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */
+#define WIN_QUEUED_SERVICE 0xA2
+#define WIN_SMART 0xB0 /* self-monitoring and reporting */
+#define CFA_ERASE_SECTORS 0xC0
+#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/
+#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */
+#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */
+#define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers */
+#define WIN_READDMA 0xC8 /* read sectors using DMA transfers */
+#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */
+#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */
+#define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */
+#define WIN_GETMEDIASTATUS 0xDA
+#define WIN_DOORLOCK 0xDE /* lock door on removable drives */
+#define WIN_DOORUNLOCK 0xDF /* unlock door on removable drives */
+#define WIN_STANDBYNOW1 0xE0
+#define WIN_IDLEIMMEDIATE 0xE1 /* force drive to become "ready" */
+#define WIN_STANDBY 0xE2 /* Set device in Standby Mode */
+#define WIN_SETIDLE1 0xE3
+#define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */
+#define WIN_CHECKPOWERMODE1 0xE5
+#define WIN_SLEEPNOW1 0xE6
+#define WIN_FLUSH_CACHE 0xE7
+#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */
+#define WIN_FLUSH_CACHE_EXT 0xEA /* 48-Bit */
+#define WIN_IDENTIFY 0xEC /* ask drive to identify itself */
+#define WIN_MEDIAEJECT 0xED
+#define WIN_IDENTIFY_DMA 0xEE /* same as WIN_IDENTIFY, but DMA */
+#define WIN_SETFEATURES 0xEF /* set special drive features */
+#define EXABYTE_ENABLE_NEST 0xF0
+#define WIN_SECURITY_SET_PASS 0xF1
+#define WIN_SECURITY_UNLOCK 0xF2
+#define WIN_SECURITY_ERASE_PREPARE 0xF3
+#define WIN_SECURITY_ERASE_UNIT 0xF4
+#define WIN_SECURITY_FREEZE_LOCK 0xF5
+#define WIN_SECURITY_DISABLE 0xF6
+#define WIN_READ_NATIVE_MAX 0xF8 /* return the native maximum address */
+#define WIN_SET_MAX 0xF9
+#define DISABLE_SEAGATE 0xFB
+
+/* WIN_SMART sub-commands */
+
+#define SMART_READ_VALUES 0xD0
+#define SMART_READ_THRESHOLDS 0xD1
+#define SMART_AUTOSAVE 0xD2
+#define SMART_SAVE 0xD3
+#define SMART_IMMEDIATE_OFFLINE 0xD4
+#define SMART_READ_LOG_SECTOR 0xD5
+#define SMART_WRITE_LOG_SECTOR 0xD6
+#define SMART_WRITE_THRESHOLDS 0xD7
+#define SMART_ENABLE 0xD8
+#define SMART_DISABLE 0xD9
+#define SMART_STATUS 0xDA
+#define SMART_AUTO_OFFLINE 0xDB
+
+/* Password used in TF4 & TF5 executing SMART commands */
+
+#define SMART_LCYL_PASS 0x4F
+#define SMART_HCYL_PASS 0xC2
+
/* WIN_SETFEATURES sub-commands */
#define SETFEATURES_EN_WCACHE 0x02 /* Enable write cache */
@@ -131,6 +296,7 @@
#define SETFEATURES_DIS_DEFECT 0x04 /* Disable Defect Management */
#define SETFEATURES_EN_APM 0x05 /* Enable advanced power management */
#define SETFEATURES_DIS_MSN 0x31 /* Disable Media Status Notification */
+#define SETFEATURES_EN_AAM 0x42 /* Enable Automatic Acoustic Management */
#define SETFEATURES_DIS_RLA 0x55 /* Disable read look-ahead feature */
#define SETFEATURES_EN_RI 0x5D /* Enable release interrupt */
#define SETFEATURES_EN_SI 0x5E /* Enable SERVICE interrupt */
@@ -141,29 +307,19 @@
#define SETFEATURES_EN_MSN 0x95 /* Enable Media Status Notification */
#define SETFEATURES_EN_RLA 0xAA /* Enable read look-ahead feature */
#define SETFEATURES_PREFETCH 0xAB /* Sets drive prefetch value */
+#define SETFEATURES_DIS_AAM 0xC2 /* Disable Automatic Acoustic Management */
#define SETFEATURES_EN_RPOD 0xCC /* Enable reverting to power on defaults */
#define SETFEATURES_DIS_RI 0xDD /* Disable release interrupt */
#define SETFEATURES_DIS_SI 0xDE /* Disable SERVICE interrupt */
/* WIN_SECURITY sub-commands */
-#define SECURITY_SET_PASSWORD 0xBA /* 0xF1 */
-#define SECURITY_UNLOCK 0xBB /* 0xF2 */
-#define SECURITY_ERASE_PREPARE 0xBC /* 0xF3 */
-#define SECURITY_ERASE_UNIT 0xBD /* 0xF4 */
-#define SECURITY_FREEZE_LOCK 0xBE /* 0xF5 */
-#define SECURITY_DISABLE_PASSWORD 0xBF /* 0xF6 */
-
-/* Bits for HD_ERROR */
-#define MARK_ERR 0x01 /* Bad address mark */
-#define TRK0_ERR 0x02 /* couldn't find track 0 */
-#define ABRT_ERR 0x04 /* Command aborted */
-#define MCR_ERR 0x08 /* media change request */
-#define ID_ERR 0x10 /* ID field not found */
-#define MC_ERR 0x20 /* media changed */
-#define ECC_ERR 0x40 /* Uncorrectable ECC error */
-#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */
-#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */
+#define SECURITY_SET_PASSWORD 0xBA
+#define SECURITY_UNLOCK 0xBB
+#define SECURITY_ERASE_PREPARE 0xBC
+#define SECURITY_ERASE_UNIT 0xBD
+#define SECURITY_FREEZE_LOCK 0xBE
+#define SECURITY_DISABLE_PASSWORD 0xBF
struct hd_geometry {
unsigned char heads;
@@ -172,6 +328,14 @@ struct hd_geometry {
unsigned long start;
};
+/* BIG GEOMETRY */
+struct hd_big_geometry {
+ unsigned char heads;
+ unsigned char sectors;
+ unsigned int cylinders;
+ unsigned long start;
+};
+
/* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x030n/0x031n */
#define HDIO_GETGEO 0x0301 /* get device geometry */
#define HDIO_GET_UNMASKINTR 0x0302 /* get current unmask setting */
@@ -186,9 +350,10 @@ struct hd_geometry {
#define HDIO_GET_IDENTITY 0x030d /* get IDE identification info */
#define HDIO_GET_WCACHE 0x030e /* get write cache mode on|off */
#define HDIO_GET_ACOUSTIC 0x030f /* get acoustic value */
+#define HDIO_GET_ADDRESS 0x0310 /* */
#define HDIO_GET_BUSSTATE 0x031a /* get the bus state of the hwif */
-#define HDIO_TRISTATE_HWIF 0x031b /* OBSOLETE - use SET_BUSSTATE */
+#define HDIO_TRISTATE_HWIF 0x031b /* execute a channel tristate */
#define HDIO_DRIVE_RESET 0x031c /* execute a device reset */
#define HDIO_DRIVE_TASKFILE 0x031d /* execute raw taskfile */
#define HDIO_DRIVE_TASK 0x031e /* execute task and special drive command */
@@ -211,6 +376,7 @@ struct hd_geometry {
#define HDIO_SET_ACOUSTIC 0x032c /* change acoustic behavior */
#define HDIO_SET_BUSSTATE 0x032d /* set the bus state of the hwif */
#define HDIO_SET_QDMA 0x032e /* change use-qdma flag */
+#define HDIO_SET_ADDRESS 0x032f /* change lba addressing modes */
/* bus states */
enum {
@@ -219,34 +385,30 @@ enum {
BUSSTATE_TRISTATE
};
-/* BIG GEOMETRY */
-struct hd_big_geometry {
- unsigned char heads;
- unsigned char sectors;
- unsigned int cylinders;
- unsigned long start;
-};
-
/* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x033n/0x033n */
#define HDIO_GETGEO_BIG 0x0330 /* */
#define HDIO_GETGEO_BIG_RAW 0x0331 /* */
#define __NEW_HD_DRIVE_ID
-/* structure returned by HDIO_GET_IDENTITY, as per ANSI ATA2 rev.2f spec */
+/* structure returned by HDIO_GET_IDENTITY,
+ * as per ANSI NCITS ATA6 rev.1b spec
+ */
struct hd_driveid {
unsigned short config; /* lots of obsolete bit flags */
- unsigned short cyls; /* "physical" cyls */
+ unsigned short cyls; /* Obsolete, "physical" cyls */
unsigned short reserved2; /* reserved (word 2) */
- unsigned short heads; /* "physical" heads */
+ unsigned short heads; /* Obsolete, "physical" heads */
unsigned short track_bytes; /* unformatted bytes per track */
unsigned short sector_bytes; /* unformatted bytes per sector */
- unsigned short sectors; /* "physical" sectors per track */
+ unsigned short sectors; /* Obsolete, "physical" sectors per track */
unsigned short vendor0; /* vendor unique */
unsigned short vendor1; /* vendor unique */
- unsigned short vendor2; /* vendor unique */
+ unsigned short vendor2; /* Retired vendor unique */
unsigned char serial_no[20]; /* 0 = not_specified */
- unsigned short buf_type;
- unsigned short buf_size; /* 512 byte increments; 0 = not_specified */
+ unsigned short buf_type; /* Retired */
+ unsigned short buf_size; /* Retired, 512 byte increments
+ * 0 = not_specified
+ */
unsigned short ecc_bytes; /* for r/w long cmds; 0 = not_specified */
unsigned char fw_rev[8]; /* 0 = not_specified */
unsigned char model[40]; /* 0 = not_specified */
@@ -254,72 +416,223 @@ struct hd_driveid {
unsigned char vendor3; /* vendor unique */
unsigned short dword_io; /* 0=not_implemented; 1=implemented */
unsigned char vendor4; /* vendor unique */
- unsigned char capability; /* bits 0:DMA 1:LBA 2:IORDYsw 3:IORDYsup*/
+ unsigned char capability; /* (upper byte of word 49)
+ * 3: IORDYsup
+ * 2: IORDYsw
+ * 1: LBA
+ * 0: DMA
+ */
unsigned short reserved50; /* reserved (word 50) */
- unsigned char vendor5; /* vendor unique */
- unsigned char tPIO; /* 0=slow, 1=medium, 2=fast */
- unsigned char vendor6; /* vendor unique */
- unsigned char tDMA; /* 0=slow, 1=medium, 2=fast */
- unsigned short field_valid; /* bits 0:cur_ok 1:eide_ok */
- unsigned short cur_cyls; /* logical cylinders */
- unsigned short cur_heads; /* logical heads */
- unsigned short cur_sectors; /* logical sectors per track */
- unsigned short cur_capacity0; /* logical total sectors on drive */
- unsigned short cur_capacity1; /* (2 words, misaligned int) */
+ unsigned char vendor5; /* Obsolete, vendor unique */
+ unsigned char tPIO; /* Obsolete, 0=slow, 1=medium, 2=fast */
+ unsigned char vendor6; /* Obsolete, vendor unique */
+ unsigned char tDMA; /* Obsolete, 0=slow, 1=medium, 2=fast */
+ unsigned short field_valid; /* (word 53)
+ * 2: ultra_ok word 88
+ * 1: eide_ok words 64-70
+ * 0: cur_ok words 54-58
+ */
+ unsigned short cur_cyls; /* Obsolete, logical cylinders */
+ unsigned short cur_heads; /* Obsolete, l heads */
+ unsigned short cur_sectors; /* Obsolete, l sectors per track */
+ unsigned short cur_capacity0; /* Obsolete, l total sectors on drive */
+ unsigned short cur_capacity1; /* Obsolete, (2 words, misaligned int) */
unsigned char multsect; /* current multiple sector count */
unsigned char multsect_valid; /* when (bit0==1) multsect is ok */
- unsigned int lba_capacity; /* total number of sectors */
- unsigned short dma_1word; /* single-word dma info */
+ unsigned int lba_capacity; /* Obsolete, total number of sectors */
+ unsigned short dma_1word; /* Obsolete, single-word dma info */
unsigned short dma_mword; /* multiple-word dma info */
unsigned short eide_pio_modes; /* bits 0:mode3 1:mode4 */
unsigned short eide_dma_min; /* min mword dma cycle time (ns) */
unsigned short eide_dma_time; /* recommended mword dma cycle time (ns) */
unsigned short eide_pio; /* min cycle time (ns), no IORDY */
unsigned short eide_pio_iordy; /* min cycle time (ns), with IORDY */
- unsigned short words69_70[2]; /* reserved words 69-70 */
+ unsigned short words69_70[2]; /* reserved words 69-70
+ * future command overlap and queuing
+ */
/* HDIO_GET_IDENTITY currently returns only words 0 through 70 */
- unsigned short words71_74[4]; /* reserved words 71-74 */
- unsigned short queue_depth; /* */
+ unsigned short words71_74[4]; /* reserved words 71-74
+ * for IDENTIFY PACKET DEVICE command
+ */
+ unsigned short queue_depth; /* (word 75)
+ * 15:5 reserved
+ * 4:0 Maximum queue depth -1
+ */
unsigned short words76_79[4]; /* reserved words 76-79 */
- unsigned short major_rev_num; /* */
- unsigned short minor_rev_num; /* */
- unsigned short command_set_1; /* bits 0:Smart 1:Security 2:Removable 3:PM */
- unsigned short command_set_2; /* bits 14:Smart Enabled 13:0 zero */
- unsigned short cfsse; /* command set-feature supported extensions */
- unsigned short cfs_enable_1; /* command set-feature enabled */
- unsigned short cfs_enable_2; /* command set-feature enabled */
- unsigned short csf_default; /* command set-feature default */
- unsigned short dma_ultra; /* */
+ unsigned short major_rev_num; /* (word 80) */
+ unsigned short minor_rev_num; /* (word 81) */
+ unsigned short command_set_1; /* (word 82) supported
+ * 15: Obsolete
+ * 14: NOP command
+ * 13: READ_BUFFER
+ * 12: WRITE_BUFFER
+ * 11: Obsolete
+ * 10: Host Protected Area
+ * 9: DEVICE Reset
+ * 8: SERVICE Interrupt
+ * 7: Release Interrupt
+ * 6: look-ahead
+ * 5: write cache
+ * 4: PACKET Command
+ * 3: Power Management Feature Set
+ * 2: Removable Feature Set
+ * 1: Security Feature Set
+ * 0: SMART Feature Set
+ */
+ unsigned short command_set_2; /* (word 83)
+ * 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 13: FLUSH CACHE EXT
+ * 12: FLUSH CACHE
+ * 11: Device Configuration Overlay
+ * 10: 48-bit Address Feature Set
+ * 9: Automatic Acoustic Management
+ * 8: SET MAX security
+ * 7: reserved 1407DT PARTIES
+ * 6: SetF sub-command Power-Up
+ * 5: Power-Up in Standby Feature Set
+ * 4: Removable Media Notification
+ * 3: APM Feature Set
+ * 2: CFA Feature Set
+ * 1: READ/WRITE DMA QUEUED
+ * 0: Download MicroCode
+ */
+ unsigned short cfsse; /* (word 84)
+ * cmd set-feature supported extensions
+ * 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 13:3 reserved
+ * 2: Media Serial Number Valid
+ * 1: SMART selt-test supported
+ * 0: SMART error logging
+ */
+ unsigned short cfs_enable_1; /* (word 85)
+ * command set-feature enabled
+ * 15: Obsolete
+ * 14: NOP command
+ * 13: READ_BUFFER
+ * 12: WRITE_BUFFER
+ * 11: Obsolete
+ * 10: Host Protected Area
+ * 9: DEVICE Reset
+ * 8: SERVICE Interrupt
+ * 7: Release Interrupt
+ * 6: look-ahead
+ * 5: write cache
+ * 4: PACKET Command
+ * 3: Power Management Feature Set
+ * 2: Removable Feature Set
+ * 1: Security Feature Set
+ * 0: SMART Feature Set
+ */
+ unsigned short cfs_enable_2; /* (word 86)
+ * command set-feature enabled
+ * 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 13: FLUSH CACHE EXT
+ * 12: FLUSH CACHE
+ * 11: Device Configuration Overlay
+ * 10: 48-bit Address Feature Set
+ * 9: Automatic Acoustic Management
+ * 8: SET MAX security
+ * 7: reserved 1407DT PARTIES
+ * 6: SetF sub-command Power-Up
+ * 5: Power-Up in Standby Feature Set
+ * 4: Removable Media Notification
+ * 3: APM Feature Set
+ * 2: CFA Feature Set
+ * 1: READ/WRITE DMA QUEUED
+ * 0: Download MicroCode
+ */
+ unsigned short csf_default; /* (word 87)
+ * command set-feature default
+ * 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 13:3 reserved
+ * 2: Media Serial Number Valid
+ * 1: SMART selt-test supported
+ * 0: SMART error logging
+ */
+ unsigned short dma_ultra; /* (word 88) */
unsigned short word89; /* reserved (word 89) */
unsigned short word90; /* reserved (word 90) */
unsigned short CurAPMvalues; /* current APM values */
unsigned short word92; /* reserved (word 92) */
- unsigned short hw_config; /* hardware config */
- unsigned short words94_125[32];/* reserved words 94-125 */
- unsigned short last_lun; /* reserved (word 126) */
- unsigned short word127; /* reserved (word 127) */
- unsigned short dlf; /* device lock function
+ unsigned short hw_config; /* hardware config (word 93)
+ * 15:
+ * 14:
+ * 13:
+ * 12:
+ * 11:
+ * 10:
+ * 9:
+ * 8:
+ * 7:
+ * 6:
+ * 5:
+ * 4:
+ * 3:
+ * 2:
+ * 1:
+ * 0:
+ */
+ unsigned short acoustic; /* (word 94)
+ * 15:8 Vendor's recommended value
+ * 7:0 current value
+ */
+ unsigned short words95_99[5]; /* reserved words 95-99 */
+#if 0
+ unsigned short words100_103[4] ;/* reserved words 100-103 */
+#else
+ unsigned long long lba_capacity_2;/* 48-bit total number of sectors */
+#endif
+ unsigned short words104_125[22];/* reserved words 104-125 */
+ unsigned short last_lun; /* (word 126) */
+ unsigned short word127; /* (word 127) Feature Set
+ * Removable Media Notification
+ * 15:2 reserved
+ * 1:0 00 = not supported
+ * 01 = supported
+ * 10 = reserved
+ * 11 = reserved
+ */
+ unsigned short dlf; /* (word 128)
+ * device lock function
* 15:9 reserved
- * 8 security level 1:max 0:high
- * 7:6 reserved
- * 5 enhanced erase
- * 4 expire
- * 3 frozen
- * 2 locked
- * 1 en/disabled
- * 0 capability
+ * 8 security level 1:max 0:high
+ * 7:6 reserved
+ * 5 enhanced erase
+ * 4 expire
+ * 3 frozen
+ * 2 locked
+ * 1 en/disabled
+ * 0 capability
*/
- unsigned short csfo; /* current set features options
+ unsigned short csfo; /* (word 129)
+ * current set features options
* 15:4 reserved
- * 3 auto reassign
- * 2 reverting
- * 1 read-look-ahead
- * 0 write cache
+ * 3: auto reassign
+ * 2: reverting
+ * 1: read-look-ahead
+ * 0: write cache
*/
unsigned short words130_155[26];/* reserved vendor words 130-155 */
- unsigned short word156;
+ unsigned short word156; /* reserved vendor word 156 */
unsigned short words157_159[3];/* reserved vendor words 157-159 */
- unsigned short words160_255[95];/* reserved words 160-255 */
+ unsigned short cfa_power; /* (word 160) CFA Power Mode
+ * 15 word 160 supported
+ * 14 reserved
+ * 13
+ * 12
+ * 11:0
+ */
+ unsigned short words161_175[14];/* Reserved for CFA */
+ unsigned short words176_205[31];/* Current Media Serial Number */
+ unsigned short words206_254[48];/* reserved words 206-254 */
+ unsigned short integrity_word; /* (word 255)
+ * 15:8 Checksum
+ * 7:0 Signature
+ */
};
/*
diff --git a/include/linux/ide.h b/include/linux/ide.h
index a8e2d11c4..b5e752a49 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -65,13 +65,14 @@ void cmd640_dump_regs (void);
/*
* IDE_DRIVE_CMD is used to implement many features of the hdparm utility
*/
-#define IDE_DRIVE_CMD 99 /* (magic) undef to reduce kernel size*/
+#define IDE_DRIVE_CMD 99 /* (magic) undef to reduce kernel size*/
+
+#define IDE_DRIVE_TASK 98
/*
- * IDE_DRIVE_TASK is used to implement many features needed for raw tasks
+ * IDE_DRIVE_TASKFILE is used to implement many features needed for raw tasks
*/
-#define IDE_DRIVE_TASK 98
-#define IDE_DRIVE_CMD_AEB 98
+#define IDE_DRIVE_TASKFILE 97
/*
* "No user-serviceable parts" beyond this point :)
@@ -120,6 +121,17 @@ typedef unsigned char byte; /* used everywhere */
#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET
#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET
+#define IDE_DATA_OFFSET_HOB (0)
+#define IDE_ERROR_OFFSET_HOB (1)
+#define IDE_NSECTOR_OFFSET_HOB (2)
+#define IDE_SECTOR_OFFSET_HOB (3)
+#define IDE_LCYL_OFFSET_HOB (4)
+#define IDE_HCYL_OFFSET_HOB (5)
+#define IDE_SELECT_OFFSET_HOB (6)
+#define IDE_CONTROL_OFFSET_HOB (7)
+
+#define IDE_FEATURE_OFFSET_HOB IDE_ERROR_OFFSET_HOB
+
#define IDE_DATA_REG (HWIF(drive)->io_ports[IDE_DATA_OFFSET])
#define IDE_ERROR_REG (HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
#define IDE_NSECTOR_REG (HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
@@ -131,6 +143,16 @@ typedef unsigned char byte; /* used everywhere */
#define IDE_CONTROL_REG (HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
#define IDE_IRQ_REG (HWIF(drive)->io_ports[IDE_IRQ_OFFSET])
+#define IDE_DATA_REG_HOB (HWIF(drive)->io_ports[IDE_DATA_OFFSET])
+#define IDE_ERROR_REG_HOB (HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
+#define IDE_NSECTOR_REG_HOB (HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
+#define IDE_SECTOR_REG_HOB (HWIF(drive)->io_ports[IDE_SECTOR_OFFSET])
+#define IDE_LCYL_REG_HOB (HWIF(drive)->io_ports[IDE_LCYL_OFFSET])
+#define IDE_HCYL_REG_HOB (HWIF(drive)->io_ports[IDE_HCYL_OFFSET])
+#define IDE_SELECT_REG_HOB (HWIF(drive)->io_ports[IDE_SELECT_OFFSET])
+#define IDE_STATUS_REG_HOB (HWIF(drive)->io_ports[IDE_STATUS_OFFSET])
+#define IDE_CONTROL_REG_HOB (HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
+
#define IDE_FEATURE_REG IDE_ERROR_REG
#define IDE_COMMAND_REG IDE_STATUS_REG
#define IDE_ALTSTATUS_REG IDE_CONTROL_REG
@@ -171,11 +193,21 @@ typedef unsigned char byte; /* used everywhere */
#define PARTN_BITS 6 /* number of minor dev bits for partitions */
#define PARTN_MASK ((1<<PARTN_BITS)-1) /* a useful bit mask */
#define MAX_DRIVES 2 /* per interface; 2 assumed by lots of code */
-#define SECTOR_WORDS (512 / 4) /* number of 32bit words per sector */
+#define CASCADE_DRIVES 8 /* per interface; 8|2 assumed by lots of code */
+#define SECTOR_SIZE 512
+#define SECTOR_WORDS (SECTOR_SIZE / 4) /* number of 32bit words per sector */
#define IDE_LARGE_SEEK(b1,b2,t) (((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
#define IDE_MIN(a,b) ((a)<(b) ? (a):(b))
#define IDE_MAX(a,b) ((a)>(b) ? (a):(b))
+#ifndef SPLIT_WORD
+# define SPLIT_WORD(W,HB,LB) ((HB)=(W>>8), (LB)=(W-((W>>8)<<8)))
+#endif
+#ifndef MAKE_WORD
+# define MAKE_WORD(W,HB,LB) ((W)=((HB<<8)+LB))
+#endif
+
+
/*
* Timeouts for various operations:
*/
@@ -185,8 +217,7 @@ typedef unsigned char byte; /* used everywhere */
#else
#define WAIT_READY (3*HZ/100) /* 30msec - should be instantaneous */
#endif /* CONFIG_APM || CONFIG_APM_MODULE */
-#define WAIT_PIDENTIFY (10*HZ) /* 10sec - should be less than 3ms (?)
- if all ATAPI CD is closed at boot */
+#define WAIT_PIDENTIFY (10*HZ) /* 10sec - should be less than 3ms (?), if all ATAPI CD is closed at boot */
#define WAIT_WORSTCASE (30*HZ) /* 30sec - worst case when spinning up */
#define WAIT_CMD (10*HZ) /* 10sec - maximum wait for an IRQ to happen */
#define WAIT_MIN_SLEEP (2*HZ/100) /* 20msec - minimum sleep time */
@@ -224,6 +255,11 @@ typedef unsigned char byte; /* used everywhere */
(drive)->quirk_list = hwif->quirkproc(drive); \
}
+#define HOST(hwif,chipset) \
+{ \
+ return ((hwif)->chipset == chipset) ? 1 : 0; \
+}
+
#define IDE_DEBUG(lineno) \
printk("%s,%s,line=%d\n", __FILE__, __FUNCTION__, (lineno))
@@ -249,11 +285,11 @@ typedef enum { ide_unknown, ide_generic, ide_pci,
ide_pmac, ide_etrax100
} hwif_chipset_t;
+
#define IDE_CHIPSET_PCI_MASK \
((1<<ide_pci)|(1<<ide_cmd646)|(1<<ide_ali14xx))
#define IDE_CHIPSET_IS_PCI(c) ((IDE_CHIPSET_PCI_MASK >> (c)) & 1)
-
/*
* Structure to hold all information about the location of this port
*/
@@ -292,16 +328,20 @@ void ide_setup_ports( hw_regs_t *hw,
#ifndef HAVE_ARCH_OUT_BYTE
#ifdef REALLY_FAST_IO
#define OUT_BYTE(b,p) outb((b),(p))
+#define OUT_WORD(w,p) outw((w),(p))
#else
#define OUT_BYTE(b,p) outb_p((b),(p))
+#define OUT_WORD(w,p) outw_p((w),(p))
#endif
#endif
#ifndef HAVE_ARCH_IN_BYTE
#ifdef REALLY_FAST_IO
-#define IN_BYTE(p) (byte)inb_p(p)
-#else
#define IN_BYTE(p) (byte)inb(p)
+#define IN_WORD(p) (short)inw(p)
+#else
+#define IN_BYTE(p) (byte)inb_p(p)
+#define IN_WORD(p) (short)inw_p(p)
#endif
#endif
@@ -361,6 +401,7 @@ typedef struct ide_drive_s {
unsigned autotune : 2; /* 1=autotune, 2=noautotune, 0=default */
unsigned remap_0_to_1 : 2; /* 0=remap if ezdrive, 1=remap, 2=noremap */
unsigned ata_flash : 1; /* 1=present, 0=default */
+ unsigned addressing; /* : 2; 0=28-bit, 1=48-bit, 2=64-bit */
byte scsi; /* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
byte media; /* disk, cdrom, tape, floppy, ... */
select_t select; /* basic drive/head select reg value */
@@ -373,7 +414,7 @@ typedef struct ide_drive_s {
byte bad_wstat; /* used for ignoring WRERR_STAT */
byte nowerr; /* used for ignoring WRERR_STAT */
byte sect0; /* offset of first sector for DM6:DDO */
- byte usage; /* current "open()" count for drive */
+ unsigned int usage; /* current "open()" count for drive */
byte head; /* "real" number of heads */
byte sect; /* "real" sectors per track */
byte bios_head; /* BIOS/fdisk/LILO number of heads */
@@ -381,6 +422,7 @@ typedef struct ide_drive_s {
unsigned int bios_cyl; /* BIOS/fdisk/LILO number of cyls */
unsigned int cyl; /* "real" number of cyls */
unsigned long capacity; /* total number of sectors */
+ unsigned long long capacity48; /* total number of sectors */
unsigned int drive_data; /* for use by tuneproc/selectproc as needed */
void *hwif; /* actually (ide_hwif_t *) */
wait_queue_head_t wqueue; /* used to wait for drive in open() */
@@ -402,6 +444,8 @@ typedef struct ide_drive_s {
byte init_speed; /* transfer rate set at boot */
byte current_speed; /* current transfer rate set */
byte dn; /* now wide spread use */
+ byte wcache; /* status of write cache */
+ byte acoustic; /* acoustic management */
unsigned int failures; /* current failure count */
unsigned int max_failures; /* maximum allowed failure count */
} ide_drive_t;
@@ -471,7 +515,7 @@ typedef void (ide_rw_proc_t) (ide_drive_t *, ide_dma_action_t);
/*
* ide soft-power support
*/
-typedef int (ide_busproc_t) (struct hwif_s *, int);
+typedef int (ide_busproc_t) (ide_drive_t *, int);
#ifdef CONFIG_BLK_DEV_IDEPCI
typedef struct ide_pci_devid_s {
@@ -538,7 +582,6 @@ typedef struct hwif_s {
byte bus_state; /* power state of the IDE bus */
} ide_hwif_t;
-
/*
* Status returned from various ide_ functions
*/
@@ -550,7 +593,9 @@ typedef enum {
/*
* internal ide interrupt handler type
*/
+typedef ide_startstop_t (ide_pre_handler_t)(ide_drive_t *, struct request *);
typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
+typedef ide_startstop_t (ide_post_handler_t)(ide_drive_t *);
/*
* when ide_timer_expiry fires, invoke a handler of this type
@@ -573,6 +618,8 @@ typedef struct hwgroup_s {
ide_expiry_t *expiry; /* queried upon timeouts */
} ide_hwgroup_t;
+/* structure attached to the request for IDE_TASK_CMDS */
+
/*
* configurable drive settings
*/
@@ -623,6 +670,8 @@ typedef struct {
#ifdef CONFIG_PROC_FS
void proc_ide_create(void);
void proc_ide_destroy(void);
+void recreate_proc_ide_device(ide_hwif_t *, ide_drive_t *);
+void destroy_proc_ide_device(ide_hwif_t *, ide_drive_t *);
void destroy_proc_ide_drives(ide_hwif_t *);
void create_proc_ide_interfaces(void);
void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data);
@@ -655,6 +704,8 @@ read_proc_t proc_ide_read_geometry;
#define IDE_SUBDRIVER_VERSION 1
typedef int (ide_cleanup_proc)(ide_drive_t *);
+typedef int (ide_standby_proc)(ide_drive_t *);
+typedef int (ide_flushcache_proc)(ide_drive_t *);
typedef ide_startstop_t (ide_do_request_proc)(ide_drive_t *, struct request *, unsigned long);
typedef void (ide_end_request_proc)(byte, ide_hwgroup_t *);
typedef int (ide_ioctl_proc)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
@@ -676,6 +727,8 @@ typedef struct ide_driver_s {
unsigned supports_dma : 1;
unsigned supports_dsc_overlap : 1;
ide_cleanup_proc *cleanup;
+ ide_standby_proc *standby;
+ ide_flushcache_proc *flushcache;
ide_do_request_proc *do_request;
ide_end_request_proc *end_request;
ide_ioctl_proc *ioctl;
@@ -733,19 +786,7 @@ extern int noautodma;
inline int __ide_end_request(ide_hwgroup_t *, int, int);
int ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup);
-/*
- * This is used for (nearly) all data transfers from/to the IDE interface
- * FIXME for 2.5, to a pointer pass verses memcpy........
- */
-void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
-void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
-
-/*
- * This is used for (nearly) all ATAPI data transfers from/to the IDE interface
- * FIXME for 2.5, to a pointer pass verses memcpy........
- */
-void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
-void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
+int drive_is_ready (ide_drive_t *drive);
/*
* This is used on exit from the driver, to designate the next irq handler
@@ -768,7 +809,7 @@ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat);
* Issue a simple drive command
* The drive must be selected beforehand.
*/
-void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler);
+void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler);
/*
* ide_fixstring() cleans up and (optionally) byte-swaps a text string,
@@ -883,24 +924,91 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
/*
* Clean up after success/failure of an explicit drive cmd.
* stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
+ * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASK_MASK).
*/
void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);
/*
- * Issue ATA command and wait for completion.
+ * Issue ATA command and wait for completion. use for implementing commands in kernel
*/
int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf);
+
int ide_wait_cmd_task (ide_drive_t *drive, byte *buf);
+
+typedef struct ide_task_s {
+ task_ioreg_t tfRegister[8];
+ task_ioreg_t hobRegister[8];
+ ide_reg_valid_t tf_out_flags;
+ ide_reg_valid_t tf_in_flags;
+ int data_phase;
+ int command_type;
+ ide_pre_handler_t *prehandler;
+ ide_handler_t *handler;
+ ide_post_handler_t *posthandler;
+ void *special; /* valid_t generally */
+ struct request *rq; /* copy of request */
+ unsigned long block; /* copy of block */
+} ide_task_t;
+
+void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
+void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
+void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+
+/*
+ * taskfile io for disks for now...
+ */
+ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task);
+
+/*
+ * Builds request from ide_ioctl
+ */
+void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler);
+
+/*
+ * Special Flagged Register Validation Caller
+ */
+// ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task);
+
+ide_startstop_t set_multmode_intr (ide_drive_t *drive);
+ide_startstop_t set_geometry_intr (ide_drive_t *drive);
+ide_startstop_t recal_intr (ide_drive_t *drive);
+ide_startstop_t task_no_data_intr (ide_drive_t *drive);
+ide_startstop_t task_in_intr (ide_drive_t *drive);
+ide_startstop_t task_mulin_intr (ide_drive_t *drive);
+ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq);
+ide_startstop_t task_out_intr (ide_drive_t *drive);
+ide_startstop_t task_mulout_intr (ide_drive_t *drive);
+void ide_init_drive_taskfile (struct request *rq);
+
+int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf);
+
+int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *cmd, byte *buf);
+
+ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
+ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
+/* Expects args is a full set of TF registers and parses the command type */
+int ide_cmd_type_parser (ide_task_t *args);
+
+int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+
+#ifdef CONFIG_PKT_TASK_IOCTL
+int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+#endif /* CONFIG_PKT_TASK_IOCTL */
void ide_delay_50ms (void);
int system_bus_clock(void);
byte ide_auto_reduce_xfer (ide_drive_t *drive);
int ide_driveid_update (ide_drive_t *drive);
-int ide_ata66_check (ide_drive_t *drive, byte cmd, byte nsect, byte feature);
+int ide_ata66_check (ide_drive_t *drive, ide_task_t *args);
int ide_config_drive_speed (ide_drive_t *drive, byte speed);
byte eighty_ninty_three (ide_drive_t *drive);
-int set_transfer (ide_drive_t *drive, byte cmd, byte nsect, byte feature);
+int set_transfer (ide_drive_t *drive, ide_task_t *args);
/*
* ide_system_bus_speed() returns what we think is the system VESA/PCI
@@ -911,12 +1019,6 @@ int set_transfer (ide_drive_t *drive, byte cmd, byte nsect, byte feature);
int ide_system_bus_speed (void);
/*
- * ide_multwrite() transfers a block of up to mcount sectors of data
- * to a drive as part of a disk multwrite operation.
- */
-int ide_multwrite (ide_drive_t *drive, unsigned int mcount);
-
-/*
* idedisk_input_data() is a wrapper around ide_input_data() which copes
* with byte-swapping the input data if required.
*/
@@ -951,23 +1053,30 @@ extern struct block_device_operations ide_fops[];
extern ide_proc_entry_t generic_subdriver_entries[];
#endif
+int ide_reinit_drive (ide_drive_t *drive);
+
#ifdef _IDE_C
#ifdef CONFIG_BLK_DEV_IDE
int ideprobe_init (void);
#endif /* CONFIG_BLK_DEV_IDE */
#ifdef CONFIG_BLK_DEV_IDEDISK
+int idedisk_reinit (ide_drive_t *drive);
int idedisk_init (void);
#endif /* CONFIG_BLK_DEV_IDEDISK */
#ifdef CONFIG_BLK_DEV_IDECD
+int ide_cdrom_reinit (ide_drive_t *drive);
int ide_cdrom_init (void);
#endif /* CONFIG_BLK_DEV_IDECD */
#ifdef CONFIG_BLK_DEV_IDETAPE
+int idetape_reinit (ide_drive_t *drive);
int idetape_init (void);
#endif /* CONFIG_BLK_DEV_IDETAPE */
#ifdef CONFIG_BLK_DEV_IDEFLOPPY
+int idefloppy_reinit (ide_drive_t *drive);
int idefloppy_init (void);
#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
#ifdef CONFIG_BLK_DEV_IDESCSI
+int idescsi_reinit (ide_drive_t *drive);
int idescsi_init (void);
#endif /* CONFIG_BLK_DEV_IDESCSI */
#endif /* _IDE_C */
@@ -1007,6 +1116,9 @@ unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *
void hwif_unregister (ide_hwif_t *hwif);
+void export_ide_init_queue (ide_drive_t *drive);
+byte export_probe_for_drive (ide_drive_t *drive);
+
extern spinlock_t ide_lock;
#endif /* _IDE_H */
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
new file mode 100644
index 000000000..3c4e71fc0
--- /dev/null
+++ b/include/linux/init_task.h
@@ -0,0 +1,88 @@
+#ifndef _LINUX__INIT_TASK_H
+#define _LINUX__INIT_TASK_H
+
+#ifndef __LINUX_FILE_H
+#include <linux/file.h>
+#endif
+
+#define INIT_FILES \
+{ \
+ count: ATOMIC_INIT(1), \
+ file_lock: RW_LOCK_UNLOCKED, \
+ max_fds: NR_OPEN_DEFAULT, \
+ max_fdset: __FD_SETSIZE, \
+ next_fd: 0, \
+ fd: &init_files.fd_array[0], \
+ close_on_exec: &init_files.close_on_exec_init, \
+ open_fds: &init_files.open_fds_init, \
+ close_on_exec_init: { { 0, } }, \
+ open_fds_init: { { 0, } }, \
+ fd_array: { NULL, } \
+}
+
+#define INIT_MM(name) \
+{ \
+ mm_rb: RB_ROOT, \
+ pgd: swapper_pg_dir, \
+ mm_users: ATOMIC_INIT(2), \
+ mm_count: ATOMIC_INIT(1), \
+ mmap_sem: __RWSEM_INITIALIZER(name.mmap_sem), \
+ page_table_lock: SPIN_LOCK_UNLOCKED, \
+ mmlist: LIST_HEAD_INIT(name.mmlist), \
+}
+
+#define INIT_SIGNALS { \
+ count: ATOMIC_INIT(1), \
+ action: { {{0,}}, }, \
+ siglock: SPIN_LOCK_UNLOCKED \
+}
+
+/*
+ * INIT_TASK is used to set up the first task table, touch at
+ * your own risk!. Base=0, limit=0x1fffff (=2MB)
+ */
+#define INIT_TASK(tsk) \
+{ \
+ state: 0, \
+ flags: 0, \
+ sigpending: 0, \
+ addr_limit: KERNEL_DS, \
+ exec_domain: &default_exec_domain, \
+ lock_depth: -1, \
+ __nice: DEF_USER_NICE, \
+ policy: SCHED_OTHER, \
+ cpus_allowed: -1, \
+ mm: NULL, \
+ active_mm: &init_mm, \
+ run_list: LIST_HEAD_INIT(tsk.run_list), \
+ time_slice: NICE_TO_TIMESLICE(DEF_USER_NICE), \
+ next_task: &tsk, \
+ prev_task: &tsk, \
+ p_opptr: &tsk, \
+ p_pptr: &tsk, \
+ thread_group: LIST_HEAD_INIT(tsk.thread_group), \
+ wait_chldexit: __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\
+ real_timer: { \
+ function: it_real_fn \
+ }, \
+ cap_effective: CAP_INIT_EFF_SET, \
+ cap_inheritable: CAP_INIT_INH_SET, \
+ cap_permitted: CAP_FULL_SET, \
+ keep_capabilities: 0, \
+ rlim: INIT_RLIMITS, \
+ user: INIT_USER, \
+ comm: "swapper", \
+ thread: INIT_THREAD, \
+ fs: &init_fs, \
+ files: &init_files, \
+ sigmask_lock: SPIN_LOCK_UNLOCKED, \
+ sig: &init_signals, \
+ pending: { NULL, &tsk.pending.head, {{0}}}, \
+ blocked: {{0}}, \
+ alloc_lock: SPIN_LOCK_UNLOCKED, \
+ journal_info: NULL, \
+}
+
+
+
+#endif
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index 63efd4cae..49d37edb8 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -19,13 +19,14 @@
#define MSDOS_DPS_BITS 4 /* log2(MSDOS_DPS) */
#define MSDOS_DIR_BITS 5 /* log2(sizeof(struct msdos_dir_entry)) */
+/* directory limit */
+#define FAT_MAX_DIR_ENTRIES (65536)
+#define FAT_MAX_DIR_SIZE (FAT_MAX_DIR_ENTRIES << MSDOS_DIR_BITS)
+
#define MSDOS_SUPER_MAGIC 0x4d44 /* MD */
#define FAT_CACHE 8 /* FAT cache size */
-#define MSDOS_MAX_EXTRA 3 /* tolerate up to that number of clusters which are
- inaccessible because the FAT is too short */
-
#define ATTR_RO 1 /* read-only */
#define ATTR_HIDDEN 2 /* hidden */
#define ATTR_SYS 4 /* system */
@@ -48,11 +49,6 @@
#define CASE_LOWER_BASE 8 /* base is lower case */
#define CASE_LOWER_EXT 16 /* extension is lower case */
-#define SCAN_ANY 0 /* either hidden or not */
-#define SCAN_HID 1 /* only hidden */
-#define SCAN_NOTHID 2 /* only not hidden */
-#define SCAN_NOTANY 3 /* test name, then use SCAN_HID or SCAN_NOTHID */
-
#define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */
#define IS_FREE(n) (!*(n) || *(const unsigned char *) (n) == DELETED_FLAG)
@@ -78,8 +74,8 @@
#define FAT_FSINFO_SIG1 0x41615252
#define FAT_FSINFO_SIG2 0x61417272
-#define IS_FSINFO(x) (CF_LE_L((x)->signature1) == FAT_FSINFO_SIG1 \
- && CF_LE_L((x)->signature2) == FAT_FSINFO_SIG2)
+#define IS_FSINFO(x) (CF_LE_L((x)->signature1) == FAT_FSINFO_SIG1 \
+ && CF_LE_L((x)->signature2) == FAT_FSINFO_SIG2)
/*
* Inode flags
@@ -184,10 +180,6 @@ struct vfat_slot_info {
int ino; /* ino for the file */
};
-/* Determine whether this FS has kB-aligned data. */
-#define MSDOS_CAN_BMAP(mib) (!(((mib)->cluster_size & 1) || \
- ((mib)->data_start & 1)))
-
/* Convert attribute bits and a mask to the UNIX mode. */
#define MSDOS_MKMODE(a,m) (m & (a & ATTR_RO ? S_IRUGO|S_IXUGO : S_IRWXUGO))
@@ -297,7 +289,7 @@ extern void fat_write_inode(struct inode *inode, int wait);
extern int fat_notify_change(struct dentry * dentry, struct iattr * attr);
/* fat/misc.c */
-extern void fat_fs_panic(struct super_block *s, const char *msg);
+extern void fat_fs_panic(struct super_block *s, const char *fmt, ...);
extern int fat_is_binary(char conversion, char *extension);
extern void lock_fat(struct super_block *sb);
extern void unlock_fat(struct super_block *sb);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index a61d733ee..b8d564fd0 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -144,7 +144,8 @@ extern void trap_init(void);
extern void update_process_times(int user);
extern void update_one_process(struct task_struct *p, unsigned long user,
unsigned long system, int cpu);
-extern void scheduler_tick(struct task_struct *p);
+extern void expire_task(struct task_struct *p);
+extern void idle_tick(void);
#define MAX_SCHEDULE_TIMEOUT LONG_MAX
extern signed long FASTCALL(schedule_timeout(signed long timeout));
@@ -155,44 +156,7 @@ extern void flush_scheduled_tasks(void);
extern int start_context_thread(void);
extern int current_is_keventd(void);
-/*
- * The default fd array needs to be at least BITS_PER_LONG,
- * as this is the granularity returned by copy_fdset().
- */
-#define NR_OPEN_DEFAULT BITS_PER_LONG
-
struct namespace;
-/*
- * Open file table structure
- */
-struct files_struct {
- atomic_t count;
- rwlock_t file_lock; /* Protects all the below members. Nests inside tsk->alloc_lock */
- int max_fds;
- int max_fdset;
- int next_fd;
- struct file ** fd; /* current fd array */
- fd_set *close_on_exec;
- fd_set *open_fds;
- fd_set close_on_exec_init;
- fd_set open_fds_init;
- struct file * fd_array[NR_OPEN_DEFAULT];
-};
-
-#define INIT_FILES \
-{ \
- count: ATOMIC_INIT(1), \
- file_lock: RW_LOCK_UNLOCKED, \
- max_fds: NR_OPEN_DEFAULT, \
- max_fdset: __FD_SETSIZE, \
- next_fd: 0, \
- fd: &init_files.fd_array[0], \
- close_on_exec: &init_files.close_on_exec_init, \
- open_fds: &init_files.open_fds_init, \
- close_on_exec_init: { { 0, } }, \
- open_fds_init: { { 0, } }, \
- fd_array: { NULL, } \
-}
/* Maximum number of active map areas.. This is a random (large) number */
#define MAX_MAP_COUNT (65536)
@@ -229,17 +193,6 @@ struct mm_struct {
extern int mmlist_nr;
-#define INIT_MM(name) \
-{ \
- mm_rb: RB_ROOT, \
- pgd: swapper_pg_dir, \
- mm_users: ATOMIC_INIT(2), \
- mm_count: ATOMIC_INIT(1), \
- mmap_sem: __RWSEM_INITIALIZER(name.mmap_sem), \
- page_table_lock: SPIN_LOCK_UNLOCKED, \
- mmlist: LIST_HEAD_INIT(name.mmlist), \
-}
-
struct signal_struct {
atomic_t count;
struct k_sigaction action[_NSIG];
@@ -247,12 +200,6 @@ struct signal_struct {
};
-#define INIT_SIGNALS { \
- count: ATOMIC_INIT(1), \
- action: { {{0,}}, }, \
- siglock: SPIN_LOCK_UNLOCKED \
-}
-
/*
* Some day this will be a full-fledged user tracking system..
*/
@@ -304,32 +251,7 @@ struct task_struct {
prio_array_t *array;
unsigned int time_slice;
- unsigned long sleep_timestamp, run_timestamp;
-
- /*
- * A task's four 'sleep history' entries.
- *
- * We track the last 4 seconds of time. (including the current second).
- *
- * A value of '0' means it has spent no time sleeping in that
- * particular past second. The maximum value of 'HZ' means that
- * the task spent all its time running in that particular second.
- *
- * 'hist_idx' points to the current second, which, unlike the other
- * 3 entries, is only partially complete. This means that a value of
- * '25' does not mean the task slept 25% of the time in the current
- * second, it means that it spent 25 timer ticks sleeping in the
- * current second.
- *
- * All this might look a bit complex, but it can be maintained very
- * small overhead and it gives very good statistics, based on which
- * the scheduler can decide whether a task is 'interactive' or a
- * 'CPU hog'. See sched.c for more details.
- */
- #define SLEEP_HIST_SIZE 4
-
- int hist_idx;
- int hist[SLEEP_HIST_SIZE];
+ unsigned long sleep_jtime;
unsigned long policy;
unsigned long cpus_allowed;
@@ -479,42 +401,19 @@ struct task_struct {
#define DEF_USER_NICE 0
/*
- * Scales user-nice values [ -20 ... 0 ... 19 ]
- * to static priority [ 128 ... 167 (MAX_PRIO-1) ]
- *
- * User-nice value of -20 == static priority 128, and
- * user-nice value 19 == static priority 167. The lower
- * the priority value, the higher the task's priority.
- */
-#define NICE_TO_PRIO(n) (MAX_PRIO-1 + (n) - 19)
-
-#define DEF_PRIO NICE_TO_PRIO(DEF_USER_NICE)
-
-/*
- * Default timeslice is 90 msecs, maximum is 150 msecs.
- * Minimum timeslice is 30 msecs.
+ * Default timeslice is 80 msecs, maximum is 160 msecs.
+ * Minimum timeslice is 10 msecs.
*/
-#define MIN_TIMESLICE ( 30 * HZ / 1000)
-#define MAX_TIMESLICE (150 * HZ / 1000)
+#define MIN_TIMESLICE (10 * HZ / 1000)
+#define MAX_TIMESLICE (160 * HZ / 1000)
#define USER_PRIO(p) ((p)-MAX_RT_PRIO)
#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO))
+#define DEF_PRIO (MAX_RT_PRIO + MAX_USER_PRIO / 3)
+#define NICE_TO_PRIO(n) (MAX_PRIO-1 + (n) - 19)
-/*
- * PRIO_TO_TIMESLICE scales priority values [ 128 ... 167 ]
- * to initial time slice values [ MAX_TIMESLICE (150 msec) ... 2 ]
- *
- * The higher a process's priority, the bigger timeslices
- * it gets during one round of execution. But even the lowest
- * priority process gets MIN_TIMESLICE worth of execution time.
- */
-#define PRIO_TO_TIMESLICE(p) \
- ((( (MAX_USER_PRIO-1-USER_PRIO(p))*(MAX_TIMESLICE-MIN_TIMESLICE) + \
- MAX_USER_PRIO-1) / MAX_USER_PRIO) + MIN_TIMESLICE)
-
-#define RT_PRIO_TO_TIMESLICE(p) \
- ((( (MAX_RT_PRIO-(p)-1)*(MAX_TIMESLICE-MIN_TIMESLICE) + \
- MAX_RT_PRIO-1) / MAX_RT_PRIO) + MIN_TIMESLICE)
+#define NICE_TO_TIMESLICE(n) (MIN_TIMESLICE + \
+ ((MAX_TIMESLICE - MIN_TIMESLICE) * (19 - (n))) / 39)
extern void set_cpus_allowed(task_t *p, unsigned long new_mask);
extern void set_user_nice(task_t *p, long nice);
@@ -526,53 +425,6 @@ asmlinkage long sys_sched_yield(void);
*/
extern struct exec_domain default_exec_domain;
-/*
- * INIT_TASK is used to set up the first task table, touch at
- * your own risk!. Base=0, limit=0x1fffff (=2MB)
- */
-#define INIT_TASK(tsk) \
-{ \
- state: 0, \
- flags: 0, \
- sigpending: 0, \
- addr_limit: KERNEL_DS, \
- exec_domain: &default_exec_domain, \
- lock_depth: -1, \
- __nice: DEF_USER_NICE, \
- policy: SCHED_OTHER, \
- cpus_allowed: -1, \
- mm: NULL, \
- active_mm: &init_mm, \
- run_list: LIST_HEAD_INIT(tsk.run_list), \
- time_slice: PRIO_TO_TIMESLICE(DEF_PRIO), \
- next_task: &tsk, \
- prev_task: &tsk, \
- p_opptr: &tsk, \
- p_pptr: &tsk, \
- thread_group: LIST_HEAD_INIT(tsk.thread_group), \
- wait_chldexit: __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\
- real_timer: { \
- function: it_real_fn \
- }, \
- cap_effective: CAP_INIT_EFF_SET, \
- cap_inheritable: CAP_INIT_INH_SET, \
- cap_permitted: CAP_FULL_SET, \
- keep_capabilities: 0, \
- rlim: INIT_RLIMITS, \
- user: INIT_USER, \
- comm: "swapper", \
- thread: INIT_THREAD, \
- fs: &init_fs, \
- files: &init_files, \
- sigmask_lock: SPIN_LOCK_UNLOCKED, \
- sig: &init_signals, \
- pending: { NULL, &tsk.pending.head, {{0}}}, \
- blocked: {{0}}, \
- alloc_lock: SPIN_LOCK_UNLOCKED, \
- journal_info: NULL, \
-}
-
-
#ifndef INIT_TASK_SIZE
# define INIT_TASK_SIZE 2048*sizeof(long)
#endif
diff --git a/kernel/exit.c b/kernel/exit.c
index 04774ebbc..850d3b7ef 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -17,6 +17,7 @@
#ifdef CONFIG_BSD_PROCESS_ACCT
#include <linux/acct.h>
#endif
+#include <linux/file.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
diff --git a/kernel/fork.c b/kernel/fork.c
index 3cf59fd03..60dd04cb6 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -21,6 +21,7 @@
#include <linux/completion.h>
#include <linux/namespace.h>
#include <linux/personality.h>
+#include <linux/file.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -703,12 +704,13 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start,
* runqueue lock is not a problem.
*/
current->time_slice = 1;
- scheduler_tick(current);
+ expire_task(current);
}
- p->sleep_timestamp = p->run_timestamp = jiffies;
- p->hist[0] = p->hist[1] = p->hist[2] = p->hist[3] = 0;
__restore_flags(flags);
+ if (p->policy == SCHED_OTHER)
+ p->prio = MAX_PRIO - 1 - ((MAX_PRIO - 1 - p->prio) * 1) / 3;
+
/*
* Ok, add it to the run-queues and make it
* visible to the rest of the system.
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 9cbf417c1..ca16be25c 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/namespace.h>
#include <linux/completion.h>
+#include <linux/file.h>
#include <asm/uaccess.h>
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index f3f8775d8..64948098e 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -85,9 +85,6 @@ EXPORT_SYMBOL(do_mmap_pgoff);
EXPORT_SYMBOL(do_munmap);
EXPORT_SYMBOL(do_brk);
EXPORT_SYMBOL(exit_mm);
-EXPORT_SYMBOL(exit_files);
-EXPORT_SYMBOL(exit_fs);
-EXPORT_SYMBOL(exit_sighand);
/* internal kernel memory management */
EXPORT_SYMBOL(_alloc_pages);
@@ -273,6 +270,8 @@ EXPORT_SYMBOL(lease_get_mtime);
EXPORT_SYMBOL(lock_may_read);
EXPORT_SYMBOL(lock_may_write);
EXPORT_SYMBOL(dcache_readdir);
+EXPORT_SYMBOL(fd_install);
+EXPORT_SYMBOL(put_unused_fd);
/* for stackable file systems (lofs, wrapfs, cryptfs, etc.) */
EXPORT_SYMBOL(default_llseek);
diff --git a/kernel/sched.c b/kernel/sched.c
index 88b5ba0f5..4bf77db6f 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -21,6 +21,9 @@
#include <asm/mmu_context.h>
#define BITMAP_SIZE ((((MAX_PRIO+7)/8)+sizeof(long)-1)/sizeof(long))
+#define PRIO_INTERACTIVE (MAX_RT_PRIO + (MAX_PRIO - MAX_RT_PRIO) / 3)
+#define TASK_INTERACTIVE(p) ((p)->prio >= MAX_RT_PRIO && (p)->prio <= PRIO_INTERACTIVE)
+#define JSLEEP_TO_PRIO(t) (((t) * 20) / HZ)
typedef struct runqueue runqueue_t;
@@ -37,36 +40,33 @@ struct prio_array {
*
* Locking rule: those places that want to lock multiple runqueues
* (such as the load balancing or the process migration code), lock
- * acquire operations must be ordered by the runqueue's cpu id.
+ * acquire operations must be ordered by rq->cpu.
*
* The RT event id is used to avoid calling into the the RT scheduler
* if there is a RT task active in an SMP system but there is no
* RT scheduling activity otherwise.
*/
-struct runqueue {
+static struct runqueue {
+ int cpu;
spinlock_t lock;
unsigned long nr_running, nr_switches;
task_t *curr, *idle;
prio_array_t *active, *expired, arrays[2];
- int prev_nr_running[NR_CPUS];
-} ____cacheline_aligned;
-
-static struct runqueue runqueues[NR_CPUS] __cacheline_aligned;
+ char __pad [SMP_CACHE_BYTES];
+} runqueues [NR_CPUS] __cacheline_aligned;
+#define this_rq() (runqueues + smp_processor_id())
+#define task_rq(p) (runqueues + (p)->cpu)
#define cpu_rq(cpu) (runqueues + (cpu))
-#define this_rq() cpu_rq(smp_processor_id())
-#define task_rq(p) cpu_rq((p)->cpu)
-#define cpu_curr(cpu) (cpu_rq(cpu)->curr)
-#define rq_cpu(rq) ((rq) - runqueues)
+#define cpu_curr(cpu) (runqueues[(cpu)].curr)
#define rt_task(p) ((p)->policy != SCHED_OTHER)
-
#define lock_task_rq(rq,p,flags) \
do { \
repeat_lock_task: \
rq = task_rq(p); \
spin_lock_irqsave(&rq->lock, flags); \
- if (unlikely(rq_cpu(rq) != (p)->cpu)) { \
+ if (unlikely((rq)->cpu != (p)->cpu)) { \
spin_unlock_irqrestore(&rq->lock, flags); \
goto repeat_lock_task; \
} \
@@ -94,214 +94,19 @@ static inline void enqueue_task(struct task_struct *p, prio_array_t *array)
p->array = array;
}
-/*
- * This is the per-process load estimator. Processes that generate
- * more load than the system can handle get a priority penalty.
- *
- * The estimator uses a 4-entry load-history ringbuffer which is
- * updated whenever a task is moved to/from the runqueue. The load
- * estimate is also updated from the timer tick to get an accurate
- * estimation of currently executing tasks as well.
- *
- * The 4-entry p->hist[4] array holds the 'sleep history' of
- * every task. Every entry holds the number of time ticks spent
- * sleeping in the past 4 seconds. Three of the entries belong to
- * one-one second in the past, the fourth entry belongs to the current
- * second. (the p->hist_idx index is used in fact as a rotating index
- * to reduce overhead.)
- *
- * The array elements are integers in the range of 0-HZ. If HZ is 100,
- * then '100' means a process has spent 100% of it's time sleeping, in
- * that particular second of time. '0' means the process has spent all
- * its time on the runqueue - ie. it was a CPU hog in that second.
- *
- * For RAM usage and algorithmic overhead reasons we do not want a too
- * big history buffer. It's also usually not interesting to the scheduler
- * to know whether a task was idle or not 10 minutes ago. 'Recent behavior'
- * is what matters, if a task was mostly sleeping recently then it's a
- * 'good' interactive task. If it has spent most (or all) of its time
- * running then it's a 'bad' CPU-hog that gets a priority penalty.
- *
- * The load estimator itself was written to be fast as well in every
- * circumstance. Eg. if a task is context switching heavily then we do
- * not call into the estimator, only about once per timer tick, on average.
- */
-
-/*
- * The 'history index' goes forward in time, if one second passes then
- * the index is increased by 1 via this function. We wrap around the
- * index if it reaches 4. (The modulo is fast with the current
- * SLEEP_HIST_SIZE of 4.)
- */
-static inline void new_second(task_t *p)
-{
- p->hist_idx = (p->hist_idx + 1) % SLEEP_HIST_SIZE;
-}
-
-/*
- * process load-history tick length. Right now it's 1 second:
- */
-#define HHZ (HZ)
-
-/*
- * This function clears the load-history entries when a task has spent
- * more than 4 seconds running.
- */
-static inline void clear_hist(task_t *p)
-{
- p->hist[0] = p->hist[1] = p->hist[2] = p->hist[3] = 0;
-}
-
-/*
- * This function fills in the load-history entries with the maximum
- * values when a task has spent more than 4 seconds sleeping.
- */
-static inline void fill_hist(task_t *p)
-{
- p->hist[0] = p->hist[1] = p->hist[2] = p->hist[3] = HHZ;
-}
-
-/*
- * This function is called when a task goes sleeping, ie. when the task
- * has potentially spent alot of time on the runqueue. p->run_timestamp
- * is the time the task has started running, 'now' is the time when the
- * task goes to sleep.
- */
-static inline void update_sleep_avg_deactivate(task_t *p)
-{
- int idx;
- unsigned long now = jiffies,
- seconds_passed = now/HHZ - p->run_timestamp/HHZ;
-
- /*
- * Do we have to update the history entries becase a
- * 'new second' has been started? If a new second has
- * been started then we have to clear all the 'full'
- * seconds that have been passed during the time the
- * task was running, and the new current entry has
- * to be cleared as well.
- *
- * Otherwise we only have to update the sleep timestamp.
- */
- if (unlikely(seconds_passed)) {
- if (seconds_passed < SLEEP_HIST_SIZE)
- for (idx = 0; idx < seconds_passed; idx++) {
- new_second(p);
- p->hist[p->hist_idx] = 0;
- }
- else
- clear_hist(p);
- }
- p->sleep_timestamp = now;
-}
-
-/*
- * This is called when a task gets runnable and gets moved to the runqueue.
- * ie. when the task has potentially spent alot of time sleeping.
- * p->sleep_timestamp is the time the task has started sleeping, 'now' is
- * the time when we go to the runqueue.
- */
-static inline void update_sleep_avg_activate(task_t *p, unsigned long now)
-{
- int idx;
- unsigned long sleep_ticks,
- seconds_passed = now/HHZ - p->sleep_timestamp/HHZ;
-
- /*
- * Do we have to update the history entries becase a
- * 'new second' has been started? This is slightly more
- * complex than the deactivate path, because in the deactivate
- * path history entries are simply cleared, but here we have
- * to add any potential time spent sleeping in the current
- * second. This value is 'sleep_ticks' - it can be anywhere
- * between 0 and HZ-1. (it cannot be HZ because that would mean
- * that the current second is over and we'd have to go to the
- * next history entry.) Another detail is that we might
- * have gone sleeping in this second, or in any previous second.
- *
- * Otherwise we only have to update the run timestamp and the
- * current history entry.
- */
- if (unlikely(seconds_passed)) {
- if (seconds_passed < SLEEP_HIST_SIZE) {
- /*
- * Update the "last partially-slept" second's entry:
- */
- p->hist[p->hist_idx] += HHZ - (p->sleep_timestamp % HHZ);
- new_second(p);
-
- /*
- * Clear any (optional) interim seconds that were
- * spent fully sleeping:
- */
- for (idx = 1; idx < seconds_passed; idx++) {
- new_second(p);
- p->hist[p->hist_idx] = HHZ;
- }
- } else
- /*
- * We slept more than 4 seconds, fill in the
- * history:
- */
- fill_hist(p);
-
- /* Clear the new current entry: */
- p->hist[p->hist_idx] = 0;
- sleep_ticks = now % HHZ;
- } else
- sleep_ticks = now - p->sleep_timestamp;
- /*
- * Update the current entry with the amount of
- * ticks the task spent sleeping:
- */
- p->hist[p->hist_idx] += sleep_ticks;
- p->run_timestamp = now;
-}
-
-/*
- * Get the current 'load average' of the task.
- *
- * Naively one would divide the sum by 4. But in fact the current entry
- * is just a partial history, so we have to divide by the actual portion
- * we recorded, which is somewhere between 3.0 and 4.0 seconds.
- */
-static inline unsigned int get_run_avg(task_t *p, unsigned long new)
-{
- return HHZ - (p->hist[0] + p->hist[1] + p->hist[2] +
- p->hist[3]) * HHZ / ((SLEEP_HIST_SIZE-1)*HHZ + (new % HHZ));
-}
-
static inline void activate_task(task_t *p, runqueue_t *rq)
{
prio_array_t *array = rq->active;
- unsigned long now = jiffies;
- unsigned int penalty;
-
- if (likely(p->run_timestamp == now))
- goto enqueue;
- update_sleep_avg_activate(p, now);
- /*
- * Give the process a priority penalty if it has not slept often
- * enough in the past. We scale the priority penalty according
- * to the current load of the runqueue, and the 'load history'
- * this process has. Eg. if the CPU has 3 processes running
- * right now then a process that has slept more than two-thirds
- * of the time is considered to be 'interactive'. The higher
- * the load of the CPUs is, the easier it is for a process to
- * get an non-interactivity penalty.
- *
- * the return value of get_run_avg() is an integer between 0 and HZ.
- * We scale this 'load value' to between 0 and MAX_USER_PRIO/3.
- * A task that generates 100% load gets the maximum penalty.
- */
- penalty = MAX_USER_PRIO * get_run_avg(p, now) / (3 * HHZ);
if (!rt_task(p)) {
- p->prio = NICE_TO_PRIO(p->__nice) + penalty;
- if (p->prio > MAX_PRIO-1)
- p->prio = MAX_PRIO-1;
+ unsigned long prio_bonus = JSLEEP_TO_PRIO(jiffies - p->sleep_jtime);
+
+ if (prio_bonus > MAX_PRIO)
+ prio_bonus = MAX_PRIO;
+ p->prio -= prio_bonus;
+ if (p->prio < MAX_RT_PRIO)
+ p->prio = MAX_RT_PRIO;
}
-enqueue:
enqueue_task(p, array);
rq->nr_running++;
}
@@ -311,7 +116,7 @@ static inline void deactivate_task(struct task_struct *p, runqueue_t *rq)
rq->nr_running--;
dequeue_task(p, p->array);
p->array = NULL;
- update_sleep_avg_deactivate(p);
+ p->sleep_jtime = jiffies;
}
static inline void resched_task(task_t *p)
@@ -482,98 +287,59 @@ static inline unsigned long max_rq_len(void)
}
/*
- * Current runqueue is empty, or rebalance tick: if there is an
- * inbalance (current runqueue is too short) then pull from
- * busiest runqueue(s).
+ * Current runqueue is empty, try to find work on
+ * other runqueues.
*
* We call this with the current runqueue locked,
* irqs disabled.
*/
-static void load_balance(runqueue_t *this_rq, int idle)
+static void load_balance(runqueue_t *this_rq)
{
- int imbalance, nr_running, load, prev_max_load,
- max_load, idx, i, this_cpu = smp_processor_id();
+ int nr_tasks, load, prev_max_load, max_load, idx, i;
task_t *next = this_rq->idle, *tmp;
- runqueue_t *busiest, *rq_src;
+ runqueue_t *busiest, *rq_tmp;
prio_array_t *array;
list_t *head, *curr;
+ prev_max_load = max_rq_len();
+ nr_tasks = prev_max_load - this_rq->nr_running;
+ /*
+ * It needs an at least ~10% imbalance to trigger balancing:
+ */
+ if (nr_tasks <= 1 + prev_max_load/8)
+ return;
+ prev_max_load++;
+
+repeat_search:
/*
* We search all runqueues to find the most busy one.
* We do this lockless to reduce cache-bouncing overhead,
- * we re-check the 'best' source CPU later on again, with
- * the lock held.
- *
- * We fend off statistical fluctuations in runqueue lengths by
- * saving the runqueue length during the previous load-balancing
- * operation and using the smaller one the current and saved lengths.
- * If a runqueue is long enough for a longer amount of time then
- * we recognize it and pull tasks from it.
- *
- * The 'current runqueue length' is a statistical maximum variable,
- * for that one we take the longer one - to avoid fluctuations in
- * the other direction. So for a load-balance to happen it needs
- * stable long runqueue on the target CPU and stable short runqueue
- * on the local runqueue.
- *
- * We make an exception if this CPU is about to become idle - in
- * that case we are less picky about moving a task across CPUs and
- * take what can be taken.
+ * we re-check the source CPU with the lock held.
*/
- if (idle || (this_rq->nr_running > this_rq->prev_nr_running[this_cpu]))
- nr_running = this_rq->nr_running;
- else
- nr_running = this_rq->prev_nr_running[this_cpu];
- prev_max_load = 1000000000;
-
busiest = NULL;
max_load = 0;
for (i = 0; i < smp_num_cpus; i++) {
- rq_src = cpu_rq(i);
- if (idle || (rq_src->nr_running < this_rq->prev_nr_running[i]))
- load = rq_src->nr_running;
- else
- load = this_rq->prev_nr_running[i];
- this_rq->prev_nr_running[i] = rq_src->nr_running;
-
+ rq_tmp = cpu_rq(i);
+ load = rq_tmp->nr_running;
if ((load > max_load) && (load < prev_max_load) &&
- (rq_src != this_rq)) {
- busiest = rq_src;
+ (rq_tmp != this_rq)) {
+ busiest = rq_tmp;
max_load = load;
}
}
if (likely(!busiest))
return;
-
- imbalance = (max_load - nr_running) / 2;
-
- /*
- * It needs an at least ~25% imbalance to trigger balancing.
- *
- * prev_max_load makes sure that we do not try to balance
- * ad infinitum - certain tasks might be impossible to be
- * pulled into this runqueue.
- */
- if (!idle && (imbalance < (max_load + 3)/4))
+ if (max_load <= this_rq->nr_running)
return;
prev_max_load = max_load;
-
- /*
- * Ok, lets do some actual balancing:
- */
-
- if (rq_cpu(busiest) < this_cpu) {
+ if (busiest->cpu < this_rq->cpu) {
spin_unlock(&this_rq->lock);
spin_lock(&busiest->lock);
spin_lock(&this_rq->lock);
} else
spin_lock(&busiest->lock);
- /*
- * Make sure nothing changed since we checked the
- * runqueue length.
- */
- if (busiest->nr_running <= nr_running + 1)
+ if (busiest->nr_running <= this_rq->nr_running + 1)
goto out_unlock;
/*
@@ -600,14 +366,14 @@ skip_bitmap:
goto new_array;
}
spin_unlock(&busiest->lock);
- goto out_unlock;
+ goto repeat_search;
}
head = array->queue + idx;
curr = head->next;
skip_queue:
tmp = list_entry(curr, task_t, run_list);
- if ((tmp == busiest->curr) || !(tmp->cpus_allowed & (1 << this_cpu))) {
+ if ((tmp == busiest->curr) || !(tmp->cpus_allowed & (1 << smp_processor_id()))) {
curr = curr->next;
if (curr != head)
goto skip_queue;
@@ -621,73 +387,42 @@ skip_queue:
*/
dequeue_task(next, array);
busiest->nr_running--;
- next->cpu = this_cpu;
+ next->cpu = smp_processor_id();
this_rq->nr_running++;
enqueue_task(next, this_rq->active);
if (next->prio < current->prio)
current->need_resched = 1;
- if (!idle && --imbalance) {
+ if (--nr_tasks) {
if (array == busiest->expired) {
array = busiest->active;
goto new_array;
}
spin_unlock(&busiest->lock);
+ goto repeat_search;
}
out_unlock:
spin_unlock(&busiest->lock);
}
-/*
- * One of the idle_cpu_tick() or the busy_cpu_tick() function will
- * gets called every timer tick, on every CPU. Our balancing action
- * frequency and balancing agressivity depends on whether the CPU is
- * idle or not.
- *
- * busy-rebalance every 250 msecs. idle-rebalance every 1 msec. (or on
- * systems with HZ=100, every 10 msecs.)
- */
-#define BUSY_REBALANCE_TICK (HZ/4 ?: 1)
-#define IDLE_REBALANCE_TICK (HZ/1000 ?: 1)
+/* Rebalance every 250 msecs */
+#define REBALANCE_TICK (HZ/4)
-static inline void idle_tick(void)
+void idle_tick(void)
{
- if ((jiffies % IDLE_REBALANCE_TICK) ||
- likely(this_rq()->curr == NULL))
- return;
- spin_lock(&this_rq()->lock);
- load_balance(this_rq(), 1);
- spin_unlock(&this_rq()->lock);
-}
-
-/*
- * Should we treat the task as interactive or not.
- * A task is interactive if it has not exceeded 50%
- * of the max CPU-hog penalty yet.
- */
-static int task_interactive(task_t *p, unsigned long now)
-{
- int penalty;
+ unsigned long flags;
- if (rt_task(p))
- return 1;
- penalty = MAX_USER_PRIO * get_run_avg(p, jiffies) / (3 * HHZ);
- if (penalty <= MAX_USER_PRIO/6)
- return 1;
- return 0;
+ if (!(jiffies % REBALANCE_TICK) && likely(this_rq()->curr != NULL)) {
+ spin_lock_irqsave(&this_rq()->lock, flags);
+ load_balance(this_rq());
+ spin_unlock_irqrestore(&this_rq()->lock, flags);
+ }
}
-/*
- * This function gets called by the timer code, with HZ frequency.
- * We call it with interrupts disabled.
- */
-void scheduler_tick(task_t *p)
+void expire_task(task_t *p)
{
- unsigned long now = jiffies;
runqueue_t *rq = this_rq();
+ unsigned long flags;
- if (p == rq->idle || !rq->idle)
- return idle_tick();
- /* Task might have expired already, but not scheduled off yet */
if (p->array != rq->active) {
p->need_resched = 1;
return;
@@ -695,43 +430,21 @@ void scheduler_tick(task_t *p)
/*
* The task cannot change CPUs because it's the current task.
*/
- spin_lock(&rq->lock);
+ spin_lock_irqsave(&rq->lock, flags);
if ((p->policy != SCHED_FIFO) && !--p->time_slice) {
+ prio_array_t *array = rq->active;
p->need_resched = 1;
- if (rt_task(p))
- p->time_slice = RT_PRIO_TO_TIMESLICE(p->prio);
- else
- p->time_slice = PRIO_TO_TIMESLICE(p->prio);
-
- /*
- * Timeslice used up - discard any possible
- * priority penalty:
- */
dequeue_task(p, rq->active);
- /*
- * Tasks that have nice values of -20 ... -15 are put
- * back into the active array. If they use up too much
- * CPU time then they'll get a priority penalty anyway
- * so this can not starve other processes accidentally.
- * Otherwise this is pretty handy for sysadmins ...
- */
- if (task_interactive(p, now))
- enqueue_task(p, rq->active);
- else
- enqueue_task(p, rq->expired);
- } else {
- /*
- * Deactivate + activate the task so that the
- * load estimator gets updated properly:
- */
if (!rt_task(p)) {
- deactivate_task(p, rq);
- activate_task(p, rq);
+ if (++p->prio >= MAX_PRIO)
+ p->prio = MAX_PRIO - 1;
+ if (!TASK_INTERACTIVE(p))
+ array = rq->expired;
}
+ enqueue_task(p, array);
+ p->time_slice = NICE_TO_TIMESLICE(p->__nice);
}
- if (!(now % BUSY_REBALANCE_TICK))
- load_balance(rq, 0);
- spin_unlock(&rq->lock);
+ spin_unlock_irqrestore(&rq->lock, flags);
}
void scheduling_functions_start_here(void) { }
@@ -756,18 +469,18 @@ need_resched_back:
spin_lock_irq(&rq->lock);
switch (prev->state) {
- case TASK_INTERRUPTIBLE:
- if (unlikely(signal_pending(prev))) {
- prev->state = TASK_RUNNING;
- break;
- }
- default:
- deactivate_task(prev, rq);
- case TASK_RUNNING:
+ case TASK_INTERRUPTIBLE:
+ if (unlikely(signal_pending(prev))) {
+ prev->state = TASK_RUNNING;
+ break;
+ }
+ default:
+ deactivate_task(prev, rq);
+ case TASK_RUNNING:
}
pick_next_task:
if (unlikely(!rq->nr_running)) {
- load_balance(rq, 1);
+ load_balance(rq);
if (rq->nr_running)
goto pick_next_task;
next = rq->idle;
@@ -1302,7 +1015,7 @@ asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval)
p = find_process_by_pid(pid);
if (p)
jiffies_to_timespec(p->policy & SCHED_FIFO ?
- 0 : RT_PRIO_TO_TIMESLICE(p->prio), &t);
+ 0 : NICE_TO_TIMESLICE(p->__nice), &t);
read_unlock(&tasklist_lock);
if (p)
retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0;
@@ -1410,7 +1123,7 @@ static inline void double_rq_lock(runqueue_t *rq1, runqueue_t *rq2)
if (rq1 == rq2)
spin_lock(&rq1->lock);
else {
- if (rq_cpu(rq1) < rq_cpu(rq2)) {
+ if (rq1->cpu < rq2->cpu) {
spin_lock(&rq1->lock);
spin_lock(&rq2->lock);
} else {
@@ -1468,6 +1181,7 @@ void __init sched_init(void)
rq->active = rq->arrays + 0;
rq->expired = rq->arrays + 1;
spin_lock_init(&rq->lock);
+ rq->cpu = i;
for (j = 0; j < 2; j++) {
array = rq->arrays + j;
diff --git a/kernel/timer.c b/kernel/timer.c
index da17ae4ac..ce3945cda 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -585,16 +585,17 @@ void update_process_times(int user_tick)
update_one_process(p, user_tick, system, cpu);
if (p->pid) {
+ expire_task(p);
if (p->__nice > 0)
kstat.per_cpu_nice[cpu] += user_tick;
else
kstat.per_cpu_user[cpu] += user_tick;
kstat.per_cpu_system[cpu] += system;
} else {
+ idle_tick();
if (local_bh_count(cpu) || local_irq_count(cpu) > 1)
kstat.per_cpu_system[cpu] += system;
}
- scheduler_tick(p);
}
/*
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 5a0152e46..03bced06b 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -616,8 +616,9 @@ int vsscanf(const char * buf, const char * fmt, va_list args)
case 'X':
base = 16;
break;
- case 'd':
case 'i':
+ base = 0;
+ case 'd':
is_sign = 1;
case 'u':
break;
@@ -637,7 +638,11 @@ int vsscanf(const char * buf, const char * fmt, va_list args)
while (isspace(*str))
str++;
- if (!*str || !isdigit(*str))
+ if (!*str
+ || (base == 16 && !isxdigit(*str))
+ || (base == 10 && !isdigit(*str))
+ || (base == 8 && (!isdigit(*str) || *str > '7'))
+ || (base == 0 && !isdigit(*str)))
break;
switch(qualifier) {
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 71d079f69..ede841b15 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -909,6 +909,7 @@ asmlinkage long sys_swapon(const char * specialfile, int swap_flags)
p->swap_file = swap_file;
+ error = -EINVAL;
if (S_ISBLK(swap_file->f_dentry->d_inode->i_mode)) {
p->swap_device = swap_file->f_dentry->d_inode->i_rdev;
set_blocksize(p->swap_device, PAGE_SIZE);