added simple error handling

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25647 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Marcus Overhagen
2008-05-24 19:17:17 +00:00
parent 5839058aa9
commit c3342cf811
3 changed files with 97 additions and 17 deletions
@@ -123,7 +123,7 @@ enum {
PORT_INT_INF = (1 << 26), // Interface Non-fatal Error Status/Enable
PORT_INT_OF = (1 << 24), // Overflow Status/Enable
PORT_INT_IPM = (1 << 23), // Incorrect Port Multiplier Status/Enable
PORT_INT_PRCE = (1 << 22), // PhyRdy Change Status/Enable
PORT_INT_PRC = (1 << 22), // PhyRdy Change Status/Enable
PORT_INT_DI = (1 << 7), // Device Interlock Status/Enable
PORT_INT_PC = (1 << 6), // Port Change Status/Enable
PORT_INT_DP = (1 << 5), // Descriptor Processed Interrupt
@@ -134,10 +134,13 @@ enum {
PORT_INT_DHR = (1 << 0), // Device to Host Register FIS Interrupt
};
#define PORT_INT_FATAL (PORT_INT_HBF | PORT_INT_IF | PORT_INT_IPM | PORT_INT_UF)
#define PORT_INT_ERROR (PORT_INT_TFE | PORT_INT_HBD)
#define PORT_INT_MASK (PORT_INT_FATAL | PORT_INT_ERROR | PORT_INT_DP |\
PORT_INT_SDB | PORT_INT_DS | PORT_INT_PS | PORT_INT_DHR)
#define PORT_INT_ERROR (PORT_INT_TFE | PORT_INT_HBF | PORT_INT_HBD \
| PORT_INT_IF | PORT_INT_INF | PORT_INT_OF \
| PORT_INT_IPM | PORT_INT_PRC | PORT_INT_PC \
| PORT_INT_UF)
#define PORT_INT_MASK (PORT_INT_ERROR | PORT_INT_DP | PORT_INT_SDB \
| PORT_INT_DS | PORT_INT_PS | PORT_INT_DHR)
enum {
ATA_BSY = 0x80,
@@ -39,6 +39,8 @@ AHCIPort::AHCIPort(AHCIController *controller, int index)
, fSectorSize(0)
, fSectorCount(0)
, fIsATAPI(false)
, fResetPort(false)
, fError(false)
{
fRequestSem = create_sem(1, "ahci request");
fResponseSem = create_sem(0, "ahci response");
@@ -281,21 +283,16 @@ void
AHCIPort::Interrupt()
{
uint32 is = fRegs->is;
uint32 ci = fRegs->ci;
fRegs->is = is; // clear interrupts
RWTRACE("AHCIPort::Interrupt port %d, fCommandsActive 0x%08lx, is 0x%08lx, ci 0x%08lx\n", fIndex, fCommandsActive, is, ci);
if (is & PORT_INT_ERROR) {
TRACE("AHCIPort::Interrupt port %d, fCommandsActive 0x%08lx, is 0x%08lx, ci 0x%08lx\n", fIndex, fCommandsActive, is, ci);
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);
InterruptErrorHandler(is);
return;
}
if (is & PORT_INT_FATAL)
panic("ahci fatal error, is 0x%08lx", is);
uint32 ci = fRegs->ci;
RWTRACE("AHCIPort::Interrupt port %d, fCommandsActive 0x%08lx, is 0x%08lx, ci 0x%08lx\n", fIndex, fCommandsActive, is, ci);
int release = 0;
@@ -311,6 +308,71 @@ AHCIPort::Interrupt()
}
void
AHCIPort::InterruptErrorHandler(uint32 is)
{
uint32 ci = fRegs->ci;
TRACE("AHCIPort::InterruptErrorHandler port %d, fCommandsActive 0x%08lx, is 0x%08lx, ci 0x%08lx\n", fIndex, fCommandsActive, is, ci);
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);
// read and clear SError
uint32 serr = fRegs->serr;
fRegs->serr = serr;
if (is & PORT_INT_TFE) {
TRACE("Task File Error\n");
fResetPort = true;
fError = true;
}
if (is & PORT_INT_HBF) {
TRACE("Host Bus Fatal Error\n");
fResetPort = true;
fError = true;
}
if (is & PORT_INT_HBD) {
TRACE("Host Bus Data Error\n");
fResetPort = true;
fError = true;
}
if (is & PORT_INT_IF) {
TRACE("Interface Fatal Error\n");
fResetPort = true;
fError = true;
}
if (is & PORT_INT_INF) {
TRACE("Interface Non Fatal Error\n");
}
if (is & PORT_INT_OF) {
TRACE("Overflow");
fResetPort = true;
fError = true;
}
if (is & PORT_INT_IPM) {
TRACE("Incorrect Port Multiplier Status");
}
if (is & PORT_INT_PRC) {
TRACE("PhyReady Change\n");
// fResetPort = true;
}
if (is & PORT_INT_PC) {
TRACE("Port Connect Change\n");
// fResetPort = true;
}
if (is & PORT_INT_UF) {
TRACE("Unknown FIS\n");
fResetPort = true;
}
if (fError)
release_sem_etc(fResponseSem, 1, B_RELEASE_IF_WAITING_ONLY | B_DO_NOT_RESCHEDULE);
}
status_t
AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const void *data, size_t dataSize)
{
@@ -386,6 +448,9 @@ AHCIPort::WaitForTransfer(int *tfd, bigtime_t timeout)
if (acquire_sem_etc(fResponseSem, 1, B_RELATIVE_TIMEOUT, timeout) < B_OK) {
fCommandsActive &= ~1;
result = B_TIMED_OUT;
} else if (fError) {
result = B_ERROR;
fError = false;
} else {
*tfd = fRegs->tfd;
}
@@ -666,7 +731,10 @@ AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite)
FinishTransfer();
if (status < B_OK) {
TRACE("ExecuteAtaRequest port %d: device transfer timeout\n", fIndex);
if (status == B_TIMED_OUT)
TRACE("ExecuteAtaRequest port %d: device timeout\n", fIndex);
else
TRACE("ExecuteAtaRequest port %d: device error\n", fIndex);
request->abort();
} else
request->finish(tfd, bytesTransfered);
@@ -677,6 +745,12 @@ void
AHCIPort::ScsiExecuteRequest(scsi_ccb *request)
{
if (fResetPort) {
fResetPort = false;
ResetDevice();
PostResetDevice();
}
// TRACE("AHCIPort::ScsiExecuteRequest port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length);
if (fIsATAPI && request->cdb[0] != SCSI_OP_INQUIRY) {
@@ -20,6 +20,7 @@ public:
void Uninit();
void Interrupt();
void InterruptErrorHandler(uint32 is);
void ScsiExecuteRequest(scsi_ccb *request);
@@ -65,6 +66,8 @@ private:
uint32 fSectorSize;
uint64 fSectorCount;
bool fIsATAPI;
bool fResetPort;
bool fError;
volatile fis * fFIS;
volatile command_list_entry * fCommandList;