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 }