blob: 3ed62cac5d0f9e22ba5b8514b9c4829ecaa74bc4 [file] [log] [blame]
Anastasiia Lukianenko722bc5b2020-08-06 12:42:55 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2020 EPAM Systems Inc.
4 */
5#include <blk.h>
6#include <common.h>
7#include <dm.h>
8#include <dm/device-internal.h>
Anastasiia Lukianenkoa9993132020-08-06 12:42:56 +03009#include <malloc.h>
10#include <part.h>
11
12#include <xen/xenbus.h>
Anastasiia Lukianenko722bc5b2020-08-06 12:42:55 +030013
14#define DRV_NAME "pvblock"
15#define DRV_NAME_BLK "pvblock_blk"
16
17struct blkfront_dev {
18 char dummy;
19};
20
Anastasiia Lukianenkoa9993132020-08-06 12:42:56 +030021struct blkfront_platdata {
22 unsigned int devid;
23};
24
Anastasiia Lukianenko722bc5b2020-08-06 12:42:55 +030025static int init_blkfront(unsigned int devid, struct blkfront_dev *dev)
26{
27 return 0;
28}
29
30static void shutdown_blkfront(struct blkfront_dev *dev)
31{
32}
33
34ulong pvblock_blk_read(struct udevice *udev, lbaint_t blknr, lbaint_t blkcnt,
35 void *buffer)
36{
37 return 0;
38}
39
40ulong pvblock_blk_write(struct udevice *udev, lbaint_t blknr, lbaint_t blkcnt,
41 const void *buffer)
42{
43 return 0;
44}
45
46static int pvblock_blk_bind(struct udevice *udev)
47{
Anastasiia Lukianenkoa9993132020-08-06 12:42:56 +030048 struct blk_desc *desc = dev_get_uclass_platdata(udev);
49 int devnum;
50
51 desc->if_type = IF_TYPE_PVBLOCK;
52 /*
53 * Initialize the devnum to -ENODEV. This is to make sure that
54 * blk_next_free_devnum() works as expected, since the default
55 * value 0 is a valid devnum.
56 */
57 desc->devnum = -ENODEV;
58 devnum = blk_next_free_devnum(IF_TYPE_PVBLOCK);
59 if (devnum < 0)
60 return devnum;
61 desc->devnum = devnum;
62 desc->part_type = PART_TYPE_UNKNOWN;
63 desc->bdev = udev;
64
65 strncpy(desc->vendor, "Xen", sizeof(desc->vendor));
66 strncpy(desc->revision, "1", sizeof(desc->revision));
67 strncpy(desc->product, "Virtual disk", sizeof(desc->product));
68
Anastasiia Lukianenko722bc5b2020-08-06 12:42:55 +030069 return 0;
70}
71
72static int pvblock_blk_probe(struct udevice *udev)
73{
74 struct blkfront_dev *blk_dev = dev_get_priv(udev);
Anastasiia Lukianenkoa9993132020-08-06 12:42:56 +030075 struct blkfront_platdata *platdata = dev_get_platdata(udev);
76 int ret, devid;
Anastasiia Lukianenko722bc5b2020-08-06 12:42:55 +030077
Anastasiia Lukianenkoa9993132020-08-06 12:42:56 +030078 devid = platdata->devid;
79 free(platdata);
80
81 ret = init_blkfront(devid, blk_dev);
Anastasiia Lukianenko722bc5b2020-08-06 12:42:55 +030082 if (ret < 0)
83 return ret;
84 return 0;
85}
86
87static int pvblock_blk_remove(struct udevice *udev)
88{
89 struct blkfront_dev *blk_dev = dev_get_priv(udev);
90
91 shutdown_blkfront(blk_dev);
92 return 0;
93}
94
95static const struct blk_ops pvblock_blk_ops = {
96 .read = pvblock_blk_read,
97 .write = pvblock_blk_write,
98};
99
100U_BOOT_DRIVER(pvblock_blk) = {
101 .name = DRV_NAME_BLK,
102 .id = UCLASS_BLK,
103 .ops = &pvblock_blk_ops,
104 .bind = pvblock_blk_bind,
105 .probe = pvblock_blk_probe,
106 .remove = pvblock_blk_remove,
107 .priv_auto_alloc_size = sizeof(struct blkfront_dev),
108 .flags = DM_FLAG_OS_PREPARE,
109};
110
111/*******************************************************************************
112 * Para-virtual block device class
113 *******************************************************************************/
114
Anastasiia Lukianenkoa9993132020-08-06 12:42:56 +0300115typedef int (*enum_vbd_callback)(struct udevice *parent, unsigned int devid);
116
117static int on_new_vbd(struct udevice *parent, unsigned int devid)
118{
119 struct driver_info info;
120 struct udevice *udev;
121 struct blkfront_platdata *platdata;
122 int ret;
123
124 debug("New " DRV_NAME_BLK ", device ID %d\n", devid);
125
126 platdata = malloc(sizeof(struct blkfront_platdata));
127 if (!platdata) {
128 printf("Failed to allocate platform data\n");
129 return -ENOMEM;
130 }
131
132 platdata->devid = devid;
133
134 info.name = DRV_NAME_BLK;
135 info.platdata = platdata;
136
137 ret = device_bind_by_name(parent, false, &info, &udev);
138 if (ret < 0) {
139 printf("Failed to bind " DRV_NAME_BLK " to device with ID %d, ret: %d\n",
140 devid, ret);
141 free(platdata);
142 }
143 return ret;
144}
145
146static int xenbus_enumerate_vbd(struct udevice *udev, enum_vbd_callback clb)
147{
148 char **dirs, *msg;
149 int i, ret;
150
151 msg = xenbus_ls(XBT_NIL, "device/vbd", &dirs);
152 if (msg) {
153 printf("Failed to read device/vbd directory: %s\n", msg);
154 free(msg);
155 return -ENODEV;
156 }
157
158 for (i = 0; dirs[i]; i++) {
159 int devid;
160
161 sscanf(dirs[i], "%d", &devid);
162 ret = clb(udev, devid);
163 if (ret < 0)
164 goto fail;
165
166 free(dirs[i]);
167 }
168 ret = 0;
169
170fail:
171 for (; dirs[i]; i++)
172 free(dirs[i]);
173 free(dirs);
174 return ret;
175}
176
Anastasiia Lukianenko722bc5b2020-08-06 12:42:55 +0300177void pvblock_init(void)
178{
179 struct driver_info info;
180 struct udevice *udev;
181 struct uclass *uc;
182 int ret;
183
184 /*
185 * At this point Xen drivers have already initialized,
186 * so we can instantiate the class driver and enumerate
187 * virtual block devices.
188 */
189 info.name = DRV_NAME;
190 ret = device_bind_by_name(gd->dm_root, false, &info, &udev);
191 if (ret < 0)
192 printf("Failed to bind " DRV_NAME ", ret: %d\n", ret);
193
194 /* Bootstrap virtual block devices class driver */
195 ret = uclass_get(UCLASS_PVBLOCK, &uc);
196 if (ret)
197 return;
198 uclass_foreach_dev_probe(UCLASS_PVBLOCK, udev);
199}
200
201static int pvblock_probe(struct udevice *udev)
202{
Anastasiia Lukianenkoa9993132020-08-06 12:42:56 +0300203 struct uclass *uc;
204 int ret;
205
206 if (xenbus_enumerate_vbd(udev, on_new_vbd) < 0)
207 return -ENODEV;
208
209 ret = uclass_get(UCLASS_BLK, &uc);
210 if (ret)
211 return ret;
212 uclass_foreach_dev_probe(UCLASS_BLK, udev) {
213 if (_ret)
214 return _ret;
215 };
Anastasiia Lukianenko722bc5b2020-08-06 12:42:55 +0300216 return 0;
217}
218
219U_BOOT_DRIVER(pvblock_drv) = {
220 .name = DRV_NAME,
221 .id = UCLASS_PVBLOCK,
222 .probe = pvblock_probe,
223};
224
225UCLASS_DRIVER(pvblock) = {
226 .name = DRV_NAME,
227 .id = UCLASS_PVBLOCK,
228};