在第一章我们简单的介绍过SCSI的内容,本节我们将更加详细的介绍一下SCSI的相关内容。即使NVMe协议大行其道的时代,SCSI依然是目前应用最广泛的协议,它被广泛的应用服务器、个人电脑和企业级存储系统当中。
最早的SCSI协议是一套包含硬件协议和软件协议的标准,在美国国家标准文档《American National Standard for Information Systems -Small Computer System Interface》详细的描述了SCSI的硬件规格(如接口的尺寸和引脚数量等)、电器特性和命令格式。如下图是该标准对接口尺寸等相关内容的描述。

SCSI的全称是Small Computer System Interface,也就是小型计算机系统接口,它定义了计算机主机与外围设备的连接方式。这里的外围设备包括硬盘、光盘和磁盘阵列等很多种类型的设备。
需要注意的是,在一个SCSI总线上可以同时连接多个外围设备,如下图是一个示例。SCSI协议采用的是客户端服务端(Client-Server)架构,也就是常说的CS架构。其中提供服务的为服务端,比如硬盘、打印机或者光驱等,在SCSI中称为目标器(Target)。使用服务的为客户端,比如主机,在SCSI中称为启动器(Initiator)。

需要注意的是,上述目标器中可能包含多个子设备,称为逻辑单元(Logical Unit),每个逻辑设备都有一个编号称为逻辑单元号(Logical Unit Number,简称LUN)。
最早的SCSI是并行总线,也就是Parallel SCSI,图中的多个插口的数据线就是并行SCSI的数据线。如下图是第一版SCSI差分信号的数据线定义,可以看到一共有50根线,其中数据线有16根,用于传输8位数据。除了数据线外,还有一些控制信号线,这些信号线用于寻址等操作。

同时可以看出,通过这个50条数据线可以实现主机与多个外围设备的连接。虽然主机可以通过一个SCSI数据线连接多个设备,但是在同一时间只能实现与一个设备之间数据的传输。原因很简单,因为并行SCSI总线是铜线,通过电压信号来传输数据的,多个设备同时传输数据必然导致相互之间的干扰。
基于上述原因,SCSI需要解决两个问题,一个是寻址的问题,也就是在传输数据之前需要找到目的设备;另外一个是建立连接的问题,建立连接后才能实现数据传输,同时也实现了对其它设备的排它操作。
为了能过实现上述目的,SCSI协议将总线划分为8种不同的状态,分别是:总线空置阶段(BUS FREE phase)、仲裁阶段(ARBITRATION phase)、选择阶段(SELECTION phase)、重选阶段(RESELECTION phase)、命令阶段(COMMAND phase)、数据阶段(DATA phase)和状态阶段(STATUS phase)和消息阶段(MESSAGE phase)。可以看出对于SCSI来说,数据传输只是其8种状态中的一种。
SCSI总线的状态总是在这8种状态之间进行切换,从状态名称可以看出,如果想要建立主机与某个设备的连接,必需要经过仲裁和选择的过程。如果想用SCSI进行数据的传输,必需处于数据传输阶段才可以。我们可以通过下面这张状态转换图描述不同状态的切换。本图包含两种场景,一种是没有仲裁阶段的,另外一种是有仲裁阶段的。

上述状态中,总线空置阶段很好理解,就是总线现在是空闲状态,没有任何任务。仲裁阶段则是获取总线使用权的过程,只有获取使用权后才能后续操作(可选)。选择阶段和重新选择阶段则是建立启动器和目标器连接的过程,这个连接是指电气信号的连接。后面命令阶段、数据阶段、状态阶段和消息阶段统称为信息传输阶段,它们有一个共同的特点就是通过数据总线传输数据或者控制信息。那么SCSI是如何实现状态之间的转换的呢?
SCSI就是通过控制信号线来实现状态转移的。首先我们来看一下SCSI主要的控制总线的作用。这里我们并不会介绍每个信号线的功能,只是介绍一下几个主要的信号线的功能。
1)BSY(Busy)信号,表示总线处于繁忙状态,也就是已经有设备占用了总线。
2)SEL(Select)信号,用于启动器选择目标器端,或者目标器重新选择启动器。
3)C/D(Control/Data)信号,控制或数据信号,用于指示数据总线传输的是控制信息还是数据。
4)I/O(Input/Output)信号,用于指示数据总线上数据的移动方向,分别为起动器端向目标器端移动,或者目标器端向启动器端移动。
5)REQ(Request)信号, 用于指示有信息传输请求。
6)ACK(Acknowledge)信号,通常与REQ配对使用,用于表示对REQ的应答。
5)DB, 用于传输数据,有8位和16位两种,如果是8位则为D0-D7,如果是16位则为D0-D15。除了用于数据传输外,DB数据线还有另外一个非常重要的作用就是用于SCSI设备标示自己是否要进行总线操作。
可能有人会问,既然一个主机可以连接多个SCSI设备,那么如何标示每一个SCSI设备呢?在SCSI中是通过SCSI ID来确定设备的。在SCSI域中的每个设备都有一个ID,包含主机。同时SCSI还通过ID的大小表示优先级。另外需要说明的是,一个SCSI域中SCSI设备的数量也就是数据线的数量,如果是8位数据线,那么做多支持8个SCSI设备(含主机),如果是16位数据线,则最多支持16个SCSI设备。
好了,有了前面的准备知识,我们看看SCSI是如何工作的吧。首先系统起来的时候是总线空置阶段,这个不必过多解释。需要知道的是,总线空置阶段控制信号线BSY和SEL都为“假”。
仲裁阶段
仲裁阶段是获取SCSI总线使用权的阶段。需要注意的是,仲裁阶段对于SCSI来说并非必须的,这个我们在前文状态转换图中也看到了。仲裁阶段主要在多启动器场景或者需要重新连接的场景。由于同一时刻只能有一对设备传输数据,对于多启动器场景,由于可能存在两个以上启动器同时访问设备的情况,就需要通过仲裁来确定谁可以使用总线。重新连接的场景我们在介绍重新连接阶段是会详细介绍。
SCSI设备在总线空置阶段等待一个延迟就可以进行仲裁申请了。此时该SCSI设备将BSY信号线和其ID对于的DB线位置设置为“真”。假设这个SCSI设备的ID为5,可以用下图表示此时SCSI总线各个信号线的状态(其中红色的表示“真”)。
由于可能有另外一个设备同时进行仲裁申请,比如ID为7的设备也在进行仲裁申请。此时DB7也会是“真”。
对于ID为5的设备,其申请仲裁后过一个延时后需要检查DB上的所有除DB5外的信号线是否有“真”的情况,此时发现DB7为“真”,由于ID7优先级高,所以本设备不再申请仲裁。当然,如果没有其它设备申请,或者优先级比它低,那么此时本设备就获取了总线的使用权。

选择阶段
获得仲裁胜利后,该设备会把BSY和SEL同时设置为“真”,经过一个延时后进入选择阶段。假设此时该设备想连接ID为0的设备,该设备会将自己ID对应的数据线(DB5)和目标设备对应的数据线(DB0)设置为“真”。过一个延时后将BSY设置为“假”。
SCSI域中的其它设备都会检测数据总线上信号状态,如果发现目的ID与自己匹配,则可以认定自己为目标设备,此时该设备就会将BSY信号重新设置为“真”,并将SEL设置为“假”,此时完成选择的过程。
重新选择阶段
在主机与存储设备(启动器与目标器)交互期间,可能存储系统需要处理某些费时的任务,这个时候如果一直占着总线将影响主机与其它设备通信。因此,对于这种情况通常会先放弃总线,让SCSI总线处于总线空置状态。
当存储系统准备后,需要重新建立与主机的连接,这个过程就是重新选择阶段。重新选择阶段与选择阶段类似,差异在于选择阶段的发起者是启动器,而重新选择阶段的发起者通常是目标器。
信息传输阶段
完成连接建立后,两个SCSI设备就可以通信了,此时也就是所谓的信息传输阶段,具体而言细分为命令阶段、数据阶段、状态阶段和消息阶段。前文我们说过SCSI协议基于CS架构,其中服务端(目标器)是提供服务,比如硬盘是提供存储服务的。因此,启动器与目标器的交互大致是:
启动器(主机):我想从X位置读数据。
目标器(硬盘):好的,我发给你
那么在SCSI中是如何描述“我想从X位置读数据”这个请求或者命令的呢?SCSI的命令称为命令描述块(Command Descriptor Block, 简称CDB),其格式大致如下图所示,其中第一个字节为操作码(Operation Code),后面若干字节为命令相关的参数,最后是一个控制码。

这里的操作码就是SCSI支持的操作,比如读数据、写数据、测试单元是否就绪、查询目标器基本信息和报告LUN列表等等。如下表是SCSI支持的最基本的命令。
命令 | 操作码 | 描述 |
READ | 0x08 | 从设备读取数据 |
WRITE | 0x0A | 向设备写入数据 |
TEST UNIT READY | 0x00 | 向设备查询其是否已经准备好传输数据 |
INQUIRY | 0x12 | 返回设备的基本信息 |
从上图中我们可以看出,SCSI的命令长度是不确定的。您可能有一个疑问,那目标器接收到命令后是怎么知道命令长度的呢?这要从其操作码的格式说起了,CDB的操作码其实分为两部分,如图所示的5到7位存储的称为组码(Group Code),而0到4字节存储的是具体的命令码(Command Code)。

比如组码如果为0则表示相应的CDB长度为6个字节,如果组码为1则表示相应的CBD长度为10字节。以常见的读命令为例,其CDB的格式如下图所示,可以看到其组码为0,表示CDB长度为6个自己,命令码为8,表示读命令。

接下来就是读命令的具体参数,其中逻辑单元号表示目标器中具体的逻辑单元,逻辑块地址(Logical Block Address,简称LBA)则表示打算读取数据在逻辑单元中的偏移地址,传输长度则表示具体想读取多少数据。我们将前文存储设备图放大,下图右侧是放大后的图,其中逻辑单元被抽象为一个线性空间。如下图所示,通过LUN、LBA和长度可以唯一定位一块数据。

当目标器解析到读请求后,总线进入数据传输阶段或者状态阶段。如果目标器可以找到具体的数据,则进入数据传输阶段,数据从目标器传输到启动器。如果目标器内部发生了错误,此时目标器需要通过状态通知启动器具体错误的原因,此时进入状态阶段。
CDB的最后一个字节称为控制(Control)字节,控制字节的格式如下图右侧所示。具体包括厂商特有的信息、保留字段、Flag(旗标)和Link(链接)。链接和旗标是配合使用的,链接用于连续多个命令的场景,设置为1时表示启动器期望当前命令成功后自动链接到下一个命令。旗标只有在链接为1的时候有效,当链接为0时,该值也必须为0。旗标主要用于启动器通知目标器应该发送的消息的类型,如果设置为0,则表示要求目标器发送一个LINKED COMMAND COMPLETE状态消息,否则表示要求目标器发送一个LINKED COMMAND COMPLETE with Flag状态消息。最后说一句,这两个字段其实在工程实践中基本上不用。

本节我们简要介绍了并行SCSI是如何基于铜缆进行工作的,并对SCSI命令(CDB)的格式进行了介绍。这些内容是学习后续块存储协议的基础,希望大家能过本节的学习能过对SCSI协议有一个整体的认识。

计算机数据存储简史,从纸到云的变迁 基于Fuse的最简单的文件系统 代码覆盖率测试,聊聊gcov和lcov SAN存储的概念与基于iSCSI的操作实战 全面了解SSD,SSD关键术语全面解析 分布式虚拟文件系统,数据编排小能手 高性能的基础RAID0,实操与代码实现解析 网络文件系统,年近五十岁,老当益壮 弹性空间之道,逻辑卷管理(LVM)技术 计算机数据存储简史,从纸到云的变迁 基于树莓派和硬盘柜搭建一个几十TB的家用NAS Linux存储软件栈到底有多复杂,存储软件栈全景概览 分布式存储的软件架构与案例解析 数万客户端NFS服务的困境,聊聊自动挂载技术 深入了解一下SSD的相关内容 什么是文件系统,以Linux中的Ext4为例细聊一下 对象存储,从单机到分布式的演进 为什么都说NFS读写性能差,如何进行优化?SPDK块设备抽象层bdev对多种后端模块(驱动)的支持 计算机的存储体系与性能金字塔 Linux是如何将硬盘展示给用户的,从物理设备到通用块层 聊聊ZFS文件系统,一个免费开源的存储引擎 云计算的出现与存储系统形态的改变 分布式数据路由的基石,聊聊一致性哈希算法 如何创建一个比物理空间大的卷 ,聊聊自动精简配置 介绍一款免费开源的企业级存储软件 企业级磁盘阵列软件架构与功能概述 高性能存储的基础,了解一下内存的方方面面 介绍几个学习存储通信协议的利器 从电商系统认识数据与数据的存储





