feat: asynchronized SATA IO
[lunaix-os.git] / lunaix-os / kernel / block / block.c
1 #include <hal/ahci/hba.h>
2 #include <klibc/stdio.h>
3 #include <klibc/string.h>
4 #include <lib/crc.h>
5 #include <lunaix/block.h>
6 #include <lunaix/fs/twifs.h>
7 #include <lunaix/mm/cake.h>
8 #include <lunaix/mm/valloc.h>
9 #include <lunaix/syslog.h>
10
11 #include <lunaix/spike.h>
12
13 #define BLOCK_EREAD 1
14 #define BLOCK_ESIG 2
15 #define BLOCK_ECRC 3
16 #define BLOCK_EFULL 3
17
18 LOG_MODULE("BLOCK")
19
20 #define MAX_DEV 32
21
22 static struct cake_pile* lbd_pile;
23 static struct block_dev** dev_registry;
24 static struct twifs_node* blk_sysroot;
25
26 int free_slot = 0;
27
28 int
29 __block_mount_partitions(struct hba_device* hd_dev);
30
31 int
32 __block_register(struct block_dev* dev);
33
34 void
35 block_init()
36 {
37     lbd_pile = cake_new_pile("block_dev", sizeof(struct block_dev), 1, 0);
38     dev_registry = vcalloc(sizeof(struct block_dev*), MAX_DEV);
39     free_slot = 0;
40     blk_sysroot = twifs_dir_node(NULL, "block");
41 }
42
43 int
44 __block_read(struct device* dev, void* buf, size_t offset, size_t len)
45 {
46     int errno;
47     struct block_dev* bdev = (struct block_dev*)dev->underlay;
48     size_t bsize = bdev->blk_size, rd_block = offset / bsize,
49            r = offset % bsize, rd_size = 0;
50
51     struct vecbuf* vbuf = vbuf_alloc(NULL, buf, len);
52     struct blkio_req* req;
53     void* tmp_buf = NULL;
54
55     if (r) {
56         tmp_buf = vzalloc(bsize);
57         rd_size = MIN(len, bsize - r);
58         vbuf->buf.size = rd_size;
59         vbuf->buf.buffer = tmp_buf;
60
61         vbuf_alloc(vbuf, buf + rd_size, len - rd_size);
62     }
63
64     req = blkio_vrd(vbuf, rd_block, NULL, NULL, 0);
65     blkio_commit(bdev->blkio, req);
66     wait_if(req->flags & BLKIO_PENDING);
67
68     if (!(errno = req->errcode)) {
69         memcpy(buf, tmp_buf + r, rd_size);
70     }
71
72     if (tmp_buf) {
73         vfree(tmp_buf);
74     }
75
76     blkio_free_req(req);
77     vbuf_free(vbuf);
78     return errno;
79 }
80
81 int
82 __block_write(struct device* dev, void* buf, size_t offset, size_t len)
83 {
84     struct block_dev* bdev = (struct block_dev*)dev->underlay;
85     size_t bsize = bdev->blk_size, rd_block = offset / bsize,
86            r = offset % bsize;
87
88     struct vecbuf* vbuf = vbuf_alloc(NULL, buf, len);
89     struct blkio_req* req;
90     void* tmp_buf = NULL;
91
92     if (r) {
93         size_t rd_size = MIN(len, bsize - r);
94         tmp_buf = vzalloc(bsize);
95         vbuf->buf.size = bsize;
96         vbuf->buf.buffer = tmp_buf;
97
98         memcpy(tmp_buf + r, buf, rd_size);
99         vbuf_alloc(vbuf, buf + rd_size, len - rd_size);
100     }
101
102     req = blkio_vwr(vbuf, rd_block, NULL, NULL, 0);
103     blkio_commit(bdev->blkio, req);
104     wait_if(req->flags & BLKIO_PENDING);
105
106     int errno = req->errcode;
107
108     if (tmp_buf) {
109         vfree(tmp_buf);
110     }
111
112     blkio_free_req(req);
113     vbuf_free(vbuf);
114     return errno;
115 }
116
117 struct block_dev*
118 block_alloc_dev(const char* blk_id, void* driver, req_handler ioreq_handler)
119 {
120     struct block_dev* bdev = cake_grab(lbd_pile);
121     *bdev = (struct block_dev){ .driver = driver };
122
123     strncpy(bdev->name, blk_id, PARTITION_NAME_SIZE);
124
125     bdev->blkio = blkio_newctx(ioreq_handler);
126
127     return bdev;
128 }
129
130 int
131 block_mount(struct block_dev* bdev, devfs_exporter fs_export)
132 {
133     int errno = 0;
134
135     if (!__block_register(bdev)) {
136         errno = BLOCK_EFULL;
137         goto error;
138     }
139
140     struct twifs_node* dev_root = twifs_dir_node(blk_sysroot, bdev->bdev_id);
141     blk_set_blkmapping(bdev, dev_root);
142     fs_export(bdev, dev_root);
143
144     return errno;
145
146 error:
147     kprintf(KERROR "Fail to mount block device: %s (%x)\n", bdev->name, -errno);
148     return errno;
149 }
150
151 int
152 __block_register(struct block_dev* bdev)
153 {
154     if (free_slot >= MAX_DEV) {
155         return 0;
156     }
157
158     struct device* dev = device_addvol(NULL, bdev, "sd%c", 'a' + free_slot);
159     dev->write = __block_write;
160     dev->read = __block_read;
161
162     bdev->dev = dev;
163     strcpy(bdev->bdev_id, dev->name_val);
164     dev_registry[free_slot++] = bdev;
165     return 1;
166 }