Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 133587
b: refs/heads/master
c: 70f8b79
h: refs/heads/master
i:
  133585: 97631fa
  133583: ce37f95
v: v3
  • Loading branch information
Mark Lord authored and Jeff Garzik committed Mar 25, 2009
1 parent 5474493 commit bfae404
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 1a660164c291f41b2aa853a7269b310933574ef9
refs/heads/master: 70f8b79cf3a2eb892a01271fdfbb1903c0c982a8
116 changes: 116 additions & 0 deletions trunk/drivers/ata/sata_mv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1821,6 +1821,105 @@ static u8 mv_sff_check_status(struct ata_port *ap)
return stat;
}

/**
* mv_send_fis - Send a FIS, using the "Vendor-Unique FIS" register
* @fis: fis to be sent
* @nwords: number of 32-bit words in the fis
*/
static unsigned int mv_send_fis(struct ata_port *ap, u32 *fis, int nwords)
{
void __iomem *port_mmio = mv_ap_base(ap);
u32 ifctl, old_ifctl, ifstat;
int i, timeout = 200, final_word = nwords - 1;

/* Initiate FIS transmission mode */
old_ifctl = readl(port_mmio + SATA_IFCTL_OFS);
ifctl = 0x100 | (old_ifctl & 0xf);
writelfl(ifctl, port_mmio + SATA_IFCTL_OFS);

/* Send all words of the FIS except for the final word */
for (i = 0; i < final_word; ++i)
writel(fis[i], port_mmio + VENDOR_UNIQUE_FIS_OFS);

/* Flag end-of-transmission, and then send the final word */
writelfl(ifctl | 0x200, port_mmio + SATA_IFCTL_OFS);
writelfl(fis[final_word], port_mmio + VENDOR_UNIQUE_FIS_OFS);

/*
* Wait for FIS transmission to complete.
* This typically takes just a single iteration.
*/
do {
ifstat = readl(port_mmio + SATA_IFSTAT_OFS);
} while (!(ifstat & 0x1000) && --timeout);

/* Restore original port configuration */
writelfl(old_ifctl, port_mmio + SATA_IFCTL_OFS);

/* See if it worked */
if ((ifstat & 0x3000) != 0x1000) {
ata_port_printk(ap, KERN_WARNING,
"%s transmission error, ifstat=%08x\n",
__func__, ifstat);
return AC_ERR_OTHER;
}
return 0;
}

/**
* mv_qc_issue_fis - Issue a command directly as a FIS
* @qc: queued command to start
*
* Note that the ATA shadow registers are not updated
* after command issue, so the device will appear "READY"
* if polled, even while it is BUSY processing the command.
*
* So we use a status hook to fake ATA_BUSY until the drive changes state.
*
* Note: we don't get updated shadow regs on *completion*
* of non-data commands. So avoid sending them via this function,
* as they will appear to have completed immediately.
*
* GEN_IIE has special registers that we could get the result tf from,
* but earlier chipsets do not. For now, we ignore those registers.
*/
static unsigned int mv_qc_issue_fis(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct mv_port_priv *pp = ap->private_data;
struct ata_link *link = qc->dev->link;
u32 fis[5];
int err = 0;

ata_tf_to_fis(&qc->tf, link->pmp, 1, (void *)fis);
err = mv_send_fis(ap, fis, sizeof(fis) / sizeof(fis[0]));
if (err)
return err;

switch (qc->tf.protocol) {
case ATAPI_PROT_PIO:
pp->pp_flags |= MV_PP_FLAG_FAKE_ATA_BUSY;
/* fall through */
case ATAPI_PROT_NODATA:
ap->hsm_task_state = HSM_ST_FIRST;
break;
case ATA_PROT_PIO:
pp->pp_flags |= MV_PP_FLAG_FAKE_ATA_BUSY;
if (qc->tf.flags & ATA_TFLAG_WRITE)
ap->hsm_task_state = HSM_ST_FIRST;
else
ap->hsm_task_state = HSM_ST;
break;
default:
ap->hsm_task_state = HSM_ST_LAST;
break;
}

if (qc->tf.flags & ATA_TFLAG_POLLING)
ata_pio_queue_task(ap, qc, 0);
return 0;
}

/**
* mv_qc_issue - Initiate a command to the host
* @qc: queued command to start
Expand Down Expand Up @@ -1896,6 +1995,23 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
mv_stop_edma(ap);
mv_clear_and_enable_port_irqs(ap, mv_ap_base(ap), port_irqs);
mv_pmp_select(ap, qc->dev->link->pmp);

if (qc->tf.command == ATA_CMD_READ_LOG_EXT) {
struct mv_host_priv *hpriv = ap->host->private_data;
/*
* Workaround for 88SX60x1 FEr SATA#25 (part 2).
*
* After any NCQ error, the READ_LOG_EXT command
* from libata-eh *must* use mv_qc_issue_fis().
* Otherwise it might fail, due to chip errata.
*
* Rather than special-case it, we'll just *always*
* use this method here for READ_LOG_EXT, making for
* easier testing.
*/
if (IS_GEN_II(hpriv))
return mv_qc_issue_fis(qc);
}
return ata_sff_qc_issue(qc);
}

Expand Down

0 comments on commit bfae404

Please sign in to comment.