fix dependency check logic cause config always disabled
[lunaix-os.git] / lunaix-os / kernel / block / block.c
1 #include <klibc/strfmt.h>
2 #include <klibc/string.h>
3
4 #include <hal/ahci/hba.h>
5
6 #include <klibc/crc.h>
7
8 #include <lunaix/blkpart_gpt.h>
9 #include <lunaix/block.h>
10 #include <lunaix/fs/twifs.h>
11 #include <lunaix/mm/cake.h>
12 #include <lunaix/mm/pagetable.h>
13 #include <lunaix/mm/valloc.h>
14 #include <lunaix/spike.h>
15 #include <lunaix/syslog.h>
16
17 #define BLOCK_EREAD 1
18 #define BLOCK_ESIG 2
19 #define BLOCK_ECRC 3
20 #define BLOCK_EFULL 3
21
22 LOG_MODULE("BLOCK")
23
24 #define MAX_DEV 32
25
26 static struct cake_pile* lbd_pile;
27 static struct block_dev** dev_registry;
28 static struct twifs_node* blk_sysroot;
29 static struct device_cat* blk_parent_dev;
30
31 int free_slot = 0;
32
33 int
34 __block_mount_partitions(struct hba_device* hd_dev);
35
36 int
37 __block_register(struct block_dev* dev);
38
39 void
40 block_init()
41 {
42     blkio_init();
43     lbd_pile = cake_new_pile("block_dev", sizeof(struct block_dev), 1, 0);
44     dev_registry = vcalloc(sizeof(struct block_dev*), MAX_DEV);
45     free_slot = 0;
46     blk_sysroot = twifs_dir_node(NULL, "block");
47     blk_parent_dev = device_addcat(NULL, "block");
48 }
49
50 static int
51 __block_commit(struct blkio_context* blkio, struct blkio_req* req, int flags)
52 {
53     int errno;
54     
55     blkio_bindctx(req, blkio);
56     blkio_mark_nfoc(req);
57     blkio_commit(req, flags);
58
59     if ((errno = req->errcode)) {
60         errno = -errno;
61     }
62
63     vbuf_free(req->vbuf);
64     blkio_free_req(req);
65     return errno;
66 }
67
68 int
69 __block_read(struct device* dev, void* buf, size_t offset, size_t len)
70 {
71     int errno;
72     struct block_dev* bdev = block_dev(dev);
73     size_t bsize = bdev->blk_size, 
74            rd_block = offset / bsize + bdev->start_lba,
75            r = offset % bsize, rd_size = 0;
76
77     if (!(len = MIN(len, ((size_t)bdev->end_lba - rd_block + 1) * bsize))) {
78         return 0;
79     }
80
81     struct vecbuf* vbuf = NULL;
82     struct blkio_req* req;
83     void *head_buf = NULL, *tail_buf = NULL;
84
85     // align the boundary
86     if (r || len < bsize) {
87         head_buf = valloc(bsize);
88         rd_size = MIN(len, bsize - r);
89         vbuf_alloc(&vbuf, head_buf, bsize);
90     }
91
92     // align the length
93     if ((len - rd_size)) {
94         size_t llen = len - rd_size;
95         assert_msg(!(llen % bsize), "misalign block read");
96         vbuf_alloc(&vbuf, buf + rd_size, llen);
97     }
98
99     req = blkio_vrd(vbuf, rd_block, NULL, NULL, 0);
100
101     if (!(errno = __block_commit(bdev->blkio, req, BLKIO_WAIT))) {
102         memcpy(buf, head_buf + r, rd_size);
103         errno = len;
104     }
105
106     if (head_buf) {
107         vfree(head_buf);
108     }
109
110     return errno;
111 }
112
113 int
114 __block_write(struct device* dev, void* buf, size_t offset, size_t len)
115 {
116     struct block_dev* bdev = block_dev(dev);
117     size_t bsize = bdev->blk_size, wr_block = offset / bsize + bdev->start_lba,
118            r = offset % bsize, wr_size = 0;
119
120     if (!(len = MIN(len, ((size_t)bdev->end_lba - wr_block + 1) * bsize))) {
121         return 0;
122     }
123
124     struct vecbuf* vbuf = NULL;
125     struct blkio_req* req;
126     void* tmp_buf = NULL;
127
128     if (r) {
129         size_t wr_size = MIN(len, bsize - r);
130         tmp_buf = vzalloc(bsize);
131         vbuf_alloc(&vbuf, tmp_buf, bsize);
132
133         memcpy(tmp_buf + r, buf, wr_size);
134     }
135
136     if ((len - wr_size)) {
137         size_t llen = len - wr_size;
138         assert_msg(!(llen % bsize), "misalign block write");
139         vbuf_alloc(&vbuf, buf + wr_size, llen);
140     }
141
142     req = blkio_vwr(vbuf, wr_block, NULL, NULL, 0);
143
144     int errno;
145     if (!(errno = __block_commit(bdev->blkio, req, BLKIO_WAIT))) {
146         errno = len;
147     }
148
149     if (tmp_buf) {
150         vfree(tmp_buf);
151     }
152
153     return errno;
154 }
155
156 int
157 __block_read_page(struct device* dev, void* buf, size_t offset)
158 {
159     struct vecbuf* vbuf = NULL;
160     struct block_dev* bdev = block_dev(dev);
161
162     u32_t lba = offset / bdev->blk_size + bdev->start_lba;
163     u32_t rd_lba = MIN(lba + PAGE_SIZE / bdev->blk_size, bdev->end_lba);
164
165     if (rd_lba <= lba) {
166         return 0;
167     }
168
169     rd_lba -= lba;
170
171     vbuf_alloc(&vbuf, buf, rd_lba * bdev->blk_size);
172
173     struct blkio_req* req = blkio_vrd(vbuf, lba, NULL, NULL, 0);
174
175     int errno;
176     if (!(errno = __block_commit(bdev->blkio, req, BLKIO_WAIT))) {
177         errno = rd_lba * bdev->blk_size;
178     }
179
180     return errno;
181 }
182
183 int
184 __block_write_page(struct device* dev, void* buf, size_t offset)
185 {
186     struct vecbuf* vbuf = NULL;
187     struct block_dev* bdev = block_dev(dev);
188
189     u32_t lba = offset / bdev->blk_size + bdev->start_lba;
190     u32_t wr_lba = MIN(lba + PAGE_SIZE / bdev->blk_size, bdev->end_lba);
191
192     if (wr_lba <= lba) {
193         return 0;
194     }
195
196     wr_lba -= lba;
197
198     vbuf_alloc(&vbuf, buf, wr_lba * bdev->blk_size);
199
200     struct blkio_req* req = blkio_vwr(vbuf, lba, NULL, NULL, 0);
201
202     int errno;
203     if (!(errno = __block_commit(bdev->blkio, req, BLKIO_WAIT))) {
204         errno = wr_lba * bdev->blk_size;
205     }
206
207     return errno;
208 }
209
210 int
211 __block_rd_lb(struct block_dev* bdev, void* buf, u64_t start, size_t count)
212 {
213     struct vecbuf* vbuf = NULL;
214     vbuf_alloc(&vbuf, buf, bdev->blk_size * count);
215
216     struct blkio_req* req = blkio_vrd(vbuf, start, NULL, NULL, 0);
217
218     int errno;
219     if (!(errno = __block_commit(bdev->blkio, req, BLKIO_WAIT))) {
220         errno = count;
221     }
222
223     return errno;
224 }
225
226 int
227 __block_wr_lb(struct block_dev* bdev, void* buf, u64_t start, size_t count)
228 {
229     struct vecbuf* vbuf = NULL;
230     vbuf_alloc(&vbuf, buf, bdev->blk_size * count);
231
232     struct blkio_req* req = blkio_vwr(vbuf, start, NULL, NULL, 0);
233
234     int errno;
235     if (!(errno = __block_commit(bdev->blkio, req, BLKIO_WAIT))) {
236         errno = count;
237     }
238
239     return errno;
240 }
241
242 void*
243 block_alloc_buf(struct block_dev* bdev)
244 {
245     return valloc(bdev->blk_size);
246 }
247
248 void
249 block_free_buf(struct block_dev* bdev, void* buf)
250 {
251     return vfree(buf);
252 }
253
254 struct block_dev*
255 block_alloc_dev(const char* blk_id, void* driver, req_handler ioreq_handler)
256 {
257     struct block_dev* bdev = cake_grab(lbd_pile);
258     memset(bdev, 0, sizeof(struct block_dev));
259     llist_init_head(&bdev->parts);
260     strncpy(bdev->name, blk_id, PARTITION_NAME_SIZE);
261
262     bdev->blkio = blkio_newctx(ioreq_handler);
263     bdev->driver = driver;
264     bdev->blkio->driver = driver;
265     bdev->ops = (struct block_dev_ops){ .block_read = __block_rd_lb,
266                                         .block_write = __block_wr_lb };
267
268     return bdev;
269 }
270
271 int
272 block_mount(struct block_dev* bdev, devfs_exporter fs_export)
273 {
274     int errno = 0;
275
276     if (!__block_register(bdev)) {
277         errno = BLOCK_EFULL;
278         goto error;
279     }
280
281     errno = blkpart_probegpt(bdev->dev);
282     if (errno < 0) {
283         ERROR("Fail to parse partition table (%d)", errno);
284     } else if (!errno) {
285         // TODO try other PT parser...
286     }
287
288     struct twifs_node* dev_root = twifs_dir_node(blk_sysroot, bdev->bdev_id);
289     blk_set_blkmapping(bdev, dev_root);
290     fs_export(bdev, dev_root);
291
292     return errno;
293
294 error:
295     ERROR("Fail to mount block device: %s (%x)", bdev->name, -errno);
296     return errno;
297 }
298
299 int
300 __block_register(struct block_dev* bdev)
301 {
302     if (free_slot >= MAX_DEV) {
303         return 0;
304     }
305
306     struct device* dev = device_allocvol(dev_meta(blk_parent_dev), bdev);
307     dev->ops.write = __block_write;
308     dev->ops.write_page = __block_write_page;
309     dev->ops.read = __block_read;
310     dev->ops.read_page = __block_read_page;
311
312     bdev->dev = dev;
313
314     register_device(dev, bdev->class, "sd%c", 'a' + free_slot);
315     dev_registry[free_slot++] = bdev;
316
317     strcpy(bdev->bdev_id, dev->name_val);
318
319     return 1;
320 }
321
322 struct block_dev*
323 blk_mount_part(struct block_dev* bdev,
324                const char* name,
325                size_t index,
326                u64_t start_lba,
327                u64_t end_lba)
328 {
329     struct block_dev* pbdev = cake_grab(lbd_pile);
330     memcpy(pbdev, bdev, sizeof(*bdev));
331
332     struct device* dev = device_allocvol(NULL, pbdev);
333     dev->ops.write = __block_write;
334     dev->ops.write_page = __block_write_page;
335     dev->ops.read = __block_read;
336     dev->ops.read_page = __block_read_page;
337
338     pbdev->start_lba = start_lba;
339     pbdev->end_lba = end_lba;
340     pbdev->dev = dev;
341
342     strcpy(pbdev->bdev_id, dev->name_val);
343     if (name) {
344         strncpy(pbdev->name, name, PARTITION_NAME_SIZE);
345     }
346
347     llist_append(&bdev->parts, &pbdev->parts);
348
349     register_device(dev, pbdev->class, "%sp%d", bdev->bdev_id, index + 1);
350
351     return pbdev;
352 }