/** * Copyright (c) 2012, University of Konstanz, Distributed Systems Group * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the University of Konstanz nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jscsi.parser.scsi; import java.nio.ByteBuffer; import org.jscsi.utils.ByteBufferCache; /** * <h1>SCSICommandDescriptorBlockParser</h1> * <p/> * This class generates a SCSI Command Descriptor Block. * * @author Volker Wildi */ public final class SCSICommandDescriptorBlockParser { /** * @author Volker Wildi */ // private static enum GroupCode { // /** */ // SIX_BYTE_COMMAND((byte) 0x06), // /** */ // TEN_BYTE_COMMAND((byte) 0x0A), // /** */ // TWELVE_BYTE_COMMAND((byte) 0x0C), // /** */ // SIXTEEN_BYTE_COMMAND((byte) 0x10), // /** */ // VENDOR_SPECIFIC((byte) 0x00); // // private byte value; // // private static ByteObjectOpenHashMap<GroupCode> mapping; // // private GroupCode(final byte newValue) { // // if (GroupCode.mapping == null) { // GroupCode.mapping = new ByteObjectOpenHashMap<GroupCode>(values().length); // } // // GroupCode.mapping.put(newValue, this); // value = newValue; // } // // /** // * Returns the value of this enumeration. // * // * @return The value of this enumeration. // */ // public final byte value() { // // return value; // } // // /** // * Returns the constant defined for the given <code>value</code>. // * // * @param value // * The value to search for. // * @return The constant defined for the given <code>value</code>. Or // * <code>null</code>, if this value is not defined by this // * enumeration. // */ // public static final GroupCode valueOf(final byte value) { // // return GroupCode.mapping.get(value); // } // // } // // // // -------------------------------------------------------------------------- // // // -------------------------------------------------------------------------- /** The default or minimal length of a CDB is <code>16</code> bytes. */ private static final int DEFAULT_CDB_LENGTH = 16; // private static final int STANDARD_BYTES = 2; // // private static final int GROUP_CODE_SHIFT = 5; // // private static final byte GROUP_CODE_MASK = (byte) 0xE0; // // private static final byte COMMAND_CODE_MASK = 0x1F; // // private static final byte NACA_FLAG_MASK = 0x04; // // private static final byte LINK_FLAG_MASK = 0x01; // // // // -------------------------------------------------------------------------- // // // -------------------------------------------------------------------------- // // private byte opCode; // // private ByteBuffer specificParameters; // // private byte control; // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- private SCSICommandDescriptorBlockParser() { super(); } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- // public final int serialize(final ByteBuffer dst, final int offset) { // // dst.position(offset); // // if (dst.remaining() < getTotalLength()) { // throw new IllegalArgumentException("Destination buffer is too small."); // } // // dst.put(serializeOperationCodeByte()); // // for (byte b = 0; b < getLength().value(); b++) { // dst.put(serializeSpecificParameters()); // } // // dst.put(serializeControlByte()); // // return dst.position() - offset; // } // // public final int deserialize(final ByteBuffer src, final int offset) { // // src.position(offset); // // if (src.remaining() < DEFAULT_CDB_LENGTH) { // throw new IllegalArgumentException("Source buffer is too small."); // } // // deserializeOperationCodeByte(src.get()); // // specificParameters = ByteBufferCache.allocate(getLength().value()); // for (byte b = 0; b < getLength().value(); b++) { // deserializeSpecificParameters(src.get()); // } // // deserializeControlByte(src.get()); // // return src.position() - offset; // } // // // // -------------------------------------------------------------------------- // // // -------------------------------------------------------------------------- // // public final byte getGroupCode() { // // return (byte) (opCode & GROUP_CODE_MASK); // } // // public final byte getCommandCode() { // // return (byte) (opCode & COMMAND_CODE_MASK); // } // // public final boolean isLinkFlag() { // // return Utils.isBitSet(control & LINK_FLAG_MASK); // } // // public final void setLinkFlag(final boolean newLinkFlag) { // // if (newLinkFlag) { // control |= LINK_FLAG_MASK; // } else { // control &= ~LINK_FLAG_MASK; // } // } // // public final boolean isNACAFlag() { // // return Utils.isBitSet(control & NACA_FLAG_MASK); // } // // public final void setNacaFlag(final boolean newNACAFlag) { // // if (newNACAFlag) { // control |= NACA_FLAG_MASK; // } else { // control &= ~NACA_FLAG_MASK; // } // } // // public final GroupCode getLength() { // // GroupCode groupCode; // // switch (getGroupCode()) { // case 0x00: // groupCode = GroupCode.SIX_BYTE_COMMAND; // break; // // case 0x01: // case 0x02: // groupCode = GroupCode.TEN_BYTE_COMMAND; // break; // // case 0x04: // groupCode = GroupCode.SIXTEEN_BYTE_COMMAND; // break; // // case 0x05: // groupCode = GroupCode.TWELVE_BYTE_COMMAND; // break; // // case 0x06: // case 0x07: // groupCode = GroupCode.VENDOR_SPECIFIC; // // default: // groupCode = null; // } // // return groupCode; // } // // // public final void setLength(final GroupCode groupCode) { // // WRONG // // opCode |= groupCode.value() << GROUP_CODE_SHIFT; // // } // // public final int getTotalLength() { // // return getLength().value() + STANDARD_BYTES; // } // // // // -------------------------------------------------------------------------- // // // -------------------------------------------------------------------------- // // protected void deserializeOperationCodeByte(final byte b) { // // opCode = b; // } // // protected void deserializeSpecificParameters(final byte b) { // // specificParameters.put(b); // } // // protected void deserializeControlByte(final byte b) { // // control = b; // } // // protected byte serializeOperationCodeByte() { // // return opCode; // } // // protected byte serializeSpecificParameters() { // // return specificParameters.get(); // } // // protected byte serializeControlByte() { // // return control; // } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** The Read Operation Code. */ private static final byte READ_OP_CODE = 0x28; /** The Read Capacity Operation Code. */ private static final byte READ_CAPACITY_OP_CODE = 0x25; /** The Write Operation Code. */ private static final byte WRITE_OP_CODE = 0x2A; /** The byte index of the logical block address information. */ private static final int LOGICAL_BLOCK_ADDRESS_OFFSET = 2; /** The byte index of the transfer length information. */ private static final int TRANSFER_LENGTH_OFFSET = 7; /** * Creates the Command Descriptor Block for a Read Message. * * @param logicalBlockAddress * The Logical Block Address to begin the read operation. * @param transferLength * The transfer length field specifies the number of contiguous * logical blocks of data to be transferred. A transfer length of * zero indicates that <code>256</code> logical blocks shall be * transferred. Any other value indicates the number of logical * blocks that shall be transferred. * @return A <code>ByteBuffer</code> object with the above data. */ public static final ByteBuffer createReadMessage(final int logicalBlockAddress, final short transferLength) { return createReadWriteMessage(READ_OP_CODE, logicalBlockAddress, transferLength); } /** * Creates the Command Descriptor Block for a Write Message. * * @param logicalBlockAddress * The Logical Block Address to begin the read operation. * @param transferLength * The transfer length field specifies the number of contiguous * logical blocks of data to be transferred. A transfer length of * zero indicates that 256 logical blocks shall be transferred. * Any other value indicates the number of logical blocks that * shall be transferred. * @return A <code>ByteBuffer</code> object with the above data. */ public static final ByteBuffer createWriteMessage(final int logicalBlockAddress, final short transferLength) { return createReadWriteMessage(WRITE_OP_CODE, logicalBlockAddress, transferLength); } /** * Creates the Command Descriptor Block for a given Operation Message. * * @param opCode * The Operation Code. * @param logicalBlockAddress * The Logical Block Address to begin the read operation. * @param transferLength * The transfer length field specifies the number of contiguous * logical blocks of data to be transferred. A transfer length of * zero indicates that 256 logical blocks shall be transferred. * Any other value indicates the number of logical blocks that * shall be transferred. * @return A <code>ByteBuffer</code> object with the above data. */ private static final ByteBuffer createReadWriteMessage(final byte opCode, final int logicalBlockAddress, final short transferLength) { ByteBuffer cdb = ByteBufferCache.allocate(DEFAULT_CDB_LENGTH); // operation code cdb.put(opCode); // logical block address cdb.position(LOGICAL_BLOCK_ADDRESS_OFFSET); cdb.putInt(logicalBlockAddress); // set transfer length cdb.position(TRANSFER_LENGTH_OFFSET); cdb.putShort(transferLength); cdb.rewind(); return cdb; } /** * Creates the Command Descriptor Block for a Read Capacity Message. * * @return A <code>ByteBuffer</code> object with the above data. */ public static final ByteBuffer createReadCapacityMessage() { ByteBuffer cdb = ByteBufferCache.allocate(DEFAULT_CDB_LENGTH); // operation code cdb.put(READ_CAPACITY_OP_CODE); cdb.rewind(); return cdb; } }