bk://gkernel.bkbits.net/libata-2.6
jgarzik@redhat.com|ChangeSet|20040427180213|50903 jgarzik

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/04/29 15:49:47-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-libata
# 
# include/linux/pci_ids.h
#   2004/04/29 15:49:44-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/04/27 14:02:13-04:00 jgarzik@redhat.com 
#   [libata sata_sx4] trivial: fix filename in header
# 
# drivers/scsi/sata_sx4.c
#   2004/04/27 14:02:07-04:00 jgarzik@redhat.com +1 -1
#   [libata sata_sx4] trivial: fix filename in header
# 
# ChangeSet
#   2004/04/26 12:41:28-04:00 akpm@osdl.org 
#   [PATCH] sata_sx4.c warning fix
#   
#   drivers/scsi/sata_sx4.c: In function `pdc20621_put_to_dimm':
#   drivers/scsi/sata_sx4.c:928: warning: comparison is always true due to limited range of data type
#   
#   The code is doing, effectively:
#   
#   	if ((long)(expr returning u32)) >= 0
#   
#   but on 64-bit architectures, that will always be true.
#   
#   So cast the u32 result to s32 before promoting to long so that bit 31
#   correctly propagates into bits 32-63.
# 
# drivers/scsi/sata_sx4.c
#   2004/04/26 02:55:02-04:00 akpm@osdl.org +1 -1
#   sata_sx4.c warning fix
# 
# ChangeSet
#   2004/04/26 12:00:03-04:00 jgarzik@redhat.com 
#   [libata] remove unused struct ata_engine
# 
# include/linux/libata.h
#   2004/04/26 11:59:58-04:00 jgarzik@redhat.com +0 -10
#   [libata] remove unused struct ata_engine
# 
# drivers/scsi/libata-core.c
#   2004/04/26 11:59:58-04:00 jgarzik@redhat.com +0 -3
#   [libata] remove unused struct ata_engine
# 
# ChangeSet
#   2004/04/26 02:09:12-04:00 jgarzik@redhat.com 
#   [libata promise] make sure our schedule_timeout(N) are never with N==0
#   
#   Make sure we delay for a minimum desired length of time.
# 
# drivers/scsi/sata_sx4.c
#   2004/04/26 02:09:07-04:00 jgarzik@redhat.com +2 -2
#   [libata promise] make sure our schedule_timeout(N) are never with N==0
#   
#   Make sure we delay for a minimum desired length of time.
# 
# drivers/scsi/sata_promise.c
#   2004/04/26 02:09:07-04:00 jgarzik@redhat.com +1 -1
#   [libata promise] make sure our schedule_timeout(N) are never with N==0
#   
#   Make sure we delay for a minimum desired length of time.
# 
# ChangeSet
#   2004/04/25 22:53:46-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-libata
# 
# include/linux/pci_ids.h
#   2004/04/25 22:53:43-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/04/26 01:36:12-04:00 jgarzik@redhat.com 
#   [libata] replace per-command semaphore with optional completion
#   
#   The semaphore was initialized and up'd for each command, but nobody
#   was listening.  Replace this with a completion, which may or may not
#   be present.
# 
# include/linux/libata.h
#   2004/04/26 01:36:07-04:00 jgarzik@redhat.com +1 -1
#   [libata] replace per-command semaphore with optional completion
#   
#   The semaphore was initialized and up'd for each command, but nobody
#   was listening.  Replace this with a completion, which may or may not
#   be present.
# 
# drivers/scsi/libata-core.c
#   2004/04/26 01:36:07-04:00 jgarzik@redhat.com +3 -2
#   [libata] replace per-command semaphore with optional completion
#   
#   The semaphore was initialized and up'd for each command, but nobody
#   was listening.  Replace this with a completion, which may or may not
#   be present.
# 
# ChangeSet
#   2004/04/26 01:15:11-04:00 jgarzik@redhat.com 
#   [libata] increase max-sectors limit for modern drives
#   
#   This is the much-discussed "speed up SATA" patch.  It limits requests
#   to 1MB as discussed, rather than the hardware maximum (32MB).
#   
#   As soon as Jens Axboe's patch to dynamically determining request
#   size is merged, max_sectors becomes what it properly should be --
#   a description of the absolute hardware maximum.
# 
# drivers/scsi/libata-scsi.c
#   2004/04/26 01:15:05-04:00 jgarzik@redhat.com +19 -0
#   [libata] increase max-sectors limit for modern drives
#   
#   This is the much-discussed "speed up SATA" patch.  It limits requests
#   to 1MB as discussed, rather than the hardware maximum (32MB).
#   
#   As soon as Jens Axboe's patch to dynamically determining request
#   size is merged, max_sectors becomes what it properly should be --
#   a description of the absolute hardware maximum.
# 
# ChangeSet
#   2004/04/26 00:54:47-04:00 jgarzik@redhat.com 
#   [libata] work queueing cleanups and fixes
#   
#   Make sure to initialize PIO data xfer state.
#   
#   Use queue_delayed_work() rather than manually calling schedule_timeout(),
#   then queue_work(), ourselves.
# 
# drivers/scsi/libata-core.c
#   2004/04/26 00:54:42-04:00 jgarzik@redhat.com +13 -13
#   [libata] work queueing cleanups and fixes
#   
#   Make sure to initialize PIO data xfer state.
#   
#   Use queue_delayed_work() rather than manually calling schedule_timeout(),
#   then queue_work(), ourselves.
# 
# ChangeSet
#   2004/04/26 00:17:47-04:00 jgarzik@redhat.com 
#   [libata] some work on the ATAPI path
#   
#   Remove a lot of redundant code in ATAPI packet submission.
#   
#   ATAPI is still disabled, it doesn't work yet.
# 
# drivers/scsi/libata-scsi.c
#   2004/04/26 00:17:42-04:00 jgarzik@redhat.com +8 -2
#   [libata] some work on the ATAPI path
#   
#   Remove a lot of redundant code in ATAPI packet submission.
#   
#   ATAPI is still disabled, it doesn't work yet.
# 
# drivers/scsi/libata-core.c
#   2004/04/26 00:17:42-04:00 jgarzik@redhat.com +11 -65
#   [libata] some work on the ATAPI path
#   
#   Remove a lot of redundant code in ATAPI packet submission.
#   
#   ATAPI is still disabled, it doesn't work yet.
# 
# ChangeSet
#   2004/04/25 23:54:36-04:00 jgarzik@redhat.com 
#   [libata] internal cleanup: kill ata_pio_start
#   
#   Integrate it into its caller.
# 
# drivers/scsi/libata-core.c
#   2004/04/25 23:54:31-04:00 jgarzik@redhat.com +5 -21
#   [libata] internal cleanup: kill ata_pio_start
#   
#   Integrate it into its caller.
# 
# ChangeSet
#   2004/04/25 23:13:39-04:00 jgarzik@redhat.com 
#   [libata] make ata_wq workqueue local to libata-core module
#   
#   Now that libata-scsi module no longer calls queue_work() directly,
#   we can localize the use of ata_wq.
# 
# drivers/scsi/libata.h
#   2004/04/25 23:13:34-04:00 jgarzik@redhat.com +0 -2
#   [libata] make ata_wq workqueue local to libata-core module
#   
#   Now that libata-scsi module no longer calls queue_work() directly,
#   we can localize the use of ata_wq.
# 
# drivers/scsi/libata-scsi.c
#   2004/04/25 23:13:34-04:00 jgarzik@redhat.com +0 -1
#   [libata] make ata_wq workqueue local to libata-core module
#   
#   Now that libata-scsi module no longer calls queue_work() directly,
#   we can localize the use of ata_wq.
# 
# drivers/scsi/libata-core.c
#   2004/04/25 23:13:34-04:00 jgarzik@redhat.com +1 -1
#   [libata] make ata_wq workqueue local to libata-core module
#   
#   Now that libata-scsi module no longer calls queue_work() directly,
#   we can localize the use of ata_wq.
# 
# ChangeSet
#   2004/04/25 23:05:58-04:00 jgarzik@redhat.com 
#   [libata] move ATAPI command initiation code from libata-scsi to libata-core
# 
# drivers/scsi/libata.h
#   2004/04/25 23:05:53-04:00 jgarzik@redhat.com +1 -0
#   [libata] move ATAPI command initiation code from libata-scsi to libata-core
# 
# drivers/scsi/libata-scsi.c
#   2004/04/25 23:05:53-04:00 jgarzik@redhat.com +4 -46
#   [libata] move ATAPI command initiation code from libata-scsi to libata-core
# 
# drivers/scsi/libata-core.c
#   2004/04/25 23:05:53-04:00 jgarzik@redhat.com +53 -0
#   [libata] move ATAPI command initiation code from libata-scsi to libata-core
# 
# ChangeSet
#   2004/04/25 21:47:36-04:00 jgarzik@redhat.com 
#   [libata] move probe execution from katad thread to workqueue thread
#   
#   This allows us to kill the katad thread itself, and several
#   thread-related variables in struct ata_port.
# 
# include/linux/libata.h
#   2004/04/25 21:47:31-04:00 jgarzik@redhat.com +2 -6
#   [libata] move probe execution from katad thread to workqueue thread
#   
#   This allows us to kill the katad thread itself, and several
#   thread-related variables in struct ata_port.
# 
# drivers/scsi/libata.h
#   2004/04/25 21:47:31-04:00 jgarzik@redhat.com +0 -1
#   [libata] move probe execution from katad thread to workqueue thread
#   
#   This allows us to kill the katad thread itself, and several
#   thread-related variables in struct ata_port.
# 
# drivers/scsi/libata-core.c
#   2004/04/25 21:47:31-04:00 jgarzik@redhat.com +20 -137
#   [libata] move probe execution from katad thread to workqueue thread
#   
#   This allows us to kill the katad thread itself, and several
#   thread-related variables in struct ata_port.
# 
# ChangeSet
#   2004/04/25 20:18:57-04:00 jgarzik@redhat.com 
#   [libata] move PIO data xfer from katad thread to workqueue thread
# 
# include/linux/libata.h
#   2004/04/25 20:18:52-04:00 jgarzik@redhat.com +15 -7
#   [libata] move PIO data xfer from katad thread to workqueue thread
# 
# drivers/scsi/libata-core.c
#   2004/04/25 20:18:52-04:00 jgarzik@redhat.com +73 -63
#   [libata] move PIO data xfer from katad thread to workqueue thread
# 
# ChangeSet
#   2004/04/25 19:28:29-04:00 jgarzik@redhat.com 
#   [libata] move ATAPI startup from katad thread to workqueue thread
#   
#   libata creates one thread per ata_port structure.  This is inadequate
#   for our needs, and also cumbersome to maintain, now that workqueues
#   and Rusty's thread work is available.
#   
#   This patch begins to move libata away from doing its own per-port
#   thread, by moving the ATAPI command initiation code to work under
#   the workqueue system.
#   
#   This patch also creates a private workqueue, global to all of libata.
# 
# include/linux/libata.h
#   2004/04/25 19:28:23-04:00 jgarzik@redhat.com +3 -1
#   [libata] move ATAPI startup from katad thread to workqueue thread
#   
#   libata creates one thread per ata_port structure.  This is inadequate
#   for our needs, and also cumbersome to maintain, now that workqueues
#   and Rusty's thread work is available.
#   
#   This patch begins to move libata away from doing its own per-port
#   thread, by moving the ATAPI command initiation code to work under
#   the workqueue system.
#   
#   This patch also creates a private workqueue, global to all of libata.
# 
# drivers/scsi/libata.h
#   2004/04/25 19:28:23-04:00 jgarzik@redhat.com +1 -0
#   [libata] move ATAPI startup from katad thread to workqueue thread
#   
#   libata creates one thread per ata_port structure.  This is inadequate
#   for our needs, and also cumbersome to maintain, now that workqueues
#   and Rusty's thread work is available.
#   
#   This patch begins to move libata away from doing its own per-port
#   thread, by moving the ATAPI command initiation code to work under
#   the workqueue system.
#   
#   This patch also creates a private workqueue, global to all of libata.
# 
# drivers/scsi/libata-scsi.c
#   2004/04/25 19:28:23-04:00 jgarzik@redhat.com +3 -2
#   [libata] move ATAPI startup from katad thread to workqueue thread
#   
#   libata creates one thread per ata_port structure.  This is inadequate
#   for our needs, and also cumbersome to maintain, now that workqueues
#   and Rusty's thread work is available.
#   
#   This patch begins to move libata away from doing its own per-port
#   thread, by moving the ATAPI command initiation code to work under
#   the workqueue system.
#   
#   This patch also creates a private workqueue, global to all of libata.
# 
# drivers/scsi/libata-core.c
#   2004/04/25 19:28:23-04:00 jgarzik@redhat.com +22 -12
#   [libata] move ATAPI startup from katad thread to workqueue thread
#   
#   libata creates one thread per ata_port structure.  This is inadequate
#   for our needs, and also cumbersome to maintain, now that workqueues
#   and Rusty's thread work is available.
#   
#   This patch begins to move libata away from doing its own per-port
#   thread, by moving the ATAPI command initiation code to work under
#   the workqueue system.
#   
#   This patch also creates a private workqueue, global to all of libata.
# 
# ChangeSet
#   2004/04/24 22:15:40-04:00 jeremy@sgi.com 
#   [PATCH] sata_vsc initialization fix
# 
# drivers/scsi/sata_vsc.c
#   2004/04/22 15:14:14-04:00 jeremy@sgi.com +4 -0
#   sata_vsc initialization fix
# 
# ChangeSet
#   2004/04/24 14:12:03-04:00 jgarzik@redhat.com 
#   [libata] clean up taskfile submission to hardware
#   
#   When writing taskfile (an ATA command) to the controller, the exact
#   setup of the taskfile is dependent on the taskfile "protocol":
#   PIO, PIO Multiple, DMA, Non-data, etc.
#   
#   So, we separate out the submission of the taskfile to hardware into
#   a separate function ata_qc_issue_prot(), which will later be the
#   home for more code.
#   
#   Also, remove some dead code (#if 0'd).
# 
# include/linux/libata.h
#   2004/04/24 14:11:58-04:00 jgarzik@redhat.com +0 -1
#   [libata] clean up taskfile submission to hardware
#   
#   When writing taskfile (an ATA command) to the controller, the exact
#   setup of the taskfile is dependent on the taskfile "protocol":
#   PIO, PIO Multiple, DMA, Non-data, etc.
#   
#   So, we separate out the submission of the taskfile to hardware into
#   a separate function ata_qc_issue_prot(), which will later be the
#   home for more code.
#   
#   Also, remove some dead code (#if 0'd).
# 
# drivers/scsi/libata-core.c
#   2004/04/24 14:11:58-04:00 jgarzik@redhat.com +53 -56
#   [libata] clean up taskfile submission to hardware
#   
#   When writing taskfile (an ATA command) to the controller, the exact
#   setup of the taskfile is dependent on the taskfile "protocol":
#   PIO, PIO Multiple, DMA, Non-data, etc.
#   
#   So, we separate out the submission of the taskfile to hardware into
#   a separate function ata_qc_issue_prot(), which will later be the
#   home for more code.
#   
#   Also, remove some dead code (#if 0'd).
# 
# ChangeSet
#   2004/04/24 13:26:06-04:00 jgarzik@redhat.com 
#   [libata] add ata_tf_{to,from}_fis helpers
# 
# include/linux/libata.h
#   2004/04/24 13:26:01-04:00 jgarzik@redhat.com +2 -0
#   [libata] add ata_tf_{to,from}_fis helpers
# 
# drivers/scsi/libata-core.c
#   2004/04/24 13:26:01-04:00 jgarzik@redhat.com +73 -0
#   [libata] add ata_tf_{to,from}_fis helpers
# 
# ChangeSet
#   2004/04/22 03:43:42-04:00 jgarzik@redhat.com 
#   [libata] Promise driver split part 4: common header
# 
# drivers/scsi/sata_sx4.c
#   2004/04/22 03:43:37-04:00 jgarzik@redhat.com +1 -124
#   [libata] Promise driver split part 4: common header
# 
# drivers/scsi/sata_promise.c
#   2004/04/22 03:43:37-04:00 jgarzik@redhat.com +2 -125
#   [libata] Promise driver split part 4: common header
# 
# drivers/scsi/Kconfig
#   2004/04/22 03:43:37-04:00 jgarzik@redhat.com +1 -1
#   [libata] Promise driver split part 4: common header
# 
# drivers/scsi/sata_promise.h
#   2004/04/22 03:39:42-04:00 jgarzik@redhat.com +154 -0
# 
# drivers/scsi/sata_promise.h
#   2004/04/22 03:39:42-04:00 jgarzik@redhat.com +0 -0
#   BitKeeper file /spare/repo/libata-2.6/drivers/scsi/sata_promise.h
# 
# ChangeSet
#   2004/04/22 03:37:49-04:00 jgarzik@redhat.com 
#   [libata] Promise driver split part 3: remove TX2/4 code from sata_sx4
# 
# drivers/scsi/sata_sx4.c
#   2004/04/22 03:37:44-04:00 jgarzik@redhat.com +26 -333
#   [libata] Promise driver split part 3: remove TX2/4 code from sata_sx4
# 
# ChangeSet
#   2004/04/22 03:26:15-04:00 jgarzik@redhat.com 
#   [libata] Promise driver split part 2: remove SX4 code from sata_promise
# 
# drivers/scsi/sata_promise.c
#   2004/04/22 03:26:10-04:00 jgarzik@redhat.com +7 -1106
#   [libata] Promise driver split part 2: remove SX4 code from sata_promise
# 
# ChangeSet
#   2004/04/22 03:11:44-04:00 jgarzik@redhat.com 
#   [libata] Promise driver split part 1: clone to sx4
#   
#   Clone sata_promise to sata_sx4.
# 
# drivers/scsi/Makefile
#   2004/04/22 03:11:39-04:00 jgarzik@redhat.com +1 -0
#   [libata] Promise driver split part 1: clone to sx4
#   
#   Clone sata_promise to sata_sx4.
# 
# drivers/scsi/Kconfig
#   2004/04/22 03:11:39-04:00 jgarzik@redhat.com +10 -2
#   [libata] Promise driver split part 1: clone to sx4
#   
#   Clone sata_promise to sata_sx4.
# 
# drivers/scsi/sata_sx4.c
#   2004/04/22 03:06:00-04:00 jgarzik@redhat.com +0 -0
#   bk cp drivers/scsi/sata_promise.c drivers/scsi/sata_sx4.c
# 
# ChangeSet
#   2004/04/22 00:51:41-04:00 jgarzik@redhat.com 
#   [libata sata_sis] add new PCI id
#   
#   Also remove constant from linux/pci_ids.h.
# 
# include/linux/pci_ids.h
#   2004/04/22 00:49:04-04:00 jgarzik@redhat.com +0 -1
#   [libata sata_sis] add new PCI id
#   
#   Also remove constant from linux/pci_ids.h.
# 
# drivers/scsi/sata_sis.c
#   2004/04/22 00:49:04-04:00 jgarzik@redhat.com +2 -1
#   [libata sata_sis] add new PCI id
#   
#   Also remove constant from linux/pci_ids.h.
# 
# drivers/scsi/sata_sx4.c
#   2004/04/14 17:04:43-04:00 jgarzik@redhat.com +2 -2
#   [libata sata_promise] fix taskfile delivery cases
#   
#   We should only be touching the ATA shadow registers if we are doing
#   PIO.
# 
# drivers/scsi/sata_sx4.c
#   2004/03/26 20:40:53-05:00 jgarzik@redhat.com +66 -17
#   [libata sata_promise] better locking and error handling
#   
#   * Prefer spin_lock() to spin_lock_irq() in interrupt handler
#   * Reset each port, before probing the SATA phy
#   * Reset port when every time an error occurs
# 
# drivers/scsi/sata_sx4.c
#   2004/03/26 01:13:16-05:00 jgarzik@redhat.com +15 -22
#   [libata sata_promise] minor initialization updates
#   
#   * remove incorrect PATA port check
#   * enable undocumented bit 13 in flash control register,
#     because the Promise driver does so.
#   * wait 10 ms after setting TBG mode, for the same reason.
# 
# drivers/scsi/sata_sx4.c
#   2004/03/25 01:44:03-05:00 jgarzik@redhat.com +24 -29
#   [libata] consolidate data transfer mode handling
#   
#   The various ways you can send data to/from your ATA device is
#   known as the ATA taskfile protocol:  PIO single sector, PIO
#   multiple sector, DMA, DMA TCQ, DMA NCQ, ...
#   
#   Prior to this change, the data direction (read/write) was encoded
#   implicitly into the ATA_PROT_xxx value itself.  This increased
#   complexity in some areas, and inhibited flexibility in others.
#   
#   This change separates data direction from taskfile protocol, and also
#   moves the data direction flag (ATA_QCFLAG_WRITE) down to a lower
#   level (ATA_TFLAG_WRITE).
# 
# drivers/scsi/sata_sx4.c
#   2004/03/24 23:50:29-05:00 jgarzik@redhat.com +20 -1
#   [libata sata_promise] check for PATA port on PDC20375
#   
#   We don't handle it yet, but this prints out a message in its presence,
#   permitting verification of the check and informing users why their
#   PATA device is not recognized.
# 
# drivers/scsi/sata_sx4.c
#   2004/03/18 17:55:44-05:00 jgarzik@redhat.com +3 -0
#   [libata] explicitly set consistent DMA mask to 0xffffffff
#   
#   Do not rely on the default being 0xffffffff.
# 
# drivers/scsi/sata_sx4.c
#   2004/03/18 13:22:43-05:00 jgarzik@redhat.com +0 -1
#   [libata] remove unneeded linux/config.h includes
# 
# drivers/scsi/sata_sx4.c
#   2004/03/18 05:34:59-05:00 jgarzik@redhat.com +0 -2
#   [libata] API cleanup
#   
#   Remove ->phy_config hook, everybody used pata_phy_config.  Rename
#   function to ata_set_mode, and directly call internally.
# 
# drivers/scsi/sata_sx4.c
#   2004/03/12 21:28:52-05:00 jgarzik@redhat.com +1 -7
#   [libata] clean up module_init() hook of sata_{promise,sil,svw} drivers
#   
#   The more verbose form existed for decreased differences with the 2.4
#   backport.  But differences in this area existed anyway, so why not
#   clean up the 2.6 versions even more.
# 
# drivers/scsi/sata_sx4.c
#   2004/03/10 21:36:23-05:00 jgarzik@redhat.com +0 -21
#   [libata] make set_{pio,udma}mode hooks optional
#   
#   Only one driver actually uses them.
# 
# drivers/scsi/sata_sx4.c
#   2004/03/09 07:14:51-05:00 jeremy@sgi.com +4 -1
#   [libata] Split up shared IO register locations into individual components
#   
#   Most ATA host controllers follow a standard layout for the
#   ATA shadow registers, where command/status, error/feature, and
#   devctl/altstatus share a single bus I/O address, because one register
#   of each pair is read-only, and the other is write-only.
#   
#   On the Vitesse/Intel chip, all registers are given distinction bus I/O
#   addresses, which necessitates changing the libata data structures
#   to cope with this.  This simply involves storing a few more bus addresses.
# 
# drivers/scsi/sata_sx4.c
#   2004/03/08 22:33:20-05:00 jgarzik@redhat.com +9 -1
#   [libata sata_promise] provide proper SCSI completion function
#   
#   Promise driver uses a custom error handling function, so we need
#   the fix that was applied to the libata core:  the SCSI error
#   handling thread requires that we complete commands using a special
#   completion function, since the normal one doesn't work inside
#   the error handling thread.
# 
# drivers/scsi/sata_sx4.c
#   2004/02/26 21:23:26-05:00 jgarzik@redhat.com +1 -1
#   [libata] limit S/G table size to 128 entries
#   
#   Agreeing with Ben H's recommendation, I reduce the max-hw-segments
#   number to 128, to match max-phys-segments number.  This shouldn't
#   affect performance because 128*64K is far above the max transfer size
#   for most current IDE devices.  Even 128*4K is OK.
# 
# drivers/scsi/sata_sx4.c
#   2004/02/25 18:29:10-05:00 jgarzik@redhat.com +1 -1
#   [libata] bump versions
# 
# drivers/scsi/sata_sx4.c
#   2004/02/25 18:26:06-05:00 dmilburn@redhat.com +57 -1
#   [libata sata_promise] Fix DIMM initialization on PCI-X bus
# 
# drivers/scsi/sata_sx4.c
#   2004/02/13 13:07:29-05:00 jgarzik@redhat.com +1 -1
#   Bump libata, ata_piix to version 1.0.
#   
#   Also update copyrights for 2004.
# 
# drivers/scsi/sata_sx4.c
#   2003/12/17 17:35:39-05:00 jgarzik@redhat.com +35 -12
#   [libata promise] fix another ugly bug
#   
#   For the SX4, only one Host DMA (local DIMM) engine is on the hardware,
#   while there is an ATA engine for each SATA port.  This means that
#   Host DMA transactions must be queued.  When previously fixing this problem
#   (the driver had previously assumed an HDMA engine per port), I stored
#   the HDMA packet queue in a per-port data structure.
#   
#   This was incorrect:  this patch changes it to correctly use a
#   per-host data structure, not a per-port structure.
# 
# drivers/scsi/sata_sx4.c
#   2003/12/16 19:16:55-05:00 Michael_E_Brown@Dell.com +1 -0
#   [libata] fake geometry for partition tables / setups that need such
# 
# drivers/scsi/sata_sx4.c
#   2003/12/05 13:41:01-05:00 jgarzik@redhat.com +413 -3
#   [libata promise] Properly initialize DIMM, on SX4
#   
#   On-board DIMM should be sized and initialized by the driver.  Previously,
#   a single DIMM size was simply (and incorrectly) assumed, and
#   initialization was presumed to have been done by the card's BIOS.
#   
#   Contributed by Promise, updated by David Milburn @ Red Hat.
# 
# drivers/scsi/sata_sx4.c
#   2003/11/30 11:56:01-05:00 grundler@parisc-linux.org +2 -2
#   [libata] use sg_dma_xxx macros
#   
#   Fixes build on some platforms, fixes issues on others.
# 
# drivers/scsi/sata_sx4.c
#   2003/11/26 16:10:43-05:00 jgarzik@redhat.com +71 -53
#   [libata] Fix PDC20621: we only have one Host DMA engine, not one per port
#   
#   Whoops.  So, we need to queue HDMA transactions internally.
# 
# drivers/scsi/sata_sx4.c
#   2003/11/14 19:52:35-05:00 pp@ee.oulu.fi +2 -0
#   [libata] add Promise PCI id
# 
# drivers/scsi/sata_sx4.c
#   2003/11/10 10:41:07-05:00 jgarzik@redhat.com +26 -11
#   [libata promise] fixes suggested by Promise
#   
#   * flush host FIFO after sending data to DIMM window
#   * don't set SCR addresses, as the hardware doesn't have SCRs
#     (cosmetic)
# 
# drivers/scsi/sata_sx4.c
#   2003/11/07 16:24:15-05:00 jgarzik@redhat.com +11 -1
#   [libata] fix Promise PCI posting bugs
# 
# drivers/scsi/sata_sx4.c
#   2003/11/06 13:31:55-05:00 jgarzik@redhat.com +3 -3
#   [libata] fix ugly Promise interrupt masking bug
# 
# drivers/scsi/sata_sx4.c
#   2003/10/31 09:55:43-05:00 jgarzik@redhat.com +2 -0
#   [libata] add Promise SATA pci id
# 
# drivers/scsi/sata_sx4.c
#   2003/10/28 11:04:25-05:00 jgarzik@redhat.com +56 -15
#   [libata] Add paranoia checks/settings suggested by Promise
# 
# drivers/scsi/sata_sx4.c
#   2003/10/23 19:27:35-04:00 jgarzik@redhat.com +5 -3
#   [libata] PDC20621 hdma fixes
# 
# drivers/scsi/sata_sx4.c
#   2003/10/22 22:26:51-04:00 jgarzik@redhat.com +2 -2
#   [libata] fix Promise build on older compilers
# 
# drivers/scsi/sata_sx4.c
#   2003/10/22 18:02:58-04:00 jgarzik@redhat.com +231 -79
#   [libata] more pdc20621 work
# 
# drivers/scsi/sata_sx4.c
#   2003/10/22 12:33:27-04:00 jgarzik@redhat.com +346 -80
#   [libata] fill in a lot more Promise PDC20621 support
# 
# drivers/scsi/sata_sx4.c
#   2003/10/22 01:05:47-04:00 jgarzik@redhat.com +102 -44
#   [libata] convert Promise to packetized DMA
# 
# drivers/scsi/sata_sx4.c
#   2003/10/21 23:13:53-04:00 jgarzik@redhat.com +4 -0
#   [libata] add per-driver port init/shutdown hooks, with helper defaults
# 
# drivers/scsi/sata_sx4.c
#   2003/10/21 19:21:36-04:00 jgarzik@redhat.com +766 -0
# 
# drivers/scsi/sata_sx4.c
#   2003/10/21 19:21:36-04:00 jgarzik@redhat.com +0 -0
#   BitKeeper file /spare/repo/libata-2.5-merge/drivers/scsi/sata_promise.c
# 
diff -Nru a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
--- a/drivers/scsi/Kconfig	Tue May  4 22:11:45 2004
+++ b/drivers/scsi/Kconfig	Tue May  4 22:11:45 2004
@@ -434,10 +434,18 @@
 	  If unsure, say N.
 
 config SCSI_SATA_PROMISE
-	tristate "Promise SATA support"
+	tristate "Promise SATA TX2/TX4 support"
+	depends on SCSI_SATA && PCI
+	help
+	  This option enables support for Promise Serial ATA TX2/TX4.
+
+	  If unsure, say N.
+
+config SCSI_SATA_SX4
+	tristate "Promise SATA SX4 support"
 	depends on SCSI_SATA && PCI && EXPERIMENTAL
 	help
-	  This option enables support for Promise Serial ATA.
+	  This option enables support for Promise Serial ATA SX4.
 
 	  If unsure, say N.
 
diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile
--- a/drivers/scsi/Makefile	Tue May  4 22:11:45 2004
+++ b/drivers/scsi/Makefile	Tue May  4 22:11:45 2004
@@ -124,6 +124,7 @@
 obj-$(CONFIG_SCSI_SATA_VIA)	+= libata.o sata_via.o
 obj-$(CONFIG_SCSI_SATA_VITESSE)	+= libata.o sata_vsc.o
 obj-$(CONFIG_SCSI_SATA_SIS)	+= libata.o sata_sis.o
+obj-$(CONFIG_SCSI_SATA_SX4)	+= libata.o sata_sx4.o
 
 obj-$(CONFIG_ARM)		+= arm/
 
diff -Nru a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
--- a/drivers/scsi/libata-core.c	Tue May  4 22:11:45 2004
+++ b/drivers/scsi/libata-core.c	Tue May  4 22:11:45 2004
@@ -34,7 +34,9 @@
 #include <linux/delay.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
+#include <linux/completion.h>
 #include <linux/suspend.h>
+#include <linux/workqueue.h>
 #include <scsi/scsi.h>
 #include "scsi.h"
 #include "hosts.h"
@@ -44,14 +46,10 @@
 
 #include "libata.h"
 
-static void atapi_cdb_send(struct ata_port *ap);
 static unsigned int ata_busy_sleep (struct ata_port *ap,
 				    unsigned long tmout_pat,
 			    	    unsigned long tmout);
 static void __ata_dev_select (struct ata_port *ap, unsigned int device);
-#if 0 /* to be used eventually */
-static void ata_qc_push (struct ata_queued_cmd *qc, unsigned int append);
-#endif
 static void ata_dma_complete(struct ata_port *ap, u8 host_stat,
 			     unsigned int done_late);
 static void ata_host_set_pio(struct ata_port *ap);
@@ -59,8 +57,10 @@
 static void ata_dev_set_pio(struct ata_port *ap, unsigned int device);
 static void ata_dev_set_udma(struct ata_port *ap, unsigned int device);
 static void ata_set_mode(struct ata_port *ap);
+static int ata_qc_issue_prot(struct ata_queued_cmd *qc);
 
 static unsigned int ata_unique_id = 1;
+static struct workqueue_struct *ata_wq;
 
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("Library module for ATA devices");
@@ -74,13 +74,6 @@
 	"THR_IDLE",
 	"THR_PROBE_SUCCESS",
 	"THR_PROBE_START",
-	"THR_PIO_POLL",
-	"THR_PIO_TMOUT",
-	"THR_PIO",
-	"THR_PIO_LAST",
-	"THR_PIO_LAST_POLL",
-	"THR_PIO_ERR",
-	"THR_PACKET",
 };
 
 /**
@@ -315,8 +308,6 @@
 
 static void ata_tf_to_host(struct ata_port *ap, struct ata_taskfile *tf)
 {
-	init_MUTEX_LOCKED(&ap->sem);
-
 	ap->ops->tf_load(ap, tf);
 
 	ata_exec(ap, tf);
@@ -337,8 +328,6 @@
 
 void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf)
 {
-	init_MUTEX_LOCKED(&ap->sem);
-
 	ap->ops->tf_load(ap, tf);
 	ap->ops->exec_command(ap, tf);
 }
@@ -440,6 +429,77 @@
 }
 
 /**
+ *	ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
+ *	@tf: Taskfile to convert
+ *	@fis: Buffer into which data will output
+ *
+ *	Converts a standard ATA taskfile to a Serial ATA
+ *	FIS structure (Register - Host to Device).
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp)
+{
+	fis[0] = 0x27;	/* Register - Host to Device FIS */
+	fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number,
+					    bit 7 indicates Command FIS */
+	fis[2] = tf->command;
+	fis[3] = tf->feature;
+
+	fis[4] = tf->lbal;
+	fis[5] = tf->lbam;
+	fis[6] = tf->lbah;
+	fis[7] = tf->device;
+
+	fis[8] = tf->hob_lbal;
+	fis[9] = tf->hob_lbam;
+	fis[10] = tf->hob_lbah;
+	fis[11] = tf->hob_feature;
+
+	fis[12] = tf->nsect;
+	fis[13] = tf->hob_nsect;
+	fis[14] = 0;
+	fis[15] = tf->ctl;
+
+	fis[16] = 0;
+	fis[17] = 0;
+	fis[18] = 0;
+	fis[19] = 0;
+}
+
+/**
+ *	ata_tf_from_fis - Convert SATA FIS to ATA taskfile
+ *	@fis: Buffer from which data will be input
+ *	@tf: Taskfile to output
+ *
+ *	Converts a standard ATA taskfile to a Serial ATA
+ *	FIS structure (Register - Host to Device).
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf)
+{
+	tf->command	= fis[2];	/* status */
+	tf->feature	= fis[3];	/* error */
+
+	tf->lbal	= fis[4];
+	tf->lbam	= fis[5];
+	tf->lbah	= fis[6];
+	tf->device	= fis[7];
+
+	tf->hob_lbal	= fis[8];
+	tf->hob_lbam	= fis[9];
+	tf->hob_lbah	= fis[10];
+
+	tf->nsect	= fis[12];
+	tf->hob_nsect	= fis[13];
+}
+
+/**
  *	ata_prot_to_cmd - determine which read/write opcodes to use
  *	@protocol: ATA_PROT_xxx taskfile protocol
  *	@lba48: true is lba48 is present
@@ -1928,20 +1988,20 @@
 static unsigned long ata_pio_poll(struct ata_port *ap)
 {
 	u8 status;
-	unsigned int poll_state = THR_UNKNOWN;
-	unsigned int reg_state = THR_UNKNOWN;
-	const unsigned int tmout_state = THR_PIO_TMOUT;
-
-	switch (ap->thr_state) {
-	case THR_PIO:
-	case THR_PIO_POLL:
-		poll_state = THR_PIO_POLL;
-		reg_state = THR_PIO;
-		break;
-	case THR_PIO_LAST:
-	case THR_PIO_LAST_POLL:
-		poll_state = THR_PIO_LAST_POLL;
-		reg_state = THR_PIO_LAST;
+	unsigned int poll_state = PIO_ST_UNKNOWN;
+	unsigned int reg_state = PIO_ST_UNKNOWN;
+	const unsigned int tmout_state = PIO_ST_TMOUT;
+
+	switch (ap->pio_task_state) {
+	case PIO_ST:
+	case PIO_ST_POLL:
+		poll_state = PIO_ST_POLL;
+		reg_state = PIO_ST;
+		break;
+	case PIO_ST_LAST:
+	case PIO_ST_LAST_POLL:
+		poll_state = PIO_ST_LAST_POLL;
+		reg_state = PIO_ST_LAST;
 		break;
 	default:
 		BUG();
@@ -1950,39 +2010,19 @@
 
 	status = ata_chk_status(ap);
 	if (status & ATA_BUSY) {
-		if (time_after(jiffies, ap->thr_timeout)) {
-			ap->thr_state = tmout_state;
+		if (time_after(jiffies, ap->pio_task_timeout)) {
+			ap->pio_task_state = tmout_state;
 			return 0;
 		}
-		ap->thr_state = poll_state;
+		ap->pio_task_state = poll_state;
 		return ATA_SHORT_PAUSE;
 	}
 
-	ap->thr_state = reg_state;
+	ap->pio_task_state = reg_state;
 	return 0;
 }
 
 /**
- *	ata_pio_start -
- *	@qc:
- *
- *	LOCKING:
- *	spin_lock_irqsave(host_set lock)
- */
-
-static void ata_pio_start (struct ata_queued_cmd *qc)
-{
-	struct ata_port *ap = qc->ap;
-
-	assert(qc->tf.protocol == ATA_PROT_PIO);
-
-	qc->flags |= ATA_QCFLAG_POLL;
-	qc->tf.ctl |= ATA_NIEN;	/* disable interrupts */
-	ata_tf_to_host_nolock(ap, &qc->tf);
-	ata_thread_wake(ap, THR_PIO);
-}
-
-/**
  *	ata_pio_complete -
  *	@ap:
  *
@@ -1992,7 +2032,6 @@
 static void ata_pio_complete (struct ata_port *ap)
 {
 	struct ata_queued_cmd *qc;
-	unsigned long flags;
 	u8 drv_stat;
 
 	/*
@@ -2001,31 +2040,29 @@
 	 * a chk-status or two.  If not, the drive is probably seeking
 	 * or something.  Snooze for a couple msecs, then
 	 * chk-status again.  If still busy, fall back to
-	 * THR_PIO_POLL state.
+	 * PIO_ST_POLL state.
 	 */
 	drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
 	if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
 		msleep(2);
 		drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
 		if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
-			ap->thr_state = THR_PIO_LAST_POLL;
-			ap->thr_timeout = jiffies + ATA_TMOUT_PIO;
+			ap->pio_task_state = PIO_ST_LAST_POLL;
+			ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
 			return;
 		}
 	}
 
 	drv_stat = ata_wait_idle(ap);
 	if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
-		ap->thr_state = THR_PIO_ERR;
+		ap->pio_task_state = PIO_ST_ERR;
 		return;
 	}
 
 	qc = ata_qc_from_tag(ap, ap->active_tag);
 	assert(qc != NULL);
 
-	spin_lock_irqsave(&ap->host_set->lock, flags);
-	ap->thr_state = THR_IDLE;
-	spin_unlock_irqrestore(&ap->host_set->lock, flags);
+	ap->pio_task_state = PIO_ST_IDLE;
 
 	ata_irq_on(ap);
 
@@ -2053,22 +2090,22 @@
 	 * a chk-status or two.  If not, the drive is probably seeking
 	 * or something.  Snooze for a couple msecs, then
 	 * chk-status again.  If still busy, fall back to
-	 * THR_PIO_POLL state.
+	 * PIO_ST_POLL state.
 	 */
 	status = ata_busy_wait(ap, ATA_BUSY, 5);
 	if (status & ATA_BUSY) {
 		msleep(2);
 		status = ata_busy_wait(ap, ATA_BUSY, 10);
 		if (status & ATA_BUSY) {
-			ap->thr_state = THR_PIO_POLL;
-			ap->thr_timeout = jiffies + ATA_TMOUT_PIO;
+			ap->pio_task_state = PIO_ST_POLL;
+			ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
 			return;
 		}
 	}
 
 	/* handle BSY=0, DRQ=0 as error */
 	if ((status & ATA_DRQ) == 0) {
-		ap->thr_state = THR_PIO_ERR;
+		ap->pio_task_state = PIO_ST_ERR;
 		return;
 	}
 
@@ -2079,7 +2116,7 @@
 	sg = qc->sg;
 
 	if (qc->cursect == (qc->nsect - 1))
-		ap->thr_state = THR_PIO_LAST;
+		ap->pio_task_state = PIO_ST_LAST;
 
 	buf = kmap(sg[qc->cursg].page) +
 	      sg[qc->cursg].offset + (qc->cursg_ofs * ATA_SECT_SIZE);
@@ -2107,20 +2144,48 @@
 	kunmap(sg[qc->cursg].page);
 }
 
-#if 0 /* to be used eventually */
-/**
- *	ata_eng_schedule - run an iteration of the pio/dma/whatever engine
- *	@ap: port on which activity will occur
- *	@eng: instance of engine
- *
- *	LOCKING:
- *	spin_lock_irqsave(host_set lock)
- */
-static void ata_eng_schedule (struct ata_port *ap, struct ata_engine *eng)
+static void ata_pio_task(void *_data)
 {
-	/* FIXME */
+	struct ata_port *ap = _data;
+	unsigned long timeout = 0;
+
+	switch (ap->pio_task_state) {
+	case PIO_ST:
+		ata_pio_sector(ap);
+		break;
+
+	case PIO_ST_LAST:
+		ata_pio_complete(ap);
+		break;
+
+	case PIO_ST_POLL:
+	case PIO_ST_LAST_POLL:
+		timeout = ata_pio_poll(ap);
+		break;
+
+	case PIO_ST_TMOUT:
+		printk(KERN_ERR "ata%d: FIXME: PIO_ST_TMOUT\n", /* FIXME */
+		       ap->id);
+		timeout = 11 * HZ;
+		break;
+
+	case PIO_ST_ERR:
+		printk(KERN_ERR "ata%d: FIXME: PIO_ST_ERR\n", /* FIXME */
+		       ap->id);
+		timeout = 11 * HZ;
+		break;
+	}
+
+	if ((ap->pio_task_state != PIO_ST_IDLE) &&
+	    (ap->pio_task_state != PIO_ST_TMOUT) &&
+	    (ap->pio_task_state != PIO_ST_ERR)) {
+		if (timeout)
+			queue_delayed_work(ata_wq, &ap->pio_task,
+					   timeout);
+		else
+			queue_work(ata_wq, &ap->pio_task);
+	}
 }
-#endif
 
 /**
  *	ata_eng_timeout - Handle timeout of queued command
@@ -2246,8 +2311,6 @@
 		qc->ap = ap;
 		qc->dev = dev;
 		qc->cursect = qc->cursg = qc->cursg_ofs = 0;
-		INIT_LIST_HEAD(&qc->node);
-		init_MUTEX_LOCKED(&qc->sem);
 
 		ata_tf_init(ap, &qc->tf, dev->devno);
 
@@ -2304,52 +2367,33 @@
 		do_clear = 1;
 	}
 
-	up(&qc->sem);
+	if (qc->waiting)
+		complete(qc->waiting);
 
 	if (likely(do_clear))
 		clear_bit(tag, &ap->qactive);
 }
 
-#if 0 /* to be used eventually */
 /**
- *	ata_qc_push -
- *	@qc:
- *	@append:
+ *	ata_qc_issue - issue taskfile to device
+ *	@qc: command to issue to device
  *
- *	LOCKING:
- *	spin_lock_irqsave(host_set lock)
- */
-static void ata_qc_push (struct ata_queued_cmd *qc, unsigned int append)
-{
-	struct ata_port *ap = qc->ap;
-	struct ata_engine *eng = &ap->eng;
-
-	if (likely(append))
-		list_add_tail(&qc->node, &eng->q);
-	else
-		list_add(&qc->node, &eng->q);
-
-	if (!test_and_set_bit(ATA_EFLG_ACTIVE, &eng->flags))
-		ata_eng_schedule(ap, eng);
-}
-#endif
-
-/**
- *	ata_qc_issue -
- *	@qc:
+ *	Prepare an ATA command to submission to device.
+ *	This includes mapping the data into a DMA-able
+ *	area, filling in the S/G table, and finally
+ *	writing the taskfile to hardware, starting the command.
  *
  *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
  *
  *	RETURNS:
- *
+ *	Zero on success, negative on error.
  */
+
 int ata_qc_issue(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	struct scsi_cmnd *cmd = qc->scsicmd;
-	unsigned int dma = qc->flags & ATA_QCFLAG_DMA;
-
-	ata_dev_select(ap, qc->dev->devno, 1, 0);
 
 	/* set up SG table */
 	if (cmd->use_sg) {
@@ -2365,20 +2409,61 @@
 	qc->ap->active_tag = qc->tag;
 	qc->flags |= ATA_QCFLAG_ACTIVE;
 
-	if (likely(dma)) {
-		ap->ops->tf_load(ap, &qc->tf);	/* load tf registers */
-		ap->ops->bmdma_start(qc);	/* initiate bmdma */
-	} else
-		/* load tf registers, initiate polling pio */
-		ata_pio_start(qc);
-
-	return 0;
+	return ata_qc_issue_prot(qc);
 
 err_out:
 	return -1;
 }
 
 /**
+ *	ata_qc_issue_prot - issue taskfile to device in proto-dependent manner
+ *	@qc: command to issue to device
+ *
+ *	Using various libata functions and hooks, this function
+ *	starts an ATA command.  ATA commands are grouped into
+ *	classes called "protocols", and issuing each type of protocol
+ *	is slightly different.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Zero on success, negative on error.
+ */
+
+static int ata_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+
+	ata_dev_select(ap, qc->dev->devno, 1, 0);
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_NODATA:
+		ata_tf_to_host_nolock(ap, &qc->tf);
+		break;
+
+	case ATA_PROT_DMA:
+		ap->ops->tf_load(ap, &qc->tf);	 /* load tf registers */
+		ap->ops->bmdma_start(qc);	    /* initiate bmdma */
+		break;
+
+	case ATA_PROT_PIO: /* load tf registers, initiate polling pio */
+		qc->flags |= ATA_QCFLAG_POLL;
+		qc->tf.ctl |= ATA_NIEN;	/* disable interrupts */
+		ata_tf_to_host_nolock(ap, &qc->tf);
+		ap->pio_task_state = PIO_ST;
+		queue_work(ata_wq, &ap->pio_task);
+		break;
+
+	default:
+		WARN_ON(1);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
  *	ata_bmdma_start_mmio -
  *	@qc:
  *
@@ -2614,36 +2699,6 @@
 }
 
 /**
- *	ata_thread_wake -
- *	@ap:
- *	@thr_state:
- *
- *	LOCKING:
- *	spin_lock_irqsave(host_set lock)
- */
-
-void ata_thread_wake(struct ata_port *ap, unsigned int thr_state)
-{
-	assert(ap->thr_state == THR_IDLE);
-	ap->thr_state = thr_state;
-	up(&ap->thr_sem);
-}
-
-/**
- *	ata_thread_timer -
- *	@opaque:
- *
- *	LOCKING:
- */
-
-static void ata_thread_timer(unsigned long opaque)
-{
-	struct ata_port *ap = (struct ata_port *) opaque;
-
-	up(&ap->thr_sem);
-}
-
-/**
  *	ata_thread_iter -
  *	@ap:
  *
@@ -2666,7 +2721,6 @@
 		break;
 
 	case THR_PROBE_START:
-		down(&ap->sem);
 		ap->thr_state = THR_PORT_RESET;
 		break;
 
@@ -2685,40 +2739,8 @@
 		break;
 
 	case THR_AWAIT_DEATH:
-		timeout = -1;
-		break;
-
 	case THR_IDLE:
-		timeout = 30 * HZ;
-		break;
-
-	case THR_PIO:
-		ata_pio_sector(ap);
-		break;
-
-	case THR_PIO_LAST:
-		ata_pio_complete(ap);
-		break;
-
-	case THR_PIO_POLL:
-	case THR_PIO_LAST_POLL:
-		timeout = ata_pio_poll(ap);
-		break;
-
-	case THR_PIO_TMOUT:
-		printk(KERN_ERR "ata%d: FIXME: THR_PIO_TMOUT\n", /* FIXME */
-		       ap->id);
-		timeout = 11 * HZ;
-		break;
-
-	case THR_PIO_ERR:
-		printk(KERN_ERR "ata%d: FIXME: THR_PIO_ERR\n", /* FIXME */
-		       ap->id);
-		timeout = 11 * HZ;
-		break;
-
-	case THR_PACKET:
-		atapi_cdb_send(ap);
+		timeout = -1;
 		break;
 
 	default:
@@ -2732,87 +2754,23 @@
 	return timeout;
 }
 
-/**
- *	ata_thread -
- *	@data:
- *
- *	LOCKING:
- *
- *	RETURNS:
- *
- */
-
-static int ata_thread (void *data)
+void atapi_start(struct ata_queued_cmd *qc)
 {
-        struct ata_port *ap = data;
-	long timeout;
-
-	daemonize ("katad-%u", ap->id);
-	allow_signal(SIGTERM);
-
-        while (1) {
-		cond_resched();
-
-		timeout = ata_thread_iter(ap);
-
-                if (signal_pending (current))
-                        flush_signals(current);
-                        
-                if (current->flags & PF_FREEZE)
-			refrigerator(PF_FREEZE);
-                                                        
-
-                if ((timeout < 0) || (ap->time_to_die))
-                        break;
-
- 		/* note sleeping for full timeout not guaranteed (that's ok) */
-		if (timeout) {
-			mod_timer(&ap->thr_timer, jiffies + timeout);
-			down_interruptible(&ap->thr_sem);
-
-                	if (signal_pending (current))
-                        	flush_signals(current);
-
-                	if (ap->time_to_die)
-                        	break;
-		}
-        }
-
-	printk(KERN_DEBUG "ata%u: thread exiting\n", ap->id);
-	ap->thr_pid = -1;
-	del_timer_sync(&ap->thr_timer);
-	complete_and_exit (&ap->thr_exited, 0);
-}
-
-/**
- *	ata_thread_kill - kill per-port kernel thread
- *	@ap: port those thread is to be killed
- *
- *	LOCKING:
- *
- */
+	struct ata_port *ap = qc->ap;
 
-static int ata_thread_kill(struct ata_port *ap)
-{
-	int ret = 0;
+	qc->flags |= ATA_QCFLAG_ACTIVE;
+	ap->active_tag = qc->tag;
 
-	if (ap->thr_pid >= 0) {
-		ap->time_to_die = 1;
-		wmb();
-		ret = kill_proc(ap->thr_pid, SIGTERM, 1);
-		if (ret)
-			printk(KERN_ERR "ata%d: unable to kill kernel thread\n",
-			       ap->id);
-		else
-			wait_for_completion(&ap->thr_exited);
-	}
+	ata_dev_select(ap, qc->dev->devno, 1, 0);
+	ata_tf_to_host_nolock(ap, &qc->tf);
+	queue_work(ata_wq, &ap->packet_task);
 
-	return ret;
+	VPRINTK("EXIT\n");
 }
 
 /**
- *	atapi_cdb_send - Write CDB bytes to hardware
- *	@ap: Port to which ATAPI device is attached.
+ *	atapi_packet_task - Write CDB bytes to hardware
+ *	@_data: Port to which ATAPI device is attached.
  *
  *	When device has indicated its readiness to accept
  *	a CDB, this function is called.  Send the CDB.
@@ -2824,8 +2782,9 @@
  *	Kernel thread context (may sleep)
  */
 
-static void atapi_cdb_send(struct ata_port *ap)
+static void atapi_packet_task(void *_data)
 {
+	struct ata_port *ap = _data;
 	struct ata_queued_cmd *qc;
 	u8 status;
 
@@ -2850,30 +2809,17 @@
 	      qc->scsicmd->cmnd, ap->host->max_cmd_len / 4);
 
 	/* if we are DMA'ing, irq handler takes over from here */
-	if (qc->tf.feature == ATAPI_PKT_DMA)
-		goto out;
-
-	/* sleep-wait for BSY to clear */
-	DPRINTK("busy wait 2\n");
-	if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB))
-		goto err_out;
-
-	/* wait for BSY,DRQ to clear */
-	status = ata_wait_idle(ap);
-	if (status & (ATA_BUSY | ATA_DRQ))
-		goto err_out;
-
-	/* transaction completed, indicate such to scsi stack */
-	ata_qc_complete(qc, status, 0);
-	ata_irq_on(ap);
+	if (qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
+		/* FIXME: start DMA here */
+	} else {
+		ap->pio_task_state = PIO_ST;
+		queue_work(ata_wq, &ap->pio_task);
+	}
 
-out:
-	ap->thr_state = THR_IDLE;
 	return;
 
 err_out:
 	ata_qc_complete(qc, ATA_ERR, 0);
-	goto out;
 }
 
 int ata_port_start (struct ata_port *ap)
@@ -2883,7 +2829,7 @@
 	ap->prd = pci_alloc_consistent(pdev, ATA_PRD_TBL_SZ, &ap->prd_dma);
 	if (!ap->prd)
 		return -ENOMEM;
-	
+
 	DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, (unsigned long long) ap->prd_dma);
 
 	return 0;
@@ -2896,6 +2842,21 @@
 	pci_free_consistent(pdev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
 }
 
+static void ata_probe_task(void *_data)
+{
+	struct ata_port *ap = _data;
+	long timeout;
+
+	timeout = ata_thread_iter(ap);
+	if (timeout < 0)
+		return;
+
+	if (timeout > 0)
+		queue_delayed_work(ata_wq, &ap->probe_task, timeout);
+	else
+		queue_work(ata_wq, &ap->probe_task);
+}
+
 /**
  *	ata_host_remove -
  *	@ap:
@@ -2913,8 +2874,6 @@
 	if (do_unregister)
 		scsi_remove_host(sh);
 
-	ata_thread_kill(ap);	/* FIXME: check return val */
-
 	ap->ops->port_stop(ap);
 }
 
@@ -2958,21 +2917,14 @@
 	ap->active_tag = ATA_TAG_POISON;
 	ap->last_ctl = 0xFF;
 
-	/* ata_engine init */
-	ap->eng.flags = 0;
-	INIT_LIST_HEAD(&ap->eng.q);
+	INIT_WORK(&ap->packet_task, atapi_packet_task, ap);
+	INIT_WORK(&ap->pio_task, ata_pio_task, ap);
+	INIT_WORK(&ap->probe_task, ata_probe_task, ap);
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++)
 		ap->device[i].devno = i;
 
-	init_completion(&ap->thr_exited);
 	init_MUTEX_LOCKED(&ap->probe_sem);
-	init_MUTEX_LOCKED(&ap->sem);
-	init_MUTEX_LOCKED(&ap->thr_sem);
-
-	init_timer(&ap->thr_timer);
-	ap->thr_timer.function = ata_thread_timer;
-	ap->thr_timer.data = (unsigned long) ap;
 
 #ifdef ATA_IRQ_TRAP
 	ap->stats.unhandled_irq = 1;
@@ -3015,18 +2967,8 @@
 	if (rc)
 		goto err_out;
 
-	ap->thr_pid = kernel_thread(ata_thread, ap, CLONE_FS | CLONE_FILES);
-	if (ap->thr_pid < 0) {
-		printk(KERN_ERR "ata%d: unable to start kernel thread\n",
-		       ap->id);
-		goto err_out_free;
-	}
-
 	return ap;
 
-err_out_free:
-	ap->ops->port_stop(ap);
-
 err_out:
 	scsi_host_put(host);
 	return NULL;
@@ -3106,7 +3048,7 @@
 		ap = host_set->ports[i];
 
 		DPRINTK("ata%u: probe begin\n", ap->id);
-		up(&ap->sem);		/* start probe */
+		queue_work(ata_wq, &ap->probe_task);	/* start probe */
 
 		DPRINTK("ata%u: probe-wait begin\n", ap->id);
 		down(&ap->probe_sem);	/* wait for end */
@@ -3489,11 +3431,21 @@
 
 static int __init ata_init(void)
 {
+	ata_wq = create_workqueue("ata");
+	if (!ata_wq)
+		return -ENOMEM;
+
 	printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
 	return 0;
 }
 
+static void __exit ata_exit(void)
+{
+	destroy_workqueue(ata_wq);
+}
+
 module_init(ata_init);
+module_exit(ata_exit);
 
 /*
  * libata is essentially a library of internal helper functions for
@@ -3512,6 +3464,8 @@
 EXPORT_SYMBOL_GPL(ata_tf_load_mmio);
 EXPORT_SYMBOL_GPL(ata_tf_read_pio);
 EXPORT_SYMBOL_GPL(ata_tf_read_mmio);
+EXPORT_SYMBOL_GPL(ata_tf_to_fis);
+EXPORT_SYMBOL_GPL(ata_tf_from_fis);
 EXPORT_SYMBOL_GPL(ata_check_status_pio);
 EXPORT_SYMBOL_GPL(ata_check_status_mmio);
 EXPORT_SYMBOL_GPL(ata_exec_command_pio);
diff -Nru a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
--- a/drivers/scsi/libata-scsi.c	Tue May  4 22:11:45 2004
+++ b/drivers/scsi/libata-scsi.c	Tue May  4 22:11:45 2004
@@ -167,8 +167,27 @@
 {
 	sdev->use_10_for_rw = 1;
 	sdev->use_10_for_ms = 1;
+
 	blk_queue_max_phys_segments(sdev->request_queue, LIBATA_MAX_PRD);
 
+	if (sdev->id < ATA_MAX_DEVICES) {
+		struct ata_port *ap;
+		struct ata_device *dev;
+
+		ap = (struct ata_port *) &sdev->host->hostdata[0];
+		dev = &ap->device[sdev->id];
+
+		/* TODO: 1024 is an arbitrary number, not the
+		 * hardware maximum.  This should be increased to
+		 * 65534 when Jens Axboe's patch for dynamically
+		 * determining max_sectors is merged.
+		 */
+		if (dev->flags & ATA_DFLAG_LBA48) {
+			sdev->host->max_sectors = 2048;
+			blk_queue_max_sectors(sdev->request_queue, 2048);
+		}
+	}
+
 	return 0;	/* scsi layer doesn't check return value, sigh */
 }
 
@@ -884,8 +903,7 @@
 			       struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
 	struct ata_queued_cmd *qc;
-	u8 *scsicmd = cmd->cmnd, status;
-	unsigned int doing_dma = 0;
+	u8 *scsicmd = cmd->cmnd;
 
 	VPRINTK("ENTER, drv_stat = 0x%x\n", ata_chk_status(ap));
 
@@ -925,52 +943,17 @@
 
 	qc->tf.command = ATA_CMD_PACKET;
 
-	/* set up SG table */
 	if (cmd->sc_data_direction == SCSI_DATA_NONE) {
-		ap->active_tag = qc->tag;
-		qc->flags |= ATA_QCFLAG_ACTIVE | ATA_QCFLAG_POLL;
 		qc->tf.protocol = ATA_PROT_ATAPI;
-
-		ata_dev_select(ap, dev->devno, 1, 0);
-
-		DPRINTK("direction: none\n");
+		qc->flags |= ATA_QCFLAG_POLL;
 		qc->tf.ctl |= ATA_NIEN;	/* disable interrupts */
-		ata_tf_to_host_nolock(ap, &qc->tf);
 	} else {
-		qc->flags |= ATA_QCFLAG_SG; /* data is present; dma-map it */
-		qc->tf.feature = ATAPI_PKT_DMA;
 		qc->tf.protocol = ATA_PROT_ATAPI_DMA;
-
-		doing_dma = 1;
-
-		/* select device, send command to hardware */
-		if (ata_qc_issue(qc))
-			goto err_out;
-	}
-
-	status = ata_busy_wait(ap, ATA_BUSY, 1000);
-	if (status & ATA_BUSY) {
-		ata_thread_wake(ap, THR_PACKET);
-		return;
+		qc->flags |= ATA_QCFLAG_SG; /* data is present; dma-map it */
+		qc->tf.feature |= ATAPI_PKT_DMA;
 	}
-	if ((status & ATA_DRQ) == 0)
-		goto err_out;
 
-	/* FIXME: mmio-ize */
-	DPRINTK("writing cdb\n");
-	outsl(ap->ioaddr.data_addr, scsicmd, ap->host->max_cmd_len / 4);
-
-	if (!doing_dma)
-		ata_thread_wake(ap, THR_PACKET);
-
-	VPRINTK("EXIT\n");
-	return;
-
-err_out:
-	if (!doing_dma)
-		ata_irq_on(ap);	/* re-enable interrupts */
-	ata_bad_cdb(cmd, done);
-	DPRINTK("EXIT - badcmd\n");
+	atapi_start(qc);
 }
 
 /**
diff -Nru a/drivers/scsi/libata.h b/drivers/scsi/libata.h
--- a/drivers/scsi/libata.h	Tue May  4 22:11:45 2004
+++ b/drivers/scsi/libata.h	Tue May  4 22:11:45 2004
@@ -35,7 +35,6 @@
 	void			(*done)(struct scsi_cmnd *);
 };
 
-
 /* libata-core.c */
 extern void ata_dev_id_string(struct ata_device *dev, unsigned char *s,
 			      unsigned int ofs, unsigned int len);
@@ -45,7 +44,7 @@
 extern void ata_dev_select(struct ata_port *ap, unsigned int device,
                            unsigned int wait, unsigned int can_sleep);
 extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf);
-extern void ata_thread_wake(struct ata_port *ap, unsigned int thr_state);
+extern void atapi_start(struct ata_queued_cmd *qc);
 
 
 /* libata-scsi.c */
diff -Nru a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
--- a/drivers/scsi/sata_promise.c	Tue May  4 22:11:45 2004
+++ b/drivers/scsi/sata_promise.c	Tue May  4 22:11:45 2004
@@ -33,16 +33,14 @@
 #include "hosts.h"
 #include <linux/libata.h>
 #include <asm/io.h>
+#include "sata_promise.h"
 
 #define DRV_NAME	"sata_promise"
-#define DRV_VERSION	"0.92"
+#define DRV_VERSION	"1.00"
 
 
 enum {
-	PDC_PRD_TBL		= 0x44,	/* Direct command DMA table addr */
-
 	PDC_PKT_SUBMIT		= 0x40, /* Command packet pointer addr */
-	PDC_HDMA_PKT_SUBMIT	= 0x100, /* Host DMA packet pointer addr */
 	PDC_INT_SEQMASK		= 0x40,	/* Mask of asserted SEQ INTs */
 	PDC_TBG_MODE		= 0x41,	/* TBG mode */
 	PDC_FLASH_CTL		= 0x44, /* Flash control register */
@@ -51,141 +49,38 @@
 	PDC_CTLSTAT		= 0x60,	/* IDE control and status (per port) */
 	PDC_SATA_PLUG_CSR	= 0x6C, /* SATA Plug control/status reg */
 	PDC_SLEW_CTL		= 0x470, /* slew rate control reg */
-	PDC_HDMA_CTLSTAT	= 0x12C, /* Host DMA control / status */
-
-	PDC_20621_SEQCTL	= 0x400,
-	PDC_20621_SEQMASK	= 0x480,
-	PDC_20621_GENERAL_CTL	= 0x484,
-	PDC_20621_PAGE_SIZE	= (32 * 1024),
-
-	/* chosen, not constant, values; we design our own DIMM mem map */
-	PDC_20621_DIMM_WINDOW	= 0x0C,	/* page# for 32K DIMM window */
-	PDC_20621_DIMM_BASE	= 0x00200000,
-	PDC_20621_DIMM_DATA	= (64 * 1024),
-	PDC_DIMM_DATA_STEP	= (256 * 1024),
-	PDC_DIMM_WINDOW_STEP	= (8 * 1024),
-	PDC_DIMM_HOST_PRD	= (6 * 1024),
-	PDC_DIMM_HOST_PKT	= (128 * 0),
-	PDC_DIMM_HPKT_PRD	= (128 * 1),
-	PDC_DIMM_ATA_PKT	= (128 * 2),
-	PDC_DIMM_APKT_PRD	= (128 * 3),
-	PDC_DIMM_HEADER_SZ	= PDC_DIMM_APKT_PRD + 128,
-	PDC_PAGE_WINDOW		= 0x40,
-	PDC_PAGE_DATA		= PDC_PAGE_WINDOW +
-				  (PDC_20621_DIMM_DATA / PDC_20621_PAGE_SIZE),
-	PDC_PAGE_SET		= PDC_DIMM_DATA_STEP / PDC_20621_PAGE_SIZE,
-
-	PDC_CHIP0_OFS		= 0xC0000, /* offset of chip #0 */
 
-	PDC_20621_ERR_MASK	= (1<<19) | (1<<20) | (1<<21) | (1<<22) |
-				  (1<<23),
 	PDC_ERR_MASK		= (1<<19) | (1<<20) | (1<<21) | (1<<22) |
 				  (1<<8) | (1<<9) | (1<<10),
 
 	board_2037x		= 0,	/* FastTrak S150 TX2plus */
 	board_20319		= 1,	/* FastTrak S150 TX4 */
-	board_20621		= 2,	/* FastTrak S150 SX4 */
 
 	PDC_HAS_PATA		= (1 << 1), /* PDC20375 has PATA */
 
-	PDC_FLAG_20621		= (1 << 30), /* we have a 20621 */
 	PDC_RESET		= (1 << 11), /* HDMA reset */
-
-	PDC_MAX_HDMA		= 32,
-	PDC_HDMA_Q_MASK		= (PDC_MAX_HDMA - 1),
-
-	PDC_DIMM0_SPD_DEV_ADDRESS     = 0x50,
-	PDC_DIMM1_SPD_DEV_ADDRESS     = 0x51,
-	PDC_MAX_DIMM_MODULE           = 0x02,
-	PDC_I2C_CONTROL_OFFSET        = 0x48,
-	PDC_I2C_ADDR_DATA_OFFSET      = 0x4C,
-	PDC_DIMM0_CONTROL_OFFSET      = 0x80,
-	PDC_DIMM1_CONTROL_OFFSET      = 0x84,
-	PDC_SDRAM_CONTROL_OFFSET      = 0x88,
-	PDC_I2C_WRITE                 = 0x00000000,
-	PDC_I2C_READ                  = 0x00000040,	
-	PDC_I2C_START                 = 0x00000080,
-	PDC_I2C_MASK_INT              = 0x00000020,
-	PDC_I2C_COMPLETE              = 0x00010000,
-	PDC_I2C_NO_ACK                = 0x00100000,
-	PDC_DIMM_SPD_SUBADDRESS_START = 0x00,
-	PDC_DIMM_SPD_SUBADDRESS_END   = 0x7F,
-	PDC_DIMM_SPD_ROW_NUM          = 3,
-	PDC_DIMM_SPD_COLUMN_NUM       = 4,
-	PDC_DIMM_SPD_MODULE_ROW       = 5,
-	PDC_DIMM_SPD_TYPE             = 11,
-	PDC_DIMM_SPD_FRESH_RATE       = 12,         
-	PDC_DIMM_SPD_BANK_NUM         = 17,	
-	PDC_DIMM_SPD_CAS_LATENCY      = 18,
-	PDC_DIMM_SPD_ATTRIBUTE        = 21,    
-	PDC_DIMM_SPD_ROW_PRE_CHARGE   = 27,
-	PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28,      
-	PDC_DIMM_SPD_RAS_CAS_DELAY    = 29,
-	PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30,
-	PDC_DIMM_SPD_SYSTEM_FREQ      = 126,
-	PDC_CTL_STATUS		      = 0x08,	
-	PDC_DIMM_WINDOW_CTLR	      = 0x0C,
-	PDC_TIME_CONTROL              = 0x3C,
-	PDC_TIME_PERIOD               = 0x40,
-	PDC_TIME_COUNTER              = 0x44,
-	PDC_GENERAL_CTLR	      = 0x484,
-	PCI_PLL_INIT                  = 0x8A531824,
-	PCI_X_TCOUNT                  = 0xEE1E5CFF
 };
 
 
 struct pdc_port_priv {
-	u8			dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512];
 	u8			*pkt;
 	dma_addr_t		pkt_dma;
 };
 
-struct pdc_host_priv {
-	void			*dimm_mmio;
-
-	unsigned int		doing_hdma;
-	unsigned int		hdma_prod;
-	unsigned int		hdma_cons;
-	struct {
-		struct ata_queued_cmd *qc;
-		unsigned int	seq;
-		unsigned long	pkt_ofs;
-	} hdma[32];
-};
-
-
 static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static void pdc_dma_start(struct ata_queued_cmd *qc);
-static void pdc20621_dma_start(struct ata_queued_cmd *qc);
 static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
-static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
 static void pdc_eng_timeout(struct ata_port *ap);
-static void pdc_20621_phy_reset (struct ata_port *ap);
 static int pdc_port_start(struct ata_port *ap);
 static void pdc_port_stop(struct ata_port *ap);
 static void pdc_phy_reset(struct ata_port *ap);
 static void pdc_fill_sg(struct ata_queued_cmd *qc);
-static void pdc20621_fill_sg(struct ata_queued_cmd *qc);
 static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf);
 static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf);
-static void pdc20621_host_stop(struct ata_host_set *host_set);
 static inline void pdc_dma_complete (struct ata_port *ap,
                                      struct ata_queued_cmd *qc, int have_err);
-static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
-static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
-static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, 
-				      u32 device, u32 subaddr, u32 *pdata);
-static int pdc20621_prog_dimm0(struct ata_probe_ent *pe);
-static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe);
-#ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, 
-				   void *psource, u32 offset, u32 size);
-#endif
-static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, 
-				 void *psource, u32 offset, u32 size);
-
 
 static Scsi_Host_Template pdc_sata_sht = {
 	.module			= THIS_MODULE,
@@ -222,22 +117,6 @@
 	.port_stop		= pdc_port_stop,
 };
 
-static struct ata_port_operations pdc_20621_ops = {
-	.port_disable		= ata_port_disable,
-	.tf_load		= pdc_tf_load_mmio,
-	.tf_read		= ata_tf_read_mmio,
-	.check_status		= ata_check_status_mmio,
-	.exec_command		= pdc_exec_command_mmio,
-	.phy_reset		= pdc_20621_phy_reset,
-	.bmdma_start            = pdc20621_dma_start,
-	.fill_sg		= pdc20621_fill_sg,
-	.eng_timeout		= pdc_eng_timeout,
-	.irq_handler		= pdc20621_interrupt,
-	.port_start		= pdc_port_start,
-	.port_stop		= pdc_port_stop,
-	.host_stop		= pdc20621_host_stop,
-};
-
 static struct ata_port_info pdc_port_info[] = {
 	/* board_2037x */
 	{
@@ -258,18 +137,6 @@
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
 		.port_ops	= &pdc_sata_ops,
 	},
-
-	/* board_20621 */
-	{
-		.sht		= &pdc_sata_sht,
-		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_SRST | ATA_FLAG_MMIO |
-				  PDC_FLAG_20621,
-		.pio_mask	= 0x03, /* pio3-4 */
-		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
-		.port_ops	= &pdc_20621_ops,
-	},
-
 };
 
 static struct pci_device_id pdc_sata_pci_tbl[] = {
@@ -285,8 +152,6 @@
 	  board_20319 },
 	{ PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_20319 },
-	{ PCI_VENDOR_ID_PROMISE, 0x6622, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_20621 },
 	{ }	/* terminate list */
 };
 
@@ -299,15 +164,6 @@
 };
 
 
-static void pdc20621_host_stop(struct ata_host_set *host_set)
-{
-	struct pdc_host_priv *hpriv = host_set->private_data;
-	void *dimm_mmio = hpriv->dimm_mmio;
-
-	iounmap(dimm_mmio);
-	kfree(hpriv);
-}
-
 static int pdc_port_start(struct ata_port *ap)
 {
 	struct pci_dev *pdev = ap->host_set->pdev;
@@ -355,14 +211,6 @@
 }
 
 
-static void pdc_20621_phy_reset (struct ata_port *ap)
-{
-	VPRINTK("ENTER\n");
-        ap->cbl = ATA_CBL_SATA;
-        ata_port_probe(ap);
-        ata_bus_reset(ap);
-}
-
 static void pdc_reset_port(struct ata_port *ap)
 {
 	void *mmio = (void *) ap->ioaddr.cmd_addr + PDC_CTLSTAT;
@@ -407,587 +255,6 @@
 	writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
 }
 
-enum pdc_packet_bits {
-	PDC_PKT_READ		= (1 << 2),
-	PDC_PKT_NODATA		= (1 << 3),
-
-	PDC_PKT_SIZEMASK	= (1 << 7) | (1 << 6) | (1 << 5),
-	PDC_PKT_CLEAR_BSY	= (1 << 4),
-	PDC_PKT_WAIT_DRDY	= (1 << 3) | (1 << 4),
-	PDC_LAST_REG		= (1 << 3),
-
-	PDC_REG_DEVCTL		= (1 << 3) | (1 << 2) | (1 << 1),
-};
-
-static inline unsigned int pdc_pkt_header(struct ata_taskfile *tf,
-					  dma_addr_t sg_table,
-					  unsigned int devno, u8 *buf)
-{
-	u8 dev_reg;
-	u32 *buf32 = (u32 *) buf;
-
-	/* set control bits (byte 0), zero delay seq id (byte 3),
-	 * and seq id (byte 2)
-	 */
-	switch (tf->protocol) {
-	case ATA_PROT_DMA:
-		if (!(tf->flags & ATA_TFLAG_WRITE))
-			buf32[0] = cpu_to_le32(PDC_PKT_READ);
-		else
-			buf32[0] = 0;
-		break;
-
-	case ATA_PROT_NODATA:
-		buf32[0] = cpu_to_le32(PDC_PKT_NODATA);
-		break;
-
-	default:
-		BUG();
-		break;
-	}
-
-	buf32[1] = cpu_to_le32(sg_table);	/* S/G table addr */
-	buf32[2] = 0;				/* no next-packet */
-
-	if (devno == 0)
-		dev_reg = ATA_DEVICE_OBS;
-	else
-		dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
-
-	/* select device */
-	buf[12] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
-	buf[13] = dev_reg;
-
-	/* device control register */
-	buf[14] = (1 << 5) | PDC_REG_DEVCTL;
-	buf[15] = tf->ctl;
-
-	return 16; 	/* offset of next byte */
-}
-
-static inline unsigned int pdc_pkt_footer(struct ata_taskfile *tf, u8 *buf,
-				  unsigned int i)
-{
-	if (tf->flags & ATA_TFLAG_DEVICE) {
-		buf[i++] = (1 << 5) | ATA_REG_DEVICE;
-		buf[i++] = tf->device;
-	}
-
-	/* and finally the command itself; also includes end-of-pkt marker */
-	buf[i++] = (1 << 5) | PDC_LAST_REG | ATA_REG_CMD;
-	buf[i++] = tf->command;
-
-	return i;
-}
-
-static inline unsigned int pdc_prep_lba28(struct ata_taskfile *tf, u8 *buf, unsigned int i)
-{
-	/* the "(1 << 5)" should be read "(count << 5)" */
-
-	/* ATA command block registers */
-	buf[i++] = (1 << 5) | ATA_REG_FEATURE;
-	buf[i++] = tf->feature;
-
-	buf[i++] = (1 << 5) | ATA_REG_NSECT;
-	buf[i++] = tf->nsect;
-
-	buf[i++] = (1 << 5) | ATA_REG_LBAL;
-	buf[i++] = tf->lbal;
-
-	buf[i++] = (1 << 5) | ATA_REG_LBAM;
-	buf[i++] = tf->lbam;
-
-	buf[i++] = (1 << 5) | ATA_REG_LBAH;
-	buf[i++] = tf->lbah;
-
-	return i;
-}
-
-static inline unsigned int pdc_prep_lba48(struct ata_taskfile *tf, u8 *buf, unsigned int i)
-{
-	/* the "(2 << 5)" should be read "(count << 5)" */
-
-	/* ATA command block registers */
-	buf[i++] = (2 << 5) | ATA_REG_FEATURE;
-	buf[i++] = tf->hob_feature;
-	buf[i++] = tf->feature;
-
-	buf[i++] = (2 << 5) | ATA_REG_NSECT;
-	buf[i++] = tf->hob_nsect;
-	buf[i++] = tf->nsect;
-
-	buf[i++] = (2 << 5) | ATA_REG_LBAL;
-	buf[i++] = tf->hob_lbal;
-	buf[i++] = tf->lbal;
-
-	buf[i++] = (2 << 5) | ATA_REG_LBAM;
-	buf[i++] = tf->hob_lbam;
-	buf[i++] = tf->lbam;
-
-	buf[i++] = (2 << 5) | ATA_REG_LBAH;
-	buf[i++] = tf->hob_lbah;
-	buf[i++] = tf->lbah;
-
-	return i;
-}
-
-static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
-				    	   unsigned int portno,
-					   unsigned int total_len)
-{
-	u32 addr;
-	unsigned int dw = PDC_DIMM_APKT_PRD >> 2;
-	u32 *buf32 = (u32 *) buf;
-
-	/* output ATA packet S/G table */
-	addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
-	       (PDC_DIMM_DATA_STEP * portno);
-	VPRINTK("ATA sg addr 0x%x, %d\n", addr, addr);
-	buf32[dw] = cpu_to_le32(addr);
-	buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
-
-	VPRINTK("ATA PSG @ %x == (0x%x, 0x%x)\n",
-		PDC_20621_DIMM_BASE +
-		       (PDC_DIMM_WINDOW_STEP * portno) +
-		       PDC_DIMM_APKT_PRD,
-		buf32[dw], buf32[dw + 1]);
-}
-
-static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf,
-				    	    unsigned int portno,
-					    unsigned int total_len)
-{
-	u32 addr;
-	unsigned int dw = PDC_DIMM_HPKT_PRD >> 2;
-	u32 *buf32 = (u32 *) buf;
-
-	/* output Host DMA packet S/G table */
-	addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
-	       (PDC_DIMM_DATA_STEP * portno);
-
-	buf32[dw] = cpu_to_le32(addr);
-	buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
-
-	VPRINTK("HOST PSG @ %x == (0x%x, 0x%x)\n",
-		PDC_20621_DIMM_BASE +
-		       (PDC_DIMM_WINDOW_STEP * portno) +
-		       PDC_DIMM_HPKT_PRD,
-		buf32[dw], buf32[dw + 1]);
-}
-
-static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf,
-					    unsigned int devno, u8 *buf,
-					    unsigned int portno)
-{
-	unsigned int i, dw;
-	u32 *buf32 = (u32 *) buf;
-	u8 dev_reg;
-
-	unsigned int dimm_sg = PDC_20621_DIMM_BASE +
-			       (PDC_DIMM_WINDOW_STEP * portno) +
-			       PDC_DIMM_APKT_PRD;
-	VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
-
-	i = PDC_DIMM_ATA_PKT;
-
-	/*
-	 * Set up ATA packet
-	 */
-	if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
-		buf[i++] = PDC_PKT_READ;
-	else if (tf->protocol == ATA_PROT_NODATA)
-		buf[i++] = PDC_PKT_NODATA;
-	else
-		buf[i++] = 0;
-	buf[i++] = 0;			/* reserved */
-	buf[i++] = portno + 1;		/* seq. id */
-	buf[i++] = 0xff;		/* delay seq. id */
-
-	/* dimm dma S/G, and next-pkt */
-	dw = i >> 2;
-	buf32[dw] = cpu_to_le32(dimm_sg);
-	buf32[dw + 1] = 0;
-	i += 8;
-
-	if (devno == 0)
-		dev_reg = ATA_DEVICE_OBS;
-	else
-		dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
-
-	/* select device */
-	buf[i++] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
-	buf[i++] = dev_reg;
-
-	/* device control register */
-	buf[i++] = (1 << 5) | PDC_REG_DEVCTL;
-	buf[i++] = tf->ctl;
-
-	return i;
-}
-
-static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf,
-				     unsigned int portno)
-{
-	unsigned int dw;
-	u32 tmp, *buf32 = (u32 *) buf;
-
-	unsigned int host_sg = PDC_20621_DIMM_BASE +
-			       (PDC_DIMM_WINDOW_STEP * portno) +
-			       PDC_DIMM_HOST_PRD;
-	unsigned int dimm_sg = PDC_20621_DIMM_BASE +
-			       (PDC_DIMM_WINDOW_STEP * portno) +
-			       PDC_DIMM_HPKT_PRD;
-	VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
-	VPRINTK("host_sg == 0x%x, %d\n", host_sg, host_sg);
-
-	dw = PDC_DIMM_HOST_PKT >> 2;
-
-	/*
-	 * Set up Host DMA packet
-	 */
-	if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
-		tmp = PDC_PKT_READ;
-	else
-		tmp = 0;
-	tmp |= ((portno + 1 + 4) << 16);	/* seq. id */
-	tmp |= (0xff << 24);			/* delay seq. id */
-	buf32[dw + 0] = cpu_to_le32(tmp);
-	buf32[dw + 1] = cpu_to_le32(host_sg);
-	buf32[dw + 2] = cpu_to_le32(dimm_sg);
-	buf32[dw + 3] = 0;
-
-	VPRINTK("HOST PKT @ %x == (0x%x 0x%x 0x%x 0x%x)\n",
-		PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * portno) +
-			PDC_DIMM_HOST_PKT,
-		buf32[dw + 0],
-		buf32[dw + 1],
-		buf32[dw + 2],
-		buf32[dw + 3]);
-}
-
-static void pdc20621_fill_sg(struct ata_queued_cmd *qc)
-{
-	struct scatterlist *sg = qc->sg;
-	struct ata_port *ap = qc->ap;
-	struct pdc_port_priv *pp = ap->private_data;
-	void *mmio = ap->host_set->mmio_base;
-	struct pdc_host_priv *hpriv = ap->host_set->private_data;
-	void *dimm_mmio = hpriv->dimm_mmio;
-	unsigned int portno = ap->port_no;
-	unsigned int i, last, idx, total_len = 0, sgt_len;
-	u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
-
-	VPRINTK("ata%u: ENTER\n", ap->id);
-
-	/* hard-code chip #0 */
-	mmio += PDC_CHIP0_OFS;
-
-	/*
-	 * Build S/G table
-	 */
-	last = qc->n_elem;
-	idx = 0;
-	for (i = 0; i < last; i++) {
-		buf[idx++] = cpu_to_le32(sg_dma_address(&sg[i]));
-		buf[idx++] = cpu_to_le32(sg_dma_len(&sg[i]));
-		total_len += sg[i].length;
-	}
-	buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT);
-	sgt_len = idx * 4;
-
-	/*
-	 * Build ATA, host DMA packets
-	 */
-	pdc20621_host_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
-	pdc20621_host_pkt(&qc->tf, &pp->dimm_buf[0], portno);
-
-	pdc20621_ata_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
-	i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
-
-	if (qc->tf.flags & ATA_TFLAG_LBA48)
-		i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
-	else
-		i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
-
-	pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
-
-	/* copy three S/G tables and two packets to DIMM MMIO window */
-	memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
-		    &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
-	memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP) +
-		    PDC_DIMM_HOST_PRD,
-		    &pp->dimm_buf[PDC_DIMM_HEADER_SZ], sgt_len);
-
-	/* force host FIFO dump */
-	writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
-
-	readl(dimm_mmio);	/* MMIO PCI posting flush */
-
-	VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len);
-}
-
-static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
-				 unsigned int seq,
-				 u32 pkt_ofs)
-{
-	struct ata_port *ap = qc->ap;
-	struct ata_host_set *host_set = ap->host_set;
-	void *mmio = host_set->mmio_base;
-
-	/* hard-code chip #0 */
-	mmio += PDC_CHIP0_OFS;
-
-	writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
-	readl(mmio + PDC_20621_SEQCTL + (seq * 4));	/* flush */
-
-	writel(pkt_ofs, mmio + PDC_HDMA_PKT_SUBMIT);
-	readl(mmio + PDC_HDMA_PKT_SUBMIT);	/* flush */
-}
-
-static void pdc20621_push_hdma(struct ata_queued_cmd *qc,
-				unsigned int seq,
-				u32 pkt_ofs)
-{
-	struct ata_port *ap = qc->ap;
-	struct pdc_host_priv *pp = ap->host_set->private_data;
-	unsigned int idx = pp->hdma_prod & PDC_HDMA_Q_MASK;
-
-	if (!pp->doing_hdma) {
-		__pdc20621_push_hdma(qc, seq, pkt_ofs);
-		pp->doing_hdma = 1;
-		return;
-	}
-
-	pp->hdma[idx].qc = qc;
-	pp->hdma[idx].seq = seq;
-	pp->hdma[idx].pkt_ofs = pkt_ofs;
-	pp->hdma_prod++;
-}
-
-static void pdc20621_pop_hdma(struct ata_queued_cmd *qc)
-{
-	struct ata_port *ap = qc->ap;
-	struct pdc_host_priv *pp = ap->host_set->private_data;
-	unsigned int idx = pp->hdma_cons & PDC_HDMA_Q_MASK;
-
-	/* if nothing on queue, we're done */
-	if (pp->hdma_prod == pp->hdma_cons) {
-		pp->doing_hdma = 0;
-		return;
-	}
-
-	__pdc20621_push_hdma(pp->hdma[idx].qc, pp->hdma[idx].seq,
-			     pp->hdma[idx].pkt_ofs);
-	pp->hdma_cons++;
-}
-
-#ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_dump_hdma(struct ata_queued_cmd *qc)
-{
-	struct ata_port *ap = qc->ap;
-	unsigned int port_no = ap->port_no;
-	struct pdc_host_priv *hpriv = ap->host_set->private_data;
-	void *dimm_mmio = hpriv->dimm_mmio;
-
-	dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP);
-	dimm_mmio += PDC_DIMM_HOST_PKT;
-
-	printk(KERN_ERR "HDMA[0] == 0x%08X\n", readl(dimm_mmio));
-	printk(KERN_ERR "HDMA[1] == 0x%08X\n", readl(dimm_mmio + 4));
-	printk(KERN_ERR "HDMA[2] == 0x%08X\n", readl(dimm_mmio + 8));
-	printk(KERN_ERR "HDMA[3] == 0x%08X\n", readl(dimm_mmio + 12));
-}
-#else
-static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { }
-#endif /* ATA_VERBOSE_DEBUG */
-
-static void pdc20621_dma_start(struct ata_queued_cmd *qc)
-{
-	struct ata_port *ap = qc->ap;
-	struct ata_host_set *host_set = ap->host_set;
-	unsigned int port_no = ap->port_no;
-	void *mmio = host_set->mmio_base;
-	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
-	u8 seq = (u8) (port_no + 1);
-	unsigned int doing_hdma = 0, port_ofs;
-
-	/* hard-code chip #0 */
-	mmio += PDC_CHIP0_OFS;
-
-	VPRINTK("ata%u: ENTER\n", ap->id);
-
-	port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
-
-	/* if writing, we (1) DMA to DIMM, then (2) do ATA command */
-	if (rw) {
-		doing_hdma = 1;
-		seq += 4;
-	}
-
-	wmb();			/* flush PRD, pkt writes */
-
-	if (doing_hdma) {
-		pdc20621_dump_hdma(qc);
-		pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT);
-		VPRINTK("queued ofs 0x%x (%u), seq %u\n",
-			port_ofs + PDC_DIMM_HOST_PKT,
-			port_ofs + PDC_DIMM_HOST_PKT,
-			seq);
-	} else {
-		writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
-		readl(mmio + PDC_20621_SEQCTL + (seq * 4));	/* flush */
-
-		writel(port_ofs + PDC_DIMM_ATA_PKT,
-		       (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
-		readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
-		VPRINTK("submitted ofs 0x%x (%u), seq %u\n",
-			port_ofs + PDC_DIMM_ATA_PKT,
-			port_ofs + PDC_DIMM_ATA_PKT,
-			seq);
-	}
-}
-
-static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
-                                          struct ata_queued_cmd *qc,
-					  unsigned int doing_hdma,
-					  void *mmio)
-{
-	unsigned int port_no = ap->port_no;
-	unsigned int port_ofs =
-		PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
-	u8 status;
-	unsigned int handled = 0;
-
-	VPRINTK("ENTER\n");
-
-	if ((qc->tf.protocol == ATA_PROT_DMA) &&	/* read */
-	    (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
-
-		/* step two - DMA from DIMM to host */
-		if (doing_hdma) {
-			VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id,
-				readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
-			pdc_dma_complete(ap, qc, 0);
-			pdc20621_pop_hdma(qc);
-		}
-
-		/* step one - exec ATA command */
-		else {
-			u8 seq = (u8) (port_no + 1 + 4);
-			VPRINTK("ata%u: read ata, 0x%x 0x%x\n", ap->id,
-				readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
-
-			/* submit hdma pkt */
-			pdc20621_dump_hdma(qc);
-			pdc20621_push_hdma(qc, seq,
-					   port_ofs + PDC_DIMM_HOST_PKT);
-		}
-		handled = 1;
-
-	} else if (qc->tf.protocol == ATA_PROT_DMA) {	/* write */
-
-		/* step one - DMA from host to DIMM */
-		if (doing_hdma) {
-			u8 seq = (u8) (port_no + 1);
-			VPRINTK("ata%u: write hdma, 0x%x 0x%x\n", ap->id,
-				readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
-
-			/* submit ata pkt */
-			writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
-			readl(mmio + PDC_20621_SEQCTL + (seq * 4));
-			writel(port_ofs + PDC_DIMM_ATA_PKT,
-			       (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
-			readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
-		}
-
-		/* step two - execute ATA command */
-		else {
-			VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id,
-				readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
-			pdc_dma_complete(ap, qc, 0);
-			pdc20621_pop_hdma(qc);
-		}
-		handled = 1;
-
-	/* command completion, but no data xfer */
-	} else if (qc->tf.protocol == ATA_PROT_NODATA) {
-
-		status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
-		DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status);
-		ata_qc_complete(qc, status, 0);
-		handled = 1;
-
-	} else {
-		ap->stats.idle_irq++;
-	}
-
-	return handled;
-}
-
-static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
-{
-	struct ata_host_set *host_set = dev_instance;
-	struct ata_port *ap;
-	u32 mask = 0;
-	unsigned int i, tmp, port_no;
-	unsigned int handled = 0;
-	void *mmio_base;
-
-	VPRINTK("ENTER\n");
-
-	if (!host_set || !host_set->mmio_base) {
-		VPRINTK("QUICK EXIT\n");
-		return IRQ_NONE;
-	}
-
-	mmio_base = host_set->mmio_base;
-
-	/* reading should also clear interrupts */
-	mmio_base += PDC_CHIP0_OFS;
-	mask = readl(mmio_base + PDC_20621_SEQMASK);
-	VPRINTK("mask == 0x%x\n", mask);
-
-	if (mask == 0xffffffff) {
-		VPRINTK("QUICK EXIT 2\n");
-		return IRQ_NONE;
-	}
-	mask &= 0xffff;		/* only 16 tags possible */
-	if (!mask) {
-		VPRINTK("QUICK EXIT 3\n");
-		return IRQ_NONE;
-	}
-
-        spin_lock(&host_set->lock);
-
-        for (i = 1; i < 9; i++) {
-		port_no = i - 1;
-		if (port_no > 3)
-			port_no -= 4;
-		if (port_no >= host_set->n_ports)
-			ap = NULL;
-		else
-			ap = host_set->ports[port_no];
-		tmp = mask & (1 << i);
-		VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
-		if (tmp && ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
-			struct ata_queued_cmd *qc;
-
-			qc = ata_qc_from_tag(ap, ap->active_tag);
-			if (qc && ((qc->flags & ATA_QCFLAG_POLL) == 0))
-				handled += pdc20621_host_intr(ap, qc, (i > 4),
-							      mmio_base);
-		}
-	}
-
-        spin_unlock(&host_set->lock);
-
-	VPRINTK("mask == 0x%x\n", mask);
-
-	VPRINTK("EXIT\n");
-
-	return IRQ_RETVAL(handled);
-}
-
 static void pdc_fill_sg(struct ata_queued_cmd *qc)
 {
 	struct pdc_port_priv *pp = qc->ap->private_data;
@@ -1210,456 +477,11 @@
 }
 
 
-#ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource, 
-				   u32 offset, u32 size)
-{
-	u32 window_size;
-	u16 idx;
-	u8 page_mask;
-	long dist;
-	void *mmio = pe->mmio_base;
-	struct pdc_host_priv *hpriv = pe->private_data;
-	void *dimm_mmio = hpriv->dimm_mmio;
-
-	/* hard-code chip #0 */
-	mmio += PDC_CHIP0_OFS;
-
-	page_mask = 0x00;	
-   	window_size = 0x2000 * 4; /* 32K byte uchar size */  
-	idx = (u16) (offset / window_size); 
-
-	writel(0x01, mmio + PDC_GENERAL_CTLR);
-	readl(mmio + PDC_GENERAL_CTLR);
-	writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
-	readl(mmio + PDC_DIMM_WINDOW_CTLR);
-
-	offset -= (idx * window_size);
-	idx++;
-	dist = ((long) (window_size - (offset + size))) >= 0 ? size : 
-		(long) (window_size - offset);
-	memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4), 
-		      dist);
-
-	psource += dist;    
-	size -= dist;
-	for (; (long) size >= (long) window_size ;) {
-		writel(0x01, mmio + PDC_GENERAL_CTLR);
-		readl(mmio + PDC_GENERAL_CTLR);
-		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
-		readl(mmio + PDC_DIMM_WINDOW_CTLR);
-		memcpy_fromio((char *) psource, (char *) (dimm_mmio), 
-			      window_size / 4);
-		psource += window_size;
-		size -= window_size;
-		idx ++;
-	}
-
-	if (size) {
-		writel(0x01, mmio + PDC_GENERAL_CTLR);
-		readl(mmio + PDC_GENERAL_CTLR);
-		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
-		readl(mmio + PDC_DIMM_WINDOW_CTLR);
-		memcpy_fromio((char *) psource, (char *) (dimm_mmio), 
-			      size / 4);
-	}
-}
-#endif
-
-
-static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, 
-				 u32 offset, u32 size)
-{
-	u32 window_size;
-	u16 idx;
-	u8 page_mask;
-	long dist;
-	void *mmio = pe->mmio_base;
-	struct pdc_host_priv *hpriv = pe->private_data;
-	void *dimm_mmio = hpriv->dimm_mmio;
-
-	/* hard-code chip #0 */   
-	mmio += PDC_CHIP0_OFS;
-
-	page_mask = 0x00;	
-   	window_size = 0x2000 * 4;       /* 32K byte uchar size */  
-	idx = (u16) (offset / window_size);
-
-	writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
-	readl(mmio + PDC_DIMM_WINDOW_CTLR);
-	offset -= (idx * window_size); 
-	idx++;
-	dist = ((long) (window_size - (offset + size))) >= 0 ? size : 
-		(long) (window_size - offset);
-	memcpy_toio((char *) (dimm_mmio + offset / 4), (char *) psource, dist);
-	writel(0x01, mmio + PDC_GENERAL_CTLR);
-	readl(mmio + PDC_GENERAL_CTLR);
-
-	psource += dist;    
-	size -= dist;
-	for (; (long) size >= (long) window_size ;) {
-		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
-		readl(mmio + PDC_DIMM_WINDOW_CTLR);
-		memcpy_toio((char *) (dimm_mmio), (char *) psource, 
-			    window_size / 4);
-		writel(0x01, mmio + PDC_GENERAL_CTLR);
-		readl(mmio + PDC_GENERAL_CTLR);
-		psource += window_size;
-		size -= window_size;
-		idx ++;
-	}
-    
-	if (size) {
-		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
-		readl(mmio + PDC_DIMM_WINDOW_CTLR);
-		memcpy_toio((char *) (dimm_mmio), (char *) psource, size / 4);
-		writel(0x01, mmio + PDC_GENERAL_CTLR);
-		readl(mmio + PDC_GENERAL_CTLR);
-	}
-}
-
-
-static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, 
-				      u32 subaddr, u32 *pdata)
-{
-	void *mmio = pe->mmio_base;
-	u32 i2creg  = 0;
-	u32 status;     
-	u32 count =0;
-
-	/* hard-code chip #0 */
-	mmio += PDC_CHIP0_OFS;
-
-	i2creg |= device << 24;
-	i2creg |= subaddr << 16;
-
-	/* Set the device and subaddress */
-	writel(i2creg, mmio + PDC_I2C_ADDR_DATA_OFFSET);
-	readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
-
-	/* Write Control to perform read operation, mask int */
-	writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT, 
-	       mmio + PDC_I2C_CONTROL_OFFSET);
-
-	for (count = 0; count <= 1000; count ++) {
-		status = readl(mmio + PDC_I2C_CONTROL_OFFSET);
-		if (status & PDC_I2C_COMPLETE) {
-			status = readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
-			break;
-		} else if (count == 1000)
-			return 0;
-	}
-
-	*pdata = (status >> 8) & 0x000000ff;
-	return 1;           
-}
-
-
-static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
-{
-	u32 data=0 ;
-  	if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 
-			     PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {
-   		if (data == 100)
-			return 100;
-  	} else
-		return 0;
- 	
-   	if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
-		if(data <= 0x75) 
-			return 133;
-   	} else
-		return 0;
-   	
-   	return 0;
-}
-
-
-static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
-{
-	u32 spd0[50];
-	u32 data = 0;
-   	int size, i;
-   	u8 bdimmsize; 
-   	void *mmio = pe->mmio_base;
-	static const struct {
-		unsigned int reg;
-		unsigned int ofs;
-	} pdc_i2c_read_data [] = {
-		{ PDC_DIMM_SPD_TYPE, 11 },		
-		{ PDC_DIMM_SPD_FRESH_RATE, 12 },
-		{ PDC_DIMM_SPD_COLUMN_NUM, 4 }, 
-		{ PDC_DIMM_SPD_ATTRIBUTE, 21 },
-		{ PDC_DIMM_SPD_ROW_NUM, 3 },
-		{ PDC_DIMM_SPD_BANK_NUM, 17 },
-		{ PDC_DIMM_SPD_MODULE_ROW, 5 },
-		{ PDC_DIMM_SPD_ROW_PRE_CHARGE, 27 },
-		{ PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 },
-		{ PDC_DIMM_SPD_RAS_CAS_DELAY, 29 },
-		{ PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 },
-		{ PDC_DIMM_SPD_CAS_LATENCY, 18 },       
-	};
-
-	/* hard-code chip #0 */
-	mmio += PDC_CHIP0_OFS;
-
-	for(i=0; i<ARRAY_SIZE(pdc_i2c_read_data); i++)
-		pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
-				  pdc_i2c_read_data[i].reg, 
-				  &spd0[pdc_i2c_read_data[i].ofs]);
-  
-   	data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4);
-   	data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) | 
-		((((spd0[27] + 9) / 10) - 1) << 8) ;
-   	data |= (((((spd0[29] > spd0[28]) 
-		    ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10; 
-   	data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12;
-   
-   	if (spd0[18] & 0x08) 
-		data |= ((0x03) << 14);
-   	else if (spd0[18] & 0x04)
-		data |= ((0x02) << 14);
-   	else if (spd0[18] & 0x01)
-		data |= ((0x01) << 14);
-   	else
-		data |= (0 << 14);
-
-  	/* 
-	   Calculate the size of bDIMMSize (power of 2) and
-	   merge the DIMM size by program start/end address.
-	*/
-
-   	bdimmsize = spd0[4] + (spd0[5] / 2) + spd0[3] + (spd0[17] / 2) + 3;
-   	size = (1 << bdimmsize) >> 20;	/* size = xxx(MB) */
-   	data |= (((size / 16) - 1) << 16);
-   	data |= (0 << 23);
-	data |= 8;
-   	writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET); 
-	readl(mmio + PDC_DIMM0_CONTROL_OFFSET);
-   	return size;                          
-}
-
-
-static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
-{
-	u32 data, spd0;
-   	int error, i;
-   	void *mmio = pe->mmio_base;
-
-	/* hard-code chip #0 */
-   	mmio += PDC_CHIP0_OFS;
-
-   	/*
-	  Set To Default : DIMM Module Global Control Register (0x022259F1)
-	  DIMM Arbitration Disable (bit 20)
-	  DIMM Data/Control Output Driving Selection (bit12 - bit15)
-	  Refresh Enable (bit 17)
-	*/
-
-	data = 0x022259F1;   
-	writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
-	readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
-
-	/* Turn on for ECC */
-	pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 
-			  PDC_DIMM_SPD_TYPE, &spd0);
-	if (spd0 == 0x02) {
-		data |= (0x01 << 16);
-		writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
-		readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
-		printk(KERN_ERR "Local DIMM ECC Enabled\n");
-   	}
-
-   	/* DIMM Initialization Select/Enable (bit 18/19) */
-   	data &= (~(1<<18));
-   	data |= (1<<19);
-   	writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
-
-   	error = 1;                     
-   	for (i = 1; i <= 10; i++) {   /* polling ~5 secs */
-		data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
-		if (!(data & (1<<19))) {
-	   		error = 0;
-	   		break;     
-		}
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout((i * 100) * HZ / 1000);
-   	}
-   	return error;
-}
-	
-
-static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
-{
-	int speed, size, length; 
-	u32 addr,spd0,pci_status;
-	u32 tmp=0;
-	u32 time_period=0;
-	u32 tcount=0;
-	u32 ticks=0;
-	u32 clock=0;
-	u32 fparam=0;
-   	void *mmio = pe->mmio_base;
-
-	/* hard-code chip #0 */
-   	mmio += PDC_CHIP0_OFS;
-
-	/* Initialize PLL based upon PCI Bus Frequency */
-
-	/* Initialize Time Period Register */
-	writel(0xffffffff, mmio + PDC_TIME_PERIOD);
-	time_period = readl(mmio + PDC_TIME_PERIOD);
-	VPRINTK("Time Period Register (0x40): 0x%x\n", time_period);
-
-	/* Enable timer */
-	writel(0x00001a0, mmio + PDC_TIME_CONTROL);
-	readl(mmio + PDC_TIME_CONTROL);
-
-	/* Wait 3 seconds */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(3 * HZ);
-
-	/* 
-	   When timer is enabled, counter is decreased every internal
-	   clock cycle.
-	*/
-
-	tcount = readl(mmio + PDC_TIME_COUNTER);
-	VPRINTK("Time Counter Register (0x44): 0x%x\n", tcount);
-
-	/* 
-	   If SX4 is on PCI-X bus, after 3 seconds, the timer counter
-	   register should be >= (0xffffffff - 3x10^8).
-	*/
-	if(tcount >= PCI_X_TCOUNT) {
-		ticks = (time_period - tcount);
-		VPRINTK("Num counters 0x%x (%d)\n", ticks, ticks);
-	
-		clock = (ticks / 300000);
-		VPRINTK("10 * Internal clk = 0x%x (%d)\n", clock, clock);
-		
-		clock = (clock * 33);
-		VPRINTK("10 * Internal clk * 33 = 0x%x (%d)\n", clock, clock);
-
-		/* PLL F Param (bit 22:16) */
-		fparam = (1400000 / clock) - 2;
-		VPRINTK("PLL F Param: 0x%x (%d)\n", fparam, fparam);
-		
-		/* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */
-		pci_status = (0x8a001824 | (fparam << 16));
-	} else
-		pci_status = PCI_PLL_INIT;
-
-	/* Initialize PLL. */
-	VPRINTK("pci_status: 0x%x\n", pci_status);
-	writel(pci_status, mmio + PDC_CTL_STATUS);
-	readl(mmio + PDC_CTL_STATUS);
-
-	/* 
-	   Read SPD of DIMM by I2C interface,
-	   and program the DIMM Module Controller.
-	*/
- 	if (!(speed = pdc20621_detect_dimm(pe))) {
-		printk(KERN_ERR "Detect Local DIMM Fail\n");  
-		return 1;	/* DIMM error */
-   	}
-   	VPRINTK("Local DIMM Speed = %d\n", speed);
-
-   	/* Programming DIMM0 Module Control Register (index_CID0:80h) */ 
-   	size = pdc20621_prog_dimm0(pe);
-   	VPRINTK("Local DIMM Size = %dMB\n",size);
-
-   	/* Programming DIMM Module Global Control Register (index_CID0:88h) */ 
-   	if (pdc20621_prog_dimm_global(pe)) {
-		printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");
-		return 1;
-   	}
-
-#ifdef ATA_VERBOSE_DEBUG
-	{
-		u8 test_parttern1[40] = {0x55,0xAA,'P','r','o','m','i','s','e',' ',
-  				'N','o','t',' ','Y','e','t',' ','D','e','f','i','n','e','d',' ',
- 				 '1','.','1','0',
-  				'9','8','0','3','1','6','1','2',0,0};
-		u8 test_parttern2[40] = {0};
-
-		pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x10040, 40);
-		pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x40, 40);
-
-		pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40);
-		pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
-		printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], 
-		       test_parttern2[1], &(test_parttern2[2]));
-		pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040, 
-				       40);
-		printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], 
-		       test_parttern2[1], &(test_parttern2[2]));
-
-		pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40);
-		pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
-		printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], 
-		       test_parttern2[1], &(test_parttern2[2]));
-	}
-#endif
-
-	/* ECC initiliazation. */
-
-	pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 
-			  PDC_DIMM_SPD_TYPE, &spd0);
-	if (spd0 == 0x02) {
-		VPRINTK("Start ECC initialization\n");
-		addr = 0;
-		length = size * 1024 * 1024;
-		while (addr < length) {
-			pdc20621_put_to_dimm(pe, (void *) &tmp, addr, 
-					     sizeof(u32));
-			addr += sizeof(u32);
-		}
-		VPRINTK("Finish ECC initialization\n");
-	}
-	return 0;
-}
-
-
-static void pdc_20621_init(struct ata_probe_ent *pe)
-{
-	u32 tmp;
-	void *mmio = pe->mmio_base;
-
-	/* hard-code chip #0 */
-	mmio += PDC_CHIP0_OFS;
-
-	/*
-	 * Select page 0x40 for our 32k DIMM window
-	 */
-	tmp = readl(mmio + PDC_20621_DIMM_WINDOW) & 0xffff0000;
-	tmp |= PDC_PAGE_WINDOW;	/* page 40h; arbitrarily selected */
-	writel(tmp, mmio + PDC_20621_DIMM_WINDOW);
-
-	/*
-	 * Reset Host DMA
-	 */
-	tmp = readl(mmio + PDC_HDMA_CTLSTAT);
-	tmp |= PDC_RESET;
-	writel(tmp, mmio + PDC_HDMA_CTLSTAT);
-	readl(mmio + PDC_HDMA_CTLSTAT);		/* flush */
-
-	udelay(10);
-
-	tmp = readl(mmio + PDC_HDMA_CTLSTAT);
-	tmp &= ~PDC_RESET;
-	writel(tmp, mmio + PDC_HDMA_CTLSTAT);
-	readl(mmio + PDC_HDMA_CTLSTAT);		/* flush */
-}
-
 static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
 {
 	void *mmio = pe->mmio_base;
 	u32 tmp;
 
-	if (chip_id == board_20621)
-		BUG();
-
 	/*
 	 * Except for the hotplug stuff, this is voodoo from the
 	 * Promise driver.  Label this entire section
@@ -1687,7 +509,7 @@
 
 	readl(mmio + PDC_TBG_MODE);	/* flush */
 	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(msecs_to_jiffies(10));
+	schedule_timeout(msecs_to_jiffies(10) + 1);
 
 	/* adjust slew rate control register. */
 	tmp = readl(mmio + PDC_SLEW_CTL);
@@ -1701,10 +523,8 @@
 	static int printed_version;
 	struct ata_probe_ent *probe_ent = NULL;
 	unsigned long base;
-	void *mmio_base, *dimm_mmio = NULL;
-	struct pdc_host_priv *hpriv = NULL;
+	void *mmio_base;
 	unsigned int board_idx = (unsigned int) ent->driver_data;
-	unsigned int have_20621 = (board_idx == board_20621);
 	int rc;
 
 	if (!printed_version++)
@@ -1747,25 +567,6 @@
 	}
 	base = (unsigned long) mmio_base;
 
-	if (have_20621) {
-		hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
-		if (!hpriv) {
-			rc = -ENOMEM;
-			goto err_out_iounmap;
-		}
-		memset(hpriv, 0, sizeof(*hpriv));
-
-		dimm_mmio = ioremap(pci_resource_start(pdev, 4),
-				    pci_resource_len(pdev, 4));
-		if (!dimm_mmio) {
-			kfree(hpriv);
-			rc = -ENOMEM;
-			goto err_out_iounmap;
-		}
-
-		hpriv->dimm_mmio = dimm_mmio;
-	}
-
 	probe_ent->sht		= pdc_port_info[board_idx].sht;
 	probe_ent->host_flags	= pdc_port_info[board_idx].host_flags;
 	probe_ent->pio_mask	= pdc_port_info[board_idx].pio_mask;
@@ -1776,32 +577,22 @@
        	probe_ent->irq_flags = SA_SHIRQ;
 	probe_ent->mmio_base = mmio_base;
 
-	if (have_20621) {
-		probe_ent->private_data = hpriv;
-		base += PDC_CHIP0_OFS;
-	}
-
 	pdc_sata_setup_port(&probe_ent->port[0], base + 0x200);
 	pdc_sata_setup_port(&probe_ent->port[1], base + 0x280);
 
-	if (!have_20621) {
-		probe_ent->port[0].scr_addr = base + 0x400;
-		probe_ent->port[1].scr_addr = base + 0x500;
-	}
+	probe_ent->port[0].scr_addr = base + 0x400;
+	probe_ent->port[1].scr_addr = base + 0x500;
 
 	/* notice 4-port boards */
 	switch (board_idx) {
 	case board_20319:
-	case board_20621:
        		probe_ent->n_ports = 4;
 
 		pdc_sata_setup_port(&probe_ent->port[2], base + 0x300);
 		pdc_sata_setup_port(&probe_ent->port[3], base + 0x380);
 
-		if (!have_20621) {
-			probe_ent->port[2].scr_addr = base + 0x600;
-			probe_ent->port[3].scr_addr = base + 0x700;
-		}
+		probe_ent->port[2].scr_addr = base + 0x600;
+		probe_ent->port[3].scr_addr = base + 0x700;
 		break;
 	case board_2037x:
        		probe_ent->n_ports = 2;
@@ -1814,15 +605,7 @@
 	pci_set_master(pdev);
 
 	/* initialize adapter */
-	if (have_20621) {
-		/* initialize local dimm */
-		if (pdc20621_dimm_init(probe_ent)) {
-			rc = -ENOMEM;
-			goto err_out_iounmap_dimm;
-		}
-		pdc_20621_init(probe_ent);
-	} else
-		pdc_host_init(board_idx, probe_ent);
+	pdc_host_init(board_idx, probe_ent);
 
 	/* FIXME: check ata_device_add return value */
 	ata_device_add(probe_ent);
@@ -1830,11 +613,6 @@
 
 	return 0;
 
-err_out_iounmap_dimm:		/* only get to this label if 20621 */
-	kfree(hpriv);
-	iounmap(dimm_mmio);
-err_out_iounmap:
-	iounmap(mmio_base);
 err_out_free_ent:
 	kfree(probe_ent);
 err_out_regions:
@@ -1858,7 +636,7 @@
 
 
 MODULE_AUTHOR("Jeff Garzik");
-MODULE_DESCRIPTION("Promise SATA low-level driver");
+MODULE_DESCRIPTION("Promise SATA TX2/TX4 low-level driver");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, pdc_sata_pci_tbl);
 
diff -Nru a/drivers/scsi/sata_promise.h b/drivers/scsi/sata_promise.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/sata_promise.h	Tue May  4 22:11:45 2004
@@ -0,0 +1,154 @@
+/*
+ *  sata_promise.h - Promise SATA common definitions and inline funcs
+ *
+ *  Copyright 2003-2004 Red Hat, Inc.
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#ifndef __SATA_PROMISE_H__
+#define __SATA_PROMISE_H__
+
+#include <linux/ata.h>
+
+enum pdc_packet_bits {
+	PDC_PKT_READ		= (1 << 2),
+	PDC_PKT_NODATA		= (1 << 3),
+
+	PDC_PKT_SIZEMASK	= (1 << 7) | (1 << 6) | (1 << 5),
+	PDC_PKT_CLEAR_BSY	= (1 << 4),
+	PDC_PKT_WAIT_DRDY	= (1 << 3) | (1 << 4),
+	PDC_LAST_REG		= (1 << 3),
+
+	PDC_REG_DEVCTL		= (1 << 3) | (1 << 2) | (1 << 1),
+};
+
+static inline unsigned int pdc_pkt_header(struct ata_taskfile *tf,
+					  dma_addr_t sg_table,
+					  unsigned int devno, u8 *buf)
+{
+	u8 dev_reg;
+	u32 *buf32 = (u32 *) buf;
+
+	/* set control bits (byte 0), zero delay seq id (byte 3),
+	 * and seq id (byte 2)
+	 */
+	switch (tf->protocol) {
+	case ATA_PROT_DMA:
+		if (!(tf->flags & ATA_TFLAG_WRITE))
+			buf32[0] = cpu_to_le32(PDC_PKT_READ);
+		else
+			buf32[0] = 0;
+		break;
+
+	case ATA_PROT_NODATA:
+		buf32[0] = cpu_to_le32(PDC_PKT_NODATA);
+		break;
+
+	default:
+		BUG();
+		break;
+	}
+
+	buf32[1] = cpu_to_le32(sg_table);	/* S/G table addr */
+	buf32[2] = 0;				/* no next-packet */
+
+	if (devno == 0)
+		dev_reg = ATA_DEVICE_OBS;
+	else
+		dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
+
+	/* select device */
+	buf[12] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
+	buf[13] = dev_reg;
+
+	/* device control register */
+	buf[14] = (1 << 5) | PDC_REG_DEVCTL;
+	buf[15] = tf->ctl;
+
+	return 16; 	/* offset of next byte */
+}
+
+static inline unsigned int pdc_pkt_footer(struct ata_taskfile *tf, u8 *buf,
+				  unsigned int i)
+{
+	if (tf->flags & ATA_TFLAG_DEVICE) {
+		buf[i++] = (1 << 5) | ATA_REG_DEVICE;
+		buf[i++] = tf->device;
+	}
+
+	/* and finally the command itself; also includes end-of-pkt marker */
+	buf[i++] = (1 << 5) | PDC_LAST_REG | ATA_REG_CMD;
+	buf[i++] = tf->command;
+
+	return i;
+}
+
+static inline unsigned int pdc_prep_lba28(struct ata_taskfile *tf, u8 *buf, unsigned int i)
+{
+	/* the "(1 << 5)" should be read "(count << 5)" */
+
+	/* ATA command block registers */
+	buf[i++] = (1 << 5) | ATA_REG_FEATURE;
+	buf[i++] = tf->feature;
+
+	buf[i++] = (1 << 5) | ATA_REG_NSECT;
+	buf[i++] = tf->nsect;
+
+	buf[i++] = (1 << 5) | ATA_REG_LBAL;
+	buf[i++] = tf->lbal;
+
+	buf[i++] = (1 << 5) | ATA_REG_LBAM;
+	buf[i++] = tf->lbam;
+
+	buf[i++] = (1 << 5) | ATA_REG_LBAH;
+	buf[i++] = tf->lbah;
+
+	return i;
+}
+
+static inline unsigned int pdc_prep_lba48(struct ata_taskfile *tf, u8 *buf, unsigned int i)
+{
+	/* the "(2 << 5)" should be read "(count << 5)" */
+
+	/* ATA command block registers */
+	buf[i++] = (2 << 5) | ATA_REG_FEATURE;
+	buf[i++] = tf->hob_feature;
+	buf[i++] = tf->feature;
+
+	buf[i++] = (2 << 5) | ATA_REG_NSECT;
+	buf[i++] = tf->hob_nsect;
+	buf[i++] = tf->nsect;
+
+	buf[i++] = (2 << 5) | ATA_REG_LBAL;
+	buf[i++] = tf->hob_lbal;
+	buf[i++] = tf->lbal;
+
+	buf[i++] = (2 << 5) | ATA_REG_LBAM;
+	buf[i++] = tf->hob_lbam;
+	buf[i++] = tf->lbam;
+
+	buf[i++] = (2 << 5) | ATA_REG_LBAH;
+	buf[i++] = tf->hob_lbah;
+	buf[i++] = tf->lbah;
+
+	return i;
+}
+
+
+#endif /* __SATA_PROMISE_H__ */
diff -Nru a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c
--- a/drivers/scsi/sata_sis.c	Tue May  4 22:11:45 2004
+++ b/drivers/scsi/sata_sis.c	Tue May  4 22:11:45 2004
@@ -45,7 +45,8 @@
 static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
 static struct pci_device_id sis_pci_tbl[] = {
-	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+	{ PCI_VENDOR_ID_SI, 0x180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+	{ PCI_VENDOR_ID_SI, 0x181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
 	{ }	/* terminate list */
 };
 
diff -Nru a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/sata_sx4.c	Tue May  4 22:11:45 2004
@@ -0,0 +1,1436 @@
+/*
+ *  sata_sx4.c - Promise SATA
+ *
+ *  Copyright 2003-2004 Red Hat, Inc.
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include "scsi.h"
+#include "hosts.h"
+#include <linux/libata.h>
+#include <asm/io.h>
+#include "sata_promise.h"
+
+#define DRV_NAME	"sata_sx4"
+#define DRV_VERSION	"0.50"
+
+
+enum {
+	PDC_PRD_TBL		= 0x44,	/* Direct command DMA table addr */
+
+	PDC_PKT_SUBMIT		= 0x40, /* Command packet pointer addr */
+	PDC_HDMA_PKT_SUBMIT	= 0x100, /* Host DMA packet pointer addr */
+	PDC_INT_SEQMASK		= 0x40,	/* Mask of asserted SEQ INTs */
+	PDC_HDMA_CTLSTAT	= 0x12C, /* Host DMA control / status */
+
+	PDC_20621_SEQCTL	= 0x400,
+	PDC_20621_SEQMASK	= 0x480,
+	PDC_20621_GENERAL_CTL	= 0x484,
+	PDC_20621_PAGE_SIZE	= (32 * 1024),
+
+	/* chosen, not constant, values; we design our own DIMM mem map */
+	PDC_20621_DIMM_WINDOW	= 0x0C,	/* page# for 32K DIMM window */
+	PDC_20621_DIMM_BASE	= 0x00200000,
+	PDC_20621_DIMM_DATA	= (64 * 1024),
+	PDC_DIMM_DATA_STEP	= (256 * 1024),
+	PDC_DIMM_WINDOW_STEP	= (8 * 1024),
+	PDC_DIMM_HOST_PRD	= (6 * 1024),
+	PDC_DIMM_HOST_PKT	= (128 * 0),
+	PDC_DIMM_HPKT_PRD	= (128 * 1),
+	PDC_DIMM_ATA_PKT	= (128 * 2),
+	PDC_DIMM_APKT_PRD	= (128 * 3),
+	PDC_DIMM_HEADER_SZ	= PDC_DIMM_APKT_PRD + 128,
+	PDC_PAGE_WINDOW		= 0x40,
+	PDC_PAGE_DATA		= PDC_PAGE_WINDOW +
+				  (PDC_20621_DIMM_DATA / PDC_20621_PAGE_SIZE),
+	PDC_PAGE_SET		= PDC_DIMM_DATA_STEP / PDC_20621_PAGE_SIZE,
+
+	PDC_CHIP0_OFS		= 0xC0000, /* offset of chip #0 */
+
+	PDC_20621_ERR_MASK	= (1<<19) | (1<<20) | (1<<21) | (1<<22) |
+				  (1<<23),
+
+	board_20621		= 0,	/* FastTrak S150 SX4 */
+
+	PDC_RESET		= (1 << 11), /* HDMA reset */
+
+	PDC_MAX_HDMA		= 32,
+	PDC_HDMA_Q_MASK		= (PDC_MAX_HDMA - 1),
+
+	PDC_DIMM0_SPD_DEV_ADDRESS     = 0x50,
+	PDC_DIMM1_SPD_DEV_ADDRESS     = 0x51,
+	PDC_MAX_DIMM_MODULE           = 0x02,
+	PDC_I2C_CONTROL_OFFSET        = 0x48,
+	PDC_I2C_ADDR_DATA_OFFSET      = 0x4C,
+	PDC_DIMM0_CONTROL_OFFSET      = 0x80,
+	PDC_DIMM1_CONTROL_OFFSET      = 0x84,
+	PDC_SDRAM_CONTROL_OFFSET      = 0x88,
+	PDC_I2C_WRITE                 = 0x00000000,
+	PDC_I2C_READ                  = 0x00000040,	
+	PDC_I2C_START                 = 0x00000080,
+	PDC_I2C_MASK_INT              = 0x00000020,
+	PDC_I2C_COMPLETE              = 0x00010000,
+	PDC_I2C_NO_ACK                = 0x00100000,
+	PDC_DIMM_SPD_SUBADDRESS_START = 0x00,
+	PDC_DIMM_SPD_SUBADDRESS_END   = 0x7F,
+	PDC_DIMM_SPD_ROW_NUM          = 3,
+	PDC_DIMM_SPD_COLUMN_NUM       = 4,
+	PDC_DIMM_SPD_MODULE_ROW       = 5,
+	PDC_DIMM_SPD_TYPE             = 11,
+	PDC_DIMM_SPD_FRESH_RATE       = 12,         
+	PDC_DIMM_SPD_BANK_NUM         = 17,	
+	PDC_DIMM_SPD_CAS_LATENCY      = 18,
+	PDC_DIMM_SPD_ATTRIBUTE        = 21,    
+	PDC_DIMM_SPD_ROW_PRE_CHARGE   = 27,
+	PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28,      
+	PDC_DIMM_SPD_RAS_CAS_DELAY    = 29,
+	PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30,
+	PDC_DIMM_SPD_SYSTEM_FREQ      = 126,
+	PDC_CTL_STATUS		      = 0x08,	
+	PDC_DIMM_WINDOW_CTLR	      = 0x0C,
+	PDC_TIME_CONTROL              = 0x3C,
+	PDC_TIME_PERIOD               = 0x40,
+	PDC_TIME_COUNTER              = 0x44,
+	PDC_GENERAL_CTLR	      = 0x484,
+	PCI_PLL_INIT                  = 0x8A531824,
+	PCI_X_TCOUNT                  = 0xEE1E5CFF
+};
+
+
+struct pdc_port_priv {
+	u8			dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512];
+	u8			*pkt;
+	dma_addr_t		pkt_dma;
+};
+
+struct pdc_host_priv {
+	void			*dimm_mmio;
+
+	unsigned int		doing_hdma;
+	unsigned int		hdma_prod;
+	unsigned int		hdma_cons;
+	struct {
+		struct ata_queued_cmd *qc;
+		unsigned int	seq;
+		unsigned long	pkt_ofs;
+	} hdma[32];
+};
+
+
+static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static void pdc20621_dma_start(struct ata_queued_cmd *qc);
+static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static void pdc_eng_timeout(struct ata_port *ap);
+static void pdc_20621_phy_reset (struct ata_port *ap);
+static int pdc_port_start(struct ata_port *ap);
+static void pdc_port_stop(struct ata_port *ap);
+static void pdc20621_fill_sg(struct ata_queued_cmd *qc);
+static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+static void pdc20621_host_stop(struct ata_host_set *host_set);
+static inline void pdc_dma_complete (struct ata_port *ap,
+                                     struct ata_queued_cmd *qc, int have_err);
+static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
+static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
+static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, 
+				      u32 device, u32 subaddr, u32 *pdata);
+static int pdc20621_prog_dimm0(struct ata_probe_ent *pe);
+static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe);
+#ifdef ATA_VERBOSE_DEBUG
+static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, 
+				   void *psource, u32 offset, u32 size);
+#endif
+static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, 
+				 void *psource, u32 offset, u32 size);
+
+
+static Scsi_Host_Template pdc_sata_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.bios_param		= ata_std_bios_param,
+};
+
+static struct ata_port_operations pdc_20621_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= pdc_tf_load_mmio,
+	.tf_read		= ata_tf_read_mmio,
+	.check_status		= ata_check_status_mmio,
+	.exec_command		= pdc_exec_command_mmio,
+	.phy_reset		= pdc_20621_phy_reset,
+	.bmdma_start            = pdc20621_dma_start,
+	.fill_sg		= pdc20621_fill_sg,
+	.eng_timeout		= pdc_eng_timeout,
+	.irq_handler		= pdc20621_interrupt,
+	.port_start		= pdc_port_start,
+	.port_stop		= pdc_port_stop,
+	.host_stop		= pdc20621_host_stop,
+};
+
+static struct ata_port_info pdc_port_info[] = {
+	/* board_20621 */
+	{
+		.sht		= &pdc_sata_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
+		.pio_mask	= 0x03, /* pio3-4 */
+		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
+		.port_ops	= &pdc_20621_ops,
+	},
+
+};
+
+static struct pci_device_id pdc_sata_pci_tbl[] = {
+	{ PCI_VENDOR_ID_PROMISE, 0x6622, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_20621 },
+	{ }	/* terminate list */
+};
+
+
+static struct pci_driver pdc_sata_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= pdc_sata_pci_tbl,
+	.probe			= pdc_sata_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+
+static void pdc20621_host_stop(struct ata_host_set *host_set)
+{
+	struct pdc_host_priv *hpriv = host_set->private_data;
+	void *dimm_mmio = hpriv->dimm_mmio;
+
+	iounmap(dimm_mmio);
+	kfree(hpriv);
+}
+
+static int pdc_port_start(struct ata_port *ap)
+{
+	struct pci_dev *pdev = ap->host_set->pdev;
+	struct pdc_port_priv *pp;
+	int rc;
+
+	rc = ata_port_start(ap);
+	if (rc)
+		return rc;
+
+	pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+	if (!pp) {
+		rc = -ENOMEM;
+		goto err_out;
+	}
+	memset(pp, 0, sizeof(*pp));
+
+	pp->pkt = pci_alloc_consistent(pdev, 128, &pp->pkt_dma);
+	if (!pp->pkt) {
+		rc = -ENOMEM;
+		goto err_out_kfree;
+	}
+
+	ap->private_data = pp;
+
+	return 0;
+
+err_out_kfree:
+	kfree(pp);
+err_out:
+	ata_port_stop(ap);
+	return rc;
+}
+
+
+static void pdc_port_stop(struct ata_port *ap)
+{
+	struct pci_dev *pdev = ap->host_set->pdev;
+	struct pdc_port_priv *pp = ap->private_data;
+
+	ap->private_data = NULL;
+	pci_free_consistent(pdev, 128, pp->pkt, pp->pkt_dma);
+	kfree(pp);
+	ata_port_stop(ap);
+}
+
+
+static void pdc_20621_phy_reset (struct ata_port *ap)
+{
+	VPRINTK("ENTER\n");
+        ap->cbl = ATA_CBL_SATA;
+        ata_port_probe(ap);
+        ata_bus_reset(ap);
+}
+
+static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
+				    	   unsigned int portno,
+					   unsigned int total_len)
+{
+	u32 addr;
+	unsigned int dw = PDC_DIMM_APKT_PRD >> 2;
+	u32 *buf32 = (u32 *) buf;
+
+	/* output ATA packet S/G table */
+	addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
+	       (PDC_DIMM_DATA_STEP * portno);
+	VPRINTK("ATA sg addr 0x%x, %d\n", addr, addr);
+	buf32[dw] = cpu_to_le32(addr);
+	buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
+
+	VPRINTK("ATA PSG @ %x == (0x%x, 0x%x)\n",
+		PDC_20621_DIMM_BASE +
+		       (PDC_DIMM_WINDOW_STEP * portno) +
+		       PDC_DIMM_APKT_PRD,
+		buf32[dw], buf32[dw + 1]);
+}
+
+static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf,
+				    	    unsigned int portno,
+					    unsigned int total_len)
+{
+	u32 addr;
+	unsigned int dw = PDC_DIMM_HPKT_PRD >> 2;
+	u32 *buf32 = (u32 *) buf;
+
+	/* output Host DMA packet S/G table */
+	addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
+	       (PDC_DIMM_DATA_STEP * portno);
+
+	buf32[dw] = cpu_to_le32(addr);
+	buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
+
+	VPRINTK("HOST PSG @ %x == (0x%x, 0x%x)\n",
+		PDC_20621_DIMM_BASE +
+		       (PDC_DIMM_WINDOW_STEP * portno) +
+		       PDC_DIMM_HPKT_PRD,
+		buf32[dw], buf32[dw + 1]);
+}
+
+static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf,
+					    unsigned int devno, u8 *buf,
+					    unsigned int portno)
+{
+	unsigned int i, dw;
+	u32 *buf32 = (u32 *) buf;
+	u8 dev_reg;
+
+	unsigned int dimm_sg = PDC_20621_DIMM_BASE +
+			       (PDC_DIMM_WINDOW_STEP * portno) +
+			       PDC_DIMM_APKT_PRD;
+	VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
+
+	i = PDC_DIMM_ATA_PKT;
+
+	/*
+	 * Set up ATA packet
+	 */
+	if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
+		buf[i++] = PDC_PKT_READ;
+	else if (tf->protocol == ATA_PROT_NODATA)
+		buf[i++] = PDC_PKT_NODATA;
+	else
+		buf[i++] = 0;
+	buf[i++] = 0;			/* reserved */
+	buf[i++] = portno + 1;		/* seq. id */
+	buf[i++] = 0xff;		/* delay seq. id */
+
+	/* dimm dma S/G, and next-pkt */
+	dw = i >> 2;
+	buf32[dw] = cpu_to_le32(dimm_sg);
+	buf32[dw + 1] = 0;
+	i += 8;
+
+	if (devno == 0)
+		dev_reg = ATA_DEVICE_OBS;
+	else
+		dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
+
+	/* select device */
+	buf[i++] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
+	buf[i++] = dev_reg;
+
+	/* device control register */
+	buf[i++] = (1 << 5) | PDC_REG_DEVCTL;
+	buf[i++] = tf->ctl;
+
+	return i;
+}
+
+static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf,
+				     unsigned int portno)
+{
+	unsigned int dw;
+	u32 tmp, *buf32 = (u32 *) buf;
+
+	unsigned int host_sg = PDC_20621_DIMM_BASE +
+			       (PDC_DIMM_WINDOW_STEP * portno) +
+			       PDC_DIMM_HOST_PRD;
+	unsigned int dimm_sg = PDC_20621_DIMM_BASE +
+			       (PDC_DIMM_WINDOW_STEP * portno) +
+			       PDC_DIMM_HPKT_PRD;
+	VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
+	VPRINTK("host_sg == 0x%x, %d\n", host_sg, host_sg);
+
+	dw = PDC_DIMM_HOST_PKT >> 2;
+
+	/*
+	 * Set up Host DMA packet
+	 */
+	if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
+		tmp = PDC_PKT_READ;
+	else
+		tmp = 0;
+	tmp |= ((portno + 1 + 4) << 16);	/* seq. id */
+	tmp |= (0xff << 24);			/* delay seq. id */
+	buf32[dw + 0] = cpu_to_le32(tmp);
+	buf32[dw + 1] = cpu_to_le32(host_sg);
+	buf32[dw + 2] = cpu_to_le32(dimm_sg);
+	buf32[dw + 3] = 0;
+
+	VPRINTK("HOST PKT @ %x == (0x%x 0x%x 0x%x 0x%x)\n",
+		PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * portno) +
+			PDC_DIMM_HOST_PKT,
+		buf32[dw + 0],
+		buf32[dw + 1],
+		buf32[dw + 2],
+		buf32[dw + 3]);
+}
+
+static void pdc20621_fill_sg(struct ata_queued_cmd *qc)
+{
+	struct scatterlist *sg = qc->sg;
+	struct ata_port *ap = qc->ap;
+	struct pdc_port_priv *pp = ap->private_data;
+	void *mmio = ap->host_set->mmio_base;
+	struct pdc_host_priv *hpriv = ap->host_set->private_data;
+	void *dimm_mmio = hpriv->dimm_mmio;
+	unsigned int portno = ap->port_no;
+	unsigned int i, last, idx, total_len = 0, sgt_len;
+	u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
+
+	VPRINTK("ata%u: ENTER\n", ap->id);
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	/*
+	 * Build S/G table
+	 */
+	last = qc->n_elem;
+	idx = 0;
+	for (i = 0; i < last; i++) {
+		buf[idx++] = cpu_to_le32(sg_dma_address(&sg[i]));
+		buf[idx++] = cpu_to_le32(sg_dma_len(&sg[i]));
+		total_len += sg[i].length;
+	}
+	buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT);
+	sgt_len = idx * 4;
+
+	/*
+	 * Build ATA, host DMA packets
+	 */
+	pdc20621_host_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
+	pdc20621_host_pkt(&qc->tf, &pp->dimm_buf[0], portno);
+
+	pdc20621_ata_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
+	i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
+
+	if (qc->tf.flags & ATA_TFLAG_LBA48)
+		i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
+	else
+		i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
+
+	pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
+
+	/* copy three S/G tables and two packets to DIMM MMIO window */
+	memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
+		    &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
+	memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP) +
+		    PDC_DIMM_HOST_PRD,
+		    &pp->dimm_buf[PDC_DIMM_HEADER_SZ], sgt_len);
+
+	/* force host FIFO dump */
+	writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
+
+	readl(dimm_mmio);	/* MMIO PCI posting flush */
+
+	VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len);
+}
+
+static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
+				 unsigned int seq,
+				 u32 pkt_ofs)
+{
+	struct ata_port *ap = qc->ap;
+	struct ata_host_set *host_set = ap->host_set;
+	void *mmio = host_set->mmio_base;
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
+	readl(mmio + PDC_20621_SEQCTL + (seq * 4));	/* flush */
+
+	writel(pkt_ofs, mmio + PDC_HDMA_PKT_SUBMIT);
+	readl(mmio + PDC_HDMA_PKT_SUBMIT);	/* flush */
+}
+
+static void pdc20621_push_hdma(struct ata_queued_cmd *qc,
+				unsigned int seq,
+				u32 pkt_ofs)
+{
+	struct ata_port *ap = qc->ap;
+	struct pdc_host_priv *pp = ap->host_set->private_data;
+	unsigned int idx = pp->hdma_prod & PDC_HDMA_Q_MASK;
+
+	if (!pp->doing_hdma) {
+		__pdc20621_push_hdma(qc, seq, pkt_ofs);
+		pp->doing_hdma = 1;
+		return;
+	}
+
+	pp->hdma[idx].qc = qc;
+	pp->hdma[idx].seq = seq;
+	pp->hdma[idx].pkt_ofs = pkt_ofs;
+	pp->hdma_prod++;
+}
+
+static void pdc20621_pop_hdma(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct pdc_host_priv *pp = ap->host_set->private_data;
+	unsigned int idx = pp->hdma_cons & PDC_HDMA_Q_MASK;
+
+	/* if nothing on queue, we're done */
+	if (pp->hdma_prod == pp->hdma_cons) {
+		pp->doing_hdma = 0;
+		return;
+	}
+
+	__pdc20621_push_hdma(pp->hdma[idx].qc, pp->hdma[idx].seq,
+			     pp->hdma[idx].pkt_ofs);
+	pp->hdma_cons++;
+}
+
+#ifdef ATA_VERBOSE_DEBUG
+static void pdc20621_dump_hdma(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	unsigned int port_no = ap->port_no;
+	struct pdc_host_priv *hpriv = ap->host_set->private_data;
+	void *dimm_mmio = hpriv->dimm_mmio;
+
+	dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP);
+	dimm_mmio += PDC_DIMM_HOST_PKT;
+
+	printk(KERN_ERR "HDMA[0] == 0x%08X\n", readl(dimm_mmio));
+	printk(KERN_ERR "HDMA[1] == 0x%08X\n", readl(dimm_mmio + 4));
+	printk(KERN_ERR "HDMA[2] == 0x%08X\n", readl(dimm_mmio + 8));
+	printk(KERN_ERR "HDMA[3] == 0x%08X\n", readl(dimm_mmio + 12));
+}
+#else
+static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { }
+#endif /* ATA_VERBOSE_DEBUG */
+
+static void pdc20621_dma_start(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct ata_host_set *host_set = ap->host_set;
+	unsigned int port_no = ap->port_no;
+	void *mmio = host_set->mmio_base;
+	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+	u8 seq = (u8) (port_no + 1);
+	unsigned int doing_hdma = 0, port_ofs;
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	VPRINTK("ata%u: ENTER\n", ap->id);
+
+	port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
+
+	/* if writing, we (1) DMA to DIMM, then (2) do ATA command */
+	if (rw) {
+		doing_hdma = 1;
+		seq += 4;
+	}
+
+	wmb();			/* flush PRD, pkt writes */
+
+	if (doing_hdma) {
+		pdc20621_dump_hdma(qc);
+		pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT);
+		VPRINTK("queued ofs 0x%x (%u), seq %u\n",
+			port_ofs + PDC_DIMM_HOST_PKT,
+			port_ofs + PDC_DIMM_HOST_PKT,
+			seq);
+	} else {
+		writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
+		readl(mmio + PDC_20621_SEQCTL + (seq * 4));	/* flush */
+
+		writel(port_ofs + PDC_DIMM_ATA_PKT,
+		       (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+		readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+		VPRINTK("submitted ofs 0x%x (%u), seq %u\n",
+			port_ofs + PDC_DIMM_ATA_PKT,
+			port_ofs + PDC_DIMM_ATA_PKT,
+			seq);
+	}
+}
+
+static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
+                                          struct ata_queued_cmd *qc,
+					  unsigned int doing_hdma,
+					  void *mmio)
+{
+	unsigned int port_no = ap->port_no;
+	unsigned int port_ofs =
+		PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
+	u8 status;
+	unsigned int handled = 0;
+
+	VPRINTK("ENTER\n");
+
+	if ((qc->tf.protocol == ATA_PROT_DMA) &&	/* read */
+	    (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
+
+		/* step two - DMA from DIMM to host */
+		if (doing_hdma) {
+			VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id,
+				readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+			pdc_dma_complete(ap, qc, 0);
+			pdc20621_pop_hdma(qc);
+		}
+
+		/* step one - exec ATA command */
+		else {
+			u8 seq = (u8) (port_no + 1 + 4);
+			VPRINTK("ata%u: read ata, 0x%x 0x%x\n", ap->id,
+				readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+
+			/* submit hdma pkt */
+			pdc20621_dump_hdma(qc);
+			pdc20621_push_hdma(qc, seq,
+					   port_ofs + PDC_DIMM_HOST_PKT);
+		}
+		handled = 1;
+
+	} else if (qc->tf.protocol == ATA_PROT_DMA) {	/* write */
+
+		/* step one - DMA from host to DIMM */
+		if (doing_hdma) {
+			u8 seq = (u8) (port_no + 1);
+			VPRINTK("ata%u: write hdma, 0x%x 0x%x\n", ap->id,
+				readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+
+			/* submit ata pkt */
+			writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
+			readl(mmio + PDC_20621_SEQCTL + (seq * 4));
+			writel(port_ofs + PDC_DIMM_ATA_PKT,
+			       (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+			readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+		}
+
+		/* step two - execute ATA command */
+		else {
+			VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id,
+				readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+			pdc_dma_complete(ap, qc, 0);
+			pdc20621_pop_hdma(qc);
+		}
+		handled = 1;
+
+	/* command completion, but no data xfer */
+	} else if (qc->tf.protocol == ATA_PROT_NODATA) {
+
+		status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+		DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status);
+		ata_qc_complete(qc, status, 0);
+		handled = 1;
+
+	} else {
+		ap->stats.idle_irq++;
+	}
+
+	return handled;
+}
+
+static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct ata_host_set *host_set = dev_instance;
+	struct ata_port *ap;
+	u32 mask = 0;
+	unsigned int i, tmp, port_no;
+	unsigned int handled = 0;
+	void *mmio_base;
+
+	VPRINTK("ENTER\n");
+
+	if (!host_set || !host_set->mmio_base) {
+		VPRINTK("QUICK EXIT\n");
+		return IRQ_NONE;
+	}
+
+	mmio_base = host_set->mmio_base;
+
+	/* reading should also clear interrupts */
+	mmio_base += PDC_CHIP0_OFS;
+	mask = readl(mmio_base + PDC_20621_SEQMASK);
+	VPRINTK("mask == 0x%x\n", mask);
+
+	if (mask == 0xffffffff) {
+		VPRINTK("QUICK EXIT 2\n");
+		return IRQ_NONE;
+	}
+	mask &= 0xffff;		/* only 16 tags possible */
+	if (!mask) {
+		VPRINTK("QUICK EXIT 3\n");
+		return IRQ_NONE;
+	}
+
+        spin_lock(&host_set->lock);
+
+        for (i = 1; i < 9; i++) {
+		port_no = i - 1;
+		if (port_no > 3)
+			port_no -= 4;
+		if (port_no >= host_set->n_ports)
+			ap = NULL;
+		else
+			ap = host_set->ports[port_no];
+		tmp = mask & (1 << i);
+		VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
+		if (tmp && ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+			struct ata_queued_cmd *qc;
+
+			qc = ata_qc_from_tag(ap, ap->active_tag);
+			if (qc && ((qc->flags & ATA_QCFLAG_POLL) == 0))
+				handled += pdc20621_host_intr(ap, qc, (i > 4),
+							      mmio_base);
+		}
+	}
+
+        spin_unlock(&host_set->lock);
+
+	VPRINTK("mask == 0x%x\n", mask);
+
+	VPRINTK("EXIT\n");
+
+	return IRQ_RETVAL(handled);
+}
+
+static inline void pdc_dma_complete (struct ata_port *ap,
+                                     struct ata_queued_cmd *qc,
+				     int have_err)
+{
+	u8 err_bit = have_err ? ATA_ERR : 0;
+
+	/* get drive status; clear intr; complete txn */
+	ata_qc_complete(ata_qc_from_tag(ap, ap->active_tag),
+			ata_wait_idle(ap) | err_bit, 0);
+}
+
+static void pdc_eng_timeout(struct ata_port *ap)
+{
+	u8 drv_stat;
+	struct ata_queued_cmd *qc;
+
+	DPRINTK("ENTER\n");
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	if (!qc) {
+		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
+		       ap->id);
+		goto out;
+	}
+
+	/* hack alert!  We cannot use the supplied completion
+	 * function from inside the ->eh_strategy_handler() thread.
+	 * libata is the only user of ->eh_strategy_handler() in
+	 * any kernel, so the default scsi_done() assumes it is
+	 * not being called from the SCSI EH.
+	 */
+	qc->scsidone = scsi_finish_command;
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+		printk(KERN_ERR "ata%u: DMA timeout\n", ap->id);
+		ata_qc_complete(ata_qc_from_tag(ap, ap->active_tag),
+			        ata_wait_idle(ap) | ATA_ERR, 0);
+		break;
+
+	case ATA_PROT_NODATA:
+		drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+
+		printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n",
+		       ap->id, qc->tf.command, drv_stat);
+
+		ata_qc_complete(qc, drv_stat, 1);
+		break;
+
+	default:
+		drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+
+		printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n",
+		       ap->id, qc->tf.command, drv_stat);
+
+		ata_qc_complete(qc, drv_stat, 1);
+		break;
+	}
+
+out:
+	DPRINTK("EXIT\n");
+}
+
+static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	if (tf->protocol == ATA_PROT_PIO)
+		ata_tf_load_mmio(ap, tf);
+}
+
+
+static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	if (tf->protocol == ATA_PROT_PIO)
+		ata_exec_command_mmio(ap, tf);
+}
+
+
+static void pdc_sata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+	port->cmd_addr		= base;
+	port->data_addr		= base;
+	port->feature_addr	=
+	port->error_addr	= base + 0x4;
+	port->nsect_addr	= base + 0x8;
+	port->lbal_addr		= base + 0xc;
+	port->lbam_addr		= base + 0x10;
+	port->lbah_addr		= base + 0x14;
+	port->device_addr	= base + 0x18;
+	port->command_addr	=
+	port->status_addr	= base + 0x1c;
+	port->altstatus_addr	=
+	port->ctl_addr		= base + 0x38;
+}
+
+
+#ifdef ATA_VERBOSE_DEBUG
+static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource, 
+				   u32 offset, u32 size)
+{
+	u32 window_size;
+	u16 idx;
+	u8 page_mask;
+	long dist;
+	void *mmio = pe->mmio_base;
+	struct pdc_host_priv *hpriv = pe->private_data;
+	void *dimm_mmio = hpriv->dimm_mmio;
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	page_mask = 0x00;	
+   	window_size = 0x2000 * 4; /* 32K byte uchar size */  
+	idx = (u16) (offset / window_size); 
+
+	writel(0x01, mmio + PDC_GENERAL_CTLR);
+	readl(mmio + PDC_GENERAL_CTLR);
+	writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+	readl(mmio + PDC_DIMM_WINDOW_CTLR);
+
+	offset -= (idx * window_size);
+	idx++;
+	dist = ((long) (window_size - (offset + size))) >= 0 ? size : 
+		(long) (window_size - offset);
+	memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4), 
+		      dist);
+
+	psource += dist;    
+	size -= dist;
+	for (; (long) size >= (long) window_size ;) {
+		writel(0x01, mmio + PDC_GENERAL_CTLR);
+		readl(mmio + PDC_GENERAL_CTLR);
+		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+		readl(mmio + PDC_DIMM_WINDOW_CTLR);
+		memcpy_fromio((char *) psource, (char *) (dimm_mmio), 
+			      window_size / 4);
+		psource += window_size;
+		size -= window_size;
+		idx ++;
+	}
+
+	if (size) {
+		writel(0x01, mmio + PDC_GENERAL_CTLR);
+		readl(mmio + PDC_GENERAL_CTLR);
+		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+		readl(mmio + PDC_DIMM_WINDOW_CTLR);
+		memcpy_fromio((char *) psource, (char *) (dimm_mmio), 
+			      size / 4);
+	}
+}
+#endif
+
+
+static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, 
+				 u32 offset, u32 size)
+{
+	u32 window_size;
+	u16 idx;
+	u8 page_mask;
+	long dist;
+	void *mmio = pe->mmio_base;
+	struct pdc_host_priv *hpriv = pe->private_data;
+	void *dimm_mmio = hpriv->dimm_mmio;
+
+	/* hard-code chip #0 */   
+	mmio += PDC_CHIP0_OFS;
+
+	page_mask = 0x00;	
+   	window_size = 0x2000 * 4;       /* 32K byte uchar size */  
+	idx = (u16) (offset / window_size);
+
+	writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+	readl(mmio + PDC_DIMM_WINDOW_CTLR);
+	offset -= (idx * window_size); 
+	idx++;
+	dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size :
+		(long) (window_size - offset);
+	memcpy_toio((char *) (dimm_mmio + offset / 4), (char *) psource, dist);
+	writel(0x01, mmio + PDC_GENERAL_CTLR);
+	readl(mmio + PDC_GENERAL_CTLR);
+
+	psource += dist;    
+	size -= dist;
+	for (; (long) size >= (long) window_size ;) {
+		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+		readl(mmio + PDC_DIMM_WINDOW_CTLR);
+		memcpy_toio((char *) (dimm_mmio), (char *) psource, 
+			    window_size / 4);
+		writel(0x01, mmio + PDC_GENERAL_CTLR);
+		readl(mmio + PDC_GENERAL_CTLR);
+		psource += window_size;
+		size -= window_size;
+		idx ++;
+	}
+    
+	if (size) {
+		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+		readl(mmio + PDC_DIMM_WINDOW_CTLR);
+		memcpy_toio((char *) (dimm_mmio), (char *) psource, size / 4);
+		writel(0x01, mmio + PDC_GENERAL_CTLR);
+		readl(mmio + PDC_GENERAL_CTLR);
+	}
+}
+
+
+static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, 
+				      u32 subaddr, u32 *pdata)
+{
+	void *mmio = pe->mmio_base;
+	u32 i2creg  = 0;
+	u32 status;     
+	u32 count =0;
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	i2creg |= device << 24;
+	i2creg |= subaddr << 16;
+
+	/* Set the device and subaddress */
+	writel(i2creg, mmio + PDC_I2C_ADDR_DATA_OFFSET);
+	readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
+
+	/* Write Control to perform read operation, mask int */
+	writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT, 
+	       mmio + PDC_I2C_CONTROL_OFFSET);
+
+	for (count = 0; count <= 1000; count ++) {
+		status = readl(mmio + PDC_I2C_CONTROL_OFFSET);
+		if (status & PDC_I2C_COMPLETE) {
+			status = readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
+			break;
+		} else if (count == 1000)
+			return 0;
+	}
+
+	*pdata = (status >> 8) & 0x000000ff;
+	return 1;           
+}
+
+
+static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
+{
+	u32 data=0 ;
+  	if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 
+			     PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {
+   		if (data == 100)
+			return 100;
+  	} else
+		return 0;
+ 	
+   	if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
+		if(data <= 0x75) 
+			return 133;
+   	} else
+		return 0;
+   	
+   	return 0;
+}
+
+
+static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
+{
+	u32 spd0[50];
+	u32 data = 0;
+   	int size, i;
+   	u8 bdimmsize; 
+   	void *mmio = pe->mmio_base;
+	static const struct {
+		unsigned int reg;
+		unsigned int ofs;
+	} pdc_i2c_read_data [] = {
+		{ PDC_DIMM_SPD_TYPE, 11 },		
+		{ PDC_DIMM_SPD_FRESH_RATE, 12 },
+		{ PDC_DIMM_SPD_COLUMN_NUM, 4 }, 
+		{ PDC_DIMM_SPD_ATTRIBUTE, 21 },
+		{ PDC_DIMM_SPD_ROW_NUM, 3 },
+		{ PDC_DIMM_SPD_BANK_NUM, 17 },
+		{ PDC_DIMM_SPD_MODULE_ROW, 5 },
+		{ PDC_DIMM_SPD_ROW_PRE_CHARGE, 27 },
+		{ PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 },
+		{ PDC_DIMM_SPD_RAS_CAS_DELAY, 29 },
+		{ PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 },
+		{ PDC_DIMM_SPD_CAS_LATENCY, 18 },       
+	};
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	for(i=0; i<ARRAY_SIZE(pdc_i2c_read_data); i++)
+		pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+				  pdc_i2c_read_data[i].reg, 
+				  &spd0[pdc_i2c_read_data[i].ofs]);
+  
+   	data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4);
+   	data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) | 
+		((((spd0[27] + 9) / 10) - 1) << 8) ;
+   	data |= (((((spd0[29] > spd0[28]) 
+		    ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10; 
+   	data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12;
+   
+   	if (spd0[18] & 0x08) 
+		data |= ((0x03) << 14);
+   	else if (spd0[18] & 0x04)
+		data |= ((0x02) << 14);
+   	else if (spd0[18] & 0x01)
+		data |= ((0x01) << 14);
+   	else
+		data |= (0 << 14);
+
+  	/* 
+	   Calculate the size of bDIMMSize (power of 2) and
+	   merge the DIMM size by program start/end address.
+	*/
+
+   	bdimmsize = spd0[4] + (spd0[5] / 2) + spd0[3] + (spd0[17] / 2) + 3;
+   	size = (1 << bdimmsize) >> 20;	/* size = xxx(MB) */
+   	data |= (((size / 16) - 1) << 16);
+   	data |= (0 << 23);
+	data |= 8;
+   	writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET); 
+	readl(mmio + PDC_DIMM0_CONTROL_OFFSET);
+   	return size;                          
+}
+
+
+static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
+{
+	u32 data, spd0;
+   	int error, i;
+   	void *mmio = pe->mmio_base;
+
+	/* hard-code chip #0 */
+   	mmio += PDC_CHIP0_OFS;
+
+   	/*
+	  Set To Default : DIMM Module Global Control Register (0x022259F1)
+	  DIMM Arbitration Disable (bit 20)
+	  DIMM Data/Control Output Driving Selection (bit12 - bit15)
+	  Refresh Enable (bit 17)
+	*/
+
+	data = 0x022259F1;   
+	writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
+	readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
+
+	/* Turn on for ECC */
+	pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 
+			  PDC_DIMM_SPD_TYPE, &spd0);
+	if (spd0 == 0x02) {
+		data |= (0x01 << 16);
+		writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
+		readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
+		printk(KERN_ERR "Local DIMM ECC Enabled\n");
+   	}
+
+   	/* DIMM Initialization Select/Enable (bit 18/19) */
+   	data &= (~(1<<18));
+   	data |= (1<<19);
+   	writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
+
+   	error = 1;                     
+   	for (i = 1; i <= 10; i++) {   /* polling ~5 secs */
+		data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
+		if (!(data & (1<<19))) {
+	   		error = 0;
+	   		break;     
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((i * 100) * HZ / 1000 + 1);
+   	}
+   	return error;
+}
+	
+
+static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
+{
+	int speed, size, length; 
+	u32 addr,spd0,pci_status;
+	u32 tmp=0;
+	u32 time_period=0;
+	u32 tcount=0;
+	u32 ticks=0;
+	u32 clock=0;
+	u32 fparam=0;
+   	void *mmio = pe->mmio_base;
+
+	/* hard-code chip #0 */
+   	mmio += PDC_CHIP0_OFS;
+
+	/* Initialize PLL based upon PCI Bus Frequency */
+
+	/* Initialize Time Period Register */
+	writel(0xffffffff, mmio + PDC_TIME_PERIOD);
+	time_period = readl(mmio + PDC_TIME_PERIOD);
+	VPRINTK("Time Period Register (0x40): 0x%x\n", time_period);
+
+	/* Enable timer */
+	writel(0x00001a0, mmio + PDC_TIME_CONTROL);
+	readl(mmio + PDC_TIME_CONTROL);
+
+	/* Wait 3 seconds */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(3 * HZ);
+
+	/* 
+	   When timer is enabled, counter is decreased every internal
+	   clock cycle.
+	*/
+
+	tcount = readl(mmio + PDC_TIME_COUNTER);
+	VPRINTK("Time Counter Register (0x44): 0x%x\n", tcount);
+
+	/* 
+	   If SX4 is on PCI-X bus, after 3 seconds, the timer counter
+	   register should be >= (0xffffffff - 3x10^8).
+	*/
+	if(tcount >= PCI_X_TCOUNT) {
+		ticks = (time_period - tcount);
+		VPRINTK("Num counters 0x%x (%d)\n", ticks, ticks);
+	
+		clock = (ticks / 300000);
+		VPRINTK("10 * Internal clk = 0x%x (%d)\n", clock, clock);
+		
+		clock = (clock * 33);
+		VPRINTK("10 * Internal clk * 33 = 0x%x (%d)\n", clock, clock);
+
+		/* PLL F Param (bit 22:16) */
+		fparam = (1400000 / clock) - 2;
+		VPRINTK("PLL F Param: 0x%x (%d)\n", fparam, fparam);
+		
+		/* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */
+		pci_status = (0x8a001824 | (fparam << 16));
+	} else
+		pci_status = PCI_PLL_INIT;
+
+	/* Initialize PLL. */
+	VPRINTK("pci_status: 0x%x\n", pci_status);
+	writel(pci_status, mmio + PDC_CTL_STATUS);
+	readl(mmio + PDC_CTL_STATUS);
+
+	/* 
+	   Read SPD of DIMM by I2C interface,
+	   and program the DIMM Module Controller.
+	*/
+ 	if (!(speed = pdc20621_detect_dimm(pe))) {
+		printk(KERN_ERR "Detect Local DIMM Fail\n");  
+		return 1;	/* DIMM error */
+   	}
+   	VPRINTK("Local DIMM Speed = %d\n", speed);
+
+   	/* Programming DIMM0 Module Control Register (index_CID0:80h) */ 
+   	size = pdc20621_prog_dimm0(pe);
+   	VPRINTK("Local DIMM Size = %dMB\n",size);
+
+   	/* Programming DIMM Module Global Control Register (index_CID0:88h) */ 
+   	if (pdc20621_prog_dimm_global(pe)) {
+		printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");
+		return 1;
+   	}
+
+#ifdef ATA_VERBOSE_DEBUG
+	{
+		u8 test_parttern1[40] = {0x55,0xAA,'P','r','o','m','i','s','e',' ',
+  				'N','o','t',' ','Y','e','t',' ','D','e','f','i','n','e','d',' ',
+ 				 '1','.','1','0',
+  				'9','8','0','3','1','6','1','2',0,0};
+		u8 test_parttern2[40] = {0};
+
+		pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x10040, 40);
+		pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x40, 40);
+
+		pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40);
+		pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
+		printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], 
+		       test_parttern2[1], &(test_parttern2[2]));
+		pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040, 
+				       40);
+		printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], 
+		       test_parttern2[1], &(test_parttern2[2]));
+
+		pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40);
+		pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
+		printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], 
+		       test_parttern2[1], &(test_parttern2[2]));
+	}
+#endif
+
+	/* ECC initiliazation. */
+
+	pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 
+			  PDC_DIMM_SPD_TYPE, &spd0);
+	if (spd0 == 0x02) {
+		VPRINTK("Start ECC initialization\n");
+		addr = 0;
+		length = size * 1024 * 1024;
+		while (addr < length) {
+			pdc20621_put_to_dimm(pe, (void *) &tmp, addr, 
+					     sizeof(u32));
+			addr += sizeof(u32);
+		}
+		VPRINTK("Finish ECC initialization\n");
+	}
+	return 0;
+}
+
+
+static void pdc_20621_init(struct ata_probe_ent *pe)
+{
+	u32 tmp;
+	void *mmio = pe->mmio_base;
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	/*
+	 * Select page 0x40 for our 32k DIMM window
+	 */
+	tmp = readl(mmio + PDC_20621_DIMM_WINDOW) & 0xffff0000;
+	tmp |= PDC_PAGE_WINDOW;	/* page 40h; arbitrarily selected */
+	writel(tmp, mmio + PDC_20621_DIMM_WINDOW);
+
+	/*
+	 * Reset Host DMA
+	 */
+	tmp = readl(mmio + PDC_HDMA_CTLSTAT);
+	tmp |= PDC_RESET;
+	writel(tmp, mmio + PDC_HDMA_CTLSTAT);
+	readl(mmio + PDC_HDMA_CTLSTAT);		/* flush */
+
+	udelay(10);
+
+	tmp = readl(mmio + PDC_HDMA_CTLSTAT);
+	tmp &= ~PDC_RESET;
+	writel(tmp, mmio + PDC_HDMA_CTLSTAT);
+	readl(mmio + PDC_HDMA_CTLSTAT);		/* flush */
+}
+
+static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	struct ata_probe_ent *probe_ent = NULL;
+	unsigned long base;
+	void *mmio_base, *dimm_mmio = NULL;
+	struct pdc_host_priv *hpriv = NULL;
+	unsigned int board_idx = (unsigned int) ent->driver_data;
+	int rc;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	/*
+	 * If this driver happens to only be useful on Apple's K2, then
+	 * we should check that here as it has a normal Serverworks ID
+	 */
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out;
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (probe_ent == NULL) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	probe_ent->pdev = pdev;
+	INIT_LIST_HEAD(&probe_ent->node);
+
+	mmio_base = ioremap(pci_resource_start(pdev, 3),
+		            pci_resource_len(pdev, 3));
+	if (mmio_base == NULL) {
+		rc = -ENOMEM;
+		goto err_out_free_ent;
+	}
+	base = (unsigned long) mmio_base;
+
+	hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
+	if (!hpriv) {
+		rc = -ENOMEM;
+		goto err_out_iounmap;
+	}
+	memset(hpriv, 0, sizeof(*hpriv));
+
+	dimm_mmio = ioremap(pci_resource_start(pdev, 4),
+			    pci_resource_len(pdev, 4));
+	if (!dimm_mmio) {
+		kfree(hpriv);
+		rc = -ENOMEM;
+		goto err_out_iounmap;
+	}
+
+	hpriv->dimm_mmio = dimm_mmio;
+
+	probe_ent->sht		= pdc_port_info[board_idx].sht;
+	probe_ent->host_flags	= pdc_port_info[board_idx].host_flags;
+	probe_ent->pio_mask	= pdc_port_info[board_idx].pio_mask;
+	probe_ent->udma_mask	= pdc_port_info[board_idx].udma_mask;
+	probe_ent->port_ops	= pdc_port_info[board_idx].port_ops;
+
+       	probe_ent->irq = pdev->irq;
+       	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->mmio_base = mmio_base;
+
+	probe_ent->private_data = hpriv;
+	base += PDC_CHIP0_OFS;
+
+	pdc_sata_setup_port(&probe_ent->port[0], base + 0x200);
+	pdc_sata_setup_port(&probe_ent->port[1], base + 0x280);
+
+	/* notice 4-port boards */
+	switch (board_idx) {
+	case board_20621:
+       		probe_ent->n_ports = 4;
+
+		pdc_sata_setup_port(&probe_ent->port[2], base + 0x300);
+		pdc_sata_setup_port(&probe_ent->port[3], base + 0x380);
+		break;
+	default:
+		BUG();
+		break;
+	}
+
+	pci_set_master(pdev);
+
+	/* initialize adapter */
+	/* initialize local dimm */
+	if (pdc20621_dimm_init(probe_ent)) {
+		rc = -ENOMEM;
+		goto err_out_iounmap_dimm;
+	}
+	pdc_20621_init(probe_ent);
+
+	/* FIXME: check ata_device_add return value */
+	ata_device_add(probe_ent);
+	kfree(probe_ent);
+
+	return 0;
+
+err_out_iounmap_dimm:		/* only get to this label if 20621 */
+	kfree(hpriv);
+	iounmap(dimm_mmio);
+err_out_iounmap:
+	iounmap(mmio_base);
+err_out_free_ent:
+	kfree(probe_ent);
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	pci_disable_device(pdev);
+	return rc;
+}
+
+
+static int __init pdc_sata_init(void)
+{
+	return pci_module_init(&pdc_sata_pci_driver);
+}
+
+
+static void __exit pdc_sata_exit(void)
+{
+	pci_unregister_driver(&pdc_sata_pci_driver);
+}
+
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("Promise SATA low-level driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pdc_sata_pci_tbl);
+
+module_init(pdc_sata_init);
+module_exit(pdc_sata_exit);
diff -Nru a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
--- a/drivers/scsi/sata_vsc.c	Tue May  4 22:11:45 2004
+++ b/drivers/scsi/sata_vsc.c	Tue May  4 22:11:45 2004
@@ -44,6 +44,8 @@
 #define VSC_SATA_TF_CTL_OFFSET		0x29
 
 /* DMA base */
+#define VSC_SATA_UP_DESCRIPTOR_OFFSET	0x64
+#define VSC_SATA_UP_DATA_BUFFER_OFFSET	0x6C
 #define VSC_SATA_DMA_CMD_OFFSET		0x70
 
 /* SCRs base */
@@ -234,6 +236,8 @@
 	port->ctl_addr		= base + VSC_SATA_TF_CTL_OFFSET;
 	port->bmdma_addr	= base + VSC_SATA_DMA_CMD_OFFSET;
 	port->scr_addr		= base + VSC_SATA_SCR_STATUS_OFFSET;
+	writel(0, base + VSC_SATA_UP_DESCRIPTOR_OFFSET);
+	writel(0, base + VSC_SATA_UP_DATA_BUFFER_OFFSET);
 }
 
 
diff -Nru a/include/linux/libata.h b/include/linux/libata.h
--- a/include/linux/libata.h	Tue May  4 22:11:45 2004
+++ b/include/linux/libata.h	Tue May  4 22:11:45 2004
@@ -27,6 +27,7 @@
 #include <linux/interrupt.h>
 #include <asm/io.h>
 #include <linux/ata.h>
+#include <linux/workqueue.h>
 
 /*
  * compile-time options
@@ -113,9 +114,6 @@
 	ATA_QCFLAG_SG		= (1 << 4), /* have s/g table? */
 	ATA_QCFLAG_POLL		= (1 << 5), /* polling, no interrupts */
 
-	/* struct ata_engine atomic flags (use test_bit, etc.) */
-	ATA_EFLG_ACTIVE		= 0,	/* engine is active */
-
 	/* various lengths of time */
 	ATA_TMOUT_EDD		= 5 * HZ,	/* hueristic */
 	ATA_TMOUT_PIO		= 30 * HZ,
@@ -144,13 +142,6 @@
 	THR_IDLE		= (THR_PROBE_FAILED + 1),
 	THR_PROBE_SUCCESS	= (THR_IDLE + 1),
 	THR_PROBE_START		= (THR_PROBE_SUCCESS + 1),
-	THR_PIO_POLL		= (THR_PROBE_START + 1),
-	THR_PIO_TMOUT		= (THR_PIO_POLL + 1),
-	THR_PIO			= (THR_PIO_TMOUT + 1),
-	THR_PIO_LAST		= (THR_PIO + 1),
-	THR_PIO_LAST_POLL	= (THR_PIO_LAST + 1),
-	THR_PIO_ERR		= (THR_PIO_LAST_POLL + 1),
-	THR_PACKET		= (THR_PIO_ERR + 1),
 
 	/* SATA port states */
 	PORT_UNKNOWN		= 0,
@@ -163,6 +154,17 @@
 	ATA_QCFLAG_TIMEOUT	= (1 << 0),
 };
 
+enum pio_task_states {
+	PIO_ST_UNKNOWN,
+	PIO_ST_IDLE,
+	PIO_ST_POLL,
+	PIO_ST_TMOUT,
+	PIO_ST,
+	PIO_ST_LAST,
+	PIO_ST_LAST_POLL,
+	PIO_ST_ERR,
+};
+
 /* forward declarations */
 struct scsi_device;
 struct ata_port_operations;
@@ -224,7 +226,6 @@
 	struct scsi_cmnd	*scsicmd;
 	void			(*scsidone)(struct scsi_cmnd *);
 
-	struct list_head	node;
 	unsigned long		flags;		/* ATA_QCFLAG_xxx */
 	unsigned int		tag;
 	unsigned int		n_elem;
@@ -239,7 +240,7 @@
 
 	ata_qc_cb_t		callback;
 
-	struct semaphore	sem;
+	struct completion	*waiting;
 
 	void			*private_data;
 };
@@ -271,11 +272,6 @@
 	u8			write_cmd;	/* opcode to use on write */
 };
 
-struct ata_engine {
-	unsigned long		flags;
-	struct list_head	q;
-};
-
 struct ata_port {
 	struct Scsi_Host	*host;	/* our co-allocated scsi host */
 	struct ata_port_operations	*ops;
@@ -296,8 +292,6 @@
 	unsigned int		udma_mask;
 	unsigned int		cbl;	/* cable type; ATA_CBL_xxx */
 
-	struct ata_engine	eng;
-
 	struct ata_device	device[ATA_MAX_DEVICES];
 
 	struct ata_queued_cmd	qcmd[ATA_MAX_QUEUE];
@@ -307,16 +301,17 @@
 	struct ata_host_stats	stats;
 	struct ata_host_set	*host_set;
 
-	struct semaphore	sem;
 	struct semaphore	probe_sem;
 
 	unsigned int		thr_state;
-	int			time_to_die;
-	pid_t			thr_pid;
-	struct completion	thr_exited;
-	struct semaphore	thr_sem;
-	struct timer_list	thr_timer;
-	unsigned long		thr_timeout;
+
+	struct work_struct	packet_task;
+
+	struct work_struct	pio_task;
+	unsigned int		pio_task_state;
+	unsigned long		pio_task_timeout;
+
+	struct work_struct	probe_task;
 
 	void			*private_data;
 };
@@ -392,6 +387,8 @@
 extern void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf);
 extern void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf);
 extern void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+extern void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp);
+extern void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf);
 extern u8 ata_check_status_pio(struct ata_port *ap);
 extern u8 ata_check_status_mmio(struct ata_port *ap);
 extern void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf);
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	Tue May  4 22:11:45 2004
+++ b/include/linux/pci_ids.h	Tue May  4 22:11:45 2004
@@ -572,7 +572,6 @@
 #define PCI_DEVICE_ID_SI_503		0x0008
 #define PCI_DEVICE_ID_SI_ACPI		0x0009
 #define PCI_DEVICE_ID_SI_LPC		0x0018
-#define PCI_DEVICE_ID_SI_180		0x0180
 #define PCI_DEVICE_ID_SI_5597_VGA	0x0200
 #define PCI_DEVICE_ID_SI_6205		0x0205
 #define PCI_DEVICE_ID_SI_501		0x0406