1 package org.jscsi.target.connection.stage.fullfeature;
2
3
4 import static org.jscsi.target.storage.IStorageModule.VIRTUAL_BLOCK_SIZE;
5
6 import java.io.IOException;
7 import java.nio.ByteBuffer;
8
9 import org.jscsi.exception.InternetSCSIException;
10 import org.jscsi.parser.BasicHeaderSegment;
11 import org.jscsi.parser.ProtocolDataUnit;
12 import org.jscsi.parser.scsi.SCSICommandParser;
13 import org.jscsi.parser.scsi.SCSIResponseParser.ServiceResponse;
14 import org.jscsi.parser.scsi.SCSIStatus;
15 import org.jscsi.target.connection.TargetPduFactory;
16 import org.jscsi.target.connection.phase.TargetFullFeaturePhase;
17 import org.jscsi.target.scsi.ScsiResponseDataSegment;
18 import org.jscsi.target.scsi.cdb.Read10Cdb;
19 import org.jscsi.target.scsi.cdb.Read6Cdb;
20 import org.jscsi.target.scsi.cdb.ReadCdb;
21 import org.jscsi.target.scsi.cdb.ScsiOperationCode;
22 import org.jscsi.target.settings.SettingsException;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26
27
28
29
30
31
32 public class ReadStage extends ReadOrWriteStage {
33
34 private static final Logger LOGGER = LoggerFactory.getLogger(ReadStage.class);
35
36 public ReadStage (final TargetFullFeaturePhase targetFullFeaturePhase) {
37 super(targetFullFeaturePhase);
38 }
39
40 @Override
41 public void execute (ProtocolDataUnit pdu) throws IOException , InterruptedException , InternetSCSIException , SettingsException {
42
43
44
45 final boolean immediateData = settings.getImmediateData();
46
47 if (LOGGER.isDebugEnabled()) {
48 LOGGER.debug("immediateData = " + immediateData);
49 LOGGER.debug("maxRecvDataSegmentLength = " + settings.getMaxRecvDataSegmentLength());
50 }
51
52
53 BasicHeaderSegment bhs = pdu.getBasicHeaderSegment();
54 SCSICommandParser parser = (SCSICommandParser) bhs.getParser();
55 final int initiatorTaskTag = bhs.getInitiatorTaskTag();
56
57
58 ReadCdb cdb;
59 final ScsiOperationCode scsiOpCode = ScsiOperationCode.valueOf(parser.getCDB().get(0));
60 if (scsiOpCode == ScsiOperationCode.READ_10)
61 cdb = new Read10Cdb(parser.getCDB());
62 else if (scsiOpCode == ScsiOperationCode.READ_6)
63 cdb = new Read6Cdb(parser.getCDB());
64 else {
65
66
67 throw new InternetSCSIException("wrong SCSI Operation Code " + scsiOpCode + " in ReadStage");
68 }
69
70
71 checkOverAndUnderflow(cdb);
72
73
74 if (cdb.getIllegalFieldPointers() != null) {
75
76
77 LOGGER.debug("illegal field in Read CDB");
78
79
80 final ProtocolDataUnit responsePdu = createFixedFormatErrorPdu(cdb.getIllegalFieldPointers(),
81 initiatorTaskTag, parser.getExpectedDataTransferLength());
82 connection.sendPdu(responsePdu);
83 return;
84 }
85
86 final int totalTransferLength = VIRTUAL_BLOCK_SIZE * cdb.getTransferLength();
87 final long storageOffset = VIRTUAL_BLOCK_SIZE * cdb.getLogicalBlockAddress();
88
89 if (LOGGER.isDebugEnabled()) {
90 LOGGER.debug("cdb.getLogicalBlockAddress() = " + cdb.getLogicalBlockAddress());
91 LOGGER.debug("blockSize = " + VIRTUAL_BLOCK_SIZE);
92 LOGGER.debug("totalTransferLength = " + totalTransferLength);
93 LOGGER.debug("expectedDataSegmentLength = " + parser.getExpectedDataTransferLength());
94 }
95
96
97
98 int bytesSent = 0;
99 int dataSequenceNumber = 0;
100 byte[] dataSegmentArray = null;
101 ByteBuffer dataSegment = null;
102 ProtocolDataUnit responsePdu;
103
104
105
106
107 if (bytesSent < totalTransferLength - settings.getMaxRecvDataSegmentLength()) {
108
109
110
111 dataSegmentArray = connection.getDataInArray(settings.getMaxRecvDataSegmentLength());
112 dataSegment = ByteBuffer.wrap(dataSegmentArray);
113 }
114
115 while (bytesSent < totalTransferLength - settings.getMaxRecvDataSegmentLength()) {
116
117
118 session.getStorageModule().read(dataSegmentArray, storageOffset + bytesSent);
119
120
121 responsePdu = TargetPduFactory.createDataInPdu(false,
122
123
124
125
126
127 false,
128
129 false,
130 false,
131 false,
132 SCSIStatus.GOOD,
133 0L,
134 initiatorTaskTag, 0xffffffff,
135 dataSequenceNumber,
136 bytesSent,
137 0,
138 dataSegment);
139
140 connection.sendPdu(responsePdu);
141
142
143 ++dataSequenceNumber;
144 bytesSent += settings.getMaxRecvDataSegmentLength();
145 }
146
147
148
149
150
151
152
153
154
155 final int bytesRemaining = totalTransferLength - bytesSent;
156 dataSegmentArray = connection.getDataInArray(bytesRemaining);
157 session.getStorageModule().read(dataSegmentArray, storageOffset + bytesSent);
158 dataSegment = ByteBuffer.wrap(dataSegmentArray);
159
160
161 responsePdu = TargetPduFactory.createDataInPdu(true,
162
163
164
165 false,
166
167 false,
168 false,
169 immediateData,
170 SCSIStatus.GOOD,
171 0L,
172 initiatorTaskTag, 0xffffffff,
173 dataSequenceNumber,
174 bytesSent,
175 0,
176 dataSegment);
177
178 LOGGER.debug("sending last Data-In PDU");
179 connection.sendPdu(responsePdu);
180
181
182 if (!immediateData) {
183
184 responsePdu = TargetPduFactory.createSCSIResponsePdu(false,
185 false,
186 false,
187 false,
188 ServiceResponse.COMMAND_COMPLETED_AT_TARGET,
189 SCSIStatus.GOOD,
190 initiatorTaskTag,
191 0,
192 0,
193 0,
194 0,
195 ScsiResponseDataSegment.EMPTY_DATA_SEGMENT);
196
197
198 LOGGER.debug("sending SCSI Response PDU");
199 connection.sendPdu(responsePdu);
200 }
201
202 }
203
204 }