Improved interrupt handling
Removed DBC_I interrupt Reduce debug output git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22386 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
ea44575a31
commit
a2a169feab
@ -23,16 +23,17 @@ AHCIPort::AHCIPort(AHCIController *controller, int index)
|
|||||||
: fIndex(index)
|
: fIndex(index)
|
||||||
, fRegs(&controller->fRegs->port[index])
|
, fRegs(&controller->fRegs->port[index])
|
||||||
, fArea(-1)
|
, fArea(-1)
|
||||||
|
, fSpinlock(0)
|
||||||
|
, fCommandsActive(0)
|
||||||
, fRequestSem(-1)
|
, fRequestSem(-1)
|
||||||
, fResponseSem(-1)
|
, fResponseSem(-1)
|
||||||
, fCommandActive(false)
|
|
||||||
, fDevicePresent(false)
|
, fDevicePresent(false)
|
||||||
, fUse48BitCommands(false)
|
, fUse48BitCommands(false)
|
||||||
, fSectorSize(0)
|
, fSectorSize(0)
|
||||||
, fSectorCount(0)
|
, fSectorCount(0)
|
||||||
{
|
{
|
||||||
fRequestSem = create_sem(1, "ahci request");
|
fRequestSem = create_sem(1, "ahci request");
|
||||||
fResponseSem = create_sem(1, "ahci response");
|
fResponseSem = create_sem(0, "ahci response");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -269,18 +270,30 @@ void
|
|||||||
AHCIPort::Interrupt()
|
AHCIPort::Interrupt()
|
||||||
{
|
{
|
||||||
uint32 is = fRegs->is;
|
uint32 is = fRegs->is;
|
||||||
TRACE("AHCIPort::Interrupt port %d, status %#08lx\n", fIndex, is);
|
uint32 ci = fRegs->ci;
|
||||||
|
fRegs->is = is; // clear interrupts
|
||||||
|
|
||||||
if (fCommandActive)
|
FLOW("AHCIPort::Interrupt port %d, fCommandsActive 0x%08lx, is 0x%08lx, ci 0x%08lx\n", fIndex, fCommandsActive, is, ci);
|
||||||
|
|
||||||
|
int release = 0;
|
||||||
|
|
||||||
|
acquire_spinlock(&fSpinlock);
|
||||||
|
if ((fCommandsActive & 1) && !(ci & 1)) {
|
||||||
|
release = 1;
|
||||||
|
fCommandsActive &= ~1;
|
||||||
|
}
|
||||||
|
release_spinlock(&fSpinlock);
|
||||||
|
|
||||||
|
if (is & PORT_INT_FATAL)
|
||||||
|
panic("ahci fatal error, is 0x%08lx", is);
|
||||||
|
|
||||||
|
if (release)
|
||||||
release_sem_etc(fResponseSem, 1, B_RELEASE_IF_WAITING_ONLY | B_DO_NOT_RESCHEDULE);
|
release_sem_etc(fResponseSem, 1, B_RELEASE_IF_WAITING_ONLY | B_DO_NOT_RESCHEDULE);
|
||||||
|
|
||||||
// clear interrupts
|
|
||||||
fRegs->is = is;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const void *data, size_t dataSize, bool ioc)
|
AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const void *data, size_t dataSize)
|
||||||
{
|
{
|
||||||
int peMax = prdMax + 1;
|
int peMax = prdMax + 1;
|
||||||
physical_entry pe[peMax];
|
physical_entry pe[peMax];
|
||||||
@ -291,12 +304,12 @@ AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const
|
|||||||
int peUsed;
|
int peUsed;
|
||||||
for (peUsed = 0; pe[peUsed].size; peUsed++)
|
for (peUsed = 0; pe[peUsed].size; peUsed++)
|
||||||
;
|
;
|
||||||
return FillPrdTable(prdTable, prdCount, prdMax, pe, peUsed, dataSize, ioc);
|
return FillPrdTable(prdTable, prdCount, prdMax, pe, peUsed, dataSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const physical_entry *sgTable, int sgCount, size_t dataSize, bool ioc)
|
AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const physical_entry *sgTable, int sgCount, size_t dataSize)
|
||||||
{
|
{
|
||||||
*prdCount = 0;
|
*prdCount = 0;
|
||||||
while (sgCount > 0 && dataSize > 0) {
|
while (sgCount > 0 && dataSize > 0) {
|
||||||
@ -335,8 +348,6 @@ AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const
|
|||||||
TRACE("AHCIPort::FillPrdTable: sg table %ld bytes too small\n", dataSize);
|
TRACE("AHCIPort::FillPrdTable: sg table %ld bytes too small\n", dataSize);
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
if (ioc)
|
|
||||||
(prdTable - 1)->dbc |= DBC_I;
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,18 +356,19 @@ void
|
|||||||
AHCIPort::StartTransfer()
|
AHCIPort::StartTransfer()
|
||||||
{
|
{
|
||||||
acquire_sem(fRequestSem);
|
acquire_sem(fRequestSem);
|
||||||
fCommandActive = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
AHCIPort::WaitForTransfer(int *status, bigtime_t timeout)
|
AHCIPort::WaitForTransfer(int *tfd, bigtime_t timeout)
|
||||||
{
|
{
|
||||||
status_t result = B_OK;
|
status_t result = B_OK;
|
||||||
if (acquire_sem_etc(fResponseSem, 1, B_RELATIVE_TIMEOUT, timeout) < B_OK) {
|
if (acquire_sem_etc(fResponseSem, 1, B_RELATIVE_TIMEOUT, timeout) < B_OK) {
|
||||||
|
fCommandsActive &= ~1;
|
||||||
result = B_TIMED_OUT;
|
result = B_TIMED_OUT;
|
||||||
|
} else {
|
||||||
|
*tfd = fRegs->tfd;
|
||||||
}
|
}
|
||||||
fCommandActive = false;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,10 +410,10 @@ AHCIPort::ScsiInquiry(scsi_ccb *request)
|
|||||||
StartTransfer();
|
StartTransfer();
|
||||||
|
|
||||||
int prdEntrys;
|
int prdEntrys;
|
||||||
FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, &ataData, sizeof(ataData), true);
|
FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, &ataData, sizeof(ataData));
|
||||||
|
|
||||||
|
|
||||||
TRACE("prdEntrys %d\n", prdEntrys);
|
FLOW("prdEntrys %d\n", prdEntrys);
|
||||||
|
|
||||||
memset((void *)fCommandTable->cfis, 0, 5 * 4);
|
memset((void *)fCommandTable->cfis, 0, 5 * 4);
|
||||||
fCommandTable->cfis[0] = 0x27;
|
fCommandTable->cfis[0] = 0x27;
|
||||||
@ -421,16 +433,22 @@ AHCIPort::ScsiInquiry(scsi_ccb *request)
|
|||||||
gSCSI->finished(request, 1);
|
gSCSI->finished(request, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpu_status cpu = disable_interrupts();
|
||||||
|
acquire_spinlock(&fSpinlock);
|
||||||
fRegs->ci |= 1;
|
fRegs->ci |= 1;
|
||||||
FlushPostedWrites();
|
FlushPostedWrites();
|
||||||
|
fCommandsActive |= 1;
|
||||||
|
release_spinlock(&fSpinlock);
|
||||||
|
restore_interrupts(cpu);
|
||||||
|
|
||||||
int status;
|
int status;
|
||||||
WaitForTransfer(&status, 100000);
|
WaitForTransfer(&status, 100000);
|
||||||
|
|
||||||
TRACE("prdbc %ld\n", fCommandList->prdbc);
|
FLOW("prdbc %ld\n", fCommandList->prdbc);
|
||||||
TRACE("ci 0x%08lx\n", fRegs->ci);
|
FLOW("ci 0x%08lx\n", fRegs->ci);
|
||||||
TRACE("is 0x%08lx\n", fRegs->is);
|
FLOW("is 0x%08lx\n", fRegs->is);
|
||||||
TRACE("serr 0x%08lx\n", fRegs->serr);
|
FLOW("serr 0x%08lx\n", fRegs->serr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TRACE("ci 0x%08lx\n", fRegs->ci);
|
TRACE("ci 0x%08lx\n", fRegs->ci);
|
||||||
@ -484,13 +502,21 @@ AHCIPort::ScsiInquiry(scsi_ccb *request)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
swap_words(ataData.model_number, sizeof(ataData.model_number));
|
char modelNumber[sizeof(ataData.model_number) + 1];
|
||||||
swap_words(ataData.serial_number, sizeof(ataData.serial_number));
|
char serialNumber[sizeof(ataData.serial_number) + 1];
|
||||||
swap_words(ataData.firmware_revision, sizeof(ataData.firmware_revision));
|
char firmwareRev[sizeof(ataData.firmware_revision) + 1];
|
||||||
|
|
||||||
TRACE("model_number: %40s\n", ataData.model_number);
|
strlcpy(modelNumber, ataData.model_number, sizeof(modelNumber));
|
||||||
TRACE("serial_number: %20s\n", ataData.serial_number);
|
strlcpy(serialNumber, ataData.serial_number, sizeof(serialNumber));
|
||||||
TRACE("firmware_revision: %8s\n", ataData.firmware_revision);
|
strlcpy(firmwareRev, ataData.firmware_revision, sizeof(firmwareRev));
|
||||||
|
|
||||||
|
swap_words(modelNumber, sizeof(modelNumber) - 1);
|
||||||
|
swap_words(serialNumber, sizeof(serialNumber) - 1);
|
||||||
|
swap_words(firmwareRev, sizeof(firmwareRev) - 1);
|
||||||
|
|
||||||
|
TRACE("model number: %s\n", modelNumber);
|
||||||
|
TRACE("serial number: %s\n", serialNumber);
|
||||||
|
TRACE("firmware rev.: %s\n", firmwareRev);
|
||||||
TRACE("lba %d, lba48 %d, fUse48BitCommands %d, sectors %lu, sectors48 %llu, size %llu\n",
|
TRACE("lba %d, lba48 %d, fUse48BitCommands %d, sectors %lu, sectors48 %llu, size %llu\n",
|
||||||
lba, lba48, fUse48BitCommands, sectors, sectors48, fSectorCount * fSectorSize);
|
lba, lba48, fUse48BitCommands, sectors, sectors48, fSectorCount * fSectorSize);
|
||||||
|
|
||||||
@ -502,7 +528,6 @@ AHCIPort::ScsiInquiry(scsi_ccb *request)
|
|||||||
request->data_length = sizeof(scsiData); // ???
|
request->data_length = sizeof(scsiData); // ???
|
||||||
}
|
}
|
||||||
|
|
||||||
fRegs->ci &= ~1;
|
|
||||||
FinishTransfer();
|
FinishTransfer();
|
||||||
|
|
||||||
gSCSI->finished(request, 1);
|
gSCSI->finished(request, 1);
|
||||||
@ -544,7 +569,9 @@ AHCIPort::ScsiReadCapacity(scsi_ccb *request)
|
|||||||
void
|
void
|
||||||
AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 position, size_t length, bool isWrite)
|
AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 position, size_t length, bool isWrite)
|
||||||
{
|
{
|
||||||
TRACE("ScsiReadWrite: pos %llu, size %lu, isWrite %d\n", position, length, isWrite);
|
uint32 bytecount = length * 512;
|
||||||
|
|
||||||
|
TRACE("ScsiReadWrite: position %llu, size %lu, isWrite %d\n", position * 512, bytecount, isWrite);
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
if (isWrite) {
|
if (isWrite) {
|
||||||
@ -559,7 +586,7 @@ AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 position, size_t length, bool
|
|||||||
StartTransfer();
|
StartTransfer();
|
||||||
|
|
||||||
int prdEntrys;
|
int prdEntrys;
|
||||||
FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, request->sg_list, request->sg_count, length * 512, true);
|
FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, request->sg_list, request->sg_count, bytecount);
|
||||||
|
|
||||||
FLOW("prdEntrys %d\n", prdEntrys);
|
FLOW("prdEntrys %d\n", prdEntrys);
|
||||||
|
|
||||||
@ -605,22 +632,31 @@ AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 position, size_t length, bool
|
|||||||
gSCSI->finished(request, 1);
|
gSCSI->finished(request, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
cpu_status cpu = disable_interrupts();
|
||||||
|
acquire_spinlock(&fSpinlock);
|
||||||
fRegs->ci |= 1;
|
fRegs->ci |= 1;
|
||||||
FlushPostedWrites();
|
FlushPostedWrites();
|
||||||
|
fCommandsActive |= 1;
|
||||||
|
release_spinlock(&fSpinlock);
|
||||||
|
restore_interrupts(cpu);
|
||||||
|
|
||||||
int status;
|
int tfd;
|
||||||
WaitForTransfer(&status, 100000);
|
status_t status = WaitForTransfer(&tfd, 4000000);
|
||||||
|
|
||||||
TRACE("prdbc %ld\n", fCommandList->prdbc);
|
FLOW("prdbc %ld\n", fCommandList->prdbc);
|
||||||
TRACE("ci 0x%08lx\n", fRegs->ci);
|
|
||||||
TRACE("is 0x%08lx\n", fRegs->is);
|
|
||||||
TRACE("serr 0x%08lx\n", fRegs->serr);
|
|
||||||
|
|
||||||
request->subsys_status = SCSI_REQ_CMP;
|
if (status < B_OK || (tfd & ATA_ERR)) {
|
||||||
|
TRACE("device error\n");
|
||||||
|
request->subsys_status = SCSI_REQ_ABORTED;
|
||||||
|
} else if (fCommandList->prdbc != bytecount) {
|
||||||
|
TRACE("should never happen\n");
|
||||||
|
request->subsys_status = SCSI_REQ_CMP_ERR;
|
||||||
|
} else {
|
||||||
|
request->subsys_status = SCSI_REQ_CMP;
|
||||||
|
}
|
||||||
request->data_resid = request->data_length - fCommandList->prdbc;// ???
|
request->data_resid = request->data_length - fCommandList->prdbc;// ???
|
||||||
request->data_length = fCommandList->prdbc; // ???
|
request->data_length = fCommandList->prdbc; // ???
|
||||||
|
|
||||||
fRegs->ci &= ~1;
|
|
||||||
FinishTransfer();
|
FinishTransfer();
|
||||||
|
|
||||||
gSCSI->finished(request, 1);
|
gSCSI->finished(request, 1);
|
||||||
@ -631,7 +667,7 @@ void
|
|||||||
AHCIPort::ScsiExecuteRequest(scsi_ccb *request)
|
AHCIPort::ScsiExecuteRequest(scsi_ccb *request)
|
||||||
{
|
{
|
||||||
|
|
||||||
TRACE("AHCIPort::ScsiExecuteRequest port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length);
|
// TRACE("AHCIPort::ScsiExecuteRequest port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length);
|
||||||
|
|
||||||
if (request->cdb[0] == SCSI_OP_REQUEST_SENSE) {
|
if (request->cdb[0] == SCSI_OP_REQUEST_SENSE) {
|
||||||
panic("ahci: SCSI_OP_REQUEST_SENSE not yet supported\n");
|
panic("ahci: SCSI_OP_REQUEST_SENSE not yet supported\n");
|
||||||
|
@ -38,21 +38,22 @@ private:
|
|||||||
void DumpD2HFis();
|
void DumpD2HFis();
|
||||||
|
|
||||||
void StartTransfer();
|
void StartTransfer();
|
||||||
status_t WaitForTransfer(int *status, bigtime_t timeout);
|
status_t WaitForTransfer(int *tfd, bigtime_t timeout);
|
||||||
void FinishTransfer();
|
void FinishTransfer();
|
||||||
|
|
||||||
|
|
||||||
// uint8 * SetCommandFis(volatile command_list_entry *cmd, volatile fis *fis, const void *data, size_t dataSize);
|
// uint8 * SetCommandFis(volatile command_list_entry *cmd, volatile fis *fis, const void *data, size_t dataSize);
|
||||||
status_t FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const void *data, size_t dataSize, bool ioc = false);
|
status_t FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const void *data, size_t dataSize);
|
||||||
status_t FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const physical_entry *sgTable, int sgCount, size_t dataSize, bool ioc = false);
|
status_t FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const physical_entry *sgTable, int sgCount, size_t dataSize);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int fIndex;
|
int fIndex;
|
||||||
volatile ahci_port * fRegs;
|
volatile ahci_port * fRegs;
|
||||||
area_id fArea;
|
area_id fArea;
|
||||||
|
spinlock fSpinlock;
|
||||||
|
volatile uint32 fCommandsActive;
|
||||||
sem_id fRequestSem;
|
sem_id fRequestSem;
|
||||||
sem_id fResponseSem;
|
sem_id fResponseSem;
|
||||||
volatile bool fCommandActive;
|
|
||||||
bool fDevicePresent;
|
bool fDevicePresent;
|
||||||
bool fUse48BitCommands;
|
bool fUse48BitCommands;
|
||||||
uint32 fSectorSize;
|
uint32 fSectorSize;
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
#define TRACE(a...) dprintf("\33[34mahci:\33[0m " a)
|
#define TRACE(a...) dprintf("\33[34mahci:\33[0m " a)
|
||||||
#define FLOW(a...) dprintf("ahci: " a)
|
//#define FLOW(a...) dprintf("ahci: " a)
|
||||||
|
#define FLOW(a...)
|
||||||
|
|
||||||
|
|
||||||
pci_device_module_info *gPCI;
|
pci_device_module_info *gPCI;
|
||||||
@ -24,7 +25,7 @@ scsi_for_sim_interface *gSCSI;
|
|||||||
static void
|
static void
|
||||||
ahci_scsi_io(scsi_sim_cookie cookie, scsi_ccb *request)
|
ahci_scsi_io(scsi_sim_cookie cookie, scsi_ccb *request)
|
||||||
{
|
{
|
||||||
TRACE("ahci_scsi_io, cookie %p, path_id %u, target_id %u, target_lun %u\n",
|
FLOW("ahci_scsi_io, cookie %p, path_id %u, target_id %u, target_lun %u\n",
|
||||||
cookie, request->path_id, request->target_id, request->target_lun);
|
cookie, request->path_id, request->target_id, request->target_lun);
|
||||||
static_cast<AHCIController *>(cookie)->ExecuteRequest(request);
|
static_cast<AHCIController *>(cookie)->ExecuteRequest(request);
|
||||||
}
|
}
|
||||||
@ -105,7 +106,7 @@ ahci_get_restrictions(scsi_sim_cookie cookie, uchar targetID, bool *isATAPI,
|
|||||||
|
|
||||||
*isATAPI = false;
|
*isATAPI = false;
|
||||||
*noAutoSense = false;
|
*noAutoSense = false;
|
||||||
*maxBlocks = 255;
|
*maxBlocks = 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user