blob: 2d340efd32b520492cc2ccfd20be140d8babd9a2 [file] [log] [blame]
Henrik Nordström26f9a6c2013-11-10 10:26:56 -07001/*
2 * Copyright (C) 2013 Henrik Nordstrom <henrik@henriknordstrom.net>
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
Henrik Nordström26f9a6c2013-11-10 10:26:56 -07007#include <common.h>
Simon Glass2c2075a2016-02-29 15:25:57 -07008#include <blk.h>
9#include <dm.h>
10#include <fdtdec.h>
Henrik Nordström26f9a6c2013-11-10 10:26:56 -070011#include <part.h>
12#include <os.h>
13#include <malloc.h>
14#include <sandboxblockdev.h>
15#include <asm/errno.h>
Simon Glass2c2075a2016-02-29 15:25:57 -070016#include <dm/device-internal.h>
Henrik Nordström26f9a6c2013-11-10 10:26:56 -070017
Simon Glass2c2075a2016-02-29 15:25:57 -070018DECLARE_GLOBAL_DATA_PTR;
19
Simon Glass2c2075a2016-02-29 15:25:57 -070020static 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
Simon Glass52e85ac2016-02-29 15:25:56 -070027 if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) ==
28 -1) {
29 printf("ERROR: Invalid block %lx\n", start);
Henrik Nordström26f9a6c2013-11-10 10:26:56 -070030 return -1;
31 }
Simon Glass52e85ac2016-02-29 15:25:56 -070032 ssize_t len = os_read(host_dev->fd, buffer, blkcnt * block_dev->blksz);
Henrik Nordström26f9a6c2013-11-10 10:26:56 -070033 if (len >= 0)
Simon Glass52e85ac2016-02-29 15:25:56 -070034 return len / block_dev->blksz;
Henrik Nordström26f9a6c2013-11-10 10:26:56 -070035 return -1;
36}
37
Simon Glass2c2075a2016-02-29 15:25:57 -070038static 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);
Simon Glass52e85ac2016-02-29 15:25:56 -070044
45 if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) ==
46 -1) {
47 printf("ERROR: Invalid block %lx\n", start);
Henrik Nordström26f9a6c2013-11-10 10:26:56 -070048 return -1;
49 }
Simon Glass52e85ac2016-02-29 15:25:56 -070050 ssize_t len = os_write(host_dev->fd, buffer, blkcnt * block_dev->blksz);
Henrik Nordström26f9a6c2013-11-10 10:26:56 -070051 if (len >= 0)
Simon Glass52e85ac2016-02-29 15:25:56 -070052 return len / block_dev->blksz;
Henrik Nordström26f9a6c2013-11-10 10:26:56 -070053 return -1;
54}
55
Simon Glass2c2075a2016-02-29 15:25:57 -070056int 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);
111err_file:
112 os_close(fd);
113err:
114 free(fname);
115 free(str);
116 return ret;
117}
Henrik Nordström26f9a6c2013-11-10 10:26:56 -0700118
Simon Glass52e85ac2016-02-29 15:25:56 -0700119int host_get_dev_err(int devnum, struct blk_desc **blk_devp)
Henrik Nordström26f9a6c2013-11-10 10:26:56 -0700120{
Simon Glass2c2075a2016-02-29 15:25:57 -0700121 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);
Simon Glass2c2075a2016-02-29 15:25:57 -0700128
Henrik Nordström26f9a6c2013-11-10 10:26:56 -0700129 return 0;
130}
131
Simon Glasse3394752016-02-29 15:25:34 -0700132struct blk_desc *host_get_dev(int dev)
Henrik Nordström26f9a6c2013-11-10 10:26:56 -0700133{
Simon Glasse3394752016-02-29 15:25:34 -0700134 struct blk_desc *blk_dev;
Henrik Nordström26f9a6c2013-11-10 10:26:56 -0700135
136 if (host_get_dev_err(dev, &blk_dev))
137 return NULL;
138
139 return blk_dev;
140}
Simon Glass2c2075a2016-02-29 15:25:57 -0700141
Simon Glass2c2075a2016-02-29 15:25:57 -0700142static const struct blk_ops sandbox_host_blk_ops = {
143 .read = host_block_read,
144 .write = host_block_write,
145};
146
147U_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};