blob: 9160eaa6751160f2d6896c3dc05a83d392bbaca8 [file] [log] [blame]
/*
* Copyright (C) 2011 Google, Inc.
*
* Derived from cmd_sata.c, which is:
* Copyright (C) 2000-2005, DENX Software Engineering
* Wolfgang Denk <wd@denx.de>
* Copyright (C) Procsys. All rights reserved.
* Mushtaq Khan <mushtaq_k@procsys.com>
* <mushtaqk_921@yahoo.co.in>
* Copyright (C) 2008 Freescale Semiconductor, Inc.
* Dave Liu <daveliu@freescale.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <command.h>
#include <part.h>
static char blk_curr_name[80];
static block_dev_desc_t *blk_curr_dev;
static int parse_hex_val(char *arg, ulong *val)
{
char *ep;
*val = simple_strtoul(arg, &ep, 16);
if (ep == arg || *ep != '\0')
return -1; /* Fail */
else
return 0; /* Success */
}
int do_blk(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
block_dev_desc_t *dev;
disk_partition_t ptn;
ulong addr;
lbaint_t blk, cnt, blks_done;
int err, is_erase = 0, is_read = 0, is_write = 0;
/*
* All of our commands are of the form "blk <action>" followed by
* parameters. For convenience, convert argc and argv into
* num_parms and parms. For clarity, if num_parms==1, parms[0] is
* the only valid parameter.
*/
const char *action = argv[1];
int num_parm = argc - 2;
char **parm = (char **)argv + 2;
if (num_parm < 0)
return cmd_usage(cmdtp);
if (!strncmp(action, "dev", 3)) {
switch (num_parm) {
case 0:
if (!blk_curr_dev) {
puts("No current block device\n");
return 1;
}
break;
case 1:
dev = get_dev_by_name(parm[0]);
if (dev == NULL) {
puts("Unknown device\n");
return 1;
}
strncpy(blk_curr_name, parm[0],
sizeof(blk_curr_name) - 1);
blk_curr_name[sizeof(blk_curr_name) - 1] = '\0';
blk_curr_dev = dev;
/* Set the partition type for our new device. */
init_part(blk_curr_dev);
break;
default:
puts("usage: blk device [dev]\n");
return 1;
}
printf("Block Device %s:\n", blk_curr_name);
dev_print(blk_curr_dev);
if (num_parm == 1)
puts("... is now current device\n");
return 0;
}
if (!strncmp(action, "part", 4)) {
switch (num_parm) {
case 0:
if (!blk_curr_dev) {
puts("No current block device\n");
return 1;
}
dev = blk_curr_dev;
break;
case 1:
dev = get_dev_by_name(parm[0]);
if (dev == NULL) {
puts("Unknown device\n");
return 1;
}
break;
default:
puts("usage: blk partition [dev]\n");
return 1;
}
init_part(dev);
print_part(dev);
return 0;
}
if (!strcmp(action, "erase"))
is_erase = 1;
else if (!strcmp(action, "read"))
is_read = 1;
else if (!strcmp(action, "write"))
is_write = 1;
else
return cmd_usage(cmdtp);
/*
* At this point, we know we have either returned with a usage error,
* returned after handling a "dev" or "part" command, or we have an
* "erase", "read" or "write" command.
*/
if (!blk_curr_dev) {
puts("No current block device\n");
return 1;
}
if (is_erase) {
/* Need blk#/partition and optional count. */
if (num_parm < 1 || num_parm > 2) {
puts("usage: blk erase blk# cnt\n");
puts(" or: blk erase partition [cnt]\n");
return 1;
}
} else {
/* Need address, blk#/partition and optional count. */
if (num_parm < 2 || num_parm > 3
|| parse_hex_val(parm[0], &addr)) {
printf("usage: blk %s addr blk# cnt\n", action);
printf(" or: blk %s addr partition [cnt]\n", action);
return 1;
}
/* Advance parm so parm[0] is offset and parm[1] is count. */
parm++;
num_parm--;
}
if (!parse_hex_val(parm[0], &blk)) {
/* We successfully parsed the parameter as an integer. */
if (num_parm != 2) {
printf("Missing cnt parameter\n");
return 1;
}
if (parse_hex_val(parm[1], &cnt)) {
printf("Invalid cnt parameter: %s\n", parm[1]);
return 1;
}
printf("Block %s: device %s block # 0x%lX, count 0x%lX ...\n",
action, blk_curr_name, blk, cnt);
if (is_erase)
blks_done = blk_curr_dev->block_erase(blk_curr_dev->dev,
blk, cnt);
else if (is_read) {
blks_done = blk_curr_dev->block_read(blk_curr_dev->dev,
blk, cnt, (void *)addr);
/* flush cache after read */
flush_cache(addr, cnt * blk_curr_dev->blksz);
} else
blks_done = blk_curr_dev->block_write(blk_curr_dev->dev,
blk, cnt, (void *)addr);
printf("0x%lX blocks %s: %s\n", blks_done, action,
(blks_done == cnt) ? "OK" : "ERROR");
return (blks_done == cnt) ? 0 : 1;
}
if (get_partition_by_name(blk_curr_dev, parm[0], &ptn)) {
printf("\"%s\" is neither a partition nor a "
"block number.\n", parm[0]);
return 1;
}
/* We successfully parsed the parameter as a partition name. */
if (num_parm > 1) {
if (parse_hex_val(parm[1], &cnt)) {
printf("Invalid cnt parameter: %s\n", parm[1]);
return 1;
}
} else
cnt = ptn.size;
printf("Block %s: device %s block # 0x%lX, count 0x%lX ...\n",
action, blk_curr_name, ptn.start, cnt);
if (is_erase)
err = partition_erase_blks(blk_curr_dev, &ptn, &cnt);
else if (is_read) {
err = partition_read_blks(blk_curr_dev, &ptn,
&cnt, (void *)addr);
/* flush cache after read */
flush_cache(addr, cnt * blk_curr_dev->blksz);
} else
err = partition_write_blks(blk_curr_dev, &ptn,
&cnt, (void *)addr);
if (err) {
printf("0x%lX blocks %s: ERROR=%d\n", cnt, action, err);
return 1;
}
printf("0x%lX blocks %s: OK\n", cnt, action);
return 0;
}
U_BOOT_CMD(
blk, 5, 0, do_blk,
"Block Device sub system",
"device [dev] - show or set current device\n"
"blk partition [dev] - print partition table\n"
"blk erase blk# cnt\n"
"blk erase partition [cnt]\n"
"blk read addr blk# cnt\n"
"blk read addr partition [cnt]\n"
"blk write addr blk# cnt\n"
"blk write addr partition [cnt]"
);