📄 overview-ffp
字号:
OVERVIEW-FPP.txt----------------Note: this document is written in ordinary ASCII text with tabs set to a width of 4.Overview of Full Feature Phase (FFP)------------------------------------There are 5 steps involved in using the iscsi initiator (the first 4 must bedone as root):1. Load the "iscsi_initiator.o" module.2. Use "../common/iscsi_manage" to set up parameters for negotiation.3. Use "iscsi_config up" to trigger the login process and the discovery process that follows it.4. Use "mount /mnt/scsi" to mount the scsi target device as a disk.5. Use ordinary operations to create/delete/read/write files on the disk.5.0 Once the scsi target device has been mounted, the file system it contains can be used by ordinary users in the way they would use any other file system on any other disk. At the command level, this means that the user can use any of the normal file manipulation commands: cp, mv, rm, tar, mkdir, rmdir, cd, pwd, etc., on files and directories stored on the scsi target disk. Furthermore, any programs can access these files using the normal open, close, read, write, etc. system calls. For example, if the file system is mounted using the command "mount /mnt/scsi" and I have a directory on this file system called "rdr", then I can do the following types of operations: cd /mnt/scsi/rdr # my local directory is now on that file system pwd # shows me that ls # lists all files in that directory vi xyz.c # edits the file xyz.c in that directory ... make xyz # builds an executable in that directory xyz # runs the executable xyz from that directory ... During these operations, the Linux SCSI mid-level delivers only READ (10) and WRITE (10) commands to the iscsi_initiator module, so these are the only commands we will look at here.5.1 SCSI READ A SCSI READ operation is used to transfer data from the target to the initiator. This means it is a "read" operation from the point of view of the initiator, who "reads" data from the target. From the target's point of view, a READ operation causes it to "read" data from the target's disk, but to "send" (i.e., "write") data to the inititator.5.1.1 Overview To simplify this discussion, we will initially assume that "phase collapse" is not being used. Later we will explain what happens when "phase collapse" is used. We will also ignore for the moment the effects of the MaxBurstSize key on data being read. This will also be explained later. A "task" is a SCSI operation. In principle, one task can require several (linked) SCSI commands, and each SCSI command can involve the transfer of several iSCSI PDUs. However, the Linux SCSI system does not seem to use multi-command tasks, so we only see one SCSI command per task. (In any case, SCSI allows only one command per task to be outstanding at any time.) This one command, however, will usually require the transfer of several iSCSI PDUs -- for a READ command, these PDUs will be: 1. one "SCSI Command" PDU sent by the initiator to deliver the READ command information to the target, 2. some number of "DataIn" PDUs sent back by the target to deliver the data to the initiator, 3. one final "SCSI Response" PDU sent back by the target to deliver the final status to the initiator. To account for these various levels, the iSCSI protocol requires that several "identifiers" and "counters" be maintained by the initiator and the target: 1. The Initiator Task Tag (ITT). This is a value determined by the initiator that uniquely identifies each outstanding iSCSI task for the life of that task. In the case of a READ operation, the same ITT value is carried in all the PDUs mentioned above (the "SCSI Command" PDU, all the "DataIn" PDUs, and the final "SCSI Response" PDU), because together they are all part of the same task. Our iscsi_initiator implements the ITT as a per-session counter, called "init_task_tag", in the session data structure. It is incremented by 1 on each call to the "iscsi_initiator_queuecommand" function. Note, however, that the iSCSI protocol does not require this to be a sequential counter! That is just the simplest way to implement it so that no two tasks will have the same ITT. The target should not check this value for sequentiality, and should just copy it opaquely into all PDUs it sends back that are related to this task in order to identify their relationship to the initiator. 2. The Command Sequence Number (CmdSN). This is a sequence number, and must be implemented by the initiator as a session-wide counter that is incremented by 1 for each command sent in that session, regardless of which task the command is associated with. This value is contained only in PDUs sent by the initiator. The target should check this value for sequentiality, and should use it to detect duplicate and/or missing PDUs. 3. The Expected Command Sequence Number (ExpCmdSN). This is a value that is maintained by the target in order to check the value of the CmdSN field in incoming PDUs from the initiator. If the incoming CmdSN value is less than the target's ExpCmdSN, the incoming PDU is a duplicate of a PDU already received by the target and should be ignored. If the incoming CmdSN value is greater than the target's ExpCmdSN, the incoming PDU is out of order, indicating that the PDU containing the proper (i.e., expected) CmdSN may have been lost. If the incoming CmdSN value is equal to the target's ExpCmdSN (the normal case), then the incoming PDU is in the proper order, and the target increments its ExpCmdSN by 1. Whenever the target sends a PDU of any kind back to the initiator, it will include in that PDU a copy of its current ExpCmdSN value. This "acknowledges" to the initiator that the target has received all command PDUs with CmdSN values less than this ExpCmdSN. 4. The Data Sequence Number (DataSN). This is a sequence number, and must be implemented by the target as a command-dependent counter that is incremented by 1 for each DataIn PDU it sends back for this command. The first DataIn PDU for each command contains a DataSN of 0. The initiator should check this value for sequentiality, and should use it to check for duplicate and/or missing DataIn PDUs from the target. 5. The Status Sequence Number (StatSN). This is a sequence number, and must be implemented by the target as a connection-wide counter that is incremented by 1 for each response PDU it sends back on this connection. It is only sent by the target. The initiator should check this value for sequentiality, and should use it to check for duplicate and/or missing response PDUs from the target. Note that after a "SCSI Command" PDU for a READ operation, the one or more DataIn PDUs sent by the target do not contain a StatSN (or rather, the StatSN field in the PDU is "reserved" and therefore contains a value of 0). Only the one "SCSI Response" PDU sent after all the DataIn PDUs contains a valid StatSN (and advances the StatSN by 1). 6. The Expected Status Sequence Number (ExpStatSN). This is a value that is maintained by the initiator in order to check the value of the StatSN field in incoming PDUs from the target. If the incoming StatSN value is less than the initiator's ExpStatSN, the incoming PDU is a duplicate of a PDU already received by the initiator and should be ignored. If the incoming StatSN value is greater than the initiator's ExpStatSN, the incoming PDU is out of order, indicating that the PDU containing the proper (i.e., expected) StatSN may have been lost. If the incoming StatSN value is equal to the initiator's ExpStatSN (the normal case), then the incoming PDU is in the proper order, and the initiator increments its ExpStatSN by 1. Whenever the initiator sends a command PDU of any kind to the target, it will include in that PDU a copy of its current ExpStatSN value. This "acknowledges" to the target that the initiator has received all response PDUs with StatSN values less than this ExpStatSN.5.1.2 PDU trace The following gives a trace of the PDUs sent during a READ command, and the values of the counters maintained by the initiator and the target during the exchange of PDUs. (This is taken directly from the file "ty4" starting at line 4510.) 0. Assumptions: 1. The command is a READ of 32768 bytes of data (64 blocks each containing 512 bytes) starting at logical block number 18572 on the disk (and ending with logical block number 18635). 2. The current value of the initiator's CmdSN counter is 22264. 3. The target has received and processed completely all previous commands from the initiator. 4. The current value of the target's StatSN counter is 67. 5. The initiator has received and processed completely all previous responses from the target. 6. The key MaxRecvPDULength=12288 was sent by the initiator to the target during the login phase (which says that the target should send no more that 12288 bytes of data (24 logical blocks) in any one PDU). This value of MaxRecvPDULength means that the target will be forced to send the total amount of data (32768 bytes) in 3 separate DataIn PDUs having DataSN numbers 0, 1, 2: 0. the first 12288 bytes (a total of 12288 sent so far); 1. the second 12288 bytes (a total of 24576 sent so far); 2. the last 8192 bytes (a total of 32768 sent so far). 7. Header and Data Digests are not in use. 8. DataPDUInOrder=yes. 1. The initiator sends a 48-byte SCSICommand PDU to the target: 1. The opcode field is 0x01 for (SCSICommand). 2. The F bit is 1 and the R bit is 1 (for a READ). 3. The DataSegmentLength (DSL) field is 0 (no data attached to this PDU). 4. The ITT field is 88931 (unique for this command). 5. The EDTL field is 32768 (the total number of bytes to READ). 6. The CmdSN field is 22264 (the initiator's CmdSN counter). 7. The ExpStatSN field is 67 (the initiator's ExpStatSN counter). 8. The CDBopcode field is 0x28 (READ (10)). 9. The CDBlba field is 18572 (starting logical block number on disk). 10. The CDBlength field is 64 (total number of blocks to READ). 2. The target sends a 12336 byte DataIn PDU that contains 48 header bytes and the 12288 bytes from the 24 logical blocks 18572 through 18595 inclusive on the disk. (12288 bytes (24 logical blocks) is the maximum amount of data allowed in any PDU sent by the target to this initiator, as controlled by the MaxRecvPDULength=12288 key negotiated during login). 1. The opcode field is 0x25 (for DataIn). 2. The I bit is 1 (for a response PDU). 3. The F bit is 0 (not the last DataIn PDU in this sequence). 4. The DSL field is 12288 (this many bytes of data are attached to this PDU (24 blocks of 512 bytes each). 5. The ITT field is 88931 (copied from the SCSICommand PDU). 6. The ExpCmdSN field is 22265 (1 more than the CmdSN field in the SCSICommand PDU, thereby acknowledging receipt of that command). 7. The DataSN field is 0 (first DataIn PDU sent in response to the SCSICommand request). 8. The BufferOffset field is 0 (the attached data goes into the first byte in the memory buffer on the initiator). 3. The target sends a 12336 byte DataIn PDU that contains 48 header bytes and the 12288 bytes from 24 logical blocks 18596 through 18619 inclusive on the disk. 1. The opcode field is 0x25 (for DataIn). 2. The I bit is 1 (for a response PDU). 3. The F bit is 0 (not the last DataIn PDU in this sequence). 4. The DSL field is 12288 (this many bytes of data are attached to this PDU (24 blocks of 512 bytes each). 5. The ITT field is 88931 (copied from the SCSICommand PDU). 6. The ExpCmdSN field is 22265 (1 more than the CmdSN field in the SCSICommand PDU, again acknowledging receipt of that command). 7. The DataSN field is 1 (second DataIn PDU sent in response to the SCSICommand request). 8. The BufferOffset field is 12288 (the attached data goes into this byte in the memory buffer on the initiator, immediately after the last byte sent in the first DataIn PDU). 4. The target sends a 8240 byte DataIn PDU that contains 48 header bytes and the 8192 bytes from 16 logical blocks 18620 through 18635 inclusive on the disk. 1. The opcode field is 0x25 (for DataIn). 2. The I bit is 1 (for a response PDU). 3. The F bit is 1 (this is the last DataIn PDU in this sequence). 4. The DSL field is 8192 (this many bytes of data are attached to this PDU (16 blocks of 512 bytes each). 5. The ITT field is 88931 (copied from the SCSICommand PDU). 6. The ExpCmdSN field is 22265 (1 more than the CmdSN field in the SCSICommand PDU, again acknowledging receipt of that command). 7. The DataSN field is 2 (third DataIn PDU sent in response to the SCSICommand request). 8. The BufferOffset field is 24576 (the attached data goes into this byte in the memory buffer on the initiator, immediately after the last byte sent in the previous DataIn PDU). 5. the target sends a 48 byte SCSIResponse PDU to the initiator: 1. The opcode field is 0x21 (for SCSIResponse). 2. The I bit is 1 (for a response PDU). 3. The F bit is 1 (always 1 on a SCSIResponse PDU). 4. The Response and Status fields are both 0 (Successful completion). 5. The DSL field is 0 (no bytes of data are attached to this PDU). 6. The ITT field is 88931 (copied from the SCSICommand PDU). 7. The StatSN field is 67 (the target's StatSN counter). 8. The ExpCmdSN field is 22265 (1 more than the CmdSN field in the SCSICommand PDU, thereby acknowledging receipt of that command). At this point, all 32768 bytes (64 logical blocks) of data have been successfully transfered from logical block numbers 18572 through 18635 inclusive on the target's disk into the initiator's memory buffer (which is at an address given to the initiator by the SCSI subsystem on the initiator). Furthermore, the initiator's CmdSN counter was updated in step 1 above to now have the value 22265 (1 more than the CmdSN value used in the SCSICommand PDU), and the target's StatSN counter was updated in step 5 above to now have the value 68 (1 more than the StatSN value used in the SCSIResponse PDU). Finally, the initiator's ITT counter was updated in step 1 above to now have the value 88932, which will be unique for the next command to be sent by the initiator (remember, this does not have to be implemented as a counter).5.1.3 QueueCommand The SCSI mid-level gets requests from higher levels of software, such as a file system, to READ or WRITE data blocks from/to a SCSI device. Using information provided by the higher level, the SCSI mid-level figures out where in memory the data should be transfered to (on a READ) or from (on a WRITE), and which SCSI device and which data blocks on the device are involved in the transfer. It then constructs a SCSI Command to perform the transfer and passes it to a "QueueCommand" function provided by each SCSI device driver. In our case, the SCSI device driver is our "iscsi_initiator" module, and its "QueueCommand" function is the "iscsi_initiator_queuecommand" entry. This function is always executed in the kernel, but within context of some process or thread. It is never executed in an interrupt context.5.1.3.1 Scsi_Cmnd When the SCSI mid-level wants to perform a READ operation, it creates a "Scsi_Cmnd" data structure and passes a pointer to it as the first parameter in a call to the "iscsi_initiator_queuecommand" function. This structure contains several important pieces of information: 1. the "target" field which is used by "iscsi_initiator_queuecommand" to associate this command with the appropriate session and connection.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -