1*0adc38beSZhikang Zhang /* 2*0adc38beSZhikang Zhang * Copyright (C) 2017 NXP Semiconductors 3*0adc38beSZhikang Zhang * Copyright (C) 2017 Bin Meng <bmeng.cn@gmail.com> 4*0adc38beSZhikang Zhang * 5*0adc38beSZhikang Zhang * SPDX-License-Identifier: GPL-2.0+ 6*0adc38beSZhikang Zhang */ 7*0adc38beSZhikang Zhang 8*0adc38beSZhikang Zhang #include <common.h> 9*0adc38beSZhikang Zhang #include <command.h> 10*0adc38beSZhikang Zhang #include <dm.h> 11*0adc38beSZhikang Zhang #include <nvme.h> 12*0adc38beSZhikang Zhang #include <part.h> 13*0adc38beSZhikang Zhang #include <linux/math64.h> 14*0adc38beSZhikang Zhang 15*0adc38beSZhikang Zhang static int nvme_curr_device; 16*0adc38beSZhikang Zhang 17*0adc38beSZhikang Zhang static int do_nvme_scan(cmd_tbl_t *cmdtp, int flag, 18*0adc38beSZhikang Zhang int argc, char * const argv[]) 19*0adc38beSZhikang Zhang { 20*0adc38beSZhikang Zhang int ret; 21*0adc38beSZhikang Zhang 22*0adc38beSZhikang Zhang ret = nvme_scan_namespace(); 23*0adc38beSZhikang Zhang if (ret) 24*0adc38beSZhikang Zhang return CMD_RET_FAILURE; 25*0adc38beSZhikang Zhang 26*0adc38beSZhikang Zhang return CMD_RET_SUCCESS; 27*0adc38beSZhikang Zhang } 28*0adc38beSZhikang Zhang 29*0adc38beSZhikang Zhang static int do_nvme_list(cmd_tbl_t *cmdtp, int flag, 30*0adc38beSZhikang Zhang int argc, char * const argv[]) 31*0adc38beSZhikang Zhang { 32*0adc38beSZhikang Zhang blk_list_devices(IF_TYPE_NVME); 33*0adc38beSZhikang Zhang 34*0adc38beSZhikang Zhang return CMD_RET_SUCCESS; 35*0adc38beSZhikang Zhang } 36*0adc38beSZhikang Zhang 37*0adc38beSZhikang Zhang static int do_nvme_info(cmd_tbl_t *cmdtp, int flag, 38*0adc38beSZhikang Zhang int argc, char * const argv[]) 39*0adc38beSZhikang Zhang { 40*0adc38beSZhikang Zhang int devnum; 41*0adc38beSZhikang Zhang struct udevice *udev; 42*0adc38beSZhikang Zhang int ret; 43*0adc38beSZhikang Zhang 44*0adc38beSZhikang Zhang if (argc > 1) 45*0adc38beSZhikang Zhang devnum = (int)simple_strtoul(argv[1], NULL, 10); 46*0adc38beSZhikang Zhang else 47*0adc38beSZhikang Zhang devnum = nvme_curr_device; 48*0adc38beSZhikang Zhang 49*0adc38beSZhikang Zhang ret = blk_get_device(IF_TYPE_NVME, devnum, &udev); 50*0adc38beSZhikang Zhang if (ret < 0) 51*0adc38beSZhikang Zhang return CMD_RET_FAILURE; 52*0adc38beSZhikang Zhang 53*0adc38beSZhikang Zhang nvme_print_info(udev); 54*0adc38beSZhikang Zhang 55*0adc38beSZhikang Zhang return CMD_RET_SUCCESS; 56*0adc38beSZhikang Zhang } 57*0adc38beSZhikang Zhang 58*0adc38beSZhikang Zhang static int do_nvme_device(cmd_tbl_t *cmdtp, int flag, 59*0adc38beSZhikang Zhang int argc, char * const argv[]) 60*0adc38beSZhikang Zhang { 61*0adc38beSZhikang Zhang if (argc > 1) { 62*0adc38beSZhikang Zhang int devnum = (int)simple_strtoul(argv[1], NULL, 10); 63*0adc38beSZhikang Zhang 64*0adc38beSZhikang Zhang if (!blk_show_device(IF_TYPE_NVME, devnum)) { 65*0adc38beSZhikang Zhang nvme_curr_device = devnum; 66*0adc38beSZhikang Zhang printf("... is now current device\n"); 67*0adc38beSZhikang Zhang } else { 68*0adc38beSZhikang Zhang return CMD_RET_FAILURE; 69*0adc38beSZhikang Zhang } 70*0adc38beSZhikang Zhang } else { 71*0adc38beSZhikang Zhang blk_show_device(IF_TYPE_NVME, nvme_curr_device); 72*0adc38beSZhikang Zhang } 73*0adc38beSZhikang Zhang 74*0adc38beSZhikang Zhang return CMD_RET_SUCCESS; 75*0adc38beSZhikang Zhang } 76*0adc38beSZhikang Zhang 77*0adc38beSZhikang Zhang static int do_nvme_part(cmd_tbl_t *cmdtp, int flag, 78*0adc38beSZhikang Zhang int argc, char * const argv[]) 79*0adc38beSZhikang Zhang { 80*0adc38beSZhikang Zhang if (argc > 1) { 81*0adc38beSZhikang Zhang int devnum = (int)simple_strtoul(argv[2], NULL, 10); 82*0adc38beSZhikang Zhang 83*0adc38beSZhikang Zhang if (blk_print_part_devnum(IF_TYPE_NVME, devnum)) { 84*0adc38beSZhikang Zhang printf("\nNVMe device %d not available\n", devnum); 85*0adc38beSZhikang Zhang return CMD_RET_FAILURE; 86*0adc38beSZhikang Zhang } 87*0adc38beSZhikang Zhang } else { 88*0adc38beSZhikang Zhang blk_print_part_devnum(IF_TYPE_NVME, nvme_curr_device); 89*0adc38beSZhikang Zhang } 90*0adc38beSZhikang Zhang 91*0adc38beSZhikang Zhang return CMD_RET_SUCCESS; 92*0adc38beSZhikang Zhang } 93*0adc38beSZhikang Zhang 94*0adc38beSZhikang Zhang static int do_nvme_read(cmd_tbl_t *cmdtp, int flag, int argc, 95*0adc38beSZhikang Zhang char * const argv[]) 96*0adc38beSZhikang Zhang { 97*0adc38beSZhikang Zhang unsigned long time; 98*0adc38beSZhikang Zhang if (argc != 4) 99*0adc38beSZhikang Zhang return CMD_RET_USAGE; 100*0adc38beSZhikang Zhang 101*0adc38beSZhikang Zhang ulong addr = simple_strtoul(argv[1], NULL, 16); 102*0adc38beSZhikang Zhang ulong cnt = simple_strtoul(argv[3], NULL, 16); 103*0adc38beSZhikang Zhang ulong n; 104*0adc38beSZhikang Zhang lbaint_t blk = simple_strtoul(argv[2], NULL, 16); 105*0adc38beSZhikang Zhang 106*0adc38beSZhikang Zhang printf("\nNVMe read: device %d block # " LBAFU " count %ld ... ", 107*0adc38beSZhikang Zhang nvme_curr_device, blk, cnt); 108*0adc38beSZhikang Zhang 109*0adc38beSZhikang Zhang time = get_timer(0); 110*0adc38beSZhikang Zhang n = blk_read_devnum(IF_TYPE_NVME, nvme_curr_device, blk, 111*0adc38beSZhikang Zhang cnt, (ulong *)addr); 112*0adc38beSZhikang Zhang time = get_timer(time); 113*0adc38beSZhikang Zhang 114*0adc38beSZhikang Zhang printf("read: %s\n", (n == cnt) ? "OK" : "ERROR"); 115*0adc38beSZhikang Zhang printf("%lu bytes read in %lu ms", cnt * 512, time); 116*0adc38beSZhikang Zhang if (time > 0) { 117*0adc38beSZhikang Zhang puts(" ("); 118*0adc38beSZhikang Zhang print_size(div_u64(cnt * 512, time) * 1000, "/s"); 119*0adc38beSZhikang Zhang puts(")"); 120*0adc38beSZhikang Zhang } 121*0adc38beSZhikang Zhang puts("\n"); 122*0adc38beSZhikang Zhang 123*0adc38beSZhikang Zhang return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE; 124*0adc38beSZhikang Zhang } 125*0adc38beSZhikang Zhang 126*0adc38beSZhikang Zhang static int do_nvme_write(cmd_tbl_t *cmdtp, int flag, int argc, 127*0adc38beSZhikang Zhang char * const argv[]) 128*0adc38beSZhikang Zhang { 129*0adc38beSZhikang Zhang unsigned long time; 130*0adc38beSZhikang Zhang if (argc != 4) 131*0adc38beSZhikang Zhang return CMD_RET_USAGE; 132*0adc38beSZhikang Zhang 133*0adc38beSZhikang Zhang ulong addr = simple_strtoul(argv[1], NULL, 16); 134*0adc38beSZhikang Zhang ulong cnt = simple_strtoul(argv[3], NULL, 16); 135*0adc38beSZhikang Zhang ulong n; 136*0adc38beSZhikang Zhang lbaint_t blk = simple_strtoul(argv[2], NULL, 16); 137*0adc38beSZhikang Zhang 138*0adc38beSZhikang Zhang printf("\nNVMe write: device %d block # " LBAFU " count %ld ... ", 139*0adc38beSZhikang Zhang nvme_curr_device, blk, cnt); 140*0adc38beSZhikang Zhang 141*0adc38beSZhikang Zhang time = get_timer(0); 142*0adc38beSZhikang Zhang n = blk_write_devnum(IF_TYPE_NVME, nvme_curr_device, blk, 143*0adc38beSZhikang Zhang cnt, (ulong *)addr); 144*0adc38beSZhikang Zhang time = get_timer(time); 145*0adc38beSZhikang Zhang 146*0adc38beSZhikang Zhang printf("write: %s\n", (n == cnt) ? "OK" : "ERROR"); 147*0adc38beSZhikang Zhang printf("%lu bytes write in %lu ms", cnt * 512, time); 148*0adc38beSZhikang Zhang if (time > 0) { 149*0adc38beSZhikang Zhang puts(" ("); 150*0adc38beSZhikang Zhang print_size(div_u64(cnt * 512, time) * 1000, "/s"); 151*0adc38beSZhikang Zhang puts(")"); 152*0adc38beSZhikang Zhang } 153*0adc38beSZhikang Zhang puts("\n"); 154*0adc38beSZhikang Zhang 155*0adc38beSZhikang Zhang return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE; 156*0adc38beSZhikang Zhang } 157*0adc38beSZhikang Zhang 158*0adc38beSZhikang Zhang static cmd_tbl_t cmd_nvme[] = { 159*0adc38beSZhikang Zhang U_BOOT_CMD_MKENT(scan, 1, 1, do_nvme_scan, "", ""), 160*0adc38beSZhikang Zhang U_BOOT_CMD_MKENT(list, 1, 1, do_nvme_list, "", ""), 161*0adc38beSZhikang Zhang U_BOOT_CMD_MKENT(info, 2, 1, do_nvme_info, "", ""), 162*0adc38beSZhikang Zhang U_BOOT_CMD_MKENT(device, 2, 1, do_nvme_device, "", ""), 163*0adc38beSZhikang Zhang U_BOOT_CMD_MKENT(part, 2, 1, do_nvme_part, "", ""), 164*0adc38beSZhikang Zhang U_BOOT_CMD_MKENT(write, 4, 0, do_nvme_write, "", ""), 165*0adc38beSZhikang Zhang U_BOOT_CMD_MKENT(read, 4, 0, do_nvme_read, "", "") 166*0adc38beSZhikang Zhang }; 167*0adc38beSZhikang Zhang 168*0adc38beSZhikang Zhang static int do_nvmecops(cmd_tbl_t *cmdtp, int flag, int argc, 169*0adc38beSZhikang Zhang char * const argv[]) 170*0adc38beSZhikang Zhang { 171*0adc38beSZhikang Zhang cmd_tbl_t *cp; 172*0adc38beSZhikang Zhang 173*0adc38beSZhikang Zhang cp = find_cmd_tbl(argv[1], cmd_nvme, ARRAY_SIZE(cmd_nvme)); 174*0adc38beSZhikang Zhang 175*0adc38beSZhikang Zhang argc--; 176*0adc38beSZhikang Zhang argv++; 177*0adc38beSZhikang Zhang 178*0adc38beSZhikang Zhang if (cp == NULL || argc > cp->maxargs) 179*0adc38beSZhikang Zhang return CMD_RET_USAGE; 180*0adc38beSZhikang Zhang 181*0adc38beSZhikang Zhang if (flag == CMD_FLAG_REPEAT && !cp->repeatable) 182*0adc38beSZhikang Zhang return CMD_RET_SUCCESS; 183*0adc38beSZhikang Zhang 184*0adc38beSZhikang Zhang return cp->cmd(cmdtp, flag, argc, argv); 185*0adc38beSZhikang Zhang } 186*0adc38beSZhikang Zhang 187*0adc38beSZhikang Zhang U_BOOT_CMD( 188*0adc38beSZhikang Zhang nvme, 8, 1, do_nvmecops, 189*0adc38beSZhikang Zhang "NVM Express sub-system", 190*0adc38beSZhikang Zhang "\nnvme scan - scan NVMe blk devices\n" 191*0adc38beSZhikang Zhang "nvme list - show all available NVMe blk devices\n" 192*0adc38beSZhikang Zhang "nvme info [dev]- show current or a specific NVMe blk device\n" 193*0adc38beSZhikang Zhang "nvme device [dev] - show or set current device\n" 194*0adc38beSZhikang Zhang "nvme part [dev] - print partition table\n" 195*0adc38beSZhikang Zhang "nvme read addr blk# cnt\n" 196*0adc38beSZhikang Zhang "nvme write addr blk# cnt" 197*0adc38beSZhikang Zhang ); 198