大家好,欢迎来到IT知识分享网。
驱动层次关系
0-> sata_xxx.c //sata的平台驱动 1-> drivers/of/xxx.c //设备树相关操作,of_xxx() 1-> sata_xxx.c //不同芯片自己的init、irq handler、ata_port ops接口、scsi_host_template sht接口 1-> drivers/ata/libata_core.c //ata驱动核心,ata_host_xxx() 1-> drivers/ata/libata_scsi.c //scsi适配层 1-> drivers/ata/libata_pmp.c //端口扩展 1-> drivers/ata/libata_eh.c //异常处理
以Freescale(飞思卡尔) 主控芯片自带的SATA控制器为例,sata_fsl.c
初始化流程
0-> sata_fsl_probe (drivers/ata/sata_fsl.c) 1-> of_iomap //从设备树种获取hcr_base、ssr_base、csr_base 1-> irq_of_parse_and_map //从设备树获取中断信息 1-> ata_host_alloc_pinfo (drivers/ata/libata_core.c) //通过ata_host_alloc分配host //host.ops及host.port.ops = sata_fsl_ops 1-> sata_fsl_init_controller //使用fsl自己的寄存器初始化SATA控制器及中断 1-> ata_host_activate //irq_handler: sata_fsl_interrupt, sht: sata_fsl_sht
ATA核心接口 ata_host_alloc_pinfo (drivers/ata/libata-core.c)
0-> ata_host_alloc_pinfo //分配host及初始化port 1-> ata_host_alloc //分配ATA host及port 1-> 初始化每个host.ports
ATA核心接口 ata_host_activate (drivers/ata/libata-core.c)
0-> ata_host_activate //启动ATA host,请求并注册IRQ 1-> ata_host_start //启动ATA host 2-> ap->ops->port_start //sata_fsl_port_start 启动端口,通过fsl内部HCONTROL寄存器复位在线phy 2-> ap->ops->freeze //sata_fsl_freeze 冻结端口,通过fsl内部HCONTROL寄存器关闭中断实现 1-> devm_request_irq //请求并注册中断处理函数 1-> ata_host_register //注册ATA 已启动的host,开启ATA端口,注册host到ATA即SCSI层,并probe注册的设备 2-> ata_tport_add //每个端口 初始化sysfs的ATA端口结构。 2-> ata_scsi_add_hosts //注册SCSI主机适配器实例 sht: sata_fsl_sht 3-> scsi_host_alloc //分配SCSI主机内存并初始化 3-> scsi_add_host_with_dma //添加带有dma设备的SCSI主机 2-> sata_link_init_spd //通过SControl(SCR2)寄存器初始化并限制速率 2-> 打印ATA端口信息 2-> async_port_probe //每个端口 异步probe 3-> ata_port_probe 4-> __ata_port_probe 5-> ata_port_schedule_eh 6-> ata_std_sched_eh //ap->ops->sched_eh 4-> ata_port_wait_eh //等待当前挂起的eh完成 3-> ata_scsi_scan_host
sysfs下的信息
cxh@cxhserver:~$ ls /sys/class/ata_port/ ata1 ata2 ata3 cxh@cxhserver:~$ ls /sys/class/ata_port/ata1 device idle_irq nr_pmp_links port_no power subsystem uevent cxh@cxhserver:~$ ls /sys/class/ata_link/ link1 link2 link3 cxh@cxhserver:~$ ls /sys/class/ata_link/link1 device hw_sata_spd_limit power sata_spd sata_spd_limit subsystem uevent
接口 ops
ata_port_operations
//libata-core.c const struct ata_port_operations ata_base_port_ops = { .prereset = ata_std_prereset, .postreset = ata_std_postreset, .error_handler = ata_std_error_handler, .sched_eh = ata_std_sched_eh, .end_eh = ata_std_end_eh, }; const struct ata_port_operations sata_port_ops = { .inherits = &ata_base_port_ops, .qc_defer = ata_std_qc_defer, .hardreset = sata_std_hardreset, }; //libata-pmp.c const struct ata_port_operations sata_pmp_port_ops = { .inherits = &sata_port_ops, .pmp_prereset = ata_std_prereset, .pmp_hardreset = sata_std_hardreset, .pmp_postreset = ata_std_postreset, .error_handler = sata_pmp_error_handler, }; //sata_fsl.c static struct ata_port_operations sata_fsl_ops = { .inherits = &sata_pmp_port_ops, .qc_defer = ata_std_qc_defer, .qc_prep = sata_fsl_qc_prep, .qc_issue = sata_fsl_qc_issue, .qc_fill_rtf = sata_fsl_qc_fill_rtf, .scr_read = sata_fsl_scr_read, .scr_write = sata_fsl_scr_write, .freeze = sata_fsl_freeze, .thaw = sata_fsl_thaw, .softreset = sata_fsl_softreset, .hardreset = sata_fsl_hardreset, .pmp_softreset = sata_fsl_softreset, .error_handler = sata_fsl_error_handler, .post_internal_cmd = sata_fsl_post_internal_cmd, .port_start = sata_fsl_port_start, .port_stop = sata_fsl_port_stop, .pmp_attach = sata_fsl_pmp_attach, .pmp_detach = sata_fsl_pmp_detach, };
scsi_host_temp
//libata.h #define ATA_BASE_SHT(drv_name) \ .module = THIS_MODULE, \ .name = drv_name, \ .ioctl = ata_scsi_ioctl, \ .queuecommand = ata_scsi_queuecmd, \ .can_queue = ATA_DEF_QUEUE, \ .tag_alloc_policy = BLK_TAG_ALLOC_RR, \ .this_id = ATA_SHT_THIS_ID, \ .emulated = ATA_SHT_EMULATED, \ .use_clustering = ATA_SHT_USE_CLUSTERING, \ .proc_name = drv_name, \ .slave_configure = ata_scsi_slave_config, \ .slave_destroy = ata_scsi_slave_destroy, \ .bios_param = ata_std_bios_param, \ .unlock_native_capacity = ata_scsi_unlock_native_capacity, \ .sdev_attrs = ata_common_sdev_attrs #define ATA_NCQ_SHT(drv_name) \ ATA_BASE_SHT(drv_name), \ .change_queue_depth = ata_scsi_change_queue_depth //sata_fsl.c static struct scsi_host_template ahci_sht = { ATA_NCQ_SHT("sata_fsl"), .can_queue = SATA_FSL_QUEUE_DEPTH, .sg_tablesize = SATA_FSL_MAX_PRD_USABLE, .dma_boundary = ATA_DMA_BOUNDARY, };
核心ATA发送命令
libata内部ata命令即scsi的ata命令流程与AHCI驱动相同。
ata_qc_issue
所有发送ata的命令都会调用到此接口。
//libata-core.c 0-> ata_qc_issue //分发taskfile到device,taskfile存放于qc中 1-> link->sactive |= 1 << qc->hw_tag; //NCQ模式下使用sactive的bit表示待处理的多个命令, 命令完成后清除sactive对应bit。 1-> link->active_tag = qc->tag; //非NCQ模式使用link->active_tag表示待处理的单个命令, 命令完成后active_tag=ATA_TAG_POISON表示空闲。 1-> ata_sg_setup //如果为DMA模式,则设置sgl 2-> dma_map_sg //配置sgl,此函数调用后dma_address才会被赋值,且新的sgl更连续,sg数量更少 2-> ap->ops->qc_prep(qc); //ahci_qc_prep 将qc命令拷贝到正确的位置,准备发送 2-> ap->ops->qc_issue(qc); //ahci_qc_issue 发送qc命令
sata_fsl_qc_prep
sata_fsl_qc_issue
流程与AHCI类似,具体操作不同cpu可能不同
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/149332.html