Initial import of block device refactoring.
authorGerd Zellweger <mail@gerdzellweger.com>
Fri, 15 Jul 2016 08:32:19 +0000 (10:32 +0200)
committerGerd Zellweger <mail@gerdzellweger.com>
Mon, 25 Jul 2016 11:02:11 +0000 (13:02 +0200)
- Refactors existing AHCI code to use device queue interface.
- Adds harness test for disks.
- Adds some minor improvements for scalebench harness.
- Disable vtd due to some bug with the identity mapping on babybel machines.

Signed-off-by: Gerd Zellweger <mail@gerdzellweger.com>

Conflicts:
usr/acpi/acpi_main.c

52 files changed:
devices/ahci_port.dev
errors/errno.fugu
include/ahci/ahci.h [deleted file]
include/ahci/ahci_defs.h [deleted file]
include/ahci/ahci_dma_pool.h [deleted file]
include/ahci/ahci_util.h [deleted file]
include/blk/ahci.h [new file with mode: 0644]
include/device_interfaces/device_queue_interface.h [deleted file]
include/devif/queue.h [new file with mode: 0644]
include/pci/pci_client_debug.h
lib/ahci/Hakefile [deleted file]
lib/ahci/ahci.c [deleted file]
lib/ahci/ahci_debug.h [deleted file]
lib/ahci/ahci_dma_pool.c [deleted file]
lib/ahci/ahci_internal.h [deleted file]
lib/ahci/ahci_util.c [deleted file]
lib/ahci/sata_fis.c [deleted file]
lib/ahci/storage_vsic.c [deleted file]
lib/barrelfish/waitset.c
lib/blk/Hakefile [new file with mode: 0644]
lib/blk/blk.c [new file with mode: 0644]
lib/blk/blk_ahci/ahci_dev.c [new file with mode: 0644]
lib/blk/blk_ahci/ahci_dev.h [new file with mode: 0644]
lib/blk/blk_ahci/ahci_init.c [new file with mode: 0644]
lib/blk/blk_ahci/ahci_port.c [new file with mode: 0644]
lib/blk/blk_ahci/blk_ahci.h [new file with mode: 0644]
lib/blk/blk_ahci/device_impl.c [new file with mode: 0644]
lib/blk/blk_ahci/sata_fis.c [new file with mode: 0644]
lib/blk/blk_ahci/sata_fis.h [moved from include/ahci/sata_fis.h with 62% similarity]
lib/blk/blk_debug.h [new file with mode: 0644]
lib/blk/dma_mem/dma_mem.c [new file with mode: 0644]
lib/blk/dma_mem/dma_mem.h [new file with mode: 0644]
lib/pci/pci_client.c
tools/harness/barrelfish.py
tools/harness/harness.py
tools/harness/machines/eth_machinedata.py
tools/harness/reprocess.py
tools/harness/results.py
tools/harness/tests/blk_tests.py [new file with mode: 0644]
usr/acpi/arch/x86/acpi_main.c
usr/ahcid/Hakefile [deleted file]
usr/ahcid/ahcid.c [deleted file]
usr/ahcid/ahcid.h [deleted file]
usr/ahcid/ahcid_debug.h [deleted file]
usr/ahcid/ahcid_hwinit.c [deleted file]
usr/drivers/ahcid/Hakefile [new file with mode: 0644]
usr/drivers/ahcid/ahcid.c [new file with mode: 0644]
usr/drivers/ahcid/ahcid.h [new file with mode: 0644]
usr/drivers/ahcid/test.c [new file with mode: 0644]
usr/drivers/ahcid/test.h [new file with mode: 0644]
usr/pci/pci.c
usr/pci/pci_service.c

index 23715e8..8b0afa6 100644 (file)
  * ahci_port.dev
  *
  * DESCRIPTION: AHCI (SATA) Host bus adaptor, per-port registers
- * 
+ *
  * Section numbers refer to the Serial ATA Advanced Host Controller
  *   Interface (AHCI) specification 1.3, June 2008
  */
 
 device ahci_port msbfirst (addr b) "AHCI port" {
 
-    // 3.3.1-2 
+    // 3.3.1-2
     // Low 10 bits mbz
     register clb rw addr(b,0x00) "Command list base address" type(uint64);
-    
+
     // 3.3.3-4
     // Low 10 bits mbz
     register fb rw addr(b,0x08) "FIS base address" type(uint64);
-    
+
     // 3.3.5
     register is addr(b,0x10) "Interrupt status" {
        cpds    1 rw1c "Cold port detect";
@@ -47,7 +47,7 @@ device ahci_port msbfirst (addr b) "AHCI port" {
        pss     1 rw1c "PIO setup FIS interrupt";
        dhrs    1 rw1c "Device to host register FIS interrupt";
     };
-    
+
     // 3.3.6
     register ie addr(b,0x14) "Interrupt enable" {
        cpde    1 rw "Cold port detect";
@@ -70,8 +70,8 @@ device ahci_port msbfirst (addr b) "AHCI port" {
        pse     1 rw "PIO setup FIS interrupt";
        dhre    1 rw "Device to host register FIS interrupt";
     };
-    
-    // 3.3.7 
+
+    // 3.3.7
     constants icct "Interface communication control" {
        slumber = 0x6 "Slumber";
        partial = 0x2 "Partial";
@@ -104,13 +104,17 @@ device ahci_port msbfirst (addr b) "AHCI port" {
        st      1 rw "Start";
     };
 
-    // 3.3.8 
+    // 3.3.8
     register tfd ro addr(b,0x20) "Task file data" {
        _       16 rsvd;
        err     8 "Error";
-       sts     8 "Status (task file status)";
+    bsy 1 ro    "Indicates the interface is busy";
+    cs2 3 ro    "Command specific";
+    drq 1 ro    "Indicates a data transfer is requested";
+    cs1 2 ro    "Command specific";
+    serr 1 ro    "Indicates an error during the transfer.";
     };
-    
+
     // 3.3.9
     register sig ro addr(b,0x24) "Signature" {
        lbah    8 "LBA high";
@@ -118,7 +122,7 @@ device ahci_port msbfirst (addr b) "AHCI port" {
        lbal    8 "LBA low";
        sectors 8 "Sector count";
     };
-    
+
     // 3.3.10
     constants speed "Interface speed" {
        gen1    = 0b0001 "Gen 1 (1.5 Gbps)";
@@ -137,7 +141,7 @@ device ahci_port msbfirst (addr b) "AHCI port" {
        spd     4 type(speed) "Current interface speed";
        det     4 type(dets) "Device detection";
     };
-    
+
     // 3.3.11
     constants ipmall "Interface transitions" {
        noipm   = 0x0 "No interface restrictions";
@@ -183,13 +187,13 @@ device ahci_port msbfirst (addr b) "AHCI port" {
 
     // 3.3.14
     register ci rw addr(b,0x38) "Command issue" type(uint32);
-    
-    // 3.3.15 
+
+    // 3.3.15
     register sntf addr(b,0x3c) "Serial ATA notification" {
        _       16 mbz;
        pmn     16 rw1c "PMN notify";
     };
-    
+
     // 3.3.16
     register fbs addr(b,0x40) "FIS-based switching control" {
        _       12 mbz;
@@ -214,12 +218,11 @@ device ahci_port msbfirst (addr b) "AHCI port" {
        w       1 "Write";
        a       1 "ATAPI";
        cfl     5 "Command FIS length";
-       
+
        prdbc   32 "Physical region descriptor byte count";
-       
-       ctba    32 "Command table descriptor base address";
-       
-       ctbau   32 "Command table descriptor base address upper";
+
+       ctba    64 "Command table descriptor base address";
+
        _       32;
        _       32;
        _       32;
@@ -235,7 +238,7 @@ device ahci_port msbfirst (addr b) "AHCI port" {
        _       9;
        dbc     22 "Data byte count";
     };
-    
+
     // 12.2
     constants emtype "Enclosure message type" {
        led     = 0x0 "LED";
@@ -250,7 +253,7 @@ device ahci_port msbfirst (addr b) "AHCI port" {
        msize   8 "Message size";
        _       8;
     };
-    
+
     // 12.2.1
     constants emledstate "Enclosure LED state" {
        off     = 0b000 "LED shall be off";
index 320fe97..bedd73c 100755 (executable)
@@ -132,7 +132,7 @@ errors kernel SYS_ERR_ {
     failure VMKIT_CTRL_INVALID          "Invalid frame capability passed for control structure",
     failure VMKIT_ENDPOINT              "Error setting monitor endpoint for dispatcher",
     failure VMKIT_ENDPOINT_INVALID      "Invalid monitor endpoint capability passed",
-    failure VMKIT_VMX_VMFAIL_INVALID   "The VMCS pointer is invalid", 
+    failure VMKIT_VMX_VMFAIL_INVALID   "The VMCS pointer is invalid",
     failure VMKIT_VMX_VMFAIL_VALID      "VMX instruction failed (VM-instruction error field = ErrorNumber)",
 
     // Serial port errors
@@ -1000,8 +1000,9 @@ errors vbe VBE_ERR_ {
     failure BIOS_CALL_FAILED    "Unknown error returned from VBE BIOS call",
 };
 
-// errors generated by ahcid and libahci
+// errors generated by lib/blk/ahci
 errors ahcid AHCI_ERR_ {
+    failure PORT_INIT           "Port initialization failed",
     failure PORT_INVALID        "Provided port id is not valid",
     failure PORT_BUSY           "Port has been opened elsewhere",
     failure PORT_MISMATCH       "Port is not opened by client",
@@ -1009,6 +1010,17 @@ errors ahcid AHCI_ERR_ {
     failure ILLEGAL_ARGUMENT    "Illegal argument in call",
 };
 
+// errors generated by devif
+errors ahcid DEV_ERR_ {
+    failure NOT_INITIALIZED     "Queue exists but could not be initialized.",
+    failure NOT_FOUND           "Invalid queue requested, not found?",
+    failure ALREADY_CREATED     "The queue specified has already been created.",
+    failure REGISTER_BUFFER     "Unable to register the buffer with the driver.",
+    failure INVALID_BUFFER_ARGS "Invalid arguments for specified buffer.",
+    failure QUEUE_EMPTY         "Nothing to dequeue.",
+    failure QUEUE_FULL          "The queue is full.",
+};
+
 errors sata SATA_ERR_ {
     failure INVALID_TYPE        "Unknown FIS type or invalid/unimplemented field for type",
 };
@@ -1080,8 +1092,8 @@ errors bulk_transfer BULK_TRANSFER_ {
     failure SM_EXCLUSIVE_WS     "BULK_SM: Exclusive waitset required per channel.",
     failure NET_MAX_QUEUES      "The number of maximum queues is reached",
     failure NET_POOL_USED       "The pool is already used over a no-copy channel.",
-    
-    
+
+
 };
 
 errors virtio VIRTIO_ERR_ {
@@ -1101,14 +1113,14 @@ errors virtio VIRTIO_ERR_ {
     failure QUEUE_INVALID        "The selected queue does not exist",
     failure QUEUE_BUSY           "The queue is busy.",
     failure BUFFER_SIZE          "The buffer size is invalid.",
-    failure BUFFER_STATE         "The state of the buffer / buffer list is invalid",               
+    failure BUFFER_STATE         "The state of the buffer / buffer list is invalid",
     failure ARG_INVALID          "The given argument is invalid.",
     failure NO_BUFFER            "No buffer given, number of buffers is 0",
     failure ALLOC_FULL           "The allocator is already full",
     failure BUFFER_USED          "The buffer is already enqueued and used",
     failure NO_DESC_AVAIL        "There is no descriptor availabe",
     failure DEQ_CHAIN            "Not the entire chain could be dequeued",
-    failure INVALID_RING_INDEX   "The supplied index is not valid", 
+    failure INVALID_RING_INDEX   "The supplied index is not valid",
     failure BLK_REQ_IOERR        "The request ended in an IO error",
     failure BLK_REQ_UNSUP        "The request type was not supported",
 };
diff --git a/include/ahci/ahci.h b/include/ahci/ahci.h
deleted file mode 100644 (file)
index 78925a9..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2011 ETH Zurich.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
- */
-
-#ifndef _AHCI_H
-#define _AHCI_H
-
-#include <barrelfish/waitset.h>
-#include <barrelfish/idc.h>
-#include <barrelfish/event_mutex.h>
-#include <flounder/flounder.h>
-#include <ahci/ahci_util.h>
-#include <ahci/ahci_dma_pool.h>
-#include <dev/ata_identify_dev.h>
-
-struct ahci_binding;
-
-typedef void ahci_bind_continuation_fn(void *st, errval_t err,
-               struct ahci_binding *_binding);
-typedef bool ahci_can_send_fn(struct ahci_binding *_binding);
-typedef errval_t ahci_register_send_fn(struct ahci_binding *_binding,
-               struct waitset *ws, struct event_closure _continuation);
-typedef errval_t ahci_change_waitset_fn(struct ahci_binding *_binding,
-               struct waitset *ws);
-typedef errval_t ahci_control_fn(struct ahci_binding *_binding,
-               idc_control_t control);
-typedef void ahci_error_handler_fn(struct ahci_binding *_binding, errval_t err);
-
-/*
- * Message type signatures (receive)
- */
-typedef void ahci_command_completed_method_fn(struct ahci_binding *_binding,
-               void *tag);
-
-/*
- * Receive VTable
- */
-struct ahci_rx_vtbl {
-    ahci_command_completed_method_fn *command_completed;
-};
-
-/*
- * The binding structure
- */
-struct ahci_binding {
-    /* user state */
-    void *st;
-
-    /* waitset for receive handlers and send continuations */
-    struct waitset *waitset;
-
-    /* Mutex for the use of user code. */
-    /* Must be held before any operation where there is a possibility of */
-    /* concurrent access to the same binding (eg. multiple threads, or */
-    /* asynchronous event handlers that use the same binding object). */
-    struct event_mutex mutex;
-
-    /* returns true iff a message could currently be accepted by the binding */
-    ahci_can_send_fn *can_send;
-
-    /* register an event for when a message is likely to be able to be sent */
-    ahci_register_send_fn *register_send;
-
-    /* change the waitset used by a binding */
-    ahci_change_waitset_fn *change_waitset;
-
-    /* perform control operations */
-    ahci_control_fn *control;
-
-    /* error handler for async errors */
-    ahci_error_handler_fn *error_handler;
-
-    /* Message receive functions (filled in by user) */
-    struct ahci_rx_vtbl rx_vtbl;
-
-    /* Private state belonging to the binding implementation */
-    uint8_t port_id;
-    struct ahci_port_info port_info;
-    struct waitset_chanstate register_chanstate;
-    struct waitset_chanstate tx_cont_chanstate;
-
-    uint8_t *identify_data;
-    size_t identify_length;
-    ata_identify_t identify;
-};
-
-errval_t ahci_issue_command(struct ahci_binding *_binding,
-               struct event_closure _continuation, void *tag, uint8_t *fis,
-               size_t fis_length, bool is_write, struct ahci_dma_region *buf,
-               size_t buflen);
-
-errval_t ahci_close(struct ahci_binding *_binding,
-               struct event_closure _continuation);
-
-errval_t ahci_init(uint8_t port, ahci_bind_continuation_fn *_continuation,
-               void *st, struct waitset *waitset);
-
-#endif // _AHCI_H
diff --git a/include/ahci/ahci_defs.h b/include/ahci/ahci_defs.h
deleted file mode 100644 (file)
index 0d9b52e..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright (c) 2011 ETH Zurich.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
- */
-
-#ifndef __AHCI_DEFS_H
-#define __AHCI_DEFS_H
-
-#include <ahci/ahci.h>
-
-#endif
diff --git a/include/ahci/ahci_dma_pool.h b/include/ahci/ahci_dma_pool.h
deleted file mode 100644 (file)
index 8fb2bc7..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2011 ETH Zurich.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
- */
-
-#ifndef _AHCI_DMA_POOL_H
-#define _AHCI_DMA_POOL_H
-#include <string.h>
-
-struct ahci_dma_region {
-    void *vaddr;
-    genpaddr_t paddr;
-    size_t size;
-    size_t backing_region;
-};
-
-errval_t ahci_dma_pool_init(size_t pool_size);
-errval_t ahci_dma_region_alloc(size_t size, struct ahci_dma_region **retregion);
-errval_t ahci_dma_region_alloc_aligned(size_t size, size_t alignment_requirement, struct ahci_dma_region **retregion);
-errval_t ahci_dma_region_free(struct ahci_dma_region *region);
-
-static inline void *ahci_dma_region_copy_in(struct ahci_dma_region *region, const void *buf, genvaddr_t offset, size_t size) {
-    void *dest = (char *)region->vaddr + offset;
-    return memcpy(dest, buf, size);
-}
-static inline void *ahci_dma_region_copy_out(struct ahci_dma_region *region, void *buf, genvaddr_t offset, size_t size) {
-    void *src_ = (char *)region->vaddr + offset;
-    return memcpy(buf, src_, size);
-}
-
-#endif // _AHCI_DMA_POOL_H
diff --git a/include/ahci/ahci_util.h b/include/ahci/ahci_util.h
deleted file mode 100644 (file)
index 7d45a98..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2011 ETH Zurich.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
- */
-
-#ifndef _AHCI_UTIL_H
-#define _AHCI_UTIL_H
-
-#include <barrelfish/barrelfish.h>
-#include <ahci/ahci_dma_pool.h>
-#include <dev/ahci_port_dev.h>
-
-#define PORT_SIZE 0x80
-
-#define BLOCK_SIZE 512
-
-// The QEMU AHCI emulation only supports PRDs of size 512 bytes
-// PR_SIZE can be used together with AHCI_FIXED_PR_SIZE to enforce 
-// PRs of fixed size specified in PR_SIZE
-// If not forced, PRs will be of arbitrary size with max length 4MB as 
-// specified in the AHCI spec
-#define PR_SIZE 512
-#define MAX_PR_SIZE (128 * 1024)
-
-#define PRDT_OFFSET 0x80
-
-#ifndef CEIL_DIV
-#define CEIL_DIV(x, d) (((x) + ((d)-1)) / (d))
-#endif
-
-struct ahci_command_slot {
-    struct ahci_dma_region *command_table;
-    bool in_use;
-    void *tag;
-};
-
-struct ahci_port_info {
-    ahci_port_t port;
-    void *mapped_vaddr;
-    void *port_base;
-    struct ahci_dma_region *command_list;
-    struct ahci_dma_region *receive_fis;
-    struct ahci_command_slot command_slots[32];
-    uint32_t hba_capabilities;
-    struct capref hba_cap;
-};
-
-errval_t ahci_port_alloc_dma_structs(ahci_port_t *port,
-        struct ahci_dma_region **command_list,
-        struct ahci_dma_region **receive_fis);
-
-#endif // _AHCI_UTIL_H
diff --git a/include/blk/ahci.h b/include/blk/ahci.h
new file mode 100644 (file)
index 0000000..8c726e3
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2016, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef _AHCI_
+#define _AHCI_
+
+#include <barrelfish/barrelfish.h>
+#include <pci/mem.h>
+
+struct ahci_disk;
+
+errval_t blk_ahci_init(struct device_mem* bar5, struct ahci_disk** out);
+errval_t blk_ahci_stop(struct ahci_disk* ad);
+
+#endif // _AHCI_
diff --git a/include/device_interfaces/device_queue_interface.h b/include/device_interfaces/device_queue_interface.h
deleted file mode 100644 (file)
index 478e91f..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (c) 2016 ETH Zurich.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
- */
-#ifndef DEVICE_QUEUE_INTERFACE_H_
-#define DEVICE_QUEUE_INTERFACE_H_ 1
-
-
-#include <barrelfish/barrelfish.h>
-
-typedef uint32_t regionid_t;
-typedef uint32_t bufferid_t;
-
-/**
- * Represent the device queue itself
- */
-struct device_queue {
-
-    uint32_t queue_id;
-
-    // name of the device
-    char* device_name;
-    // pointer to device queue state
-    void* q_state;
-
-    //TODO Other state needed ...
-    
-};
-
-
-struct device_queue_buffer {
-    // region id to which the buffer belongs
-    regionid_t region_id;
-    // id within the region
-    bufferid_t buffer_id;
-    // physical base address of the buffer
-    lpaddr_t base;
-    // length of the buffer
-    size_t len;
-}
-
-/*
- * ===========================================================================
- * Device queue creation and destruction
- * ===========================================================================
- */
-
-
- /**
-  * @brief creates a queue 
-  *
-  * @param q             Return pointer to the device_queue (handle)
-  * @param device_name   Device name of the device to which this queue belongs
-  *                      (Driver itself is running in a separate process)
-  * @param misc          Anything you can think of that makes sense for the device
-  *                      and its driver?
-  *
-  * @returns error on failure or SYS_ERR_OK on success
-  */
-
-errval_t device_queue_create(struct device_queue **q,
-                             char* device_name,
-                             char* misc);
-
-
- /**
-  * @brief destroys the device queue
-  *
-  * @param q           The queue state to free (and the device queue to be 
-                       shut down in the driver)
-  *
-  * @returns error on failure or SYS_ERR_OK on success
-  */
-errval_t device_queue_destroy(struct device_queue *qp);
-
-
-/*
- * ===========================================================================
- * Datapath functions
- * ===========================================================================
- */
-
-/**
- * @brief enqueue a buffer into the device queue
- *
- * @param q             The device queue to call the operation on
- * @param region_id     Id of the memory region the buffer belongs to
- * @param base          Physical address of the start of the enqueued buffer
- * @param lenght        Lenght of the enqueued buffer
- * @param buffer_id     The buffer id of the enqueue buffer (TODO only for 
- *                      fixed size buffers?)
- * @param misc_flags    Any other argument that makes sense to the device queue
- *
- * @returns error on failure or SYS_ERR_OK on success
- *
- */
-errval_t device_queue_enqueue(struct device_queue *q,
-                              regionid_t region_id,
-                              lpaddr_t base,
-                              size_t length,
-                              bufferid_t buffer_id,
-                              char* misc_flags);
-
-/**
- * @brief enqueue some memory into the device queue
- *
- * @param q             The device queue to call the operation on
- * @param buf           Buffer to enqueue (includes physical address, lenght, 
- *                      region id and buffer id)
- * @param misc_flags    Any other argument that makes sense to the device queue
- *
- * @returns error on failure or SYS_ERR_OK on success
- *
- */
-errval_t device_queue_enqueue(struct device_queue *q,
-                              struct device_queue_buffer* buf,
-                              char* misc_flags);
-
-
-/**
- * @brief dequeue a buffer from the device queue
- *
- * @param q             The device queue to call the operation on
- * @param region_id     Return pointer to the id of the memory 
- *                      region the buffer belongs to
- * @param base          Return pointer to the physical address of 
- *                      the of the buffer
- * @param lenght        Return pointer to the lenght of the dequeue buffer
- * @param buffer_id     Return pointer to thehe buffer id of the dequeued buffer
- *
- * @returns error on failure or SYS_ERR_OK on success
- *
- */
-errval_t device_queue_dequeue(struct device_queue *q,
-                              regionid_t* region_id,
-                              lpaddr_t* base,
-                              size_t* length,
-                              bufferid_t* buffer_id);
-
-/**
- * @brief dequeue a buffer from the device queue
- *
- * @param q             The device queue to call the operation on
- * @param buf           Return pointer to the dequeued buffer
- *
- * @returns error on failure or SYS_ERR_OK on success
- *
- */
-errval_t device_queue_dequeue(struct device_queue *q,
-                              struct device_queue_buf** buf);
-/*
- * ===========================================================================
- * Control Path
- * ===========================================================================
- */
-
-/**
-* @brief Add a memory region that can be used as buffers to 
-*        the device queue
-*
-* @param q              The device queue to call the operation on
-* @param cap            A Capability for some memory
-* @param region_id      Return pointer to a region id that is assigned
-*                       to the memory
-*
-* @returns error on failure or SYS_ERR_OK on success
-*
-*/
-errval_t device_queue_register(struct device_queue *q,
-                               struct capref cap,
-                               regionid_t* region_id);
-
-/**
-* @brief Remove a memory region 
-*
-* @param q              The device queue to call the operation on
-* @param region_id      The region id to remove from the device 
-*                       queues memory
-* @param cap            The capability to the removed memory
-*
-* @returns error on failure or SYS_ERR_OK on success
-*
-*/
-errval_t device_queue_register(struct device_queue *q,
-                               regionid_t region_id,
-                               struct capref* cap);
-
-/**
-* @brief Send a notification about new buffers on the queue
-*
-* @param q      The device queue to call the operation on
-*
-* @returns error on failure or SYS_ERR_OK on success
-*
-*/
-errval_t device_queue_sync(struct device_queue *q);
-
-/**
-* @brief Send a control message to the device queue
-*
-* @param q      The device queue to call the operation on
-* @param ctrl   A sting encoding the control message
-*
-* @returns error on failure or SYS_ERR_OK on success
-*
-*/
-errval_t device_queue_control(struct device_queue *q,
-                              char* ctrl);
-
-#endif /* DEVICE_QUEUE_INTERFACE_H_ */
diff --git a/include/devif/queue.h b/include/devif/queue.h
new file mode 100644 (file)
index 0000000..b2869bd
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2016 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+#ifndef DEVICE_QUEUE_INTERFACE_H_
+#define DEVICE_QUEUE_INTERFACE_H_ 1
+
+#include <barrelfish/barrelfish.h>
+
+typedef uint64_t regionid_t;
+typedef uint64_t bufferid_t;
+
+/*
+ * ===========================================================================
+ * Device queue creation and destruction
+ * ===========================================================================
+ */
+
+/**
+ * @brief creates a queue
+ * @returns error on failure or SYS_ERR_OK on success
+ */
+
+errval_t devq_create(void* st, char *device_name, uint64_t flags, void **queue);
+
+/**
+ * @brief destroys the device queue
+ *
+ * @param q           The queue state to free (and the device queue to be
+                      shut down in the driver)
+ *
+ * @returns error on failure or SYS_ERR_OK on success
+ */
+errval_t devq_destroy(void *queue);
+
+/*
+ * ===========================================================================
+ * Datapath functions
+ * ===========================================================================
+ */
+
+/**
+ * @brief enqueue a buffer into the device queue
+ *
+ * @param q             The device queue to call the operation on
+ * @param region_id     Id of the memory region the buffer belongs to
+ * @param base          Physical address of the start of the enqueued buffer
+ * @param length        Length of the enqueued buffer
+ * @param buffer_id     The buffer id of the enqueue buffer (TODO only for
+ *                      fixed size buffers?)
+ * @param misc_flags    Any other argument that makes sense to the device queue
+ *
+ * @returns error on failure or SYS_ERR_OK on success
+ *
+ */
+errval_t devq_enqueue(void *q, regionid_t region_id, lpaddr_t base,
+                      size_t length, bufferid_t buffer_id, uint64_t flags);
+
+/**
+ * @brief dequeue a buffer from the device queue
+ *
+ * @param q             The device queue to call the operation on
+ * @param region_id     Return pointer to the id of the memory
+ *                      region the buffer belongs to
+ * @param base          Return pointer to the physical address of
+ *                      the of the buffer
+ * @param length        Return pointer to the length of the dequeue buffer
+ * @param buffer_id     Return pointer to the buffer id of the dequeued buffer
+ *
+ * @returns error on failure or SYS_ERR_OK on success
+ *
+ */
+errval_t devq_dequeue(void *q, regionid_t *region_id, lpaddr_t *base,
+                      size_t *length, bufferid_t *buffer_id);
+/*
+ * ===========================================================================
+ * Control Path
+ * ===========================================================================
+ */
+
+/**
+* @brief Add a memory region that can be used as buffers to
+*        the device queue
+*
+* @param q              The device queue to call the operation on
+* @param cap            A Capability for some memory
+* @param region_id      Return pointer to a region id that is assigned
+*                       to the memory
+*
+* @returns error on failure or SYS_ERR_OK on success
+*
+*/
+errval_t devq_register(void *q, struct capref cap, regionid_t *region_id);
+
+/**
+* @brief Remove a memory region
+*
+* @param q              The device queue to call the operation on
+* @param region_id      The region id to remove from the device
+*                       queues memory
+* @param cap            The capability to the removed memory
+*
+* @returns error on failure or SYS_ERR_OK on success
+*
+*/
+errval_t devq_remove(void *q, regionid_t region_id);
+
+/**
+* @brief Send a notification about new buffers on the queue
+*
+* @param q      The device queue to call the operation on
+*
+* @returns error on failure or SYS_ERR_OK on success
+*
+*/
+errval_t devq_sync(void *q);
+
+/**
+* @brief Send a control message to the device queue
+*
+* @param q       The device queue to call the operation on
+* @param request A sting encoding the control message
+* @param value   A value for the request.
+*
+* @returns error on failure or SYS_ERR_OK on success
+*
+*/
+errval_t devq_control(void *q, uint64_t request, uint64_t value);
+
+#endif /* DEVICE_QUEUE_INTERFACE_H_ */
index 687fd13..430a7c9 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef PCI_CLIENT_DEBUG_H
 #define PCI_CLIENT_DEBUG_H
 
+#define PCI_LIB_DEBUG 1
+
 #if defined(PCI_LIB_DEBUG) || defined(GLOBAL_DEBUG)
 #define PCI_CLIENT_DEBUG(x...) printf("pci_client: " x)
 #else
diff --git a/lib/ahci/Hakefile b/lib/ahci/Hakefile
deleted file mode 100644 (file)
index e0f8681..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-
---------------------------------------------------------------------------
--- Copyright (c) 2007-2012, ETH Zurich.
--- All rights reserved.
---
--- This file is distributed under the terms in the attached LICENSE file.
--- If you do not find this file, copies can be found by writing to:
--- ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
---
--- Hakefile for lib/ahci
--- 
---------------------------------------------------------------------------
-
-[ build library { target = "ahci",
-                      cFiles = [ "ahci.c", "ahci_util.c", "sata_fis.c", "ahci_dma_pool.c" ],
-                      flounderDefs = [ "ata_rw28" ],
-                      flounderBindings = [ "ahci_mgmt", "ata_rw28" ],
-                      flounderExtraBindings = [ ("ahci_mgmt", ["rpcclient"]),
-                                                ("ata_rw28", ["ahci", "rpcclient"]) ],
-                      mackerelDevices = [ "ata_identify", "ahci_port", "ahci_hba" ],
-                      addLibraries = [ ]
-                },
-  build library { target = "ahci_vsic",
-                      cFiles = [ "ahci.c", "ahci_util.c", "sata_fis.c", "ahci_dma_pool.c", "storage_vsic.c" ],
-                      flounderDefs = [ "ata_rw28" ],
-                      flounderBindings = [ "ahci_mgmt", "ata_rw28" ],
-                      flounderExtraBindings = [ ("ahci_mgmt", ["rpcclient"]),
-                                                ("ata_rw28", ["ahci", "rpcclient"]) ],
-                      mackerelDevices = [ "ata_identify", "ahci_port", "ahci_hba" ],
-                      addLibraries = [ ]
-                }
-]
diff --git a/lib/ahci/ahci.c b/lib/ahci/ahci.c
deleted file mode 100644 (file)
index 962d04a..0000000
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * Copyright (c) 2011, 2012, ETH Zurich.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
- */
-
-#include <barrelfish/barrelfish.h>
-#include <barrelfish/waitset.h>
-#include <barrelfish/waitset_chan.h>
-#include <barrelfish/nameservice_client.h>
-#include <if/ahci_mgmt_defs.h>
-#include <dev/ahci_hba_dev.h> // this is used to parse HBA capabilities
-#include <dev/ahci_port_dev.h>
-#include <ahci/ahci.h>
-#include <ahci/ahci_dma_pool.h>
-#include <ahci/ahci_util.h>
-#include <string.h>
-#include "ahci_debug.h"
-#include "ahci_internal.h"
-
-static struct ahci_mgmt_binding *mgmt_binding;
-
-struct bind_st { // this is to be able to pass 3 params as user state
-    size_t num_ports;
-    struct ahci_binding **ahci_binding;
-    ahci_bind_continuation_fn *cont;
-    void *st;
-    uint8_t port; // only valid in open and identify cb
-};
-
-struct mgmt_close_call_st
-{
-    struct ahci_binding *binding;
-    struct event_closure continuation;
-};
-
-static void ahci_mgmt_identify_response_cb(struct ahci_mgmt_binding *b,
-        uint8_t *identify_data, size_t data_len)
-{
-    struct bind_st *bst = b->st;
-    struct ahci_binding *ahci_binding = bst->ahci_binding[bst->port];
-
-    if (!ahci_binding) {
-        AHCI_DEBUG("got identify data for unbound port\n");
-        return;
-    }
-
-    bool has_identify = ahci_binding->identify_data;
-    if (has_identify) {
-        free(ahci_binding->identify_data);
-    }
-    ahci_binding->identify_data = identify_data;
-    ahci_binding->identify_length = data_len;
-    ata_identify_initialize(&ahci_binding->identify,
-            (void*)ahci_binding->identify_data);
-
-    if (!has_identify) {
-        struct ahci_port_info *port = &ahci_binding->port_info;
-
-        // enable rFIS area and start running commands
-        ahci_port_cmd_t cmd = ahci_port_cmd_rd(&port->port);
-        cmd = ahci_port_cmd_fre_insert(cmd, 1);
-        cmd = ahci_port_cmd_st_insert(cmd, 1);
-        ahci_port_cmd_wr(&port->port, cmd);
-
-        // enable all interrupts of this port
-        AHCI_DEBUG("enabling all port interrupts\n");
-        ahci_port_ie_wr(&port->port, -1);
-
-        // fire off the original binding callback
-        if (bst->cont) {
-            bst->cont(bst->st, SYS_ERR_OK, ahci_binding);
-        }
-    }
-
-    AHCI_DEBUG("ahci_mgmt_identify_response_cb: exiting\n");
-}
-
-static void ahci_mgmt_open_cb(struct ahci_mgmt_binding *b, errval_t status,
-        struct capref controller_mem, uint64_t offset, uint32_t capabilities)
-{
-    AHCI_DEBUG("open cb\n");
-    struct bind_st *bst = b->st;
-    errval_t err = status, cleanup_err;
-    struct ahci_binding *ahci_binding;
-
-    if (bst->num_ports == 0) {
-        // init bind_st properly
-        ahci_binding = bst->ahci_binding[0];
-        bst->num_ports = ahci_hba_cap_np_extract(capabilities) + 1;
-        void *tmp = calloc(bst->num_ports, sizeof(struct ahci_binding *));
-        if (tmp == NULL) {
-            err = LIB_ERR_MALLOC_FAIL;
-            goto error_status;
-        }
-        bst->ahci_binding = tmp;
-        bst->ahci_binding[bst->port] = ahci_binding;
-    }
-    else {
-        // get correct ahci binding
-        ahci_binding = bst->ahci_binding[bst->port];
-    }
-
-    struct ahci_port_info *port = &ahci_binding->port_info;
-
-    // check status code from management daemon
-    if (err_is_fail(status)) {
-        DEBUG_ERR(status, "failed to open port: '%s'", err_getstring(status));
-        goto error_status;
-    }
-
-    // HBA caps
-    port->hba_capabilities = capabilities;
-
-    // init port
-    AHCI_DEBUG("mapping port in our address space\n");
-    // map device in our address space
-    err = vspace_map_one_frame_attr(&port->mapped_vaddr, offset + PORT_SIZE,
-            controller_mem, VREGION_FLAGS_READ_WRITE_NOCACHE, NULL, NULL);
-    if (err_is_fail(err)) {
-        DEBUG_ERR(err, "vspace_map_one_frame failed: '%s'", err_getstring(err));
-        goto error_map_controller;
-    }
-    port->port_base = (char *)port->mapped_vaddr + offset;
-
-    // store controller mem cap in port
-    port->hba_cap = controller_mem;
-
-    // setup mackerel struct for port
-    ahci_port_initialize(&port->port, port->port_base);
-    err = ahci_port_alloc_dma_structs(&port->port,
-            &port->command_list, &port->receive_fis);
-    if (err_is_fail(err)) {
-        DEBUG_ERR(err, "ahci_port_alloc_dma_structs failed");
-        goto error_dma_allocate;
-    }
-    AHCI_DEBUG("enabling rFIS area + start running commands\n");
-
-    // fetch identify data from management daemon
-    err = ahci_mgmt_identify_call__tx(b, NOP_CONT, ahci_binding->port_id);
-    if (err_is_fail(err)) {
-        DEBUG_ERR(err, "failed to send identify_call to ahci_mgmt");
-        goto error_identify_send;
-    }
-
-    goto end;
-
-error_identify_send:
-    // free port dma region
-    ahci_port_free_dma_structs(port);
-
-error_dma_allocate:
-    // cleanup mapping of controller mem
-    cleanup_err = vspace_unmap(port->mapped_vaddr);
-    if (err_is_fail(cleanup_err)) {
-        USER_PANIC_ERR(cleanup_err, "vspace_unmap failed");
-    }
-
-error_map_controller:
-    // destroy controller mem cap
-    cleanup_err = cap_destroy(controller_mem);
-    if (err_is_fail(cleanup_err)) {
-        USER_PANIC_ERR(cleanup_err, "cap_destroy failed");
-    }
-
-error_status:
-    // cleanup semi-initialized libahci binding
-    waitset_chanstate_destroy(&ahci_binding->register_chanstate);
-    waitset_chanstate_destroy(&ahci_binding->tx_cont_chanstate);
-
-    free(ahci_binding);
-    bst->ahci_binding[bst->port] = NULL;
-
-    if (bst->cont) {
-        bst->cont(bst->st, err, NULL);
-    }
-
-    // free user state
-    free(bst);
-
-end:
-    AHCI_DEBUG("ahci_mgmt_open_cb: exiting\n");
-}
-
-static void ahci_mgmt_command_completed_cb(struct ahci_mgmt_binding *b,
-        uint8_t port_id, uint32_t interrupt_status)
-{
-    AHCI_DEBUG("got command completed message\n");
-    struct bind_st *bst = b->st;
-    struct ahci_port_info *port_info = &bst->ahci_binding[port_id]->port_info;
-
-    if (interrupt_status == 0) {
-        // ghost irq, ignore. (although this should not even get to here)
-        return;
-    }
-
-    AHCI_DEBUG("interrupt status = 0x%"PRIx32"\n", interrupt_status);
-
-    uint8_t tfes, ifs, hbfs, hbds;
-    if ((tfes = ahci_port_is_tfes_extract(interrupt_status)) ||
-        (ifs = ahci_port_is_ifs_extract(interrupt_status)) ||
-        (hbfs = ahci_port_is_hbfs_extract(interrupt_status)) ||
-        (hbds = ahci_port_is_hbds_extract(interrupt_status)))
-    {
-        char buf[4096];
-        ahci_port_serr_t errstate = ahci_port_serr_rd(&port_info->port);
-        ahci_port_tfd_t tfd = ahci_port_tfd_rd(&port_info->port);
-        ahci_dump_rfis(port_info);
-        ahci_port_serr_prtval(buf, 4096, errstate);
-        puts(buf);
-        printf("task file data:\n");
-        ahci_port_tfd_prtval(buf, 4096, tfd);
-        puts(buf);
-        assert(!"error");
-    }
-    else if (ahci_port_is_infs_extract(interrupt_status)) {
-        char buf[4096];
-        ahci_port_serr_t errstate = ahci_port_serr_rd(&port_info->port);
-        ahci_port_serr_prtval(buf, 4096, errstate);
-        puts(buf);
-        assert(!"non-fatal error");
-    }
-
-    uint32_t ci = ahci_port_ci_rd(&port_info->port);
-
-    // which commands have been completed?
-    for (int i = 0; i < 32; i++) {
-        if (!port_info->command_slots[i].in_use || (ci & (1<<i))) {
-            continue; // skip slots we didn't use or that have not been processed yet
-        }
-
-        // free command table
-        AHCI_DEBUG("freeing command table for slot %d (in_use=%d): %p\n",
-                i, port_info->command_slots[i].in_use,
-                port_info->command_slots[i].command_table);
-        ahci_dma_region_free(port_info->command_slots[i].command_table);
-        port_info->command_slots[i].command_table = 0;
-
-        void *tag = port_info->command_slots[i].tag;
-        port_info->command_slots[i].tag = 0;
-        port_info->command_slots[i].in_use = false;
-
-        AHCI_DEBUG("dispatching to user level\n");
-        // FIXME: does this make sense? will we even return to here in the near future?
-        bst->ahci_binding[port_id]->rx_vtbl.command_completed(bst->ahci_binding[port_id], tag);
-        AHCI_DEBUG("return from user level\n");
-    }
-
-    AHCI_DEBUG("cc_cb exiting\n");
-}
-
-static void ahci_mgmt_close_cb(struct ahci_mgmt_binding *_binding, errval_t status)
-{
-    AHCI_DEBUG("mgmt close cb\n");
-    if (err_is_fail(status)) {
-        DEBUG_ERR(status, "close callback");
-    }
-    struct bind_st *bst = _binding->st;
-    struct mgmt_close_call_st *st = bst->st;
-    if (st->continuation.handler != NULL) {
-        waitset_chan_trigger_closure(st->binding->waitset,
-                &st->binding->tx_cont_chanstate, st->continuation);
-    }
-    free(st->binding->identify_data);
-    free(st->binding);
-    free(st);
-}
-
-static void ahci_mgmt_bind_cb(void *st, errval_t err, struct ahci_mgmt_binding *b)
-{
-    if (err_is_fail(err)) {
-        USER_PANIC_ERR(err, "ahci_mgmt bind failed in callback");
-    }
-
-    struct bind_st *bst = st;
-
-    // set up our binding to the mgmt daemon
-    mgmt_binding = b;
-    b->rx_vtbl.open_response = ahci_mgmt_open_cb;
-    b->rx_vtbl.command_completed = ahci_mgmt_command_completed_cb;
-    b->rx_vtbl.close_response = ahci_mgmt_close_cb;
-    b->rx_vtbl.identify_response = ahci_mgmt_identify_response_cb;
-
-    b->st = bst;
-
-    // try to open the port
-    ahci_mgmt_open_call__tx(b, NOP_CONT, bst->port);
-}
-
-static bool ahci_can_send(struct ahci_binding *_binding)
-{
-    return ahci_find_free_command_slot(&_binding->port_info) != -1;
-}
-
-static errval_t ahci_register_send(struct ahci_binding *_binding,
-        struct waitset *ws, struct event_closure _continuation)
-{
-    if (ahci_can_send(_binding)) {
-        return waitset_chan_trigger_closure(ws,
-                &(_binding->register_chanstate), _continuation);
-    }
-    else {
-        return waitset_chan_register(ws,
-                &(_binding->register_chanstate), _continuation);
-    }
-}
-
-static errval_t ahci_change_waitset(struct ahci_binding *_binding, struct waitset *ws)
-{
-    AHCI_DEBUG("change waitset, ws = %p\n", ws);
-    // TODO: re-register somewhere?
-    _binding->waitset = ws;
-    mgmt_binding->change_waitset(mgmt_binding, ws);
-
-    return SYS_ERR_OK;
-}
-
-static errval_t ahci_control(struct ahci_binding *_binding, idc_control_t control)
-{
-    // TODO: implement
-    return SYS_ERR_OK;
-}
-
-static void ahci_error_handler(struct ahci_binding *_binding, errval_t err)
-{
-    DEBUG_ERR(err, "Asynchronous in ahci messaging. Aborting.");
-    abort();
-}
-
-errval_t ahci_init(uint8_t port, ahci_bind_continuation_fn *_continuation,
-        void *st, struct waitset *waitset)
-{
-    AHCI_DEBUG("ahci_init: waitset = %p\n", waitset);
-    errval_t err;
-    iref_t iref;
-
-    // setup binding struct
-    struct ahci_binding *binding = calloc(1, sizeof(struct ahci_binding));
-    binding->st = NULL;
-    binding->waitset = waitset;
-    event_mutex_init(&binding->mutex, waitset);
-    /* set up management function pointers */
-    binding->can_send = ahci_can_send;
-    binding->register_send = ahci_register_send;
-    binding->change_waitset = ahci_change_waitset;
-    binding->control = ahci_control;
-    binding->error_handler = ahci_error_handler;
-    memset(&binding->rx_vtbl, 0, sizeof(binding->rx_vtbl));
-    waitset_chanstate_init(&binding->register_chanstate, CHANTYPE_AHCI);
-    waitset_chanstate_init(&binding->tx_cont_chanstate, CHANTYPE_AHCI);
-
-    //binding->st = st;
-    binding->port_id = port;
-
-    // setup binding to ahcid and init dma pool
-    if (mgmt_binding == NULL) {
-        err = nameservice_blocking_lookup("ahcid", &iref);
-        if (err_is_fail(err)) {
-            DEBUG_ERR(err, "nameservice_blocking_lookup for ahcid");
-            return err; // FIXME
-        }
-
-        // couple continuation and binding
-        struct bind_st *bst = malloc(sizeof(struct bind_st));
-        assert(bst != NULL);
-        bst->cont = _continuation;
-        // temp; used as flag in open_cb
-        bst->num_ports = 0;
-        // temp; realloc as soon as we know num_ports
-        bst->ahci_binding = malloc(sizeof(struct ahci_binding*));
-        bst->ahci_binding[0] = binding;
-        bst->port = port;
-        bst->st = st;
-
-        // init dma pool to 1M
-        ahci_dma_pool_init(1024 * 1024);
-
-        err = ahci_mgmt_bind(iref, ahci_mgmt_bind_cb, bst, waitset,
-                IDC_BIND_FLAG_RPC_CAP_TRANSFER);
-
-        if (err_is_fail(err)) {
-            DEBUG_ERR(err, "ahci_mgmt bind failed");
-            return err; // FIXME
-        }
-    }
-    else {
-        // change mgmt binding waitset to supplied waitset
-        struct bind_st *bst = mgmt_binding->st;
-        bst->cont = _continuation;
-        bst->ahci_binding[port] = binding;
-        bst->port = port;
-        bst->st = st;
-
-        // try to open the port
-        mgmt_binding->change_waitset(mgmt_binding, waitset);
-        ahci_mgmt_open_call__tx(mgmt_binding, NOP_CONT, binding->port_id);
-    }
-
-    AHCI_DEBUG("ahci_init: exiting\n");
-    return SYS_ERR_OK;
-}
-
-errval_t ahci_issue_command(struct ahci_binding *_binding,
-        struct event_closure _continuation, void *tag, uint8_t *fis,
-        size_t fis_length, bool is_write, struct ahci_dma_region *buf, size_t buflen)
-{
-    errval_t err = 0;
-
-    AHCI_DEBUG("entering ahci_issue_command: tag = %p; buf = %p; buflen = %zd\n",
-            tag, buf, buflen);
-
-    struct ahci_port_info *port = &_binding->port_info;
-    int command;
-    AHCI_DEBUG("ahci_issue_command: fis_length = %zd\n", fis_length);
-    size_t num_prds = 0;
-    if (buf) {
-        assert((buflen & 1) == 0); // force even byte count
-#ifdef AHCI_FIXED_PR_SIZE
-        num_prds = CEIL_DIV(buflen, PR_SIZE);
-#else
-        num_prds = CEIL_DIV(buflen, MAX_PR_SIZE);
-#endif
-    }
-    err = ahci_setup_command(&command, port, fis, fis_length, num_prds, is_write);
-    if (err_is_fail(err)) {
-        DEBUG_ERR(err, "ahci_setup_command failed");
-        return err;
-    }
-
-    // save tag
-    port->command_slots[command].tag = tag;
-
-    if (buf) {
-        err = ahci_add_physical_regions(port, command, buf, buflen);
-        if (err_is_fail(err)) {
-            DEBUG_ERR(err, "ahci_add_physical_regions failed");
-            return err;
-        }
-    }
-
-    // issue command
-    ahci_port_ci_wr(&port->port, (1<<command));
-
-    AHCI_DEBUG("ahci_load_fis: calling user continuation\n");
-    if (_continuation.handler != NULL) {
-        waitset_chan_trigger_closure(_binding->waitset,
-                &_binding->tx_cont_chanstate, _continuation);
-    }
-    AHCI_DEBUG("ahci_load_fis: exiting\n");
-    return SYS_ERR_OK;
-}
-
-errval_t ahci_close(struct ahci_binding *_binding, struct event_closure _continuation)
-{
-    AHCI_DEBUG("ahci_close: callback = %p\n", _continuation.handler);
-    struct mgmt_close_call_st *st = calloc(1, sizeof(struct mgmt_close_call_st));
-    if (!st) {
-        return LIB_ERR_MALLOC_FAIL;
-    }
-    st->binding = _binding;
-    st->continuation = _continuation;
-    struct bind_st *bst = mgmt_binding->st;
-    bst->st = st;
-    // unmap controller memory
-    errval_t err = cap_destroy(_binding->port_info.hba_cap);
-    if (err_is_fail(err)) {
-        printf("cap_destroy: %s (%"PRIuERRV")\n", err_getstring(err), err);
-    }
-    ahci_mgmt_close_call__tx(mgmt_binding, NOP_CONT, _binding->port_id);
-
-    return SYS_ERR_OK;
-}
diff --git a/lib/ahci/ahci_debug.h b/lib/ahci/ahci_debug.h
deleted file mode 100644 (file)
index 79216b3..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2011 ETH Zurich.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
- */
-
-#ifndef AHCI_DEBUG_H_
-#define AHCI_DEBUG_H_
-
-#include <stdio.h>
-
-/*****************************************************************
- * Debug printer:
- *****************************************************************/
-
-#if defined(AHCI_LIB_DEBUG) || defined(GLOBAL_DEBUG)
-#define AHCI_DEBUG(x...) printf("ahci: " x)
-#else
-#define AHCI_DEBUG(x...) ((void)0)
-#endif
-#if defined(AHCI_LIB_DEBUG) || defined(GLOBAL_DEBUG)
-#define AHCI_TRACE_ENTER0() AHCI_TRACE_ENTER(" ")
-#define AHCI_TRACE_ENTER(x...) do { \
-    printf("ahci: entering %s. ", __FUNCTION__); \
-    printf(x); \
-    printf("\n"); \
-} while(0)
-#else
-#define AHCI_TRACE_ENTER0() ((void)0)
-#define AHCI_TRACE_ENTER(x...) ((void)0)
-#endif
-
-#endif // AHCI_DEBUG_H_
diff --git a/lib/ahci/ahci_dma_pool.c b/lib/ahci/ahci_dma_pool.c
deleted file mode 100644 (file)
index 46a1ccc..0000000
+++ /dev/null
@@ -1,607 +0,0 @@
-/*
- * Copyright (c) 2011 ETH Zurich.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
- */
-
-#include <barrelfish/barrelfish.h>
-#include <ahci/ahci_dma_pool.h>
-#include <errors/errno.h>
-#include <string.h>
-#include <sys/types.h> /* for ssize_t */
-#include "ahci_debug.h"
-
-#define EIGHT_MEG 8388608
-
-// meta-data structure for the dma pool
-struct dma_pool {
-    // size of the pool in bytes
-    size_t size;
-
-    // number of allocated backing memory regions
-    size_t addr_count;
-
-    // number of allocated slots for backing memory regions
-    size_t addr_entries;
-
-    // virtual addresses of backing memory regions
-    // (valid for indices 0 .. addr_count - 1)
-    void **virt_addrs;
-
-    // physical addresses of backing memory regions
-    // (valid for indices 0 .. addr_count - 1)
-    genpaddr_t *phys_addrs;
-
-    // frame caprefs for backing memory regions
-    // (valid for indices 0 .. addr_count - 1)
-    struct capref *frame_caps;
-
-    // void* pointing to the first free chunk in backing 
-    // memory regions (only valid for indices 0 .. addr_count - 1)
-    struct free **first_free;
-};
-
-// free list element (contained in the first bytes of a free chunk itself)
-struct free {
-    // pointers to previous and next free chunks
-    struct free *next, *prev;
-
-    // size of this chunk
-    size_t size;
-
-    // the index of the backing region of memory
-    size_t backing_region;
-};
-
-
-static struct dma_pool pool;
-static struct free *first_free = NULL, *last_free = NULL;
-
-/**
- * This function grows the address arrays in the pool metadata
- * \return LIB_ERR_MALLOC_FAIL when a realloc fails, SYS_ERR_OK else.
- */
-static errval_t
-grow_vp_arrays(void)
-{
-    AHCI_TRACE_ENTER0();
-    if (pool.addr_entries == 0) { // initial alloc
-        pool.virt_addrs = calloc(8, sizeof(void *));
-        if (pool.virt_addrs == NULL) {
-            return LIB_ERR_MALLOC_FAIL;
-        }
-        pool.phys_addrs = calloc(8, sizeof(genpaddr_t));
-        if (pool.phys_addrs == NULL) {
-            return LIB_ERR_MALLOC_FAIL;
-        }
-        pool.frame_caps = calloc(8, sizeof(struct capref));
-        if (pool.frame_caps == NULL) {
-            return LIB_ERR_MALLOC_FAIL;
-        }
-        pool.first_free = calloc(8, sizeof(struct free *));
-        if (pool.first_free == NULL) {
-            return LIB_ERR_MALLOC_FAIL;
-        }
-        pool.addr_entries = 8;
-    }
-    else { // double size
-        size_t new_size = pool.addr_entries * 2;
-        void **newv;
-        struct capref *newc;
-        genpaddr_t *newp;
-        struct free **newf;
-        newv = realloc(pool.virt_addrs, new_size*sizeof(void *));
-        if (newv == NULL) {
-            AHCI_DEBUG("realloc failed for pool.virt_addrs");
-            return LIB_ERR_MALLOC_FAIL;
-        }
-        memset(newv+pool.addr_entries, 0, pool.addr_entries);
-        newp = realloc(pool.phys_addrs, new_size*sizeof(genpaddr_t));
-        if (newp == NULL) {
-            AHCI_DEBUG("realloc failed for pool.phys_addrs");
-            return LIB_ERR_MALLOC_FAIL;
-        }
-        memset(newp+pool.addr_entries, 0, pool.addr_entries);
-        newc = realloc(pool.frame_caps, new_size*sizeof(struct capref));
-        if (newc == NULL) {
-            AHCI_DEBUG("realloc failed for pool.frame_caps\n");
-            return LIB_ERR_MALLOC_FAIL;
-        }
-        memset(newc+pool.addr_entries, 0, pool.addr_entries);
-        newf = realloc(pool.first_free, new_size*sizeof(struct free *));
-        if (newf == NULL) {
-            AHCI_DEBUG("realloc failed for pool.first_free");
-            return LIB_ERR_MALLOC_FAIL;
-        }
-        memset(newf+pool.addr_entries, 0, pool.addr_entries);
-        pool.virt_addrs = newv;
-        pool.phys_addrs = newp;
-        pool.frame_caps = newc;
-        pool.first_free = newf;
-        pool.addr_entries = new_size;
-    }
-    return SYS_ERR_OK;
-}
-
-/**
- * Increase dma pool size to new_pool_size, growing
- * address arrays if necessary.
- */
-static errval_t
-grow_dma_pool(size_t new_pool_size)
-{
-    AHCI_TRACE_ENTER("new pool size = %zd", new_pool_size);
-    // determine additional pool size (using ssize_t temp variable in order to
-    // detect requests that would shrink the pool).
-    ssize_t temp_pool_size = new_pool_size;
-    if (pool.size != 0) {
-        temp_pool_size -= pool.size;
-    }
-
-    // return if pool already big enough
-    if (temp_pool_size <= 0) {
-        return SYS_ERR_OK;
-    }
-
-    // from here: temp_pool_size > 0
-    if (temp_pool_size <= BASE_PAGE_SIZE) {
-        temp_pool_size = BASE_PAGE_SIZE;
-    }
-
-    // allocate and map memory
-    struct capref frame;
-    struct frame_identity frameid;
-    errval_t err = SYS_ERR_OK;
-    void *va;
-    size_t retsize;
-    // allocate, map and store frame(s)
-    do {
-        // allocate frame
-        err = frame_alloc(&frame, temp_pool_size, &retsize);
-        if (err_is_fail(err)) {
-            break;
-        }
-        // map frame
-        err = vspace_map_one_frame_attr(&va, retsize, frame,
-                VREGION_FLAGS_READ_WRITE_NOCACHE, NULL, NULL);
-        if (err_is_fail(err)) {
-            break;
-        }
-        // get frame phys addr
-        err = invoke_frame_identify(frame, &frameid);
-        if (err_is_fail(err)) {
-            break;
-        }
-
-        // grow arrays if needed
-        if (pool.addr_count == pool.addr_entries) {
-            err = grow_vp_arrays();
-            if (err_is_fail(err)) {
-                break;
-            }
-        }
-
-        // store new frame in pool
-        pool.size += retsize;
-        pool.virt_addrs[pool.addr_count] = va;
-        pool.phys_addrs[pool.addr_count] = frameid.base;
-        pool.frame_caps[pool.addr_count] = frame;
-        // update free list
-        struct free *f = (struct free *)va;
-        pool.first_free[pool.addr_count] = f;
-        f->size = retsize;
-        f->backing_region = pool.addr_count;
-        f->prev = last_free;
-        if (first_free == NULL) { // first region
-            first_free = last_free = f;
-        } else {
-            last_free->next = f;
-        }
-        f->next = NULL;
-        pool.addr_count += 1;
-        temp_pool_size -= retsize;
-    } while(temp_pool_size > 0);
-
-    return err;
-}
-
-/**
- * Init DMA pool
- * \param pool_size Initial pool size in bytes
- */
-errval_t
-ahci_dma_pool_init(size_t pool_size)
-{
-    AHCI_TRACE_ENTER("pool size = %zd", pool_size);
-    // round pool_size up to page size
-    pool_size = ROUND_UP(pool_size, BASE_PAGE_SIZE);
-    return grow_dma_pool(pool_size);
-}
-
-static void
-remove_from_free_list(struct free *f)
-{
-    if (f == first_free && f == last_free) {
-        // only remaining free chunk, clear free list
-        first_free = last_free = NULL;
-        pool.first_free[f->backing_region] = NULL;
-    } else if (f == first_free) {
-        // we were first free, f->next != NULL, make f->next first_free
-        first_free = f->next;
-        first_free->prev = NULL;
-    } else if (f == last_free) {
-        // we were last free, f->prev != NULL, make f->prev last free
-        last_free = f->prev;
-        last_free->next = NULL;
-    } else {
-        // we are somewhere in the middle, remove
-        f->prev->next = f->next;
-        f->next->prev = f->prev;
-    }
-
-    if (f == pool.first_free[f->backing_region]) {
-        if (f->next && f->next->backing_region == f->backing_region) {
-            // we were the first free in our backing region, and there is
-            // another free chunk in the same region: make that chunk first_free
-            // in our backing region
-            pool.first_free[f->backing_region] = f->next;
-        }
-        else {
-            // no other free chunks in our backing region, clear first_free
-            pool.first_free[f->backing_region] = NULL;
-        }
-    }
-}
-
-/**
- * Build a struct ahci_dma_region using the end of the free chunk pointed to
- * by f ensuring that the resulting address for the return region is aligned to
- * alignment_requirement.
- * Note: All free chunk addresses should be aligned to at least 512 bytes.
- */
-static struct ahci_dma_region*
-get_region(struct free *f, size_t size, size_t alignment_requirement)
-{
-    AHCI_TRACE_ENTER("f = %p; size = %zd; alignment = 0x%zx",
-            f, size, alignment_requirement);
-
-    struct ahci_dma_region *r = calloc(1, sizeof(struct ahci_dma_region));
-    if (r == NULL) {
-        return NULL;
-    }
-
-    // set the backing region in the new ahci_dma_region
-    r->backing_region = f->backing_region;
-    AHCI_DEBUG("backing region = %zd\n", f->backing_region);
-
-    // check that remaining free chunk is at least 512 bytes large.
-    // If that is not the case just use the whole chunk.
-    ssize_t rem = 0;
-    if (f->size > size) {
-        rem = f->size - size;
-        if (rem < 512) {
-            rem = 0;
-            size = f->size;
-        }
-    }
-    AHCI_DEBUG("rem: %zd; size: %zd; f->size: %zd\n", rem, size, f->size);
-
-    // calculate the aligned virtual address of the new ahci_dma_region
-    uintptr_t vaddr_unaligned = ((uintptr_t) f) + rem;
-    AHCI_DEBUG("vaddr_unaligned = 0x%zx\n", vaddr_unaligned);
-    uintptr_t vaddr = vaddr_unaligned & ~(alignment_requirement-1);
-
-    // sanity check the aligned virtual address, return error if it is 
-    // smaller than the address of the free chunk.
-    //
-    // This can happen when you have a merged free chunk which was created from
-    // the following two (constructed) chunks: f1=0x600, f1->size=0x200 and
-    // f2=0x800, f2->size=0x200 --(merge)--> f=0x600, f->size=0x400
-    // Now suppose we have a request for size=0x400 and alignment_requirement=0x400:
-    // on first glance `f' seems to match that request, but after aligning the address
-    // vaddr will be smaller than f and thus f cannot fulfil this request.
-    if (vaddr < (uintptr_t)f) {
-        AHCI_DEBUG("too small\n");
-        free(r);
-        return (void*)-1;
-    }
-    AHCI_DEBUG("vaddr = 0x%zx\n", vaddr);
-
-    // recalculate the size of the ahci_dma_region and the remaining chunk size
-    ptrdiff_t addr_diff = vaddr_unaligned - vaddr;
-    size += addr_diff;
-    // here rem should either remain >= 512 or become 0
-    rem -= addr_diff;
-
-    AHCI_DEBUG("rem: %zd; size: %zd; f->size: %zd\n", rem, size, f->size);
-
-    // calculate the offset into the backing region
-    ptrdiff_t offset = vaddr - ((uintptr_t) pool.virt_addrs[f->backing_region]);
-    AHCI_DEBUG("offset = 0x%zx\n", offset);
-    // set the remaining fields in the ahci_dma_region
-    r->vaddr = (void *) vaddr;
-    r->paddr = pool.phys_addrs[f->backing_region] + offset;
-    AHCI_DEBUG("paddr = 0x%zx\n", r->paddr);
-    r->size = size;
-
-    if (rem == 0) {
-        // no remaining space in this free chunk, need to delete from free list
-        remove_from_free_list(f);
-    }
-    else {
-        // adjust size of free chunk
-        f->size = rem;
-    }
-
-    return r;
-}
-
-/**
- * Allocate a dma region aligned to a multiple of alignment_requirement.
- * \param size the minimum size of the requested region
- * \param alignment_requirement align address and size of the chunk to a
- *        multiple of this number
- * \param retregion the newly allocated ahci_dma_region
- */
-errval_t
-ahci_dma_region_alloc_aligned(size_t size, size_t alignment_requirement,
-        struct ahci_dma_region **retregion)
-{
-    AHCI_DEBUG("size = %zd; alignment_requirement = 0x%zx; retregion = %p\n",
-            size, alignment_requirement, retregion);
-
-    if (retregion == NULL) {
-        return AHCI_ERR_ILLEGAL_ARGUMENT;
-    }
-
-    // set alignment_requirement (and therefore size) of request
-    // to at least 512
-    if (alignment_requirement < 512) {
-       alignment_requirement = 512;
-    }
-
-    // round alloc request to alignment_requirement bytes
-    size = ROUND_UP(size, alignment_requirement);
-
-    // iterate over free list
-    struct free *f;
-    f = first_free;
-restart:
-    for (; f; f = f->next) {
-        AHCI_DEBUG("f = %p; f->size = %zd\n", f, f->size);
-        if (f->size >= size) { // found sufficiently big free chunk
-            AHCI_DEBUG("found free chunk\n");
-            *retregion = get_region(f, size, alignment_requirement);
-            if (retregion == (void*)-1) {
-                // when aligning the address the address became smaller than
-                // the address of the free region. Search more.
-                continue;
-            }
-            AHCI_DEBUG("retregion = %p\n", *retregion);
-            // if *retregion is NULL here, get_region() failed.
-            if (*retregion == NULL) {
-                return LIB_ERR_MALLOC_FAIL;
-            }
-            return SYS_ERR_OK;
-        }
-    }
-    AHCI_DEBUG("did not find sufficiently large free region, trying to grow pool.\n");
-    // save index of first free slot in pool
-    size_t first_new = pool.addr_count;
-
-    // grow pool by at least the size of the request.
-    // This prevents that we reach this code again, because in the next search
-    // we will find the newly allocated memory with size >= request size
-    errval_t err = grow_dma_pool(pool.size + size);
-    if (err_is_fail(err)) {
-        return err;
-    }
-
-    // continue searching for sufficiently large regions starting where we
-    // allocated new memory just now
-    f = pool.first_free[first_new];
-    goto restart;
-}
-
-/**
- * Allocate a new dma region with alignment requirement 512
- * \param size the minimum size of the requested region
- * \param alignment_requirement align address and size of the chunk to a
- *        multiple of this number
- * \param retregion the newly allocated ahci_dma_region
- */
-errval_t
-ahci_dma_region_alloc(size_t size, struct ahci_dma_region **retregion)
-{
-    return ahci_dma_region_alloc_aligned(size, 512, retregion);
-}
-
-/**
- * Insert dma region region into free list.
- * \param region region to insert into free list
- */
-static errval_t
-return_region(struct ahci_dma_region *region)
-{
-    AHCI_TRACE_ENTER("region = %p; region->vaddr = %p", region, region->vaddr);
-    if (first_free == NULL) {
-        // no free chunks. init free list with current region
-        AHCI_DEBUG("no free chunks. init free list with current region\n");
-        first_free = last_free = region->vaddr;
-        first_free->size = region->size;
-        first_free->backing_region = region->backing_region;
-        pool.first_free[first_free->backing_region] = first_free;
-    }
-    else {
-        // insert into free list
-        AHCI_DEBUG("insert into free list\n");
-        struct free *n = pool.first_free[region->backing_region];
-        struct free *f;
-        f = region->vaddr;
-        f->size = region->size;
-        f->backing_region = region->backing_region;
-        AHCI_DEBUG("free: vaddr = %p; size = %zd; backing_region = %zd\n",
-                f, f->size, f->backing_region);
-
-        if (n == NULL) {
-            // current region only free in backing block
-            AHCI_DEBUG("current region only free in backing block\n");
-            pool.first_free[region->backing_region] = f;
-            if (region->backing_region >= pool.addr_count) {
-                // we are in the last backing block && only free region in block
-                //  --> we are the new last_free
-                AHCI_DEBUG("new last_free\n");
-                f->next = NULL;
-                f->prev = last_free;
-                last_free->next = f;
-                last_free = f;
-            }
-            else {
-                // find next backing region with free chunks
-                AHCI_DEBUG("find next backing_region w/ free chunks\n");
-                size_t br = region->backing_region + 1;
-                while (br < pool.addr_count) {
-                    if ((n = pool.first_free[br]) != NULL) {
-                        // found next free, insert before
-                        AHCI_DEBUG("found next br w/ free: %zd\n", br);
-                        n->prev->next = f;
-                        f->prev = n->prev;
-                        n->prev = f;
-                        f->next = n;
-                        break;
-                    }
-                    br++;
-                }
-
-                // we didn't find any backing region after ours with free
-                // chunks --> we are last free
-                if (br >= pool.addr_count) {
-                    AHCI_DEBUG("last_free");
-                    f->next = NULL;
-                    f->prev = last_free;
-                    last_free->next = f;
-                    last_free = f;
-                }
-
-                // we've inserted ourselves before the first_free,
-                // becoming first_free
-                if (f->prev == NULL) {
-                    AHCI_DEBUG("first_free");
-                    first_free = f;
-                }
-            }
-        } // end current region only free in backing block
-        else {
-            // insert into backing block's free list
-            AHCI_DEBUG("insert into backing block's free list\n");
-
-            // find our next
-            while (n && (void *)n < region->vaddr) {
-                n = n->next;
-            }
-
-            // insert before n
-            AHCI_DEBUG("insert before: %p\n", n);
-            if (n == NULL) {
-                // we are new last_free
-                AHCI_DEBUG("last free\n");
-                f->next = NULL;
-                f->prev = last_free;
-                last_free->next = f;
-                last_free = f;
-            }
-            else if (n == first_free) {
-                // we are new first_free
-                AHCI_DEBUG("first free\n");
-                f->prev = NULL;
-                f->next = first_free;
-                first_free->prev = f;
-                first_free = f;
-                // we're first_free; this implies that we are
-                // first_free of our backing region
-                pool.first_free[f->backing_region] = f;
-            }
-            else {
-                if (n == pool.first_free[f->backing_region]) {
-                    // we are first free in our region
-                    AHCI_DEBUG("first free in region\n");
-                    pool.first_free[f->backing_region] = f;
-                }
-
-                // insert before n
-                n->prev->next = f;
-                f->prev = n->prev;
-                n->prev = f;
-                f->next = n;
-            }
-        } // end insert into backing block's free list
-
-        // merge with next, if possible
-        if (f->next && f->next->backing_region == f->backing_region) {
-            n = f->next;
-            // check if f and f->next can be merged
-            uintptr_t fp = (uintptr_t) f;
-            uintptr_t np = (uintptr_t) n;
-            if (fp + f->size == np) {
-                AHCI_DEBUG("merging with next free (%p)\n", f->next);
-                // remove f->next from free list and add its size to f
-                struct free *new_next = n->next;
-                f->size += n->size;
-                f->next = new_next;
-
-                if (last_free == n) {
-                    // we are new last free
-                    last_free = f;
-                } else {
-                    new_next->prev = f;
-                }
-            }
-        } // end merge with next
-
-        // merge with previous, if possible
-        if (f->prev && f->prev->backing_region == f->backing_region) {
-            struct free *p = f->prev;
-            // check if f->prev and f can be merged
-            uintptr_t fp = (uintptr_t) f;
-            uintptr_t pp = (uintptr_t) p;
-            if (pp + p->size == fp) {
-                AHCI_DEBUG("merging with prev free (%p)\n", f->prev);
-                // add f's size to f->prev's size and remove f from free list
-                p->size += f->size;
-                p->next = f->next;
-
-                if (last_free == f) {
-                    // we are new last free
-                    last_free = p;
-                }
-                else {
-                    f->next->prev = p;
-                }
-            }
-        } // end merge with previous
-    } // end insert into free list
-
-    return SYS_ERR_OK;
-}
-
-/**
- * Free ahci_dma_region region
- * \param region the dma region to free
- */
-errval_t
-ahci_dma_region_free(struct ahci_dma_region *region)
-{
-    AHCI_TRACE_ENTER("region = %p", region);
-    // insert memory into free list
-    errval_t err = return_region(region);
-    if (err_is_fail(err)) {
-        return err;
-    }
-    // free struct ahci_dma_region
-    free(region);
-
-    return SYS_ERR_OK;
-}
diff --git a/lib/ahci/ahci_internal.h b/lib/ahci/ahci_internal.h
deleted file mode 100644 (file)
index fbf98d6..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2011 ETH Zurich.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
- */
-
-#ifndef _AHCI_INTERNAL_H
-#define _AHCI_INTERNAL_H
-
-void ahci_dump_command(int command, struct ahci_port_info *port);
-
-void ahci_dump_rfis(struct ahci_port_info *port);
-
-int ahci_find_free_command_slot(struct ahci_port_info *port);
-
-void ahci_port_free_dma_structs(struct ahci_port_info *port);
-
-errval_t ahci_setup_command(int *command, struct ahci_port_info *port,
-        uint8_t *fis, size_t fis_length, size_t num_prds, bool is_write);
-
-errval_t ahci_add_physical_regions(struct ahci_port_info *port, int command,
-        struct ahci_dma_region *buf, size_t buflen);
-
-
-#endif
diff --git a/lib/ahci/ahci_util.c b/lib/ahci/ahci_util.c
deleted file mode 100644 (file)
index 21afd14..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright (c) 2011 ETH Zurich.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
- */
-
-#include <barrelfish/barrelfish.h>
-#include <barrelfish/memobj.h>
-#include <barrelfish/vregion.h>
-#include <ahci/ahci.h>
-#include <ahci/ahci_dma_pool.h>
-#include <dev/ahci_hba_dev.h>
-#include <string.h>
-#include "ahci_debug.h"
-#include "ahci_internal.h"
-
-#define AHCI_MAX_PRD_COUNT 65535
-
-// CL is 1K, see AHCI Spec 1.3 Section 3.3.1
-#define AHCI_CL_SIZE 1024
-
-// rFIS is 256 bytes, see AHCI Spec 1.3 Section 3.3.3
-#define AHCI_RFIS_SIZE 256
-
-
-int ahci_find_free_command_slot(struct ahci_port_info *port)
-{
-    for (int i = 0; i < ahci_hba_cap_ncs_extract(port->hba_capabilities) + 1; i++) {
-        if (!port->command_slots[i].in_use) {
-            return i;
-        }
-    }
-
-    return -1;
-}
-
-errval_t ahci_port_alloc_dma_structs(ahci_port_t *port,
-        struct ahci_dma_region **command_list,
-        struct ahci_dma_region **receive_fis)
-{
-    errval_t r;
-
-    // allocate frame for command header list
-    r = ahci_dma_region_alloc_aligned(AHCI_CL_SIZE, AHCI_CL_SIZE,
-            command_list);
-    assert(err_is_ok(r));
-    // CLB must be aligned to 1024 bytes
-    assert(((*command_list)->paddr & 0x3FF) == 0);
-    ahci_port_clb_wr(port, (*command_list)->paddr);
-
-    // allocate frame for received FIS
-    r = ahci_dma_region_alloc_aligned(AHCI_RFIS_SIZE, AHCI_RFIS_SIZE,
-           receive_fis);
-    assert(err_is_ok(r));
-    // FIS must be aligned to 256 bytes
-    assert(((*receive_fis)->paddr & 0xFF) == 0);
-    ahci_port_fb_wr(port, (*receive_fis)->paddr);
-
-    return 0;
-}
-
-void ahci_port_free_dma_structs(struct ahci_port_info *port)
-{
-    errval_t err;
-    err = ahci_dma_region_free(port->command_list);
-    if (err_is_fail(err)) {
-        USER_PANIC_ERR(err, "ahci_dma_region_free failed for port command list");
-    }
-    err = ahci_dma_region_free(port->receive_fis);
-    if (err_is_fail(err)) {
-        USER_PANIC_ERR(err, "ahci_dma_region_free failed for port receive fis");
-    }
-}
-
-errval_t ahci_setup_command(int *command, struct ahci_port_info *port,
-        uint8_t *fis, size_t fis_length, size_t num_prds, bool is_write)
-{
-    errval_t r;
-    AHCI_DEBUG("ahci_setup_command(%p, %p, %p, %zu, %zu, %d): entering\n",
-            command, port, fis, fis_length, num_prds, is_write);
-
-    int command_slot = ahci_find_free_command_slot(port);
-    assert(command_slot != -1); //TODO: what to do if we run out of slots? wait?
-    port->command_slots[command_slot].in_use = true;
-
-    // setup command table w/ enough entries for PRDs
-    size_t prdt_size = num_prds*ahci_port_prd_size;
-    size_t cmd_table_size = PRDT_OFFSET + prdt_size;
-    struct ahci_dma_region *ct;
-    r = ahci_dma_region_alloc(cmd_table_size, &ct);
-    if (err_is_fail(r)) {
-        DEBUG_ERR(r, "failed to allocate memory for command table");
-        return r;
-    }
-    port->command_slots[command_slot].command_table = ct;
-
-
-    AHCI_DEBUG("Using command slot: %d\n", command_slot);
-    // insert command table into command header at pos `next_cmd'
-    uint8_t *command_header_entry =
-        ((uint8_t*)port->command_list->vaddr) + command_slot*ahci_port_chdr_size;
-    memset(command_header_entry, 0, ahci_port_chdr_size);
-    ahci_port_chdr_t chdr = (ahci_port_chdr_t) command_header_entry;
-    ahci_port_chdr_cfl_insert(chdr, fis_length / 4);
-    ahci_port_chdr_w_insert(chdr, is_write);
-    ahci_port_chdr_ctba_insert(chdr, (uint32_t)ct->paddr);
-    ahci_port_chdr_ctbau_insert(chdr, (uint32_t)(ct->paddr >> 32));
-
-    // copy fis into command table
-    memset(ct->vaddr, 0, cmd_table_size);
-    ahci_dma_region_copy_in(ct, fis, 0, fis_length);
-
-    *command = command_slot;
-
-    AHCI_DEBUG("ahci_setup_command: exiting\n");
-    return SYS_ERR_OK;
-}
-
-static void ahci_set_physical_region(ahci_port_prd_t prd,
-        genpaddr_t physical_base, size_t length)
-{
-    //AHCI_DEBUG("ahci_set_physical_region: entering\n");
-#ifdef AHCI_FIXED_PR_SIZE
-    assert(length == PR_SIZE);
-#else
-    assert(length <= MAX_PR_SIZE);
-    assert((length & 1) == 0);
-#endif
-
-    ahci_port_prd_dba_insert(prd, (uint32_t)physical_base);
-    ahci_port_prd_dbau_insert(prd, (uint32_t)(physical_base >> 32));
-    ahci_port_prd_dbc_insert(prd, length-1);
-    //AHCI_DEBUG("ahci_set_physical_region: exiting\n");
-}
-
-static inline genpaddr_t ahci_get_sector_paddr(struct ahci_dma_region *region,
-        size_t offset)
-{
-    return region->paddr + offset;
-}
-
-errval_t ahci_add_physical_regions(struct ahci_port_info *port,
-        int command, struct ahci_dma_region *buf, size_t buflen)
-{
-    AHCI_DEBUG("ahci_add_physical_regions: entering\n");
-    uint8_t *command_header_base =
-        ((uint8_t*)port->command_list->vaddr) + command*ahci_port_chdr_size;
-    ahci_port_chdr_t chdr = (ahci_port_chdr_t) command_header_base;
-
-    // find next free prd entry in command header
-    size_t prd_count = ahci_port_chdr_prdtl_extract(chdr);
-    AHCI_DEBUG("prd_count = %zd\n", prd_count);
-    // position for next prd
-    size_t prdt_index = prd_count;
-    // get base address of prd table
-    uint8_t *prdt_base =
-        (uint8_t*)port->command_slots[command].command_table->vaddr +
-        PRDT_OFFSET;
-
-    // max 512 bytes per PR
-#ifdef AHCI_FIXED_PR_SIZE
-    size_t num_prds_needed = CEIL_DIV(buflen, PR_SIZE);
-#else
-    size_t num_prds_needed = CEIL_DIV(buflen, MAX_PR_SIZE);
-#endif
-    AHCI_DEBUG("#prds = %zd\n", num_prds_needed);
-
-    // check that remaining space is enough for requested length
-    if (prdt_index + num_prds_needed >= AHCI_MAX_PRD_COUNT) {
-        // TODO: error code
-       AHCI_DEBUG("not enough prd space left.\n");
-        return -1;
-    }
-
-    AHCI_DEBUG("PRDT base: %p\n", prdt_base);
-    // initialize a prd for each region
-    ahci_port_prd_t prd;
-    size_t offset = 0;
-    do {
-        prd = (ahci_port_prd_t) prdt_base + (prdt_index * ahci_port_prd_size);
-        memset(prd, 0, ahci_port_prd_size);
-        genpaddr_t sector_addr = ahci_get_sector_paddr(buf, offset);
-        //AHCI_DEBUG("sector_addr = 0x%lx\n", sector_addr);
-#ifdef AHCI_FIXED_PR_SIZE
-        ahci_set_physical_region(prd, sector_addr, PR_SIZE);
-        buflen -= PR_SIZE;
-        offset += PR_SIZE;
-#else
-        size_t chunksize = buflen < MAX_PR_SIZE ? buflen : MAX_PR_SIZE;
-        ahci_set_physical_region(prd, sector_addr, chunksize);
-        buflen -= chunksize;
-        offset += chunksize;
-#endif
-        prdt_index += 1;
-    } while (buflen > 0);
-
-    // update number of PRDs for command
-    ahci_port_chdr_prdtl_insert(chdr, prdt_index);
-
-    AHCI_DEBUG("ahci_add_physical_regions: exiting\n");
-    return 0;
-}
-
-#if defined(AHCI_LIB_DEBUG) || defined(GLOBAL_DEBUG)
-void ahci_dump_command(int command, struct ahci_port_info *port)
-{
-    char buf_[4096];
-    ahci_port_chdr_t chdr =
-        (ahci_port_chdr_t)((uint8_t*) port->command_list->vaddr) +
-        command*ahci_port_chdr_size;
-    ahci_port_chdr_prtval(buf_, 4096, chdr);
-    AHCI_DEBUG("\n%s\n", buf_);
-    int prd_count = ahci_port_chdr_prdtl_extract(chdr);
-    ahci_port_prd_t prd;
-    for (int k = 0; k < prd_count; k++) {
-        uint8_t *cmd_table_base = (uint8_t*) port->command_slots[command].command_table->vaddr;
-        prd = (ahci_port_prd_t) (cmd_table_base + PRDT_OFFSET + k*ahci_port_prd_size);
-        ahci_port_prd_prtval(buf_, 4096, prd);
-        AHCI_DEBUG("\nPRD %d:\n%s\n", k, buf_);
-    }
-}
-#else
-void ahci_dump_command(int command, struct ahci_port_info *port) {}
-#endif
-
-#if defined(AHCI_LIB_DEBUG) || defined(GLOBAL_DEBUG)
-void ahci_dump_rfis(struct ahci_port_info *port)
-{
-    printf("rfis:\n");
-    for (int i = 0; i < 256; i += 4) {
-        printf("%3x: 0x%02x 0x%02x 0x%02x 0x%02x\n", i,
-            *(((uint8_t*)port->receive_fis->vaddr) + i),
-            *(((uint8_t*)port->receive_fis->vaddr) + i + 1),
-            *(((uint8_t*)port->receive_fis->vaddr) + i + 2),
-            *(((uint8_t*)port->receive_fis->vaddr) + i + 3)
-        );
-    }
-}
-#else
-void ahci_dump_rfis(struct ahci_port_info *port) {}
-#endif
diff --git a/lib/ahci/sata_fis.c b/lib/ahci/sata_fis.c
deleted file mode 100644 (file)
index 98fe24a..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (c) 2011 ETH Zurich.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
- */
-
-#include <stdlib.h>
-#include <errors/errno.h>
-#include <ahci/sata_fis.h>
-
-errval_t sata_alloc_h2d_register_fis(void **fis_p, size_t *fis_size_p)
-{
-    struct sata_fis_reg_h2d *fis;
-
-    fis = calloc(1, sizeof(*fis));
-    if (!fis) {
-        return LIB_ERR_MALLOC_FAIL;
-    }
-    fis->type = SATA_FIS_TYPE_H2D;
-
-    /* Device Shadow Register layout (see: [1])
-     * [  7  |  6  |  5  |  4  |  3  |  2  |  1  |  0  ]
-     * [  -  |  L  |  -  | DEV | HS3 | HS2 | HS1 | HS0 ]
-     *
-     * L is the address mode, cleared implies CHS addressing, set, LBA addressing
-     * DEV device select, cleared and set imply Device 0 and 1 resp.
-     *   for SATA this should always be cleared (see: [2])
-     * HS3-HS0 are bits 28-25 of the LBA 28 (not used for LBA 48, see [3])
-     *
-     * [1] Serial ATA NSSD Rev. 1.0 (Sept 2008), section 6.3.1
-     * [2] Serial ATA Rev. 2.6 (15-February-2007), section 13.1, paragraph 2
-     * [3] ATA8-ACS Rev. 3f (December 11, 2006), section 7.1.5.2
-     */
-    fis->device |= (1 << 6);
-
-    *fis_p = fis;
-    *fis_size_p = sizeof(*fis);
-
-    return SYS_ERR_OK;
-}
-
-errval_t sata_set_command(void *fis, uint8_t command)
-{
-    uint8_t fis_type = *(uint8_t*)fis;
-
-    if (fis_type == SATA_FIS_TYPE_H2D) {
-        struct sata_fis_reg_h2d *fis_reg_h2d = fis;
-        fis_reg_h2d->command = command;
-
-        /* set bit to indicate update of command register (see [1])
-         *
-         * [1]: SATA Rev. 2.6 (15-February-2007), section 10.3.4
-         */
-        fis_reg_h2d->specialstuff |= (1 << 7);
-
-        return SYS_ERR_OK;
-    }
-    else {
-        return SATA_ERR_INVALID_TYPE;
-    }
-}
-
-errval_t sata_set_feature(void *fis, uint8_t feature)
-{
-    uint8_t fis_type = *(uint8_t*)fis;
-
-    if (fis_type == SATA_FIS_TYPE_H2D) {
-        struct sata_fis_reg_h2d *fis_reg_h2d = fis;
-        fis_reg_h2d->feature = feature;
-
-        return SYS_ERR_OK;
-    }
-    else {
-        return SATA_ERR_INVALID_TYPE;
-    }
-}
-
-errval_t sata_set_lba28(void *fis, uint32_t lba)
-{
-    uint8_t fis_type = *(uint8_t*)fis;
-
-    if (fis_type == SATA_FIS_TYPE_H2D) {
-        struct sata_fis_reg_h2d *fis_reg_h2d = fis;
-        fis_reg_h2d->lba0 = lba & 0xFF;
-        fis_reg_h2d->lba1 = (lba >> 8) & 0xFF;
-        fis_reg_h2d->lba2 = (lba >> 16) & 0xFF;
-        fis_reg_h2d->device = (fis_reg_h2d->device & ~0x0F) | ((lba >> 24) & 0x0F);
-
-        return SYS_ERR_OK;
-    }
-    else {
-        return SATA_ERR_INVALID_TYPE;
-    }
-}
-
-errval_t sata_set_lba48(void *fis, uint64_t lba)
-{
-    uint8_t fis_type = *(uint8_t*)fis;
-
-    if (fis_type == SATA_FIS_TYPE_H2D) {
-        struct sata_fis_reg_h2d *fis_reg_h2d = fis;
-        fis_reg_h2d->lba0 = lba & 0xFF;
-        fis_reg_h2d->lba1 = (lba >> 8) & 0xFF;
-        fis_reg_h2d->lba2 = (lba >> 16) & 0xFF;
-        fis_reg_h2d->device &= 0xF0; // clear bits otherwise used by lba28
-
-        fis_reg_h2d->lba3 = (lba >> 24) & 0xFF;
-        fis_reg_h2d->lba4 = (lba >> 32) & 0xFF;
-        fis_reg_h2d->lba5 = (lba >> 40) & 0xFF;
-
-        return SYS_ERR_OK;
-    }
-    else {
-        return SATA_ERR_INVALID_TYPE;
-    }
-}
-
-errval_t sata_set_count(void *fis, uint16_t count)
-{
-    uint8_t fis_type = *(uint8_t*)fis;
-
-    if (fis_type == SATA_FIS_TYPE_H2D) {
-        struct sata_fis_reg_h2d *fis_reg_h2d = fis;
-        fis_reg_h2d->countl = count & 0xFF;
-        fis_reg_h2d->counth = (count >> 8) & 0xFF;
-
-        return SYS_ERR_OK;
-    }
-    else {
-        return SATA_ERR_INVALID_TYPE;
-    }
-}
diff --git a/lib/ahci/storage_vsic.c b/lib/ahci/storage_vsic.c
deleted file mode 100644 (file)
index 1107d9e..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (c) 2014, University of Washington.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
- */
-
-#include <barrelfish/barrelfish.h>
-#include <barrelfish/waitset.h>
-#include <if/ata_rw28_defs.h>
-#include <if/ata_rw28_ahci_defs.h>
-#include <if/ata_rw28_rpcclient_defs.h>
-#include <storage/vsic.h>
-
-struct ahci_vsic {
-    struct ahci_ata_rw28_binding ahci_ata_rw28_binding;
-    struct ata_rw28_rpc_client ata_rw28_rpc;
-    struct ata_rw28_binding *ata_rw28_binding;
-    struct ahci_binding *ahci_binding;
-    errval_t bind_err;
-};
-
-static errval_t vsic_write(struct storage_vsic *vsic, struct storage_vsa *vsa,
-                           off_t offset, size_t size, void *buffer)
-{
-    assert(vsic != NULL);
-    assert(vsa != NULL);
-    assert(buffer != NULL);
-    struct ahci_vsic *mydata = vsic->data;
-    errval_t status;
-
-    errval_t err = mydata->ata_rw28_rpc.vtbl.
-      write_dma(&mydata->ata_rw28_rpc, buffer, STORAGE_VSIC_ROUND(vsic, size),
-               offset, &status);
-    if (err_is_fail(err)) {
-        USER_PANIC_ERR(err, "write_dma rpc");
-    }
-    if (err_is_fail(status)) {
-        USER_PANIC_ERR(status, "write_dma status");
-    }
-
-    return SYS_ERR_OK;
-}
-
-static errval_t vsic_read(struct storage_vsic *vsic, struct storage_vsa *vsa,
-                          off_t offset, size_t size, void *buffer)
-{
-    assert(vsic != NULL);
-    assert(vsa != NULL);
-    assert(buffer != NULL);
-    struct ahci_vsic *mydata = vsic->data;
-    uint8_t *buf = NULL;
-    size_t bytes_read, toread = STORAGE_VSIC_ROUND(vsic, size);
-
-    errval_t err = mydata->ata_rw28_rpc.vtbl.
-      read_dma(&mydata->ata_rw28_rpc, toread, offset, &buf, &bytes_read);
-    if (err_is_fail(err))
-        USER_PANIC_ERR(err, "read_dma rpc");
-    if (!buf)
-        USER_PANIC("read_dma -> !buf");
-    if (bytes_read != toread)
-        USER_PANIC("read_dma -> read_size != size");
-
-    // XXX: Copy from DMA buffer to user buffer
-    memcpy(buffer, buf, size);
-    free(buf);
-
-    return SYS_ERR_OK;
-}
-
-static errval_t vsic_flush(struct storage_vsic *vsic, struct storage_vsa *vsa)
-{
-  assert(vsic != NULL);
-  assert(vsa != NULL);
-  struct ahci_vsic *mydata = vsic->data;
-  errval_t outerr;
-
-  errval_t err = mydata->ata_rw28_rpc.vtbl.
-    flush_cache(&mydata->ata_rw28_rpc, &outerr);
-  assert(err_is_ok(err));
-
-  return outerr;
-}
-
-static errval_t vsic_wait(struct storage_vsic *vsic)
-{
-  // XXX: Interface currently synchronous
-  return SYS_ERR_OK;
-}
-
-static struct storage_vsic_ops ahci_vsic_ops = {
-    .write = vsic_write,
-    .read = vsic_read,
-    .flush = vsic_flush,
-    .wait = vsic_wait,
-};
-
-static void ahci_bind_cb(void *st, errval_t err, struct ahci_binding *_binding)
-{
-    assert(err_is_ok(err));
-    struct ahci_vsic *mydata = st;
-    mydata->ahci_binding = _binding;
-}
-
-// XXX: This could be made public and controlled by the programmer instead of
-// the commandline
-static errval_t ahci_vsic_alloc(struct storage_vsic *vsic, uint8_t port)
-{
-    assert(vsic != NULL);
-    errval_t err;
-    struct ahci_vsic *mydata = malloc(sizeof(struct ahci_vsic));
-    assert(mydata != NULL);
-    memset(mydata, 0, sizeof(struct ahci_vsic));
-
-    // init ahci management binding
-    err = ahci_init(port, ahci_bind_cb, mydata, get_default_waitset());
-    assert(err_is_ok(err));
-
-    while(!mydata->ahci_binding) {
-        event_dispatch(get_default_waitset());
-    }
-
-    // init ata flounder binding
-    err = ahci_ata_rw28_init(&mydata->ahci_ata_rw28_binding,
-                             get_default_waitset(), mydata->ahci_binding);
-    if (err_is_fail(err)) {
-        USER_PANIC_ERR(err, "ahci_ata_rw28_init");
-    }
-    mydata->ata_rw28_binding =
-        (struct ata_rw28_binding*)&mydata->ahci_ata_rw28_binding;
-
-    // init RPC client
-    err = ata_rw28_rpc_client_init(&mydata->ata_rw28_rpc,
-                                   mydata->ata_rw28_binding);
-    if (err_is_fail(err)) {
-        USER_PANIC_ERR(err, "ata_rw28_rpc_client_init");
-    }
-
-    // Init VSIC data structure
-    vsic->ops = ahci_vsic_ops;
-    vsic->data = mydata;
-    vsic->blocksize = 512;     // XXX: Determine from drive?
-
-    return SYS_ERR_OK;
-}
-
-errval_t storage_vsic_driver_init(int argc, const char **argv,
-                                 struct storage_vsic *vsic)
-{
-    // init dma pool
-    ahci_dma_pool_init(1024*1024);
-
-    // Allocate port 0
-    return ahci_vsic_alloc(vsic, 0);
-}
index 4cbda73..8c772a0 100644 (file)
@@ -183,6 +183,13 @@ void arranet_polling_loop_proxy(void)
     USER_PANIC("Network polling not available without Arranet!\n");
 }
 
+void poll_ahci(struct waitset_chanstate *) __attribute__((weak));
+void poll_ahci(struct waitset_chanstate *chan)
+{
+    errval_t err = waitset_chan_trigger(chan);
+    assert(err_is_ok(err)); // should not be able to fail
+}
+
 /// Helper function that knows how to poll the given channel, based on its type
 static void poll_channel(struct waitset_chanstate *chan)
 {
@@ -197,6 +204,10 @@ static void poll_channel(struct waitset_chanstate *chan)
         arranet_polling_loop_proxy();
         break;
 
+    case CHANTYPE_AHCI:
+        poll_ahci(chan);
+        break;
+
     default:
         assert(!"invalid channel type to poll!");
     }
diff --git a/lib/blk/Hakefile b/lib/blk/Hakefile
new file mode 100644 (file)
index 0000000..2401859
--- /dev/null
@@ -0,0 +1,7 @@
+[
+  build library {
+    target = "blk",
+    mackerelDevices = [ "ata_identify", "ahci_port", "ahci_hba" ],
+    cFiles = [ "blk.c", "blk_ahci/ahci_init.c", "blk_ahci/ahci_port.c", "blk_ahci/ahci_dev.c", "blk_ahci/sata_fis.c", "blk_ahci/device_impl.c", "dma_mem/dma_mem.c" ]
+  }
+]
diff --git a/lib/blk/blk.c b/lib/blk/blk.c
new file mode 100644 (file)
index 0000000..c0ed394
--- /dev/null
@@ -0,0 +1,19 @@
+/**
+ * \file
+ * \brief
+ */
+/*
+ * Copyright (c) 2016, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <barrelfish/barrelfish.h>
diff --git a/lib/blk/blk_ahci/ahci_dev.c b/lib/blk/blk_ahci/ahci_dev.c
new file mode 100644 (file)
index 0000000..5c6992f
--- /dev/null
@@ -0,0 +1,149 @@
+///! AHCI Device helper functions
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/deferred.h>
+
+#include "blk_ahci.h"
+#include "../blk_debug.h"
+
+#include "ahci_dev.h"
+
+size_t ahci_port_offset(uint32_t port)
+{
+    return 0x100 + port * 0x80;
+}
+
+bool ahci_port_is_idle(ahci_port_t* port)
+{
+    ahci_port_cmd_t cmd = ahci_port_cmd_rd(port);
+    uint8_t st = ahci_port_cmd_st_extract(cmd);
+    uint8_t cr = ahci_port_cmd_cr_extract(cmd);
+    uint8_t fre = ahci_port_cmd_fre_extract(cmd);
+
+    return st == 0 && cr == 0 && fre == 0;
+}
+
+bool ahci_port_is_ready(ahci_port_t* port)
+{
+    uint8_t busy = ahci_port_tfd_bsy_rdf(port);
+    uint8_t drq = ahci_port_tfd_drq_rdf(port);
+    return busy == 0 && drq == 0;
+}
+
+bool ahci_port_is_functional(ahci_port_t* port)
+{
+    uint8_t det = ahci_port_ssts_det_rdf(port);
+    return ahci_port_is_ready(port) && det == 0x3;
+}
+
+bool ahci_port_slot_free(ahci_port_t* port, uint8_t slot)
+{
+    bool ci_free = (ahci_port_ci_rd(port) & (1<<slot)) == 0;
+    bool sact_free = (ahci_port_sact_rd(port) & (1<<slot)) == 0;
+    return ci_free && sact_free;
+}
+
+void ahci_port_start(ahci_port_t* port)
+{
+    assert(ahci_port_is_functional(port));
+    ahci_port_cmd_st_wrf(port, 0x1);
+}
+
+void ahci_port_stop(ahci_port_t* port)
+{
+    ahci_port_cmd_st_wrf(port, 0);
+
+    ahci_port_cmd_t cmd = ahci_port_cmd_rd(port);
+    while (ahci_port_cmd_cr_extract(cmd) != 0) {
+        // TODO should clear in 500ms
+    }
+
+    ahci_port_cmd_fre_wrf(port, 0);
+    while (ahci_port_cmd_fr_rdf(port) != 0) {
+        // TODO should clear in 500ms
+    }
+}
+
+bool ahci_port_is_running(ahci_port_t* port)
+{
+    return ahci_port_cmd_st_rdf(port) > 0;
+}
+
+uint32_t ahci_port_probe(ahci_port_t* port)
+{
+    if (ahci_port_ssts_det_rdf(port) == 0x03) {
+        return ahci_port_sig_rd(port);
+    }
+
+    return 0;
+}
+
+void ahci_hba_reset(ahci_hba_t* controller)
+{
+    ahci_hba_ghc_t ghc = ahci_hba_ghc_rd(controller);
+    BLK_DEBUG("Resetting HBA (setting ghc = %x)...\n", ghc);
+    ghc = ahci_hba_ghc_hr_insert(ghc, 1);
+    ahci_hba_ghc_wr(controller, ghc);
+    barrelfish_usleep(200000);
+    while (1) {
+        ghc = ahci_hba_ghc_rd(controller);
+        if (ahci_hba_ghc_hr_extract(ghc) == 0) {
+            BLK_DEBUG("reset done\n");
+            break;
+        }
+    }
+}
+
+void ahci_hba_irq_enable(ahci_hba_t* controller)
+{
+    BLK_DEBUG("Enabling HBA Interrupts\n");
+    ahci_hba_ghc_t ghc = ahci_hba_ghc_rd(controller);
+    ghc = ahci_hba_ghc_ie_insert(ghc, 1);
+    ahci_hba_ghc_wr(controller, ghc);
+}
+
+void ahci_hba_irq_disable(ahci_hba_t* controller)
+{
+    BLK_DEBUG("Disable HBA Interrupts\n");
+    ahci_hba_ghc_t ghc = ahci_hba_ghc_rd(controller);
+    ghc = ahci_hba_ghc_ie_insert(ghc, 1);
+    ahci_hba_ghc_wr(controller, ghc);
+}
+
+uint32_t ahci_hba_get_num_ports(ahci_hba_t* controller)
+{
+    return ahci_hba_cap_np_extract(ahci_hba_cap_rd(controller)) + 1;
+}
+
+uint32_t ahci_hba_get_command_slots(ahci_hba_t* controller)
+{
+    return ahci_hba_cap_ncs_extract(ahci_hba_cap_rd(controller));
+}
+
+bool ahci_port_is_implemented(ahci_hba_t* controller, size_t port)
+{
+    return (ahci_hba_pi_rd(controller) & (1 << port)) > 0;
+}
+
+void ahci_port_print_identification(ata_identify_t *id)
+{
+    char* buf2 = malloc(10*4096);
+    assert(buf2 != NULL);
+    ata_identify_pr(buf2, 10*4096, id);
+    puts(buf2);
+    free(buf2);
+}
+
+errval_t ahci_hba_init(ahci_hba_t* controller)
+{
+    ahci_hba_reset(controller);
+
+    // Make sure AHCI is enabled:
+    BLK_DEBUG("Setting controller into AHCI mode\n");
+    ahci_hba_ghc_t ghc = ahci_hba_ghc_rd(controller);
+    ghc = ahci_hba_ghc_ae_insert(ghc, 1);
+    ahci_hba_ghc_wr(controller, ghc);
+
+    ahci_hba_irq_disable(controller);
+
+    return SYS_ERR_OK;
+}
diff --git a/lib/blk/blk_ahci/ahci_dev.h b/lib/blk/blk_ahci/ahci_dev.h
new file mode 100644 (file)
index 0000000..0e1705f
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef AHCI_DEV_H_
+#define AHCI_DEV_H_
+
+#include <stdbool.h>
+#include <errors/errno.h>
+#include <dev/ahci_hba_dev.h>
+#include <dev/ahci_port_dev.h>
+#include <dev/ata_identify_dev.h>
+
+void ahci_hba_reset(ahci_hba_t* controller);
+void ahci_hba_irq_enable(ahci_hba_t* controller);
+void ahci_hba_irq_disable(ahci_hba_t* controller);
+uint32_t ahci_hba_get_num_ports(ahci_hba_t* controller);
+errval_t ahci_hba_init(ahci_hba_t* controller);
+uint32_t ahci_hba_get_command_slots(ahci_hba_t* controller);
+bool ahci_port_is_implemented(ahci_hba_t* controller, size_t port);
+uint32_t ahci_port_probe(ahci_port_t* port);
+
+void ahci_port_start(ahci_port_t* port);
+void ahci_port_stop(ahci_port_t* port);
+bool ahci_port_is_running(ahci_port_t* port);
+bool ahci_port_is_idle(ahci_port_t* port);
+bool ahci_port_is_functional(ahci_port_t* port);
+bool ahci_port_is_ready(ahci_port_t* port);
+size_t ahci_port_offset(uint32_t port);
+bool ahci_port_slot_free(ahci_port_t* port, uint8_t slot);
+
+void ahci_port_print_identification(ata_identify_t *id);
+
+#endif // AHCI_DEV_H_
diff --git a/lib/blk/blk_ahci/ahci_init.c b/lib/blk/blk_ahci/ahci_init.c
new file mode 100644 (file)
index 0000000..25f9ba5
--- /dev/null
@@ -0,0 +1,56 @@
+#include <barrelfish/barrelfish.h>
+#include <pci/pci.h>
+
+#include "blk_ahci.h"
+#include "../blk_debug.h"
+#include "ahci_dev.h"
+
+lvaddr_t blk_ahci_get_bar5_vaddr(struct ahci_disk* ad)
+{
+    assert(ad->bar5->vaddr != NULL);
+    return (lvaddr_t)ad->bar5->vaddr;
+}
+
+errval_t blk_ahci_init(struct device_mem* bar5, struct ahci_disk** out)
+{
+    errval_t err;
+
+    err = map_device(bar5);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "Map BAR5 failed.");
+    }
+
+    struct ahci_disk* ad = calloc(sizeof(struct ahci_disk), 1);
+    assert (ad != NULL);
+
+    ad->bar5 = bar5;
+
+    ahci_hba_initialize(&ad->controller, (void *)(bar5->vaddr));
+    BLK_DEBUG("Accessing conf regs starting at %p\n", (void *)(bar5->vaddr));
+    BLK_DEBUG("Physical address of conf regs: %p\n",  (void *)(bar5->paddr));
+
+    err = ahci_hba_init(&ad->controller);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "Init HBA failed.");
+    }
+
+    ahci_hba_irq_enable(&ad->controller);
+
+    err = blk_ahci_ports_init(ad);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "Port init failed.");
+    }
+
+    *out = ad;
+    return err;
+}
+
+
+errval_t blk_ahci_stop(struct ahci_disk* ad)
+{
+    // stop device
+    // devmem free (ad->bar5)
+    // free (ad)
+
+    return SYS_ERR_OK;
+}
diff --git a/lib/blk/blk_ahci/ahci_port.c b/lib/blk/blk_ahci/ahci_port.c
new file mode 100644 (file)
index 0000000..ddec091
--- /dev/null
@@ -0,0 +1,378 @@
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/deferred.h>
+
+#include <pci/pci.h>
+
+#include "blk_ahci.h"
+#include "ahci_dev.h"
+#include "sata_fis.h"
+
+#include "../blk_debug.h"
+#include "../dma_mem/dma_mem.h"
+
+static ahci_port_chdr_t get_command_header(struct ahci_port* port, uint8_t slot)
+{
+    return (ahci_port_chdr_t) ((uint8_t*)port->clb.vaddr) + (ahci_port_chdr_size * slot);
+}
+
+static struct region_descriptor region_descriptor_new(uint64_t dba, uint32_t dbc, bool irq)
+{
+    struct region_descriptor d;
+    d.dba = dba;
+    d.dbc = dbc;
+    d.dbc |= irq << 31;
+
+    return d;
+}
+
+static void command_table_set_cfis(struct command_table* ct, struct sata_fis_reg_h2d* fis)
+{
+    assert(sizeof(ct->cfis) >= sizeof(*fis));
+    struct sata_fis_reg_h2d* fis_ptr = (struct sata_fis_reg_h2d*) ct->cfis;
+    *fis_ptr = *fis;
+}
+
+static errval_t port_init_fb(struct ahci_port* port)
+{
+    assert(port != NULL);
+
+    errval_t err = dma_mem_alloc(1024, &port->fb);
+    if (err_is_fail(err)) {
+        DEBUG_ERR(err, "DMA alloc failed");
+        return err_push(err, AHCI_ERR_PORT_INIT);
+    }
+    memset((void*)port->fb.vaddr, 0x0, 1024);
+
+    assert(port->fb.paddr % 4096 == 0);
+    ahci_port_fb_wr(&port->port, port->fb.paddr);
+    return err;
+}
+
+static errval_t port_init_clb(struct ahci_port* port)
+{
+    assert (port != NULL);
+    assert (ahci_port_chdr_size*32 == 0x400);
+
+    errval_t err = dma_mem_alloc(ahci_port_chdr_size*32, &port->clb);
+    if (err_is_fail(err)) {
+        DEBUG_ERR(err, "DMA alloc failed");
+        return err_push(err, AHCI_ERR_PORT_INIT);
+    }
+    memset((void*)port->clb.vaddr, 0x0, ahci_port_chdr_size*32);
+
+    assert(port->clb.paddr % 1024 == 0);
+    ahci_port_clb_wr(&port->port, port->clb.paddr);
+    return err;
+}
+
+static errval_t port_init_ctba(struct ahci_port* port, size_t command_slot)
+{
+    assert(port != NULL);
+    assert(command_slot < MAX_CTBA_SLOTS);
+
+    errval_t err = dma_mem_alloc(4096, &port->ctba_mem[command_slot]);
+    if (err_is_fail(err)) {
+        DEBUG_ERR(err, "DMA alloc failed");
+        return err_push(err, AHCI_ERR_PORT_INIT);
+    }
+    memset((void*)port->ctba_mem[command_slot].vaddr, 0x0, 4096);
+    port->command_table[command_slot] = (struct command_table*) port->ctba_mem[command_slot].vaddr;
+
+    return err;
+}
+
+static void blk_ahci_interrupt(struct ahci_port* port, struct dev_queue *queue)
+{
+    ahci_port_is_t status = ahci_port_is_rd(&port->port);
+
+    // A request was handled:
+    //if (ahci_port_is_dhrs_extract(status) > 0) {
+        BLK_DEBUG("Done with DMA command.\n");
+
+        for (size_t slot = 0; slot < queue->port->ncs; slot++) {
+            struct dev_queue_request *dqr = &queue->requests[slot];
+
+            bool slot_has_request = dqr->status == RequestStatus_InProgress;
+            bool slot_done = ahci_port_slot_free(&port->port, slot);
+            if (slot_has_request && !slot_done) {
+                //printf("waiting for slot %zu.\n", slot);
+            }
+            if (slot_has_request && slot_done) {
+                //printf("AHCI slot %zu is done now.\n", slot);
+                dqr->status = RequestStatus_Done;
+            }
+        }
+
+        if (ahci_port_is_dhrs_extract(status)) {
+            ahci_port_is_dhrs_wrf(&port->port, 0x1);
+        }
+    //}
+
+    // Did something happen we can't yet handle?
+    if (status > 0x1) {
+#if defined(BLK_DEBUG_ENABLE)
+        char buf[4096];
+        ahci_port_is_pr(buf, 4096, &port->port);
+        BLK_DEBUG("GOT unhandled IRQ: %u\n", ahci_port_is_rd(&port->port));
+        puts(buf);
+#else
+        printf("[BLK] unhandled irq: %u", ahci_port_is_rd(&port->port));
+#endif
+    }
+    else {
+        //printf("[BLK] IRQ handled\n");
+    }
+}
+
+errval_t blk_ahci_port_dma_async(struct ahci_port *port, size_t slot, uint64_t block, lpaddr_t base, size_t length, bool write)
+{
+    assert(length % 512 == 0);
+    assert(ahci_port_slot_free(&port->port, 1 << slot));
+
+    errval_t err = SYS_ERR_OK;
+
+    ahci_port_chdr_t header = get_command_header(port, slot);
+    memset(header, 0, ahci_port_chdr_size);
+    ahci_port_chdr_a_insert(header, 0);
+    ahci_port_chdr_w_insert(header, write);
+    ahci_port_chdr_cfl_insert(header, sizeof(struct sata_fis_reg_h2d) / sizeof(uint32_t));
+    ahci_port_chdr_prdtl_insert(header, 1);
+    ahci_port_chdr_ctba_insert(header, port->ctba_mem[slot].paddr);
+
+    uint8_t command = write ? ATA_CMD_WRITE_DMA_EXT : ATA_CMD_READ_DMA_EXT;
+    uint16_t sectors = length / 512;
+
+    struct command_table* ct = port->command_table[slot];
+    struct sata_fis_reg_h2d fis;
+    sata_h2d_fis_new(&fis, command, block, sectors);
+    command_table_set_cfis(ct, &fis);
+    ct->prdt[0] = region_descriptor_new(base, (length - 1) | 0x1, false);
+
+    while (!ahci_port_is_ready(&port->port)) {
+        // TODO: Abort return error on timeout
+    }
+
+    // Issue command in slot 0
+    ahci_port_ci_rawwr(&port->port, 1 << slot);
+    BLK_DEBUG("Issued async DMA command.\n");
+
+#if 0
+    while ((ahci_port_ci_rd(&port->port) & (1<<slot)) > 0) {
+        // TODO: abort on timeout
+        //barrelfish_usleep(10000);
+    }
+    BLK_DEBUG("Done with DMA command.\n");
+#endif
+
+    return err;
+}
+
+errval_t blk_ahci_port_dma(struct ahci_port *port, uint64_t block, struct dma_mem *buffer, bool write)
+{
+    errval_t err = SYS_ERR_OK;
+    size_t slot = 0;
+
+    // TODO: use only slot 0
+    assert(ahci_port_slot_free(&port->port, 1 << slot));
+
+    ahci_port_chdr_t header = get_command_header(port, slot);
+    memset(header, 0, ahci_port_chdr_size);
+    ahci_port_chdr_a_insert(header, 0);
+    ahci_port_chdr_w_insert(header, write);
+    ahci_port_chdr_cfl_insert(header, sizeof(struct sata_fis_reg_h2d) / sizeof(uint32_t));
+    ahci_port_chdr_prdtl_insert(header, 1);
+    ahci_port_chdr_ctba_insert(header, port->ctba_mem[slot].paddr);
+
+    uint8_t command = write ? ATA_CMD_WRITE_DMA_EXT : ATA_CMD_READ_DMA_EXT;
+    assert(buffer->bytes % 512 == 0);
+    uint16_t sectors = buffer->bytes / 512;
+
+    struct command_table* ct = port->command_table[slot];
+    struct sata_fis_reg_h2d fis;
+    sata_h2d_fis_new(&fis, command, block, sectors);
+    command_table_set_cfis(ct, &fis);
+    ct->prdt[0] = region_descriptor_new(buffer->paddr, (buffer->bytes - 1) | 0x1, false);
+
+    while (!ahci_port_is_ready(&port->port)) {
+        // TODO: Abort return error on timeout
+    }
+
+    // Issue command in slot 0
+    ahci_port_ci_wr(&port->port, 1 << slot);
+
+    BLK_DEBUG("Issued DMA command (w=%d) block=%zu.\n", write, block);
+    while ((ahci_port_ci_rd(&port->port) & (1<<slot)) > 0) {
+        // TODO: abort on timeout
+        barrelfish_usleep(10000);
+    }
+
+    BLK_DEBUG("Done with DMA command.\n");
+    // Clear expected interrupt:
+    ahci_port_is_dhrs_wrf(&port->port, 0x1);
+
+    if (ahci_port_is_rd(&port->port) != 0x0) {
+#if defined(BLK_DEBUG_ENABLE)
+        char buf[4096];
+        ahci_port_is_pr(buf, 4096, &port->port);
+        BLK_DEBUG("GOT unhandled IRQ: %u\n", ahci_port_is_rd(&port->port));
+        puts(buf);
+#endif
+    }
+
+    printf("%s:%s:%d: write? %d %zu\n", __FILE__, __FUNCTION__, __LINE__, write, ((uint64_t*)buffer->vaddr)[0]);
+    return err;
+}
+
+static errval_t port_identify(struct ahci_port *port)
+{
+    // TODO: this function needs proper error handling
+    errval_t err = SYS_ERR_OK;
+    assert(ahci_port_slot_free(&port->port, 1));
+
+    err = dma_mem_alloc(512, &port->identify_mem);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "dma memory allocation failed.");
+    }
+    memset((void*)port->identify_mem.vaddr, 0, 512);
+
+    // Write command into command list
+    ahci_port_chdr_t header = get_command_header(port, 0);
+    memset(header, 0, ahci_port_chdr_size);
+    ahci_port_chdr_w_insert(header, 0);
+    ahci_port_chdr_a_insert(header, 0);
+    ahci_port_chdr_cfl_insert(header, sizeof(struct sata_fis_reg_h2d) / sizeof(uint32_t));
+    ahci_port_chdr_prdtl_insert(header, 1); // we use 1 PRD
+    ahci_port_chdr_ctba_insert(header, port->ctba_mem[0].paddr);
+
+    struct command_table* ct = port->command_table[0];
+
+    struct sata_fis_reg_h2d fis;
+    memset(&fis, 0, sizeof(struct sata_fis_reg_h2d));
+    fis.type = SATA_FIS_TYPE_H2D;
+    fis.command = 0xEC; // ATA_CMD_IDENTIFY
+    fis.device = 0;
+    fis.specialstuff = 0x80; // Command
+    command_table_set_cfis(ct, &fis);
+
+    ct->prdt[0] = region_descriptor_new(port->identify_mem.paddr, 511, false);
+
+    while (!ahci_port_is_ready(&port->port)) {}
+
+    // Ensure command processing is on
+    ahci_port_cmd_t cmd = ahci_port_cmd_rd(&port->port);
+    assert(ahci_port_cmd_cr_extract(cmd) == 1);
+
+    // Issue command in slot 0
+    ahci_port_ci_wr(&port->port, 0x1);
+
+    BLK_DEBUG("Issued IDENTIFY command.\n");
+    while ((ahci_port_ci_rd(&port->port) & 0x1) > 0) {
+        // TODO: abort on timeout
+        barrelfish_usleep(10000);
+    }
+
+    // Clear the interrupts
+    ahci_port_is_pss_wrf(&port->port, 0x1);
+
+    // Nothing else should've happened:
+    if (ahci_port_is_rd(&port->port) != 0x0) {
+#if defined(BLK_DEBUG_ENABLE)
+        char buf[4096];
+        ahci_port_is_pr(buf, 4096, &port->port);
+        BLK_DEBUG("GOT unhandled IRQ: %u\n", ahci_port_is_rd(&port->port));
+        puts(buf);
+#endif
+    }
+    assert(ahci_port_is_rd(&port->port) == 0x0);
+
+    BLK_DEBUG("IDENTIFY command processed.\n");
+    ata_identify_initialize(&port->identify, (mackerel_addr_t)port->identify_mem.vaddr);
+
+#if defined(BLK_DEBUG_ENABLE)
+    ahci_port_print_identification(&port->identify);
+#endif
+    return err;
+}
+
+errval_t blk_ahci_ports_init(struct ahci_disk *ad)
+{
+    errval_t err = SYS_ERR_OK;
+    size_t ports = ahci_hba_get_num_ports(&ad->controller);
+    size_t ncs = ahci_hba_cap_ncs_rdf(&ad->controller);
+    BLK_DEBUG("Implemented ports: %zu\n", ports);
+    BLK_DEBUG("Implemented command slots: %zu\n", ncs);
+
+    lvaddr_t base_address = blk_ahci_get_bar5_vaddr(ad);
+
+    // Determine which ports are implemented by the HBA, by reading the PI register. This bit
+    // map value will aid software in determining how many ports are available and which port
+    // registers need to be initialized.
+    for (size_t i = 0; i < ports; i++) {
+        struct ahci_port *port = &ad->ports[i];
+        if (!ahci_port_is_implemented(&ad->controller, i)) {
+            continue;
+        }
+        ahci_port_initialize(&port->port, (mackerel_addr_t)base_address + ahci_port_offset(i));
+
+        BLK_DEBUG("Initializing port: %zu\n", i);
+        uint32_t probe = ahci_port_probe(&port->port);
+        if (probe == 0) {
+            BLK_DEBUG("Port %zu no connection\n", i);
+            continue;
+        }
+        else if (probe == 0x00000101) {
+            BLK_DEBUG("Port %zu found SATA device, initializing.\n", i);
+        }
+        else {
+            BLK_DEBUG("Port %zu unkown signature: %d\n", i, ahci_port_sig_rd(&port->port));
+            continue;
+        }
+
+        // Ensure that the controller is not in the running state by reading and examining each
+        // implemented port’s PxCMD register. If PxCMD.ST, PxCMD.CR, PxCMD.FRE and
+        // PxCMD.FR are all cleared, the port is in an idle state.
+        if (!ahci_port_is_idle(&port->port)) {
+            BLK_DEBUG("Port %zu is running, stopping it.", i);
+            ahci_port_stop(&port->port);
+        }
+        assert(ahci_port_is_idle(&port->port)); // if this triggers, try a port reset...
+
+        // For each implemented port, system software shall allocate memory for and program:
+        //  - PxCLB and PxCLBU
+        //  - PxFB and PxFBU
+        port_init_clb(port);
+        port_init_fb(port);
+
+        // After setting PxFB and PxFBU to the physical address of the FIS receive area,
+        // system software shall set PxCMD.FRE to ‘1’.
+        ahci_port_cmd_fre_wrf(&port->port, 0x1);
+
+        // For each implemented port, clear the PxSERR register, by writing ‘1s’ to each bit location.
+        uint32_t serr = ahci_port_serr_rd(&port->port);
+        ahci_port_serr_wr(&port->port, serr);
+
+        // Determine which events should cause an interrupt, and set each implemented port’s PxIE
+        ahci_port_ie_wr(&port->port, 0xffffffff);
+
+        assert(ncs < MAX_CTBA_SLOTS);
+        for (size_t slot = 0; slot < ncs; slot++) {
+            port_init_ctba(port, slot);
+        }
+
+        BLK_DEBUG("Waiting for port %zu to become ready\n", i);
+        while(!ahci_port_is_functional(&port->port)) {
+            barrelfish_usleep(5000);
+        }
+        ahci_port_start(&port->port);
+
+        BLK_DEBUG("Initialized port %zu\n", i);
+        err = port_identify(port);
+        assert(err_is_ok(err));
+
+        port->ncs = ahci_hba_get_command_slots(&ad->controller);
+        port->interrupt = blk_ahci_interrupt;
+        port->is_initialized = true;
+    }
+
+    return err;
+}
diff --git a/lib/blk/blk_ahci/blk_ahci.h b/lib/blk/blk_ahci/blk_ahci.h
new file mode 100644 (file)
index 0000000..00396b6
--- /dev/null
@@ -0,0 +1,110 @@
+
+/*
+ * Copyright (c) 2016, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef _BLK_AHCI_
+#define _BLK_AHCI_
+
+#include <barrelfish/barrelfish.h>
+#include <pci/mem.h>
+#include <blk/ahci.h>
+#include <devif/queue.h>
+
+#include <dev/ahci_hba_dev.h>
+#include <dev/ahci_port_dev.h>
+#include <dev/ata_identify_dev.h>
+
+#include "../dma_mem/dma_mem.h"
+
+#define MAX_AHCI_PORTS 32
+#define MAX_CTBA_SLOTS 32
+
+#define MAX_HBA 32
+#define MAX_BUFFERS 256
+#define MAX_REQUESTS MAX_CTBA_SLOTS
+
+struct __attribute__((__packed__)) region_descriptor {
+    /// Data base address
+    uint64_t dba;
+    uint32_t reserved;
+    /// Byte count and Interrupt bit (31)
+    uint32_t dbc;
+};
+
+struct __attribute__((__packed__)) command_table {
+    /// Command FIS
+    uint8_t cfis[64];
+    /// ATAPI command
+    uint8_t acmd[16];
+    uint8_t reserved[48];
+    /// Physical Descriptior Region Table entries
+    /// Can be up to 65536 entries, we limit this to 248 for now
+    /// (which limits the size of CommandTable to a single page).
+    struct region_descriptor prdt[248];
+};
+
+
+struct ahci_port;
+struct dev_queue;
+typedef void (*ahci_port_interrupt_handler_fn)(struct ahci_port*, struct dev_queue*);
+
+struct ahci_port {
+    bool is_initialized; //< Port is up and running, ready to read/write.
+    ahci_port_t port;
+    struct dma_mem fb;
+    struct dma_mem clb;
+    struct dma_mem ctba_mem[MAX_CTBA_SLOTS];
+    struct command_table* command_table[MAX_CTBA_SLOTS]; //< Points to ctba_mem[i].vaddr
+    size_t ncs; //< Number of command slots actually implemented
+    ahci_port_interrupt_handler_fn interrupt;
+    struct ahci_mgmt_binding *binding;
+    struct dma_mem identify_mem;
+    ata_identify_t identify; //< Points to identify_mem.vaddr, valid after port_identify() is done.
+};
+
+struct ahci_disk {
+    struct device_mem* bar5;
+    ahci_hba_t controller;
+    struct ahci_port ports[MAX_AHCI_PORTS];
+};
+
+
+enum RequestStatus {
+    RequestStatus_Unused = 0,
+    RequestStatus_InProgress = 1,
+    RequestStatus_Done = 2
+};
+
+struct dev_queue_request {
+    regionid_t region_id;
+    struct dma_mem region;
+    uint64_t command_slot;
+
+    lpaddr_t base;
+    size_t length;
+    bufferid_t buffer_id;
+
+    errval_t error;
+    enum RequestStatus status;
+};
+
+struct dev_queue {
+    struct ahci_port* port;
+    struct dma_mem buffers[MAX_BUFFERS];
+    struct dev_queue_request requests[MAX_REQUESTS];
+};
+
+/* ahci_port_init.h */
+errval_t blk_ahci_ports_init(struct ahci_disk *ad);
+errval_t blk_ahci_port_dma(struct ahci_port *port, uint64_t block, struct dma_mem *buffer, bool write);
+errval_t blk_ahci_port_dma_async(struct ahci_port *port, size_t slot, uint64_t block, lpaddr_t base, size_t length, bool write);
+
+lvaddr_t blk_ahci_get_bar5_vaddr(struct ahci_disk* ad);
+
+#endif // _BLK_AHCI_
diff --git a/lib/blk/blk_ahci/device_impl.c b/lib/blk/blk_ahci/device_impl.c
new file mode 100644 (file)
index 0000000..67f864e
--- /dev/null
@@ -0,0 +1,237 @@
+#include <barrelfish/barrelfish.h>
+#include <assert.h>
+#include <devif/queue.h>
+
+#include "blk_ahci.h"
+#include "ahci_dev.h" // TODO: get rid of this include
+#include "../dma_mem/dma_mem.h"
+#include "../blk_debug.h"
+
+static bool is_valid_buffer(struct dev_queue* dq, size_t slot)
+{
+    return !capref_is_null(dq->buffers[slot].frame);
+}
+
+static errval_t request_slot_alloc(struct dev_queue* dq, size_t* slot)
+{
+    assert(dq->port->ncs <= MAX_REQUESTS);
+
+    for (size_t i=0; i < dq->port->ncs; i++) {
+        struct dev_queue_request *dqr = &dq->requests[i];
+        if (dqr->status == RequestStatus_Unused) {
+            dqr->status = RequestStatus_InProgress;
+            *slot = i;
+            return SYS_ERR_OK;
+        }
+    }
+
+    return DEV_ERR_QUEUE_FULL;
+}
+
+static errval_t get_port(struct ahci_disk* hba, size_t port_num, struct ahci_port** p) {
+    assert(hba != NULL);
+    assert(port_num < MAX_AHCI_PORTS);
+    errval_t err = SYS_ERR_OK;
+
+    struct ahci_port* port = &hba->ports[port_num];
+    if (!port->is_initialized) {
+        return err_push(err, DEV_ERR_NOT_INITIALIZED);
+    }
+
+    *p = port;
+    return SYS_ERR_OK;
+}
+
+static errval_t init_queue(struct dev_queue** dq, struct ahci_port *port) {
+    struct dev_queue* queue = calloc(1, sizeof(struct dev_queue));
+    if (dq == NULL) {
+        return LIB_ERR_MALLOC_FAIL;
+    }
+
+    queue->port = port;
+    for (size_t i = 0; i< MAX_BUFFERS; i++) {
+        queue->buffers[i].frame = NULL_CAP;
+    }
+
+    *dq = queue;
+    return SYS_ERR_OK;
+}
+
+static bool slice_is_in_range(struct dma_mem *mem, lpaddr_t base, size_t length)
+{
+    bool lower_bound = mem->paddr <= base;
+    bool upper_bound = mem->paddr+mem->bytes >= base+length;
+
+    return lower_bound && upper_bound;
+}
+
+static uint64_t flags_get_block(uint64_t flags)
+{
+    return flags & ((1ULL<<49) - 1);
+}
+
+static bool flags_is_write(uint64_t flags) {
+    return (flags & (1ULL << 63)) > 0;
+}
+
+void devq_interrupt_handler(void* q);
+void devq_interrupt_handler(void* q)
+{
+    if (q == NULL) {
+        BLK_DEBUG("Ignored interrupt, device not yet initialized?\n");
+        return;
+    }
+    struct dev_queue *queue = q;
+    struct ahci_port *port = queue->port;
+
+    assert(port->interrupt != NULL);
+    port->interrupt(port, queue);
+}
+
+errval_t devq_create(void* st, char *device_name, uint64_t flags, void **queue)
+{
+    errval_t err = SYS_ERR_OK;
+
+    struct ahci_port* port;
+    err = get_port(st, flags, &port);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    struct dev_queue *dq;
+    err = init_queue(&dq, port);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    *queue = dq;
+
+    return err;
+}
+
+errval_t devq_destroy(void *qp)
+{
+    struct dev_queue *queue = qp;
+
+    // TODO: Wait for stuff to finish...!
+
+    // Clean-up memory:
+    for (size_t i = 0; i< MAX_BUFFERS; i++) {
+        dma_mem_free(&queue->buffers[i]);
+    }
+    free(qp);
+    return SYS_ERR_OK;
+}
+
+errval_t devq_enqueue(void *q, regionid_t region_id, lpaddr_t base, size_t length, bufferid_t buffer_id, uint64_t flags)
+{
+    struct dev_queue *queue = q;
+    assert(region_id < MAX_BUFFERS);
+    assert(is_valid_buffer(queue, region_id));
+    assert(base != 0);
+    assert(length >= 512);
+
+    struct dma_mem* mem = &queue->buffers[region_id];
+
+    if (!slice_is_in_range(mem, base, length)) {
+        return DEV_ERR_INVALID_BUFFER_ARGS;
+    }
+
+    size_t slot;
+    errval_t err = request_slot_alloc(queue, &slot);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    struct dev_queue_request *dqr = &queue->requests[slot];
+    dqr->status = RequestStatus_InProgress;
+    dqr->buffer_id = buffer_id;
+    dqr->base = base;
+    dqr->length = length;
+    dqr->region_id = region_id;
+    dqr->command_slot = slot;
+
+    uint64_t block = flags_get_block(flags);
+    bool write = flags_is_write(flags);
+    return blk_ahci_port_dma_async(queue->port, slot, block, base, length, write);
+}
+
+errval_t devq_dequeue(void *q,
+                      regionid_t* region_id,
+                      lpaddr_t* base,
+                      size_t* length,
+                      bufferid_t* buffer_id)
+{
+    assert(q != NULL);
+    assert(region_id != NULL);
+    assert(base != NULL);
+    assert(length != NULL);
+    assert(length != NULL);
+
+    struct dev_queue *queue = q;
+
+    for (size_t i=0; i<queue->port->ncs; i++) {
+        struct dev_queue_request *dqr = &queue->requests[i];
+        if (dqr->status == RequestStatus_Done) {
+            *base = dqr->base;
+            *length = dqr->length;
+            *buffer_id = dqr->buffer_id;
+            *region_id = dqr->region_id;
+
+            dqr->status = RequestStatus_Unused;
+            return dqr->error;
+        }
+    }
+
+    return DEV_ERR_QUEUE_EMPTY;
+}
+
+errval_t devq_register(void *q,
+                       struct capref cap,
+                       regionid_t* region_id)
+{
+    errval_t err = DEV_ERR_REGISTER_BUFFER;
+    assert(!capref_is_null(cap));
+    struct dev_queue *queue = q;
+
+    for (size_t i=0; i<MAX_BUFFERS; i++) {
+        if (is_valid_buffer(q, i)) {
+            printf("Don't overwrite existing buffer\n");
+            continue;
+        }
+
+        struct dma_mem* mem = &queue->buffers[i];
+        err = dma_mem_from_capref(cap, mem);
+        if (err_is_fail(err)) {
+            DEBUG_ERR(err, "call failed");
+            return err_push(err, DEV_ERR_REGISTER_BUFFER);
+        }
+
+        *region_id = i;
+        return SYS_ERR_OK;
+    }
+
+    return err;
+}
+
+errval_t devq_remove(void *q, regionid_t region_id)
+{
+    assert(region_id < MAX_BUFFERS);
+    assert(q != NULL);
+    struct dev_queue *queue = q;
+
+    struct dma_mem* mem = &queue->buffers[region_id];
+    assert(!capref_is_null(mem->frame));
+
+    return dma_mem_free(mem);
+}
+
+errval_t devq_sync(void *q)
+{
+    return SYS_ERR_OK;
+}
+
+errval_t devq_control(void *q, uint64_t request, uint64_t value)
+{
+    return SYS_ERR_OK;
+}
diff --git a/lib/blk/blk_ahci/sata_fis.c b/lib/blk/blk_ahci/sata_fis.c
new file mode 100644 (file)
index 0000000..fff051c
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2011 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <stdlib.h>
+#include <errors/errno.h>
+#include "sata_fis.h"
+
+void sata_h2d_fis_new(struct sata_fis_reg_h2d* fis, uint8_t command, uint64_t lba, uint16_t sectors)
+{
+    sata_h2d_fis_init(fis);
+    sata_h2d_set_command(fis, command);
+    sata_h2d_set_lba48(fis, lba);
+    sata_h2d_set_count(fis, sectors);
+}
+
+void sata_h2d_fis_init(struct sata_fis_reg_h2d* fis)
+{
+    fis->type = SATA_FIS_TYPE_H2D;
+
+    /* Device Shadow Register layout (see: [1])
+     * [  7  |  6  |  5  |  4  |  3  |  2  |  1  |  0  ]
+     * [  -  |  L  |  -  | DEV | HS3 | HS2 | HS1 | HS0 ]
+     *
+     * L is the address mode, cleared implies CHS addressing, set, LBA addressing
+     * DEV device select, cleared and set imply Device 0 and 1 resp.
+     *   for SATA this should always be cleared (see: [2])
+     * HS3-HS0 are bits 28-25 of the LBA 28 (not used for LBA 48, see [3])
+     *
+     * [1] Serial ATA NSSD Rev. 1.0 (Sept 2008), section 6.3.1
+     * [2] Serial ATA Rev. 2.6 (15-February-2007), section 13.1, paragraph 2
+     * [3] ATA8-ACS Rev. 3f (December 11, 2006), section 7.1.5.2
+     */
+    fis->device |= (1 << 6);
+}
+
+void sata_h2d_set_command(struct sata_fis_reg_h2d* fis, uint8_t command)
+{
+    fis->command = command;
+    /* set bit to indicate update of command register (see [1])
+     *
+     * [1]: SATA Rev. 2.6 (15-February-2007), section 10.3.4
+     */
+    fis->specialstuff |= (1 << 7);
+}
+
+void sata_h2d_set_feature(struct sata_fis_reg_h2d* fis, uint8_t feature)
+{
+    fis->feature = feature;
+}
+
+void sata_h2d_set_lba28(struct sata_fis_reg_h2d* fis, uint32_t lba)
+{
+    fis->lba0 = lba & 0xFF;
+    fis->lba1 = (lba >> 8) & 0xFF;
+    fis->lba2 = (lba >> 16) & 0xFF;
+    fis->device = (fis->device & ~0x0F) | ((lba >> 24) & 0x0F);
+}
+
+void sata_h2d_set_lba48(struct sata_fis_reg_h2d* fis, uint64_t lba)
+{
+    fis->lba0 = lba & 0xFF;
+    fis->lba1 = (lba >> 8) & 0xFF;
+    fis->lba2 = (lba >> 16) & 0xFF;
+    fis->device &= 0xF0; // clear bits otherwise used by lba28
+
+    fis->lba3 = (lba >> 24) & 0xFF;
+    fis->lba4 = (lba >> 32) & 0xFF;
+    fis->lba5 = (lba >> 40) & 0xFF;
+}
+
+void sata_h2d_set_count(struct sata_fis_reg_h2d* fis, uint16_t count)
+{
+    fis->countl = count & 0xFF;
+    fis->counth = (count >> 8) & 0xFF;
+}
similarity index 62%
rename from include/ahci/sata_fis.h
rename to lib/blk/blk_ahci/sata_fis.h
index 169ba8f..07896d8 100644 (file)
@@ -10,6 +10,8 @@
 #ifndef _AHCI_SATA_FIS_H
 #define _AHCI_SATA_FIS_H
 
+#include <stdint.h>
+
 #define SATA_FIS_TYPE_H2D      0x27 // Register FIS - Host to Device
 #define SATA_FIS_TYPE_D2H      0x34 // Register FIS - Device to Host
 #define SATA_FIS_TYPE_DMAA     0x39 // DMA Activate FIS - Device to Host
 #define SATA_FIS_TYPE_PIO      0x5F // PIO Setup FIS - Device to Host
 #define SATA_FIS_TYPE_SDB      0xA1 // Set Device Bits FIS - Device to Host
 
+#define ATA_CMD_READ_PIO          0x20
+#define ATA_CMD_READ_PIO_EXT      0x24
+#define ATA_CMD_READ_DMA          0xC8
+#define ATA_CMD_READ_DMA_EXT      0x25
+#define ATA_CMD_WRITE_PIO         0x30
+#define ATA_CMD_WRITE_PIO_EXT     0x34
+#define ATA_CMD_WRITE_DMA         0xCA
+#define ATA_CMD_WRITE_DMA_EXT     0x35
+#define ATA_CMD_CACHE_FLUSH       0xE7
+#define ATA_CMD_CACHE_FLUSH_EXT   0xEA
+#define ATA_CMD_PACKET            0xA0
+#define ATA_CMD_IDENTIFY_PACKET   0xA1
+#define ATA_CMD_IDENTIFY          0xEC
+
 struct sata_fis_reg_h2d {
        unsigned char type;
        unsigned char specialstuff;
@@ -66,12 +82,14 @@ struct sata_fis_reg_d2h {
        unsigned char reserved3[4];
 };
 
-errval_t sata_alloc_h2d_register_fis(void **fis, size_t *fis_size);
 
-errval_t sata_set_command(void *fis, uint8_t command);
-errval_t sata_set_feature(void *fis, uint8_t feature);
-errval_t sata_set_lba28(void *fis, uint32_t lba);
-errval_t sata_set_lba48(void *fis, uint64_t lba);
-errval_t sata_set_count(void *fis, uint16_t count);
+void sata_h2d_fis_new(struct sata_fis_reg_h2d* fis, uint8_t command, uint64_t lba, uint16_t sectors);
+void sata_h2d_fis_init(struct sata_fis_reg_h2d* fis);
+void sata_h2d_set_command(struct sata_fis_reg_h2d* fis, uint8_t command);
+void sata_h2d_set_feature(struct sata_fis_reg_h2d* fis, uint8_t feature);
+void sata_h2d_set_lba28(struct sata_fis_reg_h2d* fis, uint32_t lba);
+void sata_h2d_set_lba48(struct sata_fis_reg_h2d* fis, uint64_t lba);
+void sata_h2d_set_count(struct sata_fis_reg_h2d* fis, uint16_t count);
+
 
 #endif // _AHCI_SATA_FIS_H
diff --git a/lib/blk/blk_debug.h b/lib/blk/blk_debug.h
new file mode 100644 (file)
index 0000000..a3aea1e
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef BLK_DEBUG_H_
+#define BLK_DEBUG_H_
+
+//#define BLK_DEBUG_ENABLE 1
+
+#if defined(BLK_DEBUG_ENABLE) || defined(GLOBAL_DEBUG)
+#define BLK_DEBUG(x...) printf("BLK: " x)
+#else
+#define BLK_DEBUG(x...) ((void)0)
+#endif
+
+#endif
diff --git a/lib/blk/dma_mem/dma_mem.c b/lib/blk/dma_mem/dma_mem.c
new file mode 100644 (file)
index 0000000..2412b96
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <string.h>
+#include <barrelfish/barrelfish.h>
+#include "dma_mem.h"
+
+errval_t dma_mem_from_capref(struct capref frame, struct dma_mem *mem)
+{
+    errval_t err = SYS_ERR_OK;
+    if (mem == NULL) {
+        return DMA_ERR_ARG_INVALID;
+    }
+
+    struct frame_identity id;
+    err = invoke_frame_identify(frame, &id);
+    if (err_is_fail(err)) {
+        DEBUG_ERR(err, "invoke frame id");
+        return err;
+    }
+
+    mem->paddr = id.base;
+    mem->bytes = id.bytes;
+    mem->requested = id.bytes;
+    mem->frame = frame;
+
+    void *addr;
+    err = vspace_map_one_frame_attr(&addr, mem->bytes, mem->frame, VREGION_FLAGS_READ_WRITE,
+                                    NULL, NULL);
+    if (err_is_fail(err)) {
+        dma_mem_free(mem);
+        return err;
+    }
+
+    mem->vaddr = (lvaddr_t)addr;
+
+    return SYS_ERR_OK;
+}
+
+/**
+ * \brief allocates and maps a memory region to be used for DMA purposes
+ *
+ * \param bytes minimum size of the memory region in bytes
+ * \param flags VREGION flags how the region gets mapped
+ * \param mem   returns the mapping information
+ *
+ * \returns SYS_ERR_OK on success
+ *          errval on error
+ */
+errval_t dma_mem_alloc(size_t bytes, struct dma_mem *mem)
+{
+    errval_t err = SYS_ERR_OK;
+    mem->requested = bytes;
+    bytes = ROUND_UP(BASE_PAGE_SIZE, bytes);
+
+    if (mem == NULL) {
+        return DMA_ERR_ARG_INVALID;
+    }
+
+    err = frame_alloc(&mem->frame, bytes, &mem->bytes);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    struct frame_identity id;
+    err = invoke_frame_identify(mem->frame, &id);
+    if (err_is_fail(err)) {
+        dma_mem_free(mem);
+        return err;
+    }
+
+    mem->paddr = id.base;
+
+    void *addr;
+    err = vspace_map_one_frame_attr(&addr, mem->bytes, mem->frame, VREGION_FLAGS_READ_WRITE,
+                                    NULL, NULL);
+    if (err_is_fail(err)) {
+        dma_mem_free(mem);
+        return err;
+    }
+
+    mem->vaddr = (lvaddr_t)addr;
+
+    return SYS_ERR_OK;
+}
+
+/**
+ * \brief tries to free the allocated memory region
+ *
+ * \returns SYS_ERR_OK on success
+ *          errval on error
+ */
+errval_t dma_mem_free(struct dma_mem *mem)
+{
+    errval_t err;
+
+    if (mem->vaddr) {
+        err = vspace_unmap((void*)mem->vaddr);
+        if (err_is_fail(err)) {
+            USER_PANIC_ERR(err, "call failed.");
+        }
+    }
+
+    if (!capref_is_null(mem->frame)) {
+        err = cap_destroy(mem->frame);
+        if (err_is_fail(err)) {
+            if (err_is_fail(err)) {
+                USER_PANIC_ERR(err, "call failed.");
+            }
+        }
+    }
+
+    memset(mem, 0, sizeof(*mem));
+
+    return SYS_ERR_OK;
+}
diff --git a/lib/blk/dma_mem/dma_mem.h b/lib/blk/dma_mem/dma_mem.h
new file mode 100644 (file)
index 0000000..26f0350
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef LIB_DMA_MEM_UTILS_H
+#define LIB_DMA_MEM_UTILS_H
+
+#include <barrelfish/types.h>
+#include <barrelfish/capabilities.h>
+
+struct dma_mem
+{
+    lvaddr_t vaddr;         ///< virtual address of the mapped region
+    lpaddr_t paddr;         ///< physical address of the underlying frame
+    uint64_t bytes;         ///< size of the region in bytes
+    uint64_t requested;     ///< requested size of the region in bytes (<= bytes)
+    struct capref frame;    ///< frame capability backing this region
+};
+
+/**
+ * \brief allocates and maps a memory region to be used for DMA purposes
+ *
+ * \param bytes minimum size of the memory region in bytes
+ * \param mem   returns the mapping information
+ *
+  * \returns SYS_ERR_OK on success
+ *          errval on error
+ */
+errval_t dma_mem_alloc(size_t bytes, struct dma_mem *mem);
+
+/**
+ * \brief Initializes a dma_mem struct for a given capref
+ *
+ * \param frame The frame with a reference to memory
+ *
+ * \returns SYS_ERR_OK on success
+ *          errval on error
+ */
+errval_t dma_mem_from_capref(struct capref frame, struct dma_mem *mem);
+
+/**
+ * \brief tries to free the allocated memory region
+ *
+ * \returns SYS_ERR_OK on success
+ *          errval on error
+ */
+errval_t dma_mem_free(struct dma_mem *mem);
+
+
+
+#endif /* LIB_DMA_MEM_UTILS_H */
index bab725f..225ed03 100644 (file)
@@ -188,7 +188,10 @@ errval_t pci_register_driver_movable_irq(pci_driver_init_fn init_func, uint32_t
                 bar->frame_cap[nc] = cap;
                 if (nc == 0) {
                     struct frame_identity id = { .base = 0, .bytes = 0 };
-                    invoke_frame_identify(cap, &id);
+                    err = invoke_frame_identify(cap, &id);
+                    if (err_is_fail(err)) {
+                        USER_PANIC_ERR(err, "frame identify failed.");
+                    }
                     bar->paddr = id.base;
                     bar->bits = log2ceil(id.bytes);
                     bar->bytes = id.bytes * ncaps;
@@ -205,6 +208,7 @@ errval_t pci_register_driver_movable_irq(pci_driver_init_fn init_func, uint32_t
     }
 
     // initialize the device. We have all the caps now
+    PCI_CLIENT_DEBUG("Succesfully done with pci init.\n");
     init_func(bars, nbars);
 
     err = SYS_ERR_OK;
index 773bbe7..31dbee6 100644 (file)
@@ -140,7 +140,8 @@ def default_bootmodules(build, machine):
 
         if machine.name == "sbrinz1" or machine.name == "sbrinz2" \
         or machine.name == "tomme1" or machine.name == "tomme2" \
-        or machine.name == "appenzeller" or is_babybel == 1 :
+        or machine.name == "tilsiter1" or machine.name == "appenzeller" \
+        or is_babybel == 1:
             # PCI allocation broken, use BIOS plan
             m.add_module("%s/sbin/pci" % a, ["auto",
                                              "skb_bridge_program=bridge_bios"] + machine.get_pci_args())
index deeb5dd..7502503 100755 (executable)
@@ -129,7 +129,7 @@ def process_results(test, path):
         except NotImplementedError:
             passed = None
         if passed is False:
-            debug.log('Test %s FAILED' % test.name)
+            debug.log('Test %s FAILED %s' % (test.name, '(' + result.reason() + ')') )
             retval = False
         elif passed:
             debug.verbose('Test %s PASSED' % test.name)
index bc2090c..873c7e6 100644 (file)
@@ -165,6 +165,15 @@ machines = dict({
                 'xphi_tickrate'   : 1140,
                 'xphi_ram_gb'     : 6},
 
+   'tilsiter1': {'ncores'          : 2,
+                 'machine_name'    : 'tilsiter1',
+                 'bootarch'        : 'x86_64',
+                 'buildarchs'      : ['x86_64'],
+                 'cores_per_socket': 2,
+                 'perfcount_type'  : 'intel',
+                 'tickrate'        : 2500,
+                 'boot_timeout'    : 120},
+
     'nos4-32'   : {'ncores'      : 4,
                    'machine_name' : 'nos4',
                    'bootarch' : 'x86_32',
@@ -261,7 +270,7 @@ machines = dict({
                     'perfcount_type': 'intel',
                     'tickrate'    : 1870,
                     'boot_timeout': 360},
-    
+
     'vacherin-32': {'ncores'      : 4,
                 'machine_name' : 'vacherin',
                 'bootarch' : 'x86_32',
@@ -296,7 +305,6 @@ machines = dict({
                    'perfcount_type'  : 'intel',
                    'tickrate'        : 2500,
                    'boot_timeout'    : 360},
-
     'babybel4-32': {'ncores'          : 20,
                    'machine_name'    : 'babybel4',
                    'bootarch'        : 'x86_32',
@@ -315,7 +323,7 @@ machines = dict({
                    'perfcount_type'  : 'intel',
                    'tickrate'        : 1140,
                    'host_tickrate'   : 2500,
-                   'boot_timeout'    : 360}, 
+                   'boot_timeout'    : 360},
     'xeon_phi_2': {'ncores'          : 64,
                    'nphi'            : 2,
                    'host_ncores'     : 20,
@@ -349,9 +357,9 @@ machines = dict({
                    'tickrate'        : 1140,
                    'host_tickrate'   : 2500,
                    'boot_timeout'    : 360},
-                   
+
     # SK: For Python 2.7
-    # }.items() + { 
+    # }.items() + {
     #     'brie%s' % b: {
     #         'ncores' : 4,
     #         'machine_name' : ('brie%s' % b),
index 3299619..b71c97d 100755 (executable)
@@ -30,7 +30,7 @@ def parse_args():
 
     debug.current_level = options.debuglevel
     return dirs
-            
+
 
 def main(dirs):
     for dirname in dirs:
@@ -60,6 +60,5 @@ def main(dirs):
         debug.verbose('reprocess results')
         harness.process_results(test, dirname)
 
-
 if __name__ == "__main__":
     main(parse_args())
index 015dd03..4a19c21 100644 (file)
 from stats import Stats
 
 class ResultsBase(object):
-    def __init__(self, name=None):
+    def __init__(self, name=None, reason=""):
         self.name = name
+        self.fail_reason = reason
+
+    def reason(self):
+        return self.fail_reason
 
     def passed(self):
         """Returns true iff the test is considered to have passed."""
@@ -24,8 +28,8 @@ class ResultsBase(object):
 
 class PassFailResult(ResultsBase):
     """Stores results of test that is purely pass/fail."""
-    def __init__(self, passed):
-        super(PassFailResult, self).__init__()
+    def __init__(self, passed, reason=""):
+        super(PassFailResult, self).__init__(reason=reason)
         self.passfail = passed
 
     def passed(self):
@@ -37,6 +41,9 @@ class PassFailMultiResult(ResultsBase):
         self.errors = errors
         self.name = name
 
+    def reason(self):
+        return str(errors)
+
     def passed(self):
         return len(self.errors) == 0
 
@@ -66,9 +73,10 @@ class RowResults(ResultsBase):
         for r in self.rows:
             fh.write('\t'.join(map(str, r)) + '\n')
 
-    def mark_failed(self):
+    def mark_failed(self, reason):
         """Mark this test as having failed."""
         self.failed = True
+        self.fail_reason = reason
 
     def add_row(self, row):
         assert(len(row) == len(self.colnames))
diff --git a/tools/harness/tests/blk_tests.py b/tools/harness/tests/blk_tests.py
new file mode 100644 (file)
index 0000000..233fd08
--- /dev/null
@@ -0,0 +1,334 @@
+##########################################################################
+# Copyright (c) 2016, ETH Zurich.
+# All rights reserved.
+#
+# This file is distributed under the terms in the attached LICENSE file.
+# If you do not find this file, copies can be found by writing to:
+# ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+##########################################################################
+
+import re, datetime
+import debug, tests
+from common import TestCommon, TimeoutError
+from results import RowResults
+
+BLK_TEST_TIMEOUT = datetime.timedelta(minutes=8) # XXX: tilsiter1 needs a bit longer (slow write speeds?)
+
+bandwidth = {
+    'tilsiter1': {
+        'read': {
+            512: 32.67,
+            1024: 50.08,
+            2048: 90.15,
+            4096: 154.21,
+            8192: 236.92,
+            16384: 318.05,
+            32768: 379.68,
+            65536: 416.99,
+            131072: 428.64,
+            262144: 439.88,
+            524288: 495.27,
+            1048576: 528.16,
+            2097152: 546.71
+        },
+        'write': {
+            512: 5.41,
+            1024: 1.70,
+            2048: 3.32,
+            4096: 6.68,
+            8192: 26.50,
+            16384: 49.92,
+            32768: 88.74,
+            65536: 143.63,
+            131072: 212.54,
+            262144: 281.08,
+            524288: 377.55,
+            1048576: 436.48,
+            2097152: 49.25,
+        },
+    },
+
+    'vacherin': {
+        'read': {
+            512: 15.24,
+            1024: 15.35,
+            2048: 30.32,
+            4096: 57.29,
+            8192: 102.01,
+            16384: 167.28,
+            32768: 237.24,
+            65536: 316.74,
+            131072: 361.41,
+            262144: 405.19,
+            524288: 490.97,
+            1048576: 415.05,
+            2097152: 424.57
+        },
+        'write': {
+            512: 15.20,
+            1024: 12.55,
+            2048: 26.87,
+            4096: 51.89,
+            8192: 93.21,
+            16384: 152.43,
+            32768: 213.55,
+            65536: 296.29,
+            131072: 365.72,
+            262144: 412.98,
+            524288: 440.78,
+            1048576: 454.21,
+            2097152: 462.02,
+        }
+    },
+
+    'babybel1': {
+        'read': {
+            512: 43.42,
+            1024: 25.56,
+            2048: 31.16,
+            4096: 55.63,
+            8192: 85.02,
+            16384: 114.35,
+            32768: 105.40,
+            65536: 147.15,
+            131072: 414.57,
+            262144: 482.58,
+            524288: 515.73,
+            1048576: 534.20,
+            2097152: 544.49,
+            4194304: 549.79,
+        },
+        'write': {
+            512: 42.52,
+            1024: 38.18,
+            2048: 41.29,
+            4096: 75.26,
+            8192: 221.12,
+            16384: 267.90,
+            32768: 426.09,
+            65536: 494.36,
+            131072: 516.22,
+            262144: 526.34,
+            524288: 533.67,
+            1048576: 533.67,
+            2097152: 522.25,
+            4194304: 523.27
+        },
+    },
+
+    'babybel2': {
+        'read': {
+            512: 43.32,
+            1024: 14.08,
+            2048: 31.10,
+            4096: 55.14,
+            8192: 83.53,
+            16384: 108.78,
+            32768: 95.90,
+            65536: 115.02,
+            131072: 159.26,
+            262144: 427.62,
+            524288: 514.74,
+            1048576: 533.14,
+            2097152: 503.16
+        },
+        'write': {
+            512: 43.09,
+            1024: 22.52,
+            2048: 41.00,
+            4096: 75.28,
+            8192: 220.75,
+            16384: 268.17,
+            32768: 416.18,
+            65536: 497.10,
+            131072: 519.22,
+            262144: 529.46,
+            524288: 534.73,
+            1048576: 537.95,
+            2097152: 518.22,
+        },
+    },
+
+    'babybel3': {
+        'read': {
+            512: 43.53,
+            1024: 25.71,
+            2048: 31.09,
+            4096: 55.30,
+            8192: 83.35,
+            16384: 107.88,
+            32768: 95.66,
+            65536: 115.43,
+            131072: 161.73,
+            262144: 428.30,
+            524288: 514.24,
+            1048576: 532.87,
+            2097152: 504.82,
+        },
+        'write': {
+            512: 42.86,
+            1024: 38.40,
+            2048: 41.43,
+            4096: 75.83,
+            8192: 225.01,
+            16384: 265.78,
+            32768: 428.13,
+            65536: 495.27,
+            131072: 513.26,
+            262144: 528.42,
+            524288: 532.61,
+            1048576: 532.61,
+            2097152: 525.31,
+        }
+    },
+
+    'babybel4': {
+        'read': {
+            512: 43.46,
+            1024: 20.47,
+            2048: 23.44,
+            4096: 42.33,
+            8192: 64.98,
+            16384: 76.50,
+            32768: 64.45,
+            65536: 77.69,
+            131072: 111.00,
+            262144: 381.98,
+            524288: 492.54,
+            1048576: 512.53,
+            2097152: 451.34
+        },
+        'write': {
+            512: 42.49,
+            1024: 38.40,
+            2048: 41.47,
+            4096: 76.96,
+            8192: 225.20,
+            16384: 265.51,
+            32768: 430.19,
+            65536: 496.18,
+            131072: 517.22,
+            262144: 529.46,
+            524288: 534.73,
+            1048576: 534.73,
+            2097152: 524.29
+        }
+    }
+}
+
+class BlkTests(TestCommon):
+
+    def __init__(self, options):
+        super(BlkTests, self).__init__(options)
+
+    def get_module_name(self):
+        return "ahci_test"
+
+    def boot(self, *args):
+        super(BlkTests, self).boot(*args)
+        self.set_timeout(BLK_TEST_TIMEOUT)
+
+    def get_modules(self, build, machine):
+        self.machine = machine.name
+        vendor_device = "0:0"
+        if self.machine == "tilsiter1":
+            vendor_device = "8086:a102"
+        if self.machine == "vacherin":
+            vendor_device = "8086:8c02"
+        elif self.machine.startswith("babybel"):
+            vendor_device = "8086:1d02"
+
+        modules = super(BlkTests, self).get_modules(build, machine)
+        modules.add_module(self.get_module_name(), ["manual", vendor_device, self.OP])
+
+        return modules
+
+    def is_finished(self, line):
+        return line.startswith("AHCI testing completed.")
+
+    def process_data(self, testdir, rawiter):
+        self.regex = re.compile(self.REGEX)
+        result = RowResults(['op', 'buffer', 'block', 'bandwidth'])
+        if not bandwidth.has_key(self.machine):
+            result.mark_failed('No data about this disk, please set the initial performance values.')
+            return result
+
+        matches = 0
+        for line in rawiter:
+            match = self.regex.match(line)
+            if match:
+                matches += 1
+
+                buffer_size, bs, bw = match.groups()
+                buffer_size = int(buffer_size)
+                bs = int(bs)
+                bw = float(bw)
+                operation = self.OP.lower()
+                if not bandwidth[self.machine].has_key(operation):
+                    result.mark_failed('No data about this benchmark, please set the initial performance values.')
+                    return result
+                if not bandwidth[self.machine][operation].has_key(bs):
+                    result.mark_failed('No data for {} with bs {}.'.format(operation, bs))
+                    return result
+
+                lower_bound = bandwidth[self.machine][operation][bs] * (1 - 0.15)
+                upper_bound = bandwidth[self.machine][operation][bs] * (1 + 0.20)
+
+                result.add_row((operation, buffer_size, bs, bw))
+                if bw <= lower_bound:
+                    error = "{} for {} bytes blocks not within expected range (was {}, should be >= {}).".format(operation, bs, bw, lower_bound)
+                    debug.log(error)
+                    result.mark_failed(reason=error)
+                elif bw >= upper_bound:
+                    error = "Achieved {} bandwidth for {} bytes blocks was better ({}) than expected ({}).".format(operation, bs, bw, upper_bound)
+                    debug.log(error)
+                    debug.log("This is good, if you can explain it! Adjust the bandwidth numbers in blk_tests.py and re-run the test.")
+                    result.mark_failed(reason=error)
+                else:
+                    pass
+
+            if line.startswith("AHCI testing completed.") and matches > 0:
+                return result
+
+        result.mark_failed('Did not see end of test or got no bandwidth numbers.')
+        return result
+
+@tests.add_test
+class BlkAhciWriteBWTest(BlkTests):
+    ''' AHCI Driver Write Bandwidth Test'''
+    name = "blk_read_test"
+    OP = "read"
+    REGEX = r"\[ahci_perf_sequential\] Read sequential size (\d+) bs (\d+): (\d+\.\d+) \[MB/s\]"
+
+@tests.add_test
+class BlkAhciReadBWTest(BlkTests):
+    ''' AHCI Driver Read Bandwidth Test'''
+    name = "blk_write_test"
+    OP = "write"
+    REGEX = r"\[ahci_perf_sequential\] Write sequential size (\d+) bs (\d+): (\d+\.\d+) \[MB/s\]"
+
+@tests.add_test
+class BlkAhciVerifyTest(BlkTests):
+    ''' AHCI Driver Correctness test '''
+    name = "blk_verify_test"
+    OP = "verify"
+    REGEX = r"\[ahci_verify_sequential\] SUCCESS \((\d+) (\d+)\)"
+    TESTS = 14
+
+    def process_data(self, testdir, rawiter):
+        self.regex = re.compile(self.REGEX)
+
+        matches = 0
+        for line in rawiter:
+            match = self.regex.match(line)
+            if match:
+                matches += 1
+
+        if matches == self.TESTS:
+            return PassFailResult(True)
+        elif matches < self.TESTS:
+            return PassFailResult(False, "Some block/buffer size checks did not report back with SUCCESS.")
+        elif matches > self.TESTS:
+            return PassFailResult(False, "Got more SUCCESS lines than expected. If you changed the test you may need to increase self.TESTS.")
+        else:
+            assert "Should not come here"
index 2368c3f..c5f4425 100644 (file)
@@ -226,7 +226,7 @@ int main(int argc, char *argv[])
     // Parse CMD Arguments
     bool got_apic_id = false;
     bool do_video_init = false;
-    vtd_force_off = false;
+    vtd_force_off = true;
     for (int i = 1; i < argc; i++) {
         if(sscanf(argv[i], "apicid=%" PRIuPTR, &my_hw_id) == 1) {
             got_apic_id = true;
diff --git a/usr/ahcid/Hakefile b/usr/ahcid/Hakefile
deleted file mode 100644 (file)
index f954974..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
---------------------------------------------------------------------------
--- Copyright (c) 2007-2011, ETH Zurich.
--- All rights reserved.
---
--- This file is distributed under the terms in the attached LICENSE file.
--- If you do not find this file, copies can be found by writing to:
--- ETH Zurich D-INFK, Universitaetsstr. 6, CH-8092 Zurich. Attn: Systems Group.
---
--- Hakefile for /usr/drivers/ahci
--- 
---------------------------------------------------------------------------
-
-[ build application { target = "ahcid",
-                      cFiles = [ "ahcid.c", "ahcid_hwinit.c" ],
-                      flounderBindings = [ "ahci_mgmt" ],
-                      mackerelDevices = [ "ahci_hba", "ahci_port", "ata_identify" ],
-                      addLibraries = [ "pci", "skb", "ahci" ]
-                    }
-]
-
diff --git a/usr/ahcid/ahcid.c b/usr/ahcid/ahcid.c
deleted file mode 100644 (file)
index bde74e7..0000000
+++ /dev/null
@@ -1,643 +0,0 @@
-/*
- * Copyright (c) 2011 ETH Zurich.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include "ahcid.h"
-#include <barrelfish/waitset.h>
-#include <barrelfish/syscalls.h>
-#include <barrelfish/nameservice_client.h>
-#include <pci/pci.h>
-#include <if/ahci_mgmt_defs.h>
-#include <skb/skb.h>
-#include <ahci/sata_fis.h>
-#include <ahci/ahci_dma_pool.h>
-#include <dev/ahci_hba_dev.h>
-#include <dev/ata_identify_dev.h>
-#include "ahcid_debug.h"
-
-#define PCI_DEVICE_ICH9R_82801IR 0x2922
-#define PCI_DEVICE_ICH10_82801JI 0x3a22
-#define PCI_DEVICE_SB7x0 0x4390 // also SB8x0 SB9x0
-
-static ahci_hba_t controller;
-static uint8_t num_ports = -1;
-static struct ahcid_port_info **ports;
-
-static struct ahci_mgmt_binding **port_bindings;
-
-static char *my_service_name = "ahcid";
-
-static struct device_mem hbabar;
-
-#if defined(AHCI_SERVICE_DEBUG) || defined(GLOBAL_DEBUG)
-    static bool initialized = false;
-#endif
-
-struct device_id {
-    uint32_t vendor;
-    uint32_t device;
-};
-
-static void rx_list_call(struct ahci_mgmt_binding *b)
-{
-    AHCID_DEBUG("got list call\n");
-    uint8_t port;
-    uint8_t current_num_ports = (num_ports == (uint8_t)-1 ? 0 : num_ports);
-    uint8_t next_port = 0;
-    uint8_t *port_ids = malloc(current_num_ports);
-    for (port = 0; port < current_num_ports; port++) {
-        if (ports[port] && ports[port]->status == AHCID_PORT_STATUS_IDLE) {
-            port_ids[next_port++] = port;
-        }
-        else if (ports[port]) {
-            AHCID_DEBUG("skipping port %u with status %d\n",
-                    (unsigned int)port, (int)ports[port]->status);
-        }
-    }
-    AHCID_DEBUG("responding to list call with %u port_ids\n", (unsigned int)next_port);
-    ahci_mgmt_list_response__tx(b, MKCLOSURE(free, port_ids), port_ids, next_port);
-}
-
-static void rx_identify_call(struct ahci_mgmt_binding *b, uint8_t port_id)
-{
-    AHCID_DEBUG("got identify call\n");
-    if (ports[port_id] && ports[port_id]->status == AHCID_PORT_STATUS_IDLE) {
-        AHCID_DEBUG("responding...\n");
-        ahci_mgmt_identify_response__tx(b, NOP_CONT,
-                (uint8_t*)ports[port_id]->identify_data, 512);
-    }
-    else {
-        AHCID_DEBUG("not responding...\n");
-    }
-}
-
-static void rx_open_call(struct ahci_mgmt_binding *b, uint8_t port_id)
-{
-    AHCID_DEBUG("got open call\n");
-    if (ports[port_id] == NULL) {
-        ahci_mgmt_open_response__tx(b, NOP_CONT, AHCI_ERR_PORT_INVALID,
-                NULL_CAP, 0, 0);
-        return;
-    }
-    if (ports[port_id]->binding != NULL) {
-        ahci_mgmt_open_response__tx(b, NOP_CONT, AHCI_ERR_PORT_BUSY,
-                NULL_CAP, 0, 0);
-        return;
-    }
-    ports[port_id]->binding = b;
-    // find correct frame cap for port. should be a single cap as long as FRAME_SIZE > 0x80b.
-    uint32_t cap_size = hbabar.bytes / hbabar.nr_caps;
-    uint32_t offset = ahcid_port_offset(port_id);
-    int cap_index = 0;
-    while (offset >= cap_size) { cap_index++; offset -= cap_size; }
-
-    ahci_mgmt_open_response__tx(b, NOP_CONT, SYS_ERR_OK,
-            hbabar.frame_cap[cap_index], offset, ahci_hba_cap_rd(&controller));
-}
-
-static void rx_close_call(struct ahci_mgmt_binding *b, uint8_t port_id)
-{
-    AHCID_DEBUG("got close call\n");
-    if (ports[port_id] == NULL) {
-        ahci_mgmt_close_response__tx(b, NOP_CONT, AHCI_ERR_PORT_INVALID);
-        return;
-    }
-    errval_t retval = AHCI_ERR_PORT_MISMATCH;
-    if (ports[port_id]->binding == b) {
-        ports[port_id]->binding = NULL;
-        retval = SYS_ERR_OK;
-    }
-    ahci_mgmt_close_response__tx(b, NOP_CONT, retval);
-    return;
-}
-
-static struct ahci_mgmt_rx_vtbl rx_vtbl = {
-    .list_call = rx_list_call,
-    .list_response = NULL,
-    .identify_call = rx_identify_call,
-    .identify_response = NULL,
-    .open_call = rx_open_call,
-    .open_response = NULL,
-    .close_call = rx_close_call,
-    .close_response = NULL,
-    .command_completed = NULL,
-};
-
-static void export_cb(void *st, errval_t err, iref_t iref)
-{
-    if (err_is_fail(err)) {
-        USER_PANIC_ERR(err, "export failed");
-    }
-
-    AHCID_DEBUG("service exported at iref %u\n", iref);
-
-    // register this iref with the name service
-    err = nameservice_register(my_service_name, iref);
-    if (err_is_fail(err)) {
-        USER_PANIC_ERR(err, "nameservice_register failed");
-    }
-}
-
-static errval_t connect_cb(void *st, struct ahci_mgmt_binding *b)
-{
-    AHCID_DEBUG("got a connection!\n");
-
-    // copy my message receive handler vtable to the binding
-    b->rx_vtbl = rx_vtbl;
-
-    // accept the connection (we could return an error to refuse it)
-    return SYS_ERR_OK;
-}
-
-static void do_identify(struct ahcid_port_info *port)
-{
-    errval_t r;
-
-    // allocate frame for command table
-    struct ahci_dma_region *command_table;
-    r = ahci_dma_region_alloc(0x90, &command_table);
-    assert(err_is_ok(r));
-
-    // write command into command list
-    ahci_port_chdr_t commandlist = (ahci_port_chdr_t)port->command_list->vaddr;
-    memset(commandlist, 0, ahci_port_chdr_size);
-
-#if defined(AHCI_SERVICE_DEBUG) || defined(GLOBAL_DEBUG)
-    char buf[4096];
-    ahci_port_chdr_prtval(buf, 4096, commandlist);
-    AHCID_DEBUG("Command Header: \n");
-    puts(buf);
-#endif
-
-    // allocate dma region for identify result
-    struct ahci_dma_region **prd = calloc(1, sizeof(struct ahci_dma_region*));
-    r = ahci_dma_region_alloc(512, prd);
-    assert(err_is_ok(r));
-
-    memset((*prd)->vaddr, 0, 512);
-    port->prdts = prd;
-    port->prdt_count = 1;
-
-    ahci_port_chdr_w_insert(commandlist, 0); // dma on receive
-    ahci_port_chdr_a_insert(commandlist, 0);
-    ahci_port_chdr_cfl_insert(commandlist, 5);
-
-    // set dma region for identify result
-    ahci_port_chdr_prdtl_insert(commandlist, 1); // we use 1 PRD
-    ahci_port_chdr_ctba_insert(commandlist, (uint32_t)command_table->paddr);
-    ahci_port_chdr_ctbau_insert(commandlist, (uint32_t)(command_table->paddr>>32));
-
-
-    //char buf[4096];
-#if defined(AHCI_SERVICE_DEBUG) || defined(GLOBAL_DEBUG)
-    ahci_port_chdr_prtval(buf, 4096, commandlist);
-    AHCID_DEBUG("Command Header: \n");
-    puts(buf);
-#endif
-
-    // fill command table
-    memset(command_table->vaddr, 0, 0x90);
-
-    // FIS
-    struct sata_fis_reg_h2d *fis = command_table->vaddr;
-    fis->type = SATA_FIS_TYPE_H2D;
-    fis->command = 0xEC /* ATA_CMD_IDENTIFY */;
-    fis->device = 0;
-    fis->specialstuff = 0x80 /* command */;
-
-    // place PRD into PRDT which is at offset 0x80
-    uint32_t *prdt_entry = command_table->vaddr + 0x80;
-    prdt_entry[0] = (*prd)->paddr;
-    prdt_entry[3] = 511; // again this +1 thingy
-
-    // ensure command processing is on
-    ahci_port_cmd_t cmd = ahci_port_cmd_rd(&port->port);
-    assert(ahci_port_cmd_cr_extract(cmd) == 1);
-
-    // issue command in slot 0
-    ahci_port_ci_wr(&port->port, 1);
-
-    AHCID_DEBUG("Issued IDENTIFY command\n");
-
-    port->status = AHCID_PORT_STATUS_IDENTIFY_PENDING;
-}
-
-
-static void ahci_init(struct device_mem *bar_info, int nr_allocated_bars)
-{
-    // re-usable vars
-    int i;
-    char buf[4096];
-    errval_t r;
-
-    // registers
-    ahci_hba_ghc_t ghc;
-
-    // find BAR and map device data
-    AHCID_DEBUG("nr_allocated_bars = %d\n", nr_allocated_bars);
-    assert(nr_allocated_bars >= 1);
-    // Although the AHCI specification requires the AHCI memory region to be in
-    // BAR 5 (BAR 0 to 4 are used for legacy IDE mode) the QEMU AHCI emulation
-    // incorrectly uses BAR 0.  Because of this, ahcid consults both BAR 0 and
-    // BAR 5 to find the HBA's memory mapped I/O region.
-    if (nr_allocated_bars == 1) { // handle QEMU
-        memcpy(&hbabar, &bar_info[0], sizeof(struct device_mem));
-    } else if (nr_allocated_bars == 6) { // handle HW (AHCI in BAR 5)
-        memcpy(&hbabar, &bar_info[5], sizeof(struct device_mem));
-    } else {
-        AHCID_DEBUG("strange device... not supported\n");
-        abort();
-    }
-
-    map_device(&hbabar);
-    ahci_hba_initialize(&controller, (void *)(hbabar.vaddr));
-    AHCID_DEBUG("accessing conf regs starting at %p\n",
-            (void *)(hbabar.vaddr));
-    AHCID_DEBUG("physical address of conf regs: %p\n",
-            (void *)(hbabar.paddr));
-
-    // first of all, reset the device for fun and profit
-    ghc = ahci_hba_ghc_rd(&controller);
-    ghc = ahci_hba_ghc_hr_insert(ghc, 1);
-    AHCID_DEBUG("Resetting HBA (setting ghc = %x)...\n", ghc);
-    ahci_hba_ghc_wr(&controller, ghc);
-
-    // spec: "the device shall reset this bit to '0' " so we will wait
-    while (1) {
-        ghc = ahci_hba_ghc_rd(&controller);
-        if (ahci_hba_ghc_hr_extract(ghc) == 0) {
-            AHCID_DEBUG("reset done\n");
-            break;
-        }
-        sys_yield(CPTR_NULL);
-    }
-
-    // set HBA into AHCI mode
-    AHCID_DEBUG("Setting controller into AHCI mode\n");
-    ghc = ahci_hba_ghc_rd(&controller);
-    ghc = ahci_hba_ghc_ae_insert(ghc, 1);
-    ahci_hba_ghc_wr(&controller, ghc);
-
-    // disable interrupts for the moment during setup
-    ghc = ahci_hba_ghc_rd(&controller);
-    if (ahci_hba_ghc_ie_extract(ghc) == 1) {
-        AHCID_DEBUG("Interrupts are enabled. Disabling them during setup\n");
-        ghc = ahci_hba_ghc_ie_insert(ghc, 1);
-        ahci_hba_ghc_wr(&controller, ghc);
-    } else {
-        AHCID_DEBUG("Interrupts are disabled (as expected after a reset)\n");
-    }
-
-    // get number of ports the HBA supports
-    // AHCI spec 1.3, section 3.1.1; bits 0-4 specify number of ports, 0 being 1 port
-    num_ports = ahci_hba_cap_np_extract(ahci_hba_cap_rd(&controller)) + 1;
-    AHCID_DEBUG("HBA supports %d ports\n", num_ports);
-
-    ports = calloc(num_ports, sizeof(struct ahcid_port_info*));
-    port_bindings = calloc(num_ports, sizeof(struct ahci_mgmt_binding*));
-
-    // enable interrupts again
-    ghc = ahci_hba_ghc_rd(&controller);
-    ghc = ahci_hba_ghc_ie_insert(ghc, 1);
-    AHCID_DEBUG("Enabling HBA Interrupts\n");
-    ahci_hba_ghc_wr(&controller, ghc);
-
-    // init dma pool
-    r = ahci_dma_pool_init(1024 * 1024);
-
-    // initialize ports
-    r = ahcid_ports_init(ports, num_ports, ahci_hba_pi_rd(&controller),
-            (void *)(hbabar.vaddr));
-
-    for (i = 0; i < num_ports; i++) {
-        if (ports[i] != NULL) {
-            // read port state
-            ahci_port_ssts_t ssts = ahci_port_ssts_rd(&ports[i]->port);
-            if (ahci_port_ssts_det_extract(ssts) == ahci_port_detect) {
-                // we have a device
-                ahci_port_speed_prtval(buf, 4096, ahci_port_ssts_spd_extract(ssts));
-                AHCID_DEBUG("Device detected! Port: %d Type: %s\n", i, buf);
-
-                // enable all interrupts of this port
-                ahci_port_ie_wr(&ports[i]->port, -1);
-
-                // Clear PxSERR
-                ahci_port_serr_wr(&ports[i]->port, -1);
-
-                // wait until device is ready
-                ahci_port_tfd_pr(buf, 4096, &ports[i]->port);
-                AHCID_DEBUG("TFD: \n%s\n", buf);
-                AHCID_DEBUG("Waiting for device to become ready\n");
-                uint32_t taskfile;
-                while (1) {
-                    taskfile = ahci_port_tfd_rd(&ports[i]->port);
-                    // 7: BSY, 3: DRQ, 0: ERR
-                    if ((ahci_port_tfd_sts_extract(taskfile) & 0x89) == 0) {
-                        AHCID_DEBUG("Device ready\n");
-                        break;
-                    }
-                }
-
-                // start running commands
-                ahci_port_cmd_t cmd = ahci_port_cmd_rd(&ports[i]->port);
-                cmd = ahci_port_cmd_st_insert(cmd, 1);
-                ahci_port_cmd_wr(&ports[i]->port, cmd);
-
-                // send identify command to device
-                do_identify(ports[i]);
-            }
-        }
-    }
-
-    // export ahci management interface
-    ahci_mgmt_export(NULL /* state pointer for connect/export callbacks */,
-            export_cb, connect_cb, get_default_waitset(),
-            IDC_EXPORT_FLAGS_DEFAULT);
-
-#if defined(AHCI_SERVICE_DEBUG) || defined(GLOBAL_DEBUG)
-    initialized = true;
-#endif
-
-}
-
-static void ahci_interrupt_handler(void *arg)
-{
-    uint32_t hba_irq_state = ahci_hba_is_rd(&controller);
-
-    if (hba_irq_state == 0) {
-#ifdef AHCI_SERVICE_DEBUG
-        static uint32_t verb_count = 0;
-        verb_count++;
-        if (verb_count % 1 == 0) {
-            AHCID_DEBUG("Ignoring foreign interrupt\n");
-            AHCID_DEBUG("Port 0 Interrupt State: %"PRIu32"\n",
-                    ahci_port_is_rd(&ports[0]->port));
-            AHCID_DEBUG("Port 0 Command Issue state: %"PRIu32"\n",
-                    ahci_port_ci_rd(&ports[0]->port));
-        }
-#endif
-        // just ignore foreign interrupts
-        return;
-    }
-
-    bool interrupted_ports[32] = {false};
-    ahci_port_is_t interrupt_state[32] = {0};
-
-    int i = 0;
-    for (; i < 32; i++) { // check which ports have irq flag set
-        if ((hba_irq_state & (1 << i)) && ports[i]) {
-            AHCID_DEBUG("Interrupt for port %d\n", i);
-
-            ahci_port_is_t port_state = ahci_port_is_rd(&ports[i]->port);
-
-            // clear interrupts for port asap. (this is what FreeBSD also does)
-            ahci_port_is_wr(&ports[i]->port, port_state);
-
-            // process IDENTIFY response: QEMU sends D2H Register FIS, Spec.
-            // says device should send a PIO Setup FIS. We handle both for now :)
-            if ((ahci_port_is_dhrs_extract(port_state) == 1 ||
-                        ahci_port_is_pss_extract(port_state)) &&
-                    ports[i]->status == AHCID_PORT_STATUS_IDENTIFY_PENDING) {
-                // we got a d2h register or pio setup fis
-                uint8_t *d2hr_fis = ports[i]->receive_fis->vaddr +
-                    0x40 /* D2H Register FIS offset in rFIS */;
-                uint8_t *pss_fis = ports[i]->receive_fis->vaddr +
-                    0x20 /* D2H Register FIS offset in rFIS */;
-                uint8_t *fis;
-                if (ahci_port_is_dhrs_extract(port_state)) {
-                    // QEMU case: QEMU sends a D2H Register FIS as answer to
-                    // IDENTIFY Device (0xEC).
-                    // This is *NOT* according to AT Attachement 8, Sect. 7.16
-                    // IDENTIFY DEVICE which specifies PIO Data-in.
-                    // This does not change anything in handling the actual
-                    // IDENTIFY data, which is still stored in the indicated
-                    // DMA region.
-                    fis = d2hr_fis;
-                    if (fis[0] != SATA_FIS_TYPE_D2H) {
-                        AHCID_DEBUG("Interrupt signalled D2H Reg FIS but the"
-                                " FIS has another type (0x%02x)\n", fis[0]);
-                        continue; // handle next port
-                    }
-                }
-                else if (ahci_port_is_pss_extract(port_state)) {
-                    // ATA-8 compliant case. Real hardware seems to do this.
-                    // PIO Setup FIS should mean that we need to receive data
-                    // afterwards.
-                    // However the AHCI HBA handles that for us and copies the
-                    // received data into the DMA region specified in the
-                    // IDENTIFY command.
-                    fis = pss_fis;
-                    if (fis[0] != SATA_FIS_TYPE_PIO) {
-                        AHCID_DEBUG("Interrupt signalled PIO Setup FIS but the"
-                                " FIS has another type (0x%02x)\n", fis[0]);
-                        continue; // handle next port
-                    }
-                }
-
-                int identify_received = 1;
-                if (ports[i]->prdts != NULL && ports[i]->prdt_count == 1) {
-                    AHCID_DEBUG("coping data from IDENTIFY result on %d\n", i);
-                    memcpy(ports[i]->identify_data, ports[i]->prdts[0]->vaddr, 512);
-                    ata_identify_t identify;
-                    ata_identify_initialize(&identify,
-                            (char *)ports[i]->identify_data);
-#ifdef AHCI_SERVICE_DEBUG
-                    char buf[32768];
-                    ata_identify_pr(buf, 32768, &identify);
-                    puts(buf);
-#endif
-                }
-                else {
-                    AHCID_DEBUG("PRDTL structures not set up for port %d while"
-                            " processing IDENTIFY response.\n", i);
-                    identify_received = 0;
-                }
-
-                // uninitialize port
-                //  clear interrupts
-                ahci_port_is_wr(&ports[i]->port, -1);
-                //  disable all interrupts of this port
-                AHCID_DEBUG("disabling interrupts for %d\n", i);
-                ahci_port_ie_wr(&ports[i]->port, 0);
-                //  stop running commands
-                AHCID_DEBUG("stopping %d\n", i);
-                ahci_port_cmd_t cmd = ahci_port_cmd_rd(&ports[i]->port);
-                cmd = ahci_port_cmd_st_insert(cmd, 0);
-                ahci_port_cmd_wr(&ports[i]->port, cmd);
-                // free CL, rFIS
-                AHCID_DEBUG("clearing clb and fb for %d\n", i);
-                ahci_port_clb_wr(&ports[i]->port, 0);
-                ahci_port_fb_wr(&ports[i]->port, 0);
-                AHCID_DEBUG("freeing memory for %d\n", i);
-                ahci_dma_region_free(ports[i]->command_list);
-                ahci_dma_region_free(ports[i]->receive_fis);
-                ahci_dma_region_free(ports[i]->prdts[0]);
-                free(ports[i]->prdts);
-                // add port to skb
-                // TODO: true unique port_ids, more info?
-                if (identify_received) {
-                    skb_add_fact("ahci_device(%d).", i);
-                    ports[i]->status = AHCID_PORT_STATUS_IDLE;
-                    AHCID_DEBUG("Processing IDENTIFY from port %d complete\n", i);
-                }
-                else {
-                    ports[i]->status = AHCID_PORT_STATUS_UNINITIALIZED;
-                }
-                continue;
-            }
-#if defined(AHCI_SERVICE_DEBUG) || defined(GLOBAL_DEBUG)
-            else if (ports[i]->status == AHCID_PORT_STATUS_IDENTIFY_PENDING) {
-                AHCID_DEBUG("received unknown interrupt while waiting for"
-                        " IDENTIFY D2H Reg FIS\n");
-                char buf[2048];
-                ahci_port_is_prtval(buf, 2048, port_state);
-                AHCID_DEBUG("Port Status:\n");
-                puts(buf);
-            }
-#endif
-            if (ports[i]->binding != NULL) {
-                interrupted_ports[i] = true;
-                interrupt_state[i] = port_state;
-            } else {
-                AHCID_DEBUG("no client registered for port %d\n", i);
-            }
-        }
-    }
-
-    // clear interrupts for host controller
-    ahci_hba_is_wr(&controller, (uint32_t)-1);
-
-    // deliver messages to clients
-    for (i = 0; i < 32; i++) {
-        if (!interrupted_ports[i]) continue;
-
-        AHCID_DEBUG("Port %d Interrupt State: 0x%"PRIx32"\n",
-                i, interrupt_state[i]);
-        AHCID_DEBUG("Port %d Command Issue state: 0x%"PRIx32"\n",
-                i, ahci_port_ci_rd(&ports[i]->port));
-
-        ahci_mgmt_command_completed__tx(ports[i]->binding, NOP_CONT,
-                i, interrupt_state[i]);
-    }
-}
-
-static void ahci_reregister_handler(void *arg)
-{
-    errval_t err;
-    struct device_id *dev_id = arg;
-    err = pci_reregister_irq_for_device(PCI_CLASS_MASS_STORAGE, PCI_SUB_SATA,
-            PCI_DONT_CARE, dev_id->vendor, dev_id->device, PCI_DONT_CARE, PCI_DONT_CARE,
-            PCI_DONT_CARE, ahci_interrupt_handler, NULL,
-            ahci_reregister_handler, dev_id);
-    if (err_is_fail(err)) {
-        DEBUG_ERR(err, "pci_reregister_irq_for_device");
-    }
-
-    return;
-}
-
-static void polling_loop(void)
-{
-    errval_t err;
-    struct waitset *ws = get_default_waitset();
-    while (1) {
-#if defined(AHCI_SERVICE_DEBUG) || defined(GLOBAL_DEBUG)
-        if (controller.b != NULL) {
-            ahci_interrupt_handler(0);
-        }
-#endif
-        err = event_dispatch(ws);
-        if (err_is_fail(err)) {
-            DEBUG_ERR(err, "in event_dispatch");
-            break;
-        }
-    }
-}
-
-int main(int argc, char **argv)
-{
-    int r;
-
-    AHCID_DEBUG("starting\n");
-
-    //connect to the SKB
-    AHCID_DEBUG("connecting to the SKB...\n");
-    skb_client_connect();
-    AHCID_DEBUG("connected.\n");
-
-    r = pci_client_connect();
-    assert(err_is_ok(r));
-    AHCID_DEBUG("connected to pci\n");
-
-    if (argc >= 3) {
-        AHCID_DEBUG("got %s as vendor_id:device_id\n", argv[2]);
-        uint64_t vendor_id, device_id;
-        vendor_id = strtol(argv[2], NULL, 16);
-        device_id = strtol(argv[2]+5, NULL, 16);
-        struct device_id *dev_id = malloc(sizeof(*dev_id));
-        dev_id->vendor = vendor_id;
-        dev_id->device = device_id;
-        r = pci_register_driver_movable_irq(ahci_init, PCI_CLASS_MASS_STORAGE,
-                PCI_SUB_SATA, PCI_DONT_CARE, vendor_id,
-                device_id,
-                PCI_DONT_CARE, PCI_DONT_CARE, PCI_DONT_CARE,
-                ahci_interrupt_handler, NULL,
-                ahci_reregister_handler, dev_id);
-        if (err_is_fail(r)) {
-            printf("couldn't register device %04"PRIx64":%04"PRIx64": %s\n", vendor_id,
-                    device_id, err_getstring(r));
-            return 1;
-        }
-        printf("ahcid: registered device %04"PRIx64":%04"PRIx64"\n", vendor_id, device_id);
-    } else {
-        // fall-back: try some known AHCI devices
-        r = pci_register_driver_irq(ahci_init, PCI_CLASS_MASS_STORAGE,
-                PCI_SUB_SATA, PCI_DONT_CARE, PCI_VENDOR_INTEL,
-                PCI_DEVICE_ICH9R_82801IR /* QEMU ICH9R AHCI Controller */,
-                PCI_DONT_CARE, PCI_DONT_CARE, PCI_DONT_CARE,
-                ahci_interrupt_handler, NULL);
-        if (err_is_ok(r)) {
-            printf("ahcid: found QEMU ICH9R controller\n");
-            goto finish;
-        }
-        printf("ahcid: did not find QEMU ICH9R controller\n");
-
-        r = pci_register_driver_irq(ahci_init, PCI_CLASS_MASS_STORAGE,
-                PCI_SUB_SATA, PCI_DONT_CARE,
-                PCI_VENDOR_INTEL,
-                PCI_DEVICE_ICH10_82801JI /* 82801JI (ICH10 Family) AHCI Controller */,
-                PCI_DONT_CARE, PCI_DONT_CARE, PCI_DONT_CARE,
-                ahci_interrupt_handler, NULL);
-        if (err_is_ok(r)) {
-            printf("ahcid: found Sun Microsystems ICH10 Family controller\n");
-            goto finish;
-        }
-        printf("ahcid: did not find Sun Microsystems ICH10 Family controller\n");
-
-        r = pci_register_driver_irq(ahci_init, PCI_CLASS_MASS_STORAGE,
-                PCI_SUB_SATA, PCI_DONT_CARE,
-                PCI_VENDOR_ATI,
-                PCI_DEVICE_SB7x0 /* ATI SB7x0/SB8x0/SB9x0 SATA controller (IDE mode) */,
-                PCI_DONT_CARE, PCI_DONT_CARE, PCI_DONT_CARE,
-                ahci_interrupt_handler, NULL);
-        if (err_is_ok(r)) {
-            printf("ahcid: found ATI Technologies Inc. SB7x0/8x0/9x0 controller\n");
-            goto finish;
-        }
-        printf("ahcid: did not find ATI Technologies Inc. SB7x0/8x0/9x0 controller\n");
-        printf("ahcid: \ndid not find any supported AHCI controller\naborting...");
-        return 1;
-    }
-
-finish:
-    AHCID_DEBUG("registered driver: retval=%d\n", r);
-
-    polling_loop();
-}
diff --git a/usr/ahcid/ahcid.h b/usr/ahcid/ahcid.h
deleted file mode 100644 (file)
index 8a73c0c..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2011 ETH Zurich.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
- */
-
-#ifndef AHCID_H_
-#define AHCID_H_
-#include <barrelfish/barrelfish.h>
-#include <dev/ahci_port_dev.h>
-#include <ahci/ahci_dma_pool.h>
-
-enum ahcid_port_status {
-    AHCID_PORT_STATUS_UNINITIALIZED = 0,
-    AHCID_PORT_STATUS_IDLE = 1,
-    AHCID_PORT_STATUS_IDENTIFY_PENDING,
-};
-
-struct ahcid_port_info {
-    ahci_port_t port;
-    struct ahci_dma_region *command_list;
-    struct ahci_dma_region *receive_fis;
-    enum ahcid_port_status status;
-    // XXX: use data in ahci_port_t?
-    struct ahci_dma_region **prdts;
-    size_t prdt_count;
-    uint16_t identify_data[256];
-    struct ahci_mgmt_binding *binding;
-};
-
-uint32_t ahcid_port_offset(uint32_t port);
-errval_t ahcid_ports_init(struct ahcid_port_info **ports, size_t num_ports,
-               uint32_t active_ports_bf, void* base_address);
-
-#endif //AHCID_H_
diff --git a/usr/ahcid/ahcid_debug.h b/usr/ahcid/ahcid_debug.h
deleted file mode 100644 (file)
index 187c151..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2011 ETH Zurich.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
- */
-
-#ifndef AHCID_DEBUG_H_
-#define AHCID_DEBUG_H_
-
-
-/*****************************************************************
- * Debug printer:
- *****************************************************************/
-
-#if defined(AHCI_SERVICE_DEBUG) || defined(GLOBAL_DEBUG)
-#define AHCID_DEBUG(x...) printf("ahcid: " x)
-#else
-#define AHCID_DEBUG(x...) ((void)0)
-#endif
-
-#endif // AHCI_DEBUG_H_
diff --git a/usr/ahcid/ahcid_hwinit.c b/usr/ahcid/ahcid_hwinit.c
deleted file mode 100644 (file)
index 9976ee0..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2011 ETH Zurich.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
- */
-
-#include "ahcid.h"
-#include <ahci/ahci_dma_pool.h>
-#include <ahci/ahci_util.h>
-
-uint32_t ahcid_port_offset(uint32_t port)
-{
-    return 0x100 + port * 0x80;
-}
-
-errval_t ahcid_ports_init(struct ahcid_port_info **ports, size_t num_ports,
-        uint32_t active_ports_bf, void* base_address)
-{
-    errval_t r;
-    int i;
-    for (i = 0; i < num_ports; i++) {
-        if ((active_ports_bf >> i)&0x1) {
-            // only initialize implemented ports
-            ports[i] = calloc(1, sizeof(struct ahcid_port_info));
-            if (ports[i] == NULL) {
-                return LIB_ERR_MALLOC_FAIL;
-            }
-
-            ahci_port_initialize(&ports[i]->port, base_address + ahcid_port_offset(i));
-
-            // setup dma regions for command list and receive FIS area
-            r = ahci_port_alloc_dma_structs(&ports[i]->port,
-                           &ports[i]->command_list, &ports[i]->receive_fis);
-            assert(err_is_ok(r));
-
-            // enable rFIS area
-            ahci_port_cmd_t cmd = ahci_port_cmd_rd(&ports[i]->port);
-            cmd = ahci_port_cmd_fre_insert(cmd, 1);
-            ahci_port_cmd_wr(&ports[i]->port, cmd);
-        } else {
-            ports[i] = NULL;
-        }
-    }
-    return 0;
-}
-
diff --git a/usr/drivers/ahcid/Hakefile b/usr/drivers/ahcid/Hakefile
new file mode 100644 (file)
index 0000000..fe2070b
--- /dev/null
@@ -0,0 +1,29 @@
+--------------------------------------------------------------------------
+-- Copyright (c) 2007-2011, ETH Zurich.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Universitaetsstr. 6, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for /usr/drivers/ahci
+--
+--------------------------------------------------------------------------
+
+[
+    build application {
+        target = "ahcid",
+        mackerelDevices = [ "ata_identify", "ahci_port", "ahci_hba" ],
+        cFiles = [ "ahcid.c", "test.c" ],
+        addCFlags = ["-Wno-unused-variable", "-Wno-unused-function"],
+        addLibraries = [ "blk", "pci", "skb", "bench" ]
+    },
+
+    build application {
+        target = "ahci_test",
+        mackerelDevices = [ "ata_identify", "ahci_port", "ahci_hba" ],
+        cFiles = [ "ahcid.c", "test.c" ],
+        addCFlags = ["-DTESTING"],
+        addLibraries = [ "blk", "pci", "skb", "bench" ]
+    }
+]
diff --git a/usr/drivers/ahcid/ahcid.c b/usr/drivers/ahcid/ahcid.c
new file mode 100644 (file)
index 0000000..e698915
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include "ahcid.h"
+#include "test.h"
+
+void* dq = NULL;
+struct waitset disk_ws;
+
+static struct ahci_disk* ad;
+static volatile bool driver_initialized = false;
+static struct device_mem hbabar;
+static struct waitset_chanstate *chan = NULL;
+
+
+struct device_id {
+    uint16_t vendor;
+    uint16_t device;
+};
+
+static void ahci_interrupt_handler(void *arg)
+{
+    void devq_interrupt_handler(void*);
+    devq_interrupt_handler(dq);
+
+#ifdef DISABLE_INTERRUPTS
+    assert(chan != NULL);
+    assert(dq != NULL);
+    errval_t err = waitset_chan_register(&disk_ws, chan, MKCLOSURE(ahci_interrupt_handler, dq));
+    if (err_is_fail(err) && err_no(err) == LIB_ERR_CHAN_ALREADY_REGISTERED) {
+        printf("Got actual interrupt?\n");
+    }
+    else if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "Can't register our dummy channel.");
+    }
+    err = waitset_chan_trigger(chan);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "trigger failed.");
+    }
+#endif
+}
+
+static void do_ahci_init(struct device_mem* bar_info, int nr_allocated_bars)
+{
+    // Although the AHCI specification requires the AHCI memory region to be in
+    // BAR 5 (BAR 0 to 4 are used for legacy IDE mode) the QEMU AHCI emulation
+    // incorrectly uses BAR 0.  Because of this, ahcid consults both BAR 0 and
+    // BAR 5 to find the HBA's memory mapped I/O region.
+    // Since two BARs between 0-5 are I/O ports they are not passed to use by PCI.
+
+    if (nr_allocated_bars == 1) {
+        memcpy(&hbabar, &bar_info[0], sizeof(struct device_mem));
+    } else if (nr_allocated_bars == 3) {
+        memcpy(&hbabar, &bar_info[2], sizeof(struct device_mem));
+    } else {
+        printf("Strange device... not supported\n");
+        abort();
+    }
+
+    errval_t err = blk_ahci_init(&hbabar, &ad);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "AHCI HBA init failed.");
+    }
+
+    err = devq_create(ad, "", 0, &dq);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "devq create failed.");
+    }
+
+#if DISABLE_INTERRUPTS
+    waitset_init(&disk_ws);
+
+    // Hack: Why don't interrupts work?
+    chan = malloc(sizeof(struct waitset_chanstate));
+    waitset_chanstate_init(chan, CHANTYPE_AHCI);
+
+    err = waitset_chan_register(&disk_ws, chan, MKCLOSURE(ahci_interrupt_handler, dq));
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "waitset_chan_regster failed.");
+    }
+    err = waitset_chan_trigger(chan);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "trigger failed.");
+    }
+#endif
+
+    driver_initialized = true;
+}
+
+static void ahci_reregister_handler(void *arg)
+{
+    errval_t err;
+    struct device_id *dev_id = arg;
+    err = pci_reregister_irq_for_device(PCI_CLASS_MASS_STORAGE, PCI_SUB_SATA,
+            PCI_DONT_CARE, dev_id->vendor, dev_id->device, PCI_DONT_CARE, PCI_DONT_CARE,
+            PCI_DONT_CARE, ahci_interrupt_handler, NULL,
+            ahci_reregister_handler, dev_id);
+    if (err_is_fail(err)) {
+        DEBUG_ERR(err, "pci_reregister_irq_for_device");
+    }
+
+    return;
+}
+
+int main(int argc, char **argv)
+{
+    int r;
+    r = skb_client_connect();
+    assert(err_is_ok(r));
+    r = pci_client_connect();
+    assert(err_is_ok(r));
+
+    if (argc >= 3) {
+        printf("Got %s as vendor_id:device_id\n", argv[2]);
+        uint64_t vendor_id, device_id;
+        vendor_id = strtol(argv[2], NULL, 16);
+        device_id = strtol(argv[2]+5, NULL, 16);
+
+        struct device_id *dev_id = malloc(sizeof(*dev_id));
+        dev_id->vendor = vendor_id;
+        dev_id->device = device_id;
+
+        r = pci_register_driver_movable_irq(do_ahci_init, PCI_CLASS_MASS_STORAGE,
+                PCI_SUB_SATA, PCI_DONT_CARE, vendor_id, device_id,
+                PCI_DONT_CARE, PCI_DONT_CARE, PCI_DONT_CARE,
+                ahci_interrupt_handler, NULL,
+                ahci_reregister_handler, dev_id);
+        if (err_is_fail(r)) {
+            printf("Couldn't register device %04"PRIx64":%04"PRIx64": %s\n", vendor_id,
+                    device_id, err_getstring(r));
+            return 1;
+        }
+        printf("AHCID: registered device %04"PRIx64":%04"PRIx64"\n", vendor_id, device_id);
+    }
+    else {
+        printf("usage: ahcid <vendor id>:<device id>\n");
+        exit(1);
+    }
+    assert(driver_initialized);
+
+#ifdef TESTING
+    printf("Initialized driver, running tests:\n");
+    if (argc < 4) {
+        return 1;
+    }
+    if (strcmp(argv[3], "read|write") == 0) {
+        test_runner(2, AhciTest_READ, AhciTest_WRITE);
+    }
+    if (strcmp(argv[3], "read") == 0) {
+        test_runner(1, AhciTest_READ);
+    }
+    if (strcmp(argv[3], "write") == 0) {
+        test_runner(1, AhciTest_WRITE);
+    }
+    if (strcmp(argv[3], "verify") == 0) {
+        test_runner(1, AhciTest_VERIFY);
+    }
+#endif
+}
diff --git a/usr/drivers/ahcid/ahcid.h b/usr/drivers/ahcid/ahcid.h
new file mode 100644 (file)
index 0000000..041dfce
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef _AHCID_
+#define _AHCID_
+
+#include <stdio.h>
+#include <string.h>
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/waitset.h>
+#include <barrelfish/waitset_chan.h>
+#include <barrelfish/syscalls.h>
+#include <barrelfish/nameservice_client.h>
+#include <pci/pci.h>
+#include <skb/skb.h>
+#include <blk/ahci.h>
+#include <devif/queue.h>
+
+#define DISABLE_INTERRUPTS 1
+
+extern void* dq;
+extern struct waitset disk_ws;
+
+#endif // _AHCID_
diff --git a/usr/drivers/ahcid/test.c b/usr/drivers/ahcid/test.c
new file mode 100644 (file)
index 0000000..c540c09
--- /dev/null
@@ -0,0 +1,355 @@
+#include "ahcid.h"
+#include "test.h"
+
+#include <stdarg.h>
+#include <bench/bench.h>
+
+struct dma_mem {
+    lvaddr_t vaddr;         ///< virtual address of the mapped region
+    lpaddr_t paddr;         ///< physical address of the underlying frame
+    uint64_t bytes;         ///< size of the region in bytes
+    uint64_t requested;     ///< requested size of the region in bytes (<= bytes)
+    struct capref frame;    ///< frame capability backing this region
+};
+
+void test_runner(int n, ...)
+{
+    va_list arguments;
+    va_start(arguments, n);
+
+    for (size_t i=0; i<n; i++) {
+        enum AhciTest test = va_arg(arguments, enum AhciTest);
+        switch (test) {
+            case AhciTest_READ:
+                ahci_perf_sequential(1024*1024*1024, 512, false);
+                ahci_perf_sequential(1024*1024*1024, 1024, false);
+                ahci_perf_sequential(1024*1024*1024, 2048, false);
+                ahci_perf_sequential(1024*1024*1024, 4096, false);
+                ahci_perf_sequential(1024*1024*1024, 8192, false);
+                ahci_perf_sequential(1024*1024*1024, 16384, false);
+                ahci_perf_sequential(1024*1024*1024, 32768, false);
+                ahci_perf_sequential(1024*1024*1024, 65536, false);
+                ahci_perf_sequential(1024*1024*1024, 131072, false);
+                ahci_perf_sequential(1024*1024*1024, 262144, false);
+                ahci_perf_sequential(1024*1024*1024, 524288, false);
+                ahci_perf_sequential(1024*1024*1024, 1048576, false);
+                ahci_perf_sequential(1024*1024*1024, 1048576*2, false);
+                //ahci_perf_sequential(1024*1024*1024, 1048576*4, false); // ERROR: tilsiter1 OOM
+            break;
+
+            case AhciTest_WRITE:
+                ahci_perf_sequential(1024*1024*256, 512, true);
+                ahci_perf_sequential(1024*1024*256, 1024, true);
+                ahci_perf_sequential(1024*1024*256, 2048, true);
+                ahci_perf_sequential(1024*1024*256, 4096, true);
+                ahci_perf_sequential(1024*1024*256, 8192, true);
+                ahci_perf_sequential(1024*1024*256, 16384, true);
+                ahci_perf_sequential(1024*1024*256, 32768, true);
+                ahci_perf_sequential(1024*1024*256, 65536, true);
+                ahci_perf_sequential(1024*1024*256, 131072, true);
+                ahci_perf_sequential(1024*1024*256, 262144, true);
+                ahci_perf_sequential(1024*1024*256, 524288, true);
+                ahci_perf_sequential(1024*1024*256, 1048576, true);
+                ahci_perf_sequential(1024*1024*256, 1048576*2, true);
+                //ahci_perf_sequential(1024*1024*256, 1048576*4, true); // ERROR: tilsiter1 OOM
+            break;
+
+            case AhciTest_VERIFY:
+                ahci_verify_sequential(1024*1024*256, 512);
+                ahci_verify_sequential(1024*1024*256, 1024);
+                ahci_verify_sequential(1024*1024*256, 2048);
+                ahci_verify_sequential(1024*1024*256, 4096);
+                ahci_verify_sequential(1024*1024*256, 8192);
+                ahci_verify_sequential(1024*1024*256, 16384);
+                ahci_verify_sequential(1024*1024*256, 32768);
+                ahci_verify_sequential(1024*1024*256, 65536);
+                ahci_verify_sequential(1024*1024*256, 131072);
+                ahci_verify_sequential(1024*1024*256, 262144);
+                ahci_verify_sequential(1024*1024*256, 524288);
+                ahci_verify_sequential(1024*1024*256, 1048576);
+                ahci_verify_sequential(1024*1024*256, 1048576*2);
+                ahci_verify_sequential(1024*1024*256, 1048576*4);
+            break;
+
+            case AhciTest_BASIC:
+                ahci_simple_test();
+            break;
+
+            default:
+                USER_PANIC("Unknown test?");
+            break;
+        }
+    }
+
+    // Harness line
+    printf("AHCI testing completed.\n");
+}
+
+static void frame_alloc_identify(size_t size, struct capref *frame, struct frame_identity *id)
+{
+    errval_t err;
+    size_t retbytes;
+
+    err = frame_alloc(frame, size, &retbytes);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "frame_alloc");
+    }
+
+    err = invoke_frame_identify(*frame, id);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "invoke_frame_identify");
+    }
+}
+
+static void wait_for_interrupt(void)
+{
+    errval_t err = event_dispatch(&disk_ws);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "error in event_dispatch for wait_for_interrupt");
+    }
+}
+
+void ahci_simple_test(void)
+{
+    errval_t err;
+    regionid_t region_id = 0;
+    lpaddr_t base = 0;
+    size_t length = 0;
+    bufferid_t buffer_id = 0;
+
+    // Allocate a buffer:
+    struct dma_mem mem;
+    err = frame_alloc(&mem.frame, 4096, &mem.bytes);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "frame_alloc");
+    }
+    struct frame_identity id;
+    err = invoke_frame_identify(mem.frame, &id);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "invoke_frame_identify");
+    }
+
+    err = devq_register(dq, mem.frame, &region_id);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "devq register");
+    }
+
+    uint64_t flags = 0x0;
+    devq_enqueue(dq, region_id, id.base, 512, 0x123, flags);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "devq enqueue");
+    }
+
+    do {
+        err = devq_dequeue(dq, &region_id, &base, &length, &buffer_id);
+        if (err_is_ok(err)) {
+            break;
+        }
+        if (err_is_fail(err) && err_no(err) != DEV_ERR_QUEUE_EMPTY) {
+            USER_PANIC_ERR(err, "devq dequeue");
+        }
+        wait_for_interrupt();
+    } while (err_no(err) == DEV_ERR_QUEUE_EMPTY);
+
+    assert (buffer_id == 0x123);
+    assert (base == id.base);
+    assert (length == 512);
+
+    err = devq_remove(dq, region_id);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "devq_remove failed.");
+    }
+
+    printf("[%s]: DONE\n", __FUNCTION__);
+}
+
+static void blocking_dequeue(void* q, regionid_t* region_id, lpaddr_t* base, size_t* length, bufferid_t* buffer_id)
+{
+    errval_t err;
+    do {
+        err = devq_dequeue(q, region_id, base, length, buffer_id);
+        if (err_is_ok(err)) {
+            break;
+        }
+        if (err_is_fail(err) && err_no(err) != DEV_ERR_QUEUE_EMPTY) {
+            USER_PANIC_ERR(err, "devq dequeue");
+        }
+
+        assert(err_no(err) == DEV_ERR_QUEUE_EMPTY);
+        wait_for_interrupt();
+    } while (err_no(err) == DEV_ERR_QUEUE_EMPTY);
+}
+
+static void receive_block(void)
+{
+    regionid_t rid = 0;
+    lpaddr_t base = 0;
+    size_t len = 0;
+    bufferid_t bid = 0;
+    blocking_dequeue(dq, &rid, &base, &len, &bid);
+
+    bool* status = (bool*) bid;
+    assert (*status == false); // Only write region once
+    *status = true;
+}
+
+void ahci_perf_sequential(size_t buffer_size, size_t block_size, bool write)
+{
+    bench_init();
+    errval_t err;
+    assert(buffer_size % block_size == 0);
+
+    size_t read_requests = buffer_size / block_size;
+    regionid_t region_id = 0;
+
+    static struct capref frame;
+    struct frame_identity id;
+    frame_alloc_identify(buffer_size, &frame, &id);
+
+    err = devq_register(dq, frame, &region_id);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "devq register");
+    }
+
+    uint64_t write_flag = (write) ? (1ULL << 63) : 0;
+    volatile bool *received = calloc(1, sizeof(bool) * read_requests);
+    cycles_t t1 = bench_tsc();
+    for (size_t i=0; i < read_requests; i++) {
+        uint64_t disk_block = write_flag | i;
+        do {
+            err = devq_enqueue(dq, region_id, id.base + (i*block_size), block_size, (bufferid_t)&received[i], disk_block);
+            if (err_is_ok(err)) {
+                break;
+            }
+            else if (err_no(err) == DEV_ERR_QUEUE_FULL) {
+                receive_block();
+            }
+            else {
+                USER_PANIC_ERR(err, "Can't receive block.");
+            }
+        } while (true);
+    }
+    // Make sure we have all requests:
+    for (size_t i=0; i<read_requests; i++) {
+        while (!received[i]) {
+            receive_block();
+        }
+    }
+    cycles_t t2 = bench_tsc();
+    cycles_t result = (t2 - t1 - bench_tscoverhead());
+
+    double result_ms = (double)bench_tsc_to_ms(result);
+    double bw = buffer_size / result_ms / 1000; // 1e3 to sec, 10e6 to MB
+    char* cmd = write ? "Write" : "Read";
+    printf("[%s] %s sequential size %zu bs %zu: %.2f [MB/s]\n", __FUNCTION__, cmd, buffer_size, block_size, bw);
+
+    err = devq_remove(dq, region_id);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "devq_remove failed.");
+    }
+
+    cap_destroy(frame);
+}
+
+void ahci_verify_sequential(size_t buffer_size, size_t block_size)
+{
+    bench_init();
+    errval_t err;
+    assert(buffer_size % block_size == 0);
+
+    size_t requests = buffer_size / block_size;
+    regionid_t region_id = 0;
+
+    struct capref frame;
+    struct frame_identity id;
+    frame_alloc_identify(buffer_size, &frame, &id);
+    err = devq_register(dq, frame, &region_id);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "devq register");
+    }
+
+    struct capref fcopy;
+    err = slot_alloc(&fcopy);
+    assert(err_is_ok(err));
+    err = cap_copy(fcopy, frame);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "copy failed.");
+    }
+    void* retaddr;
+    err = vspace_map_one_frame(&retaddr, id.bytes, fcopy, NULL, NULL);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "map copy failed.");
+    }
+
+    uint8_t rbyte = (uint8_t) rdtsc();
+    if (rbyte == 0) rbyte++;
+    memset(retaddr, rbyte, buffer_size);
+
+    uint64_t write_flag = (1ULL << 63);
+    bool *received = calloc(1, sizeof(bool) * requests);
+    for (size_t i=0; i < requests; i++) {
+        uint64_t disk_block = write_flag | i;
+        do {
+            err = devq_enqueue(dq, region_id, id.base + (i*block_size), block_size, (bufferid_t)&received[i], disk_block);
+            if (err_is_ok(err)) {
+                break;
+            }
+            else if (err_no(err) == DEV_ERR_QUEUE_FULL) {
+                receive_block();
+            }
+            else {
+                USER_PANIC_ERR(err, "Can't receive block.");
+            }
+        } while (true);
+    }
+    // Make sure we have all requests:
+    for (size_t i=0; i<requests; i++) {
+        //printf("%s:%s:%d: i: %zu requests: %zu\n", __FILE__, __FUNCTION__, __LINE__, i, requests);
+        while (!received[i]) {
+            receive_block();
+        }
+    }
+
+    memset(retaddr, 0x00, id.bytes);
+    memset((void*)received, 0x0, sizeof(bool)*requests);
+
+    for (size_t i=0; i < requests; i++) {
+        //printf("%s:%s:%d: i: %zu requests: %zu\n", __FILE__, __FUNCTION__, __LINE__, i, requests);
+        uint64_t disk_block = i;
+        do {
+            err = devq_enqueue(dq, region_id, id.base + (i*block_size), block_size, (bufferid_t)&received[i], disk_block);
+            if (err_is_ok(err)) {
+                break;
+            }
+            else if (err_no(err) == DEV_ERR_QUEUE_FULL) {
+                receive_block();
+            }
+            else {
+                USER_PANIC_ERR(err, "Can't receive block.");
+            }
+        } while (true);
+    }
+    // Make sure we have all requests:
+    for (size_t i=0; i<requests; i++) {
+        while (!received[i]) {
+            //printf("%s:%s:%d: i: %zu requests: %zu\n", __FILE__, __FUNCTION__, __LINE__, i, requests);
+            receive_block();
+        }
+    }
+
+    for (size_t i=0; i < buffer_size; i++) {
+        uint8_t* carr = retaddr;
+        if (carr[i] != rbyte) {
+            printf("%s:%s:%d: carr[%zu]=%d != rbyte=%d\n", __FILE__, __FUNCTION__, __LINE__, i, carr[i], rbyte);
+        }
+        assert(carr[i] == rbyte);
+    }
+
+    printf("[%s] SUCCESS (%zu %zu)\n", __FUNCTION__, buffer_size, block_size);
+    cap_destroy(fcopy);
+
+    err = devq_remove(dq, region_id);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "devq_remove failed.");
+    }
+}
diff --git a/usr/drivers/ahcid/test.h b/usr/drivers/ahcid/test.h
new file mode 100644 (file)
index 0000000..582af74
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef AHCI_TEST
+#define AHCI_TEST
+
+#include <stdlib.h>
+#include <stdbool.h>
+
+enum AhciTest {
+    AhciTest_READ,
+    AhciTest_WRITE,
+    AhciTest_BASIC,
+    AhciTest_VERIFY,
+};
+
+void test_runner(int n, ...);
+
+void ahci_simple_test(void);
+void ahci_perf_sequential(size_t buffer_size, size_t block_size, bool write);
+void ahci_verify_sequential(size_t buffer_size, size_t block_size);
+
+
+#endif // AHCI_TEST
index 43e488f..3c3bac8 100644 (file)
@@ -162,6 +162,7 @@ static errval_t alloc_device_bar(uint8_t idx,
 
     struct device_caps *c = &dev_caps[bus][dev][fun][idx];
     errval_t err;
+    size = ROUND_UP(size, BASE_PAGE_SIZE); // Some BARs are less than 4 KiB
 
     // first try with maximally-sized caps (we'll reduce this if it doesn't work)
     uint8_t bits = log2ceil(size);
index c243d63..77a563d 100644 (file)
@@ -200,14 +200,20 @@ static void get_irq_cap_handler(struct pci_binding *b, uint16_t idx){
     // TODO: This should be part of the routing step
     int irq = pci_setup_interrupt(st->bus, st->dev, st->fun);
     PCI_DEBUG("pci: init_device_handler_irq: init interrupt.\n");
-    PCI_DEBUG("pci: irq = %u, core = %hhu, vector = %u\n", irq, coreid,
-                      vector);
 
     pci_enable_interrupt_for_device(st->bus, st->dev, st->fun, st->pcie);
 
+    PCI_DEBUG("pci: Interrupt enabled.\n");
 
     err = sys_debug_create_irq_src_cap(cap, irq);
-    b->tx_vtbl.get_irq_cap_response(b, NOP_CONT, err, cap);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "create irq src cap failed.");
+    }
+
+    err = b->tx_vtbl.get_irq_cap_response(b, NOP_CONT, err, cap);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "cap response failed.");
+    }
 }
 
 static void get_bar_cap_handler(struct pci_binding *b, uint32_t idx,