/** * 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.tmf; import org.jscsi.exception.InternetSCSIException; import org.jscsi.parser.BasicHeaderSegment; import org.jscsi.parser.Constants; import org.jscsi.parser.ProtocolDataUnit; import org.jscsi.parser.TargetMessageParser; import org.jscsi.parser.datasegment.DataSegmentFactory.DataSegmentFormat; import org.jscsi.utils.Utils; import com.carrotsearch.hppc.ByteObjectOpenHashMap; /** * This class parses a Task Management Function Response message defined in the * iSCSI Standard (RFC3720). * <p> * <h4>Task Management Actions on Task Sets</h4> The execution of ABORT TASK SET and CLEAR TASK SET Task * Management function requests consists of the following sequence of events in the specified order on each of * the entities. * <p> * The initiator: * <p> * <ol type="a"> * <li>Issues ABORT TASK SET/CLEAR TASK SET request.</li> * <li>Continues to respond to each target transfer tag received for the affected task set.</li> * <li>Receives any responses for the tasks in the affected task set (may process them as usual because they * are guaranteed to be valid).</li> * <li>Receives the task set management response, thus concluding all the tasks in the affected task set.</li> * </ol> * <p> * The target: * <p> * <ol type="a"> * <li>Receives the ABORT TASK SET/CLEAR TASK SET request.</li> * <li>Waits for all target transfer tags to be responded to and for all affected tasks in the task set to be * received.</li> * <li>Propagates the command to and receives the response from the target SCSI layer.</li> * <li>Takes note of last-sent StatSN on each of the connections in the iSCSI sessions (one or more) sharing * the affected task set, and waits for acknowledgement of each StatSN (may solicit for acknowledgement by way * of a NOP-In). If some tasks originate from non-iSCSI I_T_L nexi then the means by which the target insures * that all affected tasks have returned their status to the initiator are defined by the specific protocol.</li> * <li>Sends the task set management response to the issuing initiator.</li> * </ol> * <p> * <h4>TotalAHSLength and DataSegmentLength</h4> For this PDU TotalAHSLength and DataSegmentLength MUST be * <code>0</code>. * * @author Volker Wildi */ public final class TaskManagementFunctionResponseParser extends TargetMessageParser { /** * This enumeration defines all valid response code, which are defined in * the iSCSI Standard (RFC 3720). * * @author Volker Wildi */ public static enum ResponseCode { /** Function complete. */ FUNCTION_COMPLETE((byte)0), /** Task does not exist. */ TASK_DOES_NOT_EXIST((byte)1), /** LUN does not exist. */ LUN_DOES_NOT_EXIST((byte)2), /** Task still allegiant. */ TASK_STILL_ALLEGIANT((byte)3), /** Task allegiance reassignment not supported. */ TASK_ALLEGIANCE_REASSIGNMENT_NOT_SUPPORTED((byte)4), /** Task management function not supported. */ TASK_MANAGEMENT_FUNCTION_NOT_SUPPORTED((byte)5), /** Function authorization failed. */ FUNCTION_AUTHORIZATION_FAILED((byte)6), /** Function rejected. */ FUNCTION_REJECTED((byte)255); private byte value; private static ByteObjectOpenHashMap<ResponseCode> mapping; static { ResponseCode.mapping = new ByteObjectOpenHashMap<ResponseCode>(values().length); for (ResponseCode s : values()) { ResponseCode.mapping.put(s.value, s); } } private ResponseCode(final byte newValue) { 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 ResponseCode valueOf(final byte value) { return ResponseCode.mapping.get(value); } } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** The response code. */ private ResponseCode response; // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * Default constructor, creates a new, empty <code>TaskManagementFunctionResponseParser</code> object. * * @param initProtocolDataUnit * The reference <code>ProtocolDataUnit</code> instance, which * contains this <code>TaskManagementFunctionResponseParser</code> subclass * object. */ public TaskManagementFunctionResponseParser(final ProtocolDataUnit initProtocolDataUnit) { super(initProtocolDataUnit); } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** {@inheritDoc} */ @Override public final String toString() { final StringBuilder sb = new StringBuilder(Constants.LOG_INITIAL_SIZE); Utils.printField(sb, "Response", response.value(), 1); sb.append(super.toString()); return sb.toString(); } /** {@inheritDoc} */ @Override public final DataSegmentFormat getDataSegmentFormat() { return DataSegmentFormat.NONE; } /** {@inheritDoc} */ @Override public final void clear() { super.clear(); response = null; } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * The target provides a Response, which may take on the following values: <br/> * <table border = "1"> * <tr> * <th>Response Code</th> * <th>Description</th> * </tr> * <tr> * <td>0</td> * <td>Function complete.</td> * </tr> * <tr> * <td>1</td> * <td>Task does not exist.</td> * </tr> * <tr> * <td>2</td> * <td>LUN does not exist.</td> * </tr> * <tr> * <td>3</td> * <td>Task still allegiant.</td> * </tr> * <tr> * <td>4</td> * <td>Task allegiance reassignment not supported.</td> * </tr> * <tr> * <td>5</td> * <td>Task management function not supported.</td> * </tr> * <tr> * <td>6</td> * <td>Function authorization failed.</td> * </tr> * <tr> * <td>255</td> * <td>Function rejected.</td> * </tr> * </table> * <br/> * <br/> * All other values are reserved. <br/> * <br/> * For a discussion on usage of response codes <code>3</code> and <code>4</code>, see Section 6.2.2 * Allegiance Reassignment.<br/> * <br/> * For the TARGET COLD RESET and TARGET WARM RESET functions, the target * cancels all pending operations across all Logical Units known to the * issuing initiator. For the TARGET COLD RESET function, the target MUST * then close all of its TCP connections to all initiators (terminates all * sessions).<br/> * <br/> * The mapping of the response code into a SCSI service response code value, * if needed, is outside the scope of this document. However, in symbolic * terms Response values 0 and 1 map to the SCSI service response of * FUNCTION COMPLETE. All other Response values map to the SCSI service * response of FUNCTION REJECTED. If a Task Management function response PDU * does not arrive before the session is terminated, the SCSI service * response is SERVICE DELIVERY OR TARGET FAILURE.<br/> * <br/> * The response to ABORT TASK SET and CLEAR TASK SET MUST only be issued by * the target after all of the commands affected have been received by the * target, the corresponding task management functions have been executed by * the SCSI target, and the delivery of all responses delivered until the * task management function completion have been confirmed (acknowledged * through ExpStatSN) by the initiator on all connections of this session. * For the exact timeline of events, refer to Section 10.6.2 Task Management * Actions on Task Sets.<br/> * <br/> * For the ABORT TASK function, * <ol type="a"> * <li>If the Referenced Task Tag identifies a valid task leading to a successful termination, then * targets must return the "Function complete" response.</li> * <li>If the Referenced Task Tag does not identify an existing task, but if the CmdSN indicated by the * RefCmdSN field in the Task Management function request is within the valid CmdSN window and less than * the CmdSN of the Task Management function request itself, then targets must consider the CmdSN received * and return the "Function complete" response.</li> * <li>If the Referenced Task Tag does not identify an existing task and if the CmdSN indicated by the * RefCmdSN field in the Task Management function request is outside the valid CmdSN window, then targets * must return the "Task does not exist" response.</li> * </ol> * * @return The response code of this <code>TaskManagementFunctionResponseParser</code> object. */ public final ResponseCode getResponse() { return response; } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** {@inheritDoc} */ @Override protected final void deserializeBytes1to3(final int line) throws InternetSCSIException { Utils.isReserved(line & Constants.SECOND_BYTE_MASK); response = ResponseCode.valueOf((byte)(line & Constants.THIRD_BYTE_MASK)); Utils.isReserved(line & Constants.FOURTH_BYTE_MASK); } /** {@inheritDoc} */ @Override protected final void deserializeBytes20to23(final int line) throws InternetSCSIException { Utils.isReserved(line); } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** {@inheritDoc} */ @Override protected final void checkIntegrity() throws InternetSCSIException { String exceptionMessage; do { BasicHeaderSegment bhs = protocolDataUnit.getBasicHeaderSegment(); if (bhs.getTotalAHSLength() != 0) { exceptionMessage = "TotalAHSLength must be 0!"; break; } if (bhs.getDataSegmentLength() != 0) { exceptionMessage = "DataSegmentLength must be 0!"; break; } Utils.isReserved(logicalUnitNumber); // message is checked correctly return; } while (false); throw new InternetSCSIException(exceptionMessage); } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** {@inheritDoc} */ @Override protected final int serializeBytes1to3() { return response.value() << Constants.ONE_BYTE_SHIFT; } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- }