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.phase;
20  
21  
22  import java.nio.ByteBuffer;
23  
24  import org.jscsi.initiator.connection.Connection;
25  import org.jscsi.initiator.connection.ITask;
26  import org.jscsi.initiator.connection.Session;
27  import org.jscsi.initiator.connection.TargetCapacityInformations;
28  import org.jscsi.initiator.connection.state.CapacityRequestState;
29  import org.jscsi.initiator.connection.state.GetConnectionsRequestState;
30  import org.jscsi.initiator.connection.state.LogoutRequestState;
31  import org.jscsi.initiator.connection.state.ReadRequestState;
32  import org.jscsi.initiator.connection.state.WriteRequestState;
33  import org.jscsi.parser.login.LoginStage;
34  import org.jscsi.parser.logout.LogoutRequestParser.LogoutReasonCode;
35  import org.jscsi.parser.scsi.SCSICommandParser.TaskAttributes;
36  
37  
38  /**
39   * <h1>FullFeaturePhase</h1>
40   * <p/>
41   * This class represents the Full-Feature Phase of a session. In this phase all commands are allowed (eg. read, write,
42   * login of further connections, ...).
43   * 
44   * @author Volker Wildi
45   */
46  public final class FullFeaturePhase extends AbstractPhase {
47  
48      // --------------------------------------------------------------------------
49      // --------------------------------------------------------------------------
50  
51      /** Number of blocks to read in the first stage of a read operation. */
52      private static final int READ_FIRST_STAGE_BLOCKS = 64;
53  
54      /** Number of blocks to read in the second stage of a read operation. */
55      private static final int READ_SECOND_STAGE_BLOCKS = 128;
56  
57      /** Number of blocks to read in the third stage of a read operation. */
58      private static final int READ_THIRD_STAGE_BLOCKS = 256;
59  
60      /** Number of blocks to read in the first stage of a write operation. */
61      private static final int WRITE_FIRST_STAGE_BLOCKS = 1024;
62  
63      /** Number of blocks to read in the second stage of a write operation. */
64      private static final int WRITE_SECOND_STAGE_BLOCKS = 2048;
65  
66      /** Number of blocks to read in the third stage of a write operation. */
67      private static final int WRITE_THIRD_STAGE_BLOCKS = 4096;
68  
69      // --------------------------------------------------------------------------
70      // --------------------------------------------------------------------------
71  
72      /** {@inheritDoc} */
73      @Override
74      public final boolean login (final Session session) throws Exception {
75  
76          final Connection connection = session.getNextFreeConnection();
77          connection.nextState(new GetConnectionsRequestState(connection));
78          session.releaseUsedConnection(connection);
79          return true;
80      }
81  
82      // TODO: Uncomment
83      // /** {@inheritDoc} */
84      // @Override
85      // public final void logoutConnection(final Session session) throws
86      // Exception
87      // {
88      //
89      // final Connection connection = session.getNextFreeConnection();
90      // connection.setState(new LogoutRequestState(connection,
91      // LogoutReasonCode.CLOSE_CONNECTION));
92      // connection.execute();
93      // }
94  
95      /** {@inheritDoc} */
96      @Override
97      public final boolean logoutSession (final ITask task, final Session session) throws Exception {
98  
99          final Connection connection = session.getNextFreeConnection();
100         connection.getSession().addOutstandingTask(connection, task);
101         connection.nextState(new LogoutRequestState(connection, LogoutReasonCode.CLOSE_SESSION));
102         return true;
103     }
104 
105     /** {@inheritDoc} */
106     @Override
107     public final boolean read (final ITask task, final Session session, final ByteBuffer dst, final int logicalBlockAddress, final long length) throws Exception {
108 
109         if (dst.remaining() < length) { throw new IllegalArgumentException("Destination buffer is too small."); }
110 
111         int startAddress = logicalBlockAddress;
112         final long blockSize = session.getBlockSize();
113         long totalBlocks = (long) Math.ceil(length / (double) blockSize);
114         long bytes2Process = length;
115 
116         final Connection connection = session.getNextFreeConnection();
117         connection.getSession().addOutstandingTask(connection, task);
118 
119         // first stage
120         short blocks = (short) Math.min(READ_FIRST_STAGE_BLOCKS, totalBlocks);
121 
122         if (LOGGER.isInfoEnabled()) {
123             LOGGER.info("Now reading sequences of length " + blocks + " blocks.");
124         }
125 
126         connection.nextState(new ReadRequestState(connection, dst, TaskAttributes.SIMPLE, (int) Math.min(bytes2Process, blocks * blockSize), startAddress, blocks));
127         startAddress += blocks;
128         totalBlocks -= blocks;
129         bytes2Process -= blocks * blockSize;
130 
131         // second stage
132         blocks = (short) Math.min(READ_SECOND_STAGE_BLOCKS, totalBlocks);
133 
134         if (blocks > 0) {
135 
136             if (LOGGER.isInfoEnabled()) {
137                 LOGGER.info("Now reading sequences of length " + blocks + " blocks.");
138             }
139             connection.nextState(new ReadRequestState(connection, dst, TaskAttributes.SIMPLE, (int) Math.min(bytes2Process, blocks * blockSize), startAddress, blocks));
140             startAddress += blocks;
141             totalBlocks -= blocks;
142             bytes2Process -= blocks * blockSize;
143         }
144 
145         // third stage
146         blocks = (short) Math.min(READ_THIRD_STAGE_BLOCKS, totalBlocks);
147 
148         while (blocks > 0) {
149 
150             if (LOGGER.isInfoEnabled()) {
151                 LOGGER.info("Now reading sequences of length " + blocks + " blocks.");
152             }
153 
154             connection.nextState(new ReadRequestState(connection, dst, TaskAttributes.SIMPLE, (int) Math.min(bytes2Process, blocks * blockSize), startAddress, blocks));
155             startAddress += blocks;
156             totalBlocks -= blocks;
157             blocks = (short) Math.min(READ_THIRD_STAGE_BLOCKS, totalBlocks);
158         }
159         return true;
160     }
161 
162     /** {@inheritDoc} */
163     @Override
164     public final boolean write (final ITask task, final Session session, final ByteBuffer src, final int logicalBlockAddress, final long length) throws Exception {
165 
166         if (src.remaining() < length) { throw new IllegalArgumentException("Source buffer is too small. Buffer size: " + src.remaining() + " Expected: " + length); }
167 
168         int startAddress = logicalBlockAddress;
169         final long blockSize = session.getBlockSize();
170         int totalBlocks = (int) Math.ceil(length / (double) blockSize);
171         long bytes2Process = length;
172         int bufferPosition = 0;
173 
174         final Connection connection = session.getNextFreeConnection();
175         connection.getSession().addOutstandingTask(connection, task);
176 
177         // first stage
178         short blocks = (short) Math.min(WRITE_FIRST_STAGE_BLOCKS, totalBlocks);
179 
180         if (LOGGER.isInfoEnabled()) {
181             LOGGER.info("Now sending sequences of length " + blocks + " blocks.");
182         }
183 
184         int expectedDataTransferLength = (int) Math.min(bytes2Process, blocks * blockSize);
185         connection.nextState(new WriteRequestState(connection, src, bufferPosition, TaskAttributes.SIMPLE, expectedDataTransferLength, startAddress, blocks));
186         startAddress += blocks;
187         totalBlocks -= blocks;
188         bytes2Process -= blocks * blockSize;
189         bufferPosition += expectedDataTransferLength;
190 
191         // second stage
192         blocks = (short) Math.min(WRITE_SECOND_STAGE_BLOCKS, totalBlocks);
193 
194         if (blocks > 0) {
195 
196             if (LOGGER.isInfoEnabled()) {
197                 LOGGER.info("Now sending sequences of length " + blocks + " blocks.");
198                 LOGGER.info("Remaining, DataSegmentLength: " + bytes2Process + ", " + expectedDataTransferLength);
199             }
200 
201             expectedDataTransferLength = (int) Math.min(bytes2Process, blocks * blockSize);
202             connection.nextState(new WriteRequestState(connection, src, bufferPosition, TaskAttributes.SIMPLE, expectedDataTransferLength, startAddress, blocks));
203             startAddress += blocks;
204             totalBlocks -= blocks;
205             bytes2Process -= blocks * blockSize;
206             bufferPosition += expectedDataTransferLength;
207         }
208 
209         // third stage
210         blocks = (short) Math.min(WRITE_THIRD_STAGE_BLOCKS, totalBlocks);
211 
212         while (blocks > 0) {
213 
214             if (LOGGER.isInfoEnabled()) {
215                 LOGGER.info("Now sending sequences of length " + blocks + " blocks.");
216             }
217 
218             expectedDataTransferLength = (int) Math.min(bytes2Process, blocks * blockSize);
219             connection.nextState(new WriteRequestState(connection, src, bufferPosition, TaskAttributes.SIMPLE, expectedDataTransferLength, startAddress, blocks));
220             startAddress += blocks;
221             totalBlocks -= blocks;
222             blocks = (short) Math.min(READ_THIRD_STAGE_BLOCKS, totalBlocks);
223             bufferPosition += expectedDataTransferLength;
224         }
225         return true;
226     }
227 
228     /** {@inheritDoc} */
229     @Override
230     public final boolean getCapacity (final Session session, final TargetCapacityInformations capacityInformation) throws Exception {
231 
232         if (capacityInformation == null) { throw new NullPointerException(); }
233 
234         final Connection connection = session.getNextFreeConnection();
235         if (connection == null) { throw new NullPointerException(); }
236 
237         connection.nextState(new CapacityRequestState(connection, capacityInformation, TaskAttributes.SIMPLE));
238         session.releaseUsedConnection(connection);
239         return true;
240     }
241 
242     // --------------------------------------------------------------------------
243     // --------------------------------------------------------------------------
244 
245     /** {@inheritDoc} */
246     @Override
247     public final LoginStage getStage () {
248 
249         return LoginStage.FULL_FEATURE_PHASE;
250     }
251 
252     // --------------------------------------------------------------------------
253     // --------------------------------------------------------------------------
254     // --------------------------------------------------------------------------
255     // --------------------------------------------------------------------------
256 
257 }