package org.jscsi.target.connection.phase; import java.io.IOException; import java.security.DigestException; import javax.naming.OperationNotSupportedException; import org.jscsi.exception.InternetSCSIException; import org.jscsi.parser.BasicHeaderSegment; import org.jscsi.parser.ProtocolDataUnit; import org.jscsi.parser.scsi.SCSICommandParser; import org.jscsi.parser.tmf.TaskManagementFunctionRequestParser; import org.jscsi.target.connection.Connection; import org.jscsi.target.connection.stage.fullfeature.FormatUnitStage; import org.jscsi.target.connection.stage.fullfeature.InquiryStage; import org.jscsi.target.connection.stage.fullfeature.LogoutStage; import org.jscsi.target.connection.stage.fullfeature.ModeSenseStage; import org.jscsi.target.connection.stage.fullfeature.PingStage; import org.jscsi.target.connection.stage.fullfeature.ReadCapacityStage; import org.jscsi.target.connection.stage.fullfeature.ReadStage; import org.jscsi.target.connection.stage.fullfeature.ReportLunsStage; import org.jscsi.target.connection.stage.fullfeature.RequestSenseStage; import org.jscsi.target.connection.stage.fullfeature.SendDiagnosticStage; import org.jscsi.target.connection.stage.fullfeature.TargetFullFeatureStage; import org.jscsi.target.connection.stage.fullfeature.TestUnitReadyStage; import org.jscsi.target.connection.stage.fullfeature.TextNegotiationStage; import org.jscsi.target.connection.stage.fullfeature.UnsupportedOpCodeStage; import org.jscsi.target.connection.stage.fullfeature.WriteStage; import org.jscsi.target.scsi.cdb.ScsiOperationCode; import org.jscsi.target.settings.SettingsException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Objects of this class represent the Target Full Feature Phase of a * connection. * * @see TargetPhase * @author Andreas Ergenzinger */ public final class TargetFullFeaturePhase extends TargetPhase { private static final Logger LOGGER = LoggerFactory.getLogger(TargetFullFeaturePhase.class); /** * The current stage of this phase. */ private TargetFullFeatureStage stage; /** * While this variable is <code>true</code> the phase is still running, * either executing a specific stage or waiting for the next one to begin. */ private boolean running; /** * The constructor. * * @param connection * {@inheritDoc} */ public TargetFullFeaturePhase(Connection connection) { super(connection); } /** * Starts the full feature phase. * * @return {@inheritDoc} * @throws OperationNotSupportedException * {@inheritDoc} * @throws IOException * {@inheritDoc} * @throws InterruptedException * {@inheritDoc} * @throws InternetSCSIException * {@inheritDoc} * @throws DigestException * {@inheritDoc} * @throws SettingsException * {@inheritDoc} */ public PHASE_EXEC_STATUS execute(final ProtocolDataUnit pduInput) throws DigestException, IOException, InterruptedException, InternetSCSIException, SettingsException { running = true; // OODRIVE while (running) { ProtocolDataUnit pdu = pduInput == null ? connection.receivePdu() : pduInput; BasicHeaderSegment bhs = pdu.getBasicHeaderSegment(); // identify desired stage switch (bhs.getOpCode()) { case SCSI_COMMAND: if (connection.getTargetSession().isNormalSession()) { final SCSICommandParser parser = (SCSICommandParser)bhs.getParser(); ScsiOperationCode scsiOpCode = ScsiOperationCode.valueOf(parser.getCDB().get(0)); LOGGER.debug("scsiOpCode = " + scsiOpCode);// log SCSI // Operation Code if (scsiOpCode != null) { switch (scsiOpCode) { case TEST_UNIT_READY: stage = new TestUnitReadyStage(this); break; case REQUEST_SENSE: stage = new RequestSenseStage(this); break; case FORMAT_UNIT: stage = new FormatUnitStage(this); break; case INQUIRY: stage = new InquiryStage(this); break; case MODE_SELECT_6: stage = null; scsiOpCode = null; break; case MODE_SENSE_6: stage = new ModeSenseStage(this); if (!((ModeSenseStage)stage).canHandle(pdu)) { stage = null; scsiOpCode = null; } break; case SEND_DIAGNOSTIC: stage = new SendDiagnosticStage(this); break; case READ_CAPACITY_10:// use common read capacity stage case READ_CAPACITY_16: stage = new ReadCapacityStage(this); break; case WRITE_6:// use common write stage case WRITE_10: stage = new WriteStage(this); connection.addWriteStage(bhs.getInitiatorTaskTag(), (WriteStage) stage); break; case READ_6:// use common read stage case READ_10: stage = new ReadStage(this); break; case REPORT_LUNS: stage = new ReportLunsStage(this); break; default: scsiOpCode = null; } }// else, or if default block was entered (programmer error) if (scsiOpCode == null) { LOGGER.error("Unsupported SCSI OpCode 0x" + Integer.toHexString(parser.getCDB().get(0) & 255) + " in SCSI Command PDU."); stage = new UnsupportedOpCodeStage(this); } } else {// session is discovery session throw new InternetSCSIException("received SCSI command in discovery session"); } break; // SCSI_COMMAND case NOP_OUT: stage = new PingStage(this); break; case TEXT_REQUEST: stage = new TextNegotiationStage(this); break; case LOGOUT_REQUEST: stage = new LogoutStage(this); running = false; break; case SCSI_TM_REQUEST: // /DEBUG CODE!!! LOGGER.warn("Receive :"+((TaskManagementFunctionRequestParser)bhs.getParser()).getFunction() .name()+" ,which is not supported"); stage = new UnsupportedOpCodeStage(this); //running = false; break; case SCSI_DATA_OUT : stage = connection.getWriteStage (bhs.getInitiatorTaskTag()); if (stage == null){ throw new InternetSCSIException("SCSI_DATA_OUT cmd received, outside a write stage."); } break ; default: throw new InternetSCSIException(bhs.getOpCode().name() + " not recognized."); } // process the PDU stage.execute(pdu); // OODRIVE // release pdu pdu.release(); // } return running ? PHASE_EXEC_STATUS.GO_ON : PHASE_EXEC_STATUS.CLOSE; } }