diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c index 5a0ae0dbd0a2..378030dfbf9d 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]); }