redox/drivers/ahcid/src/ahci/disk.rs

117 lines
3.8 KiB
Rust
Raw Normal View History

2016-09-28 04:26:54 +02:00
use std::ptr;
use syscall::error::{Error, EIO, Result};
use super::dma::Dma;
use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader};
pub struct Disk {
id: usize,
port: &'static mut HbaPort,
size: u64,
clb: Dma<[HbaCmdHeader; 32]>,
ctbas: [Dma<HbaCmdTable>; 32],
fb: Dma<[u8; 256]>,
buf: Dma<[u8; 256 * 512]>
}
impl Disk {
pub fn new(id: usize, port: &'static mut HbaPort) -> Result<Self> {
let mut clb = Dma::zeroed()?;
let mut ctbas = [
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
];
let mut fb = Dma::zeroed()?;
let buf = Dma::zeroed()?;
port.init(&mut clb, &mut ctbas, &mut fb);
let size = unsafe { port.identify(&mut clb, &mut ctbas).unwrap_or(0) };
Ok(Disk {
id: id,
port: port,
size: size,
clb: clb,
ctbas: ctbas,
fb: fb,
buf: buf
})
}
pub fn id(&self) -> usize {
self.id
}
pub fn size(&self) -> u64 {
self.size
}
pub fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> {
let sectors = buffer.len()/512;
if sectors > 0 {
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);
}
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);
}
unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), (sectors - sector) * 512); }
sector += sectors - sector;
}
Ok(sector * 512)
} else {
println!("Invalid request");
Err(Error::new(EIO))
}
}
pub fn write(&mut self, block: u64, buffer: &[u8]) -> Result<usize> {
let sectors = (buffer.len() + 511)/512;
if sectors > 0 {
let mut sector: usize = 0;
while sectors - sector >= 255 {
unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), 255 * 512); }
if let Err(err) = self.port.ata_dma(block + sector as u64, 255, true, &mut self.clb, &mut self.ctbas, &mut self.buf) {
return Err(err);
}
sector += 255;
}
if sector < sectors {
unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), (sectors - sector) * 512); }
if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, true, &mut self.clb, &mut self.ctbas, &mut self.buf) {
return Err(err);
}
sector += sectors - sector;
}
Ok(sector * 512)
} else {
println!("Invalid request");
Err(Error::new(EIO))
}
}
}