1// 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 = dectoul(argv[5], &unit); 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 * 1024 * 1024; 59 break; 60 case 'm': 61 case 'M': 62 requested *= 1024 * 1024; 63 break; 64 case 'k': 65 case 'K': 66 requested *= 1024; 67 break; 68 } 69 } 70 printf("Copying %ld bytes from %s:%s to %s:%s\n", 71 requested, argv[1], argv[2], argv[3], argv[4]); 72 wrcnt = 0; 73 rdcnt = 0; 74 buf = (char *)malloc(BUFSIZE); 75 srcblk = 0; 76 destblk = 0; 77 timer = get_timer(0); 78 while (wrcnt < requested) { 79 unsigned long toread = BUFSIZE / srcbz; 80 unsigned long towrite = BUFSIZE / destbz; 81 unsigned long offset = 0; 82 83read: 84 ret = blk_dread(srcdesc, srcblk, toread, buf + offset); 85 if (ret < 0) { 86 printf("Src read error @blk %ld\n", srcblk); 87 goto exit; 88 } 89 rdcnt += ret * srcbz; 90 srcblk += ret; 91 if (ret < toread) { 92 toread -= ret; 93 offset += ret * srcbz; 94 goto read; 95 } 96 offset = 0; 97write: 98 ret = blk_dwrite(destdesc, destblk, towrite, buf + offset); 99 if (ret < 0) { 100 printf("Dest write error @blk %ld\n", srcblk); 101 goto exit; 102 } 103 wrcnt += ret * destbz; 104 destblk += ret; 105 if (ret < towrite) { 106 towrite -= ret; 107 offset += ret * destbz; 108 goto write; 109 } 110 } 111 112exit: 113 timer = get_timer(timer); 114 timer = 1000 * timer / CONFIG_SYS_HZ; 115 printf("%ld read\n", rdcnt); 116 printf("%ld written\n", wrcnt); 117 printf("%ldms, %ldkB/s\n", timer, wrcnt / timer); 118 free(buf); 119 120 return 0; 121} 122 123U_BOOT_CMD( 124 clone, 6, 1, do_clone, 125 "simple storage cloning", 126 "<src interface> <src dev> <dest interface> <dest dev> <size[K/M/G]>\n" 127 "clone storage from 'src dev' on 'src interface' to 'dest dev' on 'dest interface' with maximum 'size' bytes (or 0 for clone to end)" 128); 129