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