Adding ATAPI support to the new ATA bus_manager. Only tested in QEMU.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30080 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -14,7 +14,7 @@ ATAChannel::ATAChannel(device_node *node)
|
|||||||
fChannelID(0),
|
fChannelID(0),
|
||||||
fController(NULL),
|
fController(NULL),
|
||||||
fCookie(NULL),
|
fCookie(NULL),
|
||||||
fExpectsDMATransfer(false),
|
fExpectsInterrupt(false),
|
||||||
fStatus(B_NO_INIT),
|
fStatus(B_NO_INIT),
|
||||||
fSCSIBus(NULL),
|
fSCSIBus(NULL),
|
||||||
fDeviceCount(0),
|
fDeviceCount(0),
|
||||||
@@ -23,8 +23,8 @@ ATAChannel::ATAChannel(device_node *node)
|
|||||||
fRequest(NULL)
|
fRequest(NULL)
|
||||||
{
|
{
|
||||||
mutex_init(&fExecutionLock, "ata io execution");
|
mutex_init(&fExecutionLock, "ata io execution");
|
||||||
B_INITIALIZE_SPINLOCK(&fDMATransferLock);
|
B_INITIALIZE_SPINLOCK(&fInterruptLock);
|
||||||
fDMATransferCondition.Init(this, "ata dma transfer");
|
fInterruptCondition.Init(this, "ata dma transfer");
|
||||||
|
|
||||||
gDeviceManager->get_attr_uint32(node, ATA_CHANNEL_ID_ITEM, &fChannelID,
|
gDeviceManager->get_attr_uint32(node, ATA_CHANNEL_ID_ITEM, &fChannelID,
|
||||||
true);
|
true);
|
||||||
@@ -234,6 +234,9 @@ ATAChannel::ExecuteIO(scsi_ccb *ccb)
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we aren't a check sense request, clear sense data for new request
|
||||||
|
fRequest->ClearSense();
|
||||||
|
|
||||||
if (ccb->target_id >= fDeviceCount) {
|
if (ccb->target_id >= fDeviceCount) {
|
||||||
TRACE_ERROR("invalid target device\n");
|
TRACE_ERROR("invalid target device\n");
|
||||||
fRequest->SetStatus(SCSI_SEL_TIMEOUT);
|
fRequest->SetStatus(SCSI_SEL_TIMEOUT);
|
||||||
@@ -393,7 +396,7 @@ ATAChannel::Wait(uint8 setBits, uint8 clearedBits, uint32 flags,
|
|||||||
_FlushAndWait(1);
|
_FlushAndWait(1);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
uint8 status = _AltStatus();
|
uint8 status = AltStatus();
|
||||||
if ((flags & ATA_CHECK_ERROR_BIT) != 0
|
if ((flags & ATA_CHECK_ERROR_BIT) != 0
|
||||||
&& (status & ATA_STATUS_ERROR) != 0)
|
&& (status & ATA_STATUS_ERROR) != 0)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
@@ -443,7 +446,37 @@ ATAChannel::WaitDeviceReady()
|
|||||||
status_t
|
status_t
|
||||||
ATAChannel::WaitForIdle()
|
ATAChannel::WaitForIdle()
|
||||||
{
|
{
|
||||||
return Wait(0, ATA_STATUS_BUSY | ATA_STATUS_DATA_REQUEST, 0, 20 * 1000);
|
return Wait(0, ATA_STATUS_BUSY | ATA_STATUS_DATA_REQUEST, 0, 50 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ATAChannel::PrepareWaitingForInterrupt()
|
||||||
|
{
|
||||||
|
TRACE_FUNCTION("\n");
|
||||||
|
InterruptsSpinLocker locker(fInterruptLock);
|
||||||
|
fExpectsInterrupt = true;
|
||||||
|
fInterruptCondition.Add(&fInterruptConditionEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ATAChannel::WaitForInterrupt(bigtime_t timeout)
|
||||||
|
{
|
||||||
|
TRACE_FUNCTION("timeout: %lld\n", timeout);
|
||||||
|
status_t result = fInterruptConditionEntry.Wait(B_RELATIVE_TIMEOUT,
|
||||||
|
timeout);
|
||||||
|
|
||||||
|
InterruptsSpinLocker locker(fInterruptLock);
|
||||||
|
fExpectsInterrupt = false;
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
if (result != B_OK) {
|
||||||
|
TRACE_ERROR("timeout waiting for interrupt\n");
|
||||||
|
return B_TIMED_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -464,7 +497,7 @@ ATAChannel::SendRequest(ATARequest *request, uint32 flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & ATA_DEVICE_READY_REQUIRED) != 0
|
if ((flags & ATA_DEVICE_READY_REQUIRED) != 0
|
||||||
&& (_AltStatus() & ATA_STATUS_DEVICE_READY) == 0) {
|
&& (AltStatus() & ATA_STATUS_DEVICE_READY) == 0) {
|
||||||
TRACE_ERROR("device ready not set\n");
|
TRACE_ERROR("device ready not set\n");
|
||||||
request->SetStatus(SCSI_SEQUENCE_FAIL);
|
request->SetStatus(SCSI_SEQUENCE_FAIL);
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
@@ -583,35 +616,16 @@ ATAChannel::PrepareDMA(ATARequest *request)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
ATAChannel::FinishDMA()
|
ATAChannel::StartDMA()
|
||||||
{
|
{
|
||||||
return fController->finish_dma(fCookie);
|
return fController->start_dma(fCookie);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
ATAChannel::ExecuteDMATransfer(ATARequest *request)
|
ATAChannel::FinishDMA()
|
||||||
{
|
{
|
||||||
InterruptsSpinLocker locker(fDMATransferLock);
|
return fController->finish_dma(fCookie);
|
||||||
fExpectsDMATransfer = true;
|
|
||||||
ConditionVariableEntry entry;
|
|
||||||
fDMATransferCondition.Add(&entry);
|
|
||||||
locker.Unlock();
|
|
||||||
|
|
||||||
fController->start_dma(fCookie);
|
|
||||||
bigtime_t timeout = system_time() + request->Timeout();
|
|
||||||
status_t waitResult = entry.Wait(B_ABSOLUTE_TIMEOUT, timeout);
|
|
||||||
|
|
||||||
locker.Lock();
|
|
||||||
fExpectsDMATransfer = false;
|
|
||||||
locker.Unlock();
|
|
||||||
|
|
||||||
if (waitResult != B_OK) {
|
|
||||||
TRACE_ERROR("timeout waiting for DMA transfer\n");
|
|
||||||
return B_TIMED_OUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -646,7 +660,7 @@ ATAChannel::ExecutePIOTransfer(ATARequest *request)
|
|||||||
|
|
||||||
// wait 1 pio cycle
|
// wait 1 pio cycle
|
||||||
if (*blocksLeft > 0)
|
if (*blocksLeft > 0)
|
||||||
_AltStatus();
|
AltStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == B_OK && WaitDataRequest(false) != B_OK) {
|
if (result == B_OK && WaitDataRequest(false) != B_OK) {
|
||||||
@@ -658,6 +672,20 @@ ATAChannel::ExecutePIOTransfer(ATARequest *request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ATAChannel::ReadRegs(ATADevice *device)
|
||||||
|
{
|
||||||
|
return _ReadRegs(device->TaskFile(), device->RegisterMask());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8
|
||||||
|
ATAChannel::AltStatus()
|
||||||
|
{
|
||||||
|
return fController->get_altstatus(fCookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
ATAChannel::ReadPIO(uint8 *buffer, size_t length)
|
ATAChannel::ReadPIO(uint8 *buffer, size_t length)
|
||||||
{
|
{
|
||||||
@@ -666,11 +694,19 @@ ATAChannel::ReadPIO(uint8 *buffer, size_t length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ATAChannel::WritePIO(uint8 *buffer, size_t length)
|
||||||
|
{
|
||||||
|
return fController->write_pio(fCookie, (uint16 *)buffer,
|
||||||
|
length / sizeof(uint16), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ATAChannel::Interrupt(uint8 status)
|
ATAChannel::Interrupt(uint8 status)
|
||||||
{
|
{
|
||||||
SpinLocker locker(fDMATransferLock);
|
SpinLocker locker(fInterruptLock);
|
||||||
if (!fExpectsDMATransfer) {
|
if (!fExpectsInterrupt) {
|
||||||
TRACE_ERROR("interrupt when not expecting transfer\n");
|
TRACE_ERROR("interrupt when not expecting transfer\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -680,7 +716,7 @@ ATAChannel::Interrupt(uint8 status)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fDMATransferCondition.NotifyAll();
|
fInterruptCondition.NotifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -706,17 +742,10 @@ ATAChannel::_WriteControl(uint8 value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint8
|
|
||||||
ATAChannel::_AltStatus()
|
|
||||||
{
|
|
||||||
return fController->get_altstatus(fCookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ATAChannel::_FlushAndWait(bigtime_t waitTime)
|
ATAChannel::_FlushAndWait(bigtime_t waitTime)
|
||||||
{
|
{
|
||||||
_AltStatus();
|
AltStatus();
|
||||||
if (waitTime > 100)
|
if (waitTime > 100)
|
||||||
snooze(waitTime);
|
snooze(waitTime);
|
||||||
else
|
else
|
||||||
@@ -749,7 +778,7 @@ ATAChannel::_ReadPIOBlock(ATARequest *request, size_t length)
|
|||||||
if (transferred >= length)
|
if (transferred >= length)
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
TRACE_ERROR("pio read: discarding after %lu bytes", transferred);
|
TRACE_ERROR("pio read: discarding after %lu bytes\n", transferred);
|
||||||
|
|
||||||
uint8 buffer[32];
|
uint8 buffer[32];
|
||||||
length -= transferred;
|
length -= transferred;
|
||||||
@@ -799,7 +828,7 @@ ATAChannel::_WritePIOBlock(ATARequest *request, size_t length)
|
|||||||
// only solution is to send zero bytes, though it's BAD
|
// only solution is to send zero bytes, though it's BAD
|
||||||
static const uint8 buffer[32] = {};
|
static const uint8 buffer[32] = {};
|
||||||
|
|
||||||
TRACE_ERROR("pio write: discarding after %lu bytes", transferred);
|
TRACE_ERROR("pio write: discarding after %lu bytes\n", transferred);
|
||||||
|
|
||||||
length -= transferred;
|
length -= transferred;
|
||||||
while (length > 0) {
|
while (length > 0) {
|
||||||
|
|||||||
@@ -12,14 +12,14 @@
|
|||||||
|
|
||||||
ATADevice::ATADevice(ATAChannel *channel, uint8 index)
|
ATADevice::ATADevice(ATAChannel *channel, uint8 index)
|
||||||
: fChannel(channel),
|
: fChannel(channel),
|
||||||
fIndex(index),
|
fRegisterMask(0),
|
||||||
fUseLBA(false),
|
|
||||||
fUse48Bits(false),
|
|
||||||
fUseDMA(channel->UseDMA()),
|
fUseDMA(channel->UseDMA()),
|
||||||
fDMAMode(0),
|
fDMAMode(0),
|
||||||
fDMAFailures(0),
|
fDMAFailures(0),
|
||||||
fTotalSectors(0),
|
fIndex(index),
|
||||||
fRegisterMask(0)
|
fUseLBA(false),
|
||||||
|
fUse48Bits(false),
|
||||||
|
fTotalSectors(0)
|
||||||
{
|
{
|
||||||
memset(&fInfoBlock, 0, sizeof(fInfoBlock));
|
memset(&fInfoBlock, 0, sizeof(fInfoBlock));
|
||||||
memset(&fTaskFile, 0, sizeof(fTaskFile));
|
memset(&fTaskFile, 0, sizeof(fTaskFile));
|
||||||
@@ -202,7 +202,6 @@ ATADevice::ExecuteIO(ATARequest *request)
|
|||||||
|
|
||||||
TRACE("request: 0x%02x\n", ccb->cdb[0]);
|
TRACE("request: 0x%02x\n", ccb->cdb[0]);
|
||||||
|
|
||||||
request->ClearSense();
|
|
||||||
switch (ccb->cdb[0]) {
|
switch (ccb->cdb[0]) {
|
||||||
case SCSI_OP_TEST_UNIT_READY:
|
case SCSI_OP_TEST_UNIT_READY:
|
||||||
return TestUnitReady(request);
|
return TestUnitReady(request);
|
||||||
@@ -541,7 +540,10 @@ ATADevice::ExecuteReadWrite(ATARequest *request, uint64 address,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (request->UseDMA()) {
|
if (request->UseDMA()) {
|
||||||
result = fChannel->ExecuteDMATransfer(request);
|
fChannel->PrepareWaitingForInterrupt();
|
||||||
|
fChannel->StartDMA();
|
||||||
|
|
||||||
|
result = fChannel->WaitForInterrupt(request->Timeout());
|
||||||
status_t dmaResult = fChannel->FinishDMA();
|
status_t dmaResult = fChannel->FinishDMA();
|
||||||
if (result == B_OK && dmaResult == B_OK) {
|
if (result == B_OK && dmaResult == B_OK) {
|
||||||
fDMAFailures = 0;
|
fDMAFailures = 0;
|
||||||
|
|||||||
@@ -10,8 +10,7 @@
|
|||||||
#include "ATAPrivate.h"
|
#include "ATAPrivate.h"
|
||||||
|
|
||||||
ATAPIDevice::ATAPIDevice(ATAChannel *channel, uint8 index)
|
ATAPIDevice::ATAPIDevice(ATAChannel *channel, uint8 index)
|
||||||
: ATADevice(channel, index),
|
: ATADevice(channel, index)
|
||||||
fLastLun(1)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,10 +20,204 @@ ATAPIDevice::~ATAPIDevice()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ATAPIDevice::SendPacket(ATARequest *request)
|
||||||
|
{
|
||||||
|
TRACE_FUNCTION("%p\n", request);
|
||||||
|
|
||||||
|
// only READ/WRITE commands can use DMA
|
||||||
|
// (the device may support it always, but IDE controllers don't
|
||||||
|
// report how much data is transmitted, and this information is
|
||||||
|
// crucial for the SCSI protocol)
|
||||||
|
// special offer: let READ_CD commands use DMA too
|
||||||
|
uint8 command = fPacket[0];
|
||||||
|
request->SetUseDMA(UseDMA()
|
||||||
|
&& (command == SCSI_OP_READ_6 || command == SCSI_OP_WRITE_6
|
||||||
|
|| command == SCSI_OP_READ_10 || command == SCSI_OP_WRITE_10
|
||||||
|
|| command == SCSI_OP_READ_12 || command == SCSI_OP_WRITE_12
|
||||||
|
|| command == SCSI_OP_READ_CD)
|
||||||
|
&& fChannel->PrepareDMA(request) == B_OK);
|
||||||
|
TRACE("using dma: %s\n", request->UseDMA() ? "yes" : "no");
|
||||||
|
|
||||||
|
if (!request->UseDMA())
|
||||||
|
request->PrepareSGInfo();
|
||||||
|
|
||||||
|
if (_FillTaskFilePacket(request) != B_OK) {
|
||||||
|
TRACE_ERROR("failed to setup transfer request\n");
|
||||||
|
if (request->UseDMA())
|
||||||
|
fChannel->FinishDMA();
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fInterruptsForPacket)
|
||||||
|
fChannel->PrepareWaitingForInterrupt();
|
||||||
|
|
||||||
|
status_t result = fChannel->SendRequest(request, ATA_DMA_TRANSFER);
|
||||||
|
if (result != B_OK) {
|
||||||
|
TRACE_ERROR("failed to send packet request\n");
|
||||||
|
if (request->UseDMA())
|
||||||
|
fChannel->FinishDMA();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for device to get ready for packet transmission
|
||||||
|
bool timedOut = false;
|
||||||
|
if (fInterruptsForPacket)
|
||||||
|
timedOut = fChannel->WaitForInterrupt(request->Timeout()) != B_OK;
|
||||||
|
else {
|
||||||
|
timedOut = fChannel->Wait(ATA_STATUS_DATA_REQUEST, ATA_STATUS_BUSY, 0,
|
||||||
|
100 * 1000) != B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timedOut) {
|
||||||
|
TRACE_ERROR("timeout waiting for data request\n");
|
||||||
|
if (request->UseDMA())
|
||||||
|
fChannel->FinishDMA();
|
||||||
|
|
||||||
|
request->SetStatus(SCSI_SEQUENCE_FAIL);
|
||||||
|
return B_TIMED_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure device really asks for command packet
|
||||||
|
fRegisterMask = ATA_MASK_IREASON;
|
||||||
|
fChannel->ReadRegs(this);
|
||||||
|
|
||||||
|
if (!fTaskFile.packet_res.cmd_or_data
|
||||||
|
|| fTaskFile.packet_res.input_or_output) {
|
||||||
|
TRACE_ERROR("device doesn't ask for packet\n");
|
||||||
|
if (request->UseDMA())
|
||||||
|
fChannel->FinishDMA();
|
||||||
|
|
||||||
|
request->SetStatus(SCSI_SEQUENCE_FAIL);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// some old drives need a delay before submitting the packet
|
||||||
|
spin(10);
|
||||||
|
|
||||||
|
fChannel->PrepareWaitingForInterrupt();
|
||||||
|
|
||||||
|
// write packet
|
||||||
|
if (fChannel->WritePIO(fPacket, sizeof(fPacket)) != B_OK) {
|
||||||
|
TRACE_ERROR("failed to write packet\n");
|
||||||
|
if (request->UseDMA())
|
||||||
|
fChannel->FinishDMA();
|
||||||
|
|
||||||
|
request->SetStatus(SCSI_HBA_ERR);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->UseDMA()) {
|
||||||
|
fChannel->StartDMA();
|
||||||
|
result = fChannel->WaitForInterrupt(request->Timeout());
|
||||||
|
status_t dmaResult = fChannel->FinishDMA();
|
||||||
|
if (result == B_OK && dmaResult == B_OK) {
|
||||||
|
fDMAFailures = 0;
|
||||||
|
request->CCB()->data_resid = 0;
|
||||||
|
} else {
|
||||||
|
if (dmaResult != B_OK) {
|
||||||
|
request->SetSense(SCSIS_KEY_HARDWARE_ERROR,
|
||||||
|
SCSIS_ASC_LUN_COM_FAILURE);
|
||||||
|
fDMAFailures++;
|
||||||
|
if (fDMAFailures >= ATA_MAX_DMA_FAILURES) {
|
||||||
|
TRACE_ALWAYS("disabling DMA after %u failures\n",
|
||||||
|
fDMAFailures);
|
||||||
|
fUseDMA = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// timeout
|
||||||
|
request->SetStatus(SCSI_CMD_TIMEOUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = fChannel->WaitForInterrupt(request->Timeout());
|
||||||
|
if (result != B_OK) {
|
||||||
|
TRACE_ERROR("timeout waiting for device to request data\n");
|
||||||
|
request->SetStatus(SCSI_SEQUENCE_FAIL);
|
||||||
|
return B_TIMED_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
uint8 altStatus = fChannel->AltStatus();
|
||||||
|
if ((altStatus & ATA_STATUS_DATA_REQUEST) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
fRegisterMask = ATA_MASK_ERROR | ATA_MASK_IREASON;
|
||||||
|
fChannel->ReadRegs(this);
|
||||||
|
|
||||||
|
if (fTaskFile.packet_res.cmd_or_data) {
|
||||||
|
TRACE_ERROR("device expecting command instead of data\n");
|
||||||
|
request->SetStatus(SCSI_SEQUENCE_FAIL);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
fRegisterMask = ATA_MASK_BYTE_COUNT;
|
||||||
|
fChannel->ReadRegs(this);
|
||||||
|
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->SetBlocksLeft((length + 511) / 512);
|
||||||
|
if (fChannel->ExecutePIOTransfer(request) != B_OK) {
|
||||||
|
TRACE_ERROR("failed to transfer data\n");
|
||||||
|
request->SetStatus(SCSI_SEQUENCE_FAIL);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fChannel->FinishRequest(request, ATA_WAIT_FINISH, ATA_ERROR_ABORTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
ATAPIDevice::ExecuteIO(ATARequest *request)
|
ATAPIDevice::ExecuteIO(ATARequest *request)
|
||||||
{
|
{
|
||||||
request->SetStatus(SCSI_SEL_TIMEOUT);
|
scsi_ccb *ccb = request->CCB();
|
||||||
request->SetSense(SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_CDB_FIELD);
|
if (ccb->target_lun > fInfoBlock.last_lun) {
|
||||||
return B_ERROR;
|
TRACE_ERROR("invalid target lun %d, last lun is %d\n", ccb->target_lun,
|
||||||
|
fInfoBlock.last_lun);
|
||||||
|
request->SetStatus(SCSI_SEL_TIMEOUT);
|
||||||
|
return B_BAD_INDEX;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ATAPI command packets are 12 bytes long;
|
||||||
|
// if the command is shorter, remaining bytes must be padded with zeros
|
||||||
|
memset(fPacket, 0, sizeof(fPacket));
|
||||||
|
memcpy(fPacket, ccb->cdb, ccb->cdb_length);
|
||||||
|
|
||||||
|
request->SetDevice(this);
|
||||||
|
request->SetIsWrite((ccb->flags & SCSI_DIR_MASK) == SCSI_DIR_OUT);
|
||||||
|
return SendPacket(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ATAPIDevice::Configure()
|
||||||
|
{
|
||||||
|
if (fInfoBlock._0.atapi.ATAPI != 2)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
fTaskFile.packet.lun = 0;
|
||||||
|
fInterruptsForPacket = fInfoBlock._0.atapi.drq_speed == 1;
|
||||||
|
|
||||||
|
status_t result = ConfigureDMA();
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ATAPIDevice::_FillTaskFilePacket(ATARequest *request)
|
||||||
|
{
|
||||||
|
scsi_ccb *ccb = request->CCB();
|
||||||
|
fRegisterMask = ATA_MASK_FEATURES | ATA_MASK_BYTE_COUNT;
|
||||||
|
fTaskFile.packet.dma = request->UseDMA();
|
||||||
|
fTaskFile.packet.ovl = 0;
|
||||||
|
fTaskFile.packet.byte_count_0_7 = ccb->data_length & 0xff;
|
||||||
|
fTaskFile.packet.byte_count_8_15 = ccb->data_length >> 8;
|
||||||
|
fTaskFile.packet.command = ATA_COMMAND_PACKET;
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,9 @@ public:
|
|||||||
status_t WaitDeviceReady();
|
status_t WaitDeviceReady();
|
||||||
status_t WaitForIdle();
|
status_t WaitForIdle();
|
||||||
|
|
||||||
|
void PrepareWaitingForInterrupt();
|
||||||
|
status_t WaitForInterrupt(bigtime_t timeout);
|
||||||
|
|
||||||
// request handling
|
// request handling
|
||||||
status_t SendRequest(ATARequest *request,
|
status_t SendRequest(ATARequest *request,
|
||||||
uint32 flags);
|
uint32 flags);
|
||||||
@@ -93,12 +96,16 @@ public:
|
|||||||
|
|
||||||
// data transfers
|
// data transfers
|
||||||
status_t PrepareDMA(ATARequest *request);
|
status_t PrepareDMA(ATARequest *request);
|
||||||
|
status_t StartDMA();
|
||||||
status_t FinishDMA();
|
status_t FinishDMA();
|
||||||
|
|
||||||
status_t ExecuteDMATransfer(ATARequest *request);
|
|
||||||
status_t ExecutePIOTransfer(ATARequest *request);
|
status_t ExecutePIOTransfer(ATARequest *request);
|
||||||
|
|
||||||
|
status_t ReadRegs(ATADevice *device);
|
||||||
|
uint8 AltStatus();
|
||||||
|
|
||||||
status_t ReadPIO(uint8 *buffer, size_t length);
|
status_t ReadPIO(uint8 *buffer, size_t length);
|
||||||
|
status_t WritePIO(uint8 *buffer, size_t length);
|
||||||
|
|
||||||
void Interrupt(uint8 status);
|
void Interrupt(uint8 status);
|
||||||
|
|
||||||
@@ -109,7 +116,6 @@ private:
|
|||||||
ata_reg_mask mask);
|
ata_reg_mask mask);
|
||||||
status_t _WriteControl(uint8 value);
|
status_t _WriteControl(uint8 value);
|
||||||
|
|
||||||
uint8 _AltStatus();
|
|
||||||
void _FlushAndWait(bigtime_t waitTime);
|
void _FlushAndWait(bigtime_t waitTime);
|
||||||
|
|
||||||
status_t _ReadPIOBlock(ATARequest *request,
|
status_t _ReadPIOBlock(ATARequest *request,
|
||||||
@@ -133,9 +139,10 @@ private:
|
|||||||
void * fCookie;
|
void * fCookie;
|
||||||
|
|
||||||
mutex fExecutionLock;
|
mutex fExecutionLock;
|
||||||
spinlock fDMATransferLock;
|
spinlock fInterruptLock;
|
||||||
ConditionVariable fDMATransferCondition;
|
ConditionVariable fInterruptCondition;
|
||||||
bool fExpectsDMATransfer;
|
ConditionVariableEntry fInterruptConditionEntry;
|
||||||
|
bool fExpectsInterrupt;
|
||||||
|
|
||||||
status_t fStatus;
|
status_t fStatus;
|
||||||
scsi_bus fSCSIBus;
|
scsi_bus fSCSIBus;
|
||||||
@@ -179,29 +186,32 @@ virtual bool IsATAPI() { return false; };
|
|||||||
status_t DisableCommandQueueing();
|
status_t DisableCommandQueueing();
|
||||||
status_t ConfigureDMA();
|
status_t ConfigureDMA();
|
||||||
|
|
||||||
status_t Configure();
|
virtual status_t Configure();
|
||||||
status_t Identify();
|
status_t Identify();
|
||||||
|
|
||||||
status_t ExecuteReadWrite(ATARequest *request,
|
status_t ExecuteReadWrite(ATARequest *request,
|
||||||
uint64 address, uint32 sectorCount);
|
uint64 address, uint32 sectorCount);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const char * _DebugContext() { return fDebugContext; };
|
||||||
|
|
||||||
|
ATAChannel * fChannel;
|
||||||
|
ata_device_infoblock fInfoBlock;
|
||||||
|
ata_task_file fTaskFile;
|
||||||
|
ata_reg_mask fRegisterMask;
|
||||||
|
|
||||||
|
bool fUseDMA;
|
||||||
|
uint8 fDMAMode;
|
||||||
|
uint8 fDMAFailures;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t _FillTaskFile(ATARequest *request,
|
status_t _FillTaskFile(ATARequest *request,
|
||||||
uint64 address);
|
uint64 address);
|
||||||
|
|
||||||
const char * _DebugContext() { return fDebugContext; };
|
|
||||||
|
|
||||||
ATAChannel * fChannel;
|
|
||||||
uint8 fIndex;
|
uint8 fIndex;
|
||||||
bool fUseLBA;
|
bool fUseLBA;
|
||||||
bool fUse48Bits;
|
bool fUse48Bits;
|
||||||
bool fUseDMA;
|
|
||||||
uint8 fDMAMode;
|
|
||||||
uint8 fDMAFailures;
|
|
||||||
uint64 fTotalSectors;
|
uint64 fTotalSectors;
|
||||||
ata_device_infoblock fInfoBlock;
|
|
||||||
ata_task_file fTaskFile;
|
|
||||||
ata_reg_mask fRegisterMask;
|
|
||||||
|
|
||||||
char fDebugContext[16];
|
char fDebugContext[16];
|
||||||
};
|
};
|
||||||
@@ -213,12 +223,18 @@ public:
|
|||||||
uint8 index);
|
uint8 index);
|
||||||
virtual ~ATAPIDevice();
|
virtual ~ATAPIDevice();
|
||||||
|
|
||||||
|
status_t SendPacket(ATARequest *request);
|
||||||
virtual status_t ExecuteIO(ATARequest *request);
|
virtual status_t ExecuteIO(ATARequest *request);
|
||||||
|
|
||||||
virtual bool IsATAPI() { return true; };
|
virtual bool IsATAPI() { return true; };
|
||||||
|
|
||||||
|
virtual status_t Configure();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8 fLastLun;
|
status_t _FillTaskFilePacket(ATARequest *request);
|
||||||
|
|
||||||
|
bool fInterruptsForPacket;
|
||||||
|
uint8 fPacket[12];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user