Adding some initializations
[barrelfish] / lib / blk / blk_ahci / device_impl.c
1 #include <barrelfish/barrelfish.h>
2 #include <assert.h>
3 #include <devif/queue.h>
4
5 #include "blk_ahci.h"
6 #include "ahci_dev.h" // TODO: get rid of this include
7 #include "../dma_mem/dma_mem.h"
8 #include "../blk_debug.h"
9
10 static bool is_valid_buffer(struct dev_queue* dq, size_t slot)
11 {
12     return !capref_is_null(dq->buffers[slot].frame);
13 }
14
15 static errval_t request_slot_alloc(struct dev_queue* dq, size_t* slot)
16 {
17     assert(dq->port->ncs <= MAX_REQUESTS);
18
19     for (size_t i=0; i < dq->port->ncs; i++) {
20         struct dev_queue_request *dqr = &dq->requests[i];
21         if (dqr->status == RequestStatus_Unused) {
22             dqr->status = RequestStatus_InProgress;
23             *slot = i;
24             return SYS_ERR_OK;
25         }
26     }
27
28     return DEV_ERR_QUEUE_FULL;
29 }
30
31 static errval_t get_port(struct ahci_disk* hba, size_t port_num, struct ahci_port** p) {
32     assert(hba != NULL);
33     assert(port_num < MAX_AHCI_PORTS);
34     errval_t err = SYS_ERR_OK;
35
36     struct ahci_port* port = &hba->ports[port_num];
37     if (!port->is_initialized) {
38         return err_push(err, DEV_ERR_NOT_INITIALIZED);
39     }
40
41     *p = port;
42     return SYS_ERR_OK;
43 }
44
45 static errval_t init_queue(struct dev_queue** dq, struct ahci_port *port) {
46     struct dev_queue* queue = calloc(1, sizeof(struct dev_queue));
47     if (dq == NULL) {
48         return LIB_ERR_MALLOC_FAIL;
49     }
50
51     queue->port = port;
52     for (size_t i = 0; i< MAX_BUFFERS; i++) {
53         queue->buffers[i].frame = NULL_CAP;
54     }
55
56     *dq = queue;
57     return SYS_ERR_OK;
58 }
59
60 static bool slice_is_in_range(struct dma_mem *mem, lpaddr_t base, size_t length)
61 {
62     bool lower_bound = mem->paddr <= base;
63     bool upper_bound = mem->paddr+mem->bytes >= base+length;
64
65     return lower_bound && upper_bound;
66 }
67
68 static uint64_t flags_get_block(uint64_t flags)
69 {
70     return flags & ((1ULL<<49) - 1);
71 }
72
73 static bool flags_is_write(uint64_t flags) {
74     return (flags & (1ULL << 63)) > 0;
75 }
76
77 void devq_interrupt_handler(void* q);
78 void devq_interrupt_handler(void* q)
79 {
80     if (q == NULL) {
81         BLK_DEBUG("Ignored interrupt, device not yet initialized?\n");
82         return;
83     }
84     struct dev_queue *queue = q;
85     struct ahci_port *port = queue->port;
86
87     assert(port->interrupt != NULL);
88     port->interrupt(port, queue);
89 }
90
91 errval_t devq_create(void* st, char *device_name, uint64_t flags, void **queue)
92 {
93     errval_t err = SYS_ERR_OK;
94
95     struct ahci_port* port = NULL;
96     err = get_port(st, flags, &port);
97     if (err_is_fail(err)) {
98         return err;
99     }
100
101     struct dev_queue *dq;
102     err = init_queue(&dq, port);
103     if (err_is_fail(err)) {
104         return err;
105     }
106
107     *queue = dq;
108
109     return err;
110 }
111
112 errval_t devq_destroy(void *qp)
113 {
114     struct dev_queue *queue = qp;
115
116     // TODO: Wait for stuff to finish...!
117
118     // Clean-up memory:
119     for (size_t i = 0; i< MAX_BUFFERS; i++) {
120         dma_mem_free(&queue->buffers[i]);
121     }
122     free(qp);
123     return SYS_ERR_OK;
124 }
125
126 errval_t devq_enqueue(void *q, regionid_t region_id, lpaddr_t base, size_t length, bufferid_t buffer_id, uint64_t flags)
127 {
128     struct dev_queue *queue = q;
129     assert(region_id < MAX_BUFFERS);
130     assert(is_valid_buffer(queue, region_id));
131     assert(base != 0);
132     assert(length >= 512);
133
134     struct dma_mem* mem = &queue->buffers[region_id];
135
136     if (!slice_is_in_range(mem, base, length)) {
137         return DEV_ERR_INVALID_BUFFER_ARGS;
138     }
139
140     size_t slot = 0;
141     errval_t err = request_slot_alloc(queue, &slot);
142     if (err_is_fail(err)) {
143         return err;
144     }
145
146     struct dev_queue_request *dqr = &queue->requests[slot];
147     dqr->status = RequestStatus_InProgress;
148     dqr->buffer_id = buffer_id;
149     dqr->base = base;
150     dqr->length = length;
151     dqr->region_id = region_id;
152     dqr->command_slot = slot;
153
154     uint64_t block = flags_get_block(flags);
155     bool write = flags_is_write(flags);
156     return blk_ahci_port_dma_async(queue->port, slot, block, base, length, write);
157 }
158
159 errval_t devq_dequeue(void *q,
160                       regionid_t* region_id,
161                       lpaddr_t* base,
162                       size_t* length,
163                       bufferid_t* buffer_id)
164 {
165     assert(q != NULL);
166     assert(region_id != NULL);
167     assert(base != NULL);
168     assert(length != NULL);
169     assert(length != NULL);
170
171     struct dev_queue *queue = q;
172
173     for (size_t i=0; i<queue->port->ncs; i++) {
174         struct dev_queue_request *dqr = &queue->requests[i];
175         if (dqr->status == RequestStatus_Done) {
176             *base = dqr->base;
177             *length = dqr->length;
178             *buffer_id = dqr->buffer_id;
179             *region_id = dqr->region_id;
180
181             dqr->status = RequestStatus_Unused;
182             return dqr->error;
183         }
184     }
185
186     return DEV_ERR_QUEUE_EMPTY;
187 }
188
189 errval_t devq_register(void *q,
190                        struct capref cap,
191                        regionid_t* region_id)
192 {
193     errval_t err = DEV_ERR_REGISTER_BUFFER;
194     assert(!capref_is_null(cap));
195     struct dev_queue *queue = q;
196
197     for (size_t i=0; i<MAX_BUFFERS; i++) {
198         if (is_valid_buffer(q, i)) {
199             printf("Don't overwrite existing buffer\n");
200             continue;
201         }
202
203         struct dma_mem* mem = &queue->buffers[i];
204         err = dma_mem_from_capref(cap, mem);
205         if (err_is_fail(err)) {
206             DEBUG_ERR(err, "call failed");
207             return err_push(err, DEV_ERR_REGISTER_BUFFER);
208         }
209
210         *region_id = i;
211         return SYS_ERR_OK;
212     }
213
214     return err;
215 }
216
217 errval_t devq_remove(void *q, regionid_t region_id)
218 {
219     assert(region_id < MAX_BUFFERS);
220     assert(q != NULL);
221     struct dev_queue *queue = q;
222
223     struct dma_mem* mem = &queue->buffers[region_id];
224     assert(!capref_is_null(mem->frame));
225
226     return dma_mem_free(mem);
227 }
228
229 errval_t devq_sync(void *q)
230 {
231     return SYS_ERR_OK;
232 }
233
234 errval_t devq_control(void *q, uint64_t request, uint64_t value)
235 {
236     return SYS_ERR_OK;
237 }