perform port reset and wait for devices to be detected
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22293 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
be30f13184
commit
22cf14cfbe
@ -28,8 +28,8 @@ AHCIController::AHCIController(device_node_handle node, pci_device_info *device)
|
||||
{
|
||||
memset(fPort, 0, sizeof(fPort));
|
||||
|
||||
ASSERT(sizeof(ahci_port) == 120);
|
||||
ASSERT(sizeof(ahci_hba) == 4096);
|
||||
ASSERT(sizeof(ahci_port) == 128);
|
||||
ASSERT(sizeof(ahci_hba) == 4352);
|
||||
ASSERT(sizeof(fis) == 256);
|
||||
ASSERT(sizeof(command_list_entry) == 32);
|
||||
ASSERT(sizeof(command_table) == 128);
|
||||
@ -144,19 +144,31 @@ AHCIController::Init()
|
||||
TRACE("out of memory creating port %d", i);
|
||||
break;
|
||||
}
|
||||
status_t status = fPort[i]->Init();
|
||||
status_t status = fPort[i]->Init1();
|
||||
if (status < B_OK) {
|
||||
TRACE("init port %d failed", i);
|
||||
TRACE("init-1 port %d failed", i);
|
||||
delete fPort[i];
|
||||
fPort[i] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// enable interrupts
|
||||
fRegs->ghc |= GHC_IE;
|
||||
RegsFlush();
|
||||
FlushPostedWrites();
|
||||
|
||||
for (int i = 0; i <= fPortCountMax; i++) {
|
||||
if (fPort[i]) {
|
||||
status_t status = fPort[i]->Init2();
|
||||
if (status < B_OK) {
|
||||
TRACE("init-2 port %d failed", i);
|
||||
fPort[i]->Uninit();
|
||||
delete fPort[i];
|
||||
fPort[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return B_OK;
|
||||
|
||||
@ -180,11 +192,11 @@ AHCIController::Uninit()
|
||||
|
||||
// disable interrupts
|
||||
fRegs->ghc &= ~GHC_IE;
|
||||
RegsFlush();
|
||||
FlushPostedWrites();
|
||||
|
||||
// clear pending interrupts
|
||||
fRegs->is = 0xffffffff;
|
||||
RegsFlush();
|
||||
FlushPostedWrites();
|
||||
|
||||
// well...
|
||||
remove_io_interrupt_handler(fIRQ, Interrupt, this);
|
||||
@ -204,8 +216,9 @@ AHCIController::ResetController()
|
||||
uint32 saveCaps = fRegs->cap & (CAP_SMPS | CAP_SSS | CAP_SPM | CAP_EMS | CAP_SXS);
|
||||
uint32 savePI = fRegs->pi;
|
||||
|
||||
#if 1
|
||||
fRegs->ghc |= GHC_HR;
|
||||
RegsFlush();
|
||||
FlushPostedWrites();
|
||||
for (int i = 0; i < 20; i++) {
|
||||
snooze(50000);
|
||||
if ((fRegs->ghc & GHC_HR) == 0)
|
||||
@ -213,12 +226,17 @@ AHCIController::ResetController()
|
||||
}
|
||||
if (fRegs->ghc & GHC_HR)
|
||||
return B_TIMED_OUT;
|
||||
#else
|
||||
fRegs->ghc &= ~GHC_AE;
|
||||
fRegs->is = 0xffffffff;
|
||||
FlushPostedWrites();
|
||||
#endif
|
||||
|
||||
fRegs->ghc |= GHC_AE;
|
||||
RegsFlush();
|
||||
FlushPostedWrites();
|
||||
fRegs->cap |= saveCaps;
|
||||
fRegs->pi = savePI;
|
||||
RegsFlush();
|
||||
FlushPostedWrites();
|
||||
|
||||
if (fPCIVendorID == 0x8086) {
|
||||
// Intel PCS—Port Control and Status
|
||||
@ -264,7 +282,7 @@ AHCIController::ExecuteRequest(scsi_ccb *request)
|
||||
return;
|
||||
}
|
||||
|
||||
fPort[request->target_id]->ExecuteRequest(request);
|
||||
fPort[request->target_id]->ScsiExecuteRequest(request);
|
||||
}
|
||||
|
||||
|
||||
@ -274,7 +292,7 @@ AHCIController::AbortRequest(scsi_ccb *request)
|
||||
if (request->target_lun || !fPort[request->target_id])
|
||||
return SCSI_DEV_NOT_THERE;
|
||||
|
||||
return fPort[request->target_id]->AbortRequest(request);
|
||||
return fPort[request->target_id]->ScsiAbortRequest(request);
|
||||
}
|
||||
|
||||
|
||||
@ -284,7 +302,7 @@ AHCIController::TerminateRequest(scsi_ccb *request)
|
||||
if (request->target_lun || !fPort[request->target_id])
|
||||
return SCSI_DEV_NOT_THERE;
|
||||
|
||||
return fPort[request->target_id]->TerminateRequest(request);
|
||||
return fPort[request->target_id]->ScsiTerminateRequest(request);
|
||||
}
|
||||
|
||||
|
||||
@ -294,6 +312,6 @@ AHCIController::ResetDevice(uchar targetID, uchar targetLUN)
|
||||
if (targetLUN || !fPort[targetID])
|
||||
return SCSI_DEV_NOT_THERE;
|
||||
|
||||
return fPort[targetID]->ResetDevice();
|
||||
return fPort[targetID]->ScsiResetDevice();
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ public:
|
||||
private:
|
||||
bool IsDevicePresent(uint device);
|
||||
status_t ResetController();
|
||||
void RegsFlush();
|
||||
void FlushPostedWrites();
|
||||
|
||||
static int32 Interrupt(void *data);
|
||||
|
||||
@ -58,7 +58,7 @@ private:
|
||||
|
||||
|
||||
inline void
|
||||
AHCIController::RegsFlush()
|
||||
AHCIController::FlushPostedWrites()
|
||||
{
|
||||
volatile uint32 dummy = fRegs->ghc;
|
||||
dummy = dummy;
|
||||
|
@ -132,7 +132,7 @@ enum {
|
||||
PORT_INT_SDB | PORT_INT_DS | PORT_INT_PS | PORT_INT_DHR)
|
||||
|
||||
enum {
|
||||
ATA_BUSY = 0x80,
|
||||
ATA_BSY = 0x80,
|
||||
ATA_DRQ = 0x08,
|
||||
ATA_ERR = 0x01,
|
||||
};
|
||||
@ -237,7 +237,7 @@ wait_until_set(volatile uint32 *reg, uint32 bits, bigtime_t timeout)
|
||||
{
|
||||
int trys = (timeout + 9999) / 10000;
|
||||
while (trys--) {
|
||||
if ((*reg & bits) == bits)
|
||||
if (((*reg) & bits) == bits)
|
||||
return B_OK;
|
||||
snooze(10000);
|
||||
}
|
||||
@ -250,7 +250,7 @@ wait_until_clear(volatile uint32 *reg, uint32 bits, bigtime_t timeout)
|
||||
{
|
||||
int trys = (timeout + 9999) / 10000;
|
||||
while (trys--) {
|
||||
if ((*reg & bits) == 0)
|
||||
if (((*reg) & bits) == 0)
|
||||
return B_OK;
|
||||
snooze(10000);
|
||||
}
|
||||
|
@ -29,9 +29,9 @@ AHCIPort::~AHCIPort()
|
||||
|
||||
|
||||
status_t
|
||||
AHCIPort::Init()
|
||||
AHCIPort::Init1()
|
||||
{
|
||||
TRACE("AHCIPort::Init port %d\n", fIndex);
|
||||
TRACE("AHCIPort::Init1 port %d\n", fIndex);
|
||||
|
||||
size_t size = sizeof(command_list_entry) * COMMAND_LIST_ENTRY_COUNT + sizeof(fis) + sizeof(command_table) + sizeof(prd) * PRD_TABLE_ENTRY_COUNT;
|
||||
|
||||
@ -67,7 +67,8 @@ AHCIPort::Init()
|
||||
fRegs->is = fRegs->is;
|
||||
|
||||
// clear error bits
|
||||
fRegs->serr = fRegs->serr;
|
||||
// fRegs->serr = fRegs->serr;
|
||||
fRegs->serr = 0xffffffff;
|
||||
|
||||
// spin up device
|
||||
fRegs->cmd |= PORT_CMD_SUD;
|
||||
@ -78,12 +79,39 @@ AHCIPort::Init()
|
||||
// enable FIS receive
|
||||
fRegs->cmd |= PORT_CMD_FER;
|
||||
|
||||
FlushPostedWrites();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// called with global interrupts enabled
|
||||
status_t
|
||||
AHCIPort::Init2()
|
||||
{
|
||||
TRACE("AHCIPort::Init2 port %d\n", fIndex);
|
||||
|
||||
// start DMA engine
|
||||
fRegs->cmd |= PORT_CMD_ST;
|
||||
|
||||
// enable interrupts
|
||||
fRegs->ie = PORT_INT_MASK;
|
||||
|
||||
FlushPostedWrites();
|
||||
|
||||
// if (fRegs->sig == 0xffffffff)
|
||||
ResetDevice();
|
||||
|
||||
PostResetDevice();
|
||||
|
||||
TRACE("ie 0x%08lx\n", fRegs->ie);
|
||||
TRACE("is 0x%08lx\n", fRegs->is);
|
||||
TRACE("cmd 0x%08lx\n", fRegs->cmd);
|
||||
TRACE("ssts 0x%08lx\n", fRegs->ssts);
|
||||
TRACE("sctl 0x%08lx\n", fRegs->sctl);
|
||||
TRACE("serr 0x%08lx\n", fRegs->serr);
|
||||
TRACE("sact 0x%08lx\n", fRegs->sact);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -97,13 +125,7 @@ AHCIPort::Uninit()
|
||||
fRegs->cmd &= ~PORT_CMD_FER;
|
||||
|
||||
// wait for receive completition, up to 500ms
|
||||
for (int i = 0; i < 15; i++) {
|
||||
if (!(fRegs->cmd & PORT_CMD_FR))
|
||||
break;
|
||||
snooze(50000);
|
||||
}
|
||||
|
||||
if (fRegs->cmd & PORT_CMD_FR) {
|
||||
if (wait_until_clear(&fRegs->cmd, PORT_CMD_FR, 500000) < B_OK) {
|
||||
TRACE("AHCIPort::Uninit port %d error FIS rx still running\n", fIndex);
|
||||
}
|
||||
|
||||
@ -111,13 +133,7 @@ AHCIPort::Uninit()
|
||||
fRegs->cmd &= ~PORT_CMD_ST;
|
||||
|
||||
// wait for DMA completition
|
||||
for (int i = 0; i < 15; i++) {
|
||||
if (!(fRegs->cmd & PORT_CMD_CR))
|
||||
break;
|
||||
snooze(50000);
|
||||
}
|
||||
|
||||
if (fRegs->cmd & PORT_CMD_CR) {
|
||||
if (wait_until_clear(&fRegs->cmd, PORT_CMD_CR, 500000) < B_OK) {
|
||||
TRACE("AHCIPort::Uninit port %d error DMA engine still running\n", fIndex);
|
||||
}
|
||||
|
||||
@ -137,6 +153,84 @@ AHCIPort::Uninit()
|
||||
}
|
||||
|
||||
|
||||
|
||||
status_t
|
||||
AHCIPort::ResetDevice()
|
||||
{
|
||||
TRACE("AHCIPort::ResetDevice 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::ResetDevice port %d error DMA engine doesn't stop\n", fIndex);
|
||||
}
|
||||
|
||||
// perform a hard reset
|
||||
fRegs->sctl = (fRegs->sctl & ~0xf) | 1;
|
||||
FlushPostedWrites();
|
||||
snooze(10000);
|
||||
fRegs->sctl &= ~0xf;
|
||||
FlushPostedWrites();
|
||||
|
||||
if (wait_until_set(&fRegs->ssts, 0x1, 6000000) < B_OK) {
|
||||
TRACE("AHCIPort::ResetDevice port %d no device detected\n", fIndex);
|
||||
}
|
||||
|
||||
// clear error bits
|
||||
// fRegs->serr = fRegs->serr;
|
||||
fRegs->serr = 0xffffffff;
|
||||
FlushPostedWrites();
|
||||
|
||||
// start DMA engine
|
||||
fRegs->cmd |= PORT_CMD_ST;
|
||||
FlushPostedWrites();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AHCIPort::PostResetDevice()
|
||||
{
|
||||
TRACE("AHCIPort::PostResetDevice port %d\n", fIndex);
|
||||
|
||||
TRACE("tfd 1 0x%08lx\n", fRegs->tfd);
|
||||
|
||||
// wait for DMA idle ?
|
||||
// if (wait_until_clear(&fRegs->cmd, PORT_CMD_CR, 1000000) < B_OK) {
|
||||
// TRACE("AHCIPort::PostResetDevice port %d error DMA engine doesn't stop\n", fIndex);
|
||||
// }
|
||||
|
||||
switch (fRegs->tfd & 0xff) {
|
||||
case 0x7f:
|
||||
TRACE("no device present?\n");
|
||||
break;
|
||||
case 0xff:
|
||||
TRACE("invalid task file status 0xff\n");
|
||||
// fall through
|
||||
default:
|
||||
TRACE("waiting...\n");
|
||||
wait_until_clear(&fRegs->tfd, ATA_BSY | ATA_DRQ, 31000000);
|
||||
}
|
||||
|
||||
if (fRegs->sig == 0xeb140101)
|
||||
fRegs->cmd |= PORT_CMD_ATAPI;
|
||||
else
|
||||
fRegs->cmd &= ~PORT_CMD_ATAPI;
|
||||
FlushPostedWrites();
|
||||
|
||||
TRACE("device signature 0x%08lx (%s)\n", fRegs->sig,
|
||||
(fRegs->sig == 0xeb140101) ? "ATAPI" : (fRegs->sig == 0x00000101) ? "ATA" : "unknown");
|
||||
|
||||
TRACE("tfd 0x%08lx\n", fRegs->tfd);
|
||||
TRACE("device detection: 0x%lx\n", fRegs->ssts & 0xf);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AHCIPort::Interrupt()
|
||||
{
|
||||
@ -149,10 +243,11 @@ AHCIPort::Interrupt()
|
||||
|
||||
|
||||
void
|
||||
AHCIPort::ExecuteRequest(scsi_ccb *request)
|
||||
AHCIPort::ScsiExecuteRequest(scsi_ccb *request)
|
||||
{
|
||||
|
||||
TRACE("AHCIPort::ExecuteRequest port %d, opcode %u, length %u\n", fIndex, request->cdb[0], request->cdb_length);
|
||||
TRACE("AHCIPort::ScsiExecuteRequest port %d, opcode %u, length %u\n", fIndex, request->cdb[0], request->cdb_length);
|
||||
|
||||
|
||||
request->subsys_status = SCSI_DEV_NOT_THERE;
|
||||
gSCSI->finished(request, 1);
|
||||
@ -164,7 +259,7 @@ AHCIPort::ExecuteRequest(scsi_ccb *request)
|
||||
|
||||
|
||||
uchar
|
||||
AHCIPort::AbortRequest(scsi_ccb *request)
|
||||
AHCIPort::ScsiAbortRequest(scsi_ccb *request)
|
||||
{
|
||||
|
||||
return SCSI_REQ_CMP;
|
||||
@ -172,15 +267,14 @@ AHCIPort::AbortRequest(scsi_ccb *request)
|
||||
|
||||
|
||||
uchar
|
||||
AHCIPort::TerminateRequest(scsi_ccb *request)
|
||||
AHCIPort::ScsiTerminateRequest(scsi_ccb *request)
|
||||
{
|
||||
return SCSI_REQ_CMP;
|
||||
}
|
||||
|
||||
|
||||
uchar
|
||||
AHCIPort::ResetDevice()
|
||||
AHCIPort::ScsiResetDevice()
|
||||
{
|
||||
return SCSI_REQ_CMP;
|
||||
}
|
||||
|
||||
|
@ -14,18 +14,22 @@ public:
|
||||
AHCIPort(AHCIController *controller, int index);
|
||||
~AHCIPort();
|
||||
|
||||
status_t Init();
|
||||
status_t Init1();
|
||||
status_t Init2();
|
||||
void Uninit();
|
||||
|
||||
void Interrupt();
|
||||
|
||||
|
||||
void ExecuteRequest(scsi_ccb *request);
|
||||
uchar AbortRequest(scsi_ccb *request);
|
||||
uchar TerminateRequest(scsi_ccb *request);
|
||||
uchar ResetDevice();
|
||||
void ScsiExecuteRequest(scsi_ccb *request);
|
||||
uchar ScsiAbortRequest(scsi_ccb *request);
|
||||
uchar ScsiTerminateRequest(scsi_ccb *request);
|
||||
uchar ScsiResetDevice();
|
||||
|
||||
private:
|
||||
status_t ResetDevice();
|
||||
status_t PostResetDevice();
|
||||
void FlushPostedWrites();
|
||||
|
||||
private:
|
||||
int fIndex;
|
||||
@ -38,4 +42,10 @@ private:
|
||||
volatile prd * fPRDTable;
|
||||
};
|
||||
|
||||
inline void
|
||||
AHCIPort::FlushPostedWrites()
|
||||
{
|
||||
volatile uint32 dummy = fRegs->cmd;
|
||||
dummy = dummy;
|
||||
}
|
||||
#endif // _AHCI_PORT_H
|
||||
|
Loading…
Reference in New Issue
Block a user