blob: e247ce33a3ec395462c8737d3fd2b943a75488b2 [file] [log] [blame]
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +03003 * (C) 2007-2008 Samuel Thibault.
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +03004 * (C) Copyright 2020 EPAM Systems Inc.
5 */
6#include <blk.h>
7#include <common.h>
8#include <dm.h>
9#include <dm/device-internal.h>
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +030010#include <malloc.h>
11#include <part.h>
12
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +030013#include <asm/armv8/mmu.h>
14#include <asm/io.h>
15#include <asm/xen/system.h>
16
17#include <linux/compat.h>
18
19#include <xen/events.h>
20#include <xen/gnttab.h>
21#include <xen/hvm.h>
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +030022#include <xen/xenbus.h>
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +030023
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +030024#include <xen/interface/io/ring.h>
25#include <xen/interface/io/blkif.h>
26#include <xen/interface/io/protocols.h>
27
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +030028#define DRV_NAME "pvblock"
29#define DRV_NAME_BLK "pvblock_blk"
30
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +030031#define O_RDONLY 00
32#define O_RDWR 02
33
34struct blkfront_info {
35 u64 sectors;
36 unsigned int sector_size;
37 int mode;
38 int info;
39 int barrier;
40 int flush;
41};
42
43/**
44 * struct blkfront_dev - Struct representing blkfront device
45 * @dom: Domain id
46 * @ring: Front_ring structure
47 * @ring_ref: The grant reference, allowing us to grant access
48 * to the ring to the other end/domain
49 * @evtchn: Event channel used to signal ring events
50 * @handle: Events handle
51 * @nodename: Device XenStore path in format "device/vbd/" + @devid
52 * @backend: Backend XenStore path
53 * @info: Private data
54 * @devid: Device id
55 */
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +030056struct blkfront_dev {
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +030057 domid_t dom;
58
59 struct blkif_front_ring ring;
60 grant_ref_t ring_ref;
61 evtchn_port_t evtchn;
62 blkif_vdev_t handle;
63
64 char *nodename;
65 char *backend;
66 struct blkfront_info info;
67 unsigned int devid;
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +030068};
69
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +030070struct blkfront_platdata {
71 unsigned int devid;
72};
73
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +030074static void free_blkfront(struct blkfront_dev *dev)
75{
76 mask_evtchn(dev->evtchn);
77 free(dev->backend);
78
79 gnttab_end_access(dev->ring_ref);
80 free(dev->ring.sring);
81
82 unbind_evtchn(dev->evtchn);
83
84 free(dev->nodename);
85 free(dev);
86}
87
88static void blkfront_handler(evtchn_port_t port, struct pt_regs *regs,
89 void *data)
90{
91 printf("%s [Port %d] - event received\n", __func__, port);
92}
93
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +030094static int init_blkfront(unsigned int devid, struct blkfront_dev *dev)
95{
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +030096 xenbus_transaction_t xbt;
97 char *err = NULL;
98 char *message = NULL;
99 struct blkif_sring *s;
100 int retry = 0;
101 char *msg = NULL;
102 char *c;
103 char nodename[32];
104 char path[ARRAY_SIZE(nodename) + strlen("/backend-id") + 1];
105
106 sprintf(nodename, "device/vbd/%d", devid);
107
108 memset(dev, 0, sizeof(*dev));
109 dev->nodename = strdup(nodename);
110 dev->devid = devid;
111
112 snprintf(path, sizeof(path), "%s/backend-id", nodename);
113 dev->dom = xenbus_read_integer(path);
114 evtchn_alloc_unbound(dev->dom, blkfront_handler, dev, &dev->evtchn);
115
116 s = (struct blkif_sring *)memalign(PAGE_SIZE, PAGE_SIZE);
117 if (!s) {
118 printf("Failed to allocate shared ring\n");
119 goto error;
120 }
121
122 SHARED_RING_INIT(s);
123 FRONT_RING_INIT(&dev->ring, s, PAGE_SIZE);
124
125 dev->ring_ref = gnttab_grant_access(dev->dom, virt_to_pfn(s), 0);
126
127again:
128 err = xenbus_transaction_start(&xbt);
129 if (err) {
130 printf("starting transaction\n");
131 free(err);
132 }
133
134 err = xenbus_printf(xbt, nodename, "ring-ref", "%u", dev->ring_ref);
135 if (err) {
136 message = "writing ring-ref";
137 goto abort_transaction;
138 }
139 err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn);
140 if (err) {
141 message = "writing event-channel";
142 goto abort_transaction;
143 }
144 err = xenbus_printf(xbt, nodename, "protocol", "%s",
145 XEN_IO_PROTO_ABI_NATIVE);
146 if (err) {
147 message = "writing protocol";
148 goto abort_transaction;
149 }
150
151 snprintf(path, sizeof(path), "%s/state", nodename);
152 err = xenbus_switch_state(xbt, path, XenbusStateConnected);
153 if (err) {
154 message = "switching state";
155 goto abort_transaction;
156 }
157
158 err = xenbus_transaction_end(xbt, 0, &retry);
159 free(err);
160 if (retry) {
161 goto again;
162 printf("completing transaction\n");
163 }
164
165 goto done;
166
167abort_transaction:
168 free(err);
169 err = xenbus_transaction_end(xbt, 1, &retry);
170 printf("Abort transaction %s\n", message);
171 goto error;
172
173done:
174 snprintf(path, sizeof(path), "%s/backend", nodename);
175 msg = xenbus_read(XBT_NIL, path, &dev->backend);
176 if (msg) {
177 printf("Error %s when reading the backend path %s\n",
178 msg, path);
179 goto error;
180 }
181
182 dev->handle = strtoul(strrchr(nodename, '/') + 1, NULL, 0);
183
184 {
185 XenbusState state;
186 char path[strlen(dev->backend) +
187 strlen("/feature-flush-cache") + 1];
188
189 snprintf(path, sizeof(path), "%s/mode", dev->backend);
190 msg = xenbus_read(XBT_NIL, path, &c);
191 if (msg) {
192 printf("Error %s when reading the mode\n", msg);
193 goto error;
194 }
195 if (*c == 'w')
196 dev->info.mode = O_RDWR;
197 else
198 dev->info.mode = O_RDONLY;
199 free(c);
200
201 snprintf(path, sizeof(path), "%s/state", dev->backend);
202
203 msg = NULL;
204 state = xenbus_read_integer(path);
205 while (!msg && state < XenbusStateConnected)
206 msg = xenbus_wait_for_state_change(path, &state);
207 if (msg || state != XenbusStateConnected) {
208 printf("backend not available, state=%d\n", state);
209 goto error;
210 }
211
212 snprintf(path, sizeof(path), "%s/info", dev->backend);
213 dev->info.info = xenbus_read_integer(path);
214
215 snprintf(path, sizeof(path), "%s/sectors", dev->backend);
216 /*
217 * FIXME: read_integer returns an int, so disk size
218 * limited to 1TB for now
219 */
220 dev->info.sectors = xenbus_read_integer(path);
221
222 snprintf(path, sizeof(path), "%s/sector-size", dev->backend);
223 dev->info.sector_size = xenbus_read_integer(path);
224
225 snprintf(path, sizeof(path), "%s/feature-barrier",
226 dev->backend);
227 dev->info.barrier = xenbus_read_integer(path);
228
229 snprintf(path, sizeof(path), "%s/feature-flush-cache",
230 dev->backend);
231 dev->info.flush = xenbus_read_integer(path);
232 }
233 unmask_evtchn(dev->evtchn);
234
235 debug("%llu sectors of %u bytes\n",
236 dev->info.sectors, dev->info.sector_size);
237
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300238 return 0;
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +0300239
240error:
241 free(msg);
242 free(err);
243 free_blkfront(dev);
244 return -ENODEV;
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300245}
246
247static void shutdown_blkfront(struct blkfront_dev *dev)
248{
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +0300249 char *err = NULL, *err2;
250 XenbusState state;
251
252 char path[strlen(dev->backend) + strlen("/state") + 1];
253 char nodename[strlen(dev->nodename) + strlen("/event-channel") + 1];
254
255 debug("Close " DRV_NAME ", device ID %d\n", dev->devid);
256
257 snprintf(path, sizeof(path), "%s/state", dev->backend);
258 snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename);
259
260 if ((err = xenbus_switch_state(XBT_NIL, nodename,
261 XenbusStateClosing)) != NULL) {
262 printf("%s: error changing state to %d: %s\n", __func__,
263 XenbusStateClosing, err);
264 goto close;
265 }
266
267 state = xenbus_read_integer(path);
268 while (!err && state < XenbusStateClosing)
269 err = xenbus_wait_for_state_change(path, &state);
270 free(err);
271
272 if ((err = xenbus_switch_state(XBT_NIL, nodename,
273 XenbusStateClosed)) != NULL) {
274 printf("%s: error changing state to %d: %s\n", __func__,
275 XenbusStateClosed, err);
276 goto close;
277 }
278
279 state = xenbus_read_integer(path);
280 while (state < XenbusStateClosed) {
281 err = xenbus_wait_for_state_change(path, &state);
282 free(err);
283 }
284
285 if ((err = xenbus_switch_state(XBT_NIL, nodename,
286 XenbusStateInitialising)) != NULL) {
287 printf("%s: error changing state to %d: %s\n", __func__,
288 XenbusStateInitialising, err);
289 goto close;
290 }
291
292 state = xenbus_read_integer(path);
293 while (!err &&
294 (state < XenbusStateInitWait || state >= XenbusStateClosed))
295 err = xenbus_wait_for_state_change(path, &state);
296
297close:
298 free(err);
299
300 snprintf(nodename, sizeof(nodename), "%s/ring-ref", dev->nodename);
301 err2 = xenbus_rm(XBT_NIL, nodename);
302 free(err2);
303 snprintf(nodename, sizeof(nodename), "%s/event-channel", dev->nodename);
304 err2 = xenbus_rm(XBT_NIL, nodename);
305 free(err2);
306
307 if (!err)
308 free_blkfront(dev);
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300309}
310
311ulong pvblock_blk_read(struct udevice *udev, lbaint_t blknr, lbaint_t blkcnt,
312 void *buffer)
313{
314 return 0;
315}
316
317ulong pvblock_blk_write(struct udevice *udev, lbaint_t blknr, lbaint_t blkcnt,
318 const void *buffer)
319{
320 return 0;
321}
322
323static int pvblock_blk_bind(struct udevice *udev)
324{
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +0300325 struct blk_desc *desc = dev_get_uclass_platdata(udev);
326 int devnum;
327
328 desc->if_type = IF_TYPE_PVBLOCK;
329 /*
330 * Initialize the devnum to -ENODEV. This is to make sure that
331 * blk_next_free_devnum() works as expected, since the default
332 * value 0 is a valid devnum.
333 */
334 desc->devnum = -ENODEV;
335 devnum = blk_next_free_devnum(IF_TYPE_PVBLOCK);
336 if (devnum < 0)
337 return devnum;
338 desc->devnum = devnum;
339 desc->part_type = PART_TYPE_UNKNOWN;
340 desc->bdev = udev;
341
342 strncpy(desc->vendor, "Xen", sizeof(desc->vendor));
343 strncpy(desc->revision, "1", sizeof(desc->revision));
344 strncpy(desc->product, "Virtual disk", sizeof(desc->product));
345
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300346 return 0;
347}
348
349static int pvblock_blk_probe(struct udevice *udev)
350{
351 struct blkfront_dev *blk_dev = dev_get_priv(udev);
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +0300352 struct blkfront_platdata *platdata = dev_get_platdata(udev);
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +0300353 struct blk_desc *desc = dev_get_uclass_platdata(udev);
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +0300354 int ret, devid;
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300355
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +0300356 devid = platdata->devid;
357 free(platdata);
358
359 ret = init_blkfront(devid, blk_dev);
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300360 if (ret < 0)
361 return ret;
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +0300362
363 desc->blksz = blk_dev->info.sector_size;
364 desc->lba = blk_dev->info.sectors;
365 desc->log2blksz = LOG2(blk_dev->info.sector_size);
366
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300367 return 0;
368}
369
370static int pvblock_blk_remove(struct udevice *udev)
371{
372 struct blkfront_dev *blk_dev = dev_get_priv(udev);
373
374 shutdown_blkfront(blk_dev);
375 return 0;
376}
377
378static const struct blk_ops pvblock_blk_ops = {
379 .read = pvblock_blk_read,
380 .write = pvblock_blk_write,
381};
382
383U_BOOT_DRIVER(pvblock_blk) = {
384 .name = DRV_NAME_BLK,
385 .id = UCLASS_BLK,
386 .ops = &pvblock_blk_ops,
387 .bind = pvblock_blk_bind,
388 .probe = pvblock_blk_probe,
389 .remove = pvblock_blk_remove,
390 .priv_auto_alloc_size = sizeof(struct blkfront_dev),
391 .flags = DM_FLAG_OS_PREPARE,
392};
393
394/*******************************************************************************
395 * Para-virtual block device class
396 *******************************************************************************/
397
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +0300398typedef int (*enum_vbd_callback)(struct udevice *parent, unsigned int devid);
399
400static int on_new_vbd(struct udevice *parent, unsigned int devid)
401{
402 struct driver_info info;
403 struct udevice *udev;
404 struct blkfront_platdata *platdata;
405 int ret;
406
407 debug("New " DRV_NAME_BLK ", device ID %d\n", devid);
408
409 platdata = malloc(sizeof(struct blkfront_platdata));
410 if (!platdata) {
411 printf("Failed to allocate platform data\n");
412 return -ENOMEM;
413 }
414
415 platdata->devid = devid;
416
417 info.name = DRV_NAME_BLK;
418 info.platdata = platdata;
419
420 ret = device_bind_by_name(parent, false, &info, &udev);
421 if (ret < 0) {
422 printf("Failed to bind " DRV_NAME_BLK " to device with ID %d, ret: %d\n",
423 devid, ret);
424 free(platdata);
425 }
426 return ret;
427}
428
429static int xenbus_enumerate_vbd(struct udevice *udev, enum_vbd_callback clb)
430{
431 char **dirs, *msg;
432 int i, ret;
433
434 msg = xenbus_ls(XBT_NIL, "device/vbd", &dirs);
435 if (msg) {
436 printf("Failed to read device/vbd directory: %s\n", msg);
437 free(msg);
438 return -ENODEV;
439 }
440
441 for (i = 0; dirs[i]; i++) {
442 int devid;
443
444 sscanf(dirs[i], "%d", &devid);
445 ret = clb(udev, devid);
446 if (ret < 0)
447 goto fail;
448
449 free(dirs[i]);
450 }
451 ret = 0;
452
453fail:
454 for (; dirs[i]; i++)
455 free(dirs[i]);
456 free(dirs);
457 return ret;
458}
459
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300460void pvblock_init(void)
461{
462 struct driver_info info;
463 struct udevice *udev;
464 struct uclass *uc;
465 int ret;
466
467 /*
468 * At this point Xen drivers have already initialized,
469 * so we can instantiate the class driver and enumerate
470 * virtual block devices.
471 */
472 info.name = DRV_NAME;
473 ret = device_bind_by_name(gd->dm_root, false, &info, &udev);
474 if (ret < 0)
475 printf("Failed to bind " DRV_NAME ", ret: %d\n", ret);
476
477 /* Bootstrap virtual block devices class driver */
478 ret = uclass_get(UCLASS_PVBLOCK, &uc);
479 if (ret)
480 return;
481 uclass_foreach_dev_probe(UCLASS_PVBLOCK, udev);
482}
483
484static int pvblock_probe(struct udevice *udev)
485{
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +0300486 struct uclass *uc;
487 int ret;
488
489 if (xenbus_enumerate_vbd(udev, on_new_vbd) < 0)
490 return -ENODEV;
491
492 ret = uclass_get(UCLASS_BLK, &uc);
493 if (ret)
494 return ret;
495 uclass_foreach_dev_probe(UCLASS_BLK, udev) {
496 if (_ret)
497 return _ret;
498 };
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300499 return 0;
500}
501
502U_BOOT_DRIVER(pvblock_drv) = {
503 .name = DRV_NAME,
504 .id = UCLASS_PVBLOCK,
505 .probe = pvblock_probe,
506};
507
508UCLASS_DRIVER(pvblock) = {
509 .name = DRV_NAME,
510 .id = UCLASS_PVBLOCK,
511};