From b44b755c910604e54153ae5580122df0d68f6576 Mon Sep 17 00:00:00 2001 From: Marcus Overhagen Date: Mon, 7 Jan 2008 19:29:15 +0000 Subject: [PATCH] modified device detection git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23281 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/kernel/bus_managers/ata/Jamfile | 2 +- src/add-ons/kernel/bus_managers/ata/ata.c | 49 ++++ src/add-ons/kernel/bus_managers/ata/atapi.c | 2 +- .../kernel/bus_managers/ata/basic_protocol.c | 217 ++++++++---------- src/add-ons/kernel/bus_managers/ata/devices.c | 25 +- .../kernel/bus_managers/ata/ide_internal.h | 19 +- src/add-ons/kernel/bus_managers/ata/ide_sim.c | 64 ++---- src/add-ons/kernel/bus_managers/ata/queuing.c | 3 +- src/add-ons/kernel/bus_managers/ata/sync.c | 2 +- 9 files changed, 204 insertions(+), 179 deletions(-) diff --git a/src/add-ons/kernel/bus_managers/ata/Jamfile b/src/add-ons/kernel/bus_managers/ata/Jamfile index 1cdbd592a2..c38c4fdb20 100644 --- a/src/add-ons/kernel/bus_managers/ata/Jamfile +++ b/src/add-ons/kernel/bus_managers/ata/Jamfile @@ -1,4 +1,4 @@ -SubDir HAIKU_TOP src add-ons kernel bus_managers ide ; +SubDir HAIKU_TOP src add-ons kernel bus_managers ata ; UsePrivateHeaders drivers kernel ; UsePrivateHeaders [ FDirName kernel arch $(TARGET_ARCH) ] ; diff --git a/src/add-ons/kernel/bus_managers/ata/ata.c b/src/add-ons/kernel/bus_managers/ata/ata.c index 46fe0c4f06..a957cf7272 100644 --- a/src/add-ons/kernel/bus_managers/ata/ata.c +++ b/src/add-ons/kernel/bus_managers/ata/ata.c @@ -15,6 +15,7 @@ #include "ide_sim.h" #include "ide_cmds.h" +#define TRACE dprintf /** verify that device is ready for further PIO transmission */ @@ -785,3 +786,51 @@ void enable_CQ(ide_device_info *device, bool enable) { } + + +status_t +ata_read_infoblock(ide_device_info *device, bool isAtapi) +{ + ide_bus_info *bus = device->bus; + int status; + + TRACE("ata_read_infoblock: device %p, isAtapi %d\n", device, isAtapi); + + // disable interrupts + bus->controller->write_device_control(bus->channel_cookie, ide_devctrl_bit3 | ide_devctrl_nien); + + device->tf_param_mask = 0; + device->tf.write.command = isAtapi ? IDE_CMD_IDENTIFY_PACKET_DEVICE : IDE_CMD_IDENTIFY_DEVICE; + + // initialize device selection flags, + // this is the only place where this bit gets initialized in the task file + if (bus->controller->read_command_block_regs(bus->channel_cookie, &device->tf, + ide_mask_device_head) != B_OK) { + TRACE("ata_read_infoblock: read_command_block_regs failed\n"); + return B_ERROR; + } + + device->tf.lba.device = device->is_device1; + + if (!send_command(device, NULL, isAtapi ? false : true, 20, ide_state_sync_waiting)) { + TRACE("ata_read_infoblock: send_command failed\n"); + return B_ERROR; + } + + if (ata_wait(bus, ide_status_drq, ide_status_bsy, true, 4000000) != B_OK) { + TRACE("ata_read_infoblock: wait failed\n"); + return B_ERROR; + } + + // get the infoblock + bus->controller->read_pio(bus->channel_cookie, (uint16 *)&device->infoblock, + sizeof(device->infoblock) / sizeof(uint16), false); + + if (!wait_for_drqdown(device)) { + TRACE("scan_device_int: wait_for_drqdown failed\n"); + return false; + } + + TRACE("ata_read_infoblock: success\n"); + return B_OK; +} diff --git a/src/add-ons/kernel/bus_managers/ata/atapi.c b/src/add-ons/kernel/bus_managers/ata/atapi.c index 6848363d29..935ab17daf 100644 --- a/src/add-ons/kernel/bus_managers/ata/atapi.c +++ b/src/add-ons/kernel/bus_managers/ata/atapi.c @@ -201,7 +201,7 @@ packet_dpc(ide_qrequest *qrequest) // TODO: the device will abort next command with a reset condition // perhaps we should hide that by reading sense? SHOW_FLOW0(3, "Reset"); - reset_device(device, qrequest); +// reset_device(device, qrequest); finish_checksense(qrequest); return; diff --git a/src/add-ons/kernel/bus_managers/ata/basic_protocol.c b/src/add-ons/kernel/bus_managers/ata/basic_protocol.c index 5a49725c69..61f97c1539 100644 --- a/src/add-ons/kernel/bus_managers/ata/basic_protocol.c +++ b/src/add-ons/kernel/bus_managers/ata/basic_protocol.c @@ -53,142 +53,83 @@ wait_for_drdy(ide_device_info *device) } -/** reset entire IDE bus - * all active request apart from are resubmitted - */ - -bool -reset_bus(ide_device_info *device, ide_qrequest *ignore) +status_t +reset_bus(ide_bus_info *bus, uint32 *sigDev0, uint32 *sigDev1) { - ide_bus_info *bus = device->bus; ide_controller_interface *controller = bus->controller; ide_channel_cookie channel = bus->channel_cookie; + ide_task_file tf; + status_t status; - dprintf("ide: reset_bus() device %p, bus %p\n", device, bus); + dprintf("ATA: reset_bus %p\n", bus); - FAST_LOG0(bus->log, ev_ide_reset_bus); + // 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; + spin(20); - if (device->reconnect_timer_installed) { - cancel_timer(&device->reconnect_timer.te); - device->reconnect_timer_installed = false; + // clear SRST for at least 2 ms + if (controller->write_device_control(channel, ide_devctrl_bit3 | ide_devctrl_nien) != B_OK) + goto error; + snooze(5000); + + // wait up to 30 seconds for busy to clear, abort when error is set + status = ata_wait(bus, 0, ide_status_bsy, true, 33000000); + if (status != B_OK) + goto error; + + tf.chs.head = 0; + tf.chs.mode = ide_mode_lba; + + // select device 0 + tf.chs.device = 0; + if (controller->write_command_block_regs(channel, &tf, ide_mask_device_head) != B_OK) + goto error; + status = ata_wait(bus, 0, ide_status_bsy | ide_status_drq, true, 50000); + if (status != B_OK) { + dprintf("ATA: reset_bus: device 0 not present\n"); + *sigDev0 = 0; + } else { + if (controller->read_command_block_regs(channel, &tf, ide_mask_sector_count | + ide_mask_LBA_low | ide_mask_LBA_mid | ide_mask_LBA_high) != B_OK) + goto error; + + *sigDev0 = tf.lba.sector_count; + *sigDev0 |= ((uint32)tf.lba.lba_0_7) << 8; + *sigDev0 |= ((uint32)tf.lba.lba_8_15) << 16; + *sigDev0 |= ((uint32)tf.lba.lba_16_23) << 24; } - if (device->other_device->reconnect_timer_installed) { - cancel_timer(&device->other_device->reconnect_timer.te); - device->other_device->reconnect_timer_installed = false; + // select device 1 + tf.chs.device = 1; + if (controller->write_command_block_regs(channel, &tf, ide_mask_device_head) != B_OK) + goto error; + status = ata_wait(bus, 0, ide_status_bsy | ide_status_drq, true, 50000); + if (status != B_OK) { + dprintf("ATA: reset_bus: device 1 not present\n"); + *sigDev1 = 0; + } else { + if (controller->read_command_block_regs(channel, &tf, ide_mask_sector_count | + ide_mask_LBA_low | ide_mask_LBA_mid | ide_mask_LBA_high) != B_OK) + goto error; + + *sigDev1 = tf.lba.sector_count; + *sigDev1 |= ((uint32)tf.lba.lba_0_7) << 8; + *sigDev1 |= ((uint32)tf.lba.lba_8_15) << 16; + *sigDev1 |= ((uint32)tf.lba.lba_16_23) << 24; } - // activate srst signal for 5 µs - // also, deactivate IRQ - // (as usual, we will get an IRQ on disabling, but as we leave them - // disabled for 2 ms, this false report is ignored) - if (controller->write_device_control(channel, - ide_devctrl_nien | ide_devctrl_srst | ide_devctrl_bit3) != B_OK) - goto err0; + dprintf("ATA: reset_bus success, device 0 signature: 0x%08lx, device 1 signature: 0x%08lx\n", *sigDev0, *sigDev1); - spin(5); + return B_OK; - if (controller->write_device_control(channel, ide_devctrl_nien | ide_devctrl_bit3) != B_OK) - goto err0; +error: - // let devices wake up - snooze(2000); - - // ouch, we have to wait up to 31 seconds! - if (!ide_wait(device, 0, ide_status_bsy, true, 31000000)) { - // as we don't know which of the devices is broken - // we leave them both alive - if (controller->write_device_control(channel, ide_devctrl_bit3) != B_OK) - goto err0; - - set_sense(device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_LUN_TIMEOUT); - goto err1; - } - - if (controller->write_device_control(channel, ide_devctrl_bit3) != B_OK) - goto err0; - - finish_all_requests(bus->devices[0], ignore, SCSI_SCSI_BUS_RESET, true); - finish_all_requests(bus->devices[1], ignore, SCSI_SCSI_BUS_RESET, true); - - dprintf("ide: reset_bus() device %p, bus %p success\n", device, bus); - return true; - -err0: - set_sense(device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_INTERNAL_FAILURE); - -err1: - finish_all_requests(bus->devices[0], ignore, SCSI_SCSI_BUS_RESET, true); - finish_all_requests(bus->devices[1], ignore, SCSI_SCSI_BUS_RESET, true); - - //xpt->call_async( bus->xpt_cookie, -1, -1, AC_BUS_RESET, NULL, 0 ); - - dprintf("ide: reset_bus() device %p, bus %p failed\n", device, bus); - return false; + dprintf("ATA: reset_bus failed\n"); + return B_ERROR; } -/** execute packet device reset. - * resets entire bus on fail or if device is not atapi; - * all requests but are resubmitted - */ - -bool -reset_device(ide_device_info *device, ide_qrequest *ignore) -{ - ide_bus_info *bus = device->bus; - status_t res; - uint8 orig_command; - - dprintf("ide: reset_device() device %p\n", device); - - FAST_LOG1(bus->log, ev_ide_reset_device, device->is_device1); - SHOW_FLOW0(3, ""); - - if (!device->is_atapi) - goto err; - - if (device->reconnect_timer_installed) { - cancel_timer(&device->reconnect_timer.te); - device->reconnect_timer_installed = false; - } - - // select device - if (bus->controller->write_command_block_regs(bus->channel_cookie, &device->tf, - ide_mask_device_head) != B_OK) - goto err; - - // safe original command to let caller restart it - orig_command = device->tf.write.command; - - // send device reset, independ of current device state - // (that's the point of a reset) - device->tf.write.command = IDE_CMD_DEVICE_RESET; - res = bus->controller->write_command_block_regs(bus->channel_cookie, - &device->tf, ide_mask_command); - device->tf.write.command = orig_command; - - if (res != B_OK) - goto err; - - // don't know how long to wait, but 31 seconds, like soft reset, - // should be enough - if (!ide_wait(device, 0, ide_status_bsy, true, 31000000)) - goto err; - - // alright, resubmit all requests - finish_all_requests(device, ignore, SCSI_SCSI_BUS_RESET, true); - - SHOW_FLOW0(3, "done"); - dprintf("ide: reset_device() device %p success\n", device); - return true; - -err: - // do the hard way - dprintf("ide: reset_device() device %p failed, calling reset_bus\n", device); - return reset_bus(device, ignore); -} - /** new_state must be either accessing, async_waiting or sync_waiting * param_mask must not include command register */ @@ -250,12 +191,13 @@ retry: return false; } +/* // reset device and retry if (reset_device(device, qrequest) && ++num_retries <= MAX_FAILED_SEND) { SHOW_FLOW0(1, "retrying"); goto retry; } - +*/ SHOW_FLOW0(1, "giving up"); // reset to often - abort request @@ -331,6 +273,39 @@ err: } +status_t +ata_wait(ide_bus_info *bus, uint8 mask, uint8 not_mask, + bool check_err, bigtime_t timeout) +{ + bigtime_t startTime = system_time(); + bigtime_t elapsedTime; + uint8 status; + + spin(1); // device needs 400ns to set status + + for (;;) { + + status = bus->controller->get_altstatus(bus->channel_cookie); + + if (check_err && (status & ide_status_err) != 0) + return B_ERROR; + + if ((status & mask) == mask && (status & not_mask) == 0) + return B_OK; + + elapsedTime = system_time() - startTime; + + if (elapsedTime > timeout) + return B_TIMED_OUT; + + if (elapsedTime < 5000) + spin(1); + else + snooze(5000); + } +} + + /** busy-wait for device * mask - bits of status register that must be set * not_mask - bits of status register that must not be set diff --git a/src/add-ons/kernel/bus_managers/ata/devices.c b/src/add-ons/kernel/bus_managers/ata/devices.c index c9464fc146..7b2a0d2927 100644 --- a/src/add-ons/kernel/bus_managers/ata/devices.c +++ b/src/add-ons/kernel/bus_managers/ata/devices.c @@ -49,7 +49,7 @@ cleanup_device_links(ide_device_info *device) /** destroy device info */ -static void +void destroy_device(ide_device_info *device) { TRACE("destroy_device: device %p\n", device); @@ -101,7 +101,7 @@ setup_device_links(ide_bus_info *bus, ide_device_info *device) /** create device info */ -static ide_device_info * +ide_device_info * create_device(ide_bus_info *bus, bool is_device1) { ide_device_info *device; @@ -185,7 +185,7 @@ prep_infoblock(ide_device_info *device) /** read info block of ATA or ATAPI device */ - +/* static bool scan_device_int(ide_device_info *device, bool atapi) { @@ -284,10 +284,24 @@ scan_device_int(ide_device_info *device, bool atapi) prep_infoblock(device); return true; } - +*/ /** scan one device */ +status_t +scan_device(ide_device_info *device, bool isAtapi) +{ + dprintf("ATA: scan_device\n"); + if (ata_read_infoblock(device, isAtapi) != B_OK) { + dprintf("ATA: couldn't read infoblock for device %p\n", device); + return B_ERROR; + } + + prep_infoblock(device); + return B_OK; +} + +/* void scan_device_worker(ide_bus_info *bus, void *arg) { @@ -321,12 +335,11 @@ scan_device_worker(ide_bus_info *bus, void *arg) goto err; bus->state = ide_state_idle; - release_sem(bus->scan_device_sem); return; err: destroy_device(device); bus->state = ide_state_idle; - release_sem(bus->scan_device_sem); } +*/ \ No newline at end of file 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 1dfb0b8454..6cfff32d5d 100644 --- a/src/add-ons/kernel/bus_managers/ata/ide_internal.h +++ b/src/add-ons/kernel/bus_managers/ata/ide_internal.h @@ -221,9 +221,6 @@ struct ide_bus_info { ide_device_info *devices[2]; ide_device_info *first_device; - ide_synced_pc scan_bus_syncinfo; // used to start bus scan - sem_id scan_device_sem; // released when device has been scanned - ide_synced_pc disconnect_syncinfo; // used to handle lost controller uchar path_id; @@ -331,6 +328,8 @@ void ata_dpc_PIO(ide_qrequest *qrequest); void ata_exec_io(ide_device_info *device, ide_qrequest *qrequest); +status_t ata_read_infoblock(ide_device_info *device, bool isAtapi); + // atapi.c @@ -343,6 +342,9 @@ void atapi_exec_io(ide_device_info *device, ide_qrequest *qrequest); // basic_prot.c +status_t ata_wait(ide_bus_info *bus, uint8 mask, uint8 not_mask, bool check_err, bigtime_t timeout); + + bool ide_wait(ide_device_info *device, int mask, int not_mask, bool check_err, bigtime_t timeout); bool wait_for_drq(ide_device_info *device); @@ -353,11 +355,13 @@ bool wait_for_drdy(ide_device_info *device); bool send_command(ide_device_info *device, ide_qrequest *qrequest, bool need_drdy, uint32 timeout, ide_bus_state new_state); bool device_start_service( ide_device_info *device, int *tag); -bool reset_device(ide_device_info *device, ide_qrequest *ignore); -bool reset_bus(ide_device_info *device, ide_qrequest *ignore); +//bool reset_device(ide_device_info *device, ide_qrequest *ignore); +//bool reset_bus(ide_device_info *device, ide_qrequest *ignore); bool check_service_req(ide_device_info *device); +status_t reset_bus(ide_bus_info *bus, uint32 *sigDev0, uint32 *sigDev1); + // channel_mgr.c @@ -366,7 +370,10 @@ extern ide_for_controller_interface ide_for_controller_module; // device_mgr.c -void scan_device_worker(ide_bus_info *bus, void *arg); +status_t scan_device(ide_device_info *device, bool isAtapi); +void destroy_device(ide_device_info *device); +ide_device_info *create_device(ide_bus_info *bus, bool is_device1); + // dma.c 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 55dee3956e..4095f96e66 100644 --- a/src/add-ons/kernel/bus_managers/ata/ide_sim.c +++ b/src/add-ons/kernel/bus_managers/ata/ide_sim.c @@ -79,20 +79,7 @@ static void set_check_condition(ide_qrequest *qrequest); static inline bool is_queuable(ide_device_info *device, scsi_ccb *request) { - int opcode = request->cdb[0]; - - // XXX disable queuing - if (!device->CQ_enabled) - return false; - - // make sure the caller allows queuing - if ((request->flags & SCSI_ORDERED_QTAG) != 0) - return false; - - // for atapi, all commands could be queued, but all - // atapi devices I know don't support queuing anyway - return opcode == SCSI_OP_READ_6 || opcode == SCSI_OP_WRITE_6 - || opcode == SCSI_OP_READ_10 || opcode == SCSI_OP_WRITE_10; + return false; } @@ -241,34 +228,38 @@ sim_path_inquiry(ide_bus_info *bus, scsi_path_inquiry *info) } -static void -scan_device(ide_bus_info *bus, int device) -{ - SHOW_FLOW0(4, ""); - - // currently, the SCSI bus manager doesn't block the - // bus when a bus or device scan is issued, so we - // have to use a SPC for that to be sure no one else - // is accessing the device or bus concurrently - schedule_synced_pc(bus, &bus->scan_bus_syncinfo, (void *)device); - - acquire_sem(bus->scan_device_sem); -} - - static uchar sim_scan_bus(ide_bus_info *bus) { + uint32 deviceSignature[2]; + ide_device_info *device; + status_t status; + bool isAtapi; int i; - SHOW_FLOW0(4, ""); + dprintf("ATA: sim_scan_bus: bus %p\n", bus); if (bus->disconnected) return SCSI_NO_HBA; +// IDE_LOCK(bus); + + status = reset_bus(bus, &deviceSignature[0], &deviceSignature[1]); + for (i = 0; i < bus->max_devices; ++i) { - scan_device(bus, i); + if (bus->devices[i]) + destroy_device(bus->devices[i]); + + if (status == B_OK && deviceSignature[i] != 0) { + isAtapi = deviceSignature[i] == 0xeb140101; + device = create_device(bus, i /* isDevice1 */); + if (scan_device(device, isAtapi) != B_OK) + destroy_device(device); + } } +// IDE_UNLOCK(bus); + + dprintf("ATA: sim_scan_bus: bus %p finished\n", bus); return SCSI_REQ_CMP; } @@ -581,7 +572,6 @@ ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie) } #endif - init_synced_pc(&bus->scan_bus_syncinfo, scan_device_worker); init_synced_pc(&bus->disconnect_syncinfo, disconnect_worker); bus->scsi_cookie = user_cookie; @@ -601,12 +591,6 @@ ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie) bus->devices[0] = bus->devices[1] = NULL; - bus->scan_device_sem = create_sem(0, "ide_scan_finished"); - if (bus->scan_device_sem < 0) { - status = bus->scan_device_sem; - goto err3; - } - status = INIT_BEN(&bus->status_report_ben, "ide_status_report"); if (status < B_OK) goto err4; @@ -675,13 +659,11 @@ ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie) err5: DELETE_BEN(&bus->status_report_ben); err4: - delete_sem(bus->scan_device_sem); err3: delete_sem(bus->sync_wait_sem); err2: scsi->free_dpc(bus->irq_dpc); err1: - uninit_synced_pc(&bus->scan_bus_syncinfo); uninit_synced_pc(&bus->disconnect_syncinfo); #ifdef USE_FAST_LOG fast_log->stop_log(bus->log); @@ -702,10 +684,8 @@ ide_sim_uninit_bus(ide_bus_info *bus) pnp->put_device_node(parent); DELETE_BEN(&bus->status_report_ben); - delete_sem(bus->scan_device_sem); delete_sem(bus->sync_wait_sem); scsi->free_dpc(bus->irq_dpc); - uninit_synced_pc(&bus->scan_bus_syncinfo); uninit_synced_pc(&bus->disconnect_syncinfo); // fast_log->stop_log(bus->log); diff --git a/src/add-ons/kernel/bus_managers/ata/queuing.c b/src/add-ons/kernel/bus_managers/ata/queuing.c index db8d8d9d1a..df519ddc42 100644 --- a/src/add-ons/kernel/bus_managers/ata/queuing.c +++ b/src/add-ons/kernel/bus_managers/ata/queuing.c @@ -370,5 +370,6 @@ send_abort_queue(ide_device_info *device) err: // ouch! device didn't react - we have to reset it - return reset_device(device, NULL); + //return reset_device(device, NULL); + return false; } diff --git a/src/add-ons/kernel/bus_managers/ata/sync.c b/src/add-ons/kernel/bus_managers/ata/sync.c index e86f0504ae..5e06dfc295 100644 --- a/src/add-ons/kernel/bus_managers/ata/sync.c +++ b/src/add-ons/kernel/bus_managers/ata/sync.c @@ -263,7 +263,7 @@ ide_timeout_dpc(void *arg) FAST_LOG1(bus->log, ev_ide_timeout_dpc, (uint32)qrequest); // this also resets overlapped commands - reset_device(device, qrequest); +// reset_device(device, qrequest); device->subsys_status = SCSI_CMD_TIMEOUT;