package org.jscsi.target.scsi.sense;
import java.nio.ByteBuffer;
import org.jscsi.target.scsi.sense.senseDataDescriptor.SenseDataDescriptor;
import org.jscsi.target.util.BitManip;
import org.jscsi.target.util.ReadWrite;
/**
* Instances of this class represent sense data using the descriptor format.
*
* @see SenseDataFormat#DESCRIPTOR
* @author Andreas Ergenzinger
*/
public final class DescriptorFormatSenseData extends SenseData {
/**
* The length in bytes of all fixed fields of descriptor format sense data.
*/
private static final int HEADER_LENGTH = 8;
/**
* The byte position of the ADDITIONAL SENSE CODE field.
*/
private static final int ADDITIONAL_SENSE_CODE_INDEX = 2;
/**
* The position of the first reserved byte.
*
* @see #RESERVED_BYTES_MAX_INDEX
*/
private static final int RESERVED_BYTES_MIN_INDEX = 4;
/**
* The position of the last reserved byte.
*
* @see #RESERVED_BYTES_MIN_INDEX
*/
private static final int RESERVED_BYTES_MAX_INDEX = 6;
/**
* The position of the ADDITIONAL SENSE LENGTH field.
*/
private static final int ADDITIONAL_SENSE_LENGTH_INDEX = 7;
/**
* All sense data descriptors that are a part of this sense data object.
*/
private final SenseDataDescriptor[] senseDataDescriptors;
/**
* The constructor.
*
* @param errorType
* the error type
* @param senseKey
* a general description of what caused the error
* @param additionalSenseCodeAndQualifier
* a more specific description of the error
* @param senseDataDescriptors
* more specific error information
*/
public DescriptorFormatSenseData(final ErrorType errorType, final SenseKey senseKey,
AdditionalSenseCodeAndQualifier additionalSenseCodeAndQualifier,
SenseDataDescriptor... senseDataDescriptors) {
super(errorType, SenseDataFormat.DESCRIPTOR, senseKey, additionalSenseCodeAndQualifier);
this.senseDataDescriptors = senseDataDescriptors;
}
public void serialize(ByteBuffer byteBuffer, int index) {
byteBuffer.position(index);
// response code and valid
byte b = (byte)getReponseCodeFor(errorType, SenseDataFormat.DESCRIPTOR);
b = BitManip.getByteWithBitSet(b, 7, false);// bit 7 is reserved
byteBuffer.put(b);// index
// sense key
b = (byte)(senseKey.getValue() & 15);
byteBuffer.put(b);// index + 1
// additional sense code and additional sense code qualifier
ReadWrite.writeTwoByteInt(byteBuffer, additionalSenseCodeAndQualifier.getValue(), index
+ ADDITIONAL_SENSE_CODE_INDEX);
// bytes 4-6 are reserved
for (int i = index + RESERVED_BYTES_MIN_INDEX; i < index + RESERVED_BYTES_MAX_INDEX; ++i)
byteBuffer.put(i, (byte)0);
// additional sense length
byteBuffer.put(index + ADDITIONAL_SENSE_LENGTH_INDEX, (byte)getAdditionalSenseLength());
// sense data descriptors
int descriptorIndex = HEADER_LENGTH;
for (int i = 0; i < senseDataDescriptors.length; ++i) {
if (senseDataDescriptors[i] != null) {
senseDataDescriptors[i].serialize(byteBuffer, descriptorIndex);
descriptorIndex += senseDataDescriptors[i].size();
}
}
}
/**
* Returns the value of the ADDITIONAL SENSE LENGTH field.
* <p>
* This is the total length of all included {@link SenseDataDescriptor} objects.
*
* @return the value of the ADDITIONAL SENSE LENGTH field
*/
private int getAdditionalSenseLength() {
int additionalSenseLength = 0;
if (senseDataDescriptors != null) {
for (int i = 0; i < senseDataDescriptors.length; ++i)
if (senseDataDescriptors[i] != null)
additionalSenseLength += senseDataDescriptors[i].size();
}
return additionalSenseLength;
}
public int size() {
return getAdditionalSenseLength()// is never negative
+ HEADER_LENGTH;
}
}