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; 112*52f5f55eSYifeng Zhao pccb->cmd[1] = pccb->lun << 5 | 0x8; 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 146*52f5f55eSYifeng Zhao static ulong _scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, 1470fcd48feSSimon Glass void *buffer) 1480fcd48feSSimon Glass #else 149*52f5f55eSYifeng Zhao 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; 1758f7de514SShawn Lin pccb->dma_dir = DMA_FROM_DEVICE; 1760fcd48feSSimon Glass #ifdef CONFIG_SYS_64BIT_LBA 1770fcd48feSSimon Glass if (start > SCSI_LBA48_READ) { 1780fcd48feSSimon Glass unsigned long blocks; 1790fcd48feSSimon Glass blocks = min_t(lbaint_t, blks, SCSI_MAX_READ_BLK); 180*52f5f55eSYifeng Zhao pccb->datalen = block_dev->rawblksz * blocks; 1810fcd48feSSimon Glass scsi_setup_read16(pccb, start, blocks); 1820fcd48feSSimon Glass start += blocks; 1830fcd48feSSimon Glass blks -= blocks; 1840fcd48feSSimon Glass } else 1850fcd48feSSimon Glass #endif 1860fcd48feSSimon Glass if (blks > SCSI_MAX_READ_BLK) { 187*52f5f55eSYifeng Zhao pccb->datalen = block_dev->rawblksz * 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 { 193*52f5f55eSYifeng Zhao pccb->datalen = block_dev->rawblksz * 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 214*52f5f55eSYifeng Zhao #ifdef CONFIG_BLK 215*52f5f55eSYifeng Zhao static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, 216*52f5f55eSYifeng Zhao void *buffer) 217*52f5f55eSYifeng Zhao #else 218*52f5f55eSYifeng Zhao static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr, 219*52f5f55eSYifeng Zhao lbaint_t blkcnt, void *buffer) 220*52f5f55eSYifeng Zhao #endif 221*52f5f55eSYifeng Zhao { 222*52f5f55eSYifeng Zhao #ifdef CONFIG_BLK 223*52f5f55eSYifeng Zhao struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 224*52f5f55eSYifeng Zhao uint32_t rawsectsz = block_dev->rawblksz / 512; 225*52f5f55eSYifeng Zhao long ret = blkcnt; 226*52f5f55eSYifeng Zhao 227*52f5f55eSYifeng Zhao if (rawsectsz == 8) { 228*52f5f55eSYifeng Zhao if ((blknr & (rawsectsz - 1)) || (blkcnt & (rawsectsz - 1))) { 229*52f5f55eSYifeng Zhao uint32_t offset, n_sec, num_lpa; 230*52f5f55eSYifeng Zhao long lpa; 231*52f5f55eSYifeng Zhao 232*52f5f55eSYifeng Zhao while (blkcnt) { 233*52f5f55eSYifeng Zhao lpa = blknr / rawsectsz; 234*52f5f55eSYifeng Zhao offset = blknr & (rawsectsz - 1); 235*52f5f55eSYifeng Zhao n_sec = rawsectsz - offset; 236*52f5f55eSYifeng Zhao if (n_sec > blkcnt) 237*52f5f55eSYifeng Zhao n_sec = blkcnt; 238*52f5f55eSYifeng Zhao 239*52f5f55eSYifeng Zhao if (offset || n_sec < rawsectsz) { 240*52f5f55eSYifeng Zhao _scsi_read(dev, lpa, 1, block_dev->align_sector_buf); 241*52f5f55eSYifeng Zhao memcpy(buffer, block_dev->align_sector_buf + offset * 512, n_sec * 512); 242*52f5f55eSYifeng Zhao } else { 243*52f5f55eSYifeng Zhao num_lpa = blkcnt / rawsectsz; 244*52f5f55eSYifeng Zhao n_sec = num_lpa * rawsectsz; 245*52f5f55eSYifeng Zhao _scsi_read(dev, lpa, num_lpa, buffer); 246*52f5f55eSYifeng Zhao } 247*52f5f55eSYifeng Zhao blkcnt -= n_sec; 248*52f5f55eSYifeng Zhao blknr += n_sec; 249*52f5f55eSYifeng Zhao buffer += 512 * n_sec; 250*52f5f55eSYifeng Zhao } 251*52f5f55eSYifeng Zhao 252*52f5f55eSYifeng Zhao return ret; 253*52f5f55eSYifeng Zhao } 254*52f5f55eSYifeng Zhao blknr /= rawsectsz; 255*52f5f55eSYifeng Zhao blkcnt /= rawsectsz; 256*52f5f55eSYifeng Zhao _scsi_read(dev, blknr, blkcnt, buffer); 257*52f5f55eSYifeng Zhao 258*52f5f55eSYifeng Zhao return ret; 259*52f5f55eSYifeng Zhao } 260*52f5f55eSYifeng Zhao 261*52f5f55eSYifeng Zhao return _scsi_read(dev, blknr, blkcnt, buffer); 262*52f5f55eSYifeng Zhao #else 263*52f5f55eSYifeng Zhao return _scsi_read(block_dev, blknr, blkcnt, buffer); 264*52f5f55eSYifeng Zhao #endif 265*52f5f55eSYifeng Zhao } 2660fcd48feSSimon Glass /******************************************************************************* 2670fcd48feSSimon Glass * scsi_write 2680fcd48feSSimon Glass */ 2690fcd48feSSimon Glass 2700fcd48feSSimon Glass /* Almost the maximum amount of the scsi_ext command.. */ 2710fcd48feSSimon Glass #define SCSI_MAX_WRITE_BLK 0xFFFF 2720fcd48feSSimon Glass 2730fcd48feSSimon Glass #ifdef CONFIG_BLK 274*52f5f55eSYifeng Zhao static ulong _scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, 2750fcd48feSSimon Glass const void *buffer) 2760fcd48feSSimon Glass #else 277*52f5f55eSYifeng Zhao static ulong _scsi_write(struct blk_desc *block_dev, lbaint_t blknr, 2780fcd48feSSimon Glass lbaint_t blkcnt, const void *buffer) 2790fcd48feSSimon Glass #endif 2800fcd48feSSimon Glass { 2810fcd48feSSimon Glass #ifdef CONFIG_BLK 2820fcd48feSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 2834682c8a1SSimon Glass struct udevice *bdev = dev->parent; 2844682c8a1SSimon Glass #else 2854682c8a1SSimon Glass struct udevice *bdev = NULL; 2860fcd48feSSimon Glass #endif 2870fcd48feSSimon Glass lbaint_t start, blks; 2880fcd48feSSimon Glass uintptr_t buf_addr; 2890fcd48feSSimon Glass unsigned short smallblks; 290b9560ad6SSimon Glass struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb; 2910fcd48feSSimon Glass 2920fcd48feSSimon Glass /* Setup device */ 2930fcd48feSSimon Glass pccb->target = block_dev->target; 2940fcd48feSSimon Glass pccb->lun = block_dev->lun; 2950fcd48feSSimon Glass buf_addr = (unsigned long)buffer; 2960fcd48feSSimon Glass start = blknr; 2970fcd48feSSimon Glass blks = blkcnt; 2980fcd48feSSimon Glass debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n", 2990fcd48feSSimon Glass __func__, block_dev->devnum, start, blks, (unsigned long)buffer); 3000fcd48feSSimon Glass do { 3010fcd48feSSimon Glass pccb->pdata = (unsigned char *)buf_addr; 3028f7de514SShawn Lin pccb->dma_dir = DMA_TO_DEVICE; 3030fcd48feSSimon Glass if (blks > SCSI_MAX_WRITE_BLK) { 304*52f5f55eSYifeng Zhao pccb->datalen = (block_dev->rawblksz * SCSI_MAX_WRITE_BLK); 3050fcd48feSSimon Glass smallblks = SCSI_MAX_WRITE_BLK; 3060fcd48feSSimon Glass scsi_setup_write_ext(pccb, start, smallblks); 3070fcd48feSSimon Glass start += SCSI_MAX_WRITE_BLK; 3080fcd48feSSimon Glass blks -= SCSI_MAX_WRITE_BLK; 3090fcd48feSSimon Glass } else { 310*52f5f55eSYifeng Zhao pccb->datalen = block_dev->rawblksz * blks; 3110fcd48feSSimon Glass smallblks = (unsigned short)blks; 3120fcd48feSSimon Glass scsi_setup_write_ext(pccb, start, smallblks); 3130fcd48feSSimon Glass start += blks; 3140fcd48feSSimon Glass blks = 0; 3150fcd48feSSimon Glass } 3160fcd48feSSimon Glass debug("%s: startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", 3170fcd48feSSimon Glass __func__, start, smallblks, buf_addr); 3184682c8a1SSimon Glass if (scsi_exec(bdev, pccb)) { 3190fcd48feSSimon Glass scsi_print_error(pccb); 3200fcd48feSSimon Glass blkcnt -= blks; 3210fcd48feSSimon Glass break; 3220fcd48feSSimon Glass } 3230fcd48feSSimon Glass buf_addr += pccb->datalen; 3240fcd48feSSimon Glass } while (blks != 0); 3250fcd48feSSimon Glass debug("%s: end startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", 3260fcd48feSSimon Glass __func__, start, smallblks, buf_addr); 3270fcd48feSSimon Glass return blkcnt; 3280fcd48feSSimon Glass } 3290fcd48feSSimon Glass 330*52f5f55eSYifeng Zhao #ifdef CONFIG_BLK 331*52f5f55eSYifeng Zhao static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, 332*52f5f55eSYifeng Zhao const void *buffer) 333*52f5f55eSYifeng Zhao #else 334*52f5f55eSYifeng Zhao static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr, 335*52f5f55eSYifeng Zhao lbaint_t blkcnt, const void *buffer) 336*52f5f55eSYifeng Zhao #endif 337*52f5f55eSYifeng Zhao { 338*52f5f55eSYifeng Zhao #ifdef CONFIG_BLK 339*52f5f55eSYifeng Zhao struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 340*52f5f55eSYifeng Zhao uint32_t rawsectsz = block_dev->rawblksz / 512; 341*52f5f55eSYifeng Zhao long ret = blkcnt; 342*52f5f55eSYifeng Zhao 343*52f5f55eSYifeng Zhao if (rawsectsz == 8) { 344*52f5f55eSYifeng Zhao if ((blknr & (rawsectsz - 1)) || (blkcnt & (rawsectsz - 1))) { 345*52f5f55eSYifeng Zhao uint32_t num_lpa, offset, n_sec; 346*52f5f55eSYifeng Zhao long lpa; 347*52f5f55eSYifeng Zhao 348*52f5f55eSYifeng Zhao while (blkcnt) { 349*52f5f55eSYifeng Zhao lpa = blknr / rawsectsz; 350*52f5f55eSYifeng Zhao offset = blknr & (rawsectsz - 1); 351*52f5f55eSYifeng Zhao n_sec = rawsectsz - offset; 352*52f5f55eSYifeng Zhao if (n_sec > blkcnt) 353*52f5f55eSYifeng Zhao n_sec = blkcnt; 354*52f5f55eSYifeng Zhao if (offset || n_sec < rawsectsz) { 355*52f5f55eSYifeng Zhao _scsi_read(dev, lpa, 1, block_dev->align_sector_buf); 356*52f5f55eSYifeng Zhao memcpy(block_dev->align_sector_buf + offset * 512, buffer, n_sec * 512); 357*52f5f55eSYifeng Zhao _scsi_write(dev, lpa, 1, block_dev->align_sector_buf); 358*52f5f55eSYifeng Zhao } else { 359*52f5f55eSYifeng Zhao num_lpa = blkcnt / rawsectsz; 360*52f5f55eSYifeng Zhao n_sec = num_lpa * rawsectsz; 361*52f5f55eSYifeng Zhao _scsi_write(dev, lpa, num_lpa, buffer); 362*52f5f55eSYifeng Zhao } 363*52f5f55eSYifeng Zhao blkcnt -= n_sec; 364*52f5f55eSYifeng Zhao blknr += n_sec; 365*52f5f55eSYifeng Zhao buffer += 512 * n_sec; 366*52f5f55eSYifeng Zhao } 367*52f5f55eSYifeng Zhao 368*52f5f55eSYifeng Zhao return ret; 369*52f5f55eSYifeng Zhao } 370*52f5f55eSYifeng Zhao blknr /= rawsectsz; 371*52f5f55eSYifeng Zhao blkcnt /= rawsectsz; 372*52f5f55eSYifeng Zhao _scsi_write(dev, blknr, blkcnt, buffer); 373*52f5f55eSYifeng Zhao 374*52f5f55eSYifeng Zhao return ret; 375*52f5f55eSYifeng Zhao } 376*52f5f55eSYifeng Zhao 377*52f5f55eSYifeng Zhao return _scsi_write(dev, blknr, blkcnt, buffer); 378*52f5f55eSYifeng Zhao #else 379*52f5f55eSYifeng Zhao return _scsi_write(block_dev, blknr, blkcnt, buffer); 380*52f5f55eSYifeng Zhao #endif 381*52f5f55eSYifeng Zhao 382*52f5f55eSYifeng Zhao } 383*52f5f55eSYifeng Zhao 3847337fcd8SSimon Glass #if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) && \ 3857337fcd8SSimon Glass !defined(CONFIG_DM_SCSI) 3860fcd48feSSimon Glass void scsi_init(void) 3870fcd48feSSimon Glass { 3880fcd48feSSimon Glass int busdevfunc = -1; 3890fcd48feSSimon Glass int i; 3900fcd48feSSimon Glass /* 3910fcd48feSSimon Glass * Find a device from the list, this driver will support a single 3920fcd48feSSimon Glass * controller. 3930fcd48feSSimon Glass */ 3940fcd48feSSimon Glass for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) { 3950fcd48feSSimon Glass /* get PCI Device ID */ 3960fcd48feSSimon Glass #ifdef CONFIG_DM_PCI 3970fcd48feSSimon Glass struct udevice *dev; 3980fcd48feSSimon Glass int ret; 3990fcd48feSSimon Glass 4000fcd48feSSimon Glass ret = dm_pci_find_device(scsi_device_list[i].vendor, 4010fcd48feSSimon Glass scsi_device_list[i].device, 0, &dev); 4020fcd48feSSimon Glass if (!ret) { 4030fcd48feSSimon Glass busdevfunc = dm_pci_get_bdf(dev); 4040fcd48feSSimon Glass break; 4050fcd48feSSimon Glass } 4060fcd48feSSimon Glass #else 4070fcd48feSSimon Glass busdevfunc = pci_find_device(scsi_device_list[i].vendor, 4080fcd48feSSimon Glass scsi_device_list[i].device, 4090fcd48feSSimon Glass 0); 4100fcd48feSSimon Glass #endif 4110fcd48feSSimon Glass if (busdevfunc != -1) 4120fcd48feSSimon Glass break; 4130fcd48feSSimon Glass } 4140fcd48feSSimon Glass 4150fcd48feSSimon Glass if (busdevfunc == -1) { 4160fcd48feSSimon Glass printf("Error: SCSI Controller(s) "); 4170fcd48feSSimon Glass for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) { 4180fcd48feSSimon Glass printf("%04X:%04X ", 4190fcd48feSSimon Glass scsi_device_list[i].vendor, 4200fcd48feSSimon Glass scsi_device_list[i].device); 4210fcd48feSSimon Glass } 4220fcd48feSSimon Glass printf("not found\n"); 4230fcd48feSSimon Glass return; 4240fcd48feSSimon Glass } 4250fcd48feSSimon Glass #ifdef DEBUG 4260fcd48feSSimon Glass else { 4270fcd48feSSimon Glass printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n", 4280fcd48feSSimon Glass scsi_device_list[i].vendor, 4290fcd48feSSimon Glass scsi_device_list[i].device, 4300fcd48feSSimon Glass (busdevfunc >> 16) & 0xFF, 4310fcd48feSSimon Glass (busdevfunc >> 11) & 0x1F, 4320fcd48feSSimon Glass (busdevfunc >> 8) & 0x7); 4330fcd48feSSimon Glass } 4340fcd48feSSimon Glass #endif 4350fcd48feSSimon Glass bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci"); 4360fcd48feSSimon Glass scsi_low_level_init(busdevfunc); 4378eab1a58SSimon Glass scsi_scan(true); 4380fcd48feSSimon Glass bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI); 4390fcd48feSSimon Glass } 4400fcd48feSSimon Glass #endif 4410fcd48feSSimon Glass 4420fcd48feSSimon Glass /* copy src to dest, skipping leading and trailing blanks 4430fcd48feSSimon Glass * and null terminate the string 4440fcd48feSSimon Glass */ 4450fcd48feSSimon Glass static void scsi_ident_cpy(unsigned char *dest, unsigned char *src, 4460fcd48feSSimon Glass unsigned int len) 4470fcd48feSSimon Glass { 4480fcd48feSSimon Glass int start, end; 4490fcd48feSSimon Glass 4500fcd48feSSimon Glass start = 0; 4510fcd48feSSimon Glass while (start < len) { 4520fcd48feSSimon Glass if (src[start] != ' ') 4530fcd48feSSimon Glass break; 4540fcd48feSSimon Glass start++; 4550fcd48feSSimon Glass } 4560fcd48feSSimon Glass end = len-1; 4570fcd48feSSimon Glass while (end > start) { 4580fcd48feSSimon Glass if (src[end] != ' ') 4590fcd48feSSimon Glass break; 4600fcd48feSSimon Glass end--; 4610fcd48feSSimon Glass } 4620fcd48feSSimon Glass for (; start <= end; start++) 4630fcd48feSSimon Glass *dest ++= src[start]; 4640fcd48feSSimon Glass *dest = '\0'; 4650fcd48feSSimon Glass } 4660fcd48feSSimon Glass 4674682c8a1SSimon Glass static int scsi_read_capacity(struct udevice *dev, struct scsi_cmd *pccb, 4684682c8a1SSimon Glass lbaint_t *capacity, unsigned long *blksz) 4690fcd48feSSimon Glass { 4700fcd48feSSimon Glass *capacity = 0; 4710fcd48feSSimon Glass 4720fcd48feSSimon Glass memset(pccb->cmd, '\0', sizeof(pccb->cmd)); 4730fcd48feSSimon Glass pccb->cmd[0] = SCSI_RD_CAPAC10; 4740fcd48feSSimon Glass pccb->cmd[1] = pccb->lun << 5; 4750fcd48feSSimon Glass pccb->cmdlen = 10; 4760fcd48feSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 4770fcd48feSSimon Glass 4780fcd48feSSimon Glass pccb->datalen = 8; 479f6580ef3SSimon Glass if (scsi_exec(dev, pccb)) 4800fcd48feSSimon Glass return 1; 4810fcd48feSSimon Glass 4820fcd48feSSimon Glass *capacity = ((lbaint_t)pccb->pdata[0] << 24) | 4830fcd48feSSimon Glass ((lbaint_t)pccb->pdata[1] << 16) | 4840fcd48feSSimon Glass ((lbaint_t)pccb->pdata[2] << 8) | 4850fcd48feSSimon Glass ((lbaint_t)pccb->pdata[3]); 4860fcd48feSSimon Glass 4870fcd48feSSimon Glass if (*capacity != 0xffffffff) { 4880fcd48feSSimon Glass /* Read capacity (10) was sufficient for this drive. */ 4890fcd48feSSimon Glass *blksz = ((unsigned long)pccb->pdata[4] << 24) | 4900fcd48feSSimon Glass ((unsigned long)pccb->pdata[5] << 16) | 4910fcd48feSSimon Glass ((unsigned long)pccb->pdata[6] << 8) | 4920fcd48feSSimon Glass ((unsigned long)pccb->pdata[7]); 493*52f5f55eSYifeng Zhao *capacity = *capacity + 1; 4940fcd48feSSimon Glass return 0; 4950fcd48feSSimon Glass } 4960fcd48feSSimon Glass 4970fcd48feSSimon Glass /* Read capacity (10) was insufficient. Use read capacity (16). */ 4980fcd48feSSimon Glass memset(pccb->cmd, '\0', sizeof(pccb->cmd)); 4990fcd48feSSimon Glass pccb->cmd[0] = SCSI_RD_CAPAC16; 5000fcd48feSSimon Glass pccb->cmd[1] = 0x10; 5010fcd48feSSimon Glass pccb->cmdlen = 16; 5020fcd48feSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 5030fcd48feSSimon Glass 5040fcd48feSSimon Glass pccb->datalen = 16; 5058f7de514SShawn Lin pccb->dma_dir = DMA_FROM_DEVICE; 506f6580ef3SSimon Glass if (scsi_exec(dev, pccb)) 5070fcd48feSSimon Glass return 1; 5080fcd48feSSimon Glass 5090fcd48feSSimon Glass *capacity = ((uint64_t)pccb->pdata[0] << 56) | 5100fcd48feSSimon Glass ((uint64_t)pccb->pdata[1] << 48) | 5110fcd48feSSimon Glass ((uint64_t)pccb->pdata[2] << 40) | 5120fcd48feSSimon Glass ((uint64_t)pccb->pdata[3] << 32) | 5130fcd48feSSimon Glass ((uint64_t)pccb->pdata[4] << 24) | 5140fcd48feSSimon Glass ((uint64_t)pccb->pdata[5] << 16) | 5150fcd48feSSimon Glass ((uint64_t)pccb->pdata[6] << 8) | 5160fcd48feSSimon Glass ((uint64_t)pccb->pdata[7]); 517*52f5f55eSYifeng Zhao *capacity = *capacity + 1; 5180fcd48feSSimon Glass 5190fcd48feSSimon Glass *blksz = ((uint64_t)pccb->pdata[8] << 56) | 5200fcd48feSSimon Glass ((uint64_t)pccb->pdata[9] << 48) | 5210fcd48feSSimon Glass ((uint64_t)pccb->pdata[10] << 40) | 5220fcd48feSSimon Glass ((uint64_t)pccb->pdata[11] << 32) | 5230fcd48feSSimon Glass ((uint64_t)pccb->pdata[12] << 24) | 5240fcd48feSSimon Glass ((uint64_t)pccb->pdata[13] << 16) | 5250fcd48feSSimon Glass ((uint64_t)pccb->pdata[14] << 8) | 5260fcd48feSSimon Glass ((uint64_t)pccb->pdata[15]); 5270fcd48feSSimon Glass 5280fcd48feSSimon Glass return 0; 5290fcd48feSSimon Glass } 5300fcd48feSSimon Glass 5310fcd48feSSimon Glass 5320fcd48feSSimon Glass /* 5330fcd48feSSimon Glass * Some setup (fill-in) routines 5340fcd48feSSimon Glass */ 535b9560ad6SSimon Glass static void scsi_setup_test_unit_ready(struct scsi_cmd *pccb) 5360fcd48feSSimon Glass { 5370fcd48feSSimon Glass pccb->cmd[0] = SCSI_TST_U_RDY; 5380fcd48feSSimon Glass pccb->cmd[1] = pccb->lun << 5; 5390fcd48feSSimon Glass pccb->cmd[2] = 0; 5400fcd48feSSimon Glass pccb->cmd[3] = 0; 5410fcd48feSSimon Glass pccb->cmd[4] = 0; 5420fcd48feSSimon Glass pccb->cmd[5] = 0; 5430fcd48feSSimon Glass pccb->cmdlen = 6; 5440fcd48feSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 5450fcd48feSSimon Glass } 5460fcd48feSSimon Glass 5470fcd48feSSimon Glass /** 5480fcd48feSSimon Glass * scsi_init_dev_desc_priv - initialize only SCSI specific blk_desc properties 5490fcd48feSSimon Glass * 5500fcd48feSSimon Glass * @dev_desc: Block device description pointer 5510fcd48feSSimon Glass */ 5520fcd48feSSimon Glass static void scsi_init_dev_desc_priv(struct blk_desc *dev_desc) 5530fcd48feSSimon Glass { 5540fcd48feSSimon Glass dev_desc->target = 0xff; 5550fcd48feSSimon Glass dev_desc->lun = 0xff; 5560fcd48feSSimon Glass dev_desc->log2blksz = 5570fcd48feSSimon Glass LOG2_INVALID(typeof(dev_desc->log2blksz)); 5580fcd48feSSimon Glass dev_desc->type = DEV_TYPE_UNKNOWN; 5590fcd48feSSimon Glass dev_desc->vendor[0] = 0; 5600fcd48feSSimon Glass dev_desc->product[0] = 0; 5610fcd48feSSimon Glass dev_desc->revision[0] = 0; 5620fcd48feSSimon Glass dev_desc->removable = false; 563c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 5640fcd48feSSimon Glass dev_desc->block_read = scsi_read; 5650fcd48feSSimon Glass dev_desc->block_write = scsi_write; 5660fcd48feSSimon Glass #endif 5670fcd48feSSimon Glass } 5680fcd48feSSimon Glass 5690fcd48feSSimon Glass #if !defined(CONFIG_DM_SCSI) 5700fcd48feSSimon Glass /** 5710fcd48feSSimon Glass * scsi_init_dev_desc - initialize all SCSI specific blk_desc properties 5720fcd48feSSimon Glass * 5730fcd48feSSimon Glass * @dev_desc: Block device description pointer 5740fcd48feSSimon Glass * @devnum: Device number 5750fcd48feSSimon Glass */ 5760fcd48feSSimon Glass static void scsi_init_dev_desc(struct blk_desc *dev_desc, int devnum) 5770fcd48feSSimon Glass { 5780fcd48feSSimon Glass dev_desc->lba = 0; 5790fcd48feSSimon Glass dev_desc->blksz = 0; 5800fcd48feSSimon Glass dev_desc->if_type = IF_TYPE_SCSI; 5810fcd48feSSimon Glass dev_desc->devnum = devnum; 5820fcd48feSSimon Glass dev_desc->part_type = PART_TYPE_UNKNOWN; 5830fcd48feSSimon Glass 5840fcd48feSSimon Glass scsi_init_dev_desc_priv(dev_desc); 5850fcd48feSSimon Glass } 5860fcd48feSSimon Glass #endif 5870fcd48feSSimon Glass 5880fcd48feSSimon Glass /** 5890fcd48feSSimon Glass * scsi_detect_dev - Detect scsi device 5900fcd48feSSimon Glass * 5910fcd48feSSimon Glass * @target: target id 5920fcd48feSSimon Glass * @lun: target lun 5930fcd48feSSimon Glass * @dev_desc: block device description 5940fcd48feSSimon Glass * 5950fcd48feSSimon Glass * The scsi_detect_dev detects and fills a dev_desc structure when the device is 5960fcd48feSSimon Glass * detected. 5970fcd48feSSimon Glass * 5980fcd48feSSimon Glass * Return: 0 on success, error value otherwise 5990fcd48feSSimon Glass */ 6004682c8a1SSimon Glass static int scsi_detect_dev(struct udevice *dev, int target, int lun, 6014682c8a1SSimon Glass struct blk_desc *dev_desc) 6020fcd48feSSimon Glass { 6030fcd48feSSimon Glass unsigned char perq, modi; 6040fcd48feSSimon Glass lbaint_t capacity; 6050fcd48feSSimon Glass unsigned long blksz; 606b9560ad6SSimon Glass struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb; 6070fcd48feSSimon Glass 6080fcd48feSSimon Glass pccb->target = target; 6090fcd48feSSimon Glass pccb->lun = lun; 6100fcd48feSSimon Glass pccb->pdata = (unsigned char *)&tempbuff; 6110fcd48feSSimon Glass pccb->datalen = 512; 6128f7de514SShawn Lin pccb->dma_dir = DMA_FROM_DEVICE; 6130fcd48feSSimon Glass scsi_setup_inquiry(pccb); 614f6580ef3SSimon Glass if (scsi_exec(dev, pccb)) { 6150fcd48feSSimon Glass if (pccb->contr_stat == SCSI_SEL_TIME_OUT) { 6160fcd48feSSimon Glass /* 6170fcd48feSSimon Glass * selection timeout => assuming no 6180fcd48feSSimon Glass * device present 6190fcd48feSSimon Glass */ 6200fcd48feSSimon Glass debug("Selection timeout ID %d\n", 6210fcd48feSSimon Glass pccb->target); 6220fcd48feSSimon Glass return -ETIMEDOUT; 6230fcd48feSSimon Glass } 6240fcd48feSSimon Glass scsi_print_error(pccb); 6250fcd48feSSimon Glass return -ENODEV; 6260fcd48feSSimon Glass } 6270fcd48feSSimon Glass perq = tempbuff[0]; 6280fcd48feSSimon Glass modi = tempbuff[1]; 6290fcd48feSSimon Glass if ((perq & 0x1f) == 0x1f) 6300fcd48feSSimon Glass return -ENODEV; /* skip unknown devices */ 6310fcd48feSSimon Glass if ((modi & 0x80) == 0x80) /* drive is removable */ 6320fcd48feSSimon Glass dev_desc->removable = true; 6330fcd48feSSimon Glass /* get info for this device */ 6340fcd48feSSimon Glass scsi_ident_cpy((unsigned char *)dev_desc->vendor, 6350fcd48feSSimon Glass &tempbuff[8], 8); 6360fcd48feSSimon Glass scsi_ident_cpy((unsigned char *)dev_desc->product, 6370fcd48feSSimon Glass &tempbuff[16], 16); 6380fcd48feSSimon Glass scsi_ident_cpy((unsigned char *)dev_desc->revision, 6390fcd48feSSimon Glass &tempbuff[32], 4); 6400fcd48feSSimon Glass dev_desc->target = pccb->target; 6410fcd48feSSimon Glass dev_desc->lun = pccb->lun; 6420fcd48feSSimon Glass 6430fcd48feSSimon Glass pccb->datalen = 0; 6440fcd48feSSimon Glass scsi_setup_test_unit_ready(pccb); 645f6580ef3SSimon Glass if (scsi_exec(dev, pccb)) { 6460fcd48feSSimon Glass if (dev_desc->removable) { 6470fcd48feSSimon Glass dev_desc->type = perq; 6480fcd48feSSimon Glass goto removable; 6490fcd48feSSimon Glass } 6500fcd48feSSimon Glass scsi_print_error(pccb); 6510fcd48feSSimon Glass return -EINVAL; 6520fcd48feSSimon Glass } 6534682c8a1SSimon Glass if (scsi_read_capacity(dev, pccb, &capacity, &blksz)) { 6540fcd48feSSimon Glass scsi_print_error(pccb); 6550fcd48feSSimon Glass return -EINVAL; 6560fcd48feSSimon Glass } 657*52f5f55eSYifeng Zhao 6580fcd48feSSimon Glass dev_desc->lba = capacity; 6590fcd48feSSimon Glass dev_desc->blksz = blksz; 6600fcd48feSSimon Glass dev_desc->log2blksz = LOG2(dev_desc->blksz); 6610fcd48feSSimon Glass dev_desc->type = perq; 6620fcd48feSSimon Glass removable: 6630fcd48feSSimon Glass return 0; 6640fcd48feSSimon Glass } 6650fcd48feSSimon Glass 6660fcd48feSSimon Glass /* 6670fcd48feSSimon Glass * (re)-scan the scsi bus and reports scsi device info 6680fcd48feSSimon Glass * to the user if mode = 1 6690fcd48feSSimon Glass */ 6700fcd48feSSimon Glass #if defined(CONFIG_DM_SCSI) 6718eab1a58SSimon Glass static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose) 6720fcd48feSSimon Glass { 6730fcd48feSSimon Glass int ret; 6740fcd48feSSimon Glass struct udevice *bdev; 6750fcd48feSSimon Glass struct blk_desc bd; 6760fcd48feSSimon Glass struct blk_desc *bdesc; 6770fcd48feSSimon Glass char str[10]; 6780fcd48feSSimon Glass 6790fcd48feSSimon Glass /* 6800fcd48feSSimon Glass * detect the scsi driver to get information about its geometry (block 6810fcd48feSSimon Glass * size, number of blocks) and other parameters (ids, type, ...) 6820fcd48feSSimon Glass */ 6830fcd48feSSimon Glass scsi_init_dev_desc_priv(&bd); 6844682c8a1SSimon Glass if (scsi_detect_dev(dev, id, lun, &bd)) 6850fcd48feSSimon Glass return -ENODEV; 6860fcd48feSSimon Glass 6870fcd48feSSimon Glass /* 6880fcd48feSSimon Glass * Create only one block device and do detection 6890fcd48feSSimon Glass * to make sure that there won't be a lot of 6900fcd48feSSimon Glass * block devices created 6910fcd48feSSimon Glass */ 6920fcd48feSSimon Glass snprintf(str, sizeof(str), "id%dlun%d", id, lun); 6930fcd48feSSimon Glass ret = blk_create_devicef(dev, "scsi_blk", str, IF_TYPE_SCSI, -1, 6940fcd48feSSimon Glass bd.blksz, bd.blksz * bd.lba, &bdev); 6950fcd48feSSimon Glass if (ret) { 6960fcd48feSSimon Glass debug("Can't create device\n"); 6970fcd48feSSimon Glass return ret; 6980fcd48feSSimon Glass } 6990fcd48feSSimon Glass 7000fcd48feSSimon Glass bdesc = dev_get_uclass_platdata(bdev); 7010fcd48feSSimon Glass bdesc->target = id; 7020fcd48feSSimon Glass bdesc->lun = lun; 7030fcd48feSSimon Glass bdesc->removable = bd.removable; 7040fcd48feSSimon Glass bdesc->type = bd.type; 705*52f5f55eSYifeng Zhao 706*52f5f55eSYifeng Zhao if (bdesc->rawblksz == 4096) { 707*52f5f55eSYifeng Zhao bdesc->blksz = 512; 708*52f5f55eSYifeng Zhao bdesc->lba = bdesc->rawlba * 8; 709*52f5f55eSYifeng Zhao bdesc->align_sector_buf = memalign(CONFIG_SYS_CACHELINE_SIZE, bdesc->rawblksz); 710*52f5f55eSYifeng Zhao } 711*52f5f55eSYifeng Zhao 7120fcd48feSSimon Glass memcpy(&bdesc->vendor, &bd.vendor, sizeof(bd.vendor)); 7130fcd48feSSimon Glass memcpy(&bdesc->product, &bd.product, sizeof(bd.product)); 7140fcd48feSSimon Glass memcpy(&bdesc->revision, &bd.revision, sizeof(bd.revision)); 7150fcd48feSSimon Glass part_init(bdesc); 7160fcd48feSSimon Glass 7178eab1a58SSimon Glass if (verbose) { 7180fcd48feSSimon Glass printf(" Device %d: ", 0); 7190fcd48feSSimon Glass dev_print(bdesc); 7200fcd48feSSimon Glass } 7210fcd48feSSimon Glass return 0; 7220fcd48feSSimon Glass } 7230fcd48feSSimon Glass 7245c561763SSimon Glass int scsi_scan_dev(struct udevice *dev, bool verbose) 7255c561763SSimon Glass { 7265c561763SSimon Glass struct scsi_platdata *uc_plat; /* scsi controller platdata */ 7275c561763SSimon Glass int ret; 7285c561763SSimon Glass int i; 7295c561763SSimon Glass int lun; 7305c561763SSimon Glass 7315c561763SSimon Glass /* probe SCSI controller driver */ 7325c561763SSimon Glass ret = device_probe(dev); 7335c561763SSimon Glass if (ret) 7345c561763SSimon Glass return ret; 7355c561763SSimon Glass 7365c561763SSimon Glass /* Get controller platdata */ 7375c561763SSimon Glass uc_plat = dev_get_uclass_platdata(dev); 7385c561763SSimon Glass 7395c561763SSimon Glass for (i = 0; i < uc_plat->max_id; i++) 7405c561763SSimon Glass for (lun = 0; lun < uc_plat->max_lun; lun++) 7415c561763SSimon Glass do_scsi_scan_one(dev, i, lun, verbose); 7425c561763SSimon Glass 7435c561763SSimon Glass return 0; 7445c561763SSimon Glass } 7455c561763SSimon Glass 7468eab1a58SSimon Glass int scsi_scan(bool verbose) 7470fcd48feSSimon Glass { 7480fcd48feSSimon Glass struct uclass *uc; 7490fcd48feSSimon Glass struct udevice *dev; /* SCSI controller */ 7500fcd48feSSimon Glass int ret; 7510fcd48feSSimon Glass 7528eab1a58SSimon Glass if (verbose) 7530fcd48feSSimon Glass printf("scanning bus for devices...\n"); 7540fcd48feSSimon Glass 7550fcd48feSSimon Glass blk_unbind_all(IF_TYPE_SCSI); 7560fcd48feSSimon Glass 7570fcd48feSSimon Glass ret = uclass_get(UCLASS_SCSI, &uc); 7580fcd48feSSimon Glass if (ret) 7590fcd48feSSimon Glass return ret; 7600fcd48feSSimon Glass 7610fcd48feSSimon Glass uclass_foreach_dev(dev, uc) { 7625c561763SSimon Glass ret = scsi_scan_dev(dev, verbose); 7630fcd48feSSimon Glass if (ret) 7640fcd48feSSimon Glass return ret; 7650fcd48feSSimon Glass } 7660fcd48feSSimon Glass 7670fcd48feSSimon Glass return 0; 7680fcd48feSSimon Glass } 7690fcd48feSSimon Glass #else 7708eab1a58SSimon Glass int scsi_scan(bool verbose) 7710fcd48feSSimon Glass { 7720fcd48feSSimon Glass unsigned char i, lun; 7730fcd48feSSimon Glass int ret; 7740fcd48feSSimon Glass 7758eab1a58SSimon Glass if (verbose) 7760fcd48feSSimon Glass printf("scanning bus for devices...\n"); 7770fcd48feSSimon Glass for (i = 0; i < CONFIG_SYS_SCSI_MAX_DEVICE; i++) 7780fcd48feSSimon Glass scsi_init_dev_desc(&scsi_dev_desc[i], i); 7790fcd48feSSimon Glass 7800fcd48feSSimon Glass scsi_max_devs = 0; 7810fcd48feSSimon Glass for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { 7820fcd48feSSimon Glass for (lun = 0; lun < CONFIG_SYS_SCSI_MAX_LUN; lun++) { 7834682c8a1SSimon Glass ret = scsi_detect_dev(NULL, i, lun, 7840fcd48feSSimon Glass &scsi_dev_desc[scsi_max_devs]); 7850fcd48feSSimon Glass if (ret) 7860fcd48feSSimon Glass continue; 7870fcd48feSSimon Glass part_init(&scsi_dev_desc[scsi_max_devs]); 7880fcd48feSSimon Glass 7898eab1a58SSimon Glass if (verbose) { 7900fcd48feSSimon Glass printf(" Device %d: ", 0); 7910fcd48feSSimon Glass dev_print(&scsi_dev_desc[scsi_max_devs]); 7928eab1a58SSimon Glass } 7930fcd48feSSimon Glass scsi_max_devs++; 7940fcd48feSSimon Glass } /* next LUN */ 7950fcd48feSSimon Glass } 7960fcd48feSSimon Glass if (scsi_max_devs > 0) 7970fcd48feSSimon Glass scsi_curr_dev = 0; 7980fcd48feSSimon Glass else 7990fcd48feSSimon Glass scsi_curr_dev = -1; 8000fcd48feSSimon Glass 8010fcd48feSSimon Glass printf("Found %d device(s).\n", scsi_max_devs); 8020fcd48feSSimon Glass #ifndef CONFIG_SPL_BUILD 803018f5303SSimon Glass env_set_ulong("scsidevs", scsi_max_devs); 8040fcd48feSSimon Glass #endif 8050fcd48feSSimon Glass return 0; 8060fcd48feSSimon Glass } 8070fcd48feSSimon Glass #endif 8080fcd48feSSimon Glass 8090fcd48feSSimon Glass #ifdef CONFIG_BLK 8100fcd48feSSimon Glass static const struct blk_ops scsi_blk_ops = { 8110fcd48feSSimon Glass .read = scsi_read, 8120fcd48feSSimon Glass .write = scsi_write, 8130fcd48feSSimon Glass }; 8140fcd48feSSimon Glass 8150fcd48feSSimon Glass U_BOOT_DRIVER(scsi_blk) = { 8160fcd48feSSimon Glass .name = "scsi_blk", 8170fcd48feSSimon Glass .id = UCLASS_BLK, 8180fcd48feSSimon Glass .ops = &scsi_blk_ops, 8190fcd48feSSimon Glass }; 8200fcd48feSSimon Glass #else 8210fcd48feSSimon Glass U_BOOT_LEGACY_BLK(scsi) = { 8220fcd48feSSimon Glass .if_typename = "scsi", 8230fcd48feSSimon Glass .if_type = IF_TYPE_SCSI, 8240fcd48feSSimon Glass .max_devs = CONFIG_SYS_SCSI_MAX_DEVICE, 8250fcd48feSSimon Glass .desc = scsi_dev_desc, 8260fcd48feSSimon Glass }; 8270fcd48feSSimon Glass #endif 828