From: Kazuaki Ichinohe <kazuichi@fsi.co.jp>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH] Canyonlands SATA harddisk driver
Date: Fri, 17 Apr 2009 16:31:23 +0900 [thread overview]
Message-ID: <49E8304B.1050208@fsi.co.jp> (raw)
In-Reply-To: <49D0827B.7010000@fsi.co.jp>
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@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@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
*----------------------------------------------------------------------*/
--
1.6.2.1
Regards,
Kazuaki Ichinohe.
Kazuaki Ichinohe wrote:
> Hello Denk,
>
> After confirming operation, I'll send sata_dwc.c with cmd_sata.c again.
>
> Regards,
> Kazuaki Ichinohe
>
next prev parent reply other threads:[~2009-04-17 7:31 UTC|newest]
Thread overview: 63+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-03-17 13:08 [U-Boot] About PCI of U-BOOT of CANYONLANDS Kazuaki Ichinohe
2009-03-17 13:13 ` Stefan Roese
2009-03-18 1:28 ` Kazuaki Ichinohe
2009-03-18 9:07 ` Stefan Roese
2009-03-18 9:13 ` Felix Radensky
2009-03-18 9:23 ` Stefan Roese
2009-03-18 9:34 ` Felix Radensky
2009-03-18 9:39 ` Stefan Roese
2009-03-18 12:03 ` Anatolij Gustschin
2009-03-18 12:07 ` Kazuaki Ichinohe
2009-03-18 12:29 ` Kazuaki Ichinohe
2009-03-18 13:00 ` Kazuaki Ichinohe
[not found] ` <49C0EFB2.9020800@fsi.co.jp>
2009-03-18 14:48 ` Anatolij Gustschin
2009-03-19 4:43 ` Kazuaki Ichinohe
2009-03-19 9:16 ` Anatolij Gustschin
2009-03-19 11:28 ` Kazuaki Ichinohe
2009-03-19 11:44 ` Anatolij Gustschin
2009-03-19 12:09 ` Kazuaki Ichinohe
2009-03-19 12:27 ` Anatolij Gustschin
2009-03-19 12:52 ` Kazuaki Ichinohe
2009-03-19 13:17 ` Anatolij Gustschin
2009-03-20 10:50 ` Kazuaki Ichinohe
2009-03-24 5:22 ` [U-Boot] [PATCH] Canyonlands SATA harddisk driver Kazuaki Ichinohe
2009-03-24 16:22 ` Stefan Roese
2009-03-25 11:32 ` Kazuaki Ichinohe
2009-03-25 16:04 ` Stefan Roese
2009-03-26 10:56 ` Kazuaki Ichinohe
2009-03-27 16:11 ` Stefan Roese
2009-03-27 16:31 ` Wolfgang Denk
2009-03-30 8:27 ` Kazuaki Ichinohe
2009-04-17 7:31 ` Kazuaki Ichinohe [this message]
2009-04-27 1:53 ` Kazuaki Ichinohe
2009-04-27 7:42 ` Stefan Roese
2009-04-29 6:58 ` Stefan Roese
2009-05-07 6:23 ` Kazuaki Ichinohe
2009-05-07 7:38 ` Wolfgang Denk
2009-05-08 6:27 Kazuaki Ichinohe
2009-05-11 2:13 ` Kazuaki Ichinohe
2009-05-11 13:01 ` Stefan Roese
2009-05-12 9:29 ` Kazuaki Ichinohe
2009-05-12 9:43 ` Kazuaki Ichinohe
2009-05-12 9:56 Kazuaki Ichinohe
2009-05-12 18:42 ` Wolfgang Denk
2009-05-13 8:56 Kazuaki Ichinohe
2009-05-14 9:45 ` Stefan Roese
2009-05-14 8:28 Kazuaki Ichinohe
2009-05-14 8:57 ` Stefan Roese
2009-05-15 9:32 Kazuaki Ichinohe
2009-05-20 12:47 ` Stefan Roese
2009-05-20 21:08 ` Shinya Kuribayashi
2009-05-28 19:22 ` Wolfgang Denk
2009-05-29 7:36 ` Kazuaki Ichinohe
2009-05-29 9:07 ` Shinya Kuribayashi
2009-06-02 0:28 ` Kazuaki Ichinohe
2009-06-02 0:44 ` Shinya Kuribayashi
2009-06-04 5:00 ` Kazuaki Ichinohe
2009-06-04 6:30 ` Shinya Kuribayashi
2009-06-04 6:57 ` Stefan Roese
2009-06-04 8:40 ` Wolfgang Denk
2009-06-02 0:41 ` Jean-Christophe PLAGNIOL-VILLARD
2009-06-12 9:10 Kazuaki Ichinohe
2009-07-19 9:24 ` Wolfgang Denk
2009-06-12 9:50 Kazuaki Ichinohe
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=49E8304B.1050208@fsi.co.jp \
--to=kazuichi@fsi.co.jp \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.