blob: 1df04e239ad0a30a46acc6776ea7d2f194a61b9f [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 */
Patrick Delaunay81313352021-04-27 11:02:19 +02006
7#define LOG_CATEGORY UCLASS_PVBLOCK
8
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +03009#include <blk.h>
10#include <common.h>
11#include <dm.h>
12#include <dm/device-internal.h>
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +030013#include <malloc.h>
14#include <part.h>
15
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +030016#include <asm/armv8/mmu.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060017#include <asm/global_data.h>
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +030018#include <asm/io.h>
19#include <asm/xen/system.h>
20
Anastasiia Lukianenkoe855fbf2020-08-06 12:42:58 +030021#include <linux/bug.h>
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +030022#include <linux/compat.h>
23
24#include <xen/events.h>
25#include <xen/gnttab.h>
26#include <xen/hvm.h>
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +030027#include <xen/xenbus.h>
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +030028
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +030029#include <xen/interface/io/ring.h>
30#include <xen/interface/io/blkif.h>
31#include <xen/interface/io/protocols.h>
32
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +030033#define DRV_NAME "pvblock"
34#define DRV_NAME_BLK "pvblock_blk"
35
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +030036#define O_RDONLY 00
37#define O_RDWR 02
Anastasiia Lukianenkoe855fbf2020-08-06 12:42:58 +030038#define WAIT_RING_TO_MS 10
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +030039
40struct blkfront_info {
41 u64 sectors;
42 unsigned int sector_size;
43 int mode;
44 int info;
45 int barrier;
46 int flush;
47};
48
49/**
50 * struct blkfront_dev - Struct representing blkfront device
51 * @dom: Domain id
52 * @ring: Front_ring structure
53 * @ring_ref: The grant reference, allowing us to grant access
54 * to the ring to the other end/domain
55 * @evtchn: Event channel used to signal ring events
56 * @handle: Events handle
57 * @nodename: Device XenStore path in format "device/vbd/" + @devid
58 * @backend: Backend XenStore path
59 * @info: Private data
60 * @devid: Device id
61 */
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +030062struct blkfront_dev {
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +030063 domid_t dom;
64
65 struct blkif_front_ring ring;
66 grant_ref_t ring_ref;
67 evtchn_port_t evtchn;
68 blkif_vdev_t handle;
69
70 char *nodename;
71 char *backend;
72 struct blkfront_info info;
73 unsigned int devid;
Anastasiia Lukianenkoe855fbf2020-08-06 12:42:58 +030074 u8 *bounce_buffer;
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +030075};
76
Simon Glassb75b15b2020-12-03 16:55:23 -070077struct blkfront_plat {
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +030078 unsigned int devid;
79};
80
Anastasiia Lukianenkoe855fbf2020-08-06 12:42:58 +030081/**
82 * struct blkfront_aiocb - AIO сontrol block
83 * @aio_dev: Blockfront device
84 * @aio_buf: Memory buffer, which must be sector-aligned for
85 * @aio_dev sector
86 * @aio_nbytes: Size of AIO, which must be less than @aio_dev
87 * sector-sized amounts
88 * @aio_offset: Offset, which must not go beyond @aio_dev
89 * sector-aligned location
90 * @data: Data used to receiving response from ring
91 * @gref: Array of grant references
92 * @n: Number of segments
93 * @aio_cb: Represents one I/O request.
94 */
95struct blkfront_aiocb {
96 struct blkfront_dev *aio_dev;
97 u8 *aio_buf;
98 size_t aio_nbytes;
99 off_t aio_offset;
100 void *data;
101
102 grant_ref_t gref[BLKIF_MAX_SEGMENTS_PER_REQUEST];
103 int n;
104
105 void (*aio_cb)(struct blkfront_aiocb *aiocb, int ret);
106};
107
108static void blkfront_sync(struct blkfront_dev *dev);
109
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +0300110static void free_blkfront(struct blkfront_dev *dev)
111{
112 mask_evtchn(dev->evtchn);
113 free(dev->backend);
114
115 gnttab_end_access(dev->ring_ref);
116 free(dev->ring.sring);
117
118 unbind_evtchn(dev->evtchn);
119
Anastasiia Lukianenkoe855fbf2020-08-06 12:42:58 +0300120 free(dev->bounce_buffer);
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +0300121 free(dev->nodename);
122 free(dev);
123}
124
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300125static int init_blkfront(unsigned int devid, struct blkfront_dev *dev)
126{
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +0300127 xenbus_transaction_t xbt;
128 char *err = NULL;
129 char *message = NULL;
130 struct blkif_sring *s;
131 int retry = 0;
132 char *msg = NULL;
133 char *c;
134 char nodename[32];
135 char path[ARRAY_SIZE(nodename) + strlen("/backend-id") + 1];
136
137 sprintf(nodename, "device/vbd/%d", devid);
138
139 memset(dev, 0, sizeof(*dev));
140 dev->nodename = strdup(nodename);
141 dev->devid = devid;
142
143 snprintf(path, sizeof(path), "%s/backend-id", nodename);
144 dev->dom = xenbus_read_integer(path);
Anastasiia Lukianenkoe855fbf2020-08-06 12:42:58 +0300145 evtchn_alloc_unbound(dev->dom, NULL, dev, &dev->evtchn);
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +0300146
147 s = (struct blkif_sring *)memalign(PAGE_SIZE, PAGE_SIZE);
148 if (!s) {
149 printf("Failed to allocate shared ring\n");
150 goto error;
151 }
152
153 SHARED_RING_INIT(s);
154 FRONT_RING_INIT(&dev->ring, s, PAGE_SIZE);
155
156 dev->ring_ref = gnttab_grant_access(dev->dom, virt_to_pfn(s), 0);
157
158again:
159 err = xenbus_transaction_start(&xbt);
160 if (err) {
161 printf("starting transaction\n");
162 free(err);
163 }
164
165 err = xenbus_printf(xbt, nodename, "ring-ref", "%u", dev->ring_ref);
166 if (err) {
167 message = "writing ring-ref";
168 goto abort_transaction;
169 }
170 err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn);
171 if (err) {
172 message = "writing event-channel";
173 goto abort_transaction;
174 }
175 err = xenbus_printf(xbt, nodename, "protocol", "%s",
176 XEN_IO_PROTO_ABI_NATIVE);
177 if (err) {
178 message = "writing protocol";
179 goto abort_transaction;
180 }
181
182 snprintf(path, sizeof(path), "%s/state", nodename);
183 err = xenbus_switch_state(xbt, path, XenbusStateConnected);
184 if (err) {
185 message = "switching state";
186 goto abort_transaction;
187 }
188
189 err = xenbus_transaction_end(xbt, 0, &retry);
190 free(err);
191 if (retry) {
192 goto again;
193 printf("completing transaction\n");
194 }
195
196 goto done;
197
198abort_transaction:
199 free(err);
200 err = xenbus_transaction_end(xbt, 1, &retry);
201 printf("Abort transaction %s\n", message);
202 goto error;
203
204done:
205 snprintf(path, sizeof(path), "%s/backend", nodename);
206 msg = xenbus_read(XBT_NIL, path, &dev->backend);
207 if (msg) {
208 printf("Error %s when reading the backend path %s\n",
209 msg, path);
210 goto error;
211 }
212
213 dev->handle = strtoul(strrchr(nodename, '/') + 1, NULL, 0);
214
215 {
216 XenbusState state;
217 char path[strlen(dev->backend) +
218 strlen("/feature-flush-cache") + 1];
219
220 snprintf(path, sizeof(path), "%s/mode", dev->backend);
221 msg = xenbus_read(XBT_NIL, path, &c);
222 if (msg) {
223 printf("Error %s when reading the mode\n", msg);
224 goto error;
225 }
226 if (*c == 'w')
227 dev->info.mode = O_RDWR;
228 else
229 dev->info.mode = O_RDONLY;
230 free(c);
231
232 snprintf(path, sizeof(path), "%s/state", dev->backend);
233
234 msg = NULL;
235 state = xenbus_read_integer(path);
236 while (!msg && state < XenbusStateConnected)
237 msg = xenbus_wait_for_state_change(path, &state);
238 if (msg || state != XenbusStateConnected) {
239 printf("backend not available, state=%d\n", state);
240 goto error;
241 }
242
243 snprintf(path, sizeof(path), "%s/info", dev->backend);
244 dev->info.info = xenbus_read_integer(path);
245
246 snprintf(path, sizeof(path), "%s/sectors", dev->backend);
247 /*
248 * FIXME: read_integer returns an int, so disk size
249 * limited to 1TB for now
250 */
251 dev->info.sectors = xenbus_read_integer(path);
252
253 snprintf(path, sizeof(path), "%s/sector-size", dev->backend);
254 dev->info.sector_size = xenbus_read_integer(path);
255
256 snprintf(path, sizeof(path), "%s/feature-barrier",
257 dev->backend);
258 dev->info.barrier = xenbus_read_integer(path);
259
260 snprintf(path, sizeof(path), "%s/feature-flush-cache",
261 dev->backend);
262 dev->info.flush = xenbus_read_integer(path);
263 }
264 unmask_evtchn(dev->evtchn);
265
Anastasiia Lukianenkoe855fbf2020-08-06 12:42:58 +0300266 dev->bounce_buffer = memalign(dev->info.sector_size,
267 dev->info.sector_size);
268 if (!dev->bounce_buffer) {
269 printf("Failed to allocate bouncing buffer\n");
270 goto error;
271 }
272
273 debug("%llu sectors of %u bytes, bounce buffer at %p\n",
274 dev->info.sectors, dev->info.sector_size,
275 dev->bounce_buffer);
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +0300276
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300277 return 0;
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +0300278
279error:
280 free(msg);
281 free(err);
282 free_blkfront(dev);
283 return -ENODEV;
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300284}
285
286static void shutdown_blkfront(struct blkfront_dev *dev)
287{
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +0300288 char *err = NULL, *err2;
289 XenbusState state;
290
291 char path[strlen(dev->backend) + strlen("/state") + 1];
292 char nodename[strlen(dev->nodename) + strlen("/event-channel") + 1];
293
294 debug("Close " DRV_NAME ", device ID %d\n", dev->devid);
295
Anastasiia Lukianenkoe855fbf2020-08-06 12:42:58 +0300296 blkfront_sync(dev);
297
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +0300298 snprintf(path, sizeof(path), "%s/state", dev->backend);
299 snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename);
300
Anastasiia Lukianenkob6618c42020-08-21 12:10:04 +0300301 err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosing);
302 if (err) {
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +0300303 printf("%s: error changing state to %d: %s\n", __func__,
304 XenbusStateClosing, err);
305 goto close;
306 }
307
308 state = xenbus_read_integer(path);
309 while (!err && state < XenbusStateClosing)
310 err = xenbus_wait_for_state_change(path, &state);
311 free(err);
312
Anastasiia Lukianenkob6618c42020-08-21 12:10:04 +0300313 err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosed);
314 if (err) {
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +0300315 printf("%s: error changing state to %d: %s\n", __func__,
316 XenbusStateClosed, err);
317 goto close;
318 }
319
320 state = xenbus_read_integer(path);
321 while (state < XenbusStateClosed) {
322 err = xenbus_wait_for_state_change(path, &state);
323 free(err);
324 }
325
Anastasiia Lukianenkob6618c42020-08-21 12:10:04 +0300326 err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateInitialising);
327 if (err) {
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +0300328 printf("%s: error changing state to %d: %s\n", __func__,
329 XenbusStateInitialising, err);
330 goto close;
331 }
332
333 state = xenbus_read_integer(path);
334 while (!err &&
335 (state < XenbusStateInitWait || state >= XenbusStateClosed))
336 err = xenbus_wait_for_state_change(path, &state);
337
338close:
339 free(err);
340
341 snprintf(nodename, sizeof(nodename), "%s/ring-ref", dev->nodename);
342 err2 = xenbus_rm(XBT_NIL, nodename);
343 free(err2);
344 snprintf(nodename, sizeof(nodename), "%s/event-channel", dev->nodename);
345 err2 = xenbus_rm(XBT_NIL, nodename);
346 free(err2);
347
348 if (!err)
349 free_blkfront(dev);
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300350}
351
Anastasiia Lukianenkoe855fbf2020-08-06 12:42:58 +0300352/**
353 * blkfront_aio_poll() - AIO polling function.
354 * @dev: Blkfront device
355 *
356 * Here we receive response from the ring and check its status. This happens
357 * until we read all data from the ring. We read the data from consumed pointer
358 * to the response pointer. Then increase consumed pointer to make it clear that
359 * the data has been read.
360 *
361 * Return: Number of consumed bytes.
362 */
363static int blkfront_aio_poll(struct blkfront_dev *dev)
364{
365 RING_IDX rp, cons;
366 struct blkif_response *rsp;
367 int more;
368 int nr_consumed;
369
370moretodo:
371 rp = dev->ring.sring->rsp_prod;
372 rmb(); /* Ensure we see queued responses up to 'rp'. */
373 cons = dev->ring.rsp_cons;
374
375 nr_consumed = 0;
376 while ((cons != rp)) {
377 struct blkfront_aiocb *aiocbp;
378 int status;
379
380 rsp = RING_GET_RESPONSE(&dev->ring, cons);
381 nr_consumed++;
382
383 aiocbp = (void *)(uintptr_t)rsp->id;
384 status = rsp->status;
385
386 switch (rsp->operation) {
387 case BLKIF_OP_READ:
388 case BLKIF_OP_WRITE:
389 {
390 int j;
391
392 if (status != BLKIF_RSP_OKAY)
393 printf("%s error %d on %s at offset %llu, num bytes %llu\n",
394 rsp->operation == BLKIF_OP_READ ?
395 "read" : "write",
396 status, aiocbp->aio_dev->nodename,
397 (unsigned long long)aiocbp->aio_offset,
398 (unsigned long long)aiocbp->aio_nbytes);
399
400 for (j = 0; j < aiocbp->n; j++)
401 gnttab_end_access(aiocbp->gref[j]);
402
403 break;
404 }
405
406 case BLKIF_OP_WRITE_BARRIER:
407 if (status != BLKIF_RSP_OKAY)
408 printf("write barrier error %d\n", status);
409 break;
410 case BLKIF_OP_FLUSH_DISKCACHE:
411 if (status != BLKIF_RSP_OKAY)
412 printf("flush error %d\n", status);
413 break;
414
415 default:
416 printf("unrecognized block operation %d response (status %d)\n",
417 rsp->operation, status);
418 break;
419 }
420
421 dev->ring.rsp_cons = ++cons;
422 /* Nota: callback frees aiocbp itself */
423 if (aiocbp && aiocbp->aio_cb)
424 aiocbp->aio_cb(aiocbp, status ? -EIO : 0);
425 if (dev->ring.rsp_cons != cons)
426 /* We reentered, we must not continue here */
427 break;
428 }
429
430 RING_FINAL_CHECK_FOR_RESPONSES(&dev->ring, more);
431 if (more)
432 goto moretodo;
433
434 return nr_consumed;
435}
436
437static void blkfront_wait_slot(struct blkfront_dev *dev)
438{
439 /* Wait for a slot */
440 if (RING_FULL(&dev->ring)) {
441 while (true) {
442 blkfront_aio_poll(dev);
443 if (!RING_FULL(&dev->ring))
444 break;
445 wait_event_timeout(NULL, !RING_FULL(&dev->ring),
446 WAIT_RING_TO_MS);
447 }
448 }
449}
450
451/**
452 * blkfront_aio_poll() - Issue an aio.
453 * @aiocbp: AIO control block structure
454 * @write: Describes is it read or write operation
455 * 0 - read
456 * 1 - write
457 *
458 * We check whether the AIO parameters meet the requirements of the device.
459 * Then receive request from ring and define its arguments. After this we
460 * grant access to the grant references. The last step is notifying about AIO
461 * via event channel.
462 */
463static void blkfront_aio(struct blkfront_aiocb *aiocbp, int write)
464{
465 struct blkfront_dev *dev = aiocbp->aio_dev;
466 struct blkif_request *req;
467 RING_IDX i;
468 int notify;
469 int n, j;
470 uintptr_t start, end;
471
472 /* Can't io at non-sector-aligned location */
473 BUG_ON(aiocbp->aio_offset & (dev->info.sector_size - 1));
474 /* Can't io non-sector-sized amounts */
475 BUG_ON(aiocbp->aio_nbytes & (dev->info.sector_size - 1));
476 /* Can't io non-sector-aligned buffer */
477 BUG_ON(((uintptr_t)aiocbp->aio_buf & (dev->info.sector_size - 1)));
478
479 start = (uintptr_t)aiocbp->aio_buf & PAGE_MASK;
480 end = ((uintptr_t)aiocbp->aio_buf + aiocbp->aio_nbytes +
481 PAGE_SIZE - 1) & PAGE_MASK;
482 n = (end - start) / PAGE_SIZE;
483 aiocbp->n = n;
484
485 BUG_ON(n > BLKIF_MAX_SEGMENTS_PER_REQUEST);
486
487 blkfront_wait_slot(dev);
488 i = dev->ring.req_prod_pvt;
489 req = RING_GET_REQUEST(&dev->ring, i);
490
491 req->operation = write ? BLKIF_OP_WRITE : BLKIF_OP_READ;
492 req->nr_segments = n;
493 req->handle = dev->handle;
494 req->id = (uintptr_t)aiocbp;
495 req->sector_number = aiocbp->aio_offset / dev->info.sector_size;
496
497 for (j = 0; j < n; j++) {
498 req->seg[j].first_sect = 0;
499 req->seg[j].last_sect = PAGE_SIZE / dev->info.sector_size - 1;
500 }
501 req->seg[0].first_sect = ((uintptr_t)aiocbp->aio_buf & ~PAGE_MASK) /
502 dev->info.sector_size;
503 req->seg[n - 1].last_sect = (((uintptr_t)aiocbp->aio_buf +
504 aiocbp->aio_nbytes - 1) & ~PAGE_MASK) / dev->info.sector_size;
505 for (j = 0; j < n; j++) {
506 uintptr_t data = start + j * PAGE_SIZE;
507
508 if (!write) {
509 /* Trigger CoW if needed */
510 *(char *)(data + (req->seg[j].first_sect *
511 dev->info.sector_size)) = 0;
512 barrier();
513 }
514 req->seg[j].gref = gnttab_grant_access(dev->dom,
515 virt_to_pfn((void *)data),
516 write);
517 aiocbp->gref[j] = req->seg[j].gref;
518 }
519
520 dev->ring.req_prod_pvt = i + 1;
521
522 wmb();
523 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&dev->ring, notify);
524
525 if (notify)
526 notify_remote_via_evtchn(dev->evtchn);
527}
528
529static void blkfront_aio_cb(struct blkfront_aiocb *aiocbp, int ret)
530{
531 aiocbp->data = (void *)1;
532 aiocbp->aio_cb = NULL;
533}
534
535static void blkfront_io(struct blkfront_aiocb *aiocbp, int write)
536{
537 aiocbp->aio_cb = blkfront_aio_cb;
538 blkfront_aio(aiocbp, write);
539 aiocbp->data = NULL;
540
541 while (true) {
542 blkfront_aio_poll(aiocbp->aio_dev);
543 if (aiocbp->data)
544 break;
545 cpu_relax();
546 }
547}
548
549static void blkfront_push_operation(struct blkfront_dev *dev, u8 op,
550 uint64_t id)
551{
552 struct blkif_request *req;
553 int notify, i;
554
555 blkfront_wait_slot(dev);
556 i = dev->ring.req_prod_pvt;
557 req = RING_GET_REQUEST(&dev->ring, i);
558 req->operation = op;
559 req->nr_segments = 0;
560 req->handle = dev->handle;
561 req->id = id;
562 req->sector_number = 0;
563 dev->ring.req_prod_pvt = i + 1;
564 wmb();
565 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&dev->ring, notify);
566 if (notify)
567 notify_remote_via_evtchn(dev->evtchn);
568}
569
570static void blkfront_sync(struct blkfront_dev *dev)
571{
572 if (dev->info.mode == O_RDWR) {
573 if (dev->info.barrier == 1)
574 blkfront_push_operation(dev,
575 BLKIF_OP_WRITE_BARRIER, 0);
576
577 if (dev->info.flush == 1)
578 blkfront_push_operation(dev,
579 BLKIF_OP_FLUSH_DISKCACHE, 0);
580 }
581
582 while (true) {
583 blkfront_aio_poll(dev);
584 if (RING_FREE_REQUESTS(&dev->ring) == RING_SIZE(&dev->ring))
585 break;
586 cpu_relax();
587 }
588}
589
590/**
591 * pvblock_iop() - Issue an aio.
592 * @udev: Pvblock device
593 * @blknr: Block number to read from / write to
594 * @blkcnt: Amount of blocks to read / write
595 * @buffer: Memory buffer with data to be read / write
596 * @write: Describes is it read or write operation
597 * 0 - read
598 * 1 - write
599 *
600 * Depending on the operation - reading or writing, data is read / written from the
601 * specified address (@buffer) to the sector (@blknr).
602 */
603static ulong pvblock_iop(struct udevice *udev, lbaint_t blknr,
604 lbaint_t blkcnt, void *buffer, int write)
605{
606 struct blkfront_dev *blk_dev = dev_get_priv(udev);
Simon Glass71fa5b42020-12-03 16:55:18 -0700607 struct blk_desc *desc = dev_get_uclass_plat(udev);
Anastasiia Lukianenkoe855fbf2020-08-06 12:42:58 +0300608 struct blkfront_aiocb aiocb;
609 lbaint_t blocks_todo;
610 bool unaligned;
611
612 if (blkcnt == 0)
613 return 0;
614
615 if ((blknr + blkcnt) > desc->lba) {
616 printf(DRV_NAME ": block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
617 blknr + blkcnt, desc->lba);
618 return 0;
619 }
620
621 unaligned = (uintptr_t)buffer & (blk_dev->info.sector_size - 1);
622
623 aiocb.aio_dev = blk_dev;
624 aiocb.aio_offset = blknr * desc->blksz;
625 aiocb.aio_cb = NULL;
626 aiocb.data = NULL;
627 blocks_todo = blkcnt;
628 do {
629 aiocb.aio_buf = unaligned ? blk_dev->bounce_buffer : buffer;
630
631 if (write && unaligned)
632 memcpy(blk_dev->bounce_buffer, buffer, desc->blksz);
633
634 aiocb.aio_nbytes = unaligned ? desc->blksz :
AKASHI Takahiro782ad642023-11-15 10:53:45 +0900635 min((size_t)((BLKIF_MAX_SEGMENTS_PER_REQUEST - 1)
636 * PAGE_SIZE),
Anastasiia Lukianenkoe855fbf2020-08-06 12:42:58 +0300637 (size_t)(blocks_todo * desc->blksz));
638
639 blkfront_io(&aiocb, write);
640
641 if (!write && unaligned)
642 memcpy(buffer, blk_dev->bounce_buffer, desc->blksz);
643
644 aiocb.aio_offset += aiocb.aio_nbytes;
645 buffer += aiocb.aio_nbytes;
646 blocks_todo -= aiocb.aio_nbytes / desc->blksz;
647 } while (blocks_todo > 0);
648
649 return blkcnt;
650}
651
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300652ulong pvblock_blk_read(struct udevice *udev, lbaint_t blknr, lbaint_t blkcnt,
653 void *buffer)
654{
Anastasiia Lukianenkoe855fbf2020-08-06 12:42:58 +0300655 return pvblock_iop(udev, blknr, blkcnt, buffer, 0);
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300656}
657
658ulong pvblock_blk_write(struct udevice *udev, lbaint_t blknr, lbaint_t blkcnt,
659 const void *buffer)
660{
Anastasiia Lukianenkoe855fbf2020-08-06 12:42:58 +0300661 return pvblock_iop(udev, blknr, blkcnt, (void *)buffer, 1);
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300662}
663
664static int pvblock_blk_bind(struct udevice *udev)
665{
Simon Glass71fa5b42020-12-03 16:55:18 -0700666 struct blk_desc *desc = dev_get_uclass_plat(udev);
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +0300667 int devnum;
668
Simon Glassfada3f92022-09-17 09:00:09 -0600669 desc->uclass_id = UCLASS_PVBLOCK;
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +0300670 /*
671 * Initialize the devnum to -ENODEV. This is to make sure that
672 * blk_next_free_devnum() works as expected, since the default
673 * value 0 is a valid devnum.
674 */
675 desc->devnum = -ENODEV;
Simon Glassdbfa32c2022-08-11 19:34:59 -0600676 devnum = blk_next_free_devnum(UCLASS_PVBLOCK);
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +0300677 if (devnum < 0)
678 return devnum;
679 desc->devnum = devnum;
680 desc->part_type = PART_TYPE_UNKNOWN;
681 desc->bdev = udev;
682
683 strncpy(desc->vendor, "Xen", sizeof(desc->vendor));
684 strncpy(desc->revision, "1", sizeof(desc->revision));
685 strncpy(desc->product, "Virtual disk", sizeof(desc->product));
686
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300687 return 0;
688}
689
690static int pvblock_blk_probe(struct udevice *udev)
691{
692 struct blkfront_dev *blk_dev = dev_get_priv(udev);
Simon Glassb75b15b2020-12-03 16:55:23 -0700693 struct blkfront_plat *plat = dev_get_plat(udev);
Simon Glass71fa5b42020-12-03 16:55:18 -0700694 struct blk_desc *desc = dev_get_uclass_plat(udev);
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +0300695 int ret, devid;
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300696
Simon Glass71fa5b42020-12-03 16:55:18 -0700697 devid = plat->devid;
698 free(plat);
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +0300699
700 ret = init_blkfront(devid, blk_dev);
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300701 if (ret < 0)
702 return ret;
Anastasiia Lukianenko7ad05de2020-08-06 12:42:57 +0300703
704 desc->blksz = blk_dev->info.sector_size;
705 desc->lba = blk_dev->info.sectors;
706 desc->log2blksz = LOG2(blk_dev->info.sector_size);
707
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300708 return 0;
709}
710
711static int pvblock_blk_remove(struct udevice *udev)
712{
713 struct blkfront_dev *blk_dev = dev_get_priv(udev);
714
715 shutdown_blkfront(blk_dev);
716 return 0;
717}
718
719static const struct blk_ops pvblock_blk_ops = {
720 .read = pvblock_blk_read,
721 .write = pvblock_blk_write,
722};
723
724U_BOOT_DRIVER(pvblock_blk) = {
725 .name = DRV_NAME_BLK,
726 .id = UCLASS_BLK,
727 .ops = &pvblock_blk_ops,
728 .bind = pvblock_blk_bind,
729 .probe = pvblock_blk_probe,
730 .remove = pvblock_blk_remove,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700731 .priv_auto = sizeof(struct blkfront_dev),
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300732 .flags = DM_FLAG_OS_PREPARE,
733};
734
735/*******************************************************************************
736 * Para-virtual block device class
737 *******************************************************************************/
738
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +0300739typedef int (*enum_vbd_callback)(struct udevice *parent, unsigned int devid);
740
741static int on_new_vbd(struct udevice *parent, unsigned int devid)
742{
743 struct driver_info info;
744 struct udevice *udev;
Simon Glassb75b15b2020-12-03 16:55:23 -0700745 struct blkfront_plat *plat;
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +0300746 int ret;
747
748 debug("New " DRV_NAME_BLK ", device ID %d\n", devid);
749
Simon Glassb75b15b2020-12-03 16:55:23 -0700750 plat = malloc(sizeof(struct blkfront_plat));
Simon Glass71fa5b42020-12-03 16:55:18 -0700751 if (!plat) {
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +0300752 printf("Failed to allocate platform data\n");
753 return -ENOMEM;
754 }
755
Simon Glass71fa5b42020-12-03 16:55:18 -0700756 plat->devid = devid;
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +0300757
758 info.name = DRV_NAME_BLK;
Simon Glass71fa5b42020-12-03 16:55:18 -0700759 info.plat = plat;
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +0300760
761 ret = device_bind_by_name(parent, false, &info, &udev);
762 if (ret < 0) {
763 printf("Failed to bind " DRV_NAME_BLK " to device with ID %d, ret: %d\n",
764 devid, ret);
Simon Glass71fa5b42020-12-03 16:55:18 -0700765 free(plat);
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +0300766 }
767 return ret;
768}
769
770static int xenbus_enumerate_vbd(struct udevice *udev, enum_vbd_callback clb)
771{
772 char **dirs, *msg;
773 int i, ret;
774
775 msg = xenbus_ls(XBT_NIL, "device/vbd", &dirs);
776 if (msg) {
777 printf("Failed to read device/vbd directory: %s\n", msg);
778 free(msg);
779 return -ENODEV;
780 }
781
782 for (i = 0; dirs[i]; i++) {
783 int devid;
784
785 sscanf(dirs[i], "%d", &devid);
786 ret = clb(udev, devid);
787 if (ret < 0)
788 goto fail;
789
790 free(dirs[i]);
791 }
792 ret = 0;
793
794fail:
795 for (; dirs[i]; i++)
796 free(dirs[i]);
797 free(dirs);
798 return ret;
799}
800
Anastasiia Lukianenkoddf6e6a2020-08-06 12:42:59 +0300801static void print_pvblock_devices(void)
802{
803 struct udevice *udev;
804 bool first = true;
805 const char *class_name;
806
807 class_name = uclass_get_name(UCLASS_PVBLOCK);
Simon Glassdbfa32c2022-08-11 19:34:59 -0600808 for (blk_first_device(UCLASS_PVBLOCK, &udev); udev;
Anastasiia Lukianenkoddf6e6a2020-08-06 12:42:59 +0300809 blk_next_device(&udev), first = false) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700810 struct blk_desc *desc = dev_get_uclass_plat(udev);
Anastasiia Lukianenkoddf6e6a2020-08-06 12:42:59 +0300811
812 if (!first)
813 puts(", ");
814 printf("%s: %d", class_name, desc->devnum);
815 }
816 printf("\n");
817}
818
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300819void pvblock_init(void)
820{
821 struct driver_info info;
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300822 int ret;
823
824 /*
825 * At this point Xen drivers have already initialized,
826 * so we can instantiate the class driver and enumerate
827 * virtual block devices.
828 */
829 info.name = DRV_NAME;
Michal Suchanek94142a72022-10-22 16:33:05 +0200830 ret = device_bind_by_name(gd->dm_root, false, &info, NULL);
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300831 if (ret < 0)
832 printf("Failed to bind " DRV_NAME ", ret: %d\n", ret);
833
834 /* Bootstrap virtual block devices class driver */
Michal Suchanek94142a72022-10-22 16:33:05 +0200835 uclass_probe_all(UCLASS_PVBLOCK);
Anastasiia Lukianenkoddf6e6a2020-08-06 12:42:59 +0300836
837 print_pvblock_devices();
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300838}
839
840static int pvblock_probe(struct udevice *udev)
841{
Anastasiia Lukianenko79d9f2a2020-08-06 12:42:56 +0300842 struct uclass *uc;
843 int ret;
844
845 if (xenbus_enumerate_vbd(udev, on_new_vbd) < 0)
846 return -ENODEV;
847
848 ret = uclass_get(UCLASS_BLK, &uc);
849 if (ret)
850 return ret;
Michal Suchanek53beee92022-10-12 21:58:05 +0200851 uclass_foreach_dev_probe(UCLASS_BLK, udev);
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +0300852 return 0;
853}
854
855U_BOOT_DRIVER(pvblock_drv) = {
856 .name = DRV_NAME,
857 .id = UCLASS_PVBLOCK,
858 .probe = pvblock_probe,
859};
860
861UCLASS_DRIVER(pvblock) = {
862 .name = DRV_NAME,
863 .id = UCLASS_PVBLOCK,
864};