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 5373a9cfdeSSimon Glass /* almost the maximum amount of the scsi_ext command.. */ 5473a9cfdeSSimon Glass #define SCSI_MAX_READ_BLK 0xFFFF 5573a9cfdeSSimon Glass #define SCSI_LBA48_READ 0xFFFFFFF 562e192b24SSimon Glass 5773a9cfdeSSimon Glass #ifdef CONFIG_SYS_64BIT_LBA 5873a9cfdeSSimon Glass void scsi_setup_read16(ccb *pccb, lbaint_t start, unsigned long blocks) 592e192b24SSimon Glass { 6073a9cfdeSSimon Glass pccb->cmd[0] = SCSI_READ16; 6173a9cfdeSSimon Glass pccb->cmd[1] = pccb->lun << 5; 62*f1d4d937SSimon Glass pccb->cmd[2] = (unsigned char)(start >> 56) & 0xff; 63*f1d4d937SSimon Glass pccb->cmd[3] = (unsigned char)(start >> 48) & 0xff; 64*f1d4d937SSimon Glass pccb->cmd[4] = (unsigned char)(start >> 40) & 0xff; 65*f1d4d937SSimon Glass pccb->cmd[5] = (unsigned char)(start >> 32) & 0xff; 66*f1d4d937SSimon Glass pccb->cmd[6] = (unsigned char)(start >> 24) & 0xff; 67*f1d4d937SSimon Glass pccb->cmd[7] = (unsigned char)(start >> 16) & 0xff; 68*f1d4d937SSimon Glass pccb->cmd[8] = (unsigned char)(start >> 8) & 0xff; 69*f1d4d937SSimon Glass pccb->cmd[9] = (unsigned char)start & 0xff; 7073a9cfdeSSimon Glass pccb->cmd[10] = 0; 71*f1d4d937SSimon Glass pccb->cmd[11] = (unsigned char)(blocks >> 24) & 0xff; 72*f1d4d937SSimon Glass pccb->cmd[12] = (unsigned char)(blocks >> 16) & 0xff; 73*f1d4d937SSimon Glass pccb->cmd[13] = (unsigned char)(blocks >> 8) & 0xff; 7473a9cfdeSSimon Glass pccb->cmd[14] = (unsigned char)blocks & 0xff; 7573a9cfdeSSimon Glass pccb->cmd[15] = 0; 7673a9cfdeSSimon Glass pccb->cmdlen = 16; 7773a9cfdeSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 78*f1d4d937SSimon Glass debug("scsi_setup_read16: cmd: %02X %02X startblk %02X%02X%02X%02X%02X%02X%02X%02X blccnt %02X%02X%02X%02X\n", 7973a9cfdeSSimon Glass pccb->cmd[0], pccb->cmd[1], 8073a9cfdeSSimon Glass pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], 8173a9cfdeSSimon Glass pccb->cmd[6], pccb->cmd[7], pccb->cmd[8], pccb->cmd[9], 8273a9cfdeSSimon Glass pccb->cmd[11], pccb->cmd[12], pccb->cmd[13], pccb->cmd[14]); 832e192b24SSimon Glass } 842e192b24SSimon Glass #endif 8573a9cfdeSSimon Glass 8673a9cfdeSSimon Glass void scsi_setup_read_ext(ccb * pccb, lbaint_t start, unsigned short blocks) 8773a9cfdeSSimon Glass { 8873a9cfdeSSimon Glass pccb->cmd[0] = SCSI_READ10; 8973a9cfdeSSimon Glass pccb->cmd[1] = pccb->lun << 5; 90*f1d4d937SSimon Glass pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff; 91*f1d4d937SSimon Glass pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff; 92*f1d4d937SSimon Glass pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff; 93*f1d4d937SSimon Glass pccb->cmd[5] = (unsigned char)start & 0xff; 9473a9cfdeSSimon Glass pccb->cmd[6] = 0; 95*f1d4d937SSimon Glass pccb->cmd[7] = (unsigned char)(blocks >> 8) & 0xff; 9673a9cfdeSSimon Glass pccb->cmd[8] = (unsigned char)blocks & 0xff; 9773a9cfdeSSimon Glass pccb->cmd[6] = 0; 9873a9cfdeSSimon Glass pccb->cmdlen=10; 9973a9cfdeSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 10073a9cfdeSSimon Glass debug ("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", 10173a9cfdeSSimon Glass pccb->cmd[0],pccb->cmd[1], 10273a9cfdeSSimon Glass pccb->cmd[2],pccb->cmd[3],pccb->cmd[4],pccb->cmd[5], 10373a9cfdeSSimon Glass pccb->cmd[7],pccb->cmd[8]); 10473a9cfdeSSimon Glass } 10573a9cfdeSSimon Glass 10673a9cfdeSSimon Glass void scsi_setup_write_ext(ccb *pccb, lbaint_t start, unsigned short blocks) 10773a9cfdeSSimon Glass { 10873a9cfdeSSimon Glass pccb->cmd[0] = SCSI_WRITE10; 10973a9cfdeSSimon Glass pccb->cmd[1] = pccb->lun << 5; 110*f1d4d937SSimon Glass pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff; 111*f1d4d937SSimon Glass pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff; 112*f1d4d937SSimon Glass pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff; 113*f1d4d937SSimon Glass pccb->cmd[5] = (unsigned char)start & 0xff; 11473a9cfdeSSimon Glass pccb->cmd[6] = 0; 11573a9cfdeSSimon Glass pccb->cmd[7] = ((unsigned char)(blocks >> 8)) & 0xff; 11673a9cfdeSSimon Glass pccb->cmd[8] = (unsigned char)blocks & 0xff; 11773a9cfdeSSimon Glass pccb->cmd[9] = 0; 11873a9cfdeSSimon Glass pccb->cmdlen = 10; 11973a9cfdeSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 12073a9cfdeSSimon Glass debug("%s: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", 12173a9cfdeSSimon Glass __func__, 12273a9cfdeSSimon Glass pccb->cmd[0], pccb->cmd[1], 12373a9cfdeSSimon Glass pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], 12473a9cfdeSSimon Glass pccb->cmd[7], pccb->cmd[8]); 12573a9cfdeSSimon Glass } 12673a9cfdeSSimon Glass 12773a9cfdeSSimon Glass void scsi_setup_read6(ccb * pccb, lbaint_t start, unsigned short blocks) 12873a9cfdeSSimon Glass { 12973a9cfdeSSimon Glass pccb->cmd[0] = SCSI_READ6; 130*f1d4d937SSimon Glass pccb->cmd[1] = pccb->lun << 5 | ((unsigned char)(start >> 16) & 0x1f); 131*f1d4d937SSimon Glass pccb->cmd[2] = (unsigned char)(start >> 8) & 0xff; 132*f1d4d937SSimon Glass pccb->cmd[3] = (unsigned char)start & 0xff; 13373a9cfdeSSimon Glass pccb->cmd[4] = (unsigned char)blocks & 0xff; 13473a9cfdeSSimon Glass pccb->cmd[5] = 0; 13573a9cfdeSSimon Glass pccb->cmdlen=6; 13673a9cfdeSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 13773a9cfdeSSimon Glass debug("scsi_setup_read6: cmd: %02X %02X startblk %02X%02X blccnt %02X\n", 13873a9cfdeSSimon Glass pccb->cmd[0], pccb->cmd[1], 13973a9cfdeSSimon Glass pccb->cmd[2], pccb->cmd[3], pccb->cmd[4]); 14073a9cfdeSSimon Glass } 14173a9cfdeSSimon Glass 14273a9cfdeSSimon Glass 14373a9cfdeSSimon Glass void scsi_setup_inquiry(ccb * pccb) 14473a9cfdeSSimon Glass { 14573a9cfdeSSimon Glass pccb->cmd[0] = SCSI_INQUIRY; 14673a9cfdeSSimon Glass pccb->cmd[1] = pccb->lun << 5; 14773a9cfdeSSimon Glass pccb->cmd[2] = 0; 14873a9cfdeSSimon Glass pccb->cmd[3] = 0; 14973a9cfdeSSimon Glass if (pccb->datalen > 255) 15073a9cfdeSSimon Glass pccb->cmd[4] = 255; 15173a9cfdeSSimon Glass else 15273a9cfdeSSimon Glass pccb->cmd[4] = (unsigned char)pccb->datalen; 15373a9cfdeSSimon Glass pccb->cmd[5] = 0; 15473a9cfdeSSimon Glass pccb->cmdlen=6; 15573a9cfdeSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 15673a9cfdeSSimon Glass } 15773a9cfdeSSimon Glass 15873a9cfdeSSimon Glass static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr, 15973a9cfdeSSimon Glass lbaint_t blkcnt, void *buffer) 16073a9cfdeSSimon Glass { 16173a9cfdeSSimon Glass int device = block_dev->devnum; 16273a9cfdeSSimon Glass lbaint_t start, blks; 16373a9cfdeSSimon Glass uintptr_t buf_addr; 16473a9cfdeSSimon Glass unsigned short smallblks = 0; 16573a9cfdeSSimon Glass ccb* pccb=(ccb *)&tempccb; 16673a9cfdeSSimon Glass device&=0xff; 167*f1d4d937SSimon Glass 168*f1d4d937SSimon Glass /* Setup device */ 16973a9cfdeSSimon Glass pccb->target = scsi_dev_desc[device].target; 17073a9cfdeSSimon Glass pccb->lun = scsi_dev_desc[device].lun; 17173a9cfdeSSimon Glass buf_addr = (unsigned long)buffer; 17273a9cfdeSSimon Glass start = blknr; 17373a9cfdeSSimon Glass blks = blkcnt; 17473a9cfdeSSimon Glass debug("\nscsi_read: dev %d startblk " LBAF 17573a9cfdeSSimon Glass ", blccnt " LBAF " buffer %lx\n", 17673a9cfdeSSimon Glass device, start, blks, (unsigned long)buffer); 17773a9cfdeSSimon Glass do { 17873a9cfdeSSimon Glass pccb->pdata = (unsigned char *)buf_addr; 17973a9cfdeSSimon Glass #ifdef CONFIG_SYS_64BIT_LBA 18073a9cfdeSSimon Glass if (start > SCSI_LBA48_READ) { 18173a9cfdeSSimon Glass unsigned long blocks; 18273a9cfdeSSimon Glass blocks = min_t(lbaint_t, blks, SCSI_MAX_READ_BLK); 18373a9cfdeSSimon Glass pccb->datalen = scsi_dev_desc[device].blksz * blocks; 18473a9cfdeSSimon Glass scsi_setup_read16(pccb, start, blocks); 18573a9cfdeSSimon Glass start += blocks; 18673a9cfdeSSimon Glass blks -= blocks; 18773a9cfdeSSimon Glass } else 18873a9cfdeSSimon Glass #endif 18973a9cfdeSSimon Glass if (blks > SCSI_MAX_READ_BLK) { 190*f1d4d937SSimon Glass pccb->datalen = scsi_dev_desc[device].blksz * 191*f1d4d937SSimon Glass SCSI_MAX_READ_BLK; 19273a9cfdeSSimon Glass smallblks = SCSI_MAX_READ_BLK; 19373a9cfdeSSimon Glass scsi_setup_read_ext(pccb, start, smallblks); 19473a9cfdeSSimon Glass start += SCSI_MAX_READ_BLK; 19573a9cfdeSSimon Glass blks -= SCSI_MAX_READ_BLK; 19673a9cfdeSSimon Glass } 19773a9cfdeSSimon Glass else { 19873a9cfdeSSimon Glass pccb->datalen = scsi_dev_desc[device].blksz * blks; 19973a9cfdeSSimon Glass smallblks = (unsigned short)blks; 20073a9cfdeSSimon Glass scsi_setup_read_ext(pccb, start, smallblks); 20173a9cfdeSSimon Glass start += blks; 20273a9cfdeSSimon Glass blks=0; 20373a9cfdeSSimon Glass } 20473a9cfdeSSimon Glass debug("scsi_read_ext: startblk " LBAF 20573a9cfdeSSimon Glass ", blccnt %x buffer %" PRIXPTR "\n", 20673a9cfdeSSimon Glass start, smallblks, buf_addr); 20773a9cfdeSSimon Glass if (scsi_exec(pccb) != true) { 20873a9cfdeSSimon Glass scsi_print_error(pccb); 20973a9cfdeSSimon Glass blkcnt -= blks; 21073a9cfdeSSimon Glass break; 21173a9cfdeSSimon Glass } 21273a9cfdeSSimon Glass buf_addr+=pccb->datalen; 21373a9cfdeSSimon Glass } while (blks != 0); 21473a9cfdeSSimon Glass debug("scsi_read_ext: end startblk " LBAF 21573a9cfdeSSimon Glass ", blccnt %x buffer %" PRIXPTR "\n", start, smallblks, buf_addr); 216*f1d4d937SSimon Glass return blkcnt; 21773a9cfdeSSimon Glass } 21873a9cfdeSSimon Glass 21973a9cfdeSSimon Glass /******************************************************************************* 22073a9cfdeSSimon Glass * scsi_write 22173a9cfdeSSimon Glass */ 22273a9cfdeSSimon Glass 22373a9cfdeSSimon Glass /* Almost the maximum amount of the scsi_ext command.. */ 22473a9cfdeSSimon Glass #define SCSI_MAX_WRITE_BLK 0xFFFF 22573a9cfdeSSimon Glass 22673a9cfdeSSimon Glass static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr, 22773a9cfdeSSimon Glass lbaint_t blkcnt, const void *buffer) 22873a9cfdeSSimon Glass { 22973a9cfdeSSimon Glass int device = block_dev->devnum; 23073a9cfdeSSimon Glass lbaint_t start, blks; 23173a9cfdeSSimon Glass uintptr_t buf_addr; 23273a9cfdeSSimon Glass unsigned short smallblks; 23373a9cfdeSSimon Glass ccb* pccb = (ccb *)&tempccb; 23473a9cfdeSSimon Glass device &= 0xff; 23573a9cfdeSSimon Glass /* Setup device 23673a9cfdeSSimon Glass */ 23773a9cfdeSSimon Glass pccb->target = scsi_dev_desc[device].target; 23873a9cfdeSSimon Glass pccb->lun = scsi_dev_desc[device].lun; 23973a9cfdeSSimon Glass buf_addr = (unsigned long)buffer; 24073a9cfdeSSimon Glass start = blknr; 24173a9cfdeSSimon Glass blks = blkcnt; 24273a9cfdeSSimon Glass debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n", 24373a9cfdeSSimon Glass __func__, device, start, blks, (unsigned long)buffer); 24473a9cfdeSSimon Glass do { 24573a9cfdeSSimon Glass pccb->pdata = (unsigned char *)buf_addr; 24673a9cfdeSSimon Glass if (blks > SCSI_MAX_WRITE_BLK) { 24773a9cfdeSSimon Glass pccb->datalen = (scsi_dev_desc[device].blksz * 24873a9cfdeSSimon Glass SCSI_MAX_WRITE_BLK); 24973a9cfdeSSimon Glass smallblks = SCSI_MAX_WRITE_BLK; 25073a9cfdeSSimon Glass scsi_setup_write_ext(pccb, start, smallblks); 25173a9cfdeSSimon Glass start += SCSI_MAX_WRITE_BLK; 25273a9cfdeSSimon Glass blks -= SCSI_MAX_WRITE_BLK; 25373a9cfdeSSimon Glass } else { 25473a9cfdeSSimon Glass pccb->datalen = scsi_dev_desc[device].blksz * blks; 25573a9cfdeSSimon Glass smallblks = (unsigned short)blks; 25673a9cfdeSSimon Glass scsi_setup_write_ext(pccb, start, smallblks); 25773a9cfdeSSimon Glass start += blks; 25873a9cfdeSSimon Glass blks = 0; 25973a9cfdeSSimon Glass } 26073a9cfdeSSimon Glass debug("%s: startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", 26173a9cfdeSSimon Glass __func__, start, smallblks, buf_addr); 26273a9cfdeSSimon Glass if (scsi_exec(pccb) != true) { 26373a9cfdeSSimon Glass scsi_print_error(pccb); 26473a9cfdeSSimon Glass blkcnt -= blks; 26573a9cfdeSSimon Glass break; 26673a9cfdeSSimon Glass } 26773a9cfdeSSimon Glass buf_addr += pccb->datalen; 26873a9cfdeSSimon Glass } while (blks != 0); 26973a9cfdeSSimon Glass debug("%s: end startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", 27073a9cfdeSSimon Glass __func__, start, smallblks, buf_addr); 27173a9cfdeSSimon Glass return blkcnt; 2722e192b24SSimon Glass } 2732e192b24SSimon Glass 2742e192b24SSimon Glass int scsi_get_disk_count(void) 2752e192b24SSimon Glass { 2762e192b24SSimon Glass return scsi_max_devs; 2772e192b24SSimon Glass } 2782e192b24SSimon Glass 2792e192b24SSimon Glass #if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) 2802e192b24SSimon Glass void scsi_init(void) 2812e192b24SSimon Glass { 2822e192b24SSimon Glass int busdevfunc = -1; 2832e192b24SSimon Glass int i; 2842e192b24SSimon Glass /* 2852e192b24SSimon Glass * Find a device from the list, this driver will support a single 2862e192b24SSimon Glass * controller. 2872e192b24SSimon Glass */ 2882e192b24SSimon Glass for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) { 2892e192b24SSimon Glass /* get PCI Device ID */ 2902e192b24SSimon Glass #ifdef CONFIG_DM_PCI 2912e192b24SSimon Glass struct udevice *dev; 2922e192b24SSimon Glass int ret; 2932e192b24SSimon Glass 2942e192b24SSimon Glass ret = dm_pci_find_device(scsi_device_list[i].vendor, 2952e192b24SSimon Glass scsi_device_list[i].device, 0, &dev); 2962e192b24SSimon Glass if (!ret) { 2972e192b24SSimon Glass busdevfunc = dm_pci_get_bdf(dev); 2982e192b24SSimon Glass break; 2992e192b24SSimon Glass } 3002e192b24SSimon Glass #else 3012e192b24SSimon Glass busdevfunc = pci_find_device(scsi_device_list[i].vendor, 3022e192b24SSimon Glass scsi_device_list[i].device, 3032e192b24SSimon Glass 0); 3042e192b24SSimon Glass #endif 3052e192b24SSimon Glass if (busdevfunc != -1) 3062e192b24SSimon Glass break; 3072e192b24SSimon Glass } 3082e192b24SSimon Glass 3092e192b24SSimon Glass if (busdevfunc == -1) { 3102e192b24SSimon Glass printf("Error: SCSI Controller(s) "); 3112e192b24SSimon Glass for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) { 3122e192b24SSimon Glass printf("%04X:%04X ", 3132e192b24SSimon Glass scsi_device_list[i].vendor, 3142e192b24SSimon Glass scsi_device_list[i].device); 3152e192b24SSimon Glass } 3162e192b24SSimon Glass printf("not found\n"); 3172e192b24SSimon Glass return; 3182e192b24SSimon Glass } 3192e192b24SSimon Glass #ifdef DEBUG 3202e192b24SSimon Glass else { 3212e192b24SSimon Glass printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n", 3222e192b24SSimon Glass scsi_device_list[i].vendor, 3232e192b24SSimon Glass scsi_device_list[i].device, 3242e192b24SSimon Glass (busdevfunc >> 16) & 0xFF, 3252e192b24SSimon Glass (busdevfunc >> 11) & 0x1F, 3262e192b24SSimon Glass (busdevfunc >> 8) & 0x7); 3272e192b24SSimon Glass } 3282e192b24SSimon Glass #endif 3292e192b24SSimon Glass bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci"); 3302e192b24SSimon Glass scsi_low_level_init(busdevfunc); 3312e192b24SSimon Glass scsi_scan(1); 3322e192b24SSimon Glass bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI); 3332e192b24SSimon Glass } 3342e192b24SSimon Glass #endif 3352e192b24SSimon Glass 3362e192b24SSimon Glass #ifdef CONFIG_PARTITIONS 3374101f687SSimon Glass struct blk_desc *scsi_get_dev(int dev) 3382e192b24SSimon Glass { 3392e192b24SSimon Glass return (dev < CONFIG_SYS_SCSI_MAX_DEVICE) ? &scsi_dev_desc[dev] : NULL; 3402e192b24SSimon Glass } 3412e192b24SSimon Glass #endif 3422e192b24SSimon Glass 343ba524269STom Rini #ifndef CONFIG_SPL_BUILD 3442e192b24SSimon Glass /****************************************************************************** 3452e192b24SSimon Glass * scsi boot command intepreter. Derived from diskboot 3462e192b24SSimon Glass */ 3472e192b24SSimon Glass int do_scsiboot (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 3482e192b24SSimon Glass { 3492e192b24SSimon Glass return common_diskboot(cmdtp, "scsi", argc, argv); 3502e192b24SSimon Glass } 3512e192b24SSimon Glass 3522e192b24SSimon Glass /********************************************************************************* 3532e192b24SSimon Glass * scsi command intepreter 3542e192b24SSimon Glass */ 3552e192b24SSimon Glass int do_scsi (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 3562e192b24SSimon Glass { 3572e192b24SSimon Glass switch (argc) { 3582e192b24SSimon Glass case 0: 3592e192b24SSimon Glass case 1: 3602e192b24SSimon Glass return CMD_RET_USAGE; 3612e192b24SSimon Glass 3622e192b24SSimon Glass case 2: 3632e192b24SSimon Glass if (strncmp(argv[1], "res", 3) == 0) { 3642e192b24SSimon Glass printf("\nReset SCSI\n"); 3652e192b24SSimon Glass scsi_bus_reset(); 3662e192b24SSimon Glass scsi_scan(1); 3672e192b24SSimon Glass return 0; 3682e192b24SSimon Glass } 3692e192b24SSimon Glass if (strncmp(argv[1], "inf", 3) == 0) { 3702e192b24SSimon Glass int i; 3712e192b24SSimon Glass for (i = 0; i < CONFIG_SYS_SCSI_MAX_DEVICE; ++i) { 3722e192b24SSimon Glass if (scsi_dev_desc[i].type == DEV_TYPE_UNKNOWN) 3732e192b24SSimon Glass continue; /* list only known devices */ 3742e192b24SSimon Glass printf("SCSI dev. %d: ", i); 3752e192b24SSimon Glass dev_print(&scsi_dev_desc[i]); 3762e192b24SSimon Glass } 3772e192b24SSimon Glass return 0; 3782e192b24SSimon Glass } 3792e192b24SSimon Glass if (strncmp(argv[1], "dev", 3) == 0) { 380*f1d4d937SSimon Glass if (scsi_curr_dev < 0 || 381*f1d4d937SSimon Glass scsi_curr_dev >= CONFIG_SYS_SCSI_MAX_DEVICE) { 3822e192b24SSimon Glass printf("\nno SCSI devices available\n"); 3832e192b24SSimon Glass return 1; 3842e192b24SSimon Glass } 3852e192b24SSimon Glass printf("\n Device %d: ", scsi_curr_dev); 3862e192b24SSimon Glass dev_print(&scsi_dev_desc[scsi_curr_dev]); 3872e192b24SSimon Glass return 0; 3882e192b24SSimon Glass } 3892e192b24SSimon Glass if (strncmp(argv[1], "scan", 4) == 0) { 3902e192b24SSimon Glass scsi_scan(1); 3912e192b24SSimon Glass return 0; 3922e192b24SSimon Glass } 3932e192b24SSimon Glass if (strncmp(argv[1], "part", 4) == 0) { 3942e192b24SSimon Glass int dev, ok; 395*f1d4d937SSimon Glass for (ok = 0, dev = 0; 396*f1d4d937SSimon Glass dev < CONFIG_SYS_SCSI_MAX_DEVICE; ++dev) { 397*f1d4d937SSimon Glass if (scsi_dev_desc[dev].type != 398*f1d4d937SSimon Glass DEV_TYPE_UNKNOWN) { 3992e192b24SSimon Glass ok++; 4002e192b24SSimon Glass if (dev) 4012e192b24SSimon Glass printf("\n"); 4022e192b24SSimon Glass debug("print_part of %x\n", dev); 4033e8bd469SSimon Glass part_print(&scsi_dev_desc[dev]); 4042e192b24SSimon Glass } 4052e192b24SSimon Glass } 4062e192b24SSimon Glass if (!ok) 4072e192b24SSimon Glass printf("\nno SCSI devices available\n"); 4082e192b24SSimon Glass return 1; 4092e192b24SSimon Glass } 4102e192b24SSimon Glass return CMD_RET_USAGE; 4112e192b24SSimon Glass case 3: 4122e192b24SSimon Glass if (strncmp(argv[1], "dev", 3) == 0) { 4132e192b24SSimon Glass int dev = (int)simple_strtoul(argv[2], NULL, 10); 4142e192b24SSimon Glass printf("\nSCSI device %d: ", dev); 4152e192b24SSimon Glass if (dev >= CONFIG_SYS_SCSI_MAX_DEVICE) { 4162e192b24SSimon Glass printf("unknown device\n"); 4172e192b24SSimon Glass return 1; 4182e192b24SSimon Glass } 4192e192b24SSimon Glass printf("\n Device %d: ", dev); 4202e192b24SSimon Glass dev_print(&scsi_dev_desc[dev]); 421*f1d4d937SSimon Glass if (scsi_dev_desc[dev].type == DEV_TYPE_UNKNOWN) 4222e192b24SSimon Glass return 1; 4232e192b24SSimon Glass scsi_curr_dev = dev; 4242e192b24SSimon Glass printf("... is now current device\n"); 4252e192b24SSimon Glass return 0; 4262e192b24SSimon Glass } 4272e192b24SSimon Glass if (strncmp(argv[1], "part", 4) == 0) { 4282e192b24SSimon Glass int dev = (int)simple_strtoul(argv[2], NULL, 10); 429*f1d4d937SSimon Glass if (scsi_dev_desc[dev].type != DEV_TYPE_UNKNOWN) 4303e8bd469SSimon Glass part_print(&scsi_dev_desc[dev]); 431*f1d4d937SSimon Glass else 4322e192b24SSimon Glass printf("\nSCSI device %d not available\n", dev); 4332e192b24SSimon Glass return 1; 4342e192b24SSimon Glass } 4352e192b24SSimon Glass return CMD_RET_USAGE; 4362e192b24SSimon Glass default: 4372e192b24SSimon Glass /* at least 4 args */ 4382e192b24SSimon Glass if (strcmp(argv[1], "read") == 0) { 4392e192b24SSimon Glass ulong addr = simple_strtoul(argv[2], NULL, 16); 4402e192b24SSimon Glass ulong blk = simple_strtoul(argv[3], NULL, 16); 4412e192b24SSimon Glass ulong cnt = simple_strtoul(argv[4], NULL, 16); 4422e192b24SSimon Glass ulong n; 4432e192b24SSimon Glass printf("\nSCSI read: device %d block # %ld, count %ld ... ", 4442e192b24SSimon Glass scsi_curr_dev, blk, cnt); 4452e192b24SSimon Glass n = scsi_read(&scsi_dev_desc[scsi_curr_dev], 4462e192b24SSimon Glass blk, cnt, (ulong *)addr); 447*f1d4d937SSimon Glass printf("%ld blocks read: %s\n", n, 448*f1d4d937SSimon Glass n == cnt ? "OK" : "ERROR"); 4492e192b24SSimon Glass return 0; 4502e192b24SSimon Glass } else if (strcmp(argv[1], "write") == 0) { 4512e192b24SSimon Glass ulong addr = simple_strtoul(argv[2], NULL, 16); 4522e192b24SSimon Glass ulong blk = simple_strtoul(argv[3], NULL, 16); 4532e192b24SSimon Glass ulong cnt = simple_strtoul(argv[4], NULL, 16); 4542e192b24SSimon Glass ulong n; 455*f1d4d937SSimon Glass printf("\nSCSI write: device %d block # %ld, count %ld ... ", 4562e192b24SSimon Glass scsi_curr_dev, blk, cnt); 4572e192b24SSimon Glass n = scsi_write(&scsi_dev_desc[scsi_curr_dev], 4582e192b24SSimon Glass blk, cnt, (ulong *)addr); 4592e192b24SSimon Glass printf("%ld blocks written: %s\n", n, 460*f1d4d937SSimon Glass n == cnt ? "OK" : "ERROR"); 4612e192b24SSimon Glass return 0; 4622e192b24SSimon Glass } 4632e192b24SSimon Glass } /* switch */ 4642e192b24SSimon Glass return CMD_RET_USAGE; 4652e192b24SSimon Glass } 4662e192b24SSimon Glass 467ba524269STom Rini U_BOOT_CMD( 468ba524269STom Rini scsi, 5, 1, do_scsi, 469ba524269STom Rini "SCSI sub-system", 470ba524269STom Rini "reset - reset SCSI controller\n" 471ba524269STom Rini "scsi info - show available SCSI devices\n" 472ba524269STom Rini "scsi scan - (re-)scan SCSI bus\n" 473ba524269STom Rini "scsi device [dev] - show or set current device\n" 474ba524269STom Rini "scsi part [dev] - print partition table of one or all SCSI devices\n" 475ba524269STom Rini "scsi read addr blk# cnt - read `cnt' blocks starting at block `blk#'\n" 476ba524269STom Rini " to memory address `addr'\n" 477ba524269STom Rini "scsi write addr blk# cnt - write `cnt' blocks starting at block\n" 478ba524269STom Rini " `blk#' from memory address `addr'" 479ba524269STom Rini ); 480ba524269STom Rini 481ba524269STom Rini U_BOOT_CMD( 482ba524269STom Rini scsiboot, 3, 1, do_scsiboot, 483ba524269STom Rini "boot from SCSI device", 484ba524269STom Rini "loadAddr dev:part" 485ba524269STom Rini ); 486ba524269STom Rini #endif 487ba524269STom Rini 4882e192b24SSimon Glass /* copy src to dest, skipping leading and trailing blanks 4892e192b24SSimon Glass * and null terminate the string 4902e192b24SSimon Glass */ 4912e192b24SSimon Glass void scsi_ident_cpy(unsigned char *dest, unsigned char *src, unsigned int len) 4922e192b24SSimon Glass { 4932e192b24SSimon Glass int start,end; 4942e192b24SSimon Glass 4952e192b24SSimon Glass start = 0; 4962e192b24SSimon Glass while (start < len) { 4972e192b24SSimon Glass if (src[start] != ' ') 4982e192b24SSimon Glass break; 4992e192b24SSimon Glass start++; 5002e192b24SSimon Glass } 5012e192b24SSimon Glass end = len-1; 5022e192b24SSimon Glass while (end > start) { 5032e192b24SSimon Glass if (src[end] != ' ') 5042e192b24SSimon Glass break; 5052e192b24SSimon Glass end--; 5062e192b24SSimon Glass } 507*f1d4d937SSimon Glass for (; start <= end; start++) 5082e192b24SSimon Glass *dest ++= src[start]; 5092e192b24SSimon Glass *dest='\0'; 5102e192b24SSimon Glass } 5112e192b24SSimon Glass 5122e192b24SSimon Glass 5132e192b24SSimon Glass /* Trim trailing blanks, and NUL-terminate string 5142e192b24SSimon Glass */ 5152e192b24SSimon Glass void scsi_trim_trail (unsigned char *str, unsigned int len) 5162e192b24SSimon Glass { 5172e192b24SSimon Glass unsigned char *p = str + len - 1; 5182e192b24SSimon Glass 5192e192b24SSimon Glass while (len-- > 0) { 5202e192b24SSimon Glass *p-- = '\0'; 5212e192b24SSimon Glass if (*p != ' ') { 5222e192b24SSimon Glass return; 5232e192b24SSimon Glass } 5242e192b24SSimon Glass } 5252e192b24SSimon Glass } 5262e192b24SSimon Glass 5272e192b24SSimon Glass int scsi_read_capacity(ccb *pccb, lbaint_t *capacity, unsigned long *blksz) 5282e192b24SSimon Glass { 5292e192b24SSimon Glass *capacity = 0; 5302e192b24SSimon Glass 531*f1d4d937SSimon Glass memset(pccb->cmd, '\0', sizeof(pccb->cmd)); 5322e192b24SSimon Glass pccb->cmd[0] = SCSI_RD_CAPAC10; 5332e192b24SSimon Glass pccb->cmd[1] = pccb->lun << 5; 5342e192b24SSimon Glass pccb->cmdlen = 10; 5352e192b24SSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 5362e192b24SSimon Glass 5372e192b24SSimon Glass pccb->datalen = 8; 5382e192b24SSimon Glass if (scsi_exec(pccb) != true) 5392e192b24SSimon Glass return 1; 5402e192b24SSimon Glass 5412e192b24SSimon Glass *capacity = ((lbaint_t)pccb->pdata[0] << 24) | 5422e192b24SSimon Glass ((lbaint_t)pccb->pdata[1] << 16) | 5432e192b24SSimon Glass ((lbaint_t)pccb->pdata[2] << 8) | 5442e192b24SSimon Glass ((lbaint_t)pccb->pdata[3]); 5452e192b24SSimon Glass 5462e192b24SSimon Glass if (*capacity != 0xffffffff) { 5472e192b24SSimon Glass /* Read capacity (10) was sufficient for this drive. */ 5482e192b24SSimon Glass *blksz = ((unsigned long)pccb->pdata[4] << 24) | 5492e192b24SSimon Glass ((unsigned long)pccb->pdata[5] << 16) | 5502e192b24SSimon Glass ((unsigned long)pccb->pdata[6] << 8) | 5512e192b24SSimon Glass ((unsigned long)pccb->pdata[7]); 5522e192b24SSimon Glass return 0; 5532e192b24SSimon Glass } 5542e192b24SSimon Glass 5552e192b24SSimon Glass /* Read capacity (10) was insufficient. Use read capacity (16). */ 556*f1d4d937SSimon Glass memset(pccb->cmd, '\0', sizeof(pccb->cmd)); 5572e192b24SSimon Glass pccb->cmd[0] = SCSI_RD_CAPAC16; 5582e192b24SSimon Glass pccb->cmd[1] = 0x10; 5592e192b24SSimon Glass pccb->cmdlen = 16; 5602e192b24SSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 5612e192b24SSimon Glass 5622e192b24SSimon Glass pccb->datalen = 16; 5632e192b24SSimon Glass if (scsi_exec(pccb) != true) 5642e192b24SSimon Glass return 1; 5652e192b24SSimon Glass 5662e192b24SSimon Glass *capacity = ((uint64_t)pccb->pdata[0] << 56) | 5672e192b24SSimon Glass ((uint64_t)pccb->pdata[1] << 48) | 5682e192b24SSimon Glass ((uint64_t)pccb->pdata[2] << 40) | 5692e192b24SSimon Glass ((uint64_t)pccb->pdata[3] << 32) | 5702e192b24SSimon Glass ((uint64_t)pccb->pdata[4] << 24) | 5712e192b24SSimon Glass ((uint64_t)pccb->pdata[5] << 16) | 5722e192b24SSimon Glass ((uint64_t)pccb->pdata[6] << 8) | 5732e192b24SSimon Glass ((uint64_t)pccb->pdata[7]); 5742e192b24SSimon Glass 5752e192b24SSimon Glass *blksz = ((uint64_t)pccb->pdata[8] << 56) | 5762e192b24SSimon Glass ((uint64_t)pccb->pdata[9] << 48) | 5772e192b24SSimon Glass ((uint64_t)pccb->pdata[10] << 40) | 5782e192b24SSimon Glass ((uint64_t)pccb->pdata[11] << 32) | 5792e192b24SSimon Glass ((uint64_t)pccb->pdata[12] << 24) | 5802e192b24SSimon Glass ((uint64_t)pccb->pdata[13] << 16) | 5812e192b24SSimon Glass ((uint64_t)pccb->pdata[14] << 8) | 5822e192b24SSimon Glass ((uint64_t)pccb->pdata[15]); 5832e192b24SSimon Glass 5842e192b24SSimon Glass return 0; 5852e192b24SSimon Glass } 5862e192b24SSimon Glass 5872e192b24SSimon Glass 5882e192b24SSimon Glass /************************************************************************************ 5892e192b24SSimon Glass * Some setup (fill-in) routines 5902e192b24SSimon Glass */ 5912e192b24SSimon Glass void scsi_setup_test_unit_ready(ccb * pccb) 5922e192b24SSimon Glass { 5932e192b24SSimon Glass pccb->cmd[0] = SCSI_TST_U_RDY; 5942e192b24SSimon Glass pccb->cmd[1] = pccb->lun << 5; 5952e192b24SSimon Glass pccb->cmd[2] = 0; 5962e192b24SSimon Glass pccb->cmd[3] = 0; 5972e192b24SSimon Glass pccb->cmd[4] = 0; 5982e192b24SSimon Glass pccb->cmd[5] = 0; 5992e192b24SSimon Glass pccb->cmdlen = 6; 6002e192b24SSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 6012e192b24SSimon Glass } 6022e192b24SSimon Glass 60373a9cfdeSSimon Glass /********************************************************************************* 60473a9cfdeSSimon Glass * (re)-scan the scsi bus and reports scsi device info 60573a9cfdeSSimon Glass * to the user if mode = 1 60673a9cfdeSSimon Glass */ 60773a9cfdeSSimon Glass void scsi_scan(int mode) 6082e192b24SSimon Glass { 60973a9cfdeSSimon Glass unsigned char i,perq,modi,lun; 61073a9cfdeSSimon Glass lbaint_t capacity; 61173a9cfdeSSimon Glass unsigned long blksz; 61273a9cfdeSSimon Glass ccb* pccb=(ccb *)&tempccb; 61373a9cfdeSSimon Glass 614*f1d4d937SSimon Glass if (mode == 1) 61573a9cfdeSSimon Glass printf("scanning bus for devices...\n"); 61673a9cfdeSSimon Glass for (i = 0; i < CONFIG_SYS_SCSI_MAX_DEVICE; i++) { 61773a9cfdeSSimon Glass scsi_dev_desc[i].target = 0xff; 61873a9cfdeSSimon Glass scsi_dev_desc[i].lun = 0xff; 61973a9cfdeSSimon Glass scsi_dev_desc[i].lba = 0; 62073a9cfdeSSimon Glass scsi_dev_desc[i].blksz = 0; 62173a9cfdeSSimon Glass scsi_dev_desc[i].log2blksz = 62273a9cfdeSSimon Glass LOG2_INVALID(typeof(scsi_dev_desc[i].log2blksz)); 62373a9cfdeSSimon Glass scsi_dev_desc[i].type = DEV_TYPE_UNKNOWN; 62473a9cfdeSSimon Glass scsi_dev_desc[i].vendor[0] = 0; 62573a9cfdeSSimon Glass scsi_dev_desc[i].product[0] = 0; 62673a9cfdeSSimon Glass scsi_dev_desc[i].revision[0] = 0; 62773a9cfdeSSimon Glass scsi_dev_desc[i].removable = false; 62873a9cfdeSSimon Glass scsi_dev_desc[i].if_type = IF_TYPE_SCSI; 62973a9cfdeSSimon Glass scsi_dev_desc[i].devnum = i; 63073a9cfdeSSimon Glass scsi_dev_desc[i].part_type = PART_TYPE_UNKNOWN; 63173a9cfdeSSimon Glass scsi_dev_desc[i].block_read = scsi_read; 63273a9cfdeSSimon Glass scsi_dev_desc[i].block_write = scsi_write; 6332e192b24SSimon Glass } 63473a9cfdeSSimon Glass scsi_max_devs = 0; 63573a9cfdeSSimon Glass for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { 63673a9cfdeSSimon Glass pccb->target = i; 63773a9cfdeSSimon Glass for (lun = 0; lun < CONFIG_SYS_SCSI_MAX_LUN; lun++) { 63873a9cfdeSSimon Glass pccb->lun = lun; 63973a9cfdeSSimon Glass pccb->pdata = (unsigned char *)&tempbuff; 64073a9cfdeSSimon Glass pccb->datalen = 512; 64173a9cfdeSSimon Glass scsi_setup_inquiry(pccb); 64273a9cfdeSSimon Glass if (scsi_exec(pccb) != true) { 64373a9cfdeSSimon Glass if(pccb->contr_stat==SCSI_SEL_TIME_OUT) { 644*f1d4d937SSimon Glass debug("Selection timeout ID %d\n", 645*f1d4d937SSimon Glass pccb->target); 64673a9cfdeSSimon Glass continue; /* selection timeout => assuming no device present */ 6472e192b24SSimon Glass } 64873a9cfdeSSimon Glass scsi_print_error(pccb); 64973a9cfdeSSimon Glass continue; 6502e192b24SSimon Glass } 65173a9cfdeSSimon Glass perq = tempbuff[0]; 65273a9cfdeSSimon Glass modi = tempbuff[1]; 653*f1d4d937SSimon Glass if ((perq & 0x1f) == 0x1f) 65473a9cfdeSSimon Glass continue; /* skip unknown devices */ 65573a9cfdeSSimon Glass if ((modi & 0x80) == 0x80) /* drive is removable */ 65673a9cfdeSSimon Glass scsi_dev_desc[scsi_max_devs].removable = true; 65773a9cfdeSSimon Glass /* get info for this device */ 65873a9cfdeSSimon Glass scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].vendor[0], 65973a9cfdeSSimon Glass &tempbuff[8], 8); 66073a9cfdeSSimon Glass scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].product[0], 66173a9cfdeSSimon Glass &tempbuff[16], 16); 66273a9cfdeSSimon Glass scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].revision[0], 66373a9cfdeSSimon Glass &tempbuff[32], 4); 66473a9cfdeSSimon Glass scsi_dev_desc[scsi_max_devs].target = pccb->target; 66573a9cfdeSSimon Glass scsi_dev_desc[scsi_max_devs].lun = pccb->lun; 6662e192b24SSimon Glass 66773a9cfdeSSimon Glass pccb->datalen = 0; 66873a9cfdeSSimon Glass scsi_setup_test_unit_ready(pccb); 66973a9cfdeSSimon Glass if (scsi_exec(pccb) != true) { 670*f1d4d937SSimon Glass if (scsi_dev_desc[scsi_max_devs].removable) { 671*f1d4d937SSimon Glass scsi_dev_desc[scsi_max_devs].type = 672*f1d4d937SSimon Glass perq; 67373a9cfdeSSimon Glass goto removable; 67473a9cfdeSSimon Glass } 67573a9cfdeSSimon Glass scsi_print_error(pccb); 67673a9cfdeSSimon Glass continue; 67773a9cfdeSSimon Glass } 67873a9cfdeSSimon Glass if (scsi_read_capacity(pccb, &capacity, &blksz)) { 67973a9cfdeSSimon Glass scsi_print_error(pccb); 68073a9cfdeSSimon Glass continue; 68173a9cfdeSSimon Glass } 68273a9cfdeSSimon Glass scsi_dev_desc[scsi_max_devs].lba = capacity; 68373a9cfdeSSimon Glass scsi_dev_desc[scsi_max_devs].blksz = blksz; 68473a9cfdeSSimon Glass scsi_dev_desc[scsi_max_devs].log2blksz = 68573a9cfdeSSimon Glass LOG2(scsi_dev_desc[scsi_max_devs].blksz); 68673a9cfdeSSimon Glass scsi_dev_desc[scsi_max_devs].type = perq; 68773a9cfdeSSimon Glass part_init(&scsi_dev_desc[scsi_max_devs]); 68873a9cfdeSSimon Glass removable: 68973a9cfdeSSimon Glass if(mode==1) { 69073a9cfdeSSimon Glass printf (" Device %d: ", scsi_max_devs); 69173a9cfdeSSimon Glass dev_print(&scsi_dev_desc[scsi_max_devs]); 69273a9cfdeSSimon Glass } /* if mode */ 69373a9cfdeSSimon Glass scsi_max_devs++; 69473a9cfdeSSimon Glass } /* next LUN */ 69573a9cfdeSSimon Glass } 69673a9cfdeSSimon Glass if (scsi_max_devs > 0) 69773a9cfdeSSimon Glass scsi_curr_dev = 0; 6982e192b24SSimon Glass else 69973a9cfdeSSimon Glass scsi_curr_dev = -1; 70073a9cfdeSSimon Glass 70173a9cfdeSSimon Glass printf("Found %d device(s).\n", scsi_max_devs); 70273a9cfdeSSimon Glass #ifndef CONFIG_SPL_BUILD 70373a9cfdeSSimon Glass setenv_ulong("scsidevs", scsi_max_devs); 70473a9cfdeSSimon Glass #endif 7052e192b24SSimon Glass } 706