1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
40
41
42
43
44
45
46 public final class FullFeaturePhase extends AbstractPhase {
47
48
49
50
51
52 private static final int READ_FIRST_STAGE_BLOCKS = 64;
53
54
55 private static final int READ_SECOND_STAGE_BLOCKS = 128;
56
57
58 private static final int READ_THIRD_STAGE_BLOCKS = 256;
59
60
61 private static final int WRITE_FIRST_STAGE_BLOCKS = 1024;
62
63
64 private static final int WRITE_SECOND_STAGE_BLOCKS = 2048;
65
66
67 private static final int WRITE_THIRD_STAGE_BLOCKS = 4096;
68
69
70
71
72
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
83
84
85
86
87
88
89
90
91
92
93
94
95
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
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
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
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
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
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
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
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
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
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
246 @Override
247 public final LoginStage getStage () {
248
249 return LoginStage.FULL_FEATURE_PHASE;
250 }
251
252
253
254
255
256
257 }