summaryrefslogtreecommitdiff
path: root/api
diff options
context:
space:
mode:
authorCristian Ciocaltea <cristian.ciocaltea@gmail.com>2019-01-12 02:03:15 +0200
committerTom Rini <trini@konsulko.com>2019-11-07 17:58:31 -0500
commit036218a67130343a71ea34aeae1231bc11f040c2 (patch)
tree600e9b8b408872167ee05626fa7046b4df4a4371 /api
parent0be2ecd4861faa410491170e205488f9ee82a227 (diff)
api: storage: Add the missing write operation support
API_dev_write(va_list ap) is currently lacking the write support to storage devices because, historically, those devices did not implement block_write() The solution has been tested by loading and booting a (patched) GRUB instance in a QEMU vexpress-a9 environment. The disk write operations were triggered with GRUB's save_env command. Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
Diffstat (limited to 'api')
-rw-r--r--api/api.c59
-rw-r--r--api/api_private.h1
-rw-r--r--api/api_storage.c24
3 files changed, 63 insertions, 21 deletions
diff --git a/api/api.c b/api/api.c
index bc9454eb4b..71fa03804e 100644
--- a/api/api.c
+++ b/api/api.c
@@ -295,27 +295,31 @@ static int API_dev_close(va_list ap)
/*
- * Notice: this is for sending network packets only, as U-Boot does not
- * support writing to storage at the moment (12.2007)
- *
* pseudo signature:
*
* int API_dev_write(
* struct device_info *di,
* void *buf,
- * int *len
+ * int *len,
+ * unsigned long *start
* )
*
* buf: ptr to buffer from where to get the data to send
*
- * len: length of packet to be sent (in bytes)
+ * len: ptr to length to be read
+ * - network: len of packet to be sent (in bytes)
+ * - storage: # of blocks to write (can vary in size depending on define)
*
+ * start: ptr to start block (only used for storage devices, ignored for
+ * network)
*/
static int API_dev_write(va_list ap)
{
struct device_info *di;
void *buf;
- int *len;
+ lbasize_t *len_stor, act_len_stor;
+ lbastart_t *start;
+ int *len_net;
int err = 0;
/* 1. arg is ptr to the device_info struct */
@@ -333,23 +337,36 @@ static int API_dev_write(va_list ap)
if (buf == NULL)
return API_EINVAL;
- /* 3. arg is length of buffer */
- len = (int *)va_arg(ap, uintptr_t);
- if (len == NULL)
- return API_EINVAL;
- if (*len <= 0)
- return API_EINVAL;
+ if (di->type & DEV_TYP_STOR) {
+ /* 3. arg - ptr to var with # of blocks to write */
+ len_stor = (lbasize_t *)va_arg(ap, uintptr_t);
+ if (!len_stor)
+ return API_EINVAL;
+ if (*len_stor <= 0)
+ return API_EINVAL;
- if (di->type & DEV_TYP_STOR)
- /*
- * write to storage is currently not supported by U-Boot:
- * no storage device implements block_write() method
- */
- return API_ENODEV;
+ /* 4. arg - ptr to var with start block */
+ start = (lbastart_t *)va_arg(ap, uintptr_t);
- else if (di->type & DEV_TYP_NET)
- err = dev_write_net(di->cookie, buf, *len);
- else
+ act_len_stor = dev_write_stor(di->cookie, buf, *len_stor, *start);
+ if (act_len_stor != *len_stor) {
+ debugf("write @ %llu: done %llu out of %llu blocks",
+ (uint64_t)blk, (uint64_t)act_len_stor,
+ (uint64_t)len_stor);
+ return API_EIO;
+ }
+
+ } else if (di->type & DEV_TYP_NET) {
+ /* 3. arg points to the var with length of packet to write */
+ len_net = (int *)va_arg(ap, uintptr_t);
+ if (!len_net)
+ return API_EINVAL;
+ if (*len_net <= 0)
+ return API_EINVAL;
+
+ err = dev_write_net(di->cookie, buf, *len_net);
+
+ } else
err = API_ENODEV;
return err;
diff --git a/api/api_private.h b/api/api_private.h
index 8d97ca95a2..07fd50ad3a 100644
--- a/api/api_private.h
+++ b/api/api_private.h
@@ -22,6 +22,7 @@ int dev_close_stor(void *);
int dev_close_net(void *);
lbasize_t dev_read_stor(void *, void *, lbasize_t, lbastart_t);
+lbasize_t dev_write_stor(void *, void *, lbasize_t, lbastart_t);
int dev_read_net(void *, void *, int);
int dev_write_net(void *, void *, int);
diff --git a/api/api_storage.c b/api/api_storage.c
index 2b90c18aae..7ae03ac230 100644
--- a/api/api_storage.c
+++ b/api/api_storage.c
@@ -349,3 +349,27 @@ lbasize_t dev_read_stor(void *cookie, void *buf, lbasize_t len, lbastart_t start
return dd->block_read(dd, start, len, buf);
#endif /* defined(CONFIG_BLK) */
}
+
+
+lbasize_t dev_write_stor(void *cookie, void *buf, lbasize_t len, lbastart_t start)
+{
+ struct blk_desc *dd = (struct blk_desc *)cookie;
+ int type = dev_stor_type(dd);
+
+ if (type == ENUM_MAX)
+ return 0;
+
+ if (!dev_stor_is_valid(type, dd))
+ return 0;
+
+#ifdef CONFIG_BLK
+ return blk_dwrite(dd, start, len, buf);
+#else
+ if (dd->block_write == NULL) {
+ debugf("no block_write() for device 0x%08x\n", cookie);
+ return 0;
+ }
+
+ return dd->block_write(dd, start, len, buf);
+#endif /* defined(CONFIG_BLK) */
+}