feat: a file system mapping for pci devices
[lunaix-os.git] / lunaix-os / kernel / 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 struct cake_pile* lbd_pile;
23 struct block_dev** dev_registry;
24
25 int free_slot = 0;
26
27 int
28 __block_mount_partitions(struct hba_device* hd_dev);
29
30 int
31 __block_register(struct block_dev* dev);
32
33 void
34 block_init()
35 {
36     lbd_pile = cake_new_pile("block_dev", sizeof(struct block_dev), 1, 0);
37     dev_registry = vcalloc(sizeof(struct block_dev*), MAX_DEV);
38     free_slot = 0;
39 }
40
41 int
42 __block_read(struct device* dev, void* buf, size_t offset, size_t len)
43 {
44     int errno;
45     struct block_dev* bdev = (struct block_dev*)dev->underlay;
46     size_t acc_size = 0, rd_size = 0, bsize = bdev->hd_dev->block_size,
47            rd_block = offset / bsize, r = offset % bsize,
48            max_blk = (size_t)bdev->hd_dev->max_lba;
49     void* block = vzalloc(bsize);
50
51     while (acc_size < len && rd_block < max_blk) {
52         if (!bdev->hd_dev->ops.read_buffer(
53               bdev->hd_dev, rd_block, block, bsize)) {
54             errno = EIO;
55             goto error;
56         }
57         rd_size = MIN(len - acc_size, bsize - r);
58         memcpy(buf + acc_size, block + r, rd_size);
59         acc_size += rd_size;
60         r = 0;
61         rd_block++;
62     }
63
64     vfree(block);
65     return acc_size;
66
67 error:
68     vfree(block);
69     return errno;
70 }
71
72 int
73 __block_write(struct device* dev, void* buf, size_t offset, size_t len)
74 {
75     int errno;
76     struct block_dev* bdev = (struct block_dev*)dev->underlay;
77     size_t acc_size = 0, wr_size = 0, bsize = bdev->hd_dev->block_size,
78            wr_block = offset / bsize, r = offset % bsize;
79     void* block = vzalloc(bsize);
80
81     while (acc_size < len) {
82         wr_size = MIN(len - acc_size, bsize - r);
83         memcpy(block + r, buf + acc_size, wr_size);
84         if (!bdev->hd_dev->ops.write_buffer(
85               bdev->hd_dev, wr_block, block, bsize)) {
86             errno = EIO;
87             break;
88         }
89         acc_size += wr_size;
90         r = 0;
91         wr_block++;
92     }
93
94     vfree(block);
95     return wr_block;
96
97 error:
98     vfree(block);
99     return errno;
100 }
101
102 int
103 block_mount_disk(struct hba_device* hd_dev)
104 {
105     int errno = 0;
106     struct block_dev* bdev = cake_grab(lbd_pile);
107     strncpy(bdev->name, hd_dev->model, PARTITION_NAME_SIZE);
108     bdev->hd_dev = hd_dev;
109     bdev->base_lba = 0;
110     bdev->end_lba = hd_dev->max_lba;
111     if (!__block_register(bdev)) {
112         errno = BLOCK_EFULL;
113         goto error;
114     }
115
116     return errno;
117
118 error:
119     kprintf(KERROR "Fail to mount hd: %s[%s] (%x)\n",
120             hd_dev->model,
121             hd_dev->serial_num,
122             -errno);
123 }
124
125 int
126 __block_register(struct block_dev* bdev)
127 {
128     if (free_slot >= MAX_DEV) {
129         return 0;
130     }
131
132     struct device* dev = device_addvol(NULL, bdev, "sd%c", 'a' + free_slot);
133     dev->write = __block_write;
134     dev->read = __block_read;
135
136     bdev->dev = dev;
137     dev_registry[free_slot++] = bdev;
138     return 1;
139 }