Serenity Operating System
at master 520 lines 20 kB view raw
1/* 2 * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <Kernel/Arch/CPU.h> 8#include <Kernel/Arch/Delay.h> 9#include <Kernel/Storage/ATA/ATADiskDevice.h> 10#include <Kernel/Storage/ATA/ATAPort.h> 11#include <Kernel/Storage/ATA/Definitions.h> 12#include <Kernel/WorkQueue.h> 13 14namespace Kernel { 15 16class ATAPortInterruptDisabler { 17public: 18 ATAPortInterruptDisabler(ATAPort& port) 19 : m_port(port) 20 { 21 (void)port.disable_interrupts(); 22 } 23 24 ~ATAPortInterruptDisabler() 25 { 26 (void)m_port->enable_interrupts(); 27 }; 28 29private: 30 LockRefPtr<ATAPort> m_port; 31}; 32 33class ATAPortInterruptCleaner { 34public: 35 ATAPortInterruptCleaner(ATAPort& port) 36 : m_port(port) 37 { 38 } 39 40 ~ATAPortInterruptCleaner() 41 { 42 (void)m_port->force_clear_interrupts(); 43 }; 44 45private: 46 LockRefPtr<ATAPort> m_port; 47}; 48 49void ATAPort::fix_name_string_in_identify_device_block() 50{ 51 VERIFY(m_lock.is_locked()); 52 auto* wbuf = (u16*)m_ata_identify_data_buffer->data(); 53 auto* bbuf = m_ata_identify_data_buffer->data() + 27 * 2; 54 for (size_t word_index = 27; word_index < 47; word_index++) { 55 u16 data = wbuf[word_index]; 56 *(bbuf++) = MSB(data); 57 *(bbuf++) = LSB(data); 58 } 59} 60 61ErrorOr<void> ATAPort::detect_connected_devices() 62{ 63 MutexLocker locker(m_lock); 64 for (size_t device_index = 0; device_index < max_possible_devices_connected(); device_index++) { 65 TRY(device_select(device_index)); 66 auto device_presence = TRY(detect_presence_on_selected_device()); 67 if (!device_presence) 68 continue; 69 70 TaskFile identify_taskfile; 71 memset(&identify_taskfile, 0, sizeof(TaskFile)); 72 identify_taskfile.command = ATA_CMD_IDENTIFY; 73 auto buffer = UserOrKernelBuffer::for_kernel_buffer(m_ata_identify_data_buffer->data()); 74 { 75 auto result = execute_polled_command(TransactionDirection::Read, LBAMode::None, identify_taskfile, buffer, 0, 256, 100, 100); 76 if (result.is_error()) { 77 continue; 78 } 79 } 80 ATAIdentifyBlock volatile& identify_block = (ATAIdentifyBlock volatile&)(*m_ata_identify_data_buffer->data()); 81 u16 capabilities = identify_block.capabilities[0]; 82 83 StringView device_name = StringView((char const*)const_cast<u16*>(identify_block.model_number), 40); 84 fix_name_string_in_identify_device_block(); 85 86 u64 max_addressable_block = identify_block.max_28_bit_addressable_logical_sector; 87 dbgln("ATAPort: device found: Name={}, Capacity={}, Capabilities={:#04x}", device_name.trim_whitespace(), max_addressable_block * 512, capabilities); 88 // If the drive is so old that it doesn't support LBA, ignore it. 89 if (!(capabilities & ATA_CAP_LBA)) { 90 dbgln("ATAPort: device found but without LBA support (what kind of dinosaur we see here?)"); 91 continue; 92 } 93 // if we support 48-bit LBA, use that value instead. 94 if (identify_block.commands_and_feature_sets_supported[1] & (1 << 10)) 95 max_addressable_block = identify_block.user_addressable_logical_sectors_count; 96 // FIXME: Don't assume all drives will have logical sector size of 512 bytes. 97 ATADevice::Address address = { m_port_index, static_cast<u8>(device_index) }; 98 m_ata_devices.append(ATADiskDevice::create(m_parent_ata_controller, address, capabilities, 512, max_addressable_block)); 99 } 100 return {}; 101} 102 103LockRefPtr<StorageDevice> ATAPort::connected_device(size_t device_index) const 104{ 105 MutexLocker locker(m_lock); 106 if (m_ata_devices.size() > device_index) 107 return m_ata_devices[device_index]; 108 return {}; 109} 110 111ErrorOr<void> ATAPort::start_request(ATADevice const& associated_device, AsyncBlockDeviceRequest& request) 112{ 113 MutexLocker locker(m_lock); 114 VERIFY(m_current_request.is_null()); 115 VERIFY(pio_capable() || dma_capable()); 116 117 dbgln_if(ATA_DEBUG, "ATAPort::start_request"); 118 119 m_current_request = request; 120 m_current_request_block_index = 0; 121 m_current_request_flushing_cache = false; 122 123 if (dma_capable()) { 124 TRY(prepare_and_initiate_dma_transaction(associated_device)); 125 return {}; 126 } 127 TRY(prepare_and_initiate_pio_transaction(associated_device)); 128 return {}; 129} 130 131void ATAPort::complete_pio_transaction(AsyncDeviceRequest::RequestResult result) 132{ 133 VERIFY(m_current_request); 134 135 // Now schedule reading back the buffer as soon as we leave the irq handler. 136 // This is important so that we can safely write the buffer back, 137 // which could cause page faults. Note that this may be called immediately 138 // before Processor::deferred_call_queue returns! 139 auto work_item_creation_result = g_io_work->try_queue([this, result]() { 140 dbgln_if(ATA_DEBUG, "ATAPort::complete_pio_transaction result: {}", (int)result); 141 MutexLocker locker(m_lock); 142 VERIFY(m_current_request); 143 auto current_request = m_current_request; 144 m_current_request.clear(); 145 current_request->complete(result); 146 }); 147 if (work_item_creation_result.is_error()) { 148 auto current_request = m_current_request; 149 m_current_request.clear(); 150 current_request->complete(AsyncDeviceRequest::OutOfMemory); 151 } 152} 153 154void ATAPort::complete_dma_transaction(AsyncDeviceRequest::RequestResult result) 155{ 156 // NOTE: this may be called from the interrupt handler! 157 VERIFY(m_current_request); 158 VERIFY(m_lock.is_locked()); 159 160 // Now schedule reading back the buffer as soon as we leave the irq handler. 161 // This is important so that we can safely write the buffer back, 162 // which could cause page faults. Note that this may be called immediately 163 // before Processor::deferred_call_queue returns! 164 auto work_item_creation_result = g_io_work->try_queue([this, result]() { 165 dbgln_if(ATA_DEBUG, "ATAPort::complete_dma_transaction result: {}", (int)result); 166 MutexLocker locker(m_lock); 167 if (!m_current_request) 168 return; 169 auto current_request = m_current_request; 170 m_current_request.clear(); 171 172 if (result == AsyncDeviceRequest::Success) { 173 { 174 auto result = force_busmastering_status_clean(); 175 if (result.is_error()) { 176 locker.unlock(); 177 current_request->complete(AsyncDeviceRequest::Failure); 178 return; 179 } 180 } 181 182 if (current_request->request_type() == AsyncBlockDeviceRequest::Read) { 183 if (auto result = current_request->write_to_buffer(current_request->buffer(), m_dma_buffer_region->vaddr().as_ptr(), 512 * current_request->block_count()); result.is_error()) { 184 locker.unlock(); 185 current_request->complete(AsyncDeviceRequest::MemoryFault); 186 return; 187 } 188 } 189 } 190 locker.unlock(); 191 current_request->complete(result); 192 }); 193 if (work_item_creation_result.is_error()) { 194 auto current_request = m_current_request; 195 m_current_request.clear(); 196 current_request->complete(AsyncDeviceRequest::OutOfMemory); 197 } 198} 199 200static void print_ata_status(u8 status) 201{ 202 dbgln("ATAPort: print_status: DRQ={} BSY={}, DRDY={}, DSC={}, DF={}, CORR={}, IDX={}, ERR={}", 203 (status & ATA_SR_DRQ) != 0, 204 (status & ATA_SR_BSY) != 0, 205 (status & ATA_SR_DRDY) != 0, 206 (status & ATA_SR_DSC) != 0, 207 (status & ATA_SR_DF) != 0, 208 (status & ATA_SR_CORR) != 0, 209 (status & ATA_SR_IDX) != 0, 210 (status & ATA_SR_ERR) != 0); 211} 212 213static void try_disambiguate_ata_error(u8 error) 214{ 215 dbgln("ATAPort: Error cause:"); 216 217 switch (error) { 218 case ATA_ER_BBK: 219 dbgln("ATAPort: - Bad block"); 220 break; 221 case ATA_ER_UNC: 222 dbgln("ATAPort: - Uncorrectable data"); 223 break; 224 case ATA_ER_MC: 225 dbgln("ATAPort: - Media changed"); 226 break; 227 case ATA_ER_IDNF: 228 dbgln("ATAPort: - ID mark not found"); 229 break; 230 case ATA_ER_MCR: 231 dbgln("ATAPort: - Media change request"); 232 break; 233 case ATA_ER_ABRT: 234 dbgln("ATAPort: - Command aborted"); 235 break; 236 case ATA_ER_TK0NF: 237 dbgln("ATAPort: - Track 0 not found"); 238 break; 239 case ATA_ER_AMNF: 240 dbgln("ATAPort: - No address mark"); 241 break; 242 default: 243 dbgln("ATAPort: - No one knows"); 244 break; 245 } 246} 247 248ErrorOr<bool> ATAPort::handle_interrupt_after_dma_transaction() 249{ 250 if (!dma_capable()) 251 return false; 252 u8 bstatus = TRY(busmastering_status()); 253 if (!(bstatus & 0x4)) { 254 // interrupt not from this device, ignore 255 dbgln_if(ATA_DEBUG, "ATAPort: ignore interrupt"); 256 return false; 257 } 258 auto work_item_creation_result = g_ata_work->try_queue([this]() -> void { 259 MutexLocker locker(m_lock); 260 u8 status = task_file_status().release_value(); 261 262 m_entropy_source.add_random_event(status); 263 // clear bus master interrupt status 264 { 265 auto result = force_busmastering_status_clean(); 266 if (result.is_error()) { 267 complete_dma_transaction(AsyncDeviceRequest::Failure); 268 return; 269 } 270 } 271 272 SpinlockLocker lock(m_hard_lock); 273 dbgln_if(ATA_DEBUG, "ATAPort: interrupt: DRQ={}, BSY={}, DRDY={}", 274 (status & ATA_SR_DRQ) != 0, 275 (status & ATA_SR_BSY) != 0, 276 (status & ATA_SR_DRDY) != 0); 277 278 if (!m_current_request) { 279 dbgln("ATAPort: IRQ but no pending request!"); 280 return; 281 } 282 283 if (status & ATA_SR_ERR) { 284 print_ata_status(status); 285 auto device_error = task_file_error().release_value(); 286 dbgln("ATAPort: Error {:#02x}!", (u8)device_error); 287 try_disambiguate_ata_error(device_error); 288 complete_dma_transaction(AsyncDeviceRequest::Failure); 289 return; 290 } 291 complete_dma_transaction(AsyncDeviceRequest::Success); 292 return; 293 }); 294 if (work_item_creation_result.is_error()) { 295 auto current_request = m_current_request; 296 m_current_request.clear(); 297 current_request->complete(AsyncDeviceRequest::OutOfMemory); 298 return Error::from_errno(ENOMEM); 299 } 300 return true; 301} 302 303ErrorOr<void> ATAPort::prepare_and_initiate_dma_transaction(ATADevice const& associated_device) 304{ 305 VERIFY(m_lock.is_locked()); 306 VERIFY(!m_current_request.is_null()); 307 VERIFY(m_current_request->block_count() <= 256); 308 309 // Note: We might be called here from an interrupt handler (like the page fault handler), so queue a read afterwards. 310 auto work_item_creation_result = g_ata_work->try_queue([this, &associated_device]() -> void { 311 MutexLocker locker(m_lock); 312 dbgln_if(ATA_DEBUG, "ATAPort::prepare_and_initiate_dma_transaction ({} x {})", m_current_request->block_index(), m_current_request->block_count()); 313 314 VERIFY(!m_current_request.is_null()); 315 VERIFY(m_current_request->block_count() <= 256); 316 { 317 auto result = device_select(associated_device.ata_address().subport); 318 if (result.is_error()) { 319 complete_dma_transaction(AsyncDeviceRequest::Failure); 320 return; 321 } 322 } 323 324 if (m_current_request->request_type() == AsyncBlockDeviceRequest::RequestType::Write) { 325 if (auto result = m_current_request->read_from_buffer(m_current_request->buffer(), m_dma_buffer_region->vaddr().as_ptr(), 512 * m_current_request->block_count()); result.is_error()) { 326 complete_dma_transaction(AsyncDeviceRequest::MemoryFault); 327 return; 328 } 329 } 330 331 prdt().offset = m_dma_buffer_page->paddr().get(); 332 prdt().size = 512 * m_current_request->block_count(); 333 334 VERIFY(prdt().size <= PAGE_SIZE); 335 336 SpinlockLocker hard_lock_locker(m_hard_lock); 337 338 { 339 auto result = stop_busmastering(); 340 if (result.is_error()) { 341 complete_dma_transaction(AsyncDeviceRequest::Failure); 342 return; 343 } 344 } 345 346 if (m_current_request->request_type() == AsyncBlockDeviceRequest::RequestType::Write) { 347 auto result = prepare_transaction_with_busmastering(TransactionDirection::Write, m_prdt_page->paddr()); 348 if (result.is_error()) { 349 complete_dma_transaction(AsyncDeviceRequest::Failure); 350 return; 351 } 352 } else { 353 auto result = prepare_transaction_with_busmastering(TransactionDirection::Read, m_prdt_page->paddr()); 354 if (result.is_error()) { 355 complete_dma_transaction(AsyncDeviceRequest::Failure); 356 return; 357 } 358 } 359 360 TaskFile taskfile; 361 LBAMode lba_mode = LBAMode::TwentyEightBit; 362 auto lba = m_current_request->block_index(); 363 if ((lba + m_current_request->block_count()) >= 0x10000000) { 364 lba_mode = LBAMode::FortyEightBit; 365 } 366 memset(&taskfile, 0, sizeof(TaskFile)); 367 taskfile.lba_low[0] = (lba & 0x000000FF) >> 0; 368 taskfile.lba_low[1] = (lba & 0x0000FF00) >> 8; 369 taskfile.lba_low[2] = (lba & 0x00FF0000) >> 16; 370 taskfile.lba_high[0] = (lba & 0xFF000000) >> 24; 371 taskfile.lba_high[1] = (lba & 0xFF00000000ull) >> 32; 372 taskfile.lba_high[2] = (lba & 0xFF0000000000ull) >> 40; 373 taskfile.count = m_current_request->block_count(); 374 if (lba_mode == LBAMode::TwentyEightBit) 375 taskfile.command = m_current_request->request_type() == AsyncBlockDeviceRequest::RequestType::Write ? ATA_CMD_WRITE_DMA : ATA_CMD_READ_DMA; 376 else 377 taskfile.command = m_current_request->request_type() == AsyncBlockDeviceRequest::RequestType::Write ? ATA_CMD_WRITE_DMA_EXT : ATA_CMD_READ_DMA_EXT; 378 379 { 380 auto result = load_taskfile_into_registers(taskfile, lba_mode, 1000); 381 if (result.is_error()) { 382 complete_dma_transaction(AsyncDeviceRequest::Failure); 383 return; 384 } 385 } 386 387 if (m_current_request->request_type() == AsyncBlockDeviceRequest::RequestType::Write) { 388 auto result = start_busmastering(TransactionDirection::Write); 389 if (result.is_error()) { 390 complete_dma_transaction(AsyncDeviceRequest::Failure); 391 return; 392 } 393 } 394 395 else { 396 auto result = start_busmastering(TransactionDirection::Read); 397 if (result.is_error()) { 398 complete_dma_transaction(AsyncDeviceRequest::Failure); 399 return; 400 } 401 } 402 }); 403 if (work_item_creation_result.is_error()) { 404 auto current_request = m_current_request; 405 m_current_request.clear(); 406 current_request->complete(AsyncDeviceRequest::OutOfMemory); 407 return Error::from_errno(ENOMEM); 408 } 409 return {}; 410} 411 412ErrorOr<void> ATAPort::prepare_and_initiate_pio_transaction(ATADevice const& associated_device) 413{ 414 VERIFY(m_lock.is_locked()); 415 VERIFY(!m_current_request.is_null()); 416 VERIFY(m_current_request->block_count() <= 256); 417 dbgln_if(ATA_DEBUG, "ATAPort::prepare_and_initiate_pio_transaction ({} x {})", m_current_request->block_index(), m_current_request->block_count()); 418 // Note: We might be called here from an interrupt handler (like the page fault handler), so queue a read afterwards. 419 auto work_item_creation_result = g_ata_work->try_queue([this, &associated_device]() -> void { 420 MutexLocker locker(m_lock); 421 { 422 auto result = device_select(associated_device.ata_address().subport); 423 if (result.is_error()) { 424 complete_pio_transaction(AsyncDeviceRequest::Failure); 425 return; 426 } 427 } 428 for (size_t block_index = 0; block_index < m_current_request->block_count(); block_index++) { 429 TaskFile taskfile; 430 LBAMode lba_mode = LBAMode::TwentyEightBit; 431 auto lba = m_current_request->block_index() + block_index; 432 if (lba >= 0x10000000) { 433 lba_mode = LBAMode::FortyEightBit; 434 } 435 memset(&taskfile, 0, sizeof(TaskFile)); 436 taskfile.lba_low[0] = (lba & 0x000000FF) >> 0; 437 taskfile.lba_low[1] = (lba & 0x0000FF00) >> 8; 438 taskfile.lba_low[2] = (lba & 0x00FF0000) >> 16; 439 taskfile.lba_high[0] = (lba & 0xFF000000) >> 24; 440 taskfile.lba_high[1] = (lba & 0xFF00000000ull) >> 32; 441 taskfile.lba_high[2] = (lba & 0xFF0000000000ull) >> 40; 442 taskfile.count = 1; 443 if (lba_mode == LBAMode::TwentyEightBit) 444 taskfile.command = m_current_request->request_type() == AsyncBlockDeviceRequest::RequestType::Write ? ATA_CMD_WRITE_PIO : ATA_CMD_READ_PIO; 445 else 446 taskfile.command = m_current_request->request_type() == AsyncBlockDeviceRequest::RequestType::Write ? ATA_CMD_WRITE_PIO_EXT : ATA_CMD_READ_PIO_EXT; 447 448 if (m_current_request->request_type() == AsyncBlockDeviceRequest::RequestType::Read) { 449 auto result = execute_polled_command(TransactionDirection::Read, lba_mode, taskfile, m_current_request->buffer(), block_index, 256, 100, 100); 450 if (result.is_error()) { 451 complete_pio_transaction(AsyncDeviceRequest::Failure); 452 return; 453 } 454 455 } else { 456 auto result = execute_polled_command(TransactionDirection::Write, lba_mode, taskfile, m_current_request->buffer(), block_index, 256, 100, 100); 457 if (result.is_error()) { 458 complete_pio_transaction(AsyncDeviceRequest::Failure); 459 return; 460 } 461 } 462 } 463 complete_pio_transaction(AsyncDeviceRequest::Success); 464 }); 465 if (work_item_creation_result.is_error()) { 466 auto current_request = m_current_request; 467 m_current_request.clear(); 468 current_request->complete(AsyncDeviceRequest::OutOfMemory); 469 return Error::from_errno(ENOMEM); 470 } 471 return {}; 472} 473 474ErrorOr<void> ATAPort::execute_polled_command(TransactionDirection direction, LBAMode lba_mode, TaskFile const& taskfile, UserOrKernelBuffer& buffer, size_t block_offset, size_t words_count, size_t preparation_timeout_in_milliseconds, size_t completion_timeout_in_milliseconds) 475{ 476 // Disable interrupts temporarily, just in case we have that enabled, 477 // remember the value to re-enable (and clean) later if needed. 478 ATAPortInterruptDisabler disabler(*this); 479 ATAPortInterruptCleaner cleaner(*this); 480 MutexLocker locker(m_lock); 481 { 482 SpinlockLocker hard_locker(m_hard_lock); 483 484 // Wait for device to be not busy or timeout 485 TRY(wait_if_busy_until_timeout(preparation_timeout_in_milliseconds)); 486 487 // Send command, wait for result or timeout 488 TRY(load_taskfile_into_registers(taskfile, lba_mode, preparation_timeout_in_milliseconds)); 489 490 size_t milliseconds_elapsed = 0; 491 for (;;) { 492 if (milliseconds_elapsed > completion_timeout_in_milliseconds) 493 break; 494 u8 status = task_file_status().release_value(); 495 if (status & ATA_SR_ERR) { 496 return Error::from_errno(EINVAL); 497 } 498 499 if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRQ)) { 500 break; 501 } 502 503 microseconds_delay(1000); 504 milliseconds_elapsed++; 505 } 506 if (milliseconds_elapsed > completion_timeout_in_milliseconds) { 507 critical_dmesgln("ATAPort: device state unknown. Timeout exceeded."); 508 return Error::from_errno(EINVAL); 509 } 510 } 511 512 VERIFY_INTERRUPTS_ENABLED(); 513 if (direction == TransactionDirection::Read) 514 TRY(read_pio_data_to_buffer(buffer, block_offset, words_count)); 515 else 516 TRY(write_pio_data_from_buffer(buffer, block_offset, words_count)); 517 return {}; 518} 519 520}