作者
QQ群:852283276
微信:arm80x86
微信公众号:青儿创客基地
B站:主页 https://space.bilibili.com/208826118
方法
u-boot下访问sata或者sata ahci有两种方式,一种是pcie上的pcie转sata芯片,比如marvell的88se9230,需要先开启对pcie的支持,一种是cpu内部总线上的,linux上称为platform设备,以xilinx zynqmp为例,u-boot下开启的宏为:
/*u-boot-xlnx-v2018.2\include\configs\xilinx_zynqmp.h*/
#define CONFIG_SYS_SCSI_MAX_SCSI_ID 2
#define CONFIG_SYS_SCSI_MAX_LUN 1
#define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \
CONFIG_SYS_SCSI_MAX_LUN)
/*menuconfig*/
#define CONFIG_SCSI 1
#define CONFIG_AHCI 1
/*scsi 对应scsi系列命令 2015.2.1*/
#ifdef CONFIG_AHCI
#define CONFIG_LIBATA
#define CONFIG_SCSI_AHCI
#define CONFIG_SCSI_AHCI_PLAT
#define CONFIG_SUNXI_AHCI
#define CONFIG_SYS_SCSI_MAX_SCSI_ID 1
#define CONFIG_SYS_SCSI_MAX_LUN 1
#define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \
CONFIG_SYS_SCSI_MAX_LUN)
#define CONFIG_CMD_SCSI
#endif
/*sata 对应sata系列命令 2015.2.1*/
#define CONFIG_CMD_SATA
#ifdef CONFIG_CMD_SATA
#define CONFIG_DWC_AHSATA
#define CONFIG_SYS_SATA_MAX_DEVICE 1
#define CONFIG_DWC_AHSATA_PORT_ID 0
#define CONFIG_DWC_AHSATA_BASE_ADDR SATA_ARB_BASE_ADDR
#define CONFIG_LBA48
#define CONFIG_LIBATA
#endif
如果我们的sata是通过pcie转sata实现,首先我们需要打开pcie相关的宏,u-boot-xlnx-v2015.2.1\common\board_r.c
中会先初始化pcie,initr_pci
,
/*pcie*/
#define CONFIG_PCI
#define CONFIG_DM_PCI
#define CONFIG_PCI_XILINX
#define CONFIG_CMD_PCI
#ifdef CONFIG_PCI
static int initr_pci(void)
{
pci_init();
return 0;
}
#endif
然后调用后调用scsi_init
/*cmd_scsi.c*/
#ifdef CONFIG_PCI
void scsi_init(void)
{
int busdevfunc;
int i;
/*
* Find a device from the list, this driver will support a single
* controller.
*/
for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
/* get PCI Device ID */
busdevfunc = pci_find_device(scsi_device_list[i].vendor,
scsi_device_list[i].device,
0);
if (busdevfunc != -1)
break;
}
if (busdevfunc == -1) {
printf("Error: SCSI Controller(s) ");
for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
printf("%04X:%04X ",
scsi_device_list[i].vendor,
scsi_device_list[i].device);
}
printf("not found\n");
return;
}
#ifdef DEBUG
else {
printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n",
scsi_device_list[i].vendor,
scsi_device_list[i].device,
(busdevfunc >> 16) & 0xFF,
(busdevfunc >> 11) & 0x1F,
(busdevfunc >> 8) & 0x7);
}
#endif
bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci");
scsi_low_level_init(busdevfunc);
scsi_scan(1);
bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI);
}
#endif
这里需要定义你的scsi_device_list
,对应宏CONFIG_SCSI_DEV_LIST
/******************************
* console command
******************************/
#define CONFIG_CMD_EXT4
#define CONFIG_CMD_EXT4_WRITE
#define CONFIG_CMD_SCSI
#define CONFIG_CMD_SATA
#define CONFIG_CMD_USB
/* *****************************
* SATA AHCI driver configure
******************************/
#if defined(CONFIG_CMD_SCSI)
#define CONFIG_SCSI_AHCI
#define CONFIG_AHCI_SETFEATURES_XFER
#define CONFIG_LIBATA
#ifdef CONFIG_SCSI_AHCI
#define CONFIG_SATA_MAX_DEVICE_AHCI 32
#define CONFIG_SYS_SCSI_MAX_SCSI_ID 4
#define CONFIG_SYS_SCSI_MAX_LUN 1
#define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \
CONFIG_SYS_SCSI_MAX_LUN * CONFIG_SATA_MAX_DEVICE_AHCI)
#endif
#define CONFIG_ATAPI
#endif
#define CONFIG_SCSI_DEV_LIST {0x1b21, 0x0612}, \
{0x1cc4, 0x1401}, \
{0x1b4b, 0x9215}, \
{0x1b4b, 0x9235}, \
{0x1b4b, 0x9125}, \
{0x1b4b, 0x9230}, \
{0x21b4, 0x0835}
scsi的底层支持函数在u-boot-xlnx-v2015.2.1\drivers\block\ahci.c
中实现,
void scsi_low_level_init(int busdevfunc)
-->static int ahci_init_one(int pdev)
-->static int ahci_host_init(struct ahci_probe_ent *probe_ent)
-->static void ahci_print_info(struct ahci_probe_ent *probe_ent)
void scsi_scan(int mode)/*cmd_scsi.c*/
-->int scsi_exec(ccb *pccb)
int scsi_exec(ccb *pccb)
{
int ret;
switch (pccb->cmd[0]) {
case SCSI_READ10:
ret = ata_scsiop_read_write(pccb, 0);
break;
case SCSI_WRITE10:
ret = ata_scsiop_read_write(pccb, 1);
break;
case SCSI_RD_CAPAC10:
ret = ata_scsiop_read_capacity10(pccb);
break;
case SCSI_RD_CAPAC16:
ret = ata_scsiop_read_capacity16(pccb);
break;
case SCSI_TST_U_RDY:
ret = ata_scsiop_test_unit_ready(pccb);
break;
case SCSI_INQUIRY:
ret = ata_scsiop_inquiry(pccb);
break;
default:
printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]);
return false;
}
if (ret) {
debug("SCSI command 0x%02x ret errno %d\n", pccb->cmd[0], ret);
return false;
}
return true;
}
scsi系列命令,如果定义了CONFIG_SCSI_AHCI_PLAT
则需要开发者自己实现scsi_init
,或者你就是想用自己的sata ip,那你就实现自己的scsi_init函数
,参考sunxi_ahci_phy_init
,如果你需要初始化Xilinx FPGA的GTX,那就在这个地方,
/*board\xilinx\zynqmp\zynqmp.c*/
#ifdef CONFIG_SCSI_AHCI_PLAT
void scsi_init(void)
{
ahci_init(ZYNQMP_SATA_BASEADDR);
scsi_scan(1);
}
#endif
/*u-boot-xlnx-v2015.2.1\board\sunxi\ahci.c*/
void scsi_init(void)
{
printf("SUNXI SCSI INIT\n");
#ifdef CONFIG_SATAPWR
gpio_request(CONFIG_SATAPWR, "satapwr");
gpio_direction_output(CONFIG_SATAPWR, 1);
/* Give attached sata device time to power-up to avoid link timeouts */
mdelay(500);
#endif
if (sunxi_ahci_phy_init(SUNXI_SATA_BASE) < 0)
return;
ahci_init(SUNXI_SATA_BASE);
}
函数ahci_init
位于u-boot-xlnx-v2015.2.1\drivers\block\ahci.c
,注意其中的CONFIG_SYS_SCSI_MAX_SCSI_ID
,表示支持多少个port,每个port对应一个盘,CONFIG_SYS_SCSI_MAX_LUN
表示每个盘有多少分区,
#ifdef CONFIG_SCSI_AHCI_PLAT
int ahci_init(u32 base)
{
int i, rc = 0;
u32 linkmap;
probe_ent = malloc(sizeof(struct ahci_probe_ent));
if (!probe_ent) {
printf("%s: No memory for probe_ent\n", __func__);
return -ENOMEM;
}
memset(probe_ent, 0, sizeof(struct ahci_probe_ent));
probe_ent->host_flags = ATA_FLAG_SATA
| ATA_FLAG_NO_LEGACY
| ATA_FLAG_MMIO
| ATA_FLAG_PIO_DMA
| ATA_FLAG_NO_ATAPI;
probe_ent->pio_mask = 0x1f;
probe_ent->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */
probe_ent->mmio_base = base;
/* initialize adapter */
rc = ahci_host_init(probe_ent);
if (rc)
goto err_out;
ahci_print_info(probe_ent);
linkmap = probe_ent->link_port_map;
for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) {
if (((linkmap >> i) & 0x01)) {
if (ahci_port_start((u8) i)) {
printf("Can not start port %d\n", i);
continue;
}
#ifdef CONFIG_AHCI_SETFEATURES_XFER
ahci_set_feature((u8) i);
#endif
}
}
err_out:
return rc;
}
如果走sata系列命令,比如i.mx上使用的dwc的sata ahci ip,驱动实现在了u-boot-xlnx-v2015.2.1\drivers\block\dwc_ahsata.c
驱动初始化入口init_sata
在sata命令中调用,
#define CONFIG_CMD_SATA
#ifdef CONFIG_CMD_SATA
#define CONFIG_DWC_AHSATA
#define CONFIG_SYS_SATA_MAX_DEVICE 1
#define CONFIG_DWC_AHSATA_PORT_ID 0
#define CONFIG_DWC_AHSATA_BASE_ADDR SATA_BASE_ADDR
#define CONFIG_LBA48
#define CONFIG_LIBATA
#endif
int __sata_initialize(void)
{
int rc;
int i;
for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) {
memset(&sata_dev_desc[i], 0, sizeof(struct block_dev_desc));
sata_dev_desc[i].if_type = IF_TYPE_SATA;
sata_dev_desc[i].dev = i;
sata_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
sata_dev_desc[i].type = DEV_TYPE_HARDDISK;
sata_dev_desc[i].lba = 0;
sata_dev_desc[i].blksz = 512;
sata_dev_desc[i].log2blksz = LOG2(sata_dev_desc[i].blksz);
sata_dev_desc[i].block_read = sata_read;
sata_dev_desc[i].block_write = sata_write;
rc = init_sata(i);
if (!rc) {
rc = scan_sata(i);
if (!rc && (sata_dev_desc[i].lba > 0) &&
(sata_dev_desc[i].blksz > 0))
init_part(&sata_dev_desc[i]);
}
}
sata_curr_device = 0;
return rc;
}
int sata_initialize(void) __attribute__((weak,alias("__sata_initialize")));
验证
这里没有实现scsi_init
函数,因为FPGA配置文件没有加载,初始化就死机了,所以做了一个命令,
zynq-uboot> run fpga_boot && fdk_ahci && scsi scan
SF: Detected N25Q128 with page size 512 Bytes, erase size 128 KiB, total 32 MiB
SF: 15728640 bytes @ 0x100000 Read: OK
design filename = "MWM195_V2_U40_V1;UserID=0XFFFFFFFF;Version=2017.4"
part number = "7z030ffg676"
date = "2019/04/08"
time = "18:52:22"
bytes in bitstream = 5979916
zynq_align_dma_buffer: Align buffer at 10000070 to 10000000(swap 1)
FDK SCSI INIT...after fpga load
Target spinup took 0 ms.
AHCI 0001.0300 32 slots 1 ports 6 Gbps 0x1 impl SATA mode
flags: ncq stag pm led clo only pmp pio slum part apst
scanning bus for devices...
Device 0: (0:0) Vendor: ATA Prod.: MWM198-1TB Rev: V1.0
Type: Hard Disk
Capacity: 915715.3 MB = 894.2 GB (1875385008 x 512)
Found 1 device(s).
zynq-uboot> ext4ls scsi 0 /
<DIR> 4096 .
<DIR> 4096 ..
<DIR> 4096 NET
<DIR> 4096 CAN
<DIR> 4096 RS422
<DIR> 4096 RS485
zynq-uboot> ext4ls scsi 0 /NET
<DIR> 4096 .
<DIR> 4096 ..
<DIR> 4096 20191015
<DIR> 4096 20191016
<DIR> 4096 20191017
zynq-uboot>