fix: use wait queue for blocking process
[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     blkio_init();
38     lbd_pile = cake_new_pile("block_dev", sizeof(struct block_dev), 1, 0);
39     dev_registry = vcalloc(sizeof(struct block_dev*), MAX_DEV);
40     free_slot = 0;
41     blk_sysroot = twifs_dir_node(NULL, "block");
42 }
43
44 int
45 __block_read(struct device* dev, void* buf, size_t offset, size_t len)
46 {
47     int errno;
48     struct block_dev* bdev = (struct block_dev*)dev->underlay;
49     size_t bsize = bdev->blk_size, rd_block = offset / bsize,
50            r = offset % bsize, rd_size = 0;
51
52     if (!(len = MIN(len, ((size_t)bdev->end_lba - rd_block + 1) * bsize))) {
53         return 0;
54     }
55
56     struct vecbuf* vbuf = vbuf_alloc(NULL, buf, len);
57     struct blkio_req* req;
58     void* tmp_buf = NULL;
59
60     if (r) {
61         tmp_buf = vzalloc(bsize);
62         rd_size = MIN(len, bsize - r);
63         vbuf->buf.size = rd_size;
64         vbuf->buf.buffer = tmp_buf;
65
66         vbuf_alloc(vbuf, buf + rd_size, len - rd_size);
67     }
68
69     req = blkio_vrd(vbuf, rd_block, NULL, NULL, 0);
70     blkio_commit(bdev->blkio, req);
71
72     pwait(&req->wait);
73
74     if (!(errno = req->errcode)) {
75         memcpy(buf, tmp_buf + r, rd_size);
76         errno = len;
77     } else {
78         errno = -errno;
79     }
80
81     if (tmp_buf) {
82         vfree(tmp_buf);
83     }
84
85     blkio_free_req(req);
86     vbuf_free(vbuf);
87     return errno;
88 }
89
90 int
91 __block_write(struct device* dev, void* buf, size_t offset, size_t len)
92 {
93     struct block_dev* bdev = (struct block_dev*)dev->underlay;
94     size_t bsize = bdev->blk_size, rd_block = offset / bsize,
95            r = offset % bsize;
96
97     if (!(len = MIN(len, ((size_t)bdev->end_lba - rd_block + 1) * bsize))) {
98         return 0;
99     }
100
101     struct vecbuf* vbuf = vbuf_alloc(NULL, buf, len);
102     struct blkio_req* req;
103     void* tmp_buf = NULL;
104
105     if (r) {
106         size_t rd_size = MIN(len, bsize - r);
107         tmp_buf = vzalloc(bsize);
108         vbuf->buf.size = bsize;
109         vbuf->buf.buffer = tmp_buf;
110
111         memcpy(tmp_buf + r, buf, rd_size);
112         vbuf_alloc(vbuf, buf + rd_size, len - rd_size);
113     }
114
115     req = blkio_vwr(vbuf, rd_block, NULL, NULL, 0);
116     blkio_commit(bdev->blkio, req);
117
118     pwait(&req->wait);
119
120     int errno = req->errcode;
121     if (!errno) {
122         errno = len;
123     } else {
124         errno = -errno;
125     }
126
127     if (tmp_buf) {
128         vfree(tmp_buf);
129     }
130
131     blkio_free_req(req);
132     vbuf_free(vbuf);
133     return errno;
134 }
135
136 struct block_dev*
137 block_alloc_dev(const char* blk_id, void* driver, req_handler ioreq_handler)
138 {
139     struct block_dev* bdev = cake_grab(lbd_pile);
140     memset(bdev, 0, sizeof(struct block_dev));
141
142     strncpy(bdev->name, blk_id, PARTITION_NAME_SIZE);
143
144     bdev->blkio = blkio_newctx(ioreq_handler);
145     bdev->driver = driver;
146     bdev->blkio->driver = driver;
147
148     return bdev;
149 }
150
151 int
152 block_mount(struct block_dev* bdev, devfs_exporter fs_export)
153 {
154     int errno = 0;
155
156     if (!__block_register(bdev)) {
157         errno = BLOCK_EFULL;
158         goto error;
159     }
160
161     struct twifs_node* dev_root = twifs_dir_node(blk_sysroot, bdev->bdev_id);
162     blk_set_blkmapping(bdev, dev_root);
163     fs_export(bdev, dev_root);
164
165     return errno;
166
167 error:
168     kprintf(KERROR "Fail to mount block device: %s (%x)\n", bdev->name, -errno);
169     return errno;
170 }
171
172 int
173 __block_register(struct block_dev* bdev)
174 {
175     if (free_slot >= MAX_DEV) {
176         return 0;
177     }
178
179     struct device* dev = device_addvol(NULL, bdev, "sd%c", 'a' + free_slot);
180     dev->write = __block_write;
181     dev->read = __block_read;
182
183     bdev->dev = dev;
184     strcpy(bdev->bdev_id, dev->name_val);
185     dev_registry[free_slot++] = bdev;
186     return 1;
187 }