Implemented PIO transfers again. Haiku starts in vmware now with this stack.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23425 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Marcus Overhagen 2008-01-11 23:13:27 +00:00
parent 5d196712c9
commit f03e236672
4 changed files with 82 additions and 45 deletions

View File

@ -18,6 +18,11 @@
#define TRACE dprintf
#define FLOW dprintf
static void ata_exec_dma_transfer(ata_request *request);
static void ata_exec_pio_transfer(ata_request *request);
void
ata_select_device(ide_bus_info *bus, int device)
{
@ -29,16 +34,10 @@ ata_select_device(ide_bus_info *bus, int device)
tf.chs.mode = ide_mode_lba;
tf.chs.device = device ? 1 : 0;
// if (ata_wait_idle(bus) != B_OK)
// FLOW("ata_select_device step 1 bus not idle\n");
bus->controller->write_command_block_regs(bus->channel_cookie, &tf, ide_mask_device_head);
bus->controller->get_altstatus(bus->channel_cookie); // flush posted writes
spin(1); // wait 400 nsec
// if (ata_wait_idle(bus) != B_OK)
// FLOW("ata_select_device step 2 bus not idle\n");
// for debugging only
bus->controller->read_command_block_regs(bus->channel_cookie, &tf, ide_mask_device_head);
if (tf.chs.device != device)
@ -756,7 +755,7 @@ err:
void
ata_exec_read_write(ide_device_info *device, ata_request *request,
uint64 pos, size_t length, bool write)
uint64 address, size_t sectorCount, bool write)
{
ide_bus_info *bus = device->bus;
ata_flags flags = 0;
@ -769,19 +768,18 @@ ata_exec_read_write(ide_device_info *device, ata_request *request,
if (request->uses_dma) {
if (!prepare_dma(device, request)) {
// fall back to PIO on error
request->uses_dma = false;
}
}
if (!request->uses_dma) {
prep_PIO_transfer(device, request);
device->left_blocks = length;
device->left_blocks = sectorCount;
}
// compose command
if (!create_rw_taskfile(device, request, pos, length, write))
goto err_setup;
if (!create_rw_taskfile(device, request, address, sectorCount, write))
goto error;
// if no timeout is specified, use standard
timeout = request->ccb->timeout > 0 ? request->ccb->timeout * 1000 : IDE_STD_TIMEOUT;
@ -791,42 +789,80 @@ ata_exec_read_write(ide_device_info *device, ata_request *request,
if (request->uses_dma)
flags |= ATA_DMA_TRANSFER;
if (ata_send_command(device, request, flags, timeout) != B_OK)
goto err_send;
goto error;
// this could be executed in a DPC to improve performance
if (request->uses_dma) {
start_dma_wait_no_lock(device, request);
ata_exec_dma_transfer(request);
} else {
// on PIO read, we start with waiting, on PIO write we can
// transmit data immediately; we let the service thread do
// the writing, so the caller can issue the next command
// immediately (this optimisation really pays on SMP systems
// only)
SHOW_FLOW0(3, "Ready for PIO");
if (request->is_write) {
SHOW_FLOW0(3, "Scheduling write DPC");
scsi->schedule_dpc(bus->scsi_cookie, bus->irq_dpc, ide_dpc, bus);
}
ata_exec_pio_transfer(request);
}
return;
error:
if (request->uses_dma)
abort_dma(device, request);
ata_request_finish(request, false);
}
static void
ata_exec_dma_transfer(ata_request *request)
{
ASSERT(0);
}
static void
ata_exec_pio_transfer(ata_request *request)
{
ide_device_info *device = request->device;
ide_bus_info *bus = device->bus;
uint32 timeout = request->ccb->timeout > 0 ?
request->ccb->timeout * 1000 : IDE_STD_TIMEOUT;
// FLOW("ata_exec_pio_transfer\n");
FLOW("ata_exec_pio_transfer: length %d, left_sg_elem %d, cur_sg_elem %d, cur_sg_ofs %d\n",
request->ccb->data_length, device->left_sg_elem, device->cur_sg_elem, device->cur_sg_ofs);
if (ata_wait(bus, ide_status_drq, ide_status_bsy, 0, 4000000) != B_OK) {
TRACE("ata_exec_pio_transfer: wait failed\n");
goto error;
}
while (device->left_blocks > 0) {
if (request->is_write) {
FLOW("writing 1 block\n");
if (write_PIO_block(request, 512) != B_OK)
goto transfer_error;
} else {
FLOW("reading 1 block\n");
if (read_PIO_block(request, 512) != B_OK)
goto transfer_error;
}
device->left_blocks--;
FLOW("%d blocks left\n", device->left_blocks);
}
if (ata_wait_for_drqdown(bus) != B_OK) {
TRACE("ata_exec_pio_transfer: ata_wait_for_drqdown failed\n");
goto error;
}
ata_finish_command(device, &request, ATA_WAIT_FINISH | ATA_DRDY_REQUIRED, ide_error_abrt);
ata_request_finish(request, false /* resubmit */);
return;
err_setup:
// error during setup
if (request->uses_dma)
abort_dma(device, request);
ata_request_finish(request, false);
error:
TRACE("ata_exec_pio_transfer: error\n");
ata_request_set_status(request, SCSI_SEQUENCE_FAIL);
ata_request_finish(request, false /* resubmit */);
return;
err_send:
// error during/after send;
// in this case, the device discards queued ccb automatically
if (request->uses_dma)
abort_dma(device, request);
// finish_reset_queue(request);
ata_request_finish(request, false);
transfer_error:
TRACE("ata_exec_pio_transfer: transfer error\n");
ata_request_set_status(request, SCSI_SEQUENCE_FAIL);
ata_request_finish(request, false /* resubmit */);
}
@ -1079,7 +1115,7 @@ ata_identify_device(ide_device_info *device, bool isAtapi)
return B_ERROR;
}
if (ata_wait(bus, ide_status_drq, ide_status_bsy, ATA_CHECK_ERROR_BIT, 4000000) != B_OK) {
if (ata_wait(bus, ide_status_drq, ide_status_bsy, 0, 4000000) != B_OK) {
TRACE("ata_identify_device: wait failed\n");
return B_ERROR;
}

View File

@ -139,7 +139,7 @@ ata_request_finish(ata_request *request, bool resubmit)
}
IDE_LOCK(request->device->bus);
ASSERT(request->device->bus->state == ata_state_busy);
ASSERT(request->device->bus->state != ata_state_idle);
ASSERT(request->device->bus->active_device == request->device);
ASSERT(request->device->requestActive == request);
ASSERT(request->device->requestFree == NULL);

View File

@ -208,7 +208,7 @@ status_t ata_finish_command(ide_device_info *device, ata_request *request, ata_f
bool check_rw_error(ide_device_info *device, ata_request *request);
bool check_output(ide_device_info *device, bool drdy_required, int error_mask, bool is_write);
void ata_exec_read_write(ide_device_info *device, ata_request *request, uint64 pos, size_t length, bool write);
void ata_exec_read_write(ide_device_info *device, ata_request *request, uint64 address, size_t sectorCount, bool write);
void ata_dpc_DMA(ata_request *request);
void ata_dpc_PIO(ata_request *request);

View File

@ -43,6 +43,7 @@
#include <string.h>
#define FLOW dprintf
// internal error code if scatter gather table is too short
#define ERR_TOO_BIG (B_ERRORS_END + 1)
@ -157,6 +158,8 @@ transfer_PIO_physcont(ide_device_info *device, addr_t physicalAddress,
return B_ERROR;
}
ASSERT((physicalAddress & 4097) == (virtualAddress & 4097));
// if chunks starts in the middle of a page, we have even less then
// a page left
page_left = B_PAGE_SIZE - physicalAddress % B_PAGE_SIZE;
@ -184,7 +187,7 @@ transfer_PIO_physcont(ide_device_info *device, addr_t physicalAddress,
/*! Transfer PIO block from/to buffer */
static inline int
static inline status_t
transfer_PIO_block(ide_device_info *device, int length, bool write, int *transferred)
{
// data is usually split up into multiple scatter/gather blocks
@ -230,10 +233,8 @@ transfer_PIO_block(ide_device_info *device, int length, bool write, int *transfe
static void
write_discard_PIO(ide_device_info *device, int length)
{
static const uint8 buffer[32] = {};
ide_bus_info *bus = device->bus;
uint8 buffer[32];
memset(buffer, 0, sizeof(buffer));
// we transmit 32 zero-bytes at once
// (not very efficient but easy to implement - you get what you deserve