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
+75 -39
View File
@@ -18,6 +18,11 @@
#define TRACE dprintf #define TRACE dprintf
#define FLOW dprintf #define FLOW dprintf
static void ata_exec_dma_transfer(ata_request *request);
static void ata_exec_pio_transfer(ata_request *request);
void void
ata_select_device(ide_bus_info *bus, int device) 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.mode = ide_mode_lba;
tf.chs.device = device ? 1 : 0; 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->write_command_block_regs(bus->channel_cookie, &tf, ide_mask_device_head);
bus->controller->get_altstatus(bus->channel_cookie); // flush posted writes bus->controller->get_altstatus(bus->channel_cookie); // flush posted writes
spin(1); // wait 400 nsec 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 // for debugging only
bus->controller->read_command_block_regs(bus->channel_cookie, &tf, ide_mask_device_head); bus->controller->read_command_block_regs(bus->channel_cookie, &tf, ide_mask_device_head);
if (tf.chs.device != device) if (tf.chs.device != device)
@@ -756,7 +755,7 @@ err:
void void
ata_exec_read_write(ide_device_info *device, ata_request *request, 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; ide_bus_info *bus = device->bus;
ata_flags flags = 0; ata_flags flags = 0;
@@ -769,19 +768,18 @@ ata_exec_read_write(ide_device_info *device, ata_request *request,
if (request->uses_dma) { if (request->uses_dma) {
if (!prepare_dma(device, request)) { if (!prepare_dma(device, request)) {
// fall back to PIO on error // fall back to PIO on error
request->uses_dma = false; request->uses_dma = false;
} }
} }
if (!request->uses_dma) { if (!request->uses_dma) {
prep_PIO_transfer(device, request); prep_PIO_transfer(device, request);
device->left_blocks = length; device->left_blocks = sectorCount;
} }
// compose command // compose command
if (!create_rw_taskfile(device, request, pos, length, write)) if (!create_rw_taskfile(device, request, address, sectorCount, write))
goto err_setup; goto error;
// if no timeout is specified, use standard // if no timeout is specified, use standard
timeout = request->ccb->timeout > 0 ? request->ccb->timeout * 1000 : IDE_STD_TIMEOUT; 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) if (request->uses_dma)
flags |= ATA_DMA_TRANSFER; flags |= ATA_DMA_TRANSFER;
if (ata_send_command(device, request, flags, timeout) != B_OK) 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) { if (request->uses_dma) {
ata_exec_dma_transfer(request);
start_dma_wait_no_lock(device, request);
} else { } else {
// on PIO read, we start with waiting, on PIO write we can ata_exec_pio_transfer(request);
// transmit data immediately; we let the service thread do }
// the writing, so the caller can issue the next command return;
// immediately (this optimisation really pays on SMP systems
// only) error:
SHOW_FLOW0(3, "Ready for PIO"); if (request->uses_dma)
if (request->is_write) { abort_dma(device, request);
SHOW_FLOW0(3, "Scheduling write DPC"); ata_request_finish(request, false);
scsi->schedule_dpc(bus->scsi_cookie, bus->irq_dpc, ide_dpc, bus); }
}
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; return;
err_setup: error:
// error during setup TRACE("ata_exec_pio_transfer: error\n");
if (request->uses_dma) ata_request_set_status(request, SCSI_SEQUENCE_FAIL);
abort_dma(device, request); ata_request_finish(request, false /* resubmit */);
ata_request_finish(request, false);
return; 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); transfer_error:
ata_request_finish(request, false); 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; 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"); TRACE("ata_identify_device: wait failed\n");
return B_ERROR; return B_ERROR;
} }
@@ -139,7 +139,7 @@ ata_request_finish(ata_request *request, bool resubmit)
} }
IDE_LOCK(request->device->bus); 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->bus->active_device == request->device);
ASSERT(request->device->requestActive == request); ASSERT(request->device->requestActive == request);
ASSERT(request->device->requestFree == NULL); ASSERT(request->device->requestFree == NULL);
@@ -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_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); 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_DMA(ata_request *request);
void ata_dpc_PIO(ata_request *request); void ata_dpc_PIO(ata_request *request);
+5 -4
View File
@@ -43,6 +43,7 @@
#include <string.h> #include <string.h>
#define FLOW dprintf
// internal error code if scatter gather table is too short // internal error code if scatter gather table is too short
#define ERR_TOO_BIG (B_ERRORS_END + 1) #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; return B_ERROR;
} }
ASSERT((physicalAddress & 4097) == (virtualAddress & 4097));
// if chunks starts in the middle of a page, we have even less then // if chunks starts in the middle of a page, we have even less then
// a page left // a page left
page_left = B_PAGE_SIZE - physicalAddress % B_PAGE_SIZE; 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 */ /*! 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) transfer_PIO_block(ide_device_info *device, int length, bool write, int *transferred)
{ {
// data is usually split up into multiple scatter/gather blocks // 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 static void
write_discard_PIO(ide_device_info *device, int length) write_discard_PIO(ide_device_info *device, int length)
{ {
static const uint8 buffer[32] = {};
ide_bus_info *bus = device->bus; ide_bus_info *bus = device->bus;
uint8 buffer[32];
memset(buffer, 0, sizeof(buffer));
// we transmit 32 zero-bytes at once // we transmit 32 zero-bytes at once
// (not very efficient but easy to implement - you get what you deserve // (not very efficient but easy to implement - you get what you deserve