1*0fcd48feSSimon Glass /* 2*0fcd48feSSimon Glass * (C) Copyright 2001 3*0fcd48feSSimon Glass * Denis Peter, MPL AG Switzerland 4*0fcd48feSSimon Glass * 5*0fcd48feSSimon Glass * SPDX-License-Identifier: GPL-2.0+ 6*0fcd48feSSimon Glass */ 7*0fcd48feSSimon Glass 8*0fcd48feSSimon Glass #include <common.h> 9*0fcd48feSSimon Glass #include <dm.h> 10*0fcd48feSSimon Glass #include <inttypes.h> 11*0fcd48feSSimon Glass #include <pci.h> 12*0fcd48feSSimon Glass #include <scsi.h> 13*0fcd48feSSimon Glass #include <dm/device-internal.h> 14*0fcd48feSSimon Glass #include <dm/uclass-internal.h> 15*0fcd48feSSimon Glass 16*0fcd48feSSimon Glass #if !defined(CONFIG_DM_SCSI) 17*0fcd48feSSimon Glass #ifdef CONFIG_SCSI_DEV_LIST 18*0fcd48feSSimon Glass #define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST 19*0fcd48feSSimon Glass #else 20*0fcd48feSSimon Glass #ifdef CONFIG_SATA_ULI5288 21*0fcd48feSSimon Glass 22*0fcd48feSSimon Glass #define SCSI_VEND_ID 0x10b9 23*0fcd48feSSimon Glass #define SCSI_DEV_ID 0x5288 24*0fcd48feSSimon Glass 25*0fcd48feSSimon Glass #elif !defined(CONFIG_SCSI_AHCI_PLAT) 26*0fcd48feSSimon Glass #error no scsi device defined 27*0fcd48feSSimon Glass #endif 28*0fcd48feSSimon Glass #define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID} 29*0fcd48feSSimon Glass #endif 30*0fcd48feSSimon Glass #endif 31*0fcd48feSSimon Glass 32*0fcd48feSSimon Glass #if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) 33*0fcd48feSSimon Glass const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST }; 34*0fcd48feSSimon Glass #endif 35*0fcd48feSSimon Glass static ccb tempccb; /* temporary scsi command buffer */ 36*0fcd48feSSimon Glass 37*0fcd48feSSimon Glass static unsigned char tempbuff[512]; /* temporary data buffer */ 38*0fcd48feSSimon Glass 39*0fcd48feSSimon Glass #if !defined(CONFIG_DM_SCSI) 40*0fcd48feSSimon Glass static int scsi_max_devs; /* number of highest available scsi device */ 41*0fcd48feSSimon Glass 42*0fcd48feSSimon Glass static int scsi_curr_dev; /* current device */ 43*0fcd48feSSimon Glass 44*0fcd48feSSimon Glass static struct blk_desc scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE]; 45*0fcd48feSSimon Glass #endif 46*0fcd48feSSimon Glass 47*0fcd48feSSimon Glass /* almost the maximum amount of the scsi_ext command.. */ 48*0fcd48feSSimon Glass #define SCSI_MAX_READ_BLK 0xFFFF 49*0fcd48feSSimon Glass #define SCSI_LBA48_READ 0xFFFFFFF 50*0fcd48feSSimon Glass 51*0fcd48feSSimon Glass static void scsi_print_error(ccb *pccb) 52*0fcd48feSSimon Glass { 53*0fcd48feSSimon Glass /* Dummy function that could print an error for debugging */ 54*0fcd48feSSimon Glass } 55*0fcd48feSSimon Glass 56*0fcd48feSSimon Glass #ifdef CONFIG_SYS_64BIT_LBA 57*0fcd48feSSimon Glass void scsi_setup_read16(ccb *pccb, lbaint_t start, unsigned long blocks) 58*0fcd48feSSimon Glass { 59*0fcd48feSSimon Glass pccb->cmd[0] = SCSI_READ16; 60*0fcd48feSSimon Glass pccb->cmd[1] = pccb->lun << 5; 61*0fcd48feSSimon Glass pccb->cmd[2] = (unsigned char)(start >> 56) & 0xff; 62*0fcd48feSSimon Glass pccb->cmd[3] = (unsigned char)(start >> 48) & 0xff; 63*0fcd48feSSimon Glass pccb->cmd[4] = (unsigned char)(start >> 40) & 0xff; 64*0fcd48feSSimon Glass pccb->cmd[5] = (unsigned char)(start >> 32) & 0xff; 65*0fcd48feSSimon Glass pccb->cmd[6] = (unsigned char)(start >> 24) & 0xff; 66*0fcd48feSSimon Glass pccb->cmd[7] = (unsigned char)(start >> 16) & 0xff; 67*0fcd48feSSimon Glass pccb->cmd[8] = (unsigned char)(start >> 8) & 0xff; 68*0fcd48feSSimon Glass pccb->cmd[9] = (unsigned char)start & 0xff; 69*0fcd48feSSimon Glass pccb->cmd[10] = 0; 70*0fcd48feSSimon Glass pccb->cmd[11] = (unsigned char)(blocks >> 24) & 0xff; 71*0fcd48feSSimon Glass pccb->cmd[12] = (unsigned char)(blocks >> 16) & 0xff; 72*0fcd48feSSimon Glass pccb->cmd[13] = (unsigned char)(blocks >> 8) & 0xff; 73*0fcd48feSSimon Glass pccb->cmd[14] = (unsigned char)blocks & 0xff; 74*0fcd48feSSimon Glass pccb->cmd[15] = 0; 75*0fcd48feSSimon Glass pccb->cmdlen = 16; 76*0fcd48feSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 77*0fcd48feSSimon Glass debug("scsi_setup_read16: cmd: %02X %02X startblk %02X%02X%02X%02X%02X%02X%02X%02X blccnt %02X%02X%02X%02X\n", 78*0fcd48feSSimon Glass pccb->cmd[0], pccb->cmd[1], 79*0fcd48feSSimon Glass pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], 80*0fcd48feSSimon Glass pccb->cmd[6], pccb->cmd[7], pccb->cmd[8], pccb->cmd[9], 81*0fcd48feSSimon Glass pccb->cmd[11], pccb->cmd[12], pccb->cmd[13], pccb->cmd[14]); 82*0fcd48feSSimon Glass } 83*0fcd48feSSimon Glass #endif 84*0fcd48feSSimon Glass 85*0fcd48feSSimon Glass static void scsi_setup_read_ext(ccb *pccb, lbaint_t start, 86*0fcd48feSSimon Glass unsigned short blocks) 87*0fcd48feSSimon Glass { 88*0fcd48feSSimon Glass pccb->cmd[0] = SCSI_READ10; 89*0fcd48feSSimon Glass pccb->cmd[1] = pccb->lun << 5; 90*0fcd48feSSimon Glass pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff; 91*0fcd48feSSimon Glass pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff; 92*0fcd48feSSimon Glass pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff; 93*0fcd48feSSimon Glass pccb->cmd[5] = (unsigned char)start & 0xff; 94*0fcd48feSSimon Glass pccb->cmd[6] = 0; 95*0fcd48feSSimon Glass pccb->cmd[7] = (unsigned char)(blocks >> 8) & 0xff; 96*0fcd48feSSimon Glass pccb->cmd[8] = (unsigned char)blocks & 0xff; 97*0fcd48feSSimon Glass pccb->cmd[6] = 0; 98*0fcd48feSSimon Glass pccb->cmdlen = 10; 99*0fcd48feSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 100*0fcd48feSSimon Glass debug("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", 101*0fcd48feSSimon Glass pccb->cmd[0], pccb->cmd[1], 102*0fcd48feSSimon Glass pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], 103*0fcd48feSSimon Glass pccb->cmd[7], pccb->cmd[8]); 104*0fcd48feSSimon Glass } 105*0fcd48feSSimon Glass 106*0fcd48feSSimon Glass static void scsi_setup_write_ext(ccb *pccb, lbaint_t start, 107*0fcd48feSSimon Glass unsigned short blocks) 108*0fcd48feSSimon Glass { 109*0fcd48feSSimon Glass pccb->cmd[0] = SCSI_WRITE10; 110*0fcd48feSSimon Glass pccb->cmd[1] = pccb->lun << 5; 111*0fcd48feSSimon Glass pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff; 112*0fcd48feSSimon Glass pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff; 113*0fcd48feSSimon Glass pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff; 114*0fcd48feSSimon Glass pccb->cmd[5] = (unsigned char)start & 0xff; 115*0fcd48feSSimon Glass pccb->cmd[6] = 0; 116*0fcd48feSSimon Glass pccb->cmd[7] = ((unsigned char)(blocks >> 8)) & 0xff; 117*0fcd48feSSimon Glass pccb->cmd[8] = (unsigned char)blocks & 0xff; 118*0fcd48feSSimon Glass pccb->cmd[9] = 0; 119*0fcd48feSSimon Glass pccb->cmdlen = 10; 120*0fcd48feSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 121*0fcd48feSSimon Glass debug("%s: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", 122*0fcd48feSSimon Glass __func__, 123*0fcd48feSSimon Glass pccb->cmd[0], pccb->cmd[1], 124*0fcd48feSSimon Glass pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], 125*0fcd48feSSimon Glass pccb->cmd[7], pccb->cmd[8]); 126*0fcd48feSSimon Glass } 127*0fcd48feSSimon Glass 128*0fcd48feSSimon Glass static void scsi_setup_inquiry(ccb *pccb) 129*0fcd48feSSimon Glass { 130*0fcd48feSSimon Glass pccb->cmd[0] = SCSI_INQUIRY; 131*0fcd48feSSimon Glass pccb->cmd[1] = pccb->lun << 5; 132*0fcd48feSSimon Glass pccb->cmd[2] = 0; 133*0fcd48feSSimon Glass pccb->cmd[3] = 0; 134*0fcd48feSSimon Glass if (pccb->datalen > 255) 135*0fcd48feSSimon Glass pccb->cmd[4] = 255; 136*0fcd48feSSimon Glass else 137*0fcd48feSSimon Glass pccb->cmd[4] = (unsigned char)pccb->datalen; 138*0fcd48feSSimon Glass pccb->cmd[5] = 0; 139*0fcd48feSSimon Glass pccb->cmdlen = 6; 140*0fcd48feSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 141*0fcd48feSSimon Glass } 142*0fcd48feSSimon Glass 143*0fcd48feSSimon Glass #ifdef CONFIG_BLK 144*0fcd48feSSimon Glass static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, 145*0fcd48feSSimon Glass void *buffer) 146*0fcd48feSSimon Glass #else 147*0fcd48feSSimon Glass static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr, 148*0fcd48feSSimon Glass lbaint_t blkcnt, void *buffer) 149*0fcd48feSSimon Glass #endif 150*0fcd48feSSimon Glass { 151*0fcd48feSSimon Glass #ifdef CONFIG_BLK 152*0fcd48feSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 153*0fcd48feSSimon Glass #endif 154*0fcd48feSSimon Glass lbaint_t start, blks; 155*0fcd48feSSimon Glass uintptr_t buf_addr; 156*0fcd48feSSimon Glass unsigned short smallblks = 0; 157*0fcd48feSSimon Glass ccb *pccb = (ccb *)&tempccb; 158*0fcd48feSSimon Glass 159*0fcd48feSSimon Glass /* Setup device */ 160*0fcd48feSSimon Glass pccb->target = block_dev->target; 161*0fcd48feSSimon Glass pccb->lun = block_dev->lun; 162*0fcd48feSSimon Glass buf_addr = (unsigned long)buffer; 163*0fcd48feSSimon Glass start = blknr; 164*0fcd48feSSimon Glass blks = blkcnt; 165*0fcd48feSSimon Glass debug("\nscsi_read: dev %d startblk " LBAF 166*0fcd48feSSimon Glass ", blccnt " LBAF " buffer %lx\n", 167*0fcd48feSSimon Glass block_dev->devnum, start, blks, (unsigned long)buffer); 168*0fcd48feSSimon Glass do { 169*0fcd48feSSimon Glass pccb->pdata = (unsigned char *)buf_addr; 170*0fcd48feSSimon Glass #ifdef CONFIG_SYS_64BIT_LBA 171*0fcd48feSSimon Glass if (start > SCSI_LBA48_READ) { 172*0fcd48feSSimon Glass unsigned long blocks; 173*0fcd48feSSimon Glass blocks = min_t(lbaint_t, blks, SCSI_MAX_READ_BLK); 174*0fcd48feSSimon Glass pccb->datalen = block_dev->blksz * blocks; 175*0fcd48feSSimon Glass scsi_setup_read16(pccb, start, blocks); 176*0fcd48feSSimon Glass start += blocks; 177*0fcd48feSSimon Glass blks -= blocks; 178*0fcd48feSSimon Glass } else 179*0fcd48feSSimon Glass #endif 180*0fcd48feSSimon Glass if (blks > SCSI_MAX_READ_BLK) { 181*0fcd48feSSimon Glass pccb->datalen = block_dev->blksz * 182*0fcd48feSSimon Glass SCSI_MAX_READ_BLK; 183*0fcd48feSSimon Glass smallblks = SCSI_MAX_READ_BLK; 184*0fcd48feSSimon Glass scsi_setup_read_ext(pccb, start, smallblks); 185*0fcd48feSSimon Glass start += SCSI_MAX_READ_BLK; 186*0fcd48feSSimon Glass blks -= SCSI_MAX_READ_BLK; 187*0fcd48feSSimon Glass } else { 188*0fcd48feSSimon Glass pccb->datalen = block_dev->blksz * blks; 189*0fcd48feSSimon Glass smallblks = (unsigned short)blks; 190*0fcd48feSSimon Glass scsi_setup_read_ext(pccb, start, smallblks); 191*0fcd48feSSimon Glass start += blks; 192*0fcd48feSSimon Glass blks = 0; 193*0fcd48feSSimon Glass } 194*0fcd48feSSimon Glass debug("scsi_read_ext: startblk " LBAF 195*0fcd48feSSimon Glass ", blccnt %x buffer %" PRIXPTR "\n", 196*0fcd48feSSimon Glass start, smallblks, buf_addr); 197*0fcd48feSSimon Glass if (scsi_exec(pccb) != true) { 198*0fcd48feSSimon Glass scsi_print_error(pccb); 199*0fcd48feSSimon Glass blkcnt -= blks; 200*0fcd48feSSimon Glass break; 201*0fcd48feSSimon Glass } 202*0fcd48feSSimon Glass buf_addr += pccb->datalen; 203*0fcd48feSSimon Glass } while (blks != 0); 204*0fcd48feSSimon Glass debug("scsi_read_ext: end startblk " LBAF 205*0fcd48feSSimon Glass ", blccnt %x buffer %" PRIXPTR "\n", start, smallblks, buf_addr); 206*0fcd48feSSimon Glass return blkcnt; 207*0fcd48feSSimon Glass } 208*0fcd48feSSimon Glass 209*0fcd48feSSimon Glass /******************************************************************************* 210*0fcd48feSSimon Glass * scsi_write 211*0fcd48feSSimon Glass */ 212*0fcd48feSSimon Glass 213*0fcd48feSSimon Glass /* Almost the maximum amount of the scsi_ext command.. */ 214*0fcd48feSSimon Glass #define SCSI_MAX_WRITE_BLK 0xFFFF 215*0fcd48feSSimon Glass 216*0fcd48feSSimon Glass #ifdef CONFIG_BLK 217*0fcd48feSSimon Glass static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, 218*0fcd48feSSimon Glass const void *buffer) 219*0fcd48feSSimon Glass #else 220*0fcd48feSSimon Glass static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr, 221*0fcd48feSSimon Glass lbaint_t blkcnt, const void *buffer) 222*0fcd48feSSimon Glass #endif 223*0fcd48feSSimon Glass { 224*0fcd48feSSimon Glass #ifdef CONFIG_BLK 225*0fcd48feSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 226*0fcd48feSSimon Glass #endif 227*0fcd48feSSimon Glass lbaint_t start, blks; 228*0fcd48feSSimon Glass uintptr_t buf_addr; 229*0fcd48feSSimon Glass unsigned short smallblks; 230*0fcd48feSSimon Glass ccb *pccb = (ccb *)&tempccb; 231*0fcd48feSSimon Glass 232*0fcd48feSSimon Glass /* Setup device */ 233*0fcd48feSSimon Glass pccb->target = block_dev->target; 234*0fcd48feSSimon Glass pccb->lun = block_dev->lun; 235*0fcd48feSSimon Glass buf_addr = (unsigned long)buffer; 236*0fcd48feSSimon Glass start = blknr; 237*0fcd48feSSimon Glass blks = blkcnt; 238*0fcd48feSSimon Glass debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n", 239*0fcd48feSSimon Glass __func__, block_dev->devnum, start, blks, (unsigned long)buffer); 240*0fcd48feSSimon Glass do { 241*0fcd48feSSimon Glass pccb->pdata = (unsigned char *)buf_addr; 242*0fcd48feSSimon Glass if (blks > SCSI_MAX_WRITE_BLK) { 243*0fcd48feSSimon Glass pccb->datalen = (block_dev->blksz * 244*0fcd48feSSimon Glass SCSI_MAX_WRITE_BLK); 245*0fcd48feSSimon Glass smallblks = SCSI_MAX_WRITE_BLK; 246*0fcd48feSSimon Glass scsi_setup_write_ext(pccb, start, smallblks); 247*0fcd48feSSimon Glass start += SCSI_MAX_WRITE_BLK; 248*0fcd48feSSimon Glass blks -= SCSI_MAX_WRITE_BLK; 249*0fcd48feSSimon Glass } else { 250*0fcd48feSSimon Glass pccb->datalen = block_dev->blksz * blks; 251*0fcd48feSSimon Glass smallblks = (unsigned short)blks; 252*0fcd48feSSimon Glass scsi_setup_write_ext(pccb, start, smallblks); 253*0fcd48feSSimon Glass start += blks; 254*0fcd48feSSimon Glass blks = 0; 255*0fcd48feSSimon Glass } 256*0fcd48feSSimon Glass debug("%s: startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", 257*0fcd48feSSimon Glass __func__, start, smallblks, buf_addr); 258*0fcd48feSSimon Glass if (scsi_exec(pccb) != true) { 259*0fcd48feSSimon Glass scsi_print_error(pccb); 260*0fcd48feSSimon Glass blkcnt -= blks; 261*0fcd48feSSimon Glass break; 262*0fcd48feSSimon Glass } 263*0fcd48feSSimon Glass buf_addr += pccb->datalen; 264*0fcd48feSSimon Glass } while (blks != 0); 265*0fcd48feSSimon Glass debug("%s: end startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", 266*0fcd48feSSimon Glass __func__, start, smallblks, buf_addr); 267*0fcd48feSSimon Glass return blkcnt; 268*0fcd48feSSimon Glass } 269*0fcd48feSSimon Glass 270*0fcd48feSSimon Glass #if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) 271*0fcd48feSSimon Glass void scsi_init(void) 272*0fcd48feSSimon Glass { 273*0fcd48feSSimon Glass int busdevfunc = -1; 274*0fcd48feSSimon Glass int i; 275*0fcd48feSSimon Glass /* 276*0fcd48feSSimon Glass * Find a device from the list, this driver will support a single 277*0fcd48feSSimon Glass * controller. 278*0fcd48feSSimon Glass */ 279*0fcd48feSSimon Glass for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) { 280*0fcd48feSSimon Glass /* get PCI Device ID */ 281*0fcd48feSSimon Glass #ifdef CONFIG_DM_PCI 282*0fcd48feSSimon Glass struct udevice *dev; 283*0fcd48feSSimon Glass int ret; 284*0fcd48feSSimon Glass 285*0fcd48feSSimon Glass ret = dm_pci_find_device(scsi_device_list[i].vendor, 286*0fcd48feSSimon Glass scsi_device_list[i].device, 0, &dev); 287*0fcd48feSSimon Glass if (!ret) { 288*0fcd48feSSimon Glass busdevfunc = dm_pci_get_bdf(dev); 289*0fcd48feSSimon Glass break; 290*0fcd48feSSimon Glass } 291*0fcd48feSSimon Glass #else 292*0fcd48feSSimon Glass busdevfunc = pci_find_device(scsi_device_list[i].vendor, 293*0fcd48feSSimon Glass scsi_device_list[i].device, 294*0fcd48feSSimon Glass 0); 295*0fcd48feSSimon Glass #endif 296*0fcd48feSSimon Glass if (busdevfunc != -1) 297*0fcd48feSSimon Glass break; 298*0fcd48feSSimon Glass } 299*0fcd48feSSimon Glass 300*0fcd48feSSimon Glass if (busdevfunc == -1) { 301*0fcd48feSSimon Glass printf("Error: SCSI Controller(s) "); 302*0fcd48feSSimon Glass for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) { 303*0fcd48feSSimon Glass printf("%04X:%04X ", 304*0fcd48feSSimon Glass scsi_device_list[i].vendor, 305*0fcd48feSSimon Glass scsi_device_list[i].device); 306*0fcd48feSSimon Glass } 307*0fcd48feSSimon Glass printf("not found\n"); 308*0fcd48feSSimon Glass return; 309*0fcd48feSSimon Glass } 310*0fcd48feSSimon Glass #ifdef DEBUG 311*0fcd48feSSimon Glass else { 312*0fcd48feSSimon Glass printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n", 313*0fcd48feSSimon Glass scsi_device_list[i].vendor, 314*0fcd48feSSimon Glass scsi_device_list[i].device, 315*0fcd48feSSimon Glass (busdevfunc >> 16) & 0xFF, 316*0fcd48feSSimon Glass (busdevfunc >> 11) & 0x1F, 317*0fcd48feSSimon Glass (busdevfunc >> 8) & 0x7); 318*0fcd48feSSimon Glass } 319*0fcd48feSSimon Glass #endif 320*0fcd48feSSimon Glass bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci"); 321*0fcd48feSSimon Glass scsi_low_level_init(busdevfunc); 322*0fcd48feSSimon Glass scsi_scan(1); 323*0fcd48feSSimon Glass bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI); 324*0fcd48feSSimon Glass } 325*0fcd48feSSimon Glass #endif 326*0fcd48feSSimon Glass 327*0fcd48feSSimon Glass /* copy src to dest, skipping leading and trailing blanks 328*0fcd48feSSimon Glass * and null terminate the string 329*0fcd48feSSimon Glass */ 330*0fcd48feSSimon Glass static void scsi_ident_cpy(unsigned char *dest, unsigned char *src, 331*0fcd48feSSimon Glass unsigned int len) 332*0fcd48feSSimon Glass { 333*0fcd48feSSimon Glass int start, end; 334*0fcd48feSSimon Glass 335*0fcd48feSSimon Glass start = 0; 336*0fcd48feSSimon Glass while (start < len) { 337*0fcd48feSSimon Glass if (src[start] != ' ') 338*0fcd48feSSimon Glass break; 339*0fcd48feSSimon Glass start++; 340*0fcd48feSSimon Glass } 341*0fcd48feSSimon Glass end = len-1; 342*0fcd48feSSimon Glass while (end > start) { 343*0fcd48feSSimon Glass if (src[end] != ' ') 344*0fcd48feSSimon Glass break; 345*0fcd48feSSimon Glass end--; 346*0fcd48feSSimon Glass } 347*0fcd48feSSimon Glass for (; start <= end; start++) 348*0fcd48feSSimon Glass *dest ++= src[start]; 349*0fcd48feSSimon Glass *dest = '\0'; 350*0fcd48feSSimon Glass } 351*0fcd48feSSimon Glass 352*0fcd48feSSimon Glass static int scsi_read_capacity(ccb *pccb, lbaint_t *capacity, 353*0fcd48feSSimon Glass unsigned long *blksz) 354*0fcd48feSSimon Glass { 355*0fcd48feSSimon Glass *capacity = 0; 356*0fcd48feSSimon Glass 357*0fcd48feSSimon Glass memset(pccb->cmd, '\0', sizeof(pccb->cmd)); 358*0fcd48feSSimon Glass pccb->cmd[0] = SCSI_RD_CAPAC10; 359*0fcd48feSSimon Glass pccb->cmd[1] = pccb->lun << 5; 360*0fcd48feSSimon Glass pccb->cmdlen = 10; 361*0fcd48feSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 362*0fcd48feSSimon Glass 363*0fcd48feSSimon Glass pccb->datalen = 8; 364*0fcd48feSSimon Glass if (scsi_exec(pccb) != true) 365*0fcd48feSSimon Glass return 1; 366*0fcd48feSSimon Glass 367*0fcd48feSSimon Glass *capacity = ((lbaint_t)pccb->pdata[0] << 24) | 368*0fcd48feSSimon Glass ((lbaint_t)pccb->pdata[1] << 16) | 369*0fcd48feSSimon Glass ((lbaint_t)pccb->pdata[2] << 8) | 370*0fcd48feSSimon Glass ((lbaint_t)pccb->pdata[3]); 371*0fcd48feSSimon Glass 372*0fcd48feSSimon Glass if (*capacity != 0xffffffff) { 373*0fcd48feSSimon Glass /* Read capacity (10) was sufficient for this drive. */ 374*0fcd48feSSimon Glass *blksz = ((unsigned long)pccb->pdata[4] << 24) | 375*0fcd48feSSimon Glass ((unsigned long)pccb->pdata[5] << 16) | 376*0fcd48feSSimon Glass ((unsigned long)pccb->pdata[6] << 8) | 377*0fcd48feSSimon Glass ((unsigned long)pccb->pdata[7]); 378*0fcd48feSSimon Glass return 0; 379*0fcd48feSSimon Glass } 380*0fcd48feSSimon Glass 381*0fcd48feSSimon Glass /* Read capacity (10) was insufficient. Use read capacity (16). */ 382*0fcd48feSSimon Glass memset(pccb->cmd, '\0', sizeof(pccb->cmd)); 383*0fcd48feSSimon Glass pccb->cmd[0] = SCSI_RD_CAPAC16; 384*0fcd48feSSimon Glass pccb->cmd[1] = 0x10; 385*0fcd48feSSimon Glass pccb->cmdlen = 16; 386*0fcd48feSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 387*0fcd48feSSimon Glass 388*0fcd48feSSimon Glass pccb->datalen = 16; 389*0fcd48feSSimon Glass if (scsi_exec(pccb) != true) 390*0fcd48feSSimon Glass return 1; 391*0fcd48feSSimon Glass 392*0fcd48feSSimon Glass *capacity = ((uint64_t)pccb->pdata[0] << 56) | 393*0fcd48feSSimon Glass ((uint64_t)pccb->pdata[1] << 48) | 394*0fcd48feSSimon Glass ((uint64_t)pccb->pdata[2] << 40) | 395*0fcd48feSSimon Glass ((uint64_t)pccb->pdata[3] << 32) | 396*0fcd48feSSimon Glass ((uint64_t)pccb->pdata[4] << 24) | 397*0fcd48feSSimon Glass ((uint64_t)pccb->pdata[5] << 16) | 398*0fcd48feSSimon Glass ((uint64_t)pccb->pdata[6] << 8) | 399*0fcd48feSSimon Glass ((uint64_t)pccb->pdata[7]); 400*0fcd48feSSimon Glass 401*0fcd48feSSimon Glass *blksz = ((uint64_t)pccb->pdata[8] << 56) | 402*0fcd48feSSimon Glass ((uint64_t)pccb->pdata[9] << 48) | 403*0fcd48feSSimon Glass ((uint64_t)pccb->pdata[10] << 40) | 404*0fcd48feSSimon Glass ((uint64_t)pccb->pdata[11] << 32) | 405*0fcd48feSSimon Glass ((uint64_t)pccb->pdata[12] << 24) | 406*0fcd48feSSimon Glass ((uint64_t)pccb->pdata[13] << 16) | 407*0fcd48feSSimon Glass ((uint64_t)pccb->pdata[14] << 8) | 408*0fcd48feSSimon Glass ((uint64_t)pccb->pdata[15]); 409*0fcd48feSSimon Glass 410*0fcd48feSSimon Glass return 0; 411*0fcd48feSSimon Glass } 412*0fcd48feSSimon Glass 413*0fcd48feSSimon Glass 414*0fcd48feSSimon Glass /* 415*0fcd48feSSimon Glass * Some setup (fill-in) routines 416*0fcd48feSSimon Glass */ 417*0fcd48feSSimon Glass static void scsi_setup_test_unit_ready(ccb *pccb) 418*0fcd48feSSimon Glass { 419*0fcd48feSSimon Glass pccb->cmd[0] = SCSI_TST_U_RDY; 420*0fcd48feSSimon Glass pccb->cmd[1] = pccb->lun << 5; 421*0fcd48feSSimon Glass pccb->cmd[2] = 0; 422*0fcd48feSSimon Glass pccb->cmd[3] = 0; 423*0fcd48feSSimon Glass pccb->cmd[4] = 0; 424*0fcd48feSSimon Glass pccb->cmd[5] = 0; 425*0fcd48feSSimon Glass pccb->cmdlen = 6; 426*0fcd48feSSimon Glass pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ 427*0fcd48feSSimon Glass } 428*0fcd48feSSimon Glass 429*0fcd48feSSimon Glass /** 430*0fcd48feSSimon Glass * scsi_init_dev_desc_priv - initialize only SCSI specific blk_desc properties 431*0fcd48feSSimon Glass * 432*0fcd48feSSimon Glass * @dev_desc: Block device description pointer 433*0fcd48feSSimon Glass */ 434*0fcd48feSSimon Glass static void scsi_init_dev_desc_priv(struct blk_desc *dev_desc) 435*0fcd48feSSimon Glass { 436*0fcd48feSSimon Glass dev_desc->target = 0xff; 437*0fcd48feSSimon Glass dev_desc->lun = 0xff; 438*0fcd48feSSimon Glass dev_desc->log2blksz = 439*0fcd48feSSimon Glass LOG2_INVALID(typeof(dev_desc->log2blksz)); 440*0fcd48feSSimon Glass dev_desc->type = DEV_TYPE_UNKNOWN; 441*0fcd48feSSimon Glass dev_desc->vendor[0] = 0; 442*0fcd48feSSimon Glass dev_desc->product[0] = 0; 443*0fcd48feSSimon Glass dev_desc->revision[0] = 0; 444*0fcd48feSSimon Glass dev_desc->removable = false; 445*0fcd48feSSimon Glass #ifndef CONFIG_BLK 446*0fcd48feSSimon Glass dev_desc->block_read = scsi_read; 447*0fcd48feSSimon Glass dev_desc->block_write = scsi_write; 448*0fcd48feSSimon Glass #endif 449*0fcd48feSSimon Glass } 450*0fcd48feSSimon Glass 451*0fcd48feSSimon Glass #if !defined(CONFIG_DM_SCSI) 452*0fcd48feSSimon Glass /** 453*0fcd48feSSimon Glass * scsi_init_dev_desc - initialize all SCSI specific blk_desc properties 454*0fcd48feSSimon Glass * 455*0fcd48feSSimon Glass * @dev_desc: Block device description pointer 456*0fcd48feSSimon Glass * @devnum: Device number 457*0fcd48feSSimon Glass */ 458*0fcd48feSSimon Glass static void scsi_init_dev_desc(struct blk_desc *dev_desc, int devnum) 459*0fcd48feSSimon Glass { 460*0fcd48feSSimon Glass dev_desc->lba = 0; 461*0fcd48feSSimon Glass dev_desc->blksz = 0; 462*0fcd48feSSimon Glass dev_desc->if_type = IF_TYPE_SCSI; 463*0fcd48feSSimon Glass dev_desc->devnum = devnum; 464*0fcd48feSSimon Glass dev_desc->part_type = PART_TYPE_UNKNOWN; 465*0fcd48feSSimon Glass 466*0fcd48feSSimon Glass scsi_init_dev_desc_priv(dev_desc); 467*0fcd48feSSimon Glass } 468*0fcd48feSSimon Glass #endif 469*0fcd48feSSimon Glass 470*0fcd48feSSimon Glass /** 471*0fcd48feSSimon Glass * scsi_detect_dev - Detect scsi device 472*0fcd48feSSimon Glass * 473*0fcd48feSSimon Glass * @target: target id 474*0fcd48feSSimon Glass * @lun: target lun 475*0fcd48feSSimon Glass * @dev_desc: block device description 476*0fcd48feSSimon Glass * 477*0fcd48feSSimon Glass * The scsi_detect_dev detects and fills a dev_desc structure when the device is 478*0fcd48feSSimon Glass * detected. 479*0fcd48feSSimon Glass * 480*0fcd48feSSimon Glass * Return: 0 on success, error value otherwise 481*0fcd48feSSimon Glass */ 482*0fcd48feSSimon Glass static int scsi_detect_dev(int target, int lun, struct blk_desc *dev_desc) 483*0fcd48feSSimon Glass { 484*0fcd48feSSimon Glass unsigned char perq, modi; 485*0fcd48feSSimon Glass lbaint_t capacity; 486*0fcd48feSSimon Glass unsigned long blksz; 487*0fcd48feSSimon Glass ccb *pccb = (ccb *)&tempccb; 488*0fcd48feSSimon Glass 489*0fcd48feSSimon Glass pccb->target = target; 490*0fcd48feSSimon Glass pccb->lun = lun; 491*0fcd48feSSimon Glass pccb->pdata = (unsigned char *)&tempbuff; 492*0fcd48feSSimon Glass pccb->datalen = 512; 493*0fcd48feSSimon Glass scsi_setup_inquiry(pccb); 494*0fcd48feSSimon Glass if (scsi_exec(pccb) != true) { 495*0fcd48feSSimon Glass if (pccb->contr_stat == SCSI_SEL_TIME_OUT) { 496*0fcd48feSSimon Glass /* 497*0fcd48feSSimon Glass * selection timeout => assuming no 498*0fcd48feSSimon Glass * device present 499*0fcd48feSSimon Glass */ 500*0fcd48feSSimon Glass debug("Selection timeout ID %d\n", 501*0fcd48feSSimon Glass pccb->target); 502*0fcd48feSSimon Glass return -ETIMEDOUT; 503*0fcd48feSSimon Glass } 504*0fcd48feSSimon Glass scsi_print_error(pccb); 505*0fcd48feSSimon Glass return -ENODEV; 506*0fcd48feSSimon Glass } 507*0fcd48feSSimon Glass perq = tempbuff[0]; 508*0fcd48feSSimon Glass modi = tempbuff[1]; 509*0fcd48feSSimon Glass if ((perq & 0x1f) == 0x1f) 510*0fcd48feSSimon Glass return -ENODEV; /* skip unknown devices */ 511*0fcd48feSSimon Glass if ((modi & 0x80) == 0x80) /* drive is removable */ 512*0fcd48feSSimon Glass dev_desc->removable = true; 513*0fcd48feSSimon Glass /* get info for this device */ 514*0fcd48feSSimon Glass scsi_ident_cpy((unsigned char *)dev_desc->vendor, 515*0fcd48feSSimon Glass &tempbuff[8], 8); 516*0fcd48feSSimon Glass scsi_ident_cpy((unsigned char *)dev_desc->product, 517*0fcd48feSSimon Glass &tempbuff[16], 16); 518*0fcd48feSSimon Glass scsi_ident_cpy((unsigned char *)dev_desc->revision, 519*0fcd48feSSimon Glass &tempbuff[32], 4); 520*0fcd48feSSimon Glass dev_desc->target = pccb->target; 521*0fcd48feSSimon Glass dev_desc->lun = pccb->lun; 522*0fcd48feSSimon Glass 523*0fcd48feSSimon Glass pccb->datalen = 0; 524*0fcd48feSSimon Glass scsi_setup_test_unit_ready(pccb); 525*0fcd48feSSimon Glass if (scsi_exec(pccb) != true) { 526*0fcd48feSSimon Glass if (dev_desc->removable) { 527*0fcd48feSSimon Glass dev_desc->type = perq; 528*0fcd48feSSimon Glass goto removable; 529*0fcd48feSSimon Glass } 530*0fcd48feSSimon Glass scsi_print_error(pccb); 531*0fcd48feSSimon Glass return -EINVAL; 532*0fcd48feSSimon Glass } 533*0fcd48feSSimon Glass if (scsi_read_capacity(pccb, &capacity, &blksz)) { 534*0fcd48feSSimon Glass scsi_print_error(pccb); 535*0fcd48feSSimon Glass return -EINVAL; 536*0fcd48feSSimon Glass } 537*0fcd48feSSimon Glass dev_desc->lba = capacity; 538*0fcd48feSSimon Glass dev_desc->blksz = blksz; 539*0fcd48feSSimon Glass dev_desc->log2blksz = LOG2(dev_desc->blksz); 540*0fcd48feSSimon Glass dev_desc->type = perq; 541*0fcd48feSSimon Glass removable: 542*0fcd48feSSimon Glass return 0; 543*0fcd48feSSimon Glass } 544*0fcd48feSSimon Glass 545*0fcd48feSSimon Glass /* 546*0fcd48feSSimon Glass * (re)-scan the scsi bus and reports scsi device info 547*0fcd48feSSimon Glass * to the user if mode = 1 548*0fcd48feSSimon Glass */ 549*0fcd48feSSimon Glass #if defined(CONFIG_DM_SCSI) 550*0fcd48feSSimon Glass static int do_scsi_scan_one(struct udevice *dev, int id, int lun, int mode) 551*0fcd48feSSimon Glass { 552*0fcd48feSSimon Glass int ret; 553*0fcd48feSSimon Glass struct udevice *bdev; 554*0fcd48feSSimon Glass struct blk_desc bd; 555*0fcd48feSSimon Glass struct blk_desc *bdesc; 556*0fcd48feSSimon Glass char str[10]; 557*0fcd48feSSimon Glass 558*0fcd48feSSimon Glass /* 559*0fcd48feSSimon Glass * detect the scsi driver to get information about its geometry (block 560*0fcd48feSSimon Glass * size, number of blocks) and other parameters (ids, type, ...) 561*0fcd48feSSimon Glass */ 562*0fcd48feSSimon Glass scsi_init_dev_desc_priv(&bd); 563*0fcd48feSSimon Glass if (scsi_detect_dev(id, lun, &bd)) 564*0fcd48feSSimon Glass return -ENODEV; 565*0fcd48feSSimon Glass 566*0fcd48feSSimon Glass /* 567*0fcd48feSSimon Glass * Create only one block device and do detection 568*0fcd48feSSimon Glass * to make sure that there won't be a lot of 569*0fcd48feSSimon Glass * block devices created 570*0fcd48feSSimon Glass */ 571*0fcd48feSSimon Glass snprintf(str, sizeof(str), "id%dlun%d", id, lun); 572*0fcd48feSSimon Glass ret = blk_create_devicef(dev, "scsi_blk", str, IF_TYPE_SCSI, -1, 573*0fcd48feSSimon Glass bd.blksz, bd.blksz * bd.lba, &bdev); 574*0fcd48feSSimon Glass if (ret) { 575*0fcd48feSSimon Glass debug("Can't create device\n"); 576*0fcd48feSSimon Glass return ret; 577*0fcd48feSSimon Glass } 578*0fcd48feSSimon Glass 579*0fcd48feSSimon Glass bdesc = dev_get_uclass_platdata(bdev); 580*0fcd48feSSimon Glass bdesc->target = id; 581*0fcd48feSSimon Glass bdesc->lun = lun; 582*0fcd48feSSimon Glass bdesc->removable = bd.removable; 583*0fcd48feSSimon Glass bdesc->type = bd.type; 584*0fcd48feSSimon Glass memcpy(&bdesc->vendor, &bd.vendor, sizeof(bd.vendor)); 585*0fcd48feSSimon Glass memcpy(&bdesc->product, &bd.product, sizeof(bd.product)); 586*0fcd48feSSimon Glass memcpy(&bdesc->revision, &bd.revision, sizeof(bd.revision)); 587*0fcd48feSSimon Glass part_init(bdesc); 588*0fcd48feSSimon Glass 589*0fcd48feSSimon Glass if (mode == 1) { 590*0fcd48feSSimon Glass printf(" Device %d: ", 0); 591*0fcd48feSSimon Glass dev_print(bdesc); 592*0fcd48feSSimon Glass } 593*0fcd48feSSimon Glass return 0; 594*0fcd48feSSimon Glass } 595*0fcd48feSSimon Glass 596*0fcd48feSSimon Glass int scsi_scan(int mode) 597*0fcd48feSSimon Glass { 598*0fcd48feSSimon Glass unsigned char i, lun; 599*0fcd48feSSimon Glass struct uclass *uc; 600*0fcd48feSSimon Glass struct udevice *dev; /* SCSI controller */ 601*0fcd48feSSimon Glass int ret; 602*0fcd48feSSimon Glass 603*0fcd48feSSimon Glass if (mode == 1) 604*0fcd48feSSimon Glass printf("scanning bus for devices...\n"); 605*0fcd48feSSimon Glass 606*0fcd48feSSimon Glass blk_unbind_all(IF_TYPE_SCSI); 607*0fcd48feSSimon Glass 608*0fcd48feSSimon Glass ret = uclass_get(UCLASS_SCSI, &uc); 609*0fcd48feSSimon Glass if (ret) 610*0fcd48feSSimon Glass return ret; 611*0fcd48feSSimon Glass 612*0fcd48feSSimon Glass uclass_foreach_dev(dev, uc) { 613*0fcd48feSSimon Glass struct scsi_platdata *plat; /* scsi controller platdata */ 614*0fcd48feSSimon Glass 615*0fcd48feSSimon Glass /* probe SCSI controller driver */ 616*0fcd48feSSimon Glass ret = device_probe(dev); 617*0fcd48feSSimon Glass if (ret) 618*0fcd48feSSimon Glass return ret; 619*0fcd48feSSimon Glass 620*0fcd48feSSimon Glass /* Get controller platdata */ 621*0fcd48feSSimon Glass plat = dev_get_platdata(dev); 622*0fcd48feSSimon Glass 623*0fcd48feSSimon Glass for (i = 0; i < plat->max_id; i++) 624*0fcd48feSSimon Glass for (lun = 0; lun < plat->max_lun; lun++) 625*0fcd48feSSimon Glass do_scsi_scan_one(dev, i, lun, mode); 626*0fcd48feSSimon Glass } 627*0fcd48feSSimon Glass 628*0fcd48feSSimon Glass return 0; 629*0fcd48feSSimon Glass } 630*0fcd48feSSimon Glass #else 631*0fcd48feSSimon Glass int scsi_scan(int mode) 632*0fcd48feSSimon Glass { 633*0fcd48feSSimon Glass unsigned char i, lun; 634*0fcd48feSSimon Glass int ret; 635*0fcd48feSSimon Glass 636*0fcd48feSSimon Glass if (mode == 1) 637*0fcd48feSSimon Glass printf("scanning bus for devices...\n"); 638*0fcd48feSSimon Glass for (i = 0; i < CONFIG_SYS_SCSI_MAX_DEVICE; i++) 639*0fcd48feSSimon Glass scsi_init_dev_desc(&scsi_dev_desc[i], i); 640*0fcd48feSSimon Glass 641*0fcd48feSSimon Glass scsi_max_devs = 0; 642*0fcd48feSSimon Glass for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { 643*0fcd48feSSimon Glass for (lun = 0; lun < CONFIG_SYS_SCSI_MAX_LUN; lun++) { 644*0fcd48feSSimon Glass ret = scsi_detect_dev(i, lun, 645*0fcd48feSSimon Glass &scsi_dev_desc[scsi_max_devs]); 646*0fcd48feSSimon Glass if (ret) 647*0fcd48feSSimon Glass continue; 648*0fcd48feSSimon Glass part_init(&scsi_dev_desc[scsi_max_devs]); 649*0fcd48feSSimon Glass 650*0fcd48feSSimon Glass if (mode == 1) { 651*0fcd48feSSimon Glass printf(" Device %d: ", 0); 652*0fcd48feSSimon Glass dev_print(&scsi_dev_desc[scsi_max_devs]); 653*0fcd48feSSimon Glass } /* if mode */ 654*0fcd48feSSimon Glass scsi_max_devs++; 655*0fcd48feSSimon Glass } /* next LUN */ 656*0fcd48feSSimon Glass } 657*0fcd48feSSimon Glass if (scsi_max_devs > 0) 658*0fcd48feSSimon Glass scsi_curr_dev = 0; 659*0fcd48feSSimon Glass else 660*0fcd48feSSimon Glass scsi_curr_dev = -1; 661*0fcd48feSSimon Glass 662*0fcd48feSSimon Glass printf("Found %d device(s).\n", scsi_max_devs); 663*0fcd48feSSimon Glass #ifndef CONFIG_SPL_BUILD 664*0fcd48feSSimon Glass setenv_ulong("scsidevs", scsi_max_devs); 665*0fcd48feSSimon Glass #endif 666*0fcd48feSSimon Glass return 0; 667*0fcd48feSSimon Glass } 668*0fcd48feSSimon Glass #endif 669*0fcd48feSSimon Glass 670*0fcd48feSSimon Glass #ifdef CONFIG_BLK 671*0fcd48feSSimon Glass static const struct blk_ops scsi_blk_ops = { 672*0fcd48feSSimon Glass .read = scsi_read, 673*0fcd48feSSimon Glass .write = scsi_write, 674*0fcd48feSSimon Glass }; 675*0fcd48feSSimon Glass 676*0fcd48feSSimon Glass U_BOOT_DRIVER(scsi_blk) = { 677*0fcd48feSSimon Glass .name = "scsi_blk", 678*0fcd48feSSimon Glass .id = UCLASS_BLK, 679*0fcd48feSSimon Glass .ops = &scsi_blk_ops, 680*0fcd48feSSimon Glass }; 681*0fcd48feSSimon Glass #else 682*0fcd48feSSimon Glass U_BOOT_LEGACY_BLK(scsi) = { 683*0fcd48feSSimon Glass .if_typename = "scsi", 684*0fcd48feSSimon Glass .if_type = IF_TYPE_SCSI, 685*0fcd48feSSimon Glass .max_devs = CONFIG_SYS_SCSI_MAX_DEVICE, 686*0fcd48feSSimon Glass .desc = scsi_dev_desc, 687*0fcd48feSSimon Glass }; 688*0fcd48feSSimon Glass #endif 689