Chinaunix首页 | 论坛 | 博客
  • 博客访问: 129785
  • 博文数量: 38
  • 博客积分: 1277
  • 博客等级: 中尉
  • 技术积分: 450
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-11 23:24
文章分类

全部博文(38)

文章存档

2012年(2)

2011年(7)

2010年(24)

2009年(5)

分类: 服务器与存储

2009-10-20 00:17:15

    iSCSI Initiator是通过SCSI Command PDU向Target发出SCSI请求,Target接收请求,执行SCSI命令,然后返回数据以及SCSI状态。在SCSI任务执行时,Initiator/Target之间会涉及大量数据I/O。RFC3720中对这些I/O的组织有特别的规定,以下结合RFC3720, 分析一下iSCSI中对SCSI请求的具体实现。
    SCSI Read比较简单,就先说说SCSI Read吧。Initiator发出SCSI Read请求以后,Target从设备中读取出数据,然后通过DataIn数据包返回给Initiator。如果数据长度太长,就要分成多个DataIn数据包。至于每个DataIn数据包最大数据段长度为多少由Login时Initiator给出的MaxRecvDataSegmentLength值控制,不能超过该值。另外, 这些DataIn是否按顺序发送同则由DataSequenceInOrder以及DataPDUInOrder控制。具体请参阅《iscsi几个关键字协商与实现》一文。数据包交互流程大致如下:

  SCSI Read (128) -------->
                  <-------- DataIn(flags=0, data_sn=0, data_offset=0)
                  <-------- DataIn(flags=0, data_sn=1, data_offset=8192)
                  <-------- DataIn(flags=0, data_sn=2, data_offset=16384)
                  <-------- DataIn(flags=0x81, data_sn=3, data_offset=32768)
                  # 结束包带F标记以及Status

作为Target端来说,似乎想不出有什么理由不按顺序发送DataIn,但有一种情况就是MC/s时,有可能从各个Connection中分发DataIn(这样可提高率能),如果各个链路走的路径不一样,那么到达Initiator端的DataIn包就有可能为非顺序的了。别外,在协议兼容性测试时,为了增加测试覆盖率,也会想尽办法产生这样的Case。当然最简单的处理方式为Target端直接协商时就直接声明按顺序收发DataIn,如果是这种情况,我想每一个SCSI任务,只能由一个Connect上进行收到数据包了,否则没有办法保证DataIn的顺序性(至少理论上没法保证吧)。

   SCSI Write实现与SCSI Read稍有不同,主要是受几个协商关键字的影响。一般SCSI Write过程为:首先发SCSI写指令,Target端收到请求后会分配置相应缓冲区进行接收,然后返回R2T包要求Initiator先发这个范 围的数据,R2T包中指定了Initiator要发送的数据范围。Initiator就是根据R2T划定的范围依次发出这个范围的数据。如果整个数据没有完全接收完,会再发出一下个R2T要求Initiator继续发数据,重复上面过程直到接收全部数据,最后返回SCSI Response告诉Initiator任务执行完成。Initiator数据是通过DataOut形式进行发出的,当然DataOut顺序与 DataIn一样,受协商关键字影响。由于这些DataOut中的数据是由R2T指定范围,也就是说应答R2T的这些DataOut数据包属于请求类数据 (solicated),根据R2T的请求来发送。当然还有一些属于非请求数(Unsolicated),也就是说在没有R2T请求之前就已经发出去,也就是说从SCSI Write到第一个R2T之间,Initiator所发了的数据都称为非请求数据(包括立即数据以及最开始几个DataOut数据),非请求类数据位于整个数据的最前面。这段数据的长度由FirstBurstLength控制,另外,是否允许这些非请求类数据由InitialR2T,以及ImmediateData所控制。R2T中的请求范围值也是控制的,主要受MaxBurstLength值所限制。可以这样去理解,ImmediateData是立即数据开关,InitiR2T是非请求DataOut开关。比如:

1.
ImmediateData=Yes, InitialR2T=Yes,这时只允许立即数据,不允许非请求类DataOut:
  SCSI_Write------------>
           ImmediateData
           <-------------  R2T0(请求范围<=MaxBurstLength)
  DataOut0  -------------> # 单PDU数据段长度<= MaxRecvDataSegmentLength
  DataOut1  ------------->
  DataOutn  -------------> # DataOut(0,1,2..n)总长<= MaxBurstLength
           <-------------  R2T1(请求范围<=MaxBurstLength)
  DataOut0  ------------->
  DataOut1  ------------->
  DataOutn  ------------->
           <-------------  SCSI_Response

2.ImmediateData=Yes, InitialR2T=No,这时即允许立即数据,也允许非请求类DataOut:
  SCSI_Write------------>
           ImmediateData
  DataOut0  -------------> # 单PDU数据段长度<= MaxRecvDataSegmentLength
  DataOut1  ------------->
  DataOutn  -------------> # ImmediateData + 几个DataOut总长 <= FirstBurstLength
           <-------------  R2T0(请求范围<=MaxBurstLength)
  DataOut0  -------------> # 单PDU数据段长度<= MaxRecvDataSegmentLength
  DataOut1  ------------->
  DataOutn  -------------> # DataOut(0,1,2..n)总长<= MaxBurstLength
           <-------------  R2T1(请求范围<=MaxBurstLength)
  DataOut0  ------------->
  DataOut1  ------------->
  DataOutn  ------------->
           <-------------  SCSI_Response

3.ImmediateData=No, InitialR2T=Yes,这时不允许立即数据,也不允许非请求类DataOut:
  SCSI_Write------------>
           <-------------  R2T0(请求范围<=MaxBurstLength)
  DataOut0  -------------> # 单PDU数据段长度<= MaxRecvDataSegmentLength
  DataOut1  ------------->
  DataOutn  -------------> # DataOut(0,1,2..n)总长<= MaxBurstLength
           <-------------  R2T1(请求范围<=MaxBurstLength)
  DataOut0  ------------->
  DataOut1  ------------->
  DataOutn  ------------->
           <-------------  SCSI_Response

4.ImmediateData=No, InitialR2T=No,这时不允许立即数据,允许非请求类DataOut:
  SCSI_Write------------>
  DataOut0  -------------> # 单PDU数据段长度<= MaxRecvDataSegmentLength
  DataOut1  ------------->
  DataOutn  -------------> # ImmediateData + 几个DataOut总长 <= FirstBurstLength
           <-------------  R2T0(请求范围<=MaxBurstLength)
  DataOut0  -------------> # 单PDU数据段长度<= MaxRecvDataSegmentLength
  DataOut1  ------------->
  DataOutn  -------------> # DataOut(0,1,2..n)总长<= MaxBurstLength
           <-------------  R2T1(请求范围<=MaxBurstLength)
  DataOut0  ------------->
  DataOut1  ------------->
  DataOutn  ------------->
           <-------------  SCSI_Response

阅读(4548) | 评论(1) | 转发(1) |
0

上一篇:pyTarget

下一篇:VTL的核心实现

给主人留下些什么吧!~~

chinaunix网友2011-04-15 15:23:39

不错