Serenity Operating System
at master 335 lines 13 kB view raw
1/* 2 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/ByteBuffer.h> 8#include <AK/Singleton.h> 9#include <AK/StringView.h> 10#include <Kernel/Arch/Delay.h> 11#include <Kernel/Bus/PCI/API.h> 12#include <Kernel/IOWindow.h> 13#include <Kernel/Memory/MemoryManager.h> 14#include <Kernel/Process.h> 15#include <Kernel/Sections.h> 16#include <Kernel/Storage/ATA/ATADiskDevice.h> 17#include <Kernel/Storage/ATA/Definitions.h> 18#include <Kernel/Storage/ATA/GenericIDE/Channel.h> 19#include <Kernel/Storage/ATA/GenericIDE/Controller.h> 20#include <Kernel/WorkQueue.h> 21 22namespace Kernel { 23 24#define PATA_PRIMARY_IRQ 14 25#define PATA_SECONDARY_IRQ 15 26 27UNMAP_AFTER_INIT NonnullLockRefPtr<IDEChannel> IDEChannel::create(IDEController const& controller, IOWindowGroup io_window_group, ChannelType type) 28{ 29 auto ata_identify_data_buffer = KBuffer::try_create_with_size("ATA Identify Page"sv, 4096, Memory::Region::Access::ReadWrite, AllocationStrategy::AllocateNow).release_value(); 30 return adopt_lock_ref(*new IDEChannel(controller, move(io_window_group), type, move(ata_identify_data_buffer))); 31} 32 33UNMAP_AFTER_INIT NonnullLockRefPtr<IDEChannel> IDEChannel::create(IDEController const& controller, u8 irq, IOWindowGroup io_window_group, ChannelType type) 34{ 35 auto ata_identify_data_buffer = KBuffer::try_create_with_size("ATA Identify Page"sv, 4096, Memory::Region::Access::ReadWrite, AllocationStrategy::AllocateNow).release_value(); 36 return adopt_lock_ref(*new IDEChannel(controller, irq, move(io_window_group), type, move(ata_identify_data_buffer))); 37} 38 39StringView IDEChannel::channel_type_string() const 40{ 41 if (m_channel_type == ChannelType::Primary) 42 return "Primary"sv; 43 return "Secondary"sv; 44} 45 46bool IDEChannel::select_device_and_wait_until_not_busy(DeviceType device_type, size_t milliseconds_timeout) 47{ 48 microseconds_delay(20); 49 u8 slave = device_type == DeviceType::Slave; 50 m_io_window_group.io_window().write8(ATA_REG_HDDEVSEL, 0xA0 | (slave << 4)); // First, we need to select the drive itself 51 microseconds_delay(20); 52 size_t time_elapsed = 0; 53 while (m_io_window_group.control_window().read8(0) & ATA_SR_BSY && time_elapsed <= milliseconds_timeout) { 54 microseconds_delay(1000); 55 time_elapsed++; 56 } 57 return time_elapsed <= milliseconds_timeout; 58} 59 60ErrorOr<void> IDEChannel::port_phy_reset() 61{ 62 MutexLocker locker(m_lock); 63 SpinlockLocker hard_locker(m_hard_lock); 64 // reset the channel 65 u8 device_control = m_io_window_group.control_window().read8(0); 66 // Wait 30 milliseconds 67 microseconds_delay(30000); 68 m_io_window_group.control_window().write8(0, device_control | (1 << 2)); 69 // Wait 30 milliseconds 70 microseconds_delay(30000); 71 m_io_window_group.control_window().write8(0, device_control); 72 // Wait up to 30 seconds before failing 73 if (!select_device_and_wait_until_not_busy(DeviceType::Master, 30000)) { 74 dbgln("IDEChannel: reset failed, busy flag on master stuck"); 75 return Error::from_errno(EBUSY); 76 } 77 // Wait up to 30 seconds before failing 78 if (!select_device_and_wait_until_not_busy(DeviceType::Slave, 30000)) { 79 dbgln("IDEChannel: reset failed, busy flag on slave stuck"); 80 return Error::from_errno(EBUSY); 81 } 82 return {}; 83} 84 85#if ARCH(X86_64) 86ErrorOr<void> IDEChannel::allocate_resources_for_pci_ide_controller(Badge<PCIIDELegacyModeController>, bool force_pio) 87{ 88 return allocate_resources(force_pio); 89} 90ErrorOr<void> IDEChannel::allocate_resources_for_isa_ide_controller(Badge<ISAIDEController>) 91{ 92 return allocate_resources(true); 93} 94#endif 95 96UNMAP_AFTER_INIT ErrorOr<void> IDEChannel::allocate_resources(bool force_pio) 97{ 98 dbgln_if(PATA_DEBUG, "IDEChannel: {} IO base: {}", channel_type_string(), m_io_window_group.io_window()); 99 dbgln_if(PATA_DEBUG, "IDEChannel: {} control base: {}", channel_type_string(), m_io_window_group.control_window()); 100 if (m_io_window_group.bus_master_window()) 101 dbgln_if(PATA_DEBUG, "IDEChannel: {} bus master base: {}", channel_type_string(), m_io_window_group.bus_master_window()); 102 else 103 dbgln_if(PATA_DEBUG, "IDEChannel: {} bus master base disabled", channel_type_string()); 104 105 if (!force_pio) { 106 m_dma_enabled = true; 107 VERIFY(m_io_window_group.bus_master_window()); 108 // Let's try to set up DMA transfers. 109 110 m_prdt_region = TRY(MM.allocate_dma_buffer_page("IDE PRDT"sv, Memory::Region::Access::ReadWrite, m_prdt_page)); 111 VERIFY(!m_prdt_page.is_null()); 112 m_dma_buffer_region = TRY(MM.allocate_dma_buffer_page("IDE DMA region"sv, Memory::Region::Access::ReadWrite, m_dma_buffer_page)); 113 VERIFY(!m_dma_buffer_page.is_null()); 114 115 prdt().end_of_table = 0x8000; 116 117 // clear bus master interrupt status 118 m_io_window_group.bus_master_window()->write8(2, m_io_window_group.bus_master_window()->read8(2) | 4); 119 } 120 return {}; 121} 122 123UNMAP_AFTER_INIT IDEChannel::IDEChannel(IDEController const& controller, u8 irq, IOWindowGroup io_group, ChannelType type, NonnullOwnPtr<KBuffer> ata_identify_data_buffer) 124 : ATAPort(controller, (type == ChannelType::Primary ? 0 : 1), move(ata_identify_data_buffer)) 125 , IRQHandler(irq) 126 , m_channel_type(type) 127 , m_io_window_group(move(io_group)) 128{ 129} 130 131UNMAP_AFTER_INIT IDEChannel::IDEChannel(IDEController const& controller, IOWindowGroup io_group, ChannelType type, NonnullOwnPtr<KBuffer> ata_identify_data_buffer) 132 : ATAPort(controller, (type == ChannelType::Primary ? 0 : 1), move(ata_identify_data_buffer)) 133 , IRQHandler(type == ChannelType::Primary ? PATA_PRIMARY_IRQ : PATA_SECONDARY_IRQ) 134 , m_channel_type(type) 135 , m_io_window_group(move(io_group)) 136{ 137} 138 139UNMAP_AFTER_INIT IDEChannel::~IDEChannel() = default; 140 141bool IDEChannel::handle_irq(RegisterState const&) 142{ 143 auto result = handle_interrupt_after_dma_transaction(); 144 // FIXME: Propagate errors properly 145 VERIFY(!result.is_error()); 146 return result.release_value(); 147} 148 149ErrorOr<void> IDEChannel::stop_busmastering() 150{ 151 VERIFY(m_lock.is_locked()); 152 VERIFY(m_io_window_group.bus_master_window()); 153 m_io_window_group.bus_master_window()->write8(0, 0); 154 return {}; 155} 156ErrorOr<void> IDEChannel::start_busmastering(TransactionDirection direction) 157{ 158 VERIFY(m_lock.is_locked()); 159 VERIFY(m_io_window_group.bus_master_window()); 160 m_io_window_group.bus_master_window()->write8(0, (direction != TransactionDirection::Write ? 0x9 : 0x1)); 161 return {}; 162} 163ErrorOr<void> IDEChannel::force_busmastering_status_clean() 164{ 165 VERIFY(m_lock.is_locked()); 166 VERIFY(m_io_window_group.bus_master_window()); 167 m_io_window_group.bus_master_window()->write8(2, m_io_window_group.bus_master_window()->read8(2) | 4); 168 return {}; 169} 170ErrorOr<u8> IDEChannel::busmastering_status() 171{ 172 VERIFY(m_io_window_group.bus_master_window()); 173 return m_io_window_group.bus_master_window()->read8(2); 174} 175ErrorOr<void> IDEChannel::prepare_transaction_with_busmastering(TransactionDirection direction, PhysicalAddress prdt_buffer) 176{ 177 VERIFY(m_lock.is_locked()); 178 m_io_window_group.bus_master_window()->write32(4, prdt_buffer.get()); 179 m_io_window_group.bus_master_window()->write8(0, direction != TransactionDirection::Write ? 0x8 : 0); 180 181 // Turn on "Interrupt" and "Error" flag. The error flag should be cleared by hardware. 182 m_io_window_group.bus_master_window()->write8(2, m_io_window_group.bus_master_window()->read8(2) | 0x6); 183 return {}; 184} 185ErrorOr<void> IDEChannel::initiate_transaction(TransactionDirection) 186{ 187 VERIFY(m_lock.is_locked()); 188 return {}; 189} 190 191ErrorOr<u8> IDEChannel::task_file_status() 192{ 193 VERIFY(m_lock.is_locked()); 194 return m_io_window_group.control_window().read8(0); 195} 196 197ErrorOr<u8> IDEChannel::task_file_error() 198{ 199 VERIFY(m_lock.is_locked()); 200 return m_io_window_group.io_window().read8(ATA_REG_ERROR); 201} 202 203ErrorOr<bool> IDEChannel::detect_presence_on_selected_device() 204{ 205 VERIFY(m_lock.is_locked()); 206 m_io_window_group.io_window().write8(ATA_REG_SECCOUNT0, 0x55); 207 m_io_window_group.io_window().write8(ATA_REG_LBA0, 0xAA); 208 209 m_io_window_group.io_window().write8(ATA_REG_SECCOUNT0, 0xAA); 210 m_io_window_group.io_window().write8(ATA_REG_LBA0, 0x55); 211 212 m_io_window_group.io_window().write8(ATA_REG_SECCOUNT0, 0x55); 213 m_io_window_group.io_window().write8(ATA_REG_LBA0, 0xAA); 214 215 auto nsectors_value = m_io_window_group.io_window().read8(ATA_REG_SECCOUNT0); 216 auto lba0 = m_io_window_group.io_window().read8(ATA_REG_LBA0); 217 218 if (lba0 == 0xAA && nsectors_value == 0x55) 219 return true; 220 return false; 221} 222 223ErrorOr<void> IDEChannel::wait_if_busy_until_timeout(size_t timeout_in_milliseconds) 224{ 225 size_t time_elapsed = 0; 226 while (m_io_window_group.control_window().read8(0) & ATA_SR_BSY && time_elapsed <= timeout_in_milliseconds) { 227 microseconds_delay(1000); 228 time_elapsed++; 229 } 230 if (time_elapsed <= timeout_in_milliseconds) 231 return {}; 232 return Error::from_errno(EBUSY); 233} 234 235ErrorOr<void> IDEChannel::force_clear_interrupts() 236{ 237 VERIFY(m_lock.is_locked()); 238 m_io_window_group.io_window().read8(ATA_REG_STATUS); 239 return {}; 240} 241 242ErrorOr<void> IDEChannel::load_taskfile_into_registers(ATAPort::TaskFile const& task_file, LBAMode lba_mode, size_t completion_timeout_in_milliseconds) 243{ 244 VERIFY(m_lock.is_locked()); 245 VERIFY(m_hard_lock.is_locked()); 246 u8 head = 0; 247 if (lba_mode == LBAMode::FortyEightBit) { 248 head = 0; 249 } else if (lba_mode == LBAMode::TwentyEightBit) { 250 head = (task_file.lba_high[0] & 0x0F); 251 } 252 253 // Note: Preserve the selected drive, always use LBA addressing 254 auto driver_register = ((m_io_window_group.io_window().read8(ATA_REG_HDDEVSEL) & (1 << 4)) | (head | (1 << 5) | (1 << 6))); 255 m_io_window_group.io_window().write8(ATA_REG_HDDEVSEL, driver_register); 256 microseconds_delay(50); 257 258 if (lba_mode == LBAMode::FortyEightBit) { 259 m_io_window_group.io_window().write8(ATA_REG_SECCOUNT1, (task_file.count >> 8) & 0xFF); 260 m_io_window_group.io_window().write8(ATA_REG_LBA3, task_file.lba_high[0]); 261 m_io_window_group.io_window().write8(ATA_REG_LBA4, task_file.lba_high[1]); 262 m_io_window_group.io_window().write8(ATA_REG_LBA5, task_file.lba_high[2]); 263 } 264 265 m_io_window_group.io_window().write8(ATA_REG_SECCOUNT0, task_file.count & 0xFF); 266 m_io_window_group.io_window().write8(ATA_REG_LBA0, task_file.lba_low[0]); 267 m_io_window_group.io_window().write8(ATA_REG_LBA1, task_file.lba_low[1]); 268 m_io_window_group.io_window().write8(ATA_REG_LBA2, task_file.lba_low[2]); 269 270 // FIXME: Set a timeout here? 271 size_t time_elapsed = 0; 272 for (;;) { 273 if (time_elapsed > completion_timeout_in_milliseconds) 274 return Error::from_errno(EBUSY); 275 // FIXME: Use task_file_status method 276 auto status = m_io_window_group.control_window().read8(0); 277 if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) 278 break; 279 microseconds_delay(1000); 280 time_elapsed++; 281 } 282 m_io_window_group.io_window().write8(ATA_REG_COMMAND, task_file.command); 283 return {}; 284} 285 286ErrorOr<void> IDEChannel::device_select(size_t device_index) 287{ 288 VERIFY(m_lock.is_locked()); 289 if (device_index > 1) 290 return Error::from_errno(EINVAL); 291 microseconds_delay(20); 292 m_io_window_group.io_window().write8(ATA_REG_HDDEVSEL, (0xA0 | ((device_index) << 4))); 293 microseconds_delay(20); 294 return {}; 295} 296 297ErrorOr<void> IDEChannel::enable_interrupts() 298{ 299 VERIFY(m_lock.is_locked()); 300 m_io_window_group.control_window().write8(0, 0); 301 m_interrupts_enabled = true; 302 return {}; 303} 304ErrorOr<void> IDEChannel::disable_interrupts() 305{ 306 VERIFY(m_lock.is_locked()); 307 m_io_window_group.control_window().write8(0, 1 << 1); 308 m_interrupts_enabled = false; 309 return {}; 310} 311 312ErrorOr<void> IDEChannel::read_pio_data_to_buffer(UserOrKernelBuffer& buffer, size_t block_offset, size_t words_count) 313{ 314 VERIFY(m_lock.is_locked()); 315 VERIFY(words_count == 256); 316 for (u32 i = 0; i < 256; ++i) { 317 u16 data = m_io_window_group.io_window().read16(ATA_REG_DATA); 318 // FIXME: Don't assume 512 bytes sector 319 TRY(buffer.write(&data, block_offset * 512 + (i * 2), 2)); 320 } 321 return {}; 322} 323ErrorOr<void> IDEChannel::write_pio_data_from_buffer(UserOrKernelBuffer const& buffer, size_t block_offset, size_t words_count) 324{ 325 VERIFY(m_lock.is_locked()); 326 VERIFY(words_count == 256); 327 for (u32 i = 0; i < 256; ++i) { 328 u16 buf; 329 // FIXME: Don't assume 512 bytes sector 330 TRY(buffer.read(&buf, block_offset * 512 + (i * 2), 2)); 331 m_io_window_group.io_window().write16(ATA_REG_DATA, buf); 332 } 333 return {}; 334} 335}