[U-Boot] About PCI of U-BOOT of CANYONLANDS

Hello!
I am testing the video display of U-BOOT by using PCI of CANYONLANDS. I added the following lines.
#ifdef CONFIG_VIDEO #define CONFIG_BIOSEMU #define CONFIG_ATI_RADEON_FB #define VIDEO_IO_OFFSET 0xD8000000 #define CONFIG_SYS_ISA_IO_BASE_ADDRESS VIDEO_IO_OFFSET #define CONFIG_VIDEO_SW_CURSOR #define CONFIG_VIDEO_LOGO #define CONFIG_CFB_CONSOLE #define CONFIG_SPLASH_SCREEN #define CONFIG_VGA_AS_SINGLE_DEVICE #define CONFIG_CMD_BMP #endif /* #ifdef CONFIG_VIDEO */
However, if the memory space of PCI is read, the exception is generated. Do you have any information for PCI of U-BOOT of CANYONLANDS?
Regards, Kazuaki Ichinohe.

On Tuesday 17 March 2009, Kazuaki Ichinohe wrote:
I am testing the video display of U-BOOT by using PCI of CANYONLANDS. I added the following lines.
#ifdef CONFIG_VIDEO #define CONFIG_BIOSEMU #define CONFIG_ATI_RADEON_FB #define VIDEO_IO_OFFSET 0xD8000000 #define CONFIG_SYS_ISA_IO_BASE_ADDRESS VIDEO_IO_OFFSET #define CONFIG_VIDEO_SW_CURSOR #define CONFIG_VIDEO_LOGO #define CONFIG_CFB_CONSOLE #define CONFIG_SPLASH_SCREEN #define CONFIG_VGA_AS_SINGLE_DEVICE #define CONFIG_CMD_BMP #endif /* #ifdef CONFIG_VIDEO */
However, if the memory space of PCI is read, the exception is generated. Do you have any information for PCI of U-BOOT of CANYONLANDS?
PCI should be working on Canyonlands. At least it was the last time I tested. I never tested with an PCI Video card though.
Which U-Boot version are you using? What's the exact error message? Please post the complete bootlog.
Best regards, Stefan
===================================================================== DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de =====================================================================

Hello,
Thank you for the reply.
U-boot version: u-boot-2009.01 boot log is the following.
U-Boot 2009.01 ( 3譛 18 2009 - 09:38:17)
・PU: AMCC PowerPC 460EX Rev. A at 600 MHz (PLB=200, OPB=100, EBC=100 MHz) Security/Kasumi support Bootstrap Option H - Boot ROM Location I2C (Addr 0x52) Internal PCI arbiter disabled 32 kB I-Cache 32 kB D-Cache Board: Canyonlands - AMCC PPC460EX Evaluation Board, 1*PCIe/1*SATA, Rev. 14 I2C: ready DTT: 1 is 38 C DRAM: 512 MB (ECC not enabled, 400 MHz, CL3) FLASH: 64 MB NAND: 128 MiB PCI: Bus Dev VenId DevId Class Int 00 06 1002 5960 0300 ff 00 06 1002 5940 0380 ff PCIE1: link is not up. PCIE1: initialization as root-complex failed Video: ATI Radeon video card (1002, 5960) found @(0:6:0) Machine Check Exception. Caused by (from msr): regs 1fe3ac30 Data Read PLB Error NIP: 1FF82B10 XER: 00000000 LR: 1FF82AE8 REGS: 1fe3ac30 TRAP: 0200 DEAR: 7060002 7 MSR: 00021000 EE: 0 PR: 0 FP: 0 ME: 1 IR/DR: 00
GPR00: 08000080 1FE3AD20 1FE3AF20 00000000 80003018 00000018 1FE401BC 15A30439 GPR08: 1FF43408 88000000 05F5E101 1FF94E10 00000006 FDFFFFFF 1FFABD00 1FFBF000 GPR16: FBFFFFFF FDFFFFFF DFFFFFFF FFFFFBFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF GPR24: FFFFFFFF 1FE3AF20 1FE3AF08 1FE3AE88 1FE3AE80 00003000 1FFADF20 1FE40198 Call backtrace: 1FF82AE8 1FF83458 1FF82498 1FF5FCDC 1FF42EF0 1FF41710 1E29AB51 machine check
U-Boot 2009.01 ( 3譛 18 2009 - 09:38:17)
・PU: AMCC PowerPC 460EX Rev. A at 600 MHz (PLB=200, OPB=100, EBC=100 MHz) Security/Kasumi support Bootstrap Option H - Boot ROM Location I2C (Addr 0x52) Internal PCI arbiter disabled 32 kB I-Cache 32 kB D-Cache Board: Canyonlands - AMCC PPC460EX Evaluation Board, 1*PCIe/1*SATA, Rev. 14 I2C: ready DTT: 1 is 38 C DRAM: 512 MB (ECC not enabled, 400 MHz, CL3) FLASH: 64 MB NAND: 128 MiB PCI: Bus Dev VenId DevId Class Int 00 06 1002 5960 0300 ff 00 06 1002 5940 0380 ff PCIE1: link is not up. PCIE1: initialization as root-complex failed Video: ATI Radeon video card (1002, 5960) found @(0:6:0) Machine Check Exception. Caused by (from msr): regs 1fe3ac30 Data Read PLB Error NIP: 1FF82B10 XER: 00000000 LR: 1FF82AE8 REGS: 1fe3ac30 TRAP: 0200 DEAR: 7060002 7 MSR: 00021000 EE: 0 PR: 0 FP: 0 ME: 1 IR/DR: 00
GPR00: 08000080 1FE3AD20 1FE3AF20 00000000 80003018 00000018 1FE401BC 15AC08AD GPR08: 1FF43408 88000000 05F5E101 1FF94E10 00000006 FDFFFFFF 1FFABD00 1FFBF000 GPR16: FBFFFFFF FDFFFFFF DFFFFFFF FFFFFBFF 00000000 1FE3AC20 00000000 1FF41450 GPR24: 1FF41D34 1FE3AF20 1FE3AF08 1FE3AE88 1FE3AE80 00003000 1FFADF20 1FE40198 Call backtrace: 1FF82AE8 1FF83458 1FF82498 1FF5FCDC 1FF42EF0 1FF41710 1E29AB51 machine check
U-Boot 2009.01 ( 3譛 18 2009 - 09:38:17)
・PU: AMCC PowerPC 460EX Rev. A at 600 MHz (PLB=200, OPB=100, EBC=100 MHz) Security/Kasumi support Bootstrap Option H - Boot ROM Location I2C (Addr 0x52) Internal PCI arbiter disabled 32 kB I-Cache 32 kB D-Cache Board: Canyonlands - AMCC PPC460EX Evaluation Board, 1*PCIe/1*SATA, Rev. 14 I2C: ready DTT: 1 is 38 C DRAM: 512 MB (ECC not enabled, 400 MHz, CL3) FLASH: 64 MB NAND: 128 MiB PCI: Bus Dev VenId DevId Class Int 00 06 1002 5960 0300 ff 00 06 1002 5940 0380 ff PCIE1: link is not up. PCIE1: initialization as root-complex failed Video: ATI Radeon video card (1002, 5960) found @(0:6:0) Machine Check Exception. Caused by (from msr): regs 1fe3ac30 Data Read PLB Error NIP: 1FF82B10 XER: 00000000 LR: 1FF82AE8 REGS: 1fe3ac30 TRAP: 0200 DEAR: 7060002 7 MSR: 00021000 EE: 0 PR: 0 FP: 0 ME: 1 IR/DR: 00
GPR00: 08000080 1FE3AD20 1FE3AF20 00000000 80003018 00000018 1FE401BC 15A680AD GPR08: 1FF43408 88000000 05F5E101 1FF94E10 00000006 FDFFFFFF 1FFABD00 1FFBF000 GPR16: FBFFFFFF FDFFFFFF DFFFFFFF FFFFFBFF 00000000 1FE3AC20 00000000 1FF41450 GPR24: 1FF41D34 1FE3AF20 1FE3AF08 1FE3AE88 1FE3AE80 00003000 1FFADF20 1FE40198 Call backtrace: 1FF82AE8 1FF83458 1FF82498 1FF5FCDC 1FF42EF0 1FF41710 1E29AB51 machine check
U-Boot 2009.01 ( 3譛 18 2009 - 09:38:17)
・PU: AMCC PowerPC 460EX Rev. A at 600 MHz (PLB=200, OPB=100, EBC=100 MHz) Security/Kasumi support Bootstrap Option H - Boot ROM Location I2C (Addr 0x52) Internal PCI arbiter disabled 32 kB I-Cache 32 kB D-Cache Board: Canyonlands - AMCC PPC460EX Evaluation Board, 1*PCIe/1*SATA, Rev. 14 I2C: ready DTT: 1 is 38 C DRAM: 512 MB (ECC not enabled, 400 MHz, CL3) FLASH: 64 MB NAND: 128 MiB PCI: Bus Dev VenId DevId Class Int 00 06 1002 5960 0300 ff 00 06 1002 5940 0380 ff PCIE1: link is not up. PCIE1: initialization as root-complex failed Video: ATI Radeon video card (1002, 5960) found @(0:6:0) Machine Check Exception. Caused by (from msr): regs 1fe3ac30 Data Read PLB Error NIP: 1FF82B10 XER: 00000000 LR: 1FF82AE8 REGS: 1fe3ac30 TRAP: 0200 DEAR: 7060002 7 MSR: 00021000 EE: 0 PR: 0 FP: 0 ME: 1 IR/DR: 00
GPR00: 08000080 1FE3AD20 1FE3AF20 00000000 80003018 00000018 1FE401BC 15AC57B8 GPR08: 1FF43408 88000000 05F5E101 1FF94E10 00000006 FDFFFFFF 1FFABD00 1FFBF000 GPR16: FBFFFFFF FDFFFFFF DFFFFFFF FFFFFBFF 00000000 1FE3AC20 00000000 1FF41450 GPR24: 1FF41D34 1FE3AF20 1FE3AF08 1FE3AE88 1FE3AE80 00003000 1FFADF20 1FE40198 Call backtrace: 1FF82AE8 1FF83458 1FF82498 1FF5FCDC 1FF42EF0 1FF41710 1E29AB51 machine check
U-Boot 2009.01 ( 3譛 18 2009 - 09:38:17)
・PU: AMCC PowerPC 460EX Rev. A at 600 MHz (PLB=200, OPB=100, EBC=100 MHz) Security/Kasumi support Bootstrap Option H - Boot ROM Location I2C (Addr 0x52) Internal PCI arbiter disabled 32 kB I-Cache 32 kB D-Cache Board: Canyonlands - AMCC PPC460EX Evaluation Board, 1*PCIe/1*SATA, Rev. 14 I2C: ready DTT: 1 is 38 C DRAM: 512 MB (ECC not enabled, 400 MHz, CL3)
----------------------------------------------------- The patch is appended.
diff -crN u-boot-2009.01/Makefile u-boot-2009.01-canyonlands/Makefile *** u-boot-2009.01/Makefile 2009-01-26 10:35:44.000000000 +0900 --- u-boot-2009.01-canyonlands/Makefile 2009-01-26 11:08:19.000000000 +0900 *************** *** 148,154 **** CROSS_COMPILE = else ifeq ($(ARCH),ppc) ! CROSS_COMPILE = ppc_8xx- endif ifeq ($(ARCH),arm) CROSS_COMPILE = arm-linux- --- 148,154 ---- CROSS_COMPILE = else ifeq ($(ARCH),ppc) ! CROSS_COMPILE = ppc_4xxFP- endif ifeq ($(ARCH),arm) CROSS_COMPILE = arm-linux- diff -crN u-boot-2009.01/board/amcc/canyonlands/config.mk u-boot-2009.01-canyonlands/board/amcc/canyonlands/config.mk *** u-boot-2009.01/board/amcc/canyonlands/config.mk 2009-01-26 10:35:50.000000000 +0900 --- u-boot-2009.01-canyonlands/board/amcc/canyonlands/config.mk 2009-01-26 11:08:19.000000000 +0900 *************** *** 27,33 **** sinclude $(OBJTREE)/board/$(BOARDDIR)/config.tmp
ifndef TEXT_BASE ! TEXT_BASE = 0xFFFA0000 endif
PLATFORM_CPPFLAGS += -DCONFIG_440=1 --- 27,34 ---- sinclude $(OBJTREE)/board/$(BOARDDIR)/config.tmp
ifndef TEXT_BASE ! #TEXT_BASE = 0xFFFA0000 ! TEXT_BASE = 0xFFF80000 endif
PLATFORM_CPPFLAGS += -DCONFIG_440=1 diff -crN u-boot-2009.01/include/configs/amcc-common.h u-boot-2009.01-canyonlands/include/configs/amcc-common.h *** u-boot-2009.01/include/configs/amcc-common.h 2009-01-26 10:35:52.000000000 +0900 --- u-boot-2009.01-canyonlands/include/configs/amcc-common.h 2009-01-26 11:08:19.000000000 +0900 *************** *** 233,238 **** --- 233,278 ---- "fdt_file=" xstr(CONFIG_HOSTNAME) "/" xstr(CONFIG_HOSTNAME) ".dtb\0"
+ #define CONFIG_AMCC_DEF_ENV_AZBIL \ + "rootfs=/dev/sda6\0" \ + "eldk-rootfs=/dev/sda7\0" \ + "e2drv=0:2\0" \ + "udrv=0:3\0" \ + "atargs=setenv bootargs root=${rootfs} rw\0" \ + "ata_old=run atargs addtty addmisc;" \ + " disk ${kernel_addr_r} ${udrv};" \ + " bootm ${kernel_addr_r}\0" \ + "ata_ud_e2=run atargs addtty addmisc;" \ + " ext2load ide ${e2drv} ${kernel_addr_r} /${bootfile};" \ + " ext2load ide ${e2drv} ${fdt_addr_r} /${fdt_file};" \ + " fdt addr ${fdt_addr_r} 0x4000;" \ + " bootm ${kernel_addr_r} - ${fdt_addr_r}\0" \ + "ata_cu=run atargs addtty addmisc;" \ + " disk ${kernel_addr_cu} ${udrv};" \ + " bootm ${kernel_addr_cu}\0" \ + "ata_cu_e2=run atargs addtty addmisc;" \ + " ext2load ide ${e2drv} ${kernel_addr_cu} /${bootfile-cu};" \ + " bootm ${kernel_addr_cu}\0" \ + "cfargs=setenv bootargs root=${rootfs} rw\0" \ + "cfboot=run cfargs addtty addmisc;" \ + " disk ${kernel_addr_r} ${udrv};" \ + " bootm ${kernel_addr_r}\0" \ + "satargs=setenv bootargs root=${rootfs} rw\0" \ + "flash_sata=run satargs addtty addmisc;" \ + "bootm ${kernel_addr} - ${fdt_addr}\0" \ + "eldkargs=setenv bootargs root=${eldk-rootfs} rw\0" \ + "eldk_boot=run eldkargs addtty addmisc;" \ + " ext2load ide ${e2drv} ${kernel_addr_r} /${bootfile};" \ + " ext2load ide ${e2drv} ${fdt_addr_r} /${fdt_file};" \ + " fdt addr ${fdt_addr_r} 0x4000;" \ + " bootm ${kernel_addr_r} - ${fdt_addr_r}\0" \ + "eldk_flash_sata=run eldkargs addtty addmisc;" \ + "bootm ${kernel_addr} - ${fdt_addr}\0" + + /* * Default environment for arch/ppc booting, * for boards that are not ported to arch/powerpc yet */ *************** *** 259,264 **** --- 299,314 ---- "bootm ${kernel_addr_r}\0"
#define CONFIG_AMCC_DEF_ENV_NOR_UPD \ + "fload=tftp 200000 ${fdt_file}\0" \ + "fupdate=protect off all;" \ + "era 0xFC300000 0xFC31FFFF;" \ + "cp.b 0x200000 0xFC300000 0x20000\0" \ + "fupd=run fload fupdate\0" \ + "kload=tftp 200000 " xstr(CONFIG_HOSTNAME) "/uImage\0" \ + "kupdate=protect off all;" \ + "era 0xFC000000 0xFC2FFFFF;" \ + "cp.b 0x200000 0xFC000000 0x300000\0" \ + "kupd=run kload kupdate\0" \ "load=tftp 200000 " xstr(CONFIG_HOSTNAME) "/u-boot.bin\0" \ "update=protect off " xstr(CONFIG_SYS_MONITOR_BASE) " FFFFFFFF;" \ "era " xstr(CONFIG_SYS_MONITOR_BASE) " FFFFFFFF;" \ diff -crN u-boot-2009.01/include/configs/canyonlands.h u-boot-2009.01-canyonlands/include/configs/canyonlands.h *** u-boot-2009.01/include/configs/canyonlands.h 2009-01-26 10:35:53.000000000 +0900 --- u-boot-2009.01-canyonlands/include/configs/canyonlands.h 2009-03-18 09:37:02.000000000 +0900 *************** *** 413,426 **** * Default environment variables */ #if !defined(CONFIG_ARCHES) #define CONFIG_EXTRA_ENV_SETTINGS \ CONFIG_AMCC_DEF_ENV \ CONFIG_AMCC_DEF_ENV_POWERPC \ CONFIG_AMCC_DEF_ENV_NOR_UPD \ CONFIG_AMCC_DEF_ENV_NAND_UPD \ "kernel_addr=fc000000\0" \ ! "fdt_addr=fc1e0000\0" \ ! "ramdisk_addr=fc200000\0" \ "pciconfighost=1\0" \ "pcie_mode=RP:RP\0" \ "" --- 413,434 ---- * Default environment variables */ #if !defined(CONFIG_ARCHES) + #define CONFIG_ENV_OVERWRITE + #define CONFIG_ETHADDR 00:10:EC:00:FC:A3 + #define CONFIG_ETH1ADDR 00:10:EC:80:FC:A3 + #define CONFIG_IPADDR 10.10.67.40 + #define CONFIG_SERVERIP 10.10.66.208 + #define CONFIG_NETMASK 255.255.255.0 + #define CONFIG_GATEWAYIP 10.10.67.1 #define CONFIG_EXTRA_ENV_SETTINGS \ CONFIG_AMCC_DEF_ENV \ CONFIG_AMCC_DEF_ENV_POWERPC \ + CONFIG_AMCC_DEF_ENV_AZBIL \ CONFIG_AMCC_DEF_ENV_NOR_UPD \ CONFIG_AMCC_DEF_ENV_NAND_UPD \ "kernel_addr=fc000000\0" \ ! "fdt_addr=fc300000\0" \ ! "ramdisk_addr=fc320000\0" \ "pciconfighost=1\0" \ "pcie_mode=RP:RP\0" \ "" *************** *** 733,736 **** --- 741,759 ---- } #endif
+ #define CONFIG_VIDEO + + #ifdef CONFIG_VIDEO + #define CONFIG_BIOSEMU + #define CONFIG_ATI_RADEON_FB + #define VIDEO_IO_OFFSET 0xD8000000 + #define CONFIG_SYS_ISA_IO_BASE_ADDRESS VIDEO_IO_OFFSET + #define CONFIG_VIDEO_SW_CURSOR + #define CONFIG_VIDEO_LOGO + #define CONFIG_CFB_CONSOLE + #define CONFIG_SPLASH_SCREEN + #define CONFIG_VGA_AS_SINGLE_DEVICE + #define CONFIG_CMD_BMP + #endif /* #ifdef CONFIG_VIDEO */ + #endif /* __CONFIG_H */
Stefan Roese さんは書きました:
On Tuesday 17 March 2009, Kazuaki Ichinohe wrote:
I am testing the video display of U-BOOT by using PCI of CANYONLANDS. I added the following lines.
#ifdef CONFIG_VIDEO #define CONFIG_BIOSEMU #define CONFIG_ATI_RADEON_FB #define VIDEO_IO_OFFSET 0xD8000000 #define CONFIG_SYS_ISA_IO_BASE_ADDRESS VIDEO_IO_OFFSET #define CONFIG_VIDEO_SW_CURSOR #define CONFIG_VIDEO_LOGO #define CONFIG_CFB_CONSOLE #define CONFIG_SPLASH_SCREEN #define CONFIG_VGA_AS_SINGLE_DEVICE #define CONFIG_CMD_BMP #endif /* #ifdef CONFIG_VIDEO */
However, if the memory space of PCI is read, the exception is generated. Do you have any information for PCI of U-BOOT of CANYONLANDS?
PCI should be working on Canyonlands. At least it was the last time I tested. I never tested with an PCI Video card though.
Which U-Boot version are you using? What's the exact error message? Please post the complete bootlog.
Best regards, Stefan
===================================================================== DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de =====================================================================

On Wednesday 18 March 2009, Kazuaki Ichinohe wrote:
U-boot version: u-boot-2009.01 boot log is the following.
U-Boot 2009.01 ( 3譛 18 2009 - 09:38:17)
・PU: AMCC PowerPC 460EX Rev. A at 600 MHz (PLB=200, OPB=100, EBC=100 MHz) Security/Kasumi support Bootstrap Option H - Boot ROM Location I2C (Addr 0x52) Internal PCI arbiter disabled 32 kB I-Cache 32 kB D-Cache Board: Canyonlands - AMCC PPC460EX Evaluation Board, 1*PCIe/1*SATA, Rev. 14 I2C: ready DTT: 1 is 38 C DRAM: 512 MB (ECC not enabled, 400 MHz, CL3) FLASH: 64 MB NAND: 128 MiB PCI: Bus Dev VenId DevId Class Int 00 06 1002 5960 0300 ff 00 06 1002 5940 0380 ff PCIE1: link is not up. PCIE1: initialization as root-complex failed Video: ATI Radeon video card (1002, 5960) found @(0:6:0) Machine Check Exception. Caused by (from msr): regs 1fe3ac30 Data Read PLB Error NIP: 1FF82B10 XER: 00000000 LR: 1FF82AE8 REGS: 1fe3ac30 TRAP: 0200 DEAR: 70600027 MSR: 00021000 EE: 0 PR: 0 FP: 0 ME: 1 IR/DR: 00
Anatolij, do you have any ideas what's going wrong here?
Thanks.
Best regards, Stefan
===================================================================== DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de =====================================================================

Stefan Roese wrote:
On Wednesday 18 March 2009, Kazuaki Ichinohe wrote:
U-boot version: u-boot-2009.01 boot log is the following.
U-Boot 2009.01 ( 3譛 18 2009 - 09:38:17)
・PU: AMCC PowerPC 460EX Rev. A at 600 MHz (PLB=200, OPB=100, EBC=100 MHz) Security/Kasumi support Bootstrap Option H - Boot ROM Location I2C (Addr 0x52) Internal PCI arbiter disabled 32 kB I-Cache 32 kB D-Cache Board: Canyonlands - AMCC PPC460EX Evaluation Board, 1*PCIe/1*SATA, Rev. 14 I2C: ready DTT: 1 is 38 C DRAM: 512 MB (ECC not enabled, 400 MHz, CL3) FLASH: 64 MB NAND: 128 MiB PCI: Bus Dev VenId DevId Class Int 00 06 1002 5960 0300 ff 00 06 1002 5940 0380 ff PCIE1: link is not up. PCIE1: initialization as root-complex failed Video: ATI Radeon video card (1002, 5960) found @(0:6:0) Machine Check Exception. Caused by (from msr): regs 1fe3ac30 Data Read PLB Error NIP: 1FF82B10 XER: 00000000 LR: 1FF82AE8 REGS: 1fe3ac30 TRAP: 0200 DEAR: 70600027 MSR: 00021000 EE: 0 PR: 0 FP: 0 ME: 1 IR/DR: 00
Anatolij, do you have any ideas what's going wrong here?
Thanks.
Looks like you have ATI cards in both PCI-E slots and also SATA enabled. This cannot work, as SATA shares lines with x1 PCI-E slot on Canyonlands. Use J6 jumper to enable both PCI-E slots.
Felix.

On Wednesday 18 March 2009, Felix Radensky wrote:
PCI: Bus Dev VenId DevId Class Int 00 06 1002 5960 0300 ff 00 06 1002 5940 0380 ff PCIE1: link is not up. PCIE1: initialization as root-complex failed Video: ATI Radeon video card (1002, 5960) found @(0:6:0) Machine Check Exception. Caused by (from msr): regs 1fe3ac30 Data Read PLB Error NIP: 1FF82B10 XER: 00000000 LR: 1FF82AE8 REGS: 1fe3ac30 TRAP: 0200 DEAR: 70600027 MSR: 00021000 EE: 0 PR: 0 FP: 0 ME: 1 IR/DR: 00
Anatolij, do you have any ideas what's going wrong here?
Thanks.
Looks like you have ATI cards in both PCI-E slots and also SATA enabled. This cannot work, as SATA shares lines with x1 PCI-E slot on Canyonlands. Use J6 jumper to enable both PCI-E slots.
No, it's PCI and not PCIe.
Best regards, Stefan
===================================================================== DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de =====================================================================

Stefan Roese wrote:
On Wednesday 18 March 2009, Felix Radensky wrote:
PCI: Bus Dev VenId DevId Class Int 00 06 1002 5960 0300 ff 00 06 1002 5940 0380 ff PCIE1: link is not up. PCIE1: initialization as root-complex failed Video: ATI Radeon video card (1002, 5960) found @(0:6:0) Machine Check Exception. Caused by (from msr): regs 1fe3ac30 Data Read PLB Error NIP: 1FF82B10 XER: 00000000 LR: 1FF82AE8 REGS: 1fe3ac30 TRAP: 0200 DEAR: 70600027 MSR: 00021000 EE: 0 PR: 0 FP: 0 ME: 1 IR/DR: 00
Anatolij, do you have any ideas what's going wrong here?
Thanks.
Looks like you have ATI cards in both PCI-E slots and also SATA enabled. This cannot work, as SATA shares lines with x1 PCI-E slot on Canyonlands. Use J6 jumper to enable both PCI-E slots.
No, it's PCI and not PCIe.
Best regards, Stefan
I see. Sorry for the noise. I was confused by the presence of two devices, and the fact that there's only one PCI slot on this board. It should be a multifunction PCI device then.
Felix.

On Wednesday 18 March 2009, Felix Radensky wrote:
Looks like you have ATI cards in both PCI-E slots and also SATA enabled. This cannot work, as SATA shares lines with x1 PCI-E slot on Canyonlands. Use J6 jumper to enable both PCI-E slots.
No, it's PCI and not PCIe.
Best regards, Stefan
I see. Sorry for the noise. I was confused by the presence of two devices, and the fact that there's only one PCI slot on this board. It should be a multifunction PCI device then.
Yep. :)
Best regards, Stefan
===================================================================== DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de =====================================================================

Hi Stefan, Kazuaki,
Stefan Roese wrote:
On Wednesday 18 March 2009, Kazuaki Ichinohe wrote:
U-boot version: u-boot-2009.01 boot log is the following.
U-Boot 2009.01 ( 3譛 18 2009 - 09:38:17)
・PU: AMCC PowerPC 460EX Rev. A at 600 MHz (PLB=200, OPB=100, EBC=100 MHz) Security/Kasumi support Bootstrap Option H - Boot ROM Location I2C (Addr 0x52) Internal PCI arbiter disabled 32 kB I-Cache 32 kB D-Cache Board: Canyonlands - AMCC PPC460EX Evaluation Board, 1*PCIe/1*SATA, Rev. 14 I2C: ready DTT: 1 is 38 C DRAM: 512 MB (ECC not enabled, 400 MHz, CL3) FLASH: 64 MB NAND: 128 MiB PCI: Bus Dev VenId DevId Class Int 00 06 1002 5960 0300 ff 00 06 1002 5940 0380 ff PCIE1: link is not up. PCIE1: initialization as root-complex failed Video: ATI Radeon video card (1002, 5960) found @(0:6:0) Machine Check Exception. Caused by (from msr): regs 1fe3ac30 Data Read PLB Error NIP: 1FF82B10 XER: 00000000 LR: 1FF82AE8 REGS: 1fe3ac30 TRAP: 0200 DEAR: 70600027 MSR: 00021000 EE: 0 PR: 0 FP: 0 ME: 1 IR/DR: 00
Anatolij, do you have any ideas what's going wrong here?
one issue is incorrect VIDEO_IO_OFFSET in the board config file, it should be 0xD0800000 instead of 0xD8000000, i think.
Kazuaki, could you please change VIDEO_IO_OFFSET to 0xD0800000 and test again?
Best regards, Anatolij

Hi Anatolij !
Kazuaki, could you please change VIDEO_IO_OFFSET to 0xD0800000 and test again?
I'll try it.
Regards, Kazuaki Ichinohe.
Anatolij Gustschin さんは書きました:
Hi Stefan, Kazuaki,
Stefan Roese wrote:
On Wednesday 18 March 2009, Kazuaki Ichinohe wrote:
U-boot version: u-boot-2009.01 boot log is the following.
U-Boot 2009.01 ( 3譛 18 2009 - 09:38:17)
・PU: AMCC PowerPC 460EX Rev. A at 600 MHz (PLB=200, OPB=100, EBC=100 MHz) Security/Kasumi support Bootstrap Option H - Boot ROM Location I2C (Addr 0x52) Internal PCI arbiter disabled 32 kB I-Cache 32 kB D-Cache Board: Canyonlands - AMCC PPC460EX Evaluation Board, 1*PCIe/1*SATA, Rev. 14 I2C: ready DTT: 1 is 38 C DRAM: 512 MB (ECC not enabled, 400 MHz, CL3) FLASH: 64 MB NAND: 128 MiB PCI: Bus Dev VenId DevId Class Int 00 06 1002 5960 0300 ff 00 06 1002 5940 0380 ff PCIE1: link is not up. PCIE1: initialization as root-complex failed Video: ATI Radeon video card (1002, 5960) found @(0:6:0) Machine Check Exception. Caused by (from msr): regs 1fe3ac30 Data Read PLB Error NIP: 1FF82B10 XER: 00000000 LR: 1FF82AE8 REGS: 1fe3ac30 TRAP: 0200 DEAR: 70600027 MSR: 00021000 EE: 0 PR: 0 FP: 0 ME: 1 IR/DR: 00
Anatolij, do you have any ideas what's going wrong here?
one issue is incorrect VIDEO_IO_OFFSET in the board config file, it should be 0xD0800000 instead of 0xD8000000, i think.
Kazuaki, could you please change VIDEO_IO_OFFSET to 0xD0800000 and test again?
Best regards, Anatolij

Hi Anatolij, Stefan,
The exception was generated.
---------------------------------- U-Boot 2009.01 ( 3月 18 2009 - 21:16:24)
CPU: AMCC PowerPC 460EX Rev. A at 800 MHz (PLB=200, OPB=100, EBC=100 MHz) Security/Kasumi support Bootstrap Option H - Boot ROM Location I2C (Addr 0x52) Internal PCI arbiter disabled 32 kB I-Cache 32 kB D-Cache Board: Canyonlands - AMCC PPC460EX Evaluation Board, 1*PCIe/1*SATA, Rev. 14 I2C: ready DTT: 1 is 39 C DRAM: 512 MB (ECC not enabled, 400 MHz, CL3) FLASH: 64 MB NAND: 128 MiB PCI: Bus Dev VenId DevId Class Int 00 06 1002 5960 0300 ff 00 06 1002 5940 0380 ff PCIE1: link is not up. PCIE1: initialization as root-complex failed Video: ATI Radeon video card (1002, 5960) found @(0:6:0) Machine Check Exception. Caused by (from msr): regs 1fe3ac30 Data Read PLB Error NIP: 1FF82B10 XER: 00000000 LR: 1FF82AE8 REGS: 1fe3ac30 TRAP: 0200 DEAR: 00000000 MSR: 00021000 EE: 0 PR: 0 FP: 0 ME: 1 IR/DR: 00
GPR00: 08000080 1FE3AD20 1FE3AF20 00000000 80003018 00000018 1FE401BC 1CA13040 GPR08: 1FF43408 88000000 05F5E101 1FF94E10 00000006 055671DE 1FFABD00 1FFBF000 GPR16: FFFE21E8 FFFE21E8 FFFE2068 FFFE21E8 FFFE21E8 FFFE2068 FFFE2068 FFFD572C GPR24: E3000D80 1FE3AF20 1FE3AF08 1FE3AE88 1FE3AE80 00003000 1FFADF20 1FE40198 Call backtrace: 1FF82AE8 1FF83458 1FF82498 1FF5FCDC 1FF42EF0 1FF41710 machine check
Regards, Kazuaki Ichinohe
Kazuaki Ichinohe さんは書きました:
Hi Anatolij !
Kazuaki, could you please change VIDEO_IO_OFFSET to 0xD0800000 and test again?
I'll try it.
Regards, Kazuaki Ichinohe.
Anatolij Gustschin さんは書きました:
Hi Stefan, Kazuaki,
Stefan Roese wrote:
On Wednesday 18 March 2009, Kazuaki Ichinohe wrote:
U-boot version: u-boot-2009.01 boot log is the following.
U-Boot 2009.01 ( 3譛 18 2009 - 09:38:17)
・PU: AMCC PowerPC 460EX Rev. A at 600 MHz (PLB=200, OPB=100, EBC=100 MHz) Security/Kasumi support Bootstrap Option H - Boot ROM Location I2C (Addr 0x52) Internal PCI arbiter disabled 32 kB I-Cache 32 kB D-Cache Board: Canyonlands - AMCC PPC460EX Evaluation Board, 1*PCIe/1*SATA, Rev. 14 I2C: ready DTT: 1 is 38 C DRAM: 512 MB (ECC not enabled, 400 MHz, CL3) FLASH: 64 MB NAND: 128 MiB PCI: Bus Dev VenId DevId Class Int 00 06 1002 5960 0300 ff 00 06 1002 5940 0380 ff PCIE1: link is not up. PCIE1: initialization as root-complex failed Video: ATI Radeon video card (1002, 5960) found @(0:6:0) Machine Check Exception. Caused by (from msr): regs 1fe3ac30 Data Read PLB Error NIP: 1FF82B10 XER: 00000000 LR: 1FF82AE8 REGS: 1fe3ac30 TRAP: 0200 DEAR: 70600027 MSR: 00021000 EE: 0 PR: 0 FP: 0 ME: 1 IR/DR: 00
Anatolij, do you have any ideas what's going wrong here?
one issue is incorrect VIDEO_IO_OFFSET in the board config file, it should be 0xD0800000 instead of 0xD8000000, i think.
Kazuaki, could you please change VIDEO_IO_OFFSET to 0xD0800000 and test again?
Best regards, Anatolij

Hi Anatolij, Stefan,
The memory space is displayed in BAR2 of the PCI configuration space. The video driver accesses this memory space and the exception is generated.
driver source: u-boot/drivers/video/ati_radeon_fb.c function name: void *video_hw_init(void) line : 760line
I attach the log where the exception is generated. I confirmed it by the source of the following patches.
----- patch ------ #undef CONFIG_VIDEO #ifdef CONFIG_VIDEO #define CONFIG_BIOSEMU #define CONFIG_ATI_RADEON_FB #define VIDEO_IO_OFFSET 0xD8000000 #define CONFIG_SYS_ISA_IO_BASE_ADDRESS VIDEO_IO_OFFSET #define CONFIG_VIDEO_SW_CURSOR #define CONFIG_VIDEO_LOGO #define CONFIG_CFB_CONSOLE #define CONFIG_SPLASH_SCREEN #define CONFIG_VGA_AS_SINGLE_DEVICE #define CONFIG_CMD_BMP #endif /* #ifdef CONFIG_VIDEO */
----- exception log -------- U-Boot 2009.01 ( 3月 18 2009 - 18:52:14)
CPU: AMCC PowerPC 460EX Rev. A at 800 MHz (PLB=200, OPB=100, EBC=100 MHz) Security/Kasumi support Bootstrap Option H - Boot ROM Location I2C (Addr 0x52) Internal PCI arbiter disabled 32 kB I-Cache 32 kB D-Cache Board: Canyonlands - AMCC PPC460EX Evaluation Board, 1*PCIe/1*SATA, Rev. 14 I2C: ready DTT: 1 is 39 C DRAM: 512 MB (ECC not enabled, 400 MHz, CL3) FLASH: 64 MB NAND: 128 MiB PCI: Bus Dev VenId DevId Class Int 00 06 1002 5960 0300 ff 00 06 1002 5940 0380 ff PCIE1: link is not up. PCIE1: initialization as root-complex failed Net: ppc_4xx_eth0, ppc_4xx_eth1
Type run flash_nfs to mount root filesystem over NFS
=> pci Scanning PCI devices on bus 0 BusDevFun VendorId DeviceId Device Class Sub-Class _____________________________________________________________ 00.06.00 0x1002 0x5960 Display controller 0x00 00.06.01 0x1002 0x5940 Display controller 0x80 => pci header 0.6.0 vendor ID = 0x1002 device ID = 0x5960 command register = 0x0007 status register = 0x02b0 revision ID = 0x01 class code = 0x03 (Display controller) sub class code = 0x00 programming interface = 0x00 cache line = 0x08 latency time = 0x80 header type = 0x80 BIST = 0x00 base address 0 = 0x80000008 base address 1 = 0x00001001 base address 2 = 0x88000000 base address 3 = 0x00000000 base address 4 = 0x00000000 base address 5 = 0x00000000 cardBus CIS pointer = 0x00000000 sub system vendor ID = 0x18bc sub system ID = 0x0580 expansion ROM base address = 0x00000000 interrupt line = 0xff interrupt pin = 0x01 min Grant = 0x08 max Latency = 0x00 => md 0x88000000 88000000:Machine Check Exception. Caused by (from msr): regs 1fe51c08 Data Read PLB Error NIP: 1FF859DC XER: 00000000 LR: 1FF859AC REGS: 1fe51c08 TRAP: 0200 DEAR: 00000000 MSR: 00029000 EE: 1 PR: 0 FP: 0 ME: 1 IR/DR: 00
GPR00: 1FFB2178 1FE51CF8 1FE51F24 1FFA0528 1FFB2178 00000003 00000003 2E6C1FF4 GPR08: 1FF5A408 00000020 05F5E101 2FAF080A 00000008 055661DE 1FFB0700 1FF9F8F4 GPR16: 1FF9F870 1FFA0530 1FFA0528 1FF9F120 1FFABC34 1FE51D00 88000000 88000000 GPR24: 1FE51D00 00000040 00000000 00000004 1FE51D00 00000004 1FFB2178 88000000 Call backtrace: 1FF859AC 1FF702D4 1FF7B948 1FF7B04C 1FF7B1BC 1FF7DDD0 1FF59F64 1FF58710 machine check
U-Boot 2009.01 ( 3月 18 2009 - 18:52:14)
CPU: AMCC PowerPC 460EX Rev. A at 800 MHz (PLB=200, OPB=100, EBC=100 MHz) Security/Kasumi support Bootstrap Option H - Boot ROM Location I2C (Addr 0x52) Internal PCI arbiter disabled 32 kB I-Cache 32 kB D-Cache Board: Canyonlands - AMCC PPC460EX Evaluation Board, 1*PCIe/1*SATA, Rev. 14 I2C: ready DTT: 1 is 40 C DRAM: 512 MB (ECC not enabled, 400 MHz, CL3) FLASH: 64 MB NAND: 128 MiB PCI: Bus Dev VenId DevId Class Int 00 06 1002 5960 0300 ff 00 06 1002 5940 0380 ff PCIE1: link is not up. PCIE1: initialization as root-complex failed Net: ppc_4xx_eth0, ppc_4xx_eth1
Type run flash_nfs to mount root filesystem over NFS
=>
Regards, Kazuaki Ichinohe
Kazuaki Ichinohe さんは書きました:
Hi Anatolij, Stefan,
The exception was generated.
U-Boot 2009.01 ( 3月 18 2009 - 21:16:24)
CPU: AMCC PowerPC 460EX Rev. A at 800 MHz (PLB=200, OPB=100, EBC=100 MHz) Security/Kasumi support Bootstrap Option H - Boot ROM Location I2C (Addr 0x52) Internal PCI arbiter disabled 32 kB I-Cache 32 kB D-Cache Board: Canyonlands - AMCC PPC460EX Evaluation Board, 1*PCIe/1*SATA, Rev. 14 I2C: ready DTT: 1 is 39 C DRAM: 512 MB (ECC not enabled, 400 MHz, CL3) FLASH: 64 MB NAND: 128 MiB PCI: Bus Dev VenId DevId Class Int 00 06 1002 5960 0300 ff 00 06 1002 5940 0380 ff PCIE1: link is not up. PCIE1: initialization as root-complex failed Video: ATI Radeon video card (1002, 5960) found @(0:6:0) Machine Check Exception. Caused by (from msr): regs 1fe3ac30 Data Read PLB Error NIP: 1FF82B10 XER: 00000000 LR: 1FF82AE8 REGS: 1fe3ac30 TRAP: 0200 DEAR: 00000000 MSR: 00021000 EE: 0 PR: 0 FP: 0 ME: 1 IR/DR: 00
GPR00: 08000080 1FE3AD20 1FE3AF20 00000000 80003018 00000018 1FE401BC 1CA13040 GPR08: 1FF43408 88000000 05F5E101 1FF94E10 00000006 055671DE 1FFABD00 1FFBF000 GPR16: FFFE21E8 FFFE21E8 FFFE2068 FFFE21E8 FFFE21E8 FFFE2068 FFFE2068 FFFD572C GPR24: E3000D80 1FE3AF20 1FE3AF08 1FE3AE88 1FE3AE80 00003000 1FFADF20 1FE40198 Call backtrace: 1FF82AE8 1FF83458 1FF82498 1FF5FCDC 1FF42EF0 1FF41710 machine check
Regards, Kazuaki Ichinohe
Kazuaki Ichinohe さんは書きました:
Hi Anatolij !
Kazuaki, could you please change VIDEO_IO_OFFSET to 0xD0800000 and test again?
I'll try it.
Regards, Kazuaki Ichinohe.
Anatolij Gustschin さんは書きました:
Hi Stefan, Kazuaki,
Stefan Roese wrote:
On Wednesday 18 March 2009, Kazuaki Ichinohe wrote:
U-boot version: u-boot-2009.01 boot log is the following.
U-Boot 2009.01 ( 3譛 18 2009 - 09:38:17)
・PU: AMCC PowerPC 460EX Rev. A at 600 MHz (PLB=200, OPB=100, EBC=100 MHz) Security/Kasumi support Bootstrap Option H - Boot ROM Location I2C (Addr 0x52) Internal PCI arbiter disabled 32 kB I-Cache 32 kB D-Cache Board: Canyonlands - AMCC PPC460EX Evaluation Board, 1*PCIe/1*SATA, Rev. 14 I2C: ready DTT: 1 is 38 C DRAM: 512 MB (ECC not enabled, 400 MHz, CL3) FLASH: 64 MB NAND: 128 MiB PCI: Bus Dev VenId DevId Class Int 00 06 1002 5960 0300 ff 00 06 1002 5940 0380 ff PCIE1: link is not up. PCIE1: initialization as root-complex failed Video: ATI Radeon video card (1002, 5960) found @(0:6:0) Machine Check Exception. Caused by (from msr): regs 1fe3ac30 Data Read PLB Error NIP: 1FF82B10 XER: 00000000 LR: 1FF82AE8 REGS: 1fe3ac30 TRAP: 0200 DEAR: 70600027 MSR: 00021000 EE: 0 PR: 0 FP: 0 ME: 1 IR/DR: 00
Anatolij, do you have any ideas what's going wrong here?
one issue is incorrect VIDEO_IO_OFFSET in the board config file, it should be 0xD0800000 instead of 0xD8000000, i think.
Kazuaki, could you please change VIDEO_IO_OFFSET to 0xD0800000 and test again?
Best regards, Anatolij

This patch adds a SATA harddisk driver for the canyonlands.
[environment variable, boot script] setenv bootargs root=/dev/sda7 rw setenv bootargs ${bootargs} console=ttyS0,115200 setenv bootargs ${bootargs} console=ttyS0,115200 ext2load scsi 0:2 0x400000 /canyonlands/uImage ext2load scsi 0:2 0x800000 /canyonlands/canyonlands.dtb fdt addr 0x800000 0x4000 bootm 0x400000 - 0x800000
[confirmed hard disk] Bootable disk (1)maker: FUJITSU , type : MODEL No.MHW2040BS (2)maker: HAGIWARA SYSCOM , type : HFD25S-032GT (3)maker: TOSHIBA , type : MK4032GSX
UnBootable disk (1) maker: FUJITSU , type : MHW2060BK (2) maker: MTRON , type : MSD-SATA3525 (3) maker: SAMSUNG , type : HD250HJ
[patch] diff -crN u-boot-2009.03/common/cmd_scsi.c u-boot-2009.03-sata/common/cmd_scsi.c *** u-boot-2009.03/common/cmd_scsi.c 2009-03-22 06:04:41.000000000 +0900 --- u-boot-2009.03-sata/common/cmd_scsi.c 2009-03-23 19:24:45.000000000 +0900 *************** *** 47,54 **** --- 47,56 ---- #define SCSI_DEV_ID 0x5288
#else + #ifndef CONFIG_SATA_DWC #error no scsi device defined #endif + #endif
static ccb tempccb; /* temporary scsi command buffer */ *************** *** 179,184 **** --- 181,187 ---- { int busdevfunc;
+ #ifndef CONFIG_SATA_DWC busdevfunc=pci_find_device(SCSI_VEND_ID,SCSI_DEV_ID,0); /* get PCI Device ID */ if(busdevfunc==-1) { printf("Error SCSI Controller (%04X,%04X) not found\n",SCSI_VEND_ID,SCSI_DEV_ID); *************** *** 189,195 **** --- 192,204 ---- printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n",SCSI_VEND_ID,SCSI_DEV_ID,(busdevfunc>>16)&0xFF,(busdevfunc>>11)&0x1F,(busdevfunc>>8)&0x7); } #endif + #endif + #ifdef CONFIG_SATA_DWC + sata_dwc_probe(); + #endif + #ifndef CONFIG_SATA_DWC scsi_low_level_init(busdevfunc); + #endif scsi_scan(1); }
*************** *** 444,451 ****
/**************************************************************************************** * scsi_read */ ! #define SCSI_MAX_READ_BLK 0xFFFF /* almost the maximum amount of the scsi_ext command.. */
ulong scsi_read(int device, ulong blknr, ulong blkcnt, void *buffer) { --- 453,463 ----
/**************************************************************************************** * scsi_read */ ! #if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) ! #define SCSI_MAX_READ_BLK 0xFF ! #else #define SCSI_MAX_READ_BLK 0xFFFF /* almost the maximum amount of the scsi_ext command.. */ + #endif
ulong scsi_read(int device, ulong blknr, ulong blkcnt, void *buffer) { diff -crN u-boot-2009.03/drivers/block/Makefile u-boot-2009.03-sata/drivers/block/Makefile *** u-boot-2009.03/drivers/block/Makefile 2009-03-22 06:04:41.000000000 +0900 --- u-boot-2009.03-sata/drivers/block/Makefile 2009-03-23 19:22:31.000000000 +0900 *************** *** 34,39 **** --- 34,40 ---- COBJS-$(CONFIG_IDE_SIL680) += sil680.o COBJS-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o COBJS-$(CONFIG_SYSTEMACE) += systemace.o + COBJS-$(CONFIG_SATA_DWC) += sata_dwc.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff -crN u-boot-2009.03/drivers/block/sata_dwc.c u-boot-2009.03-sata/drivers/block/sata_dwc.c *** u-boot-2009.03/drivers/block/sata_dwc.c 1970-01-01 09:00:00.000000000 +0900 --- u-boot-2009.03-sata/drivers/block/sata_dwc.c 2009-03-23 19:22:31.000000000 +0900 *************** *** 0 **** --- 1,2166 ---- + /* + * sata_dwc.c + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld mmiesfeld@amcc.com + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese sr@denx.de + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + + #include <common.h> + #include <command.h> + #include <pci.h> + #include <asm/processor.h> + #include <asm/errno.h> + #include <asm/io.h> + #include <malloc.h> + #include <scsi.h> + #include <ata.h> + #include <linux/ctype.h> + + /* sata_dwc.h */ + #include "sata_dwc.h" + + /* Base Address */ + #define SATA_BASE_ADDR 0xe20d1000 + #define SATA_DMA_REG_ADDR 0xe20d0800 + + /* SATA DMA driver Globals */ + #define DMA_NUM_CHANS 1 + #define DMA_NUM_CHAN_REGS 8 + + /* SATA DMA Register definitions */ + #define AHB_DMA_BRST_DFLT 16 /* 4 data items burst length */ + + struct dmareg { + u32 low; /* Low bits 0-31 */ + u32 high; /* High bits 32-63 */ + }; + + /* DMA Per Channel registers */ + struct dma_chan_regs { + struct dmareg sar; /* Source Address */ + struct dmareg dar; /* Destination address */ + struct dmareg llp; /* Linked List Pointer */ + struct dmareg ctl; /* Control */ + struct dmareg sstat; /* Source Status not implemented in core */ + struct dmareg dstat; /* Destination Status not implemented in core */ + struct dmareg sstatar; /* Source Status Address not impl in core */ + struct dmareg dstatar; /* Destination Status Address not implemented */ + struct dmareg cfg; /* Config */ + struct dmareg sgr; /* Source Gather */ + struct dmareg dsr; /* Destination Scatter */ + }; + + /* Generic Interrupt Registers */ + struct dma_interrupt_regs { + struct dmareg tfr; /* Transfer Interrupt */ + struct dmareg block; /* Block Interrupt */ + struct dmareg srctran; /* Source Transfer Interrupt */ + struct dmareg dsttran; /* Dest Transfer Interrupt */ + struct dmareg error; /* Error */ + }; + + struct ahb_dma_regs { + struct dma_chan_regs chan_regs[DMA_NUM_CHAN_REGS]; /* Channel Registers */ + struct dma_interrupt_regs interrupt_raw; /* Raw Interrupt */ + struct dma_interrupt_regs interrupt_status; /* Interrupt Status */ + struct dma_interrupt_regs interrupt_mask; /* Interrupt Mask */ + struct dma_interrupt_regs interrupt_clear; /* Interrupt Clear */ + struct dmareg statusInt; /* Interrupt combined */ + struct dmareg rq_srcreg; /* Src Trans Req */ + struct dmareg rq_dstreg; /* Dst Trans Req */ + struct dmareg rq_sgl_srcreg; /* Sngl Src Trans Req */ + struct dmareg rq_sgl_dstreg; /* Sngl Dst Trans Req */ + struct dmareg rq_lst_srcreg; /* Last Src Trans Req */ + struct dmareg rq_lst_dstreg; /* Last Dst Trans Req */ + struct dmareg dma_cfg; /* DMA Config */ + struct dmareg dma_chan_en; /* DMA Channel Enable */ + struct dmareg dma_id; /* DMA ID */ + struct dmareg dma_test; /* DMA Test */ + struct dmareg res1; /* reserved */ + struct dmareg res2; /* reserved */ + /* DMA Comp Params + * Param 6 = dma_param[0], Param 5 = dma_param[1], + * Param 4 = dma_param[2] ... + */ + struct dmareg dma_params[6]; + }; + + /* DMA Register Operation Bits */ + #define DMA_EN 0x00000001 /* Enable AHB DMA */ + #define DMA_CHANNEL(ch) (0x00000001 << (ch)) /* Select channel */ + #define DMA_ENABLE_CHAN(ch) ((0x00000001 << (ch)) | \ + ((0x000000001 << (ch)) << 8)) /* Enable channel */ + #define DMA_DISABLE_CHAN(ch) (0x00000000 | \ + ((0x000000001 << (ch)) << 8)) /* Disable channel */ + + #define SATA_DWC_MAX_PORTS 1 + #define SATA_DWC_SCR_OFFSET 0x24 + #define SATA_DWC_REG_OFFSET 0x64 + + /* DWC SATA Registers */ + struct sata_dwc_regs { + u32 fptagr; /* 1st party DMA tag */ + u32 fpbor; /* 1st party DMA buffer offset */ + u32 fptcr; /* 1st party DMA Xfr count */ + u32 dmacr; /* DMA Control */ + u32 dbtsr; /* DMA Burst Transac size */ + u32 intpr; /* Interrupt Pending */ + u32 intmr; /* Interrupt Mask */ + u32 errmr; /* Error Mask */ + u32 llcr; /* Link Layer Control */ + u32 phycr; /* PHY Control */ + u32 physr; /* PHY Status */ + u32 rxbistpd; /* Recvd BIST pattern def register */ + u32 rxbistpd1; /* Recvd BIST data dword1 */ + u32 rxbistpd2; /* Recvd BIST pattern data dword2 */ + u32 txbistpd; /* Trans BIST pattern def register */ + u32 txbistpd1; /* Trans BIST data dword1 */ + u32 txbistpd2; /* Trans BIST data dword2 */ + u32 bistcr; /* BIST Control Register */ + u32 bistfctr; /* BIST FIS Count Register */ + u32 bistsr; /* BIST Status Register */ + u32 bistdecr; /* BIST Dword Error count register */ + u32 res[15]; /* Reserved locations */ + u32 testr; /* Test Register */ + u32 versionr; /* Version Register */ + u32 idr; /* ID Register */ + u32 unimpl[192]; /* Unimplemented */ + u32 dmadr[256]; /* FIFO Locations in DMA Mode */ + }; + + /* DWC SATA Register Operations */ + #define SATA_DWC_TXFIFO_DEPTH 0x01FF + #define SATA_DWC_RXFIFO_DEPTH 0x01FF + + #define SATA_DWC_DBTSR_MWR(size) ((size/4) & SATA_DWC_TXFIFO_DEPTH) + #define SATA_DWC_DBTSR_MRD(size) (((size/4) & SATA_DWC_RXFIFO_DEPTH) << 16) + #define SATA_DWC_INTPR_DMAT 0x00000001 + #define SATA_DWC_INTPR_NEWFP 0x00000002 + #define SATA_DWC_INTPR_PMABRT 0x00000004 + #define SATA_DWC_INTPR_ERR 0x00000008 + #define SATA_DWC_INTPR_NEWBIST 0x00000010 + #define SATA_DWC_INTPR_IPF 0x10000000 + #define SATA_DWC_INTMR_DMATM 0x00000001 + #define SATA_DWC_INTMR_NEWFPM 0x00000002 + #define SATA_DWC_INTMR_PMABRTM 0x00000004 + #define SATA_DWC_INTMR_ERRM 0x00000008 + #define SATA_DWC_INTMR_NEWBISTM 0x00000010 + + #define SATA_DWC_DMACR_TMOD_TXCHEN 0x00000004 + #define SATA_DWC_DMACR_TXRXCH_CLEAR SATA_DWC_DMACR_TMOD_TXCHEN + + #define SATA_DWC_QCMD_MAX 32 + + /* This is all error bits, zero's are reserved fields. */ + #define SATA_DWC_SERROR_ERR_BITS 0x0FFF0F03 + + /* + * Commonly used DWC SATA driver Macros + */ + #define HSDEVP_FROM_AP(ap) (struct sata_dwc_device_port*)(ap)->private_data + + struct sata_dwc_device { + struct device *dev; /* generic device struct */ + struct ata_probe_ent *pe; /* ptr to probe-ent */ + struct ata_host *host; + u8 *reg_base; + struct sata_dwc_regs *sata_dwc_regs; /* DW Synopsys SATA specific */ + int irq_dma; + }; + + struct sata_dwc_device_port { + struct sata_dwc_device *hsdev; + int cmd_issued[SATA_DWC_QCMD_MAX]; + u32 dma_chan[SATA_DWC_QCMD_MAX]; + int dma_pending[SATA_DWC_QCMD_MAX]; + }; + + enum { + SATA_DWC_CMD_ISSUED_NOT = 0, + SATA_DWC_CMD_ISSUED_PEND = 1, + SATA_DWC_CMD_ISSUED_EXEC = 2, + SATA_DWC_CMD_ISSUED_NODATA = 3, + + SATA_DWC_DMA_PENDING_NONE = 0, + SATA_DWC_DMA_PENDING_TX = 1, + SATA_DWC_DMA_PENDING_RX = 2, + }; + + /* delay Macros */ + #define msleep(a) udelay(a * 1000) + #define ssleep(a) msleep(a * 1000) + + static int ata_probe_timeout = (ATA_TMOUT_INTERNAL / 100); + + enum sata_dev_state { + SATA_INIT = 0, + SATA_READY = 1, + SATA_NODEVICE = 2, + SATA_ERROR = 3, + }; + enum sata_dev_state dev_state = SATA_INIT; + + /* + * Globals + */ + static struct ahb_dma_regs *sata_dma_regs = 0; + static struct ata_host *phost; + static struct ata_port ap; + static struct ata_port *pap = ≈ + static struct ata_device ata_device; + static struct sata_dwc_device_port dwc_devp; + + static void *scr_addr_sstatus; + static char temp_data_buf[512]; + static u32 temp_n_block = 0; + + /* + * Prototype + */ + unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, unsigned int buflen, + unsigned long timeout); + unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable,u8 feature); + unsigned int ata_dev_init_params(struct ata_device *dev, u16 heads, u16 sectors); + void clear_serror(void); + u8 ata_irq_on(struct ata_port *ap); + struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap,unsigned int tag); + int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq); + void ata_tf_to_host(struct ata_port *ap,const struct ata_taskfile *tf); + unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc); + void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf); + unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc); + u8 ata_check_altstatus(struct ata_port *ap); + static u8 ata_check_status(struct ata_port *ap); + void ata_dev_select(struct ata_port *ap, unsigned int device,unsigned int wait, + unsigned int can_sleep); + void ata_qc_issue(struct ata_queued_cmd *qc); + void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf); + int ata_dev_read_sectors(ccb *pccb); + void ata_std_dev_select(struct ata_port *ap, unsigned int device); + void ata_qc_complete(struct ata_queued_cmd *qc); + void __ata_qc_complete(struct ata_queued_cmd *qc); + void fill_result_tf(struct ata_queued_cmd *qc); + void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); + void ata_mmio_data_xfer(struct ata_device *dev, + unsigned char *buf,unsigned int buflen); + void ata_pio_task(struct ata_port *arg_ap); + void __ata_port_freeze(struct ata_port *ap); + int ata_port_freeze(struct ata_port *ap); + void ata_qc_free(struct ata_queued_cmd *qc); + void ata_pio_sectors(struct ata_queued_cmd *qc); + void ata_pio_sector(struct ata_queued_cmd *qc); + void ata_pio_queue_task(struct ata_port *ap, + void *data,unsigned long delay); + void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq); + int sata_dwc_softreset(struct ata_port *ap); + void sata_dwc_probe(void); + + u8 ata_check_altstatus(struct ata_port *ap) + { + u8 val = 0; + val = readb(ap->ioaddr.altstatus_addr); + return val; + } + + int check_sata_dev_state(void) + { + static ccb tempccb; /* temporary scsi command buffer */ + ccb *pccb = (ccb *)&tempccb; + int ret = 0; + int i = 0; + + while(1){ + udelay (10000); /* 10 ms */ + + pccb->cmd[0] = SCSI_READ10; + pccb->cmd[1] = 0; + pccb->cmd[2] = 0; + pccb->cmd[3] = 0; + pccb->cmd[4] = 0; + pccb->cmd[5] = 0; + pccb->cmd[6] = 0; + pccb->cmd[7] = 0; + pccb->cmd[8] = 1; + pccb->cmdlen = 10; + pccb->pdata = &temp_data_buf[0]; /* dummy */ + pccb->datalen = 512; + + /* Send Read Command */ + ret = ata_dev_read_sectors(pccb); + + /* result TRUE => break */ + if(ret == 0){ + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)){ + printf("** TimeOUT **\n"); + dev_state = SATA_NODEVICE; /* set device status flag */ + return FALSE; + } + + if ((i >= 100) && ((i%100)==0)) { + printf("."); + } + } + + /* Set device status flag */ + dev_state = SATA_READY; + + return TRUE; + } + + void ata_id_string(const u16 *id, unsigned char *s, + unsigned int ofs, unsigned int len) + { + unsigned int c; + + while (len > 0) { + c = id[ofs] >> 8; + *s = c; + s++; + + c = id[ofs] & 0xff; + *s = c; + s++; + + ofs++; + len -= 2; + } + } + + static int waiting_for_reg_state(volatile u8 *offset, + int timeout_msec, + u32 sign) + { + int i; + u32 status; + + for (i = 0; i < timeout_msec; i++){ + status = readl(offset); + if ( ( status & sign ) != 0 ){ + break; + } + msleep(1); + } + + return (i < timeout_msec) ? 0 : -1; + } + + static inline u32 qcmd_tag_to_mask(u8 tag) + { + return (0x00000001 << (tag & 0x1f)); + } + + static u8 ata_check_status(struct ata_port *ap) + { + u8 val = 0; + val = readb(ap->ioaddr.status_addr); + return val; + } + + static u8 ata_busy_wait(struct ata_port *ap, unsigned int bits,unsigned int max) + { + u8 status; + + do { + udelay(10); + status = ata_check_status(ap); + max--; + } while (status != 0xff && (status & bits) && (max > 0)); + + return status; + } + + static u8 ata_wait_idle(struct ata_port *ap) + { + u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + return status; + } + + static int sata_dwc_scsiop_inq(ccb *pccb) + { + struct ata_device *ata_dev = &ata_device; + u16 *id; + + /* Set IDENTIFY Data */ + id = ata_dev->id; + + /* make INQUIRY header */ + u8 hdr[] = { + 0, + 0, + 0x5, /* claim SPC-3 version compatibility */ + 2, + 95 - 4 + }; + + /* set scsi removeable (RMB) bit per ata bit */ + if (ata_id_removeable(id)){ + hdr[1] |= (1 << 7); + } + + memcpy(pccb->pdata, hdr, sizeof(hdr)); + + if (pccb->datalen > 35) { + memcpy(&pccb->pdata[8], "ATA ", 8); + ata_id_string(id, &pccb->pdata[16], ATA_ID_PROD, 16); + ata_id_string(id, &pccb->pdata[32], ATA_ID_FW_REV, 4); + if (pccb->pdata[32] == 0 || pccb->pdata[32] == ' '){ + memcpy(&pccb->pdata[32], "n/a ", 4); + } + } + + if (pccb->datalen > 63) { + const u8 versions[] = { + 0x60, /* SAM-3 (no version claimed) */ + 0x03, + 0x20, /* SBC-2 (no version claimed) */ + 0x02, + 0x60 /* SPC-3 (no version claimed) */ + }; + memcpy(pccb->pdata + 59, versions, sizeof(versions)); + } + + return 0; + } + + #define ATA_SCSI_PDATA_SET(idx, val) do { \ + if ((idx) < pccb->datalen) pccb->pdata[(idx)] = (u8)(val); \ + } while (0) + + static int sata_dwc_scsiop_read_cap(ccb *pccb) + { + struct ata_device *ata_dev = &ata_device; + u32 last_lba; + last_lba = ata_dev->n_sectors; /* LBA of the last block */ + + if (pccb->cmd[0] == SCSI_RD_CAPAC) { + if (last_lba >= 0xffffffffULL){ + last_lba = 0xffffffff; + } + + /* sector count, 32-bit */ + ATA_SCSI_PDATA_SET(0, last_lba >> (8 * 3)); + ATA_SCSI_PDATA_SET(1, last_lba >> (8 * 2)); + ATA_SCSI_PDATA_SET(2, last_lba >> (8 * 1)); + ATA_SCSI_PDATA_SET(3, last_lba); + + /* buffer clear */ + ATA_SCSI_PDATA_SET(4, 0); + ATA_SCSI_PDATA_SET(5, 0); + + /* sector size */ + ATA_SCSI_PDATA_SET(6, ATA_SECT_SIZE >> 8); + ATA_SCSI_PDATA_SET(7, ATA_SECT_SIZE & 0xff); + + } else { + /* sector count, 64-bit */ + ATA_SCSI_PDATA_SET(0, last_lba >> (8 * 7)); + ATA_SCSI_PDATA_SET(1, last_lba >> (8 * 6)); + ATA_SCSI_PDATA_SET(2, last_lba >> (8 * 5)); + ATA_SCSI_PDATA_SET(3, last_lba >> (8 * 4)); + ATA_SCSI_PDATA_SET(4, last_lba >> (8 * 3)); + ATA_SCSI_PDATA_SET(5, last_lba >> (8 * 2)); + ATA_SCSI_PDATA_SET(6, last_lba >> (8 * 1)); + ATA_SCSI_PDATA_SET(7, last_lba); + + /* sector size */ + ATA_SCSI_PDATA_SET(10, ATA_SECT_SIZE >> 8); + ATA_SCSI_PDATA_SET(11, ATA_SECT_SIZE & 0xff); + } + + return 0; + } + + /* + * SCSI TEST UNIT READY command operation. + * No operation. Simply returns success to caller, to indicate + * that the caller should successfully complete this SCSI command. + */ + static int sata_dwc_scsiop_test_unit_ready(ccb *pccb) + { + /* No operation */ + return 0; + } + + int scsi_exec(ccb *pccb) + { + int ret; + + /* check device status */ + if(dev_state != SATA_READY){ + return FALSE; + } + + switch (pccb->cmd[0]) { + case SCSI_READ10: + ret = ata_dev_read_sectors(pccb); + break; + case SCSI_RD_CAPAC: + ret = sata_dwc_scsiop_read_cap(pccb); + break; + case SCSI_TST_U_RDY: + ret = sata_dwc_scsiop_test_unit_ready(pccb); + break; + case SCSI_INQUIRY: + ret = sata_dwc_scsiop_inq(pccb); + break; + default: + printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]); + return FALSE; + } + + if (ret) { + debug("SCSI command 0x%02x ret errno %d\n", pccb->cmd[0], ret); + return FALSE; + } + return TRUE; + } + + static const struct ata_port_info sata_dwc_port_info[] = { + { + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING | + ATA_FLAG_SRST | ATA_FLAG_NCQ, + .pio_mask = 0x1f, /* pio 0-4 */ + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + }, + }; + + int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, + unsigned int flags, u16 *id) + { + struct ata_port *ap = pap; + unsigned int class = *p_class; + struct ata_taskfile tf; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1, tried_spinup = 0; + u8 status; + int rc; + + /* cheack BSY = 0 */ + status = ata_busy_wait(ap, ATA_BUSY, 30000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + rc = FALSE; + return rc; + } + + ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */ + + retry: + memset(&tf, 0, sizeof(tf)); + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + tf.ctl = ap->ctl; /* 0x08 */ + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_ID_ATA; + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + + /* Device presence detection is unreliable on some + * controllers. Always poll IDENTIFY if available. + */ + tf.flags |= ATA_TFLAG_POLLING; + + temp_n_block = 1; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, + sizeof(id[0]) * ATA_ID_WORDS, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + #ifdef __BIG_ENDIAN + unsigned int id_cnt; + + for (id_cnt = 0; id_cnt < ATA_ID_WORDS; id_cnt++) + id[id_cnt] = le16_to_cpu(id[id_cnt]); + + #endif /* __BIG_ENDIAN */ + + /* sanity check */ + rc = -EINVAL; + reason = "device reports invalid type"; + + if (class == ATA_DEV_ATA) { + if (!ata_id_is_ata(id) && !ata_id_is_cfa(id)){ + goto err_out; + } + } else { + if (ata_id_is_ata(id)){ + goto err_out; + } + } + if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) { + tried_spinup = 1; + /* + * Drive powered-up in standby mode, and requires a specific + * SET_FEATURES spin-up subcommand before it will accept + * anything other than the original IDENTIFY command. + */ + err_mask = ata_dev_set_feature(dev, SETFEATURES_SPINUP, 0); + if (err_mask && id[2] != 0x738c) { + rc = -EIO; + reason = "SPINUP failed"; + goto err_out; + } + /* + * If the drive initially returned incomplete IDENTIFY info, + * we now must reissue the IDENTIFY command. + */ + if (id[2] == 0x37c8) + goto retry; + } + + if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) { + /* + * The exact sequence expected by certain pre-ATA4 drives is: + * SRST RESET + * IDENTIFY (optional in early ATA) + * INITIALIZE DEVICE PARAMETERS (later IDE and ATA) + * anything else.. + * Some drives were very specific about that exact sequence. + * + * Note that ATA4 says lba is mandatory so the second check + * shoud never trigger. + */ + if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { + err_mask = ata_dev_init_params(dev, id[3], id[6]); + if (err_mask) { + rc = -EIO; + reason = "INIT_DEV_PARAMS failed"; + goto err_out; + } + + /* current CHS translation info (id[53-58]) might be + * changed. reread the identify device info. + */ + flags &= ~ATA_READID_POSTRESET; + goto retry; + } + } + + *p_class = class; + return 0; + + err_out: + return rc; + } + + void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep) + { + if (wait){ + ata_wait_idle(ap); + } + + ata_std_dev_select(ap, device); + + if (wait) { + ata_wait_idle(ap); + } + } + + void ata_std_dev_select(struct ata_port *ap, unsigned int device) + { + u8 tmp; + + if (device == 0) { + tmp = ATA_DEVICE_OBS; + } else { + tmp = ATA_DEVICE_OBS | ATA_DEV1; + } + + writeb(tmp, ap->ioaddr.device_addr); + + /* needed; also flushes, for mmio */ + readb(ap->ioaddr.altstatus_addr); + + /* need delay 400nsec over */ + udelay(1); + } + + void ata_qc_reinit(struct ata_queued_cmd *qc) + { + qc->dma_dir = DMA_NONE; + qc->flags = 0; + qc->nbytes = qc->extrabytes = qc->curbytes = 0; + qc->n_elem = 0; + qc->err_mask = 0; + qc->sect_size = ATA_SECT_SIZE; + qc->nbytes = ATA_SECT_SIZE * temp_n_block; + + memset(&qc->tf, 0, sizeof(qc->tf)); + qc->tf.ctl = 0; + qc->tf.device = ATA_DEVICE_OBS; + + /* init result_tf such that it indicates normal completion */ + qc->result_tf.command = ATA_DRDY; + qc->result_tf.feature = 0; + } + + unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, unsigned int buflen, + unsigned long timeout) + { + struct ata_link *link = dev->link; + struct ata_port *ap = pap; + struct ata_queued_cmd *qc; + unsigned int tag, preempted_tag; + u32 preempted_sactive, preempted_qc_active; + int preempted_nr_active_links; + unsigned int err_mask; + int rc = 0; + u8 status; + + /* cheack BSY = 0 */ + status = ata_busy_wait(ap, ATA_BUSY, 300000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + rc = FALSE; + return rc; + } + + /* no internal command while frozen */ + if (ap->pflags & ATA_PFLAG_FROZEN) { + return AC_ERR_SYSTEM; + } + + tag = ATA_TAG_INTERNAL; + + if (test_and_set_bit(tag, &ap->qc_allocated)){ + printf("test_and_set_bit failed\n"); + } + + qc = __ata_qc_from_tag(ap, tag); + qc->tag = tag; + qc->ap = ap; + qc->dev = dev; + + ata_qc_reinit(qc); + + preempted_tag = link->active_tag; + preempted_sactive = link->sactive; + preempted_qc_active = ap->qc_active; + preempted_nr_active_links = ap->nr_active_links; + link->active_tag = ATA_TAG_POISON; + link->sactive = 0; + ap->qc_active = 0; + ap->nr_active_links = 0; + + /* prepare & issue qc */ + qc->tf = *tf; + if (cdb) + memcpy(qc->cdb, cdb, ATAPI_CDB_LEN); + qc->flags |= ATA_QCFLAG_RESULT_TF; + qc->dma_dir = dma_dir; + qc->private_data = 0; + + ata_qc_issue(qc); + + if (!timeout){ + timeout = ata_probe_timeout * 1000 / HZ; + } + + /* cheack BSY = 0 */ + status = ata_busy_wait(ap, ATA_BUSY, 30000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + printf("altstatus = 0x%x.\n",status); + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + if(waiting_for_reg_state(ap->ioaddr.altstatus_addr,1000,0x8)){ + printf("DRQ = 1 check timeout 1000msec\n"); + u8 status = 0; + u8 errorStatus = 0; + + status = readb( ap->ioaddr.altstatus_addr); + if ((status&0x01) != 0) { + errorStatus = readb( ap->ioaddr.feature_addr); + printf("ERROR STATUS = 0x%x\n",errorStatus); + } + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + status = ata_busy_wait(ap, ATA_BUSY, 10); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + ata_pio_task(ap); + + if (!rc) { + if (qc->flags & ATA_QCFLAG_ACTIVE) { + qc->err_mask |= AC_ERR_TIMEOUT; + ata_port_freeze(ap); + } + } + + /* perform minimal error analysis */ + if (qc->flags & ATA_QCFLAG_FAILED) { + if (qc->result_tf.command & (ATA_ERR | ATA_DF)){ + qc->err_mask |= AC_ERR_DEV; + } + + if (!qc->err_mask){ + qc->err_mask |= AC_ERR_OTHER; + } + + if (qc->err_mask & ~AC_ERR_OTHER){ + qc->err_mask &= ~AC_ERR_OTHER; + } + } + + /* finish up */ + *tf = qc->result_tf; + err_mask = qc->err_mask; + ata_qc_free(qc); + link->active_tag = preempted_tag; + link->sactive = preempted_sactive; + ap->qc_active = preempted_qc_active; + ap->nr_active_links = preempted_nr_active_links; + + if (ap->flags & ATA_FLAG_DISABLED) { + err_mask |= AC_ERR_SYSTEM; + ap->flags &= ~ATA_FLAG_DISABLED; + } + + return err_mask; + } + + unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable, u8 feature) + { + struct ata_taskfile tf; + struct ata_port *ap; + ap = pap; + unsigned int err_mask; + + /* set up set-features taskfile */ + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_SET_FEATURES; + tf.feature = enable; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = feature; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); + + return err_mask; + } + + unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors) + { + struct ata_taskfile tf; + struct ata_port *ap; + ap = pap; + unsigned int err_mask; + + /* Number of sectors per track 1-255. Number of heads 1-16 */ + if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) + return AC_ERR_INVALID; + + /* set up init dev params taskfile */ + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_INIT_DEV_PARAMS; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = sectors; + tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */ + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); + + if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED)) + err_mask = 0; + + return err_mask; + } + + struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, unsigned int tag) + { + if (tag < ATA_MAX_QUEUE) + return &ap->qcmd[tag]; + return NULL; + } + + void ata_qc_issue(struct ata_queued_cmd *qc) + { + struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; + u8 prot = qc->tf.protocol; + + if (ata_is_ncq(prot)) { + if (!link->sactive) + ap->nr_active_links++; + link->sactive |= 1 << qc->tag; + } else { + ap->nr_active_links++; + link->active_tag = qc->tag; + } + + qc->flags |= ATA_QCFLAG_ACTIVE; + ap->qc_active |= 1 << qc->tag; + + if (qc->dev->flags & ATA_DFLAG_SLEEPING) { + msleep(1); /* delay 1msec */ + return; + } + + qc->err_mask |= sata_dwc_qc_issue(qc); + if (qc->err_mask) + goto err; + + return; + err: + ata_qc_complete(qc); + } + + unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc) + { + ata_qc_issue_prot(qc); + return 0; + } + + void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) + { + /* set command register */ + writeb(tf->command, ap->ioaddr.command_addr); + + /* read alternative status register */ + readb(ap->ioaddr.altstatus_addr); + + /* delay 400nsec over */ + udelay(1); + } + + void __ata_port_freeze(struct ata_port *ap) + { + printf("set port freeze.\n"); + ap->pflags |= ATA_PFLAG_FROZEN; + } + + int ata_port_freeze(struct ata_port *ap) + { + __ata_port_freeze(ap); + return 0; + } + + unsigned int ata_tag_internal(unsigned int tag) + { + return tag == ATA_MAX_QUEUE - 1; + } + + void ata_qc_complete(struct ata_queued_cmd *qc) + { + struct ata_device *dev = qc->dev; + if (qc->err_mask) + qc->flags |= ATA_QCFLAG_FAILED; + + if (qc->flags & ATA_QCFLAG_FAILED) { + if (!ata_tag_internal(qc->tag)) { + /* always fill result TF for failed qc */ + fill_result_tf(qc); + return; + } + } + /* read result TF if requested */ + if (qc->flags & ATA_QCFLAG_RESULT_TF) + fill_result_tf(qc); + + /* Some commands need post-processing after successful + * completion. + */ + switch (qc->tf.command) { + case ATA_CMD_SET_FEATURES: + if (qc->tf.feature != SETFEATURES_WC_ON && + qc->tf.feature != SETFEATURES_WC_OFF) + break; + case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */ + case ATA_CMD_SET_MULTI: /* multi_count changed */ + break; + + case ATA_CMD_SLEEP: + dev->flags |= ATA_DFLAG_SLEEPING; + break; + } + + __ata_qc_complete(qc); + } + + void __ata_qc_complete(struct ata_queued_cmd *qc) + { + struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; + + /* command should be marked inactive atomically with qc completion */ + link->active_tag = ATA_TAG_POISON; + ap->nr_active_links--; + + /* clear exclusive status */ + if (qc->flags & ATA_QCFLAG_CLEAR_EXCL && ap->excl_link == link) + ap->excl_link = NULL; + + qc->flags &= ~ATA_QCFLAG_ACTIVE; + ap->qc_active &= ~(1 << qc->tag); + } + + void fill_result_tf(struct ata_queued_cmd *qc) + { + struct ata_port *ap = qc->ap; + + qc->result_tf.flags = qc->tf.flags; + ata_tf_read(ap, &qc->result_tf); + } + + void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) + { + struct ata_ioports *ioaddr = &ap->ioaddr; + + tf->command = ata_check_status(ap); + tf->feature = readb(ioaddr->error_addr); + tf->nsect = readb(ioaddr->nsect_addr); + tf->lbal = readb(ioaddr->lbal_addr); + tf->lbam = readb(ioaddr->lbam_addr); + tf->lbah = readb(ioaddr->lbah_addr); + tf->device = readb(ioaddr->device_addr); + + if (tf->flags & ATA_TFLAG_LBA48) { + if (ioaddr->ctl_addr) { + writeb(tf->ctl | ATA_HOB, ioaddr->ctl_addr); + + tf->hob_feature = readb(ioaddr->error_addr); + tf->hob_nsect = readb(ioaddr->nsect_addr); + tf->hob_lbal = readb(ioaddr->lbal_addr); + tf->hob_lbam = readb(ioaddr->lbam_addr); + tf->hob_lbah = readb(ioaddr->lbah_addr); + + writeb(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + } else { + printf("sata_dwc warnning register read.\n"); + } + } + } + + void ata_qc_free(struct ata_queued_cmd *qc) + { + struct ata_port *ap = qc->ap; + unsigned int tag; + qc->flags = 0; + tag = qc->tag; + if (tag < ATA_MAX_QUEUE){ + qc->tag = ATA_TAG_POISON; + clear_bit(tag, &ap->qc_allocated); + } + } + + void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) + { + struct ata_ioports *ioaddr = &ap->ioaddr; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + if (tf->ctl != ap->last_ctl) { + if (ioaddr->ctl_addr){ + writeb(tf->ctl, ioaddr->ctl_addr); + } + ap->last_ctl = tf->ctl; + ata_wait_idle(ap); + } + + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + writeb(tf->hob_feature, ioaddr->feature_addr); + writeb(tf->hob_nsect, ioaddr->nsect_addr); + writeb(tf->hob_lbal, ioaddr->lbal_addr); + writeb(tf->hob_lbam, ioaddr->lbam_addr); + writeb(tf->hob_lbah, ioaddr->lbah_addr); + } + + if (is_addr) { + writeb(tf->feature, ioaddr->feature_addr); + writeb(tf->nsect, ioaddr->nsect_addr); + writeb(tf->lbal, ioaddr->lbal_addr); + writeb(tf->lbam, ioaddr->lbam_addr); + writeb(tf->lbah, ioaddr->lbah_addr); + } + + if (tf->flags & ATA_TFLAG_DEVICE) { + writeb(tf->device, ioaddr->device_addr); + } + + ata_wait_idle(ap); + } + + void sata_dwc_exec_command_by_tag(struct ata_port *ap, + struct ata_taskfile *tf, + u8 tag, u32 cmd_issued) + { + struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); + hsdevp->cmd_issued[tag] = cmd_issued; + + /* Clear SError before executing a new command.*/ + clear_serror(); + ata_exec_command(ap, tf); + } + + void clear_serror(void) + { + u32 temp; + temp = in_le32((void __iomem *)scr_addr_sstatus + 4); + + out_le32((void __iomem *)scr_addr_sstatus + 4, temp); + } + + void ata_tf_to_host(struct ata_port *ap, const struct ata_taskfile *tf) + { + ata_tf_load(ap, tf); + ata_exec_command(ap, tf); + } + + unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) + { + struct ata_port *ap = qc->ap; + + if (ap->flags & ATA_FLAG_PIO_POLLING) { + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + case ATA_PROT_NODATA: + case ATAPI_PROT_PIO: + case ATAPI_PROT_NODATA: + qc->tf.flags |= ATA_TFLAG_POLLING; + break; + default: + break; + } + } + + /* select the device */ + ata_dev_select(ap, qc->dev->devno, 1, 0); + + /* start the command */ + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + if (qc->tf.flags & ATA_TFLAG_POLLING){ + qc->tf.ctl |= ATA_NIEN; + } + + ata_tf_to_host(ap, &qc->tf); + + /* PIO data in protocol */ + ap->hsm_task_state = HSM_ST; + + if (qc->tf.flags & ATA_TFLAG_POLLING){ + ata_pio_queue_task(ap, qc, 0); + } + + break; + + default: + return AC_ERR_SYSTEM; + } + + return 0; + } + + void ata_pio_task(struct ata_port *arg_ap) + { + struct ata_port *ap = arg_ap; + struct ata_queued_cmd *qc = ap->port_task_data; + u8 status; + int poll_next; + + fsm_start: + /* + * This is purely heuristic. This is a fast path. + * Sometimes when we enter, BSY will be cleared in + * 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, queue delayed work. + */ + 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) { + ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE); + return; + } + } + + /* move the HSM */ + poll_next = ata_hsm_move(ap, qc, status, 1); + + /* another command or interrupt handler + * may be running at this point. + */ + if (poll_next) + goto fsm_start; + } + + void ata_pio_queue_task(struct ata_port *ap, void *data,unsigned long delay) + { + ap->port_task_data = data; + } + + unsigned int ac_err_mask(u8 status) + { + if (status & (ATA_BUSY | ATA_DRQ)) + return AC_ERR_HSM; + if (status & (ATA_ERR | ATA_DF)) + return AC_ERR_DEV; + return 0; + } + + unsigned int __ac_err_mask(u8 status) + { + unsigned int mask = ac_err_mask(status); + if (mask == 0) + return AC_ERR_OTHER; + return mask; + } + + int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq) + { + int poll_next; + + fsm_start: + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + poll_next = (qc->tf.flags & ATA_TFLAG_POLLING); + + /* check device status */ + if ((status & ATA_DRQ) == 0) { + /* handle BSY=0, DRQ=0 as error */ + if (status & (ATA_ERR | ATA_DF)) { + /* device stops HSM for abort/error */ + qc->err_mask |= AC_ERR_DEV; + } else { + /* HSM violation. Let EH handle this */ + qc->err_mask |= AC_ERR_HSM; + } + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + /* Device should not ask for data transfer (DRQ=1) + * when it finds something wrong. + * We ignore DRQ here and stop the HSM by + * changing hsm_task_state to HSM_ST_ERR and + * let the EH abort the command or reset the device. + */ + if (status & (ATA_ERR | ATA_DF)) { + if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) { + printf("DRQ=1 with device error, " + "dev_stat 0x%X\n", status); + qc->err_mask |= AC_ERR_HSM; + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + } + + if (qc->tf.protocol == ATA_PROT_PIO) { + /* PIO data out protocol. + * send first data block. + */ + /* ata_pio_sectors() might change the state + * to HSM_ST_LAST. so, the state is changed here + * before ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST; + ata_pio_sectors(qc); + } else { + printf("protocol is not ATA_PROT_PIO \n"); + } + break; + + case HSM_ST: + /* complete command or read/write the data register */ + /* ATA PIO protocol */ + if ((status & ATA_DRQ) == 0) { + /* handle BSY=0, DRQ=0 as error */ + if (status & (ATA_ERR | ATA_DF)){ + /* device stops HSM for abort/error */ + qc->err_mask |= AC_ERR_DEV; + } else { + /* HSM violation. Let EH handle this. + * Phantom devices also trigger this + * condition. Mark hint. + */ + qc->err_mask |= AC_ERR_HSM | AC_ERR_NODEV_HINT; + } + + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + /* For PIO reads, some devices may ask for + * data transfer (DRQ=1) alone with ERR=1. + * We respect DRQ here and transfer one + * block of junk data before changing the + * hsm_task_state to HSM_ST_ERR. + * + * For PIO writes, ERR=1 DRQ=1 doesn't make + * sense since the data block has been + * transferred to the device. + */ + if (status & (ATA_ERR | ATA_DF)) { + /* data might be corrputed */ + qc->err_mask |= AC_ERR_DEV; + + if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { + ata_pio_sectors(qc); + status = ata_wait_idle(ap); + } + + if (status & (ATA_BUSY | ATA_DRQ)){ + qc->err_mask |= AC_ERR_HSM; + } + + /* ata_pio_sectors() might change the + * state to HSM_ST_LAST. so, the state + * is changed after ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + ata_pio_sectors(qc); + if (ap->hsm_task_state == HSM_ST_LAST && + (!(qc->tf.flags & ATA_TFLAG_WRITE))) { + /* all data read */ + status = ata_wait_idle(ap); + goto fsm_start; + } + + poll_next = 1; + break; + + case HSM_ST_LAST: + if (!ata_ok(status)) { + qc->err_mask |= __ac_err_mask(status); + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + /* no more data to transfer */ + ap->hsm_task_state = HSM_ST_IDLE; + + /* complete taskfile transaction */ + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + + case HSM_ST_ERR: + /* make sure qc->err_mask is available to + * know what's wrong and recover + */ + ap->hsm_task_state = HSM_ST_IDLE; + + /* complete taskfile transaction */ + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + default: + poll_next = 0; + } + + return poll_next; + } + + int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *qc) + { + if (qc->tf.flags & ATA_TFLAG_POLLING) + return 1; + + if (ap->hsm_task_state == HSM_ST_FIRST) { + if (ata_is_atapi(qc->tf.protocol) && + !(qc->dev->flags & ATA_DFLAG_CDB_INTR)) + return 1; + } + + return 0; + } + + void ata_pio_sectors(struct ata_queued_cmd *qc) + { + struct ata_port *ap; + ap = pap; + qc->pdata = ap->pdata; + + if (is_multi_taskfile(&qc->tf)) { + /* READ/WRITE MULTIPLE */ + unsigned int nsect; + + nsect = min((qc->nbytes - qc->curbytes) / qc->sect_size, + qc->dev->multi_count); + while (nsect--) + ata_pio_sector(qc); + } else { + ata_pio_sector(qc); + } + + readb(qc->ap->ioaddr.altstatus_addr); + udelay(1); + } + + void ata_pio_sector(struct ata_queued_cmd *qc) + { + struct ata_port *ap = qc->ap; + unsigned int offset; + unsigned char *buf; + + if (qc->curbytes == qc->nbytes - qc->sect_size){ + ap->hsm_task_state = HSM_ST_LAST; + } + + offset = qc->curbytes; + + /* check cmd and set buffer */ + switch (qc->tf.command) { + case ATA_CMD_ID_ATA: /* IDENTIFY */ + buf = &ata_device.id[0]; + break; + case ATA_CMD_PIO_READ_EXT: /* READ SECTORS EX 0x24 */ + case ATA_CMD_PIO_READ: /* READ SECTORS 0x20 */ + buf = qc->pdata + offset; + break; + default: + buf = &temp_data_buf[0]; + } + + /* data xfer */ + ata_mmio_data_xfer(qc->dev, buf, qc->sect_size); + + qc->curbytes += qc->sect_size; + + } + + void ata_mmio_data_xfer(struct ata_device *dev, unsigned char *buf, + unsigned int buflen) + { + struct ata_port *ap = pap; + void __iomem *data_addr = ap->ioaddr.data_addr; + unsigned int words = buflen >> 1; + u16 *buf16 = (u16 *)buf; + unsigned int i = 0; + + udelay(100); + /* Transfer */ + for(i=0; i < words; i++) + buf16[i] = cpu_to_le16(readw(data_addr)); + + /* Transfer trailing 1 byte, if any. */ + if (buflen & 0x01) { + __le16 align_buf[1] = { 0 }; + unsigned char *trailing_buf = buf + buflen - 1; + + align_buf[0] = cpu_to_le16(readw(data_addr)); + memcpy(trailing_buf, align_buf, 1); + words++; + } + } + + void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) + { + struct ata_port *ap = qc->ap; + + if (in_wq) { + /* EH might have kicked in while host lock is + * released. + */ + qc = &ap->qcmd[qc->tag]; + if (qc) { + if (!(qc->err_mask & AC_ERR_HSM)) { + ata_irq_on(ap); + ata_qc_complete(qc); + } else { + ata_port_freeze(ap); + } + } + } else { + if (!(qc->err_mask & AC_ERR_HSM)) { + ata_qc_complete(qc); + } else { + ata_port_freeze(ap); + } + } + } + + u8 ata_irq_on(struct ata_port *ap) + { + struct ata_ioports *ioaddr = &ap->ioaddr; + u8 tmp; + + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; + + if (ioaddr->ctl_addr) + writeb(ap->ctl, ioaddr->ctl_addr); + + tmp = ata_wait_idle(ap); + + return tmp; + } + + void sata_dwc_probe(void) + { + struct sata_dwc_device hsdev; + struct ata_host host; + struct ata_port_info pi = sata_dwc_port_info[0]; + struct ata_device *ata_dev = &ata_device; + struct ata_link *link; + struct sata_dwc_device_port hsdevp = dwc_devp; + u8 *base = 0; + u8 *sata_dma_regs_addr = 0; + u32 idr, versionr; + u8 status; + unsigned long base_addr = 0; + int chan = 0; + int rc; + int i; + const u16 *id; + unsigned long xfer_mask; + char revbuf[7]; /* XYZ-99\0 */ + unsigned long pio_mask, mwdma_mask, udma_mask; + + phost = &host; /* set grobal */ + + /* Base address */ + base = (u8*)SATA_BASE_ADDR; + + /* SATA register init */ + hsdev.sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET); + + host.n_ports = SATA_DWC_MAX_PORTS; + + for(i = 0; i < SATA_DWC_MAX_PORTS; i++){ + ap.pflags |= ATA_PFLAG_INITIALIZING; + ap.flags = ATA_FLAG_DISABLED; + ap.print_id = -1; + ap.ctl = ATA_DEVCTL_OBS; + ap.host = &host; + ap.last_ctl = 0xFF; + ap.dev = &ata_device; + + link = &ap.link; + link->ap = ≈ + link->pmp = 0; + link->active_tag = ATA_TAG_POISON; + link->hw_sata_spd_limit = 0; + + ap.port_no = i; + host.ports[i] = ≈ + } + + ap.pio_mask = pi.pio_mask; + ap.mwdma_mask = pi.mwdma_mask; + ap.udma_mask = pi.udma_mask; + ap.flags |= pi.flags; + ap.link.flags |= pi.link_flags; + + /* Host port init */ + host.ports[0]->ioaddr.cmd_addr = base; + host.ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET; + scr_addr_sstatus = base + SATA_DWC_SCR_OFFSET; + + /* sata_dwc setup port */ + base_addr = (unsigned long)base; + + host.ports[0]->ioaddr.cmd_addr = (void *)base_addr + 0x00; + host.ports[0]->ioaddr.data_addr = (void *)base_addr + 0x00; + + host.ports[0]->ioaddr.error_addr = (void *)base_addr + 0x04; + host.ports[0]->ioaddr.feature_addr = (void *)base_addr + 0x04; + + host.ports[0]->ioaddr.nsect_addr = (void *)base_addr + 0x08; + + host.ports[0]->ioaddr.lbal_addr = (void *)base_addr + 0x0c; + host.ports[0]->ioaddr.lbam_addr = (void *)base_addr + 0x10; + host.ports[0]->ioaddr.lbah_addr = (void *)base_addr + 0x14; + + host.ports[0]->ioaddr.device_addr = (void *)base_addr + 0x18; + host.ports[0]->ioaddr.command_addr = (void *)base_addr + 0x1c; + host.ports[0]->ioaddr.status_addr = (void *)base_addr + 0x1c; + + host.ports[0]->ioaddr.altstatus_addr = (void *)base_addr + 0x20; + host.ports[0]->ioaddr.ctl_addr = (void *)base_addr + 0x20; + + /* Get Host ID / Version */ + idr = in_le32(&hsdev.sata_dwc_regs->idr); + versionr = in_le32(&hsdev.sata_dwc_regs->versionr); + + /* DMA register init */ + sata_dma_regs_addr = (u8*)SATA_DMA_REG_ADDR; + sata_dma_regs = (void *__iomem)sata_dma_regs_addr; + + /* DMA channel Interrupt is disable. DMA Enable setup is next. */ + for(chan = 0; chan < DMA_NUM_CHANS; chan++){ + /* DMA Interrupt register(error) mask. */ + out_le32(&(sata_dma_regs->interrupt_mask.error.low), + DMA_DISABLE_CHAN(chan)); + + /* DMA Interrupt register(transfer) mask. */ + out_le32(&(sata_dma_regs->interrupt_mask.tfr.low), + DMA_DISABLE_CHAN(chan)); + } + + /* DMA Enable by DMAC Configuration Register */ + out_le32(&(sata_dma_regs->dma_cfg.low), DMA_EN); + + /* Enable selective interrupts by setting the interrupt mask register */ + out_le32(&hsdev.sata_dwc_regs->intmr, + SATA_DWC_INTMR_ERRM | + SATA_DWC_INTMR_NEWFPM | + SATA_DWC_INTMR_PMABRTM | + SATA_DWC_INTMR_DMATM); + + /* Unmask the error bits that should trigger an error interrupt by + * setting the error mask register. + */ + out_le32(&hsdev.sata_dwc_regs->errmr,SATA_DWC_SERROR_ERR_BITS); + + hsdev.host = ap.host; + memset(&hsdevp, 0, sizeof(hsdevp)); + hsdevp.hsdev = &hsdev; + + for (i = 0; i < SATA_DWC_QCMD_MAX; i++) + hsdevp.cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT; + + if (ap.port_no == 0) { + out_le32(&hsdev.sata_dwc_regs->dmacr,SATA_DWC_DMACR_TXRXCH_CLEAR); + + out_le32(&hsdev.sata_dwc_regs->dbtsr, + (SATA_DWC_DBTSR_MWR(AHB_DMA_BRST_DFLT) | + SATA_DWC_DBTSR_MRD(AHB_DMA_BRST_DFLT))); + } + + /* Clear any error bits before libata starts issuing commands */ + out_le32((void __iomem *)scr_addr_sstatus + 4, + in_le32((void __iomem *)scr_addr_sstatus + 4)); + + /* check altstatus register (find device) */ + status = ata_check_altstatus(&ap); + + if(status == 0x7f){ + printf("Hard Disk not found.\n"); + dev_state = SATA_NODEVICE; + return; + } + + /* waiting for device ready. time out 30sec */ + printf("waitng for device ready."); + i = 0; + while(1){ + udelay (10000); /* 10 ms */ + + /* read altstatus */ + status = ata_check_altstatus(&ap); + + /* status is not busy => break */ + if((status & ATA_BUSY) == 0){ + printf("\n"); + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + + /* bussy set devise state flag */ + dev_state = SATA_NODEVICE; + return; + } + if ((i >= 100) && ((i%100)==0)) { + printf("."); + } + } + + /* softreset */ + rc = sata_dwc_softreset(&ap); + + if(rc){ + printf("sata_dwc : error. soft reset failed\n"); + } + + /* waiting for device ready. time out 30sec */ + printf("waitng for device ready."); + i = 0; + while(1){ + udelay (10000); /* 10 ms */ + + /* read altstatus */ + status = ata_check_altstatus(&ap); + + /* status is not busy => break */ + if((status & ATA_BUSY) == 0){ + printf("\n"); + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + + /* bussy set devise state flag */ + dev_state = SATA_NODEVICE; + return; + } + if ((i >= 100) && ((i%100)==0)) { + printf("."); + } + } + + udelay (1000); /* before IDENTIFY command safety delay 1 ms */ + + /* IDENTIFY command send */ + rc = ata_dev_read_id(ata_dev, &ata_dev->class, + ATA_READID_POSTRESET,ata_dev->id); + + if(rc){ + printf("sata_dwc : error. IDENTIFY Command failed\n"); + } + + /* SATA drives indicate we have a bridge. We don't know which + * end of the link the bridge is which is a problem + */ + if (ata_id_is_sata(ata_dev->id)) + ap.cbl = ATA_CBL_SATA; + + id = ata_dev->id; + + /* initialize to be configured parameters */ + ata_dev->flags &= ~ATA_DFLAG_CFG_MASK; + ata_dev->max_sectors = 0; + ata_dev->cdb_len = 0; + ata_dev->n_sectors = 0; + ata_dev->cylinders = 0; + ata_dev->heads = 0; + ata_dev->sectors = 0; + + /* Usual case. Word 53 indicates word 64 is valid */ + if (id[ATA_ID_FIELD_VALID] & (1 << 1)) { + pio_mask = id[ATA_ID_PIO_MODES] & 0x03; + pio_mask <<= 3; + pio_mask |= 0x7; + } else { + /* If word 64 isn't valid then Word 51 high byte holds + * the PIO timing number for the maximum. Turn it into + * a mask. + */ + u8 mode = (id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF; + if (mode < 5){ /* Valid PIO range */ + pio_mask = (2 << mode) - 1; + } else { + pio_mask = 1; + } + } + + mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07; + + if (ata_id_is_cfa(id)) { + /* + * Process compact flash extended modes + */ + int pio = id[163] & 0x7; + int dma = (id[163] >> 3) & 7; + + if (pio) + pio_mask |= (1 << 5); + if (pio > 1) + pio_mask |= (1 << 6); + if (dma) + mwdma_mask |= (1 << 3); + if (dma > 1) + mwdma_mask |= (1 << 4); + } + + udma_mask = 0; + if (id[ATA_ID_FIELD_VALID] & (1 << 2)) + udma_mask = id[ATA_ID_UDMA_MODES] & 0xff; + + xfer_mask = (pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO | + (mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA | + (udma_mask << ATA_SHIFT_UDMA) & ATA_MASK_UDMA; + + /* ATA-specific feature tests */ + if (ata_dev->class == ATA_DEV_ATA) { + if (ata_id_is_cfa(id)) { + if (id[162] & 1) /* CPRM may make this media unusable */ + printf("supports DRM functions and may " + "not be fully accessable.\n"); + sprintf(revbuf, "%s", "CFA"); + } else { + /* Warn the user if the device has TPM extensions */ + if (ata_id_has_tpm(id)) + printf("supports DRM functions and may " + "not be fully accessable.\n"); + } + + /* set n_secters */ + ata_dev->n_sectors = ata_id_n_sectors((u16*)id); + + if (ata_dev->id[59] & 0x100) + ata_dev->multi_count = ata_dev->id[59] & 0xff; + + if (ata_id_has_lba(id)) { + const char *lba_desc; + char ncq_desc[20]; + + lba_desc = "LBA"; + ata_dev->flags |= ATA_DFLAG_LBA; + if (ata_id_has_lba48(id)) { + ata_dev->flags |= ATA_DFLAG_LBA48; + lba_desc = "LBA48"; + + if (ata_dev->n_sectors >= (1UL << 28) && + ata_id_has_flush_ext(id)) + ata_dev->flags |= ATA_DFLAG_FLUSH_EXT; + } + /* config NCQ */ + if (!ata_id_has_ncq(ata_dev->id)) { + ncq_desc[0] = '\0'; + } + + if (ata_dev->horkage & ATA_HORKAGE_NONCQ) { + sprintf(ncq_desc, "%s", "NCQ (not used)"); + } + + if (ap.flags & ATA_FLAG_NCQ) { + ata_dev->flags |= ATA_DFLAG_NCQ; + } + } + ata_dev->cdb_len = 16; + } + /* determine max_sectors */ + ata_dev->max_sectors = ATA_MAX_SECTORS; + if (ata_dev->flags & ATA_DFLAG_LBA48) + ata_dev->max_sectors = ATA_MAX_SECTORS_LBA48; + + if (!(ata_dev->horkage & ATA_HORKAGE_IPM)) { + if (ata_id_has_hipm(ata_dev->id)) + ata_dev->flags |= ATA_DFLAG_HIPM; + if (ata_id_has_dipm(ata_dev->id)) + ata_dev->flags |= ATA_DFLAG_DIPM; + } + + if ((ap.cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ata_dev->id))) { + ata_dev->udma_mask &= ATA_UDMA5; + ata_dev->max_sectors = ATA_MAX_SECTORS; + } + + if (ata_dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { + printf("Drive reports diagnostics failure." + "This may indicate a drive\n"); + printf("fault or invalid emulation." + "Contact drive vendor for information.\n"); + } + + /* Hard Disk status check : test send READ Command */ + rc = check_sata_dev_state(); + } + + int sata_dwc_softreset(struct ata_port *ap) + { + u8 nsect,lbal = 0; + u8 tmp = 0; + u32 serror = 0; + u8 status = 0; + struct ata_ioports *ioaddr = &ap->ioaddr; + + /* read SCR ERROR */ + serror = in_le32((void *)ap->ioaddr.scr_addr + (SCR_ERROR * 4)); + + /* device check */ + writeb(0x55, ioaddr->nsect_addr); + writeb(0xaa, ioaddr->lbal_addr); + writeb(0xaa, ioaddr->nsect_addr); + writeb(0x55, ioaddr->lbal_addr); + writeb(0x55, ioaddr->nsect_addr); + writeb(0xaa, ioaddr->lbal_addr); + + nsect = readb(ioaddr->nsect_addr); + lbal = readb(ioaddr->lbal_addr); + + if ((nsect == 0x55) && (lbal == 0xaa)){ + /* we found a device */ + printf("we found a device\n"); + } else { + /* nothing found */ + printf("Not found a device.\n"); + dev_state = SATA_NODEVICE; + return FALSE; + } + + tmp = ATA_DEVICE_OBS; + writeb(tmp,ioaddr->device_addr); + writeb(ap->ctl,ioaddr->ctl_addr); + + udelay(200); + + /* set softreset */ + writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr); + + udelay(200); + writeb(ap->ctl,ioaddr->ctl_addr); + + /* wait a while before cheking status */ + msleep(150); + status = ata_check_status(ap); + + msleep(50); + ata_check_status(ap); + + while (1) { + u8 status = ata_check_status(ap); + + if (!(status & ATA_BUSY)){ + break; + } + + status = in_le32((void *)ap->ioaddr.scr_addr + (SCR_STATUS * 4)); + if(status == 0xff || (status & 0xf) != 0x3){ + } + + printf("Hard Disk status is BUSY.\n"); + msleep(50); + } + + tmp = ATA_DEVICE_OBS; + writeb(tmp,ioaddr->device_addr); + + nsect = readb(ioaddr->nsect_addr); + lbal = readb(ioaddr->lbal_addr); + + return 0; + } + + void scsi_bus_reset() + { + struct ata_port *ap = pap; + + /* check device state */ + if(dev_state != SATA_READY){ + printf("no devices available\n"); + return; + } + + /*soft reset process*/ + sata_dwc_softreset(ap); + } + + void scsi_print_error(ccb * pccb) + { + /*The ahci error info can be read in the ahci driver*/ + } + + int ata_dev_read_sectors(ccb *pccb) + { + struct ata_port *ap = pap; + struct ata_device *dev = &ata_device; + struct ata_taskfile tf; + unsigned int class = ATA_DEV_ATA; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1; + int rc; + + u32 block=0; + u32 n_block=0; + + ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */ + + retry: + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; /*ap->ctl = 0x08 */ + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + + /* set pdata */ + ap->pdata = pccb->pdata; + + tf.device = ATA_DEVICE_OBS; + + block |= ((u32)pccb->cmd[2]) << 24; + block |= ((u32)pccb->cmd[3]) << 16; + block |= ((u32)pccb->cmd[4]) << 8; + block |= ((u32)pccb->cmd[5]); + + n_block |= ((u32)pccb->cmd[7]) << 8; + n_block |= ((u32)pccb->cmd[8]); + + /* trying temp to n_block */ + temp_n_block = n_block; + + + #ifdef CONFIG_LBA48 + tf.command = ATA_CMD_PIO_READ_EXT; /* READ SECTOR(S) EXT 0x24 */ + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; + + tf.hob_feature = 31; + tf.feature = 31; + tf.hob_nsect = (n_block >> 8) & 0xff; + tf.nsect = n_block & 0xff; + + tf.hob_lbah = 0x0; + tf.hob_lbam = 0x0; + tf.hob_lbal = (block >> 24) & 0xff; + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; + #else /* LBA24 */ + tf.command = ATA_CMD_PIO_READ; /* READ SECTOR(S) 0x20 */ + tf.flags |= ATA_TFLAG_LBA ; + + tf.feature = 31; + tf.nsect = n_block & 0xff; + + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = (block >> 24) & 0xf; + + tf.device |= 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; + + #endif /* CONFIG_LBA48 */ + + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.flags |= ATA_TFLAG_POLLING; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,0, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("READ_SECTORS NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + /* sanity check */ + rc = -EINVAL; + reason = "device reports invalid type"; + + return 0; + + err_out: + printf("failed to READ SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); + return rc; + } diff -crN u-boot-2009.03/drivers/block/sata_dwc.h u-boot-2009.03-sata/drivers/block/sata_dwc.h *** u-boot-2009.03/drivers/block/sata_dwc.h 1970-01-01 09:00:00.000000000 +0900 --- u-boot-2009.03-sata/drivers/block/sata_dwc.h 2009-03-23 19:22:31.000000000 +0900 *************** *** 0 **** --- 1,495 ---- + /* + * sata_dwc.h + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld mmiesfeld@amcc.com + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese sr@denx.de + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + + #ifndef _SATA_DWC_H_ + #define _SATA_DWC_H_ + + #define HZ 100 + + #define READ 0 + #define WRITE 1 + + static int ata_id_has_hipm(const u16 *id) + { + u16 val = id[76]; + + if (val == 0 || val == 0xffff) + return -1; + + return val & (1 << 9); + } + + static int ata_id_has_dipm(const u16 *id) + { + u16 val = id[78]; + + if (val == 0 || val == 0xffff) + return -1; + + return val & (1 << 3); + } + + enum { + ATA_READID_POSTRESET = (1 << 0), /* reading ID after reset */ + + ATA_DNXFER_PIO = 0, /* speed down PIO */ + ATA_DNXFER_DMA = 1, /* speed down DMA */ + ATA_DNXFER_40C = 2, /* apply 40c cable limit */ + ATA_DNXFER_FORCE_PIO = 3, /* force PIO */ + ATA_DNXFER_FORCE_PIO0 = 4, /* force PIO0 */ + + ATA_DNXFER_QUIET = (1 << 31), + }; + + enum hsm_task_states { + HSM_ST_IDLE, /* no command on going */ + HSM_ST_FIRST, /* (waiting the device to) + * write CDB or first data block */ + HSM_ST, /* (waiting the device to) transfer data */ + HSM_ST_LAST, /* (waiting the device to) complete command */ + HSM_ST_ERR, /* error */ + }; + + #define ATA_SHORT_PAUSE ((HZ >> 6) + 1) + + typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc); + + struct ata_queued_cmd { + struct ata_port *ap; + struct ata_device *dev; + + struct ata_taskfile tf; + u8 cdb[ATAPI_CDB_LEN]; + + unsigned long flags; /* ATA_QCFLAG_xxx */ + unsigned int tag; + unsigned int n_elem; + + int dma_dir; + + unsigned int sect_size; + + unsigned int nbytes; + unsigned int extrabytes; + unsigned int curbytes; + + unsigned int err_mask; + struct ata_taskfile result_tf; + + void *private_data; + void *lldd_task; + unsigned char *pdata; + }; + + /* defines only for the constants which don't work cell as enums*/ + #define ATA_TAG_POISON 0xfafbfcfdU + + enum { + /* various global constants */ + LIBATA_MAX_PRD = ATA_MAX_PRD / 2, + LIBATA_DUMB_MAX_PRD = ATA_MAX_PRD / 4, /* Worst case */ + ATA_MAX_PORTS = 8, + ATA_DEF_QUEUE = 1, + /* tag ATA_MAX_QUEUE - 1 is reserved for internal commands */ + ATA_MAX_QUEUE = 32, + ATA_TAG_INTERNAL = ATA_MAX_QUEUE - 1, + ATA_MAX_BUS = 2, + ATA_DEF_BUSY_WAIT = 10000, + + ATAPI_MAX_DRAIN = 16 << 10, + + ATA_SHT_EMULATED = 1, + ATA_SHT_CMD_PER_LUN = 1, + ATA_SHT_THIS_ID = -1, + ATA_SHT_USE_CLUSTERING = 1, + + /* struct ata_device stuff */ + ATA_DFLAG_LBA = (1 << 0), /* device supports LBA */ + ATA_DFLAG_LBA48 = (1 << 1), /* device supports LBA48 */ + ATA_DFLAG_CDB_INTR = (1 << 2), /* device asserts INTRQ */ + ATA_DFLAG_NCQ = (1 << 3), /* device supports NCQ */ + ATA_DFLAG_FLUSH_EXT = (1 << 4), /* do FLUSH_EXT instead of FLUSH */ + ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */ + ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */ + ATA_DFLAG_AN = (1 << 7), /* AN configured */ + ATA_DFLAG_HIPM = (1 << 8), /* device supports HIPM */ + ATA_DFLAG_DIPM = (1 << 9), /* device supports DIPM */ + ATA_DFLAG_DMADIR = (1 << 10), /* device requires DMADIR */ + ATA_DFLAG_CFG_MASK = (1 << 12) - 1, + + ATA_DFLAG_PIO = (1 << 12), /* device limited to PIO mode */ + ATA_DFLAG_NCQ_OFF = (1 << 13), /* device limited to non-NCQ mode */ + ATA_DFLAG_SPUNDOWN = (1 << 14), /* XXX: for spindown_compat */ + ATA_DFLAG_SLEEPING = (1 << 15), /* device is sleeping */ + ATA_DFLAG_DUBIOUS_XFER = (1 << 16), /* data transfer not verified */ + ATA_DFLAG_INIT_MASK = (1 << 24) - 1, + + ATA_DFLAG_DETACH = (1 << 24), + ATA_DFLAG_DETACHED = (1 << 25), + + /* struct ata_link flags */ + ATA_LFLAG_HRST_TO_RESUME = (1 << 0), /* hardreset to resume link */ + ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), /* can't wait for the first D2H + * Register FIS clearing BSY */ + ATA_LFLAG_NO_SRST = (1 << 2), /* avoid softreset */ + ATA_LFLAG_ASSUME_ATA = (1 << 3), /* assume ATA class */ + ATA_LFLAG_ASSUME_SEMB = (1 << 4), /* assume SEMB class */ + ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, + ATA_LFLAG_NO_RETRY = (1 << 5), /* don't retry this link */ + ATA_LFLAG_DISABLED = (1 << 6), /* link is disabled */ + + /* struct ata_port flags */ + ATA_FLAG_SLAVE_POSS = (1 << 0), + ATA_FLAG_SATA = (1 << 1), + ATA_FLAG_NO_LEGACY = (1 << 2), /* no legacy mode check */ + ATA_FLAG_MMIO = (1 << 3), /* use MMIO, not PIO */ + ATA_FLAG_SRST = (1 << 4), /* (obsolete) use ATA SRST, not E.D.D. */ + ATA_FLAG_SATA_RESET = (1 << 5), /* (obsolete) use COMRESET */ + ATA_FLAG_NO_ATAPI = (1 << 6), /* No ATAPI support */ + ATA_FLAG_PIO_DMA = (1 << 7), /* PIO cmds via DMA */ + ATA_FLAG_PIO_LBA48 = (1 << 8), /* Host DMA engine is LBA28 only */ + ATA_FLAG_PIO_POLLING = (1 << 9), /* use polling PIO if LLD + * doesn't handle PIO interrupts */ + ATA_FLAG_NCQ = (1 << 10), /* host supports NCQ */ + ATA_FLAG_DEBUGMSG = (1 << 13), + ATA_FLAG_IGN_SIMPLEX = (1 << 15), /* ignore SIMPLEX */ + ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */ + ATA_FLAG_ACPI_SATA = (1 << 17), /* need native SATA ACPI layout */ + ATA_FLAG_AN = (1 << 18), /* controller supports AN */ + ATA_FLAG_PMP = (1 << 19), /* controller supports PMP */ + ATA_FLAG_IPM = (1 << 20), /* driver can handle IPM */ + + ATA_FLAG_DISABLED = (1 << 23), /* port is disabled, ignore it */ + + /* struct ata_port pflags */ + ATA_PFLAG_EH_PENDING = (1 << 0), /* EH pending */ + ATA_PFLAG_EH_IN_PROGRESS = (1 << 1), /* EH in progress */ + ATA_PFLAG_FROZEN = (1 << 2), /* port is frozen */ + ATA_PFLAG_RECOVERED = (1 << 3), /* recovery action performed */ + ATA_PFLAG_LOADING = (1 << 4), /* boot/loading probe */ + ATA_PFLAG_UNLOADING = (1 << 5), /* module is unloading */ + ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), /* SCSI hotplug scheduled */ + ATA_PFLAG_INITIALIZING = (1 << 7), /* being initialized, don't touch */ + ATA_PFLAG_RESETTING = (1 << 8), /* reset in progress */ + ATA_PFLAG_SUSPENDED = (1 << 17), /* port is suspended (power) */ + ATA_PFLAG_PM_PENDING = (1 << 18), /* PM operation pending */ + + /* struct ata_queued_cmd flags */ + ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */ + ATA_QCFLAG_DMAMAP = (1 << 1), /* SG table is DMA mapped */ + ATA_QCFLAG_IO = (1 << 3), /* standard IO command */ + ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */ + ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */ + ATA_QCFLAG_QUIET = (1 << 6), /* don't report device error */ + + ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */ + ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */ + ATA_QCFLAG_EH_SCHEDULED = (1 << 18), /* EH scheduled (obsolete) */ + + /* host set flags */ + ATA_HOST_SIMPLEX = (1 << 0), + ATA_HOST_STARTED = (1 << 1), /* Host started */ + + /* various lengths of time */ + ATA_TMOUT_BOOT = 30 * 100, /* heuristic */ + ATA_TMOUT_BOOT_QUICK = 7 * 100, /* heuristic */ + ATA_TMOUT_INTERNAL = 30 * 100, + ATA_TMOUT_INTERNAL_QUICK = 5 * 100, + + /* FIXME: GoVault needs 2s but we can't afford that without + * parallel probing. 800ms is enough for iVDR disk + * HHD424020F7SV00. Increase to 2secs when parallel probing + * is in place. + */ + ATA_TMOUT_FF_WAIT = 4 * 100 / 5, + + /* ATA bus states */ + BUS_UNKNOWN = 0, + BUS_DMA = 1, + BUS_IDLE = 2, + BUS_NOINTR = 3, + BUS_NODATA = 4, + BUS_TIMER = 5, + BUS_PIO = 6, + BUS_EDD = 7, + BUS_IDENTIFY = 8, + BUS_PACKET = 9, + + /* SATA port states */ + PORT_UNKNOWN = 0, + PORT_ENABLED = 1, + PORT_DISABLED = 2, + + /* encoding various smaller bitmaps into a single + * unsigned long bitmap + */ + ATA_NR_PIO_MODES = 7, + ATA_NR_MWDMA_MODES = 5, + ATA_NR_UDMA_MODES = 8, + + ATA_SHIFT_PIO = 0, + ATA_SHIFT_MWDMA = ATA_SHIFT_PIO + ATA_NR_PIO_MODES, + ATA_SHIFT_UDMA = ATA_SHIFT_MWDMA + ATA_NR_MWDMA_MODES, + + /* size of buffer to pad xfers ending on unaligned boundaries */ + ATA_DMA_PAD_SZ = 4, + + /* ering size */ + ATA_ERING_SIZE = 32, + + ATA_DEFER_LINK = 1, + ATA_DEFER_PORT = 2, + + /* desc_len for ata_eh_info and context */ + ATA_EH_DESC_LEN = 80, + + /* reset / recovery action types */ + ATA_EH_REVALIDATE = (1 << 0), + ATA_EH_SOFTRESET = (1 << 1), + ATA_EH_HARDRESET = (1 << 2), + ATA_EH_ENABLE_LINK = (1 << 3), + ATA_EH_LPM = (1 << 4), /* link power management action */ + + ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, + ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, + + /* ata_eh_info->flags */ + ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ + ATA_EHI_RESUME_LINK = (1 << 1), /* resume link (reset modifier) */ + ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */ + ATA_EHI_QUIET = (1 << 3), /* be quiet */ + + ATA_EHI_DID_SOFTRESET = (1 << 16), /* already soft-reset this port */ + ATA_EHI_DID_HARDRESET = (1 << 17), /* already soft-reset this port */ + ATA_EHI_PRINTINFO = (1 << 18), /* print configuration info */ + ATA_EHI_SETMODE = (1 << 19), /* configure transfer mode */ + ATA_EHI_POST_SETMODE = (1 << 20), /* revaildating after setmode */ + + ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET, + ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, + + /* max tries if error condition is still set after ->error_handler */ + ATA_EH_MAX_TRIES = 5, + + /* how hard are we gonna try to probe/recover devices */ + ATA_PROBE_MAX_TRIES = 3, + ATA_EH_DEV_TRIES = 3, + ATA_EH_PMP_TRIES = 5, + ATA_EH_PMP_LINK_TRIES = 3, + + SATA_PMP_SCR_TIMEOUT = 250, + + /* Horkage types. May be set by libata or controller on drives + (some horkage may be drive/controller pair dependant */ + + ATA_HORKAGE_DIAGNOSTIC = (1 << 0), /* Failed boot diag */ + ATA_HORKAGE_NODMA = (1 << 1), /* DMA problems */ + ATA_HORKAGE_NONCQ = (1 << 2), /* Don't use NCQ */ + ATA_HORKAGE_MAX_SEC_128 = (1 << 3), /* Limit max sects to 128 */ + ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */ + ATA_HORKAGE_SKIP_PM = (1 << 5), /* Skip PM operations */ + ATA_HORKAGE_HPA_SIZE = (1 << 6), /* native size off by one */ + ATA_HORKAGE_IPM = (1 << 7), /* Link PM problems */ + ATA_HORKAGE_IVB = (1 << 8), /* cbl det validity bit bugs */ + ATA_HORKAGE_STUCK_ERR = (1 << 9), /* stuck ERR on next PACKET */ + + /* DMA mask for user DMA control: User visible values; DO NOT renumber */ + ATA_DMA_MASK_ATA = (1 << 0), /* DMA on ATA Disk */ + ATA_DMA_MASK_ATAPI = (1 << 1), /* DMA on ATAPI */ + ATA_DMA_MASK_CFA = (1 << 2), /* DMA on CF Card */ + + /* ATAPI command types */ + ATAPI_READ = 0, /* READs */ + ATAPI_WRITE = 1, /* WRITEs */ + ATAPI_READ_CD = 2, /* READ CD [MSF] */ + ATAPI_PASS_THRU = 3, /* SAT pass-thru */ + ATAPI_MISC = 4, /* the rest */ + }; + + enum ata_completion_errors { + AC_ERR_DEV = (1 << 0), /* device reported error */ + AC_ERR_HSM = (1 << 1), /* host state machine violation */ + AC_ERR_TIMEOUT = (1 << 2), /* timeout */ + AC_ERR_MEDIA = (1 << 3), /* media error */ + AC_ERR_ATA_BUS = (1 << 4), /* ATA bus error */ + AC_ERR_HOST_BUS = (1 << 5), /* host bus error */ + AC_ERR_SYSTEM = (1 << 6), /* system error */ + AC_ERR_INVALID = (1 << 7), /* invalid argument */ + AC_ERR_OTHER = (1 << 8), /* unknown */ + AC_ERR_NODEV_HINT = (1 << 9), /* polling device detection hint */ + AC_ERR_NCQ = (1 << 10), /* marker for offending NCQ qc */ + }; + + enum ata_xfer_mask { + ATA_MASK_PIO = ((1LU << ATA_NR_PIO_MODES) - 1) << ATA_SHIFT_PIO, + ATA_MASK_MWDMA = ((1LU << ATA_NR_MWDMA_MODES) - 1) << ATA_SHIFT_MWDMA, + ATA_MASK_UDMA = ((1LU << ATA_NR_UDMA_MODES) - 1) << ATA_SHIFT_UDMA, + }; + + struct ata_port_info { + struct scsi_host_template *sht; + unsigned long flags; + unsigned long link_flags; + unsigned long pio_mask; + unsigned long mwdma_mask; + unsigned long udma_mask; + const struct ata_port_operations *port_ops; + void *private_data; + }; + + struct ata_ioports { + void __iomem *cmd_addr; + void __iomem *data_addr; + void __iomem *error_addr; + void __iomem *feature_addr; + void __iomem *nsect_addr; + void __iomem *lbal_addr; + void __iomem *lbam_addr; + void __iomem *lbah_addr; + void __iomem *device_addr; + void __iomem *status_addr; + void __iomem *command_addr; + void __iomem *altstatus_addr; + void __iomem *ctl_addr; + void __iomem *bmdma_addr; + void __iomem *scr_addr; + }; + + struct ata_host { + void __iomem * const *iomap; + unsigned int n_ports; + void *private_data; + const struct ata_port_operations *ops; + unsigned long flags; + struct ata_port *simplex_claimed; /* channel owning the DMA */ + struct ata_port *ports[0]; + }; + + struct ata_port_stats { + unsigned long unhandled_irq; + unsigned long idle_irq; + unsigned long rw_reqbuf; + }; + + struct ata_device { + struct ata_link *link; + unsigned int devno; /* 0 or 1 */ + unsigned long flags; /* ATA_DFLAG_xxx */ + unsigned int horkage; /* List of broken features */ + struct scsi_device *sdev; /* attached SCSI device */ + #ifdef CONFIG_ATA_ACPI + acpi_handle acpi_handle; + union acpi_object *gtf_cache; + #endif + /* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */ + u64 n_sectors; /* size of device, if ATA */ + unsigned int class; /* ATA_DEV_xxx */ + + union { + u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ + u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */ + }; + + u8 pio_mode; + u8 dma_mode; + u8 xfer_mode; + unsigned int xfer_shift; /* ATA_SHIFT_xxx */ + + unsigned int multi_count; /* sectors count for + *READ/WRITE MULTIPLE */ + unsigned int max_sectors; /* per-device max sectors */ + unsigned int cdb_len; + + /* per-dev xfer mask */ + unsigned long pio_mask; + unsigned long mwdma_mask; + unsigned long udma_mask; + + /* for CHS addressing */ + u16 cylinders; /* Number of cylinders */ + u16 heads; /* Number of heads */ + u16 sectors; /* Number of sectors per track */ + + /* error history */ + int spdn_cnt; + }; + + enum dma_data_direction { + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, + DMA_NONE = 3, + }; + + struct ata_link { + struct ata_port *ap; + int pmp; /* port multiplier port # */ + unsigned int active_tag; /* active tag on this link */ + u32 sactive; /* active NCQ commands */ + + unsigned int flags; /* ATA_LFLAG_xxx */ + + unsigned int hw_sata_spd_limit; + unsigned int sata_spd_limit; + unsigned int sata_spd; /* current SATA PHY speed */ + + struct ata_device device[2]; + }; + + struct ata_port { + unsigned long flags; /* ATA_FLAG_xxx */ + unsigned int pflags; /* ATA_PFLAG_xxx */ + unsigned int print_id; /* user visible unique port ID */ + unsigned int port_no; /* 0 based port no. inside the host */ + + struct ata_ioports ioaddr; /* ATA cmd/ctl/dma register blocks */ + + u8 ctl; /* cache of ATA control register */ + u8 last_ctl; /* Cache last written value */ + unsigned int pio_mask; + unsigned int mwdma_mask; + unsigned int udma_mask; + unsigned int cbl; /* cable type; ATA_CBL_xxx */ + + struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; + unsigned long qc_allocated; + unsigned int qc_active; + int nr_active_links; /* #links with active qcs */ + + struct ata_link link; /* host default link */ + + int nr_pmp_links; /* nr of available PMP links */ + struct ata_link *pmp_link; /* array of PMP links */ + struct ata_link *excl_link; /* for PMP qc exclusion */ + + struct ata_port_stats stats; + struct ata_host *host; + + struct device *dev; + void *port_task_data; + + unsigned int hsm_task_state; + + u32 msg_enable; + void *private_data; + unsigned char *pdata; + }; + #endif /* _SATA_DWC_H_ */ diff -crN u-boot-2009.03/include/configs/canyonlands.h u-boot-2009.03-sata/include/configs/canyonlands.h *** u-boot-2009.03/include/configs/canyonlands.h 2009-03-22 06:04:41.000000000 +0900 --- u-boot-2009.03-sata/include/configs/canyonlands.h 2009-03-24 13:04:12.000000000 +0900 *************** *** 34,39 **** --- 34,40 ---- #ifdef CONFIG_CANYONLANDS #define CONFIG_460EX 1 /* Specific PPC460EX */ #define CONFIG_HOSTNAME canyonlands + #define CONFIG_SATA_DWC /* PPC460EX SATA support */ #else #define CONFIG_460GT 1 /* Specific PPC460GT */ #ifdef CONFIG_GLACIER *************** *** 454,459 **** --- 455,463 ---- #define CONFIG_CMD_SDRAM #define CONFIG_CMD_SNTP #define CONFIG_CMD_USB + #if defined(CONFIG_SATA_DWC) + #define CONFIG_CMD_SCSI + #endif #elif defined(CONFIG_GLACIER) #define CONFIG_CMD_DATE #define CONFIG_CMD_DTT *************** *** 517,522 **** --- 521,537 ---- #endif /* CONFIG_460GT */
/*----------------------------------------------------------------------- + * S-ATA driver setup + *----------------------------------------------------------------------*/ + #ifdef CONFIG_SATA_DWC + #define CONFIG_LIBATA + #define CONFIG_SYS_SCSI_MAX_SCSI_ID 1 /* SCSI ID */ + #define CONFIG_SYS_SCSI_MAX_LUN 1 /* SCSI LUN */ + #define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * CONFIG_SYS_SCSI_MAX_LUN) + #define CONFIG_SYS_SCSI_MAXDEVICE CONFIG_SYS_SCSI_MAX_DEVICE + #endif + + /*----------------------------------------------------------------------- * External Bus Controller (EBC) Setup *----------------------------------------------------------------------*/
Regards, Kazuaki Ichinohe.

On Tuesday 24 March 2009, Kazuaki Ichinohe wrote:
This patch adds a SATA harddisk driver for the canyonlands.
Thanks.
But your patch is linewrapped and therefor hard to read and can't be applied. And the commit message could be a little more descriptive. And please don't forget to add you Signed-off-by line next time.
As a general comment I suggest that you take a look at:
http://www.denx.de/wiki/view/U-Boot/Patches
to see how patches should be posted to the list. Best would be to use the git tools (git format-patch and git send-email) for patch submission.
I'll make a review in more depth when you send a patch that's not linewrapped.
Thanks again.
Best regards, Stefan
===================================================================== DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de =====================================================================

Hi Stefan,
Thank you for the reply. This is the patch that corrects the point.
Signed-off-by: Kazuaki Ichinohe <kazuichi at fsi.co.jp> ---
[patch] diff -purN u-boot-2009.03/common/cmd_scsi.c u-boot-2009.03-sata/common/cmd_scsi.c --- u-boot-2009.03/common/cmd_scsi.c 2009-03-22 06:04:41.000000000 +0900 +++ u-boot-2009.03-sata/common/cmd_scsi.c 2009-03-25 18:53:29.000000000 +0900 @@ -47,8 +47,10 @@ #define SCSI_DEV_ID 0x5288
#else +#ifndef CONFIG_SATA_DWC #error no scsi device defined #endif +#endif
static ccb tempccb; /* temporary scsi command buffer */ @@ -179,6 +181,7 @@ void scsi_init(void) { int busdevfunc;
+#ifndef CONFIG_SATA_DWC busdevfunc=pci_find_device(SCSI_VEND_ID,SCSI_DEV_ID,0); /* get PCI Device ID */ if(busdevfunc==-1) { printf("Error SCSI Controller (%04X,%04X) not found\n",SCSI_VEND_ID,SCSI_DEV_ID); @@ -189,7 +192,13 @@ void scsi_init(void) printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n",SCSI_VEND_ID,SCSI_DEV_ID,(busdevfunc>>16)&0xFF,(busdevfunc>>11)&0x1F,(busdevfunc>>8)&0x7); } #endif +#endif +#ifdef CONFIG_SATA_DWC + sata_dwc_probe(); +#endif +#ifndef CONFIG_SATA_DWC scsi_low_level_init(busdevfunc); +#endif scsi_scan(1); }
@@ -444,8 +453,11 @@ int do_scsi (cmd_tbl_t *cmdtp, int flag, /**************************************************************************************** * scsi_read */ - +#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) +#define SCSI_MAX_READ_BLK 0xFF +#else #define SCSI_MAX_READ_BLK 0xFFFF /* almost the maximum amount of the scsi_ext command.. */ +#endif
ulong scsi_read(int device, ulong blknr, ulong blkcnt, void *buffer) { diff -purN u-boot-2009.03/drivers/block/Makefile u-boot-2009.03-sata/drivers/block/Makefile --- u-boot-2009.03/drivers/block/Makefile 2009-03-22 06:04:41.000000000 +0900 +++ u-boot-2009.03-sata/drivers/block/Makefile 2009-03-23 19:22:31.000000000 +0900 @@ -34,6 +34,7 @@ COBJS-$(CONFIG_SATA_SIL3114) += sata_sil COBJS-$(CONFIG_IDE_SIL680) += sil680.o COBJS-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o COBJS-$(CONFIG_SYSTEMACE) += systemace.o +COBJS-$(CONFIG_SATA_DWC) += sata_dwc.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff -purN u-boot-2009.03/drivers/block/sata_dwc.c u-boot-2009.03-sata/drivers/block/sata_dwc.c --- u-boot-2009.03/drivers/block/sata_dwc.c 1970-01-01 09:00:00.000000000 +0900 +++ u-boot-2009.03-sata/drivers/block/sata_dwc.c 2009-03-25 18:02:07.000000000 +0900 @@ -0,0 +1,2175 @@ +/* + * sata_dwc.c + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld mmiesfeld@amcc.com + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese sr@denx.de + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * This program is free software; you can redistribute + * it and/or modify it under the terms of the GNU + * General Public License as published by the + * Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + */ + +#include <common.h> +#include <command.h> +#include <pci.h> +#include <asm/processor.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <malloc.h> +#include <scsi.h> +#include <ata.h> +#include <linux/ctype.h> + +/* sata_dwc.h */ +#include "sata_dwc.h" + +/* Base Address */ +#define SATA_BASE_ADDR 0xe20d1000 +#define SATA_DMA_REG_ADDR 0xe20d0800 + +/* SATA DMA driver Globals */ +#define DMA_NUM_CHANS 1 +#define DMA_NUM_CHAN_REGS 8 + +/* SATA DMA Register definitions */ +#define AHB_DMA_BRST_DFLT 16 /* 4 data items burst length */ + +struct dmareg { + u32 low; /* Low bits 0-31 */ + u32 high; /* High bits 32-63 */ +}; + +/* DMA Per Channel registers */ +struct dma_chan_regs { + struct dmareg sar; /* Source Address */ + struct dmareg dar; /* Destination address */ + struct dmareg llp; /* Linked List Pointer */ + struct dmareg ctl; /* Control */ + struct dmareg sstat; /* Source Status not implemented in core */ + struct dmareg dstat; /* Destination Status not implemented in core */ + struct dmareg sstatar; /* Source Status Address not impl in core */ + struct dmareg dstatar; /* Destination Status Address not implemented */ + struct dmareg cfg; /* Config */ + struct dmareg sgr; /* Source Gather */ + struct dmareg dsr; /* Destination Scatter */ +}; + +/* Generic Interrupt Registers */ +struct dma_interrupt_regs { + struct dmareg tfr; /* Transfer Interrupt */ + struct dmareg block; /* Block Interrupt */ + struct dmareg srctran; /* Source Transfer Interrupt */ + struct dmareg dsttran; /* Dest Transfer Interrupt */ + struct dmareg error; /* Error */ +}; + +struct ahb_dma_regs { + struct dma_chan_regs chan_regs[DMA_NUM_CHAN_REGS]; + struct dma_interrupt_regs interrupt_raw; /* Raw Interrupt */ + struct dma_interrupt_regs interrupt_status; /* Interrupt Status */ + struct dma_interrupt_regs interrupt_mask; /* Interrupt Mask */ + struct dma_interrupt_regs interrupt_clear; /* Interrupt Clear */ + struct dmareg statusInt; /* Interrupt combined */ + struct dmareg rq_srcreg; /* Src Trans Req */ + struct dmareg rq_dstreg; /* Dst Trans Req */ + struct dmareg rq_sgl_srcreg; /* Sngl Src Trans Req */ + struct dmareg rq_sgl_dstreg; /* Sngl Dst Trans Req */ + struct dmareg rq_lst_srcreg; /* Last Src Trans Req */ + struct dmareg rq_lst_dstreg; /* Last Dst Trans Req */ + struct dmareg dma_cfg; /* DMA Config */ + struct dmareg dma_chan_en; /* DMA Channel Enable */ + struct dmareg dma_id; /* DMA ID */ + struct dmareg dma_test; /* DMA Test */ + struct dmareg res1; /* reserved */ + struct dmareg res2; /* reserved */ + /* DMA Comp Params + * Param 6 = dma_param[0], Param 5 = dma_param[1], + * Param 4 = dma_param[2] ... + */ + struct dmareg dma_params[6]; +}; + +/* DMA Register Operation Bits */ +#define DMA_EN 0x00000001 /* Enable AHB DMA */ +#define DMA_CHANNEL(ch) (0x00000001 << (ch)) /* Select channel */ +#define DMA_ENABLE_CHAN(ch) ((0x00000001 << (ch)) | \ + ((0x000000001 << (ch)) << 8)) /* Enable channel */ +#define DMA_DISABLE_CHAN(ch) (0x00000000 | \ + ((0x000000001 << (ch)) << 8)) /* Disable channel */ + +#define SATA_DWC_MAX_PORTS 1 +#define SATA_DWC_SCR_OFFSET 0x24 +#define SATA_DWC_REG_OFFSET 0x64 + +/* DWC SATA Registers */ +struct sata_dwc_regs { + u32 fptagr; /* 1st party DMA tag */ + u32 fpbor; /* 1st party DMA buffer offset */ + u32 fptcr; /* 1st party DMA Xfr count */ + u32 dmacr; /* DMA Control */ + u32 dbtsr; /* DMA Burst Transac size */ + u32 intpr; /* Interrupt Pending */ + u32 intmr; /* Interrupt Mask */ + u32 errmr; /* Error Mask */ + u32 llcr; /* Link Layer Control */ + u32 phycr; /* PHY Control */ + u32 physr; /* PHY Status */ + u32 rxbistpd; /* Recvd BIST pattern def register */ + u32 rxbistpd1; /* Recvd BIST data dword1 */ + u32 rxbistpd2; /* Recvd BIST pattern data dword2 */ + u32 txbistpd; /* Trans BIST pattern def register */ + u32 txbistpd1; /* Trans BIST data dword1 */ + u32 txbistpd2; /* Trans BIST data dword2 */ + u32 bistcr; /* BIST Control Register */ + u32 bistfctr; /* BIST FIS Count Register */ + u32 bistsr; /* BIST Status Register */ + u32 bistdecr; /* BIST Dword Error count register */ + u32 res[15]; /* Reserved locations */ + u32 testr; /* Test Register */ + u32 versionr; /* Version Register */ + u32 idr; /* ID Register */ + u32 unimpl[192]; /* Unimplemented */ + u32 dmadr[256]; /* FIFO Locations in DMA Mode */ +}; + +/* DWC SATA Register Operations */ +#define SATA_DWC_TXFIFO_DEPTH 0x01FF +#define SATA_DWC_RXFIFO_DEPTH 0x01FF + +#define SATA_DWC_DBTSR_MWR(size) ((size/4) & SATA_DWC_TXFIFO_DEPTH) +#define SATA_DWC_DBTSR_MRD(size) (((size/4) & \ + SATA_DWC_RXFIFO_DEPTH) << 16) +#define SATA_DWC_INTPR_DMAT 0x00000001 +#define SATA_DWC_INTPR_NEWFP 0x00000002 +#define SATA_DWC_INTPR_PMABRT 0x00000004 +#define SATA_DWC_INTPR_ERR 0x00000008 +#define SATA_DWC_INTPR_NEWBIST 0x00000010 +#define SATA_DWC_INTPR_IPF 0x10000000 +#define SATA_DWC_INTMR_DMATM 0x00000001 +#define SATA_DWC_INTMR_NEWFPM 0x00000002 +#define SATA_DWC_INTMR_PMABRTM 0x00000004 +#define SATA_DWC_INTMR_ERRM 0x00000008 +#define SATA_DWC_INTMR_NEWBISTM 0x00000010 + +#define SATA_DWC_DMACR_TMOD_TXCHEN 0x00000004 +#define SATA_DWC_DMACR_TXRXCH_CLEAR SATA_DWC_DMACR_TMOD_TXCHEN + +#define SATA_DWC_QCMD_MAX 32 + +/* This is all error bits, zero's are reserved fields. */ +#define SATA_DWC_SERROR_ERR_BITS 0x0FFF0F03 + +/* + * Commonly used DWC SATA driver Macros + */ +#define HSDEVP_FROM_AP(ap) (struct sata_dwc_device_port*) \ + (ap)->private_data + +struct sata_dwc_device { + struct device *dev; /* generic device struct */ + struct ata_probe_ent *pe; /* ptr to probe-ent */ + struct ata_host *host; + u8 *reg_base; + struct sata_dwc_regs *sata_dwc_regs; /* DW Synopsys SATA specific */ + int irq_dma; +}; + +struct sata_dwc_device_port { + struct sata_dwc_device *hsdev; + int cmd_issued[SATA_DWC_QCMD_MAX]; + u32 dma_chan[SATA_DWC_QCMD_MAX]; + int dma_pending[SATA_DWC_QCMD_MAX]; +}; + +enum { + SATA_DWC_CMD_ISSUED_NOT = 0, + SATA_DWC_CMD_ISSUED_PEND = 1, + SATA_DWC_CMD_ISSUED_EXEC = 2, + SATA_DWC_CMD_ISSUED_NODATA = 3, + + SATA_DWC_DMA_PENDING_NONE = 0, + SATA_DWC_DMA_PENDING_TX = 1, + SATA_DWC_DMA_PENDING_RX = 2, +}; + +/* delay Macros */ +#define msleep(a) udelay(a * 1000) +#define ssleep(a) msleep(a * 1000) + +static int ata_probe_timeout = (ATA_TMOUT_INTERNAL / 100); + +enum sata_dev_state { + SATA_INIT = 0, + SATA_READY = 1, + SATA_NODEVICE = 2, + SATA_ERROR = 3, +}; +enum sata_dev_state dev_state = SATA_INIT; + +/* + * Globals + */ +static struct ahb_dma_regs *sata_dma_regs = 0; +static struct ata_host *phost; +static struct ata_port ap; +static struct ata_port *pap = ≈ +static struct ata_device ata_device; +static struct sata_dwc_device_port dwc_devp; + +static void *scr_addr_sstatus; +static char temp_data_buf[512]; +static u32 temp_n_block = 0; + +/* + * Prototype + */ +unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, unsigned int buflen, + unsigned long timeout); +unsigned int ata_dev_set_feature(struct ata_device *dev, + u8 enable,u8 feature); +unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors); +void clear_serror(void); +u8 ata_irq_on(struct ata_port *ap); +struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, + unsigned int tag); +int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq); +void ata_tf_to_host(struct ata_port *ap,const struct ata_taskfile *tf); +unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc); +void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf); +unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc); +u8 ata_check_altstatus(struct ata_port *ap); +static u8 ata_check_status(struct ata_port *ap); +void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep); +void ata_qc_issue(struct ata_queued_cmd *qc); +void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf); +int ata_dev_read_sectors(ccb *pccb); +void ata_std_dev_select(struct ata_port *ap, unsigned int device); +void ata_qc_complete(struct ata_queued_cmd *qc); +void __ata_qc_complete(struct ata_queued_cmd *qc); +void fill_result_tf(struct ata_queued_cmd *qc); +void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); +void ata_mmio_data_xfer(struct ata_device *dev, + unsigned char *buf,unsigned int buflen); +void ata_pio_task(struct ata_port *arg_ap); +void __ata_port_freeze(struct ata_port *ap); +int ata_port_freeze(struct ata_port *ap); +void ata_qc_free(struct ata_queued_cmd *qc); +void ata_pio_sectors(struct ata_queued_cmd *qc); +void ata_pio_sector(struct ata_queued_cmd *qc); +void ata_pio_queue_task(struct ata_port *ap, + void *data,unsigned long delay); +void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq); +int sata_dwc_softreset(struct ata_port *ap); +void sata_dwc_probe(void); + +u8 ata_check_altstatus(struct ata_port *ap) +{ + u8 val = 0; + val = readb(ap->ioaddr.altstatus_addr); + return val; +} + +int check_sata_dev_state(void) +{ + static ccb tempccb; /* temporary scsi command buffer */ + ccb *pccb = (ccb *)&tempccb; + int ret = 0; + int i = 0; + + while(1){ + udelay (10000); /* 10 ms */ + + pccb->cmd[0] = SCSI_READ10; + pccb->cmd[1] = 0; + pccb->cmd[2] = 0; + pccb->cmd[3] = 0; + pccb->cmd[4] = 0; + pccb->cmd[5] = 0; + pccb->cmd[6] = 0; + pccb->cmd[7] = 0; + pccb->cmd[8] = 1; + pccb->cmdlen = 10; + pccb->pdata = &temp_data_buf[0]; /* dummy */ + pccb->datalen = 512; + + /* Send Read Command */ + ret = ata_dev_read_sectors(pccb); + + /* result TRUE => break */ + if(ret == 0){ + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)){ + printf("** TimeOUT **\n"); + dev_state = SATA_NODEVICE; /* set device status flag */ + return FALSE; + } + + if ((i >= 100) && ((i%100)==0)) { + printf("."); + } + } + + /* Set device status flag */ + dev_state = SATA_READY; + + return TRUE; +} + +void ata_id_string(const u16 *id, unsigned char *s, + unsigned int ofs, unsigned int len) +{ + unsigned int c; + + while (len > 0) { + c = id[ofs] >> 8; + *s = c; + s++; + + c = id[ofs] & 0xff; + *s = c; + s++; + + ofs++; + len -= 2; + } +} + +static int waiting_for_reg_state(volatile u8 *offset, + int timeout_msec, + u32 sign) +{ + int i; + u32 status; + + for (i = 0; i < timeout_msec; i++){ + status = readl(offset); + if ( ( status & sign ) != 0 ){ + break; + } + msleep(1); + } + + return (i < timeout_msec) ? 0 : -1; +} + +static inline u32 qcmd_tag_to_mask(u8 tag) +{ + return (0x00000001 << (tag & 0x1f)); +} + +static u8 ata_check_status(struct ata_port *ap) +{ + u8 val = 0; + val = readb(ap->ioaddr.status_addr); + return val; +} + +static u8 ata_busy_wait(struct ata_port *ap, + unsigned int bits,unsigned int max) +{ + u8 status; + + do { + udelay(10); + status = ata_check_status(ap); + max--; + } while (status != 0xff && (status & bits) && (max > 0)); + + return status; +} + +static u8 ata_wait_idle(struct ata_port *ap) +{ + u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + return status; +} + +static int sata_dwc_scsiop_inq(ccb *pccb) +{ + struct ata_device *ata_dev = &ata_device; + u16 *id; + + /* Set IDENTIFY Data */ + id = ata_dev->id; + + /* make INQUIRY header */ + u8 hdr[] = { + 0, + 0, + 0x5, /* claim SPC-3 version compatibility */ + 2, + 95 - 4 + }; + + /* set scsi removeable (RMB) bit per ata bit */ + if (ata_id_removeable(id)){ + hdr[1] |= (1 << 7); + } + + memcpy(pccb->pdata, hdr, sizeof(hdr)); + + if (pccb->datalen > 35) { + memcpy(&pccb->pdata[8], "ATA ", 8); + ata_id_string(id, &pccb->pdata[16], ATA_ID_PROD, 16); + ata_id_string(id, &pccb->pdata[32], ATA_ID_FW_REV, 4); + if (pccb->pdata[32] == 0 || pccb->pdata[32] == ' '){ + memcpy(&pccb->pdata[32], "n/a ", 4); + } + } + + if (pccb->datalen > 63) { + const u8 versions[] = { + 0x60, /* SAM-3 (no version claimed) */ + 0x03, + 0x20, /* SBC-2 (no version claimed) */ + 0x02, + 0x60 /* SPC-3 (no version claimed) */ + }; + memcpy(pccb->pdata + 59, versions, sizeof(versions)); + } + + return 0; +} + +#define ATA_SCSI_PDATA_SET(idx, val) do { \ + if ((idx) < pccb->datalen) pccb->pdata[(idx)] = (u8)(val); \ + } while (0) + +static int sata_dwc_scsiop_read_cap(ccb *pccb) +{ + struct ata_device *ata_dev = &ata_device; + u32 last_lba; + last_lba = ata_dev->n_sectors; /* LBA of the last block */ + + if (pccb->cmd[0] == SCSI_RD_CAPAC) { + if (last_lba >= 0xffffffffULL){ + last_lba = 0xffffffff; + } + + /* sector count, 32-bit */ + ATA_SCSI_PDATA_SET(0, last_lba >> (8 * 3)); + ATA_SCSI_PDATA_SET(1, last_lba >> (8 * 2)); + ATA_SCSI_PDATA_SET(2, last_lba >> (8 * 1)); + ATA_SCSI_PDATA_SET(3, last_lba); + + /* buffer clear */ + ATA_SCSI_PDATA_SET(4, 0); + ATA_SCSI_PDATA_SET(5, 0); + + /* sector size */ + ATA_SCSI_PDATA_SET(6, ATA_SECT_SIZE >> 8); + ATA_SCSI_PDATA_SET(7, ATA_SECT_SIZE & 0xff); + + } else { + /* sector count, 64-bit */ + ATA_SCSI_PDATA_SET(0, last_lba >> (8 * 7)); + ATA_SCSI_PDATA_SET(1, last_lba >> (8 * 6)); + ATA_SCSI_PDATA_SET(2, last_lba >> (8 * 5)); + ATA_SCSI_PDATA_SET(3, last_lba >> (8 * 4)); + ATA_SCSI_PDATA_SET(4, last_lba >> (8 * 3)); + ATA_SCSI_PDATA_SET(5, last_lba >> (8 * 2)); + ATA_SCSI_PDATA_SET(6, last_lba >> (8 * 1)); + ATA_SCSI_PDATA_SET(7, last_lba); + + /* sector size */ + ATA_SCSI_PDATA_SET(10, ATA_SECT_SIZE >> 8); + ATA_SCSI_PDATA_SET(11, ATA_SECT_SIZE & 0xff); + } + + return 0; +} + +/* + * SCSI TEST UNIT READY command operation. + * No operation. Simply returns success to caller, to indicate + * that the caller should successfully complete this SCSI command. + */ +static int sata_dwc_scsiop_test_unit_ready(ccb *pccb) +{ + /* No operation */ + return 0; +} + +int scsi_exec(ccb *pccb) +{ + int ret; + + /* check device status */ + if(dev_state != SATA_READY){ + return FALSE; + } + + switch (pccb->cmd[0]) { + case SCSI_READ10: + ret = ata_dev_read_sectors(pccb); + break; + case SCSI_RD_CAPAC: + ret = sata_dwc_scsiop_read_cap(pccb); + break; + case SCSI_TST_U_RDY: + ret = sata_dwc_scsiop_test_unit_ready(pccb); + break; + case SCSI_INQUIRY: + ret = sata_dwc_scsiop_inq(pccb); + break; + default: + printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]); + return FALSE; + } + + if (ret) { + debug("SCSI command 0x%02x ret errno %d\n", pccb->cmd[0], ret); + return FALSE; + } + return TRUE; +} + +static const struct ata_port_info sata_dwc_port_info[] = { + { + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING | + ATA_FLAG_SRST | ATA_FLAG_NCQ, + .pio_mask = 0x1f, /* pio 0-4 */ + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + }, +}; + +int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, + unsigned int flags, u16 *id) +{ + struct ata_port *ap = pap; + unsigned int class = *p_class; + struct ata_taskfile tf; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1, tried_spinup = 0; + u8 status; + int rc; + + /* cheack BSY = 0 */ + status = ata_busy_wait(ap, ATA_BUSY, 30000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + rc = FALSE; + return rc; + } + + ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */ + +retry: + memset(&tf, 0, sizeof(tf)); + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + tf.ctl = ap->ctl; /* 0x08 */ + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_ID_ATA; + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + + /* Device presence detection is unreliable on some + * controllers. Always poll IDENTIFY if available. + */ + tf.flags |= ATA_TFLAG_POLLING; + + temp_n_block = 1; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, + sizeof(id[0]) * ATA_ID_WORDS, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + +#ifdef __BIG_ENDIAN + unsigned int id_cnt; + + for (id_cnt = 0; id_cnt < ATA_ID_WORDS; id_cnt++) + id[id_cnt] = le16_to_cpu(id[id_cnt]); + +#endif /* __BIG_ENDIAN */ + + /* sanity check */ + rc = -EINVAL; + reason = "device reports invalid type"; + + if (class == ATA_DEV_ATA) { + if (!ata_id_is_ata(id) && !ata_id_is_cfa(id)){ + goto err_out; + } + } else { + if (ata_id_is_ata(id)){ + goto err_out; + } + } + if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) { + tried_spinup = 1; + /* + * Drive powered-up in standby mode, and requires a specific + * SET_FEATURES spin-up subcommand before it will accept + * anything other than the original IDENTIFY command. + */ + err_mask = ata_dev_set_feature(dev, SETFEATURES_SPINUP, 0); + if (err_mask && id[2] != 0x738c) { + rc = -EIO; + reason = "SPINUP failed"; + goto err_out; + } + /* + * If the drive initially returned incomplete IDENTIFY info, + * we now must reissue the IDENTIFY command. + */ + if (id[2] == 0x37c8) + goto retry; + } + + if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) { + /* + * The exact sequence expected by certain pre-ATA4 drives is: + * SRST RESET + * IDENTIFY (optional in early ATA) + * INITIALIZE DEVICE PARAMETERS (later IDE and ATA) + * anything else.. + * Some drives were very specific about that exact sequence. + * + * Note that ATA4 says lba is mandatory so the second check + * shoud never trigger. + */ + if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { + err_mask = ata_dev_init_params(dev, id[3], id[6]); + if (err_mask) { + rc = -EIO; + reason = "INIT_DEV_PARAMS failed"; + goto err_out; + } + + /* current CHS translation info (id[53-58]) might be + * changed. reread the identify device info. + */ + flags &= ~ATA_READID_POSTRESET; + goto retry; + } + } + + *p_class = class; + return 0; + +err_out: + return rc; +} + +void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep) +{ + if (wait){ + ata_wait_idle(ap); + } + + ata_std_dev_select(ap, device); + + if (wait) { + ata_wait_idle(ap); + } +} + +void ata_std_dev_select(struct ata_port *ap, unsigned int device) +{ + u8 tmp; + + if (device == 0) { + tmp = ATA_DEVICE_OBS; + } else { + tmp = ATA_DEVICE_OBS | ATA_DEV1; + } + + writeb(tmp, ap->ioaddr.device_addr); + + /* needed; also flushes, for mmio */ + readb(ap->ioaddr.altstatus_addr); + + /* need delay 400nsec over */ + udelay(1); +} + +void ata_qc_reinit(struct ata_queued_cmd *qc) +{ + qc->dma_dir = DMA_NONE; + qc->flags = 0; + qc->nbytes = qc->extrabytes = qc->curbytes = 0; + qc->n_elem = 0; + qc->err_mask = 0; + qc->sect_size = ATA_SECT_SIZE; + qc->nbytes = ATA_SECT_SIZE * temp_n_block; + + memset(&qc->tf, 0, sizeof(qc->tf)); + qc->tf.ctl = 0; + qc->tf.device = ATA_DEVICE_OBS; + + /* init result_tf such that it indicates normal completion */ + qc->result_tf.command = ATA_DRDY; + qc->result_tf.feature = 0; +} + +unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, unsigned int buflen, + unsigned long timeout) +{ + struct ata_link *link = dev->link; + struct ata_port *ap = pap; + struct ata_queued_cmd *qc; + unsigned int tag, preempted_tag; + u32 preempted_sactive, preempted_qc_active; + int preempted_nr_active_links; + unsigned int err_mask; + int rc = 0; + u8 status; + + /* cheack BSY = 0 */ + status = ata_busy_wait(ap, ATA_BUSY, 300000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + rc = FALSE; + return rc; + } + + /* no internal command while frozen */ + if (ap->pflags & ATA_PFLAG_FROZEN) { + return AC_ERR_SYSTEM; + } + + tag = ATA_TAG_INTERNAL; + + if (test_and_set_bit(tag, &ap->qc_allocated)){ + printf("test_and_set_bit failed\n"); + } + + qc = __ata_qc_from_tag(ap, tag); + qc->tag = tag; + qc->ap = ap; + qc->dev = dev; + + ata_qc_reinit(qc); + + preempted_tag = link->active_tag; + preempted_sactive = link->sactive; + preempted_qc_active = ap->qc_active; + preempted_nr_active_links = ap->nr_active_links; + link->active_tag = ATA_TAG_POISON; + link->sactive = 0; + ap->qc_active = 0; + ap->nr_active_links = 0; + + /* prepare & issue qc */ + qc->tf = *tf; + if (cdb) + memcpy(qc->cdb, cdb, ATAPI_CDB_LEN); + qc->flags |= ATA_QCFLAG_RESULT_TF; + qc->dma_dir = dma_dir; + qc->private_data = 0; + + ata_qc_issue(qc); + + if (!timeout){ + timeout = ata_probe_timeout * 1000 / HZ; + } + + /* cheack BSY = 0 */ + status = ata_busy_wait(ap, ATA_BUSY, 30000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + printf("altstatus = 0x%x.\n",status); + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + if(waiting_for_reg_state(ap->ioaddr.altstatus_addr,1000,0x8)){ + printf("DRQ = 1 check timeout 1000msec\n"); + u8 status = 0; + u8 errorStatus = 0; + + status = readb( ap->ioaddr.altstatus_addr); + if ((status&0x01) != 0) { + errorStatus = readb( ap->ioaddr.feature_addr); + printf("ERROR STATUS = 0x%x\n",errorStatus); + } + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + status = ata_busy_wait(ap, ATA_BUSY, 10); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + ata_pio_task(ap); + + if (!rc) { + if (qc->flags & ATA_QCFLAG_ACTIVE) { + qc->err_mask |= AC_ERR_TIMEOUT; + ata_port_freeze(ap); + } + } + + /* perform minimal error analysis */ + if (qc->flags & ATA_QCFLAG_FAILED) { + if (qc->result_tf.command & (ATA_ERR | ATA_DF)){ + qc->err_mask |= AC_ERR_DEV; + } + + if (!qc->err_mask){ + qc->err_mask |= AC_ERR_OTHER; + } + + if (qc->err_mask & ~AC_ERR_OTHER){ + qc->err_mask &= ~AC_ERR_OTHER; + } + } + + /* finish up */ + *tf = qc->result_tf; + err_mask = qc->err_mask; + ata_qc_free(qc); + link->active_tag = preempted_tag; + link->sactive = preempted_sactive; + ap->qc_active = preempted_qc_active; + ap->nr_active_links = preempted_nr_active_links; + + if (ap->flags & ATA_FLAG_DISABLED) { + err_mask |= AC_ERR_SYSTEM; + ap->flags &= ~ATA_FLAG_DISABLED; + } + + return err_mask; +} + +unsigned int ata_dev_set_feature(struct ata_device *dev, + u8 enable, u8 feature) +{ + struct ata_taskfile tf; + struct ata_port *ap; + ap = pap; + unsigned int err_mask; + + /* set up set-features taskfile */ + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_SET_FEATURES; + tf.feature = enable; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = feature; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); + + return err_mask; +} + +unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors) +{ + struct ata_taskfile tf; + struct ata_port *ap; + ap = pap; + unsigned int err_mask; + + /* Number of sectors per track 1-255. Number of heads 1-16 */ + if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) + return AC_ERR_INVALID; + + /* set up init dev params taskfile */ + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_INIT_DEV_PARAMS; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = sectors; + tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */ + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); + + if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED)) + err_mask = 0; + + return err_mask; +} + +struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, + unsigned int tag) +{ + if (tag < ATA_MAX_QUEUE) + return &ap->qcmd[tag]; + return NULL; +} + +void ata_qc_issue(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; + u8 prot = qc->tf.protocol; + + if (ata_is_ncq(prot)) { + if (!link->sactive) + ap->nr_active_links++; + link->sactive |= 1 << qc->tag; + } else { + ap->nr_active_links++; + link->active_tag = qc->tag; + } + + qc->flags |= ATA_QCFLAG_ACTIVE; + ap->qc_active |= 1 << qc->tag; + + if (qc->dev->flags & ATA_DFLAG_SLEEPING) { + msleep(1); /* delay 1msec */ + return; + } + + qc->err_mask |= sata_dwc_qc_issue(qc); + if (qc->err_mask) + goto err; + + return; +err: + ata_qc_complete(qc); +} + +unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc) +{ + ata_qc_issue_prot(qc); + return 0; +} + +void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) +{ + /* set command register */ + writeb(tf->command, ap->ioaddr.command_addr); + + /* read alternative status register */ + readb(ap->ioaddr.altstatus_addr); + + /* delay 400nsec over */ + udelay(1); +} + +void __ata_port_freeze(struct ata_port *ap) +{ + printf("set port freeze.\n"); + ap->pflags |= ATA_PFLAG_FROZEN; +} + +int ata_port_freeze(struct ata_port *ap) +{ + __ata_port_freeze(ap); + return 0; +} + +unsigned int ata_tag_internal(unsigned int tag) +{ + return tag == ATA_MAX_QUEUE - 1; +} + +void ata_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_device *dev = qc->dev; + if (qc->err_mask) + qc->flags |= ATA_QCFLAG_FAILED; + + if (qc->flags & ATA_QCFLAG_FAILED) { + if (!ata_tag_internal(qc->tag)) { + /* always fill result TF for failed qc */ + fill_result_tf(qc); + return; + } + } + /* read result TF if requested */ + if (qc->flags & ATA_QCFLAG_RESULT_TF) + fill_result_tf(qc); + + /* Some commands need post-processing after successful + * completion. + */ + switch (qc->tf.command) { + case ATA_CMD_SET_FEATURES: + if (qc->tf.feature != SETFEATURES_WC_ON && + qc->tf.feature != SETFEATURES_WC_OFF) + break; + case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */ + case ATA_CMD_SET_MULTI: /* multi_count changed */ + break; + + case ATA_CMD_SLEEP: + dev->flags |= ATA_DFLAG_SLEEPING; + break; + } + + __ata_qc_complete(qc); +} + +void __ata_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; + + /* command should be marked inactive atomically with qc completion */ + link->active_tag = ATA_TAG_POISON; + ap->nr_active_links--; + + /* clear exclusive status */ + if (qc->flags & ATA_QCFLAG_CLEAR_EXCL && ap->excl_link == link) + ap->excl_link = NULL; + + qc->flags &= ~ATA_QCFLAG_ACTIVE; + ap->qc_active &= ~(1 << qc->tag); +} + +void fill_result_tf(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + qc->result_tf.flags = qc->tf.flags; + ata_tf_read(ap, &qc->result_tf); +} + +void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + tf->command = ata_check_status(ap); + tf->feature = readb(ioaddr->error_addr); + tf->nsect = readb(ioaddr->nsect_addr); + tf->lbal = readb(ioaddr->lbal_addr); + tf->lbam = readb(ioaddr->lbam_addr); + tf->lbah = readb(ioaddr->lbah_addr); + tf->device = readb(ioaddr->device_addr); + + if (tf->flags & ATA_TFLAG_LBA48) { + if (ioaddr->ctl_addr) { + writeb(tf->ctl | ATA_HOB, ioaddr->ctl_addr); + + tf->hob_feature = readb(ioaddr->error_addr); + tf->hob_nsect = readb(ioaddr->nsect_addr); + tf->hob_lbal = readb(ioaddr->lbal_addr); + tf->hob_lbam = readb(ioaddr->lbam_addr); + tf->hob_lbah = readb(ioaddr->lbah_addr); + + writeb(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + } else { + printf("sata_dwc warnning register read.\n"); + } + } +} + +void ata_qc_free(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int tag; + qc->flags = 0; + tag = qc->tag; + if (tag < ATA_MAX_QUEUE){ + qc->tag = ATA_TAG_POISON; + clear_bit(tag, &ap->qc_allocated); + } +} + +void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + if (tf->ctl != ap->last_ctl) { + if (ioaddr->ctl_addr){ + writeb(tf->ctl, ioaddr->ctl_addr); + } + ap->last_ctl = tf->ctl; + ata_wait_idle(ap); + } + + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + writeb(tf->hob_feature, ioaddr->feature_addr); + writeb(tf->hob_nsect, ioaddr->nsect_addr); + writeb(tf->hob_lbal, ioaddr->lbal_addr); + writeb(tf->hob_lbam, ioaddr->lbam_addr); + writeb(tf->hob_lbah, ioaddr->lbah_addr); + } + + if (is_addr) { + writeb(tf->feature, ioaddr->feature_addr); + writeb(tf->nsect, ioaddr->nsect_addr); + writeb(tf->lbal, ioaddr->lbal_addr); + writeb(tf->lbam, ioaddr->lbam_addr); + writeb(tf->lbah, ioaddr->lbah_addr); + } + + if (tf->flags & ATA_TFLAG_DEVICE) { + writeb(tf->device, ioaddr->device_addr); + } + + ata_wait_idle(ap); +} + +void sata_dwc_exec_command_by_tag(struct ata_port *ap, + struct ata_taskfile *tf, + u8 tag, u32 cmd_issued) +{ + struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); + hsdevp->cmd_issued[tag] = cmd_issued; + + /* Clear SError before executing a new command.*/ + clear_serror(); + ata_exec_command(ap, tf); +} + +void clear_serror(void) +{ + u32 temp; + temp = in_le32((void __iomem *)scr_addr_sstatus + 4); + + out_le32((void __iomem *)scr_addr_sstatus + 4, temp); +} + +void ata_tf_to_host(struct ata_port *ap, const struct ata_taskfile *tf) +{ + ata_tf_load(ap, tf); + ata_exec_command(ap, tf); +} + +unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + if (ap->flags & ATA_FLAG_PIO_POLLING) { + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + case ATA_PROT_NODATA: + case ATAPI_PROT_PIO: + case ATAPI_PROT_NODATA: + qc->tf.flags |= ATA_TFLAG_POLLING; + break; + default: + break; + } + } + + /* select the device */ + ata_dev_select(ap, qc->dev->devno, 1, 0); + + /* start the command */ + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + if (qc->tf.flags & ATA_TFLAG_POLLING){ + qc->tf.ctl |= ATA_NIEN; + } + + ata_tf_to_host(ap, &qc->tf); + + /* PIO data in protocol */ + ap->hsm_task_state = HSM_ST; + + if (qc->tf.flags & ATA_TFLAG_POLLING){ + ata_pio_queue_task(ap, qc, 0); + } + + break; + + default: + return AC_ERR_SYSTEM; + } + + return 0; +} + +void ata_pio_task(struct ata_port *arg_ap) +{ + struct ata_port *ap = arg_ap; + struct ata_queued_cmd *qc = ap->port_task_data; + u8 status; + int poll_next; + +fsm_start: + /* + * This is purely heuristic. This is a fast path. + * Sometimes when we enter, BSY will be cleared in + * 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, queue delayed work. + */ + 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) { + ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE); + return; + } + } + + /* move the HSM */ + poll_next = ata_hsm_move(ap, qc, status, 1); + + /* another command or interrupt handler + * may be running at this point. + */ + if (poll_next) + goto fsm_start; +} + +void ata_pio_queue_task(struct ata_port *ap, void *data,unsigned long delay) +{ + ap->port_task_data = data; +} + +unsigned int ac_err_mask(u8 status) +{ + if (status & (ATA_BUSY | ATA_DRQ)) + return AC_ERR_HSM; + if (status & (ATA_ERR | ATA_DF)) + return AC_ERR_DEV; + return 0; +} + +unsigned int __ac_err_mask(u8 status) +{ + unsigned int mask = ac_err_mask(status); + if (mask == 0) + return AC_ERR_OTHER; + return mask; +} + +int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq) +{ + int poll_next; + +fsm_start: + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + poll_next = (qc->tf.flags & ATA_TFLAG_POLLING); + + /* check device status */ + if ((status & ATA_DRQ) == 0) { + /* handle BSY=0, DRQ=0 as error */ + if (status & (ATA_ERR | ATA_DF)) { + /* device stops HSM for abort/error */ + qc->err_mask |= AC_ERR_DEV; + } else { + /* HSM violation. Let EH handle this */ + qc->err_mask |= AC_ERR_HSM; + } + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + /* Device should not ask for data transfer (DRQ=1) + * when it finds something wrong. + * We ignore DRQ here and stop the HSM by + * changing hsm_task_state to HSM_ST_ERR and + * let the EH abort the command or reset the device. + */ + if (status & (ATA_ERR | ATA_DF)) { + if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) { + printf("DRQ=1 with device error, " + "dev_stat 0x%X\n", status); + qc->err_mask |= AC_ERR_HSM; + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + } + + if (qc->tf.protocol == ATA_PROT_PIO) { + /* PIO data out protocol. + * send first data block. + */ + /* ata_pio_sectors() might change the state + * to HSM_ST_LAST. so, the state is changed here + * before ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST; + ata_pio_sectors(qc); + } else { + printf("protocol is not ATA_PROT_PIO \n"); + } + break; + + case HSM_ST: + /* complete command or read/write the data register */ + /* ATA PIO protocol */ + if ((status & ATA_DRQ) == 0) { + /* handle BSY=0, DRQ=0 as error */ + if (status & (ATA_ERR | ATA_DF)){ + /* device stops HSM for abort/error */ + qc->err_mask |= AC_ERR_DEV; + } else { + /* HSM violation. Let EH handle this. + * Phantom devices also trigger this + * condition. Mark hint. + */ + qc->err_mask |= AC_ERR_HSM | AC_ERR_NODEV_HINT; + } + + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + /* For PIO reads, some devices may ask for + * data transfer (DRQ=1) alone with ERR=1. + * We respect DRQ here and transfer one + * block of junk data before changing the + * hsm_task_state to HSM_ST_ERR. + * + * For PIO writes, ERR=1 DRQ=1 doesn't make + * sense since the data block has been + * transferred to the device. + */ + if (status & (ATA_ERR | ATA_DF)) { + /* data might be corrputed */ + qc->err_mask |= AC_ERR_DEV; + + if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { + ata_pio_sectors(qc); + status = ata_wait_idle(ap); + } + + if (status & (ATA_BUSY | ATA_DRQ)){ + qc->err_mask |= AC_ERR_HSM; + } + + /* ata_pio_sectors() might change the + * state to HSM_ST_LAST. so, the state + * is changed after ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + ata_pio_sectors(qc); + if (ap->hsm_task_state == HSM_ST_LAST && + (!(qc->tf.flags & ATA_TFLAG_WRITE))) { + /* all data read */ + status = ata_wait_idle(ap); + goto fsm_start; + } + + poll_next = 1; + break; + + case HSM_ST_LAST: + if (!ata_ok(status)) { + qc->err_mask |= __ac_err_mask(status); + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + /* no more data to transfer */ + ap->hsm_task_state = HSM_ST_IDLE; + + /* complete taskfile transaction */ + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + + case HSM_ST_ERR: + /* make sure qc->err_mask is available to + * know what's wrong and recover + */ + ap->hsm_task_state = HSM_ST_IDLE; + + /* complete taskfile transaction */ + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + default: + poll_next = 0; + } + + return poll_next; +} + +int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *qc) +{ + if (qc->tf.flags & ATA_TFLAG_POLLING) + return 1; + + if (ap->hsm_task_state == HSM_ST_FIRST) { + if (ata_is_atapi(qc->tf.protocol) && + !(qc->dev->flags & ATA_DFLAG_CDB_INTR)) + return 1; + } + + return 0; +} + +void ata_pio_sectors(struct ata_queued_cmd *qc) +{ + struct ata_port *ap; + ap = pap; + qc->pdata = ap->pdata; + + if (is_multi_taskfile(&qc->tf)) { + /* READ/WRITE MULTIPLE */ + unsigned int nsect; + + nsect = min((qc->nbytes - qc->curbytes) / qc->sect_size, + qc->dev->multi_count); + while (nsect--) + ata_pio_sector(qc); + } else { + ata_pio_sector(qc); + } + + readb(qc->ap->ioaddr.altstatus_addr); + udelay(1); +} + +void ata_pio_sector(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int offset; + unsigned char *buf; + + if (qc->curbytes == qc->nbytes - qc->sect_size){ + ap->hsm_task_state = HSM_ST_LAST; + } + + offset = qc->curbytes; + + /* check cmd and set buffer */ + switch (qc->tf.command) { + case ATA_CMD_ID_ATA: /* IDENTIFY */ + buf = &ata_device.id[0]; + break; + case ATA_CMD_PIO_READ_EXT: /* READ SECTORS EX 0x24 */ + case ATA_CMD_PIO_READ: /* READ SECTORS 0x20 */ + buf = qc->pdata + offset; + break; + default: + buf = &temp_data_buf[0]; + } + + /* data xfer */ + ata_mmio_data_xfer(qc->dev, buf, qc->sect_size); + + qc->curbytes += qc->sect_size; + +} + +void ata_mmio_data_xfer(struct ata_device *dev, unsigned char *buf, + unsigned int buflen) +{ + struct ata_port *ap = pap; + void __iomem *data_addr = ap->ioaddr.data_addr; + unsigned int words = buflen >> 1; + u16 *buf16 = (u16 *)buf; + unsigned int i = 0; + + udelay(100); + /* Transfer */ + for(i=0; i < words; i++) + buf16[i] = cpu_to_le16(readw(data_addr)); + + /* Transfer trailing 1 byte, if any. */ + if (buflen & 0x01) { + __le16 align_buf[1] = { 0 }; + unsigned char *trailing_buf = buf + buflen - 1; + + align_buf[0] = cpu_to_le16(readw(data_addr)); + memcpy(trailing_buf, align_buf, 1); + words++; + } +} + +void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) +{ + struct ata_port *ap = qc->ap; + + if (in_wq) { + /* EH might have kicked in while host lock is + * released. + */ + qc = &ap->qcmd[qc->tag]; + if (qc) { + if (!(qc->err_mask & AC_ERR_HSM)) { + ata_irq_on(ap); + ata_qc_complete(qc); + } else { + ata_port_freeze(ap); + } + } + } else { + if (!(qc->err_mask & AC_ERR_HSM)) { + ata_qc_complete(qc); + } else { + ata_port_freeze(ap); + } + } +} + +u8 ata_irq_on(struct ata_port *ap) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + u8 tmp; + + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; + + if (ioaddr->ctl_addr) + writeb(ap->ctl, ioaddr->ctl_addr); + + tmp = ata_wait_idle(ap); + + return tmp; +} + +void sata_dwc_probe(void) +{ + struct sata_dwc_device hsdev; + struct ata_host host; + struct ata_port_info pi = sata_dwc_port_info[0]; + struct ata_device *ata_dev = &ata_device; + struct ata_link *link; + struct sata_dwc_device_port hsdevp = dwc_devp; + u8 *base = 0; + u8 *sata_dma_regs_addr = 0; + u32 idr, versionr; + u8 status; + unsigned long base_addr = 0; + int chan = 0; + int rc; + int i; + const u16 *id; + unsigned long xfer_mask; + char revbuf[7]; /* XYZ-99\0 */ + unsigned long pio_mask, mwdma_mask, udma_mask; + + phost = &host; /* set grobal */ + + /* Base address */ + base = (u8*)SATA_BASE_ADDR; + + /* SATA register init */ + hsdev.sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET); + + host.n_ports = SATA_DWC_MAX_PORTS; + + for(i = 0; i < SATA_DWC_MAX_PORTS; i++){ + ap.pflags |= ATA_PFLAG_INITIALIZING; + ap.flags = ATA_FLAG_DISABLED; + ap.print_id = -1; + ap.ctl = ATA_DEVCTL_OBS; + ap.host = &host; + ap.last_ctl = 0xFF; + ap.dev = &ata_device; + + link = &ap.link; + link->ap = ≈ + link->pmp = 0; + link->active_tag = ATA_TAG_POISON; + link->hw_sata_spd_limit = 0; + + ap.port_no = i; + host.ports[i] = ≈ + } + + ap.pio_mask = pi.pio_mask; + ap.mwdma_mask = pi.mwdma_mask; + ap.udma_mask = pi.udma_mask; + ap.flags |= pi.flags; + ap.link.flags |= pi.link_flags; + + /* Host port init */ + host.ports[0]->ioaddr.cmd_addr = base; + host.ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET; + scr_addr_sstatus = base + SATA_DWC_SCR_OFFSET; + + /* sata_dwc setup port */ + base_addr = (unsigned long)base; + + host.ports[0]->ioaddr.cmd_addr = (void *)base_addr + 0x00; + host.ports[0]->ioaddr.data_addr = (void *)base_addr + 0x00; + + host.ports[0]->ioaddr.error_addr = (void *)base_addr + 0x04; + host.ports[0]->ioaddr.feature_addr = (void *)base_addr + 0x04; + + host.ports[0]->ioaddr.nsect_addr = (void *)base_addr + 0x08; + + host.ports[0]->ioaddr.lbal_addr = (void *)base_addr + 0x0c; + host.ports[0]->ioaddr.lbam_addr = (void *)base_addr + 0x10; + host.ports[0]->ioaddr.lbah_addr = (void *)base_addr + 0x14; + + host.ports[0]->ioaddr.device_addr = (void *)base_addr + 0x18; + host.ports[0]->ioaddr.command_addr = (void *)base_addr + 0x1c; + host.ports[0]->ioaddr.status_addr = (void *)base_addr + 0x1c; + + host.ports[0]->ioaddr.altstatus_addr = (void *)base_addr + 0x20; + host.ports[0]->ioaddr.ctl_addr = (void *)base_addr + 0x20; + + /* Get Host ID / Version */ + idr = in_le32(&hsdev.sata_dwc_regs->idr); + versionr = in_le32(&hsdev.sata_dwc_regs->versionr); + + /* DMA register init */ + sata_dma_regs_addr = (u8*)SATA_DMA_REG_ADDR; + sata_dma_regs = (void *__iomem)sata_dma_regs_addr; + + /* DMA channel Interrupt is disable. DMA Enable setup is next. */ + for(chan = 0; chan < DMA_NUM_CHANS; chan++){ + /* DMA Interrupt register(error) mask. */ + out_le32(&(sata_dma_regs->interrupt_mask.error.low), + DMA_DISABLE_CHAN(chan)); + + /* DMA Interrupt register(transfer) mask. */ + out_le32(&(sata_dma_regs->interrupt_mask.tfr.low), + DMA_DISABLE_CHAN(chan)); + } + + /* DMA Enable by DMAC Configuration Register */ + out_le32(&(sata_dma_regs->dma_cfg.low), DMA_EN); + + /* Enable selective interrupts by setting the interrupt mask register */ + out_le32(&hsdev.sata_dwc_regs->intmr, + SATA_DWC_INTMR_ERRM | + SATA_DWC_INTMR_NEWFPM | + SATA_DWC_INTMR_PMABRTM | + SATA_DWC_INTMR_DMATM); + + /* Unmask the error bits that should trigger an error interrupt by + * setting the error mask register. + */ + out_le32(&hsdev.sata_dwc_regs->errmr,SATA_DWC_SERROR_ERR_BITS); + + hsdev.host = ap.host; + memset(&hsdevp, 0, sizeof(hsdevp)); + hsdevp.hsdev = &hsdev; + + for (i = 0; i < SATA_DWC_QCMD_MAX; i++) + hsdevp.cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT; + + if (ap.port_no == 0) { + out_le32(&hsdev.sata_dwc_regs->dmacr,SATA_DWC_DMACR_TXRXCH_CLEAR); + + out_le32(&hsdev.sata_dwc_regs->dbtsr, + (SATA_DWC_DBTSR_MWR(AHB_DMA_BRST_DFLT) | + SATA_DWC_DBTSR_MRD(AHB_DMA_BRST_DFLT))); + } + + /* Clear any error bits before libata starts issuing commands */ + out_le32((void __iomem *)scr_addr_sstatus + 4, + in_le32((void __iomem *)scr_addr_sstatus + 4)); + + /* check altstatus register (find device) */ + status = ata_check_altstatus(&ap); + + if(status == 0x7f){ + printf("Hard Disk not found.\n"); + dev_state = SATA_NODEVICE; + return; + } + + /* waiting for device ready. time out 30sec */ + printf("waitng for device ready."); + i = 0; + while(1){ + udelay (10000); /* 10 ms */ + + /* read altstatus */ + status = ata_check_altstatus(&ap); + + /* status is not busy => break */ + if((status & ATA_BUSY) == 0){ + printf("\n"); + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + + /* bussy set devise state flag */ + dev_state = SATA_NODEVICE; + return; + } + if ((i >= 100) && ((i%100)==0)) { + printf("."); + } + } + + /* softreset */ + rc = sata_dwc_softreset(&ap); + + if(rc){ + printf("sata_dwc : error. soft reset failed\n"); + } + + /* waiting for device ready. time out 30sec */ + printf("waitng for device ready."); + i = 0; + while(1){ + udelay (10000); /* 10 ms */ + + /* read altstatus */ + status = ata_check_altstatus(&ap); + + /* status is not busy => break */ + if((status & ATA_BUSY) == 0){ + printf("\n"); + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + + /* bussy set devise state flag */ + dev_state = SATA_NODEVICE; + return; + } + if ((i >= 100) && ((i%100)==0)) { + printf("."); + } + } + + udelay (1000); /* before IDENTIFY command safety delay 1 ms */ + + /* IDENTIFY command send */ + rc = ata_dev_read_id(ata_dev, &ata_dev->class, + ATA_READID_POSTRESET,ata_dev->id); + + if(rc){ + printf("sata_dwc : error. IDENTIFY Command failed\n"); + } + + /* SATA drives indicate we have a bridge. We don't know which + * end of the link the bridge is which is a problem + */ + if (ata_id_is_sata(ata_dev->id)) + ap.cbl = ATA_CBL_SATA; + + id = ata_dev->id; + + /* initialize to be configured parameters */ + ata_dev->flags &= ~ATA_DFLAG_CFG_MASK; + ata_dev->max_sectors = 0; + ata_dev->cdb_len = 0; + ata_dev->n_sectors = 0; + ata_dev->cylinders = 0; + ata_dev->heads = 0; + ata_dev->sectors = 0; + + /* Usual case. Word 53 indicates word 64 is valid */ + if (id[ATA_ID_FIELD_VALID] & (1 << 1)) { + pio_mask = id[ATA_ID_PIO_MODES] & 0x03; + pio_mask <<= 3; + pio_mask |= 0x7; + } else { + /* If word 64 isn't valid then Word 51 high byte holds + * the PIO timing number for the maximum. Turn it into + * a mask. + */ + u8 mode = (id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF; + if (mode < 5){ /* Valid PIO range */ + pio_mask = (2 << mode) - 1; + } else { + pio_mask = 1; + } + } + + mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07; + + if (ata_id_is_cfa(id)) { + /* + * Process compact flash extended modes + */ + int pio = id[163] & 0x7; + int dma = (id[163] >> 3) & 7; + + if (pio) + pio_mask |= (1 << 5); + if (pio > 1) + pio_mask |= (1 << 6); + if (dma) + mwdma_mask |= (1 << 3); + if (dma > 1) + mwdma_mask |= (1 << 4); + } + + udma_mask = 0; + if (id[ATA_ID_FIELD_VALID] & (1 << 2)) + udma_mask = id[ATA_ID_UDMA_MODES] & 0xff; + + xfer_mask = (pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO | + (mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA | + (udma_mask << ATA_SHIFT_UDMA) & ATA_MASK_UDMA; + + /* ATA-specific feature tests */ + if (ata_dev->class == ATA_DEV_ATA) { + if (ata_id_is_cfa(id)) { + if (id[162] & 1) /* CPRM may make this media unusable */ + printf("supports DRM functions and may " + "not be fully accessable.\n"); + sprintf(revbuf, "%s", "CFA"); + } else { + /* Warn the user if the device has TPM extensions */ + if (ata_id_has_tpm(id)) + printf("supports DRM functions and may " + "not be fully accessable.\n"); + } + + /* set n_secters */ + ata_dev->n_sectors = ata_id_n_sectors((u16*)id); + + if (ata_dev->id[59] & 0x100) + ata_dev->multi_count = ata_dev->id[59] & 0xff; + + if (ata_id_has_lba(id)) { + const char *lba_desc; + char ncq_desc[20]; + + lba_desc = "LBA"; + ata_dev->flags |= ATA_DFLAG_LBA; + if (ata_id_has_lba48(id)) { + ata_dev->flags |= ATA_DFLAG_LBA48; + lba_desc = "LBA48"; + + if (ata_dev->n_sectors >= (1UL << 28) && + ata_id_has_flush_ext(id)) + ata_dev->flags |= ATA_DFLAG_FLUSH_EXT; + } + /* config NCQ */ + if (!ata_id_has_ncq(ata_dev->id)) { + ncq_desc[0] = '\0'; + } + + if (ata_dev->horkage & ATA_HORKAGE_NONCQ) { + sprintf(ncq_desc, "%s", "NCQ (not used)"); + } + + if (ap.flags & ATA_FLAG_NCQ) { + ata_dev->flags |= ATA_DFLAG_NCQ; + } + } + ata_dev->cdb_len = 16; + } + /* determine max_sectors */ + ata_dev->max_sectors = ATA_MAX_SECTORS; + if (ata_dev->flags & ATA_DFLAG_LBA48) + ata_dev->max_sectors = ATA_MAX_SECTORS_LBA48; + + if (!(ata_dev->horkage & ATA_HORKAGE_IPM)) { + if (ata_id_has_hipm(ata_dev->id)) + ata_dev->flags |= ATA_DFLAG_HIPM; + if (ata_id_has_dipm(ata_dev->id)) + ata_dev->flags |= ATA_DFLAG_DIPM; + } + + if ((ap.cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ata_dev->id))) { + ata_dev->udma_mask &= ATA_UDMA5; + ata_dev->max_sectors = ATA_MAX_SECTORS; + } + + if (ata_dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { + printf("Drive reports diagnostics failure." + "This may indicate a drive\n"); + printf("fault or invalid emulation." + "Contact drive vendor for information.\n"); + } + + /* Hard Disk status check : test send READ Command */ + rc = check_sata_dev_state(); +} + +int sata_dwc_softreset(struct ata_port *ap) +{ + u8 nsect,lbal = 0; + u8 tmp = 0; + u32 serror = 0; + u8 status = 0; + struct ata_ioports *ioaddr = &ap->ioaddr; + + /* read SCR ERROR */ + serror = in_le32((void *)ap->ioaddr.scr_addr + (SCR_ERROR * 4)); + + /* device check */ + writeb(0x55, ioaddr->nsect_addr); + writeb(0xaa, ioaddr->lbal_addr); + writeb(0xaa, ioaddr->nsect_addr); + writeb(0x55, ioaddr->lbal_addr); + writeb(0x55, ioaddr->nsect_addr); + writeb(0xaa, ioaddr->lbal_addr); + + nsect = readb(ioaddr->nsect_addr); + lbal = readb(ioaddr->lbal_addr); + + if ((nsect == 0x55) && (lbal == 0xaa)){ + /* we found a device */ + printf("we found a device\n"); + } else { + /* nothing found */ + printf("Not found a device.\n"); + dev_state = SATA_NODEVICE; + return FALSE; + } + + tmp = ATA_DEVICE_OBS; + writeb(tmp,ioaddr->device_addr); + writeb(ap->ctl,ioaddr->ctl_addr); + + udelay(200); + + /* set softreset */ + writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr); + + udelay(200); + writeb(ap->ctl,ioaddr->ctl_addr); + + /* wait a while before cheking status */ + msleep(150); + status = ata_check_status(ap); + + msleep(50); + ata_check_status(ap); + + while (1) { + u8 status = ata_check_status(ap); + + if (!(status & ATA_BUSY)){ + break; + } + + status = in_le32((void *)ap->ioaddr.scr_addr + (SCR_STATUS * 4)); + if(status == 0xff || (status & 0xf) != 0x3){ + } + + printf("Hard Disk status is BUSY.\n"); + msleep(50); + } + + tmp = ATA_DEVICE_OBS; + writeb(tmp,ioaddr->device_addr); + + nsect = readb(ioaddr->nsect_addr); + lbal = readb(ioaddr->lbal_addr); + + return 0; +} + +void scsi_bus_reset() +{ + struct ata_port *ap = pap; + + /* check device state */ + if(dev_state != SATA_READY){ + printf("no devices available\n"); + return; + } + + /*soft reset process*/ + sata_dwc_softreset(ap); +} + +void scsi_print_error(ccb * pccb) +{ + /*The ahci error info can be read in the ahci driver*/ +} + +int ata_dev_read_sectors(ccb *pccb) +{ + struct ata_port *ap = pap; + struct ata_device *dev = &ata_device; + struct ata_taskfile tf; + unsigned int class = ATA_DEV_ATA; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1; + int rc; + + u32 block=0; + u32 n_block=0; + + ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */ + +retry: + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; /*ap->ctl = 0x08 */ + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + + /* set pdata */ + ap->pdata = pccb->pdata; + + tf.device = ATA_DEVICE_OBS; + + block |= ((u32)pccb->cmd[2]) << 24; + block |= ((u32)pccb->cmd[3]) << 16; + block |= ((u32)pccb->cmd[4]) << 8; + block |= ((u32)pccb->cmd[5]); + + n_block |= ((u32)pccb->cmd[7]) << 8; + n_block |= ((u32)pccb->cmd[8]); + + /* trying temp to n_block */ + temp_n_block = n_block; + + +#ifdef CONFIG_LBA48 + tf.command = ATA_CMD_PIO_READ_EXT; /* READ SECTOR(S) EXT 0x24 */ + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; + + tf.hob_feature = 31; + tf.feature = 31; + tf.hob_nsect = (n_block >> 8) & 0xff; + tf.nsect = n_block & 0xff; + + tf.hob_lbah = 0x0; + tf.hob_lbam = 0x0; + tf.hob_lbal = (block >> 24) & 0xff; + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; +#else /* LBA24 */ + tf.command = ATA_CMD_PIO_READ; /* READ SECTOR(S) 0x20 */ + tf.flags |= ATA_TFLAG_LBA ; + + tf.feature = 31; + tf.nsect = n_block & 0xff; + + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = (block >> 24) & 0xf; + + tf.device |= 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; + +#endif /* CONFIG_LBA48 */ + + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.flags |= ATA_TFLAG_POLLING; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,0, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("READ_SECTORS NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + /* sanity check */ + rc = -EINVAL; + reason = "device reports invalid type"; + + return 0; + +err_out: + printf("failed to READ SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); + return rc; +} diff -purN u-boot-2009.03/drivers/block/sata_dwc.h u-boot-2009.03-sata/drivers/block/sata_dwc.h --- u-boot-2009.03/drivers/block/sata_dwc.h 1970-01-01 09:00:00.000000000 +0900 +++ u-boot-2009.03-sata/drivers/block/sata_dwc.h 2009-03-25 17:27:01.000000000 +0900 @@ -0,0 +1,496 @@ +/* + * sata_dwc.h + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld mmiesfeld@amcc.com + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese sr@denx.de + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * This program is free software; you can redistribute + * it and/or modify it under the terms of the GNU + * General Public License as published by the + * Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + */ + +#ifndef _SATA_DWC_H_ +#define _SATA_DWC_H_ + +#define HZ 100 + +#define READ 0 +#define WRITE 1 + +static int ata_id_has_hipm(const u16 *id) +{ + u16 val = id[76]; + + if (val == 0 || val == 0xffff) + return -1; + + return val & (1 << 9); +} + +static int ata_id_has_dipm(const u16 *id) +{ + u16 val = id[78]; + + if (val == 0 || val == 0xffff) + return -1; + + return val & (1 << 3); +} + +enum { + ATA_READID_POSTRESET = (1 << 0), /* reading ID after reset */ + + ATA_DNXFER_PIO = 0, /* speed down PIO */ + ATA_DNXFER_DMA = 1, /* speed down DMA */ + ATA_DNXFER_40C = 2, /* apply 40c cable limit */ + ATA_DNXFER_FORCE_PIO = 3, /* force PIO */ + ATA_DNXFER_FORCE_PIO0 = 4, /* force PIO0 */ + + ATA_DNXFER_QUIET = (1 << 31), +}; + +enum hsm_task_states { + HSM_ST_IDLE, /* no command on going */ + HSM_ST_FIRST, /* (waiting the device to) + * write CDB or first data block */ + HSM_ST, /* (waiting the device to) transfer data */ + HSM_ST_LAST, /* (waiting the device to) complete command */ + HSM_ST_ERR, /* error */ +}; + +#define ATA_SHORT_PAUSE ((HZ >> 6) + 1) + +typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc); + +struct ata_queued_cmd { + struct ata_port *ap; + struct ata_device *dev; + + struct ata_taskfile tf; + u8 cdb[ATAPI_CDB_LEN]; + + unsigned long flags; /* ATA_QCFLAG_xxx */ + unsigned int tag; + unsigned int n_elem; + + int dma_dir; + + unsigned int sect_size; + + unsigned int nbytes; + unsigned int extrabytes; + unsigned int curbytes; + + unsigned int err_mask; + struct ata_taskfile result_tf; + + void *private_data; + void *lldd_task; + unsigned char *pdata; +}; + +/* defines only for the constants which don't work cell as enums*/ +#define ATA_TAG_POISON 0xfafbfcfdU + +enum { + /* various global constants */ + LIBATA_MAX_PRD = ATA_MAX_PRD / 2, + LIBATA_DUMB_MAX_PRD = ATA_MAX_PRD / 4, /* Worst case */ + ATA_MAX_PORTS = 8, + ATA_DEF_QUEUE = 1, + /* tag ATA_MAX_QUEUE - 1 is reserved for internal commands */ + ATA_MAX_QUEUE = 32, + ATA_TAG_INTERNAL = ATA_MAX_QUEUE - 1, + ATA_MAX_BUS = 2, + ATA_DEF_BUSY_WAIT = 10000, + + ATAPI_MAX_DRAIN = 16 << 10, + + ATA_SHT_EMULATED = 1, + ATA_SHT_CMD_PER_LUN = 1, + ATA_SHT_THIS_ID = -1, + ATA_SHT_USE_CLUSTERING = 1, + + /* struct ata_device stuff */ + ATA_DFLAG_LBA = (1 << 0), /* device supports LBA */ + ATA_DFLAG_LBA48 = (1 << 1), /* device supports LBA48 */ + ATA_DFLAG_CDB_INTR = (1 << 2), /* device asserts INTRQ */ + ATA_DFLAG_NCQ = (1 << 3), /* device supports NCQ */ + ATA_DFLAG_FLUSH_EXT = (1 << 4), /* do FLUSH_EXT instead of FLUSH */ + ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */ + ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */ + ATA_DFLAG_AN = (1 << 7), /* AN configured */ + ATA_DFLAG_HIPM = (1 << 8), /* device supports HIPM */ + ATA_DFLAG_DIPM = (1 << 9), /* device supports DIPM */ + ATA_DFLAG_DMADIR = (1 << 10), /* device requires DMADIR */ + ATA_DFLAG_CFG_MASK = (1 << 12) - 1, + + ATA_DFLAG_PIO = (1 << 12), /* device limited to PIO mode */ + ATA_DFLAG_NCQ_OFF = (1 << 13), /* device limited to non-NCQ mode */ + ATA_DFLAG_SPUNDOWN = (1 << 14), /* XXX: for spindown_compat */ + ATA_DFLAG_SLEEPING = (1 << 15), /* device is sleeping */ + ATA_DFLAG_DUBIOUS_XFER = (1 << 16), /* data transfer not verified */ + ATA_DFLAG_INIT_MASK = (1 << 24) - 1, + + ATA_DFLAG_DETACH = (1 << 24), + ATA_DFLAG_DETACHED = (1 << 25), + + /* struct ata_link flags */ + ATA_LFLAG_HRST_TO_RESUME = (1 << 0), /* hardreset to resume link */ + ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), /* can't wait for the first D2H + * Register FIS clearing BSY */ + ATA_LFLAG_NO_SRST = (1 << 2), /* avoid softreset */ + ATA_LFLAG_ASSUME_ATA = (1 << 3), /* assume ATA class */ + ATA_LFLAG_ASSUME_SEMB = (1 << 4), /* assume SEMB class */ + ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, + ATA_LFLAG_NO_RETRY = (1 << 5), /* don't retry this link */ + ATA_LFLAG_DISABLED = (1 << 6), /* link is disabled */ + + /* struct ata_port flags */ + ATA_FLAG_SLAVE_POSS = (1 << 0), + ATA_FLAG_SATA = (1 << 1), + ATA_FLAG_NO_LEGACY = (1 << 2), /* no legacy mode check */ + ATA_FLAG_MMIO = (1 << 3), /* use MMIO, not PIO */ + ATA_FLAG_SRST = (1 << 4), /* (obsolete) use ATA SRST, not E.D.D. */ + ATA_FLAG_SATA_RESET = (1 << 5), /* (obsolete) use COMRESET */ + ATA_FLAG_NO_ATAPI = (1 << 6), /* No ATAPI support */ + ATA_FLAG_PIO_DMA = (1 << 7), /* PIO cmds via DMA */ + ATA_FLAG_PIO_LBA48 = (1 << 8), /* Host DMA engine is LBA28 only */ + ATA_FLAG_PIO_POLLING = (1 << 9), /* use polling PIO if LLD + * doesn't handle PIO interrupts */ + ATA_FLAG_NCQ = (1 << 10), /* host supports NCQ */ + ATA_FLAG_DEBUGMSG = (1 << 13), + ATA_FLAG_IGN_SIMPLEX = (1 << 15), /* ignore SIMPLEX */ + ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */ + ATA_FLAG_ACPI_SATA = (1 << 17), /* need native SATA ACPI layout */ + ATA_FLAG_AN = (1 << 18), /* controller supports AN */ + ATA_FLAG_PMP = (1 << 19), /* controller supports PMP */ + ATA_FLAG_IPM = (1 << 20), /* driver can handle IPM */ + + ATA_FLAG_DISABLED = (1 << 23), /* port is disabled, ignore it */ + + /* struct ata_port pflags */ + ATA_PFLAG_EH_PENDING = (1 << 0), /* EH pending */ + ATA_PFLAG_EH_IN_PROGRESS = (1 << 1), /* EH in progress */ + ATA_PFLAG_FROZEN = (1 << 2), /* port is frozen */ + ATA_PFLAG_RECOVERED = (1 << 3), /* recovery action performed */ + ATA_PFLAG_LOADING = (1 << 4), /* boot/loading probe */ + ATA_PFLAG_UNLOADING = (1 << 5), /* module is unloading */ + ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), /* SCSI hotplug scheduled */ + ATA_PFLAG_INITIALIZING = (1 << 7), /* being initialized, don't touch */ + ATA_PFLAG_RESETTING = (1 << 8), /* reset in progress */ + ATA_PFLAG_SUSPENDED = (1 << 17), /* port is suspended (power) */ + ATA_PFLAG_PM_PENDING = (1 << 18), /* PM operation pending */ + + /* struct ata_queued_cmd flags */ + ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */ + ATA_QCFLAG_DMAMAP = (1 << 1), /* SG table is DMA mapped */ + ATA_QCFLAG_IO = (1 << 3), /* standard IO command */ + ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */ + ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */ + ATA_QCFLAG_QUIET = (1 << 6), /* don't report device error */ + + ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */ + ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */ + ATA_QCFLAG_EH_SCHEDULED = (1 << 18), /* EH scheduled (obsolete) */ + + /* host set flags */ + ATA_HOST_SIMPLEX = (1 << 0), + ATA_HOST_STARTED = (1 << 1), /* Host started */ + + /* various lengths of time */ + ATA_TMOUT_BOOT = 30 * 100, /* heuristic */ + ATA_TMOUT_BOOT_QUICK = 7 * 100, /* heuristic */ + ATA_TMOUT_INTERNAL = 30 * 100, + ATA_TMOUT_INTERNAL_QUICK = 5 * 100, + + /* FIXME: GoVault needs 2s but we can't afford that without + * parallel probing. 800ms is enough for iVDR disk + * HHD424020F7SV00. Increase to 2secs when parallel probing + * is in place. + */ + ATA_TMOUT_FF_WAIT = 4 * 100 / 5, + + /* ATA bus states */ + BUS_UNKNOWN = 0, + BUS_DMA = 1, + BUS_IDLE = 2, + BUS_NOINTR = 3, + BUS_NODATA = 4, + BUS_TIMER = 5, + BUS_PIO = 6, + BUS_EDD = 7, + BUS_IDENTIFY = 8, + BUS_PACKET = 9, + + /* SATA port states */ + PORT_UNKNOWN = 0, + PORT_ENABLED = 1, + PORT_DISABLED = 2, + + /* encoding various smaller bitmaps into a single + * unsigned long bitmap + */ + ATA_NR_PIO_MODES = 7, + ATA_NR_MWDMA_MODES = 5, + ATA_NR_UDMA_MODES = 8, + + ATA_SHIFT_PIO = 0, + ATA_SHIFT_MWDMA = ATA_SHIFT_PIO + ATA_NR_PIO_MODES, + ATA_SHIFT_UDMA = ATA_SHIFT_MWDMA + ATA_NR_MWDMA_MODES, + + /* size of buffer to pad xfers ending on unaligned boundaries */ + ATA_DMA_PAD_SZ = 4, + + /* ering size */ + ATA_ERING_SIZE = 32, + + ATA_DEFER_LINK = 1, + ATA_DEFER_PORT = 2, + + /* desc_len for ata_eh_info and context */ + ATA_EH_DESC_LEN = 80, + + /* reset / recovery action types */ + ATA_EH_REVALIDATE = (1 << 0), + ATA_EH_SOFTRESET = (1 << 1), + ATA_EH_HARDRESET = (1 << 2), + ATA_EH_ENABLE_LINK = (1 << 3), + ATA_EH_LPM = (1 << 4), /* link power management action */ + + ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, + ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, + + /* ata_eh_info->flags */ + ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ + ATA_EHI_RESUME_LINK = (1 << 1), /* resume link (reset modifier) */ + ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */ + ATA_EHI_QUIET = (1 << 3), /* be quiet */ + + ATA_EHI_DID_SOFTRESET = (1 << 16), /* already soft-reset this port */ + ATA_EHI_DID_HARDRESET = (1 << 17), /* already soft-reset this port */ + ATA_EHI_PRINTINFO = (1 << 18), /* print configuration info */ + ATA_EHI_SETMODE = (1 << 19), /* configure transfer mode */ + ATA_EHI_POST_SETMODE = (1 << 20), /* revaildating after setmode */ + + ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET, + ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, + + /* max tries if error condition is still set after ->error_handler */ + ATA_EH_MAX_TRIES = 5, + + /* how hard are we gonna try to probe/recover devices */ + ATA_PROBE_MAX_TRIES = 3, + ATA_EH_DEV_TRIES = 3, + ATA_EH_PMP_TRIES = 5, + ATA_EH_PMP_LINK_TRIES = 3, + + SATA_PMP_SCR_TIMEOUT = 250, + + /* Horkage types. May be set by libata or controller on drives + (some horkage may be drive/controller pair dependant */ + + ATA_HORKAGE_DIAGNOSTIC = (1 << 0), /* Failed boot diag */ + ATA_HORKAGE_NODMA = (1 << 1), /* DMA problems */ + ATA_HORKAGE_NONCQ = (1 << 2), /* Don't use NCQ */ + ATA_HORKAGE_MAX_SEC_128 = (1 << 3), /* Limit max sects to 128 */ + ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */ + ATA_HORKAGE_SKIP_PM = (1 << 5), /* Skip PM operations */ + ATA_HORKAGE_HPA_SIZE = (1 << 6), /* native size off by one */ + ATA_HORKAGE_IPM = (1 << 7), /* Link PM problems */ + ATA_HORKAGE_IVB = (1 << 8), /* cbl det validity bit bugs */ + ATA_HORKAGE_STUCK_ERR = (1 << 9), /* stuck ERR on next PACKET */ + + /* DMA mask for user DMA control: User visible values; DO NOT renumber */ + ATA_DMA_MASK_ATA = (1 << 0), /* DMA on ATA Disk */ + ATA_DMA_MASK_ATAPI = (1 << 1), /* DMA on ATAPI */ + ATA_DMA_MASK_CFA = (1 << 2), /* DMA on CF Card */ + + /* ATAPI command types */ + ATAPI_READ = 0, /* READs */ + ATAPI_WRITE = 1, /* WRITEs */ + ATAPI_READ_CD = 2, /* READ CD [MSF] */ + ATAPI_PASS_THRU = 3, /* SAT pass-thru */ + ATAPI_MISC = 4, /* the rest */ +}; + +enum ata_completion_errors { + AC_ERR_DEV = (1 << 0), /* device reported error */ + AC_ERR_HSM = (1 << 1), /* host state machine violation */ + AC_ERR_TIMEOUT = (1 << 2), /* timeout */ + AC_ERR_MEDIA = (1 << 3), /* media error */ + AC_ERR_ATA_BUS = (1 << 4), /* ATA bus error */ + AC_ERR_HOST_BUS = (1 << 5), /* host bus error */ + AC_ERR_SYSTEM = (1 << 6), /* system error */ + AC_ERR_INVALID = (1 << 7), /* invalid argument */ + AC_ERR_OTHER = (1 << 8), /* unknown */ + AC_ERR_NODEV_HINT = (1 << 9), /* polling device detection hint */ + AC_ERR_NCQ = (1 << 10), /* marker for offending NCQ qc */ +}; + +enum ata_xfer_mask { + ATA_MASK_PIO = ((1LU << ATA_NR_PIO_MODES) - 1) << ATA_SHIFT_PIO, + ATA_MASK_MWDMA = ((1LU << ATA_NR_MWDMA_MODES) - 1) << ATA_SHIFT_MWDMA, + ATA_MASK_UDMA = ((1LU << ATA_NR_UDMA_MODES) - 1) << ATA_SHIFT_UDMA, +}; + +struct ata_port_info { + struct scsi_host_template *sht; + unsigned long flags; + unsigned long link_flags; + unsigned long pio_mask; + unsigned long mwdma_mask; + unsigned long udma_mask; + const struct ata_port_operations *port_ops; + void *private_data; +}; + +struct ata_ioports { + void __iomem *cmd_addr; + void __iomem *data_addr; + void __iomem *error_addr; + void __iomem *feature_addr; + void __iomem *nsect_addr; + void __iomem *lbal_addr; + void __iomem *lbam_addr; + void __iomem *lbah_addr; + void __iomem *device_addr; + void __iomem *status_addr; + void __iomem *command_addr; + void __iomem *altstatus_addr; + void __iomem *ctl_addr; + void __iomem *bmdma_addr; + void __iomem *scr_addr; +}; + +struct ata_host { + void __iomem * const *iomap; + unsigned int n_ports; + void *private_data; + const struct ata_port_operations *ops; + unsigned long flags; + struct ata_port *simplex_claimed; /* channel owning the DMA */ + struct ata_port *ports[0]; +}; + +struct ata_port_stats { + unsigned long unhandled_irq; + unsigned long idle_irq; + unsigned long rw_reqbuf; +}; + +struct ata_device { + struct ata_link *link; + unsigned int devno; /* 0 or 1 */ + unsigned long flags; /* ATA_DFLAG_xxx */ + unsigned int horkage; /* List of broken features */ + struct scsi_device *sdev; /* attached SCSI device */ +#ifdef CONFIG_ATA_ACPI + acpi_handle acpi_handle; + union acpi_object *gtf_cache; +#endif + /* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */ + u64 n_sectors; /* size of device, if ATA */ + unsigned int class; /* ATA_DEV_xxx */ + + union { + u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ + u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */ + }; + + u8 pio_mode; + u8 dma_mode; + u8 xfer_mode; + unsigned int xfer_shift; /* ATA_SHIFT_xxx */ + + unsigned int multi_count; /* sectors count for + *READ/WRITE MULTIPLE */ + unsigned int max_sectors; /* per-device max sectors */ + unsigned int cdb_len; + + /* per-dev xfer mask */ + unsigned long pio_mask; + unsigned long mwdma_mask; + unsigned long udma_mask; + + /* for CHS addressing */ + u16 cylinders; /* Number of cylinders */ + u16 heads; /* Number of heads */ + u16 sectors; /* Number of sectors per track */ + + /* error history */ + int spdn_cnt; +}; + +enum dma_data_direction { + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, + DMA_NONE = 3, +}; + +struct ata_link { + struct ata_port *ap; + int pmp; /* port multiplier port # */ + unsigned int active_tag; /* active tag on this link */ + u32 sactive; /* active NCQ commands */ + + unsigned int flags; /* ATA_LFLAG_xxx */ + + unsigned int hw_sata_spd_limit; + unsigned int sata_spd_limit; + unsigned int sata_spd; /* current SATA PHY speed */ + + struct ata_device device[2]; +}; + +struct ata_port { + unsigned long flags; /* ATA_FLAG_xxx */ + unsigned int pflags; /* ATA_PFLAG_xxx */ + unsigned int print_id; /* user visible unique port ID */ + unsigned int port_no; /* 0 based port no. inside the host */ + + struct ata_ioports ioaddr; /* ATA cmd/ctl/dma register blocks */ + + u8 ctl; /* cache of ATA control register */ + u8 last_ctl; /* Cache last written value */ + unsigned int pio_mask; + unsigned int mwdma_mask; + unsigned int udma_mask; + unsigned int cbl; /* cable type; ATA_CBL_xxx */ + + struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; + unsigned long qc_allocated; + unsigned int qc_active; + int nr_active_links; /* #links with active qcs */ + + struct ata_link link; /* host default link */ + + int nr_pmp_links; /* nr of available PMP links */ + struct ata_link *pmp_link; /* array of PMP links */ + struct ata_link *excl_link; /* for PMP qc exclusion */ + + struct ata_port_stats stats; + struct ata_host *host; + + struct device *dev; + void *port_task_data; + + unsigned int hsm_task_state; + + u32 msg_enable; + void *private_data; + unsigned char *pdata; +}; +#endif /* _SATA_DWC_H_ */ diff -purN u-boot-2009.03/include/configs/canyonlands.h u-boot-2009.03-sata/include/configs/canyonlands.h --- u-boot-2009.03/include/configs/canyonlands.h 2009-03-22 06:04:41.000000000 +0900 +++ u-boot-2009.03-sata/include/configs/canyonlands.h 2009-03-25 17:31:40.000000000 +0900 @@ -34,6 +34,7 @@ #ifdef CONFIG_CANYONLANDS #define CONFIG_460EX 1 /* Specific PPC460EX */ #define CONFIG_HOSTNAME canyonlands +#define CONFIG_SATA_DWC /* PPC460EX SATA support */ #else #define CONFIG_460GT 1 /* Specific PPC460GT */ #ifdef CONFIG_GLACIER @@ -454,6 +455,9 @@ #define CONFIG_CMD_SDRAM #define CONFIG_CMD_SNTP #define CONFIG_CMD_USB +#if defined(CONFIG_SATA_DWC) +#define CONFIG_CMD_SCSI +#endif #elif defined(CONFIG_GLACIER) #define CONFIG_CMD_DATE #define CONFIG_CMD_DTT @@ -517,6 +521,18 @@ #endif /* CONFIG_460GT */
/*----------------------------------------------------------------------- + * S-ATA driver setup + *----------------------------------------------------------------------*/ +#ifdef CONFIG_SATA_DWC +#define CONFIG_LIBATA +#define CONFIG_SYS_SCSI_MAX_SCSI_ID 1 /* SCSI ID */ +#define CONFIG_SYS_SCSI_MAX_LUN 1 /* SCSI LUN */ +#define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \ + CONFIG_SYS_SCSI_MAX_LUN) +#define CONFIG_SYS_SCSI_MAXDEVICE CONFIG_SYS_SCSI_MAX_DEVICE +#endif + +/*----------------------------------------------------------------------- * External Bus Controller (EBC) Setup *----------------------------------------------------------------------*/
Regards, Kazuaki Ichinohe

On Wednesday 25 March 2009, Kazuaki Ichinohe wrote:
Hi Stefan,
Thank you for the reply. This is the patch that corrects the point.
Signed-off-by: Kazuaki Ichinohe <kazuichi at fsi.co.jp>
OK, now you added your Signed-off-by line and the patch itself doesn't seem to be line wrapped. But the commit text above is not really describing the patch. Your first version was better.
Please find some more comments below.
[patch] diff -purN u-boot-2009.03/common/cmd_scsi.c u-boot-2009.03-sata/common/cmd_scsi.c --- u-boot-2009.03/common/cmd_scsi.c 2009-03-22 06:04:41.000000000 +0900 +++ u-boot-2009.03-sata/common/cmd_scsi.c 2009-03-25 18:53:29.000000000 +0900 @@ -47,8 +47,10 @@ #define SCSI_DEV_ID 0x5288
#else +#ifndef CONFIG_SATA_DWC #error no scsi device defined #endif +#endif
Why do you add this 460EX SATA support to cmd_scsi.c? Wouldn't cmd_sata.c be a better place? Or did I miss something here?
<snip>
+++ u-boot-2009.03-sata/drivers/block/sata_dwc.c 2009-03-25 18:02:07.000000000 +0900 @@ -0,0 +1,2175 @@ +/*
- sata_dwc.c
- Synopsys DesignWare Cores (DWC) SATA host driver
- Author: Mark Miesfeld mmiesfeld@amcc.com
- Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese sr@denx.de
- Copyright 2008 DENX Software Engineering
- Based on versions provided by AMCC and Synopsys which are:
Copyright 2006 Applied Micro Circuits Corporation
COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED
- This program is free software; you can redistribute
- it and/or modify it under the terms of the GNU
- General Public License as published by the
- Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
- */
As it seems you added the Linux driver version with some changes so that it fits into U-Boot. You should document this in the commit text of this patch.
+#include <common.h> +#include <command.h> +#include <pci.h> +#include <asm/processor.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <malloc.h> +#include <scsi.h> +#include <ata.h> +#include <linux/ctype.h>
+/* sata_dwc.h */ +#include "sata_dwc.h"
+/* Base Address */ +#define SATA_BASE_ADDR 0xe20d1000 +#define SATA_DMA_REG_ADDR 0xe20d0800
These defines should be moved to another (Canyonlands specific) header. It could be that at some time another platform/board will be added using the same DesignWare SATA core but with different addresses.
<snip>
+u8 ata_check_altstatus(struct ata_port *ap) +{
- u8 val = 0;
- val = readb(ap->ioaddr.altstatus_addr);
- return val;
+}
+int check_sata_dev_state(void) +{
- static ccb tempccb; /* temporary scsi command buffer */
- ccb *pccb = (ccb *)&tempccb;
- int ret = 0;
- int i = 0;
- while(1){
Space after "while" please. Please check this file again. Here are multiple places where you don't have a space after the "while" or "if" statement.
udelay (10000); /* 10 ms */
pccb->cmd[0] = SCSI_READ10;
pccb->cmd[1] = 0;
pccb->cmd[2] = 0;
pccb->cmd[3] = 0;
pccb->cmd[4] = 0;
pccb->cmd[5] = 0;
pccb->cmd[6] = 0;
pccb->cmd[7] = 0;
pccb->cmd[8] = 1;
pccb->cmdlen = 10;
pccb->pdata = &temp_data_buf[0]; /* dummy */
pccb->datalen = 512;
/* Send Read Command */
ret = ata_dev_read_sectors(pccb);
/* result TRUE => break */
if(ret == 0){
Here again.
break;
}
And these curly braces are not needed (because of a single line statement). Please remove them,
i++;
if (i > (ATA_RESET_TIME * 100)){
printf("** TimeOUT **\n");
dev_state = SATA_NODEVICE; /* set device status flag */
return FALSE;
}
if ((i >= 100) && ((i%100)==0)) {
printf(".");
}
Again, single line statement.
- }
- /* Set device status flag */
- dev_state = SATA_READY;
- return TRUE;
+}
+void ata_id_string(const u16 *id, unsigned char *s,
unsigned int ofs, unsigned int len)
+{
- unsigned int c;
- while (len > 0) {
c = id[ofs] >> 8;
*s = c;
s++;
c = id[ofs] & 0xff;
*s = c;
s++;
ofs++;
len -= 2;
- }
+}
+static int waiting_for_reg_state(volatile u8 *offset,
int timeout_msec,
u32 sign)
+{
- int i;
- u32 status;
- for (i = 0; i < timeout_msec; i++){
status = readl(offset);
if ( ( status & sign ) != 0 ){
This should be:
if ((status & sign) != 0) {
break;
}
Remove curly braces.
msleep(1);
- }
- return (i < timeout_msec) ? 0 : -1;
+}
+static inline u32 qcmd_tag_to_mask(u8 tag) +{
- return (0x00000001 << (tag & 0x1f));
+}
+static u8 ata_check_status(struct ata_port *ap) +{
- u8 val = 0;
- val = readb(ap->ioaddr.status_addr);
- return val;
+}
+static u8 ata_busy_wait(struct ata_port *ap,
unsigned int bits,unsigned int max)
+{
- u8 status;
- do {
udelay(10);
status = ata_check_status(ap);
max--;
- } while (status != 0xff && (status & bits) && (max > 0));
- return status;
+}
+static u8 ata_wait_idle(struct ata_port *ap) +{
- u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
- return status;
+}
+static int sata_dwc_scsiop_inq(ccb *pccb) +{
- struct ata_device *ata_dev = &ata_device;
- u16 *id;
- /* Set IDENTIFY Data */
- id = ata_dev->id;
- /* make INQUIRY header */
- u8 hdr[] = {
0,
0,
0x5, /* claim SPC-3 version compatibility */
2,
95 - 4
- };
- /* set scsi removeable (RMB) bit per ata bit */
- if (ata_id_removeable(id)){
hdr[1] |= (1 << 7);
- }
Single line statement. Please remove the curly braces. There are most likely further places with this issue. I won't comment on them again. Please check the complete file for it.
- memcpy(pccb->pdata, hdr, sizeof(hdr));
- if (pccb->datalen > 35) {
memcpy(&pccb->pdata[8], "ATA ", 8);
ata_id_string(id, &pccb->pdata[16], ATA_ID_PROD, 16);
ata_id_string(id, &pccb->pdata[32], ATA_ID_FW_REV, 4);
if (pccb->pdata[32] == 0 || pccb->pdata[32] == ' '){
memcpy(&pccb->pdata[32], "n/a ", 4);
}
- }
- if (pccb->datalen > 63) {
const u8 versions[] = {
0x60, /* SAM-3 (no version claimed) */
0x03,
0x20, /* SBC-2 (no version claimed) */
0x02,
0x60 /* SPC-3 (no version claimed) */
};
memcpy(pccb->pdata + 59, versions, sizeof(versions));
- }
- return 0;
+}
+#define ATA_SCSI_PDATA_SET(idx, val) do { \
- if ((idx) < pccb->datalen) pccb->pdata[(idx)] = (u8)(val); \
- } while (0)
+static int sata_dwc_scsiop_read_cap(ccb *pccb) +{
- struct ata_device *ata_dev = &ata_device;
- u32 last_lba;
- last_lba = ata_dev->n_sectors; /* LBA of the last block */
- if (pccb->cmd[0] == SCSI_RD_CAPAC) {
if (last_lba >= 0xffffffffULL){
last_lba = 0xffffffff;
}
/* sector count, 32-bit */
ATA_SCSI_PDATA_SET(0, last_lba >> (8 * 3));
ATA_SCSI_PDATA_SET(1, last_lba >> (8 * 2));
ATA_SCSI_PDATA_SET(2, last_lba >> (8 * 1));
ATA_SCSI_PDATA_SET(3, last_lba);
/* buffer clear */
ATA_SCSI_PDATA_SET(4, 0);
ATA_SCSI_PDATA_SET(5, 0);
/* sector size */
ATA_SCSI_PDATA_SET(6, ATA_SECT_SIZE >> 8);
ATA_SCSI_PDATA_SET(7, ATA_SECT_SIZE & 0xff);
- } else {
/* sector count, 64-bit */
ATA_SCSI_PDATA_SET(0, last_lba >> (8 * 7));
ATA_SCSI_PDATA_SET(1, last_lba >> (8 * 6));
ATA_SCSI_PDATA_SET(2, last_lba >> (8 * 5));
ATA_SCSI_PDATA_SET(3, last_lba >> (8 * 4));
ATA_SCSI_PDATA_SET(4, last_lba >> (8 * 3));
ATA_SCSI_PDATA_SET(5, last_lba >> (8 * 2));
ATA_SCSI_PDATA_SET(6, last_lba >> (8 * 1));
ATA_SCSI_PDATA_SET(7, last_lba);
/* sector size */
ATA_SCSI_PDATA_SET(10, ATA_SECT_SIZE >> 8);
ATA_SCSI_PDATA_SET(11, ATA_SECT_SIZE & 0xff);
- }
- return 0;
+}
+/*
- SCSI TEST UNIT READY command operation.
No operation. Simply returns success to caller, to indicate
that the caller should successfully complete this SCSI command.
- */
+static int sata_dwc_scsiop_test_unit_ready(ccb *pccb) +{
- /* No operation */
- return 0;
+}
+int scsi_exec(ccb *pccb) +{
- int ret;
- /* check device status */
- if(dev_state != SATA_READY){
return FALSE;
- }
- switch (pccb->cmd[0]) {
- case SCSI_READ10:
ret = ata_dev_read_sectors(pccb);
break;
- case SCSI_RD_CAPAC:
ret = sata_dwc_scsiop_read_cap(pccb);
break;
- case SCSI_TST_U_RDY:
ret = sata_dwc_scsiop_test_unit_ready(pccb);
break;
- case SCSI_INQUIRY:
ret = sata_dwc_scsiop_inq(pccb);
break;
- default:
printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]);
return FALSE;
- }
- if (ret) {
debug("SCSI command 0x%02x ret errno %d\n", pccb->cmd[0], ret);
return FALSE;
- }
- return TRUE;
+}
+static const struct ata_port_info sata_dwc_port_info[] = {
- {
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING |
ATA_FLAG_SRST | ATA_FLAG_NCQ,
.pio_mask = 0x1f, /* pio 0-4 */
.mwdma_mask = 0x07,
.udma_mask = 0x7f,
- },
+};
+int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
unsigned int flags, u16 *id)
+{
- struct ata_port *ap = pap;
- unsigned int class = *p_class;
- struct ata_taskfile tf;
- unsigned int err_mask = 0;
- const char *reason;
- int may_fallback = 1, tried_spinup = 0;
- u8 status;
- int rc;
- /* cheack BSY = 0 */
- status = ata_busy_wait(ap, ATA_BUSY, 30000);
- if (status & ATA_BUSY) {
printf("BSY = 0 check. timeout.\n");
rc = FALSE;
return rc;
- }
ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
+retry:
- memset(&tf, 0, sizeof(tf));
- ap->print_id = 1;
- ap->flags &= ~ATA_FLAG_DISABLED;
- tf.ctl = ap->ctl; /* 0x08 */
- tf.device = ATA_DEVICE_OBS;
- tf.command = ATA_CMD_ID_ATA;
- tf.protocol = ATA_PROT_PIO;
- /* Some devices choke if TF registers contain garbage. Make
* sure those are properly initialized.
*/
- tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
- /* Device presence detection is unreliable on some
* controllers. Always poll IDENTIFY if available.
*/
- tf.flags |= ATA_TFLAG_POLLING;
- temp_n_block = 1;
- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
sizeof(id[0]) * ATA_ID_WORDS, 0);
- if (err_mask) {
if (err_mask & AC_ERR_NODEV_HINT) {
printf("NODEV after polling detection\n");
return -ENOENT;
}
if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) {
/* Device or controller might have reported
* the wrong device class. Give a shot at the
* other IDENTIFY if the current one is
* aborted by the device.
*/
if (may_fallback) {
may_fallback = 0;
if (class == ATA_DEV_ATA) {
class = ATA_DEV_ATAPI;
} else {
class = ATA_DEV_ATA;
}
goto retry;
}
/* Control reaches here iff the device aborted
* both flavors of IDENTIFYs which happens
* sometimes with phantom devices.
*/
printf("both IDENTIFYs aborted, assuming NODEV\n");
return -ENOENT;
}
rc = -EIO;
reason = "I/O error";
goto err_out;
- }
- /* Falling back doesn't make sense if ID data was read
* successfully at least once.
*/
- may_fallback = 0;
+#ifdef __BIG_ENDIAN
- unsigned int id_cnt;
- for (id_cnt = 0; id_cnt < ATA_ID_WORDS; id_cnt++)
id[id_cnt] = le16_to_cpu(id[id_cnt]);
+#endif /* __BIG_ENDIAN */
And what happens if the platform is little-endian? Doesn't the le16_to_cpu() function handle the conversion? I think you can remove the #ifdef and use this code unconditionally.
<big snip>
u-boot-2009.03/drivers/block/sata_dwc.h 1970-01-01 09:00:00.000000000 +0900 +++ u-boot-2009.03-sata/drivers/block/sata_dwc.h 2009-03-25 17:27:01.000000000 +0900 @@ -0,0 +1,496 @@ +/*
- sata_dwc.h
- Synopsys DesignWare Cores (DWC) SATA host driver
- Author: Mark Miesfeld mmiesfeld@amcc.com
- Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese sr@denx.de
- Copyright 2008 DENX Software Engineering
- Based on versions provided by AMCC and Synopsys which are:
Copyright 2006 Applied Micro Circuits Corporation
COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED
- This program is free software; you can redistribute
- it and/or modify it under the terms of the GNU
- General Public License as published by the
- Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
- */
+#ifndef _SATA_DWC_H_ +#define _SATA_DWC_H_
+#define HZ 100
+#define READ 0 +#define WRITE 1
+static int ata_id_has_hipm(const u16 *id) +{
- u16 val = id[76];
- if (val == 0 || val == 0xffff)
return -1;
- return val & (1 << 9);
+}
Don't add code to header. Only inline functions should be added here. So either add "inline" or move it to a ".c" file.
+static int ata_id_has_dipm(const u16 *id) +{
- u16 val = id[78];
- if (val == 0 || val == 0xffff)
return -1;
- return val & (1 << 3);
+}
Same here.
<snip>
u-boot-2009.03/include/configs/canyonlands.h 2009-03-22 06:04:41.000000000 +0900 +++ u-boot-2009.03-sata/include/configs/canyonlands.h 2009-03-25 17:31:40.000000000 +0900 @@ -34,6 +34,7 @@ #ifdef CONFIG_CANYONLANDS #define CONFIG_460EX 1 /* Specific PPC460EX */ #define CONFIG_HOSTNAME canyonlands +#define CONFIG_SATA_DWC /* PPC460EX SATA support */
Not sure if we really should enable this per default on the Canyonlands platform. What's the size impact of this SATA support?
#else #define CONFIG_460GT 1 /* Specific PPC460GT */ #ifdef CONFIG_GLACIER @@ -454,6 +455,9 @@ #define CONFIG_CMD_SDRAM #define CONFIG_CMD_SNTP #define CONFIG_CMD_USB +#if defined(CONFIG_SATA_DWC) +#define CONFIG_CMD_SCSI +#endif
Again, I think this should go into CMD_SATA instead of SCSI.
Thanks.
Best regards, Stefan
===================================================================== DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de =====================================================================

Hi Stefan,
Thank you for the reply. My answer is described in the beginning.
Hi Stefan,
Thank you for the reply. This is the patch that corrects the point.
Signed-off-by: Kazuaki Ichinohe <kazuichi at fsi.co.jp>
OK, now you added your Signed-off-by line and the patch itself doesn't seem to be line wrapped. But the commit text above is not really describing the patch. Your first version was better.
It will take care next time.
[patch] diff -purN u-boot-2009.03/common/cmd_scsi.c u-boot-2009.03-sata/common/cmd_scsi.c --- u-boot-2009.03/common/cmd_scsi.c 2009-03-22 06:04:41.000000000 +0900 +++ u-boot-2009.03-sata/common/cmd_scsi.c 2009-03-25 18:53:29.000000000 +0900 @@ -47,8 +47,10 @@ #define SCSI_DEV_ID 0x5288
#else +#ifndef CONFIG_SATA_DWC #error no scsi device defined #endif +#endif
Why do you add this 460EX SATA support to cmd_scsi.c? Wouldn't cmd_sata.c be a better place? Or did I miss something here?
The cmd_scsi.c which define CONFIG_CMD_SCSI are modified because I want to use scsiboot command of U-BOOT.
+++ u-boot-2009.03-sata/drivers/block/sata_dwc.c 2009-03-25 18:02:07.000000000 +0900 @@ -0,0 +1,2175 @@ +/*
- sata_dwc.c
- Synopsys DesignWare Cores (DWC) SATA host driver
- Author: Mark Miesfeld <mmiesfeld at amcc.com>
- Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese <sr at denx.de>
- Copyright 2008 DENX Software Engineering
- Based on versions provided by AMCC and Synopsys which are:
Copyright 2006 Applied Micro Circuits Corporation
COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED
- This program is free software; you can redistribute
- it and/or modify it under the terms of the GNU
- General Public License as published by the
- Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
- */
As it seems you added the Linux driver version with some changes so that it fits into U-Boot. You should document this in the commit text of this patch.
I corrected.
+#include <common.h> +#include <command.h> +#include <pci.h> +#include <asm/processor.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <malloc.h> +#include <scsi.h> +#include <ata.h> +#include <linux/ctype.h>
+/* sata_dwc.h */ +#include "sata_dwc.h"
+/* Base Address */ +#define SATA_BASE_ADDR 0xe20d1000 +#define SATA_DMA_REG_ADDR 0xe20d0800
These defines should be moved to another (Canyonlands specific) header. It could be that at some time another platform/board will be added using the same DesignWare SATA core but with different addresses.
I corrected.
+u8 ata_check_altstatus(struct ata_port *ap) +{
- u8 val = 0;
- val = readb(ap->ioaddr.altstatus_addr);
- return val;
+}
+int check_sata_dev_state(void) +{
- static ccb tempccb; /* temporary scsi command buffer */
- ccb *pccb = (ccb *)&tempccb;
- int ret = 0;
- int i = 0;
- while(1){
Space after "while" please. Please check this file again. Here are multiple places where you don't have a space after the "while" or "if" statement.
I corrected.
udelay (10000); /* 10 ms */>
pccb->cmd[0] = SCSI_READ10;
pccb->cmd[1] = 0;
pccb->cmd[2] = 0;
pccb->cmd[3] = 0;
pccb->cmd[4] = 0;
pccb->cmd[5] = 0;
pccb->cmd[6] = 0;
pccb->cmd[7] = 0;
pccb->cmd[8] = 1;
pccb->cmdlen = 10;
pccb->pdata = &temp_data_buf[0]; /* dummy */
pccb->datalen = 512;
/* Send Read Command */
ret = ata_dev_read_sectors(pccb);
/* result TRUE => break */
if(ret == 0){
Here again.
break;
}
And these curly braces are not needed (because of a single line statement). Please remove them,
I corrected.
- }
- /* Set device status flag */
- dev_state = SATA_READY;
- return TRUE;
+}
+void ata_id_string(const u16 *id, unsigned char *s,
unsigned int ofs, unsigned int len)
+{
- unsigned int c;
- while (len > 0) {
c = id[ofs] >> 8;
*s = c;
s++;
c = id[ofs] & 0xff;
*s = c;
s++;
ofs++;
len -= 2;
- }
+}
+static int waiting_for_reg_state(volatile u8 *offset,
int timeout_msec,
u32 sign)
+{
- int i;
- u32 status;
- for (i = 0; i < timeout_msec; i++){
status = readl(offset);
if ( ( status & sign ) != 0 ){
This should be:
if ((status & sign) != 0) {
I corrected.
- /* Falling back doesn't make sense if ID data was read
* successfully at least once.
*/
- may_fallback = 0;
+#ifdef __BIG_ENDIAN
- unsigned int id_cnt;
- for (id_cnt = 0; id_cnt < ATA_ID_WORDS; id_cnt++)
id[id_cnt] = le16_to_cpu(id[id_cnt]);
+#endif /* __BIG_ENDIAN */
And what happens if the platform is little-endian? Doesn't the le16_to_cpu() function handle the conversion? I think you can remove the #ifdef and use this code unconditionally.
I corrected.
u-boot-2009.03/drivers/block/sata_dwc.h 1970-01-01 09:00:00.000000000 +0900 +++ u-boot-2009.03-sata/drivers/block/sata_dwc.h 2009-03-25 17:27:01.000000000 +0900 @@ -0,0 +1,496 @@ +/*
- sata_dwc.h
- Synopsys DesignWare Cores (DWC) SATA host driver
- Author: Mark Miesfeld <mmiesfeld at amcc.com>
- Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese <sr at denx.de>
- Copyright 2008 DENX Software Engineering
- Based on versions provided by AMCC and Synopsys which are:
Copyright 2006 Applied Micro Circuits Corporation
COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED
- This program is free software; you can redistribute
- it and/or modify it under the terms of the GNU
- General Public License as published by the
- Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
- */
+#ifndef _SATA_DWC_H_ +#define _SATA_DWC_H_
+#define HZ 100
+#define READ 0 +#define WRITE 1
+static int ata_id_has_hipm(const u16 *id) +{
- u16 val = id[76];
- if (val == 0 || val == 0xffff)
return -1;
- return val & (1 << 9);
+}
Don't add code to header. Only inline functions should be added here. So either add "inline" or move it to a ".c" file.
I corrected.
u-boot-2009.03/include/configs/canyonlands.h 2009-03-22 06:04:41.000000000 +0900 +++ u-boot-2009.03-sata/include/configs/canyonlands.h 2009-03-25 17:31:40.000000000 +0900 @@ -34,6 +34,7 @@ #ifdef CONFIG_CANYONLANDS #define CONFIG_460EX 1 /* Specific PPC460EX */ #define CONFIG_HOSTNAME canyonlands +#define CONFIG_SATA_DWC /* PPC460EX SATA support */
Not sure if we really should enable this per default on the Canyonlands platform. What's the size impact of this SATA support?
I excluded the above patch.
------------------------------------------ The confirmed patch is sent again.
This patch adds a SATA harddisk driver for the canyonlands. Signed-off-by: Kazuaki Ichinohe <kazuichi at fsi.co.jp> ---
[patch] diff -purN u-boot-2009.03/common/cmd_scsi.c u-boot-2009.03-sata/common/cmd_scsi.c --- u-boot-2009.03/common/cmd_scsi.c 2009-03-22 06:04:41.000000000 +0900 +++ u-boot-2009.03-sata/common/cmd_scsi.c 2009-03-25 18:53:29.000000000 +0900 @@ -47,8 +47,10 @@ #define SCSI_DEV_ID 0x5288
#else +#ifndef CONFIG_SATA_DWC #error no scsi device defined #endif +#endif
static ccb tempccb; /* temporary scsi command buffer */ @@ -179,6 +181,7 @@ void scsi_init(void) { int busdevfunc;
+#ifndef CONFIG_SATA_DWC busdevfunc=pci_find_device(SCSI_VEND_ID,SCSI_DEV_ID,0); /* get PCI Device ID */ if(busdevfunc==-1) { printf("Error SCSI Controller (%04X,%04X) not found\n",SCSI_VEND_ID,SCSI_DEV_ID); @@ -189,7 +192,13 @@ void scsi_init(void) printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n",SCSI_VEND_ID,SCSI_DEV_ID,(busdevfunc>>16)&0xFF,(busdevfunc>>11)&0x1F,(busdevfunc>>8)&0x7); } #endif +#endif +#ifdef CONFIG_SATA_DWC + sata_dwc_probe(); +#endif +#ifndef CONFIG_SATA_DWC scsi_low_level_init(busdevfunc); +#endif scsi_scan(1); }
@@ -444,8 +453,11 @@ int do_scsi (cmd_tbl_t *cmdtp, int flag, /**************************************************************************************** * scsi_read */ - +#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) +#define SCSI_MAX_READ_BLK 0xFF +#else #define SCSI_MAX_READ_BLK 0xFFFF /* almost the maximum amount of the scsi_ext command.. */ +#endif
ulong scsi_read(int device, ulong blknr, ulong blkcnt, void *buffer) { diff -purN u-boot-2009.03/drivers/block/Makefile u-boot-2009.03-sata/drivers/block/Makefile --- u-boot-2009.03/drivers/block/Makefile 2009-03-22 06:04:41.000000000 +0900 +++ u-boot-2009.03-sata/drivers/block/Makefile 2009-03-23 19:22:31.000000000 +0900 @@ -34,6 +34,7 @@ COBJS-$(CONFIG_SATA_SIL3114) += sata_sil COBJS-$(CONFIG_IDE_SIL680) += sil680.o COBJS-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o COBJS-$(CONFIG_SYSTEMACE) += systemace.o +COBJS-$(CONFIG_SATA_DWC) += sata_dwc.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff -purN u-boot-2009.03/drivers/block/sata_dwc.c u-boot-2009.03-sata/drivers/block/sata_dwc.c --- u-boot-2009.03/drivers/block/sata_dwc.c 1970-01-01 09:00:00.000000000 +0900 +++ u-boot-2009.03-sata/drivers/block/sata_dwc.c 2009-03-26 18:39:31.000000000 +0900 @@ -0,0 +1,2163 @@ +/* + * sata_dwc.c + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld mmiesfeld@amcc.com + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese sr@denx.de + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * This program is free software; you can redistribute + * it and/or modify it under the terms of the GNU + * General Public License as published by the + * Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + */ +/* + * SATA support based on the chip canyonlands. + * + * 03-26-2009 + * The local version of this driver for the canyonlands board + * does not use interrupts but polls the chip instead. + */ + + +#include <common.h> +#include <command.h> +#include <pci.h> +#include <asm/processor.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <malloc.h> +#include <scsi.h> +#include <ata.h> +#include <linux/ctype.h> + +/* sata_dwc.h */ +#include "sata_dwc.h" + +/* SATA DMA driver Globals */ +#define DMA_NUM_CHANS 1 +#define DMA_NUM_CHAN_REGS 8 + +/* SATA DMA Register definitions */ +#define AHB_DMA_BRST_DFLT 16 /* 4 data items burst length */ + +struct dmareg { + u32 low; /* Low bits 0-31 */ + u32 high; /* High bits 32-63 */ +}; + +/* DMA Per Channel registers */ +struct dma_chan_regs { + struct dmareg sar; /* Source Address */ + struct dmareg dar; /* Destination address */ + struct dmareg llp; /* Linked List Pointer */ + struct dmareg ctl; /* Control */ + struct dmareg sstat; /* Source Status not implemented in core */ + struct dmareg dstat; /* Destination Status not implemented in core */ + struct dmareg sstatar; /* Source Status Address not impl in core */ + struct dmareg dstatar; /* Destination Status Address not implemented */ + struct dmareg cfg; /* Config */ + struct dmareg sgr; /* Source Gather */ + struct dmareg dsr; /* Destination Scatter */ +}; + +/* Generic Interrupt Registers */ +struct dma_interrupt_regs { + struct dmareg tfr; /* Transfer Interrupt */ + struct dmareg block; /* Block Interrupt */ + struct dmareg srctran; /* Source Transfer Interrupt */ + struct dmareg dsttran; /* Dest Transfer Interrupt */ + struct dmareg error; /* Error */ +}; + +struct ahb_dma_regs { + struct dma_chan_regs chan_regs[DMA_NUM_CHAN_REGS]; + struct dma_interrupt_regs interrupt_raw; /* Raw Interrupt */ + struct dma_interrupt_regs interrupt_status; /* Interrupt Status */ + struct dma_interrupt_regs interrupt_mask; /* Interrupt Mask */ + struct dma_interrupt_regs interrupt_clear; /* Interrupt Clear */ + struct dmareg statusInt; /* Interrupt combined */ + struct dmareg rq_srcreg; /* Src Trans Req */ + struct dmareg rq_dstreg; /* Dst Trans Req */ + struct dmareg rq_sgl_srcreg; /* Sngl Src Trans Req */ + struct dmareg rq_sgl_dstreg; /* Sngl Dst Trans Req */ + struct dmareg rq_lst_srcreg; /* Last Src Trans Req */ + struct dmareg rq_lst_dstreg; /* Last Dst Trans Req */ + struct dmareg dma_cfg; /* DMA Config */ + struct dmareg dma_chan_en; /* DMA Channel Enable */ + struct dmareg dma_id; /* DMA ID */ + struct dmareg dma_test; /* DMA Test */ + struct dmareg res1; /* reserved */ + struct dmareg res2; /* reserved */ + /* DMA Comp Params + * Param 6 = dma_param[0], Param 5 = dma_param[1], + * Param 4 = dma_param[2] ... + */ + struct dmareg dma_params[6]; +}; + +/* DMA Register Operation Bits */ +#define DMA_EN 0x00000001 /* Enable AHB DMA */ +#define DMA_CHANNEL(ch) (0x00000001 << (ch)) /* Select channel */ +#define DMA_ENABLE_CHAN(ch) ((0x00000001 << (ch)) | \ + ((0x000000001 << (ch)) << 8)) /* Enable channel */ +#define DMA_DISABLE_CHAN(ch) (0x00000000 | \ + ((0x000000001 << (ch)) << 8)) /* Disable channel */ + +#define SATA_DWC_MAX_PORTS 1 +#define SATA_DWC_SCR_OFFSET 0x24 +#define SATA_DWC_REG_OFFSET 0x64 + +/* DWC SATA Registers */ +struct sata_dwc_regs { + u32 fptagr; /* 1st party DMA tag */ + u32 fpbor; /* 1st party DMA buffer offset */ + u32 fptcr; /* 1st party DMA Xfr count */ + u32 dmacr; /* DMA Control */ + u32 dbtsr; /* DMA Burst Transac size */ + u32 intpr; /* Interrupt Pending */ + u32 intmr; /* Interrupt Mask */ + u32 errmr; /* Error Mask */ + u32 llcr; /* Link Layer Control */ + u32 phycr; /* PHY Control */ + u32 physr; /* PHY Status */ + u32 rxbistpd; /* Recvd BIST pattern def register */ + u32 rxbistpd1; /* Recvd BIST data dword1 */ + u32 rxbistpd2; /* Recvd BIST pattern data dword2 */ + u32 txbistpd; /* Trans BIST pattern def register */ + u32 txbistpd1; /* Trans BIST data dword1 */ + u32 txbistpd2; /* Trans BIST data dword2 */ + u32 bistcr; /* BIST Control Register */ + u32 bistfctr; /* BIST FIS Count Register */ + u32 bistsr; /* BIST Status Register */ + u32 bistdecr; /* BIST Dword Error count register */ + u32 res[15]; /* Reserved locations */ + u32 testr; /* Test Register */ + u32 versionr; /* Version Register */ + u32 idr; /* ID Register */ + u32 unimpl[192]; /* Unimplemented */ + u32 dmadr[256]; /* FIFO Locations in DMA Mode */ +}; + +/* DWC SATA Register Operations */ +#define SATA_DWC_TXFIFO_DEPTH 0x01FF +#define SATA_DWC_RXFIFO_DEPTH 0x01FF + +#define SATA_DWC_DBTSR_MWR(size) ((size/4) & SATA_DWC_TXFIFO_DEPTH) +#define SATA_DWC_DBTSR_MRD(size) (((size/4) & \ + SATA_DWC_RXFIFO_DEPTH) << 16) +#define SATA_DWC_INTPR_DMAT 0x00000001 +#define SATA_DWC_INTPR_NEWFP 0x00000002 +#define SATA_DWC_INTPR_PMABRT 0x00000004 +#define SATA_DWC_INTPR_ERR 0x00000008 +#define SATA_DWC_INTPR_NEWBIST 0x00000010 +#define SATA_DWC_INTPR_IPF 0x10000000 +#define SATA_DWC_INTMR_DMATM 0x00000001 +#define SATA_DWC_INTMR_NEWFPM 0x00000002 +#define SATA_DWC_INTMR_PMABRTM 0x00000004 +#define SATA_DWC_INTMR_ERRM 0x00000008 +#define SATA_DWC_INTMR_NEWBISTM 0x00000010 + +#define SATA_DWC_DMACR_TMOD_TXCHEN 0x00000004 +#define SATA_DWC_DMACR_TXRXCH_CLEAR SATA_DWC_DMACR_TMOD_TXCHEN + +#define SATA_DWC_QCMD_MAX 32 + +/* This is all error bits, zero's are reserved fields. */ +#define SATA_DWC_SERROR_ERR_BITS 0x0FFF0F03 + +/* + * Commonly used DWC SATA driver Macros + */ +#define HSDEVP_FROM_AP(ap) (struct sata_dwc_device_port*) \ + (ap)->private_data + +struct sata_dwc_device { + struct device *dev; /* generic device struct */ + struct ata_probe_ent *pe; /* ptr to probe-ent */ + struct ata_host *host; + u8 *reg_base; + struct sata_dwc_regs *sata_dwc_regs; /* DW Synopsys SATA specific */ + int irq_dma; +}; + +struct sata_dwc_device_port { + struct sata_dwc_device *hsdev; + int cmd_issued[SATA_DWC_QCMD_MAX]; + u32 dma_chan[SATA_DWC_QCMD_MAX]; + int dma_pending[SATA_DWC_QCMD_MAX]; +}; + +enum { + SATA_DWC_CMD_ISSUED_NOT = 0, + SATA_DWC_CMD_ISSUED_PEND = 1, + SATA_DWC_CMD_ISSUED_EXEC = 2, + SATA_DWC_CMD_ISSUED_NODATA = 3, + + SATA_DWC_DMA_PENDING_NONE = 0, + SATA_DWC_DMA_PENDING_TX = 1, + SATA_DWC_DMA_PENDING_RX = 2, +}; + +/* delay Macros */ +#define msleep(a) udelay(a * 1000) +#define ssleep(a) msleep(a * 1000) + +static int ata_probe_timeout = (ATA_TMOUT_INTERNAL / 100); + +enum sata_dev_state { + SATA_INIT = 0, + SATA_READY = 1, + SATA_NODEVICE = 2, + SATA_ERROR = 3, +}; +enum sata_dev_state dev_state = SATA_INIT; + +/* + * Globals + */ +static struct ahb_dma_regs *sata_dma_regs = 0; +static struct ata_host *phost; +static struct ata_port ap; +static struct ata_port *pap = ≈ +static struct ata_device ata_device; +static struct sata_dwc_device_port dwc_devp; + +static void *scr_addr_sstatus; +static char temp_data_buf[512]; +static u32 temp_n_block = 0; + +/* + * Prototype + */ +unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, unsigned int buflen, + unsigned long timeout); +unsigned int ata_dev_set_feature(struct ata_device *dev, + u8 enable,u8 feature); +unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors); +void clear_serror(void); +u8 ata_irq_on(struct ata_port *ap); +struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, + unsigned int tag); +int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq); +void ata_tf_to_host(struct ata_port *ap,const struct ata_taskfile *tf); +unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc); +void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf); +unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc); +u8 ata_check_altstatus(struct ata_port *ap); +static u8 ata_check_status(struct ata_port *ap); +void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep); +void ata_qc_issue(struct ata_queued_cmd *qc); +void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf); +int ata_dev_read_sectors(ccb *pccb); +void ata_std_dev_select(struct ata_port *ap, unsigned int device); +void ata_qc_complete(struct ata_queued_cmd *qc); +void __ata_qc_complete(struct ata_queued_cmd *qc); +void fill_result_tf(struct ata_queued_cmd *qc); +void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); +void ata_mmio_data_xfer(struct ata_device *dev, + unsigned char *buf,unsigned int buflen); +void ata_pio_task(struct ata_port *arg_ap); +void __ata_port_freeze(struct ata_port *ap); +int ata_port_freeze(struct ata_port *ap); +void ata_qc_free(struct ata_queued_cmd *qc); +void ata_pio_sectors(struct ata_queued_cmd *qc); +void ata_pio_sector(struct ata_queued_cmd *qc); +void ata_pio_queue_task(struct ata_port *ap, + void *data,unsigned long delay); +void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq); +int sata_dwc_softreset(struct ata_port *ap); +void sata_dwc_probe(void); + +static int ata_id_has_hipm(const u16 *id) +{ + u16 val = id[76]; + + if (val == 0 || val == 0xffff) + return -1; + + return val & (1 << 9); +} + +static int ata_id_has_dipm(const u16 *id) +{ + u16 val = id[78]; + + if (val == 0 || val == 0xffff) + return -1; + + return val & (1 << 3); +} + +u8 ata_check_altstatus(struct ata_port *ap) +{ + u8 val = 0; + val = readb(ap->ioaddr.altstatus_addr); + return val; +} + +int check_sata_dev_state(void) +{ + static ccb tempccb; /* temporary scsi command buffer */ + ccb *pccb = (ccb *)&tempccb; + int ret = 0; + int i = 0; + + while (1) { + udelay (10000); /* 10 ms */ + + pccb->cmd[0] = SCSI_READ10; + pccb->cmd[1] = 0; + pccb->cmd[2] = 0; + pccb->cmd[3] = 0; + pccb->cmd[4] = 0; + pccb->cmd[5] = 0; + pccb->cmd[6] = 0; + pccb->cmd[7] = 0; + pccb->cmd[8] = 1; + pccb->cmdlen = 10; + pccb->pdata = &temp_data_buf[0]; /* dummy */ + pccb->datalen = 512; + + /* Send Read Command */ + ret = ata_dev_read_sectors(pccb); + + /* result TRUE => break */ + if (ret == 0) + break; + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + dev_state = SATA_NODEVICE; /* set device status flag */ + return FALSE; + } + + if ((i >= 100) && ((i%100)==0)) + printf("."); + } + + /* Set device status flag */ + dev_state = SATA_READY; + + return TRUE; +} + +void ata_id_string(const u16 *id, unsigned char *s, + unsigned int ofs, unsigned int len) +{ + unsigned int c; + + while (len > 0) { + c = id[ofs] >> 8; + *s = c; + s++; + + c = id[ofs] & 0xff; + *s = c; + s++; + + ofs++; + len -= 2; + } +} + +static int waiting_for_reg_state(volatile u8 *offset, + int timeout_msec, + u32 sign) +{ + int i; + u32 status; + + for (i = 0; i < timeout_msec; i++) { + status = readl(offset); + if ((status & sign) != 0) + break; + msleep(1); + } + + return (i < timeout_msec) ? 0 : -1; +} + +static inline u32 qcmd_tag_to_mask(u8 tag) +{ + return (0x00000001 << (tag & 0x1f)); +} + +static u8 ata_check_status(struct ata_port *ap) +{ + u8 val = 0; + val = readb(ap->ioaddr.status_addr); + return val; +} + +static u8 ata_busy_wait(struct ata_port *ap, + unsigned int bits,unsigned int max) +{ + u8 status; + + do { + udelay(10); + status = ata_check_status(ap); + max--; + } while (status != 0xff && (status & bits) && (max > 0)); + + return status; +} + +static u8 ata_wait_idle(struct ata_port *ap) +{ + u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + return status; +} + +static int sata_dwc_scsiop_inq(ccb *pccb) +{ + struct ata_device *ata_dev = &ata_device; + u16 *id; + + /* Set IDENTIFY Data */ + id = ata_dev->id; + + /* make INQUIRY header */ + u8 hdr[] = { + 0, + 0, + 0x5, /* claim SPC-3 version compatibility */ + 2, + 95 - 4 + }; + + /* set scsi removeable (RMB) bit per ata bit */ + if (ata_id_removeable(id)) + hdr[1] |= (1 << 7); + + memcpy(pccb->pdata, hdr, sizeof(hdr)); + + if (pccb->datalen > 35) { + memcpy(&pccb->pdata[8], "ATA ", 8); + ata_id_string(id, &pccb->pdata[16], ATA_ID_PROD, 16); + ata_id_string(id, &pccb->pdata[32], ATA_ID_FW_REV, 4); + if (pccb->pdata[32] == 0 || pccb->pdata[32] == ' ') + memcpy(&pccb->pdata[32], "n/a ", 4); + } + + if (pccb->datalen > 63) { + const u8 versions[] = { + 0x60, /* SAM-3 (no version claimed) */ + 0x03, + 0x20, /* SBC-2 (no version claimed) */ + 0x02, + 0x60 /* SPC-3 (no version claimed) */ + }; + memcpy(pccb->pdata + 59, versions, sizeof(versions)); + } + + return 0; +} + +#define ATA_SCSI_PDATA_SET(idx, val) do { \ + if ((idx) < pccb->datalen) pccb->pdata[(idx)] = (u8)(val); \ + } while (0) + +static int sata_dwc_scsiop_read_cap(ccb *pccb) +{ + struct ata_device *ata_dev = &ata_device; + u32 last_lba; + last_lba = ata_dev->n_sectors; /* LBA of the last block */ + + if (pccb->cmd[0] == SCSI_RD_CAPAC) { + if (last_lba >= 0xffffffffULL) + last_lba = 0xffffffff; + + /* sector count, 32-bit */ + ATA_SCSI_PDATA_SET(0, last_lba >> (8 * 3)); + ATA_SCSI_PDATA_SET(1, last_lba >> (8 * 2)); + ATA_SCSI_PDATA_SET(2, last_lba >> (8 * 1)); + ATA_SCSI_PDATA_SET(3, last_lba); + + /* buffer clear */ + ATA_SCSI_PDATA_SET(4, 0); + ATA_SCSI_PDATA_SET(5, 0); + + /* sector size */ + ATA_SCSI_PDATA_SET(6, ATA_SECT_SIZE >> 8); + ATA_SCSI_PDATA_SET(7, ATA_SECT_SIZE & 0xff); + + } else { + /* sector count, 64-bit */ + ATA_SCSI_PDATA_SET(0, last_lba >> (8 * 7)); + ATA_SCSI_PDATA_SET(1, last_lba >> (8 * 6)); + ATA_SCSI_PDATA_SET(2, last_lba >> (8 * 5)); + ATA_SCSI_PDATA_SET(3, last_lba >> (8 * 4)); + ATA_SCSI_PDATA_SET(4, last_lba >> (8 * 3)); + ATA_SCSI_PDATA_SET(5, last_lba >> (8 * 2)); + ATA_SCSI_PDATA_SET(6, last_lba >> (8 * 1)); + ATA_SCSI_PDATA_SET(7, last_lba); + + /* sector size */ + ATA_SCSI_PDATA_SET(10, ATA_SECT_SIZE >> 8); + ATA_SCSI_PDATA_SET(11, ATA_SECT_SIZE & 0xff); + } + + return 0; +} + +/* + * SCSI TEST UNIT READY command operation. + * No operation. Simply returns success to caller, to indicate + * that the caller should successfully complete this SCSI command. + */ +static int sata_dwc_scsiop_test_unit_ready(ccb *pccb) +{ + /* No operation */ + return 0; +} + +int scsi_exec(ccb *pccb) +{ + int ret; + + /* check device status */ + if (dev_state != SATA_READY) + return FALSE; + + switch (pccb->cmd[0]) { + case SCSI_READ10: + ret = ata_dev_read_sectors(pccb); + break; + case SCSI_RD_CAPAC: + ret = sata_dwc_scsiop_read_cap(pccb); + break; + case SCSI_TST_U_RDY: + ret = sata_dwc_scsiop_test_unit_ready(pccb); + break; + case SCSI_INQUIRY: + ret = sata_dwc_scsiop_inq(pccb); + break; + default: + printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]); + return FALSE; + } + + if (ret) { + debug("SCSI command 0x%02x ret errno %d\n", pccb->cmd[0], ret); + return FALSE; + } + return TRUE; +} + +static const struct ata_port_info sata_dwc_port_info[] = { + { + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING | + ATA_FLAG_SRST | ATA_FLAG_NCQ, + .pio_mask = 0x1f, /* pio 0-4 */ + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + }, +}; + +int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, + unsigned int flags, u16 *id) +{ + struct ata_port *ap = pap; + unsigned int class = *p_class; + struct ata_taskfile tf; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1, tried_spinup = 0; + u8 status; + int rc; + + /* cheack BSY = 0 */ + status = ata_busy_wait(ap, ATA_BUSY, 30000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + rc = FALSE; + return rc; + } + + ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */ + +retry: + memset(&tf, 0, sizeof(tf)); + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + tf.ctl = ap->ctl; /* 0x08 */ + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_ID_ATA; + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + + /* Device presence detection is unreliable on some + * controllers. Always poll IDENTIFY if available. + */ + tf.flags |= ATA_TFLAG_POLLING; + + temp_n_block = 1; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, + sizeof(id[0]) * ATA_ID_WORDS, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + unsigned int id_cnt; + + for (id_cnt = 0; id_cnt < ATA_ID_WORDS; id_cnt++) + id[id_cnt] = le16_to_cpu(id[id_cnt]); + + + /* sanity check */ + rc = -EINVAL; + reason = "device reports invalid type"; + + if (class == ATA_DEV_ATA) { + if (!ata_id_is_ata(id) && !ata_id_is_cfa(id)) + goto err_out; + } else { + if (ata_id_is_ata(id)) + goto err_out; + } + if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) { + tried_spinup = 1; + /* + * Drive powered-up in standby mode, and requires a specific + * SET_FEATURES spin-up subcommand before it will accept + * anything other than the original IDENTIFY command. + */ + err_mask = ata_dev_set_feature(dev, SETFEATURES_SPINUP, 0); + if (err_mask && id[2] != 0x738c) { + rc = -EIO; + reason = "SPINUP failed"; + goto err_out; + } + /* + * If the drive initially returned incomplete IDENTIFY info, + * we now must reissue the IDENTIFY command. + */ + if (id[2] == 0x37c8) + goto retry; + } + + if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) { + /* + * The exact sequence expected by certain pre-ATA4 drives is: + * SRST RESET + * IDENTIFY (optional in early ATA) + * INITIALIZE DEVICE PARAMETERS (later IDE and ATA) + * anything else.. + * Some drives were very specific about that exact sequence. + * + * Note that ATA4 says lba is mandatory so the second check + * shoud never trigger. + */ + if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { + err_mask = ata_dev_init_params(dev, id[3], id[6]); + if (err_mask) { + rc = -EIO; + reason = "INIT_DEV_PARAMS failed"; + goto err_out; + } + + /* current CHS translation info (id[53-58]) might be + * changed. reread the identify device info. + */ + flags &= ~ATA_READID_POSTRESET; + goto retry; + } + } + + *p_class = class; + return 0; + +err_out: + return rc; +} + +void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep) +{ + if (wait) + ata_wait_idle(ap); + + ata_std_dev_select(ap, device); + + if (wait) + ata_wait_idle(ap); +} + +void ata_std_dev_select(struct ata_port *ap, unsigned int device) +{ + u8 tmp; + + if (device == 0) { + tmp = ATA_DEVICE_OBS; + } else { + tmp = ATA_DEVICE_OBS | ATA_DEV1; + } + + writeb(tmp, ap->ioaddr.device_addr); + + /* needed; also flushes, for mmio */ + readb(ap->ioaddr.altstatus_addr); + + /* need delay 400nsec over */ + udelay(1); +} + +void ata_qc_reinit(struct ata_queued_cmd *qc) +{ + qc->dma_dir = DMA_NONE; + qc->flags = 0; + qc->nbytes = qc->extrabytes = qc->curbytes = 0; + qc->n_elem = 0; + qc->err_mask = 0; + qc->sect_size = ATA_SECT_SIZE; + qc->nbytes = ATA_SECT_SIZE * temp_n_block; + + memset(&qc->tf, 0, sizeof(qc->tf)); + qc->tf.ctl = 0; + qc->tf.device = ATA_DEVICE_OBS; + + /* init result_tf such that it indicates normal completion */ + qc->result_tf.command = ATA_DRDY; + qc->result_tf.feature = 0; +} + +unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, unsigned int buflen, + unsigned long timeout) +{ + struct ata_link *link = dev->link; + struct ata_port *ap = pap; + struct ata_queued_cmd *qc; + unsigned int tag, preempted_tag; + u32 preempted_sactive, preempted_qc_active; + int preempted_nr_active_links; + unsigned int err_mask; + int rc = 0; + u8 status; + + /* cheack BSY = 0 */ + status = ata_busy_wait(ap, ATA_BUSY, 300000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + rc = FALSE; + return rc; + } + + /* no internal command while frozen */ + if (ap->pflags & ATA_PFLAG_FROZEN) + return AC_ERR_SYSTEM; + + tag = ATA_TAG_INTERNAL; + + if (test_and_set_bit(tag, &ap->qc_allocated)) + printf("test_and_set_bit failed\n"); + + qc = __ata_qc_from_tag(ap, tag); + qc->tag = tag; + qc->ap = ap; + qc->dev = dev; + + ata_qc_reinit(qc); + + preempted_tag = link->active_tag; + preempted_sactive = link->sactive; + preempted_qc_active = ap->qc_active; + preempted_nr_active_links = ap->nr_active_links; + link->active_tag = ATA_TAG_POISON; + link->sactive = 0; + ap->qc_active = 0; + ap->nr_active_links = 0; + + /* prepare & issue qc */ + qc->tf = *tf; + if (cdb) + memcpy(qc->cdb, cdb, ATAPI_CDB_LEN); + qc->flags |= ATA_QCFLAG_RESULT_TF; + qc->dma_dir = dma_dir; + qc->private_data = 0; + + ata_qc_issue(qc); + + if (!timeout) + timeout = ata_probe_timeout * 1000 / HZ; + + /* cheack BSY = 0 */ + status = ata_busy_wait(ap, ATA_BUSY, 30000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + printf("altstatus = 0x%x.\n",status); + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + if (waiting_for_reg_state(ap->ioaddr.altstatus_addr,1000,0x8)) { + printf("DRQ = 1 check timeout 1000msec\n"); + u8 status = 0; + u8 errorStatus = 0; + + status = readb( ap->ioaddr.altstatus_addr); + if ((status&0x01) != 0) { + errorStatus = readb( ap->ioaddr.feature_addr); + printf("ERROR STATUS = 0x%x\n",errorStatus); + } + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + status = ata_busy_wait(ap, ATA_BUSY, 10); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + ata_pio_task(ap); + + if (!rc) { + if (qc->flags & ATA_QCFLAG_ACTIVE) { + qc->err_mask |= AC_ERR_TIMEOUT; + ata_port_freeze(ap); + } + } + + /* perform minimal error analysis */ + if (qc->flags & ATA_QCFLAG_FAILED) { + if (qc->result_tf.command & (ATA_ERR | ATA_DF)) + qc->err_mask |= AC_ERR_DEV; + + if (!qc->err_mask) + qc->err_mask |= AC_ERR_OTHER; + + if (qc->err_mask & ~AC_ERR_OTHER) + qc->err_mask &= ~AC_ERR_OTHER; + } + + /* finish up */ + *tf = qc->result_tf; + err_mask = qc->err_mask; + ata_qc_free(qc); + link->active_tag = preempted_tag; + link->sactive = preempted_sactive; + ap->qc_active = preempted_qc_active; + ap->nr_active_links = preempted_nr_active_links; + + if (ap->flags & ATA_FLAG_DISABLED) { + err_mask |= AC_ERR_SYSTEM; + ap->flags &= ~ATA_FLAG_DISABLED; + } + + return err_mask; +} + +unsigned int ata_dev_set_feature(struct ata_device *dev, + u8 enable, u8 feature) +{ + struct ata_taskfile tf; + struct ata_port *ap; + ap = pap; + unsigned int err_mask; + + /* set up set-features taskfile */ + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_SET_FEATURES; + tf.feature = enable; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = feature; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); + + return err_mask; +} + +unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors) +{ + struct ata_taskfile tf; + struct ata_port *ap; + ap = pap; + unsigned int err_mask; + + /* Number of sectors per track 1-255. Number of heads 1-16 */ + if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) + return AC_ERR_INVALID; + + /* set up init dev params taskfile */ + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_INIT_DEV_PARAMS; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = sectors; + tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */ + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); + + if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED)) + err_mask = 0; + + return err_mask; +} + +struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, + unsigned int tag) +{ + if (tag < ATA_MAX_QUEUE) + return &ap->qcmd[tag]; + return NULL; +} + +void ata_qc_issue(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; + u8 prot = qc->tf.protocol; + + if (ata_is_ncq(prot)) { + if (!link->sactive) + ap->nr_active_links++; + link->sactive |= 1 << qc->tag; + } else { + ap->nr_active_links++; + link->active_tag = qc->tag; + } + + qc->flags |= ATA_QCFLAG_ACTIVE; + ap->qc_active |= 1 << qc->tag; + + if (qc->dev->flags & ATA_DFLAG_SLEEPING) { + msleep(1); /* delay 1msec */ + return; + } + + qc->err_mask |= sata_dwc_qc_issue(qc); + if (qc->err_mask) + goto err; + + return; +err: + ata_qc_complete(qc); +} + +unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc) +{ + ata_qc_issue_prot(qc); + return 0; +} + +void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) +{ + /* set command register */ + writeb(tf->command, ap->ioaddr.command_addr); + + /* read alternative status register */ + readb(ap->ioaddr.altstatus_addr); + + /* delay 400nsec over */ + udelay(1); +} + +void __ata_port_freeze(struct ata_port *ap) +{ + printf("set port freeze.\n"); + ap->pflags |= ATA_PFLAG_FROZEN; +} + +int ata_port_freeze(struct ata_port *ap) +{ + __ata_port_freeze(ap); + return 0; +} + +unsigned int ata_tag_internal(unsigned int tag) +{ + return tag == ATA_MAX_QUEUE - 1; +} + +void ata_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_device *dev = qc->dev; + if (qc->err_mask) + qc->flags |= ATA_QCFLAG_FAILED; + + if (qc->flags & ATA_QCFLAG_FAILED) { + if (!ata_tag_internal(qc->tag)) { + /* always fill result TF for failed qc */ + fill_result_tf(qc); + return; + } + } + /* read result TF if requested */ + if (qc->flags & ATA_QCFLAG_RESULT_TF) + fill_result_tf(qc); + + /* Some commands need post-processing after successful + * completion. + */ + switch (qc->tf.command) { + case ATA_CMD_SET_FEATURES: + if (qc->tf.feature != SETFEATURES_WC_ON && + qc->tf.feature != SETFEATURES_WC_OFF) + break; + case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */ + case ATA_CMD_SET_MULTI: /* multi_count changed */ + break; + + case ATA_CMD_SLEEP: + dev->flags |= ATA_DFLAG_SLEEPING; + break; + } + + __ata_qc_complete(qc); +} + +void __ata_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; + + /* command should be marked inactive atomically with qc completion */ + link->active_tag = ATA_TAG_POISON; + ap->nr_active_links--; + + /* clear exclusive status */ + if (qc->flags & ATA_QCFLAG_CLEAR_EXCL && ap->excl_link == link) + ap->excl_link = NULL; + + qc->flags &= ~ATA_QCFLAG_ACTIVE; + ap->qc_active &= ~(1 << qc->tag); +} + +void fill_result_tf(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + qc->result_tf.flags = qc->tf.flags; + ata_tf_read(ap, &qc->result_tf); +} + +void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + tf->command = ata_check_status(ap); + tf->feature = readb(ioaddr->error_addr); + tf->nsect = readb(ioaddr->nsect_addr); + tf->lbal = readb(ioaddr->lbal_addr); + tf->lbam = readb(ioaddr->lbam_addr); + tf->lbah = readb(ioaddr->lbah_addr); + tf->device = readb(ioaddr->device_addr); + + if (tf->flags & ATA_TFLAG_LBA48) { + if (ioaddr->ctl_addr) { + writeb(tf->ctl | ATA_HOB, ioaddr->ctl_addr); + + tf->hob_feature = readb(ioaddr->error_addr); + tf->hob_nsect = readb(ioaddr->nsect_addr); + tf->hob_lbal = readb(ioaddr->lbal_addr); + tf->hob_lbam = readb(ioaddr->lbam_addr); + tf->hob_lbah = readb(ioaddr->lbah_addr); + + writeb(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + } else { + printf("sata_dwc warnning register read.\n"); + } + } +} + +void ata_qc_free(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int tag; + qc->flags = 0; + tag = qc->tag; + if (tag < ATA_MAX_QUEUE) { + qc->tag = ATA_TAG_POISON; + clear_bit(tag, &ap->qc_allocated); + } +} + +void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + if (tf->ctl != ap->last_ctl) { + if (ioaddr->ctl_addr) + writeb(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + ata_wait_idle(ap); + } + + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + writeb(tf->hob_feature, ioaddr->feature_addr); + writeb(tf->hob_nsect, ioaddr->nsect_addr); + writeb(tf->hob_lbal, ioaddr->lbal_addr); + writeb(tf->hob_lbam, ioaddr->lbam_addr); + writeb(tf->hob_lbah, ioaddr->lbah_addr); + } + + if (is_addr) { + writeb(tf->feature, ioaddr->feature_addr); + writeb(tf->nsect, ioaddr->nsect_addr); + writeb(tf->lbal, ioaddr->lbal_addr); + writeb(tf->lbam, ioaddr->lbam_addr); + writeb(tf->lbah, ioaddr->lbah_addr); + } + + if (tf->flags & ATA_TFLAG_DEVICE) + writeb(tf->device, ioaddr->device_addr); + + ata_wait_idle(ap); +} + +void sata_dwc_exec_command_by_tag(struct ata_port *ap, + struct ata_taskfile *tf, + u8 tag, u32 cmd_issued) +{ + struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); + hsdevp->cmd_issued[tag] = cmd_issued; + + /* Clear SError before executing a new command.*/ + clear_serror(); + ata_exec_command(ap, tf); +} + +void clear_serror(void) +{ + u32 temp; + temp = in_le32((void __iomem *)scr_addr_sstatus + 4); + + out_le32((void __iomem *)scr_addr_sstatus + 4, temp); +} + +void ata_tf_to_host(struct ata_port *ap, const struct ata_taskfile *tf) +{ + ata_tf_load(ap, tf); + ata_exec_command(ap, tf); +} + +unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + if (ap->flags & ATA_FLAG_PIO_POLLING) { + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + case ATA_PROT_NODATA: + case ATAPI_PROT_PIO: + case ATAPI_PROT_NODATA: + qc->tf.flags |= ATA_TFLAG_POLLING; + break; + default: + break; + } + } + + /* select the device */ + ata_dev_select(ap, qc->dev->devno, 1, 0); + + /* start the command */ + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + if (qc->tf.flags & ATA_TFLAG_POLLING) { + qc->tf.ctl |= ATA_NIEN; + } + + ata_tf_to_host(ap, &qc->tf); + + /* PIO data in protocol */ + ap->hsm_task_state = HSM_ST; + + if (qc->tf.flags & ATA_TFLAG_POLLING) + ata_pio_queue_task(ap, qc, 0); + + break; + + default: + return AC_ERR_SYSTEM; + } + + return 0; +} + +void ata_pio_task(struct ata_port *arg_ap) +{ + struct ata_port *ap = arg_ap; + struct ata_queued_cmd *qc = ap->port_task_data; + u8 status; + int poll_next; + +fsm_start: + /* + * This is purely heuristic. This is a fast path. + * Sometimes when we enter, BSY will be cleared in + * 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, queue delayed work. + */ + 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) { + ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE); + return; + } + } + + /* move the HSM */ + poll_next = ata_hsm_move(ap, qc, status, 1); + + /* another command or interrupt handler + * may be running at this point. + */ + if (poll_next) + goto fsm_start; +} + +void ata_pio_queue_task(struct ata_port *ap, void *data,unsigned long delay) +{ + ap->port_task_data = data; +} + +unsigned int ac_err_mask(u8 status) +{ + if (status & (ATA_BUSY | ATA_DRQ)) + return AC_ERR_HSM; + if (status & (ATA_ERR | ATA_DF)) + return AC_ERR_DEV; + return 0; +} + +unsigned int __ac_err_mask(u8 status) +{ + unsigned int mask = ac_err_mask(status); + if (mask == 0) + return AC_ERR_OTHER; + return mask; +} + +int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq) +{ + int poll_next; + +fsm_start: + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + poll_next = (qc->tf.flags & ATA_TFLAG_POLLING); + + /* check device status */ + if ((status & ATA_DRQ) == 0) { + /* handle BSY=0, DRQ=0 as error */ + if (status & (ATA_ERR | ATA_DF)) { + /* device stops HSM for abort/error */ + qc->err_mask |= AC_ERR_DEV; + } else { + /* HSM violation. Let EH handle this */ + qc->err_mask |= AC_ERR_HSM; + } + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + /* Device should not ask for data transfer (DRQ=1) + * when it finds something wrong. + * We ignore DRQ here and stop the HSM by + * changing hsm_task_state to HSM_ST_ERR and + * let the EH abort the command or reset the device. + */ + if (status & (ATA_ERR | ATA_DF)) { + if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) { + printf("DRQ=1 with device error, " + "dev_stat 0x%X\n", status); + qc->err_mask |= AC_ERR_HSM; + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + } + + if (qc->tf.protocol == ATA_PROT_PIO) { + /* PIO data out protocol. + * send first data block. + */ + /* ata_pio_sectors() might change the state + * to HSM_ST_LAST. so, the state is changed here + * before ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST; + ata_pio_sectors(qc); + } else { + printf("protocol is not ATA_PROT_PIO \n"); + } + break; + + case HSM_ST: + /* complete command or read/write the data register */ + /* ATA PIO protocol */ + if ((status & ATA_DRQ) == 0) { + /* handle BSY=0, DRQ=0 as error */ + if (status & (ATA_ERR | ATA_DF)) { + /* device stops HSM for abort/error */ + qc->err_mask |= AC_ERR_DEV; + } else { + /* HSM violation. Let EH handle this. + * Phantom devices also trigger this + * condition. Mark hint. + */ + qc->err_mask |= AC_ERR_HSM | AC_ERR_NODEV_HINT; + } + + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + /* For PIO reads, some devices may ask for + * data transfer (DRQ=1) alone with ERR=1. + * We respect DRQ here and transfer one + * block of junk data before changing the + * hsm_task_state to HSM_ST_ERR. + * + * For PIO writes, ERR=1 DRQ=1 doesn't make + * sense since the data block has been + * transferred to the device. + */ + if (status & (ATA_ERR | ATA_DF)) { + /* data might be corrputed */ + qc->err_mask |= AC_ERR_DEV; + + if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { + ata_pio_sectors(qc); + status = ata_wait_idle(ap); + } + + if (status & (ATA_BUSY | ATA_DRQ)) + qc->err_mask |= AC_ERR_HSM; + + /* ata_pio_sectors() might change the + * state to HSM_ST_LAST. so, the state + * is changed after ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + ata_pio_sectors(qc); + if (ap->hsm_task_state == HSM_ST_LAST && + (!(qc->tf.flags & ATA_TFLAG_WRITE))) { + /* all data read */ + status = ata_wait_idle(ap); + goto fsm_start; + } + + poll_next = 1; + break; + + case HSM_ST_LAST: + if (!ata_ok(status)) { + qc->err_mask |= __ac_err_mask(status); + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + /* no more data to transfer */ + ap->hsm_task_state = HSM_ST_IDLE; + + /* complete taskfile transaction */ + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + + case HSM_ST_ERR: + /* make sure qc->err_mask is available to + * know what's wrong and recover + */ + ap->hsm_task_state = HSM_ST_IDLE; + + /* complete taskfile transaction */ + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + default: + poll_next = 0; + } + + return poll_next; +} + +int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *qc) +{ + if (qc->tf.flags & ATA_TFLAG_POLLING) + return 1; + + if (ap->hsm_task_state == HSM_ST_FIRST) { + if (ata_is_atapi(qc->tf.protocol) && + !(qc->dev->flags & ATA_DFLAG_CDB_INTR)) + return 1; + } + + return 0; +} + +void ata_pio_sectors(struct ata_queued_cmd *qc) +{ + struct ata_port *ap; + ap = pap; + qc->pdata = ap->pdata; + + if (is_multi_taskfile(&qc->tf)) { + /* READ/WRITE MULTIPLE */ + unsigned int nsect; + + nsect = min((qc->nbytes - qc->curbytes) / qc->sect_size, + qc->dev->multi_count); + while (nsect--) + ata_pio_sector(qc); + } else { + ata_pio_sector(qc); + } + + readb(qc->ap->ioaddr.altstatus_addr); + udelay(1); +} + +void ata_pio_sector(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int offset; + unsigned char *buf; + + if (qc->curbytes == qc->nbytes - qc->sect_size) + ap->hsm_task_state = HSM_ST_LAST; + + offset = qc->curbytes; + + /* check cmd and set buffer */ + switch (qc->tf.command) { + case ATA_CMD_ID_ATA: /* IDENTIFY */ + buf = (unsigned char *)&ata_device.id[0]; + break; + case ATA_CMD_PIO_READ_EXT: /* READ SECTORS EX 0x24 */ + case ATA_CMD_PIO_READ: /* READ SECTORS 0x20 */ + buf = qc->pdata + offset; + break; + default: + buf = &temp_data_buf[0]; + } + + /* data xfer */ + ata_mmio_data_xfer(qc->dev, buf, qc->sect_size); + + qc->curbytes += qc->sect_size; + +} + +void ata_mmio_data_xfer(struct ata_device *dev, unsigned char *buf, + unsigned int buflen) +{ + struct ata_port *ap = pap; + void __iomem *data_addr = ap->ioaddr.data_addr; + unsigned int words = buflen >> 1; + u16 *buf16 = (u16 *)buf; + unsigned int i = 0; + + udelay(100); + /* Transfer */ + for (i=0; i < words; i++) + buf16[i] = cpu_to_le16(readw(data_addr)); + + /* Transfer trailing 1 byte, if any. */ + if (buflen & 0x01) { + __le16 align_buf[1] = { 0 }; + unsigned char *trailing_buf = buf + buflen - 1; + + align_buf[0] = cpu_to_le16(readw(data_addr)); + memcpy(trailing_buf, align_buf, 1); + words++; + } +} + +void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) +{ + struct ata_port *ap = qc->ap; + + if (in_wq) { + /* EH might have kicked in while host lock is + * released. + */ + qc = &ap->qcmd[qc->tag]; + if (qc) { + if (!(qc->err_mask & AC_ERR_HSM)) { + ata_irq_on(ap); + ata_qc_complete(qc); + } else { + ata_port_freeze(ap); + } + } + } else { + if (!(qc->err_mask & AC_ERR_HSM)) { + ata_qc_complete(qc); + } else { + ata_port_freeze(ap); + } + } +} + +u8 ata_irq_on(struct ata_port *ap) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + u8 tmp; + + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; + + if (ioaddr->ctl_addr) + writeb(ap->ctl, ioaddr->ctl_addr); + + tmp = ata_wait_idle(ap); + + return tmp; +} + +void sata_dwc_probe(void) +{ + struct sata_dwc_device hsdev; + struct ata_host host; + struct ata_port_info pi = sata_dwc_port_info[0]; + struct ata_device *ata_dev = &ata_device; + struct ata_link *link; + struct sata_dwc_device_port hsdevp = dwc_devp; + u8 *base = 0; + u8 *sata_dma_regs_addr = 0; + u32 idr, versionr; + u8 status; + unsigned long base_addr = 0; + int chan = 0; + int rc; + int i; + const u16 *id; + unsigned long xfer_mask; + char revbuf[7]; /* XYZ-99\0 */ + unsigned long pio_mask, mwdma_mask, udma_mask; + + phost = &host; /* set grobal */ + + /* Base address */ + base = (u8*)SATA_BASE_ADDR; + + /* SATA register init */ + hsdev.sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET); + + host.n_ports = SATA_DWC_MAX_PORTS; + + for (i = 0; i < SATA_DWC_MAX_PORTS; i++) { + ap.pflags |= ATA_PFLAG_INITIALIZING; + ap.flags = ATA_FLAG_DISABLED; + ap.print_id = -1; + ap.ctl = ATA_DEVCTL_OBS; + ap.host = &host; + ap.last_ctl = 0xFF; + ap.dev = &ata_device; + + link = &ap.link; + link->ap = ≈ + link->pmp = 0; + link->active_tag = ATA_TAG_POISON; + link->hw_sata_spd_limit = 0; + + ap.port_no = i; + host.ports[i] = ≈ + } + + ap.pio_mask = pi.pio_mask; + ap.mwdma_mask = pi.mwdma_mask; + ap.udma_mask = pi.udma_mask; + ap.flags |= pi.flags; + ap.link.flags |= pi.link_flags; + + /* Host port init */ + host.ports[0]->ioaddr.cmd_addr = base; + host.ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET; + scr_addr_sstatus = base + SATA_DWC_SCR_OFFSET; + + /* sata_dwc setup port */ + base_addr = (unsigned long)base; + + host.ports[0]->ioaddr.cmd_addr = (void *)base_addr + 0x00; + host.ports[0]->ioaddr.data_addr = (void *)base_addr + 0x00; + + host.ports[0]->ioaddr.error_addr = (void *)base_addr + 0x04; + host.ports[0]->ioaddr.feature_addr = (void *)base_addr + 0x04; + + host.ports[0]->ioaddr.nsect_addr = (void *)base_addr + 0x08; + + host.ports[0]->ioaddr.lbal_addr = (void *)base_addr + 0x0c; + host.ports[0]->ioaddr.lbam_addr = (void *)base_addr + 0x10; + host.ports[0]->ioaddr.lbah_addr = (void *)base_addr + 0x14; + + host.ports[0]->ioaddr.device_addr = (void *)base_addr + 0x18; + host.ports[0]->ioaddr.command_addr = (void *)base_addr + 0x1c; + host.ports[0]->ioaddr.status_addr = (void *)base_addr + 0x1c; + + host.ports[0]->ioaddr.altstatus_addr = (void *)base_addr + 0x20; + host.ports[0]->ioaddr.ctl_addr = (void *)base_addr + 0x20; + + /* Get Host ID / Version */ + idr = in_le32(&hsdev.sata_dwc_regs->idr); + versionr = in_le32(&hsdev.sata_dwc_regs->versionr); + + /* DMA register init */ + sata_dma_regs_addr = (u8*)SATA_DMA_REG_ADDR; + sata_dma_regs = (void *__iomem)sata_dma_regs_addr; + + /* DMA channel Interrupt is disable. DMA Enable setup is next. */ + for (chan = 0; chan < DMA_NUM_CHANS; chan++) { + /* DMA Interrupt register(error) mask. */ + out_le32(&(sata_dma_regs->interrupt_mask.error.low), + DMA_DISABLE_CHAN(chan)); + + /* DMA Interrupt register(transfer) mask. */ + out_le32(&(sata_dma_regs->interrupt_mask.tfr.low), + DMA_DISABLE_CHAN(chan)); + } + + /* DMA Enable by DMAC Configuration Register */ + out_le32(&(sata_dma_regs->dma_cfg.low), DMA_EN); + + /* Enable selective interrupts by setting the interrupt mask register */ + out_le32(&hsdev.sata_dwc_regs->intmr, + SATA_DWC_INTMR_ERRM | + SATA_DWC_INTMR_NEWFPM | + SATA_DWC_INTMR_PMABRTM | + SATA_DWC_INTMR_DMATM); + + /* Unmask the error bits that should trigger an error interrupt by + * setting the error mask register. + */ + out_le32(&hsdev.sata_dwc_regs->errmr,SATA_DWC_SERROR_ERR_BITS); + + hsdev.host = ap.host; + memset(&hsdevp, 0, sizeof(hsdevp)); + hsdevp.hsdev = &hsdev; + + for (i = 0; i < SATA_DWC_QCMD_MAX; i++) + hsdevp.cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT; + + if (ap.port_no == 0) { + out_le32(&hsdev.sata_dwc_regs->dmacr,SATA_DWC_DMACR_TXRXCH_CLEAR); + + out_le32(&hsdev.sata_dwc_regs->dbtsr, + (SATA_DWC_DBTSR_MWR(AHB_DMA_BRST_DFLT) | + SATA_DWC_DBTSR_MRD(AHB_DMA_BRST_DFLT))); + } + + /* Clear any error bits before libata starts issuing commands */ + out_le32((void __iomem *)scr_addr_sstatus + 4, + in_le32((void __iomem *)scr_addr_sstatus + 4)); + + /* check altstatus register (find device) */ + status = ata_check_altstatus(&ap); + + if (status == 0x7f) { + printf("Hard Disk not found.\n"); + dev_state = SATA_NODEVICE; + return; + } + + /* waiting for device ready. time out 30sec */ + printf("waitng for device ready."); + i = 0; + while (1) { + udelay (10000); /* 10 ms */ + + /* read altstatus */ + status = ata_check_altstatus(&ap); + + /* status is not busy => break */ + if ((status & ATA_BUSY) == 0) { + printf("\n"); + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + + /* bussy set devise state flag */ + dev_state = SATA_NODEVICE; + return; + } + if ((i >= 100) && ((i%100)==0)) + printf("."); + } + + /* softreset */ + rc = sata_dwc_softreset(&ap); + + if (rc) + printf("sata_dwc : error. soft reset failed\n"); + + /* waiting for device ready. time out 30sec */ + printf("waitng for device ready."); + i = 0; + while (1) { + udelay (10000); /* 10 ms */ + + /* read altstatus */ + status = ata_check_altstatus(&ap); + + /* status is not busy => break */ + if ((status & ATA_BUSY) == 0) { + printf("\n"); + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + + /* bussy set devise state flag */ + dev_state = SATA_NODEVICE; + return; + } + if ((i >= 100) && ((i%100)==0)) + printf("."); + } + + udelay (1000); /* before IDENTIFY command safety delay 1 ms */ + + /* IDENTIFY command send */ + rc = ata_dev_read_id(ata_dev, &ata_dev->class, + ATA_READID_POSTRESET,ata_dev->id); + + if (rc) + printf("sata_dwc : error. IDENTIFY Command failed\n"); + + /* SATA drives indicate we have a bridge. We don't know which + * end of the link the bridge is which is a problem + */ + if (ata_id_is_sata(ata_dev->id)) + ap.cbl = ATA_CBL_SATA; + + id = ata_dev->id; + + /* initialize to be configured parameters */ + ata_dev->flags &= ~ATA_DFLAG_CFG_MASK; + ata_dev->max_sectors = 0; + ata_dev->cdb_len = 0; + ata_dev->n_sectors = 0; + ata_dev->cylinders = 0; + ata_dev->heads = 0; + ata_dev->sectors = 0; + + /* Usual case. Word 53 indicates word 64 is valid */ + if (id[ATA_ID_FIELD_VALID] & (1 << 1)) { + pio_mask = id[ATA_ID_PIO_MODES] & 0x03; + pio_mask <<= 3; + pio_mask |= 0x7; + } else { + /* If word 64 isn't valid then Word 51 high byte holds + * the PIO timing number for the maximum. Turn it into + * a mask. + */ + u8 mode = (id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF; + if (mode < 5) { /* Valid PIO range */ + pio_mask = (2 << mode) - 1; + } else { + pio_mask = 1; + } + } + + mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07; + + if (ata_id_is_cfa(id)) { + /* + * Process compact flash extended modes + */ + int pio = id[163] & 0x7; + int dma = (id[163] >> 3) & 7; + + if (pio) + pio_mask |= (1 << 5); + if (pio > 1) + pio_mask |= (1 << 6); + if (dma) + mwdma_mask |= (1 << 3); + if (dma > 1) + mwdma_mask |= (1 << 4); + } + + udma_mask = 0; + if (id[ATA_ID_FIELD_VALID] & (1 << 2)) + udma_mask = id[ATA_ID_UDMA_MODES] & 0xff; + + xfer_mask = (pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO | + (mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA | + (udma_mask << ATA_SHIFT_UDMA) & ATA_MASK_UDMA; + + /* ATA-specific feature tests */ + if (ata_dev->class == ATA_DEV_ATA) { + if (ata_id_is_cfa(id)) { + if (id[162] & 1) /* CPRM may make this media unusable */ + printf("supports DRM functions and may " + "not be fully accessable.\n"); + sprintf(revbuf, "%s", "CFA"); + } else { + /* Warn the user if the device has TPM extensions */ + if (ata_id_has_tpm(id)) + printf("supports DRM functions and may " + "not be fully accessable.\n"); + } + + /* set n_secters */ + ata_dev->n_sectors = ata_id_n_sectors((u16*)id); + + if (ata_dev->id[59] & 0x100) + ata_dev->multi_count = ata_dev->id[59] & 0xff; + + if (ata_id_has_lba(id)) { + const char *lba_desc; + char ncq_desc[20]; + + lba_desc = "LBA"; + ata_dev->flags |= ATA_DFLAG_LBA; + if (ata_id_has_lba48(id)) { + ata_dev->flags |= ATA_DFLAG_LBA48; + lba_desc = "LBA48"; + + if (ata_dev->n_sectors >= (1UL << 28) && + ata_id_has_flush_ext(id)) + ata_dev->flags |= ATA_DFLAG_FLUSH_EXT; + } + /* config NCQ */ + if (!ata_id_has_ncq(ata_dev->id)) + ncq_desc[0] = '\0'; + + if (ata_dev->horkage & ATA_HORKAGE_NONCQ) + sprintf(ncq_desc, "%s", "NCQ (not used)"); + + if (ap.flags & ATA_FLAG_NCQ) + ata_dev->flags |= ATA_DFLAG_NCQ; + } + ata_dev->cdb_len = 16; + } + /* determine max_sectors */ + ata_dev->max_sectors = ATA_MAX_SECTORS; + if (ata_dev->flags & ATA_DFLAG_LBA48) + ata_dev->max_sectors = ATA_MAX_SECTORS_LBA48; + + if (!(ata_dev->horkage & ATA_HORKAGE_IPM)) { + if (ata_id_has_hipm(ata_dev->id)) + ata_dev->flags |= ATA_DFLAG_HIPM; + if (ata_id_has_dipm(ata_dev->id)) + ata_dev->flags |= ATA_DFLAG_DIPM; + } + + if ((ap.cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ata_dev->id))) { + ata_dev->udma_mask &= ATA_UDMA5; + ata_dev->max_sectors = ATA_MAX_SECTORS; + } + + if (ata_dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { + printf("Drive reports diagnostics failure." + "This may indicate a drive\n"); + printf("fault or invalid emulation." + "Contact drive vendor for information.\n"); + } + + /* Hard Disk status check : test send READ Command */ + rc = check_sata_dev_state(); +} + +int sata_dwc_softreset(struct ata_port *ap) +{ + u8 nsect,lbal = 0; + u8 tmp = 0; + u32 serror = 0; + u8 status = 0; + struct ata_ioports *ioaddr = &ap->ioaddr; + + /* read SCR ERROR */ + serror = in_le32((void *)ap->ioaddr.scr_addr + (SCR_ERROR * 4)); + + /* device check */ + writeb(0x55, ioaddr->nsect_addr); + writeb(0xaa, ioaddr->lbal_addr); + writeb(0xaa, ioaddr->nsect_addr); + writeb(0x55, ioaddr->lbal_addr); + writeb(0x55, ioaddr->nsect_addr); + writeb(0xaa, ioaddr->lbal_addr); + + nsect = readb(ioaddr->nsect_addr); + lbal = readb(ioaddr->lbal_addr); + + if ((nsect == 0x55) && (lbal == 0xaa)) { + /* we found a device */ + printf("we found a device\n"); + } else { + /* nothing found */ + printf("Not found a device.\n"); + dev_state = SATA_NODEVICE; + return FALSE; + } + + tmp = ATA_DEVICE_OBS; + writeb(tmp,ioaddr->device_addr); + writeb(ap->ctl,ioaddr->ctl_addr); + + udelay(200); + + /* set softreset */ + writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr); + + udelay(200); + writeb(ap->ctl,ioaddr->ctl_addr); + + /* wait a while before cheking status */ + msleep(150); + status = ata_check_status(ap); + + msleep(50); + ata_check_status(ap); + + while (1) { + u8 status = ata_check_status(ap); + + if (!(status & ATA_BUSY)) + break; + + printf("Hard Disk status is BUSY.\n"); + msleep(50); + } + + tmp = ATA_DEVICE_OBS; + writeb(tmp,ioaddr->device_addr); + + nsect = readb(ioaddr->nsect_addr); + lbal = readb(ioaddr->lbal_addr); + + return 0; +} + +void scsi_bus_reset() +{ + struct ata_port *ap = pap; + + /* check device state */ + if (dev_state != SATA_READY) { + printf("no devices available\n"); + return; + } + + /*soft reset process*/ + sata_dwc_softreset(ap); +} + +void scsi_print_error(ccb * pccb) +{ + /*The ahci error info can be read in the ahci driver*/ +} + +int ata_dev_read_sectors(ccb *pccb) +{ + struct ata_port *ap = pap; + struct ata_device *dev = &ata_device; + struct ata_taskfile tf; + unsigned int class = ATA_DEV_ATA; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1; + int rc; + + u32 block=0; + u32 n_block=0; + + ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */ + +retry: + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; /*ap->ctl = 0x08 */ + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + + /* set pdata */ + ap->pdata = pccb->pdata; + + tf.device = ATA_DEVICE_OBS; + + block |= ((u32)pccb->cmd[2]) << 24; + block |= ((u32)pccb->cmd[3]) << 16; + block |= ((u32)pccb->cmd[4]) << 8; + block |= ((u32)pccb->cmd[5]); + + n_block |= ((u32)pccb->cmd[7]) << 8; + n_block |= ((u32)pccb->cmd[8]); + + /* trying temp to n_block */ + temp_n_block = n_block; + + +#ifdef CONFIG_LBA48 + tf.command = ATA_CMD_PIO_READ_EXT; /* READ SECTOR(S) EXT 0x24 */ + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; + + tf.hob_feature = 31; + tf.feature = 31; + tf.hob_nsect = (n_block >> 8) & 0xff; + tf.nsect = n_block & 0xff; + + tf.hob_lbah = 0x0; + tf.hob_lbam = 0x0; + tf.hob_lbal = (block >> 24) & 0xff; + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; +#else /* LBA24 */ + tf.command = ATA_CMD_PIO_READ; /* READ SECTOR(S) 0x20 */ + tf.flags |= ATA_TFLAG_LBA ; + + tf.feature = 31; + tf.nsect = n_block & 0xff; + + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = (block >> 24) & 0xf; + + tf.device |= 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; + +#endif /* CONFIG_LBA48 */ + + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.flags |= ATA_TFLAG_POLLING; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,0, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("READ_SECTORS NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + /* sanity check */ + rc = -EINVAL; + reason = "device reports invalid type"; + + return 0; + +err_out: + printf("failed to READ SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); + return rc; +} diff -purN u-boot-2009.03/drivers/block/sata_dwc.h u-boot-2009.03-sata/drivers/block/sata_dwc.h --- u-boot-2009.03/drivers/block/sata_dwc.h 1970-01-01 09:00:00.000000000 +0900 +++ u-boot-2009.03-sata/drivers/block/sata_dwc.h 2009-03-26 18:39:46.000000000 +0900 @@ -0,0 +1,484 @@ +/* + * sata_dwc.h + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld mmiesfeld@amcc.com + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese sr@denx.de + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * This program is free software; you can redistribute + * it and/or modify it under the terms of the GNU + * General Public License as published by the + * Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + */ +/* + * SATA support based on the chip canyonlands. + * + * 03-26-2009 + * The local version of this driver for the canyonlands board + * does not use interrupts but polls the chip instead. + */ + + +#ifndef _SATA_DWC_H_ +#define _SATA_DWC_H_ + +#define HZ 100 + +#define READ 0 +#define WRITE 1 + +enum { + ATA_READID_POSTRESET = (1 << 0), /* reading ID after reset */ + + ATA_DNXFER_PIO = 0, /* speed down PIO */ + ATA_DNXFER_DMA = 1, /* speed down DMA */ + ATA_DNXFER_40C = 2, /* apply 40c cable limit */ + ATA_DNXFER_FORCE_PIO = 3, /* force PIO */ + ATA_DNXFER_FORCE_PIO0 = 4, /* force PIO0 */ + + ATA_DNXFER_QUIET = (1 << 31), +}; + +enum hsm_task_states { + HSM_ST_IDLE, /* no command on going */ + HSM_ST_FIRST, /* (waiting the device to) + * write CDB or first data block */ + HSM_ST, /* (waiting the device to) transfer data */ + HSM_ST_LAST, /* (waiting the device to) complete command */ + HSM_ST_ERR, /* error */ +}; + +#define ATA_SHORT_PAUSE ((HZ >> 6) + 1) + +struct ata_queued_cmd { + struct ata_port *ap; + struct ata_device *dev; + + struct ata_taskfile tf; + u8 cdb[ATAPI_CDB_LEN]; + + unsigned long flags; /* ATA_QCFLAG_xxx */ + unsigned int tag; + unsigned int n_elem; + + int dma_dir; + + unsigned int sect_size; + + unsigned int nbytes; + unsigned int extrabytes; + unsigned int curbytes; + + unsigned int err_mask; + struct ata_taskfile result_tf; + + void *private_data; + void *lldd_task; + unsigned char *pdata; +}; + +typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc); + +/* defines only for the constants which don't work cell as enums*/ +#define ATA_TAG_POISON 0xfafbfcfdU + +enum { + /* various global constants */ + LIBATA_MAX_PRD = ATA_MAX_PRD / 2, + LIBATA_DUMB_MAX_PRD = ATA_MAX_PRD / 4, /* Worst case */ + ATA_MAX_PORTS = 8, + ATA_DEF_QUEUE = 1, + /* tag ATA_MAX_QUEUE - 1 is reserved for internal commands */ + ATA_MAX_QUEUE = 32, + ATA_TAG_INTERNAL = ATA_MAX_QUEUE - 1, + ATA_MAX_BUS = 2, + ATA_DEF_BUSY_WAIT = 10000, + + ATAPI_MAX_DRAIN = 16 << 10, + + ATA_SHT_EMULATED = 1, + ATA_SHT_CMD_PER_LUN = 1, + ATA_SHT_THIS_ID = -1, + ATA_SHT_USE_CLUSTERING = 1, + + /* struct ata_device stuff */ + ATA_DFLAG_LBA = (1 << 0), /* device supports LBA */ + ATA_DFLAG_LBA48 = (1 << 1), /* device supports LBA48 */ + ATA_DFLAG_CDB_INTR = (1 << 2), /* device asserts INTRQ */ + ATA_DFLAG_NCQ = (1 << 3), /* device supports NCQ */ + ATA_DFLAG_FLUSH_EXT = (1 << 4), /* do FLUSH_EXT instead of FLUSH */ + ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */ + ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */ + ATA_DFLAG_AN = (1 << 7), /* AN configured */ + ATA_DFLAG_HIPM = (1 << 8), /* device supports HIPM */ + ATA_DFLAG_DIPM = (1 << 9), /* device supports DIPM */ + ATA_DFLAG_DMADIR = (1 << 10), /* device requires DMADIR */ + ATA_DFLAG_CFG_MASK = (1 << 12) - 1, + + ATA_DFLAG_PIO = (1 << 12), /* device limited to PIO mode */ + ATA_DFLAG_NCQ_OFF = (1 << 13), /* device limited to non-NCQ mode */ + ATA_DFLAG_SPUNDOWN = (1 << 14), /* XXX: for spindown_compat */ + ATA_DFLAG_SLEEPING = (1 << 15), /* device is sleeping */ + ATA_DFLAG_DUBIOUS_XFER = (1 << 16), /* data transfer not verified */ + ATA_DFLAG_INIT_MASK = (1 << 24) - 1, + + ATA_DFLAG_DETACH = (1 << 24), + ATA_DFLAG_DETACHED = (1 << 25), + + /* struct ata_link flags */ + ATA_LFLAG_HRST_TO_RESUME = (1 << 0), /* hardreset to resume link */ + ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), /* can't wait for the first D2H + * Register FIS clearing BSY */ + ATA_LFLAG_NO_SRST = (1 << 2), /* avoid softreset */ + ATA_LFLAG_ASSUME_ATA = (1 << 3), /* assume ATA class */ + ATA_LFLAG_ASSUME_SEMB = (1 << 4), /* assume SEMB class */ + ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, + ATA_LFLAG_NO_RETRY = (1 << 5), /* don't retry this link */ + ATA_LFLAG_DISABLED = (1 << 6), /* link is disabled */ + + /* struct ata_port flags */ + ATA_FLAG_SLAVE_POSS = (1 << 0), + ATA_FLAG_SATA = (1 << 1), + ATA_FLAG_NO_LEGACY = (1 << 2), /* no legacy mode check */ + ATA_FLAG_MMIO = (1 << 3), /* use MMIO, not PIO */ + ATA_FLAG_SRST = (1 << 4), /* (obsolete) use ATA SRST, not E.D.D. */ + ATA_FLAG_SATA_RESET = (1 << 5), /* (obsolete) use COMRESET */ + ATA_FLAG_NO_ATAPI = (1 << 6), /* No ATAPI support */ + ATA_FLAG_PIO_DMA = (1 << 7), /* PIO cmds via DMA */ + ATA_FLAG_PIO_LBA48 = (1 << 8), /* Host DMA engine is LBA28 only */ + ATA_FLAG_PIO_POLLING = (1 << 9), /* use polling PIO if LLD + * doesn't handle PIO interrupts */ + ATA_FLAG_NCQ = (1 << 10), /* host supports NCQ */ + ATA_FLAG_DEBUGMSG = (1 << 13), + ATA_FLAG_IGN_SIMPLEX = (1 << 15), /* ignore SIMPLEX */ + ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */ + ATA_FLAG_ACPI_SATA = (1 << 17), /* need native SATA ACPI layout */ + ATA_FLAG_AN = (1 << 18), /* controller supports AN */ + ATA_FLAG_PMP = (1 << 19), /* controller supports PMP */ + ATA_FLAG_IPM = (1 << 20), /* driver can handle IPM */ + + ATA_FLAG_DISABLED = (1 << 23), /* port is disabled, ignore it */ + + /* struct ata_port pflags */ + ATA_PFLAG_EH_PENDING = (1 << 0), /* EH pending */ + ATA_PFLAG_EH_IN_PROGRESS = (1 << 1), /* EH in progress */ + ATA_PFLAG_FROZEN = (1 << 2), /* port is frozen */ + ATA_PFLAG_RECOVERED = (1 << 3), /* recovery action performed */ + ATA_PFLAG_LOADING = (1 << 4), /* boot/loading probe */ + ATA_PFLAG_UNLOADING = (1 << 5), /* module is unloading */ + ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), /* SCSI hotplug scheduled */ + ATA_PFLAG_INITIALIZING = (1 << 7), /* being initialized, don't touch */ + ATA_PFLAG_RESETTING = (1 << 8), /* reset in progress */ + ATA_PFLAG_SUSPENDED = (1 << 17), /* port is suspended (power) */ + ATA_PFLAG_PM_PENDING = (1 << 18), /* PM operation pending */ + + /* struct ata_queued_cmd flags */ + ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */ + ATA_QCFLAG_DMAMAP = (1 << 1), /* SG table is DMA mapped */ + ATA_QCFLAG_IO = (1 << 3), /* standard IO command */ + ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */ + ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */ + ATA_QCFLAG_QUIET = (1 << 6), /* don't report device error */ + + ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */ + ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */ + ATA_QCFLAG_EH_SCHEDULED = (1 << 18), /* EH scheduled (obsolete) */ + + /* host set flags */ + ATA_HOST_SIMPLEX = (1 << 0), + ATA_HOST_STARTED = (1 << 1), /* Host started */ + + /* various lengths of time */ + ATA_TMOUT_BOOT = 30 * 100, /* heuristic */ + ATA_TMOUT_BOOT_QUICK = 7 * 100, /* heuristic */ + ATA_TMOUT_INTERNAL = 30 * 100, + ATA_TMOUT_INTERNAL_QUICK = 5 * 100, + + /* FIXME: GoVault needs 2s but we can't afford that without + * parallel probing. 800ms is enough for iVDR disk + * HHD424020F7SV00. Increase to 2secs when parallel probing + * is in place. + */ + ATA_TMOUT_FF_WAIT = 4 * 100 / 5, + + /* ATA bus states */ + BUS_UNKNOWN = 0, + BUS_DMA = 1, + BUS_IDLE = 2, + BUS_NOINTR = 3, + BUS_NODATA = 4, + BUS_TIMER = 5, + BUS_PIO = 6, + BUS_EDD = 7, + BUS_IDENTIFY = 8, + BUS_PACKET = 9, + + /* SATA port states */ + PORT_UNKNOWN = 0, + PORT_ENABLED = 1, + PORT_DISABLED = 2, + + /* encoding various smaller bitmaps into a single + * unsigned long bitmap + */ + ATA_NR_PIO_MODES = 7, + ATA_NR_MWDMA_MODES = 5, + ATA_NR_UDMA_MODES = 8, + + ATA_SHIFT_PIO = 0, + ATA_SHIFT_MWDMA = ATA_SHIFT_PIO + ATA_NR_PIO_MODES, + ATA_SHIFT_UDMA = ATA_SHIFT_MWDMA + ATA_NR_MWDMA_MODES, + + /* size of buffer to pad xfers ending on unaligned boundaries */ + ATA_DMA_PAD_SZ = 4, + + /* ering size */ + ATA_ERING_SIZE = 32, + + ATA_DEFER_LINK = 1, + ATA_DEFER_PORT = 2, + + /* desc_len for ata_eh_info and context */ + ATA_EH_DESC_LEN = 80, + + /* reset / recovery action types */ + ATA_EH_REVALIDATE = (1 << 0), + ATA_EH_SOFTRESET = (1 << 1), + ATA_EH_HARDRESET = (1 << 2), + ATA_EH_ENABLE_LINK = (1 << 3), + ATA_EH_LPM = (1 << 4), /* link power management action */ + + ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, + ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, + + /* ata_eh_info->flags */ + ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ + ATA_EHI_RESUME_LINK = (1 << 1), /* resume link (reset modifier) */ + ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */ + ATA_EHI_QUIET = (1 << 3), /* be quiet */ + + ATA_EHI_DID_SOFTRESET = (1 << 16), /* already soft-reset this port */ + ATA_EHI_DID_HARDRESET = (1 << 17), /* already soft-reset this port */ + ATA_EHI_PRINTINFO = (1 << 18), /* print configuration info */ + ATA_EHI_SETMODE = (1 << 19), /* configure transfer mode */ + ATA_EHI_POST_SETMODE = (1 << 20), /* revaildating after setmode */ + + ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET, + ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, + + /* max tries if error condition is still set after ->error_handler */ + ATA_EH_MAX_TRIES = 5, + + /* how hard are we gonna try to probe/recover devices */ + ATA_PROBE_MAX_TRIES = 3, + ATA_EH_DEV_TRIES = 3, + ATA_EH_PMP_TRIES = 5, + ATA_EH_PMP_LINK_TRIES = 3, + + SATA_PMP_SCR_TIMEOUT = 250, + + /* Horkage types. May be set by libata or controller on drives + (some horkage may be drive/controller pair dependant */ + + ATA_HORKAGE_DIAGNOSTIC = (1 << 0), /* Failed boot diag */ + ATA_HORKAGE_NODMA = (1 << 1), /* DMA problems */ + ATA_HORKAGE_NONCQ = (1 << 2), /* Don't use NCQ */ + ATA_HORKAGE_MAX_SEC_128 = (1 << 3), /* Limit max sects to 128 */ + ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */ + ATA_HORKAGE_SKIP_PM = (1 << 5), /* Skip PM operations */ + ATA_HORKAGE_HPA_SIZE = (1 << 6), /* native size off by one */ + ATA_HORKAGE_IPM = (1 << 7), /* Link PM problems */ + ATA_HORKAGE_IVB = (1 << 8), /* cbl det validity bit bugs */ + ATA_HORKAGE_STUCK_ERR = (1 << 9), /* stuck ERR on next PACKET */ + + /* DMA mask for user DMA control: User visible values; DO NOT renumber */ + ATA_DMA_MASK_ATA = (1 << 0), /* DMA on ATA Disk */ + ATA_DMA_MASK_ATAPI = (1 << 1), /* DMA on ATAPI */ + ATA_DMA_MASK_CFA = (1 << 2), /* DMA on CF Card */ + + /* ATAPI command types */ + ATAPI_READ = 0, /* READs */ + ATAPI_WRITE = 1, /* WRITEs */ + ATAPI_READ_CD = 2, /* READ CD [MSF] */ + ATAPI_PASS_THRU = 3, /* SAT pass-thru */ + ATAPI_MISC = 4, /* the rest */ +}; + +enum ata_completion_errors { + AC_ERR_DEV = (1 << 0), /* device reported error */ + AC_ERR_HSM = (1 << 1), /* host state machine violation */ + AC_ERR_TIMEOUT = (1 << 2), /* timeout */ + AC_ERR_MEDIA = (1 << 3), /* media error */ + AC_ERR_ATA_BUS = (1 << 4), /* ATA bus error */ + AC_ERR_HOST_BUS = (1 << 5), /* host bus error */ + AC_ERR_SYSTEM = (1 << 6), /* system error */ + AC_ERR_INVALID = (1 << 7), /* invalid argument */ + AC_ERR_OTHER = (1 << 8), /* unknown */ + AC_ERR_NODEV_HINT = (1 << 9), /* polling device detection hint */ + AC_ERR_NCQ = (1 << 10), /* marker for offending NCQ qc */ +}; + +enum ata_xfer_mask { + ATA_MASK_PIO = ((1LU << ATA_NR_PIO_MODES) - 1) << ATA_SHIFT_PIO, + ATA_MASK_MWDMA = ((1LU << ATA_NR_MWDMA_MODES) - 1) << ATA_SHIFT_MWDMA, + ATA_MASK_UDMA = ((1LU << ATA_NR_UDMA_MODES) - 1) << ATA_SHIFT_UDMA, +}; + +struct ata_port_info { + struct scsi_host_template *sht; + unsigned long flags; + unsigned long link_flags; + unsigned long pio_mask; + unsigned long mwdma_mask; + unsigned long udma_mask; + const struct ata_port_operations *port_ops; + void *private_data; +}; + +struct ata_ioports { + void __iomem *cmd_addr; + void __iomem *data_addr; + void __iomem *error_addr; + void __iomem *feature_addr; + void __iomem *nsect_addr; + void __iomem *lbal_addr; + void __iomem *lbam_addr; + void __iomem *lbah_addr; + void __iomem *device_addr; + void __iomem *status_addr; + void __iomem *command_addr; + void __iomem *altstatus_addr; + void __iomem *ctl_addr; + void __iomem *bmdma_addr; + void __iomem *scr_addr; +}; + +struct ata_host { + void __iomem * const *iomap; + unsigned int n_ports; + void *private_data; + const struct ata_port_operations *ops; + unsigned long flags; + struct ata_port *simplex_claimed; /* channel owning the DMA */ + struct ata_port *ports[0]; +}; + +struct ata_port_stats { + unsigned long unhandled_irq; + unsigned long idle_irq; + unsigned long rw_reqbuf; +}; + +struct ata_device { + struct ata_link *link; + unsigned int devno; /* 0 or 1 */ + unsigned long flags; /* ATA_DFLAG_xxx */ + unsigned int horkage; /* List of broken features */ + struct scsi_device *sdev; /* attached SCSI device */ +#ifdef CONFIG_ATA_ACPI + acpi_handle acpi_handle; + union acpi_object *gtf_cache; +#endif + /* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */ + u64 n_sectors; /* size of device, if ATA */ + unsigned int class; /* ATA_DEV_xxx */ + + union { + u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ + u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */ + }; + + u8 pio_mode; + u8 dma_mode; + u8 xfer_mode; + unsigned int xfer_shift; /* ATA_SHIFT_xxx */ + + unsigned int multi_count; /* sectors count for + *READ/WRITE MULTIPLE */ + unsigned int max_sectors; /* per-device max sectors */ + unsigned int cdb_len; + + /* per-dev xfer mask */ + unsigned long pio_mask; + unsigned long mwdma_mask; + unsigned long udma_mask; + + /* for CHS addressing */ + u16 cylinders; /* Number of cylinders */ + u16 heads; /* Number of heads */ + u16 sectors; /* Number of sectors per track */ + + /* error history */ + int spdn_cnt; +}; + +enum dma_data_direction { + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, + DMA_NONE = 3, +}; + +struct ata_link { + struct ata_port *ap; + int pmp; /* port multiplier port # */ + unsigned int active_tag; /* active tag on this link */ + u32 sactive; /* active NCQ commands */ + + unsigned int flags; /* ATA_LFLAG_xxx */ + + unsigned int hw_sata_spd_limit; + unsigned int sata_spd_limit; + unsigned int sata_spd; /* current SATA PHY speed */ + + struct ata_device device[2]; +}; + +struct ata_port { + unsigned long flags; /* ATA_FLAG_xxx */ + unsigned int pflags; /* ATA_PFLAG_xxx */ + unsigned int print_id; /* user visible unique port ID */ + unsigned int port_no; /* 0 based port no. inside the host */ + + struct ata_ioports ioaddr; /* ATA cmd/ctl/dma register blocks */ + + u8 ctl; /* cache of ATA control register */ + u8 last_ctl; /* Cache last written value */ + unsigned int pio_mask; + unsigned int mwdma_mask; + unsigned int udma_mask; + unsigned int cbl; /* cable type; ATA_CBL_xxx */ + + struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; + unsigned long qc_allocated; + unsigned int qc_active; + int nr_active_links; /* #links with active qcs */ + + struct ata_link link; /* host default link */ + + int nr_pmp_links; /* nr of available PMP links */ + struct ata_link *pmp_link; /* array of PMP links */ + struct ata_link *excl_link; /* for PMP qc exclusion */ + + struct ata_port_stats stats; + struct ata_host *host; + + struct device *dev; + void *port_task_data; + + unsigned int hsm_task_state; + + u32 msg_enable; + void *private_data; + unsigned char *pdata; +}; +#endif /* _SATA_DWC_H_ */ diff -purN u-boot-2009.03/include/configs/canyonlands.h u-boot-2009.03-sata/include/configs/canyonlands.h --- u-boot-2009.03/include/configs/canyonlands.h 2009-03-22 06:04:41.000000000 +0900 +++ u-boot-2009.03-sata/include/configs/canyonlands.h 2009-03-26 18:15:30.000000000 +0900 @@ -454,6 +454,7 @@ #define CONFIG_CMD_SDRAM #define CONFIG_CMD_SNTP #define CONFIG_CMD_USB +#define CONFIG_CMD_SCSI #elif defined(CONFIG_GLACIER) #define CONFIG_CMD_DATE #define CONFIG_CMD_DTT @@ -517,6 +518,22 @@ #endif /* CONFIG_460GT */
/*----------------------------------------------------------------------- + * S-ATA driver setup + *----------------------------------------------------------------------*/ +#define CONFIG_SATA_DWC + +#ifdef CONFIG_SATA_DWC +#define CONFIG_LIBATA +#define CONFIG_SYS_SCSI_MAX_SCSI_ID 1 /* SCSI ID */ +#define CONFIG_SYS_SCSI_MAX_LUN 1 /* SCSI LUN */ +#define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \ + CONFIG_SYS_SCSI_MAX_LUN) +#define CONFIG_SYS_SCSI_MAXDEVICE CONFIG_SYS_SCSI_MAX_DEVICE +#define SATA_BASE_ADDR 0xe20d1000 /* PPC460EX SATA Base Address */ +#define SATA_DMA_REG_ADDR 0xe20d0800 /* PPC460EX SATA Base Address */ +#endif + +/*----------------------------------------------------------------------- * External Bus Controller (EBC) Setup *----------------------------------------------------------------------*/
Regards, Kazuaki Ichinohe

On Thursday 26 March 2009, Kazuaki Ichinohe wrote:
Thank you for the reply. My answer is described in the beginning.
OK, I just tried to apply your patch for basic testing. Didn't work though. Here the error log:
[stefan@kubuntu u-boot (master)]$ patch -p1 < patches_sata/[U-Boot]\ [PATCH]\ Canyonlands\ SATA\ harddisk\ driver.mbox patching file common/cmd_scsi.c Hunk #1 FAILED at 47. Hunk #2 FAILED at 181. Hunk #3 FAILED at 192. Hunk #4 FAILED at 453. 4 out of 4 hunks FAILED -- saving rejects to file common/cmd_scsi.c.rej patching file drivers/block/Makefile Hunk #1 FAILED at 34. 1 out of 1 hunk FAILED -- saving rejects to file drivers/block/Makefile.rej patching file drivers/block/sata_dwc.c patching file drivers/block/sata_dwc.h patching file include/configs/canyonlands.h Hunk #1 FAILED at 454. Hunk #2 FAILED at 518. 2 out of 2 hunks FAILED -- saving rejects to file include/configs/canyonlands.h.rej
Seems that you didn't base your patch on the latest git version of U-Boot. Please rebase your patch again that it applies cleanly. And again, please use the git tools to generate the patch. Or at least send the patch in a git compatible way, so that it can be applied using "git am".
Thanks.
Best regards, Stefan
===================================================================== DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de =====================================================================

Dear Kazuaki Ichinohe,
In message 49CB5F77.1060304@fsi.co.jp you wrote: ...
Why do you add this 460EX SATA support to cmd_scsi.c? Wouldn't cmd_sata.c be a better place? Or did I miss something here?
The cmd_scsi.c which define CONFIG_CMD_SCSI are modified because I want to use scsiboot command of U-BOOT.
This makes no sense. It is a S-ATA driver, not a SCSI driver, and as such it has to be supported in the context of the S-ATA support.
I explicitly NAK the changes to the SCSI related files.
Best regards,
Wolfgang Denk

Hello Denk,
After confirming operation, I'll send sata_dwc.c with cmd_sata.c again.
Regards, Kazuaki Ichinohe
Wolfgang Denk wrote:
Dear Kazuaki Ichinohe,
In message 49CB5F77.1060304@fsi.co.jp you wrote: ...
Why do you add this 460EX SATA support to cmd_scsi.c? Wouldn't cmd_sata.c be a better place? Or did I miss something here?
The cmd_scsi.c which define CONFIG_CMD_SCSI are modified because I want to use scsiboot command of U-BOOT.
This makes no sense. It is a S-ATA driver, not a SCSI driver, and as such it has to be supported in the context of the S-ATA support.
I explicitly NAK the changes to the SCSI related files.
Best regards,
Wolfgang Denk

Hello Denk, Stefan,
This patch adds a SATA harddisk driver for the canyonlands. This patch is kernel driver's porting. This pach corresponded to not cmd_scsi but cmd_sata.
[environment variable, boot script] setenv bootargs root=/dev/sda7 rw setenv bootargs ${bootargs} console=ttyS0,115200 ext2load sata 0:2 0x400000 /canyonlands/uImage ext2load sata 0:2 0x800000 /canyonlands/canyonlands.dtb fdt addr 0x800000 0x4000 bootm 0x400000 - 0x800000
If you drive SATA-2 disk on Canyonlands, you must change parts from PI2PCIE212 to PI2PCIE2212 on U25. We confirmed to boot by using following disk.
1.Vender: Fujitsu Type: MHW2040BS 2.Vender: Fujitsu Type: MHW2060BK 3.Vendor: HAGIWARA SYS-COM:HFD25S-032GT 4.Vender: WesternDigital Type: WD3200BJKT (CONFIG_LBA48 required) 5.Vender: WesternDigital Type: WD3200BEVT (CONFIG_LBA48 required) 6.Vender: hitachi Type: HTS543232L9A300 (CONFIG_LBA48 required) 7.Vender: Seagate Type: ST31000333AS (CONFIG_LBA48 required) 8.Vender: Transcend Type: TS32GSSD25S-M 9.Vender: MTRON Type: MSD-SATA1525-016
Signed-off-by: Kazuaki Ichinohe <kazuichi at fsi.co.jp> ---
[patch] --- drivers/block/Makefile | 1 + drivers/block/sata_dwc.c | 2110 +++++++++++++++++++++++++++++++++++++++++ drivers/block/sata_dwc.h | 463 +++++++++ include/configs/canyonlands.h | 16 + 4 files changed, 2590 insertions(+), 0 deletions(-) create mode 100644 drivers/block/sata_dwc.c create mode 100644 drivers/block/sata_dwc.h
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index eccefc1..e0af40e 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -35,6 +35,7 @@ COBJS-$(CONFIG_SATA_SIL3114) += sata_sil3114.o COBJS-$(CONFIG_SCSI_AHCI) += ahci.o COBJS-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o COBJS-$(CONFIG_SYSTEMACE) += systemace.o +COBJS-$(CONFIG_SATA_DWC) += sata_dwc.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/block/sata_dwc.c b/drivers/block/sata_dwc.c new file mode 100644 index 0000000..91211bb --- /dev/null +++ b/drivers/block/sata_dwc.c @@ -0,0 +1,2110 @@ +/* + * sata_dwc.c + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld mmiesfeld@amcc.com + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese sr@denx.de + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * This program is free software; you can redistribute + * it and/or modify it under the terms of the GNU + * General Public License as published by the + * Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + */ +/* + * SATA support based on the chip canyonlands. + * + * 04-17-2009 + * The local version of this driver for the canyonlands board + * does not use interrupts but polls the chip instead. + */ + +#include <common.h> +#include <command.h> +#include <pci.h> +#include <asm/processor.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <malloc.h> +#include <ata.h> +#include <linux/ctype.h> + +#include "sata_dwc.h" + +#define DMA_NUM_CHANS 1 +#define DMA_NUM_CHAN_REGS 8 + +#define AHB_DMA_BRST_DFLT 16 + +struct dmareg { + u32 low; + u32 high; +}; + +struct dma_chan_regs { + struct dmareg sar; + struct dmareg dar; + struct dmareg llp; + struct dmareg ctl; + struct dmareg sstat; + struct dmareg dstat; + struct dmareg sstatar; + struct dmareg dstatar; + struct dmareg cfg; + struct dmareg sgr; + struct dmareg dsr; +}; + +struct dma_interrupt_regs { + struct dmareg tfr; + struct dmareg block; + struct dmareg srctran; + struct dmareg dsttran; + struct dmareg error; +}; + +struct ahb_dma_regs { + struct dma_chan_regs chan_regs[DMA_NUM_CHAN_REGS]; + struct dma_interrupt_regs interrupt_raw; + struct dma_interrupt_regs interrupt_status; + struct dma_interrupt_regs interrupt_mask; + struct dma_interrupt_regs interrupt_clear; + struct dmareg statusInt; + struct dmareg rq_srcreg; + struct dmareg rq_dstreg; + struct dmareg rq_sgl_srcreg; + struct dmareg rq_sgl_dstreg; + struct dmareg rq_lst_srcreg; + struct dmareg rq_lst_dstreg; + struct dmareg dma_cfg; + struct dmareg dma_chan_en; + struct dmareg dma_id; + struct dmareg dma_test; + struct dmareg res1; + struct dmareg res2; + /* DMA Comp Params + * Param 6 = dma_param[0], Param 5 = dma_param[1], + * Param 4 = dma_param[2] ... + */ + struct dmareg dma_params[6]; +}; + +#define DMA_EN 0x00000001 +#define DMA_DI 0x00000000 +#define DMA_CHANNEL(ch) (0x00000001 << (ch)) +#define DMA_ENABLE_CHAN(ch) ((0x00000001 << (ch)) | \ + ((0x000000001 << (ch)) << 8)) +#define DMA_DISABLE_CHAN(ch) (0x00000000 | \ + ((0x000000001 << (ch)) << 8)) + +#define SATA_DWC_MAX_PORTS 1 +#define SATA_DWC_SCR_OFFSET 0x24 +#define SATA_DWC_REG_OFFSET 0x64 + +struct sata_dwc_regs { + u32 fptagr; + u32 fpbor; + u32 fptcr; + u32 dmacr; + u32 dbtsr; + u32 intpr; + u32 intmr; + u32 errmr; + u32 llcr; + u32 phycr; + u32 physr; + u32 rxbistpd; + u32 rxbistpd1; + u32 rxbistpd2; + u32 txbistpd; + u32 txbistpd1; + u32 txbistpd2; + u32 bistcr; + u32 bistfctr; + u32 bistsr; + u32 bistdecr; + u32 res[15]; + u32 testr; + u32 versionr; + u32 idr; + u32 unimpl[192]; + u32 dmadr[256]; +}; + +#define SATA_DWC_TXFIFO_DEPTH 0x01FF +#define SATA_DWC_RXFIFO_DEPTH 0x01FF + +#define SATA_DWC_DBTSR_MWR(size) ((size / 4) & SATA_DWC_TXFIFO_DEPTH) +#define SATA_DWC_DBTSR_MRD(size) (((size / 4) & \ + SATA_DWC_RXFIFO_DEPTH) << 16) +#define SATA_DWC_INTPR_DMAT 0x00000001 +#define SATA_DWC_INTPR_NEWFP 0x00000002 +#define SATA_DWC_INTPR_PMABRT 0x00000004 +#define SATA_DWC_INTPR_ERR 0x00000008 +#define SATA_DWC_INTPR_NEWBIST 0x00000010 +#define SATA_DWC_INTPR_IPF 0x10000000 +#define SATA_DWC_INTMR_DMATM 0x00000001 +#define SATA_DWC_INTMR_NEWFPM 0x00000002 +#define SATA_DWC_INTMR_PMABRTM 0x00000004 +#define SATA_DWC_INTMR_ERRM 0x00000008 +#define SATA_DWC_INTMR_NEWBISTM 0x00000010 + +#define SATA_DWC_DMACR_TMOD_TXCHEN 0x00000004 +#define SATA_DWC_DMACR_TXRXCH_CLEAR SATA_DWC_DMACR_TMOD_TXCHEN + +#define SATA_DWC_QCMD_MAX 32 + +#define SATA_DWC_SERROR_ERR_BITS 0x0FFF0F03 + +#define HSDEVP_FROM_AP(ap) (struct sata_dwc_device_port*) \ + (ap)->private_data + +struct sata_dwc_device { + struct device *dev; + struct ata_probe_ent *pe; + struct ata_host *host; + u8 *reg_base; + struct sata_dwc_regs *sata_dwc_regs; + int irq_dma; +}; + +struct sata_dwc_device_port { + struct sata_dwc_device *hsdev; + int cmd_issued[SATA_DWC_QCMD_MAX]; + u32 dma_chan[SATA_DWC_QCMD_MAX]; + int dma_pending[SATA_DWC_QCMD_MAX]; +}; + +enum { + SATA_DWC_CMD_ISSUED_NOT = 0, + SATA_DWC_CMD_ISSUED_PEND = 1, + SATA_DWC_CMD_ISSUED_EXEC = 2, + SATA_DWC_CMD_ISSUED_NODATA = 3, + + SATA_DWC_DMA_PENDING_NONE = 0, + SATA_DWC_DMA_PENDING_TX = 1, + SATA_DWC_DMA_PENDING_RX = 2, +}; + +#define msleep(a) udelay(a * 1000) +#define ssleep(a) msleep(a * 1000) + +static int ata_probe_timeout = (ATA_TMOUT_INTERNAL / 100); + +enum sata_dev_state { + SATA_INIT = 0, + SATA_READY = 1, + SATA_NODEVICE = 2, + SATA_ERROR = 3, +}; +enum sata_dev_state dev_state = SATA_INIT; + +static struct ahb_dma_regs *sata_dma_regs = 0; +static struct ata_host *phost; +static struct ata_port ap; +static struct ata_port *pap = ≈ +static struct ata_device ata_device; +static struct sata_dwc_device_port dwc_devp; + +static void *scr_addr_sstatus; +static u32 temp_n_block = 0; + +static unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, unsigned int buflen, + unsigned long timeout); +static unsigned int ata_dev_set_feature(struct ata_device *dev, + u8 enable,u8 feature); +static unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors); +static u8 ata_irq_on(struct ata_port *ap); +static struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, + unsigned int tag); +static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq); +static void ata_tf_to_host(struct ata_port *ap, + const struct ata_taskfile *tf); +static void ata_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf); +static unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc); +static u8 ata_check_altstatus(struct ata_port *ap); +static u8 ata_check_status(struct ata_port *ap); +static void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep); +static void ata_qc_issue(struct ata_queued_cmd *qc); +static void ata_tf_load(struct ata_port *ap, + const struct ata_taskfile *tf); +static int ata_dev_read_sectors(unsigned char* pdata, + unsigned long datalen, u32 block, u32 n_block); +static int ata_dev_write_sectors(unsigned char* pdata, + unsigned long datalen , u32 block, u32 n_block); +static void ata_std_dev_select(struct ata_port *ap, unsigned int device); +static void ata_qc_complete(struct ata_queued_cmd *qc); +static void __ata_qc_complete(struct ata_queued_cmd *qc); +static void fill_result_tf(struct ata_queued_cmd *qc); +static void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); +static void ata_mmio_data_xfer(struct ata_device *dev, + unsigned char *buf, + unsigned int buflen,int do_write); +static void ata_pio_task(struct ata_port *arg_ap); +static void __ata_port_freeze(struct ata_port *ap); +static int ata_port_freeze(struct ata_port *ap); +static void ata_qc_free(struct ata_queued_cmd *qc); +static void ata_pio_sectors(struct ata_queued_cmd *qc); +static void ata_pio_sector(struct ata_queued_cmd *qc); +static void ata_pio_queue_task(struct ata_port *ap, + void *data,unsigned long delay); +static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq); +static int sata_dwc_softreset(struct ata_port *ap); +static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, + unsigned int flags, u16 *id); +static int check_sata_dev_state(void); + +extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE]; + +static const struct ata_port_info sata_dwc_port_info[] = { + { + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING | + ATA_FLAG_SRST | ATA_FLAG_NCQ, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + }, +}; + +int init_sata (int dev) +{ + struct sata_dwc_device hsdev; + struct ata_host host; + struct ata_port_info pi = sata_dwc_port_info[0]; + struct ata_link *link; + struct sata_dwc_device_port hsdevp = dwc_devp; + u8 *base = 0; + u8 *sata_dma_regs_addr = 0; + u8 status; + unsigned long base_addr = 0; + int chan = 0; + int rc; + int i; + + phost = &host; + + base = (u8*)SATA_BASE_ADDR; + + hsdev.sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET); + + host.n_ports = SATA_DWC_MAX_PORTS; + + for (i = 0; i < SATA_DWC_MAX_PORTS; i++) { + ap.pflags |= ATA_PFLAG_INITIALIZING; + ap.flags = ATA_FLAG_DISABLED; + ap.print_id = -1; + ap.ctl = ATA_DEVCTL_OBS; + ap.host = &host; + ap.last_ctl = 0xFF; + + link = &ap.link; + link->ap = ≈ + link->pmp = 0; + link->active_tag = ATA_TAG_POISON; + link->hw_sata_spd_limit = 0; + + ap.port_no = i; + host.ports[i] = ≈ + } + + ap.pio_mask = pi.pio_mask; + ap.mwdma_mask = pi.mwdma_mask; + ap.udma_mask = pi.udma_mask; + ap.flags |= pi.flags; + ap.link.flags |= pi.link_flags; + + host.ports[0]->ioaddr.cmd_addr = base; + host.ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET; + scr_addr_sstatus = base + SATA_DWC_SCR_OFFSET; + + base_addr = (unsigned long)base; + + host.ports[0]->ioaddr.cmd_addr = (void *)base_addr + 0x00; + host.ports[0]->ioaddr.data_addr = (void *)base_addr + 0x00; + + host.ports[0]->ioaddr.error_addr = (void *)base_addr + 0x04; + host.ports[0]->ioaddr.feature_addr = (void *)base_addr + 0x04; + + host.ports[0]->ioaddr.nsect_addr = (void *)base_addr + 0x08; + + host.ports[0]->ioaddr.lbal_addr = (void *)base_addr + 0x0c; + host.ports[0]->ioaddr.lbam_addr = (void *)base_addr + 0x10; + host.ports[0]->ioaddr.lbah_addr = (void *)base_addr + 0x14; + + host.ports[0]->ioaddr.device_addr = (void *)base_addr + 0x18; + host.ports[0]->ioaddr.command_addr = (void *)base_addr + 0x1c; + host.ports[0]->ioaddr.status_addr = (void *)base_addr + 0x1c; + + host.ports[0]->ioaddr.altstatus_addr = (void *)base_addr + 0x20; + host.ports[0]->ioaddr.ctl_addr = (void *)base_addr + 0x20; + + sata_dma_regs_addr = (u8*)SATA_DMA_REG_ADDR; + sata_dma_regs = (void *__iomem)sata_dma_regs_addr; + + status = ata_check_altstatus(&ap); + + if (status == 0x7f) { + printf("Hard Disk not found.\n"); + dev_state = SATA_NODEVICE; + rc = FALSE; + return rc; + } + + printf("waitng for device ready."); + i = 0; + while (1) { + udelay (10000); + + status = ata_check_altstatus(&ap); + + if ((status & ATA_BUSY) == 0) { + printf("\n"); + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + + dev_state = SATA_NODEVICE; + rc = FALSE; + return rc; + } + if ((i >= 100) && ((i % 100) == 0)) + printf("."); + } + + rc = sata_dwc_softreset(&ap); + + if (rc) { + printf("sata_dwc : error. soft reset failed\n"); + return rc; + } + + for (chan = 0; chan < DMA_NUM_CHANS; chan++) { + out_le32(&(sata_dma_regs->interrupt_mask.error.low), + DMA_DISABLE_CHAN(chan)); + + out_le32(&(sata_dma_regs->interrupt_mask.tfr.low), + DMA_DISABLE_CHAN(chan)); + } + + out_le32(&(sata_dma_regs->dma_cfg.low), DMA_DI); + + out_le32(&hsdev.sata_dwc_regs->intmr, + SATA_DWC_INTMR_ERRM | + SATA_DWC_INTMR_PMABRTM); + + /* Unmask the error bits that should trigger + * an error interrupt by setting the error mask register. + */ + out_le32(&hsdev.sata_dwc_regs->errmr,SATA_DWC_SERROR_ERR_BITS); + + hsdev.host = ap.host; + memset(&hsdevp, 0, sizeof(hsdevp)); + hsdevp.hsdev = &hsdev; + + for (i = 0; i < SATA_DWC_QCMD_MAX; i++) + hsdevp.cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT; + + out_le32((void __iomem *)scr_addr_sstatus + 4, + in_le32((void __iomem *)scr_addr_sstatus + 4)); + + rc = 0; + return rc; +} + +static u8 ata_check_altstatus(struct ata_port *ap) +{ + u8 val = 0; + val = readb(ap->ioaddr.altstatus_addr); + return val; +} + +static int sata_dwc_softreset(struct ata_port *ap) +{ + u8 nsect,lbal = 0; + u8 tmp = 0; + u32 serror = 0; + u8 status = 0; + struct ata_ioports *ioaddr = &ap->ioaddr; + + serror = in_le32((void *)ap->ioaddr.scr_addr + (SCR_ERROR * 4)); + + writeb(0x55, ioaddr->nsect_addr); + writeb(0xaa, ioaddr->lbal_addr); + writeb(0xaa, ioaddr->nsect_addr); + writeb(0x55, ioaddr->lbal_addr); + writeb(0x55, ioaddr->nsect_addr); + writeb(0xaa, ioaddr->lbal_addr); + + nsect = readb(ioaddr->nsect_addr); + lbal = readb(ioaddr->lbal_addr); + + if ((nsect == 0x55) && (lbal == 0xaa)) { + printf("we found a device\n"); + } else { + printf("Not found a device.\n"); + dev_state = SATA_NODEVICE; + return FALSE; + } + + tmp = ATA_DEVICE_OBS; + writeb(tmp,ioaddr->device_addr); + writeb(ap->ctl,ioaddr->ctl_addr); + + udelay(200); + + writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr); + + udelay(200); + writeb(ap->ctl,ioaddr->ctl_addr); + + msleep(150); + status = ata_check_status(ap); + + msleep(50); + ata_check_status(ap); + + while (1) { + u8 status = ata_check_status(ap); + + if (!(status & ATA_BUSY)) + break; + + printf("Hard Disk status is BUSY.\n"); + msleep(50); + } + + tmp = ATA_DEVICE_OBS; + writeb(tmp,ioaddr->device_addr); + + nsect = readb(ioaddr->nsect_addr); + lbal = readb(ioaddr->lbal_addr); + + return 0; +} + +static u8 ata_check_status(struct ata_port *ap) +{ + u8 val = 0; + val = readb(ap->ioaddr.status_addr); + return val; +} + +static int ata_id_has_hipm(const u16 *id) +{ + u16 val = id[76]; + + if (val == 0 || val == 0xffff) + return -1; + + return val & (1 << 9); +} + +static int ata_id_has_dipm(const u16 *id) +{ + u16 val = id[78]; + + if (val == 0 || val == 0xffff) + return -1; + + return val & (1 << 3); +} + +int scan_sata (int dev) +{ + int i; + int rc; + u8 status; + const u16 *id; + struct ata_device *ata_dev = &ata_device; + unsigned long pio_mask, mwdma_mask, udma_mask; + unsigned long xfer_mask; + char revbuf[7]; + u16 iobuf[ATA_SECTOR_WORDS]; + + memset ( iobuf, 0, sizeof(iobuf)); + + if (dev_state == SATA_NODEVICE) + return 1; + + printf("waitng for device ready."); + i = 0; + while (1) { + udelay (10000); + + status = ata_check_altstatus(&ap); + + if ((status & ATA_BUSY) == 0) { + printf("\n"); + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + + dev_state = SATA_NODEVICE; + return 1; + } + if ((i >= 100) && ((i % 100) == 0)) + printf("."); + } + + udelay (1000); + + rc = ata_dev_read_id(ata_dev, &ata_dev->class, + ATA_READID_POSTRESET,ata_dev->id); + if (rc) { + printf("sata_dwc : error. failed sata scan\n"); + return 1; + } + + /* SATA drives indicate we have a bridge. We don't know which + * end of the link the bridge is which is a problem + */ + if (ata_id_is_sata(ata_dev->id)) + ap.cbl = ATA_CBL_SATA; + + id = ata_dev->id; + + ata_dev->flags &= ~ATA_DFLAG_CFG_MASK; + ata_dev->max_sectors = 0; + ata_dev->cdb_len = 0; + ata_dev->n_sectors = 0; + ata_dev->cylinders = 0; + ata_dev->heads = 0; + ata_dev->sectors = 0; + + if (id[ATA_ID_FIELD_VALID] & (1 << 1)) { + pio_mask = id[ATA_ID_PIO_MODES] & 0x03; + pio_mask <<= 3; + pio_mask |= 0x7; + } else { + /* If word 64 isn't valid then Word 51 high byte holds + * the PIO timing number for the maximum. Turn it into + * a mask. + */ + u8 mode = (id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF; + if (mode < 5) { + pio_mask = (2 << mode) - 1; + } else { + pio_mask = 1; + } + } + + mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07; + + if (ata_id_is_cfa(id)) { + int pio = id[163] & 0x7; + int dma = (id[163] >> 3) & 7; + + if (pio) + pio_mask |= (1 << 5); + if (pio > 1) + pio_mask |= (1 << 6); + if (dma) + mwdma_mask |= (1 << 3); + if (dma > 1) + mwdma_mask |= (1 << 4); + } + + udma_mask = 0; + if (id[ATA_ID_FIELD_VALID] & (1 << 2)) + udma_mask = id[ATA_ID_UDMA_MODES] & 0xff; + + xfer_mask = ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) | + ((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) | + ((udma_mask << ATA_SHIFT_UDMA) & ATA_MASK_UDMA); + + if (ata_dev->class == ATA_DEV_ATA) { + if (ata_id_is_cfa(id)) { + if (id[162] & 1) + printf("supports DRM functions and may " + "not be fully accessable.\n"); + sprintf(revbuf, "%s", "CFA"); + } else { + if (ata_id_has_tpm(id)) + printf("supports DRM functions and may " + "not be fully accessable.\n"); + } + + ata_dev->n_sectors = ata_id_n_sectors((u16*)id); + + if (ata_dev->id[59] & 0x100) + ata_dev->multi_count = ata_dev->id[59] & 0xff; + + if (ata_id_has_lba(id)) { + const char *lba_desc; + char ncq_desc[20]; + + lba_desc = "LBA"; + ata_dev->flags |= ATA_DFLAG_LBA; + if (ata_id_has_lba48(id)) { + ata_dev->flags |= ATA_DFLAG_LBA48; + lba_desc = "LBA48"; + + if (ata_dev->n_sectors >= (1UL << 28) && + ata_id_has_flush_ext(id)) + ata_dev->flags |= ATA_DFLAG_FLUSH_EXT; + } + if (!ata_id_has_ncq(ata_dev->id)) + ncq_desc[0] = '\0'; + + if (ata_dev->horkage & ATA_HORKAGE_NONCQ) + sprintf(ncq_desc, "%s", "NCQ (not used)"); + + if (ap.flags & ATA_FLAG_NCQ) + ata_dev->flags |= ATA_DFLAG_NCQ; + } + ata_dev->cdb_len = 16; + } + ata_dev->max_sectors = ATA_MAX_SECTORS; + if (ata_dev->flags & ATA_DFLAG_LBA48) + ata_dev->max_sectors = ATA_MAX_SECTORS_LBA48; + + if (!(ata_dev->horkage & ATA_HORKAGE_IPM)) { + if (ata_id_has_hipm(ata_dev->id)) + ata_dev->flags |= ATA_DFLAG_HIPM; + if (ata_id_has_dipm(ata_dev->id)) + ata_dev->flags |= ATA_DFLAG_DIPM; + } + + if ((ap.cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ata_dev->id))) { + ata_dev->udma_mask &= ATA_UDMA5; + ata_dev->max_sectors = ATA_MAX_SECTORS; + } + + if (ata_dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { + printf("Drive reports diagnostics failure." + "This may indicate a drive\n"); + printf("fault or invalid emulation." + "Contact drive vendor for information.\n"); + } + + rc = check_sata_dev_state(); + + ata_id_c_string (ata_dev->id, + (unsigned char *)sata_dev_desc[dev].revision, + ATA_ID_FW_REV, sizeof(sata_dev_desc[dev].revision)); + ata_id_c_string (ata_dev->id, + (unsigned char *)sata_dev_desc[dev].vendor, + ATA_ID_PROD, sizeof(sata_dev_desc[dev].vendor)); + ata_id_c_string (ata_dev->id, + (unsigned char *)sata_dev_desc[dev].product, + ATA_ID_SERNO, sizeof(sata_dev_desc[dev].product)); + + sata_dev_desc[dev].lba = (u32) ata_dev->n_sectors; + +#ifdef CONFIG_LBA48 + if (ata_dev->id[83] & (1 << 10)) { + sata_dev_desc[dev].lba48 = 1; + } else { + sata_dev_desc[dev].lba48 = 0; + } +#endif + + return 0; +} + +static u8 ata_busy_wait(struct ata_port *ap, + unsigned int bits,unsigned int max) +{ + u8 status; + + do { + udelay(10); + status = ata_check_status(ap); + max--; + } while (status != 0xff && (status & bits) && (max > 0)); + + return status; +} + +static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, + unsigned int flags, u16 *id) +{ + struct ata_port *ap = pap; + unsigned int class = *p_class; + struct ata_taskfile tf; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1, tried_spinup = 0; + u8 status; + int rc; + + status = ata_busy_wait(ap, ATA_BUSY, 30000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + rc = FALSE; + return rc; + } + + ata_dev_select(ap, dev->devno, 1, 1); + +retry: + memset(&tf, 0, sizeof(tf)); + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + tf.ctl = ap->ctl; + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_ID_ATA; + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + + /* Device presence detection is unreliable on some + * controllers. Always poll IDENTIFY if available. + */ + tf.flags |= ATA_TFLAG_POLLING; + + temp_n_block = 1; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, + sizeof(id[0]) * ATA_ID_WORDS, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + unsigned int id_cnt; + + for (id_cnt = 0; id_cnt < ATA_ID_WORDS; id_cnt++) + id[id_cnt] = le16_to_cpu(id[id_cnt]); + + + rc = -EINVAL; + reason = "device reports invalid type"; + + if (class == ATA_DEV_ATA) { + if (!ata_id_is_ata(id) && !ata_id_is_cfa(id)) + goto err_out; + } else { + if (ata_id_is_ata(id)) + goto err_out; + } + if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) { + tried_spinup = 1; + /* + * Drive powered-up in standby mode, and requires a specific + * SET_FEATURES spin-up subcommand before it will accept + * anything other than the original IDENTIFY command. + */ + err_mask = ata_dev_set_feature(dev, SETFEATURES_SPINUP, 0); + if (err_mask && id[2] != 0x738c) { + rc = -EIO; + reason = "SPINUP failed"; + goto err_out; + } + /* + * If the drive initially returned incomplete IDENTIFY info, + * we now must reissue the IDENTIFY command. + */ + if (id[2] == 0x37c8) + goto retry; + } + + if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) { + /* + * The exact sequence expected by certain pre-ATA4 drives is: + * SRST RESET + * IDENTIFY (optional in early ATA) + * INITIALIZE DEVICE PARAMETERS (later IDE and ATA) + * anything else.. + * Some drives were very specific about that exact sequence. + * + * Note that ATA4 says lba is mandatory so the second check + * shoud never trigger. + */ + if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { + err_mask = ata_dev_init_params(dev, id[3], id[6]); + if (err_mask) { + rc = -EIO; + reason = "INIT_DEV_PARAMS failed"; + goto err_out; + } + + /* current CHS translation info (id[53-58]) might be + * changed. reread the identify device info. + */ + flags &= ~ATA_READID_POSTRESET; + goto retry; + } + } + + *p_class = class; + return 0; + +err_out: + return rc; +} + +static u8 ata_wait_idle(struct ata_port *ap) +{ + u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + return status; +} + +static void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep) +{ + if (wait) + ata_wait_idle(ap); + + ata_std_dev_select(ap, device); + + if (wait) + ata_wait_idle(ap); +} + +static void ata_std_dev_select(struct ata_port *ap, unsigned int device) +{ + u8 tmp; + + if (device == 0) { + tmp = ATA_DEVICE_OBS; + } else { + tmp = ATA_DEVICE_OBS | ATA_DEV1; + } + + writeb(tmp, ap->ioaddr.device_addr); + + readb(ap->ioaddr.altstatus_addr); + + udelay(1); +} + +static int waiting_for_reg_state(volatile u8 *offset, + int timeout_msec, + u32 sign) +{ + int i; + u32 status; + + for (i = 0; i < timeout_msec; i++) { + status = readl(offset); + if ((status & sign) != 0) + break; + msleep(1); + } + + return (i < timeout_msec) ? 0 : -1; +} + +static void ata_qc_reinit(struct ata_queued_cmd *qc) +{ + qc->dma_dir = DMA_NONE; + qc->flags = 0; + qc->nbytes = qc->extrabytes = qc->curbytes = 0; + qc->n_elem = 0; + qc->err_mask = 0; + qc->sect_size = ATA_SECT_SIZE; + qc->nbytes = ATA_SECT_SIZE * temp_n_block; + + memset(&qc->tf, 0, sizeof(qc->tf)); + qc->tf.ctl = 0; + qc->tf.device = ATA_DEVICE_OBS; + + qc->result_tf.command = ATA_DRDY; + qc->result_tf.feature = 0; +} + +struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, + unsigned int tag) +{ + if (tag < ATA_MAX_QUEUE) + return &ap->qcmd[tag]; + return NULL; +} + +static void __ata_port_freeze(struct ata_port *ap) +{ + printf("set port freeze.\n"); + ap->pflags |= ATA_PFLAG_FROZEN; +} + +static int ata_port_freeze(struct ata_port *ap) +{ + __ata_port_freeze(ap); + return 0; +} + +unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, unsigned int buflen, + unsigned long timeout) +{ + struct ata_link *link = dev->link; + struct ata_port *ap = pap; + struct ata_queued_cmd *qc; + unsigned int tag, preempted_tag; + u32 preempted_sactive, preempted_qc_active; + int preempted_nr_active_links; + unsigned int err_mask; + int rc = 0; + u8 status; + + status = ata_busy_wait(ap, ATA_BUSY, 300000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + rc = FALSE; + return rc; + } + + if (ap->pflags & ATA_PFLAG_FROZEN) + return AC_ERR_SYSTEM; + + tag = ATA_TAG_INTERNAL; + + if (test_and_set_bit(tag, &ap->qc_allocated)) { + rc = FALSE; + return rc; + } + + qc = __ata_qc_from_tag(ap, tag); + qc->tag = tag; + qc->ap = ap; + qc->dev = dev; + + ata_qc_reinit(qc); + + preempted_tag = link->active_tag; + preempted_sactive = link->sactive; + preempted_qc_active = ap->qc_active; + preempted_nr_active_links = ap->nr_active_links; + link->active_tag = ATA_TAG_POISON; + link->sactive = 0; + ap->qc_active = 0; + ap->nr_active_links = 0; + + qc->tf = *tf; + if (cdb) + memcpy(qc->cdb, cdb, ATAPI_CDB_LEN); + qc->flags |= ATA_QCFLAG_RESULT_TF; + qc->dma_dir = dma_dir; + qc->private_data = 0; + + ata_qc_issue(qc); + + if (!timeout) + timeout = ata_probe_timeout * 1000 / HZ; + + status = ata_busy_wait(ap, ATA_BUSY, 30000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + printf("altstatus = 0x%x.\n",status); + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + if (waiting_for_reg_state(ap->ioaddr.altstatus_addr,1000,0x8)) { + u8 status = 0; + u8 errorStatus = 0; + + status = readb( ap->ioaddr.altstatus_addr); + if ((status & 0x01) != 0) { + errorStatus = readb( ap->ioaddr.feature_addr); + if (errorStatus == 0x04 && + qc->tf.command == ATA_CMD_PIO_READ_EXT){ + printf("Hard Disk doesn't support LBA48\n"); + dev_state = SATA_ERROR; + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + } + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + status = ata_busy_wait(ap, ATA_BUSY, 10); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + ata_pio_task(ap); + + if (!rc) { + if (qc->flags & ATA_QCFLAG_ACTIVE) { + qc->err_mask |= AC_ERR_TIMEOUT; + ata_port_freeze(ap); + } + } + + if (qc->flags & ATA_QCFLAG_FAILED) { + if (qc->result_tf.command & (ATA_ERR | ATA_DF)) + qc->err_mask |= AC_ERR_DEV; + + if (!qc->err_mask) + qc->err_mask |= AC_ERR_OTHER; + + if (qc->err_mask & ~AC_ERR_OTHER) + qc->err_mask &= ~AC_ERR_OTHER; + } + + *tf = qc->result_tf; + err_mask = qc->err_mask; + ata_qc_free(qc); + link->active_tag = preempted_tag; + link->sactive = preempted_sactive; + ap->qc_active = preempted_qc_active; + ap->nr_active_links = preempted_nr_active_links; + + if (ap->flags & ATA_FLAG_DISABLED) { + err_mask |= AC_ERR_SYSTEM; + ap->flags &= ~ATA_FLAG_DISABLED; + } + + return err_mask; +} + +static void ata_qc_issue(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; + u8 prot = qc->tf.protocol; + + if (ata_is_ncq(prot)) { + if (!link->sactive) + ap->nr_active_links++; + link->sactive |= 1 << qc->tag; + } else { + ap->nr_active_links++; + link->active_tag = qc->tag; + } + + qc->flags |= ATA_QCFLAG_ACTIVE; + ap->qc_active |= 1 << qc->tag; + + if (qc->dev->flags & ATA_DFLAG_SLEEPING) { + msleep(1); + return; + } + + qc->err_mask |= ata_qc_issue_prot(qc); + if (qc->err_mask) + goto err; + + return; +err: + ata_qc_complete(qc); +} + +static unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + if (ap->flags & ATA_FLAG_PIO_POLLING) { + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + case ATA_PROT_NODATA: + case ATAPI_PROT_PIO: + case ATAPI_PROT_NODATA: + qc->tf.flags |= ATA_TFLAG_POLLING; + break; + default: + break; + } + } + + ata_dev_select(ap, qc->dev->devno, 1, 0); + + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + if (qc->tf.flags & ATA_TFLAG_POLLING) + qc->tf.ctl |= ATA_NIEN; + + ata_tf_to_host(ap, &qc->tf); + + ap->hsm_task_state = HSM_ST; + + if (qc->tf.flags & ATA_TFLAG_POLLING) + ata_pio_queue_task(ap, qc, 0); + + break; + + default: + return AC_ERR_SYSTEM; + } + + return 0; +} + +static void ata_tf_to_host(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + ata_tf_load(ap, tf); + ata_exec_command(ap, tf); +} + +static void ata_tf_load(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + if (tf->ctl != ap->last_ctl) { + if (ioaddr->ctl_addr) + writeb(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + ata_wait_idle(ap); + } + + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + writeb(tf->hob_feature, ioaddr->feature_addr); + writeb(tf->hob_nsect, ioaddr->nsect_addr); + writeb(tf->hob_lbal, ioaddr->lbal_addr); + writeb(tf->hob_lbam, ioaddr->lbam_addr); + writeb(tf->hob_lbah, ioaddr->lbah_addr); + } + + if (is_addr) { + writeb(tf->feature, ioaddr->feature_addr); + writeb(tf->nsect, ioaddr->nsect_addr); + writeb(tf->lbal, ioaddr->lbal_addr); + writeb(tf->lbam, ioaddr->lbam_addr); + writeb(tf->lbah, ioaddr->lbah_addr); + } + + if (tf->flags & ATA_TFLAG_DEVICE) + writeb(tf->device, ioaddr->device_addr); + + ata_wait_idle(ap); +} + +static void ata_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + writeb(tf->command, ap->ioaddr.command_addr); + + readb(ap->ioaddr.altstatus_addr); + + udelay(1); +} + +static void ata_pio_queue_task(struct ata_port *ap, + void *data,unsigned long delay) +{ + ap->port_task_data = data; +} + +static unsigned int ac_err_mask(u8 status) +{ + if (status & (ATA_BUSY | ATA_DRQ)) + return AC_ERR_HSM; + if (status & (ATA_ERR | ATA_DF)) + return AC_ERR_DEV; + return 0; +} + +static unsigned int __ac_err_mask(u8 status) +{ + unsigned int mask = ac_err_mask(status); + if (mask == 0) + return AC_ERR_OTHER; + return mask; +} + +static void ata_pio_task(struct ata_port *arg_ap) +{ + struct ata_port *ap = arg_ap; + struct ata_queued_cmd *qc = ap->port_task_data; + u8 status; + int poll_next; + +fsm_start: + /* + * This is purely heuristic. This is a fast path. + * Sometimes when we enter, BSY will be cleared in + * 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, queue delayed work. + */ + 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) { + ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE); + return; + } + } + + poll_next = ata_hsm_move(ap, qc, status, 1); + + /* another command or interrupt handler + * may be running at this point. + */ + if (poll_next) + goto fsm_start; +} + +static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq) +{ + int poll_next; + +fsm_start: + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + poll_next = (qc->tf.flags & ATA_TFLAG_POLLING); + + if ((status & ATA_DRQ) == 0) { + if (status & (ATA_ERR | ATA_DF)) { + qc->err_mask |= AC_ERR_DEV; + } else { + qc->err_mask |= AC_ERR_HSM; + } + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + /* Device should not ask for data transfer (DRQ=1) + * when it finds something wrong. + * We ignore DRQ here and stop the HSM by + * changing hsm_task_state to HSM_ST_ERR and + * let the EH abort the command or reset the device. + */ + if (status & (ATA_ERR | ATA_DF)) { + if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) { + printf("DRQ=1 with device error, " + "dev_stat 0x%X\n", status); + qc->err_mask |= AC_ERR_HSM; + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + } + + if (qc->tf.protocol == ATA_PROT_PIO) { + /* PIO data out protocol. + * send first data block. + */ + /* ata_pio_sectors() might change the state + * to HSM_ST_LAST. so, the state is changed here + * before ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST; + ata_pio_sectors(qc); + } else { + printf("protocol is not ATA_PROT_PIO \n"); + } + break; + + case HSM_ST: + if ((status & ATA_DRQ) == 0) { + if (status & (ATA_ERR | ATA_DF)) { + qc->err_mask |= AC_ERR_DEV; + } else { + /* HSM violation. Let EH handle this. + * Phantom devices also trigger this + * condition. Mark hint. + */ + qc->err_mask |= AC_ERR_HSM | AC_ERR_NODEV_HINT; + } + + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + /* For PIO reads, some devices may ask for + * data transfer (DRQ=1) alone with ERR=1. + * We respect DRQ here and transfer one + * block of junk data before changing the + * hsm_task_state to HSM_ST_ERR. + * + * For PIO writes, ERR=1 DRQ=1 doesn't make + * sense since the data block has been + * transferred to the device. + */ + if (status & (ATA_ERR | ATA_DF)) { + qc->err_mask |= AC_ERR_DEV; + + if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { + ata_pio_sectors(qc); + status = ata_wait_idle(ap); + } + + if (status & (ATA_BUSY | ATA_DRQ)) + qc->err_mask |= AC_ERR_HSM; + + /* ata_pio_sectors() might change the + * state to HSM_ST_LAST. so, the state + * is changed after ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + ata_pio_sectors(qc); + if (ap->hsm_task_state == HSM_ST_LAST && + (!(qc->tf.flags & ATA_TFLAG_WRITE))) { + status = ata_wait_idle(ap); + goto fsm_start; + } + + poll_next = 1; + break; + + case HSM_ST_LAST: + if (!ata_ok(status)) { + qc->err_mask |= __ac_err_mask(status); + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + ap->hsm_task_state = HSM_ST_IDLE; + + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + + case HSM_ST_ERR: + /* make sure qc->err_mask is available to + * know what's wrong and recover + */ + ap->hsm_task_state = HSM_ST_IDLE; + + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + default: + poll_next = 0; + } + + return poll_next; +} + +static void ata_pio_sectors(struct ata_queued_cmd *qc) +{ + struct ata_port *ap; + ap = pap; + qc->pdata = ap->pdata; + + ata_pio_sector(qc); + + readb(qc->ap->ioaddr.altstatus_addr); + udelay(1); +} + +static void ata_pio_sector(struct ata_queued_cmd *qc) +{ + int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); + struct ata_port *ap = qc->ap; + unsigned int offset; + unsigned char *buf; + char temp_data_buf[512]; + + if (qc->curbytes == qc->nbytes - qc->sect_size) + ap->hsm_task_state = HSM_ST_LAST; + + offset = qc->curbytes; + + switch (qc->tf.command) { + case ATA_CMD_ID_ATA: + buf = (unsigned char *)&ata_device.id[0]; + break; + case ATA_CMD_PIO_READ_EXT: + case ATA_CMD_PIO_READ: + case ATA_CMD_PIO_WRITE_EXT: + case ATA_CMD_PIO_WRITE: + buf = qc->pdata + offset; + break; + default: + buf = (unsigned char *)&temp_data_buf[0]; + } + + ata_mmio_data_xfer(qc->dev, buf, qc->sect_size, do_write); + + qc->curbytes += qc->sect_size; + +} + +static void ata_mmio_data_xfer(struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int do_write) +{ + struct ata_port *ap = pap; + void __iomem *data_addr = ap->ioaddr.data_addr; + unsigned int words = buflen >> 1; + u16 *buf16 = (u16 *)buf; + unsigned int i = 0; + + udelay(100); + if (do_write) { + for (i = 0; i < words; i++) + writew(le16_to_cpu(buf16[i]), data_addr); + } else { + for (i = 0; i < words; i++) + buf16[i] = cpu_to_le16(readw(data_addr)); + } + + if (buflen & 0x01) { + __le16 align_buf[1] = { 0 }; + unsigned char *trailing_buf = buf + buflen - 1; + + if (do_write) { + memcpy(align_buf, trailing_buf, 1); + writew(le16_to_cpu(align_buf[0]), data_addr); + } else { + align_buf[0] = cpu_to_le16(readw(data_addr)); + memcpy(trailing_buf, align_buf, 1); + } + } +} + +static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) +{ + struct ata_port *ap = qc->ap; + + if (in_wq) { + /* EH might have kicked in while host lock is + * released. + */ + qc = &ap->qcmd[qc->tag]; + if (qc) { + if (!(qc->err_mask & AC_ERR_HSM)) { + ata_irq_on(ap); + ata_qc_complete(qc); + } else { + ata_port_freeze(ap); + } + } + } else { + if (!(qc->err_mask & AC_ERR_HSM)) { + ata_qc_complete(qc); + } else { + ata_port_freeze(ap); + } + } +} + +static u8 ata_irq_on(struct ata_port *ap) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + u8 tmp; + + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; + + if (ioaddr->ctl_addr) + writeb(ap->ctl, ioaddr->ctl_addr); + + tmp = ata_wait_idle(ap); + + return tmp; +} + +static unsigned int ata_tag_internal(unsigned int tag) +{ + return tag == ATA_MAX_QUEUE - 1; +} + +static void ata_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_device *dev = qc->dev; + if (qc->err_mask) + qc->flags |= ATA_QCFLAG_FAILED; + + if (qc->flags & ATA_QCFLAG_FAILED) { + if (!ata_tag_internal(qc->tag)) { + fill_result_tf(qc); + return; + } + } + if (qc->flags & ATA_QCFLAG_RESULT_TF) + fill_result_tf(qc); + + /* Some commands need post-processing after successful + * completion. + */ + switch (qc->tf.command) { + case ATA_CMD_SET_FEATURES: + if (qc->tf.feature != SETFEATURES_WC_ON && + qc->tf.feature != SETFEATURES_WC_OFF) + break; + case ATA_CMD_INIT_DEV_PARAMS: + case ATA_CMD_SET_MULTI: + break; + + case ATA_CMD_SLEEP: + dev->flags |= ATA_DFLAG_SLEEPING; + break; + } + + __ata_qc_complete(qc); +} + +static void fill_result_tf(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + qc->result_tf.flags = qc->tf.flags; + ata_tf_read(ap, &qc->result_tf); +} + +static void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + tf->command = ata_check_status(ap); + tf->feature = readb(ioaddr->error_addr); + tf->nsect = readb(ioaddr->nsect_addr); + tf->lbal = readb(ioaddr->lbal_addr); + tf->lbam = readb(ioaddr->lbam_addr); + tf->lbah = readb(ioaddr->lbah_addr); + tf->device = readb(ioaddr->device_addr); + + if (tf->flags & ATA_TFLAG_LBA48) { + if (ioaddr->ctl_addr) { + writeb(tf->ctl | ATA_HOB, ioaddr->ctl_addr); + + tf->hob_feature = readb(ioaddr->error_addr); + tf->hob_nsect = readb(ioaddr->nsect_addr); + tf->hob_lbal = readb(ioaddr->lbal_addr); + tf->hob_lbam = readb(ioaddr->lbam_addr); + tf->hob_lbah = readb(ioaddr->lbah_addr); + + writeb(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + } else { + printf("sata_dwc warnning register read.\n"); + } + } +} + +static void __ata_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; + + link->active_tag = ATA_TAG_POISON; + ap->nr_active_links--; + + if (qc->flags & ATA_QCFLAG_CLEAR_EXCL && ap->excl_link == link) + ap->excl_link = NULL; + + qc->flags &= ~ATA_QCFLAG_ACTIVE; + ap->qc_active &= ~(1 << qc->tag); +} + +static void ata_qc_free(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int tag; + qc->flags = 0; + tag = qc->tag; + if (tag < ATA_MAX_QUEUE) { + qc->tag = ATA_TAG_POISON; + clear_bit(tag, &ap->qc_allocated); + } +} + +static int check_sata_dev_state(void) +{ + unsigned long datalen; + unsigned char *pdata; + int ret = 0; + int i = 0; + char temp_data_buf[512]; + + while (1) { + udelay (10000); + + pdata = (unsigned char*)&temp_data_buf[0]; + datalen = 512; + + ret = ata_dev_read_sectors(pdata, datalen, 0, 1); + + if (ret == TRUE) + break; + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + dev_state = SATA_NODEVICE; + return FALSE; + } + + if ((i >= 100) && ((i % 100) == 0)) + printf("."); + } + + dev_state = SATA_READY; + + return TRUE; +} + +static unsigned int ata_dev_set_feature(struct ata_device *dev, + u8 enable, u8 feature) +{ + struct ata_taskfile tf; + struct ata_port *ap; + ap = pap; + unsigned int err_mask; + + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_SET_FEATURES; + tf.feature = enable; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = feature; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); + + return err_mask; +} + +static unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors) +{ + struct ata_taskfile tf; + struct ata_port *ap; + ap = pap; + unsigned int err_mask; + + if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) + return AC_ERR_INVALID; + + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_INIT_DEV_PARAMS; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = sectors; + tf.device |= (heads - 1) & 0x0f; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); + + if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED)) + err_mask = 0; + + return err_mask; +} + +#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) +#define SATA_MAX_READ_BLK 0xFF +#else +#define SATA_MAX_READ_BLK 0xFFFF +#endif + +ulong sata_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + ulong start,blks, buf_addr; + unsigned short smallblks; + unsigned long datalen; + unsigned char *pdata; + device &= 0xff; + + u32 block = 0; + u32 n_block = 0; + + if (dev_state != SATA_READY) + return 0; + + buf_addr = (unsigned long)buffer; + start = blknr; + blks = blkcnt; + do { + pdata = (unsigned char *)buf_addr; + if (blks > SATA_MAX_READ_BLK) { + datalen = sata_dev_desc[device].blksz * SATA_MAX_READ_BLK; + smallblks = SATA_MAX_READ_BLK; + + block = (u32)start; + n_block = (u32)smallblks; + + start += SATA_MAX_READ_BLK; + blks -= SATA_MAX_READ_BLK; + } else { + datalen = sata_dev_desc[device].blksz * SATA_MAX_READ_BLK; + datalen = sata_dev_desc[device].blksz * blks; + smallblks = (unsigned short)blks; + + block = (u32)start; + n_block = (u32)smallblks; + + start += blks; + blks = 0; + } + + if (ata_dev_read_sectors(pdata, datalen, block, n_block) != TRUE) { + printf("sata_dwc : Hard disk read error.\n"); + blkcnt -= blks; + break; + } + buf_addr += datalen; + } while (blks != 0); + + return (blkcnt); +} + +static int ata_dev_read_sectors(unsigned char *pdata, unsigned long datalen, + u32 block, u32 n_block) +{ + struct ata_port *ap = pap; + struct ata_device *dev = &ata_device; + struct ata_taskfile tf; + unsigned int class = ATA_DEV_ATA; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1; + int rc; + + if (dev_state == SATA_ERROR) + return FALSE; + + ata_dev_select(ap, dev->devno, 1, 1); + +retry: + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + + ap->pdata = pdata; + + tf.device = ATA_DEVICE_OBS; + + temp_n_block = n_block; + +#ifdef CONFIG_LBA48 + tf.command = ATA_CMD_PIO_READ_EXT; + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; + + tf.hob_feature = 31; + tf.feature = 31; + tf.hob_nsect = (n_block >> 8) & 0xff; + tf.nsect = n_block & 0xff; + + tf.hob_lbah = 0x0; + tf.hob_lbam = 0x0; + tf.hob_lbal = (block >> 24) & 0xff; + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; +#else + tf.command = ATA_CMD_PIO_READ; + tf.flags |= ATA_TFLAG_LBA ; + + tf.feature = 31; + tf.nsect = n_block & 0xff; + + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = (block >> 24) & 0xf; + + tf.device |= 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; + +#endif + + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.flags |= ATA_TFLAG_POLLING; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,0, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("READ_SECTORS NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + rc = -EINVAL; + reason = "device reports invalid type"; + + return TRUE; + +err_out: + printf("failed to READ SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); + return FALSE; +} + +#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) +#define SATA_MAX_WRITE_BLK 0xFF +#else +#define SATA_MAX_WRITE_BLK 0xFFFF +#endif + +ulong sata_write(int device, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + ulong start,blks, buf_addr; + unsigned short smallblks; + unsigned long datalen; + unsigned char *pdata; + device &= 0xff; + + + u32 block = 0; + u32 n_block = 0; + + if (dev_state != SATA_READY) + return 0; + + buf_addr = (unsigned long)buffer; + start = blknr; + blks = blkcnt; + do { + pdata = (unsigned char *)buf_addr; + if (blks > SATA_MAX_WRITE_BLK) { + datalen = sata_dev_desc[device].blksz * SATA_MAX_WRITE_BLK; + smallblks = SATA_MAX_WRITE_BLK; + + block = (u32)start; + n_block = (u32)smallblks; + + start += SATA_MAX_WRITE_BLK; + blks -= SATA_MAX_WRITE_BLK; + } else { + datalen = sata_dev_desc[device].blksz * blks; + smallblks = (unsigned short)blks; + + block = (u32)start; + n_block = (u32)smallblks; + + start += blks; + blks = 0; + } + + if (ata_dev_write_sectors(pdata, datalen, block, n_block) != TRUE) { + printf("sata_dwc : Hard disk read error.\n"); + blkcnt -= blks; + break; + } + buf_addr += datalen; + } while (blks != 0); + + return (blkcnt); +} + +static int ata_dev_write_sectors(unsigned char* pdata, unsigned long datalen, + u32 block, u32 n_block) +{ + struct ata_port *ap = pap; + struct ata_device *dev = &ata_device; + struct ata_taskfile tf; + unsigned int class = ATA_DEV_ATA; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1; + int rc; + + if (dev_state == SATA_ERROR) + return FALSE; + + ata_dev_select(ap, dev->devno, 1, 1); + +retry: + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + + ap->pdata = pdata; + + tf.device = ATA_DEVICE_OBS; + + temp_n_block = n_block; + + +#ifdef CONFIG_LBA48 + tf.command = ATA_CMD_PIO_WRITE_EXT; + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48 | ATA_TFLAG_WRITE; + + tf.hob_feature = 31; + tf.feature = 31; + tf.hob_nsect = (n_block >> 8) & 0xff; + tf.nsect = n_block & 0xff; + + tf.hob_lbah = 0x0; + tf.hob_lbam = 0x0; + tf.hob_lbal = (block >> 24) & 0xff; + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; +#else + tf.command = ATA_CMD_PIO_WRITE; + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_WRITE; + + tf.feature = 31; + tf.nsect = n_block & 0xff; + + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = (block >> 24) & 0xf; + + tf.device |= 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; + +#endif + + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.flags |= ATA_TFLAG_POLLING; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,0, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("READ_SECTORS NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + rc = -EINVAL; + reason = "device reports invalid type"; + + return TRUE; + +err_out: + printf("failed to WRITE SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); + return FALSE; +} diff --git a/drivers/block/sata_dwc.h b/drivers/block/sata_dwc.h new file mode 100644 index 0000000..6259804 --- /dev/null +++ b/drivers/block/sata_dwc.h @@ -0,0 +1,463 @@ +/* + * sata_dwc.h + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld mmiesfeld@amcc.com + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese sr@denx.de + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * This program is free software; you can redistribute + * it and/or modify it under the terms of the GNU + * General Public License as published by the + * Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + */ +/* + * SATA support based on the chip canyonlands. + * + * 04-17-2009 + * The local version of this driver for the canyonlands board + * does not use interrupts but polls the chip instead. + */ + + +#ifndef _SATA_DWC_H_ +#define _SATA_DWC_H_ + +#define HZ 100 + +#define READ 0 +#define WRITE 1 + +enum { + ATA_READID_POSTRESET = (1 << 0), + + ATA_DNXFER_PIO = 0, + ATA_DNXFER_DMA = 1, + ATA_DNXFER_40C = 2, + ATA_DNXFER_FORCE_PIO = 3, + ATA_DNXFER_FORCE_PIO0 = 4, + + ATA_DNXFER_QUIET = (1 << 31), +}; + +enum hsm_task_states { + HSM_ST_IDLE, + HSM_ST_FIRST, + HSM_ST, + HSM_ST_LAST, + HSM_ST_ERR, +}; + +#define ATA_SHORT_PAUSE ((HZ >> 6) + 1) + +struct ata_queued_cmd { + struct ata_port *ap; + struct ata_device *dev; + + struct ata_taskfile tf; + u8 cdb[ATAPI_CDB_LEN]; + + unsigned long flags; + unsigned int tag; + unsigned int n_elem; + + int dma_dir; + + unsigned int sect_size; + + unsigned int nbytes; + unsigned int extrabytes; + unsigned int curbytes; + + unsigned int err_mask; + struct ata_taskfile result_tf; + + void *private_data; + void *lldd_task; + unsigned char *pdata; +}; + +typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc); + +#define ATA_TAG_POISON 0xfafbfcfdU + +enum { + LIBATA_MAX_PRD = ATA_MAX_PRD / 2, + LIBATA_DUMB_MAX_PRD = ATA_MAX_PRD / 4, + ATA_MAX_PORTS = 8, + ATA_DEF_QUEUE = 1, + ATA_MAX_QUEUE = 32, + ATA_TAG_INTERNAL = ATA_MAX_QUEUE - 1, + ATA_MAX_BUS = 2, + ATA_DEF_BUSY_WAIT = 10000, + + ATAPI_MAX_DRAIN = 16 << 10, + + ATA_SHT_EMULATED = 1, + ATA_SHT_CMD_PER_LUN = 1, + ATA_SHT_THIS_ID = -1, + ATA_SHT_USE_CLUSTERING = 1, + + ATA_DFLAG_LBA = (1 << 0), + ATA_DFLAG_LBA48 = (1 << 1), + ATA_DFLAG_CDB_INTR = (1 << 2), + ATA_DFLAG_NCQ = (1 << 3), + ATA_DFLAG_FLUSH_EXT = (1 << 4), + ATA_DFLAG_ACPI_PENDING = (1 << 5), + ATA_DFLAG_ACPI_FAILED = (1 << 6), + ATA_DFLAG_AN = (1 << 7), + ATA_DFLAG_HIPM = (1 << 8), + ATA_DFLAG_DIPM = (1 << 9), + ATA_DFLAG_DMADIR = (1 << 10), + ATA_DFLAG_CFG_MASK = (1 << 12) - 1, + + ATA_DFLAG_PIO = (1 << 12), + ATA_DFLAG_NCQ_OFF = (1 << 13), + ATA_DFLAG_SPUNDOWN = (1 << 14), + ATA_DFLAG_SLEEPING = (1 << 15), + ATA_DFLAG_DUBIOUS_XFER = (1 << 16), + ATA_DFLAG_INIT_MASK = (1 << 24) - 1, + + ATA_DFLAG_DETACH = (1 << 24), + ATA_DFLAG_DETACHED = (1 << 25), + + ATA_LFLAG_HRST_TO_RESUME = (1 << 0), + ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), + ATA_LFLAG_NO_SRST = (1 << 2), + ATA_LFLAG_ASSUME_ATA = (1 << 3), + ATA_LFLAG_ASSUME_SEMB = (1 << 4), + ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, + ATA_LFLAG_NO_RETRY = (1 << 5), + ATA_LFLAG_DISABLED = (1 << 6), + + ATA_FLAG_SLAVE_POSS = (1 << 0), + ATA_FLAG_SATA = (1 << 1), + ATA_FLAG_NO_LEGACY = (1 << 2), + ATA_FLAG_MMIO = (1 << 3), + ATA_FLAG_SRST = (1 << 4), + ATA_FLAG_SATA_RESET = (1 << 5), + ATA_FLAG_NO_ATAPI = (1 << 6), + ATA_FLAG_PIO_DMA = (1 << 7), + ATA_FLAG_PIO_LBA48 = (1 << 8), + ATA_FLAG_PIO_POLLING = (1 << 9), + ATA_FLAG_NCQ = (1 << 10), + ATA_FLAG_DEBUGMSG = (1 << 13), + ATA_FLAG_IGN_SIMPLEX = (1 << 15), + ATA_FLAG_NO_IORDY = (1 << 16), + ATA_FLAG_ACPI_SATA = (1 << 17), + ATA_FLAG_AN = (1 << 18), + ATA_FLAG_PMP = (1 << 19), + ATA_FLAG_IPM = (1 << 20), + + ATA_FLAG_DISABLED = (1 << 23), + + ATA_PFLAG_EH_PENDING = (1 << 0), + ATA_PFLAG_EH_IN_PROGRESS = (1 << 1), + ATA_PFLAG_FROZEN = (1 << 2), + ATA_PFLAG_RECOVERED = (1 << 3), + ATA_PFLAG_LOADING = (1 << 4), + ATA_PFLAG_UNLOADING = (1 << 5), + ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), + ATA_PFLAG_INITIALIZING = (1 << 7), + ATA_PFLAG_RESETTING = (1 << 8), + ATA_PFLAG_SUSPENDED = (1 << 17), + ATA_PFLAG_PM_PENDING = (1 << 18), + + ATA_QCFLAG_ACTIVE = (1 << 0), + ATA_QCFLAG_DMAMAP = (1 << 1), + ATA_QCFLAG_IO = (1 << 3), + ATA_QCFLAG_RESULT_TF = (1 << 4), + ATA_QCFLAG_CLEAR_EXCL = (1 << 5), + ATA_QCFLAG_QUIET = (1 << 6), + + ATA_QCFLAG_FAILED = (1 << 16), + ATA_QCFLAG_SENSE_VALID = (1 << 17), + ATA_QCFLAG_EH_SCHEDULED = (1 << 18), + + ATA_HOST_SIMPLEX = (1 << 0), + ATA_HOST_STARTED = (1 << 1), + + ATA_TMOUT_BOOT = 30 * 100, + ATA_TMOUT_BOOT_QUICK = 7 * 100, + ATA_TMOUT_INTERNAL = 30 * 100, + ATA_TMOUT_INTERNAL_QUICK = 5 * 100, + + /* FIXME: GoVault needs 2s but we can't afford that without + * parallel probing. 800ms is enough for iVDR disk + * HHD424020F7SV00. Increase to 2secs when parallel probing + * is in place. + */ + ATA_TMOUT_FF_WAIT = 4 * 100 / 5, + + BUS_UNKNOWN = 0, + BUS_DMA = 1, + BUS_IDLE = 2, + BUS_NOINTR = 3, + BUS_NODATA = 4, + BUS_TIMER = 5, + BUS_PIO = 6, + BUS_EDD = 7, + BUS_IDENTIFY = 8, + BUS_PACKET = 9, + + PORT_UNKNOWN = 0, + PORT_ENABLED = 1, + PORT_DISABLED = 2, + + /* encoding various smaller bitmaps into a single + * unsigned long bitmap + */ + ATA_NR_PIO_MODES = 7, + ATA_NR_MWDMA_MODES = 5, + ATA_NR_UDMA_MODES = 8, + + ATA_SHIFT_PIO = 0, + ATA_SHIFT_MWDMA = ATA_SHIFT_PIO + ATA_NR_PIO_MODES, + ATA_SHIFT_UDMA = ATA_SHIFT_MWDMA + ATA_NR_MWDMA_MODES, + + ATA_DMA_PAD_SZ = 4, + + ATA_ERING_SIZE = 32, + + ATA_DEFER_LINK = 1, + ATA_DEFER_PORT = 2, + + ATA_EH_DESC_LEN = 80, + + ATA_EH_REVALIDATE = (1 << 0), + ATA_EH_SOFTRESET = (1 << 1), + ATA_EH_HARDRESET = (1 << 2), + ATA_EH_ENABLE_LINK = (1 << 3), + ATA_EH_LPM = (1 << 4), + + ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, + ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, + + ATA_EHI_HOTPLUGGED = (1 << 0), + ATA_EHI_RESUME_LINK = (1 << 1), + ATA_EHI_NO_AUTOPSY = (1 << 2), + ATA_EHI_QUIET = (1 << 3), + + ATA_EHI_DID_SOFTRESET = (1 << 16), + ATA_EHI_DID_HARDRESET = (1 << 17), + ATA_EHI_PRINTINFO = (1 << 18), + ATA_EHI_SETMODE = (1 << 19), + ATA_EHI_POST_SETMODE = (1 << 20), + + ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET, + ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, + + ATA_EH_MAX_TRIES = 5, + + ATA_PROBE_MAX_TRIES = 3, + ATA_EH_DEV_TRIES = 3, + ATA_EH_PMP_TRIES = 5, + ATA_EH_PMP_LINK_TRIES = 3, + + SATA_PMP_SCR_TIMEOUT = 250, + + /* Horkage types. May be set by libata or controller on drives + (some horkage may be drive/controller pair dependant */ + + ATA_HORKAGE_DIAGNOSTIC = (1 << 0), + ATA_HORKAGE_NODMA = (1 << 1), + ATA_HORKAGE_NONCQ = (1 << 2), + ATA_HORKAGE_MAX_SEC_128 = (1 << 3), + ATA_HORKAGE_BROKEN_HPA = (1 << 4), + ATA_HORKAGE_SKIP_PM = (1 << 5), + ATA_HORKAGE_HPA_SIZE = (1 << 6), + ATA_HORKAGE_IPM = (1 << 7), + ATA_HORKAGE_IVB = (1 << 8), + ATA_HORKAGE_STUCK_ERR = (1 << 9), + + ATA_DMA_MASK_ATA = (1 << 0), + ATA_DMA_MASK_ATAPI = (1 << 1), + ATA_DMA_MASK_CFA = (1 << 2), + + ATAPI_READ = 0, + ATAPI_WRITE = 1, + ATAPI_READ_CD = 2, + ATAPI_PASS_THRU = 3, + ATAPI_MISC = 4, +}; + +enum ata_completion_errors { + AC_ERR_DEV = (1 << 0), + AC_ERR_HSM = (1 << 1), + AC_ERR_TIMEOUT = (1 << 2), + AC_ERR_MEDIA = (1 << 3), + AC_ERR_ATA_BUS = (1 << 4), + AC_ERR_HOST_BUS = (1 << 5), + AC_ERR_SYSTEM = (1 << 6), + AC_ERR_INVALID = (1 << 7), + AC_ERR_OTHER = (1 << 8), + AC_ERR_NODEV_HINT = (1 << 9), + AC_ERR_NCQ = (1 << 10), +}; + +enum ata_xfer_mask { + ATA_MASK_PIO = ((1LU << ATA_NR_PIO_MODES) - 1) << ATA_SHIFT_PIO, + ATA_MASK_MWDMA = ((1LU << ATA_NR_MWDMA_MODES) - 1) << ATA_SHIFT_MWDMA, + ATA_MASK_UDMA = ((1LU << ATA_NR_UDMA_MODES) - 1) << ATA_SHIFT_UDMA, +}; + +struct ata_port_info { + struct scsi_host_template *sht; + unsigned long flags; + unsigned long link_flags; + unsigned long pio_mask; + unsigned long mwdma_mask; + unsigned long udma_mask; + const struct ata_port_operations *port_ops; + void *private_data; +}; + +struct ata_ioports { + void __iomem *cmd_addr; + void __iomem *data_addr; + void __iomem *error_addr; + void __iomem *feature_addr; + void __iomem *nsect_addr; + void __iomem *lbal_addr; + void __iomem *lbam_addr; + void __iomem *lbah_addr; + void __iomem *device_addr; + void __iomem *status_addr; + void __iomem *command_addr; + void __iomem *altstatus_addr; + void __iomem *ctl_addr; + void __iomem *bmdma_addr; + void __iomem *scr_addr; +}; + +struct ata_host { + void __iomem * const *iomap; + unsigned int n_ports; + void *private_data; + const struct ata_port_operations *ops; + unsigned long flags; + struct ata_port *simplex_claimed; + struct ata_port *ports[0]; +}; + +struct ata_port_stats { + unsigned long unhandled_irq; + unsigned long idle_irq; + unsigned long rw_reqbuf; +}; + +struct ata_device { + struct ata_link *link; + unsigned int devno; + unsigned long flags; + unsigned int horkage; + struct scsi_device *sdev; +#ifdef CONFIG_ATA_ACPI + acpi_handle acpi_handle; + union acpi_object *gtf_cache; +#endif + u64 n_sectors; + unsigned int class; + + union { + u16 id[ATA_ID_WORDS]; + u32 gscr[SATA_PMP_GSCR_DWORDS]; + }; + + u8 pio_mode; + u8 dma_mode; + u8 xfer_mode; + unsigned int xfer_shift; + + unsigned int multi_count; + unsigned int max_sectors; + unsigned int cdb_len; + + unsigned long pio_mask; + unsigned long mwdma_mask; + unsigned long udma_mask; + + u16 cylinders; + u16 heads; + u16 sectors; + + int spdn_cnt; +}; + +enum dma_data_direction { + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, + DMA_NONE = 3, +}; + +struct ata_link { + struct ata_port *ap; + int pmp; + unsigned int active_tag; + u32 sactive; + + unsigned int flags; + + unsigned int hw_sata_spd_limit; + unsigned int sata_spd_limit; + unsigned int sata_spd; + + struct ata_device device[2]; +}; + +struct ata_port { + unsigned long flags; + unsigned int pflags; + unsigned int print_id; + unsigned int port_no; + + struct ata_ioports ioaddr; + + u8 ctl; + u8 last_ctl; + unsigned int pio_mask; + unsigned int mwdma_mask; + unsigned int udma_mask; + unsigned int cbl; + + struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; + unsigned long qc_allocated; + unsigned int qc_active; + int nr_active_links; + + struct ata_link link; + + int nr_pmp_links; + struct ata_link *pmp_link; + struct ata_link *excl_link; + + struct ata_port_stats stats; + struct ata_host *host; + + struct device *dev; + void *port_task_data; + + unsigned int hsm_task_state; + + u32 msg_enable; + void *private_data; + unsigned char *pdata; +}; + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#endif diff --git a/include/configs/canyonlands.h b/include/configs/canyonlands.h index d814012..d9b73dc 100644 --- a/include/configs/canyonlands.h +++ b/include/configs/canyonlands.h @@ -454,6 +454,7 @@ #define CONFIG_CMD_SDRAM #define CONFIG_CMD_SNTP #define CONFIG_CMD_USB +#define CONFIG_CMD_SATA #elif defined(CONFIG_GLACIER) #define CONFIG_CMD_DATE #define CONFIG_CMD_DTT @@ -517,6 +518,21 @@ #endif /* CONFIG_460GT */
/*----------------------------------------------------------------------- + * S-ATA driver setup + *----------------------------------------------------------------------*/ +#define CONFIG_SATA_DWC + +#ifdef CONFIG_SATA_DWC +#define CONFIG_LIBATA + +#define SATA_BASE_ADDR 0xe20d1000 /* PPC460EX SATA Base Address */ +#define SATA_DMA_REG_ADDR 0xe20d0800 /* PPC460EX SATA Base Address */ +#define CONFIG_SYS_SATA_MAX_DEVICE 1 /* SATA MAX DEVICE */ +/* Convert sectorsize to wordsize */ +#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2) +#endif + +/*----------------------------------------------------------------------- * External Bus Controller (EBC) Setup *----------------------------------------------------------------------*/

Hello Denk, Stefan,
I sent the SATA patch mail on April 17. However, the following content is not confirmed, and there is not a reply either. Could you confirm it? I re-send the SATA driver patch. ---
This patch adds a SATA harddisk driver for the canyonlands. This patch is kernel driver's porting. This pach corresponded to not cmd_scsi but cmd_sata.
[environment variable, boot script] setenv bootargs root=/dev/sda7 rw setenv bootargs ${bootargs} console=ttyS0,115200 ext2load sata 0:2 0x400000 /canyonlands/uImage ext2load sata 0:2 0x800000 /canyonlands/canyonlands.dtb fdt addr 0x800000 0x4000 bootm 0x400000 - 0x800000
If you drive SATA-2 disk on Canyonlands, you must change parts from PI2PCIE212 to PI2PCIE2212 on U25. We confirmed to boot by using following disk.
1.Vender: Fujitsu Type: MHW2040BS 2.Vender: Fujitsu Type: MHW2060BK 3.Vendor: HAGIWARA SYS-COM:HFD25S-032GT 4.Vender: WesternDigital Type: WD3200BJKT (CONFIG_LBA48 required) 5.Vender: WesternDigital Type: WD3200BEVT (CONFIG_LBA48 required) 6.Vender: hitachi Type: HTS543232L9A300 (CONFIG_LBA48 required) 7.Vender: Seagate Type: ST31000333AS (CONFIG_LBA48 required) 8.Vender: Transcend Type: TS32GSSD25S-M 9.Vender: MTRON Type: MSD-SATA1525-016
Signed-off-by: Kazuaki Ichinohe <kazuichi at fsi.co.jp> ---
[patch] ---
drivers/block/Makefile | 1 + drivers/block/sata_dwc.c | 2110 +++++++++++++++++++++++++++++++++++++++++ drivers/block/sata_dwc.h | 463 +++++++++ include/configs/canyonlands.h | 16 + 4 files changed, 2590 insertions(+), 0 deletions(-) create mode 100644 drivers/block/sata_dwc.c create mode 100644 drivers/block/sata_dwc.h
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index eccefc1..e0af40e 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -35,6 +35,7 @@ COBJS-$(CONFIG_SATA_SIL3114) += sata_sil3114.o COBJS-$(CONFIG_SCSI_AHCI) += ahci.o COBJS-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o COBJS-$(CONFIG_SYSTEMACE) += systemace.o +COBJS-$(CONFIG_SATA_DWC) += sata_dwc.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/block/sata_dwc.c b/drivers/block/sata_dwc.c new file mode 100644 index 0000000..91211bb --- /dev/null +++ b/drivers/block/sata_dwc.c @@ -0,0 +1,2110 @@ +/* + * sata_dwc.c + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld <mmiesfeld at amcc.com> + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese <sr at denx.de> + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * This program is free software; you can redistribute + * it and/or modify it under the terms of the GNU + * General Public License as published by the + * Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + */ +/* + * SATA support based on the chip canyonlands. + * + * 04-17-2009 + * The local version of this driver for the canyonlands board + * does not use interrupts but polls the chip instead. + */ + +#include <common.h> +#include <command.h> +#include <pci.h> +#include <asm/processor.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <malloc.h> +#include <ata.h> +#include <linux/ctype.h> + +#include "sata_dwc.h" + +#define DMA_NUM_CHANS 1 +#define DMA_NUM_CHAN_REGS 8 + +#define AHB_DMA_BRST_DFLT 16 + +struct dmareg { + u32 low; + u32 high; +}; + +struct dma_chan_regs { + struct dmareg sar; + struct dmareg dar; + struct dmareg llp; + struct dmareg ctl; + struct dmareg sstat; + struct dmareg dstat; + struct dmareg sstatar; + struct dmareg dstatar; + struct dmareg cfg; + struct dmareg sgr; + struct dmareg dsr; +}; + +struct dma_interrupt_regs { + struct dmareg tfr; + struct dmareg block; + struct dmareg srctran; + struct dmareg dsttran; + struct dmareg error; +}; + +struct ahb_dma_regs { + struct dma_chan_regs chan_regs[DMA_NUM_CHAN_REGS]; + struct dma_interrupt_regs interrupt_raw; + struct dma_interrupt_regs interrupt_status; + struct dma_interrupt_regs interrupt_mask; + struct dma_interrupt_regs interrupt_clear; + struct dmareg statusInt; + struct dmareg rq_srcreg; + struct dmareg rq_dstreg; + struct dmareg rq_sgl_srcreg; + struct dmareg rq_sgl_dstreg; + struct dmareg rq_lst_srcreg; + struct dmareg rq_lst_dstreg; + struct dmareg dma_cfg; + struct dmareg dma_chan_en; + struct dmareg dma_id; + struct dmareg dma_test; + struct dmareg res1; + struct dmareg res2; + /* DMA Comp Params + * Param 6 = dma_param[0], Param 5 = dma_param[1], + * Param 4 = dma_param[2] ... + */ + struct dmareg dma_params[6]; +}; + +#define DMA_EN 0x00000001 +#define DMA_DI 0x00000000 +#define DMA_CHANNEL(ch) (0x00000001 << (ch)) +#define DMA_ENABLE_CHAN(ch) ((0x00000001 << (ch)) | \ + ((0x000000001 << (ch)) << 8)) +#define DMA_DISABLE_CHAN(ch) (0x00000000 | \ + ((0x000000001 << (ch)) << 8)) + +#define SATA_DWC_MAX_PORTS 1 +#define SATA_DWC_SCR_OFFSET 0x24 +#define SATA_DWC_REG_OFFSET 0x64 + +struct sata_dwc_regs { + u32 fptagr; + u32 fpbor; + u32 fptcr; + u32 dmacr; + u32 dbtsr; + u32 intpr; + u32 intmr; + u32 errmr; + u32 llcr; + u32 phycr; + u32 physr; + u32 rxbistpd; + u32 rxbistpd1; + u32 rxbistpd2; + u32 txbistpd; + u32 txbistpd1; + u32 txbistpd2; + u32 bistcr; + u32 bistfctr; + u32 bistsr; + u32 bistdecr; + u32 res[15]; + u32 testr; + u32 versionr; + u32 idr; + u32 unimpl[192]; + u32 dmadr[256]; +}; + +#define SATA_DWC_TXFIFO_DEPTH 0x01FF +#define SATA_DWC_RXFIFO_DEPTH 0x01FF + +#define SATA_DWC_DBTSR_MWR(size) ((size / 4) & SATA_DWC_TXFIFO_DEPTH) +#define SATA_DWC_DBTSR_MRD(size) (((size / 4) & \ + SATA_DWC_RXFIFO_DEPTH) << 16) +#define SATA_DWC_INTPR_DMAT 0x00000001 +#define SATA_DWC_INTPR_NEWFP 0x00000002 +#define SATA_DWC_INTPR_PMABRT 0x00000004 +#define SATA_DWC_INTPR_ERR 0x00000008 +#define SATA_DWC_INTPR_NEWBIST 0x00000010 +#define SATA_DWC_INTPR_IPF 0x10000000 +#define SATA_DWC_INTMR_DMATM 0x00000001 +#define SATA_DWC_INTMR_NEWFPM 0x00000002 +#define SATA_DWC_INTMR_PMABRTM 0x00000004 +#define SATA_DWC_INTMR_ERRM 0x00000008 +#define SATA_DWC_INTMR_NEWBISTM 0x00000010 + +#define SATA_DWC_DMACR_TMOD_TXCHEN 0x00000004 +#define SATA_DWC_DMACR_TXRXCH_CLEAR SATA_DWC_DMACR_TMOD_TXCHEN + +#define SATA_DWC_QCMD_MAX 32 + +#define SATA_DWC_SERROR_ERR_BITS 0x0FFF0F03 + +#define HSDEVP_FROM_AP(ap) (struct sata_dwc_device_port*) \ + (ap)->private_data + +struct sata_dwc_device { + struct device *dev; + struct ata_probe_ent *pe; + struct ata_host *host; + u8 *reg_base; + struct sata_dwc_regs *sata_dwc_regs; + int irq_dma; +}; + +struct sata_dwc_device_port { + struct sata_dwc_device *hsdev; + int cmd_issued[SATA_DWC_QCMD_MAX]; + u32 dma_chan[SATA_DWC_QCMD_MAX]; + int dma_pending[SATA_DWC_QCMD_MAX]; +}; + +enum { + SATA_DWC_CMD_ISSUED_NOT = 0, + SATA_DWC_CMD_ISSUED_PEND = 1, + SATA_DWC_CMD_ISSUED_EXEC = 2, + SATA_DWC_CMD_ISSUED_NODATA = 3, + + SATA_DWC_DMA_PENDING_NONE = 0, + SATA_DWC_DMA_PENDING_TX = 1, + SATA_DWC_DMA_PENDING_RX = 2, +}; + +#define msleep(a) udelay(a * 1000) +#define ssleep(a) msleep(a * 1000) + +static int ata_probe_timeout = (ATA_TMOUT_INTERNAL / 100); + +enum sata_dev_state { + SATA_INIT = 0, + SATA_READY = 1, + SATA_NODEVICE = 2, + SATA_ERROR = 3, +}; +enum sata_dev_state dev_state = SATA_INIT; + +static struct ahb_dma_regs *sata_dma_regs = 0; +static struct ata_host *phost; +static struct ata_port ap; +static struct ata_port *pap = ≈ +static struct ata_device ata_device; +static struct sata_dwc_device_port dwc_devp; + +static void *scr_addr_sstatus; +static u32 temp_n_block = 0; + +static unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, unsigned int buflen, + unsigned long timeout); +static unsigned int ata_dev_set_feature(struct ata_device *dev, + u8 enable,u8 feature); +static unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors); +static u8 ata_irq_on(struct ata_port *ap); +static struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, + unsigned int tag); +static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq); +static void ata_tf_to_host(struct ata_port *ap, + const struct ata_taskfile *tf); +static void ata_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf); +static unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc); +static u8 ata_check_altstatus(struct ata_port *ap); +static u8 ata_check_status(struct ata_port *ap); +static void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep); +static void ata_qc_issue(struct ata_queued_cmd *qc); +static void ata_tf_load(struct ata_port *ap, + const struct ata_taskfile *tf); +static int ata_dev_read_sectors(unsigned char* pdata, + unsigned long datalen, u32 block, u32 n_block); +static int ata_dev_write_sectors(unsigned char* pdata, + unsigned long datalen , u32 block, u32 n_block); +static void ata_std_dev_select(struct ata_port *ap, unsigned int device); +static void ata_qc_complete(struct ata_queued_cmd *qc); +static void __ata_qc_complete(struct ata_queued_cmd *qc); +static void fill_result_tf(struct ata_queued_cmd *qc); +static void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); +static void ata_mmio_data_xfer(struct ata_device *dev, + unsigned char *buf, + unsigned int buflen,int do_write); +static void ata_pio_task(struct ata_port *arg_ap); +static void __ata_port_freeze(struct ata_port *ap); +static int ata_port_freeze(struct ata_port *ap); +static void ata_qc_free(struct ata_queued_cmd *qc); +static void ata_pio_sectors(struct ata_queued_cmd *qc); +static void ata_pio_sector(struct ata_queued_cmd *qc); +static void ata_pio_queue_task(struct ata_port *ap, + void *data,unsigned long delay); +static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq); +static int sata_dwc_softreset(struct ata_port *ap); +static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, + unsigned int flags, u16 *id); +static int check_sata_dev_state(void); + +extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE]; + +static const struct ata_port_info sata_dwc_port_info[] = { + { + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING | + ATA_FLAG_SRST | ATA_FLAG_NCQ, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + }, +}; + +int init_sata (int dev) +{ + struct sata_dwc_device hsdev; + struct ata_host host; + struct ata_port_info pi = sata_dwc_port_info[0]; + struct ata_link *link; + struct sata_dwc_device_port hsdevp = dwc_devp; + u8 *base = 0; + u8 *sata_dma_regs_addr = 0; + u8 status; + unsigned long base_addr = 0; + int chan = 0; + int rc; + int i; + + phost = &host; + + base = (u8*)SATA_BASE_ADDR; + + hsdev.sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET); + + host.n_ports = SATA_DWC_MAX_PORTS; + + for (i = 0; i < SATA_DWC_MAX_PORTS; i++) { + ap.pflags |= ATA_PFLAG_INITIALIZING; + ap.flags = ATA_FLAG_DISABLED; + ap.print_id = -1; + ap.ctl = ATA_DEVCTL_OBS; + ap.host = &host; + ap.last_ctl = 0xFF; + + link = &ap.link; + link->ap = ≈ + link->pmp = 0; + link->active_tag = ATA_TAG_POISON; + link->hw_sata_spd_limit = 0; + + ap.port_no = i; + host.ports[i] = ≈ + } + + ap.pio_mask = pi.pio_mask; + ap.mwdma_mask = pi.mwdma_mask; + ap.udma_mask = pi.udma_mask; + ap.flags |= pi.flags; + ap.link.flags |= pi.link_flags; + + host.ports[0]->ioaddr.cmd_addr = base; + host.ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET; + scr_addr_sstatus = base + SATA_DWC_SCR_OFFSET; + + base_addr = (unsigned long)base; + + host.ports[0]->ioaddr.cmd_addr = (void *)base_addr + 0x00; + host.ports[0]->ioaddr.data_addr = (void *)base_addr + 0x00; + + host.ports[0]->ioaddr.error_addr = (void *)base_addr + 0x04; + host.ports[0]->ioaddr.feature_addr = (void *)base_addr + 0x04; + + host.ports[0]->ioaddr.nsect_addr = (void *)base_addr + 0x08; + + host.ports[0]->ioaddr.lbal_addr = (void *)base_addr + 0x0c; + host.ports[0]->ioaddr.lbam_addr = (void *)base_addr + 0x10; + host.ports[0]->ioaddr.lbah_addr = (void *)base_addr + 0x14; + + host.ports[0]->ioaddr.device_addr = (void *)base_addr + 0x18; + host.ports[0]->ioaddr.command_addr = (void *)base_addr + 0x1c; + host.ports[0]->ioaddr.status_addr = (void *)base_addr + 0x1c; + + host.ports[0]->ioaddr.altstatus_addr = (void *)base_addr + 0x20; + host.ports[0]->ioaddr.ctl_addr = (void *)base_addr + 0x20; + + sata_dma_regs_addr = (u8*)SATA_DMA_REG_ADDR; + sata_dma_regs = (void *__iomem)sata_dma_regs_addr; + + status = ata_check_altstatus(&ap); + + if (status == 0x7f) { + printf("Hard Disk not found.\n"); + dev_state = SATA_NODEVICE; + rc = FALSE; + return rc; + } + + printf("waitng for device ready."); + i = 0; + while (1) { + udelay (10000); + + status = ata_check_altstatus(&ap); + + if ((status & ATA_BUSY) == 0) { + printf("\n"); + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + + dev_state = SATA_NODEVICE; + rc = FALSE; + return rc; + } + if ((i >= 100) && ((i % 100) == 0)) + printf("."); + } + + rc = sata_dwc_softreset(&ap); + + if (rc) { + printf("sata_dwc : error. soft reset failed\n"); + return rc; + } + + for (chan = 0; chan < DMA_NUM_CHANS; chan++) { + out_le32(&(sata_dma_regs->interrupt_mask.error.low), + DMA_DISABLE_CHAN(chan)); + + out_le32(&(sata_dma_regs->interrupt_mask.tfr.low), + DMA_DISABLE_CHAN(chan)); + } + + out_le32(&(sata_dma_regs->dma_cfg.low), DMA_DI); + + out_le32(&hsdev.sata_dwc_regs->intmr, + SATA_DWC_INTMR_ERRM | + SATA_DWC_INTMR_PMABRTM); + + /* Unmask the error bits that should trigger + * an error interrupt by setting the error mask register. + */ + out_le32(&hsdev.sata_dwc_regs->errmr,SATA_DWC_SERROR_ERR_BITS); + + hsdev.host = ap.host; + memset(&hsdevp, 0, sizeof(hsdevp)); + hsdevp.hsdev = &hsdev; + + for (i = 0; i < SATA_DWC_QCMD_MAX; i++) + hsdevp.cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT; + + out_le32((void __iomem *)scr_addr_sstatus + 4, + in_le32((void __iomem *)scr_addr_sstatus + 4)); + + rc = 0; + return rc; +} + +static u8 ata_check_altstatus(struct ata_port *ap) +{ + u8 val = 0; + val = readb(ap->ioaddr.altstatus_addr); + return val; +} + +static int sata_dwc_softreset(struct ata_port *ap) +{ + u8 nsect,lbal = 0; + u8 tmp = 0; + u32 serror = 0; + u8 status = 0; + struct ata_ioports *ioaddr = &ap->ioaddr; + + serror = in_le32((void *)ap->ioaddr.scr_addr + (SCR_ERROR * 4)); + + writeb(0x55, ioaddr->nsect_addr); + writeb(0xaa, ioaddr->lbal_addr); + writeb(0xaa, ioaddr->nsect_addr); + writeb(0x55, ioaddr->lbal_addr); + writeb(0x55, ioaddr->nsect_addr); + writeb(0xaa, ioaddr->lbal_addr); + + nsect = readb(ioaddr->nsect_addr); + lbal = readb(ioaddr->lbal_addr); + + if ((nsect == 0x55) && (lbal == 0xaa)) { + printf("we found a device\n"); + } else { + printf("Not found a device.\n"); + dev_state = SATA_NODEVICE; + return FALSE; + } + + tmp = ATA_DEVICE_OBS; + writeb(tmp,ioaddr->device_addr); + writeb(ap->ctl,ioaddr->ctl_addr); + + udelay(200); + + writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr); + + udelay(200); + writeb(ap->ctl,ioaddr->ctl_addr); + + msleep(150); + status = ata_check_status(ap); + + msleep(50); + ata_check_status(ap); + + while (1) { + u8 status = ata_check_status(ap); + + if (!(status & ATA_BUSY)) + break; + + printf("Hard Disk status is BUSY.\n"); + msleep(50); + } + + tmp = ATA_DEVICE_OBS; + writeb(tmp,ioaddr->device_addr); + + nsect = readb(ioaddr->nsect_addr); + lbal = readb(ioaddr->lbal_addr); + + return 0; +} + +static u8 ata_check_status(struct ata_port *ap) +{ + u8 val = 0; + val = readb(ap->ioaddr.status_addr); + return val; +} + +static int ata_id_has_hipm(const u16 *id) +{ + u16 val = id[76]; + + if (val == 0 || val == 0xffff) + return -1; + + return val & (1 << 9); +} + +static int ata_id_has_dipm(const u16 *id) +{ + u16 val = id[78]; + + if (val == 0 || val == 0xffff) + return -1; + + return val & (1 << 3); +} + +int scan_sata (int dev) +{ + int i; + int rc; + u8 status; + const u16 *id; + struct ata_device *ata_dev = &ata_device; + unsigned long pio_mask, mwdma_mask, udma_mask; + unsigned long xfer_mask; + char revbuf[7]; + u16 iobuf[ATA_SECTOR_WORDS]; + + memset ( iobuf, 0, sizeof(iobuf)); + + if (dev_state == SATA_NODEVICE) + return 1; + + printf("waitng for device ready."); + i = 0; + while (1) { + udelay (10000); + + status = ata_check_altstatus(&ap); + + if ((status & ATA_BUSY) == 0) { + printf("\n"); + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + + dev_state = SATA_NODEVICE; + return 1; + } + if ((i >= 100) && ((i % 100) == 0)) + printf("."); + } + + udelay (1000); + + rc = ata_dev_read_id(ata_dev, &ata_dev->class, + ATA_READID_POSTRESET,ata_dev->id); + if (rc) { + printf("sata_dwc : error. failed sata scan\n"); + return 1; + } + + /* SATA drives indicate we have a bridge. We don't know which + * end of the link the bridge is which is a problem + */ + if (ata_id_is_sata(ata_dev->id)) + ap.cbl = ATA_CBL_SATA; + + id = ata_dev->id; + + ata_dev->flags &= ~ATA_DFLAG_CFG_MASK; + ata_dev->max_sectors = 0; + ata_dev->cdb_len = 0; + ata_dev->n_sectors = 0; + ata_dev->cylinders = 0; + ata_dev->heads = 0; + ata_dev->sectors = 0; + + if (id[ATA_ID_FIELD_VALID] & (1 << 1)) { + pio_mask = id[ATA_ID_PIO_MODES] & 0x03; + pio_mask <<= 3; + pio_mask |= 0x7; + } else { + /* If word 64 isn't valid then Word 51 high byte holds + * the PIO timing number for the maximum. Turn it into + * a mask. + */ + u8 mode = (id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF; + if (mode < 5) { + pio_mask = (2 << mode) - 1; + } else { + pio_mask = 1; + } + } + + mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07; + + if (ata_id_is_cfa(id)) { + int pio = id[163] & 0x7; + int dma = (id[163] >> 3) & 7; + + if (pio) + pio_mask |= (1 << 5); + if (pio > 1) + pio_mask |= (1 << 6); + if (dma) + mwdma_mask |= (1 << 3); + if (dma > 1) + mwdma_mask |= (1 << 4); + } + + udma_mask = 0; + if (id[ATA_ID_FIELD_VALID] & (1 << 2)) + udma_mask = id[ATA_ID_UDMA_MODES] & 0xff; + + xfer_mask = ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) | + ((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) | + ((udma_mask << ATA_SHIFT_UDMA) & ATA_MASK_UDMA); + + if (ata_dev->class == ATA_DEV_ATA) { + if (ata_id_is_cfa(id)) { + if (id[162] & 1) + printf("supports DRM functions and may " + "not be fully accessable.\n"); + sprintf(revbuf, "%s", "CFA"); + } else { + if (ata_id_has_tpm(id)) + printf("supports DRM functions and may " + "not be fully accessable.\n"); + } + + ata_dev->n_sectors = ata_id_n_sectors((u16*)id); + + if (ata_dev->id[59] & 0x100) + ata_dev->multi_count = ata_dev->id[59] & 0xff; + + if (ata_id_has_lba(id)) { + const char *lba_desc; + char ncq_desc[20]; + + lba_desc = "LBA"; + ata_dev->flags |= ATA_DFLAG_LBA; + if (ata_id_has_lba48(id)) { + ata_dev->flags |= ATA_DFLAG_LBA48; + lba_desc = "LBA48"; + + if (ata_dev->n_sectors >= (1UL << 28) && + ata_id_has_flush_ext(id)) + ata_dev->flags |= ATA_DFLAG_FLUSH_EXT; + } + if (!ata_id_has_ncq(ata_dev->id)) + ncq_desc[0] = '\0'; + + if (ata_dev->horkage & ATA_HORKAGE_NONCQ) + sprintf(ncq_desc, "%s", "NCQ (not used)"); + + if (ap.flags & ATA_FLAG_NCQ) + ata_dev->flags |= ATA_DFLAG_NCQ; + } + ata_dev->cdb_len = 16; + } + ata_dev->max_sectors = ATA_MAX_SECTORS; + if (ata_dev->flags & ATA_DFLAG_LBA48) + ata_dev->max_sectors = ATA_MAX_SECTORS_LBA48; + + if (!(ata_dev->horkage & ATA_HORKAGE_IPM)) { + if (ata_id_has_hipm(ata_dev->id)) + ata_dev->flags |= ATA_DFLAG_HIPM; + if (ata_id_has_dipm(ata_dev->id)) + ata_dev->flags |= ATA_DFLAG_DIPM; + } + + if ((ap.cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ata_dev->id))) { + ata_dev->udma_mask &= ATA_UDMA5; + ata_dev->max_sectors = ATA_MAX_SECTORS; + } + + if (ata_dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { + printf("Drive reports diagnostics failure." + "This may indicate a drive\n"); + printf("fault or invalid emulation." + "Contact drive vendor for information.\n"); + } + + rc = check_sata_dev_state(); + + ata_id_c_string (ata_dev->id, + (unsigned char *)sata_dev_desc[dev].revision, + ATA_ID_FW_REV, sizeof(sata_dev_desc[dev].revision)); + ata_id_c_string (ata_dev->id, + (unsigned char *)sata_dev_desc[dev].vendor, + ATA_ID_PROD, sizeof(sata_dev_desc[dev].vendor)); + ata_id_c_string (ata_dev->id, + (unsigned char *)sata_dev_desc[dev].product, + ATA_ID_SERNO, sizeof(sata_dev_desc[dev].product)); + + sata_dev_desc[dev].lba = (u32) ata_dev->n_sectors; + +#ifdef CONFIG_LBA48 + if (ata_dev->id[83] & (1 << 10)) { + sata_dev_desc[dev].lba48 = 1; + } else { + sata_dev_desc[dev].lba48 = 0; + } +#endif + + return 0; +} + +static u8 ata_busy_wait(struct ata_port *ap, + unsigned int bits,unsigned int max) +{ + u8 status; + + do { + udelay(10); + status = ata_check_status(ap); + max--; + } while (status != 0xff && (status & bits) && (max > 0)); + + return status; +} + +static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, + unsigned int flags, u16 *id) +{ + struct ata_port *ap = pap; + unsigned int class = *p_class; + struct ata_taskfile tf; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1, tried_spinup = 0; + u8 status; + int rc; + + status = ata_busy_wait(ap, ATA_BUSY, 30000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + rc = FALSE; + return rc; + } + + ata_dev_select(ap, dev->devno, 1, 1); + +retry: + memset(&tf, 0, sizeof(tf)); + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + tf.ctl = ap->ctl; + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_ID_ATA; + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + + /* Device presence detection is unreliable on some + * controllers. Always poll IDENTIFY if available. + */ + tf.flags |= ATA_TFLAG_POLLING; + + temp_n_block = 1; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, + sizeof(id[0]) * ATA_ID_WORDS, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + unsigned int id_cnt; + + for (id_cnt = 0; id_cnt < ATA_ID_WORDS; id_cnt++) + id[id_cnt] = le16_to_cpu(id[id_cnt]); + + + rc = -EINVAL; + reason = "device reports invalid type"; + + if (class == ATA_DEV_ATA) { + if (!ata_id_is_ata(id) && !ata_id_is_cfa(id)) + goto err_out; + } else { + if (ata_id_is_ata(id)) + goto err_out; + } + if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) { + tried_spinup = 1; + /* + * Drive powered-up in standby mode, and requires a specific + * SET_FEATURES spin-up subcommand before it will accept + * anything other than the original IDENTIFY command. + */ + err_mask = ata_dev_set_feature(dev, SETFEATURES_SPINUP, 0); + if (err_mask && id[2] != 0x738c) { + rc = -EIO; + reason = "SPINUP failed"; + goto err_out; + } + /* + * If the drive initially returned incomplete IDENTIFY info, + * we now must reissue the IDENTIFY command. + */ + if (id[2] == 0x37c8) + goto retry; + } + + if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) { + /* + * The exact sequence expected by certain pre-ATA4 drives is: + * SRST RESET + * IDENTIFY (optional in early ATA) + * INITIALIZE DEVICE PARAMETERS (later IDE and ATA) + * anything else.. + * Some drives were very specific about that exact sequence. + * + * Note that ATA4 says lba is mandatory so the second check + * shoud never trigger. + */ + if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { + err_mask = ata_dev_init_params(dev, id[3], id[6]); + if (err_mask) { + rc = -EIO; + reason = "INIT_DEV_PARAMS failed"; + goto err_out; + } + + /* current CHS translation info (id[53-58]) might be + * changed. reread the identify device info. + */ + flags &= ~ATA_READID_POSTRESET; + goto retry; + } + } + + *p_class = class; + return 0; + +err_out: + return rc; +} + +static u8 ata_wait_idle(struct ata_port *ap) +{ + u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + return status; +} + +static void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep) +{ + if (wait) + ata_wait_idle(ap); + + ata_std_dev_select(ap, device); + + if (wait) + ata_wait_idle(ap); +} + +static void ata_std_dev_select(struct ata_port *ap, unsigned int device) +{ + u8 tmp; + + if (device == 0) { + tmp = ATA_DEVICE_OBS; + } else { + tmp = ATA_DEVICE_OBS | ATA_DEV1; + } + + writeb(tmp, ap->ioaddr.device_addr); + + readb(ap->ioaddr.altstatus_addr); + + udelay(1); +} + +static int waiting_for_reg_state(volatile u8 *offset, + int timeout_msec, + u32 sign) +{ + int i; + u32 status; + + for (i = 0; i < timeout_msec; i++) { + status = readl(offset); + if ((status & sign) != 0) + break; + msleep(1); + } + + return (i < timeout_msec) ? 0 : -1; +} + +static void ata_qc_reinit(struct ata_queued_cmd *qc) +{ + qc->dma_dir = DMA_NONE; + qc->flags = 0; + qc->nbytes = qc->extrabytes = qc->curbytes = 0; + qc->n_elem = 0; + qc->err_mask = 0; + qc->sect_size = ATA_SECT_SIZE; + qc->nbytes = ATA_SECT_SIZE * temp_n_block; + + memset(&qc->tf, 0, sizeof(qc->tf)); + qc->tf.ctl = 0; + qc->tf.device = ATA_DEVICE_OBS; + + qc->result_tf.command = ATA_DRDY; + qc->result_tf.feature = 0; +} + +struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, + unsigned int tag) +{ + if (tag < ATA_MAX_QUEUE) + return &ap->qcmd[tag]; + return NULL; +} + +static void __ata_port_freeze(struct ata_port *ap) +{ + printf("set port freeze.\n"); + ap->pflags |= ATA_PFLAG_FROZEN; +} + +static int ata_port_freeze(struct ata_port *ap) +{ + __ata_port_freeze(ap); + return 0; +} + +unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, unsigned int buflen, + unsigned long timeout) +{ + struct ata_link *link = dev->link; + struct ata_port *ap = pap; + struct ata_queued_cmd *qc; + unsigned int tag, preempted_tag; + u32 preempted_sactive, preempted_qc_active; + int preempted_nr_active_links; + unsigned int err_mask; + int rc = 0; + u8 status; + + status = ata_busy_wait(ap, ATA_BUSY, 300000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + rc = FALSE; + return rc; + } + + if (ap->pflags & ATA_PFLAG_FROZEN) + return AC_ERR_SYSTEM; + + tag = ATA_TAG_INTERNAL; + + if (test_and_set_bit(tag, &ap->qc_allocated)) { + rc = FALSE; + return rc; + } + + qc = __ata_qc_from_tag(ap, tag); + qc->tag = tag; + qc->ap = ap; + qc->dev = dev; + + ata_qc_reinit(qc); + + preempted_tag = link->active_tag; + preempted_sactive = link->sactive; + preempted_qc_active = ap->qc_active; + preempted_nr_active_links = ap->nr_active_links; + link->active_tag = ATA_TAG_POISON; + link->sactive = 0; + ap->qc_active = 0; + ap->nr_active_links = 0; + + qc->tf = *tf; + if (cdb) + memcpy(qc->cdb, cdb, ATAPI_CDB_LEN); + qc->flags |= ATA_QCFLAG_RESULT_TF; + qc->dma_dir = dma_dir; + qc->private_data = 0; + + ata_qc_issue(qc); + + if (!timeout) + timeout = ata_probe_timeout * 1000 / HZ; + + status = ata_busy_wait(ap, ATA_BUSY, 30000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + printf("altstatus = 0x%x.\n",status); + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + if (waiting_for_reg_state(ap->ioaddr.altstatus_addr,1000,0x8)) { + u8 status = 0; + u8 errorStatus = 0; + + status = readb( ap->ioaddr.altstatus_addr); + if ((status & 0x01) != 0) { + errorStatus = readb( ap->ioaddr.feature_addr); + if (errorStatus == 0x04 && + qc->tf.command == ATA_CMD_PIO_READ_EXT){ + printf("Hard Disk doesn't support LBA48\n"); + dev_state = SATA_ERROR; + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + } + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + status = ata_busy_wait(ap, ATA_BUSY, 10); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + ata_pio_task(ap); + + if (!rc) { + if (qc->flags & ATA_QCFLAG_ACTIVE) { + qc->err_mask |= AC_ERR_TIMEOUT; + ata_port_freeze(ap); + } + } + + if (qc->flags & ATA_QCFLAG_FAILED) { + if (qc->result_tf.command & (ATA_ERR | ATA_DF)) + qc->err_mask |= AC_ERR_DEV; + + if (!qc->err_mask) + qc->err_mask |= AC_ERR_OTHER; + + if (qc->err_mask & ~AC_ERR_OTHER) + qc->err_mask &= ~AC_ERR_OTHER; + } + + *tf = qc->result_tf; + err_mask = qc->err_mask; + ata_qc_free(qc); + link->active_tag = preempted_tag; + link->sactive = preempted_sactive; + ap->qc_active = preempted_qc_active; + ap->nr_active_links = preempted_nr_active_links; + + if (ap->flags & ATA_FLAG_DISABLED) { + err_mask |= AC_ERR_SYSTEM; + ap->flags &= ~ATA_FLAG_DISABLED; + } + + return err_mask; +} + +static void ata_qc_issue(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; + u8 prot = qc->tf.protocol; + + if (ata_is_ncq(prot)) { + if (!link->sactive) + ap->nr_active_links++; + link->sactive |= 1 << qc->tag; + } else { + ap->nr_active_links++; + link->active_tag = qc->tag; + } + + qc->flags |= ATA_QCFLAG_ACTIVE; + ap->qc_active |= 1 << qc->tag; + + if (qc->dev->flags & ATA_DFLAG_SLEEPING) { + msleep(1); + return; + } + + qc->err_mask |= ata_qc_issue_prot(qc); + if (qc->err_mask) + goto err; + + return; +err: + ata_qc_complete(qc); +} + +static unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + if (ap->flags & ATA_FLAG_PIO_POLLING) { + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + case ATA_PROT_NODATA: + case ATAPI_PROT_PIO: + case ATAPI_PROT_NODATA: + qc->tf.flags |= ATA_TFLAG_POLLING; + break; + default: + break; + } + } + + ata_dev_select(ap, qc->dev->devno, 1, 0); + + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + if (qc->tf.flags & ATA_TFLAG_POLLING) + qc->tf.ctl |= ATA_NIEN; + + ata_tf_to_host(ap, &qc->tf); + + ap->hsm_task_state = HSM_ST; + + if (qc->tf.flags & ATA_TFLAG_POLLING) + ata_pio_queue_task(ap, qc, 0); + + break; + + default: + return AC_ERR_SYSTEM; + } + + return 0; +} + +static void ata_tf_to_host(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + ata_tf_load(ap, tf); + ata_exec_command(ap, tf); +} + +static void ata_tf_load(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + if (tf->ctl != ap->last_ctl) { + if (ioaddr->ctl_addr) + writeb(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + ata_wait_idle(ap); + } + + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + writeb(tf->hob_feature, ioaddr->feature_addr); + writeb(tf->hob_nsect, ioaddr->nsect_addr); + writeb(tf->hob_lbal, ioaddr->lbal_addr); + writeb(tf->hob_lbam, ioaddr->lbam_addr); + writeb(tf->hob_lbah, ioaddr->lbah_addr); + } + + if (is_addr) { + writeb(tf->feature, ioaddr->feature_addr); + writeb(tf->nsect, ioaddr->nsect_addr); + writeb(tf->lbal, ioaddr->lbal_addr); + writeb(tf->lbam, ioaddr->lbam_addr); + writeb(tf->lbah, ioaddr->lbah_addr); + } + + if (tf->flags & ATA_TFLAG_DEVICE) + writeb(tf->device, ioaddr->device_addr); + + ata_wait_idle(ap); +} + +static void ata_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + writeb(tf->command, ap->ioaddr.command_addr); + + readb(ap->ioaddr.altstatus_addr); + + udelay(1); +} + +static void ata_pio_queue_task(struct ata_port *ap, + void *data,unsigned long delay) +{ + ap->port_task_data = data; +} + +static unsigned int ac_err_mask(u8 status) +{ + if (status & (ATA_BUSY | ATA_DRQ)) + return AC_ERR_HSM; + if (status & (ATA_ERR | ATA_DF)) + return AC_ERR_DEV; + return 0; +} + +static unsigned int __ac_err_mask(u8 status) +{ + unsigned int mask = ac_err_mask(status); + if (mask == 0) + return AC_ERR_OTHER; + return mask; +} + +static void ata_pio_task(struct ata_port *arg_ap) +{ + struct ata_port *ap = arg_ap; + struct ata_queued_cmd *qc = ap->port_task_data; + u8 status; + int poll_next; + +fsm_start: + /* + * This is purely heuristic. This is a fast path. + * Sometimes when we enter, BSY will be cleared in + * 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, queue delayed work. + */ + 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) { + ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE); + return; + } + } + + poll_next = ata_hsm_move(ap, qc, status, 1); + + /* another command or interrupt handler + * may be running at this point. + */ + if (poll_next) + goto fsm_start; +} + +static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq) +{ + int poll_next; + +fsm_start: + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + poll_next = (qc->tf.flags & ATA_TFLAG_POLLING); + + if ((status & ATA_DRQ) == 0) { + if (status & (ATA_ERR | ATA_DF)) { + qc->err_mask |= AC_ERR_DEV; + } else { + qc->err_mask |= AC_ERR_HSM; + } + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + /* Device should not ask for data transfer (DRQ=1) + * when it finds something wrong. + * We ignore DRQ here and stop the HSM by + * changing hsm_task_state to HSM_ST_ERR and + * let the EH abort the command or reset the device. + */ + if (status & (ATA_ERR | ATA_DF)) { + if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) { + printf("DRQ=1 with device error, " + "dev_stat 0x%X\n", status); + qc->err_mask |= AC_ERR_HSM; + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + } + + if (qc->tf.protocol == ATA_PROT_PIO) { + /* PIO data out protocol. + * send first data block. + */ + /* ata_pio_sectors() might change the state + * to HSM_ST_LAST. so, the state is changed here + * before ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST; + ata_pio_sectors(qc); + } else { + printf("protocol is not ATA_PROT_PIO \n"); + } + break; + + case HSM_ST: + if ((status & ATA_DRQ) == 0) { + if (status & (ATA_ERR | ATA_DF)) { + qc->err_mask |= AC_ERR_DEV; + } else { + /* HSM violation. Let EH handle this. + * Phantom devices also trigger this + * condition. Mark hint. + */ + qc->err_mask |= AC_ERR_HSM | AC_ERR_NODEV_HINT; + } + + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + /* For PIO reads, some devices may ask for + * data transfer (DRQ=1) alone with ERR=1. + * We respect DRQ here and transfer one + * block of junk data before changing the + * hsm_task_state to HSM_ST_ERR. + * + * For PIO writes, ERR=1 DRQ=1 doesn't make + * sense since the data block has been + * transferred to the device. + */ + if (status & (ATA_ERR | ATA_DF)) { + qc->err_mask |= AC_ERR_DEV; + + if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { + ata_pio_sectors(qc); + status = ata_wait_idle(ap); + } + + if (status & (ATA_BUSY | ATA_DRQ)) + qc->err_mask |= AC_ERR_HSM; + + /* ata_pio_sectors() might change the + * state to HSM_ST_LAST. so, the state + * is changed after ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + ata_pio_sectors(qc); + if (ap->hsm_task_state == HSM_ST_LAST && + (!(qc->tf.flags & ATA_TFLAG_WRITE))) { + status = ata_wait_idle(ap); + goto fsm_start; + } + + poll_next = 1; + break; + + case HSM_ST_LAST: + if (!ata_ok(status)) { + qc->err_mask |= __ac_err_mask(status); + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + ap->hsm_task_state = HSM_ST_IDLE; + + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + + case HSM_ST_ERR: + /* make sure qc->err_mask is available to + * know what's wrong and recover + */ + ap->hsm_task_state = HSM_ST_IDLE; + + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + default: + poll_next = 0; + } + + return poll_next; +} + +static void ata_pio_sectors(struct ata_queued_cmd *qc) +{ + struct ata_port *ap; + ap = pap; + qc->pdata = ap->pdata; + + ata_pio_sector(qc); + + readb(qc->ap->ioaddr.altstatus_addr); + udelay(1); +} + +static void ata_pio_sector(struct ata_queued_cmd *qc) +{ + int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); + struct ata_port *ap = qc->ap; + unsigned int offset; + unsigned char *buf; + char temp_data_buf[512]; + + if (qc->curbytes == qc->nbytes - qc->sect_size) + ap->hsm_task_state = HSM_ST_LAST; + + offset = qc->curbytes; + + switch (qc->tf.command) { + case ATA_CMD_ID_ATA: + buf = (unsigned char *)&ata_device.id[0]; + break; + case ATA_CMD_PIO_READ_EXT: + case ATA_CMD_PIO_READ: + case ATA_CMD_PIO_WRITE_EXT: + case ATA_CMD_PIO_WRITE: + buf = qc->pdata + offset; + break; + default: + buf = (unsigned char *)&temp_data_buf[0]; + } + + ata_mmio_data_xfer(qc->dev, buf, qc->sect_size, do_write); + + qc->curbytes += qc->sect_size; + +} + +static void ata_mmio_data_xfer(struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int do_write) +{ + struct ata_port *ap = pap; + void __iomem *data_addr = ap->ioaddr.data_addr; + unsigned int words = buflen >> 1; + u16 *buf16 = (u16 *)buf; + unsigned int i = 0; + + udelay(100); + if (do_write) { + for (i = 0; i < words; i++) + writew(le16_to_cpu(buf16[i]), data_addr); + } else { + for (i = 0; i < words; i++) + buf16[i] = cpu_to_le16(readw(data_addr)); + } + + if (buflen & 0x01) { + __le16 align_buf[1] = { 0 }; + unsigned char *trailing_buf = buf + buflen - 1; + + if (do_write) { + memcpy(align_buf, trailing_buf, 1); + writew(le16_to_cpu(align_buf[0]), data_addr); + } else { + align_buf[0] = cpu_to_le16(readw(data_addr)); + memcpy(trailing_buf, align_buf, 1); + } + } +} + +static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) +{ + struct ata_port *ap = qc->ap; + + if (in_wq) { + /* EH might have kicked in while host lock is + * released. + */ + qc = &ap->qcmd[qc->tag]; + if (qc) { + if (!(qc->err_mask & AC_ERR_HSM)) { + ata_irq_on(ap); + ata_qc_complete(qc); + } else { + ata_port_freeze(ap); + } + } + } else { + if (!(qc->err_mask & AC_ERR_HSM)) { + ata_qc_complete(qc); + } else { + ata_port_freeze(ap); + } + } +} + +static u8 ata_irq_on(struct ata_port *ap) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + u8 tmp; + + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; + + if (ioaddr->ctl_addr) + writeb(ap->ctl, ioaddr->ctl_addr); + + tmp = ata_wait_idle(ap); + + return tmp; +} + +static unsigned int ata_tag_internal(unsigned int tag) +{ + return tag == ATA_MAX_QUEUE - 1; +} + +static void ata_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_device *dev = qc->dev; + if (qc->err_mask) + qc->flags |= ATA_QCFLAG_FAILED; + + if (qc->flags & ATA_QCFLAG_FAILED) { + if (!ata_tag_internal(qc->tag)) { + fill_result_tf(qc); + return; + } + } + if (qc->flags & ATA_QCFLAG_RESULT_TF) + fill_result_tf(qc); + + /* Some commands need post-processing after successful + * completion. + */ + switch (qc->tf.command) { + case ATA_CMD_SET_FEATURES: + if (qc->tf.feature != SETFEATURES_WC_ON && + qc->tf.feature != SETFEATURES_WC_OFF) + break; + case ATA_CMD_INIT_DEV_PARAMS: + case ATA_CMD_SET_MULTI: + break; + + case ATA_CMD_SLEEP: + dev->flags |= ATA_DFLAG_SLEEPING; + break; + } + + __ata_qc_complete(qc); +} + +static void fill_result_tf(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + qc->result_tf.flags = qc->tf.flags; + ata_tf_read(ap, &qc->result_tf); +} + +static void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + tf->command = ata_check_status(ap); + tf->feature = readb(ioaddr->error_addr); + tf->nsect = readb(ioaddr->nsect_addr); + tf->lbal = readb(ioaddr->lbal_addr); + tf->lbam = readb(ioaddr->lbam_addr); + tf->lbah = readb(ioaddr->lbah_addr); + tf->device = readb(ioaddr->device_addr); + + if (tf->flags & ATA_TFLAG_LBA48) { + if (ioaddr->ctl_addr) { + writeb(tf->ctl | ATA_HOB, ioaddr->ctl_addr); + + tf->hob_feature = readb(ioaddr->error_addr); + tf->hob_nsect = readb(ioaddr->nsect_addr); + tf->hob_lbal = readb(ioaddr->lbal_addr); + tf->hob_lbam = readb(ioaddr->lbam_addr); + tf->hob_lbah = readb(ioaddr->lbah_addr); + + writeb(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + } else { + printf("sata_dwc warnning register read.\n"); + } + } +} + +static void __ata_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; + + link->active_tag = ATA_TAG_POISON; + ap->nr_active_links--; + + if (qc->flags & ATA_QCFLAG_CLEAR_EXCL && ap->excl_link == link) + ap->excl_link = NULL; + + qc->flags &= ~ATA_QCFLAG_ACTIVE; + ap->qc_active &= ~(1 << qc->tag); +} + +static void ata_qc_free(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int tag; + qc->flags = 0; + tag = qc->tag; + if (tag < ATA_MAX_QUEUE) { + qc->tag = ATA_TAG_POISON; + clear_bit(tag, &ap->qc_allocated); + } +} + +static int check_sata_dev_state(void) +{ + unsigned long datalen; + unsigned char *pdata; + int ret = 0; + int i = 0; + char temp_data_buf[512]; + + while (1) { + udelay (10000); + + pdata = (unsigned char*)&temp_data_buf[0]; + datalen = 512; + + ret = ata_dev_read_sectors(pdata, datalen, 0, 1); + + if (ret == TRUE) + break; + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + dev_state = SATA_NODEVICE; + return FALSE; + } + + if ((i >= 100) && ((i % 100) == 0)) + printf("."); + } + + dev_state = SATA_READY; + + return TRUE; +} + +static unsigned int ata_dev_set_feature(struct ata_device *dev, + u8 enable, u8 feature) +{ + struct ata_taskfile tf; + struct ata_port *ap; + ap = pap; + unsigned int err_mask; + + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_SET_FEATURES; + tf.feature = enable; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = feature; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); + + return err_mask; +} + +static unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors) +{ + struct ata_taskfile tf; + struct ata_port *ap; + ap = pap; + unsigned int err_mask; + + if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) + return AC_ERR_INVALID; + + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_INIT_DEV_PARAMS; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = sectors; + tf.device |= (heads - 1) & 0x0f; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); + + if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED)) + err_mask = 0; + + return err_mask; +} + +#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) +#define SATA_MAX_READ_BLK 0xFF +#else +#define SATA_MAX_READ_BLK 0xFFFF +#endif + +ulong sata_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + ulong start,blks, buf_addr; + unsigned short smallblks; + unsigned long datalen; + unsigned char *pdata; + device &= 0xff; + + u32 block = 0; + u32 n_block = 0; + + if (dev_state != SATA_READY) + return 0; + + buf_addr = (unsigned long)buffer; + start = blknr; + blks = blkcnt; + do { + pdata = (unsigned char *)buf_addr; + if (blks > SATA_MAX_READ_BLK) { + datalen = sata_dev_desc[device].blksz * SATA_MAX_READ_BLK; + smallblks = SATA_MAX_READ_BLK; + + block = (u32)start; + n_block = (u32)smallblks; + + start += SATA_MAX_READ_BLK; + blks -= SATA_MAX_READ_BLK; + } else { + datalen = sata_dev_desc[device].blksz * SATA_MAX_READ_BLK; + datalen = sata_dev_desc[device].blksz * blks; + smallblks = (unsigned short)blks; + + block = (u32)start; + n_block = (u32)smallblks; + + start += blks; + blks = 0; + } + + if (ata_dev_read_sectors(pdata, datalen, block, n_block) != TRUE) { + printf("sata_dwc : Hard disk read error.\n"); + blkcnt -= blks; + break; + } + buf_addr += datalen; + } while (blks != 0); + + return (blkcnt); +} + +static int ata_dev_read_sectors(unsigned char *pdata, unsigned long datalen, + u32 block, u32 n_block) +{ + struct ata_port *ap = pap; + struct ata_device *dev = &ata_device; + struct ata_taskfile tf; + unsigned int class = ATA_DEV_ATA; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1; + int rc; + + if (dev_state == SATA_ERROR) + return FALSE; + + ata_dev_select(ap, dev->devno, 1, 1); + +retry: + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + + ap->pdata = pdata; + + tf.device = ATA_DEVICE_OBS; + + temp_n_block = n_block; + +#ifdef CONFIG_LBA48 + tf.command = ATA_CMD_PIO_READ_EXT; + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; + + tf.hob_feature = 31; + tf.feature = 31; + tf.hob_nsect = (n_block >> 8) & 0xff; + tf.nsect = n_block & 0xff; + + tf.hob_lbah = 0x0; + tf.hob_lbam = 0x0; + tf.hob_lbal = (block >> 24) & 0xff; + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; +#else + tf.command = ATA_CMD_PIO_READ; + tf.flags |= ATA_TFLAG_LBA ; + + tf.feature = 31; + tf.nsect = n_block & 0xff; + + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = (block >> 24) & 0xf; + + tf.device |= 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; + +#endif + + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.flags |= ATA_TFLAG_POLLING; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,0, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("READ_SECTORS NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + rc = -EINVAL; + reason = "device reports invalid type"; + + return TRUE; + +err_out: + printf("failed to READ SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); + return FALSE; +} + +#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) +#define SATA_MAX_WRITE_BLK 0xFF +#else +#define SATA_MAX_WRITE_BLK 0xFFFF +#endif + +ulong sata_write(int device, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + ulong start,blks, buf_addr; + unsigned short smallblks; + unsigned long datalen; + unsigned char *pdata; + device &= 0xff; + + + u32 block = 0; + u32 n_block = 0; + + if (dev_state != SATA_READY) + return 0; + + buf_addr = (unsigned long)buffer; + start = blknr; + blks = blkcnt; + do { + pdata = (unsigned char *)buf_addr; + if (blks > SATA_MAX_WRITE_BLK) { + datalen = sata_dev_desc[device].blksz * SATA_MAX_WRITE_BLK; + smallblks = SATA_MAX_WRITE_BLK; + + block = (u32)start; + n_block = (u32)smallblks; + + start += SATA_MAX_WRITE_BLK; + blks -= SATA_MAX_WRITE_BLK; + } else { + datalen = sata_dev_desc[device].blksz * blks; + smallblks = (unsigned short)blks; + + block = (u32)start; + n_block = (u32)smallblks; + + start += blks; + blks = 0; + } + + if (ata_dev_write_sectors(pdata, datalen, block, n_block) != TRUE) { + printf("sata_dwc : Hard disk read error.\n"); + blkcnt -= blks; + break; + } + buf_addr += datalen; + } while (blks != 0); + + return (blkcnt); +} + +static int ata_dev_write_sectors(unsigned char* pdata, unsigned long datalen, + u32 block, u32 n_block) +{ + struct ata_port *ap = pap; + struct ata_device *dev = &ata_device; + struct ata_taskfile tf; + unsigned int class = ATA_DEV_ATA; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1; + int rc; + + if (dev_state == SATA_ERROR) + return FALSE; + + ata_dev_select(ap, dev->devno, 1, 1); + +retry: + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + + ap->pdata = pdata; + + tf.device = ATA_DEVICE_OBS; + + temp_n_block = n_block; + + +#ifdef CONFIG_LBA48 + tf.command = ATA_CMD_PIO_WRITE_EXT; + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48 | ATA_TFLAG_WRITE; + + tf.hob_feature = 31; + tf.feature = 31; + tf.hob_nsect = (n_block >> 8) & 0xff; + tf.nsect = n_block & 0xff; + + tf.hob_lbah = 0x0; + tf.hob_lbam = 0x0; + tf.hob_lbal = (block >> 24) & 0xff; + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; +#else + tf.command = ATA_CMD_PIO_WRITE; + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_WRITE; + + tf.feature = 31; + tf.nsect = n_block & 0xff; + + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = (block >> 24) & 0xf; + + tf.device |= 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; + +#endif + + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.flags |= ATA_TFLAG_POLLING; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,0, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("READ_SECTORS NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + rc = -EINVAL; + reason = "device reports invalid type"; + + return TRUE; + +err_out: + printf("failed to WRITE SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); + return FALSE; +} diff --git a/drivers/block/sata_dwc.h b/drivers/block/sata_dwc.h new file mode 100644 index 0000000..6259804 --- /dev/null +++ b/drivers/block/sata_dwc.h @@ -0,0 +1,463 @@ +/* + * sata_dwc.h + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld <mmiesfeld at amcc.com> + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese <sr at denx.de> + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * This program is free software; you can redistribute + * it and/or modify it under the terms of the GNU + * General Public License as published by the + * Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + */ +/* + * SATA support based on the chip canyonlands. + * + * 04-17-2009 + * The local version of this driver for the canyonlands board + * does not use interrupts but polls the chip instead. + */ + + +#ifndef _SATA_DWC_H_ +#define _SATA_DWC_H_ + +#define HZ 100 + +#define READ 0 +#define WRITE 1 + +enum { + ATA_READID_POSTRESET = (1 << 0), + + ATA_DNXFER_PIO = 0, + ATA_DNXFER_DMA = 1, + ATA_DNXFER_40C = 2, + ATA_DNXFER_FORCE_PIO = 3, + ATA_DNXFER_FORCE_PIO0 = 4, + + ATA_DNXFER_QUIET = (1 << 31), +}; + +enum hsm_task_states { + HSM_ST_IDLE, + HSM_ST_FIRST, + HSM_ST, + HSM_ST_LAST, + HSM_ST_ERR, +}; + +#define ATA_SHORT_PAUSE ((HZ >> 6) + 1) + +struct ata_queued_cmd { + struct ata_port *ap; + struct ata_device *dev; + + struct ata_taskfile tf; + u8 cdb[ATAPI_CDB_LEN]; + + unsigned long flags; + unsigned int tag; + unsigned int n_elem; + + int dma_dir; + + unsigned int sect_size; + + unsigned int nbytes; + unsigned int extrabytes; + unsigned int curbytes; + + unsigned int err_mask; + struct ata_taskfile result_tf; + + void *private_data; + void *lldd_task; + unsigned char *pdata; +}; + +typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc); + +#define ATA_TAG_POISON 0xfafbfcfdU + +enum { + LIBATA_MAX_PRD = ATA_MAX_PRD / 2, + LIBATA_DUMB_MAX_PRD = ATA_MAX_PRD / 4, + ATA_MAX_PORTS = 8, + ATA_DEF_QUEUE = 1, + ATA_MAX_QUEUE = 32, + ATA_TAG_INTERNAL = ATA_MAX_QUEUE - 1, + ATA_MAX_BUS = 2, + ATA_DEF_BUSY_WAIT = 10000, + + ATAPI_MAX_DRAIN = 16 << 10, + + ATA_SHT_EMULATED = 1, + ATA_SHT_CMD_PER_LUN = 1, + ATA_SHT_THIS_ID = -1, + ATA_SHT_USE_CLUSTERING = 1, + + ATA_DFLAG_LBA = (1 << 0), + ATA_DFLAG_LBA48 = (1 << 1), + ATA_DFLAG_CDB_INTR = (1 << 2), + ATA_DFLAG_NCQ = (1 << 3), + ATA_DFLAG_FLUSH_EXT = (1 << 4), + ATA_DFLAG_ACPI_PENDING = (1 << 5), + ATA_DFLAG_ACPI_FAILED = (1 << 6), + ATA_DFLAG_AN = (1 << 7), + ATA_DFLAG_HIPM = (1 << 8), + ATA_DFLAG_DIPM = (1 << 9), + ATA_DFLAG_DMADIR = (1 << 10), + ATA_DFLAG_CFG_MASK = (1 << 12) - 1, + + ATA_DFLAG_PIO = (1 << 12), + ATA_DFLAG_NCQ_OFF = (1 << 13), + ATA_DFLAG_SPUNDOWN = (1 << 14), + ATA_DFLAG_SLEEPING = (1 << 15), + ATA_DFLAG_DUBIOUS_XFER = (1 << 16), + ATA_DFLAG_INIT_MASK = (1 << 24) - 1, + + ATA_DFLAG_DETACH = (1 << 24), + ATA_DFLAG_DETACHED = (1 << 25), + + ATA_LFLAG_HRST_TO_RESUME = (1 << 0), + ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), + ATA_LFLAG_NO_SRST = (1 << 2), + ATA_LFLAG_ASSUME_ATA = (1 << 3), + ATA_LFLAG_ASSUME_SEMB = (1 << 4), + ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, + ATA_LFLAG_NO_RETRY = (1 << 5), + ATA_LFLAG_DISABLED = (1 << 6), + + ATA_FLAG_SLAVE_POSS = (1 << 0), + ATA_FLAG_SATA = (1 << 1), + ATA_FLAG_NO_LEGACY = (1 << 2), + ATA_FLAG_MMIO = (1 << 3), + ATA_FLAG_SRST = (1 << 4), + ATA_FLAG_SATA_RESET = (1 << 5), + ATA_FLAG_NO_ATAPI = (1 << 6), + ATA_FLAG_PIO_DMA = (1 << 7), + ATA_FLAG_PIO_LBA48 = (1 << 8), + ATA_FLAG_PIO_POLLING = (1 << 9), + ATA_FLAG_NCQ = (1 << 10), + ATA_FLAG_DEBUGMSG = (1 << 13), + ATA_FLAG_IGN_SIMPLEX = (1 << 15), + ATA_FLAG_NO_IORDY = (1 << 16), + ATA_FLAG_ACPI_SATA = (1 << 17), + ATA_FLAG_AN = (1 << 18), + ATA_FLAG_PMP = (1 << 19), + ATA_FLAG_IPM = (1 << 20), + + ATA_FLAG_DISABLED = (1 << 23), + + ATA_PFLAG_EH_PENDING = (1 << 0), + ATA_PFLAG_EH_IN_PROGRESS = (1 << 1), + ATA_PFLAG_FROZEN = (1 << 2), + ATA_PFLAG_RECOVERED = (1 << 3), + ATA_PFLAG_LOADING = (1 << 4), + ATA_PFLAG_UNLOADING = (1 << 5), + ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), + ATA_PFLAG_INITIALIZING = (1 << 7), + ATA_PFLAG_RESETTING = (1 << 8), + ATA_PFLAG_SUSPENDED = (1 << 17), + ATA_PFLAG_PM_PENDING = (1 << 18), + + ATA_QCFLAG_ACTIVE = (1 << 0), + ATA_QCFLAG_DMAMAP = (1 << 1), + ATA_QCFLAG_IO = (1 << 3), + ATA_QCFLAG_RESULT_TF = (1 << 4), + ATA_QCFLAG_CLEAR_EXCL = (1 << 5), + ATA_QCFLAG_QUIET = (1 << 6), + + ATA_QCFLAG_FAILED = (1 << 16), + ATA_QCFLAG_SENSE_VALID = (1 << 17), + ATA_QCFLAG_EH_SCHEDULED = (1 << 18), + + ATA_HOST_SIMPLEX = (1 << 0), + ATA_HOST_STARTED = (1 << 1), + + ATA_TMOUT_BOOT = 30 * 100, + ATA_TMOUT_BOOT_QUICK = 7 * 100, + ATA_TMOUT_INTERNAL = 30 * 100, + ATA_TMOUT_INTERNAL_QUICK = 5 * 100, + + /* FIXME: GoVault needs 2s but we can't afford that without + * parallel probing. 800ms is enough for iVDR disk + * HHD424020F7SV00. Increase to 2secs when parallel probing + * is in place. + */ + ATA_TMOUT_FF_WAIT = 4 * 100 / 5, + + BUS_UNKNOWN = 0, + BUS_DMA = 1, + BUS_IDLE = 2, + BUS_NOINTR = 3, + BUS_NODATA = 4, + BUS_TIMER = 5, + BUS_PIO = 6, + BUS_EDD = 7, + BUS_IDENTIFY = 8, + BUS_PACKET = 9, + + PORT_UNKNOWN = 0, + PORT_ENABLED = 1, + PORT_DISABLED = 2, + + /* encoding various smaller bitmaps into a single + * unsigned long bitmap + */ + ATA_NR_PIO_MODES = 7, + ATA_NR_MWDMA_MODES = 5, + ATA_NR_UDMA_MODES = 8, + + ATA_SHIFT_PIO = 0, + ATA_SHIFT_MWDMA = ATA_SHIFT_PIO + ATA_NR_PIO_MODES, + ATA_SHIFT_UDMA = ATA_SHIFT_MWDMA + ATA_NR_MWDMA_MODES, + + ATA_DMA_PAD_SZ = 4, + + ATA_ERING_SIZE = 32, + + ATA_DEFER_LINK = 1, + ATA_DEFER_PORT = 2, + + ATA_EH_DESC_LEN = 80, + + ATA_EH_REVALIDATE = (1 << 0), + ATA_EH_SOFTRESET = (1 << 1), + ATA_EH_HARDRESET = (1 << 2), + ATA_EH_ENABLE_LINK = (1 << 3), + ATA_EH_LPM = (1 << 4), + + ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, + ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, + + ATA_EHI_HOTPLUGGED = (1 << 0), + ATA_EHI_RESUME_LINK = (1 << 1), + ATA_EHI_NO_AUTOPSY = (1 << 2), + ATA_EHI_QUIET = (1 << 3), + + ATA_EHI_DID_SOFTRESET = (1 << 16), + ATA_EHI_DID_HARDRESET = (1 << 17), + ATA_EHI_PRINTINFO = (1 << 18), + ATA_EHI_SETMODE = (1 << 19), + ATA_EHI_POST_SETMODE = (1 << 20), + + ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET, + ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, + + ATA_EH_MAX_TRIES = 5, + + ATA_PROBE_MAX_TRIES = 3, + ATA_EH_DEV_TRIES = 3, + ATA_EH_PMP_TRIES = 5, + ATA_EH_PMP_LINK_TRIES = 3, + + SATA_PMP_SCR_TIMEOUT = 250, + + /* Horkage types. May be set by libata or controller on drives + (some horkage may be drive/controller pair dependant */ + + ATA_HORKAGE_DIAGNOSTIC = (1 << 0), + ATA_HORKAGE_NODMA = (1 << 1), + ATA_HORKAGE_NONCQ = (1 << 2), + ATA_HORKAGE_MAX_SEC_128 = (1 << 3), + ATA_HORKAGE_BROKEN_HPA = (1 << 4), + ATA_HORKAGE_SKIP_PM = (1 << 5), + ATA_HORKAGE_HPA_SIZE = (1 << 6), + ATA_HORKAGE_IPM = (1 << 7), + ATA_HORKAGE_IVB = (1 << 8), + ATA_HORKAGE_STUCK_ERR = (1 << 9), + + ATA_DMA_MASK_ATA = (1 << 0), + ATA_DMA_MASK_ATAPI = (1 << 1), + ATA_DMA_MASK_CFA = (1 << 2), + + ATAPI_READ = 0, + ATAPI_WRITE = 1, + ATAPI_READ_CD = 2, + ATAPI_PASS_THRU = 3, + ATAPI_MISC = 4, +}; + +enum ata_completion_errors { + AC_ERR_DEV = (1 << 0), + AC_ERR_HSM = (1 << 1), + AC_ERR_TIMEOUT = (1 << 2), + AC_ERR_MEDIA = (1 << 3), + AC_ERR_ATA_BUS = (1 << 4), + AC_ERR_HOST_BUS = (1 << 5), + AC_ERR_SYSTEM = (1 << 6), + AC_ERR_INVALID = (1 << 7), + AC_ERR_OTHER = (1 << 8), + AC_ERR_NODEV_HINT = (1 << 9), + AC_ERR_NCQ = (1 << 10), +}; + +enum ata_xfer_mask { + ATA_MASK_PIO = ((1LU << ATA_NR_PIO_MODES) - 1) << ATA_SHIFT_PIO, + ATA_MASK_MWDMA = ((1LU << ATA_NR_MWDMA_MODES) - 1) << ATA_SHIFT_MWDMA, + ATA_MASK_UDMA = ((1LU << ATA_NR_UDMA_MODES) - 1) << ATA_SHIFT_UDMA, +}; + +struct ata_port_info { + struct scsi_host_template *sht; + unsigned long flags; + unsigned long link_flags; + unsigned long pio_mask; + unsigned long mwdma_mask; + unsigned long udma_mask; + const struct ata_port_operations *port_ops; + void *private_data; +}; + +struct ata_ioports { + void __iomem *cmd_addr; + void __iomem *data_addr; + void __iomem *error_addr; + void __iomem *feature_addr; + void __iomem *nsect_addr; + void __iomem *lbal_addr; + void __iomem *lbam_addr; + void __iomem *lbah_addr; + void __iomem *device_addr; + void __iomem *status_addr; + void __iomem *command_addr; + void __iomem *altstatus_addr; + void __iomem *ctl_addr; + void __iomem *bmdma_addr; + void __iomem *scr_addr; +}; + +struct ata_host { + void __iomem * const *iomap; + unsigned int n_ports; + void *private_data; + const struct ata_port_operations *ops; + unsigned long flags; + struct ata_port *simplex_claimed; + struct ata_port *ports[0]; +}; + +struct ata_port_stats { + unsigned long unhandled_irq; + unsigned long idle_irq; + unsigned long rw_reqbuf; +}; + +struct ata_device { + struct ata_link *link; + unsigned int devno; + unsigned long flags; + unsigned int horkage; + struct scsi_device *sdev; +#ifdef CONFIG_ATA_ACPI + acpi_handle acpi_handle; + union acpi_object *gtf_cache; +#endif + u64 n_sectors; + unsigned int class; + + union { + u16 id[ATA_ID_WORDS]; + u32 gscr[SATA_PMP_GSCR_DWORDS]; + }; + + u8 pio_mode; + u8 dma_mode; + u8 xfer_mode; + unsigned int xfer_shift; + + unsigned int multi_count; + unsigned int max_sectors; + unsigned int cdb_len; + + unsigned long pio_mask; + unsigned long mwdma_mask; + unsigned long udma_mask; + + u16 cylinders; + u16 heads; + u16 sectors; + + int spdn_cnt; +}; + +enum dma_data_direction { + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, + DMA_NONE = 3, +}; + +struct ata_link { + struct ata_port *ap; + int pmp; + unsigned int active_tag; + u32 sactive; + + unsigned int flags; + + unsigned int hw_sata_spd_limit; + unsigned int sata_spd_limit; + unsigned int sata_spd; + + struct ata_device device[2]; +}; + +struct ata_port { + unsigned long flags; + unsigned int pflags; + unsigned int print_id; + unsigned int port_no; + + struct ata_ioports ioaddr; + + u8 ctl; + u8 last_ctl; + unsigned int pio_mask; + unsigned int mwdma_mask; + unsigned int udma_mask; + unsigned int cbl; + + struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; + unsigned long qc_allocated; + unsigned int qc_active; + int nr_active_links; + + struct ata_link link; + + int nr_pmp_links; + struct ata_link *pmp_link; + struct ata_link *excl_link; + + struct ata_port_stats stats; + struct ata_host *host; + + struct device *dev; + void *port_task_data; + + unsigned int hsm_task_state; + + u32 msg_enable; + void *private_data; + unsigned char *pdata; +}; + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#endif diff --git a/include/configs/canyonlands.h b/include/configs/canyonlands.h index d814012..d9b73dc 100644 --- a/include/configs/canyonlands.h +++ b/include/configs/canyonlands.h @@ -454,6 +454,7 @@ #define CONFIG_CMD_SDRAM #define CONFIG_CMD_SNTP #define CONFIG_CMD_USB +#define CONFIG_CMD_SATA #elif defined(CONFIG_GLACIER) #define CONFIG_CMD_DATE #define CONFIG_CMD_DTT @@ -517,6 +518,21 @@ #endif /* CONFIG_460GT */
/*----------------------------------------------------------------------- + * S-ATA driver setup + *----------------------------------------------------------------------*/ +#define CONFIG_SATA_DWC + +#ifdef CONFIG_SATA_DWC +#define CONFIG_LIBATA + +#define SATA_BASE_ADDR 0xe20d1000 /* PPC460EX SATA Base Address */ +#define SATA_DMA_REG_ADDR 0xe20d0800 /* PPC460EX SATA Base Address */ +#define CONFIG_SYS_SATA_MAX_DEVICE 1 /* SATA MAX DEVICE */ +/* Convert sectorsize to wordsize */ +#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2) +#endif + +/*----------------------------------------------------------------------- * External Bus Controller (EBC) Setup *----------------------------------------------------------------------*/

Hi Kazuaki Ichinohe,
On Monday 27 April 2009, Kazuaki Ichinohe wrote:
I sent the SATA patch mail on April 17. However, the following content is not confirmed, and there is not a reply either. Could you confirm it? I re-send the SATA driver patch.
Sorry, I forgot about reviewing it. I'll do this today or tomorrow.
Thanks.
Best regards, Stefan
===================================================================== DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de =====================================================================

On Monday 27 April 2009, Kazuaki Ichinohe wrote:
I sent the SATA patch mail on April 17. However, the following content is not confirmed, and there is not a reply either. Could you confirm it? I re-send the SATA driver patch.
I failed applying your patch:
Applying: Canyonlands SATA harddisk driver error: patch failed: drivers/block/Makefile:35 error: drivers/block/Makefile: patch does not apply error: patch failed: include/configs/canyonlands.h:454 error: include/configs/canyonlands.h: patch does not apply Patch failed at 0001 Canyonlands SATA harddisk driver When you have resolved this problem run "git am --resolved". If you would prefer to skip this patch, instead run "git am --skip". To restore the original branch and stop patching run "git am --abort".
Could you please rebase your patch against the current top-of-tree mainline repository and resumbmit?
Thanks.
Best regards, Stefan
===================================================================== DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de =====================================================================

Hello Denk, Stefan,
Could you please rebase your patch against the current top-of-tree mainline repository and resumbmit?
Thank you for the reply. I made the patch from the source obtained with git in 5/7. The confirmed patch is sent again. Please review this patch. ---
This patch adds a SATA harddisk driver for the canyonlands. This patch is kernel driver's porting. This pach corresponded to not cmd_scsi but cmd_sata.
[environment variable, boot script] setenv bootargs root=/dev/sda7 rw setenv bootargs ${bootargs} console=ttyS0,115200 ext2load sata 0:2 0x400000 /canyonlands/uImage ext2load sata 0:2 0x800000 /canyonlands/canyonlands.dtb fdt addr 0x800000 0x4000 bootm 0x400000 - 0x800000
If you drive SATA-2 disk on Canyonlands, you must change parts from PI2PCIE212 to PI2PCIE2212 on U25. We confirmed to boot by using following disk.
1.Vender: Fujitsu Type: MHW2040BS 2.Vender: Fujitsu Type: MHW2060BK 3.Vendor: HAGIWARA SYS-COM:HFD25S-032GT 4.Vender: WesternDigital Type: WD3200BJKT (CONFIG_LBA48 required) 5.Vender: WesternDigital Type: WD3200BEVT (CONFIG_LBA48 required) 6.Vender: hitachi Type: HTS543232L9A300 (CONFIG_LBA48 required) 7.Vender: Seagate Type: ST31000333AS (CONFIG_LBA48 required) 8.Vender: Transcend Type: TS32GSSD25S-M 9.Vender: MTRON Type: MSD-SATA1525-016
Signed-off-by: Kazuaki Ichinohe <kazuichi at fsi.co.jp> ---
[patch] diff -uprN u-boot-0507/drivers/block/Makefile u-boot-sata/drivers/block/Makefile --- u-boot-0507/drivers/block/Makefile 2009-05-07 09:25:48.000000000 +0900 +++ u-boot-sata/drivers/block/Makefile 2009-05-07 09:43:56.000000000 +0900 @@ -35,6 +35,7 @@ COBJS-$(CONFIG_SATA_SIL3114) += sata_sil COBJS-$(CONFIG_SCSI_AHCI) += ahci.o COBJS-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o COBJS-$(CONFIG_SYSTEMACE) += systemace.o +COBJS-$(CONFIG_SATA_DWC) += sata_dwc.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff -uprN u-boot-0507/drivers/block/sata_dwc.c u-boot-sata/drivers/block/sata_dwc.c --- u-boot-0507/drivers/block/sata_dwc.c 1970-01-01 09:00:00.000000000 +0900 +++ u-boot-sata/drivers/block/sata_dwc.c 2009-05-07 09:42:37.000000000 +0900 @@ -0,0 +1,2110 @@ +/* + * sata_dwc.c + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld mmiesfeld@amcc.com + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese sr@denx.de + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * This program is free software; you can redistribute + * it and/or modify it under the terms of the GNU + * General Public License as published by the + * Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + */ +/* + * SATA support based on the chip canyonlands. + * + * 04-17-2009 + * The local version of this driver for the canyonlands board + * does not use interrupts but polls the chip instead. + */ + +#include <common.h> +#include <command.h> +#include <pci.h> +#include <asm/processor.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <malloc.h> +#include <ata.h> +#include <linux/ctype.h> + +#include "sata_dwc.h" + +#define DMA_NUM_CHANS 1 +#define DMA_NUM_CHAN_REGS 8 + +#define AHB_DMA_BRST_DFLT 16 + +struct dmareg { + u32 low; + u32 high; +}; + +struct dma_chan_regs { + struct dmareg sar; + struct dmareg dar; + struct dmareg llp; + struct dmareg ctl; + struct dmareg sstat; + struct dmareg dstat; + struct dmareg sstatar; + struct dmareg dstatar; + struct dmareg cfg; + struct dmareg sgr; + struct dmareg dsr; +}; + +struct dma_interrupt_regs { + struct dmareg tfr; + struct dmareg block; + struct dmareg srctran; + struct dmareg dsttran; + struct dmareg error; +}; + +struct ahb_dma_regs { + struct dma_chan_regs chan_regs[DMA_NUM_CHAN_REGS]; + struct dma_interrupt_regs interrupt_raw; + struct dma_interrupt_regs interrupt_status; + struct dma_interrupt_regs interrupt_mask; + struct dma_interrupt_regs interrupt_clear; + struct dmareg statusInt; + struct dmareg rq_srcreg; + struct dmareg rq_dstreg; + struct dmareg rq_sgl_srcreg; + struct dmareg rq_sgl_dstreg; + struct dmareg rq_lst_srcreg; + struct dmareg rq_lst_dstreg; + struct dmareg dma_cfg; + struct dmareg dma_chan_en; + struct dmareg dma_id; + struct dmareg dma_test; + struct dmareg res1; + struct dmareg res2; + /* DMA Comp Params + * Param 6 = dma_param[0], Param 5 = dma_param[1], + * Param 4 = dma_param[2] ... + */ + struct dmareg dma_params[6]; +}; + +#define DMA_EN 0x00000001 +#define DMA_DI 0x00000000 +#define DMA_CHANNEL(ch) (0x00000001 << (ch)) +#define DMA_ENABLE_CHAN(ch) ((0x00000001 << (ch)) | \ + ((0x000000001 << (ch)) << 8)) +#define DMA_DISABLE_CHAN(ch) (0x00000000 | \ + ((0x000000001 << (ch)) << 8)) + +#define SATA_DWC_MAX_PORTS 1 +#define SATA_DWC_SCR_OFFSET 0x24 +#define SATA_DWC_REG_OFFSET 0x64 + +struct sata_dwc_regs { + u32 fptagr; + u32 fpbor; + u32 fptcr; + u32 dmacr; + u32 dbtsr; + u32 intpr; + u32 intmr; + u32 errmr; + u32 llcr; + u32 phycr; + u32 physr; + u32 rxbistpd; + u32 rxbistpd1; + u32 rxbistpd2; + u32 txbistpd; + u32 txbistpd1; + u32 txbistpd2; + u32 bistcr; + u32 bistfctr; + u32 bistsr; + u32 bistdecr; + u32 res[15]; + u32 testr; + u32 versionr; + u32 idr; + u32 unimpl[192]; + u32 dmadr[256]; +}; + +#define SATA_DWC_TXFIFO_DEPTH 0x01FF +#define SATA_DWC_RXFIFO_DEPTH 0x01FF + +#define SATA_DWC_DBTSR_MWR(size) ((size / 4) & SATA_DWC_TXFIFO_DEPTH) +#define SATA_DWC_DBTSR_MRD(size) (((size / 4) & \ + SATA_DWC_RXFIFO_DEPTH) << 16) +#define SATA_DWC_INTPR_DMAT 0x00000001 +#define SATA_DWC_INTPR_NEWFP 0x00000002 +#define SATA_DWC_INTPR_PMABRT 0x00000004 +#define SATA_DWC_INTPR_ERR 0x00000008 +#define SATA_DWC_INTPR_NEWBIST 0x00000010 +#define SATA_DWC_INTPR_IPF 0x10000000 +#define SATA_DWC_INTMR_DMATM 0x00000001 +#define SATA_DWC_INTMR_NEWFPM 0x00000002 +#define SATA_DWC_INTMR_PMABRTM 0x00000004 +#define SATA_DWC_INTMR_ERRM 0x00000008 +#define SATA_DWC_INTMR_NEWBISTM 0x00000010 + +#define SATA_DWC_DMACR_TMOD_TXCHEN 0x00000004 +#define SATA_DWC_DMACR_TXRXCH_CLEAR SATA_DWC_DMACR_TMOD_TXCHEN + +#define SATA_DWC_QCMD_MAX 32 + +#define SATA_DWC_SERROR_ERR_BITS 0x0FFF0F03 + +#define HSDEVP_FROM_AP(ap) (struct sata_dwc_device_port*) \ + (ap)->private_data + +struct sata_dwc_device { + struct device *dev; + struct ata_probe_ent *pe; + struct ata_host *host; + u8 *reg_base; + struct sata_dwc_regs *sata_dwc_regs; + int irq_dma; +}; + +struct sata_dwc_device_port { + struct sata_dwc_device *hsdev; + int cmd_issued[SATA_DWC_QCMD_MAX]; + u32 dma_chan[SATA_DWC_QCMD_MAX]; + int dma_pending[SATA_DWC_QCMD_MAX]; +}; + +enum { + SATA_DWC_CMD_ISSUED_NOT = 0, + SATA_DWC_CMD_ISSUED_PEND = 1, + SATA_DWC_CMD_ISSUED_EXEC = 2, + SATA_DWC_CMD_ISSUED_NODATA = 3, + + SATA_DWC_DMA_PENDING_NONE = 0, + SATA_DWC_DMA_PENDING_TX = 1, + SATA_DWC_DMA_PENDING_RX = 2, +}; + +#define msleep(a) udelay(a * 1000) +#define ssleep(a) msleep(a * 1000) + +static int ata_probe_timeout = (ATA_TMOUT_INTERNAL / 100); + +enum sata_dev_state { + SATA_INIT = 0, + SATA_READY = 1, + SATA_NODEVICE = 2, + SATA_ERROR = 3, +}; +enum sata_dev_state dev_state = SATA_INIT; + +static struct ahb_dma_regs *sata_dma_regs = 0; +static struct ata_host *phost; +static struct ata_port ap; +static struct ata_port *pap = ≈ +static struct ata_device ata_device; +static struct sata_dwc_device_port dwc_devp; + +static void *scr_addr_sstatus; +static u32 temp_n_block = 0; + +static unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, unsigned int buflen, + unsigned long timeout); +static unsigned int ata_dev_set_feature(struct ata_device *dev, + u8 enable,u8 feature); +static unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors); +static u8 ata_irq_on(struct ata_port *ap); +static struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, + unsigned int tag); +static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq); +static void ata_tf_to_host(struct ata_port *ap, + const struct ata_taskfile *tf); +static void ata_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf); +static unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc); +static u8 ata_check_altstatus(struct ata_port *ap); +static u8 ata_check_status(struct ata_port *ap); +static void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep); +static void ata_qc_issue(struct ata_queued_cmd *qc); +static void ata_tf_load(struct ata_port *ap, + const struct ata_taskfile *tf); +static int ata_dev_read_sectors(unsigned char* pdata, + unsigned long datalen, u32 block, u32 n_block); +static int ata_dev_write_sectors(unsigned char* pdata, + unsigned long datalen , u32 block, u32 n_block); +static void ata_std_dev_select(struct ata_port *ap, unsigned int device); +static void ata_qc_complete(struct ata_queued_cmd *qc); +static void __ata_qc_complete(struct ata_queued_cmd *qc); +static void fill_result_tf(struct ata_queued_cmd *qc); +static void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); +static void ata_mmio_data_xfer(struct ata_device *dev, + unsigned char *buf, + unsigned int buflen,int do_write); +static void ata_pio_task(struct ata_port *arg_ap); +static void __ata_port_freeze(struct ata_port *ap); +static int ata_port_freeze(struct ata_port *ap); +static void ata_qc_free(struct ata_queued_cmd *qc); +static void ata_pio_sectors(struct ata_queued_cmd *qc); +static void ata_pio_sector(struct ata_queued_cmd *qc); +static void ata_pio_queue_task(struct ata_port *ap, + void *data,unsigned long delay); +static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq); +static int sata_dwc_softreset(struct ata_port *ap); +static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, + unsigned int flags, u16 *id); +static int check_sata_dev_state(void); + +extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE]; + +static const struct ata_port_info sata_dwc_port_info[] = { + { + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING | + ATA_FLAG_SRST | ATA_FLAG_NCQ, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + }, +}; + +int init_sata (int dev) +{ + struct sata_dwc_device hsdev; + struct ata_host host; + struct ata_port_info pi = sata_dwc_port_info[0]; + struct ata_link *link; + struct sata_dwc_device_port hsdevp = dwc_devp; + u8 *base = 0; + u8 *sata_dma_regs_addr = 0; + u8 status; + unsigned long base_addr = 0; + int chan = 0; + int rc; + int i; + + phost = &host; + + base = (u8*)SATA_BASE_ADDR; + + hsdev.sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET); + + host.n_ports = SATA_DWC_MAX_PORTS; + + for (i = 0; i < SATA_DWC_MAX_PORTS; i++) { + ap.pflags |= ATA_PFLAG_INITIALIZING; + ap.flags = ATA_FLAG_DISABLED; + ap.print_id = -1; + ap.ctl = ATA_DEVCTL_OBS; + ap.host = &host; + ap.last_ctl = 0xFF; + + link = &ap.link; + link->ap = ≈ + link->pmp = 0; + link->active_tag = ATA_TAG_POISON; + link->hw_sata_spd_limit = 0; + + ap.port_no = i; + host.ports[i] = ≈ + } + + ap.pio_mask = pi.pio_mask; + ap.mwdma_mask = pi.mwdma_mask; + ap.udma_mask = pi.udma_mask; + ap.flags |= pi.flags; + ap.link.flags |= pi.link_flags; + + host.ports[0]->ioaddr.cmd_addr = base; + host.ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET; + scr_addr_sstatus = base + SATA_DWC_SCR_OFFSET; + + base_addr = (unsigned long)base; + + host.ports[0]->ioaddr.cmd_addr = (void *)base_addr + 0x00; + host.ports[0]->ioaddr.data_addr = (void *)base_addr + 0x00; + + host.ports[0]->ioaddr.error_addr = (void *)base_addr + 0x04; + host.ports[0]->ioaddr.feature_addr = (void *)base_addr + 0x04; + + host.ports[0]->ioaddr.nsect_addr = (void *)base_addr + 0x08; + + host.ports[0]->ioaddr.lbal_addr = (void *)base_addr + 0x0c; + host.ports[0]->ioaddr.lbam_addr = (void *)base_addr + 0x10; + host.ports[0]->ioaddr.lbah_addr = (void *)base_addr + 0x14; + + host.ports[0]->ioaddr.device_addr = (void *)base_addr + 0x18; + host.ports[0]->ioaddr.command_addr = (void *)base_addr + 0x1c; + host.ports[0]->ioaddr.status_addr = (void *)base_addr + 0x1c; + + host.ports[0]->ioaddr.altstatus_addr = (void *)base_addr + 0x20; + host.ports[0]->ioaddr.ctl_addr = (void *)base_addr + 0x20; + + sata_dma_regs_addr = (u8*)SATA_DMA_REG_ADDR; + sata_dma_regs = (void *__iomem)sata_dma_regs_addr; + + status = ata_check_altstatus(&ap); + + if (status == 0x7f) { + printf("Hard Disk not found.\n"); + dev_state = SATA_NODEVICE; + rc = FALSE; + return rc; + } + + printf("waitng for device ready."); + i = 0; + while (1) { + udelay (10000); + + status = ata_check_altstatus(&ap); + + if ((status & ATA_BUSY) == 0) { + printf("\n"); + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + + dev_state = SATA_NODEVICE; + rc = FALSE; + return rc; + } + if ((i >= 100) && ((i % 100) == 0)) + printf("."); + } + + rc = sata_dwc_softreset(&ap); + + if (rc) { + printf("sata_dwc : error. soft reset failed\n"); + return rc; + } + + for (chan = 0; chan < DMA_NUM_CHANS; chan++) { + out_le32(&(sata_dma_regs->interrupt_mask.error.low), + DMA_DISABLE_CHAN(chan)); + + out_le32(&(sata_dma_regs->interrupt_mask.tfr.low), + DMA_DISABLE_CHAN(chan)); + } + + out_le32(&(sata_dma_regs->dma_cfg.low), DMA_DI); + + out_le32(&hsdev.sata_dwc_regs->intmr, + SATA_DWC_INTMR_ERRM | + SATA_DWC_INTMR_PMABRTM); + + /* Unmask the error bits that should trigger + * an error interrupt by setting the error mask register. + */ + out_le32(&hsdev.sata_dwc_regs->errmr,SATA_DWC_SERROR_ERR_BITS); + + hsdev.host = ap.host; + memset(&hsdevp, 0, sizeof(hsdevp)); + hsdevp.hsdev = &hsdev; + + for (i = 0; i < SATA_DWC_QCMD_MAX; i++) + hsdevp.cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT; + + out_le32((void __iomem *)scr_addr_sstatus + 4, + in_le32((void __iomem *)scr_addr_sstatus + 4)); + + rc = 0; + return rc; +} + +static u8 ata_check_altstatus(struct ata_port *ap) +{ + u8 val = 0; + val = readb(ap->ioaddr.altstatus_addr); + return val; +} + +static int sata_dwc_softreset(struct ata_port *ap) +{ + u8 nsect,lbal = 0; + u8 tmp = 0; + u32 serror = 0; + u8 status = 0; + struct ata_ioports *ioaddr = &ap->ioaddr; + + serror = in_le32((void *)ap->ioaddr.scr_addr + (SCR_ERROR * 4)); + + writeb(0x55, ioaddr->nsect_addr); + writeb(0xaa, ioaddr->lbal_addr); + writeb(0xaa, ioaddr->nsect_addr); + writeb(0x55, ioaddr->lbal_addr); + writeb(0x55, ioaddr->nsect_addr); + writeb(0xaa, ioaddr->lbal_addr); + + nsect = readb(ioaddr->nsect_addr); + lbal = readb(ioaddr->lbal_addr); + + if ((nsect == 0x55) && (lbal == 0xaa)) { + printf("we found a device\n"); + } else { + printf("Not found a device.\n"); + dev_state = SATA_NODEVICE; + return FALSE; + } + + tmp = ATA_DEVICE_OBS; + writeb(tmp,ioaddr->device_addr); + writeb(ap->ctl,ioaddr->ctl_addr); + + udelay(200); + + writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr); + + udelay(200); + writeb(ap->ctl,ioaddr->ctl_addr); + + msleep(150); + status = ata_check_status(ap); + + msleep(50); + ata_check_status(ap); + + while (1) { + u8 status = ata_check_status(ap); + + if (!(status & ATA_BUSY)) + break; + + printf("Hard Disk status is BUSY.\n"); + msleep(50); + } + + tmp = ATA_DEVICE_OBS; + writeb(tmp,ioaddr->device_addr); + + nsect = readb(ioaddr->nsect_addr); + lbal = readb(ioaddr->lbal_addr); + + return 0; +} + +static u8 ata_check_status(struct ata_port *ap) +{ + u8 val = 0; + val = readb(ap->ioaddr.status_addr); + return val; +} + +static int ata_id_has_hipm(const u16 *id) +{ + u16 val = id[76]; + + if (val == 0 || val == 0xffff) + return -1; + + return val & (1 << 9); +} + +static int ata_id_has_dipm(const u16 *id) +{ + u16 val = id[78]; + + if (val == 0 || val == 0xffff) + return -1; + + return val & (1 << 3); +} + +int scan_sata (int dev) +{ + int i; + int rc; + u8 status; + const u16 *id; + struct ata_device *ata_dev = &ata_device; + unsigned long pio_mask, mwdma_mask, udma_mask; + unsigned long xfer_mask; + char revbuf[7]; + u16 iobuf[ATA_SECTOR_WORDS]; + + memset ( iobuf, 0, sizeof(iobuf)); + + if (dev_state == SATA_NODEVICE) + return 1; + + printf("waitng for device ready."); + i = 0; + while (1) { + udelay (10000); + + status = ata_check_altstatus(&ap); + + if ((status & ATA_BUSY) == 0) { + printf("\n"); + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + + dev_state = SATA_NODEVICE; + return 1; + } + if ((i >= 100) && ((i % 100) == 0)) + printf("."); + } + + udelay (1000); + + rc = ata_dev_read_id(ata_dev, &ata_dev->class, + ATA_READID_POSTRESET,ata_dev->id); + if (rc) { + printf("sata_dwc : error. failed sata scan\n"); + return 1; + } + + /* SATA drives indicate we have a bridge. We don't know which + * end of the link the bridge is which is a problem + */ + if (ata_id_is_sata(ata_dev->id)) + ap.cbl = ATA_CBL_SATA; + + id = ata_dev->id; + + ata_dev->flags &= ~ATA_DFLAG_CFG_MASK; + ata_dev->max_sectors = 0; + ata_dev->cdb_len = 0; + ata_dev->n_sectors = 0; + ata_dev->cylinders = 0; + ata_dev->heads = 0; + ata_dev->sectors = 0; + + if (id[ATA_ID_FIELD_VALID] & (1 << 1)) { + pio_mask = id[ATA_ID_PIO_MODES] & 0x03; + pio_mask <<= 3; + pio_mask |= 0x7; + } else { + /* If word 64 isn't valid then Word 51 high byte holds + * the PIO timing number for the maximum. Turn it into + * a mask. + */ + u8 mode = (id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF; + if (mode < 5) { + pio_mask = (2 << mode) - 1; + } else { + pio_mask = 1; + } + } + + mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07; + + if (ata_id_is_cfa(id)) { + int pio = id[163] & 0x7; + int dma = (id[163] >> 3) & 7; + + if (pio) + pio_mask |= (1 << 5); + if (pio > 1) + pio_mask |= (1 << 6); + if (dma) + mwdma_mask |= (1 << 3); + if (dma > 1) + mwdma_mask |= (1 << 4); + } + + udma_mask = 0; + if (id[ATA_ID_FIELD_VALID] & (1 << 2)) + udma_mask = id[ATA_ID_UDMA_MODES] & 0xff; + + xfer_mask = ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) | + ((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) | + ((udma_mask << ATA_SHIFT_UDMA) & ATA_MASK_UDMA); + + if (ata_dev->class == ATA_DEV_ATA) { + if (ata_id_is_cfa(id)) { + if (id[162] & 1) + printf("supports DRM functions and may " + "not be fully accessable.\n"); + sprintf(revbuf, "%s", "CFA"); + } else { + if (ata_id_has_tpm(id)) + printf("supports DRM functions and may " + "not be fully accessable.\n"); + } + + ata_dev->n_sectors = ata_id_n_sectors((u16*)id); + + if (ata_dev->id[59] & 0x100) + ata_dev->multi_count = ata_dev->id[59] & 0xff; + + if (ata_id_has_lba(id)) { + const char *lba_desc; + char ncq_desc[20]; + + lba_desc = "LBA"; + ata_dev->flags |= ATA_DFLAG_LBA; + if (ata_id_has_lba48(id)) { + ata_dev->flags |= ATA_DFLAG_LBA48; + lba_desc = "LBA48"; + + if (ata_dev->n_sectors >= (1UL << 28) && + ata_id_has_flush_ext(id)) + ata_dev->flags |= ATA_DFLAG_FLUSH_EXT; + } + if (!ata_id_has_ncq(ata_dev->id)) + ncq_desc[0] = '\0'; + + if (ata_dev->horkage & ATA_HORKAGE_NONCQ) + sprintf(ncq_desc, "%s", "NCQ (not used)"); + + if (ap.flags & ATA_FLAG_NCQ) + ata_dev->flags |= ATA_DFLAG_NCQ; + } + ata_dev->cdb_len = 16; + } + ata_dev->max_sectors = ATA_MAX_SECTORS; + if (ata_dev->flags & ATA_DFLAG_LBA48) + ata_dev->max_sectors = ATA_MAX_SECTORS_LBA48; + + if (!(ata_dev->horkage & ATA_HORKAGE_IPM)) { + if (ata_id_has_hipm(ata_dev->id)) + ata_dev->flags |= ATA_DFLAG_HIPM; + if (ata_id_has_dipm(ata_dev->id)) + ata_dev->flags |= ATA_DFLAG_DIPM; + } + + if ((ap.cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ata_dev->id))) { + ata_dev->udma_mask &= ATA_UDMA5; + ata_dev->max_sectors = ATA_MAX_SECTORS; + } + + if (ata_dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { + printf("Drive reports diagnostics failure." + "This may indicate a drive\n"); + printf("fault or invalid emulation." + "Contact drive vendor for information.\n"); + } + + rc = check_sata_dev_state(); + + ata_id_c_string (ata_dev->id, + (unsigned char *)sata_dev_desc[dev].revision, + ATA_ID_FW_REV, sizeof(sata_dev_desc[dev].revision)); + ata_id_c_string (ata_dev->id, + (unsigned char *)sata_dev_desc[dev].vendor, + ATA_ID_PROD, sizeof(sata_dev_desc[dev].vendor)); + ata_id_c_string (ata_dev->id, + (unsigned char *)sata_dev_desc[dev].product, + ATA_ID_SERNO, sizeof(sata_dev_desc[dev].product)); + + sata_dev_desc[dev].lba = (u32) ata_dev->n_sectors; + +#ifdef CONFIG_LBA48 + if (ata_dev->id[83] & (1 << 10)) { + sata_dev_desc[dev].lba48 = 1; + } else { + sata_dev_desc[dev].lba48 = 0; + } +#endif + + return 0; +} + +static u8 ata_busy_wait(struct ata_port *ap, + unsigned int bits,unsigned int max) +{ + u8 status; + + do { + udelay(10); + status = ata_check_status(ap); + max--; + } while (status != 0xff && (status & bits) && (max > 0)); + + return status; +} + +static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, + unsigned int flags, u16 *id) +{ + struct ata_port *ap = pap; + unsigned int class = *p_class; + struct ata_taskfile tf; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1, tried_spinup = 0; + u8 status; + int rc; + + status = ata_busy_wait(ap, ATA_BUSY, 30000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + rc = FALSE; + return rc; + } + + ata_dev_select(ap, dev->devno, 1, 1); + +retry: + memset(&tf, 0, sizeof(tf)); + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + tf.ctl = ap->ctl; + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_ID_ATA; + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + + /* Device presence detection is unreliable on some + * controllers. Always poll IDENTIFY if available. + */ + tf.flags |= ATA_TFLAG_POLLING; + + temp_n_block = 1; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, + sizeof(id[0]) * ATA_ID_WORDS, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + unsigned int id_cnt; + + for (id_cnt = 0; id_cnt < ATA_ID_WORDS; id_cnt++) + id[id_cnt] = le16_to_cpu(id[id_cnt]); + + + rc = -EINVAL; + reason = "device reports invalid type"; + + if (class == ATA_DEV_ATA) { + if (!ata_id_is_ata(id) && !ata_id_is_cfa(id)) + goto err_out; + } else { + if (ata_id_is_ata(id)) + goto err_out; + } + if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) { + tried_spinup = 1; + /* + * Drive powered-up in standby mode, and requires a specific + * SET_FEATURES spin-up subcommand before it will accept + * anything other than the original IDENTIFY command. + */ + err_mask = ata_dev_set_feature(dev, SETFEATURES_SPINUP, 0); + if (err_mask && id[2] != 0x738c) { + rc = -EIO; + reason = "SPINUP failed"; + goto err_out; + } + /* + * If the drive initially returned incomplete IDENTIFY info, + * we now must reissue the IDENTIFY command. + */ + if (id[2] == 0x37c8) + goto retry; + } + + if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) { + /* + * The exact sequence expected by certain pre-ATA4 drives is: + * SRST RESET + * IDENTIFY (optional in early ATA) + * INITIALIZE DEVICE PARAMETERS (later IDE and ATA) + * anything else.. + * Some drives were very specific about that exact sequence. + * + * Note that ATA4 says lba is mandatory so the second check + * shoud never trigger. + */ + if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { + err_mask = ata_dev_init_params(dev, id[3], id[6]); + if (err_mask) { + rc = -EIO; + reason = "INIT_DEV_PARAMS failed"; + goto err_out; + } + + /* current CHS translation info (id[53-58]) might be + * changed. reread the identify device info. + */ + flags &= ~ATA_READID_POSTRESET; + goto retry; + } + } + + *p_class = class; + return 0; + +err_out: + return rc; +} + +static u8 ata_wait_idle(struct ata_port *ap) +{ + u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + return status; +} + +static void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep) +{ + if (wait) + ata_wait_idle(ap); + + ata_std_dev_select(ap, device); + + if (wait) + ata_wait_idle(ap); +} + +static void ata_std_dev_select(struct ata_port *ap, unsigned int device) +{ + u8 tmp; + + if (device == 0) { + tmp = ATA_DEVICE_OBS; + } else { + tmp = ATA_DEVICE_OBS | ATA_DEV1; + } + + writeb(tmp, ap->ioaddr.device_addr); + + readb(ap->ioaddr.altstatus_addr); + + udelay(1); +} + +static int waiting_for_reg_state(volatile u8 *offset, + int timeout_msec, + u32 sign) +{ + int i; + u32 status; + + for (i = 0; i < timeout_msec; i++) { + status = readl(offset); + if ((status & sign) != 0) + break; + msleep(1); + } + + return (i < timeout_msec) ? 0 : -1; +} + +static void ata_qc_reinit(struct ata_queued_cmd *qc) +{ + qc->dma_dir = DMA_NONE; + qc->flags = 0; + qc->nbytes = qc->extrabytes = qc->curbytes = 0; + qc->n_elem = 0; + qc->err_mask = 0; + qc->sect_size = ATA_SECT_SIZE; + qc->nbytes = ATA_SECT_SIZE * temp_n_block; + + memset(&qc->tf, 0, sizeof(qc->tf)); + qc->tf.ctl = 0; + qc->tf.device = ATA_DEVICE_OBS; + + qc->result_tf.command = ATA_DRDY; + qc->result_tf.feature = 0; +} + +struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, + unsigned int tag) +{ + if (tag < ATA_MAX_QUEUE) + return &ap->qcmd[tag]; + return NULL; +} + +static void __ata_port_freeze(struct ata_port *ap) +{ + printf("set port freeze.\n"); + ap->pflags |= ATA_PFLAG_FROZEN; +} + +static int ata_port_freeze(struct ata_port *ap) +{ + __ata_port_freeze(ap); + return 0; +} + +unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, unsigned int buflen, + unsigned long timeout) +{ + struct ata_link *link = dev->link; + struct ata_port *ap = pap; + struct ata_queued_cmd *qc; + unsigned int tag, preempted_tag; + u32 preempted_sactive, preempted_qc_active; + int preempted_nr_active_links; + unsigned int err_mask; + int rc = 0; + u8 status; + + status = ata_busy_wait(ap, ATA_BUSY, 300000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + rc = FALSE; + return rc; + } + + if (ap->pflags & ATA_PFLAG_FROZEN) + return AC_ERR_SYSTEM; + + tag = ATA_TAG_INTERNAL; + + if (test_and_set_bit(tag, &ap->qc_allocated)) { + rc = FALSE; + return rc; + } + + qc = __ata_qc_from_tag(ap, tag); + qc->tag = tag; + qc->ap = ap; + qc->dev = dev; + + ata_qc_reinit(qc); + + preempted_tag = link->active_tag; + preempted_sactive = link->sactive; + preempted_qc_active = ap->qc_active; + preempted_nr_active_links = ap->nr_active_links; + link->active_tag = ATA_TAG_POISON; + link->sactive = 0; + ap->qc_active = 0; + ap->nr_active_links = 0; + + qc->tf = *tf; + if (cdb) + memcpy(qc->cdb, cdb, ATAPI_CDB_LEN); + qc->flags |= ATA_QCFLAG_RESULT_TF; + qc->dma_dir = dma_dir; + qc->private_data = 0; + + ata_qc_issue(qc); + + if (!timeout) + timeout = ata_probe_timeout * 1000 / HZ; + + status = ata_busy_wait(ap, ATA_BUSY, 30000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + printf("altstatus = 0x%x.\n",status); + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + if (waiting_for_reg_state(ap->ioaddr.altstatus_addr,1000,0x8)) { + u8 status = 0; + u8 errorStatus = 0; + + status = readb( ap->ioaddr.altstatus_addr); + if ((status & 0x01) != 0) { + errorStatus = readb( ap->ioaddr.feature_addr); + if (errorStatus == 0x04 && + qc->tf.command == ATA_CMD_PIO_READ_EXT){ + printf("Hard Disk doesn't support LBA48\n"); + dev_state = SATA_ERROR; + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + } + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + status = ata_busy_wait(ap, ATA_BUSY, 10); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + ata_pio_task(ap); + + if (!rc) { + if (qc->flags & ATA_QCFLAG_ACTIVE) { + qc->err_mask |= AC_ERR_TIMEOUT; + ata_port_freeze(ap); + } + } + + if (qc->flags & ATA_QCFLAG_FAILED) { + if (qc->result_tf.command & (ATA_ERR | ATA_DF)) + qc->err_mask |= AC_ERR_DEV; + + if (!qc->err_mask) + qc->err_mask |= AC_ERR_OTHER; + + if (qc->err_mask & ~AC_ERR_OTHER) + qc->err_mask &= ~AC_ERR_OTHER; + } + + *tf = qc->result_tf; + err_mask = qc->err_mask; + ata_qc_free(qc); + link->active_tag = preempted_tag; + link->sactive = preempted_sactive; + ap->qc_active = preempted_qc_active; + ap->nr_active_links = preempted_nr_active_links; + + if (ap->flags & ATA_FLAG_DISABLED) { + err_mask |= AC_ERR_SYSTEM; + ap->flags &= ~ATA_FLAG_DISABLED; + } + + return err_mask; +} + +static void ata_qc_issue(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; + u8 prot = qc->tf.protocol; + + if (ata_is_ncq(prot)) { + if (!link->sactive) + ap->nr_active_links++; + link->sactive |= 1 << qc->tag; + } else { + ap->nr_active_links++; + link->active_tag = qc->tag; + } + + qc->flags |= ATA_QCFLAG_ACTIVE; + ap->qc_active |= 1 << qc->tag; + + if (qc->dev->flags & ATA_DFLAG_SLEEPING) { + msleep(1); + return; + } + + qc->err_mask |= ata_qc_issue_prot(qc); + if (qc->err_mask) + goto err; + + return; +err: + ata_qc_complete(qc); +} + +static unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + if (ap->flags & ATA_FLAG_PIO_POLLING) { + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + case ATA_PROT_NODATA: + case ATAPI_PROT_PIO: + case ATAPI_PROT_NODATA: + qc->tf.flags |= ATA_TFLAG_POLLING; + break; + default: + break; + } + } + + ata_dev_select(ap, qc->dev->devno, 1, 0); + + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + if (qc->tf.flags & ATA_TFLAG_POLLING) + qc->tf.ctl |= ATA_NIEN; + + ata_tf_to_host(ap, &qc->tf); + + ap->hsm_task_state = HSM_ST; + + if (qc->tf.flags & ATA_TFLAG_POLLING) + ata_pio_queue_task(ap, qc, 0); + + break; + + default: + return AC_ERR_SYSTEM; + } + + return 0; +} + +static void ata_tf_to_host(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + ata_tf_load(ap, tf); + ata_exec_command(ap, tf); +} + +static void ata_tf_load(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + if (tf->ctl != ap->last_ctl) { + if (ioaddr->ctl_addr) + writeb(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + ata_wait_idle(ap); + } + + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + writeb(tf->hob_feature, ioaddr->feature_addr); + writeb(tf->hob_nsect, ioaddr->nsect_addr); + writeb(tf->hob_lbal, ioaddr->lbal_addr); + writeb(tf->hob_lbam, ioaddr->lbam_addr); + writeb(tf->hob_lbah, ioaddr->lbah_addr); + } + + if (is_addr) { + writeb(tf->feature, ioaddr->feature_addr); + writeb(tf->nsect, ioaddr->nsect_addr); + writeb(tf->lbal, ioaddr->lbal_addr); + writeb(tf->lbam, ioaddr->lbam_addr); + writeb(tf->lbah, ioaddr->lbah_addr); + } + + if (tf->flags & ATA_TFLAG_DEVICE) + writeb(tf->device, ioaddr->device_addr); + + ata_wait_idle(ap); +} + +static void ata_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + writeb(tf->command, ap->ioaddr.command_addr); + + readb(ap->ioaddr.altstatus_addr); + + udelay(1); +} + +static void ata_pio_queue_task(struct ata_port *ap, + void *data,unsigned long delay) +{ + ap->port_task_data = data; +} + +static unsigned int ac_err_mask(u8 status) +{ + if (status & (ATA_BUSY | ATA_DRQ)) + return AC_ERR_HSM; + if (status & (ATA_ERR | ATA_DF)) + return AC_ERR_DEV; + return 0; +} + +static unsigned int __ac_err_mask(u8 status) +{ + unsigned int mask = ac_err_mask(status); + if (mask == 0) + return AC_ERR_OTHER; + return mask; +} + +static void ata_pio_task(struct ata_port *arg_ap) +{ + struct ata_port *ap = arg_ap; + struct ata_queued_cmd *qc = ap->port_task_data; + u8 status; + int poll_next; + +fsm_start: + /* + * This is purely heuristic. This is a fast path. + * Sometimes when we enter, BSY will be cleared in + * 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, queue delayed work. + */ + 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) { + ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE); + return; + } + } + + poll_next = ata_hsm_move(ap, qc, status, 1); + + /* another command or interrupt handler + * may be running at this point. + */ + if (poll_next) + goto fsm_start; +} + +static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq) +{ + int poll_next; + +fsm_start: + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + poll_next = (qc->tf.flags & ATA_TFLAG_POLLING); + + if ((status & ATA_DRQ) == 0) { + if (status & (ATA_ERR | ATA_DF)) { + qc->err_mask |= AC_ERR_DEV; + } else { + qc->err_mask |= AC_ERR_HSM; + } + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + /* Device should not ask for data transfer (DRQ=1) + * when it finds something wrong. + * We ignore DRQ here and stop the HSM by + * changing hsm_task_state to HSM_ST_ERR and + * let the EH abort the command or reset the device. + */ + if (status & (ATA_ERR | ATA_DF)) { + if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) { + printf("DRQ=1 with device error, " + "dev_stat 0x%X\n", status); + qc->err_mask |= AC_ERR_HSM; + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + } + + if (qc->tf.protocol == ATA_PROT_PIO) { + /* PIO data out protocol. + * send first data block. + */ + /* ata_pio_sectors() might change the state + * to HSM_ST_LAST. so, the state is changed here + * before ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST; + ata_pio_sectors(qc); + } else { + printf("protocol is not ATA_PROT_PIO \n"); + } + break; + + case HSM_ST: + if ((status & ATA_DRQ) == 0) { + if (status & (ATA_ERR | ATA_DF)) { + qc->err_mask |= AC_ERR_DEV; + } else { + /* HSM violation. Let EH handle this. + * Phantom devices also trigger this + * condition. Mark hint. + */ + qc->err_mask |= AC_ERR_HSM | AC_ERR_NODEV_HINT; + } + + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + /* For PIO reads, some devices may ask for + * data transfer (DRQ=1) alone with ERR=1. + * We respect DRQ here and transfer one + * block of junk data before changing the + * hsm_task_state to HSM_ST_ERR. + * + * For PIO writes, ERR=1 DRQ=1 doesn't make + * sense since the data block has been + * transferred to the device. + */ + if (status & (ATA_ERR | ATA_DF)) { + qc->err_mask |= AC_ERR_DEV; + + if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { + ata_pio_sectors(qc); + status = ata_wait_idle(ap); + } + + if (status & (ATA_BUSY | ATA_DRQ)) + qc->err_mask |= AC_ERR_HSM; + + /* ata_pio_sectors() might change the + * state to HSM_ST_LAST. so, the state + * is changed after ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + ata_pio_sectors(qc); + if (ap->hsm_task_state == HSM_ST_LAST && + (!(qc->tf.flags & ATA_TFLAG_WRITE))) { + status = ata_wait_idle(ap); + goto fsm_start; + } + + poll_next = 1; + break; + + case HSM_ST_LAST: + if (!ata_ok(status)) { + qc->err_mask |= __ac_err_mask(status); + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + ap->hsm_task_state = HSM_ST_IDLE; + + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + + case HSM_ST_ERR: + /* make sure qc->err_mask is available to + * know what's wrong and recover + */ + ap->hsm_task_state = HSM_ST_IDLE; + + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + default: + poll_next = 0; + } + + return poll_next; +} + +static void ata_pio_sectors(struct ata_queued_cmd *qc) +{ + struct ata_port *ap; + ap = pap; + qc->pdata = ap->pdata; + + ata_pio_sector(qc); + + readb(qc->ap->ioaddr.altstatus_addr); + udelay(1); +} + +static void ata_pio_sector(struct ata_queued_cmd *qc) +{ + int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); + struct ata_port *ap = qc->ap; + unsigned int offset; + unsigned char *buf; + char temp_data_buf[512]; + + if (qc->curbytes == qc->nbytes - qc->sect_size) + ap->hsm_task_state = HSM_ST_LAST; + + offset = qc->curbytes; + + switch (qc->tf.command) { + case ATA_CMD_ID_ATA: + buf = (unsigned char *)&ata_device.id[0]; + break; + case ATA_CMD_PIO_READ_EXT: + case ATA_CMD_PIO_READ: + case ATA_CMD_PIO_WRITE_EXT: + case ATA_CMD_PIO_WRITE: + buf = qc->pdata + offset; + break; + default: + buf = (unsigned char *)&temp_data_buf[0]; + } + + ata_mmio_data_xfer(qc->dev, buf, qc->sect_size, do_write); + + qc->curbytes += qc->sect_size; + +} + +static void ata_mmio_data_xfer(struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int do_write) +{ + struct ata_port *ap = pap; + void __iomem *data_addr = ap->ioaddr.data_addr; + unsigned int words = buflen >> 1; + u16 *buf16 = (u16 *)buf; + unsigned int i = 0; + + udelay(100); + if (do_write) { + for (i = 0; i < words; i++) + writew(le16_to_cpu(buf16[i]), data_addr); + } else { + for (i = 0; i < words; i++) + buf16[i] = cpu_to_le16(readw(data_addr)); + } + + if (buflen & 0x01) { + __le16 align_buf[1] = { 0 }; + unsigned char *trailing_buf = buf + buflen - 1; + + if (do_write) { + memcpy(align_buf, trailing_buf, 1); + writew(le16_to_cpu(align_buf[0]), data_addr); + } else { + align_buf[0] = cpu_to_le16(readw(data_addr)); + memcpy(trailing_buf, align_buf, 1); + } + } +} + +static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) +{ + struct ata_port *ap = qc->ap; + + if (in_wq) { + /* EH might have kicked in while host lock is + * released. + */ + qc = &ap->qcmd[qc->tag]; + if (qc) { + if (!(qc->err_mask & AC_ERR_HSM)) { + ata_irq_on(ap); + ata_qc_complete(qc); + } else { + ata_port_freeze(ap); + } + } + } else { + if (!(qc->err_mask & AC_ERR_HSM)) { + ata_qc_complete(qc); + } else { + ata_port_freeze(ap); + } + } +} + +static u8 ata_irq_on(struct ata_port *ap) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + u8 tmp; + + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; + + if (ioaddr->ctl_addr) + writeb(ap->ctl, ioaddr->ctl_addr); + + tmp = ata_wait_idle(ap); + + return tmp; +} + +static unsigned int ata_tag_internal(unsigned int tag) +{ + return tag == ATA_MAX_QUEUE - 1; +} + +static void ata_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_device *dev = qc->dev; + if (qc->err_mask) + qc->flags |= ATA_QCFLAG_FAILED; + + if (qc->flags & ATA_QCFLAG_FAILED) { + if (!ata_tag_internal(qc->tag)) { + fill_result_tf(qc); + return; + } + } + if (qc->flags & ATA_QCFLAG_RESULT_TF) + fill_result_tf(qc); + + /* Some commands need post-processing after successful + * completion. + */ + switch (qc->tf.command) { + case ATA_CMD_SET_FEATURES: + if (qc->tf.feature != SETFEATURES_WC_ON && + qc->tf.feature != SETFEATURES_WC_OFF) + break; + case ATA_CMD_INIT_DEV_PARAMS: + case ATA_CMD_SET_MULTI: + break; + + case ATA_CMD_SLEEP: + dev->flags |= ATA_DFLAG_SLEEPING; + break; + } + + __ata_qc_complete(qc); +} + +static void fill_result_tf(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + qc->result_tf.flags = qc->tf.flags; + ata_tf_read(ap, &qc->result_tf); +} + +static void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + tf->command = ata_check_status(ap); + tf->feature = readb(ioaddr->error_addr); + tf->nsect = readb(ioaddr->nsect_addr); + tf->lbal = readb(ioaddr->lbal_addr); + tf->lbam = readb(ioaddr->lbam_addr); + tf->lbah = readb(ioaddr->lbah_addr); + tf->device = readb(ioaddr->device_addr); + + if (tf->flags & ATA_TFLAG_LBA48) { + if (ioaddr->ctl_addr) { + writeb(tf->ctl | ATA_HOB, ioaddr->ctl_addr); + + tf->hob_feature = readb(ioaddr->error_addr); + tf->hob_nsect = readb(ioaddr->nsect_addr); + tf->hob_lbal = readb(ioaddr->lbal_addr); + tf->hob_lbam = readb(ioaddr->lbam_addr); + tf->hob_lbah = readb(ioaddr->lbah_addr); + + writeb(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + } else { + printf("sata_dwc warnning register read.\n"); + } + } +} + +static void __ata_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; + + link->active_tag = ATA_TAG_POISON; + ap->nr_active_links--; + + if (qc->flags & ATA_QCFLAG_CLEAR_EXCL && ap->excl_link == link) + ap->excl_link = NULL; + + qc->flags &= ~ATA_QCFLAG_ACTIVE; + ap->qc_active &= ~(1 << qc->tag); +} + +static void ata_qc_free(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int tag; + qc->flags = 0; + tag = qc->tag; + if (tag < ATA_MAX_QUEUE) { + qc->tag = ATA_TAG_POISON; + clear_bit(tag, &ap->qc_allocated); + } +} + +static int check_sata_dev_state(void) +{ + unsigned long datalen; + unsigned char *pdata; + int ret = 0; + int i = 0; + char temp_data_buf[512]; + + while (1) { + udelay (10000); + + pdata = (unsigned char*)&temp_data_buf[0]; + datalen = 512; + + ret = ata_dev_read_sectors(pdata, datalen, 0, 1); + + if (ret == TRUE) + break; + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + dev_state = SATA_NODEVICE; + return FALSE; + } + + if ((i >= 100) && ((i % 100) == 0)) + printf("."); + } + + dev_state = SATA_READY; + + return TRUE; +} + +static unsigned int ata_dev_set_feature(struct ata_device *dev, + u8 enable, u8 feature) +{ + struct ata_taskfile tf; + struct ata_port *ap; + ap = pap; + unsigned int err_mask; + + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_SET_FEATURES; + tf.feature = enable; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = feature; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); + + return err_mask; +} + +static unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors) +{ + struct ata_taskfile tf; + struct ata_port *ap; + ap = pap; + unsigned int err_mask; + + if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) + return AC_ERR_INVALID; + + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_INIT_DEV_PARAMS; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = sectors; + tf.device |= (heads - 1) & 0x0f; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); + + if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED)) + err_mask = 0; + + return err_mask; +} + +#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) +#define SATA_MAX_READ_BLK 0xFF +#else +#define SATA_MAX_READ_BLK 0xFFFF +#endif + +ulong sata_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + ulong start,blks, buf_addr; + unsigned short smallblks; + unsigned long datalen; + unsigned char *pdata; + device &= 0xff; + + u32 block = 0; + u32 n_block = 0; + + if (dev_state != SATA_READY) + return 0; + + buf_addr = (unsigned long)buffer; + start = blknr; + blks = blkcnt; + do { + pdata = (unsigned char *)buf_addr; + if (blks > SATA_MAX_READ_BLK) { + datalen = sata_dev_desc[device].blksz * SATA_MAX_READ_BLK; + smallblks = SATA_MAX_READ_BLK; + + block = (u32)start; + n_block = (u32)smallblks; + + start += SATA_MAX_READ_BLK; + blks -= SATA_MAX_READ_BLK; + } else { + datalen = sata_dev_desc[device].blksz * SATA_MAX_READ_BLK; + datalen = sata_dev_desc[device].blksz * blks; + smallblks = (unsigned short)blks; + + block = (u32)start; + n_block = (u32)smallblks; + + start += blks; + blks = 0; + } + + if (ata_dev_read_sectors(pdata, datalen, block, n_block) != TRUE) { + printf("sata_dwc : Hard disk read error.\n"); + blkcnt -= blks; + break; + } + buf_addr += datalen; + } while (blks != 0); + + return (blkcnt); +} + +static int ata_dev_read_sectors(unsigned char *pdata, unsigned long datalen, + u32 block, u32 n_block) +{ + struct ata_port *ap = pap; + struct ata_device *dev = &ata_device; + struct ata_taskfile tf; + unsigned int class = ATA_DEV_ATA; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1; + int rc; + + if (dev_state == SATA_ERROR) + return FALSE; + + ata_dev_select(ap, dev->devno, 1, 1); + +retry: + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + + ap->pdata = pdata; + + tf.device = ATA_DEVICE_OBS; + + temp_n_block = n_block; + +#ifdef CONFIG_LBA48 + tf.command = ATA_CMD_PIO_READ_EXT; + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; + + tf.hob_feature = 31; + tf.feature = 31; + tf.hob_nsect = (n_block >> 8) & 0xff; + tf.nsect = n_block & 0xff; + + tf.hob_lbah = 0x0; + tf.hob_lbam = 0x0; + tf.hob_lbal = (block >> 24) & 0xff; + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; +#else + tf.command = ATA_CMD_PIO_READ; + tf.flags |= ATA_TFLAG_LBA ; + + tf.feature = 31; + tf.nsect = n_block & 0xff; + + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = (block >> 24) & 0xf; + + tf.device |= 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; + +#endif + + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.flags |= ATA_TFLAG_POLLING; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,0, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("READ_SECTORS NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + rc = -EINVAL; + reason = "device reports invalid type"; + + return TRUE; + +err_out: + printf("failed to READ SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); + return FALSE; +} + +#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) +#define SATA_MAX_WRITE_BLK 0xFF +#else +#define SATA_MAX_WRITE_BLK 0xFFFF +#endif + +ulong sata_write(int device, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + ulong start,blks, buf_addr; + unsigned short smallblks; + unsigned long datalen; + unsigned char *pdata; + device &= 0xff; + + + u32 block = 0; + u32 n_block = 0; + + if (dev_state != SATA_READY) + return 0; + + buf_addr = (unsigned long)buffer; + start = blknr; + blks = blkcnt; + do { + pdata = (unsigned char *)buf_addr; + if (blks > SATA_MAX_WRITE_BLK) { + datalen = sata_dev_desc[device].blksz * SATA_MAX_WRITE_BLK; + smallblks = SATA_MAX_WRITE_BLK; + + block = (u32)start; + n_block = (u32)smallblks; + + start += SATA_MAX_WRITE_BLK; + blks -= SATA_MAX_WRITE_BLK; + } else { + datalen = sata_dev_desc[device].blksz * blks; + smallblks = (unsigned short)blks; + + block = (u32)start; + n_block = (u32)smallblks; + + start += blks; + blks = 0; + } + + if (ata_dev_write_sectors(pdata, datalen, block, n_block) != TRUE) { + printf("sata_dwc : Hard disk read error.\n"); + blkcnt -= blks; + break; + } + buf_addr += datalen; + } while (blks != 0); + + return (blkcnt); +} + +static int ata_dev_write_sectors(unsigned char* pdata, unsigned long datalen, + u32 block, u32 n_block) +{ + struct ata_port *ap = pap; + struct ata_device *dev = &ata_device; + struct ata_taskfile tf; + unsigned int class = ATA_DEV_ATA; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1; + int rc; + + if (dev_state == SATA_ERROR) + return FALSE; + + ata_dev_select(ap, dev->devno, 1, 1); + +retry: + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + + ap->pdata = pdata; + + tf.device = ATA_DEVICE_OBS; + + temp_n_block = n_block; + + +#ifdef CONFIG_LBA48 + tf.command = ATA_CMD_PIO_WRITE_EXT; + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48 | ATA_TFLAG_WRITE; + + tf.hob_feature = 31; + tf.feature = 31; + tf.hob_nsect = (n_block >> 8) & 0xff; + tf.nsect = n_block & 0xff; + + tf.hob_lbah = 0x0; + tf.hob_lbam = 0x0; + tf.hob_lbal = (block >> 24) & 0xff; + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; +#else + tf.command = ATA_CMD_PIO_WRITE; + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_WRITE; + + tf.feature = 31; + tf.nsect = n_block & 0xff; + + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = (block >> 24) & 0xf; + + tf.device |= 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; + +#endif + + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.flags |= ATA_TFLAG_POLLING; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,0, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("READ_SECTORS NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + rc = -EINVAL; + reason = "device reports invalid type"; + + return TRUE; + +err_out: + printf("failed to WRITE SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); + return FALSE; +} diff -uprN u-boot-0507/drivers/block/sata_dwc.h u-boot-sata/drivers/block/sata_dwc.h --- u-boot-0507/drivers/block/sata_dwc.h 1970-01-01 09:00:00.000000000 +0900 +++ u-boot-sata/drivers/block/sata_dwc.h 2009-05-07 09:42:37.000000000 +0900 @@ -0,0 +1,463 @@ +/* + * sata_dwc.h + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld mmiesfeld@amcc.com + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese sr@denx.de + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * This program is free software; you can redistribute + * it and/or modify it under the terms of the GNU + * General Public License as published by the + * Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + */ +/* + * SATA support based on the chip canyonlands. + * + * 04-17-2009 + * The local version of this driver for the canyonlands board + * does not use interrupts but polls the chip instead. + */ + + +#ifndef _SATA_DWC_H_ +#define _SATA_DWC_H_ + +#define HZ 100 + +#define READ 0 +#define WRITE 1 + +enum { + ATA_READID_POSTRESET = (1 << 0), + + ATA_DNXFER_PIO = 0, + ATA_DNXFER_DMA = 1, + ATA_DNXFER_40C = 2, + ATA_DNXFER_FORCE_PIO = 3, + ATA_DNXFER_FORCE_PIO0 = 4, + + ATA_DNXFER_QUIET = (1 << 31), +}; + +enum hsm_task_states { + HSM_ST_IDLE, + HSM_ST_FIRST, + HSM_ST, + HSM_ST_LAST, + HSM_ST_ERR, +}; + +#define ATA_SHORT_PAUSE ((HZ >> 6) + 1) + +struct ata_queued_cmd { + struct ata_port *ap; + struct ata_device *dev; + + struct ata_taskfile tf; + u8 cdb[ATAPI_CDB_LEN]; + + unsigned long flags; + unsigned int tag; + unsigned int n_elem; + + int dma_dir; + + unsigned int sect_size; + + unsigned int nbytes; + unsigned int extrabytes; + unsigned int curbytes; + + unsigned int err_mask; + struct ata_taskfile result_tf; + + void *private_data; + void *lldd_task; + unsigned char *pdata; +}; + +typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc); + +#define ATA_TAG_POISON 0xfafbfcfdU + +enum { + LIBATA_MAX_PRD = ATA_MAX_PRD / 2, + LIBATA_DUMB_MAX_PRD = ATA_MAX_PRD / 4, + ATA_MAX_PORTS = 8, + ATA_DEF_QUEUE = 1, + ATA_MAX_QUEUE = 32, + ATA_TAG_INTERNAL = ATA_MAX_QUEUE - 1, + ATA_MAX_BUS = 2, + ATA_DEF_BUSY_WAIT = 10000, + + ATAPI_MAX_DRAIN = 16 << 10, + + ATA_SHT_EMULATED = 1, + ATA_SHT_CMD_PER_LUN = 1, + ATA_SHT_THIS_ID = -1, + ATA_SHT_USE_CLUSTERING = 1, + + ATA_DFLAG_LBA = (1 << 0), + ATA_DFLAG_LBA48 = (1 << 1), + ATA_DFLAG_CDB_INTR = (1 << 2), + ATA_DFLAG_NCQ = (1 << 3), + ATA_DFLAG_FLUSH_EXT = (1 << 4), + ATA_DFLAG_ACPI_PENDING = (1 << 5), + ATA_DFLAG_ACPI_FAILED = (1 << 6), + ATA_DFLAG_AN = (1 << 7), + ATA_DFLAG_HIPM = (1 << 8), + ATA_DFLAG_DIPM = (1 << 9), + ATA_DFLAG_DMADIR = (1 << 10), + ATA_DFLAG_CFG_MASK = (1 << 12) - 1, + + ATA_DFLAG_PIO = (1 << 12), + ATA_DFLAG_NCQ_OFF = (1 << 13), + ATA_DFLAG_SPUNDOWN = (1 << 14), + ATA_DFLAG_SLEEPING = (1 << 15), + ATA_DFLAG_DUBIOUS_XFER = (1 << 16), + ATA_DFLAG_INIT_MASK = (1 << 24) - 1, + + ATA_DFLAG_DETACH = (1 << 24), + ATA_DFLAG_DETACHED = (1 << 25), + + ATA_LFLAG_HRST_TO_RESUME = (1 << 0), + ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), + ATA_LFLAG_NO_SRST = (1 << 2), + ATA_LFLAG_ASSUME_ATA = (1 << 3), + ATA_LFLAG_ASSUME_SEMB = (1 << 4), + ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, + ATA_LFLAG_NO_RETRY = (1 << 5), + ATA_LFLAG_DISABLED = (1 << 6), + + ATA_FLAG_SLAVE_POSS = (1 << 0), + ATA_FLAG_SATA = (1 << 1), + ATA_FLAG_NO_LEGACY = (1 << 2), + ATA_FLAG_MMIO = (1 << 3), + ATA_FLAG_SRST = (1 << 4), + ATA_FLAG_SATA_RESET = (1 << 5), + ATA_FLAG_NO_ATAPI = (1 << 6), + ATA_FLAG_PIO_DMA = (1 << 7), + ATA_FLAG_PIO_LBA48 = (1 << 8), + ATA_FLAG_PIO_POLLING = (1 << 9), + ATA_FLAG_NCQ = (1 << 10), + ATA_FLAG_DEBUGMSG = (1 << 13), + ATA_FLAG_IGN_SIMPLEX = (1 << 15), + ATA_FLAG_NO_IORDY = (1 << 16), + ATA_FLAG_ACPI_SATA = (1 << 17), + ATA_FLAG_AN = (1 << 18), + ATA_FLAG_PMP = (1 << 19), + ATA_FLAG_IPM = (1 << 20), + + ATA_FLAG_DISABLED = (1 << 23), + + ATA_PFLAG_EH_PENDING = (1 << 0), + ATA_PFLAG_EH_IN_PROGRESS = (1 << 1), + ATA_PFLAG_FROZEN = (1 << 2), + ATA_PFLAG_RECOVERED = (1 << 3), + ATA_PFLAG_LOADING = (1 << 4), + ATA_PFLAG_UNLOADING = (1 << 5), + ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), + ATA_PFLAG_INITIALIZING = (1 << 7), + ATA_PFLAG_RESETTING = (1 << 8), + ATA_PFLAG_SUSPENDED = (1 << 17), + ATA_PFLAG_PM_PENDING = (1 << 18), + + ATA_QCFLAG_ACTIVE = (1 << 0), + ATA_QCFLAG_DMAMAP = (1 << 1), + ATA_QCFLAG_IO = (1 << 3), + ATA_QCFLAG_RESULT_TF = (1 << 4), + ATA_QCFLAG_CLEAR_EXCL = (1 << 5), + ATA_QCFLAG_QUIET = (1 << 6), + + ATA_QCFLAG_FAILED = (1 << 16), + ATA_QCFLAG_SENSE_VALID = (1 << 17), + ATA_QCFLAG_EH_SCHEDULED = (1 << 18), + + ATA_HOST_SIMPLEX = (1 << 0), + ATA_HOST_STARTED = (1 << 1), + + ATA_TMOUT_BOOT = 30 * 100, + ATA_TMOUT_BOOT_QUICK = 7 * 100, + ATA_TMOUT_INTERNAL = 30 * 100, + ATA_TMOUT_INTERNAL_QUICK = 5 * 100, + + /* FIXME: GoVault needs 2s but we can't afford that without + * parallel probing. 800ms is enough for iVDR disk + * HHD424020F7SV00. Increase to 2secs when parallel probing + * is in place. + */ + ATA_TMOUT_FF_WAIT = 4 * 100 / 5, + + BUS_UNKNOWN = 0, + BUS_DMA = 1, + BUS_IDLE = 2, + BUS_NOINTR = 3, + BUS_NODATA = 4, + BUS_TIMER = 5, + BUS_PIO = 6, + BUS_EDD = 7, + BUS_IDENTIFY = 8, + BUS_PACKET = 9, + + PORT_UNKNOWN = 0, + PORT_ENABLED = 1, + PORT_DISABLED = 2, + + /* encoding various smaller bitmaps into a single + * unsigned long bitmap + */ + ATA_NR_PIO_MODES = 7, + ATA_NR_MWDMA_MODES = 5, + ATA_NR_UDMA_MODES = 8, + + ATA_SHIFT_PIO = 0, + ATA_SHIFT_MWDMA = ATA_SHIFT_PIO + ATA_NR_PIO_MODES, + ATA_SHIFT_UDMA = ATA_SHIFT_MWDMA + ATA_NR_MWDMA_MODES, + + ATA_DMA_PAD_SZ = 4, + + ATA_ERING_SIZE = 32, + + ATA_DEFER_LINK = 1, + ATA_DEFER_PORT = 2, + + ATA_EH_DESC_LEN = 80, + + ATA_EH_REVALIDATE = (1 << 0), + ATA_EH_SOFTRESET = (1 << 1), + ATA_EH_HARDRESET = (1 << 2), + ATA_EH_ENABLE_LINK = (1 << 3), + ATA_EH_LPM = (1 << 4), + + ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, + ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, + + ATA_EHI_HOTPLUGGED = (1 << 0), + ATA_EHI_RESUME_LINK = (1 << 1), + ATA_EHI_NO_AUTOPSY = (1 << 2), + ATA_EHI_QUIET = (1 << 3), + + ATA_EHI_DID_SOFTRESET = (1 << 16), + ATA_EHI_DID_HARDRESET = (1 << 17), + ATA_EHI_PRINTINFO = (1 << 18), + ATA_EHI_SETMODE = (1 << 19), + ATA_EHI_POST_SETMODE = (1 << 20), + + ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET, + ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, + + ATA_EH_MAX_TRIES = 5, + + ATA_PROBE_MAX_TRIES = 3, + ATA_EH_DEV_TRIES = 3, + ATA_EH_PMP_TRIES = 5, + ATA_EH_PMP_LINK_TRIES = 3, + + SATA_PMP_SCR_TIMEOUT = 250, + + /* Horkage types. May be set by libata or controller on drives + (some horkage may be drive/controller pair dependant */ + + ATA_HORKAGE_DIAGNOSTIC = (1 << 0), + ATA_HORKAGE_NODMA = (1 << 1), + ATA_HORKAGE_NONCQ = (1 << 2), + ATA_HORKAGE_MAX_SEC_128 = (1 << 3), + ATA_HORKAGE_BROKEN_HPA = (1 << 4), + ATA_HORKAGE_SKIP_PM = (1 << 5), + ATA_HORKAGE_HPA_SIZE = (1 << 6), + ATA_HORKAGE_IPM = (1 << 7), + ATA_HORKAGE_IVB = (1 << 8), + ATA_HORKAGE_STUCK_ERR = (1 << 9), + + ATA_DMA_MASK_ATA = (1 << 0), + ATA_DMA_MASK_ATAPI = (1 << 1), + ATA_DMA_MASK_CFA = (1 << 2), + + ATAPI_READ = 0, + ATAPI_WRITE = 1, + ATAPI_READ_CD = 2, + ATAPI_PASS_THRU = 3, + ATAPI_MISC = 4, +}; + +enum ata_completion_errors { + AC_ERR_DEV = (1 << 0), + AC_ERR_HSM = (1 << 1), + AC_ERR_TIMEOUT = (1 << 2), + AC_ERR_MEDIA = (1 << 3), + AC_ERR_ATA_BUS = (1 << 4), + AC_ERR_HOST_BUS = (1 << 5), + AC_ERR_SYSTEM = (1 << 6), + AC_ERR_INVALID = (1 << 7), + AC_ERR_OTHER = (1 << 8), + AC_ERR_NODEV_HINT = (1 << 9), + AC_ERR_NCQ = (1 << 10), +}; + +enum ata_xfer_mask { + ATA_MASK_PIO = ((1LU << ATA_NR_PIO_MODES) - 1) << ATA_SHIFT_PIO, + ATA_MASK_MWDMA = ((1LU << ATA_NR_MWDMA_MODES) - 1) << ATA_SHIFT_MWDMA, + ATA_MASK_UDMA = ((1LU << ATA_NR_UDMA_MODES) - 1) << ATA_SHIFT_UDMA, +}; + +struct ata_port_info { + struct scsi_host_template *sht; + unsigned long flags; + unsigned long link_flags; + unsigned long pio_mask; + unsigned long mwdma_mask; + unsigned long udma_mask; + const struct ata_port_operations *port_ops; + void *private_data; +}; + +struct ata_ioports { + void __iomem *cmd_addr; + void __iomem *data_addr; + void __iomem *error_addr; + void __iomem *feature_addr; + void __iomem *nsect_addr; + void __iomem *lbal_addr; + void __iomem *lbam_addr; + void __iomem *lbah_addr; + void __iomem *device_addr; + void __iomem *status_addr; + void __iomem *command_addr; + void __iomem *altstatus_addr; + void __iomem *ctl_addr; + void __iomem *bmdma_addr; + void __iomem *scr_addr; +}; + +struct ata_host { + void __iomem * const *iomap; + unsigned int n_ports; + void *private_data; + const struct ata_port_operations *ops; + unsigned long flags; + struct ata_port *simplex_claimed; + struct ata_port *ports[0]; +}; + +struct ata_port_stats { + unsigned long unhandled_irq; + unsigned long idle_irq; + unsigned long rw_reqbuf; +}; + +struct ata_device { + struct ata_link *link; + unsigned int devno; + unsigned long flags; + unsigned int horkage; + struct scsi_device *sdev; +#ifdef CONFIG_ATA_ACPI + acpi_handle acpi_handle; + union acpi_object *gtf_cache; +#endif + u64 n_sectors; + unsigned int class; + + union { + u16 id[ATA_ID_WORDS]; + u32 gscr[SATA_PMP_GSCR_DWORDS]; + }; + + u8 pio_mode; + u8 dma_mode; + u8 xfer_mode; + unsigned int xfer_shift; + + unsigned int multi_count; + unsigned int max_sectors; + unsigned int cdb_len; + + unsigned long pio_mask; + unsigned long mwdma_mask; + unsigned long udma_mask; + + u16 cylinders; + u16 heads; + u16 sectors; + + int spdn_cnt; +}; + +enum dma_data_direction { + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, + DMA_NONE = 3, +}; + +struct ata_link { + struct ata_port *ap; + int pmp; + unsigned int active_tag; + u32 sactive; + + unsigned int flags; + + unsigned int hw_sata_spd_limit; + unsigned int sata_spd_limit; + unsigned int sata_spd; + + struct ata_device device[2]; +}; + +struct ata_port { + unsigned long flags; + unsigned int pflags; + unsigned int print_id; + unsigned int port_no; + + struct ata_ioports ioaddr; + + u8 ctl; + u8 last_ctl; + unsigned int pio_mask; + unsigned int mwdma_mask; + unsigned int udma_mask; + unsigned int cbl; + + struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; + unsigned long qc_allocated; + unsigned int qc_active; + int nr_active_links; + + struct ata_link link; + + int nr_pmp_links; + struct ata_link *pmp_link; + struct ata_link *excl_link; + + struct ata_port_stats stats; + struct ata_host *host; + + struct device *dev; + void *port_task_data; + + unsigned int hsm_task_state; + + u32 msg_enable; + void *private_data; + unsigned char *pdata; +}; + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#endif diff -uprN u-boot-0507/include/configs/canyonlands.h u-boot-sata/include/configs/canyonlands.h --- u-boot-0507/include/configs/canyonlands.h 2009-05-07 09:25:50.000000000 +0900 +++ u-boot-sata/include/configs/canyonlands.h 2009-05-07 09:49:10.000000000 +0900 @@ -454,6 +454,7 @@ #define CONFIG_CMD_SDRAM #define CONFIG_CMD_SNTP #define CONFIG_CMD_USB +#define CONFIG_CMD_SATA #elif defined(CONFIG_GLACIER) #define CONFIG_CMD_DATE #define CONFIG_CMD_DTT @@ -517,6 +518,21 @@ #endif /* CONFIG_460GT */
/*----------------------------------------------------------------------- + * S-ATA driver setup + *----------------------------------------------------------------------*/ +#define CONFIG_SATA_DWC + +#ifdef CONFIG_SATA_DWC +#define CONFIG_LIBATA + +#define SATA_BASE_ADDR 0xe20d1000 /* PPC460EX SATA Base Address */ +#define SATA_DMA_REG_ADDR 0xe20d0800 /* PPC460EX SATA Base Address */ +#define CONFIG_SYS_SATA_MAX_DEVICE 1 /* SATA MAX DEVICE */ +/* Convert sectorsize to wordsize */ +#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2) +#endif + +/*----------------------------------------------------------------------- * External Bus Controller (EBC) Setup *----------------------------------------------------------------------*/ --- Thanks.
Regards, Kazuaki Ichinohe.

Dear Kazuaki Ichinohe,
In message 4A027E44.5080100@fsi.co.jp you wrote:
Hello Denk, Stefan,
Could you please rebase your patch against the current top-of-tree mainline repository and resumbmit?
Thank you for the reply. I made the patch from the source obtained with git in 5/7. The confirmed patch is sent again. Please review this patch.
Please put comments BELOW the "---" line, not above. Only put the commit message ABOVE the "---" line. And note that there is only ONE "---" line in a patch.
[patch] diff -uprN u-boot-0507/drivers/block/Makefile u-boot-sata/drivers/block/Makefile --- u-boot-0507/drivers/block/Makefile 2009-05-07 09:25:48.000000000 +0900 +++ u-boot-sata/drivers/block/Makefile 2009-05-07 09:43:56.000000000 +0900 @@ -35,6 +35,7 @@ COBJS-$(CONFIG_SATA_SIL3114) += sata_sil COBJS-$(CONFIG_SCSI_AHCI) += ahci.o COBJS-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o COBJS-$(CONFIG_SYSTEMACE) += systemace.o +COBJS-$(CONFIG_SATA_DWC) += sata_dwc.o
Sorry, your patch is white-space corrupted:
patching file drivers/block/Makefile Hunk #1 FAILED at 35. 1 out of 1 hunk FAILED -- saving rejects to file drivers/block/Makefile.rej patching file drivers/block/sata_dwc.c patching file drivers/block/sata_dwc.h patching file include/configs/canyonlands.h Hunk #1 FAILED at 454. patch: **** malformed patch at line 2718: Thanks.
Best regards,
Wolfgang Denk
participants (5)
-
Anatolij Gustschin
-
Felix Radensky
-
Kazuaki Ichinohe
-
Stefan Roese
-
Wolfgang Denk