scsi学习笔记

笔记写的比较杂乱,仅供自己以后复习参考。

命令层 块命令和流命令等

协议层 xxoo

物理层

第二章 SCSI基础

协议的重要性

总线空闲条件:SCSI总线上没有活动

选择阶段
SCSI ID表示总线控制权优先级

消息阶段 协议使用消息来报告错误 命令状态和其他信息 也可以使用消息发送控制信息

命令阶段
启动器发送一个带有命令指令和参数数据的数据块给目标器
如果目标器要报告命令块格式或者参数错误 那么事务处理又机虐了消息阶段

数据阶段 是否产生数据阶段取决于发送的命令 命令决定了数据传输的方向

状态阶段 标志着SCSI命令的完成

最后的事务处理的还是消息阶段

启动器 SCSI设备

第三章 SCSI阶段
在一个简单的SCSI事务处理中 启动器为取得总线的控制权而进行仲裁
一旦获得了对总线的控制权它就选择一个目标器进行连接
目标器做出反应

SCSI设备可以分为启动器(initiator)或目标器(target),例如SCSI主机适配器是启动器,硬盘驱动器是目标器.一个S最小的可行配置是一个启动器和一个目标器.
计算机通过主机适配器连接到SCSI总线上,主机适配器一般在主板上,外围设备通过一个控制器连接到SCSI总线上,控制器一般在设备的电路板上.有时一个控制器也可以连接多个设备,叫做桥式连接.
启动器把一个命令发送到目标器,目标器执行命令并把结果通知给启动器,例如格式化硬盘就只需发送FORMAT UNIT命令然后就可以将控制权完全交给驱动器,格式化完成后,启动器仅仅得到命令执行成功或失败的信息.

总线状态
BSY SEL C/D I/O MSG ATN

第五章 SCSI命令
SCSI的命令和参数被封装在称为CDB命令描述块的结构中
不同的命令组对应于不同的长度命令描述符

0号组CDB是6字节
1号组和2号组是10字节长
5号组的CDB占用12个字节
其他由厂商自定义

CDB的第一个字节描述命令的操作码
高三位表示命令组 0-7
低5位表示命令码

CDB的第二个字节的高三位表示一个LUN(逻辑单元号)
低五位可能是保留的 也可能是以后字段的一部分 取决于命令组

命令参数 LUN字段后就是命令参数字段
对于直接存取设备来说 它包含的是逻辑块地址
对于传输数据的命令来说 包含的是传输长度
也可以包含和特定命令或者设备类型相关的值

控制字段
每个命令描述符的最后一个字段是控制字段

参数列表

多字节字段是按大端法来存储的
和X86相反

▲Scsi Pass through requests go to the miniport as
SRB_FUNCTION_EXECUTE_SCSI

///////////////////////////////////////
硬盘驱动器模型

IDE接口前身——ST506

ATAPI使用IDE作为其物理接口
但命令使用的是SCSI命令
数据通过逻辑块号来定位(LBA?)
格式化整个磁盘则是由某个命令直接触发的

SCSI-2总线可以对8个设备进行编址
SCSI-3可以更多

设备的SCSI总线地址称为SCSI ID
这些设备扮演了启动器或者目标器的角色

启动器和目标器
启动器是一个在SCSI总线上触发任务的设备
而目标器则是执行该任务的设备

逻辑单元LUN

LUN的概念
LUN的全称是Logical Unit Number,也就是逻辑单元号。我们知道SCSI总线上可挂接的设备数量是有限的,一般为6个或者15个,我们可以用Target ID(也有称为SCSI ID的)来描述这些设备,设备只要一加入系统,就有一个代号,我们在区别设备的时候,只要说几号几号就ok了。
而实际上我们需要用来描述的对象,是远远超过该数字的,于是我们引进了LUN的概念,也就是说LUN ID的作用就是扩充了Target ID。每个Target下都可以有多个LUN Device,我们通常简称LUN Device为LUN,这样就可以说每个设备的描述就有原来的Target x变成Target x LUN y了,那么显而易见的,我们描述设备的能力增强了。就好比,以前你给别人邮寄东西,写地址的时候,可以写:
xx市人民大街54号 xxx(收)
但是自从高楼大厦越来越多,你不得不这么写:
xx市人民大街54号xx大厦518室 xxx (收)
所以我们可以总结一下,LUN就是我们为了使用和描述更多设备及对象而引进的一个方法而已,一点也没什么特别的地方。

这里提到一点,由于TARGET Id的数量是有限的 那么我们为了表示更多的SCSI设备,就引入了LUN的概念
把设备一维的标示改成二维的标示TargetId = X, LUN = Y

客户机-服务器模型是实现SCSI系统很好的途径
从这个角度来说,PC是客户端 它自己的SCSI硬盘是服务器
PC向硬盘发送一个请求 硬盘执行请求并把数据传送回来

LBA->CHS

SCSI命令模型:
SCSI命令可以看作是对远程过程的调用:
Service Response = Execute Command(Task Identifier, Command, Descriptor Block, [Task Attribute], [Data Output Buffer], [Data Input Buffer], [Command Buffer], [Command Length], [Autosense Request], [Sense Data], Status)
SCSI命令由一个启动器发送到目标器的LUN,LUN的设备服务器执行命令,并返回一个状态.命令的输入输出方向是以启动器为参照的.

★在SCSI命令中必须实现:
1.任务标识符:只有SCSI-3中有,由一套64位的数字组成,分成启动器标识符,目标器标识符和LUN标识符.排序后的任务还有一个附加的标签.

2.命令描述块(CDC):包含完整的SCSI命令.

3.状态字节:命令结束后,状态字节给出一个命令是否被正确执行的信息,而且它还提供了一些关于命令结束的附加信息.

DISK.SYS-类驱动
SCSIPORT.SYS-端口驱动
ATAPI.SYS-微端口驱动

IOCTL_SCSI_GET_INQUIRY_DATA
获取每个SCSI总线和相应的驱动器所控制的设备的信息

在这些miniport驱动上面的是称为SCSIPORT的驱动
SCSIPORT驱动对于系统中的所有SCSI请求提供了唯一的入口点
                                          ~~~~~~~~~~~~
把系统特有的SCSI IO请求转化成标准的SCSI 命令描述块COMMAND DESCRIPTOR BLOCK
也就是传说中的CDB
      ~~~~~~~~~~~
并把这些请求发送给适当的MINIPORT驱动
由于其硬件细节被隐藏在了miniport驱动中,所以高层驱动可以调用
scsiport驱动来执行所有SCSI IO操作 而不用管硬件接口

一个限制
如果某驱动对一个特殊设备发出请求
我们要做的是向该类驱动发送和SCSI PASS-THOUGH命令
              ~~~~~~~~~~~~
而不是发送给SCSIPORT
~~~~~~~~~~~~~~~~~~~~
避免应用程序在某有通知类驱动的情况下发送命令
而且还可以允许类驱动保持对设备的控制权

这里难道是为了防止绕过类驱动直接向SCSIPORT发送SCSI命令?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

SCSI_PASS_THROUGH 和SCSI_REQUEST_BLOCK这两个结构很像啊~
The values of the DataIn member correspond to the SCSI_IOCTL_DATA_IN, SCSI_IOCTL_DATA_OUT, and SCSI_IOCTL_DATA_UNSPECIFIED

SCSI_PASS_THOUGH是可以让RING3通过DEVICE_IO_CONTROL来直接发CDB
SCSI_REQUEST_BLOCK是在驱动下 自己构造IRP包来发CDB

■如果是读取ATA设备 那么我们就不用填PATHID TARGRT ID LUN?
是的 这三个参数填0就行

[WIN32 SCSI支持模型]

win32应用程序    WIN32
    ↓
文件系统驱动    FSD
    ↓
磁盘类驱动(DISK.SYS) CD-ROM类驱动...
    ↓
SCSIPORT驱动(SCSIPORT.SYS) 端口驱动
    ↓
ATAPI(EIDE) Miniport驱动(atapi.sys atapi ide miniport driver) 微端口驱动
    ↓
标准IDE接口

详细的图参考 SCSI程序员指南p134

----------------------------------------分割线---------------------------------

[走aspi路线]

win32应用程序
    ↓
ASPI管理器
    ↓
ASPI驱动
    ↓
SCSIPORT驱动 剩下的同上图

atapi直接就可以接收SCSI指令。。。DISK.SYS也是通过CLASSPNP把SCSI转发到atapi的

scsi设备和scsi指令是两回事,DISK。SYS通过CLASSPNP把SCSI命令发到你的设备,如你是atapi的就发往他,如你是scsi设备就发往SCSI端口驱动

CDB命令描述块结构

操作码
命令特定参数
控制字节

每个命令的第0字节就是操作码 他定义了命令的类型和长度
高三位代表命令所属的命令组 低五位表示命令本身
每个命令组都有一个命令长度
因为对命令的第一个字节也就是操作码进行解析后
目标器就知道这个命令还剩下多少字节

对于不同类型的设备来说同样的操作码可以被解释为不同的命令
尽管通常它们之间还是有一点相似之处的
例如操作码0AH在磁盘和磁带设备表示WRITE 写命令 然后对于处理器设备
它代表SEND命令 而且命令的结构也可能是不同的。
因此,你不能仅仅从操作码来推断命令,必须知道这个命令是用在哪个设备上的

命令组
代表命令组的高三位可以有2^3=8个不同组合
所以可以代表8个命令组
除了保留组绝对不可以使用外 剩下的都可以使用

我们知道,Windows管理驱动设备栈,是使用的DeviceObject 中的AttachedDevice域,例如在我的虚拟机上,一个磁盘请求IRP发送到Disk.sys的磁盘设备后,会被接着转发到总线上的Atapi.sys的端口设备,实际是存在这样的关系:Atapi.sys的设备(例如\Deivce\Ide\IdeDevicePOTOLO-3)的AttachedDevice域 = Disk.sys的设备(例如\Device\Harddisk0\DR0) 。

\Device\HarddiskX\DRX     --------->    \Deivce\Ide\IdeDevicePOTOLO-X

SENSE DATA
当一个SCSI设备(通常是一个LUN)发现它自己处于异常状态时,它就拒绝执行下面的命令
并返回一个CHECK CONDITION状态
它在这种状态下产生18个字节的数据 这个数据包括经过编码的关于错误的信息
就被称作 SENSE DATA
typedef struct _SENSE_DATA {
    BYTE Valid;
    BYTE SegmentNumber;
    BYTE  FileMark;
    BYTE Information[4];
    BYTE AdditionalSenseLength;
    BYTE CommandSpecificInformation[4];
    BYTE AdditionalSenseCode;
    BYTE AdditionalSenseCodeQualifier;
    BYTE FieldReplaceableUnitCode;
    BYTE SenseKeySpecific[3];
} SENSE_DATA, *PSENSE_DATA;

SRB(SCSI_REQUEST_BLOCK结构)

typedef struct _SCSI_REQUEST_BLOCK {
  USHORT  Length;
  UCHAR  Function;
  UCHAR  SrbStatus;
  UCHAR  ScsiStatus;
  UCHAR  PathId;
  UCHAR  TargetId;
  UCHAR  Lun;
  UCHAR  QueueTag;
  UCHAR  QueueAction;
  UCHAR  CdbLength;
  UCHAR  SenseInfoBufferLength;
  ULONG  SrbFlags;
  ULONG  DataTransferLength;
  ULONG  TimeOutValue;
  PVOID  DataBuffer;
  PVOID  SenseInfoBuffer;
  struct _SCSI_REQUEST_BLOCK  *NextSrb;
  PVOID  OriginalRequest;
  PVOID  SrbExtension;
  union {
      ULONG  InternalStatus;
      ULONG  QueueSortKey;
  };
  UCHAR  Cdb[16];
} SCSI_REQUEST_BLOCK, *PSCSI_REQUEST_BLOCK;

我的猜测:
由于ATA设备不是SCSI设备 那么其中的PathId(总线ID),TargetId(目标器ID)和LUN都没有意义,这样向ATA发SRB的时候,这些区域填0就OK(不知正确与否)


参考资料:
《SCSI程序员指南》
《SCSI总线和IDE接口:协议、应用和编程》

posted @ 2010-01-18 21:03  robinh00d  阅读(9040)  评论(0编辑  收藏  举报