Linux Scsi子系统框架介绍

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

Linux Scsi子系统框架介绍

文章插图
 
这篇文章以抽象硬件模型 , 引申出linux scsi子系统的设计框架 。
一、硬件建模以下描述:
  • 硬件层面的总线或者控制器 , 在文档里称之为总线或者控制器;硬件层面的设备在文档里称之为设备 。
  • 软件层面的总线 , 在文档里称之为bus , 对应着structbus_type类型;软件层面的设备称之为device , 对应着struce device类型 。
linux内部的任何大的驱动子系统(例如mmc , scsi , pcie , usb等等)都是以硬件对象为基础设计的 , 包括
  • 硬件各级设备的睡眠和唤醒顺序 , 决定了软件上的设备父子关系 。例如sd , emmc先sleep , sdio才能sleep 。
  • 硬件上的连接关系决定了软件上扫描顺序 。例如pcie现有rc虚拟bridge , 再扫描一级总线上的各种外设 , 扫到了bridge才能再递归扫描下一级总线上的外设 。
  • 硬件总线上传输的信息的封装方式 , 决定了多级设备的驱动 , 各自处理的范围 。例如ufs驱动负责upiu等等处理 , scsi子系统负责scsi命令的处理 。
因此了解linux scsi子系统前 , 需要先了解scsi硬件拓扑模型
硬件模型:
Linux 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)为主
  • 一个控制器对应一个外设;也可以不接任何外设 。
注意:需要说明的是 , 现实硬件里看不到任何纯scsi控制器;例如ufs的scsi命令是ufs控制器通过upiu传送和接收的 , upiu是在mipi总线上传送的物理信息 , 而scsi则是cmd upiu中的字段 。再例如usb U盘 , 也是类似情况 。
因此这里的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命令通道 。
Linux Scsi子系统框架介绍

文章插图
 
Scsi只是一个协议 , 因此各种五花八门的控制器都可以使用scsi进行交互 。因此这个“通道”是借助各种控制器的驱动来完成的 。有点像协议分层 , scsi类似于协议层 , 而物理层 , 链路层则交给了各种控制器去完成 。
在软件上 , linux scsi子系统发送和接收的任何scsi命令都是由底层物理设备对应的驱动程序完成的 , 例如可以通过usb某个子设备驱动或者通过ufs驱动去实现scsi命令传输
3. channel+id