Linux Scsi子系统框架介绍

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

这篇文章以抽象硬件模型,引申出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硬件拓扑模型。

 

硬件模型:

上面这张图是一个抽象的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命令通道。

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信息交给了驱动。更详细的信息在后面的数据结构图里面会描述。

  • channel和id对scsi而言没有实质意义,因此linuxscsi子系统创造了一个target的概念,如下图:

  • 上面的图用不同的颜色画出了三个target,target的名字是host编号,channel编号和id编号组合命名,因此上面三个target的名字分别是(k:0:0)(k:0:1) (k:0:...)。以此类推,这张图后面还可以框出更多的target。

    注意channel编号和id编号是底层驱动自行管理的,而host编号(也就是前k)则是linux scsi子系统自行管理(参看static DEFINE_IDA(host_index_ida)(drivers/scsi/host.c))

  • 引入target概念后,每个device内部可以看成被分为被多个target,每个target下面接着多个lun。硬件拓扑图可以画成下面的样子:

其中channel(0)_id(0)到channel(m)_id(n)就是target(k:0:0)到target(k:m:n)。

4. lun

  • 每个target下面挂接着多个lun。

  • lun是能够接收scsi命令的主体。例如可以是一个物理硬盘,一个光驱;对ufs而言是ufs固件虚拟出来的rpmb,boot0,boot1;也有一些lun不是物理实体但是能接收scsi命令,也被看作为lun,例如report luns可以响应scsi report luns command返回设备lun总数等信息。因此软件上每个lun在linux的通用块设备层都有独享的一个request queue。注意下,有时候一个硬盘通过GPT或者MBR分为多个逻辑分区;它们是一个lun里面,共用一个request queue。关于逻辑分区,不在linux scsi子系统中处理,这里不深究。

  • 注意每个lun都从host对应的物理总线通路发送和接收数据。这个也涉及到通用块设备层的配置,后面会讲。

二、Linux scsi

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OPPO内核工匠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值