1f4d8de48SHenrik Nordström /* 2f4d8de48SHenrik Nordström * Copyright (C) 2013 Henrik Nordstrom <henrik@henriknordstrom.net> 3f4d8de48SHenrik Nordström * 4f4d8de48SHenrik Nordström * SPDX-License-Identifier: GPL-2.0+ 5f4d8de48SHenrik Nordström */ 6f4d8de48SHenrik Nordström 7f4d8de48SHenrik Nordström #include <common.h> 840fd0508SSimon Glass #include <blk.h> 940fd0508SSimon Glass #include <dm.h> 1040fd0508SSimon Glass #include <fdtdec.h> 11f4d8de48SHenrik Nordström #include <part.h> 12f4d8de48SHenrik Nordström #include <os.h> 13f4d8de48SHenrik Nordström #include <malloc.h> 14f4d8de48SHenrik Nordström #include <sandboxblockdev.h> 151221ce45SMasahiro Yamada #include <linux/errno.h> 1640fd0508SSimon Glass #include <dm/device-internal.h> 17f4d8de48SHenrik Nordström 1840fd0508SSimon Glass DECLARE_GLOBAL_DATA_PTR; 1940fd0508SSimon Glass 20e161356bSSimon Glass #ifndef CONFIG_BLK 21e161356bSSimon Glass static struct host_block_dev host_devices[CONFIG_HOST_MAX_DEVICES]; 22e161356bSSimon Glass 23e161356bSSimon Glass static struct host_block_dev *find_host_device(int dev) 24e161356bSSimon Glass { 25e161356bSSimon Glass if (dev >= 0 && dev < CONFIG_HOST_MAX_DEVICES) 26e161356bSSimon Glass return &host_devices[dev]; 27e161356bSSimon Glass 28e161356bSSimon Glass return NULL; 29e161356bSSimon Glass } 30e161356bSSimon Glass #endif 31e161356bSSimon Glass 32e161356bSSimon Glass #ifdef CONFIG_BLK 3340fd0508SSimon Glass static unsigned long host_block_read(struct udevice *dev, 3440fd0508SSimon Glass unsigned long start, lbaint_t blkcnt, 3540fd0508SSimon Glass void *buffer) 3640fd0508SSimon Glass { 3740fd0508SSimon Glass struct host_block_dev *host_dev = dev_get_priv(dev); 3840fd0508SSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 3940fd0508SSimon Glass 40e161356bSSimon Glass #else 41e161356bSSimon Glass static unsigned long host_block_read(struct blk_desc *block_dev, 42e161356bSSimon Glass unsigned long start, lbaint_t blkcnt, 43e161356bSSimon Glass void *buffer) 44e161356bSSimon Glass { 45e161356bSSimon Glass int dev = block_dev->devnum; 46e161356bSSimon Glass struct host_block_dev *host_dev = find_host_device(dev); 47e161356bSSimon Glass 48e161356bSSimon Glass if (!host_dev) 49e161356bSSimon Glass return -1; 50e161356bSSimon Glass #endif 51e161356bSSimon Glass 527ded959eSSimon Glass if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) == 537ded959eSSimon Glass -1) { 547ded959eSSimon Glass printf("ERROR: Invalid block %lx\n", start); 55f4d8de48SHenrik Nordström return -1; 56f4d8de48SHenrik Nordström } 577ded959eSSimon Glass ssize_t len = os_read(host_dev->fd, buffer, blkcnt * block_dev->blksz); 58f4d8de48SHenrik Nordström if (len >= 0) 597ded959eSSimon Glass return len / block_dev->blksz; 60f4d8de48SHenrik Nordström return -1; 61f4d8de48SHenrik Nordström } 62f4d8de48SHenrik Nordström 63e161356bSSimon Glass #ifdef CONFIG_BLK 6440fd0508SSimon Glass static unsigned long host_block_write(struct udevice *dev, 6540fd0508SSimon Glass unsigned long start, lbaint_t blkcnt, 6640fd0508SSimon Glass const void *buffer) 6740fd0508SSimon Glass { 6840fd0508SSimon Glass struct host_block_dev *host_dev = dev_get_priv(dev); 6940fd0508SSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 70e161356bSSimon Glass #else 71e161356bSSimon Glass static unsigned long host_block_write(struct blk_desc *block_dev, 72e161356bSSimon Glass unsigned long start, lbaint_t blkcnt, 73e161356bSSimon Glass const void *buffer) 74e161356bSSimon Glass { 75e161356bSSimon Glass int dev = block_dev->devnum; 76e161356bSSimon Glass struct host_block_dev *host_dev = find_host_device(dev); 77e161356bSSimon Glass #endif 787ded959eSSimon Glass 797ded959eSSimon Glass if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) == 807ded959eSSimon Glass -1) { 817ded959eSSimon Glass printf("ERROR: Invalid block %lx\n", start); 82f4d8de48SHenrik Nordström return -1; 83f4d8de48SHenrik Nordström } 847ded959eSSimon Glass ssize_t len = os_write(host_dev->fd, buffer, blkcnt * block_dev->blksz); 85f4d8de48SHenrik Nordström if (len >= 0) 867ded959eSSimon Glass return len / block_dev->blksz; 87f4d8de48SHenrik Nordström return -1; 88f4d8de48SHenrik Nordström } 89f4d8de48SHenrik Nordström 90e161356bSSimon Glass #ifdef CONFIG_BLK 9140fd0508SSimon Glass int host_dev_bind(int devnum, char *filename) 9240fd0508SSimon Glass { 9340fd0508SSimon Glass struct host_block_dev *host_dev; 9440fd0508SSimon Glass struct udevice *dev; 9540fd0508SSimon Glass char dev_name[20], *str, *fname; 9640fd0508SSimon Glass int ret, fd; 9740fd0508SSimon Glass 9840fd0508SSimon Glass /* Remove and unbind the old device, if any */ 9940fd0508SSimon Glass ret = blk_get_device(IF_TYPE_HOST, devnum, &dev); 10040fd0508SSimon Glass if (ret == 0) { 101*706865afSStefan Roese ret = device_remove(dev, DM_REMOVE_NORMAL); 10240fd0508SSimon Glass if (ret) 10340fd0508SSimon Glass return ret; 10440fd0508SSimon Glass ret = device_unbind(dev); 10540fd0508SSimon Glass if (ret) 10640fd0508SSimon Glass return ret; 10740fd0508SSimon Glass } else if (ret != -ENODEV) { 10840fd0508SSimon Glass return ret; 10940fd0508SSimon Glass } 11040fd0508SSimon Glass 11140fd0508SSimon Glass if (!filename) 11240fd0508SSimon Glass return 0; 11340fd0508SSimon Glass 11440fd0508SSimon Glass snprintf(dev_name, sizeof(dev_name), "host%d", devnum); 11540fd0508SSimon Glass str = strdup(dev_name); 11640fd0508SSimon Glass if (!str) 11740fd0508SSimon Glass return -ENOMEM; 11840fd0508SSimon Glass fname = strdup(filename); 11940fd0508SSimon Glass if (!fname) { 12040fd0508SSimon Glass free(str); 12140fd0508SSimon Glass return -ENOMEM; 12240fd0508SSimon Glass } 12340fd0508SSimon Glass 12440fd0508SSimon Glass fd = os_open(filename, OS_O_RDWR); 12540fd0508SSimon Glass if (fd == -1) { 12640fd0508SSimon Glass printf("Failed to access host backing file '%s'\n", filename); 12740fd0508SSimon Glass ret = -ENOENT; 12840fd0508SSimon Glass goto err; 12940fd0508SSimon Glass } 13040fd0508SSimon Glass ret = blk_create_device(gd->dm_root, "sandbox_host_blk", str, 13140fd0508SSimon Glass IF_TYPE_HOST, devnum, 512, 13240fd0508SSimon Glass os_lseek(fd, 0, OS_SEEK_END), &dev); 13340fd0508SSimon Glass if (ret) 13440fd0508SSimon Glass goto err_file; 13540fd0508SSimon Glass ret = device_probe(dev); 13640fd0508SSimon Glass if (ret) { 13740fd0508SSimon Glass device_unbind(dev); 13840fd0508SSimon Glass goto err_file; 13940fd0508SSimon Glass } 14040fd0508SSimon Glass 14140fd0508SSimon Glass host_dev = dev_get_priv(dev); 14240fd0508SSimon Glass host_dev->fd = fd; 14340fd0508SSimon Glass host_dev->filename = fname; 14440fd0508SSimon Glass 14540fd0508SSimon Glass return blk_prepare_device(dev); 14640fd0508SSimon Glass err_file: 14740fd0508SSimon Glass os_close(fd); 14840fd0508SSimon Glass err: 14940fd0508SSimon Glass free(fname); 15040fd0508SSimon Glass free(str); 15140fd0508SSimon Glass return ret; 15240fd0508SSimon Glass } 153e161356bSSimon Glass #else 154e161356bSSimon Glass int host_dev_bind(int dev, char *filename) 155e161356bSSimon Glass { 156e161356bSSimon Glass struct host_block_dev *host_dev = find_host_device(dev); 157e161356bSSimon Glass 158e161356bSSimon Glass if (!host_dev) 159e161356bSSimon Glass return -1; 160e161356bSSimon Glass if (host_dev->blk_dev.priv) { 161e161356bSSimon Glass os_close(host_dev->fd); 162e161356bSSimon Glass host_dev->blk_dev.priv = NULL; 163e161356bSSimon Glass } 164e161356bSSimon Glass if (host_dev->filename) 165e161356bSSimon Glass free(host_dev->filename); 166e161356bSSimon Glass if (filename && *filename) { 167e161356bSSimon Glass host_dev->filename = strdup(filename); 168e161356bSSimon Glass } else { 169e161356bSSimon Glass host_dev->filename = NULL; 170e161356bSSimon Glass return 0; 171e161356bSSimon Glass } 172e161356bSSimon Glass 173e161356bSSimon Glass host_dev->fd = os_open(host_dev->filename, OS_O_RDWR); 174e161356bSSimon Glass if (host_dev->fd == -1) { 175e161356bSSimon Glass printf("Failed to access host backing file '%s'\n", 176e161356bSSimon Glass host_dev->filename); 177e161356bSSimon Glass return 1; 178e161356bSSimon Glass } 179e161356bSSimon Glass 180e161356bSSimon Glass struct blk_desc *blk_dev = &host_dev->blk_dev; 181e161356bSSimon Glass blk_dev->if_type = IF_TYPE_HOST; 182e161356bSSimon Glass blk_dev->priv = host_dev; 183e161356bSSimon Glass blk_dev->blksz = 512; 184e161356bSSimon Glass blk_dev->lba = os_lseek(host_dev->fd, 0, OS_SEEK_END) / blk_dev->blksz; 185e161356bSSimon Glass blk_dev->block_read = host_block_read; 186e161356bSSimon Glass blk_dev->block_write = host_block_write; 187e161356bSSimon Glass blk_dev->devnum = dev; 188e161356bSSimon Glass blk_dev->part_type = PART_TYPE_UNKNOWN; 189e161356bSSimon Glass part_init(blk_dev); 190e161356bSSimon Glass 191e161356bSSimon Glass return 0; 192e161356bSSimon Glass } 193e161356bSSimon Glass #endif 194f4d8de48SHenrik Nordström 1957ded959eSSimon Glass int host_get_dev_err(int devnum, struct blk_desc **blk_devp) 196f4d8de48SHenrik Nordström { 197e161356bSSimon Glass #ifdef CONFIG_BLK 19840fd0508SSimon Glass struct udevice *dev; 19940fd0508SSimon Glass int ret; 20040fd0508SSimon Glass 20140fd0508SSimon Glass ret = blk_get_device(IF_TYPE_HOST, devnum, &dev); 20240fd0508SSimon Glass if (ret) 20340fd0508SSimon Glass return ret; 20440fd0508SSimon Glass *blk_devp = dev_get_uclass_platdata(dev); 205e161356bSSimon Glass #else 206e161356bSSimon Glass struct host_block_dev *host_dev = find_host_device(devnum); 207e161356bSSimon Glass 208e161356bSSimon Glass if (!host_dev) 209e161356bSSimon Glass return -ENODEV; 210e161356bSSimon Glass 211e161356bSSimon Glass if (!host_dev->blk_dev.priv) 212e161356bSSimon Glass return -ENOENT; 213e161356bSSimon Glass 214e161356bSSimon Glass *blk_devp = &host_dev->blk_dev; 215e161356bSSimon Glass #endif 21640fd0508SSimon Glass 217f4d8de48SHenrik Nordström return 0; 218f4d8de48SHenrik Nordström } 219f4d8de48SHenrik Nordström 220e161356bSSimon Glass #ifdef CONFIG_BLK 22140fd0508SSimon Glass static const struct blk_ops sandbox_host_blk_ops = { 22240fd0508SSimon Glass .read = host_block_read, 22340fd0508SSimon Glass .write = host_block_write, 22440fd0508SSimon Glass }; 22540fd0508SSimon Glass 22640fd0508SSimon Glass U_BOOT_DRIVER(sandbox_host_blk) = { 22740fd0508SSimon Glass .name = "sandbox_host_blk", 22840fd0508SSimon Glass .id = UCLASS_BLK, 22940fd0508SSimon Glass .ops = &sandbox_host_blk_ops, 23040fd0508SSimon Glass .priv_auto_alloc_size = sizeof(struct host_block_dev), 23140fd0508SSimon Glass }; 2320cc65a7cSSimon Glass #else 2330cc65a7cSSimon Glass U_BOOT_LEGACY_BLK(sandbox_host) = { 2340cc65a7cSSimon Glass .if_typename = "host", 2350cc65a7cSSimon Glass .if_type = IF_TYPE_HOST, 2360cc65a7cSSimon Glass .max_devs = CONFIG_HOST_MAX_DEVICES, 2370cc65a7cSSimon Glass .get_dev = host_get_dev_err, 2380cc65a7cSSimon Glass }; 239e161356bSSimon Glass #endif 240