From e3c8f43645777b4bdca9e1dfa4204e1fa46056cc Mon Sep 17 00:00:00 2001 From: Marcus Overhagen Date: Fri, 11 Jan 2008 01:10:00 +0000 Subject: [PATCH] implemented basic atapi support framework. improved device detection. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23373 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/kernel/bus_managers/ata/ata.c | 81 +++++++++++++++---- src/add-ons/kernel/bus_managers/ata/atapi.c | 19 +++++ .../kernel/bus_managers/ata/ide_internal.h | 1 + src/add-ons/kernel/bus_managers/ata/ide_sim.c | 5 +- .../kernel/bus_managers/ata/scsi2ata.c | 2 +- 5 files changed, 88 insertions(+), 20 deletions(-) diff --git a/src/add-ons/kernel/bus_managers/ata/ata.c b/src/add-ons/kernel/bus_managers/ata/ata.c index 676ab3cc7e..072193290d 100644 --- a/src/add-ons/kernel/bus_managers/ata/ata.c +++ b/src/add-ons/kernel/bus_managers/ata/ata.c @@ -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; diff --git a/src/add-ons/kernel/bus_managers/ata/atapi.c b/src/add-ons/kernel/bus_managers/ata/atapi.c index c963882f90..e92713a35d 100644 --- a/src/add-ons/kernel/bus_managers/ata/atapi.c +++ b/src/add-ons/kernel/bus_managers/ata/atapi.c @@ -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; diff --git a/src/add-ons/kernel/bus_managers/ata/ide_internal.h b/src/add-ons/kernel/bus_managers/ata/ide_internal.h index 8e3b49223b..87fc0d8aa6 100644 --- a/src/add-ons/kernel/bus_managers/ata/ide_internal.h +++ b/src/add-ons/kernel/bus_managers/ata/ide_internal.h @@ -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); diff --git a/src/add-ons/kernel/bus_managers/ata/ide_sim.c b/src/add-ons/kernel/bus_managers/ata/ide_sim.c index b24f27e727..e429c43264 100644 --- a/src/add-ons/kernel/bus_managers/ata/ide_sim.c +++ b/src/add-ons/kernel/bus_managers/ata/ide_sim.c @@ -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); diff --git a/src/add-ons/kernel/bus_managers/ata/scsi2ata.c b/src/add-ons/kernel/bus_managers/ata/scsi2ata.c index f3fcdd7e83..36131a34f0 100644 --- a/src/add-ons/kernel/bus_managers/ata/scsi2ata.c +++ b/src/add-ons/kernel/bus_managers/ata/scsi2ata.c @@ -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;