implemented basic atapi support framework.

improved device detection.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23373 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Marcus Overhagen
2008-01-11 01:10:00 +00:00
parent 1906acb2cd
commit e3c8f43645
5 changed files with 88 additions and 20 deletions
+65 -16
View File
@@ -22,26 +22,42 @@ void
ata_select_device(ide_bus_info *bus, int device)
{
ide_task_file tf;
// FLOW("ata_select_device device %d\n", device);
tf.chs.head = 0;
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)
TRACE("ata_select_device result: device %d not selected! head 0x%x, mode 0x%x, device %d\n", device, tf.chs.head, tf.chs.mode, tf.chs.device);
}
void
ata_select(ide_device_info *device)
{
// ata_select_device(device->bus, device->is_device1);
ASSERT(device->is_device1 == device->tf.chs.device);
device->bus->controller->write_command_block_regs(device->bus->channel_cookie, &device->tf, ide_mask_device_head);
ata_select_device(device->bus, device->is_device1);
}
/* Detect if the device is present
* This is unrelyable for some controllers and
* may report false posives.
*/
bool
ata_is_device_present(ide_bus_info *bus, int device)
{
@@ -51,10 +67,10 @@ ata_is_device_present(ide_bus_info *bus, int device)
tf.lba.sector_count = 0xaa;
tf.lba.lba_0_7 = 0x55;
bus->controller->write_command_block_regs(bus->channel_cookie, &tf,
ide_mask_sector_count | ide_mask_LBA_low);
spin(1); // wait 400 nsec
bus->controller->get_altstatus(bus->channel_cookie); // flush posted writes
spin(1);
bus->controller->read_command_block_regs(bus->channel_cookie, &tf,
ide_mask_sector_count | ide_mask_LBA_low);
@@ -74,9 +90,10 @@ ata_wait(ide_bus_info *bus, uint8 set, uint8 cleared,
bool check_err, bigtime_t timeout)
{
bigtime_t startTime = system_time();
bigtime_t elapsedTime;
bigtime_t elapsedTime = 0;
uint8 status;
bus->controller->get_altstatus(bus->channel_cookie); // flush posted writes
spin(1); // device needs 400ns to set status
for (;;) {
@@ -85,18 +102,20 @@ ata_wait(ide_bus_info *bus, uint8 set, uint8 cleared,
if (check_err && (status & ide_status_err) != 0)
return B_ERROR;
if ((status & set) == set && (status & cleared) == 0)
if ((status & set) == set && (status & cleared) == 0) {
dprintf("ata_wait: set %x, cleared %x, elapsed time %lld\n", set, cleared, elapsedTime);
return B_OK;
}
elapsedTime = system_time() - startTime;
if (elapsedTime > timeout)
return B_TIMED_OUT;
if (elapsedTime < 5000)
if (elapsedTime < 100000)
spin(1);
else
snooze(5000);
snooze(3000);
}
}
@@ -125,6 +144,14 @@ ata_wait_for_drdy(ide_bus_info *bus)
}
// wait 20ms for device to report idle (busy and drq clear)
status_t
ata_wait_idle(ide_bus_info *bus)
{
return ata_wait(bus, 0, ide_status_bsy | ide_status_drq, false, 20000);
}
// busy wait for device beeing ready,
// using the timeout set by the previous ata_send_command
status_t
@@ -163,7 +190,7 @@ ata_send_command(ide_device_info *device, ata_request *request, bool need_drdy,
ata_select(device);
if (ata_wait(bus, 0, ide_status_bsy | ide_status_drq, false, 50000) != B_OK) {
if (ata_wait_idle(bus) != B_OK) {
// resetting the device here will discard current configuration,
// it's better when the SCSI bus manager requests an external reset.
TRACE("device selection timeout\n");
@@ -181,7 +208,7 @@ ata_send_command(ide_device_info *device, ata_request *request, bool need_drdy,
if (bus->controller->write_command_block_regs(bus->channel_cookie, &device->tf, device->tf_param_mask) != B_OK)
goto err;
FLOW("Writing command 0x%02x", (int)device->tf.write.command);
FLOW("Writing command 0x%02x\n", (int)device->tf.write.command);
IDE_LOCK(bus);
@@ -215,6 +242,15 @@ err:
return B_ERROR;
}
status_t
ata_read_status(ide_device_info *device, uint8 *status)
{
status_t result = device->bus->controller->read_command_block_regs(device->bus->channel_cookie, &device->tf, ide_mask_status);
if (status)
*status = device->tf.read.status;
}
status_t
ata_finish_command(ide_device_info *device)
{
@@ -237,23 +273,28 @@ ata_reset_bus(ide_bus_info *bus, bool *_devicePresent0, uint32 *_sigDev0, bool *
devicePresent0 = ata_is_device_present(bus, 0);
devicePresent1 = ata_is_device_present(bus, 1);
dprintf("ATA: reset_bus: ata_is_device_present device 0, present %d\n", devicePresent0);
dprintf("ATA: reset_bus: ata_is_device_present device 1, present %d\n", devicePresent1);
dprintf("ATA: reset_bus: device 0: %s present\n", devicePresent0 ? "might be" : "is not");
dprintf("ATA: reset_bus: device 1: %s present\n", devicePresent1 ? "might be" : "is not");
// select device 0
ata_select_device(bus, 0);
// disable interrupts and assert SRST for at least 5 usec
if (controller->write_device_control(channel, ide_devctrl_bit3 | ide_devctrl_nien | ide_devctrl_srst) != B_OK)
goto error;
controller->get_altstatus(channel); // flush posted writes
spin(20);
// clear SRST and wait for at least 2 ms but (we wait 150ms like everyone else does)
if (controller->write_device_control(channel, ide_devctrl_bit3 | ide_devctrl_nien) != B_OK)
goto error;
controller->get_altstatus(channel); // flush posted writes
snooze(150000);
if (devicePresent0) {
ata_select_device(bus, 0);
dprintf("altstatus device 0: %x\n", controller->get_altstatus(channel));
// dprintf("altstatus device 0: %x\n", controller->get_altstatus(channel));
// wait up to 31 seconds for busy to clear, abort when error is set
status = ata_wait(bus, 0, ide_status_bsy, false, 31000000);
@@ -283,7 +324,7 @@ ata_reset_bus(ide_bus_info *bus, bool *_devicePresent0, uint32 *_sigDev0, bool *
if (devicePresent1) {
ata_select_device(bus, 1);
dprintf("altstatus device 1: %x\n", controller->get_altstatus(channel));
// dprintf("altstatus device 1: %x\n", controller->get_altstatus(channel));
// wait up to 31 seconds for busy to clear, abort when error is set
status = ata_wait(bus, 0, ide_status_bsy, false, 31000000);
@@ -1042,6 +1083,9 @@ ata_read_infoblock(ide_device_info *device, bool isAtapi)
goto error;
}
// clear pending interrupt
ata_read_status(device, NULL);
// XXX fix me
IDE_LOCK(bus);
bus->state = ata_state_busy;
@@ -1051,6 +1095,11 @@ ata_read_infoblock(ide_device_info *device, bool isAtapi)
return B_OK;
error:
// clear pending interrupt
ata_read_status(device, NULL);
// XXX fix me
IDE_LOCK(bus);
bus->state = ata_state_busy;
@@ -449,7 +449,26 @@ err_setup:
void
atapi_exec_io(ide_device_info *device, ata_request *request)
{
scsi_ccb *ccb = request->ccb;
TRACE("atapi_exec_io\n");
if (ccb->cdb[0] == SCSI_OP_REQUEST_SENSE) {
// No initial clear sense, as this request is used
// by the scsi stack to request the sense data of
// the previous command.
scsi_request_sense(device, request);
ata_request_finish(request, false /* no resubmit */);
return;
}
ata_request_clear_sense(request);
FLOW("command not implemented\n");
ata_request_set_sense(request, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE);
ata_request_finish(request, false /* no resubmit */);
/*
scsi_ccb *ccb = request->ccb;
@@ -271,6 +271,7 @@ status_t write_PIO_block(ata_request *request, int length);
struct scsi_sense;
void scsi_set_sense(struct scsi_sense *sense, const ata_request *request);
void scsi_request_sense(ide_device_info *device, ata_request *request);
@@ -122,9 +122,8 @@ sim_path_inquiry(ide_bus_info *bus, scsi_path_inquiry *info)
// there is no initiator for IDE, but SCSI needs it for scanning
info->initiator_id = 2;
// there's no controller limit, so set it higher then the maximum
// number of queued requests, which is 32 per device * 2 devices
info->hba_queue_size = 65;
// we only support 1 request at a time
info->hba_queue_size = 1;
strncpy(info->sim_vid, "Haiku", SCSI_SIM_ID);
@@ -398,7 +398,7 @@ scsi_read_capacity(ide_device_info *device, ata_request *request)
}
static void
void
scsi_request_sense(ide_device_info *device, ata_request *request)
{
scsi_ccb *ccb = request->ccb;