scsi是一套古老的协议 , 至今它还在一些硬件中存在和使用 , 例如基于sata协议的ssd硬盘 , ufs器件等 。因为scsi命令已经标准化 , 因此scsi子系统也成为了linux kernel众多子系统中的一份子 。

文章插图
这篇文章以抽象硬件模型 , 引申出linux scsi子系统的设计框架 。
一、硬件建模以下描述:
- 硬件层面的总线或者控制器 , 在文档里称之为总线或者控制器;硬件层面的设备在文档里称之为设备 。
- 软件层面的总线 , 在文档里称之为bus , 对应着structbus_type类型;软件层面的设备称之为device , 对应着struce device类型 。
- 硬件各级设备的睡眠和唤醒顺序 , 决定了软件上的设备父子关系 。例如sd , emmc先sleep , sdio才能sleep 。
- 硬件上的连接关系决定了软件上扫描顺序 。例如pcie现有rc虚拟bridge , 再扫描一级总线上的各种外设 , 扫到了bridge才能再递归扫描下一级总线上的外设 。
- 硬件总线上传输的信息的封装方式 , 决定了多级设备的驱动 , 各自处理的范围 。例如ufs驱动负责upiu等等处理 , scsi子系统负责scsi命令的处理 。
硬件模型:

文章插图
上面这张图是一个抽象的scsi子系统的硬件拓扑图 。图上:
- soc芯片内部有host(0),host(1)...host(k)这些有scsi功能的控制器 。
- 这些host分别连接着片外的scsi设备device(0)...device(k)外设 。为了形象点 , host(1)没有接任何scsi外设 。
- 每个device内部有若干个channel , 每个channel下面有若干个id , 每个id下面有若干个lun 。
- 这些lun就是可以接受scsi命令的实体 , 例如可以是硬盘 , cdrom , 磁带等等 , 也可以是一些可以接收特殊scsi命令的wlun 。
1. Host(0-k)
- 表示可以发送和接收scsi命令的控制器 。图示中的host(0) , host(1)是一个示意图 , 框图以描述host(k)为主
- 一个控制器对应一个外设;也可以不接任何外设 。
因此这里的host(0),host(1)...host(k)是一个控制器抽象描述 , 真实的控制器可以是ufs、usb上接着的硬盘控制器(这个应该画在soc外面)或者pcie上挂着的硬盘控制器(这个也应该画在soc外面) 。
2. device(0-k)图示中 , 例子device(0)是连接到host(0)控制器上的外设;device(k)是连接到host(k)控制器上的外设 。外设可以是硬盘 , 光驱 , ufs等 。
注意:
Host和device之间的连接方式用了一个双箭头表示 , 它是一个抽象描述 , 代表scsi命令通道 。

文章插图
Scsi只是一个协议 , 因此各种五花八门的控制器都可以使用scsi进行交互 。因此这个“通道”是借助各种控制器的驱动来完成的 。有点像协议分层 , scsi类似于协议层 , 而物理层 , 链路层则交给了各种控制器去完成 。
在软件上 , linux scsi子系统发送和接收的任何scsi命令都是由底层物理设备对应的驱动程序完成的 , 例如可以通过usb某个子设备驱动或者通过ufs驱动去实现scsi命令传输
3. channel+id
- 关于channel和id , 我目前没有在scsi协议里面找到任何关于它们的描述 。
- 这里个人理解的channel和id更多的是要给底层各种驱动程序一个灵活性 。软件上channel和id给device内部构造了一个树形图 , 而众多的lun是这个树上的叶子节点 。关于channel和id的处理 , scsi是交给底层驱动去处理的 , scsi仅仅只是用这些来给lun的struce device做命名 , 并在发送scsi命令时把lun所属的channel和id信息交给了驱动 。更详细的信息在后面的数据结构图里面会描述 。
推荐阅读
- linux之间传文件命令之Rsync傻瓜式教程
- 微软提交补丁,用Linux替代Hyper-V根分区的Win
- 借助 HTTP 通过 SSH 绕过 Linux 防火墙
- Linux或者Mac下命令行speedtest测试网络速度
- 硬盘有必要分区吗?MacOS、Linux都不分区
- linux中ELF格式二进制程序
- 利用这个 USB ID 仓库识别更多 Linux 上的设备
- Linux内核虚拟内存管理之匿名映射缺页异常分析
- 在Linux中使用Bashtop与Bpytop监管系统资源
- Linux驱动-互斥锁用法,建议先保存
