blob: 97747f8f080857e22cd8949280e7286192adf7f9 [file] [log] [blame]
John Chau4a4830c2020-07-02 12:01:21 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2020 John Chau <john@harmon.hk>
4 *
5 */
6
7#include <common.h>
8#include <command.h>
9#include <malloc.h>
10#include <part.h>
11#include <blk.h>
12#include <vsprintf.h>
13
14#define BUFSIZE (1 * 1024 * 1024)
15static int do_clone(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
16{
17 int srcdev, destdev;
18 struct blk_desc *srcdesc, *destdesc;
19 int srcbz, destbz, ret;
20 char *unit, *buf;
21 unsigned long wrcnt, rdcnt, requested, srcblk, destblk;
22 unsigned long timer;
23 const unsigned long buffersize = 1024 * 1024;
24
25 if (argc < 6)
26 return CMD_RET_USAGE;
27
28 srcdev = blk_get_device_by_str(argv[1], argv[2], &srcdesc);
29 destdev = blk_get_device_by_str(argv[3], argv[4], &destdesc);
30 if (srcdev < 0) {
31 printf("Unable to open source device\n");
32 return 1;
33 } else if (destdev < 0) {
34 printf("Unable to open destination device\n");
35 return 1;
36 }
37 requested = simple_strtoul(argv[5], &unit, 10);
38 srcbz = srcdesc->blksz;
39 destbz = destdesc->blksz;
40
41 if ((srcbz * (buffersize / srcbz) != buffersize) &&
42 (destbz * (buffersize / destbz) != buffersize)) {
43 printf("failed: cannot match device block sizes\n");
44 return 1;
45 }
46 if (requested == 0) {
47 unsigned long a = srcdesc->lba * srcdesc->blksz;
48 unsigned long b = destdesc->lba * destdesc->blksz;
49
50 if (a > b)
51 requested = a;
52 else
53 requested = b;
54 } else {
55 switch (unit[0]) {
56 case 'g':
57 case 'G':
58 requested *= 1024;
59 case 'm':
60 case 'M':
61 requested *= 1024;
62 case 'k':
63 case 'K':
64 requested *= 1024;
65 break;
66 }
67 }
68 printf("Copying %ld bytes from %s:%s to %s:%s\n",
69 requested, argv[1], argv[2], argv[3], argv[4]);
70 wrcnt = 0;
71 rdcnt = 0;
72 buf = (char *)malloc(BUFSIZE);
73 srcblk = 0;
74 destblk = 0;
75 timer = get_timer(0);
76 while (wrcnt < requested) {
77 unsigned long toread = BUFSIZE / srcbz;
78 unsigned long towrite = BUFSIZE / destbz;
79 unsigned long offset = 0;
80
81read:
82 ret = blk_dread(srcdesc, srcblk, toread, buf + offset);
83 if (ret < 0) {
84 printf("Src read error @blk %ld\n", srcblk);
85 goto exit;
86 }
87 rdcnt += ret * srcbz;
88 srcblk += ret;
89 if (ret < toread) {
90 toread -= ret;
91 offset += ret * srcbz;
92 goto read;
93 }
94 offset = 0;
95write:
96 ret = blk_dwrite(destdesc, destblk, towrite, buf + offset);
97 if (ret < 0) {
98 printf("Dest write error @blk %ld\n", srcblk);
99 goto exit;
100 }
101 wrcnt += ret * destbz;
102 destblk += ret;
103 if (ret < towrite) {
104 towrite -= ret;
105 offset += ret * destbz;
106 goto write;
107 }
108 }
109
110exit:
111 timer = get_timer(timer);
112 timer = 1000 * timer / CONFIG_SYS_HZ;
113 printf("%ld read\n", rdcnt);
114 printf("%ld written\n", wrcnt);
115 printf("%ldms, %ldkB/s\n", timer, wrcnt / timer);
116 free(buf);
117
118 return 0;
119}
120
121U_BOOT_CMD(
122 clone, 6, 1, do_clone,
123 "simple storage cloning",
124 "<src interface> <src dev> <dest interface> <dest dev> <size[K/M/G]>\n"
125 "clone storage from 'src dev' on 'src interface' to 'dest dev' on 'dest interface' with maximum 'size' bytes (or 0 for clone to end)"
126);