Index: ahcisata_core.c =================================================================== RCS file: /cvsroot/src/sys/dev/ic/ahcisata_core.c,v retrieving revision 1.60 diff -u -p -r1.60 ahcisata_core.c --- ahcisata_core.c 11 Nov 2017 16:49:13 -0000 1.60 +++ ahcisata_core.c 21 Jun 2018 21:52:55 -0000 @@ -877,18 +877,71 @@ end: return 0; } +static uint32_t +ahci_sata_phy_reset(struct ata_channel *chp, int flags) +{ + struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac; + uint32_t status; + int timeout; + bool found = false; + + AHCI_WRITE(sc, AHCI_P_SCTL(chp->ch_channel), + SControl_DET_INIT | SControl_SPD_ANY | SControl_IPM_NONE); + DELAY(1000); + + AHCI_WRITE(sc, AHCI_P_SCTL(chp->ch_channel), + SControl_DET_NONE | SControl_SPD_ANY | SControl_IPM_NONE); + + /* Wait up to 1s for "connect well" */ + for (timeout = 0; timeout < 100 ; timeout++) { + status = AHCI_READ(sc, AHCI_P_SSTS(chp->ch_channel)); + + if ((status & SStatus_DET_mask) != SStatus_DET_NODEV) + found = true; + + if (((status & SStatus_DET_mask) == SStatus_DET_DEV) && + ((status & SStatus_SPD_mask) != SStatus_SPD_NONE) && + ((status & SStatus_IPM_mask) == SStatus_IPM_ACTIVE)) + break; + + if ((status & SStatus_DET_mask) == SStatus_DET_OFFLINE) + goto out; + + if (!found && timeout >= 10) { + /* No device detected yet */ + break; + } + + ata_delay(chp, 10, "ahciprst", flags); + } + if (timeout >= 100) { + aprint_error( + "%s port %d: SATA connect timeout time=%dms status=%08x\n", + device_xname(sc->sc_atac.atac_dev), chp->ch_channel, + timeout * 10, status); + goto out; + } + aprint_verbose("%s port %d: SATA connect time=%dms status=%08x\n", + device_xname(sc->sc_atac.atac_dev), chp->ch_channel, + timeout * 10, status); + /* Clear SATA error register */ + AHCI_WRITE(sc, AHCI_P_SERR(chp->ch_channel), 0xffffffff); + +out: + sata_interpret_det(chp, status); + return (status & SStatus_DET_mask); +} + static void ahci_reset_channel(struct ata_channel *chp, int flags) { struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac; - struct ahci_channel *achp = (struct ahci_channel *)chp; int i, tfd; ata_channel_lock(chp); ahci_channel_stop(sc, chp, flags); - if (sata_reset_interface(chp, sc->sc_ahcit, achp->ahcic_scontrol, - achp->ahcic_sstatus, flags) != SStatus_DET_DEV) { + if (ahci_sata_phy_reset(chp, flags) != SStatus_DET_DEV) { printf("%s: port %d reset failed\n", AHCINAME(sc), chp->ch_channel); /* XXX and then ? */ } @@ -941,7 +994,6 @@ static void ahci_probe_drive(struct ata_channel *chp) { struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac; - struct ahci_channel *achp = (struct ahci_channel *)chp; uint32_t sig; struct ata_xfer *xfer; @@ -960,8 +1012,7 @@ ahci_probe_drive(struct ata_channel *chp AHCI_P_CMD_ICC_AC | AHCI_P_CMD_FRE | AHCI_P_CMD_POD | AHCI_P_CMD_SUD); /* reset the PHY and bring online */ - switch (sata_reset_interface(chp, sc->sc_ahcit, achp->ahcic_scontrol, - achp->ahcic_sstatus, AT_WAIT)) { + switch (ahci_sata_phy_reset(chp, AT_WAIT)) { case SStatus_DET_DEV: ata_delay(chp, 500, "ahcidv", AT_WAIT); if (sc->sc_ahci_cap & AHCI_CAP_SPM) {