Linux AHCI驱动分析之块设备层
作者
QQ群:852283276
微信:arm80x86
微信公众号:青儿创客基地
B站:主页 https://space.bilibili.com/208826118
接上一篇博客Linux AHCI驱动分析之设备初始化
参考
ATA Disk在Linux中的驱动架构对比分析
ata驱动框架及scsi请求处理流程
ATA接口寄存器描述
从ATA层向设备发送TRIM命令
使用硬盘ATA命令读取磁盘
scsi底层设备注册——如何一步步注册到block层
Scsi命令队列转换为ata命令过程
scsi设备的请求处理函数(request_fn)
libATA Developer’s Guide
块设备读写流程
块设备读写流程
Linux Block Layer块设备层基于MultiQueue的部分源码分析
为request的每一个bio创建DMA映射
Linux kernel scatterlist API介绍
打开内核调试信息
定义ATA_DEBUG
和ATA_VERBOSE_DEBUG
,
//include\linux\libata.h
/** compile-time options: to be removed as soon as all the drivers are* converted to the new debugging mechanism*/
#undef ATA_DEBUG /* debugging output */
#undef ATA_VERBOSE_DEBUG /* yet more debugging output */
#undef ATA_IRQ_TRAP /* define to ack screaming irqs */
#undef ATA_NDEBUG /* define to disable quick runtime checks *//* note: prints function name for you */
#ifdef ATA_DEBUG
#define DPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ## args)
#ifdef ATA_VERBOSE_DEBUG
#define VPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ## args)
#else
#define VPRINTK(fmt, args...)
#endif /* ATA_VERBOSE_DEBUG */
#else
#define DPRINTK(fmt, args...)
#define VPRINTK(fmt, args...)
#endif /* ATA_DEBUG */
//drivers\ata\libata-core.c
struct ata_port *ata_port_alloc(struct ata_host *host)
{...
#if defined(ATA_VERBOSE_DEBUG)/* turn on all debugging levels */ap->msg_enable = 0x00FF;
#elif defined(ATA_DEBUG)ap->msg_enable = ATA_MSG_DRV | ATA_MSG_INFO | ATA_MSG_CTL | ATA_MSG_WARN | ATA_MSG_ERR;
#elseap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN;
#endif
...
}
驱动模型
驱动模型如下图,通过LibATA驱动作为SCSI Middle Level与ATA Host之间的转换层,从而可以很好的将ATA Host直接融入到SCSI的驱动体系中来,可以直接将ATA设备驱成SCSI Device。
注册块设备
下面进入ata_host_register
函数,
ata_host_register //drivers\ata\libata-core.chost->n_tags = clamp(sht->can_queue, 1, ATA_MAX_QUEUE - 1); //can_queue = AHCI_MAX_CMDS - 1, n_tags=31, tag ATA_MAX_QUEUE - 1 is reserved for internal commandsata_tport_addata_scsi_add_hosts //drivers\ata\libata-scsi.cscsi_host_allocshost->hostt = sht; // struct scsi_host_template *shtshost->can_queue = sht->can_queue; //struct scsi_host_templateshost->sg_tablesize = sht->sg_tablesize; //struct scsi_host_templateshost->use_blk_mq = scsi_use_blk_mq && !shost->hostt->disable_blk_mq; //scsi_use_blk_mq is from Kconfigshost->max_cmd_len = 16;scsi_add_host_with_dma //drivers\scsi\hosts.cscsi_use_blk_mq: scsi_mq_setup_tags //mq tagsetscsi_setup_command_freelistscsi_get_host_cmd_poolscsi_host_alloc_commandscsi_host_set_state(shost, SHOST_RUNNING)scsi_sysfs_add_hostscsi_proc_host_addsata_link_init_spdata_pack_xfermaskasync_schedule(async_port_probe, ap)ata_port_probe__ata_port_probeata_port_wait_ehata_scsi_scan_host //drivers\ata\libata-scsi.c__scsi_add_device //drivers\scsi\scsi_scan.cscsi_alloc_targetscsi_probe_and_add_lunscsi_device_lookup_by_targetscsi_alloc_sdevscsi_mq_alloc_queue/scsi_alloc_queuescsi_change_queue_depthscsi_sysfs_device_initializescsi_probe_lun //探测lunscsi_execute_req: INQUIRYscsi_execute_req_flags //drivers\scsi\scsi_lib.cscsi_executeblk_get_requestblk_rq_set_block_pcblk_rq_map_kernblk_execute_rqscsi_add_lun //drivers\scsi\scsi_scan.cscsi_sysfs_add_sdev //drivers\scsi\scsi_sysfs.cdevice_add //触发上层probe,bsg_register_queue //block\bsg.c scsi_target_reap
块设备队列
队列创建,支持多队列和传统的单队列,Linux内核默认是单队列(3.19,4.14),请求分发函数为scsi_queue_rq/scsi_request_fn
__scsi_init_queue //drivers\scsi\scsi_lib.cblk_queue_max_segmentsblk_queue_max_hw_sectorsblk_queue_bounce_limitblk_queue_segment_boundarydma_set_seg_boundaryblk_queue_max_segment_sizeblk_queue_dma_alignmentscsi_alloc_queue //传统单队列__scsi_alloc_queueblk_init_queue__scsi_init_queueblk_queue_prep_rq(q, scsi_prep_fn); //设置prep_rq函数blk_queue_unprep_rq(q, scsi_unprep_fn);blk_queue_softirq_done(q, scsi_softirq_done);blk_queue_rq_timed_out(q, scsi_times_out);blk_queue_lld_busy(q, scsi_lld_busy);static struct blk_mq_ops scsi_mq_ops = {.map_queue = blk_mq_map_queue,.queue_rq = scsi_queue_rq,.complete = scsi_softirq_done,.timeout = scsi_timeout,.init_request = scsi_init_request,.exit_request = scsi_exit_request,
};scsi_mq_alloc_queue //多队列mqblk_mq_init_queue__scsi_init_queue
以传统单队列为例,
scsi_request_fn //drivers\scsi\scsi_lib.cblk_peek_requestret = q->prep_rq_fn(q, rq); //scsi_prep_fnscsi_prep_state_checkscsi_get_cmd_from_req //构造struct scsi_cmndscsi_setup_cmndscsi_setup_fs_cmnd/scsi_setup_blk_pc_cmndscsi_prep_returnscsi_dev_queue_readyblk_start_requeststruct scsi_cmnd *cmd = req->special;scsi_target_queue_readyscsi_host_queue_readyscsi_init_cmd_errhcmd->scsi_done = scsi_done; //中断函数中会用到scsi_dispatch_cmdscsi_log_sendhost->hostt->queuecommand;scsi_queue_insert
其中host->hostt->queuecommand
来自struct scsi_host_template
,对应ata_scsi_queuecmd
函数,函数ata_sg_setup
中调用dma_map_sg
,对于我们的异构系统,需要修改的就是这个函数,
ata_scsi_queuecmd //drivers\ata\libata-scsi.cata_shost_to_portata_scsi_dump_cdbata_scsi_find_dev__ata_scsi_queuecmdata_get_xlat_func/atapi_xlat //check if SCSI to ATA translation is possibleata_scsi_translate/ata_scsi_simulateata_scsi_translateata_scsi_qc_newqc->scsicmd = cmd;qc->scsidone = cmd->scsi_done;qc->sg = scsi_sglist(cmd);qc->n_elem = scsi_sg_count(cmd);ata_sg_initqc->complete_fn = ata_scsi_qc_complete;ata_get_xlat_func[ata_scsi_rw_xlat/ata_scsi_pass_thru]/atapi_xlat //translatestruct ata_taskfile *tf //构建tfap->ops->qc_defer //ahci_pmp_qc_defer, deferred:推迟; 延缓; 展期 drivers\ata\libahci.cata_std_qc_defer/sata_pmp_qc_defer_cmd_switchata_qc_issueata_sg_setupdma_map_sgap->ops->qc_prep //ahci_qc_prep drivers\ata\libahci.cata_tf_to_fis //tf转fis,协议Command Table的CFISmemcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len) //协议Command Table的ACMDahci_fill_sgahci_fill_cmd_slotap->ops->qc_issue //ahci_qc_issue drivers\ata\libahci.cwritel(1 << qc->tag, port_mmio + PORT_SCR_ACT);writel(fbs, port_mmio + PORT_FBS);writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
scsi驱动
scsi驱动位于drivers\scsi\sd.c
,
init_sd //drivers\scsi\sd.cregister_blkdevblk_register_regionclass_registerscsi_register_driver
其中scsi_register_driver(&sd_template.gendrv)
,上面说的probe函数即sd_probe
static struct scsi_driver sd_template = {.gendrv = {.name = "sd",.owner = THIS_MODULE,.probe = sd_probe,.remove = sd_remove,.shutdown = sd_shutdown,.pm = &sd_pm_ops,},.rescan = sd_rescan,.init_command = sd_init_command,.uninit_command = sd_uninit_command,.done = sd_done,.eh_action = sd_eh_action,
};
sd_probe
函数,磁盘的队列就是用的scsi_device
里的队列,不需要新创建了,
sd_probe //drivers\scsi\sd.calloc_disksd_format_disk_namesd_probe_asyncgd->fops = &sd_fops;gd->queue = sdkp->device->request_queue; //scsi_disk->scsi_device->request_queuesd_revalidate_diskadd_disksd_dif_config_hostsd_revalidate_disk
其中sd_fops
如下,
static const struct block_device_operations sd_fops = {.owner = THIS_MODULE,.open = sd_open,.release = sd_release,.ioctl = sd_ioctl,.getgeo = sd_getgeo,
#ifdef CONFIG_COMPAT.compat_ioctl = sd_compat_ioctl,
#endif.check_events = sd_check_events,.revalidate_disk = sd_revalidate_disk,.unlock_native_capacity = sd_unlock_native_capacity,
};sd_ioctlscsi_verify_blk_ioctlscsi_ioctl/scsi_cmd_blk_ioctl
其中,
scsi_ioctl //block\scsi_ioctl.csg_scsi_ioctl/sdev->host->hostt->ioctl //ata_scsi_ioctlscsi_cmd_blk_ioctlscsi_verify_blk_ioctlscsi_cmd_ioctlsg_ioata_scsi_ioctl //drivers\ata\libata-scsi.cata_sas_scsi_ioctlATA_IOC_GET_IO32ATA_IOC_SET_IO32HDIO_GET_IDENTITY ata_get_identityHDIO_DRIVE_CMD ata_cmd_ioctlHDIO_DRIVE_TASK ata_task_ioctl
中断
以传统单队列为例,
ahci_single_irq_intr //drivers\ata\libahci.cahci_port_intrahci_handle_port_interruptata_qc_complete_multiple //drivers\ata\libata-core.cata_qc_from_tagata_qc_complete__ata_qc_completeata_sg_cleandma_unmap_sgqc->complete_fn //ata_scsi_qc_complete drivers\ata\libata-scsi.cata_gen_passthru_sense/ata_gen_ata_senseata_dump_statusqc->scsidone //scsi_done drivers\scsi\scsi_lib.cata_qc_free
Linux AHCI驱动分析之块设备层相关推荐
- Linux nvme驱动分析之块设备层
作者 QQ群:852283276 微信:arm80x86 微信公众号:青儿创客基地 B站:主页 https://space.bilibili.com/208826118 参考 Product Docu ...
- nvme命令中prp_Linux nvme驱动分析之块设备层
参考 Product Documentation Red Hat Enterprise Linux7 7.2 发行注记 第 14 章 存储 blk_mq 数据缓冲区转换成prp或者sg列表 用户态分配 ...
- Linux文件系统概述:硬盘驱动>通用块设备层>文件系统>虚拟文件系统(VFS)
目录 一.概述 1. 硬盘驱动 2. 通用块设备层 General Block Device Layer 3. 文件系统 4. 虚拟文件系统(VFS) 二.存储介质 闪存(Flash Memory) ...
- Linux AHCI驱动
目录 概念 port link device tag scsi host scsi device sgl Port.Link.Device之间的关系 Port Link host link pmp l ...
- linux串口驱动分析
linux串口驱动分析 硬件资源及描写叙述 s3c2440A 通用异步接收器和发送器(UART)提供了三个独立的异步串行 I/O(SIO)port,每一个port都能够在中断模式或 DMA 模式下操作 ...
- Linux spi驱动分析(四)----SPI设备驱动(W25Q32BV)
一.W25Q32BV芯片简介 W25X是一系列SPI接口Flash芯片的简称,它采用SPI接口和CPU通信,本文使用的W25Q32BV容量为32M,具体特性如下: 1.1.基本特性 该芯片最大支持10 ...
- Linux spi驱动分析----SPI设备驱动(W25Q32BV)
转载地址:http://blog.chinaunix.net/uid-25445243-id-4026974.html 一.W25Q32BV芯片简介 W25X是一系列SPI接口Flash芯片的简称,它 ...
- Linux网卡驱动分析之RTL8139(五)
Linux网卡驱动分析之RTL8139(五) deliver_skb(dev.c) // 该函数就是调用个协议的接收函数处理该skb 包,进入第三层网络层处理 static __inline__ in ...
- linux pinctrl驱动分析
linux pinctrl驱动分析 altas200模块 准备 设备树节点 pinctrl驱动分析 pcs_probe函数 pcs_allocate_pin_table函数 pcs_add_pin函数 ...
- Linux下驱动开发_块设备驱动开发(硬件上采用SD卡+SPI协议)
一.前言 块设备主要为存储设备设计的框架. 在前面章节Linux下驱动开发_块设备驱动开发(内存模拟存储) 里介绍了块设备驱动编写思路,并且利用内存模拟了硬件存储,完成了块设备驱动开发测试.这一篇文章 ...
最新文章
- iOS 标签自动布局
- 人脸识别开源网络笔记
- 卷积神经网络原理及实现
- oracle导入与导出,oracle导入与导出
- 多线程-NSOperation
- 文件包含漏洞不能包含php,ThinkPHP5漏洞分析之文件包含
- go 数据类型和操作符
- Java中的ThreadLocal的使用--学习笔记
- [转载] python 元组tuple - python基础入门(14)
- The content of elements must consist of well-formed character data or markup
- 斜视术后融合训练方法_做斜视手术两年后又复发了怎么办?
- 2010计算机网络考研真题及答案,2010年计算机考研统考真题参考答案
- 抽象类和接口到底是什么“垃圾“——教你分类
- 熊猫分发_熊猫下降列和行
- vue进入页面加载数据缓慢实现loading提示
- hivesql的几种优化的方法
- java生成pdf带图片_(例)Java生成PDF图片 iText
- 对冲基金小镇 鬼城_未来系统,代码寿命和网络鬼城
- Android(15)——ButterKnife
- 重庆华侨城携手T.M.D PCP 发财潮流文化节2.0国庆重磅来袭