Commit c78d4dcf authored by Ian Douglas Scott's avatar Ian Douglas Scott

ahci: atapi support (incomplete)

It can currently retrieve the capacity; no reads or writes yet.
parent c11736f7
This diff is collapsed.
......@@ -6,3 +6,4 @@ version = "0.1.0"
bitflags = "0.7"
spin = "0.4"
redox_syscall = "0.1"
byteorder = "1.2"
......@@ -4,8 +4,9 @@ use syscall::io::Dma;
use syscall::error::Result;
use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader};
use super::Disk;
pub struct Disk {
pub struct DiskATA {
id: usize,
port: &'static mut HbaPort,
size: u64,
......@@ -15,7 +16,7 @@ pub struct Disk {
buf: Dma<[u8; 256 * 512]>
}
impl Disk {
impl DiskATA {
pub fn new(id: usize, port: &'static mut HbaPort) -> Result<Self> {
let mut clb = Dma::zeroed()?;
let mut ctbas = [
......@@ -35,7 +36,7 @@ impl Disk {
let size = unsafe { port.identify(&mut clb, &mut ctbas).unwrap_or(0) };
Ok(Disk {
Ok(DiskATA {
id: id,
port: port,
size: size,
......@@ -45,16 +46,18 @@ impl Disk {
buf: buf
})
}
}
pub fn id(&self) -> usize {
impl Disk for DiskATA {
fn id(&self) -> usize {
self.id
}
pub fn size(&self) -> u64 {
fn size(&mut self) -> u64 {
self.size
}
pub fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> {
fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> {
let sectors = buffer.len()/512;
let mut sector: usize = 0;
......@@ -80,7 +83,7 @@ impl Disk {
Ok(sector * 512)
}
pub fn write(&mut self, block: u64, buffer: &[u8]) -> Result<usize> {
fn write(&mut self, block: u64, buffer: &[u8]) -> Result<usize> {
let sectors = buffer.len()/512;
let mut sector: usize = 0;
......
#![allow(dead_code)]
use byteorder::{ByteOrder, BigEndian};
use syscall::io::Dma;
use syscall::error::{Result, ENOSYS, Error};
use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader};
use super::Disk;
const SCSI_READ_CAPACITY: u8 = 0x25;
pub struct DiskATAPI {
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 DiskATAPI {
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_packet(&mut clb, &mut ctbas).unwrap_or(0) };
Ok(DiskATAPI {
id: id,
port: port,
size: size,
clb: clb,
ctbas: ctbas,
_fb: fb,
buf: buf
})
}
}
impl Disk for DiskATAPI {
fn id(&self) -> usize {
self.id
}
fn size(&mut self) -> u64 {
let mut cmd = [0; 16];
cmd[0] = SCSI_READ_CAPACITY;
if let Err(_) = self.port.packet(&cmd, 8, &mut self.clb, &mut self.ctbas, &mut self.buf) {
return 0; // XXX
}
let blk_count = BigEndian::read_u32(&self.buf[0..4]);
let blk_size = BigEndian::read_u32(&self.buf[4..8]);
(blk_count as u64) * (blk_size as u64)
}
fn read(&mut self, _block: u64, _buffer: &mut [u8]) -> Result<usize> {
Err(Error::new(ENOSYS))
}
fn write(&mut self, _block: u64, _buffer: &[u8]) -> Result<usize> {
Err(Error::new(ENOSYS)) // TODO: Implement writting
}
}
......@@ -10,6 +10,8 @@ use super::fis::{FisType, FisRegH2D};
const ATA_CMD_READ_DMA_EXT: u8 = 0x25;
const ATA_CMD_WRITE_DMA_EXT: u8 = 0x35;
const ATA_CMD_IDENTIFY: u8 = 0xEC;
const ATA_CMD_IDENTIFY_PACKET: u8 = 0xA1;
const ATA_CMD_PACKET: u8 = 0xA0;
const ATA_DEV_BUSY: u8 = 0x80;
const ATA_DEV_DRQ: u8 = 0x08;
......@@ -129,6 +131,15 @@ impl HbaPort {
}
pub unsafe fn identify(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma<HbaCmdTable>; 32]) -> Option<u64> {
self.identify_inner(ATA_CMD_IDENTIFY, clb, ctbas)
}
pub unsafe fn identify_packet(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma<HbaCmdTable>; 32]) -> Option<u64> {
self.identify_inner(ATA_CMD_IDENTIFY_PACKET, clb, ctbas)
}
// Shared between identify() and identify_packet()
unsafe fn identify_inner(&mut self, cmd: u8, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma<HbaCmdTable>; 32]) -> Option<u64> {
self.is.write(u32::MAX);
let dest: Dma<[u16; 256]> = Dma::new([0; 256]).unwrap();
......@@ -152,7 +163,7 @@ impl HbaPort {
cmdfis.fis_type.write(FisType::RegH2D as u8);
cmdfis.pm.write(1 << 7);
cmdfis.command.write(ATA_CMD_IDENTIFY);
cmdfis.command.write(cmd);
cmdfis.device.write(0);
cmdfis.countl.write(1);
cmdfis.counth.write(0);
......@@ -335,6 +346,67 @@ impl HbaPort {
Err(Error::new(EIO))
}
}
/// 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.is.write(u32::MAX);
if let Some(slot) = self.slot() {
let cmdheader = &mut clb[slot as usize];
cmdheader.cfl.write(((size_of::<FisRegH2D>() / size_of::<u32>()) as u8) | (1 << 5));
cmdheader.prdtl.write(1);
{
let cmdtbl = &mut ctbas[slot as usize];
unsafe { ptr::write_bytes(cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, 0, size_of::<HbaCmdTable>()) };
let prdt_entry = &mut cmdtbl.prdt_entry[0];
prdt_entry.dba.write(buf.physical() as u64);
prdt_entry.dbc.write(size - 1);
}
{
let cmdfis = unsafe { &mut *(ctbas[slot as usize].cfis.as_mut_ptr() as *mut FisRegH2D) };
cmdfis.fis_type.write(FisType::RegH2D as u8);
cmdfis.pm.write(1 << 7);
cmdfis.command.write(ATA_CMD_PACKET);
cmdfis.device.write(0);
cmdfis.lba1.write(0);
cmdfis.lba2.write(0);
cmdfis.featurel.write(1);
cmdfis.featureh.write(0);
}
let acmd = unsafe { &mut *(ctbas[slot as usize].acmd.as_mut_ptr() as *mut [u8; 16]) };
*acmd = *cmd;
while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {
thread::yield_now();
}
self.ci.writef(1 << slot, true);
self.start();
while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 {
thread::yield_now();
}
self.stop();
if self.is.read() & HBA_PORT_IS_ERR != 0 {
print!("{}", format!("ERROR IS {:X} TFD {:X} SERR {:X}\n", self.is.read(), self.tfd.read(), self.serr.read()));
return Err(Error::new(EIO));
}
Ok(())
} else {
print!("No Command Slots\n");
Err(Error::new(EIO))
}
}
}
#[repr(packed)]
......@@ -384,7 +456,7 @@ pub struct HbaCmdTable {
cfis: [Mmio<u8>; 64], // Command FIS
// 0x40
_acmd: [Mmio<u8>; 16], // ATAPI command, 12 or 16 bytes
acmd: [Mmio<u8>; 16], // ATAPI command, 12 or 16 bytes
// 0x50
_rsv: [Mmio<u8>; 48], // Reserved
......
use syscall::io::Io;
use syscall::error::Result;
use self::disk::Disk;
use self::disk_ata::DiskATA;
use self::disk_atapi::DiskATAPI;
use self::hba::{HbaMem, HbaPortType};
pub mod disk;
pub mod disk_ata;
pub mod disk_atapi;
pub mod fis;
pub mod hba;
pub fn disks(base: usize, name: &str) -> Vec<Disk> {
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>;
}
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<Disk> = (0..32)
let ret: Vec<Box<Disk>> = (0..32)
.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_type = port.probe();
print!("{}", format!("{}-{}: {:?}\n", name, i, port_type));
match port_type {
let disk: Option<Box<Disk>> = match port_type {
HbaPortType::SATA => {
match Disk::new(i, port) {
Ok(disk) => Some(disk),
match DiskATA::new(i, port) {
Ok(disk) => Some(Box::new(disk)),
Err(err) => {
print!("{}", format!("{}: {}\n", i, err));
None
}
}
}
HbaPortType::SATAPI => {
match DiskATAPI::new(i, port) {
Ok(disk) => Some(Box::new(disk)),
Err(err) => {
print!("{}", format!("{}: {}\n", i, err));
None
......@@ -27,7 +47,9 @@ pub fn disks(base: usize, name: &str) -> Vec<Disk> {
}
}
_ => None,
}
};
disk
})
.collect();
......
......@@ -3,6 +3,7 @@
extern crate spin;
extern crate syscall;
extern crate byteorder;
use std::{env, usize};
use std::fs::File;
......
......@@ -7,23 +7,23 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use spin::Mutex;
use syscall::{Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, Result, Scheme, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET};
use ahci::disk::Disk;
use ahci::Disk;
#[derive(Clone)]
enum Handle {
List(Vec<u8>, usize),
Disk(Arc<Mutex<Disk>>, usize, usize)
Disk(Arc<Mutex<Box<Disk>>>, usize, usize)
}
pub struct DiskScheme {
scheme_name: String,
disks: Box<[Arc<Mutex<Disk>>]>,
disks: Box<[Arc<Mutex<Box<Disk>>>]>,
handles: Mutex<BTreeMap<usize, Handle>>,
next_id: AtomicUsize
}
impl DiskScheme {
pub fn new(scheme_name: String, disks: Vec<Disk>) -> DiskScheme {
pub fn new(scheme_name: String, disks: Vec<Box<Disk>>) -> DiskScheme {
let mut disk_arcs = vec![];
for disk in disks {
disk_arcs.push(Arc::new(Mutex::new(disk)));
......
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