2002-04-06 01:02:15

by Linus Torvalds

[permalink] [raw]
Subject: Linux 2.5.8-pre2


More merging with various people, USB+ARM+more network drivers etc.

The actual patch is pretty huge, because the USB changes moves USB files
around a lot. The BK diffs (and actual "real changes") are smaller than
the patch would imply (here Larry pipes up with number of deltas ;)

Linus

---

Summary of changes from v2.5.8-pre1 to v2.5.8-pre2
============================================

<[email protected]> (02/03/13 1.384.11.1)
[PATCH] 1054/1: Fixes security problem with static i/o mapping.


For 2.5.x only. (Patch 1042/1 is for 2.4.x)

(replaces patch 1041/1.)

Christopher Hoover
mailto:[email protected]
mailto:[email protected]


<[email protected]> (02/03/13 1.384.11.2)
[PATCH] 964/1: Consus led patches

+++ linux/arch/arm/mach-sa1100/leds.c Wed Feb 13 13:55:33 2002
+++ linux/arch/arm/mach-sa1100/leds.h Wed Feb 13 13:55:52 2002
+++ linux/include/asm-arm/leds.h Wed Feb 13 13:01:31 2002

Additions for consus_leds_event (parallels assabet_leds_event).
Added led_start_time_mode and led_stop_timer_mode for heartbeat led.
Added led_blue_on and led_blue_off for Blue led support.


<[email protected]> (02/03/13 1.388.3.2)
Miscellaneous compiler warning fixes, other small fixes and
cleanups for ARM.

<[email protected]> (02/03/13 1.388.3.4)
Fix scope of init/exit functions in ds1620.c
NetWinder flash driver should use ioremap, not the private __ioremap.

<[email protected]> (02/03/13 1.388.3.5)
Update ARM related video drivers:
- cyber2000fb
- sa1100fb
Add new ARM video drivers:
- anakinfb
- clps711xfb

<[email protected]> (02/03/17 1.526)
SA1100 IrDA driver updates.

<[email protected]> (02/03/19 1.528)
Convert ARM92x/ARM1020 specific configuration symbols to generic CPU
symbols. Remove unused flush_page_to_ram in ARM code.

<[email protected]> (02/03/22 1.384.11.3)
[PATCH] 1079/1: recognize PXA250 revision B0 and hier



<[email protected]> (02/03/22 1.384.11.4)
[PATCH] 1080/1: Addition of new files for the Intel PXA250/210 architecture

This only populates the linux/arch/arm/mach-pxa directory.


<[email protected]> (02/03/22 1.384.11.5)
[PATCH] 1081/1: addition of new header files for the Intel PXA250/210 architecture

This patch populates the linux/include/asm-arm/arch-pxa directory.


<[email protected]> (02/03/22 1.384.11.6)
[PATCH] 1082/1: changes to linux/arch/arm/kernel/* for PXA architecture
Actually only debug.S and entry-armv.S


<[email protected]> (02/03/22 1.384.11.7)
[PATCH] 1083/1: 64-bit unsigned modulo arithmetic support
I've added support for 64-bit modulo arithmetic on ARM. This is needed for
the video4linux API to function properly and since there's already support
for 64-bit divides, I think there shouldn't be any reason for the absence of
this.


<[email protected]> (02/03/23 1.384.11.8)
[PATCH] 1092/1: Avoid unbalanced IRQ from LCD on SA1100

Remove "enable_irq(IRQ_LCD)" call from video/sa1100fb.c

<[email protected]> (02/03/24 1.384.11.9)
[PATCH] 1094/1: 2.4.18-rmk3: fix for build failure with no video
2.4.18-rmk3 fails to build on the EBSA285 if there is no video stuff
enabled with a missing symbol. For me the linker lied and told me it
was in irq.c but it was actually in the previous file in the link,
mach-footbridge/arch.c ; the symbol is screen_info which is what the
ORIG_* macros use.

Note I haven't yet tested this booting, just building.


<[email protected]> (02/03/24 1.529)
Miscellaneous build corrections/warning fixes.

<[email protected]> (02/03/25 1.524.11.1)
Break an include loop by moving cache flushing routines from
asm/pgtable.h and/or asm/pgalloc.h to asm/cacheflush.h, and
tlb flushing routines to asm/tlbflush.h.

<[email protected]> (02/03/26 1.524.12.1)
Add concept of system bus, so system devices (CPUs, PICs, etc) can have a common home in the device tree.
Add helper functions for {un,}registering.

<[email protected]> (02/03/26 1.524.12.2)
Ok, really add drivers/base/sys.c

<[email protected]> (02/03/26 1.524.12.3)
Driver model update:
Create global list in which all devices are inserted. Done by Kai Germaschewski.

<[email protected]> (02/03/26 1.524.12.4)
Add device_{suspend,resume,shutdown} calls.

<[email protected]> (02/03/28 1.531)
Miscellaneous build/bug fixes.

<[email protected]> (02/04/01 1.524.13.1)
Fix the kernel build when we have multi-part objects both in $(obj-y)
and $(obj-m).

Before, we would have built (though not linked) the individual objects
for multi-part modules even when building vmlinux and vice versa.

<[email protected]> (02/04/03 1.524.7.39)
Tigon3 driver pci_unmap_foo changes were half complete,
fix things up. Noted by Jeff Garzik.

<[email protected]> (02/04/03 1.524.21.1)
kernel/time.c needs linux/errno.h

<[email protected]> (02/04/03 1.524.21.2)
drivers/usb/hub.c needs linux/errno.h

<[email protected]> (02/04/03 1.524.21.3)
drivers/media/video/videodev.c needs linux/slab.h

<[email protected]> (02/04/03 1.524.22.1)
sparc64/kernel/semaphore.c needs errno.h
add forward decl of struct page to asm-sparc64/pgtable.h

<[email protected]> (02/04/03 1.524.22.2)
sparc64/kernel/binfmt_elf32.c:ELF_CORE_COPY_REGS needs
final semi-colon.

<[email protected]> (02/04/03 1.524.22.3)
sparc64/math-emu/math.c needs linux/errno.h

<[email protected]> (02/04/03 1.524.23.1)
Update pcnet_cs net driver for recent removal of rmem_{start,end}
from struct net_device. (actually, for this driver, the functionality
was simply moved to 8390.h)

<[email protected]> (02/04/04 1.524.24.2)
Remove unused references to dev->rmem_{start,end}
from wavelan_cs net driver.

<[email protected]> (02/04/04 1.524.24.3)
olympic tokenring driver compile fix

<[email protected]> (02/04/04 1.524.24.4)
Add missing MODULE_LICENSE tags to several net drivers.

Also... surprise! Andrew Morton's aic7xxx build fix
is also included. Ah well, 1001 people probably applied
the same patch by hand, and it's easy to merge, so oh well.

<[email protected]> (02/04/04 1.524.24.5)
Merge ioc3-eth net drvr changes from 2.4.x:
- Improved MAC address discovery.
- endian fixes


<[email protected]> (02/04/04 1.524.24.6)
Merge gt96100 mips net drvr updates from 2.4.x:
* Moved to 2.4.14, [email protected]. Modified driver to add
proper gt96100A support.
* Moved eth port 0 to irq 3 (mapped to GT_SERINT0 on EV96100A)
in order for both ports to work. Also cleaned up boot
option support (mac address string parsing), fleshed out
gt96100_cleanup_module(), and other general code cleanups
<[email protected]>.

<[email protected]> (02/04/04 1.524.24.7)
Merge au1000_eth net drvr updates from 2.4.x:
* add support for LSI 10/100 phy
* other minor cleanups

<[email protected]> (02/04/04 1.524.24.8)
com20020 arcnet drvr build fix (add missing comma)

<[email protected]> (02/04/04 1.524.24.9)
Merge ariadne2 net drvr updates from 2.4.x:
* use Zorro-specific z_{read,write}[bwl] routines
* remove superfluous include

<[email protected]> (02/04/04 1.524.24.10)
Merge a2065 net drvr update from 2.4.x:
* make sure to stop chip before enabling interrupt via request_irq

<[email protected]> (02/04/04 1.524.25.1)
IrDA: Fix w83977af_ir FIR drivers for new DMA API

<[email protected]> (02/04/04 1.524.25.2)
IrDA trivial fixes:
o [CORRECT] Handle signals while IrSock is blocked on Tx
o [CORRECT] Fix race condition in LAP when receiving with pf bit
o [CRITICA] Prevent queuing Tx data before IrComm is ready
o [FEATURE] Warn user of common misuse of IrLPT


<[email protected]> (02/04/04 1.524.25.3)
IrDA: Allow tuning of Max Tx MTU to workaround spec contradiction


<[email protected]> (02/04/04 1.524.25.4)
IrDA: Correct fix for IrNET disconnect indication :
if socket is not connected, don't hangup, to allow passive operation


<[email protected]> (02/04/04 1.524.25.5)
IrDA discovery fixes:
o [FEATURE] Propagate mode of discovery to higher protocols
o [CORRECT] Disable passive discovery in ircomm and irlan
Prevent client and server to simultaneously connect to each other
o [CORRECT] Force expiry of discovery log on LAP disconnect


<[email protected]> (02/04/04 1.524.25.6)
IrDA USB disconnect changes:
o [CRITICA] Fix race condition between disconnect and the rest
o [CRITICA] Force synchronous unlink of URBs in disconnect
o [CRITICA] Cleanup instance if disconnect before close
<Following patch from Martin Diehl>
o [CRITICA] Call usb_submit_urb() with GPF_ATOMIC

<[email protected]> (02/04/04 1.524.25.7)
IrDA: handle new NSC chip variant

<[email protected]> (02/04/04 1.524.25.8)
IrDA: Correct location of dev tx stats update

<[email protected]> (02/04/04 1.524.24.11)
Merge hydra net drvr conversion to Zorro-specific
z_{read,write}[bwl] routines from 2.4.x.

<[email protected]> (02/04/04 1.524.26.1)
This fixes the "i_blocks went wrong when the disk filled up"
problem.

In ext3_new_block() we increment i_blocks early, so the
quota operation can be performed outside lock_super().
But if the block allocation ends up failing, we forget to
undo the allocation.

This is not a serious bug, and probably does not warrant
an upgrade for production machines. Its effects are:

1) errors are generated from e2fsck and

2) users could appear to be over quota when they really aren't.

The patch undoes the accounting operation if the allocation
ends up failing.

<[email protected]> (02/04/04 1.524.24.12)
Merge some new PCI ids from e100 to eepro100 net driver.

<[email protected]> (02/04/04 1.524.24.13)
Various minor bug fixes for 3c59x net driver.

<[email protected]> (02/04/04 1.524.24.14)
Fix jiffies-comparison timeout bug in arlan net driver.

<[email protected]> (02/04/04 1.524.26.2)
Andrew Morton's ext2 sync mount speedup. Description:

At present, when mounted synchronously or with `chattr +S' in effect,
ext2 syncs the indirect blocks for every new block when extending a
file.

This is not necessary, because a sync is performed on the way out of
generic_file_write(). This will pick up all necessary data from
inode->i_dirty_buffers and inode->i_dirty_data_buffers, and is
sufficient.

The patch removes all the syncing of indirect blocks.

On a non-write-caching scsi disk, an untar of the util-linux tarball
runs three times faster. Writing a 100 megabyte file in one megabyte
chunks speeds up ten times.

The patch also removes the intermediate indirect block syncing on the
truncate() path. Instead, we sync the indirects at a single place, via
inode->i_dirty_buffers. This not only means that the writes (may)
cluster better. It means that we perform much, much less actual I/O
during truncate, because most or all of the indirects will no longer be
needed for the file, and will be invalidated.

fsync() and msync() still work correctly. One side effect of this
patch is that VM-initiated writepage() against a file hole will no
longer block on writeout of indirect blocks. This is good.


<[email protected]> (02/04/04 1.524.26.3)
ext3 filesystem sync mount speedup:
Again, we don't need to sync indirects as we dirty them because
we run a commit if IS_SYNC(inode) prior to returning to the
caller of write(2).

Writing a 10 meg file in 0.1 meg chunks is sped up by, err,
a factor of fifty. That's a best case.


<[email protected]> (02/04/04 1.524.24.15)
e100 net driver update 1/3:
The patch separates max busy wait constants making in max of 100 usec for
wait scb and max of 50 usec for wait cus idle. These constants found
sufficient using heavy traffic tests.

<[email protected]> (02/04/04 1.524.24.16)
e100 net driver update 2/3:
Adding missing pci write flush to the procedure e100_exec_cmd

<[email protected]> (02/04/04 1.524.24.17)
e100 net driver update 3/3:
Adding proper print level qualifier to the printk calls.

<[email protected]> (02/04/04 1.524.28.1)
Detect bad JFS directory to avoid infinite loop

<[email protected]> (02/04/04 1.524.28.2)
JFS include cleanup

Remove redundant include of slab.h
Submitted by Christoph Hellwig

<[email protected]> (02/04/04 1.524.28.3)
JFS: remove dead code

Submitted by Christoph Hellwig

<[email protected]> (02/04/04 1.524.28.4)
Add support for external JFS journal

Submitted by Christoph Hellwig & Dave Kleikamp

<[email protected]> (02/04/04 1.524.28.5)
JFS: simplify sync_metapage

Submitted by Christoph Hellwig

<[email protected]> (02/04/04 1.524.28.6)
Remove register keyword from JFS code

Submitted by Christoph Hellwig

<[email protected]> (02/04/04 1.524.28.7)
No need to handle regular files in jfs_mknod
Submitted by Christoph Hellwig

<[email protected]> (02/04/04 1.524.28.8)
Make JFS licence boilerplate uniform, update copyright dates
Submitted by Christoph Hellwig and Dave Kleikamp

<[email protected]> (02/04/04 1.524.29.1)
Don't allow preemption to change task state.

<[email protected]> (02/04/04 1.524.29.2)
[PATCH] kjournald exits with nonzero preempt_count

The preempt_count debug check that went into 2.5.8-pre1 already caught a
simple case in kjournald. Specifically, kjournald does not drop the BKL
when it exits as it knows schedule will do so for it.

For the sake of clarity and exiting with a preempt_count of zero, the
attached patch explicitly calls unlock_kernel when kjournald is exiting.

<[email protected]> (02/04/04 1.524.29.4)
Fix up bad time compare from the -dj merge

<[email protected]> (02/04/04 1.534)
Cset exclude: [email protected]|ChangeSet|20020403195622

<[email protected]> (02/04/04 1.524.7.40)
In linux/skbuff.h, always use unsigned long for flags.

<[email protected]> (02/04/04 1.524.22.4)
On sparc64, flush_thread needs to setup the PGD cache
for 64-bit apps too.

<[email protected]> (02/04/04 1.524.30.1)
USB visor driver

Added support for the Sony OS 4.1 devices. Thanks to Hiroyuki ARAKI
<[email protected]> for the information.

<[email protected]> (02/04/04 1.535)
Update kernel version

<[email protected]> (02/04/04 1.536)
[PATCH] cleanup list usage in dquot

From the kernel janitor folks

<[email protected]> (02/04/04 1.537)
[PATCH] list_for_each is fs/

From the kernel janitor folks

<[email protected]> (02/04/04 1.538)
[PATCH] Improved allocator for NTFS

Originally by Anton Altaparmakov.
I think Anton is going to submit his rewritten NTFS soon making this null and void,
but in the interim, it fixes a known problem with NTFS and large allocations.

<[email protected]> (02/04/04 1.539)
[PATCH] increase number of transaction locks in JFS txnmgr

Original fix from Andi Kleen

<[email protected]> (02/04/04 1.540)
[PATCH] MSDOS fs option parser cleanup

Original from Rene Scharfe
This fixes a problem where MSDOS fs's ignore their 'check' mount option.

<[email protected]> (02/04/04 1.541)
[PATCH] bss bits for isofs

Originally from the kernel janitor folks

<[email protected]> (02/04/04 1.542)
[PATCH] QNX4fs sync

Brings QNX4FS back in sync with 2.4

<[email protected]> (02/04/04 1.543)
[PATCH] better dquot accounting


<[email protected]> (02/04/04 1.544)
[PATCH] ext3 inode generation improvements.

Originally from Andrew Morton

<[email protected]> (02/04/04 1.545)
[PATCH] named structure initialisers for fs/

Originally by Grant R.Guenther
Has had a quick once over by Al, who weeded out one chunk that was
unrelated.

<[email protected]> (02/04/04 1.546)
[PATCH] struct super_block cleanup - reiserfs

Original from: Brian Gerst <[email protected]>
Has had a once over by Chris Mason and Al.

Seperates reiserfs_sb_info from struct super_block.

Brian Gerst

<[email protected]> (02/04/04 1.555)
[PATCH] EFI GUID partition support update.

More bits from Matt Domsch. Fixes GUID printing, and updates
to what's in the IA64 tree. Other cleanups are mentioned in
the changelog in the patch.

<[email protected]> (02/04/04 1.524.30.2)
USB

moved files to different subdirectories to make try to make sense
of the current mess, and to allow usb client drivers to integrate into
the tree easier.

<[email protected]> (02/04/04 1.556)
[PATCH] IS_DEADDIR checks (2.5)

2.4 variant will go to Marcelo in a couple of minutes.

Patch moves IS_DEADDIR() checks into may_delete().

<[email protected]> (02/04/04 1.524.30.3)
usb subsystem now builds as modules.
dependancies still seem broken.

<[email protected]> (02/04/04 1.557)
update x86 defconfig

<[email protected]> (02/04/04 1.558)
Fix tlbflush header file dependencies

<[email protected]> (02/04/04 1.559)
uhhuh. Fix duplicate merge from -dj tree

<[email protected]> (02/04/04 1.560)
[PATCH] preemptive kernel behavior change: don't be rude

- do not manually set task->state
- instead, in preempt_schedule, set a flag in preempt_count that
denotes that this task is entering schedule off a kernel preemption.
- use this flag in schedule to jump to pick_next_task
- in preempt_schedule, upon return from schedule, unset the flag
- have entry.S just call preempt_schedule and not duplicate this work,
as Linus suggested. I agree. Note this makes debugging easier as
we keep a single point of entry for kernel preemptions.

The result: we can safely preempt non-TASK_RUNNING tasks. If one is
preempted, we can safely survive schedule because we won't handle the
special casing of non-TASK_RUNNING at the top of schedule. Thus other
tasks can run as desired and our non-TASK_RUNNING task will eventually
be rescheduled, in its original state, and complete happily.

This is the behavior we have in the 2.4 patches and 2.5 until
~2.5.6-pre. This works. It requires no other changes elsewhere (it
actually removes some special-casing Ingo did in the signal code).

<[email protected]> (02/04/04 1.524.30.4)
USB

moved lots of the Config.in info into the subdirectories.
fixed up the makefiles to work nicer.

<[email protected]> (02/04/04 1.561)
Scheduler preempt fixes and cleanups

<[email protected]> (02/04/04 1.562)
Make the assembly-level code match the preempt_sched
changes

<[email protected]> (02/04/04 1.563)
More fixups for tlbflush.h header split

<[email protected]> (02/04/04 1.564)
Fix exit_notify() to actually do what the comment
says it should do - lock out preemption.

<[email protected]> (02/04/04 1.524.30.5)
USB

moved some files from misc to image
cleaned up makefile some more.

<[email protected]> (02/04/04 1.524.30.6)
USB

fixed lib Makefile problem with usb files moving
moved drivers/usb/scanner/ to drivers/usb/image/

<[email protected]> (02/04/05 1.524.30.7)
USB

moved the host drivers help to the host directory

<[email protected]> (02/04/05 1.524.30.8)
USB

more file movement cleanups. Now handles misc drivers compiled into
the kernel corectly.

<[email protected]> (02/04/05 1.566)
Add device_shutdown() calls to reboot and power off transitions (and let the user know)

<[email protected]> (02/04/05 1.567)
compile fix for drivers/base/sys.c

<[email protected]> (02/04/05 1.568)
Add platform driver object

<[email protected]> (02/04/05 1.524.30.9)
USB

moved class/storage/ back to storage/
created input/
orderd the makefiles and config.in menus better.

<[email protected]> (02/04/05 1.570)
Duh. Use "device_lock", not "device_root" for locking.

<[email protected]> (02/04/05 1.524.30.10)
USB

added a README file to explain what the different subdirectories are for.

<[email protected]> (02/04/05 1.524.30.11)
USB

moved the USB_STORAGE Config.help items into the drivers/usb/storage directory.

<[email protected]> (02/04/05 1.572)
[PATCH] elevator 'buglet'

Lets just kill this check -- it usually only catches drivers queueing
something in front of a started request on their own (such as shoving a
request sense in front of a failed packet command, for instance). So
it's either working around this detection in some drivers, or killing
it. I vote for the latter, patch attached against 2.5.8-pre1 :-)

<[email protected]> (02/04/05 1.573)
[PATCH] PATCH 1 of 4 : knfsd : Use symbols for size calculation for response sizes.

Use symbolic names for some common size components in the response
size calculation for the NFSD. This makes it easier to get the
numbers right and to review them.
This patch also fixes a few number for nfsv3 that were wrong.

<[email protected]> (02/04/05 1.574)
[PATCH] PATCH 2 of 4 : knfsd : Allow exporting of deviceless filesystems if fsid= given

Previously we could only export FS_REQUIRES_DEV filesystems
as we need a devno to put in the filehandle.
Now that we have fsid= (NFSEXP_FSID) we don't need a devno
to put in the filehandle so we can relax this requirement.

<[email protected]> (02/04/05 1.575)
[PATCH] PATCH 3 of 4 : knfsd : Store the fsid in the returned attributes instead of the device number

When a filesystem is exported with fsid= we should use that
fsid instead of the i_dev number when returning NFS attributes,
so that there is no chance of clients that depend on the filesys
id in the attributes getting confused by device numbers changing.

We only do this if the reference filehandle uses fsid to identify
the filesystem, so that a server can be converted from non-fsid= to
using fsid= without confusing active clients.

<[email protected]> (02/04/05 1.576)
[PATCH] PATCH 4 of 4 : knfsd : Increase the max block size for NFS replies.

This increases the max read/write size for nfsd from 8K to 32K.

This requires making NFSv2 return the right number in statfs
requests. NFSv3 already does that.

<[email protected]> (02/04/05 1.577)
[PATCH] PATCH 4a or 4 : knfs : typo...

typo in that last patch, sorry.

<[email protected]> (02/04/05 1.578)
[PATCH] shift BKL out of notify_change

Moved i_sem down into notify_change() and out of the UMSDOS
function. Moved BKL down from notify_change into filesystems.

<[email protected]> (02/04/05 1.579)
Make legacy drivers who use "virt_to_bus()" and friends work on x86.

It's up to other architectures to worry about portability for now.

<[email protected]> (02/04/05 1.581)
Oops, remove remnants of old attribute lock

<[email protected]> (02/04/05 1.582)
Force some semblance of workingness onto qla1280 driver

<[email protected]> (02/04/05 1.583)
Clean up do_truncate due notify_change() locking change



2002-04-06 06:59:45

by Larry McVoy

[permalink] [raw]
Subject: Re: Linux 2.5.8-pre2

On Fri, Apr 05, 2002 at 05:01:31PM -0800, Linus Torvalds wrote:
>
> More merging with various people, USB+ARM+more network drivers etc.
>
> The actual patch is pretty huge, because the USB changes moves USB files
> around a lot. The BK diffs (and actual "real changes") are smaller than
> the patch would imply (here Larry pipes up with number of deltas ;)

Here ya go.

takepatch: 991 new revisions, 0 conflicts in 578 files
206734 bytes uncompressed to 954854, 4.62X expansion
Running resolve to apply new work ...
Using lm.bitmover.com:0 as graphical display
Verifying consistency of the RESYNC tree...
resolve: found 103 renames in pass 1
resolve: resolved 103 renames in pass 2
resolve: applied 578 files in pass 4

I love how much people move around files when the SCM system actually handles
it properly. I used to worry that people who were trained to not move files
by CVS would never figure out that BK handles it; I was wrong and glad of it :)
--
---
Larry McVoy lm at bitmover.com http://www.bitmover.com/lm

2002-04-07 10:18:19

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: Linux 2.5.8-pre2

On Fri, 5 Apr 2002, Linus Torvalds wrote:
> <[email protected]> (02/03/13 1.388.3.5)
> Update ARM related video drivers:
> - cyber2000fb
> - sa1100fb
> Add new ARM video drivers:
> - anakinfb
> - clps711xfb

Please either add resource management code to anakinfb and clps711xfb, or apply
the patch below.

--- linux-2.5.8-pre2/drivers/video/fbmem.c.orig Sun Apr 7 10:54:24 2002
+++ linux-2.5.8-pre2/drivers/video/fbmem.c Sun Apr 7 12:15:21 2002
@@ -157,12 +157,6 @@
#ifdef CONFIG_FB_AMIGA
{ "amifb", amifb_init, amifb_setup },
#endif
-#ifdef CONFIG_FB_ANAKIN
- { "anakinfb", anakinfb_init, NULL },
-#endif
-#ifdef CONFIG_FB_CLPS711X
- { "clps711xfb", clps711xfb_init, NULL },
-#endif
#ifdef CONFIG_FB_CYBER
{ "cyber", cyberfb_init, cyberfb_setup },
#endif
@@ -293,6 +287,12 @@
#endif
#ifdef CONFIG_FB_VOODOO1
{ "sst", sstfb_init, sstfb_setup },
+#endif
+#ifdef CONFIG_FB_ANAKIN
+ { "anakinfb", anakinfb_init, NULL },
+#endif
+#ifdef CONFIG_FB_CLPS711X
+ { "clps711xfb", clps711xfb_init, NULL },
#endif
/*
* Generic drivers that don't use resource management (yet)

Gr{oetje,eeting}s,

Geert (fbdev init order watchdog^H^H^Hpenguin)

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2002-04-07 10:27:25

by Russell King

[permalink] [raw]
Subject: Re: Linux 2.5.8-pre2

On Sun, Apr 07, 2002 at 12:17:28PM +0200, Geert Uytterhoeven wrote:
> Please either add resource management code to anakinfb and clps711xfb,
> or apply the patch below.

They're not ISA nor PCI - in fact, they're specific system-on-a-chip
framebuffers. I therefore don't see the point of your patch.

(Oh, and a bugbear - people go running around adding checks for the
return value of request_region and friends on embedded devices where
there can't be the possibility of a clash waste memory needlessly.)

--
Russell King ([email protected]) The developer of ARM Linux
http://www.arm.linux.org.uk/personal/aboutme.html

2002-04-07 10:43:31

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: Linux 2.5.8-pre2

On Sun, 7 Apr 2002, Russell King wrote:
> On Sun, Apr 07, 2002 at 12:17:28PM +0200, Geert Uytterhoeven wrote:
> > Please either add resource management code to anakinfb and clps711xfb,
> > or apply the patch below.
>
> They're not ISA nor PCI - in fact, they're specific system-on-a-chip
> framebuffers. I therefore don't see the point of your patch.

Even then, please don't add them to the section marked with the comment
`Chipset specific drivers that use resource management'. My patch just moves
their initialization to the section marked with the comment `Chipset specific
drivers that don't use resource management (yet)'. So it's still valid.

> (Oh, and a bugbear - people go running around adding checks for the
> return value of request_region and friends on embedded devices where
> there can't be the possibility of a clash waste memory needlessly.)

Perhaps you want to modularize the driver later? Resource management also
prevents you from insmoding two drivers for the same hardware.

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2002-04-07 10:50:47

by Andrew Morton

[permalink] [raw]
Subject: Re: Linux 2.5.8-pre2

Russell King wrote:
>
> (Oh, and a bugbear - people go running around adding checks for the
> return value of request_region and friends on embedded devices where
> there can't be the possibility of a clash waste memory needlessly.)

If you do:

#define request_region(start, n, name)
({
__request_region(start, n, name);
(struct resource *)1;
})
#define release_region(start, n) do { } while (0)

then the compiler will remove all those error checks for you,
as well as the release_region calls.

Of course if you actually want to use the innards of the
returned resource * then that's not so good.

However, you can make it:

#define request_region() \
({ \
struct resource *r; \
r = __request_region(); \
(struct resource *)((long)r | 1); \
})

and, amazingly, the compiler still knows that the value
is non-zero, and still will elide those tests. You'll
need to mask that bit off again to use the pointer.

Whether you'll stoop this low depends upon how much you
want those bytes back :)

-

2002-04-07 10:56:40

by Russell King

[permalink] [raw]
Subject: Re: Linux 2.5.8-pre2

On Sun, Apr 07, 2002 at 12:42:45PM +0200, Geert Uytterhoeven wrote:
> Perhaps you want to modularize the driver later? Resource management also
> prevents you from insmoding two drivers for the same hardware.

I doubt I'll be doing anything with those two drivers - up to other
people. I'm prodding them now, but not expecting any immediate
reaction.

--
Russell King ([email protected]) The developer of ARM Linux
http://www.arm.linux.org.uk/personal/aboutme.html

2002-04-07 13:34:46

by Russell King

[permalink] [raw]
Subject: Re: Linux 2.5.8-pre2

On Sun, Apr 07, 2002 at 12:42:45PM +0200, Geert Uytterhoeven wrote:
> On Sun, 7 Apr 2002, Russell King wrote:
> > On Sun, Apr 07, 2002 at 12:17:28PM +0200, Geert Uytterhoeven wrote:
> > > Please either add resource management code to anakinfb and clps711xfb,
> > > or apply the patch below.
> >
> > They're not ISA nor PCI - in fact, they're specific system-on-a-chip
> > framebuffers. I therefore don't see the point of your patch.
>
> Even then, please don't add them to the section marked with the comment
> `Chipset specific drivers that use resource management'. My patch just moves
> their initialization to the section marked with the comment `Chipset specific
> drivers that don't use resource management (yet)'. So it's still valid.

Ok, I agree the clps711x can be moved. As for Anakin, that's up to the
anakin people to sort out - I've mailed them directly. There's a bunch
of other stuff in there as well that needs to be fixed up.

> > (Oh, and a bugbear - people go running around adding checks for the
> > return value of request_region and friends on embedded devices where
> > there can't be the possibility of a clash waste memory needlessly.)
>
> Perhaps you want to modularize the driver later? Resource management also
> prevents you from insmoding two drivers for the same hardware.

Point 1: You can't perform resource management on the System RAM since
they're already claimed.
Point 2: You can't perform resource management on bits in a control
register that performs many other random functions; resource management
is byte based not bit based.

--
Russell King ([email protected]) The developer of ARM Linux
http://www.arm.linux.org.uk/personal/aboutme.html

2002-04-07 14:52:24

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: Linux 2.5.8-pre2

On Sun, 7 Apr 2002, Russell King wrote:
> On Sun, Apr 07, 2002 at 12:42:45PM +0200, Geert Uytterhoeven wrote:
> > On Sun, 7 Apr 2002, Russell King wrote:
> > > (Oh, and a bugbear - people go running around adding checks for the
> > > return value of request_region and friends on embedded devices where
> > > there can't be the possibility of a clash waste memory needlessly.)
> >
> > Perhaps you want to modularize the driver later? Resource management also
> > prevents you from insmoding two drivers for the same hardware.
>
> Point 1: You can't perform resource management on the System RAM since
> they're already claimed.

Hmmm... Just guessing: perhaps because you created the System RAM resource
using request_mem_region() instead of request_resource()?

On Amiga the Chip RAM allocator uses the resource management system, and both
the whole bunch of Chip RAM (parent) and all allocated blocks (children) show
up in /proc/iomem.

> Point 2: You can't perform resource management on bits in a control
> register that performs many other random functions; resource management
> is byte based not bit based.

That's indeed more nasty.

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2002-04-08 07:30:00

by Andi Kleen

[permalink] [raw]
Subject: Re: Linux 2.5.8-pre2

Linus Torvalds <[email protected]> writes:
> +++ linux/include/asm-arm/leds.h Wed Feb 13 13:01:31 2002
> <[email protected]> (02/04/04 1.539)
> [PATCH] increase number of transaction locks in JFS txnmgr
>
> Original fix from Andi Kleen

The patch was from Steve Best actually. I just forwarded it.

-Andi

2002-04-09 09:08:22

by Martin Dalecki

[permalink] [raw]
Subject: [PATCH] 2.5.8-pre2 IDE 29b

diff -urN linux-2.5.8-pre2/MAINTAINERS linux/MAINTAINERS
--- linux-2.5.8-pre2/MAINTAINERS Mon Apr 8 21:12:44 2002
+++ linux/MAINTAINERS Mon Apr 8 16:29:16 2002
@@ -1386,6 +1386,13 @@
M: [email protected]
S: Maintained

+SIS 5513 IDE CONTROLLER DRIVER
+P: Lionel Bouton
+M: [email protected]
+W: http://inet6.dyn.dhs.org/sponsoring/sis5513/index.html
+W: http://gyver.homeip.net/sis5513/index.html
+S: Maintained
+
SIS 900/7016 FAST ETHERNET DRIVER
P: Ollie Lho
M: [email protected]
diff -urN linux-2.5.8-pre2/drivers/ide/ali14xx.c linux/drivers/ide/ali14xx.c
--- linux-2.5.8-pre2/drivers/ide/ali14xx.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/ali14xx.c Mon Apr 8 16:29:16 2002
@@ -212,9 +212,8 @@
ide_hwifs[1].chipset = ide_ali14xx;
ide_hwifs[0].tuneproc = &ali14xx_tune_drive;
ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
- ide_hwifs[0].mate = &ide_hwifs[1];
- ide_hwifs[1].mate = &ide_hwifs[0];
- ide_hwifs[1].unit = 1;
+ ide_hwifs[0].unit = ATA_PRIMARY;
+ ide_hwifs[1].unit = ATA_SECONDARY;

/* initialize controller registers */
if (!initRegisters()) {
diff -urN linux-2.5.8-pre2/drivers/ide/cmd640.c linux/drivers/ide/cmd640.c
--- linux-2.5.8-pre2/drivers/ide/cmd640.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/cmd640.c Mon Apr 8 16:29:16 2002
@@ -689,7 +689,7 @@
/*
* Probe for a cmd640 chipset, and initialize it if found. Called from ide.c
*/
-int __init ide_probe_for_cmd640x (void)
+int __init ide_probe_for_cmd640x(void)
{
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
int second_port_toggled = 0;
@@ -793,9 +793,7 @@
cmd_hwif0->serialized = 1;
cmd_hwif1->serialized = 1;
cmd_hwif1->chipset = ide_cmd640;
- cmd_hwif0->mate = cmd_hwif1;
- cmd_hwif1->mate = cmd_hwif0;
- cmd_hwif1->unit = 1;
+ cmd_hwif1->unit = ATA_SECONDARY;
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
cmd_hwif1->tuneproc = &cmd640_tune_drive;
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
@@ -811,8 +809,8 @@
ide_drive_t *drive = cmd_drives[index];
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
if (drive->autotune || ((index > 1) && second_port_toggled)) {
- /*
- * Reset timing to the slowest speed and turn off prefetch.
+ /*
+ * Reset timing to the slowest speed and turn off prefetch.
* This way, the drive identify code has a better chance.
*/
setup_counts [index] = 4; /* max possible */
diff -urN linux-2.5.8-pre2/drivers/ide/cs5530.c linux/drivers/ide/cs5530.c
--- linux-2.5.8-pre2/drivers/ide/cs5530.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/cs5530.c Mon Apr 8 16:29:16 2002
@@ -346,8 +346,7 @@
*/
void __init ide_init_cs5530(struct ata_channel *hwif)
{
- if (hwif->mate)
- hwif->serialized = hwif->mate->serialized = 1;
+ hwif->serialized = 1;
if (!hwif->dma_base) {
hwif->autodma = 0;
} else {
diff -urN linux-2.5.8-pre2/drivers/ide/dtc2278.c linux/drivers/ide/dtc2278.c
--- linux-2.5.8-pre2/drivers/ide/dtc2278.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/dtc2278.c Mon Apr 8 16:29:16 2002
@@ -124,7 +124,6 @@
ide_hwifs[0].drives[1].no_unmask = 1;
ide_hwifs[1].drives[0].no_unmask = 1;
ide_hwifs[1].drives[1].no_unmask = 1;
- ide_hwifs[0].mate = &ide_hwifs[1];
- ide_hwifs[1].mate = &ide_hwifs[0];
- ide_hwifs[1].unit = 1;
+ ide_hwifs[0].unit = ATA_PRIMARY;
+ ide_hwifs[1].unit = ATA_SECONDARY;
}
diff -urN linux-2.5.8-pre2/drivers/ide/hpt366.c linux/drivers/ide/hpt366.c
--- linux-2.5.8-pre2/drivers/ide/hpt366.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/hpt366.c Mon Apr 8 19:07:00 2002
@@ -1125,13 +1125,13 @@

if (n_hpt_devs < HPT366_MAX_DEVS)
hpt_devs[n_hpt_devs++] = dev;
-
+
#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
if (!hpt366_proc) {
hpt366_proc = 1;
hpt366_display_info = &hpt366_get_info;
}
-#endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */
+#endif

return dev->irq;
}
@@ -1146,7 +1146,7 @@
printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
ata66, (ata66 & regmask) ? "33" : "66",
PCI_FUNC(hwif->pci_dev->devfn));
-#endif /* DEBUG */
+#endif
return ((ata66 & regmask) ? 0 : 1);
}

diff -urN linux-2.5.8-pre2/drivers/ide/ht6560b.c linux/drivers/ide/ht6560b.c
--- linux-2.5.8-pre2/drivers/ide/ht6560b.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/ht6560b.c Mon Apr 8 16:29:16 2002
@@ -319,10 +319,9 @@
ide_hwifs[1].tuneproc = &tune_ht6560b;
ide_hwifs[0].serialized = 1; /* is this needed? */
ide_hwifs[1].serialized = 1; /* is this needed? */
- ide_hwifs[0].mate = &ide_hwifs[1];
- ide_hwifs[1].mate = &ide_hwifs[0];
- ide_hwifs[1].unit = 1;
-
+ ide_hwifs[0].unit = ATA_PRIMARY;
+ ide_hwifs[1].unit = ATA_SECONDARY;
+
/*
* Setting default configurations for drives
*/
diff -urN linux-2.5.8-pre2/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c
--- linux-2.5.8-pre2/drivers/ide/ide-dma.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/ide-dma.c Mon Apr 8 18:11:42 2002
@@ -421,7 +421,7 @@
return 0;
}

-static int report_drive_dmaing (ide_drive_t *drive)
+int report_drive_dmaing (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;

@@ -562,8 +562,8 @@
switch (func) {
case ide_dma_off:
printk("%s: DMA disabled\n", drive->name);
- set_high = 0;
case ide_dma_off_quietly:
+ set_high = 0;
outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
case ide_dma_on:
ide_toggle_bounce(drive, set_high);
diff -urN linux-2.5.8-pre2/drivers/ide/ide-pci.c linux/drivers/ide/ide-pci.c
--- linux-2.5.8-pre2/drivers/ide/ide-pci.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/ide-pci.c Mon Apr 8 21:02:52 2002
@@ -182,7 +182,7 @@
unsigned short device;
unsigned int (*init_chipset)(struct pci_dev *dev);
unsigned int (*ata66_check)(struct ata_channel *hwif);
- void (*init_hwif)(struct ata_channel *hwif);
+ void (*init_channel)(struct ata_channel *hwif);
void (*dma_init)(struct ata_channel *hwif, unsigned long dmabase);
ide_pci_enablebit_t enablebits[2];
unsigned int bootable;
@@ -436,24 +436,21 @@
unsigned long dma_base = 0;
struct pci_dev *dev = hwif->pci_dev;

- /*
- * If we are on the second channel, the dma base address will be one
- * entry away from the primary interface.
- */
-
- if (hwif->mate && hwif->mate->dma_base)
- dma_base = hwif->mate->dma_base - (hwif->unit ? 0 : 8);
- else
- dma_base = pci_resource_start(dev, 4);
-
+ dma_base = pci_resource_start(dev, 4);
if (!dma_base)
return 0;

- if (extra) /* PDC20246, PDC20262, HPT343, & HPT366 */
+ /* PDC20246, PDC20262, HPT343, & HPT366 */
+ if (extra) {
request_region(dma_base + 16, extra, name);
+ hwif->dma_extra = extra;
+ }

- dma_base += hwif->unit ? 8 : 0;
- hwif->dma_extra = extra;
+ /* If we are on the second channel, the dma base address will be one
+ * entry away from the primary interface.
+ */
+ if (hwif->unit == ATA_SECONDARY)
+ dma_base += 8;

if ((dev->vendor == PCI_VENDOR_ID_AL && dev->device == PCI_DEVICE_ID_AL_M5219) ||
(dev->vendor == PCI_VENDOR_ID_AMD && dev->device == PCI_DEVICE_ID_AMD_VIPER_7409) ||
@@ -463,8 +460,7 @@
printk(KERN_INFO "%s: simplex device: DMA forced\n", name);
} else {

- /*
- * If the device claims "simplex" DMA, this means only one of
+ /* If the device claims "simplex" DMA, this means only one of
* the two interfaces can be trusted with DMA at any point in
* time. So we should enable DMA only on one of the two
* interfaces.
@@ -472,7 +468,7 @@

if ((inb(dma_base + 2) & 0x80)) {
if ((!hwif->drives[0].present && !hwif->drives[1].present) ||
- (hwif->mate && hwif->mate->dma_base)) {
+ hwif->unit == ATA_SECONDARY) {
printk("%s: simplex device: DMA disabled\n", name);
dma_base = 0;
}
@@ -489,8 +485,9 @@
ide_pci_device_t *d,
int port,
u8 class_rev,
- int pciirq, struct ata_channel **mate,
- int autodma, unsigned short *pcicmd)
+ int pciirq,
+ int autodma,
+ unsigned short *pcicmd)
{
unsigned long dma_base;

@@ -503,8 +500,13 @@
if (!((d->flags & ATA_F_DMA) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))))
return;

- dma_base = get_dma_base(hwif, (!*mate && d->extra) ? d->extra : 0, dev->name);
- if (dma_base && !(*pcicmd & PCI_COMMAND_MASTER)) {
+ dma_base = get_dma_base(hwif, ((port == ATA_PRIMARY) && d->extra) ? d->extra : 0, dev->name);
+ if (!dma_base) {
+ printk("%s: %s Bus-Master DMA was disabled by BIOS\n", hwif->name, dev->name);
+
+ return;
+ }
+ if (!(*pcicmd & PCI_COMMAND_MASTER)) {

/*
* Set up BM-DMA capability (PnP BIOS should have done this already)
@@ -517,13 +519,10 @@
dma_base = 0;
}
}
- if (dma_base) {
- if (d->dma_init)
- d->dma_init(hwif, dma_base);
- else
- ide_setup_dma(hwif, dma_base, 8);
- } else
- printk("%s: %s Bus-Master DMA was disabled by BIOS\n", hwif->name, dev->name);
+ if (d->dma_init)
+ d->dma_init(hwif, dma_base);
+ else
+ ide_setup_dma(hwif, dma_base, 8);
}
#endif

@@ -537,17 +536,16 @@
int port,
u8 class_rev,
int pciirq,
- struct ata_channel **mate,
int autodma,
unsigned short *pcicmd)
{
unsigned long base = 0;
unsigned long ctl = 0;
ide_pci_enablebit_t *e = &(d->enablebits[port]);
- struct ata_channel *hwif;
+ struct ata_channel *ch;

u8 tmp;
- if (port == 1) {
+ if (port == ATA_SECONDARY) {

/* If this is a Promise FakeRaid controller, the 2nd controller
* will be marked as disabled while it is actually there and
@@ -569,7 +567,7 @@

/* Nothing to be done for the second port.
*/
- if (port == 1) {
+ if (port == ATA_SECONDARY) {
if ((d->flags & ATA_F_HPTHACK) && (class_rev < 0x03))
return 0;
}
@@ -599,57 +597,50 @@
if (!base)
base = port ? 0x170 : 0x1f0;

- if ((hwif = lookup_hwif(base, d->bootable, dev->name)) == NULL)
+ if ((ch = lookup_hwif(base, d->bootable, dev->name)) == NULL)
return -ENOMEM; /* no room in ide_hwifs[] */

- if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
- ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL);
- memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
- hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
- }
-
- hwif->chipset = ide_pci;
- hwif->pci_dev = dev;
- hwif->unit = port;
- if (!hwif->irq)
- hwif->irq = pciirq;
-
- /* Setup the mate interface if we have two channels.
- */
- if (*mate) {
- hwif->mate = *mate;
- (*mate)->mate = hwif;
- if (d->flags & ATA_F_SER) {
- hwif->serialized = 1;
- (*mate)->serialized = 1;
- }
- }
+ if (ch->io_ports[IDE_DATA_OFFSET] != base) {
+ ide_init_hwif_ports(&ch->hw, base, (ctl | 2), NULL);
+ memcpy(ch->io_ports, ch->hw.io_ports, sizeof(ch->io_ports));
+ ch->noprobe = !ch->io_ports[IDE_DATA_OFFSET];
+ }
+
+ ch->chipset = ide_pci;
+ ch->pci_dev = dev;
+ ch->unit = port;
+ if (!ch->irq)
+ ch->irq = pciirq;
+
+ /* Serialize the interfaces if requested by configuration information.
+ */
+ if (d->flags & ATA_F_SER)
+ ch->serialized = 1;

/* Cross wired IRQ lines on UMC chips and no DMA transfers.*/
if (d->flags & ATA_F_FIXIRQ) {
- hwif->irq = port ? 15 : 14;
+ ch->irq = port ? 15 : 14;
goto no_dma;
}
if (d->flags & ATA_F_NODMA)
goto no_dma;

/* Check whatever this interface is UDMA4 mode capable. */
- if (hwif->udma_four) {
+ if (ch->udma_four) {
printk("%s: warning: ATA-66/100 forced bit set!\n", dev->name);
} else {
if (d->ata66_check)
- hwif->udma_four = d->ata66_check(hwif);
+ ch->udma_four = d->ata66_check(ch);
}

#ifdef CONFIG_BLK_DEV_IDEDMA
- setup_channel_dma(hwif, dev, d, port, class_rev, pciirq, mate, autodma, pcicmd);
+ setup_channel_dma(ch, dev, d, port, class_rev, pciirq, autodma, pcicmd);
#endif

no_dma:
- if (d->init_hwif) /* Call chipset-specific routine for each enabled hwif */
- d->init_hwif(hwif);
-
- *mate = hwif;
+ /* Call chipset-specific routine for each enabled channel. */
+ if (d->init_channel)
+ d->init_channel(ch);

return 0;
}
@@ -671,7 +662,6 @@
int pciirq = 0;
unsigned short pcicmd = 0;
unsigned short tried_config = 0;
- struct ata_channel *mate = NULL;
unsigned int class_rev;

#ifdef CONFIG_IDEDMA_AUTO
@@ -679,9 +669,9 @@
autodma = 1;
#endif

- if (d->init_hwif == IDE_NO_DRIVER) {
+ if (d->init_channel == IDE_NO_DRIVER) {
printk(KERN_WARNING "%s: detected chipset, but driver not compiled in!\n", dev->name);
- d->init_hwif = NULL;
+ d->init_channel = NULL;
}

if (pci_enable_device(dev)) {
@@ -779,8 +769,8 @@
/*
* Set up IDE chanells. First the primary, then the secondary.
*/
- setup_host_channel(dev, d, 0, class_rev, pciirq, &mate, autodma, &pcicmd);
- setup_host_channel(dev, d, 1, class_rev, pciirq, &mate, autodma, &pcicmd);
+ setup_host_channel(dev, d, ATA_PRIMARY, class_rev, pciirq, autodma, &pcicmd);
+ setup_host_channel(dev, d, ATA_SECONDARY, class_rev, pciirq, autodma, &pcicmd);
}

static void __init pdc20270_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
@@ -856,12 +846,6 @@
if (hpt363_shared_pin && hpt363_shared_irq) {
d->bootable = ON_BOARD;
printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", dev->name, pin1, pin2);
-#if 0
- /* I forgot why I did this once, but it fixed something. */
- pci_write_config_byte(dev2, PCI_INTERRUPT_PIN, dev->irq);
- printk("PCI: %s: Fixing interrupt %d pin %d to ZERO \n", d->name, dev2->irq, pin2);
- pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, 0);
-#endif
}
break;
}
@@ -894,7 +878,7 @@
while (d->vendor && !(d->vendor == vendor && d->device == device))
++d;

- if (d->init_hwif == ATA_PCI_IGNORE)
+ if (d->init_channel == ATA_PCI_IGNORE)
printk("%s: has been ignored by PCI bus scan\n", dev->name);
else if ((d->vendor == PCI_VENDOR_ID_OPTI && d->device == PCI_DEVICE_ID_OPTI_82C558) && !(PCI_FUNC(dev->devfn) & 1))
return;
diff -urN linux-2.5.8-pre2/drivers/ide/ide-pmac.c linux/drivers/ide/ide-pmac.c
--- linux-2.5.8-pre2/drivers/ide/ide-pmac.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/ide-pmac.c Mon Apr 8 18:11:42 2002
@@ -15,6 +15,16 @@
* Some code taken from drivers/ide/ide-dma.c:
*
* Copyright (c) 1995-1998 Mark Lord
+ *
+ * TODO:
+ *
+ * - Find a way to duplicate less code with ide-dma and use the
+ * dma fileds in the hwif structure instead of our own
+ * - Fix check_disk_change() call
+ * - Make module-able (includes setting ppc_md. hooks from within
+ * this file and not from arch code, and handling module deps with
+ * mediabay (by having both modules do dynamic lookup of each other
+ * symbols or by storing hooks at arch level).
*
*/
#include <linux/config.h>
@@ -24,26 +34,30 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/ide.h>
+#include <linux/pci.h>

#include <asm/prom.h>
#include <asm/io.h>
#include <asm/dbdma.h>
#include <asm/ide.h>
#include <asm/mediabay.h>
-#include <asm/feature.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/sections.h>
+#include <asm/irq.h>
#ifdef CONFIG_PMAC_PBOOK
#include <linux/adb.h>
#include <linux/pmu.h>
-#include <asm/irq.h>
#endif
#include "ata-timing.h"

extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
+extern spinlock_t ide_lock;

#undef IDE_PMAC_DEBUG

-#define IDE_SYSCLK_NS 30
-#define IDE_SYSCLK_ULTRA_PS 0x1d4c /* (15 * 1000 / 2)*/
+#define DMA_WAIT_TIMEOUT 500

struct pmac_ide_hwif {
ide_ioreg_t regbase;
@@ -53,11 +67,20 @@
struct device_node* node;
u32 timings[2];
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+ /* Those fields are duplicating what is in hwif. We currently
+ * can't use the hwif ones because of some assumptions that are
+ * beeing done by the generic code about the kind of dma controller
+ * and format of the dma table. This will have to be fixed though.
+ */
volatile struct dbdma_regs* dma_regs;
- struct dbdma_cmd* dma_table;
-#endif
+ struct dbdma_cmd* dma_table_cpu;
+ dma_addr_t dma_table_dma;
+ struct scatterlist* sg_table;
+ int sg_nents;
+ int sg_dma_direction;
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */

-} pmac_ide[MAX_HWIFS];
+} pmac_ide[MAX_HWIFS] __pmacdata;

static int pmac_ide_count;

@@ -65,36 +88,160 @@
controller_ohare, /* OHare based */
controller_heathrow, /* Heathrow/Paddington */
controller_kl_ata3, /* KeyLargo ATA-3 */
- controller_kl_ata4 /* KeyLargo ATA-4 */
+ controller_kl_ata4, /* KeyLargo ATA-4 */
+ controller_kl_ata4_80 /* KeyLargo ATA-4 with 80 conductor cable */
};

+/*
+ * Extra registers, both 32-bit little-endian
+ */
+#define IDE_TIMING_CONFIG 0x200
+#define IDE_INTERRUPT 0x300
+
+/*
+ * Timing configuration register definitions
+ */
+
+/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
+#define SYSCLK_TICKS(t) (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
+#define SYSCLK_TICKS_66(t) (((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS)
+#define IDE_SYSCLK_NS 30 /* 33Mhz cell */
+#define IDE_SYSCLK_66_NS 15 /* 66Mhz cell */
+
+/* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on
+ * 40 connector cable and to 4 on 80 connector one.
+ * Clock unit is 15ns (66Mhz)
+ *
+ * 3 Values can be programmed:
+ * - Write data setup, which appears to match the cycle time. They
+ * also call it DIOW setup.
+ * - Ready to pause time (from spec)
+ * - Address setup. That one is weird. I don't see where exactly
+ * it fits in UDMA cycles, I got it's name from an obscure piece
+ * of commented out code in Darwin. They leave it to 0, we do as
+ * well, despite a comment that would lead to think it has a
+ * min value of 45ns.
+ * Apple also add 60ns to the write data setup (or cycle time ?) on
+ * reads. I can't explain that, I tried it and it broke everything
+ * here.
+ */
+#define TR_66_UDMA_MASK 0xfff00000
+#define TR_66_UDMA_EN 0x00100000 /* Enable Ultra mode for DMA */
+#define TR_66_UDMA_ADDRSETUP_MASK 0xe0000000 /* Address setup */
+#define TR_66_UDMA_ADDRSETUP_SHIFT 29
+#define TR_66_UDMA_RDY2PAUS_MASK 0x1e000000 /* Ready 2 pause time */
+#define TR_66_UDMA_RDY2PAUS_SHIFT 25
+#define TR_66_UDMA_WRDATASETUP_MASK 0x01e00000 /* Write data setup time */
+#define TR_66_UDMA_WRDATASETUP_SHIFT 21
+#define TR_66_MDMA_MASK 0x000ffc00
+#define TR_66_MDMA_RECOVERY_MASK 0x000f8000
+#define TR_66_MDMA_RECOVERY_SHIFT 15
+#define TR_66_MDMA_ACCESS_MASK 0x00007c00
+#define TR_66_MDMA_ACCESS_SHIFT 10
+#define TR_66_PIO_MASK 0x000003ff
+#define TR_66_PIO_RECOVERY_MASK 0x000003e0
+#define TR_66_PIO_RECOVERY_SHIFT 5
+#define TR_66_PIO_ACCESS_MASK 0x0000001f
+#define TR_66_PIO_ACCESS_SHIFT 0
+
+/* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo
+ * Can do pio & mdma modes, clock unit is 30ns (33Mhz)
+ *
+ * The access time and recovery time can be programmed. Some older
+ * Darwin code base limit OHare to 150ns cycle time. I decided to do
+ * the same here fore safety against broken old hardware ;)
+ * The HalfTick bit, when set, adds half a clock (15ns) to the access
+ * time and removes one from recovery. It's not supported on KeyLargo
+ * implementation afaik. The E bit appears to be set for PIO mode 0 and
+ * is used to reach long timings used in this mode.
+ */
+#define TR_33_MDMA_MASK 0x003ff800
+#define TR_33_MDMA_RECOVERY_MASK 0x001f0000
+#define TR_33_MDMA_RECOVERY_SHIFT 16
+#define TR_33_MDMA_ACCESS_MASK 0x0000f800
+#define TR_33_MDMA_ACCESS_SHIFT 11
+#define TR_33_MDMA_HALFTICK 0x00200000
+#define TR_33_PIO_MASK 0x000007ff
+#define TR_33_PIO_E 0x00000400
+#define TR_33_PIO_RECOVERY_MASK 0x000003e0
+#define TR_33_PIO_RECOVERY_SHIFT 5
+#define TR_33_PIO_ACCESS_MASK 0x0000001f
+#define TR_33_PIO_ACCESS_SHIFT 0
+
+/*
+ * Interrupt register definitions
+ */
+#define IDE_INTR_DMA 0x80000000
+#define IDE_INTR_DEVICE 0x40000000

#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC

# define BAD_DMA_DRIVE 0
# define GOOD_DMA_DRIVE 1

-typedef struct {
+/* Rounded Multiword DMA timings
+ *
+ * I gave up finding a generic formula for all controller
+ * types and instead, built tables based on timing values
+ * used by Apple in Darwin's implementation.
+ */
+struct mdma_timings_t {
int accessTime;
+ int recoveryTime;
int cycleTime;
-} pmac_ide_timing;
+};

-/* Multiword DMA timings */
-static pmac_ide_timing mdma_timings[] =
+struct mdma_timings_t mdma_timings_33[] __pmacdata =
{
- { 215, 480 }, /* Mode 0 */
- { 80, 150 }, /* 1 */
- { 70, 120 } /* 2 */
+ { 240, 240, 480 },
+ { 180, 180, 360 },
+ { 135, 135, 270 },
+ { 120, 120, 240 },
+ { 105, 105, 210 },
+ { 90, 90, 180 },
+ { 75, 75, 150 },
+ { 75, 45, 120 },
+ { 0, 0, 0 }
};

-/* Ultra DMA timings (for use when I know how to calculate them */
-static pmac_ide_timing udma_timings[] =
+struct mdma_timings_t mdma_timings_33k[] __pmacdata =
{
- { 0, 114 }, /* Mode 0 */
- { 0, 75 }, /* 1 */
- { 0, 55 }, /* 2 */
- { 100, 45 }, /* 3 */
- { 100, 25 } /* 4 */
+ { 240, 240, 480 },
+ { 180, 180, 360 },
+ { 150, 150, 300 },
+ { 120, 120, 240 },
+ { 90, 120, 210 },
+ { 90, 90, 180 },
+ { 90, 60, 150 },
+ { 90, 30, 120 },
+ { 0, 0, 0 }
+};
+
+struct mdma_timings_t mdma_timings_66[] __pmacdata =
+{
+ { 240, 240, 480 },
+ { 180, 180, 360 },
+ { 135, 135, 270 },
+ { 120, 120, 240 },
+ { 105, 105, 210 },
+ { 90, 90, 180 },
+ { 90, 75, 165 },
+ { 75, 45, 120 },
+ { 0, 0, 0 }
+};
+
+/* Ultra DMA timings (rounded) */
+struct {
+ int addrSetup; /* ??? */
+ int rdy2pause;
+ int wrDataSetup;
+} udma_timings[] __pmacdata =
+{
+ { 0, 180, 120 }, /* Mode 0 */
+ { 0, 150, 90 }, /* 1 */
+ { 0, 120, 60 }, /* 2 */
+ { 0, 90, 45 }, /* 3 */
+ { 0, 90, 30 } /* 4 */
};

/* allow up to 256 DBDMA commands per xfer */
@@ -124,7 +271,7 @@
};
#endif /* CONFIG_PMAC_PBOOK */

-static int
+static int __pmac
pmac_ide_find(ide_drive_t *drive)
{
struct ata_channel *hwif = drive->channel;
@@ -143,7 +290,8 @@
* N.B. this can't be an initfunc, because the media-bay task can
* call ide_[un]register at any time.
*/
-void pmac_ide_init_hwif_ports(hw_regs_t *hw,
+void __pmac
+pmac_ide_init_hwif_ports(hw_regs_t *hw,
ide_ioreg_t data_port, ide_ioreg_t ctrl_port,
int *irq)
{
@@ -174,7 +322,7 @@
ide_hwifs[ix].tuneproc = pmac_ide_tuneproc;
ide_hwifs[ix].selectproc = pmac_ide_selectproc;
ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset;
- if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table) {
+ if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table_cpu) {
ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
if (!noautodma)
@@ -201,24 +349,33 @@
/* Setup timings for the selected drive (master/slave). I still need to verify if this
* is enough, I beleive selectproc will be called whenever an IDE command is started,
* but... */
-static void
+static void __pmac
pmac_ide_selectproc(ide_drive_t *drive)
{
int i = pmac_ide_find(drive);
if (i < 0)
return;
-
- if (drive->select.all & 0x10)
- out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), pmac_ide[i].timings[1]);
+
+ if (drive->select.b.unit & 0x01)
+ out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
+ pmac_ide[i].timings[1]);
else
- out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), pmac_ide[i].timings[0]);
+ out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
+ pmac_ide[i].timings[0]);
+ (void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
}

-/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
-#define SYSCLK_TICKS(t) (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
-#define SYSCLK_TICKS_UDMA(t) (((t) + IDE_SYSCLK_ULTRA_PS - 1) / IDE_SYSCLK_ULTRA_PS)

-static __inline__ int
+/* Note: We don't use the generic routine here because for some
+ * yet unexplained reasons, it cause some media-bay CD-ROMs to
+ * lockup the bus. Strangely, this new version of the code is
+ * almost identical to the generic one and works, I've not yet
+ * managed to figure out what bit is causing the lockup in the
+ * generic code, possibly a timing issue...
+ *
+ * --BenH
+ */
+static int __pmac
wait_for_ready(ide_drive_t *drive)
{
/* Timeout bumped for some powerbooks */
@@ -244,57 +401,80 @@
return 0;
}

-/* Note: We don't use the generic routine here because some of Apple's
- * controller seem to be very sensitive about how things are done.
- * We should probably set the NIEN bit, but that's an example of thing
- * that can cause the controller to hang under some circumstances when
- * done on the media-bay CD-ROM during boot. We do get occasional
- * spurrious interrupts because of that.
- * --BenH
- */
-static int
+static int __pmac
pmac_ide_do_setfeature(ide_drive_t *drive, byte command)
{
- unsigned long flags;
int result = 1;
-
- save_flags(flags);
- cli();
+ unsigned long flags;
+ struct ata_channel *hwif = HWIF(drive);
+
+ disable_irq(hwif->irq); /* disable_irq_nosync ?? */
udelay(1);
SELECT_DRIVE(drive->channel, drive);
SELECT_MASK(drive->channel, drive, 0);
udelay(1);
+ (void)GET_STAT(); /* Get rid of pending error state */
if(wait_for_ready(drive)) {
printk(KERN_ERR "pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n");
goto out;
}
- OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
+ udelay(10);
+ OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
OUT_BYTE(command, IDE_NSECTOR_REG);
+ OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
udelay(1);
+ __save_flags(flags); /* local CPU only */
+ ide__sti(); /* local CPU only -- for jiffies */
result = wait_for_ready(drive);
+ __restore_flags(flags); /* local CPU only */
+ OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
if (result)
printk(KERN_ERR "pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n");
out:
- restore_flags(flags);
+ SELECT_MASK(HWIF(drive), drive, 0);
+ if (result == 0) {
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_1word &= ~0x0F00;
+ switch(command) {
+ case XFER_UDMA_7: drive->id->dma_ultra |= 0x8080; break;
+ case XFER_UDMA_6: drive->id->dma_ultra |= 0x4040; break;
+ case XFER_UDMA_5: drive->id->dma_ultra |= 0x2020; break;
+ case XFER_UDMA_4: drive->id->dma_ultra |= 0x1010; break;
+ case XFER_UDMA_3: drive->id->dma_ultra |= 0x0808; break;
+ case XFER_UDMA_2: drive->id->dma_ultra |= 0x0404; break;
+ case XFER_UDMA_1: drive->id->dma_ultra |= 0x0202; break;
+ case XFER_UDMA_0: drive->id->dma_ultra |= 0x0101; break;
+ case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
+ case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
+ case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
+ case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
+ case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
+ case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
+ default: break;
+ }
+ }
+ enable_irq(hwif->irq);

return result;
}

/* Calculate PIO timings */
-static void
+static void __pmac
pmac_ide_tuneproc(ide_drive_t *drive, byte pio)
{
struct ata_timing *t;
int i;
u32 *timings;
- int accessTicks, recTicks;
+ unsigned accessTicks, recTicks;
+ unsigned accessTime, recTime;

i = pmac_ide_find(drive);
if (i < 0)
return;

- if (pio = 255)
+ if (pio == 255)
pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO);
else
pio = XFER_PIO_0 + min_t(byte, pio, 4);
@@ -302,27 +482,40 @@
t = ata_timing_data(pio);

accessTicks = SYSCLK_TICKS(t->active);
- if (drive->select.all & 0x10)
- timings = &pmac_ide[i].timings[1];
- else
- timings = &pmac_ide[i].timings[0];
-
- if (pmac_ide[i].kind == controller_kl_ata4) {
- /* The "ata-4" IDE controller of Core99 machines */
- accessTicks = SYSCLK_TICKS_UDMA(t->active * 1000);
- recTicks = SYSCLK_TICKS_UDMA(t->cycle * 1000) - accessTicks;
+ timings = &pmac_ide[i].timings[drive->select.b.unit & 0x01];

- *timings = ((*timings) & 0x1FFFFFC00) | accessTicks | (recTicks << 5);
+ recTime = t->cycle - t->active - t->setup;
+ recTime = max(recTime, 150U);
+ accessTime = t->active;
+ accessTime = max(accessTime, 150U);
+ if (pmac_ide[i].kind == controller_kl_ata4 ||
+ pmac_ide[i].kind == controller_kl_ata4_80) {
+ /* 66Mhz cell */
+ accessTicks = SYSCLK_TICKS_66(accessTime);
+ accessTicks = min(accessTicks, 0x1fU);
+ recTicks = SYSCLK_TICKS_66(recTime);
+ recTicks = min(recTicks, 0x1fU);
+ *timings = ((*timings) & ~TR_66_PIO_MASK) |
+ (accessTicks << TR_66_PIO_ACCESS_SHIFT) |
+ (recTicks << TR_66_PIO_RECOVERY_SHIFT);
} else {
- /* The old "ata-3" IDE controller */
- accessTicks = SYSCLK_TICKS(t->active);
- if (accessTicks < 4)
- accessTicks = 4;
- recTicks = SYSCLK_TICKS(t->cycle) - accessTicks - 4;
- if (recTicks < 1)
- recTicks = 1;
-
- *timings = ((*timings) & 0xFFFFFF800) | accessTicks | (recTicks << 5);
+ /* 33Mhz cell */
+ int ebit = 0;
+ accessTicks = SYSCLK_TICKS(accessTime);
+ accessTicks = min(accessTicks, 0x1fU);
+ accessTicks = max(accessTicks, 4U);
+ recTicks = SYSCLK_TICKS(recTime);
+ recTicks = min(recTicks, 0x1fU);
+ recTicks = max(recTicks, 5U) - 4;
+ if (recTicks > 9) {
+ recTicks--; /* guess, but it's only for PIO0, so... */
+ ebit = 1;
+ }
+ *timings = ((*timings) & ~TR_33_PIO_MASK) |
+ (accessTicks << TR_33_PIO_ACCESS_SHIFT) |
+ (recTicks << TR_33_PIO_RECOVERY_SHIFT);
+ if (ebit)
+ *timings |= TR_33_PIO_E;
}

#ifdef IDE_PMAC_DEBUG
@@ -335,70 +528,134 @@
}

#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-static int
-set_timings_udma(int intf, u32 *timings, byte speed)
+static int __pmac
+set_timings_udma(u32 *timings, byte speed)
{
- int cycleTime, accessTime;
- int rdyToPauseTicks, cycleTicks;
-
- if (pmac_ide[intf].kind != controller_kl_ata4)
- return 1;
-
- cycleTime = udma_timings[speed & 0xf].cycleTime;
- accessTime = udma_timings[speed & 0xf].accessTime;
+ unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks;

- rdyToPauseTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);
- cycleTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000);
-
- *timings = ((*timings) & 0xe00fffff) |
- ((cycleTicks << 1) | (rdyToPauseTicks << 5) | 1) << 20;
+ rdyToPauseTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].rdy2pause);
+ wrDataSetupTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].wrDataSetup);
+ addrTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].addrSetup);
+
+ *timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) |
+ (wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) |
+ (rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) |
+ (addrTicks <<TR_66_UDMA_ADDRSETUP_SHIFT) |
+ TR_66_UDMA_EN;
+#ifdef IDE_PMAC_DEBUG
+ printk(KERN_ERR "ide_pmac: Set UDMA timing for mode %d, reg: 0x%08x\n",
+ speed & 0xf, *timings);
+#endif

return 0;
}

-static int
-set_timings_mdma(int intf, u32 *timings, byte speed)
+static int __pmac
+set_timings_mdma(int intf_type, u32 *timings, byte speed, int drive_cycle_time)
{
- int cycleTime, accessTime;
- int accessTicks, recTicks;
+ int cycleTime, accessTime, recTime;
+ unsigned accessTicks, recTicks;
+ struct mdma_timings_t* tm;
+ int i;

- /* Calculate accesstime and cycle time */
- cycleTime = mdma_timings[speed & 0xf].cycleTime;
- accessTime = mdma_timings[speed & 0xf].accessTime;
- if ((pmac_ide[intf].kind == controller_ohare) && (cycleTime < 150))
+ /* Get default cycle time for mode */
+ switch(speed & 0xf) {
+ case 0: cycleTime = 480; break;
+ case 1: cycleTime = 150; break;
+ case 2: cycleTime = 120; break;
+ default:
+ return -1;
+ }
+ /* Adjust for drive */
+ if (drive_cycle_time && drive_cycle_time > cycleTime)
+ cycleTime = drive_cycle_time;
+ /* OHare limits according to some old Apple sources */
+ if ((intf_type == controller_ohare) && (cycleTime < 150))
cycleTime = 150;
+ /* Get the proper timing array for this controller */
+ switch(intf_type) {
+ case controller_kl_ata4:
+ case controller_kl_ata4_80:
+ tm = mdma_timings_66;
+ break;
+ case controller_kl_ata3:
+ tm = mdma_timings_33k;
+ break;
+ default:
+ tm = mdma_timings_33;
+ break;
+ }
+ /* Lookup matching access & recovery times */
+ i = -1;
+ for (;;) {
+ if (tm[i+1].cycleTime < cycleTime)
+ break;
+ i++;
+ }
+ if (i < 0)
+ return -1;
+ cycleTime = tm[i].cycleTime;
+ accessTime = tm[i].accessTime;
+ recTime = tm[i].recoveryTime;

- /* For ata-4 controller */
- if (pmac_ide[intf].kind == controller_kl_ata4) {
- accessTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);
- recTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000) - accessTicks;
- *timings = ((*timings) & 0xffe003ff) |
- (accessTicks | (recTicks << 5)) << 10;
+#ifdef IDE_PMAC_DEBUG
+ printk(KERN_ERR "ide_pmac: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n",
+ cycleTime, accessTime, recTime);
+#endif
+ if (intf_type == controller_kl_ata4 || intf_type == controller_kl_ata4_80) {
+ /* 66Mhz cell */
+ accessTicks = SYSCLK_TICKS_66(accessTime);
+ accessTicks = min(accessTicks, 0x1fU);
+ accessTicks = max(accessTicks, 0x1U);
+ recTicks = SYSCLK_TICKS_66(recTime);
+ recTicks = min(recTicks, 0x1fU);
+ recTicks = max(recTicks, 0x3U);
+ /* Clear out mdma bits and disable udma */
+ *timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) |
+ (accessTicks << TR_66_MDMA_ACCESS_SHIFT) |
+ (recTicks << TR_66_MDMA_RECOVERY_SHIFT);
+ } else if (intf_type == controller_kl_ata3) {
+ /* 33Mhz cell on KeyLargo */
+ accessTicks = SYSCLK_TICKS(accessTime);
+ accessTicks = max(accessTicks, 1U);
+ accessTicks = min(accessTicks, 0x1fU);
+ accessTime = accessTicks * IDE_SYSCLK_NS;
+ recTicks = SYSCLK_TICKS(recTime);
+ recTicks = max(recTicks, 1U);
+ recTicks = min(recTicks, 0x1fU);
+ *timings = ((*timings) & ~TR_33_MDMA_MASK) |
+ (accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
+ (recTicks << TR_33_MDMA_RECOVERY_SHIFT);
} else {
+ /* 33Mhz cell on others */
int halfTick = 0;
int origAccessTime = accessTime;
- int origCycleTime = cycleTime;
+ int origRecTime = recTime;

accessTicks = SYSCLK_TICKS(accessTime);
- if (accessTicks < 1)
- accessTicks = 1;
+ accessTicks = max(accessTicks, 1U);
+ accessTicks = min(accessTicks, 0x1fU);
accessTime = accessTicks * IDE_SYSCLK_NS;
- recTicks = SYSCLK_TICKS(cycleTime - accessTime) - 1;
- if (recTicks < 1)
- recTicks = 1;
- cycleTime = (recTicks + 1 + accessTicks) * IDE_SYSCLK_NS;
-
- /* KeyLargo ata-3 don't support the half-tick stuff */
- if ((pmac_ide[intf].kind != controller_kl_ata3) &&
- (accessTicks > 1) &&
- ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
- ((cycleTime - IDE_SYSCLK_NS) >= origCycleTime)) {
- halfTick = 1;
- accessTicks--;
- }
- *timings = ((*timings) & 0x7FF) |
- (accessTicks | (recTicks << 5) | (halfTick << 10)) << 11;
+ recTicks = SYSCLK_TICKS(recTime);
+ recTicks = max(recTicks, 2U) - 1;
+ recTicks = min(recTicks, 0x1fU);
+ recTime = (recTicks + 1) * IDE_SYSCLK_NS;
+ if ((accessTicks > 1) &&
+ ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
+ ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) {
+ halfTick = 1;
+ accessTicks--;
+ }
+ *timings = ((*timings) & ~TR_33_MDMA_MASK) |
+ (accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
+ (recTicks << TR_33_MDMA_RECOVERY_SHIFT);
+ if (halfTick)
+ *timings |= TR_33_MDMA_HALFTICK;
}
+#ifdef IDE_PMAC_DEBUG
+ printk(KERN_ERR "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
+ speed & 0xf, *timings);
+#endif
return 0;
}
#endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */
@@ -406,11 +663,11 @@
/* You may notice we don't use this function on normal operation,
* our, normal mdma function is supposed to be more precise
*/
-static int
+static int __pmac
pmac_ide_tune_chipset (ide_drive_t *drive, byte speed)
{
int intf = pmac_ide_find(drive);
- int unit = (drive->select.all & 0x10) ? 1:0;
+ int unit = (drive->select.b.unit & 0x01);
int ret = 0;
u32 *timings;

@@ -423,19 +680,25 @@
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
case XFER_UDMA_4:
case XFER_UDMA_3:
+ if (pmac_ide[intf].kind != controller_kl_ata4_80)
+ return 1;
case XFER_UDMA_2:
case XFER_UDMA_1:
case XFER_UDMA_0:
- ret = set_timings_udma(intf, timings, speed);
+ if (pmac_ide[intf].kind != controller_kl_ata4 &&
+ pmac_ide[intf].kind != controller_kl_ata4_80)
+ return 1;
+ ret = set_timings_udma(timings, speed);
break;
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
case XFER_MW_DMA_0:
+ ret = set_timings_mdma(pmac_ide[intf].kind, timings, speed, 0);
+ break;
case XFER_SW_DMA_2:
case XFER_SW_DMA_1:
case XFER_SW_DMA_0:
- ret = set_timings_mdma(intf, timings, speed);
- break;
+ return 1;
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
case XFER_PIO_4:
case XFER_PIO_3:
@@ -460,13 +723,46 @@
return 0;
}

-ide_ioreg_t
+static void __pmac
+sanitize_timings(int i)
+{
+ unsigned value;
+
+ switch(pmac_ide[i].kind) {
+ case controller_kl_ata4:
+ case controller_kl_ata4_80:
+ value = 0x0008438c;
+ break;
+ case controller_kl_ata3:
+ value = 0x00084526;
+ break;
+ case controller_heathrow:
+ case controller_ohare:
+ default:
+ value = 0x00074526;
+ break;
+ }
+ pmac_ide[i].timings[0] = pmac_ide[i].timings[1] = value;
+}
+
+ide_ioreg_t __pmac
pmac_ide_get_base(int index)
{
return pmac_ide[index].regbase;
}

-int
+int __pmac
+pmac_ide_check_base(ide_ioreg_t base)
+{
+ int ix;
+
+ for (ix = 0; ix < MAX_HWIFS; ++ix)
+ if (base == pmac_ide[ix].regbase)
+ return ix;
+ return -1;
+}
+
+int __pmac
pmac_ide_get_irq(ide_ioreg_t base)
{
int ix;
@@ -477,7 +773,7 @@
return 0;
}

-static int ide_majors[] = { 3, 22, 33, 34, 56, 57 };
+static int ide_majors[] __pmacdata = { 3, 22, 33, 34, 56, 57 };

kdev_t __init
pmac_find_ide_boot(char *bootdevice, int n)
@@ -494,11 +790,11 @@
name = pmac_ide[i].node->full_name;
if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
/* XXX should cope with the 2nd drive as well... */
- return MKDEV(ide_majors[i], 0);
+ return mk_kdev(ide_majors[i], 0);
}
}

- return 0;
+ return NODEV;
}

void __init
@@ -541,9 +837,12 @@

for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
struct device_node *tp;
+ struct pmac_ide_hwif *pmif;
int *bidp;
int in_bay = 0;
-
+ u8 pbus, pid;
+ struct pci_dev *pdev = NULL;
+
/*
* If this node is not under a mac-io or dbdma node,
* leave it to the generic PCI driver.
@@ -561,6 +860,15 @@
continue;
}

+ /* We need to find the pci_dev of the mac-io holding the
+ * IDE interface
+ */
+ if (pci_device_from_OF_node(tp, &pbus, &pid) == 0)
+ pdev = pci_find_slot(pbus, pid);
+ if (pdev == NULL)
+ printk(KERN_WARNING "ide: no PCI host for device %s, DMA disabled\n",
+ np->full_name);
+
/*
* If this slot is taken (e.g. by ide-pci.c) try the next one.
*/
@@ -569,8 +877,23 @@
++i;
if (i >= MAX_HWIFS)
break;
+ pmif = &pmac_ide[i];

- base = (unsigned long) ioremap(np->addrs[0].address, 0x200) - _IO_BASE;
+ /*
+ * Some older OFs have bogus sizes, causing request_OF_resource
+ * to fail. We fix them up here
+ */
+ if (np->addrs[0].size > 0x1000)
+ np->addrs[0].size = 0x1000;
+ if (np->n_addrs > 1 && np->addrs[1].size > 0x100)
+ np->addrs[1].size = 0x100;
+
+ if (request_OF_resource(np, 0, " (mac-io IDE IO)") == NULL) {
+ printk(KERN_ERR "ide-pmac(%s): can't request IO resource !\n", np->name);
+ continue;
+ }
+
+ base = (unsigned long) ioremap(np->addrs[0].address, 0x400) - _IO_BASE;

/* XXX This is bogus. Should be fixed in the registry by checking
the kind of host interrupt controller, a bit like gatwick
@@ -583,21 +906,30 @@
} else {
irq = np->intrs[0].line;
}
- pmac_ide[i].regbase = base;
- pmac_ide[i].irq = irq;
- pmac_ide[i].node = np;
+ pmif->regbase = base;
+ pmif->irq = irq;
+ pmif->node = np;
if (device_is_compatible(np, "keylargo-ata")) {
if (strcmp(np->name, "ata-4") == 0)
- pmac_ide[i].kind = controller_kl_ata4;
+ pmif->kind = controller_kl_ata4;
else
- pmac_ide[i].kind = controller_kl_ata3;
+ pmif->kind = controller_kl_ata3;
} else if (device_is_compatible(np, "heathrow-ata"))
- pmac_ide[i].kind = controller_heathrow;
+ pmif->kind = controller_heathrow;
else
- pmac_ide[i].kind = controller_ohare;
+ pmif->kind = controller_ohare;

bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
- pmac_ide[i].aapl_bus_id = bidp ? *bidp : 0;
+ pmif->aapl_bus_id = bidp ? *bidp : 0;
+
+ if (pmif->kind == controller_kl_ata4) {
+ char* cable = get_property(np, "cable-type", NULL);
+ if (cable && !strncmp(cable, "80-", 3))
+ pmif->kind = controller_kl_ata4_80;
+ }
+
+ /* Make sure we have sane timings */
+ sanitize_timings(i);

if (np->parent && np->parent->name
&& strcasecmp(np->parent->name, "media-bay") == 0) {
@@ -605,39 +937,22 @@
media_bay_set_ide_infos(np->parent,base,irq,i);
#endif /* CONFIG_PMAC_PBOOK */
in_bay = 1;
- } else if (pmac_ide[i].kind == controller_ohare) {
+ if (!bidp)
+ pmif->aapl_bus_id = 1;
+ } else if (pmif->kind == controller_ohare) {
/* The code below is having trouble on some ohare machines
* (timing related ?). Until I can put my hand on one of these
* units, I keep the old way
*/
- feature_set(np, FEATURE_IDE0_enable);
+ ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1);
} else {
/* This is necessary to enable IDE when net-booting */
printk(KERN_INFO "pmac_ide: enabling IDE bus ID %d\n",
- pmac_ide[i].aapl_bus_id);
- switch(pmac_ide[i].aapl_bus_id) {
- case 0:
- feature_set(np, FEATURE_IDE0_reset);
- mdelay(10);
- feature_set(np, FEATURE_IDE0_enable);
- mdelay(10);
- feature_clear(np, FEATURE_IDE0_reset);
- break;
- case 1:
- feature_set(np, FEATURE_IDE1_reset);
- mdelay(10);
- feature_set(np, FEATURE_IDE1_enable);
- mdelay(10);
- feature_clear(np, FEATURE_IDE1_reset);
- break;
- case 2:
- /* This one exists only for KL, I don't know
- about any enable bit */
- feature_set(np, FEATURE_IDE2_reset);
- mdelay(10);
- feature_clear(np, FEATURE_IDE2_reset);
- break;
- }
+ pmif->aapl_bus_id);
+ ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1);
+ ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1);
+ mdelay(10);
+ ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0);
big_delay = 1;
}

@@ -646,13 +961,15 @@
memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
hwif->chipset = ide_pmac;
hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay;
+ hwif->udma_four = (pmif->kind == controller_kl_ata4_80);
+ hwif->pci_dev = pdev;
#ifdef CONFIG_PMAC_PBOOK
if (in_bay && check_media_bay_by_base(base, MB_CD) == 0)
hwif->noprobe = 0;
#endif /* CONFIG_PMAC_PBOOK */

#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
- if (np->n_addrs >= 2) {
+ if (pdev && np->n_addrs >= 2) {
/* has a DBDMA controller channel */
pmac_ide_setup_dma(np, i);
}
@@ -674,7 +991,15 @@
static void __init
pmac_ide_setup_dma(struct device_node *np, int ix)
{
- pmac_ide[ix].dma_regs =
+ struct pmac_ide_hwif *pmif = &pmac_ide[ix];
+
+ if (request_OF_resource(np, 1, " (mac-io IDE DMA)") == NULL) {
+ printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n",
+ np->name);
+ return;
+ }
+
+ pmif->dma_regs =
(volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200);

/*
@@ -682,14 +1007,24 @@
* The +2 is +1 for the stop command and +1 to allow for
* aligning the start address to a multiple of 16 bytes.
*/
- pmac_ide[ix].dma_table = (struct dbdma_cmd*)
- kmalloc((MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), GFP_KERNEL);
- if (pmac_ide[ix].dma_table == 0) {
+ pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent(
+ ide_hwifs[ix].pci_dev,
+ (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
+ &pmif->dma_table_dma);
+ if (pmif->dma_table_cpu == NULL) {
printk(KERN_ERR "%s: unable to allocate DMA command list\n",
ide_hwifs[ix].name);
return;
}

+ pmif->sg_table = kmalloc(sizeof(struct scatterlist) * MAX_DCMDS,
+ GFP_KERNEL);
+ if (pmif->sg_table == NULL) {
+ pci_free_consistent( ide_hwifs[ix].pci_dev,
+ (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
+ pmif->dma_table_cpu, pmif->dma_table_dma);
+ return;
+ }
ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
if (!noautodma)
@@ -697,6 +1032,62 @@
#endif
}

+static int
+pmac_ide_build_sglist (int ix, struct request *rq)
+{
+ struct ata_channel *hwif = &ide_hwifs[ix];
+ struct pmac_ide_hwif *pmif = &pmac_ide[ix];
+ request_queue_t *q = &hwif->drives[DEVICE_NR(rq->rq_dev) & 1].queue;
+ struct scatterlist *sg = pmif->sg_table;
+ int nents;
+
+ nents = blk_rq_map_sg(q, rq, pmif->sg_table);
+
+ if (rq->q && nents > rq->nr_phys_segments)
+ printk("ide-pmac: received %d phys segments, build %d\n", rq->nr_phys_segments, nents);
+
+ if (rq_data_dir(rq) == READ)
+ pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+ else
+ pmif->sg_dma_direction = PCI_DMA_TODEVICE;
+
+ return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
+}
+
+static int
+pmac_ide_raw_build_sglist (int ix, struct request *rq)
+{
+ struct ata_channel *hwif = &ide_hwifs[ix];
+ struct pmac_ide_hwif *pmif = &pmac_ide[ix];
+ struct scatterlist *sg = pmif->sg_table;
+ int nents = 0;
+ ide_task_t *args = rq->special;
+ unsigned char *virt_addr = rq->buffer;
+ int sector_count = rq->nr_sectors;
+
+ if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
+ pmif->sg_dma_direction = PCI_DMA_TODEVICE;
+ else
+ pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+
+ 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++;
+
+ return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
+}
+
/*
* pmac_ide_build_dmatable builds the DBDMA command list
* for a transfer and sets the DBDMA channel to point to it.
@@ -704,47 +1095,40 @@
static int
pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr)
{
- struct dbdma_cmd *table, *tstart;
- int count = 0;
+ struct dbdma_cmd *table;
+ int i, count = 0;
struct request *rq = HWGROUP(drive)->rq;
- struct buffer_head *bh = rq->bh;
- unsigned int size, addr;
volatile struct dbdma_regs *dma = pmac_ide[ix].dma_regs;
+ struct scatterlist *sg;
+
+ /* DMA table is already aligned */
+ table = (struct dbdma_cmd *) pmac_ide[ix].dma_table_cpu;

- table = tstart = (struct dbdma_cmd *) DBDMA_ALIGN(pmac_ide[ix].dma_table);
+ /* Make sure DMA controller is stopped (necessary ?) */
out_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16);
while (in_le32(&dma->status) & RUN)
udelay(1);

- do {
- /*
- * Determine addr and size of next buffer area. We assume that
- * individual virtual buffers are always composed linearly in
- * physical memory. For example, we assume that any 8kB buffer
- * is always composed of two adjacent physical 4kB pages rather
- * than two possibly non-adjacent physical 4kB pages.
- */
- if (bh == NULL) { /* paging requests have (rq->bh == NULL) */
- addr = virt_to_bus(rq->buffer);
- size = rq->nr_sectors << 9;
- } else {
- /* group sequential buffers into one large buffer */
- addr = virt_to_bus(bh->b_data);
- size = bh->b_size;
- while ((bh = bh->b_reqnext) != NULL) {
- if ((addr + size) != virt_to_bus(bh->b_data))
- break;
- size += bh->b_size;
- }
- }
+ /* Build sglist */
+ if (rq->flags & REQ_DRIVE_TASKFILE) {
+ pmac_ide[ix].sg_nents = i = pmac_ide_raw_build_sglist(ix, rq);
+ } else {
+ pmac_ide[ix].sg_nents = i = pmac_ide_build_sglist(ix, rq);
+ }
+ if (!i)
+ return 0;

- /*
- * Fill in the next DBDMA command block.
- * Note that one DBDMA command can transfer
- * at most 65535 bytes.
- */
- while (size) {
- unsigned int tc = (size < 0xfe00)? size: 0xfe00;
+ /* Build DBDMA commands list */
+ sg = pmac_ide[ix].sg_table;
+ while (i) {
+ u32 cur_addr;
+ u32 cur_len;
+
+ cur_addr = sg_dma_address(sg);
+ cur_len = sg_dma_len(sg);
+
+ while (cur_len) {
+ unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;

if (++count >= MAX_DCMDS) {
printk(KERN_WARNING "%s: DMA table too small\n",
@@ -753,15 +1137,17 @@
}
st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE);
st_le16(&table->req_count, tc);
- st_le32(&table->phy_addr, addr);
+ st_le32(&table->phy_addr, cur_addr);
table->cmd_dep = 0;
table->xfer_status = 0;
table->res_count = 0;
- addr += tc;
- size -= tc;
+ cur_addr += tc;
+ cur_len -= tc;
++table;
}
- } while (bh != NULL);
+ sg++;
+ i--;
+ }

/* convert the last command to an input/output last command */
if (count)
@@ -773,10 +1159,24 @@
memset(table, 0, sizeof(struct dbdma_cmd));
out_le16(&table->command, DBDMA_STOP);

- out_le32(&dma->cmdptr, virt_to_bus(tstart));
+ out_le32(&dma->cmdptr, pmac_ide[ix].dma_table_dma);
return 1;
}

+/* Teardown mappings after DMA has completed. */
+static void
+pmac_ide_destroy_dmatable (ide_drive_t *drive, int ix)
+{
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ struct scatterlist *sg = pmac_ide[ix].sg_table;
+ int nents = pmac_ide[ix].sg_nents;
+
+ if (nents) {
+ pci_unmap_sg(dev, sg, nents, pmac_ide[ix].sg_dma_direction);
+ pmac_ide[ix].sg_nents = 0;
+ }
+}
+

static __inline__ unsigned char
dma_bits_to_command(unsigned char bits)
@@ -791,12 +1191,14 @@
}

static __inline__ unsigned char
-udma_bits_to_command(unsigned char bits)
+udma_bits_to_command(unsigned char bits, int high_speed)
{
- if(bits & 0x10)
- return XFER_UDMA_4;
- if(bits & 0x08)
- return XFER_UDMA_3;
+ if (high_speed) {
+ if(bits & 0x10)
+ return XFER_UDMA_4;
+ if(bits & 0x08)
+ return XFER_UDMA_3;
+ }
if(bits & 0x04)
return XFER_UDMA_2;
if(bits & 0x02)
@@ -807,14 +1209,13 @@
}

/* Calculate MultiWord DMA timings */
-static int
+static int __pmac
pmac_ide_mdma_enable(ide_drive_t *drive, int idx)
{
byte bits = drive->id->dma_mword & 0x07;
byte feature = dma_bits_to_command(bits);
u32 *timings;
- int cycleTime, accessTime;
- int accessTicks, recTicks;
+ int drive_cycle_time;
struct hd_driveid *id = drive->id;
int ret;

@@ -830,66 +1231,30 @@
drive->init_speed = feature;

/* which drive is it ? */
- if (drive->select.all & 0x10)
+ if (drive->select.b.unit & 0x01)
timings = &pmac_ide[idx].timings[1];
else
timings = &pmac_ide[idx].timings[0];

- /* Calculate accesstime and cycle time */
- cycleTime = mdma_timings[feature & 0xf].cycleTime;
- accessTime = mdma_timings[feature & 0xf].accessTime;
+ /* Check if drive provide explicit cycle time */
if ((id->field_valid & 2) && (id->eide_dma_time))
- cycleTime = id->eide_dma_time;
- if ((pmac_ide[idx].kind == controller_ohare) && (cycleTime < 150))
- cycleTime = 150;
+ drive_cycle_time = id->eide_dma_time;
+ else
+ drive_cycle_time = 0;
+
+ /* Calculate controller timings */
+ set_timings_mdma(pmac_ide[idx].kind, timings, feature, drive_cycle_time);

- /* For ata-4 controller */
- if (pmac_ide[idx].kind == controller_kl_ata4) {
- accessTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);
- recTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000) - accessTicks;
- *timings = ((*timings) & 0xffe003ff) |
- (accessTicks | (recTicks << 5)) << 10;
- } else {
- int halfTick = 0;
- int origAccessTime = accessTime;
- int origCycleTime = cycleTime;
-
- accessTicks = SYSCLK_TICKS(accessTime);
- if (accessTicks < 1)
- accessTicks = 1;
- accessTime = accessTicks * IDE_SYSCLK_NS;
- recTicks = SYSCLK_TICKS(cycleTime - accessTime) - 1;
- if (recTicks < 1)
- recTicks = 1;
- cycleTime = (recTicks + 1 + accessTicks) * IDE_SYSCLK_NS;
-
- /* KeyLargo ata-3 don't support the half-tick stuff */
- if ((pmac_ide[idx].kind != controller_kl_ata3) &&
- (accessTicks > 1) &&
- ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
- ((cycleTime - IDE_SYSCLK_NS) >= origCycleTime)) {
- halfTick = 1;
- accessTicks--;
- }
- *timings = ((*timings) & 0x7FF) |
- (accessTicks | (recTicks << 5) | (halfTick << 10)) << 11;
- }
-#ifdef IDE_PMAC_DEBUG
- printk(KERN_INFO "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
- feature & 0xf, *timings);
-#endif
drive->current_speed = feature;
return 1;
}

/* Calculate Ultra DMA timings */
-static int
-pmac_ide_udma_enable(ide_drive_t *drive, int idx)
+static int __pmac
+pmac_ide_udma_enable(ide_drive_t *drive, int idx, int high_speed)
{
byte bits = drive->id->dma_ultra & 0x1f;
- byte feature = udma_bits_to_command(bits);
- int cycleTime, accessTime;
- int rdyToPauseTicks, cycleTicks;
+ byte feature = udma_bits_to_command(bits, high_speed);
u32 *timings;
int ret;

@@ -905,25 +1270,18 @@
drive->init_speed = feature;

/* which drive is it ? */
- if (drive->select.all & 0x10)
+ if (drive->select.b.unit & 0x01)
timings = &pmac_ide[idx].timings[1];
else
timings = &pmac_ide[idx].timings[0];

- cycleTime = udma_timings[feature & 0xf].cycleTime;
- accessTime = udma_timings[feature & 0xf].accessTime;
-
- rdyToPauseTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);
- cycleTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000);
-
- *timings = ((*timings) & 0xe00fffff) |
- ((cycleTicks << 1) | (rdyToPauseTicks << 5) | 1) << 20;
+ set_timings_udma(timings, feature);

drive->current_speed = feature;
return 1;
}

-static int
+static int __pmac
pmac_ide_check_dma(ide_drive_t *drive)
{
int ata4, udma, idx;
@@ -944,21 +1302,20 @@
enable = 0;

udma = 0;
- ata4 = (pmac_ide[idx].kind == controller_kl_ata4);
+ ata4 = (pmac_ide[idx].kind == controller_kl_ata4 ||
+ pmac_ide[idx].kind == controller_kl_ata4_80);

if(enable) {
if (ata4 && (drive->type == ATA_DISK) &&
- (id->field_valid & 0x0004) && (id->dma_ultra & 0x17)) {
+ (id->field_valid & 0x0004) && (id->dma_ultra & 0x1f)) {
/* UltraDMA modes. */
- drive->using_dma = pmac_ide_udma_enable(drive, idx);
+ drive->using_dma = pmac_ide_udma_enable(drive, idx,
+ pmac_ide[idx].kind == controller_kl_ata4_80);
}
if (!drive->using_dma && (id->dma_mword & 0x0007)) {
/* Normal MultiWord DMA modes. */
drive->using_dma = pmac_ide_mdma_enable(drive, idx);
}
- /* Without this, strange things will happen on Keylargo-based
- * machines
- */
OUT_BYTE(0, IDE_CONTROL_REG);
/* Apply settings to controller */
pmac_ide_selectproc(drive);
@@ -966,11 +1323,26 @@
return 0;
}

+static void ide_toggle_bounce(ide_drive_t *drive, int on)
+{
+ dma64_addr_t addr = BLK_BOUNCE_HIGH;
+
+ if (on && drive->type == ATA_DISK && HWIF(drive)->highmem) {
+ if (!PCI_DMA_BUS_IS_PHYS)
+ addr = BLK_BOUNCE_ANY;
+ else
+ addr = HWIF(drive)->pci_dev->dma_mask;
+ }
+
+ blk_queue_bounce_limit(&drive->queue, addr);
+}
+
int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
{
- int ix, dstat, i;
+ int ix, dstat, reading, ata4;
volatile struct dbdma_regs *dma;
-
+ byte unit = (drive->select.b.unit & 0x01);
+
/* Can we stuff a pointer to our intf structure in config_data
* or select_data in hwif ?
*/
@@ -978,59 +1350,106 @@
if (ix < 0)
return 0;
dma = pmac_ide[ix].dma_regs;
-
+ ata4 = (pmac_ide[ix].kind == controller_kl_ata4 ||
+ pmac_ide[ix].kind == controller_kl_ata4_80);
+
switch (func) {
case ide_dma_off:
printk(KERN_INFO "%s: DMA disabled\n", drive->name);
case ide_dma_off_quietly:
drive->using_dma = 0;
+ ide_toggle_bounce(drive, 0);
break;
case ide_dma_on:
case ide_dma_check:
+ /* Change this to better match ide-dma.c */
pmac_ide_check_dma(drive);
+ ide_toggle_bounce(drive, drive->using_dma);
break;
case ide_dma_read:
case ide_dma_write:
- if (!pmac_ide_build_dmatable(drive, ix, func==ide_dma_write))
+ /* this almost certainly isn't needed since we don't
+ appear to have a rwproc */
+ if (HWIF(drive)->rwproc)
+ HWIF(drive)->rwproc(drive, func);
+ reading = (func == ide_dma_read);
+ if (!pmac_ide_build_dmatable(drive, ix, !reading))
return 1;
+ /* Apple adds 60ns to wrDataSetup on reads */
+ if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) {
+ out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
+ pmac_ide[ix].timings[unit] +
+ ((func == ide_dma_read) ? 0x00800000UL : 0));
+ (void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
+ }
drive->waiting_for_dma = 1;
if (drive->type != ATA_DISK)
return 0;
BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
- OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA,
- 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->taskfile.command, 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);
+ }
+ /* fall through */
case ide_dma_begin:
out_le32(&dma->control, (RUN << 16) | RUN);
+ /* Make sure it gets to the controller right now */
+ (void)in_le32(&dma->control);
break;
- case ide_dma_end:
+ case ide_dma_end: /* returns 1 on error, 0 otherwise */
drive->waiting_for_dma = 0;
dstat = in_le32(&dma->status);
out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16));
+ pmac_ide_destroy_dmatable(drive, ix);
/* verify good dma status */
return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
- case ide_dma_test_irq:
- if ((in_le32(&dma->status) & (RUN|ACTIVE)) == RUN)
- return 1;
- /* That's a bit ugly and dangerous, but works in our case
- * to workaround a problem with the channel status staying
- * active if the drive returns an error
+ case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
+ /* We have to things to deal with here:
+ *
+ * - The dbdma won't stop if the command was started
+ * but completed with an error without transfering all
+ * datas. This happens when bad blocks are met during
+ * a multi-block transfer.
+ *
+ * - The dbdma fifo hasn't yet finished flushing to
+ * to system memory when the disk interrupt occurs.
+ *
+ * The trick here is to increment drive->waiting_for_dma,
+ * and return as if no interrupt occured. If the counter
+ * reach a certain timeout value, we then return 1. If
+ * we really got the interrupt, it will happen right away
+ * again.
+ * Apple's solution here may be more elegant. They issue
+ * a DMA channel interrupt (a separate irq line) via a DBDMA
+ * NOP command just before the STOP, and wait for both the
+ * disk and DBDMA interrupts to have completed.
*/
- if (IDE_CONTROL_REG) {
- byte stat;
- stat = GET_ALTSTAT();
- if (stat & ERR_STAT)
- return 1;
- }
- /* In some edge cases, some datas may still be in the dbdma
- * engine fifo, we wait a bit for dbdma to complete
+
+ /* If ACTIVE is cleared, the STOP command have passed and
+ * transfer is complete.
*/
- while ((in_le32(&dma->status) & (RUN|ACTIVE)) != RUN) {
- if (++i > 100)
- return 0;
- udelay(1);
+ if (!(in_le32(&dma->status) & ACTIVE))
+ return 1;
+ if (!drive->waiting_for_dma)
+ printk(KERN_WARNING "ide%d, ide_dma_test_irq \
+ called while not waiting\n", ix);
+
+ /* If dbdma didn't execute the STOP command yet, the
+ * active bit is still set */
+ drive->waiting_for_dma++;
+ if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
+ printk(KERN_WARNING "ide%d, timeout waiting \
+ for dbdma command stop\n", ix);
+ return 1;
}
- return 1;
+ udelay(1);
+ return 0;

/* Let's implement tose just in case someone wants them */
case ide_dma_bad_drive:
@@ -1051,7 +1470,6 @@
}
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */

-#ifdef CONFIG_PMAC_PBOOK
static void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base)
{
int j;
@@ -1062,7 +1480,9 @@
switch (drive->type) {
case ATA_DISK:
/* Spin down the drive */
- outb(0xa0, base+0x60);
+ outb(drive->select.all, base+0x60);
+ (void)inb(base+0x60);
+ udelay(100);
outb(0x0, base+0x30);
outb(0x0, base+0x20);
outb(0x0, base+0x40);
@@ -1086,19 +1506,21 @@
}
}

-static void idepmac_wake_device(ide_drive_t *drive, int used_dma)
- {
+#ifdef CONFIG_PMAC_PBOOK
+static void __pmac
+idepmac_wake_device(ide_drive_t *drive, int used_dma)
+{
/* We force the IDE subdriver to check for a media change
* This must be done first or we may lost the condition
*
* Problem: This can schedule. I moved the block device
* wakeup almost late by priority because of that.
*/
- if (DRIVER(drive) && DRIVER(drive)->media_change)
- DRIVER(drive)->media_change(drive);
+ if (drive->driver != NULL && ata_ops(drive)->check_media_change)
+ ata_ops(drive)->check_media_change(drive);

/* We kick the VFS too (see fix in ide.c revalidate) */
- check_disk_change(MKDEV(drive->channel->major, (drive->select.b.unit) << PARTN_BITS));
+ check_disk_change(mk_kdev(drive->channel->major, (drive->select.b.unit) << PARTN_BITS));

#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
/* We re-enable DMA on the drive if it was active. */
@@ -1108,15 +1530,16 @@
*/
if (used_dma && !ide_spin_wait_hwgroup(drive)) {
/* Lock HW group */
- HWGROUP(drive)->busy = 1;
+ set_bit(IDE_BUSY, &HWGROUP(drive)->flags);
pmac_ide_check_dma(drive);
- HWGROUP(drive)->busy = 0;
+ clear_bit(IDE_BUSY, &HWGROUP(drive)->flags);
spin_unlock_irq(&ide_lock);
}
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
}

-static void idepmac_sleep_interface(int i, unsigned base, int mediabay)
+static void __pmac
+idepmac_sleep_interface(int i, unsigned base, int mediabay)
{
struct device_node* np = pmac_ide[i].node;

@@ -1128,73 +1551,81 @@
if (mediabay)
return;

- /* Disable and reset the bus */
- feature_set(np, FEATURE_IDE0_reset);
- feature_clear(np, FEATURE_IDE0_enable);
- switch(pmac_ide[i].aapl_bus_id) {
- case 0:
- feature_set(np, FEATURE_IDE0_reset);
- feature_clear(np, FEATURE_IDE0_enable);
- break;
- case 1:
- feature_set(np, FEATURE_IDE1_reset);
- feature_clear(np, FEATURE_IDE1_enable);
- break;
- case 2:
- feature_set(np, FEATURE_IDE2_reset);
- break;
- }
+ /* Disable the bus */
+ ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 0);
}

-static void idepmac_wake_interface(int i, unsigned long base, int mediabay)
+static void __pmac
+idepmac_wake_interface(int i, unsigned long base, int mediabay)
{
struct device_node* np = pmac_ide[i].node;

if (!mediabay) {
/* Revive IDE disk and controller */
- switch(pmac_ide[i].aapl_bus_id) {
- case 0:
- feature_set(np, FEATURE_IDE0_reset);
- feature_set(np, FEATURE_IOBUS_enable);
- mdelay(10);
- feature_set(np, FEATURE_IDE0_enable);
- mdelay(10);
- feature_clear(np, FEATURE_IDE0_reset);
- break;
- case 1:
- feature_set(np, FEATURE_IDE1_reset);
- feature_set(np, FEATURE_IOBUS_enable);
- mdelay(10);
- feature_set(np, FEATURE_IDE1_enable);
- mdelay(10);
- feature_clear(np, FEATURE_IDE1_reset);
- break;
- case 2:
- /* This one exists only for KL, I don't know
- about any enable bit */
- feature_set(np, FEATURE_IDE2_reset);
- mdelay(10);
- feature_clear(np, FEATURE_IDE2_reset);
- break;
- }
+ ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmac_ide[i].aapl_bus_id, 1);
+ ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 1);
+ mdelay(10);
+ ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmac_ide[i].aapl_bus_id, 0);
}
+}
+
+static void
+idepmac_sleep_drive(ide_drive_t *drive, int idx, unsigned long base)
+{
+ /* Wait for HW group to complete operations */
+ if (ide_spin_wait_hwgroup(drive))
+ // What can we do here ? Wake drive we had already
+ // put to sleep and return an error ?
+ return;
+ else {
+ /* Lock HW group */
+ set_bit(IDE_BUSY, &HWGROUP(drive)->flags);
+ /* Stop the device */
+ idepmac_sleep_device(drive, idx, base);
+ spin_unlock_irq(&ide_lock);
+ }
+}
+
+static void
+idepmac_wake_drive(ide_drive_t *drive, unsigned long base)
+{
+ int j;

/* Reset timings */
- pmac_ide_selectproc(&ide_hwifs[i].drives[0]);
+ pmac_ide_selectproc(drive);
mdelay(10);
+
+ /* Wait up to 20 seconds for the drive to be ready */
+ for (j = 0; j < 200; j++) {
+ int status;
+ mdelay(100);
+ outb(drive->select.all, base + 0x60);
+ if (inb(base + 0x60) != drive->select.all)
+ continue;
+ status = inb(base + 0x70);
+ if (!(status & BUSY_STAT))
+ break;
+ }
+
+ /* We resume processing on the HW group */
+ spin_lock_irq(&ide_lock);
+ clear_bit(IDE_BUSY, &HWGROUP(drive)->flags);
+ if (!list_empty(&drive->queue.queue_head))
+ do_ide_request(&drive->queue);
+ spin_unlock_irq(&ide_lock);
}

/* Note: We support only master drives for now. This will have to be
* improved if we want to handle sleep on the iMacDV where the CD-ROM
* is a slave
*/
-static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
+static int __pmac
+idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
{
int i, ret;
unsigned long base;
- unsigned long flags;
int big_delay;
-
+
switch (when) {
case PBOOK_SLEEP_REQUEST:
break;
@@ -1203,34 +1634,19 @@
case PBOOK_SLEEP_NOW:
for (i = 0; i < pmac_ide_count; ++i) {
struct ata_channel *hwif;
- ide_drive_t *drive;
- int unlock = 0;
+ int dn;

if ((base = pmac_ide[i].regbase) == 0)
- continue;
+ continue;

hwif = &ide_hwifs[i];
- drive = &hwif->drives[0];
-
- if (drive->present) {
- /* Wait for HW group to complete operations */
- if (ide_spin_wait_hwgroup(drive)) {
- // What can we do here ? Wake drive we had already
- // put to sleep and return an error ?
- } else {
- unlock = 1;
- /* Lock HW group */
- HWGROUP(drive)->busy = 1;
-
- /* Stop the device */
- idepmac_sleep_device(drive, i, base);
-
- }
+ for (dn=0; dn<MAX_DRIVES; dn++) {
+ if (!hwif->drives[dn].present)
+ continue;
+ idepmac_sleep_drive(&hwif->drives[dn], i, base);
}
/* Disable irq during sleep */
disable_irq(pmac_ide[i].irq);
- if (unlock)
- spin_unlock_irq(&ide_lock);

/* Check if this is a media bay with an IDE device or not
* a media bay.
@@ -1247,6 +1663,9 @@
if ((base = pmac_ide[i].regbase) == 0)
continue;

+ /* Make sure we have sane timings */
+ sanitize_timings(i);
+
/* Check if this is a media bay with an IDE device or not
* a media bay
*/
@@ -1263,43 +1682,29 @@

for (i = 0; i < pmac_ide_count; ++i) {
struct ata_channel *hwif;
- ide_drive_t *drive;
- int j, used_dma;
+ int used_dma, dn;
+ int irq_on = 0;

if ((base = pmac_ide[i].regbase) == 0)
continue;

hwif = &ide_hwifs[i];
- drive = &hwif->drives[0];
-
- /* Wait for the drive to come up and set it's DMA */
- if (drive->present) {
- /* Wait up to 20 seconds */
- for (j = 0; j < 200; j++) {
- int status;
- mdelay(100);
- status = inb(base + 0x70);
- if (!(status & BUSY_STAT))
- break;
+ for (dn=0; dn<MAX_DRIVES; dn++) {
+ ide_drive_t *drive = &hwif->drives[dn];
+ if (!drive->present)
+ continue;
+ /* We don't have re-configured DMA yet */
+ used_dma = drive->using_dma;
+ drive->using_dma = 0;
+ idepmac_wake_drive(drive, base);
+ if (!irq_on) {
+ enable_irq(pmac_ide[i].irq);
+ irq_on = 1;
}
- }
-
- /* We don't have re-configured DMA yet */
- used_dma = drive->using_dma;
- drive->using_dma = 0;
-
- /* We resume processing on the HW group */
- spin_lock_irqsave(&ide_lock, flags);
- enable_irq(pmac_ide[i].irq);
- if (drive->present)
- HWGROUP(drive)->busy = 0;
- spin_unlock_irqrestore(&ide_lock, flags);
-
- /* Wake the device
- * We could handle the slave here
- */
- if (drive->present)
idepmac_wake_device(drive, used_dma);
+ }
+ if (!irq_on)
+ enable_irq(pmac_ide[i].irq);
}
break;
}
diff -urN linux-2.5.8-pre2/drivers/ide/ide-pnp.c linux/drivers/ide/ide-pnp.c
--- linux-2.5.8-pre2/drivers/ide/ide-pnp.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/ide-pnp.c Mon Apr 8 16:29:16 2002
@@ -16,6 +16,7 @@
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

+#include <linux/types.h>
#include <linux/ide.h>
#include <linux/init.h>

diff -urN linux-2.5.8-pre2/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c
--- linux-2.5.8-pre2/drivers/ide/ide-probe.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/ide-probe.c Mon Apr 8 18:21:28 2002
@@ -140,7 +140,7 @@
/* kludge for Apple PowerBook internal zip */
if (!strstr(id->model, "CD-ROM") && strstr(id->model, "ZIP")) {
printk ("FLOPPY");
- type = ide_floppy;
+ type = ATA_FLOPPY;
break;
}
#endif
@@ -666,13 +666,12 @@
hwif->sharing_irq = h->sharing_irq = 1;
if (hwif->chipset != ide_pci || h->chipset != ide_pci)
save_match(hwif, h, &match);
- }
- if (hwif->serialized) {
- if (hwif->mate && hwif->mate->irq == h->irq)
- save_match(hwif, h, &match);
- }
- if (h->serialized) {
- if (h->mate && hwif->irq == h->mate->irq)
+
+ /* FIXME: This is still confusing. What would
+ * happen if we match-ed two times?
+ */
+
+ if (hwif->serialized || h->serialized)
save_match(hwif, h, &match);
}
}
@@ -823,12 +822,11 @@

for (unit = 0; unit < MAX_DRIVES; ++unit) {
char name[80];
+
ide_add_generic_settings(hwif->drives + unit);
hwif->drives[unit].dn = ((hwif->unit ? 2 : 0) + unit);
sprintf (name, "host%d/bus%d/target%d/lun%d",
- (hwif->unit && hwif->mate) ?
- hwif->mate->index : hwif->index,
- hwif->unit, unit, hwif->drives[unit].lun);
+ hwif->index, hwif->unit, unit, hwif->drives[unit].lun);
if (hwif->drives[unit].present)
hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
}
diff -urN linux-2.5.8-pre2/drivers/ide/ide-proc.c linux/drivers/ide/ide-proc.c
--- linux-2.5.8-pre2/drivers/ide/ide-proc.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/ide-proc.c Mon Apr 8 16:29:16 2002
@@ -164,19 +164,6 @@
PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
}

-static int proc_ide_read_mate
- (char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- struct ata_channel *hwif = data;
- int len;
-
- if (hwif && hwif->mate && hwif->mate->present)
- len = sprintf(page, "%s\n", hwif->mate->name);
- else
- len = sprintf(page, "(none)\n");
- PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-
static int proc_ide_read_channel
(char *page, char **start, off_t off, int count, int *eof, void *data)
{
@@ -493,7 +480,6 @@

static ide_proc_entry_t hwif_entries[] = {
{ "channel", S_IFREG|S_IRUGO, proc_ide_read_channel, NULL },
- { "mate", S_IFREG|S_IRUGO, proc_ide_read_mate, NULL },
{ "model", S_IFREG|S_IRUGO, proc_ide_read_imodel, NULL },
{ NULL, 0, NULL, NULL }
};
diff -urN linux-2.5.8-pre2/drivers/ide/ide.c linux/drivers/ide/ide.c
--- linux-2.5.8-pre2/drivers/ide/ide.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/ide.c Mon Apr 8 16:29:16 2002
@@ -2177,7 +2177,7 @@
}
for (h = 0; h < MAX_HWIFS; ++h) {
hwif = &ide_hwifs[h];
- if ((!hwif->present && !hwif->mate && !initializing) ||
+ if ((!hwif->present && (hwif->unit == ATA_PRIMARY) && !initializing) ||
(!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing))
goto found;
}
@@ -3052,9 +3052,13 @@
goto done;
case -2: /* "serialize" */
do_serialize:
- hwif->mate = &ide_hwifs[hw^1];
- hwif->mate->mate = hwif;
- hwif->serialized = hwif->mate->serialized = 1;
+ {
+ struct ata_channel *mate;
+
+ mate = &ide_hwifs[hw ^ 1];
+ hwif->serialized = 1;
+ mate->serialized = 1;
+ }
goto done;

case -1: /* "noprobe" */
diff -urN linux-2.5.8-pre2/drivers/ide/ns87415.c linux/drivers/ide/ns87415.c
--- linux-2.5.8-pre2/drivers/ide/ns87415.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/ns87415.c Mon Apr 8 19:01:23 2002
@@ -141,11 +141,21 @@
using_inta = progif & (1 << (hwif->unit << 1));
if (!using_inta)
using_inta = ctrl & (1 << (4 + hwif->unit));
- if (hwif->mate) {
- hwif->select_data = hwif->mate->select_data;
+ if (hwif->unit == ATA_SECONDARY) {
+
+ /* FIXME: If we are initializing the secondary channel, let us
+ * assume that the primary channel got initialized just a tad
+ * bit before now. It would be much cleaner if the data in
+ * ns87415_control just got duplicated.
+ */
+
+ if (!hwif->select_data)
+ hwif->select_data = (unsigned long)
+ &ns87415_control[ns87415_count - 1];
} else {
- hwif->select_data = (unsigned long)
- &ns87415_control[ns87415_count++];
+ if (!hwif->select_data)
+ hwif->select_data = (unsigned long)
+ &ns87415_control[ns87415_count++];
ctrl |= (1 << 8) | (1 << 9); /* mask both IRQs */
if (using_inta)
ctrl &= ~(1 << 6); /* unmask INTA */
@@ -170,9 +180,9 @@
do {
udelay(50);
stat = inb(hwif->io_ports[IDE_STATUS_OFFSET]);
- if (stat == 0xff)
- break;
- } while ((stat & BUSY_STAT) && --timeout);
+ if (stat == 0xff)
+ break;
+ } while ((stat & BUSY_STAT) && --timeout);
#endif
}

@@ -181,13 +191,23 @@

if (!using_inta)
hwif->irq = hwif->unit ? 15 : 14; /* legacy mode */
- else if (!hwif->irq && hwif->mate && hwif->mate->irq)
- hwif->irq = hwif->mate->irq; /* share IRQ with mate */
+ else {
+ static int primary_irq = 0;
+
+ /* Ugly way to let the primary and secondary channel on the
+ * chip use the same IRQ line.
+ */
+
+ if (hwif->unit == ATA_PRIMARY)
+ primary_irq = hwif->irq;
+ else if (!hwif->irq)
+ hwif->irq = primary_irq;
+ }

#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->dma_base)
hwif->dmaproc = &ns87415_dmaproc;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+#endif

hwif->selectproc = &ns87415_selectproc;
}
diff -urN linux-2.5.8-pre2/drivers/ide/pdc4030.c linux/drivers/ide/pdc4030.c
--- linux-2.5.8-pre2/drivers/ide/pdc4030.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/pdc4030.c Mon Apr 8 16:29:16 2002
@@ -162,7 +162,7 @@
struct dc_ident ident;
int i;
ide_startstop_t startstop;
-
+
if (!hwif) return 0;

drive = &hwif->drives[0];
@@ -224,9 +224,8 @@
*/

hwif->chipset = hwif2->chipset = ide_pdc4030;
- hwif->mate = hwif2;
- hwif2->mate = hwif;
- hwif2->unit = 1;
+ hwif->unit = ATA_PRIMARY;
+ hwif2->unit = ATA_SECONDARY;
hwif->selectproc = hwif2->selectproc = &promise_selectproc;
hwif->serialized = hwif2->serialized = 1;

diff -urN linux-2.5.8-pre2/drivers/ide/piix.c linux/drivers/ide/piix.c
--- linux-2.5.8-pre2/drivers/ide/piix.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/piix.c Mon Apr 8 16:29:16 2002
@@ -1,5 +1,5 @@
/*
- * $Id: piix.c,v 1.2 2002/03/13 22:50:43 vojtech Exp $
+ * $Id: piix.c,v 1.3 2002/03/29 16:06:06 vojtech Exp $
*
* Copyright (c) 2000-2002 Vojtech Pavlik
*
@@ -128,7 +128,7 @@

piix_print("----------PIIX BusMastering IDE Configuration---------------");

- piix_print("Driver Version: 1.2");
+ piix_print("Driver Version: 1.3");
piix_print("South Bridge: %s", bmide_dev->name);

pci_read_config_byte(dev, PCI_REVISION_ID, &t);
@@ -331,7 +331,7 @@
umul = 2;

T = 1000000000 / piix_clock;
- UT = T / umul;
+ UT = umul ? (T / umul) : 0;

ata_timing_compute(drive, speed, &t, T, UT);

diff -urN linux-2.5.8-pre2/drivers/ide/qd65xx.c linux/drivers/ide/qd65xx.c
--- linux-2.5.8-pre2/drivers/ide/qd65xx.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/qd65xx.c Mon Apr 8 16:29:16 2002
@@ -411,22 +411,23 @@

return 1;
} else {
- int i,j;
+ int i;
+
/* secondary enabled */
printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n",
ide_hwifs[0].name,ide_hwifs[1].name);

- for (i=0;i<2;i++) {
+ for (i = 0; i < 2; i++) {
+ int j;

ide_hwifs[i].chipset = ide_qd65xx;
- ide_hwifs[i].mate = &ide_hwifs[i^1];
ide_hwifs[i].unit = i;

ide_hwifs[i].select_data = base;
ide_hwifs[i].config_data = config | (control <<8);
ide_hwifs[i].tuneproc = &qd6580_tune_drive;

- for (j=0;j<2;j++) {
+ for (j = 0; j < 2; j++) {
ide_hwifs[i].drives[j].drive_data =
i?QD6580_DEF_DATA2:QD6580_DEF_DATA;
ide_hwifs[i].drives[j].io_32bit = 1;
diff -urN linux-2.5.8-pre2/drivers/ide/sis5513.c linux/drivers/ide/sis5513.c
--- linux-2.5.8-pre2/drivers/ide/sis5513.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/sis5513.c Mon Apr 8 16:29:16 2002
@@ -1,17 +1,17 @@
/*
- * linux/drivers/ide/sis5513.c Version 0.13 March 4, 2002
+ * linux/drivers/ide/sis5513.c Version 0.13 March 6, 2002
*
* Copyright (C) 1999-2000 Andre Hedrick <[email protected]>
* Copyright (C) 2002 Lionel Bouton <[email protected]>, Maintainer
* May be copied or modified under the terms of the GNU General Public License
*
-*/
-
-/* Thanks :
- * For direct support and hardware : SiS Taiwan.
- * For ATA100 support advice : Daniela Engert.
- * For checking code correctness, providing patches :
- * John Fremlin, Manfred Spraul
+ *
+ * Thanks :
+ *
+ * SiS Taiwan : for direct support and hardware.
+ * Daniela Engert : for initial ATA100 advices and numerous others.
+ * John Fremlin, Manfred Spraul :
+ * for checking code correctness, providing patches.
*/

/*
@@ -52,59 +52,40 @@

#include "ata-timing.h"

+/* When DEBUG is defined it outputs initial PCI config register
+ values and changes made to them by the driver */
// #define DEBUG
-/* if BROKEN_LEVEL is defined it limits the DMA mode
+/* When BROKEN_LEVEL is defined it limits the DMA mode
at boot time to its value */
// #define BROKEN_LEVEL XFER_SW_DMA_0
#define DISPLAY_SIS_TIMINGS

/* Miscellaneaous flags */
#define SIS5513_LATENCY 0x01
-/* ATA transfer mode capabilities */
+
+/* registers layout and init values are chipset family dependant */
+/* 1/ define families */
#define ATA_00 0x00
#define ATA_16 0x01
#define ATA_33 0x02
#define ATA_66 0x03
-#define ATA_100a 0x04
+#define ATA_100a 0x04 // SiS730 is ATA100 with ATA66 layout
#define ATA_100 0x05
#define ATA_133 0x06

-static unsigned char dma_capability = 0x00;
-
+/* 2/ variable holding the controller chipset family value */
+static unsigned char chipset_family;

/*
* Debug code: following IDE config registers' changes
*/
#ifdef DEBUG
-/* Copy of IDE Config registers 0x00 -> 0x58
+/* Copy of IDE Config registers 0x00 -> 0x57
Fewer might be used depending on the actual chipset */
-static unsigned char ide_regs_copy[] = {
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0
-};
+static unsigned char ide_regs_copy[0x58];

static byte sis5513_max_config_register(void) {
- switch(dma_capability) {
+ switch(chipset_family) {
case ATA_00:
case ATA_16: return 0x4f;
case ATA_33: return 0x52;
@@ -185,7 +166,7 @@
static const struct {
const char *name;
unsigned short host_id;
- unsigned char dma_capability;
+ unsigned char chipset_family;
unsigned char flags;
} SiSHostChipInfo[] = {
{ "SiS750", PCI_DEVICE_ID_SI_750, ATA_100, SIS5513_LATENCY },
@@ -211,7 +192,7 @@

/* Cycle time bits and values vary accross chip dma capabilities
These three arrays hold the register layout and the values to set.
- Indexed by dma_capability and (dma_mode - XFER_UDMA_0) */
+ Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */
static byte cycle_time_offset[] = {0,0,5,4,4,0,0};
static byte cycle_time_range[] = {0,0,2,3,3,4,4};
static byte cycle_time_value[][XFER_UDMA_5 - XFER_UDMA_0 + 1] = {
@@ -293,13 +274,13 @@
pci_read_config_byte(bmide_dev, 0x45+2*pos, &reg11);

/* UDMA */
- if (dma_capability >= ATA_33) {
+ if (chipset_family >= ATA_33) {
p += sprintf(p, " UDMA %s \t \t \t UDMA %s\n",
(reg01 & 0x80) ? "Enabled" : "Disabled",
(reg11 & 0x80) ? "Enabled" : "Disabled");

p += sprintf(p, " UDMA Cycle Time ");
- switch(dma_capability) {
+ switch(chipset_family) {
case ATA_33: p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break;
case ATA_66:
case ATA_100a: p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break;
@@ -308,7 +289,7 @@
default: p += sprintf(p, "133+ ?"); break;
}
p += sprintf(p, " \t UDMA Cycle Time ");
- switch(dma_capability) {
+ switch(chipset_family) {
case ATA_33: p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break;
case ATA_66:
case ATA_100a: p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break;
@@ -321,7 +302,7 @@

/* Data Active */
p += sprintf(p, " Data Active Time ");
- switch(dma_capability) {
+ switch(chipset_family) {
case ATA_00:
case ATA_16: /* confirmed */
case ATA_33:
@@ -332,7 +313,7 @@
default: p += sprintf(p, "133+ ?"); break;
}
p += sprintf(p, " \t Data Active Time ");
- switch(dma_capability) {
+ switch(chipset_family) {
case ATA_00:
case ATA_16:
case ATA_33:
@@ -370,7 +351,7 @@
u16 reg2, reg3;

p += sprintf(p, "\nSiS 5513 ");
- switch(dma_capability) {
+ switch(chipset_family) {
case ATA_00: p += sprintf(p, "Unknown???"); break;
case ATA_16: p += sprintf(p, "DMA 16"); break;
case ATA_33: p += sprintf(p, "Ultra 33"); break;
@@ -386,7 +367,7 @@
/* Status */
pci_read_config_byte(bmide_dev, 0x4a, &reg);
p += sprintf(p, "Channel Status: ");
- if (dma_capability < ATA_66) {
+ if (chipset_family < ATA_66) {
p += sprintf(p, "%s \t \t \t \t %s\n",
(reg & 0x04) ? "On" : "Off",
(reg & 0x02) ? "On" : "Off");
@@ -403,7 +384,7 @@
(reg & 0x04) ? "Native" : "Compatible");

/* 80-pin cable ? */
- if (dma_capability > ATA_33) {
+ if (chipset_family > ATA_33) {
pci_read_config_byte(bmide_dev, 0x48, &reg);
p += sprintf(p, "Cable Type: %s \t \t \t %s\n",
(reg & 0x10) ? cable_type[1] : cable_type[0],
@@ -507,7 +488,7 @@
}

/* register layout changed with newer ATA100 chips */
- if (dma_capability < ATA_100) {
+ if (chipset_family < ATA_100) {
pci_read_config_byte(dev, drive_pci, &test1);
pci_read_config_byte(dev, drive_pci+1, &test2);

@@ -587,7 +568,7 @@

pci_read_config_byte(dev, drive_pci+1, &reg);
/* Disable UDMA bit for non UDMA modes on UDMA chips */
- if ((speed < XFER_UDMA_0) && (dma_capability > ATA_16)) {
+ if ((speed < XFER_UDMA_0) && (chipset_family > ATA_16)) {
reg &= 0x7F;
pci_write_config_byte(dev, drive_pci+1, reg);
}
@@ -604,11 +585,11 @@
/* Force the UDMA bit on if we want to use UDMA */
reg |= 0x80;
/* clean reg cycle time bits */
- reg &= ~((0xFF >> (8 - cycle_time_range[dma_capability]))
- << cycle_time_offset[dma_capability]);
+ reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family]))
+ << cycle_time_offset[chipset_family]);
/* set reg cycle time bits */
- reg |= cycle_time_value[dma_capability-ATA_00][speed-XFER_UDMA_0]
- << cycle_time_offset[dma_capability];
+ reg |= cycle_time_value[chipset_family-ATA_00][speed-XFER_UDMA_0]
+ << cycle_time_offset[chipset_family];
pci_write_config_byte(dev, drive_pci+1, reg);
break;
case XFER_MW_DMA_2:
@@ -624,7 +605,7 @@
case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2));
case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1));
case XFER_PIO_0:
- default: return((int) config_chipset_for_pio(drive, 0));
+ default: return((int) config_chipset_for_pio(drive, 0));
}
drive->current_speed = speed;
#ifdef DEBUG
@@ -657,17 +638,17 @@
drive->dn, ultra);
#endif

- if ((id->dma_ultra & 0x0020) && ultra && udma_66 && (dma_capability >= ATA_100a))
+ if ((id->dma_ultra & 0x0020) && ultra && udma_66 && (chipset_family >= ATA_100a))
speed = XFER_UDMA_5;
- else if ((id->dma_ultra & 0x0010) && ultra && udma_66 && (dma_capability >= ATA_66))
+ else if ((id->dma_ultra & 0x0010) && ultra && udma_66 && (chipset_family >= ATA_66))
speed = XFER_UDMA_4;
- else if ((id->dma_ultra & 0x0008) && ultra && udma_66 && (dma_capability >= ATA_66))
+ else if ((id->dma_ultra & 0x0008) && ultra && udma_66 && (chipset_family >= ATA_66))
speed = XFER_UDMA_3;
- else if ((id->dma_ultra & 0x0004) && ultra && (dma_capability >= ATA_33))
+ else if ((id->dma_ultra & 0x0004) && ultra && (chipset_family >= ATA_33))
speed = XFER_UDMA_2;
- else if ((id->dma_ultra & 0x0002) && ultra && (dma_capability >= ATA_33))
+ else if ((id->dma_ultra & 0x0002) && ultra && (chipset_family >= ATA_33))
speed = XFER_UDMA_1;
- else if ((id->dma_ultra & 0x0001) && ultra && (dma_capability >= ATA_33))
+ else if ((id->dma_ultra & 0x0001) && ultra && (chipset_family >= ATA_33))
speed = XFER_UDMA_0;
else if (id->dma_mword & 0x0004)
speed = XFER_MW_DMA_2;
@@ -700,6 +681,8 @@
struct hd_driveid *id = drive->id;
ide_dma_action_t dma_func = ide_dma_off_quietly;

+ config_chipset_for_pio(drive, 5);
+
if (id && (id->capability & 1) && drive->channel->autodma) {
/* Consult the list of known "bad" drives */
if (ide_dmaproc(ide_dma_bad_drive, drive)) {
@@ -764,10 +747,6 @@
struct pci_dev *host;
int i = 0;

-#ifdef DEBUG
- sis5513_print_registers(dev, "pci_init_sis5513 start");
-#endif
-
/* Find the chip */
for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !host_dev; i++) {
host = pci_find_device (PCI_VENDOR_ID_SI,
@@ -777,12 +756,16 @@
continue;

host_dev = host;
- dma_capability = SiSHostChipInfo[i].dma_capability;
+ chipset_family = SiSHostChipInfo[i].chipset_family;
printk(SiSHostChipInfo[i].name);
printk("\n");

+#ifdef DEBUG
+ sis5513_print_registers(dev, "pci_init_sis5513 start");
+#endif
+
if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) {
- byte latency = (dma_capability == ATA_100)? 0x80 : 0x10; /* Lacking specs */
+ byte latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */
pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
}
}
@@ -792,7 +775,7 @@
2/ tell old chips to allow per drive IDE timings */
if (host_dev) {
byte reg;
- switch(dma_capability) {
+ switch(chipset_family) {
case ATA_133:
case ATA_100:
/* Set compatibility bit */
@@ -847,7 +830,7 @@
byte mask = hwif->unit ? 0x20 : 0x10;
pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);

- if (dma_capability >= ATA_66) {
+ if (chipset_family >= ATA_66) {
ata66 = (reg48h & mask) ? 0 : 1;
}
return ata66;
@@ -866,7 +849,7 @@

if (host_dev) {
#ifdef CONFIG_BLK_DEV_IDEDMA
- if (dma_capability > ATA_16) {
+ if (chipset_family > ATA_16) {
hwif->autodma = noautodma ? 0 : 1;
hwif->highmem = 1;
hwif->dmaproc = &sis5513_dmaproc;
diff -urN linux-2.5.8-pre2/drivers/ide/trm290.c linux/drivers/ide/trm290.c
--- linux-2.5.8-pre2/drivers/ide/trm290.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/trm290.c Mon Apr 8 19:01:19 2002
@@ -248,8 +248,19 @@

if ((reg & 0x10))
hwif->irq = hwif->unit ? 15 : 14; /* legacy mode */
- else if (!hwif->irq && hwif->mate && hwif->mate->irq)
- hwif->irq = hwif->mate->irq; /* sharing IRQ with mate */
+ else {
+ static int primary_irq = 0;
+
+ /* Ugly way to let the primary and secondary channel on the
+ * chip use the same IRQ line.
+ */
+
+ if (hwif->unit == ATA_PRIMARY)
+ primary_irq = hwif->irq;
+ else if (!hwif->irq)
+ hwif->irq = primary_irq;
+ }
+
ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->unit ? 0x0080 : 0x0000), 3);

#ifdef CONFIG_BLK_DEV_IDEDMA
diff -urN linux-2.5.8-pre2/drivers/ide/umc8672.c linux/drivers/ide/umc8672.c
--- linux-2.5.8-pre2/drivers/ide/umc8672.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/umc8672.c Mon Apr 8 16:29:16 2002
@@ -146,7 +146,7 @@
{
__restore_flags(flags); /* local CPU only */
printk ("umc8672: not found\n");
- return;
+ return;
}
outb_p (0xa5,0x108); /* disable umc */

@@ -158,7 +158,6 @@
ide_hwifs[1].chipset = ide_umc8672;
ide_hwifs[0].tuneproc = &tune_umc;
ide_hwifs[1].tuneproc = &tune_umc;
- ide_hwifs[0].mate = &ide_hwifs[1];
- ide_hwifs[1].mate = &ide_hwifs[0];
- ide_hwifs[1].unit = 1;
+ ide_hwifs[0].unit = ATA_PRIMARY;
+ ide_hwifs[1].unit = ATA_SECONDARY;
}
diff -urN linux-2.5.8-pre2/include/linux/ide.h linux/include/linux/ide.h
--- linux-2.5.8-pre2/include/linux/ide.h Mon Apr 8 21:12:46 2002
+++ linux/include/linux/ide.h Mon Apr 8 20:01:44 2002
@@ -433,10 +433,10 @@
typedef void (ide_maskproc_t) (ide_drive_t *, int);
typedef void (ide_rw_proc_t) (ide_drive_t *, ide_dma_action_t);

-/*
- * ide soft-power support
- */
-typedef int (ide_busproc_t) (ide_drive_t *, int);
+enum {
+ ATA_PRIMARY = 0,
+ ATA_SECONDARY = 1
+};

struct ata_channel {
struct device dev; /* device handle */
@@ -467,7 +467,6 @@
struct scatterlist *sg_table; /* Scatter-gather list used to build the above */
int sg_nents; /* Current number of entries in it */
int sg_dma_direction; /* dma transfer direction */
- struct ata_channel *mate; /* other hwif from same PCI chip */
unsigned long dma_base; /* base addr for dma ports */
unsigned dma_extra; /* extra addr for dma ports */
unsigned long config_data; /* for use by chipset-specific code */
@@ -480,7 +479,7 @@
hwif_chipset_t chipset; /* sub-module for tuning.. */
unsigned noprobe : 1; /* don't probe for this interface */
unsigned present : 1; /* there is a device on this interface */
- unsigned serialized : 1; /* serialized operation with mate hwif */
+ unsigned serialized : 1; /* serialized operation between channels */
unsigned sharing_irq: 1; /* 1 = sharing irq with another hwif */
unsigned reset : 1; /* reset after probe */
unsigned autodma : 1; /* automatically try to enable DMA at boot */
@@ -490,7 +489,7 @@
unsigned long last_time; /* time when previous rq was done */
#endif
byte straight8; /* Alan's straight 8 check */
- ide_busproc_t *busproc; /* driver soft-power interface */
+ int (*busproc)(ide_drive_t *, int); /* driver soft-power interface */
byte bus_state; /* power state of the IDE bus */
};

@@ -513,7 +512,6 @@
*/
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


Attachments:
ide-clean-29b.diff (89.16 kB)

2002-04-10 14:16:15

by Martin Dalecki

[permalink] [raw]
Subject: [PATCH] 2.5.8-pre3 IDE 30

diff -urN linux-2.5.8-pre2/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c
--- linux-2.5.8-pre2/drivers/ide/ide-disk.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/ide-disk.c Tue Apr 9 02:25:53 2002
@@ -154,7 +154,7 @@
{
struct hd_drive_task_hdr taskfile;
struct hd_drive_hob_hdr hobfile;
- ide_task_t args;
+ struct ata_taskfile args;
int sectors;

unsigned int track = (block / drive->sect);
@@ -193,19 +193,14 @@
ide_cmd_type_parser(&args);
rq->special = &args;

- return ata_taskfile(drive,
- &args.taskfile,
- &args.hobfile,
- args.handler,
- args.prehandler,
- rq);
+ return ata_taskfile(drive, &args, rq);
}

static ide_startstop_t lba28_do_request(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;
+ struct ata_taskfile args;
int sectors;

sectors = rq->nr_sectors;
@@ -239,12 +234,7 @@
ide_cmd_type_parser(&args);
rq->special = &args;

- return ata_taskfile(drive,
- &args.taskfile,
- &args.hobfile,
- args.handler,
- args.prehandler,
- rq);
+ return ata_taskfile(drive, &args, rq);
}

/*
@@ -257,7 +247,7 @@
{
struct hd_drive_task_hdr taskfile;
struct hd_drive_hob_hdr hobfile;
- ide_task_t args;
+ struct ata_taskfile args;
int sectors;

memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
@@ -302,12 +292,7 @@
ide_cmd_type_parser(&args);
rq->special = &args;

- return ata_taskfile(drive,
- &args.taskfile,
- &args.hobfile,
- args.handler,
- args.prehandler,
- rq);
+ return ata_taskfile(drive, &args, rq);
}

/*
@@ -426,7 +411,8 @@
*/
static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
{
- ide_task_t args;
+ /* FIXME: This is on stack! */
+ struct ata_taskfile args;
unsigned long addr = 0;

if (!(drive->id->command_set_1 & 0x0400) &&
@@ -434,7 +420,7 @@
return addr;

/* Create IDE/ATA command request structure */
- memset(&args, 0, sizeof(ide_task_t));
+ memset(&args, 0, sizeof(args));
args.taskfile.device_head = 0x40;
args.taskfile.command = WIN_READ_NATIVE_MAX;
args.handler = task_no_data_intr;
@@ -457,11 +443,11 @@

static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive)
{
- ide_task_t args;
+ struct ata_taskfile args;
unsigned long long addr = 0;

/* Create IDE/ATA command request structure */
- memset(&args, 0, sizeof(ide_task_t));
+ memset(&args, 0, sizeof(args));

args.taskfile.device_head = 0x40;
args.taskfile.command = WIN_READ_NATIVE_MAX_EXT;
@@ -493,12 +479,12 @@
*/
static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req)
{
- ide_task_t args;
+ struct ata_taskfile args;
unsigned long addr_set = 0;

addr_req--;
/* Create IDE/ATA command request structure */
- memset(&args, 0, sizeof(ide_task_t));
+ memset(&args, 0, sizeof(args));

args.taskfile.sector_number = (addr_req >> 0);
args.taskfile.low_cylinder = (addr_req >> 8);
@@ -522,12 +508,12 @@

static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req)
{
- ide_task_t args;
+ struct ata_taskfile args;
unsigned long long addr_set = 0;

addr_req--;
/* Create IDE/ATA command request structure */
- memset(&args, 0, sizeof(ide_task_t));
+ memset(&args, 0, sizeof(args));

args.taskfile.sector_number = (addr_req >> 0);
args.taskfile.low_cylinder = (addr_req >>= 8);
@@ -667,47 +653,45 @@
special_t *s = &drive->special;

if (s->b.set_geometry) {
- 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));
+ struct ata_taskfile args;

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;
+
+ memset(&args, 0, sizeof(args));
+ args.taskfile.sector_number = drive->sect;
+ args.taskfile.low_cylinder = drive->cyl;
+ args.taskfile.high_cylinder = drive->cyl>>8;
+ args.taskfile.device_head = ((drive->head-1)|drive->select.all)&0xBF;
if (!IS_PDC4030_DRIVE) {
- taskfile.sector_count = drive->sect;
- taskfile.command = WIN_SPECIFY;
- handler = set_geometry_intr;;
+ args.taskfile.sector_count = drive->sect;
+ args.taskfile.command = WIN_SPECIFY;
+ args.handler = set_geometry_intr;;
}
- ata_taskfile(drive, &taskfile, &hobfile, handler, NULL, NULL);
+ ata_taskfile(drive, &args, NULL);
} else if (s->b.recalibrate) {
s->b.recalibrate = 0;
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;
- ata_taskfile(drive, &taskfile, &hobfile, recal_intr, NULL, NULL);
+ struct ata_taskfile args;
+
+ memset(&args, 0, sizeof(args));
+ args.taskfile.sector_count = drive->sect;
+ args.taskfile.command = WIN_RESTORE;
+ args.handler = recal_intr;
+ ata_taskfile(drive, &args, NULL);
}
} 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) {
- 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;
- ata_taskfile(drive, &taskfile, &hobfile, set_multmode_intr, NULL, NULL);
+ struct ata_taskfile args;
+
+ memset(&args, 0, sizeof(args));
+ args.taskfile.sector_count = drive->mult_req;
+ args.taskfile.command = WIN_SETMULT;
+ args.handler = set_multmode_intr;
+
+ ata_taskfile(drive, &args, NULL);
}
} else if (s->all) {
int special = s->all;
diff -urN linux-2.5.8-pre2/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c
--- linux-2.5.8-pre2/drivers/ide/ide-dma.c Tue Apr 9 20:36:00 2002
+++ linux/drivers/ide/ide-dma.c Tue Apr 9 01:43:45 2002
@@ -82,6 +82,7 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ide.h>
+#include <linux/delay.h>

#include <asm/io.h>
#include <asm/irq.h>
@@ -238,29 +239,33 @@
return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
}

-static int ide_raw_build_sglist(struct ata_channel *hwif, struct request *rq)
+/*
+ * FIXME: taskfiles should be a map of pages, not a long virt address... /jens
+ * FIXME: I agree with Jens --mdcki!
+ */
+static int raw_build_sglist(struct ata_channel *ch, struct request *rq)
{
- struct scatterlist *sg = hwif->sg_table;
+ struct scatterlist *sg = ch->sg_table;
int nents = 0;
- ide_task_t *args = rq->special;
+ struct ata_taskfile *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);
+ nents = blk_rq_map_sg(rq->q, rq, ch->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;
+ ch->sg_dma_direction = PCI_DMA_TODEVICE;
else
- hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+ ch->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;
@@ -273,9 +278,8 @@
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);
+ return pci_map_sg(ch->pci_dev, sg, nents, ch->sg_dma_direction);
}

/*
@@ -297,7 +301,7 @@
struct scatterlist *sg;

if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
- hwif->sg_nents = i = ide_raw_build_sglist(hwif, HWGROUP(drive)->rq);
+ hwif->sg_nents = i = raw_build_sglist(hwif, HWGROUP(drive)->rq);
} else {
hwif->sg_nents = i = ide_build_sglist(hwif, HWGROUP(drive)->rq);
}
@@ -593,7 +597,7 @@
ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry); /* issue cmd to drive */
if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) &&
(drive->addressing == 1)) {
- ide_task_t *args = HWGROUP(drive)->rq->special;
+ struct ata_taskfile *args = HWGROUP(drive)->rq->special;
OUT_BYTE(args->taskfile.command, IDE_COMMAND_REG);
} else if (drive->addressing) {
OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
diff -urN linux-2.5.8-pre2/drivers/ide/ide-features.c linux/drivers/ide/ide-features.c
--- linux-2.5.8-pre2/drivers/ide/ide-features.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/ide-features.c Tue Apr 9 01:42:38 2002
@@ -184,7 +184,7 @@
* 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, ide_task_t *args)
+int ide_ata66_check (ide_drive_t *drive, struct ata_taskfile *args)
{
if ((args->taskfile.command == WIN_SETFEATURES) &&
(args->taskfile.sector_number > XFER_UDMA_2) &&
@@ -211,7 +211,7 @@
* 1 : Safe to update drive->id DMA registers.
* 0 : OOPs not allowed.
*/
-int set_transfer (ide_drive_t *drive, ide_task_t *args)
+int set_transfer (ide_drive_t *drive, struct ata_taskfile *args)
{
if ((args->taskfile.command == WIN_SETFEATURES) &&
(args->taskfile.sector_number >= XFER_SW_DMA_0) &&
diff -urN linux-2.5.8-pre2/drivers/ide/ide-pmac.c linux/drivers/ide/ide-pmac.c
--- linux-2.5.8-pre2/drivers/ide/ide-pmac.c Tue Apr 9 20:36:00 2002
+++ linux/drivers/ide/ide-pmac.c Tue Apr 9 01:53:06 2002
@@ -1055,13 +1055,13 @@
}

static int
-pmac_ide_raw_build_sglist (int ix, struct request *rq)
+pmac_raw_build_sglist (int ix, struct request *rq)
{
struct ata_channel *hwif = &ide_hwifs[ix];
struct pmac_ide_hwif *pmif = &pmac_ide[ix];
struct scatterlist *sg = pmif->sg_table;
int nents = 0;
- ide_task_t *args = rq->special;
+ struct ata_taskfile *args = rq->special;
unsigned char *virt_addr = rq->buffer;
int sector_count = rq->nr_sectors;

@@ -1111,7 +1111,7 @@

/* Build sglist */
if (rq->flags & REQ_DRIVE_TASKFILE) {
- pmac_ide[ix].sg_nents = i = pmac_ide_raw_build_sglist(ix, rq);
+ pmac_ide[ix].sg_nents = i = pmac_raw_build_sglist(ix, rq);
} else {
pmac_ide[ix].sg_nents = i = pmac_ide_build_sglist(ix, rq);
}
@@ -1389,7 +1389,7 @@
ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) &&
(drive->addressing == 1)) {
- ide_task_t *args = HWGROUP(drive)->rq->special;
+ struct ata_taskfile *args = HWGROUP(drive)->rq->special;
OUT_BYTE(args->taskfile.command, IDE_COMMAND_REG);
} else if (drive->addressing) {
OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
diff -urN linux-2.5.8-pre2/drivers/ide/ide-taskfile.c linux/drivers/ide/ide-taskfile.c
--- linux-2.5.8-pre2/drivers/ide/ide-taskfile.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/ide-taskfile.c Tue Apr 9 02:48:27 2002
@@ -291,7 +291,7 @@

static ide_startstop_t pre_task_mulout_intr(ide_drive_t *drive, struct request *rq)
{
- ide_task_t *args = rq->special;
+ struct ata_taskfile *args = rq->special;
ide_startstop_t startstop;

/*
@@ -303,6 +303,7 @@
return startstop;

ata_poll_drive_ready(drive);
+
return args->handler(drive);
}

@@ -391,18 +392,13 @@
}

ide_startstop_t ata_taskfile(ide_drive_t *drive,
- struct hd_drive_task_hdr *taskfile,
- struct hd_drive_hob_hdr *hobfile,
- ide_handler_t *handler,
- ide_pre_handler_t *prehandler,
- struct request *rq
- )
+ struct ata_taskfile *args, struct request *rq)
{
struct hd_driveid *id = drive->id;
u8 HIHI = (drive->addressing) ? 0xE0 : 0xEF;

/* (ks/hs): Moved to start, do not use for multiple out commands */
- if (handler != task_mulout_intr) {
+ if (args->handler != task_mulout_intr) {
if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */
SELECT_MASK(drive->channel, drive, 0);
@@ -411,35 +407,38 @@
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(args->hobfile.feature, IDE_FEATURE_REG);
+ OUT_BYTE(args->hobfile.sector_count, IDE_NSECTOR_REG);
+ OUT_BYTE(args->hobfile.sector_number, IDE_SECTOR_REG);
+ OUT_BYTE(args->hobfile.low_cylinder, IDE_LCYL_REG);
+ OUT_BYTE(args->hobfile.high_cylinder, IDE_HCYL_REG);
}

- OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
- OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+ OUT_BYTE(args->taskfile.feature, IDE_FEATURE_REG);
+ OUT_BYTE(args->taskfile.sector_count, IDE_NSECTOR_REG);
/* refers to number of sectors to transfer */
- OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+ OUT_BYTE(args->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(args->taskfile.low_cylinder, IDE_LCYL_REG);
+ OUT_BYTE(args->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);
+ OUT_BYTE((args->taskfile.device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
+ if (args->handler != NULL) {
+ ide_set_handler(drive, args->handler, WAIT_CMD, NULL);
+ OUT_BYTE(args->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 (prehandler != NULL)
- return prehandler(drive, rq);
+ if (args->prehandler != NULL)
+ return args->prehandler(drive, rq);
} else {
/* for dma commands we down set the handler */
- if (drive->using_dma && !(drive->channel->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
+ if (drive->using_dma &&
+ !(drive->channel->dmaproc(((args->taskfile.command == WIN_WRITEDMA)
+ || (args->taskfile.command == WIN_WRITEDMA_EXT))
+ ? ide_dma_write : ide_dma_read, drive)));
}

return ide_started;
@@ -496,7 +495,7 @@
*/
ide_startstop_t task_no_data_intr (ide_drive_t *drive)
{
- ide_task_t *args = HWGROUP(drive)->rq->special;
+ struct ata_taskfile *args = HWGROUP(drive)->rq->special;
byte stat = GET_STAT();

ide__sti(); /* local CPU only */
@@ -554,9 +553,9 @@
return ide_stopped;
}

-static ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
+static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq)
{
- ide_task_t *args = rq->special;
+ struct ata_taskfile *args = rq->special;
ide_startstop_t startstop;

if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
@@ -669,7 +668,7 @@
}

/* Called by ioctl to feature out type of command being called */
-void ide_cmd_type_parser(ide_task_t *args)
+void ide_cmd_type_parser(struct ata_taskfile *args)
{
struct hd_drive_task_hdr *taskfile = &args->taskfile;

@@ -877,9 +876,9 @@
{
struct request rq;
/* FIXME: This is on stack! */
- ide_task_t args;
+ struct ata_taskfile args;

- memset(&args, 0, sizeof(ide_task_t));
+ memset(&args, 0, sizeof(args));

args.taskfile = *taskfile;
args.hobfile = *hobfile;
@@ -897,7 +896,7 @@
return ide_do_drive_cmd(drive, &rq, ide_wait);
}

-int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *args, byte *buf)
+int ide_raw_taskfile(ide_drive_t *drive, struct ata_taskfile *args, byte *buf)
{
struct request rq;
init_taskfile_request(&rq);
@@ -943,7 +942,8 @@
u8 *argbuf = args;
byte xfer_rate = 0;
int argsize = 4;
- ide_task_t tfargs;
+ /* FIXME: this should not reside on the stack */
+ struct ata_taskfile tfargs;

if (NULL == (void *) arg) {
struct request rq;
diff -urN linux-2.5.8-pre2/drivers/ide/ide.c linux/drivers/ide/ide.c
--- linux-2.5.8-pre2/drivers/ide/ide.c Tue Apr 9 20:36:00 2002
+++ linux/drivers/ide/ide.c Tue Apr 9 03:07:51 2002
@@ -709,7 +709,7 @@
/*
* Clean up after success/failure of an explicit drive cmd
*/
-void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
+void ide_end_drive_cmd(ide_drive_t *drive, byte stat, byte err)
{
unsigned long flags;
struct request *rq;
@@ -738,8 +738,8 @@
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);
+ struct ata_taskfile *args = rq->special;
+ rq->errors = !OK_STAT(stat, READY_STAT, BAD_STAT);
if (args) {
args->taskfile.feature = err;
args->taskfile.sector_count = IN_BYTE(IDE_NSECTOR_REG);
@@ -1023,9 +1023,9 @@
}

/*
- * start_request() initiates handling of a new I/O request
+ * This initiates handling of a new I/O request.
*/
-static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
+static ide_startstop_t start_request(ide_drive_t *drive, struct request *rq)
{
ide_startstop_t startstop;
unsigned long block;
@@ -1083,15 +1083,12 @@
*/

if (rq->flags & REQ_DRIVE_TASKFILE) {
- ide_task_t *args = rq->special;
+ struct ata_taskfile *args = rq->special;

if (!(args))
goto args_error;

- ata_taskfile(drive,
- &args->taskfile,
- &args->hobfile,
- args->handler, NULL, NULL);
+ ata_taskfile(drive, args, NULL);

if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) ||
(args->command_type == IDE_DRIVE_TASK_OUT)) &&
@@ -1185,7 +1182,7 @@
return ide_stopped;
}

-ide_startstop_t restart_request (ide_drive_t *drive)
+ide_startstop_t restart_request(ide_drive_t *drive)
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
unsigned long flags;
@@ -1417,9 +1414,9 @@
}

/*
- * ide_timer_expiry() is our timeout function for all drive operations.
- * But note that it can also be invoked as a result of a "sleep" operation
- * triggered by the mod_timer() call in ide_do_request.
+ * This is our timeout function for all drive operations. But note that it can
+ * also be invoked as a result of a "sleep" operation triggered by the
+ * mod_timer() call in ide_do_request.
*/
void ide_timer_expiry(unsigned long data)
{
@@ -1478,7 +1475,7 @@
disable_irq_nosync(hwif->irq);
#else
disable_irq(hwif->irq); /* disable_irq_nosync ?? */
-#endif /* DISABLE_IRQ_NOSYNC */
+#endif
__cli(); /* local CPU only, as if we were handling an interrupt */
if (hwgroup->poll_timeout != 0) {
startstop = handler(drive);
@@ -1608,7 +1605,8 @@
drive = hwgroup->drive;
if (!drive) {
/*
- * This should NEVER happen, and there isn't much we could do about it here.
+ * This should NEVER happen, and there isn't much we could do
+ * about it here.
*/
goto out_lock;
}
@@ -1734,9 +1732,9 @@
if (action == ide_preempt)
hwgroup->rq = NULL;
} else {
- if (action == ide_wait || action == ide_end) {
+ if (action == ide_wait || action == ide_end)
queue_head = queue_head->prev;
- } else
+ else
queue_head = queue_head->next;
}
q->elevator.elevator_add_req_fn(q, rq, queue_head);
@@ -1848,7 +1846,7 @@

/* Request a particular device type module.
*
- * FIXME: The function which should rather requests the drivers is
+ * FIXME: The function which should rather requests the drivers in
* ide_driver_module(), since it seems illogical and even a bit
* dangerous to delay this until open time!
*/
@@ -2088,7 +2086,7 @@
* it.
*/

- old_hwif = *channel;
+ old_hwif = *channel;
init_hwif_data(channel, channel->index);
channel->hwgroup = old_hwif.hwgroup;
channel->tuneproc = old_hwif.tuneproc;
diff -urN linux-2.5.8-pre2/drivers/ide/pdc4030.c linux/drivers/ide/pdc4030.c
--- linux-2.5.8-pre2/drivers/ide/pdc4030.c Tue Apr 9 20:36:00 2002
+++ linux/drivers/ide/pdc4030.c Tue Apr 9 01:45:39 2002
@@ -551,7 +551,7 @@
* 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, ide_task_t *task)
+ide_startstop_t do_pdc4030_io(ide_drive_t *drive, struct ata_taskfile *task)
{
struct request *rq = HWGROUP(drive)->rq;
struct hd_drive_task_hdr *taskfile = &task->taskfile;
@@ -644,7 +644,7 @@
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;
+ struct ata_taskfile args;

memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));

diff -urN linux-2.5.8-pre2/include/linux/ide.h linux/include/linux/ide.h
--- linux-2.5.8-pre2/include/linux/ide.h Tue Apr 9 20:36:00 2002
+++ linux/include/linux/ide.h Tue Apr 9 02:09:37 2002
@@ -13,7 +13,9 @@
#include <linux/proc_fs.h>
#include <linux/device.h>
#include <linux/devfs_fs_kernel.h>
+#include <linux/interrupt.h>
#include <asm/hdreg.h>
+#include <asm/bitops.h>

/*
* This is the multiple IDE interface driver, as evolved from hd.c.
@@ -111,6 +113,7 @@
#define GET_ERR() IN_BYTE(IDE_ERROR_REG)
#define GET_STAT() IN_BYTE(IDE_STATUS_REG)
#define GET_ALTSTAT() IN_BYTE(IDE_CONTROL_REG)
+#define GET_FEAT() IN_BYTE(IDE_NSECTOR_REG)
#define OK_STAT(stat,good,bad) (((stat)&((good)|(bad)))==(good))
#define BAD_R_STAT (BUSY_STAT | ERR_STAT)
#define BAD_W_STAT (BAD_R_STAT | WRERR_STAT)
@@ -132,6 +135,7 @@
*/
#define PRD_BYTES 8
#define PRD_ENTRIES (PAGE_SIZE / (2 * PRD_BYTES))
+#define PRD_SEGMENTS 32

/*
* Some more useful definitions
@@ -275,7 +279,7 @@
char type; /* distingiush different devices: disk, cdrom, tape, floppy, ... */

/* NOTE: If we had proper separation between channel and host chip, we
- * could move this to the chanell and many sync problems would
+ * could move this to the channel and many sync problems would
* magically just go away.
*/
request_queue_t queue; /* per device request queue */
@@ -500,16 +504,18 @@
extern void ide_unregister(struct ata_channel *hwif);

/*
- * Status returned from various ide_ functions
+ * Status returned by various functions.
*/
typedef enum {
ide_stopped, /* no drive operation was started */
- ide_started /* a drive operation was started, and a handler was set */
+ ide_started, /* a drive operation was started, and a handler was set */
+ ide_released /* started and released bus */
} ide_startstop_t;

/*
- * internal ide interrupt handler type
+ * Interrupt handler types.
*/
+struct ata_taskfile;
typedef ide_startstop_t (ide_pre_handler_t)(ide_drive_t *, struct request *);
typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);

@@ -519,15 +525,18 @@
*/
typedef int (ide_expiry_t)(ide_drive_t *);

-#define IDE_BUSY 0
+#define IDE_BUSY 0 /* awaiting an interrupt */
#define IDE_SLEEP 1
+#define IDE_DMA 2 /* DMA in progress */

typedef struct hwgroup_s {
ide_handler_t *handler;/* irq handler, if active */
unsigned long flags; /* BUSY, SLEEPING */
ide_drive_t *drive; /* current drive */
struct ata_channel *hwif; /* ptr to current hwif in linked-list */
+
struct request *rq; /* current request */
+
struct timer_list timer; /* failsafe timer */
struct request wrq; /* local copy of current write rq */
unsigned long poll_timeout; /* timeout value during long polls */
@@ -736,7 +745,7 @@
/*
* This function is intended to be used prior to invoking ide_do_drive_cmd().
*/
-void ide_init_drive_cmd (struct request *rq);
+extern void ide_init_drive_cmd (struct request *rq);

/*
* "action" parameter type for ide_do_drive_cmd() below.
@@ -760,13 +769,13 @@
*/
void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);

-typedef struct ide_task_s {
+struct ata_taskfile {
struct hd_drive_task_hdr taskfile;
struct hd_drive_hob_hdr hobfile;
int command_type;
ide_pre_handler_t *prehandler;
ide_handler_t *handler;
-} 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);
@@ -776,11 +785,7 @@
void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);

extern ide_startstop_t ata_taskfile(ide_drive_t *drive,
- struct hd_drive_task_hdr *taskfile,
- struct hd_drive_hob_hdr *hobfile,
- ide_handler_t *handler,
- ide_pre_handler_t *prehandler,
- struct request *rq);
+ struct ata_taskfile *args, struct request *rq);

/*
* Special Flagged Register Validation Caller
@@ -793,10 +798,11 @@

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);
+int ide_raw_taskfile (ide_drive_t *drive, struct ata_taskfile *cmd, byte *buf);

-/* Expects args is a full set of TF registers and parses the command type */
-extern void ide_cmd_type_parser(ide_task_t *args);
+/* This is setting up all fields in args, which depend upon the command type.
+ */
+extern void ide_cmd_type_parser(struct ata_taskfile *args);

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);
@@ -805,10 +811,10 @@

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, ide_task_t *args);
+int ide_ata66_check (ide_drive_t *drive, struct ata_taskfile *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, ide_task_t *args);
+int set_transfer (ide_drive_t *drive, struct ata_taskfile *args);

extern int system_bus_speed;

@@ -896,6 +902,8 @@

extern spinlock_t ide_lock;

+#define DRIVE_LOCK(drive) ((drive)->queue.queue_lock)
+
extern int drive_is_ready(ide_drive_t *drive);
extern void revalidate_drives(void);


Attachments:
ide-clean-30.diff (26.34 kB)

2002-04-10 14:18:53

by Martin Dalecki

[permalink] [raw]
Subject: [PATCH] 2.5.8-pre3 IDE 31

diff -urN linux-2.5.8-pre2/drivers/ide/Config.help linux/drivers/ide/Config.help
--- linux-2.5.8-pre2/drivers/ide/Config.help Mon Mar 18 21:37:18 2002
+++ linux/drivers/ide/Config.help Tue Apr 9 21:12:05 2002
@@ -744,6 +744,28 @@

Generally say N here.

+CONFIG_BLK_DEV_IDE_TCQ
+ Support for tagged command queueing on ATA disk drives. This enables
+ the IDE layer to have multiple in-flight requests on hardware that
+ supports it. For now this includes the IBM Deskstar series drives,
+ such as the GXP75, 40GV, GXP60, and GXP120 (ie any Deskstar made in
+ the last couple of years).
+
+ If you have such a drive, say Y here.
+
+CONFIG_BLK_DEV_IDE_TCQ_DEFAULT
+ Enabled tagged command queueing unconditionally on drives that report
+ support for it.
+
+ Generally say Y here.
+
+CONFIG_BLK_DEV_IDE_TCQ_DEPTH
+ Maximum size of commands to enable per-drive. Any value between 1
+ and 32 is valid, with 32 being the maxium that the hardware supports.
+
+ You probably just want the default of 32 here. If you enter an invalid
+ number, the default value will be used.
+
CONFIG_BLK_DEV_IT8172
Say Y here to support the on-board IDE controller on the Integrated
Technology Express, Inc. ITE8172 SBC. Vendor page at
diff -urN linux-2.5.8-pre2/drivers/ide/Config.in linux/drivers/ide/Config.in
--- linux-2.5.8-pre2/drivers/ide/Config.in Mon Mar 18 21:37:18 2002
+++ linux/drivers/ide/Config.in Wed Apr 10 00:00:37 2002
@@ -47,6 +47,11 @@
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 tagged command queueing' CONFIG_BLK_DEV_IDE_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI
+ dep_bool ' TCQ on by default' CONFIG_BLK_DEV_IDE_TCQ_DEFAULT $CONFIG_BLK_DEV_IDE_TCQ
+ if [ $CONFIG_BLK_DEV_IDE_TCQ_DEFAULT != "n" ]; then
+ int ' Default queue depth' CONFIG_BLK_DEV_IDE_TCQ_DEPTH 32
+ fi
dep_bool ' ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
dep_bool ' Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP
dep_bool ' AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
diff -urN linux-2.5.8-pre2/drivers/ide/Makefile linux/drivers/ide/Makefile
--- linux-2.5.8-pre2/drivers/ide/Makefile Mon Mar 18 21:37:05 2002
+++ linux/drivers/ide/Makefile Tue Apr 9 21:12:05 2002
@@ -45,6 +45,7 @@
ide-obj-$(CONFIG_BLK_DEV_HT6560B) += ht6560b.o
ide-obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o
ide-obj-$(CONFIG_BLK_DEV_IDEDMA_PCI) += ide-dma.o
+ide-obj-$(CONFIG_BLK_DEV_IDE_TCQ) += ide-tcq.o
ide-obj-$(CONFIG_BLK_DEV_IDEPCI) += ide-pci.o
ide-obj-$(CONFIG_BLK_DEV_ISAPNP) += ide-pnp.o
ide-obj-$(CONFIG_BLK_DEV_IDE_PMAC) += ide-pmac.o
diff -urN linux-2.5.8-pre2/drivers/ide/hpt366.c linux/drivers/ide/hpt366.c
--- linux-2.5.8-pre2/drivers/ide/hpt366.c Tue Apr 9 20:36:00 2002
+++ linux/drivers/ide/hpt366.c Wed Apr 10 01:10:06 2002
@@ -75,8 +75,6 @@
#include <linux/proc_fs.h>
#endif /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */

-extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
-
const char *quirk_drives[] = {
"QUANTUM FIREBALLlct08 08",
"QUANTUM FIREBALLP KA6.4",
@@ -815,10 +813,8 @@
pci_read_config_byte(drive->channel->pci_dev, 0x50, &reg50h);
pci_read_config_byte(drive->channel->pci_dev, 0x52, &reg52h);
pci_read_config_byte(drive->channel->pci_dev, 0x5a, &reg5ah);
- printk("%s: (%s) reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
- drive->name,
- ide_dmafunc_verbose(func),
- reg50h, reg52h, reg5ah);
+ printk("%s: (ide_dma_lostirq) reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
+ drive->name, reg50h, reg52h, reg5ah);
if (reg5ah & 0x10)
pci_write_config_byte(drive->channel->pci_dev, 0x5a, reg5ah & ~0x10);
/* fall through to a reset */
diff -urN linux-2.5.8-pre2/drivers/ide/icside.c linux/drivers/ide/icside.c
--- linux-2.5.8-pre2/drivers/ide/icside.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/icside.c Wed Apr 10 01:10:29 2002
@@ -27,7 +27,6 @@
#include <asm/io.h>

extern char *ide_xfer_verbose (byte xfer_rate);
-extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);

/*
* Maximum number of interfaces per card
@@ -467,8 +466,7 @@

case ide_dma_timeout:
default:
- printk("icside_dmaproc: unsupported %s func: %d\n",
- ide_dmafunc_verbose(func), func);
+ printk("icside_dmaproc: unsupported function: %d\n", func);
}
return 1;
}
diff -urN linux-2.5.8-pre2/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c
--- linux-2.5.8-pre2/drivers/ide/ide-disk.c Wed Apr 10 01:45:01 2002
+++ linux/drivers/ide/ide-disk.c Wed Apr 10 00:55:16 2002
@@ -1,34 +1,16 @@
/*
- * Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
+ * Copyright (C) 1994-1998 Linus Torvalds and authors:
*
- * Mostly written by Mark Lord <[email protected]>
- * and Gadi Oxman <[email protected]>
- * and Andre Hedrick <[email protected]>
+ * Mark Lord <[email protected]>
+ * Gadi Oxman <[email protected]>
+ * Andre Hedrick <[email protected]>
+ * Jens Axboe <[email protected]>
+ * Marcin Dalecki <[email protected]>
*
- * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c.
- *
- * Version 1.00 move disk only code from ide.c to ide-disk.c
- * support optional byte-swapping of all data
- * Version 1.01 fix previous byte-swapping code
- * Version 1.02 remove ", LBA" from drive identification msgs
- * Version 1.03 fix display of id->buf_size for big-endian
- * Version 1.04 add /proc configurable settings and S.M.A.R.T support
- * Version 1.05 add capacity support for ATA3 >= 8GB
- * Version 1.06 get boot-up messages to show full cyl count
- * Version 1.07 disable door-locking if it fails
- * Version 1.08 fixed CHS/LBA translations for ATA4 > 8GB,
- * process of adding new ATA4 compliance.
- * fixed problems in allowing fdisk to see
- * the entire disk.
- * Version 1.09 added increment of rq->sector in ide_multwrite
- * added UDMA 3/4 reporting
- * Version 1.10 request queue changes, Ultra DMA 100
- * Version 1.11 Highmem I/O support, Jens Axboe <[email protected]>
- * Version 1.12 added 48-bit lba
- * Version 1.13 adding taskfile io access method
+ * This is the ATA disk device driver, as evolved from hd.c and ide.c.
*/

-#define IDEDISK_VERSION "1.13"
+#define IDEDISK_VERSION "1.14"

#include <linux/config.h>
#include <linux/module.h>
@@ -57,7 +39,7 @@
#endif

/*
- * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
+ * Perform a sanity check on the claimed "lba_capacity"
* value for this drive (from its reported identification information).
*
* Returns: 1 if lba_capacity looks sensible
@@ -65,7 +47,7 @@
*
* It is called only once for each drive.
*/
-static int lba_capacity_is_ok (struct hd_driveid *id)
+static int lba_capacity_is_ok(struct hd_driveid *id)
{
unsigned long lba_sects, chs_sects, head, tail;

@@ -106,135 +88,163 @@
return 0; /* lba_capacity value may be bad */
}

+/*
+ * Determine the apriopriate hardware command correspnding to the action in
+ * question, depending upon the device capabilities and setup.
+ */
static u8 get_command(ide_drive_t *drive, int cmd)
{
int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
+ /* Well, calculating the command in this variable may be an
+ * overoptimization. */
+ u8 command = WIN_NOP;

#if 1
lba48bit = drive->addressing;
#endif

+ /*
+ * 48-bit commands are pretty sanely laid out
+ */
if (lba48bit) {
- if (cmd == READ) {
- if (drive->using_dma)
- return WIN_READDMA_EXT;
- else if (drive->mult_count)
- return WIN_MULTREAD_EXT;
- else
- return WIN_READ_EXT;
- } else if (cmd == WRITE) {
- if (drive->using_dma)
- return WIN_WRITEDMA_EXT;
- else if (drive->mult_count)
- return WIN_MULTWRITE_EXT;
- else
- return WIN_WRITE_EXT;
- }
+ if (cmd == READ)
+ command = WIN_READ_EXT;
+ else
+ command = WIN_WRITE_EXT;
+
+ if (drive->using_dma) {
+ command++; /* WIN_*DMA_EXT */
+ if (drive->using_tcq)
+ command++; /* WIN_*DMA_QUEUED_EXT */
+ } else if (drive->mult_count)
+ command += 5; /* WIN_MULT*_EXT */
} else {
+ /*
+ * 28-bit commands seem not to be, though...
+ */
if (cmd == READ) {
- if (drive->using_dma)
- return WIN_READDMA;
- else if (drive->mult_count)
- return WIN_MULTREAD;
+ if (drive->using_dma) {
+ if (drive->using_tcq)
+ command = WIN_READDMA_QUEUED;
+ else
+ command = WIN_READDMA;
+ } else if (drive->mult_count)
+ command = WIN_MULTREAD;
else
- return WIN_READ;
- } else if (cmd == WRITE) {
- if (drive->using_dma)
- return WIN_WRITEDMA;
- else if (drive->mult_count)
- return WIN_MULTWRITE;
+ command = WIN_READ;
+ } else {
+ if (drive->using_dma) {
+ if (drive->using_tcq)
+ command = WIN_WRITEDMA_QUEUED;
+ else
+ command = WIN_WRITEDMA;
+ } else if (drive->mult_count)
+ command = WIN_MULTWRITE;
else
- return WIN_WRITE;
+ command = WIN_WRITE;
}
}
- return WIN_NOP;
+
+ return command;
}

-static ide_startstop_t chs_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t chs_do_request(ide_drive_t *drive, struct ata_request *ar, sector_t block)
{
- struct hd_drive_task_hdr taskfile;
- struct hd_drive_hob_hdr hobfile;
- struct ata_taskfile args;
- int sectors;
+ struct ata_taskfile *args = &ar->ar_task;
+ struct request *rq = ar->ar_rq;
+ int sectors = rq->nr_sectors;

- 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);
+ 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(struct hd_drive_task_hdr));
- memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+ memset(&args->taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&args->hobfile, 0, sizeof(struct hd_drive_hob_hdr));

- sectors = rq->nr_sectors;
if (sectors == 256)
sectors = 0;

- taskfile.sector_count = sectors;
+ if (ar->ar_flags & ATA_AR_QUEUED) {
+ unsigned long flags;
+
+ args->taskfile.feature = sectors;
+ args->taskfile.sector_count = ar->ar_tag << 3;

- 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 = get_command(drive, rq_data_dir(rq));
+ spin_lock_irqsave(DRIVE_LOCK(drive), flags);
+ blkdev_dequeue_request(rq);
+ spin_unlock_irqrestore(DRIVE_LOCK(drive), flags);
+ } else
+ args->taskfile.sector_count = sectors;
+
+ args->taskfile.sector_number = sect;
+ args->taskfile.low_cylinder = cyl;
+ args->taskfile.high_cylinder = (cyl>>8);
+
+ args->taskfile.device_head = head;
+ args->taskfile.device_head |= drive->select.all;
+ args->taskfile.command = get_command(drive, rq_data_dir(rq));

#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("CHS=%d/%d/%d, ", cyl, head, sect);
printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
#endif

- args.taskfile = taskfile;
- args.hobfile = hobfile;
- ide_cmd_type_parser(&args);
- rq->special = &args;
+ ide_cmd_type_parser(args);
+ args->ar = ar;
+ rq->special = ar;

- return ata_taskfile(drive, &args, rq);
+ return ata_taskfile(drive, args, rq);
}

-static ide_startstop_t lba28_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t lba28_do_request(ide_drive_t *drive, struct ata_request *ar, sector_t block)
{
- struct hd_drive_task_hdr taskfile;
- struct hd_drive_hob_hdr hobfile;
- struct ata_taskfile args;
- int sectors;
+ struct ata_taskfile *args = &ar->ar_task;
+ struct request *rq = ar->ar_rq;
+ int sectors = rq->nr_sectors;

- sectors = rq->nr_sectors;
if (sectors == 256)
sectors = 0;

- memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
- memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+ memset(&args->taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&args->hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
+ if (ar->ar_flags & ATA_AR_QUEUED) {
+ unsigned long flags;
+
+ args->taskfile.feature = sectors;
+ args->taskfile.sector_count = ar->ar_tag << 3;

- taskfile.sector_count = 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 = get_command(drive, rq_data_dir(rq));
+ spin_lock_irqsave(DRIVE_LOCK(drive), flags);
+ blkdev_dequeue_request(rq);
+ spin_unlock_irqrestore(DRIVE_LOCK(drive), flags);
+ } else
+ args->taskfile.sector_count = sectors;
+
+ args->taskfile.sector_number = block;
+ args->taskfile.low_cylinder = (block >>= 8);
+
+ args->taskfile.high_cylinder = (block >>= 8);
+
+ args->taskfile.device_head = ((block >> 8) & 0x0f);
+ args->taskfile.device_head |= drive->select.all;
+ args->taskfile.command = get_command(drive, rq_data_dir(rq));

#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("sector=%lx, sectors=%ld, ", block, rq->nr_sectors);
printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
#endif

- args.taskfile = taskfile;
- args.hobfile = hobfile;
- ide_cmd_type_parser(&args);
- rq->special = &args;
+ ide_cmd_type_parser(args);
+ args->ar = ar;
+ rq->special = ar;

- return ata_taskfile(drive, &args, rq);
+ return ata_taskfile(drive, args, rq);
}

/*
@@ -242,57 +252,58 @@
* 320173056 == 163929 MB or 48bit addressing
* 1073741822 == 549756 MB or 48bit addressing fake drive
*/
-
-static ide_startstop_t lba48_do_request(ide_drive_t *drive, struct request *rq, unsigned long long block)
+static ide_startstop_t lba48_do_request(ide_drive_t *drive, struct ata_request *ar, sector_t block)
{
- struct hd_drive_task_hdr taskfile;
- struct hd_drive_hob_hdr hobfile;
- struct ata_taskfile args;
- int sectors;
+ struct ata_taskfile *args = &ar->ar_task;
+ struct request *rq = ar->ar_rq;
+ int sectors = rq->nr_sectors;

- memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
- memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+ memset(&args->taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&args->hobfile, 0, sizeof(struct hd_drive_hob_hdr));

- sectors = rq->nr_sectors;
if (sectors == 65536)
sectors = 0;

- taskfile.sector_count = sectors;
- hobfile.sector_count = sectors >> 8;
+ if (ar->ar_flags & ATA_AR_QUEUED) {
+ unsigned long flags;
+
+ args->taskfile.feature = sectors;
+ args->hobfile.feature = sectors >> 8;
+ args->taskfile.sector_count = ar->ar_tag << 3;
+
+ spin_lock_irqsave(DRIVE_LOCK(drive), flags);
+ blkdev_dequeue_request(rq);
+ spin_unlock_irqrestore(DRIVE_LOCK(drive), flags);
+ } else {
+ args->taskfile.sector_count = sectors;
+ args->hobfile.sector_count = 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 = get_command(drive, rq_data_dir(rq));
+ args->taskfile.sector_number = block;
+ args->taskfile.low_cylinder = (block >>= 8);
+ args->taskfile.high_cylinder = (block >>= 8);
+
+ args->hobfile.sector_number = (block >>= 8);
+ args->hobfile.low_cylinder = (block >>= 8);
+ args->hobfile.high_cylinder = (block >>= 8);
+
+ args->taskfile.device_head = drive->select.all;
+ args->hobfile.device_head = args->taskfile.device_head;
+ args->hobfile.control = (drive->ctl|0x80);
+ args->taskfile.command = get_command(drive, rq_data_dir(rq));

#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("sector=%lx, sectors=%ld, ", block, rq->nr_sectors);
printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
#endif

- args.taskfile = taskfile;
- args.hobfile = hobfile;
- ide_cmd_type_parser(&args);
- rq->special = &args;
+ ide_cmd_type_parser(args);
+ args->ar = ar;
+ rq->special = ar;

- return ata_taskfile(drive, &args, rq);
+ return ata_taskfile(drive, args, rq);
}

/*
@@ -300,8 +311,11 @@
* otherwise, to address sectors. It also takes care of issuing special
* DRIVE_CMDs.
*/
-static ide_startstop_t idedisk_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t idedisk_do_request(ide_drive_t *drive, struct request *rq, sector_t block)
{
+ unsigned long flags;
+ struct ata_request *ar;
+
/*
* Wait until all request have bin finished.
*/
@@ -323,16 +337,49 @@
return promise_rw_disk(drive, rq, block);
}

+ /*
+ * get a new command (push ar further down to avoid grabbing lock here
+ */
+ spin_lock_irqsave(DRIVE_LOCK(drive), flags);
+
+ ar = ata_ar_get(drive);
+
+ /*
+ * we've reached maximum queue depth, bail
+ */
+ if (!ar) {
+ spin_unlock_irqrestore(DRIVE_LOCK(drive), flags);
+ return ide_started;
+ }
+
+ ar->ar_rq = rq;
+
+ if (drive->using_tcq) {
+ int tag = ide_get_tag(drive);
+
+ BUG_ON(drive->tcq->active_tag != -1);
+
+ /* Set the tag: */
+ ar->ar_flags |= ATA_AR_QUEUED;
+ ar->ar_tag = tag;
+ drive->tcq->ar[tag] = ar;
+ drive->tcq->active_tag = tag;
+ ar->ar_time = jiffies;
+ drive->tcq->queued++;
+ }
+
+ spin_unlock_irqrestore(DRIVE_LOCK(drive), flags);
+
/* 48-bit LBA */
if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing))
- return lba48_do_request(drive, rq, block);
+ return lba48_do_request(drive, ar, block);

/* 28-bit LBA */
if (drive->select.b.lba)
- return lba28_do_request(drive, rq, block);
+ return lba28_do_request(drive, ar, block);

/* 28-bit CHS */
- return chs_do_request(drive, rq, block);
+ return chs_do_request(drive, ar, block);
}

static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
@@ -411,7 +458,6 @@
*/
static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
{
- /* FIXME: This is on stack! */
struct ata_taskfile args;
unsigned long addr = 0;

@@ -814,11 +860,71 @@
PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
}

+#ifdef CONFIG_BLK_DEV_IDE_TCQ
+static int proc_idedisk_read_tcq
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ char *out = page;
+ int len, cmds, i;
+ unsigned long tag_mask = 0, flags, cur_jif = jiffies, max_jif;
+
+ if (!drive->tcq) {
+ len = sprintf(out, "not configured\n");
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+ }
+
+ spin_lock_irqsave(&ide_lock, flags);
+
+ len = sprintf(out, "TCQ currently on:\t%s\n", drive->using_tcq ? "yes" : "no");
+ len += sprintf(out+len, "Max queue depth:\t%d\n",drive->queue_depth);
+ len += sprintf(out+len, "Max achieved depth:\t%d\n",drive->tcq->max_depth);
+ len += sprintf(out+len, "Max depth since last:\t%d\n",drive->tcq->max_last_depth);
+ len += sprintf(out+len, "Current depth:\t\t%d\n", drive->tcq->queued);
+ max_jif = 0;
+ len += sprintf(out+len, "Active tags:\t\t[ ");
+ for (i = 0, cmds = 0; i < drive->queue_depth; i++) {
+ struct ata_request *ar = IDE_GET_AR(drive, i);
+
+ if (!ar)
+ continue;
+
+ __set_bit(i, &tag_mask);
+ len += sprintf(out+len, "%d, ", i);
+ if (ar->ar_time > max_jif)
+ max_jif = ar->ar_time;
+ cmds++;
+ }
+ len += sprintf(out+len, "]\n");
+
+ if (drive->tcq->queued != cmds)
+ len += sprintf(out+len, "pending request and queue count mismatch (%d)\n", cmds);
+
+ if (tag_mask != drive->tcq->tag_mask)
+ len += sprintf(out+len, "tag masks differ (counted %lx != %lx\n", tag_mask, drive->tcq->tag_mask);
+
+ len += sprintf(out+len, "DMA status:\t\t%srunning\n", test_bit(IDE_DMA, &HWGROUP(drive)->flags) ? "" : "not ");
+
+ if (max_jif)
+ len += sprintf(out+len, "Oldest command:\t\t%lu\n", cur_jif - max_jif);
+
+ len += sprintf(out+len, "immed rel %d, immed comp %d\n", drive->tcq->immed_rel, drive->tcq->immed_comp);
+
+ drive->tcq->max_last_depth = 0;
+
+ spin_unlock_irqrestore(&ide_lock, flags);
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+#endif
+
static ide_proc_entry_t idedisk_proc[] = {
{ "cache", S_IFREG|S_IRUGO, proc_idedisk_read_cache, NULL },
{ "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL },
{ "smart_values", S_IFREG|S_IRUSR, proc_idedisk_read_smart_values, NULL },
{ "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_smart_thresholds, NULL },
+#ifdef CONFIG_BLK_DEV_IDE_TCQ
+ { "tcq", S_IFREG|S_IRUSR, proc_idedisk_read_tcq, NULL },
+#endif
{ NULL, 0, NULL, NULL }
};

@@ -855,7 +961,7 @@
return 0;
}

-static int write_cache (ide_drive_t *drive, int arg)
+static int write_cache(ide_drive_t *drive, int arg)
{
struct hd_drive_task_hdr taskfile;
struct hd_drive_hob_hdr hobfile;
@@ -872,7 +978,7 @@
return 0;
}

-static int idedisk_standby (ide_drive_t *drive)
+static int idedisk_standby(ide_drive_t *drive)
{
struct hd_drive_task_hdr taskfile;
struct hd_drive_hob_hdr hobfile;
@@ -882,7 +988,7 @@
return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
}

-static int set_acoustic (ide_drive_t *drive, int arg)
+static int set_acoustic(ide_drive_t *drive, int arg)
{
struct hd_drive_task_hdr taskfile;
struct hd_drive_hob_hdr hobfile;
@@ -898,6 +1004,22 @@
return 0;
}

+#ifdef CONFIG_BLK_DEV_IDE_TCQ
+static int set_using_tcq(ide_drive_t *drive, int arg)
+{
+ if (!drive->driver)
+ return -EPERM;
+ if (!drive->channel->dmaproc)
+ return -EPERM;
+
+ drive->using_tcq = arg;
+ if (drive->channel->dmaproc(arg ? ide_dma_queued_on : ide_dma_queued_off, drive))
+ return -EIO;
+
+ return 0;
+}
+#endif
+
static int probe_lba_addressing (ide_drive_t *drive, int arg)
{
drive->addressing = 0;
@@ -930,6 +1052,9 @@
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);
+#ifdef CONFIG_BLK_DEV_IDE_TCQ
+ ide_add_setting(drive, "using_tcq", SETTING_RW, HDIO_GET_QDMA, HDIO_SET_QDMA, TYPE_BYTE, 0, IDE_MAX_TAG, 1, 1, &drive->using_tcq, set_using_tcq);
+#endif
}

static int idedisk_suspend(struct device *dev, u32 state, u32 level)
@@ -1025,12 +1150,12 @@
*/

if (drvid != -1) {
- sprintf(drive->device.bus_id, "%d", drvid);
- sprintf(drive->device.name, "ide-disk");
- drive->device.driver = &idedisk_devdrv;
- drive->device.parent = &drive->channel->dev;
- drive->device.driver_data = drive;
- device_register(&drive->device);
+ sprintf(drive->device.bus_id, "%d", drvid);
+ sprintf(drive->device.name, "ide-disk");
+ drive->device.driver = &idedisk_devdrv;
+ drive->device.parent = &drive->channel->dev;
+ drive->device.driver_data = drive;
+ device_register(&drive->device);
}

/* Extract geometry if we did not already have one for the drive */
@@ -1102,7 +1227,7 @@
drive->no_io_32bit = id->dword_io ? 1 : 0;
if (drive->id->cfs_enable_2 & 0x3000)
write_cache(drive, (id->cfs_enable_2 & 0x3000));
- (void) probe_lba_addressing(drive, 1);
+ probe_lba_addressing(drive, 1);
}

static int idedisk_cleanup(ide_drive_t *drive)
diff -urN linux-2.5.8-pre2/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c
--- linux-2.5.8-pre2/drivers/ide/ide-dma.c Wed Apr 10 01:45:01 2002
+++ linux/drivers/ide/ide-dma.c Wed Apr 10 01:12:46 2002
@@ -1,13 +1,10 @@
/*
- * Copyright (c) 1999-2000 Andre Hedrick <[email protected]>
- * May be copied or modified under the terms of the GNU General Public License
- */
-
-/*
- * Special Thanks to Mark for his Six years of work.
- *
+ * Copyright (c) 1999-2000 Andre Hedrick <[email protected]>
* Copyright (c) 1995-1998 Mark Lord
+ *
* May be copied or modified under the terms of the GNU General Public License
+ *
+ * Special Thanks to Mark for his Six years of work.
*/

/*
@@ -98,8 +95,6 @@
#define DEFAULT_BMCRBA 0xcc00 /* VIA's default value */
#define DEFAULT_BMALIBA 0xd400 /* ALI's default value */

-extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
-
#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS

struct drive_list_entry {
@@ -214,29 +209,36 @@
__ide_end_request(drive, 1, rq->nr_sectors);
return ide_stopped;
}
- printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n",
+ printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n",
drive->name, dma_stat);
}
return ide_error(drive, "dma_intr", stat);
}

-static int ide_build_sglist(struct ata_channel *hwif, struct request *rq)
+int ide_build_sglist(struct ata_channel *hwif, struct request *rq)
{
request_queue_t *q = &hwif->drives[DEVICE_NR(rq->rq_dev) & 1].queue;
- struct scatterlist *sg = hwif->sg_table;
- int nents;
+ struct ata_request *ar = rq->special;

- nents = blk_rq_map_sg(q, rq, hwif->sg_table);
+ if (!(ar->ar_flags & ATA_AR_SETUP)) {
+ ar->ar_flags |= ATA_AR_SETUP;
+ ar->ar_sg_nents = blk_rq_map_sg(q, rq, ar->ar_sg_table);
+ }

- if (rq->q && nents > rq->nr_phys_segments)
- printk("ide-dma: received %d phys segments, build %d\n", rq->nr_phys_segments, nents);
+ if (rq->q && ar->ar_sg_nents > rq->nr_phys_segments) {
+ printk("%s: received %d phys segments, build %d\n", __FILE__, rq->nr_phys_segments, ar->ar_sg_nents);
+ return 0;
+ } else if (!ar->ar_sg_nents) {
+ printk("%s: zero segments in request\n", __FILE__);
+ return 0;
+ }

if (rq_data_dir(rq) == READ)
- hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+ ar->ar_sg_ddir = PCI_DMA_FROMDEVICE;
else
- hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+ ar->ar_sg_ddir = PCI_DMA_TODEVICE;

- return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
+ return pci_map_sg(hwif->pci_dev, ar->ar_sg_table, ar->ar_sg_nents, ar->ar_sg_ddir);
}

/*
@@ -245,23 +247,17 @@
*/
static int raw_build_sglist(struct ata_channel *ch, struct request *rq)
{
- struct scatterlist *sg = ch->sg_table;
- int nents = 0;
- struct ata_taskfile *args = rq->special;
-#if 1
+ struct ata_request *ar = rq->special;
+ struct scatterlist *sg = ar->ar_sg_table;
+ struct ata_taskfile *args = &ar->ar_task;
unsigned char *virt_addr = rq->buffer;
int sector_count = rq->nr_sectors;
-#else
- nents = blk_rq_map_sg(rq->q, rq, ch->sg_table);
-
- if (nents > rq->nr_segments)
- printk("ide-dma: received %d segments, build %d\n", rq->nr_segments, nents);
-#endif
+ int nents = 0;

if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
- ch->sg_dma_direction = PCI_DMA_TODEVICE;
+ ar->ar_sg_ddir = PCI_DMA_TODEVICE;
else
- ch->sg_dma_direction = PCI_DMA_FROMDEVICE;
+ ar->ar_sg_ddir = PCI_DMA_FROMDEVICE;

if (sector_count > 128) {
memset(&sg[nents], 0, sizeof(*sg));
@@ -279,18 +275,18 @@
sg[nents].length = sector_count * SECTOR_SIZE;
nents++;

- return pci_map_sg(ch->pci_dev, sg, nents, ch->sg_dma_direction);
+ return pci_map_sg(ch->pci_dev, sg, nents, ar->ar_sg_ddir);
}

/*
- * ide_build_dmatable() prepares a dma request.
+ * Prepare a dma request.
* Returns 0 if all went okay, returns 1 otherwise.
- * May also be invoked from trm290.c
+ * This may also be invoked from trm290.c
*/
-int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func)
+int ide_build_dmatable(ide_drive_t *drive, struct request *rq,
+ ide_dma_action_t func)
{
struct ata_channel *hwif = drive->channel;
- unsigned int *table = hwif->dmatable_cpu;
#ifdef CONFIG_BLK_DEV_TRM290
unsigned int is_trm290_chipset = (hwif->chipset == ide_trm290);
#else
@@ -299,16 +295,19 @@
unsigned int count = 0;
int i;
struct scatterlist *sg;
+ struct ata_request *ar = rq->special;
+ unsigned int *table = ar->ar_dmatable_cpu;

- if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
- hwif->sg_nents = i = raw_build_sglist(hwif, HWGROUP(drive)->rq);
- } else {
- hwif->sg_nents = i = ide_build_sglist(hwif, HWGROUP(drive)->rq);
- }
- if (!i)
+ if (rq->flags & REQ_DRIVE_TASKFILE)
+ ar->ar_sg_nents = raw_build_sglist(hwif, rq);
+ else
+ ar->ar_sg_nents = ide_build_sglist(hwif, rq);
+
+ if (!ar->ar_sg_nents)
return 0;

- sg = hwif->sg_table;
+ sg = ar->ar_sg_table;
+ i = ar->ar_sg_nents;
while (i) {
u32 cur_addr;
u32 cur_len;
@@ -327,7 +326,7 @@

if (count++ >= PRD_ENTRIES) {
printk("ide-dma: req %p\n", HWGROUP(drive)->rq);
- printk("count %d, sg_nents %d, cur_len %d, cur_addr %u\n", count, hwif->sg_nents, cur_len, cur_addr);
+ printk("count %d, sg_nents %d, cur_len %d, cur_addr %u\n", count, ar->ar_sg_nents, cur_len, cur_addr);
BUG();
}

@@ -338,7 +337,7 @@
if (is_trm290_chipset)
xcount = ((xcount >> 2) - 1) << 16;
if (xcount == 0x0000) {
- /*
+ /*
* Most chipsets correctly interpret a length of
* 0x0000 as 64KB, but at least one (e.g. CS5530)
* misinterprets it as zero (!). So here we break
@@ -346,8 +345,8 @@
*/
if (count++ >= PRD_ENTRIES) {
pci_unmap_sg(hwif->pci_dev, sg,
- hwif->sg_nents,
- hwif->sg_dma_direction);
+ ar->ar_sg_nents,
+ ar->ar_sg_ddir);
return 0;
}

@@ -376,10 +375,9 @@
void ide_destroy_dmatable (ide_drive_t *drive)
{
struct pci_dev *dev = drive->channel->pci_dev;
- struct scatterlist *sg = drive->channel->sg_table;
- int nents = drive->channel->sg_nents;
+ struct ata_request *ar = IDE_CUR_AR(drive);

- pci_unmap_sg(dev, sg, nents, drive->channel->sg_dma_direction);
+ pci_unmap_sg(dev, ar->ar_sg_table, ar->ar_sg_nents, ar->ar_sg_ddir);
}

/*
@@ -437,7 +435,7 @@
printk(", UDMA(133)"); /* UDMA BIOS-enabled! */
}
} else if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
- (id->dma_ultra & (id->dma_ultra >> 11) & 7)) {
+ (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) {
@@ -540,6 +538,32 @@
}

/*
+ * Start DMA engine.
+ */
+int ide_start_dma(struct ata_channel *hwif, ide_drive_t *drive, ide_dma_action_t func)
+{
+ unsigned int reading = 0, count;
+ unsigned long dma_base = hwif->dma_base;
+ struct ata_request *ar = IDE_CUR_AR(drive);
+
+ if (rq_data_dir(ar->ar_rq) == READ)
+ reading = 1 << 3;
+
+ if (hwif->rwproc)
+ hwif->rwproc(drive, func);
+
+ if (!(count = ide_build_dmatable(drive, ar->ar_rq, func)))
+ return 1; /* try PIO instead of DMA */
+
+ ar->ar_flags |= ATA_AR_SETUP;
+ outl(ar->ar_dmatable, dma_base + 4); /* PRD table */
+ outb(reading, dma_base); /* specify r/w */
+ outb(inb(dma_base + 2) | 6, dma_base+2);/* clear INTR & ERROR flags */
+ drive->waiting_for_dma = 1;
+ return 0;
+}
+
+/*
* ide_dmaproc() initiates/aborts DMA read/write operations on a drive.
*
* The caller is assumed to have selected the drive and programmed the drive's
@@ -559,15 +583,17 @@
{
struct ata_channel *hwif = drive->channel;
unsigned long dma_base = hwif->dma_base;
- byte unit = (drive->select.b.unit & 0x01);
- unsigned int count, reading = 0, set_high = 1;
- byte dma_stat;
+ u8 unit = (drive->select.b.unit & 0x01);
+ unsigned int reading = 0, set_high = 1;
+ struct ata_request *ar;
+ u8 dma_stat;

switch (func) {
case ide_dma_off:
printk("%s: DMA disabled\n", drive->name);
case ide_dma_off_quietly:
set_high = 0;
+ drive->using_tcq = 0;
outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
case ide_dma_on:
ide_toggle_bounce(drive, set_high);
@@ -577,48 +603,66 @@
return 0;
case ide_dma_check:
return config_drive_for_dma (drive);
+ case ide_dma_begin:
+#ifdef DEBUG
+ printk("ide_dma_begin: from %p\n", __builtin_return_address(0));
+#endif
+ if (test_and_set_bit(IDE_DMA, &HWGROUP(drive)->flags))
+ BUG();
+ /* 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.
+ */
+ outb(inb(dma_base)|1, dma_base); /* start DMA */
+ return 0;
+#ifdef CONFIG_BLK_DEV_IDE_TCQ
+ case ide_dma_queued_on:
+ case ide_dma_queued_off:
+ case ide_dma_read_queued:
+ case ide_dma_write_queued:
+ case ide_dma_queued_start:
+ return ide_tcq_dmaproc(func, drive);
+#endif
+
case ide_dma_read:
reading = 1 << 3;
case ide_dma_write:
- /* active tuning based on IO direction */
- if (hwif->rwproc)
- hwif->rwproc(drive, func);
-
- if (!(count = ide_build_dmatable(drive, func)))
- return 1; /* try PIO instead of DMA */
- outl(hwif->dmatable_dma, dma_base + 4); /* PRD table */
- outb(reading, dma_base); /* specify r/w */
- outb(inb(dma_base+2)|6, dma_base+2); /* clear INTR & ERROR flags */
- drive->waiting_for_dma = 1;
+ ar = HWGROUP(drive)->rq->special;
+
+ if (ide_start_dma(hwif, drive, func))
+ return 1;
+
if (drive->type != ATA_DISK)
return 0;

BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry); /* issue cmd to drive */
- if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) &&
+ if ((ar->ar_rq->flags & REQ_DRIVE_TASKFILE) &&
(drive->addressing == 1)) {
- struct ata_taskfile *args = HWGROUP(drive)->rq->special;
+ struct ata_taskfile *args = &ar->ar_task;
OUT_BYTE(args->taskfile.command, 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 drive->channel->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.
- * The Promise Ultra33 doesn't work correctly when
- * we do this part before issuing the drive cmd.
- */
- outb(inb(dma_base)|1, dma_base); /* start DMA */
- return 0;
+ return hwif->dmaproc(ide_dma_begin, drive);
case ide_dma_end: /* returns 1 on error, 0 otherwise */
+#ifdef DEBUG
+ printk("ide_dma_end: from %p\n", __builtin_return_address(0));
+#endif
+ if (!test_and_clear_bit(IDE_DMA, &HWGROUP(drive)->flags)) {
+ printk("ide_dma_end: dma not going? %p\n", __builtin_return_address(0));
+ return 1;
+ }
drive->waiting_for_dma = 0;
outb(inb(dma_base)&~1, dma_base); /* stop DMA */
- dma_stat = inb(dma_base+2); /* get DMA status */
+ dma_stat = inb(dma_base+2); /* get DMA status */
outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */
ide_destroy_dmatable(drive); /* purge DMA mappings */
+ if (drive->tcq)
+ IDE_SET_CUR_TAG(drive, -1);
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);
@@ -635,14 +679,14 @@
case ide_dma_verbose:
return report_drive_dmaing(drive);
case ide_dma_timeout:
- printk("ide_dmaproc: DMA timeout occured!\n");
+ printk(KERN_ERR "%s: DMA timeout occured!\n", __FUNCTION__);
return 1;
case ide_dma_retune:
case ide_dma_lostirq:
- printk("ide_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func), func);
+ printk(KERN_ERR "%s: chipset supported func only: %d\n", __FUNCTION__, func);
return 1;
default:
- printk("ide_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);
+ printk(KERN_ERR "%s: unsupported func: %d\n", __FUNCTION__, func);
return 1;
}
}
@@ -655,17 +699,6 @@
if (!hwif->dma_base)
return;

- if (hwif->dmatable_cpu) {
- pci_free_consistent(hwif->pci_dev,
- PRD_ENTRIES * PRD_BYTES,
- hwif->dmatable_cpu,
- hwif->dmatable_dma);
- hwif->dmatable_cpu = NULL;
- }
- if (hwif->sg_table) {
- kfree(hwif->sg_table);
- hwif->sg_table = NULL;
- }
if ((hwif->dma_extra) && (hwif->unit == 0))
release_region((hwif->dma_base + 16), hwif->dma_extra);
release_region(hwif->dma_base, 8);
@@ -684,20 +717,6 @@
}
request_region(dma_base, num_ports, hwif->name);
hwif->dma_base = dma_base;
- hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
- PRD_ENTRIES * PRD_BYTES,
- &hwif->dmatable_dma);
- if (hwif->dmatable_cpu == NULL)
- goto dma_alloc_failure;
-
- hwif->sg_table = kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES,
- GFP_KERNEL);
- if (hwif->sg_table == NULL) {
- pci_free_consistent(hwif->pci_dev, PRD_ENTRIES * PRD_BYTES,
- hwif->dmatable_cpu, hwif->dmatable_dma);
- goto dma_alloc_failure;
- }
-
hwif->dmaproc = &ide_dmaproc;

if (hwif->chipset != ide_trm290) {
@@ -708,7 +727,4 @@
}
printk("\n");
return;
-
-dma_alloc_failure:
- printk(" -- ERROR, UNABLE TO ALLOCATE DMA TABLES\n");
}
diff -urN linux-2.5.8-pre2/drivers/ide/ide-features.c linux/drivers/ide/ide-features.c
--- linux-2.5.8-pre2/drivers/ide/ide-features.c Wed Apr 10 01:45:01 2002
+++ linux/drivers/ide/ide-features.c Wed Apr 10 01:13:51 2002
@@ -69,34 +69,6 @@
}
}

-/*
- * A Verbose noise maker for debugging on the attempted dmaing calls.
- */
-char *ide_dmafunc_verbose (ide_dma_action_t dmafunc)
-{
- switch (dmafunc) {
- case ide_dma_read: return("ide_dma_read");
- case ide_dma_write: return("ide_dma_write");
- case ide_dma_begin: return("ide_dma_begin");
- case ide_dma_end: return("ide_dma_end:");
- case ide_dma_check: return("ide_dma_check");
- case ide_dma_on: return("ide_dma_on");
- case ide_dma_off: return("ide_dma_off");
- case ide_dma_off_quietly: return("ide_dma_off_quietly");
- case ide_dma_test_irq: return("ide_dma_test_irq");
- case ide_dma_bad_drive: return("ide_dma_bad_drive");
- case ide_dma_good_drive: return("ide_dma_good_drive");
- case ide_dma_verbose: return("ide_dma_verbose");
- case ide_dma_retune: return("ide_dma_retune");
- case ide_dma_lostirq: return("ide_dma_lostirq");
- case ide_dma_timeout: return("ide_dma_timeout");
- default: return("unknown");
- }
-}
-
-/*
- *
- */
byte ide_auto_reduce_xfer (ide_drive_t *drive)
{
if (!drive->crc_count)
@@ -122,9 +94,6 @@
}
}

-/*
- * Update the
- */
int ide_driveid_update (ide_drive_t *drive)
{
/*
@@ -195,10 +164,10 @@
}
#ifndef CONFIG_IDEDMA_IVB
if ((drive->id->hw_config & 0x6000) == 0) {
-#else /* !CONFIG_IDEDMA_IVB */
+#else
if (((drive->id->hw_config & 0x2000) == 0) ||
((drive->id->hw_config & 0x4000) == 0)) {
-#endif /* CONFIG_IDEDMA_IVB */
+#endif
printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", drive->name);
return 1;
}
@@ -232,7 +201,7 @@
return ((byte) ((drive->channel->udma_four) &&
#ifndef CONFIG_IDEDMA_IVB
(drive->id->hw_config & 0x4000) &&
-#endif /* CONFIG_IDEDMA_IVB */
+#endif
(drive->id->hw_config & 0x6000)) ? 1 : 0);
}

diff -urN linux-2.5.8-pre2/drivers/ide/ide-pmac.c linux/drivers/ide/ide-pmac.c
--- linux-2.5.8-pre2/drivers/ide/ide-pmac.c Wed Apr 10 01:45:01 2002
+++ linux/drivers/ide/ide-pmac.c Wed Apr 10 01:09:56 2002
@@ -52,7 +52,6 @@
#endif
#include "ata-timing.h"

-extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
extern spinlock_t ide_lock;

#undef IDE_PMAC_DEBUG
@@ -1460,10 +1459,10 @@
case ide_dma_retune:
case ide_dma_lostirq:
case ide_dma_timeout:
- printk(KERN_WARNING "ide_pmac_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func), func);
+ printk(KERN_WARNING "ide_pmac_dmaproc: chipset supported func only: %d\n", func);
return 1;
default:
- printk(KERN_WARNING "ide_pmac_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);
+ printk(KERN_WARNING "ide_pmac_dmaproc: unsupported func: %d\n", func);
return 1;
}
return 0;
diff -urN linux-2.5.8-pre2/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c
--- linux-2.5.8-pre2/drivers/ide/ide-probe.c Tue Apr 9 20:36:00 2002
+++ linux/drivers/ide/ide-probe.c Tue Apr 9 21:12:13 2002
@@ -189,6 +189,21 @@
if (drive->channel->quirkproc)
drive->quirk_list = drive->channel->quirkproc(drive);

+ /*
+ * it's an ata drive, build command list
+ */
+#ifndef CONFIG_BLK_DEV_IDE_TCQ
+ drive->queue_depth = 1;
+#else
+ drive->queue_depth = drive->id->queue_depth + 1;
+ if (drive->queue_depth > CONFIG_BLK_DEV_IDE_TCQ_DEPTH)
+ drive->queue_depth = CONFIG_BLK_DEV_IDE_TCQ_DEPTH;
+ if (drive->queue_depth < 1 || drive->queue_depth > IDE_MAX_TAG)
+ drive->queue_depth = IDE_MAX_TAG;
+#endif
+ if (ide_build_commandlist(drive))
+ goto err_misc;
+
return;

err_misc:
@@ -593,10 +608,10 @@
blk_queue_max_sectors(q, max_sectors);

/* IDE DMA can do PRD_ENTRIES number of segments. */
- blk_queue_max_hw_segments(q, PRD_ENTRIES);
+ blk_queue_max_hw_segments(q, PRD_SEGMENTS);

/* This is a driver limit and could be eliminated. */
- blk_queue_max_phys_segments(q, PRD_ENTRIES);
+ blk_queue_max_phys_segments(q, PRD_SEGMENTS);
}

#if MAX_HWIFS > 1
diff -urN linux-2.5.8-pre2/drivers/ide/ide-taskfile.c linux/drivers/ide/ide-taskfile.c
--- linux-2.5.8-pre2/drivers/ide/ide-taskfile.c Wed Apr 10 01:45:01 2002
+++ linux/drivers/ide/ide-taskfile.c Wed Apr 10 00:48:55 2002
@@ -291,7 +291,8 @@

static ide_startstop_t pre_task_mulout_intr(ide_drive_t *drive, struct request *rq)
{
- struct ata_taskfile *args = rq->special;
+ struct ata_request *ar = rq->special;
+ struct ata_taskfile *args = &ar->ar_task;
ide_startstop_t startstop;

/*
@@ -434,11 +435,35 @@
if (args->prehandler != NULL)
return args->prehandler(drive, rq);
} else {
- /* for dma commands we down set the handler */
- if (drive->using_dma &&
- !(drive->channel->dmaproc(((args->taskfile.command == WIN_WRITEDMA)
- || (args->taskfile.command == WIN_WRITEDMA_EXT))
- ? ide_dma_write : ide_dma_read, drive)));
+ ide_dma_action_t dmaaction;
+ u8 command;
+
+ if (!drive->using_dma)
+ return ide_started;
+
+ command = args->taskfile.command;
+
+#ifdef CONFIG_BLK_DEV_IDE_TCQ
+ if (drive->using_tcq) {
+ if (command == WIN_READDMA_QUEUED
+ || command == WIN_READDMA_QUEUED_EXT
+ || command == WIN_WRITEDMA_QUEUED
+ || command == WIN_READDMA_QUEUED_EXT)
+ return ide_start_tag(ide_dma_queued_start, drive, rq->special);
+ }
+#endif
+
+ if (command == WIN_WRITEDMA || command == WIN_WRITEDMA_EXT)
+ dmaaction = ide_dma_write;
+ else if (command == WIN_READDMA || command == WIN_READDMA_EXT)
+ dmaaction = ide_dma_read;
+ else
+ return ide_stopped;
+
+ if (!drive->channel->dmaproc(dmaaction, drive))
+ return ide_started;
+
+ return ide_stopped;
}

return ide_started;
@@ -495,8 +520,9 @@
*/
ide_startstop_t task_no_data_intr (ide_drive_t *drive)
{
- struct ata_taskfile *args = HWGROUP(drive)->rq->special;
- byte stat = GET_STAT();
+ struct ata_request *ar = HWGROUP(drive)->rq->special;
+ struct ata_taskfile *args = &ar->ar_task;
+ u8 stat = GET_STAT();

ide__sti(); /* local CPU only */

@@ -555,7 +581,8 @@

static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq)
{
- struct ata_taskfile *args = rq->special;
+ struct ata_request *ar = rq->special;
+ struct ata_taskfile *args = &ar->ar_task;
ide_startstop_t startstop;

if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
@@ -644,7 +671,7 @@

pBuf = ide_map_rq(rq, &flags);

- DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+ DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %d\n",
pBuf, nsect, rq->current_nr_sectors);
drive->io_32bit = 0;
taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
@@ -858,7 +885,7 @@
/*
* This function is intended to be used prior to invoking ide_do_drive_cmd().
*/
-static void init_taskfile_request(struct request *rq)
+void init_taskfile_request(struct request *rq)
{
memset(rq, 0, sizeof(*rq));
rq->flags = REQ_DRIVE_TASKFILE;
@@ -875,23 +902,24 @@
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;
- /* FIXME: This is on stack! */
- struct ata_taskfile args;
+ struct ata_request ar;
+ struct ata_taskfile *args = &ar.ar_task;

- memset(&args, 0, sizeof(args));
+ ata_ar_init(drive, &ar);

- args.taskfile = *taskfile;
- args.hobfile = *hobfile;
+ memcpy(&args->taskfile, taskfile, sizeof(*taskfile));
+ if (hobfile)
+ memcpy(&args->hobfile, hobfile, sizeof(*hobfile));

init_taskfile_request(&rq);

/* This is kept for internal use only !!! */
- ide_cmd_type_parser(&args);
- if (args.command_type != IDE_DRIVE_TASK_NO_DATA)
+ 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;
+ rq.special = &ar;

return ide_do_drive_cmd(drive, &rq, ide_wait);
}
@@ -899,15 +927,19 @@
int ide_raw_taskfile(ide_drive_t *drive, struct ata_taskfile *args, byte *buf)
{
struct request rq;
+ struct ata_request ar;
+
+ ata_ar_init(drive, &ar);
init_taskfile_request(&rq);
rq.buffer = buf;
+ memcpy(&ar.ar_task, args, sizeof(*args));

if (args->command_type != IDE_DRIVE_TASK_NO_DATA)
rq.current_nr_sectors = rq.nr_sectors
= (args->hobfile.sector_count << 8)
| args->taskfile.sector_count;

- rq.special = args;
+ rq.special = &ar;

return ide_do_drive_cmd(drive, &rq, ide_wait);
}
diff -urN linux-2.5.8-pre2/drivers/ide/ide-tcq.c linux/drivers/ide/ide-tcq.c
--- linux-2.5.8-pre2/drivers/ide/ide-tcq.c Thu Jan 1 01:00:00 1970
+++ linux/drivers/ide/ide-tcq.c Wed Apr 10 01:39:43 2002
@@ -0,0 +1,594 @@
+/*
+ * Copyright (C) 2001, 2002 Jens Axboe <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Support for the DMA queued protocol, which enables ATA disk drives to
+ * use tagged command queueing.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ide.h>
+
+#include <asm/delay.h>
+
+/*
+ * warning: it will be _very_ verbose if set to 1
+ */
+#if 0
+#define TCQ_PRINTK printk
+#else
+#define TCQ_PRINTK(x...)
+#endif
+
+/*
+ * use nIEN or not
+ */
+#undef IDE_TCQ_NIEN
+
+/*
+ * we are leaving the SERVICE interrupt alone, IBM drives have it
+ * on per default and it can't be turned off. Doesn't matter, this
+ * is the sane config.
+ */
+#undef IDE_TCQ_FIDDLE_SI
+
+int ide_tcq_end(ide_drive_t *drive);
+ide_startstop_t ide_dmaq_intr(ide_drive_t *drive);
+
+static inline void drive_ctl_nien(ide_drive_t *drive, int clear)
+{
+#ifdef IDE_TCQ_NIEN
+ int mask = clear ? 0 : 2;
+
+ if (IDE_CONTROL_REG)
+ OUT_BYTE(drive->ctl | mask, IDE_CONTROL_REG);
+#endif
+}
+
+/*
+ * if we encounter _any_ error doing I/O to one of the tags, we must
+ * invalidate the pending queue. clear the software busy queue and requeue
+ * on the request queue for restart. issue a WIN_NOP to clear hardware queue
+ */
+static void ide_tcq_invalidate_queue(ide_drive_t *drive)
+{
+ request_queue_t *q = &drive->queue;
+ unsigned long flags;
+ struct ata_request *ar;
+ int i;
+
+ printk("%s: invalidating pending queue\n", drive->name);
+
+ spin_lock_irqsave(&ide_lock, flags);
+
+ del_timer(&HWGROUP(drive)->timer);
+
+ /*
+ * assume oldest commands have the higher tags... doesn't matter
+ * much. shove requests back into request queue.
+ */
+ for (i = drive->queue_depth - 1; i; i--) {
+ ar = drive->tcq->ar[i];
+ if (!ar)
+ continue;
+
+ ar->ar_rq->special = NULL;
+ ar->ar_rq->flags &= ~REQ_STARTED;
+ _elv_add_request(q, ar->ar_rq, 0, 0);
+ ata_ar_put(drive, ar);
+ }
+
+ drive->tcq->queued = 0;
+ drive->using_tcq = 0;
+ drive->queue_depth = 1;
+ clear_bit(IDE_BUSY, &HWGROUP(drive)->flags);
+ clear_bit(IDE_DMA, &HWGROUP(drive)->flags);
+ HWGROUP(drive)->handler = NULL;
+
+ /*
+ * do some internal stuff -- we really need this command to be
+ * executed before any new commands are started. issue a NOP
+ * to clear internal queue on drive
+ */
+ ar = ata_ar_get(drive);
+
+ memset(&ar->ar_task, 0, sizeof(ar->ar_task));
+ AR_TASK_CMD(ar) = WIN_NOP;
+ ide_cmd_type_parser(&ar->ar_task);
+ ar->ar_rq = &HWGROUP(drive)->wrq;
+ init_taskfile_request(ar->ar_rq);
+ ar->ar_rq->rq_dev = mk_kdev(drive->channel->major, (drive->select.b.unit)<<PARTN_BITS);
+ ar->ar_rq->special = ar;
+ ar->ar_flags |= ATA_AR_RETURN;
+ _elv_add_request(q, ar->ar_rq, 0, 0);
+
+ /*
+ * make sure that nIEN is cleared
+ */
+ drive_ctl_nien(drive, 0);
+
+ /*
+ * start doing stuff again
+ */
+ q->request_fn(q);
+ spin_unlock_irqrestore(&ide_lock, flags);
+ printk("ide_tcq_invalidate_queue: done\n");
+}
+
+void ide_tcq_intr_timeout(unsigned long data)
+{
+ ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data;
+ unsigned long flags;
+ ide_drive_t *drive;
+
+ printk("ide_tcq_intr_timeout: timeout waiting for interrupt...\n");
+
+ spin_lock_irqsave(&ide_lock, flags);
+
+ if (test_bit(IDE_BUSY, &hwgroup->flags))
+ printk("ide_tcq_intr_timeout: hwgroup not busy\n");
+ if (hwgroup->handler == NULL)
+ printk("ide_tcq_intr_timeout: missing isr!\n");
+ if ((drive = hwgroup->drive) == NULL)
+ printk("ide_tcq_intr_timeout: missing drive!\n");
+
+ spin_unlock_irqrestore(&ide_lock, flags);
+
+ if (drive)
+ ide_tcq_invalidate_queue(drive);
+}
+
+void ide_tcq_set_intr(ide_hwgroup_t *hwgroup, ide_handler_t *handler)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ide_lock, flags);
+
+ /*
+ * always just bump the timer for now, the timeout handling will
+ * have to be changed to be per-command
+ */
+ hwgroup->timer.function = ide_tcq_intr_timeout;
+ hwgroup->timer.data = (unsigned long) hwgroup;
+ mod_timer(&hwgroup->timer, jiffies + 5 * HZ);
+
+ hwgroup->handler = handler;
+ spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * wait 400ns, then poll for busy_mask to clear from alt status
+ */
+#define IDE_TCQ_WAIT (10000)
+int ide_tcq_wait_altstat(ide_drive_t *drive, byte *stat, byte busy_mask)
+{
+ int i;
+
+ /*
+ * one initial udelay(1) should be enough, reading alt stat should
+ * provide the required delay...
+ */
+ *stat = 0;
+ i = 0;
+ do {
+ udelay(1);
+
+ if (unlikely(i++ > IDE_TCQ_WAIT))
+ return 1;
+ } while ((*stat = GET_ALTSTAT()) & busy_mask);
+
+ return 0;
+}
+
+/*
+ * issue SERVICE command to drive -- drive must have been selected first,
+ * and it must have reported a need for service (status has SERVICE_STAT set)
+ *
+ * Also, nIEN must be set as not to need protection against ide_dmaq_intr
+ */
+ide_startstop_t ide_service(ide_drive_t *drive)
+{
+ struct ata_request *ar;
+ byte feat, tag, stat;
+
+ if (test_bit(IDE_DMA, &HWGROUP(drive)->flags))
+ printk("ide_service: DMA in progress\n");
+
+ /*
+ * need to select the right drive first...
+ */
+ if (drive != HWGROUP(drive)->drive) {
+ SELECT_DRIVE(drive->channel, drive);
+ udelay(10);
+ }
+
+ drive_ctl_nien(drive, 1);
+
+ /*
+ * send SERVICE, wait 400ns, wait for BUSY_STAT to clear
+ */
+ OUT_BYTE(WIN_QUEUED_SERVICE, IDE_COMMAND_REG);
+
+ if (ide_tcq_wait_altstat(drive, &stat, BUSY_STAT)) {
+ printk("ide_service: BUSY clear took too long\n");
+ ide_tcq_invalidate_queue(drive);
+ return ide_stopped;
+ }
+
+ drive_ctl_nien(drive, 0);
+
+ /*
+ * FIXME, invalidate queue
+ */
+ if (stat & ERR_STAT) {
+ printk("%s: error SERVICING drive (%x)\n", drive->name, stat);
+ ide_dump_status(drive, "ide_service", stat);
+ return ide_tcq_end(drive);
+ }
+
+ /*
+ * should not happen, a buggy device could introduce loop
+ */
+ if ((feat = GET_FEAT()) & NSEC_REL) {
+ printk("%s: release in service\n", drive->name);
+ IDE_SET_CUR_TAG(drive, -1);
+ return ide_stopped;
+ }
+
+ /*
+ * start dma
+ */
+ tag = feat >> 3;
+ IDE_SET_CUR_TAG(drive, tag);
+
+ TCQ_PRINTK("ide_service: stat %x, feat %x\n", stat, feat);
+
+ if ((ar = IDE_CUR_TAG(drive)) == NULL) {
+ printk("ide_service: missing request for tag %d\n", tag);
+ return ide_stopped;
+ }
+
+ /*
+ * we'll start a dma read or write, device will trigger
+ * interrupt to indicate end of transfer, release is not allowed
+ */
+ if (rq_data_dir(ar->ar_rq) == READ) {
+ TCQ_PRINTK("ide_service: starting READ %x\n", stat);
+ drive->channel->dmaproc(ide_dma_read_queued, drive);
+ } else {
+ TCQ_PRINTK("ide_service: starting WRITE %x\n", stat);
+ drive->channel->dmaproc(ide_dma_write_queued, drive);
+ }
+
+ /*
+ * dmaproc set intr handler
+ */
+ return ide_started;
+}
+
+ide_startstop_t ide_check_service(ide_drive_t *drive)
+{
+ byte stat;
+
+ if (!ide_pending_commands(drive))
+ return ide_stopped;
+
+ if ((stat = GET_STAT()) & SERVICE_STAT)
+ return ide_service(drive);
+
+ /*
+ * we have pending commands, wait for interrupt
+ */
+ ide_tcq_set_intr(HWGROUP(drive), ide_dmaq_intr);
+ return ide_started;
+}
+
+int ide_tcq_end(ide_drive_t *drive)
+{
+ byte stat = GET_STAT();
+
+ if (stat & ERR_STAT) {
+ ide_dump_status(drive, "ide_tcq_end", stat);
+ ide_tcq_invalidate_queue(drive);
+ return ide_stopped;
+ } else if (stat & SERVICE_STAT) {
+ TCQ_PRINTK("ide_tcq_end: serv stat=%x\n", stat);
+ return ide_service(drive);
+ }
+
+ TCQ_PRINTK("ide_tcq_end: stat=%x, feat=%x\n", stat, GET_FEAT());
+ return ide_stopped;
+}
+
+ide_startstop_t ide_dmaq_complete(ide_drive_t *drive, byte stat)
+{
+ struct ata_request *ar;
+ byte dma_stat;
+
+#if 0
+ byte feat = GET_FEAT();
+
+ if ((feat & (NSEC_CD | NSEC_IO)) != (NSEC_CD | NSEC_IO))
+ printk("%s: C/D | I/O not set\n", drive->name);
+#endif
+
+ /*
+ * transfer was in progress, stop DMA engine
+ */
+ ar = IDE_CUR_TAG(drive);
+
+ dma_stat = drive->channel->dmaproc(ide_dma_end, drive);
+
+ /*
+ * must be end of I/O, check status and complete as necessary
+ */
+ if (unlikely(!OK_STAT(stat, READY_STAT, drive->bad_wstat | DRQ_STAT))) {
+ printk("ide_dmaq_intr: %s: error status %x\n", drive->name, stat);
+ ide_dump_status(drive, "ide_dmaq_intr", stat);
+ ide_tcq_invalidate_queue(drive);
+ return ide_stopped;
+ }
+
+ if (dma_stat)
+ printk("%s: bad DMA status (dma_stat=%x)\n", drive->name, dma_stat);
+
+ TCQ_PRINTK("ide_dmaq_intr: ending %p, tag %d\n", ar, ar->ar_tag);
+ ide_end_queued_request(drive, !dma_stat, ar->ar_rq);
+
+ IDE_SET_CUR_TAG(drive, -1);
+ return ide_check_service(drive);
+}
+
+/*
+ * intr handler for queued dma operations. this can be entered for two
+ * reasons:
+ *
+ * 1) device has completed dma transfer
+ * 2) service request to start a command
+ *
+ * if the drive has an active tag, we first complete that request before
+ * processing any pending SERVICE.
+ */
+ide_startstop_t ide_dmaq_intr(ide_drive_t *drive)
+{
+ byte stat = GET_STAT();
+
+ TCQ_PRINTK("ide_dmaq_intr: stat=%x, tag %d\n", stat, drive->tcq->active_tag);
+
+ /*
+ * if a command completion interrupt is pending, do that first and
+ * check service afterwards
+ */
+ if (drive->tcq->active_tag != -1)
+ return ide_dmaq_complete(drive, stat);
+
+ /*
+ * service interrupt
+ */
+ if (stat & SERVICE_STAT) {
+ TCQ_PRINTK("ide_dmaq_intr: SERV (stat=%x)\n", stat);
+ return ide_service(drive);
+ }
+
+ printk("ide_dmaq_intr: stat=%x, not expected\n", stat);
+ return ide_check_service(drive);
+}
+
+/*
+ * configure the drive for tcq
+ */
+static int ide_tcq_configure(ide_drive_t *drive)
+{
+ struct hd_drive_task_hdr taskfile;
+ int tcq_supp = 1 << 1 | 1 << 14;
+
+ memset(&taskfile, 0, sizeof(taskfile));
+
+ /*
+ * bit 14 and 1 must be set in word 83 of the device id to indicate
+ * support for dma queued protocol
+ */
+ if ((drive->id->command_set_2 & tcq_supp) != tcq_supp) {
+ printk("%s: queued feature set not supported\n", drive->name);
+ return 1;
+ }
+
+ taskfile.feature = SETFEATURES_EN_WCACHE;
+ taskfile.command = WIN_SETFEATURES;
+ if (ide_wait_taskfile(drive, &taskfile, NULL, NULL)) {
+ printk("%s: failed to enable write cache\n", drive->name);
+ return 1;
+ }
+
+ /*
+ * disable RELease interrupt, it's quicker to poll this after
+ * having sent the command opcode
+ */
+ taskfile.feature = SETFEATURES_DIS_RI;
+ taskfile.command = WIN_SETFEATURES;
+ if (ide_wait_taskfile(drive, &taskfile, NULL, NULL)) {
+ printk("%s: disabling release interrupt fail\n", drive->name);
+ return 1;
+ }
+
+#ifdef IDE_TCQ_FIDDLE_SI
+ /*
+ * enable SERVICE interrupt
+ */
+ taskfile.feature = SETFEATURES_EN_SI;
+ taskfile.command = WIN_SETFEATURES;
+ if (ide_wait_taskfile(drive, &taskfile, NULL, NULL)) {
+ printk("%s: enabling service interrupt fail\n", drive->name);
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+/*
+ * for now assume that command list is always as big as we need and don't
+ * attempt to shrink it on tcq disable
+ */
+static int ide_enable_queued(ide_drive_t *drive, int on)
+{
+ /*
+ * disable or adjust queue depth
+ */
+ if (!on) {
+ printk("%s: TCQ disabled\n", drive->name);
+ drive->using_tcq = 0;
+
+ return 0;
+ } else if (drive->using_tcq) {
+ drive->queue_depth = drive->using_tcq;
+
+ goto out;
+ }
+
+ if (ide_tcq_configure(drive)) {
+ drive->using_tcq = 0;
+
+ return 1;
+ }
+
+out:
+ drive->tcq->max_depth = 0;
+
+ printk("%s: tagged command queueing enabled, command queue depth %d\n", drive->name, drive->queue_depth);
+ drive->using_tcq = 1;
+
+ return 0;
+}
+
+int ide_tcq_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+{
+ struct ata_channel *hwif = drive->channel;
+ unsigned int reading = 0, enable_tcq = 1;
+ ide_startstop_t startstop;
+ struct ata_request *ar;
+ byte stat, feat;
+
+ switch (func) {
+ /*
+ * invoked from a SERVICE interrupt, command etc already known.
+ * just need to start the dma engine for this tag
+ */
+ case ide_dma_read_queued:
+ reading = 1 << 3;
+ case ide_dma_write_queued:
+ TCQ_PRINTK("ide_dma: setting up queued %d\n", drive->tcq->active_tag);
+ BUG_ON(drive->tcq->active_tag == -1);
+
+ if (!test_bit(IDE_BUSY, &HWGROUP(drive)->flags))
+ printk("queued_rw: IDE_BUSY not set\n");
+
+ if (ide_wait_stat(&startstop, drive, READY_STAT | DRQ_STAT, BUSY_STAT, WAIT_READY)) {
+ printk("%s: timeout waiting for data phase\n", drive->name);
+ return startstop;
+ }
+
+ if (ide_start_dma(hwif, drive, func))
+ return 1;
+
+ ide_tcq_set_intr(HWGROUP(drive), ide_dmaq_intr);
+ return hwif->dmaproc(ide_dma_begin, drive);
+
+ /*
+ * start a queued command from scratch
+ */
+ case ide_dma_queued_start:
+ BUG_ON(drive->tcq->active_tag == -1);
+ ar = IDE_CUR_TAG(drive);
+
+ /*
+ * set nIEN, tag start operation will enable again when
+ * it is safe
+ */
+ drive_ctl_nien(drive, 1);
+
+ OUT_BYTE(AR_TASK_CMD(ar), IDE_COMMAND_REG);
+
+ if (ide_tcq_wait_altstat(drive, &stat, BUSY_STAT)) {
+ printk("ide_dma_queued_start: abort (stat=%x)\n", stat);
+ return ide_stopped;
+ }
+
+ drive_ctl_nien(drive, 0);
+
+ if (stat & ERR_STAT) {
+ printk("ide_dma_queued_start: abort (stat=%x)\n", stat);
+ return ide_stopped;
+ }
+
+ if ((feat = GET_FEAT()) & NSEC_REL) {
+ drive->tcq->immed_rel++;
+ TCQ_PRINTK("REL in queued_start\n");
+ IDE_SET_CUR_TAG(drive, -1);
+
+ if ((stat = GET_STAT()) & SERVICE_STAT)
+ return ide_service(drive);
+
+ ide_tcq_set_intr(HWGROUP(drive), ide_dmaq_intr);
+ return ide_released;
+ }
+
+ drive->tcq->immed_comp++;
+
+ if (ide_wait_stat(&startstop, drive, READY_STAT | DRQ_STAT, BUSY_STAT, WAIT_READY)) {
+ printk("%s: timeout waiting for data phase\n", drive->name);
+ return startstop;
+ }
+
+ if (ide_start_dma(hwif, drive, func))
+ return ide_stopped;
+
+ if (hwif->dmaproc(ide_dma_begin, drive))
+ return ide_stopped;
+
+ /*
+ * wait for SERVICE or completion interrupt
+ */
+ ide_tcq_set_intr(HWGROUP(drive), ide_dmaq_intr);
+ return ide_started;
+
+ case ide_dma_queued_off:
+ enable_tcq = 0;
+ case ide_dma_queued_on:
+ return ide_enable_queued(drive, enable_tcq);
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+int ide_build_sglist (struct ata_channel *hwif, struct request *rq);
+ide_startstop_t ide_start_tag(ide_dma_action_t func, ide_drive_t *drive,
+ struct ata_request *ar)
+{
+ /*
+ * do this now, no need to run that with interrupts disabled
+ */
+ if (!ide_build_sglist(drive->channel, ar->ar_rq))
+ return ide_stopped;
+
+ IDE_SET_CUR_TAG(drive, ar->ar_tag);
+ return ide_tcq_dmaproc(func, drive);
+}
diff -urN linux-2.5.8-pre2/drivers/ide/ide.c linux/drivers/ide/ide.c
--- linux-2.5.8-pre2/drivers/ide/ide.c Wed Apr 10 01:45:01 2002
+++ linux/drivers/ide/ide.c Wed Apr 10 00:20:02 2002
@@ -368,6 +368,25 @@
return 0; /* no, it is not a flash memory card */
}

+void ide_end_queued_request(ide_drive_t *drive, int uptodate, struct request *rq)
+{
+ unsigned long flags;
+
+ BUG_ON(!(rq->flags & REQ_STARTED));
+ BUG_ON(!rq->special);
+
+ if (!end_that_request_first(rq, uptodate, rq->hard_nr_sectors)) {
+ struct ata_request *ar = rq->special;
+
+ add_blkdev_randomness(major(rq->rq_dev));
+
+ spin_lock_irqsave(&ide_lock, flags);
+ ata_ar_put(drive, ar);
+ end_that_request_last(rq);
+ spin_unlock_irqrestore(&ide_lock, flags);
+ }
+}
+
int __ide_end_request(ide_drive_t *drive, int uptodate, int nr_secs)
{
struct request *rq;
@@ -396,9 +415,17 @@
}

if (!end_that_request_first(rq, uptodate, nr_secs)) {
+ struct ata_request *ar = rq->special;
+
add_blkdev_randomness(major(rq->rq_dev));
+ /*
+ * request with ATA_AR_QUEUED set have already been
+ * dequeued, but doing it twice is ok
+ */
blkdev_dequeue_request(rq);
HWGROUP(drive)->rq = NULL;
+ if (ar)
+ ata_ar_put(drive, ar);
end_that_request_last(rq);
ret = 0;
}
@@ -422,8 +449,8 @@

spin_lock_irqsave(&ide_lock, flags);
if (hwgroup->handler != NULL) {
- printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n",
- drive->name, hwgroup->handler, handler);
+ printk("%s: ide_set_handler: handler not null; old=%p, new=%p, from %p\n",
+ drive->name, hwgroup->handler, handler, __builtin_return_address(0));
}
hwgroup->handler = handler;
hwgroup->expiry = expiry;
@@ -738,8 +765,12 @@
args[6] = IN_BYTE(IDE_SELECT_REG);
}
} else if (rq->flags & REQ_DRIVE_TASKFILE) {
- struct ata_taskfile *args = rq->special;
+ struct ata_request *ar = rq->special;
+ struct ata_taskfile *args = &ar->ar_task;
+
rq->errors = !OK_STAT(stat, READY_STAT, BAD_STAT);
+ if (args && args->taskfile.command == WIN_NOP)
+ printk(KERN_INFO "%s: NOP completed\n", __FUNCTION__);
if (args) {
args->taskfile.feature = err;
args->taskfile.sector_count = IN_BYTE(IDE_NSECTOR_REG);
@@ -762,6 +793,8 @@
args->hobfile.high_cylinder = IN_BYTE(IDE_HCYL_REG);
}
}
+ if (ar->ar_flags & ATA_AR_RETURN)
+ ata_ar_put(drive, ar);
}

blkdev_dequeue_request(rq);
@@ -879,6 +912,11 @@
struct request *rq;
byte err;

+ /*
+ * FIXME: remember to invalidate tcq queue when drive->using_tcq
+ * and atomic_read(&drive->tcq->queued) /jens
+ */
+
err = ide_dump_status(drive, msg, stat);
if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
return ide_stopped;
@@ -1063,7 +1101,11 @@
while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
#endif

+ if (test_bit(IDE_DMA, &HWGROUP(drive)->flags))
+ printk("start_request: auch, DMA in progress 1\n");
SELECT_DRIVE(hwif, drive);
+ if (test_bit(IDE_DMA, &HWGROUP(drive)->flags))
+ printk("start_request: auch, DMA in progress 2\n");
if (ide_wait_stat(&startstop, drive, drive->ready_stat,
BUSY_STAT|DRQ_STAT, WAIT_READY)) {
printk(KERN_WARNING "%s: drive not ready for command\n", drive->name);
@@ -1083,11 +1125,14 @@
*/

if (rq->flags & REQ_DRIVE_TASKFILE) {
- struct ata_taskfile *args = rq->special;
+ struct ata_request *ar = rq->special;
+ struct ata_taskfile *args;

- if (!(args))
+ if (!ar)
goto args_error;

+ args = &ar->ar_task;
+
ata_taskfile(drive, args, NULL);

if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) ||
@@ -1318,16 +1363,37 @@
hwgroup->hwif = hwif;
hwgroup->drive = drive;
drive->PADAM_sleep = 0;
+queue_next:
drive->PADAM_service_start = jiffies;

- if (blk_queue_plugged(&drive->queue))
- BUG();
+ if (test_bit(IDE_DMA, &hwgroup->flags)) {
+ printk("ide_do_request: DMA in progress...\n");
+ break;
+ }
+
+ /*
+ * there's a small window between where the queue could be
+ * replugged while we are in here when using tcq (in which
+ * case the queue is probably empty anyways...), so check
+ * and leave if appropriate. When not using tcq, this is
+ * still a severe BUG!
+ */
+ if (blk_queue_plugged(&drive->queue)) {
+ BUG_ON(!drive->using_tcq);
+ break;
+ }

/*
* just continuing an interrupted request maybe
*/
rq = hwgroup->rq = elv_next_request(&drive->queue);

+ if (!rq) {
+ if (!ide_pending_commands(drive))
+ clear_bit(IDE_BUSY, &HWGROUP(drive)->flags);
+ break;
+ }
+
/*
* Some systems have trouble with IDE IRQs arriving while
* the driver is still setting things up. So, here we disable
@@ -1338,14 +1404,22 @@
*/
if (masked_irq && hwif->irq != masked_irq)
disable_irq_nosync(hwif->irq);
+
spin_unlock(&ide_lock);
ide__sti(); /* allow other IRQs while we start this request */
startstop = start_request(drive, rq);
+
spin_lock_irq(&ide_lock);
if (masked_irq && hwif->irq != masked_irq)
enable_irq(hwif->irq);
- if (startstop == ide_stopped)
+
+ if (startstop == ide_released)
+ goto queue_next;
+ else if (startstop == ide_stopped) {
+ if (test_bit(IDE_DMA, &hwgroup->flags))
+ printk("2nd illegal clear\n");
clear_bit(IDE_BUSY, &hwgroup->flags);
+ }
}
}

@@ -1372,21 +1446,39 @@
* un-busy the hwgroup etc, and clear any pending DMA status. we want to
* retry the current request in PIO mode instead of risking tossing it
* all away
+ *
+ * FIXME: needs a bit of tcq work
*/
void ide_dma_timeout_retry(ide_drive_t *drive)
{
struct ata_channel *hwif = drive->channel;
- struct request *rq;
+ struct request *rq = NULL;
+ struct ata_request *ar = NULL;
+
+ if (drive->using_tcq) {
+ if (drive->tcq->active_tag != -1) {
+ ar = IDE_CUR_AR(drive);
+ rq = ar->ar_rq;
+ }
+ } else {
+ rq = HWGROUP(drive)->rq;
+ ar = rq->special;
+ }

/*
* end current dma transaction
*/
- hwif->dmaproc(ide_dma_end, drive);
+ if (rq)
+ hwif->dmaproc(ide_dma_end, drive);

/*
* complain a little, later we might remove some of this verbosity
*/
- printk("%s: timeout waiting for DMA\n", drive->name);
+ printk("%s: timeout waiting for DMA", drive->name);
+ if (drive->using_tcq)
+ printk(" queued, active tag %d", drive->tcq->active_tag);
+ printk("\n");
+
hwif->dmaproc(ide_dma_timeout, drive);

/*
@@ -1402,15 +1494,25 @@
* un-busy drive etc (hwgroup->busy is cleared on return) and
* make sure request is sane
*/
- rq = HWGROUP(drive)->rq;
HWGROUP(drive)->rq = NULL;

+ if (!rq)
+ return;
+
rq->errors = 0;
if (rq->bio) {
rq->sector = rq->bio->bi_sector;
rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
rq->buffer = NULL;
}
+
+ /*
+ * this request was not on the queue any more
+ */
+ if (ar->ar_flags & ATA_AR_QUEUED) {
+ ata_ar_put(drive, ar);
+ _elv_add_request(&drive->queue, rq, 0, 0);
+ }
}

/*
@@ -1641,8 +1743,10 @@
set_recovery_timer(drive->channel);
drive->PADAM_service_time = jiffies - drive->PADAM_service_start;
if (startstop == ide_stopped) {
- if (hwgroup->handler == NULL) { /* paranoia */
+ if (hwgroup->handler == NULL) { /* paranoia */
clear_bit(IDE_BUSY, &hwgroup->flags);
+ if (test_bit(IDE_DMA, &hwgroup->flags))
+ printk("ide_intr: illegal clear\n");
ide_do_request(hwgroup, hwif->irq);
} else {
printk("%s: ide_intr: huh? expected NULL handler on exit\n", drive->name);
@@ -1722,6 +1826,7 @@
if (drive->channel->chipset == ide_pdc4030 && rq->buffer != NULL)
return -ENOSYS; /* special drive cmds not supported */
#endif
+ rq->flags |= REQ_STARTED;
rq->errors = 0;
rq->rq_status = RQ_ACTIVE;
rq->rq_dev = mk_kdev(major,(drive->select.b.unit)<<PARTN_BITS);
@@ -2045,6 +2150,7 @@
}
drive->present = 0;
blk_cleanup_queue(&drive->queue);
+ ide_teardown_commandlist(drive);
}
if (d->present)
hwgroup->drive = d;
@@ -2595,6 +2701,89 @@
}
}

+void ide_teardown_commandlist(ide_drive_t *drive)
+{
+ struct pci_dev *pdev= drive->channel->pci_dev;
+ struct list_head *entry;
+
+ list_for_each(entry, &drive->free_req) {
+ struct ata_request *ar = list_ata_entry(entry);
+
+ list_del(&ar->ar_queue);
+ kfree(ar->ar_sg_table);
+ pci_free_consistent(pdev, PRD_SEGMENTS * PRD_BYTES, ar->ar_dmatable_cpu, ar->ar_dmatable);
+ kfree(ar);
+ }
+}
+
+int ide_build_commandlist(ide_drive_t *drive)
+{
+ struct pci_dev *pdev= drive->channel->pci_dev;
+ struct ata_request *ar;
+ ide_tag_info_t *tcq;
+ int i, err;
+
+ tcq = kmalloc(sizeof(ide_tag_info_t), GFP_ATOMIC);
+ if (!tcq)
+ return -ENOMEM;
+
+ drive->tcq = tcq;
+ memset(drive->tcq, 0, sizeof(ide_tag_info_t));
+
+ INIT_LIST_HEAD(&drive->free_req);
+ drive->using_tcq = 0;
+
+ err = -ENOMEM;
+ for (i = 0; i < drive->queue_depth; i++) {
+ /* Having kzmalloc would help reduce code size at quite
+ * many places in kernel. */
+ ar = kmalloc(sizeof(*ar), GFP_ATOMIC);
+ if (!ar)
+ break;
+
+ memset(ar, 0, sizeof(*ar));
+ INIT_LIST_HEAD(&ar->ar_queue);
+
+ ar->ar_sg_table = kmalloc(PRD_SEGMENTS * sizeof(struct scatterlist), GFP_ATOMIC);
+ if (!ar->ar_sg_table) {
+ kfree(ar);
+ break;
+ }
+
+ ar->ar_dmatable_cpu = pci_alloc_consistent(pdev, PRD_SEGMENTS * PRD_BYTES, &ar->ar_dmatable);
+ if (!ar->ar_dmatable_cpu) {
+ kfree(ar->ar_sg_table);
+ kfree(ar);
+ break;
+ }
+
+
+
+ /*
+ * pheew, all done, add to list
+ */
+ list_add_tail(&ar->ar_queue, &drive->free_req);
+ }
+
+ if (i) {
+ drive->queue_depth = i;
+ if (i >= 1) {
+ drive->using_tcq = 1;
+ drive->tcq->queued = 0;
+ drive->tcq->active_tag = -1;
+ return 0;
+ }
+
+ kfree(drive->tcq);
+ drive->tcq = NULL;
+ err = 0;
+ }
+
+ kfree(drive->tcq);
+ drive->tcq = NULL;
+ return err;
+}
+
static int ide_check_media_change (kdev_t i_rdev)
{
ide_drive_t *drive;
@@ -3156,6 +3345,9 @@

drive->channel->dmaproc(ide_dma_off_quietly, drive);
drive->channel->dmaproc(ide_dma_check, drive);
+#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT
+ drive->channel->dmaproc(ide_dma_queued_on, drive);
+#endif /* CONFIG_BLK_DEV_IDE_TCQ_DEFAULT */
}
/* Only CD-ROMs and tape drives support DSC overlap. */
drive->dsc_overlap = (drive->next != drive
diff -urN linux-2.5.8-pre2/drivers/ide/pdc202xx.c linux/drivers/ide/pdc202xx.c
--- linux-2.5.8-pre2/drivers/ide/pdc202xx.c Mon Apr 8 21:12:44 2002
+++ linux/drivers/ide/pdc202xx.c Tue Apr 9 21:12:13 2002
@@ -1057,6 +1057,12 @@
case ide_dma_timeout:
if (drive->channel->resetproc != NULL)
drive->channel->resetproc(drive);
+ /*
+ * we cannot support queued operations on promise, so fail to
+ * to enable it...
+ */
+ case ide_dma_queued_on:
+ return 1;
default:
break;
}
diff -urN linux-2.5.8-pre2/include/linux/hdreg.h linux/include/linux/hdreg.h
--- linux-2.5.8-pre2/include/linux/hdreg.h Mon Apr 8 21:12:46 2002
+++ linux/include/linux/hdreg.h Tue Apr 9 21:12:13 2002
@@ -34,6 +34,7 @@
#define ECC_STAT 0x04 /* Corrected error */
#define DRQ_STAT 0x08
#define SEEK_STAT 0x10
+#define SERVICE_STAT SEEK_STAT
#define WRERR_STAT 0x20
#define READY_STAT 0x40
#define BUSY_STAT 0x80
@@ -50,6 +51,13 @@
#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */

/*
+ * bits of NSECTOR reg
+ */
+#define NSEC_CD 0x1
+#define NSEC_IO 0x2
+#define NSEC_REL 0x4
+
+/*
* Command Header sizes for IOCTL commands
* HDIO_DRIVE_CMD and HDIO_DRIVE_TASK
*/
diff -urN linux-2.5.8-pre2/include/linux/ide.h linux/include/linux/ide.h
--- linux-2.5.8-pre2/include/linux/ide.h Wed Apr 10 01:45:01 2002
+++ linux/include/linux/ide.h Wed Apr 10 01:01:22 2002
@@ -114,10 +114,13 @@
#define GET_STAT() IN_BYTE(IDE_STATUS_REG)
#define GET_ALTSTAT() IN_BYTE(IDE_CONTROL_REG)
#define GET_FEAT() IN_BYTE(IDE_NSECTOR_REG)
+
#define OK_STAT(stat,good,bad) (((stat)&((good)|(bad)))==(good))
+
#define BAD_R_STAT (BUSY_STAT | ERR_STAT)
#define BAD_W_STAT (BAD_R_STAT | WRERR_STAT)
#define BAD_STAT (BAD_R_STAT | DRQ_STAT)
+
#define DRIVE_READY (READY_STAT | SEEK_STAT)
#define DATA_READY (DRQ_STAT)

@@ -270,6 +273,37 @@
} b;
} special_t;

+#define IDE_MAX_TAG 32 /* spec says 32 max */
+
+struct ata_request;
+typedef struct ide_tag_info_s {
+ unsigned long tag_mask; /* next tag bit mask */
+ struct ata_request *ar[IDE_MAX_TAG]; /* in-progress requests */
+ int active_tag; /* current active tag */
+ int queued; /* current depth */
+
+ /*
+ * stats ->
+ */
+ int max_depth; /* max depth ever */
+ int max_last_depth; /* max since last check */
+
+ /*
+ * Either the command completed immediately after being started
+ * (immed_comp), or the device did a bus release before dma was
+ * started (immed_rel).
+ */
+ int immed_rel;
+ int immed_comp;
+} ide_tag_info_t;
+
+#define IDE_GET_AR(drive, tag) ((drive)->tcq->ar[(tag)])
+#define IDE_CUR_TAG(drive) (IDE_GET_AR((drive), (drive)->tcq->active_tag))
+#define IDE_SET_CUR_TAG(drive, tag) ((drive)->tcq->active_tag = (tag))
+
+#define IDE_CUR_AR(drive) \
+ ((drive)->using_tcq ? IDE_CUR_TAG((drive)) : HWGROUP((drive))->rq->special)
+
struct ide_settings_s;

typedef struct ide_drive_s {
@@ -284,6 +318,8 @@
*/
request_queue_t queue; /* per device request queue */

+ struct list_head free_req; /* free ata requests */
+
struct ide_drive_s *next; /* circular list of hwgroup drives */

/* Those are directly injected jiffie values. They should go away and
@@ -298,6 +334,7 @@
special_t special; /* special action flags */
byte keep_settings; /* restore settings after drive reset */
byte using_dma; /* disk is using dma for read/write */
+ byte using_tcq; /* disk is using queued dma operations*/
byte retry_pio; /* retrying dma capable host in pio */
byte state; /* retry state */
byte unmask; /* flag: okay to unmask other irqs */
@@ -349,7 +386,7 @@
struct hd_driveid *id; /* drive model identification info */
struct hd_struct *part; /* drive partition table */

- char name[4]; /* drive name, such as "hda" */
+ char name[6]; /* drive name, such as "hda" */
struct ata_operations *driver;

void *driver_data; /* extra driver data */
@@ -373,6 +410,8 @@
unsigned int failures; /* current failure count */
unsigned int max_failures; /* maximum allowed failure count */
struct device device; /* global device tree handle */
+ unsigned int queue_depth;
+ ide_tag_info_t *tcq;
} ide_drive_t;

/*
@@ -391,7 +430,10 @@
ide_dma_off, ide_dma_off_quietly, ide_dma_test_irq,
ide_dma_bad_drive, ide_dma_good_drive,
ide_dma_verbose, ide_dma_retune,
- ide_dma_lostirq, ide_dma_timeout
+ ide_dma_lostirq, ide_dma_timeout,
+ ide_dma_read_queued, ide_dma_write_queued,
+ ide_dma_queued_start, ide_dma_queued_on,
+ ide_dma_queued_off,
} ide_dma_action_t;

typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
@@ -466,11 +508,6 @@
ide_rw_proc_t *rwproc; /* adjust timing based upon rq->cmd direction */
ide_ideproc_t *ideproc; /* CPU-polled transfer routine */
ide_dmaproc_t *dmaproc; /* dma read/write/abort routine */
- unsigned int *dmatable_cpu; /* dma physical region descriptor table (cpu view) */
- dma_addr_t dmatable_dma; /* dma physical region descriptor table (dma view) */
- struct scatterlist *sg_table; /* Scatter-gather list used to build the above */
- int sg_nents; /* Current number of entries in it */
- int sg_dma_direction; /* dma transfer direction */
unsigned long dma_base; /* base addr for dma ports */
unsigned dma_extra; /* extra addr for dma ports */
unsigned long config_data; /* for use by chipset-specific code */
@@ -530,21 +567,19 @@
#define IDE_DMA 2 /* DMA in progress */

typedef struct hwgroup_s {
- ide_handler_t *handler;/* irq handler, if active */
- unsigned long flags; /* BUSY, SLEEPING */
- ide_drive_t *drive; /* current drive */
- struct ata_channel *hwif; /* ptr to current hwif in linked-list */
+ ide_handler_t *handler; /* irq handler, if active */
+ unsigned long flags; /* BUSY, SLEEPING */
+ ide_drive_t *drive; /* current drive */
+ struct ata_channel *hwif; /* ptr to current hwif in linked-list */

- struct request *rq; /* current request */
+ struct request *rq; /* current request */

- struct timer_list timer; /* failsafe timer */
- struct request wrq; /* local copy of current write rq */
+ struct timer_list timer; /* failsafe timer */
+ struct request wrq; /* local copy of current write rq */
unsigned long poll_timeout; /* timeout value during long polls */
ide_expiry_t *expiry; /* queried upon timeouts */
} ide_hwgroup_t;

-/* structure attached to the request for IDE_TASK_CMDS */
-
/*
* configurable drive settings
*/
@@ -617,7 +652,7 @@
return len; \
}
#else
-#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0;
+# define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0;
#endif

/*
@@ -681,6 +716,7 @@

extern int __ide_end_request(ide_drive_t *drive, int uptodate, int nr_secs);
extern int ide_end_request(ide_drive_t *drive, int uptodate);
+extern void ide_end_queued_request(ide_drive_t *drive, int, struct request *);

/*
* This is used on exit from the driver, to designate the next irq handler
@@ -703,7 +739,7 @@
* 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,
@@ -711,7 +747,7 @@
* It is primarily used to tidy up the model name/number fields as
* returned by the WIN_[P]IDENTIFY commands.
*/
-void ide_fixstring (byte *s, const int bytecount, const int byteswap);
+void ide_fixstring(byte *s, const int bytecount, const int byteswap);

/*
* This routine busy-waits for the drive status to be not "busy".
@@ -721,31 +757,32 @@
* caller should return the updated value of "startstop" in this case.
* "startstop" is unchanged when the function returns 0;
*/
-int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
+int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout);

-int ide_wait_noerr (ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
+int ide_wait_noerr(ide_drive_t *drive, byte good, byte bad, unsigned long timeout);

/*
* This routine is called from the partition-table code in genhd.c
* to "convert" a drive to a logical geometry with fewer than 1024 cyls.
*/
-int ide_xlate_1024 (kdev_t, int, int, const char *);
+int ide_xlate_1024(kdev_t, int, int, const char *);

/*
* Convert kdev_t structure into ide_drive_t * one.
*/
-ide_drive_t *get_info_ptr (kdev_t i_rdev);
+ide_drive_t *get_info_ptr(kdev_t i_rdev);

/*
* Re-Start an operation for an IDE interface.
* The caller should return immediately after invoking this.
*/
-ide_startstop_t restart_request (ide_drive_t *);
+ide_startstop_t restart_request(ide_drive_t *);

/*
* This function is intended to be used prior to invoking ide_do_drive_cmd().
*/
-extern void ide_init_drive_cmd (struct request *rq);
+extern void ide_init_drive_cmd(struct request *rq);
+extern void init_taskfile_request(struct request *rq);

/*
* "action" parameter type for ide_do_drive_cmd() below.
@@ -775,8 +812,33 @@
int command_type;
ide_pre_handler_t *prehandler;
ide_handler_t *handler;
+ struct ata_request *ar;
};

+/*
+ * Merge this with the above struct soon.
+ */
+struct ata_request {
+ struct request *ar_rq; /* real request */
+ struct ide_drive_s *ar_drive; /* associated drive */
+ unsigned long ar_flags; /* ATA_AR_* flags */
+ int ar_tag; /* tag number, if any */
+ struct list_head ar_queue; /* pending list */
+ struct ata_taskfile ar_task; /* associated taskfile */
+ unsigned long ar_time;
+
+ /* DMA stuff, PCI layer */
+ struct scatterlist *ar_sg_table;
+ int ar_sg_nents;
+ int ar_sg_ddir;
+
+ /* CPU related DMA stuff */
+ unsigned int *ar_dmatable_cpu;
+ dma_addr_t ar_dmatable;
+};
+
+#define AR_TASK_CMD(ar) ((ar)->ar_task.taskfile.command)
+
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);
@@ -879,22 +941,24 @@
extern int ide_unregister_subdriver(ide_drive_t *drive);

#ifdef CONFIG_BLK_DEV_IDEPCI
-#define ON_BOARD 1
-#define NEVER_BOARD 0
-#ifdef CONFIG_BLK_DEV_OFFBOARD
-# define OFF_BOARD ON_BOARD
-#else
-# define OFF_BOARD NEVER_BOARD
-#endif
+# define ON_BOARD 1
+# define NEVER_BOARD 0
+# ifdef CONFIG_BLK_DEV_OFFBOARD
+# define OFF_BOARD ON_BOARD
+# else
+# define OFF_BOARD NEVER_BOARD
+# endif

-void __init ide_scan_pcibus(int scan_direction);
+/* FIXME: This should go away possible. */
+extern void __init ide_scan_pcibus(int scan_direction);
#endif
#ifdef CONFIG_BLK_DEV_IDEDMA
-int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func);
-void ide_destroy_dmatable (ide_drive_t *drive);
-ide_startstop_t ide_dma_intr (ide_drive_t *drive);
-int check_drive_lists (ide_drive_t *drive, int good_bad);
-int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
+extern int ide_build_dmatable(ide_drive_t *drive, struct request *rq, ide_dma_action_t func);
+extern void ide_destroy_dmatable(ide_drive_t *drive);
+extern int ide_start_dma(struct ata_channel *, ide_drive_t *, ide_dma_action_t);
+extern ide_startstop_t ide_dma_intr(ide_drive_t *drive);
+extern int check_drive_lists(ide_drive_t *drive, int good_bad);
+extern int ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
extern void ide_release_dma(struct ata_channel *hwif);
extern void ide_setup_dma(struct ata_channel *hwif,
unsigned long dmabase, unsigned int num_ports) __init;
@@ -907,4 +971,88 @@
extern int drive_is_ready(ide_drive_t *drive);
extern void revalidate_drives(void);

-#endif /* _IDE_H */
+/*
+ * Tagged Command Queueing:
+ */
+
+/*
+ * ata_request flag bits
+ */
+#define ATA_AR_QUEUED 1
+#define ATA_AR_SETUP 2
+#define ATA_AR_RETURN 4
+
+#define list_ata_entry(entry) list_entry((entry), struct ata_request, ar_queue)
+
+static inline void ata_ar_init(ide_drive_t *drive, struct ata_request *ar)
+{
+ ar->ar_rq = NULL;
+ ar->ar_drive = drive;
+ ar->ar_flags = 0;
+ ar->ar_tag = 0;
+ memset(&ar->ar_task, 0, sizeof(ar->ar_task));
+ ar->ar_sg_nents = 0;
+ ar->ar_sg_ddir = 0;
+}
+
+/*
+ * Return a free command, automatically add it to busy list.
+ */
+static inline struct ata_request *ata_ar_get(ide_drive_t *drive)
+{
+ struct ata_request *ar = NULL;
+
+ if (drive->tcq && drive->tcq->queued >= drive->queue_depth)
+ return NULL;
+
+ if (!list_empty(&drive->free_req)) {
+ ar = list_ata_entry(drive->free_req.next);
+ list_del(&ar->ar_queue);
+ ata_ar_init(drive, ar);
+ }
+
+ return ar;
+}
+
+static inline void ata_ar_put(ide_drive_t *drive, struct ata_request *ar)
+{
+ list_add(&ar->ar_queue, &drive->free_req);
+
+ if (ar->ar_flags & ATA_AR_QUEUED) {
+ /* clear the tag */
+ drive->tcq->ar[ar->ar_tag] = NULL;
+ __clear_bit(ar->ar_tag, &drive->tcq->tag_mask);
+ drive->tcq->queued--;
+ }
+
+ ar->ar_rq = NULL;
+}
+
+extern inline int ide_get_tag(ide_drive_t *drive)
+{
+ int tag = ffz(drive->tcq->tag_mask);
+
+ BUG_ON(drive->tcq->tag_mask == 0xffffffff);
+
+ __set_bit(tag, &drive->tcq->tag_mask);
+
+ if (tag + 1 > drive->tcq->max_depth)
+ drive->tcq->max_depth = tag + 1;
+ if (tag + 1 > drive->tcq->max_last_depth)
+ drive->tcq->max_last_depth = tag + 1;
+
+ return tag;
+}
+
+#ifdef CONFIG_BLK_DEV_IDE_TCQ
+# define ide_pending_commands(drive) ((drive)->using_tcq && (drive)->tcq->queued)
+#else
+# define ide_pending_commands(drive) 0
+#endif
+
+int ide_build_commandlist(ide_drive_t *);
+void ide_teardown_commandlist(ide_drive_t *);
+int ide_tcq_dmaproc(ide_dma_action_t, ide_drive_t *);
+ide_startstop_t ide_start_tag(ide_dma_action_t, ide_drive_t *, struct ata_request *);
+
+#endif


Attachments:
ide-clean-31.diff (84.18 kB)

2002-04-11 14:44:58

by Martin Dalecki

[permalink] [raw]
Subject: [PATCH] 2.5.8-pre3 IDE 32

diff -urN linux-2.5.8-pre3/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c
--- linux-2.5.8-pre3/drivers/ide/ide-disk.c Thu Apr 11 14:46:25 2002
+++ linux/drivers/ide/ide-disk.c Thu Apr 11 13:37:04 2002
@@ -386,23 +386,22 @@
{
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));
+ struct ata_taskfile args;

check_disk_change(inode->i_rdev);

- taskfile.command = WIN_DOORLOCK;
+ memset(&args, 0, sizeof(args));
+
+ args.taskfile.command = WIN_DOORLOCK;
+ ide_cmd_type_parser(&args);

/*
- * Ignore the return code from door_lock,
- * since the open() has already succeeded,
- * and the door_lock is irrelevant at this point.
+ * 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_taskfile(drive, &taskfile, &hobfile, NULL))
+
+ if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
drive->doorlocking = 0;
}
return 0;
@@ -410,33 +409,33 @@

static int idedisk_flushcache(ide_drive_t *drive)
{
- struct hd_drive_task_hdr taskfile;
- struct hd_drive_hob_hdr hobfile;
+ struct ata_taskfile args;
+
+ memset(&args, 0, sizeof(args));

- 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;
+ args.taskfile.command = WIN_FLUSH_CACHE_EXT;
else
- taskfile.command = WIN_FLUSH_CACHE;
+ args.taskfile.command = WIN_FLUSH_CACHE;

- return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+ ide_cmd_type_parser(&args);
+
+ return ide_raw_taskfile(drive, &args, NULL);
}

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));
+ struct ata_taskfile args;

invalidate_bdev(inode->i_bdev, 0);

- taskfile.command = WIN_DOORUNLOCK;
+ memset(&args, 0, sizeof(args));
+ args.taskfile.command = WIN_DOORUNLOCK;
+ ide_cmd_type_parser(&args);
+
if (drive->doorlocking &&
- ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
+ ide_raw_taskfile(drive, &args, NULL))
drive->doorlocking = 0;
}
if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
@@ -601,7 +600,7 @@
return flag;
}

-#endif /* CONFIG_IDEDISK_STROKE */
+#endif

/*
* Compute drive->capacity, the full capacity of the drive
@@ -767,45 +766,50 @@

static int smart_enable(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.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;
+ struct ata_taskfile args;
+
+ memset(&args, 0, sizeof(args));
+ args.taskfile.feature = SMART_ENABLE;
+ args.taskfile.low_cylinder = SMART_LCYL_PASS;
+ args.taskfile.high_cylinder = SMART_HCYL_PASS;
+ args.taskfile.command = WIN_SMART;
+ ide_cmd_type_parser(&args);
+
+ return ide_raw_taskfile(drive, &args, NULL);
+}
+
+static int get_smart_values(ide_drive_t *drive, u8 *buf)
+{
+ struct ata_taskfile args;
+
+ memset(&args, 0, sizeof(args));
+ args.taskfile.feature = SMART_READ_VALUES;
+ args.taskfile.sector_count = 0x01;
+ args.taskfile.low_cylinder = SMART_LCYL_PASS;
+ args.taskfile.high_cylinder = SMART_HCYL_PASS;
+ args.taskfile.command = WIN_SMART;
+ ide_cmd_type_parser(&args);
+
smart_enable(drive);
- return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
+
+ return ide_raw_taskfile(drive, &args, buf);
}

-static int get_smart_thresholds(ide_drive_t *drive, byte *buf)
+static int get_smart_thresholds(ide_drive_t *drive, u8 *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;
+ struct ata_taskfile args;
+
+ memset(&args, 0, sizeof(args));
+ args.taskfile.feature = SMART_READ_THRESHOLDS;
+ args.taskfile.sector_count = 0x01;
+ args.taskfile.low_cylinder = SMART_LCYL_PASS;
+ args.taskfile.high_cylinder = SMART_HCYL_PASS;
+ args.taskfile.command = WIN_SMART;
+ ide_cmd_type_parser(&args);
+
smart_enable(drive);
- return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
+
+ return ide_raw_taskfile(drive, &args, buf);
}

static int proc_idedisk_read_cache
@@ -947,7 +951,7 @@
ide_init_drive_cmd (&rq);
drive->mult_req = arg;
drive->special.b.set_multmode = 1;
- (void) ide_do_drive_cmd (drive, &rq, ide_wait);
+ ide_do_drive_cmd (drive, &rq, ide_wait);
return (drive->mult_count == arg) ? 0 : -EIO;
}

@@ -963,44 +967,46 @@

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;
+ struct ata_taskfile args;

if (!(drive->id->cfs_enable_2 & 0x3000))
return 1;

- ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+ memset(&args, 0, sizeof(args));
+ args.taskfile.feature = (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
+ args.taskfile.command = WIN_SETFEATURES;
+ ide_cmd_type_parser(&args);
+ ide_raw_taskfile(drive, &args, NULL);
+
drive->wcache = arg;
+
return 0;
}

static int 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);
+ struct ata_taskfile args;
+
+ memset(&args, 0, sizeof(args));
+ args.taskfile.command = WIN_STANDBYNOW1;
+ ide_cmd_type_parser(&args);
+
+ return ide_raw_taskfile(drive, &args, 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));
+ struct ata_taskfile args;

- taskfile.feature = (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM;
- taskfile.sector_count = arg;
+ memset(&args, 0, sizeof(args));
+ args.taskfile.feature = (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM;
+ args.taskfile.sector_count = arg;
+ args.taskfile.command = WIN_SETFEATURES;
+ ide_cmd_type_parser(&args);
+ ide_raw_taskfile(drive, &args, NULL);

- taskfile.command = WIN_SETFEATURES;
- ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
drive->acoustic = arg;
+
return 0;
}

diff -urN linux-2.5.8-pre3/drivers/ide/ide-proc.c linux/drivers/ide/ide-proc.c
--- linux-2.5.8-pre3/drivers/ide/ide-proc.c Wed Apr 10 14:38:29 2002
+++ linux/drivers/ide/ide-proc.c Thu Apr 11 13:48:32 2002
@@ -1,10 +1,6 @@
/*
- * linux/drivers/ide/ide-proc.c Version 1.03 January 2, 1998
- *
* Copyright (C) 1997-1998 Mark Lord
- */
-
-/*
+ *
* This is the /proc/ide/ filesystem implementation.
*
* The major reason this exists is to provide sufficient access
@@ -176,26 +172,26 @@
PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
}

-static int proc_ide_get_identify(ide_drive_t *drive, byte *buf)
+static int get_identify(ide_drive_t *drive, u8 *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));
+ struct ata_taskfile args;

- taskfile.sector_count = 0x01;
- taskfile.command = (drive->type == ATA_DISK) ? WIN_IDENTIFY : WIN_PIDENTIFY ;
+ memset(&args, 0, sizeof(args));
+ args.taskfile.sector_count = 0x01;
+ args.taskfile.command = (drive->type == ATA_DISK) ? WIN_IDENTIFY : WIN_PIDENTIFY ;
+ ide_cmd_type_parser(&args);

- return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
+ return ide_raw_taskfile(drive, &args, buf);
}

static int proc_ide_read_identify
(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- ide_drive_t *drive = data;
- int len = 0, i = 0;
+ ide_drive_t *drive = data;
+ int len = 0;
+ int i = 0;

- if (drive && !proc_ide_get_identify(drive, page)) {
+ if (drive && !get_identify(drive, page)) {
unsigned short *val = (unsigned short *) page;
char *out = ((char *)val) + (SECTOR_WORDS * 4);
page = out;
@@ -204,8 +200,7 @@
val += 1;
} while (i < (SECTOR_WORDS * 2));
len = out - page;
- }
- else
+ } else
len = sprintf(page, "\n");
PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
}
@@ -422,6 +417,8 @@
}
}

+/* FIXME: we should iterate over the hwifs here as everywhere else.
+ */
static void create_proc_ide_drives(struct ata_channel *hwif)
{
int d;
@@ -447,8 +444,6 @@
}
}
sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name);
- ent = proc_symlink(drive->name, proc_ide_root, name);
- if (!ent) return;
}
}

diff -urN linux-2.5.8-pre3/drivers/ide/ide-taskfile.c linux/drivers/ide/ide-taskfile.c
--- linux-2.5.8-pre3/drivers/ide/ide-taskfile.c Thu Apr 11 14:46:25 2002
+++ linux/drivers/ide/ide-taskfile.c Thu Apr 11 14:06:26 2002
@@ -891,39 +891,6 @@
rq->flags = REQ_DRIVE_TASKFILE;
}

-/*
- * This is kept for internal use only !!!
- * This is an internal call and nobody in user-space has a
- * 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;
- struct ata_request ar;
- struct ata_taskfile *args = &ar.ar_task;
-
- ata_ar_init(drive, &ar);
-
- memcpy(&args->taskfile, taskfile, sizeof(*taskfile));
- if (hobfile)
- memcpy(&args->hobfile, hobfile, sizeof(*hobfile));
-
- init_taskfile_request(&rq);
-
- /* This is kept for internal use only !!! */
- 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 = &ar;
-
- return ide_do_drive_cmd(drive, &rq, ide_wait);
-}
-
int ide_raw_taskfile(ide_drive_t *drive, struct ata_taskfile *args, byte *buf)
{
struct request rq;
@@ -932,6 +899,7 @@
ata_ar_init(drive, &ar);
init_taskfile_request(&rq);
rq.buffer = buf;
+
memcpy(&ar.ar_task, args, sizeof(*args));

if (args->command_type != IDE_DRIVE_TASK_NO_DATA)
@@ -1022,7 +990,7 @@
return err;
}

-int ide_task_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)
{
int err = 0;
u8 args[7];
@@ -1051,15 +1019,14 @@
EXPORT_SYMBOL(atapi_output_bytes);
EXPORT_SYMBOL(taskfile_input_data);
EXPORT_SYMBOL(taskfile_output_data);
-EXPORT_SYMBOL(ata_taskfile);

+EXPORT_SYMBOL(ata_taskfile);
EXPORT_SYMBOL(recal_intr);
EXPORT_SYMBOL(set_geometry_intr);
EXPORT_SYMBOL(set_multmode_intr);
EXPORT_SYMBOL(task_no_data_intr);
-
-EXPORT_SYMBOL(ide_wait_taskfile);
EXPORT_SYMBOL(ide_raw_taskfile);
EXPORT_SYMBOL(ide_cmd_type_parser);
+
EXPORT_SYMBOL(ide_cmd_ioctl);
EXPORT_SYMBOL(ide_task_ioctl);
diff -urN linux-2.5.8-pre3/drivers/ide/ide-tcq.c linux/drivers/ide/ide-tcq.c
--- linux-2.5.8-pre3/drivers/ide/ide-tcq.c Thu Apr 11 14:46:25 2002
+++ linux/drivers/ide/ide-tcq.c Thu Apr 11 13:49:30 2002
@@ -396,11 +396,9 @@
*/
static int ide_tcq_configure(ide_drive_t *drive)
{
- struct hd_drive_task_hdr taskfile;
+ struct ata_taskfile args;
int tcq_supp = 1 << 1 | 1 << 14;

- memset(&taskfile, 0, sizeof(taskfile));
-
/*
* bit 14 and 1 must be set in word 83 of the device id to indicate
* support for dma queued protocol
@@ -410,9 +408,12 @@
return 1;
}

- taskfile.feature = SETFEATURES_EN_WCACHE;
- taskfile.command = WIN_SETFEATURES;
- if (ide_wait_taskfile(drive, &taskfile, NULL, NULL)) {
+ memset(&args, 0, sizeof(args));
+ args.taskfile.feature = SETFEATURES_EN_WCACHE;
+ args.taskfile.command = WIN_SETFEATURES;
+ ide_cmd_type_parser(&args);
+
+ if (ide_raw_taskfile(drive, &args, NULL)) {
printk("%s: failed to enable write cache\n", drive->name);
return 1;
}
@@ -421,9 +422,12 @@
* disable RELease interrupt, it's quicker to poll this after
* having sent the command opcode
*/
- taskfile.feature = SETFEATURES_DIS_RI;
- taskfile.command = WIN_SETFEATURES;
- if (ide_wait_taskfile(drive, &taskfile, NULL, NULL)) {
+ memset(&args, 0, sizeof(args));
+ args.taskfile.feature = SETFEATURES_DIS_RI;
+ args.taskfile.command = WIN_SETFEATURES;
+ ide_cmd_type_parser(&args);
+
+ if (ide_raw_taskfile(drive, &args, NULL)) {
printk("%s: disabling release interrupt fail\n", drive->name);
return 1;
}
@@ -432,9 +436,12 @@
/*
* enable SERVICE interrupt
*/
- taskfile.feature = SETFEATURES_EN_SI;
- taskfile.command = WIN_SETFEATURES;
- if (ide_wait_taskfile(drive, &taskfile, NULL, NULL)) {
+ memset(&args, 0, sizeof(args));
+ args.taskfile.feature = SETFEATURES_EN_SI;
+ args.taskfile.command = WIN_SETFEATURES;
+ ide_cmd_type_parser(&args);
+
+ if (ide_raw_taskfile(drive, &args, NULL)) {
printk("%s: enabling service interrupt fail\n", drive->name);
return 1;
}
diff -urN linux-2.5.8-pre3/drivers/ide/ide.c linux/drivers/ide/ide.c
--- linux-2.5.8-pre3/drivers/ide/ide.c Thu Apr 11 14:46:25 2002
+++ linux/drivers/ide/ide.c Wed Apr 10 17:31:17 2002
@@ -494,8 +494,11 @@
if (ata_ops(drive) && ata_ops(drive)->capacity)
return ata_ops(drive)->capacity(drive);

- /* FIXME: This magic number seems to be bogous. */
- return 0x7fffffff;
+ /* This used to be 0x7fffffff, but since now we use the maximal drive
+ * capacity value used by other kernel subsystems as well.
+ */
+
+ return ~0UL;
}

/*
@@ -556,13 +559,12 @@
}
}

-static ide_startstop_t do_reset1 (ide_drive_t *, int); /* needed below */
+static ide_startstop_t do_reset1(ide_drive_t *, int); /* needed below */

/*
- * ATAPI_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
- * during an ATAPI drive reset operation. If the drive has not yet responded,
- * and we have not yet hit our maximum waiting time, then the timer is restarted
- * for another 50ms.
+ * Poll the interface for completion every 50ms during an ATAPI drive reset
+ * operation. If the drive has not yet responded, and we have not yet hit our
+ * maximum waiting time, then the timer is restarted for another 50ms.
*/
static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
{
@@ -589,10 +591,9 @@
}

/*
- * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
- * during an ide reset operation. If the drives have not yet responded,
- * and we have not yet hit our maximum waiting time, then the timer is restarted
- * for another 50ms.
+ * Poll the interface for completion every 50ms during an ata reset operation.
+ * If the drives have not yet responded, and we have not yet hit our maximum
+ * waiting time, then the timer is restarted for another 50ms.
*/
static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
{
@@ -905,9 +906,9 @@
}

/*
- * ide_error() takes action based on the error returned by the drive.
+ * Take action based on the error returned by the drive.
*/
-ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat)
+ide_startstop_t ide_error(ide_drive_t *drive, const char *msg, byte stat)
{
struct request *rq;
byte err;
@@ -968,10 +969,9 @@
}

/*
- * Issue a simple drive command
- * The drive must be selected beforehand.
+ * 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)
{
BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, handler, WAIT_CMD, NULL);
@@ -983,7 +983,7 @@
}

/*
- * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
+ * Invoked on completion of a special DRIVE_CMD.
*/
static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
{
@@ -1009,15 +1009,15 @@
}

/*
- * This routine busy-waits for the drive status to be not "busy".
- * It then checks the status for all of the "good" bits and none
- * of the "bad" bits, and if all is okay it returns 0. All other
- * cases return 1 after invoking ide_error() -- caller should just return.
+ * Busy-wait for the drive status to be not "busy". Check then the status for
+ * all of the "good" bits and none of the "bad" bits, and if all is okay it
+ * returns 0. All other cases return 1 after invoking ide_error() -- caller
+ * should just return.
*
* This routine should get fixed to not hog the cpu during extra long waits..
* That could be done by busy-waiting for the first jiffy or two, and then
- * setting a timer to wake up at half second intervals thereafter,
- * until timeout is achieved, before timing out.
+ * setting a timer to wake up at half second intervals thereafter, until
+ * timeout is achieved, before timing out.
*/
int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout) {
byte stat;
@@ -1243,8 +1243,8 @@
}

/*
- * ide_stall_queue() can be used by a drive to give excess bandwidth back
- * to the hwgroup by sleeping for timeout jiffies.
+ * This is used by a drive to give excess bandwidth back to the hwgroup by
+ * sleeping for timeout jiffies.
*/
void ide_stall_queue(ide_drive_t *drive, unsigned long timeout)
{
@@ -1254,7 +1254,7 @@
}

/*
- * choose_drive() selects the next drive which will be serviced.
+ * Select the next drive which will be serviced.
*/
static inline ide_drive_t *choose_drive(ide_hwgroup_t *hwgroup)
{
@@ -1482,7 +1482,7 @@
hwif->dmaproc(ide_dma_timeout, drive);

/*
- * disable dma for now, but remember that we did so because of
+ * Disable dma for now, but remember that we did so because of
* a timeout -- we'll reenable after we finish this next request
* (or rather the first chunk of it) in pio.
*/
@@ -1631,7 +1631,7 @@
*/
static void unexpected_intr(int irq, ide_hwgroup_t *hwgroup)
{
- byte stat;
+ u8 stat;
struct ata_channel *hwif = hwgroup->hwif;

/*
@@ -2167,7 +2167,7 @@
#endif

/*
- * Remove us from the kernel's knowledge
+ * Remove us from the kernel's knowledge.
*/
unregister_blkdev(channel->major, channel->name);
kfree(blksize_size[channel->major]);
@@ -2249,7 +2249,7 @@
case IDE_IRQ_OFFSET:
hw->io_ports[i] = intr;
break;
-#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
+#endif
default:
hw->io_ports[i] = 0;
break;
@@ -2316,7 +2316,7 @@
}

/*
- * Compatability function with existing drivers. If you want
+ * Compatability function for existing drivers. If you want
* something different, use the function above.
*/
int ide_register(int arg1, int arg2, int irq)
@@ -2327,7 +2327,7 @@
return ide_register_hw(&hw, NULL);
}

-void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
+void ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
{
ide_settings_t **p = &drive->settings;
ide_settings_t *setting = NULL;
@@ -2506,9 +2506,7 @@

void ide_add_generic_settings (ide_drive_t *drive)
{
-/*
- * drive setting name read/write access read ioctl write ioctl data type min max mul_factor div_factor data pointer set function
- */
+/* drive setting name read/write access read ioctl write ioctl data type min max mul_factor div_factor data pointer set function */
ide_add_setting(drive, "io_32bit", drive->no_io_32bit ? SETTING_READ : SETTING_RW, HDIO_GET_32BIT, HDIO_SET_32BIT, TYPE_BYTE, 0, 1 + (SUPPORT_VLB_SYNC << 1), 1, 1, &drive->io_32bit, set_io_32bit);
ide_add_setting(drive, "keepsettings", SETTING_RW, HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, TYPE_BYTE, 0, 1, 1, 1, &drive->keep_settings, NULL);
ide_add_setting(drive, "pio_mode", SETTING_WRITE, -1, HDIO_SET_PIO_MODE, TYPE_BYTE, 0, 255, 1, 1, NULL, set_pio_mode);
@@ -2757,8 +2755,6 @@
break;
}

-
-
/*
* pheew, all done, add to list
*/
@@ -2787,18 +2783,21 @@
static int ide_check_media_change (kdev_t i_rdev)
{
ide_drive_t *drive;
+ int res = 0; /* not changed */

- if ((drive = get_info_ptr(i_rdev)) == NULL)
+ drive = get_info_ptr(i_rdev);
+ if (!drive)
return -ENODEV;
+
if (ata_ops(drive)) {
ata_get(ata_ops(drive));
if (ata_ops(drive)->check_media_change)
- return ata_ops(drive)->check_media_change(drive);
+ res = ata_ops(drive)->check_media_change(drive);
else
- return 1; /* assume it was changed */
+ res = 1; /* assume it was changed */
ata_put(ata_ops(drive));
}
- return 0;
+ return res;
}

void ide_fixstring (byte *s, const int bytecount, const int byteswap)
@@ -2828,6 +2827,10 @@
*p++ = '\0';
}

+/****************************************************************************
+ * FIXME: rewrite the following crap:
+ */
+
/*
* stridx() returns the offset of c within s,
* or -1 if c is '\0' or not found within s.
@@ -2835,11 +2838,12 @@
static int __init stridx (const char *s, char c)
{
char *i = strchr(s, c);
+
return (i && c) ? i - s : -1;
}

/*
- * match_parm() does parsing for ide_setup():
+ * Parsing for ide_setup():
*
* 1. the first char of s must be '='.
* 2. if the remainder matches one of the supplied keywords,
@@ -3000,6 +3004,7 @@

printk(" : Enabled support for IDE doublers\n");
ide_doubler = 1;
+
return 1;
}
#endif
@@ -3007,6 +3012,7 @@
if (!strcmp(s, "ide=nodma")) {
printk("IDE: Prevented DMA\n");
noautodma = 1;
+
return 1;
}

@@ -3014,14 +3020,15 @@
if (!strcmp(s, "ide=reverse")) {
ide_scan_direction = 1;
printk(" : Enabled support for IDE inverse scan order.\n");
+
return 1;
}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif

/*
* Look for drive options: "hdx="
*/
- if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
+ if (!strncmp(s, "hd", 2) && s[2] >= 'a' && s[2] <= max_drive) {
const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom",
"serialize", "autotune", "noautotune",
"slow", "swapdata", "bswap", "flash",
@@ -3038,7 +3045,7 @@
/*
* Look for last lun option: "hdxlun="
*/
- if (s[3] == 'l' && s[4] == 'u' && s[5] == 'n') {
+ if (!strncmp(&s[3], "lun", 3)) {
if (match_parm(&s[6], NULL, vals, 1) != 1)
goto bad_option;
if (vals[0] >= 0 && vals[0] <= 7) {
@@ -3095,7 +3102,7 @@
#else
drive->scsi = 0;
goto bad_option;
-#endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */
+#endif
case 3: /* cyl,head,sect */
drive->type = ATA_DISK;
drive->cyl = drive->bios_cyl = vals[0];
@@ -3110,12 +3117,10 @@
}
}

- if (s[0] != 'i' || s[1] != 'd' || s[2] != 'e')
- goto bad_option;
/*
* Look for bus speed option: "idebus="
*/
- if (s[3] == 'b' && s[4] == 'u' && s[5] == 's') {
+ if (strncmp(s, "idebus", 6)) {
if (match_parm(&s[6], NULL, vals, 1) != 1)
goto bad_option;
if (vals[0] >= 20 && vals[0] <= 66) {
@@ -3124,13 +3129,14 @@
printk(" -- BAD BUS SPEED! Expected value from 20 to 66");
goto done;
}
+
/*
* Look for interface options: "idex="
*/
- if (s[3] >= '0' && s[3] <= max_hwif) {
+ if (!strncmp(s, "ide", 3) && s[3] >= '0' && s[3] <= max_hwif) {
/*
* Be VERY CAREFUL changing this: note hardcoded indexes below
- * -8,-9,-10 : are reserved for future idex calls to ease the hardcoding.
+ * -8,-9,-10. -11 : are reserved for future idex calls to ease the hardcoding.
*/
const char *ide_words[] = {
"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66",
@@ -3138,6 +3144,7 @@
"qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL };
hw = s[3] - '0';
hwif = &ide_hwifs[hw];
+
i = match_parm(&s[4], ide_words, vals, 3);

/*
@@ -3169,7 +3176,7 @@
init_ali14xx();
goto done;
}
-#endif /* CONFIG_BLK_DEV_ALI14XX */
+#endif
#ifdef CONFIG_BLK_DEV_UMC8672
case -16: /* "umc8672" */
{
@@ -3177,7 +3184,7 @@
init_umc8672();
goto done;
}
-#endif /* CONFIG_BLK_DEV_UMC8672 */
+#endif
#ifdef CONFIG_BLK_DEV_DTC2278
case -15: /* "dtc2278" */
{
@@ -3185,7 +3192,7 @@
init_dtc2278();
goto done;
}
-#endif /* CONFIG_BLK_DEV_DTC2278 */
+#endif
#ifdef CONFIG_BLK_DEV_CMD640
case -14: /* "cmd640_vlb" */
{
@@ -3193,7 +3200,7 @@
cmd640_vlb = 1;
goto done;
}
-#endif /* CONFIG_BLK_DEV_CMD640 */
+#endif
#ifdef CONFIG_BLK_DEV_HT6560B
case -13: /* "ht6560b" */
{
@@ -3201,7 +3208,7 @@
init_ht6560b();
goto done;
}
-#endif /* CONFIG_BLK_DEV_HT6560B */
+#endif
#if CONFIG_BLK_DEV_QD65XX
case -12: /* "qd65xx" */
{
@@ -3209,7 +3216,7 @@
init_qd65xx();
goto done;
}
-#endif /* CONFIG_BLK_DEV_QD65XX */
+#endif
case -11: /* minus11 */
case -10: /* minus10 */
case -9: /* minus9 */
@@ -3219,10 +3226,10 @@
#ifdef CONFIG_BLK_DEV_IDEPCI
hwif->udma_four = 1;
goto done;
-#else /* !CONFIG_BLK_DEV_IDEPCI */
+#else
hwif->udma_four = 0;
goto bad_hwif;
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
case -6: /* dma */
hwif->autodma = 1;
goto done;
@@ -3271,16 +3278,22 @@
return 1;
}
}
+
bad_option:
printk(" -- BAD OPTION\n");
return 1;
+
bad_hwif:
printk("-- NOT SUPPORTED ON ide%d", hw);
+
done:
printk("\n");
+
return 1;
}

+/****************************************************************************/
+
/* This is the default end request function as well */
int ide_end_request(ide_drive_t *drive, int uptodate)
{
diff -urN linux-2.5.8-pre3/drivers/ide/piix.c linux/drivers/ide/piix.c
--- linux-2.5.8-pre3/drivers/ide/piix.c Wed Apr 10 14:38:29 2002
+++ linux/drivers/ide/piix.c Thu Apr 11 11:22:45 2002
@@ -199,7 +199,7 @@

if (~piix_config->flags & PIIX_VICTORY) {
if ((piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_66 && (u & (1 << i))) umul = 2;
- if ((piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_100 && (u & ((1 << i) + 12))) umul = 1;
+ if ((piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_100 && (u & (1 << (i + 12)))) umul = 1;
udma[i] = (4 - ((e >> (i << 2)) & 3)) * umul;
} else udma[i] = (8 - ((e >> (i << 2)) & 7)) * 2;

diff -urN linux-2.5.8-pre3/include/linux/ide.h linux/include/linux/ide.h
--- linux-2.5.8-pre3/include/linux/ide.h Thu Apr 11 14:46:25 2002
+++ linux/include/linux/ide.h Thu Apr 11 13:56:22 2002
@@ -858,16 +858,14 @@
extern ide_startstop_t set_multmode_intr(ide_drive_t *drive);
extern ide_startstop_t task_no_data_intr(ide_drive_t *drive);

-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, struct ata_taskfile *cmd, byte *buf);

/* This is setting up all fields in args, which depend upon the command type.
*/
extern void ide_cmd_type_parser(struct ata_taskfile *args);
+extern int ide_raw_taskfile(ide_drive_t *drive, struct ata_taskfile *cmd, byte *buf);

-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);
+extern int ide_cmd_ioctl(ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+extern int ide_task_ioctl(ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);

void ide_delay_50ms (void);


Attachments:
ide-clean-32.diff (28.61 kB)

2002-04-14 14:57:54

by Martin Dalecki

[permalink] [raw]
Subject: [PATCH] 2.5.8-pre3 IDE 33

diff -urN linux-2.5.8-pre3/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c
--- linux-2.5.8-pre3/drivers/ide/ide-cd.c Wed Apr 10 14:38:29 2002
+++ linux/drivers/ide/ide-cd.c Sun Apr 14 16:13:51 2002
@@ -512,7 +512,7 @@
#endif /* not VERBOSE_IDE_CD_ERRORS */
}

-static void cdrom_queue_request_sense(ide_drive_t *drive,
+static void cdrom_queue_request_sense(ide_drive_t *drive,
struct completion *wait,
struct request_sense *sense,
struct packet_command *failed_command)
@@ -536,7 +536,7 @@
rq->flags = REQ_SENSE;
rq->special = (char *) pc;
rq->waiting = wait;
- (void) ide_do_drive_cmd(drive, rq, ide_preempt);
+ ide_do_drive_cmd(drive, rq, ide_preempt);
}


@@ -554,6 +554,7 @@
if ((rq->flags & REQ_CMD) && !rq->current_nr_sectors)
uptodate = 1;

+ HWGROUP(drive)->rq->special = NULL;
ide_end_request(drive, uptodate);
}

diff -urN linux-2.5.8-pre3/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c
--- linux-2.5.8-pre3/drivers/ide/ide-dma.c Fri Apr 12 00:43:19 2002
+++ linux/drivers/ide/ide-dma.c Sun Apr 14 16:19:16 2002
@@ -546,6 +546,12 @@
unsigned long dma_base = hwif->dma_base;
struct ata_request *ar = IDE_CUR_AR(drive);

+ /* This can happen with drivers abusing the special request field.
+ */
+
+ if (!ar)
+ return 1;
+
if (rq_data_dir(ar->ar_rq) == READ)
reading = 1 << 3;

diff -urN linux-2.5.8-pre3/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c
--- linux-2.5.8-pre3/drivers/ide/ide-probe.c Fri Apr 12 00:43:19 2002
+++ linux/drivers/ide/ide-probe.c Fri Apr 12 01:16:27 2002
@@ -195,6 +195,9 @@
#ifndef CONFIG_BLK_DEV_IDE_TCQ
drive->queue_depth = 1;
#else
+# ifndef CONFIG_BLK_DEV_IDE_TCQ_DEPTH
+# define CONFIG_BLK_DEV_IDE_TCQ_DEPTH 1
+# endif
drive->queue_depth = drive->id->queue_depth + 1;
if (drive->queue_depth > CONFIG_BLK_DEV_IDE_TCQ_DEPTH)
drive->queue_depth = CONFIG_BLK_DEV_IDE_TCQ_DEPTH;
diff -urN linux-2.5.8-pre3/drivers/ide/ide-taskfile.c linux/drivers/ide/ide-taskfile.c
--- linux-2.5.8-pre3/drivers/ide/ide-taskfile.c Fri Apr 12 00:43:23 2002
+++ linux/drivers/ide/ide-taskfile.c Fri Apr 12 14:33:01 2002
@@ -311,6 +311,7 @@
static ide_startstop_t task_mulout_intr (ide_drive_t *drive)
{
byte stat = GET_STAT();
+ /* FIXME: this should go possible as well */
byte io_32bit = drive->io_32bit;
struct request *rq = &HWGROUP(drive)->wrq;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
@@ -612,6 +613,7 @@
static ide_startstop_t task_out_intr(ide_drive_t *drive)
{
byte stat = GET_STAT();
+ /* FIXME: this should go possible as well */
byte io_32bit = drive->io_32bit;
struct request *rq = HWGROUP(drive)->rq;
char *pBuf = NULL;
@@ -628,7 +630,7 @@
rq = HWGROUP(drive)->rq;
pBuf = ide_map_rq(rq, &flags);
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);
ide_unmap_rq(rq, pBuf, &flags);
drive->io_32bit = io_32bit;
@@ -647,6 +649,7 @@
{
unsigned int msect, nsect;
byte stat = GET_STAT();
+ /* FIXME: this should go possible as well */
byte io_32bit = drive->io_32bit;
struct request *rq = HWGROUP(drive)->rq;
char *pBuf = NULL;
@@ -913,68 +916,76 @@
}

/*
- * Issue ATA command and wait for completion. Use for implementing commands in
- * kernel.
+ * Implement generic ioctls invoked from userspace to imlpement specific
+ * functionality.
+ *
+ * FIXME:
+ *
+ * 1. Rewrite hdparm to use the ide_task_ioctl function.
*
- * The caller has to make sure buf is never NULL!
+ * 2. Publish it.
+ *
+ * 3. Kill this and HDIO_DRIVE_CMD alltogether.
*/
-static int ide_wait_cmd(ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *argbuf)
-{
- struct request rq;
-
- /* FIXME: Do we really have to zero out the buffer?
- */
- memset(argbuf, 0, 4 + SECTOR_WORDS * 4 * sectors);
- ide_init_drive_cmd(&rq);
- rq.buffer = argbuf;
- argbuf[0] = cmd;
- argbuf[1] = nsect;
- argbuf[2] = feature;
- argbuf[3] = sectors;
-
- return ide_do_drive_cmd(drive, &rq, ide_wait);
-}

-int ide_cmd_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, unsigned long arg)
{
int err = 0;
- u8 args[4];
- u8 *argbuf = args;
+ u8 vals[4];
+ u8 *argbuf = vals;
byte xfer_rate = 0;
int argsize = 4;
- /* FIXME: this should not reside on the stack */
- struct ata_taskfile tfargs;
+ struct ata_taskfile args;
+ struct request rq;

+ /*
+ * First phase.
+ */
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))
+
+ /*
+ * Second phase.
+ */
+ if (copy_from_user(vals, (void *)arg, 4))
return -EFAULT;

- tfargs.taskfile.feature = args[2];
- tfargs.taskfile.sector_count = args[3];
- tfargs.taskfile.sector_number = args[1];
- tfargs.taskfile.low_cylinder = 0x00;
- tfargs.taskfile.high_cylinder = 0x00;
- tfargs.taskfile.device_head = 0x00;
- tfargs.taskfile.command = args[0];
+ args.taskfile.feature = vals[2];
+ args.taskfile.sector_count = vals[3];
+ args.taskfile.sector_number = vals[1];
+ args.taskfile.low_cylinder = 0x00;
+ args.taskfile.high_cylinder = 0x00;
+ args.taskfile.device_head = 0x00;
+ args.taskfile.command = vals[0];

- if (args[3]) {
- argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
+ if (vals[3]) {
+ argsize = 4 + (SECTOR_WORDS * 4 * vals[3]);
argbuf = kmalloc(argsize, GFP_KERNEL);
if (argbuf == NULL)
return -ENOMEM;
- memcpy(argbuf, args, 4);
+ memcpy(argbuf, vals, 4);
}
- if (set_transfer(drive, &tfargs)) {
- xfer_rate = args[1];
- if (ide_ata66_check(drive, &tfargs))
+
+ if (set_transfer(drive, &args)) {
+ xfer_rate = vals[1];
+ if (ide_ata66_check(drive, &args))
goto abort;
}

- err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
+ /* Issue ATA command and wait for completion.
+ */
+
+ /* FIXME: Do we really have to zero out the buffer?
+ */
+ memset(argbuf, 0, 4 + SECTOR_WORDS * 4 * vals[3]);
+ ide_init_drive_cmd(&rq);
+ rq.buffer = argbuf;
+ memcpy(argbuf, vals, 4);
+
+ err = ide_do_drive_cmd(drive, &rq, ide_wait);

if (!err && xfer_rate) {
/* active-retuning-calls future */
@@ -987,10 +998,11 @@
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 ide_task_ioctl(ide_drive_t *drive, unsigned long arg)
{
int err = 0;
u8 args[7];
diff -urN linux-2.5.8-pre3/drivers/ide/ide.c linux/drivers/ide/ide.c
--- linux-2.5.8-pre3/drivers/ide/ide.c Fri Apr 12 00:43:23 2002
+++ linux/drivers/ide/ide.c Fri Apr 12 01:40:11 2002
@@ -2640,12 +2640,12 @@
case HDIO_DRIVE_CMD:
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
return -EACCES;
- return ide_cmd_ioctl(drive, inode, file, cmd, arg);
+ return ide_cmd_ioctl(drive, arg);

case HDIO_DRIVE_TASK:
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
return -EACCES;
- return ide_task_ioctl(drive, inode, file, cmd, arg);
+ return ide_task_ioctl(drive, arg);

case HDIO_SET_NICE:
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
diff -urN linux-2.5.8-pre3/include/linux/ide.h linux/include/linux/ide.h
--- linux-2.5.8-pre3/include/linux/ide.h Fri Apr 12 00:43:23 2002
+++ linux/include/linux/ide.h Sun Apr 14 15:48:46 2002
@@ -864,10 +864,10 @@
extern void ide_cmd_type_parser(struct ata_taskfile *args);
extern int ide_raw_taskfile(ide_drive_t *drive, struct ata_taskfile *cmd, byte *buf);

-extern int ide_cmd_ioctl(ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-extern int ide_task_ioctl(ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+extern int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg);
+extern int ide_task_ioctl(ide_drive_t *drive, unsigned long arg);

-void ide_delay_50ms (void);
+void ide_delay_50ms(void);

byte ide_auto_reduce_xfer (ide_drive_t *drive);
int ide_driveid_update (ide_drive_t *drive);


Attachments:
ide-clean-33.diff (7.98 kB)

2002-04-15 14:47:40

by Martin Dalecki

[permalink] [raw]
Subject: [PATCH] 2.5.8 IDE 35

diff -urN linux-2.5.8/drivers/ide/Config.help linux/drivers/ide/Config.help
--- linux-2.5.8/drivers/ide/Config.help Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/Config.help Mon Apr 15 16:07:45 2002
@@ -753,9 +753,17 @@

If you have such a drive, say Y here.

-CONFIG_BLK_DEV_IDE_TCQ_DEFAULT
- Enabled tagged command queueing unconditionally on drives that report
- support for it.
+CONFIG_BLK_DEV_IDE_TCQ_FULL
+ When a command completes from the drive, the SERVICE bit is checked to
+ see if other queued commands are ready to be started. Doing this
+ immediately after a command completes has a tendency to 'starve' the
+ device hardware queue, since we risk emptying the queue completely
+ before starting any new commands. This shows up during stressing the
+ drive as a /\/\/\/\ queue size balance, where we could instead try and
+ maintain a minimum queue size and get a /---------\ graph instead.
+
+ Saying Y here will attempt to always keep the queue full when possible
+ at the cost of possibly increasing command turn-around latency.

Generally say Y here.

@@ -766,6 +774,18 @@
You probably just want the default of 32 here. If you enter an invalid
number, the default value will be used.

+CONFIG_BLK_DEV_IDE_TCQ_DEFAULT
+ Enabled tagged command queueing unconditionally on drives that report
+ support for it. Regardless of the chosen value here, tagging can be
+ controlled at run time:
+
+ echo "using_tcq:32" > /proc/ide/hdX/settings
+
+ where any value between 1-32 selects chosen queue depth and enables
+ TCQ, and 0 disables it.
+
+ Generally say Y here.
+
CONFIG_BLK_DEV_IT8172
Say Y here to support the on-board IDE controller on the Integrated
Technology Express, Inc. ITE8172 SBC. Vendor page at
diff -urN linux-2.5.8/drivers/ide/Config.in linux/drivers/ide/Config.in
--- linux-2.5.8/drivers/ide/Config.in Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/Config.in Mon Apr 15 16:07:45 2002
@@ -48,10 +48,11 @@
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 tagged command queueing' CONFIG_BLK_DEV_IDE_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI
- dep_bool ' TCQ on by default' CONFIG_BLK_DEV_IDE_TCQ_DEFAULT $CONFIG_BLK_DEV_IDE_TCQ
- if [ $CONFIG_BLK_DEV_IDE_TCQ_DEFAULT != "n" ]; then
- int ' Default queue depth' CONFIG_BLK_DEV_IDE_TCQ_DEPTH 32
- fi
+ dep_bool ' Attempt to keep queue full' CONFIG_BLK_DEV_IDE_TCQ_FULL $CONFIG_BLK_DEV_IDE_TCQ
+ dep_bool ' TCQ on by default' CONFIG_BLK_DEV_IDE_TCQ_DEFAULT $CONFIG_BLK_DEV_IDE_TCQ
+ if [ "$CONFIG_BLK_DEV_IDE_TCQ" != "n" ]; then
+ int ' Default queue depth' CONFIG_BLK_DEV_IDE_TCQ_DEPTH 8
+ fi
dep_bool ' ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
dep_bool ' Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP
dep_bool ' AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
diff -urN linux-2.5.8/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c
--- linux-2.5.8/drivers/ide/ide-disk.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/ide-disk.c Mon Apr 15 16:07:45 2002
@@ -107,10 +107,7 @@
* 48-bit commands are pretty sanely laid out
*/
if (lba48bit) {
- if (cmd == READ)
- command = WIN_READ_EXT;
- else
- command = WIN_WRITE_EXT;
+ command = cmd == READ ? WIN_READ_EXT : WIN_WRITE_EXT;

if (drive->using_dma) {
command++; /* WIN_*DMA_EXT */
@@ -118,31 +115,33 @@
command++; /* WIN_*DMA_QUEUED_EXT */
} else if (drive->mult_count)
command += 5; /* WIN_MULT*_EXT */
- } else {
- /*
- * 28-bit commands seem not to be, though...
- */
- if (cmd == READ) {
- if (drive->using_dma) {
- if (drive->using_tcq)
- command = WIN_READDMA_QUEUED;
- else
- command = WIN_READDMA;
- } else if (drive->mult_count)
- command = WIN_MULTREAD;
+
+ return command;
+ }
+
+ /*
+ * 28-bit commands seem not to be, though...
+ */
+ if (cmd == READ) {
+ if (drive->using_dma) {
+ if (drive->using_tcq)
+ command = WIN_READDMA_QUEUED;
else
- command = WIN_READ;
- } else {
- if (drive->using_dma) {
- if (drive->using_tcq)
- command = WIN_WRITEDMA_QUEUED;
- else
- command = WIN_WRITEDMA;
- } else if (drive->mult_count)
- command = WIN_MULTWRITE;
+ command = WIN_READDMA;
+ } else if (drive->mult_count)
+ command = WIN_MULTREAD;
+ else
+ command = WIN_READ;
+ } else {
+ if (drive->using_dma) {
+ if (drive->using_tcq)
+ command = WIN_WRITEDMA_QUEUED;
else
- command = WIN_WRITE;
- }
+ command = WIN_WRITEDMA;
+ } else if (drive->mult_count)
+ command = WIN_MULTWRITE;
+ else
+ command = WIN_WRITE;
}

return command;
@@ -895,24 +894,24 @@

__set_bit(i, &tag_mask);
len += sprintf(out+len, "%d, ", i);
- if (ar->ar_time > max_jif)
- max_jif = ar->ar_time;
+ if (cur_jif - ar->ar_time > max_jif)
+ max_jif = cur_jif - ar->ar_time;
cmds++;
}
len += sprintf(out+len, "]\n");

+ len += sprintf(out+len, "Queue:\t\t\treleased [ %d ] - started [ %d ]\n", drive->tcq->immed_rel, drive->tcq->immed_comp);
+
if (drive->tcq->queued != cmds)
- len += sprintf(out+len, "pending request and queue count mismatch (%d)\n", cmds);
+ len += sprintf(out+len, "pending request and queue count mismatch (counted: %d)\n", cmds);

if (tag_mask != drive->tcq->tag_mask)
len += sprintf(out+len, "tag masks differ (counted %lx != %lx\n", tag_mask, drive->tcq->tag_mask);

len += sprintf(out+len, "DMA status:\t\t%srunning\n", test_bit(IDE_DMA, &HWGROUP(drive)->flags) ? "" : "not ");

- if (max_jif)
- len += sprintf(out+len, "Oldest command:\t\t%lu\n", cur_jif - max_jif);
-
- len += sprintf(out+len, "immed rel %d, immed comp %d\n", drive->tcq->immed_rel, drive->tcq->immed_comp);
+ len += sprintf(out+len, "Oldest command:\t\t%lu jiffies\n", max_jif);
+ len += sprintf(out+len, "Oldest command ever:\t%lu\n", drive->tcq->oldest_command);

drive->tcq->max_last_depth = 0;

@@ -1017,8 +1016,10 @@
return -EPERM;
if (!drive->channel->dmaproc)
return -EPERM;
+ if (arg == drive->queue_depth && drive->using_tcq)
+ return 0;

- drive->using_tcq = arg;
+ drive->queue_depth = arg ? arg : 1;
if (drive->channel->dmaproc(arg ? ide_dma_queued_on : ide_dma_queued_off, drive))
return -EIO;

diff -urN linux-2.5.8/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c
--- linux-2.5.8/drivers/ide/ide-dma.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/ide-dma.c Mon Apr 15 16:07:45 2002
@@ -610,9 +610,6 @@
case ide_dma_check:
return config_drive_for_dma (drive);
case ide_dma_begin:
-#ifdef DEBUG
- printk("ide_dma_begin: from %p\n", __builtin_return_address(0));
-#endif
if (test_and_set_bit(IDE_DMA, &HWGROUP(drive)->flags))
BUG();
/* Note that this is done *after* the cmd has
@@ -634,14 +631,13 @@
case ide_dma_read:
reading = 1 << 3;
case ide_dma_write:
- ar = HWGROUP(drive)->rq->special;
+ ar = IDE_CUR_AR(drive);

if (ide_start_dma(hwif, drive, func))
return 1;

if (drive->type != ATA_DISK)
return 0;
-
BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry); /* issue cmd to drive */
if ((ar->ar_rq->flags & REQ_DRIVE_TASKFILE) &&
@@ -655,20 +651,13 @@
}
return hwif->dmaproc(ide_dma_begin, drive);
case ide_dma_end: /* returns 1 on error, 0 otherwise */
-#ifdef DEBUG
- printk("ide_dma_end: from %p\n", __builtin_return_address(0));
-#endif
- if (!test_and_clear_bit(IDE_DMA, &HWGROUP(drive)->flags)) {
- printk("ide_dma_end: dma not going? %p\n", __builtin_return_address(0));
- return 1;
- }
+ if (!test_and_clear_bit(IDE_DMA, &HWGROUP(drive)->flags))
+ BUG();
drive->waiting_for_dma = 0;
outb(inb(dma_base)&~1, dma_base); /* stop DMA */
dma_stat = inb(dma_base+2); /* get DMA status */
outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */
ide_destroy_dmatable(drive); /* purge DMA mappings */
- if (drive->tcq)
- IDE_SET_CUR_TAG(drive, -1);
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);
diff -urN linux-2.5.8/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c
--- linux-2.5.8/drivers/ide/ide-probe.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/ide-probe.c Mon Apr 15 16:07:45 2002
@@ -192,19 +192,16 @@
/*
* it's an ata drive, build command list
*/
-#ifndef CONFIG_BLK_DEV_IDE_TCQ
drive->queue_depth = 1;
+#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEPTH
+ drive->queue_depth = CONFIG_BLK_DEV_IDE_TCQ_DEPTH;
#else
-# ifndef CONFIG_BLK_DEV_IDE_TCQ_DEPTH
-# define CONFIG_BLK_DEV_IDE_TCQ_DEPTH 1
-# endif
drive->queue_depth = drive->id->queue_depth + 1;
- if (drive->queue_depth > CONFIG_BLK_DEV_IDE_TCQ_DEPTH)
- drive->queue_depth = CONFIG_BLK_DEV_IDE_TCQ_DEPTH;
+#endif
if (drive->queue_depth < 1 || drive->queue_depth > IDE_MAX_TAG)
drive->queue_depth = IDE_MAX_TAG;
-#endif
- if (ide_build_commandlist(drive))
+
+ if (ide_init_commandlist(drive))
goto err_misc;

return;
diff -urN linux-2.5.8/drivers/ide/ide-tcq.c linux/drivers/ide/ide-tcq.c
--- linux-2.5.8/drivers/ide/ide-tcq.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/ide-tcq.c Mon Apr 15 16:07:45 2002
@@ -29,9 +29,11 @@
#include <asm/delay.h>

/*
- * warning: it will be _very_ verbose if set to 1
+ * warning: it will be _very_ verbose if defined
*/
-#if 0
+#undef IDE_TCQ_DEBUG
+
+#ifdef IDE_TCQ_DEBUG
#define TCQ_PRINTK printk
#else
#define TCQ_PRINTK(x...)
@@ -49,13 +51,18 @@
*/
#undef IDE_TCQ_FIDDLE_SI

-int ide_tcq_end(ide_drive_t *drive);
+/*
+ * wait for data phase before starting DMA or not
+ */
+#undef IDE_TCQ_WAIT_DATAPHASE
+
ide_startstop_t ide_dmaq_intr(ide_drive_t *drive);
+ide_startstop_t ide_service(ide_drive_t *drive);

static inline void drive_ctl_nien(ide_drive_t *drive, int clear)
{
#ifdef IDE_TCQ_NIEN
- int mask = clear ? 0 : 2;
+ int mask = clear ? 0x00 : 0x02;

if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl | mask, IDE_CONTROL_REG);
@@ -142,7 +149,7 @@

spin_lock_irqsave(&ide_lock, flags);

- if (test_bit(IDE_BUSY, &hwgroup->flags))
+ if (test_and_set_bit(IDE_BUSY, &hwgroup->flags))
printk("ide_tcq_intr_timeout: hwgroup not busy\n");
if (hwgroup->handler == NULL)
printk("ide_tcq_intr_timeout: missing isr!\n");
@@ -151,6 +158,13 @@

spin_unlock_irqrestore(&ide_lock, flags);

+ /*
+ * if pending commands, try service before giving up
+ */
+ if (ide_pending_commands(drive) && (GET_STAT() & SERVICE_STAT))
+ if (ide_service(drive) == ide_started)
+ return;
+
if (drive)
ide_tcq_invalidate_queue(drive);
}
@@ -192,6 +206,7 @@

if (unlikely(i++ > IDE_TCQ_WAIT))
return 1;
+
} while ((*stat = GET_ALTSTAT()) & busy_mask);

return 0;
@@ -206,7 +221,12 @@
ide_startstop_t ide_service(ide_drive_t *drive)
{
struct ata_request *ar;
- byte feat, tag, stat;
+ byte feat, stat;
+ int tag;
+
+ TCQ_PRINTK("%s: started service\n", drive->name);
+
+ drive->service_pending = 0;

if (test_bit(IDE_DMA, &HWGROUP(drive)->flags))
printk("ide_service: DMA in progress\n");
@@ -238,9 +258,9 @@
* FIXME, invalidate queue
*/
if (stat & ERR_STAT) {
- printk("%s: error SERVICING drive (%x)\n", drive->name, stat);
ide_dump_status(drive, "ide_service", stat);
- return ide_tcq_end(drive);
+ ide_tcq_invalidate_queue(drive);
+ return ide_stopped;
}

/*
@@ -248,7 +268,7 @@
*/
if ((feat = GET_FEAT()) & NSEC_REL) {
printk("%s: release in service\n", drive->name);
- IDE_SET_CUR_TAG(drive, -1);
+ IDE_SET_CUR_TAG(drive, IDE_INACTIVE_TAG);
return ide_stopped;
}

@@ -265,6 +285,8 @@
return ide_stopped;
}

+ HWGROUP(drive)->rq = ar->ar_rq;
+
/*
* we'll start a dma read or write, device will trigger
* interrupt to indicate end of transfer, release is not allowed
@@ -287,6 +309,8 @@
{
byte stat;

+ TCQ_PRINTK("%s: ide_check_service\n", drive->name);
+
if (!ide_pending_commands(drive))
return ide_stopped;

@@ -300,40 +324,14 @@
return ide_started;
}

-int ide_tcq_end(ide_drive_t *drive)
-{
- byte stat = GET_STAT();
-
- if (stat & ERR_STAT) {
- ide_dump_status(drive, "ide_tcq_end", stat);
- ide_tcq_invalidate_queue(drive);
- return ide_stopped;
- } else if (stat & SERVICE_STAT) {
- TCQ_PRINTK("ide_tcq_end: serv stat=%x\n", stat);
- return ide_service(drive);
- }
-
- TCQ_PRINTK("ide_tcq_end: stat=%x, feat=%x\n", stat, GET_FEAT());
- return ide_stopped;
-}
-
ide_startstop_t ide_dmaq_complete(ide_drive_t *drive, byte stat)
{
- struct ata_request *ar;
+ struct ata_request *ar = IDE_CUR_TAG(drive);
byte dma_stat;

-#if 0
- byte feat = GET_FEAT();
-
- if ((feat & (NSEC_CD | NSEC_IO)) != (NSEC_CD | NSEC_IO))
- printk("%s: C/D | I/O not set\n", drive->name);
-#endif
-
/*
* transfer was in progress, stop DMA engine
*/
- ar = IDE_CUR_TAG(drive);
-
dma_stat = drive->channel->dmaproc(ide_dma_end, drive);

/*
@@ -352,7 +350,23 @@
TCQ_PRINTK("ide_dmaq_intr: ending %p, tag %d\n", ar, ar->ar_tag);
ide_end_queued_request(drive, !dma_stat, ar->ar_rq);

- IDE_SET_CUR_TAG(drive, -1);
+ IDE_SET_CUR_TAG(drive, IDE_INACTIVE_TAG);
+
+ /*
+ * keep the queue full, or honor SERVICE? note that this may race
+ * and no new command will be started, in which case idedisk_do_request
+ * will notice and do the service check
+ */
+#if CONFIG_BLK_DEV_IDE_TCQ_FULL
+ if (!drive->service_pending && (ide_pending_commands(drive) > 1)) {
+ if (!blk_queue_empty(&drive->queue)) {
+ drive->service_pending = 1;
+ ide_tcq_set_intr(HWGROUP(drive), ide_dmaq_intr);
+ return ide_released;
+ }
+ }
+#endif
+
return ide_check_service(drive);
}

@@ -376,7 +390,7 @@
* if a command completion interrupt is pending, do that first and
* check service afterwards
*/
- if (drive->tcq->active_tag != -1)
+ if (drive->tcq->active_tag != IDE_INACTIVE_TAG)
return ide_dmaq_complete(drive, stat);

/*
@@ -403,10 +417,8 @@
* bit 14 and 1 must be set in word 83 of the device id to indicate
* support for dma queued protocol
*/
- if ((drive->id->command_set_2 & tcq_supp) != tcq_supp) {
- printk("%s: queued feature set not supported\n", drive->name);
- return 1;
- }
+ if ((drive->id->command_set_2 & tcq_supp) != tcq_supp)
+ return -EIO;

memset(&args, 0, sizeof(args));
args.taskfile.feature = SETFEATURES_EN_WCACHE;
@@ -446,6 +458,16 @@
return 1;
}
#endif
+
+ if (!drive->tcq) {
+ drive->tcq = kmalloc(sizeof(ide_tag_info_t), GFP_ATOMIC);
+ if (!drive->tcq)
+ return -ENOMEM;
+
+ memset(drive->tcq, 0, sizeof(ide_tag_info_t));
+ drive->tcq->active_tag = IDE_INACTIVE_TAG;
+ }
+
return 0;
}

@@ -461,26 +483,33 @@
if (!on) {
printk("%s: TCQ disabled\n", drive->name);
drive->using_tcq = 0;
-
return 0;
- } else if (drive->using_tcq) {
- drive->queue_depth = drive->using_tcq;
-
- goto out;
}

if (ide_tcq_configure(drive)) {
drive->using_tcq = 0;
-
return 1;
}

-out:
- drive->tcq->max_depth = 0;
+ if (ide_build_commandlist(drive))
+ return 1;

printk("%s: tagged command queueing enabled, command queue depth %d\n", drive->name, drive->queue_depth);
drive->using_tcq = 1;
+ drive->tcq->max_depth = 0;
+ return 0;
+}

+int ide_tcq_wait_dataphase(ide_drive_t *drive)
+{
+#ifdef IDE_TCQ_WAIT_DATAPHASE
+ ide_startstop_t foo;
+
+ if (ide_wait_stat(&startstop, drive, READY_STAT | DRQ_STAT, BUSY_STAT, WAIT_READY)) {
+ printk("%s: timeout waiting for data phase\n", drive->name);
+ return 1;
+ }
+#endif
return 0;
}

@@ -488,7 +517,6 @@
{
struct ata_channel *hwif = drive->channel;
unsigned int reading = 0, enable_tcq = 1;
- ide_startstop_t startstop;
struct ata_request *ar;
byte stat, feat;

@@ -501,15 +529,13 @@
reading = 1 << 3;
case ide_dma_write_queued:
TCQ_PRINTK("ide_dma: setting up queued %d\n", drive->tcq->active_tag);
- BUG_ON(drive->tcq->active_tag == -1);
+ BUG_ON(drive->tcq->active_tag == IDE_INACTIVE_TAG);

if (!test_bit(IDE_BUSY, &HWGROUP(drive)->flags))
printk("queued_rw: IDE_BUSY not set\n");

- if (ide_wait_stat(&startstop, drive, READY_STAT | DRQ_STAT, BUSY_STAT, WAIT_READY)) {
- printk("%s: timeout waiting for data phase\n", drive->name);
- return startstop;
- }
+ if (ide_tcq_wait_dataphase(drive))
+ return ide_stopped;

if (ide_start_dma(hwif, drive, func))
return 1;
@@ -521,7 +547,7 @@
* start a queued command from scratch
*/
case ide_dma_queued_start:
- BUG_ON(drive->tcq->active_tag == -1);
+ BUG_ON(drive->tcq->active_tag == IDE_INACTIVE_TAG);
ar = IDE_CUR_TAG(drive);

/*
@@ -540,14 +566,19 @@
drive_ctl_nien(drive, 0);

if (stat & ERR_STAT) {
- printk("ide_dma_queued_start: abort (stat=%x)\n", stat);
+ ide_dump_status(drive, "tcq_start", stat);
return ide_stopped;
}

+ /*
+ * drive released the bus, clear active tag and
+ * check for service
+ */
if ((feat = GET_FEAT()) & NSEC_REL) {
+ IDE_SET_CUR_TAG(drive, IDE_INACTIVE_TAG);
drive->tcq->immed_rel++;
+
TCQ_PRINTK("REL in queued_start\n");
- IDE_SET_CUR_TAG(drive, -1);

if ((stat = GET_STAT()) & SERVICE_STAT)
return ide_service(drive);
@@ -558,21 +589,24 @@

drive->tcq->immed_comp++;

- if (ide_wait_stat(&startstop, drive, READY_STAT | DRQ_STAT, BUSY_STAT, WAIT_READY)) {
- printk("%s: timeout waiting for data phase\n", drive->name);
- return startstop;
- }
+ if (ide_tcq_wait_dataphase(drive))
+ return ide_stopped;

if (ide_start_dma(hwif, drive, func))
return ide_stopped;

+ /*
+ * need to arm handler before starting dma engine,
+ * transfer could complete right away
+ */
+ ide_tcq_set_intr(HWGROUP(drive), ide_dmaq_intr);
+
if (hwif->dmaproc(ide_dma_begin, drive))
return ide_stopped;

/*
* wait for SERVICE or completion interrupt
*/
- ide_tcq_set_intr(HWGROUP(drive), ide_dmaq_intr);
return ide_started;

case ide_dma_queued_off:
@@ -590,6 +624,10 @@
ide_startstop_t ide_start_tag(ide_dma_action_t func, ide_drive_t *drive,
struct ata_request *ar)
{
+ ide_startstop_t startstop;
+
+ TCQ_PRINTK("%s: ide_start_tag: begin tag %p/%d, rq %p\n", drive->name,ar,ar->ar_tag, ar->ar_rq);
+
/*
* do this now, no need to run that with interrupts disabled
*/
@@ -597,5 +635,14 @@
return ide_stopped;

IDE_SET_CUR_TAG(drive, ar->ar_tag);
- return ide_tcq_dmaproc(func, drive);
+ HWGROUP(drive)->rq = ar->ar_rq;
+
+ startstop = ide_tcq_dmaproc(func, drive);
+
+ if (unlikely(startstop == ide_stopped)) {
+ IDE_SET_CUR_TAG(drive, IDE_INACTIVE_TAG);
+ HWGROUP(drive)->rq = NULL;
+ }
+
+ return startstop;
}
diff -urN linux-2.5.8/drivers/ide/ide.c linux/drivers/ide/ide.c
--- linux-2.5.8/drivers/ide/ide.c Mon Apr 15 16:36:43 2002
+++ linux/drivers/ide/ide.c Mon Apr 15 16:13:05 2002
@@ -381,8 +381,23 @@
add_blkdev_randomness(major(rq->rq_dev));

spin_lock_irqsave(&ide_lock, flags);
+
+ if ((jiffies - ar->ar_time > ATA_AR_MAX_TURNAROUND) && drive->queue_depth > 1) {
+ printk("%s: exceeded max command turn-around time (%d seconds)\n", drive->name, ATA_AR_MAX_TURNAROUND / HZ);
+ drive->queue_depth >>= 1;
+ }
+
+ if (jiffies - ar->ar_time > drive->tcq->oldest_command)
+ drive->tcq->oldest_command = jiffies - ar->ar_time;
+
ata_ar_put(drive, ar);
end_that_request_last(rq);
+ /*
+ * IDE_SET_CUR_TAG(drive, IDE_INACTIVE_TAG) will do this
+ * too, but it really belongs here. assumes that the
+ * ended request is the active one.
+ */
+ HWGROUP(drive)->rq = NULL;
spin_unlock_irqrestore(&ide_lock, flags);
}
}
@@ -770,8 +785,7 @@
struct ata_taskfile *args = &ar->ar_task;

rq->errors = !OK_STAT(stat, READY_STAT, BAD_STAT);
- if (args && args->taskfile.command == WIN_NOP)
- printk(KERN_INFO "%s: NOP completed\n", __FUNCTION__);
+
if (args) {
args->taskfile.feature = err;
args->taskfile.sector_count = IN_BYTE(IDE_NSECTOR_REG);
@@ -1101,11 +1115,7 @@
while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
#endif

- if (test_bit(IDE_DMA, &HWGROUP(drive)->flags))
- printk("start_request: auch, DMA in progress 1\n");
SELECT_DRIVE(hwif, drive);
- if (test_bit(IDE_DMA, &HWGROUP(drive)->flags))
- printk("start_request: auch, DMA in progress 2\n");
if (ide_wait_stat(&startstop, drive, drive->ready_stat,
BUSY_STAT|DRQ_STAT, WAIT_READY)) {
printk(KERN_WARNING "%s: drive not ready for command\n", drive->name);
@@ -1277,6 +1287,170 @@
return best;
}

+static ide_drive_t *ide_choose_drive(ide_hwgroup_t *hwgroup)
+{
+ ide_drive_t *drive = choose_drive(hwgroup);
+ unsigned long sleep = 0;
+
+ if (drive)
+ return drive;
+
+ hwgroup->rq = NULL;
+ drive = hwgroup->drive;
+ do {
+ if (drive->PADAM_sleep && (!sleep || time_after(sleep, drive->PADAM_sleep)))
+ sleep = drive->PADAM_sleep;
+ } while ((drive = drive->next) != hwgroup->drive);
+
+ if (sleep) {
+ /*
+ * Take a short snooze, and then wake up this hwgroup
+ * again. This gives other hwgroups on the same a
+ * chance to play fairly with us, just in case there
+ * are big differences in relative throughputs.. don't
+ * want to hog the cpu too much.
+ */
+ if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep))
+ sleep = jiffies + WAIT_MIN_SLEEP;
+
+ if (timer_pending(&hwgroup->timer))
+ printk("ide_set_handler: timer already active\n");
+
+ set_bit(IDE_SLEEP, &hwgroup->flags);
+ mod_timer(&hwgroup->timer, sleep);
+ /* we purposely leave hwgroup busy while
+ * sleeping */
+ } else {
+ /* Ugly, but how can we sleep for the lock
+ * otherwise? perhaps from tq_disk? */
+ ide_release_lock(&ide_intr_lock);/* for atari only */
+ clear_bit(IDE_BUSY, &hwgroup->flags);
+ }
+
+ return NULL;
+}
+
+#ifdef CONFIG_BLK_DEV_IDE_TCQ
+ide_startstop_t ide_check_service(ide_drive_t *drive);
+#else
+#define ide_check_service(drive) (ide_stopped)
+#endif
+
+/*
+ * feed commands to a drive until it barfs. used to be part of ide_do_request.
+ * called with ide_lock/DRIVE_LOCK held and busy hwgroup
+ */
+static void ide_queue_commands(ide_drive_t *drive, int masked_irq)
+{
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ ide_startstop_t startstop = -1;
+ struct request *rq;
+ int do_service = 0;
+
+ do {
+ rq = NULL;
+
+ if (!test_bit(IDE_BUSY, &hwgroup->flags))
+ printk("%s: hwgroup not busy while queueing\n", drive->name);
+
+ /*
+ * abort early if we can't queue another command. for non
+ * tcq, ide_can_queue is always 1 since we never get here
+ * unless the drive is idle.
+ */
+ if (!ide_can_queue(drive)) {
+ if (!ide_pending_commands(drive))
+ clear_bit(IDE_BUSY, &hwgroup->flags);
+ break;
+ }
+
+ drive->PADAM_sleep = 0;
+ drive->PADAM_service_start = jiffies;
+
+ if (test_bit(IDE_DMA, &hwgroup->flags)) {
+ printk("ide_do_request: DMA in progress...\n");
+ break;
+ }
+
+ /*
+ * there's a small window between where the queue could be
+ * replugged while we are in here when using tcq (in which
+ * case the queue is probably empty anyways...), so check
+ * and leave if appropriate. When not using tcq, this is
+ * still a severe BUG!
+ */
+ if (blk_queue_plugged(&drive->queue)) {
+ BUG_ON(!drive->using_tcq);
+ break;
+ }
+
+ if (!(rq = elv_next_request(&drive->queue))) {
+ if (!ide_pending_commands(drive))
+ clear_bit(IDE_BUSY, &hwgroup->flags);
+ hwgroup->rq = NULL;
+ break;
+ }
+
+ /*
+ * if there are queued commands, we can't start a non-fs
+ * request (really, a non-queuable command) until the
+ * queue is empty
+ */
+ if (!(rq->flags & REQ_CMD) && ide_pending_commands(drive))
+ break;
+
+ hwgroup->rq = rq;
+
+service:
+ /*
+ * Some systems have trouble with IDE IRQs arriving while
+ * the driver is still setting things up. So, here we disable
+ * the IRQ used by this interface while the request is being
+ * started. This may look bad at first, but pretty much the
+ * same thing happens anyway when any interrupt comes in, IDE
+ * or otherwise -- the kernel masks the IRQ while it is being
+ * handled.
+ */
+ if (masked_irq && HWIF(drive)->irq != masked_irq)
+ disable_irq_nosync(HWIF(drive)->irq);
+
+ spin_unlock(&ide_lock);
+ ide__sti(); /* allow other IRQs while we start this request */
+ if (!do_service)
+ startstop = start_request(drive, rq);
+ else
+ startstop = ide_check_service(drive);
+
+ spin_lock_irq(&ide_lock);
+ if (masked_irq && HWIF(drive)->irq != masked_irq)
+ enable_irq(HWIF(drive)->irq);
+
+ /*
+ * command started, we are busy
+ */
+ if (startstop == ide_started)
+ break;
+
+ /*
+ * start_request() can return either ide_stopped (no command
+ * was started), ide_started (command started, don't queue
+ * more), or ide_released (command started, try and queue
+ * more).
+ */
+#if 0
+ if (startstop == ide_stopped)
+ set_bit(IDE_BUSY, &hwgroup->flags);
+#endif
+
+ } while (1);
+
+ if (startstop == ide_started)
+ return;
+
+ if ((do_service = drive->service_pending))
+ goto service;
+}
+
/*
* Issue a new request to a drive from hwgroup
* Caller must have already done spin_lock_irqsave(&ide_lock, ...)
@@ -1311,115 +1485,34 @@
{
ide_drive_t *drive;
struct ata_channel *hwif;
- ide_startstop_t startstop;
- struct request *rq;

ide_get_lock(&ide_intr_lock, ide_intr, hwgroup);/* for atari only: POSSIBLY BROKEN HERE(?) */

__cli(); /* necessary paranoia: ensure IRQs are masked on local CPU */

while (!test_and_set_bit(IDE_BUSY, &hwgroup->flags)) {
- drive = choose_drive(hwgroup);
- if (drive == NULL) {
- unsigned long sleep = 0;
- hwgroup->rq = NULL;
- drive = hwgroup->drive;
- do {
- if (drive->PADAM_sleep && (!sleep || time_after(sleep, drive->PADAM_sleep)))
- sleep = drive->PADAM_sleep;
- } while ((drive = drive->next) != hwgroup->drive);
- if (sleep) {
- /*
- * Take a short snooze, and then wake up this hwgroup again.
- * This gives other hwgroups on the same a chance to
- * play fairly with us, just in case there are big differences
- * in relative throughputs.. don't want to hog the cpu too much.
- */
- if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep))
- sleep = jiffies + WAIT_MIN_SLEEP;
-#if 1
- if (timer_pending(&hwgroup->timer))
- printk("ide_set_handler: timer already active\n");
-#endif
- set_bit(IDE_SLEEP, &hwgroup->flags);
- mod_timer(&hwgroup->timer, sleep);
- /* we purposely leave hwgroup busy while sleeping */
- } else {
- /* Ugly, but how can we sleep for the lock otherwise? perhaps from tq_disk? */
- ide_release_lock(&ide_intr_lock);/* for atari only */
- clear_bit(IDE_BUSY, &hwgroup->flags);
- }
- return; /* no more work for this hwgroup (for now) */
- }
+
+ /*
+ * will clear IDE_BUSY, if appropriate
+ */
+ if ((drive = ide_choose_drive(hwgroup)) == NULL)
+ break;
+
hwif = drive->channel;
- if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && hwif->io_ports[IDE_CONTROL_OFFSET]) {
+ if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && IDE_CONTROL_REG) {
/* set nIEN for previous hwif */
-
if (hwif->intrproc)
hwif->intrproc(drive);
else
- OUT_BYTE((drive)->ctl|2, hwif->io_ports[IDE_CONTROL_OFFSET]);
+ OUT_BYTE(drive->ctl|2, IDE_CONTROL_REG);
}
hwgroup->hwif = hwif;
hwgroup->drive = drive;
- drive->PADAM_sleep = 0;
-queue_next:
- drive->PADAM_service_start = jiffies;
-
- if (test_bit(IDE_DMA, &hwgroup->flags)) {
- printk("ide_do_request: DMA in progress...\n");
- break;
- }
-
- /*
- * there's a small window between where the queue could be
- * replugged while we are in here when using tcq (in which
- * case the queue is probably empty anyways...), so check
- * and leave if appropriate. When not using tcq, this is
- * still a severe BUG!
- */
- if (blk_queue_plugged(&drive->queue)) {
- BUG_ON(!drive->using_tcq);
- break;
- }

/*
- * just continuing an interrupted request maybe
- */
- rq = hwgroup->rq = elv_next_request(&drive->queue);
-
- if (!rq) {
- if (!ide_pending_commands(drive))
- clear_bit(IDE_BUSY, &HWGROUP(drive)->flags);
- break;
- }
-
- /*
- * Some systems have trouble with IDE IRQs arriving while
- * the driver is still setting things up. So, here we disable
- * the IRQ used by this interface while the request is being started.
- * This may look bad at first, but pretty much the same thing
- * happens anyway when any interrupt comes in, IDE or otherwise
- * -- the kernel masks the IRQ while it is being handled.
+ * main queueing loop
*/
- if (masked_irq && hwif->irq != masked_irq)
- disable_irq_nosync(hwif->irq);
-
- spin_unlock(&ide_lock);
- ide__sti(); /* allow other IRQs while we start this request */
- startstop = start_request(drive, rq);
-
- spin_lock_irq(&ide_lock);
- if (masked_irq && hwif->irq != masked_irq)
- enable_irq(hwif->irq);
-
- if (startstop == ide_released)
- goto queue_next;
- else if (startstop == ide_stopped) {
- if (test_bit(IDE_DMA, &hwgroup->flags))
- printk("2nd illegal clear\n");
- clear_bit(IDE_BUSY, &hwgroup->flags);
- }
+ ide_queue_commands(drive, masked_irq);
}
}

@@ -1673,6 +1766,7 @@
goto out_lock;

if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) {
+ printk("ide: unexpected interrupt\n");
/*
* Not expecting an interrupt from this drive.
* That means this could be:
@@ -1751,7 +1845,8 @@
} else {
printk("%s: ide_intr: huh? expected NULL handler on exit\n", drive->name);
}
- }
+ } else if (startstop == ide_released)
+ ide_queue_commands(drive, hwif->irq);

out_lock:
spin_unlock_irqrestore(&ide_lock, flags);
@@ -2221,6 +2316,8 @@
channel->udma_four = old_hwif.udma_four;
#ifdef CONFIG_BLK_DEV_IDEPCI
channel->pci_dev = old_hwif.pci_dev;
+#else
+ channel->pci_dev = NULL;
#endif
channel->straight8 = old_hwif.straight8;
abort:
@@ -2699,25 +2796,6 @@
}
}

-void ide_teardown_commandlist(ide_drive_t *drive)
-{
-#ifdef CONFIG_BLK_DEV_IDEPCI
- struct pci_dev *pdev = drive->channel->pci_dev;
-#else
- struct pci_dev *pdev = NULL;
-#endif
- struct list_head *entry;
-
- list_for_each(entry, &drive->free_req) {
- struct ata_request *ar = list_ata_entry(entry);
-
- list_del(&ar->ar_queue);
- kfree(ar->ar_sg_table);
- pci_free_consistent(pdev, PRD_SEGMENTS * PRD_BYTES, ar->ar_dmatable_cpu, ar->ar_dmatable);
- kfree(ar);
- }
-}
-
int ide_build_commandlist(ide_drive_t *drive)
{
#ifdef CONFIG_BLK_DEV_IDEPCI
@@ -2725,24 +2803,26 @@
#else
struct pci_dev *pdev = NULL;
#endif
+ struct list_head *p;
+ unsigned long flags;
struct ata_request *ar;
- ide_tag_info_t *tcq;
- int i, err;
+ int i, cur;

- tcq = kmalloc(sizeof(ide_tag_info_t), GFP_ATOMIC);
- if (!tcq)
- return -ENOMEM;
+ spin_lock_irqsave(&ide_lock, flags);

- drive->tcq = tcq;
- memset(drive->tcq, 0, sizeof(ide_tag_info_t));
+ cur = 0;
+ list_for_each(p, &drive->free_req)
+ cur++;

- INIT_LIST_HEAD(&drive->free_req);
- drive->using_tcq = 0;
+ /*
+ * for now, just don't shrink it...
+ */
+ if (drive->queue_depth <= cur) {
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return 0;
+ }

- err = -ENOMEM;
- for (i = 0; i < drive->queue_depth; i++) {
- /* Having kzmalloc would help reduce code size at quite
- * many places in kernel. */
+ for (i = cur; i < drive->queue_depth; i++) {
ar = kmalloc(sizeof(*ar), GFP_ATOMIC);
if (!ar)
break;
@@ -2767,25 +2847,33 @@
* pheew, all done, add to list
*/
list_add_tail(&ar->ar_queue, &drive->free_req);
+ ++cur;
}
+ drive->queue_depth = cur;
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return 0;
+}

- if (i) {
- drive->queue_depth = i;
- if (i >= 1) {
- drive->tcq->queued = 0;
- drive->tcq->active_tag = -1;
+int ide_init_commandlist(ide_drive_t *drive)
+{
+ INIT_LIST_HEAD(&drive->free_req);

- return 0;
- }
+ return ide_build_commandlist(drive);
+}

- kfree(drive->tcq);
- drive->tcq = NULL;
- err = 0;
- }
+void ide_teardown_commandlist(ide_drive_t *drive)
+{
+ struct pci_dev *pdev= drive->channel->pci_dev;
+ struct list_head *entry;

- kfree(drive->tcq);
- drive->tcq = NULL;
- return err;
+ list_for_each(entry, &drive->free_req) {
+ struct ata_request *ar = list_ata_entry(entry);
+
+ list_del(&ar->ar_queue);
+ kfree(ar->ar_sg_table);
+ pci_free_consistent(pdev, PRD_SEGMENTS * PRD_BYTES, ar->ar_dmatable_cpu, ar->ar_dmatable);
+ kfree(ar);
+ }
}

static int ide_check_media_change (kdev_t i_rdev)
@@ -3046,7 +3134,7 @@
unit = unit % MAX_DRIVES;
hwif = &ide_hwifs[hw];
drive = &hwif->drives[unit];
- if (strncmp(s + 4, "ide-", 4) == 0) {
+ if (!strncmp(s + 4, "ide-", 4)) {
strncpy(drive->driver_req, s + 4, 9);
goto done;
}
@@ -3128,7 +3216,7 @@
/*
* Look for bus speed option: "idebus="
*/
- if (strncmp(s, "idebus", 6)) {
+ if (!strncmp(s, "idebus", 6)) {
if (match_parm(&s[6], NULL, vals, 1) != 1)
goto bad_option;
if (vals[0] >= 20 && vals[0] <= 66) {
diff -urN linux-2.5.8/drivers/ide/pdc4030.c linux/drivers/ide/pdc4030.c
--- linux-2.5.8/drivers/ide/pdc4030.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/pdc4030.c Mon Apr 15 13:10:51 2002
@@ -648,6 +648,12 @@

memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));

+ /* The four drives on the two logical (one physical) interfaces
+ are distinguished by writing the drive number (0-3) to the
+ Feature register.
+ FIXME: Is promise_selectproc now redundant??
+ */
+ taskfile.feature = (drive->channel->unit << 1) + drive->select.b.unit;
taskfile.sector_count = rq->nr_sectors;
taskfile.sector_number = block;
taskfile.low_cylinder = (block>>=8);
diff -urN linux-2.5.8/include/linux/ide.h linux/include/linux/ide.h
--- linux-2.5.8/include/linux/ide.h Mon Apr 15 08:53:56 2002
+++ linux/include/linux/ide.h Mon Apr 15 16:07:45 2002
@@ -273,19 +273,22 @@
} b;
} special_t;

-#define IDE_MAX_TAG 32 /* spec says 32 max */
+#define IDE_MAX_TAG (32) /* spec says 32 max */
+#define IDE_INACTIVE_TAG (-1)

struct ata_request;
typedef struct ide_tag_info_s {
unsigned long tag_mask; /* next tag bit mask */
struct ata_request *ar[IDE_MAX_TAG]; /* in-progress requests */
int active_tag; /* current active tag */
+
int queued; /* current depth */

/*
* stats ->
*/
int max_depth; /* max depth ever */
+
int max_last_depth; /* max since last check */

/*
@@ -295,14 +298,19 @@
*/
int immed_rel;
int immed_comp;
+ unsigned long oldest_command;
} ide_tag_info_t;

#define IDE_GET_AR(drive, tag) ((drive)->tcq->ar[(tag)])
#define IDE_CUR_TAG(drive) (IDE_GET_AR((drive), (drive)->tcq->active_tag))
-#define IDE_SET_CUR_TAG(drive, tag) ((drive)->tcq->active_tag = (tag))
+#define IDE_SET_CUR_TAG(drive, tag) \
+ do { \
+ ((drive)->tcq->active_tag = (tag)); \
+ if ((tag) == IDE_INACTIVE_TAG) \
+ HWGROUP((drive))->rq = NULL; \
+ } while (0);

-#define IDE_CUR_AR(drive) \
- ((drive)->using_tcq ? IDE_CUR_TAG((drive)) : HWGROUP((drive))->rq->special)
+#define IDE_CUR_AR(drive) (HWGROUP((drive))->rq->special)

struct ide_settings_s;

@@ -359,6 +367,7 @@
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 service_pending: 1;
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 */
select_t select; /* basic drive/head select reg value */
@@ -546,7 +555,7 @@
typedef enum {
ide_stopped, /* no drive operation was started */
ide_started, /* a drive operation was started, and a handler was set */
- ide_released /* started and released bus */
+ ide_released, /* started, handler set, bus released */
} ide_startstop_t;

/*
@@ -980,6 +989,11 @@
#define ATA_AR_SETUP 2
#define ATA_AR_RETURN 4

+/*
+ * if turn-around time is longer than this, halve queue depth
+ */
+#define ATA_AR_MAX_TURNAROUND (3 * HZ)
+
#define list_ata_entry(entry) list_entry((entry), struct ata_request, ar_queue)

static inline void ata_ar_init(ide_drive_t *drive, struct ata_request *ar)
@@ -1026,7 +1040,7 @@
ar->ar_rq = NULL;
}

-extern inline int ide_get_tag(ide_drive_t *drive)
+static inline int ide_get_tag(ide_drive_t *drive)
{
int tag = ffz(drive->tcq->tag_mask);

@@ -1043,12 +1057,28 @@
}

#ifdef CONFIG_BLK_DEV_IDE_TCQ
-# define ide_pending_commands(drive) ((drive)->using_tcq && (drive)->tcq->queued)
+static inline int ide_pending_commands(ide_drive_t *drive)
+{
+ if (!drive->tcq)
+ return 0;
+
+ return drive->tcq->queued;
+}
+
+static inline int ide_can_queue(ide_drive_t *drive)
+{
+ if (!drive->tcq)
+ return 1;
+
+ return drive->tcq->queued < drive->queue_depth;
+}
#else
-# define ide_pending_commands(drive) 0
+#define ide_pending_commands(drive) (0)
+#define ide_can_queue(drive) (1)
#endif

int ide_build_commandlist(ide_drive_t *);
+int ide_init_commandlist(ide_drive_t *);
void ide_teardown_commandlist(ide_drive_t *);
int ide_tcq_dmaproc(ide_dma_action_t, ide_drive_t *);
ide_startstop_t ide_start_tag(ide_dma_action_t, ide_drive_t *, struct ata_request *);


Attachments:
ide-clean-35.diff (36.57 kB)

2002-04-16 08:07:45

by Martin Dalecki

[permalink] [raw]
Subject: [PATCH] 2.5.8 IDE 36

diff -urN linux-2.5.8/arch/cris/drivers/ide.c linux/arch/cris/drivers/ide.c
--- linux-2.5.8/arch/cris/drivers/ide.c Mon Apr 15 08:53:39 2002
+++ linux/arch/cris/drivers/ide.c Tue Apr 16 03:44:10 2002
@@ -272,13 +272,17 @@
printk("ide: ETRAX 100LX built-in ATA DMA controller\n");

/* first initialize the channel interface data */
-
+
for(h = 0; h < MAX_HWIFS; h++) {
struct ata_channel *hwif = &ide_hwifs[h];
+
hwif->chipset = ide_etrax100;
hwif->tuneproc = &tune_e100_ide;
hwif->dmaproc = &e100_dmaproc;
- hwif->ideproc = &e100_ideproc;
+ hwif->ata_read = e100_ide_input_data;
+ hwif->ata_write = e100_ide_input_data;
+ hwif->atapi_read = e100_atapi_read;
+ hwif->atapi_write = e100_atapi_write;
}
/* actually reset and configure the etrax100 ide/ata interface */

@@ -375,12 +379,12 @@
* so if an odd bytecount is specified, be sure that there's at least one
* extra byte allocated for the buffer.
*/
-static void
-e100_atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+static void
+e100_atapi_read(ide_drive_t *drive, void *buffer, unsigned int bytecount)
{
ide_ioreg_t data_reg = IDE_DATA_REG;

- D(printk("atapi_input_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
+ D(printk("atapi_read, dreg 0x%x, buffer 0x%x, count %d\n",
data_reg, buffer, bytecount));

if(bytecount & 1) {
@@ -454,12 +458,12 @@
#endif
}

-static void
-e100_atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+static void
+e100_atapi_write(ide_drive_t *drive, void *buffer, unsigned int bytecount)
{
ide_ioreg_t data_reg = IDE_DATA_REG;

- D(printk("atapi_output_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
+ D(printk("atapi_write, dreg 0x%x, buffer 0x%x, count %d\n",
data_reg, buffer, bytecount));

if(bytecount & 1) {
@@ -544,7 +548,7 @@
static void
e100_ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
{
- e100_atapi_input_bytes(drive, buffer, wcount << 2);
+ e100_atapi_read(drive, buffer, wcount << 2);
}

/*
@@ -553,7 +557,7 @@
static void
e100_ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
{
- e100_atapi_output_bytes(drive, buffer, wcount << 2);
+ e100_atapi_write(drive, buffer, wcount << 2);
}

/*
@@ -570,11 +574,11 @@
case ideproc_ide_output_data:
e100_ide_input_data(drive, buffer, length);
break;
- case ideproc_atapi_input_bytes:
- e100_atapi_input_bytes(drive, buffer, length);
+ case ideproc_atapi_read:
+ e100_atapi_read(drive, buffer, length);
break;
- case ideproc_atapi_output_bytes:
- e100_atapi_output_bytes(drive, buffer, length);
+ case ideproc_atapi_write:
+ e100_atapi_write(drive, buffer, length);
break;
default:
printk("e100_ideproc: unsupported func %d!\n", func);
diff -urN linux-2.5.8/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c
--- linux-2.5.8/drivers/ide/ide-cd.c Tue Apr 16 06:01:04 2002
+++ linux/drivers/ide/ide-cd.c Tue Apr 16 03:23:56 2002
@@ -791,7 +791,7 @@
ide_set_handler(drive, handler, timeout, cdrom_timer_expiry);

/* Send the command to the device. */
- atapi_output_bytes(drive, cmd, CDROM_PACKET_SIZE);
+ atapi_write(drive, cmd, CDROM_PACKET_SIZE);

return ide_started;
}
@@ -830,7 +830,7 @@
/* Read the data into the buffer. */
dest = info->buffer + info->nsectors_buffered * SECTOR_SIZE;
while (sectors_to_buffer > 0) {
- atapi_input_bytes (drive, dest, SECTOR_SIZE);
+ atapi_read(drive, dest, SECTOR_SIZE);
--sectors_to_buffer;
--sectors_to_transfer;
++info->nsectors_buffered;
@@ -840,7 +840,7 @@
/* Throw away any remaining data. */
while (sectors_to_transfer > 0) {
char dum[SECTOR_SIZE];
- atapi_input_bytes (drive, dum, sizeof (dum));
+ atapi_read(drive, dum, sizeof (dum));
--sectors_to_transfer;
}
}
@@ -866,7 +866,7 @@
and quit this request. */
while (len > 0) {
int dum = 0;
- atapi_output_bytes (drive, &dum, sizeof (dum));
+ atapi_write(drive, &dum, sizeof (dum));
len -= sizeof (dum);
}
} else if (ireason == 1) {
@@ -963,7 +963,7 @@
while (nskip > 0) {
/* We need to throw away a sector. */
char dum[SECTOR_SIZE];
- atapi_input_bytes (drive, dum, sizeof (dum));
+ atapi_read(drive, dum, SECTOR_SIZE);

--rq->current_nr_sectors;
--nskip;
@@ -994,7 +994,7 @@
/* Read this_transfer sectors
into the current buffer. */
while (this_transfer > 0) {
- atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE);
+ atapi_read(drive, rq->buffer, SECTOR_SIZE);
rq->buffer += SECTOR_SIZE;
--rq->nr_sectors;
--rq->current_nr_sectors;
@@ -1290,13 +1290,14 @@
/* The drive wants to be written to. */
if ((ireason & 3) == 0) {
/* Transfer the data. */
- atapi_output_bytes (drive, pc->buffer, thislen);
+ atapi_write(drive, pc->buffer, thislen);

/* If we haven't moved enough data to satisfy the drive,
add some padding. */
while (len > thislen) {
int dum = 0;
- atapi_output_bytes (drive, &dum, sizeof (dum));
+
+ atapi_write(drive, &dum, sizeof (dum));
len -= sizeof (dum);
}

@@ -1307,15 +1308,14 @@

/* Same drill for reading. */
else if ((ireason & 3) == 2) {
-
/* Transfer the data. */
- atapi_input_bytes (drive, pc->buffer, thislen);
+ atapi_read(drive, pc->buffer, thislen);

/* If we haven't moved enough data to satisfy the drive,
add some padding. */
while (len > thislen) {
int dum = 0;
- atapi_input_bytes (drive, &dum, sizeof (dum));
+ atapi_read(drive, &dum, sizeof (dum));
len -= sizeof (dum);
}

@@ -1458,7 +1458,7 @@
and quit this request. */
while (len > 0) {
int dum = 0;
- atapi_output_bytes(drive, &dum, sizeof(dum));
+ atapi_write(drive, &dum, sizeof(dum));
len -= sizeof(dum);
}
} else {
@@ -1549,7 +1549,7 @@
this_transfer = MIN(sectors_to_transfer,rq->current_nr_sectors);

while (this_transfer > 0) {
- atapi_output_bytes(drive, rq->buffer, SECTOR_SIZE);
+ atapi_write(drive, rq->buffer, SECTOR_SIZE);
rq->buffer += SECTOR_SIZE;
--rq->nr_sectors;
--rq->current_nr_sectors;
diff -urN linux-2.5.8/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c
--- linux-2.5.8/drivers/ide/ide-disk.c Tue Apr 16 06:01:07 2002
+++ linux/drivers/ide/ide-disk.c Tue Apr 16 05:38:16 2002
@@ -1051,7 +1051,6 @@
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, 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, "lun", SETTING_RW, -1, -1, TYPE_INT, 0, 7, 1, 1, &drive->lun, NULL);
@@ -1198,11 +1197,11 @@
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);
+ printk(KERN_INFO "%s: %ld sectors", drive->name, capacity);

/* Give size in megabytes (MB), not mebibytes (MiB). */
/* We compute the exact rounded value, avoiding overflow. */
- printk (" (%ld MB)", (capacity - capacity/625 + 974)/1950);
+ printk(" (%ld MB)", (capacity - capacity/625 + 974)/1950);

/* Only print cache size when it was specified */
if (id->buf_size)
@@ -1213,7 +1212,7 @@
#ifdef CONFIG_BLK_DEV_IDEDMA
if (drive->using_dma)
(void) drive->channel->dmaproc(ide_dma_verbose, drive);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+#endif
printk("\n");

drive->mult_count = 0;
@@ -1223,15 +1222,17 @@
id->multsect_valid = id->multsect ? 1 : 0;
drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT;
drive->special.b.set_multmode = drive->mult_req ? 1 : 0;
-#else /* original, pre IDE-NFG, per request of AC */
+#else
+ /* original, pre IDE-NFG, per request of AC */
drive->mult_req = INITIAL_MULT_COUNT;
if (drive->mult_req > id->max_multsect)
drive->mult_req = id->max_multsect;
if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
drive->special.b.set_multmode = 1;
-#endif /* CONFIG_IDEDISK_MULTI_MODE */
+#endif
}
drive->no_io_32bit = id->dword_io ? 1 : 0;
+
if (drive->id->cfs_enable_2 & 0x3000)
write_cache(drive, (id->cfs_enable_2 & 0x3000));
probe_lba_addressing(drive, 1);
diff -urN linux-2.5.8/drivers/ide/ide-features.c linux/drivers/ide/ide-features.c
--- linux-2.5.8/drivers/ide/ide-features.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/ide-features.c Tue Apr 16 02:36:34 2002
@@ -130,8 +130,8 @@
__restore_flags(flags); /* local CPU only */
return 0;
}
- ata_input_data(drive, id, SECTOR_WORDS);
- (void) GET_STAT(); /* clear drive IRQ */
+ ata_read(drive, id, SECTOR_WORDS);
+ GET_STAT(); /* clear drive IRQ */
ide__sti(); /* local CPU only */
__restore_flags(flags); /* local CPU only */
ide_fix_driveid(id);
@@ -285,7 +285,7 @@
enable_irq(hwif->irq);

if (error) {
- (void) ide_dump_status(drive, "set_drive_speed_status", stat);
+ ide_dump_status(drive, "set_drive_speed_status", stat);
return error;
}

diff -urN linux-2.5.8/drivers/ide/ide-floppy.c linux/drivers/ide/ide-floppy.c
--- linux-2.5.8/drivers/ide/ide-floppy.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/ide-floppy.c Tue Apr 16 03:24:42 2002
@@ -717,7 +717,7 @@
return;
}
count = IDEFLOPPY_MIN (bio->bi_size - pc->b_count, bcount);
- atapi_input_bytes (drive, bio_data(bio) + pc->b_count, count);
+ atapi_read(drive, bio_data(bio) + pc->b_count, count);
bcount -= count; pc->b_count += count;
}
}
@@ -744,7 +744,7 @@
return;
}
count = IDEFLOPPY_MIN (pc->b_count, bcount);
- atapi_output_bytes (drive, pc->b_data, count);
+ atapi_write(drive, pc->b_data, count);
bcount -= count; pc->b_data += count; pc->b_count -= count;
}
}
@@ -979,12 +979,12 @@
}
if (test_bit (PC_WRITING, &pc->flags)) {
if (pc->buffer != NULL)
- atapi_output_bytes (drive,pc->current_position,bcount.all); /* Write the current buffer */
+ atapi_write(drive,pc->current_position,bcount.all); /* Write the current buffer */
else
idefloppy_output_buffers (drive, pc, bcount.all);
} else {
if (pc->buffer != NULL)
- atapi_input_bytes (drive,pc->current_position,bcount.all); /* Read the current buffer */
+ atapi_read(drive,pc->current_position,bcount.all); /* Read the current buffer */
else
idefloppy_input_buffers (drive, pc, bcount.all);
}
@@ -1020,7 +1020,7 @@

BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* Set the interrupt routine */
- atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
+ atapi_write(drive, floppy->pc->c, 12); /* Send the actual packet */

return ide_started;
}
@@ -1042,7 +1042,7 @@
{
idefloppy_floppy_t *floppy = drive->driver_data;

- atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
+ atapi_write(drive, floppy->pc->c, 12); /* Send the actual packet */
return IDEFLOPPY_WAIT_CMD; /* Timeout for the packet command */
}

diff -urN linux-2.5.8/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c
--- linux-2.5.8/drivers/ide/ide-probe.c Tue Apr 16 06:01:07 2002
+++ linux/drivers/ide/ide-probe.c Tue Apr 16 03:48:14 2002
@@ -57,9 +57,18 @@
printk(KERN_WARNING "(ide-probe::do_identify) Out of memory.\n");
goto err_kmalloc;
}
- /* read 512 bytes of id info */
+
+ /* Read 512 bytes of id info.
+ *
+ * Please note that it is well known that some *very* old drives are
+ * able to provide only 256 of them, since this was the amount read by
+ * DOS.
+ *
+ * However let's try to get away with this...
+ */
+
#if 1
- ata_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */
+ ata_read(drive, id, SECTOR_WORDS);
#else
{
unsigned long *ptr = (unsigned long *)id ;
@@ -580,10 +589,10 @@
__restore_flags(flags); /* local CPU only */
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
- if (drive->present) {
- ide_tuneproc_t *tuneproc = drive->channel->tuneproc;
- if (tuneproc != NULL && drive->autotune == 1)
- tuneproc(drive, 255); /* auto-tune PIO mode */
+
+ if (drive->present && (drive->autotune == 1)) {
+ if (drive->channel->tuneproc != NULL)
+ drive->channel->tuneproc(drive, 255); /* auto-tune PIO mode */
}
}
}
diff -urN linux-2.5.8/drivers/ide/ide-proc.c linux/drivers/ide/ide-proc.c
--- linux-2.5.8/drivers/ide/ide-proc.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/ide-proc.c Tue Apr 16 04:05:19 2002
@@ -422,7 +422,6 @@
static void create_proc_ide_drives(struct ata_channel *hwif)
{
int d;
- struct proc_dir_entry *ent;
struct proc_dir_entry *parent = hwif->proc;
char name[64];

diff -urN linux-2.5.8/drivers/ide/ide-tape.c linux/drivers/ide/ide-tape.c
--- linux-2.5.8/drivers/ide/ide-tape.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/ide-tape.c Tue Apr 16 03:25:29 2002
@@ -1503,9 +1503,9 @@
idetape_discard_data (drive, bcount);
return;
}
-#endif /* IDETAPE_DEBUG_BUGS */
+#endif
count = min(bio->bi_size - pc->b_count, bcount);
- atapi_input_bytes (drive, bio_data(bio) + pc->b_count, count);
+ atapi_read(drive, bio_data(bio) + pc->b_count, count);
bcount -= count;
pc->b_count += bio->bi_size;
if (pc->b_count == bio->bi_size) {
@@ -1530,7 +1530,7 @@
}
#endif /* IDETAPE_DEBUG_BUGS */
count = min(pc->b_count, bcount);
- atapi_output_bytes (drive, bio_data(bio), count);
+ atapi_write(drive, bio_data(bio), count);
bcount -= count;
pc->b_data += count;
pc->b_count -= count;
@@ -2169,12 +2169,12 @@
if (pc->bio != NULL)
idetape_output_buffers (drive, pc, bcount.all);
else
- atapi_output_bytes (drive,pc->current_position,bcount.all); /* Write the current buffer */
+ atapi_write(drive,pc->current_position,bcount.all); /* Write the current buffer */
} else {
if (pc->bio != NULL)
idetape_input_buffers (drive, pc, bcount.all);
else
- atapi_input_bytes (drive,pc->current_position,bcount.all); /* Read the current buffer */
+ atapi_read(drive,pc->current_position,bcount.all); /* Read the current buffer */
}
pc->actually_transferred += bcount.all; /* Update the current position */
pc->current_position+=bcount.all;
@@ -2259,7 +2259,7 @@
tape->cmd_start_time = jiffies;
BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); /* Set the interrupt routine */
- atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */
+ atapi_write(drive,pc->c,12); /* Send the actual packet */
return ide_started;
}

diff -urN linux-2.5.8/drivers/ide/ide-taskfile.c linux/drivers/ide/ide-taskfile.c
--- linux-2.5.8/drivers/ide/ide-taskfile.c Tue Apr 16 06:01:04 2002
+++ linux/drivers/ide/ide-taskfile.c Tue Apr 16 05:38:53 2002
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2002 Marcin Dalecki <[email protected]>
* Copyright (C) 2000 Michael Cornwell <[email protected]>
* Copyright (C) 2000 Andre Hedrick <[email protected]>
*
@@ -58,15 +59,9 @@
bio_kunmap_irq(to, flags);
}

-static void bswap_data (void *buffer, int wcount)
-{
- u16 *p = buffer;
-
- while (wcount--) {
- *p = *p << 8 | *p >> 8; p++;
- *p = *p << 8 | *p >> 8; p++;
- }
-}
+/*
+ * Data transfer functions for polled IO.
+ */

#if SUPPORT_VLB_SYNC
/*
@@ -76,30 +71,88 @@
* of the sector count register location, with interrupts disabled
* to ensure that the reads all happen together.
*/
-static inline void task_vlb_sync(ide_drive_t *drive)
+static void ata_read_vlb(struct ata_device *drive, void *buffer, unsigned int wcount)
{
- ide_ioreg_t port = IDE_NSECTOR_REG;
+ unsigned long flags;

- IN_BYTE(port);
- IN_BYTE(port);
- IN_BYTE(port);
+ __save_flags(flags); /* local CPU only */
+ __cli(); /* local CPU only */
+ IN_BYTE(IDE_NSECTOR_REG);
+ IN_BYTE(IDE_NSECTOR_REG);
+ IN_BYTE(IDE_NSECTOR_REG);
+ insl(IDE_DATA_REG, buffer, wcount);
+ __restore_flags(flags); /* local CPU only */
+}
+
+static void ata_write_vlb(struct ata_device *drive, void *buffer, unsigned int wcount)
+{
+ unsigned long flags;
+
+ __save_flags(flags); /* local CPU only */
+ __cli(); /* local CPU only */
+ IN_BYTE(IDE_NSECTOR_REG);
+ IN_BYTE(IDE_NSECTOR_REG);
+ IN_BYTE(IDE_NSECTOR_REG);
+ outsl(IDE_DATA_REG, buffer, wcount);
+ __restore_flags(flags); /* local CPU only */
}
#endif

+static void ata_read_32(struct ata_device *drive, void *buffer, unsigned int wcount)
+{
+ insl(IDE_DATA_REG, buffer, wcount);
+}
+
+static void ata_write_32(struct ata_device *drive, void *buffer, unsigned int wcount)
+{
+ outsl(IDE_DATA_REG, buffer, wcount);
+}
+
+#if SUPPORT_SLOW_DATA_PORTS
+static void ata_read_slow(struct ata_device *drive, void *buffer, unsigned int wcount)
+{
+ unsigned short *ptr = (unsigned short *) buffer;
+
+ while (wcount--) {
+ *ptr++ = inw_p(IDE_DATA_REG);
+ *ptr++ = inw_p(IDE_DATA_REG);
+ }
+}
+
+static void ata_write_slow(struct ata_device *drive, void *buffer, unsigned int wcount)
+{
+ unsigned short *ptr = (unsigned short *) buffer;
+
+ while (wcount--) {
+ outw_p(*ptr++, IDE_DATA_REG);
+ outw_p(*ptr++, IDE_DATA_REG);
+ }
+}
+#endif
+
+static void ata_read_16(ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+ insw(IDE_DATA_REG, buffer, wcount<<1);
+}
+
+static void ata_write_16(ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+ outsw(IDE_DATA_REG, buffer, wcount<<1);
+}
+
/*
- * This is used for most PIO data transfers *from* the IDE interface
+ * This is used for most PIO data transfers *from* the device.
*/
-void ata_input_data(ide_drive_t *drive, void *buffer, unsigned int wcount)
+void ata_read(ide_drive_t *drive, void *buffer, unsigned int wcount)
{
- byte io_32bit;
+ int io_32bit;

/*
- * first check if this controller has defined a special function
- * for handling polled ide transfers
+ * First check if this controller has defined a special function
+ * for handling polled ide transfers.
*/
-
- if (drive->channel->ideproc) {
- drive->channel->ideproc(ideproc_ide_input_data, drive, buffer, wcount);
+ if (drive->channel->ata_read) {
+ drive->channel->ata_read(drive, buffer, wcount);
return;
}

@@ -107,39 +160,30 @@

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(drive);
- insl(IDE_DATA_REG, buffer, wcount);
- __restore_flags(flags); /* local CPU only */
- } else
+ if (io_32bit & 2)
+ ata_read_vlb(drive, buffer, wcount);
+ else
#endif
- insl(IDE_DATA_REG, buffer, wcount);
+ ata_read_32(drive, 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
+ if (drive->slow)
+ ata_read_slow(drive, buffer, wcount);
+ else
#endif
- insw(IDE_DATA_REG, buffer, wcount<<1);
+ ata_read_16(drive, buffer, wcount);
}
}

/*
- * This is used for most PIO data transfers *to* the IDE interface
+ * This is used for most PIO data transfers *to* the device interface.
*/
-void ata_output_data(ide_drive_t *drive, void *buffer, unsigned int wcount)
+void ata_write(ide_drive_t *drive, void *buffer, unsigned int wcount)
{
- byte io_32bit;
+ int io_32bit;

- if (drive->channel->ideproc) {
- drive->channel->ideproc(ideproc_ide_output_data, drive, buffer, wcount);
+ if (drive->channel->ata_write) {
+ drive->channel->ata_write(drive, buffer, wcount);
return;
}

@@ -147,27 +191,18 @@

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(drive);
- outsl(IDE_DATA_REG, buffer, wcount);
- __restore_flags(flags); /* local CPU only */
- } else
+ if (io_32bit & 2)
+ ata_write_vlb(drive, buffer, wcount);
+ else
#endif
- outsl(IDE_DATA_REG, buffer, wcount);
+ ata_write_32(drive, 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
+ if (drive->slow)
+ ata_write_slow(drive, buffer, wcount);
+ else
#endif
- outsw(IDE_DATA_REG, buffer, wcount<<1);
+ ata_write_16(drive, buffer, wcount<<1);
}
}

@@ -178,10 +213,10 @@
* 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)
+void atapi_read(ide_drive_t *drive, void *buffer, unsigned int bytecount)
{
- if (drive->channel->ideproc) {
- drive->channel->ideproc(ideproc_atapi_input_bytes, drive, buffer, bytecount);
+ if (drive->channel->atapi_read) {
+ drive->channel->atapi_read(drive, buffer, bytecount);
return;
}

@@ -193,15 +228,15 @@
return;
}
#endif
- ata_input_data (drive, buffer, bytecount / 4);
+ ata_read(drive, buffer, bytecount / 4);
if ((bytecount & 0x03) >= 2)
- insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
+ insw(IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
}

-void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+void atapi_write(ide_drive_t *drive, void *buffer, unsigned int bytecount)
{
- if (drive->channel->ideproc) {
- drive->channel->ideproc(ideproc_atapi_output_bytes, drive, buffer, bytecount);
+ if (drive->channel->atapi_write) {
+ drive->channel->atapi_write(drive, buffer, bytecount);
return;
}

@@ -213,29 +248,11 @@
return;
}
#endif
- ata_output_data (drive, buffer, bytecount / 4);
+ ata_write(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)
- bswap_data(buffer, wcount);
-}
-
-void taskfile_output_data(ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
- if (drive->bswap) {
- bswap_data(buffer, wcount);
- ata_output_data(drive, buffer, wcount);
- bswap_data(buffer, wcount);
- } else {
- ata_output_data(drive, buffer, wcount);
- }
-}
-
/*
* Needed for PCI irq sharing
*/
@@ -311,8 +328,6 @@
static ide_startstop_t task_mulout_intr (ide_drive_t *drive)
{
byte stat = GET_STAT();
- /* FIXME: this should go possible as well */
- byte io_32bit = drive->io_32bit;
struct request *rq = &HWGROUP(drive)->wrq;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
int mcount = drive->mult_count;
@@ -378,14 +393,13 @@
}

/*
- * Ok, we're all setup for the interrupt
- * re-entering us on the last transfer.
+ * Ok, we're all setup for the interrupt re-entering us on the
+ * last transfer.
*/
- taskfile_output_data(drive, buffer, nsect * SECTOR_WORDS);
+ ata_write(drive, buffer, nsect * SECTOR_WORDS);
bio_kunmap_irq(buffer, &flags);
} while (mcount);

- drive->io_32bit = io_32bit;
rq->errors = 0;
if (hwgroup->handler == NULL)
ide_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
@@ -542,7 +556,6 @@
static 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;
unsigned long flags;
@@ -561,10 +574,8 @@
pBuf = ide_map_rq(rq, &flags);
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);
+ ata_read(drive, pBuf, SECTOR_WORDS);
ide_unmap_rq(rq, pBuf, &flags);
- drive->io_32bit = io_32bit;

if (--rq->current_nr_sectors <= 0) {
/* (hs): swapped next 2 lines */
@@ -597,7 +608,7 @@
unsigned long flags;
char *buf = ide_map_rq(rq, &flags);
/* For Write_sectors we need to stuff the first sector */
- taskfile_output_data(drive, buf, SECTOR_WORDS);
+ ata_write(drive, buf, SECTOR_WORDS);
rq->current_nr_sectors--;
ide_unmap_rq(rq, buf, &flags);
} else {
@@ -613,8 +624,6 @@
static ide_startstop_t task_out_intr(ide_drive_t *drive)
{
byte stat = GET_STAT();
- /* FIXME: this should go possible as well */
- byte io_32bit = drive->io_32bit;
struct request *rq = HWGROUP(drive)->rq;
char *pBuf = NULL;
unsigned long flags;
@@ -631,9 +640,8 @@
pBuf = ide_map_rq(rq, &flags);
DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);

- taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+ ata_write(drive, pBuf, SECTOR_WORDS);
ide_unmap_rq(rq, pBuf, &flags);
- drive->io_32bit = io_32bit;
rq->errors = 0;
rq->current_nr_sectors--;
}
@@ -649,8 +657,6 @@
{
unsigned int msect, nsect;
byte stat = GET_STAT();
- /* FIXME: this should go possible as well */
- byte io_32bit = drive->io_32bit;
struct request *rq = HWGROUP(drive)->rq;
char *pBuf = NULL;
unsigned long flags;
@@ -676,10 +682,8 @@

DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %d\n",
pBuf, nsect, rq->current_nr_sectors);
- drive->io_32bit = 0;
- taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+ ata_read(drive, pBuf, nsect * SECTOR_WORDS);
ide_unmap_rq(rq, pBuf, &flags);
- drive->io_32bit = io_32bit;
rq->errors = 0;
rq->current_nr_sectors -= nsect;
msect -= nsect;
@@ -1025,12 +1029,11 @@
}

EXPORT_SYMBOL(drive_is_ready);
-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(ata_read);
+EXPORT_SYMBOL(ata_write);
+EXPORT_SYMBOL(atapi_read);
+EXPORT_SYMBOL(atapi_write);

EXPORT_SYMBOL(ata_taskfile);
EXPORT_SYMBOL(recal_intr);
diff -urN linux-2.5.8/drivers/ide/ide.c linux/drivers/ide/ide.c
--- linux-2.5.8/drivers/ide/ide.c Tue Apr 16 06:01:07 2002
+++ linux/drivers/ide/ide.c Tue Apr 16 05:38:37 2002
@@ -383,7 +383,7 @@
spin_lock_irqsave(&ide_lock, flags);

if ((jiffies - ar->ar_time > ATA_AR_MAX_TURNAROUND) && drive->queue_depth > 1) {
- printk("%s: exceeded max command turn-around time (%d seconds)\n", drive->name, ATA_AR_MAX_TURNAROUND / HZ);
+ printk(KERN_INFO "%s: exceeded max command turn-around time (%d seconds)\n", drive->name, ATA_AR_MAX_TURNAROUND / HZ);
drive->queue_depth >>= 1;
}

@@ -474,7 +474,7 @@
spin_unlock_irqrestore(&ide_lock, flags);
}

-static void ata_pre_reset (ide_drive_t *drive)
+static void ata_pre_reset(ide_drive_t *drive)
{
if (ata_ops(drive) && ata_ops(drive)->pre_reset)
ata_ops(drive)->pre_reset(drive);
@@ -528,10 +528,9 @@
printk("%s: ata_special: 0x%02x\n", drive->name, s->all);
#endif
if (s->b.set_tune) {
- ide_tuneproc_t *tuneproc = drive->channel->tuneproc;
s->b.set_tune = 0;
- if (tuneproc != NULL)
- tuneproc(drive, drive->tune_req);
+ if (drive->channel->tuneproc != NULL)
+ drive->channel->tuneproc(drive, drive->tune_req);
} else if (drive->driver != NULL) {
if (ata_ops(drive)->special)
return ata_ops(drive)->special(drive);
@@ -899,23 +898,24 @@
}

/*
- * 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 gets invoked in response to a drive unexpectedly having its DRQ_STAT
+ * bit set. As an alternative to resetting the drive, it tries to clear the
+ * condition by reading a sector's worth of data from the drive. Of course,
* this may not help if the drive is *waiting* for data from *us*.
*/
static void try_to_flush_leftover_data (ide_drive_t *drive)
{
- int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
+ int i = (drive->mult_count ? drive->mult_count : 1);

if (drive->type != ATA_DISK)
return;
+
while (i > 0) {
- u32 buffer[16];
- unsigned int wcount = (i > 16) ? 16 : i;
- i -= wcount;
- ata_input_data (drive, buffer, wcount);
+ u32 buffer[SECTOR_WORDS];
+ unsigned int count = (i > 1) ? 1 : i;
+
+ ata_read(drive, buffer, count * SECTOR_WORDS);
+ i -= count;
}
}

@@ -1002,16 +1002,18 @@
static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
{
struct request *rq = HWGROUP(drive)->rq;
- byte *args = (byte *) rq->buffer;
- byte stat = GET_STAT();
+ u8 *args = rq->buffer;
+ u8 stat = GET_STAT();
int retries = 10;

ide__sti(); /* local CPU only */
if ((stat & DRQ_STAT) && args && args[3]) {
- byte io_32bit = drive->io_32bit;
+ int io_32bit = drive->io_32bit;
+
drive->io_32bit = 0;
- ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
+ ata_read(drive, &args[4], args[3] * SECTOR_WORDS);
drive->io_32bit = io_32bit;
+
while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
udelay(100);
}
@@ -1019,6 +1021,7 @@
if (!OK_STAT(stat, READY_STAT, BAD_STAT))
return ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
ide_end_drive_cmd (drive, stat, GET_ERR());
+
return ide_stopped;
}

@@ -1266,31 +1269,26 @@
/*
* Select the next drive which will be serviced.
*/
-static inline ide_drive_t *choose_drive(ide_hwgroup_t *hwgroup)
+static ide_drive_t *choose_drive(ide_hwgroup_t *hwgroup)
{
- ide_drive_t *drive, *best;
+ ide_drive_t *tmp;
+ ide_drive_t *drive = NULL;
+ unsigned long sleep = 0;

- best = NULL;
- drive = hwgroup->drive;
+ tmp = hwgroup->drive;
do {
- if (!list_empty(&drive->queue.queue_head)
- && (!drive->PADAM_sleep || time_after_eq(drive->PADAM_sleep, jiffies))) {
- if (!best
- || (drive->PADAM_sleep && (!best->PADAM_sleep || time_after(best->PADAM_sleep, drive->PADAM_sleep)))
- || (!best->PADAM_sleep && time_after(best->PADAM_service_start + 2 * best->PADAM_service_time, drive->PADAM_service_start + 2 * drive->PADAM_service_time)))
+ if (!list_empty(&tmp->queue.queue_head)
+ && (!tmp->PADAM_sleep || time_after_eq(tmp->PADAM_sleep, jiffies))) {
+ if (!drive
+ || (tmp->PADAM_sleep && (!drive->PADAM_sleep || time_after(drive->PADAM_sleep, tmp->PADAM_sleep)))
+ || (!drive->PADAM_sleep && time_after(drive->PADAM_service_start + 2 * drive->PADAM_service_time, tmp->PADAM_service_start + 2 * tmp->PADAM_service_time)))
{
- if (!blk_queue_plugged(&drive->queue))
- best = drive;
+ if (!blk_queue_plugged(&tmp->queue))
+ drive = tmp;
}
}
- } while ((drive = drive->next) != hwgroup->drive);
- return best;
-}
-
-static ide_drive_t *ide_choose_drive(ide_hwgroup_t *hwgroup)
-{
- ide_drive_t *drive = choose_drive(hwgroup);
- unsigned long sleep = 0;
+ tmp = tmp->next;
+ } while (tmp != hwgroup->drive);

if (drive)
return drive;
@@ -1495,7 +1493,7 @@
/*
* will clear IDE_BUSY, if appropriate
*/
- if ((drive = ide_choose_drive(hwgroup)) == NULL)
+ if ((drive = choose_drive(hwgroup)) == NULL)
break;

hwif = drive->channel;
@@ -2298,7 +2296,10 @@
channel->maskproc = old_hwif.maskproc;
channel->quirkproc = old_hwif.quirkproc;
channel->rwproc = old_hwif.rwproc;
- channel->ideproc = old_hwif.ideproc;
+ channel->ata_read = old_hwif.ata_read;
+ channel->ata_write = old_hwif.ata_write;
+ channel->atapi_read = old_hwif.atapi_read;
+ channel->atapi_write = old_hwif.atapi_write;
channel->dmaproc = old_hwif.dmaproc;
channel->busproc = old_hwif.busproc;
channel->bus_state = old_hwif.bus_state;
@@ -2565,13 +2566,17 @@
return 0;
}

-static int set_io_32bit(ide_drive_t *drive, int arg)
+static int set_io_32bit(struct ata_device *drive, int arg)
{
+ if (drive->no_io_32bit)
+ return -EIO;
+
drive->io_32bit = arg;
#ifdef CONFIG_BLK_DEV_DTC2278
if (drive->channel->chipset == ide_dtc2278)
drive->channel->drives[!drive->select.b.unit].io_32bit = arg;
-#endif /* CONFIG_BLK_DEV_DTC2278 */
+#endif
+
return 0;
}

@@ -3018,8 +3023,6 @@
* "hdx=slow" : insert a huge pause after each access to the data
* port. Should be used only as a last resort.
*
- * "hdx=swapdata" : when the drive is a disk, byte swap all data
- * "hdx=bswap" : same as above..........
* "hdxlun=xx" : set the drive last logical unit.
* "hdx=flash" : allows for more than one ata_flash disk to be
* registered. In most cases, only one device
@@ -3127,8 +3130,7 @@
if (!strncmp(s, "hd", 2) && s[2] >= 'a' && s[2] <= max_drive) {
const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom",
"serialize", "autotune", "noautotune",
- "slow", "swapdata", "bswap", "flash",
- "remap", "noremap", "scsi", NULL};
+ "slow", "flash", "remap", "noremap", "scsi", NULL};
unit = s[2] - 'a';
hw = unit / MAX_DRIVES;
unit = unit % MAX_DRIVES;
@@ -3178,20 +3180,16 @@
case -8: /* "slow" */
drive->slow = 1;
goto done;
- case -9: /* "swapdata" or "bswap" */
- case -10:
- drive->bswap = 1;
- goto done;
- case -11: /* "flash" */
+ case -9: /* "flash" */
drive->ata_flash = 1;
goto done;
- case -12: /* "remap" */
+ case -10: /* "remap" */
drive->remap_0_to_1 = 1;
goto done;
- case -13: /* "noremap" */
+ case -11: /* "noremap" */
drive->remap_0_to_1 = 2;
goto done;
- case -14: /* "scsi" */
+ case -12: /* "scsi" */
#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI)
drive->scsi = 1;
goto done;
diff -urN linux-2.5.8/drivers/ide/pdc202xx.c linux/drivers/ide/pdc202xx.c
--- linux-2.5.8/drivers/ide/pdc202xx.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/pdc202xx.c Tue Apr 16 05:39:06 2002
@@ -1270,9 +1270,10 @@
#ifdef CONFIG_PDC202XX_32_UNMASK
hwif->drives[0].io_32bit = 1;
hwif->drives[1].io_32bit = 1;
+
hwif->drives[0].unmask = 1;
hwif->drives[1].unmask = 1;
-#endif /* CONFIG_PDC202XX_32_UNMASK */
+#endif

#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->dma_base) {
@@ -1285,9 +1286,9 @@
hwif->drives[1].autotune = 1;
hwif->autodma = 0;
}
-#else /* !CONFIG_BLK_DEV_IDEDMA */
+#else
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+#endif
}
diff -urN linux-2.5.8/drivers/ide/pdc4030.c linux/drivers/ide/pdc4030.c
--- linux-2.5.8/drivers/ide/pdc4030.c Tue Apr 16 06:01:07 2002
+++ linux/drivers/ide/pdc4030.c Tue Apr 16 02:59:10 2002
@@ -183,7 +183,7 @@
"%s: Failed Promise read config!\n",hwif->name);
return 0;
}
- ata_input_data(drive, &ident, SECTOR_WORDS);
+ ata_read(drive, &ident, SECTOR_WORDS);
if (ident.id[1] != 'P' || ident.id[0] != 'T') {
return 0;
}
@@ -332,7 +332,7 @@
nsect = sectors_avail;
sectors_avail -= nsect;
to = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
- ata_input_data(drive, to, nsect * SECTOR_WORDS);
+ ata_read(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,
@@ -460,7 +460,7 @@
* Ok, we're all setup for the interrupt
* re-entering us on the last transfer.
*/
- taskfile_output_data(drive, buffer, nsect<<7);
+ ata_write(drive, buffer, nsect << 7);
bio_kunmap_irq(buffer, &flags);
} while (mcount);

diff -urN linux-2.5.8/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- linux-2.5.8/drivers/scsi/ide-scsi.c Mon Apr 15 08:53:51 2002
+++ linux/drivers/scsi/ide-scsi.c Tue Apr 16 03:39:25 2002
@@ -140,7 +140,7 @@
}
count = min(pc->sg->length - pc->b_count, bcount);
buf = page_address(pc->sg->page) + pc->sg->offset;
- atapi_input_bytes (drive, buf + pc->b_count, count);
+ atapi_read(drive, buf + pc->b_count, count);
bcount -= count; pc->b_count += count;
if (pc->b_count == pc->sg->length) {
pc->sg++;
@@ -162,7 +162,7 @@
}
count = min(pc->sg->length - pc->b_count, bcount);
buf = page_address(pc->sg->page) + pc->sg->offset;
- atapi_output_bytes (drive, buf + pc->b_count, count);
+ atapi_write(drive, buf + pc->b_count, count);
bcount -= count; pc->b_count += count;
if (pc->b_count == pc->sg->length) {
pc->sg++;
@@ -363,7 +363,7 @@
if (pc->sg)
idescsi_input_buffers(drive, pc, temp);
else
- atapi_input_bytes(drive, pc->current_position, temp);
+ atapi_read(drive, pc->current_position, temp);
printk(KERN_ERR "ide-scsi: transferred %d of %d bytes\n", temp, bcount);
}
pc->actually_transferred += temp;
@@ -382,13 +382,13 @@
if (pc->sg)
idescsi_input_buffers (drive, pc, bcount);
else
- atapi_input_bytes (drive,pc->current_position,bcount);
+ atapi_read(drive,pc->current_position,bcount);
} else {
set_bit(PC_WRITING, &pc->flags);
if (pc->sg)
idescsi_output_buffers (drive, pc, bcount);
else
- atapi_output_bytes (drive,pc->current_position,bcount);
+ atapi_write(drive,pc->current_position,bcount);
}
pc->actually_transferred+=bcount; /* Update the current position */
pc->current_position+=bcount;
@@ -414,7 +414,7 @@
return ide_stopped;
}
ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL); /* Set the interrupt routine */
- atapi_output_bytes (drive, scsi->pc->c, 12); /* Send the actual packet */
+ atapi_write(drive, scsi->pc->c, 12); /* Send the actual packet */
return ide_started;
}

diff -urN linux-2.5.8/include/linux/ide.h linux/include/linux/ide.h
--- linux-2.5.8/include/linux/ide.h Tue Apr 16 06:01:07 2002
+++ linux/include/linux/ide.h Tue Apr 16 05:44:28 2002
@@ -313,9 +313,11 @@
#define IDE_CUR_AR(drive) (HWGROUP((drive))->rq->special)

struct ide_settings_s;
-
-typedef struct ide_drive_s {
- struct ata_channel *channel; /* parent pointer to the channel we are attached to */
+/* structure describing an ATA/ATAPI device */
+typedef
+struct ata_device {
+ struct ata_channel * channel;
+ char name[6]; /* device name */

unsigned int usage; /* current "open()" count for drive */
char type; /* distingiush different devices: disk, cdrom, tape, floppy, ... */
@@ -324,11 +326,11 @@
* could move this to the channel and many sync problems would
* magically just go away.
*/
- request_queue_t queue; /* per device request queue */
+ request_queue_t queue; /* per device request queue */

- struct list_head free_req; /* free ata requests */
+ struct list_head free_req; /* free ata requests */

- struct ide_drive_s *next; /* circular list of hwgroup drives */
+ struct ata_device *next; /* circular list of hwgroup drives */

/* Those are directly injected jiffie values. They should go away and
* we should use generic timers instead!!!
@@ -346,8 +348,6 @@
byte retry_pio; /* retrying dma capable host in pio */
byte state; /* retry state */
byte unmask; /* flag: okay to unmask other irqs */
- byte slow; /* flag: slow data port */
- byte bswap; /* flag: byte swap data */
byte dsc_overlap; /* flag: DSC overlap */

unsigned waiting_for_dma: 1; /* dma currently in progress */
@@ -359,7 +359,6 @@
unsigned removable : 1; /* 1 if need to do check_media_change */
unsigned forced_geom : 1; /* 1 if hdx=c,h,s was given at boot */
unsigned no_unmask : 1; /* disallow setting unmask bit */
- unsigned no_io_32bit : 1; /* disallow enabling 32bit I/O */
unsigned nobios : 1; /* flag: do not probe bios for drive */
unsigned revalidate : 1; /* request revalidation */
unsigned atapi_overlap : 1; /* flag: ATAPI overlap (not supported) */
@@ -376,7 +375,6 @@
byte mult_count; /* current multiple sector setting */
byte mult_req; /* requested multiple sector setting */
byte tune_req; /* requested drive tuning setting */
- byte io_32bit; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
byte bad_wstat; /* used for ignoring WRERR_STAT */
byte nowerr; /* used for ignoring WRERR_STAT */
byte sect0; /* offset of first sector for DM6:DDO */
@@ -390,12 +388,18 @@
unsigned long long capacity48; /* total number of sectors */
unsigned int drive_data; /* for use by tuneproc/selectproc as needed */

+ /* FIXME: Those are properties of a channel and not a drive! Move them
+ * later there.
+ */
+ byte slow; /* flag: slow data port */
+ unsigned no_io_32bit : 1; /* disallow enabling 32bit I/O */
+ byte io_32bit; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
+
wait_queue_head_t wqueue; /* used to wait for drive in open() */

struct hd_driveid *id; /* drive model identification info */
struct hd_struct *part; /* drive partition table */

- char name[6]; /* drive name, such as "hda" */
struct ata_operations *driver;

void *driver_data; /* extra driver data */
@@ -447,47 +451,6 @@

typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);

-/*
- * An ide_ideproc_t() performs CPU-polled transfers to/from a drive.
- * Arguments are: the drive, the buffer pointer, and the length (in bytes or
- * words depending on if it's an IDE or ATAPI call).
- *
- * If it is not defined for a controller, standard-code is used from ide.c.
- *
- * Controllers which are not memory-mapped in the standard way need to
- * override that mechanism using this function to work.
- *
- */
-typedef enum { ideproc_ide_input_data, ideproc_ide_output_data,
- ideproc_atapi_input_bytes, ideproc_atapi_output_bytes
-} ide_ide_action_t;
-
-typedef void (ide_ideproc_t)(ide_ide_action_t, ide_drive_t *, void *, unsigned int);
-
-/*
- * An ide_tuneproc_t() is used to set the speed of an IDE interface
- * to a particular PIO mode. The "byte" parameter is used
- * to select the PIO mode by number (0,1,2,3,4,5), and a value of 255
- * indicates that the interface driver should "auto-tune" the PIO mode
- * according to the drive capabilities in drive->id;
- *
- * Not all interface types support tuning, and not all of those
- * support all possible PIO settings. They may silently ignore
- * or round values as they see fit.
- */
-typedef void (ide_tuneproc_t) (ide_drive_t *, byte);
-typedef int (ide_speedproc_t) (ide_drive_t *, byte);
-
-/*
- * This is used to provide support for strange interfaces
- */
-typedef void (ide_selectproc_t) (ide_drive_t *);
-typedef void (ide_resetproc_t) (ide_drive_t *);
-typedef int (ide_quirkproc_t) (ide_drive_t *);
-typedef void (ide_intrproc_t) (ide_drive_t *);
-typedef void (ide_maskproc_t) (ide_drive_t *, int);
-typedef void (ide_rw_proc_t) (ide_drive_t *, ide_dma_action_t);
-
enum {
ATA_PRIMARY = 0,
ATA_SECONDARY = 1
@@ -507,15 +470,40 @@
#endif
ide_drive_t drives[MAX_DRIVES]; /* drive info */
struct gendisk *gd; /* gendisk structure */
- ide_tuneproc_t *tuneproc; /* routine to tune PIO mode for drives */
- ide_speedproc_t *speedproc; /* routine to retune DMA modes for drives */
- ide_selectproc_t *selectproc; /* tweaks hardware to select drive */
- ide_resetproc_t *resetproc; /* routine to reset controller after a disk reset */
- ide_intrproc_t *intrproc; /* special interrupt handling for shared pci interrupts */
- ide_maskproc_t *maskproc; /* special host masking for drive selection */
- ide_quirkproc_t *quirkproc; /* check host's drive quirk list */
- ide_rw_proc_t *rwproc; /* adjust timing based upon rq->cmd direction */
- ide_ideproc_t *ideproc; /* CPU-polled transfer routine */
+
+ /*
+ * Routines to tune PIO and DMA mode for drives.
+ *
+ * A value of 255 indicates that the function should choose the optimal
+ * mode itself.
+ */
+ void (*tuneproc) (ide_drive_t *, byte pio);
+ int (*speedproc) (ide_drive_t *, byte pio);
+
+ /* tweaks hardware to select drive */
+ void (*selectproc) (ide_drive_t *);
+
+ /* routine to reset controller after a disk reset */
+ void (*resetproc) (ide_drive_t *);
+
+ /* special interrupt handling for shared pci interrupts */
+ void (*intrproc) (ide_drive_t *);
+
+ /* special host masking for drive selection */
+ void (*maskproc) (ide_drive_t *, int);
+
+ /* adjust timing based upon rq->cmd direction */
+ void (*rwproc) (ide_drive_t *, ide_dma_action_t);
+
+ /* check host's drive quirk list */
+ int (*quirkproc) (ide_drive_t *);
+
+ /* CPU-polled transfer routines */
+ void (*ata_read)(ide_drive_t *, void *, unsigned int);
+ void (*ata_write)(ide_drive_t *, void *, unsigned int);
+ void (*atapi_read)(ide_drive_t *, void *, unsigned int);
+ void (*atapi_write)(ide_drive_t *, void *, unsigned int);
+
ide_dmaproc_t *dmaproc; /* dma read/write/abort routine */
unsigned long dma_base; /* base addr for dma ports */
unsigned dma_extra; /* extra addr for dma ports */
@@ -829,7 +817,7 @@
*/
struct ata_request {
struct request *ar_rq; /* real request */
- struct ide_drive_s *ar_drive; /* associated drive */
+ struct ata_device *ar_drive; /* associated drive */
unsigned long ar_flags; /* ATA_AR_* flags */
int ar_tag; /* tag number, if any */
struct list_head ar_queue; /* pending list */
@@ -848,12 +836,11 @@

#define AR_TASK_CMD(ar) ((ar)->ar_task.taskfile.command)

-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);
+extern void ata_read(ide_drive_t *drive, void *buffer, unsigned int wcount);
+extern void ata_write(ide_drive_t *drive, void *buffer, unsigned int wcount);
+
+extern void atapi_read(ide_drive_t *drive, void *buffer, unsigned int bytecount);
+extern void atapi_write(ide_drive_t *drive, void *buffer, unsigned int bytecount);

extern ide_startstop_t ata_taskfile(ide_drive_t *drive,
struct ata_taskfile *args, struct request *rq);


Attachments:
ide-clean-36.diff (45.46 kB)

2002-04-16 08:30:32

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

On Tue, Apr 16, 2002 at 09:05:21AM +0200, Martin Dalecki wrote:
> Tue Apr 16 01:02:47 CEST 2002 ide-clean-36
>
> - Consolidate ide_choose_drive() and choose_drive() in to one function.
>
> - Remove sector data byteswpapping support. Byte-swapping the data is supported
> on the file-system level where applicable. Byte-swapped interfaces are
> supported on a lower level anyway. And finally it was used inconsistently.

Are you sure about this? I think file systems support LE/BE, but not
byteswapping because of IDE being LE on a BE system.

> - Eliminate taskfile_input_data() and taskfile_output_data(). This allowed us
> to split up ideproc and eliminate the ugly action switch as well as the
> corresponding defines.
>
> - Remove tons of unnecessary typedefs from ide.h
>
> - Prepate the PIO read write code for soon overhaul.
>
> - Misc small bits here and there :-).
>

--
Vojtech Pavlik
SuSE Labs

2002-04-16 08:35:12

by Martin Dalecki

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

Vojtech Pavlik wrote:
> On Tue, Apr 16, 2002 at 09:05:21AM +0200, Martin Dalecki wrote:
>
>>Tue Apr 16 01:02:47 CEST 2002 ide-clean-36
>>
>>- Consolidate ide_choose_drive() and choose_drive() in to one function.
>>
>>- Remove sector data byteswpapping support. Byte-swapping the data is supported
>> on the file-system level where applicable. Byte-swapped interfaces are
>> supported on a lower level anyway. And finally it was used inconsistently.
>
>
> Are you sure about this? I think file systems support LE/BE, but not
> byteswapping because of IDE being LE on a BE system.

I'm sure about this. For the following reasons:

1. The removed functionality affected only sector data transfers.

2. The following code for interfaces with byte swapped BUS setups
still remains intact:

#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

And indeed as you show - there was confusion about this issue
throughout the whole driver, since the taskfile_in(out)
functions where basically just the byteswapped variants and
where not uses consistently.

2002-04-16 08:43:59

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

On Tue, Apr 16, 2002 at 09:33:00AM +0200, Martin Dalecki wrote:
> Vojtech Pavlik wrote:
> > On Tue, Apr 16, 2002 at 09:05:21AM +0200, Martin Dalecki wrote:
> >
> >>Tue Apr 16 01:02:47 CEST 2002 ide-clean-36
> >>
> >>- Consolidate ide_choose_drive() and choose_drive() in to one function.
> >>
> >>- Remove sector data byteswpapping support. Byte-swapping the data is supported
> >> on the file-system level where applicable. Byte-swapped interfaces are
> >> supported on a lower level anyway. And finally it was used inconsistently.
> >
> >
> > Are you sure about this? I think file systems support LE/BE, but not
> > byteswapping because of IDE being LE on a BE system.
>
> I'm sure about this. For the following reasons:
>
> 1. The removed functionality affected only sector data transfers.
>
> 2. The following code for interfaces with byte swapped BUS setups
> still remains intact:
>
> #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

If this is kept, then OK.

>
> And indeed as you show - there was confusion about this issue
> throughout the whole driver, since the taskfile_in(out)
> functions where basically just the byteswapped variants and
> where not uses consistently.

--
Vojtech Pavlik
SuSE Labs

2002-04-16 09:10:18

by Norbert Kiesel

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

Hi,

while trying to understand recent kernel changes I stumbled over
the following patch to

diff -urN linux-2.5.8/drivers/ide/ide.c linux/drivers/ide/ide.c
--- linux-2.5.8/drivers/ide/ide.c Tue Apr 16 06:01:07 2002
+++ linux/drivers/ide/ide.c Tue Apr 16 05:38:37 2002

...
while (i > 0) {
- u32 buffer[16];
- unsigned int wcount = (i > 16) ? 16 : i;
- i -= wcount;
- ata_input_data (drive, buffer, wcount);
+ u32 buffer[SECTOR_WORDS];
+ unsigned int count = (i > 1) ? 1 : i;
+
+ ata_read(drive, buffer, count * SECTOR_WORDS);
+ i -= count;
}
}
...

While the old code called ata_input_read() with [0:16] as last param,
the new code calls the (renamed) ata_read() with either 0 or 16. Also,
the new code loops "i" times while the old code looped "i/16+1" times.
Was this intended or should the patch better read like:

...
while (i > 0) {
- u32 buffer[16];
- unsigned int wcount = (i > 16) ? 16 : i;
- i -= wcount;
- ata_input_data (drive, buffer, wcount);
+ u32 buffer[SECTOR_WORDS];
+ unsigned int count = max(i, SECTOR_WORDS);
+
+ ata_read(drive, buffer, count);
+ i -= count;
}
}
...

so long
Norbert

2002-04-16 09:21:32

by David Lang

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

The common thing I use byteswap for is to mount my tivo (kernel 2.1.x)
drives on my PC (2.4/5.x). those drives are byteswapped throughout the
entire drive, including the partition table.

It sounds as if you are removing this capability, am I misunderstaning you
or is there some other way to do this? (and duplicating the drive to use
dd to byteswap is not practical for 100G+)

David Lang

On Tue, 16 Apr 2002, Martin Dalecki wrote:

> Vojtech Pavlik wrote:
> > On Tue, Apr 16, 2002 at 09:05:21AM +0200, Martin Dalecki wrote:
> >
> >>Tue Apr 16 01:02:47 CEST 2002 ide-clean-36
> >>
> >>- Consolidate ide_choose_drive() and choose_drive() in to one function.
> >>
> >>- Remove sector data byteswpapping support. Byte-swapping the data is supported
> >> on the file-system level where applicable. Byte-swapped interfaces are
> >> supported on a lower level anyway. And finally it was used inconsistently.
> >
> >
> > Are you sure about this? I think file systems support LE/BE, but not
> > byteswapping because of IDE being LE on a BE system.
>
> I'm sure about this. For the following reasons:
>
> 1. The removed functionality affected only sector data transfers.
>
> 2. The following code for interfaces with byte swapped BUS setups
> still remains intact:
>
> #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
>
> And indeed as you show - there was confusion about this issue
> throughout the whole driver, since the taskfile_in(out)
> functions where basically just the byteswapped variants and
> where not uses consistently.
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>

2002-04-16 09:23:51

by Martin Dalecki

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

Norbert Kiesel wrote:
> Hi,
>
> while trying to understand recent kernel changes I stumbled over
> the following patch to
>
> diff -urN linux-2.5.8/drivers/ide/ide.c linux/drivers/ide/ide.c
> --- linux-2.5.8/drivers/ide/ide.c Tue Apr 16 06:01:07 2002
> +++ linux/drivers/ide/ide.c Tue Apr 16 05:38:37 2002
>
> ...
> while (i > 0) {
> - u32 buffer[16];
> - unsigned int wcount = (i > 16) ? 16 : i;
> - i -= wcount;
> - ata_input_data (drive, buffer, wcount);
> + u32 buffer[SECTOR_WORDS];
> + unsigned int count = (i > 1) ? 1 : i;
> +
> + ata_read(drive, buffer, count * SECTOR_WORDS);
> + i -= count;
> }
> }
> ...
>
> While the old code called ata_input_read() with [0:16] as last param,
> the new code calls the (renamed) ata_read() with either 0 or 16. Also,
> the new code loops "i" times while the old code looped "i/16+1" times.
> Was this intended or should the patch better read like:
>
> ...
> while (i > 0) {
> - u32 buffer[16];
> - unsigned int wcount = (i > 16) ? 16 : i;
> - i -= wcount;
> - ata_input_data (drive, buffer, wcount);
> + u32 buffer[SECTOR_WORDS];
> + unsigned int count = max(i, SECTOR_WORDS);
> +
> + ata_read(drive, buffer, count);
> + i -= count;
> }
> }
> ...
>
> so long

It's fine as it is I think. Please look up at the initialization of i.
I have just divded the SECTROT_WORDS (== 16) factor out
of all the places above ata_read.

2002-04-16 09:45:51

by Martin Dalecki

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

David Lang wrote:
> The common thing I use byteswap for is to mount my tivo (kernel 2.1.x)
> drives on my PC (2.4/5.x). those drives are byteswapped throughout the
> entire drive, including the partition table.
>
> It sounds as if you are removing this capability, am I misunderstaning you
> or is there some other way to do this? (and duplicating the drive to use
> dd to byteswap is not practical for 100G+)


Same problem as with SCSI disks, which are even more commonly moved
between different system types - please look there for a solution.
BTW.> I hardly beleve that your tivo is containing a DOS partition table -
otherwise the partition table will handle it all autmagically.

2002-04-16 10:14:41

by Norbert Kiesel

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

On Tue, 2002-04-16 at 01:21, Martin Dalecki wrote:
> Norbert Kiesel wrote:
> > Hi,
> >
> > while trying to understand recent kernel changes I stumbled over
> > the following patch to
> >
> > diff -urN linux-2.5.8/drivers/ide/ide.c linux/drivers/ide/ide.c
> > --- linux-2.5.8/drivers/ide/ide.c Tue Apr 16 06:01:07 2002
> > +++ linux/drivers/ide/ide.c Tue Apr 16 05:38:37 2002
> >
> > ...
> > while (i > 0) {
> > - u32 buffer[16];
> > - unsigned int wcount = (i > 16) ? 16 : i;
> > - i -= wcount;
> > - ata_input_data (drive, buffer, wcount);
> > + u32 buffer[SECTOR_WORDS];
> > + unsigned int count = (i > 1) ? 1 : i;
> > +
> > + ata_read(drive, buffer, count * SECTOR_WORDS);
> > + i -= count;
> > }
> > }
> > ...
> >
> > While the old code called ata_input_read() with [0:16] as last param,
> > the new code calls the (renamed) ata_read() with either 0 or 16. Also,
> > the new code loops "i" times while the old code looped "i/16+1" times.
> > Was this intended or should the patch better read like:
> >
> > ...
> > while (i > 0) {
> > - u32 buffer[16];
> > - unsigned int wcount = (i > 16) ? 16 : i;
> > - i -= wcount;
> > - ata_input_data (drive, buffer, wcount);
> > + u32 buffer[SECTOR_WORDS];
> > + unsigned int count = max(i, SECTOR_WORDS);
> > +
> > + ata_read(drive, buffer, count);
> > + i -= count;
> > }
> > }
> > ...
> >
> > so long
>
> It's fine as it is I think. Please look up at the initialization of i.
> I have just divded the SECTROT_WORDS (== 16) factor out
> of all the places above ata_read.
>

You are right (assuming SECTOR_WORDS == 16. I was looking it up in
2.4.18 where SECTOR_WORDS is 512/4 == 128). However, the new code looks
overly complicated (at least for me, easily proven by my wrong first
email :-), given that count is now always == 1. Would the following not
be nicer?

int i;

if (drive->type != ATA_DISK)
return;

for (i = min(drive->mult_count, 1); i > 0; i--) {
u32 buffer[SECTOR_WORDS];

ata_read(drive, buffer, SECTOR_WORDS);
}

(This of course assumes that drive->mult_count is always non-negative)

--nk


--
Key fingerprint = 6C58 F18D 4747 3295 F2DB 15C1 3882 4302 F8B4 C11C


Attachments:
signature.asc (232.00 B)
This is a digitally signed message part

2002-04-16 10:22:32

by Martin Dalecki

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

Norbert Kiesel wrote:
> On Tue, 2002-04-16 at 01:21, Martin Dalecki wrote:
>
>>Norbert Kiesel wrote:
>>
>>>Hi,
>>>
>>>while trying to understand recent kernel changes I stumbled over
>>>the following patch to
>>>
>>>diff -urN linux-2.5.8/drivers/ide/ide.c linux/drivers/ide/ide.c
>>>--- linux-2.5.8/drivers/ide/ide.c Tue Apr 16 06:01:07 2002
>>>+++ linux/drivers/ide/ide.c Tue Apr 16 05:38:37 2002
>>>
>>>...
>>> while (i > 0) {
>>>- u32 buffer[16];
>>>- unsigned int wcount = (i > 16) ? 16 : i;
>>>- i -= wcount;
>>>- ata_input_data (drive, buffer, wcount);
>>>+ u32 buffer[SECTOR_WORDS];
>>>+ unsigned int count = (i > 1) ? 1 : i;
>>>+
>>>+ ata_read(drive, buffer, count * SECTOR_WORDS);
>>>+ i -= count;
>>> }
>>> }
>>>...
>>>
>>>While the old code called ata_input_read() with [0:16] as last param,
>>>the new code calls the (renamed) ata_read() with either 0 or 16. Also,
>>>the new code loops "i" times while the old code looped "i/16+1" times.
>>>Was this intended or should the patch better read like:
>>>
>>>...
>>> while (i > 0) {
>>>- u32 buffer[16];
>>>- unsigned int wcount = (i > 16) ? 16 : i;
>>>- i -= wcount;
>>>- ata_input_data (drive, buffer, wcount);
>>>+ u32 buffer[SECTOR_WORDS];
>>>+ unsigned int count = max(i, SECTOR_WORDS);
>>>+
>>>+ ata_read(drive, buffer, count);
>>>+ i -= count;
>>> }
>>> }
>>>...
>>>
>>>so long
>>
>>It's fine as it is I think. Please look up at the initialization of i.
>>I have just divded the SECTROT_WORDS (== 16) factor out
>>of all the places above ata_read.
>>
>
>
> You are right (assuming SECTOR_WORDS == 16. I was looking it up in
> 2.4.18 where SECTOR_WORDS is 512/4 == 128). However, the new code looks
> overly complicated (at least for me, easily proven by my wrong first
> email :-), given that count is now always == 1. Would the following not
> be nicer?
>
> int i;
>
> if (drive->type != ATA_DISK)
> return;
>
> for (i = min(drive->mult_count, 1); i > 0; i--) {
> u32 buffer[SECTOR_WORDS];
>
> ata_read(drive, buffer, SECTOR_WORDS);
> }
>
> (This of course assumes that drive->mult_count is always non-negative)

Yes this looks nicer. Would you mind to test it and drop me
a patch?

2002-04-16 10:24:28

by Martin Dalecki

[permalink] [raw]
Subject: [PATCH] 2.5.8 IDE 37

diff -urN linux-2.5.8/drivers/ide/Config.help linux/drivers/ide/Config.help
--- linux-2.5.8/drivers/ide/Config.help Tue Apr 16 11:58:06 2002
+++ linux/drivers/ide/Config.help Tue Apr 16 09:24:10 2002
@@ -160,7 +160,7 @@
you can then use this emulation together with an appropriate SCSI
device driver. In order to do this, say Y here and to "SCSI support"
and "SCSI generic support", below. You must then provide the kernel
- command line "hdx=scsi" (try "man bootparam" or see the
+ command line "hdx=ide-scsi" (try "man bootparam" or see the
documentation of your boot loader (lilo or loadlin) about how to
pass options to the kernel at boot time) for devices if you want the
native EIDE sub-drivers to skip over the native support, so that
@@ -543,13 +543,13 @@

CONFIG_BLK_DEV_PDC4030
This driver provides support for the secondary IDE interface and
- cache of Promise IDE chipsets, e.g. DC4030 and DC5030. This driver
- is known to incur timeouts/retries during heavy I/O to drives
- attached to the secondary interface. CD-ROM and TAPE devices are
- not supported yet. This driver is enabled at runtime using the
- "ide0=dc4030" kernel boot parameter. See the
- <file:Documentation/ide.txt> and <file:drivers/ide/pdc4030.c> files
- for more info.
+ cache of the original Promise IDE chipsets, e.g. DC4030 and DC5030.
+ It is nothing to do with the later range of Promise UDMA chipsets -
+ see the PDC_202XX support for these. CD-ROM and TAPE devices are not
+ supported (and probably never will be since I don't think the cards
+ support them). This driver is enabled at runtime using the "ide0=dc4030"
+ or "ide1=dc4030" kernel boot parameter. See the
+ <file:drivers/ide/pdc4030.c> file for more info.

CONFIG_BLK_DEV_QD65XX
This driver is enabled at runtime using the "ide0=qd65xx" kernel
@@ -629,6 +629,11 @@
devices (hard disks, CD-ROM drives, etc.) that are connected to the
builtin IDE interface.

+CONFIG_BLK_DEV_Q40IDE
+ Enable the on-board IDE controller in the Q40/Q60. This should
+ normally be on; disable it only if you are running a custom hard
+ drive subsystem through an expansion card.
+
CONFIG_BLK_DEV_IDE_ICSIDE
On Acorn systems, say Y here if you wish to use the ICS IDE
interface card. This is not required for ICS partition support.
diff -urN linux-2.5.8/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c
--- linux-2.5.8/drivers/ide/ide-cd.c Tue Apr 16 11:58:09 2002
+++ linux/drivers/ide/ide-cd.c Tue Apr 16 11:42:44 2002
@@ -337,7 +337,9 @@
int log = 0;
/* FIXME --mdcki */
struct packet_command *pc = (struct packet_command *) rq->special;
- struct packet_command *failed_command = (struct packet_command *) pc->sense;
+ struct packet_command *failed_command = pc->failed_command;
+
+ /* Decode sense data from drive */
struct request_sense *sense = (struct request_sense *) (pc->buffer - rq->cmd[4]);
unsigned char fail_cmd;

@@ -526,10 +528,10 @@
if (sense == NULL)
sense = &info->sense_data;

- memset(pc, 0, sizeof(struct packet_command));
+ memset(pc, 0, sizeof(*pc));
pc->buffer = (void *) sense;
pc->buflen = 18;
- pc->sense = (struct request_sense *) failed_command;
+ pc->failed_command = failed_command;

/* stuff the sense request in front of our current request */
rq = &info->request_sense_request;
@@ -598,6 +600,7 @@
pc->stat = 1;
cdrom_end_request(drive, 1);
*startstop = ide_error (drive, "request sense failure", stat);
+
return 1;
} else if (rq->flags & (REQ_PC | REQ_BLOCK_PC)) {
/* All other functions, except for READ. */
@@ -635,6 +638,10 @@
pc->stat = 1;
cdrom_end_request(drive, 1);

+ /* FIXME: this is the only place where pc->sense get's used.
+ * Think hard about how to get rid of it...
+ */
+
if ((stat & ERR_STAT) != 0)
cdrom_queue_request_sense(drive, wait, pc->sense, pc);
} else if (rq->flags & REQ_CMD) {
@@ -728,27 +735,26 @@
return startstop;

if (info->dma) {
- if (info->cmd == READ) {
+ if (info->cmd == READ)
info->dma = !drive->channel->dmaproc(ide_dma_read, drive);
- } else if (info->cmd == WRITE) {
+ else if (info->cmd == WRITE)
info->dma = !drive->channel->dmaproc(ide_dma_write, drive);
- } else {
+ 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(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);
+ 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) drive->channel->dmaproc(ide_dma_begin, drive);
+ drive->channel->dmaproc(ide_dma_begin, drive);

if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
BUG_ON(HWGROUP(drive)->handler);
@@ -1386,17 +1392,13 @@
}

static
-int cdrom_queue_packet_command(ide_drive_t *drive, unsigned char *cmd, struct packet_command *pc)
+int cdrom_queue_packet_command(ide_drive_t *drive, unsigned char *cmd,
+ struct request_sense *sense, struct packet_command *pc)
{
- struct request_sense sense;
struct request rq;
int retries = 10;

memcpy(rq.cmd, cmd, CDROM_PACKET_SIZE);
-
- if (pc->sense == NULL)
- pc->sense = &sense;
-
/* Start of retry loop. */
do {
ide_init_drive_cmd(&rq);
@@ -1408,18 +1410,25 @@
if (ide_do_drive_cmd(drive, &rq, ide_wait)) {
printk("%s: do_drive_cmd returned stat=%02x,err=%02x\n",
drive->name, rq.buffer[0], rq.buffer[1]);
+
/* FIXME: we should probably abort/retry or something */
+ if (sense) {
+
+ /* Decode the error here at least for error
+ * reporting to upper layers.!
+ */
+
+ }
}
if (pc->stat != 0) {
/* The request failed. Retry if it was due to a unit
attention status
(usually means media was changed). */
- struct request_sense *reqbuf = pc->sense;

- if (reqbuf->sense_key == UNIT_ATTENTION)
+ if (sense && sense->sense_key == UNIT_ATTENTION)
cdrom_saw_media_change (drive);
- else if (reqbuf->sense_key == NOT_READY &&
- reqbuf->asc == 4 && reqbuf->ascq != 4) {
+ else if (sense && sense->sense_key == NOT_READY &&
+ sense->asc == 4 && sense->ascq != 4) {
/* The drive is in the process of loading
a disk. Retry, but wait a little to give
the drive time to complete the load. */
@@ -1753,7 +1762,7 @@
cmd[7] = cdi->sanyo_slot % 3;
#endif

- return cdrom_queue_packet_command(drive, cmd, &pc);
+ return cdrom_queue_packet_command(drive, cmd, sense, &pc);
}


@@ -1774,7 +1783,7 @@
pc.sense = sense;
cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
cmd[4] = lockflag ? 1 : 0;
- stat = cdrom_queue_packet_command(drive, cmd, &pc);
+ stat = cdrom_queue_packet_command(drive, cmd, sense, &pc);
}

/* If we got an illegal field error, the drive
@@ -1819,7 +1828,7 @@

cmd[0] = GPCMD_START_STOP_UNIT;
cmd[4] = 0x02 + (ejectflag != 0);
- return cdrom_queue_packet_command(drive, cmd, &pc);
+ return cdrom_queue_packet_command(drive, cmd, sense, &pc);
}

static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
@@ -1840,7 +1849,7 @@
cmd[0] = GPCMD_READ_CDVD_CAPACITY;
pc.buffer = (char *)&capbuf;
pc.buflen = sizeof(capbuf);
- stat = cdrom_queue_packet_command(drive, cmd, &pc);
+ stat = cdrom_queue_packet_command(drive, cmd, sense, &pc);
if (stat == 0)
*capacity = 1 + be32_to_cpu(capbuf.lba);

@@ -1869,7 +1878,7 @@
cmd[8] = (buflen & 0xff);
cmd[9] = (format << 6);

- return cdrom_queue_packet_command(drive, cmd, &pc);
+ return cdrom_queue_packet_command(drive, cmd, sense, &pc);
}


@@ -2046,7 +2055,7 @@
cmd[7] = (buflen >> 8);
cmd[8] = (buflen & 0xff);

- return cdrom_queue_packet_command(drive, cmd, &pc);
+ return cdrom_queue_packet_command(drive, cmd, sense, &pc);
}

/* ATAPI cdrom drives are free to select the speed you request or any slower
@@ -2078,7 +2087,7 @@
cmd[5] = speed & 0xff;
}

- return cdrom_queue_packet_command(drive, cmd, &pc);
+ return cdrom_queue_packet_command(drive, cmd, sense, &pc);
}

static int cdrom_play_audio(ide_drive_t *drive, int lba_start, int lba_end)
@@ -2094,7 +2103,7 @@
lba_to_msf(lba_start, &cmd[3], &cmd[4], &cmd[5]);
lba_to_msf(lba_end-1, &cmd[6], &cmd[7], &cmd[8]);

- return cdrom_queue_packet_command(drive, cmd, &pc);
+ return cdrom_queue_packet_command(drive, cmd, &sense, &pc);
}

static int cdrom_get_toc_entry(ide_drive_t *drive, int track,
@@ -2143,7 +2152,7 @@
pc.quiet = cgc->quiet;
pc.timeout = cgc->timeout;
pc.sense = cgc->sense;
- cgc->stat = cdrom_queue_packet_command(drive, cgc->cmd, &pc);
+ cgc->stat = cdrom_queue_packet_command(drive, cgc->cmd, cgc->sense, &pc);
if (!cgc->stat)
cgc->buflen -= pc.buflen;

diff -urN linux-2.5.8/drivers/ide/ide-cd.h linux/drivers/ide/ide-cd.h
--- linux-2.5.8/drivers/ide/ide-cd.h Tue Apr 16 11:58:02 2002
+++ linux/drivers/ide/ide-cd.h Tue Apr 16 11:36:58 2002
@@ -104,6 +104,15 @@
int quiet;
int timeout;
struct request_sense *sense;
+
+ /* This is currently used to pass failed commands through the request
+ * queue. Is this for asynchronos error reporting?
+ *
+ * Can we always be sure that this didn't valish from stack beneath us
+ * - we can't!
+ */
+
+ struct packet_command *failed_command;
};

/* Structure of a MSF cdrom address. */
diff -urN linux-2.5.8/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c
--- linux-2.5.8/drivers/ide/ide-dma.c Tue Apr 16 11:58:06 2002
+++ linux/drivers/ide/ide-dma.c Tue Apr 16 06:35:57 2002
@@ -372,10 +372,10 @@
}

/* Teardown mappings after DMA has completed. */
-void ide_destroy_dmatable (ide_drive_t *drive)
+void ide_destroy_dmatable(struct ata_device *d)
{
- struct pci_dev *dev = drive->channel->pci_dev;
- struct ata_request *ar = IDE_CUR_AR(drive);
+ struct pci_dev *dev = d->channel->pci_dev;
+ struct ata_request *ar = IDE_CUR_AR(d);

pci_unmap_sg(dev, ar->ar_sg_table, ar->ar_sg_nents, ar->ar_sg_ddir);
}
diff -urN linux-2.5.8/drivers/ide/ide-floppy.c linux/drivers/ide/ide-floppy.c
--- linux-2.5.8/drivers/ide/ide-floppy.c Tue Apr 16 11:58:09 2002
+++ linux/drivers/ide/ide-floppy.c Tue Apr 16 09:24:10 2002
@@ -1,8 +1,8 @@
/*
- * linux/drivers/ide/ide-floppy.c Version 0.97.sv Jan 14 2001
+ * linux/drivers/ide/ide-floppy.c Version 0.99 Feb 24 2002
*
* Copyright (C) 1996 - 1999 Gadi Oxman <[email protected]>
- * Copyright (C) 2000 - 2001 Paul Bristow <[email protected]>
+ * Copyright (C) 2000 - 2002 Paul Bristow <[email protected]>
*/

/*
@@ -13,7 +13,7 @@
*
* This driver supports the following IDE floppy drives:
*
- * LS-120 SuperDisk
+ * LS-120/240 SuperDisk
* Iomega Zip 100/250
* Iomega PC Card Clik!/PocketZip
*
@@ -76,9 +76,11 @@
* 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.
+ * Ver 0.99 Feb 24 02 Remove duplicate code, modify clik! detection code
+ * to support new PocketZip drives
*/

-#define IDEFLOPPY_VERSION "0.98a"
+#define IDEFLOPPY_VERSION "0.99"

#include <linux/config.h>
#include <linux/module.h>
@@ -1070,8 +1072,8 @@
*/
BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive,
- &idefloppy_pc_intr, /* service routine for packet command */
- floppy->ticks, /* wait this long before "failing" */
+ &idefloppy_pc_intr, /* service routine for packet command */
+ floppy->ticks, /* wait this long before "failing" */
&idefloppy_transfer_pc2); /* fail == transfer_pc2 */

return ide_started;
@@ -2005,7 +2007,7 @@
* above fix. It makes nasty clicking noises without
* it, so please don't remove this.
*/
- if (strcmp(drive->id->model, "IOMEGA Clik! 40 CZ ATAPI") == 0) {
+ if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) {
blk_queue_max_sectors(&drive->queue, 64);
set_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags);
}
diff -urN linux-2.5.8/drivers/ide/ide-m8xx.c linux/drivers/ide/ide-m8xx.c
--- linux-2.5.8/drivers/ide/ide-m8xx.c Mon Mar 18 21:37:14 2002
+++ linux/drivers/ide/ide-m8xx.c Tue Apr 16 09:24:10 2002
@@ -1,8 +1,14 @@
/*
- *
- *
* linux/drivers/ide/ide-m8xx.c
*
+ * Copyright (C) 2000, 2001 Wolfgang Denk, [email protected]
+ * Modified for direct IDE interface
+ * by Thomas Lange, [email protected]
+ * Modified for direct IDE interface on 8xx without using the PCMCIA
+ * controller
+ * by [email protected]
+ * Moved out of arch/ppc/kernel/m8xx_setup.c, other minor cleanups
+ * by Mathew Locke <[email protected]>
*/

#include <linux/config.h>
diff -urN linux-2.5.8/drivers/ide/ide-taskfile.c linux/drivers/ide/ide-taskfile.c
--- linux-2.5.8/drivers/ide/ide-taskfile.c Tue Apr 16 11:58:09 2002
+++ linux/drivers/ide/ide-taskfile.c Tue Apr 16 11:49:42 2002
@@ -34,7 +34,7 @@
#define DEBUG_TASKFILE 0 /* unset when fixed */

#if DEBUG_TASKFILE
-#define DTF(x...) printk(x)
+#define DTF(x...) printk(##x)
#else
#define DTF(x...)
#endif
@@ -901,20 +901,25 @@
int ide_raw_taskfile(ide_drive_t *drive, struct ata_taskfile *args, byte *buf)
{
struct request rq;
- struct ata_request ar;
+ struct ata_request star;
+
+ ata_ar_init(drive, &star);
+
+ /* Don't put this request on free_req list after usage.
+ */
+ star.ar_flags |= ATA_AR_STATIC;

- ata_ar_init(drive, &ar);
init_taskfile_request(&rq);
rq.buffer = buf;

- memcpy(&ar.ar_task, args, sizeof(*args));
+ memcpy(&star.ar_task, args, sizeof(*args));

if (args->command_type != IDE_DRIVE_TASK_NO_DATA)
rq.current_nr_sectors = rq.nr_sectors
= (args->hobfile.sector_count << 8)
| args->taskfile.sector_count;

- rq.special = &ar;
+ rq.special = &star;

return ide_do_drive_cmd(drive, &rq, ide_wait);
}
diff -urN linux-2.5.8/drivers/ide/ide.c linux/drivers/ide/ide.c
--- linux-2.5.8/drivers/ide/ide.c Tue Apr 16 11:58:09 2002
+++ linux/drivers/ide/ide.c Tue Apr 16 10:35:40 2002
@@ -1729,20 +1729,23 @@
* handle the unexpected interrupt
*/
do {
- if (hwif->irq == irq) {
- stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
- if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
- /* Try to not flood the console with msgs */
- static unsigned long last_msgtime, count;
- ++count;
- if (0 < (signed long)(jiffies - (last_msgtime + HZ))) {
- last_msgtime = jiffies;
- printk("%s%s: unexpected interrupt, status=0x%02x, count=%ld\n",
- hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat, count);
- }
+ if (hwif->irq != irq)
+ continue;
+
+ stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
+ if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
+ /* Try to not flood the console with msgs */
+ static unsigned long last_msgtime;
+ static int count;
+ ++count;
+ if (time_after(jiffies, last_msgtime + HZ)) {
+ last_msgtime = jiffies;
+ printk("%s%s: unexpected interrupt, status=0x%02x, count=%d\n",
+ hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat, count);
}
}
- } while ((hwif = hwif->next) != hwgroup->hwif);
+ hwif = hwif->next;
+ } while (hwif != hwgroup->hwif);
}

/*
@@ -1764,7 +1767,8 @@
goto out_lock;

if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) {
- printk("ide: unexpected interrupt\n");
+ printk(KERN_INFO "ide: unexpected interrupt %d %d\n", hwif->unit, irq);
+
/*
* Not expecting an interrupt from this drive.
* That means this could be:
diff -urN linux-2.5.8/drivers/ide/it8172.c linux/drivers/ide/it8172.c
--- linux-2.5.8/drivers/ide/it8172.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/it8172.c Tue Apr 16 09:24:10 2002
@@ -50,7 +50,7 @@
#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING)
static byte it8172_dma_2_pio (byte xfer_rate);
static int it8172_tune_chipset (ide_drive_t *drive, byte speed);
-static int it8172_config_drive_for_dma (ide_drive_t *drive);
+static int it8172_config_chipset_for_dma (ide_drive_t *drive);
static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
#endif
void __init ide_init_it8172(struct ata_channel *channel);
@@ -59,16 +59,14 @@
static void it8172_tune_drive (ide_drive_t *drive, byte pio)
{
unsigned long flags;
- u16 master_data;
- u32 slave_data;
+ u16 drive_enables;
+ u32 drive_timing;
int is_slave = (&drive->channel->drives[1] == drive);
- int master_port = 0x40;
- int slave_port = 0x44;
-
- if (pio == 255)
- pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0;
- else
- pio = min_t(byte, pio, 4);
+
+ if (pio == 255)
+ pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0;
+ else
+ pio = min_t(byte, pio, 4);

pci_read_config_word(drive->channel->pci_dev, master_port, &master_data);
pci_read_config_dword(drive->channel->pci_dev, slave_port, &slave_data);
@@ -77,19 +75,27 @@
* FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
* are being left at the default values of 8 PCI clocks (242 nsec
* for a 33 MHz clock). These can be safely shortened at higher
- * PIO modes.
+ * PIO modes. The DIOR/DIOW pulse width and recovery times only
+ * apply to PIO modes, not to the DMA modes.
*/

+ /*
+ * Enable port 0x44. The IT8172G spec is confused; it calls
+ * this register the "Slave IDE Timing Register", but in fact,
+ * it controls timing for both master and slave drives.
+ */
+ drive_enables |= 0x4000;
+
if (is_slave) {
- master_data |= 0x4000;
+ drive_enables &= 0xc006;
if (pio > 1)
- /* enable PPE and IE */
- master_data |= 0x0060;
+ /* enable prefetch and IORDY sample-point */
+ drive_enables |= 0x0060;
} else {
- master_data &= 0xc060;
+ drive_enables &= 0xc060;
if (pio > 1)
- /* enable PPE and IE */
- master_data |= 0x0006;
+ /* enable prefetch and IORDY sample-point */
+ drive_enables |= 0x0006;
}

save_flags(flags);
@@ -163,6 +169,7 @@
case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break;
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
+ case XFER_MW_DMA_0:
case XFER_SW_DMA_2: break;
default: return -1;
}
@@ -185,7 +192,7 @@
return err;
}

-static int it8172_config_drive_for_dma(ide_drive_t *drive)
+static int it8172_config_chipset_for_dma(ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
byte speed;
@@ -205,7 +212,7 @@
{
switch (func) {
case ide_dma_check:
- return ide_dmaproc((ide_dma_action_t)it8172_config_drive_for_dma(drive),
+ return ide_dmaproc((ide_dma_action_t)it8172_config_chipset_for_dma(drive),
drive);
default :
break;
diff -urN linux-2.5.8/drivers/ide/pdc4030.c linux/drivers/ide/pdc4030.c
--- linux-2.5.8/drivers/ide/pdc4030.c Tue Apr 16 11:58:09 2002
+++ linux/drivers/ide/pdc4030.c Tue Apr 16 09:24:54 2002
@@ -1,7 +1,7 @@
/* -*- linux-c -*-
- * linux/drivers/ide/pdc4030.c Version 0.90 May 27, 1999
+ * linux/drivers/ide/pdc4030.c Version 0.92 Jan 15, 2002
*
- * Copyright (C) 1995-1999 Linus Torvalds & authors (see below)
+ * Copyright (C) 1995-2002 Linus Torvalds & authors (see below)
*/

/*
@@ -37,6 +37,8 @@
* Autodetection code added.
*
* Version 0.90 Transition to BETA code. No lost/unexpected interrupts
+ * Version 0.91 Bring in line with new bio code in 2.5.1
+ * Version 0.92 Update for IDE driver taskfile changes
*/

/*
@@ -72,8 +74,8 @@
* effects.
*/

-#define DEBUG_READ
-#define DEBUG_WRITE
+#undef DEBUG_READ
+#undef DEBUG_WRITE

#include <linux/types.h>
#include <linux/kernel.h>
@@ -91,6 +93,10 @@

#include "pdc4030.h"

+#if SUPPORT_VLB_SYNC != 1
+#error This driver will not work unless SUPPORT_VLB_SYNC is 1
+#endif
+
/*
* promise_selectproc() is invoked by ide.c
* in preparation for access to the specified drive.
@@ -229,12 +235,12 @@
hwif->selectproc = hwif2->selectproc = &promise_selectproc;
hwif->serialized = hwif2->serialized = 1;

-/* Shift the remaining interfaces down by one */
+/* Shift the remaining interfaces up by one */
for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) {
struct ata_channel *h = &ide_hwifs[i];

#ifdef DEBUG
- printk(KERN_DEBUG "Shifting i/f %d values to i/f %d\n",i-1,i);
+ printk(KERN_DEBUG "pdc4030: Shifting i/f %d values to i/f %d\n",i-1,i);
#endif
ide_init_hwif_ports(&h->hw, (h-1)->io_ports[IDE_DATA_OFFSET], 0, NULL);
memcpy(h->io_ports, h->hw.io_ports, sizeof(h->io_ports));
@@ -652,8 +658,8 @@
are distinguished by writing the drive number (0-3) to the
Feature register.
FIXME: Is promise_selectproc now redundant??
- */
- taskfile.feature = (drive->channel->unit << 1) + drive->select.b.unit;
+ */
+ taskfile.feature = (drive->channel->unit << 1) + drive->select.b.unit;
taskfile.sector_count = rq->nr_sectors;
taskfile.sector_number = block;
taskfile.low_cylinder = (block>>=8);
diff -urN linux-2.5.8/include/linux/ide.h linux/include/linux/ide.h
--- linux-2.5.8/include/linux/ide.h Tue Apr 16 11:58:09 2002
+++ linux/include/linux/ide.h Tue Apr 16 11:18:42 2002
@@ -975,6 +975,7 @@
#define ATA_AR_QUEUED 1
#define ATA_AR_SETUP 2
#define ATA_AR_RETURN 4
+#define ATA_AR_STATIC 8

/*
* if turn-around time is longer than this, halve queue depth
@@ -1015,7 +1016,8 @@

static inline void ata_ar_put(ide_drive_t *drive, struct ata_request *ar)
{
- list_add(&ar->ar_queue, &drive->free_req);
+ if (!(ar->ar_flags & ATA_AR_STATIC))
+ list_add(&ar->ar_queue, &drive->free_req);

if (ar->ar_flags & ATA_AR_QUEUED) {
/* clear the tag */


Attachments:
ide-clean-37.diff (21.28 kB)

2002-04-16 10:27:53

by Norbert Kiesel

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

I can for sure provide a patch, testing will take a bit longer because I
currently only use 2.4.x. Give me 24h...

--nk

On Tue, 2002-04-16 at 02:20, Martin Dalecki wrote:
> Norbert Kiesel wrote:
> > On Tue, 2002-04-16 at 01:21, Martin Dalecki wrote:
> >
> >>Norbert Kiesel wrote:
> >>
> >>>Hi,
> >>>
> >>>while trying to understand recent kernel changes I stumbled over
> >>>the following patch to
> >>>
> >>>diff -urN linux-2.5.8/drivers/ide/ide.c linux/drivers/ide/ide.c
> >>>--- linux-2.5.8/drivers/ide/ide.c Tue Apr 16 06:01:07 2002
> >>>+++ linux/drivers/ide/ide.c Tue Apr 16 05:38:37 2002
> >>>
> >>>...
> >>> while (i > 0) {
> >>>- u32 buffer[16];
> >>>- unsigned int wcount = (i > 16) ? 16 : i;
> >>>- i -= wcount;
> >>>- ata_input_data (drive, buffer, wcount);
> >>>+ u32 buffer[SECTOR_WORDS];
> >>>+ unsigned int count = (i > 1) ? 1 : i;
> >>>+
> >>>+ ata_read(drive, buffer, count * SECTOR_WORDS);
> >>>+ i -= count;
> >>> }
> >>> }
> >>>...
> >>>
> >>>While the old code called ata_input_read() with [0:16] as last param,
> >>>the new code calls the (renamed) ata_read() with either 0 or 16. Also,
> >>>the new code loops "i" times while the old code looped "i/16+1" times.
> >>>Was this intended or should the patch better read like:
> >>>
> >>>...
> >>> while (i > 0) {
> >>>- u32 buffer[16];
> >>>- unsigned int wcount = (i > 16) ? 16 : i;
> >>>- i -= wcount;
> >>>- ata_input_data (drive, buffer, wcount);
> >>>+ u32 buffer[SECTOR_WORDS];
> >>>+ unsigned int count = max(i, SECTOR_WORDS);
> >>>+
> >>>+ ata_read(drive, buffer, count);
> >>>+ i -= count;
> >>> }
> >>> }
> >>>...
> >>>
> >>>so long
> >>
> >>It's fine as it is I think. Please look up at the initialization of i.
> >>I have just divded the SECTROT_WORDS (== 16) factor out
> >>of all the places above ata_read.
> >>
> >
> >
> > You are right (assuming SECTOR_WORDS == 16. I was looking it up in
> > 2.4.18 where SECTOR_WORDS is 512/4 == 128). However, the new code looks
> > overly complicated (at least for me, easily proven by my wrong first
> > email :-), given that count is now always == 1. Would the following not
> > be nicer?
> >
> > int i;
> >
> > if (drive->type != ATA_DISK)
> > return;
> >
> > for (i = min(drive->mult_count, 1); i > 0; i--) {
> > u32 buffer[SECTOR_WORDS];
> >
> > ata_read(drive, buffer, SECTOR_WORDS);
> > }
> >
> > (This of course assumes that drive->mult_count is always non-negative)
>
> Yes this looks nicer. Would you mind to test it and drop me
> a patch?
>
--
Key fingerprint = 6C58 F18D 4747 3295 F2DB 15C1 3882 4302 F8B4 C11C


Attachments:
signature.asc (232.00 B)
This is a digitally signed message part

2002-04-16 14:14:32

by Richard Gooch

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

Martin Dalecki writes:
> David Lang wrote:
> > The common thing I use byteswap for is to mount my tivo (kernel 2.1.x)
> > drives on my PC (2.4/5.x). those drives are byteswapped throughout the
> > entire drive, including the partition table.
> >
> > It sounds as if you are removing this capability, am I misunderstaning you
> > or is there some other way to do this? (and duplicating the drive to use
> > dd to byteswap is not practical for 100G+)
>
> Same problem as with SCSI disks, which are even more commonly moved
> between different system types - please look there for a solution.
> BTW. I hardly beleve that your tivo is containing a DOS partition
> table - otherwise the partition table will handle it all
> autmagically.

Well, there *is* a partition table on the drive, but the byte-swapping
isn't handled automatically. Otherwise people wouldn't need to bswap
their TiVo drives when plugging into an x86 box.

Having the bswap option is definately useful. With it, you can "bless"
the drive and then mount the partitions and poke around. Please don't
remove the bswap option. You'll make life harder for a bunch of
people.

This gratuitous removal of features in the guise of "cleanups" is why
you got flamed earlier this year. I thought you'd learned :-/

Regards,

Richard....
Permanent: [email protected]
Current: [email protected]

2002-04-16 14:52:29

by Martin Dalecki

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

Richard Gooch wrote:
> Martin Dalecki writes:
>
>>David Lang wrote:
>>
>>>The common thing I use byteswap for is to mount my tivo (kernel 2.1.x)
>>>drives on my PC (2.4/5.x). those drives are byteswapped throughout the
>>>entire drive, including the partition table.
>>>
>>>It sounds as if you are removing this capability, am I misunderstaning you
>>>or is there some other way to do this? (and duplicating the drive to use
>>>dd to byteswap is not practical for 100G+)
>>
>>Same problem as with SCSI disks, which are even more commonly moved
>>between different system types - please look there for a solution.
>>BTW. I hardly beleve that your tivo is containing a DOS partition
>>table - otherwise the partition table will handle it all
>>autmagically.
>
>
> Well, there *is* a partition table on the drive, but the byte-swapping
> isn't handled automatically. Otherwise people wouldn't need to bswap
> their TiVo drives when plugging into an x86 box.
>
> Having the bswap option is definately useful. With it, you can "bless"
> the drive and then mount the partitions and poke around. Please don't
> remove the bswap option. You'll make life harder for a bunch of
> people.

Please note one sample from ext2 code:

if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV)

And from partition handling code linux/fs/partitions/sun.c:

/* All Sun disks have 8 partition entries */
spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect);

You see those many le32_to_cpu() and reverse commands?
If there is something that has to be fixed for linux/fs/partition/whatever.c -
please fix it there if you are actually *needing* it.

You also notice that the option was used only by the
taskfile_(in|out)put_bytes() function, which in turn was only used for
taks_in_intr, which in turn only matters for PIO mode but did NOTHING to DMA
transfers for example? DMA transfers are those days the >> 90% most common
on disks in PC systems. And you notice that the IDE driver sometimes starts in
DMA and falls backs to DMA if it has for example to fill in a not full memmory
page?

And you notice that the SCSI people are more likely to exchange disks
regularly between some RISC big endian host and linux on intel?
Please ask yourself why they don't have someting like the byteswap option.

Do you remember that byteswap was something introduced by the Atari people
a long long time ago even before the fs code started to understand
about native endianess issues and is today both: broken (it *may* work
for someone but it *is* broken) unneccessary and not the proper
way to deal with the problems in question?

You notice as well that the arch specific bytswapping for physically
cross wired ata host chips on some historical archs is still there
where it should be?

You don't? So please flame me now as much as you desire...

2002-04-16 15:25:27

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

On Tue, Apr 16, 2002 at 03:49:57PM +0200, Martin Dalecki wrote:
> Richard Gooch wrote:
> > Martin Dalecki writes:
> >
> >>David Lang wrote:
> >>
> >>>The common thing I use byteswap for is to mount my tivo (kernel 2.1.x)
> >>>drives on my PC (2.4/5.x). those drives are byteswapped throughout the
> >>>entire drive, including the partition table.
> >>>
> >>>It sounds as if you are removing this capability, am I misunderstaning you
> >>>or is there some other way to do this? (and duplicating the drive to use
> >>>dd to byteswap is not practical for 100G+)
> >>
> >>Same problem as with SCSI disks, which are even more commonly moved
> >>between different system types - please look there for a solution.
> >>BTW. I hardly beleve that your tivo is containing a DOS partition
> >>table - otherwise the partition table will handle it all
> >>autmagically.
> >
> >
> > Well, there *is* a partition table on the drive, but the byte-swapping
> > isn't handled automatically. Otherwise people wouldn't need to bswap
> > their TiVo drives when plugging into an x86 box.
> >
> > Having the bswap option is definately useful. With it, you can "bless"
> > the drive and then mount the partitions and poke around. Please don't
> > remove the bswap option. You'll make life harder for a bunch of
> > people.
>
> Please note one sample from ext2 code:
>
> if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV)
>
> And from partition handling code linux/fs/partitions/sun.c:
>
> /* All Sun disks have 8 partition entries */
> spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect);
>
> You see those many le32_to_cpu() and reverse commands?
> If there is something that has to be fixed for linux/fs/partition/whatever.c -
> please fix it there if you are actually *needing* it.

Note that the above commands are no help in case of plugging TIVO
drive into a PC. While they assure that all ext2 filesystems are LE on
the media and all sun disklabels are BE on the media, still if you plug
in a BE ext2 into the system (or a BE PC partition table), the kernel
won't understand them.

> You also notice that the option was used only by the
> taskfile_(in|out)put_bytes() function, which in turn was only used for
> taks_in_intr, which in turn only matters for PIO mode but did NOTHING to DMA
> transfers for example? DMA transfers are those days the >> 90% most common
> on disks in PC systems. And you notice that the IDE driver sometimes starts in
> DMA and falls backs to DMA if it has for example to fill in a not full memmory
> page?

I think you wanted to say 'falls back to PIO'. Oh, OK. But still I can
disable DMA and access the damn TIVO drive data.

> And you notice that the SCSI people are more likely to exchange disks
> regularly between some RISC big endian host and linux on intel?
> Please ask yourself why they don't have someting like the byteswap option.

Because for Linux filesystems it was decided some time ago (after people
HAD huge byteswap problems) that ext2 is always LE, etc, etc. So
filesystems are supposed to be the same on every system.

But IDE is used in some pretty weird hardware configurations, where you
actually get one more byteswap on IDE, even when Linux takes care of the
system itself being LE/BE. And furthermore, IDE is now used in stuff
like TIVO or X-Box, where you can't really control what's on the drive,
and thus you can't rely on that it'll be in a format you decided is the
'right' one.

> Do you remember that byteswap was something introduced by the Atari people
> a long long time ago even before the fs code started to understand
> about native endianess issues and is today both: broken (it *may* work
> for someone but it *is* broken) unneccessary and not the proper
> way to deal with the problems in question?

It may be it's broken now. But IMO it should be fixed instead of
removed. Limited to PIO perhaps (if you set bswap on a drive, then it
the driver won't allow DMA on it), but still it's a feature that's
useful now and then.

> You notice as well that the arch specific bytswapping for physically
> cross wired ata host chips on some historical archs is still there
> where it should be?
>
> You don't? So please flame me now as much as you desire...

--
Vojtech Pavlik
SuSE Labs

2002-04-16 15:33:29

by Linus Torvalds

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36


On Tue, 16 Apr 2002, David Lang wrote:
>
> It sounds as if you are removing this capability, am I misunderstaning you
> or is there some other way to do this? (and duplicating the drive to use
> dd to byteswap is not practical for 100G+)

Doing it with a loopback like interface at a higher level is the much
saner operation - I understand why Martin removed the byteswap support,
and agree with it 100%. It just didn't make any sense from a driver
standpoint.

In fact, the byteswapping was actively incorrect, in that it swapped data
in-place - which means that it corrupts the data area while IO is in
progress. It also only works for PIO.

The only reason byteswapping exists is a rather historical one: Linux did
the wrong thing for "insw/outsw" on big-endian architectures at one point
(it byteswapped the data).

(Oh, and coupled with the fact that the IDE ID string is in a "big-endian"
word order, which may have been one more reason to add a "do byteswapped
IO" thing).

Linus

2002-04-16 15:48:45

by Alan

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

> Doing it with a loopback like interface at a higher level is the much
> saner operation - I understand why Martin removed the byteswap support,
> and agree with it 100%. It just didn't make any sense from a driver
> standpoint.

We need to support partitioning on loopback devices in that case.

> The only reason byteswapping exists is a rather historical one: Linux did
> the wrong thing for "insw/outsw" on big-endian architectures at one point
> (it byteswapped the data).

A small number of other setups people wired the IDE the quick and easy
way and their native format is indeed ass backwards - some M68K disks and
the Tivo are examples of that. Interworking requires byteswapping and the
ability to handle byteswapped partition tables.

Given the ability to see partitions on loop devices all works out I think

Alan

2002-04-16 15:47:49

by Linus Torvalds

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36


On Tue, 16 Apr 2002, Richard Gooch wrote:
>
> This gratuitous removal of features in the guise of "cleanups" is why
> you got flamed earlier this year. I thought you'd learned :-/

Richard, have you looked at the IDE mess? That "feature" is a bug, the way
it was implemented - and considering that it's implementable at a
different level much more cleanly for the (few) people who actually need
it...

Also note that performance is likely to _increase_ by removing that stupid
feature - using DMA to do the actual IO and them byteswapping in some
higher level than the driver is likely to be a _lot_ faster than doing PIO
(and byteswap in-place, resulting in random mmap corruption).

Do you realize that because the current bswap writeback reverses the bytes
in place, you can actually seriously corrupt your filesystem by just being
unlucky in timing (ie a bswap on a dirty metadata block at the same time
another process accesses it)?

It's a BUG guys, not a feature.

Linus

2002-04-16 15:50:31

by Linus Torvalds

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36


On Tue, 16 Apr 2002, Vojtech Pavlik wrote:
>
> Note that the above commands are no help in case of plugging TIVO
> drive into a PC. While they assure that all ext2 filesystems are LE on
> the media and all sun disklabels are BE on the media, still if you plug
> in a BE ext2 into the system (or a BE PC partition table), the kernel
> won't understand them.

Please use a the network block device, and teach the ndb deamon to just
byteswap each word.

Problem solved, WITHOUT keeping bugs in the IDE driver.

Oh, and performance improved at the same time.

What are you guys thinging about? There are two rules here:
- optimize for the common case
- keep the code clean.

Both of them say that Martin is 100% right.

Linus

2002-04-16 15:58:56

by Richard Gooch

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

Linus Torvalds writes:
>
> On Tue, 16 Apr 2002, Richard Gooch wrote:
> >
> > This gratuitous removal of features in the guise of "cleanups" is why
> > you got flamed earlier this year. I thought you'd learned :-/
>
> Richard, have you looked at the IDE mess?

Yeah, years ago when I was adding devfs calls. I've tried to forget
about it since then...

> Also note that performance is likely to _increase_ by removing that
> stupid feature - using DMA to do the actual IO and them byteswapping
> in some higher level than the driver is likely to be a _lot_ faster
> than doing PIO (and byteswap in-place, resulting in random mmap
> corruption).

I'm actually not that concerned about performance for this case,
because it's not a common operation. If we had some kind of loop
driver that supported partitioning then I'd be satisfied. In fact, I
agree that would probably be better.

What I object to is the removal of a feature that people depend on,
*without a replacement being made available prior to removal*. If you
want to remove a feature, build the replacement *first*. Don't remove
the feature and say "the rest of you can pick up the pieces".

Regards,

Richard....
Permanent: [email protected]
Current: [email protected]

2002-04-16 15:58:33

by Alan

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

> Please use a the network block device, and teach the ndb deamon to just
> byteswap each word.

You need to use loop not nbd - loopback nbd can deadlock. Byteswap as a
new revolutionary crypto system for the loopback driver isnt hard

Alan

2002-04-16 16:00:43

by Linus Torvalds

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36



On Tue, 16 Apr 2002, Alan Cox wrote:
>
> We need to support partitioning on loopback devices in that case.

No, you just need to do the loopback over nbd - you need something to do
the byte swapping anyway (ie you can't really use the normal "loop"
device: I really just meant the more generic "loop the data back"
approach).

nbd devices already do partitioning, I'm fairly certain.

(But no, I've never tested it, obviously).

Btw, while I'm at it - who out there actually uses the new "enbd"
(Enhanced NBD)? I have this feeling that that would be the better choice,
since unlike plain nbd it should be deadlock-free on localhost (ie you
don't need a remote machine).

> > The only reason byteswapping exists is a rather historical one: Linux did
> > the wrong thing for "insw/outsw" on big-endian architectures at one point
> > (it byteswapped the data).
>
> A small number of other setups people wired the IDE the quick and easy
> way and their native format is indeed ass backwards - some M68K disks and
> the Tivo are examples of that. Interworking requires byteswapping and the
> ability to handle byteswapped partition tables.

Note that THAT case is an architecture issue, and should probably be
handled by just making the IDE "insw" macro do the byteswapping natively.
That way you don't get the current "it can actually corrupt your
filesystem on SMP" behaviour.

(Although I suspect that none of the architectures in question have ever
even jokingly considered SMP support ;)

Linus

2002-04-16 16:08:27

by Alan

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

> No, you just need to do the loopback over nbd - you need something to do
> the byte swapping anyway (ie you can't really use the normal "loop"
> device: I really just meant the more generic "loop the data back"
> approach).

nbd goes via the networking layer and deadlocks if looped. The loop driver
is also much faster. Partitioned loop doesnt seem hard.

> nbd devices already do partitioning, I'm fairly certain.

Not when I checked.

> > the Tivo are examples of that. Interworking requires byteswapping and the
> > ability to handle byteswapped partition tables.
>
> Note that THAT case is an architecture issue, and should probably be
> handled by just making the IDE "insw" macro do the byteswapping natively.
> That way you don't get the current "it can actually corrupt your
> filesystem on SMP" behaviour.

Thats still not enough. If you have the ide insw macro then control
transfers come out wrong. And to maximise the pain - some Amiga controllers
are backwards some are not.
"The use of excessive force has been authorised in the ..."

And then people stick TiVo disks in their PC's in order to prep them for
various TiVo hackery.

2002-04-16 16:11:51

by Alan

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

> compatibility issues, of course. Is anybody still working on the new early
> initrd?).

Bits of it exist - the dhcp/bootp client in userspace initrd is out there and
in real world use courtesy of the LTSP - who wrote it before anyone had even
thought about the initrd stuff 8)

2002-04-16 16:06:30

by Linus Torvalds

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36



On Tue, 16 Apr 2002, Alan Cox wrote:
> > Please use a the network block device, and teach the ndb deamon to just
> > byteswap each word.
>
> You need to use loop not nbd - loopback nbd can deadlock. Byteswap as a
> new revolutionary crypto system for the loopback driver isnt hard

Even better - I did indeed miss the "security" aspect of the byteswapping
;)

And I know from personal experience that allowing partitioning of a
loopback thing would certainly have made some things a _lot_ easier (ie
not having to figure out the damn offsets in order to mount a filesystem
on a loopback volume), so having support for partitioning would be good.

Although I do have this suspicion that that partitioning support should be
in user space (along with all the rest of the partitioning support, but
that's another matter and has some rather more serious backwards
compatibility issues, of course. Is anybody still working on the new early
initrd?).

Linus

2002-04-16 16:11:49

by Linus Torvalds

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36



On Tue, 16 Apr 2002, Richard Gooch wrote:
>
> What I object to is the removal of a feature that people depend on,
> *without a replacement being made available prior to removal*. If you
> want to remove a feature, build the replacement *first*. Don't remove
> the feature and say "the rest of you can pick up the pieces".

Hey, that happens all the time - look how many times VFS changes have made
various filesystems unusable (including yours ;)

The fact is, many things are easier to fix afterwards. Particularly
because that's the only time you'll find people motivated enough to bother
about it. If you were to need to fix everything before-the-fact, nothing
fundamental would ever get fixed, simply because the people who can fix
one thing are not usually the same people who can fix another.

(Just to take an example that _isn't_ the IDE driver, this is exactly what
the more generic bio changes have been an example of - it's just
inconceivable to fix every use of the old request interface, so somebody
has to take the first step and taker the heat about it. Otherwise it never
gets anywhere)

Linus

2002-04-16 16:34:04

by Padraig Brady

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

Linus Torvalds wrote:
>
> On Tue, 16 Apr 2002, Alan Cox wrote:
>
>>>Please use a the network block device, and teach the ndb deamon to just
>>>byteswap each word.
>>
>>You need to use loop not nbd - loopback nbd can deadlock. Byteswap as a
>>new revolutionary crypto system for the loopback driver isnt hard
>
>
> Even better - I did indeed miss the "security" aspect of the byteswapping
> ;)
>
> And I know from personal experience that allowing partitioning of a
> loopback thing would certainly have made some things a _lot_ easier (ie
> not having to figure out the damn offsets in order to mount a filesystem
> on a loopback volume), so having support for partitioning would be good.

gpart is good for this:
For e.g:

$gpart -vgd partitions.img

dev(partitions.img) mss(512)

Primary partition(1)
type: 131(0x83)(Linux ext2 filesystem)
size: 2mb #s(4576) s(32-4607)
chs: (0/1/1)-(8/15/32)d (0/0/0)-(0/0/0)r
hex: 00 01 01 00 83 0F 20 08 20 00 00 00 E0 11 00 00

Primary partition(2)
type: 131(0x83)(Linux ext2 filesystem)
size: 59mb #s(121856) s(4608-126463)
chs: (9/0/1)-(246/15/32)d (0/0/0)-(0/0/0)r
hex: 00 00 01 09 83 0F 20 F6 00 12 00 00 00 DC 01 00

The pertinent info here is s(32-4607) & s(4608-126463).
Blocks are 512 bytes so in this e.g. the offsets for
the first and second partitions respectively are:
16384 & 2359296

> Although I do have this suspicion that that partitioning support should be
> in user space (along with all the rest of the partitioning support, but
> that's another matter and has some rather more serious backwards
> compatibility issues, of course. Is anybody still working on the new early
> initrd?).
>
> Linus

Padraig.

2002-04-16 17:00:46

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

On Tue, Apr 16, 2002 at 08:46:31AM -0700, Linus Torvalds wrote:
>
> On Tue, 16 Apr 2002, Vojtech Pavlik wrote:
> >
> > Note that the above commands are no help in case of plugging TIVO
> > drive into a PC. While they assure that all ext2 filesystems are LE on
> > the media and all sun disklabels are BE on the media, still if you plug
> > in a BE ext2 into the system (or a BE PC partition table), the kernel
> > won't understand them.
>
> Please use a the network block device, and teach the ndb deamon to just
> byteswap each word.
>
> Problem solved, WITHOUT keeping bugs in the IDE driver.

Yeah, that's a pretty cool idea.

> Oh, and performance improved at the same time.
>
> What are you guys thinging about? There are two rules here:
> - optimize for the common case
> - keep the code clean.

There is also this one:

- don't remove existing features if you don't have an usable
replacement or users will hate you.

> Both of them say that Martin is 100% right.

Now that you've come up with the NBD idea, I have to agree.

--
Vojtech Pavlik
SuSE Labs

2002-04-16 17:06:02

by David Lang

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

On Tue, 16 Apr 2002, Vojtech Pavlik wrote:

> Because for Linux filesystems it was decided some time ago (after people
> HAD huge byteswap problems) that ext2 is always LE, etc, etc. So
> filesystems are supposed to be the same on every system.

In the case of Tivo they are useing a kernel from the time before the fix
went in so even their ext2 partitions are incorrect (not to mention their
other partitions that aren't ext2)

David Lang

2002-04-16 17:07:20

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

On Tue, Apr 16, 2002 at 05:23:11PM +0100, Alan Cox wrote:
> > No, you just need to do the loopback over nbd - you need something to do
> > the byte swapping anyway (ie you can't really use the normal "loop"
> > device: I really just meant the more generic "loop the data back"
> > approach).
>
> nbd goes via the networking layer and deadlocks if looped. The loop driver
> is also much faster. Partitioned loop doesnt seem hard.

And it'd be very cool for stuff like mounting Bochs disk images and
similar.

>
> > nbd devices already do partitioning, I'm fairly certain.
>
> Not when I checked.
>
> > > the Tivo are examples of that. Interworking requires byteswapping and the
> > > ability to handle byteswapped partition tables.
> >
> > Note that THAT case is an architecture issue, and should probably be
> > handled by just making the IDE "insw" macro do the byteswapping natively.
> > That way you don't get the current "it can actually corrupt your
> > filesystem on SMP" behaviour.
>
> Thats still not enough. If you have the ide insw macro then control
> transfers come out wrong. And to maximise the pain - some Amiga controllers
> are backwards some are not.
> "The use of excessive force has been authorised in the ..."
>
> And then people stick TiVo disks in their PC's in order to prep them for
> various TiVo hackery.

--
Vojtech Pavlik
SuSE Labs

2002-04-16 17:10:23

by David Miller

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

From: David Lang <[email protected]>
Date: Tue, 16 Apr 2002 10:04:02 -0700 (PDT)

On Tue, 16 Apr 2002, Vojtech Pavlik wrote:

> Because for Linux filesystems it was decided some time ago (after people
> HAD huge byteswap problems) that ext2 is always LE, etc, etc. So
> filesystems are supposed to be the same on every system.

In the case of Tivo they are useing a kernel from the time before the fix
went in so even their ext2 partitions are incorrect (not to mention their
other partitions that aren't ext2)

That's absurd. I made the fix 6 years ago, I doubt they are using a
kernel older than that.

2002-04-16 17:11:46

by David Lang

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

I could be wrong, it's a 2.1.x kernel that they started with. I thought
that was around the time the fix went in.

David Lang

On Tue, 16 Apr 2002, David S. Miller wrote:

> Date: Tue, 16 Apr 2002 10:00:55 -0700 (PDT)
> From: David S. Miller <[email protected]>
> To: [email protected]
> Cc: [email protected], [email protected], [email protected],
> [email protected], [email protected]
> Subject: Re: [PATCH] 2.5.8 IDE 36
>
> From: David Lang <[email protected]>
> Date: Tue, 16 Apr 2002 10:04:02 -0700 (PDT)
>
> On Tue, 16 Apr 2002, Vojtech Pavlik wrote:
>
> > Because for Linux filesystems it was decided some time ago (after people
> > HAD huge byteswap problems) that ext2 is always LE, etc, etc. So
> > filesystems are supposed to be the same on every system.
>
> In the case of Tivo they are useing a kernel from the time before the fix
> went in so even their ext2 partitions are incorrect (not to mention their
> other partitions that aren't ext2)
>
> That's absurd. I made the fix 6 years ago, I doubt they are using a
> kernel older than that.
>

2002-04-16 17:15:27

by David Miller

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

From: David Lang <[email protected]>
Date: Tue, 16 Apr 2002 10:09:38 -0700 (PDT)

I could be wrong, it's a 2.1.x kernel that they started with. I thought
that was around the time the fix went in.

Again, I did the fix 6 years ago, thats pre-2.0.x days

EXT2 has been little-endian only with proper byte-swapping support
across all architectures, since that time.

2002-04-16 17:18:42

by David Lang

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

Ok, in that case it must be a wierd wiring of the IDE or something.

I thought it was something more logical (silly me :-)

David Lang

On Tue, 16 Apr 2002, David S. Miller wrote:

> Date: Tue, 16 Apr 2002 10:06:10 -0700 (PDT)
> From: David S. Miller <[email protected]>
> To: [email protected]
> Cc: [email protected], [email protected], [email protected],
> [email protected], [email protected]
> Subject: Re: [PATCH] 2.5.8 IDE 36
>
> From: David Lang <[email protected]>
> Date: Tue, 16 Apr 2002 10:09:38 -0700 (PDT)
>
> I could be wrong, it's a 2.1.x kernel that they started with. I thought
> that was around the time the fix went in.
>
> Again, I did the fix 6 years ago, thats pre-2.0.x days
>
> EXT2 has been little-endian only with proper byte-swapping support
> across all architectures, since that time.
>

2002-04-16 17:43:18

by Benjamin Herrenschmidt

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

> I could be wrong, it's a 2.1.x kernel that they started with. I thought
> that was around the time the fix went in.
>
>Again, I did the fix 6 years ago, thats pre-2.0.x days
>
>EXT2 has been little-endian only with proper byte-swapping support
>across all architectures, since that time.

My understanding it that Tivo behaves like some Amiga's here
and has broken swapping of the IDE bus itself, not the ext2
filesystem.

On PPC, we still have some historical horrible macros redefinitions
in asm/ide.h to let APUS (PPC Amiga) deal with these.

Now, the problem of dealing with DMA along with the swapping is
something scary. I beleive the sanest solution that won't please
affected people is to _not_ support DMA on these broken HW ;)

Another way would be, for such broken controllers, to break the
request into 1 page max requests and let them all go through a
bounce buffer.

Ben.


2002-04-16 17:50:31

by Andreas Dilger

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

On Apr 16, 2002 09:01 -0700, Linus Torvalds wrote:
> And I know from personal experience that allowing partitioning of a
> loopback thing would certainly have made some things a _lot_ easier (ie
> not having to figure out the damn offsets in order to mount a filesystem
> on a loopback volume), so having support for partitioning would be good.

This can be done trivially in user-space without breaking any existing
code and without having to enable partitioning of a single loop device.
All that we need to do is take a tool like partx (from util-linux)
to decode the partition table and find the partition offset+size, and then
feed that to losetup (or call the loop setup ioctl directly) for each
partition. You get a bunch of loop devices set up, one for each partition.

The only thing one might want to have is some option to losetup to list
all of the loop devices currently set up ("losetup -a" or something) so
you can see which loop device corresponds to what disk partition. Of
course the partx tool would also print that out at setup time, but
people have short memories for this sort of stuff.

> Although I do have this suspicion that that partitioning support should be
> in user space (along with all the rest of the partitioning support, but
> that's another matter and has some rather more serious backwards
> compatibility issues, of course.

The partx tool (and GNU parted as well) _already_ can grok partitions
from user-space and tell the kernel about them (I had set up some
GPT/ia64 partitions on my ia32 box and mounted them just fine). All
that needs to be done is run this in early setup before we need to
mount the root filesystem.

Cheers, Andreas
--
Andreas Dilger
http://www-mddsp.enel.ucalgary.ca/People/adilger/
http://sourceforge.net/projects/ext2resize/

2002-04-16 22:48:18

by Brian Gerst

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

diff -urN linux-ide/arch/cris/drivers/ide.c linux/arch/cris/drivers/ide.c
--- linux-ide/arch/cris/drivers/ide.c Tue Apr 16 18:37:43 2002
+++ linux/arch/cris/drivers/ide.c Tue Apr 16 18:40:18 2002
@@ -192,8 +192,6 @@
#define ATA_PIO0_HOLD 4

static int e100_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
-static void e100_ideproc (ide_ide_action_t func, ide_drive_t *drive,
- void *buffer, unsigned int length);

/*
* good_dma_drives() lists the model names (from "hdparm -i")
@@ -280,7 +278,7 @@
hwif->tuneproc = &tune_e100_ide;
hwif->dmaproc = &e100_dmaproc;
hwif->ata_read = e100_ide_input_data;
- hwif->ata_write = e100_ide_input_data;
+ hwif->ata_write = e100_ide_output_data;
hwif->atapi_read = e100_atapi_read;
hwif->atapi_write = e100_atapi_write;
}
@@ -560,32 +558,6 @@
e100_atapi_write(drive, buffer, wcount << 2);
}

-/*
- * The multiplexor for ide_xxxput_data and atapi calls
- */
-static void
-e100_ideproc (ide_ide_action_t func, ide_drive_t *drive,
- void *buffer, unsigned int length)
-{
- switch (func) {
- case ideproc_ide_input_data:
- e100_ide_input_data(drive, buffer, length);
- break;
- case ideproc_ide_output_data:
- e100_ide_input_data(drive, buffer, length);
- break;
- case ideproc_atapi_read:
- e100_atapi_read(drive, buffer, length);
- break;
- case ideproc_atapi_write:
- e100_atapi_write(drive, buffer, length);
- break;
- default:
- printk("e100_ideproc: unsupported func %d!\n", func);
- break;
- }
-}
-
/* we only have one DMA channel on the chip for ATA, so we can keep these statically */
static etrax_dma_descr ata_descrs[MAX_DMA_DESCRS];
static unsigned int ata_tot_size;


Attachments:
ide36-1 (1.65 kB)

2002-04-17 08:32:32

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

On Tue, 16 Apr 2002, David S. Miller wrote:
> From: David Lang <[email protected]>
> Date: Tue, 16 Apr 2002 10:09:38 -0700 (PDT)
>
> I could be wrong, it's a 2.1.x kernel that they started with. I thought
> that was around the time the fix went in.
>
> Again, I did the fix 6 years ago, thats pre-2.0.x days
>
> EXT2 has been little-endian only with proper byte-swapping support
> across all architectures, since that time.

On SPARC. M68k followed a bit later. But when I got my CHRP board, ext2 was
still big endian on (at least some) PPC boxes, so PPC must have been switched
over in 1997/1998.

I tried to find the exact date of the appearance of the `-s' option of e2fsck
in the changelog og e2fsprogs, but apparently not all changes are mentioned
there.

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2002-04-17 08:38:42

by Martin Dalecki

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

Alan Cox wrote:
>>Doing it with a loopback like interface at a higher level is the much
>>saner operation - I understand why Martin removed the byteswap support,
>>and agree with it 100%. It just didn't make any sense from a driver
>>standpoint.
>
>
> We need to support partitioning on loopback devices in that case.
>
>
>>The only reason byteswapping exists is a rather historical one: Linux did
>>the wrong thing for "insw/outsw" on big-endian architectures at one point
>>(it byteswapped the data).
>
>
> A small number of other setups people wired the IDE the quick and easy
> way and their native format is indeed ass backwards - some M68K disks and
> the Tivo are examples of that. Interworking requires byteswapping and the
> ability to handle byteswapped partition tables.

I said it already multiple times Alan - please note that the byte-swapping code
for *physically* crosswired systems is *still there*. OK?

2002-04-17 08:41:14

by Martin Dalecki

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

Linus Torvalds wrote:
>
> On Tue, 16 Apr 2002, Richard Gooch wrote:
>
>>What I object to is the removal of a feature that people depend on,
>>*without a replacement being made available prior to removal*. If you
>>want to remove a feature, build the replacement *first*. Don't remove
>>the feature and say "the rest of you can pick up the pieces".
>
>
> Hey, that happens all the time - look how many times VFS changes have made
> various filesystems unusable (including yours ;)

Another example from the real world: Do you always have to elect democratically
a new president, before you assult the bad dictator?


2002-04-17 08:47:18

by Martin Dalecki

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

David Lang wrote:
> Ok, in that case it must be a wierd wiring of the IDE or something.
>
> I thought it was something more logical (silly me :-)
>
> David Lang

Please do me a favour - next time don't proclaim using some feature which you
actually don't. I know that the grammatical conjunktiv form is nearly dead in
english - but please intersperese the next time words like "could" "may be"
OK?

2002-04-17 08:48:42

by Martin Dalecki

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

Benjamin Herrenschmidt wrote:
>> I could be wrong, it's a 2.1.x kernel that they started with. I thought
>> that was around the time the fix went in.
>>
>>Again, I did the fix 6 years ago, thats pre-2.0.x days
>>
>>EXT2 has been little-endian only with proper byte-swapping support
>>across all architectures, since that time.
>
>
> My understanding it that Tivo behaves like some Amiga's here
> and has broken swapping of the IDE bus itself, not the ext2
> filesystem.
>
> On PPC, we still have some historical horrible macros redefinitions
> in asm/ide.h to let APUS (PPC Amiga) deal with these.
>
> Now, the problem of dealing with DMA along with the swapping is
> something scary. I beleive the sanest solution that won't please
> affected people is to _not_ support DMA on these broken HW ;)

No: the sane sollution would be to not support swapping disks between
those systems and other systems.

2002-04-17 08:54:46

by Martin Dalecki

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

Brian Gerst wrote:

>
> There is a typo in the cris ide driver ata_write value. Also,
> e100_ideproc is now dead and can be removed. Patch attached (untested,
> but obvious).
>

You are right. And your patch does the proper thing.
I thank you very much for looking in to this!

2002-04-17 09:07:21

by Alan

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

> > A small number of other setups people wired the IDE the quick and easy
> > way and their native format is indeed ass backwards - some M68K disks and
> > the Tivo are examples of that. Interworking requires byteswapping and the
> > ability to handle byteswapped partition tables.
>
> I said it already multiple times Alan - please note that the byte-swapping code
> for *physically* crosswired systems is *still there*. OK?

Thats not relevant to the discussion. I don't see why you brought it up. The
loopback stuff is about handling backward disks for interchange between
systems or dealing with historical weirdnesses much more than physical layer

2002-04-17 09:16:12

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

On Tue, 16 Apr 2002, Benjamin Herrenschmidt wrote:

> > I could be wrong, it's a 2.1.x kernel that they started with. I thought
> > that was around the time the fix went in.
> >
> >Again, I did the fix 6 years ago, thats pre-2.0.x days
> >
> >EXT2 has been little-endian only with proper byte-swapping support
> >across all architectures, since that time.
>
> My understanding it that Tivo behaves like some Amiga's here
> and has broken swapping of the IDE bus itself, not the ext2
> filesystem.

You mean Ataris and Q40/Q60s?

I'm not aware if any Amiga IDE interface with byteswapped IDE interface. Or it
must be a very rare interface not supported by Linux anyway ;-)

> On PPC, we still have some historical horrible macros redefinitions
> in asm/ide.h to let APUS (PPC Amiga) deal with these.

In asm-ppc/ide.h? Didn't see them there.

The main problem is that IDE use[sd] `inb' et al. for accesses, which is not
valid for I/O on something other than ISA/PCI I/O space. So for m68k and APUS
we have to do weird things. The new IN_BYTE() etc. should help a bit there,
though.

> Now, the problem of dealing with DMA along with the swapping is
> something scary. I beleive the sanest solution that won't please
> affected people is to _not_ support DMA on these broken HW ;)

Agreed. And you have to disable DMA when accessing a disk that originates from
such a system on a sane box.

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2002-04-17 09:27:49

by Anton Altaparmakov

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

At 08:46 17/04/02, Martin Dalecki wrote:
>Benjamin Herrenschmidt wrote:
>>My understanding it that Tivo behaves like some Amiga's here
>>and has broken swapping of the IDE bus itself, not the ext2
>>filesystem.
>>On PPC, we still have some historical horrible macros redefinitions
>>in asm/ide.h to let APUS (PPC Amiga) deal with these.
>>Now, the problem of dealing with DMA along with the swapping is
>>something scary. I beleive the sanest solution that won't please
>>affected people is to _not_ support DMA on these broken HW ;)
>
>No: the sane sollution would be to not support swapping disks between
>those systems and other systems.

<disclaimer: rant>

No it isn't. You can't just go removing features people use. Your attitude
as the new IDE maintainer is a bit distressing.

In the sake of a cleanup you start throwing away one feature after the
other. IMHO cleanups are not worth feature removal, obviously your opinion
differs. Hopefully, we will see the features come back but still the
interim is annoying for some people...

Also, even more distressing is that you seem to be almost completely
unresponsive to bug reports about your IDE changes completely breaking IDE.
My email reporting in detail how any post 2.5.7 kernel fails to boot due to
hanging during IDE device discovery was left unanswered. Off-line I am told
you responded to another similar bug report trying to shift the blame to
someone else's code and when it became apparent it was the IDE code you
just stopped responding. Do you expect everyone to understand IDE and find
and fix your bugs? A maintainer of a subsystem should work with people to
find bugs and fix them, not expect users to do that... Your IDE patches
keep flowing in one after the other but you completely ignore the fact that
you broke IDE for some people along the way and the chances of it fixing
itself by accident are minute... and finding the bug is probably getting
harder with every patch you submit...

This is _not_ what I would expect from a maintainer of such an important
subsystem!

</rant>

Apologies for the rant but I feel a lot better now.

Best regards,

Anton


--
"I've not lost my mind. It's backed up on tape somewhere." - Unknown
--
Anton Altaparmakov <aia21 at cantab.net> (replace at with @)
Linux NTFS Maintainer / IRC: #ntfs on irc.openprojects.net
WWW: http://linux-ntfs.sf.net/ & http://www-stu.christs.cam.ac.uk/~aia21/

2002-04-17 09:34:07

by Benjamin Herrenschmidt

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

>On Tue, 16 Apr 2002, Benjamin Herrenschmidt wrote:
>
>> > I could be wrong, it's a 2.1.x kernel that they started with. I thought
>> > that was around the time the fix went in.
>> >
>> >Again, I did the fix 6 years ago, thats pre-2.0.x days
>> >
>> >EXT2 has been little-endian only with proper byte-swapping support
>> >across all architectures, since that time.
>>
>> My understanding it that Tivo behaves like some Amiga's here
>> and has broken swapping of the IDE bus itself, not the ext2
>> filesystem.
>
>You mean Ataris and Q40/Q60s?
>
>I'm not aware if any Amiga IDE interface with byteswapped IDE interface.
Or it
>must be a very rare interface not supported by Linux anyway ;-)

My confusion then. We used to have these in the PPC tree, and I
suspected those were APUS related ;)

>> On PPC, we still have some historical horrible macros redefinitions
>> in asm/ide.h to let APUS (PPC Amiga) deal with these.
>
>In asm-ppc/ide.h? Didn't see them there.

Right, looks like they are gone lately. Well, the TiVO may have been one
reason for these though I don't think the support for this box has ever
made it into our main tree. It's possible that we had some broken PReP
or whatever early boxes.

>The main problem is that IDE use[sd] `inb' et al. for accesses, which is not
>valid for I/O on something other than ISA/PCI I/O space. So for m68k and APUS
>we have to do weird things. The new IN_BYTE() etc. should help a bit there,
>though.

We tweak on pmac by feeding the IDE layer with our controller virtual address
minus _IO_BASE (for non-PPC people, _IO_BASE is the virtual address of the
main PCI IO space, all inx/outx are relative to this). The pointer arithmetic
does the magic. It sucks, but works without redefining everything around.
I haven't looked at the new IN_BYTE stuff, though if it is IDE specific,
I'd rather see it called IDE_IN_BYTE. The current scheme sucks also because
inx/outx, at least on PPC, are a lot slower than normal MMIO access (one
reason beeing their ability to recovert from machine checks). It would be
nice for IDE to use it's own accessors on MMIO platforms. This has to be
a per-controller things though. A global macro is no good. You can (and on
some configs, you do have on the motherboard) both MMIO mapped controllers
and old-style IO mapped ones. One example is the B&W mac G3 which has both
the Apple MMIO mapped mac-io IDE controller and the CMD646 on the PCI bus.

Also, when applying the taskfile, I suspect we don't need strong barriers as
we do currently have, only on IO write barrier before actually writing the
command byte. But I would gladly leave the whole issue of redefining barriers
especially regarding IOs to Anton Blanchard ;)

Maybe the entire function for writing a taskfile register state to the
controller should be made a hwif indirect call. (On Darwin, they more or
less do that, along with a bitmask indicating which register has to be
applied, though I suspect the tests against this bitmask would eats pretty
much all of the benefit of removing the useless barriers).

>> Now, the problem of dealing with DMA along with the swapping is
>> something scary. I beleive the sanest solution that won't please
>> affected people is to _not_ support DMA on these broken HW ;)
>
>Agreed. And you have to disable DMA when accessing a disk that
originates from
>such a system on a sane box.

Agreed.

Ben.

2002-04-17 09:35:58

by David Lang

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

I use the byteswap feature to access these disks. It appears I was wrong
about the reason that I needed to use it, but the need is correct.

the fact is that for whatever reason the drives the tivo uses are
byteswapped compared to what they need to be for me to read them on an x86
system.

if another way is available I will use it, in the meantime I will not be
able to use 2.5 kernels to access those drives (since connecting and
disconnecting the drives requires a reboot this isn't a fatal flaw)

David Lang

On Wed, 17 Apr 2002, Martin Dalecki wrote:

> Date: Wed, 17 Apr 2002 09:44:54 +0200
> From: Martin Dalecki <[email protected]>
> To: David Lang <[email protected]>
> Cc: David S. Miller <[email protected]>, [email protected],
> [email protected], [email protected],
> [email protected]
> Subject: Re: [PATCH] 2.5.8 IDE 36
>
> David Lang wrote:
> > Ok, in that case it must be a wierd wiring of the IDE or something.
> >
> > I thought it was something more logical (silly me :-)
> >
> > David Lang
>
> Please do me a favour - next time don't proclaim using some feature which you
> actually don't. I know that the grammatical conjunktiv form is nearly dead in
> english - but please intersperese the next time words like "could" "may be"
> OK?
>

2002-04-17 09:41:59

by Martin Dalecki

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

Benjamin Herrenschmidt wrote:

> We tweak on pmac by feeding the IDE layer with our controller virtual address
> minus _IO_BASE (for non-PPC people, _IO_BASE is the virtual address of the
> main PCI IO space, all inx/outx are relative to this). The pointer arithmetic
> does the magic. It sucks, but works without redefining everything around.
> I haven't looked at the new IN_BYTE stuff, though if it is IDE specific,
> I'd rather see it called IDE_IN_BYTE. The current scheme sucks also because
> inx/outx, at least on PPC, are a lot slower than normal MMIO access (one
> reason beeing their ability to recovert from machine checks). It would be
> nice for IDE to use it's own accessors on MMIO platforms. This has to be
> a per-controller things though. A global macro is no good. You can (and on
> some configs, you do have on the motherboard) both MMIO mapped controllers
> and old-style IO mapped ones. One example is the B&W mac G3 which has both
> the Apple MMIO mapped mac-io IDE controller and the CMD646 on the PCI bus.
>
> Also, when applying the taskfile, I suspect we don't need strong barriers as
> we do currently have, only on IO write barrier before actually writing the
> command byte. But I would gladly leave the whole issue of redefining barriers
> especially regarding IOs to Anton Blanchard ;)
>
> Maybe the entire function for writing a taskfile register state to the
> controller should be made a hwif indirect call. (On Darwin, they more or
> less do that, along with a bitmask indicating which register has to be
> applied, though I suspect the tests against this bitmask would eats pretty
> much all of the benefit of removing the useless barriers).

Thank you for the elaborated explanation. I think that some
of your ideas presented here could be well pursued becouse they are
indeed good. :-).

2002-04-17 09:41:34

by David Lang

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

On Wed, 17 Apr 2002, Martin Dalecki wrote:

> > Now, the problem of dealing with DMA along with the swapping is
> > something scary. I beleive the sanest solution that won't please
> > affected people is to _not_ support DMA on these broken HW ;)
>
> No: the sane sollution would be to not support swapping disks between
> those systems and other systems.

in this case please send me a system compatable with my tivo so that I can
hack on it since you are telling me I'm not going to be able to swap disks
between it and any sane system.

doing without DMA is very reasonable and not a significant problem (yes it
slows me down if I am duplicating drives, but if I am mounting the drive
so that I can go in and vi the startup files the speed difference doesn't
matter)

David Lang

2002-04-17 10:11:41

by Petr Vandrovec

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

On 17 Apr 02 at 2:39, David Lang wrote:
> On Wed, 17 Apr 2002, Martin Dalecki wrote:
>
> > > Now, the problem of dealing with DMA along with the swapping is
> > > something scary. I beleive the sanest solution that won't please
> > > affected people is to _not_ support DMA on these broken HW ;)
> >
> > No: the sane sollution would be to not support swapping disks between
> > those systems and other systems.
>
> in this case please send me a system compatable with my tivo so that I can
> hack on it since you are telling me I'm not going to be able to swap disks
> between it and any sane system.
>
> doing without DMA is very reasonable and not a significant problem (yes it
> slows me down if I am duplicating drives, but if I am mounting the drive
> so that I can go in and vi the startup files the speed difference doesn't
> matter)

I believe that if you'll create patch which will not byteswap data in
place, and which will not slow system down, he'll accept it.

As there are only three places where bswap should be checked
(taskfile_input_data, taskfile_output_data, enabling DMA),
it is trivial - just fork ata_{input,output}_data, and use insw_swapw/
outsw_swapw in new variant. It will work long as driver properly
diferentiates that taskfile_*_data is for data read to/from disk plates,
while ata_*_data is for data produced by disk itself (identify & co.),
and without speed difference, as PCI/VLB/ISA/disk/whatever is limiting
factor for speed of ata_*_data function.
Petr Vandrovec
[email protected]

2002-04-17 10:22:19

by David Lang

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

My understanding of the old code was that it worked in PIO mode, but was
unsafe to use with DMA. I don't think anyone asking to have it upgraded to
work in DMA mode (not that anyone would object to that if it happened),
just don't remove the working PIO mode byteswap capability without some
thought as to how to achieve the same result.

also if another way becomes available to do the same job (i.e. loopback
with partition support) that will also solve my problem and I won't care
if direct byteswap support is removed.

what I do object to is the statement that "the sane solution would be to
not support swapping disks between these systems and other systems"

declaring that the capability that is currently in place and in use by
people should be eliminated with no replacement is wrong.

David Lang

On Wed, 17 Apr 2002, Petr Vandrovec wrote:

> On 17 Apr 02 at 2:39, David Lang wrote:
> > On Wed, 17 Apr 2002, Martin Dalecki wrote:
> >
> > > > Now, the problem of dealing with DMA along with the swapping is
> > > > something scary. I beleive the sanest solution that won't please
> > > > affected people is to _not_ support DMA on these broken HW ;)
> > >
> > > No: the sane sollution would be to not support swapping disks between
> > > those systems and other systems.
> >
> > in this case please send me a system compatable with my tivo so that I can
> > hack on it since you are telling me I'm not going to be able to swap disks
> > between it and any sane system.
> >
> > doing without DMA is very reasonable and not a significant problem (yes it
> > slows me down if I am duplicating drives, but if I am mounting the drive
> > so that I can go in and vi the startup files the speed difference doesn't
> > matter)
>
> I believe that if you'll create patch which will not byteswap data in
> place, and which will not slow system down, he'll accept it.
>
> As there are only three places where bswap should be checked
> (taskfile_input_data, taskfile_output_data, enabling DMA),
> it is trivial - just fork ata_{input,output}_data, and use insw_swapw/
> outsw_swapw in new variant. It will work long as driver properly
> diferentiates that taskfile_*_data is for data read to/from disk plates,
> while ata_*_data is for data produced by disk itself (identify & co.),
> and without speed difference, as PCI/VLB/ISA/disk/whatever is limiting
> factor for speed of ata_*_data function.
> Petr Vandrovec
> [email protected]
>
>

2002-04-17 20:56:48

by Mike Fedyk

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

On Wed, Apr 17, 2002 at 09:46:15AM +0200, Martin Dalecki wrote:
> Benjamin Herrenschmidt wrote:
> >something scary. I beleive the sanest solution that won't please
> >affected people is to _not_ support DMA on these broken HW ;)
>
> No: the sane sollution would be to not support swapping disks between
> those systems and other systems.

Martin,

Go ahead and remove the byte swaping code for now, since it is a development
kernel after all...

*But*, make sure you put that on your to do list to add it back in a "sane"
way.

2002-04-18 10:18:32

by Martin Dalecki

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 37

diff -urN linux-2.5.8/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c
--- linux-2.5.8/drivers/ide/ide-dma.c Wed Apr 17 23:09:19 2002
+++ linux/drivers/ide/ide-dma.c Wed Apr 17 23:28:22 2002
@@ -599,13 +599,19 @@
printk("%s: DMA disabled\n", drive->name);
case ide_dma_off_quietly:
set_high = 0;
- drive->using_tcq = 0;
outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
+#ifdef CONFIG_BLK_DEV_IDE_TCQ
+ hwif->dmaproc(ide_dma_queued_off, drive);
+#endif
case ide_dma_on:
ide_toggle_bounce(drive, set_high);
drive->using_dma = (func == ide_dma_on);
- if (drive->using_dma)
+ if (drive->using_dma) {
outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT
+ hwif->dmaproc(ide_dma_queued_on, drive);
+#endif
+ }
return 0;
case ide_dma_check:
return config_drive_for_dma (drive);
diff -urN linux-2.5.8/drivers/ide/ide-taskfile.c linux/drivers/ide/ide-taskfile.c
--- linux-2.5.8/drivers/ide/ide-taskfile.c Wed Apr 17 23:22:53 2002
+++ linux/drivers/ide/ide-taskfile.c Wed Apr 17 23:28:22 2002
@@ -413,6 +413,20 @@
struct hd_driveid *id = drive->id;
u8 HIHI = (drive->addressing) ? 0xE0 : 0xEF;

+#if 0
+ printk("ata_taskfile ... %p\n", args->handler);
+
+ printk(" sector feature %02x\n", args->taskfile.feature);
+ printk(" sector count %02x\n", args->taskfile.sector_count);
+ printk(" drive/head %02x\n", args->taskfile.device_head);
+ printk(" command %02x\n", args->taskfile.command);
+
+ if (rq)
+ printk(" rq->nr_sectors %2li\n", rq->nr_sectors);
+ else
+ printk(" rq-> = null\n");
+#endif
+
/* (ks/hs): Moved to start, do not use for multiple out commands */
if (args->handler != task_mulout_intr) {
if (IDE_CONTROL_REG)
@@ -577,18 +591,22 @@
ata_read(drive, pBuf, SECTOR_WORDS);
ide_unmap_rq(rq, pBuf, &flags);

+ /*
+ * first segment of the request is complete. note that this does not
+ * necessarily mean that the entire request is done!! this is only
+ * true if ide_end_request() returns 0.
+ */
if (--rq->current_nr_sectors <= 0) {
- /* (hs): swapped next 2 lines */
DTF("Request Ended stat: %02x\n", GET_STAT());
- if (ide_end_request(drive, 1)) {
- ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
- return ide_started;
- }
- } else {
- ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
- return ide_started;
+ if (!ide_end_request(drive, 1))
+ return ide_stopped;
}
- return ide_stopped;
+
+ /*
+ * still data left to transfer
+ */
+ ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
+ return ide_started;
}

static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq)
@@ -874,7 +892,6 @@
return;

case WIN_NOP:
-
args->command_type = IDE_DRIVE_TASK_NO_DATA;
return;

@@ -904,11 +921,6 @@
struct ata_request star;

ata_ar_init(drive, &star);
-
- /* Don't put this request on free_req list after usage.
- */
- star.ar_flags |= ATA_AR_STATIC;
-
init_taskfile_request(&rq);
rq.buffer = buf;

diff -urN linux-2.5.8/drivers/ide/ide-tcq.c linux/drivers/ide/ide-tcq.c
--- linux-2.5.8/drivers/ide/ide-tcq.c Wed Apr 17 23:09:14 2002
+++ linux/drivers/ide/ide-tcq.c Wed Apr 17 23:28:22 2002
@@ -51,21 +51,17 @@
*/
#undef IDE_TCQ_FIDDLE_SI

-/*
- * wait for data phase before starting DMA or not
- */
-#undef IDE_TCQ_WAIT_DATAPHASE
-
ide_startstop_t ide_dmaq_intr(ide_drive_t *drive);
ide_startstop_t ide_service(ide_drive_t *drive);

static inline void drive_ctl_nien(ide_drive_t *drive, int clear)
{
#ifdef IDE_TCQ_NIEN
- int mask = clear ? 0x00 : 0x02;
+ if (IDE_CONTROL_REG) {
+ int mask = clear ? 0x00 : 0x02;

- if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl | mask, IDE_CONTROL_REG);
+ }
#endif
}

@@ -123,7 +119,6 @@
init_taskfile_request(ar->ar_rq);
ar->ar_rq->rq_dev = mk_kdev(drive->channel->major, (drive->select.b.unit)<<PARTN_BITS);
ar->ar_rq->special = ar;
- ar->ar_flags |= ATA_AR_RETURN;
_elv_add_request(q, ar->ar_rq, 0, 0);

/*
@@ -222,7 +217,7 @@
{
struct ata_request *ar;
byte feat, stat;
- int tag;
+ int tag, ret;

TCQ_PRINTK("%s: started service\n", drive->name);

@@ -272,9 +267,6 @@
return ide_stopped;
}

- /*
- * start dma
- */
tag = feat >> 3;
IDE_SET_CUR_TAG(drive, tag);

@@ -293,16 +285,16 @@
*/
if (rq_data_dir(ar->ar_rq) == READ) {
TCQ_PRINTK("ide_service: starting READ %x\n", stat);
- drive->channel->dmaproc(ide_dma_read_queued, drive);
+ ret = drive->channel->dmaproc(ide_dma_read_queued, drive);
} else {
TCQ_PRINTK("ide_service: starting WRITE %x\n", stat);
- drive->channel->dmaproc(ide_dma_write_queued, drive);
+ ret = drive->channel->dmaproc(ide_dma_write_queued, drive);
}

/*
* dmaproc set intr handler
*/
- return ide_started;
+ return !ret ? ide_started : ide_stopped;
}

ide_startstop_t ide_check_service(ide_drive_t *drive)
@@ -410,14 +402,15 @@
*/
static int ide_tcq_configure(ide_drive_t *drive)
{
+ int tcq_mask = 1 << 1 | 1 << 14;
+ int tcq_bits = tcq_mask | 1 << 15;
struct ata_taskfile args;
- int tcq_supp = 1 << 1 | 1 << 14;

/*
* bit 14 and 1 must be set in word 83 of the device id to indicate
- * support for dma queued protocol
+ * support for dma queued protocol, and bit 15 must be cleared
*/
- if ((drive->id->command_set_2 & tcq_supp) != tcq_supp)
+ if ((drive->id->command_set_2 & tcq_bits) ^ tcq_mask)
return -EIO;

memset(&args, 0, sizeof(args));
@@ -477,11 +470,14 @@
*/
static int ide_enable_queued(ide_drive_t *drive, int on)
{
+ int depth = drive->using_tcq ? drive->queue_depth : 0;
+
/*
* disable or adjust queue depth
*/
if (!on) {
- printk("%s: TCQ disabled\n", drive->name);
+ if (drive->using_tcq)
+ printk("%s: TCQ disabled\n", drive->name);
drive->using_tcq = 0;
return 0;
}
@@ -491,25 +487,33 @@
return 1;
}

+ /*
+ * possibly expand command list
+ */
if (ide_build_commandlist(drive))
return 1;

- printk("%s: tagged command queueing enabled, command queue depth %d\n", drive->name, drive->queue_depth);
+ if (depth != drive->queue_depth)
+ printk("%s: tagged command queueing enabled, command queue depth %d\n", drive->name, drive->queue_depth);
+
drive->using_tcq = 1;
+
+ /*
+ * clear stats
+ */
drive->tcq->max_depth = 0;
return 0;
}

int ide_tcq_wait_dataphase(ide_drive_t *drive)
{
-#ifdef IDE_TCQ_WAIT_DATAPHASE
ide_startstop_t foo;

- if (ide_wait_stat(&startstop, drive, READY_STAT | DRQ_STAT, BUSY_STAT, WAIT_READY)) {
+ if (ide_wait_stat(&foo, drive, READY_STAT | DRQ_STAT, BUSY_STAT, WAIT_READY)) {
printk("%s: timeout waiting for data phase\n", drive->name);
return 1;
}
-#endif
+
return 0;
}

@@ -595,6 +599,8 @@
if (ide_start_dma(hwif, drive, func))
return ide_stopped;

+ TCQ_PRINTK("IMMED in queued_start\n");
+
/*
* need to arm handler before starting dma engine,
* transfer could complete right away
@@ -612,6 +618,8 @@
case ide_dma_queued_off:
enable_tcq = 0;
case ide_dma_queued_on:
+ if (enable_tcq && !drive->using_dma)
+ return 1;
return ide_enable_queued(drive, enable_tcq);
default:
break;
diff -urN linux-2.5.8/drivers/ide/ide.c linux/drivers/ide/ide.c
--- linux-2.5.8/drivers/ide/ide.c Wed Apr 17 23:22:53 2002
+++ linux/drivers/ide/ide.c Wed Apr 17 23:28:22 2002
@@ -803,8 +803,7 @@
args->hobfile.high_cylinder = IN_BYTE(IDE_HCYL_REG);
}
}
- if (ar->ar_flags & ATA_AR_RETURN)
- ata_ar_put(drive, ar);
+ ata_ar_put(drive, ar);
}

blkdev_dequeue_request(rq);
diff -urN linux-2.5.8/include/linux/ide.h linux/include/linux/ide.h
--- linux-2.5.8/include/linux/ide.h Wed Apr 17 23:22:53 2002
+++ linux/include/linux/ide.h Wed Apr 17 23:30:30 2002
@@ -968,10 +968,9 @@
/*
* ata_request flag bits
*/
-#define ATA_AR_QUEUED 1
-#define ATA_AR_SETUP 2
-#define ATA_AR_RETURN 4
-#define ATA_AR_STATIC 8
+#define ATA_AR_QUEUED 1 /* was queued */
+#define ATA_AR_SETUP 2 /* dma table mapped */
+#define ATA_AR_POOL 4 /* originated from drive pool */

/*
* if turn-around time is longer than this, halve queue depth
@@ -1003,8 +1002,10 @@

if (!list_empty(&drive->free_req)) {
ar = list_ata_entry(drive->free_req.next);
+
list_del(&ar->ar_queue);
ata_ar_init(drive, ar);
+ ar->ar_flags |= ATA_AR_POOL;
}

return ar;
@@ -1012,8 +1013,8 @@

static inline void ata_ar_put(ide_drive_t *drive, struct ata_request *ar)
{
- if (!(ar->ar_flags & ATA_AR_STATIC))
- list_add(&ar->ar_queue, &drive->free_req);
+ if (ar->ar_flags & ATA_AR_POOL)
+ list_add(&ar->ar_queue, &drive->free_req);

if (ar->ar_flags & ATA_AR_QUEUED) {
/* clear the tag */


Attachments:
ide-clean-39.diff (8.50 kB)

2002-04-18 10:16:31

by Martin Dalecki

[permalink] [raw]
Subject: [PATCH] 2.5.8 IDE 38

diff -urN linux-2.5.8/Documentation/ide.txt linux/Documentation/ide.txt
--- linux-2.5.8/Documentation/ide.txt Mon Mar 18 21:37:06 2002
+++ linux/Documentation/ide.txt Wed Apr 17 22:55:55 2002
@@ -1,71 +1,16 @@
-ide.txt -- Information regarding the Enhanced IDE drive in Linux 2.2/2.3/2.4
-===============================================================================

- +-----------------------------------------------------------------+
- | The hdparm utility for controlling various IDE features is |
- | packaged separately. Look for it on popular linux FTP sites. |
- +-----------------------------------------------------------------+
-
-See description later on below for handling BIG IDE drives with >1024 cyls.
-
-Major features of the 2.1/2.2 IDE driver ("NEW!" marks changes since 2.0.xx):
-
-NEW! - support for IDE ATAPI *floppy* drives
- - support for IDE ATAPI *tape* drives, courtesy of Gadi Oxman
- (re-run MAKEDEV.ide to create the tape device entries in /dev/)
- - support for up to *four* IDE interfaces on one or more IRQs
- - support for any mix of up to *eight* IDE drives
- - support for reading IDE ATAPI cdrom drives (NEC,MITSUMI,VERTOS,SONY)
- - support for audio functions
- - auto-detection of interfaces, drives, IRQs, and disk geometries
- - "single" drives should be jumpered as "master", not "slave"
- (both are now probed for)
- - support for BIOSs which report "more than 16 heads" on disk drives
- - uses LBA (slightly faster) on disk drives which support it
- - support for lots of fancy (E)IDE drive functions with hdparm utility
- - optional (compile time) support for 32-bit VLB data transfers
- - support for IDE multiple (block) mode (same as hd.c)
- - support for interrupt unmasking during I/O (better than hd.c)
- - improved handshaking and error detection/recovery
- - can co-exist with hd.c controlling the first interface
- - run-time selectable 32bit interface support (using hdparm-2.3)
- - support for reliable operation of buggy RZ1000 interfaces
- - PCI support is automatic when rz1000 support is configured
- - support for reliable operation of buggy CMD-640 interfaces
- - PCI support is automatic when cmd640 support is configured
- - for VLB, use kernel command line option: ide0=cmd640_vlb
- - this support also enables the secondary i/f when needed
- - interface PIO timing & prefetch parameter support
- - experimental support for UMC 8672 interfaces
- - support for secondary interface on the FGI/Holtek HT-6560B VLB i/f
- - use kernel command line option: ide0=ht6560b
- - experimental support for various IDE chipsets
- - use appropriate kernel command line option from list below
- - support for drives with a stuck WRERR_STAT bit
- - support for removable devices, including door lock/unlock
- - transparent support for DiskManager 6.0x and "Dynamic Disk Overlay"
- - works with Linux fdisk, LILO, loadlin, bootln, etc..
- - mostly transparent support for EZ-Drive disk translation software
- - to use LILO with EZ, install LILO on the linux partition
- rather than on the master boot record, and then mark the
- linux partition as "bootable" or "active" using fdisk.
- (courtesy of Juha Laiho <[email protected]>).
- - auto-detect of disk translations by examining partition table
- - ide-cd.c now compiles separate from ide.c
- - ide-cd.c now supports door locking and auto-loading.
- - Also preliminary support for multisession
- and direct reads of audio data.
- - experimental support for Promise DC4030VL caching interface card
- - email thanks/problems to: [email protected]
- - the hdparm-3.1 package can be used to set PIO modes for some chipsets.
-NEW! - support for setting PIO modes with the OPTi 82C621, courtesy of Jaromir Koutek.
-NEW! - support for loadable modules
-NEW! - optional SCSI host adapter emulation for ATAPI devices
-NEW! - generic PCI Bus-Master DMA support
-NEW! - works with most Pentium PCI systems, chipsets, add-on cards
-NEW! - works with regular DMA as well as Ultra DMA
-NEW! - automatically probes for all PCI IDE interfaces
-NEW! - generic support for using BIOS-configured Ultra-DMA (UDMA) transfers
+
+
+ Information regarding the Enhanced IDE drive in Linux 2.5
+
+
+==============================================================================
+
+
+ The hdparm utility can be used to controll various IDE features on a
+ running system. It is packaged separately. Please Look for it on popular
+ linux FTP sites.
+


*** IMPORTANT NOTICES: BUGGY IDE CHIPSETS CAN CORRUPT DATA!!
@@ -92,9 +37,9 @@
***
*** Use of the "serialize" option is no longer necessary.

-This is the multiple IDE interface driver, as evolved from hd.c.
-It supports up to six IDE interfaces, on one or more IRQs (usually 14 & 15).
-There can be up to two drives per interface, as per the ATA-2 spec.
+This is the multiple IDE interface driver, as evolved from hd.c. It supports
+up to 9 IDE interfaces per default, on one or more IRQs (usually 14 & 15).
+There can be up to two drives per interface, as per the ATA-6 spec.

Primary: ide0, port 0x1f0; major=3; hda is minor=0; hdb is minor=64
Secondary: ide1, port 0x170; major=22; hdc is minor=0; hdd is minor=64
@@ -103,16 +48,14 @@
fifth.. ide4, usually PCI, probed
sixth.. ide5, usually PCI, probed

-To access devices on interfaces > ide0, device entries must first be
-created in /dev for them. To create such entries, simply run the included
-shell script: /usr/src/linux/scripts/MAKEDEV.ide
-
-Apparently many older releases of Slackware had incorrect entries
-in /dev for hdc* and hdd* -- this can also be corrected by running MAKEDEV.ide
-
-ide.c automatically probes for most IDE interfaces (including all PCI ones),
-for the drives/geometries attached to those interfaces, and for the
-IRQ numbers being used by the interfaces (normally 14, 15 for ide0/ide1).
+To access devices on interfaces > ide0, device entries please make sure that
+device files for them are present in /dev. If not, please create such
+entries, by simply running the included shell script:
+/usr/src/linux/scripts/MAKEDEV.ide
+
+This driver automatically probes for most IDE interfaces (including all PCI
+ones), for the drives/geometries attached to those interfaces, and for the IRQ
+lines being used by the interfaces (normally 14, 15 for ide0/ide1).

For special cases, interfaces may be specified using kernel "command line"
options. For example,
@@ -170,11 +113,11 @@
hdc=768,16,32
hdc=noprobe

-Note that when only one IDE device is attached to an interface,
-it should be jumpered as "single" or "master", *not* "slave".
-Many folks have had "trouble" with cdroms because of this requirement,
-so ide.c now probes for both units, though success is more likely
-when the drive is jumpered correctly.
+Note that when only one IDE device is attached to an interface, it should be
+jumpered as "single" or "master", *not* "slave". Many folks have had
+"trouble" with cdroms because of this requirement, so the driver now probes
+for both units, though success is more likely when the drive is jumpered
+correctly.

Courtesy of Scott Snyder and others, the driver supports ATAPI cdrom drives
such as the NEC-260 and the new MITSUMI triple/quad speed drives.
@@ -193,8 +136,8 @@
(/dev/hdc). To mount a CD in the cdrom drive, one would use something like:

ln -sf /dev/hdc /dev/cdrom
- mkdir /cd
- mount /dev/cdrom /cd -t iso9660 -o ro
+ mkdir /mnt/cdrom
+ mount /dev/cdrom /mnt/cdrom -t iso9660 -o ro

If, after doing all of the above, mount doesn't work and you see
errors from the driver (with dmesg) complaining about `status=0xff',
@@ -274,8 +217,6 @@
older/odd IDE drives.
"hdx=slow" : insert a huge pause after each access to the data
port. Should be used only as a last resort.
- "hdx=swapdata" : when the drive is a disk, byte swap all data
-
"hdxlun=xx" : set the drive last logical unit

"idebus=xx" : inform IDE driver of VESA/PCI bus speed in MHz,
@@ -307,8 +248,9 @@
"idex=reset" : reset interface after probe
"idex=dma" : automatically configure/use DMA if possible.

- The following are valid ONLY on ide0,
- and the defaults for the base,ctl ports must not be altered.
+The following are valid ONLY on ide0, which usually corresponds to the first
+ATA interface found on the particular host, and the defaults for the base,ctl
+ports must not be altered.

"ide0=dtc2278" : probe/support DTC2278 interface
"ide0=ht6560b" : probe/support HT6560B interface
@@ -329,179 +271,21 @@
IDE = Integrated Drive Electronics, meaning that each drive has a built-in
controller, which is why an "IDE interface card" is not a "controller card".

-IDE drives are designed to attach almost directly to the ISA bus of an AT-style
-computer. The typical IDE interface card merely provides I/O port address
-decoding and tri-state buffers, although several newer localbus cards go much
-beyond the basics. When purchasing a localbus IDE interface, avoid cards with
-an onboard BIOS and those which require special drivers. Instead, look for a
-card which uses hardware switches/jumpers to select the interface timing speed,
-to allow much faster data transfers than the original 8MHz ISA bus allows.
-
ATA = AT (the old IBM 286 computer) Attachment Interface, a draft American
National Standard for connecting hard drives to PCs. This is the official
name for "IDE".

-The latest standards define some enhancements, known as the ATA-2 spec,
+The latest standards define some enhancements, known as the ATA-6 spec,
which grew out of vendor-specific "Enhanced IDE" (EIDE) implementations.

ATAPI = ATA Packet Interface, a new protocol for controlling the drives,
similar to SCSI protocols, created at the same time as the ATA2 standard.
-ATAPI is currently used for controlling CDROM and TAPE devices, and will
-likely also soon be used for Floppy drives, removable R/W cartridges,
-and for high capacity hard disk drives.
-
-How To Use *Big* ATA/IDE drives with Linux
-------------------------------------------
-The ATA Interface spec for IDE disk drives allows a total of 28 bits
-(8 bits for sector, 16 bits for cylinder, and 4 bits for head) for addressing
-individual disk sectors of 512 bytes each (in "Linear Block Address" (LBA)
-mode, there is still only a total of 28 bits available in the hardware).
-This "limits" the capacity of an IDE drive to no more than 128GB (Giga-bytes).
-All current day IDE drives are somewhat smaller than this upper limit, and
-within a few years, ATAPI disk drives will raise the limit considerably.
-
-All IDE disk drives "suffer" from a "16-heads" limitation: the hardware has
-only a four bit field for head selection, restricting the number of "physical"
-heads to 16 or less. Since the BIOS usually has a 63 sectors/track limit,
-this means that all IDE drivers larger than 504MB (528Meg) must use a "physical"
-geometry with more than 1024 cylinders.
-
- (1024cyls * 16heads * 63sects * 512bytes/sector) / (1024 * 1024) == 504MB
-
-(Some BIOSs (and controllers with onboard BIOS) pretend to allow "32" or "64"
- heads per drive (discussed below), but can only do so by playing games with
- the real (hidden) geometry, which is always limited to 16 or fewer heads).
-
-This presents two problems to most systems:
-
- 1. The INT13 interface to the BIOS only allows 10-bits for cylinder
- addresses, giving a limit of 1024cyls for programs which use it.
-
- 2. The physical geometry fields of the disk partition table only
- allow 10-bits for cylinder addresses, giving a similar limit of 1024
- cyls for operating systems that do not use the "sector count" fields
- instead of the physical Cyl/Head/Sect (CHS) geometry fields.
-
-Neither of these limitations affects Linux itself, as it (1) does not use the
-BIOS for disk access, and it (2) is clever enough to use the "sector count"
-fields of the partition table instead of the physical CHS geometry fields.
-
- a) Most folks use LILO to load linux. LILO uses the INT13 interface
- to the BIOS to load the kernel at boot time. Therefore, LILO can only
- load linux if the files it needs (usually just the kernel images) are
- located below the magic 1024 cylinder "boundary" (more on this later).
-
- b) Many folks also like to have bootable DOS partitions on their
- drive(s). DOS also uses the INT13 interface to the BIOS, not only
- for booting, but also for operation after booting. Therefore, DOS
- can normally only access partitions which are contained entirely below
- the magic 1024 cylinder "boundary".
-
-There are at least seven commonly used schemes for kludging DOS to work
-around this "limitation". In the long term, the problem is being solved
-by introduction of an alternative BIOS interface that does not have the
-same limitations as the INT13 interface. New versions of DOS are expected
-to detect and use this interface in systems whose BIOS provides it.
-
-But in the present day, alternative solutions are necessary.
-
-The most popular solution in newer systems is to have the BIOS shift bits
-between the cylinder and head number fields. This is activated by entering
-a translated logical geometry into the BIOS/CMOS setup for the drive.
-Thus, if the drive has a geometry of 2100/16/63 (CHS), then the BIOS could
-present a "logical" geometry of 525/64/63 by "shifting" two bits from the
-cylinder number into the head number field for purposes of the partition table,
-CMOS setup, and INT13 interfaces. Linux kernels 1.1.39 and higher detect and
-"handle" this translation automatically, making this a rather painless solution
-for the 1024 cyls problem. If for some reason Linux gets confused (unlikely),
-then use the kernel command line parameters to pass the *logical* geometry,
-as in: hda=525,64,63
-
-If the BIOS does not support this form of drive translation, then several
-options remain, listed below in order of popularity:
-
- - use a partition below the 1024 cyl boundary to hold the linux
- boot files (kernel images and /boot directory), and place the rest
- of linux anywhere else on the drive. These files can reside in a DOS
- partition, or in a tailor-made linux boot partition.
- - use DiskManager software from OnTrack, supplied free with
- many new hard drive purchases.
- - use EZ-Drive software (similar to DiskManager). Note though,
- that LILO must *not* use the MBR when EZ-Drive is present.
- Instead, install LILO on the first sector of your linux partition,
- and mark it as "active" or "bootable" with fdisk.
- - boot from a floppy disk instead of the hard drive (takes 10 seconds).
-
-If you cannot use drive translation, *and* your BIOS also restricts you to
-entering no more than 1024 cylinders in the geometry field in the CMOS setup,
-then just set it to 1024. As of v3.5 of this driver, Linux automatically
-determines the *real* number of cylinders for fdisk to use, allowing easy
-access to the full disk capacity without having to fiddle around.
-
-Regardless of what you do, all DOS partitions *must* be contained entirely
-within the first 1024 logical cylinders. For a 1Gig WD disk drive, here's
-a good "half and half" partitioning scheme to start with:
-
- geometry = 2100/16/63
- /dev/hda1 from cyl 1 to 992 dos
- /dev/hda2 from cyl 993 to 1023 swap
- /dev/hda3 from cyl 1024 to 2100 linux
-
-To ensure that LILO can boot linux, the boot files (kernel and /boot/*)
-must reside within the first 1024 cylinders of the drive. If your linux
-root partition is *not* completely within the first 1024 cyls (quite common),
-then you can use LILO to boot linux from files on your DOS partition
-by doing the following after installing Slackware (or whatever):
-
- 0. Boot from the "boot floppy" created during the installation
- 1. Mount your DOS partition as /dos (and stick it in /etc/fstab)
- 2. Move /boot to /dos/boot with: cp -a /boot /dos ; rm -r /boot
- 3. Create a symlink for LILO to use with: ln -s /dos/boot /boot
- 4. Move your kernel (/vmlinuz) to /boot/vmlinuz: mv /vmlinuz /boot
- 5. Edit /etc/lilo.conf to change /vmlinuz to /boot/vmlinuz
- 6. Re-run LILO with: lilo
-
- A danger with this approach is that whenever an MS-DOS "defragmentation"
- program is run (like Norton "speeddisk"), it may move the Linux boot
- files around, confusing LILO and making the (Linux) system unbootable.
- Be sure to keep a kernel "boot floppy" at hand for such circumstances.
- A possible workaround is to mark the Linux files as S+H+R (System,
- Hidden, Readonly), to prevent most defragmentation programs from
- moving the files around.
-
-If you "don't do DOS", then partition as you please, but remember to create
-a small partition to hold the /boot directory (and vmlinuz) as described above
-such that they stay within the first 1024 cylinders.
-
-Note that when creating partitions that span beyond cylinder 1024,
-Linux fdisk will complain about "Partition X has different physical/logical
-endings" and emit messages such as "This is larger than 1024, and may cause
-problems with some software". Ignore this for linux partitions. The "some
-software" refers to DOS, the BIOS, and LILO, as described previously.
-
-Western Digital ships a "DiskManager 6.03" diskette with all of their big
-hard drives. Use BIOS translation instead of this if possible, as it is a
-more generally compatible method of achieving the same results (DOS access
-to the entire disk). However, if you must use DiskManager, it now works
-with Linux 1.3.x in most cases. Let me know if you still have trouble.
-
-My recommendations to anyone who asks about NEW systems are:
-
- - buy a motherboard that uses the Intel Triton chipset -- very common.
- - use IDE for the first two drives, placing them on separate interfaces.
- - very fast 7200rpm drives are now available
- (though many problems have been reported with Seagate ones).
- - place the IDE cdrom drive as slave on either interface.
- - if additional disks are to be connected, consider your needs:
- - fileserver? Buy a SC200 SCSI adaptor for the next few drives.
- - personal system? Use IDE for the next two drives.
- - still not enough? Keep adding SC200 SCSI cards as needed.
-
-Most manufacturers make both IDE and SCSI versions of each of their drives.
-The IDE ones are usually as fast and cheaper, due to lower command overhead
-and the higher data transfer speed of UDMA2. But fast/ultrawide/superlative
-SCSI is still king of the heap, especially for servers, if you've got the bucks.
+ATAPI is currently used for controlling CDROM, TAPE and FLOPPY (ZIP or
+LS120/240) devices, removable R/W cartridges, and for high capacity hard disk
+drives.

[email protected]
--
-For current maintainers of this stuff, see the linux/MAINTAINERS file.
+Wed Apr 17 22:52:44 CEST 2002 edited by Marcin Dalecki
+
+For current maintainers of this stuff, please see the linux/MAINTAINERS file.
diff -urN linux-2.5.8/arch/cris/drivers/ide.c linux/arch/cris/drivers/ide.c
--- linux-2.5.8/arch/cris/drivers/ide.c Wed Apr 17 23:09:16 2002
+++ linux/arch/cris/drivers/ide.c Wed Apr 17 13:18:32 2002
@@ -280,7 +280,7 @@
hwif->tuneproc = &tune_e100_ide;
hwif->dmaproc = &e100_dmaproc;
hwif->ata_read = e100_ide_input_data;
- hwif->ata_write = e100_ide_input_data;
+ hwif->ata_write = e100_ide_output_data;
hwif->atapi_read = e100_atapi_read;
hwif->atapi_write = e100_atapi_write;
}
@@ -560,32 +560,6 @@
e100_atapi_write(drive, buffer, wcount << 2);
}

-/*
- * The multiplexor for ide_xxxput_data and atapi calls
- */
-static void
-e100_ideproc (ide_ide_action_t func, ide_drive_t *drive,
- void *buffer, unsigned int length)
-{
- switch (func) {
- case ideproc_ide_input_data:
- e100_ide_input_data(drive, buffer, length);
- break;
- case ideproc_ide_output_data:
- e100_ide_input_data(drive, buffer, length);
- break;
- case ideproc_atapi_read:
- e100_atapi_read(drive, buffer, length);
- break;
- case ideproc_atapi_write:
- e100_atapi_write(drive, buffer, length);
- break;
- default:
- printk("e100_ideproc: unsupported func %d!\n", func);
- break;
- }
-}
-
/* we only have one DMA channel on the chip for ATA, so we can keep these statically */
static etrax_dma_descr ata_descrs[MAX_DMA_DESCRS];
static unsigned int ata_tot_size;
diff -urN linux-2.5.8/drivers/ide/amd74xx.c linux/drivers/ide/amd74xx.c
--- linux-2.5.8/drivers/ide/amd74xx.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/amd74xx.c Wed Apr 17 18:41:36 2002
@@ -422,9 +422,10 @@
hwif->speedproc = &amd_set_drive;
hwif->autodma = 0;

+ hwif->io_32bit = 1;
+ hwif->unmask = 1;
+
for (i = 0; i < 2; i++) {
- hwif->drives[i].io_32bit = 1;
- hwif->drives[i].unmask = 1;
hwif->drives[i].autotune = 1;
hwif->drives[i].dn = hwif->unit * 2 + i;
}
diff -urN linux-2.5.8/drivers/ide/cmd640.c linux/drivers/ide/cmd640.c
--- linux-2.5.8/drivers/ide/cmd640.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/cmd640.c Wed Apr 17 23:05:54 2002
@@ -21,7 +21,7 @@
*
* [email protected], [email protected], [email protected],
* [email protected], [email protected], [email protected],
- * [email protected], [email protected],
+ * [email protected], [email protected],
* [email protected], [email protected],
* [email protected], [email protected], [email protected],
* [email protected], [email protected], [email protected],
@@ -403,19 +403,19 @@
*/
static void __init check_prefetch (unsigned int index)
{
- ide_drive_t *drive = cmd_drives[index];
+ struct ata_device *drive = cmd_drives[index];
byte b = get_cmd640_reg(prefetch_regs[index]);

if (b & prefetch_masks[index]) { /* is prefetch off? */
- drive->no_unmask = 0;
- drive->no_io_32bit = 1;
- drive->io_32bit = 0;
+ drive->channel->no_unmask = 0;
+ drive->channel->no_io_32bit = 1;
+ drive->channel->io_32bit = 0;
} else {
#if CMD640_PREFETCH_MASKS
- drive->no_unmask = 1;
- drive->unmask = 0;
+ drive->channel->no_unmask = 1;
+ drive->channel->unmask = 0;
#endif
- drive->no_io_32bit = 0;
+ drive->channel->no_io_32bit = 0;
}
}

@@ -460,15 +460,15 @@
b = get_cmd640_reg(reg);
if (mode) { /* want prefetch on? */
#if CMD640_PREFETCH_MASKS
- drive->no_unmask = 1;
- drive->unmask = 0;
+ drive->channel->no_unmask = 1;
+ drive->channel->unmask = 0;
#endif
- drive->no_io_32bit = 0;
+ drive->channel->no_io_32bit = 0;
b &= ~prefetch_masks[index]; /* enable prefetch */
} else {
- drive->no_unmask = 0;
- drive->no_io_32bit = 1;
- drive->io_32bit = 0;
+ drive->channel->no_unmask = 0;
+ drive->channel->no_io_32bit = 1;
+ drive->channel->io_32bit = 0;
b |= prefetch_masks[index]; /* disable prefetch */
}
put_cmd640_reg(reg, b);
@@ -827,7 +827,7 @@
retrieve_drive_counts (index);
check_prefetch (index);
printk("cmd640: drive%d timings/prefetch(%s) preserved",
- index, drive->no_io_32bit ? "off" : "on");
+ index, drive->channel->no_io_32bit ? "off" : "on");
display_clocks(index);
}
#else
@@ -836,7 +836,7 @@
*/
check_prefetch (index);
printk("cmd640: drive%d timings/prefetch(%s) preserved\n",
- index, drive->no_io_32bit ? "off" : "on");
+ index, drive->channel->no_io_32bit ? "off" : "on");
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
}

diff -urN linux-2.5.8/drivers/ide/dtc2278.c linux/drivers/ide/dtc2278.c
--- linux-2.5.8/drivers/ide/dtc2278.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/dtc2278.c Wed Apr 17 18:45:21 2002
@@ -88,8 +88,7 @@
/*
* 32bit I/O has to be enabled for *both* drives at the same time.
*/
- drive->io_32bit = 1;
- drive->channel->drives[!drive->select.b.unit].io_32bit = 1;
+ drive->channel->io_32bit = 1;
}

void __init init_dtc2278 (void)
@@ -120,10 +119,11 @@
ide_hwifs[0].chipset = ide_dtc2278;
ide_hwifs[1].chipset = ide_dtc2278;
ide_hwifs[0].tuneproc = &tune_dtc2278;
- ide_hwifs[0].drives[0].no_unmask = 1;
- ide_hwifs[0].drives[1].no_unmask = 1;
- ide_hwifs[1].drives[0].no_unmask = 1;
- ide_hwifs[1].drives[1].no_unmask = 1;
+ /* FIXME: What about the following?!
+ ide_hwifs[1].tuneproc = &tune_dtc2278;
+ */
+ ide_hwifs[0].no_unmask = 1;
+ ide_hwifs[1].no_unmask = 1;
ide_hwifs[0].unit = ATA_PRIMARY;
ide_hwifs[1].unit = ATA_SECONDARY;
}
diff -urN linux-2.5.8/drivers/ide/ht6560b.c linux/drivers/ide/ht6560b.c
--- linux-2.5.8/drivers/ide/ht6560b.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/ht6560b.c Wed Apr 17 18:46:13 2002
@@ -261,11 +261,11 @@
*/
if (state) {
drive->drive_data |= t; /* enable prefetch mode */
- drive->no_unmask = 1;
- drive->unmask = 0;
+ drive->channel->no_unmask = 1;
+ drive->channel->unmask = 0;
} else {
drive->drive_data &= ~t; /* disable prefetch mode */
- drive->no_unmask = 0;
+ drive->channel->no_unmask = 0;
}

restore_flags (flags); /* all CPUs */
diff -urN linux-2.5.8/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c
--- linux-2.5.8/drivers/ide/ide-cd.c Wed Apr 17 23:09:19 2002
+++ linux/drivers/ide/ide-cd.c Wed Apr 17 16:58:38 2002
@@ -669,6 +669,12 @@
request or data protect error.*/
ide_dump_status (drive, "command error", stat);
cdrom_end_request(drive, 0);
+ } else if (sense_key == MEDIUM_ERROR) {
+ /* No point in re-trying a zillion times on a bad
+ * sector. The error is not correctable at all.
+ */
+ ide_dump_status (drive, "media error (bad sector)", stat);
+ cdrom_end_request(drive, 0);
} else if ((err & ~ABRT_ERR) != 0) {
/* Go to the default handler
for other errors. */
diff -urN linux-2.5.8/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c
--- linux-2.5.8/drivers/ide/ide-disk.c Wed Apr 17 23:09:16 2002
+++ linux/drivers/ide/ide-disk.c Wed Apr 17 21:40:09 2002
@@ -755,8 +755,6 @@
drive->special.b.recalibrate = legacy;
if (OK_TO_RESET_CONTROLLER)
drive->mult_count = 0;
- if (!drive->keep_settings && !drive->using_dma)
- drive->mult_req = 0;
if (drive->mult_req != drive->mult_count)
drive->special.b.set_multmode = 1;
}
@@ -1231,7 +1229,14 @@
drive->special.b.set_multmode = 1;
#endif
}
- drive->no_io_32bit = id->dword_io ? 1 : 0;
+
+ /* FIXME: Nowadays there are many chipsets out there which *require* 32
+ * bit IO. Those will most propably not work properly with drives not
+ * supporting this. But right now we don't do anything about this. We
+ * dont' even *warn* the user!
+ */
+
+ drive->channel->no_io_32bit = id->dword_io ? 1 : 0;

if (drive->id->cfs_enable_2 & 0x3000)
write_cache(drive, (id->cfs_enable_2 & 0x3000));
diff -urN linux-2.5.8/drivers/ide/ide-taskfile.c linux/drivers/ide/ide-taskfile.c
--- linux-2.5.8/drivers/ide/ide-taskfile.c Wed Apr 17 23:09:19 2002
+++ linux/drivers/ide/ide-taskfile.c Wed Apr 17 17:55:52 2002
@@ -156,7 +156,7 @@
return;
}

- io_32bit = drive->io_32bit;
+ io_32bit = drive->channel->io_32bit;

if (io_32bit) {
#if SUPPORT_VLB_SYNC
@@ -167,7 +167,7 @@
ata_read_32(drive, buffer, wcount);
} else {
#if SUPPORT_SLOW_DATA_PORTS
- if (drive->slow)
+ if (drive->channel->slow)
ata_read_slow(drive, buffer, wcount);
else
#endif
@@ -187,7 +187,7 @@
return;
}

- io_32bit = drive->io_32bit;
+ io_32bit = drive->channel->io_32bit;

if (io_32bit) {
#if SUPPORT_VLB_SYNC
@@ -198,7 +198,7 @@
ata_write_32(drive, buffer, wcount);
} else {
#if SUPPORT_SLOW_DATA_PORTS
- if (drive->slow)
+ if (drive->channel->slow)
ata_write_slow(drive, buffer, wcount);
else
#endif
@@ -976,6 +976,7 @@
if (argbuf == NULL)
return -ENOMEM;
memcpy(argbuf, vals, 4);
+ memset(argbuf + 4, 0, argsize - 4);
}

if (set_transfer(drive, &args)) {
@@ -986,14 +987,8 @@

/* Issue ATA command and wait for completion.
*/
-
- /* FIXME: Do we really have to zero out the buffer?
- */
- memset(argbuf, 4, SECTOR_WORDS * 4 * vals[3]);
ide_init_drive_cmd(&rq);
rq.buffer = argbuf;
- memcpy(argbuf, vals, 4);
-
err = ide_do_drive_cmd(drive, &rq, ide_wait);

if (!err && xfer_rate) {
diff -urN linux-2.5.8/drivers/ide/ide.c linux/drivers/ide/ide.c
--- linux-2.5.8/drivers/ide/ide.c Wed Apr 17 23:09:19 2002
+++ linux/drivers/ide/ide.c Wed Apr 17 21:47:51 2002
@@ -479,22 +479,18 @@
if (ata_ops(drive) && ata_ops(drive)->pre_reset)
ata_ops(drive)->pre_reset(drive);

- if (!drive->keep_settings && !drive->using_dma) {
- drive->unmask = 0;
- drive->io_32bit = 0;
- }
+ if (!drive->using_dma)
+ return;

- if (drive->using_dma) {
- /* check the DMA crc count */
- if (drive->crc_count) {
- drive->channel->dmaproc(ide_dma_off_quietly, drive);
- if ((drive->channel->speedproc) != NULL)
- drive->channel->speedproc(drive, ide_auto_reduce_xfer(drive));
- if (drive->current_speed >= XFER_SW_DMA_0)
- drive->channel->dmaproc(ide_dma_on, drive);
- } else
- drive->channel->dmaproc(ide_dma_off, drive);
- }
+ /* check the DMA crc count */
+ if (drive->crc_count) {
+ drive->channel->dmaproc(ide_dma_off_quietly, drive);
+ if ((drive->channel->speedproc) != NULL)
+ drive->channel->speedproc(drive, ide_auto_reduce_xfer(drive));
+ if (drive->current_speed >= XFER_SW_DMA_0)
+ drive->channel->dmaproc(ide_dma_on, drive);
+ } else
+ drive->channel->dmaproc(ide_dma_off, drive);
}

/*
@@ -905,17 +901,15 @@
*/
static void try_to_flush_leftover_data (ide_drive_t *drive)
{
- int i = (drive->mult_count ? drive->mult_count : 1);
+ int i;

if (drive->type != ATA_DISK)
return;

- while (i > 0) {
+ for (i = (drive->mult_count ? drive->mult_count : 1); i > 0; --i) {
u32 buffer[SECTOR_WORDS];
- unsigned int count = (i > 1) ? 1 : i;

- ata_read(drive, buffer, count * SECTOR_WORDS);
- i -= count;
+ ata_read(drive, buffer, SECTOR_WORDS);
}
}

@@ -999,7 +993,7 @@
/*
* Invoked on completion of a special DRIVE_CMD.
*/
-static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
+static ide_startstop_t drive_cmd_intr(ide_drive_t *drive)
{
struct request *rq = HWGROUP(drive)->rq;
u8 *args = rq->buffer;
@@ -1008,11 +1002,7 @@

ide__sti(); /* local CPU only */
if ((stat & DRQ_STAT) && args && args[3]) {
- int io_32bit = drive->io_32bit;
-
- drive->io_32bit = 0;
ata_read(drive, &args[4], args[3] * SECTOR_WORDS);
- drive->io_32bit = io_32bit;

while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
udelay(100);
@@ -1824,7 +1814,7 @@
del_timer(&hwgroup->timer);
spin_unlock(&ide_lock);

- if (drive->unmask)
+ if (hwif->unmask)
ide__sti(); /* local CPU only */
startstop = handler(drive); /* service this interrupt, may set handler for next interrupt */
spin_lock_irq(&ide_lock);
@@ -2572,14 +2562,10 @@

static int set_io_32bit(struct ata_device *drive, int arg)
{
- if (drive->no_io_32bit)
+ if (drive->channel->no_io_32bit)
return -EIO;

- drive->io_32bit = arg;
-#ifdef CONFIG_BLK_DEV_DTC2278
- if (drive->channel->chipset == ide_dtc2278)
- drive->channel->drives[!drive->select.b.unit].io_32bit = arg;
-#endif
+ drive->channel->io_32bit = arg;

return 0;
}
@@ -2613,11 +2599,10 @@
void ide_add_generic_settings (ide_drive_t *drive)
{
/* drive setting name read/write access read ioctl write ioctl data type min max mul_factor div_factor data pointer set function */
- ide_add_setting(drive, "io_32bit", drive->no_io_32bit ? SETTING_READ : SETTING_RW, HDIO_GET_32BIT, HDIO_SET_32BIT, TYPE_BYTE, 0, 1 + (SUPPORT_VLB_SYNC << 1), 1, 1, &drive->io_32bit, set_io_32bit);
- ide_add_setting(drive, "keepsettings", SETTING_RW, HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, TYPE_BYTE, 0, 1, 1, 1, &drive->keep_settings, NULL);
+ ide_add_setting(drive, "io_32bit", drive->channel->no_io_32bit ? SETTING_READ : SETTING_RW, HDIO_GET_32BIT, HDIO_SET_32BIT, TYPE_BYTE, 0, 1 + (SUPPORT_VLB_SYNC << 1), 1, 1, &drive->channel->io_32bit, set_io_32bit);
ide_add_setting(drive, "pio_mode", SETTING_WRITE, -1, HDIO_SET_PIO_MODE, TYPE_BYTE, 0, 255, 1, 1, NULL, set_pio_mode);
- ide_add_setting(drive, "slow", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->slow, NULL);
- ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL);
+ ide_add_setting(drive, "slow", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->channel->slow, NULL);
+ ide_add_setting(drive, "unmaskirq", drive->channel->no_unmask ? SETTING_READ : SETTING_RW, HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, TYPE_BYTE, 0, 1, 1, 1, &drive->channel->unmask, NULL);
ide_add_setting(drive, "using_dma", SETTING_RW, HDIO_GET_DMA, HDIO_SET_DMA, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma);
ide_add_setting(drive, "ide_scsi", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->scsi, NULL);
ide_add_setting(drive, "init_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 69, 1, 1, &drive->init_speed, NULL);
@@ -3182,7 +3167,7 @@
drive->autotune = 2;
goto done;
case -8: /* "slow" */
- drive->slow = 1;
+ hwif->slow = 1;
goto done;
case -9: /* "flash" */
drive->ata_flash = 1;
diff -urN linux-2.5.8/drivers/ide/pdc202xx.c linux/drivers/ide/pdc202xx.c
--- linux-2.5.8/drivers/ide/pdc202xx.c Wed Apr 17 23:09:16 2002
+++ linux/drivers/ide/pdc202xx.c Wed Apr 17 19:02:12 2002
@@ -1268,11 +1268,8 @@

#undef CONFIG_PDC202XX_32_UNMASK
#ifdef CONFIG_PDC202XX_32_UNMASK
- hwif->drives[0].io_32bit = 1;
- hwif->drives[1].io_32bit = 1;
-
- hwif->drives[0].unmask = 1;
- hwif->drives[1].unmask = 1;
+ hwif->io_32bit = 1;
+ hwif->unmask = 1;
#endif

#ifdef CONFIG_BLK_DEV_IDEDMA
diff -urN linux-2.5.8/drivers/ide/pdc4030.c linux/drivers/ide/pdc4030.c
--- linux-2.5.8/drivers/ide/pdc4030.c Wed Apr 17 23:09:19 2002
+++ linux/drivers/ide/pdc4030.c Wed Apr 17 21:42:09 2002
@@ -250,11 +250,9 @@
memcpy(hwif2->io_ports, hwif->hw.io_ports, sizeof(hwif2->io_ports));
hwif2->irq = hwif->irq;
hwif2->hw.irq = hwif->hw.irq = hwif->irq;
+ hwif->io_32bit = 3;
+ hwif2->io_32bit = 3;
for (i=0; i<2 ; i++) {
- hwif->drives[i].io_32bit = 3;
- hwif2->drives[i].io_32bit = 3;
- hwif->drives[i].keep_settings = 1;
- hwif2->drives[i].keep_settings = 1;
if (!ident.current_tm[i].cyl)
hwif->drives[i].noprobe = 1;
if (!ident.current_tm[i+2].cyl)
@@ -634,7 +632,7 @@
"PROMISE_WRITE\n", drive->name);
return startstop;
}
- if (!drive->unmask)
+ if (!drive->channel->unmask)
__cli(); /* local CPU only */
HWGROUP(drive)->wrq = *rq; /* scratchpad */
return promise_write(drive);
diff -urN linux-2.5.8/drivers/ide/piix.c linux/drivers/ide/piix.c
--- linux-2.5.8/drivers/ide/piix.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/piix.c Wed Apr 17 18:54:19 2002
@@ -545,10 +545,9 @@
hwif->tuneproc = &piix_tune_drive;
hwif->speedproc = &piix_set_drive;
hwif->autodma = 0;
-
+ hwif->io_32bit = 1;
+ hwif->unmask = 1;
for (i = 0; i < 2; i++) {
- hwif->drives[i].io_32bit = 1;
- hwif->drives[i].unmask = 1;
hwif->drives[i].autotune = 1;
hwif->drives[i].dn = hwif->unit * 2 + i;
}
diff -urN linux-2.5.8/drivers/ide/qd65xx.c linux/drivers/ide/qd65xx.c
--- linux-2.5.8/drivers/ide/qd65xx.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/qd65xx.c Wed Apr 17 18:25:46 2002
@@ -370,8 +370,7 @@
hwif->config_data = config;
hwif->drives[0].drive_data =
hwif->drives[1].drive_data = QD6500_DEF_DATA;
- hwif->drives[0].io_32bit =
- hwif->drives[1].io_32bit = 1;
+ hwif->io_32bit = 1;
hwif->tuneproc = &qd6500_tune_drive;
return 1;
}
@@ -403,8 +402,7 @@
hwif->config_data = config | (control <<8);
hwif->drives[0].drive_data =
hwif->drives[1].drive_data = QD6580_DEF_DATA;
- hwif->drives[0].io_32bit =
- hwif->drives[1].io_32bit = 1;
+ hwif->io_32bit = 1;
hwif->tuneproc = &qd6580_tune_drive;

qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
@@ -426,11 +424,11 @@
ide_hwifs[i].select_data = base;
ide_hwifs[i].config_data = config | (control <<8);
ide_hwifs[i].tuneproc = &qd6580_tune_drive;
+ ide_hwifs[i].io_32bit = 1;

for (j = 0; j < 2; j++) {
ide_hwifs[i].drives[j].drive_data =
i?QD6580_DEF_DATA2:QD6580_DEF_DATA;
- ide_hwifs[i].drives[j].io_32bit = 1;
}
}

diff -urN linux-2.5.8/drivers/ide/rz1000.c linux/drivers/ide/rz1000.c
--- linux-2.5.8/drivers/ide/rz1000.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/rz1000.c Wed Apr 17 18:55:00 2002
@@ -40,8 +40,7 @@
printk("%s: disabled chipset read-ahead (buggy RZ1000/RZ1001)\n", hwif->name);
} else {
hwif->serialized = 1;
- hwif->drives[0].no_unmask = 1;
- hwif->drives[1].no_unmask = 1;
+ hwif->no_unmask = 1;
printk("%s: serialized, disabled unmasking (buggy RZ1000/RZ1001)\n", hwif->name);
}
}
diff -urN linux-2.5.8/drivers/ide/via82cxxx.c linux/drivers/ide/via82cxxx.c
--- linux-2.5.8/drivers/ide/via82cxxx.c Mon Apr 15 08:53:44 2002
+++ linux/drivers/ide/via82cxxx.c Wed Apr 17 18:55:57 2002
@@ -535,10 +535,10 @@
hwif->tuneproc = &via82cxxx_tune_drive;
hwif->speedproc = &via_set_drive;
hwif->autodma = 0;
+ hwif->io_32bit = 1;

+ hwif->unmask = (via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
for (i = 0; i < 2; i++) {
- hwif->drives[i].io_32bit = 1;
- hwif->drives[i].unmask = (via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
hwif->drives[i].autotune = 1;
hwif->drives[i].dn = hwif->unit * 2 + i;
}
diff -urN linux-2.5.8/include/linux/hdreg.h linux/include/linux/hdreg.h
--- linux-2.5.8/include/linux/hdreg.h Mon Apr 15 08:53:56 2002
+++ linux/include/linux/hdreg.h Wed Apr 17 21:40:40 2002
@@ -296,7 +296,6 @@
#define HDIO_GET_MULTCOUNT 0x0304 /* get current IDE blockmode setting */
#define HDIO_GET_QDMA 0x0305 /* get use-qdma flag */
#define HDIO_OBSOLETE_IDENTITY 0x0307 /* OBSOLETE, DO NOT USE: returns 142 bytes */
-#define HDIO_GET_KEEPSETTINGS 0x0308 /* get keep-settings-on-reset flag */
#define HDIO_GET_32BIT 0x0309 /* get current io_32bit setting */
#define HDIO_GET_NOWERR 0x030a /* get ignore-write-error flag */
#define HDIO_GET_DMA 0x030b /* get use-dma flag */
@@ -316,7 +315,6 @@
/* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */
#define HDIO_SET_MULTCOUNT 0x0321 /* change IDE blockmode */
#define HDIO_SET_UNMASKINTR 0x0322 /* permit other irqs during I/O */
-#define HDIO_SET_KEEPSETTINGS 0x0323 /* keep ioctl settings on reset */
#define HDIO_SET_32BIT 0x0324 /* change io_32bit flags */
#define HDIO_SET_NOWERR 0x0325 /* change ignore-write-error flag */
#define HDIO_SET_DMA 0x0326 /* change use-dma flag */
diff -urN linux-2.5.8/include/linux/ide.h linux/include/linux/ide.h
--- linux-2.5.8/include/linux/ide.h Wed Apr 17 23:09:19 2002
+++ linux/include/linux/ide.h Wed Apr 17 21:42:48 2002
@@ -342,12 +342,10 @@
unsigned long PADAM_timeout; /* max time to wait for irq */

special_t special; /* special action flags */
- byte keep_settings; /* restore settings after drive reset */
byte using_dma; /* disk is using dma for read/write */
byte using_tcq; /* disk is using queued dma operations*/
byte retry_pio; /* retrying dma capable host in pio */
byte state; /* retry state */
- byte unmask; /* flag: okay to unmask other irqs */
byte dsc_overlap; /* flag: DSC overlap */

unsigned waiting_for_dma: 1; /* dma currently in progress */
@@ -358,7 +356,6 @@
unsigned noprobe : 1; /* from: hdx=noprobe */
unsigned removable : 1; /* 1 if need to do check_media_change */
unsigned forced_geom : 1; /* 1 if hdx=c,h,s was given at boot */
- unsigned no_unmask : 1; /* disallow setting unmask bit */
unsigned nobios : 1; /* flag: do not probe bios for drive */
unsigned revalidate : 1; /* request revalidation */
unsigned atapi_overlap : 1; /* flag: ATAPI overlap (not supported) */
@@ -388,13 +385,6 @@
unsigned long long capacity48; /* total number of sectors */
unsigned int drive_data; /* for use by tuneproc/selectproc as needed */

- /* FIXME: Those are properties of a channel and not a drive! Move them
- * later there.
- */
- byte slow; /* flag: slow data port */
- unsigned no_io_32bit : 1; /* disallow enabling 32bit I/O */
- byte io_32bit; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
-
wait_queue_head_t wqueue; /* used to wait for drive in open() */

struct hd_driveid *id; /* drive model identification info */
@@ -523,6 +513,12 @@
unsigned autodma : 1; /* automatically try to enable DMA at boot */
unsigned udma_four : 1; /* 1=ATA-66 capable, 0=default */
unsigned highmem : 1; /* can do full 32-bit dma */
+ byte slow; /* flag: slow data port */
+ unsigned no_io_32bit : 1; /* disallow enabling 32bit I/O */
+ byte io_32bit; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
+ unsigned no_unmask : 1; /* disallow setting unmask bit */
+ byte unmask; /* flag: okay to unmask other irqs */
+
#if (DISK_RECOVERY_TIME > 0)
unsigned long last_time; /* time when previous rq was done */
#endif


Attachments:
ide-clean-38.diff (40.15 kB)

2002-04-18 10:24:41

by Martin Dalecki

[permalink] [raw]
Subject: [PATCH] 2.5.8 IDE 39

diff -urN linux-2.5.8/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c
--- linux-2.5.8/drivers/ide/ide-dma.c Wed Apr 17 23:09:19 2002
+++ linux/drivers/ide/ide-dma.c Wed Apr 17 23:28:22 2002
@@ -599,13 +599,19 @@
printk("%s: DMA disabled\n", drive->name);
case ide_dma_off_quietly:
set_high = 0;
- drive->using_tcq = 0;
outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
+#ifdef CONFIG_BLK_DEV_IDE_TCQ
+ hwif->dmaproc(ide_dma_queued_off, drive);
+#endif
case ide_dma_on:
ide_toggle_bounce(drive, set_high);
drive->using_dma = (func == ide_dma_on);
- if (drive->using_dma)
+ if (drive->using_dma) {
outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT
+ hwif->dmaproc(ide_dma_queued_on, drive);
+#endif
+ }
return 0;
case ide_dma_check:
return config_drive_for_dma (drive);
diff -urN linux-2.5.8/drivers/ide/ide-taskfile.c linux/drivers/ide/ide-taskfile.c
--- linux-2.5.8/drivers/ide/ide-taskfile.c Wed Apr 17 23:22:53 2002
+++ linux/drivers/ide/ide-taskfile.c Wed Apr 17 23:28:22 2002
@@ -413,6 +413,20 @@
struct hd_driveid *id = drive->id;
u8 HIHI = (drive->addressing) ? 0xE0 : 0xEF;

+#if 0
+ printk("ata_taskfile ... %p\n", args->handler);
+
+ printk(" sector feature %02x\n", args->taskfile.feature);
+ printk(" sector count %02x\n", args->taskfile.sector_count);
+ printk(" drive/head %02x\n", args->taskfile.device_head);
+ printk(" command %02x\n", args->taskfile.command);
+
+ if (rq)
+ printk(" rq->nr_sectors %2li\n", rq->nr_sectors);
+ else
+ printk(" rq-> = null\n");
+#endif
+
/* (ks/hs): Moved to start, do not use for multiple out commands */
if (args->handler != task_mulout_intr) {
if (IDE_CONTROL_REG)
@@ -577,18 +591,22 @@
ata_read(drive, pBuf, SECTOR_WORDS);
ide_unmap_rq(rq, pBuf, &flags);

+ /*
+ * first segment of the request is complete. note that this does not
+ * necessarily mean that the entire request is done!! this is only
+ * true if ide_end_request() returns 0.
+ */
if (--rq->current_nr_sectors <= 0) {
- /* (hs): swapped next 2 lines */
DTF("Request Ended stat: %02x\n", GET_STAT());
- if (ide_end_request(drive, 1)) {
- ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
- return ide_started;
- }
- } else {
- ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
- return ide_started;
+ if (!ide_end_request(drive, 1))
+ return ide_stopped;
}
- return ide_stopped;
+
+ /*
+ * still data left to transfer
+ */
+ ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
+ return ide_started;
}

static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq)
@@ -874,7 +892,6 @@
return;

case WIN_NOP:
-
args->command_type = IDE_DRIVE_TASK_NO_DATA;
return;

@@ -904,11 +921,6 @@
struct ata_request star;

ata_ar_init(drive, &star);
-
- /* Don't put this request on free_req list after usage.
- */
- star.ar_flags |= ATA_AR_STATIC;
-
init_taskfile_request(&rq);
rq.buffer = buf;

diff -urN linux-2.5.8/drivers/ide/ide-tcq.c linux/drivers/ide/ide-tcq.c
--- linux-2.5.8/drivers/ide/ide-tcq.c Wed Apr 17 23:09:14 2002
+++ linux/drivers/ide/ide-tcq.c Wed Apr 17 23:28:22 2002
@@ -51,21 +51,17 @@
*/
#undef IDE_TCQ_FIDDLE_SI

-/*
- * wait for data phase before starting DMA or not
- */
-#undef IDE_TCQ_WAIT_DATAPHASE
-
ide_startstop_t ide_dmaq_intr(ide_drive_t *drive);
ide_startstop_t ide_service(ide_drive_t *drive);

static inline void drive_ctl_nien(ide_drive_t *drive, int clear)
{
#ifdef IDE_TCQ_NIEN
- int mask = clear ? 0x00 : 0x02;
+ if (IDE_CONTROL_REG) {
+ int mask = clear ? 0x00 : 0x02;

- if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl | mask, IDE_CONTROL_REG);
+ }
#endif
}

@@ -123,7 +119,6 @@
init_taskfile_request(ar->ar_rq);
ar->ar_rq->rq_dev = mk_kdev(drive->channel->major, (drive->select.b.unit)<<PARTN_BITS);
ar->ar_rq->special = ar;
- ar->ar_flags |= ATA_AR_RETURN;
_elv_add_request(q, ar->ar_rq, 0, 0);

/*
@@ -222,7 +217,7 @@
{
struct ata_request *ar;
byte feat, stat;
- int tag;
+ int tag, ret;

TCQ_PRINTK("%s: started service\n", drive->name);

@@ -272,9 +267,6 @@
return ide_stopped;
}

- /*
- * start dma
- */
tag = feat >> 3;
IDE_SET_CUR_TAG(drive, tag);

@@ -293,16 +285,16 @@
*/
if (rq_data_dir(ar->ar_rq) == READ) {
TCQ_PRINTK("ide_service: starting READ %x\n", stat);
- drive->channel->dmaproc(ide_dma_read_queued, drive);
+ ret = drive->channel->dmaproc(ide_dma_read_queued, drive);
} else {
TCQ_PRINTK("ide_service: starting WRITE %x\n", stat);
- drive->channel->dmaproc(ide_dma_write_queued, drive);
+ ret = drive->channel->dmaproc(ide_dma_write_queued, drive);
}

/*
* dmaproc set intr handler
*/
- return ide_started;
+ return !ret ? ide_started : ide_stopped;
}

ide_startstop_t ide_check_service(ide_drive_t *drive)
@@ -410,14 +402,15 @@
*/
static int ide_tcq_configure(ide_drive_t *drive)
{
+ int tcq_mask = 1 << 1 | 1 << 14;
+ int tcq_bits = tcq_mask | 1 << 15;
struct ata_taskfile args;
- int tcq_supp = 1 << 1 | 1 << 14;

/*
* bit 14 and 1 must be set in word 83 of the device id to indicate
- * support for dma queued protocol
+ * support for dma queued protocol, and bit 15 must be cleared
*/
- if ((drive->id->command_set_2 & tcq_supp) != tcq_supp)
+ if ((drive->id->command_set_2 & tcq_bits) ^ tcq_mask)
return -EIO;

memset(&args, 0, sizeof(args));
@@ -477,11 +470,14 @@
*/
static int ide_enable_queued(ide_drive_t *drive, int on)
{
+ int depth = drive->using_tcq ? drive->queue_depth : 0;
+
/*
* disable or adjust queue depth
*/
if (!on) {
- printk("%s: TCQ disabled\n", drive->name);
+ if (drive->using_tcq)
+ printk("%s: TCQ disabled\n", drive->name);
drive->using_tcq = 0;
return 0;
}
@@ -491,25 +487,33 @@
return 1;
}

+ /*
+ * possibly expand command list
+ */
if (ide_build_commandlist(drive))
return 1;

- printk("%s: tagged command queueing enabled, command queue depth %d\n", drive->name, drive->queue_depth);
+ if (depth != drive->queue_depth)
+ printk("%s: tagged command queueing enabled, command queue depth %d\n", drive->name, drive->queue_depth);
+
drive->using_tcq = 1;
+
+ /*
+ * clear stats
+ */
drive->tcq->max_depth = 0;
return 0;
}

int ide_tcq_wait_dataphase(ide_drive_t *drive)
{
-#ifdef IDE_TCQ_WAIT_DATAPHASE
ide_startstop_t foo;

- if (ide_wait_stat(&startstop, drive, READY_STAT | DRQ_STAT, BUSY_STAT, WAIT_READY)) {
+ if (ide_wait_stat(&foo, drive, READY_STAT | DRQ_STAT, BUSY_STAT, WAIT_READY)) {
printk("%s: timeout waiting for data phase\n", drive->name);
return 1;
}
-#endif
+
return 0;
}

@@ -595,6 +599,8 @@
if (ide_start_dma(hwif, drive, func))
return ide_stopped;

+ TCQ_PRINTK("IMMED in queued_start\n");
+
/*
* need to arm handler before starting dma engine,
* transfer could complete right away
@@ -612,6 +618,8 @@
case ide_dma_queued_off:
enable_tcq = 0;
case ide_dma_queued_on:
+ if (enable_tcq && !drive->using_dma)
+ return 1;
return ide_enable_queued(drive, enable_tcq);
default:
break;
diff -urN linux-2.5.8/drivers/ide/ide.c linux/drivers/ide/ide.c
--- linux-2.5.8/drivers/ide/ide.c Wed Apr 17 23:22:53 2002
+++ linux/drivers/ide/ide.c Wed Apr 17 23:28:22 2002
@@ -803,8 +803,7 @@
args->hobfile.high_cylinder = IN_BYTE(IDE_HCYL_REG);
}
}
- if (ar->ar_flags & ATA_AR_RETURN)
- ata_ar_put(drive, ar);
+ ata_ar_put(drive, ar);
}

blkdev_dequeue_request(rq);
diff -urN linux-2.5.8/include/linux/ide.h linux/include/linux/ide.h
--- linux-2.5.8/include/linux/ide.h Wed Apr 17 23:22:53 2002
+++ linux/include/linux/ide.h Wed Apr 17 23:30:30 2002
@@ -968,10 +968,9 @@
/*
* ata_request flag bits
*/
-#define ATA_AR_QUEUED 1
-#define ATA_AR_SETUP 2
-#define ATA_AR_RETURN 4
-#define ATA_AR_STATIC 8
+#define ATA_AR_QUEUED 1 /* was queued */
+#define ATA_AR_SETUP 2 /* dma table mapped */
+#define ATA_AR_POOL 4 /* originated from drive pool */

/*
* if turn-around time is longer than this, halve queue depth
@@ -1003,8 +1002,10 @@

if (!list_empty(&drive->free_req)) {
ar = list_ata_entry(drive->free_req.next);
+
list_del(&ar->ar_queue);
ata_ar_init(drive, ar);
+ ar->ar_flags |= ATA_AR_POOL;
}

return ar;
@@ -1012,8 +1013,8 @@

static inline void ata_ar_put(ide_drive_t *drive, struct ata_request *ar)
{
- if (!(ar->ar_flags & ATA_AR_STATIC))
- list_add(&ar->ar_queue, &drive->free_req);
+ if (ar->ar_flags & ATA_AR_POOL)
+ list_add(&ar->ar_queue, &drive->free_req);

if (ar->ar_flags & ATA_AR_QUEUED) {
/* clear the tag */


Attachments:
ide-clean-39.diff (8.50 kB)

2002-04-18 10:48:53

by Russell King

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 38

On Thu, Apr 18, 2002 at 11:14:09AM +0200, Martin Dalecki wrote:
> @@ -523,6 +513,12 @@
> unsigned autodma : 1; /* automatically try to enable DMA at boot */
> unsigned udma_four : 1; /* 1=ATA-66 capable, 0=default */
> unsigned highmem : 1; /* can do full 32-bit dma */
> + byte slow; /* flag: slow data port */
> + unsigned no_io_32bit : 1; /* disallow enabling 32bit I/O */
> + byte io_32bit; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
> + unsigned no_unmask : 1; /* disallow setting unmask bit */
> + byte unmask; /* flag: okay to unmask other irqs */
> +

Just cosmetic... This causes the layout to be:

1 bit
1 bit
1 bit
align to word
1 byte
align to word
1 bit
align to word
1 byte
align to word
1 bit
align to word
1 byte
align to word

which is rather wasteful. Any chance you can group the bits together
and the bytes together?

--
Russell King ([email protected]) The developer of ARM Linux
http://www.arm.linux.org.uk/personal/aboutme.html

2002-04-18 10:57:02

by Martin Dalecki

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 38

Russell King wrote:
> On Thu, Apr 18, 2002 at 11:14:09AM +0200, Martin Dalecki wrote:
>
>>@@ -523,6 +513,12 @@
>> unsigned autodma : 1; /* automatically try to enable DMA at boot */
>> unsigned udma_four : 1; /* 1=ATA-66 capable, 0=default */
>> unsigned highmem : 1; /* can do full 32-bit dma */
>>+ byte slow; /* flag: slow data port */
>>+ unsigned no_io_32bit : 1; /* disallow enabling 32bit I/O */
>>+ byte io_32bit; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
>>+ unsigned no_unmask : 1; /* disallow setting unmask bit */
>>+ byte unmask; /* flag: okay to unmask other irqs */
>>+
>
>
> Just cosmetic... This causes the layout to be:
>
> 1 bit
> 1 bit
> 1 bit
> align to word
> 1 byte
> align to word
> 1 bit
> align to word
> 1 byte
> align to word
> 1 bit
> align to word
> 1 byte
> align to word
>
> which is rather wasteful. Any chance you can group the bits together
> and the bytes together?

Of course you are right. I will group them later.


2002-04-18 20:34:53

by Pavel Machek

[permalink] [raw]
Subject: eNBD on loopback [was Re: [PATCH] 2.5.8 IDE 36]

Hi!

> Btw, while I'm at it - who out there actually uses the new "enbd"
> (Enhanced NBD)? I have this feeling that that would be the better choice,
> since unlike plain nbd it should be deadlock-free on localhost (ie you
> don't need a remote machine).

How does eNBD manage to do that? It was pretty hard last time I
checked...

What if their enbd server is swapped out, and all memory is in dirty
pages waiting for writeback to eNBD?
Pavel
--
(about SSSCA) "I don't say this lightly. However, I really think that the U.S.
no longer is classifiable as a democracy, but rather as a plutocracy." --hpa

2002-04-18 20:41:00

by Linus Torvalds

[permalink] [raw]
Subject: Re: eNBD on loopback [was Re: [PATCH] 2.5.8 IDE 36]


On Thu, 18 Apr 2002, Pavel Machek wrote:
>
> > Btw, while I'm at it - who out there actually uses the new "enbd"
> > (Enhanced NBD)? I have this feeling that that would be the better choice,
> > since unlike plain nbd it should be deadlock-free on localhost (ie you
> > don't need a remote machine).
>
> How does eNBD manage to do that? It was pretty hard last time I
> checked...

Don't ask me, I'm not a user, I have just seen the patch submissions, and
I just want to get real user feedback before I'd merge a new "extended
nbd".

So far I haven't heard anything from any actual users..

Linus

2002-04-18 21:47:21

by Jehanzeb Hameed

[permalink] [raw]
Subject: regarding NFS

I was looking at the code and I couldnt find how NFS implements
inode->i_mapping->a_ops->readpage(filp,page) in
used by generic_file_read in mm/filemapc.c. All I could find was
inode->i_op->readpage(filp,page). But NFS uses generic_file_read....so how
does it work out. Kernel 2.4.17??

Jehanzeb

2002-04-19 09:37:45

by Trond Myklebust

[permalink] [raw]
Subject: Re: regarding NFS

>>>>> " " == Jehanzeb Hameed <[email protected]> writes:

> I was looking at the code and I couldnt find how NFS implements
> inode->i_mapping->a_ops->readpage(filp,page) in
> used by generic_file_read in mm/filemapc.c. All I could find
> was inode->i_op->readpage(filp,page). But NFS uses
> generic_file_read....so how does it work out. Kernel 2.4.17??

Look again: there is no such thing as readpage() in the struct
inode_operations in the 2.4.x kernels. Just grep for 'nfs_file_aops'
in the source.

Cheers,
Trond

2002-04-19 12:17:15

by Jehanzeb Hameed

[permalink] [raw]
Subject: Re: regarding NFS


> Look again: there is no such thing as readpage() in the struct
> inode_operations in the 2.4.x kernels. Just grep for 'nfs_file_aops'
> in the source.
>
> Cheers,
> Trond
>

In inode.c inside code for NFS says :
inode->i_data.a_ops = &nfs_file_aops;

it's still not "inode->i_mapping->a_ops "!!!!!!

it should, somewhere, assign something to inode->i_mapping->a_ops ?????

2002-04-19 12:25:16

by Trond Myklebust

[permalink] [raw]
Subject: Re: regarding NFS

On Friday 19. April 2002 03:19, Jehanzeb Hameed wrote:
> In inode.c inside code for NFS says :
> inode->i_data.a_ops = &nfs_file_aops;
>
> it's still not "inode->i_mapping->a_ops "!!!!!!
>
> it should, somewhere, assign something to inode->i_mapping->a_ops ?????

No. inode->i_mapping is initialized by the VFS, not the NFS client
filesystem. (see linux/fs/inode.c:clean_inode())

Cheers,
Trond

2002-04-19 13:24:04

by Jehanzeb Hameed

[permalink] [raw]
Subject: Re: regarding NFS

>
> No. inode->i_mapping is initialized by the VFS, not the NFS client
> filesystem. (see linux/fs/inode.c:clean_inode())
>
> Cheers,
> Trond
>

but then why does RAMFS assign it..??

2002-04-19 13:46:15

by Trond Myklebust

[permalink] [raw]
Subject: Re: regarding NFS

On Friday 19. April 2002 04:26, Jehanzeb Hameed wrote:
> > No. inode->i_mapping is initialized by the VFS, not the NFS client
> > filesystem. (see linux/fs/inode.c:clean_inode())
> >
> > Cheers,
> > Trond
>
> but then why does RAMFS assign it..??

I didn't do RAMFS, so I have no idea. Perhaps they figured that the effect of
the extra indirection was not too performance critical?

Cheers,
Trond

2002-04-19 17:17:57

by Peter T. Breuer

[permalink] [raw]
Subject: Re: [PATCH] 2.5.8 IDE 36

(mutters under breath .. let me put this back in the thread it came
from. Sorry. Double post for the records, with the right subject line
this time ...)

> On Tue, 16 Apr 2002, Alan Cox wrote:
> > We need to support partitioning on loopback devices in that case.
>
> No, you just need to do the loopback over nbd - you need something to do
> the byte swapping anyway (ie you can't really use the normal "loop"
> device: I really just meant the more generic "loop the data back"
> approach).
>
> nbd devices already do partitioning, I'm fairly certain.

Well, sort of. They make the right motions in the code, waving
their arms about in the right directions. It's doubtful if what's
there is enough.

> (But no, I've never tested it, obviously).

Neither have the authors.

> Btw, while I'm at it - who out there actually uses the new "enbd"
> (Enhanced NBD)? I have this feeling that that would be the better choice,
> since unlike plain nbd it should be deadlock-free on localhost (ie you
> don't need a remote machine).

No - it will deadlock the same way. The deadlock is not related to the
device driver itself. It goes like this.

kernel runs low on memory
kernel flushes buffers to device drivers under pressure
nbd client daemon sends to the net (potential conflict with tcp buffers,
but not the mechanism that hurts)
server on the _same machine_ receives request over the net
server tries to write request to disk
server process needs buffers to write to
bang (or whatever deadlock sounds like)

The enbd client has a special "-a" flag which is meant to be used in
cases where we trust the transport medium. Localhost is such a case.

With it, the protocol in the client daemon will ack the kernel _before_
it gets an ack from the remote server. That should help relieve the
deadlock. Things then go like this:

kernel runs low on memory
kernel flushes buffers to device drivers under pressure
nbd client daemon sends to the net
* client acks kernel and releases buffers in kernel
server on the _same machine_ receives request over the net
server tries to write request to disk
server process needs buffers to write to
* server gets buffers released by client in kernel

At least, potentially. If I recall right, there's still a deadlock
window in-kernel, but it's small. I don't recall the details. Oh -
well, the request still hangs around in the driver until the client
daemon acks .. maybe the client daemon can't ack without being swapped
in first, and that'd be deadlock.

Well, there's a "-s" flag (for swap devices) that does an mlockall()
that might take care of that. So "-a -s" might do it. Really needs
a "-aa" option (release write request in kernel asap).

However, a real cure would be not to use the network transport at all in
enbd. Enbd can use different transports. Instead of using the stub for
the server in the client daemon code, one could use the "fileserver"
object directly. It'd just be a question of changing the
initialization. Both have the same generic interface.

Incidentally, the newer VM code in 2.4 is a real problem for enbd.
I would ideally like _no_ _buffering_ whatsoever on the clientside.

As it is, it seems almost mandatory to raise the bdflush sync
boundary as high as possible, and to drop the async boundary really
low. One wants to start sending buffers out across the net
asynchronously as early as possible, and one never wants to go
sync. Going sync makes for a deadlock where we need to send
a request across the net in order to free a buffer, but we can't,
because we need some buffers to do that with ...

* Is there any way of turning off the VM for a single device? *

The 2.5 i/o changes, otoh, seem immensely favourable to enbd, since
it's multithreaded and asyncronous in-kernel.


Peter

2002-04-21 03:28:49

by Sean Reifschneider

[permalink] [raw]
Subject: Re: eNBD on loopback [was Re: [PATCH] 2.5.8 IDE 36]

>Don't ask me, I'm not a user, I have just seen the patch submissions, and
>I just want to get real user feedback before I'd merge a new "extended
>nbd".

I haven't used enbd, because the site was down the weekend I was evaluating
the alternatives... I did try NBD and DRBD, however. My experience was
that enbd could hardly be worse than nbd, for the following reasons:

The nbd server software referenced in the Configuration documentation
(the only I was able to find, and that only after some digging), would
fail rather quickly because the remote kernel would send a request much
larger than the server was expecting.

After a couple of days, the primary machine would just lock up when
running RAID-1 on top of the NBD.

The NBD server code is, not pretty... It sounds like that server was
written as just a hack, and really hasn't been looked at since then.

This was with kernel version 2.4.18.

DRBD is what I'm currently using and it's been running for a few weeks now
without any problems. It combines the mirroring and NBD functionality into
a single combined package. A nice feature of DRBD is that it understands
about the second node and can do things like wait for a RAID mirror to
finish before starting up other processes.

enbd has some nice features, particularly it looks like the server code
has had a lot more development in it. Particularly nice is that the
client/server will auto-negotiate an optimized mirror mode where they will
exchange MD5 sums of each block, and only transmit the block if the MD5 is
different... It switches to and from this mode automatically.

I can't really on wether enbd should be in the kernel... It can't be worse
than nbd, based on my experience. It's active development makes it a
better choice to include.

Sean
--
Fire at the celuloud factory. No film at eleven.
-- _Kentucky_Fried_Movie_
Sean Reifschneider, Inimitably Superfluous <[email protected]>
tummy.com - Linux Consulting since 1995. Qmail, KRUD, Firewalls, Python

2002-04-21 10:40:18

by Anton Altaparmakov

[permalink] [raw]
Subject: Re: eNBD on loopback [was Re: [PATCH] 2.5.8 IDE 36]

At 04:28 21/04/02, Sean Reifschneider wrote:
> >Don't ask me, I'm not a user, I have just seen the patch submissions, and
> >I just want to get real user feedback before I'd merge a new "extended
> >nbd".
>
>I haven't used enbd, because the site was down the weekend I was evaluating
>the alternatives... I did try NBD and DRBD, however. My experience was
>that enbd could hardly be worse than nbd, for the following reasons:
>
> The nbd server software referenced in the Configuration documentation
> (the only I was able to find, and that only after some digging), would
> fail rather quickly because the remote kernel would send a request much
> larger than the server was expecting.

Indeed. The source code reference in th Configuration documentation is very
much out of data and completely broken for anything that requires 64 bit
sizes on a 32 bit architecture.

This is all fixed now (I know because I shared your frustration and went
and fixed it myself (-:), if you want to get a properly working version
which exhibits no problems under very intensive i/o on a 15GiB partition
over a 100MBit lan just go to http://sf.net/projects/nbd/ and get the
latest version from CVS or download the new 2.0 release tarball.

> After a couple of days, the primary machine would just lock up when
> running RAID-1 on top of the NBD.

I haven't tried RAID... Interesting idea though.

> The NBD server code is, not pretty... It sounds like that server was
> written as just a hack, and really hasn't been looked at since then.

Yes, I had that impression, too. I hope I made the parts I touched look a
bit better. (-8

>This was with kernel version 2.4.18.

Simillar here on server side (2.4.18-pre7-ac2+misc patches).

>DRBD is what I'm currently using and it's been running for a few weeks now
>without any problems. It combines the mirroring and NBD functionality into
>a single combined package. A nice feature of DRBD is that it understands
>about the second node and can do things like wait for a RAID mirror to
>finish before starting up other processes.
>
>enbd has some nice features, particularly it looks like the server code
>has had a lot more development in it. Particularly nice is that the
>client/server will auto-negotiate an optimized mirror mode where they will
>exchange MD5 sums of each block, and only transmit the block if the MD5 is
>different... It switches to and from this mode automatically.
>
>I can't really on wether enbd should be in the kernel... It can't be worse
>than nbd, based on my experience. It's active development makes it a
>better choice to include.

nbd is also actively developed. The only problem is nobody has bothered to
update the kernel documentation to point to the website where development
happens. )-:

While we are here, I will make patches for 2.4 and 2.5 in a minute and
submit them...

Anton


--
"I've not lost my mind. It's backed up on tape somewhere." - Unknown
--
Anton Altaparmakov <aia21 at cantab.net> (replace at with @)
Linux NTFS Maintainer / IRC: #ntfs on irc.openprojects.net
WWW: http://linux-ntfs.sf.net/ & http://www-stu.christs.cam.ac.uk/~aia21/

2002-04-21 11:41:50

by Sean Reifschneider

[permalink] [raw]
Subject: Re: eNBD on loopback [was Re: [PATCH] 2.5.8 IDE 36]

On Sun, Apr 21, 2002 at 11:40:09AM +0100, Anton Altaparmakov wrote:
>I haven't tried RAID... Interesting idea though.

My use for it was in a high availability cluster, where I was using NBD to
set up shared storage between the two machines.

Another challenge I ran into, which DRBD solves well, is that it was hard
to get the RAID to operate in degraded mode. It would try to access the
block device on the first startup of the md device after the primary
failure, even if the raidtab told it the drive was dead... I finally just
set up a noop nbd server that would return the proper size on startup, but
any subsequent read/writes would fail...

>nbd is also actively developed. The only problem is nobody has bothered to
>update the kernel documentation to point to the website where development
>happens. )-:

Updates to the Configuration documentation would really help. I've asked
google to index nbd.sf.net, and also asked Alan Robertson to add it to his
list of shared storage alternatives on the linux-ha.com site. When I was
trying to get NBD going, I was unable to find nbd.sf.net through google,
though this may have changed in month since I was doing the work...

Sean
--
Got Source?
Sean Reifschneider, Inimitably Superfluous <[email protected]>
tummy.com - Linux Consulting since 1995. Qmail, KRUD, Firewalls, Python

2002-04-23 20:39:35

by Pavel Machek

[permalink] [raw]
Subject: Re: eNBD on loopback [was Re: [PATCH] 2.5.8 IDE 36]

Hi!

> > >Don't ask me, I'm not a user, I have just seen the patch submissions, and
> > >I just want to get real user feedback before I'd merge a new "extended
> > >nbd".
> >
> >I haven't used enbd, because the site was down the weekend I was evaluating
> >the alternatives... I did try NBD and DRBD, however. My experience was
> >that enbd could hardly be worse than nbd, for the following reasons:
> >
> > The nbd server software referenced in the Configuration documentation
> > (the only I was able to find, and that only after some digging), would
> > fail rather quickly because the remote kernel would send a request much
> > larger than the server was expecting.
>
> Indeed. The source code reference in th Configuration documentation is very
> much out of data and completely broken for anything that requires 64 bit
> sizes on a 32 bit architecture.

Can you submit patch to fix that docs? It should point to sourceforge..

> This is all fixed now (I know because I shared your frustration and went
> and fixed it myself (-:), if you want to get a properly working version
> which exhibits no problems under very intensive i/o on a 15GiB partition
> over a 100MBit lan just go to http://sf.net/projects/nbd/ and get the
> latest version from CVS or download the new 2.0 release tarball.
Pavel
--
Philips Velo 1: 1"x4"x8", 300gram, 60, 12MB, 40bogomips, linux, mutt,
details at http://atrey.karlin.mff.cuni.cz/~pavel/velo/index.html.