xref: /openbmc/u-boot/drivers/block/sandbox.c (revision 9ecb0c41)
1 /*
2  * Copyright (C) 2013 Henrik Nordstrom <henrik@henriknordstrom.net>
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <blk.h>
9 #include <dm.h>
10 #include <fdtdec.h>
11 #include <part.h>
12 #include <os.h>
13 #include <malloc.h>
14 #include <sandboxblockdev.h>
15 #include <asm/errno.h>
16 #include <dm/device-internal.h>
17 
18 DECLARE_GLOBAL_DATA_PTR;
19 
20 static unsigned long host_block_read(struct udevice *dev,
21 				     unsigned long start, lbaint_t blkcnt,
22 				     void *buffer)
23 {
24 	struct host_block_dev *host_dev = dev_get_priv(dev);
25 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
26 
27 	if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) ==
28 			-1) {
29 		printf("ERROR: Invalid block %lx\n", start);
30 		return -1;
31 	}
32 	ssize_t len = os_read(host_dev->fd, buffer, blkcnt * block_dev->blksz);
33 	if (len >= 0)
34 		return len / block_dev->blksz;
35 	return -1;
36 }
37 
38 static unsigned long host_block_write(struct udevice *dev,
39 				      unsigned long start, lbaint_t blkcnt,
40 				      const void *buffer)
41 {
42 	struct host_block_dev *host_dev = dev_get_priv(dev);
43 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
44 
45 	if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) ==
46 			-1) {
47 		printf("ERROR: Invalid block %lx\n", start);
48 		return -1;
49 	}
50 	ssize_t len = os_write(host_dev->fd, buffer, blkcnt * block_dev->blksz);
51 	if (len >= 0)
52 		return len / block_dev->blksz;
53 	return -1;
54 }
55 
56 int host_dev_bind(int devnum, char *filename)
57 {
58 	struct host_block_dev *host_dev;
59 	struct udevice *dev;
60 	char dev_name[20], *str, *fname;
61 	int ret, fd;
62 
63 	/* Remove and unbind the old device, if any */
64 	ret = blk_get_device(IF_TYPE_HOST, devnum, &dev);
65 	if (ret == 0) {
66 		ret = device_remove(dev);
67 		if (ret)
68 			return ret;
69 		ret = device_unbind(dev);
70 		if (ret)
71 			return ret;
72 	} else if (ret != -ENODEV) {
73 		return ret;
74 	}
75 
76 	if (!filename)
77 		return 0;
78 
79 	snprintf(dev_name, sizeof(dev_name), "host%d", devnum);
80 	str = strdup(dev_name);
81 	if (!str)
82 		return -ENOMEM;
83 	fname = strdup(filename);
84 	if (!fname) {
85 		free(str);
86 		return -ENOMEM;
87 	}
88 
89 	fd = os_open(filename, OS_O_RDWR);
90 	if (fd == -1) {
91 		printf("Failed to access host backing file '%s'\n", filename);
92 		ret = -ENOENT;
93 		goto err;
94 	}
95 	ret = blk_create_device(gd->dm_root, "sandbox_host_blk", str,
96 				IF_TYPE_HOST, devnum, 512,
97 				os_lseek(fd, 0, OS_SEEK_END), &dev);
98 	if (ret)
99 		goto err_file;
100 	ret = device_probe(dev);
101 	if (ret) {
102 		device_unbind(dev);
103 		goto err_file;
104 	}
105 
106 	host_dev = dev_get_priv(dev);
107 	host_dev->fd = fd;
108 	host_dev->filename = fname;
109 
110 	return blk_prepare_device(dev);
111 err_file:
112 	os_close(fd);
113 err:
114 	free(fname);
115 	free(str);
116 	return ret;
117 }
118 
119 int host_get_dev_err(int devnum, struct blk_desc **blk_devp)
120 {
121 	struct udevice *dev;
122 	int ret;
123 
124 	ret = blk_get_device(IF_TYPE_HOST, devnum, &dev);
125 	if (ret)
126 		return ret;
127 	*blk_devp = dev_get_uclass_platdata(dev);
128 
129 	return 0;
130 }
131 
132 struct blk_desc *host_get_dev(int dev)
133 {
134 	struct blk_desc *blk_dev;
135 
136 	if (host_get_dev_err(dev, &blk_dev))
137 		return NULL;
138 
139 	return blk_dev;
140 }
141 
142 static const struct blk_ops sandbox_host_blk_ops = {
143 	.read	= host_block_read,
144 	.write	= host_block_write,
145 };
146 
147 U_BOOT_DRIVER(sandbox_host_blk) = {
148 	.name		= "sandbox_host_blk",
149 	.id		= UCLASS_BLK,
150 	.ops		= &sandbox_host_blk_ops,
151 	.priv_auto_alloc_size	= sizeof(struct host_block_dev),
152 };
153