SCSI_PASS_THROUGH structure (转)

SCSI_PASS_THROUGH的格式

 

http://technet.microsoft.com/zh-cn/subscriptions/ff565345

typedef unsigned long ULONG;

typedef struct _SCSI_PASS_THROUGH {

    USHORT Length;

    UCHAR ScsiStatus;

    UCHAR PathId;

    UCHAR TargetId;

    UCHAR Lun;

    UCHAR CdbLength;

    UCHAR SenseInfoLength;

    UCHAR DataIn;

    ULONG DataTransferLength;

    ULONG TimeOutValue;

    ULONG DataBufferOffset;

    ULONG SenseInfoOffset;

    UCHAR Cdb[16];

}SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;


Members

Length

Contains the value of sizeof(SCSI_PASS_THROUGH).  

 

   


ScsiStatus

Reports the SCSI status that was returned by the HBA or the target device.

The ScsiStatus should be initialized to 0.  The SCSI status of the requested SCSI operation is returned in this structure member.  The possible SCSI statuses are defined in SCSI.H and are of the form SCSISTAT_xxx.

PathId

Indicates the SCSI port or bus for the request.  The PathId is the bus number for the SCSI host adapter that controls the SCSI device in question.  Typically, this value will be 0, but there are SCSI host adapters that have more than one SCSI bus on the adapter. 

TargetId

Indicates the target controller or device on the bus.

Lun

Indicates the logical unit number of the device.

The TargetId and Lun are the SCSI ID number and logical unit number for the device.  If the handle was obtained for a claimed device, then the PathId, TargetId and Lun as defined in this structure will be ignored and the appropriate class driver will provide this SCSI address information.  If the handle was obtained for the SCSI port driver, then the PathId, TargetId and Lun must be correct for the device intended. 

CdbLength

Indicates the size in bytes of the SCSI command descriptor block.The CdbLength is the length of the CDB. Typical values are 6, 10, and 12 up to the maximum of 16.

(关于CDB http://en.wikipedia.org/wiki/SCSI_CDB)

SenseInfoLength

Indicates the size in bytes of the request-sense buffer.The SenseInfoLength is the length of the SenseInfo buffer.

DataIn
Indicates whether the SCSI command will read or write data. This field must have one of three values:

Data Transfer Type Meaning

SCSI_IOCTL_DATA_IN

Read data from the device.

SCSI_IOCTL_DATA_OUT

Write data to the device.

SCSI_IOCTL_DATA_UNSPECIFIED

No data is transferred.

DataIn has three possible values which are defined in NTDDSCSI.H;  SCSI_IOCTL_DATA_OUT, SCSI_IOCTL_DATA_IN and SCSI_IOCTL_DATA_UNSPECIFIED.  SCSI_IOCTL_DATA_UNSPECIFIED should be used only if the appropriate SCSI miniport driver supports its usage. 

 

DataTransferLength

Indicates the size in bytes of the data buffer. Many devices transfer chunks of data of predefined length. The value in DataTransferLength must be an integral multiple of this predefined, minimum length that is specified by the device. If an underrun occurs, the miniport driver must update this member to the number of bytes actually transferred.

TimeOutValue

Indicates the interval in seconds that the request can execute before the port driver considers it timed out.The TimeOutValue is the length of time, in seconds, until a time-out error should occur. This can range from 0 to a maximum of 30 minutes (108000 seconds). 

DataBufferOffset

Contains an offset from the beginning of this structure to the data buffer. The offset must respect the data alignment requirements of the device. The DataBufferOffset is the offset of the data buffer from the beginning of the pass through structure.  For the SCSI_PASS_THROUGH_DIRECT structure, this value is not an offset, but rather is a pointer to a data buffer. 

SenseInfoOffset

Offset from the beginning of this structure to the request-sense buffer. The SenseInfoOffset is similarly an offset to the SenseInfo buffer from the beginning of the pass through structure.

Cdb

Specifies the SCSI command descriptor block to be sent to the target device. Finally, the sixteen remaining bytes are for the CDB data.  The format of this data must conform to the SCSI-2 standard as defined by ANSI.

Remarks

The SCSI_PASS_THROUGH structure is used with IOCTL_SCSI_PASS_THROUGH, which is a buffered device control request. To bypass buffering in system memory, callers should use IOCTL_SCSI_PASS_THROUGH_DIRECT. When handling an IOCTL_SCSI_PASS_THROUGH_DIRECT request, the system locks down the buffer in user memory and the device accesses this memory directly.

The members of SCSI_PASS_THROUGH correspond roughly to the members of a SCSI_REQUEST_BLOCK structure. The values of the DataIn member correspond to the SCSI_IOCTL_DATA_IN, SCSI_IOCTL_DATA_OUT, and SCSI_IOCTL_DATA_UNSPECIFIED flags assigned to SrbFlags member of SCSI_REQUEST_BLOCK.

Requirements

Header

Ntddscsi.h (include Ntddscsi.h)




(笔记转载)


http://www.cnblogs.com/robinh00d/archive/2010/01/18/1651012.html

命令层 块命令和流命令等

协议层 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接口:协议、应用和编程》

你可能感兴趣的:(BUS,Interface)