refactor: more compact log message
[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 = vbuf_alloc(NULL, buf, len);
59     struct blkio_req* req;
60     void* tmp_buf = NULL;
61
62     if (r) {
63         tmp_buf = vzalloc(bsize);
64         rd_size = MIN(len, bsize - r);
65         vbuf->buf.size = bsize;
66         vbuf->buf.buffer = tmp_buf;
67
68         if ((len - rd_size)) {
69             vbuf_alloc(vbuf, buf + rd_size, len - rd_size);
70         }
71     }
72
73     req = blkio_vrd(vbuf, rd_block, NULL, NULL, 0);
74     blkio_commit(bdev->blkio, req);
75
76     pwait(&req->wait);
77
78     if (!(errno = req->errcode)) {
79         memcpy(buf, tmp_buf + r, rd_size);
80         errno = len;
81     } else {
82         errno = -errno;
83     }
84
85     if (tmp_buf) {
86         vfree(tmp_buf);
87     }
88
89     blkio_free_req(req);
90     vbuf_free(vbuf);
91     return errno;
92 }
93
94 int
95 __block_write(struct device* dev, void* buf, size_t offset, size_t len)
96 {
97     struct block_dev* bdev = (struct block_dev*)dev->underlay;
98     size_t bsize = bdev->blk_size, rd_block = offset / bsize + bdev->start_lba,
99            r = offset % bsize;
100
101     if (!(len = MIN(len, ((size_t)bdev->end_lba - rd_block + 1) * bsize))) {
102         return 0;
103     }
104
105     struct vecbuf* vbuf = vbuf_alloc(NULL, buf, len);
106     struct blkio_req* req;
107     void* tmp_buf = NULL;
108
109     if (r) {
110         size_t rd_size = MIN(len, bsize - r);
111         tmp_buf = vzalloc(bsize);
112         vbuf->buf.size = bsize;
113         vbuf->buf.buffer = tmp_buf;
114
115         memcpy(tmp_buf + r, buf, rd_size);
116         vbuf_alloc(vbuf, buf + rd_size, len - rd_size);
117     }
118
119     req = blkio_vwr(vbuf, rd_block, NULL, NULL, 0);
120     blkio_commit(bdev->blkio, req);
121
122     pwait(&req->wait);
123
124     int errno = req->errcode;
125     if (!errno) {
126         errno = len;
127     } else {
128         errno = -errno;
129     }
130
131     if (tmp_buf) {
132         vfree(tmp_buf);
133     }
134
135     blkio_free_req(req);
136     vbuf_free(vbuf);
137     return errno;
138 }
139
140 struct block_dev*
141 block_alloc_dev(const char* blk_id, void* driver, req_handler ioreq_handler)
142 {
143     struct block_dev* bdev = cake_grab(lbd_pile);
144     memset(bdev, 0, sizeof(struct block_dev));
145     llist_init_head(&bdev->parts);
146     strncpy(bdev->name, blk_id, PARTITION_NAME_SIZE);
147
148     bdev->blkio = blkio_newctx(ioreq_handler);
149     bdev->driver = driver;
150     bdev->blkio->driver = driver;
151
152     return bdev;
153 }
154
155 int
156 block_mount(struct block_dev* bdev, devfs_exporter fs_export)
157 {
158     int errno = 0;
159
160     if (!__block_register(bdev)) {
161         errno = BLOCK_EFULL;
162         goto error;
163     }
164
165     errno = blkpart_probegpt(bdev->dev);
166     if (errno < 0) {
167         kprintf(KERROR "Fail to parse partition table (%d)\n", errno);
168     } else if (!errno) {
169         // TODO try other PT parser...
170     }
171
172     struct twifs_node* dev_root = twifs_dir_node(blk_sysroot, bdev->bdev_id);
173     blk_set_blkmapping(bdev, dev_root);
174     fs_export(bdev, dev_root);
175
176     return errno;
177
178 error:
179     kprintf(KERROR "Fail to mount block device: %s (%x)\n", bdev->name, -errno);
180     return errno;
181 }
182
183 int
184 __block_register(struct block_dev* bdev)
185 {
186     if (free_slot >= MAX_DEV) {
187         return 0;
188     }
189
190     struct device* dev = device_addvol(NULL, bdev, "sd%c", 'a' + free_slot);
191     dev->write = __block_write;
192     dev->read = __block_read;
193
194     bdev->dev = dev;
195     strcpy(bdev->bdev_id, dev->name_val);
196     dev_registry[free_slot++] = bdev;
197     return 1;
198 }
199
200 struct block_dev*
201 blk_mount_part(struct block_dev* bdev,
202                const char* name,
203                size_t index,
204                u64_t start_lba,
205                u64_t end_lba)
206 {
207     struct block_dev* pbdev = cake_grab(lbd_pile);
208     memcpy(pbdev, bdev, sizeof(*bdev));
209
210     struct device* dev =
211       device_addvol(NULL, pbdev, "%sp%d", bdev->bdev_id, index + 1);
212     dev->write = __block_write;
213     dev->read = __block_read;
214
215     pbdev->start_lba = start_lba;
216     pbdev->end_lba = end_lba;
217     pbdev->dev = dev;
218
219     strcpy(pbdev->bdev_id, dev->name_val);
220     if (name) {
221         strncpy(pbdev->name, name, PARTITION_NAME_SIZE);
222     }
223
224     llist_append(&bdev->parts, &pbdev->parts);
225
226     return pbdev;
227 }