IDE: Add LBA28 addressing support
LBA28 is obsolete at this point, but we prefer to use it over LBA48 whenever we can because LBA28 is faster.
This commit is contained in:
parent
f993f6d7b9
commit
9329059510
|
@ -73,6 +73,9 @@ const ALT_STATUS_OFFSET: u16 = 2;
|
||||||
/// ATA identification command
|
/// ATA identification command
|
||||||
const CMD_IDENTIFY: u8 = 0xEC;
|
const CMD_IDENTIFY: u8 = 0xEC;
|
||||||
|
|
||||||
|
/// ATA read using LBA28 DMA command
|
||||||
|
const CMD_READ_DMA: u8 = 0xC8;
|
||||||
|
|
||||||
/// ATA read using LBA48 DMA command
|
/// ATA read using LBA48 DMA command
|
||||||
const CMD_READ_DMA_EXT: u8 = 0x25;
|
const CMD_READ_DMA_EXT: u8 = 0x25;
|
||||||
|
|
||||||
|
@ -154,10 +157,8 @@ impl PciIde {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer[167] >> 2) & 1 != 1 {
|
// FIXME: CHS support
|
||||||
// FIXME: 24-bit LBA and CHS support
|
let lba48 = (buffer[167] >> 2) & 1 == 1;
|
||||||
error!("IDE drive {channel:?}/{drive:?} does not support 48-bit LBA");
|
|
||||||
}
|
|
||||||
|
|
||||||
let size = buffer[200] as u64
|
let size = buffer[200] as u64
|
||||||
| (buffer[201] as u64) << 8
|
| (buffer[201] as u64) << 8
|
||||||
|
@ -173,6 +174,7 @@ impl PciIde {
|
||||||
channel,
|
channel,
|
||||||
drive,
|
drive,
|
||||||
size,
|
size,
|
||||||
|
lba48_support: lba48,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,9 +262,19 @@ impl PciIde {
|
||||||
drive: Drive,
|
drive: Drive,
|
||||||
lba: u64,
|
lba: u64,
|
||||||
sector_count: u16,
|
sector_count: u16,
|
||||||
) -> Result<Vec<u8>, TryFromIntError> {
|
buffer: &mut Vec<u8>,
|
||||||
|
) -> Result<(), TryFromIntError> {
|
||||||
|
let lba48_support = self
|
||||||
|
.ide_devices
|
||||||
|
.iter()
|
||||||
|
.find(|d| d.channel == channel && d.drive == drive)
|
||||||
|
.map(|d| d.lba48_support)
|
||||||
|
.unwrap(); // FIXME: make this an error
|
||||||
|
let lba48 = lba > 0xFFFFFFF && lba48_support;
|
||||||
|
|
||||||
// FIXME: make this an error
|
// FIXME: make this an error
|
||||||
assert!(lba < 0xFFFFFFFFFFFF);
|
assert!((lba48 && lba > 0xFFFFFFF) || (!lba48 && lba <= 0xFFFFFFF));
|
||||||
|
|
||||||
let byte_count = sector_count * SECTOR_SIZE;
|
let byte_count = sector_count * SECTOR_SIZE;
|
||||||
|
|
||||||
// prepare PRD table
|
// prepare PRD table
|
||||||
|
@ -285,8 +297,14 @@ impl PciIde {
|
||||||
self.set_read(channel);
|
self.set_read(channel);
|
||||||
self.clear_bmi_status(channel);
|
self.clear_bmi_status(channel);
|
||||||
select_drive(drive, channel);
|
select_drive(drive, channel);
|
||||||
set_lba(channel, lba, sector_count);
|
set_lba(channel, lba, sector_count, lba48);
|
||||||
ata_send_command(CMD_READ_DMA_EXT, channel);
|
|
||||||
|
if lba48 {
|
||||||
|
ata_send_command(CMD_READ_DMA_EXT, channel);
|
||||||
|
} else {
|
||||||
|
ata_send_command(CMD_READ_DMA, channel);
|
||||||
|
}
|
||||||
|
|
||||||
self.start(channel);
|
self.start(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,13 +327,12 @@ impl PciIde {
|
||||||
self.clear_bmi_status(channel);
|
self.clear_bmi_status(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buffer = Vec::with_capacity(byte_count as usize);
|
for i in 0..byte_count as u64 {
|
||||||
for i in 0..512 {
|
|
||||||
let addr = (BUFFER_START + i) as *mut u8;
|
let addr = (BUFFER_START + i) as *mut u8;
|
||||||
buffer.push(unsafe { *addr });
|
buffer.push(unsafe { *addr });
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(buffer)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn device_info(&self) -> PciDeviceInfo {
|
pub fn device_info(&self) -> PciDeviceInfo {
|
||||||
|
@ -474,30 +491,33 @@ unsafe fn ata_delay(channel: Channel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set LBA and sector count registers. sector_count of 0 means 65536 sectors
|
/// Set LBA and sector count registers. sector_count of 0 means 65536 sectors
|
||||||
unsafe fn set_lba(channel: Channel, lba: u64, sector_count: u16) {
|
unsafe fn set_lba(channel: Channel, lba: u64, sector_count: u16, lba48: bool) {
|
||||||
// FIXME: CHS and LBA24 support
|
|
||||||
assert!(lba < 0xFFFFFFFFFFFF);
|
|
||||||
|
|
||||||
let command_block = if channel.secondary() {
|
let command_block = if channel.secondary() {
|
||||||
SECONDARY_COMMAND
|
SECONDARY_COMMAND
|
||||||
} else {
|
} else {
|
||||||
PRIMARY_COMMAND
|
PRIMARY_COMMAND
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut seccount = Port::new(command_block + SECCOUNT_OFFSET);
|
let mut seccount = Port::new(command_block + SECCOUNT_OFFSET);
|
||||||
let mut lba0 = Port::new(command_block + LBA0_OFFSET);
|
let mut lba0 = Port::new(command_block + LBA0_OFFSET);
|
||||||
let mut lba1 = Port::new(command_block + LBA1_OFFSET);
|
let mut lba1 = Port::new(command_block + LBA1_OFFSET);
|
||||||
let mut lba2 = Port::new(command_block + LBA2_OFFSET);
|
let mut lba2 = Port::new(command_block + LBA2_OFFSET);
|
||||||
|
let mut head = Port::new(command_block + DRIVE_HEAD_OFFSET);
|
||||||
|
let head_value: u8 = head.read();
|
||||||
|
|
||||||
let lba_bytes = lba.to_le_bytes();
|
let lba_bytes = lba.to_le_bytes();
|
||||||
let sector_count_bytes = sector_count.to_le_bytes();
|
let sector_count_bytes = sector_count.to_le_bytes();
|
||||||
|
|
||||||
// write the new LBA & sector count registers
|
// write the new LBA & sector count registers
|
||||||
// if LBA48 {
|
// FIXME: CHS support
|
||||||
seccount.write(sector_count_bytes[1]);
|
if lba48 {
|
||||||
lba0.write(lba_bytes[3]);
|
seccount.write(sector_count_bytes[1]);
|
||||||
lba1.write(lba_bytes[4]);
|
lba0.write(lba_bytes[3]);
|
||||||
lba2.write(lba_bytes[5]);
|
lba1.write(lba_bytes[4]);
|
||||||
// }
|
lba2.write(lba_bytes[5]);
|
||||||
|
} else {
|
||||||
|
head.write(head_value | (lba_bytes[3] & 0x0F));
|
||||||
|
}
|
||||||
seccount.write(sector_count_bytes[0]);
|
seccount.write(sector_count_bytes[0]);
|
||||||
lba0.write(lba_bytes[0]);
|
lba0.write(lba_bytes[0]);
|
||||||
lba1.write(lba_bytes[1]);
|
lba1.write(lba_bytes[1]);
|
||||||
|
@ -522,10 +542,11 @@ struct IdeDevice {
|
||||||
pub channel: Channel,
|
pub channel: Channel,
|
||||||
pub drive: Drive,
|
pub drive: Drive,
|
||||||
pub size: u64, // in sectors
|
pub size: u64, // in sectors
|
||||||
// FIXME: model
|
pub lba48_support: bool,
|
||||||
|
// FIXME: model
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Channel {
|
pub enum Channel {
|
||||||
Primary,
|
Primary,
|
||||||
Secondary,
|
Secondary,
|
||||||
|
@ -537,7 +558,7 @@ impl Channel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Drive {
|
pub enum Drive {
|
||||||
Master,
|
Master,
|
||||||
Slave,
|
Slave,
|
||||||
|
|
|
@ -132,7 +132,8 @@ pub fn scratchpad() {
|
||||||
{
|
{
|
||||||
let mut pci_ide_device = pci_ide_device.lock();
|
let mut pci_ide_device = pci_ide_device.lock();
|
||||||
if let PciDevice::Ide(device) = &mut *pci_ide_device {
|
if let PciDevice::Ide(device) = &mut *pci_ide_device {
|
||||||
let first_sector = device.read(Channel::Primary, Drive::Master, 0, 1).unwrap();
|
let mut first_sector = Vec::with_capacity(512);
|
||||||
|
device.read(Channel::Primary, Drive::Master, 0, 1, &mut first_sector).unwrap();
|
||||||
trace!("IDE Primary/Master sector 0: {first_sector:?}");
|
trace!("IDE Primary/Master sector 0: {first_sector:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,14 +135,14 @@ fn test_push_number() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bytes,
|
bytes,
|
||||||
vec![
|
vec![
|
||||||
0b0101_1010, // 90
|
0b0101_1010, // 90
|
||||||
0b1001_1010, // 154
|
0b1001_1010, // 154
|
||||||
0b1100_1011, // 203
|
0b1100_1011, // 203
|
||||||
0b0110_1101, // 109
|
0b0110_1101, // 109
|
||||||
0b01_1001_00, // 100
|
0b01_1001_00, // 100
|
||||||
0b0111_1001, // 121
|
0b0111_1001, // 121
|
||||||
0b0111_0001, // 113
|
0b0111_0001, // 113
|
||||||
0b1000_0000, // 128
|
0b1000_0000, // 128
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -357,10 +357,7 @@ mod numeric_tests {
|
||||||
fn test_iso_18004_2006_example_1() {
|
fn test_iso_18004_2006_example_1() {
|
||||||
let mut bits = Bits::new(Version::Normal(1));
|
let mut bits = Bits::new(Version::Normal(1));
|
||||||
assert_eq!(bits.push_numeric_data(b"01234567"), Ok(()));
|
assert_eq!(bits.push_numeric_data(b"01234567"), Ok(()));
|
||||||
assert_eq!(
|
assert_eq!(bits.into_bytes(), vec![0b0001_0000, 0b001000_00, 0b00001100, 0b01010110, 0b0110_0001, 0b1000_0000]);
|
||||||
bits.into_bytes(),
|
|
||||||
vec![0b0001_0000, 0b001000_00, 0b00001100, 0b01010110, 0b0110_0001, 0b1000_0000]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -389,16 +386,7 @@ mod numeric_tests {
|
||||||
assert_eq!(bits.push_numeric_data(b"0123456789012345"), Ok(()));
|
assert_eq!(bits.push_numeric_data(b"0123456789012345"), Ok(()));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bits.into_bytes(),
|
bits.into_bytes(),
|
||||||
vec![
|
vec![0b0010_0000, 0b00000110, 0b0010_1011, 0b0011_0101, 0b0011_0111, 0b0000_1010, 0b01110101, 0b0010_1000,]
|
||||||
0b0010_0000,
|
|
||||||
0b00000110,
|
|
||||||
0b0010_1011,
|
|
||||||
0b0011_0101,
|
|
||||||
0b0011_0111,
|
|
||||||
0b0000_1010,
|
|
||||||
0b01110101,
|
|
||||||
0b0010_1000,
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,10 +453,7 @@ mod alphanumeric_tests {
|
||||||
fn test_iso_18004_2006_example() {
|
fn test_iso_18004_2006_example() {
|
||||||
let mut bits = Bits::new(Version::Normal(1));
|
let mut bits = Bits::new(Version::Normal(1));
|
||||||
assert_eq!(bits.push_alphanumeric_data(b"AC-42"), Ok(()));
|
assert_eq!(bits.push_alphanumeric_data(b"AC-42"), Ok(()));
|
||||||
assert_eq!(
|
assert_eq!(bits.into_bytes(), vec![0b0010_0000, 0b0010_1001, 0b11001110, 0b11100111, 0b0010_0001, 0b0000_0000]);
|
||||||
bits.into_bytes(),
|
|
||||||
vec![0b0010_0000, 0b0010_1001, 0b11001110, 0b11100111, 0b0010_0001, 0b0000_0000]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
//! Find the optimal data mode sequence to encode a piece of data.
|
//! Find the optimal data mode sequence to encode a piece of data.
|
||||||
use crate::types::{Mode, Version};
|
use crate::types::{Mode, Version};
|
||||||
|
|
||||||
|
|
||||||
use core::slice::Iter;
|
use core::slice::Iter;
|
||||||
|
|
||||||
#[cfg(feature = "bench")]
|
#[cfg(feature = "bench")]
|
||||||
|
@ -155,7 +154,7 @@ impl<'a> Iterator for Parser<'a> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod parse_tests {
|
mod parse_tests {
|
||||||
use alloc::vec::{Vec};
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use crate::optimize::{Parser, Segment};
|
use crate::optimize::{Parser, Segment};
|
||||||
use crate::types::Mode;
|
use crate::types::Mode;
|
||||||
|
|
Loading…
Reference in a new issue