u-boot scsi sata源码解析

news/2024/11/8 22:33:08/

作者

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 DEBUGelse {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);}
#endifbootstage_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_SATAPWRgpio_request(CONFIG_SATAPWR, "satapwr");gpio_direction_output(CONFIG_SATAPWR, 1);/* Give attached sata device time to power-up to avoid link timeouts */mdelay(500);
#endifif (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_XFERahci_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
#endifint __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: OKdesign 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.0Type: Hard DiskCapacity: 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> 

http://www.ppmy.cn/news/240457.html

相关文章

linux u盘 慢_用U盘装Linux,运行速度会很慢吗?卡不卡

给你推荐下配置: 主板:华硕 P8Z77-V LX 780元 cpu: i7 3770k 1900元 / i5 3570k 1500元 / i5 3470 1100元 / i3 3220 750元 内存:金士顿 DDR3 1600 4G 两条 220元 显卡:英伟达Nivida GTX 660 (位宽192bit)1500元 / GTX 560TI (位宽256bit) 1000元 / 英伟达GTX 460 (位宽192位) …

Python数据攻略-Pandas的数据创建与基础特性

大家好&#xff0c;我是Mr数据杨&#xff01;今天将进入Python的Pandas数据世界&#xff0c;就像三国演义中的英雄们&#xff0c;用聪明才智塑造自己的命运。 记得三国中&#xff0c;周瑜曾利用兵法巧妙策划火烧赤壁&#xff0c;击败曹军。这就像创建一个Pandas DataFrame&…

笔记本gtx1650最好用驱动_5000元价位,GTX 1650入门游戏独显究竟表现怎么样?

最近“高性能”三个字在笔记本领域很火热,不管是小白还是老鸟,都在讨论。不时出现这样的说法:处理器,甭管什么U系列还是H系列,2020年啦,至少买个六核机型才有牌面儿;显卡,也不管用来玩啥游戏,一定得RTX系列起步,最好上个RTX 2070/80带SUPER,心理上才满足。至于GTX?…

u盘启动linux出现grub,通过U盘为Ubuntu更新GRUB恢复系统引导的教程

工作需要更换主板,但是不想重装电脑. 怎么办呢? 其实并不需要重装电脑,只需要回复boot menu即可。 1. 首先用u盘制作一个ubuntu的live CD(就是U盘制作为装系统的USBHDD+模式),然后通过u盘启动, 选择try ubuntu, 进入live CD系统 2. 然后需要确定你的/boot是否单独分区, 一…

lunix remount u盘_[全网首发] 有惊喜也有失望——iQunix Aomr2 金属U盘 拆解评测

IMG_3999(20191008-010913).jpg (4.4 MB, 下载次数: 10) 2019-10-8 15:29 上传 包装盒正面的 iQunix LOGO 会随着光线的变化呈现出不同的颜色,十分炫酷 IMG_4001.JPG (2.99 MB, 下载次数: 11) 2019-10-8 15:29 上传 包装盒侧面有工作人员用铅笔标注的容量和颜色信息,略显廉价…

U盘安装CentOS7.4

0 前述 个人博客来源: U盘安装CentOS7.4Keylala在线工具程序员导航 1 系统刻盘 刻盘软件使用UltraISO 镜像下载 这里使用阿里云镜像站https://mirrors.aliyun.com/centos/7.4.1708/isos/x86_64/我选择的是CentOS-7-x86_64-DVD-1708.iso 镜像验证 下载后需要对文件进行验证 …

影驰gtx960 2g

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

U_Net语义分割完整版

1、背景 鉴于莫有人看俄的博客.....&#xff0c;俄决定放一个小项目。同时放一个吸引眼球的封面。 cover 2、U_Net完整版 网上发布的U_Net版本多是针对灰度图&#xff0c;彩色的rgb图像包含颜色信息&#xff0c;因此本项目以信息量更大的彩色图作为网络的输入&#xff0c;做一…