1.SCSI协议
SCSI的起源
- SCSI出现的原因主要是因为原来的IDE接口的硬盘转速太慢,传输速率太低,因此高速的SCSI硬盘出现。
- 其实SCSI并不是专为硬盘设计的,实际上它是一种总线型接口。由于独立于系统总线工作,所以它的最大优势在于其系统占用率极低。
SCSI的定义
- SCSI-2模制线缆,HPDB50公头/DB50公头
英文全称是Small Computer System Interface,小型计算机系统接口。一种用于计算机和智能设备之间系统级接口的独立处理器标准(智能设备包括硬盘、软驱、光驱、打印机、扫描仪等)。同样也是通用接口标准,I/O技术,并且以块的方式进行数据传输。 - SCSI-3线缆,HPDB68公头/公头,带磁环
SCSI技术从推出至今,经过了SCSI-1、SCSI-2、SCSI-3、Ultra2 SCSI、Ultra3 SCSI、Ultra160 SCSI和Ultra320 SCSI等多个版本,其接口带宽从最初的4MB/S一直发展到目前最快的320MB/S。目前SCSI存储设备普遍采用Ultra160 SCSI和Ultra320 SCSI协议。 SCSI-3是所有存储协议的基础,其它存储协议都用到SCSI的指令集。
它的优缺点也很明显。
-
优点:与主机无关、多设备并行、高带宽。 -
缺点:允许连接设备数量少、连接距离非常有限。 -
SCSI协议定义了一套不同设备(磁盘,磁带,处理器,光设备,网络设备等)利用该框架进行信息交互的模型和必要指令集。 -
SCSI协议本质上同传输介质无关,SCSI可以在多种介质上实现,甚至是虚拟介质。例如基于光纤的FCP链路协议,基于SAS的链路协议,基于虚拟IP链路的ISCSI协议。 -
通俗点说SCSI协议就是一个存储设备与服务器之间接口传递的一个规范。
SCSI的逻辑拓扑
-
逻辑单元(LUN): LUN是SCSI目标器中所描述的名字空间资源,一个目标器可以包括多个LUN,而且每个LUN的属性可以有所区别,比如LUN#0可以是磁盘,LUN#1可以是其他设备。 -
启动器(Initiator): 本质上,SCSI是一个C/S架构,其中客户端成为启动器,负责向SCSI目标器发送请求指令,一般主机系统都充当了启动器的角色。 -
目标器(Target): 处理SCSI指令的服务端称为目标器,它接收来自主机的指令并解析处理,比如磁盘阵列的角色就是目标器。 SCSI的Initiator与Target共同构成了一个典型的C/S模型,每个指令都是“请求/应答”这样的模型来实现。 -
Initiator主要任务:发出SCSI请求。 Target主要任务:回答SCSI请求,通过LUN提供业务,并通过任务管理器提供任务管理功能
SCSI启动器模型
- 主机的SCSI系统一般工作在“启动器”模式下面,从SCSI的体系结构来说,分为了“架构层(中间层)”,“设备层”,“传输层”,故此一般的操作系统,都将SCSI分为三个层次
- Linux下的启动器架构:Linux将SCSI启动器分为三个逻辑层次,其中scsi_mod中间层复杂处理SCSI设备无关和适配器无关的流程处理,比如一些异常,名字空间维护等。
HBA驱动提供SCSI指令的打包解包传输等链路实现细节,设备驱动实现特定的SCSI设备驱动,比如著名的sd(SCSI磁盘)驱动,st(SCSI磁带)驱动,sr(SCSI光盘设备)驱动等。
SCSI目标层器模型 Target一般依据SCSI体系结构,分为三个层次,分别是链路端口层(Port Layer),中间层( Middle Layer),目标设备层(Device Layer)。
其中最重要的是中间层,在中间层中将以SAM/SPC为规范,对LUN命名空间,链路端口,目标设备,任务,任务集,会话等进行管理维护。
端口层的驱动都以注册的形式动态载入,设备层的驱动也是动态载入。
- 目标器中PORT模型:
PORT驱动将动态载入,PORT主要完成的任务是对链路上携带的SCSI指令的解包和封包,比如将指令打包为FPC或者ISCSI或者SAS等,或者将指令从FCP/ISCSI/SAS中解开。iSCSI/FCP/SAS等硬件的目标器模式驱动都属于PORT范畴,PORT需要提供的方法函数可能包括,传输报文(xmit_response),准备好接受数据(xfer_data),管理指令处理完毕回调(mgmt_task_done),任务处理结束(cmd_done),端口控制(复位等control)等。 - 目标器中间层:
中间层维护了“LUN空间”,“任务集”,“任务(命令)”等模型,对于LUN空间维护有两种截然不同的实现方法: (1)一种是所有的PORT都看见的是一个全局的LUN, (2)一种是为每个PORT维护一个LUN空间, 其中第一种方法实现较为简单,这里的讨论以第一种展开。 - 目标器中的Device模型:本质上Device是一个SCSI指令“分析器”,通过处理INQUIRY告诉Initiator当前LUN是什么设备,通过READ/WRITE处理IO。
SCSI协议和存储系统
-
SCSI协议是主机与存储磁盘通信的基本协议。 -
DAS使用SCSI协议实现主机服务器与存储设备的互联。 -
控制器首先向总线处理器发出请求使用总线的信号。该请求被接受之后,控制器高速缓存就开始执行发送操作。在这个过程中,控制器占用了总线,总线上所连接的其它设备都不能使用总线。当然,由于总线具备中断功能,所以总线处理器可以随时中断这一传输过程并将总线控制权交给其它设备,以便执行更高优先级的操作。 -
SCSI 控制器相当于一个小型CPU,有自己的命令集和缓存。 -
SCSI是一种特殊的总线结构,可以对计算机中的多个设备进行动态分工操作,对于系统同时要求的多个任务可以灵活机动的适当分配,动态完成。
SCSI寻址
-
为了对连接在SCSI总线上的设备寻址,SCSI协议引入了SCSI设备ID和逻辑单元号LUN(Logical Unit Number)。 在SCSI总线上的每个设备都必须有一个唯一的设备ID,当然服务器中的主机总线适配器也拥有自己的设备ID,固定为7。 每条总线,包括总线适配器,最多允许有8个或者16个设备ID。 设备ID一方面用以寻址,另一个作用是标识该设备在总线使用上的优先级。 此外,在同一条总线上连接的不同的设备的设备ID必须不同,否则就会引起寻址和优先级的冲突。 -
每一个存储设备可能包括若干个子设备,如虚拟磁盘、磁带驱动器等。 因此SCSI协议引入了逻辑单元号LUN ID,以便于对存储设备中的子设备进行寻址。 -
传统的SCSI控制器连接单条总线,相应的只具有一个总线号。 企业级的一个服务器则可能配置了多个SCSI控制器,从而就可能有多条SCSI总线。 在引入存储网络之后,每个FC HBA(Host Bus Adapter)或iSCSI(Internet SCSI)网卡也都各连接着一条总线,因此必须对每一条总线分配一个总线号,在他们之间依靠不同的总线号加以区分。我们可以使用一个三元描述,标识一个SCSI目标:总线号/目标设备ID/逻辑单元号LUN ID。
2.iSCSI协议
-
SCSI (Internet SCSI)把SCSI命令和块状数据封装在TCP中在IP网络中传输。 -
iSCSI作为SCSI的传输层协议,基本出发点是利用成熟的IP网络技术来实现和延伸SAN。 -
iSCSI是互联网小型计算机系统接口(Internet Small Computer System Interface)的简称,是一种在TCP/IP上进行数据块传输的标准,可以理解为SCSI over IP。 iSCSI可构成基于IP的SAN,为用户提供高速、低价、长距离的存储解决方案。 -
iSCSI将SCSI命令封装到TCP/IP数据包中,使I/O数据块可通过IP网络传输。 -
iSCSI协议是SCSI远程过程调用模型到TCP/IP协议的映射。 SCSI协议层负责生成CDB,并将其送到iSCSI协议层,然后由 iSCSI协议层进一步封装成PDU,经IP网络进行传送。 ISCSI系统模型 -
发起端(Initiator) SCSI层负责生成CDB(命令描述符块),将CDB传给iSCSI。 iSCSI层负责生成iSCSI PDU(协议数据单元),并通过IP网络将PDU发给target。 -
目标器(Target) iSCSI层收到PDU,将CDB传给SCSI层。 SCSI层负责解释CDB的意义,必要时发送响应。
ISCSI体系架构
-
iSCSI节点将SCSI指令和数据封装成iSCSI包,然后该数据封装被传送给TCP/IP层,再由TCP/IP协议将iSCSI包封装成IP协议数据以适合在网络中传输。 -
在支持iSCSI的系统中,用户在一台SCSI存储设备上发出存数据或取数据的命令,操作系统对该请求进行处理,并将该请求转换成一条或者多条SCSI指令,然后再传给目标SCSI控制卡。 iSCSI节点将指令和数据封装起来,形成一个iSCSI包,然后该数据封装被传送给TCP/IP层,再由TCP/IP协议将iSCSI包封装成IP协议数据以适合在网络中传输。也可以对封装的SCSI命令进行加密处理,然后在不安全的网络上传送。 -
数据包可以在局域网或Internet上传送。 在接收存储控制器上,数据报重新被组合,然后存储控制器读取iSCSI包中的SCSI控制命令和数据发送到相应的磁盘驱动器上,磁盘驱动器再执行初始计算机或应用所需求的功能。 如果发送的是数据请求,那么将数据从磁盘驱动器中取出进行封装后发送给发出请求的计算机,而这整个过程对于用户来说都是透明的。 -
尽管SCSI命令的执行和数据准备可以通过使用标准TCP/IP和现成的网络控制卡的软件来完成,但是在利用软件完成封装和解封装的情况下,在主机处理器上实现这些功能需要很多的CPU运算周期来处理数据和SCSI命令。如果将这些事务交给专门的设备处理,则可以将对系统性能的影响减少到最小程度。 因此,发展在iSCSI标准下并执行SCSI命令和完成数据准备的专用iSCSI适配器是有必要的。iSCSI 适配器结合了NIC(网络接口控制器)和HBA(主机总线适配器)的功能。 这种适配器以块方式取得数据,利用 TCP/IP处理引擎在适配卡上完成数据分化和处理,然后通过IP网络送出IP数据包。这些功能的完成使用户可以在不降低服务器性能的基础上创建一个基于IP的SAN。 -
8b/10b编码是将一组连续的8位数据分解成两组数据,一组3位,一组5位,经过编码后分别成为一组4位的代码和一组6位的代码,从而组成一组10位的数据发送出去
3.IO–SCSI错误处理机制
基本原理 SCSI层提供的错误处理机制,主要针对两种IO错误类型(其实也就只有这两种类型):
- 1、IO错误(IO Error)。
IO错误是底层固件(比如SAS控制器固件或光纤卡固件)主动上报的事件(中断),表示下发的IO请求(SCSI命令)执行完成,但是出错了。 出现的情况较少,典型情况如:磁盘损坏导致IO执行错误。 - 2、IO超时(IO Timeout)。IO超时是IO请求下发后,在指定时间内(在IO请求下发时会启动相应的定时器,默认为30s,有些特殊的指令设置为60s或10s)没有执行完成(执行完成的标志是有相应的中断事件上报)。
那可能的原因就多了,在IO链路上的每个环节出现问题(而又没有相应的事件主动上报时),都可能出现超时,这种情况相对比较复杂。 典型的案例为:光纤卡链路问题(虚断)。
SCSI层提供的错误处理机制基本原理为:
- 1、在host初始化时启动相应的错误处理内核线程(scsi_eh_x)
- 2、当出现IO超时(由定时器触发后检测)或IO错误(由软中断触发后检测)时,将相应的错误IO命令加入到指定的队列中,并设置host状态为recovery(非常关键,这意味这至此所有该host的IO都将阻塞至error handler处理完成),然后唤醒相应的内核线程。
- 3、内核线程中,遍历相应的队列,对每个错误IO进行如下恢复操作:
1)尝试abort相应命令,实质为向指定设备发送Abort指令,如果设备还能响应,则abort成功,该错误IO处理结束。 2)如果abort失败,则尝试向设备发送START_UNIT指令,尝试让设备进行软重启。如果设备还能响应命令,那软重启可能成功。 3)如果软重启失败,那只能尝试硬重启了。硬重启分如下几个层次: a、先尝试reset device b、如果device reset失败,则尝试target rest c、如果target reset失败,则尝试bus(也称channel) reset d、如果bus reset失败,最后尝试host reset。 4)如果host reset后,设备状态仍不能恢复,那就无计可施了,只能将设备离线了。 5)设备离线后,继续处理相应队列中剩余的错误IO,当所有错误IO都处理完毕后,恢复host状态为running,至此error handler处理完成,Host状态恢复正常,IO阻塞结束。
主要问题
-
现有SCSI错误处理流程的主要问题为: 进入SCSI处理处理流程之前,会设置host状态为recovery状态,此后该host将处于阻塞状态,任何发往该host的IO都将阻塞,直至error handler处理完成。 这样设计的目的是因为当IO出现超时或错误时,内核并不知道具体是什么原因导致的,问题可能就出在host上,当host出现问题而此时不阻塞整个host时,可能导致错误IO继续下发,错误IO不断累积,导致error handler一直无法完成。 但是这样设计可能导致当host下一个硬盘出现问题时,其它硬盘的IO都会阻塞到error handler处理完成,这样会导致整个系统的IO阻塞或延迟,严重时(当host下磁盘数量较多时,比如磁阵或expender场景中),可能导致系统IO瘫痪。这个问题在一些应用场景中(比如共享存储的云计算场景中)非常严重,即使在新内核版本中加入了超时机制,但是由于host reset的时间通常也比较长,当错误IO数量较多时,IO阻塞时间仍比较长,而且不可控,需要考虑优化。 -
参考:SCSI协议与iSCSI协议,SCSI硬盘存储技术详解,linux scsi相关的一些学习笔记,kernel 3.10内核源码分析–IO–SCSI错误处理机制
|