xref: /openbmc/u-boot/drivers/scsi/scsi.c (revision c507d306)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
20fcd48feSSimon Glass /*
30fcd48feSSimon Glass  * (C) Copyright 2001
40fcd48feSSimon Glass  * Denis Peter, MPL AG Switzerland
50fcd48feSSimon Glass  */
60fcd48feSSimon Glass 
70fcd48feSSimon Glass #include <common.h>
80fcd48feSSimon Glass #include <dm.h>
90fcd48feSSimon Glass #include <pci.h>
100fcd48feSSimon Glass #include <scsi.h>
110fcd48feSSimon Glass #include <dm/device-internal.h>
120fcd48feSSimon Glass #include <dm/uclass-internal.h>
130fcd48feSSimon Glass 
140fcd48feSSimon Glass #if !defined(CONFIG_DM_SCSI)
150fcd48feSSimon Glass # ifdef CONFIG_SCSI_DEV_LIST
160fcd48feSSimon Glass #  define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST
170fcd48feSSimon Glass # else
180fcd48feSSimon Glass #  ifdef CONFIG_SATA_ULI5288
190fcd48feSSimon Glass 
200fcd48feSSimon Glass #   define SCSI_VEND_ID 0x10b9
210fcd48feSSimon Glass #   define SCSI_DEV_ID  0x5288
220fcd48feSSimon Glass 
230fcd48feSSimon Glass #  elif !defined(CONFIG_SCSI_AHCI_PLAT)
240fcd48feSSimon Glass #   error no scsi device defined
250fcd48feSSimon Glass #  endif
260fcd48feSSimon Glass # define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID}
270fcd48feSSimon Glass # endif
280fcd48feSSimon Glass #endif
290fcd48feSSimon Glass 
307337fcd8SSimon Glass #if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) && \
317337fcd8SSimon Glass 	!defined(CONFIG_DM_SCSI)
320fcd48feSSimon Glass const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST };
330fcd48feSSimon Glass #endif
34b9560ad6SSimon Glass static struct scsi_cmd tempccb;	/* temporary scsi command buffer */
350fcd48feSSimon Glass 
360fcd48feSSimon Glass static unsigned char tempbuff[512]; /* temporary data buffer */
370fcd48feSSimon Glass 
380fcd48feSSimon Glass #if !defined(CONFIG_DM_SCSI)
390fcd48feSSimon Glass static int scsi_max_devs; /* number of highest available scsi device */
400fcd48feSSimon Glass 
410fcd48feSSimon Glass static int scsi_curr_dev; /* current device */
420fcd48feSSimon Glass 
430fcd48feSSimon Glass static struct blk_desc scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE];
440fcd48feSSimon Glass #endif
450fcd48feSSimon Glass 
460fcd48feSSimon Glass /* almost the maximum amount of the scsi_ext command.. */
470fcd48feSSimon Glass #define SCSI_MAX_READ_BLK 0xFFFF
480fcd48feSSimon Glass #define SCSI_LBA48_READ	0xFFFFFFF
490fcd48feSSimon Glass 
scsi_print_error(struct scsi_cmd * pccb)50b9560ad6SSimon Glass static void scsi_print_error(struct scsi_cmd *pccb)
510fcd48feSSimon Glass {
520fcd48feSSimon Glass 	/* Dummy function that could print an error for debugging */
530fcd48feSSimon Glass }
540fcd48feSSimon Glass 
550fcd48feSSimon Glass #ifdef CONFIG_SYS_64BIT_LBA
scsi_setup_read16(struct scsi_cmd * pccb,lbaint_t start,unsigned long blocks)56b9560ad6SSimon Glass void scsi_setup_read16(struct scsi_cmd *pccb, lbaint_t start,
57b9560ad6SSimon Glass 		       unsigned long blocks)
580fcd48feSSimon Glass {
590fcd48feSSimon Glass 	pccb->cmd[0] = SCSI_READ16;
600fcd48feSSimon Glass 	pccb->cmd[1] = pccb->lun << 5;
610fcd48feSSimon Glass 	pccb->cmd[2] = (unsigned char)(start >> 56) & 0xff;
620fcd48feSSimon Glass 	pccb->cmd[3] = (unsigned char)(start >> 48) & 0xff;
630fcd48feSSimon Glass 	pccb->cmd[4] = (unsigned char)(start >> 40) & 0xff;
640fcd48feSSimon Glass 	pccb->cmd[5] = (unsigned char)(start >> 32) & 0xff;
650fcd48feSSimon Glass 	pccb->cmd[6] = (unsigned char)(start >> 24) & 0xff;
660fcd48feSSimon Glass 	pccb->cmd[7] = (unsigned char)(start >> 16) & 0xff;
670fcd48feSSimon Glass 	pccb->cmd[8] = (unsigned char)(start >> 8) & 0xff;
680fcd48feSSimon Glass 	pccb->cmd[9] = (unsigned char)start & 0xff;
690fcd48feSSimon Glass 	pccb->cmd[10] = 0;
700fcd48feSSimon Glass 	pccb->cmd[11] = (unsigned char)(blocks >> 24) & 0xff;
710fcd48feSSimon Glass 	pccb->cmd[12] = (unsigned char)(blocks >> 16) & 0xff;
720fcd48feSSimon Glass 	pccb->cmd[13] = (unsigned char)(blocks >> 8) & 0xff;
730fcd48feSSimon Glass 	pccb->cmd[14] = (unsigned char)blocks & 0xff;
740fcd48feSSimon Glass 	pccb->cmd[15] = 0;
750fcd48feSSimon Glass 	pccb->cmdlen = 16;
760fcd48feSSimon Glass 	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
770fcd48feSSimon Glass 	debug("scsi_setup_read16: cmd: %02X %02X startblk %02X%02X%02X%02X%02X%02X%02X%02X blccnt %02X%02X%02X%02X\n",
780fcd48feSSimon Glass 	      pccb->cmd[0], pccb->cmd[1],
790fcd48feSSimon Glass 	      pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
800fcd48feSSimon Glass 	      pccb->cmd[6], pccb->cmd[7], pccb->cmd[8], pccb->cmd[9],
810fcd48feSSimon Glass 	      pccb->cmd[11], pccb->cmd[12], pccb->cmd[13], pccb->cmd[14]);
820fcd48feSSimon Glass }
830fcd48feSSimon Glass #endif
840fcd48feSSimon Glass 
scsi_setup_read_ext(struct scsi_cmd * pccb,lbaint_t start,unsigned short blocks)85b9560ad6SSimon Glass static void scsi_setup_read_ext(struct scsi_cmd *pccb, lbaint_t start,
860fcd48feSSimon Glass 				unsigned short blocks)
870fcd48feSSimon Glass {
880fcd48feSSimon Glass 	pccb->cmd[0] = SCSI_READ10;
890fcd48feSSimon Glass 	pccb->cmd[1] = pccb->lun << 5;
900fcd48feSSimon Glass 	pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff;
910fcd48feSSimon Glass 	pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff;
920fcd48feSSimon Glass 	pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff;
930fcd48feSSimon Glass 	pccb->cmd[5] = (unsigned char)start & 0xff;
940fcd48feSSimon Glass 	pccb->cmd[6] = 0;
950fcd48feSSimon Glass 	pccb->cmd[7] = (unsigned char)(blocks >> 8) & 0xff;
960fcd48feSSimon Glass 	pccb->cmd[8] = (unsigned char)blocks & 0xff;
970fcd48feSSimon Glass 	pccb->cmd[6] = 0;
980fcd48feSSimon Glass 	pccb->cmdlen = 10;
990fcd48feSSimon Glass 	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
1000fcd48feSSimon Glass 	debug("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n",
1010fcd48feSSimon Glass 	      pccb->cmd[0], pccb->cmd[1],
1020fcd48feSSimon Glass 	      pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
1030fcd48feSSimon Glass 	      pccb->cmd[7], pccb->cmd[8]);
1040fcd48feSSimon Glass }
1050fcd48feSSimon Glass 
scsi_setup_write_ext(struct scsi_cmd * pccb,lbaint_t start,unsigned short blocks)106b9560ad6SSimon Glass static void scsi_setup_write_ext(struct scsi_cmd *pccb, lbaint_t start,
1070fcd48feSSimon Glass 				 unsigned short blocks)
1080fcd48feSSimon Glass {
1090fcd48feSSimon Glass 	pccb->cmd[0] = SCSI_WRITE10;
1100fcd48feSSimon Glass 	pccb->cmd[1] = pccb->lun << 5;
1110fcd48feSSimon Glass 	pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff;
1120fcd48feSSimon Glass 	pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff;
1130fcd48feSSimon Glass 	pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff;
1140fcd48feSSimon Glass 	pccb->cmd[5] = (unsigned char)start & 0xff;
1150fcd48feSSimon Glass 	pccb->cmd[6] = 0;
1160fcd48feSSimon Glass 	pccb->cmd[7] = ((unsigned char)(blocks >> 8)) & 0xff;
1170fcd48feSSimon Glass 	pccb->cmd[8] = (unsigned char)blocks & 0xff;
1180fcd48feSSimon Glass 	pccb->cmd[9] = 0;
1190fcd48feSSimon Glass 	pccb->cmdlen = 10;
1200fcd48feSSimon Glass 	pccb->msgout[0] = SCSI_IDENTIFY;  /* NOT USED */
1210fcd48feSSimon Glass 	debug("%s: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n",
1220fcd48feSSimon Glass 	      __func__,
1230fcd48feSSimon Glass 	      pccb->cmd[0], pccb->cmd[1],
1240fcd48feSSimon Glass 	      pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
1250fcd48feSSimon Glass 	      pccb->cmd[7], pccb->cmd[8]);
1260fcd48feSSimon Glass }
1270fcd48feSSimon Glass 
scsi_setup_inquiry(struct scsi_cmd * pccb)128b9560ad6SSimon Glass static void scsi_setup_inquiry(struct scsi_cmd *pccb)
1290fcd48feSSimon Glass {
1300fcd48feSSimon Glass 	pccb->cmd[0] = SCSI_INQUIRY;
1310fcd48feSSimon Glass 	pccb->cmd[1] = pccb->lun << 5;
1320fcd48feSSimon Glass 	pccb->cmd[2] = 0;
1330fcd48feSSimon Glass 	pccb->cmd[3] = 0;
1340fcd48feSSimon Glass 	if (pccb->datalen > 255)
1350fcd48feSSimon Glass 		pccb->cmd[4] = 255;
1360fcd48feSSimon Glass 	else
1370fcd48feSSimon Glass 		pccb->cmd[4] = (unsigned char)pccb->datalen;
1380fcd48feSSimon Glass 	pccb->cmd[5] = 0;
1390fcd48feSSimon Glass 	pccb->cmdlen = 6;
1400fcd48feSSimon Glass 	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
1410fcd48feSSimon Glass }
1420fcd48feSSimon Glass 
1430fcd48feSSimon Glass #ifdef CONFIG_BLK
scsi_read(struct udevice * dev,lbaint_t blknr,lbaint_t blkcnt,void * buffer)1440fcd48feSSimon Glass static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
1450fcd48feSSimon Glass 		       void *buffer)
1460fcd48feSSimon Glass #else
1470fcd48feSSimon Glass static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr,
1480fcd48feSSimon Glass 		       lbaint_t blkcnt, void *buffer)
1490fcd48feSSimon Glass #endif
1500fcd48feSSimon Glass {
1510fcd48feSSimon Glass #ifdef CONFIG_BLK
1520fcd48feSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
1534682c8a1SSimon Glass 	struct udevice *bdev = dev->parent;
1544682c8a1SSimon Glass #else
1554682c8a1SSimon Glass 	struct udevice *bdev = NULL;
1560fcd48feSSimon Glass #endif
1570fcd48feSSimon Glass 	lbaint_t start, blks;
1580fcd48feSSimon Glass 	uintptr_t buf_addr;
1590fcd48feSSimon Glass 	unsigned short smallblks = 0;
160b9560ad6SSimon Glass 	struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;
1610fcd48feSSimon Glass 
1620fcd48feSSimon Glass 	/* Setup device */
1630fcd48feSSimon Glass 	pccb->target = block_dev->target;
1640fcd48feSSimon Glass 	pccb->lun = block_dev->lun;
1650fcd48feSSimon Glass 	buf_addr = (unsigned long)buffer;
1660fcd48feSSimon Glass 	start = blknr;
1670fcd48feSSimon Glass 	blks = blkcnt;
1680fcd48feSSimon Glass 	debug("\nscsi_read: dev %d startblk " LBAF
1690fcd48feSSimon Glass 	      ", blccnt " LBAF " buffer %lx\n",
1700fcd48feSSimon Glass 	      block_dev->devnum, start, blks, (unsigned long)buffer);
1710fcd48feSSimon Glass 	do {
1720fcd48feSSimon Glass 		pccb->pdata = (unsigned char *)buf_addr;
1730fcd48feSSimon Glass #ifdef CONFIG_SYS_64BIT_LBA
1740fcd48feSSimon Glass 		if (start > SCSI_LBA48_READ) {
1750fcd48feSSimon Glass 			unsigned long blocks;
1760fcd48feSSimon Glass 			blocks = min_t(lbaint_t, blks, SCSI_MAX_READ_BLK);
1770fcd48feSSimon Glass 			pccb->datalen = block_dev->blksz * blocks;
1780fcd48feSSimon Glass 			scsi_setup_read16(pccb, start, blocks);
1790fcd48feSSimon Glass 			start += blocks;
1800fcd48feSSimon Glass 			blks -= blocks;
1810fcd48feSSimon Glass 		} else
1820fcd48feSSimon Glass #endif
1830fcd48feSSimon Glass 		if (blks > SCSI_MAX_READ_BLK) {
1840fcd48feSSimon Glass 			pccb->datalen = block_dev->blksz *
1850fcd48feSSimon Glass 				SCSI_MAX_READ_BLK;
1860fcd48feSSimon Glass 			smallblks = SCSI_MAX_READ_BLK;
1870fcd48feSSimon Glass 			scsi_setup_read_ext(pccb, start, smallblks);
1880fcd48feSSimon Glass 			start += SCSI_MAX_READ_BLK;
1890fcd48feSSimon Glass 			blks -= SCSI_MAX_READ_BLK;
1900fcd48feSSimon Glass 		} else {
1910fcd48feSSimon Glass 			pccb->datalen = block_dev->blksz * blks;
1920fcd48feSSimon Glass 			smallblks = (unsigned short)blks;
1930fcd48feSSimon Glass 			scsi_setup_read_ext(pccb, start, smallblks);
1940fcd48feSSimon Glass 			start += blks;
1950fcd48feSSimon Glass 			blks = 0;
1960fcd48feSSimon Glass 		}
1970fcd48feSSimon Glass 		debug("scsi_read_ext: startblk " LBAF
198dee37fc9SMasahiro Yamada 		      ", blccnt %x buffer %lX\n",
1990fcd48feSSimon Glass 		      start, smallblks, buf_addr);
2004682c8a1SSimon Glass 		if (scsi_exec(bdev, pccb)) {
2010fcd48feSSimon Glass 			scsi_print_error(pccb);
2020fcd48feSSimon Glass 			blkcnt -= blks;
2030fcd48feSSimon Glass 			break;
2040fcd48feSSimon Glass 		}
2050fcd48feSSimon Glass 		buf_addr += pccb->datalen;
2060fcd48feSSimon Glass 	} while (blks != 0);
2070fcd48feSSimon Glass 	debug("scsi_read_ext: end startblk " LBAF
208dee37fc9SMasahiro Yamada 	      ", blccnt %x buffer %lX\n", start, smallblks, buf_addr);
2090fcd48feSSimon Glass 	return blkcnt;
2100fcd48feSSimon Glass }
2110fcd48feSSimon Glass 
2120fcd48feSSimon Glass /*******************************************************************************
2130fcd48feSSimon Glass  * scsi_write
2140fcd48feSSimon Glass  */
2150fcd48feSSimon Glass 
2160fcd48feSSimon Glass /* Almost the maximum amount of the scsi_ext command.. */
2170fcd48feSSimon Glass #define SCSI_MAX_WRITE_BLK 0xFFFF
2180fcd48feSSimon Glass 
2190fcd48feSSimon Glass #ifdef CONFIG_BLK
scsi_write(struct udevice * dev,lbaint_t blknr,lbaint_t blkcnt,const void * buffer)2200fcd48feSSimon Glass static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
2210fcd48feSSimon Glass 			const void *buffer)
2220fcd48feSSimon Glass #else
2230fcd48feSSimon Glass static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr,
2240fcd48feSSimon Glass 			lbaint_t blkcnt, const void *buffer)
2250fcd48feSSimon Glass #endif
2260fcd48feSSimon Glass {
2270fcd48feSSimon Glass #ifdef CONFIG_BLK
2280fcd48feSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
2294682c8a1SSimon Glass 	struct udevice *bdev = dev->parent;
2304682c8a1SSimon Glass #else
2314682c8a1SSimon Glass 	struct udevice *bdev = NULL;
2320fcd48feSSimon Glass #endif
2330fcd48feSSimon Glass 	lbaint_t start, blks;
2340fcd48feSSimon Glass 	uintptr_t buf_addr;
2350fcd48feSSimon Glass 	unsigned short smallblks;
236b9560ad6SSimon Glass 	struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;
2370fcd48feSSimon Glass 
2380fcd48feSSimon Glass 	/* Setup device */
2390fcd48feSSimon Glass 	pccb->target = block_dev->target;
2400fcd48feSSimon Glass 	pccb->lun = block_dev->lun;
2410fcd48feSSimon Glass 	buf_addr = (unsigned long)buffer;
2420fcd48feSSimon Glass 	start = blknr;
2430fcd48feSSimon Glass 	blks = blkcnt;
2440fcd48feSSimon Glass 	debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n",
2450fcd48feSSimon Glass 	      __func__, block_dev->devnum, start, blks, (unsigned long)buffer);
2460fcd48feSSimon Glass 	do {
2470fcd48feSSimon Glass 		pccb->pdata = (unsigned char *)buf_addr;
2480fcd48feSSimon Glass 		if (blks > SCSI_MAX_WRITE_BLK) {
2490fcd48feSSimon Glass 			pccb->datalen = (block_dev->blksz *
2500fcd48feSSimon Glass 					 SCSI_MAX_WRITE_BLK);
2510fcd48feSSimon Glass 			smallblks = SCSI_MAX_WRITE_BLK;
2520fcd48feSSimon Glass 			scsi_setup_write_ext(pccb, start, smallblks);
2530fcd48feSSimon Glass 			start += SCSI_MAX_WRITE_BLK;
2540fcd48feSSimon Glass 			blks -= SCSI_MAX_WRITE_BLK;
2550fcd48feSSimon Glass 		} else {
2560fcd48feSSimon Glass 			pccb->datalen = block_dev->blksz * blks;
2570fcd48feSSimon Glass 			smallblks = (unsigned short)blks;
2580fcd48feSSimon Glass 			scsi_setup_write_ext(pccb, start, smallblks);
2590fcd48feSSimon Glass 			start += blks;
2600fcd48feSSimon Glass 			blks = 0;
2610fcd48feSSimon Glass 		}
262dee37fc9SMasahiro Yamada 		debug("%s: startblk " LBAF ", blccnt %x buffer %lx\n",
2630fcd48feSSimon Glass 		      __func__, start, smallblks, buf_addr);
2644682c8a1SSimon Glass 		if (scsi_exec(bdev, pccb)) {
2650fcd48feSSimon Glass 			scsi_print_error(pccb);
2660fcd48feSSimon Glass 			blkcnt -= blks;
2670fcd48feSSimon Glass 			break;
2680fcd48feSSimon Glass 		}
2690fcd48feSSimon Glass 		buf_addr += pccb->datalen;
2700fcd48feSSimon Glass 	} while (blks != 0);
271dee37fc9SMasahiro Yamada 	debug("%s: end startblk " LBAF ", blccnt %x buffer %lX\n",
2720fcd48feSSimon Glass 	      __func__, start, smallblks, buf_addr);
2730fcd48feSSimon Glass 	return blkcnt;
2740fcd48feSSimon Glass }
2750fcd48feSSimon Glass 
2767337fcd8SSimon Glass #if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) && \
2777337fcd8SSimon Glass 	!defined(CONFIG_DM_SCSI)
scsi_init(void)2780fcd48feSSimon Glass void scsi_init(void)
2790fcd48feSSimon Glass {
2800fcd48feSSimon Glass 	int busdevfunc = -1;
2810fcd48feSSimon Glass 	int i;
2820fcd48feSSimon Glass 	/*
2830fcd48feSSimon Glass 	 * Find a device from the list, this driver will support a single
2840fcd48feSSimon Glass 	 * controller.
2850fcd48feSSimon Glass 	 */
2860fcd48feSSimon Glass 	for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
2870fcd48feSSimon Glass 		/* get PCI Device ID */
2880fcd48feSSimon Glass #ifdef CONFIG_DM_PCI
2890fcd48feSSimon Glass 		struct udevice *dev;
2900fcd48feSSimon Glass 		int ret;
2910fcd48feSSimon Glass 
2920fcd48feSSimon Glass 		ret = dm_pci_find_device(scsi_device_list[i].vendor,
2930fcd48feSSimon Glass 					 scsi_device_list[i].device, 0, &dev);
2940fcd48feSSimon Glass 		if (!ret) {
2950fcd48feSSimon Glass 			busdevfunc = dm_pci_get_bdf(dev);
2960fcd48feSSimon Glass 			break;
2970fcd48feSSimon Glass 		}
2980fcd48feSSimon Glass #else
2990fcd48feSSimon Glass 		busdevfunc = pci_find_device(scsi_device_list[i].vendor,
3000fcd48feSSimon Glass 					     scsi_device_list[i].device,
3010fcd48feSSimon Glass 					     0);
3020fcd48feSSimon Glass #endif
3030fcd48feSSimon Glass 		if (busdevfunc != -1)
3040fcd48feSSimon Glass 			break;
3050fcd48feSSimon Glass 	}
3060fcd48feSSimon Glass 
3070fcd48feSSimon Glass 	if (busdevfunc == -1) {
3080fcd48feSSimon Glass 		printf("Error: SCSI Controller(s) ");
3090fcd48feSSimon Glass 		for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
3100fcd48feSSimon Glass 			printf("%04X:%04X ",
3110fcd48feSSimon Glass 			       scsi_device_list[i].vendor,
3120fcd48feSSimon Glass 			       scsi_device_list[i].device);
3130fcd48feSSimon Glass 		}
3140fcd48feSSimon Glass 		printf("not found\n");
3150fcd48feSSimon Glass 		return;
3160fcd48feSSimon Glass 	}
3170fcd48feSSimon Glass #ifdef DEBUG
3180fcd48feSSimon Glass 	else {
3190fcd48feSSimon Glass 		printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n",
3200fcd48feSSimon Glass 		       scsi_device_list[i].vendor,
3210fcd48feSSimon Glass 		       scsi_device_list[i].device,
3220fcd48feSSimon Glass 		       (busdevfunc >> 16) & 0xFF,
3230fcd48feSSimon Glass 		       (busdevfunc >> 11) & 0x1F,
3240fcd48feSSimon Glass 		       (busdevfunc >> 8) & 0x7);
3250fcd48feSSimon Glass 	}
3260fcd48feSSimon Glass #endif
3270fcd48feSSimon Glass 	bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci");
3280fcd48feSSimon Glass 	scsi_low_level_init(busdevfunc);
3298eab1a58SSimon Glass 	scsi_scan(true);
3300fcd48feSSimon Glass 	bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI);
3310fcd48feSSimon Glass }
3320fcd48feSSimon Glass #endif
3330fcd48feSSimon Glass 
3340fcd48feSSimon Glass /* copy src to dest, skipping leading and trailing blanks
3350fcd48feSSimon Glass  * and null terminate the string
3360fcd48feSSimon Glass  */
scsi_ident_cpy(unsigned char * dest,unsigned char * src,unsigned int len)3370fcd48feSSimon Glass static void scsi_ident_cpy(unsigned char *dest, unsigned char *src,
3380fcd48feSSimon Glass 			   unsigned int len)
3390fcd48feSSimon Glass {
3400fcd48feSSimon Glass 	int start, end;
3410fcd48feSSimon Glass 
3420fcd48feSSimon Glass 	start = 0;
3430fcd48feSSimon Glass 	while (start < len) {
3440fcd48feSSimon Glass 		if (src[start] != ' ')
3450fcd48feSSimon Glass 			break;
3460fcd48feSSimon Glass 		start++;
3470fcd48feSSimon Glass 	}
3480fcd48feSSimon Glass 	end = len-1;
3490fcd48feSSimon Glass 	while (end > start) {
3500fcd48feSSimon Glass 		if (src[end] != ' ')
3510fcd48feSSimon Glass 			break;
3520fcd48feSSimon Glass 		end--;
3530fcd48feSSimon Glass 	}
3540fcd48feSSimon Glass 	for (; start <= end; start++)
3550fcd48feSSimon Glass 		*dest ++= src[start];
3560fcd48feSSimon Glass 	*dest = '\0';
3570fcd48feSSimon Glass }
3580fcd48feSSimon Glass 
scsi_read_capacity(struct udevice * dev,struct scsi_cmd * pccb,lbaint_t * capacity,unsigned long * blksz)3594682c8a1SSimon Glass static int scsi_read_capacity(struct udevice *dev, struct scsi_cmd *pccb,
3604682c8a1SSimon Glass 			      lbaint_t *capacity, unsigned long *blksz)
3610fcd48feSSimon Glass {
3620fcd48feSSimon Glass 	*capacity = 0;
3630fcd48feSSimon Glass 
3640fcd48feSSimon Glass 	memset(pccb->cmd, '\0', sizeof(pccb->cmd));
3650fcd48feSSimon Glass 	pccb->cmd[0] = SCSI_RD_CAPAC10;
3660fcd48feSSimon Glass 	pccb->cmd[1] = pccb->lun << 5;
3670fcd48feSSimon Glass 	pccb->cmdlen = 10;
3680fcd48feSSimon Glass 	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
3690fcd48feSSimon Glass 
3700fcd48feSSimon Glass 	pccb->datalen = 8;
371f6580ef3SSimon Glass 	if (scsi_exec(dev, pccb))
3720fcd48feSSimon Glass 		return 1;
3730fcd48feSSimon Glass 
3740fcd48feSSimon Glass 	*capacity = ((lbaint_t)pccb->pdata[0] << 24) |
3750fcd48feSSimon Glass 		    ((lbaint_t)pccb->pdata[1] << 16) |
3760fcd48feSSimon Glass 		    ((lbaint_t)pccb->pdata[2] << 8)  |
3770fcd48feSSimon Glass 		    ((lbaint_t)pccb->pdata[3]);
3780fcd48feSSimon Glass 
3790fcd48feSSimon Glass 	if (*capacity != 0xffffffff) {
3800fcd48feSSimon Glass 		/* Read capacity (10) was sufficient for this drive. */
3810fcd48feSSimon Glass 		*blksz = ((unsigned long)pccb->pdata[4] << 24) |
3820fcd48feSSimon Glass 			 ((unsigned long)pccb->pdata[5] << 16) |
3830fcd48feSSimon Glass 			 ((unsigned long)pccb->pdata[6] << 8)  |
3840fcd48feSSimon Glass 			 ((unsigned long)pccb->pdata[7]);
3850fcd48feSSimon Glass 		return 0;
3860fcd48feSSimon Glass 	}
3870fcd48feSSimon Glass 
3880fcd48feSSimon Glass 	/* Read capacity (10) was insufficient. Use read capacity (16). */
3890fcd48feSSimon Glass 	memset(pccb->cmd, '\0', sizeof(pccb->cmd));
3900fcd48feSSimon Glass 	pccb->cmd[0] = SCSI_RD_CAPAC16;
3910fcd48feSSimon Glass 	pccb->cmd[1] = 0x10;
3920fcd48feSSimon Glass 	pccb->cmdlen = 16;
3930fcd48feSSimon Glass 	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
3940fcd48feSSimon Glass 
3950fcd48feSSimon Glass 	pccb->datalen = 16;
396f6580ef3SSimon Glass 	if (scsi_exec(dev, pccb))
3970fcd48feSSimon Glass 		return 1;
3980fcd48feSSimon Glass 
3990fcd48feSSimon Glass 	*capacity = ((uint64_t)pccb->pdata[0] << 56) |
4000fcd48feSSimon Glass 		    ((uint64_t)pccb->pdata[1] << 48) |
4010fcd48feSSimon Glass 		    ((uint64_t)pccb->pdata[2] << 40) |
4020fcd48feSSimon Glass 		    ((uint64_t)pccb->pdata[3] << 32) |
4030fcd48feSSimon Glass 		    ((uint64_t)pccb->pdata[4] << 24) |
4040fcd48feSSimon Glass 		    ((uint64_t)pccb->pdata[5] << 16) |
4050fcd48feSSimon Glass 		    ((uint64_t)pccb->pdata[6] << 8)  |
4060fcd48feSSimon Glass 		    ((uint64_t)pccb->pdata[7]);
4070fcd48feSSimon Glass 
4080fcd48feSSimon Glass 	*blksz = ((uint64_t)pccb->pdata[8]  << 56) |
4090fcd48feSSimon Glass 		 ((uint64_t)pccb->pdata[9]  << 48) |
4100fcd48feSSimon Glass 		 ((uint64_t)pccb->pdata[10] << 40) |
4110fcd48feSSimon Glass 		 ((uint64_t)pccb->pdata[11] << 32) |
4120fcd48feSSimon Glass 		 ((uint64_t)pccb->pdata[12] << 24) |
4130fcd48feSSimon Glass 		 ((uint64_t)pccb->pdata[13] << 16) |
4140fcd48feSSimon Glass 		 ((uint64_t)pccb->pdata[14] << 8)  |
4150fcd48feSSimon Glass 		 ((uint64_t)pccb->pdata[15]);
4160fcd48feSSimon Glass 
4170fcd48feSSimon Glass 	return 0;
4180fcd48feSSimon Glass }
4190fcd48feSSimon Glass 
4200fcd48feSSimon Glass 
4210fcd48feSSimon Glass /*
4220fcd48feSSimon Glass  * Some setup (fill-in) routines
4230fcd48feSSimon Glass  */
scsi_setup_test_unit_ready(struct scsi_cmd * pccb)424b9560ad6SSimon Glass static void scsi_setup_test_unit_ready(struct scsi_cmd *pccb)
4250fcd48feSSimon Glass {
4260fcd48feSSimon Glass 	pccb->cmd[0] = SCSI_TST_U_RDY;
4270fcd48feSSimon Glass 	pccb->cmd[1] = pccb->lun << 5;
4280fcd48feSSimon Glass 	pccb->cmd[2] = 0;
4290fcd48feSSimon Glass 	pccb->cmd[3] = 0;
4300fcd48feSSimon Glass 	pccb->cmd[4] = 0;
4310fcd48feSSimon Glass 	pccb->cmd[5] = 0;
4320fcd48feSSimon Glass 	pccb->cmdlen = 6;
4330fcd48feSSimon Glass 	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
4340fcd48feSSimon Glass }
4350fcd48feSSimon Glass 
4360fcd48feSSimon Glass /**
4370fcd48feSSimon Glass  * scsi_init_dev_desc_priv - initialize only SCSI specific blk_desc properties
4380fcd48feSSimon Glass  *
4390fcd48feSSimon Glass  * @dev_desc: Block device description pointer
4400fcd48feSSimon Glass  */
scsi_init_dev_desc_priv(struct blk_desc * dev_desc)4410fcd48feSSimon Glass static void scsi_init_dev_desc_priv(struct blk_desc *dev_desc)
4420fcd48feSSimon Glass {
4430fcd48feSSimon Glass 	dev_desc->target = 0xff;
4440fcd48feSSimon Glass 	dev_desc->lun = 0xff;
4450fcd48feSSimon Glass 	dev_desc->log2blksz =
4460fcd48feSSimon Glass 		LOG2_INVALID(typeof(dev_desc->log2blksz));
4470fcd48feSSimon Glass 	dev_desc->type = DEV_TYPE_UNKNOWN;
4480fcd48feSSimon Glass 	dev_desc->vendor[0] = 0;
4490fcd48feSSimon Glass 	dev_desc->product[0] = 0;
4500fcd48feSSimon Glass 	dev_desc->revision[0] = 0;
4510fcd48feSSimon Glass 	dev_desc->removable = false;
452c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
4530fcd48feSSimon Glass 	dev_desc->block_read = scsi_read;
4540fcd48feSSimon Glass 	dev_desc->block_write = scsi_write;
4550fcd48feSSimon Glass #endif
4560fcd48feSSimon Glass }
4570fcd48feSSimon Glass 
4580fcd48feSSimon Glass #if !defined(CONFIG_DM_SCSI)
4590fcd48feSSimon Glass /**
4600fcd48feSSimon Glass  * scsi_init_dev_desc - initialize all SCSI specific blk_desc properties
4610fcd48feSSimon Glass  *
4620fcd48feSSimon Glass  * @dev_desc: Block device description pointer
4630fcd48feSSimon Glass  * @devnum: Device number
4640fcd48feSSimon Glass  */
scsi_init_dev_desc(struct blk_desc * dev_desc,int devnum)4650fcd48feSSimon Glass static void scsi_init_dev_desc(struct blk_desc *dev_desc, int devnum)
4660fcd48feSSimon Glass {
4670fcd48feSSimon Glass 	dev_desc->lba = 0;
4680fcd48feSSimon Glass 	dev_desc->blksz = 0;
4690fcd48feSSimon Glass 	dev_desc->if_type = IF_TYPE_SCSI;
4700fcd48feSSimon Glass 	dev_desc->devnum = devnum;
4710fcd48feSSimon Glass 	dev_desc->part_type = PART_TYPE_UNKNOWN;
4720fcd48feSSimon Glass 
4730fcd48feSSimon Glass 	scsi_init_dev_desc_priv(dev_desc);
4740fcd48feSSimon Glass }
4750fcd48feSSimon Glass #endif
4760fcd48feSSimon Glass 
4770fcd48feSSimon Glass /**
4780fcd48feSSimon Glass  * scsi_detect_dev - Detect scsi device
4790fcd48feSSimon Glass  *
4800fcd48feSSimon Glass  * @target: target id
4810fcd48feSSimon Glass  * @lun: target lun
4820fcd48feSSimon Glass  * @dev_desc: block device description
4830fcd48feSSimon Glass  *
4840fcd48feSSimon Glass  * The scsi_detect_dev detects and fills a dev_desc structure when the device is
4850fcd48feSSimon Glass  * detected.
4860fcd48feSSimon Glass  *
4870fcd48feSSimon Glass  * Return: 0 on success, error value otherwise
4880fcd48feSSimon Glass  */
scsi_detect_dev(struct udevice * dev,int target,int lun,struct blk_desc * dev_desc)4894682c8a1SSimon Glass static int scsi_detect_dev(struct udevice *dev, int target, int lun,
4904682c8a1SSimon Glass 			   struct blk_desc *dev_desc)
4910fcd48feSSimon Glass {
4920fcd48feSSimon Glass 	unsigned char perq, modi;
4930fcd48feSSimon Glass 	lbaint_t capacity;
4940fcd48feSSimon Glass 	unsigned long blksz;
495b9560ad6SSimon Glass 	struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;
4960fcd48feSSimon Glass 
4970fcd48feSSimon Glass 	pccb->target = target;
4980fcd48feSSimon Glass 	pccb->lun = lun;
4990fcd48feSSimon Glass 	pccb->pdata = (unsigned char *)&tempbuff;
5000fcd48feSSimon Glass 	pccb->datalen = 512;
5010fcd48feSSimon Glass 	scsi_setup_inquiry(pccb);
502f6580ef3SSimon Glass 	if (scsi_exec(dev, pccb)) {
5030fcd48feSSimon Glass 		if (pccb->contr_stat == SCSI_SEL_TIME_OUT) {
5040fcd48feSSimon Glass 			/*
5050fcd48feSSimon Glass 			  * selection timeout => assuming no
5060fcd48feSSimon Glass 			  * device present
5070fcd48feSSimon Glass 			  */
5080fcd48feSSimon Glass 			debug("Selection timeout ID %d\n",
5090fcd48feSSimon Glass 			      pccb->target);
5100fcd48feSSimon Glass 			return -ETIMEDOUT;
5110fcd48feSSimon Glass 		}
5120fcd48feSSimon Glass 		scsi_print_error(pccb);
5130fcd48feSSimon Glass 		return -ENODEV;
5140fcd48feSSimon Glass 	}
5150fcd48feSSimon Glass 	perq = tempbuff[0];
5160fcd48feSSimon Glass 	modi = tempbuff[1];
5170fcd48feSSimon Glass 	if ((perq & 0x1f) == 0x1f)
5180fcd48feSSimon Glass 		return -ENODEV; /* skip unknown devices */
5190fcd48feSSimon Glass 	if ((modi & 0x80) == 0x80) /* drive is removable */
5200fcd48feSSimon Glass 		dev_desc->removable = true;
5210fcd48feSSimon Glass 	/* get info for this device */
5220fcd48feSSimon Glass 	scsi_ident_cpy((unsigned char *)dev_desc->vendor,
5230fcd48feSSimon Glass 		       &tempbuff[8], 8);
5240fcd48feSSimon Glass 	scsi_ident_cpy((unsigned char *)dev_desc->product,
5250fcd48feSSimon Glass 		       &tempbuff[16], 16);
5260fcd48feSSimon Glass 	scsi_ident_cpy((unsigned char *)dev_desc->revision,
5270fcd48feSSimon Glass 		       &tempbuff[32], 4);
5280fcd48feSSimon Glass 	dev_desc->target = pccb->target;
5290fcd48feSSimon Glass 	dev_desc->lun = pccb->lun;
5300fcd48feSSimon Glass 
5310fcd48feSSimon Glass 	pccb->datalen = 0;
5320fcd48feSSimon Glass 	scsi_setup_test_unit_ready(pccb);
533f6580ef3SSimon Glass 	if (scsi_exec(dev, pccb)) {
5340fcd48feSSimon Glass 		if (dev_desc->removable) {
5350fcd48feSSimon Glass 			dev_desc->type = perq;
5360fcd48feSSimon Glass 			goto removable;
5370fcd48feSSimon Glass 		}
5380fcd48feSSimon Glass 		scsi_print_error(pccb);
5390fcd48feSSimon Glass 		return -EINVAL;
5400fcd48feSSimon Glass 	}
5414682c8a1SSimon Glass 	if (scsi_read_capacity(dev, pccb, &capacity, &blksz)) {
5420fcd48feSSimon Glass 		scsi_print_error(pccb);
5430fcd48feSSimon Glass 		return -EINVAL;
5440fcd48feSSimon Glass 	}
5450fcd48feSSimon Glass 	dev_desc->lba = capacity;
5460fcd48feSSimon Glass 	dev_desc->blksz = blksz;
5470fcd48feSSimon Glass 	dev_desc->log2blksz = LOG2(dev_desc->blksz);
5480fcd48feSSimon Glass 	dev_desc->type = perq;
5490fcd48feSSimon Glass removable:
5500fcd48feSSimon Glass 	return 0;
5510fcd48feSSimon Glass }
5520fcd48feSSimon Glass 
5530fcd48feSSimon Glass /*
5540fcd48feSSimon Glass  * (re)-scan the scsi bus and reports scsi device info
5550fcd48feSSimon Glass  * to the user if mode = 1
5560fcd48feSSimon Glass  */
5570fcd48feSSimon Glass #if defined(CONFIG_DM_SCSI)
do_scsi_scan_one(struct udevice * dev,int id,int lun,bool verbose)5588eab1a58SSimon Glass static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose)
5590fcd48feSSimon Glass {
5600fcd48feSSimon Glass 	int ret;
5610fcd48feSSimon Glass 	struct udevice *bdev;
5620fcd48feSSimon Glass 	struct blk_desc bd;
5630fcd48feSSimon Glass 	struct blk_desc *bdesc;
5640fcd48feSSimon Glass 	char str[10];
5650fcd48feSSimon Glass 
5660fcd48feSSimon Glass 	/*
5670fcd48feSSimon Glass 	 * detect the scsi driver to get information about its geometry (block
5680fcd48feSSimon Glass 	 * size, number of blocks) and other parameters (ids, type, ...)
5690fcd48feSSimon Glass 	 */
5700fcd48feSSimon Glass 	scsi_init_dev_desc_priv(&bd);
5714682c8a1SSimon Glass 	if (scsi_detect_dev(dev, id, lun, &bd))
5720fcd48feSSimon Glass 		return -ENODEV;
5730fcd48feSSimon Glass 
5740fcd48feSSimon Glass 	/*
5750fcd48feSSimon Glass 	* Create only one block device and do detection
5760fcd48feSSimon Glass 	* to make sure that there won't be a lot of
5770fcd48feSSimon Glass 	* block devices created
5780fcd48feSSimon Glass 	*/
5790fcd48feSSimon Glass 	snprintf(str, sizeof(str), "id%dlun%d", id, lun);
5800fcd48feSSimon Glass 	ret = blk_create_devicef(dev, "scsi_blk", str, IF_TYPE_SCSI, -1,
5815fe7702eSJean-Jacques Hiblot 			bd.blksz, bd.lba, &bdev);
5820fcd48feSSimon Glass 	if (ret) {
5830fcd48feSSimon Glass 		debug("Can't create device\n");
5840fcd48feSSimon Glass 		return ret;
5850fcd48feSSimon Glass 	}
5860fcd48feSSimon Glass 
5870fcd48feSSimon Glass 	bdesc = dev_get_uclass_platdata(bdev);
5880fcd48feSSimon Glass 	bdesc->target = id;
5890fcd48feSSimon Glass 	bdesc->lun = lun;
5900fcd48feSSimon Glass 	bdesc->removable = bd.removable;
5910fcd48feSSimon Glass 	bdesc->type = bd.type;
5920fcd48feSSimon Glass 	memcpy(&bdesc->vendor, &bd.vendor, sizeof(bd.vendor));
5930fcd48feSSimon Glass 	memcpy(&bdesc->product, &bd.product, sizeof(bd.product));
5940fcd48feSSimon Glass 	memcpy(&bdesc->revision, &bd.revision,	sizeof(bd.revision));
5950fcd48feSSimon Glass 
5968eab1a58SSimon Glass 	if (verbose) {
597*90037d4cSHeinrich Schuchardt 		printf("  Device %d: ", bdesc->devnum);
5980fcd48feSSimon Glass 		dev_print(bdesc);
5990fcd48feSSimon Glass 	}
6000fcd48feSSimon Glass 	return 0;
6010fcd48feSSimon Glass }
6020fcd48feSSimon Glass 
scsi_scan_dev(struct udevice * dev,bool verbose)6035c561763SSimon Glass int scsi_scan_dev(struct udevice *dev, bool verbose)
6045c561763SSimon Glass {
6055c561763SSimon Glass 	struct scsi_platdata *uc_plat; /* scsi controller platdata */
6065c561763SSimon Glass 	int ret;
6075c561763SSimon Glass 	int i;
6085c561763SSimon Glass 	int lun;
6095c561763SSimon Glass 
6105c561763SSimon Glass 	/* probe SCSI controller driver */
6115c561763SSimon Glass 	ret = device_probe(dev);
6125c561763SSimon Glass 	if (ret)
6135c561763SSimon Glass 		return ret;
6145c561763SSimon Glass 
6155c561763SSimon Glass 	/* Get controller platdata */
6165c561763SSimon Glass 	uc_plat = dev_get_uclass_platdata(dev);
6175c561763SSimon Glass 
6185c561763SSimon Glass 	for (i = 0; i < uc_plat->max_id; i++)
6195c561763SSimon Glass 		for (lun = 0; lun < uc_plat->max_lun; lun++)
6205c561763SSimon Glass 			do_scsi_scan_one(dev, i, lun, verbose);
6215c561763SSimon Glass 
6225c561763SSimon Glass 	return 0;
6235c561763SSimon Glass }
6245c561763SSimon Glass 
scsi_scan(bool verbose)6258eab1a58SSimon Glass int scsi_scan(bool verbose)
6260fcd48feSSimon Glass {
6270fcd48feSSimon Glass 	struct uclass *uc;
6280fcd48feSSimon Glass 	struct udevice *dev; /* SCSI controller */
6290fcd48feSSimon Glass 	int ret;
6300fcd48feSSimon Glass 
6318eab1a58SSimon Glass 	if (verbose)
6320fcd48feSSimon Glass 		printf("scanning bus for devices...\n");
6330fcd48feSSimon Glass 
6340fcd48feSSimon Glass 	blk_unbind_all(IF_TYPE_SCSI);
6350fcd48feSSimon Glass 
6360fcd48feSSimon Glass 	ret = uclass_get(UCLASS_SCSI, &uc);
6370fcd48feSSimon Glass 	if (ret)
6380fcd48feSSimon Glass 		return ret;
6390fcd48feSSimon Glass 
6400fcd48feSSimon Glass 	uclass_foreach_dev(dev, uc) {
6415c561763SSimon Glass 		ret = scsi_scan_dev(dev, verbose);
6420fcd48feSSimon Glass 		if (ret)
6430fcd48feSSimon Glass 			return ret;
6440fcd48feSSimon Glass 	}
6450fcd48feSSimon Glass 
6460fcd48feSSimon Glass 	return 0;
6470fcd48feSSimon Glass }
6480fcd48feSSimon Glass #else
scsi_scan(bool verbose)6498eab1a58SSimon Glass int scsi_scan(bool verbose)
6500fcd48feSSimon Glass {
6510fcd48feSSimon Glass 	unsigned char i, lun;
6520fcd48feSSimon Glass 	int ret;
6530fcd48feSSimon Glass 
6548eab1a58SSimon Glass 	if (verbose)
6550fcd48feSSimon Glass 		printf("scanning bus for devices...\n");
6560fcd48feSSimon Glass 	for (i = 0; i < CONFIG_SYS_SCSI_MAX_DEVICE; i++)
6570fcd48feSSimon Glass 		scsi_init_dev_desc(&scsi_dev_desc[i], i);
6580fcd48feSSimon Glass 
6590fcd48feSSimon Glass 	scsi_max_devs = 0;
6600fcd48feSSimon Glass 	for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) {
6610fcd48feSSimon Glass 		for (lun = 0; lun < CONFIG_SYS_SCSI_MAX_LUN; lun++) {
662*90037d4cSHeinrich Schuchardt 			struct blk_desc *bdesc = &scsi_dev_desc[scsi_max_devs];
663*90037d4cSHeinrich Schuchardt 
664*90037d4cSHeinrich Schuchardt 			ret = scsi_detect_dev(NULL, i, lun, bdesc);
6650fcd48feSSimon Glass 			if (ret)
6660fcd48feSSimon Glass 				continue;
667*90037d4cSHeinrich Schuchardt 			part_init(bdesc);
6680fcd48feSSimon Glass 
6698eab1a58SSimon Glass 			if (verbose) {
670*90037d4cSHeinrich Schuchardt 				printf("  Device %d: ", bdesc->devnum);
671*90037d4cSHeinrich Schuchardt 				dev_print(bdesc);
6728eab1a58SSimon Glass 			}
6730fcd48feSSimon Glass 			scsi_max_devs++;
6740fcd48feSSimon Glass 		} /* next LUN */
6750fcd48feSSimon Glass 	}
6760fcd48feSSimon Glass 	if (scsi_max_devs > 0)
6770fcd48feSSimon Glass 		scsi_curr_dev = 0;
6780fcd48feSSimon Glass 	else
6790fcd48feSSimon Glass 		scsi_curr_dev = -1;
6800fcd48feSSimon Glass 
6810fcd48feSSimon Glass 	printf("Found %d device(s).\n", scsi_max_devs);
6820fcd48feSSimon Glass #ifndef CONFIG_SPL_BUILD
683018f5303SSimon Glass 	env_set_ulong("scsidevs", scsi_max_devs);
6840fcd48feSSimon Glass #endif
6850fcd48feSSimon Glass 	return 0;
6860fcd48feSSimon Glass }
6870fcd48feSSimon Glass #endif
6880fcd48feSSimon Glass 
6890fcd48feSSimon Glass #ifdef CONFIG_BLK
6900fcd48feSSimon Glass static const struct blk_ops scsi_blk_ops = {
6910fcd48feSSimon Glass 	.read	= scsi_read,
6920fcd48feSSimon Glass 	.write	= scsi_write,
6930fcd48feSSimon Glass };
6940fcd48feSSimon Glass 
6950fcd48feSSimon Glass U_BOOT_DRIVER(scsi_blk) = {
6960fcd48feSSimon Glass 	.name		= "scsi_blk",
6970fcd48feSSimon Glass 	.id		= UCLASS_BLK,
6980fcd48feSSimon Glass 	.ops		= &scsi_blk_ops,
6990fcd48feSSimon Glass };
7000fcd48feSSimon Glass #else
7010fcd48feSSimon Glass U_BOOT_LEGACY_BLK(scsi) = {
7020fcd48feSSimon Glass 	.if_typename	= "scsi",
7030fcd48feSSimon Glass 	.if_type	= IF_TYPE_SCSI,
7040fcd48feSSimon Glass 	.max_devs	= CONFIG_SYS_SCSI_MAX_DEVICE,
7050fcd48feSSimon Glass 	.desc		= scsi_dev_desc,
7060fcd48feSSimon Glass };
7070fcd48feSSimon Glass #endif
708