summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ata/ata-chipset.c89
1 files changed, 60 insertions, 29 deletions
diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c
index 5a0ae0d..378030d 100644
--- a/sys/dev/ata/ata-chipset.c
+++ b/sys/dev/ata/ata-chipset.c
@@ -321,8 +321,8 @@ ata_sata_phy_reset(device_t dev)
for (loop = 0; loop < 10; loop++) {
ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_RESET);
ata_udelay(100);
- if ((ATA_IDX_INL(ch, ATA_SCONTROL) &
- ATA_SC_DET_MASK) == ATA_SC_DET_RESET)
+ if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) ==
+ ATA_SC_DET_RESET)
break;
}
ata_udelay(5000);
@@ -409,7 +409,7 @@ ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis)
fis[0] = 0x27; /* host to device */
fis[1] = 0x80; /* command FIS (note PM goes here) */
fis[2] = ATA_PACKET_CMD;
- if (request->flags & ATA_R_DMA)
+ if (request->flags & (ATA_R_READ | ATA_R_WRITE))
fis[3] = ATA_F_DMA;
else {
fis[5] = request->transfersize;
@@ -620,7 +620,7 @@ ata_ahci_begin_transaction(struct ata_request *request)
ATA_IDX_OUTL(ch, ATA_SACTIVE, ATA_IDX_INL(ch, ATA_SACTIVE) & (1 << tag));
/* set command type bit */
- if (request->flags & ATA_R_ATAPI)
+ if (ch->devices & ATA_ATAPI_MASTER)
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) |
ATA_AHCI_P_CMD_ATAPI);
@@ -629,8 +629,28 @@ ata_ahci_begin_transaction(struct ata_request *request)
ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) &
~ATA_AHCI_P_CMD_ATAPI);
- /* issue the command */
+ /* issue command to controller */
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, (1 << tag));
+
+ if (!(request->flags & ATA_R_ATAPI)) {
+ /* device reset doesn't interrupt */
+ if (request->u.ata.command == ATA_DEVICE_RESET) {
+ u_int32_t tf_data;
+ int timeout = 1000000;
+
+ do {
+ DELAY(10);
+ tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + (ch->unit<<7));
+ } while ((tf_data & ATA_S_BUSY) && timeout--);
+ if (bootverbose)
+ device_printf(ch->dev, "device_reset timeout=%dus\n",
+ (1000000-timeout)*10);
+ request->status = tf_data;
+ if (request->status & ATA_S_ERROR)
+ request->error = tf_data >> 8;
+ return ATA_OP_FINISHED;
+ }
+ }
/* start the timeout */
callout_reset(&request->callout, request->timeout * hz,
@@ -676,7 +696,7 @@ ata_ahci_reset(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
struct ata_channel *ch = device_get_softc(dev);
- u_int32_t cmd;
+ u_int32_t cmd, signature;
int offset = ch->unit << 7;
int timeout;
@@ -695,10 +715,11 @@ ata_ahci_reset(device_t dev)
timeout = 0;
do {
DELAY(1000);
- if (timeout++ > 500)
+ if (timeout++ > 500) {
device_printf(dev, "stopping AHCI engine failed\n");
break;
}
+ }
while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR);
/* issue Command List Override if supported */
@@ -709,43 +730,53 @@ ata_ahci_reset(device_t dev)
timeout = 0;
do {
DELAY(1000);
- if (timeout++ > 500)
+ if (timeout++ > 500) {
device_printf(dev, "executing CLO failed\n");
break;
}
+ }
while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD+offset)&ATA_AHCI_P_CMD_CLO);
}
- /* spin up device */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, ATA_AHCI_P_CMD_SUD);
-
- /* enable interface */
+ /* reset PHY and decide what is present */
if (ata_sata_phy_reset(dev)) {
- switch (ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset)) {
- case 0xeb140101:
- ch->devices = ATA_ATAPI_MASTER;
- device_printf(ch->dev, "SATA ATAPI devices not supported yet\n");
- ch->devices = 0;
+
+ /* clear any interrupts pending on this channel */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset,
+ ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset));
+
+ /* clear SATA error register */
+ ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR));
+
+ /* start operations on this channel */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
+ (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE |
+ ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | ATA_AHCI_P_CMD_ST));
+
+ signature = ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset);
+ if (bootverbose)
+ device_printf(dev, "SIGNATURE: %08x\n", signature);
+ switch (signature) {
+ case 0x00000101:
+ ch->devices = ATA_ATA_MASTER;
break;
case 0x96690101:
ch->devices = ATA_PORTMULTIPLIER;
device_printf(ch->dev, "Portmultipliers not supported yet\n");
ch->devices = 0;
break;
- case 0x00000101:
- ch->devices = ATA_ATA_MASTER;
+ case 0xeb140101:
+ ch->devices = ATA_ATAPI_MASTER;
break;
+ default: /* SOS XXX */
+ if (bootverbose)
+ device_printf(ch->dev, "No signature, asuming disk device\n");
+ ch->devices = ATA_ATA_MASTER;
}
}
-
- /* clear any interrupts pending on this channel */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset,
- ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset));
-
- /* start operations on this channel */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
- (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE |
- ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | ATA_AHCI_P_CMD_ST));
+ if (bootverbose)
+ device_printf(dev, "ahci_reset devices=0x%b\n", ch->devices,
+ "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER");
}
static void
@@ -786,7 +817,7 @@ ata_ahci_setup_fis(struct ata_ahci_cmd_tab *ctp, struct ata_request *request)
bzero(ctp->cfis, 64);
if (request->flags & ATA_R_ATAPI) {
bzero(ctp->acmd, 32);
- bcopy(request->u.atapi.ccb, ctp->acmd, 12);
+ bcopy(request->u.atapi.ccb, ctp->acmd, 16);
}
return ata_request2fis_h2d(request, &ctp->cfis[0]);
}
OpenPOWER on IntegriCloud