Coverage Report - org.jscsi.target.connection.stage.fullfeature.TargetFullFeatureStage
 
Classes in this File Line Coverage Branch Coverage Complexity
TargetFullFeatureStage
0%
0/26
0%
0/14
1.2
 
 1  
 package org.jscsi.target.connection.stage.fullfeature;
 2  
 
 3  
 import java.io.IOException;
 4  
 import java.nio.ByteBuffer;
 5  
 
 6  
 import org.jscsi.exception.InternetSCSIException;
 7  
 import org.jscsi.parser.ProtocolDataUnit;
 8  
 import org.jscsi.parser.scsi.SCSIResponseParser;
 9  
 import org.jscsi.parser.scsi.SCSIStatus;
 10  
 import org.jscsi.target.connection.TargetPduFactory;
 11  
 import org.jscsi.target.connection.phase.TargetFullFeaturePhase;
 12  
 import org.jscsi.target.connection.stage.TargetStage;
 13  
 import org.jscsi.target.scsi.IResponseData;
 14  
 import org.jscsi.target.scsi.ScsiResponseDataSegment;
 15  
 import org.jscsi.target.scsi.sense.AdditionalSenseBytes;
 16  
 import org.jscsi.target.scsi.sense.AdditionalSenseCodeAndQualifier;
 17  
 import org.jscsi.target.scsi.sense.ErrorType;
 18  
 import org.jscsi.target.scsi.sense.FixedFormatSenseData;
 19  
 import org.jscsi.target.scsi.sense.SenseKey;
 20  
 import org.jscsi.target.scsi.sense.information.FourByteInformation;
 21  
 import org.jscsi.target.scsi.sense.senseDataDescriptor.senseKeySpecific.FieldPointerSenseKeySpecificData;
 22  
 
 23  
 /**
 24  
  * This class is an abstract super-class for stages of the {@link TargetFullFeaturePhase}.
 25  
  * 
 26  
  * @see TargetStage
 27  
  * @author Andreas Ergenzinger
 28  
  */
 29  
 public abstract class TargetFullFeatureStage extends TargetStage {
 30  
 
 31  
     /**
 32  
      * The abstract constructor.
 33  
      * 
 34  
      * @param targetFullFeaturePhase
 35  
      *            the phase this stage is a part of
 36  
      */
 37  
     public TargetFullFeatureStage(TargetFullFeaturePhase targetFullFeaturePhase) {
 38  0
         super(targetFullFeaturePhase);
 39  0
     }
 40  
 
 41  
     /**
 42  
      * Creates a PDU with {@link FixedFormatSenseData} that must be sent to the initiator after receiving a
 43  
      * Command
 44  
      * Descriptor Block with an illegal field.
 45  
      * 
 46  
      * @param senseKeySpecificData
 47  
      *            contains a list of all illegal fields
 48  
      * @param additionalSenseCodeAndQualifier
 49  
      *            provides more specific information about the cause of the check condition
 50  
      * @param initiatorTaskTag
 51  
      *            used by the initiator to identify the task
 52  
      * @param expectedDataTransferLength
 53  
      *            the amount of payload data expected by the initiator (i.e. allocated buffer
 54  
      *            space)
 55  
      * @return the error PDU
 56  
      */
 57  
     protected static final ProtocolDataUnit createFixedFormatErrorPdu(
 58  
         final FieldPointerSenseKeySpecificData[] senseKeySpecificData,
 59  
         final AdditionalSenseCodeAndQualifier additionalSenseCodeAndQualifier, final int initiatorTaskTag,
 60  
         final int expectedDataTransferLength) {
 61  
 
 62  
         // create the whole sense data
 63  0
         FixedFormatSenseData senseData = new FixedFormatSenseData(false,// valid
 64  
             ErrorType.CURRENT,// error type
 65  
             false,// file mark
 66  
             false,// end of medium
 67  
             false,// incorrect length indicator
 68  
             SenseKey.ILLEGAL_REQUEST,// sense key
 69  
             new FourByteInformation(),// information
 70  
             new FourByteInformation(),// command specific information
 71  
             additionalSenseCodeAndQualifier,// additional sense code and
 72  
                                             // qualifier
 73  
             (byte)0,// field replaceable unit code
 74  
             senseKeySpecificData[0],// sense key specific data, only report
 75  
                                     // first problem
 76  
             new AdditionalSenseBytes());// additional sense bytes
 77  
 
 78  
         // keep only the part of the sense data that will be sent
 79  0
         final ScsiResponseDataSegment dataSegment =
 80  
             new ScsiResponseDataSegment(senseData, expectedDataTransferLength);
 81  0
         final int senseDataSize = senseData.size();
 82  
 
 83  
         // calculate residuals and flags
 84  0
         final int residualCount = Math.abs(expectedDataTransferLength - senseDataSize);
 85  0
         final boolean residualOverflow = expectedDataTransferLength < senseDataSize;
 86  0
         final boolean residualUnderflow = expectedDataTransferLength > senseDataSize;
 87  
 
 88  
         // create and return PDU
 89  0
         return TargetPduFactory.createSCSIResponsePdu(false,// bidirectionalReadResidualOverflow
 90  
             false,// bidirectionalReadResidualUnderflow
 91  
             residualOverflow,// residualOverflow
 92  
             residualUnderflow,// residualUnderflow,
 93  
             SCSIResponseParser.ServiceResponse.COMMAND_COMPLETED_AT_TARGET,// response,
 94  
             SCSIStatus.CHECK_CONDITION,// status,
 95  
             initiatorTaskTag,// initiatorTaskTag,
 96  
             0,// snackTag
 97  
             0,// expectedDataSequenceNumber
 98  
             0,// bidirectionalReadResidualCount
 99  
             residualCount,// residualCount
 100  
             dataSegment);// data segment
 101  
     }
 102  
 
 103  
     /**
 104  
      * Creates a PDU with {@link FixedFormatSenseData} that must be sent to the initiator after receiving a
 105  
      * Command
 106  
      * Descriptor Block with an illegal field, which requires the the additional sense code
 107  
      * {@link AdditionalSenseCodeAndQualifier#INVALID_FIELD_IN_CDB}.
 108  
      * 
 109  
      * @param senseKeySpecificData
 110  
      *            contains a list of all illegal fields
 111  
      * @param initiatorTaskTag
 112  
      *            used by the initiator to identify the task
 113  
      * @param expectedDataTransferLength
 114  
      *            the amount of payload data expected by the initiator (i.e. allocated buffer
 115  
      *            space)
 116  
      * @return the error PDU
 117  
      */
 118  
     protected static final ProtocolDataUnit createFixedFormatErrorPdu(
 119  
         final FieldPointerSenseKeySpecificData[] senseKeySpecificData, final int initiatorTaskTag,
 120  
         final int expectedDataTransferLength) {
 121  0
         return createFixedFormatErrorPdu(senseKeySpecificData,
 122  
             AdditionalSenseCodeAndQualifier.INVALID_FIELD_IN_CDB, initiatorTaskTag,
 123  
             expectedDataTransferLength);
 124  
     }
 125  
 
 126  
     /**
 127  
      * Creates a SCSI Response PDU with a length zero data segment. Objects created with this method can be
 128  
      * used as
 129  
      * replies in task terminating with {@link SCSIStatus#GOOD} which do not require additional data to be
 130  
      * transfered,
 131  
      * or for creating follow-up PDU with {@link SCSIStatus#CHECK_CONDITION} status sent after Data-In PDUs
 132  
      * with sense
 133  
      * data.
 134  
      * 
 135  
      * @param status
 136  
      *            the SCSI status of the task
 137  
      * @param initiatorTaskTag
 138  
      *            used by the initiator to identify the task
 139  
      * @param expectedDataTransferLength
 140  
      *            total amount of payload data in bytes expected by the initiator
 141  
      * @param responseDataSize
 142  
      *            actual amount of payload data in bytes sent by the target
 143  
      * @return the SCSI Response PDU
 144  
      */
 145  
     protected static final ProtocolDataUnit createScsiResponsePdu(final SCSIStatus status,
 146  
         final int initiatorTaskTag, final int expectedDataTransferLength, final int responseDataSize) {
 147  
 
 148  
         // calculate residuals and flags
 149  0
         final int residualCount = Math.abs(expectedDataTransferLength - responseDataSize);
 150  0
         final boolean residualOverflow = expectedDataTransferLength < responseDataSize;
 151  0
         final boolean residualUnderflow = expectedDataTransferLength > responseDataSize;
 152  
 
 153  0
         return TargetPduFactory.createSCSIResponsePdu(false,// bidirectionalReadResidualOverflow
 154  
             false,// bidirectionalReadResidualUnderflow
 155  
             residualOverflow,// residualOverflow,
 156  
             residualUnderflow,// residualUnderflow,
 157  
             SCSIResponseParser.ServiceResponse.COMMAND_COMPLETED_AT_TARGET,// response
 158  
             status,// status
 159  
             initiatorTaskTag,// initiatorTaskTag
 160  
             0,// snackTag
 161  
             0,// expectedDataSequenceNumber
 162  
             0,// bidirectionalReadResidualCount
 163  
             residualCount,// residualCount
 164  
             ScsiResponseDataSegment.EMPTY_DATA_SEGMENT);// data segment
 165  
     }
 166  
 
 167  
     /**
 168  
      * Sends a two byte sequence of a Data-In and a SCSI Response PDU with the specified <i>responseData</i>
 169  
      * payload to
 170  
      * the initiator.
 171  
      * 
 172  
      * @param initiatorTaskTag
 173  
      *            used by the initiator to identify the task
 174  
      * @param expectedDataTransferLength
 175  
      *            the total amount of payload data in bytes expected by the initiator
 176  
      *            <p>
 177  
      *            The method might throw exceptions during PDU serialization and sending.
 178  
      * @param responseData
 179  
      *            the data requested by the initiator
 180  
      * @throws InterruptedException
 181  
      * @throws IOException
 182  
      * @throws InternetSCSIException
 183  
      */
 184  
     protected final void sendResponse(final int initiatorTaskTag, final int expectedDataTransferLength,
 185  
         final IResponseData responseData) throws InterruptedException, IOException, InternetSCSIException {
 186  
 
 187  
         // serialize all response data
 188  0
         final ByteBuffer fullBuffer = ByteBuffer.allocate(responseData.size());
 189  0
         responseData.serialize(fullBuffer, 0);
 190  
         
 191  
         // copy fullBuffer to buffer with size trimmed to
 192  
         // expectedDataTransferLength
 193  
         ByteBuffer trimmedBuffer;
 194  0
         if (fullBuffer.capacity() <= expectedDataTransferLength) {
 195  
             // no trimming
 196  0
             trimmedBuffer = fullBuffer;
 197  
         } else {
 198  0
             trimmedBuffer = ByteBuffer.allocate(expectedDataTransferLength);
 199  0
             trimmedBuffer.put(fullBuffer.array(),// source array
 200  
                 0,// offset in source
 201  
                 expectedDataTransferLength);// length
 202  
         }
 203  
 
 204  
         // coompute residual count and associated flags
 205  0
         final boolean residualOverflow = expectedDataTransferLength < fullBuffer.capacity();
 206  0
         final boolean residualUnderflow = expectedDataTransferLength > fullBuffer.capacity();
 207  0
         final int residualCount = Math.abs(expectedDataTransferLength - fullBuffer.capacity());
 208  
 
 209  
         // create and send PDU
 210  0
         ProtocolDataUnit pdu = TargetPduFactory.createDataInPdu(true,// finalFlag
 211  
             false,// acknowledgeFlag always false
 212  
             residualOverflow,// residualOverflowFlag x
 213  
             residualUnderflow,// residualUnderflowFlag x
 214  
             true,// statusFlag
 215  
             SCSIStatus.GOOD,// status, reserved
 216  
             0,// logicalUnitNumber reserved
 217  
             initiatorTaskTag,// initiatorTaskTag
 218  
             -1,// targetTransferTag reserved
 219  
             0,// dataSequenceNumber
 220  
             0,// bufferOffset
 221  
             residualCount,// residualCount x
 222  
             trimmedBuffer);// dataSegment
 223  
 
 224  0
         connection.sendPdu(pdu);
 225  
         
 226  
         //        VirtualBox was not working with the success message sent via ScsiResponse ..
 227  
         //        Deactivated this method and set the data-in pdu up to take over the success
 228  
         //        notification.
 229  
         //        pdu = TargetPduFactory.createSCSIResponsePdu(false,// bidirectionalReadResidualOverflow
 230  
         //            false,// bidirectionalReadResidualUnderflow
 231  
         //            residualOverflow,// residualOverflow
 232  
         //            residualUnderflow,// residualUnderflow
 233  
         //            ServiceResponse.COMMAND_COMPLETED_AT_TARGET,// response
 234  
         //            SCSIStatus.GOOD,// status
 235  
         //            initiatorTaskTag, 0,// snackTag, reserved
 236  
         //            0,// expectedDataSequenceNumber
 237  
         //            0,// bidirectionalReadResidualCount
 238  
         //            residualCount,// residualCount
 239  
         //            ScsiResponseDataSegment.EMPTY_DATA_SEGMENT);// scsiResponseDataSegment
 240  
         //
 241  
         //        connection.sendPdu(pdu);
 242  
 
 243  0
     }
 244  
 }