Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 98103
b: refs/heads/master
c: bd17243
h: refs/heads/master
i:
  98101: 12efb3e
  98099: 7f26159
  98095: c2f2519
v: v3
  • Loading branch information
Shane Huang authored and Jeff Garzik committed Jun 13, 2008
1 parent 2cd9121 commit ecbf32d
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 18 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: e297d99e103f951a71fcb1534f1ff3480dd3a851
refs/heads/master: bd17243a84632465f5403bc9eb8b4831bd67e582
99 changes: 82 additions & 17 deletions trunk/drivers/ata/ahci.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ static void ahci_pmp_attach(struct ata_port *ap);
static void ahci_pmp_detach(struct ata_port *ap);
static int ahci_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
static int ahci_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
Expand Down Expand Up @@ -331,6 +333,12 @@ static struct ata_port_operations ahci_p5wdh_ops = {
.hardreset = ahci_p5wdh_hardreset,
};

static struct ata_port_operations ahci_sb600_ops = {
.inherits = &ahci_ops,
.softreset = ahci_sb600_softreset,
.pmp_softreset = ahci_sb600_softreset,
};

#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)

static const struct ata_port_info ahci_port_info[] = {
Expand Down Expand Up @@ -361,11 +369,11 @@ static const struct ata_port_info ahci_port_info[] = {
{
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
AHCI_HFLAG_SECT255 | AHCI_HFLAG_NO_PMP),
AHCI_HFLAG_SECT255),
.flags = AHCI_FLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
.port_ops = &ahci_sb600_ops,
},
/* board_ahci_mv */
{
Expand All @@ -379,12 +387,11 @@ static const struct ata_port_info ahci_port_info[] = {
},
/* board_ahci_sb700 */
{
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
AHCI_HFLAG_NO_PMP),
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL),
.flags = AHCI_FLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
.port_ops = &ahci_sb600_ops,
},
/* board_ahci_mcp65 */
{
Expand Down Expand Up @@ -1278,19 +1285,11 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
return 0;
}

static int ahci_check_ready(struct ata_link *link)
{
void __iomem *port_mmio = ahci_port_base(link->ap);
u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;

return ata_check_ready(status);
}

static int ahci_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
int pmp, unsigned long deadline,
int (*check_ready)(struct ata_link *link))
{
struct ata_port *ap = link->ap;
int pmp = sata_srst_pmp(link);
const char *reason = NULL;
unsigned long now, msecs;
struct ata_taskfile tf;
Expand Down Expand Up @@ -1328,7 +1327,7 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);

/* wait for link to become ready */
rc = ata_wait_after_reset(link, deadline, ahci_check_ready);
rc = ata_wait_after_reset(link, deadline, check_ready);
/* link occupied, -ENODEV too is an error */
if (rc) {
reason = "device not ready";
Expand All @@ -1344,6 +1343,72 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
return rc;
}

static int ahci_check_ready(struct ata_link *link)
{
void __iomem *port_mmio = ahci_port_base(link->ap);
u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;

return ata_check_ready(status);
}

static int ahci_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
int pmp = sata_srst_pmp(link);

DPRINTK("ENTER\n");

return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
}

static int ahci_sb600_check_ready(struct ata_link *link)
{
void __iomem *port_mmio = ahci_port_base(link->ap);
u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
u32 irq_status = readl(port_mmio + PORT_IRQ_STAT);

/*
* There is no need to check TFDATA if BAD PMP is found due to HW bug,
* which can save timeout delay.
*/
if (irq_status & PORT_IRQ_BAD_PMP)
return -EIO;

return ata_check_ready(status);
}

static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
struct ata_port *ap = link->ap;
void __iomem *port_mmio = ahci_port_base(ap);
int pmp = sata_srst_pmp(link);
int rc;
u32 irq_sts;

DPRINTK("ENTER\n");

rc = ahci_do_softreset(link, class, pmp, deadline,
ahci_sb600_check_ready);

/*
* Soft reset fails on some ATI chips with IPMS set when PMP
* is enabled but SATA HDD/ODD is connected to SATA port,
* do soft reset again to port 0.
*/
if (rc == -EIO) {
irq_sts = readl(port_mmio + PORT_IRQ_STAT);
if (irq_sts & PORT_IRQ_BAD_PMP) {
ata_link_printk(link, KERN_WARNING,
"failed due to HW bug, retry pmp=0\n");
rc = ahci_do_softreset(link, class, 0, deadline,
ahci_check_ready);
}
}

return rc;
}

static int ahci_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
Expand Down

0 comments on commit ecbf32d

Please sign in to comment.