os: remove ATAPI driver

The driver will be superseeded soon by a new AHCI driver that supports
ATAPI devices. There is no IDE support in Gende anymore, however.

Issue #1456.
devel
Josef Söntgen 8 years ago committed by Christian Helmuth
parent 97dc9664fe
commit 2002e1ccba

@ -1,34 +1,15 @@
set use_sd_card_drv [expr [have_spec omap4] || [have_spec platform_arndale] || [have_spec pl180]]
set use_atapi_drv [have_spec x86]
set use_ahci_drv [have_spec x86]
if {[expr [have_spec linux] || [have_spec hw_odroid_xu]]} {
puts "Run script does not support this platform"; exit }
if {[expr [have_spec 64bit] && $use_atapi_drv]} {
puts "ATAPI driver does not support 64 bit."; exit 0 }
if {![have_include power_on/qemu]} {
puts "\nPlease setup your native sd or hard drive. Remove this fail stop";
puts "check when you have prepared your native environment.\n";
exit 0
}
if {[have_spec x86]} {
set qemu "qemu-system-i386"
if {[have_spec 64bit]} { set qemu "qemu-system-x86_64" }
set version [exec $qemu --version]
set version [regexp -inline {[0-9]+\.[0-9]+\.[0-9]+} $version]
if {$version >= 1.5} {
puts "Atapi driver on Qemu $version known to be not working.";
puts "For more details see Genode issue 827 on github";
puts stderr "Test requires 'fix for issue 827'"
exit 0;
}
}
#
# Build
#
@ -41,7 +22,7 @@ set build_components {
lappend_if [have_spec pci] build_components drivers/pci
lappend_if [have_spec acpi] build_components drivers/acpi
lappend_if $use_atapi_drv build_components drivers/atapi
lappend_if $use_ahci_drv build_components drivers/ahci
lappend_if $use_sd_card_drv build_components drivers/sd_card
build $build_components
@ -108,8 +89,8 @@ append_if [expr ![have_spec acpi] && [have_spec pci]] config {
<provides><service name="PCI"/></provides>
</start>}
append_if $use_atapi_drv config {
<start name="atapi_drv">
append_if $use_ahci_drv config {
<start name="ahci">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Block"/> </provides>
<config ata="yes" />
@ -142,7 +123,7 @@ set boot_modules {
lappend_if [have_spec pci] boot_modules pci_drv
lappend_if [have_spec acpi] boot_modules acpi_drv
lappend_if $use_atapi_drv boot_modules atapi_drv
lappend_if $use_ahci_drv boot_modules ahci
lappend_if $use_sd_card_drv boot_modules sd_card_drv
build_boot_image $boot_modules
@ -160,7 +141,7 @@ catch { exec sh -c $cmd }
# Qemu
#
append qemu_args " -m 128 -nographic "
append_if $use_atapi_drv qemu_args " -hda $disk_image -boot order=d "
append_if $use_ahci_drv qemu_args " -drive id=disk,file=$disk_image,if=none -device ahci,id=ahci -device ide-drive,drive=disk,bus=ahci.0 -boot d"
append_if $use_sd_card_drv qemu_args " -drive file=$disk_image,if=sd,cache=writeback "
run_genode_until {.*child "test-libc_block" exited with exit value 0.*} 60

@ -5,7 +5,7 @@
#
set use_sd_card_drv [expr [have_spec omap4] || [have_spec platform_arndale] || [have_spec pl180]]
set use_atapi_drv [have_spec x86]
set use_ahci_drv [have_spec x86]
if {[catch { exec which mkfs.vfat } ]} {
puts stderr "Error: mkfs.vfat not installed, aborting test"; exit }
@ -26,7 +26,7 @@ set build_components {
lappend_if [have_spec pci] build_components drivers/pci
lappend_if [have_spec acpi] build_components drivers/acpi
lappend_if $use_atapi_drv build_components drivers/atapi
lappend_if $use_ahci_drv build_components drivers/ahci
lappend_if $use_sd_card_drv build_components drivers/sd_card
build $build_components
@ -96,8 +96,8 @@ append_if [expr ![have_spec acpi] && [have_spec pci]] config {
<provides><service name="PCI"/></provides>
</start>}
append_if $use_atapi_drv config {
<start name="atapi_drv">
append_if $use_ahci_drv config {
<start name="ahci">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Block"/> </provides>
<config ata="yes" />
@ -130,7 +130,7 @@ set boot_modules {
lappend_if [have_spec pci] boot_modules pci_drv
lappend_if [have_spec acpi] boot_modules acpi_drv
lappend_if $use_atapi_drv boot_modules atapi_drv
lappend_if $use_ahci_drv boot_modules ahci
lappend_if $use_sd_card_drv boot_modules sd_card_drv
build_boot_image $boot_modules
@ -152,7 +152,7 @@ catch { exec sh -c $cmd }
# Qemu
#
append qemu_args " -m 128 -nographic "
append_if $use_atapi_drv qemu_args " -hda $disk_image -boot order=d "
append_if $use_ahci_drv qemu_args " -drive id=disk,file=$disk_image,if=none -device ahci,id=ahci -device ide-drive,drive=disk,bus=ahci.0 -boot d"
append_if $use_sd_card_drv qemu_args " -drive file=$disk_image,if=sd,cache=writeback "
run_genode_until {.*child "test-libc_vfs" exited with exit value 0.*} 60

@ -12,19 +12,8 @@ if {[have_spec hw_odroid_xu]} {
# use SD on ARM
set use_sd_card_drv [expr [have_spec omap4] || [have_spec platform_arndale] || [have_spec pl180]]
# use ATAPI on x86 (deprecated)
#set use_atapi_drv [have_spec x86]
#set use_ahci 0
# use AHCI on x86
set use_ahci [have_spec x86]
set use_atapi_drv 0
if {[expr $use_atapi_drv && $use_ahci]} {
puts "Usage of atapi and ahci is exclusive - choose one."
exit 1
}
if {[catch { exec which $mkfs_cmd } ]} {
puts stderr "Error: $mkfs_cmd not installed, aborting test"; exit }
@ -32,31 +21,12 @@ if {[catch { exec which $mkfs_cmd } ]} {
if {[have_spec linux]} {
puts "Run script does not support this platform"; exit }
if {[expr [have_spec 64bit] && $use_atapi_drv]} {
puts "ATAPI driver does not support 64 bit."; exit 0 }
if {![have_include "power_on/qemu"]} {
puts "\nPlease setup your native sd or hard drive. Remove this fail stop";
puts "check when you have prepared your native environment.\n";
exit 0
}
if {[expr $use_atapi_drv && [have_spec x86]]} {
set qemu "qemu-system-i386"
if {[have_spec 64bit]} { set qemu "qemu-system-x86_64" }
set version [exec $qemu --version]
set version [regexp -inline {[0-9]+\.[0-9]+\.[0-9]+} $version]
if {$version >= 1.5} {
puts "Atapi driver on Qemu $version known to be not working.";
puts "For more details see Genode issue 827 on github";
puts stderr "Test requires 'fix for issue 827'"
exit 0;
}
}
#
# Build
#
@ -72,7 +42,6 @@ lappend build_components test/libc_$filesystem
lappend_if [have_spec pci] build_components drivers/pci
lappend_if [have_spec acpi] build_components drivers/acpi
lappend_if $use_ahci build_components drivers/ahci
lappend_if $use_atapi_drv build_components drivers/atapi
lappend_if $use_sd_card_drv build_components drivers/sd_card
build $build_components
@ -142,14 +111,6 @@ append_if [expr ![have_spec acpi] && [have_spec pci]] config {
<provides><service name="PCI"/></provides>
</start>}
append_if $use_atapi_drv config {
<start name="atapi_drv">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Block"/> </provides>
<config ata="yes" />
</start>
}
append_if $use_ahci config {
<start name="ahci">
<binary name="ahci" />
@ -193,7 +154,6 @@ append boot_modules libc_$filesystem.lib.so
lappend_if [have_spec pci] boot_modules pci_drv
lappend_if [have_spec acpi] boot_modules acpi_drv
lappend_if $use_atapi_drv boot_modules atapi_drv
lappend_if $use_ahci boot_modules ahci
lappend_if $use_sd_card_drv boot_modules sd_card_drv
@ -216,7 +176,6 @@ catch { exec sh -c $cmd }
# Qemu
#
append qemu_args " -m 128 -nographic "
append_if $use_atapi_drv qemu_args " -hda $disk_image -boot order=d "
append_if $use_ahci qemu_args " -drive id=disk,file=$disk_image,if=none -device ahci,id=ahci -device ide-drive,drive=disk,bus=ahci.0 -boot d"
append_if $use_sd_card_drv qemu_args " -drive file=$disk_image,if=sd,cache=writeback "

@ -16,9 +16,10 @@ append build_components {
}
set use_sd_card_driver [expr [have_spec omap4] || [have_spec platform_arndale]]
set use_ahci_driver [have_spec x86]
lappend_if $use_sd_card_driver build_components drivers/sd_card
lappend_if [have_spec pci] build_components drivers/atapi
lappend_if $use_ahci_driver build_components drivers/ahci
lappend_if [have_spec acpi] build_components drivers/acpi
lappend_if [have_spec linux] build_components server/ram_fs
lappend_if [expr ![have_spec linux]] build_components server/ffat_fs
@ -48,8 +49,8 @@ append config {
append config [qt5_start_nodes feature]
append_if [have_spec pci] config {
<start name="atapi_drv">
append_if $use_ahci_driver config {
<start name="ahci">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Block"/> </provides>
<config ata="yes" />
@ -143,8 +144,8 @@ append boot_modules {
# platform-specific modules
lappend_if [have_spec linux] boot_modules ram_fs
lappend_if [expr ![have_spec linux]] boot_modules ffat_fs
lappend_if [have_spec pci] boot_modules atapi_drv
lappend_if $use_sd_card_driver boot_modules sd_card_drv
lappend_if $use_ahci_driver boot_modules ahci
build_boot_image $boot_modules
@ -157,7 +158,7 @@ set cmd "mkfs.vfat -F32 $disk_image"
puts "formating disk image with vfat file system: $cmd"
catch { exec sh -c $cmd }
append_if [have_spec pci] qemu_args " -hda $disk_image -boot order=d "
append_if $use_ahci_driver qemu_args " -drive id=disk,file=$disk_image,if=none -device ahci,id=ahci -device ide-drive,drive=disk,bus=ahci.0 -boot d"
append qemu_args " -m 256"

@ -1,24 +0,0 @@
This directory contains a port of the MINDRVR PATA/SATA driver (See:
[http://ata-atapi.com].
The driver will probe the system's IDE bus and will use the first ATAPI device
present.
Usage
-----
Simply start the 'atapi_drv' in your Genode environment. The front-end
implemented by the driver is Genode's block interface (see:
'os/include/block_session').
Configuration example:
! <start name="atapi_drv">
! <resource name="RAM" quantum="1M" />
! <provides><service name="Block" /></provides>
! </start>
To use the driver as IDE block driver supporting both read and write
transactions, supply the XML attribute 'ata="yes"' to the config node of
'atapi_drv'.

@ -1,140 +0,0 @@
/*
* \brief I/O interface to the IDE bus master
* \author Sebastian Sumpf <Sebastian.Sumpf@genode-labs.com>
* \date 2010-07-15
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
#include <io_port_session/connection.h>
#include <pci_session/connection.h>
#include <pci_device/client.h>
/* local includes */
#include "ata_bus_master.h"
#include "mindrvr.h"
using namespace Genode;
Ata::Bus_master::Bus_master(bool secondary) : _bmiba(0), _secondary(secondary)
{}
Ata::Bus_master::~Bus_master()
{
destroy(env()->heap(), _pio);
}
bool Ata::Bus_master::scan_pci()
{
Pci::Connection pci;
Pci::Device_capability prev_device_cap,
device_cap = pci.first_device();
/* test if standard legacy ports are used, if not skip */
uint32_t legacy = _secondary ? PI_CH2_LEGACY : PI_CH1_LEGACY;
while (device_cap.valid()) {
pci.release_device(prev_device_cap);
prev_device_cap = device_cap;
::Pci::Device_client device(device_cap);
if ((device.class_code() & CLASS_MASK)
== (CLASS_MASS_STORAGE | SUBCLASS_IDE) &&
!(device.class_code() & legacy)) {
Genode::printf("Found IDE Bus Master (Vendor ID: %04x Device ID: %04x Class: %08x)\n",
device.vendor_id(), device.device_id(), device.class_code());
/* read BMIBA */
_bmiba = device.config_read(PCI_CFG_BMIBA_OFF,
::Pci::Device::ACCESS_32BIT);
if (_bmiba == 0xffff)
_bmiba = 0;
/* port I/O or memory mapped ? */
_port_io = _bmiba & 0x1 ? true : false;
/* XXX cbass: This may only be true for Intel IDE controllers */
if (_bmiba && _port_io) {
_bmiba &= 0xfff0;
_pio = new(env()->heap()) Genode::Io_port_connection(_bmiba, 0x10);
if (_secondary)
_bmiba += 0x8;
}
Genode::printf("\tBus master interface base addr: %08x (%s) secondary (%s) (%s)\n",
_bmiba, _port_io ? "I/O" : "MEM",
_secondary ? "yes" : "no",
_bmiba ? "supported" : "invalid");
pci.release_device(prev_device_cap);
return _bmiba;
}
device_cap = pci.next_device(prev_device_cap);
}
/* release last device */
pci.release_device(prev_device_cap);
return _bmiba;
}
unsigned char Ata::Bus_master::read_cmd()
{
if (!_bmiba || !_port_io)
return 0;
return _pio->inb(_bmiba + BM_COMMAND_REG);
}
unsigned char Ata::Bus_master::read_status()
{
if (!_bmiba || !_port_io)
return 0;
return _pio->inb(_bmiba + BM_STATUS_REG);
}
void Ata::Bus_master::write_cmd(unsigned char val)
{
if (!_bmiba || !_port_io)
return;
_pio->outb(_bmiba + BM_COMMAND_REG, val);
}
void Ata::Bus_master::write_status(unsigned char val)
{
if (!_bmiba || !_port_io)
return;
_pio->outb(_bmiba + BM_STATUS_REG, val);
}
void Ata::Bus_master::write_prd(unsigned long val)
{
if (!_bmiba || !_port_io)
return;
if (val == _prd_virt) {
_pio->outl(_bmiba + BM_PRD_ADDR_LOW, _prd_phys);
}
}

@ -1,75 +0,0 @@
/*
* \brief I/O interface to the IDE bus master
* \author Sebastian Sumpf <Sebastian.Sumpf@genode-labs.com>
* \date 2010-07-15
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _ATA_PCI_H_
#define _ATA_PCI_H_
namespace Genode {
class Io_port_connection;
}
namespace Ata {
class Bus_master {
enum {
PCI_CFG_BMIBA_OFF = 0x20, /* offset in PCI config space */
CLASS_MASS_STORAGE = 0x10000,
SUBCLASS_IDE = 0x0100,
CLASS_MASK = 0xffff00,
/* These bits of the programming interface part within the class code
* define if the corresponding channel operates on standard legacy ports
* (bits are cleared) or if the corresponding ports in base register 0-1
* and 2-3 for channel 2 must be used as I/O bases (bits are set) */
PI_CH1_LEGACY = 0x1,
PI_CH2_LEGACY = 0x4,
};
/**
* Bus master interface base address
*/
unsigned _bmiba;
bool _port_io;
bool _secondary;
unsigned long _prd_virt;
unsigned long _prd_phys;
Genode::Io_port_connection *_pio;
public:
Bus_master(bool secondary);
~Bus_master();
unsigned char read_cmd();
unsigned char read_status();
void write_cmd(unsigned char val);
void write_status(unsigned char val);
void write_prd(unsigned long val);
void set_prd(unsigned long virt, unsigned long phys)
{
_prd_virt = virt;
_prd_phys = phys;
}
/**
* Scan PCI Bus for IDE devices and set BMBIA
*/
bool scan_pci();
};
}
#endif /* _ATA_PCI_H_ */

@ -1,317 +0,0 @@
/*
* \brief ATA device class
* \author Sebastian.Sump <Sebastian.Sumpf@genode-labs.com>
* \date 2010-07-15
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/lock.h>
#include <io_port_session/io_port_session.h>
#include <irq_session/connection.h>
/* local includes */
#include "ata_device.h"
#include "ata_bus_master.h"
#include "io.h"
#include "mindrvr.h"
static const int verbose = 0;
using namespace Genode;
Ata::Device::Device(unsigned base_cmd, unsigned base_ctrl)
: _lba48(false), _host_protected_area(false)
{
_pio = new(env()->heap()) Ata::Io_port(base_cmd, base_ctrl);
}
Ata::Device::~Device()
{
destroy(env()->heap(), _pio);
if (_irq)
destroy(env()->heap(), _irq);
if (_bus_master)
destroy(env()->heap(), _bus_master);
}
void Ata::Device::set_bus_master(bool secondary)
{
_bus_master = new(env()->heap()) Ata::Bus_master(secondary);
}
void Ata::Device::set_irq(unsigned irq)
{
_irq = new(env()->heap()) Irq_connection(irq);
}
void Ata::Device::probe_dma()
{
/* find bus master interface base address */
if (!_bus_master->scan_pci())
return;
/* read device information */
reg_reset(dev_num());
unsigned char *buffer;
if (!(env()->heap()->alloc(4096, &buffer))) return;
unsigned char cmd = dynamic_cast<Atapi_device *>(this) ? CMD_IDENTIFY_DEVICE_PACKET : CMD_IDENTIFY_DEVICE;
if (!reg_pio_data_in_lba28(
dev_num(),
cmd,
0, 1,
0L,
buffer,
1L, 0 )) {
/* check command set's LBA48 bit */
_lba48 = !!(buffer[167] & 0x4);
/* check for host protected area feature */
_host_protected_area = !!(buffer[165] & 0x4);
Genode::printf( "Adress mode is LBA%d\n", _lba48 ? 48 : 28 );
Genode::printf("UDMA Modes supported:\n");
for (int i = 0; i <= 5; i++) {
Genode::printf("\t%d and below: %s enabled: %s\n",
i ,(buffer[176] & (1 << i)) ? "yes" : "no",
(buffer[177] & (1 << i)) ? "yes" : "no");
if (buffer[177] & (1 << i)) {
/* initialize PRD's */
dma_pci_config();
_dma = true;
return;
}
}
}
env()->heap()->free(buffer, 4096);
}
void Ata::Device::read_capacity()
{
_block_start = 0;
_block_size = 512;
enum {
CMD_NATIVE_MAX_ADDRESS = 0xf8, /* LBA28 */
CMD_NATIVE_MAX_ADDRESS_EXT = 0x27, /* LBA48 */
};
/*
* If both LBA48 is enabled and host protected area feature is set, then NATIVE MAX
* ADDRESS EXT becomes mandatory, use LBA28 otherwise
*/
if (_lba48 && _host_protected_area) {
if (!reg_non_data_lba48(dev_num(), CMD_NATIVE_MAX_ADDRESS_EXT, 0, 1, 0UL, 0UL)) {
_block_end = _pio->inb(CB_SN); /* 0 - 7 */
_block_end |= _pio->inb(CB_CL) << 8; /* 8 - 15 */
_block_end |= _pio->inb(CB_CH) << 16; /* 16 - 23 */
/* read higher order LBA registers */
_pio->outb(CB_DC, CB_DC_HOB);
_block_end |= _pio->inb(CB_SN) << 24; /* 24 - 31 */
/* FIXME: read bits 32 - 47 */
}
} else {
if (!reg_non_data_lba28(dev_num(), CMD_NATIVE_MAX_ADDRESS, 0, 1, 0UL)) {
_block_end = _pio->inb(CB_SN); /* 0 - 7 */
_block_end |= _pio->inb(CB_CL) << 8; /* 8 - 15 */
_block_end |= _pio->inb(CB_CH) << 16; /* 16 - 23 */
_block_end |= (_pio->inb(CB_DH) & 0xf) << 24; /* 24 - 27 */
}
}
PINF("First block: %u last block %u, block size %u",
_block_start, _block_end, _block_size);
}
void Ata::Device::_read(Block::sector_t block_nr,
Genode::size_t count,
char *buffer,
bool dma)
{
Genode::size_t offset = 0;
while (count > 0) {
Genode::size_t c = count > 255 ? 255 : count;
if (dma) {
if (verbose)
PDBG("DMA read: block %llu, c %zu, buffer: %p",
block_nr, c, (void*)(buffer + offset));
if (!_lba48)
{
if (dma_pci_lba28(dev_num(), CMD_READ_DMA, 0, c, block_nr,
(unsigned char*)(buffer + offset), c))
throw Io_error();
} else {
if (dma_pci_lba48(dev_num(), CMD_READ_DMA_EXT, 0, c, 0, block_nr,
(unsigned char*)(buffer + offset), c))
throw Io_error();
}
}
else {
if (!_lba48)
{
if (reg_pio_data_in_lba28(dev_num(), CMD_READ_SECTORS, 0, c, block_nr,
(unsigned char*)(buffer + offset), c, 0))
throw Io_error();
} else {
if (reg_pio_data_in_lba48(dev_num(), CMD_READ_SECTORS_EXT, 0, c, 0, block_nr,
(unsigned char*)(buffer + offset), c, 0))
throw Io_error();
}
}
count -= c;
block_nr += c;
offset += c * block_size();
}
}
void Ata::Device::_write(Block::sector_t block_nr,
Genode::size_t count,
char const *buffer,
bool dma)
{
Genode::size_t offset = 0;
while (count > 0) {
Genode::size_t c = count > 255 ? 255 : count;
if (dma) {
if (verbose)
PDBG("DMA read: block %llu, c %zu, buffer: %p",
block_nr, c, (void*)(buffer + offset));
if (!_lba48)
{
if (dma_pci_lba28(dev_num(), CMD_WRITE_DMA, 0, c, block_nr,
(unsigned char*)(buffer + offset), c))
throw Io_error();
}
else {
if (dma_pci_lba48(dev_num(), CMD_WRITE_DMA_EXT, 0, c, 0, block_nr,
(unsigned char*)(buffer + offset), c))
throw Io_error();
}
}
else {
if (!_lba48)
{
if (reg_pio_data_out_lba28(dev_num(), CMD_WRITE_SECTORS, 0, c, block_nr,
(unsigned char*)(buffer + offset), c, 0))
throw Io_error();
} else {
if (reg_pio_data_out_lba48(dev_num(), CMD_WRITE_SECTORS_EXT, 0, c, 0, block_nr,
(unsigned char*)(buffer + offset), c, 0))
throw Io_error();
}
}
count -= c;
block_nr += c;
offset += c * block_size();
}
}
Ata::Device * Ata::Device::probe_legacy(int search_type)
{
unsigned base[] = { 0x1f0, 0x170 };
unsigned dev_irq[] = { 14, 15 };
const char *type = "";
for (int i = 0; i < 2; i++) {
Device *dev = new (env()->heap() )Device(base[i], base[i] + 0x200);
Device::current(dev);
/* Scan for devices */
reg_config();
for (unsigned char j = 0; j < 2; j++) {
switch (reg_config_info[j]) {
case REG_CONFIG_TYPE_NONE:
type = "none"; break;
case REG_CONFIG_TYPE_UNKN:
type = "unknown"; break;
case REG_CONFIG_TYPE_ATA:
type = "ATA"; break;
case REG_CONFIG_TYPE_ATAPI:
type = "ATAPI";
destroy (env()->heap(), dev);
dev = new (env()->heap() )Atapi_device(base[i], base[i] + 0x200);
break;
default:
type = "";
}
Genode::printf("IDE %d Device %d: %s IRQ: %u\n", i, j, type, dev_irq[i]);
/* prepare device */
if (reg_config_info[j] == search_type) {
dev->set_bus_master(i);
dev->set_dev_num(j);
dev->set_irq(dev_irq[i]);
dev->probe_dma();
Genode::printf("Device initialized! Enabling interrupts ...\n");
int_use_intr_flag = 1;
reg_reset(dev->dev_num());
return dev;
}
}
type = "";
destroy(env()->heap(), dev);
}
return 0;
}
Block::Session::Operations Ata::Device::ops()
{
Block::Session::Operations o;
o.set_operation(Block::Packet_descriptor::READ);
o.set_operation(Block::Packet_descriptor::WRITE);
return o;
}

@ -1,185 +0,0 @@
/*
* \brief ATA device class
* \author Sebastian.Sump <Sebastian.Sumpf@genode-labs.com>
* \date 2010-07-15
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _ATA_DEVICE_H_
#define _ATA_DEVICE_H_
#include <base/exception.h>
#include <base/stdint.h>
#include <block/component.h>
namespace Genode {
class Io_port_session;
class Irq_connection;
}
namespace Ata {
class Bus_master;
class Device : public Block::Driver
{
/* I/O back end may access private data (see io.cc) */
friend Genode::Io_port_session *get_io(Device *dev);
friend Genode::Irq_connection *get_irq(Device *dev);
friend Bus_master *get_bus_master(Device *dev);
protected:
unsigned char _dev_num;
Genode::Io_port_session *_pio;
Genode::Irq_connection *_irq;
Bus_master *_bus_master;
bool _dma;
unsigned _block_start;
unsigned _block_end;
unsigned _block_size;
bool _lba48;
bool _host_protected_area;
protected:
void probe_dma();
void set_bus_master(bool secondary);
void set_irq(unsigned irq);
void set_dev_num(unsigned char dev_num) { _dev_num = dev_num; }
unsigned char dev_num() { return _dev_num; }
Bus_master *bus_master(){ return _bus_master; }
Genode::Irq_connection *irq() { return _irq; }
Genode::Io_port_session *io() { return _pio; }
virtual void _read(Block::sector_t block_number,
Genode::size_t block_count,
char *out_buffer,
bool dma);
virtual void _write(Block::sector_t block_number,
Genode::size_t block_count,
char const *buffer,
bool dma);
public:
class Exception : public ::Genode::Exception { };
class Io_error : public Exception { };
/**
* Constructor
*
* \param base_cmd I/O port base of command registers
* \param base_ctrl I/O prot base of control registers
*/
Device(unsigned base_cmd, unsigned base_ctrl);
~Device();
/**
* Return and set current device
*/
static Device * current(Device *dev = 0)
{
static Device *_current = 0;
if (dev) _current = dev;
return _current;
}
/**
* Probe legacy bus for device class
*
* \param search_type REG_CONFIG_TYPE_ATA or REG_CONFIG_TYPE_ATAPI
*/
static Device * probe_legacy(int search_type);
/**
* Read block size and block count (from device),
* updates block_count and block_size
*/
virtual void read_capacity();
/*******************************
** Block::Driver interface **
*******************************/
Block::sector_t block_count() {
return _block_end - _block_start + 1; }
Genode::size_t block_size() { return _block_size; }
virtual Block::Session::Operations ops();
void read(Block::sector_t block_number,
Genode::size_t block_count,
char *buffer,
Block::Packet_descriptor &packet)
{
_read(block_number, block_count, buffer, false);
ack_packet(packet);
}
void write(Block::sector_t block_number,
Genode::size_t block_count,
char const *buffer,
Block::Packet_descriptor &packet)
{
_write(block_number, block_count, buffer, false);
ack_packet(packet);
}
void read_dma(Block::sector_t block_number,
Genode::size_t block_count,
Genode::addr_t phys,
Block::Packet_descriptor &packet)
{
_read(block_number, block_count, (char*)phys, true);
ack_packet(packet);
}
void write_dma(Block::sector_t block_number,
Genode::size_t block_count,
Genode::addr_t phys,
Block::Packet_descriptor &packet)
{
_write(block_number, block_count, (char*)phys, true);
ack_packet(packet);
}
bool dma_enabled() { return _dma; }
};
class Atapi_device : public Device
{
private:
int read_sense(unsigned char *sense, int length);
void read_capacity();
void _read(Block::sector_t block_number,
Genode::size_t block_count,
char *out_buffer,
bool dma);
void _write(Block::sector_t block_number,
Genode::size_t block_count,
char const *buffer,
bool dma);
public:
Atapi_device(unsigned base_cmd, unsigned base_ctrl);
bool test_unit_ready(int level = 0);
Block::Session::Operations ops();
};
}
#endif

@ -1,155 +0,0 @@
/*
* \brief ATAPI specific implementation of an Ata::Device
* \author Sebastian.Sumpf <sebastian.sumpf@genode-labs.com>
* \date 2010-07-19
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/env.h>
#include <base/printf.h>
#include <util/string.h>
/* local includes */
#include "ata_device.h"
#include "ata_bus_master.h"
#include "endian.h"
#include "mindrvr.h"
static const int verbose = 0;
using namespace Ata;
using namespace Genode;
enum Commands {
CMD_READ_10 = 0x28,
CMD_READ_CAPACITY = 0x25,
CMD_REQUEST_SENSE = 0x03,
CMD_TEST_UNIT_READY = 0x00,
};
Atapi_device::Atapi_device(unsigned base_cmd, unsigned base_ctrl)
: Device(base_cmd, base_ctrl) { }
int Atapi_device::read_sense(unsigned char *sense, int length)
{
unsigned char cmd_sense[12];
memset(cmd_sense, 0, 12);
memset(sense, 0, length);
cmd_sense[0] = CMD_REQUEST_SENSE;
cmd_sense[4] = length; /* allocation length */
return reg_packet(dev_num(), 12, cmd_sense, 0, length, sense);
}
bool Atapi_device::test_unit_ready(int level)
{
unsigned char cmd[12];
memset(cmd, 0, 12);
cmd[0] = CMD_TEST_UNIT_READY;
if (reg_packet(dev_num(), 12, cmd, 0, 0, 0)) {
unsigned char sense[32];
read_sense(sense, 32);
PERR("Sense: key %x sub-key %x", sense[2], sense[12]);
if (level < 3)
return test_unit_ready(level + 1);
else {
return false;
}
}
return true;
}
void Atapi_device::read_capacity()
{
unsigned char cmd[12];
unsigned buffer[2];
memset(cmd, 0, 12);
memset(buffer, 0, 8);
cmd[0] = CMD_READ_CAPACITY;
if (!test_unit_ready())
throw Io_error();
if (reg_packet(dev_num(), 12, cmd, 0, 8, (unsigned char *)buffer))
throw Io_error();
_block_start = 0;
_block_end = bswap32(buffer[0]);
_block_size = bswap32(buffer[1]);
if (verbose)
PDBG("First block: %u last block %u, block size %u",
_block_start, _block_end, _block_size);
}
void Atapi_device::_read(Block::sector_t block_nr,
Genode::size_t count,
char *buffer,
bool dma)
{
unsigned char cmd[12];
memset(cmd, 0, 12);
cmd[0] = CMD_READ_10;
block_nr += _block_start;
if (block_nr < _block_start || block_nr + count > _block_end + 1)
throw Io_error();
/* block address */
cmd[2] = (block_nr >> 24) & 0xff;
cmd[3] = (block_nr >> 16) & 0xff;
cmd[4] = (block_nr >> 8) & 0xff;
cmd[5] = block_nr & 0xff;
/* transfer length */
cmd[7] = (count >> 8) & 0xff;
cmd[8] = count & 0xff;
if (dma) {
if (verbose)
PDBG("DMA read: block %llu, count %zu, buffer: %p",
block_nr, count, (void*)buffer);
if (dma_pci_packet(dev_num(), 12, cmd, 0, count * _block_size,
(unsigned char*)buffer))
throw Io_error();
} else {
if (reg_packet(dev_num(), 12, cmd, 0, count * _block_size,
(unsigned char*)buffer))
throw Io_error();
}
}
void Atapi_device::_write(Block::sector_t block_number,
Genode::size_t block_count,
char const *buffer,
bool dma) { throw Io_error(); }
Block::Session::Operations Atapi_device::ops()
{
Block::Session::Operations o;
o.set_operation(Block::Packet_descriptor::READ);
return o;
}

@ -1,387 +0,0 @@
MINDRVR
Simple ATA/ATAPI Low Level Driver for Embedded Systems
User's Guide
by Hale Landis
Version 0G and higher
INTRODUCTION
------------
MINDRVR is a simple version of ATADRVR. ATADRVR is Hale Landis'
C code that shows the low level programming required to configure
and execute commands on ATA and ATAPI devices. MINDRVR is
suitable for embedded systems that have simple ATA interface
hardware that is memory mapped. MINDRVR does not have some
features of ATADRVR, such as, the command and low level trace
facility, no support for ATA CHS addressing, no and checking of
ATAPI command protocol errors.
MINDRVR is fully contained in two files: MINDRVR.H and
MINDRVR.C.
MINDRVR, like ATADRVR, supports all of the ATA and ATA/ATAPI
standards.
The MINDRVR C code has been placed into the public domain by Hale
Landis. This C code has no copyright or other restrictions on
how it is used.
USING MINDRVR
-------------
Normally a "file system" driver would call MINDRVR to perform actual
phyical I/O operations on ATA or ATAPI devices using PIO or DMA data
transfer modes. Any program or driver that calls MINDRVR must include
the MINDRVR.H header file. MINDRVR.H defines all the MINDRVR public
functions and public data.
The basics of using MINDRVR are:
1) Review the MINDRVR.H and MINDRVR.C files. In these files look
for comment lines that have the string '!!!'. These comments
explain the information you must provide at compile time, such
as, the memory addresses for the ATA registers in your
system's memory.
2) #include "mindrvr.h" in your program or driver that will call
MINDRVR.
3) Call reg_config() so that MINDRVR can determine what devices
are attached to the ATA host adapter.
4) Call reg_reset() or any of the other "reg_" functions to issue
ATA or ATAPI commands in PIO data transfer mode. If your
system can support ATA/ATAPI DMA then call the dma_pci_"
functions to issue ATA or ATAPI commands in DMA data transfer
mode.
Note that MINDRVR is designed for systems with a single ATA
controller (single ATA inteface). If you system has multiple ATA
controllers/interfaces then you will need to either: a) make a
separate MINDRVR for each controller, or b) switch between
controllers by swapping the MINDRVR configuration information
between calls to MINDRVR.
MINDRVR REFERENCE
-----------------
Each of the public functions and symbols of MINDRVR are described
below in alphabetical order.
Note that there is no "interrupt handler" defined by MINDRVR.
You must supply the appropriate interrupt handler as described in
MINDRVR.H and MINDRVR.C.
Public Data
-----------
unsigned char int_ata_status;
When using interrupts the interrupt handler must return this
data. This is the interrupting device's ATA status as read by
interrupt handler.
unsigned char int_bmide_status;
When using interrupts the interrupt handler must return this
data. This is the interrupting controller's BMIDE status read
by interrupt handler.
unsigned char int_use_intr_flag;
MINDRVR can be switched between polling mode and interrupt
mode. Note that interrupt mode is required for DMA data
transfers.
Make this value not zero to use interrupts.
unsigned char pio_xfer_width;
This variable controls the width of PIO data transfers.
This variable can have the following values:
8 = 8-bits. PIO transfers will use 8-bit memory write/read
when accessing the ATA Data register.
16 = 16-bits. PIO transfers will use 16-bit memory write/read
when accessing the ATA Data register.
32 = 32-bits. PIO transfers will 32-bit memory write/read
when accessing the ATA Data register.
Any other value is treated the same as 16.
struct REG_CMD_INFO
{
// command code
unsigned char cmd; // command code
// command parameters
unsigned int fr; // feature (8 or 16 bits)
unsigned int sc; // sec cnt (8 or 16 bits)
unsigned int sn; // sec num (8 or 16 bits)
unsigned int cl; // cyl low (8 or 16 bits)
unsigned int ch; // cyl high (8 or 16 bits)
unsigned char dh; // device head
unsigned char dc; // device control
long ns; // actual sector count
int mc; // current multiple block setting
unsigned char lbaSize; // size of LBA used
#define LBACHS 0 // last command used ATA CHS (not supported by MINDRVR)
// -or- last command was ATAPI PACKET command
#define LBA28 28 // last command used ATA 28-bit LBA
#define LBA48 48 // last command used ATA 48-bit LBA
unsigned long lbaLow; // lower 32-bits of ATA LBA
unsigned long lbaHigh; // upper 32-bits of ATA LBA
// status and error regs
unsigned char st; // status reg
unsigned char as; // alt status reg
unsigned char er ; // error reg
// driver error codes
unsigned char ec; // detailed error code
unsigned char to; // not zero if time out error
// additional result info
long totalBytesXfer; // total bytes transfered
long drqPackets; // number of PIO DRQ packets
} ;
struct REG_CMD_INFO reg_cmd_info;
This data structure contains information about the last reset or command
that was executed.
int reg_config( void );
This function shoul be called so that MINDRVR can correctly
configure itself. reg_config() sets the values into
reg_config_info[2].
Note that the program calling MINDRVR may bypass calling this
function as long as reg_config_info[] is set appropriately
before attempting to execute any resets or commands.
int reg_config_info[2];
This array is set by calling reg_config(). reg_config_info[0]
describes device 0 and reg_config_info[1] describes device 1.
The possible values in these words are (see MINDRVR.H):
REG_CONFIG_TYPE_NONE, REG_CONFIG_TYPE_UNKN,
REG_CONFIG_TYPE_ATA, REG_CONFIG_TYPE_ATAPI.
Note that MINDRVR is not able to determine the type of some
devices. However, after issuing some commands the calling
program may be able to determine the exact type of a device.
The calling program may change the values in this array but
this must be done very carefully:
a) DO NOT CHANGE the value REG_CONFIG_TYPE_NONE.
b) DO NOT CHANGE a value to REG_CONFIG_TYPE_NONE.
c) The value REG_CONFIG_TYPE_UNKN can be changed to either
REG_CONFIG_TYPE_ATA or REG_CONFIG_TYPE_ATAPI.
int reg_non_data_lba28( unsigned char dev, // device (0 or 1)
unsigned char cmd, // command register
int fr, // feature register
int sc, // sector count
long lba ); // LBA
Execute an ATA Non-Data command using LBA sector addressing.
Returns 0 if no error or 1 if there is an error. See the
contents of reg_cmd_info.
int reg_non_data_lba48( unsigned char dev, // device (0 or 1)
unsigned char cmd, // command register
int fr, // feature register
int sc, // sector count
long lbahi, // LBA upper 16-bits
long lbalo ); // LBA lower 32 bits
Execute an ATA Non-Data command using LBA sector addressing.
Returns 0 if no error or 1 if there is an error. See the
contents of reg_cmd_info.
int reg_packet( unsigned char dev, // device (0 or 1)
unsigned int cpbc, // command packet size
unsigned char * cdbBufAddr, // CDB buffer
int dir, // 0 for no data or read, 1 for write
unsigned int dpbc, // max data packet size
unsigned char * dataBufAddr ); // data packet buffer
Execute an ATAPI Packet (A0H) command in PIO mode. Note that
the first byte of the Commmand Packet buffer is the command
code of the "SCSI CDB" that is to be executed by the device.
Returns 0 if no error or 1 if there is an error. See the
contents of reg_cmd_info.
int reg_pio_data_in_lba28( unsigned char dev, // device (0 or 1)
unsigned char cmd, // command register
int fr, // feature register
int sc, // sector count
long lba, // LBA
unsigned char * bufAddr, // buffer address
int numSect, // number of sectors to transfer
int multiCnt ); // current multiple count
Execute an ATA PIO Data In command in LBA sector addressing
mode.
numSect is the actual number of sectors to be transferred.
This value may be different than the sc value.
If cmd is C4H (Read Multiple) then multiCnt MUST be set to the
current sectors per block.
Returns 0 if no error or 1 if there is an error. See the
contents of reg_cmd_info.
int reg_pio_data_in_lba48( unsigned char dev, // device (0 or 1)
unsigned char cmd, // command register
int fr, // feature register
int sc, // sector count
long lbahi, // LBA upper 16-bits
long lbalo, // LBA lower 32 bits
unsigned char * bufAddr, // buffer address
int numSect, // number of sectors to transfer
int multiCnt ); // current multiple count
Execute an ATA PIO Data In command in LBA sector addressing
mode.
numSect is the actual number of sectors to be transferred.
This value may be different than the sc value.
If cmd is C4H (Read Multiple) then multiCnt MUST be set to the
current sectors per block.
Returns 0 if no error or 1 if there is an error. See the
contents of reg_cmd_info.
int reg_pio_data_out_lba28( unsigned char dev, // device (0 or 1)
unsigned char cmd, // command register
int fr, // feature register
int sc, // sector count
long lba, // LBA
unsigned char * bufAddr, // buffer address
int numSect, // number of sectors to transfer
int multiCnt ); // current multiple count
Execute an ATA PIO Data Out command in LBA sector addressing
mode.
numSect is the actual number of sectors to be transferred.
This value may be different than the sc value.
If cmd is C5H (Write Multiple) then multiCnt MUST be set to
the current sectors per block.
Returns 0 if no error or 1 if there is an error. See the
contents of reg_cmd_info.
int reg_pio_data_out_lba48( unsigned char dev, // device (0 or 1)
unsigned char cmd, // command register
int fr, // feature register
int sc, // sector count
long lbahi, // LBA upper 16-bits
long lbalo, // LBA lower 32 bits
unsigned char * bufAddr, // buffer address
int numSect, // number of sectors to transfer
int multiCnt ); // current multiple count
Execute an ATA PIO Data Out command in LBA sector addressing
mode.
numSect is the actual number of sectors to be transferred.
This value may be different than the sc value.
If cmd is C5H (Write Multiple) then multiCnt MUST be set to
the current sectors per block.
Returns 0 if no error or 1 if there is an error. See the
contents of reg_cmd_info.
int reg_reset( unsigned char devRtrn ); // device's data returned
Execute an ATA Soft Reset. Set devRtrn to 0 or 1 to determine
which device's register contents are returned in reg_cmd_info.
DMA Data Transfer Functions And Data
------------------------------------
These functions setup PCI bus DMA (ATA Multiword or Ultra DMA)
and perform ATA and ATAPI commands using DMA. The function
dma_pci_config() MUST be called with no error before any of the
other functions will attempt to execute a command.
int dma_pci_config( void );
Configure MINDRVR to use PCI bus DMA (ATA Multiword or Ultra
DMA) on a PCI Bus Mastering ATA controller.
This function may not be needed in your system - see the MINDRVR.H
and MINDRVR.C files.
int dma_pci_lba28( unsigned char dev, // device (0 or 1)
unsigned char cmd, // command register
int fr, // feature register
int sc, // sector count
long lba, // LBA
unsigned char * bufAddr ); // buffer address
Execute an ATA Read DMA (C8H) or ATA Write DMA (CAH) command
using LBA sector addressing.
Returns 0 if no error or 1 if there is an error. See the
contents of reg_cmd_info.
int dma_pci_lba48( unsigned char dev, // device (0 or 1)
unsigned char cmd, // command register
int fr, // feature register
int sc, // sector count
long lbahi, // LBA upper 16-bits
long lbalo, // LBA lower 32 bits
unsigned char * bufAddr ); // buffer address
Execute an ATA Read DMA (C8H) or ATA Write DMA (CAH) command
using LBA sector addressing.
Returns 0 if no error or 1 if there is an error. See the
contents of reg_cmd_info.
int dma_pci_packet( unsigned char dev, // device (0 or 1)
unsigned int cpbc, // command packet size
unsigned char * cdbBufAddr, // CDB buffer
int dir, // 0 for no data or read, 1 for write
unsigned int dpbc, // max data packet size
unsigned char * dataBufAddr ); // data packet buffer
Execute an ATAPI Packet (A0H) command in DMA mode. Note that
the first byte of the Commmand Packet buffer is the command
code of the "SCSI CDB" that is to be executed by the device.
Returns 0 if no error or 1 if there is an error. See the
contents of reg_cmd_info.
QUESTIONS OR PROBLEMS?
----------------------