bk://gkernel.bkbits.net/libata-2.6 jgarzik@redhat.com|ChangeSet|20040402182304|06020 jgarzik # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/04/02 13:23:04-05:00 jgarzik@redhat.com # Merge redhat.com:/spare/repo/linux-2.6 # into redhat.com:/spare/repo/libata-2.6 # # include/linux/pci_ids.h # 2004/04/02 13:23:00-05:00 jgarzik@redhat.com +0 -0 # Auto merged # # drivers/scsi/sata_via.c # 2004/04/02 13:23:00-05:00 jgarzik@redhat.com +0 -15 # Auto merged # # ChangeSet # 2004/03/31 14:51:55-05:00 jgarzik@redhat.com # [libata sata_via] Fix detection of device 1 # # VIA hardware thinks port 1 (second port) is "SATA primary slave". # Since the hardware rarely configures SATA to present as slave devices, # we must pretend that the second hardware port (as the user sees it) # is the third port (as the VIA PCI config registers see it). # # drivers/scsi/sata_via.c # 2004/03/31 14:51:50-05:00 jgarzik@redhat.com +15 -10 # [libata sata_via] Fix detection of device 1 # # VIA hardware thinks port 1 (second port) is "SATA primary slave". # Since the hardware rarely configures SATA to present as slave devices, # we must pretend that the second hardware port (as the user sees it) # is the third port (as the VIA PCI config registers see it). # # ChangeSet # 2004/03/30 16:42:18-05:00 jgarzik@redhat.com # [libata] fix broken delay # # Due to rounding and HZ==100, sometimes delays would not occur for # the desired length of time, or even at all. # # Fix call to schedule_timeout() to ensure we delay -at least- for # the correct amount of time. # # drivers/scsi/libata-core.c # 2004/03/30 11:42:11-05:00 jgarzik@redhat.com +1 -1 # [libata] fix broken delay # # Due to rounding and HZ==100, sometimes delays would not occur for # the desired length of time, or even at all. # # Fix call to schedule_timeout() to ensure we delay -at least- for # the correct amount of time. # # ChangeSet # 2004/03/29 19:30:47-05:00 jgarzik@redhat.com # [libata] back out duplicated upstream fix # # We already fixed this bug locally, so fix up the automerge # by removing the upstream change. # # drivers/scsi/libata-scsi.c # 2004/03/29 19:30:42-05:00 jgarzik@redhat.com +0 -2 # [libata] back out duplicated upstream fix # # We already fixed this bug locally, so fix up the automerge # by removing the upstream change. # # ChangeSet # 2004/03/29 19:28:22-05:00 jgarzik@redhat.com # Merge redhat.com:/spare/repo/linux-2.6 # into redhat.com:/spare/repo/libata-2.6 # # drivers/scsi/libata-scsi.c # 2004/03/29 19:28:20-05:00 jgarzik@redhat.com +0 -0 # Auto merged # # ChangeSet # 2004/03/27 00:21:34-05:00 jgarzik@redhat.com # [libata] remove synchronize-cache dead code # # Just a placeholder, and now that a better way to do this is coming, # we don't even need the [unused] placeholder anymore. # # drivers/scsi/libata-scsi.c # 2004/03/27 00:21:29-05:00 jgarzik@redhat.com +0 -31 # [libata] remove synchronize-cache dead code # # Just a placeholder, and now that a better way to do this is coming, # we don't even need the [unused] placeholder anymore. # # ChangeSet # 2004/03/26 22:14:11-05:00 jgarzik@redhat.com # [libata] fix bug with READ(6) and WRITE(6) SCSI commands # # Must set the LBA bit on all transfers, not just {read,write}{10,16} # scsi commands. # # drivers/scsi/libata-scsi.c # 2004/03/26 22:14:06-05:00 jgarzik@redhat.com +1 -4 # [libata] fix bug with READ(6) and WRITE(6) SCSI commands # # Must set the LBA bit on all transfers, not just {read,write}{10,16} # scsi commands. # # ChangeSet # 2004/03/26 20:40:58-05:00 jgarzik@redhat.com # [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_promise.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 # # ChangeSet # 2004/03/26 19:33:40-05:00 jgarzik@redhat.com # Merge redhat.com:/spare/repo/linux-2.6 # into redhat.com:/spare/repo/libata-2.6 # # include/linux/pci_ids.h # 2004/03/26 19:33:38-05:00 jgarzik@redhat.com +0 -0 # Auto merged # # ChangeSet # 2004/03/26 18:02:34-05:00 jgarzik@redhat.com # [libata] more documentation # # libata-scsi.c should now be fully documented. # # drivers/scsi/libata-scsi.c # 2004/03/26 18:02:29-05:00 jgarzik@redhat.com +125 -31 # [libata] more documentation # # libata-scsi.c should now be fully documented. # # ChangeSet # 2004/03/26 04:04:17-05:00 jgarzik@redhat.com # [libata] more cmd queue path cleanups # # Final part in tonight's series of changes to clean up the # command queueing path. # # The simulate-ATA-over-SCSI code is moved to a new function, # ata_scsi_simulate(), and ata_scsi_rw_queue() is renamed to # ata_scsi_translate(). With the SCSI CDB debugging dump function # also moved into its own function, the queue-command path is now # nice, compact, and readable. # # drivers/scsi/libata-scsi.c # 2004/03/26 04:04:12-05:00 jgarzik@redhat.com +50 -27 # [libata] more cmd queue path cleanups # # Final part in tonight's series of changes to clean up the # command queueing path. # # The simulate-ATA-over-SCSI code is moved to a new function, # ata_scsi_simulate(), and ata_scsi_rw_queue() is renamed to # ata_scsi_translate(). With the SCSI CDB debugging dump function # also moved into its own function, the queue-command path is now # nice, compact, and readable. # # ChangeSet # 2004/03/26 03:32:10-05:00 jgarzik@redhat.com # [libata] more command queue path cleanup # # A new helper ata_scsi_xlat_possible(), and the command queue path # gets a bit more compact. # # As side effects we kill the 'cmd_size' argument from two functions, # and mark ata_scsi_rw_queue() as static, as its only needed # in libata-scsi.c. # # drivers/scsi/libata.h # 2004/03/26 03:32:05-05:00 jgarzik@redhat.com +0 -3 # [libata] more command queue path cleanup # # A new helper ata_scsi_xlat_possible(), and the command queue path # gets a bit more compact. # # As side effects we kill the 'cmd_size' argument from two functions, # and mark ata_scsi_rw_queue() as static, as its only needed # in libata-scsi.c. # # drivers/scsi/libata-scsi.c # 2004/03/26 03:32:05-05:00 jgarzik@redhat.com +28 -29 # [libata] more command queue path cleanup # # A new helper ata_scsi_xlat_possible(), and the command queue path # gets a bit more compact. # # As side effects we kill the 'cmd_size' argument from two functions, # and mark ata_scsi_rw_queue() as static, as its only needed # in libata-scsi.c. # # ChangeSet # 2004/03/26 03:20:47-05:00 jgarzik@redhat.com # [libata] clean up command queue/submit path a bit # # This change is part of a series that compartmentalizes and consolidates # ATA taskfile submission. # # Here, the device-location-related checks are moved out of the ->queuecommand() # hook and into an inline helper function. # # drivers/scsi/libata-scsi.c # 2004/03/26 03:20:42-05:00 jgarzik@redhat.com +38 -32 # [libata] clean up command queue/submit path a bit # # This change is part of a series that compartmentalizes and consolidates # ATA taskfile submission. # # Here, the device-location-related checks are moved out of the ->queuecommand() # hook and into an inline helper function. # # ChangeSet # 2004/03/26 01:13:20-05:00 jgarzik@redhat.com # [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_promise.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. # # ChangeSet # 2004/03/25 17:23:41-05:00 jgarzik@redhat.com # [libata] documentation, and a couple tiny cleanups # # Add more per-function source code documentation. Some of this stuff # is esoteric ATA crapola, and definitely needed to be documented. # # Also, two tiny cleanups spotted while documenting: # * kill unused arg from internal function ata_dev_try_classify() # * kill unused return value from ata_dev_id_string() # # drivers/scsi/libata.h # 2004/03/25 17:23:37-05:00 jgarzik@redhat.com +2 -2 # [libata] documentation, and a couple tiny cleanups # # Add more per-function source code documentation. Some of this stuff # is esoteric ATA crapola, and definitely needed to be documented. # # Also, two tiny cleanups spotted while documenting: # * kill unused arg from internal function ata_dev_try_classify() # * kill unused return value from ata_dev_id_string() # # drivers/scsi/libata-core.c # 2004/03/25 17:23:37-05:00 jgarzik@redhat.com +125 -50 # [libata] documentation, and a couple tiny cleanups # # Add more per-function source code documentation. Some of this stuff # is esoteric ATA crapola, and definitely needed to be documented. # # Also, two tiny cleanups spotted while documenting: # * kill unused arg from internal function ata_dev_try_classify() # * kill unused return value from ata_dev_id_string() # # ChangeSet # 2004/03/25 14:40:17-05:00 jgarzik@redhat.com # [libata] use scsi host lock # # In 2.4 we release io_request_lock and take our own per-host lock, # in the ->queuecommand() hook. In 2.6, the SCSI layer provides a # useful to simply use the lock we already have, via scsi_assign_lock(). # # drivers/scsi/libata-scsi.c # 2004/03/25 14:40:12-05:00 jgarzik@redhat.com +1 -8 # [libata] use scsi host lock # # In 2.4 we release io_request_lock and take our own per-host lock, # in the ->queuecommand() hook. In 2.6, the SCSI layer provides a # useful to simply use the lock we already have, via scsi_assign_lock(). # # drivers/scsi/libata-core.c # 2004/03/25 14:40:12-05:00 jgarzik@redhat.com +1 -0 # [libata] use scsi host lock # # In 2.4 we release io_request_lock and take our own per-host lock, # in the ->queuecommand() hook. In 2.6, the SCSI layer provides a # useful to simply use the lock we already have, via scsi_assign_lock(). # # ChangeSet # 2004/03/25 14:36:59-05:00 jgarzik@redhat.com # [libata] reduce diff with 2.4 libata backport # # include/linux/libata.h # 2004/03/25 14:36:54-05:00 jgarzik@redhat.com +1 -1 # [libata] reduce diff with 2.4 libata backport # # ChangeSet # 2004/03/25 14:36:27-05:00 jgarzik@redhat.com # [libata] pci_dma_error() was renamed to pci_dma_mapping_error() # # drivers/scsi/libata-core.c # 2004/03/25 14:36:22-05:00 jgarzik@redhat.com +1 -1 # [libata] pci_dma_error() was renamed to pci_dma_mapping_error() # # ChangeSet # 2004/03/25 14:18:04-05:00 jgarzik@redhat.com # Merge redhat.com:/spare/repo/linux-2.6 # into redhat.com:/spare/repo/libata-2.6 # # drivers/scsi/Kconfig # 2004/03/25 14:18:02-05:00 jgarzik@redhat.com +0 -0 # Auto merged # # ChangeSet # 2004/03/25 01:57:34-05:00 jgarzik@redhat.com # [ata] move some generic stuff linux/libata.h -> linux/ata.h # # struct ata_taskfile is generic, and so far its flags (ATA_TFLAG_xxx) # # Also, move ATA_PROT_xxx definitions into their own enum. # # include/linux/libata.h # 2004/03/25 01:57:29-05:00 jgarzik@redhat.com +0 -29 # [ata] move some generic stuff linux/libata.h -> linux/ata.h # # struct ata_taskfile is generic, and so far its flags (ATA_TFLAG_xxx) # # Also, move ATA_PROT_xxx definitions into their own enum. # # include/linux/ata.h # 2004/03/25 01:57:29-05:00 jgarzik@redhat.com +41 -8 # [ata] move some generic stuff linux/libata.h -> linux/ata.h # # struct ata_taskfile is generic, and so far its flags (ATA_TFLAG_xxx) # # Also, move ATA_PROT_xxx definitions into their own enum. # # ChangeSet # 2004/03/25 01:44:08-05:00 jgarzik@redhat.com # [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). # # include/linux/libata.h # 2004/03/25 01:44:03-05:00 jgarzik@redhat.com +3 -4 # [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). # # include/linux/ata.h # 2004/03/25 01:44:03-05:00 jgarzik@redhat.com +2 -4 # [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_promise.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/libata-scsi.c # 2004/03/25 01:44:03-05:00 jgarzik@redhat.com +4 -6 # [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/libata-core.c # 2004/03/25 01:44:03-05:00 jgarzik@redhat.com +15 -23 # [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). # # ChangeSet # 2004/03/25 00:53:07-05:00 jgarzik@redhat.com # [libata] set up some of the per-command data beforehand # # The data transfer mode and the set of read/write commands we generate # during normal operation remains constant until we change the data # transfer mode. # # This removes a series of branches in the read/write fast path, # and in general cleans up that particular spot of code. # # include/linux/libata.h # 2004/03/25 00:53:02-05:00 jgarzik@redhat.com +6 -0 # [libata] set up some of the per-command data beforehand # # The data transfer mode and the set of read/write commands we generate # during normal operation remains constant until we change the data # transfer mode. # # This removes a series of branches in the read/write fast path, # and in general cleans up that particular spot of code. # # drivers/scsi/libata-scsi.c # 2004/03/25 00:53:02-05:00 jgarzik@redhat.com +4 -27 # [libata] set up some of the per-command data beforehand # # The data transfer mode and the set of read/write commands we generate # during normal operation remains constant until we change the data # transfer mode. # # This removes a series of branches in the read/write fast path, # and in general cleans up that particular spot of code. # # drivers/scsi/libata-core.c # 2004/03/25 00:53:02-05:00 jgarzik@redhat.com +65 -7 # [libata] set up some of the per-command data beforehand # # The data transfer mode and the set of read/write commands we generate # during normal operation remains constant until we change the data # transfer mode. # # This removes a series of branches in the read/write fast path, # and in general cleans up that particular spot of code. # # ChangeSet # 2004/03/24 23:50:34-05:00 jgarzik@redhat.com # [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_promise.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. # # ChangeSet # 2004/03/23 12:35:54-05:00 jgarzik@redhat.com # [libata ata_piix] fix combined mode device detection # # SATA port detection should not have assumed that a single SATA port # mapped to a single struct ata_port. Combined mode breaks this # assumption. # # Change code to simply detect if one or more devices are present # on the struct ata_port, which is what we really wanted to do. # # drivers/scsi/ata_piix.c # 2004/03/23 12:35:45-05:00 jgarzik@redhat.com +36 -29 # [libata ata_piix] fix combined mode device detection # # SATA port detection should not have assumed that a single SATA port # mapped to a single struct ata_port. Combined mode breaks this # assumption. # # Change code to simply detect if one or more devices are present # on the struct ata_port, which is what we really wanted to do. # # ChangeSet # 2004/03/23 11:52:00-05:00 jgarzik@redhat.com # [libata ata_piix] clean up combined mode handling # # drivers/scsi/ata_piix.c # 2004/03/23 11:51:55-05:00 jgarzik@redhat.com +24 -39 # [libata ata_piix] clean up combined mode handling # # ChangeSet # 2004/03/23 11:14:06-05:00 jgarzik@redhat.com # [libata ata_piix] do not disable SATA port on module unload # # We were disabling the SATA port, but not enabling it on module load. # So, modprobe+rmmod+modprobe would fail. # # drivers/scsi/ata_piix.c # 2004/03/23 11:14:01-05:00 jgarzik@redhat.com +11 -52 # [libata ata_piix] do not disable SATA port on module unload # # We were disabling the SATA port, but not enabling it on module load. # So, modprobe+rmmod+modprobe would fail. # # ChangeSet # 2004/03/23 09:20:14-05:00 jgarzik@redhat.com # [libata] use kmap_atomic() rather than kmap() # # drivers/scsi/libata-scsi.c # 2004/03/23 09:20:09-05:00 jgarzik@redhat.com +2 -3 # [libata] use kmap_atomic() rather than kmap() # # ChangeSet # 2004/03/22 23:40:01-05:00 jgarzik@redhat.com # [libata] use new pci_dma_error() to check for pci_map_single() failure # # drivers/scsi/libata-core.c # 2004/03/22 23:38:20-05:00 jgarzik@redhat.com +7 -3 # [libata] use new pci_dma_error() to check for pci_map_single() failure # # ChangeSet # 2004/03/21 12:15:16-05:00 jgarzik@redhat.com # [libata sata_sis] minor cleanups # # include/linux/pci_ids.h # 2004/03/21 12:15:11-05:00 jgarzik@redhat.com +1 -0 # [libata sata_sis] minor cleanups # # drivers/scsi/sata_sis.c # 2004/03/21 12:15:11-05:00 jgarzik@redhat.com +24 -33 # [libata sata_sis] minor cleanups # # ChangeSet # 2004/03/21 11:55:35-05:00 uwe.koziolek@gmx.net # [libata] Add driver for SiS 964/180 SATA. # # drivers/scsi/Makefile # 2004/03/21 11:54:11-05:00 uwe.koziolek@gmx.net +1 -0 # [libata] Add driver for SiS 964/180 SATA. # # drivers/scsi/Kconfig # 2004/03/21 11:54:11-05:00 uwe.koziolek@gmx.net +8 -0 # [libata] Add driver for SiS 964/180 SATA. # # drivers/scsi/sata_sis.c # 2004/03/21 11:53:36-05:00 jgarzik@redhat.com +223 -0 # # drivers/scsi/sata_sis.c # 2004/03/21 11:53:36-05:00 jgarzik@redhat.com +0 -0 # BitKeeper file /spare/repo/libata-2.6/drivers/scsi/sata_sis.c # diff -Nru a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig --- a/drivers/scsi/Kconfig Thu Apr 8 14:58:15 2004 +++ b/drivers/scsi/Kconfig Thu Apr 8 14:58:15 2004 @@ -449,6 +449,14 @@ If unsure, say N. +config SCSI_SATA_SIS + tristate "SiS 964/180 SATA support" + depends on SCSI_SATA && PCI + help + This option enables support for SiS Serial ATA 964/180. + + If unsure, say N. + config SCSI_SATA_VIA tristate "VIA SATA support" depends on SCSI_SATA && PCI && EXPERIMENTAL diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile --- a/drivers/scsi/Makefile Thu Apr 8 14:58:15 2004 +++ b/drivers/scsi/Makefile Thu Apr 8 14:58:15 2004 @@ -123,6 +123,7 @@ obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o 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_ARM) += arm/ diff -Nru a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c --- a/drivers/scsi/ata_piix.c Thu Apr 8 14:58:15 2004 +++ b/drivers/scsi/ata_piix.c Thu Apr 8 14:58:15 2004 @@ -28,17 +28,24 @@ #include #define DRV_NAME "ata_piix" -#define DRV_VERSION "1.01" +#define DRV_VERSION "1.02" enum { PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ + ICH5_PMR = 0x90, /* port mapping register */ ICH5_PCS = 0x92, /* port control and status */ PIIX_FLAG_CHECKINTR = (1 << 29), /* make sure PCI INTx enabled */ PIIX_FLAG_COMBINED = (1 << 30), /* combined mode possible */ - PIIX_COMB_PRI = (1 << 0), /* combined mode, PATA primary */ - PIIX_COMB_SEC = (1 << 1), /* combined mode, PATA secondary */ + /* combined mode. if set, PATA is channel 0. + * if clear, PATA is channel 1. + */ + PIIX_COMB_PATA_P0 = (1 << 1), + PIIX_COMB = (1 << 2), /* combined mode enabled? */ + + PIIX_PORT_PRESENT = (1 << 0), + PIIX_PORT_ENABLED = (1 << 4), PIIX_80C_PRI = (1 << 5) | (1 << 4), PIIX_80C_SEC = (1 << 7) | (1 << 6), @@ -53,7 +60,6 @@ static void piix_pata_phy_reset(struct ata_port *ap); static void piix_sata_phy_reset(struct ata_port *ap); -static void piix_sata_port_disable(struct ata_port *ap); static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev, unsigned int pio); static void piix_set_udmamode (struct ata_port *ap, struct ata_device *adev, @@ -137,7 +143,7 @@ }; static struct ata_port_operations piix_sata_ops = { - .port_disable = piix_sata_port_disable, + .port_disable = ata_port_disable, .set_piomode = piix_set_piomode, .set_udmamode = piix_set_udmamode, @@ -259,54 +265,48 @@ } /** - * piix_pcs_probe - Probe SATA port configuration and status register - * @ap: Port to probe - * @have_port: (output) Non-zero if SATA port is enabled - * @have_device: (output) Non-zero if SATA phy indicates device present + * piix_sata_probe - Probe PCI device for present SATA devices + * @pdev: PCI device to probe * * Reads SATA PCI device's PCI config register Port Configuration * and Status (PCS) to determine port and device availability. * * LOCKING: * None (inherited from caller). - */ -static void piix_pcs_probe (struct ata_port *ap, unsigned int *have_port, - unsigned int *have_device) -{ - struct pci_dev *pdev = ap->host_set->pdev; - u16 pcs; - - pci_read_config_word(pdev, ICH5_PCS, &pcs); - - /* is SATA port enabled? */ - if (pcs & (1 << ap->port_no)) { - *have_port = 1; - - if (pcs & (1 << (ap->port_no + 4))) - *have_device = 1; - } -} - -/** - * piix_pcs_disable - Disable SATA port - * @ap: Port to disable - * - * Disable SATA phy for specified port. * - * LOCKING: - * None (inherited from caller). + * RETURNS: + * Non-zero if device detected, zero otherwise. */ -static void piix_pcs_disable (struct ata_port *ap) +static int piix_sata_probe (struct ata_port *ap) { struct pci_dev *pdev = ap->host_set->pdev; - u16 pcs; + int combined = (ap->flags & ATA_FLAG_SLAVE_POSS); + int orig_mask, mask, i; + u8 pcs; + + mask = (PIIX_PORT_PRESENT << ap->port_no) | + (PIIX_PORT_ENABLED << ap->port_no); + + pci_read_config_byte(pdev, ICH5_PCS, &pcs); + orig_mask = (int) pcs & 0xff; + + /* TODO: this is vaguely wrong for ICH6 combined mode, + * where only two of the four SATA ports are mapped + * onto a single ATA channel. It is also vaguely inaccurate + * for ICH5, which has only two ports. However, this is ok, + * as further device presence detection code will handle + * any false positives produced here. + */ - pci_read_config_word(pdev, ICH5_PCS, &pcs); + for (i = 0; i < 4; i++) { + mask = (PIIX_PORT_PRESENT << i) | (PIIX_PORT_ENABLED << i); - if (pcs & (1 << ap->port_no)) { - pcs &= ~(1 << ap->port_no); - pci_write_config_word(pdev, ICH5_PCS, pcs); + if ((orig_mask & mask) == mask) + if (combined || (i == ap->port_no)) + return 1; } + + return 0; } /** @@ -321,8 +321,6 @@ static void piix_sata_phy_reset(struct ata_port *ap) { - unsigned int have_port = 0, have_dev = 0; - if (!pci_test_config_bits(ap->host_set->pdev, &piix_enable_bits[ap->port_no])) { ata_port_disable(ap); @@ -330,21 +328,9 @@ return; } - piix_pcs_probe(ap, &have_port, &have_dev); - - /* if port not enabled, exit */ - if (!have_port) { + if (!piix_sata_probe(ap)) { ata_port_disable(ap); - printk(KERN_INFO "ata%u: SATA port disabled. ignoring.\n", - ap->id); - return; - } - - /* if port enabled but no device, disable port and exit */ - if (!have_dev) { - piix_sata_port_disable(ap); - printk(KERN_INFO "ata%u: SATA port has no device. disabling.\n", - ap->id); + printk(KERN_INFO "ata%u: SATA port has no device.\n", ap->id); return; } @@ -356,22 +342,6 @@ } /** - * piix_sata_port_disable - Disable SATA port - * @ap: Port to disable. - * - * Disable SATA port. - * - * LOCKING: - * None (inherited from caller). - */ - -static void piix_sata_port_disable(struct ata_port *ap) -{ - ata_port_disable(ap); - piix_pcs_disable(ap); -} - -/** * piix_set_piomode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring * @adev: um @@ -493,31 +463,6 @@ } } -/** - * piix_probe_combined - Determine if PATA and SATA are combined - * @pdev: PCI device to examine - * @mask: (output) zero, %PIIX_COMB_PRI or %PIIX_COMB_SEC - * - * Determine if BIOS has secretly stuffed a PATA port into our - * otherwise-beautiful SATA PCI device. - * - * LOCKING: - * Inherited from PCI layer (may sleep). - */ -static void piix_probe_combined (struct pci_dev *pdev, unsigned int *mask) -{ - u8 tmp; - - pci_read_config_byte(pdev, 0x90, &tmp); /* combined mode reg */ - tmp &= 0x6; /* interesting bits 2:1, PATA primary/secondary */ - - /* backwards from what one might expect */ - if (tmp == 0x4) /* bits 10x */ - *mask |= PIIX_COMB_SEC; - if (tmp == 0x6) /* bits 11x */ - *mask |= PIIX_COMB_PRI; -} - /* move to PCI layer, integrate w/ MSI stuff */ static void pci_enable_intx(struct pci_dev *pdev) { @@ -550,7 +495,7 @@ static int printed_version; struct ata_port_info *port_info[2]; unsigned int combined = 0, n_ports = 1; - unsigned int pata_comb = 0, sata_comb = 0; + unsigned int pata_chan = 0, sata_chan = 0; if (!printed_version++) printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); @@ -561,8 +506,19 @@ port_info[0] = &piix_port_info[ent->driver_data]; port_info[1] = NULL; - if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) - piix_probe_combined(pdev, &combined); + + if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) { + u8 tmp; + pci_read_config_byte(pdev, ICH5_PMR, &tmp); + + if (tmp & PIIX_COMB) { + combined = 1; + if (tmp & PIIX_COMB_PATA_P0) + sata_chan = 1; + else + pata_chan = 1; + } + } /* On ICH5, some BIOSen disable the interrupt using the * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3. @@ -573,15 +529,10 @@ if (port_info[0]->host_flags & PIIX_FLAG_CHECKINTR) pci_enable_intx(pdev); - if (combined & PIIX_COMB_PRI) - sata_comb = 1; - else if (combined & PIIX_COMB_SEC) - pata_comb = 1; - - if (pata_comb || sata_comb) { - port_info[sata_comb] = &piix_port_info[ent->driver_data]; - port_info[sata_comb]->host_flags |= ATA_FLAG_SLAVE_POSS; /* sigh */ - port_info[pata_comb] = &piix_port_info[ich5_pata]; /*ich5-specific*/ + if (combined) { + port_info[sata_chan] = &piix_port_info[ent->driver_data]; + port_info[sata_chan]->host_flags |= ATA_FLAG_SLAVE_POSS; + port_info[pata_chan] = &piix_port_info[ich5_pata]; n_ports++; printk(KERN_WARNING DRV_NAME ": combined mode detected\n"); diff -Nru a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c --- a/drivers/scsi/libata-core.c Thu Apr 8 14:58:15 2004 +++ b/drivers/scsi/libata-core.c Thu Apr 8 14:58:15 2004 @@ -118,7 +118,7 @@ static void msleep(unsigned long msecs) { set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(msecs)); + schedule_timeout(msecs_to_jiffies(msecs) + 1); } /** @@ -439,6 +439,81 @@ return readb((void *) ap->ioaddr.status_addr); } +/** + * ata_prot_to_cmd - determine which read/write opcodes to use + * @protocol: ATA_PROT_xxx taskfile protocol + * @lba48: true is lba48 is present + * + * Given necessary input, determine which read/write commands + * to use to transfer data. + * + * LOCKING: + * None. + */ +static int ata_prot_to_cmd(int protocol, int lba48) +{ + int rcmd = 0, wcmd = 0; + + switch (protocol) { + case ATA_PROT_PIO: + if (lba48) { + rcmd = ATA_CMD_PIO_READ_EXT; + wcmd = ATA_CMD_PIO_WRITE_EXT; + } else { + rcmd = ATA_CMD_PIO_READ; + wcmd = ATA_CMD_PIO_WRITE; + } + break; + + case ATA_PROT_DMA: + if (lba48) { + rcmd = ATA_CMD_READ_EXT; + wcmd = ATA_CMD_WRITE_EXT; + } else { + rcmd = ATA_CMD_READ; + wcmd = ATA_CMD_WRITE; + } + break; + + default: + return -1; + } + + return rcmd | (wcmd << 8); +} + +/** + * ata_dev_set_protocol - set taskfile protocol and r/w commands + * @dev: device to examine and configure + * + * Examine the device configuration, after we have + * read the identify-device page and configured the + * data transfer mode. Set internal state related to + * the ATA taskfile protocol (pio, pio mult, dma, etc.) + * and calculate the proper read/write commands to use. + * + * LOCKING: + * caller. + */ +static void ata_dev_set_protocol(struct ata_device *dev) +{ + int pio = (dev->flags & ATA_DFLAG_PIO); + int lba48 = (dev->flags & ATA_DFLAG_LBA48); + int proto, cmd; + + if (pio) + proto = dev->xfer_protocol = ATA_PROT_PIO; + else + proto = dev->xfer_protocol = ATA_PROT_DMA; + + cmd = ata_prot_to_cmd(proto, lba48); + if (cmd < 0) + BUG(); + + dev->read_cmd = cmd & 0xff; + dev->write_cmd = (cmd >> 8) & 0xff; +} + static const char * udma_str[] = { "UDMA/16", "UDMA/25", @@ -478,12 +553,21 @@ } /** - * ata_pio_devchk - - * @ap: - * @device: + * ata_pio_devchk - PATA device presence detection + * @ap: ATA channel to examine + * @device: Device to examine (starting at zero) * - * LOCKING: + * This technique was originally described in + * Hale Landis's ATADRVR (www.ata-atapi.com), and + * later found its way into the ATA/ATAPI spec. * + * Write a pattern to the ATA shadow registers, + * and if a device is present, it will respond by + * correctly storing and echoing back the + * ATA shadow register contents. + * + * LOCKING: + * caller. */ static unsigned int ata_pio_devchk(struct ata_port *ap, @@ -513,12 +597,21 @@ } /** - * ata_mmio_devchk - - * @ap: - * @device: + * ata_mmio_devchk - PATA device presence detection + * @ap: ATA channel to examine + * @device: Device to examine (starting at zero) * - * LOCKING: + * This technique was originally described in + * Hale Landis's ATADRVR (www.ata-atapi.com), and + * later found its way into the ATA/ATAPI spec. * + * Write a pattern to the ATA shadow registers, + * and if a device is present, it will respond by + * correctly storing and echoing back the + * ATA shadow register contents. + * + * LOCKING: + * caller. */ static unsigned int ata_mmio_devchk(struct ata_port *ap, @@ -548,12 +641,16 @@ } /** - * ata_dev_devchk - - * @ap: - * @device: + * ata_dev_devchk - PATA device presence detection + * @ap: ATA channel to examine + * @device: Device to examine (starting at zero) * - * LOCKING: + * Dispatch ATA device presence detection, depending + * on whether we are using PIO or MMIO to talk to the + * ATA shadow registers. * + * LOCKING: + * caller. */ static unsigned int ata_dev_devchk(struct ata_port *ap, @@ -604,16 +701,24 @@ } /** - * ata_dev_try_classify - - * @ap: - * @device: + * ata_dev_try_classify - Parse returned ATA device signature + * @ap: ATA channel to examine + * @device: Device to examine (starting at zero) * - * LOCKING: + * After an event -- SRST, E.D.D., or SATA COMRESET -- occurs, + * an ATA/ATAPI-defined set of values is placed in the ATA + * shadow registers, indicating the results of device detection + * and diagnostics. * + * Select the ATA device, and read the values from the ATA shadow + * registers. Then parse according to the Error register value, + * and the spec-defined values examined by ata_dev_classify(). + * + * LOCKING: + * caller. */ -static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device, - unsigned int maybe_have_dev) +static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device) { struct ata_device *dev = &ap->device[device]; struct ata_taskfile tf; @@ -650,44 +755,51 @@ } /** - * ata_dev_id_string - - * @dev: - * @s: - * @ofs: - * @len: + * ata_dev_id_string - Convert IDENTIFY DEVICE page into string + * @dev: Device whose IDENTIFY DEVICE results we will examine + * @s: string into which data is output + * @ofs: offset into identify device page + * @len: length of string to return * - * LOCKING: - * - * RETURNS: + * The strings in the IDENTIFY DEVICE page are broken up into + * 16-bit chunks. Run through the string, and output each + * 8-bit chunk linearly, regardless of platform. * + * LOCKING: + * caller. */ -unsigned int ata_dev_id_string(struct ata_device *dev, unsigned char *s, - unsigned int ofs, unsigned int len) +void ata_dev_id_string(struct ata_device *dev, unsigned char *s, + unsigned int ofs, unsigned int len) { - unsigned int c, ret = 0; + unsigned int c; while (len > 0) { c = dev->id[ofs] >> 8; *s = c; s++; - ret = c = dev->id[ofs] & 0xff; + c = dev->id[ofs] & 0xff; *s = c; s++; ofs++; len -= 2; } - - return ret; } /** - * ata_dev_parse_strings - - * @dev: + * ata_dev_parse_strings - Store useful IDENTIFY DEVICE page strings + * @dev: Device whose IDENTIFY DEVICE page info we use + * + * We store 'vendor' and 'product' strings read from the device, + * for later use in the SCSI simulator's INQUIRY data. + * + * Set these strings here, in the case of 'product', using + * data read from the ATA IDENTIFY DEVICE page. * * LOCKING: + * caller. */ static void ata_dev_parse_strings(struct ata_device *dev) @@ -700,12 +812,16 @@ } /** - * __ata_dev_select - - * @ap: - * @device: + * __ata_dev_select - Select device 0/1 on ATA bus + * @ap: ATA channel to manipulate + * @device: ATA device (numbered from zero) to select * - * LOCKING: + * Use the method defined in the ATA specification to + * make either device 0, or device 1, active on the + * ATA channel. * + * LOCKING: + * caller. */ static void __ata_dev_select (struct ata_port *ap, unsigned int device) @@ -726,16 +842,22 @@ } /** - * ata_dev_select - - * @ap: - * @device: - * @wait: - * @can_sleep: + * ata_dev_select - Select device 0/1 on ATA bus + * @ap: ATA channel to manipulate + * @device: ATA device (numbered from zero) to select + * @wait: non-zero to wait for Status register BSY bit to clear + * @can_sleep: non-zero if context allows sleeping + * + * Use the method defined in the ATA specification to + * make either device 0, or device 1, active on the + * ATA channel. + * + * This is a high-level version of __ata_dev_select(), + * which additionally provides the services of inserting + * the proper pauses and status polling, where needed. * * LOCKING: - * - * RETURNS: - * + * caller. */ void ata_dev_select(struct ata_port *ap, unsigned int device, @@ -757,10 +879,14 @@ } /** - * ata_dump_id - - * @dev: + * ata_dump_id - IDENTIFY DEVICE info debugging output + * @dev: Device whose IDENTIFY DEVICE page we will dump + * + * Dump selected 16-bit words from a detected device's + * IDENTIFY PAGE page. * * LOCKING: + * caller. */ static inline void ata_dump_id(struct ata_device *dev) @@ -843,7 +969,7 @@ retry: ata_tf_init(ap, &tf, device); tf.ctl |= ATA_NIEN; - tf.protocol = ATA_PROT_PIO_READ; + tf.protocol = ATA_PROT_PIO; if (dev->class == ATA_DEV_ATA) { tf.command = ATA_CMD_ID_ATA; @@ -1129,7 +1255,7 @@ */ static void ata_set_mode(struct ata_port *ap) { - unsigned int force_pio; + unsigned int force_pio, i; ata_host_set_pio(ap); if (ap->flags & ATA_FLAG_PORT_DISABLED) @@ -1148,19 +1274,21 @@ if (force_pio) { ata_dev_set_pio(ap, 0); ata_dev_set_pio(ap, 1); - - if (ap->flags & ATA_FLAG_PORT_DISABLED) - return; } else { ata_dev_set_udma(ap, 0); ata_dev_set_udma(ap, 1); - - if (ap->flags & ATA_FLAG_PORT_DISABLED) - return; } + if (ap->flags & ATA_FLAG_PORT_DISABLED) + return; + if (ap->ops->post_set_mode) ap->ops->post_set_mode(ap); + + for (i = 0; i < 2; i++) { + struct ata_device *dev = &ap->device[i]; + ata_dev_set_protocol(dev); + } } /** @@ -1386,9 +1514,9 @@ /* * determine by signature whether we have ATA or ATAPI devices */ - err = ata_dev_try_classify(ap, 0, dev0); + err = ata_dev_try_classify(ap, 0); if ((slave_possible) && (err != 0x81)) - ata_dev_try_classify(ap, 1, dev1); + ata_dev_try_classify(ap, 1); /* re-enable interrupts */ ata_irq_on(ap); @@ -1725,6 +1853,7 @@ int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); struct scatterlist *sg = qc->sg; unsigned int have_sg = (qc->flags & ATA_QCFLAG_SG); + dma_addr_t dma_address; assert(sg == &qc->sgent); assert(qc->n_elem == 1); @@ -1736,12 +1865,15 @@ if (!have_sg) return 0; - sg_dma_address(sg) = pci_map_single(ap->host_set->pdev, - cmd->request_buffer, - cmd->request_bufflen, dir); + dma_address = pci_map_single(ap->host_set->pdev, cmd->request_buffer, + cmd->request_bufflen, dir); + if (pci_dma_mapping_error(dma_address)) + return -1; + + sg_dma_address(sg) = dma_address; DPRINTK("mapped buffer of %d bytes for %s\n", cmd->request_bufflen, - qc->flags & ATA_QCFLAG_WRITE ? "write" : "read"); + qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); return 0; } @@ -1842,8 +1974,7 @@ { struct ata_port *ap = qc->ap; - assert((qc->tf.protocol == ATA_PROT_PIO_READ) || - (qc->tf.protocol == ATA_PROT_PIO_WRITE)); + assert(qc->tf.protocol == ATA_PROT_PIO); qc->flags |= ATA_QCFLAG_POLL; qc->tf.ctl |= ATA_NIEN; /* disable interrupts */ @@ -1963,12 +2094,12 @@ } DPRINTK("data %s, drv_stat 0x%X\n", - qc->flags & ATA_QCFLAG_WRITE ? "write" : "read", + qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read", status); /* do the actual data transfer */ /* FIXME: mmio-ize */ - if (qc->flags & ATA_QCFLAG_WRITE) + if (qc->tf.flags & ATA_TFLAG_WRITE) outsl(ap->ioaddr.data_addr, buf, ATA_SECT_DWORDS); else insl(ap->ioaddr.data_addr, buf, ATA_SECT_DWORDS); @@ -2033,8 +2164,7 @@ qc->scsidone = scsi_finish_command; switch (qc->tf.protocol) { - case ATA_PROT_DMA_READ: - case ATA_PROT_DMA_WRITE: + case ATA_PROT_DMA: if (ap->flags & ATA_FLAG_MMIO) { void *mmio = (void *) ap->ioaddr.bmdma_addr; host_stat = readb(mmio + ATA_DMA_STATUS); @@ -2258,7 +2388,7 @@ void ata_bmdma_start_mmio (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - unsigned int rw = (qc->flags & ATA_QCFLAG_WRITE); + unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); u8 host_stat, dmactl; void *mmio = (void *) ap->ioaddr.bmdma_addr; @@ -2307,7 +2437,7 @@ void ata_bmdma_start_pio (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - unsigned int rw = (qc->flags & ATA_QCFLAG_WRITE); + unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); u8 host_stat, dmactl; /* load PRD table addr. */ @@ -2402,8 +2532,7 @@ unsigned int handled = 0; switch (qc->tf.protocol) { - case ATA_PROT_DMA_READ: - case ATA_PROT_DMA_WRITE: + case ATA_PROT_DMA: if (ap->flags & ATA_FLAG_MMIO) { void *mmio = (void *) ap->ioaddr.bmdma_addr; host_stat = readb(mmio + ATA_DMA_STATUS); @@ -2810,6 +2939,7 @@ host->unique_id = ata_unique_id++; host->max_cmd_len = 12; scsi_set_device(host, &ent->pdev->dev); + scsi_assign_lock(host, &host_set->lock); ap->flags = ATA_FLAG_PORT_DISABLED; ap->id = host->unique_id; diff -Nru a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c --- a/drivers/scsi/libata-scsi.c Thu Apr 8 14:58:15 2004 +++ b/drivers/scsi/libata-scsi.c Thu Apr 8 14:58:15 2004 @@ -32,17 +32,28 @@ #include "libata.h" +static void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, + struct scsi_cmnd *cmd, + void (*done)(struct scsi_cmnd *)); + /** - * ata_std_bios_param - generic bios head/sector/cylinder calculator - * used by sd. Most BIOSes nowadays expect a XXX/255/16 (CHS) - * mapping. Some situations may arise where the disk is not - * bootable if this is not used. + * ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd. + * @sdev: SCSI device for which BIOS geometry is to be determined + * @bdev: block device associated with @sdev + * @capacity: capacity of SCSI device + * @geom: location to which geometry will be output + * + * Generic bios head/sector/cylinder calculator + * used by sd. Most BIOSes nowadays expect a XXX/255/16 (CHS) + * mapping. Some situations may arise where the disk is not + * bootable if this is not used. * * LOCKING: + * Defined by the SCSI layer. We don't really care. * * RETURNS: - * + * Zero. */ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) @@ -56,6 +67,27 @@ } +/** + * ata_scsi_qc_new - acquire new ata_queued_cmd reference + * @ap: ATA port to which the new command is attached + * @dev: ATA device to which the new command is attached + * @cmd: SCSI command that originated this ATA command + * @done: SCSI command completion function + * + * Obtain a reference to an unused ata_queued_cmd structure, + * which is the basic libata structure representing a single + * ATA command sent to the hardware. + * + * If a command was available, fill in the SCSI-specific + * portions of the structure with information on the + * current command. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Command allocated, or %NULL if none available. + */ struct ata_queued_cmd *ata_scsi_qc_new(struct ata_port *ap, struct ata_device *dev, struct scsi_cmnd *cmd, @@ -84,11 +116,18 @@ } /** - * ata_to_sense_error - - * @qc: - * @cmd: + * ata_to_sense_error - convert ATA error to SCSI error + * @qc: Command that we are erroring out + * + * Converts an ATA error into a SCSI error. + * + * Right now, this routine is laughably primitive. We + * don't even examine what ATA told us, we just look at + * the command data direction, and return a fatal SCSI + * sense error based on that. * * LOCKING: + * spin_lock_irqsave(host_set lock) */ void ata_to_sense_error(struct ata_queued_cmd *qc) @@ -102,7 +141,7 @@ cmd->sense_buffer[7] = 14 - 8; /* addnl. sense len. FIXME: correct? */ /* additional-sense-code[-qualifier] */ - if ((qc->flags & ATA_QCFLAG_WRITE) == 0) { + if (cmd->sc_data_direction == SCSI_DATA_READ) { cmd->sense_buffer[12] = 0x11; /* "unrecovered read error" */ cmd->sense_buffer[13] = 0x04; } else { @@ -112,11 +151,15 @@ } /** - * ata_scsi_slave_config - - * @sdev: + * ata_scsi_slave_config - Set SCSI device attributes + * @sdev: SCSI device to examine * - * LOCKING: + * This is called before we actually start reading + * and writing to the device, to configure certain + * SCSI mid-layer behaviors. * + * LOCKING: + * Defined by SCSI layer. We don't really care. */ int ata_scsi_slave_config(struct scsi_device *sdev) @@ -155,24 +198,29 @@ } /** - * ata_scsi_rw_xlat - - * @qc: - * @scsicmd: - * @cmd_size: + * ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one + * @qc: Storage for translated ATA taskfile + * @scsicmd: SCSI command to translate + * + * Converts any of six SCSI read/write commands into the + * ATA counterpart, including starting sector (LBA), + * sector count, and taking into account the device's LBA48 + * support. + * + * Commands %READ_6, %READ_10, %READ_16, %WRITE_6, %WRITE_10, and + * %WRITE_16 are currently supported. * * LOCKING: * spin_lock_irqsave(host_set lock) * * RETURNS: - * + * Zero on success, non-zero on error. */ -static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd, - unsigned int cmd_size) +static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; - unsigned int dma = qc->flags & ATA_QCFLAG_DMA; qc->cursect = qc->cursg = qc->cursg_ofs = 0; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; @@ -180,43 +228,18 @@ tf->hob_lbal = 0; tf->hob_lbam = 0; tf->hob_lbah = 0; + tf->protocol = qc->dev->xfer_protocol; + tf->device |= ATA_LBA; if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 || scsicmd[0] == READ_16) { - if (likely(dma)) { - if (lba48) - tf->command = ATA_CMD_READ_EXT; - else - tf->command = ATA_CMD_READ; - tf->protocol = ATA_PROT_DMA_READ; - } else { - if (lba48) - tf->command = ATA_CMD_PIO_READ_EXT; - else - tf->command = ATA_CMD_PIO_READ; - tf->protocol = ATA_PROT_PIO_READ; - } - qc->flags &= ~ATA_QCFLAG_WRITE; - VPRINTK("reading\n"); + tf->command = qc->dev->read_cmd; } else { - if (likely(dma)) { - if (lba48) - tf->command = ATA_CMD_WRITE_EXT; - else - tf->command = ATA_CMD_WRITE; - tf->protocol = ATA_PROT_DMA_WRITE; - } else { - if (lba48) - tf->command = ATA_CMD_PIO_WRITE_EXT; - else - tf->command = ATA_CMD_PIO_WRITE; - tf->protocol = ATA_PROT_PIO_WRITE; - } - qc->flags |= ATA_QCFLAG_WRITE; - VPRINTK("writing\n"); + tf->command = qc->dev->write_cmd; + tf->flags |= ATA_TFLAG_WRITE; } - if (cmd_size == 10) { + if (scsicmd[0] == READ_10 || scsicmd[0] == WRITE_10) { if (lba48) { tf->hob_nsect = scsicmd[7]; tf->hob_lbal = scsicmd[2]; @@ -234,7 +257,6 @@ qc->nsect = scsicmd[8]; } - tf->device |= ATA_LBA; tf->nsect = scsicmd[8]; tf->lbal = scsicmd[5]; @@ -245,19 +267,17 @@ return 0; } - if (cmd_size == 6) { + if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) { qc->nsect = tf->nsect = scsicmd[4]; tf->lbal = scsicmd[3]; tf->lbam = scsicmd[2]; tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */ - tf->device |= ATA_LBA; - VPRINTK("six-byte command\n"); return 0; } - if (cmd_size == 16) { + if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) { /* rule out impossible LBAs and sector counts */ if (scsicmd[2] || scsicmd[3] || scsicmd[10] || scsicmd[11]) return 1; @@ -281,7 +301,6 @@ qc->nsect = scsicmd[13]; } - tf->device |= ATA_LBA; tf->nsect = scsicmd[13]; tf->lbal = scsicmd[9]; @@ -297,20 +316,26 @@ } /** - * ata_scsi_rw_queue - - * @ap: - * @dev: - * @cmd: - * @done: - * @cmd_size: + * ata_scsi_translate - Translate then issue SCSI command to ATA device + * @ap: ATA port to which the command is addressed + * @dev: ATA device to which the command is addressed + * @cmd: SCSI command to execute + * @done: SCSI command completion function + * + * Our ->queuecommand() function has decided that the SCSI + * command issued can be directly translated into an ATA + * command, rather than handled internally. + * + * This function sets up an ata_queued_cmd structure for the + * SCSI command, and sends that ata_queued_cmd to the hardware. * * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_scsi_rw_queue(struct ata_port *ap, struct ata_device *dev, - struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), - unsigned int cmd_size) +static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, + struct scsi_cmnd *cmd, + void (*done)(struct scsi_cmnd *)) { struct ata_queued_cmd *qc; u8 *scsicmd = cmd->cmnd; @@ -329,7 +354,7 @@ qc->flags |= ATA_QCFLAG_SG; /* data is present; dma-map it */ - if (ata_scsi_rw_xlat(qc, scsicmd, cmd_size)) + if (ata_scsi_rw_xlat(qc, scsicmd)) goto err_out; /* select device, send command to hardware */ @@ -353,7 +378,6 @@ * * LOCKING: * spin_lock_irqsave(host_set lock) - * FIXME: kmap inside spin_lock_irqsave ok? * * RETURNS: * Length of response buffer. @@ -368,7 +392,7 @@ struct scatterlist *sg; sg = (struct scatterlist *) cmd->request_buffer; - buf = kmap(sg->page) + sg->offset; + buf = kmap_atomic(sg->page, KM_USER0) + sg->offset; buflen = sg->length; } else { buf = cmd->request_buffer; @@ -396,7 +420,7 @@ struct scatterlist *sg; sg = (struct scatterlist *) cmd->request_buffer; - kunmap(sg->page); + kunmap_atomic(sg->page, KM_USER0); } } @@ -596,30 +620,6 @@ } /** - * ata_scsiop_sync_cache - Simulate SYNCHRONIZE CACHE command - * @args: Port / device / SCSI command of interest. - * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. - * - * Initiates flush of device's cache. - * - * TODO: - * Actually do this :) - * - * LOCKING: - * spin_lock_irqsave(host_set lock) - */ - -unsigned int ata_scsiop_sync_cache(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) -{ - VPRINTK("ENTER\n"); - - /* FIXME */ - return 1; -} - -/** * ata_msense_push - Push data onto MODE SENSE data output buffer * @ptr_io: (input/output) Location to store more output data * @last: End of output data buffer @@ -649,9 +649,9 @@ /** * ata_msense_caching - Simulate MODE SENSE caching info page - * @dev: - * @ptr_io: - * @last: + * @dev: Device associated with this MODE SENSE command + * @ptr_io: (input/output) Location to store more output data + * @last: End of output data buffer * * Generate a caching info page, which conditionally indicates * write caching to the SCSI layer, depending on device @@ -674,9 +674,9 @@ /** * ata_msense_ctl_mode - Simulate MODE SENSE control mode page - * @dev: - * @ptr_io: - * @last: + * @dev: Device associated with this MODE SENSE command + * @ptr_io: (input/output) Location to store more output data + * @last: End of output data buffer * * Generate a generic MODE SENSE control mode page. * @@ -834,11 +834,15 @@ } /** - * ata_scsi_badcmd - - * @cmd: - * @done: - * @asc: - * @ascq: + * ata_scsi_badcmd - End a SCSI request with an error + * @cmd: SCSI request to be handled + * @done: SCSI command completion function + * @asc: SCSI-defined additional sense code + * @ascq: SCSI-defined additional sense code qualifier + * + * Helper function that completes a SCSI command with + * %SAM_STAT_CHECK_CONDITION, with a sense key %ILLEGAL_REQUEST + * and the specified additional sense codes. * * LOCKING: * spin_lock_irqsave(host_set lock) @@ -912,7 +916,7 @@ qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; if (cmd->sc_data_direction == SCSI_DATA_WRITE) { - qc->flags |= ATA_QCFLAG_WRITE; + qc->tf.flags |= ATA_TFLAG_WRITE; DPRINTK("direction: write\n"); } @@ -967,6 +971,99 @@ } /** + * ata_scsi_find_dev - lookup ata_device from scsi_cmnd + * @ap: ATA port to which the device is attached + * @cmd: SCSI command to be sent to the device + * + * Given various information provided in struct scsi_cmnd, + * map that onto an ATA bus, and using that mapping + * determine which ata_device is associated with the + * SCSI command to be sent. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Associated ATA device, or %NULL if not found. + */ + +static inline struct ata_device * +ata_scsi_find_dev(struct ata_port *ap, struct scsi_cmnd *cmd) +{ + struct ata_device *dev; + + /* skip commands not addressed to targets we simulate */ + if (likely(cmd->device->id < ATA_MAX_DEVICES)) + dev = &ap->device[cmd->device->id]; + else + return NULL; + + if (unlikely((cmd->device->channel != 0) || + (cmd->device->lun != 0))) + return NULL; + + if (unlikely(!ata_dev_present(dev))) + return NULL; + +#ifndef ATA_ENABLE_ATAPI + if (unlikely(dev->class == ATA_DEV_ATAPI)) + return NULL; +#endif + + return dev; +} + +/** + * ata_scsi_xlat_possible - check if SCSI to ATA translation is possible + * @cmd: SCSI command opcode to consider + * + * Look up the SCSI command given, and determine whether the + * SCSI command is to be translated or simulated. + * + * RETURNS: + * Non-zero if possible, zero if not. + */ + +static inline int ata_scsi_xlat_possible(u8 cmd) +{ + switch (cmd) { + case READ_6: + case READ_10: + case READ_16: + + case WRITE_6: + case WRITE_10: + case WRITE_16: + return 1; + } + + return 0; +} + +/** + * ata_scsi_dump_cdb - dump SCSI command contents to dmesg + * @ap: ATA port to which the command was being sent + * @cmd: SCSI command to dump + * + * Prints the contents of a SCSI command via printk(). + */ + +static inline void ata_scsi_dump_cdb(struct ata_port *ap, + struct scsi_cmnd *cmd) +{ +#ifdef ATA_DEBUG + u8 *scsicmd = cmd->cmnd; + + DPRINTK("CDB (%u:%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + ap->id, + cmd->device->channel, cmd->device->id, cmd->device->lun, + scsicmd[0], scsicmd[1], scsicmd[2], scsicmd[3], + scsicmd[4], scsicmd[5], scsicmd[6], scsicmd[7], + scsicmd[8]); +#endif +} + +/** * ata_scsi_queuecmd - Issue SCSI cdb to libata-managed device * @cmd: SCSI command to be sent * @done: Completion function, called when command is complete @@ -987,83 +1084,52 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { - u8 *scsicmd = cmd->cmnd; struct ata_port *ap; struct ata_device *dev; - struct ata_scsi_args args; - const unsigned int atapi_support = -#ifdef ATA_ENABLE_ATAPI - 1; -#else - 0; -#endif - - /* Note: spin_lock_irqsave is held by caller... */ - spin_unlock(cmd->device->host->host_lock); ap = (struct ata_port *) &cmd->device->host->hostdata[0]; - DPRINTK("CDB (%u:%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - ap->id, - cmd->device->channel, cmd->device->id, cmd->device->lun, - scsicmd[0], scsicmd[1], scsicmd[2], scsicmd[3], - scsicmd[4], scsicmd[5], scsicmd[6], scsicmd[7], - scsicmd[8]); + ata_scsi_dump_cdb(ap, cmd); - /* skip commands not addressed to targets we care about */ - if ((cmd->device->channel != 0) || (cmd->device->lun != 0) || - (cmd->device->id >= ATA_MAX_DEVICES)) { - cmd->result = (DID_BAD_TARGET << 16); /* FIXME: correct? */ - done(cmd); - goto out; - } - - spin_lock(&ap->host_set->lock); - - dev = &ap->device[cmd->device->id]; - - if (!ata_dev_present(dev)) { - DPRINTK("no device\n"); - cmd->result = (DID_BAD_TARGET << 16); /* FIXME: correct? */ + dev = ata_scsi_find_dev(ap, cmd); + if (unlikely(!dev)) { + cmd->result = (DID_BAD_TARGET << 16); done(cmd); goto out_unlock; } - if (dev->class == ATA_DEV_ATAPI) { - if (atapi_support) - atapi_scsi_queuecmd(ap, dev, cmd, done); - else { - cmd->result = (DID_BAD_TARGET << 16); /* correct? */ - done(cmd); - } - goto out_unlock; - } + if (dev->class == ATA_DEV_ATA) { + if (ata_scsi_xlat_possible(cmd->cmnd[0])) + ata_scsi_translate(ap, dev, cmd, done); + else + ata_scsi_simulate(ap, dev, cmd, done); + } else + atapi_scsi_queuecmd(ap, dev, cmd, done); - /* fast path */ - switch(scsicmd[0]) { - case READ_6: - case WRITE_6: - ata_scsi_rw_queue(ap, dev, cmd, done, 6); - goto out_unlock; - - case READ_10: - case WRITE_10: - ata_scsi_rw_queue(ap, dev, cmd, done, 10); - goto out_unlock; - - case READ_16: - case WRITE_16: - ata_scsi_rw_queue(ap, dev, cmd, done, 16); - goto out_unlock; +out_unlock: + return 0; +} - default: - /* do nothing */ - break; - } +/** + * ata_scsi_simulate - simulate SCSI command on ATA device + * @ap: Port to which ATA device is attached. + * @dev: Target device for CDB. + * @cmd: SCSI command being sent to device. + * @done: SCSI command completion function. + * + * Interprets and directly executes a select list of SCSI commands + * that can be handled internally. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ - /* - * slow path - */ +static void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, + struct scsi_cmnd *cmd, + void (*done)(struct scsi_cmnd *)) +{ + struct ata_scsi_args args; + u8 *scsicmd = cmd->cmnd; args.ap = ap; args.dev = dev; @@ -1102,13 +1168,6 @@ ata_bad_cdb(cmd, done); break; - case SYNCHRONIZE_CACHE: - if ((dev->flags & ATA_DFLAG_WCACHE) == 0) - ata_bad_scsiop(cmd, done); - else - ata_scsi_rbuf_fill(&args, ata_scsiop_sync_cache); - break; - case READ_CAPACITY: ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap); break; @@ -1132,11 +1191,5 @@ ata_bad_scsiop(cmd, done); break; } - -out_unlock: - spin_unlock(&ap->host_set->lock); -out: - spin_lock(cmd->device->host->host_lock); - return 0; } diff -Nru a/drivers/scsi/libata.h b/drivers/scsi/libata.h --- a/drivers/scsi/libata.h Thu Apr 8 14:58:15 2004 +++ b/drivers/scsi/libata.h Thu Apr 8 14:58:15 2004 @@ -37,8 +37,8 @@ /* libata-core.c */ -extern unsigned int ata_dev_id_string(struct ata_device *dev, unsigned char *s, - unsigned int ofs, unsigned int len); +extern void ata_dev_id_string(struct ata_device *dev, unsigned char *s, + unsigned int ofs, unsigned int len); extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, struct ata_device *dev); extern int ata_qc_issue(struct ata_queued_cmd *qc); @@ -50,9 +50,6 @@ /* libata-scsi.c */ extern void ata_to_sense_error(struct ata_queued_cmd *qc); -extern void ata_scsi_rw_queue(struct ata_port *ap, struct ata_device *dev, - struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), - unsigned int cmd_size); extern int ata_scsi_error(struct Scsi_Host *host); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen); diff -Nru a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c --- a/drivers/scsi/sata_promise.c Thu Apr 8 14:58:15 2004 +++ b/drivers/scsi/sata_promise.c Thu Apr 8 14:58:15 2004 @@ -28,13 +28,14 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" #include #include #define DRV_NAME "sata_promise" -#define DRV_VERSION "0.91" +#define DRV_VERSION "0.92" enum { @@ -45,10 +46,13 @@ PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */ PDC_TBG_MODE = 0x41, /* TBG mode */ PDC_FLASH_CTL = 0x44, /* Flash control register */ - PDC_CTLSTAT = 0x60, /* IDE control and status register */ + PDC_PCI_CTL = 0x48, /* PCI control and status register */ + PDC_GLOBAL_CTL = 0x48, /* Global control/status (per port) */ + 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, @@ -73,12 +77,19 @@ 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_HDMA_RESET = (1 << 11), /* HDMA reset */ + PDC_RESET = (1 << 11), /* HDMA reset */ PDC_MAX_HDMA = 32, PDC_HDMA_Q_MASK = (PDC_MAX_HDMA - 1), @@ -154,13 +165,14 @@ 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); + 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, @@ -199,7 +211,7 @@ .tf_read = ata_tf_read_mmio, .check_status = ata_check_status_mmio, .exec_command = pdc_exec_command_mmio, - .phy_reset = sata_phy_reset, + .phy_reset = pdc_phy_reset, .bmdma_start = pdc_dma_start, .fill_sg = pdc_fill_sg, .eng_timeout = pdc_eng_timeout, @@ -351,6 +363,34 @@ ata_bus_reset(ap); } +static void pdc_reset_port(struct ata_port *ap) +{ + void *mmio = (void *) ap->ioaddr.cmd_addr + PDC_CTLSTAT; + unsigned int i; + u32 tmp; + + for (i = 11; i > 0; i--) { + tmp = readl(mmio); + if (tmp & PDC_RESET) + break; + + udelay(100); + + tmp |= PDC_RESET; + writel(tmp, mmio); + } + + tmp &= ~PDC_RESET; + writel(tmp, mmio); + readl(mmio); /* flush */ +} + +static void pdc_phy_reset(struct ata_port *ap) +{ + pdc_reset_port(ap); + sata_phy_reset(ap); +} + static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { if (sc_reg > SCR_CONTROL) @@ -390,12 +430,11 @@ * and seq id (byte 2) */ switch (tf->protocol) { - case ATA_PROT_DMA_READ: - buf32[0] = cpu_to_le32(PDC_PKT_READ); - break; - - case ATA_PROT_DMA_WRITE: - buf32[0] = 0; + 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: @@ -554,7 +593,7 @@ /* * Set up ATA packet */ - if (tf->protocol == ATA_PROT_DMA_READ) + 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; @@ -606,7 +645,7 @@ /* * Set up Host DMA packet */ - if (tf->protocol == ATA_PROT_DMA_READ) + if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE))) tmp = PDC_PKT_READ; else tmp = 0; @@ -768,7 +807,7 @@ 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->flags & ATA_QCFLAG_WRITE); + unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); u8 seq = (u8) (port_no + 1); unsigned int doing_hdma = 0, port_ofs; @@ -821,13 +860,14 @@ VPRINTK("ENTER\n"); - switch (qc->tf.protocol) { - case ATA_PROT_DMA_READ: + 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); + pdc_dma_complete(ap, qc, 0); pdc20621_pop_hdma(qc); } @@ -843,9 +883,9 @@ port_ofs + PDC_DIMM_HOST_PKT); } handled = 1; - break; - case ATA_PROT_DMA_WRITE: + } 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); @@ -864,25 +904,24 @@ 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); + pdc_dma_complete(ap, qc, 0); pdc20621_pop_hdma(qc); } handled = 1; - break; - case ATA_PROT_NODATA: /* command completion, but no data xfer */ + /* 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; - break; - default: - ap->stats.idle_irq++; - break; - } + } else { + ap->stats.idle_irq++; + } - return handled; + return handled; } static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs) @@ -918,7 +957,7 @@ return IRQ_NONE; } - spin_lock_irq(&host_set->lock); + spin_lock(&host_set->lock); for (i = 1; i < 9; i++) { port_no = i - 1; @@ -940,7 +979,7 @@ } } - spin_unlock_irq(&host_set->lock); + spin_unlock(&host_set->lock); VPRINTK("mask == 0x%x\n", mask); @@ -969,11 +1008,14 @@ } static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc) + 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), 0); + ata_wait_idle(ap) | err_bit, 0); } static void pdc_eng_timeout(struct ata_port *ap) @@ -999,8 +1041,7 @@ qc->scsidone = scsi_finish_command; switch (qc->tf.protocol) { - case ATA_PROT_DMA_READ: - case ATA_PROT_DMA_WRITE: + 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); @@ -1033,18 +1074,27 @@ struct ata_queued_cmd *qc) { u8 status; - unsigned int handled = 0; + unsigned int handled = 0, have_err = 0; + u32 tmp; + void *mmio = (void *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL; + + tmp = readl(mmio); + if (tmp & PDC_ERR_MASK) { + have_err = 1; + pdc_reset_port(ap); + } switch (qc->tf.protocol) { - case ATA_PROT_DMA_READ: - case ATA_PROT_DMA_WRITE: - pdc_dma_complete(ap, qc); + case ATA_PROT_DMA: + pdc_dma_complete(ap, qc, have_err); handled = 1; break; case ATA_PROT_NODATA: /* command completion, but no data xfer */ status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status); + if (have_err) + status |= ATA_ERR; ata_qc_complete(qc, status, 0); handled = 1; break; @@ -1088,7 +1138,7 @@ return IRQ_NONE; } - spin_lock_irq(&host_set->lock); + spin_lock(&host_set->lock); for (i = 0; i < host_set->n_ports; i++) { VPRINTK("port %u\n", i); @@ -1103,7 +1153,7 @@ } } - spin_unlock_irq(&host_set->lock); + spin_unlock(&host_set->lock); VPRINTK("EXIT\n"); @@ -1130,16 +1180,14 @@ static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - if ((tf->protocol != ATA_PROT_DMA_READ) && - (tf->protocol != ATA_PROT_DMA_WRITE)) + if (tf->protocol != ATA_PROT_DMA) 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_DMA_READ) && - (tf->protocol != ATA_PROT_DMA_WRITE)) + if (tf->protocol != ATA_PROT_DMA) ata_exec_command_mmio(ap, tf); } @@ -1592,14 +1640,14 @@ * Reset Host DMA */ tmp = readl(mmio + PDC_HDMA_CTLSTAT); - tmp |= PDC_HDMA_RESET; + 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_HDMA_RESET; + tmp &= ~PDC_RESET; writel(tmp, mmio + PDC_HDMA_CTLSTAT); readl(mmio + PDC_HDMA_CTLSTAT); /* flush */ } @@ -1610,14 +1658,18 @@ u32 tmp; if (chip_id == board_20621) - return; + BUG(); - /* change FIFO_SHD to 8 dwords. Promise driver does this... - * dunno why. + /* + * Except for the hotplug stuff, this is voodoo from the + * Promise driver. Label this entire section + * "TODO: figure out why we do this" */ + + /* change FIFO_SHD to 8 dwords, enable BMR_BURST */ tmp = readl(mmio + PDC_FLASH_CTL); - if ((tmp & (1 << 16)) == 0) - writel(tmp | (1 << 16), mmio + PDC_FLASH_CTL); + tmp |= 0x12000; /* bit 16 (fifo 8 dw) and 13 (bmr burst?) */ + writel(tmp, mmio + PDC_FLASH_CTL); /* clear plug/unplug flags for all ports */ tmp = readl(mmio + PDC_SATA_PLUG_CSR); @@ -1627,13 +1679,17 @@ tmp = readl(mmio + PDC_SATA_PLUG_CSR); writel(tmp | 0xff0000, mmio + PDC_SATA_PLUG_CSR); - /* reduce TBG clock to 133 Mhz. FIXME: why? */ + /* reduce TBG clock to 133 Mhz. */ tmp = readl(mmio + PDC_TBG_MODE); tmp &= ~0x30000; /* clear bit 17, 16*/ tmp |= 0x10000; /* set bit 17:16 = 0:1 */ writel(tmp, mmio + PDC_TBG_MODE); - /* adjust slew rate control register. FIXME: why? */ + readl(mmio + PDC_TBG_MODE); /* flush */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(10)); + + /* adjust slew rate control register. */ tmp = readl(mmio + PDC_SLEW_CTL); tmp &= 0xFFFFF03F; /* clear bit 11 ~ 6 */ tmp |= 0x00000900; /* set bit 11-9 = 100b , bit 8-6 = 100 */ diff -Nru a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/sata_sis.c Thu Apr 8 14:58:15 2004 @@ -0,0 +1,214 @@ +/* + * sata_sis.c - Silicon Integrated Systems SATA + * + * Copyright 2004 Uwe Koziolek + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" +#include + +#define DRV_NAME "sata_sis" +#define DRV_VERSION "0.04" + +enum { + sis_180 = 0, +}; + +static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); +static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg); +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 }, + { } /* terminate list */ +}; + + +static struct pci_driver sis_pci_driver = { + .name = DRV_NAME, + .id_table = sis_pci_tbl, + .probe = sis_init_one, + .remove = ata_pci_remove_one, +}; + +static Scsi_Host_Template sis_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 = ATA_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 sis_ops = { + .port_disable = ata_port_disable, + .tf_load = ata_tf_load_pio, + .tf_read = ata_tf_read_pio, + .check_status = ata_check_status_pio, + .exec_command = ata_exec_command_pio, + .phy_reset = sata_phy_reset, + .bmdma_start = ata_bmdma_start_pio, + .fill_sg = ata_fill_sg, + .eng_timeout = ata_eng_timeout, + .irq_handler = ata_interrupt, + .scr_read = sis_scr_read, + .scr_write = sis_scr_write, + .port_start = ata_port_start, + .port_stop = ata_port_stop, +}; + + +MODULE_AUTHOR("Uwe Koziolek"); +MODULE_DESCRIPTION("low-level driver for Silicon Integratad Systems SATA controller"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, sis_pci_tbl); + + +static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg) +{ + if (sc_reg >= 16) + return 0xffffffffU; + + return inl(ap->ioaddr.scr_addr + (sc_reg * 4)); +} + +static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) +{ + if (sc_reg >= 16) + return; + outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)); +} + +/* move to PCI layer, integrate w/ MSI stuff */ +static void pci_enable_intx(struct pci_dev *pdev) +{ + u16 pci_command; + + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + if (pci_command & PCI_COMMAND_INTX_DISABLE) { + pci_command &= ~PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(pdev, PCI_COMMAND, pci_command); + } +} + +static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct ata_probe_ent *probe_ent = NULL; + int rc; + + 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) { + rc = -ENOMEM; + goto err_out_regions; + } + + memset(probe_ent, 0, sizeof(*probe_ent)); + probe_ent->pdev = pdev; + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = &sis_sht; + probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET | + ATA_FLAG_NO_LEGACY; + probe_ent->pio_mask = 0x03; + probe_ent->udma_mask = 0x7f; + probe_ent->port_ops = &sis_ops; + + probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); + ata_std_ports(&probe_ent->port[0]); + probe_ent->port[0].ctl_addr = + pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; + probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); + probe_ent->port[0].scr_addr = pci_resource_start(pdev, 5); + + probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); + ata_std_ports(&probe_ent->port[1]); + probe_ent->port[1].ctl_addr = + pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; + probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; + probe_ent->port[1].scr_addr = pci_resource_start(pdev, 5) + 64; + + probe_ent->n_ports = 2; + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + + pci_set_master(pdev); + pci_enable_intx(pdev); + + /* FIXME: check ata_device_add return value */ + ata_device_add(probe_ent); + kfree(probe_ent); + + return 0; + +err_out_regions: + pci_release_regions(pdev); + +err_out: + pci_disable_device(pdev); + return rc; + +} + +static int __init sis_init(void) +{ + return pci_module_init(&sis_pci_driver); +} + +static void __exit sis_exit(void) +{ + pci_unregister_driver(&sis_pci_driver); +} + + +module_init(sis_init); +module_exit(sis_exit); diff -Nru a/include/linux/ata.h b/include/linux/ata.h --- a/include/linux/ata.h Thu Apr 8 14:58:15 2004 +++ b/include/linux/ata.h Thu Apr 8 14:58:15 2004 @@ -102,16 +102,6 @@ ATA_REG_DEVSEL = ATA_REG_DEVICE, ATA_REG_IRQ = ATA_REG_NSECT, - /* ATA taskfile protocols */ - ATA_PROT_UNKNOWN = 0, - ATA_PROT_NODATA = 1, - ATA_PROT_PIO_READ = 2, - ATA_PROT_PIO_WRITE = 3, - ATA_PROT_DMA_READ = 4, - ATA_PROT_DMA_WRITE = 5, - ATA_PROT_ATAPI = 6, - ATA_PROT_ATAPI_DMA = 7, - /* ATA device commands */ ATA_CMD_EDD = 0x90, /* execute device diagnostic */ ATA_CMD_ID_ATA = 0xEC, @@ -156,13 +146,54 @@ SCR_CONTROL = 2, SCR_ACTIVE = 3, SCR_NOTIFICATION = 4, + + /* struct ata_taskfile flags */ + ATA_TFLAG_LBA48 = (1 << 0), /* enable 48-bit LBA and "HOB" */ + ATA_TFLAG_ISADDR = (1 << 1), /* enable r/w to nsect/lba regs */ + ATA_TFLAG_DEVICE = (1 << 2), /* enable r/w to device reg */ + ATA_TFLAG_WRITE = (1 << 3), /* data dir: host->dev==1 (write) */ +}; + +enum ata_tf_protocols { + /* ATA taskfile protocols */ + ATA_PROT_UNKNOWN, /* unknown/invalid */ + ATA_PROT_NODATA, /* no data */ + ATA_PROT_PIO, /* PIO single sector */ + ATA_PROT_PIO_MULT, /* PIO multiple sector */ + ATA_PROT_DMA, /* DMA */ + ATA_PROT_ATAPI, /* packet command */ + ATA_PROT_ATAPI_DMA, /* packet command with special DMA sauce */ }; /* core structures */ + struct ata_prd { u32 addr; u32 flags_len; } __attribute__((packed)); + +struct ata_taskfile { + unsigned long flags; /* ATA_TFLAG_xxx */ + u8 protocol; /* ATA_PROT_xxx */ + + u8 ctl; /* control reg */ + + u8 hob_feature; /* additional data */ + u8 hob_nsect; /* to support LBA48 */ + u8 hob_lbal; + u8 hob_lbam; + u8 hob_lbah; + + u8 feature; + u8 nsect; + u8 lbal; + u8 lbam; + u8 lbah; + + u8 device; + + u8 command; /* IO operation */ +}; #define ata_id_is_ata(dev) (((dev)->id[0] & (1 << 15)) == 0) #define ata_id_has_lba48(dev) ((dev)->id[83] & (1 << 10)) diff -Nru a/include/linux/libata.h b/include/linux/libata.h --- a/include/linux/libata.h Thu Apr 8 14:58:15 2004 +++ b/include/linux/libata.h Thu Apr 8 14:58:15 2004 @@ -107,12 +107,6 @@ ATA_FLAG_MMIO = (1 << 6), /* use MMIO, not PIO */ ATA_FLAG_SATA_RESET = (1 << 7), /* use COMRESET */ - /* struct ata_taskfile flags */ - ATA_TFLAG_LBA48 = (1 << 0), - ATA_TFLAG_ISADDR = (1 << 1), /* enable r/w to nsect/lba regs */ - ATA_TFLAG_DEVICE = (1 << 2), /* enable r/w to device reg */ - - ATA_QCFLAG_WRITE = (1 << 0), /* read==0, write==1 */ ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ ATA_QCFLAG_DMA = (1 << 2), /* data delivered via DMA */ ATA_QCFLAG_ATAPI = (1 << 3), /* is ATAPI packet command? */ @@ -223,29 +217,6 @@ struct ata_port * ports[0]; }; -struct ata_taskfile { - unsigned long flags; /* ATA_TFLAG_xxx */ - u8 protocol; /* ATA_PROT_xxx */ - - u8 ctl; /* control reg */ - - u8 hob_feature; /* additional data */ - u8 hob_nsect; /* to support LBA48 */ - u8 hob_lbal; - u8 hob_lbam; - u8 hob_lbah; - - u8 feature; - u8 nsect; - u8 lbal; - u8 lbam; - u8 lbah; - - u8 device; - - u8 command; /* IO operation */ -}; - struct ata_queued_cmd { struct ata_port *ap; struct ata_device *dev; @@ -293,6 +264,11 @@ * ATAPI7 spec size, 40 ASCII * characters */ + + /* cache info about current transfer mode */ + u8 xfer_protocol; /* taskfile xfer protocol */ + u8 read_cmd; /* opcode to use on read */ + u8 write_cmd; /* opcode to use on write */ }; struct ata_engine { @@ -408,7 +384,6 @@ extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); extern int ata_scsi_error(struct Scsi_Host *host); extern int ata_scsi_release(struct Scsi_Host *host); -extern int ata_scsi_slave_config(struct scsi_device *sdev); extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); /* * Default driver ops implementations @@ -433,6 +408,7 @@ extern int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]); +extern int ata_scsi_slave_config(struct scsi_device *sdev); static inline unsigned long msecs_to_jiffies(unsigned long msecs) diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h --- a/include/linux/pci_ids.h Thu Apr 8 14:58:15 2004 +++ b/include/linux/pci_ids.h Thu Apr 8 14:58:15 2004 @@ -572,6 +572,7 @@ #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