diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp index bc9f9b7091..cb1a904504 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp @@ -131,8 +131,8 @@ AHCIPort::Init2() FlushPostedWrites(); - ResetDevice(); - PostResetDevice(); + ResetPort(true); + PostReset(); TRACE("ie 0x%08lx\n", fRegs->ie); TRACE("is 0x%08lx\n", fRegs->is); @@ -186,20 +186,13 @@ AHCIPort::Uninit() } -status_t +void AHCIPort::ResetDevice() { - TRACE("AHCIPort::ResetDevice port %d\n", fIndex); + if (fRegs->cmd & PORT_CMD_ST) + TRACE("AHCIPort::ResetDevice PORT_CMD_ST set, behaviour undefined\n"); - // stop DMA engine - fRegs->cmd &= ~PORT_CMD_ST; - FlushPostedWrites(); - - if (wait_until_clear(&fRegs->cmd, PORT_CMD_CR, 500000) < B_OK) { - TRACE("AHCIPort::ResetDevice port %d error DMA engine doesn't stop\n", fIndex); - } - - // perform a hard reset + // perform a hard reset fRegs->sctl = (fRegs->sctl & ~0xf) | 1; FlushPostedWrites(); spin(1100); @@ -223,6 +216,30 @@ AHCIPort::ResetDevice() // clear error bits fRegs->serr = fRegs->serr; FlushPostedWrites(); +} + + + +status_t +AHCIPort::ResetPort(bool forceDeviceReset) +{ + TRACE("AHCIPort::ResetPort port %d\n", fIndex); + + // stop DMA engine + fRegs->cmd &= ~PORT_CMD_ST; + FlushPostedWrites(); + + if (wait_until_clear(&fRegs->cmd, PORT_CMD_CR, 500000) < B_OK) { + TRACE("AHCIPort::ResetPort port %d error DMA engine doesn't stop\n", fIndex); + } + + bool deviceBusy = fRegs->tfd & (ATA_BSY | ATA_DRQ); + + TRACE("AHCIPort::ResetPort port %d, deviceBusy %d, forceDeviceReset %d\n", + fIndex, deviceBusy, forceDeviceReset); + + if (deviceBusy || forceDeviceReset) + ResetDevice(); // start DMA engine fRegs->cmd |= PORT_CMD_ST; @@ -233,12 +250,12 @@ AHCIPort::ResetDevice() status_t -AHCIPort::PostResetDevice() +AHCIPort::PostReset() { - TRACE("AHCIPort::PostResetDevice port %d\n", fIndex); + TRACE("AHCIPort::PostReset port %d\n", fIndex); if ((fRegs->ssts & 0xf) != 0x3 || (fRegs->tfd & 0xff) == 0x7f) { - TRACE("AHCIPort::PostResetDevice port %d: no device\n", fIndex); + TRACE("AHCIPort::PostReset port %d: no device\n", fIndex); return B_OK; } @@ -246,7 +263,7 @@ AHCIPort::PostResetDevice() snooze(200000); if ((fRegs->tfd & 0xff) == 0xff) { - TRACE("AHCIPort::PostResetDevice port %d: invalid task file status 0xff\n", fIndex); + TRACE("AHCIPort::PostReset port %d: invalid task file status 0xff\n", fIndex); return B_ERROR; } @@ -747,8 +764,8 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request) if (fResetPort) { fResetPort = false; - ResetDevice(); - PostResetDevice(); + ResetPort(); + PostReset(); } // TRACE("AHCIPort::ScsiExecuteRequest port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length); diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h index 740555acce..90eeb8b324 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h @@ -38,8 +38,9 @@ private: void ExecuteSataRequest(sata_request *request, bool isWrite = false); - status_t ResetDevice(); - status_t PostResetDevice(); + void ResetDevice(); + status_t ResetPort(bool forceDeviceReset = false); + status_t PostReset(); void FlushPostedWrites(); void DumpD2HFis();