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> 1163a7b5a0SYifeng Zhao #include <memalign.h> 120fcd48feSSimon Glass #include <pci.h> 130fcd48feSSimon Glass #include <scsi.h> 140fcd48feSSimon Glass #include <dm/device-internal.h> 150fcd48feSSimon Glass #include <dm/uclass-internal.h> 160fcd48feSSimon Glass 170fcd48feSSimon Glass #if !defined(CONFIG_DM_SCSI) 180fcd48feSSimon Glass # ifdef CONFIG_SCSI_DEV_LIST 190fcd48feSSimon Glass # define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST 200fcd48feSSimon Glass # else 210fcd48feSSimon Glass # ifdef CONFIG_SATA_ULI5288 220fcd48feSSimon Glass 230fcd48feSSimon Glass # define SCSI_VEND_ID 0x10b9 240fcd48feSSimon Glass # define SCSI_DEV_ID 0x5288 250fcd48feSSimon Glass 260fcd48feSSimon Glass # elif !defined(CONFIG_SCSI_AHCI_PLAT) 270fcd48feSSimon Glass # error no scsi device defined 280fcd48feSSimon Glass # endif 290fcd48feSSimon Glass # define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID} 300fcd48feSSimon Glass # endif 310fcd48feSSimon Glass #endif 320fcd48feSSimon Glass 337337fcd8SSimon Glass #if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) && \ 347337fcd8SSimon Glass !defined(CONFIG_DM_SCSI) 350fcd48feSSimon Glass const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST }; 360fcd48feSSimon Glass #endif 37b9560ad6SSimon Glass static struct scsi_cmd tempccb; /* temporary scsi command buffer */ 380fcd48feSSimon Glass 390fcd48feSSimon Glass static unsigned char tempbuff[512]; /* temporary data buffer */ 400fcd48feSSimon Glass 410fcd48feSSimon Glass #if !defined(CONFIG_DM_SCSI) 420fcd48feSSimon Glass static int scsi_max_devs; /* number of highest available scsi device */ 430fcd48feSSimon Glass 440fcd48feSSimon Glass static int scsi_curr_dev; /* current device */ 450fcd48feSSimon Glass 460fcd48feSSimon Glass static struct blk_desc scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE]; 470fcd48feSSimon Glass #endif 480fcd48feSSimon Glass 490fcd48feSSimon Glass /* almost the maximum amount of the scsi_ext command.. */ 500fcd48feSSimon Glass #define SCSI_MAX_READ_BLK 0xFFFF 510fcd48feSSimon Glass #define SCSI_LBA48_READ 0xFFFFFFF 520fcd48feSSimon Glass 53b9560ad6SSimon Glass static void scsi_print_error(struct scsi_cmd *pccb) 540fcd48feSSimon Glass { 550fcd48feSSimon Glass /* Dummy function that could print an error for debugging */ 560fcd48feSSimon Glass } 570fcd48feSSimon Glass 580fcd48feSSimon Glass #ifdef CONFIG_SYS_64BIT_LBA 59b9560ad6SSimon Glass void scsi_setup_read16(struct scsi_cmd *pccb, lbaint_t start, 60b9560ad6SSimon Glass unsigned long blocks) 610fcd48feSSimon Glass { 620fcd48feSSimon Glass pccb->cmd[0] = SCSI_READ16; 630fcd48feSSimon Glass pccb->cmd[1] = pccb->lun << 5; 640fcd48feSSimon Glass pccb->cmd[2] = (unsigned char)(start >> 56) & 0xff; 650fcd48feSSimon Glass pccb->cmd[3] = (unsigned char)(start >> 48) & 0xff; 660fcd48feSSimon Glass pccb->cmd[4] = (unsigned char)(start >> 40) & 0xff; 670fcd48feSSimon Glass pccb->cmd[5] = (unsigned char)(start >> 32) & 0xff; 680fcd48feSSimon Glass pccb->cmd[6] = (unsigned char)(start >> 24) & 0xff; 690fcd48feSSimon Glass pccb->cmd[7] = (unsigned char)(start >> 16) & 0xff; 700fcd48feSSimon Glass pccb->cmd[8] = (unsigned char)(start >> 8) & 0xff; 710fcd48feSSimon Glass pccb->cmd[9] = (unsigned char)start & 0xff; 720fcd48feSSimon Glass pccb->cmd[10] = 0; 730fcd48feSSimon Glass pccb->cmd[11] = (unsigned char)(blocks >> 24) & 0xff; 740fcd48feSSimon Glass pccb->cmd[12] = (unsigned char)(blocks >> 16) & 0xff; 750fcd48feSSimon Glass pccb->cmd[13] = (unsigned char)(blocks >> 8) & 0xff; 760fcd48feSSimon Glass pccb->cmd[14] = (unsigned char)blocks & 0xff; 770fcd48feSSimon Glass pccb->cmd[15] = 0; 780fcd48feSSimon Glass pccb->cmdlen = 16; 790fcd48feSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 800fcd48feSSimon Glass debug("scsi_setup_read16: cmd: %02X %02X startblk %02X%02X%02X%02X%02X%02X%02X%02X blccnt %02X%02X%02X%02X\n", 810fcd48feSSimon Glass pccb->cmd[0], pccb->cmd[1], 820fcd48feSSimon Glass pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], 830fcd48feSSimon Glass pccb->cmd[6], pccb->cmd[7], pccb->cmd[8], pccb->cmd[9], 840fcd48feSSimon Glass pccb->cmd[11], pccb->cmd[12], pccb->cmd[13], pccb->cmd[14]); 850fcd48feSSimon Glass } 860fcd48feSSimon Glass #endif 870fcd48feSSimon Glass 88b9560ad6SSimon Glass static void scsi_setup_read_ext(struct scsi_cmd *pccb, lbaint_t start, 890fcd48feSSimon Glass unsigned short blocks) 900fcd48feSSimon Glass { 910fcd48feSSimon Glass pccb->cmd[0] = SCSI_READ10; 920fcd48feSSimon Glass pccb->cmd[1] = pccb->lun << 5; 930fcd48feSSimon Glass pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff; 940fcd48feSSimon Glass pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff; 950fcd48feSSimon Glass pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff; 960fcd48feSSimon Glass pccb->cmd[5] = (unsigned char)start & 0xff; 970fcd48feSSimon Glass pccb->cmd[6] = 0; 980fcd48feSSimon Glass pccb->cmd[7] = (unsigned char)(blocks >> 8) & 0xff; 990fcd48feSSimon Glass pccb->cmd[8] = (unsigned char)blocks & 0xff; 1000fcd48feSSimon Glass pccb->cmd[6] = 0; 1010fcd48feSSimon Glass pccb->cmdlen = 10; 1020fcd48feSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 1030fcd48feSSimon Glass debug("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", 1040fcd48feSSimon Glass pccb->cmd[0], pccb->cmd[1], 1050fcd48feSSimon Glass pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], 1060fcd48feSSimon Glass pccb->cmd[7], pccb->cmd[8]); 1070fcd48feSSimon Glass } 1080fcd48feSSimon Glass 109b9560ad6SSimon Glass static void scsi_setup_write_ext(struct scsi_cmd *pccb, lbaint_t start, 1100fcd48feSSimon Glass unsigned short blocks) 1110fcd48feSSimon Glass { 1120fcd48feSSimon Glass pccb->cmd[0] = SCSI_WRITE10; 11352f5f55eSYifeng Zhao pccb->cmd[1] = pccb->lun << 5 | 0x8; 1140fcd48feSSimon Glass pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff; 1150fcd48feSSimon Glass pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff; 1160fcd48feSSimon Glass pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff; 1170fcd48feSSimon Glass pccb->cmd[5] = (unsigned char)start & 0xff; 1180fcd48feSSimon Glass pccb->cmd[6] = 0; 1190fcd48feSSimon Glass pccb->cmd[7] = ((unsigned char)(blocks >> 8)) & 0xff; 1200fcd48feSSimon Glass pccb->cmd[8] = (unsigned char)blocks & 0xff; 1210fcd48feSSimon Glass pccb->cmd[9] = 0; 1220fcd48feSSimon Glass pccb->cmdlen = 10; 1230fcd48feSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 1240fcd48feSSimon Glass debug("%s: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", 1250fcd48feSSimon Glass __func__, 1260fcd48feSSimon Glass pccb->cmd[0], pccb->cmd[1], 1270fcd48feSSimon Glass pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], 1280fcd48feSSimon Glass pccb->cmd[7], pccb->cmd[8]); 1290fcd48feSSimon Glass } 1300fcd48feSSimon Glass 131b9560ad6SSimon Glass static void scsi_setup_inquiry(struct scsi_cmd *pccb) 1320fcd48feSSimon Glass { 1330fcd48feSSimon Glass pccb->cmd[0] = SCSI_INQUIRY; 1340fcd48feSSimon Glass pccb->cmd[1] = pccb->lun << 5; 1350fcd48feSSimon Glass pccb->cmd[2] = 0; 1360fcd48feSSimon Glass pccb->cmd[3] = 0; 13755d11a71SYifeng Zhao if (pccb->datalen > SCSI_MAX_INQUIRY_BYTES) 13855d11a71SYifeng Zhao pccb->cmd[4] = SCSI_MAX_INQUIRY_BYTES; 1390fcd48feSSimon Glass else 1400fcd48feSSimon Glass pccb->cmd[4] = (unsigned char)pccb->datalen; 1410fcd48feSSimon Glass pccb->cmd[5] = 0; 1420fcd48feSSimon Glass pccb->cmdlen = 6; 1430fcd48feSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 1440fcd48feSSimon Glass } 1450fcd48feSSimon Glass 14663a7b5a0SYifeng Zhao /* 14763a7b5a0SYifeng Zhao * Some setup (fill-in) routines 14863a7b5a0SYifeng Zhao */ 14963a7b5a0SYifeng Zhao static void scsi_setup_test_unit_ready(struct scsi_cmd *pccb) 15063a7b5a0SYifeng Zhao { 15163a7b5a0SYifeng Zhao pccb->cmd[0] = SCSI_TST_U_RDY; 15263a7b5a0SYifeng Zhao pccb->cmd[1] = pccb->lun << 5; 15363a7b5a0SYifeng Zhao pccb->cmd[2] = 0; 15463a7b5a0SYifeng Zhao pccb->cmd[3] = 0; 15563a7b5a0SYifeng Zhao pccb->cmd[4] = 0; 15663a7b5a0SYifeng Zhao pccb->cmd[5] = 0; 15763a7b5a0SYifeng Zhao pccb->cmdlen = 6; 15863a7b5a0SYifeng Zhao pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 15963a7b5a0SYifeng Zhao } 16063a7b5a0SYifeng Zhao 1610fcd48feSSimon Glass #ifdef CONFIG_BLK 16252f5f55eSYifeng Zhao static ulong _scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, 1630fcd48feSSimon Glass void *buffer) 1640fcd48feSSimon Glass #else 16552f5f55eSYifeng Zhao static ulong _scsi_read(struct blk_desc *block_dev, lbaint_t blknr, 1660fcd48feSSimon Glass lbaint_t blkcnt, void *buffer) 1670fcd48feSSimon Glass #endif 1680fcd48feSSimon Glass { 1690fcd48feSSimon Glass #ifdef CONFIG_BLK 1700fcd48feSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 1714682c8a1SSimon Glass struct udevice *bdev = dev->parent; 1724682c8a1SSimon Glass #else 1734682c8a1SSimon Glass struct udevice *bdev = NULL; 1740fcd48feSSimon Glass #endif 1750fcd48feSSimon Glass lbaint_t start, blks; 1760fcd48feSSimon Glass uintptr_t buf_addr; 1770fcd48feSSimon Glass unsigned short smallblks = 0; 178b9560ad6SSimon Glass struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb; 1790fcd48feSSimon Glass 1800fcd48feSSimon Glass /* Setup device */ 1810fcd48feSSimon Glass pccb->target = block_dev->target; 1820fcd48feSSimon Glass pccb->lun = block_dev->lun; 1830fcd48feSSimon Glass buf_addr = (unsigned long)buffer; 1840fcd48feSSimon Glass start = blknr; 1850fcd48feSSimon Glass blks = blkcnt; 1860fcd48feSSimon Glass debug("\nscsi_read: dev %d startblk " LBAF 1870fcd48feSSimon Glass ", blccnt " LBAF " buffer %lx\n", 1880fcd48feSSimon Glass block_dev->devnum, start, blks, (unsigned long)buffer); 1890fcd48feSSimon Glass do { 1900fcd48feSSimon Glass pccb->pdata = (unsigned char *)buf_addr; 1918f7de514SShawn Lin pccb->dma_dir = DMA_FROM_DEVICE; 1920fcd48feSSimon Glass #ifdef CONFIG_SYS_64BIT_LBA 1930fcd48feSSimon Glass if (start > SCSI_LBA48_READ) { 1940fcd48feSSimon Glass unsigned long blocks; 1950fcd48feSSimon Glass blocks = min_t(lbaint_t, blks, SCSI_MAX_READ_BLK); 19652f5f55eSYifeng Zhao pccb->datalen = block_dev->rawblksz * blocks; 1970fcd48feSSimon Glass scsi_setup_read16(pccb, start, blocks); 1980fcd48feSSimon Glass start += blocks; 1990fcd48feSSimon Glass blks -= blocks; 2000fcd48feSSimon Glass } else 2010fcd48feSSimon Glass #endif 2020fcd48feSSimon Glass if (blks > SCSI_MAX_READ_BLK) { 20352f5f55eSYifeng Zhao pccb->datalen = block_dev->rawblksz * SCSI_MAX_READ_BLK; 2040fcd48feSSimon Glass smallblks = SCSI_MAX_READ_BLK; 2050fcd48feSSimon Glass scsi_setup_read_ext(pccb, start, smallblks); 2060fcd48feSSimon Glass start += SCSI_MAX_READ_BLK; 2070fcd48feSSimon Glass blks -= SCSI_MAX_READ_BLK; 2080fcd48feSSimon Glass } else { 20952f5f55eSYifeng Zhao pccb->datalen = block_dev->rawblksz * blks; 2100fcd48feSSimon Glass smallblks = (unsigned short)blks; 2110fcd48feSSimon Glass scsi_setup_read_ext(pccb, start, smallblks); 2120fcd48feSSimon Glass start += blks; 2130fcd48feSSimon Glass blks = 0; 2140fcd48feSSimon Glass } 2150fcd48feSSimon Glass debug("scsi_read_ext: startblk " LBAF 2160fcd48feSSimon Glass ", blccnt %x buffer %" PRIXPTR "\n", 2170fcd48feSSimon Glass start, smallblks, buf_addr); 2184682c8a1SSimon Glass if (scsi_exec(bdev, pccb)) { 2190fcd48feSSimon Glass scsi_print_error(pccb); 2200fcd48feSSimon Glass blkcnt -= blks; 2210fcd48feSSimon Glass break; 2220fcd48feSSimon Glass } 2230fcd48feSSimon Glass buf_addr += pccb->datalen; 2240fcd48feSSimon Glass } while (blks != 0); 2250fcd48feSSimon Glass debug("scsi_read_ext: end startblk " LBAF 2260fcd48feSSimon Glass ", blccnt %x buffer %" PRIXPTR "\n", start, smallblks, buf_addr); 2270fcd48feSSimon Glass return blkcnt; 2280fcd48feSSimon Glass } 2290fcd48feSSimon Glass 23052f5f55eSYifeng Zhao #ifdef CONFIG_BLK 23152f5f55eSYifeng Zhao static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, 23252f5f55eSYifeng Zhao void *buffer) 23352f5f55eSYifeng Zhao #else 23452f5f55eSYifeng Zhao static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr, 23552f5f55eSYifeng Zhao lbaint_t blkcnt, void *buffer) 23652f5f55eSYifeng Zhao #endif 23752f5f55eSYifeng Zhao { 23852f5f55eSYifeng Zhao #ifdef CONFIG_BLK 23952f5f55eSYifeng Zhao struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 24052f5f55eSYifeng Zhao uint32_t rawsectsz = block_dev->rawblksz / 512; 24152f5f55eSYifeng Zhao long ret = blkcnt; 24252f5f55eSYifeng Zhao 24352f5f55eSYifeng Zhao if (rawsectsz == 8) { 24452f5f55eSYifeng Zhao if ((blknr & (rawsectsz - 1)) || (blkcnt & (rawsectsz - 1))) { 24552f5f55eSYifeng Zhao uint32_t offset, n_sec, num_lpa; 24652f5f55eSYifeng Zhao long lpa; 24752f5f55eSYifeng Zhao 24852f5f55eSYifeng Zhao while (blkcnt) { 24952f5f55eSYifeng Zhao lpa = blknr / rawsectsz; 25052f5f55eSYifeng Zhao offset = blknr & (rawsectsz - 1); 25152f5f55eSYifeng Zhao n_sec = rawsectsz - offset; 25252f5f55eSYifeng Zhao if (n_sec > blkcnt) 25352f5f55eSYifeng Zhao n_sec = blkcnt; 25452f5f55eSYifeng Zhao 25552f5f55eSYifeng Zhao if (offset || n_sec < rawsectsz) { 25652f5f55eSYifeng Zhao _scsi_read(dev, lpa, 1, block_dev->align_sector_buf); 25752f5f55eSYifeng Zhao memcpy(buffer, block_dev->align_sector_buf + offset * 512, n_sec * 512); 25852f5f55eSYifeng Zhao } else { 25952f5f55eSYifeng Zhao num_lpa = blkcnt / rawsectsz; 26052f5f55eSYifeng Zhao n_sec = num_lpa * rawsectsz; 26152f5f55eSYifeng Zhao _scsi_read(dev, lpa, num_lpa, buffer); 26252f5f55eSYifeng Zhao } 26352f5f55eSYifeng Zhao blkcnt -= n_sec; 26452f5f55eSYifeng Zhao blknr += n_sec; 26552f5f55eSYifeng Zhao buffer += 512 * n_sec; 26652f5f55eSYifeng Zhao } 26752f5f55eSYifeng Zhao 26852f5f55eSYifeng Zhao return ret; 26952f5f55eSYifeng Zhao } 27052f5f55eSYifeng Zhao blknr /= rawsectsz; 27152f5f55eSYifeng Zhao blkcnt /= rawsectsz; 27252f5f55eSYifeng Zhao _scsi_read(dev, blknr, blkcnt, buffer); 27352f5f55eSYifeng Zhao 27452f5f55eSYifeng Zhao return ret; 27552f5f55eSYifeng Zhao } 27652f5f55eSYifeng Zhao 27752f5f55eSYifeng Zhao return _scsi_read(dev, blknr, blkcnt, buffer); 27852f5f55eSYifeng Zhao #else 27952f5f55eSYifeng Zhao return _scsi_read(block_dev, blknr, blkcnt, buffer); 28052f5f55eSYifeng Zhao #endif 28152f5f55eSYifeng Zhao } 2820fcd48feSSimon Glass /******************************************************************************* 2830fcd48feSSimon Glass * scsi_write 2840fcd48feSSimon Glass */ 2850fcd48feSSimon Glass 2860fcd48feSSimon Glass /* Almost the maximum amount of the scsi_ext command.. */ 2870fcd48feSSimon Glass #define SCSI_MAX_WRITE_BLK 0xFFFF 2880fcd48feSSimon Glass 2890fcd48feSSimon Glass #ifdef CONFIG_BLK 29052f5f55eSYifeng Zhao static ulong _scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, 2910fcd48feSSimon Glass const void *buffer) 2920fcd48feSSimon Glass #else 29352f5f55eSYifeng Zhao static ulong _scsi_write(struct blk_desc *block_dev, lbaint_t blknr, 2940fcd48feSSimon Glass lbaint_t blkcnt, const void *buffer) 2950fcd48feSSimon Glass #endif 2960fcd48feSSimon Glass { 2970fcd48feSSimon Glass #ifdef CONFIG_BLK 2980fcd48feSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 2994682c8a1SSimon Glass struct udevice *bdev = dev->parent; 3004682c8a1SSimon Glass #else 3014682c8a1SSimon Glass struct udevice *bdev = NULL; 3020fcd48feSSimon Glass #endif 3030fcd48feSSimon Glass lbaint_t start, blks; 3040fcd48feSSimon Glass uintptr_t buf_addr; 3050fcd48feSSimon Glass unsigned short smallblks; 306b9560ad6SSimon Glass struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb; 3070fcd48feSSimon Glass 3080fcd48feSSimon Glass /* Setup device */ 3090fcd48feSSimon Glass pccb->target = block_dev->target; 3100fcd48feSSimon Glass pccb->lun = block_dev->lun; 3110fcd48feSSimon Glass buf_addr = (unsigned long)buffer; 3120fcd48feSSimon Glass start = blknr; 3130fcd48feSSimon Glass blks = blkcnt; 3140fcd48feSSimon Glass debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n", 3150fcd48feSSimon Glass __func__, block_dev->devnum, start, blks, (unsigned long)buffer); 3160fcd48feSSimon Glass do { 3170fcd48feSSimon Glass pccb->pdata = (unsigned char *)buf_addr; 3188f7de514SShawn Lin pccb->dma_dir = DMA_TO_DEVICE; 3190fcd48feSSimon Glass if (blks > SCSI_MAX_WRITE_BLK) { 32052f5f55eSYifeng Zhao pccb->datalen = (block_dev->rawblksz * SCSI_MAX_WRITE_BLK); 3210fcd48feSSimon Glass smallblks = SCSI_MAX_WRITE_BLK; 3220fcd48feSSimon Glass scsi_setup_write_ext(pccb, start, smallblks); 3230fcd48feSSimon Glass start += SCSI_MAX_WRITE_BLK; 3240fcd48feSSimon Glass blks -= SCSI_MAX_WRITE_BLK; 3250fcd48feSSimon Glass } else { 32652f5f55eSYifeng Zhao pccb->datalen = block_dev->rawblksz * blks; 3270fcd48feSSimon Glass smallblks = (unsigned short)blks; 3280fcd48feSSimon Glass scsi_setup_write_ext(pccb, start, smallblks); 3290fcd48feSSimon Glass start += blks; 3300fcd48feSSimon Glass blks = 0; 3310fcd48feSSimon Glass } 3320fcd48feSSimon Glass debug("%s: startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", 3330fcd48feSSimon Glass __func__, start, smallblks, buf_addr); 3344682c8a1SSimon Glass if (scsi_exec(bdev, pccb)) { 3350fcd48feSSimon Glass scsi_print_error(pccb); 3360fcd48feSSimon Glass blkcnt -= blks; 3370fcd48feSSimon Glass break; 3380fcd48feSSimon Glass } 3390fcd48feSSimon Glass buf_addr += pccb->datalen; 3400fcd48feSSimon Glass } while (blks != 0); 3410fcd48feSSimon Glass debug("%s: end startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", 3420fcd48feSSimon Glass __func__, start, smallblks, buf_addr); 3430fcd48feSSimon Glass return blkcnt; 3440fcd48feSSimon Glass } 3450fcd48feSSimon Glass 34652f5f55eSYifeng Zhao #ifdef CONFIG_BLK 34752f5f55eSYifeng Zhao static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, 34852f5f55eSYifeng Zhao const void *buffer) 34952f5f55eSYifeng Zhao #else 35052f5f55eSYifeng Zhao static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr, 35152f5f55eSYifeng Zhao lbaint_t blkcnt, const void *buffer) 35252f5f55eSYifeng Zhao #endif 35352f5f55eSYifeng Zhao { 35452f5f55eSYifeng Zhao #ifdef CONFIG_BLK 35552f5f55eSYifeng Zhao struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 35652f5f55eSYifeng Zhao uint32_t rawsectsz = block_dev->rawblksz / 512; 35752f5f55eSYifeng Zhao long ret = blkcnt; 35852f5f55eSYifeng Zhao 35952f5f55eSYifeng Zhao if (rawsectsz == 8) { 36052f5f55eSYifeng Zhao if ((blknr & (rawsectsz - 1)) || (blkcnt & (rawsectsz - 1))) { 36152f5f55eSYifeng Zhao uint32_t num_lpa, offset, n_sec; 36252f5f55eSYifeng Zhao long lpa; 36352f5f55eSYifeng Zhao 36452f5f55eSYifeng Zhao while (blkcnt) { 36552f5f55eSYifeng Zhao lpa = blknr / rawsectsz; 36652f5f55eSYifeng Zhao offset = blknr & (rawsectsz - 1); 36752f5f55eSYifeng Zhao n_sec = rawsectsz - offset; 36852f5f55eSYifeng Zhao if (n_sec > blkcnt) 36952f5f55eSYifeng Zhao n_sec = blkcnt; 37052f5f55eSYifeng Zhao if (offset || n_sec < rawsectsz) { 37152f5f55eSYifeng Zhao _scsi_read(dev, lpa, 1, block_dev->align_sector_buf); 37252f5f55eSYifeng Zhao memcpy(block_dev->align_sector_buf + offset * 512, buffer, n_sec * 512); 37352f5f55eSYifeng Zhao _scsi_write(dev, lpa, 1, block_dev->align_sector_buf); 37452f5f55eSYifeng Zhao } else { 37552f5f55eSYifeng Zhao num_lpa = blkcnt / rawsectsz; 37652f5f55eSYifeng Zhao n_sec = num_lpa * rawsectsz; 37752f5f55eSYifeng Zhao _scsi_write(dev, lpa, num_lpa, buffer); 37852f5f55eSYifeng Zhao } 37952f5f55eSYifeng Zhao blkcnt -= n_sec; 38052f5f55eSYifeng Zhao blknr += n_sec; 38152f5f55eSYifeng Zhao buffer += 512 * n_sec; 38252f5f55eSYifeng Zhao } 38352f5f55eSYifeng Zhao 38452f5f55eSYifeng Zhao return ret; 38552f5f55eSYifeng Zhao } 38652f5f55eSYifeng Zhao blknr /= rawsectsz; 38752f5f55eSYifeng Zhao blkcnt /= rawsectsz; 38852f5f55eSYifeng Zhao _scsi_write(dev, blknr, blkcnt, buffer); 38952f5f55eSYifeng Zhao 39052f5f55eSYifeng Zhao return ret; 39152f5f55eSYifeng Zhao } 39252f5f55eSYifeng Zhao 39352f5f55eSYifeng Zhao return _scsi_write(dev, blknr, blkcnt, buffer); 39452f5f55eSYifeng Zhao #else 39552f5f55eSYifeng Zhao return _scsi_write(block_dev, blknr, blkcnt, buffer); 39652f5f55eSYifeng Zhao #endif 39752f5f55eSYifeng Zhao 39852f5f55eSYifeng Zhao } 39932d06e10SYifeng Zhao 40063a7b5a0SYifeng Zhao #ifdef CONFIG_BLK 40163a7b5a0SYifeng Zhao static ulong scsi_erase(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt) 40263a7b5a0SYifeng Zhao { 40363a7b5a0SYifeng Zhao ALLOC_CACHE_ALIGN_BUFFER_PAD(struct unmap_para_list, um_list, 1, ARCH_DMA_MINALIGN); 40463a7b5a0SYifeng Zhao struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 40563a7b5a0SYifeng Zhao struct udevice *bdev = dev->parent; 40663a7b5a0SYifeng Zhao struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb; 40763a7b5a0SYifeng Zhao uint32_t rawsectsz = block_dev->rawblksz / block_dev->blksz; 40863a7b5a0SYifeng Zhao 409*e36090fdSYifeng Zhao if (rawsectsz == 1) /* The sata devices not support data erase yet. */ 410*e36090fdSYifeng Zhao return blkcnt; 411*e36090fdSYifeng Zhao 41263a7b5a0SYifeng Zhao pccb->target = block_dev->target; 41363a7b5a0SYifeng Zhao pccb->lun = block_dev->lun; 41463a7b5a0SYifeng Zhao pccb->datalen = 0; 41563a7b5a0SYifeng Zhao scsi_setup_test_unit_ready(pccb); 41663a7b5a0SYifeng Zhao if (scsi_exec(bdev, pccb)) { 41763a7b5a0SYifeng Zhao printf("TEST UNIT READY fail!Can not erase UFS device\n"); 41863a7b5a0SYifeng Zhao return 0; 41963a7b5a0SYifeng Zhao } 42063a7b5a0SYifeng Zhao 42163a7b5a0SYifeng Zhao if (blknr % rawsectsz != 0 || blkcnt % rawsectsz != 0) 42263a7b5a0SYifeng Zhao printf("UFS erase area not aligned to %d, blknr = %lx, blkcnt = %lx\n", rawsectsz, blknr, blkcnt); 42363a7b5a0SYifeng Zhao 42463a7b5a0SYifeng Zhao um_list->um_data_len = cpu_to_be16(sizeof(struct unmap_para_list) - 2); 42563a7b5a0SYifeng Zhao um_list->um_block_desc_len = cpu_to_be16(sizeof(struct um_block_descriptor)); 42663a7b5a0SYifeng Zhao if (8 == sizeof(lbaint_t)) 42763a7b5a0SYifeng Zhao um_list->ub_desc.um_block_addr = cpu_to_be64(blknr / rawsectsz); 42863a7b5a0SYifeng Zhao else 42963a7b5a0SYifeng Zhao um_list->ub_desc.um_block_addr = cpu_to_be64((uint64_t)blknr / rawsectsz); 43063a7b5a0SYifeng Zhao um_list->ub_desc.um_block_sz = cpu_to_be32((uint32_t)blkcnt / rawsectsz); 43163a7b5a0SYifeng Zhao 43263a7b5a0SYifeng Zhao pccb->pdata = (void *)um_list; 43363a7b5a0SYifeng Zhao pccb->datalen = 24; 43463a7b5a0SYifeng Zhao pccb->dma_dir = DMA_TO_DEVICE; 43563a7b5a0SYifeng Zhao memset(pccb->cmd, 0, 10); 43663a7b5a0SYifeng Zhao pccb->cmd[0] = SCSI_UNMAP; 43763a7b5a0SYifeng Zhao pccb->cmd[8] = 24; 43863a7b5a0SYifeng Zhao pccb->cmdlen = 10; 43963a7b5a0SYifeng Zhao 44063a7b5a0SYifeng Zhao if (scsi_exec(bdev, pccb)) { 44163a7b5a0SYifeng Zhao printf("erase UFS device error.\n"); 44263a7b5a0SYifeng Zhao return 0; 44363a7b5a0SYifeng Zhao } 44463a7b5a0SYifeng Zhao 44563a7b5a0SYifeng Zhao return blkcnt; 44663a7b5a0SYifeng Zhao } 44763a7b5a0SYifeng Zhao #endif 44852f5f55eSYifeng Zhao 4497337fcd8SSimon Glass #if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) && \ 4507337fcd8SSimon Glass !defined(CONFIG_DM_SCSI) 4510fcd48feSSimon Glass void scsi_init(void) 4520fcd48feSSimon Glass { 4530fcd48feSSimon Glass int busdevfunc = -1; 4540fcd48feSSimon Glass int i; 4550fcd48feSSimon Glass /* 4560fcd48feSSimon Glass * Find a device from the list, this driver will support a single 4570fcd48feSSimon Glass * controller. 4580fcd48feSSimon Glass */ 4590fcd48feSSimon Glass for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) { 4600fcd48feSSimon Glass /* get PCI Device ID */ 4610fcd48feSSimon Glass #ifdef CONFIG_DM_PCI 4620fcd48feSSimon Glass struct udevice *dev; 4630fcd48feSSimon Glass int ret; 4640fcd48feSSimon Glass 4650fcd48feSSimon Glass ret = dm_pci_find_device(scsi_device_list[i].vendor, 4660fcd48feSSimon Glass scsi_device_list[i].device, 0, &dev); 4670fcd48feSSimon Glass if (!ret) { 4680fcd48feSSimon Glass busdevfunc = dm_pci_get_bdf(dev); 4690fcd48feSSimon Glass break; 4700fcd48feSSimon Glass } 4710fcd48feSSimon Glass #else 4720fcd48feSSimon Glass busdevfunc = pci_find_device(scsi_device_list[i].vendor, 4730fcd48feSSimon Glass scsi_device_list[i].device, 4740fcd48feSSimon Glass 0); 4750fcd48feSSimon Glass #endif 4760fcd48feSSimon Glass if (busdevfunc != -1) 4770fcd48feSSimon Glass break; 4780fcd48feSSimon Glass } 4790fcd48feSSimon Glass 4800fcd48feSSimon Glass if (busdevfunc == -1) { 4810fcd48feSSimon Glass printf("Error: SCSI Controller(s) "); 4820fcd48feSSimon Glass for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) { 4830fcd48feSSimon Glass printf("%04X:%04X ", 4840fcd48feSSimon Glass scsi_device_list[i].vendor, 4850fcd48feSSimon Glass scsi_device_list[i].device); 4860fcd48feSSimon Glass } 4870fcd48feSSimon Glass printf("not found\n"); 4880fcd48feSSimon Glass return; 4890fcd48feSSimon Glass } 4900fcd48feSSimon Glass #ifdef DEBUG 4910fcd48feSSimon Glass else { 4920fcd48feSSimon Glass printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n", 4930fcd48feSSimon Glass scsi_device_list[i].vendor, 4940fcd48feSSimon Glass scsi_device_list[i].device, 4950fcd48feSSimon Glass (busdevfunc >> 16) & 0xFF, 4960fcd48feSSimon Glass (busdevfunc >> 11) & 0x1F, 4970fcd48feSSimon Glass (busdevfunc >> 8) & 0x7); 4980fcd48feSSimon Glass } 4990fcd48feSSimon Glass #endif 5000fcd48feSSimon Glass bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci"); 5010fcd48feSSimon Glass scsi_low_level_init(busdevfunc); 5028eab1a58SSimon Glass scsi_scan(true); 5030fcd48feSSimon Glass bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI); 5040fcd48feSSimon Glass } 5050fcd48feSSimon Glass #endif 5060fcd48feSSimon Glass 5070fcd48feSSimon Glass /* copy src to dest, skipping leading and trailing blanks 5080fcd48feSSimon Glass * and null terminate the string 5090fcd48feSSimon Glass */ 5100fcd48feSSimon Glass static void scsi_ident_cpy(unsigned char *dest, unsigned char *src, 5110fcd48feSSimon Glass unsigned int len) 5120fcd48feSSimon Glass { 5130fcd48feSSimon Glass int start, end; 5140fcd48feSSimon Glass 5150fcd48feSSimon Glass start = 0; 5160fcd48feSSimon Glass while (start < len) { 5170fcd48feSSimon Glass if (src[start] != ' ') 5180fcd48feSSimon Glass break; 5190fcd48feSSimon Glass start++; 5200fcd48feSSimon Glass } 5210fcd48feSSimon Glass end = len-1; 5220fcd48feSSimon Glass while (end > start) { 5230fcd48feSSimon Glass if (src[end] != ' ') 5240fcd48feSSimon Glass break; 5250fcd48feSSimon Glass end--; 5260fcd48feSSimon Glass } 5270fcd48feSSimon Glass for (; start <= end; start++) 5280fcd48feSSimon Glass *dest ++= src[start]; 5290fcd48feSSimon Glass *dest = '\0'; 5300fcd48feSSimon Glass } 5310fcd48feSSimon Glass 5324682c8a1SSimon Glass static int scsi_read_capacity(struct udevice *dev, struct scsi_cmd *pccb, 5334682c8a1SSimon Glass lbaint_t *capacity, unsigned long *blksz) 5340fcd48feSSimon Glass { 5350fcd48feSSimon Glass *capacity = 0; 5360fcd48feSSimon Glass 5370fcd48feSSimon Glass memset(pccb->cmd, '\0', sizeof(pccb->cmd)); 5380fcd48feSSimon Glass pccb->cmd[0] = SCSI_RD_CAPAC10; 5390fcd48feSSimon Glass pccb->cmd[1] = pccb->lun << 5; 5400fcd48feSSimon Glass pccb->cmdlen = 10; 5410fcd48feSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 5420fcd48feSSimon Glass 5430fcd48feSSimon Glass pccb->datalen = 8; 544f6580ef3SSimon Glass if (scsi_exec(dev, pccb)) 5450fcd48feSSimon Glass return 1; 5460fcd48feSSimon Glass 5470fcd48feSSimon Glass *capacity = ((lbaint_t)pccb->pdata[0] << 24) | 5480fcd48feSSimon Glass ((lbaint_t)pccb->pdata[1] << 16) | 5490fcd48feSSimon Glass ((lbaint_t)pccb->pdata[2] << 8) | 5500fcd48feSSimon Glass ((lbaint_t)pccb->pdata[3]); 5510fcd48feSSimon Glass 5520fcd48feSSimon Glass if (*capacity != 0xffffffff) { 5530fcd48feSSimon Glass /* Read capacity (10) was sufficient for this drive. */ 5540fcd48feSSimon Glass *blksz = ((unsigned long)pccb->pdata[4] << 24) | 5550fcd48feSSimon Glass ((unsigned long)pccb->pdata[5] << 16) | 5560fcd48feSSimon Glass ((unsigned long)pccb->pdata[6] << 8) | 5570fcd48feSSimon Glass ((unsigned long)pccb->pdata[7]); 5580fcd48feSSimon Glass return 0; 5590fcd48feSSimon Glass } 5600fcd48feSSimon Glass 5610fcd48feSSimon Glass /* Read capacity (10) was insufficient. Use read capacity (16). */ 5620fcd48feSSimon Glass memset(pccb->cmd, '\0', sizeof(pccb->cmd)); 5630fcd48feSSimon Glass pccb->cmd[0] = SCSI_RD_CAPAC16; 5640fcd48feSSimon Glass pccb->cmd[1] = 0x10; 5650fcd48feSSimon Glass pccb->cmdlen = 16; 5660fcd48feSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 5670fcd48feSSimon Glass 5680fcd48feSSimon Glass pccb->datalen = 16; 5698f7de514SShawn Lin pccb->dma_dir = DMA_FROM_DEVICE; 570f6580ef3SSimon Glass if (scsi_exec(dev, pccb)) 5710fcd48feSSimon Glass return 1; 5720fcd48feSSimon Glass 5730fcd48feSSimon Glass *capacity = ((uint64_t)pccb->pdata[0] << 56) | 5740fcd48feSSimon Glass ((uint64_t)pccb->pdata[1] << 48) | 5750fcd48feSSimon Glass ((uint64_t)pccb->pdata[2] << 40) | 5760fcd48feSSimon Glass ((uint64_t)pccb->pdata[3] << 32) | 5770fcd48feSSimon Glass ((uint64_t)pccb->pdata[4] << 24) | 5780fcd48feSSimon Glass ((uint64_t)pccb->pdata[5] << 16) | 5790fcd48feSSimon Glass ((uint64_t)pccb->pdata[6] << 8) | 5800fcd48feSSimon Glass ((uint64_t)pccb->pdata[7]); 5810fcd48feSSimon Glass 5820fcd48feSSimon Glass *blksz = ((uint64_t)pccb->pdata[8] << 56) | 5830fcd48feSSimon Glass ((uint64_t)pccb->pdata[9] << 48) | 5840fcd48feSSimon Glass ((uint64_t)pccb->pdata[10] << 40) | 5850fcd48feSSimon Glass ((uint64_t)pccb->pdata[11] << 32) | 5860fcd48feSSimon Glass ((uint64_t)pccb->pdata[12] << 24) | 5870fcd48feSSimon Glass ((uint64_t)pccb->pdata[13] << 16) | 5880fcd48feSSimon Glass ((uint64_t)pccb->pdata[14] << 8) | 5890fcd48feSSimon Glass ((uint64_t)pccb->pdata[15]); 5900fcd48feSSimon Glass 5910fcd48feSSimon Glass return 0; 5920fcd48feSSimon Glass } 5930fcd48feSSimon Glass 5940fcd48feSSimon Glass /** 5950fcd48feSSimon Glass * scsi_init_dev_desc_priv - initialize only SCSI specific blk_desc properties 5960fcd48feSSimon Glass * 5970fcd48feSSimon Glass * @dev_desc: Block device description pointer 5980fcd48feSSimon Glass */ 5990fcd48feSSimon Glass static void scsi_init_dev_desc_priv(struct blk_desc *dev_desc) 6000fcd48feSSimon Glass { 6010fcd48feSSimon Glass dev_desc->target = 0xff; 6020fcd48feSSimon Glass dev_desc->lun = 0xff; 6030fcd48feSSimon Glass dev_desc->log2blksz = 6040fcd48feSSimon Glass LOG2_INVALID(typeof(dev_desc->log2blksz)); 6050fcd48feSSimon Glass dev_desc->type = DEV_TYPE_UNKNOWN; 6060fcd48feSSimon Glass dev_desc->vendor[0] = 0; 6070fcd48feSSimon Glass dev_desc->product[0] = 0; 6080fcd48feSSimon Glass dev_desc->revision[0] = 0; 6090fcd48feSSimon Glass dev_desc->removable = false; 610c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 6110fcd48feSSimon Glass dev_desc->block_read = scsi_read; 6120fcd48feSSimon Glass dev_desc->block_write = scsi_write; 6130fcd48feSSimon Glass #endif 6140fcd48feSSimon Glass } 6150fcd48feSSimon Glass 6160fcd48feSSimon Glass #if !defined(CONFIG_DM_SCSI) 6170fcd48feSSimon Glass /** 6180fcd48feSSimon Glass * scsi_init_dev_desc - initialize all SCSI specific blk_desc properties 6190fcd48feSSimon Glass * 6200fcd48feSSimon Glass * @dev_desc: Block device description pointer 6210fcd48feSSimon Glass * @devnum: Device number 6220fcd48feSSimon Glass */ 6230fcd48feSSimon Glass static void scsi_init_dev_desc(struct blk_desc *dev_desc, int devnum) 6240fcd48feSSimon Glass { 6250fcd48feSSimon Glass dev_desc->lba = 0; 6260fcd48feSSimon Glass dev_desc->blksz = 0; 6270fcd48feSSimon Glass dev_desc->if_type = IF_TYPE_SCSI; 6280fcd48feSSimon Glass dev_desc->devnum = devnum; 6290fcd48feSSimon Glass dev_desc->part_type = PART_TYPE_UNKNOWN; 6300fcd48feSSimon Glass 6310fcd48feSSimon Glass scsi_init_dev_desc_priv(dev_desc); 6320fcd48feSSimon Glass } 6330fcd48feSSimon Glass #endif 6340fcd48feSSimon Glass 6350fcd48feSSimon Glass /** 6360fcd48feSSimon Glass * scsi_detect_dev - Detect scsi device 6370fcd48feSSimon Glass * 6380fcd48feSSimon Glass * @target: target id 6390fcd48feSSimon Glass * @lun: target lun 6400fcd48feSSimon Glass * @dev_desc: block device description 6410fcd48feSSimon Glass * 6420fcd48feSSimon Glass * The scsi_detect_dev detects and fills a dev_desc structure when the device is 6430fcd48feSSimon Glass * detected. 6440fcd48feSSimon Glass * 6450fcd48feSSimon Glass * Return: 0 on success, error value otherwise 6460fcd48feSSimon Glass */ 6474682c8a1SSimon Glass static int scsi_detect_dev(struct udevice *dev, int target, int lun, 6484682c8a1SSimon Glass struct blk_desc *dev_desc) 6490fcd48feSSimon Glass { 6500fcd48feSSimon Glass unsigned char perq, modi; 6510fcd48feSSimon Glass lbaint_t capacity; 6520fcd48feSSimon Glass unsigned long blksz; 653b9560ad6SSimon Glass struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb; 6540fcd48feSSimon Glass 6550fcd48feSSimon Glass pccb->target = target; 6560fcd48feSSimon Glass pccb->lun = lun; 6570fcd48feSSimon Glass pccb->pdata = (unsigned char *)&tempbuff; 65855d11a71SYifeng Zhao pccb->datalen = SCSI_STD_INQUIRY_BYTES; 6598f7de514SShawn Lin pccb->dma_dir = DMA_FROM_DEVICE; 6600fcd48feSSimon Glass scsi_setup_inquiry(pccb); 661f6580ef3SSimon Glass if (scsi_exec(dev, pccb)) { 6620fcd48feSSimon Glass if (pccb->contr_stat == SCSI_SEL_TIME_OUT) { 6630fcd48feSSimon Glass /* 6640fcd48feSSimon Glass * selection timeout => assuming no 6650fcd48feSSimon Glass * device present 6660fcd48feSSimon Glass */ 6670fcd48feSSimon Glass debug("Selection timeout ID %d\n", 6680fcd48feSSimon Glass pccb->target); 6690fcd48feSSimon Glass return -ETIMEDOUT; 6700fcd48feSSimon Glass } 6710fcd48feSSimon Glass scsi_print_error(pccb); 6720fcd48feSSimon Glass return -ENODEV; 6730fcd48feSSimon Glass } 6740fcd48feSSimon Glass perq = tempbuff[0]; 6750fcd48feSSimon Glass modi = tempbuff[1]; 6760fcd48feSSimon Glass if ((perq & 0x1f) == 0x1f) 6770fcd48feSSimon Glass return -ENODEV; /* skip unknown devices */ 6780fcd48feSSimon Glass if ((modi & 0x80) == 0x80) /* drive is removable */ 6790fcd48feSSimon Glass dev_desc->removable = true; 6800fcd48feSSimon Glass /* get info for this device */ 6810fcd48feSSimon Glass scsi_ident_cpy((unsigned char *)dev_desc->vendor, 6820fcd48feSSimon Glass &tempbuff[8], 8); 6830fcd48feSSimon Glass scsi_ident_cpy((unsigned char *)dev_desc->product, 6840fcd48feSSimon Glass &tempbuff[16], 16); 6850fcd48feSSimon Glass scsi_ident_cpy((unsigned char *)dev_desc->revision, 6860fcd48feSSimon Glass &tempbuff[32], 4); 6870fcd48feSSimon Glass dev_desc->target = pccb->target; 6880fcd48feSSimon Glass dev_desc->lun = pccb->lun; 6890fcd48feSSimon Glass 6900fcd48feSSimon Glass pccb->datalen = 0; 6910fcd48feSSimon Glass scsi_setup_test_unit_ready(pccb); 692f6580ef3SSimon Glass if (scsi_exec(dev, pccb)) { 6930fcd48feSSimon Glass if (dev_desc->removable) { 6940fcd48feSSimon Glass dev_desc->type = perq; 6950fcd48feSSimon Glass goto removable; 6960fcd48feSSimon Glass } 6970fcd48feSSimon Glass scsi_print_error(pccb); 6980fcd48feSSimon Glass return -EINVAL; 6990fcd48feSSimon Glass } 7004682c8a1SSimon Glass if (scsi_read_capacity(dev, pccb, &capacity, &blksz)) { 7010fcd48feSSimon Glass scsi_print_error(pccb); 7020fcd48feSSimon Glass return -EINVAL; 7030fcd48feSSimon Glass } 70452f5f55eSYifeng Zhao 7050fcd48feSSimon Glass dev_desc->lba = capacity; 7060fcd48feSSimon Glass dev_desc->blksz = blksz; 7070fcd48feSSimon Glass dev_desc->log2blksz = LOG2(dev_desc->blksz); 7080fcd48feSSimon Glass dev_desc->type = perq; 7090fcd48feSSimon Glass removable: 7100fcd48feSSimon Glass return 0; 7110fcd48feSSimon Glass } 7120fcd48feSSimon Glass 7130fcd48feSSimon Glass /* 7140fcd48feSSimon Glass * (re)-scan the scsi bus and reports scsi device info 7150fcd48feSSimon Glass * to the user if mode = 1 7160fcd48feSSimon Glass */ 7170fcd48feSSimon Glass #if defined(CONFIG_DM_SCSI) 7188eab1a58SSimon Glass static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose) 7190fcd48feSSimon Glass { 7200fcd48feSSimon Glass int ret; 7210fcd48feSSimon Glass struct udevice *bdev; 7220fcd48feSSimon Glass struct blk_desc bd; 7230fcd48feSSimon Glass struct blk_desc *bdesc; 7240fcd48feSSimon Glass char str[10]; 7250fcd48feSSimon Glass 7260fcd48feSSimon Glass /* 7270fcd48feSSimon Glass * detect the scsi driver to get information about its geometry (block 7280fcd48feSSimon Glass * size, number of blocks) and other parameters (ids, type, ...) 7290fcd48feSSimon Glass */ 7300fcd48feSSimon Glass scsi_init_dev_desc_priv(&bd); 7314682c8a1SSimon Glass if (scsi_detect_dev(dev, id, lun, &bd)) 7320fcd48feSSimon Glass return -ENODEV; 7330fcd48feSSimon Glass 7340fcd48feSSimon Glass /* 7350fcd48feSSimon Glass * Create only one block device and do detection 7360fcd48feSSimon Glass * to make sure that there won't be a lot of 7370fcd48feSSimon Glass * block devices created 7380fcd48feSSimon Glass */ 7390fcd48feSSimon Glass snprintf(str, sizeof(str), "id%dlun%d", id, lun); 7400fcd48feSSimon Glass ret = blk_create_devicef(dev, "scsi_blk", str, IF_TYPE_SCSI, -1, 7410fcd48feSSimon Glass bd.blksz, bd.blksz * bd.lba, &bdev); 7420fcd48feSSimon Glass if (ret) { 7430fcd48feSSimon Glass debug("Can't create device\n"); 7440fcd48feSSimon Glass return ret; 7450fcd48feSSimon Glass } 7460fcd48feSSimon Glass 7470fcd48feSSimon Glass bdesc = dev_get_uclass_platdata(bdev); 7480fcd48feSSimon Glass bdesc->target = id; 7490fcd48feSSimon Glass bdesc->lun = lun; 7500fcd48feSSimon Glass bdesc->removable = bd.removable; 7510fcd48feSSimon Glass bdesc->type = bd.type; 75252f5f55eSYifeng Zhao 75352f5f55eSYifeng Zhao if (bdesc->rawblksz == 4096) { 75452f5f55eSYifeng Zhao bdesc->blksz = 512; 75532d06e10SYifeng Zhao bdesc->rawlba++; /* add 1 sector for ufs */ 75652f5f55eSYifeng Zhao bdesc->lba = bdesc->rawlba * 8; 75752f5f55eSYifeng Zhao bdesc->align_sector_buf = memalign(CONFIG_SYS_CACHELINE_SIZE, bdesc->rawblksz); 75852f5f55eSYifeng Zhao } 75952f5f55eSYifeng Zhao 7600fcd48feSSimon Glass memcpy(&bdesc->vendor, &bd.vendor, sizeof(bd.vendor)); 7610fcd48feSSimon Glass memcpy(&bdesc->product, &bd.product, sizeof(bd.product)); 7620fcd48feSSimon Glass memcpy(&bdesc->revision, &bd.revision, sizeof(bd.revision)); 7630fcd48feSSimon Glass part_init(bdesc); 7640fcd48feSSimon Glass 7658eab1a58SSimon Glass if (verbose) { 7660fcd48feSSimon Glass printf(" Device %d: ", 0); 7670fcd48feSSimon Glass dev_print(bdesc); 7680fcd48feSSimon Glass } 7690fcd48feSSimon Glass return 0; 7700fcd48feSSimon Glass } 7710fcd48feSSimon Glass 7725c561763SSimon Glass int scsi_scan_dev(struct udevice *dev, bool verbose) 7735c561763SSimon Glass { 7745c561763SSimon Glass struct scsi_platdata *uc_plat; /* scsi controller platdata */ 7755c561763SSimon Glass int ret; 7765c561763SSimon Glass int i; 7775c561763SSimon Glass int lun; 7785c561763SSimon Glass 7795c561763SSimon Glass /* probe SCSI controller driver */ 7805c561763SSimon Glass ret = device_probe(dev); 7815c561763SSimon Glass if (ret) 7825c561763SSimon Glass return ret; 7835c561763SSimon Glass 7845c561763SSimon Glass /* Get controller platdata */ 7855c561763SSimon Glass uc_plat = dev_get_uclass_platdata(dev); 7865c561763SSimon Glass 7875c561763SSimon Glass for (i = 0; i < uc_plat->max_id; i++) 7885c561763SSimon Glass for (lun = 0; lun < uc_plat->max_lun; lun++) 7895c561763SSimon Glass do_scsi_scan_one(dev, i, lun, verbose); 7905c561763SSimon Glass 7915c561763SSimon Glass return 0; 7925c561763SSimon Glass } 7935c561763SSimon Glass 7948eab1a58SSimon Glass int scsi_scan(bool verbose) 7950fcd48feSSimon Glass { 7960fcd48feSSimon Glass struct uclass *uc; 7970fcd48feSSimon Glass struct udevice *dev; /* SCSI controller */ 7980fcd48feSSimon Glass int ret; 7990fcd48feSSimon Glass 8008eab1a58SSimon Glass if (verbose) 8010fcd48feSSimon Glass printf("scanning bus for devices...\n"); 8020fcd48feSSimon Glass 8030fcd48feSSimon Glass blk_unbind_all(IF_TYPE_SCSI); 8040fcd48feSSimon Glass 8050fcd48feSSimon Glass ret = uclass_get(UCLASS_SCSI, &uc); 8060fcd48feSSimon Glass if (ret) 8070fcd48feSSimon Glass return ret; 8080fcd48feSSimon Glass 8090fcd48feSSimon Glass uclass_foreach_dev(dev, uc) { 8105c561763SSimon Glass ret = scsi_scan_dev(dev, verbose); 8110fcd48feSSimon Glass if (ret) 8120fcd48feSSimon Glass return ret; 8130fcd48feSSimon Glass } 8140fcd48feSSimon Glass 8150fcd48feSSimon Glass return 0; 8160fcd48feSSimon Glass } 8170fcd48feSSimon Glass #else 8188eab1a58SSimon Glass int scsi_scan(bool verbose) 8190fcd48feSSimon Glass { 8200fcd48feSSimon Glass unsigned char i, lun; 8210fcd48feSSimon Glass int ret; 8220fcd48feSSimon Glass 8238eab1a58SSimon Glass if (verbose) 8240fcd48feSSimon Glass printf("scanning bus for devices...\n"); 8250fcd48feSSimon Glass for (i = 0; i < CONFIG_SYS_SCSI_MAX_DEVICE; i++) 8260fcd48feSSimon Glass scsi_init_dev_desc(&scsi_dev_desc[i], i); 8270fcd48feSSimon Glass 8280fcd48feSSimon Glass scsi_max_devs = 0; 8290fcd48feSSimon Glass for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { 8300fcd48feSSimon Glass for (lun = 0; lun < CONFIG_SYS_SCSI_MAX_LUN; lun++) { 8314682c8a1SSimon Glass ret = scsi_detect_dev(NULL, i, lun, 8320fcd48feSSimon Glass &scsi_dev_desc[scsi_max_devs]); 8330fcd48feSSimon Glass if (ret) 8340fcd48feSSimon Glass continue; 8350fcd48feSSimon Glass part_init(&scsi_dev_desc[scsi_max_devs]); 8360fcd48feSSimon Glass 8378eab1a58SSimon Glass if (verbose) { 8380fcd48feSSimon Glass printf(" Device %d: ", 0); 8390fcd48feSSimon Glass dev_print(&scsi_dev_desc[scsi_max_devs]); 8408eab1a58SSimon Glass } 8410fcd48feSSimon Glass scsi_max_devs++; 8420fcd48feSSimon Glass } /* next LUN */ 8430fcd48feSSimon Glass } 8440fcd48feSSimon Glass if (scsi_max_devs > 0) 8450fcd48feSSimon Glass scsi_curr_dev = 0; 8460fcd48feSSimon Glass else 8470fcd48feSSimon Glass scsi_curr_dev = -1; 8480fcd48feSSimon Glass 8490fcd48feSSimon Glass printf("Found %d device(s).\n", scsi_max_devs); 8500fcd48feSSimon Glass #ifndef CONFIG_SPL_BUILD 851018f5303SSimon Glass env_set_ulong("scsidevs", scsi_max_devs); 8520fcd48feSSimon Glass #endif 8530fcd48feSSimon Glass return 0; 8540fcd48feSSimon Glass } 8550fcd48feSSimon Glass #endif 8560fcd48feSSimon Glass 8570fcd48feSSimon Glass #ifdef CONFIG_BLK 8580fcd48feSSimon Glass static const struct blk_ops scsi_blk_ops = { 8590fcd48feSSimon Glass .read = scsi_read, 8600fcd48feSSimon Glass .write = scsi_write, 86163a7b5a0SYifeng Zhao .erase = scsi_erase, 8620fcd48feSSimon Glass }; 8630fcd48feSSimon Glass 8640fcd48feSSimon Glass U_BOOT_DRIVER(scsi_blk) = { 8650fcd48feSSimon Glass .name = "scsi_blk", 8660fcd48feSSimon Glass .id = UCLASS_BLK, 8670fcd48feSSimon Glass .ops = &scsi_blk_ops, 8680fcd48feSSimon Glass }; 8690fcd48feSSimon Glass #else 8700fcd48feSSimon Glass U_BOOT_LEGACY_BLK(scsi) = { 8710fcd48feSSimon Glass .if_typename = "scsi", 8720fcd48feSSimon Glass .if_type = IF_TYPE_SCSI, 8730fcd48feSSimon Glass .max_devs = CONFIG_SYS_SCSI_MAX_DEVICE, 8740fcd48feSSimon Glass .desc = scsi_dev_desc, 8750fcd48feSSimon Glass }; 8760fcd48feSSimon Glass #endif 877