* Reworked device detection, we'll see how well this works...
* Reworked some of the transfer handling after reading the specs. * Ensure that the device selection bit is set correctly for all commands. * Generally disable interrupts and enable them only when expecting a DMA one. * Renamed disk failure to device fault according to specs. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30248 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -215,7 +215,7 @@ enum {
|
|||||||
|
|
||||||
// packet and dma queued result
|
// packet and dma queued result
|
||||||
ATA_MASK_ERROR = 0x01,
|
ATA_MASK_ERROR = 0x01,
|
||||||
ATA_MASK_IREASON = 0x02,
|
ATA_MASK_INTERRUPT_REASON = 0x02,
|
||||||
|
|
||||||
ATA_MASK_DEVICE_HEAD = 0x20,
|
ATA_MASK_DEVICE_HEAD = 0x20,
|
||||||
ATA_MASK_COMMAND = 0x40,
|
ATA_MASK_COMMAND = 0x40,
|
||||||
@@ -243,7 +243,7 @@ enum {
|
|||||||
ATA_STATUS_DWF = 0x20, // reserved
|
ATA_STATUS_DWF = 0x20, // reserved
|
||||||
ATA_STATUS_DMA = 0x20, // reserved
|
ATA_STATUS_DMA = 0x20, // reserved
|
||||||
ATA_STATUS_DMA_READY = 0x20, // packet: DMA ready
|
ATA_STATUS_DMA_READY = 0x20, // packet: DMA ready
|
||||||
ATA_STATUS_DISK_FAILURE = 0x20, // packet: disk failure
|
ATA_STATUS_DEVICE_FAULT = 0x20, // device fault
|
||||||
ATA_STATUS_DEVICE_READY = 0x40, // device ready
|
ATA_STATUS_DEVICE_READY = 0x40, // device ready
|
||||||
ATA_STATUS_BUSY = 0x80 // busy
|
ATA_STATUS_BUSY = 0x80 // busy
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -116,41 +116,34 @@ ATAChannel::SetBus(scsi_bus bus)
|
|||||||
status_t
|
status_t
|
||||||
ATAChannel::ScanBus()
|
ATAChannel::ScanBus()
|
||||||
{
|
{
|
||||||
bool devicePresent[fDeviceCount];
|
// check if there is anything at all
|
||||||
|
if (AltStatus() == 0xff) {
|
||||||
|
TRACE_ALWAYS("illegal status value, assuming no devices connected\n");
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
uint32 deviceSignature[fDeviceCount];
|
uint32 deviceSignature[fDeviceCount];
|
||||||
status_t result = Reset(devicePresent, deviceSignature);
|
status_t result = Reset(deviceSignature);
|
||||||
if (result != B_OK) {
|
if (result != B_OK) {
|
||||||
TRACE_ERROR("resetting the channel failed\n");
|
TRACE_ERROR("resetting the channel failed\n");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint8 i = 0; i < fDeviceCount; i++) {
|
for (uint8 i = 0; i < fDeviceCount; i++) {
|
||||||
if (!devicePresent[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ATADevice *device = NULL;
|
ATADevice *device = NULL;
|
||||||
if (deviceSignature[i] == ATA_SIGNATURE_ATAPI)
|
if (deviceSignature[i] == ATA_SIGNATURE_ATAPI)
|
||||||
device = new(std::nothrow) ATAPIDevice(this, i);
|
device = new(std::nothrow) ATAPIDevice(this, i);
|
||||||
else
|
else
|
||||||
device = new(std::nothrow) ATADevice(this, i);
|
device = new(std::nothrow) ATADevice(this, i);
|
||||||
|
|
||||||
if (device == NULL)
|
if (device == NULL) {
|
||||||
|
TRACE_ERROR("out of memory allocating device\n");
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
TRACE("trying ATA%s device %u\n", device->IsATAPI() ? "PI" : "", i);
|
TRACE("trying ATA%s device %u\n", device->IsATAPI() ? "PI" : "", i);
|
||||||
|
|
||||||
bool identified = device->Identify() == B_OK;
|
if (device->Identify() != B_OK) {
|
||||||
if (!identified && !device->IsATAPI()) {
|
|
||||||
// retry as atapi
|
|
||||||
delete device;
|
|
||||||
device = new(std::nothrow) ATAPIDevice(this, i);
|
|
||||||
if (device == NULL)
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
|
|
||||||
identified = device->Identify() == B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!identified) {
|
|
||||||
delete device;
|
delete device;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -265,9 +258,8 @@ ATAChannel::SelectDevice(uint8 device)
|
|||||||
return B_BAD_INDEX;
|
return B_BAD_INDEX;
|
||||||
|
|
||||||
ata_task_file taskFile;
|
ata_task_file taskFile;
|
||||||
taskFile.chs.head = 0;
|
taskFile.lba.mode = ATA_MODE_LBA;
|
||||||
taskFile.chs.mode = ATA_MODE_LBA;
|
taskFile.lba.device = device;
|
||||||
taskFile.chs.device = device;
|
|
||||||
|
|
||||||
_WriteRegs(&taskFile, ATA_MASK_DEVICE_HEAD);
|
_WriteRegs(&taskFile, ATA_MASK_DEVICE_HEAD);
|
||||||
_FlushAndWait(1);
|
_FlushAndWait(1);
|
||||||
@@ -286,38 +278,10 @@ ATAChannel::SelectDevice(uint8 device)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
ATAChannel::IsDevicePresent(uint8 device)
|
|
||||||
{
|
|
||||||
if (SelectDevice(device) != B_OK)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ata_task_file taskFile;
|
|
||||||
taskFile.chs.device = device;
|
|
||||||
taskFile.chs.mode = ATA_MODE_LBA;
|
|
||||||
taskFile.chs.command = ATA_COMMAND_NOP;
|
|
||||||
_WriteRegs(&taskFile, ATA_MASK_DEVICE_HEAD);
|
|
||||||
|
|
||||||
_FlushAndWait(10);
|
|
||||||
|
|
||||||
_ReadRegs(&taskFile, ATA_MASK_STATUS | ATA_MASK_ERROR);
|
|
||||||
TRACE("status: 0x%02x; error: 0x%02x\n", taskFile.read.status,
|
|
||||||
taskFile.read.error);
|
|
||||||
return (taskFile.read.status & 0xf8) != 0xf8
|
|
||||||
&& taskFile.read.status != 0xa5;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
ATAChannel::Reset(bool *presence, uint32 *signatures)
|
ATAChannel::Reset(uint32 *signatures)
|
||||||
{
|
{
|
||||||
TRACE_FUNCTION("%p, %p\n", presence, signatures);
|
TRACE_FUNCTION("\n");
|
||||||
|
|
||||||
bool devicePresent[fDeviceCount];
|
|
||||||
for (uint8 i = 0; i < fDeviceCount; i++) {
|
|
||||||
devicePresent[i] = IsDevicePresent(i);
|
|
||||||
TRACE("device %d: %s present\n", i, devicePresent[i] ? "might be" : "is not");
|
|
||||||
}
|
|
||||||
|
|
||||||
SelectDevice(0);
|
SelectDevice(0);
|
||||||
|
|
||||||
@@ -339,14 +303,11 @@ ATAChannel::Reset(bool *presence, uint32 *signatures)
|
|||||||
_FlushAndWait(150 * 1000);
|
_FlushAndWait(150 * 1000);
|
||||||
|
|
||||||
for (uint8 i = 0; i < fDeviceCount; i++) {
|
for (uint8 i = 0; i < fDeviceCount; i++) {
|
||||||
if (presence != NULL)
|
|
||||||
presence[i] = devicePresent[i];
|
|
||||||
|
|
||||||
if (!devicePresent[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
SelectDevice(i);
|
SelectDevice(i);
|
||||||
|
|
||||||
|
// ensure interrupts are disabled for this device
|
||||||
|
_WriteControl(ATA_DEVICE_CONTROL_DISABLE_INTS);
|
||||||
|
|
||||||
// wait up to 31 seconds for busy to clear
|
// wait up to 31 seconds for busy to clear
|
||||||
if (Wait(0, ATA_STATUS_BUSY, 0, 31 * 1000 * 1000) != B_OK) {
|
if (Wait(0, ATA_STATUS_BUSY, 0, 31 * 1000 * 1000) != B_OK) {
|
||||||
TRACE_ERROR("reset timeout\n");
|
TRACE_ERROR("reset timeout\n");
|
||||||
@@ -390,6 +351,9 @@ ATAChannel::Wait(uint8 setBits, uint8 clearedBits, uint32 flags,
|
|||||||
bigtime_t startTime = system_time();
|
bigtime_t startTime = system_time();
|
||||||
_FlushAndWait(1);
|
_FlushAndWait(1);
|
||||||
|
|
||||||
|
TRACE("waiting for set bits 0x%02x and cleared bits 0x%02x\n",
|
||||||
|
setBits, clearedBits);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
uint8 status = AltStatus();
|
uint8 status = AltStatus();
|
||||||
if ((flags & ATA_CHECK_ERROR_BIT) != 0
|
if ((flags & ATA_CHECK_ERROR_BIT) != 0
|
||||||
@@ -398,9 +362,9 @@ ATAChannel::Wait(uint8 setBits, uint8 clearedBits, uint32 flags,
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & ATA_CHECK_DISK_FAILURE) != 0
|
if ((flags & ATA_CHECK_DEVICE_FAULT) != 0
|
||||||
&& (status & ATA_STATUS_DISK_FAILURE) != 0) {
|
&& (status & ATA_STATUS_DEVICE_FAULT) != 0) {
|
||||||
TRACE("disk failure bit set while waiting\n");
|
TRACE("device fault bit set while waiting\n");
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,7 +376,7 @@ ATAChannel::Wait(uint8 setBits, uint8 clearedBits, uint32 flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bigtime_t elapsedTime = system_time() - startTime;
|
bigtime_t elapsedTime = system_time() - startTime;
|
||||||
//TRACE("wait status after %lld: %u\n", elapsedTime, status);
|
TRACE("wait status after %lld: 0x%02x\n", elapsedTime, status);
|
||||||
if (elapsedTime > timeout)
|
if (elapsedTime > timeout)
|
||||||
return B_TIMED_OUT;
|
return B_TIMED_OUT;
|
||||||
|
|
||||||
@@ -459,6 +423,9 @@ ATAChannel::PrepareWaitingForInterrupt()
|
|||||||
InterruptsSpinLocker locker(fInterruptLock);
|
InterruptsSpinLocker locker(fInterruptLock);
|
||||||
fExpectsInterrupt = true;
|
fExpectsInterrupt = true;
|
||||||
fInterruptCondition.Add(&fInterruptConditionEntry);
|
fInterruptCondition.Add(&fInterruptConditionEntry);
|
||||||
|
|
||||||
|
// enable interrupts
|
||||||
|
_WriteControl(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -473,6 +440,9 @@ ATAChannel::WaitForInterrupt(bigtime_t timeout)
|
|||||||
fExpectsInterrupt = false;
|
fExpectsInterrupt = false;
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
|
// disable interrupts
|
||||||
|
_WriteControl(ATA_DEVICE_CONTROL_DISABLE_INTS);
|
||||||
|
|
||||||
if (result != B_OK) {
|
if (result != B_OK) {
|
||||||
TRACE_ERROR("timeout waiting for interrupt\n");
|
TRACE_ERROR("timeout waiting for interrupt\n");
|
||||||
return B_TIMED_OUT;
|
return B_TIMED_OUT;
|
||||||
@@ -485,10 +455,6 @@ ATAChannel::WaitForInterrupt(bigtime_t timeout)
|
|||||||
status_t
|
status_t
|
||||||
ATAChannel::SendRequest(ATARequest *request, uint32 flags)
|
ATAChannel::SendRequest(ATARequest *request, uint32 flags)
|
||||||
{
|
{
|
||||||
// disable interrupts for PIO transfers, enable them for DMA
|
|
||||||
_WriteControl((flags & ATA_DMA_TRANSFER) != 0 ? 0
|
|
||||||
: ATA_DEVICE_CONTROL_DISABLE_INTS);
|
|
||||||
|
|
||||||
ATADevice *device = request->Device();
|
ATADevice *device = request->Device();
|
||||||
if (device->Select() != B_OK || WaitForIdle() != B_OK) {
|
if (device->Select() != B_OK || WaitForIdle() != B_OK) {
|
||||||
// resetting the device here will discard current configuration,
|
// resetting the device here will discard current configuration,
|
||||||
@@ -553,8 +519,8 @@ ATAChannel::FinishRequest(ATARequest *request, uint32 flags, uint8 errorMask)
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8 checkFlags = ATA_STATUS_ERROR;
|
uint8 checkFlags = ATA_STATUS_ERROR;
|
||||||
if (flags & ATA_CHECK_DISK_FAILURE)
|
if (flags & ATA_CHECK_DEVICE_FAULT)
|
||||||
checkFlags |= ATA_STATUS_DISK_FAILURE;
|
checkFlags |= ATA_STATUS_DEVICE_FAULT;
|
||||||
|
|
||||||
if ((taskFile->read.status & checkFlags) == 0)
|
if ((taskFile->read.status & checkFlags) == 0)
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -646,13 +612,6 @@ ATAChannel::ExecutePIOTransfer(ATARequest *request)
|
|||||||
status_t result = B_OK;
|
status_t result = B_OK;
|
||||||
size_t *bytesLeft = request->BytesLeft();
|
size_t *bytesLeft = request->BytesLeft();
|
||||||
while (*bytesLeft > 0) {
|
while (*bytesLeft > 0) {
|
||||||
if (Wait(ATA_STATUS_DATA_REQUEST, ATA_STATUS_BUSY, ATA_CHECK_ERROR_BIT
|
|
||||||
| ATA_CHECK_DISK_FAILURE, timeout) != B_OK) {
|
|
||||||
TRACE_ERROR("timeout waiting for device to request data\n");
|
|
||||||
result = B_TIMED_OUT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t currentLength = MIN(*bytesLeft, ATA_BLOCK_SIZE);
|
size_t currentLength = MIN(*bytesLeft, ATA_BLOCK_SIZE);
|
||||||
if (request->IsWrite()) {
|
if (request->IsWrite()) {
|
||||||
result = _WritePIOBlock(request, currentLength);
|
result = _WritePIOBlock(request, currentLength);
|
||||||
@@ -670,9 +629,16 @@ ATAChannel::ExecutePIOTransfer(ATARequest *request)
|
|||||||
|
|
||||||
*bytesLeft -= currentLength;
|
*bytesLeft -= currentLength;
|
||||||
|
|
||||||
// wait 1 pio cycle
|
if (*bytesLeft > 0) {
|
||||||
if (*bytesLeft > 0)
|
// wait for next block to be ready
|
||||||
AltStatus();
|
if (Wait(ATA_STATUS_DATA_REQUEST, ATA_STATUS_BUSY,
|
||||||
|
ATA_CHECK_ERROR_BIT | ATA_CHECK_DEVICE_FAULT,
|
||||||
|
timeout) != B_OK) {
|
||||||
|
TRACE_ERROR("timeout waiting for device to request data\n");
|
||||||
|
result = B_TIMED_OUT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == B_OK && WaitDataRequest(false) != B_OK) {
|
if (result == B_OK && WaitDataRequest(false) != B_OK) {
|
||||||
|
|||||||
@@ -436,9 +436,11 @@ ATADevice::Configure()
|
|||||||
if (fUseLBA) {
|
if (fUseLBA) {
|
||||||
fTotalSectors = fInfoBlock.LBA_total_sectors;
|
fTotalSectors = fInfoBlock.LBA_total_sectors;
|
||||||
fTaskFile.lba.mode = ATA_MODE_LBA;
|
fTaskFile.lba.mode = ATA_MODE_LBA;
|
||||||
|
fTaskFile.lba.device = fIndex;
|
||||||
} else {
|
} else {
|
||||||
fTotalSectors = chsCapacity;
|
fTotalSectors = chsCapacity;
|
||||||
fTaskFile.chs.mode = ATA_MODE_CHS;
|
fTaskFile.chs.mode = ATA_MODE_CHS;
|
||||||
|
fTaskFile.chs.device = fIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
fUse48Bits = fInfoBlock._48_bit_addresses_supported;
|
fUse48Bits = fInfoBlock._48_bit_addresses_supported;
|
||||||
@@ -485,7 +487,7 @@ ATADevice::Identify()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fChannel->Wait(ATA_STATUS_DATA_REQUEST, ATA_STATUS_BUSY,
|
if (fChannel->Wait(ATA_STATUS_DATA_REQUEST, ATA_STATUS_BUSY,
|
||||||
ATA_CHECK_ERROR_BIT | ATA_CHECK_DISK_FAILURE, IsATAPI()
|
ATA_CHECK_ERROR_BIT | ATA_CHECK_DEVICE_FAULT, IsATAPI()
|
||||||
? 20 * 1000 * 1000 : 500 * 1000) != B_OK) {
|
? 20 * 1000 * 1000 : 500 * 1000) != B_OK) {
|
||||||
TRACE_ERROR("timeout waiting for identify request\n");
|
TRACE_ERROR("timeout waiting for identify request\n");
|
||||||
return B_TIMED_OUT;
|
return B_TIMED_OUT;
|
||||||
@@ -525,13 +527,8 @@ ATADevice::ExecuteReadWrite(ATARequest *request, uint64 address,
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 flags = 0;
|
status_t result = fChannel->SendRequest(request, IsATAPI()
|
||||||
if (!IsATAPI())
|
? 0 : ATA_DEVICE_READY_REQUIRED);
|
||||||
flags |= ATA_DEVICE_READY_REQUIRED;
|
|
||||||
if (request->UseDMA())
|
|
||||||
flags |= ATA_DMA_TRANSFER;
|
|
||||||
|
|
||||||
status_t result = fChannel->SendRequest(request, flags);
|
|
||||||
if (result != B_OK) {
|
if (result != B_OK) {
|
||||||
TRACE_ERROR("failed to send transfer request\n");
|
TRACE_ERROR("failed to send transfer request\n");
|
||||||
if (request->UseDMA())
|
if (request->UseDMA())
|
||||||
@@ -539,6 +536,13 @@ ATADevice::ExecuteReadWrite(ATARequest *request, uint64 address,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fChannel->Wait(ATA_STATUS_DATA_REQUEST, 0, ATA_CHECK_ERROR_BIT
|
||||||
|
| ATA_CHECK_DEVICE_FAULT, request->Timeout()) != B_OK) {
|
||||||
|
TRACE_ERROR("timeout waiting for device to request data\n");
|
||||||
|
request->SetStatus(SCSI_CMD_TIMEOUT);
|
||||||
|
return B_TIMED_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
if (request->UseDMA()) {
|
if (request->UseDMA()) {
|
||||||
fChannel->PrepareWaitingForInterrupt();
|
fChannel->PrepareWaitingForInterrupt();
|
||||||
fChannel->StartDMA();
|
fChannel->StartDMA();
|
||||||
@@ -591,6 +595,8 @@ ATADevice::_FillTaskFile(ATARequest *request, uint64 address)
|
|||||||
};
|
};
|
||||||
|
|
||||||
uint32 sectorCount = *request->BytesLeft() / ATA_BLOCK_SIZE;
|
uint32 sectorCount = *request->BytesLeft() / ATA_BLOCK_SIZE;
|
||||||
|
TRACE("about to transfer %lu sectors\n", sectorCount);
|
||||||
|
|
||||||
if (fUseLBA) {
|
if (fUseLBA) {
|
||||||
if (fUse48Bits
|
if (fUse48Bits
|
||||||
&& (address + sectorCount > 0xfffffff || sectorCount > 0x100)) {
|
&& (address + sectorCount > 0xfffffff || sectorCount > 0x100)) {
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ ata_sim_reset_bus(scsi_sim_cookie cookie)
|
|||||||
if (channel->Bus() == NULL)
|
if (channel->Bus() == NULL)
|
||||||
return SCSI_NO_HBA;
|
return SCSI_NO_HBA;
|
||||||
|
|
||||||
channel->Reset(NULL, NULL);
|
channel->Reset(NULL);
|
||||||
return SCSI_REQ_CMP;
|
return SCSI_REQ_CMP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,8 +49,7 @@ ATAPIDevice::SendPacket(ATARequest *request)
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t result = fChannel->SendRequest(request, request->UseDMA()
|
status_t result = fChannel->SendRequest(request, 0);
|
||||||
? ATA_DMA_TRANSFER : 0);
|
|
||||||
if (result != B_OK) {
|
if (result != B_OK) {
|
||||||
TRACE_ERROR("failed to send packet request\n");
|
TRACE_ERROR("failed to send packet request\n");
|
||||||
if (request->UseDMA())
|
if (request->UseDMA())
|
||||||
@@ -60,7 +59,7 @@ ATAPIDevice::SendPacket(ATARequest *request)
|
|||||||
|
|
||||||
// wait for device to get ready for packet transmission
|
// wait for device to get ready for packet transmission
|
||||||
if (fChannel->Wait(ATA_STATUS_DATA_REQUEST, ATA_STATUS_BUSY,
|
if (fChannel->Wait(ATA_STATUS_DATA_REQUEST, ATA_STATUS_BUSY,
|
||||||
ATA_CHECK_ERROR_BIT | ATA_CHECK_DISK_FAILURE, 100 * 1000) != B_OK) {
|
ATA_CHECK_ERROR_BIT | ATA_CHECK_DEVICE_FAULT, 100 * 1000) != B_OK) {
|
||||||
TRACE_ERROR("timeout waiting for data request\n");
|
TRACE_ERROR("timeout waiting for data request\n");
|
||||||
if (request->UseDMA())
|
if (request->UseDMA())
|
||||||
fChannel->FinishDMA();
|
fChannel->FinishDMA();
|
||||||
@@ -70,7 +69,7 @@ ATAPIDevice::SendPacket(ATARequest *request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make sure device really asks for command packet
|
// make sure device really asks for command packet
|
||||||
fRegisterMask = ATA_MASK_IREASON;
|
fRegisterMask = ATA_MASK_INTERRUPT_REASON;
|
||||||
fChannel->ReadRegs(this);
|
fChannel->ReadRegs(this);
|
||||||
|
|
||||||
if (!fTaskFile.packet_res.cmd_or_data
|
if (!fTaskFile.packet_res.cmd_or_data
|
||||||
@@ -96,6 +95,14 @@ ATAPIDevice::SendPacket(ATARequest *request)
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!request->HasData()) {
|
||||||
|
result = fChannel->FinishRequest(request, ATA_WAIT_FINISH
|
||||||
|
| ATA_CHECK_DEVICE_FAULT, ATA_ERROR_ALL);
|
||||||
|
if (result != B_OK)
|
||||||
|
TRACE_ERROR("device indicates error after non-data command\n");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
if (request->UseDMA()) {
|
if (request->UseDMA()) {
|
||||||
fChannel->PrepareWaitingForInterrupt();
|
fChannel->PrepareWaitingForInterrupt();
|
||||||
fChannel->StartDMA();
|
fChannel->StartDMA();
|
||||||
@@ -107,7 +114,7 @@ ATAPIDevice::SendPacket(ATARequest *request)
|
|||||||
return B_TIMED_OUT;
|
return B_TIMED_OUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = fChannel->FinishRequest(request, ATA_CHECK_DISK_FAILURE,
|
result = fChannel->FinishRequest(request, ATA_CHECK_DEVICE_FAULT,
|
||||||
ATA_ERROR_ALL);
|
ATA_ERROR_ALL);
|
||||||
if (result != B_OK) {
|
if (result != B_OK) {
|
||||||
TRACE_ERROR("device indicates transfer error after dma\n");
|
TRACE_ERROR("device indicates transfer error after dma\n");
|
||||||
@@ -133,33 +140,47 @@ ATAPIDevice::SendPacket(ATARequest *request)
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PIO data transfer
|
|
||||||
if (fChannel->Wait(ATA_STATUS_DATA_REQUEST, ATA_STATUS_BUSY,
|
if (fChannel->Wait(ATA_STATUS_DATA_REQUEST, ATA_STATUS_BUSY,
|
||||||
ATA_CHECK_ERROR_BIT | ATA_CHECK_DISK_FAILURE,
|
ATA_CHECK_ERROR_BIT | ATA_CHECK_DEVICE_FAULT,
|
||||||
request->Timeout()) != B_OK) {
|
request->Timeout()) != B_OK) {
|
||||||
TRACE_ERROR("timeout waiting for device to request data\n");
|
TRACE_ERROR("timeout waiting for device to request data\n");
|
||||||
request->SetStatus(SCSI_CMD_TIMEOUT);
|
request->SetStatus(SCSI_CMD_TIMEOUT);
|
||||||
return B_TIMED_OUT;
|
return B_TIMED_OUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
fRegisterMask = ATA_MASK_IREASON | ATA_MASK_BYTE_COUNT;
|
// PIO data transfer
|
||||||
fChannel->ReadRegs(this);
|
while (true) {
|
||||||
|
fRegisterMask = ATA_MASK_INTERRUPT_REASON | ATA_MASK_BYTE_COUNT;
|
||||||
|
fChannel->ReadRegs(this);
|
||||||
|
|
||||||
if (fTaskFile.packet_res.cmd_or_data) {
|
if (fTaskFile.packet_res.cmd_or_data) {
|
||||||
TRACE_ERROR("device expecting command instead of data\n");
|
TRACE_ERROR("device expecting command instead of data\n");
|
||||||
request->SetStatus(SCSI_SEQUENCE_FAIL);
|
request->SetStatus(SCSI_SEQUENCE_FAIL);
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length = fTaskFile.packet_res.byte_count_0_7
|
||||||
|
| ((size_t)fTaskFile.packet_res.byte_count_8_15 << 8);
|
||||||
|
TRACE("about to transfer %lu bytes\n", length);
|
||||||
|
|
||||||
|
request->SetBytesLeft(length);
|
||||||
|
fChannel->ExecutePIOTransfer(request);
|
||||||
|
|
||||||
|
if (fChannel->Wait(0, ATA_STATUS_BUSY, 0, request->Timeout()) != B_OK) {
|
||||||
|
TRACE_ERROR("timeout waiting for device to finish transfer\n");
|
||||||
|
request->SetStatus(SCSI_CMD_TIMEOUT);
|
||||||
|
return B_TIMED_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fChannel->AltStatus() & ATA_STATUS_DATA_REQUEST) == 0) {
|
||||||
|
// transfer complete
|
||||||
|
TRACE("pio transfer complete\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t length = fTaskFile.packet_res.byte_count_0_7
|
|
||||||
| ((size_t)fTaskFile.packet_res.byte_count_8_15 << 8);
|
|
||||||
TRACE("about to transfer %lu bytes\n", length);
|
|
||||||
|
|
||||||
request->SetBytesLeft(length);
|
|
||||||
fChannel->ExecutePIOTransfer(request);
|
|
||||||
|
|
||||||
result = fChannel->FinishRequest(request, ATA_WAIT_FINISH
|
result = fChannel->FinishRequest(request, ATA_WAIT_FINISH
|
||||||
| ATA_CHECK_DISK_FAILURE, ATA_ERROR_ALL);
|
| ATA_CHECK_DEVICE_FAULT, ATA_ERROR_ALL);
|
||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
TRACE_ERROR("device indicates transfer error after pio\n");
|
TRACE_ERROR("device indicates transfer error after pio\n");
|
||||||
|
|
||||||
@@ -210,7 +231,7 @@ ATAPIDevice::_FillTaskFilePacket(ATARequest *request)
|
|||||||
{
|
{
|
||||||
scsi_ccb *ccb = request->CCB();
|
scsi_ccb *ccb = request->CCB();
|
||||||
fRegisterMask = ATA_MASK_FEATURES | ATA_MASK_BYTE_COUNT;
|
fRegisterMask = ATA_MASK_FEATURES | ATA_MASK_BYTE_COUNT;
|
||||||
fTaskFile.packet.dma = request->UseDMA();
|
fTaskFile.packet.dma = request->UseDMA() ? 1 : 0;
|
||||||
fTaskFile.packet.ovl = 0;
|
fTaskFile.packet.ovl = 0;
|
||||||
fTaskFile.packet.byte_count_0_7 = ccb->data_length & 0xff;
|
fTaskFile.packet.byte_count_0_7 = ccb->data_length & 0xff;
|
||||||
fTaskFile.packet.byte_count_8_15 = ccb->data_length >> 8;
|
fTaskFile.packet.byte_count_8_15 = ccb->data_length >> 8;
|
||||||
|
|||||||
@@ -29,7 +29,9 @@
|
|||||||
#define ATA_MAX_DMA_FAILURES 3
|
#define ATA_MAX_DMA_FAILURES 3
|
||||||
#define ATA_STANDARD_TIMEOUT 10 * 1000 * 1000
|
#define ATA_STANDARD_TIMEOUT 10 * 1000 * 1000
|
||||||
#define ATA_RELEASE_TIMEOUT 10 * 1000 * 1000
|
#define ATA_RELEASE_TIMEOUT 10 * 1000 * 1000
|
||||||
|
#define ATA_SIGNATURE_ATA 0x00000101
|
||||||
#define ATA_SIGNATURE_ATAPI 0xeb140101
|
#define ATA_SIGNATURE_ATAPI 0xeb140101
|
||||||
|
#define ATA_SIGNATURE_SATA 0xc33c0101
|
||||||
#define ATA_SIM_MODULE_NAME "bus_managers/ata/sim/driver_v1"
|
#define ATA_SIM_MODULE_NAME "bus_managers/ata/sim/driver_v1"
|
||||||
#define ATA_CHANNEL_ID_GENERATOR "ata/channel_id"
|
#define ATA_CHANNEL_ID_GENERATOR "ata/channel_id"
|
||||||
#define ATA_CHANNEL_ID_ITEM "ata/channel_id"
|
#define ATA_CHANNEL_ID_ITEM "ata/channel_id"
|
||||||
@@ -41,7 +43,7 @@ enum {
|
|||||||
ATA_CHECK_ERROR_BIT = 0x08,
|
ATA_CHECK_ERROR_BIT = 0x08,
|
||||||
ATA_WAIT_FINISH = 0x10,
|
ATA_WAIT_FINISH = 0x10,
|
||||||
ATA_WAIT_ANY_BIT = 0x20,
|
ATA_WAIT_ANY_BIT = 0x20,
|
||||||
ATA_CHECK_DISK_FAILURE = 0x40
|
ATA_CHECK_DEVICE_FAULT = 0x40
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -75,9 +77,8 @@ public:
|
|||||||
|
|
||||||
// ATA stuff
|
// ATA stuff
|
||||||
status_t SelectDevice(uint8 index);
|
status_t SelectDevice(uint8 index);
|
||||||
bool IsDevicePresent(uint8 index);
|
|
||||||
|
|
||||||
status_t Reset(bool *presence, uint32 *signatures);
|
status_t Reset(uint32 *signatures);
|
||||||
|
|
||||||
bool UseDMA() { return fUseDMA; };
|
bool UseDMA() { return fUseDMA; };
|
||||||
|
|
||||||
@@ -268,6 +269,8 @@ public:
|
|||||||
void SetBytesLeft(uint32 bytesLeft);
|
void SetBytesLeft(uint32 bytesLeft);
|
||||||
size_t * BytesLeft() { return &fBytesLeft; };
|
size_t * BytesLeft() { return &fBytesLeft; };
|
||||||
|
|
||||||
|
bool HasData() { return fCCB->data_length > 0; };
|
||||||
|
|
||||||
status_t Finish(bool resubmit);
|
status_t Finish(bool resubmit);
|
||||||
|
|
||||||
// SCSI stuff
|
// SCSI stuff
|
||||||
|
|||||||
Reference in New Issue
Block a user