feat: asynchronized SATA IO
[lunaix-os.git] / lunaix-os / kernel / block / blkio.c
1 #include <lunaix/blkio.h>
2 #include <lunaix/mm/cake.h>
3 #include <lunaix/mm/valloc.h>
4
5 static struct cake_pile* blkio_reqpile;
6
7 void
8 blkio_init()
9 {
10     blkio_reqpile = cake_new_pile("blkio_req", sizeof(struct blkio_req), 1, 0);
11 }
12
13 static inline struct blkio_req*
14 __blkio_req_create(struct vecbuf* buffer,
15                    u64_t start_lba,
16                    blkio_cb completed,
17                    void* evt_args,
18                    u32_t options)
19 {
20     options = options & ~0xf;
21     struct blkio_req* breq = (struct blkio_req*)cake_grab(blkio_reqpile);
22     *breq = (struct blkio_req){ .blk_addr = start_lba,
23                                 .completed = completed,
24                                 .flags = options,
25                                 .evt_args = evt_args };
26     breq->vbuf = buffer;
27     return breq;
28 }
29
30 struct blkio_req*
31 blkio_vrd(struct vecbuf* buffer,
32           u64_t start_lba,
33           blkio_cb completed,
34           void* evt_args,
35           u32_t options)
36 {
37     return __blkio_req_create(buffer, start_lba, completed, evt_args, options);
38 }
39
40 struct blkio_req*
41 blkio_vwr(struct vecbuf* buffer,
42           u64_t start_lba,
43           blkio_cb completed,
44           void* evt_args,
45           u32_t options)
46 {
47     struct blkio_req* breq =
48       __blkio_req_create(buffer, start_lba, completed, evt_args, options);
49     breq->flags |= BLKIO_WRITE;
50     return breq;
51 }
52
53 void
54 blkio_free_req(struct blkio_req* req)
55 {
56     cake_release(blkio_reqpile, (void*)req);
57 }
58
59 struct blkio_context*
60 blkio_newctx(req_handler handler)
61 {
62     struct blkio_context* ctx =
63       (struct blkio_context*)vzalloc(sizeof(struct blkio_context));
64     ctx->handle_one = handler;
65
66     llist_init_head(&ctx->queue);
67
68     return ctx;
69 }
70
71 void
72 blkio_commit(struct blkio_context* ctx, struct blkio_req* req)
73 {
74     req->flags |= BLKIO_PENDING;
75     req->io_ctx = ctx;
76     llist_append(&ctx->queue, &req->reqs);
77
78     // if the pipeline is not running (e.g., stalling). Then we should schedule
79     // one immediately and kick it start.
80     if (!ctx->busy) {
81         blkio_schedule(ctx);
82     }
83 }
84
85 void
86 blkio_schedule(struct blkio_context* ctx)
87 {
88     if (llist_empty(&ctx->queue)) {
89         return;
90     }
91
92     struct blkio_req* head = (struct blkio_req*)ctx->queue.next;
93     llist_delete(&head->reqs);
94
95     head->flags |= BLKIO_BUSY;
96     head->io_ctx->busy++;
97
98     ctx->handle_one(head);
99 }
100
101 void
102 blkio_complete(struct blkio_req* req)
103 {
104     req->flags &= ~(BLKIO_BUSY | BLKIO_PENDING);
105     if (req->completed) {
106         req->completed(req);
107     }
108     if ((req->flags & BLKIO_FOC)) {
109         blkio_free_req(req);
110     }
111
112     req->io_ctx->busy--;
113
114     blkio_schedule(req->io_ctx);
115 }