12e192b24SSimon Glass /* 22e192b24SSimon Glass * (C) Copyright 2001 32e192b24SSimon Glass * Denis Peter, MPL AG Switzerland 42e192b24SSimon Glass * 52e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 62e192b24SSimon Glass */ 72e192b24SSimon Glass 82e192b24SSimon Glass /* 92e192b24SSimon Glass * SCSI support. 102e192b24SSimon Glass */ 112e192b24SSimon Glass #include <common.h> 122e192b24SSimon Glass #include <command.h> 132e192b24SSimon Glass #include <inttypes.h> 142e192b24SSimon Glass #include <asm/processor.h> 152e192b24SSimon Glass #include <scsi.h> 162e192b24SSimon Glass #include <image.h> 172e192b24SSimon Glass #include <pci.h> 182e192b24SSimon Glass 192e192b24SSimon Glass #ifdef CONFIG_SCSI_DEV_LIST 202e192b24SSimon Glass #define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST 212e192b24SSimon Glass #else 222e192b24SSimon Glass #ifdef CONFIG_SCSI_SYM53C8XX 232e192b24SSimon Glass #define SCSI_VEND_ID 0x1000 242e192b24SSimon Glass #ifndef CONFIG_SCSI_DEV_ID 252e192b24SSimon Glass #define SCSI_DEV_ID 0x0001 262e192b24SSimon Glass #else 272e192b24SSimon Glass #define SCSI_DEV_ID CONFIG_SCSI_DEV_ID 282e192b24SSimon Glass #endif 292e192b24SSimon Glass #elif defined CONFIG_SATA_ULI5288 302e192b24SSimon Glass 312e192b24SSimon Glass #define SCSI_VEND_ID 0x10b9 322e192b24SSimon Glass #define SCSI_DEV_ID 0x5288 332e192b24SSimon Glass 342e192b24SSimon Glass #elif !defined(CONFIG_SCSI_AHCI_PLAT) 352e192b24SSimon Glass #error no scsi device defined 362e192b24SSimon Glass #endif 372e192b24SSimon Glass #define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID} 382e192b24SSimon Glass #endif 392e192b24SSimon Glass 402e192b24SSimon Glass #if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) 412e192b24SSimon Glass const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST }; 422e192b24SSimon Glass #endif 432e192b24SSimon Glass static ccb tempccb; /* temporary scsi command buffer */ 442e192b24SSimon Glass 452e192b24SSimon Glass static unsigned char tempbuff[512]; /* temporary data buffer */ 462e192b24SSimon Glass 472e192b24SSimon Glass static int scsi_max_devs; /* number of highest available scsi device */ 482e192b24SSimon Glass 492e192b24SSimon Glass static int scsi_curr_dev; /* current device */ 502e192b24SSimon Glass 514101f687SSimon Glass static struct blk_desc scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE]; 522e192b24SSimon Glass 532e192b24SSimon Glass /******************************************************************************** 542e192b24SSimon Glass * forward declerations of some Setup Routines 552e192b24SSimon Glass */ 562e192b24SSimon Glass void scsi_setup_test_unit_ready(ccb * pccb); 572e192b24SSimon Glass void scsi_setup_read6(ccb * pccb, lbaint_t start, unsigned short blocks); 582e192b24SSimon Glass void scsi_setup_read_ext(ccb * pccb, lbaint_t start, unsigned short blocks); 592e192b24SSimon Glass void scsi_setup_read16(ccb * pccb, lbaint_t start, unsigned long blocks); 602e192b24SSimon Glass 612e192b24SSimon Glass static void scsi_setup_write_ext(ccb *pccb, lbaint_t start, 622e192b24SSimon Glass unsigned short blocks); 632e192b24SSimon Glass void scsi_setup_inquiry(ccb * pccb); 642e192b24SSimon Glass void scsi_ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len); 652e192b24SSimon Glass 662e192b24SSimon Glass 672e192b24SSimon Glass static int scsi_read_capacity(ccb *pccb, lbaint_t *capacity, 682e192b24SSimon Glass unsigned long *blksz); 694101f687SSimon Glass static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr, 702e192b24SSimon Glass lbaint_t blkcnt, void *buffer); 714101f687SSimon Glass static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr, 722e192b24SSimon Glass lbaint_t blkcnt, const void *buffer); 732e192b24SSimon Glass 742e192b24SSimon Glass 752e192b24SSimon Glass /********************************************************************************* 762e192b24SSimon Glass * (re)-scan the scsi bus and reports scsi device info 772e192b24SSimon Glass * to the user if mode = 1 782e192b24SSimon Glass */ 792e192b24SSimon Glass void scsi_scan(int mode) 802e192b24SSimon Glass { 812e192b24SSimon Glass unsigned char i,perq,modi,lun; 822e192b24SSimon Glass lbaint_t capacity; 832e192b24SSimon Glass unsigned long blksz; 842e192b24SSimon Glass ccb* pccb=(ccb *)&tempccb; 852e192b24SSimon Glass 862e192b24SSimon Glass if(mode==1) { 872e192b24SSimon Glass printf("scanning bus for devices...\n"); 882e192b24SSimon Glass } 892e192b24SSimon Glass for(i=0;i<CONFIG_SYS_SCSI_MAX_DEVICE;i++) { 902e192b24SSimon Glass scsi_dev_desc[i].target=0xff; 912e192b24SSimon Glass scsi_dev_desc[i].lun=0xff; 922e192b24SSimon Glass scsi_dev_desc[i].lba=0; 932e192b24SSimon Glass scsi_dev_desc[i].blksz=0; 942e192b24SSimon Glass scsi_dev_desc[i].log2blksz = 952e192b24SSimon Glass LOG2_INVALID(typeof(scsi_dev_desc[i].log2blksz)); 962e192b24SSimon Glass scsi_dev_desc[i].type=DEV_TYPE_UNKNOWN; 972e192b24SSimon Glass scsi_dev_desc[i].vendor[0]=0; 982e192b24SSimon Glass scsi_dev_desc[i].product[0]=0; 992e192b24SSimon Glass scsi_dev_desc[i].revision[0]=0; 1002e192b24SSimon Glass scsi_dev_desc[i].removable = false; 1012e192b24SSimon Glass scsi_dev_desc[i].if_type=IF_TYPE_SCSI; 1022e192b24SSimon Glass scsi_dev_desc[i].dev=i; 1032e192b24SSimon Glass scsi_dev_desc[i].part_type=PART_TYPE_UNKNOWN; 1042e192b24SSimon Glass scsi_dev_desc[i].block_read=scsi_read; 1052e192b24SSimon Glass scsi_dev_desc[i].block_write = scsi_write; 1062e192b24SSimon Glass } 1072e192b24SSimon Glass scsi_max_devs=0; 1082e192b24SSimon Glass for(i=0;i<CONFIG_SYS_SCSI_MAX_SCSI_ID;i++) { 1092e192b24SSimon Glass pccb->target=i; 1102e192b24SSimon Glass for(lun=0;lun<CONFIG_SYS_SCSI_MAX_LUN;lun++) { 1112e192b24SSimon Glass pccb->lun=lun; 1122e192b24SSimon Glass pccb->pdata=(unsigned char *)&tempbuff; 1132e192b24SSimon Glass pccb->datalen=512; 1142e192b24SSimon Glass scsi_setup_inquiry(pccb); 1152e192b24SSimon Glass if (scsi_exec(pccb) != true) { 1162e192b24SSimon Glass if(pccb->contr_stat==SCSI_SEL_TIME_OUT) { 1172e192b24SSimon Glass debug ("Selection timeout ID %d\n",pccb->target); 1182e192b24SSimon Glass continue; /* selection timeout => assuming no device present */ 1192e192b24SSimon Glass } 1202e192b24SSimon Glass scsi_print_error(pccb); 1212e192b24SSimon Glass continue; 1222e192b24SSimon Glass } 1232e192b24SSimon Glass perq=tempbuff[0]; 1242e192b24SSimon Glass modi=tempbuff[1]; 1252e192b24SSimon Glass if((perq & 0x1f)==0x1f) { 1262e192b24SSimon Glass continue; /* skip unknown devices */ 1272e192b24SSimon Glass } 1282e192b24SSimon Glass if((modi&0x80)==0x80) /* drive is removable */ 1292e192b24SSimon Glass scsi_dev_desc[scsi_max_devs].removable=true; 1302e192b24SSimon Glass /* get info for this device */ 1312e192b24SSimon Glass scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].vendor[0], 1322e192b24SSimon Glass &tempbuff[8], 8); 1332e192b24SSimon Glass scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].product[0], 1342e192b24SSimon Glass &tempbuff[16], 16); 1352e192b24SSimon Glass scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].revision[0], 1362e192b24SSimon Glass &tempbuff[32], 4); 1372e192b24SSimon Glass scsi_dev_desc[scsi_max_devs].target=pccb->target; 1382e192b24SSimon Glass scsi_dev_desc[scsi_max_devs].lun=pccb->lun; 1392e192b24SSimon Glass 1402e192b24SSimon Glass pccb->datalen=0; 1412e192b24SSimon Glass scsi_setup_test_unit_ready(pccb); 1422e192b24SSimon Glass if (scsi_exec(pccb) != true) { 1432e192b24SSimon Glass if (scsi_dev_desc[scsi_max_devs].removable == true) { 1442e192b24SSimon Glass scsi_dev_desc[scsi_max_devs].type=perq; 1452e192b24SSimon Glass goto removable; 1462e192b24SSimon Glass } 1472e192b24SSimon Glass scsi_print_error(pccb); 1482e192b24SSimon Glass continue; 1492e192b24SSimon Glass } 1502e192b24SSimon Glass if (scsi_read_capacity(pccb, &capacity, &blksz)) { 1512e192b24SSimon Glass scsi_print_error(pccb); 1522e192b24SSimon Glass continue; 1532e192b24SSimon Glass } 1542e192b24SSimon Glass scsi_dev_desc[scsi_max_devs].lba=capacity; 1552e192b24SSimon Glass scsi_dev_desc[scsi_max_devs].blksz=blksz; 1562e192b24SSimon Glass scsi_dev_desc[scsi_max_devs].log2blksz = 1572e192b24SSimon Glass LOG2(scsi_dev_desc[scsi_max_devs].blksz); 1582e192b24SSimon Glass scsi_dev_desc[scsi_max_devs].type=perq; 159*3e8bd469SSimon Glass part_init(&scsi_dev_desc[scsi_max_devs]); 1602e192b24SSimon Glass removable: 1612e192b24SSimon Glass if(mode==1) { 1622e192b24SSimon Glass printf (" Device %d: ", scsi_max_devs); 1632e192b24SSimon Glass dev_print(&scsi_dev_desc[scsi_max_devs]); 1642e192b24SSimon Glass } /* if mode */ 1652e192b24SSimon Glass scsi_max_devs++; 1662e192b24SSimon Glass } /* next LUN */ 1672e192b24SSimon Glass } 1682e192b24SSimon Glass if(scsi_max_devs>0) 1692e192b24SSimon Glass scsi_curr_dev=0; 1702e192b24SSimon Glass else 1712e192b24SSimon Glass scsi_curr_dev = -1; 1722e192b24SSimon Glass 1732e192b24SSimon Glass printf("Found %d device(s).\n", scsi_max_devs); 1742e192b24SSimon Glass #ifndef CONFIG_SPL_BUILD 1752e192b24SSimon Glass setenv_ulong("scsidevs", scsi_max_devs); 1762e192b24SSimon Glass #endif 1772e192b24SSimon Glass } 1782e192b24SSimon Glass 1792e192b24SSimon Glass int scsi_get_disk_count(void) 1802e192b24SSimon Glass { 1812e192b24SSimon Glass return scsi_max_devs; 1822e192b24SSimon Glass } 1832e192b24SSimon Glass 1842e192b24SSimon Glass #if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) 1852e192b24SSimon Glass void scsi_init(void) 1862e192b24SSimon Glass { 1872e192b24SSimon Glass int busdevfunc = -1; 1882e192b24SSimon Glass int i; 1892e192b24SSimon Glass /* 1902e192b24SSimon Glass * Find a device from the list, this driver will support a single 1912e192b24SSimon Glass * controller. 1922e192b24SSimon Glass */ 1932e192b24SSimon Glass for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) { 1942e192b24SSimon Glass /* get PCI Device ID */ 1952e192b24SSimon Glass #ifdef CONFIG_DM_PCI 1962e192b24SSimon Glass struct udevice *dev; 1972e192b24SSimon Glass int ret; 1982e192b24SSimon Glass 1992e192b24SSimon Glass ret = dm_pci_find_device(scsi_device_list[i].vendor, 2002e192b24SSimon Glass scsi_device_list[i].device, 0, &dev); 2012e192b24SSimon Glass if (!ret) { 2022e192b24SSimon Glass busdevfunc = dm_pci_get_bdf(dev); 2032e192b24SSimon Glass break; 2042e192b24SSimon Glass } 2052e192b24SSimon Glass #else 2062e192b24SSimon Glass busdevfunc = pci_find_device(scsi_device_list[i].vendor, 2072e192b24SSimon Glass scsi_device_list[i].device, 2082e192b24SSimon Glass 0); 2092e192b24SSimon Glass #endif 2102e192b24SSimon Glass if (busdevfunc != -1) 2112e192b24SSimon Glass break; 2122e192b24SSimon Glass } 2132e192b24SSimon Glass 2142e192b24SSimon Glass if (busdevfunc == -1) { 2152e192b24SSimon Glass printf("Error: SCSI Controller(s) "); 2162e192b24SSimon Glass for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) { 2172e192b24SSimon Glass printf("%04X:%04X ", 2182e192b24SSimon Glass scsi_device_list[i].vendor, 2192e192b24SSimon Glass scsi_device_list[i].device); 2202e192b24SSimon Glass } 2212e192b24SSimon Glass printf("not found\n"); 2222e192b24SSimon Glass return; 2232e192b24SSimon Glass } 2242e192b24SSimon Glass #ifdef DEBUG 2252e192b24SSimon Glass else { 2262e192b24SSimon Glass printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n", 2272e192b24SSimon Glass scsi_device_list[i].vendor, 2282e192b24SSimon Glass scsi_device_list[i].device, 2292e192b24SSimon Glass (busdevfunc >> 16) & 0xFF, 2302e192b24SSimon Glass (busdevfunc >> 11) & 0x1F, 2312e192b24SSimon Glass (busdevfunc >> 8) & 0x7); 2322e192b24SSimon Glass } 2332e192b24SSimon Glass #endif 2342e192b24SSimon Glass bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci"); 2352e192b24SSimon Glass scsi_low_level_init(busdevfunc); 2362e192b24SSimon Glass scsi_scan(1); 2372e192b24SSimon Glass bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI); 2382e192b24SSimon Glass } 2392e192b24SSimon Glass #endif 2402e192b24SSimon Glass 2412e192b24SSimon Glass #ifdef CONFIG_PARTITIONS 2424101f687SSimon Glass struct blk_desc *scsi_get_dev(int dev) 2432e192b24SSimon Glass { 2442e192b24SSimon Glass return (dev < CONFIG_SYS_SCSI_MAX_DEVICE) ? &scsi_dev_desc[dev] : NULL; 2452e192b24SSimon Glass } 2462e192b24SSimon Glass #endif 2472e192b24SSimon Glass 2482e192b24SSimon Glass /****************************************************************************** 2492e192b24SSimon Glass * scsi boot command intepreter. Derived from diskboot 2502e192b24SSimon Glass */ 2512e192b24SSimon Glass int do_scsiboot (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 2522e192b24SSimon Glass { 2532e192b24SSimon Glass return common_diskboot(cmdtp, "scsi", argc, argv); 2542e192b24SSimon Glass } 2552e192b24SSimon Glass 2562e192b24SSimon Glass /********************************************************************************* 2572e192b24SSimon Glass * scsi command intepreter 2582e192b24SSimon Glass */ 2592e192b24SSimon Glass int do_scsi (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 2602e192b24SSimon Glass { 2612e192b24SSimon Glass switch (argc) { 2622e192b24SSimon Glass case 0: 2632e192b24SSimon Glass case 1: 2642e192b24SSimon Glass return CMD_RET_USAGE; 2652e192b24SSimon Glass 2662e192b24SSimon Glass case 2: 2672e192b24SSimon Glass if (strncmp(argv[1],"res",3) == 0) { 2682e192b24SSimon Glass printf("\nReset SCSI\n"); 2692e192b24SSimon Glass scsi_bus_reset(); 2702e192b24SSimon Glass scsi_scan(1); 2712e192b24SSimon Glass return 0; 2722e192b24SSimon Glass } 2732e192b24SSimon Glass if (strncmp(argv[1],"inf",3) == 0) { 2742e192b24SSimon Glass int i; 2752e192b24SSimon Glass for (i=0; i<CONFIG_SYS_SCSI_MAX_DEVICE; ++i) { 2762e192b24SSimon Glass if(scsi_dev_desc[i].type==DEV_TYPE_UNKNOWN) 2772e192b24SSimon Glass continue; /* list only known devices */ 2782e192b24SSimon Glass printf ("SCSI dev. %d: ", i); 2792e192b24SSimon Glass dev_print(&scsi_dev_desc[i]); 2802e192b24SSimon Glass } 2812e192b24SSimon Glass return 0; 2822e192b24SSimon Glass } 2832e192b24SSimon Glass if (strncmp(argv[1],"dev",3) == 0) { 2842e192b24SSimon Glass if ((scsi_curr_dev < 0) || (scsi_curr_dev >= CONFIG_SYS_SCSI_MAX_DEVICE)) { 2852e192b24SSimon Glass printf("\nno SCSI devices available\n"); 2862e192b24SSimon Glass return 1; 2872e192b24SSimon Glass } 2882e192b24SSimon Glass printf ("\n Device %d: ", scsi_curr_dev); 2892e192b24SSimon Glass dev_print(&scsi_dev_desc[scsi_curr_dev]); 2902e192b24SSimon Glass return 0; 2912e192b24SSimon Glass } 2922e192b24SSimon Glass if (strncmp(argv[1],"scan",4) == 0) { 2932e192b24SSimon Glass scsi_scan(1); 2942e192b24SSimon Glass return 0; 2952e192b24SSimon Glass } 2962e192b24SSimon Glass if (strncmp(argv[1],"part",4) == 0) { 2972e192b24SSimon Glass int dev, ok; 2982e192b24SSimon Glass for (ok=0, dev=0; dev<CONFIG_SYS_SCSI_MAX_DEVICE; ++dev) { 2992e192b24SSimon Glass if (scsi_dev_desc[dev].type!=DEV_TYPE_UNKNOWN) { 3002e192b24SSimon Glass ok++; 3012e192b24SSimon Glass if (dev) 3022e192b24SSimon Glass printf("\n"); 3032e192b24SSimon Glass debug ("print_part of %x\n",dev); 304*3e8bd469SSimon Glass part_print(&scsi_dev_desc[dev]); 3052e192b24SSimon Glass } 3062e192b24SSimon Glass } 3072e192b24SSimon Glass if (!ok) 3082e192b24SSimon Glass printf("\nno SCSI devices available\n"); 3092e192b24SSimon Glass return 1; 3102e192b24SSimon Glass } 3112e192b24SSimon Glass return CMD_RET_USAGE; 3122e192b24SSimon Glass case 3: 3132e192b24SSimon Glass if (strncmp(argv[1],"dev",3) == 0) { 3142e192b24SSimon Glass int dev = (int)simple_strtoul(argv[2], NULL, 10); 3152e192b24SSimon Glass printf ("\nSCSI device %d: ", dev); 3162e192b24SSimon Glass if (dev >= CONFIG_SYS_SCSI_MAX_DEVICE) { 3172e192b24SSimon Glass printf("unknown device\n"); 3182e192b24SSimon Glass return 1; 3192e192b24SSimon Glass } 3202e192b24SSimon Glass printf ("\n Device %d: ", dev); 3212e192b24SSimon Glass dev_print(&scsi_dev_desc[dev]); 3222e192b24SSimon Glass if(scsi_dev_desc[dev].type == DEV_TYPE_UNKNOWN) { 3232e192b24SSimon Glass return 1; 3242e192b24SSimon Glass } 3252e192b24SSimon Glass scsi_curr_dev = dev; 3262e192b24SSimon Glass printf("... is now current device\n"); 3272e192b24SSimon Glass return 0; 3282e192b24SSimon Glass } 3292e192b24SSimon Glass if (strncmp(argv[1],"part",4) == 0) { 3302e192b24SSimon Glass int dev = (int)simple_strtoul(argv[2], NULL, 10); 3312e192b24SSimon Glass if(scsi_dev_desc[dev].type != DEV_TYPE_UNKNOWN) { 332*3e8bd469SSimon Glass part_print(&scsi_dev_desc[dev]); 3332e192b24SSimon Glass } 3342e192b24SSimon Glass else { 3352e192b24SSimon Glass printf ("\nSCSI device %d not available\n", dev); 3362e192b24SSimon Glass } 3372e192b24SSimon Glass return 1; 3382e192b24SSimon Glass } 3392e192b24SSimon Glass return CMD_RET_USAGE; 3402e192b24SSimon Glass default: 3412e192b24SSimon Glass /* at least 4 args */ 3422e192b24SSimon Glass if (strcmp(argv[1],"read") == 0) { 3432e192b24SSimon Glass ulong addr = simple_strtoul(argv[2], NULL, 16); 3442e192b24SSimon Glass ulong blk = simple_strtoul(argv[3], NULL, 16); 3452e192b24SSimon Glass ulong cnt = simple_strtoul(argv[4], NULL, 16); 3462e192b24SSimon Glass ulong n; 3472e192b24SSimon Glass printf ("\nSCSI read: device %d block # %ld, count %ld ... ", 3482e192b24SSimon Glass scsi_curr_dev, blk, cnt); 3492e192b24SSimon Glass n = scsi_read(&scsi_dev_desc[scsi_curr_dev], 3502e192b24SSimon Glass blk, cnt, (ulong *)addr); 3512e192b24SSimon Glass printf ("%ld blocks read: %s\n",n,(n==cnt) ? "OK" : "ERROR"); 3522e192b24SSimon Glass return 0; 3532e192b24SSimon Glass } else if (strcmp(argv[1], "write") == 0) { 3542e192b24SSimon Glass ulong addr = simple_strtoul(argv[2], NULL, 16); 3552e192b24SSimon Glass ulong blk = simple_strtoul(argv[3], NULL, 16); 3562e192b24SSimon Glass ulong cnt = simple_strtoul(argv[4], NULL, 16); 3572e192b24SSimon Glass ulong n; 3582e192b24SSimon Glass printf("\nSCSI write: device %d block # %ld, " 3592e192b24SSimon Glass "count %ld ... ", 3602e192b24SSimon Glass scsi_curr_dev, blk, cnt); 3612e192b24SSimon Glass n = scsi_write(&scsi_dev_desc[scsi_curr_dev], 3622e192b24SSimon Glass blk, cnt, (ulong *)addr); 3632e192b24SSimon Glass printf("%ld blocks written: %s\n", n, 3642e192b24SSimon Glass (n == cnt) ? "OK" : "ERROR"); 3652e192b24SSimon Glass return 0; 3662e192b24SSimon Glass } 3672e192b24SSimon Glass } /* switch */ 3682e192b24SSimon Glass return CMD_RET_USAGE; 3692e192b24SSimon Glass } 3702e192b24SSimon Glass 3712e192b24SSimon Glass /**************************************************************************************** 3722e192b24SSimon Glass * scsi_read 3732e192b24SSimon Glass */ 3742e192b24SSimon Glass 3752e192b24SSimon Glass /* almost the maximum amount of the scsi_ext command.. */ 3762e192b24SSimon Glass #define SCSI_MAX_READ_BLK 0xFFFF 3772e192b24SSimon Glass #define SCSI_LBA48_READ 0xFFFFFFF 3782e192b24SSimon Glass 3794101f687SSimon Glass static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr, 3802e192b24SSimon Glass lbaint_t blkcnt, void *buffer) 3812e192b24SSimon Glass { 3822e192b24SSimon Glass int device = block_dev->dev; 3832e192b24SSimon Glass lbaint_t start, blks; 3842e192b24SSimon Glass uintptr_t buf_addr; 3852e192b24SSimon Glass unsigned short smallblks = 0; 3862e192b24SSimon Glass ccb* pccb=(ccb *)&tempccb; 3872e192b24SSimon Glass device&=0xff; 3882e192b24SSimon Glass /* Setup device 3892e192b24SSimon Glass */ 3902e192b24SSimon Glass pccb->target=scsi_dev_desc[device].target; 3912e192b24SSimon Glass pccb->lun=scsi_dev_desc[device].lun; 3922e192b24SSimon Glass buf_addr=(unsigned long)buffer; 3932e192b24SSimon Glass start=blknr; 3942e192b24SSimon Glass blks=blkcnt; 3952e192b24SSimon Glass debug("\nscsi_read: dev %d startblk " LBAF 3962e192b24SSimon Glass ", blccnt " LBAF " buffer %lx\n", 3972e192b24SSimon Glass device, start, blks, (unsigned long)buffer); 3982e192b24SSimon Glass do { 3992e192b24SSimon Glass pccb->pdata=(unsigned char *)buf_addr; 4002e192b24SSimon Glass #ifdef CONFIG_SYS_64BIT_LBA 4012e192b24SSimon Glass if (start > SCSI_LBA48_READ) { 4022e192b24SSimon Glass unsigned long blocks; 4032e192b24SSimon Glass blocks = min_t(lbaint_t, blks, SCSI_MAX_READ_BLK); 4042e192b24SSimon Glass pccb->datalen = scsi_dev_desc[device].blksz * blocks; 4052e192b24SSimon Glass scsi_setup_read16(pccb, start, blocks); 4062e192b24SSimon Glass start += blocks; 4072e192b24SSimon Glass blks -= blocks; 4082e192b24SSimon Glass } else 4092e192b24SSimon Glass #endif 4102e192b24SSimon Glass if (blks > SCSI_MAX_READ_BLK) { 4112e192b24SSimon Glass pccb->datalen=scsi_dev_desc[device].blksz * SCSI_MAX_READ_BLK; 4122e192b24SSimon Glass smallblks=SCSI_MAX_READ_BLK; 4132e192b24SSimon Glass scsi_setup_read_ext(pccb,start,smallblks); 4142e192b24SSimon Glass start+=SCSI_MAX_READ_BLK; 4152e192b24SSimon Glass blks-=SCSI_MAX_READ_BLK; 4162e192b24SSimon Glass } 4172e192b24SSimon Glass else { 4182e192b24SSimon Glass pccb->datalen=scsi_dev_desc[device].blksz * blks; 4192e192b24SSimon Glass smallblks=(unsigned short) blks; 4202e192b24SSimon Glass scsi_setup_read_ext(pccb,start,smallblks); 4212e192b24SSimon Glass start+=blks; 4222e192b24SSimon Glass blks=0; 4232e192b24SSimon Glass } 4242e192b24SSimon Glass debug("scsi_read_ext: startblk " LBAF 4252e192b24SSimon Glass ", blccnt %x buffer %" PRIXPTR "\n", 4262e192b24SSimon Glass start, smallblks, buf_addr); 4272e192b24SSimon Glass if (scsi_exec(pccb) != true) { 4282e192b24SSimon Glass scsi_print_error(pccb); 4292e192b24SSimon Glass blkcnt-=blks; 4302e192b24SSimon Glass break; 4312e192b24SSimon Glass } 4322e192b24SSimon Glass buf_addr+=pccb->datalen; 4332e192b24SSimon Glass } while(blks!=0); 4342e192b24SSimon Glass debug("scsi_read_ext: end startblk " LBAF 4352e192b24SSimon Glass ", blccnt %x buffer %" PRIXPTR "\n", start, smallblks, buf_addr); 4362e192b24SSimon Glass return(blkcnt); 4372e192b24SSimon Glass } 4382e192b24SSimon Glass 4392e192b24SSimon Glass /******************************************************************************* 4402e192b24SSimon Glass * scsi_write 4412e192b24SSimon Glass */ 4422e192b24SSimon Glass 4432e192b24SSimon Glass /* Almost the maximum amount of the scsi_ext command.. */ 4442e192b24SSimon Glass #define SCSI_MAX_WRITE_BLK 0xFFFF 4452e192b24SSimon Glass 4464101f687SSimon Glass static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr, 4472e192b24SSimon Glass lbaint_t blkcnt, const void *buffer) 4482e192b24SSimon Glass { 4492e192b24SSimon Glass int device = block_dev->dev; 4502e192b24SSimon Glass lbaint_t start, blks; 4512e192b24SSimon Glass uintptr_t buf_addr; 4522e192b24SSimon Glass unsigned short smallblks; 4532e192b24SSimon Glass ccb* pccb = (ccb *)&tempccb; 4542e192b24SSimon Glass device &= 0xff; 4552e192b24SSimon Glass /* Setup device 4562e192b24SSimon Glass */ 4572e192b24SSimon Glass pccb->target = scsi_dev_desc[device].target; 4582e192b24SSimon Glass pccb->lun = scsi_dev_desc[device].lun; 4592e192b24SSimon Glass buf_addr = (unsigned long)buffer; 4602e192b24SSimon Glass start = blknr; 4612e192b24SSimon Glass blks = blkcnt; 4622e192b24SSimon Glass debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n", 4632e192b24SSimon Glass __func__, device, start, blks, (unsigned long)buffer); 4642e192b24SSimon Glass do { 4652e192b24SSimon Glass pccb->pdata = (unsigned char *)buf_addr; 4662e192b24SSimon Glass if (blks > SCSI_MAX_WRITE_BLK) { 4672e192b24SSimon Glass pccb->datalen = (scsi_dev_desc[device].blksz * 4682e192b24SSimon Glass SCSI_MAX_WRITE_BLK); 4692e192b24SSimon Glass smallblks = SCSI_MAX_WRITE_BLK; 4702e192b24SSimon Glass scsi_setup_write_ext(pccb, start, smallblks); 4712e192b24SSimon Glass start += SCSI_MAX_WRITE_BLK; 4722e192b24SSimon Glass blks -= SCSI_MAX_WRITE_BLK; 4732e192b24SSimon Glass } else { 4742e192b24SSimon Glass pccb->datalen = scsi_dev_desc[device].blksz * blks; 4752e192b24SSimon Glass smallblks = (unsigned short)blks; 4762e192b24SSimon Glass scsi_setup_write_ext(pccb, start, smallblks); 4772e192b24SSimon Glass start += blks; 4782e192b24SSimon Glass blks = 0; 4792e192b24SSimon Glass } 4802e192b24SSimon Glass debug("%s: startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", 4812e192b24SSimon Glass __func__, start, smallblks, buf_addr); 4822e192b24SSimon Glass if (scsi_exec(pccb) != true) { 4832e192b24SSimon Glass scsi_print_error(pccb); 4842e192b24SSimon Glass blkcnt -= blks; 4852e192b24SSimon Glass break; 4862e192b24SSimon Glass } 4872e192b24SSimon Glass buf_addr += pccb->datalen; 4882e192b24SSimon Glass } while (blks != 0); 4892e192b24SSimon Glass debug("%s: end startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", 4902e192b24SSimon Glass __func__, start, smallblks, buf_addr); 4912e192b24SSimon Glass return blkcnt; 4922e192b24SSimon Glass } 4932e192b24SSimon Glass 4942e192b24SSimon Glass /* copy src to dest, skipping leading and trailing blanks 4952e192b24SSimon Glass * and null terminate the string 4962e192b24SSimon Glass */ 4972e192b24SSimon Glass void scsi_ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len) 4982e192b24SSimon Glass { 4992e192b24SSimon Glass int start,end; 5002e192b24SSimon Glass 5012e192b24SSimon Glass start=0; 5022e192b24SSimon Glass while(start<len) { 5032e192b24SSimon Glass if(src[start]!=' ') 5042e192b24SSimon Glass break; 5052e192b24SSimon Glass start++; 5062e192b24SSimon Glass } 5072e192b24SSimon Glass end=len-1; 5082e192b24SSimon Glass while(end>start) { 5092e192b24SSimon Glass if(src[end]!=' ') 5102e192b24SSimon Glass break; 5112e192b24SSimon Glass end--; 5122e192b24SSimon Glass } 5132e192b24SSimon Glass for( ; start<=end; start++) { 5142e192b24SSimon Glass *dest++=src[start]; 5152e192b24SSimon Glass } 5162e192b24SSimon Glass *dest='\0'; 5172e192b24SSimon Glass } 5182e192b24SSimon Glass 5192e192b24SSimon Glass 5202e192b24SSimon Glass /* Trim trailing blanks, and NUL-terminate string 5212e192b24SSimon Glass */ 5222e192b24SSimon Glass void scsi_trim_trail (unsigned char *str, unsigned int len) 5232e192b24SSimon Glass { 5242e192b24SSimon Glass unsigned char *p = str + len - 1; 5252e192b24SSimon Glass 5262e192b24SSimon Glass while (len-- > 0) { 5272e192b24SSimon Glass *p-- = '\0'; 5282e192b24SSimon Glass if (*p != ' ') { 5292e192b24SSimon Glass return; 5302e192b24SSimon Glass } 5312e192b24SSimon Glass } 5322e192b24SSimon Glass } 5332e192b24SSimon Glass 5342e192b24SSimon Glass int scsi_read_capacity(ccb *pccb, lbaint_t *capacity, unsigned long *blksz) 5352e192b24SSimon Glass { 5362e192b24SSimon Glass *capacity = 0; 5372e192b24SSimon Glass 5382e192b24SSimon Glass memset(pccb->cmd, 0, sizeof(pccb->cmd)); 5392e192b24SSimon Glass pccb->cmd[0] = SCSI_RD_CAPAC10; 5402e192b24SSimon Glass pccb->cmd[1] = pccb->lun << 5; 5412e192b24SSimon Glass pccb->cmdlen = 10; 5422e192b24SSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 5432e192b24SSimon Glass 5442e192b24SSimon Glass pccb->datalen = 8; 5452e192b24SSimon Glass if (scsi_exec(pccb) != true) 5462e192b24SSimon Glass return 1; 5472e192b24SSimon Glass 5482e192b24SSimon Glass *capacity = ((lbaint_t)pccb->pdata[0] << 24) | 5492e192b24SSimon Glass ((lbaint_t)pccb->pdata[1] << 16) | 5502e192b24SSimon Glass ((lbaint_t)pccb->pdata[2] << 8) | 5512e192b24SSimon Glass ((lbaint_t)pccb->pdata[3]); 5522e192b24SSimon Glass 5532e192b24SSimon Glass if (*capacity != 0xffffffff) { 5542e192b24SSimon Glass /* Read capacity (10) was sufficient for this drive. */ 5552e192b24SSimon Glass *blksz = ((unsigned long)pccb->pdata[4] << 24) | 5562e192b24SSimon Glass ((unsigned long)pccb->pdata[5] << 16) | 5572e192b24SSimon Glass ((unsigned long)pccb->pdata[6] << 8) | 5582e192b24SSimon Glass ((unsigned long)pccb->pdata[7]); 5592e192b24SSimon Glass return 0; 5602e192b24SSimon Glass } 5612e192b24SSimon Glass 5622e192b24SSimon Glass /* Read capacity (10) was insufficient. Use read capacity (16). */ 5632e192b24SSimon Glass 5642e192b24SSimon Glass memset(pccb->cmd, 0, sizeof(pccb->cmd)); 5652e192b24SSimon Glass pccb->cmd[0] = SCSI_RD_CAPAC16; 5662e192b24SSimon Glass pccb->cmd[1] = 0x10; 5672e192b24SSimon Glass pccb->cmdlen = 16; 5682e192b24SSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 5692e192b24SSimon Glass 5702e192b24SSimon Glass pccb->datalen = 16; 5712e192b24SSimon Glass if (scsi_exec(pccb) != true) 5722e192b24SSimon Glass return 1; 5732e192b24SSimon Glass 5742e192b24SSimon Glass *capacity = ((uint64_t)pccb->pdata[0] << 56) | 5752e192b24SSimon Glass ((uint64_t)pccb->pdata[1] << 48) | 5762e192b24SSimon Glass ((uint64_t)pccb->pdata[2] << 40) | 5772e192b24SSimon Glass ((uint64_t)pccb->pdata[3] << 32) | 5782e192b24SSimon Glass ((uint64_t)pccb->pdata[4] << 24) | 5792e192b24SSimon Glass ((uint64_t)pccb->pdata[5] << 16) | 5802e192b24SSimon Glass ((uint64_t)pccb->pdata[6] << 8) | 5812e192b24SSimon Glass ((uint64_t)pccb->pdata[7]); 5822e192b24SSimon Glass 5832e192b24SSimon Glass *blksz = ((uint64_t)pccb->pdata[8] << 56) | 5842e192b24SSimon Glass ((uint64_t)pccb->pdata[9] << 48) | 5852e192b24SSimon Glass ((uint64_t)pccb->pdata[10] << 40) | 5862e192b24SSimon Glass ((uint64_t)pccb->pdata[11] << 32) | 5872e192b24SSimon Glass ((uint64_t)pccb->pdata[12] << 24) | 5882e192b24SSimon Glass ((uint64_t)pccb->pdata[13] << 16) | 5892e192b24SSimon Glass ((uint64_t)pccb->pdata[14] << 8) | 5902e192b24SSimon Glass ((uint64_t)pccb->pdata[15]); 5912e192b24SSimon Glass 5922e192b24SSimon Glass return 0; 5932e192b24SSimon Glass } 5942e192b24SSimon Glass 5952e192b24SSimon Glass 5962e192b24SSimon Glass /************************************************************************************ 5972e192b24SSimon Glass * Some setup (fill-in) routines 5982e192b24SSimon Glass */ 5992e192b24SSimon Glass void scsi_setup_test_unit_ready(ccb * pccb) 6002e192b24SSimon Glass { 6012e192b24SSimon Glass pccb->cmd[0]=SCSI_TST_U_RDY; 6022e192b24SSimon Glass pccb->cmd[1]=pccb->lun<<5; 6032e192b24SSimon Glass pccb->cmd[2]=0; 6042e192b24SSimon Glass pccb->cmd[3]=0; 6052e192b24SSimon Glass pccb->cmd[4]=0; 6062e192b24SSimon Glass pccb->cmd[5]=0; 6072e192b24SSimon Glass pccb->cmdlen=6; 6082e192b24SSimon Glass pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */ 6092e192b24SSimon Glass } 6102e192b24SSimon Glass 6112e192b24SSimon Glass #ifdef CONFIG_SYS_64BIT_LBA 6122e192b24SSimon Glass void scsi_setup_read16(ccb * pccb, lbaint_t start, unsigned long blocks) 6132e192b24SSimon Glass { 6142e192b24SSimon Glass pccb->cmd[0] = SCSI_READ16; 6152e192b24SSimon Glass pccb->cmd[1] = pccb->lun<<5; 6162e192b24SSimon Glass pccb->cmd[2] = ((unsigned char) (start >> 56)) & 0xff; 6172e192b24SSimon Glass pccb->cmd[3] = ((unsigned char) (start >> 48)) & 0xff; 6182e192b24SSimon Glass pccb->cmd[4] = ((unsigned char) (start >> 40)) & 0xff; 6192e192b24SSimon Glass pccb->cmd[5] = ((unsigned char) (start >> 32)) & 0xff; 6202e192b24SSimon Glass pccb->cmd[6] = ((unsigned char) (start >> 24)) & 0xff; 6212e192b24SSimon Glass pccb->cmd[7] = ((unsigned char) (start >> 16)) & 0xff; 6222e192b24SSimon Glass pccb->cmd[8] = ((unsigned char) (start >> 8)) & 0xff; 6232e192b24SSimon Glass pccb->cmd[9] = ((unsigned char) (start)) & 0xff; 6242e192b24SSimon Glass pccb->cmd[10] = 0; 6252e192b24SSimon Glass pccb->cmd[11] = ((unsigned char) (blocks >> 24)) & 0xff; 6262e192b24SSimon Glass pccb->cmd[12] = ((unsigned char) (blocks >> 16)) & 0xff; 6272e192b24SSimon Glass pccb->cmd[13] = ((unsigned char) (blocks >> 8)) & 0xff; 6282e192b24SSimon Glass pccb->cmd[14] = (unsigned char) blocks & 0xff; 6292e192b24SSimon Glass pccb->cmd[15] = 0; 6302e192b24SSimon Glass pccb->cmdlen = 16; 6312e192b24SSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 6322e192b24SSimon Glass debug ("scsi_setup_read16: cmd: %02X %02X " 6332e192b24SSimon Glass "startblk %02X%02X%02X%02X%02X%02X%02X%02X " 6342e192b24SSimon Glass "blccnt %02X%02X%02X%02X\n", 6352e192b24SSimon Glass pccb->cmd[0], pccb->cmd[1], 6362e192b24SSimon Glass pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], 6372e192b24SSimon Glass pccb->cmd[6], pccb->cmd[7], pccb->cmd[8], pccb->cmd[9], 6382e192b24SSimon Glass pccb->cmd[11], pccb->cmd[12], pccb->cmd[13], pccb->cmd[14]); 6392e192b24SSimon Glass } 6402e192b24SSimon Glass #endif 6412e192b24SSimon Glass 6422e192b24SSimon Glass void scsi_setup_read_ext(ccb * pccb, lbaint_t start, unsigned short blocks) 6432e192b24SSimon Glass { 6442e192b24SSimon Glass pccb->cmd[0]=SCSI_READ10; 6452e192b24SSimon Glass pccb->cmd[1]=pccb->lun<<5; 6462e192b24SSimon Glass pccb->cmd[2]=((unsigned char) (start>>24))&0xff; 6472e192b24SSimon Glass pccb->cmd[3]=((unsigned char) (start>>16))&0xff; 6482e192b24SSimon Glass pccb->cmd[4]=((unsigned char) (start>>8))&0xff; 6492e192b24SSimon Glass pccb->cmd[5]=((unsigned char) (start))&0xff; 6502e192b24SSimon Glass pccb->cmd[6]=0; 6512e192b24SSimon Glass pccb->cmd[7]=((unsigned char) (blocks>>8))&0xff; 6522e192b24SSimon Glass pccb->cmd[8]=(unsigned char) blocks & 0xff; 6532e192b24SSimon Glass pccb->cmd[6]=0; 6542e192b24SSimon Glass pccb->cmdlen=10; 6552e192b24SSimon Glass pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */ 6562e192b24SSimon Glass debug ("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", 6572e192b24SSimon Glass pccb->cmd[0],pccb->cmd[1], 6582e192b24SSimon Glass pccb->cmd[2],pccb->cmd[3],pccb->cmd[4],pccb->cmd[5], 6592e192b24SSimon Glass pccb->cmd[7],pccb->cmd[8]); 6602e192b24SSimon Glass } 6612e192b24SSimon Glass 6622e192b24SSimon Glass void scsi_setup_write_ext(ccb *pccb, lbaint_t start, unsigned short blocks) 6632e192b24SSimon Glass { 6642e192b24SSimon Glass pccb->cmd[0] = SCSI_WRITE10; 6652e192b24SSimon Glass pccb->cmd[1] = pccb->lun << 5; 6662e192b24SSimon Glass pccb->cmd[2] = ((unsigned char) (start>>24)) & 0xff; 6672e192b24SSimon Glass pccb->cmd[3] = ((unsigned char) (start>>16)) & 0xff; 6682e192b24SSimon Glass pccb->cmd[4] = ((unsigned char) (start>>8)) & 0xff; 6692e192b24SSimon Glass pccb->cmd[5] = ((unsigned char) (start)) & 0xff; 6702e192b24SSimon Glass pccb->cmd[6] = 0; 6712e192b24SSimon Glass pccb->cmd[7] = ((unsigned char) (blocks>>8)) & 0xff; 6722e192b24SSimon Glass pccb->cmd[8] = (unsigned char)blocks & 0xff; 6732e192b24SSimon Glass pccb->cmd[9] = 0; 6742e192b24SSimon Glass pccb->cmdlen = 10; 6752e192b24SSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 6762e192b24SSimon Glass debug("%s: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", 6772e192b24SSimon Glass __func__, 6782e192b24SSimon Glass pccb->cmd[0], pccb->cmd[1], 6792e192b24SSimon Glass pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], 6802e192b24SSimon Glass pccb->cmd[7], pccb->cmd[8]); 6812e192b24SSimon Glass } 6822e192b24SSimon Glass 6832e192b24SSimon Glass void scsi_setup_read6(ccb * pccb, lbaint_t start, unsigned short blocks) 6842e192b24SSimon Glass { 6852e192b24SSimon Glass pccb->cmd[0]=SCSI_READ6; 6862e192b24SSimon Glass pccb->cmd[1]=pccb->lun<<5 | (((unsigned char)(start>>16))&0x1f); 6872e192b24SSimon Glass pccb->cmd[2]=((unsigned char) (start>>8))&0xff; 6882e192b24SSimon Glass pccb->cmd[3]=((unsigned char) (start))&0xff; 6892e192b24SSimon Glass pccb->cmd[4]=(unsigned char) blocks & 0xff; 6902e192b24SSimon Glass pccb->cmd[5]=0; 6912e192b24SSimon Glass pccb->cmdlen=6; 6922e192b24SSimon Glass pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */ 6932e192b24SSimon Glass debug ("scsi_setup_read6: cmd: %02X %02X startblk %02X%02X blccnt %02X\n", 6942e192b24SSimon Glass pccb->cmd[0],pccb->cmd[1], 6952e192b24SSimon Glass pccb->cmd[2],pccb->cmd[3],pccb->cmd[4]); 6962e192b24SSimon Glass } 6972e192b24SSimon Glass 6982e192b24SSimon Glass 6992e192b24SSimon Glass void scsi_setup_inquiry(ccb * pccb) 7002e192b24SSimon Glass { 7012e192b24SSimon Glass pccb->cmd[0]=SCSI_INQUIRY; 7022e192b24SSimon Glass pccb->cmd[1]=pccb->lun<<5; 7032e192b24SSimon Glass pccb->cmd[2]=0; 7042e192b24SSimon Glass pccb->cmd[3]=0; 7052e192b24SSimon Glass if(pccb->datalen>255) 7062e192b24SSimon Glass pccb->cmd[4]=255; 7072e192b24SSimon Glass else 7082e192b24SSimon Glass pccb->cmd[4]=(unsigned char)pccb->datalen; 7092e192b24SSimon Glass pccb->cmd[5]=0; 7102e192b24SSimon Glass pccb->cmdlen=6; 7112e192b24SSimon Glass pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */ 7122e192b24SSimon Glass } 7132e192b24SSimon Glass 7142e192b24SSimon Glass 7152e192b24SSimon Glass U_BOOT_CMD( 7162e192b24SSimon Glass scsi, 5, 1, do_scsi, 7172e192b24SSimon Glass "SCSI sub-system", 7182e192b24SSimon Glass "reset - reset SCSI controller\n" 7192e192b24SSimon Glass "scsi info - show available SCSI devices\n" 7202e192b24SSimon Glass "scsi scan - (re-)scan SCSI bus\n" 7212e192b24SSimon Glass "scsi device [dev] - show or set current device\n" 7222e192b24SSimon Glass "scsi part [dev] - print partition table of one or all SCSI devices\n" 7232e192b24SSimon Glass "scsi read addr blk# cnt - read `cnt' blocks starting at block `blk#'\n" 7242e192b24SSimon Glass " to memory address `addr'\n" 7252e192b24SSimon Glass "scsi write addr blk# cnt - write `cnt' blocks starting at block\n" 7262e192b24SSimon Glass " `blk#' from memory address `addr'" 7272e192b24SSimon Glass ); 7282e192b24SSimon Glass 7292e192b24SSimon Glass U_BOOT_CMD( 7302e192b24SSimon Glass scsiboot, 3, 1, do_scsiboot, 7312e192b24SSimon Glass "boot from SCSI device", 7322e192b24SSimon Glass "loadAddr dev:part" 7332e192b24SSimon Glass ); 734