From 8c5cccce46dcef2f3505205372d8121ac6aba17c Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Mon, 20 Apr 2009 22:14:02 +0000 Subject: [PATCH] * Explicitly check device selection success. If device selection failed, assume there is no device. Should fix long reset timeouts when only device 1 is present and therefore device 0 can't be selected. * In case a device reset error is reported, don't try to identify/use the device. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30286 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/bus_managers/ata/ATAChannel.cpp | 40 ++++++++++++++++--- .../kernel/bus_managers/ata/ATAModule.cpp | 2 +- .../kernel/bus_managers/ata/ATAPrivate.h | 3 +- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/add-ons/kernel/bus_managers/ata/ATAChannel.cpp b/src/add-ons/kernel/bus_managers/ata/ATAChannel.cpp index 42384e2d5d..3df867c40d 100644 --- a/src/add-ons/kernel/bus_managers/ata/ATAChannel.cpp +++ b/src/add-ons/kernel/bus_managers/ata/ATAChannel.cpp @@ -122,14 +122,18 @@ ATAChannel::ScanBus() return B_OK; } + bool devicePresent[fDeviceCount]; uint32 deviceSignature[fDeviceCount]; - status_t result = Reset(deviceSignature); + status_t result = Reset(devicePresent, deviceSignature); if (result != B_OK) { TRACE_ERROR("resetting the channel failed\n"); return result; } for (uint8 i = 0; i < fDeviceCount; i++) { + if (!devicePresent[i]) + continue; + ATADevice *device = NULL; if (deviceSignature[i] == ATA_SIGNATURE_ATAPI) device = new(std::nothrow) ATAPIDevice(this, i); @@ -261,7 +265,7 @@ ATAChannel::SelectDevice(uint8 device) _WriteRegs(&taskFile, ATA_MASK_DEVICE_HEAD); _FlushAndWait(1); -#if KDEBUG > 0 +#if 0 // for debugging only _ReadRegs(&taskFile, ATA_MASK_DEVICE_HEAD); if (taskFile.chs.device != device) { @@ -275,8 +279,17 @@ ATAChannel::SelectDevice(uint8 device) } +uint8 +ATAChannel::SelectedDevice() +{ + ata_task_file taskFile; + _ReadRegs(&taskFile, ATA_MASK_DEVICE_HEAD); + return taskFile.lba.device; +} + + status_t -ATAChannel::Reset(uint32 *signatures) +ATAChannel::Reset(bool *presence, uint32 *signatures) { TRACE_FUNCTION("\n"); @@ -299,16 +312,26 @@ ATAChannel::Reset(uint32 *signatures) _FlushAndWait(150 * 1000); - for (uint8 i = 0; i < fDeviceCount; i++) { + if (presence != NULL) { + for (uint8 i = 0; i < fDeviceCount; i++) + presence[i] = false; + } + + uint8 deviceCount = fDeviceCount; + for (uint8 i = 0; i < deviceCount; i++) { SelectDevice(i); + if (SelectedDevice() != i) { + TRACE_ALWAYS("cannot select device %d, assuming not present\n", i); + continue; + } // ensure interrupts are disabled for this device _WriteControl(ATA_DEVICE_CONTROL_DISABLE_INTS); // wait up to 31 seconds for busy to clear if (Wait(0, ATA_STATUS_BUSY, 0, 31 * 1000 * 1000) != B_OK) { - TRACE_ERROR("reset timeout\n"); - return B_TIMED_OUT; + TRACE_ERROR("device %d reset timeout\n", i); + continue; } ata_task_file taskFile; @@ -322,13 +345,18 @@ ATAChannel::Reset(uint32 *signatures) && (i > 0 || taskFile.read.error != 0x81)) { TRACE_ERROR("device %d failed, error code is 0x%02x\n", i, taskFile.read.error); + continue; } if (i == 0 && taskFile.read.error >= 0x80) { TRACE_ERROR("device %d indicates that other device failed" " with code 0x%02x\n", i, taskFile.read.error); + deviceCount = 1; } + if (presence != NULL) + presence[i] = true; + if (signatures != NULL) { signatures[i] = taskFile.lba.sector_count | (((uint32)taskFile.lba.lba_0_7) << 8) diff --git a/src/add-ons/kernel/bus_managers/ata/ATAModule.cpp b/src/add-ons/kernel/bus_managers/ata/ATAModule.cpp index 9a1c40ca5f..c9ec6fd2b6 100644 --- a/src/add-ons/kernel/bus_managers/ata/ATAModule.cpp +++ b/src/add-ons/kernel/bus_managers/ata/ATAModule.cpp @@ -136,7 +136,7 @@ ata_sim_reset_bus(scsi_sim_cookie cookie) if (channel->Bus() == NULL) return SCSI_NO_HBA; - channel->Reset(NULL); + channel->Reset(NULL, NULL); return SCSI_REQ_CMP; } diff --git a/src/add-ons/kernel/bus_managers/ata/ATAPrivate.h b/src/add-ons/kernel/bus_managers/ata/ATAPrivate.h index f2b093f6ae..7d9be24eb0 100644 --- a/src/add-ons/kernel/bus_managers/ata/ATAPrivate.h +++ b/src/add-ons/kernel/bus_managers/ata/ATAPrivate.h @@ -77,8 +77,9 @@ public: // ATA stuff status_t SelectDevice(uint8 index); + uint8 SelectedDevice(); - status_t Reset(uint32 *signatures); + status_t Reset(bool *presence, uint32 *signatures); bool UseDMA() { return fUseDMA; };