scsi_add_host: 把shost_gendev和shost_dev挂靠到各自的bus或class上 。
(2) Target和lun扫描

文章插图
从前面的硬件建模上来看 , 它的扫描过程是
- 先从0开始for循环扫描channel
- 在每个channel循环下面再for循环扫描每个id
- 在每个id下面再for循环扫描所有的lun伪码如下:

文章插图
以scsi_scan_host为例 , 这个函数是以host为单位进行全扫描

文章插图
(3) 各种scan入口
- 以host为单位进行scan:scsi_scan_host
- 以target为单位触发scsi进行scan:scsi_scan_target
- 以lun为单位触发scsi进行scan:scsi_add_device或者__scsi_add_device
- 通过/proc/scsi/scsi:scsi_scan_host_selected
- 通过host对应user空间设备的属性“scan”节点:scsi_scan_host_selected
注册multi q , 需要做两件事情
- 通过blk_mq_alloc_tag_set注册一个blk_mq_tag_set 。注册时我们要提供一堆钩子函数给通用块设备层 , 处理block发下来的request请求 。
- 通过blk_mq_init_queue并以blk_mq_tag_set为参数为每个能独立处理block请求的实体申请一个request_queue 。这样所有的request_queue都和tag_set关联起来了 。
前面讲了host(k)和device(k)中间的双箭头是scsi命令的传输通道 , lun是接收和处理scsi命令的实体 。因此和block层关联的
- 第一步是在创建shost_devgen或者shost_dev的地方做的 。

文章插图
- 第二步是在创建sdev_dev或者sdev_devgen的地方做的 。

文章插图
代码截图:
第1步

文章插图

文章插图

文章插图
第2步

文章插图
至此外界任何发送给lun的请求都会进入到lun相关的request_queue , 例如通过ioctl对sda或者sg设备的命令request都会进入到其对应lun的request_queue 。最终都会走到tag_set的queue_rq钩子函数 , 也就是走到了scsi_queue_rq->scsi_dispatch_cmd->host->hostt->queuecommand函数 , 其中queuecommand是底层驱动注册上来的钩子函数 , scsi子系统把request请求发送到这一步之后 , 剩下的工作就交给底层类似于ufs , sata驱动去处理了 。例如 , ufs会根据请求的类型把上层传下来的信息封装成upiu发给硬件控制器 , 从而完成一次传输 。
5.休眠唤醒休眠唤醒是驱动的一部分 , 包括PM(suspendresume) , runtime PM , 也有shutdown , remove等 。以休眠为例:在”scsi” bus上那些公版driver实现了子设备的休眠唤醒操作 。这个级别的驱动操作的都是lun设备 , 因此这个级别的驱动是基于scsi命令对设备进行操作 。那些更底层的操作例如断开link , 给外设断电等是更底层的父设备们去完成的 。例如
- 硬盘驱动sd.c在休眠的时候 , 给lun发送了scsiSYNCHRONIZE_CACHE命令 , 要求lun把缓存数据回写到硬盘防止断电丢失 , 并发送了start_stop命令要求lun进入低功耗状态 。

文章插图
- 光盘驱动sr.c在连休眠唤醒没有实现 , 只有一个runtime pm操作啥也没做 , 可能它的功耗是由光驱自动控制的 , 不需要软件参与 。

文章插图
Linux设备驱动模型会保证子设备suspend之后 , 才会是父设备的suspend , 向底层一级一级父辈驱动的suspend调用 。
推荐阅读
- linux之间传文件命令之Rsync傻瓜式教程
- 微软提交补丁,用Linux替代Hyper-V根分区的Win
- 借助 HTTP 通过 SSH 绕过 Linux 防火墙
- Linux或者Mac下命令行speedtest测试网络速度
- 硬盘有必要分区吗?MacOS、Linux都不分区
- linux中ELF格式二进制程序
- 利用这个 USB ID 仓库识别更多 Linux 上的设备
- Linux内核虚拟内存管理之匿名映射缺页异常分析
- 在Linux中使用Bashtop与Bpytop监管系统资源
- Linux驱动-互斥锁用法,建议先保存
