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