1/*
2 * Copyright (c) 2014, University of Washington.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <barrelfish/barrelfish.h>
11#include <barrelfish/waitset.h>
12#include <if/ata_rw28_defs.h>
13#include <if/ata_rw28_ahci_defs.h>
14#include <if/ata_rw28_defs.h>
15#include <storage/vsic.h>
16
17struct ahci_vsic {
18    struct ahci_ata_rw28_binding ahci_ata_rw28_binding;
19    struct ata_rw28_binding ata_rw28_rpc;
20    struct ata_rw28_binding *ata_rw28_binding;
21    struct ahci_binding *ahci_binding;
22    errval_t bind_err;
23};
24
25static errval_t vsic_write(struct storage_vsic *vsic, struct storage_vsa *vsa,
26                           off_t offset, size_t size, void *buffer)
27{
28    assert(vsic != NULL);
29    assert(vsa != NULL);
30    assert(buffer != NULL);
31    struct ahci_vsic *mydata = vsic->data;
32    errval_t status;
33
34    errval_t err = mydata->ata_rw28_rpc->rpc_tx_vtbl.
35      write_dma(&mydata->ata_rw28_rpc, buffer, STORAGE_VSIC_ROUND(vsic, size),
36		offset, &status);
37    if (err_is_fail(err)) {
38        USER_PANIC_ERR(err, "write_dma rpc");
39    }
40    if (err_is_fail(status)) {
41        USER_PANIC_ERR(status, "write_dma status");
42    }
43
44    return SYS_ERR_OK;
45}
46
47static errval_t vsic_read(struct storage_vsic *vsic, struct storage_vsa *vsa,
48                          off_t offset, size_t size, void *buffer)
49{
50    assert(vsic != NULL);
51    assert(vsa != NULL);
52    assert(buffer != NULL);
53    struct ahci_vsic *mydata = vsic->data;
54    uint8_t *buf = NULL;
55    size_t bytes_read, toread = STORAGE_VSIC_ROUND(vsic, size);
56
57    errval_t err = mydata->ata_rw28_rpc->rpc_tx_vtbl.
58      read_dma(&mydata->ata_rw28_rpc, toread, offset, &buf, &bytes_read);
59    if (err_is_fail(err))
60        USER_PANIC_ERR(err, "read_dma rpc");
61    if (!buf)
62        USER_PANIC("read_dma -> !buf");
63    if (bytes_read != toread)
64        USER_PANIC("read_dma -> read_size != size");
65
66    // XXX: Copy from DMA buffer to user buffer
67    memcpy(buffer, buf, size);
68    free(buf);
69
70    return SYS_ERR_OK;
71}
72
73static errval_t vsic_flush(struct storage_vsic *vsic, struct storage_vsa *vsa)
74{
75  assert(vsic != NULL);
76  assert(vsa != NULL);
77  struct ahci_vsic *mydata = vsic->data;
78  errval_t outerr;
79
80  errval_t err = mydata->ata_rw28_rpc->rpc_tx_vtbl.
81    flush_cache(&mydata->ata_rw28_rpc, &outerr);
82  assert(err_is_ok(err));
83
84  return outerr;
85}
86
87static errval_t vsic_wait(struct storage_vsic *vsic)
88{
89  // XXX: Interface currently synchronous
90  return SYS_ERR_OK;
91}
92
93static struct storage_vsic_ops ahci_vsic_ops = {
94    .write = vsic_write,
95    .read = vsic_read,
96    .flush = vsic_flush,
97    .wait = vsic_wait,
98};
99
100static void ahci_bind_cb(void *st, errval_t err, struct ahci_binding *_binding)
101{
102    assert(err_is_ok(err));
103    struct ahci_vsic *mydata = st;
104    mydata->ahci_binding = _binding;
105}
106
107// XXX: This could be made public and controlled by the programmer instead of
108// the commandline
109static errval_t ahci_vsic_alloc(struct storage_vsic *vsic, uint8_t port)
110{
111    assert(vsic != NULL);
112    errval_t err;
113    struct ahci_vsic *mydata = malloc(sizeof(struct ahci_vsic));
114    assert(mydata != NULL);
115    memset(mydata, 0, sizeof(struct ahci_vsic));
116
117    // init ahci management binding
118    err = ahci_init(port, ahci_bind_cb, mydata, get_default_waitset());
119    assert(err_is_ok(err));
120
121    while(!mydata->ahci_binding) {
122        event_dispatch(get_default_waitset());
123    }
124
125    // init ata flounder binding
126    err = ahci_ata_rw28_init(&mydata->ahci_ata_rw28_binding,
127                             get_default_waitset(), mydata->ahci_binding);
128    if (err_is_fail(err)) {
129        USER_PANIC_ERR(err, "ahci_ata_rw28_init");
130    }
131    mydata->ata_rw28_binding =
132        (struct ata_rw28_binding*)&mydata->ahci_ata_rw28_binding;
133
134    // init RPC client
135    err = ata_rw28_binding_init(&mydata->ata_rw28_rpc,
136                                   mydata->ata_rw28_binding);
137    if (err_is_fail(err)) {
138        USER_PANIC_ERR(err, "ata_rw28_binding_init");
139    }
140
141    // Init VSIC data structure
142    vsic->ops = ahci_vsic_ops;
143    vsic->data = mydata;
144    vsic->blocksize = 512;	// XXX: Determine from drive?
145
146    return SYS_ERR_OK;
147}
148
149errval_t storage_vsic_driver_init(int argc, const char **argv,
150				  struct storage_vsic *vsic)
151{
152    // init dma pool
153    ahci_dma_pool_init(1024*1024);
154
155    // Allocate port 0
156    return ahci_vsic_alloc(vsic, 0);
157}
158