Coverage Report - org.jscsi.target.scsi.cdb.CommandDescriptorBlock
 
Classes in this File Line Coverage Branch Coverage Complexity
CommandDescriptorBlock
0%
0/49
0%
0/25
3
CommandDescriptorBlock$1
0%
0/1
N/A
3
 
 1  
 package org.jscsi.target.scsi.cdb;
 2  
 
 3  
 
 4  
 import java.nio.ByteBuffer;
 5  
 
 6  
 import org.jscsi.parser.scsi.SCSICommandParser;
 7  
 import org.jscsi.target.scsi.sense.AdditionalSenseCodeAndQualifier;
 8  
 import org.jscsi.target.scsi.sense.SenseData;
 9  
 import org.jscsi.target.scsi.sense.SenseKey;
 10  
 import org.jscsi.target.scsi.sense.senseDataDescriptor.senseKeySpecific.FieldPointerSenseKeySpecificData;
 11  
 import org.jscsi.target.util.BitManip;
 12  
 
 13  
 
 14  
 /**
 15  
  * An abstract class for accessing the variables common to Command Descriptor Blocks of all sizes.
 16  
  * <p>
 17  
  * A Command Descriptor Blocks is a blocks of multiple bytes that contains a {@link ScsiOperationCode}, specifying a
 18  
  * command the SCSI initiator wants the SCSI target to perform and related fields, which determine details of the
 19  
  * ordered task.
 20  
  * <p>
 21  
  * Since all fields in the Control byte except for the Normal ACA bit are either reserved, obsolete, or vendor specific,
 22  
  * the NACA bit can be accessed directly from this class.
 23  
  * 
 24  
  * @author Andreas Ergenzinger
 25  
  */
 26  
 public abstract class CommandDescriptorBlock {
 27  
 
 28  
     /**
 29  
      * Not a CDB field. This array stores all {@link FieldPointerSenseKeySpecificData} that has to be sent back to the
 30  
      * SCSI initiator as a reaction to the CDB {@link ByteBuffer} passed during initialization of this
 31  
      * {@link CommandDescriptorBlock} instance.
 32  
      * <p>
 33  
      * If, during the parsing process, an illegal value is detected, the array will be initialized and a
 34  
      * {@link FieldPointerSenseKeySpecificData} object, specifying the position of the illegal field, will be added.
 35  
      */
 36  0
     private FieldPointerSenseKeySpecificData[] illegalFieldPointers = null;
 37  
 
 38  
     /**
 39  
      * Determines which command to perform.
 40  
      */
 41  
     private ScsiOperationCode scsiOperationCode;
 42  
 
 43  
     /**
 44  
      * Specifies if Normal ACA shall be used. A value of <code>true</code> is not supported by the jSCSI Target.
 45  
      */
 46  
     private boolean normalAutoContingentAllegiance;
 47  
 
 48  
     /**
 49  
      * The abstract constructor.
 50  
      * <p>
 51  
      * Deserializes the first byte containing the SCSI Operation Code and the Control byte.
 52  
      * <p>
 53  
      * The passed {@link ByteBuffer} parameter <b>must</b> have a capacity &ge; the length of the specific command
 54  
      * descriptor block. Since this is assured by the {@link SCSICommandParser#getCDB()} method, which always returns
 55  
      * {@link ByteBuffer} objects with capacity 16, no checks will be performed.
 56  
      * 
 57  
      * @param buffer contains the serialized CDB starting at index position zero
 58  
      */
 59  0
     public CommandDescriptorBlock (ByteBuffer buffer) {
 60  
         // SCSI OpCode
 61  0
         scsiOperationCode = ScsiOperationCode.valueOf(buffer.get(0));
 62  0
         if (scsiOperationCode == null) // unsupported OpCode
 63  0
         addIllegalFieldPointer(0);
 64  
         /*
 65  
          * The above if block should never be entered, since unsupported operation codes in the CDB would have been
 66  
          * discovered during TargetFullFeatureStage selection in TargetFullFeaturePhase.execute().
 67  
          */
 68  
 
 69  
         // Control (NACA bit, all other fields are obsolete, reserved, or vendor
 70  
         // specific)
 71  0
         final CdbType cdbType = scsiOperationCode.getCdbType();
 72  
         int controlByteIndex;
 73  
 
 74  0
         switch (cdbType) {
 75  
             case SIX_BYTE_COMMANDS :
 76  0
                 controlByteIndex = 5;
 77  0
                 break;
 78  
             case TEN_BYTE_COMMANDS :
 79  0
                 controlByteIndex = 9;
 80  0
                 break;
 81  
             case TWELVE_BYTE_COMMANDS :
 82  0
                 controlByteIndex = 11;
 83  0
                 break;
 84  
             case SIXTEEN_BYTE_COMMANDS :
 85  0
                 controlByteIndex = 15;
 86  0
                 break;
 87  
             default :
 88  0
                 controlByteIndex = -1;
 89  
                 /*
 90  
                  * Would lead to ArrayOutOfBoundsException, however, this will not happen, since unsupported group codes
 91  
                  * will be filtered in TargetFullFeaturePhase.execute() (see above).
 92  
                  */
 93  
         }
 94  
 
 95  0
         normalAutoContingentAllegiance = BitManip.getBit(buffer.get(controlByteIndex), 2);
 96  0
         if (normalAutoContingentAllegiance) {// normalACA is not supported
 97  0
             addIllegalFieldPointer(controlByteIndex, 2);
 98  
         }
 99  0
     }
 100  
 
 101  
     public final ScsiOperationCode getScsiOperationCode () {
 102  0
         return scsiOperationCode;
 103  
     }
 104  
 
 105  
     /**
 106  
      * The NACA (Normal ACA) bit specifies whether an auto contingent allegiance (ACA) is established if the command
 107  
      * terminates with CHECK CONDITION status. A NACA bit set to one specifies that an ACA shall be established. A NACA
 108  
      * bit set to zero specifies that an ACA shall not be established.
 109  
      * 
 110  
      * @return <code>true</code> if the Normal ACA bit in the CDB's Control byte is set and <code>false</code> if it is
 111  
      *         not.
 112  
      */
 113  
     public final boolean isNormalACA () {
 114  0
         return normalAutoContingentAllegiance;
 115  
     }
 116  
 
 117  
     /**
 118  
      * Adds an instance {@link FieldPointerSenseKeySpecificData}, which specifies an illegal field by the position of
 119  
      * its first byte, to {@link #illegalFieldPointers}.
 120  
      * 
 121  
      * @param byteNumber index of the first byte of the illegal field
 122  
      */
 123  
     protected final void addIllegalFieldPointer (int byteNumber) {
 124  0
         final FieldPointerSenseKeySpecificData fp = new FieldPointerSenseKeySpecificData(true,// senseKeySpecificDataValid
 125  
         true,// commandData (i.e. invalid field in CDB)
 126  
         false,// bitPointerValid
 127  
         0,// bitPointer
 128  
         byteNumber);// fieldPointer
 129  0
         addIllegalFieldPointer(fp);
 130  0
     }
 131  
 
 132  
     /**
 133  
      * Adds an instance {@link FieldPointerSenseKeySpecificData}, which specifies an illegal field by the position of
 134  
      * its first byte and its first bit, to {@link #illegalFieldPointers}.
 135  
      * 
 136  
      * @param byteNumber index of the first byte of the illegal field
 137  
      * @param bitNumber index of the first bit of the illegal field
 138  
      */
 139  
     protected final void addIllegalFieldPointer (int byteNumber, int bitNumber) {
 140  0
         FieldPointerSenseKeySpecificData fp = new FieldPointerSenseKeySpecificData(true,// senseKeySpecificDataValid
 141  
         true,// commandData (i.e. invalid field in CDB)
 142  
         true,// bitPointerValid
 143  
         bitNumber,// bitPointer
 144  
         byteNumber);// fieldPointer
 145  0
         addIllegalFieldPointer(fp);
 146  0
     }
 147  
 
 148  
     /**
 149  
      * Adds a {@link FieldPointerSenseKeySpecificData} object to {@link #illegalFieldPointers}. Initializes and grows
 150  
      * the array if necessary.
 151  
      * 
 152  
      * @param illegalFieldPointer the object to add
 153  
      */
 154  
     private final void addIllegalFieldPointer (final FieldPointerSenseKeySpecificData illegalFieldPointer) {
 155  
         // grow array?
 156  0
         if (illegalFieldPointers == null) illegalFieldPointers = new FieldPointerSenseKeySpecificData[10];
 157  0
         final int size = getIllegalFieldPointerSize();
 158  0
         if (size >= illegalFieldPointers.length) {
 159  
             // grow
 160  0
             FieldPointerSenseKeySpecificData[] temp = new FieldPointerSenseKeySpecificData[illegalFieldPointers.length + 1];
 161  0
             for (int i = 0; i < size; ++i) {
 162  0
                 temp[i] = illegalFieldPointers[i];
 163  
             }
 164  0
             illegalFieldPointers = temp;
 165  
         }
 166  
         // add new element
 167  0
         illegalFieldPointers[size] = illegalFieldPointer;
 168  0
     }
 169  
 
 170  
     /**
 171  
      * Returns the number of elements stored in {@link #illegalFieldPointers}.
 172  
      * 
 173  
      * @return the number of elements stored in {@link #illegalFieldPointers}
 174  
      */
 175  
     private final int getIllegalFieldPointerSize () {
 176  0
         if (illegalFieldPointers == null) return 0;
 177  0
         int size = 0;
 178  0
         while (size < illegalFieldPointers.length) {
 179  0
             if (illegalFieldPointers[size] != null)
 180  0
                 ++size;
 181  
             else
 182  
                 break;
 183  
         }
 184  0
         return size;
 185  
     }
 186  
 
 187  
     /**
 188  
      * Returns <code>null</code> if there were no illegal fields in the serialized CDB passed to the constructor, or an
 189  
      * array of appropriate {@link FieldPointerSenseKeySpecificData}, that have to be enclosed in the {@link SenseData}
 190  
      * returned to the initiator (with sense key {@link SenseKey#ILLEGAL_REQUEST} and additional sense code and sense
 191  
      * code qualifier {@link AdditionalSenseCodeAndQualifier#INVALID_FIELD_IN_CDB}).
 192  
      * 
 193  
      * @return <code>null</code> or an array of appropriate {@link FieldPointerSenseKeySpecificData}
 194  
      */
 195  
     public final FieldPointerSenseKeySpecificData[] getIllegalFieldPointers () {
 196  0
         if (illegalFieldPointers == null) return null;
 197  
         // returned trimmed array without null values
 198  0
         final int size = getIllegalFieldPointerSize();
 199  0
         FieldPointerSenseKeySpecificData[] result = new FieldPointerSenseKeySpecificData[size];
 200  0
         for (int i = 0; i < size; ++i) {
 201  0
             result[i] = illegalFieldPointers[i];
 202  
         }
 203  0
         return result;
 204  
     }
 205  
 }