Coverage Report - org.jscsi.target.connection.stage.fullfeature.ReadStage
 
Classes in this File Line Coverage Branch Coverage Complexity
ReadStage
0%
0/54
0%
0/16
6
 
 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  
  * A stage for processing <code>READ (6)</code> and <code>READ (10)</code> SCSI commands.
 29  
  * 
 30  
  * @author Andreas Ergenzinger
 31  
  */
 32  
 public class ReadStage extends ReadOrWriteStage {
 33  
 
 34  0
     private static final Logger LOGGER = LoggerFactory.getLogger(ReadStage.class);
 35  
 
 36  
     public ReadStage (final TargetFullFeaturePhase targetFullFeaturePhase) {
 37  0
         super(targetFullFeaturePhase);
 38  0
     }
 39  
 
 40  
     @Override
 41  
     public void execute (ProtocolDataUnit pdu) throws IOException , InterruptedException , InternetSCSIException , SettingsException {
 42  
 
 43  
         // get relevant variables ...
 44  
         // ... from settings
 45  0
         final boolean immediateData = settings.getImmediateData();
 46  
 
 47  0
         if (LOGGER.isDebugEnabled()) {
 48  0
             LOGGER.debug("immediateData = " + immediateData);
 49  0
             LOGGER.debug("maxRecvDataSegmentLength = " + settings.getMaxRecvDataSegmentLength());
 50  
         }
 51  
 
 52  
         // ... and from the PDU
 53  0
         BasicHeaderSegment bhs = pdu.getBasicHeaderSegment();
 54  0
         SCSICommandParser parser = (SCSICommandParser) bhs.getParser();
 55  0
         final int initiatorTaskTag = bhs.getInitiatorTaskTag();
 56  
 
 57  
         // get the Read(6) or Read(10) CDB
 58  
         ReadCdb cdb;
 59  0
         final ScsiOperationCode scsiOpCode = ScsiOperationCode.valueOf(parser.getCDB().get(0));
 60  0
         if (scsiOpCode == ScsiOperationCode.READ_10)// most likely option first
 61  0
             cdb = new Read10Cdb(parser.getCDB());
 62  0
         else if (scsiOpCode == ScsiOperationCode.READ_6)
 63  0
             cdb = new Read6Cdb(parser.getCDB());
 64  
         else {
 65  
             // anything else wouldn't be good (programmer error)
 66  
             // close connection
 67  0
             throw new InternetSCSIException("wrong SCSI Operation Code " + scsiOpCode + " in ReadStage");
 68  
         }
 69  
 
 70  
         // check if requested blocks are out of bounds
 71  0
         checkOverAndUnderflow(cdb);
 72  
 
 73  
         // check illegal field pointers
 74  0
         if (cdb.getIllegalFieldPointers() != null) {
 75  
             // the command must fail
 76  
 
 77  0
             LOGGER.debug("illegal field in Read CDB");
 78  
 
 79  
             // create and send error PDU and leave stage
 80  0
             final ProtocolDataUnit responsePdu = createFixedFormatErrorPdu(cdb.getIllegalFieldPointers(),// senseKeySpecificData
 81  
                     initiatorTaskTag, parser.getExpectedDataTransferLength());
 82  0
             connection.sendPdu(responsePdu);
 83  0
             return;
 84  
         }
 85  
 
 86  0
         final int totalTransferLength = VIRTUAL_BLOCK_SIZE * cdb.getTransferLength();
 87  0
         final long storageOffset = VIRTUAL_BLOCK_SIZE * cdb.getLogicalBlockAddress();
 88  
 
 89  0
         if (LOGGER.isDebugEnabled()) {
 90  0
             LOGGER.debug("cdb.getLogicalBlockAddress() = " + cdb.getLogicalBlockAddress());
 91  0
             LOGGER.debug("blockSize = " + VIRTUAL_BLOCK_SIZE);
 92  0
             LOGGER.debug("totalTransferLength = " + totalTransferLength);
 93  0
             LOGGER.debug("expectedDataSegmentLength = " + parser.getExpectedDataTransferLength());
 94  
         }
 95  
 
 96  
         // *** start sending ***
 97  
         // initialize counters and data segment buffer
 98  0
         int bytesSent = 0;
 99  0
         int dataSequenceNumber = 0;
 100  0
         byte[] dataSegmentArray = null;
 101  0
         ByteBuffer dataSegment = null;
 102  
         ProtocolDataUnit responsePdu;
 103  
 
 104  
         // *** send up to last but one Data-In PDU ***
 105  
         // (with DataSegmentSize == MaxRecvDataSegmentLength)
 106  
 
 107  0
         if (bytesSent < totalTransferLength - settings.getMaxRecvDataSegmentLength()) {
 108  
             /*
 109  
              * Initialize dataSegmentArray and dataSegment with MaxRecvDataSegmentLength bytes.
 110  
              */
 111  0
             dataSegmentArray = connection.getDataInArray(settings.getMaxRecvDataSegmentLength());
 112  0
             dataSegment = ByteBuffer.wrap(dataSegmentArray);
 113  
         }
 114  
 
 115  0
         while (bytesSent < totalTransferLength - settings.getMaxRecvDataSegmentLength()) {
 116  
 
 117  
             // get data and prepare data segment
 118  0
             session.getStorageModule().read(dataSegmentArray, storageOffset + bytesSent);
 119  
 
 120  
             // create and send PDU
 121  0
             responsePdu = TargetPduFactory.createDataInPdu(false,// finalFlag,
 122  
                                                                  // not the last
 123  
                                                                  // PDU with
 124  
                                                                  // data payload
 125  
                                                                  // in the
 126  
                                                                  // sequence
 127  
                     false,// acknowledgeFlag, ErrorRecoveryLevel == 0, so we
 128  
                           // never do that
 129  
                     false,// residualOverflowFlag
 130  
                     false,// residualUnderflowFlag
 131  
                     false,// statusFlag
 132  
                     SCSIStatus.GOOD,// status, actually reserved i.e. 0x0
 133  
                     0L,// logicalUnitNumber, reserved
 134  
                     initiatorTaskTag, 0xffffffff,// targetTransferTag
 135  
                     dataSequenceNumber,// dataSequenceNumber
 136  
                     bytesSent,// bufferOffset
 137  
                     0,// residualCount
 138  
                     dataSegment);
 139  
 
 140  0
             connection.sendPdu(responsePdu);
 141  
 
 142  
             // increment counters
 143  0
             ++dataSequenceNumber;
 144  0
             bytesSent += settings.getMaxRecvDataSegmentLength();
 145  
         }
 146  
 
 147  
         /*
 148  
          * If ImmediateData=Yes has been negotiated, then a phase collapse has to take place, i.e. the status is sent in
 149  
          * the last Data-In PDU. Otherwise a separate SCSI Response PDU must follow.
 150  
          */
 151  
 
 152  
         // *** send last Data-In PDU ***
 153  
 
 154  
         // get data and prepare data segment
 155  0
         final int bytesRemaining = totalTransferLength - bytesSent;
 156  0
         dataSegmentArray = connection.getDataInArray(bytesRemaining);
 157  0
         session.getStorageModule().read(dataSegmentArray, storageOffset + bytesSent);
 158  0
         dataSegment = ByteBuffer.wrap(dataSegmentArray);
 159  
 
 160  
         // create and send PDU (with or without status)
 161  0
         responsePdu = TargetPduFactory.createDataInPdu(true,// finalFlag, last
 162  
                                                             // PDU in the
 163  
                                                             // sequence with
 164  
                                                             // data payload
 165  
                 false,// acknowledgeFlag, ErrorRecoveryLevel == 0, so we never
 166  
                       // do that
 167  
                 false,// residualOverflowFlag
 168  
                 false,// residualUnderflowFlag
 169  
                 immediateData,// statusFlag
 170  
                 SCSIStatus.GOOD,// status, or not (reserved if no status)
 171  
                 0L,// logicalUnitNumber, reserved
 172  
                 initiatorTaskTag, 0xffffffff,// targetTransferTag
 173  
                 dataSequenceNumber,// dataSequenceNumber
 174  
                 bytesSent,// bufferOffset
 175  
                 0,// residualCount
 176  
                 dataSegment);
 177  
 
 178  0
         LOGGER.debug("sending last Data-In PDU");
 179  0
         connection.sendPdu(responsePdu);
 180  
 
 181  
         // send SCSI Response PDU?
 182  0
         if (!immediateData) {
 183  
 
 184  0
             responsePdu = TargetPduFactory.createSCSIResponsePdu(false,// bidirectionalReadResidualOverflow
 185  
                     false,// bidirectionalReadResidualUnderflow
 186  
                     false,// residualOverflow
 187  
                     false,// residualUnderflow
 188  
                     ServiceResponse.COMMAND_COMPLETED_AT_TARGET,// response
 189  
                     SCSIStatus.GOOD,// status
 190  
                     initiatorTaskTag,// initiatorTaskTag
 191  
                     0,// snackTag, reserved
 192  
                     0,// expectedDataSequenceNumber, reserved
 193  
                     0,// bidirectionalReadResidualCount
 194  
                     0,// residualCount
 195  
                     ScsiResponseDataSegment.EMPTY_DATA_SEGMENT);// empty
 196  
                                                                 // ScsiResponseDataSegment
 197  
 
 198  0
             LOGGER.debug("sending SCSI Response PDU");
 199  0
             connection.sendPdu(responsePdu);
 200  
         }
 201  
 
 202  0
     }
 203  
 
 204  
 }