Fix the signature matching code on AHCI controllers.

Add SATA ATAPI support for AHCI controllers.
This commit is contained in:
sos 2007-10-26 09:01:06 +00:00
parent 8a3367a3b4
commit 4e65ee2c1d

View File

@ -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]);
}