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:
Marcus Overhagen 2007-09-30 15:12:39 +00:00
parent ea44575a31
commit a2a169feab
3 changed files with 84 additions and 46 deletions

View File

@ -23,16 +23,17 @@ AHCIPort::AHCIPort(AHCIController *controller, int index)
: fIndex(index)
, fRegs(&controller->fRegs->port[index])
, fArea(-1)
, fSpinlock(0)
, fCommandsActive(0)
, fRequestSem(-1)
, fResponseSem(-1)
, fCommandActive(false)
, fDevicePresent(false)
, fUse48BitCommands(false)
, fSectorSize(0)
, fSectorCount(0)
{
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()
{
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);
// clear interrupts
fRegs->is = is;
}
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;
physical_entry pe[peMax];
@ -291,12 +304,12 @@ AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const
int 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
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;
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);
return B_ERROR;
}
if (ioc)
(prdTable - 1)->dbc |= DBC_I;
return B_OK;
}
@ -345,18 +356,19 @@ void
AHCIPort::StartTransfer()
{
acquire_sem(fRequestSem);
fCommandActive = true;
}
status_t
AHCIPort::WaitForTransfer(int *status, bigtime_t timeout)
AHCIPort::WaitForTransfer(int *tfd, bigtime_t timeout)
{
status_t result = B_OK;
if (acquire_sem_etc(fResponseSem, 1, B_RELATIVE_TIMEOUT, timeout) < B_OK) {
fCommandsActive &= ~1;
result = B_TIMED_OUT;
} else {
*tfd = fRegs->tfd;
}
fCommandActive = false;
return result;
}
@ -398,10 +410,10 @@ AHCIPort::ScsiInquiry(scsi_ccb *request)
StartTransfer();
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);
fCommandTable->cfis[0] = 0x27;
@ -421,16 +433,22 @@ AHCIPort::ScsiInquiry(scsi_ccb *request)
gSCSI->finished(request, 1);
return;
}
cpu_status cpu = disable_interrupts();
acquire_spinlock(&fSpinlock);
fRegs->ci |= 1;
FlushPostedWrites();
fCommandsActive |= 1;
release_spinlock(&fSpinlock);
restore_interrupts(cpu);
int status;
WaitForTransfer(&status, 100000);
TRACE("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);
FLOW("prdbc %ld\n", fCommandList->prdbc);
FLOW("ci 0x%08lx\n", fRegs->ci);
FLOW("is 0x%08lx\n", fRegs->is);
FLOW("serr 0x%08lx\n", fRegs->serr);
/*
TRACE("ci 0x%08lx\n", fRegs->ci);
@ -484,13 +502,21 @@ AHCIPort::ScsiInquiry(scsi_ccb *request)
}
#endif
swap_words(ataData.model_number, sizeof(ataData.model_number));
swap_words(ataData.serial_number, sizeof(ataData.serial_number));
swap_words(ataData.firmware_revision, sizeof(ataData.firmware_revision));
char modelNumber[sizeof(ataData.model_number) + 1];
char serialNumber[sizeof(ataData.serial_number) + 1];
char firmwareRev[sizeof(ataData.firmware_revision) + 1];
TRACE("model_number: %40s\n", ataData.model_number);
TRACE("serial_number: %20s\n", ataData.serial_number);
TRACE("firmware_revision: %8s\n", ataData.firmware_revision);
strlcpy(modelNumber, ataData.model_number, sizeof(modelNumber));
strlcpy(serialNumber, ataData.serial_number, sizeof(serialNumber));
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",
lba, lba48, fUse48BitCommands, sectors, sectors48, fSectorCount * fSectorSize);
@ -502,7 +528,6 @@ AHCIPort::ScsiInquiry(scsi_ccb *request)
request->data_length = sizeof(scsiData); // ???
}
fRegs->ci &= ~1;
FinishTransfer();
gSCSI->finished(request, 1);
@ -544,7 +569,9 @@ AHCIPort::ScsiReadCapacity(scsi_ccb *request)
void
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 (isWrite) {
@ -559,7 +586,7 @@ AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 position, size_t length, bool
StartTransfer();
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);
@ -605,22 +632,31 @@ AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 position, size_t length, bool
gSCSI->finished(request, 1);
return;
}
cpu_status cpu = disable_interrupts();
acquire_spinlock(&fSpinlock);
fRegs->ci |= 1;
FlushPostedWrites();
fCommandsActive |= 1;
release_spinlock(&fSpinlock);
restore_interrupts(cpu);
int status;
WaitForTransfer(&status, 100000);
int tfd;
status_t status = WaitForTransfer(&tfd, 4000000);
TRACE("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);
FLOW("prdbc %ld\n", fCommandList->prdbc);
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_length = fCommandList->prdbc; // ???
fRegs->ci &= ~1;
FinishTransfer();
gSCSI->finished(request, 1);
@ -631,7 +667,7 @@ void
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) {
panic("ahci: SCSI_OP_REQUEST_SENSE not yet supported\n");

View File

@ -38,21 +38,22 @@ private:
void DumpD2HFis();
void StartTransfer();
status_t WaitForTransfer(int *status, bigtime_t timeout);
status_t WaitForTransfer(int *tfd, bigtime_t timeout);
void FinishTransfer();
// 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 physical_entry *sgTable, int sgCount, 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);
private:
int fIndex;
volatile ahci_port * fRegs;
area_id fArea;
spinlock fSpinlock;
volatile uint32 fCommandsActive;
sem_id fRequestSem;
sem_id fResponseSem;
volatile bool fCommandActive;
bool fDevicePresent;
bool fUse48BitCommands;
uint32 fSectorSize;

View File

@ -10,7 +10,8 @@
#include <new>
#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;
@ -24,7 +25,7 @@ scsi_for_sim_interface *gSCSI;
static void
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);
static_cast<AHCIController *>(cookie)->ExecuteRequest(request);
}
@ -105,7 +106,7 @@ ahci_get_restrictions(scsi_sim_cookie cookie, uchar targetID, bool *isATAPI,
*isATAPI = false;
*noAutoSense = false;
*maxBlocks = 255;
*maxBlocks = 256;
}