View Javadoc

1   /**
2    * Copyright (c) 2012, University of Konstanz, Distributed Systems Group All rights reserved.
3    * 
4    * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
5    * following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of
6    * conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice,
7    * this list of conditions and the following disclaimer in the documentation and/or other materials provided with the
8    * distribution. * Neither the name of the University of Konstanz nor the names of its contributors may be used to
9    * endorse or promote products derived from this software without specific prior written permission.
10   * 
11   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
12   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
13   * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
14   * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
15   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
16   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
17   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18   */
19  package org.jscsi.initiator.connection.state;
20  
21  
22  import java.nio.ByteBuffer;
23  
24  import org.jscsi.exception.InternetSCSIException;
25  import org.jscsi.initiator.connection.Connection;
26  import org.jscsi.parser.OperationCode;
27  import org.jscsi.parser.ProtocolDataUnit;
28  import org.jscsi.parser.datasegment.DataSegmentFactory;
29  import org.jscsi.parser.datasegment.DataSegmentFactory.DataSegmentFormat;
30  import org.jscsi.parser.datasegment.IDataSegment;
31  import org.jscsi.parser.datasegment.IDataSegmentIterator;
32  import org.jscsi.parser.datasegment.OperationalTextKey;
33  import org.jscsi.parser.scsi.SCSICommandDescriptorBlockParser;
34  import org.jscsi.parser.scsi.SCSICommandParser;
35  import org.jscsi.parser.scsi.SCSICommandParser.TaskAttributes;
36  
37  
38  /**
39   * <h1>WriteRequestState</h1>
40   * <p/>
41   * This state handles a Write Response with unsolicited data.
42   * 
43   * @author Volker Wildi
44   */
45  public final class WriteRequestState extends AbstractState {
46  
47      // --------------------------------------------------------------------------
48      // --------------------------------------------------------------------------
49  
50      /** The buffer to used for the message transfer. */
51      private final ByteBuffer buffer;
52  
53      /** The task attributes of this write operation. */
54      private final TaskAttributes taskAttributes;
55  
56      /** The expected length in bytes, which should be transfered. */
57      private final int expectedDataTransferLength;
58  
59      /** The logical block address of the start block for this write operation. */
60      private final int logicalBlockAddress;
61  
62      /** The start index of the buffer. */
63      private final int bufferPosition;
64  
65      /**
66       * The number of blocks (This block size is dependent on the size used on the target side.) to read.
67       */
68      private final short transferLength;
69  
70      // --------------------------------------------------------------------------
71      // --------------------------------------------------------------------------
72  
73      /**
74       * Constructor to create a <code>WriteRequestState</code> instance, which creates a request to the iSCSI Target.
75       * 
76       * @param initConnection This is the connection, which is used for the network transmission.
77       * @param initBuffer This buffer should be sent.
78       * @param initBufferPosition The start index of the buffer.
79       * @param initTaskAttributes The task attributes of this task.
80       * @param initExpectedDataTransferLength The expected length in bytes, which should be transfered.
81       * @param initLogicalBlockAddress The logical block address of the first block to write.
82       * @param initTransferLength The number of blocks to write.
83       */
84      public WriteRequestState (final Connection initConnection, final ByteBuffer initBuffer, final int initBufferPosition, final TaskAttributes initTaskAttributes, final int initExpectedDataTransferLength, final int initLogicalBlockAddress, final short initTransferLength) {
85  
86          super(initConnection);
87          buffer = initBuffer;
88          bufferPosition = initBufferPosition;
89          taskAttributes = initTaskAttributes;
90          expectedDataTransferLength = initExpectedDataTransferLength;
91          logicalBlockAddress = initLogicalBlockAddress;
92          transferLength = initTransferLength;
93      }
94  
95      // --------------------------------------------------------------------------
96      // --------------------------------------------------------------------------
97  
98      /** {@inheritDoc} */
99      public final void execute () throws InternetSCSIException {
100 
101         final ProtocolDataUnit protocolDataUnit = protocolDataUnitFactory.create(false, true, OperationCode.SCSI_COMMAND, connection.getSetting(OperationalTextKey.HEADER_DIGEST), connection.getSetting(OperationalTextKey.DATA_DIGEST));
102         final SCSICommandParser scsi = (SCSICommandParser) protocolDataUnit.getBasicHeaderSegment().getParser();
103 
104         scsi.setReadExpectedFlag(false);
105         scsi.setWriteExpectedFlag(true);
106         scsi.setTaskAttributes(taskAttributes);
107 
108         scsi.setExpectedDataTransferLength(expectedDataTransferLength);
109 
110         final int maxRecvDataSegmentLength = connection.getSettingAsInt(OperationalTextKey.MAX_RECV_DATA_SEGMENT_LENGTH);
111         scsi.setCommandDescriptorBlock(SCSICommandDescriptorBlockParser.createWriteMessage(logicalBlockAddress, transferLength));
112 
113         final IDataSegment dataSegment = DataSegmentFactory.create(buffer, bufferPosition, expectedDataTransferLength, DataSegmentFormat.BINARY, maxRecvDataSegmentLength);
114         final IDataSegmentIterator iterator = dataSegment.iterator();
115         int bufferOffset = 0;
116 
117         if (connection.getSettingAsBoolean(OperationalTextKey.IMMEDIATE_DATA)) {
118             final int min = Math.min(maxRecvDataSegmentLength, connection.getSettingAsInt(OperationalTextKey.FIRST_BURST_LENGTH));
119             protocolDataUnit.setDataSegment(iterator.next(min));
120             bufferOffset += min;
121         }
122 
123         connection.send(protocolDataUnit);
124 
125         if (!connection.getSettingAsBoolean(OperationalTextKey.INITIAL_R2T) && iterator.hasNext()) {
126             connection.nextState(new WriteFirstBurstState(connection, iterator, 0xFFFFFFFF, 0, bufferOffset));
127         } else {
128             connection.nextState(new WriteSecondResponseState(connection, iterator, 0, bufferOffset));
129         }
130         super.stateFollowing = true;
131         // return true;
132     }
133     // --------------------------------------------------------------------------
134     // --------------------------------------------------------------------------
135     // --------------------------------------------------------------------------
136     // --------------------------------------------------------------------------
137 
138 }