Commit a38dfb32 authored by Jeremy Soller's avatar Jeremy Soller

Use IRQs to prevent spin loops in ahcid

parent ca748c99
......@@ -5,7 +5,6 @@ dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
......
......@@ -4,6 +4,5 @@ version = "0.1.0"
[dependencies]
bitflags = "0.7"
spin = "0.4"
redox_syscall = "0.1"
byteorder = "1.2"
......@@ -6,10 +6,23 @@ use syscall::error::Result;
use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader};
use super::Disk;
enum BufferKind<'a> {
Read(&'a mut [u8]),
Write(&'a [u8]),
}
struct Request {
address: usize,
total_sectors: usize,
sector: usize,
running_opt: Option<(u32, usize)>,
}
pub struct DiskATA {
id: usize,
port: &'static mut HbaPort,
size: u64,
request_opt: Option<Request>,
clb: Dma<[HbaCmdHeader; 32]>,
ctbas: [Dma<HbaCmdTable>; 32],
_fb: Dma<[u8; 256]>,
......@@ -40,69 +53,92 @@ impl DiskATA {
id: id,
port: port,
size: size,
request_opt: None,
clb: clb,
ctbas: ctbas,
_fb: fb,
buf: buf
})
}
}
impl Disk for DiskATA {
fn id(&self) -> usize {
self.id
}
fn size(&mut self) -> u64 {
self.size
}
fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> {
let sectors = buffer.len()/512;
let mut sector: usize = 0;
while sectors - sector >= 255 {
self.port.dma_read_write(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); }
fn request(&mut self, block: u64, mut buffer_kind: BufferKind) -> Result<Option<usize>> {
let (write, address, total_sectors) = match buffer_kind {
BufferKind::Read(ref buffer) => (false, buffer.as_ptr() as usize, buffer.len()/512),
BufferKind::Write(ref buffer) => (true, buffer.as_ptr() as usize, buffer.len()/512),
};
let mut request = match self.request_opt.take() {
Some(request) => if address == request.address && total_sectors == request.total_sectors {
// Keep servicing current request
request
} else {
// Have to wait for another request to finish
self.request_opt = Some(request);
return Ok(None);
},
None => {
// Create new request
Request {
address,
total_sectors,
sector: 0,
running_opt: None,
}
}
};
sector += 255;
}
if sector < sectors {
self.port.dma_read_write(block + sector as u64, sectors - sector, false, &mut self.clb, &mut self.ctbas, &mut self.buf)?;
// Finish a previously running request
if let Some(running) = request.running_opt.take() {
self.port.ata_stop(running.0)?;
unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), (sectors - sector) * 512); }
if let BufferKind::Read(ref mut buffer) = buffer_kind {
unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().add(request.sector * 512), running.1 * 512); }
}
sector += sectors - sector;
request.sector += running.1;
}
Ok(sector * 512)
}
fn write(&mut self, block: u64, buffer: &[u8]) -> Result<usize> {
let sectors = buffer.len()/512;
if request.sector < request.total_sectors {
// Start a new request
let sectors = if request.total_sectors - request.sector >= 255 {
255
} else {
request.total_sectors - request.sector
};
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 BufferKind::Write(ref buffer) = buffer_kind {
unsafe { ptr::copy(buffer.as_ptr().add(request.sector * 512), self.buf.as_mut_ptr(), sectors * 512); }
}
if let Err(err) = self.port.dma_read_write(block + sector as u64, 255, true, &mut self.clb, &mut self.ctbas, &mut self.buf) {
return Err(err);
if let Some(slot) = self.port.ata_dma(block + request.sector as u64, sectors, write, &mut self.clb, &mut self.ctbas, &mut self.buf) {
request.running_opt = Some((slot, sectors));
}
sector += 255;
self.request_opt = Some(request);
Ok(None)
} else {
// Done
Ok(Some(request.sector * 512))
}
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.dma_read_write(block + sector as u64, sectors - sector, true, &mut self.clb, &mut self.ctbas, &mut self.buf) {
return Err(err);
}
impl Disk for DiskATA {
fn id(&self) -> usize {
self.id
}
sector += sectors - sector;
}
fn size(&mut self) -> u64 {
self.size
}
fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result<Option<usize>> {
self.request(block, BufferKind::Read(buffer))
}
Ok(sector * 512)
fn write(&mut self, block: u64, buffer: &[u8]) -> Result<Option<usize>> {
self.request(block, BufferKind::Write(buffer))
}
fn block_length(&mut self) -> Result<u32> {
......
......@@ -5,7 +5,7 @@ use std::ptr;
use byteorder::{ByteOrder, BigEndian};
use syscall::io::Dma;
use syscall::error::{Result, ENOSYS, Error};
use syscall::error::{Result, EBADF, Error};
use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader};
use super::Disk;
......@@ -61,7 +61,7 @@ impl DiskATAPI {
let mut cmd = [0; 16];
cmd[0] = SCSI_READ_CAPACITY;
self.port.packet(&cmd, 8, &mut self.clb, &mut self.ctbas, &mut self.buf)?;
self.port.atapi_dma(&cmd, 8, &mut self.clb, &mut self.ctbas, &mut self.buf)?;
// Instead of a count, contains number of last LBA, so add 1
let blk_count = BigEndian::read_u32(&self.buf[0..4]) + 1;
......@@ -83,9 +83,9 @@ impl Disk for DiskATAPI {
}
}
fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> {
fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result<Option<usize>> {
// TODO: Handle audio CDs, which use special READ CD command
let blk_len = self.block_length()?;
let sectors = buffer.len() as u32 / blk_len;
......@@ -102,7 +102,7 @@ impl Disk for DiskATAPI {
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)?;
self.port.atapi_dma(&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); }
......@@ -110,20 +110,20 @@ impl Disk for DiskATAPI {
}
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)?;
self.port.atapi_dma(&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)
Ok(Some((sector * blk_len) as usize))
}
fn write(&mut self, _block: u64, _buffer: &[u8]) -> Result<usize> {
Err(Error::new(ENOSYS)) // TODO: Implement writting
fn write(&mut self, _block: u64, _buffer: &[u8]) -> Result<Option<usize>> {
Err(Error::new(EBADF)) // TODO: Implement writing
}
fn block_length(&mut self) -> Result<u32> {
Ok(self.read_capacity()?.1)
}
......
......@@ -116,7 +116,7 @@ impl HbaPort {
self.fb[1].write((fb.physical() >> 32) as u32);
let is = self.is.read();
self.is.write(is);
self.ie.write(0);
self.ie.write(0b10111);
let serr = self.serr.read();
self.serr.write(serr);
......@@ -142,7 +142,7 @@ impl HbaPort {
unsafe fn identify_inner(&mut self, cmd: u8, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma<HbaCmdTable>; 32]) -> Option<u64> {
let dest: Dma<[u16; 256]> = Dma::new([0; 256]).unwrap();
let res = self.ata_dma(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| {
let slot = self.ata_start(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| {
cmdheader.prdtl.write(1);
let prdt_entry = &mut prdt_entries[0];
......@@ -154,9 +154,9 @@ impl HbaPort {
cmdfis.device.write(0);
cmdfis.countl.write(1);
cmdfis.counth.write(0);
});
})?;
if res.is_ok() {
if self.ata_stop(slot).is_ok() {
let mut serial = String::new();
for word in 10..20 {
let d = dest[word];
......@@ -217,14 +217,12 @@ impl HbaPort {
}
}
pub fn dma_read_write(&mut self, block: u64, sectors: usize, write: bool, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma<HbaCmdTable>; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result<usize> {
if write {
//print!("{}", format!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}\n", (self as *mut HbaPort) as usize, block, sectors, write));
}
pub fn ata_dma(&mut self, block: u64, sectors: usize, write: bool, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma<HbaCmdTable>; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Option<u32> {
// print!("{}", format!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}\n", (self as *mut HbaPort) as usize, block, sectors, write));
assert!(sectors > 0 && sectors < 256);
let res = self.ata_dma(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| {
self.ata_start(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| {
if write {
let cfl = cmdheader.cfl.read();
cmdheader.cfl.write(cfl | 1 << 7 | 1 << 6)
......@@ -255,14 +253,12 @@ impl HbaPort {
cmdfis.countl.write(sectors as u8);
cmdfis.counth.write((sectors >> 8) as u8);
});
res.and(Ok(sectors * 512))
})
}
/// Send ATAPI packet
pub fn packet(&mut self, cmd: &[u8; 16], size: u32, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma<HbaCmdTable>; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result<()> {
self.ata_dma(clb, ctbas, |cmdheader, cmdfis, prdt_entries, acmd| {
pub fn atapi_dma(&mut self, cmd: &[u8; 16], size: u32, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma<HbaCmdTable>; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result<()> {
let slot = self.ata_start(clb, ctbas, |cmdheader, cmdfis, prdt_entries, acmd| {
let cfl = cmdheader.cfl.read();
cmdheader.cfl.write(cfl | 1 << 5);
......@@ -281,12 +277,14 @@ impl HbaPort {
cmdfis.featureh.write(0);
unsafe { ptr::write_volatile(acmd.as_mut_ptr() as *mut [u8; 16], *cmd) };
})
}).ok_or(Error::new(EIO))?;
self.ata_stop(slot)
}
fn ata_dma<F>(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma<HbaCmdTable>; 32], callback: F) -> Result<()>
pub fn ata_start<F>(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma<HbaCmdTable>; 32], callback: F) -> Option<u32>
where F: FnOnce(&mut HbaCmdHeader, &mut FisRegH2D, &mut [HbaPrdtEntry; 65536], &mut [Mmio<u8>; 16]) {
//TODO: Should probably remove
self.is.write(u32::MAX);
if let Some(slot) = self.slot() {
......@@ -312,27 +310,31 @@ impl HbaPort {
self.ci.writef(1 << slot, true);
//TODO: Should probably remove
self.start();
while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 {
thread::yield_now();
}
Some(slot)
} else {
None
}
}
self.stop();
pub fn ata_stop(&mut self, slot: u32) -> Result<()> {
while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 {
thread::yield_now();
}
if self.is.read() & HBA_PORT_IS_ERR != 0 {
print!("{}", format!("ERROR IS {:X} IE {:X} CMD {:X} TFD {:X}\nSSTS {:X} SCTL {:X} SERR {:X} SACT {:X}\nCI {:X} SNTF {:X} FBS {:X}\n",
self.is.read(), self.ie.read(), self.cmd.read(), self.tfd.read(),
self.ssts.read(), self.sctl.read(), self.serr.read(), self.sact.read(),
self.ci.read(), self.sntf.read(), self.fbs.read()));
self.is.write(u32::MAX);
Err(Error::new(EIO))
} else {
Ok(())
}
} else {
print!("No Command Slots\n");
self.stop();
if self.is.read() & HBA_PORT_IS_ERR != 0 {
print!("{}", format!("ERROR IS {:X} IE {:X} CMD {:X} TFD {:X}\nSSTS {:X} SCTL {:X} SERR {:X} SACT {:X}\nCI {:X} SNTF {:X} FBS {:X}\n",
self.is.read(), self.ie.read(), self.cmd.read(), self.tfd.read(),
self.ssts.read(), self.sctl.read(), self.serr.read(), self.sact.read(),
self.ci.read(), self.sntf.read(), self.fbs.read()));
self.is.write(u32::MAX);
Err(Error::new(EIO))
} else {
Ok(())
}
}
}
......
......@@ -13,18 +13,19 @@ pub mod hba;
pub trait Disk {
fn id(&self) -> usize;
fn size(&mut self) -> u64;
fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize>;
fn write(&mut self, block: u64, buffer: &[u8]) -> Result<usize>;
fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result<Option<usize>>;
fn write(&mut self, block: u64, buffer: &[u8]) -> Result<Option<usize>>;
fn block_length(&mut self) -> Result<u32>;
}
pub fn disks(base: usize, name: &str) -> Vec<Box<Disk>> {
unsafe { &mut *(base as *mut HbaMem) }.init();
let pi = unsafe { &mut *(base as *mut HbaMem) }.pi.read();
let ret: Vec<Box<Disk>> = (0..32)
pub fn disks(base: usize, name: &str) -> (&'static mut HbaMem, Vec<Box<Disk>>) {
let hba_mem = unsafe { &mut *(base as *mut HbaMem) };
hba_mem.init();
let pi = hba_mem.pi.read();
let disks: Vec<Box<Disk>> = (0..hba_mem.ports.len())
.filter(|&i| pi & 1 << i as i32 == 1 << i as i32)
.filter_map(|i| {
let port = &mut unsafe { &mut *(base as *mut HbaMem) }.ports[i];
let port = unsafe { &mut *hba_mem.ports.as_mut_ptr().add(i) };
let port_type = port.probe();
print!("{}", format!("{}-{}: {:?}\n", name, i, port_type));
......@@ -54,5 +55,5 @@ pub fn disks(base: usize, name: &str) -> Vec<Box<Disk>> {
})
.collect();
ret
(hba_mem, disks)
}
#![deny(warnings)]
#![feature(asm)]
//#![deny(warnings)]
extern crate spin;
extern crate syscall;
extern crate byteorder;
......@@ -9,7 +7,7 @@ use std::{env, usize};
use std::fs::File;
use std::io::{Read, Write};
use std::os::unix::io::FromRawFd;
use syscall::{EVENT_READ, PHYSMAP_WRITE, Event, Packet, Scheme};
use syscall::{EVENT_READ, PHYSMAP_WRITE, Event, Packet, SchemeBlockMut};
use scheme::DiskScheme;
......@@ -49,6 +47,8 @@ fn main() {
let mut event_file = File::open("event:").expect("ahcid: failed to open event file");
syscall::setrens(0, 0).expect("ahcid: failed to enter null namespace");
event_file.write(&Event {
id: socket_fd,
flags: EVENT_READ,
......@@ -61,10 +61,10 @@ fn main() {
data: 0
}).expect("ahcid: failed to event irq scheme");
let scheme = DiskScheme::new(scheme_name, ahci::disks(address, &name));
syscall::setrens(0, 0).expect("ahcid: failed to enter null namespace");
let (hba_mem, disks) = ahci::disks(address, &name);
let mut scheme = DiskScheme::new(scheme_name, hba_mem, disks);
let mut todo = Vec::new();
loop {
let mut event = Event::default();
if event_file.read(&mut event).expect("ahcid: failed to read event file") == 0 {
......@@ -76,14 +76,42 @@ fn main() {
if socket.read(&mut packet).expect("ahcid: failed to read disk scheme") == 0 {
break;
}
scheme.handle(&mut packet);
socket.write(&mut packet).expect("ahcid: failed to write disk scheme");
if let Some(a) = scheme.handle(&packet) {
packet.a = a;
socket.write(&mut packet).expect("ahcid: failed to write disk scheme");
} else {
todo.push(packet);
}
}
// let mut i = 0;
// while i < todo.len() {
// if let Some(a) = scheme.handle(&todo[i]) {
// let mut packet = todo.remove(i);
// packet.a = a;
// socket.write(&mut packet).expect("ahcid: failed to write disk scheme");
// } else {
// i += 1;
// }
// }
} else if event.id == irq_fd {
let mut irq = [0; 8];
if irq_file.read(&mut irq).expect("ahcid: failed to read irq file") >= irq.len() {
//TODO : Test for IRQ
//irq_file.write(&irq).expect("ahcid: failed to write irq file");
if scheme.irq() {
irq_file.write(&irq).expect("ahcid: failed to write irq file");
let mut i = 0;
while i < todo.len() {
if let Some(a) = scheme.handle(&todo[i]) {
let mut packet = todo.remove(i);
packet.a = a;
socket.write(&mut packet).expect("ahcid: failed to write disk scheme");
} else {
i += 1;
}
}
}
}
} else {
println!("Unknown event {}", event.id);
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment