1#include <barrelfish/barrelfish.h>
2#include <assert.h>
3#include <devif/queue_interface.h>
4#include <devif/queue_interface_backend.h>
5#include <devif/backends/blk/ahci_devq.h>
6
7#include "blk_ahci.h"
8#include "ahci_dev.h" // TODO: get rid of this include
9#include "../dma_mem/dma_mem.h"
10#include "../blk_debug.h"
11
12struct ahci_queue {
13    struct devq q;
14    struct ahci_port* port;
15    struct dma_mem buffers[MAX_BUFFERS];
16    struct dev_queue_request requests[MAX_REQUESTS];
17};
18
19
20static bool is_valid_buffer(struct ahci_queue* dq, size_t slot)
21{
22    return !capref_is_null(dq->buffers[slot].frame);
23}
24
25static errval_t request_slot_alloc(struct ahci_queue* dq, size_t* slot)
26{
27    assert(dq->port->ncs <= MAX_REQUESTS);
28
29    for (size_t i=0; i < dq->port->ncs; i++) {
30        struct dev_queue_request *dqr = &dq->requests[i];
31        if (dqr->status == RequestStatus_Unused) {
32            dqr->status = RequestStatus_InProgress;
33            *slot = i;
34            return SYS_ERR_OK;
35        }
36    }
37
38    return DEVQ_ERR_QUEUE_FULL;
39}
40
41static errval_t get_port(struct ahci_disk* hba, size_t port_num, struct ahci_port** p) {
42    assert(hba != NULL);
43    assert(port_num < MAX_AHCI_PORTS);
44    errval_t err = SYS_ERR_OK;
45
46    struct ahci_port* port = &hba->ports[port_num];
47    if (!port->is_initialized) {
48        return err_push(err, DEVQ_ERR_INIT_QUEUE);
49    }
50
51    *p = port;
52    return SYS_ERR_OK;
53}
54
55static errval_t init_queue(struct ahci_queue** dq) {
56    struct ahci_queue* queue = calloc(1, sizeof(struct ahci_queue));
57    if (dq == NULL) {
58        return LIB_ERR_MALLOC_FAIL;
59    }
60
61    for (size_t i = 0; i< MAX_BUFFERS; i++) {
62        queue->buffers[i].frame = NULL_CAP;
63    }
64
65    *dq = queue;
66    return SYS_ERR_OK;
67}
68
69static bool slice_is_in_range(struct dma_mem *mem, genpaddr_t offset, size_t length)
70{
71    // do not have to check lower bound since it is unsigned
72    bool upper_bound = (mem->bytes >= length);
73    bool upper_bound2 = (mem->paddr + offset + length) <= (mem->paddr + mem->bytes);
74   // printf("mem->paddr %lx, mem->bytes %lx, offset %lx, length %lx \n",
75   //        mem->paddr, mem->bytes, offset, length);
76    return upper_bound2 && upper_bound;
77}
78
79static uint64_t flags_get_block(uint64_t flags)
80{
81    return flags & ((1ULL<<49) - 1);
82}
83
84static bool flags_is_write(uint64_t flags) {
85    return (flags & (1ULL << 63)) > 0;
86}
87
88void ahci_interrupt_handler(void* q)
89{
90    if (q == NULL) {
91        BLK_DEBUG("Ignored interrupt, device not yet initialized?\n");
92        return;
93    }
94    struct ahci_queue *queue = q;
95    struct ahci_port *port = queue->port;
96
97    assert(port->interrupt != NULL);
98    port->interrupt(port, queue->requests, port->ncs);
99}
100
101static errval_t ahci_destroy(struct devq *queue)
102{
103    // TODO: Wait for stuff to finish...!
104
105    struct ahci_queue *q = (struct ahci_queue*) queue;
106    // Clean-up memory:
107    for (size_t i = 0; i< MAX_BUFFERS; i++) {
108        dma_mem_free(&q->buffers[i]);
109    }
110    free(q);
111    return SYS_ERR_OK;
112}
113
114static errval_t ahci_enqueue(struct devq *q,
115                             regionid_t region_id,
116                             genoffset_t offset,
117                             genoffset_t length,
118                             genoffset_t valid_data,
119                             genoffset_t valid_length,
120                             uint64_t flags)
121{
122    struct ahci_queue *queue = (struct ahci_queue*) q;
123
124    assert(is_valid_buffer(queue, (region_id % MAX_BUFFERS)));
125    assert(length >= 512);
126
127    struct dma_mem* mem = &queue->buffers[(region_id % MAX_BUFFERS)];
128
129    if (!slice_is_in_range(mem, offset, length)) {
130        return DEVQ_ERR_INVALID_BUFFER_ARGS;
131    }
132
133    size_t slot = 0;
134
135    errval_t err = request_slot_alloc(queue, &slot);
136    if (err_is_fail(err)) {
137        return err;
138    }
139
140    struct dev_queue_request *dqr = &queue->requests[slot];
141    dqr->status = RequestStatus_InProgress;
142    dqr->region_id = region_id;
143    dqr->offset = offset;
144    dqr->length = length;
145    dqr->valid_data = valid_data;
146    dqr->valid_length = valid_length;
147    dqr->command_slot = slot;
148
149    uint64_t block = flags_get_block(flags);
150    bool write = flags_is_write(flags);
151
152    err = blk_ahci_port_dma_async(queue->port, slot, block, mem->paddr+offset,
153                                  length, write);
154    return err;
155}
156
157static errval_t ahci_dequeue(struct devq* q,
158                             regionid_t* region_id,
159                             genoffset_t* offset,
160                             genoffset_t* length,
161                             genoffset_t* valid_data,
162                             genoffset_t* valid_length,
163                             uint64_t* misc_flags)
164{
165    assert(q != NULL);
166    assert(region_id != NULL);
167    assert(offset != NULL);
168    assert(valid_data != NULL);
169    assert(valid_length != NULL);
170    assert(length != NULL);
171
172    struct ahci_queue *queue = (struct ahci_queue*) q;
173
174    for (size_t i=0; i < queue->port->ncs; i++) {
175        struct dev_queue_request *dqr = &queue->requests[i];
176        if (dqr->status == RequestStatus_Done) {
177            *region_id = dqr->region_id;
178            *offset = dqr->offset;
179            *length = dqr->length;
180            *valid_data = dqr->valid_data;
181            *valid_length = dqr->valid_length;
182            dqr->status = RequestStatus_Unused;
183            return dqr->error;
184        }
185    }
186
187    return DEVQ_ERR_QUEUE_EMPTY;
188}
189
190static errval_t ahci_register(struct devq *q,
191                              struct capref cap,
192                              regionid_t region_id)
193{
194
195    errval_t err = DEVQ_ERR_REGISTER_REGION;
196    assert(!capref_is_null(cap));
197    struct ahci_queue *queue = (struct ahci_queue*) q;
198
199    for (size_t i=0; i<MAX_BUFFERS; i++) {
200        uint16_t slot = ((region_id+i) % MAX_BUFFERS);
201
202        if (is_valid_buffer(queue, slot)) {
203            printf("Don't overwrite existing buffer\n");
204            continue;
205        }
206
207        queue->buffers[slot].frame = cap;
208
209        struct dma_mem* mem = &queue->buffers[slot];
210        err = dma_mem_from_capref(cap, mem);
211        if (err_is_fail(err)) {
212            DEBUG_ERR(err, "call failed");
213            return err_push(err, DEVQ_ERR_REGISTER_REGION);
214        }
215        return SYS_ERR_OK;
216    }
217
218    return err;
219}
220
221static errval_t ahci_deregister(struct devq *q, regionid_t region_id)
222{
223    assert(q != NULL);
224    struct ahci_queue *queue = (struct ahci_queue*) q;
225
226    struct dma_mem* mem = &queue->buffers[(region_id % MAX_BUFFERS)];
227    assert(!capref_is_null(mem->frame));
228
229    return dma_mem_free(mem);
230}
231
232static errval_t ahci_notify(struct devq *q)
233{
234    return SYS_ERR_OK;
235}
236
237static errval_t ahci_control(struct devq *q, uint64_t request, uint64_t value,
238                             uint64_t *result)
239{
240    return SYS_ERR_OK;
241}
242
243errval_t ahci_create(struct ahci_queue** q, void* st, uint64_t flags)
244{
245    errval_t err = SYS_ERR_OK;
246
247    struct ahci_port* port = NULL;
248    err = get_port(st, flags, &port);
249    if (err_is_fail(err)) {
250        return err;
251    }
252
253    struct ahci_queue *dq;
254    err = init_queue(&dq);
255    if (err_is_fail(err)) {
256        return err;
257    }
258
259    dq->port = port;
260
261    dq->q.f.enq = ahci_enqueue;
262    dq->q.f.deq = ahci_dequeue;
263    dq->q.f.reg = ahci_register;
264    dq->q.f.dereg = ahci_deregister;
265    dq->q.f.ctrl = ahci_control;
266    dq->q.f.notify = ahci_notify;
267    dq->q.f.destroy = ahci_destroy;
268
269    err = devq_init(&dq->q, false);
270    if (err_is_fail(err)) {
271        return err;
272    }
273
274    *q = dq;
275
276    return err;
277}
278