From 9de5eb7045f447b0fa1febaca78ccb892ce8625b Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Thu, 4 Jan 2018 14:20:12 -0800 Subject: [PATCH] atapi: Implement read support --- ahcid/src/ahci/disk_ata.rs | 12 +++++----- ahcid/src/ahci/disk_atapi.rs | 45 ++++++++++++++++++++++++++++++++++-- ahcid/src/ahci/mod.rs | 1 + ahcid/src/scheme.rs | 6 +++-- 4 files changed, 54 insertions(+), 10 deletions(-) diff --git a/ahcid/src/ahci/disk_ata.rs b/ahcid/src/ahci/disk_ata.rs index 9168c52804..8ac33d56b4 100644 --- a/ahcid/src/ahci/disk_ata.rs +++ b/ahcid/src/ahci/disk_ata.rs @@ -62,18 +62,14 @@ impl Disk for DiskATA { let mut sector: usize = 0; while sectors - sector >= 255 { - if let Err(err) = self.port.ata_dma(block + sector as u64, 255, false, &mut self.clb, &mut self.ctbas, &mut self.buf) { - return Err(err); - } + self.port.ata_dma(block + sector as u64, 255, false, &mut self.clb, &mut self.ctbas, &mut self.buf)?; unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), 255 * 512); } sector += 255; } if sector < sectors { - if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, false, &mut self.clb, &mut self.ctbas, &mut self.buf) { - return Err(err); - } + self.port.ata_dma(block + sector as u64, sectors - sector, false, &mut self.clb, &mut self.ctbas, &mut self.buf)?; unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), (sectors - sector) * 512); } @@ -108,4 +104,8 @@ impl Disk for DiskATA { Ok(sector * 512) } + + fn block_length(&mut self) -> Result { + Ok(512) + } } diff --git a/ahcid/src/ahci/disk_atapi.rs b/ahcid/src/ahci/disk_atapi.rs index 8159c39bf3..0dd7b69966 100644 --- a/ahcid/src/ahci/disk_atapi.rs +++ b/ahcid/src/ahci/disk_atapi.rs @@ -1,5 +1,7 @@ #![allow(dead_code)] +use std::ptr; + use byteorder::{ByteOrder, BigEndian}; use syscall::io::Dma; @@ -9,6 +11,7 @@ use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader}; use super::Disk; const SCSI_READ_CAPACITY: u8 = 0x25; +const SCSI_READ10: u8 = 0x28; pub struct DiskATAPI { id: usize, @@ -17,6 +20,8 @@ pub struct DiskATAPI { clb: Dma<[HbaCmdHeader; 32]>, ctbas: [Dma; 32], _fb: Dma<[u8; 256]>, + // Just using the same buffer size as DiskATA + // Although the sector size is different (and varies) buf: Dma<[u8; 256 * 512]> } @@ -77,12 +82,48 @@ impl Disk for DiskATAPI { } } - fn read(&mut self, _block: u64, _buffer: &mut [u8]) -> Result { - Err(Error::new(ENOSYS)) + fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result { + // TODO: Handle audio CDs, which use special READ CD command + + let blk_len = self.block_length()?; + let sectors = buffer.len() as u32 / blk_len; + + fn read10_cmd(block: u32, count: u16) -> [u8; 16] { + let mut cmd = [0; 16]; + cmd[0] = SCSI_READ10; + BigEndian::write_u32(&mut cmd[2..6], block as u32); + BigEndian::write_u16(&mut cmd[7..9], count as u16); + cmd + } + + let mut sector = 0; + let buf_len = (256 * 512) / blk_len; + let buf_size = buf_len * blk_len; + while sectors - sector >= buf_len { + let cmd = read10_cmd(block as u32 + sector, buf_len as u16); + self.port.packet(&cmd, buf_size, &mut self.clb, &mut self.ctbas, &mut self.buf)?; + + unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * blk_len as isize), buf_size as usize); } + + sector += blk_len; + } + if sector < sectors { + let cmd = read10_cmd(block as u32 + sector, (sectors - sector) as u16); + self.port.packet(&cmd, buf_size, &mut self.clb, &mut self.ctbas, &mut self.buf)?; + + unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * blk_len as isize), ((sectors - sector) * blk_len) as usize); } + + sector += sectors - sector; + } + + Ok((sector * blk_len) as usize) } fn write(&mut self, _block: u64, _buffer: &[u8]) -> Result { Err(Error::new(ENOSYS)) // TODO: Implement writting } + fn block_length(&mut self) -> Result { + Ok(self.read_capacity()?.1) + } } diff --git a/ahcid/src/ahci/mod.rs b/ahcid/src/ahci/mod.rs index b91f68558b..7b8444d749 100644 --- a/ahcid/src/ahci/mod.rs +++ b/ahcid/src/ahci/mod.rs @@ -15,6 +15,7 @@ pub trait Disk { fn size(&mut self) -> u64; fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result; fn write(&mut self, block: u64, buffer: &[u8]) -> Result; + fn block_length(&mut self) -> Result; } pub fn disks(base: usize, name: &str) -> Vec> { diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index 7701496a28..e981443e9e 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -150,7 +150,8 @@ impl Scheme for DiskScheme { }, Handle::Disk(ref mut handle, ref mut size, _) => { let mut disk = handle.lock(); - let count = disk.read((*size as u64)/512, buf)?; + let blk_len = disk.block_length()?; + let count = disk.read((*size as u64)/(blk_len as u64), buf)?; *size += count; Ok(count) } @@ -165,7 +166,8 @@ impl Scheme for DiskScheme { }, Handle::Disk(ref mut handle, ref mut size, _) => { let mut disk = handle.lock(); - let count = disk.write((*size as u64)/512, buf)?; + let blk_len = disk.block_length()?; + let count = disk.write((*size as u64)/(blk_len as u64), buf)?; *size += count; Ok(count) }