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;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值